Merge from Chromium at DEPS revision r219274

This commit was generated by merge_to_master.py.

Change-Id: Ibb7f41396cadf4071e89153e1913c986d126f65d
diff --git a/.DEPS.git b/.DEPS.git
index 5571e05..cd8a199 100644
--- a/.DEPS.git
+++ b/.DEPS.git
@@ -11,7 +11,7 @@
     'git_url':
          'https://chromium.googlesource.com',
     'webkit_rev':
-         '@2901640416871fcfce5c4650ea7c2b5c545ef324'
+         '@fd52c40dc3d9e0ec255caf735a72a6c4914f1b69'
 }
 
 deps = {
@@ -28,7 +28,7 @@
     'src/media/cdm/ppapi/api':
         Var('git_url') + '/chromium/cdm.git@c2b192a02546916d28233cfd8b7717ffcdcc8347',
     'src/native_client':
-        Var('git_url') + '/native_client/src/native_client.git@3a9cf2a60e4c3f54564de368d540c556efaa9289',
+        Var('git_url') + '/native_client/src/native_client.git@8bd7716486accbb3562003a8d9dfec9e369721d1',
     'src/sdch/open-vcdiff':
         Var('git_url') + '/external/open-vcdiff.git@438f2a5be6d809bc21611a94cd37bfc8c28ceb33',
     'src/testing/gmock':
@@ -40,11 +40,13 @@
     'src/third_party/accessibility-developer-tools':
         Var('git_url') + '/external/accessibility-developer-tools.git@2e3c9c8e49277a0ca1eeba510271eb03f9486d8f',
     'src/third_party/angle_dx11':
-        Var('git_url') + '/external/angle.git@b93f84acdecd3eebf316750d8024b8b592c9012b',
+        Var('git_url') + '/external/angle.git@827fb6ad615eca2755ae80789a02e1a5587832b6',
     'src/third_party/bidichecker':
         Var('git_url') + '/external/bidichecker/lib.git@97f2aa645b74c28c57eca56992235c79850fa9e0',
     'src/third_party/cacheinvalidation/src':
-        Var('git_url') + '/external/google-cache-invalidation-api/src.git@7f2db96c800ac833fba9af7b446feb3fd73bd9e6',
+        Var('git_url') + '/external/google-cache-invalidation-api/src.git@b4602c6a124e702a1a753f2a16c8531459a6ff32',
+    'src/third_party/cld2':
+        Var('git_url') + '/external/cld2.git@3a527fe115d7c67ac4bf294a523a7e5c6eecef37',
     'src/third_party/ffmpeg':
         Var('git_url') + '/chromium/third_party/ffmpeg.git' + Var('ffmpeg_hash'),
     'src/third_party/flac':
@@ -54,17 +56,17 @@
     'src/third_party/hunspell_dictionaries':
         Var('git_url') + '/chromium/deps/hunspell_dictionaries.git@bc7edb352e97fa71e387b9a5522f1bbd5b11a5eb',
     'src/third_party/icu':
-        Var('git_url') + '/chromium/deps/icu46.git@e39fea897879c8004609e382d1e568a85c3ab345',
+        Var('git_url') + '/chromium/deps/icu46.git@6c837760feb38bc3d489542d1d430feec960cf6c',
     'src/third_party/jsoncpp/source/include':
         Var('git_url') + '/external/jsoncpp/jsoncpp/include.git@b0dd48e02b6e6248328db78a65b5c601f150c349',
     'src/third_party/jsoncpp/source/src/lib_json':
         Var('git_url') + '/external/jsoncpp/jsoncpp/src/lib_json.git@a8caa51ba2f80971a45880425bf2ae864a786784',
     'src/third_party/leveldatabase/src':
-        Var('git_url') + '/external/leveldb.git@9768d126762064fb35c6fd19e41ef9b988c3c329',
+        Var('git_url') + '/external/leveldb.git@08595b9e51ded54851b7664bd38affad63a67838',
     'src/third_party/libexif/sources':
         Var('git_url') + '/chromium/deps/libexif/sources.git@d815c325bab0d1871d4c7e70600ecdfdab07db9e',
     'src/third_party/libjingle/source/talk':
-        Var('git_url') + '/external/webrtc/stable/talk.git@3ca2c3528853f8a25fe42f0e998596ea5ce1f33d',
+        Var('git_url') + '/external/webrtc/stable/talk.git@b57335ce77a25d53842d30fe148ccc4dac2e9c52',
     'src/third_party/libjpeg_turbo':
         Var('git_url') + '/chromium/deps/libjpeg_turbo.git@82ce8a6d4ebe12a177c0c3597192f2b4f09e81c3',
     'src/third_party/libphonenumber/src/phonenumbers':
@@ -98,11 +100,11 @@
     'src/third_party/sfntly/cpp/src':
         Var('git_url') + '/external/sfntly/cpp/src.git@cfb2f1743f0169ad8d01035458617bce97107539',
     'src/third_party/skia/gyp':
-        Var('git_url') + '/external/skia/gyp.git@d147bb92759ec927a4cc53ab5817439991378fad',
+        Var('git_url') + '/external/skia/gyp.git@d47765b26e84582af96a763da51147211a0abd92',
     'src/third_party/skia/include':
-        Var('git_url') + '/external/skia/include.git@1b5ed10ab357a71ecd169a46a654574ad7d57363',
+        Var('git_url') + '/external/skia/include.git@0107089f772605188293bcec21abbc10a9b58d64',
     'src/third_party/skia/src':
-        Var('git_url') + '/external/skia/src.git@1f1c0d428453bea56d6092a89906fb668a7900f9',
+        Var('git_url') + '/external/skia/src.git@64f196fd22f821c9d99ddaf011473543c7b1e152',
     'src/third_party/smhasher/src':
         Var('git_url') + '/external/smhasher.git@6f63a4882e6b2cf87e8eec1a3ef8644e0d963283',
     'src/third_party/snappy/src':
@@ -112,17 +114,17 @@
     'src/third_party/swig/Lib':
         Var('git_url') + '/chromium/deps/swig/Lib.git@549f0b084ad9c40ef42d111303d831eb8d91252e',
     'src/third_party/trace-viewer':
-        Var('git_url') + '/external/trace-viewer.git@105f1a5f16ef9ca378f8caf006cc7da2d09da57f',
+        Var('git_url') + '/external/trace-viewer.git@063e84dd8f142bfad25f406b721c1daf66a7d430',
     'src/third_party/usrsctp/usrsctplib':
         Var('git_url') + '/external/usrsctplib.git@9fde21ced28f3314e75a2d90e5dcc7867e2a6b75',
     '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@f138aa3ce7e555e329d8e388115018452f1cf60f',
+        Var('git_url') + '/chromium/deps/webgl/sdk/tests.git@eddddb40ed480aa7aa25e4ff519fea122044ea8e',
     'src/third_party/webpagereplay':
-        Var('git_url') + '/external/web-page-replay.git@ca269709e412d06b7b9f649dd47fb91f38f73852',
+        Var('git_url') + '/external/web-page-replay.git@932244e6242b374f83b9b1d0be8913100af5b070',
     'src/third_party/webrtc':
-        Var('git_url') + '/external/webrtc/stable/webrtc.git@29613e9492aa3adb60b4fa2cf988f7c959056957',
+        Var('git_url') + '/external/webrtc/stable/webrtc.git@728d09a99990016bc4cf5b826dec0c79e309a376',
     'src/third_party/yasm/source/patched-yasm':
         Var('git_url') + '/chromium/deps/yasm/patched-yasm.git@c960eb11ccda80b10ed50be39df4f0663b371d1d',
     'src/tools/deps2git':
@@ -130,24 +132,26 @@
     'src/tools/grit':
         Var('git_url') + '/external/grit-i18n.git@fbf8c54856bccf2d3e2431127ab334ab1dbd619e',
     'src/tools/gyp':
-        Var('git_url') + '/external/gyp.git@793f69bbc09792052636dbe6038678b24d68e11b',
+        Var('git_url') + '/external/gyp.git@5d6c573d89bad8700442e12af9e6489d6bcafc4a',
     '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@51336a32732d4eea3f07e44e4a62c4d8103ef29f',
     'src/v8':
-        Var('git_url') + '/external/v8.git@387c3b089100ae5db9136ef045e71086f007d907',
+        Var('git_url') + '/external/v8.git@3f7dfd6b89fc3921382fbdc1212fabab54a19757',
 }
 
 deps_os = {
     'android':
     {
         'src/third_party/android_tools':
-            Var('git_url') + '/android_tools.git@881586ca84f2fb8e82faa9c8d645416d175d0f01',
+            Var('git_url') + '/android_tools.git@d8a5bfea861dfbacd9a74275c00561f7bb27d6e3',
         'src/third_party/aosp':
             Var('git_url') + '/chromium/deps/aosp.git@bbafe5155dff86bbba1e92b42a073ffcfcfbf28c',
         'src/third_party/apache-mime4j':
             Var('git_url') + '/chromium/deps/apache-mime4j.git@28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a',
+        'src/third_party/cld2':
+            None,
         'src/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille':
             Var('git_url') + '/external/eyes-free/braille/client/src/com/googlecode/eyesfree/braille.git@77bf6edb0138e3a38a2772248696f130dab45e34',
         'src/third_party/findbugs':
@@ -187,12 +191,12 @@
             Var('git_url') + '/chromium/deps/class-dump.git@89bd40883c767584240b4dade8b74e6f57b9bdab',
         'src/third_party/GTM':
             Var('git_url') + '/external/google-toolbox-for-mac.git@471407b943b14bcebe017dc6d098b3f54019eaba',
-        'src/third_party/angle':
-            None,
         'src/third_party/angle_dx11':
             None,
         'src/third_party/bidichecker':
             None,
+        'src/third_party/cld2':
+            None,
         'src/third_party/ffmpeg':
             None,
         'src/third_party/hunspell':
@@ -284,7 +288,7 @@
         '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@9bad33f702cd5cefb0d5603d6853b26428425081',
+            Var('git_url') + '/chromiumos/platform/system_api.git@94831a5a958ea6029aaf0c900b5187726557aacf',
         'src/third_party/freetype2/src':
             Var('git_url') + '/chromium/src/third_party/freetype2.git@d699c2994ecc178c4ed05ac2086061b2034c2178',
         'src/third_party/gold':
@@ -339,7 +343,7 @@
         'src/third_party/swig/win':
             Var('git_url') + '/chromium/deps/swig/win.git@986f013ba518541adf5c839811efb35630a31031',
         'src/third_party/syzygy/binaries':
-            Var('git_url') + '/external/sawbuck/syzygy/binaries.git@d25845b9eb9b5e2b42e60e8dadcfc711987ebd18',
+            Var('git_url') + '/external/sawbuck/syzygy/binaries.git@13cc989926e7f97dc00769e32a204835174e2392',
         'src/third_party/xulrunner-sdk':
             Var('git_url') + '/chromium/deps/xulrunner-sdk.git@e9b241c183fa4e7af838ecd70714069ca0eb150c',
         'src/third_party/yasm/binaries':
diff --git a/.gitignore b/.gitignore
index c387610..34c63a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -175,7 +175,6 @@
 /third_party/adobe/flash/symbols
 /third_party/amd/
 /third_party/android_tools/
-/third_party/angle
 /third_party/angle_dx11
 /third_party/aosp
 /third_party/apache-mime4j
diff --git a/AUTHORS b/AUTHORS
index f770e73..794db30 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,6 +11,7 @@
 Aaron Jacobs <samusaaron3@gmail.com>
 Aaron Leventhal <aaronlevbugs@gmail.com>
 Aaron Randolph <aaron.randolph@gmail.com>
+Adenilson Cavalcanti <a.cavalcanti@partner.samsung.com>
 Aditya Bhargava <heuristicist@gmail.com>
 Alex Gartrell <agartrell@cmu.edu>
 Alex Scheele <alexscheele@gmail.com>
@@ -22,6 +23,8 @@
 Amruth Raj <amruthraj@motorola.com>
 Amruth Raj <ckqr36@motorola.com>
 Anastasios Cassiotis <tom.cassiotis@gmail.com>
+Andrei Parvu <andrei.prv@gmail.com>
+Andrei Parvu <parvu@adobe.com>
 Andrew Brampton <me@bramp.net>
 Arthur Lussos <developer0420@gmail.com>
 Arun Mankuzhi <arun.m@samsung.com>
@@ -34,6 +37,7 @@
 Brian G. Merrell <bgmerrell@gmail.com>
 Brian Merrell, Novell Inc. <bgmerrell@gmail.com>
 Bruno Calvignac <bruno@flock.com>
+Bruno de Oliveira Abinader <bruno.d@partner.samsung.com>
 Bryan Donlan <bdonlan@gmail.com>
 Byungwoo Lee <bw80.lee@samsung.com>
 Caio Marcelo de Oliveira Filho <caio.de.oliveira.filho@intel.com>
@@ -79,7 +83,9 @@
 Gajendra Singh <wxjg68@motorola.com>
 Gao Chun <gaochun.dev@gmail.com>
 Giuseppe Iuculano <giuseppe@iuculano.it>
+Glenn Adams <glenn@chromium.org>
 Goutham Jagannatha <wrm364@motorola.com>
+Grzegorz Czajkowski <g.czajkowski@samsung.com>
 Gyuyoung Kim <gyuyoung.kim@samsung.com>
 Haitao Feng <haitao.feng@intel.com>
 Halton Huo <halton.huo@intel.com>
@@ -107,6 +113,7 @@
 Jin Yang <jin.a.yang@intel.com>
 Jingwei Liu <kingweiliu@gmail.com>
 Jinwoo Song <jinwoo7.song@samsung.com>
+Joe Knoll <joe.knoll@workday.com>
 Joe Thomas <mhx348@motorola.com>
 Joel Stanley <joel@jms.id.au>
 Johannes Rudolph <johannes.rudolph@googlemail.com>
@@ -165,6 +172,8 @@
 Mihai Tica <mitica@adobe.com>
 Mike Tilburg <mtilburg@adobe.com>
 Mingmin Xie <melvinxie@gmail.com>
+Mirela Budaes <mbudaes@gmail.com>
+Mirela Budaes <mbudaes@adobe.com>
 Mitchell Rosen <mitchellwrosen@chromium.org>
 Mohamed I. Hammad <ibraaaa@gmail.com>
 Mohamed Mansour <m0.interactive@gmail.com>
@@ -227,6 +236,7 @@
 Satoshi Matsuzaki <satoshi.matsuzaki@gmail.com>
 Sean Bryant <sean@cyberwang.net>
 Seo Sanghyeon <sanxiyn@gmail.com>
+Seokju Kwon <seokju.kwon@gmail.com>
 Sergio Carlos Morales Angeles <carloschilazo@gmail.com>
 Sergiy Byelozyorov <rryk.ua@gmail.com>
 Seshadri Mahalingam <seshadri.mahalingam@gmail.com>
@@ -240,6 +250,7 @@
 Song YeWen <ffmpeg@gmail.com>
 Stephen Searles <stephen.searles@gmail.com>
 Steven Pennington <spenn@engr.uvic.ca>
+Suchit Agrawal <a.suchit@samsung.com>
 Sudarsana Babu Nagineni <sudarsana.nagineni@intel.com>
 Sungguk Lim <limasdf@gmail.com>
 Sungmann Cho <sungmann.cho@gmail.com>
diff --git a/DEPS b/DEPS
index ef8224f..0556178 100644
--- a/DEPS
+++ b/DEPS
@@ -8,12 +8,12 @@
   "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": "155942",
+  "webkit_revision": "156598",
   "chromium_git": "https://chromium.googlesource.com",
   "chromiumos_git": "https://chromium.googlesource.com/chromiumos",
   "skia_git": "https://skia.googlesource.com",
   "swig_revision": "69281",
-  "nacl_revision": "11988",
+  "nacl_revision": "12040",
   # After changing nacl_revision, run 'glient sync' and check native_client/DEPS
   # to update other nacl_*_revision's.
   "nacl_tools_revision": "11437",  # native_client/DEPS: tools_rev
@@ -29,16 +29,16 @@
   "ffmpeg_hash": "894e6f715645528e815aee2dad45b59704238dcd",
 
   "sfntly_revision": "134",
-  "skia_revision": "10680",
-  "skia_hash": "8f4825bfb1da69439e1e96a0c6ea04488757d95e",
+  "skia_revision": "10884",
+  "skia_hash": "5ff3e8c7872eb5b840399b22fe4734b968f61a4b",
   # 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": "16159",
+  "v8_revision": "16277",
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling WebRTC
   # and V8 without interference from each other.
-  "webrtc_revision": "4533",
+  "webrtc_revision": "4595",
   "jsoncpp_revision": "248",
   "nss_revision": "209026",
   # Three lines of non-changing comments so that
@@ -66,16 +66,16 @@
 
   "src/third_party/angle_dx11":
     Var("chromium_git") +
-    "/external/angle.git@b93f84acdecd3eebf316750d8024b8b592c9012b",
+    "/external/angle.git@827fb6ad615eca2755ae80789a02e1a5587832b6",
 
   "src/third_party/trace-viewer":
-    (Var("googlecode_url") % "trace-viewer") + "/trunk@847",
+    (Var("googlecode_url") % "trace-viewer") + "/trunk@893",
 
   "src/third_party/WebKit":
     Var("webkit_trunk") + "@" + Var("webkit_revision"),
 
   "src/third_party/icu":
-    "/trunk/deps/third_party/icu46@214189",
+    "/trunk/deps/third_party/icu46@219032",
 
   "src/third_party/libexif/sources":
     "/trunk/deps/third_party/libexif/sources@146817",
@@ -91,10 +91,10 @@
 
   "src/third_party/cacheinvalidation/src":
     (Var("googlecode_url") % "google-cache-invalidation-api") +
-    "/trunk/src@309",
+    "/trunk/src@312",
 
   "src/third_party/leveldatabase/src":
-    (Var("googlecode_url") % "leveldb") + "/trunk@75",
+    (Var("googlecode_url") % "leveldb") + "/trunk@76",
 
   "src/third_party/snappy/src":
     (Var("googlecode_url") % "snappy") + "/trunk@74",
@@ -103,7 +103,7 @@
     (Var("googlecode_url") % "grit-i18n") + "/trunk@129",
 
   "src/tools/gyp":
-    (Var("googlecode_url") % "gyp") + "/trunk@1693",
+    (Var("googlecode_url") % "gyp") + "/trunk@1700",
 
   "src/tools/swarm_client":
     "/trunk/tools/swarm_client@" + Var("swarm_revision"),
@@ -152,7 +152,7 @@
   # When roll to another webgl conformance tests revision, please goto
   # chrome/test/gpu and run generate_webgl_conformance_test_list.py.
   "src/third_party/webgl_conformance":
-    "/trunk/deps/third_party/webgl/sdk/tests@217097",
+    "/trunk/deps/third_party/webgl/sdk/tests@218717",
 
   "src/third_party/swig/Lib":
     "/trunk/deps/third_party/swig/Lib@" + Var("swig_revision"),
@@ -233,7 +233,7 @@
     "/trunk/tools/deps2git@214390",
 
   "src/third_party/webpagereplay":
-    (Var("googlecode_url") % "web-page-replay") + "/trunk@518",
+    (Var("googlecode_url") % "web-page-replay") + "/trunk@519",
 
   "src/third_party/pywebsocket/src":
     (Var("googlecode_url") % "pywebsocket") + "/trunk/src@662",
@@ -249,6 +249,9 @@
 
   "src/third_party/mesa/src":
     "/trunk/deps/third_party/mesa@210110",
+
+  "src/third_party/cld2":
+    (Var("googlecode_url") % "cld2") + "/trunk@19",
 }
 
 
@@ -311,7 +314,7 @@
     # Binary level profile guided optimizations. This points to the
     # latest release binaries for the toolchain.
     "src/third_party/syzygy/binaries":
-      (Var("googlecode_url") % "sawbuck") + "/trunk/syzygy/binaries@1718",
+      (Var("googlecode_url") % "sawbuck") + "/trunk/syzygy/binaries@1740",
 
     # Binaries for nacl sdk.
     "src/third_party/nacl_sdk_binaries":
@@ -336,8 +339,8 @@
     "src/chrome/test/data/perf/frame_rate/content": None,
     "src/native_client": None,
     "src/native_client/src/third_party/ppapi": None,
-    "src/third_party/angle": None,
     "src/third_party/angle_dx11": None,
+    "src/third_party/cld2": None,
     "src/third_party/bidichecker": None,
     "src/third_party/webgl_conformance": None,
     "src/third_party/ffmpeg": None,
@@ -430,7 +433,7 @@
     # For Linux and Chromium OS.
     "src/third_party/cros_system_api":
       Var("chromiumos_git") + "/platform/system_api.git" +
-      "@9bad33f702cd5cefb0d5603d6853b26428425081",
+      "@94831a5a958ea6029aaf0c900b5187726557aacf",
 
     # Note that this is different from Android's freetype repo.
     "src/third_party/freetype2/src":
@@ -453,7 +456,7 @@
   "android": {
     "src/third_party/android_tools":
       Var("chromium_git") + "/android_tools.git" +
-      "@881586ca84f2fb8e82faa9c8d645416d175d0f01",
+      "@d8a5bfea861dfbacd9a74275c00561f7bb27d6e3",
 
     "src/third_party/aosp":
       "/trunk/deps/third_party/aosp@148330",
@@ -493,6 +496,8 @@
 
     "src/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille":
       (Var("googlecode_url") % "eyes-free") + "/trunk/braille/client/src/com/googlecode/eyesfree/braille@797",
+
+    "src/third_party/cld2": None,
   },
 }
 
diff --git a/GypAndroid.darwin-arm.mk b/GypAndroid.darwin-arm.mk
index 85b5b60..d123e5d 100644
--- a/GypAndroid.darwin-arm.mk
+++ b/GypAndroid.darwin-arm.mk
@@ -129,6 +129,7 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_css.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_elements_js.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_js.target.darwin-arm.mk
+include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_layers_js.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_network_js.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_profiles_js.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_resources_js.target.darwin-arm.mk
@@ -197,8 +198,8 @@
 include $(LOCAL_PATH)/third_party/smhasher/cityhash.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/sqlite/sqlite.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/widevine/cdm/widevine_cdm_version_h.target.darwin-arm.mk
+include $(LOCAL_PATH)/third_party/zlib/google/zip.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/zlib/minizip.target.darwin-arm.mk
-include $(LOCAL_PATH)/third_party/zlib/zip.target.darwin-arm.mk
 include $(LOCAL_PATH)/third_party/zlib/zlib.target.darwin-arm.mk
 include $(LOCAL_PATH)/ui/base/strings/ui_strings.target.darwin-arm.mk
 include $(LOCAL_PATH)/ui/gl/gl.target.darwin-arm.mk
@@ -234,7 +235,6 @@
 include $(LOCAL_PATH)/webkit/webkit_resources.target.darwin-arm.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_browser.target.darwin-arm.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_common.target.darwin-arm.mk
-include $(LOCAL_PATH)/webkit/webkit_storage_renderer.target.darwin-arm.mk
 include $(LOCAL_PATH)/webkit/webkit_strings.target.darwin-arm.mk
 
 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
diff --git a/GypAndroid.darwin-mips.mk b/GypAndroid.darwin-mips.mk
index 5dc9a15..620cd4c 100644
--- a/GypAndroid.darwin-mips.mk
+++ b/GypAndroid.darwin-mips.mk
@@ -125,6 +125,7 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_css.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_elements_js.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_js.target.darwin-mips.mk
+include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_layers_js.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_network_js.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_profiles_js.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_resources_js.target.darwin-mips.mk
@@ -193,8 +194,8 @@
 include $(LOCAL_PATH)/third_party/smhasher/cityhash.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/sqlite/sqlite.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/widevine/cdm/widevine_cdm_version_h.target.darwin-mips.mk
+include $(LOCAL_PATH)/third_party/zlib/google/zip.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/zlib/minizip.target.darwin-mips.mk
-include $(LOCAL_PATH)/third_party/zlib/zip.target.darwin-mips.mk
 include $(LOCAL_PATH)/third_party/zlib/zlib.target.darwin-mips.mk
 include $(LOCAL_PATH)/ui/base/strings/ui_strings.target.darwin-mips.mk
 include $(LOCAL_PATH)/ui/gl/gl.target.darwin-mips.mk
@@ -230,7 +231,6 @@
 include $(LOCAL_PATH)/webkit/webkit_resources.target.darwin-mips.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_browser.target.darwin-mips.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_common.target.darwin-mips.mk
-include $(LOCAL_PATH)/webkit/webkit_storage_renderer.target.darwin-mips.mk
 include $(LOCAL_PATH)/webkit/webkit_strings.target.darwin-mips.mk
 
 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
diff --git a/GypAndroid.darwin-x86.mk b/GypAndroid.darwin-x86.mk
index f9ea4ce..952d73c 100644
--- a/GypAndroid.darwin-x86.mk
+++ b/GypAndroid.darwin-x86.mk
@@ -133,6 +133,7 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_css.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_elements_js.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_js.target.darwin-x86.mk
+include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_layers_js.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_network_js.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_profiles_js.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_resources_js.target.darwin-x86.mk
@@ -211,8 +212,8 @@
 include $(LOCAL_PATH)/third_party/yasm/genversion.host.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/yasm/re2c.host.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/yasm/yasm.host.darwin-x86.mk
+include $(LOCAL_PATH)/third_party/zlib/google/zip.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/zlib/minizip.target.darwin-x86.mk
-include $(LOCAL_PATH)/third_party/zlib/zip.target.darwin-x86.mk
 include $(LOCAL_PATH)/third_party/zlib/zlib.target.darwin-x86.mk
 include $(LOCAL_PATH)/ui/base/strings/ui_strings.target.darwin-x86.mk
 include $(LOCAL_PATH)/ui/gl/gl.target.darwin-x86.mk
@@ -248,7 +249,6 @@
 include $(LOCAL_PATH)/webkit/webkit_resources.target.darwin-x86.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_browser.target.darwin-x86.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_common.target.darwin-x86.mk
-include $(LOCAL_PATH)/webkit/webkit_storage_renderer.target.darwin-x86.mk
 include $(LOCAL_PATH)/webkit/webkit_strings.target.darwin-x86.mk
 
 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
diff --git a/GypAndroid.linux-arm.mk b/GypAndroid.linux-arm.mk
index 673934c..4d94b7f 100644
--- a/GypAndroid.linux-arm.mk
+++ b/GypAndroid.linux-arm.mk
@@ -129,6 +129,7 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_css.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_elements_js.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_js.target.linux-arm.mk
+include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_layers_js.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_network_js.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_profiles_js.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_resources_js.target.linux-arm.mk
@@ -197,8 +198,8 @@
 include $(LOCAL_PATH)/third_party/smhasher/cityhash.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/sqlite/sqlite.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/widevine/cdm/widevine_cdm_version_h.target.linux-arm.mk
+include $(LOCAL_PATH)/third_party/zlib/google/zip.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/zlib/minizip.target.linux-arm.mk
-include $(LOCAL_PATH)/third_party/zlib/zip.target.linux-arm.mk
 include $(LOCAL_PATH)/third_party/zlib/zlib.target.linux-arm.mk
 include $(LOCAL_PATH)/ui/base/strings/ui_strings.target.linux-arm.mk
 include $(LOCAL_PATH)/ui/gl/gl.target.linux-arm.mk
@@ -234,7 +235,6 @@
 include $(LOCAL_PATH)/webkit/webkit_resources.target.linux-arm.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_browser.target.linux-arm.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_common.target.linux-arm.mk
-include $(LOCAL_PATH)/webkit/webkit_storage_renderer.target.linux-arm.mk
 include $(LOCAL_PATH)/webkit/webkit_strings.target.linux-arm.mk
 
 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
diff --git a/GypAndroid.linux-mips.mk b/GypAndroid.linux-mips.mk
index d3e160f..4e845b4 100644
--- a/GypAndroid.linux-mips.mk
+++ b/GypAndroid.linux-mips.mk
@@ -125,6 +125,7 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_css.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_elements_js.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_js.target.linux-mips.mk
+include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_layers_js.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_network_js.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_profiles_js.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_resources_js.target.linux-mips.mk
@@ -193,8 +194,8 @@
 include $(LOCAL_PATH)/third_party/smhasher/cityhash.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/sqlite/sqlite.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/widevine/cdm/widevine_cdm_version_h.target.linux-mips.mk
+include $(LOCAL_PATH)/third_party/zlib/google/zip.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/zlib/minizip.target.linux-mips.mk
-include $(LOCAL_PATH)/third_party/zlib/zip.target.linux-mips.mk
 include $(LOCAL_PATH)/third_party/zlib/zlib.target.linux-mips.mk
 include $(LOCAL_PATH)/ui/base/strings/ui_strings.target.linux-mips.mk
 include $(LOCAL_PATH)/ui/gl/gl.target.linux-mips.mk
@@ -230,7 +231,6 @@
 include $(LOCAL_PATH)/webkit/webkit_resources.target.linux-mips.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_browser.target.linux-mips.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_common.target.linux-mips.mk
-include $(LOCAL_PATH)/webkit/webkit_storage_renderer.target.linux-mips.mk
 include $(LOCAL_PATH)/webkit/webkit_strings.target.linux-mips.mk
 
 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
diff --git a/GypAndroid.linux-x86.mk b/GypAndroid.linux-x86.mk
index 06bb9bf..0e437a7 100644
--- a/GypAndroid.linux-x86.mk
+++ b/GypAndroid.linux-x86.mk
@@ -133,6 +133,7 @@
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_css.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_elements_js.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_js.target.linux-x86.mk
+include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_layers_js.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_network_js.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_profiles_js.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/WebKit/Source/devtools/concatenated_devtools_resources_js.target.linux-x86.mk
@@ -211,8 +212,8 @@
 include $(LOCAL_PATH)/third_party/yasm/genversion.host.linux-x86.mk
 include $(LOCAL_PATH)/third_party/yasm/re2c.host.linux-x86.mk
 include $(LOCAL_PATH)/third_party/yasm/yasm.host.linux-x86.mk
+include $(LOCAL_PATH)/third_party/zlib/google/zip.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/zlib/minizip.target.linux-x86.mk
-include $(LOCAL_PATH)/third_party/zlib/zip.target.linux-x86.mk
 include $(LOCAL_PATH)/third_party/zlib/zlib.target.linux-x86.mk
 include $(LOCAL_PATH)/ui/base/strings/ui_strings.target.linux-x86.mk
 include $(LOCAL_PATH)/ui/gl/gl.target.linux-x86.mk
@@ -248,7 +249,6 @@
 include $(LOCAL_PATH)/webkit/webkit_resources.target.linux-x86.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_browser.target.linux-x86.mk
 include $(LOCAL_PATH)/webkit/webkit_storage_common.target.linux-x86.mk
-include $(LOCAL_PATH)/webkit/webkit_storage_renderer.target.linux-x86.mk
 include $(LOCAL_PATH)/webkit/webkit_strings.target.linux-x86.mk
 
 # "gyp_all_modules" is a concatenation of the "gyp_all_modules" targets from
diff --git a/NOTICE b/NOTICE
index 3e42dcf..58cba77 100644
--- a/NOTICE
+++ b/NOTICE
@@ -3561,7 +3561,7 @@
    limitations under the License.
 
 
-Copyright (c) 2007-2009 IOLA and Ole Laursen
+Copyright (c) 2007-2013 IOLA and Ole Laursen
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
@@ -4882,25 +4882,6 @@
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-License copied from bin/lcov:
-
-#
-#   Copyright (c) International Business Machines  Corp., 2002,2007
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.                 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
 		    GNU GENERAL PUBLIC LICENSE
 		       Version 2, June 1991
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 0b1f6c7..7f4af43 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -25,6 +25,7 @@
     r".*MakeFile$",
     r".+_autogen\.h$",
     r".+[\\\/]pnacl_shim\.c$",
+    r"^gpu[\\\/]config[\\\/].*_list_json\.cc$",
 )
 
 # Fragment of a regular expression that matches C++ and Objective-C++
@@ -156,7 +157,8 @@
       ),
       True,
       (
-        r"^content[\\\/]shell[\\\/]shell_browser_main\.cc$",
+        r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
+        r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
         r"^net[\\\/]disk_cache[\\\/]cache_util\.cc$",
       ),
     ),
diff --git a/WATCHLISTS b/WATCHLISTS
index b9c1b36..ff3e514 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -137,6 +137,9 @@
       'filepath': 'ui/views/bubble/|'\
                   'chrome/browser/ui/views/bubble/',
     },
+    'cast': {
+      'filepath': 'media/cast/',
+    },
     'cc': {
       'filepath': 'cc/|'\
                   'webkit/renderer/compositor_bindings/|'\
@@ -156,7 +159,8 @@
     },
     'chromeos_attestation': {
       'filepath': 'chromeos/attestation/|'\
-                  'chrome/browser/chromeos/attestation/',
+                  'chrome/browser/chromeos/attestation/|'\
+                  'chrome/browser/extensions/api/enterprise_platform_keys_private/',
     },
     'chromeos_calculator': {
       'filepath': 'chrome/common/extensions/docs/examples/apps/calculator/',
@@ -641,6 +645,7 @@
     'browser_resources': ['arv+watch@chromium.org'],
     'browsing_data': ['markusheintz@chromium.org'],
     'bubble': ['alicet@chromium.org', 'msw+watch@chromium.org'],
+    'cast': ['miu+watch@chromium.org'],
     'cc': ['cc-bugs@chromium.org'],
     'chrome_frame': ['amit@chromium.org', 'grt+watch@chromium.org',
                      'robertshield@chromium.org'],
diff --git a/android_webview/browser/aw_devtools_delegate.cc b/android_webview/browser/aw_devtools_delegate.cc
index 0e0e026..25f2b7a 100644
--- a/android_webview/browser/aw_devtools_delegate.cc
+++ b/android_webview/browser/aw_devtools_delegate.cc
@@ -224,7 +224,7 @@
   if (!bvr) return "";
   base::DictionaryValue description;
   description.SetBoolean("attached", bvr->IsAttachedToWindow());
-  description.SetBoolean("visible", bvr->IsViewVisible());
+  description.SetBoolean("visible", bvr->IsVisible());
   gfx::Rect screen_rect = bvr->GetScreenRect();
   description.SetInteger("screenX", screen_rect.x());
   description.SetInteger("screenY", screen_rect.y());
diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h
index 78beb17..f54420c 100644
--- a/android_webview/browser/browser_view_renderer.h
+++ b/android_webview/browser/browser_view_renderer.h
@@ -113,7 +113,9 @@
   virtual void EnableOnNewPicture(bool enabled) = 0;
 
   // View update notifications.
-  virtual void OnVisibilityChanged(bool visible) = 0;
+  virtual void SetIsPaused(bool paused) = 0;
+  virtual void SetViewVisibility(bool visible) = 0;
+  virtual void SetWindowVisibility(bool visible) = 0;
   virtual void OnSizeChanged(int width, int height) = 0;
   virtual void OnAttachedToWindow(int width, int height) = 0;
   virtual void OnDetachedFromWindow() = 0;
@@ -127,7 +129,7 @@
 
   // Android views hierarchy gluing.
   virtual bool IsAttachedToWindow() = 0;
-  virtual bool IsViewVisible() = 0;
+  virtual bool IsVisible() = 0;
   virtual gfx::Rect GetScreenRect() = 0;
 
   virtual ~BrowserViewRenderer() {}
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc
index 39614d3..3f935ff 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/in_process_view_renderer.cc
@@ -171,6 +171,21 @@
 
 base::LazyInstance<GLViewRendererManager>::Leaky g_view_renderer_manager;
 
+void RequestProcessGLOnUIThread() {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE, base::Bind(&RequestProcessGLOnUIThread));
+    return;
+  }
+
+  InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
+      g_view_renderer_manager.Get().GetMostRecentlyDrawn());
+  if (!renderer || !renderer->RequestProcessGL()) {
+    LOG(ERROR) << "Failed to request GL process. Deadlock likely: "
+               << !!renderer;
+  }
+}
+
 }  // namespace
 
 // Called from different threads!
@@ -178,11 +193,7 @@
   if (ScopedAllowGL::IsAllowed()) {
     gpu::InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread();
   } else {
-    InProcessViewRenderer* renderer = static_cast<InProcessViewRenderer*>(
-        g_view_renderer_manager.Get().GetMostRecentlyDrawn());
-    if (!renderer || !renderer->RequestProcessGL()) {
-      LOG(ERROR) << "Failed to request DrawGL. Probably going to deadlock.";
-    }
+    RequestProcessGLOnUIThread();
   }
 }
 
@@ -207,16 +218,17 @@
       java_helper_(java_helper),
       web_contents_(web_contents),
       compositor_(NULL),
-      visible_(false),
+      is_paused_(false),
+      view_visible_(false),
+      window_visible_(false),
+      attached_to_window_(false),
       dip_scale_(0.0),
       page_scale_factor_(1.0),
       on_new_picture_enable_(false),
       compositor_needs_continuous_invalidate_(false),
-      need_fast_invalidate_(false),
       block_invalidates_(false),
       width_(0),
       height_(0),
-      attached_to_window_(false),
       hardware_initialized_(false),
       hardware_failed_(false),
       last_egl_context_(NULL),
@@ -541,13 +553,33 @@
   on_new_picture_enable_ = enabled;
 }
 
-void InProcessViewRenderer::OnVisibilityChanged(bool visible) {
+void InProcessViewRenderer::SetIsPaused(bool paused) {
   TRACE_EVENT_INSTANT1("android_webview",
-                       "InProcessViewRenderer::OnVisibilityChanged",
+                       "InProcessViewRenderer::SetIsPaused",
                        TRACE_EVENT_SCOPE_THREAD,
-                       "visible",
-                       visible);
-  visible_ = visible;
+                       "paused",
+                       paused);
+  is_paused_ = paused;
+  EnsureContinuousInvalidation(NULL, false);
+}
+
+void InProcessViewRenderer::SetViewVisibility(bool view_visible) {
+  TRACE_EVENT_INSTANT1("android_webview",
+                       "InProcessViewRenderer::SetViewVisibility",
+                       TRACE_EVENT_SCOPE_THREAD,
+                       "view_visible",
+                       view_visible);
+  view_visible_ = view_visible;
+}
+
+void InProcessViewRenderer::SetWindowVisibility(bool window_visible) {
+  TRACE_EVENT_INSTANT1("android_webview",
+                       "InProcessViewRenderer::SetWindowVisibility",
+                       TRACE_EVENT_SCOPE_THREAD,
+                       "window_visible",
+                       window_visible);
+  window_visible_ = window_visible;
+  EnsureContinuousInvalidation(NULL, false);
 }
 
 void InProcessViewRenderer::OnSizeChanged(int width, int height) {
@@ -598,8 +630,9 @@
   return attached_to_window_;
 }
 
-bool InProcessViewRenderer::IsViewVisible() {
-  return visible_;
+bool InProcessViewRenderer::IsVisible() {
+  // Ignore |window_visible_| if |attached_to_window_| is false.
+  return view_visible_ && (!attached_to_window_ || window_visible_);
 }
 
 gfx::Rect InProcessViewRenderer::GetScreenRect() {
@@ -640,7 +673,6 @@
                        "invalidate",
                        invalidate);
   compositor_needs_continuous_invalidate_ = invalidate;
-  need_fast_invalidate_ = compositor_needs_continuous_invalidate_;
   EnsureContinuousInvalidation(NULL, false);
 }
 
@@ -723,42 +755,40 @@
 void InProcessViewRenderer::EnsureContinuousInvalidation(
     AwDrawGLInfo* draw_info,
     bool invalidate_ignore_compositor) {
-  if ((compositor_needs_continuous_invalidate_ ||
-       invalidate_ignore_compositor) &&
-      !block_invalidates_) {
-    if (draw_info) {
-      draw_info->dirty_left = cached_global_visible_rect_.x();
-      draw_info->dirty_top = cached_global_visible_rect_.y();
-      draw_info->dirty_right = cached_global_visible_rect_.right();
-      draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
-      draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
-    } else {
-      client_->PostInvalidate();
-    }
+  // This method should be called again when any of these conditions change.
+  bool need_invalidate =
+      compositor_needs_continuous_invalidate_ || invalidate_ignore_compositor;
+  bool throttle = is_paused_ || (attached_to_window_ && !window_visible_);
+  if (!need_invalidate || block_invalidates_ || throttle)
+    return;
 
-    block_invalidates_ = true;
+  if (draw_info) {
+    draw_info->dirty_left = cached_global_visible_rect_.x();
+    draw_info->dirty_top = cached_global_visible_rect_.y();
+    draw_info->dirty_right = cached_global_visible_rect_.right();
+    draw_info->dirty_bottom = cached_global_visible_rect_.bottom();
+    draw_info->status_mask |= AwDrawGLInfo::kStatusMaskDraw;
+  } else {
+    client_->PostInvalidate();
+  }
 
-    // Unretained here is safe because the callback is cancelled when
-    // |fallback_tick_| is destroyed.
-    fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
-                                    base::Unretained(this)));
+  block_invalidates_ = true;
 
-    // No need to reschedule fallback tick if compositor does not need to be
-    // ticked. This can happen if this is reached because
-    // invalidate_ignore_compositor is true.
-    if (compositor_needs_continuous_invalidate_) {
-      int64 delay_in_ms = kFallbackTickTimeoutInMilliseconds;
-      if (need_fast_invalidate_) {
-        TRACE_EVENT_INSTANT0(
-            "android_webview", "FastFallbackTick", TRACE_EVENT_SCOPE_THREAD);
-        delay_in_ms = 0;
-        need_fast_invalidate_ = false;
-      }
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          fallback_tick_.callback(),
-          base::TimeDelta::FromMilliseconds(delay_in_ms));
-    }
+  // Unretained here is safe because the callback is cancelled when
+  // |fallback_tick_| is destroyed.
+  fallback_tick_.Reset(base::Bind(&InProcessViewRenderer::FallbackTickFired,
+                                  base::Unretained(this)));
+
+  // No need to reschedule fallback tick if compositor does not need to be
+  // ticked. This can happen if this is reached because
+  // invalidate_ignore_compositor is true.
+  if (compositor_needs_continuous_invalidate_) {
+    BrowserThread::PostDelayedTask(
+        BrowserThread::UI,
+        FROM_HERE,
+        fallback_tick_.callback(),
+        base::TimeDelta::FromMilliseconds(
+            kFallbackTickTimeoutInMilliseconds));
   }
 }
 
@@ -788,7 +818,9 @@
 
 std::string InProcessViewRenderer::ToString(AwDrawGLInfo* draw_info) const {
   std::string str;
-  base::StringAppendF(&str, "visible: %d ", visible_);
+  base::StringAppendF(&str, "is_paused: %d ", is_paused_);
+  base::StringAppendF(&str, "view_visible: %d ", view_visible_);
+  base::StringAppendF(&str, "window_visible: %d ", window_visible_);
   base::StringAppendF(&str, "dip_scale: %f ", dip_scale_);
   base::StringAppendF(&str, "page_scale_factor: %f ", page_scale_factor_);
   base::StringAppendF(&str,
diff --git a/android_webview/browser/in_process_view_renderer.h b/android_webview/browser/in_process_view_renderer.h
index e86796f..b5933bd 100644
--- a/android_webview/browser/in_process_view_renderer.h
+++ b/android_webview/browser/in_process_view_renderer.h
@@ -58,7 +58,9 @@
   virtual skia::RefPtr<SkPicture> CapturePicture(int width,
                                                  int height) OVERRIDE;
   virtual void EnableOnNewPicture(bool enabled) OVERRIDE;
-  virtual void OnVisibilityChanged(bool visible) OVERRIDE;
+  virtual void SetIsPaused(bool paused) OVERRIDE;
+  virtual void SetViewVisibility(bool visible) OVERRIDE;
+  virtual void SetWindowVisibility(bool visible) OVERRIDE;
   virtual void OnSizeChanged(int width, int height) OVERRIDE;
   virtual void ScrollTo(gfx::Vector2d new_value) OVERRIDE;
   virtual void SetPageScaleFactor(float page_scale_factor) OVERRIDE;
@@ -66,7 +68,7 @@
   virtual void OnDetachedFromWindow() OVERRIDE;
   virtual void SetDipScale(float dip_scale) OVERRIDE;
   virtual bool IsAttachedToWindow() OVERRIDE;
-  virtual bool IsViewVisible() OVERRIDE;
+  virtual bool IsVisible() OVERRIDE;
   virtual gfx::Rect GetScreenRect() OVERRIDE;
 
   // SynchronousCompositorClient overrides
@@ -115,7 +117,10 @@
   content::WebContents* web_contents_;
   content::SynchronousCompositor* compositor_;
 
-  bool visible_;
+  bool is_paused_;
+  bool view_visible_;
+  bool window_visible_;  // Only applicable if |attached_to_window_| is true.
+  bool attached_to_window_;
   float dip_scale_;
   float page_scale_factor_;
   bool on_new_picture_enable_;
@@ -126,13 +131,6 @@
   // states.
   bool compositor_needs_continuous_invalidate_;
 
-  // If this is true, then the fallback tick is posted with zero delay. This
-  // is to reduce the time in cases when blink main thread is blocked waiting.
-  // This is set when |compositor_needs_continuous_invalidate_| is set.
-  // Eventually, this should correspond to BeginFrame when BeginFrame and
-  // BeginFrameDeadline are separate functions.
-  bool need_fast_invalidate_;
-
   // Used to block additional invalidates while one is already pending or before
   // compositor draw which may switch continuous_invalidate on and off in the
   // process.
@@ -144,7 +142,6 @@
   int width_;
   int height_;
 
-  bool attached_to_window_;
   bool hardware_initialized_;
   bool hardware_failed_;
   scoped_refptr<AwGLSurface> gl_surface_;
diff --git a/android_webview/browser/net/aw_network_delegate.cc b/android_webview/browser/net/aw_network_delegate.cc
index bd69d38..b9059b8 100644
--- a/android_webview/browser/net/aw_network_delegate.cc
+++ b/android_webview/browser/net/aw_network_delegate.cc
@@ -5,6 +5,7 @@
 #include "android_webview/browser/net/aw_network_delegate.h"
 
 #include "android_webview/browser/aw_cookie_access_policy.h"
+#include "base/android/build_info.h"
 #include "net/base/net_errors.h"
 #include "net/base/completion_callback.h"
 #include "net/url_request/url_request.h"
@@ -28,6 +29,11 @@
     net::URLRequest* request,
     const net::CompletionCallback& callback,
     net::HttpRequestHeaders* headers) {
+
+  DCHECK(headers);
+  headers->SetHeaderIfMissing(
+      "X-Requested-With",
+      base::android::BuildInfo::GetInstance()->package_name());
   return net::OK;
 }
 
diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc
index eed948f..4017c18 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -14,6 +14,7 @@
 #include "android_webview/browser/net/init_native_callback.h"
 #include "android_webview/common/aw_switches.h"
 #include "base/command_line.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/cookie_store_factory.h"
@@ -123,7 +124,11 @@
   if (!job_factory_) {
     scoped_ptr<AwURLRequestJobFactory> job_factory(new AwURLRequestJobFactory);
     bool set_protocol = job_factory->SetProtocolHandler(
-        chrome::kFileScheme, new net::FileProtocolHandler());
+        chrome::kFileScheme,
+        new net::FileProtocolHandler(
+            content::BrowserThread::GetBlockingPool()->
+                GetTaskRunnerWithShutdownBehavior(
+                    base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
     DCHECK(set_protocol);
     set_protocol = job_factory->SetProtocolHandler(
         chrome::kDataScheme, new net::DataProtocolHandler());
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 80cf4c6..df560c4 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -158,7 +158,9 @@
     // This can be accessed on any thread after construction. See AwContentsIoThreadClient.
     private final AwSettings mSettings;
 
-    private boolean mIsVisible;  // Equivalent to windowVisible && viewVisible.
+    private boolean mIsPaused;
+    private boolean mIsViewVisible;
+    private boolean mIsWindowVisible;
     private boolean mIsAttachedToWindow;
     private Bitmap mFavicon;
     private boolean mHasRequestedVisitedHistoryFromClient;
@@ -351,6 +353,7 @@
                 implements ContentViewCore.UpdateFrameInfoListener {
         @Override
         public void onFrameInfoUpdated(float widthCss, float heightCss, float pageScaleFactor) {
+            if (mNativeAwContents == 0) return;
             int widthPix = (int) Math.floor(widthCss * mDIPScale * pageScaleFactor);
             int heightPix = (int) Math.floor(heightCss * mDIPScale * pageScaleFactor);
             mScrollOffsetManager.setContentSize(widthPix, heightPix);
@@ -375,6 +378,7 @@
 
         @Override
         public void scrollNativeTo(int x, int y) {
+            if (mNativeAwContents == 0) return;
             nativeScrollTo(mNativeAwContents, x, y);
         }
 
@@ -445,6 +449,13 @@
                 isAccessFromFileURLsGrantedByDefault, new AwLayoutSizer());
     }
 
+    public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
+            InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
+            boolean isAccessFromFileURLsGrantedByDefault, AwLayoutSizer layoutSizer) {
+        this(browserContext, containerView, internalAccessAdapter, contentsClient,
+                isAccessFromFileURLsGrantedByDefault, layoutSizer, false);
+    }
+
     private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
             InternalAccessDelegate internalDispatcher, int nativeWebContents,
             ContentViewCore.GestureStateListener pinchGestureStateListener,
@@ -469,7 +480,8 @@
      */
     public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
             InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
-            boolean isAccessFromFileURLsGrantedByDefault, AwLayoutSizer layoutSizer) {
+            boolean isAccessFromFileURLsGrantedByDefault, AwLayoutSizer layoutSizer,
+            boolean supportsLegacyQuirks) {
         mBrowserContext = browserContext;
         mContainerView = containerView;
         mInternalAccessAdapter = internalAccessAdapter;
@@ -492,12 +504,14 @@
         AwSettings.ZoomSupportChangeListener zoomListener =
                 new AwSettings.ZoomSupportChangeListener() {
                     @Override
-                    public void onMultiTouchZoomSupportChanged(boolean supportsMultiTouchZoom) {
-                        mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
+                    public void onGestureZoomSupportChanged(boolean supportsGestureZoom) {
+                        mContentViewCore.updateMultiTouchZoomSupport(supportsGestureZoom);
+                        mContentViewCore.updateDoubleTapDragSupport(supportsGestureZoom);
                     }
+
                 };
         mSettings = new AwSettings(mContainerView.getContext(), hasInternetPermission, zoomListener,
-                isAccessFromFileURLsGrantedByDefault, mDIPScale);
+                isAccessFromFileURLsGrantedByDefault, mDIPScale, supportsLegacyQuirks);
         mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient);
         mSettings.setDefaultVideoPosterURL(
                 mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
@@ -576,14 +590,19 @@
     private void receivePopupContents(int popupNativeAwContents) {
         // Save existing view state.
         final boolean wasAttached = mIsAttachedToWindow;
-        final boolean wasVisible = getContainerViewVisible();
-        final boolean wasPaused = mUnimplementedIsPaused;
+        final boolean wasViewVisible = mIsViewVisible;
+        final boolean wasWindowVisible = mIsWindowVisible;
+        final boolean wasPaused = mIsPaused;
         final boolean wasFocused = mWindowFocused;
 
         // Properly clean up existing mContentViewCore and mNativeAwContents.
         if (wasFocused) onWindowFocusChanged(false);
-        if (wasVisible) setVisibilityInternal(false);
+        if (wasViewVisible) setViewVisibilityInternal(false);
+        if (wasWindowVisible) setWindowVisibilityInternal(false);
         if (!wasPaused) onPause();
+        // Not calling onDetachedFromWindow here because native code requires GL context to release
+        // GL resources. This case is properly handled when destroy is called while still attached
+        // to window.
 
         setNewAwContents(popupNativeAwContents);
 
@@ -591,7 +610,8 @@
         if (!wasPaused) onResume();
         if (wasAttached) onAttachedToWindow();
         onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
-        if (wasVisible) setVisibilityInternal(true);
+        if (wasWindowVisible) setWindowVisibilityInternal(true);
+        if (wasViewVisible) setViewVisibilityInternal(true);
         if (wasFocused) onWindowFocusChanged(true);
     }
 
@@ -660,6 +680,10 @@
     }
 
     public int getAwDrawGLViewContext() {
+        // Only called during early construction, so client should not have had a chance to
+        // call destroy yet.
+        assert mNativeAwContents != 0;
+
         // Using the native pointer as the returned viewContext. This is matched by the
         // reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction.
         return nativeGetAwDrawGLViewContext(mNativeAwContents);
@@ -671,6 +695,7 @@
 
     @CalledByNative
     private void updateGlobalVisibleRect() {
+        if (mNativeAwContents == 0) return;
         if (!mContainerView.getGlobalVisibleRect(sLocalGlobalVisibleRect)) {
             sLocalGlobalVisibleRect.setEmpty();
         }
@@ -724,6 +749,7 @@
     }
 
     public Picture capturePicture() {
+        if (mNativeAwContents == 0) return null;
         return new AwPicture(nativeCapturePicture(mNativeAwContents,
                     mScrollOffsetManager.computeHorizontalScrollRange(),
                     mScrollOffsetManager.computeVerticalScrollRange()));
@@ -735,6 +761,7 @@
      * @param invalidationOnly Flag to call back only on invalidation without providing a picture.
      */
     public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) {
+        if (mNativeAwContents == 0) return;
         if (invalidationOnly) {
             mPictureListenerContentProvider = null;
         } else if (enabled && mPictureListenerContentProvider == null) {
@@ -853,6 +880,7 @@
     }
 
     public void requestFocus() {
+        if (mNativeAwContents == 0) return;
         if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
             nativeFocusFirstNode(mNativeAwContents);
         }
@@ -874,7 +902,7 @@
     }
 
     public boolean isMultiTouchZoomSupported() {
-        return mSettings.supportsMultiTouchZoom();
+        return mSettings.supportsGestureZoom();
     }
 
     public View getZoomControlsForTest() {
@@ -937,7 +965,7 @@
      * @see View#overlayHorizontalScrollbar()
      */
     public boolean overlayHorizontalScrollbar() {
-        return mOverlayVerticalScrollbar;
+        return mOverlayHorizontalScrollbar;
     }
 
     /**
@@ -975,6 +1003,15 @@
     }
 
     /**
+     * @see WebView#requestChildRectangleOnScreen(View, Rect, boolean)
+     */
+    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
+        return mScrollOffsetManager.requestChildRectangleOnScreen(
+                child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY(),
+                rect, immediate);
+    }
+
+    /**
      * @see View.computeScroll()
      */
     public void computeScroll() {
@@ -1092,27 +1129,29 @@
         ContentViewStatics.setWebKitSharedTimersSuspended(false);
     }
 
-    private boolean mUnimplementedIsPaused;
-
     /**
      * @see android.webkit.WebView#onPause()
      */
     public void onPause() {
-        mUnimplementedIsPaused = true;
+        if (mIsPaused || mNativeAwContents == 0) return;
+        mIsPaused = true;
+        nativeSetIsPaused(mNativeAwContents, mIsPaused);
     }
 
     /**
      * @see android.webkit.WebView#onResume()
      */
     public void onResume() {
-        mUnimplementedIsPaused = false;
+        if (!mIsPaused || mNativeAwContents == 0) return;
+        mIsPaused = false;
+        nativeSetIsPaused(mNativeAwContents, mIsPaused);
     }
 
     /**
      * @see android.webkit.WebView#isPaused()
      */
     public boolean isPaused() {
-        return mUnimplementedIsPaused;
+        return mIsPaused;
     }
 
     /**
@@ -1336,7 +1375,7 @@
     }
 
     /**
-     * @see ContentViewCore.evaluateJavaScript(String, ContentViewCOre.JavaScriptCallback)
+     * @see ContentViewCore.evaluateJavaScript(String, ContentViewCore.JavaScriptCallback)
      */
     public void evaluateJavaScript(String script, final ValueCallback<String> callback) {
         ContentViewCore.JavaScriptCallback jsCallback = null;
@@ -1352,6 +1391,13 @@
         mContentViewCore.evaluateJavaScript(script, jsCallback);
     }
 
+    /**
+     * @see ContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(String)
+     */
+    public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
+        mContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(script);
+    }
+
     //--------------------------------------------------------------------------------------------
     //  View and ViewGroup method implementations
     //--------------------------------------------------------------------------------------------
@@ -1409,6 +1455,7 @@
      * Note that this is also called from receivePopupContents.
      */
     public void onAttachedToWindow() {
+        if (mNativeAwContents == 0) return;
         mIsAttachedToWindow = true;
 
         mContentViewCore.onAttachedToWindow();
@@ -1467,38 +1514,30 @@
      * @see android.view.View#onVisibilityChanged()
      */
     public void onVisibilityChanged(View changedView, int visibility) {
-        updateVisibilityState();
+        boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE;
+        if (mIsViewVisible == viewVisible) return;
+        setViewVisibilityInternal(viewVisible);
     }
 
     /**
      * @see android.view.View#onWindowVisibilityChanged()
      */
     public void onWindowVisibilityChanged(int visibility) {
-        updateVisibilityState();
+        boolean windowVisible = visibility == View.VISIBLE;
+        if (mIsWindowVisible == windowVisible) return;
+        setWindowVisibilityInternal(windowVisible);
     }
 
-    private void updateVisibilityState() {
-        boolean visible = getContainerViewVisible();
-        if (mIsVisible == visible) return;
-
-        setVisibilityInternal(visible);
-    }
-
-    private boolean getContainerViewVisible() {
-        boolean windowVisible = mContainerView.getWindowVisibility() == View.VISIBLE;
-        boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE;
-
-        return windowVisible && viewVisible;
-    }
-
-    private void setVisibilityInternal(boolean visible) {
-        // Note that this skips mIsVisible check and unconditionally sets
-        // visibility. In general, callers should use updateVisibilityState
-        // instead.
-        mIsVisible = visible;
-
+    private void setViewVisibilityInternal(boolean visible) {
+        mIsViewVisible = visible;
         if (mNativeAwContents == 0) return;
-        nativeSetVisibility(mNativeAwContents, mIsVisible);
+        nativeSetViewVisibility(mNativeAwContents, mIsViewVisible);
+    }
+
+    private void setWindowVisibilityInternal(boolean visible) {
+        mIsWindowVisible = visible;
+        if (mNativeAwContents == 0) return;
+        nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible);
     }
 
     /**
@@ -1511,7 +1550,7 @@
      * @return False if saving state failed.
      */
     public boolean saveState(Bundle outState) {
-        if (outState == null) return false;
+        if (mNativeAwContents == 0 || outState == null) return false;
 
         byte[] state = nativeGetOpaqueState(mNativeAwContents);
         if (state == null) return false;
@@ -1526,7 +1565,7 @@
      * @return False if restoring state failed.
      */
     public boolean restoreState(Bundle inState) {
-        if (inState == null) return false;
+        if (mNativeAwContents == 0 || inState == null) return false;
 
         byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
         if (state == null) return false;
@@ -1648,6 +1687,7 @@
                             mBrowserContext.getGeolocationPermissions().deny(origin);
                         }
                     }
+                    if (mNativeAwContents == 0) return;
                     nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin);
                 }
             });
@@ -1656,6 +1696,7 @@
 
     @CalledByNative
     private void onGeolocationPermissionsShowPrompt(String origin) {
+        if (mNativeAwContents == 0) return;
         AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions();
         // Reject if geoloaction is disabled, or the origin has a retained deny
         if (!mSettings.getGeolocationEnabled()) {
@@ -1851,7 +1892,9 @@
 
     private native void nativeOnSizeChanged(int nativeAwContents, int w, int h, int ow, int oh);
     private native void nativeScrollTo(int nativeAwContents, int x, int y);
-    private native void nativeSetVisibility(int nativeAwContents, boolean visible);
+    private native void nativeSetViewVisibility(int nativeAwContents, boolean visible);
+    private native void nativeSetWindowVisibility(int nativeAwContents, boolean visible);
+    private native void nativeSetIsPaused(int nativeAwContents, boolean paused);
     private native void nativeOnAttachedToWindow(int nativeAwContents, int w, int h);
     private static native void nativeOnDetachedFromWindow(int nativeAwContents);
     private native void nativeSetDipScale(int nativeAwContents, float dipScale);
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 14962ec..c792a18 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
@@ -8,6 +8,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemClock;
 
 import org.chromium.content.browser.ContentViewCore;
 
@@ -75,6 +76,13 @@
     private final static int MSG_ON_RECEIVED_ERROR = 5;
     private final static int MSG_ON_NEW_PICTURE = 6;
 
+    // Minimum period allowed between consecutive onNewPicture calls, to rate-limit the callbacks.
+    private static final long ON_NEW_PICTURE_MIN_PERIOD_MILLIS = 500;
+    // Timestamp of the most recent onNewPicture callback.
+    private long mLastPictureTime = 0;
+    // True when a onNewPicture callback is currenly in flight.
+    private boolean mHasPendingOnNewPicture = false;
+
     private final AwContentsClient mContentsClient;
 
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -116,6 +124,8 @@
                         throw new RuntimeException("Error getting picture", e);
                     }
                     mContentsClient.onNewPicture(picture);
+                    mLastPictureTime = SystemClock.uptimeMillis();
+                    mHasPendingOnNewPicture = false;
                     break;
                 }
                 default:
@@ -155,6 +165,11 @@
     }
 
     public void postOnNewPicture(Callable<Picture> pictureProvider) {
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_NEW_PICTURE, pictureProvider));
+        if (mHasPendingOnNewPicture) return;
+        mHasPendingOnNewPicture = true;
+        long pictureTime = java.lang.Math.max(mLastPictureTime + ON_NEW_PICTURE_MIN_PERIOD_MILLIS,
+                SystemClock.uptimeMillis());
+        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ON_NEW_PICTURE, pictureProvider),
+                pictureTime);
     }
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
index d94f55f..1eca5aa 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java
@@ -4,6 +4,7 @@
 
 package org.chromium.android_webview;
 
+import android.graphics.Rect;
 import android.widget.OverScroller;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -363,4 +364,66 @@
         // fine.
         return animateScrollTo(scrollX, scrollY + dy);
     }
+
+    /**
+     * See {@link WebView#requestChildRectangleOnScreen(View, Rect, boolean)}
+     */
+    public boolean requestChildRectangleOnScreen(int childOffsetX, int childOffsetY, Rect rect,
+            boolean immediate) {
+        // TODO(mkosiba): WebViewClassic immediately returns false if a zoom animation is
+        // in progress. We currently can't tell if one is happening.. should we instead cancel any
+        // scroll animation when the size/pageScaleFactor changes?
+
+        // TODO(mkosiba): Take scrollbar width into account in the screenRight/screenBotton
+        // calculations. http://crbug.com/269032
+
+        final int scrollX = mDelegate.getContainerViewScrollX();
+        final int scrollY = mDelegate.getContainerViewScrollY();
+
+        rect.offset(childOffsetX, childOffsetY);
+
+        int screenTop = scrollY;
+        int screenBottom = scrollY + mContainerViewHeight;
+        int scrollYDelta = 0;
+
+        if (rect.bottom > screenBottom) {
+            int oneThirdOfScreenHeight = mContainerViewHeight / 3;
+            if (rect.width() > 2 * oneThirdOfScreenHeight) {
+                // If the rectangle is too tall to fit in the bottom two thirds
+                // of the screen, place it at the top.
+                scrollYDelta = rect.top - screenTop;
+            } else {
+                // If the rectangle will still fit on screen, we want its
+                // top to be in the top third of the screen.
+                scrollYDelta = rect.top - (screenTop + oneThirdOfScreenHeight);
+            }
+        } else if (rect.top < screenTop) {
+            scrollYDelta = rect.top - screenTop;
+        }
+
+        int screenLeft = scrollX;
+        int screenRight = scrollX + mContainerViewWidth;
+        int scrollXDelta = 0;
+
+        if (rect.right > screenRight && rect.left > screenLeft) {
+            if (rect.width() > mContainerViewWidth) {
+                scrollXDelta += (rect.left - screenLeft);
+            } else {
+                scrollXDelta += (rect.right - screenRight);
+            }
+        } else if (rect.left < screenLeft) {
+            scrollXDelta -= (screenLeft - rect.left);
+        }
+
+        if (scrollYDelta == 0 && scrollXDelta == 0) {
+            return false;
+        }
+
+        if (immediate) {
+            scrollBy(scrollXDelta, scrollYDelta);
+            return true;
+        } else {
+            return animateScrollTo(scrollX + scrollXDelta, scrollY + scrollYDelta);
+        }
+    }
 }
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 b62cc4d..0247ed4 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -82,7 +82,7 @@
     private String mDefaultVideoPosterURL;
     private float mInitialPageScalePercent = 0;
 
-    private final boolean mSupportDeprecatedTargetDensityDPI = true;
+    private final boolean mSupportDeprecatedTargetDensityDPI;
 
     private final boolean mPasswordEchoEnabled;
 
@@ -169,13 +169,14 @@
     }
 
     interface ZoomSupportChangeListener {
-        public void onMultiTouchZoomSupportChanged(boolean supportsMultiTouchZoom);
+        public void onGestureZoomSupportChanged(boolean supportsGestureZoom);
     }
 
     public AwSettings(Context context, boolean hasInternetPermission,
             ZoomSupportChangeListener zoomChangeListener,
             boolean isAccessFromFileURLsGrantedByDefault,
-            double dipScale) {
+            double dipScale,
+            boolean supportsLegacyQuirks) {
         ThreadUtils.assertOnUiThread();
         synchronized (mAwSettingsLock) {
             mHasInternetPermission = hasInternetPermission;
@@ -190,11 +191,13 @@
             }
 
             mUserAgent = LazyDefaultUserAgent.sInstance;
-            onMultiTouchZoomSupportChanged(supportsMultiTouchZoomLocked());
+            onGestureZoomSupportChanged(supportsGestureZoomLocked());
 
             // Respect the system setting for password echoing.
             mPasswordEchoEnabled = Settings.System.getInt(context.getContentResolver(),
                     Settings.System.TEXT_SHOW_PASSWORD, 1) == 1;
+
+            mSupportDeprecatedTargetDensityDPI = supportsLegacyQuirks;
         }
         // Defer initializing the native side until a native WebContents instance is set.
     }
@@ -1249,12 +1252,12 @@
         return mDefaultVideoPosterURL;
     }
 
-    private void onMultiTouchZoomSupportChanged(final boolean supportsMultiTouchZoom) {
+    private void onGestureZoomSupportChanged(final boolean supportsGestureZoom) {
         // Always post asynchronously here, to avoid doubling back onto the caller.
         ThreadUtils.postOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mZoomChangeListener.onMultiTouchZoomSupportChanged(supportsMultiTouchZoom);
+                mZoomChangeListener.onGestureZoomSupportChanged(supportsGestureZoom);
             }
         });
     }
@@ -1266,7 +1269,7 @@
         synchronized (mAwSettingsLock) {
             if (mSupportZoom != support) {
                 mSupportZoom = support;
-                onMultiTouchZoomSupportChanged(supportsMultiTouchZoomLocked());
+                onGestureZoomSupportChanged(supportsGestureZoomLocked());
             }
         }
     }
@@ -1287,7 +1290,7 @@
         synchronized (mAwSettingsLock) {
             if (mBuiltInZoomControls != enabled) {
                 mBuiltInZoomControls = enabled;
-                onMultiTouchZoomSupportChanged(supportsMultiTouchZoomLocked());
+                onGestureZoomSupportChanged(supportsGestureZoomLocked());
             }
         }
     }
@@ -1319,20 +1322,20 @@
         }
     }
 
-    private boolean supportsMultiTouchZoomLocked() {
+    private boolean supportsGestureZoomLocked() {
         assert Thread.holdsLock(mAwSettingsLock);
         return mSupportZoom && mBuiltInZoomControls;
     }
 
-    boolean supportsMultiTouchZoom() {
+    boolean supportsGestureZoom() {
         synchronized (mAwSettingsLock) {
-            return supportsMultiTouchZoomLocked();
+            return supportsGestureZoomLocked();
         }
     }
 
     boolean shouldDisplayZoomControls() {
         synchronized (mAwSettingsLock) {
-            return supportsMultiTouchZoomLocked() && mDisplayZoomControls;
+            return supportsGestureZoomLocked() && mDisplayZoomControls;
         }
     }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
index c394774..b692820 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
@@ -5,11 +5,12 @@
 package org.chromium.android_webview.test;
 
 import android.content.Context;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.widget.OverScroller;
+import android.graphics.Rect;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View.MeasureSpec;
+import android.view.View;
+import android.widget.OverScroller;
 
 import org.chromium.android_webview.AwScrollOffsetManager;
 import org.chromium.base.test.util.Feature;
@@ -106,6 +107,15 @@
         offsetManager.onContainerViewOverScrolled(scrollX, scrollY, false, false);
     }
 
+    private void simlateOverScrollPropagation(AwScrollOffsetManager offsetManager,
+            TestScrollOffsetManagerDelegate delegate) {
+        assertTrue(delegate.getOverScrollCallCount() > 0);
+
+        offsetManager.onContainerViewOverScrolled(
+                delegate.getOverScrollDeltaX() + delegate.getScrollX(),
+                delegate.getOverScrollDeltaY() + delegate.getScrollY(), false, false);
+    }
+
     @SmallTest
     @Feature({"AndroidWebView"})
     public void testWhenContentSizeMatchesView() {
@@ -154,8 +164,8 @@
 
     private static final int VIEW_WIDTH = 211;
     private static final int VIEW_HEIGHT = 312;
-    private static final int MAX_HORIZONTAL_OFFSET = 61;
-    private static final int MAX_VERTICAL_OFFSET = 42;
+    private static final int MAX_HORIZONTAL_OFFSET = 757;
+    private static final int MAX_VERTICAL_OFFSET = 127;
     private static final int CONTENT_WIDTH = VIEW_WIDTH + MAX_HORIZONTAL_OFFSET;
     private static final int CONTENT_HEIGHT = VIEW_HEIGHT + MAX_VERTICAL_OFFSET;
 
@@ -235,8 +245,8 @@
     @SmallTest
     @Feature({"AndroidWebView"})
     public void testDelegateOverridenScrollsDontExceedBounds() {
-        final int overrideScrollX = 222;
-        final int overrideScrollY = 333;
+        final int overrideScrollX = MAX_HORIZONTAL_OFFSET + 10;
+        final int overrideScrollY = MAX_VERTICAL_OFFSET + 20;
         TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate() {
             @Override
             public int getContainerViewScrollX() {
@@ -351,4 +361,97 @@
         assertTrue(delegate.getInvalidateCount() == 2);
         assertEquals(111, (int) scroller.getCurrVelocity());
     }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testRequestChildRectangleOnScreenDontScrollIfAlreadyThere() {
+        TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
+        OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+        AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
+
+        offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT);
+        offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
+
+        offsetManager.requestChildRectangleOnScreen(0, 0,
+                new Rect(0, 0, VIEW_WIDTH / 4, VIEW_HEIGHT / 4), true);
+        assertEquals(0, delegate.getOverScrollDeltaX());
+        assertEquals(0, delegate.getOverScrollDeltaY());
+        assertEquals(0, delegate.getScrollX());
+        assertEquals(0, delegate.getScrollY());
+
+        offsetManager.requestChildRectangleOnScreen(3 * VIEW_WIDTH / 4, 3 * VIEW_HEIGHT / 4,
+                new Rect(0, 0, VIEW_WIDTH / 4, VIEW_HEIGHT / 4), true);
+        assertEquals(0, delegate.getOverScrollDeltaX());
+        assertEquals(0, delegate.getOverScrollDeltaY());
+        assertEquals(0, delegate.getScrollX());
+        assertEquals(0, delegate.getScrollY());
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testRequestChildRectangleOnScreenScrollToBottom() {
+        TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
+        OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+        AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
+
+        final int rectWidth = 2;
+        final int rectHeight = 3;
+
+        offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT);
+        offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
+
+        offsetManager.requestChildRectangleOnScreen(CONTENT_WIDTH - rectWidth,
+                CONTENT_HEIGHT - rectHeight, new Rect(0, 0, rectWidth, rectHeight), true);
+        simlateOverScrollPropagation(offsetManager, delegate);
+        assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getOverScrollDeltaX());
+        assertEquals(CONTENT_HEIGHT - rectHeight - VIEW_HEIGHT / 3, delegate.getOverScrollDeltaY());
+        assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
+        assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testRequestChildRectangleOnScreenScrollToBottomLargeRect() {
+        TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
+        OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+        AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
+
+        final int rectWidth = VIEW_WIDTH;
+        final int rectHeight = VIEW_HEIGHT;
+
+        offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT);
+        offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
+
+        offsetManager.requestChildRectangleOnScreen(CONTENT_WIDTH - rectWidth,
+                CONTENT_HEIGHT - rectHeight, new Rect(0, 0, rectWidth, rectHeight), true);
+        simlateOverScrollPropagation(offsetManager, delegate);
+        assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getOverScrollDeltaX());
+        assertEquals(MAX_VERTICAL_OFFSET, delegate.getOverScrollDeltaY());
+        assertEquals(MAX_HORIZONTAL_OFFSET, delegate.getScrollX());
+        assertEquals(MAX_VERTICAL_OFFSET, delegate.getScrollY());
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testRequestChildRectangleOnScreenScrollToTop() {
+        TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
+        OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+        AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
+
+        final int rectWidth = 2;
+        final int rectHeight = 3;
+
+        offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT);
+        offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
+        simulateScrolling(offsetManager, delegate,
+                CONTENT_WIDTH - VIEW_WIDTH, CONTENT_HEIGHT - VIEW_HEIGHT);
+
+        offsetManager.requestChildRectangleOnScreen(0, 0,
+                new Rect(0, 0, rectWidth, rectHeight), true);
+        simlateOverScrollPropagation(offsetManager, delegate);
+        assertEquals(-CONTENT_WIDTH + VIEW_WIDTH, delegate.getOverScrollDeltaX());
+        assertEquals(-CONTENT_HEIGHT + VIEW_HEIGHT, delegate.getOverScrollDeltaY());
+        assertEquals(0, delegate.getScrollX());
+        assertEquals(0, delegate.getScrollX());
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
index ace591c..3180969 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
@@ -1617,8 +1617,12 @@
         helper.ensureSettingHasInitialValue();
     }
 
-    @SmallTest
-    @Feature({"AndroidWebView", "Preferences"})
+    /**
+     * @SmallTest
+     * @Feature({"AndroidWebView", "Preferences"})
+     * crbug.com/277077
+     */
+    @DisabledTest
     public void testUniversalAccessFromFilesWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
@@ -1630,8 +1634,12 @@
 
     // This test verifies that local image resources can be loaded from file:
     // URLs regardless of file access state.
-    @SmallTest
-    @Feature({"AndroidWebView", "Preferences"})
+    /**
+     * @SmallTest
+     * @Feature({"AndroidWebView", "Preferences"})
+     * crbug.com/277077
+     */
+    @DisabledTest
     public void testFileAccessFromFilesImage() throws Throwable {
         final String imageContainerUrl = UrlUtils.getTestFileUrl("webview/image_access.html");
         final String imageHeight = "16";
@@ -1647,8 +1655,12 @@
         assertEquals(imageHeight, getTitleOnUiThread(awContents));
     }
 
-    @SmallTest
-    @Feature({"AndroidWebView", "Preferences"})
+    /**
+     * @SmallTest
+     * @Feature({"AndroidWebView", "Preferences"})
+     * crbug.com/277077
+     */
+    @DisabledTest
     public void testFileAccessFromFilesIframeWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
@@ -1658,8 +1670,12 @@
                 views.getContents1(), views.getClient1()));
     }
 
-    @SmallTest
-    @Feature({"AndroidWebView", "Preferences"})
+    /**
+     * @SmallTest
+     * @Feature({"AndroidWebView", "Preferences"})
+     * crbug.com/277077
+     */
+    @DisabledTest
     public void testFileAccessFromFilesXhrWithTwoViews() throws Throwable {
         ViewPair views = createViews();
         runPerViewSettingsTest(
@@ -2436,22 +2452,14 @@
         }
     }
 
-    /*
     @LargeTest
     @Feature({"AndroidWebView", "Preferences"})
-    Disabled until video is working. crbug.com/239760
-    */
-    @DisabledTest
     public void testMediaPlaybackWithoutUserGesture() throws Throwable {
         assertTrue(runVideoTest(false, -1));
     }
 
-    /*
     @SmallTest
     @Feature({"AndroidWebView", "Preferences"})
-    Disabled until video is working. crbug.com/239760
-    */
-    @DisabledTest
     public void testMediaPlaybackWithUserGesture() throws Throwable {
         // Wait for 5 second to see if video played.
         assertFalse(runVideoTest(true, 5000));
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 0bb148e..29906b5 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
@@ -226,9 +226,11 @@
         final TestDependencyFactory testDependencyFactory = createTestDependencyFactory();
         final AwTestContainerView testContainerView =
             testDependencyFactory.createAwTestContainerView(getActivity());
+        // TODO(mnaganov): Should also have tests for the "pure Chromium" mode.
+        // See http://crbug.com/278106
         testContainerView.initialize(new AwContents(
                 mBrowserContext, testContainerView, testContainerView.getInternalAccessDelegate(),
-                awContentsClient, false, testDependencyFactory.createLayoutSizer()));
+                awContentsClient, false, testDependencyFactory.createLayoutSizer(), true));
         return testContainerView;
     }
 
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index 6344b1f..6843a74 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -46,7 +46,7 @@
 bool AwMainDelegate::BasicStartupComplete(int* exit_code) {
   content::SetContentClient(&content_client_);
 
-  gpu::GLInProcessContext::SetGpuMemoryBufferFactory(
+  gpu::InProcessCommandBuffer::SetGpuMemoryBufferFactory(
       gpu_memory_buffer_factory_.get());
   gpu::InProcessCommandBuffer::EnableVirtualizedContext();
 
@@ -62,6 +62,9 @@
   // Not yet secure in single-process mode.
   cl->AppendSwitch(switches::kDisableExperimentalWebGL);
 
+  // Ganesh backed 2D-Canvas is not yet working and causes crashes.
+  cl->AppendSwitch(switches::kDisableAccelerated2dCanvas);
+
   return false;
 }
 
diff --git a/android_webview/libwebviewchromium.target.darwin-arm.mk b/android_webview/libwebviewchromium.target.darwin-arm.mk
index fe7c5a0..b0ce2c2 100644
--- a/android_webview/libwebviewchromium.target.darwin-arm.mk
+++ b/android_webview/libwebviewchromium.target.darwin-arm.mk
@@ -167,7 +167,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_browser_gyp)/content_content_browser_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_browser_speech_proto_speech_proto_gyp)/content_browser_speech_proto_speech_proto_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,google_apis_google_apis_gyp)/google_apis_google_apis_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_zip_gyp)/third_party_zlib_zip_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_google_zip_gyp)/third_party_zlib_google_zip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_minizip_gyp)/third_party_zlib_minizip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_snapshot_snapshot_gyp)/ui_snapshot_snapshot_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_gpu_gyp)/content_content_gpu_gyp.a \
@@ -190,6 +190,7 @@
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_profiles_js_gyp)/concatenated_devtools_profiles_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_audits_js_gyp)/concatenated_devtools_audits_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_codemirror_js_gyp)/concatenated_devtools_codemirror_js.stamp \
+	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_layers_js_gyp)/concatenated_devtools_layers_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_heap_snapshot_worker_js_gyp)/concatenated_heap_snapshot_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_script_formatter_worker_js_gyp)/concatenated_script_formatter_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_css_gyp)/concatenated_devtools_css.stamp \
@@ -215,7 +216,6 @@
 	$(call intermediates-dir-for,GYP,jingle_jingle_glue_gyp)/jingle_glue.stamp \
 	$(call intermediates-dir-for,GYP,third_party_widevine_cdm_widevine_cdm_version_h_gyp)/widevine_cdm_version_h.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_renderer_webkit_renderer_gyp)/webkit_renderer_webkit_renderer_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_webkit_storage_renderer_gyp)/webkit_webkit_storage_renderer_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_navigation_interception_gyp)/components_navigation_interception_gyp.a \
 	$(call intermediates-dir-for,GYP,components_navigation_interception_jni_headers_gyp)/navigation_interception_jni_headers.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_visitedlink_browser_gyp)/components_visitedlink_browser_gyp.a \
@@ -554,7 +554,7 @@
 	content_content_browser_gyp \
 	content_browser_speech_proto_speech_proto_gyp \
 	google_apis_google_apis_gyp \
-	third_party_zlib_zip_gyp \
+	third_party_zlib_google_zip_gyp \
 	third_party_zlib_minizip_gyp \
 	ui_snapshot_snapshot_gyp \
 	content_content_gpu_gyp \
@@ -576,7 +576,6 @@
 	components_autofill_content_renderer_gyp \
 	content_content_renderer_gyp \
 	webkit_renderer_webkit_renderer_gyp \
-	webkit_webkit_storage_renderer_gyp \
 	components_navigation_interception_gyp \
 	components_visitedlink_browser_gyp \
 	components_visitedlink_common_gyp \
diff --git a/android_webview/libwebviewchromium.target.darwin-mips.mk b/android_webview/libwebviewchromium.target.darwin-mips.mk
index f153051..1fa1577 100644
--- a/android_webview/libwebviewchromium.target.darwin-mips.mk
+++ b/android_webview/libwebviewchromium.target.darwin-mips.mk
@@ -165,7 +165,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_browser_gyp)/content_content_browser_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_browser_speech_proto_speech_proto_gyp)/content_browser_speech_proto_speech_proto_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,google_apis_google_apis_gyp)/google_apis_google_apis_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_zip_gyp)/third_party_zlib_zip_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_google_zip_gyp)/third_party_zlib_google_zip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_minizip_gyp)/third_party_zlib_minizip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_snapshot_snapshot_gyp)/ui_snapshot_snapshot_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_gpu_gyp)/content_content_gpu_gyp.a \
@@ -188,6 +188,7 @@
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_profiles_js_gyp)/concatenated_devtools_profiles_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_audits_js_gyp)/concatenated_devtools_audits_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_codemirror_js_gyp)/concatenated_devtools_codemirror_js.stamp \
+	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_layers_js_gyp)/concatenated_devtools_layers_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_heap_snapshot_worker_js_gyp)/concatenated_heap_snapshot_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_script_formatter_worker_js_gyp)/concatenated_script_formatter_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_css_gyp)/concatenated_devtools_css.stamp \
@@ -211,7 +212,6 @@
 	$(call intermediates-dir-for,GYP,jingle_jingle_glue_gyp)/jingle_glue.stamp \
 	$(call intermediates-dir-for,GYP,third_party_widevine_cdm_widevine_cdm_version_h_gyp)/widevine_cdm_version_h.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_renderer_webkit_renderer_gyp)/webkit_renderer_webkit_renderer_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_webkit_storage_renderer_gyp)/webkit_webkit_storage_renderer_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_navigation_interception_gyp)/components_navigation_interception_gyp.a \
 	$(call intermediates-dir-for,GYP,components_navigation_interception_jni_headers_gyp)/navigation_interception_jni_headers.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_visitedlink_browser_gyp)/components_visitedlink_browser_gyp.a \
@@ -541,7 +541,7 @@
 	content_content_browser_gyp \
 	content_browser_speech_proto_speech_proto_gyp \
 	google_apis_google_apis_gyp \
-	third_party_zlib_zip_gyp \
+	third_party_zlib_google_zip_gyp \
 	third_party_zlib_minizip_gyp \
 	ui_snapshot_snapshot_gyp \
 	content_content_gpu_gyp \
@@ -562,7 +562,6 @@
 	components_autofill_content_renderer_gyp \
 	content_content_renderer_gyp \
 	webkit_renderer_webkit_renderer_gyp \
-	webkit_webkit_storage_renderer_gyp \
 	components_navigation_interception_gyp \
 	components_visitedlink_browser_gyp \
 	components_visitedlink_common_gyp \
diff --git a/android_webview/libwebviewchromium.target.darwin-x86.mk b/android_webview/libwebviewchromium.target.darwin-x86.mk
index 5bc5e16..c387e0b 100644
--- a/android_webview/libwebviewchromium.target.darwin-x86.mk
+++ b/android_webview/libwebviewchromium.target.darwin-x86.mk
@@ -171,7 +171,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_browser_gyp)/content_content_browser_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_browser_speech_proto_speech_proto_gyp)/content_browser_speech_proto_speech_proto_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,google_apis_google_apis_gyp)/google_apis_google_apis_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_zip_gyp)/third_party_zlib_zip_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_google_zip_gyp)/third_party_zlib_google_zip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_minizip_gyp)/third_party_zlib_minizip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_snapshot_snapshot_gyp)/ui_snapshot_snapshot_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_gpu_gyp)/content_content_gpu_gyp.a \
@@ -194,6 +194,7 @@
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_profiles_js_gyp)/concatenated_devtools_profiles_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_audits_js_gyp)/concatenated_devtools_audits_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_codemirror_js_gyp)/concatenated_devtools_codemirror_js.stamp \
+	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_layers_js_gyp)/concatenated_devtools_layers_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_heap_snapshot_worker_js_gyp)/concatenated_heap_snapshot_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_script_formatter_worker_js_gyp)/concatenated_script_formatter_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_css_gyp)/concatenated_devtools_css.stamp \
@@ -219,7 +220,6 @@
 	$(call intermediates-dir-for,GYP,jingle_jingle_glue_gyp)/jingle_glue.stamp \
 	$(call intermediates-dir-for,GYP,third_party_widevine_cdm_widevine_cdm_version_h_gyp)/widevine_cdm_version_h.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_renderer_webkit_renderer_gyp)/webkit_renderer_webkit_renderer_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_webkit_storage_renderer_gyp)/webkit_webkit_storage_renderer_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_navigation_interception_gyp)/components_navigation_interception_gyp.a \
 	$(call intermediates-dir-for,GYP,components_navigation_interception_jni_headers_gyp)/navigation_interception_jni_headers.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_visitedlink_browser_gyp)/components_visitedlink_browser_gyp.a \
@@ -561,7 +561,7 @@
 	content_content_browser_gyp \
 	content_browser_speech_proto_speech_proto_gyp \
 	google_apis_google_apis_gyp \
-	third_party_zlib_zip_gyp \
+	third_party_zlib_google_zip_gyp \
 	third_party_zlib_minizip_gyp \
 	ui_snapshot_snapshot_gyp \
 	content_content_gpu_gyp \
@@ -583,7 +583,6 @@
 	components_autofill_content_renderer_gyp \
 	content_content_renderer_gyp \
 	webkit_renderer_webkit_renderer_gyp \
-	webkit_webkit_storage_renderer_gyp \
 	components_navigation_interception_gyp \
 	components_visitedlink_browser_gyp \
 	components_visitedlink_common_gyp \
diff --git a/android_webview/libwebviewchromium.target.linux-arm.mk b/android_webview/libwebviewchromium.target.linux-arm.mk
index fe7c5a0..b0ce2c2 100644
--- a/android_webview/libwebviewchromium.target.linux-arm.mk
+++ b/android_webview/libwebviewchromium.target.linux-arm.mk
@@ -167,7 +167,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_browser_gyp)/content_content_browser_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_browser_speech_proto_speech_proto_gyp)/content_browser_speech_proto_speech_proto_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,google_apis_google_apis_gyp)/google_apis_google_apis_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_zip_gyp)/third_party_zlib_zip_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_google_zip_gyp)/third_party_zlib_google_zip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_minizip_gyp)/third_party_zlib_minizip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_snapshot_snapshot_gyp)/ui_snapshot_snapshot_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_gpu_gyp)/content_content_gpu_gyp.a \
@@ -190,6 +190,7 @@
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_profiles_js_gyp)/concatenated_devtools_profiles_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_audits_js_gyp)/concatenated_devtools_audits_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_codemirror_js_gyp)/concatenated_devtools_codemirror_js.stamp \
+	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_layers_js_gyp)/concatenated_devtools_layers_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_heap_snapshot_worker_js_gyp)/concatenated_heap_snapshot_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_script_formatter_worker_js_gyp)/concatenated_script_formatter_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_css_gyp)/concatenated_devtools_css.stamp \
@@ -215,7 +216,6 @@
 	$(call intermediates-dir-for,GYP,jingle_jingle_glue_gyp)/jingle_glue.stamp \
 	$(call intermediates-dir-for,GYP,third_party_widevine_cdm_widevine_cdm_version_h_gyp)/widevine_cdm_version_h.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_renderer_webkit_renderer_gyp)/webkit_renderer_webkit_renderer_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_webkit_storage_renderer_gyp)/webkit_webkit_storage_renderer_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_navigation_interception_gyp)/components_navigation_interception_gyp.a \
 	$(call intermediates-dir-for,GYP,components_navigation_interception_jni_headers_gyp)/navigation_interception_jni_headers.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_visitedlink_browser_gyp)/components_visitedlink_browser_gyp.a \
@@ -554,7 +554,7 @@
 	content_content_browser_gyp \
 	content_browser_speech_proto_speech_proto_gyp \
 	google_apis_google_apis_gyp \
-	third_party_zlib_zip_gyp \
+	third_party_zlib_google_zip_gyp \
 	third_party_zlib_minizip_gyp \
 	ui_snapshot_snapshot_gyp \
 	content_content_gpu_gyp \
@@ -576,7 +576,6 @@
 	components_autofill_content_renderer_gyp \
 	content_content_renderer_gyp \
 	webkit_renderer_webkit_renderer_gyp \
-	webkit_webkit_storage_renderer_gyp \
 	components_navigation_interception_gyp \
 	components_visitedlink_browser_gyp \
 	components_visitedlink_common_gyp \
diff --git a/android_webview/libwebviewchromium.target.linux-mips.mk b/android_webview/libwebviewchromium.target.linux-mips.mk
index f153051..1fa1577 100644
--- a/android_webview/libwebviewchromium.target.linux-mips.mk
+++ b/android_webview/libwebviewchromium.target.linux-mips.mk
@@ -165,7 +165,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_browser_gyp)/content_content_browser_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_browser_speech_proto_speech_proto_gyp)/content_browser_speech_proto_speech_proto_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,google_apis_google_apis_gyp)/google_apis_google_apis_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_zip_gyp)/third_party_zlib_zip_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_google_zip_gyp)/third_party_zlib_google_zip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_minizip_gyp)/third_party_zlib_minizip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_snapshot_snapshot_gyp)/ui_snapshot_snapshot_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_gpu_gyp)/content_content_gpu_gyp.a \
@@ -188,6 +188,7 @@
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_profiles_js_gyp)/concatenated_devtools_profiles_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_audits_js_gyp)/concatenated_devtools_audits_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_codemirror_js_gyp)/concatenated_devtools_codemirror_js.stamp \
+	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_layers_js_gyp)/concatenated_devtools_layers_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_heap_snapshot_worker_js_gyp)/concatenated_heap_snapshot_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_script_formatter_worker_js_gyp)/concatenated_script_formatter_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_css_gyp)/concatenated_devtools_css.stamp \
@@ -211,7 +212,6 @@
 	$(call intermediates-dir-for,GYP,jingle_jingle_glue_gyp)/jingle_glue.stamp \
 	$(call intermediates-dir-for,GYP,third_party_widevine_cdm_widevine_cdm_version_h_gyp)/widevine_cdm_version_h.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_renderer_webkit_renderer_gyp)/webkit_renderer_webkit_renderer_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_webkit_storage_renderer_gyp)/webkit_webkit_storage_renderer_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_navigation_interception_gyp)/components_navigation_interception_gyp.a \
 	$(call intermediates-dir-for,GYP,components_navigation_interception_jni_headers_gyp)/navigation_interception_jni_headers.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_visitedlink_browser_gyp)/components_visitedlink_browser_gyp.a \
@@ -541,7 +541,7 @@
 	content_content_browser_gyp \
 	content_browser_speech_proto_speech_proto_gyp \
 	google_apis_google_apis_gyp \
-	third_party_zlib_zip_gyp \
+	third_party_zlib_google_zip_gyp \
 	third_party_zlib_minizip_gyp \
 	ui_snapshot_snapshot_gyp \
 	content_content_gpu_gyp \
@@ -562,7 +562,6 @@
 	components_autofill_content_renderer_gyp \
 	content_content_renderer_gyp \
 	webkit_renderer_webkit_renderer_gyp \
-	webkit_webkit_storage_renderer_gyp \
 	components_navigation_interception_gyp \
 	components_visitedlink_browser_gyp \
 	components_visitedlink_common_gyp \
diff --git a/android_webview/libwebviewchromium.target.linux-x86.mk b/android_webview/libwebviewchromium.target.linux-x86.mk
index 5bc5e16..c387e0b 100644
--- a/android_webview/libwebviewchromium.target.linux-x86.mk
+++ b/android_webview/libwebviewchromium.target.linux-x86.mk
@@ -171,7 +171,7 @@
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_browser_gyp)/content_content_browser_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_browser_speech_proto_speech_proto_gyp)/content_browser_speech_proto_speech_proto_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,google_apis_google_apis_gyp)/google_apis_google_apis_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_zip_gyp)/third_party_zlib_zip_gyp.a \
+	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_google_zip_gyp)/third_party_zlib_google_zip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,third_party_zlib_minizip_gyp)/third_party_zlib_minizip_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,ui_snapshot_snapshot_gyp)/ui_snapshot_snapshot_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,content_content_gpu_gyp)/content_content_gpu_gyp.a \
@@ -194,6 +194,7 @@
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_profiles_js_gyp)/concatenated_devtools_profiles_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_audits_js_gyp)/concatenated_devtools_audits_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_codemirror_js_gyp)/concatenated_devtools_codemirror_js.stamp \
+	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_layers_js_gyp)/concatenated_devtools_layers_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_heap_snapshot_worker_js_gyp)/concatenated_heap_snapshot_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_script_formatter_worker_js_gyp)/concatenated_script_formatter_worker_js.stamp \
 	$(call intermediates-dir-for,GYP,third_party_WebKit_Source_devtools_concatenated_devtools_css_gyp)/concatenated_devtools_css.stamp \
@@ -219,7 +220,6 @@
 	$(call intermediates-dir-for,GYP,jingle_jingle_glue_gyp)/jingle_glue.stamp \
 	$(call intermediates-dir-for,GYP,third_party_widevine_cdm_widevine_cdm_version_h_gyp)/widevine_cdm_version_h.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_renderer_webkit_renderer_gyp)/webkit_renderer_webkit_renderer_gyp.a \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,webkit_webkit_storage_renderer_gyp)/webkit_webkit_storage_renderer_gyp.a \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_navigation_interception_gyp)/components_navigation_interception_gyp.a \
 	$(call intermediates-dir-for,GYP,components_navigation_interception_jni_headers_gyp)/navigation_interception_jni_headers.stamp \
 	$(call intermediates-dir-for,STATIC_LIBRARIES,components_visitedlink_browser_gyp)/components_visitedlink_browser_gyp.a \
@@ -561,7 +561,7 @@
 	content_content_browser_gyp \
 	content_browser_speech_proto_speech_proto_gyp \
 	google_apis_google_apis_gyp \
-	third_party_zlib_zip_gyp \
+	third_party_zlib_google_zip_gyp \
 	third_party_zlib_minizip_gyp \
 	ui_snapshot_snapshot_gyp \
 	content_content_gpu_gyp \
@@ -583,7 +583,6 @@
 	components_autofill_content_renderer_gyp \
 	content_content_renderer_gyp \
 	webkit_renderer_webkit_renderer_gyp \
-	webkit_webkit_storage_renderer_gyp \
 	components_navigation_interception_gyp \
 	components_visitedlink_browser_gyp \
 	components_visitedlink_common_gyp \
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 4cabfe4..e6cf841 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -606,8 +606,16 @@
   browser_view_renderer_->OnSizeChanged(w, h);
 }
 
-void AwContents::SetVisibility(JNIEnv* env, jobject obj, bool visible) {
-  browser_view_renderer_->OnVisibilityChanged(visible);
+void AwContents::SetViewVisibility(JNIEnv* env, jobject obj, bool visible) {
+  browser_view_renderer_->SetViewVisibility(visible);
+}
+
+void AwContents::SetWindowVisibility(JNIEnv* env, jobject obj, bool visible) {
+  browser_view_renderer_->SetWindowVisibility(visible);
+}
+
+void AwContents::SetIsPaused(JNIEnv* env, jobject obj, bool paused) {
+  browser_view_renderer_->SetIsPaused(paused);
 }
 
 void AwContents::OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h) {
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 38b433d..24dff4f 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -92,7 +92,9 @@
   void RequestNewHitTestDataAt(JNIEnv* env, jobject obj, jint x, jint y);
   void UpdateLastHitTestData(JNIEnv* env, jobject obj);
   void OnSizeChanged(JNIEnv* env, jobject obj, int w, int h, int ow, int oh);
-  void SetVisibility(JNIEnv* env, jobject obj, bool visible);
+  void SetViewVisibility(JNIEnv* env, jobject obj, bool visible);
+  void SetWindowVisibility(JNIEnv* env, jobject obj, bool visible);
+  void SetIsPaused(JNIEnv* env, jobject obj, bool paused);
   void OnAttachedToWindow(JNIEnv* env, jobject obj, int w, int h);
   void OnDetachedFromWindow(JNIEnv* env, jobject obj);
   base::android::ScopedJavaLocalRef<jbyteArray> GetOpaqueState(
diff --git a/android_webview/native/aw_settings.cc b/android_webview/native/aw_settings.cc
index a425402..f47b20b 100644
--- a/android_webview/native/aw_settings.cc
+++ b/android_webview/native/aw_settings.cc
@@ -206,13 +206,6 @@
   prefs.support_deprecated_target_density_dpi =
       Java_AwSettings_getSupportDeprecatedTargetDensityDPILocked(env, obj);
 
-  // TODO(primiano): deferred image decoding seems to cause increased memory
-  // usage in WebView chromium after http://crrev.com/19838002  (at least on
-  // some tests, for instance +18MB on moz and moz2). Thus, deferred image
-  // decoding is being disabled until the root of the problem is found.
-  // See http://crbug.com/262957 .
-  prefs.deferred_image_decoding_enabled = false;
-
   prefs.password_echo_enabled =
       Java_AwSettings_getPasswordEchoEnabled(env, obj);
 
diff --git a/android_webview/renderer/aw_render_view_ext.cc b/android_webview/renderer/aw_render_view_ext.cc
index 056bf69..14cbb17 100644
--- a/android_webview/renderer/aw_render_view_ext.cc
+++ b/android_webview/renderer/aw_render_view_ext.cc
@@ -24,6 +24,7 @@
 #include "third_party/WebKit/public/web/WebElement.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebHitTestResult.h"
+#include "third_party/WebKit/public/web/WebImageCache.h"
 #include "third_party/WebKit/public/web/WebNode.h"
 #include "third_party/WebKit/public/web/WebNodeList.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
@@ -121,7 +122,7 @@
     data->img_src = absolute_image_url;
 
   const bool is_javascript_scheme =
-      absolute_link_url.SchemeIs(chrome::kJavaScriptScheme);
+      absolute_link_url.SchemeIs(content::kJavaScriptScheme);
   const bool has_link_url = !absolute_link_url.is_empty();
   const bool has_image_url = !absolute_image_url.is_empty();
 
@@ -221,6 +222,17 @@
   }
 }
 
+void AwRenderViewExt::Navigate(const GURL& url) {
+  // Navigate is called only on NEW navigations, so WebImageCache won't be freed
+  // when the user just clicks on links, but only when a navigation is started,
+  // for instance via loadUrl. A better approach would be clearing the cache on
+  // cross-site boundaries, however this would require too many changes both on
+  // the browser side (in RenderViewHostManger), to the IPCmessages and to the
+  // RenderViewObserver. Thus, clearing decoding image cache on Navigate, seems
+  // a more acceptable compromise.
+  WebKit::WebImageCache::clear();
+}
+
 void AwRenderViewExt::FocusedNodeChanged(const WebKit::WebNode& node) {
   if (node.isNull() || !node.isElementNode() || !render_view())
     return;
diff --git a/android_webview/renderer/aw_render_view_ext.h b/android_webview/renderer/aw_render_view_ext.h
index 744c045..031d513 100644
--- a/android_webview/renderer/aw_render_view_ext.h
+++ b/android_webview/renderer/aw_render_view_ext.h
@@ -38,6 +38,7 @@
                                         bool is_new_navigation) OVERRIDE;
   virtual void FocusedNodeChanged(const WebKit::WebNode& node) OVERRIDE;
   virtual void DidCommitCompositorFrame() OVERRIDE;
+  virtual void Navigate(const GURL& url) OVERRIDE;
 
   void OnDocumentHasImagesRequest(int id);
 
diff --git a/android_webview/test/shell/AndroidManifest.xml b/android_webview/test/shell/AndroidManifest.xml
index 0b10eea..5e6c541 100644
--- a/android_webview/test/shell/AndroidManifest.xml
+++ b/android_webview/test/shell/AndroidManifest.xml
@@ -32,4 +32,5 @@
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
   <uses-permission android:name="android.permission.INTERNET"/>
   <uses-permission android:name="android.permission.WAKE_LOCK"/>
+  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 </manifest>
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java
index a252627..1e1a3eb 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java
@@ -29,6 +29,7 @@
 import org.chromium.android_webview.AwBrowserContext;
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.AwContentsClient;
+import org.chromium.android_webview.AwLayoutSizer;
 import org.chromium.android_webview.test.AwTestContainerView;
 import org.chromium.android_webview.test.NullContentsClient;
 import org.chromium.content.browser.LoadUrlParams;
@@ -89,7 +90,7 @@
         }
         testContainerView.initialize(new AwContents(mBrowserContext, testContainerView,
                 testContainerView.getInternalAccessDelegate(),
-                awContentsClient, false));
+                awContentsClient, false, new AwLayoutSizer(), true));
         testContainerView.getAwContents().getSettings().setJavaScriptEnabled(true);
         return testContainerView;
     }
diff --git a/android_webview/tools/third_party_files_whitelist.txt b/android_webview/tools/third_party_files_whitelist.txt
index 8438515..60b6542 100644
--- a/android_webview/tools/third_party_files_whitelist.txt
+++ b/android_webview/tools/third_party_files_whitelist.txt
@@ -110,8 +110,6 @@
 # v2) licenses. This third-party code is taken from Mozilla, the license for
 # which we already pick up from third_party/npapi/.
 net/base/registry_controlled_domains/registry_controlled_domain.h
-# Copyright John LoVerso; no license. Test code only.
-net/data/proxy_resolver_perftest/no-ads.pac
 # Copyright The Chromium Authors and IBM Corporation; BSD and (MPL, GPL v2 or
 # LGPL v2) licenses. This third-party code is taken from Mozilla, the license
 # for which we already pick up from third_party/npapi/.
@@ -177,10 +175,6 @@
 # This third-party code is taken from Mozilla, but is copyright Google and has
 # been re-licensed under the Chromium license.
 ui/gfx/codec/png_codec.cc
-# Copyright Netscape Communications Corporation; MPL, GPL v2 or LGPL v2
-# license. This third-party code is taken from Mozilla, the license for which
-# we already pick up from third_party/npapi/.
-url/url_parse.cc
 # Copyright The Chromium Authors and Apple Inc; BSD license. This third-party
 # code is taken from WebKit, the license for which we already pick up from
 # webkit/.
@@ -196,7 +190,3 @@
 # Copyright Tim Copperfield and Christian Dywan; LGPL license. Not used on
 # Android.
 webkit/common/cursors/webcursor_gtk_data.h
-# Copyright Apple, Inc, Graham Dennis and Eric Seidel; BSD license. Tool only
-webkit/support/mac/DumpRenderTreePasteboard.h
-# Copyright Apple, Inc, Graham Dennis and Eric Seidel; BSD license. Tool only
-webkit/support/mac/DumpRenderTreePasteboard.m
diff --git a/android_webview/tools/webview_licenses.py b/android_webview/tools/webview_licenses.py
index d5afe61..aa4f28f 100755
--- a/android_webview/tools/webview_licenses.py
+++ b/android_webview/tools/webview_licenses.py
@@ -109,6 +109,9 @@
   excluded_dirs_list.append('data/dom_perf')
   # Histogram tools, doesn't exist in the snapshot
   excluded_dirs_list.append('tools/histograms')
+  # swarm_client is a third_party and not used on Android.
+  excluded_dirs_list.append('tools/swarm_client')
+  excluded_dirs_list.append('tools/swarming_client')
   # Arm sysroot tools, doesn't exist in the snapshot
   excluded_dirs_list.append('arm-sysroot')
   # Data is not part of open source chromium, but are included on some bots.
diff --git a/apps/DEPS b/apps/DEPS
index 7920f1a..ff58a2c 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -12,6 +12,7 @@
   "+win8",
   # Temporary allowed includes.
   # TODO(benwells): remove these (http://crbug.com/159366)
+  "+chrome/browser/apps/app_browsertest_util.h",
   "+chrome/browser/browser_process.h",
   "+chrome/browser/browser_shutdown.h",
   "+chrome/browser/chrome_notification_types.h",
@@ -20,7 +21,7 @@
   "+chrome/browser/lifetime/application_lifetime.h",
   "+chrome/browser/profiles",
   "+chrome/browser/sessions/session_id.h",
-  "+chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h",
+  "+chrome/browser/ui/apps/app_metro_infobar_delegate_win.h",
   "+chrome/browser/ui/host_desktop.h",
   "+chrome/common/chrome_switches.h",
   "+chrome/common/extensions",
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc
index c3bac8f..88ceb65 100644
--- a/apps/app_restore_service_browsertest.cc
+++ b/apps/app_restore_service_browsertest.cc
@@ -5,11 +5,11 @@
 #include "apps/app_restore_service.h"
 #include "apps/app_restore_service_factory.h"
 #include "apps/saved_files_service.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
diff --git a/apps/app_shim/DEPS b/apps/app_shim/DEPS
index 4a6173f..7e718d7 100644
--- a/apps/app_shim/DEPS
+++ b/apps/app_shim/DEPS
@@ -3,6 +3,7 @@
   # See http://crbug.com/266705.
   "+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",
diff --git a/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm b/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
index f16caef..5b5dad6 100644
--- a/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
+++ b/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
@@ -9,11 +9,11 @@
 #include "apps/app_shim/app_shim_host_manager_mac.h"
 #include "apps/app_shim/extension_app_shim_handler_mac.h"
 #include "apps/switches.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/interactive_test_utils.h"
diff --git a/apps/app_shim/extension_app_shim_handler_mac.cc b/apps/app_shim/extension_app_shim_handler_mac.cc
index 130c7f1..8fe8f6b 100644
--- a/apps/app_shim/extension_app_shim_handler_mac.cc
+++ b/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -22,7 +22,9 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/web_applications/web_app_ui.h"
+#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
 #include "chrome/browser/web_applications/web_app_mac.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_source.h"
@@ -107,6 +109,8 @@
 void ExtensionAppShimHandler::Delegate::LaunchApp(
     Profile* profile,
     const extensions::Extension* extension) {
+  CoreAppLauncherHandler::RecordAppLaunchType(
+      extension_misc::APP_LAUNCH_CMD_LINE_APP, extension->GetType());
   chrome::OpenApplication(
       chrome::AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB));
 }
diff --git a/apps/launcher.cc b/apps/launcher.cc
index 9ebb46e..e5990a5 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h"
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_prefs.h"
@@ -23,7 +22,8 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h"
+#include "chrome/browser/ui/apps/app_metro_infobar_delegate_win.h"
+#include "chrome/common/extensions/api/app_runtime.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "content/public/browser/browser_thread.h"
@@ -43,6 +43,8 @@
 #include "win8/util/win8_util.h"
 #endif
 
+namespace app_runtime = extensions::api::app_runtime;
+
 using content::BrowserThread;
 using extensions::app_file_handler_util::FileHandlerForId;
 using extensions::app_file_handler_util::FileHandlerCanHandleFile;
@@ -342,7 +344,7 @@
       ExtensionSystem::Get(profile)->event_router();
   bool listening_to_restart = event_router->
       ExtensionHasEventListener(extension->id(),
-                                extensions::event_names::kOnRestarted);
+                                app_runtime::OnRestarted::kEventName);
 
   if (listening_to_restart) {
     extensions::AppEventRouter::DispatchOnRestartedEvent(profile, extension);
@@ -355,7 +357,7 @@
   extension_prefs->SetIsActive(extension->id(), false);
   bool listening_to_launch = event_router->
       ExtensionHasEventListener(extension->id(),
-                                extensions::event_names::kOnLaunched);
+                                app_runtime::OnLaunched::kEventName);
 
   if (listening_to_launch && had_windows)
     LaunchPlatformAppWithNoData(profile, extension);
diff --git a/apps/load_and_launch_browsertest.cc b/apps/load_and_launch_browsertest.cc
index 620152e..40f748c 100644
--- a/apps/load_and_launch_browsertest.cc
+++ b/apps/load_and_launch_browsertest.cc
@@ -9,9 +9,9 @@
 #include "apps/switches.h"
 #include "base/process/launch.h"
 #include "base/test/test_timeouts.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/test/test_launcher.h"
diff --git a/apps/native_app_window.h b/apps/native_app_window.h
index 0286453..fcad3ce 100644
--- a/apps/native_app_window.h
+++ b/apps/native_app_window.h
@@ -22,6 +22,10 @@
   virtual void UpdateDraggableRegions(
       const std::vector<extensions::DraggableRegion>& regions) = 0;
 
+  // Called when the region that accepts input events is changed.
+  // If |region| is NULL, then the entire window will accept input events.
+  virtual void UpdateInputRegion(scoped_ptr<SkRegion> region) = 0;
+
   virtual void SetFullscreen(bool fullscreen) = 0;
   virtual bool IsFullscreenOrPending() const = 0;
 
diff --git a/apps/pref_names.cc b/apps/pref_names.cc
index cb9dea0..02b652c 100644
--- a/apps/pref_names.cc
+++ b/apps/pref_names.cc
@@ -8,15 +8,6 @@
 
 namespace prefs {
 
-// If set, the user requested to launch the app with this extension id while
-// in Metro mode, and then relaunched to Desktop mode to start it.
-const char kAppLaunchForMetroRestart[] = "apps.app_launch_for_metro_restart";
-
-// Set with |kAppLaunchForMetroRestart|, the profile whose loading triggers
-// launch of the specified app when restarting Chrome in desktop mode.
-const char kAppLaunchForMetroRestartProfile[] =
-    "apps.app_launch_for_metro_restart_profile";
-
 // A boolean that tracks whether the user has ever enabled the app launcher.
 const char kAppLauncherHasBeenEnabled[] =
     "apps.app_launcher.has_been_enabled";
@@ -27,6 +18,19 @@
 const char kAppLauncherIsEnabled[] =
     "apps.app_launcher.should_show_apps_page";
 
+// Integer representing the version of the app launcher shortcut installed on
+// the system. Incremented, e.g., when embedded icons change.
+const char kAppLauncherShortcutVersion[] = "apps.app_launcher.shortcut_version";
+
+// If set, the user requested to launch the app with this extension id while
+// in Metro mode, and then relaunched to Desktop mode to start it.
+const char kAppLaunchForMetroRestart[] = "apps.app_launch_for_metro_restart";
+
+// Set with |kAppLaunchForMetroRestart|, the profile whose loading triggers
+// launch of the specified app when restarting Chrome in desktop mode.
+const char kAppLaunchForMetroRestartProfile[] =
+    "apps.app_launch_for_metro_restart_profile";
+
 // A boolean that indicates whether app shortcuts have been created.
 // On a transition from false to true, shortcuts are created for all apps.
 const char kShortcutsHaveBeenCreated[] = "apps.shortcuts_have_been_created";
diff --git a/apps/pref_names.h b/apps/pref_names.h
index 13b26a8..55af7d0 100644
--- a/apps/pref_names.h
+++ b/apps/pref_names.h
@@ -10,10 +10,11 @@
 
 // Alphabetical list of preference names specific to Apps component.
 // Keep alphabetized and document each one in the source file.
-extern const char kAppLaunchForMetroRestartProfile[];
-extern const char kAppLaunchForMetroRestart[];
 extern const char kAppLauncherHasBeenEnabled[];
 extern const char kAppLauncherIsEnabled[];
+extern const char kAppLauncherShortcutVersion[];
+extern const char kAppLaunchForMetroRestart[];
+extern const char kAppLaunchForMetroRestartProfile[];
 extern const char kShortcutsHaveBeenCreated[];
 extern const char kShowAppLauncherPromo[];
 
diff --git a/apps/prefs.cc b/apps/prefs.cc
index 311d663..9347783 100644
--- a/apps/prefs.cc
+++ b/apps/prefs.cc
@@ -22,6 +22,10 @@
   registry->RegisterBooleanPref(prefs::kAppLauncherIsEnabled, false);
   registry->RegisterBooleanPref(prefs::kAppLauncherHasBeenEnabled, false);
 
+#if defined(OS_MACOSX)
+  registry->RegisterIntegerPref(prefs::kAppLauncherShortcutVersion, 0);
+#endif
+
 #if defined(OS_WIN)
   registry->RegisterStringPref(prefs::kAppLaunchForMetroRestart, "");
   registry->RegisterStringPref(prefs::kAppLaunchForMetroRestartProfile, "");
diff --git a/apps/shell_window.cc b/apps/shell_window.cc
index 10ab851..425adf6 100644
--- a/apps/shell_window.cc
+++ b/apps/shell_window.cc
@@ -91,7 +91,7 @@
 
   web_contents->SetDelegate(this);
   WebContentsModalDialogManager::FromWebContents(web_contents)->
-      set_delegate(this);
+      SetDelegate(this);
   extensions::SetViewType(web_contents, extensions::VIEW_TYPE_APP_SHELL);
 
   // Initialize the window
@@ -364,6 +364,10 @@
                  image_loader_ptr_factory_.GetWeakPtr()));
 }
 
+void ShellWindow::UpdateInputRegion(scoped_ptr<SkRegion> region) {
+  native_app_window_->UpdateInputRegion(region.Pass());
+}
+
 void ShellWindow::UpdateDraggableRegions(
     const std::vector<extensions::DraggableRegion>& regions) {
   native_app_window_->UpdateDraggableRegions(regions);
diff --git a/apps/shell_window.h b/apps/shell_window.h
index 6bf4ebf..53dd2b3 100644
--- a/apps/shell_window.h
+++ b/apps/shell_window.h
@@ -228,6 +228,10 @@
   // Specifies a url for the launcher icon.
   void SetAppIconUrl(const GURL& icon_url);
 
+  // Set the region in the window that will accept input events.
+  // If |region| is NULL, then the entire window will accept input events.
+  void UpdateInputRegion(scoped_ptr<SkRegion> region);
+
   // Called from the render interface to modify the draggable regions.
   void UpdateDraggableRegions(
       const std::vector<extensions::DraggableRegion>& regions);
diff --git a/apps/shell_window_geometry_cache.cc b/apps/shell_window_geometry_cache.cc
index 31b44a4..a3b0bcf 100644
--- a/apps/shell_window_geometry_cache.cc
+++ b/apps/shell_window_geometry_cache.cc
@@ -111,6 +111,9 @@
       base::DictionaryValue* value = new base::DictionaryValue;
       const gfx::Rect& bounds = it->second.bounds;
       const gfx::Rect& screen_bounds = it->second.screen_bounds;
+      DCHECK(!bounds.IsEmpty());
+      DCHECK(!screen_bounds.IsEmpty());
+      DCHECK(it->second.window_state != ui::SHOW_STATE_DEFAULT);
       value->SetInteger("x", bounds.x());
       value->SetInteger("y", bounds.y());
       value->SetInteger("w", bounds.width());
diff --git a/apps/shell_window_geometry_cache_unittest.cc b/apps/shell_window_geometry_cache_unittest.cc
index 98c4bdc..2b42d48 100644
--- a/apps/shell_window_geometry_cache_unittest.cc
+++ b/apps/shell_window_geometry_cache_unittest.cc
@@ -108,7 +108,7 @@
   AddGeometryAndLoadExtension(extension_id1, kWindowId,
                               gfx::Rect(4, 5, 31, 43),
                               gfx::Rect(0, 0, 1600, 900),
-                              ui::SHOW_STATE_DEFAULT);
+                              ui::SHOW_STATE_NORMAL);
   ASSERT_FALSE(cache_->GetGeometry(extension_id2, kWindowId, NULL, NULL, NULL));
 }
 
@@ -118,7 +118,7 @@
   AddGeometryAndLoadExtension(extension_id, kWindowId,
                               gfx::Rect(4, 5, 31, 43),
                               gfx::Rect(0, 0, 1600, 900),
-                              ui::SHOW_STATE_DEFAULT);
+                              ui::SHOW_STATE_NORMAL);
   ASSERT_FALSE(cache_->GetGeometry(extension_id, kWindowId2, NULL, NULL, NULL));
 }
 
@@ -282,28 +282,28 @@
   // Write the first bounds - it should do > 0 writes.
   EXPECT_CALL(observer, OnPreferenceChanged(_));
   cache_->SaveGeometry(extension_id, kWindowId, bounds1,
-                       screen_bounds1, ui::SHOW_STATE_DEFAULT);
+                       screen_bounds1, ui::SHOW_STATE_NORMAL);
   WaitForSync();
   Mock::VerifyAndClearExpectations(&observer);
 
   // Write a different bounds - it should also do > 0 writes.
   EXPECT_CALL(observer, OnPreferenceChanged(_));
   cache_->SaveGeometry(extension_id, kWindowId, bounds2,
-                       screen_bounds1, ui::SHOW_STATE_DEFAULT);
+                       screen_bounds1, ui::SHOW_STATE_NORMAL);
   WaitForSync();
   Mock::VerifyAndClearExpectations(&observer);
 
   // Write a different screen bounds - it should also do > 0 writes.
   EXPECT_CALL(observer, OnPreferenceChanged(_));
   cache_->SaveGeometry(extension_id, kWindowId, bounds2,
-                       screen_bounds2, ui::SHOW_STATE_DEFAULT);
+                       screen_bounds2, ui::SHOW_STATE_NORMAL);
   WaitForSync();
   Mock::VerifyAndClearExpectations(&observer);
 
   // Write a different state - it should also do > 0 writes.
   EXPECT_CALL(observer, OnPreferenceChanged(_));
   cache_->SaveGeometry(extension_id, kWindowId, bounds2,
-                       screen_bounds2, ui::SHOW_STATE_NORMAL);
+                       screen_bounds2, ui::SHOW_STATE_MAXIMIZED);
   WaitForSync();
   Mock::VerifyAndClearExpectations(&observer);
 
@@ -311,7 +311,7 @@
   // already have. This should not do any writes.
   EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0);
   cache_->SaveGeometry(extension_id, kWindowId, bounds2_duplicate,
-                       screen_bounds2_duplicate, ui::SHOW_STATE_NORMAL);
+                       screen_bounds2_duplicate, ui::SHOW_STATE_MAXIMIZED);
   WaitForSync();
   Mock::VerifyAndClearExpectations(&observer);
 }
@@ -327,7 +327,7 @@
   for (size_t i = 0; i < ShellWindowGeometryCache::kMaxCachedWindows + 1; ++i) {
     std::string window_id = "window_" + base::IntToString(i);
     cache_->SaveGeometry(extension_id, window_id, bounds,
-                         screen_bounds, ui::SHOW_STATE_DEFAULT);
+                         screen_bounds, ui::SHOW_STATE_NORMAL);
   }
 
   // The first added window should no longer have cached geometry.
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 3d669bb..d80cfea 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -41,11 +41,11 @@
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/touch/touch_hud_debug.h"
 #include "ash/volume_control_delegate.h"
+#include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/partial_screenshot_view.h"
 #include "ash/wm/power_button_controller.h"
 #include "ash/wm/property_util.h"
 #include "ash/wm/window_cycle_controller.h"
-#include "ash/wm/window_selector_controller.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/workspace/snap_sizer.h"
 #include "base/bind.h"
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index fe9f518..4c00f72 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -35,8 +35,8 @@
 
 class TestTarget : public ui::AcceleratorTarget {
  public:
-  TestTarget() : accelerator_pressed_count_(0) {};
-  virtual ~TestTarget() {};
+  TestTarget() : accelerator_pressed_count_(0) {}
+  virtual ~TestTarget() {}
 
   int accelerator_pressed_count() const {
     return accelerator_pressed_count_;
@@ -298,8 +298,8 @@
 
 class AcceleratorControllerTest : public test::AshTestBase {
  public:
-  AcceleratorControllerTest() {};
-  virtual ~AcceleratorControllerTest() {};
+  AcceleratorControllerTest() {}
+  virtual ~AcceleratorControllerTest() {}
 
  protected:
   void EnableInternalDisplay() {
@@ -360,7 +360,7 @@
   EXPECT_FALSE(ProcessWithContext(release));
   EXPECT_FALSE(is_idle(ewh));
   EXPECT_TRUE(is_ui_shown(ewh));
-  EXPECT_TRUE(ProcessWithContext(press)); // second press before timer.
+  EXPECT_TRUE(ProcessWithContext(press));  // second press before timer.
   EXPECT_FALSE(ProcessWithContext(release));
   SimulateTimerExpired(ewh);
   EXPECT_TRUE(is_exiting(ewh));
@@ -387,6 +387,20 @@
   EXPECT_FALSE(is_ui_shown(ewh));
   Reset(ewh);
 }
+
+// Shutdown ash with exit warning bubble open should not crash.
+TEST_F(AcceleratorControllerTest, LingeringExitWarningBubble) {
+  ExitWarningHandler* ewh = GetController()->GetExitWarningHandlerForTest();
+  ASSERT_TRUE(!!ewh);
+  StubForTest(ewh);
+
+  // Trigger once to show the bubble.
+  ewh->HandleAccelerator();
+  EXPECT_FALSE(is_idle(ewh));
+  EXPECT_TRUE(is_ui_shown(ewh));
+
+  // Exit ash and there should be no crash
+}
 #endif  // !defined(OS_WIN)
 
 TEST_F(AcceleratorControllerTest, Register) {
@@ -908,8 +922,8 @@
   // ToggleDesktopFullScreen (not implemented yet on Linux)
   EXPECT_TRUE(ProcessWithContext(
       ui::Accelerator(ui::VKEY_F11, ui::EF_CONTROL_DOWN)));
-#endif //  OS_LINUX
-#endif //  !NDEBUG
+#endif  // OS_LINUX
+#endif  // !NDEBUG
 
 #if !defined(OS_WIN)
   // Exit
@@ -1234,7 +1248,7 @@
     EXPECT_EQ(2, delegate->handle_take_screenshot_count());
     EXPECT_TRUE(ProcessWithContext(
         ui::Accelerator(ui::VKEY_MEDIA_LAUNCH_APP1,
- ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
+        ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN)));
     EXPECT_EQ(2, delegate->handle_take_screenshot_count());
   }
   // Brightness
diff --git a/ash/accelerators/exit_warning_handler.cc b/ash/accelerators/exit_warning_handler.cc
index 767b266..864286b 100644
--- a/ash/accelerators/exit_warning_handler.cc
+++ b/ash/accelerators/exit_warning_handler.cc
@@ -27,8 +27,12 @@
 namespace {
 
 const int64 kTimeOutMilliseconds = 2000;
-const SkColor kForegroundColor = 0xFFFFFFFF;
-const SkColor kBackgroundColor = 0xE0808080;
+// Color of the text of the warning message.
+const SkColor kTextColor = SK_ColorWHITE;
+// Color of the window background.
+const SkColor kWindowBackgroundColor = SkColorSetARGB(0xC0, 0x0, 0x0, 0x0);
+// Radius of the rounded corners of the window.
+const int kWindowCornerRadius = 2;
 const int kHorizontalMarginAroundText = 100;
 const int kVerticalMarginAroundText = 100;
 
@@ -68,8 +72,8 @@
     label->SetText(text_);
     label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
     label->SetFont(font_);
-    label->SetEnabledColor(kForegroundColor);
-    label->SetDisabledColor(kForegroundColor);
+    label->SetEnabledColor(kTextColor);
+    label->SetDisabledColor(kTextColor);
     label->SetAutoColorReadabilityEnabled(false);
     AddChildView(label);
     SetLayoutManager(new views::FillLayout);
@@ -80,7 +84,10 @@
   }
 
   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
-    canvas->FillRect(GetLocalBounds(), kBackgroundColor);
+    SkPaint paint;
+    paint.setStyle(SkPaint::kFill_Style);
+    paint.setColor(kWindowBackgroundColor);
+    canvas->DrawRoundRect(GetLocalBounds(), kWindowCornerRadius, paint);
     views::WidgetDelegateView::OnPaint(canvas);
   }
 
@@ -100,11 +107,10 @@
   DISALLOW_COPY_AND_ASSIGN(ExitWarningWidgetDelegateView);
 };
 
-} // namespace
+}  // namespace
 
 ExitWarningHandler::ExitWarningHandler()
     : state_(IDLE),
-      widget_(NULL),
       stub_timer_for_test_(false) {
 }
 
@@ -169,6 +175,7 @@
   views::Widget::InitParams params;
   params.type = views::Widget::InitParams::TYPE_POPUP;
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.accept_events = false;
   params.can_activate = false;
   params.keep_on_top = true;
@@ -178,7 +185,7 @@
   params.parent = Shell::GetContainer(
       root_window,
       internal::kShellWindowId_SettingBubbleContainer);
-  widget_ = new views::Widget;
+  widget_.reset(new views::Widget);
   widget_->Init(params);
   widget_->SetContentsView(delegate);
   widget_->GetNativeView()->SetName("ExitWarningWindow");
@@ -188,10 +195,7 @@
 }
 
 void ExitWarningHandler::Hide() {
-  if (!widget_)
-    return;
-  widget_->Close();
-  widget_ = NULL;
+  widget_.reset();
 }
 
 }  // namespace ash
diff --git a/ash/accelerators/exit_warning_handler.h b/ash/accelerators/exit_warning_handler.h
index b303d84..b99681c 100644
--- a/ash/accelerators/exit_warning_handler.h
+++ b/ash/accelerators/exit_warning_handler.h
@@ -6,6 +6,7 @@
 #define ASH_ACCELERATORS_EXIT_WARNING_HANDLER_H_
 
 #include "ash/ash_export.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/timer/timer.h"
 #include "ui/base/accelerators/accelerator.h"
 
@@ -71,7 +72,7 @@
   void Hide();
 
   State state_;
-  views::Widget* widget_; // owned by |this|.
+  scoped_ptr<views::Widget> widget_;
   base::OneShotTimer<ExitWarningHandler> timer_;
 
   // Flag to suppress starting the timer for testing. For test we call
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 7a3f1be..a91b268 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -83,12 +83,12 @@
         'desktop_background/wallpaper_resizer.cc',
         'desktop_background/wallpaper_resizer.h',
         'desktop_background/wallpaper_resizer_observer.h',
-        'display/display_change_observer_x11.cc',
-        'display/display_change_observer_x11.h',
+        'display/display_change_observer_chromeos.cc',
+        'display/display_change_observer_chromeos.h',
         'display/display_controller.cc',
         'display/display_controller.h',
-        'display/display_error_observer.cc',
-        'display/display_error_observer.h',
+        'display/display_error_observer_chromeos.cc',
+        'display/display_error_observer_chromeos.h',
         'display/display_info.h',
         'display/display_info.cc',
         'display/display_layout.h',
@@ -98,8 +98,6 @@
         'display/display_manager.cc',
         'display/display_manager.h',
         'display/display_pref_util.h',
-        'display/display_util_x11.cc',
-        'display/display_util_x11.h',
         'display/event_transformation_handler.cc',
         'display/event_transformation_handler.h',
         'display/mirror_window_controller.cc',
@@ -130,6 +128,8 @@
         'host/root_window_host_factory.cc',
         'host/root_window_host_factory.h',
         'host/root_window_host_factory_win.cc',
+        'keyboard_controller_proxy_stub.cc',
+        'keyboard_controller_proxy_stub.h',
         'keyboard_overlay/keyboard_overlay_delegate.cc',
         'keyboard_overlay/keyboard_overlay_delegate.h',
         'keyboard_overlay/keyboard_overlay_view.cc',
@@ -207,7 +207,7 @@
         'system/brightness/brightness_observer.h',
         'system/brightness/brightness_control_delegate.h',
         'system/brightness/tray_brightness.cc',
-        'system/brightness/tray_brightness.h',        
+        'system/brightness/tray_brightness.h',
         'system/chromeos/audio/tray_audio.cc',
         'system/chromeos/audio/tray_audio.h',
         'system/chromeos/enterprise/enterprise_domain_observer.h',
@@ -227,13 +227,11 @@
         'system/chromeos/network/network_icon_animation.cc',
         'system/chromeos/network/network_icon_animation.h',
         'system/chromeos/network/network_icon_animation_observer.h',
-        'system/chromeos/network/network_observer.cc',
         'system/chromeos/network/network_observer.h',
         'system/chromeos/network/network_state_list_detailed_view.cc',
         'system/chromeos/network/network_state_list_detailed_view.h',
         'system/chromeos/network/network_state_notifier.cc',
         'system/chromeos/network/network_state_notifier.h',
-        'system/chromeos/network/network_tray_delegate.h',
         'system/chromeos/network/tray_network.cc',
         'system/chromeos/network/tray_network.h',
         'system/chromeos/network/tray_network_state_observer.cc',
@@ -277,8 +275,8 @@
         'system/locale/locale_notification_controller.cc',
         'system/locale/locale_notification_controller.h',
         'system/logout_button/logout_button_observer.h',
-        'system/logout_button/tray_logout_button.cc',
-        'system/logout_button/tray_logout_button.h',
+        'system/logout_button/logout_button_tray.cc',
+        'system/logout_button/logout_button_tray.h',
         'system/monitor/tray_monitor.cc',
         'system/monitor/tray_monitor.h',
         'system/session_length_limit/session_length_limit_observer.h',
@@ -382,10 +380,8 @@
         'wm/ash_focus_rules.h',
         'wm/base_layout_manager.cc',
         'wm/base_layout_manager.h',
-        'wm/boot_splash_screen.cc',
-        'wm/boot_splash_screen.h',
-        'wm/capture_controller.cc',
-        'wm/capture_controller.h',
+        'wm/boot_splash_screen_chromeos.cc',
+        'wm/boot_splash_screen_chromeos.h',
         'wm/coordinate_conversion.cc',
         'wm/coordinate_conversion.h',
         'wm/custom_frame_view_ash.cc',
@@ -430,6 +426,13 @@
         'wm/mru_window_tracker.h',
         'wm/overlay_event_filter.cc',
         'wm/overlay_event_filter.h',
+        'wm/overview/window_selector.cc',
+        'wm/overview/window_selector.h',
+        'wm/overview/window_selector_controller.cc',
+        'wm/overview/window_selector_controller.h',
+        'wm/overview/window_selector_delegate.h',
+        'wm/overview/window_selector_window.cc',
+        'wm/overview/window_selector_window.h',
         'wm/panels/panel_frame_view.cc',
         'wm/panels/panel_frame_view.h',
         'wm/panels/panel_layout_manager.cc',
@@ -488,11 +491,6 @@
         'wm/window_properties.h',
         'wm/window_resizer.cc',
         'wm/window_resizer.h',
-        'wm/window_selector.cc',
-        'wm/window_selector.h',
-        'wm/window_selector_controller.cc',
-        'wm/window_selector_controller.h',
-        'wm/window_selector_delegate.h',
         'wm/window_util.cc',
         'wm/window_util.h',
         'wm/workspace_controller.cc',
@@ -503,6 +501,8 @@
         'wm/workspace/colored_window_controller.h',
         'wm/workspace/desktop_background_fade_controller.cc',
         'wm/workspace/desktop_background_fade_controller.h',
+        'wm/workspace/frame_caption_button_container_view.cc',
+        'wm/workspace/frame_caption_button_container_view.h',
         'wm/workspace/frame_maximize_button.cc',
         'wm/workspace/frame_maximize_button.h',
         'wm/workspace/magnetism_matcher.cc',
@@ -553,6 +553,14 @@
             ['exclude', 'system/monitor/tray_monitor.h'],
           ],
         }],
+        ['use_x11!=1', {
+          'sources/': [
+            ['exclude', 'display/display_change_observer_chromeos.cc'],
+            ['exclude', 'display/display_change_observer_chromeos.h'],
+            ['exclude', 'display/display_error_observer_chromeos.cc'],
+            ['exclude', 'display/display_error_observer_chromeos.h'],
+          ],
+        }],
         ['chromeos==1', {
           'dependencies': [
             '../chromeos/chromeos.gyp:chromeos',
@@ -562,8 +570,6 @@
         }, { # else: chromeos!=1
           'sources/': [
             ['exclude', '/chromeos/'],
-            ['exclude', 'display/display_error_observer.cc'],
-            ['exclude', 'display/display_error_observer.h'],
             ['exclude', 'display/output_configurator_animation.cc'],
             ['exclude', 'display/output_configurator_animation.h'],
           ],
@@ -672,7 +678,8 @@
         'desktop_background/wallpaper_resizer_unittest.cc',
         'dip_unittest.cc',
         'display/display_controller_unittest.cc',
-        'display/display_error_observer_unittest.cc',
+        'display/display_change_observer_chromeos_unittest.cc',
+        'display/display_error_observer_chromeos_unittest.cc',
         'display/display_info_unittest.cc',
         'display/display_manager_unittest.cc',
         'display/mirror_window_controller_unittest.cc',
@@ -715,6 +722,7 @@
         'shell/window_type_launcher.cc',
         'shell/window_watcher.cc',
         'shell/window_watcher_unittest.cc',
+        'system/chromeos/managed/tray_locally_managed_user_unittest.cc',
         'system/chromeos/network/network_state_notifier_unittest.cc',
         'system/chromeos/power/power_status_unittest.cc',
         'system/chromeos/power/tray_power_unittest.cc',
@@ -737,6 +745,7 @@
         'wm/drag_window_resizer_unittest.cc',
         'wm/frame_painter_unittest.cc',
         'wm/lock_state_controller_impl2_unittest.cc',
+        'wm/overview/window_selector_unittest.cc',
         'wm/panels/panel_layout_manager_unittest.cc',
         'wm/panels/panel_window_resizer_unittest.cc',
         'wm/partial_screenshot_view_unittest.cc',
@@ -753,11 +762,11 @@
         'wm/window_cycle_controller_unittest.cc',
         'wm/window_manager_unittest.cc',
         'wm/window_modality_controller_unittest.cc',
-        'wm/window_selector_unittest.cc',
         'wm/window_util_unittest.cc',
         'wm/workspace_controller_test_helper.cc',
         'wm/workspace_controller_test_helper.h',
         'wm/workspace_controller_unittest.cc',
+        'wm/workspace/frame_caption_button_container_view_unittest.cc',
         'wm/workspace/magnetism_matcher_unittest.cc',
         'wm/workspace/multi_window_resize_controller_unittest.cc',
         'wm/workspace/workspace_event_handler_test_helper.cc',
@@ -802,16 +811,13 @@
           # are not referenced in code, but are referenced in nibs.
           'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']},
         }],
-        ['use_x11==1', {
-          'sources': [
-            'display/display_util_x11_unittest.cc'
+        ['use_x11!=1', {
+          'sources/': [
+            ['exclude', 'display/display_change_observer_chromeos_unittest.cc'],
+            ['exclude', 'display/display_error_observer_chromeos_unittest.cc'],
           ],
         }],
-        ['chromeos!=1', {
-          'sources/': [
-            ['exclude', 'display/display_error_observer_unittest.cc'],
-          ],
-        }, {  # chromeos==1
+        ['chromeos==1', {
           'dependencies': [
             '../chromeos/chromeos.gyp:power_manager_proto',
           ],
@@ -910,7 +916,6 @@
             'shell/cocoa/app-Info.plist',
             'shell/cocoa/nibs/MainMenu.xib',
             'shell/cocoa/nibs/RootWindow.xib',
-            '<(SHARED_INTERMEDIATE_DIR)/repack/chrome.pak',
             '<!@pymod_do_main(repack_locales -o -p <(OS) -g <(grit_out_dir) -s <(SHARED_INTERMEDIATE_DIR) -x <(SHARED_INTERMEDIATE_DIR) <(locales))',
           ],
           'mac_bundle_resources!': [
diff --git a/ash/ash_chromeos_strings.grdp b/ash/ash_chromeos_strings.grdp
index 1190db9..3f164de 100644
--- a/ash/ash_chromeos_strings.grdp
+++ b/ash/ash_chromeos_strings.grdp
@@ -122,25 +122,37 @@
   <message name="IDS_NETWORK_CONNECTION_ERROR_TITLE" desc="Title for network connection error notification">
     Network Connection Error
   </message>
-  <message name="IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_DETAILS" desc="Message for network connection error notification with details">
+  <message name="IDS_NETWORK_CONNECTION_ERROR_MESSAGE" desc="Message for network connection error notification">
     Failed to connect to network '<ph name="name">$1<ex>GoogleGuest</ex></ph>': <ph name="details">$2<ex>Unrecognized error</ex></ph>
   </message>
   <message name="IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_SERVER_MESSAGE" desc="Message for network connection error notification with details and a server message">
 Failed to connect to '<ph name="name">$1<ex>GoogleGuest</ex></ph>': <ph name="details">$2<ex>Unrecognized error</ex></ph>
 Server message: <ph name="server_msg">$3<ex>Incorrect password</ex></ph>
   </message>
+  <message name="IDS_NETWORK_CONNECTION_ERROR_MESSAGE_NO_NAME" desc="Message for network connection error where the network name is unavailable">
+    Failed to connect to network: <ph name="details">$2<ex>Unrecognized error</ex></ph>
+  </message>
   <message name="IDS_NETWORK_OUT_OF_CREDITS_TITLE" desc="Title for network out of data error notification">
     Network Connection Error
   </message>
   <message name="IDS_NETWORK_OUT_OF_CREDITS_BODY" desc="Message body for network out of data error notification">
-    You may have used up your mobile data allowance.
-  </message>
-  <message name="IDS_NETWORK_OUT_OF_CREDITS_LINK" desc="Link text for network out of data error notification">
-    Visit the <ph name="name">$1<ex>GoogleGuest</ex></ph> activation portal to buy more data.
+    You may have used up your mobile data allowance. Visit the <ph name="name">$1<ex>GoogleGuest</ex></ph> activation portal to buy more data.
   </message>
   <message name="IDS_NETWORK_UNRECOGNIZED_ERROR" desc="Unrecognized Network error text">
     Unrecognized error: <ph name="desc">$1<ex>ShillErrorString</ex></ph>
   </message>
+  <message name="IDS_NETWORK_CELLULAR_ACTIVATED_TITLE" desc="Title for cellular activated notification">
+    Cellular Activated
+  </message>
+  <message name="IDS_NETWORK_CELLULAR_ACTIVATED" desc="Text of the cellular activated notification">
+    Congratulations! Your '<ph name="name">$1<ex>Generic Wireless</ex></ph>' data service has been activated and is ready to go.
+  </message>
+  <message name="IDS_NETWORK_ACTIVATION_ERROR_TITLE" desc="Title for network activation error notification">
+    Network Activation Error
+  </message>
+  <message name="IDS_NETWORK_ACTIVATION_NEEDS_CONNECTION" desc="Message when attempting to activate a mobile network that requires a connection">
+    Activation of '<ph name="name">$1<ex>Generic Wireless</ex></ph>' requires a network connection.
+  </message>
 
   <!-- Network state strings -->
   <message name="IDS_CHROMEOS_NETWORK_STATE_UNKNOWN" desc="Network state in about:network: UNKNOWN">
@@ -266,5 +278,30 @@
   <message name="IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED_NAME" desc="label for screen sharing notification with name">
     Sharing control of your screen with <ph name="HELPER_NAME">$1<ex>Walder Frey</ex></ph> via Hangouts.
   </message>
+  
+  <!-- Status tray audio strings. -->
+  <message name="IDS_ASH_STATUS_TRAY_AUDIO_HEADPHONE" desc="label used for audio headphone device">
+    Headphone
+  </message> 
+  
+  <message name="IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_SPEAKER" desc="label used for internal audio speaker">
+    Speaker (Internal)
+  </message>
+  
+  <message name="IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_MIC" desc="label used for internal microphone">
+    Microphone (Internal)
+  </message>
+  
+  <message name="IDS_ASH_STATUS_TRAY_AUDIO_USB_DEVICE" desc="label used for usb audio device">
+    <ph name="device_name">$1<ex>Headphone</ex></ph> (USB)
+  </message>
+
+  <message name="IDS_ASH_STATUS_TRAY_AUDIO_BLUETOOTH_DEVICE" desc="label used for bluetooth audio device">
+    <ph name="device_name">$1<ex>Headphone</ex></ph> (Bluetooth)
+  </message>
+
+  <message name="IDS_ASH_STATUS_TRAY_AUDIO_HDMI_DEVICE" desc="label used for hdmi audio device">
+    <ph name="device_name">$1<ex>Speaker</ex></ph> (HDMI)
+  </message>
 
 </grit-part>
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 2d75802..62693dc 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -325,7 +325,10 @@
         Extending screen
       </message>
       <message name="IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED" desc="The label used in the tray to show that the current status is docked mode.">
-        Dock mode
+        Docked mode
+      </message>
+      <message name="IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED_DESCRIPTION" desc="The label used in the notification body to describe what the docked mode means.">
+        Your Chromebook will stay on while connected to an external display, even with the lid closed.
       </message>
       <message name="IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED" desc="The label used in the tray to notify that the display resolution settings has changed.">
         <ph name="DISPLAY_NAME">$1</ph> resolution was changed to <ph name="RESOLUTION">$2</ph>
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc
index b47ba50..9fbc975 100644
--- a/ash/ash_switches.cc
+++ b/ash/ash_switches.cc
@@ -54,10 +54,6 @@
 // Disable auto window maximization logic.
 const char kAshDisableAutoMaximizing[] = "ash-disable-auto-maximizing";
 
-// Disable support for auto window placement.
-const char kAshDisableAutoWindowPlacement[] =
-    "ash-enable-auto-window-placement";
-
 // Disables the limitter to throttle how quickly a user
 // can change display settings.
 const char kAshDisableDisplayChangeLimiter[] =
@@ -66,19 +62,10 @@
 // If present new lock animations are enabled.
 const char kAshDisableNewLockAnimations[] = "ash-disable-new-lock-animations";
 
-// Disable the per application grouping version of the launcher.
-const char kAshDisablePerAppLauncher[] = "ash-disable-per-app-launcher";
-
-// Disables display rotation.
-const char kAshDisableDisplayRotation[] = "ash-disable-display-rotation";
-
 // Disable immersive fullscreen mode, regardless of default setting.
 const char kAshDisableImmersiveFullscreen[] =
     "ash-disable-immersive-fullscreen";
 
-// Disables ui scaling.
-const char kAshDisableUIScaling[] = "ash-disable-ui-scaling";
-
 #if defined(OS_CHROMEOS)
 // Disable compositor based mirroring.
 const char kAshDisableSoftwareMirroring[] = "ash-disable-software-mirroring";
@@ -159,6 +146,10 @@
 // crbug's [244983, 244990, 244994, 245005, 245012]
 const char kAshUseAlternateShelfLayout[] = "ash-use-alternate-shelf";
 
+// Flags explicitly show or hide the shelf alignment menu.
+const char kShowShelfAlignmentMenu[] = "show-launcher-alignment-menu";
+const char kHideShelfAlignmentMenu[] = "hide-launcher-alignment-menu";
+
 // Uses the 1st display in --ash-host-window-bounds as internal display.
 // This is for debugging on linux desktop.
 const char kAshUseFirstDisplayAsInternal[] =
@@ -187,7 +178,12 @@
 
 bool UseAlternateShelfLayout() {
   return CommandLine::ForCurrentProcess()->
-        HasSwitch(ash::switches::kAshUseAlternateShelfLayout);
+      HasSwitch(ash::switches::kAshUseAlternateShelfLayout);
+}
+
+bool ShowShelfAlignmentMenu() {
+  return CommandLine::ForCurrentProcess()->
+      HasSwitch(switches::kShowShelfAlignmentMenu);
 }
 
 #if defined(OS_CHROMEOS)
@@ -198,7 +194,7 @@
 
 bool UseUsbChargerNotification() {
   return !CommandLine::ForCurrentProcess()->
-        HasSwitch(ash::switches::kAshDisableUsbChargerNotification);
+      HasSwitch(ash::switches::kAshDisableUsbChargerNotification);
 }
 #endif
 
diff --git a/ash/ash_switches.h b/ash/ash_switches.h
index 7e5d471..ddafe6d 100644
--- a/ash/ash_switches.h
+++ b/ash/ash_switches.h
@@ -30,13 +30,9 @@
 ASH_EXPORT extern const char kAshDisableAudioDeviceMenu[];
 #endif
 ASH_EXPORT extern const char kAshDisableAutoMaximizing[];
-ASH_EXPORT extern const char kAshDisableAutoWindowPlacement[];
 ASH_EXPORT extern const char kAshDisableDisplayChangeLimiter[];
 ASH_EXPORT extern const char kAshDisableImmersiveFullscreen[];
 ASH_EXPORT extern const char kAshDisableNewLockAnimations[];
-ASH_EXPORT extern const char kAshDisablePerAppLauncher[];
-ASH_EXPORT extern const char kAshDisableUIScaling[];
-ASH_EXPORT extern const char kAshDisableDisplayRotation[];
 ASH_EXPORT extern const char kAshDisableDragAndDropAppListToLauncher[];
 #if defined(OS_CHROMEOS)
 ASH_EXPORT extern const char kAshDisableSoftwareMirroring[];
@@ -68,9 +64,15 @@
 #endif
 ASH_EXPORT extern const char kForcedMaximizeMode[];
 
+ASH_EXPORT extern const char kShowShelfAlignmentMenu[];
+ASH_EXPORT extern const char kHideShelfAlignmentMenu[];
+
 // Returns true if the alternate shelf layout should be used.
 ASH_EXPORT bool UseAlternateShelfLayout();
 
+// Returns true if side shelf alignment is enabled.
+ASH_EXPORT bool ShowShelfAlignmentMenu();
+
 #if defined(OS_CHROMEOS)
 // Returns true if new audio handler should be used.
 ASH_EXPORT bool UseNewAudioHandler();
diff --git a/ash/desktop_background/desktop_background_view.cc b/ash/desktop_background/desktop_background_view.cc
index ff18b16..6f16850 100644
--- a/ash/desktop_background/desktop_background_view.cc
+++ b/ash/desktop_background/desktop_background_view.cc
@@ -10,6 +10,7 @@
 #include "ash/desktop_background/desktop_background_controller.h"
 #include "ash/desktop_background/desktop_background_widget_controller.h"
 #include "ash/desktop_background/user_wallpaper_delegate.h"
+#include "ash/display/display_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/session_state_delegate.h"
 #include "ash/shell.h"
@@ -56,13 +57,28 @@
   // streching to avoid upsampling artifacts (Note that we could tile too, but
   // decided not to do this at the moment).
   DesktopBackgroundController* controller =
-      ash::Shell::GetInstance()->desktop_background_controller();
+      Shell::GetInstance()->desktop_background_controller();
   gfx::ImageSkia wallpaper = controller->GetWallpaper();
   WallpaperLayout wallpaper_layout = controller->GetWallpaperLayout();
 
-  gfx::Rect wallpaper_rect(0, 0, wallpaper.width(), wallpaper.height());
+  gfx::NativeView native_view = GetWidget()->GetNativeView();
+  gfx::Display display = gfx::Screen::GetScreenFor(native_view)->
+      GetDisplayNearestWindow(native_view);
+
+  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
+  DisplayInfo display_info = display_manager->GetDisplayInfo(display.id());
+  float scaling = display_info.ui_scale();
+  if (scaling <= 1.0f)
+    scaling = 1.0f;
+  // Allow scaling up to the UI scaling.
+  // TODO(oshima): Create separate layer that fits to the image and then
+  // scale to avoid artifacts and be more efficient when clipped.
+  gfx::Rect wallpaper_rect(
+      0, 0, wallpaper.width() * scaling, wallpaper.height() * scaling);
+
   if (wallpaper_layout == WALLPAPER_LAYOUT_CENTER_CROPPED &&
-      wallpaper.width() > width() && wallpaper.height() > height()) {
+      wallpaper_rect.width() >= width() &&
+      wallpaper_rect.height() >= height()) {
     // The dimension with the smallest ratio must be cropped, the other one
     // is preserved. Both are set in gfx::Size cropped_size.
     double horizontal_ratio = static_cast<double>(width()) /
@@ -80,7 +96,8 @@
           RoundPositive(static_cast<double>(height()) / horizontal_ratio));
     }
 
-    gfx::Rect wallpaper_cropped_rect = wallpaper_rect;
+    gfx::Rect wallpaper_cropped_rect(
+        0, 0, wallpaper.width(), wallpaper.height());
     wallpaper_cropped_rect.ClampToCenteredSize(cropped_size);
     canvas->DrawImageInt(wallpaper,
         wallpaper_cropped_rect.x(), wallpaper_cropped_rect.y(),
@@ -94,9 +111,19 @@
     canvas->DrawImageInt(wallpaper, 0, 0, wallpaper.width(),
         wallpaper.height(), 0, 0, width(), height(), true);
   } else {
+    // Fill with black to make sure that the entire area is opaque.
+    canvas->FillRect(GetLocalBounds(), SK_ColorBLACK);
     // All other are simply centered, and not scaled (but may be clipped).
-     canvas->DrawImageInt(wallpaper, (width() - wallpaper.width()) / 2,
-         (height() - wallpaper.height()) / 2);
+    if (wallpaper.width() && wallpaper.height()) {
+      canvas->DrawImageInt(
+          wallpaper,
+          0, 0, wallpaper.width(), wallpaper.height(),
+          (width() - wallpaper_rect.width()) / 2,
+          (height() - wallpaper_rect.height()) / 2,
+          wallpaper_rect.width(),
+          wallpaper_rect.height(),
+          true);
+    }
   }
 }
 
@@ -114,9 +141,9 @@
 views::Widget* CreateDesktopBackground(aura::RootWindow* root_window,
                                        int container_id) {
   DesktopBackgroundController* controller =
-      ash::Shell::GetInstance()->desktop_background_controller();
-  ash::UserWallpaperDelegate* wallpaper_delegate =
-    ash::Shell::GetInstance()->user_wallpaper_delegate();
+      Shell::GetInstance()->desktop_background_controller();
+  UserWallpaperDelegate* wallpaper_delegate =
+      Shell::GetInstance()->user_wallpaper_delegate();
 
   views::Widget* desktop_widget = new views::Widget;
   views::Widget::InitParams params(
diff --git a/ash/display/display_change_observer_chromeos.cc b/ash/display/display_change_observer_chromeos.cc
new file mode 100644
index 0000000..71bdfcd
--- /dev/null
+++ b/ash/display/display_change_observer_chromeos.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 "ash/display/display_change_observer_chromeos.h"
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <vector>
+
+#include "ash/ash_switches.h"
+#include "ash/display/display_info.h"
+#include "ash/display/display_layout_store.h"
+#include "ash/display/display_manager.h"
+#include "ash/shell.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "chromeos/display/output_util.h"
+#include "grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/gfx/display.h"
+
+namespace ash {
+namespace internal {
+
+using chromeos::OutputConfigurator;
+
+namespace {
+
+// The DPI threshold to detect high density screen.
+// Higher DPI than this will use device_scale_factor=2.
+const unsigned int kHighDensityDPIThreshold = 160;
+
+// 1 inch in mm.
+const float kInchInMm = 25.4f;
+
+// A list of bogus sizes in mm that X detects that should be ignored.
+// See crbug.com/136533. The first element maintains the minimum
+// size required to be valid size.
+const unsigned long kInvalidDisplaySizeList[][2] = {
+  {40, 30},
+  {50, 40},
+  {160, 90},
+  {160, 100},
+};
+
+// Resolution list are sorted by the area in pixels and the larger
+// one comes first.
+struct ResolutionSorter {
+  bool operator()(const Resolution& a, const Resolution& b) {
+    return a.size.width() * a.size.height() > b.size.width() * b.size.height();
+  }
+};
+
+}  // namespace
+
+// static
+bool DisplayChangeObserver::ShouldIgnoreSize(unsigned long mm_width,
+                                             unsigned long mm_height) {
+  // Ignore if the reported display is smaller than minimum size.
+  if (mm_width <= kInvalidDisplaySizeList[0][0] ||
+      mm_height <= kInvalidDisplaySizeList[0][1]) {
+    LOG(WARNING) << "Smaller than minimum display size";
+    return true;
+  }
+  for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) {
+    const unsigned long* size = kInvalidDisplaySizeList[i];
+    if (mm_width == size[0] && mm_height == size[1]) {
+      LOG(WARNING) << "Black listed display size detected:"
+                   << size[0] << "x" << size[1];
+      return true;
+    }
+  }
+  return false;
+}
+
+// static
+std::vector<Resolution> DisplayChangeObserver::GetResolutionList(
+    const OutputConfigurator::OutputSnapshot& output) {
+  typedef std::map<std::pair<int,int>, Resolution> ResolutionMap;
+  ResolutionMap resolution_map;
+
+  for (std::map<RRMode, OutputConfigurator::ModeInfo>::const_iterator it =
+       output.mode_infos.begin(); it != output.mode_infos.end(); ++it) {
+    const OutputConfigurator::ModeInfo& mode_info = it->second;
+    const std::pair<int, int> size(mode_info.width, mode_info.height);
+    const Resolution resolution(gfx::Size(mode_info.width, mode_info.height),
+                                mode_info.interlaced);
+
+    // Add the resolution if it isn't already present and override interlaced
+    // resolutions with non-interlaced ones.
+    ResolutionMap::iterator resolution_it = resolution_map.find(size);
+    if (resolution_it == resolution_map.end())
+      resolution_map.insert(std::make_pair(size, resolution));
+    else if (resolution_it->second.interlaced && !resolution.interlaced)
+      resolution_it->second = resolution;
+  }
+
+  std::vector<Resolution> resolution_list;
+  for (ResolutionMap::const_iterator iter = resolution_map.begin();
+       iter != resolution_map.end();
+       ++iter) {
+    resolution_list.push_back(iter->second);
+  }
+  std::sort(resolution_list.begin(), resolution_list.end(), ResolutionSorter());
+  return resolution_list;
+}
+
+DisplayChangeObserver::DisplayChangeObserver() {
+  Shell::GetInstance()->AddShellObserver(this);
+}
+
+DisplayChangeObserver::~DisplayChangeObserver() {
+  Shell::GetInstance()->RemoveShellObserver(this);
+}
+
+chromeos::OutputState DisplayChangeObserver::GetStateForDisplayIds(
+    const std::vector<int64>& display_ids) const {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAshForceMirrorMode)) {
+    return chromeos::STATE_DUAL_MIRROR;
+  }
+
+  CHECK_EQ(2U, display_ids.size());
+  DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]);
+  DisplayLayout layout = Shell::GetInstance()->display_manager()->
+      layout_store()->GetRegisteredDisplayLayout(pair);
+  return layout.mirrored ?
+      chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED;
+}
+
+bool DisplayChangeObserver::GetResolutionForDisplayId(int64 display_id,
+                                                      int* width,
+                                                      int* height) const {
+  gfx::Size resolution;
+  if (!Shell::GetInstance()->display_manager()->
+      GetSelectedResolutionForDisplayId(display_id, &resolution)) {
+    return false;
+  }
+
+  *width = resolution.width();
+  *height = resolution.height();
+  return true;
+}
+
+void DisplayChangeObserver::OnDisplayModeChanged(
+    const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
+  std::vector<DisplayInfo> displays;
+  std::set<int64> ids;
+  for (size_t i = 0; i < outputs.size(); ++i) {
+    const OutputConfigurator::OutputSnapshot& output = outputs[i];
+
+    if (output.is_internal &&
+        gfx::Display::InternalDisplayId() == gfx::Display::kInvalidDisplayID) {
+      // Fall back to output index. crbug.com/180100
+      gfx::Display::SetInternalDisplayId(
+          output.display_id == gfx::Display::kInvalidDisplayID ? output.index :
+          output.display_id);
+    }
+
+    const OutputConfigurator::ModeInfo* mode_info =
+        OutputConfigurator::GetModeInfo(output, output.current_mode);
+    if (!mode_info)
+      continue;
+
+    float device_scale_factor = 1.0f;
+    if (!ShouldIgnoreSize(output.width_mm, output.height_mm) &&
+        (kInchInMm * mode_info->width / output.width_mm) >
+        kHighDensityDPIThreshold) {
+      device_scale_factor = 2.0f;
+    }
+    gfx::Rect display_bounds(
+        output.x, output.y, mode_info->width, mode_info->height);
+
+    std::vector<Resolution> resolutions;
+    if (!output.is_internal)
+      resolutions = GetResolutionList(output);
+
+    std::string name = output.is_internal ?
+        l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) :
+        chromeos::GetDisplayName(output.output);
+    if (name.empty())
+      name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
+
+    bool has_overscan = false;
+    chromeos::GetOutputOverscanFlag(output.output, &has_overscan);
+
+    int64 id = output.display_id;
+    if (id == gfx::Display::kInvalidDisplayID || ids.find(id) != ids.end())
+      id = output.index;
+    ids.insert(id);
+
+    displays.push_back(DisplayInfo(id, name, has_overscan));
+    displays.back().set_device_scale_factor(device_scale_factor);
+    displays.back().SetBounds(display_bounds);
+    displays.back().set_native(true);
+    displays.back().set_resolutions(resolutions);
+  }
+
+  // DisplayManager can be null during the boot.
+  Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays);
+}
+
+void DisplayChangeObserver::OnAppTerminating() {
+#if defined(USE_ASH)
+  // Stop handling display configuration events once the shutdown
+  // process starts. crbug.com/177014.
+  Shell::GetInstance()->output_configurator()->Stop();
+#endif
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/display/display_change_observer_chromeos.h b/ash/display/display_change_observer_chromeos.h
new file mode 100644
index 0000000..6beb731
--- /dev/null
+++ b/ash/display/display_change_observer_chromeos.h
@@ -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.
+
+#ifndef ASH_DISPLAY_DISPLAY_CHANGE_OBSERVER_CHROMEOS_H
+#define ASH_DISPLAY_DISPLAY_CHANGE_OBSERVER_CHROMEOS_H
+
+#include "ash/ash_export.h"
+#include "ash/shell_observer.h"
+#include "base/basictypes.h"
+#include "chromeos/display/output_configurator.h"
+
+namespace ash {
+namespace internal {
+
+struct Resolution;
+
+// An object that observes changes in display configuration and
+// update DisplayManagers.
+class DisplayChangeObserver
+    : public chromeos::OutputConfigurator::StateController,
+      public chromeos::OutputConfigurator::Observer,
+      public ShellObserver {
+ public:
+  // Returns true if the size info in the output_info isn't valid
+  // and should be ignored. This is exposed for testing.
+  // |mm_width| and |mm_height| are given in millimeters.
+  ASH_EXPORT static bool ShouldIgnoreSize(unsigned long mm_width,
+                                          unsigned long mm_height);
+
+  // Returns the resolution list.
+  ASH_EXPORT static std::vector<Resolution> GetResolutionList(
+      const chromeos::OutputConfigurator::OutputSnapshot& output);
+
+  DisplayChangeObserver();
+  virtual ~DisplayChangeObserver();
+
+  // chromeos::OutputConfigurator::StateController overrides:
+  virtual chromeos::OutputState GetStateForDisplayIds(
+      const std::vector<int64>& outputs) const OVERRIDE;
+  virtual bool GetResolutionForDisplayId(int64 display_id,
+                                         int* width,
+                                         int* height) const OVERRIDE;
+
+  // Overriden from chromeos::OutputConfigurator::Observer:
+  virtual void OnDisplayModeChanged(
+      const std::vector<chromeos::OutputConfigurator::OutputSnapshot>& outputs)
+      OVERRIDE;
+
+  // Overriden from ShellObserver:
+  virtual void OnAppTerminating() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisplayChangeObserver);
+};
+
+}  // namespace internal
+}  // namespace ash
+
+#endif  // ASH_DISPLAY_AURA_DISPLAY_CHANGE_OBSERVER_CHROMEOS_H
diff --git a/ash/display/display_change_observer_chromeos_unittest.cc b/ash/display/display_change_observer_chromeos_unittest.cc
new file mode 100644
index 0000000..dc8d492
--- /dev/null
+++ b/ash/display/display_change_observer_chromeos_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 "ash/display/display_change_observer_chromeos.h"
+
+#include "ash/display/display_info.h"
+#include "chromeos/display/output_configurator.h"
+#include "chromeos/display/output_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using chromeos::OutputConfigurator;
+
+typedef testing::Test DisplayChangeObserverTest;
+
+namespace ash {
+namespace internal {
+
+TEST_F(DisplayChangeObserverTest, TestBlackListedDisplay) {
+  EXPECT_TRUE(DisplayChangeObserver::ShouldIgnoreSize(10, 10));
+  EXPECT_TRUE(DisplayChangeObserver::ShouldIgnoreSize(40, 30));
+  EXPECT_TRUE(DisplayChangeObserver::ShouldIgnoreSize(50, 40));
+  EXPECT_TRUE(DisplayChangeObserver::ShouldIgnoreSize(160, 90));
+  EXPECT_TRUE(DisplayChangeObserver::ShouldIgnoreSize(160, 100));
+
+  EXPECT_FALSE(DisplayChangeObserver::ShouldIgnoreSize(50, 60));
+  EXPECT_FALSE(DisplayChangeObserver::ShouldIgnoreSize(100, 70));
+  EXPECT_FALSE(DisplayChangeObserver::ShouldIgnoreSize(272, 181));
+}
+
+TEST_F(DisplayChangeObserverTest, GetResolutionList) {
+  OutputConfigurator::OutputSnapshot output;
+  output.mode_infos[11] = OutputConfigurator::ModeInfo(1920, 1200, false);
+
+  // All non-interlaced (as would be seen with different refresh rates).
+  output.mode_infos[12] = OutputConfigurator::ModeInfo(1920, 1080, false);
+  output.mode_infos[13] = OutputConfigurator::ModeInfo(1920, 1080, false);
+  output.mode_infos[14] = OutputConfigurator::ModeInfo(1920, 1080, false);
+
+  // Interlaced vs non-interlaced.
+  output.mode_infos[15] = OutputConfigurator::ModeInfo(1280, 720, true);
+  output.mode_infos[16] = OutputConfigurator::ModeInfo(1280, 720, false);
+
+  // Interlaced only.
+  output.mode_infos[17] = OutputConfigurator::ModeInfo(1024, 768, true);
+  output.mode_infos[18] = OutputConfigurator::ModeInfo(1024, 768, true);
+
+  // Mixed.
+  output.mode_infos[19] = OutputConfigurator::ModeInfo(1024, 600, true);
+  output.mode_infos[20] = OutputConfigurator::ModeInfo(1024, 600, false);
+  output.mode_infos[21] = OutputConfigurator::ModeInfo(1024, 600, false);
+
+  // Just one interlaced mode.
+  output.mode_infos[22] = OutputConfigurator::ModeInfo(640, 480, true);
+
+  std::vector<Resolution> resolutions =
+      DisplayChangeObserver::GetResolutionList(output);
+  ASSERT_EQ(6u, resolutions.size());
+  EXPECT_EQ("1920x1200", resolutions[0].size.ToString());
+  EXPECT_FALSE(resolutions[0].interlaced);
+
+  EXPECT_EQ("1920x1080", resolutions[1].size.ToString());
+  EXPECT_FALSE(resolutions[1].interlaced);
+
+  EXPECT_EQ("1280x720", resolutions[2].size.ToString());
+  EXPECT_FALSE(resolutions[2].interlaced);
+
+  EXPECT_EQ("1024x768", resolutions[3].size.ToString());
+  EXPECT_TRUE(resolutions[3].interlaced);
+
+  EXPECT_EQ("1024x600", resolutions[4].size.ToString());
+  EXPECT_FALSE(resolutions[4].interlaced);
+
+  EXPECT_EQ("640x480", resolutions[5].size.ToString());
+  EXPECT_TRUE(resolutions[5].interlaced);
+
+  // Outputs without any modes shouldn't cause a crash.
+  output.mode_infos.clear();
+  resolutions = DisplayChangeObserver::GetResolutionList(output);
+  EXPECT_EQ(0u, resolutions.size());
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/display/display_change_observer_x11.cc b/ash/display/display_change_observer_x11.cc
deleted file mode 100644
index 860a5ea..0000000
--- a/ash/display/display_change_observer_x11.cc
+++ /dev/null
@@ -1,199 +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 "ash/display/display_change_observer_x11.h"
-
-#include <algorithm>
-#include <map>
-#include <set>
-#include <vector>
-
-#include <X11/extensions/Xrandr.h>
-
-#include "ash/ash_switches.h"
-#include "ash/display/display_info.h"
-#include "ash/display/display_layout_store.h"
-#include "ash/display/display_manager.h"
-#include "ash/display/display_util_x11.h"
-#include "ash/shell.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_pump_aurax11.h"
-#include "chromeos/display/output_util.h"
-#include "grit/ash_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/compositor/dip_util.h"
-#include "ui/gfx/display.h"
-
-namespace ash {
-namespace internal {
-namespace {
-
-// The DPI threshold to detect high density screen.
-// Higher DPI than this will use device_scale_factor=2.
-const unsigned int kHighDensityDPIThreshold = 160;
-
-// 1 inch in mm.
-const float kInchInMm = 25.4f;
-
-int64 GetDisplayId(XID output, size_t output_index) {
-  int64 display_id;
-  if (chromeos::GetDisplayId(output, output_index, &display_id))
-    return display_id;
-  return gfx::Display::kInvalidDisplayID;
-}
-
-}  // namespace
-
-DisplayChangeObserverX11::DisplayChangeObserverX11()
-    : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()),
-      x_root_window_(DefaultRootWindow(xdisplay_)),
-      xrandr_event_base_(0) {
-  int error_base_ignored;
-  XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
-
-  Shell::GetInstance()->AddShellObserver(this);
-}
-
-DisplayChangeObserverX11::~DisplayChangeObserverX11() {
-  Shell::GetInstance()->RemoveShellObserver(this);
-}
-
-chromeos::OutputState DisplayChangeObserverX11::GetStateForDisplayIds(
-    const std::vector<int64>& display_ids) const {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAshForceMirrorMode)) {
-    return chromeos::STATE_DUAL_MIRROR;
-  }
-
-  CHECK_EQ(2U, display_ids.size());
-  DisplayIdPair pair = std::make_pair(display_ids[0], display_ids[1]);
-  DisplayLayout layout = Shell::GetInstance()->display_manager()->
-      layout_store()->GetRegisteredDisplayLayout(pair);
-  return layout.mirrored ?
-      chromeos::STATE_DUAL_MIRROR : chromeos::STATE_DUAL_EXTENDED;
-}
-
-bool DisplayChangeObserverX11::GetResolutionForDisplayId(int64 display_id,
-                                                         int* width,
-                                                         int* height) const {
-
-  gfx::Size resolution;
-  if (!Shell::GetInstance()->display_manager()->
-      GetSelectedResolutionForDisplayId(display_id, &resolution)) {
-    return false;
-  }
-
-  *width = resolution.width();
-  *height = resolution.height();
-  return true;
-}
-
-void DisplayChangeObserverX11::OnDisplayModeChanged() {
-  XRRScreenResources* screen_resources =
-      XRRGetScreenResources(xdisplay_, x_root_window_);
-  std::map<XID, XRRCrtcInfo*> crtc_info_map;
-
-  for (int c = 0; c < screen_resources->ncrtc; c++) {
-    XID crtc_id = screen_resources->crtcs[c];
-    XRRCrtcInfo *crtc_info =
-        XRRGetCrtcInfo(xdisplay_, screen_resources, crtc_id);
-    crtc_info_map[crtc_id] = crtc_info;
-  }
-
-  std::vector<DisplayInfo> displays;
-  std::set<int64> ids;
-  for (int output_index = 0; output_index < screen_resources->noutput;
-       output_index++) {
-    XID output = screen_resources->outputs[output_index];
-    XRROutputInfo *output_info =
-        XRRGetOutputInfo(xdisplay_, screen_resources, output);
-
-    const bool is_internal = chromeos::IsInternalOutputName(
-        std::string(output_info->name));
-
-    if (is_internal &&
-        gfx::Display::InternalDisplayId() == gfx::Display::kInvalidDisplayID) {
-      int64 id = GetDisplayId(output, output_index);
-      // Fallback to output index. crbug.com/180100
-      gfx::Display::SetInternalDisplayId(
-          id == gfx::Display::kInvalidDisplayID ? output_index : id);
-    }
-
-    if (output_info->connection != RR_Connected) {
-      XRRFreeOutputInfo(output_info);
-      continue;
-    }
-    const XRRCrtcInfo* crtc_info = crtc_info_map[output_info->crtc];
-    if (!crtc_info) {
-      LOG(WARNING) << "Crtc not found for output: output_index="
-                   << output_index;
-      continue;
-    }
-    const XRRModeInfo* mode =
-        chromeos::FindModeInfo(screen_resources, crtc_info->mode);
-    if (!mode) {
-      LOG(WARNING) << "Could not find a mode for the output: output_index="
-                   << output_index;
-      continue;
-    }
-
-    float device_scale_factor = 1.0f;
-    if (!ShouldIgnoreSize(output_info->mm_width, output_info->mm_height) &&
-        (kInchInMm * mode->width / output_info->mm_width) >
-        kHighDensityDPIThreshold) {
-      device_scale_factor = 2.0f;
-    }
-    gfx::Rect display_bounds(
-        crtc_info->x, crtc_info->y, mode->width, mode->height);
-
-    std::vector<Resolution> resolutions;
-    if (!is_internal)
-      resolutions = GetResolutionList(screen_resources, output_info);
-
-    XRRFreeOutputInfo(output_info);
-
-    std::string name = is_internal ?
-        l10n_util::GetStringUTF8(IDS_ASH_INTERNAL_DISPLAY_NAME) :
-        chromeos::GetDisplayName(output);
-    if (name.empty())
-      name = l10n_util::GetStringUTF8(IDS_ASH_STATUS_TRAY_UNKNOWN_DISPLAY_NAME);
-
-    bool has_overscan = false;
-    chromeos::GetOutputOverscanFlag(output, &has_overscan);
-
-    int64 id = GetDisplayId(output, output_index);
-
-    // If ID is invalid or there is an duplicate, just use output index.
-    if (id == gfx::Display::kInvalidDisplayID || ids.find(id) != ids.end())
-      id = output_index;
-    ids.insert(id);
-
-    displays.push_back(DisplayInfo(id, name, has_overscan));
-    displays.back().set_device_scale_factor(device_scale_factor);
-    displays.back().SetBounds(display_bounds);
-    displays.back().set_native(true);
-    displays.back().set_resolutions(resolutions);
-  }
-
-  // Free all allocated resources.
-  for (std::map<XID, XRRCrtcInfo*>::const_iterator iter = crtc_info_map.begin();
-       iter != crtc_info_map.end(); ++iter) {
-    XRRFreeCrtcInfo(iter->second);
-  }
-  XRRFreeScreenResources(screen_resources);
-
-  // DisplayManager can be null during the boot.
-  Shell::GetInstance()->display_manager()->OnNativeDisplaysChanged(displays);
-}
-
-void DisplayChangeObserverX11::OnAppTerminating() {
-#if defined(USE_ASH)
-  // Stop handling display configuration events once the shutdown
-  // process starts. crbug.com/177014.
-  Shell::GetInstance()->output_configurator()->Stop();
-#endif
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/display/display_change_observer_x11.h b/ash/display/display_change_observer_x11.h
deleted file mode 100644
index 6781151..0000000
--- a/ash/display/display_change_observer_x11.h
+++ /dev/null
@@ -1,57 +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_DISPLAY_DISPLAY_CHANGE_OBSERVER_X11_H
-#define ASH_DISPLAY_DISPLAY_CHANGE_OBSERVER_X11_H
-
-#include <X11/Xlib.h>
-
-// Xlib.h defines RootWindow.
-#undef RootWindow
-
-#include "ash/ash_export.h"
-#include "ash/shell_observer.h"
-#include "base/basictypes.h"
-#include "chromeos/display/output_configurator.h"
-
-namespace ash {
-namespace internal {
-
-// An object that observes changes in display configuration and
-// update DisplayManagers.
-class DisplayChangeObserverX11
-    : public chromeos::OutputConfigurator::StateController,
-      public chromeos::OutputConfigurator::Observer,
-      public ShellObserver {
- public:
-  DisplayChangeObserverX11();
-  virtual ~DisplayChangeObserverX11();
-
-  // chromeos::OutputConfigurator::StateController overrides:
-  virtual chromeos::OutputState GetStateForDisplayIds(
-      const std::vector<int64>& outputs) const OVERRIDE;
-  virtual bool GetResolutionForDisplayId(int64 display_id,
-                                         int* width,
-                                         int* height) const OVERRIDE;
-
-  // Overriden from chromeos::OutputConfigurator::Observer:
-  virtual void OnDisplayModeChanged() OVERRIDE;
-
-  // Overriden from ShellObserver:
-  virtual void OnAppTerminating() OVERRIDE;
-
- private:
-  Display* xdisplay_;
-
-  ::Window x_root_window_;
-
-  int xrandr_event_base_;
-
-  DISALLOW_COPY_AND_ASSIGN(DisplayChangeObserverX11);
-};
-
-}  // namespace internal
-}  // namespace ash
-
-#endif  // ASH_DISPLAY_AURA_DISPLAY_CHANGE_OBSERVER_X11_H
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
index fce5a82..f0ac711 100644
--- a/ash/display/display_controller.cc
+++ b/ash/display/display_controller.cc
@@ -288,15 +288,14 @@
 }
 
 void DisplayController::InitPrimaryDisplay() {
-  const gfx::Display* primary_candidate =
+  const gfx::Display& primary_candidate =
       GetDisplayManager()->GetPrimaryDisplayCandidate();
-  primary_display_id = primary_candidate->id();
-  AddRootWindowForDisplay(*primary_candidate);
+  primary_display_id = primary_candidate.id();
+  AddRootWindowForDisplay(primary_candidate);
 }
 
 void DisplayController::InitSecondaryDisplays() {
   internal::DisplayManager* display_manager = GetDisplayManager();
-  UpdateDisplayBoundsForLayout();
   for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
     const gfx::Display& display = display_manager->GetDisplayAt(i);
     if (primary_display_id != display.id()) {
@@ -304,13 +303,6 @@
       Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root);
     }
   }
-  if (display_manager->GetNumDisplays() > 1) {
-    DisplayIdPair pair = GetCurrentDisplayIdPair();
-    DisplayLayout layout = GetCurrentDisplayLayout();
-    SetPrimaryDisplayId(
-        layout.primary_id == gfx::Display::kInvalidDisplayID ?
-        pair.first : layout.primary_id);
-  }
   UpdateHostWindowNames();
 }
 
@@ -387,7 +379,7 @@
   if (GetDisplayManager()->GetNumDisplays() < 2)
     return;
   const gfx::Display& primary = GetPrimaryDisplay();
-  const DisplayIdPair pair = GetCurrentDisplayIdPair();
+  const DisplayIdPair pair = GetDisplayManager()->GetCurrentDisplayIdPair();
   // Invert if the primary was swapped.
   DisplayLayout to_set = pair.first == primary.id() ?
       layout_relative_to_primary : layout_relative_to_primary.Invert();
@@ -412,40 +404,6 @@
   }
 }
 
-DisplayLayout DisplayController::GetCurrentDisplayLayout() {
-  DCHECK_EQ(2U, GetDisplayManager()->num_connected_displays());
-  // Invert if the primary was swapped.
-  if (GetDisplayManager()->num_connected_displays() > 1) {
-    DisplayIdPair pair = GetCurrentDisplayIdPair();
-    return GetDisplayManager()->layout_store()->
-        ComputeDisplayLayoutForDisplayIdPair(pair);
-  }
-  NOTREACHED() << "DisplayLayout is requested for single display";
-  // On release build, just fallback to default instead of blowing up.
-  DisplayLayout layout =
-      GetDisplayManager()->layout_store()->default_display_layout();
-  layout.primary_id = primary_display_id;
-  return layout;
-}
-
-DisplayIdPair DisplayController::GetCurrentDisplayIdPair() const {
-  internal::DisplayManager* display_manager = GetDisplayManager();
-  const gfx::Display& primary = GetPrimaryDisplay();
-  if (display_manager->IsMirrored()) {
-    return std::make_pair(primary.id(),
-                          display_manager->mirrored_display().id());
-  }
-
-  const gfx::Display& secondary = ScreenAsh::GetSecondaryDisplay();
-  if (primary.IsInternal() ||
-      GetDisplayManager()->first_display_id() == primary.id()) {
-    return std::make_pair(primary.id(), secondary.id());
-  } else {
-    // Display has been Swapped.
-    return std::make_pair(secondary.id(), primary.id());
-  }
-}
-
 void DisplayController::ToggleMirrorMode() {
   internal::DisplayManager* display_manager = GetDisplayManager();
   if (display_manager->num_connected_displays() <= 1)
@@ -542,7 +500,7 @@
 
   primary_display_id = new_primary_display.id();
   GetDisplayManager()->layout_store()->UpdatePrimaryDisplayId(
-      GetCurrentDisplayIdPair(), primary_display_id);
+      display_manager->GetCurrentDisplayIdPair(), primary_display_id);
 
   UpdateWorkAreaOfDisplayNearestWindow(
       primary_root, old_primary_display.GetWorkAreaInsets());
@@ -783,7 +741,7 @@
   internal::DisplayManager* display_manager = GetDisplayManager();
   internal::DisplayLayoutStore* layout_store = display_manager->layout_store();
   if (display_manager->num_connected_displays() > 1) {
-    DisplayIdPair pair = GetCurrentDisplayIdPair();
+    DisplayIdPair pair = display_manager->GetCurrentDisplayIdPair();
     layout_store->UpdateMirrorStatus(pair, display_manager->IsMirrored());
     DisplayLayout layout = layout_store->GetRegisteredDisplayLayout(pair);
 
@@ -837,14 +795,15 @@
 }
 
 void DisplayController::UpdateDisplayBoundsForLayout() {
+  internal::DisplayManager* display_manager = GetDisplayManager();
   if (Shell::GetScreen()->GetNumDisplays() < 2 ||
-      GetDisplayManager()->num_connected_displays() < 2) {
+      display_manager->num_connected_displays() < 2) {
     return;
   }
   DCHECK_EQ(2, Shell::GetScreen()->GetNumDisplays());
 
-  const DisplayLayout layout = GetCurrentDisplayLayout();
-  Shell::GetInstance()->display_manager()->UpdateDisplayBoundsForLayoutById(
+  const DisplayLayout layout = display_manager->GetCurrentDisplayLayout();
+  display_manager->UpdateDisplayBoundsForLayoutById(
       layout, GetPrimaryDisplay(),
       ScreenAsh::GetSecondaryDisplay().id());
 }
diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h
index f67f27d..97620fc 100644
--- a/ash/display/display_controller.h
+++ b/ash/display/display_controller.h
@@ -133,12 +133,6 @@
   // the locaion of the secondary display relative to the primary.
   void SetLayoutForCurrentDisplays(const DisplayLayout& layout);
 
-  // Returns the display layout used for current displays.
-  DisplayLayout GetCurrentDisplayLayout();
-
-  // Returns the current display pair.
-  DisplayIdPair GetCurrentDisplayIdPair() const;
-
   // Checks if the mouse pointer is on one of displays, and moves to
   // the center of the nearest display if it's outside of all displays.
   void EnsurePointerInDisplays();
diff --git a/ash/display/display_controller_unittest.cc b/ash/display/display_controller_unittest.cc
index 9131468..7e6a048 100644
--- a/ash/display/display_controller_unittest.cc
+++ b/ash/display/display_controller_unittest.cc
@@ -416,31 +416,6 @@
   EXPECT_EQ(0, observer.CountAndReset());
 }
 
-TEST_F(DisplayControllerTest, MirroredLayout) {
-  if (!SupportsMultipleDisplays())
-    return;
-
-  DisplayController* display_controller =
-      Shell::GetInstance()->display_controller();
-  UpdateDisplay("500x500,400x400");
-  EXPECT_FALSE(display_controller->GetCurrentDisplayLayout().mirrored);
-  EXPECT_EQ(2, Shell::GetScreen()->GetNumDisplays());
-  EXPECT_EQ(
-      2U, Shell::GetInstance()->display_manager()->num_connected_displays());
-
-  UpdateDisplay("1+0-500x500,1+0-500x500");
-  EXPECT_TRUE(display_controller->GetCurrentDisplayLayout().mirrored);
-  EXPECT_EQ(1, Shell::GetScreen()->GetNumDisplays());
-  EXPECT_EQ(
-      2U, Shell::GetInstance()->display_manager()->num_connected_displays());
-
-  UpdateDisplay("500x500,500x500");
-  EXPECT_FALSE(display_controller->GetCurrentDisplayLayout().mirrored);
-  EXPECT_EQ(2, Shell::GetScreen()->GetNumDisplays());
-  EXPECT_EQ(
-      2U, Shell::GetInstance()->display_manager()->num_connected_displays());
-}
-
 TEST_F(DisplayControllerTest, InvertLayout) {
   EXPECT_EQ("left, 0",
             DisplayLayout(DisplayLayout::RIGHT, 0).Invert().ToString());
@@ -477,6 +452,8 @@
 
   DisplayController* display_controller =
       Shell::GetInstance()->display_controller();
+  internal::DisplayManager* display_manager =
+      Shell::GetInstance()->display_manager();
 
   UpdateDisplay("200x200,300x300");
   gfx::Display primary_display = Shell::GetScreen()->GetPrimaryDisplay();
@@ -506,12 +483,12 @@
   EXPECT_EQ("200,0 300x300", secondary_display.bounds().ToString());
   EXPECT_EQ("200,0 300x252", secondary_display.work_area().ToString());
   EXPECT_EQ("right, 50",
-            display_controller->GetCurrentDisplayLayout().ToString());
+            display_manager->GetCurrentDisplayLayout().ToString());
 
   // Switch primary and secondary
   display_controller->SetPrimaryDisplay(secondary_display);
   const DisplayLayout& inverted_layout =
-      display_controller->GetCurrentDisplayLayout();
+      display_manager->GetCurrentDisplayLayout();
   EXPECT_EQ("left, -50", inverted_layout.ToString());
 
   EXPECT_EQ(secondary_display.id(),
@@ -566,6 +543,8 @@
 
   DisplayController* display_controller =
       Shell::GetInstance()->display_controller();
+  internal::DisplayManager* display_manager =
+      Shell::GetInstance()->display_manager();
 
   UpdateDisplay("200x200,300x300");
   gfx::Display primary_display = Shell::GetScreen()->GetPrimaryDisplay();
@@ -608,7 +587,7 @@
   EXPECT_FALSE(secondary_root->Contains(launcher_window));
 
   const DisplayLayout& inverted_layout =
-      display_controller->GetCurrentDisplayLayout();
+      display_manager->GetCurrentDisplayLayout();
 
   EXPECT_EQ("left, -50", inverted_layout.ToString());
 
@@ -634,8 +613,6 @@
   EXPECT_FALSE(tracker.Contains(secondary_root));
   EXPECT_TRUE(primary_root->Contains(launcher_window));
 
-  internal::DisplayManager* display_manager =
-      Shell::GetInstance()->display_manager();
   // Adding 2nd display with the same ID.  The 2nd display should become primary
   // since secondary id is still stored as desirable_primary_id.
   std::vector<internal::DisplayInfo> display_info_list;
diff --git a/ash/display/display_error_observer.cc b/ash/display/display_error_observer.cc
deleted file mode 100644
index d4080a2..0000000
--- a/ash/display/display_error_observer.cc
+++ /dev/null
@@ -1,89 +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/display/display_error_observer.h"
-
-#include "grit/ash_resources.h"
-#include "grit/ash_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/message_center/message_center.h"
-#include "ui/message_center/notification.h"
-#include "ui/message_center/notification_delegate.h"
-#include "ui/message_center/notification_list.h"
-
-using message_center::Notification;
-
-namespace ash {
-namespace internal {
-namespace {
-
-const char kDisplayErrorNotificationId[] = "chrome://settings/display/error";
-
-class DisplayErrorNotificationDelegate
-    : public message_center::NotificationDelegate {
- public:
-  DisplayErrorNotificationDelegate() {}
-
-  // message_center::NotificationDelegate overrides:
-  virtual void Display() OVERRIDE {}
-  virtual void Error() OVERRIDE {}
-  virtual void Close(bool by_user) OVERRIDE {}
-  virtual bool HasClickedListener() OVERRIDE { return false; }
-  virtual void Click() OVERRIDE { }
-
- protected:
-  virtual ~DisplayErrorNotificationDelegate() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DisplayErrorNotificationDelegate);
-};
-
-}  // namespace
-
-DisplayErrorObserver::DisplayErrorObserver() {
-}
-
-DisplayErrorObserver::~DisplayErrorObserver() {
-}
-
-void DisplayErrorObserver::OnDisplayModeChangeFailed(
-    chromeos::OutputState new_state) {
-  // Always remove the notification to make sure the notification appears
-  // as a popup in any situation.
-  message_center::MessageCenter::Get()->RemoveNotification(
-      kDisplayErrorNotificationId, false /* by_user */);
-
-  int message_id = (new_state == chromeos::STATE_DUAL_MIRROR) ?
-      IDS_ASH_DISPLAY_FAILURE_ON_MIRRORING :
-      IDS_ASH_DISPLAY_FAILURE_ON_NON_MIRRORING;
-
-  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  scoped_ptr<Notification> notification(new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE,
-      kDisplayErrorNotificationId,
-      l10n_util::GetStringUTF16(message_id),
-      base::string16(),  // message
-      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY),
-      base::string16(),  // display_source
-      std::string(),  // extension_id
-      message_center::RichNotificationData(),
-      new DisplayErrorNotificationDelegate()));
-  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
-}
-
-string16 DisplayErrorObserver::GetTitleOfDisplayErrorNotificationForTest() {
-  message_center::NotificationList::Notifications notifications =
-      message_center::MessageCenter::Get()->GetNotifications();
-  for (message_center::NotificationList::Notifications::const_iterator iter =
-           notifications.begin(); iter != notifications.end(); ++iter) {
-    if ((*iter)->id() == kDisplayErrorNotificationId)
-      return (*iter)->title();
-  }
-
-  return base::string16();
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/display/display_error_observer.h b/ash/display/display_error_observer.h
deleted file mode 100644
index 5cba904..0000000
--- a/ash/display/display_error_observer.h
+++ /dev/null
@@ -1,39 +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_DISPLAY_DISPLAY_ERROR_OBSERVER_H_
-#define ASH_DISPLAY_DISPLAY_ERROR_OBSERVER_H_
-
-#include "ash/ash_export.h"
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "chromeos/display/output_configurator.h"
-
-namespace ash {
-namespace internal {
-
-// The class to observe the output failures and shows the error dialog when
-// necessary.
-class ASH_EXPORT DisplayErrorObserver
-    : public chromeos::OutputConfigurator::Observer {
- public:
-  DisplayErrorObserver();
-  virtual ~DisplayErrorObserver();
-
-  // chromeos::OutputConfigurator::Observer overrides:
-  virtual void OnDisplayModeChangeFailed(
-      chromeos::OutputState failed_new_state) OVERRIDE;
-
- private:
-  friend class DisplayErrorObserverTest;
-
-  base::string16 GetTitleOfDisplayErrorNotificationForTest();
-
-  DISALLOW_COPY_AND_ASSIGN(DisplayErrorObserver);
-};
-
-}  // namespace internal
-}  // namespace ash
-
-#endif  // ASH_DISPLAY_DISPLAY_ERROR_OBSERVER_H_
diff --git a/ash/display/display_error_observer_chromeos.cc b/ash/display/display_error_observer_chromeos.cc
new file mode 100644
index 0000000..f12b61e
--- /dev/null
+++ b/ash/display/display_error_observer_chromeos.cc
@@ -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.
+
+#include "ash/display/display_error_observer_chromeos.h"
+
+#include "grit/ash_resources.h"
+#include "grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_delegate.h"
+#include "ui/message_center/notification_list.h"
+
+using message_center::Notification;
+
+namespace ash {
+namespace internal {
+namespace {
+
+const char kDisplayErrorNotificationId[] = "chrome://settings/display/error";
+
+class DisplayErrorNotificationDelegate
+    : public message_center::NotificationDelegate {
+ public:
+  DisplayErrorNotificationDelegate() {}
+
+  // message_center::NotificationDelegate overrides:
+  virtual void Display() OVERRIDE {}
+  virtual void Error() OVERRIDE {}
+  virtual void Close(bool by_user) OVERRIDE {}
+  virtual bool HasClickedListener() OVERRIDE { return false; }
+  virtual void Click() OVERRIDE { }
+
+ protected:
+  virtual ~DisplayErrorNotificationDelegate() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisplayErrorNotificationDelegate);
+};
+
+}  // namespace
+
+DisplayErrorObserver::DisplayErrorObserver() {
+}
+
+DisplayErrorObserver::~DisplayErrorObserver() {
+}
+
+void DisplayErrorObserver::OnDisplayModeChangeFailed(
+    chromeos::OutputState new_state) {
+  // Always remove the notification to make sure the notification appears
+  // as a popup in any situation.
+  message_center::MessageCenter::Get()->RemoveNotification(
+      kDisplayErrorNotificationId, false /* by_user */);
+
+  int message_id = (new_state == chromeos::STATE_DUAL_MIRROR) ?
+      IDS_ASH_DISPLAY_FAILURE_ON_MIRRORING :
+      IDS_ASH_DISPLAY_FAILURE_ON_NON_MIRRORING;
+
+  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+  scoped_ptr<Notification> notification(new Notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE,
+      kDisplayErrorNotificationId,
+      l10n_util::GetStringUTF16(message_id),
+      base::string16(),  // message
+      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY),
+      base::string16(),  // display_source
+      std::string(),  // extension_id
+      message_center::RichNotificationData(),
+      new DisplayErrorNotificationDelegate()));
+  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
+}
+
+string16 DisplayErrorObserver::GetTitleOfDisplayErrorNotificationForTest() {
+  message_center::NotificationList::Notifications notifications =
+      message_center::MessageCenter::Get()->GetNotifications();
+  for (message_center::NotificationList::Notifications::const_iterator iter =
+           notifications.begin(); iter != notifications.end(); ++iter) {
+    if ((*iter)->id() == kDisplayErrorNotificationId)
+      return (*iter)->title();
+  }
+
+  return base::string16();
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/display/display_error_observer_chromeos.h b/ash/display/display_error_observer_chromeos.h
new file mode 100644
index 0000000..b8bb1c1
--- /dev/null
+++ b/ash/display/display_error_observer_chromeos.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 ASH_DISPLAY_DISPLAY_ERROR_OBSERVER_CHROMEOS_H_
+#define ASH_DISPLAY_DISPLAY_ERROR_OBSERVER_CHROMEOS_H_
+
+#include "ash/ash_export.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "chromeos/display/output_configurator.h"
+
+namespace ash {
+namespace internal {
+
+// The class to observe the output failures and shows the error dialog when
+// necessary.
+class ASH_EXPORT DisplayErrorObserver
+    : public chromeos::OutputConfigurator::Observer {
+ public:
+  DisplayErrorObserver();
+  virtual ~DisplayErrorObserver();
+
+  // chromeos::OutputConfigurator::Observer overrides:
+  virtual void OnDisplayModeChangeFailed(
+      chromeos::OutputState failed_new_state) OVERRIDE;
+
+ private:
+  friend class DisplayErrorObserverTest;
+
+  base::string16 GetTitleOfDisplayErrorNotificationForTest();
+
+  DISALLOW_COPY_AND_ASSIGN(DisplayErrorObserver);
+};
+
+}  // namespace internal
+}  // namespace ash
+
+#endif  // ASH_DISPLAY_DISPLAY_ERROR_OBSERVER_CHROMEOS_H_
diff --git a/ash/display/display_error_observer_chromeos_unittest.cc b/ash/display/display_error_observer_chromeos_unittest.cc
new file mode 100644
index 0000000..7cd0503
--- /dev/null
+++ b/ash/display/display_error_observer_chromeos_unittest.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 "ash/display/display_error_observer_chromeos.h"
+
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "grit/ash_strings.h"
+#include "ui/aura/window.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+namespace internal {
+
+class DisplayErrorObserverTest : public test::AshTestBase {
+ protected:
+  DisplayErrorObserverTest() {
+  }
+
+  virtual ~DisplayErrorObserverTest() {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    test::AshTestBase::SetUp();
+    observer_.reset(new DisplayErrorObserver());
+  }
+
+ protected:
+  DisplayErrorObserver* observer() { return observer_.get(); }
+
+  base::string16 GetMessageContents() {
+    return observer_->GetTitleOfDisplayErrorNotificationForTest();
+  }
+
+ private:
+  scoped_ptr<DisplayErrorObserver> observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplayErrorObserverTest);
+};
+
+TEST_F(DisplayErrorObserverTest, Normal) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("200x200,300x300");
+  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_FAILURE_ON_MIRRORING),
+            GetMessageContents());
+}
+
+TEST_F(DisplayErrorObserverTest, CallTwice) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("200x200,300x300");
+  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
+  base::string16 message = GetMessageContents();
+  EXPECT_FALSE(message.empty());
+
+  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
+  base::string16 message2 = GetMessageContents();
+  EXPECT_FALSE(message2.empty());
+  EXPECT_EQ(message, message2);
+}
+
+TEST_F(DisplayErrorObserverTest, CallWithDifferentState) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("200x200,300x300");
+  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_FAILURE_ON_MIRRORING),
+            GetMessageContents());
+
+  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_EXTENDED);
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_FAILURE_ON_NON_MIRRORING),
+            GetMessageContents());
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/display/display_error_observer_unittest.cc b/ash/display/display_error_observer_unittest.cc
deleted file mode 100644
index abe4907..0000000
--- a/ash/display/display_error_observer_unittest.cc
+++ /dev/null
@@ -1,85 +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/display/display_error_observer.h"
-
-#include "ash/shell.h"
-#include "ash/test/ash_test_base.h"
-#include "grit/ash_strings.h"
-#include "ui/aura/window.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-namespace internal {
-
-class DisplayErrorObserverTest : public test::AshTestBase {
- protected:
-  DisplayErrorObserverTest() {
-  }
-
-  virtual ~DisplayErrorObserverTest() {
-  }
-
-  virtual void SetUp() OVERRIDE {
-    test::AshTestBase::SetUp();
-    observer_.reset(new DisplayErrorObserver());
-  }
-
- protected:
-  DisplayErrorObserver* observer() { return observer_.get(); }
-
-  base::string16 GetMessageContents() {
-    return observer_->GetTitleOfDisplayErrorNotificationForTest();
-  }
-
- private:
-  scoped_ptr<DisplayErrorObserver> observer_;
-
-  DISALLOW_COPY_AND_ASSIGN(DisplayErrorObserverTest);
-};
-
-TEST_F(DisplayErrorObserverTest, Normal) {
-  if (!SupportsMultipleDisplays())
-    return;
-
-  UpdateDisplay("200x200,300x300");
-  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_FAILURE_ON_MIRRORING),
-            GetMessageContents());
-}
-
-TEST_F(DisplayErrorObserverTest, CallTwice) {
-  if (!SupportsMultipleDisplays())
-    return;
-
-  UpdateDisplay("200x200,300x300");
-  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
-  base::string16 message = GetMessageContents();
-  EXPECT_FALSE(message.empty());
-
-  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
-  base::string16 message2 = GetMessageContents();
-  EXPECT_FALSE(message2.empty());
-  EXPECT_EQ(message, message2);
-}
-
-TEST_F(DisplayErrorObserverTest, CallWithDifferentState) {
-  if (!SupportsMultipleDisplays())
-    return;
-
-  UpdateDisplay("200x200,300x300");
-  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_MIRROR);
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_FAILURE_ON_MIRRORING),
-            GetMessageContents());
-
-  observer()->OnDisplayModeChangeFailed(chromeos::STATE_DUAL_EXTENDED);
-  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_DISPLAY_FAILURE_ON_NON_MIRRORING),
-            GetMessageContents());
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/display/display_info.cc b/ash/display/display_info.cc
index 8f71e6d..5dcca89 100644
--- a/ash/display/display_info.cc
+++ b/ash/display/display_info.cc
@@ -96,6 +96,20 @@
              &device_scale_factor) >= 4) {
     bounds_in_pixel.SetRect(x, y, width, height);
   }
+
+  std::vector<Resolution> resolutions;
+  if (Tokenize(main_spec, "#", &parts) == 2) {
+    main_spec = parts[0];
+    std::string resolution_list = parts[1];
+    count = Tokenize(resolution_list, "|", &parts);
+    for (size_t i = 0; i < count; ++i) {
+      std::string resolution = parts[i];
+      int width, height;
+      if (sscanf(resolution.c_str(), "%dx%d", &width, &height) == 2)
+        resolutions.push_back(Resolution(gfx::Size(width, height), false));
+    }
+  }
+
   if (id == gfx::Display::kInvalidDisplayID)
     id = synthesized_display_id++;
   DisplayInfo display_info(
@@ -104,6 +118,7 @@
   display_info.set_rotation(rotation);
   display_info.set_ui_scale(ui_scale);
   display_info.SetBounds(bounds_in_pixel);
+  display_info.set_resolutions(resolutions);
 
   // To test the overscan, it creates the default 5% overscan.
   if (has_overscan) {
@@ -164,7 +179,7 @@
 
   // Rotation_ and ui_scale_ are given by preference, or unit
   // tests. Don't copy if this native_info came from
-  // DisplayChangeObserverX11.
+  // DisplayChangeObserver.
   if (!native_info.native()) {
     rotation_ = native_info.rotation_;
     ui_scale_ = native_info.ui_scale_;
diff --git a/ash/display/display_info.h b/ash/display/display_info.h
index 899dd15..57f250d 100644
--- a/ash/display/display_info.h
+++ b/ash/display/display_info.h
@@ -36,7 +36,8 @@
   // whose size is 1440x800 at the location (100, 200) in host coordinates.
   // The format is
   //
-  // [origin-]widthxheight[*device_scale_factor][/<properties>][@ui-scale]
+  // [origin-]widthxheight[*device_scale_factor][#resolutions list]
+  //     [/<properties>][@ui-scale]
   //
   // where [] are optional:
   // - |origin| is given in x+y- format.
@@ -46,6 +47,8 @@
   //   (to the 'r'ight) 'u' is 180 degrees ('u'pside-down) and 'l' is
   //   270 degrees (to the 'l'eft).
   // - ui-scale is floating value, e.g. @1.5 or @1.25.
+  // - |resolution list| is the list of size that is given in
+  //   |width x height| separated by '|'.
   //
   // A couple of examples:
   // "100x100"
@@ -61,6 +64,9 @@
   // "10+20-300x200/u@1.5"
   //      300x200 window at 10,20 origin. 1x device scale factor.
   //      no overscan. flipped upside-down (180 degree) and 1.5 ui scale.
+  // "200x100#300x200|200x100|100x100"
+  //      200x100 window at 0,0 origin, with 3 possible resolutions,
+  //      300x200, 200x100 and 100x100.
   static DisplayInfo CreateFromSpec(const std::string& spec);
 
   // Creates a DisplayInfo from string spec using given |id|.
@@ -154,7 +160,7 @@
   // UI scale of the display.
   float ui_scale_;
 
-  // True if this comes from native platform (DisplayChangeObserverX11).
+  // True if this comes from native platform (DisplayChangeObserver).
   bool native_;
 
   // The list of resolutions supported by this display.
diff --git a/ash/display/display_info_unittest.cc b/ash/display/display_info_unittest.cc
index d425046..4e9768d 100644
--- a/ash/display/display_info_unittest.cc
+++ b/ash/display/display_info_unittest.cc
@@ -43,6 +43,14 @@
   EXPECT_EQ("10,20 300x400", info.bounds_in_pixel().ToString());
   EXPECT_EQ(gfx::Display::ROTATE_270, info.rotation());
   EXPECT_EQ(1.5f, info.ui_scale());
+
+  info = DisplayInfo::CreateFromSpecWithID(
+      "200x200#300x200|200x200|100x100", 10);
+  EXPECT_EQ("0,0 200x200", info.bounds_in_pixel().ToString());
+  EXPECT_EQ(3u, info.resolutions().size());
+  EXPECT_EQ("300x200", info.resolutions()[0].size.ToString());
+  EXPECT_EQ("200x200", info.resolutions()[1].size.ToString());
+  EXPECT_EQ("100x100", info.resolutions()[2].size.ToString());
 }
 
 }  // namespace internal
diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc
index 5943f99..1c3edea 100644
--- a/ash/display/display_manager.cc
+++ b/ash/display/display_manager.cc
@@ -72,6 +72,14 @@
   }
 };
 
+struct ResolutionMatcher {
+  ResolutionMatcher(const gfx::Size& size) : size(size) {}
+  bool operator()(const Resolution& resolution) {
+    return resolution.size == size;
+  }
+  gfx::Size size;
+};
+
 struct ScaleComparator {
   ScaleComparator(float s) : scale(s) {}
 
@@ -87,6 +95,12 @@
   return *invalid_display;
 }
 
+void MaybeInitInternalDisplay(int64 id) {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal))
+    gfx::Display::SetInternalDisplayId(id);
+}
+
 // Scoped objects used to either create or close the mirror window
 // at specific timing.
 class MirrorWindowCreator {
@@ -201,9 +215,8 @@
        iter != parts.end(); ++iter) {
     info_list.push_back(DisplayInfo::CreateFromSpec(*iter));
   }
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kAshUseFirstDisplayAsInternal))
-    gfx::Display::SetInternalDisplayId(info_list[0].id());
+  if (info_list.size())
+    MaybeInitInternalDisplay(info_list[0].id());
   OnNativeDisplaysChanged(info_list);
 }
 
@@ -236,6 +249,38 @@
   return gfx::Display::InternalDisplayId() == id;
 }
 
+DisplayLayout DisplayManager::GetCurrentDisplayLayout() {
+  DCHECK_EQ(2U, num_connected_displays());
+  // Invert if the primary was swapped.
+  if (num_connected_displays() > 1) {
+    DisplayIdPair pair = GetCurrentDisplayIdPair();
+    return layout_store_->ComputeDisplayLayoutForDisplayIdPair(pair);
+  }
+  NOTREACHED() << "DisplayLayout is requested for single display";
+  // On release build, just fallback to default instead of blowing up.
+  DisplayLayout layout =
+      layout_store_->default_display_layout();
+  layout.primary_id = displays_[0].id();
+  return layout;
+}
+
+DisplayIdPair DisplayManager::GetCurrentDisplayIdPair() const {
+  if (IsMirrored()) {
+    int64 mirrored_id = mirrored_display().id();
+    return displays_[0].id() == mirrored_id ?
+        std::make_pair(displays_[1].id(), mirrored_id) :
+        std::make_pair(displays_[0].id(), mirrored_id);
+  } else {
+    int64 id_at_zero = displays_[0].id();
+    if (id_at_zero == gfx::Display::InternalDisplayId() ||
+        id_at_zero == first_display_id()) {
+      return std::make_pair(id_at_zero, displays_[1].id());
+    } else {
+      return std::make_pair(displays_[1].id(), id_at_zero);
+    }
+  }
+}
+
 const gfx::Display& DisplayManager::GetDisplayForId(int64 id) const {
   gfx::Display* display =
       const_cast<DisplayManager*>(this)->FindDisplayForId(id);
@@ -276,8 +321,6 @@
 
 void DisplayManager::SetDisplayRotation(int64 display_id,
                                         gfx::Display::Rotation rotation) {
-  if (!IsDisplayRotationEnabled())
-    return;
   DisplayInfoList display_info_list;
   for (DisplayList::const_iterator iter = displays_.begin();
        iter != displays_.end(); ++iter) {
@@ -326,7 +369,23 @@
   DCHECK_NE(gfx::Display::InternalDisplayId(), display_id);
   if (gfx::Display::InternalDisplayId() == display_id)
     return;
-  resolutions_[display_id] = resolution;
+  const DisplayInfo& display_info = GetDisplayInfo(display_id);
+  const std::vector<Resolution>& resolutions = display_info.resolutions();
+  DCHECK_NE(0u, resolutions.size());
+  std::vector<Resolution>::const_iterator iter =
+      std::find_if(resolutions.begin(),
+                   resolutions.end(),
+                   ResolutionMatcher(resolution));
+  if (iter == resolutions.end()) {
+    LOG(WARNING) << "Unsupported resolution was requested:"
+                 << resolution.ToString();
+    return;
+  } else if (iter == resolutions.begin()) {
+    // The best resolution was set, so forget it.
+    resolutions_.erase(display_id);
+  } else {
+    resolutions_[display_id] = resolution;
+  }
 #if defined(OS_CHROMEOS) && defined(USE_X11)
   if (base::chromeos::IsRunningOnChromeOS())
     Shell::GetInstance()->output_configurator()->ScheduleConfigureOutputs();
@@ -365,17 +424,7 @@
   return true;
 }
 
-bool DisplayManager::IsDisplayRotationEnabled() const {
-  static bool enabled = !CommandLine::ForCurrentProcess()->
-      HasSwitch(switches::kAshDisableDisplayRotation);
-  return enabled;
-}
-
 bool DisplayManager::IsDisplayUIScalingEnabled() const {
-  static bool enabled = !CommandLine::ForCurrentProcess()->
-      HasSwitch(switches::kAshDisableUIScaling);
-  if (!enabled)
-    return false;
   return GetDisplayIdForUIScaling() != gfx::Display::kInvalidDisplayID;
 }
 
@@ -395,6 +444,7 @@
     if (displays_.empty()) {
       std::vector<DisplayInfo> init_displays;
       init_displays.push_back(DisplayInfo::CreateFromSpec(std::string()));
+      MaybeInitInternalDisplay(init_displays[0].id());
       OnNativeDisplaysChanged(init_displays);
     } else {
       // Otherwise don't update the displays when all displays are disconnected.
@@ -642,28 +692,13 @@
   return displays_[index];
 }
 
-const gfx::Display* DisplayManager::GetPrimaryDisplayCandidate() const {
-  const gfx::Display* primary_candidate = &displays_[0];
-#if defined(OS_CHROMEOS)
-  if (base::chromeos::IsRunningOnChromeOS()) {
-    // On ChromeOS device, root windows are stacked vertically, and
-    // default primary is the one on top.
-    int count = GetNumDisplays();
-    int y = GetDisplayInfo(primary_candidate->id()).bounds_in_pixel().y();
-    for (int i = 1; i < count; ++i) {
-      const gfx::Display* display = &displays_[i];
-      const DisplayInfo& display_info = GetDisplayInfo(display->id());
-      if (display->IsInternal()) {
-        primary_candidate = display;
-        break;
-      } else if (display_info.bounds_in_pixel().y() < y) {
-        primary_candidate = display;
-        y = display_info.bounds_in_pixel().y();
-      }
-    }
+const gfx::Display& DisplayManager::GetPrimaryDisplayCandidate() const {
+  if (GetNumDisplays() == 1) {
+    return displays_[0];
   }
-#endif
-  return primary_candidate;
+  DisplayLayout layout = layout_store_->GetRegisteredDisplayLayout(
+      GetCurrentDisplayIdPair());
+  return GetDisplayForId(layout.primary_id);
 }
 
 size_t DisplayManager::GetNumDisplays() const {
@@ -733,7 +768,7 @@
 void DisplayManager::AddRemoveDisplay() {
   DCHECK(!displays_.empty());
   std::vector<DisplayInfo> new_display_info_list;
-  DisplayInfo first_display = GetDisplayInfo(displays_[0].id());
+  const DisplayInfo& first_display = GetDisplayInfo(displays_[0].id());
   new_display_info_list.push_back(first_display);
   // Add if there is only one display connected.
   if (num_connected_displays() == 1) {
@@ -852,6 +887,9 @@
       primary_index = 1;
       secondary_index = 0;
     }
+    // This function may be called before the secondary display is
+    // registered. The bounds is empty in that case and will
+    // return true.
     gfx::Rect bounds =
         GetDisplayForId(displays->at(secondary_index).id()).bounds();
     UpdateDisplayBoundsForLayout(
diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h
index 24303e1..b2ef8d1 100644
--- a/ash/display/display_manager.h
+++ b/ash/display/display_manager.h
@@ -107,6 +107,12 @@
 
   bool IsInternalDisplayId(int64 id) const;
 
+  // Returns the display layout used for current displays.
+  DisplayLayout GetCurrentDisplayLayout();
+
+  // Returns the current display pair.
+  DisplayIdPair GetCurrentDisplayIdPair() const;
+
   // Returns display for given |id|;
   const gfx::Display& GetDisplayForId(int64 id) const;
 
@@ -145,8 +151,7 @@
   bool GetSelectedResolutionForDisplayId(int64 display_id,
                                          gfx::Size* resolution_out) const;
 
-  // Tells if display rotation/ui scaling features are enabled.
-  bool IsDisplayRotationEnabled() const;
+  // Tells if the virtual resolution feature is enabled.
   bool IsDisplayUIScalingEnabled() const;
 
   // Returns the current overscan insets for the specified |display_id|.
@@ -170,7 +175,7 @@
   // no longer considered "primary".
   const gfx::Display& GetDisplayAt(size_t index) const;
 
-  const gfx::Display* GetPrimaryDisplayCandidate() const;
+  const gfx::Display& GetPrimaryDisplayCandidate() const;
 
   // Returns the logical number of displays. This returns 1
   // when displays are mirrored.
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 33ca06e..f7b6d1d 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -717,6 +717,42 @@
   EXPECT_EQ("0,0 100x100", GetDisplayForId(10).bounds().ToString());
 }
 
+TEST_F(DisplayManagerTest, DontRememberBestResolution) {
+  int display_id = 1000;
+  DisplayInfo native_display_info =
+      CreateDisplayInfo(display_id, gfx::Rect(0, 0, 1000, 500));
+  std::vector<Resolution> resolutions;
+  resolutions.push_back(Resolution(gfx::Size(1000, 500), false));
+  resolutions.push_back(Resolution(gfx::Size(800, 300), false));
+  resolutions.push_back(Resolution(gfx::Size(400, 500), false));
+
+  native_display_info.set_resolutions(resolutions);
+
+  std::vector<DisplayInfo> display_info_list;
+  display_info_list.push_back(native_display_info);
+  display_manager()->OnNativeDisplaysChanged(display_info_list);
+
+  gfx::Size selected;
+  EXPECT_FALSE(display_manager()->GetSelectedResolutionForDisplayId(
+      display_id, &selected));
+
+  // Unsupported resolution.
+  display_manager()->SetDisplayResolution(display_id, gfx::Size(800, 4000));
+  EXPECT_FALSE(display_manager()->GetSelectedResolutionForDisplayId(
+      display_id, &selected));
+
+  // Supported resolution.
+  display_manager()->SetDisplayResolution(display_id, gfx::Size(800, 300));
+  EXPECT_TRUE(display_manager()->GetSelectedResolutionForDisplayId(
+      display_id, &selected));
+  EXPECT_EQ("800x300", selected.ToString());
+
+  // Best resolution.
+  display_manager()->SetDisplayResolution(display_id, gfx::Size(1000, 500));
+  EXPECT_FALSE(display_manager()->GetSelectedResolutionForDisplayId(
+      display_id, &selected));
+}
+
 TEST_F(DisplayManagerTest, Rotate) {
   if (!SupportsMultipleDisplays())
     return;
@@ -991,5 +1027,26 @@
   Shell::GetScreen()->RemoveObserver(&display_observer);
 }
 
+TEST_F(DisplayManagerTest, MirroredLayout) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
+  UpdateDisplay("500x500,400x400");
+  EXPECT_FALSE(display_manager->GetCurrentDisplayLayout().mirrored);
+  EXPECT_EQ(2, Shell::GetScreen()->GetNumDisplays());
+  EXPECT_EQ(2U, display_manager->num_connected_displays());
+
+  UpdateDisplay("1+0-500x500,1+0-500x500");
+  EXPECT_TRUE(display_manager->GetCurrentDisplayLayout().mirrored);
+  EXPECT_EQ(1, Shell::GetScreen()->GetNumDisplays());
+  EXPECT_EQ(2U, display_manager->num_connected_displays());
+
+  UpdateDisplay("500x500,500x500");
+  EXPECT_FALSE(display_manager->GetCurrentDisplayLayout().mirrored);
+  EXPECT_EQ(2, Shell::GetScreen()->GetNumDisplays());
+  EXPECT_EQ(2U, display_manager->num_connected_displays());
+}
+
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/display/display_util_x11.cc b/ash/display/display_util_x11.cc
deleted file mode 100644
index e662ce2..0000000
--- a/ash/display/display_util_x11.cc
+++ /dev/null
@@ -1,97 +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/display/display_util_x11.h"
-
-#include <algorithm>
-#include <map>
-#include <X11/extensions/Xrandr.h>
-
-#include "ash/display/display_info.h"
-#include "base/logging.h"
-#include "chromeos/display/output_util.h"
-
-namespace ash {
-namespace internal {
-namespace {
-
-// A list of bogus sizes in mm that X detects that should be ignored.
-// See crbug.com/136533. The first element maintains the minimum
-// size required to be valid size.
-const unsigned long kInvalidDisplaySizeList[][2] = {
-  {40, 30},
-  {50, 40},
-  {160, 90},
-  {160, 100},
-};
-
-// Resolution list are sorted by the area in pixels and the larger
-// one comes first.
-struct ResolutionSorter {
-  bool operator()(const Resolution& a, const Resolution& b) {
-    return a.size.width() * a.size.height() > b.size.width() * b.size.height();
-  }
-};
-
-}  // namespace
-
-bool ShouldIgnoreSize(unsigned long mm_width, unsigned long mm_height) {
-  // Ignore if the reported display is smaller than minimum size.
-  if (mm_width <= kInvalidDisplaySizeList[0][0] ||
-      mm_height <= kInvalidDisplaySizeList[0][1]) {
-    LOG(WARNING) << "Smaller than minimum display size";
-    return true;
-  }
-  for (unsigned long i = 1 ; i < arraysize(kInvalidDisplaySizeList); ++i) {
-    const unsigned long* size = kInvalidDisplaySizeList[i];
-    if (mm_width == size[0] && mm_height == size[1]) {
-      LOG(WARNING) << "Black listed display size detected:"
-                   << size[0] << "x" << size[1];
-      return true;
-    }
-  }
-  return false;
-}
-
-std::vector<Resolution> GetResolutionList(
-    XRRScreenResources* screen_resources,
-    XRROutputInfo* output_info) {
-  typedef std::map<std::pair<int,int>, Resolution> ResolutionMap;
-
-  ResolutionMap resolution_map;
-
-  for (int i = 0; i < output_info->nmode; i++) {
-    RRMode mode = output_info->modes[i];
-    const XRRModeInfo* info = chromeos::FindModeInfo(screen_resources, mode);
-    DCHECK(info);
-    // Just ignore bad entry on Release build.
-    if (!info)
-      continue;
-    ResolutionMap::key_type size = std::make_pair(info->width, info->height);
-    bool interlaced = (info->modeFlags & RR_Interlace) != 0;
-
-    ResolutionMap::iterator iter = resolution_map.find(size);
-
-    // Add new resolution if it's new size or override interlaced mode.
-    if (iter == resolution_map.end()) {
-      resolution_map.insert(ResolutionMap::value_type(
-          size,
-          Resolution(gfx::Size(info->width, info->height), interlaced)));
-    } else if (iter->second.interlaced && !interlaced) {
-      iter->second.interlaced = false;
-    }
-  }
-
-  std::vector<Resolution> resolution_list;
-  for (ResolutionMap::const_iterator iter = resolution_map.begin();
-       iter != resolution_map.end();
-       ++iter) {
-    resolution_list.push_back(iter->second);
-  }
-  std::sort(resolution_list.begin(), resolution_list.end(), ResolutionSorter());
-  return resolution_list;
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/display/display_util_x11.h b/ash/display/display_util_x11.h
deleted file mode 100644
index 6647688..0000000
--- a/ash/display/display_util_x11.h
+++ /dev/null
@@ -1,36 +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_DISPLAY_DISPLAY_UTIL_X11_H_
-#define ASH_DISPLAY_DISPLAY_UTIL_X11_H_
-
-#include <vector>
-
-#include "ash/ash_export.h"
-#include "ash/display/display_info.h"
-
-struct _XRRScreenResources;
-typedef _XRRScreenResources XRRScreenResources;
-struct _XRROutputInfo;
-typedef _XRROutputInfo XRROutputInfo;
-
-namespace ash {
-namespace internal {
-struct Resolution;
-
-// Returns true if the size info in the output_info isn't valid
-// and should be ignored. This is exposed for testing.
-// |mm_width| and |mm_height| are given in millimeters.
-ASH_EXPORT bool ShouldIgnoreSize(unsigned long mm_width,
-                                 unsigned long mm_height);
-
-// Returns the resolution list.
-ASH_EXPORT std::vector<Resolution> GetResolutionList(
-    XRRScreenResources* screen_resources,
-    XRROutputInfo* output_info);
-
-}  // namespace internal
-}  // namespace ash
-
-#endif  // ASH_DISPLAY_DISPLAY_UTIL_X11_H_
diff --git a/ash/display/display_util_x11_unittest.cc b/ash/display/display_util_x11_unittest.cc
deleted file mode 100644
index f534a28..0000000
--- a/ash/display/display_util_x11_unittest.cc
+++ /dev/null
@@ -1,104 +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/display/display_util_x11.h"
-
-#include <X11/extensions/Xrandr.h>
-
-// Undefine X's macros used in gtest.
-#undef Bool
-#undef None
-
-#include "chromeos/display/output_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-typedef testing::Test DisplayUtilX11Test;
-
-namespace ash {
-namespace internal {
-
-TEST_F(DisplayUtilX11Test, TestBlackListedDisplay) {
-  EXPECT_TRUE(ShouldIgnoreSize(10, 10));
-  EXPECT_TRUE(ShouldIgnoreSize(40, 30));
-  EXPECT_TRUE(ShouldIgnoreSize(50, 40));
-  EXPECT_TRUE(ShouldIgnoreSize(160, 90));
-  EXPECT_TRUE(ShouldIgnoreSize(160, 100));
-
-  EXPECT_FALSE(ShouldIgnoreSize(50, 60));
-  EXPECT_FALSE(ShouldIgnoreSize(100, 70));
-  EXPECT_FALSE(ShouldIgnoreSize(272, 181));
-}
-
-TEST_F(DisplayUtilX11Test, GetResolutionList) {
-  XRRScreenResources resources = {0};
-  RROutput outputs[] = {1};
-  resources.noutput = arraysize(outputs);
-  resources.outputs = outputs;
-  XRRModeInfo modes[] = {
-    // id, width, height, interlaced, refresh rate
-    chromeos::test::CreateModeInfo(11, 1920, 1200, false, 60.0f),
-
-    // different rates
-    chromeos::test::CreateModeInfo(12, 1920, 1080, false, 30.0f),
-    chromeos::test::CreateModeInfo(13, 1920, 1080, false, 50.0f),
-    chromeos::test::CreateModeInfo(14, 1920, 1080, false, 40.0f),
-
-    // interlace vs non interlace
-    chromeos::test::CreateModeInfo(15, 1280, 720, true, 60.0f),
-    chromeos::test::CreateModeInfo(16, 1280, 720, false, 40.0f),
-
-    // interlace only
-    chromeos::test::CreateModeInfo(17, 1024, 768, true, 40.0f),
-    chromeos::test::CreateModeInfo(18, 1024, 768, true, 60.0f),
-
-    // mixed
-    chromeos::test::CreateModeInfo(19, 1024, 600, true, 60.0f),
-    chromeos::test::CreateModeInfo(20, 1024, 600, false, 40.0f),
-    chromeos::test::CreateModeInfo(21, 1024, 600, false, 50.0f),
-
-    // just one interlaced mode
-    chromeos::test::CreateModeInfo(22, 640, 480, true, 60.0f),
-  };
-  resources.nmode = arraysize(modes);
-  resources.modes = modes;
-
-  XRROutputInfo output_info = {0};
-  RRMode output_modes[] = {
-    11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
-  };
-  output_info.nmode = arraysize(output_modes);
-  output_info.modes = output_modes;
-
-  std::vector<Resolution> resolutions =
-      GetResolutionList(&resources, &output_info);
-  EXPECT_EQ(6u, resolutions.size());
-  EXPECT_EQ("1920x1200", resolutions[0].size.ToString());
-  EXPECT_FALSE(resolutions[0].interlaced);
-
-  EXPECT_EQ("1920x1080", resolutions[1].size.ToString());
-  EXPECT_FALSE(resolutions[1].interlaced);
-
-  EXPECT_EQ("1280x720", resolutions[2].size.ToString());
-  EXPECT_FALSE(resolutions[2].interlaced);
-
-  EXPECT_EQ("1024x768", resolutions[3].size.ToString());
-  EXPECT_TRUE(resolutions[3].interlaced);
-
-  EXPECT_EQ("1024x600", resolutions[4].size.ToString());
-  EXPECT_FALSE(resolutions[4].interlaced);
-
-  EXPECT_EQ("640x480", resolutions[5].size.ToString());
-  EXPECT_TRUE(resolutions[5].interlaced);
-
-  // Empty output shouldn't crash.
-  RRMode empty_output_modes[] = {};
-  output_info.nmode = 0;
-  output_info.modes = empty_output_modes;
-
-  resolutions = GetResolutionList(&resources, &output_info);
-  EXPECT_EQ(0u, resolutions.size());
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/display/mouse_cursor_event_filter.cc b/ash/display/mouse_cursor_event_filter.cc
index 419ea78..f3c3a74 100644
--- a/ash/display/mouse_cursor_event_filter.cc
+++ b/ash/display/mouse_cursor_event_filter.cc
@@ -5,6 +5,7 @@
 #include "ash/display/mouse_cursor_event_filter.h"
 
 #include "ash/display/display_controller.h"
+#include "ash/display/display_manager.h"
 #include "ash/display/mirror_window_controller.h"
 #include "ash/display/shared_display_edge_indicator.h"
 #include "ash/screen_ash.h"
@@ -57,7 +58,7 @@
   drag_source_root_ = from;
 
   DisplayLayout::Position position = Shell::GetInstance()->
-      display_controller()->GetCurrentDisplayLayout().position;
+      display_manager()->GetCurrentDisplayLayout().position;
   if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM)
     UpdateHorizontalIndicatorWindowBounds();
   else
@@ -158,7 +159,7 @@
       Shell::GetScreen()->GetPrimaryDisplay().bounds();
   const gfx::Rect secondary_bounds = ScreenAsh::GetSecondaryDisplay().bounds();
   DisplayLayout::Position position = Shell::GetInstance()->
-      display_controller()->GetCurrentDisplayLayout().position;
+      display_manager()->GetCurrentDisplayLayout().position;
 
   src_indicator_bounds_.set_x(
       std::max(primary_bounds.x(), secondary_bounds.x()));
@@ -187,7 +188,7 @@
       Shell::GetScreen()->GetPrimaryDisplay().bounds();
   const gfx::Rect secondary_bounds = ScreenAsh::GetSecondaryDisplay().bounds();
   DisplayLayout::Position position = Shell::GetInstance()->
-      display_controller()->GetCurrentDisplayLayout().position;
+      display_manager()->GetCurrentDisplayLayout().position;
 
   int upper_shared_y = std::max(primary_bounds.y(), secondary_bounds.y());
   int lower_shared_y = std::min(primary_bounds.bottom(),
diff --git a/ash/display/mouse_cursor_event_filter_unittest.cc b/ash/display/mouse_cursor_event_filter_unittest.cc
index db4c5dc..e4c1f55 100644
--- a/ash/display/mouse_cursor_event_filter_unittest.cc
+++ b/ash/display/mouse_cursor_event_filter_unittest.cc
@@ -108,7 +108,7 @@
       Shell::GetInstance()->mouse_cursor_filter();
   ASSERT_EQ(
       DisplayLayout::RIGHT,
-      Shell::GetInstance()->display_controller()->
+      Shell::GetInstance()->display_manager()->
           GetCurrentDisplayLayout().position);
 
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
@@ -143,7 +143,7 @@
       Shell::GetInstance()->mouse_cursor_filter();
   ASSERT_EQ(
       DisplayLayout::RIGHT,
-      Shell::GetInstance()->display_controller()->
+      Shell::GetInstance()->display_manager()->
           GetCurrentDisplayLayout().position);
 
   Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
diff --git a/ash/display/output_configurator_animation.cc b/ash/display/output_configurator_animation.cc
index 6161bef..5e58497 100644
--- a/ash/display/output_configurator_animation.cc
+++ b/ash/display/output_configurator_animation.cc
@@ -203,7 +203,8 @@
   }
 }
 
-void OutputConfiguratorAnimation::OnDisplayModeChanged() {
+void OutputConfiguratorAnimation::OnDisplayModeChanged(
+    const std::vector<chromeos::OutputConfigurator::OutputSnapshot>& outputs) {
   if (!hiding_layers_.empty())
     StartFadeInAnimation();
 }
diff --git a/ash/display/output_configurator_animation.h b/ash/display/output_configurator_animation.h
index 3fefe92..42a66ef 100644
--- a/ash/display/output_configurator_animation.h
+++ b/ash/display/output_configurator_animation.h
@@ -42,7 +42,9 @@
 
  protected:
   // chromeos::OutputConfigurator::Observer overrides:
-  virtual void OnDisplayModeChanged() OVERRIDE;
+  virtual void OnDisplayModeChanged(
+      const std::vector<chromeos::OutputConfigurator::OutputSnapshot>& outputs)
+      OVERRIDE;
   virtual void OnDisplayModeChangeFailed(
       chromeos::OutputState failed_new_state) OVERRIDE;
 
diff --git a/ash/display/resolution_notification_controller.cc b/ash/display/resolution_notification_controller.cc
index a765d61..e2755a0 100644
--- a/ash/display/resolution_notification_controller.cc
+++ b/ash/display/resolution_notification_controller.cc
@@ -71,11 +71,11 @@
 
 void ResolutionChangeNotificationDelegate::Close(bool by_user) {
   if (by_user)
-    controller_->AcceptResolutionChange();
+    controller_->AcceptResolutionChange(false);
 }
 
 void ResolutionChangeNotificationDelegate::Click() {
-  controller_->AcceptResolutionChange();
+  controller_->AcceptResolutionChange(true);
 }
 
 bool ResolutionChangeNotificationDelegate::HasClickedListener() {
@@ -86,7 +86,7 @@
   // If there's the timeout, the first button is "Accept". Otherwise the
   // button click should be "Revert".
   if (has_timeout_ && button_index == 0)
-    controller_->AcceptResolutionChange();
+    controller_->AcceptResolutionChange(true);
   else
     controller_->RevertResolutionChange();
 }
@@ -243,9 +243,12 @@
     CreateOrUpdateNotification();
 }
 
-void ResolutionNotificationController::AcceptResolutionChange() {
-  message_center::MessageCenter::Get()->RemoveNotification(
-      kNotificationId, false /* by_user */);
+void ResolutionNotificationController::AcceptResolutionChange(
+    bool close_notification) {
+  if (close_notification) {
+    message_center::MessageCenter::Get()->RemoveNotification(
+        kNotificationId, false /* by_user */);
+  }
   base::Closure callback = change_info_->accept_callback;
   change_info_.reset();
   callback.Run();
diff --git a/ash/display/resolution_notification_controller.h b/ash/display/resolution_notification_controller.h
index 4de39c2..14e6b59 100644
--- a/ash/display/resolution_notification_controller.h
+++ b/ash/display/resolution_notification_controller.h
@@ -50,8 +50,9 @@
   bool DoesNotificationTimeout();
 
   // Called by the notification delegate when the user accepts the display
-  // resolution change.
-  void AcceptResolutionChange();
+  // resolution change. Set |close_notification| to true when the notification
+  // should be removed.
+  void AcceptResolutionChange(bool close_notification);
 
   // Called by the notification delegate when the user wants to revert the
   // display resolution change.
diff --git a/ash/display/resolution_notification_controller_unittest.cc b/ash/display/resolution_notification_controller_unittest.cc
index bdb6f12..036cce0 100644
--- a/ash/display/resolution_notification_controller_unittest.cc
+++ b/ash/display/resolution_notification_controller_unittest.cc
@@ -43,16 +43,18 @@
 
     // OnConfigurationChanged event won't be emitted in the test environment,
     // so invoke UpdateDisplay() to emit that event explicitly.
-    std::string display_spec;
+    std::vector<DisplayInfo> info_list;
     for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
-      if (i > 0)
-        display_spec.append(",");
       int64 id = display_manager->GetDisplayAt(i).id();
-      gfx::Size size = (display.id() == id) ?
-          new_resolution : display_manager->GetDisplayInfo(id).size_in_pixel();
-      display_spec.append(size.ToString());
+      DisplayInfo info = display_manager->GetDisplayInfo(id);
+      if (display.id() == id) {
+        gfx::Rect bounds = info.bounds_in_pixel();
+        bounds.set_size(new_resolution);
+        info.SetBounds(bounds);
+      }
+      info_list.push_back(info);
     }
-    UpdateDisplay(display_spec);
+    display_manager->OnNativeDisplaysChanged(info_list);
     RunAllPendingInMessageLoop();
   }
 
@@ -66,6 +68,11 @@
         ResolutionNotificationController::kNotificationId, index);
   }
 
+  void CloseNotification() {
+    message_center::MessageCenter::Get()->RemoveNotification(
+        ResolutionNotificationController::kNotificationId, true /* by_user */);
+  }
+
   bool IsNotificationVisible() {
     return message_center::MessageCenter::Get()->HasNotification(
         ResolutionNotificationController::kNotificationId);
@@ -99,7 +106,7 @@
   if (!SupportsMultipleDisplays())
     return;
 
-  UpdateDisplay("100x100,150x150");
+  UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200");
   int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
   ash::internal::DisplayManager* display_manager =
       ash::Shell::GetInstance()->display_manager();
@@ -116,21 +123,20 @@
       display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
   EXPECT_EQ("200x200", resolution.ToString());
 
-  // Click the revert button, which reverts the resolution.
+  // Click the revert button, which reverts to the best resolution.
   ClickOnNotificationButton(0);
   RunAllPendingInMessageLoop();
   EXPECT_FALSE(IsNotificationVisible());
   EXPECT_EQ(0, accept_count());
-  EXPECT_TRUE(
+  EXPECT_FALSE(
       display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
-  EXPECT_EQ("150x150", resolution.ToString());
 }
 
 TEST_F(ResolutionNotificationControllerTest, ClickMeansAccept) {
   if (!SupportsMultipleDisplays())
     return;
 
-  UpdateDisplay("100x100,150x150");
+  UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200");
   int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
   ash::internal::DisplayManager* display_manager =
       ash::Shell::GetInstance()->display_manager();
@@ -164,7 +170,7 @@
   ash::internal::DisplayManager* display_manager =
       ash::Shell::GetInstance()->display_manager();
 
-  UpdateDisplay("100x100");
+  UpdateDisplay("300x300#300x300|200x200");
   const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay();
   SetDisplayResolutionAndNotify(display, gfx::Size(200, 200));
   EXPECT_TRUE(IsNotificationVisible());
@@ -181,7 +187,7 @@
   EXPECT_EQ("200x200", resolution.ToString());
 
   // In that case the second button is revert.
-  UpdateDisplay("100x100");
+  UpdateDisplay("300x300#300x300|200x200");
   SetDisplayResolutionAndNotify(display, gfx::Size(200, 200));
   EXPECT_TRUE(IsNotificationVisible());
 
@@ -189,16 +195,44 @@
   ClickOnNotificationButton(1);
   EXPECT_FALSE(IsNotificationVisible());
   EXPECT_EQ(1, accept_count());
-  EXPECT_TRUE(display_manager->GetSelectedResolutionForDisplayId(
+  EXPECT_FALSE(display_manager->GetSelectedResolutionForDisplayId(
       display.id(), &resolution));
-  EXPECT_EQ("100x100", resolution.ToString());
+}
+
+TEST_F(ResolutionNotificationControllerTest, Close) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("100x100,150x150#150x150|200x200");
+  int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
+  ash::internal::DisplayManager* display_manager =
+      ash::Shell::GetInstance()->display_manager();
+  ASSERT_EQ(0, accept_count());
+  EXPECT_FALSE(IsNotificationVisible());
+
+  // Changes the resolution and apply the result.
+  SetDisplayResolutionAndNotify(
+      ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200));
+  EXPECT_TRUE(IsNotificationVisible());
+  EXPECT_FALSE(controller()->DoesNotificationTimeout());
+  gfx::Size resolution;
+  EXPECT_TRUE(
+      display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
+  EXPECT_EQ("200x200", resolution.ToString());
+
+  // Close the notification (imitates clicking [x] button). Also verifies if
+  // this does not cause a crash.  See crbug.com/271784
+  CloseNotification();
+  RunAllPendingInMessageLoop();
+  EXPECT_FALSE(IsNotificationVisible());
+  EXPECT_EQ(1, accept_count());
 }
 
 TEST_F(ResolutionNotificationControllerTest, Timeout) {
   if (!SupportsMultipleDisplays())
     return;
 
-  UpdateDisplay("100x100");
+  UpdateDisplay("300x300#300x300|200x200");
   const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay();
   SetDisplayResolutionAndNotify(display, gfx::Size(200, 200));
 
@@ -213,39 +247,38 @@
   gfx::Size resolution;
   ash::internal::DisplayManager* display_manager =
       ash::Shell::GetInstance()->display_manager();
-  EXPECT_TRUE(display_manager->GetSelectedResolutionForDisplayId(
+  EXPECT_FALSE(display_manager->GetSelectedResolutionForDisplayId(
       display.id(), &resolution));
-  EXPECT_EQ("100x100", resolution.ToString());
 }
 
 TEST_F(ResolutionNotificationControllerTest, DisplayDisconnected) {
   if (!SupportsMultipleDisplays())
     return;
 
-  UpdateDisplay("100x100,150x150");
+  UpdateDisplay("300x300#300x300|200x200,200x200#250x250|200x200|100x100");
   int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
   ash::internal::DisplayManager* display_manager =
       ash::Shell::GetInstance()->display_manager();
   SetDisplayResolutionAndNotify(
-      ScreenAsh::GetSecondaryDisplay(), gfx::Size(200, 200));
+      ScreenAsh::GetSecondaryDisplay(), gfx::Size(100, 100));
   ASSERT_TRUE(IsNotificationVisible());
 
   // Disconnects the secondary display and verifies it doesn't cause crashes.
-  UpdateDisplay("100x100");
+  UpdateDisplay("300x300#300x300|200x200");
   RunAllPendingInMessageLoop();
   EXPECT_FALSE(IsNotificationVisible());
   EXPECT_EQ(0, accept_count());
   gfx::Size resolution;
   EXPECT_TRUE(
       display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
-  EXPECT_EQ("150x150", resolution.ToString());
+  EXPECT_EQ("200x200", resolution.ToString());
 }
 
 TEST_F(ResolutionNotificationControllerTest, MultipleResolutionChange) {
   if (!SupportsMultipleDisplays())
     return;
 
-  UpdateDisplay("100x100,150x150");
+  UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200");
   int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
   ash::internal::DisplayManager* display_manager =
       ash::Shell::GetInstance()->display_manager();
@@ -263,9 +296,8 @@
   // visible.
   SetDisplayResolutionAndNotify(
       ScreenAsh::GetSecondaryDisplay(), gfx::Size(250, 250));
-  EXPECT_TRUE(
+  EXPECT_FALSE(
       display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
-  EXPECT_EQ("250x250", resolution.ToString());
 
   // Then, click the revert button. Although |old_resolution| for the second
   // SetDisplayResolutionAndNotify is 200x200, it should revert to the original
@@ -274,9 +306,8 @@
   RunAllPendingInMessageLoop();
   EXPECT_FALSE(IsNotificationVisible());
   EXPECT_EQ(0, accept_count());
-  EXPECT_TRUE(
+  EXPECT_FALSE(
       display_manager->GetSelectedResolutionForDisplayId(id2, &resolution));
-  EXPECT_EQ("150x150", resolution.ToString());
 }
 
 }  // namespace internal
diff --git a/ash/display/screen_position_controller.cc b/ash/display/screen_position_controller.cc
index 03033b4..8c37efe 100644
--- a/ash/display/screen_position_controller.cc
+++ b/ash/display/screen_position_controller.cc
@@ -170,10 +170,6 @@
     aura::Window* dst_container = NULL;
     if (dst_root != window->GetRootWindow()) {
       int container_id = window->parent()->id();
-      // Dragging a docked window to another root window should show it floating
-      // rather than docked in another screen's dock.
-      if (container_id == kShellWindowId_DockedContainer)
-        container_id = kShellWindowId_DefaultContainer;
       // All containers that uses screen coordinates must have valid window ids.
       DCHECK_GE(container_id, 0);
       // Don't move modal background.
diff --git a/ash/display/screen_position_controller_unittest.cc b/ash/display/screen_position_controller_unittest.cc
index 3b62f52..260590a 100644
--- a/ash/display/screen_position_controller_unittest.cc
+++ b/ash/display/screen_position_controller_unittest.cc
@@ -34,11 +34,11 @@
 
 namespace {
 void SetSecondaryDisplayLayout(DisplayLayout::Position position) {
-  DisplayController* display_controller =
-      Shell::GetInstance()->display_controller();
-  DisplayLayout layout = display_controller->GetCurrentDisplayLayout();
+  DisplayLayout layout =
+      Shell::GetInstance()->display_manager()->GetCurrentDisplayLayout();
   layout.position = position;
-  display_controller->SetLayoutForCurrentDisplays(layout);
+  Shell::GetInstance()->display_controller()->
+      SetLayoutForCurrentDisplays(layout);
 }
 
 internal::ScreenPositionController* GetScreenPositionController() {
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index 36161e0..d36e824 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -36,11 +36,11 @@
 namespace {
 
 void SetSecondaryDisplayLayout(DisplayLayout::Position position) {
-  DisplayController* display_controller =
-      Shell::GetInstance()->display_controller();
-  DisplayLayout layout = display_controller->GetCurrentDisplayLayout();
+  DisplayLayout layout =
+      Shell::GetInstance()->display_manager()->GetCurrentDisplayLayout();
   layout.position = position;
-  display_controller->SetLayoutForCurrentDisplays(layout);
+  Shell::GetInstance()->display_controller()->
+      SetLayoutForCurrentDisplays(layout);
 }
 
 internal::DisplayManager* GetDisplayManager() {
diff --git a/ash/keyboard_controller_proxy_stub.cc b/ash/keyboard_controller_proxy_stub.cc
new file mode 100644
index 0000000..caaa3dd
--- /dev/null
+++ b/ash/keyboard_controller_proxy_stub.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 "ash/keyboard_controller_proxy_stub.h"
+
+#include "ash/shell.h"
+#include "ui/views/corewm/input_method_event_filter.h"
+
+using namespace content;
+
+namespace ash {
+
+KeyboardControllerProxyStub::KeyboardControllerProxyStub() {
+}
+
+KeyboardControllerProxyStub::~KeyboardControllerProxyStub() {
+}
+
+BrowserContext* KeyboardControllerProxyStub::GetBrowserContext() {
+  return Shell::GetInstance()->browser_context();
+}
+
+ui::InputMethod* KeyboardControllerProxyStub::GetInputMethod() {
+  return Shell::GetInstance()->input_method_filter()->input_method();
+}
+
+void KeyboardControllerProxyStub::RequestAudioInput(
+    WebContents* web_contents,
+    const MediaStreamRequest& request,
+    const MediaResponseCallback& callback) {
+}
+
+}  // namespace ash
diff --git a/ash/keyboard_controller_proxy_stub.h b/ash/keyboard_controller_proxy_stub.h
new file mode 100644
index 0000000..25310d7
--- /dev/null
+++ b/ash/keyboard_controller_proxy_stub.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 ASH_KEYBOARD_CONTROLLER_PROXY_STUB_H_
+#define ASH_KEYBOARD_CONTROLLER_PROXY_STUB_H_
+
+#include "ash/ash_export.h"
+#include "ui/keyboard/keyboard_controller_proxy.h"
+
+namespace ash {
+
+// Stub implementation of KeyboardControllerProxy
+class ASH_EXPORT KeyboardControllerProxyStub
+    : public keyboard::KeyboardControllerProxy {
+ public:
+  KeyboardControllerProxyStub();
+  virtual ~KeyboardControllerProxyStub();
+
+ private:
+  // Overridden from keyboard::KeyboardControllerProxy:
+  virtual content::BrowserContext* GetBrowserContext() OVERRIDE;
+  virtual ui::InputMethod* GetInputMethod() OVERRIDE;
+  virtual void RequestAudioInput(content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyboardControllerProxyStub);
+};
+
+}  // namespace ash
+
+#endif  // ASH_KEYBOARD_CONTROLLER_PROXY_STUB_H_
diff --git a/ash/launcher/launcher.cc b/ash/launcher/launcher.cc
index 5bd1262..008646d 100644
--- a/ash/launcher/launcher.cc
+++ b/ash/launcher/launcher.cc
@@ -169,10 +169,7 @@
   // There are two ways how found_index can be valid: a.) the nth item was
   // found (which is true when indexes_left is -1) or b.) the last item was
   // requested (which is true when index was passed in as a negative number).
-  if (found_index >= 0 && (indexes_left == -1 || item_index < 0) &&
-      (delegate_->IsPerAppLauncher() ||
-       (items[found_index].status == ash::STATUS_RUNNING ||
-        items[found_index].status == ash::STATUS_CLOSED))) {
+  if (found_index >= 0 && (indexes_left == -1 || item_index < 0)) {
     // Then set this one as active (or advance to the next item of its kind).
     ActivateLauncherItem(found_index);
   }
diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h
index 6781058..c3acf44 100644
--- a/ash/launcher/launcher.h
+++ b/ash/launcher/launcher.h
@@ -101,8 +101,6 @@
   // TODO(sky): remove this!
   internal::LauncherView* GetLauncherViewForTest();
 
-  LauncherDelegate* delegate() { return delegate_; }
-
   ShelfWidget* shelf_widget() { return shelf_widget_; }
 
   // Set the bounds of the launcher view.
diff --git a/ash/launcher/launcher_button.cc b/ash/launcher/launcher_button.cc
index 2859d98..26677ae 100644
--- a/ash/launcher/launcher_button.cc
+++ b/ash/launcher/launcher_button.cc
@@ -439,6 +439,12 @@
       icon_width,
       icon_height));
 
+  // Icon size has been incorrect when running
+  // PanelLayoutManagerTest.PanelAlignmentSecondDisplay on valgrind bot, see
+  // http://crbug.com/234854.
+  DCHECK_LE(icon_width, kIconSize);
+  DCHECK_LE(icon_height, kIconSize);
+
   bar_->SetBarBoundsRect(button_bounds);
 
   UpdateState();
diff --git a/ash/launcher/launcher_delegate.h b/ash/launcher/launcher_delegate.h
index 20064ea..322df38 100644
--- a/ash/launcher/launcher_delegate.h
+++ b/ash/launcher/launcher_delegate.h
@@ -46,7 +46,7 @@
   // and has an instance of |views::View| as the event target
   // but not |aura::Window|. If the |event| is of type KeyEvent, it is assumed
   // that this was triggered by keyboard action (Alt+<number>) and special
-  // handling might happen (PerApp launcher).
+  // handling might happen.
   virtual void ItemSelected(const LauncherItem& item,
                             const ui::Event& event) = 0;
 
@@ -74,6 +74,8 @@
 
   // Returns the id of the item associated with the specified window, or 0 if
   // there isn't one.
+  // Note: Windows of tabbed browsers will return the |LauncherID| of the
+  // currently active tab or selected tab.
   virtual LauncherID GetIDByWindow(aura::Window* window) = 0;
 
   // Whether the given launcher item is draggable.
@@ -90,9 +92,6 @@
   // exists.
   virtual void OnLauncherDestroyed(Launcher* launcher) = 0;
 
-  // True if the running launcher is the per application launcher.
-  virtual bool IsPerAppLauncher() = 0;
-
   // Get the launcher ID from an application ID.
   virtual LauncherID GetLauncherIDForAppID(const std::string& app_id) = 0;
 
diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc
index 82f75be..b6095a8 100644
--- a/ash/launcher/launcher_view.cc
+++ b/ash/launcher/launcher_view.cc
@@ -1317,10 +1317,15 @@
     model_index = CancelDrag(model_index);
     scoped_ptr<views::View> old_view(view_model_->view_at(model_index));
     bounds_animator_->StopAnimatingView(old_view.get());
+    // Removing and re-inserting a view in our view model will strip the ideal
+    // bounds from the item. To avoid recalculation of everything the bounds
+    // get remembered and restored after the insertion to the previous value.
+    gfx::Rect old_ideal_bounds = view_model_->ideal_bounds(model_index);
     view_model_->Remove(model_index);
     views::View* new_view = CreateViewForItem(item);
     AddChildView(new_view);
     view_model_->Add(new_view, model_index);
+    view_model_->set_ideal_bounds(model_index, old_ideal_bounds);
     new_view->SetBoundsRect(old_view->bounds());
     return;
   }
@@ -1521,6 +1526,11 @@
       case TYPE_TABBED:
       case TYPE_APP_PANEL:
         delegate_->ItemSelected(model_->items()[view_index], event);
+        // Don't show the menu when the user creates a new browser using ctrl
+        // click.
+        if (model_->items()[view_index].type != TYPE_BROWSER_SHORTCUT ||
+            !(event.flags() & ui::EF_CONTROL_DOWN))
+          ShowListMenuForView(model_->items()[view_index], sender, event);
         break;
 
       case TYPE_APP_LIST:
@@ -1530,9 +1540,6 @@
         break;
     }
   }
-
-  if (model_->items()[view_index].type != TYPE_APP_LIST)
-    ShowListMenuForView(model_->items()[view_index], sender, event);
 }
 
 bool LauncherView::ShowListMenuForView(const LauncherItem& item,
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
index 166fe5f..991c895 100644
--- a/ash/resources/ash_resources.grd
+++ b/ash/resources/ash_resources.grd
@@ -113,15 +113,6 @@
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_GUEST_ICON" file="cros/status/status_guest_icon.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_GUEST_ICON_LARGE" file="common/alt_launcher/status_guest_icon.png" />
 
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_BOTTOM" file="cros/status/status_logout_button_hover_bottom.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_BOTTOM_LEFT" file="cros/status/status_logout_button_hover_bottom_left.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_BOTTOM_RIGHT" file="cros/status/status_logout_button_hover_bottom_right.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_CENTER" file="cros/status/status_logout_button_hover_center.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_LEFT" file="cros/status/status_logout_button_hover_left.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_RIGHT" file="cros/status/status_logout_button_hover_right.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_TOP" file="cros/status/status_logout_button_hover_top.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_TOP_LEFT" file="cros/status/status_logout_button_hover_top_left.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_TOP_RIGHT" file="cros/status/status_logout_button_hover_top_right.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM" file="cros/status/status_logout_button_pushed_bottom.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_LEFT" file="cros/status/status_logout_button_pushed_bottom_left.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_RIGHT" file="cros/status/status_logout_button_pushed_bottom_right.png" />
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom.png
deleted file mode 100644
index 4bfbaeb..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom_left.png
deleted file mode 100644
index 5a96fee..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom_right.png
deleted file mode 100644
index a5ddc1c..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_center.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_center.png
deleted file mode 100644
index 18ef4f8..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_left.png
deleted file mode 100644
index d806c99..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_right.png
deleted file mode 100644
index 2baa507..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top.png
deleted file mode 100644
index 2752a48..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top_left.png
deleted file mode 100644
index 71d450d..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top_right.png
deleted file mode 100644
index 3270b26..0000000
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_hover_top_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom.png
index 76c31f3..48a9b78 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_left.png
index 64dd932..ed08895 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_left.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_left.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_right.png
index 4ece433..5c41166 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_right.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_bottom_right.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_center.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_center.png
index 18ef4f8..674a2ca 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_center.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_center.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_left.png
index 5decc7d..0ca8c15 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_left.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_left.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_right.png
index 22b0896..107f25e 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_right.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_right.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top.png
index 8100431..0c882a3 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_left.png
index acd6641..a288584 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_left.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_left.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_right.png
index 63e7c51..ac7c0df 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_right.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_normal_top_right.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom.png
index cb40232..07b1a81 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_left.png
index 59664ce..a0c58bb 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_left.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_left.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_right.png
index b6a2d42..f20a29d 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_right.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_bottom_right.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_center.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_center.png
index 95e1357..948a922 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_center.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_center.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_left.png
index 6ff819e..e896e81 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_left.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_left.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_right.png
index c1e9dda..47e1e4b 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_right.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_right.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top.png
index f2b8fc5..6e304f2 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_left.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_left.png
index 7aa3057..aecbe19 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_left.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_left.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_right.png b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_right.png
index 6d610d5..5356770 100644
--- a/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_right.png
+++ b/ash/resources/default_100_percent/cros/status/status_logout_button_pushed_top_right.png
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_managed_mode_user.png b/ash/resources/default_100_percent/cros/status/status_managed_mode_user.png
index 5110417..684702b 100644
--- a/ash/resources/default_100_percent/cros/status/status_managed_mode_user.png
+++ b/ash/resources/default_100_percent/cros/status/status_managed_mode_user.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom.png
deleted file mode 100644
index d15cb08..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom_left.png
deleted file mode 100644
index 40de4bb..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom_right.png
deleted file mode 100644
index 216bffd..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_center.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_center.png
deleted file mode 100644
index eb3f2c8..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_center.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_left.png
deleted file mode 100644
index bc35d9d..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_right.png
deleted file mode 100644
index 55ae128..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top.png
deleted file mode 100644
index a4b48b2..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top_left.png
deleted file mode 100644
index 8d3823c..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top_right.png
deleted file mode 100644
index b73cd7e..0000000
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_hover_top_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom.png
index a6a2e66..679ebe9 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_left.png
index 47768bc..7b615e6 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_left.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_left.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_right.png
index 3cd5993..149b4a9 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_right.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_bottom_right.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_center.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_center.png
index eb3f2c8..436c2ac 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_center.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_center.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_left.png
index dbc95d6..c58ee94 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_left.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_left.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_right.png
index 0dc5385..5f7d650 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_right.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_right.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top.png
index 6b9e086..cc11444 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_left.png
index 3d9ff7f..05dfa2f 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_left.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_left.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_right.png
index 6f263c2..bf15dcd 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_right.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_normal_top_right.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom.png
index 211e857..0e23e56 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_left.png
index 615d7ca..79f2792 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_left.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_left.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_right.png
index e9a05e1..d6aa1a4 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_right.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_bottom_right.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_center.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_center.png
index 22b0846..41a39c9 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_center.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_center.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_left.png
index 6c22eee..1617280 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_left.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_left.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_right.png
index 315bd16..c5a5730 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_right.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_right.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top.png
index e463139..b340b1b 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_left.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_left.png
index 3dede73..787ef70 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_left.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_left.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_right.png b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_right.png
index 3d9e5d9..5d5f634 100644
--- a/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_right.png
+++ b/ash/resources/default_200_percent/cros/status/status_logout_button_pushed_top_right.png
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_managed_mode_user.png b/ash/resources/default_200_percent/cros/status/status_managed_mode_user.png
index b0b522d..02eb311 100644
--- a/ash/resources/default_200_percent/cros/status/status_managed_mode_user.png
+++ b/ash/resources/default_200_percent/cros/status/status_managed_mode_user.png
Binary files differ
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 6d5fb62..2f76528 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -4,6 +4,7 @@
 
 #include "ash/root_window_controller.h"
 
+#include <queue>
 #include <vector>
 
 #include "ash/ash_constants.h"
@@ -27,7 +28,6 @@
 #include "ash/touch/touch_observer_hud.h"
 #include "ash/wm/always_on_top_controller.h"
 #include "ash/wm/base_layout_manager.h"
-#include "ash/wm/boot_splash_screen.h"
 #include "ash/wm/dock/docked_window_layout_manager.h"
 #include "ash/wm/panels/panel_layout_manager.h"
 #include "ash/wm/panels/panel_window_event_handler.h"
@@ -45,29 +45,38 @@
 #include "base/command_line.h"
 #include "base/time/time.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/client/drag_drop_client.h"
 #include "ui/aura/client/tooltip_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_observer.h"
+#include "ui/aura/window_tracker.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/gfx/screen.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_util.h"
 #include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/corewm/capture_controller.h"
 #include "ui/views/corewm/visibility_controller.h"
 #include "ui/views/view_model.h"
 #include "ui/views/view_model_utils.h"
 
+#if defined(OS_CHROMEOS)
+#include "ash/wm/boot_splash_screen_chromeos.h"
+#endif
+
 namespace ash {
 namespace {
 
+#if defined(OS_CHROMEOS)
 // Duration for the animation that hides the boot splash screen, in
 // milliseconds.  This should be short enough in relation to
 // wm/window_animation.cc's brightness/grayscale fade animation that the login
 // background image animation isn't hidden by the splash screen animation.
 const int kBootSplashScreenHideDurationMs = 500;
+#endif
 
 // Creates a new window for use as a container.
 aura::Window* CreateContainer(int window_id,
@@ -213,11 +222,15 @@
 
   stacking_controller_.reset(new StackingController);
   aura::client::SetStackingClient(root_window, stacking_controller_.get());
+  capture_client_.reset(new views::corewm::ScopedCaptureClient(root_window));
 }
 
 RootWindowController::~RootWindowController() {
   Shutdown();
   root_window_.reset();
+  // The CaptureClient needs to be around for as long as the RootWindow is
+  // valid.
+  capture_client_.reset();
 }
 
 // static
@@ -345,6 +358,7 @@
 }
 
 void RootWindowController::HandleInitialDesktopBackgroundAnimationStarted() {
+#if defined(OS_CHROMEOS)
   if (CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kAshAnimateFromBootSplashScreen) &&
       boot_splash_screen_.get()) {
@@ -353,12 +367,15 @@
     boot_splash_screen_->StartHideAnimation(
         base::TimeDelta::FromMilliseconds(kBootSplashScreenHideDurationMs));
   }
+#endif
 }
 
 void RootWindowController::OnWallpaperAnimationFinished(views::Widget* widget) {
   // Make sure the wallpaper is visible.
   system_background_->SetColor(SK_ColorBLACK);
+#if defined(OS_CHROMEOS)
   boot_splash_screen_.reset();
+#endif
 
   Shell::GetInstance()->user_wallpaper_delegate()->
       OnWallpaperAnimationFinished();
@@ -395,6 +412,8 @@
     docked_layout_manager_ = NULL;
   }
 
+  aura::client::SetDragDropClient(root_window_.get(), NULL);
+
   // TODO(harrym): Remove when Status Area Widget is a child view.
   shelf_->ShutdownStatusAreaWidget();
 
@@ -408,10 +427,26 @@
   workspace_controller_.reset();
   aura::client::SetTooltipClient(root_window_.get(), NULL);
 
-  while (!root_window_->children().empty()) {
-    aura::Window* child = root_window_->children()[0];
-    delete child;
+  // Remove all toplevel windows first.
+  std::queue<aura::Window*> non_toplevel_windows;
+  non_toplevel_windows.push(root_window_.get());
+  while (!non_toplevel_windows.empty()) {
+    aura::Window* non_toplevel_window = non_toplevel_windows.front();
+    non_toplevel_windows.pop();
+    aura::WindowTracker toplevel_windows;
+    for (size_t i = 0; i < non_toplevel_window->children().size(); ++i) {
+      aura::Window* child = non_toplevel_window->children()[i];
+      if (child->delegate())
+        toplevel_windows.Add(child);
+      else
+        non_toplevel_windows.push(child);
+    }
+    while (!toplevel_windows.windows().empty())
+      delete *toplevel_windows.windows().begin();
   }
+  // And then remove the containers.
+  while (!root_window_->children().empty())
+    delete root_window_->children()[0];
 
   shelf_.reset(NULL);
 }
@@ -487,6 +522,7 @@
 
     aura::Window* keyboard_container =
         keyboard_controller_->GetContainerWindow();
+    keyboard_container->set_id(kShellWindowId_VirtualKeyboardContainer);
     parent->AddChild(keyboard_container);
     keyboard_container->SetBounds(parent->bounds());
   }
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index bbf29ce..d57aaf8 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -33,6 +33,7 @@
 namespace corewm {
 class InputMethodEventFilter;
 class RootWindowEventFilter;
+class ScopedCaptureClient;
 }
 }
 
@@ -50,7 +51,6 @@
 
 class AlwaysOnTopController;
 class AnimatingDesktopController;
-class BootSplashScreen;
 class DesktopBackgroundWidgetController;
 class DockedWindowLayoutManager;
 class PanelLayoutManager;
@@ -64,6 +64,10 @@
 class TouchHudProjection;
 class WorkspaceController;
 
+#if defined(USE_X11)
+class BootSplashScreen;
+#endif
+
 // This class maintains the per root window state for ash. This class
 // owns the root window and other dependent objects that should be
 // deleted upon the deletion of the root window.  The RootWindowController
@@ -255,7 +259,9 @@
   PanelLayoutManager* panel_layout_manager_;
 
   scoped_ptr<SystemBackgroundController> system_background_;
+#if defined(USE_X11)
   scoped_ptr<BootSplashScreen> boot_splash_screen_;
+#endif
 
   scoped_ptr<ScreenDimmer> screen_dimmer_;
   scoped_ptr<WorkspaceController> workspace_controller_;
@@ -276,6 +282,7 @@
 
   scoped_ptr<DesktopBackgroundWidgetController> wallpaper_controller_;
   scoped_ptr<AnimatingDesktopController> animating_wallpaper_controller_;
+  scoped_ptr<views::corewm::ScopedCaptureClient> capture_client_;
 
   DISALLOW_COPY_AND_ASSIGN(RootWindowController);
 };
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index 0d40125..b4c16e3 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/wm/system_modal_container_layout_manager.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
+#include "base/command_line.h"
 #include "ui/aura/client/focus_change_observer.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/env.h"
@@ -22,6 +23,7 @@
 #include "ui/aura/test/test_windows.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tracker.h"
+#include "ui/keyboard/keyboard_switches.h"
 #include "ui/views/controls/menu/menu_controller.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -80,6 +82,36 @@
   DISALLOW_COPY_AND_ASSIGN(DeleteOnBlurDelegate);
 };
 
+class ClickTestWindow : public views::WidgetDelegateView {
+ public:
+  ClickTestWindow() : mouse_presses_(0) {}
+  virtual ~ClickTestWindow() {}
+
+  // Overridden from views::WidgetDelegate:
+  virtual views::View* GetContentsView() OVERRIDE {
+    return this;
+  }
+
+  aura::Window* CreateTestWindowWithParent(aura::Window* parent) {
+    DCHECK(parent);
+    views::Widget* widget = Widget::CreateWindowWithParent(this, parent);
+    return widget->GetNativeView();
+  }
+
+  // Overridden from views::View:
+  virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE {
+    mouse_presses_++;
+    return false;
+  }
+
+  int mouse_presses() const { return mouse_presses_; }
+
+ private:
+  int mouse_presses_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClickTestWindow);
+};
+
 }  // namespace
 
 namespace test {
@@ -492,5 +524,52 @@
                 gfx::Point(size.width() - 1, size.height() - 1)));
 }
 
+class VirtualKeyboardRootWindowControllerTest : public test::AshTestBase {
+ public:
+  VirtualKeyboardRootWindowControllerTest() {};
+  virtual ~VirtualKeyboardRootWindowControllerTest() {};
+
+  virtual void SetUp() OVERRIDE {
+    CommandLine::ForCurrentProcess()->AppendSwitch(
+        keyboard::switches::kEnableVirtualKeyboard);
+    test::AshTestBase::SetUp();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VirtualKeyboardRootWindowControllerTest);
+};
+
+// Test for http://crbug.com/263599. Virtual keyboard should be able to receive
+// events at blocked user session.
+TEST_F(VirtualKeyboardRootWindowControllerTest,
+       ClickVirtualKeyboardInBlockedWindow) {
+  aura::RootWindow* root_window = ash::Shell::GetPrimaryRootWindow();
+  aura::Window* keyboard_container = Shell::GetContainer(root_window,
+      internal::kShellWindowId_VirtualKeyboardContainer);
+  ASSERT_TRUE(keyboard_container);
+  keyboard_container->Show();
+
+  ClickTestWindow* main_delegate = new ClickTestWindow();
+  scoped_ptr<aura::Window> keyboard_window(
+      main_delegate->CreateTestWindowWithParent(keyboard_container));
+  keyboard_container->layout_manager()->OnWindowResized();
+  keyboard_window->Show();
+  aura::test::EventGenerator event_generator(root_window,
+                                             keyboard_window.get());
+  event_generator.ClickLeftButton();
+  int expected_mouse_presses = 1;
+  EXPECT_EQ(expected_mouse_presses, main_delegate->mouse_presses());
+
+  for (int block_reason = FIRST_BLOCK_REASON;
+       block_reason < NUMBER_OF_BLOCK_REASONS;
+       ++block_reason) {
+    BlockUserSession(static_cast<UserSessionBlockReason>(block_reason));
+    event_generator.ClickLeftButton();
+    expected_mouse_presses++;
+    EXPECT_EQ(expected_mouse_presses, main_delegate->mouse_presses());
+    UnblockUserSession();
+  }
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index e392cc2..a507da6 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -197,7 +197,7 @@
 
 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf)
     : root_window_(shelf->GetNativeView()->GetRootWindow()),
-      in_layout_(false),
+      updating_bounds_(false),
       auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER),
       alignment_(SHELF_ALIGNMENT_BOTTOM),
       shelf_(shelf),
@@ -272,34 +272,20 @@
 }
 
 void ShelfLayoutManager::LayoutShelf() {
-  base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
-  StopAnimating();
   TargetBounds target_bounds;
   CalculateTargetBounds(state_, &target_bounds);
-  GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
-  shelf_->SetWidgetBounds(
-      ScreenAsh::ConvertRectToScreen(
-          shelf_->GetNativeView()->parent(),
-          target_bounds.shelf_bounds_in_root));
-  if (shelf_->launcher())
+  UpdateBoundsAndOpacity(target_bounds, false, NULL);
+
+  if (shelf_->launcher()) {
+    // This is not part of UpdateBoundsAndOpacity() because
+    // SetLauncherViewBounds() sets the bounds immediately and does not animate.
+    // The height of the LauncherView for a horizontal shelf and the width of
+    // the LauncherView for a vertical shelf are set when |shelf_|'s bounds
+    // are changed via UpdateBoundsAndOpacity(). This sets the origin and the
+    // dimension in the other direction.
     shelf_->launcher()->SetLauncherViewBounds(
         target_bounds.launcher_bounds_in_shelf);
-  GetLayer(shelf_->status_area_widget())->SetOpacity(
-      target_bounds.status_opacity);
-  // TODO(harrym): Once status area widget is a child view of shelf
-  // this can be simplified.
-  gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
-  status_bounds.set_x(status_bounds.x() +
-                      target_bounds.shelf_bounds_in_root.x());
-  status_bounds.set_y(status_bounds.y() +
-                      target_bounds.shelf_bounds_in_root.y());
-  shelf_->status_area_widget()->SetBounds(
-      ScreenAsh::ConvertRectToScreen(
-          shelf_->status_area_widget()->GetNativeView()->parent(),
-          status_bounds));
-  Shell::GetInstance()->SetDisplayWorkAreaInsets(
-      root_window_, target_bounds.work_area_insets);
-  UpdateHitTestBounds();
+  }
 }
 
 ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() {
@@ -481,17 +467,12 @@
   else
     UpdateVisibilityState();
   gesture_drag_status_ = GESTURE_DRAG_NONE;
-  LayoutShelf();
 }
 
 void ShelfLayoutManager::CancelGestureDrag() {
-  gesture_drag_status_ = GESTURE_DRAG_NONE;
-  ui::ScopedLayerAnimationSettings
-      launcher_settings(GetLayer(shelf_)->GetAnimator()),
-      status_settings(GetLayer(shelf_->status_area_widget())->GetAnimator());
-  LayoutShelf();
+  gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS;
   UpdateVisibilityState();
-  UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
+  gesture_drag_status_ = GESTURE_DRAG_NONE;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -519,7 +500,7 @@
   SetChildBoundsDirect(child, requested_bounds);
   // We may contain other widgets (such as frame maximize bubble) but they don't
   // effect the layout in anyway.
-  if (!in_layout_ &&
+  if (!updating_bounds_ &&
       ((shelf_->GetNativeView() == child) ||
        (shelf_->status_area_widget()->GetNativeView() == child))) {
     LayoutShelf();
@@ -576,7 +557,13 @@
   state.window_state = workspace_controller_ ?
       workspace_controller_->GetWindowState() : WORKSPACE_WINDOW_STATE_DEFAULT;
 
-  if (state_.Equals(state))
+  // Force an update because gesture drags affect the shelf bounds and we
+  // should animate back to the normal bounds at the end of a gesture.
+  bool force_update =
+      (gesture_drag_status_ == GESTURE_DRAG_CANCEL_IN_PROGRESS ||
+       gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS);
+
+  if (!force_update && state_.Equals(state))
     return;  // Nothing changed.
 
   FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
@@ -595,26 +582,6 @@
 
   State old_state = state_;
   state_ = state;
-  TargetBounds target_bounds;
-  CalculateTargetBounds(state_, &target_bounds);
-
-  ui::ScopedLayerAnimationSettings launcher_animation_setter(
-      GetLayer(shelf_)->GetAnimator());
-  launcher_animation_setter.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
-  launcher_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
-  launcher_animation_setter.SetPreemptionStrategy(
-      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-  GetLayer(shelf_)->SetBounds(
-      target_bounds.shelf_bounds_in_root);
-  GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
-  ui::ScopedLayerAnimationSettings status_animation_setter(
-      GetLayer(shelf_->status_area_widget())->GetAnimator());
-  status_animation_setter.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
-  status_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
-  status_animation_setter.SetPreemptionStrategy(
-      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
 
   BackgroundAnimator::ChangeType change_type =
       BackgroundAnimator::CHANGE_ANIMATE;
@@ -644,7 +611,6 @@
       update_shelf_observer_->Detach();
     // UpdateShelfBackground deletes itself when the animation is done.
     update_shelf_observer_ = new UpdateShelfObserver(this);
-    status_animation_setter.AddObserver(update_shelf_observer_);
   } else {
     UpdateShelfBackground(change_type);
   }
@@ -653,18 +619,10 @@
       state.visibility_state == SHELF_VISIBLE &&
       state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED);
 
-  ui::Layer* layer = GetLayer(shelf_->status_area_widget());
-  // TODO(harrym): Remove when status_area is view (crbug.com/180422).
-  gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
-  status_bounds.set_x(status_bounds.x() +
-                      target_bounds.shelf_bounds_in_root.x());
-  status_bounds.set_y(status_bounds.y() +
-                      target_bounds.shelf_bounds_in_root.y());
-  layer->SetBounds(status_bounds);
-  layer->SetOpacity(target_bounds.status_opacity);
-  Shell::GetInstance()->SetDisplayWorkAreaInsets(
-      root_window_, target_bounds.work_area_insets);
-  UpdateHitTestBounds();
+  TargetBounds target_bounds;
+  CalculateTargetBounds(state_, &target_bounds);
+  UpdateBoundsAndOpacity(target_bounds, true,
+      delay_background_change ? update_shelf_observer_ : NULL);
 
   // OnAutoHideStateChanged Should be emitted when:
   //  - firstly state changed to auto-hide from other state
@@ -677,6 +635,58 @@
   }
 }
 
+void ShelfLayoutManager::UpdateBoundsAndOpacity(
+    const TargetBounds& target_bounds,
+    bool animate,
+    ui::ImplicitAnimationObserver* observer) {
+  base::AutoReset<bool> auto_reset_updating_bounds(&updating_bounds_, true);
+
+  ui::ScopedLayerAnimationSettings launcher_animation_setter(
+      GetLayer(shelf_)->GetAnimator());
+  ui::ScopedLayerAnimationSettings status_animation_setter(
+      GetLayer(shelf_->status_area_widget())->GetAnimator());
+  if (animate) {
+    launcher_animation_setter.SetTransitionDuration(
+        base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
+    launcher_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
+    launcher_animation_setter.SetPreemptionStrategy(
+        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+    status_animation_setter.SetTransitionDuration(
+        base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
+    status_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
+    status_animation_setter.SetPreemptionStrategy(
+        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+  } else {
+    StopAnimating();
+    launcher_animation_setter.SetTransitionDuration(base::TimeDelta());
+    status_animation_setter.SetTransitionDuration(base::TimeDelta());
+  }
+  if (observer)
+    status_animation_setter.AddObserver(observer);
+
+  GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
+  shelf_->SetBounds(ScreenAsh::ConvertRectToScreen(
+       shelf_->GetNativeView()->parent(),
+       target_bounds.shelf_bounds_in_root));
+
+  GetLayer(shelf_->status_area_widget())->SetOpacity(
+      target_bounds.status_opacity);
+  // TODO(harrym): Once status area widget is a child view of shelf
+  // this can be simplified.
+  gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
+  status_bounds.set_x(status_bounds.x() +
+                      target_bounds.shelf_bounds_in_root.x());
+  status_bounds.set_y(status_bounds.y() +
+                      target_bounds.shelf_bounds_in_root.y());
+  shelf_->status_area_widget()->SetBounds(
+      ScreenAsh::ConvertRectToScreen(
+          shelf_->status_area_widget()->GetNativeView()->parent(),
+          status_bounds));
+  Shell::GetInstance()->SetDisplayWorkAreaInsets(
+      root_window_, target_bounds.work_area_insets);
+  UpdateHitTestBounds();
+}
+
 void ShelfLayoutManager::StopAnimating() {
   GetLayer(shelf_)->GetAnimator()->StopAnimating();
   GetLayer(shelf_->status_area_widget())->GetAnimator()->StopAnimating();
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 467fe1a..56d7032 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -33,12 +33,15 @@
 
 namespace ui {
 class GestureEvent;
+class ImplicitAnimationObserver;
 }
 
 namespace ash {
 class ScreenAsh;
 class ShelfLayoutManagerObserver;
 class ShelfWidget;
+FORWARD_DECLARE_TEST(WebNotificationTrayTest, PopupAndFullscreen);
+
 namespace internal {
 
 class PanelLayoutManagerTest;
@@ -98,7 +101,7 @@
     workspace_controller_ = controller;
   }
 
-  bool in_layout() const { return in_layout_; }
+  bool updating_bounds() const { return updating_bounds_; }
 
   // Clears internal data for shutdown process.
   void PrepareForShutdown();
@@ -211,6 +214,7 @@
   friend class ash::ScreenAsh;
   friend class PanelLayoutManagerTest;
   friend class ShelfLayoutManagerTest;
+  FRIEND_TEST_ALL_PREFIXES(ash::WebNotificationTrayTest, PopupAndFullscreen);
 
   struct TargetBounds {
     TargetBounds();
@@ -251,6 +255,13 @@
   // Sets the visibility of the shelf to |state|.
   void SetState(ShelfVisibilityState visibility_state);
 
+  // Updates the bounds and opacity of the launcher and status widgets.
+  // If |observer| is specified, it will be called back when the animations, if
+  // any, are complete.
+  void UpdateBoundsAndOpacity(const TargetBounds& target_bounds,
+                              bool animate,
+                              ui::ImplicitAnimationObserver* observer);
+
   // Stops any animations and progresses them to the end.
   void StopAnimating();
 
@@ -319,9 +330,9 @@
   // deleted too.
   aura::RootWindow* root_window_;
 
-  // True when inside LayoutShelf method. Used to prevent calling LayoutShelf
-  // again from SetChildBounds().
-  bool in_layout_;
+  // True when inside UpdateBoundsAndOpacity() method. Used to prevent calling
+  // UpdateBoundsAndOpacity() again from SetChildBounds().
+  bool updating_bounds_;
 
   // See description above setter.
   ShelfAutoHideBehavior auto_hide_behavior_;
@@ -360,6 +371,7 @@
   enum GestureDragStatus {
     GESTURE_DRAG_NONE,
     GESTURE_DRAG_IN_PROGRESS,
+    GESTURE_DRAG_CANCEL_IN_PROGRESS,
     GESTURE_DRAG_COMPLETE_IN_PROGRESS
   };
   GestureDragStatus gesture_drag_status_;
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index e62bcec..e44fe34 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -70,6 +70,66 @@
   return Shell::GetPrimaryRootWindowController()->GetSystemTray();
 }
 
+// Class which waits till the shelf finishes animating to the target size and
+// counts the number of animation steps.
+class ShelfAnimationWaiter : views::WidgetObserver {
+ public:
+  explicit ShelfAnimationWaiter(const gfx::Rect& target_bounds)
+      : target_bounds_(target_bounds),
+        animation_steps_(0),
+        done_waiting_(false) {
+    GetShelfWidget()->AddObserver(this);
+  }
+
+  virtual ~ShelfAnimationWaiter() {
+    GetShelfWidget()->RemoveObserver(this);
+  }
+
+  // Wait till the shelf finishes animating to its expected bounds.
+  void WaitTillDoneAnimating() {
+    if (IsDoneAnimating())
+      done_waiting_ = true;
+    else
+      base::MessageLoop::current()->Run();
+  }
+
+  // Returns true if the animation has completed and it was valid.
+  bool WasValidAnimation() const {
+    return done_waiting_ && animation_steps_ > 0;
+  }
+
+ private:
+  // Returns true if shelf has finished animating to the target size.
+  bool IsDoneAnimating() const {
+    ShelfLayoutManager* layout_manager = GetShelfLayoutManager();
+    gfx::Rect current_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
+    int size = layout_manager->PrimaryAxisValue(current_bounds.height(),
+        current_bounds.width());
+    int desired_size = layout_manager->PrimaryAxisValue(target_bounds_.height(),
+        target_bounds_.width());
+    return (size == desired_size);
+  }
+
+  // views::WidgetObserver override.
+  virtual void OnWidgetBoundsChanged(views::Widget* widget,
+                                     const gfx::Rect& new_bounds) OVERRIDE {
+    if (done_waiting_)
+      return;
+
+    ++animation_steps_;
+    if (IsDoneAnimating()) {
+      done_waiting_ = true;
+      base::MessageLoop::current()->Quit();
+    }
+  }
+
+  gfx::Rect target_bounds_;
+  int animation_steps_;
+  bool done_waiting_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShelfAnimationWaiter);
+};
+
 class ShelfDragCallback {
  public:
   ShelfDragCallback(const gfx::Rect& not_visible, const gfx::Rect& visible)
@@ -1429,7 +1489,7 @@
   window1->Minimize();
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
 
-  // both minimzed => disable auto hide
+  // both minimized => disable auto hide
   window2->Minimize();
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
 
@@ -1444,14 +1504,84 @@
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
 }
 
-#if defined(OS_WIN)
-// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
-#define MAYBE_GestureRevealsTrayBubble DISABLED_GestureRevealsTrayBubble
-#else
-#define MAYBE_GestureRevealsTrayBubble GestureRevealsTrayBubble
-#endif
+// Test that the shelf animates back to its normal position upon a user
+// completing a gesture drag.
+TEST_F(ShelfLayoutManagerTest, ShelfAnimatesWhenGestureComplete) {
+  if (!SupportsHostWindowResize())
+    return;
 
-TEST_F(ShelfLayoutManagerTest, MAYBE_GestureRevealsTrayBubble) {
+  // Test the shelf animates back to its original visible bounds when it is
+  // dragged when there are no visible windows.
+  ShelfLayoutManager* shelf = GetShelfLayoutManager();
+  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+  gfx::Rect visible_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
+  {
+    // Enable animations so that we can make sure that they occur.
+    ui::ScopedAnimationDurationScaleMode regular_animations(
+        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+
+    aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+    gfx::Rect shelf_bounds_in_screen =
+        GetShelfWidget()->GetWindowBoundsInScreen();
+    gfx::Point start(shelf_bounds_in_screen.CenterPoint());
+    gfx::Point end(start.x(), shelf_bounds_in_screen.bottom());
+    generator.GestureScrollSequence(start, end,
+        base::TimeDelta::FromMilliseconds(10), 1);
+    EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
+    EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+
+    ShelfAnimationWaiter waiter(visible_bounds);
+    // Wait till the animation completes and check that it occurred.
+    waiter.WaitTillDoneAnimating();
+    EXPECT_TRUE(waiter.WasValidAnimation());
+  }
+
+  // Create a visible window so auto-hide behavior is enforced.
+  CreateTestWidget();
+
+  // Get the bounds of the shelf when it is hidden.
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+  gfx::Rect auto_hidden_bounds = GetShelfWidget()->GetWindowBoundsInScreen();
+
+  {
+    // Enable the animations so that we can make sure they do occur.
+    ui::ScopedAnimationDurationScaleMode regular_animations(
+        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+
+    gfx::Point start =
+        GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
+    gfx::Point end(start.x(), start.y() - 100);
+    aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+
+    // Test that the shelf animates to the visible bounds after a swipe up on
+    // the auto hidden shelf.
+    generator.GestureScrollSequence(start, end,
+        base::TimeDelta::FromMilliseconds(10), 1);
+    EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
+    ShelfAnimationWaiter waiter1(visible_bounds);
+    waiter1.WaitTillDoneAnimating();
+    EXPECT_TRUE(waiter1.WasValidAnimation());
+
+    // Test that the shelf animates to the auto hidden bounds after a swipe up
+    // on the visible shelf.
+    EXPECT_EQ(SHELF_VISIBLE, shelf->visibility_state());
+    generator.GestureScrollSequence(start, end,
+        base::TimeDelta::FromMilliseconds(10), 1);
+    EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
+    EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+    ShelfAnimationWaiter waiter2(auto_hidden_bounds);
+    waiter2.WaitTillDoneAnimating();
+    EXPECT_TRUE(waiter2.WasValidAnimation());
+  }
+}
+
+TEST_F(ShelfLayoutManagerTest, GestureRevealsTrayBubble) {
+  if (!SupportsHostWindowResize())
+    return;
+
   ShelfLayoutManager* shelf = GetShelfLayoutManager();
   shelf->LayoutShelf();
 
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index d16f876..8c7733f 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -4,6 +4,7 @@
 
 #include "ash/shelf/shelf_widget.h"
 
+#include "ash/ash_switches.h"
 #include "ash/focus_cycler.h"
 #include "ash/launcher/launcher_delegate.h"
 #include "ash/launcher/launcher_model.h"
@@ -15,6 +16,7 @@
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
+#include "ash/system/tray/test_system_tray_delegate.h"
 #include "ash/wm/property_util.h"
 #include "ash/wm/status_area_layout_manager.h"
 #include "ash/wm/window_properties.h"
@@ -254,9 +256,6 @@
   void SetDimmed(bool dimmed);
   bool GetDimmed() const;
 
-  // Set the bounds of the widget.
-  void SetWidgetBounds(const gfx::Rect bounds);
-
   void SetParentLayer(ui::Layer* layer);
 
   // views::View overrides:
@@ -359,11 +358,6 @@
   return dimmer_.get() && dimmer_->IsVisible();
 }
 
-void ShelfWidget::DelegateView::SetWidgetBounds(const gfx::Rect bounds) {
-  if (dimmer_)
-    dimmer_->SetBounds(bounds);
-}
-
 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) {
   layer->Add(&opaque_background_);
   ReorderLayers();
@@ -430,6 +424,8 @@
 
 void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect& old_bounds) {
   opaque_background_.SetBounds(GetLocalBounds());
+  if (dimmer_)
+    dimmer_->SetBounds(GetBoundsInScreen());
 }
 
 void ShelfWidget::DelegateView::ForceUndimming(bool force) {
@@ -528,6 +524,31 @@
   return SHELF_BACKGROUND_DEFAULT;
 }
 
+// static
+bool ShelfWidget::ShelfAlignmentAllowed() {
+  if (!ash::switches::ShowShelfAlignmentMenu())
+    return false;
+  user::LoginStatus login_status =
+      Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
+
+  switch (login_status) {
+    case user::LOGGED_IN_USER:
+    case user::LOGGED_IN_OWNER:
+      return true;
+    case user::LOGGED_IN_LOCKED:
+    case user::LOGGED_IN_PUBLIC:
+    case user::LOGGED_IN_LOCALLY_MANAGED:
+    case user::LOGGED_IN_GUEST:
+    case user::LOGGED_IN_RETAIL_MODE:
+    case user::LOGGED_IN_KIOSK_APP:
+    case user::LOGGED_IN_NONE:
+      return false;
+  }
+
+  DCHECK(false);
+  return false;
+}
+
 ShelfAlignment ShelfWidget::GetAlignment() const {
   return shelf_layout_manager_->GetAlignment();
 }
@@ -602,11 +623,6 @@
   status_area_widget_ = NULL;
 }
 
-void ShelfWidget::SetWidgetBounds(const gfx::Rect& rect) {
-  Widget::SetBounds(rect);
-  delegate_view_->SetWidgetBounds(rect);
-}
-
 void ShelfWidget::ForceUndimming(bool force) {
   delegate_view_->ForceUndimming(force);
 }
diff --git a/ash/shelf/shelf_widget.h b/ash/shelf/shelf_widget.h
index 392264a..c7adb74 100644
--- a/ash/shelf/shelf_widget.h
+++ b/ash/shelf/shelf_widget.h
@@ -34,6 +34,11 @@
       internal::WorkspaceController* workspace_controller);
   virtual ~ShelfWidget();
 
+  // Returns if shelf alignment option is enabled, and the user is able
+  // to adjust the alignment (guest and supervised mode users cannot for
+  // example).
+  static bool ShelfAlignmentAllowed();
+
   void SetAlignment(ShelfAlignment alignmnet);
   ShelfAlignment GetAlignment() const;
 
@@ -74,9 +79,6 @@
   // TODO(harrym): Remove when Status Area Widget is a child view.
   void ShutdownStatusAreaWidget();
 
-  // Set the bounds of the widget and the dim shelf overlay.
-  void SetWidgetBounds(const gfx::Rect& rect);
-
   // Force the shelf to be presented in an undimmed state.
   void ForceUndimming(bool force);
 
diff --git a/ash/shell.cc b/ash/shell.cc
index 996c817..c32371f 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -45,7 +45,6 @@
 #include "ash/wm/ash_focus_rules.h"
 #include "ash/wm/ash_native_cursor_manager.h"
 #include "ash/wm/base_layout_manager.h"
-#include "ash/wm/capture_controller.h"
 #include "ash/wm/coordinate_conversion.h"
 #include "ash/wm/custom_frame_view_ash.h"
 #include "ash/wm/event_client_impl.h"
@@ -54,6 +53,7 @@
 #include "ash/wm/lock_state_controller_impl2.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overlay_event_filter.h"
+#include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/power_button_controller.h"
 #include "ash/wm/property_util.h"
 #include "ash/wm/resize_shadow_controller.h"
@@ -68,7 +68,6 @@
 #include "ash/wm/window_animations.h"
 #include "ash/wm/window_cycle_controller.h"
 #include "ash/wm/window_properties.h"
-#include "ash/wm/window_selector_controller.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/workspace_controller.h"
 #include "base/bind.h"
@@ -112,14 +111,13 @@
 #if defined(OS_CHROMEOS)
 #if defined(USE_X11)
 #include "ash/ash_constants.h"
-#include "ash/display/display_change_observer_x11.h"
-#include "ash/display/display_error_observer.h"
+#include "ash/display/display_change_observer_chromeos.h"
+#include "ash/display/display_error_observer_chromeos.h"
 #include "ash/display/output_configurator_animation.h"
 #include "base/chromeos/chromeos_version.h"
 #include "base/message_loop/message_pump_aurax11.h"
 #include "chromeos/display/output_configurator.h"
 #include "content/public/browser/gpu_data_manager.h"
-#include "content/public/common/content_switches.h"
 #include "gpu/config/gpu_feature_type.h"
 #endif  // defined(USE_X11)
 #include "ash/system/chromeos/power/power_status.h"
@@ -227,9 +225,7 @@
 #if defined(OS_CHROMEOS) && defined(USE_X11)
   bool is_panel_fitting_disabled =
       content::GpuDataManager::GetInstance()->IsFeatureBlacklisted(
-          gpu::GPU_FEATURE_TYPE_PANEL_FITTING) ||
-      CommandLine::ForCurrentProcess()->HasSwitch(
-          ::switches::kDisablePanelFitting);
+          gpu::GPU_FEATURE_TYPE_PANEL_FITTING);
 
   output_configurator_->Init(!is_panel_fitting_disabled);
 
@@ -283,6 +279,9 @@
 
   locale_notification_controller_.reset();
 
+  // Drag-and-drop must be canceled prior to close all windows.
+  drag_drop_controller_.reset();
+
   // Destroy all child windows including widgets.
   display_controller_->CloseChildWindows();
 
@@ -293,7 +292,6 @@
   // These need a valid Shell instance to clean up properly, so explicitly
   // delete them before invalidating the instance.
   // Alphabetical. TODO(oshima): sort.
-  drag_drop_controller_.reset();
   magnification_controller_.reset();
   partial_magnification_controller_.reset();
   resize_shadow_controller_.reset();
@@ -301,7 +299,6 @@
   tooltip_controller_.reset();
   event_client_.reset();
   window_cycle_controller_.reset();
-  capture_controller_.reset();
   nested_dispatcher_controller_.reset();
   user_action_client_.reset();
   visibility_controller_.reset();
@@ -454,7 +451,7 @@
       new internal::OutputConfiguratorAnimation());
   output_configurator_->AddObserver(output_configurator_animation_.get());
   if (base::chromeos::IsRunningOnChromeOS()) {
-    display_change_observer_.reset(new internal::DisplayChangeObserverX11);
+    display_change_observer_.reset(new internal::DisplayChangeObserver);
     // Register |display_change_observer_| first so that the rest of
     // observer gets invoked after the root windows are configured.
     output_configurator_->AddObserver(display_change_observer_.get());
@@ -467,7 +464,7 @@
         delegate_->IsFirstRunAfterBoot() ? kChromeOsBootColor : 0);
     display_initialized = true;
   }
-#endif
+#endif  // defined(OS_CHROMEOS) && defined(USE_X11)
   if (!display_initialized)
     display_manager_->InitFromCommandLine();
 
@@ -546,8 +543,6 @@
   system_gesture_filter_.reset(new internal::SystemGestureEventFilter);
   AddPreTargetHandler(system_gesture_filter_.get());
 
-  capture_controller_.reset(new internal::CaptureController);
-
   // The keyboard system must be initialized before the RootWindowController is
   // created.
   if (keyboard::IsKeyboardEnabled())
@@ -920,7 +915,6 @@
   DCHECK(activation_client_);
   DCHECK(visibility_controller_.get());
   DCHECK(drag_drop_controller_.get());
-  DCHECK(capture_controller_.get());
   DCHECK(window_cycle_controller_.get());
 
   aura::client::SetFocusClient(root_window, focus_client_.get());
@@ -933,7 +927,6 @@
   }
   aura::client::SetVisibilityClient(root_window, visibility_controller_.get());
   aura::client::SetDragDropClient(root_window, drag_drop_controller_.get());
-  aura::client::SetCaptureClient(root_window, capture_controller_.get());
   aura::client::SetScreenPositionClient(root_window,
                                         screen_position_controller_.get());
   aura::client::SetCursorClient(root_window, &cursor_manager_);
diff --git a/ash/shell.h b/ash/shell.h
index ae08e7b..5068815 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -102,7 +102,7 @@
 class ActivationController;
 class AppListController;
 class CaptureController;
-class DisplayChangeObserverX11;
+class DisplayChangeObserver;
 class DisplayErrorObserver;
 class DisplayManager;
 class DragDropController;
@@ -547,7 +547,6 @@
   scoped_ptr<internal::AppListController> app_list_controller_;
 
   scoped_ptr<internal::ActivationController> activation_controller_;
-  scoped_ptr<internal::CaptureController> capture_controller_;
   scoped_ptr<internal::DragDropController> drag_drop_controller_;
   scoped_ptr<internal::ResizeShadowController> resize_shadow_controller_;
   scoped_ptr<views::corewm::ShadowController> shadow_controller_;
@@ -609,8 +608,8 @@
       output_configurator_animation_;
   scoped_ptr<internal::DisplayErrorObserver> display_error_observer_;
 
-  // Receives output change events and udpates the display manager.
-  scoped_ptr<internal::DisplayChangeObserverX11> display_change_observer_;
+  // Listens for output changes and updates the display manager.
+  scoped_ptr<internal::DisplayChangeObserver> display_change_observer_;
 #endif  // defined(OS_CHROMEOS) && defined(USE_X11)
 
   scoped_ptr<internal::ResolutionNotificationController>
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index dd7adc5..498de37 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -294,22 +294,10 @@
     // Nothing needs to be done.
   }
 
-  virtual void ViewActivationChanged(bool active) OVERRIDE {
-    // Nothing needs to be done.
-  }
-
   virtual gfx::ImageSkia GetWindowIcon() OVERRIDE {
     return gfx::ImageSkia();
   }
 
-  virtual base::string16 GetCurrentUserName() OVERRIDE {
-    return base::string16();
-  }
-
-  virtual base::string16 GetCurrentUserEmail() OVERRIDE {
-    return base::string16();
-  }
-
   virtual void OpenSettings() OVERRIDE {
     // Nothing needs to be done.
   }
diff --git a/ash/shell/content_client/shell_browser_main_parts.cc b/ash/shell/content_client/shell_browser_main_parts.cc
index fae491f..1dc0b3e 100644
--- a/ash/shell/content_client/shell_browser_main_parts.cc
+++ b/ash/shell/content_client/shell_browser_main_parts.cc
@@ -18,8 +18,8 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/common/content_switches.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_net_log.h"
+#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"
diff --git a/ash/shell/content_client/shell_content_browser_client.cc b/ash/shell/content_client/shell_content_browser_client.cc
index 93fc834..ec24bc7 100644
--- a/ash/shell/content_client/shell_content_browser_client.cc
+++ b/ash/shell/content_client/shell_content_browser_client.cc
@@ -5,7 +5,7 @@
 #include "ash/shell/content_client/shell_content_browser_client.h"
 
 #include "ash/shell/content_client/shell_browser_main_parts.h"
-#include "content/shell/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_context.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 namespace ash {
diff --git a/ash/shell/launcher_delegate_impl.cc b/ash/shell/launcher_delegate_impl.cc
index 51f6171..ac0aeee 100644
--- a/ash/shell/launcher_delegate_impl.cc
+++ b/ash/shell/launcher_delegate_impl.cc
@@ -64,10 +64,6 @@
 void LauncherDelegateImpl::OnLauncherDestroyed(Launcher* launcher) {
 }
 
-bool LauncherDelegateImpl::IsPerAppLauncher() {
-  return false;
-}
-
 LauncherID LauncherDelegateImpl::GetLauncherIDForAppID(
     const std::string& app_id) {
   return 0;
diff --git a/ash/shell/launcher_delegate_impl.h b/ash/shell/launcher_delegate_impl.h
index 4788029..86a3579 100644
--- a/ash/shell/launcher_delegate_impl.h
+++ b/ash/shell/launcher_delegate_impl.h
@@ -39,7 +39,6 @@
   virtual bool ShouldShowTooltip(const LauncherItem& item) OVERRIDE;
   virtual void OnLauncherCreated(Launcher* launcher) OVERRIDE;
   virtual void OnLauncherDestroyed(Launcher* launcher) OVERRIDE;
-  virtual bool IsPerAppLauncher() OVERRIDE;
   virtual LauncherID GetLauncherIDForAppID(const std::string& app_id) OVERRIDE;
   virtual void PinAppWithID(const std::string& app_id) OVERRIDE;
   virtual bool IsAppPinned(const std::string& app_id) OVERRIDE;
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 20d0a7f..471f5ac 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -8,6 +8,7 @@
 
 #include "ash/caps_lock_delegate_stub.h"
 #include "ash/host/root_window_host_factory.h"
+#include "ash/keyboard_controller_proxy_stub.h"
 #include "ash/session_state_delegate.h"
 #include "ash/session_state_delegate_stub.h"
 #include "ash/shell/context_menu.h"
@@ -18,39 +19,9 @@
 #include "ash/wm/window_util.h"
 #include "base/message_loop/message_loop.h"
 #include "ui/aura/window.h"
-#include "ui/keyboard/keyboard_controller_proxy.h"
 #include "ui/views/corewm/input_method_event_filter.h"
 
 namespace ash {
-
-namespace {
-
-class DummyKeyboardControllerProxy : public keyboard::KeyboardControllerProxy {
- public:
-  DummyKeyboardControllerProxy() {}
-  virtual ~DummyKeyboardControllerProxy() {}
-
- private:
-  // Overridden from keyboard::KeyboardControllerProxy:
-  virtual content::BrowserContext* GetBrowserContext() OVERRIDE {
-    return Shell::GetInstance()->browser_context();
-  }
-
-  virtual ui::InputMethod* GetInputMethod() OVERRIDE {
-    return Shell::GetInstance()->input_method_filter()->input_method();
-  }
-
-  virtual void RequestAudioInput(content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback) OVERRIDE {
-    return;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(DummyKeyboardControllerProxy);
-};
-
-}  // namespace
-
 namespace shell {
 
 ShellDelegateImpl::ShellDelegateImpl()
@@ -128,7 +99,7 @@
 
 keyboard::KeyboardControllerProxy*
     ShellDelegateImpl::CreateKeyboardControllerProxy() {
-  return new DummyKeyboardControllerProxy();
+  return new KeyboardControllerProxyStub();
 }
 
 void ShellDelegateImpl::ShowTaskManager() {
diff --git a/ash/shell/shell_main_parts.cc b/ash/shell/shell_main_parts.cc
index 7399503..8cad410 100644
--- a/ash/shell/shell_main_parts.cc
+++ b/ash/shell/shell_main_parts.cc
@@ -13,7 +13,7 @@
 
 void PreMainMessageLoopStart() {
   ui::RegisterPathProvider();
-  icu_util::Initialize();
+  base::i18n::InitializeICU();
   ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL);
 }
 
diff --git a/ash/shell/shell_main_parts_mac.mm b/ash/shell/shell_main_parts_mac.mm
index 292e1d5..4153a58 100644
--- a/ash/shell/shell_main_parts_mac.mm
+++ b/ash/shell/shell_main_parts_mac.mm
@@ -17,7 +17,7 @@
 
 void PreMainMessageLoopStart() {
   ui::RegisterPathProvider();
-  icu_util::Initialize();
+  base::i18n::InitializeICU();
   ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL);
 
   base::scoped_nsobject<NSNib> nib(
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index 842eb5d..0cc1e44 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -16,6 +16,7 @@
 #include "ash/session_state_delegate.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_widget.h"
+#include "ash/shell_delegate.h"
 #include "ash/shell_window_ids.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shell_test_api.h"
@@ -25,7 +26,10 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
+#include "ui/base/models/simple_menu_model.h"
 #include "ui/gfx/size.h"
+#include "ui/views/controls/menu/menu_controller.h"
+#include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/window/dialog_delegate.h"
@@ -104,6 +108,32 @@
   DISALLOW_COPY_AND_ASSIGN(ModalWindow);
 };
 
+class SimpleMenuDelegate : public ui::SimpleMenuModel::Delegate {
+ public:
+  SimpleMenuDelegate() {}
+  virtual ~SimpleMenuDelegate() {}
+
+  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE {
+    return false;
+  }
+
+  virtual bool IsCommandIdEnabled(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 {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SimpleMenuDelegate);
+};
+
 }  // namespace
 
 class ShellTest : public test::AshTestBase {
@@ -130,8 +160,39 @@
         always_on_top;
 
     widget->Close();
-}
+  }
 
+  void LockScreenAndVerifyMenuClosed() {
+    // Verify a menu is open before locking.
+    views::MenuController* menu_controller =
+        views::MenuController::GetActiveInstance();
+    DCHECK(menu_controller);
+    EXPECT_EQ(views::MenuController::EXIT_NONE, menu_controller->exit_type());
+
+    // Create a LockScreen window.
+    views::Widget::InitParams widget_params(
+        views::Widget::InitParams::TYPE_WINDOW);
+    SessionStateDelegate* delegate =
+        Shell::GetInstance()->session_state_delegate();
+    delegate->LockScreen();
+    views::Widget* lock_widget = CreateTestWindow(widget_params);
+    ash::Shell::GetContainer(
+        Shell::GetPrimaryRootWindow(),
+        ash::internal::kShellWindowId_LockScreenContainer)->
+        AddChild(lock_widget->GetNativeView());
+    lock_widget->Show();
+    EXPECT_TRUE(delegate->IsScreenLocked());
+    EXPECT_TRUE(lock_widget->GetNativeView()->HasFocus());
+
+    // Verify menu is closed.
+    EXPECT_NE(views::MenuController::EXIT_NONE, menu_controller->exit_type());
+    lock_widget->Close();
+    delegate->UnlockScreen();
+
+    // In case the menu wasn't closed, cancel the menu to exit the nested menu
+    // run loop so that the test will not time out.
+    menu_controller->CancelAll();
+  }
 };
 
 TEST_F(ShellTest, CreateWindow) {
@@ -302,6 +363,29 @@
   EXPECT_FALSE(delegate->IsScreenLocked());
 }
 
+TEST_F(ShellTest, LockScreenClosesActiveMenu) {
+  SimpleMenuDelegate menu_delegate;
+  scoped_ptr<ui::SimpleMenuModel> menu_model(
+      new ui::SimpleMenuModel(&menu_delegate));
+  menu_model->AddItem(0, ASCIIToUTF16("Menu item"));
+  views::Widget* widget = ash::Shell::GetPrimaryRootWindowController()->
+      wallpaper_controller()->widget();
+  scoped_ptr<views::MenuRunner> menu_runner(
+      new views::MenuRunner(menu_model.get()));
+
+  // When MenuRunner runs a nested loop the LockScreenAndVerifyMenuClosed
+  // command will fire, check the menu state and ensure the nested menu loop
+  // is exited so that the test will terminate.
+  base::MessageLoopForUI::current()->PostTask(FROM_HERE,
+      base::Bind(&ShellTest::LockScreenAndVerifyMenuClosed,
+                 base::Unretained(this)));
+
+  EXPECT_EQ(views::MenuRunner::NORMAL_EXIT,
+      menu_runner->RunMenuAt(widget, NULL, gfx::Rect(),
+        views::MenuItemView::TOPLEFT, ui::MENU_SOURCE_MOUSE,
+        views::MenuRunner::CONTEXT_MENU));
+}
+
 // Fails on Mac, see http://crbug.com/115662
 #if defined(OS_MACOSX)
 #define MAYBE_ManagedWindowModeBasics DISABLED_ManagedWindowModeBasics
diff --git a/ash/shell_window_ids.h b/ash/shell_window_ids.h
index 406f417..1c1c396 100644
--- a/ash/shell_window_ids.h
+++ b/ash/shell_window_ids.h
@@ -36,65 +36,68 @@
 // The desktop background window.
 const int kShellWindowId_DesktopBackgroundContainer = 4;
 
+// The virtual keyboard container.
+const int kShellWindowId_VirtualKeyboardContainer = 5;
+
 // TODO(sky): rename kShellWindowId_DefaultContainer.
 
 // The container for standard top-level windows.
-const int kShellWindowId_DefaultContainer = 5;
+const int kShellWindowId_DefaultContainer = 6;
 
 // The container for top-level windows with the 'always-on-top' flag set.
-const int kShellWindowId_AlwaysOnTopContainer = 6;
+const int kShellWindowId_AlwaysOnTopContainer = 7;
 
 // The container for windows docked to either side of the desktop.
-const int kShellWindowId_DockedContainer = 7;
+const int kShellWindowId_DockedContainer = 8;
 
 // The container for panel windows.
-const int kShellWindowId_PanelContainer = 8;
+const int kShellWindowId_PanelContainer = 9;
 
 // The container for the shelf.
-const int kShellWindowId_ShelfContainer = 9;
+const int kShellWindowId_ShelfContainer = 10;
 
 // The container for the app list.
-const int kShellWindowId_AppListContainer = 10;
+const int kShellWindowId_AppListContainer = 11;
 
 // The container for user-specific modal windows.
-const int kShellWindowId_SystemModalContainer = 11;
+const int kShellWindowId_SystemModalContainer = 12;
 
 // 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 = 12;
+const int kShellWindowId_InputMethodContainer = 13;
 
 // The container for the lock screen background.
-const int kShellWindowId_LockScreenBackgroundContainer = 13;
+const int kShellWindowId_LockScreenBackgroundContainer = 14;
 
 // The container for the lock screen.
-const int kShellWindowId_LockScreenContainer = 14;
+const int kShellWindowId_LockScreenContainer = 15;
 
 // The container for the lock screen modal windows.
-const int kShellWindowId_LockSystemModalContainer = 15;
+const int kShellWindowId_LockSystemModalContainer = 16;
 
 // The container for the status area.
-const int kShellWindowId_StatusContainer = 16;
+const int kShellWindowId_StatusContainer = 17;
 
 // The container for menus.
-const int kShellWindowId_MenuContainer = 17;
+const int kShellWindowId_MenuContainer = 18;
 
 // The container for drag/drop images and tooltips.
-const int kShellWindowId_DragImageAndTooltipContainer = 18;
+const int kShellWindowId_DragImageAndTooltipContainer = 19;
 
 // The container for bubbles briefly overlaid onscreen to show settings changes
 // (volume, brightness, etc.).
-const int kShellWindowId_SettingBubbleContainer = 19;
+const int kShellWindowId_SettingBubbleContainer = 20;
 
 // The container for special components overlaid onscreen, such as the
 // region selector for partial screenshots.
-const int kShellWindowId_OverlayContainer = 20;
+const int kShellWindowId_OverlayContainer = 21;
 
 // ID of the window created by PhantomWindowController or DragWindowController.
-const int kShellWindowId_PhantomWindow = 21;
+const int kShellWindowId_PhantomWindow = 22;
 
 // The topmost container, used for power off animation.
-const int kShellWindowId_PowerButtonAnimationContainer = 22;
+const int kShellWindowId_PowerButtonAnimationContainer = 23;
 
 }  // namespace internal
 
diff --git a/ash/strings/ash_strings_ar.xtb b/ash/strings/ash_strings_ar.xtb
index 0ba0fff..7be62a6 100644
--- a/ash/strings/ash_strings_ar.xtb
+++ b/ash/strings/ash_strings_ar.xtb
@@ -82,7 +82,7 @@
 <translation id="1480041086352807611">الوضع التجريبي</translation>
 <translation id="3626637461649818317">باقٍ <ph name="PERCENTAGE"/>%</translation>
 <translation id="9089416786594320554">أساليب الإدخال</translation>
-<translation id="6247708409970142803"><ph name="PERCENTAGE"/>%</translation>
+<translation id="6247708409970142803">%<ph name="PERCENTAGE"/></translation>
 <translation id="2614835198358683673">قد لا يستجيب جهاز Chromebook لعملية الشحن وهو قيد التشغيل. مع مراعاة استخدام الشاحن المخصص للجهاز.</translation>
 <translation id="1895658205118569222">إيقاف التشغيل</translation>
 <translation id="4430019312045809116">مستوى الصوت</translation>
diff --git a/ash/strings/ash_strings_fa.xtb b/ash/strings/ash_strings_fa.xtb
index 2237487..9639c88 100644
--- a/ash/strings/ash_strings_fa.xtb
+++ b/ash/strings/ash_strings_fa.xtb
@@ -80,7 +80,7 @@
 <translation id="1480041086352807611">حالت نمایش</translation>
 <translation id="3626637461649818317"><ph name="PERCENTAGE"/>٪ باقیمانده</translation>
 <translation id="9089416786594320554">روش‌های ورودی</translation>
-<translation id="6247708409970142803"><ph name="PERCENTAGE"/>%</translation>
+<translation id="6247708409970142803">%<ph name="PERCENTAGE"/></translation>
 <translation id="2614835198358683673">وقتی Chromebook روشن است ممکن است شارژ نشود. از شارژر مخصوص دستگاه استفاده کنید.</translation>
 <translation id="1895658205118569222">بسته شدن</translation>
 <translation id="4430019312045809116">میزان صدا</translation>
diff --git a/ash/strings/ash_strings_fr.xtb b/ash/strings/ash_strings_fr.xtb
index 40007f4..05c9f7c 100644
--- a/ash/strings/ash_strings_fr.xtb
+++ b/ash/strings/ash_strings_fr.xtb
@@ -139,7 +139,7 @@
 <translation id="5045550434625856497">Mot de passe incorrect.</translation>
 <translation id="1602076796624386989">Activer les données mobiles</translation>
 <translation id="6981982820502123353">Accessibilité</translation>
-<translation id="3157931365184549694">Rétablir</translation>
+<translation id="3157931365184549694">Restaurer</translation>
 <translation id="4274292172790327596">Erreur non reconnue</translation>
 <translation id="4032485810211612751"><ph name="HOURS"/>:<ph name="MINUTES"/>:<ph name="SECONDS"/></translation>
 <translation id="225680501294068881">Recherche d'appareils en cours…</translation>
diff --git a/ash/strings/ash_strings_id.xtb b/ash/strings/ash_strings_id.xtb
index 570d3e4..3007b2f 100644
--- a/ash/strings/ash_strings_id.xtb
+++ b/ash/strings/ash_strings_id.xtb
@@ -139,7 +139,7 @@
 <translation id="5045550434625856497">Sandi salah</translation>
 <translation id="1602076796624386989">Aktifkan data seluler</translation>
 <translation id="6981982820502123353">Aksesibilitas</translation>
-<translation id="3157931365184549694">Kembalikan</translation>
+<translation id="3157931365184549694">Pulihkan</translation>
 <translation id="4274292172790327596">Kesalahan tak dikenal</translation>
 <translation id="4032485810211612751"><ph name="HOURS"/>.<ph name="MINUTES"/>.<ph name="SECONDS"/></translation>
 <translation id="225680501294068881">Memindai perangkat...</translation>
diff --git a/ash/strings/ash_strings_ja.xtb b/ash/strings/ash_strings_ja.xtb
index b7cc1d5..c98ccb3 100644
--- a/ash/strings/ash_strings_ja.xtb
+++ b/ash/strings/ash_strings_ja.xtb
@@ -73,7 +73,7 @@
 <translation id="6549021752953852991">利用可能なセルラー ネットワークがありません</translation>
 <translation id="4379753398862151997">Dear Monitor, it's not working out between us.(このモニターはサポートされていません)</translation>
 <translation id="6426039856985689743">モバイル データを無効にする</translation>
-<translation id="3087734570205094154">一番下</translation>
+<translation id="3087734570205094154">下</translation>
 <translation id="3742055079367172538">スクリーンショット撮影完了</translation>
 <translation id="8878886163241303700">画面を拡張しています</translation>
 <translation id="5271016907025319479">VPN が設定されていません。</translation>
diff --git a/ash/strings/ash_strings_ml.xtb b/ash/strings/ash_strings_ml.xtb
index 5abec82..df9b8e8 100644
--- a/ash/strings/ash_strings_ml.xtb
+++ b/ash/strings/ash_strings_ml.xtb
@@ -138,7 +138,7 @@
 <translation id="5045550434625856497">പാസ്‌വേഡ് തെറ്റാണ്</translation>
 <translation id="1602076796624386989">മൊബൈൽ ഡാറ്റ പ്രാപ്‌തമാക്കുക</translation>
 <translation id="6981982820502123353">പ്രവേശനക്ഷമത</translation>
-<translation id="3157931365184549694">പുനസ്ഥാപിക്കുക</translation>
+<translation id="3157931365184549694">പുനഃസ്ഥാപിക്കുക</translation>
 <translation id="4274292172790327596">തിരിച്ചറിയാത്ത പിശക്</translation>
 <translation id="4032485810211612751"><ph name="HOURS"/>:<ph name="MINUTES"/>:<ph name="SECONDS"/></translation>
 <translation id="225680501294068881">ഉപകരണങ്ങൾക്കായി സ്‌കാൻ ചെയ്യുന്നു...</translation>
diff --git a/ash/strings/ash_strings_ru.xtb b/ash/strings/ash_strings_ru.xtb
index 8760a08..c248abc 100644
--- a/ash/strings/ash_strings_ru.xtb
+++ b/ash/strings/ash_strings_ru.xtb
@@ -1,7 +1,7 @@
 <?xml version="1.0" ?>
 <!DOCTYPE translationbundle>
 <translationbundle lang="ru">
-<translation id="3595596368722241419">Аккумулятор заряжен.</translation>
+<translation id="3595596368722241419">Аккумулятор заряжен</translation>
 <translation id="5250713215130379958">Автоматически скрывать панель запуска</translation>
 <translation id="7814236020522506259"><ph name="HOUR"/> <ph name="MINUTE"/></translation>
 <translation id="7880025619322806991">Состояние портала</translation>
diff --git a/ash/strings/ash_strings_th.xtb b/ash/strings/ash_strings_th.xtb
index ddd6485..a749f02 100644
--- a/ash/strings/ash_strings_th.xtb
+++ b/ash/strings/ash_strings_th.xtb
@@ -139,7 +139,7 @@
 <translation id="5045550434625856497">รหัสผ่านไม่ถูกต้อง</translation>
 <translation id="1602076796624386989">เปิดใช้งานข้อมูลมือถือ</translation>
 <translation id="6981982820502123353">การเข้าถึง</translation>
-<translation id="3157931365184549694">คืนสภาพ</translation>
+<translation id="3157931365184549694">คืนค่า</translation>
 <translation id="4274292172790327596">ข้อผิดพลาดที่ไม่รู้จัก</translation>
 <translation id="4032485810211612751"><ph name="HOURS"/>:<ph name="MINUTES"/>:<ph name="SECONDS"/></translation>
 <translation id="225680501294068881">กำลังสแกนหาอุปกรณ์...</translation>
diff --git a/ash/system/chromeos/audio/tray_audio.cc b/ash/system/chromeos/audio/tray_audio.cc
index 6ad4362..f25233a 100644
--- a/ash/system/chromeos/audio/tray_audio.cc
+++ b/ash/system/chromeos/audio/tray_audio.cc
@@ -78,6 +78,32 @@
     return kNoAudioDeviceIcon;
 }
 
+base::string16 GetAudioDeviceName(const chromeos::AudioDevice& device) {
+  switch(device.type) {
+    case chromeos::AUDIO_TYPE_HEADPHONE:
+      return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_HEADPHONE);
+    case chromeos::AUDIO_TYPE_INTERNAL_SPEAKER:
+      return l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_SPEAKER);
+    case chromeos::AUDIO_TYPE_INTERNAL_MIC:
+      return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_AUDIO_INTERNAL_MIC);
+    case chromeos::AUDIO_TYPE_USB:
+      return l10n_util::GetStringFUTF16(
+          IDS_ASH_STATUS_TRAY_AUDIO_USB_DEVICE,
+          UTF8ToUTF16(device.display_name));
+    case chromeos::AUDIO_TYPE_BLUETOOTH:
+      return l10n_util::GetStringFUTF16(
+          IDS_ASH_STATUS_TRAY_AUDIO_BLUETOOTH_DEVICE,
+          UTF8ToUTF16(device.display_name));
+    case chromeos::AUDIO_TYPE_HDMI:
+      return l10n_util::GetStringFUTF16(
+          IDS_ASH_STATUS_TRAY_AUDIO_HDMI_DEVICE,
+          UTF8ToUTF16(device.display_name));
+    default:
+      return UTF8ToUTF16(device.display_name);
+  }
+}
+
 }  // namespace
 
 namespace tray {
@@ -434,7 +460,7 @@
         false);  /* no checkmark */
     for (size_t i = 0; i < output_devices_.size(); ++i) {
       HoverHighlightView* container = AddScrollListItem(
-          UTF8ToUTF16(output_devices_[i].display_name),
+          GetAudioDeviceName(output_devices_[i]),
           gfx::Font::NORMAL,
           output_devices_[i].active);  /* checkmark if active */
       device_map_[container] = output_devices_[i];
@@ -449,7 +475,7 @@
         false);  /* no checkmark */
     for (size_t i = 0; i < input_devices_.size(); ++i) {
       HoverHighlightView* container = AddScrollListItem(
-          UTF8ToUTF16(input_devices_[i].display_name),
+          GetAudioDeviceName(input_devices_[i]),
           gfx::Font::NORMAL,
           input_devices_[i].active);  /* checkmark if active */
       device_map_[container] = input_devices_[i];
diff --git a/ash/system/chromeos/managed/tray_locally_managed_user.cc b/ash/system/chromeos/managed/tray_locally_managed_user.cc
index 49dea0c..e42ea6f 100644
--- a/ash/system/chromeos/managed/tray_locally_managed_user.cc
+++ b/ash/system/chromeos/managed/tray_locally_managed_user.cc
@@ -10,6 +10,7 @@
 #include "ash/system/user/login_status.h"
 #include "base/logging.h"
 #include "grit/ash_resources.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_delegate.h"
@@ -18,28 +19,10 @@
 
 namespace ash {
 namespace internal {
-namespace {
 
-const char kLocallyManagedUserNotificationId[] =
+const char TrayLocallyManagedUser::kNotificationId[] =
     "chrome://user/locally-managed";
 
-void CreateOrUpdateNotification(const base::string16& new_message) {
-  scoped_ptr<Notification> notification(new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE,
-      kLocallyManagedUserNotificationId,
-      new_message,
-      base::string16() /* body is empty */,
-      gfx::Image() /* icon */,
-      base::string16() /* display_source */,
-      std::string() /* extension_id */,
-      message_center::RichNotificationData(),
-      NULL /* no delegate */));
-  notification->SetSystemPriority();
-  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
-}
-
-} // namespace
-
 TrayLocallyManagedUser::TrayLocallyManagedUser(SystemTray* system_tray)
     : SystemTrayItem(system_tray),
       tray_view_(NULL),
@@ -54,10 +37,8 @@
       GetLocallyManagedUserMessage();
   if (tray_view_)
     tray_view_->SetMessage(message);
-  if (message_center::MessageCenter::Get()->HasNotification(
-          kLocallyManagedUserNotificationId)) {
+  if (message_center::MessageCenter::Get()->HasNotification(kNotificationId))
     CreateOrUpdateNotification(message);
-  }
 }
 
 views::View* TrayLocallyManagedUser::CreateDefaultView(
@@ -91,5 +72,22 @@
   status_ = status;
 }
 
+void TrayLocallyManagedUser::CreateOrUpdateNotification(
+    const base::string16& new_message) {
+  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+  scoped_ptr<Notification> notification(new Notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE,
+      kNotificationId,
+      new_message,
+      base::string16() /* body is empty */,
+      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_MANAGED_USER),
+      base::string16() /* display_source */,
+      std::string() /* extension_id */,
+      message_center::RichNotificationData(),
+      NULL /* no delegate */));
+  notification->SetSystemPriority();
+  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
+}
+
 } // namespace internal
 } // namespace ash
diff --git a/ash/system/chromeos/managed/tray_locally_managed_user.h b/ash/system/chromeos/managed/tray_locally_managed_user.h
index e028634..a508ec3 100644
--- a/ash/system/chromeos/managed/tray_locally_managed_user.h
+++ b/ash/system/chromeos/managed/tray_locally_managed_user.h
@@ -5,20 +5,20 @@
 #ifndef ASH_SYSTEM_CHROMEOS_LOCALLY_MANAGED_TRAY_LOCALLY_MANAGED_USER_H
 #define ASH_SYSTEM_CHROMEOS_LOCALLY_MANAGED_TRAY_LOCALLY_MANAGED_USER_H
 
+#include "ash/ash_export.h"
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/system/tray/view_click_listener.h"
+#include "base/strings/string16.h"
 
 namespace ash {
 class SystemTray;
-}
 
-namespace ash {
 namespace internal {
 
 class LabelTrayView;
 
-class TrayLocallyManagedUser : public SystemTrayItem,
-                               public ViewClickListener {
+class ASH_EXPORT TrayLocallyManagedUser : public SystemTrayItem,
+                                          public ViewClickListener {
  public:
   explicit TrayLocallyManagedUser(SystemTray* system_tray);
   virtual ~TrayLocallyManagedUser();
@@ -36,6 +36,12 @@
   virtual void OnViewClicked(views::View* sender) OVERRIDE;
 
  private:
+  friend class TrayLocallyManagedUserTest;
+
+  static const char kNotificationId[];
+
+  void CreateOrUpdateNotification(const base::string16& new_message);
+
   LabelTrayView* tray_view_;
   // Previous login status to avoid showing notification upon unlock.
   user::LoginStatus status_;
diff --git a/ash/system/chromeos/managed/tray_locally_managed_user_unittest.cc b/ash/system/chromeos/managed/tray_locally_managed_user_unittest.cc
new file mode 100644
index 0000000..af7e5d9
--- /dev/null
+++ b/ash/system/chromeos/managed/tray_locally_managed_user_unittest.cc
@@ -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.
+
+#include "ash/system/chromeos/managed/tray_locally_managed_user.h"
+
+#include "ash/shell.h"
+#include "ash/system/tray/test_system_tray_delegate.h"
+#include "ash/system/user/login_status.h"
+#include "ash/test/ash_test_base.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_list.h"
+#include "ui/message_center/notification_types.h"
+
+using message_center::NotificationList;
+
+namespace ash {
+namespace internal {
+
+class TrayLocallyManagedUserTest : public test::AshTestBase {
+ public:
+  TrayLocallyManagedUserTest() {}
+  virtual ~TrayLocallyManagedUserTest() {}
+
+ protected:
+  message_center::Notification* GetPopup();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TrayLocallyManagedUserTest);
+};
+
+message_center::Notification* TrayLocallyManagedUserTest::GetPopup() {
+  NotificationList::PopupNotifications popups =
+      message_center::MessageCenter::Get()->GetPopupNotifications();
+  for (NotificationList::PopupNotifications::const_iterator iter =
+           popups.begin(); iter != popups.end(); ++iter) {
+    if ((*iter)->id() == TrayLocallyManagedUser::kNotificationId)
+      return *iter;
+  }
+  return NULL;
+}
+
+class TrayLocallyManagedUserInitialTest : public TrayLocallyManagedUserTest {
+ public:
+  TrayLocallyManagedUserInitialTest() {}
+  virtual ~TrayLocallyManagedUserInitialTest() {}
+
+  virtual void SetUp() OVERRIDE;
+  virtual void TearDown() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TrayLocallyManagedUserInitialTest);
+};
+
+void TrayLocallyManagedUserInitialTest::SetUp() {
+  test::TestSystemTrayDelegate::SetInitialLoginStatus(
+      user::LOGGED_IN_LOCALLY_MANAGED);
+  test::AshTestBase::SetUp();
+}
+
+void TrayLocallyManagedUserInitialTest::TearDown() {
+  test::AshTestBase::TearDown();
+  // SetInitialLoginStatus() is reset in AshTestHelper::TearDown().
+}
+
+TEST_F(TrayLocallyManagedUserTest, LocallyManagedUserHasNotification) {
+  test::TestSystemTrayDelegate* delegate =
+      static_cast<test::TestSystemTrayDelegate*>(
+          ash::Shell::GetInstance()->system_tray_delegate());
+  delegate->SetLoginStatus(user::LOGGED_IN_LOCALLY_MANAGED);
+
+  message_center::Notification* notification = GetPopup();
+  ASSERT_NE(static_cast<message_center::Notification*>(NULL), notification);
+  EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY),
+            notification->rich_notification_data().priority);
+}
+
+TEST_F(TrayLocallyManagedUserInitialTest, LocallyManagedUserNoCrash) {
+  // Initial login status is already LOCALLY_MANAGED, which should create
+  // the notification and should not cause crashes.
+  message_center::Notification* notification = GetPopup();
+  ASSERT_NE(static_cast<message_center::Notification*>(NULL), notification);
+  EXPECT_EQ(static_cast<int>(message_center::SYSTEM_PRIORITY),
+            notification->rich_notification_data().priority);
+}
+
+}  // namespace test
+}  // namespace
diff --git a/ash/system/chromeos/network/network_connect.cc b/ash/system/chromeos/network/network_connect.cc
index 3aca162..534b706 100644
--- a/ash/system/chromeos/network/network_connect.cc
+++ b/ash/system/chromeos/network/network_connect.cc
@@ -5,7 +5,6 @@
 #include "ash/system/chromeos/network/network_connect.h"
 
 #include "ash/shell.h"
-#include "ash/system/chromeos/network/network_observer.h"
 #include "ash/system/chromeos/network/network_state_notifier.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "ash/system/tray/system_tray_notifier.h"
@@ -23,9 +22,13 @@
 #include "chromeos/network/network_profile_handler.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
+#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
 
 using chromeos::DeviceState;
 using chromeos::NetworkConfigurationHandler;
@@ -34,6 +37,7 @@
 using chromeos::NetworkProfile;
 using chromeos::NetworkProfileHandler;
 using chromeos::NetworkState;
+using chromeos::NetworkStateHandler;
 
 namespace ash {
 
@@ -62,6 +66,9 @@
                      scoped_ptr<base::DictionaryValue> error_data) {
   NET_LOG_ERROR("Connect Failed: " + error_name, service_path);
 
+  if (!ash::Shell::HasInstance())
+    return;
+
   // If a new connect attempt canceled this connect, no need to notify the user.
   if (error_name == NetworkConnectionHandler::kErrorConnectCanceled)
     return;
@@ -87,8 +94,7 @@
 
   if (error_name == NetworkConnectionHandler::kErrorConnected ||
       error_name == NetworkConnectionHandler::kErrorConnecting) {
-    ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(
-        service_path);
+    network_connect::ShowNetworkSettings(service_path);
     return;
   }
 
@@ -112,8 +118,10 @@
 
 void OnConnectSucceeded(const std::string& service_path) {
   NET_LOG_USER("Connect Succeeded", service_path);
-  ash::Shell::GetInstance()->system_tray_notifier()->NotifyClearNetworkMessage(
-      NetworkObserver::ERROR_CONNECT_FAILED);
+  if (!ash::Shell::HasInstance())
+    return;
+  message_center::MessageCenter::Get()->RemoveNotification(
+      network_connect::kNetworkConnectNotificationId, false /* not by user */);
 }
 
 // If |check_error_state| is true, error state for the network is checked,
@@ -124,10 +132,10 @@
 void CallConnectToNetwork(const std::string& service_path,
                           bool check_error_state,
                           gfx::NativeWindow owning_window) {
-  NET_LOG_USER("ConnectToNetwork", service_path);
-
-  ash::Shell::GetInstance()->system_tray_notifier()->NotifyClearNetworkMessage(
-      NetworkObserver::ERROR_CONNECT_FAILED);
+  if (!ash::Shell::HasInstance())
+    return;
+  message_center::MessageCenter::Get()->RemoveNotification(
+      network_connect::kNetworkConnectNotificationId, false /* not by user */);
 
   NetworkHandler::Get()->network_connection_handler()->ConnectToNetwork(
       service_path,
@@ -246,33 +254,102 @@
 
 namespace network_connect {
 
+const char kNetworkConnectNotificationId[] =
+    "chrome://settings/internet/connect";
+const char kNetworkActivateNotificationId[] =
+    "chrome://settings/internet/activate";
+
 void ConnectToNetwork(const std::string& service_path,
                       gfx::NativeWindow owning_window) {
+  NET_LOG_USER("ConnectToNetwork", service_path);
+  const NetworkState* network =
+      NetworkHandler::Get()->network_state_handler()->
+      GetNetworkState(service_path);
+  if (network && !network->error().empty()) {
+    NET_LOG_USER("Configure: " + network->error(), service_path);
+    // If the network is in an error state, show the configuration UI directly
+    // to avoid a spurious notification.
+    ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork(
+        service_path);
+    return;
+  }
   const bool check_error_state = true;
   CallConnectToNetwork(service_path, check_error_state, owning_window);
 }
 
+void SetTechnologyEnabled(const std::string& technology, bool enabled_state) {
+  std::string log_string =
+      base::StringPrintf("technology %s, target state: %s",
+                         technology.c_str(),
+                         (enabled_state ? "ENABLED" : "DISABLED"));
+  NET_LOG_USER("SetTechnologyEnabled", log_string);
+  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
+  bool enabled = handler->IsTechnologyEnabled(technology);
+  if (enabled_state == enabled) {
+    NET_LOG_USER("Technology already in target state.", log_string);
+    return;
+  }
+  if (enabled) {
+    // User requested to disable the technology.
+    handler->SetTechnologyEnabled(
+        technology, false, chromeos::network_handler::ErrorCallback());
+    return;
+  }
+  // If we're dealing with a mobile network, then handle SIM lock here.
+  // SIM locking only applies to cellular, so the code below won't execute
+  // if |technology| has been explicitly set to WiMAX.
+  if (technology == NetworkStateHandler::kMatchTypeMobile ||
+      technology == flimflam::kTypeCellular) {
+    const DeviceState* mobile = handler->GetDeviceStateByType(technology);
+    if (!mobile) {
+      NET_LOG_ERROR("SetTechnologyEnabled with no device", log_string);
+      return;
+    }
+    // The following only applies to cellular.
+    if (mobile->type() == flimflam::kTypeCellular) {
+      if (mobile->IsSimAbsent()) {
+        // If this is true, then we have a cellular device with no SIM inserted.
+        // TODO(armansito): Chrome should display a notification here, prompting
+        // the user to insert a SIM card and restart the device to enable
+        // cellular. See crbug.com/125171.
+        NET_LOG_USER("Cannot enable cellular device without SIM.", log_string);
+        return;
+      }
+      if (!mobile->sim_lock_type().empty()) {
+        // A SIM has been inserted, but it is locked. Let the user unlock it
+        // via the dialog.
+        ash::Shell::GetInstance()->system_tray_delegate()->
+            ShowMobileSimDialog();
+        return;
+      }
+    }
+  }
+  handler->SetTechnologyEnabled(
+    technology, true, chromeos::network_handler::ErrorCallback());
+}
+
 void ActivateCellular(const std::string& service_path) {
   NET_LOG_USER("ActivateCellular", service_path);
+  const NetworkState* cellular =
+      NetworkHandler::Get()->network_state_handler()->
+      GetNetworkState(service_path);
+  if (!cellular || cellular->type() != flimflam::kTypeCellular) {
+    NET_LOG_ERROR("ActivateCellular with no Service", service_path);
+    return;
+  }
   const DeviceState* cellular_device =
       NetworkHandler::Get()->network_state_handler()->
-      GetDeviceStateByType(flimflam::kTypeCellular);
+      GetDeviceState(cellular->device_path());
   if (!cellular_device) {
     NET_LOG_ERROR("ActivateCellular with no Device", service_path);
     return;
   }
   if (!IsDirectActivatedCarrier(cellular_device->carrier())) {
     // For non direct activation, show the mobile setup dialog which can be
-    // used to activate the network.
-    ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSetup(
-        service_path);
-    return;
-  }
-  const NetworkState* cellular =
-      NetworkHandler::Get()->network_state_handler()->
-      GetNetworkState(service_path);
-  if (!cellular || cellular->type() != flimflam::kTypeCellular) {
-    NET_LOG_ERROR("ActivateCellular with no Service", service_path);
+    // used to activate the network. Only show the dialog, if an account
+    // management URL is available.
+    if (!cellular->payment_url().empty())
+      ShowMobileSetup(service_path);
     return;
   }
   if (cellular->activation_state() == flimflam::kActivationStateActivated) {
@@ -287,6 +364,32 @@
       base::Bind(&OnActivateFailed, service_path));
 }
 
+void ShowMobileSetup(const std::string& service_path) {
+  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
+  const NetworkState* cellular = handler->GetNetworkState(service_path);
+  if (!cellular || cellular->type() != flimflam::kTypeCellular) {
+    NET_LOG_ERROR("ShowMobileSetup without Cellular network", service_path);
+    return;
+  }
+  if (cellular->activation_state() != flimflam::kActivationStateActivated &&
+      cellular->activate_over_non_cellular_networks() &&
+      !handler->DefaultNetwork()) {
+    message_center::MessageCenter::Get()->AddNotification(
+        message_center::Notification::CreateSystemNotification(
+            kNetworkActivateNotificationId,
+            l10n_util::GetStringUTF16(IDS_NETWORK_ACTIVATION_ERROR_TITLE),
+            l10n_util::GetStringFUTF16(IDS_NETWORK_ACTIVATION_NEEDS_CONNECTION,
+                                       UTF8ToUTF16(cellular->name())),
+            ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+                IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED),
+            base::Bind(&ash::network_connect::ShowNetworkSettings,
+                       service_path)));
+    return;
+  }
+  ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSetupDialog(
+      service_path);
+}
+
 void ConfigureNetworkAndConnect(const std::string& service_path,
                                 const base::DictionaryValue& properties,
                                 bool shared) {
@@ -393,5 +496,12 @@
                                     UTF8ToUTF16(error));
 }
 
+void ShowNetworkSettings(const std::string& service_path) {
+  if (!ash::Shell::HasInstance())
+    return;
+  ash::Shell::GetInstance()->system_tray_delegate()->ShowNetworkSettings(
+      service_path);
+}
+
 }  // network_connect
 }  // ash
diff --git a/ash/system/chromeos/network/network_connect.h b/ash/system/chromeos/network/network_connect.h
index 65c430d..eb7df2e 100644
--- a/ash/system/chromeos/network/network_connect.h
+++ b/ash/system/chromeos/network/network_connect.h
@@ -18,15 +18,28 @@
 namespace ash {
 namespace network_connect {
 
+ASH_EXPORT extern const char kNetworkConnectNotificationId[];
+ASH_EXPORT extern const char kNetworkActivateNotificationId[];
+
 // Requests a network connection and handles any errors and notifications.
 // |owning_window| is used to parent any UI on failure (e.g. for certificate
 // enrollment). If NULL, the default window will be used.
 ASH_EXPORT void ConnectToNetwork(const std::string& service_path,
                                  gfx::NativeWindow owning_window);
 
+// Enables or disables a network technology. If |technology| refers to cellular
+// and the device cannot be enabled due to a SIM lock, this function will
+// launch the SIM unlock dialog.
+ASH_EXPORT void SetTechnologyEnabled(const std::string& technology,
+                                     bool enabled_state);
+
 // Requests network activation and handles any errors and notifications.
 ASH_EXPORT void ActivateCellular(const std::string& service_path);
 
+// Determines whether or not a network requires a connection to activate or
+// setup and either shows a notification or opens the mobile setup dialog.
+ASH_EXPORT void ShowMobileSetup(const std::string& service_path);
+
 // Configures a network with a dictionary of Shill properties, then sends a
 // connect request. The profile is set according to 'shared' if allowed.
 ASH_EXPORT void ConfigureNetworkAndConnect(
@@ -42,6 +55,10 @@
 // Returns the localized string for shill error string |error|.
 ASH_EXPORT base::string16 ErrorString(const std::string& error);
 
+// Shows the settings for the network specified by |service_path|. If empty,
+// or no matching network exists, shows the general internet settings page.
+ASH_EXPORT void ShowNetworkSettings(const std::string& service_path);
+
 }  // network_connect
 }  // ash
 
diff --git a/ash/system/chromeos/network/network_observer.cc b/ash/system/chromeos/network/network_observer.cc
deleted file mode 100644
index 09f4f45..0000000
--- a/ash/system/chromeos/network/network_observer.cc
+++ /dev/null
@@ -1,35 +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 "ash/system/chromeos/network/network_observer.h"
-
-#include "chromeos/network/network_state.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
-
-namespace ash {
-
-//static
-NetworkObserver::NetworkType NetworkObserver::GetNetworkTypeForNetworkState(
-    const chromeos::NetworkState* network) {
-  if (!network)
-    return NETWORK_UNKNOWN;
-  const std::string& type = network->type();
-  if (type == flimflam::kTypeCellular) {
-    const std::string& technology = network->network_technology();
-    if (technology == flimflam::kNetworkTechnologyLte ||
-        technology == flimflam::kNetworkTechnologyLteAdvanced)
-      return NETWORK_CELLULAR_LTE;
-    else
-      return NETWORK_CELLULAR;
-  }
-  if (type == flimflam::kTypeEthernet)
-     return NETWORK_ETHERNET;
-  if (type == flimflam::kTypeWifi)
-     return NETWORK_WIFI;
-  if (type == flimflam::kTypeBluetooth)
-     return NETWORK_BLUETOOTH;
-  return NETWORK_UNKNOWN;
-}
-
-}  // namespace ash
diff --git a/ash/system/chromeos/network/network_observer.h b/ash/system/chromeos/network/network_observer.h
index cff0c69..20473c7 100644
--- a/ash/system/chromeos/network/network_observer.h
+++ b/ash/system/chromeos/network/network_observer.h
@@ -9,59 +9,16 @@
 
 #include "base/strings/string16.h"
 
-namespace chromeos {
-class NetworkState;
-}
-
 namespace ash {
 
-struct NetworkIconInfo;
-class NetworkTrayDelegate;
-
 class NetworkObserver {
  public:
-  enum MessageType {
-    // Priority order, highest to lowest.
-    ERROR_CONNECT_FAILED,
-    ERROR_OUT_OF_CREDITS,
-    MESSAGE_DATA_PROMO,
-  };
-
-  enum NetworkType {
-    // ash relevant subset of network_constants.h connection type.
-    NETWORK_ETHERNET,
-    NETWORK_CELLULAR,
-    NETWORK_CELLULAR_LTE,
-    NETWORK_WIFI,
-    NETWORK_BLUETOOTH,
-    NETWORK_UNKNOWN,
-  };
-
   virtual ~NetworkObserver() {}
 
-  // Sets a network message notification.
-  // |message_type| identifies the type of message.
-  // |network_type| identifies the type of network involved.
-  // |delegate|->NotificationLinkClicked() will be called if any of the
-  // |links| are clicked (if supplied, |links| may be empty).
-  virtual void SetNetworkMessage(NetworkTrayDelegate* delegate,
-                                 MessageType message_type,
-                                 NetworkType network_type,
-                                 const base::string16& title,
-                                 const base::string16& message,
-                                 const std::vector<base::string16>& links) = 0;
-
-  // Clears the message notification for |message_type|.
-  virtual void ClearNetworkMessage(MessageType message_type) = 0;
-
   // Called to request toggling Wi-Fi enable/disable, e.g. from an accelerator.
   // NOTE: Toggling is asynchronous and subsequent calls to query the current
   // state may return the old value.
   virtual void RequestToggleWifi() = 0;
-
-  // Helper function to get the network type from NetworkState.
-  static NetworkType GetNetworkTypeForNetworkState(
-      const chromeos::NetworkState* network);
 };
 
 }  // namespace ash
diff --git a/ash/system/chromeos/network/network_state_list_detailed_view.cc b/ash/system/chromeos/network/network_state_list_detailed_view.cc
index 64e6d3b..03a181e 100644
--- a/ash/system/chromeos/network/network_state_list_detailed_view.cc
+++ b/ash/system/chromeos/network/network_state_list_detailed_view.cc
@@ -856,25 +856,8 @@
   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
   bool enabled =
       handler->IsTechnologyEnabled(NetworkStateHandler::kMatchTypeMobile);
-  if (enabled) {
-    handler->SetTechnologyEnabled(
-        NetworkStateHandler::kMatchTypeMobile, false,
-        chromeos::network_handler::ErrorCallback());
-  } else {
-    const DeviceState* mobile =
-        handler->GetDeviceStateByType(NetworkStateHandler::kMatchTypeMobile);
-    if (!mobile) {
-      LOG(ERROR) << "Mobile device not found.";
-      return;
-    }
-    if (!mobile->sim_lock_type().empty() || mobile->IsSimAbsent()) {
-      ash::Shell::GetInstance()->system_tray_delegate()->ShowMobileSimDialog();
-    } else {
-      handler->SetTechnologyEnabled(
-          NetworkStateHandler::kMatchTypeMobile, true,
-          chromeos::network_handler::ErrorCallback());
-    }
-  }
+  ash::network_connect::SetTechnologyEnabled(
+      NetworkStateHandler::kMatchTypeMobile, !enabled);
 }
 
 }  // namespace tray
diff --git a/ash/system/chromeos/network/network_state_notifier.cc b/ash/system/chromeos/network/network_state_notifier.cc
index 1c971a3..dbd8702 100644
--- a/ash/system/chromeos/network/network_state_notifier.cc
+++ b/ash/system/chromeos/network/network_state_notifier.cc
@@ -6,18 +6,22 @@
 
 #include "ash/shell.h"
 #include "ash/system/chromeos/network/network_connect.h"
-#include "ash/system/chromeos/network/network_observer.h"
-#include "ash/system/tray/system_tray_notifier.h"
+#include "ash/system/tray/system_tray_delegate.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chromeos/network/network_configuration_handler.h"
 #include "chromeos/network/network_connection_handler.h"
 #include "chromeos/network/network_event_log.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
+#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
 
 using chromeos::NetworkConnectionHandler;
 using chromeos::NetworkHandler;
@@ -26,6 +30,9 @@
 
 namespace {
 
+const char kNetworkOutOfCreditsNotificationId[] =
+    "chrome://settings/internet/out-of-credits";
+
 const int kMinTimeBetweenOutOfCreditsNotifySeconds = 10 * 60;
 
 // Error messages based on |error_name|, not network_state->error().
@@ -41,21 +48,38 @@
   return string16();
 }
 
+void ShowErrorNotification(const std::string& notification_id,
+                           const std::string& network_type,
+                           const base::string16& title,
+                           const base::string16& message,
+                           const base::Closure& callback) {
+  int icon_id = (network_type == flimflam::kTypeCellular) ?
+      IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED :
+      IDR_AURA_UBER_TRAY_NETWORK_FAILED;
+  const gfx::Image& icon =
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
+  message_center::MessageCenter::Get()->AddNotification(
+      message_center::Notification::CreateSystemNotification(
+          notification_id, title, message, icon, callback));
+}
+
+void ConfigureNetwork(const std::string& service_path) {
+  ash::Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork(
+      service_path);
+}
+
 }  // namespace
 
 namespace ash {
 
 NetworkStateNotifier::NetworkStateNotifier()
-    : cellular_out_of_credits_(false) {
+    : did_show_out_of_credits_(false),
+      weak_ptr_factory_(this) {
   if (!NetworkHandler::IsInitialized())
     return;
-  NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
-
-  // Initialize |last_active_network_|.
-  const NetworkState* default_network =
-      NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
-  if (default_network && default_network->IsConnectedState())
-    last_active_network_ = default_network->path();
+  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
+  handler->AddObserver(this, FROM_HERE);
+  UpdateDefaultNetwork(handler->DefaultNetwork());
 }
 
 NetworkStateNotifier::~NetworkStateNotifier() {
@@ -65,120 +89,184 @@
       this, FROM_HERE);
 }
 
-void NetworkStateNotifier::NetworkListChanged() {
-  // Trigger any pending connect failed error if the network list changes
-  // (which indicates all NetworkState entries are up to date). This is in
-  // case a connect attempt fails because a network is no longer visible.
-  if (!connect_failed_network_.empty()) {
-    ShowNetworkConnectError(
-        NetworkConnectionHandler::kErrorConnectFailed, connect_failed_network_);
-  }
-}
-
 void NetworkStateNotifier::DefaultNetworkChanged(const NetworkState* network) {
-  if (!network || !network->IsConnectedState())
+  if (!UpdateDefaultNetwork(network))
     return;
-  if (network->path() != last_active_network_) {
-    last_active_network_ = network->path();
-    // Reset state for new connected network
-    cellular_out_of_credits_ = false;
-  }
+  // If the default network changes to another network, allow the out of
+  // credits notification to be shown again. A delay prevents the notification
+  // from being shown too frequently (see below).
+  if (network)
+    did_show_out_of_credits_ = false;
 }
 
 void NetworkStateNotifier::NetworkPropertiesUpdated(
     const NetworkState* network) {
-  DCHECK(network);
-  // Trigger a pending connect failed error for |network| when the Error
-  // property has been set.
-  if (network->path() == connect_failed_network_ && !network->error().empty()) {
-    ShowNetworkConnectError(
-        NetworkConnectionHandler::kErrorConnectFailed, connect_failed_network_);
+  if (network->type() != flimflam::kTypeCellular)
+    return;
+  UpdateCellularOutOfCredits(network);
+  UpdateCellularActivating(network);
+}
+
+bool NetworkStateNotifier::UpdateDefaultNetwork(const NetworkState* network) {
+  std::string default_network_path;
+  if (network)
+    default_network_path = network->path();
+  if (default_network_path != last_default_network_) {
+    last_default_network_ = default_network_path;
+    return true;
   }
-  // Trigger "Out of credits" notification if the cellular network is the most
-  // recent default network (i.e. we have not switched to another network).
-  if (network->type() == flimflam::kTypeCellular &&
-      network->path() == last_active_network_) {
-    cellular_network_ = network->path();
-    if (network->cellular_out_of_credits() &&
-        !cellular_out_of_credits_) {
-      cellular_out_of_credits_ = true;
-      base::TimeDelta dtime = base::Time::Now() - out_of_credits_notify_time_;
-      if (dtime.InSeconds() > kMinTimeBetweenOutOfCreditsNotifySeconds) {
-        out_of_credits_notify_time_ = base::Time::Now();
-        std::vector<string16> links;
-        links.push_back(
-            l10n_util::GetStringFUTF16(IDS_NETWORK_OUT_OF_CREDITS_LINK,
-                                       UTF8ToUTF16(network->name())));
-        ash::Shell::GetInstance()->system_tray_notifier()->
-            NotifySetNetworkMessage(
-                this,
-                NetworkObserver::ERROR_OUT_OF_CREDITS,
-                NetworkObserver::GetNetworkTypeForNetworkState(network),
-                l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE),
-                l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_BODY),
-                links);
-      }
-    }
+  return false;
+}
+
+void NetworkStateNotifier::UpdateCellularOutOfCredits(
+    const NetworkState* cellular) {
+  // Only display a notification if we are out of credits and have not already
+  // shown a notification (or have since connected to another network type).
+  if (!cellular->cellular_out_of_credits() || did_show_out_of_credits_)
+    return;
+
+  // Only display a notification if not connected, connecting, or waiting to
+  // connect to another network.
+  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
+  const NetworkState* default_network = handler->DefaultNetwork();
+  if (default_network && default_network != cellular)
+    return;
+  if (handler->ConnectingNetworkByType(
+          NetworkStateHandler::kMatchTypeNonVirtual) ||
+      NetworkHandler::Get()->network_connection_handler()
+          ->HasPendingConnectRequest())
+    return;
+
+  did_show_out_of_credits_ = true;
+  base::TimeDelta dtime = base::Time::Now() - out_of_credits_notify_time_;
+  if (dtime.InSeconds() > kMinTimeBetweenOutOfCreditsNotifySeconds) {
+    out_of_credits_notify_time_ = base::Time::Now();
+    string16 error_msg = l10n_util::GetStringFUTF16(
+        IDS_NETWORK_OUT_OF_CREDITS_BODY,
+        UTF8ToUTF16(cellular->name()));
+    ShowErrorNotification(
+        kNetworkOutOfCreditsNotificationId,
+        cellular->type(),
+        l10n_util::GetStringUTF16(IDS_NETWORK_OUT_OF_CREDITS_TITLE),
+        error_msg,
+        base::Bind(&ConfigureNetwork, cellular->path()));
   }
 }
 
-void NetworkStateNotifier::NotificationLinkClicked(
-    NetworkObserver::MessageType message_type,
-    size_t link_index) {
-  if (message_type == NetworkObserver::ERROR_OUT_OF_CREDITS) {
-    if (!cellular_network_.empty()) {
-      // This will trigger the activation / portal code.
-      Shell::GetInstance()->system_tray_delegate()->ConfigureNetwork(
-          cellular_network_);
-    }
-    ash::Shell::GetInstance()->system_tray_notifier()->
-        NotifyClearNetworkMessage(message_type);
+void NetworkStateNotifier::UpdateCellularActivating(
+    const NetworkState* cellular) {
+  // Keep track of any activating cellular network.
+  std::string activation_state = cellular->activation_state();
+  if (activation_state == flimflam::kActivationStateActivating) {
+    cellular_activating_.insert(cellular->path());
+    return;
   }
+  // Only display a notification if this network was activating and is now
+  // activated.
+  if (!cellular_activating_.count(cellular->path()) ||
+      activation_state != flimflam::kActivationStateActivated)
+    return;
+
+  cellular_activating_.erase(cellular->path());
+  int icon_id;
+  if (cellular->network_technology() == flimflam::kNetworkTechnologyLte)
+    icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_LTE;
+  else
+    icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_3G;
+  const gfx::Image& icon =
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
+  message_center::MessageCenter::Get()->AddNotification(
+      message_center::Notification::CreateSystemNotification(
+          ash::network_connect::kNetworkActivateNotificationId,
+          l10n_util::GetStringUTF16(IDS_NETWORK_CELLULAR_ACTIVATED_TITLE),
+          l10n_util::GetStringFUTF16(IDS_NETWORK_CELLULAR_ACTIVATED,
+                                     UTF8ToUTF16((cellular->name()))),
+          icon,
+          base::Bind(&ash::network_connect::ShowNetworkSettings,
+                     cellular->path())));
 }
 
 void NetworkStateNotifier::ShowNetworkConnectError(
     const std::string& error_name,
     const std::string& service_path) {
-  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
-      GetNetworkState(service_path);
-  if (error_name == NetworkConnectionHandler::kErrorConnectFailed &&
-      service_path != connect_failed_network_) {
-    // Shill may not have set the Error property yet. First request an update
-    // and wait for either the update to complete or the network list to be
-    // updated before displaying the error.
-    connect_failed_network_ = service_path;
+  if (service_path.empty()) {
+    base::DictionaryValue shill_properties;
+    ShowConnectErrorNotification(error_name, service_path, shill_properties);
     return;
   }
-  connect_failed_network_.clear();
+  // Get the up-to-date properties for the network and display the error.
+  NetworkHandler::Get()->network_configuration_handler()->GetProperties(
+      service_path,
+      base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesSucceeded,
+                 weak_ptr_factory_.GetWeakPtr(), error_name),
+      base::Bind(&NetworkStateNotifier::ConnectErrorPropertiesFailed,
+                 weak_ptr_factory_.GetWeakPtr(), error_name, service_path));
+}
 
+void NetworkStateNotifier::ConnectErrorPropertiesSucceeded(
+    const std::string& error_name,
+    const std::string& service_path,
+    const base::DictionaryValue& shill_properties) {
+  ShowConnectErrorNotification(error_name, service_path, shill_properties);
+}
+
+void NetworkStateNotifier::ConnectErrorPropertiesFailed(
+    const std::string& error_name,
+    const std::string& service_path,
+    const std::string& shill_error_name,
+    scoped_ptr<base::DictionaryValue> shill_error_data) {
+  base::DictionaryValue shill_properties;
+  ShowConnectErrorNotification(error_name, service_path, shill_properties);
+}
+
+void NetworkStateNotifier::ShowConnectErrorNotification(
+    const std::string& error_name,
+    const std::string& service_path,
+    const base::DictionaryValue& shill_properties) {
   string16 error = GetConnectErrorString(error_name);
-  if (error.empty() && network)
-    error = network_connect::ErrorString(network->error());
-  if (error.empty())
-    error = l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
+  if (error.empty()) {
+    std::string network_error;
+    shill_properties.GetStringWithoutPathExpansion(
+        flimflam::kErrorProperty, &network_error);
+    error = network_connect::ErrorString(network_error);
+    if (error.empty())
+      error = l10n_util::GetStringUTF16(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
+  }
   NET_LOG_ERROR("Connect error notification: " + UTF16ToUTF8(error),
                 service_path);
 
-  std::string name = network ? network->name() : "";
+  std::string network_name =
+      NetworkState::GetNameFromProperties(service_path, shill_properties);
+  std::string network_error_details;
+  shill_properties.GetStringWithoutPathExpansion(
+        shill::kErrorDetailsProperty, &network_error_details);
+
   string16 error_msg;
-  if (network && !network->error_details().empty()) {
+  if (!network_error_details.empty()) {
+    // network_name should't be empty if network_error_details is set.
     error_msg = l10n_util::GetStringFUTF16(
         IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_SERVER_MESSAGE,
-        UTF8ToUTF16(name), error, UTF8ToUTF16(network->error_details()));
+        UTF8ToUTF16(network_name), error,
+        UTF8ToUTF16(network_error_details));
+  } else if (network_name.empty()) {
+    error_msg = l10n_util::GetStringFUTF16(
+        IDS_NETWORK_CONNECTION_ERROR_MESSAGE_NO_NAME, error);
   } else {
     error_msg = l10n_util::GetStringFUTF16(
-        IDS_NETWORK_CONNECTION_ERROR_MESSAGE_WITH_DETAILS,
-        UTF8ToUTF16(name), error);
+        IDS_NETWORK_CONNECTION_ERROR_MESSAGE,
+        UTF8ToUTF16(network_name), error);
   }
 
-  std::vector<string16> no_links;
-  ash::Shell::GetInstance()->system_tray_notifier()->NotifySetNetworkMessage(
-      this,
-      NetworkObserver::ERROR_CONNECT_FAILED,
-      NetworkObserver::GetNetworkTypeForNetworkState(network),
+  std::string network_type;
+  shill_properties.GetStringWithoutPathExpansion(
+      flimflam::kTypeProperty, &network_type);
+
+  ShowErrorNotification(
+      network_connect::kNetworkConnectNotificationId,
+      network_type,
       l10n_util::GetStringUTF16(IDS_NETWORK_CONNECTION_ERROR_TITLE),
       error_msg,
-      no_links);
+      base::Bind(&network_connect::ShowNetworkSettings, service_path));
 }
 
 }  // namespace ash
diff --git a/ash/system/chromeos/network/network_state_notifier.h b/ash/system/chromeos/network/network_state_notifier.h
index 30a41b3..612dfbf 100644
--- a/ash/system/chromeos/network/network_state_notifier.h
+++ b/ash/system/chromeos/network/network_state_notifier.h
@@ -5,15 +5,20 @@
 #ifndef ASH_SYSTEM_CHROMEOS_NETWORK_NETWORK_STATE_NOTIFIER_H_
 #define ASH_SYSTEM_CHROMEOS_NETWORK_NETWORK_STATE_NOTIFIER_H_
 
-#include <map>
+#include <set>
 
 #include "ash/ash_export.h"
-#include "ash/system/chromeos/network/network_tray_delegate.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "chromeos/network/network_state_handler_observer.h"
 
+namespace base {
+class DictionaryValue;
+}
+
 namespace chromeos {
 class NetworkState;
 }
@@ -23,47 +28,57 @@
 // This class has two purposes:
 // 1. ShowNetworkConnectError() gets called after any user initiated connect
 //    failure. This will handle displaying an error notification.
-//    NOTE: Because Shill sets the Error property of a Service *after*
-//    the Connect call fails, this class will delay the notification if
-//    necessary until the Error property is set so that the correct
-//    message can be displayed.
 //    TODO(stevenjb): convert this class to use the new MessageCenter
-//    notification system, generate a notification immediately, and update
-//    it when the Error property is set to guarantee that a notification is
-//    displayed for every failure.
+//    notification system.
 // 2. It observes NetworkState changes to generate notifications when a
 //    Cellular network is out of credits.
 class ASH_EXPORT NetworkStateNotifier :
-      public chromeos::NetworkStateHandlerObserver,
-      public NetworkTrayDelegate {
+      public chromeos::NetworkStateHandlerObserver {
  public:
   NetworkStateNotifier();
   virtual ~NetworkStateNotifier();
 
   // NetworkStateHandlerObserver
-  virtual void NetworkListChanged() OVERRIDE;
   virtual void DefaultNetworkChanged(
       const chromeos::NetworkState* network) OVERRIDE;
   virtual void NetworkPropertiesUpdated(
       const chromeos::NetworkState* network) OVERRIDE;
 
-  // NetworkTrayDelegate
-  virtual void NotificationLinkClicked(
-      NetworkObserver::MessageType message_type,
-      size_t link_index) OVERRIDE;
-
-  // Show a connection error notification.
+  // Show a connection error notification. If |error_name| matches an error
+  // defined in NetworkConnectionHandler for connect, configure, or activation
+  // failed, then the associated message is shown, otherwise the Shill
+  // error for Service.Error is used (from network_connect::ErrorString), or
+  // "Unknown network error".
   void ShowNetworkConnectError(const std::string& error_name,
                                const std::string& service_path);
 
  private:
-  typedef std::map<std::string, std::string> CachedStateMap;
+  void ConnectErrorPropertiesSucceeded(
+      const std::string& error_name,
+      const std::string& service_path,
+      const base::DictionaryValue& shill_properties);
+  void ConnectErrorPropertiesFailed(
+      const std::string& error_name,
+      const std::string& service_path,
+      const std::string& shill_error_name,
+      scoped_ptr<base::DictionaryValue> shill_error_data);
+  void ShowConnectErrorNotification(
+      const std::string& error_name,
+      const std::string& service_path,
+      const base::DictionaryValue& shill_properties);
 
-  std::string last_active_network_;
-  std::string cellular_network_;
-  std::string connect_failed_network_;
-  bool cellular_out_of_credits_;
+  // Returns true if the default network changed.
+  bool UpdateDefaultNetwork(const chromeos::NetworkState* network);
+
+  // Helper methods to update state and check for notifications.
+  void UpdateCellularOutOfCredits(const chromeos::NetworkState* cellular);
+  void UpdateCellularActivating(const chromeos::NetworkState* cellular);
+
+  std::string last_default_network_;
+  bool did_show_out_of_credits_;
   base::Time out_of_credits_notify_time_;
+  std::set<std::string> cellular_activating_;
+  base::WeakPtrFactory<NetworkStateNotifier> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkStateNotifier);
 };
diff --git a/ash/system/chromeos/network/network_state_notifier_unittest.cc b/ash/system/chromeos/network/network_state_notifier_unittest.cc
index 6e2069d..4743f0a 100644
--- a/ash/system/chromeos/network/network_state_notifier_unittest.cc
+++ b/ash/system/chromeos/network/network_state_notifier_unittest.cc
@@ -14,8 +14,8 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_device_client.h"
 #include "chromeos/dbus/shill_service_client.h"
-#include "chromeos/network/network_connection_handler.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
+#include "ui/message_center/message_center.h"
 
 namespace {
 
@@ -27,8 +27,6 @@
 }  // namespace
 
 using chromeos::DBusThreadManager;
-using chromeos::NetworkHandler;
-using chromeos::NetworkConnectionHandler;
 using chromeos::ShillDeviceClient;
 using chromeos::ShillServiceClient;
 
@@ -43,14 +41,12 @@
   virtual void SetUp() OVERRIDE {
     DBusThreadManager::InitializeWithStub();
     SetupDefaultShillState();
-    NetworkHandler::Initialize();
     RunAllPendingInMessageLoop();
     AshTestBase::SetUp();
   }
 
   virtual void TearDown() OVERRIDE {
     AshTestBase::TearDown();
-    NetworkHandler::Shutdown();
     DBusThreadManager::Shutdown();
   }
 
@@ -95,7 +91,10 @@
   ash::network_connect::ConnectToNetwork("wifi1", NULL /* owning_window */);
   RunAllPendingInMessageLoop();
   // Failure should spawn a notification.
-  EXPECT_TRUE(GetSystemTray()->CloseNotificationBubbleForTest());
+  message_center::MessageCenter* message_center =
+      message_center::MessageCenter::Get();
+  EXPECT_TRUE(message_center->HasNotification(
+      network_connect::kNetworkConnectNotificationId));
 }
 
 }  // namespace test
diff --git a/ash/system/chromeos/network/network_tray_delegate.h b/ash/system/chromeos/network/network_tray_delegate.h
deleted file mode 100644
index 0ce5402..0000000
--- a/ash/system/chromeos/network/network_tray_delegate.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_SYSTEM_CHROMEOS_NETWORK_NETWORK_TRAY_DELEGATE_H
-#define ASH_SYSTEM_CHROMEOS_NETWORK_NETWORK_TRAY_DELEGATE_H
-
-#include "ash/system/chromeos/network/network_observer.h"
-
-namespace ash {
-
-class NetworkTrayDelegate {
- public:
-  virtual ~NetworkTrayDelegate() {}
-
-  // Notifies that the |index|-th link on the notification is clicked.
-  virtual void NotificationLinkClicked(
-      NetworkObserver::MessageType message_type,
-      size_t link_index) = 0;
-};
-
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_CHROMEOS_NETWORK_NETWORK_TRAY_DELEGATE_H
diff --git a/ash/system/chromeos/network/sms_observer.h b/ash/system/chromeos/network/sms_observer.h
deleted file mode 100644
index bc54967..0000000
--- a/ash/system/chromeos/network/sms_observer.h
+++ /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.
-
-#ifndef ASH_SYSTEM_CHROMEOS_NETWORK_SMS_OBSERVER_H
-#define ASH_SYSTEM_CHROMEOS_NETWORK_SMS_OBSERVER_H
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace ash {
-
-const char kSmsNumberKey[] = "number";
-const char kSmsTextKey[] = "text";
-
-class SmsObserver {
- public:
-  virtual ~SmsObserver() {}
-
-  virtual void AddMessage(const base::DictionaryValue& message) = 0;
-};
-
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_CHROMEOS_NETWORK_SMS_OBSERVER_H
diff --git a/ash/system/chromeos/network/tray_network.cc b/ash/system/chromeos/network/tray_network.cc
index e8c1683..e4a5fb1 100644
--- a/ash/system/chromeos/network/tray_network.cc
+++ b/ash/system/chromeos/network/tray_network.cc
@@ -8,7 +8,6 @@
 #include "ash/shell.h"
 #include "ash/system/chromeos/network/network_icon_animation.h"
 #include "ash/system/chromeos/network/network_state_list_detailed_view.h"
-#include "ash/system/chromeos/network/network_tray_delegate.h"
 #include "ash/system/chromeos/network/tray_network_state_observer.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_delegate.h"
@@ -16,7 +15,6 @@
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_item_more.h"
 #include "ash/system/tray/tray_item_view.h"
-#include "ash/system/tray/tray_notification_view.h"
 #include "ash/system/tray/tray_utils.h"
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
@@ -41,60 +39,8 @@
 namespace ash {
 namespace internal {
 
-namespace {
-
-int GetMessageIcon(NetworkObserver::MessageType message_type,
-                   NetworkObserver::NetworkType network_type) {
-  switch(message_type) {
-    case NetworkObserver::ERROR_CONNECT_FAILED:
-      if (NetworkObserver::NETWORK_CELLULAR == network_type)
-        return IDR_AURA_UBER_TRAY_CELLULAR_NETWORK_FAILED;
-      else
-        return IDR_AURA_UBER_TRAY_NETWORK_FAILED;
-    case NetworkObserver::ERROR_OUT_OF_CREDITS:
-    case NetworkObserver::MESSAGE_DATA_PROMO:
-      if (network_type == TrayNetwork::NETWORK_CELLULAR_LTE)
-        return IDR_AURA_UBER_TRAY_NOTIFICATION_LTE;
-      else
-        return IDR_AURA_UBER_TRAY_NOTIFICATION_3G;
-  }
-  NOTREACHED();
-  return 0;
-}
-
-}  // namespace
-
 namespace tray {
 
-class NetworkMessages {
- public:
-  struct Message {
-    Message() : delegate(NULL) {}
-    Message(NetworkTrayDelegate* in_delegate,
-            NetworkObserver::NetworkType network_type,
-            const base::string16& in_title,
-            const base::string16& in_message,
-            const std::vector<base::string16>& in_links) :
-        delegate(in_delegate),
-        network_type_(network_type),
-        title(in_title),
-        message(in_message),
-        links(in_links) {}
-    NetworkTrayDelegate* delegate;
-    NetworkObserver::NetworkType network_type_;
-    base::string16 title;
-    base::string16 message;
-    std::vector<base::string16> links;
-  };
-  typedef std::map<NetworkObserver::MessageType, Message> MessageMap;
-
-  MessageMap& messages() { return messages_; }
-  const MessageMap& messages() const { return messages_; }
-
- private:
-  MessageMap messages_;
-};
-
 class NetworkTrayView : public TrayItemView,
                         public network_icon::AnimationObserver {
  public:
@@ -296,112 +242,6 @@
   DISALLOW_COPY_AND_ASSIGN(NetworkWifiDetailedView);
 };
 
-class NetworkMessageView : public views::View,
-                           public views::LinkListener {
- public:
-  NetworkMessageView(TrayNetwork* tray_network,
-                     NetworkObserver::MessageType message_type,
-                     const NetworkMessages::Message& network_msg)
-      : tray_network_(tray_network),
-        message_type_(message_type),
-        network_type_(network_msg.network_type_) {
-    SetLayoutManager(
-        new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
-
-    if (!network_msg.title.empty()) {
-      views::Label* title = new views::Label(network_msg.title);
-      title->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-      title->SetFont(title->font().DeriveFont(0, gfx::Font::BOLD));
-      AddChildView(title);
-    }
-
-    if (!network_msg.message.empty()) {
-      views::Label* message = new views::Label(network_msg.message);
-      message->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-      message->SetMultiLine(true);
-      message->SizeToFit(kTrayNotificationContentsWidth);
-      AddChildView(message);
-    }
-
-    if (!network_msg.links.empty()) {
-      for (size_t i = 0; i < network_msg.links.size(); ++i) {
-        views::Link* link = new views::Link(network_msg.links[i]);
-        link->set_id(i);
-        link->set_listener(this);
-        link->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-        link->SetMultiLine(true);
-        link->SizeToFit(kTrayNotificationContentsWidth);
-        AddChildView(link);
-      }
-    }
-  }
-
-  virtual ~NetworkMessageView() {
-  }
-
-  // Overridden from views::LinkListener.
-  virtual void LinkClicked(views::Link* source, int event_flags) OVERRIDE {
-    tray_network_->LinkClicked(message_type_, source->id());
-  }
-
-  NetworkObserver::MessageType message_type() const { return message_type_; }
-  NetworkObserver::NetworkType network_type() const { return network_type_; }
-
- private:
-  TrayNetwork* tray_network_;
-  NetworkObserver::MessageType message_type_;
-  NetworkObserver::NetworkType network_type_;
-
-  DISALLOW_COPY_AND_ASSIGN(NetworkMessageView);
-};
-
-class NetworkNotificationView : public TrayNotificationView {
- public:
-  explicit NetworkNotificationView(TrayNetwork* tray_network)
-      : TrayNotificationView(tray_network, 0),
-        tray_network_(tray_network) {
-    CreateMessageView();
-    InitView(network_message_view_);
-    SetIconImage(*ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-        GetMessageIcon(network_message_view_->message_type(),
-            network_message_view_->network_type())));
-  }
-
-  // Overridden from TrayNotificationView.
-  virtual void OnClose() OVERRIDE {
-    tray_network_->ClearNetworkMessage(network_message_view_->message_type());
-  }
-
-  virtual void OnClickAction() OVERRIDE {
-    if (network_message_view_->message_type() !=
-        TrayNetwork::MESSAGE_DATA_PROMO)
-      tray_network_->PopupDetailedView(0, true);
-  }
-
-  void Update() {
-    CreateMessageView();
-    UpdateViewAndImage(network_message_view_,
-        *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            GetMessageIcon(network_message_view_->message_type(),
-                network_message_view_->network_type())));
-  }
-
- private:
-  void CreateMessageView() {
-    // Display the first (highest priority) message.
-    CHECK(!tray_network_->messages()->messages().empty());
-    NetworkMessages::MessageMap::const_iterator iter =
-        tray_network_->messages()->messages().begin();
-    network_message_view_ =
-        new NetworkMessageView(tray_network_, iter->first, iter->second);
-  }
-
-  TrayNetwork* tray_network_;
-  tray::NetworkMessageView* network_message_view_;
-
-  DISALLOW_COPY_AND_ASSIGN(NetworkNotificationView);
-};
-
 }  // namespace tray
 
 TrayNetwork::TrayNetwork(SystemTray* system_tray)
@@ -409,8 +249,6 @@
       tray_(NULL),
       default_(NULL),
       detailed_(NULL),
-      notification_(NULL),
-      messages_(new tray::NetworkMessages()),
       request_wifi_view_(false) {
   network_state_observer_.reset(new TrayNetworkStateObserver(this));
   Shell::GetInstance()->system_tray_notifier()->AddNetworkObserver(this);
@@ -442,9 +280,6 @@
   CHECK(detailed_ == NULL);
   if (!chromeos::NetworkHandler::IsInitialized())
     return NULL;
-  // Clear any notifications when showing the detailed view.
-  messages_->messages().clear();
-  HideNotificationView();
   if (request_wifi_view_) {
     detailed_ = new tray::NetworkWifiDetailedView(this);
     request_wifi_view_ = false;
@@ -456,14 +291,6 @@
   return detailed_;
 }
 
-views::View* TrayNetwork::CreateNotificationView(user::LoginStatus status) {
-  CHECK(notification_ == NULL);
-  if (messages_->messages().empty())
-    return NULL;  // Message has already been cleared.
-  notification_ = new tray::NetworkNotificationView(this);
-  return notification_;
-}
-
 void TrayNetwork::DestroyTrayView() {
   tray_ = NULL;
 }
@@ -476,10 +303,6 @@
   detailed_ = NULL;
 }
 
-void TrayNetwork::DestroyNotificationView() {
-  notification_ = NULL;
-}
-
 void TrayNetwork::UpdateAfterLoginStatusChange(user::LoginStatus status) {
 }
 
@@ -488,34 +311,6 @@
     SetTrayImageItemBorder(tray_, alignment);
 }
 
-void TrayNetwork::SetNetworkMessage(NetworkTrayDelegate* delegate,
-                                    MessageType message_type,
-                                    NetworkType network_type,
-                                    const base::string16& title,
-                                    const base::string16& message,
-                                    const std::vector<base::string16>& links) {
-  messages_->messages()[message_type] = tray::NetworkMessages::Message(
-      delegate, network_type, title, message, links);
-  if (!Shell::GetInstance()->system_tray_delegate()->IsOobeCompleted())
-    return;
-  if (notification_)
-    notification_->Update();
-  else
-    ShowNotificationView();
-}
-
-void TrayNetwork::ClearNetworkMessage(MessageType message_type) {
-  messages_->messages().erase(message_type);
-  if (messages_->messages().empty()) {
-    HideNotificationView();
-    return;
-  }
-  if (notification_)
-    notification_->Update();
-  else
-    ShowNotificationView();
-}
-
 void TrayNetwork::RequestToggleWifi() {
   // This will always be triggered by a user action (e.g. keyboard shortcut)
   if (!detailed_ ||
@@ -548,12 +343,5 @@
     detailed_->NetworkServiceChanged(network);
 }
 
-void TrayNetwork::LinkClicked(MessageType message_type, int link_id) {
-  tray::NetworkMessages::MessageMap::const_iterator iter =
-      messages()->messages().find(message_type);
-  if (iter != messages()->messages().end() && iter->second.delegate)
-    iter->second.delegate->NotificationLinkClicked(message_type, link_id);
-}
-
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/system/chromeos/network/tray_network.h b/ash/system/chromeos/network/tray_network.h
index 332db1d..240c5c1 100644
--- a/ash/system/chromeos/network/tray_network.h
+++ b/ash/system/chromeos/network/tray_network.h
@@ -24,9 +24,6 @@
 namespace tray {
 class NetworkDefaultView;
 class NetworkDetailedView;
-class NetworkMessages;
-class NetworkMessageView;
-class NetworkNotificationView;
 class NetworkTrayView;
 }
 
@@ -43,25 +40,14 @@
   virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE;
   virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE;
   virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE;
-  virtual views::View* CreateNotificationView(
-      user::LoginStatus status) OVERRIDE;
   virtual void DestroyTrayView() OVERRIDE;
   virtual void DestroyDefaultView() OVERRIDE;
   virtual void DestroyDetailedView() OVERRIDE;
-  virtual void DestroyNotificationView() OVERRIDE;
   virtual void UpdateAfterLoginStatusChange(user::LoginStatus status) OVERRIDE;
   virtual void UpdateAfterShelfAlignmentChange(
       ShelfAlignment alignment) OVERRIDE;
 
   // NetworkObserver
-  virtual void SetNetworkMessage(
-      NetworkTrayDelegate* delegate,
-      MessageType message_type,
-      NetworkType network_type,
-      const base::string16& title,
-      const base::string16& message,
-      const std::vector<base::string16>& links) OVERRIDE;
-  virtual void ClearNetworkMessage(MessageType message_type) OVERRIDE;
   virtual void RequestToggleWifi() OVERRIDE;
 
   // TrayNetworkStateObserver::Delegate
@@ -70,18 +56,9 @@
       const chromeos::NetworkState* network) OVERRIDE;
 
  private:
-  friend class tray::NetworkMessageView;
-  friend class tray::NetworkNotificationView;
-
-  void LinkClicked(MessageType message_type, int link_id);
-
-  const tray::NetworkMessages* messages() const { return messages_.get(); }
-
   tray::NetworkTrayView* tray_;
   tray::NetworkDefaultView* default_;
   tray::NetworkDetailedView* detailed_;
-  tray::NetworkNotificationView* notification_;
-  scoped_ptr<tray::NetworkMessages> messages_;
   bool request_wifi_view_;
   scoped_ptr<TrayNetworkStateObserver> network_state_observer_;
 
diff --git a/ash/system/chromeos/network/tray_sms.cc b/ash/system/chromeos/network/tray_sms.cc
index 982a564..9adb5f9 100644
--- a/ash/system/chromeos/network/tray_sms.cc
+++ b/ash/system/chromeos/network/tray_sms.cc
@@ -16,6 +16,8 @@
 #include "ash/system/tray/tray_notification_view.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chromeos/network/network_event_log.h"
+#include "chromeos/network/network_handler.h"
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -35,12 +37,15 @@
 // Top/bottom padding of the text items.
 const int kPaddingVertical = 10;
 
+const char kSmsNumberKey[] = "number";
+const char kSmsTextKey[] = "text";
+
 bool GetMessageFromDictionary(const base::DictionaryValue* message,
                               std::string* number,
                               std::string* text) {
-  if (!message->GetStringWithoutPathExpansion(ash::kSmsNumberKey, number))
+  if (!message->GetStringWithoutPathExpansion(kSmsNumberKey, number))
     return false;
-  if (!message->GetStringWithoutPathExpansion(ash::kSmsTextKey, text))
+  if (!message->GetStringWithoutPathExpansion(kSmsTextKey, text))
     return false;
   return true;
 }
@@ -281,11 +286,18 @@
       default_(NULL),
       detailed_(NULL),
       notification_(NULL) {
-  Shell::GetInstance()->system_tray_notifier()->AddSmsObserver(this);
+  // TODO(armansito): SMS could be a special case for cellular that requires a
+  // user (perhaps the owner) to be logged in. If that is the case, then an
+  // additional check should be done before subscribing for SMS notifications.
+  if (chromeos::NetworkHandler::IsInitialized())
+    chromeos::NetworkHandler::Get()->network_sms_handler()->AddObserver(this);
 }
 
 TraySms::~TraySms() {
-  Shell::GetInstance()->system_tray_notifier()->RemoveSmsObserver(this);
+  if (chromeos::NetworkHandler::IsInitialized()) {
+    chromeos::NetworkHandler::Get()->network_sms_handler()->RemoveObserver(
+        this);
+  }
 }
 
 views::View* TraySms::CreateDefaultView(user::LoginStatus status) {
@@ -327,8 +339,35 @@
   notification_ = NULL;
 }
 
-void TraySms::AddMessage(const base::DictionaryValue& message) {
-  messages_.Append(message.DeepCopy());
+void TraySms::MessageReceived(const base::DictionaryValue& message) {
+
+  std::string message_text;
+  if (!message.GetStringWithoutPathExpansion(
+          chromeos::NetworkSmsHandler::kTextKey, &message_text)) {
+    NET_LOG_ERROR("SMS message contains no content.", "");
+    return;
+  }
+  // TODO(armansito): A message might be due to a special "Message Waiting"
+  // state that the message is in. Once SMS handling moves to shill, such
+  // messages should be filtered there so that this check becomes unnecessary.
+  if (message_text.empty()) {
+    NET_LOG_DEBUG("SMS has empty content text. Ignoring.", "");
+    return;
+  }
+  std::string message_number;
+  if (!message.GetStringWithoutPathExpansion(
+          chromeos::NetworkSmsHandler::kNumberKey, &message_number)) {
+    NET_LOG_DEBUG("SMS contains no number. Ignoring.", "");
+    return;
+  }
+
+  NET_LOG_DEBUG("Received SMS from: " + message_number + " with text: " +
+                message_text, "");
+
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetString(kSmsNumberKey, message_number);
+  dict->SetString(kSmsTextKey, message_text);
+  messages_.Append(dict);
   Update(true);
 }
 
diff --git a/ash/system/chromeos/network/tray_sms.h b/ash/system/chromeos/network/tray_sms.h
index 7fc334b..5a79360 100644
--- a/ash/system/chromeos/network/tray_sms.h
+++ b/ash/system/chromeos/network/tray_sms.h
@@ -7,15 +7,15 @@
 
 #include <string>
 
-#include "ash/system/chromeos/network/sms_observer.h"
 #include "ash/system/tray/system_tray_item.h"
 #include "base/values.h"
+#include "chromeos/network/network_sms_handler.h"
 
 namespace ash {
 namespace internal {
 
 class TraySms : public SystemTrayItem,
-                public SmsObserver {
+                public chromeos::NetworkSmsHandler::Observer {
  public:
   explicit TraySms(SystemTray* system_tray);
   virtual ~TraySms();
@@ -29,8 +29,8 @@
   virtual void DestroyDetailedView() OVERRIDE;
   virtual void DestroyNotificationView() OVERRIDE;
 
-  // Overridden from SmsObserver.
-  virtual void AddMessage(const base::DictionaryValue& message) OVERRIDE;
+  // Overridden from chromeos::NetworkSmsHandler::Observer.
+  virtual void MessageReceived(const base::DictionaryValue& message) OVERRIDE;
 
  protected:
   class SmsDefaultView;
@@ -45,7 +45,8 @@
   // Removes message at |index| from message list.
   void RemoveMessage(size_t index);
 
-  // Called when sms messages have changed (by tray::SmsObserver).
+  // Called when sms messages have changed (through
+  // chromeos::NetworkSmsHandler::Observer).
   void Update(bool notify);
 
   base::ListValue& messages() { return messages_; }
diff --git a/ash/system/chromeos/settings/tray_settings.cc b/ash/system/chromeos/settings/tray_settings.cc
index 8153aea..8868b7c 100644
--- a/ash/system/chromeos/settings/tray_settings.cc
+++ b/ash/system/chromeos/settings/tray_settings.cc
@@ -142,6 +142,9 @@
       !PowerStatus::Get()->IsBatteryPresent())
     return NULL;
 
+  if (!ash::Shell::GetInstance()->system_tray_delegate()->ShouldShowSettings())
+    return NULL;
+
   CHECK(default_view_ == NULL);
   default_view_ =  new tray::SettingsDefaultView(status);
   return default_view_;
diff --git a/ash/system/chromeos/tray_display.cc b/ash/system/chromeos/tray_display.cc
index 1f81f77..0231c5d 100644
--- a/ash/system/chromeos/tray_display.cc
+++ b/ash/system/chromeos/tray_display.cc
@@ -23,7 +23,6 @@
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_delegate.h"
-#include "ui/message_center/notification_list.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
@@ -34,8 +33,6 @@
 namespace internal {
 namespace {
 
-static const char kDisplayNotificationId[] = "chrome://settings/display";
-
 DisplayManager* GetDisplayManager() {
   return Shell::GetInstance()->display_manager();
 }
@@ -144,7 +141,7 @@
   return name;
 }
 
-base::string16 GetTrayDisplayMessage() {
+base::string16 GetTrayDisplayMessage(base::string16* additional_message_out) {
   DisplayManager* display_manager = GetDisplayManager();
   if (display_manager->GetNumDisplays() > 1) {
     if (GetDisplayManager()->HasInternalDisplay()) {
@@ -167,6 +164,10 @@
   int64 first_id = display_manager->first_display_id();
   if (display_manager->HasInternalDisplay() &&
       !display_manager->IsInternalDisplayId(first_id)) {
+    if (additional_message_out) {
+      *additional_message_out = l10n_util::GetStringUTF16(
+          IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED_DESCRIPTION);
+    }
     return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED);
   }
 
@@ -181,34 +182,10 @@
   }
 }
 
-void UpdateDisplayNotification(const base::string16& message) {
-  // Always remove the notification to make sure the notification appears
-  // as a popup in any situation.
-  message_center::MessageCenter::Get()->RemoveNotification(
-      kDisplayNotificationId, false /* by_user */);
-
-  if (message.empty())
-    return;
-
-  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  scoped_ptr<Notification> notification(new Notification(
-      message_center::NOTIFICATION_TYPE_SIMPLE,
-      kDisplayNotificationId,
-      message,
-      base::string16(),  // body is intentionally empty, see crbug.com/265915
-      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY),
-      base::string16(),  // display_source
-      "",  // extension_id
-      message_center::RichNotificationData(),
-      new message_center::HandleNotificationClickedDelegate(
-          base::Bind(&OpenSettings,
-                     Shell::GetInstance()->system_tray_delegate()->
-                     GetUserLoginStatus()))));
-  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
-}
-
 }  // namespace
 
+const char TrayDisplay::kNotificationId[] = "chrome://settings/display";
+
 class DisplayView : public ash::internal::ActionableView {
  public:
   explicit DisplayView(user::LoginStatus login_status)
@@ -235,19 +212,19 @@
   virtual ~DisplayView() {}
 
   void Update() {
-    base::string16 message = GetTrayDisplayMessage();
+    base::string16 message = GetTrayDisplayMessage(NULL);
     if (message.empty() && ShouldShowFirstDisplayInfo())
       message = GetDisplayInfoLine(GetDisplayManager()->first_display_id());
     SetVisible(!message.empty());
     label_->SetText(message);
   }
 
-  views::Label* label() { return label_; }
+  const views::Label* label() const { return label_; }
 
   // Overridden from views::View.
   virtual bool GetTooltipText(const gfx::Point& p,
                               base::string16* tooltip) const OVERRIDE {
-    base::string16 tray_message = GetTrayDisplayMessage();
+    base::string16 tray_message = GetTrayDisplayMessage(NULL);
     base::string16 display_message = GetAllDisplayInfo();
     if (tray_message.empty() && display_message.empty())
       return false;
@@ -346,12 +323,13 @@
 }
 
 bool TrayDisplay::GetDisplayMessageForNotification(
-    base::string16* message,
-    const TrayDisplay::DisplayInfoMap& old_info) {
+    const TrayDisplay::DisplayInfoMap& old_info,
+    base::string16* message_out,
+    base::string16* additional_message_out) {
   // Display is added or removed. Use the same message as the one in
   // the system tray.
   if (display_info_.size() != old_info.size()) {
-    *message = GetTrayDisplayMessage();
+    *message_out = GetTrayDisplayMessage(additional_message_out);
     return true;
   }
 
@@ -362,12 +340,12 @@
     // for the transition between docked mode and mirrored display. Falls back
     // to GetTrayDisplayMessage().
     if (old_iter == old_info.end()) {
-      *message = GetTrayDisplayMessage();
+      *message_out = GetTrayDisplayMessage(additional_message_out);
       return true;
     }
 
     if (iter->second.ui_scale() != old_iter->second.ui_scale()) {
-      *message = l10n_util::GetStringFUTF16(
+      *message_out = l10n_util::GetStringFUTF16(
           IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
           GetDisplayName(iter->first),
           GetDisplaySize(iter->first));
@@ -389,7 +367,7 @@
           rotation_text_id = IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270;
           break;
       }
-      *message = l10n_util::GetStringFUTF16(
+      *message_out = l10n_util::GetStringFUTF16(
           IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED,
           GetDisplayName(iter->first),
           l10n_util::GetStringUTF16(rotation_text_id));
@@ -401,6 +379,34 @@
   return false;
 }
 
+void TrayDisplay::CreateOrUpdateNotification(
+    const base::string16& message,
+    const base::string16& additional_message) {
+  // Always remove the notification to make sure the notification appears
+  // as a popup in any situation.
+  message_center::MessageCenter::Get()->RemoveNotification(
+      kNotificationId, false /* by_user */);
+
+  if (message.empty())
+    return;
+
+  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+  scoped_ptr<Notification> notification(new Notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE,
+      kNotificationId,
+      message,
+      additional_message,
+      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY),
+      base::string16(),  // display_source
+      "",  // extension_id
+      message_center::RichNotificationData(),
+      new message_center::HandleNotificationClickedDelegate(
+          base::Bind(&OpenSettings,
+                     Shell::GetInstance()->system_tray_delegate()->
+                     GetUserLoginStatus()))));
+  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
+}
+
 views::View* TrayDisplay::CreateDefaultView(user::LoginStatus status) {
   DCHECK(default_ == NULL);
   default_ = new DisplayView(status);
@@ -421,33 +427,17 @@
   }
 
   base::string16 message;
-  if (GetDisplayMessageForNotification(&message, old_info))
-    UpdateDisplayNotification(message);
+  base::string16 additional_message;
+  if (GetDisplayMessageForNotification(old_info, &message, &additional_message))
+    CreateOrUpdateNotification(message, additional_message);
 }
 
-base::string16 TrayDisplay::GetDefaultViewMessage() {
+base::string16 TrayDisplay::GetDefaultViewMessage() const {
   if (!default_ || !default_->visible())
     return base::string16();
 
   return static_cast<DisplayView*>(default_)->label()->text();
 }
 
-base::string16 TrayDisplay::GetNotificationMessage() {
-  message_center::NotificationList::Notifications notifications =
-      message_center::MessageCenter::Get()->GetNotifications();
-  for (message_center::NotificationList::Notifications::const_iterator iter =
-           notifications.begin(); iter != notifications.end(); ++iter) {
-    if ((*iter)->id() == kDisplayNotificationId)
-      return (*iter)->title();
-  }
-
-  return base::string16();
-}
-
-void TrayDisplay::CloseNotificationForTest() {
-  message_center::MessageCenter::Get()->RemoveNotification(
-      kDisplayNotificationId, false);
-}
-
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/system/chromeos/tray_display.h b/ash/system/chromeos/tray_display.h
index 328bce5..2923f5d 100644
--- a/ash/system/chromeos/tray_display.h
+++ b/ash/system/chromeos/tray_display.h
@@ -37,27 +37,34 @@
 
   typedef std::map<int64, DisplayInfo> DisplayInfoMap;
 
+  static const char kNotificationId[];
+
   // Scans the current display info and updates |display_info_|. Sets the
   // previous data to |old_info| if it's not NULL.
   void UpdateDisplayInfo(DisplayInfoMap* old_info);
 
   // Compares the current display settings with |old_info| and determine what
   // message should be shown for notification. Returns true if there's a
-  // meaningful change. Note that it's possible to return true and set |message|
-  // to empty, which means the notification should be removed.
+  // meaningful change. Note that it's possible to return true and set
+  // |message_out| to empty, which means the notification should be removed. It
+  // also sets |additional_message_out| which appears in the notification with
+  // the |message_out|.
   bool GetDisplayMessageForNotification(
-      base::string16* message,
-      const DisplayInfoMap& old_info);
+      const DisplayInfoMap& old_info,
+      base::string16* message_out,
+      base::string16* additional_message_out);
+
+  // Creates or updates the display notification.
+  void CreateOrUpdateNotification(const base::string16& message,
+                                  const base::string16& additional_message);
 
   // Overridden from SystemTrayItem.
   virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE;
   virtual void DestroyDefaultView() OVERRIDE;
 
   // Test accessors.
-  base::string16 GetDefaultViewMessage();
-  base::string16 GetNotificationMessage();
-  void CloseNotificationForTest();
-  views::View* default_view() { return default_; }
+  base::string16 GetDefaultViewMessage() const;
+  const views::View* default_view() const { return default_; }
 
   views::View* default_;
   DisplayInfoMap display_info_;
diff --git a/ash/system/chromeos/tray_display_unittest.cc b/ash/system/chromeos/tray_display_unittest.cc
index c6fa9e9..2a9794c 100644
--- a/ash/system/chromeos/tray_display_unittest.cc
+++ b/ash/system/chromeos/tray_display_unittest.cc
@@ -16,6 +16,9 @@
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/display.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
+#include "ui/message_center/notification_list.h"
 #include "ui/views/controls/label.h"
 
 namespace ash {
@@ -75,12 +78,15 @@
   TrayDisplay* tray_display() { return tray_display_; }
 
   void CloseNotification();
-  bool IsDisplayVisibleInTray();
-  base::string16 GetTrayDisplayText();
-  base::string16 GetTrayDisplayTooltipText();
-  base::string16 GetDisplayNotificationText();
+  bool IsDisplayVisibleInTray() const;
+  base::string16 GetTrayDisplayText() const;
+  base::string16 GetTrayDisplayTooltipText() const;
+  base::string16 GetDisplayNotificationText() const;
+  base::string16 GetDisplayNotificationAdditionalText() const;
 
  private:
+  const message_center::Notification* GetDisplayNotification() const;
+
   // Weak reference, owned by Shell.
   SystemTray* tray_;
 
@@ -104,20 +110,21 @@
 }
 
 void TrayDisplayTest::CloseNotification() {
-  tray_display_->CloseNotificationForTest();
+  message_center::MessageCenter::Get()->RemoveNotification(
+      TrayDisplay::kNotificationId, false);
   RunAllPendingInMessageLoop();
 }
 
-bool TrayDisplayTest::IsDisplayVisibleInTray() {
+bool TrayDisplayTest::IsDisplayVisibleInTray() const {
   return tray_display_->default_view() &&
       tray_display_->default_view()->visible();
 }
 
-base::string16 TrayDisplayTest::GetTrayDisplayText() {
+base::string16 TrayDisplayTest::GetTrayDisplayText() const {
   return tray_display_->GetDefaultViewMessage();
 }
 
-base::string16 TrayDisplayTest::GetTrayDisplayTooltipText() {
+base::string16 TrayDisplayTest::GetTrayDisplayTooltipText() const {
   if (!tray_display_->default_view())
     return base::string16();
 
@@ -127,8 +134,27 @@
   return tooltip;
 }
 
-base::string16 TrayDisplayTest::GetDisplayNotificationText() {
-  return tray_display_->GetNotificationMessage();
+base::string16 TrayDisplayTest::GetDisplayNotificationText() const {
+  const message_center::Notification* notification = GetDisplayNotification();
+  return notification ? notification->title() : base::string16();
+}
+
+base::string16 TrayDisplayTest::GetDisplayNotificationAdditionalText() const {
+  const message_center::Notification* notification = GetDisplayNotification();
+  return notification ? notification->message() : base::string16();
+}
+
+const message_center::Notification* TrayDisplayTest::GetDisplayNotification()
+    const {
+  const message_center::NotificationList::Notifications notifications =
+      message_center::MessageCenter::Get()->GetNotifications();
+  for (message_center::NotificationList::Notifications::const_iterator iter =
+           notifications.begin(); iter != notifications.end(); ++iter) {
+    if ((*iter)->id() == TrayDisplay::kNotificationId)
+      return *iter;
+  }
+
+  return NULL;
 }
 
 TEST_F(TrayDisplayTest, NoInternalDisplay) {
@@ -189,8 +215,6 @@
   EXPECT_EQ(expected, GetTrayDisplayText());
   EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"),
             GetTrayDisplayTooltipText());
-
-  // TODO(mukai): add test case for docked mode here.
 }
 
 TEST_F(TrayDisplayTest, InternalDisplayResized) {
@@ -230,6 +254,20 @@
   EXPECT_EQ(expected, GetTrayDisplayText());
   EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "600x600"),
             GetTrayDisplayTooltipText());
+
+  // Closed lid mode.
+  display_manager->SetSoftwareMirroring(false);
+  UpdateDisplay("400x400@1.5,200x200");
+  gfx::Display::SetInternalDisplayId(ScreenAsh::GetSecondaryDisplay().id());
+  UpdateDisplay("400x400@1.5");
+  tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
+  EXPECT_TRUE(IsDisplayVisibleInTray());
+  expected = l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED);
+  EXPECT_EQ(expected, GetTrayDisplayText());
+  EXPECT_EQ(
+      GetTooltipText(
+          expected, GetFirstDisplayName(), "600x600", base::string16(), ""),
+      GetTrayDisplayTooltipText());
 }
 
 TEST_F(TrayDisplayTest, ExternalDisplayResized) {
@@ -332,6 +370,7 @@
           l10n_util::GetStringUTF16(
               IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   CloseNotification();
   UpdateDisplay("400x400");
@@ -341,6 +380,7 @@
           l10n_util::GetStringUTF16(
               IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION)),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   // UI-scale
   CloseNotification();
@@ -350,6 +390,7 @@
           IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
           GetFirstDisplayName(), UTF8ToUTF16("600x600")),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   // UI-scale to 1.0
   CloseNotification();
@@ -359,11 +400,13 @@
           IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
           GetFirstDisplayName(), UTF8ToUTF16("400x400")),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   // No-update
   CloseNotification();
   UpdateDisplay("400x400");
   EXPECT_TRUE(GetDisplayNotificationText().empty());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   // Extended.
   CloseNotification();
@@ -372,6 +415,7 @@
       l10n_util::GetStringFUTF16(
           IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   // Mirroring.
   CloseNotification();
@@ -381,6 +425,7 @@
       l10n_util::GetStringFUTF16(
           IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName()),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   // Back to extended.
   CloseNotification();
@@ -390,6 +435,7 @@
       l10n_util::GetStringFUTF16(
           IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
   // Resize the first display.
   UpdateDisplay("400x400@1.5,200x200");
@@ -398,8 +444,9 @@
           IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
           GetFirstDisplayName(), UTF8ToUTF16("600x600")),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
 
-  // rotate the second.
+  // Rotate the second.
   UpdateDisplay("400x400@1.5,200x200/r");
   EXPECT_EQ(
       l10n_util::GetStringFUTF16(
@@ -408,6 +455,17 @@
           l10n_util::GetStringUTF16(
               IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)),
       GetDisplayNotificationText());
+  EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
+
+  // Enters closed lid mode.
+  UpdateDisplay("400x400@1.5,200x200");
+  gfx::Display::SetInternalDisplayId(ScreenAsh::GetSecondaryDisplay().id());
+  UpdateDisplay("400x400@1.5");
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED),
+            GetDisplayNotificationText());
+  EXPECT_EQ(
+      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED_DESCRIPTION),
+      GetDisplayNotificationAdditionalText());
 }
 
 TEST_F(TrayDisplayTest, DisplayConfigurationChangedTwice) {
diff --git a/ash/system/chromeos/tray_tracing.cc b/ash/system/chromeos/tray_tracing.cc
index b6a8cf1..764e943 100644
--- a/ash/system/chromeos/tray_tracing.cc
+++ b/ash/system/chromeos/tray_tracing.cc
@@ -89,7 +89,8 @@
 
 views::View* TrayTracing::CreateDefaultView(user::LoginStatus status) {
   CHECK(default_ == NULL);
-  default_ = new tray::DefaultTracingView();
+  if (tray_view() && tray_view()->visible())
+    default_ = new tray::DefaultTracingView();
   return default_;
 }
 
diff --git a/ash/system/ime/tray_ime.cc b/ash/system/ime/tray_ime.cc
index 6fac8fd..e8c9eda 100644
--- a/ash/system/ime/tray_ime.cc
+++ b/ash/system/ime/tray_ime.cc
@@ -218,6 +218,7 @@
   IMEInfo current;
   delegate->GetCurrentIME(&current);
 
+  ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
   scoped_ptr<Notification> notification(new Notification(
       message_center::NOTIFICATION_TYPE_SIMPLE,
       kIMENotificationId,
@@ -227,7 +228,7 @@
           IDS_ASH_STATUS_TRAY_IME_TURNED_ON_BUBBLE,
           current.medium_name),
       base::string16(),  // message
-      gfx::Image(),  // icon
+      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_IME),
       base::string16(),  // display_source
       "",  // extension_id
       message_center::RichNotificationData(),
diff --git a/ash/system/locale/locale_notification_controller.cc b/ash/system/locale/locale_notification_controller.cc
index 342c5a6..9f368b0 100644
--- a/ash/system/locale/locale_notification_controller.cc
+++ b/ash/system/locale/locale_notification_controller.cc
@@ -7,8 +7,10 @@
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/strings/string16.h"
+#include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_delegate.h"
@@ -105,14 +107,14 @@
           IDS_ASH_STATUS_TRAY_LOCALE_REVERT_MESSAGE, from)));
   optional.never_timeout = true;
 
+  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
   scoped_ptr<Notification> notification(new Notification(
       message_center::NOTIFICATION_TYPE_SIMPLE,
       kLocaleChangeNotificationId,
       l10n_util::GetStringFUTF16(
           IDS_ASH_STATUS_TRAY_LOCALE_CHANGE_MESSAGE, from, to),
       base::string16()  /* message */,
-      // TODO(mukai): add the icon here. see crbug.com/262393
-      gfx::Image()  /* icon */,
+      bundle.GetImageNamed(IDR_AURA_UBER_TRAY_LOCALE),
       base::string16()  /* display_source */,
       std::string()  /* extension_id */,
       optional,
diff --git a/ash/system/logout_button/logout_button_tray.cc b/ash/system/logout_button/logout_button_tray.cc
new file mode 100644
index 0000000..f62921f
--- /dev/null
+++ b/ash/system/logout_button/logout_button_tray.cc
@@ -0,0 +1,158 @@
+// Copyright 2013 The Chromium Authors. 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/logout_button/logout_button_tray.h"
+
+#include "ash/shelf/shelf_types.h"
+#include "ash/shell.h"
+#include "ash/system/status_area_widget.h"
+#include "ash/system/tray/system_tray_delegate.h"
+#include "ash/system/tray/system_tray_notifier.h"
+#include "ash/system/tray/tray_constants.h"
+#include "ash/system/tray/tray_utils.h"
+#include "base/logging.h"
+#include "grit/ash_resources.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/events/event.h"
+#include "ui/gfx/font.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/size.h"
+#include "ui/views/bubble/tray_bubble_view.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/painter.h"
+
+namespace ash {
+
+namespace internal {
+
+namespace {
+
+const int kLogoutButtonHorizontalExtraPadding = 7;
+
+const int kLogoutButtonNormalImages[] = {
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_LEFT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_RIGHT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_LEFT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_CENTER,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_RIGHT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_LEFT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_RIGHT
+};
+
+const int kLogoutButtonPushedImages[] = {
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_LEFT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_RIGHT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_LEFT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_CENTER,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_RIGHT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_LEFT,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM,
+  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_RIGHT
+};
+
+class LogoutButton : public views::LabelButton {
+ public:
+  LogoutButton(views::ButtonListener* listener);
+  virtual ~LogoutButton();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LogoutButton);
+};
+
+}  // namespace
+
+LogoutButton::LogoutButton(views::ButtonListener* listener)
+    : views::LabelButton(listener, base::string16()) {
+  SetupLabelForTray(label());
+  SetFont(GetFont().DeriveFont(0, gfx::Font::NORMAL));
+  for (size_t state = 0; state < views::Button::STATE_COUNT; ++state)
+    SetTextColor(static_cast<views::Button::ButtonState>(state), SK_ColorWHITE);
+
+  views::LabelButtonBorder* border =
+      new views::LabelButtonBorder(views::Button::STYLE_TEXTBUTTON);
+  border->SetPainter(false, views::Button::STATE_NORMAL,
+      views::Painter::CreateImageGridPainter(kLogoutButtonNormalImages));
+  border->SetPainter(false, views::Button::STATE_HOVERED,
+      views::Painter::CreateImageGridPainter(kLogoutButtonNormalImages));
+  border->SetPainter(false, views::Button::STATE_PRESSED,
+      views::Painter::CreateImageGridPainter(kLogoutButtonPushedImages));
+  gfx::Insets insets = border->GetInsets();
+  insets += gfx::Insets(0, kLogoutButtonHorizontalExtraPadding,
+                        0, kLogoutButtonHorizontalExtraPadding);
+  border->set_insets(insets);
+  set_border(border);
+  set_animate_on_state_change(false);
+
+  set_min_size(gfx::Size(0, GetShelfItemHeight()));
+}
+
+LogoutButton::~LogoutButton() {
+}
+
+LogoutButtonTray::LogoutButtonTray(StatusAreaWidget* status_area_widget)
+    : TrayBackgroundView(status_area_widget),
+      button_(NULL),
+      login_status_(user::LOGGED_IN_NONE),
+      show_logout_button_in_tray_(false) {
+  button_ = new LogoutButton(this);
+  tray_container()->AddChildView(button_);
+  tray_container()->set_border(NULL);
+  Shell::GetInstance()->system_tray_notifier()->AddLogoutButtonObserver(this);
+}
+
+LogoutButtonTray::~LogoutButtonTray() {
+  Shell::GetInstance()->system_tray_notifier()->
+      RemoveLogoutButtonObserver(this);
+}
+
+void LogoutButtonTray::SetShelfAlignment(ShelfAlignment alignment) {
+  TrayBackgroundView::SetShelfAlignment(alignment);
+  tray_container()->set_border(NULL);
+}
+
+base::string16 LogoutButtonTray::GetAccessibleNameForTray() {
+  return button_->GetText();
+}
+
+void LogoutButtonTray::HideBubbleWithView(
+    const views::TrayBubbleView* bubble_view) {
+}
+
+bool LogoutButtonTray::ClickedOutsideBubble() {
+  return false;
+}
+
+void LogoutButtonTray::OnShowLogoutButtonInTrayChanged(bool show) {
+  show_logout_button_in_tray_ = show;
+  UpdateVisibility();
+}
+
+void LogoutButtonTray::ButtonPressed(views::Button* sender,
+                                     const ui::Event& event) {
+  DCHECK_EQ(sender, button_);
+  Shell::GetInstance()->system_tray_delegate()->SignOut();
+}
+
+void LogoutButtonTray::UpdateAfterLoginStatusChange(
+    user::LoginStatus login_status) {
+  login_status_ = login_status;
+  const base::string16 title =
+      GetLocalizedSignOutStringForStatus(login_status, false);
+  button_->SetText(title);
+  button_->SetAccessibleName(title);
+  UpdateVisibility();
+}
+
+void LogoutButtonTray::UpdateVisibility() {
+  SetVisible(show_logout_button_in_tray_ &&
+             login_status_ != user::LOGGED_IN_NONE &&
+             login_status_ != user::LOGGED_IN_LOCKED);
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/system/logout_button/logout_button_tray.h b/ash/system/logout_button/logout_button_tray.h
new file mode 100644
index 0000000..5683e5e
--- /dev/null
+++ b/ash/system/logout_button/logout_button_tray.h
@@ -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.
+
+#ifndef ASH_SYSTEM_LOGOUT_BUTTON_LOGOUT_BUTTON_TRAY_H_
+#define ASH_SYSTEM_LOGOUT_BUTTON_LOGOUT_BUTTON_TRAY_H_
+
+#include "ash/system/logout_button/logout_button_observer.h"
+#include "ash/system/tray/tray_background_view.h"
+#include "ash/system/user/login_status.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/views/controls/button/button.h"
+
+namespace views {
+class LabelButton;
+}
+
+namespace ash {
+namespace internal {
+
+class StatusAreaWidget;
+
+// Adds a logout button to the launcher's status area if enabled by the
+// kShowLogoutButtonInTray pref.
+class LogoutButtonTray : public TrayBackgroundView,
+                         public LogoutButtonObserver,
+                         public views::ButtonListener {
+ public:
+  explicit LogoutButtonTray(StatusAreaWidget* status_area_widget);
+  virtual ~LogoutButtonTray();
+
+  // TrayBackgroundView:
+  virtual void SetShelfAlignment(ShelfAlignment alignment) OVERRIDE;
+  virtual base::string16 GetAccessibleNameForTray() OVERRIDE;
+  virtual void HideBubbleWithView(
+      const views::TrayBubbleView* bubble_view) OVERRIDE;
+  virtual bool ClickedOutsideBubble() OVERRIDE;
+
+  // LogoutButtonObserver:
+  virtual void OnShowLogoutButtonInTrayChanged(bool show) OVERRIDE;
+
+  // views::ButtonListener:
+  virtual void ButtonPressed(views::Button* sender,
+                             const ui::Event& event) OVERRIDE;
+
+  void UpdateAfterLoginStatusChange(user::LoginStatus login_status);
+
+ private:
+  void UpdateVisibility();
+
+  views::LabelButton* button_;  // Not owned.
+  user::LoginStatus login_status_;
+  bool show_logout_button_in_tray_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogoutButtonTray);
+};
+
+}  // namespace internal
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_LOGOUT_BUTTON_LOGOUT_BUTTON_TRAY_H_
diff --git a/ash/system/logout_button/tray_logout_button.cc b/ash/system/logout_button/tray_logout_button.cc
deleted file mode 100644
index 102329c..0000000
--- a/ash/system/logout_button/tray_logout_button.cc
+++ /dev/null
@@ -1,168 +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 "ash/system/logout_button/tray_logout_button.h"
-
-#include <cstddef>
-
-#include "ash/shell.h"
-#include "ash/system/tray/system_tray_delegate.h"
-#include "ash/system/tray/system_tray_notifier.h"
-#include "ash/system/tray/tray_constants.h"
-#include "ash/system/user/login_status.h"
-#include "base/logging.h"
-#include "base/strings/string16.h"
-#include "grit/ash_resources.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/views/border.h"
-#include "ui/views/controls/button/button.h"
-#include "ui/views/controls/button/custom_button.h"
-#include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/button/label_button_border.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/view.h"
-
-namespace {
-
-const int kLogoutButtonNormalImages[] = {
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_TOP_RIGHT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_CENTER,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_RIGHT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_NORMAL_BOTTOM_RIGHT
-};
-const int kLogoutButtonHotImages[] = {
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_TOP_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_TOP,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_TOP_RIGHT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_CENTER,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_RIGHT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_BOTTOM_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_BOTTOM,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_HOT_BOTTOM_RIGHT
-};
-const int kLogoutButtonPushedImages[] = {
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_TOP_RIGHT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_CENTER,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_RIGHT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_LEFT,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM,
-  IDR_AURA_UBER_TRAY_LOGOUT_BUTTON_PUSHED_BOTTOM_RIGHT
-};
-
-}  // namespace
-
-namespace ash {
-namespace internal {
-
-namespace tray {
-
-class LogoutButton : public views::View,
-                     public views::ButtonListener {
- public:
-  LogoutButton(user::LoginStatus status) : button_(NULL),
-                                           login_status_(user::LOGGED_IN_NONE),
-                                           show_logout_button_in_tray_(false) {
-    views::BoxLayout* layout = new views::BoxLayout(
-        views::BoxLayout::kHorizontal, 0, 0, 0);
-    layout->set_spread_blank_space(true);
-    SetLayoutManager(layout);
-    set_border(views::Border::CreateEmptyBorder(
-        0, kTrayLabelItemHorizontalPaddingBottomAlignment, 0, 0));
-
-    button_ = new views::LabelButton(this, base::string16());
-    for (size_t state = 0; state < views::Button::STATE_COUNT; ++state) {
-      button_->SetTextColor(
-          static_cast<views::Button::ButtonState>(state), SK_ColorWHITE);
-    }
-    button_->SetFont(button_->GetFont().DeriveFont(1));
-    views::LabelButtonBorder* border =
-        new views::LabelButtonBorder(views::Button::STYLE_TEXTBUTTON);
-    border->SetPainter(false, views::Button::STATE_NORMAL,
-        views::Painter::CreateImageGridPainter(kLogoutButtonNormalImages));
-    border->SetPainter(false, views::Button::STATE_HOVERED,
-        views::Painter::CreateImageGridPainter(kLogoutButtonHotImages));
-    border->SetPainter(false, views::Button::STATE_PRESSED,
-        views::Painter::CreateImageGridPainter(kLogoutButtonPushedImages));
-    button_->set_border(border);
-    AddChildView(button_);
-    OnLoginStatusChanged(status);
-  }
-
-  void OnLoginStatusChanged(user::LoginStatus status) {
-    login_status_ = status;
-    const base::string16 title = GetLocalizedSignOutStringForStatus(
-        login_status_, false);
-    button_->SetText(title);
-    button_->SetAccessibleName(title);
-    UpdateVisibility();
-  }
-
-  void OnShowLogoutButtonInTrayChanged(bool show) {
-    show_logout_button_in_tray_ = show;
-    UpdateVisibility();
-  }
-
-  // Overridden from views::ButtonListener.
-  virtual void ButtonPressed(views::Button* sender,
-                             const ui::Event& event) OVERRIDE {
-    DCHECK_EQ(sender, button_);
-    Shell::GetInstance()->system_tray_delegate()->SignOut();
-  }
-
- private:
-  void UpdateVisibility() {
-    SetVisible(show_logout_button_in_tray_ &&
-               login_status_ != user::LOGGED_IN_NONE &&
-               login_status_ != user::LOGGED_IN_LOCKED);
-  }
-
-  views::LabelButton* button_;
-  user::LoginStatus login_status_;
-  bool show_logout_button_in_tray_;
-
-  DISALLOW_COPY_AND_ASSIGN(LogoutButton);
-};
-
-}  // namespace tray
-
-TrayLogoutButton::TrayLogoutButton(SystemTray* system_tray)
-    : SystemTrayItem(system_tray),
-      logout_button_(NULL) {
-  Shell::GetInstance()->system_tray_notifier()->AddLogoutButtonObserver(this);
-}
-
-TrayLogoutButton::~TrayLogoutButton() {
-  Shell::GetInstance()->system_tray_notifier()->
-      RemoveLogoutButtonObserver(this);
-}
-
-views::View* TrayLogoutButton::CreateTrayView(user::LoginStatus status) {
-  CHECK(logout_button_ == NULL);
-  logout_button_ = new tray::LogoutButton(status);
-  return logout_button_;
-}
-
-void TrayLogoutButton::DestroyTrayView() {
-  logout_button_ = NULL;
-}
-
-void TrayLogoutButton::UpdateAfterLoginStatusChange(user::LoginStatus status) {
-  logout_button_->OnLoginStatusChanged(status);
-}
-
-void TrayLogoutButton::OnShowLogoutButtonInTrayChanged(bool show) {
-  logout_button_->OnShowLogoutButtonInTrayChanged(show);
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/system/logout_button/tray_logout_button.h b/ash/system/logout_button/tray_logout_button.h
deleted file mode 100644
index 50ca9f9..0000000
--- a/ash/system/logout_button/tray_logout_button.h
+++ /dev/null
@@ -1,44 +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_SYSTEM_LOGOUT_BUTTON_TRAY_LOGOUT_BUTTON_H_
-#define ASH_SYSTEM_LOGOUT_BUTTON_TRAY_LOGOUT_BUTTON_H_
-
-#include "ash/system/logout_button/logout_button_observer.h"
-#include "ash/system/tray/system_tray_item.h"
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-
-namespace ash {
-namespace internal {
-
-namespace tray {
-class LogoutButton;
-}
-
-// Adds a logout button to the system tray if enabled by the
-// kShowLogoutButtonInTray pref.
-class TrayLogoutButton : public SystemTrayItem, public LogoutButtonObserver {
- public:
-  explicit TrayLogoutButton(SystemTray* system_tray);
-  virtual ~TrayLogoutButton();
-
-  // Overridden from SystemTrayItem.
-  virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE;
-  virtual void DestroyTrayView() OVERRIDE;
-  virtual void UpdateAfterLoginStatusChange(user::LoginStatus status) OVERRIDE;
-
-  // Overridden from LogoutButtonObserver.
-  virtual void OnShowLogoutButtonInTrayChanged(bool show) OVERRIDE;
-
- private:
-  tray::LogoutButton* logout_button_;
-
-  DISALLOW_COPY_AND_ASSIGN(TrayLogoutButton);
-};
-
-}  // namespace internal
-}  // namespace ash
-
-#endif  // ASH_SYSTEM_LOGOUT_BUTTON_TRAY_LOGOUT_BUTTON_H_
diff --git a/ash/system/session_length_limit/tray_session_length_limit.cc b/ash/system/session_length_limit/tray_session_length_limit.cc
index 1b2b944..c807446 100644
--- a/ash/system/session_length_limit/tray_session_length_limit.cc
+++ b/ash/system/session_length_limit/tray_session_length_limit.cc
@@ -23,6 +23,7 @@
 #include "grit/ash_strings.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/views/border.h"
@@ -66,8 +67,7 @@
     const base::TimeDelta& remaining_session_time) {
   return l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_REMAINING_SESSION_TIME_NOTIFICATION,
-      Shell::GetInstance()->system_tray_delegate()->
-          FormatTimeDuration(remaining_session_time));
+      ui::TimeFormat::TimeDurationLong(remaining_session_time));
 }
 
 }  // namespace
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index 147251c..19649b1 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -11,6 +11,7 @@
 #include "ash/shell_delegate.h"
 #include "ash/shell_window_ids.h"
 #include "ash/system/bluetooth/bluetooth_observer.h"
+#include "ash/system/logout_button/logout_button_tray.h"
 #include "ash/system/status_area_widget_delegate.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_delegate.h"
@@ -30,6 +31,7 @@
     : status_area_widget_delegate_(new internal::StatusAreaWidgetDelegate),
       system_tray_(NULL),
       web_notification_tray_(NULL),
+      logout_button_tray_(NULL),
       login_status_(user::LOGGED_IN_NONE) {
   views::Widget::InitParams params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
@@ -48,6 +50,7 @@
 void StatusAreaWidget::CreateTrayViews() {
   AddSystemTray();
   AddWebNotificationTray();
+  AddLogoutButtonTray();
   SystemTrayDelegate* delegate =
       ash::Shell::GetInstance()->system_tray_delegate();
   DCHECK(delegate);
@@ -56,6 +59,8 @@
     system_tray_->InitializeTrayItems(delegate);
   if (web_notification_tray_)
     web_notification_tray_->Initialize();
+  if (logout_button_tray_)
+    logout_button_tray_->Initialize();
   UpdateAfterLoginStatusChange(delegate->GetUserLoginStatus());
 }
 
@@ -63,6 +68,8 @@
   // Destroy the trays early, causing them to be removed from the view
   // hierarchy. Do not used scoped pointers since we don't want to destroy them
   // in the destructor if Shutdown() is not called (e.g. in tests).
+  delete logout_button_tray_;
+  logout_button_tray_ = NULL;
   delete web_notification_tray_;
   web_notification_tray_ = NULL;
   delete system_tray_;
@@ -107,12 +114,19 @@
   status_area_widget_delegate_->AddTray(web_notification_tray_);
 }
 
+void StatusAreaWidget::AddLogoutButtonTray() {
+  logout_button_tray_ = new LogoutButtonTray(this);
+  status_area_widget_delegate_->AddTray(logout_button_tray_);
+}
+
 void StatusAreaWidget::SetShelfAlignment(ShelfAlignment alignment) {
   status_area_widget_delegate_->set_alignment(alignment);
   if (system_tray_)
     system_tray_->SetShelfAlignment(alignment);
   if (web_notification_tray_)
     web_notification_tray_->SetShelfAlignment(alignment);
+  if (logout_button_tray_)
+    logout_button_tray_->SetShelfAlignment(alignment);
   status_area_widget_delegate_->UpdateLayout();
 }
 
@@ -121,10 +135,6 @@
     system_tray_->SetHideNotifications(hide);
 }
 
-bool StatusAreaWidget::ShouldShowWebNotifications() {
-  return !(system_tray_ && system_tray_->IsAnyBubbleVisible());
-}
-
 void StatusAreaWidget::UpdateAfterLoginStatusChange(
     user::LoginStatus login_status) {
   if (login_status_ == login_status)
@@ -134,6 +144,8 @@
     system_tray_->UpdateAfterLoginStatusChange(login_status);
   if (web_notification_tray_)
     web_notification_tray_->UpdateAfterLoginStatusChange(login_status);
+  if (logout_button_tray_)
+    logout_button_tray_->UpdateAfterLoginStatusChange(login_status);
 }
 
 }  // namespace internal
diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h
index 5283535..731eed1 100644
--- a/ash/system/status_area_widget.h
+++ b/ash/system/status_area_widget.h
@@ -18,6 +18,7 @@
 
 namespace internal {
 
+class LogoutButtonTray;
 class StatusAreaWidgetDelegate;
 
 class ASH_EXPORT StatusAreaWidget : public views::Widget {
@@ -27,7 +28,7 @@
   explicit StatusAreaWidget(aura::Window* status_container);
   virtual ~StatusAreaWidget();
 
-  // Creates the SystemTray and the WebNotificationTray.
+  // Creates the SystemTray, WebNotificationTray and LogoutButtonTray.
   void CreateTrayViews();
 
   // Destroys the system tray and web notification tray. Called before
@@ -40,9 +41,6 @@
   // Set the visibility of system notifications.
   void SetHideSystemNotifications(bool hide);
 
-  // Returns true if it is OK to show a non system notification.
-  bool ShouldShowWebNotifications();
-
   // Called by the client when the login status changes. Caches login_status
   // and calls UpdateAfterLoginStatusChange for the system tray and the web
   // notification tray.
@@ -72,11 +70,13 @@
  private:
   void AddSystemTray();
   void AddWebNotificationTray();
+  void AddLogoutButtonTray();
 
   // Weak pointers to View classes that are parented to StatusAreaWidget:
   internal::StatusAreaWidgetDelegate* status_area_widget_delegate_;
   SystemTray* system_tray_;
   WebNotificationTray* web_notification_tray_;
+  LogoutButtonTray* logout_button_tray_;
   user::LoginStatus login_status_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusAreaWidget);
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 122253f..47157ea 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -15,7 +15,6 @@
 #include "ash/system/date/tray_date.h"
 #include "ash/system/drive/tray_drive.h"
 #include "ash/system/ime/tray_ime.h"
-#include "ash/system/logout_button/tray_logout_button.h"
 #include "ash/system/monitor/tray_monitor.h"
 #include "ash/system/session_length_limit/tray_session_length_limit.h"
 #include "ash/system/status_area_widget.h"
@@ -147,7 +146,6 @@
 void SystemTray::CreateItems(SystemTrayDelegate* delegate) {
 #if !defined(OS_WIN)
   AddTrayItem(new internal::TraySessionLengthLimit(this));
-  AddTrayItem(new internal::TrayLogoutButton(this));
   // In multi-profile user mode we can have multiple user tiles.
   ash::Shell* shell = ash::Shell::GetInstance();
   int maximum_user_profiles =
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index ded6475..b37a643 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -36,7 +36,6 @@
 class UserObserver;
 #if defined(OS_CHROMEOS)
 class NetworkObserver;
-class SmsObserver;
 #endif
 
 class SystemTrayItem;
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index 0dcc07d..8b43562 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -111,7 +111,7 @@
 
 class VolumeControlDelegate;
 
-class SystemTrayDelegate {
+class ASH_EXPORT SystemTrayDelegate {
  public:
   virtual ~SystemTrayDelegate() {}
 
@@ -156,6 +156,9 @@
   // Shows settings.
   virtual void ShowSettings() = 0;
 
+  // Returns true if settings menu item should appear.
+  virtual bool ShouldShowSettings() = 0;
+
   // Shows the settings related to date, timezone etc.
   virtual void ShowDateSettings() = 0;
 
@@ -252,7 +255,8 @@
   virtual void GetDriveOperationStatusList(
       DriveOperationStatusList* list) = 0;
 
-  // Shows UI to configure or activate the network specified by |network_id|.
+  // Shows UI to configure or activate the network specified by |network_id|,
+  // which may include showing Payment or Portal UI when appropriate.
   virtual void ConfigureNetwork(const std::string& network_id) = 0;
 
   // Shows UI to enroll the network specified by |network_id| if appropriate,
@@ -271,7 +275,7 @@
   virtual void ShowMobileSimDialog() = 0;
 
   // Shows UI to setup a mobile network.
-  virtual void ShowMobileSetup(const std::string& network_id) = 0;
+  virtual void ShowMobileSetupDialog(const std::string& service_path) = 0;
 
   // Shows UI to connect to an unlisted wifi network.
   virtual void ShowOtherWifi() = 0;
@@ -288,16 +292,6 @@
   // Returns whether bluetooth is enabled.
   virtual bool GetBluetoothEnabled() = 0;
 
-  // Retrieves information about the carrier and locale specific |setup_url|.
-  // If none of the carrier info/setup URL cannot be retrieved, returns false.
-  // Note: |setup_url| is returned when carrier is not defined (no SIM card).
-  virtual bool GetCellularCarrierInfo(std::string* carrier_id,
-                                      std::string* topup_url,
-                                      std::string* setup_url) = 0;
-
-  // Opens the cellular network specific URL.
-  virtual void ShowCellularURL(const std::string& url) = 0;
-
   // Shows UI for changing proxy settings.
   virtual void ChangeProxySettings() = 0;
 
@@ -317,12 +311,6 @@
   // Get the system tray menu size in pixels (dependent on the language).
   virtual int GetSystemTrayMenuWidth() = 0;
 
-  // Returns the duration formatted as a localized string.
-  // TODO(stevenjb): Move TimeFormat from src/chrome to src/ui so that it can be
-  // accessed without going through the delegate. crbug.com/222697
-  virtual base::string16 FormatTimeDuration(
-      const base::TimeDelta& delta) const = 0;
-
   // Speaks the given text if spoken feedback is enabled.
   virtual void MaybeSpeak(const std::string& utterance) const = 0;
 
diff --git a/ash/system/tray/system_tray_notifier.cc b/ash/system/tray/system_tray_notifier.cc
index 73f6195..fde1e7d 100644
--- a/ash/system/tray/system_tray_notifier.cc
+++ b/ash/system/tray/system_tray_notifier.cc
@@ -140,14 +140,6 @@
   network_observers_.RemoveObserver(observer);
 }
 
-void SystemTrayNotifier::AddSmsObserver(SmsObserver* observer) {
-  sms_observers_.AddObserver(observer);
-}
-
-void SystemTrayNotifier::RemoveSmsObserver(SmsObserver* observer) {
-  sms_observers_.RemoveObserver(observer);
-}
-
 void SystemTrayNotifier::AddEnterpriseDomainObserver(
     EnterpriseDomainObserver* observer) {
   enterprise_domain_observers_.AddObserver(observer);
@@ -295,42 +287,12 @@
 
 #if defined(OS_CHROMEOS)
 
-void SystemTrayNotifier::NotifySetNetworkMessage(
-    NetworkTrayDelegate* delegate,
-    NetworkObserver::MessageType message_type,
-    NetworkObserver::NetworkType network_type,
-    const base::string16& title,
-    const base::string16& message,
-    const std::vector<base::string16>& links) {
-  FOR_EACH_OBSERVER(NetworkObserver,
-                    network_observers_,
-                    SetNetworkMessage(
-                        delegate,
-                        message_type,
-                        network_type,
-                        title,
-                        message,
-                        links));
-}
-
-void SystemTrayNotifier::NotifyClearNetworkMessage(
-    NetworkObserver::MessageType message_type) {
-  FOR_EACH_OBSERVER(NetworkObserver,
-                    network_observers_,
-                    ClearNetworkMessage(message_type));
-}
-
 void SystemTrayNotifier::NotifyRequestToggleWifi() {
   FOR_EACH_OBSERVER(NetworkObserver,
                     network_observers_,
                     RequestToggleWifi());
 }
 
-void SystemTrayNotifier::NotifyAddSmsMessage(
-    const base::DictionaryValue& message) {
-  FOR_EACH_OBSERVER(SmsObserver, sms_observers_, AddMessage(message));
-}
-
 void SystemTrayNotifier::NotifyEnterpriseDomainChanged() {
   FOR_EACH_OBSERVER(EnterpriseDomainObserver, enterprise_domain_observers_,
       OnEnterpriseDomainChanged());
diff --git a/ash/system/tray/system_tray_notifier.h b/ash/system/tray/system_tray_notifier.h
index 86210b4..3ca2189 100644
--- a/ash/system/tray/system_tray_notifier.h
+++ b/ash/system/tray/system_tray_notifier.h
@@ -11,9 +11,6 @@
 #include "ash/ash_export.h"
 #include "ash/system/bluetooth/bluetooth_observer.h"
 #include "ash/system/brightness/brightness_observer.h"
-#include "ash/system/chromeos/enterprise/enterprise_domain_observer.h"
-#include "ash/system/chromeos/network/network_observer.h"
-#include "ash/system/chromeos/network/sms_observer.h"
 #include "ash/system/chromeos/tray_tracing.h"
 #include "ash/system/date/clock_observer.h"
 #include "ash/system/drive/drive_observer.h"
@@ -28,8 +25,8 @@
 #include "base/observer_list.h"
 
 #if defined(OS_CHROMEOS)
+#include "ash/system/chromeos/enterprise/enterprise_domain_observer.h"
 #include "ash/system/chromeos/network/network_observer.h"
-#include "ash/system/chromeos/network/sms_observer.h"
 #include "ash/system/chromeos/screen_security/screen_capture_observer.h"
 #include "ash/system/chromeos/screen_security/screen_share_observer.h"
 #endif
@@ -88,9 +85,6 @@
   void AddNetworkObserver(NetworkObserver* observer);
   void RemoveNetworkObserver(NetworkObserver* observer);
 
-  void AddSmsObserver(SmsObserver* observer);
-  void RemoveSmsObserver(SmsObserver* observer);
-
   void AddEnterpriseDomainObserver(EnterpriseDomainObserver* observer);
   void RemoveEnterpriseDomainObserver(EnterpriseDomainObserver* observer);
 
@@ -123,15 +117,7 @@
   void NotifyUpdateRecommended(UpdateObserver::UpdateSeverity severity);
   void NotifyUserUpdate();
 #if defined(OS_CHROMEOS)
-  void NotifySetNetworkMessage(NetworkTrayDelegate* delegate,
-                               NetworkObserver::MessageType message_type,
-                               NetworkObserver::NetworkType network_type,
-                               const base::string16& title,
-                               const base::string16& message,
-                               const std::vector<base::string16>& links);
-  void NotifyClearNetworkMessage(NetworkObserver::MessageType message_type);
   void NotifyRequestToggleWifi();
-  void NotifyAddSmsMessage(const base::DictionaryValue& message);
   void NotifyEnterpriseDomainChanged();
   void NotifyScreenCaptureStart(const base::Closure& stop_callback,
                                 const base::string16& sharing_app_name);
@@ -161,7 +147,6 @@
   ObserverList<UserObserver> user_observers_;
 #if defined(OS_CHROMEOS)
   ObserverList<NetworkObserver> network_observers_;
-  ObserverList<SmsObserver> sms_observers_;
   ObserverList<EnterpriseDomainObserver> enterprise_domain_observers_;
   ObserverList<ScreenCaptureObserver> screen_capture_observers_;
   ObserverList<ScreenShareObserver> screen_share_observers_;
diff --git a/ash/system/tray/test_system_tray_delegate.cc b/ash/system/tray/test_system_tray_delegate.cc
index c3a2bfc..87ac92c 100644
--- a/ash/system/tray/test_system_tray_delegate.cc
+++ b/ash/system/tray/test_system_tray_delegate.cc
@@ -17,6 +17,8 @@
 
 namespace {
 
+user::LoginStatus g_initial_status = user::LOGGED_IN_USER;
+
 class TestVolumeControlDelegate : public VolumeControlDelegate {
  public:
   TestVolumeControlDelegate() {}
@@ -38,16 +40,28 @@
 
 }  // namespace
 
+// static
+void TestSystemTrayDelegate::SetInitialLoginStatus(
+    user::LoginStatus login_status) {
+  g_initial_status = login_status;
+}
+
 TestSystemTrayDelegate::TestSystemTrayDelegate()
     : bluetooth_enabled_(true),
       caps_lock_enabled_(false),
       should_show_display_notification_(false),
+      login_status_(g_initial_status),
       volume_control_delegate_(new TestVolumeControlDelegate) {
 }
 
 TestSystemTrayDelegate::~TestSystemTrayDelegate() {
 }
 
+void TestSystemTrayDelegate::SetLoginStatus(user::LoginStatus login_status) {
+  login_status_ = login_status;
+  Shell::GetInstance()->UpdateAfterLoginStatusChange(login_status);
+}
+
 void TestSystemTrayDelegate::Initialize() {
 }
 
@@ -60,6 +74,12 @@
 
 // Overridden from SystemTrayDelegate:
 user::LoginStatus TestSystemTrayDelegate::GetUserLoginStatus() const {
+  // Initial login status has been changed for testing.
+  if (g_initial_status != user::LOGGED_IN_USER &&
+      g_initial_status == login_status_) {
+    return login_status_;
+  }
+
   // At new user image screen manager->IsUserLoggedIn() would return true
   // but there's no browser session available yet so use SessionStarted().
   SessionStateDelegate* delegate =
@@ -69,9 +89,7 @@
     return ash::user::LOGGED_IN_NONE;
   if (delegate->IsScreenLocked())
     return user::LOGGED_IN_LOCKED;
-  // TODO(nkostylev): Support LOGGED_IN_OWNER, LOGGED_IN_GUEST, LOGGED_IN_KIOSK,
-  //                  LOGGED_IN_PUBLIC.
-  return user::LOGGED_IN_USER;
+  return login_status_;
 }
 
 bool TestSystemTrayDelegate::IsOobeCompleted() const {
@@ -114,6 +132,10 @@
 void TestSystemTrayDelegate::ShowSettings() {
 }
 
+bool TestSystemTrayDelegate::ShouldShowSettings() {
+  return true;
+}
+
 void TestSystemTrayDelegate::ShowDateSettings() {
 }
 
@@ -234,7 +256,8 @@
 void TestSystemTrayDelegate::ShowMobileSimDialog() {
 }
 
-void TestSystemTrayDelegate::ShowMobileSetup(const std::string& network_id) {
+void TestSystemTrayDelegate::ShowMobileSetupDialog(
+    const std::string& service_path) {
 }
 
 void TestSystemTrayDelegate::ShowOtherWifi() {
@@ -254,15 +277,6 @@
   return bluetooth_enabled_;
 }
 
-bool TestSystemTrayDelegate::GetCellularCarrierInfo(std::string* carrier_id,
-                                                    std::string* topup_url,
-                                                    std::string* setup_url) {
-  return false;
-}
-
-void TestSystemTrayDelegate::ShowCellularURL(const std::string& url) {
-}
-
 void TestSystemTrayDelegate::ChangeProxySettings() {
 }
 
@@ -291,11 +305,6 @@
   return 300;
 }
 
-base::string16 TestSystemTrayDelegate::FormatTimeDuration(
-    const base::TimeDelta& delta) const {
-  return base::string16();
-}
-
 void TestSystemTrayDelegate::MaybeSpeak(const std::string& utterance) const {
 }
 
diff --git a/ash/system/tray/test_system_tray_delegate.h b/ash/system/tray/test_system_tray_delegate.h
index 4dc847d..cd9affe 100644
--- a/ash/system/tray/test_system_tray_delegate.h
+++ b/ash/system/tray/test_system_tray_delegate.h
@@ -5,6 +5,7 @@
 #ifndef ASH_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_
 #define ASH_TEST_TEST_SYSTEM_TRAY_DELEGATE_H_
 
+#include "ash/ash_export.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
@@ -14,13 +15,26 @@
 namespace ash {
 namespace test {
 
-class TestSystemTrayDelegate : public SystemTrayDelegate {
+class ASH_EXPORT TestSystemTrayDelegate : public SystemTrayDelegate {
  public:
+  // Changes the login status when initially the delegate is created. This will
+  // be called before AshTestBase::SetUp() to test the case when chrome is
+  // restarted right after the login (such like a flag is set).
+  // This value will be reset in AshTestHelper::TearDown,  most test fixtures
+  // don't need to care its lifecycle.
+  static void SetInitialLoginStatus(user::LoginStatus login_status);
+
   TestSystemTrayDelegate();
 
   virtual ~TestSystemTrayDelegate();
 
- public:
+  // Changes the current login status in the test. This also invokes
+  // UpdateAfterLoginStatusChange(). Usually this is called in the test code to
+  // set up a login status. This will fit to most of the test cases, but this
+  // cannot be set during the initialization. To test the initialization,
+  // consider using SetInitialLoginStatus() instead.
+  void SetLoginStatus(user::LoginStatus login_status);
+
   virtual void Initialize() OVERRIDE;
   virtual void Shutdown() OVERRIDE;
   virtual bool GetTrayVisibilityOnStartup() OVERRIDE;
@@ -38,6 +52,7 @@
   virtual bool SystemShouldUpgrade() const OVERRIDE;
   virtual base::HourClockType GetHourClockType() const OVERRIDE;
   virtual void ShowSettings() OVERRIDE;
+  virtual bool ShouldShowSettings() OVERRIDE;
   virtual void ShowDateSettings() OVERRIDE;
   virtual void ShowNetworkSettings(const std::string& service_path) OVERRIDE;
   virtual void ShowBluetoothSettings() OVERRIDE;
@@ -77,16 +92,12 @@
   virtual void ToggleBluetooth() OVERRIDE;
   virtual bool IsBluetoothDiscovering() OVERRIDE;
   virtual void ShowMobileSimDialog() OVERRIDE;
-  virtual void ShowMobileSetup(const std::string& network_id) OVERRIDE;
+  virtual void ShowMobileSetupDialog(const std::string& service_path) OVERRIDE;
   virtual void ShowOtherWifi() OVERRIDE;
   virtual void ShowOtherVPN() OVERRIDE;
   virtual void ShowOtherCellular() OVERRIDE;
   virtual bool GetBluetoothAvailable() OVERRIDE;
   virtual bool GetBluetoothEnabled() OVERRIDE;
-  virtual bool GetCellularCarrierInfo(std::string* carrier_id,
-                                      std::string* topup_url,
-                                      std::string* setup_url) OVERRIDE;
-  virtual void ShowCellularURL(const std::string& url) OVERRIDE;
   virtual void ChangeProxySettings() OVERRIDE;
   virtual VolumeControlDelegate* GetVolumeControlDelegate() const OVERRIDE;
   virtual void SetVolumeControlDelegate(
@@ -96,8 +107,6 @@
   virtual bool GetSessionLengthLimit(
       base::TimeDelta* session_length_limit) OVERRIDE;
   virtual int GetSystemTrayMenuWidth() OVERRIDE;
-  virtual base::string16 FormatTimeDuration(
-      const base::TimeDelta& delta) const OVERRIDE;
   virtual void MaybeSpeak(const std::string& utterance) const OVERRIDE;
 
   void set_should_show_display_notification(bool should_show) {
@@ -108,6 +117,7 @@
   bool bluetooth_enabled_;
   bool caps_lock_enabled_;
   bool should_show_display_notification_;
+  user::LoginStatus login_status_;
   scoped_ptr<VolumeControlDelegate> volume_control_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(TestSystemTrayDelegate);
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 9f84322..a20e371 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -600,8 +600,9 @@
   ash::internal::ShelfLayoutManager* shelf =
       ShelfLayoutManager::ForLauncher(root_window);
   bubble_view->SetArrowPaintType(
-      shelf->IsVisible() ? views::BubbleBorder::PAINT_NORMAL :
-                           views::BubbleBorder::PAINT_TRANSPARENT);
+      (shelf && shelf->IsVisible()) ?
+      views::BubbleBorder::PAINT_NORMAL :
+      views::BubbleBorder::PAINT_TRANSPARENT);
 }
 
 }  // namespace internal
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index 4d57d5b..b0f2806 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -19,7 +19,8 @@
 class TrayEventFilter;
 class TrayBackground;
 
-// Base class for children of StatusAreaWidget: SystemTray, WebNotificationTray.
+// Base class for children of StatusAreaWidget: SystemTray, WebNotificationTray,
+// LogoutButtonTray.
 // This class handles setting and animating the background when the Launcher
 // his shown/hidden. It also inherits from ActionableView so that the tray
 // items can override PerformAction when clicked on.
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc
index 6d108c8..6d4b2e6 100644
--- a/ash/system/tray/tray_constants.cc
+++ b/ash/system/tray/tray_constants.cc
@@ -67,12 +67,17 @@
      (kTrayPopupPaddingHorizontal / 2) * 3);
 const int kTraySpacing = 8;
 const int kAlternateTraySpacing = 4;
+const int kShelfItemHeight = 31;
+const int kAlternateShelfItemHeight = 38;
 
-// Returns kTraySpacing or kAlternateTraySpacing as applicable
-// (Determined by ash::switches::UseAlternateShelfLayout).
 int GetTraySpacing() {
   return ash::switches::UseAlternateShelfLayout() ?
       kAlternateTraySpacing : kTraySpacing;
 }
 
+int GetShelfItemHeight() {
+  return ash::switches::UseAlternateShelfLayout() ?
+      kAlternateShelfItemHeight : kShelfItemHeight;
+}
+
 }  // namespace ash
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index 480d5d5..50b2210 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -66,6 +66,10 @@
 // (Determined by ash::switches::UseAlternateShelfLayout).
 int GetTraySpacing();
 
+// Returns kShelfItemHeight or kAlternateShelfItemHeight as applicable
+// (Determined by ash::switches::UseAlternateShelfLayout).
+int GetShelfItemHeight();
+
 }  // namespace ash
 
 #endif  // ASH_SYSTEM_TRAY_TRAY_CONSTANTS_H_
diff --git a/ash/system/tray/tray_image_item.cc b/ash/system/tray/tray_image_item.cc
index d4ff904..7c5e216 100644
--- a/ash/system/tray/tray_image_item.cc
+++ b/ash/system/tray/tray_image_item.cc
@@ -4,12 +4,13 @@
 
 #include "ash/system/tray/tray_image_item.h"
 
+#include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/tray_item_view.h"
 #include "ash/system/tray/tray_utils.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 #include "ui/views/controls/image_view.h"
-#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/box_layout.h"
 
 namespace ash {
 namespace internal {
@@ -41,6 +42,7 @@
   tray_view_->image_view()->SetImage(ui::ResourceBundle::GetSharedInstance().
       GetImageNamed(resource_id_).ToImageSkia());
   tray_view_->SetVisible(GetInitialVisibility());
+  SetItemAlignment(system_tray()->shelf_alignment());
   return tray_view_;
 }
 
@@ -57,6 +59,7 @@
 
 void TrayImageItem::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
   SetTrayImageItemBorder(tray_view_, alignment);
+  SetItemAlignment(alignment);
 }
 
 void TrayImageItem::DestroyTrayView() {
@@ -69,5 +72,22 @@
 void TrayImageItem::DestroyDetailedView() {
 }
 
+void TrayImageItem::SetItemAlignment(ShelfAlignment alignment) {
+  // Center the item dependent on the orientation of the shelf.
+  views::BoxLayout::Orientation layout = views::BoxLayout::kHorizontal;
+  switch (alignment) {
+    case ash::SHELF_ALIGNMENT_BOTTOM:
+    case ash::SHELF_ALIGNMENT_TOP:
+      layout = views::BoxLayout::kHorizontal;
+      break;
+    case ash::SHELF_ALIGNMENT_LEFT:
+    case ash::SHELF_ALIGNMENT_RIGHT:
+      layout = views::BoxLayout::kVertical;
+      break;
+  }
+  tray_view_->SetLayoutManager(new views::BoxLayout(layout, 0, 0, 0));
+  tray_view_->Layout();
+}
+
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/system/tray/tray_image_item.h b/ash/system/tray/tray_image_item.h
index ebaf30e..6dea5c8 100644
--- a/ash/system/tray/tray_image_item.h
+++ b/ash/system/tray/tray_image_item.h
@@ -41,6 +41,9 @@
       ShelfAlignment alignment) OVERRIDE;
 
  private:
+  // Set the alignment of the image depending on the shelf alignment.
+  void SetItemAlignment(ShelfAlignment alignment);
+
   int resource_id_;
   TrayItemView* tray_view_;
 
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
index 2ab24a8..42bb55a 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/system/user/tray_user.cc
@@ -10,7 +10,9 @@
 
 #include "ash/ash_switches.h"
 #include "ash/popup_message.h"
+#include "ash/root_window_controller.h"
 #include "ash/session_state_delegate.h"
+#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/system/tray/system_tray.h"
@@ -759,11 +761,6 @@
 }
 
 void UserView::AddLogoutButton(ash::user::LoginStatus login) {
-  // A user should not be able to modify logged-in state when screen is
-  // locked.
-  if (login == ash::user::LOGGED_IN_LOCKED)
-    return;
-
   const base::string16 title = ash::user::GetLocalizedSignOutStringForStatus(
       login, true);
   TrayPopupLabelButton* logout_button = new TrayPopupLabelButton(this, title);
@@ -1170,7 +1167,7 @@
       need_label = true;
       break;
     case user::LOGGED_IN_GUEST:
-      need_avatar = true;
+      need_label = true;
       break;
     case user::LOGGED_IN_RETAIL_MODE:
     case user::LOGGED_IN_KIOSK_APP:
@@ -1200,6 +1197,8 @@
   if (status == user::LOGGED_IN_LOCALLY_MANAGED) {
     label_->SetText(
         bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_LOCALLY_MANAGED_LABEL));
+  } else if (status == user::LOGGED_IN_GUEST) {
+    label_->SetText(bundle.GetLocalizedString(IDS_ASH_STATUS_TRAY_GUEST_LABEL));
   }
 
   if (avatar_ && ash::switches::UseAlternateShelfLayout()) {
@@ -1210,6 +1209,12 @@
     avatar_->set_border(NULL);
   }
   UpdateAvatarImage(status);
+
+  // Update layout after setting label_ and avatar_ with new login status.
+  if (Shell::GetPrimaryRootWindowController()->shelf())
+    UpdateAfterShelfAlignmentChange(
+        Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
+            GetAlignment());
 }
 
 void TrayUser::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment) {
@@ -1276,19 +1281,10 @@
   int icon_size = ash::switches::UseAlternateShelfLayout() ?
       kUserIconLargeSize : kUserIconSize;
 
-  if (status == user::LOGGED_IN_GUEST) {
-    int image_name = ash::switches::UseAlternateShelfLayout() ?
-        IDR_AURA_UBER_TRAY_GUEST_ICON_LARGE :
-        IDR_AURA_UBER_TRAY_GUEST_ICON;
-    avatar_->SetImage(*ui::ResourceBundle::GetSharedInstance().
-        GetImageNamed(image_name).ToImageSkia(),
-        gfx::Size(icon_size, icon_size));
-  } else {
-    avatar_->SetImage(
-        ash::Shell::GetInstance()->session_state_delegate()->GetUserImage(
-            multiprofile_index_),
-        gfx::Size(icon_size, icon_size));
-  }
+  avatar_->SetImage(
+      ash::Shell::GetInstance()->session_state_delegate()->GetUserImage(
+          multiprofile_index_),
+      gfx::Size(icon_size, icon_size));
 }
 
 }  // namespace internal
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index 2a6e2de..08e1904 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -58,10 +58,6 @@
 namespace internal {
 namespace {
 
-const int kWebNotificationIconSize = 31;
-// Height of the art assets used in alternate shelf layout,
-// see ash/ash_switches.h:UseAlternateShelfLayout.
-const int kWebNotificationAlternateSize = 38;
 const SkColor kWebNotificationColorNoUnread = SkColorSetA(SK_ColorWHITE, 128);
 const SkColor kWebNotificationColorWithUnread = SK_ColorWHITE;
 
@@ -72,12 +68,18 @@
 class WorkAreaObserver : public ShelfLayoutManagerObserver,
                          public ShellObserver {
  public:
-  WorkAreaObserver(message_center::MessagePopupCollection* collection,
-                   ShelfLayoutManager* shelf);
+  WorkAreaObserver();
   virtual ~WorkAreaObserver();
 
   void SetSystemTrayHeight(int height);
 
+  // Starts observing |shelf| and shell and sends the change to |collection|.
+  void StartObserving(message_center::MessagePopupCollection* collection,
+                      aura::RootWindow* root_window);
+
+  // Stops the observing session.
+  void StopObserving();
+
   // Overridden from ShellObserver:
   virtual void OnDisplayWorkAreaInsetsChanged() OVERRIDE;
 
@@ -85,38 +87,71 @@
   virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) OVERRIDE;
 
  private:
+  // Updates |shelf_| from |root_window_|.
+  void UpdateShelf();
+
   message_center::MessagePopupCollection* collection_;
+  aura::RootWindow* root_window_;
   ShelfLayoutManager* shelf_;
   int system_tray_height_;
 
   DISALLOW_COPY_AND_ASSIGN(WorkAreaObserver);
 };
 
-WorkAreaObserver::WorkAreaObserver(
-    message_center::MessagePopupCollection* collection,
-    ShelfLayoutManager* shelf)
-    : collection_(collection),
-      shelf_(shelf),
+WorkAreaObserver::WorkAreaObserver()
+    : collection_(NULL),
+      root_window_(NULL),
+      shelf_(NULL),
       system_tray_height_(0) {
-  DCHECK(collection_);
-  shelf_->AddObserver(this);
-  Shell::GetInstance()->AddShellObserver(this);
 }
 
 WorkAreaObserver::~WorkAreaObserver() {
-  Shell::GetInstance()->RemoveShellObserver(this);
-  shelf_->RemoveObserver(this);
+  StopObserving();
 }
 
 void WorkAreaObserver::SetSystemTrayHeight(int height) {
   system_tray_height_ = height;
+
+  // If the shelf is shown during auto-hide state, the distance from the edge
+  // should be reduced by the height of shelf's shown height.
+  if (shelf_ && shelf_->visibility_state() == SHELF_AUTO_HIDE &&
+      shelf_->auto_hide_state() == SHELF_AUTO_HIDE_SHOWN) {
+    system_tray_height_ -= ShelfLayoutManager::GetPreferredShelfSize() -
+        ShelfLayoutManager::kAutoHideSize;
+  }
+
   if (system_tray_height_ > 0 && ash::switches::UseAlternateShelfLayout())
     system_tray_height_ += message_center::kMarginBetweenItems;
 
+  if (!shelf_)
+    return;
+
   OnAutoHideStateChanged(shelf_->auto_hide_state());
 }
 
+void WorkAreaObserver::StartObserving(
+    message_center::MessagePopupCollection* collection,
+    aura::RootWindow* root_window) {
+  DCHECK(collection);
+  collection_ = collection;
+  root_window_ = root_window;
+  UpdateShelf();
+  Shell::GetInstance()->AddShellObserver(this);
+  if (system_tray_height_ > 0)
+    OnAutoHideStateChanged(shelf_->auto_hide_state());
+}
+
+void WorkAreaObserver::StopObserving() {
+  Shell::GetInstance()->RemoveShellObserver(this);
+  if (shelf_)
+    shelf_->RemoveObserver(this);
+  collection_ = NULL;
+  shelf_ = NULL;
+}
+
 void WorkAreaObserver::OnDisplayWorkAreaInsetsChanged() {
+  UpdateShelf();
+
   collection_->OnDisplayBoundsChanged(
       Shell::GetScreen()->GetDisplayNearestWindow(
           shelf_->shelf_widget()->GetNativeView()));
@@ -127,47 +162,36 @@
       shelf_->shelf_widget()->GetNativeView());
   gfx::Rect work_area = display.work_area();
   int width = 0;
-  if (shelf_->auto_hide_behavior() != SHELF_AUTO_HIDE_BEHAVIOR_NEVER) {
-    width = (new_state == SHELF_AUTO_HIDE_HIDDEN) ?
-        ShelfLayoutManager::kAutoHideSize :
-        ShelfLayoutManager::GetPreferredShelfSize();
+  if ((shelf_->visibility_state() == SHELF_AUTO_HIDE) &&
+      new_state == SHELF_AUTO_HIDE_SHOWN) {
+    // Since the work_area is already reduced by kAutoHideSize, the inset width
+    // should be just the difference.
+    width = ShelfLayoutManager::GetPreferredShelfSize() -
+        ShelfLayoutManager::kAutoHideSize;
   }
-  switch (shelf_->GetAlignment()) {
-    case SHELF_ALIGNMENT_BOTTOM:
-      work_area.Inset(0, 0, 0, width);
-      if (system_tray_height_ > 0) {
-        work_area.set_height(
-            std::max(0, work_area.height() - system_tray_height_));
-      }
-      break;
-    case SHELF_ALIGNMENT_LEFT:
-      work_area.Inset(width, 0, 0, 0);
-      // Popups appear on the left bottom only when UI is RTL.
-      if (base::i18n::IsRTL() && system_tray_height_ > 0) {
-        work_area.set_height(
-            std::max(0, work_area.height() - system_tray_height_));
-      }
-      break;
-    case SHELF_ALIGNMENT_RIGHT:
-      work_area.Inset(0, 0, width, 0);
-      // Popups appear on the right bottom only when UI isn't RTL.
-      if (!base::i18n::IsRTL() && system_tray_height_ > 0) {
-        work_area.set_height(
-            std::max(0, work_area.height() - system_tray_height_));
-      }
-      break;
-    case SHELF_ALIGNMENT_TOP:
-      work_area.Inset(0, width, 0, 0);
-      if (system_tray_height_ > 0) {
-        work_area.set_y(work_area.y() + system_tray_height_);
-        work_area.set_height(
-            std::max(0, work_area.height() - system_tray_height_));
-      }
-      break;
+  work_area.Inset(shelf_->SelectValueForShelfAlignment(
+      gfx::Insets(0, 0, width, 0),
+      gfx::Insets(0, width, 0, 0),
+      gfx::Insets(0, 0, 0, width),
+      gfx::Insets(width, 0, 0, 0)));
+  if (system_tray_height_ > 0) {
+    work_area.set_height(
+        std::max(0, work_area.height() - system_tray_height_));
+    if (shelf_->GetAlignment() == SHELF_ALIGNMENT_TOP)
+      work_area.set_y(work_area.y() + system_tray_height_);
   }
   collection_->SetDisplayInfo(work_area, display.bounds());
 }
 
+void WorkAreaObserver::UpdateShelf() {
+  if (shelf_)
+    return;
+
+  shelf_ = ShelfLayoutManager::ForLauncher(root_window_);
+  if (shelf_)
+    shelf_->AddObserver(this);
+}
+
 // Class to initialize and manage the WebNotificationBubble and
 // TrayBubbleWrapper instances for a bubble.
 class WebNotificationBubbleWrapper {
@@ -241,10 +265,12 @@
  protected:
   // Overridden from views::ImageButton:
   virtual gfx::Size GetPreferredSize() OVERRIDE {
-    if (ash::switches::UseAlternateShelfLayout())
-      return gfx::Size(kWebNotificationAlternateSize,
-                       kWebNotificationAlternateSize);
-    return gfx::Size(kWebNotificationIconSize, kWebNotificationIconSize);
+    const int notification_item_size = GetShelfItemHeight();
+    return gfx::Size(notification_item_size, notification_item_size);
+  }
+
+  virtual int GetHeightForWidth(int width) OVERRIDE {
+    return GetPreferredSize().height();
   }
 
  private:
@@ -282,6 +308,7 @@
   message_center_tray_.reset(new message_center::MessageCenterTray(
       this,
       message_center::MessageCenter::Get()));
+  work_area_observer_.reset(new internal::WorkAreaObserver());
   OnMessageCenterTrayChanged();
 }
 
@@ -359,15 +386,12 @@
 }
 
 void WebNotificationTray::SetSystemTrayHeight(int height) {
-  if (!work_area_observer_)
-    return;
   work_area_observer_->SetSystemTrayHeight(height);
 }
 
 bool WebNotificationTray::ShowPopups() {
   if (status_area_widget()->login_status() == user::LOGGED_IN_LOCKED ||
-      message_center_bubble() ||
-      !status_area_widget()->ShouldShowWebNotifications()) {
+      message_center_bubble()) {
     return false;
   }
 
@@ -378,14 +402,14 @@
       message_center(),
       message_center_tray_.get(),
       ash::switches::UseAlternateShelfLayout()));
-  work_area_observer_.reset(new internal::WorkAreaObserver(
-      popup_collection_.get(), GetShelfLayoutManager()));
+  work_area_observer_->StartObserving(
+      popup_collection_.get(), GetWidget()->GetNativeView()->GetRootWindow());
   return true;
 }
 
 void WebNotificationTray::HidePopups() {
   popup_collection_.reset();
-  work_area_observer_.reset();
+  work_area_observer_->StopObserving();
 }
 
 // Private methods.
diff --git a/ash/system/web_notification/web_notification_tray.h b/ash/system/web_notification/web_notification_tray.h
index d8b2fd3..1fb9c4d 100644
--- a/ash/system/web_notification/web_notification_tray.h
+++ b/ash/system/web_notification/web_notification_tray.h
@@ -124,6 +124,7 @@
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, ManyPopupNotifications);
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupShownOnBothDisplays);
   FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupAndSystemTray);
+  FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, PopupAndAutoHideShelf);
 
   void UpdateTrayContent();
 
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc
index 026500f..5b67b7d 100644
--- a/ash/system/web_notification/web_notification_tray_unittest.cc
+++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -16,8 +16,14 @@
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/system/tray/test_system_tray_delegate.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/wm/window_properties.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/screen.h"
 #include "ui/message_center/message_center_style.h"
 #include "ui/message_center/message_center_tray.h"
 #include "ui/message_center/message_center_util.h"
@@ -144,6 +150,10 @@
     return tray->popup_collection_->work_area_;
   }
 
+  bool IsPopupVisible() {
+    return GetTray()->IsPopupVisible();
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(WebNotificationTrayTest);
 };
@@ -294,8 +304,12 @@
 // RootWindow's bound can be bigger than gfx::Display's work area so that
 // openingsystem tray doesn't affect at all the work area of popups.
 #define MAYBE_PopupAndSystemTray PopupAndSystemTray
+#define MAYBE_PopupAndAutoHideShelf PopupAndAutoHideShelf
+#define MAYBE_PopupAndFullscreen PopupAndFullscreen
 #else
 #define MAYBE_PopupAndSystemTray DISABLED_PopupAndSystemTray
+#define MAYBE_PopupAndAutoHideShelf DISABLED_PopupAndAutoHideShelf
+#define MAYBE_PopupAndFullscreen DISABLED_PopupAndFullscreen
 #endif
 
 TEST_F(WebNotificationTrayTest, MAYBE_PopupAndSystemTray) {
@@ -332,22 +346,115 @@
   EXPECT_LT(work_area_with_tray_notificaiton.size().GetArea(),
             work_area_with_notification.size().GetArea());
 
-  // Close the notifications.
+  // Close the system tray notifications.
   GetSystemTray()->HideNotificationView(test_item);
   EXPECT_TRUE(GetTray()->IsPopupVisible());
   EXPECT_EQ(work_area.ToString(), GetPopupWorkArea().ToString());
 }
 
-TEST_F(WebNotificationTrayTest, PopupAndSystemTrayAlignment) {
-  Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
-      SetAlignment(SHELF_ALIGNMENT_LEFT);
+TEST_F(WebNotificationTrayTest, MAYBE_PopupAndAutoHideShelf) {
   AddNotification("test_id");
+  EXPECT_TRUE(GetTray()->IsPopupVisible());
   gfx::Rect work_area = GetPopupWorkArea();
 
-  // System tray is created, but the work area is not affected since the tray
-  // appears at the left-bottom while the popups appear at the right bottom.
+  // Shelf's auto-hide state won't be HIDDEN unless window exists.
+  scoped_ptr<aura::Window> window(
+      CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
+  internal::ShelfLayoutManager* shelf =
+      Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
+  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+  gfx::Rect work_area_auto_hidden = GetPopupWorkArea();
+  EXPECT_LT(work_area.size().GetArea(), work_area_auto_hidden.size().GetArea());
+
+  // Close the window, which shows the shelf.
+  window.reset();
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+  gfx::Rect work_area_auto_shown = GetPopupWorkArea();
+  EXPECT_EQ(work_area.ToString(), work_area_auto_shown.ToString());
+
+  // Create the system tray during auto-hide.
+  window.reset(CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
+  TestItem* test_item = new TestItem;
+  GetSystemTray()->AddTrayItem(test_item);
   GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW);
+
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+  EXPECT_TRUE(GetTray()->IsPopupVisible());
+  gfx::Rect work_area_with_tray = GetPopupWorkArea();
+  EXPECT_GT(work_area_auto_shown.size().GetArea(),
+            work_area_with_tray.size().GetArea());
+
+  // Create tray notification.
+  GetSystemTray()->ShowNotificationView(test_item);
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+  gfx::Rect work_area_with_tray_notification = GetPopupWorkArea();
+  EXPECT_GT(work_area_with_tray.size().GetArea(),
+            work_area_with_tray_notification.size().GetArea());
+
+  // Close the system tray.
+  GetSystemTray()->ClickedOutsideBubble();
+  shelf->UpdateAutoHideState();
+  RunAllPendingInMessageLoop();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+  gfx::Rect work_area_hidden_with_tray_notification = GetPopupWorkArea();
+  EXPECT_LT(work_area_with_tray_notification.size().GetArea(),
+            work_area_hidden_with_tray_notification.size().GetArea());
+  EXPECT_GT(work_area_auto_hidden.size().GetArea(),
+            work_area_hidden_with_tray_notification.size().GetArea());
+
+  // Close the window again, which shows the shelf.
+  window.reset();
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+  gfx::Rect work_area_shown_with_tray_notification = GetPopupWorkArea();
+  EXPECT_GT(work_area_hidden_with_tray_notification.size().GetArea(),
+            work_area_shown_with_tray_notification.size().GetArea());
+  EXPECT_GT(work_area_auto_shown.size().GetArea(),
+            work_area_shown_with_tray_notification.size().GetArea());
+}
+
+TEST_F(WebNotificationTrayTest, MAYBE_PopupAndFullscreen) {
+  AddNotification("test_id");
+  EXPECT_TRUE(IsPopupVisible());
+  gfx::Rect work_area = GetPopupWorkArea();
+
+  // Checks the work area for normal auto-hidden state.
+  scoped_ptr<aura::Window> window(
+      CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
+  internal::ShelfLayoutManager* shelf =
+      Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
+  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+  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);
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
+  RunAllPendingInMessageLoop();
+
+  // The work area for auto-hidden status of fullscreen is a bit larger
+  // since it doesn't even have the 3-pixel width.
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+  gfx::Rect work_area_fullscreen_hidden = GetPopupWorkArea();
+  EXPECT_EQ(work_area_auto_hidden.ToString(),
+            work_area_fullscreen_hidden.ToString());
+
+  // Move the mouse cursor at the bottom, which shows the shelf.
+  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  gfx::Point bottom_right =
+      Shell::GetScreen()->GetPrimaryDisplay().bounds().bottom_right();
+  bottom_right.Offset(-1, -1);
+  generator.MoveMouseTo(bottom_right);
+  shelf->UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
   EXPECT_EQ(work_area.ToString(), GetPopupWorkArea().ToString());
+
+  generator.MoveMouseTo(work_area.CenterPoint());
+  shelf->UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+  EXPECT_EQ(work_area_auto_hidden.ToString(), GetPopupWorkArea().ToString());
 }
 
 TEST_F(WebNotificationTrayTest, MAYBE_PopupAndSystemTrayMultiDisplay) {
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 45a1740..b7391e3 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -6,6 +6,7 @@
 
 #include "ash/ash_switches.h"
 #include "ash/shell.h"
+#include "ash/system/tray/test_system_tray_delegate.h"
 #include "ash/test/display_manager_test_api.h"
 #include "ash/test/shell_test_api.h"
 #include "ash/test/test_session_state_delegate.h"
@@ -15,9 +16,11 @@
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/message_center/message_center.h"
+#include "ui/views/corewm/capture_controller.h"
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/audio/cras_audio_handler.h"
+#include "chromeos/network/network_handler.h"
 #endif
 
 #if defined(USE_X11)
@@ -29,7 +32,8 @@
 
 AshTestHelper::AshTestHelper(base::MessageLoopForUI* message_loop)
     : message_loop_(message_loop),
-      test_shell_delegate_(NULL) {
+      test_shell_delegate_(NULL),
+      tear_down_network_handler_(false) {
   CHECK(message_loop_);
 #if defined(USE_X11)
   aura::test::SetUseOverrideRedirectWindowByDefault(true);
@@ -56,8 +60,16 @@
   // Create CrasAudioHandler for testing since g_browser_process is not
   // created in AshTestBase tests.
   chromeos::CrasAudioHandler::InitializeForTesting();
-#endif
 
+  // Some tests may not initialize NetworkHandler. Initialize it here if that
+  // is the case.
+  if (!chromeos::NetworkHandler::IsInitialized()) {
+    tear_down_network_handler_ = true;
+    chromeos::NetworkHandler::Initialize();
+  }
+
+  RunAllPendingInMessageLoop();
+#endif
   ash::Shell::CreateInstance(test_shell_delegate_);
   Shell* shell = Shell::GetInstance();
   if (start_session) {
@@ -80,13 +92,20 @@
   message_center::MessageCenter::Shutdown();
 
 #if defined(OS_CHROMEOS)
+  if (tear_down_network_handler_ && chromeos::NetworkHandler::IsInitialized())
+    chromeos::NetworkHandler::Shutdown();
   chromeos::CrasAudioHandler::Shutdown();
 #endif
 
   aura::Env::DeleteInstance();
 
+  // Need to reset the initial login status.
+  TestSystemTrayDelegate::SetInitialLoginStatus(user::LOGGED_IN_USER);
+
   ui::ShutdownInputMethodForTesting();
   zero_duration_mode_.reset();
+
+  CHECK(!views::corewm::ScopedCaptureClient::IsActive());
 }
 
 void AshTestHelper::RunAllPendingInMessageLoop() {
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index f4d7706..196567e 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -55,6 +55,9 @@
   TestShellDelegate* test_shell_delegate_;  // Owned by ash::Shell.
   scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_;
 
+  // true, if NetworkHandler was initialized by this instance.
+  bool tear_down_network_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(AshTestHelper);
 };
 
diff --git a/ash/test/test_launcher_delegate.cc b/ash/test/test_launcher_delegate.cc
index 0830d32..ed3e517 100644
--- a/ash/test/test_launcher_delegate.cc
+++ b/ash/test/test_launcher_delegate.cc
@@ -126,10 +126,6 @@
 void TestLauncherDelegate::OnLauncherDestroyed(Launcher* launcher) {
 }
 
-bool TestLauncherDelegate::IsPerAppLauncher() {
-  return true;
-}
-
 LauncherID TestLauncherDelegate::GetLauncherIDForAppID(
     const std::string& app_id) {
   return 0;
diff --git a/ash/test/test_launcher_delegate.h b/ash/test/test_launcher_delegate.h
index 6214b8d..06d0cde 100644
--- a/ash/test/test_launcher_delegate.h
+++ b/ash/test/test_launcher_delegate.h
@@ -51,7 +51,6 @@
   virtual bool ShouldShowTooltip(const LauncherItem& item) OVERRIDE;
   virtual void OnLauncherCreated(Launcher* launcher) OVERRIDE;
   virtual void OnLauncherDestroyed(Launcher* launcher) OVERRIDE;
-  virtual bool IsPerAppLauncher() OVERRIDE;
   virtual LauncherID GetLauncherIDForAppID(const std::string& app_id) OVERRIDE;
   virtual void PinAppWithID(const std::string& app_id) OVERRIDE;
   virtual bool IsAppPinned(const std::string& app_id) OVERRIDE;
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc
index f7b1eaa..bdbdfc8 100644
--- a/ash/test/test_shell_delegate.cc
+++ b/ash/test/test_shell_delegate.cc
@@ -8,6 +8,7 @@
 
 #include "ash/caps_lock_delegate_stub.h"
 #include "ash/host/root_window_host_factory.h"
+#include "ash/keyboard_controller_proxy_stub.h"
 #include "ash/session_state_delegate.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
@@ -87,7 +88,7 @@
 
 keyboard::KeyboardControllerProxy*
     TestShellDelegate::CreateKeyboardControllerProxy() {
-  return NULL;
+  return new KeyboardControllerProxyStub();
 }
 
 void TestShellDelegate::ShowTaskManager() {
diff --git a/ash/touch/touch_observer_hud.cc b/ash/touch/touch_observer_hud.cc
index 3daeba6..9dcccd3 100644
--- a/ash/touch/touch_observer_hud.cc
+++ b/ash/touch/touch_observer_hud.cc
@@ -104,7 +104,8 @@
 }
 
 #if defined(OS_CHROMEOS)
-void TouchObserverHUD::OnDisplayModeChanged() {
+void TouchObserverHUD::OnDisplayModeChanged(
+    const std::vector<chromeos::OutputConfigurator::OutputSnapshot>& outputs) {
   // Clear touch HUD for any change in display mode (single, dual extended, dual
   // mirrored, ...).
   Clear();
diff --git a/ash/touch/touch_observer_hud.h b/ash/touch/touch_observer_hud.h
index 850bc5e..70e23a7 100644
--- a/ash/touch/touch_observer_hud.h
+++ b/ash/touch/touch_observer_hud.h
@@ -67,7 +67,9 @@
 
 #if defined(OS_CHROMEOS)
   // Overriden from chromeos::OutputConfigurator::Observer.
-  virtual void OnDisplayModeChanged() OVERRIDE;
+  virtual void OnDisplayModeChanged(
+      const std::vector<chromeos::OutputConfigurator::OutputSnapshot>& outputs)
+      OVERRIDE;
 #endif  // defined(OS_CHROMEOS)
 
   // Overriden form DisplayController::Observer.
diff --git a/ash/wm/ash_native_cursor_manager_unittest.cc b/ash/wm/ash_native_cursor_manager_unittest.cc
index bd748ed..8e1de2e 100644
--- a/ash/wm/ash_native_cursor_manager_unittest.cc
+++ b/ash/wm/ash_native_cursor_manager_unittest.cc
@@ -72,7 +72,7 @@
   EXPECT_TRUE(test_api.GetCurrentCursor().platform());
 
   cursor_manager->LockCursor();
-  EXPECT_TRUE(cursor_manager->is_cursor_locked());
+  EXPECT_TRUE(cursor_manager->IsCursorLocked());
 
   // Cusror scale does change even while cursor is locked.
   EXPECT_EQ(2.5f, test_api.GetCurrentScale());
@@ -93,7 +93,7 @@
   EXPECT_EQ(gfx::Display::ROTATE_180, test_api.GetDisplay().rotation());
 
   cursor_manager->UnlockCursor();
-  EXPECT_FALSE(cursor_manager->is_cursor_locked());
+  EXPECT_FALSE(cursor_manager->IsCursorLocked());
 
   // Cursor type changes to the one specified while cursor is locked.
   EXPECT_EQ(1.5f, test_api.GetCurrentScale());
diff --git a/ash/wm/boot_splash_screen.cc b/ash/wm/boot_splash_screen.cc
deleted file mode 100644
index 202ebe2..0000000
--- a/ash/wm/boot_splash_screen.cc
+++ /dev/null
@@ -1,75 +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 "ash/wm/boot_splash_screen.h"
-
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/aura/root_window.h"
-#include "ui/compositor/layer.h"
-#include "ui/compositor/layer_type.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/gfx/canvas.h"
-
-namespace ash {
-namespace internal {
-
-// ui::LayerDelegate that copies the aura host window's content to a ui::Layer.
-class BootSplashScreen::CopyHostContentLayerDelegate
-    : public ui::LayerDelegate {
- public:
-  explicit CopyHostContentLayerDelegate(aura::RootWindow* root_window)
-      : root_window_(root_window) {
-  }
-
-  virtual ~CopyHostContentLayerDelegate() {}
-
-  // ui::LayerDelegate overrides:
-  virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
-    // It'd be safer to copy the area to a canvas in the constructor and then
-    // copy from that canvas to this one here, but this appears to work (i.e. we
-    // only call this before we draw our first frame) and it saves us an extra
-    // copy.
-    // TODO(derat): Instead of copying the data, use GLX_EXT_texture_from_pixmap
-    // to create a zero-copy texture (when possible):
-    // https://codereview.chromium.org/10543125
-    root_window_->CopyAreaToSkCanvas(
-        gfx::Rect(root_window_->GetHostOrigin(), root_window_->GetHostSize()),
-        gfx::Point(), canvas->sk_canvas());
-  }
-
-  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
-
-  virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
-    return base::Closure();
-  }
-
- private:
-  aura::RootWindow* root_window_;  // not owned
-
-  DISALLOW_COPY_AND_ASSIGN(CopyHostContentLayerDelegate);
-};
-
-BootSplashScreen::BootSplashScreen(aura::RootWindow* root_window)
-    : layer_delegate_(new CopyHostContentLayerDelegate(root_window)),
-      layer_(new ui::Layer(ui::LAYER_TEXTURED)) {
-  layer_->set_delegate(layer_delegate_.get());
-
-  ui::Layer* root_layer = root_window->layer();
-  layer_->SetBounds(gfx::Rect(root_layer->bounds().size()));
-  root_layer->Add(layer_.get());
-  root_layer->StackAtTop(layer_.get());
-}
-
-BootSplashScreen::~BootSplashScreen() {
-}
-
-void BootSplashScreen::StartHideAnimation(base::TimeDelta duration) {
-  ui::ScopedLayerAnimationSettings settings(layer_->GetAnimator());
-  settings.SetTransitionDuration(duration);
-  settings.SetPreemptionStrategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
-  layer_->SetOpacity(0.0f);
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/wm/boot_splash_screen.h b/ash/wm/boot_splash_screen.h
deleted file mode 100644
index f56f49f..0000000
--- a/ash/wm/boot_splash_screen.h
+++ /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.
-
-#ifndef ASH_WM_BOOT_SPLASH_SCREEN_H_
-#define ASH_WM_BOOT_SPLASH_SCREEN_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
-
-namespace aura {
-class RootWindow;
-}
-
-namespace ui {
-class Layer;
-class LayerDelegate;
-}
-
-namespace ash {
-namespace internal {
-
-// BootSplashScreen manages a ui::Layer, stacked at the top of the root layer's
-// children, that displays a copy of the initial contents of the host window.
-// This allows us to continue displaying the Chrome OS boot splash screen (which
-// is displayed before Ash starts) after the compositor has taken over so we can
-// animate the transition between the splash screen and the login screen.
-class BootSplashScreen {
- public:
-  explicit BootSplashScreen(aura::RootWindow* root_window);
-  ~BootSplashScreen();
-
-  // Begins animating |layer_|'s opacity to 0 over |duration|.
-  void StartHideAnimation(base::TimeDelta duration);
-
- private:
-  class CopyHostContentLayerDelegate;
-
-  // Copies the host window's content to |layer_|.
-  scoped_ptr<CopyHostContentLayerDelegate> layer_delegate_;
-
-  scoped_ptr<ui::Layer> layer_;
-
-  DISALLOW_COPY_AND_ASSIGN(BootSplashScreen);
-};
-
-}  // namespace internal
-}  // namespace ash
-
-#endif  // ASH_WM_BOOT_SPLASH_SCREEN_H_
diff --git a/ash/wm/boot_splash_screen_chromeos.cc b/ash/wm/boot_splash_screen_chromeos.cc
new file mode 100644
index 0000000..0074340
--- /dev/null
+++ b/ash/wm/boot_splash_screen_chromeos.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 "ash/wm/boot_splash_screen_chromeos.h"
+
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/aura/root_window.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_type.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/gfx/canvas.h"
+
+namespace ash {
+namespace internal {
+
+// ui::LayerDelegate that copies the aura host window's content to a ui::Layer.
+class BootSplashScreen::CopyHostContentLayerDelegate
+    : public ui::LayerDelegate {
+ public:
+  explicit CopyHostContentLayerDelegate(aura::RootWindow* root_window)
+      : root_window_(root_window) {
+  }
+
+  virtual ~CopyHostContentLayerDelegate() {}
+
+  // ui::LayerDelegate overrides:
+  virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
+    // It'd be safer to copy the area to a canvas in the constructor and then
+    // copy from that canvas to this one here, but this appears to work (i.e. we
+    // only call this before we draw our first frame) and it saves us an extra
+    // copy.
+    // TODO(derat): Instead of copying the data, use GLX_EXT_texture_from_pixmap
+    // to create a zero-copy texture (when possible):
+    // https://codereview.chromium.org/10543125
+    ui::CopyAreaToCanvas(root_window_->GetAcceleratedWidget(),
+        gfx::Rect(root_window_->GetHostOrigin(), root_window_->GetHostSize()),
+        gfx::Point(), canvas);
+  }
+
+  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
+
+  virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
+    return base::Closure();
+  }
+
+ private:
+  aura::RootWindow* root_window_;  // not owned
+
+  DISALLOW_COPY_AND_ASSIGN(CopyHostContentLayerDelegate);
+};
+
+BootSplashScreen::BootSplashScreen(aura::RootWindow* root_window)
+    : layer_delegate_(new CopyHostContentLayerDelegate(root_window)),
+      layer_(new ui::Layer(ui::LAYER_TEXTURED)) {
+  layer_->set_delegate(layer_delegate_.get());
+
+  ui::Layer* root_layer = root_window->layer();
+  layer_->SetBounds(gfx::Rect(root_layer->bounds().size()));
+  root_layer->Add(layer_.get());
+  root_layer->StackAtTop(layer_.get());
+}
+
+BootSplashScreen::~BootSplashScreen() {
+}
+
+void BootSplashScreen::StartHideAnimation(base::TimeDelta duration) {
+  ui::ScopedLayerAnimationSettings settings(layer_->GetAnimator());
+  settings.SetTransitionDuration(duration);
+  settings.SetPreemptionStrategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
+  layer_->SetOpacity(0.0f);
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/wm/boot_splash_screen_chromeos.h b/ash/wm/boot_splash_screen_chromeos.h
new file mode 100644
index 0000000..e844275
--- /dev/null
+++ b/ash/wm/boot_splash_screen_chromeos.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_WM_BOOT_SPLASH_SCREEN_CHROMEOS_H_
+#define ASH_WM_BOOT_SPLASH_SCREEN_CHROMEOS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+
+namespace aura {
+class RootWindow;
+}
+
+namespace ui {
+class Layer;
+class LayerDelegate;
+}
+
+namespace ash {
+namespace internal {
+
+// BootSplashScreen manages a ui::Layer, stacked at the top of the root layer's
+// children, that displays a copy of the initial contents of the host window.
+// This allows us to continue displaying the Chrome OS boot splash screen (which
+// is displayed before Ash starts) after the compositor has taken over so we can
+// animate the transition between the splash screen and the login screen.
+class BootSplashScreen {
+ public:
+  explicit BootSplashScreen(aura::RootWindow* root_window);
+  ~BootSplashScreen();
+
+  // Begins animating |layer_|'s opacity to 0 over |duration|.
+  void StartHideAnimation(base::TimeDelta duration);
+
+ private:
+  class CopyHostContentLayerDelegate;
+
+  // Copies the host window's content to |layer_|.
+  scoped_ptr<CopyHostContentLayerDelegate> layer_delegate_;
+
+  scoped_ptr<ui::Layer> layer_;
+
+  DISALLOW_COPY_AND_ASSIGN(BootSplashScreen);
+};
+
+}  // namespace internal
+}  // namespace ash
+
+#endif  // ASH_WM_BOOT_SPLASH_SCREEN_CHROMEOS_H_
diff --git a/ash/wm/capture_controller.cc b/ash/wm/capture_controller.cc
deleted file mode 100644
index 4e17054..0000000
--- a/ash/wm/capture_controller.cc
+++ /dev/null
@@ -1,74 +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 "ash/wm/capture_controller.h"
-
-#include "ash/shell.h"
-#include "ui/aura/window.h"
-#include "ui/aura/root_window.h"
-
-namespace ash {
-namespace internal {
-
-////////////////////////////////////////////////////////////////////////////////
-// CaptureController, public:
-
-CaptureController::CaptureController()
-    : capture_window_(NULL) {
-}
-
-CaptureController::~CaptureController() {
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// CaptureController, client::CaptureClient implementation:
-
-void CaptureController::SetCapture(aura::Window* new_capture_window) {
-  if (capture_window_ == new_capture_window)
-    return;
-  // Make sure window has a root window.
-  DCHECK(!new_capture_window || new_capture_window->GetRootWindow());
-  DCHECK(!capture_window_ || capture_window_->GetRootWindow());
-
-  aura::Window* old_capture_window = capture_window_;
-  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
-
-  // 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
-  // distinction between the touches/gestures that were in the window all
-  // along (and so shouldn't be canceled) and those that got moved, so
-  // just leave them all where they are.
-  if (new_capture_window) {
-    for (Shell::RootWindowList::iterator iter = root_windows.begin();
-         iter != root_windows.end(); ++iter) {
-      aura::RootWindow* root_window = *iter;
-      root_window->gesture_recognizer()->
-          TransferEventsTo(old_capture_window, new_capture_window);
-    }
-  }
-
-  capture_window_ = new_capture_window;
-
-  for (Shell::RootWindowList::iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    aura::RootWindow* root_window = *iter;
-    root_window->UpdateCapture(old_capture_window, new_capture_window);
-  }
-
-  return;
-}
-
-void CaptureController::ReleaseCapture(aura::Window* window) {
-  if (capture_window_ != window)
-    return;
-  SetCapture(NULL);
-}
-
-aura::Window* CaptureController::GetCaptureWindow() {
-  return capture_window_;
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/wm/capture_controller.h b/ash/wm/capture_controller.h
deleted file mode 100644
index 4468fb3..0000000
--- a/ash/wm/capture_controller.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 ASH_WM_CAPTURE_CONTROLLER_H_
-#define ASH_WM_CAPTURE_CONTROLLER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/aura/client/capture_client.h"
-#include "ash/ash_export.h"
-
-namespace ash {
-namespace internal {
-
-class ASH_EXPORT CaptureController : public aura::client::CaptureClient {
- public:
-  CaptureController();
-  virtual ~CaptureController();
-
-  // Overridden from aura::client::CaptureClient:
-  virtual void SetCapture(aura::Window* window) OVERRIDE;
-  virtual void ReleaseCapture(aura::Window* window) OVERRIDE;
-  virtual aura::Window* GetCaptureWindow() OVERRIDE;
-
- private:
-  // The current capture window. Null if there is no capture window.
-  aura::Window* capture_window_;
-
-  DISALLOW_COPY_AND_ASSIGN(CaptureController);
-};
-
-}  // namespace internal
-}  // namespace ash
-
-#endif  // ASH_WM_CAPTURE_CONTROLLER_H_
diff --git a/ash/wm/custom_frame_view_ash.cc b/ash/wm/custom_frame_view_ash.cc
index 9852d16..f7090a4 100644
--- a/ash/wm/custom_frame_view_ash.cc
+++ b/ash/wm/custom_frame_view_ash.cc
@@ -45,7 +45,6 @@
     : frame_(NULL),
       maximize_button_(NULL),
       close_button_(NULL),
-      window_icon_(NULL),
       frame_painter_(new ash::FramePainter) {
 }
 
@@ -66,12 +65,7 @@
 
   maximize_button_->SetVisible(frame_->widget_delegate()->CanMaximize());
 
-  if (frame_->widget_delegate()->ShouldShowWindowIcon()) {
-    window_icon_ = new views::ImageButton(this);
-    AddChildView(window_icon_);
-  }
-
-  frame_painter_->Init(frame_, window_icon_, maximize_button_, close_button_,
+  frame_painter_->Init(frame_, NULL, maximize_button_, close_button_,
                        FramePainter::SIZE_BUTTON_MAXIMIZES);
 }
 
@@ -104,8 +98,6 @@
 }
 
 void CustomFrameViewAsh::UpdateWindowIcon() {
-  if (window_icon_)
-    window_icon_->SchedulePaint();
 }
 
 void CustomFrameViewAsh::UpdateWindowTitle() {
diff --git a/ash/wm/custom_frame_view_ash.h b/ash/wm/custom_frame_view_ash.h
index b6ccf7f..80525c3 100644
--- a/ash/wm/custom_frame_view_ash.h
+++ b/ash/wm/custom_frame_view_ash.h
@@ -86,7 +86,6 @@
 
   ash::FrameMaximizeButton* maximize_button_;
   views::ImageButton* close_button_;
-  views::ImageButton* window_icon_;
 
   scoped_ptr<FramePainter> frame_painter_;
 
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc
index d73a0cc..36998df 100644
--- a/ash/wm/dock/docked_window_layout_manager.cc
+++ b/ash/wm/dock/docked_window_layout_manager.cc
@@ -84,10 +84,58 @@
           window->type() != aura::client::WINDOW_TYPE_POPUP);
 }
 
-bool CompareWindowPos(const aura::Window* win1, const aura::Window* win2) {
-  return win1->GetTargetBounds().CenterPoint().y() <
-      win2->GetTargetBounds().CenterPoint().y();
-}
+// A functor used to sort the windows in order of their center Y position.
+// |delta| is a pre-calculated distance from the bottom of one window to the top
+// of the next. Its value can be positive (gap) or negative (overlap).
+// Half of |delta| is used as a transition point at which windows could ideally
+// swap positions.
+struct CompareWindowPos {
+  CompareWindowPos(aura::Window* dragged_window, float delta)
+      : dragged_window_(dragged_window),
+        delta_(delta / 2) {}
+
+  bool operator()(const aura::Window* win1, const aura::Window* win2) {
+    const gfx::Rect win1_bounds = win1->GetBoundsInScreen();
+    const gfx::Rect win2_bounds = win2->GetBoundsInScreen();
+    // If one of the windows is the |dragged_window_| attempt to make an
+    // earlier swap between the windows than just based on their centers.
+    // This is possible if the dragged window is at least as tall as the other
+    // window.
+    if (win1 == dragged_window_)
+      return compare_two_windows(win1_bounds, win2_bounds);
+    if (win2 == dragged_window_)
+      return !compare_two_windows(win2_bounds, win1_bounds);
+    // Otherwise just compare the centers.
+    return win1_bounds.CenterPoint().y() < win2_bounds.CenterPoint().y();
+  }
+
+  // Based on center point tries to deduce where the drag is coming from.
+  // When dragging from below up the transition point is lower.
+  // When dragging from above down the transition point is higher.
+  bool compare_bounds(const gfx::Rect dragged, const gfx::Rect other) {
+    if (dragged.CenterPoint().y() < other.CenterPoint().y())
+      return dragged.CenterPoint().y() < other.y() - delta_;
+    return dragged.CenterPoint().y() < other.bottom() + delta_;
+  }
+
+  // Performs comparison both ways and selects stable result.
+  bool compare_two_windows(const gfx::Rect bounds1, const gfx::Rect bounds2) {
+    // Try comparing windows in both possible orders and see if the comparison
+    // is stable.
+    bool result1 = compare_bounds(bounds1, bounds2);
+    bool result2 = compare_bounds(bounds2, bounds1);
+    if (result1 != result2)
+      return result1;
+
+    // Otherwise it is not possible to be sure that the windows will not bounce.
+    // In this case just compare the centers.
+    return bounds1.CenterPoint().y() < bounds2.CenterPoint().y();
+  }
+
+ private:
+  aura::Window* dragged_window_;
+  float delta_;
+};
 
 }  // namespace
 
@@ -98,6 +146,8 @@
     : dock_container_(dock_container),
       in_layout_(false),
       dragged_window_(NULL),
+      is_dragged_window_docked_(false),
+      is_dragged_from_dock_(false),
       launcher_(NULL),
       shelf_layout_manager_(NULL),
       shelf_hidden_(false),
@@ -139,96 +189,41 @@
 }
 
 void DockedWindowLayoutManager::StartDragging(aura::Window* window) {
-  if (window->parent() != dock_container_)
-    return;
   DCHECK(!dragged_window_);
   dragged_window_ = window;
+  // Start observing a window unless it is docked container's child in which
+  // case it is already observed.
+  if (dragged_window_->parent() != dock_container_)
+    dragged_window_->AddObserver(this);
+  is_dragged_from_dock_ = window->parent() == dock_container_;
+  DCHECK(!is_dragged_window_docked_);
+}
+
+void DockedWindowLayoutManager::DockDraggedWindow(aura::Window* window) {
+  OnWindowDocked(window);
   Relayout();
 }
 
+void DockedWindowLayoutManager::UndockDraggedWindow() {
+  OnWindowUndocked();
+  Relayout();
+  is_dragged_from_dock_ = false;
+}
+
 void DockedWindowLayoutManager::FinishDragging() {
-  if (!dragged_window_)
-    return;
-
-  // If this is the first window getting docked - update alignment.
-  if (alignment_ == DOCKED_ALIGNMENT_NONE) {
-    alignment_ = AlignmentOfWindow(dragged_window_);
-  } else {
-    // There were some docked windows before. Check if the |dragged_window_|
-    // was the only one remaining and if so possibly switch alignment to
-    // opposite side. Ignore popups.
-    bool found_docked_window = false;
-    for (size_t i = 0; i < dock_container_->children().size(); ++i) {
-      aura::Window* window(dock_container_->children()[i]);
-      if (window != dragged_window_ &&
-          window->type() != aura::client::WINDOW_TYPE_POPUP) {
-        found_docked_window = true;
-        break;
-      }
-    }
-    if (!found_docked_window)
-      alignment_ = AlignmentOfWindow(dragged_window_);
-  }
-
-  // We no longer need to observe |dragged_window_| unless it is added back;
-  if (dragged_window_) {
-    if (dragged_window_->parent() != dock_container_)
-      dragged_window_->RemoveObserver(this);
-    dragged_window_ = NULL;
-  }
-
+  DCHECK(dragged_window_);
+  if (is_dragged_window_docked_)
+    OnWindowUndocked();
+  DCHECK (!is_dragged_window_docked_);
+  // Stop observing a window unless it is docked container's child in which
+  // case it needs to keep being observed after the drag completes.
+  if (dragged_window_->parent() != dock_container_)
+    dragged_window_->RemoveObserver(this);
+  dragged_window_ = NULL;
   Relayout();
   UpdateDockBounds();
 }
 
-// static
-bool DockedWindowLayoutManager::ShouldWindowDock(aura::Window* window,
-                                                 const gfx::Point& location) {
-  DockedWindowLayoutManager* layout_manager = GetDockLayoutManager(window,
-                                                                   location);
-  const DockedAlignment alignment = layout_manager->CalculateAlignment();
-  const gfx::Rect& bounds(window->GetBoundsInScreen());
-  const gfx::Rect docked_bounds = (alignment == DOCKED_ALIGNMENT_NONE) ?
-      layout_manager->dock_container_->GetBoundsInScreen() :
-      layout_manager->docked_bounds_;
-  DockedAlignment dock_edge = DOCKED_ALIGNMENT_NONE;
-  if (alignment == DOCKED_ALIGNMENT_NONE) {
-    // Check if the window is touching the edge - it may need to get docked.
-    dock_edge = layout_manager->AlignmentOfWindow(window);
-  } else if ((docked_bounds.Intersects(bounds) &&
-              docked_bounds.Contains(location)) ||
-             alignment == layout_manager->AlignmentOfWindow(window)) {
-    // A window is being added to other docked windows (on the same side).
-    // Both bounds and pointer location are checked because some drags involve
-    // sticky edges and so the |location| may be outside of the |bounds|.
-    // It is also possible that all the docked windows are minimized or hidden
-    // in which case the dragged window needs to be exactly touching the same
-    // edge that those docked windows were aligned before they got minimized.
-    dock_edge = alignment;
-  }
-
-  // Do not allow docking on the same side as launcher shelf.
-  if (layout_manager->launcher_ && layout_manager->launcher_->shelf_widget()) {
-    ShelfAlignment shelf_alignment =
-        layout_manager->launcher_->shelf_widget()->GetAlignment();
-    if ((shelf_alignment == SHELF_ALIGNMENT_LEFT &&
-         dock_edge == DOCKED_ALIGNMENT_LEFT) ||
-        (shelf_alignment == SHELF_ALIGNMENT_RIGHT &&
-         dock_edge == DOCKED_ALIGNMENT_RIGHT)) {
-      dock_edge = DOCKED_ALIGNMENT_NONE;
-    }
-  }
-
-  // Do not allow docking if a window is vertically maximized (as is the case
-  // when it is snapped).
-  const gfx::Rect work_area =
-      Shell::GetScreen()->GetDisplayNearestWindow(window).work_area();
-  if (bounds.y() == work_area.y() && bounds.height() == work_area.height())
-    dock_edge = DOCKED_ALIGNMENT_NONE;
-
-  return dock_edge != DOCKED_ALIGNMENT_NONE;
-}
-
 void DockedWindowLayoutManager::SetLauncher(ash::Launcher* launcher) {
   DCHECK(!launcher_);
   DCHECK(!shelf_layout_manager_);
@@ -241,6 +236,34 @@
   }
 }
 
+DockedAlignment DockedWindowLayoutManager::GetAlignmentOfWindow(
+    const aura::Window* window) const {
+  const gfx::Rect& bounds(window->GetBoundsInScreen());
+  const gfx::Rect docked_bounds = dock_container_->GetBoundsInScreen();
+
+  // Do not allow docking if a window is vertically maximized (as is the case
+  // when it is snapped).
+  const gfx::Rect work_area =
+      Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area();
+  if (bounds.y() == work_area.y() && bounds.height() == work_area.height())
+    return DOCKED_ALIGNMENT_NONE;
+
+  // Do not allow docking on the same side as launcher shelf.
+  ShelfAlignment shelf_alignment = SHELF_ALIGNMENT_BOTTOM;
+  if (launcher_)
+    shelf_alignment = launcher_->alignment();
+
+  if (bounds.x() == docked_bounds.x() &&
+      shelf_alignment != SHELF_ALIGNMENT_LEFT) {
+    return DOCKED_ALIGNMENT_LEFT;
+  }
+  if (bounds.right() == docked_bounds.right() &&
+      shelf_alignment != SHELF_ALIGNMENT_RIGHT) {
+    return DOCKED_ALIGNMENT_RIGHT;
+  }
+  return DOCKED_ALIGNMENT_NONE;
+}
+
 DockedAlignment DockedWindowLayoutManager::CalculateAlignment() const {
   // Find a child that is not being dragged and is not a popup.
   // If such exists the current alignment is returned - even if some of the
@@ -262,22 +285,24 @@
 // DockLayoutManager, aura::LayoutManager implementation:
 void DockedWindowLayoutManager::OnWindowResized() {
   Relayout();
-  // When screen resizes we need to update the insets even when dock width or
-  // alignment does not change.
+  // When screen resizes update the insets even when dock width or alignment
+  // does not change.
   UpdateDockBounds();
 }
 
 void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
   if (child->type() == aura::client::WINDOW_TYPE_POPUP)
     return;
-
+  // Dragged windows are already observed by StartDragging and do not change
+  // docked alignment during the drag.
+  if (child == dragged_window_)
+    return;
   // If this is the first window getting docked - update alignment.
-  if (alignment_ == DOCKED_ALIGNMENT_NONE)
-    alignment_ = AlignmentOfWindow(child);
-  // We need to observe a child unless it is a |dragged_window_| that just got
-  // added back in which case we are already observing it.
-  if (child != dragged_window_)
-    child->AddObserver(this);
+  if (alignment_ == DOCKED_ALIGNMENT_NONE) {
+    alignment_ = GetAlignmentOfWindow(child);
+    DCHECK(alignment_ != DOCKED_ALIGNMENT_NONE);
+  }
+  child->AddObserver(this);
   Relayout();
   UpdateDockBounds();
 }
@@ -285,36 +310,20 @@
 void DockedWindowLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
   if (child->type() == aura::client::WINDOW_TYPE_POPUP)
     return;
-
-  // Try to find a child that is not a popup and is not being dragged.
-  bool found_docked_window = false;
-  for (size_t i = 0; i < dock_container_->children().size(); ++i) {
-    aura::Window* window(dock_container_->children()[i]);
-    if (window != dragged_window_ &&
-        window->type() != aura::client::WINDOW_TYPE_POPUP) {
-      found_docked_window = true;
-      break;
-    }
-  }
-  if (!found_docked_window)
+  // Dragged windows are stopped being observed by FinishDragging and do not
+  // change alignment during the drag. They also cannot be set to be the
+  // |last_active_window_|.
+  if (child == dragged_window_)
+    return;
+  // If this is the last window, set alignment and maximize the workspace.
+  if (!IsAnyWindowDocked()) {
     alignment_ = DOCKED_ALIGNMENT_NONE;
-
-  // Keep track of former children if they are dragged as they can be reparented
-  // temporarily just for the drag.
-  if (child != dragged_window_)
-    child->RemoveObserver(this);
-
+    docked_width_ = 0;
+  }
   if (last_active_window_ == child)
     last_active_window_ = NULL;
-
-  // Close the dock and expand workspace work area.
+  child->RemoveObserver(this);
   Relayout();
-
-  // When a panel is removed from this layout manager it may still be dragged.
-  // Delay updating dock and workspace bounds until the drag is completed. This
-  // preserves the docked area width until the panel drag is finished.
-  if (child->type() != aura::client::WINDOW_TYPE_PANEL)
-    UpdateDockBounds();
 }
 
 void DockedWindowLayoutManager::OnChildWindowVisibilityChanged(
@@ -331,11 +340,8 @@
 void DockedWindowLayoutManager::SetChildBounds(
     aura::Window* child,
     const gfx::Rect& requested_bounds) {
-  // Whenever one of our windows is moved or resized we need to enforce layout.
+  // Whenever one of our windows is moved or resized enforce layout.
   SetChildBoundsDirect(child, requested_bounds);
-  if (child->type() == aura::client::WINDOW_TYPE_POPUP)
-    return;
-  Relayout();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -388,13 +394,19 @@
     aura::Window* window,
     const gfx::Rect& old_bounds,
     const gfx::Rect& new_bounds) {
-  if (window == dragged_window_)
+  // Only relayout if the dragged window would get docked.
+  if (window == dragged_window_ && is_dragged_window_docked_)
     Relayout();
 }
 
 void DockedWindowLayoutManager::OnWindowDestroying(aura::Window* window) {
-  if (dragged_window_ == window)
-    dragged_window_ = NULL;
+  if (dragged_window_ == window) {
+    FinishDragging();
+    DCHECK(!dragged_window_);
+    DCHECK (!is_dragged_window_docked_);
+  }
+  if (window == last_active_window_)
+    last_active_window_ = NULL;
 }
 
 
@@ -426,7 +438,7 @@
   // to allow the full-screen application to use the full screen.
 
   // TODO(varkha): ShelfLayoutManager::UpdateVisibilityState sets state to
-  // SHELF_AUTO_HIDE when in immersive mode. We need to distinguish this from
+  // SHELF_AUTO_HIDE when in immersive mode. Distinguish this from
   // when shelf enters auto-hide state based on mouse hover when auto-hide
   // setting is enabled and hide all windows (immersive mode should hide docked
   // windows).
@@ -462,30 +474,43 @@
   window->Show();
 }
 
-DockedAlignment DockedWindowLayoutManager::AlignmentOfWindow(
-    const aura::Window* window) const {
-  const gfx::Rect& bounds(window->GetBoundsInScreen());
-  const gfx::Rect docked_bounds = dock_container_->GetBoundsInScreen();
-  if (bounds.x() == docked_bounds.x())
-    return DOCKED_ALIGNMENT_LEFT;
-  if (bounds.right() == docked_bounds.right())
-    return DOCKED_ALIGNMENT_RIGHT;
-  return DOCKED_ALIGNMENT_NONE;
+void DockedWindowLayoutManager::OnWindowDocked(aura::Window* window) {
+  DCHECK(!is_dragged_window_docked_);
+  is_dragged_window_docked_ = true;
+
+  // If there are no other docked windows update alignment.
+  if (!IsAnyWindowDocked())
+    alignment_ = DOCKED_ALIGNMENT_NONE;
+}
+
+void DockedWindowLayoutManager::OnWindowUndocked() {
+  // If this is the first window getting docked - update alignment.
+  if (!IsAnyWindowDocked())
+    alignment_ = GetAlignmentOfWindow(dragged_window_);
+
+  DCHECK (is_dragged_window_docked_);
+  is_dragged_window_docked_ = false;
+}
+
+bool DockedWindowLayoutManager::IsAnyWindowDocked() {
+  return CalculateAlignment() != DOCKED_ALIGNMENT_NONE;
 }
 
 void DockedWindowLayoutManager::Relayout() {
-  if (in_layout_ || alignment_ == DOCKED_ALIGNMENT_NONE)
+  if (in_layout_)
+    return;
+  if (alignment_ == DOCKED_ALIGNMENT_NONE && !is_dragged_window_docked_)
     return;
   base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
 
-  gfx::Rect dock_bounds = dock_container_->bounds();
+  gfx::Rect dock_bounds = dock_container_->GetBoundsInScreen();
   aura::Window* active_window = NULL;
   aura::Window::Windows visible_windows;
   docked_width_ = 0;
   for (size_t i = 0; i < dock_container_->children().size(); ++i) {
     aura::Window* window(dock_container_->children()[i]);
 
-    if (!IsUsedByLayout(window))
+    if (!IsUsedByLayout(window) || window == dragged_window_)
       continue;
 
     // If the shelf is currently hidden (full-screen mode), hide window until
@@ -505,14 +530,14 @@
     visible_windows.push_back(window);
   }
 
-  // Consider windows that were formerly children of the |dock_container_|
-  // when fanning out other child windows.
-  if (dragged_window_ && dragged_window_->parent() != dock_container_)
+  // Consider docked dragged_window_ when fanning out other child windows.
+  if (is_dragged_window_docked_) {
     visible_windows.push_back(dragged_window_);
+    DCHECK(!active_window);
+    active_window = dragged_window_;
+  }
 
-  // Sort windows by their center positions and fan out overlapping
-  // windows.
-  std::sort(visible_windows.begin(), visible_windows.end(), CompareWindowPos);
+  // Calculate free space or overlap.
   gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
       dock_container_);
   const gfx::Rect work_area = display.work_area();
@@ -525,15 +550,19 @@
   const float delta = (float)available_room /
       ((available_room > 0 || num_windows <= 1) ?
           num_windows + 1 : num_windows - 1);
-  float y_pos = (available_room > 0) ? delta : 0;
+  float y_pos = work_area.y() + ((available_room > 0) ? delta : 0);
 
+  // Sort windows by their center positions and fan out overlapping
+  // windows.
+  std::sort(visible_windows.begin(),
+            visible_windows.end(),
+            CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : NULL,
+                             delta));
+  is_dragged_from_dock_ = true;
   for (aura::Window::Windows::const_iterator iter = visible_windows.begin();
       iter != visible_windows.end(); ++iter) {
     aura::Window* window = *iter;
-    gfx::Rect bounds = window->GetTargetBounds();
-    // Do not force position of a single window.
-    if (num_windows == 1)
-      y_pos = bounds.y();
+    gfx::Rect bounds = window->GetBoundsInScreen();
 
     // Fan out windows evenly distributing the overlap or remaining free space.
     bounds.set_y(std::max(work_area.y(),
@@ -543,24 +572,27 @@
 
     // All docked windows other than the one currently dragged remain stuck
     // to the screen edge.
-    if (window == dragged_window_)
-      continue;
     switch (alignment_) {
       case DOCKED_ALIGNMENT_LEFT:
-        bounds.set_x(0);
+        bounds.set_x(dock_bounds.x());
         break;
       case DOCKED_ALIGNMENT_RIGHT:
         bounds.set_x(dock_bounds.right() - bounds.width());
         break;
       case DOCKED_ALIGNMENT_NONE:
-        NOTREACHED() << "Relayout called when dock alignment is 'NONE'";
         break;
     }
+    if (window == dragged_window_) {
+      dragged_bounds_ = bounds;
+      continue;
+    }
+    DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE);
     // Keep the dock at least kMinDockWidth when all windows in it overhang.
     docked_width_ = std::min(kMaxDockWidth,
                              std::max(docked_width_,
                                       bounds.width() > kMaxDockWidth ?
                                           kMinDockWidth : bounds.width()));
+    bounds = ScreenAsh::ConvertRectFromScreen(dock_container_, bounds);
     SetChildBoundsDirect(window, bounds);
   }
   UpdateStacking(active_window);
@@ -569,7 +601,7 @@
 void DockedWindowLayoutManager::UpdateDockBounds() {
   int dock_inset = docked_width_ + (docked_width_ > 0 ? kMinDockGap : 0);
   gfx::Rect bounds = gfx::Rect(
-      alignment_ == DOCKED_ALIGNMENT_RIGHT ?
+      alignment_ == DOCKED_ALIGNMENT_RIGHT && dock_inset > 0 ?
           dock_container_->bounds().right() - dock_inset:
           dock_container_->bounds().x(),
       dock_container_->bounds().y(),
@@ -601,7 +633,7 @@
     active_window = last_active_window_;
   }
 
-  // We want to to stack the windows like a deck of cards:
+  // Windows are stacked like a deck of cards:
   //  ,------.
   // |,------.|
   // |,------.|
@@ -610,22 +642,24 @@
   // |`------'|
   // |`------'|
   //  `------'
-  // We use the middle of each window to figure out how to stack the window.
+  // Use the middle of each window to figure out how to stack the window.
   // This allows us to update the stacking when a window is being dragged around
   // by the titlebar.
   std::map<int, aura::Window*> window_ordering;
   for (aura::Window::Windows::const_iterator it =
            dock_container_->children().begin();
        it != dock_container_->children().end(); ++it) {
-    if (!IsUsedByLayout(*it))
+    if (!IsUsedByLayout(*it) ||
+        ((*it) == dragged_window_ && !is_dragged_window_docked_)) {
       continue;
+    }
     gfx::Rect bounds = (*it)->bounds();
     window_ordering.insert(std::make_pair(bounds.y() + bounds.height() / 2,
                                           *it));
   }
   int active_center_y = active_window->bounds().CenterPoint().y();
 
-  aura::Window* previous_window = background_widget_->GetNativeWindow();
+  aura::Window* previous_window = NULL;
   for (std::map<int, aura::Window*>::const_iterator it =
        window_ordering.begin();
        it != window_ordering.end() && it->first < active_center_y; ++it) {
@@ -633,8 +667,6 @@
       dock_container_->StackChildAbove(it->second, previous_window);
     previous_window = it->second;
   }
-
-  previous_window = NULL;
   for (std::map<int, aura::Window*>::const_reverse_iterator it =
        window_ordering.rbegin();
        it != window_ordering.rend() && it->first > active_center_y; ++it) {
@@ -643,11 +675,10 @@
     previous_window = it->second;
   }
 
-  if (active_window->parent() == dock_container_)
-    dock_container_->StackChildAtTop(active_window);
-  if (dragged_window_ && dragged_window_->parent() == dock_container_)
-    dock_container_->StackChildAtTop(dragged_window_);
-  last_active_window_ = active_window;
+  if (previous_window && active_window->parent() == dock_container_)
+    dock_container_->StackChildAbove(active_window, previous_window);
+  if (active_window != dragged_window_)
+    last_active_window_ = active_window;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ash/wm/dock/docked_window_layout_manager.h b/ash/wm/dock/docked_window_layout_manager.h
index aa02b34..a3019aa 100644
--- a/ash/wm/dock/docked_window_layout_manager.h
+++ b/ash/wm/dock/docked_window_layout_manager.h
@@ -50,7 +50,9 @@
 // its layout manager to this instance, e.g.:
 // dock_container->SetLayoutManager(
 //     new DockedWindowLayoutManager(dock_container));
-
+//
+// TODO(varkha): extend BaseLayoutManager instead of LayoutManager to inherit
+// common functionality.
 class ASH_EXPORT DockedWindowLayoutManager
     : public aura::LayoutManager,
       public ash::ShellObserver,
@@ -70,26 +72,35 @@
   virtual void RemoveObserver(DockedWindowLayoutManagerObserver* observer);
 
   // Called by a DockedWindowResizer to update which window is being dragged.
+  // Starts observing the window unless it is a child.
   void StartDragging(aura::Window* window);
-  void FinishDragging();
 
-  // Returns true if a window is touching the side of the screen except 2 cases:
-  // when some other windows are already docked on the other side or
-  // when launcher (shelf) is aligned on the same side.
-  static bool ShouldWindowDock(aura::Window* window,
-                               const gfx::Point& location);
+  // Called by a DockedWindowResizer when a dragged window is docked.
+  void DockDraggedWindow(aura::Window* window);
+
+  // Called by a DockedWindowResizer when a dragged window is no longer docked.
+  void UndockDraggedWindow();
+
+  // Called by a DockedWindowResizer when a window is no longer being dragged.
+  // Stops observing the window unless it is a child.
+  void FinishDragging();
 
   ash::Launcher* launcher() { return launcher_; }
   void SetLauncher(ash::Launcher* launcher);
 
+  // Calculates if a window is touching the screen edges and returns edge.
+  DockedAlignment GetAlignmentOfWindow(const aura::Window* window) const;
+
   // Used to snap docked windows to the side of screen during drag.
   DockedAlignment CalculateAlignment() const;
 
+  aura::Window* dock_container() const { return dock_container_; }
+
   // Returns current bounding rectangle of docked windows area.
   const gfx::Rect& docked_bounds() const { return docked_bounds_; }
 
-  // Currently dragged window should be able to dock on another screen
-  aura::Window* dragged_window() const { return dragged_window_;}
+  // Returns last known coordinates of |dragged_window_| after Relayout.
+  const gfx::Rect dragged_bounds() const { return dragged_bounds_;}
 
   // aura::LayoutManager:
   virtual void OnWindowResized() OVERRIDE;
@@ -143,8 +154,14 @@
   void MinimizeWindow(aura::Window* window);
   void RestoreWindow(aura::Window* window);
 
-  // Calculates if a window is touching the screen edges and returns edge.
-  DockedAlignment AlignmentOfWindow(const aura::Window* window) const;
+  // Updates docked layout state when a window gets inside the dock.
+  void OnWindowDocked(aura::Window* window);
+
+  // Updates docked layout state when a window gets outside the dock.
+  void OnWindowUndocked();
+
+  // Returns true if there are any windows currently docked.
+  bool IsAnyWindowDocked();
 
   // Called whenever the window layout might change.
   void Relayout();
@@ -165,8 +182,21 @@
   aura::Window* dock_container_;
   // Protect against recursive calls to Relayout().
   bool in_layout_;
-  // The docked window being dragged.
+
+  // A window that is being dragged (whether docked or not).
+  // Windows are tracked by docked layout manager only if they are docked;
+  // however we need to know if a window is being dragged in order to avoid
+  // positioning it or even considering it for layout.
   aura::Window* dragged_window_;
+
+  // True if the window being dragged is currently docked.
+  bool is_dragged_window_docked_;
+
+  // Previously docked windows use a more relaxed dragging sorting algorithm
+  // that uses assumption that a window starts being dragged out of position
+  // that was previously established in Relayout. This allows easier reordering.
+  bool is_dragged_from_dock_;
+
   // The launcher we are observing for launcher icon changes.
   Launcher* launcher_;
   // The shelf layout manager being observed for visibility changes.
@@ -180,6 +210,9 @@
   // Last bounds that were sent to observers.
   gfx::Rect docked_bounds_;
 
+  // Target bounds of a docked window being dragged.
+  gfx::Rect dragged_bounds_;
+
   // Side of the screen that the dock is positioned at.
   DockedAlignment alignment_;
 
diff --git a/ash/wm/dock/docked_window_layout_manager_unittest.cc b/ash/wm/dock/docked_window_layout_manager_unittest.cc
index cf7b476..b2f6ffd 100644
--- a/ash/wm/dock/docked_window_layout_manager_unittest.cc
+++ b/ash/wm/dock/docked_window_layout_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/wm/dock/docked_window_layout_manager.h"
 
 #include "ash/ash_switches.h"
+#include "ash/display/display_controller.h"
 #include "ash/launcher/launcher.h"
 #include "ash/launcher/launcher_model.h"
 #include "ash/root_window_controller.h"
@@ -27,6 +28,7 @@
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
+#include "ui/gfx/screen.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
@@ -60,11 +62,6 @@
     DOCKED_EDGE_RIGHT,
   };
 
-  enum DockedState {
-    UNDOCKED,
-    DOCKED,
-  };
-
   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         NULL,
@@ -136,12 +133,10 @@
   // Docked windows are parented by dock container during drags.
   // All other windows that we are testing here have default container as a
   // parent.
-  int CorrectContainerIdDuringDrag(DockedState is_docked) {
+  int CorrectContainerIdDuringDrag() {
     if (window_type_ == aura::client::WINDOW_TYPE_PANEL)
       return internal::kShellWindowId_PanelContainer;
-    if (is_docked == DOCKED)
-      return internal::kShellWindowId_DockedContainer;
-    return internal::kShellWindowId_DefaultContainer;
+    return internal::kShellWindowId_DockedContainer;
   }
 
   // Test dragging the window vertically (to detach if it is a panel) and then
@@ -186,7 +181,7 @@
       // Drag enough to detach since our tests assume panels to be initially
       // detached.
       DragMove(0, dy);
-      EXPECT_EQ(CorrectContainerIdDuringDrag(UNDOCKED), window->parent()->id());
+      EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
       EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
       EXPECT_EQ(initial_bounds.y() + dy, window->GetBoundsInScreen().y());
 
@@ -208,7 +203,7 @@
     else if (edge == DOCKED_EDGE_RIGHT)
       dx += window->GetRootWindow()->bounds().right() - initial_bounds.right();
     DragMove(dx, window_type_ == aura::client::WINDOW_TYPE_PANEL ? 0 : dy);
-    EXPECT_EQ(CorrectContainerIdDuringDrag(UNDOCKED), window->parent()->id());
+    EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
     // Release the mouse and the panel should be attached to the dock.
     DragEnd();
 
@@ -314,7 +309,7 @@
   scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
   scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 0, 210, 202)));
-  DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 100);
+  DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 200);
   scoped_ptr<aura::Window> w3(CreateTestWindow(gfx::Rect(0, 0, 220, 204)));
   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w3.get(), 300);
 
@@ -341,9 +336,10 @@
   EXPECT_LE(abs(overlap2 - overlap3), 1);
   EXPECT_EQ(0, overlap4);
 
-  // Drag w1 below w2.
+  // Drag w1 below the point where w1 and w2 would swap places. This point is
+  // half way between the tops of those two windows. Add 1 because w2 is taller.
   ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w1.get(), 0, 20));
-  DragMove(0, w2->bounds().y() - w1->bounds().y() + 20);
+  DragMove(0, (w2->bounds().y() - w1->bounds().y()) / 2 + 1);
 
   // During the drag the windows get rearranged and the top and the bottom
   // should be clamped by the work area.
@@ -364,6 +360,73 @@
   EXPECT_EQ(0, overlap4);
 }
 
+// Adds three windows in bottom display and tests layout after a drag.
+TEST_P(DockedWindowLayoutManagerTest, ThreeWindowsDraggingSecondScreen) {
+  if (!SupportsMultipleDisplays())
+    return;
+  if (!SupportsHostWindowResize())
+    return;
+
+  // Create two screen vertical layout.
+  UpdateDisplay("100+100-600x600,100+700-600x600");
+  // Layout the secondary display to the bottom of the primary.
+  DisplayLayout layout(DisplayLayout::BOTTOM, 0);
+  ASSERT_GT(Shell::GetScreen()->GetNumDisplays(), 1);
+  Shell::GetInstance()->display_controller()->
+      SetLayoutForCurrentDisplays(layout);
+
+  scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 600, 201, 201)));
+  DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 600 + 20);
+  scoped_ptr<aura::Window> w2(CreateTestWindow(gfx::Rect(0, 600, 210, 202)));
+  DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w2.get(), 600 + 200);
+  scoped_ptr<aura::Window> w3(CreateTestWindow(gfx::Rect(0, 600, 220, 204)));
+  DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w3.get(), 600 + 300);
+
+  // All windows should be attached and snapped to the right side of the screen.
+  EXPECT_EQ(w1->GetRootWindow()->bounds().right(),
+            w1->GetBoundsInScreen().right());
+  EXPECT_EQ(internal::kShellWindowId_DockedContainer, w1->parent()->id());
+  EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
+            w2->GetBoundsInScreen().right());
+  EXPECT_EQ(internal::kShellWindowId_DockedContainer, w2->parent()->id());
+  EXPECT_EQ(w3->GetRootWindow()->bounds().right(),
+            w3->GetBoundsInScreen().right());
+  EXPECT_EQ(internal::kShellWindowId_DockedContainer, w3->parent()->id());
+
+  gfx::Rect work_area =
+      Shell::GetScreen()->GetDisplayNearestWindow(w1.get()).work_area();
+  // Test that the top and bottom windows are clamped in work area and
+  // that the overlaps between the windows differ at most by a pixel.
+  int overlap1 = w1->GetBoundsInScreen().y() - work_area.y();
+  int overlap2 = w1->GetBoundsInScreen().bottom() - w2->GetBoundsInScreen().y();
+  int overlap3 = w2->GetBoundsInScreen().bottom() - w3->GetBoundsInScreen().y();
+  int overlap4 = work_area.bottom() - w3->GetBoundsInScreen().bottom();
+  EXPECT_EQ(0, overlap1);
+  EXPECT_LE(abs(overlap2 - overlap3), 1);
+  EXPECT_EQ(0, overlap4);
+
+  // Drag w1 below the point where w1 and w2 would swap places. This point is
+  // half way between the tops of those two windows. Add 1 because w2 is taller.
+  ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w1.get(), 0, 20));
+  DragMove(0, (w2->bounds().y() - w1->bounds().y()) / 2 + 1);
+
+  // During the drag the windows get rearranged and the top and the bottom
+  // should be clamped by the work area.
+  EXPECT_EQ(work_area.y(), w2->GetBoundsInScreen().y());
+  EXPECT_GT(w1->GetBoundsInScreen().y(), w2->GetBoundsInScreen().y());
+  EXPECT_EQ(work_area.bottom(), w3->GetBoundsInScreen().bottom());
+  DragEnd();
+
+  // Test the new windows order and that the overlaps differ at most by a pixel.
+  overlap1 = w2->GetBoundsInScreen().y() - work_area.y();
+  overlap2 = w2->GetBoundsInScreen().bottom() - w1->GetBoundsInScreen().y();
+  overlap3 = w1->GetBoundsInScreen().bottom() - w3->GetBoundsInScreen().y();
+  overlap4 = work_area.bottom() - w3->GetBoundsInScreen().bottom();
+  EXPECT_EQ(0, overlap1);
+  EXPECT_LE(abs(overlap2 - overlap3), 1);
+  EXPECT_EQ(0, overlap4);
+}
+
 // Tests run twice - on both panels and normal windows
 INSTANTIATE_TEST_CASE_P(NormalOrPanel,
                         DockedWindowLayoutManagerTest,
diff --git a/ash/wm/dock/docked_window_resizer.cc b/ash/wm/dock/docked_window_resizer.cc
index beae1d1..3e1ef29 100644
--- a/ash/wm/dock/docked_window_resizer.cc
+++ b/ash/wm/dock/docked_window_resizer.cc
@@ -16,7 +16,9 @@
 #include "ash/wm/dock/docked_window_layout_manager.h"
 #include "ash/wm/property_util.h"
 #include "ash/wm/window_properties.h"
-#include "ash/wm/workspace_controller.h"
+#include "ash/wm/workspace/magnetism_matcher.h"
+#include "ash/wm/workspace/phantom_window_controller.h"
+#include "ash/wm/workspace/workspace_window_resizer.h"
 #include "base/command_line.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
@@ -29,15 +31,18 @@
 #include "ui/views/widget/widget.h"
 
 namespace ash {
+namespace internal {
 
 namespace {
 
-// Distance in pixels that the cursor must move past an edge for a window
-// to move beyond that edge.
-const int kStickyDistance = 64;
-
-// How far in pixels we have to drag to undock a window.
-const int kSnapToDockDistance = 32;
+DockedWindowLayoutManager* GetDockedLayoutManagerAtPoint(
+    const gfx::Point& point) {
+  aura::Window* dock_container = Shell::GetContainer(
+      wm::GetRootWindowAt(point),
+      kShellWindowId_DockedContainer);
+  return static_cast<DockedWindowLayoutManager*>(
+      dock_container->layout_manager());
+}
 
 }  // namespace
 
@@ -89,37 +94,78 @@
   destroyed_ = NULL;
   if (set_tracked_by_workspace)
     SetTrackedByWorkspace(GetTarget(), tracked_by_workspace);
+
+  DockedWindowLayoutManager* new_dock_layout =
+      GetDockedLayoutManagerAtPoint(last_location_);
+  if (new_dock_layout != dock_layout_) {
+    // The window is being dragged to a new display. If the previous
+    // container is the current parent of the window it will be informed of
+    // the end of drag when the window is reparented, otherwise let the
+    // previous container know the drag is complete. If we told the
+    // window's parent that the drag was complete it would begin
+    // positioning the window.
+    if (is_docked_)
+      dock_layout_->UndockDraggedWindow();
+    if (dock_layout_ != initial_dock_layout_)
+      dock_layout_->FinishDragging();
+    is_docked_ = false;
+    dock_layout_ = new_dock_layout;
+    // The window's initial layout manager already knows that the drag is
+    // in progress for this window.
+    if (new_dock_layout != initial_dock_layout_)
+      new_dock_layout->StartDragging(GetTarget());
+  }
+
+  // Show snapping animation when a window touches a screen edge or when
+  // it is about to get docked.
+  DockedAlignment new_docked_alignment = GetDraggedWindowAlignment();
+  if (new_docked_alignment != DOCKED_ALIGNMENT_NONE) {
+    if (!is_docked_) {
+      dock_layout_->DockDraggedWindow(GetTarget());
+      is_docked_ = true;
+    }
+    UpdateSnapPhantomWindow();
+  } else {
+    if (is_docked_) {
+      dock_layout_->UndockDraggedWindow();
+      is_docked_ = false;
+    }
+    // Clear phantom window when a window gets undocked.
+    snap_phantom_window_controller_.reset();
+  }
 }
 
 void DockedWindowResizer::CompleteDrag(int event_flags) {
+  snap_phantom_window_controller_.reset();
+
   // Temporarily clear kWindowTrackedByWorkspaceKey for panels so that they
   // don't get forced into the workspace that may be shrunken because of docked
   // windows.
   bool tracked_by_workspace = GetTrackedByWorkspace(GetTarget());
-  bool set_tracked_by_workspace =
-      (was_docked_ && GetTarget()->type() == aura::client::WINDOW_TYPE_PANEL);
+  bool set_tracked_by_workspace = was_docked_;
   if (set_tracked_by_workspace)
     SetTrackedByWorkspace(GetTarget(), false);
   // The root window can change when dragging into a different screen.
   next_window_resizer_->CompleteDrag(event_flags);
+  FinishedDragging();
   if (set_tracked_by_workspace)
     SetTrackedByWorkspace(GetTarget(), tracked_by_workspace);
-  FinishDragging();
 }
 
 void DockedWindowResizer::RevertDrag() {
+  snap_phantom_window_controller_.reset();
+
   // Temporarily clear kWindowTrackedByWorkspaceKey for panels so that they
   // don't get forced into the workspace that may be shrunken because of docked
   // windows.
   bool tracked_by_workspace = GetTrackedByWorkspace(GetTarget());
-  bool set_tracked_by_workspace =
-      (was_docked_ && GetTarget()->type() == aura::client::WINDOW_TYPE_PANEL);
+  bool set_tracked_by_workspace = was_docked_;
   if (set_tracked_by_workspace)
     SetTrackedByWorkspace(GetTarget(), false);
   next_window_resizer_->RevertDrag();
+  FinishedDragging();
   if (set_tracked_by_workspace)
     SetTrackedByWorkspace(GetTarget(), tracked_by_workspace);
-  FinishDragging();
 }
 
 aura::Window* DockedWindowResizer::GetTarget() {
@@ -135,29 +181,57 @@
     : details_(details),
       next_window_resizer_(next_window_resizer),
       dock_layout_(NULL),
+      initial_dock_layout_(NULL),
       did_move_or_resize_(false),
       was_docked_(false),
+      is_docked_(false),
       destroyed_(NULL) {
   DCHECK(details_.is_resizable);
   aura::Window* dock_container = Shell::GetContainer(
       details.window->GetRootWindow(),
-      internal::kShellWindowId_DockedContainer);
-  DCHECK(dock_container->id() == internal::kShellWindowId_DockedContainer);
-  dock_layout_ = static_cast<internal::DockedWindowLayoutManager*>(
+      kShellWindowId_DockedContainer);
+  dock_layout_ = static_cast<DockedWindowLayoutManager*>(
       dock_container->layout_manager());
+  initial_dock_layout_ = dock_layout_;
   was_docked_ = details.window->parent() == dock_container;
+  is_docked_ = was_docked_;
+}
+
+DockedAlignment DockedWindowResizer::GetDraggedWindowAlignment() {
+  aura::Window* window = GetTarget();
+  DockedWindowLayoutManager* layout_manager =
+      GetDockedLayoutManagerAtPoint(last_location_);
+  const DockedAlignment alignment = layout_manager->CalculateAlignment();
+  const gfx::Rect& bounds(window->GetBoundsInScreen());
+
+  // Check if the window is touching the edge - it may need to get docked.
+  if (alignment == DOCKED_ALIGNMENT_NONE)
+    return layout_manager->GetAlignmentOfWindow(window);
+
+  // Both bounds and pointer location are checked because some drags involve
+  // stickiness at the workspace-to-dock boundary and so the |location| may be
+  // outside of the |bounds|.
+  // It is also possible that all the docked windows are minimized or hidden
+  // in which case the dragged window needs to be exactly touching the same
+  // edge that those docked windows were aligned before they got minimized.
+  // TODO(varkha): Consider eliminating sticky behavior on that boundary when
+  // a pointer enters docked area.
+  if ((layout_manager->docked_bounds().Intersects(bounds) &&
+       layout_manager->docked_bounds().Contains(last_location_)) ||
+      alignment == layout_manager->GetAlignmentOfWindow(window)) {
+    // A window is being added to other docked windows (on the same side).
+    return alignment;
+  }
+  return DOCKED_ALIGNMENT_NONE;
 }
 
 bool DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds,
                                           gfx::Point* offset) {
   aura::Window* dock_container = Shell::GetContainer(
       wm::GetRootWindowAt(last_location_),
-      internal::kShellWindowId_DockedContainer);
-  DCHECK(dock_container->id() == internal::kShellWindowId_DockedContainer);
-  internal::DockedWindowLayoutManager* dock_layout =
-      static_cast<internal::DockedWindowLayoutManager*>(
-          dock_container->layout_manager());
-  internal::DockedAlignment dock_alignment = dock_layout->CalculateAlignment();
+      kShellWindowId_DockedContainer);
+  DockedAlignment dock_alignment =
+      GetDockedLayoutManagerAtPoint(last_location_)->CalculateAlignment();
   gfx::Rect dock_bounds = ScreenAsh::ConvertRectFromScreen(
       GetTarget()->parent(), dock_container->GetBoundsInScreen());
   // Windows only snap magnetically when they are close to the edge of the
@@ -165,23 +239,33 @@
   // When a window being dragged is the last window that was previously
   // docked it is still allowed to magnetically snap to either side.
   bool can_snap = was_docked_ ||
-      internal::DockedWindowLayoutManager::ShouldWindowDock(GetTarget(),
-                                                            last_location_);
+      (GetDraggedWindowAlignment() != DOCKED_ALIGNMENT_NONE);
   if (!can_snap)
     return false;
 
-  if (dock_alignment == internal::DOCKED_ALIGNMENT_LEFT ||
-      (dock_alignment == internal::DOCKED_ALIGNMENT_NONE && was_docked_)) {
+  // Distance in pixels that the cursor must move past an edge for a window
+  // to move beyond that edge. Same constant as in WorkspaceWindowResizer
+  // is used for consistency.
+  const int kStickyDistance = WorkspaceWindowResizer::kStickyDistancePixels;
+
+  // Short-range magnetism when retaining docked state. Same constant as in
+  // MagnetismMatcher is used for consistency.
+  const int kSnapToDockDistance = MagnetismMatcher::kMagneticDistance;
+
+  if (dock_alignment == DOCKED_ALIGNMENT_LEFT ||
+      (dock_alignment == DOCKED_ALIGNMENT_NONE && was_docked_)) {
     const int distance = bounds.x() - dock_bounds.x();
-    if (distance < kSnapToDockDistance && distance > -kStickyDistance) {
+    if (distance < (was_docked_ ? kSnapToDockDistance : 0) &&
+        distance > -kStickyDistance) {
       offset->set_x(-distance);
       return true;
     }
   }
-  if (dock_alignment == internal::DOCKED_ALIGNMENT_RIGHT ||
-      (dock_alignment == internal::DOCKED_ALIGNMENT_NONE && was_docked_)) {
+  if (dock_alignment == DOCKED_ALIGNMENT_RIGHT ||
+      (dock_alignment == DOCKED_ALIGNMENT_NONE && was_docked_)) {
     const int distance = dock_bounds.right() - bounds.right();
-    if (distance < kSnapToDockDistance && distance > -kStickyDistance) {
+    if (distance < (was_docked_ ? kSnapToDockDistance : 0) &&
+        distance > -kStickyDistance) {
       offset->set_x(distance);
       return true;
     }
@@ -191,37 +275,54 @@
 
 void DockedWindowResizer::StartedDragging() {
   // Tell the dock layout manager that we are dragging this window.
+  // At this point we are not yet animating the window as it may not be
+  // inside the docked area.
   dock_layout_->StartDragging(GetTarget());
+  // Reparent workspace windows during the drag to elevate them above workspace.
+  // Other windows for which the DockedWindowResizer is instantiated include
+  // panels and windows that are already docked. Those do not need reparenting.
+  if (GetTarget()->type() != aura::client::WINDOW_TYPE_PANEL &&
+      GetTarget()->parent()->id() == kShellWindowId_DefaultContainer) {
+    // The window is going to be reparented - avoid completing the drag.
+    GetTarget()->SetProperty(kContinueDragAfterReparent, true);
+
+    // Reparent the window into the docked windows container in order to get it
+    // on top of other docked windows.
+    aura::Window* docked_container = Shell::GetContainer(
+        GetTarget()->GetRootWindow(),
+        kShellWindowId_DockedContainer);
+    docked_container->AddChild(GetTarget());
+  }
+  if (is_docked_)
+    dock_layout_->DockDraggedWindow(GetTarget());
 }
 
-void DockedWindowResizer::FinishDragging() {
+void DockedWindowResizer::FinishedDragging() {
   if (!did_move_or_resize_)
     return;
 
   aura::Window* window = GetTarget();
   bool should_dock = was_docked_;
-  if ((details_.bounds_change & WindowResizer::kBoundsChange_Repositions) &&
-      !(details_.bounds_change & WindowResizer::kBoundsChange_Resizes) &&
-      CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAshEnableDockedWindows)) {
-    const bool attached_panel =
-        window->type() == aura::client::WINDOW_TYPE_PANEL &&
-        window->GetProperty(internal::kPanelAttachedKey);
-    should_dock = !attached_panel &&
-        internal::DockedWindowLayoutManager::ShouldWindowDock(window,
-                                                              last_location_);
+  const bool attached_panel =
+      window->type() == aura::client::WINDOW_TYPE_PANEL &&
+      window->GetProperty(kPanelAttachedKey);
+  // If a window was previously docked then keep it docked if it is resized and
+  // still aligned at the screen edge.
+  if ((was_docked_ ||
+       ((details_.bounds_change & WindowResizer::kBoundsChange_Repositions) &&
+        !(details_.bounds_change & WindowResizer::kBoundsChange_Resizes)))) {
+    should_dock = GetDraggedWindowAlignment() != DOCKED_ALIGNMENT_NONE;
   }
 
-  // Check if desired docked state is not same as current.
-  // If not same dock or undock accordingly.
-  if (should_dock !=
-      (window->parent()->id() == internal::kShellWindowId_DockedContainer)) {
+  // Check if the window needs to be docked or returned to workspace.
+  aura::Window* dock_container = Shell::GetContainer(
+      window->GetRootWindow(),
+      kShellWindowId_DockedContainer);
+  if (!attached_panel &&
+      should_dock != (window->parent() == dock_container)) {
     if (should_dock) {
-      aura::Window* dock_container = Shell::GetContainer(
-          window->GetRootWindow(),
-          internal::kShellWindowId_DockedContainer);
       dock_container->AddChild(window);
-    } else {
+    } else if (window->parent()->id() == kShellWindowId_DockedContainer) {
       // Reparent the window back to workspace.
       // We need to be careful to give SetDefaultParentByRootWindow location in
       // the right root window (matching the logic in DragWindowResizer) based
@@ -235,6 +336,25 @@
     }
   }
   dock_layout_->FinishDragging();
+
+  // If we started the drag in one root window and moved into another root
+  // but then canceled the drag we may need to inform the original layout
+  // manager that the drag is finished.
+  if (initial_dock_layout_ != dock_layout_)
+    initial_dock_layout_->FinishDragging();
+  is_docked_ = false;
 }
 
-}  // namespace aura
+void DockedWindowResizer::UpdateSnapPhantomWindow() {
+  if (!did_move_or_resize_ || details_.window_component != HTCAPTION)
+    return;
+
+  if (!snap_phantom_window_controller_) {
+    snap_phantom_window_controller_.reset(
+        new PhantomWindowController(GetTarget()));
+  }
+  snap_phantom_window_controller_->Show(dock_layout_->dragged_bounds());
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/wm/dock/docked_window_resizer.h b/ash/wm/dock/docked_window_resizer.h
index 41dd47d..41bb4fe 100644
--- a/ash/wm/dock/docked_window_resizer.h
+++ b/ash/wm/dock/docked_window_resizer.h
@@ -5,8 +5,10 @@
 #ifndef ASH_WM_DOCK_DOCK_WINDOW_RESIZER_H_
 #define ASH_WM_DOCK_DOCK_WINDOW_RESIZER_H_
 
+#include "ash/wm/dock/dock_types.h"
 #include "ash/wm/window_resizer.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 
 namespace gfx {
 class Point;
@@ -18,10 +20,10 @@
 }
 
 namespace ash {
-
 namespace internal {
+
 class DockedWindowLayoutManager;
-}
+class PhantomWindowController;
 
 // DockWindowResizer is used by ToplevelWindowEventFilter to handle dragging,
 // moving or resizing of a window while it is docked to the side of a screen.
@@ -52,6 +54,12 @@
   DockedWindowResizer(WindowResizer* next_window_resizer,
                       const Details& details);
 
+  // Returns the side of the screen that the window should dock to or
+  // DOCKED_ALIGNMENT_NONE when the window is not on a side or when some other
+  // windows are already docked on the other side or when launcher (shelf) is
+  // aligned on the same side.
+  DockedAlignment GetDraggedWindowAlignment();
+
   // Checks if the provided window bounds should snap to the side of a screen.
   // If so the offset returned gives the necessary adjustment to snap.
   bool MaybeSnapToEdge(const gfx::Rect& bounds, gfx::Point* offset);
@@ -62,7 +70,10 @@
 
   // Informs the DockLayoutManager that the drag is complete if it was informed
   // of the drag start.
-  void FinishDragging();
+  void FinishedDragging();
+
+  // Updates the bounds of the phantom window that is used as a docking hint.
+  void UpdateSnapPhantomWindow();
 
   const Details details_;
 
@@ -73,13 +84,20 @@
 
   // Dock container window.
   internal::DockedWindowLayoutManager* dock_layout_;
+  internal::DockedWindowLayoutManager* initial_dock_layout_;
 
   // Set to true once Drag() is invoked and the bounds of the window change.
   bool did_move_or_resize_;
 
+  // Gives a preview of where the the window will end up.
+  scoped_ptr<PhantomWindowController> snap_phantom_window_controller_;
+
   // Set to true if the window that is being dragged was docked before drag.
   bool was_docked_;
 
+  // True if the dragged window is docked during the drag.
+  bool is_docked_;
+
   // If non-NULL the destructor sets this to true. Used to determine if this has
   // been deleted.
   bool* destroyed_;
@@ -87,6 +105,7 @@
   DISALLOW_COPY_AND_ASSIGN(DockedWindowResizer);
 };
 
+}  // namespace internal
 }  // namespace ash
 
 #endif  // ASH_WM_DOCK_DOCK_WINDOW_RESIZER_H_
diff --git a/ash/wm/dock/docked_window_resizer_unittest.cc b/ash/wm/dock/docked_window_resizer_unittest.cc
index 606e6f4..49aeca2 100644
--- a/ash/wm/dock/docked_window_resizer_unittest.cc
+++ b/ash/wm/dock/docked_window_resizer_unittest.cc
@@ -63,11 +63,6 @@
     DOCKED_EDGE_RIGHT,
   };
 
-  enum DockedState {
-    UNDOCKED,
-    DOCKED,
-  };
-
   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         &delegate_,
@@ -145,15 +140,12 @@
   }
 
   // Panels are parented by panel container during drags.
-  // Docked windows are parented by dock container during drags.
-  // All other windows that we are testing here have default container as a
-  // parent.
-  int CorrectContainerIdDuringDrag(DockedState is_docked) {
+  // All other windows that are tested here are parented by dock container
+  // during drags.
+  int CorrectContainerIdDuringDrag() {
     if (window_type_ == aura::client::WINDOW_TYPE_PANEL)
       return internal::kShellWindowId_PanelContainer;
-    if (is_docked == DOCKED)
-      return internal::kShellWindowId_DockedContainer;
-    return internal::kShellWindowId_DefaultContainer;
+    return internal::kShellWindowId_DockedContainer;
   }
 
   // Test dragging the window vertically (to detach if it is a panel) and then
@@ -198,7 +190,7 @@
       // Drag enough to detach since our tests assume panels to be initially
       // detached.
       DragMove(0, dy);
-      EXPECT_EQ(CorrectContainerIdDuringDrag(UNDOCKED), window->parent()->id());
+      EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
       EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
       EXPECT_EQ(initial_bounds.y() + dy, window->GetBoundsInScreen().y());
 
@@ -220,7 +212,7 @@
     else if (edge == DOCKED_EDGE_RIGHT)
       dx += window->GetRootWindow()->bounds().right() - initial_bounds.right();
     DragMove(dx, window_type_ == aura::client::WINDOW_TYPE_PANEL ? 0 : dy);
-    EXPECT_EQ(CorrectContainerIdDuringDrag(UNDOCKED), window->parent()->id());
+    EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
     // Release the mouse and the panel should be attached to the dock.
     DragEnd();
 
@@ -389,9 +381,10 @@
             window->GetBoundsInScreen().right());
   EXPECT_EQ(internal::kShellWindowId_DockedContainer, window->parent()->id());
 
-  // Try to detach by dragging left a bit (should stay docked)
+  // Try to detach by dragging left less than kSnapToDockDistance.
+  // The window should stay docked.
   ASSERT_NO_FATAL_FAILURE(DragStart(window.get()));
-  DragMove(-10, -10);
+  DragMove(-4, -10);
   // Release the mouse and the window should be still attached to the dock.
   DragEnd();
 
@@ -400,7 +393,8 @@
             window->GetBoundsInScreen().right());
   EXPECT_EQ(internal::kShellWindowId_DockedContainer, window->parent()->id());
 
-  // Try to detach by dragging left a bit more (should get undocked)
+  // Try to detach by dragging left by kSnapToDockDistance or more.
+  // The window should get undocked.
   ASSERT_NO_FATAL_FAILURE(DragStart(window.get()));
   DragMove(-32, -10);
   // Release the mouse and the window should be no longer attached to the dock.
@@ -545,7 +539,7 @@
   // but not enough to land in the other screen
   ASSERT_NO_FATAL_FAILURE(DragStart(window.get()));
   DragMove(70, 0);
-  EXPECT_EQ(CorrectContainerIdDuringDrag(DOCKED), window->parent()->id());
+  EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
   DragEnd();
   EXPECT_NE(window->GetRootWindow()->bounds().right(),
             window->GetBoundsInScreen().right());
@@ -556,7 +550,7 @@
   // Move back left - should dock again.
   ASSERT_NO_FATAL_FAILURE(DragStart(window.get()));
   DragMove(-70, 0);
-  EXPECT_EQ(CorrectContainerIdDuringDrag(UNDOCKED), window->parent()->id());
+  EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
   DragEnd();
   EXPECT_EQ(window->GetRootWindow()->bounds().right(),
             window->GetBoundsInScreen().right());
@@ -572,7 +566,7 @@
       window->bounds().width()/2 + 10,
       0));
   DragMove(window->bounds().width()/2 - 5, 0);
-  EXPECT_EQ(CorrectContainerIdDuringDrag(DOCKED), window->parent()->id());
+  EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
   DragEnd();
   EXPECT_NE(window->GetRootWindow()->bounds().right(),
             window->GetBoundsInScreen().right());
@@ -589,7 +583,7 @@
   DragMove(window->GetRootWindow()->GetBoundsInScreen().x() -
            window->GetBoundsInScreen().x(),
            0);
-  EXPECT_EQ(CorrectContainerIdDuringDrag(UNDOCKED), window->parent()->id());
+  EXPECT_EQ(CorrectContainerIdDuringDrag(), window->parent()->id());
   DragEnd();
   EXPECT_EQ(window->GetRootWindow()->GetBoundsInScreen().x(),
             window->GetBoundsInScreen().x());
@@ -620,7 +614,7 @@
   EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, manager->alignment_);
   EXPECT_EQ(w1->bounds().width(), manager->docked_width_);
 
-  DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_RIGHT, w2.get(), 0, 50);
+  DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_RIGHT, w2.get(), 0, 100);
   // Both windows should now be attached and snapped to the right edge.
   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
             w2->GetBoundsInScreen().right());
@@ -727,12 +721,11 @@
   ASSERT_NO_FATAL_FAILURE(DragStart(w1.get()));
   EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, manager->alignment_);
   DragMove(-35, 10);
-  // For NORMAL windows alignment is set to "RIGHT" until the drag is completed.
-  // For PANEL windows alignment is set to "NONE" when drag starts.
-  EXPECT_EQ(test_panels() ? DOCKED_ALIGNMENT_NONE : DOCKED_ALIGNMENT_RIGHT,
-            manager->alignment_);
+  // Alignment is set to "NONE" when drag starts.
+  EXPECT_EQ(DOCKED_ALIGNMENT_NONE, manager->alignment_);
   // Release the mouse and the window should be no longer attached to the edge.
   DragEnd();
+  EXPECT_EQ(DOCKED_ALIGNMENT_NONE, manager->alignment_);
   // Dock should get shrunk and desktop should get expanded.
   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, w1->parent()->id());
   EXPECT_EQ(internal::kShellWindowId_DefaultContainer, w2->parent()->id());
@@ -824,7 +817,7 @@
 
   // Drag w2 by a bit more - it should resist the drag (stuck edges)
   int start_x = w2->bounds().x();
-  ASSERT_NO_FATAL_FAILURE(DragStart(w2.get()));
+  ASSERT_NO_FATAL_FAILURE(DragStartAtOffsetFromwindowOrigin(w2.get(), 100, 5));
   DragMove(-2, 0);
   // Window should not actually move.
   EXPECT_EQ(start_x, w2->bounds().x());
@@ -888,7 +881,7 @@
   EXPECT_EQ(DOCKED_ALIGNMENT_RIGHT, manager->alignment_);
   EXPECT_EQ(w1->bounds().width(), manager->docked_width_);
 
-  DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_RIGHT, w2.get(), 0, 50);
+  DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_RIGHT, w2.get(), 0, 100);
   // Both windows should now be attached and snapped to the right edge.
   EXPECT_EQ(w2->GetRootWindow()->bounds().right(),
             w2->GetBoundsInScreen().right());
@@ -1031,12 +1024,11 @@
   // Detach and drag down to shelf.
   ASSERT_NO_FATAL_FAILURE(DragStart(w1.get()));
   DragMove(-40, 0);
-  // For NORMAL windows alignment is set to "RIGHT" until the drag is completed.
-  // For PANEL windows alignment is set to "NONE" when drag starts.
-  EXPECT_EQ(test_panels() ? DOCKED_ALIGNMENT_NONE : DOCKED_ALIGNMENT_RIGHT,
-            manager->alignment_);
+  // Alignment is set to "NONE" when drag starts.
+  EXPECT_EQ(DOCKED_ALIGNMENT_NONE, manager->alignment_);
   // Release the mouse and the window should be no longer attached to the edge.
   DragEnd();
+  EXPECT_EQ(DOCKED_ALIGNMENT_NONE, manager->alignment_);
 
   // Drag down almost to shelf. A panel will snap, a regular window won't.
   ShelfWidget* shelf = Launcher::ForPrimaryDisplay()->shelf_widget();
diff --git a/ash/wm/event_client_impl.cc b/ash/wm/event_client_impl.cc
index fcdc1b4..03d4dea 100644
--- a/ash/wm/event_client_impl.cc
+++ b/ash/wm/event_client_impl.cc
@@ -8,6 +8,7 @@
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
 #include "ui/aura/window.h"
+#include "ui/keyboard/keyboard_util.h"
 
 namespace ash {
 namespace internal {
@@ -21,26 +22,34 @@
 bool EventClientImpl::CanProcessEventsWithinSubtree(
     const aura::Window* window) const {
   const aura::RootWindow* root_window = window ? window->GetRootWindow() : NULL;
-  if (!root_window)
+  if (!root_window ||
+      !Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked()) {
     return true;
-  if (Shell::GetInstance()->session_state_delegate()->IsUserSessionBlocked()) {
-    const aura::Window* lock_screen_containers = Shell::GetContainer(
-        root_window,
-        kShellWindowId_LockScreenContainersContainer);
-    const aura::Window* lock_background_containers = Shell::GetContainer(
-        root_window,
-        kShellWindowId_LockScreenBackgroundContainer);
-    const aura::Window* lock_screen_related_containers = Shell::GetContainer(
-        root_window,
-        kShellWindowId_LockScreenRelatedContainersContainer);
-    return (window->Contains(lock_screen_containers) &&
-        window->Contains(lock_background_containers) &&
-        window->Contains(lock_screen_related_containers)) ||
-        lock_screen_containers->Contains(window) ||
-        lock_background_containers->Contains(window) ||
-        lock_screen_related_containers->Contains(window);
   }
-  return true;
+
+  const aura::Window* lock_screen_containers = Shell::GetContainer(
+      root_window,
+      kShellWindowId_LockScreenContainersContainer);
+  const aura::Window* lock_background_containers = Shell::GetContainer(
+      root_window,
+      kShellWindowId_LockScreenBackgroundContainer);
+  const aura::Window* lock_screen_related_containers = Shell::GetContainer(
+      root_window,
+      kShellWindowId_LockScreenRelatedContainersContainer);
+  bool can_process_events = (window->Contains(lock_screen_containers) &&
+      window->Contains(lock_background_containers) &&
+      window->Contains(lock_screen_related_containers)) ||
+      lock_screen_containers->Contains(window) ||
+      lock_background_containers->Contains(window) ||
+      lock_screen_related_containers->Contains(window);
+  if (keyboard::IsKeyboardEnabled()) {
+    const aura::Window* virtual_keyboard_container = Shell::GetContainer(
+        root_window,
+        kShellWindowId_VirtualKeyboardContainer);
+    can_process_events |= (window->Contains(virtual_keyboard_container) ||
+                           virtual_keyboard_container->Contains(window));
+  }
+  return can_process_events;
 }
 
 ui::EventTarget* EventClientImpl::GetToplevelEventTarget() {
diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc
index adf9dd7..5b7782a 100644
--- a/ash/wm/frame_painter.cc
+++ b/ash/wm/frame_painter.cc
@@ -787,19 +787,6 @@
                    theme_provider->GetImageSkiaNamed(pushed_image_id));
 }
 
-void FramePainter::SetToggledButtonImages(views::ToggleImageButton* button,
-                                          int normal_image_id,
-                                          int hot_image_id,
-                                          int pushed_image_id) {
-  ui::ThemeProvider* theme_provider = frame_->GetThemeProvider();
-  button->SetToggledImage(views::CustomButton::STATE_NORMAL,
-                          theme_provider->GetImageSkiaNamed(normal_image_id));
-  button->SetToggledImage(views::CustomButton::STATE_HOVERED,
-                          theme_provider->GetImageSkiaNamed(hot_image_id));
-  button->SetToggledImage(views::CustomButton::STATE_PRESSED,
-                          theme_provider->GetImageSkiaNamed(pushed_image_id));
-}
-
 int FramePainter::GetTitleOffsetX() const {
   return window_icon_ ?
       window_icon_->bounds().right() + kTitleIconOffsetX :
diff --git a/ash/wm/frame_painter.h b/ash/wm/frame_painter.h
index e79b012..b164edf 100644
--- a/ash/wm/frame_painter.h
+++ b/ash/wm/frame_painter.h
@@ -31,7 +31,6 @@
 namespace views {
 class ImageButton;
 class NonClientFrameView;
-class ToggleImageButton;
 class View;
 class Widget;
 }
@@ -160,6 +159,8 @@
   FRIEND_TEST_ALL_PREFIXES(FramePainterTest, GetHeaderOpacity);
   FRIEND_TEST_ALL_PREFIXES(FramePainterTest, TitleIconAlignment);
   FRIEND_TEST_ALL_PREFIXES(FramePainterTest, ChildWindowVisibility);
+  FRIEND_TEST_ALL_PREFIXES(FramePainterTest,
+                           NoCrashShutdownWithAlwaysOnTopWindow);
 
   // Sets the images for a button based on IDs from the |frame_| theme provider.
   void SetButtonImages(views::ImageButton* button,
@@ -167,13 +168,6 @@
                        int hot_image_id,
                        int pushed_image_id);
 
-  // Sets the toggled-state button images for a button based on IDs from the
-  // |frame_| theme provider.
-  void SetToggledButtonImages(views::ToggleImageButton* button,
-                              int normal_image_id,
-                              int hot_image_id,
-                              int pushed_image_id);
-
   // Returns the offset between window left edge and title string.
   int GetTitleOffsetX() const;
 
diff --git a/ash/wm/frame_painter_unittest.cc b/ash/wm/frame_painter_unittest.cc
index ee9313f..5826be6 100644
--- a/ash/wm/frame_painter_unittest.cc
+++ b/ash/wm/frame_painter_unittest.cc
@@ -12,6 +12,7 @@
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "grit/ash_resources.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/client/aura_constants.h"
@@ -25,6 +26,7 @@
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_observer.h"
 #include "ui/views/window/non_client_view.h"
 
 using ash::FramePainter;
@@ -148,6 +150,33 @@
   return painter;
 }
 
+// Self-owned manager of the frame painter which deletes the painter and itself
+// when its widget is closed.
+class FramePainterOwner : views::WidgetObserver {
+ public:
+  explicit FramePainterOwner(Widget* widget)
+      : frame_painter_(CreateTestPainter(widget)) {
+    widget->AddObserver(this);
+  }
+
+  virtual ~FramePainterOwner() {}
+
+  FramePainter* frame_painter() { return frame_painter_.get(); }
+
+ private:
+  virtual void OnWidgetDestroying(Widget* widget) OVERRIDE {
+    widget->RemoveObserver(this);
+    // Do not delete directly here, since the task of FramePainter causing
+    // the crash of crbug.com/273310 may run after this class handles this
+    // event.
+    base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+  }
+
+  scoped_ptr<FramePainter> frame_painter_;
+
+  DISALLOW_COPY_AND_ASSIGN(FramePainterOwner);
+};
+
 }  // namespace
 
 namespace ash {
@@ -690,4 +719,33 @@
                                  0));
 }
 
+TEST_F(FramePainterTest, NoCrashShutdownWithAlwaysOnTopWindow) {
+  // Create normal window and an always-on-top window, and leave it as is
+  // and finish the test, then verify it doesn't cause a crash. See
+  // crbug.com/273310.  Note that those widgets will be deleted at
+  // RootWindowController::CloseChildWindows(), so this code is memory-safe.
+  Widget* w1 = new Widget;
+  Widget::InitParams params1;
+  params1.context = CurrentContext();
+  w1->Init(params1);
+  FramePainterOwner* o1 = new FramePainterOwner(w1);
+  FramePainter* p1 = o1->frame_painter();
+  w1->SetBounds(gfx::Rect(0, 0, 100, 100));
+  w1->Show();
+  EXPECT_TRUE(p1->UseSoloWindowHeader());
+
+  Widget* w2 = new Widget;
+  Widget::InitParams params2;
+  params2.context = CurrentContext();
+  params2.keep_on_top = true;
+  w2->Init(params2);
+  FramePainterOwner* o2 = new FramePainterOwner(w2);
+  FramePainter* p2 = o2->frame_painter();
+  w2->Show();
+  EXPECT_FALSE(p1->UseSoloWindowHeader());
+  EXPECT_FALSE(p2->UseSoloWindowHeader());
+
+  // Exit with no resource release. They'll be released at shutdown.
+}
+
 }  // namespace ash
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
new file mode 100644
index 0000000..91aca6d
--- /dev/null
+++ b/ash/wm/overview/window_selector.cc
@@ -0,0 +1,285 @@
+// Copyright 2013 The Chromium Authors. 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/window_selector.h"
+
+#include <algorithm>
+
+#include "ash/screen_ash.h"
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/wm/overview/window_selector_delegate.h"
+#include "ash/wm/overview/window_selector_window.h"
+#include "ash/wm/window_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/base/events/event.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/views/widget/widget.h"
+
+namespace ash {
+
+namespace {
+
+const float kCardAspectRatio = 4.0f / 3.0f;
+const int kWindowMargin = 30;
+const int kMinCardsMajor = 3;
+const int kOverviewSelectorTransitionMilliseconds = 100;
+const SkColor kWindowSelectorSelectionColor = SK_ColorBLACK;
+const float kWindowSelectorSelectionOpacity = 0.5f;
+const int kWindowSelectorSelectionPadding = 15;
+
+// A comparator for locating a given target window.
+struct WindowSelectorWindowComparator
+    : public std::unary_function<WindowSelectorWindow*, bool> {
+  explicit WindowSelectorWindowComparator(const aura::Window* target_window)
+      : target(target_window) {
+  }
+
+  bool operator()(const WindowSelectorWindow* window) const {
+    return target == window->window();
+  }
+
+  const aura::Window* target;
+};
+
+}  // namespace
+
+WindowSelector::WindowSelector(const WindowList& windows,
+                               WindowSelector::Mode mode,
+                               WindowSelectorDelegate* delegate)
+    : mode_(mode),
+      delegate_(delegate),
+      selected_window_(0),
+      selection_root_(NULL) {
+  DCHECK(delegate_);
+  for (size_t i = 0; i < windows.size(); ++i) {
+    windows[i]->AddObserver(this);
+    windows_.push_back(new WindowSelectorWindow(windows[i]));
+  }
+  if (mode == WindowSelector::CYCLE)
+    selection_root_ = ash::Shell::GetActiveRootWindow();
+  PositionWindows();
+  ash::Shell::GetInstance()->AddPreTargetHandler(this);
+}
+
+WindowSelector::~WindowSelector() {
+  for (size_t i = 0; i < windows_.size(); i++) {
+    windows_[i]->window()->RemoveObserver(this);
+  }
+  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
+}
+
+void WindowSelector::Step(WindowSelector::Direction direction) {
+  DCHECK(windows_.size() > 0);
+  if (!selection_widget_)
+    InitializeSelectionWidget();
+  selected_window_ = (selected_window_ + windows_.size() +
+      (direction == WindowSelector::FORWARD ? 1 : -1)) % windows_.size();
+  UpdateSelectionLocation(true);
+}
+
+void WindowSelector::SelectWindow() {
+  delegate_->OnWindowSelected(windows_[selected_window_]->window());
+}
+
+void WindowSelector::OnEvent(ui::Event* event) {
+  // If the event is targetted at any of the windows in the overview, then
+  // prevent it from propagating.
+  aura::Window* target = static_cast<aura::Window*>(event->target());
+  for (size_t i = 0; i < windows_.size(); ++i) {
+    if (windows_[i]->Contains(target)) {
+      // TODO(flackr): StopPropogation prevents generation of gesture events.
+      // We should find a better way to prevent events from being delivered to
+      // the window, perhaps a transparent window in front of the target window
+      // or using EventClientImpl::CanProcessEventsWithinSubtree.
+      event->StopPropagation();
+      break;
+    }
+  }
+
+  // This object may not be valid after this call as a selection event can
+  // trigger deletion of the window selector.
+  ui::EventHandler::OnEvent(event);
+}
+
+void WindowSelector::OnMouseEvent(ui::MouseEvent* event) {
+  if (event->type() != ui::ET_MOUSE_RELEASED)
+    return;
+  WindowSelectorWindow* target = GetEventTarget(event);
+  if (!target)
+    return;
+
+  HandleSelectionEvent(target);
+}
+
+void WindowSelector::OnTouchEvent(ui::TouchEvent* event) {
+  if (event->type() != ui::ET_TOUCH_PRESSED)
+    return;
+  WindowSelectorWindow* target = GetEventTarget(event);
+  if (!target)
+    return;
+
+  HandleSelectionEvent(target);
+}
+
+void WindowSelector::OnWindowDestroyed(aura::Window* window) {
+  ScopedVector<WindowSelectorWindow>::iterator iter =
+      std::find_if(windows_.begin(), windows_.end(),
+                   WindowSelectorWindowComparator(window));
+  DCHECK(iter != windows_.end());
+  size_t deleted_index = iter - windows_.begin();
+  (*iter)->OnWindowDestroyed();
+  windows_.erase(iter);
+  if (windows_.empty()) {
+    delegate_->OnSelectionCanceled();
+    return;
+  }
+  if (selected_window_ >= deleted_index) {
+    if (selected_window_ > deleted_index)
+      selected_window_--;
+    selected_window_ = selected_window_ % windows_.size();
+    UpdateSelectionLocation(true);
+  }
+
+  PositionWindows();
+}
+
+WindowSelectorWindow* WindowSelector::GetEventTarget(ui::LocatedEvent* event) {
+  aura::Window* target = static_cast<aura::Window*>(event->target());
+  // If the target window doesn't actually contain the event location (i.e.
+  // mouse down over the window and mouse up elsewhere) then do not select the
+  // window.
+  if (!target->HitTest(event->location()))
+    return NULL;
+
+  for (size_t i = 0; i < windows_.size(); i++) {
+    if (windows_[i]->Contains(target))
+      return windows_[i];
+  }
+  return NULL;
+}
+
+void WindowSelector::HandleSelectionEvent(WindowSelectorWindow* target) {
+  // The selected window should not be minimized when window selection is
+  // ended.
+  target->RestoreWindowOnExit();
+  delegate_->OnWindowSelected(target->window());
+}
+
+void WindowSelector::PositionWindows() {
+  if (selection_root_) {
+    DCHECK_EQ(mode_, CYCLE);
+    std::vector<WindowSelectorWindow*> windows;
+    for (size_t i = 0; i < windows_.size(); ++i)
+      windows.push_back(windows_[i]);
+    PositionWindowsOnRoot(selection_root_, windows);
+  } else {
+    DCHECK_EQ(mode_, OVERVIEW);
+    Shell::RootWindowList root_window_list = Shell::GetAllRootWindows();
+    for (size_t i = 0; i < root_window_list.size(); ++i)
+      PositionWindowsFromRoot(root_window_list[i]);
+  }
+}
+
+void WindowSelector::PositionWindowsFromRoot(aura::RootWindow* root_window) {
+  std::vector<WindowSelectorWindow*> windows;
+  for (size_t i = 0; i < windows_.size(); ++i) {
+    if (windows_[i]->window()->GetRootWindow() == root_window)
+      windows.push_back(windows_[i]);
+  }
+  PositionWindowsOnRoot(root_window, windows);
+}
+
+void WindowSelector::PositionWindowsOnRoot(
+    aura::RootWindow* root_window,
+    const std::vector<WindowSelectorWindow*>& windows) {
+  if (windows.empty())
+    return;
+
+  gfx::Size window_size;
+  gfx::Rect total_bounds = ScreenAsh::ConvertRectToScreen(root_window,
+      ScreenAsh::GetDisplayWorkAreaBoundsInParent(
+      Shell::GetContainer(root_window,
+                          internal::kShellWindowId_DefaultContainer)));
+
+  // Find the minimum number of windows per row that will fit all of the
+  // windows on screen.
+  size_t columns = std::max(
+      total_bounds.width() > total_bounds.height() ? kMinCardsMajor : 1,
+      static_cast<int>(ceil(sqrt(total_bounds.width() * windows.size() /
+                                 (kCardAspectRatio * total_bounds.height())))));
+  size_t rows = ((windows.size() + columns - 1) / columns);
+  window_size.set_width(std::min(
+      static_cast<int>(total_bounds.width() / columns),
+      static_cast<int>(total_bounds.height() * kCardAspectRatio / rows)));
+  window_size.set_height(window_size.width() / kCardAspectRatio);
+
+  // Calculate the X and Y offsets necessary to center the grid.
+  int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 :
+      (columns - windows.size()) * window_size.width()) +
+      (total_bounds.width() - columns * window_size.width())) / 2;
+  int y_offset = total_bounds.y() + (total_bounds.height() -
+      rows * window_size.height()) / 2;
+  for (size_t i = 0; i < windows.size(); ++i) {
+    gfx::Transform transform;
+    int column = i % columns;
+    int row = i / columns;
+    gfx::Rect target_bounds(window_size.width() * column + x_offset,
+                            window_size.height() * row + y_offset,
+                            window_size.width(),
+                            window_size.height());
+    target_bounds.Inset(kWindowMargin, kWindowMargin);
+    windows[i]->TransformToFitBounds(root_window, target_bounds);
+  }
+}
+
+void WindowSelector::InitializeSelectionWidget() {
+  selection_widget_.reset(new views::Widget);
+  views::Widget::InitParams params;
+  params.type = views::Widget::InitParams::TYPE_POPUP;
+  params.can_activate = false;
+  params.keep_on_top = false;
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
+  params.parent = Shell::GetContainer(
+      selection_root_,
+      internal::kShellWindowId_DefaultContainer);
+  params.accept_events = false;
+  selection_widget_->set_focus_on_creation(false);
+  selection_widget_->Init(params);
+  views::View* content_view = new views::View;
+  content_view->set_background(
+      views::Background::CreateSolidBackground(kWindowSelectorSelectionColor));
+  selection_widget_->SetContentsView(content_view);
+  UpdateSelectionLocation(false);
+  selection_widget_->GetNativeWindow()->parent()->StackChildAtBottom(
+      selection_widget_->GetNativeWindow());
+  selection_widget_->Show();
+  selection_widget_->GetNativeWindow()->layer()->SetOpacity(
+      kWindowSelectorSelectionOpacity);
+}
+
+void WindowSelector::UpdateSelectionLocation(bool animate) {
+  if (!selection_widget_)
+    return;
+  gfx::Rect target_bounds = windows_[selected_window_]->bounds();
+  target_bounds.Inset(-kWindowSelectorSelectionPadding,
+                      -kWindowSelectorSelectionPadding);
+  if (animate) {
+    ui::ScopedLayerAnimationSettings animation_settings(
+        selection_widget_->GetNativeWindow()->layer()->GetAnimator());
+    animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
+        kOverviewSelectorTransitionMilliseconds));
+    animation_settings.SetPreemptionStrategy(
+        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+    selection_widget_->SetBounds(target_bounds);
+  } else {
+    selection_widget_->SetBounds(target_bounds);
+  }
+}
+
+}  // namespace ash
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
new file mode 100644
index 0000000..79de36f
--- /dev/null
+++ b/ash/wm/overview/window_selector.h
@@ -0,0 +1,120 @@
+// Copyright 2013 The Chromium Authors. 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_WINDOW_SELECTOR_H_
+#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/events/event_handler.h"
+#include "ui/gfx/transform.h"
+
+namespace aura {
+class RootWindow;
+}
+
+namespace ui {
+class LocatedEvent;
+}
+
+namespace views {
+class Widget;
+}
+
+namespace ash {
+
+class WindowSelectorDelegate;
+class WindowSelectorWindow;
+
+// The WindowSelector shows a grid of all of your windows and allows selecting
+// a window by clicking or tapping on it (OVERVIEW mode) or by alt-tabbing to
+// it (CYCLE mode).
+class WindowSelector : public ui::EventHandler,
+                       public aura::WindowObserver {
+ public:
+  enum Direction {
+    FORWARD,
+    BACKWARD
+  };
+  enum Mode {
+    CYCLE,
+    OVERVIEW
+  };
+
+  typedef std::vector<aura::Window*> WindowList;
+
+  WindowSelector(const WindowList& windows,
+                 Mode mode,
+                 WindowSelectorDelegate* delegate);
+  virtual ~WindowSelector();
+
+  // Step to the next window in |direction|.
+  void Step(Direction direction);
+
+  // Select the current window.
+  void SelectWindow();
+
+  Mode mode() { return mode_; }
+
+  // ui::EventHandler:
+  virtual void OnEvent(ui::Event* event) OVERRIDE;
+  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+  virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+
+  // aura::WindowObserver:
+  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ private:
+  // Returns the target of |event| or NULL if the event is not targeted at
+  // any of the windows in the selector.
+  WindowSelectorWindow* GetEventTarget(ui::LocatedEvent* event);
+
+  // Handles a selection event for |target|.
+  void HandleSelectionEvent(WindowSelectorWindow* target);
+
+  // 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);
+  // Position all of the |windows| to fit on the |root_window|.
+  void PositionWindowsOnRoot(aura::RootWindow* root_window,
+                             const std::vector<WindowSelectorWindow*>& windows);
+
+  void InitializeSelectionWidget();
+
+  // Updates the selection widget's location to the currently selected window.
+  // If |animate| the transition to the new location is animated.
+  void UpdateSelectionLocation(bool animate);
+
+  // The collection of windows in the overview wrapped by a helper class which
+  // restores their state and helps transform them to other root windows.
+  ScopedVector<WindowSelectorWindow> windows_;
+
+  // The window selection mode.
+  Mode mode_;
+
+  // Weak pointer to the selector delegate which will be called when a
+  // selection is made.
+  WindowSelectorDelegate* delegate_;
+
+  // Index of the currently selected window if the mode is CYCLE.
+  size_t selected_window_;
+
+  // Widget indicating which window is currently selected.
+  scoped_ptr<views::Widget> selection_widget_;
+
+  // In CYCLE mode, the root window in which selection is taking place.
+  // NULL otherwise.
+  aura::RootWindow* selection_root_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowSelector);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_OVERVIEW_WINDOW_SELECTOR_H_
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
new file mode 100644
index 0000000..a04669f
--- /dev/null
+++ b/ash/wm/overview/window_selector_controller.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 "ash/wm/overview/window_selector_controller.h"
+
+#include "ash/session_state_delegate.h"
+#include "ash/shell.h"
+#include "ash/wm/mru_window_tracker.h"
+#include "ash/wm/overview/window_selector.h"
+#include "ash/wm/window_util.h"
+#include "ui/base/events/event.h"
+#include "ui/base/events/event_handler.h"
+
+namespace ash {
+
+namespace {
+
+// Filter to watch for the termination of a keyboard gesture to cycle through
+// multiple windows.
+class WindowSelectorEventFilter : public ui::EventHandler {
+ public:
+  WindowSelectorEventFilter();
+  virtual ~WindowSelectorEventFilter();
+
+  // Overridden from ui::EventHandler:
+  virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WindowSelectorEventFilter);
+};
+
+// Watch for all keyboard events by filtering the root window.
+WindowSelectorEventFilter::WindowSelectorEventFilter() {
+  Shell::GetInstance()->AddPreTargetHandler(this);
+}
+
+WindowSelectorEventFilter::~WindowSelectorEventFilter() {
+  Shell::GetInstance()->RemovePreTargetHandler(this);
+}
+
+void WindowSelectorEventFilter::OnKeyEvent(ui::KeyEvent* event) {
+  // Views uses VKEY_MENU for both left and right Alt keys.
+  if (event->key_code() == ui::VKEY_MENU &&
+      event->type() == ui::ET_KEY_RELEASED) {
+    Shell::GetInstance()->window_selector_controller()->AltKeyReleased();
+    // Warning: |this| will be deleted from here on.
+  }
+}
+
+}  // namespace
+
+WindowSelectorController::WindowSelectorController() {
+}
+
+WindowSelectorController::~WindowSelectorController() {
+}
+
+// static
+bool WindowSelectorController::CanSelect() {
+  // Don't allow a window overview if the screen is locked or a modal dialog is
+  // open.
+  return !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() &&
+         !Shell::GetInstance()->IsSystemModalWindowOpen();
+}
+
+void WindowSelectorController::ToggleOverview() {
+  if (window_selector_.get()) {
+    window_selector_.reset();
+  } else {
+    std::vector<aura::Window*> windows = ash::Shell::GetInstance()->
+        mru_window_tracker()->BuildMruWindowList();
+    // Don't enter overview mode with no windows.
+    if (windows.empty())
+      return;
+
+    // Deactivating the window will hide popup windows like the omnibar or
+    // open menus.
+    aura::Window* active_window = wm::GetActiveWindow();
+    if (active_window)
+      wm::DeactivateWindow(active_window);
+    window_selector_.reset(
+        new WindowSelector(windows, WindowSelector::OVERVIEW, this));
+  }
+}
+
+void WindowSelectorController::HandleCycleWindow(
+    WindowSelector::Direction direction) {
+  if (!CanSelect())
+    return;
+
+  if (!IsSelecting()) {
+    event_handler_.reset(new WindowSelectorEventFilter());
+    std::vector<aura::Window*> windows = ash::Shell::GetInstance()->
+        mru_window_tracker()->BuildMruWindowList();
+    window_selector_.reset(
+        new WindowSelector(windows, WindowSelector::CYCLE, this));
+    window_selector_->Step(direction);
+  } else if (window_selector_->mode() == WindowSelector::CYCLE) {
+    window_selector_->Step(direction);
+  }
+}
+
+void WindowSelectorController::AltKeyReleased() {
+  event_handler_.reset();
+  window_selector_->SelectWindow();
+}
+
+bool WindowSelectorController::IsSelecting() {
+  return window_selector_.get() != NULL;
+}
+
+void WindowSelectorController::OnWindowSelected(aura::Window* window) {
+  window_selector_.reset();
+  wm::ActivateWindow(window);
+}
+
+void WindowSelectorController::OnSelectionCanceled() {
+  window_selector_.reset();
+}
+
+}  // namespace ash
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h
new file mode 100644
index 0000000..725e902
--- /dev/null
+++ b/ash/wm/overview/window_selector_controller.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 ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_
+#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_
+
+#include <list>
+#include <vector>
+
+#include "ash/ash_export.h"
+#include "ash/wm/overview/window_selector.h"
+#include "ash/wm/overview/window_selector_delegate.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_observer.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+class EventHandler;
+}
+
+namespace ash {
+
+class WindowSelector;
+
+// Manages a window selector which displays an overview of all windows and
+// allows selecting a window to activate it.
+class ASH_EXPORT WindowSelectorController
+    : public WindowSelectorDelegate {
+ public:
+  WindowSelectorController();
+  virtual ~WindowSelectorController();
+
+  // Returns true if selecting windows in an overview is enabled. This is false
+  // at certain times, such as when the lock screen is visible.
+  static bool CanSelect();
+
+  // Enters overview mode. This is essentially the window cycling mode however
+  // not released on releasing the alt key and allows selecting with the mouse
+  // or touch rather than keypresses.
+  void ToggleOverview();
+
+  // Cycles between windows in the given |direction|. It is assumed that the
+  // alt key is held down and a key filter is installed to watch for alt being
+  // released.
+  void HandleCycleWindow(WindowSelector::Direction direction);
+
+  // Informs the controller that the Alt key has been released and it can
+  // terminate the existing multi-step cycle.
+  void AltKeyReleased();
+
+  // Returns true if window selection mode is active.
+  bool IsSelecting();
+
+  // WindowSelectorDelegate:
+  virtual void OnWindowSelected(aura::Window* window) OVERRIDE;
+  virtual void OnSelectionCanceled() OVERRIDE;
+
+ private:
+  scoped_ptr<WindowSelector> window_selector_;
+  scoped_ptr<ui::EventHandler> event_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowSelectorController);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_OVERVIEW_WINDOW_SELECTOR_CONTROLLER_H_
diff --git a/ash/wm/overview/window_selector_delegate.h b/ash/wm/overview/window_selector_delegate.h
new file mode 100644
index 0000000..2bce3ca
--- /dev/null
+++ b/ash/wm/overview/window_selector_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_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_
+#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_
+
+#include "ash/ash_export.h"
+#include "base/compiler_specific.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ash {
+
+// Implement this class to handle the selection event from WindowSelector.
+class ASH_EXPORT WindowSelectorDelegate {
+ public:
+  // Invoked when a window is selected.
+  virtual void OnWindowSelected(aura::Window* window) = 0;
+
+  // Invoked if selection is canceled.
+  virtual void OnSelectionCanceled() = 0;
+
+ protected:
+  virtual ~WindowSelectorDelegate() {}
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_OVERVIEW_WINDOW_SELECTOR_DELEGATE_H_
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
new file mode 100644
index 0000000..c36332b
--- /dev/null
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -0,0 +1,202 @@
+// Copyright 2013 The Chromium Authors. 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/root_window_controller.h"
+#include "ash/screen_ash.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/shell_test_api.h"
+#include "ash/wm/mru_window_tracker.h"
+#include "ash/wm/overview/window_selector_controller.h"
+#include "ash/wm/window_util.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_vector.h"
+#include "base/run_loop.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/transform.h"
+
+namespace ash {
+namespace internal {
+
+class WindowSelectorTest : public test::AshTestBase {
+ public:
+  WindowSelectorTest() {}
+  virtual ~WindowSelectorTest() {}
+
+  aura::Window* CreateWindow(const gfx::Rect& bounds) {
+    return CreateTestWindowInShellWithDelegate(&wd, -1, bounds);
+  }
+
+  bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) {
+    gfx::RectF window1_bounds = GetTransformedTargetBounds(window1);
+    gfx::RectF window2_bounds = GetTransformedTargetBounds(window2);
+    return window1_bounds.Intersects(window2_bounds);
+  }
+
+  void ToggleOverview() {
+    ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview();
+  }
+
+  void Cycle(WindowSelector::Direction direction) {
+    ash::Shell::GetInstance()->window_selector_controller()->
+        HandleCycleWindow(direction);
+  }
+
+  void StopCycling() {
+    ash::Shell::GetInstance()->window_selector_controller()->AltKeyReleased();
+  }
+
+  gfx::RectF GetTransformedBounds(aura::Window* window) {
+    gfx::RectF bounds(window->layer()->bounds());
+    window->layer()->transform().TransformRect(&bounds);
+    return bounds;
+  }
+
+  gfx::RectF GetTransformedTargetBounds(aura::Window* window) {
+    gfx::RectF bounds(window->layer()->GetTargetBounds());
+    window->layer()->GetTargetTransform().TransformRect(&bounds);
+    return bounds;
+  }
+
+  void ClickWindow(aura::Window* window) {
+    aura::test::EventGenerator event_generator(window->GetRootWindow(), window);
+    gfx::RectF target = GetTransformedBounds(window);
+    event_generator.ClickLeftButton();
+  }
+
+  bool IsSelecting() {
+    return ash::Shell::GetInstance()->window_selector_controller()->
+        IsSelecting();
+  }
+
+ private:
+  aura::test::TestWindowDelegate wd;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest);
+};
+
+// Tests entering overview mode with two windows and selecting one.
+TEST_F(WindowSelectorTest, Basic) {
+  gfx::Rect bounds(0, 0, 400, 400);
+  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+  EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
+  wm::ActivateWindow(window2.get());
+  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  // In overview mode the windows should no longer overlap.
+  ToggleOverview();
+  EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
+
+  // Clicking window 1 should activate it.
+  ClickWindow(window1.get());
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
+  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
+}
+
+// Tests entering overview mode with three windows and cycling through them.
+TEST_F(WindowSelectorTest, BasicCycle) {
+  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());
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
+  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
+  EXPECT_FALSE(wm::IsActiveWindow(window3.get()));
+
+  Cycle(WindowSelector::FORWARD);
+  EXPECT_TRUE(IsSelecting());
+  Cycle(WindowSelector::FORWARD);
+  StopCycling();
+  EXPECT_FALSE(IsSelecting());
+  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
+  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
+  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
+}
+
+// Tests that overview mode is exited if the last remaining window is destroyed.
+TEST_F(WindowSelectorTest, LastWindowDestroyed) {
+  gfx::Rect bounds(0, 0, 400, 400);
+  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+  ToggleOverview();
+
+  window1.reset();
+  window2.reset();
+  EXPECT_FALSE(IsSelecting());
+}
+
+// Tests that entering overview mode restores a window to its original
+// target location.
+TEST_F(WindowSelectorTest, QuickReentryRestoresInitialTransform) {
+  gfx::Rect bounds(0, 0, 400, 400);
+  scoped_ptr<aura::Window> window(CreateWindow(bounds));
+  gfx::Rect initial_bounds = ToEnclosingRect(
+      GetTransformedBounds(window.get()));
+  ToggleOverview();
+  // Quickly exit and reenter overview mode. The window should still be
+  // animating when we reenter. We cannot short circuit animations for this but
+  // we also don't have to wait for them to complete.
+  {
+    ui::ScopedAnimationDurationScaleMode normal_duration_mode(
+        ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+    ToggleOverview();
+    ToggleOverview();
+  }
+  EXPECT_NE(initial_bounds, ToEnclosingRect(
+      GetTransformedTargetBounds(window.get())));
+  ToggleOverview();
+  EXPECT_FALSE(IsSelecting());
+  EXPECT_EQ(initial_bounds, ToEnclosingRect(
+      GetTransformedTargetBounds(window.get())));
+}
+
+// Tests that windows remain on the display they are currently on in overview
+// mode.
+TEST_F(WindowSelectorTest, MultipleDisplays) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("400x400,400x400");
+  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
+
+  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
+  scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(0, 0, 100, 100)));
+  scoped_ptr<aura::Window> window3(CreateWindow(gfx::Rect(450, 0, 100, 100)));
+  scoped_ptr<aura::Window> window4(CreateWindow(gfx::Rect(450, 0, 100, 100)));
+  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
+  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
+  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
+  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
+
+  // In overview mode, each window remains in the same root window.
+  ToggleOverview();
+  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
+  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
+  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
+  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
+  root_windows[0]->bounds().Contains(
+      ToEnclosingRect(GetTransformedBounds(window1.get())));
+  root_windows[0]->bounds().Contains(
+      ToEnclosingRect(GetTransformedBounds(window2.get())));
+  root_windows[1]->bounds().Contains(
+      ToEnclosingRect(GetTransformedBounds(window3.get())));
+  root_windows[1]->bounds().Contains(
+      ToEnclosingRect(GetTransformedBounds(window4.get())));
+}
+
+}  // namespace internal
+}  // namespace ash
diff --git a/ash/wm/overview/window_selector_window.cc b/ash/wm/overview/window_selector_window.cc
new file mode 100644
index 0000000..47c1dda
--- /dev/null
+++ b/ash/wm/overview/window_selector_window.cc
@@ -0,0 +1,239 @@
+// Copyright 2013 The Chromium Authors. 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/window_selector_window.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/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 {
+
+const int kOverviewWindowTransitionMilliseconds = 100;
+
+// 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) {
+  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->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);
+
+  virtual void OnLayerAnimationEnded(
+      ui::LayerAnimationSequence* sequence) OVERRIDE;
+  virtual void OnLayerAnimationAborted(
+      ui::LayerAnimationSequence* sequence) OVERRIDE;
+  virtual void OnLayerAnimationScheduled(
+      ui::LayerAnimationSequence* sequence) OVERRIDE;
+
+ protected:
+  virtual ~CleanupWidgetAfterAnimationObserver();
+
+ private:
+  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 {
+ public:
+  WindowSelectorAnimationSettings(aura::Window* window) :
+      ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) {
+    SetPreemptionStrategy(
+        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+    SetTransitionDuration(base::TimeDelta::FromMilliseconds(
+        kOverviewWindowTransitionMilliseconds));
+  }
+
+  virtual ~WindowSelectorAnimationSettings() {
+  }
+};
+
+}  // namespace
+
+WindowSelectorWindow::WindowSelectorWindow(aura::Window* window)
+    : window_(window),
+      window_copy_(NULL),
+      layer_(NULL),
+      minimized_(window->GetProperty(aura::client::kShowStateKey) ==
+                 ui::SHOW_STATE_MINIMIZED),
+      original_transform_(window->layer()->GetTargetTransform()) {
+  if (minimized_)
+    window_->Show();
+}
+
+WindowSelectorWindow::~WindowSelectorWindow() {
+  if (window_) {
+    WindowSelectorAnimationSettings animation_settings(window_);
+    gfx::Transform transform;
+    window_->SetTransform(original_transform_);
+    if (minimized_) {
+      // Setting opacity 0 and visible false ensures that the property change
+      // to SHOW_STATE_MINIMIZED will not animate the window from its original
+      // bounds to the minimized position.
+      window_->layer()->SetOpacity(0);
+      window_->layer()->SetVisible(false);
+      window_->SetProperty(aura::client::kShowStateKey,
+                           ui::SHOW_STATE_MINIMIZED);
+    }
+  }
+  // If a copy of the window was created, clean it up.
+  if (window_copy_) {
+    if (window_) {
+      // If the initial window wasn't destroyed, the copy needs to be animated
+      // out. CleanupWidgetAfterAnimationObserver will destroy the widget and
+      // layer after the animation is complete.
+      new CleanupWidgetAfterAnimationObserver(window_copy_, layer_);
+      WindowSelectorAnimationSettings animation_settings(
+          window_copy_->GetNativeWindow());
+      window_copy_->GetNativeWindow()->SetTransform(original_transform_);
+    } else {
+      window_copy_->Close();
+      if (layer_)
+        views::corewm::DeepDeleteLayers(layer_);
+    }
+    window_copy_ = NULL;
+    layer_ = NULL;
+  }
+}
+
+bool WindowSelectorWindow::Contains(const aura::Window* window) const {
+  if (window_copy_ && window_copy_->GetNativeWindow()->Contains(window))
+    return true;
+  return window_->Contains(window);
+}
+
+void WindowSelectorWindow::RestoreWindowOnExit() {
+  minimized_ = false;
+  original_transform_ = gfx::Transform();
+}
+
+void WindowSelectorWindow::OnWindowDestroyed() {
+  window_ = NULL;
+}
+
+void WindowSelectorWindow::TransformToFitBounds(
+    aura::RootWindow* root_window,
+    const gfx::Rect& target_bounds) {
+  fit_bounds_ = target_bounds;
+  const gfx::Rect bounds = window_->GetBoundsInScreen();
+  float scale = std::min(1.0f,
+      std::min(static_cast<float>(target_bounds.width()) / bounds.width(),
+               static_cast<float>(target_bounds.height()) / bounds.height()));
+  gfx::Transform transform;
+  gfx::Vector2d offset(
+      0.5 * (target_bounds.width() - scale * bounds.width()),
+      0.5 * (target_bounds.height() - scale * bounds.height()));
+  transform.Translate(target_bounds.x() - bounds.x() + offset.x(),
+                      target_bounds.y() - bounds.y() + offset.y());
+  transform.Scale(scale, scale);
+  if (root_window != window_->GetRootWindow()) {
+    if (!window_copy_) {
+      DCHECK(!layer_);
+      layer_ = views::corewm::RecreateWindowLayers(window_, true);
+      window_copy_ = CreateCopyOfWindow(root_window, window_, layer_);
+    }
+    WindowSelectorAnimationSettings animation_settings(
+        window_copy_->GetNativeWindow());
+    window_copy_->GetNativeWindow()->SetTransform(transform);
+  }
+  WindowSelectorAnimationSettings animation_settings(window_);
+  window_->SetTransform(transform);
+}
+
+}  // namespace ash
diff --git a/ash/wm/overview/window_selector_window.h b/ash/wm/overview/window_selector_window.h
new file mode 100644
index 0000000..050ac93
--- /dev/null
+++ b/ash/wm/overview/window_selector_window.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 ASH_WM_OVERVIEW_WINDOW_SELECTOR_WINDOW_H_
+#define ASH_WM_OVERVIEW_WINDOW_SELECTOR_WINDOW_H_
+
+#include "base/compiler_specific.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/transform.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+}
+
+namespace ui {
+class Layer;
+}
+
+namespace views {
+class Widget;
+}
+
+namespace ash {
+
+// Manages a window in the overview mode. This class transitions the window
+// to the best fit within the available overview rectangle, copying it if the
+// window is sent to another display and restores the window state on
+// deletion.
+class WindowSelectorWindow {
+ public:
+  explicit WindowSelectorWindow(aura::Window* window);
+  virtual ~WindowSelectorWindow();
+
+  aura::Window* window() { return window_; }
+  const aura::Window* window() const { return window_; }
+
+  // Returns true if this window selector window contains the |target|. This is
+  // used to determine if an event targetted this window.
+  bool Contains(const aura::Window* target) const;
+
+  // Restores this window on exit rather than returning it to a minimized state
+  // if it was minimized on entering overview mode.
+  void RestoreWindowOnExit();
+
+  // Informs the WindowSelectorWindow that the window being watched was
+  // destroyed. This resets the internal window pointer to avoid calling
+  // anything on the window at destruction time.
+  void OnWindowDestroyed();
+
+  // Applies a transform to the window to fit within |target_bounds| while
+  // maintaining its aspect ratio.
+  void TransformToFitBounds(aura::RootWindow* root_window,
+                            const gfx::Rect& target_bounds);
+
+  const gfx::Rect& bounds() { return fit_bounds_; }
+
+ private:
+  // 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_;
+
+  // If true, the window was minimized and should be restored if the window
+  // was not selected.
+  bool minimized_;
+
+  // The original transform of the window before entering overview mode.
+  gfx::Transform original_transform_;
+
+  // The bounds this window is fit to.
+  gfx::Rect fit_bounds_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowSelectorWindow);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_OVERVIEW_WINDOW_SELECTOR_WINDOW_H_
diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc
index 8c18215..f394dc0 100644
--- a/ash/wm/panels/panel_frame_view.cc
+++ b/ash/wm/panels/panel_frame_view.cc
@@ -17,6 +17,7 @@
 #include "ui/gfx/font.h"
 #include "ui/gfx/image/image.h"
 #include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/image_view.h"
 #include "ui/views/widget/native_widget_aura.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -57,7 +58,7 @@
   AddChildView(minimize_button_);
 
   if (frame_->widget_delegate()->ShouldShowWindowIcon()) {
-    window_icon_ = new views::ImageButton(this);
+    window_icon_ = new views::ImageView();
     AddChildView(window_icon_);
   }
 
@@ -85,10 +86,8 @@
   if (!window_icon_)
     return;
   views::WidgetDelegate* delegate = frame_->widget_delegate();
-  if (delegate) {
-    gfx::ImageSkia image = delegate->GetWindowIcon();
-    window_icon_->SetImage(views::CustomButton::STATE_NORMAL, &image);
-  }
+  if (delegate)
+    window_icon_->SetImage(delegate->GetWindowIcon());
   window_icon_->SchedulePaint();
 }
 
diff --git a/ash/wm/panels/panel_frame_view.h b/ash/wm/panels/panel_frame_view.h
index ee124df..4a0a6f2 100644
--- a/ash/wm/panels/panel_frame_view.h
+++ b/ash/wm/panels/panel_frame_view.h
@@ -14,6 +14,7 @@
 
 namespace views {
 class ImageButton;
+class ImageView;
 }
 
 namespace ash {
@@ -66,7 +67,7 @@
   views::Widget* frame_;
   views::ImageButton* close_button_;
   views::ImageButton* minimize_button_;
-  views::ImageButton* window_icon_;
+  views::ImageView* window_icon_;
   gfx::Rect client_view_bounds_;
   const gfx::Font title_font_;
 
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index ca231ce..08f53f7 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -128,6 +128,8 @@
     ASSERT_FALSE(icon_bounds.width() == 0 && icon_bounds.height() == 0);
 
     gfx::Rect window_bounds = panel->GetBoundsInScreen();
+    ASSERT_LT(icon_bounds.width(), window_bounds.width());
+    ASSERT_LT(icon_bounds.height(), window_bounds.height());
     gfx::Rect launcher_bounds = launcher->shelf_widget()->
         GetWindowBoundsInScreen();
     ShelfAlignment alignment = GetAlignment(panel->GetRootWindow());
diff --git a/ash/wm/status_area_layout_manager.cc b/ash/wm/status_area_layout_manager.cc
index e17d84e..d9e0424 100644
--- a/ash/wm/status_area_layout_manager.cc
+++ b/ash/wm/status_area_layout_manager.cc
@@ -70,7 +70,7 @@
 
 void StatusAreaLayoutManager::LayoutStatusArea() {
   // Shelf layout manager may be already doing layout.
-  if (shelf_->shelf_layout_manager()->in_layout())
+  if (shelf_->shelf_layout_manager()->updating_bounds())
     return;
 
   base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
diff --git a/ash/wm/window_resizer.cc b/ash/wm/window_resizer.cc
index e312fc1..1ea317a 100644
--- a/ash/wm/window_resizer.cc
+++ b/ash/wm/window_resizer.cc
@@ -7,6 +7,7 @@
 #include "ash/screen_ash.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
+#include "ash/wm/coordinate_conversion.h"
 #include "ash/wm/dock/docked_window_layout_manager.h"
 #include "ash/wm/property_util.h"
 #include "ash/wm/window_util.h"
@@ -180,14 +181,6 @@
     return details.initial_bounds_in_parent;
 
   gfx::Point location = passed_location;
-  aura::Window* dock_container = Shell::GetContainer(
-      details.window->GetRootWindow(),
-      internal::kShellWindowId_DockedContainer);
-  DCHECK_EQ(dock_container->id(), internal::kShellWindowId_DockedContainer);
-  internal::DockedWindowLayoutManager* dock_layout =
-      static_cast<internal::DockedWindowLayoutManager*>(
-          dock_container->layout_manager());
-
   int delta_x = location.x() - details.initial_location_in_parent.x();
   int delta_y = location.y() - details.initial_location_in_parent.y();
 
@@ -206,6 +199,13 @@
   if (details.bounds_change & kBoundsChange_Resizes) {
     gfx::Rect work_area =
         Shell::GetScreen()->GetDisplayNearestWindow(details.window).work_area();
+    aura::Window* dock_container = Shell::GetContainer(
+        details.window->GetRootWindow(),
+        internal::kShellWindowId_DockedContainer);
+    internal::DockedWindowLayoutManager* dock_layout =
+        static_cast<internal::DockedWindowLayoutManager*>(
+            dock_container->layout_manager());
+
     work_area.Union(dock_layout->docked_bounds());
     work_area = ScreenAsh::ConvertRectFromScreen(details.window->parent(),
                                                  work_area);
@@ -265,6 +265,13 @@
         ScreenAsh::ConvertRectToScreen(parent, new_bounds);
     const gfx::Display& display =
         Shell::GetScreen()->GetDisplayMatching(new_bounds_in_screen);
+    aura::Window* dock_container = Shell::GetContainer(
+        wm::GetRootWindowMatching(new_bounds_in_screen),
+        internal::kShellWindowId_DockedContainer);
+    internal::DockedWindowLayoutManager* dock_layout =
+        static_cast<internal::DockedWindowLayoutManager*>(
+            dock_container->layout_manager());
+
     gfx::Rect screen_work_area = display.work_area();
     screen_work_area.Union(dock_layout->docked_bounds());
     screen_work_area.Inset(kMinimumOnScreenArea, 0);
diff --git a/ash/wm/window_selector.cc b/ash/wm/window_selector.cc
deleted file mode 100644
index 8e87a95..0000000
--- a/ash/wm/window_selector.cc
+++ /dev/null
@@ -1,546 +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/wm/window_selector.h"
-
-#include <algorithm>
-
-#include "ash/screen_ash.h"
-#include "ash/shell.h"
-#include "ash/shell_window_ids.h"
-#include "ash/wm/window_selector_delegate.h"
-#include "ash/wm/window_util.h"
-#include "base/memory/scoped_ptr.h"
-#include "third_party/skia/include/core/SkColor.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/base/events/event.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 {
-
-const float kCardAspectRatio = 4.0f / 3.0f;
-const int kWindowMargin = 30;
-const int kMinCardsMajor = 3;
-const int kOverviewTransitionMilliseconds = 100;
-const SkColor kWindowSelectorSelectionColor = SK_ColorBLACK;
-const float kWindowSelectorSelectionOpacity = 0.5f;
-const int kWindowSelectorSelectionPadding = 15;
-
-// 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) {
-  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->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);
-
-  virtual void OnLayerAnimationEnded(
-      ui::LayerAnimationSequence* sequence) OVERRIDE;
-  virtual void OnLayerAnimationAborted(
-      ui::LayerAnimationSequence* sequence) OVERRIDE;
-  virtual void OnLayerAnimationScheduled(
-      ui::LayerAnimationSequence* sequence) OVERRIDE;
-
- protected:
-  virtual ~CleanupWidgetAfterAnimationObserver();
-
- private:
-  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 {
- public:
-  WindowSelectorAnimationSettings(aura::Window* window) :
-      ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator()) {
-    SetPreemptionStrategy(
-        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-    SetTransitionDuration(
-        base::TimeDelta::FromMilliseconds(kOverviewTransitionMilliseconds));
-  }
-
-  virtual ~WindowSelectorAnimationSettings() {
-  }
-};
-
-}  // namespace
-
-// TODO(flackr): Split up into separate file under subdirectory in ash/wm.
-class WindowSelectorWindow {
- public:
-  explicit WindowSelectorWindow(aura::Window* window);
-  virtual ~WindowSelectorWindow();
-
-  aura::Window* window() { return window_; }
-  const aura::Window* window() const { return window_; }
-
-  // Returns true if this window selector window contains the |target|. This is
-  // used to determine if an event targetted this window.
-  bool Contains(const aura::Window* target) const;
-
-  // Restores this window on exit rather than returning it to a minimized state
-  // if it was minimized on entering overview mode.
-  void RestoreWindowOnExit();
-
-  // Informs the WindowSelectorWindow that the window being watched was
-  // destroyed. This resets the internal window pointer to avoid calling
-  // anything on the window at destruction time.
-  void OnWindowDestroyed();
-
-  // Applies a transform to the window to fit within |target_bounds| while
-  // maintaining its aspect ratio.
-  void TransformToFitBounds(aura::RootWindow* root_window,
-                            const gfx::Rect& target_bounds);
-
-  gfx::Rect bounds() { return fit_bounds_; }
-
- private:
-  // 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_;
-
-  // If true, the window was minimized and should be restored if the window
-  // was not selected.
-  bool minimized_;
-
-  // The original transform of the window before entering overview mode.
-  gfx::Transform original_transform_;
-
-  // The bounds this window is fit to.
-  gfx::Rect fit_bounds_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowSelectorWindow);
-};
-
-WindowSelectorWindow::WindowSelectorWindow(aura::Window* window)
-    : window_(window),
-      window_copy_(NULL),
-      layer_(NULL),
-      minimized_(window->GetProperty(aura::client::kShowStateKey) ==
-                 ui::SHOW_STATE_MINIMIZED),
-      original_transform_(window->layer()->transform()) {
-  if (minimized_)
-    window_->Show();
-}
-
-WindowSelectorWindow::~WindowSelectorWindow() {
-  if (window_) {
-    WindowSelectorAnimationSettings animation_settings(window_);
-    gfx::Transform transform;
-    window_->SetTransform(original_transform_);
-    if (minimized_) {
-      // Setting opacity 0 and visible false ensures that the property change
-      // to SHOW_STATE_MINIMIZED will not animate the window from its original
-      // bounds to the minimized position.
-      window_->layer()->SetOpacity(0);
-      window_->layer()->SetVisible(false);
-      window_->SetProperty(aura::client::kShowStateKey,
-                           ui::SHOW_STATE_MINIMIZED);
-    }
-  }
-  // If a copy of the window was created, clean it up.
-  if (window_copy_) {
-    if (window_) {
-      // If the initial window wasn't destroyed, the copy needs to be animated
-      // out. CleanupWidgetAfterAnimationObserver will destroy the widget and
-      // layer after the animation is complete.
-      new CleanupWidgetAfterAnimationObserver(window_copy_, layer_);
-      WindowSelectorAnimationSettings animation_settings(
-          window_copy_->GetNativeWindow());
-      window_copy_->GetNativeWindow()->SetTransform(original_transform_);
-    } else {
-      window_copy_->Close();
-      if (layer_)
-        views::corewm::DeepDeleteLayers(layer_);
-    }
-    window_copy_ = NULL;
-    layer_ = NULL;
-  }
-}
-
-bool WindowSelectorWindow::Contains(const aura::Window* window) const {
-  if (window_copy_ && window_copy_->GetNativeWindow()->Contains(window))
-    return true;
-  return window_->Contains(window);
-}
-
-void WindowSelectorWindow::RestoreWindowOnExit() {
-  minimized_ = false;
-  original_transform_ = gfx::Transform();
-}
-
-void WindowSelectorWindow::OnWindowDestroyed() {
-  window_ = NULL;
-}
-
-void WindowSelectorWindow::TransformToFitBounds(
-    aura::RootWindow* root_window,
-    const gfx::Rect& target_bounds) {
-  fit_bounds_ = target_bounds;
-  const gfx::Rect bounds = window_->GetBoundsInScreen();
-  float scale = std::min(1.0f,
-      std::min(static_cast<float>(target_bounds.width()) / bounds.width(),
-               static_cast<float>(target_bounds.height()) / bounds.height()));
-  gfx::Transform transform;
-  gfx::Vector2d offset(
-      0.5 * (target_bounds.width() - scale * bounds.width()),
-      0.5 * (target_bounds.height() - scale * bounds.height()));
-  transform.Translate(target_bounds.x() - bounds.x() + offset.x(),
-                      target_bounds.y() - bounds.y() + offset.y());
-  transform.Scale(scale, scale);
-  if (root_window != window_->GetRootWindow()) {
-    if (!window_copy_) {
-      DCHECK(!layer_);
-      layer_ = views::corewm::RecreateWindowLayers(window_, true);
-      window_copy_ = CreateCopyOfWindow(root_window, window_, layer_);
-    }
-    WindowSelectorAnimationSettings animation_settings(
-        window_copy_->GetNativeWindow());
-    window_copy_->GetNativeWindow()->SetTransform(transform);
-  }
-  WindowSelectorAnimationSettings animation_settings(window_);
-  window_->SetTransform(transform);
-}
-
-// A comparator for locating a given target window.
-struct WindowSelectorWindowComparator
-    : public std::unary_function<WindowSelectorWindow*, bool> {
-  explicit WindowSelectorWindowComparator(const aura::Window* target_window)
-      : target(target_window) {
-  }
-
-  bool operator()(const WindowSelectorWindow* window) const {
-    return target == window->window();
-  }
-
-  const aura::Window* target;
-};
-
-WindowSelector::WindowSelector(const WindowList& windows,
-                               WindowSelector::Mode mode,
-                               WindowSelectorDelegate* delegate)
-    : mode_(mode),
-      delegate_(delegate),
-      selected_window_(0),
-      selection_root_(NULL) {
-  DCHECK(delegate_);
-  for (size_t i = 0; i < windows.size(); ++i) {
-    windows[i]->AddObserver(this);
-    windows_.push_back(new WindowSelectorWindow(windows[i]));
-  }
-  if (mode == WindowSelector::CYCLE)
-    selection_root_ = ash::Shell::GetActiveRootWindow();
-  PositionWindows();
-  ash::Shell::GetInstance()->AddPreTargetHandler(this);
-}
-
-WindowSelector::~WindowSelector() {
-  for (size_t i = 0; i < windows_.size(); i++) {
-    windows_[i]->window()->RemoveObserver(this);
-  }
-  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
-}
-
-void WindowSelector::Step(WindowSelector::Direction direction) {
-  DCHECK(windows_.size() > 0);
-  if (!selection_widget_)
-    InitializeSelectionWidget();
-  selected_window_ = (selected_window_ + windows_.size() +
-      (direction == WindowSelector::FORWARD ? 1 : -1)) % windows_.size();
-  UpdateSelectionLocation(true);
-}
-
-void WindowSelector::SelectWindow() {
-  delegate_->OnWindowSelected(windows_[selected_window_]->window());
-}
-
-void WindowSelector::OnEvent(ui::Event* event) {
-  // If the event is targetted at any of the windows in the overview, then
-  // prevent it from propagating.
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  for (size_t i = 0; i < windows_.size(); ++i) {
-    if (windows_[i]->Contains(target)) {
-      event->StopPropagation();
-      break;
-    }
-  }
-
-  // This object may not be valid after this call as a selection event can
-  // trigger deletion of the window selector.
-  ui::EventHandler::OnEvent(event);
-}
-
-void WindowSelector::OnMouseEvent(ui::MouseEvent* event) {
-  if (event->type() != ui::ET_MOUSE_RELEASED)
-    return;
-  WindowSelectorWindow* target = GetEventTarget(event);
-  if (!target)
-    return;
-
-  HandleSelectionEvent(target);
-}
-
-void WindowSelector::OnGestureEvent(ui::GestureEvent* event) {
-  if (event->type() != ui::ET_GESTURE_TAP)
-    return;
-  WindowSelectorWindow* target = GetEventTarget(event);
-  if (!target)
-    return;
-
-  HandleSelectionEvent(target);
-}
-
-void WindowSelector::OnWindowDestroyed(aura::Window* window) {
-  ScopedVector<WindowSelectorWindow>::iterator iter =
-      std::find_if(windows_.begin(), windows_.end(),
-                   WindowSelectorWindowComparator(window));
-  DCHECK(iter != windows_.end());
-  size_t deleted_index = iter - windows_.begin();
-  (*iter)->OnWindowDestroyed();
-  windows_.erase(iter);
-  if (windows_.empty()) {
-    delegate_->OnSelectionCanceled();
-    return;
-  }
-  if (selected_window_ >= deleted_index) {
-    if (selected_window_ > deleted_index)
-      selected_window_--;
-    selected_window_ = selected_window_ % windows_.size();
-    UpdateSelectionLocation(true);
-  }
-
-  PositionWindows();
-}
-
-WindowSelectorWindow* WindowSelector::GetEventTarget(ui::LocatedEvent* event) {
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  // If the target window doesn't actually contain the event location (i.e.
-  // mouse down over the window and mouse up elsewhere) then do not select the
-  // window.
-  if (!target->HitTest(event->location()))
-    return NULL;
-
-  for (size_t i = 0; i < windows_.size(); i++) {
-    if (windows_[i]->Contains(target))
-      return windows_[i];
-  }
-  return NULL;
-}
-
-void WindowSelector::HandleSelectionEvent(WindowSelectorWindow* target) {
-  // The selected window should not be minimized when window selection is
-  // ended.
-  target->RestoreWindowOnExit();
-  delegate_->OnWindowSelected(target->window());
-}
-
-void WindowSelector::PositionWindows() {
-  if (selection_root_) {
-    DCHECK_EQ(mode_, CYCLE);
-    std::vector<WindowSelectorWindow*> windows;
-    for (size_t i = 0; i < windows_.size(); ++i)
-      windows.push_back(windows_[i]);
-    PositionWindowsOnRoot(selection_root_, windows);
-  } else {
-    DCHECK_EQ(mode_, OVERVIEW);
-    Shell::RootWindowList root_window_list = Shell::GetAllRootWindows();
-    for (size_t i = 0; i < root_window_list.size(); ++i)
-      PositionWindowsFromRoot(root_window_list[i]);
-  }
-}
-
-void WindowSelector::PositionWindowsFromRoot(aura::RootWindow* root_window) {
-  std::vector<WindowSelectorWindow*> windows;
-  for (size_t i = 0; i < windows_.size(); ++i) {
-    if (windows_[i]->window()->GetRootWindow() == root_window)
-      windows.push_back(windows_[i]);
-  }
-  PositionWindowsOnRoot(root_window, windows);
-}
-
-void WindowSelector::PositionWindowsOnRoot(
-    aura::RootWindow* root_window,
-    const std::vector<WindowSelectorWindow*>& windows) {
-  if (windows.empty())
-    return;
-
-  gfx::Size window_size;
-  gfx::Rect total_bounds = ScreenAsh::ConvertRectToScreen(root_window,
-      ScreenAsh::GetDisplayWorkAreaBoundsInParent(
-      Shell::GetContainer(root_window,
-                          internal::kShellWindowId_DefaultContainer)));
-
-  // Find the minimum number of windows per row that will fit all of the
-  // windows on screen.
-  size_t columns = std::max(
-      total_bounds.width() > total_bounds.height() ? kMinCardsMajor : 1,
-      static_cast<int>(ceil(sqrt(total_bounds.width() * windows.size() /
-                                 (kCardAspectRatio * total_bounds.height())))));
-  size_t rows = ((windows.size() + columns - 1) / columns);
-  window_size.set_width(std::min(
-      static_cast<int>(total_bounds.width() / columns),
-      static_cast<int>(total_bounds.height() * kCardAspectRatio / rows)));
-  window_size.set_height(window_size.width() / kCardAspectRatio);
-
-  // Calculate the X and Y offsets necessary to center the grid.
-  int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 :
-      (columns - windows.size()) * window_size.width()) +
-      (total_bounds.width() - columns * window_size.width())) / 2;
-  int y_offset = total_bounds.y() + (total_bounds.height() -
-      rows * window_size.height()) / 2;
-  for (size_t i = 0; i < windows.size(); ++i) {
-    gfx::Transform transform;
-    int column = i % columns;
-    int row = i / columns;
-    gfx::Rect target_bounds(window_size.width() * column + x_offset,
-                            window_size.height() * row + y_offset,
-                            window_size.width(),
-                            window_size.height());
-    target_bounds.Inset(kWindowMargin, kWindowMargin);
-    windows[i]->TransformToFitBounds(root_window, target_bounds);
-  }
-}
-
-void WindowSelector::InitializeSelectionWidget() {
-  selection_widget_.reset(new views::Widget);
-  views::Widget::InitParams params;
-  params.type = views::Widget::InitParams::TYPE_POPUP;
-  params.can_activate = false;
-  params.keep_on_top = false;
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
-  params.parent = Shell::GetContainer(
-      selection_root_,
-      internal::kShellWindowId_DefaultContainer);
-  params.accept_events = false;
-  selection_widget_->set_focus_on_creation(false);
-  selection_widget_->Init(params);
-  views::View* content_view = new views::View;
-  content_view->set_background(
-      views::Background::CreateSolidBackground(kWindowSelectorSelectionColor));
-  selection_widget_->SetContentsView(content_view);
-  UpdateSelectionLocation(false);
-  selection_widget_->GetNativeWindow()->parent()->StackChildAtBottom(
-      selection_widget_->GetNativeWindow());
-  selection_widget_->Show();
-  selection_widget_->GetNativeWindow()->layer()->SetOpacity(
-      kWindowSelectorSelectionOpacity);
-}
-
-void WindowSelector::UpdateSelectionLocation(bool animate) {
-  if (!selection_widget_)
-    return;
-  gfx::Rect target_bounds = windows_[selected_window_]->bounds();
-  target_bounds.Inset(-kWindowSelectorSelectionPadding,
-                      -kWindowSelectorSelectionPadding);
-  if (animate) {
-    WindowSelectorAnimationSettings animation_settings(
-        selection_widget_->GetNativeWindow());
-    selection_widget_->SetBounds(target_bounds);
-  } else {
-    selection_widget_->SetBounds(target_bounds);
-  }
-}
-
-}  // namespace ash
diff --git a/ash/wm/window_selector.h b/ash/wm/window_selector.h
deleted file mode 100644
index 92ed607..0000000
--- a/ash/wm/window_selector.h
+++ /dev/null
@@ -1,120 +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_WM_WINDOW_SELECTOR_H_
-#define ASH_WM_WINDOW_SELECTOR_H_
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "ui/aura/window_observer.h"
-#include "ui/base/events/event_handler.h"
-#include "ui/gfx/transform.h"
-
-namespace aura {
-class RootWindow;
-}
-
-namespace ui {
-class LocatedEvent;
-}
-
-namespace views {
-class Widget;
-}
-
-namespace ash {
-
-class WindowSelectorDelegate;
-class WindowSelectorWindow;
-
-// The WindowSelector shows a grid of all of your windows and allows selecting
-// a window by clicking or tapping on it (OVERVIEW mode) or by alt-tabbing to
-// it (CYCLE mode).
-class WindowSelector : public ui::EventHandler,
-                       public aura::WindowObserver {
- public:
-  enum Direction {
-    FORWARD,
-    BACKWARD
-  };
-  enum Mode {
-    CYCLE,
-    OVERVIEW
-  };
-
-  typedef std::vector<aura::Window*> WindowList;
-
-  WindowSelector(const WindowList& windows,
-                 Mode mode,
-                 WindowSelectorDelegate* delegate);
-  virtual ~WindowSelector();
-
-  // Step to the next window in |direction|.
-  void Step(Direction direction);
-
-  // Select the current window.
-  void SelectWindow();
-
-  Mode mode() { return mode_; }
-
-  // ui::EventHandler:
-  virtual void OnEvent(ui::Event* event) OVERRIDE;
-  virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
-  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
-
-  // aura::WindowObserver:
-  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
-
- private:
-  // Returns the target of |event| or NULL if the event is not targeted at
-  // any of the windows in the selector.
-  WindowSelectorWindow* GetEventTarget(ui::LocatedEvent* event);
-
-  // Handles a selection event for |target|.
-  void HandleSelectionEvent(WindowSelectorWindow* target);
-
-  // 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);
-  // Position all of the |windows| to fit on the |root_window|.
-  void PositionWindowsOnRoot(aura::RootWindow* root_window,
-                             const std::vector<WindowSelectorWindow*>& windows);
-
-  void InitializeSelectionWidget();
-
-  // Updates the selection widget's location to the currently selected window.
-  // If |animate| the transition to the new location is animated.
-  void UpdateSelectionLocation(bool animate);
-
-  // The collection of windows in the overview wrapped by a helper class which
-  // restores their state and helps transform them to other root windows.
-  ScopedVector<WindowSelectorWindow> windows_;
-
-  // The window selection mode.
-  Mode mode_;
-
-  // Weak pointer to the selector delegate which will be called when a
-  // selection is made.
-  WindowSelectorDelegate* delegate_;
-
-  // Index of the currently selected window if the mode is CYCLE.
-  size_t selected_window_;
-
-  // Widget indicating which window is currently selected.
-  scoped_ptr<views::Widget> selection_widget_;
-
-  // In CYCLE mode, the root window in which selection is taking place.
-  // NULL otherwise.
-  aura::RootWindow* selection_root_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowSelector);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_WINDOW_SELECTOR_H_
diff --git a/ash/wm/window_selector_controller.cc b/ash/wm/window_selector_controller.cc
deleted file mode 100644
index e6cd383..0000000
--- a/ash/wm/window_selector_controller.cc
+++ /dev/null
@@ -1,122 +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/wm/window_selector_controller.h"
-
-#include "ash/session_state_delegate.h"
-#include "ash/shell.h"
-#include "ash/wm/mru_window_tracker.h"
-#include "ash/wm/window_selector.h"
-#include "ash/wm/window_util.h"
-#include "ui/base/events/event.h"
-#include "ui/base/events/event_handler.h"
-
-namespace ash {
-
-namespace {
-
-// Filter to watch for the termination of a keyboard gesture to cycle through
-// multiple windows.
-class WindowSelectorEventFilter : public ui::EventHandler {
- public:
-  WindowSelectorEventFilter();
-  virtual ~WindowSelectorEventFilter();
-
-  // Overridden from ui::EventHandler:
-  virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WindowSelectorEventFilter);
-};
-
-// Watch for all keyboard events by filtering the root window.
-WindowSelectorEventFilter::WindowSelectorEventFilter() {
-  Shell::GetInstance()->AddPreTargetHandler(this);
-}
-
-WindowSelectorEventFilter::~WindowSelectorEventFilter() {
-  Shell::GetInstance()->RemovePreTargetHandler(this);
-}
-
-void WindowSelectorEventFilter::OnKeyEvent(ui::KeyEvent* event) {
-  // Views uses VKEY_MENU for both left and right Alt keys.
-  if (event->key_code() == ui::VKEY_MENU &&
-      event->type() == ui::ET_KEY_RELEASED) {
-    Shell::GetInstance()->window_selector_controller()->AltKeyReleased();
-    // Warning: |this| will be deleted from here on.
-  }
-}
-
-}  // namespace
-
-WindowSelectorController::WindowSelectorController() {
-}
-
-WindowSelectorController::~WindowSelectorController() {
-}
-
-// static
-bool WindowSelectorController::CanSelect() {
-  // Don't allow a window overview if the screen is locked or a modal dialog is
-  // open.
-  return !Shell::GetInstance()->session_state_delegate()->IsScreenLocked() &&
-         !Shell::GetInstance()->IsSystemModalWindowOpen();
-}
-
-void WindowSelectorController::ToggleOverview() {
-  if (window_selector_.get()) {
-    window_selector_.reset();
-  } else {
-    std::vector<aura::Window*> windows = ash::Shell::GetInstance()->
-        mru_window_tracker()->BuildMruWindowList();
-    // Don't enter overview mode with no windows.
-    if (windows.empty())
-      return;
-
-    // Deactivating the window will hide popup windows like the omnibar or
-    // open menus.
-    aura::Window* active_window = wm::GetActiveWindow();
-    if (active_window)
-      wm::DeactivateWindow(active_window);
-    window_selector_.reset(
-        new WindowSelector(windows, WindowSelector::OVERVIEW, this));
-  }
-}
-
-void WindowSelectorController::HandleCycleWindow(
-    WindowSelector::Direction direction) {
-  if (!CanSelect())
-    return;
-
-  if (!IsSelecting()) {
-    event_handler_.reset(new WindowSelectorEventFilter());
-    std::vector<aura::Window*> windows = ash::Shell::GetInstance()->
-        mru_window_tracker()->BuildMruWindowList();
-    window_selector_.reset(
-        new WindowSelector(windows, WindowSelector::CYCLE, this));
-    window_selector_->Step(direction);
-  } else if (window_selector_->mode() == WindowSelector::CYCLE) {
-    window_selector_->Step(direction);
-  }
-}
-
-void WindowSelectorController::AltKeyReleased() {
-  event_handler_.reset();
-  window_selector_->SelectWindow();
-}
-
-bool WindowSelectorController::IsSelecting() {
-  return window_selector_.get() != NULL;
-}
-
-void WindowSelectorController::OnWindowSelected(aura::Window* window) {
-  window_selector_.reset();
-  wm::ActivateWindow(window);
-}
-
-void WindowSelectorController::OnSelectionCanceled() {
-  window_selector_.reset();
-}
-
-}  // namespace ash
diff --git a/ash/wm/window_selector_controller.h b/ash/wm/window_selector_controller.h
deleted file mode 100644
index 385c30e..0000000
--- a/ash/wm/window_selector_controller.h
+++ /dev/null
@@ -1,72 +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_WM_WINDOW_SELECTOR_CONTROLLER_H_
-#define ASH_WM_WINDOW_SELECTOR_CONTROLLER_H_
-
-#include <list>
-#include <vector>
-
-#include "ash/ash_export.h"
-#include "ash/wm/window_selector.h"
-#include "ash/wm/window_selector_delegate.h"
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/aura/window_observer.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ui {
-class EventHandler;
-}
-
-namespace ash {
-
-class WindowSelector;
-
-// Manages a window selector which displays an overview of all windows and
-// allows selecting a window to activate it.
-class ASH_EXPORT WindowSelectorController
-    : public WindowSelectorDelegate {
- public:
-  WindowSelectorController();
-  virtual ~WindowSelectorController();
-
-  // Returns true if selecting windows in an overview is enabled. This is false
-  // at certain times, such as when the lock screen is visible.
-  static bool CanSelect();
-
-  // Enters overview mode. This is essentially the window cycling mode however
-  // not released on releasing the alt key and allows selecting with the mouse
-  // or touch rather than keypresses.
-  void ToggleOverview();
-
-  // Cycles between windows in the given |direction|. It is assumed that the
-  // alt key is held down and a key filter is installed to watch for alt being
-  // released.
-  void HandleCycleWindow(WindowSelector::Direction direction);
-
-  // Informs the controller that the Alt key has been released and it can
-  // terminate the existing multi-step cycle.
-  void AltKeyReleased();
-
-  // Returns true if window selection mode is active.
-  bool IsSelecting();
-
-  // WindowSelectorDelegate:
-  virtual void OnWindowSelected(aura::Window* window) OVERRIDE;
-  virtual void OnSelectionCanceled() OVERRIDE;
-
- private:
-  scoped_ptr<WindowSelector> window_selector_;
-  scoped_ptr<ui::EventHandler> event_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowSelectorController);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_WINDOW_SELECTOR_CONTROLLER_H_
diff --git a/ash/wm/window_selector_delegate.h b/ash/wm/window_selector_delegate.h
deleted file mode 100644
index fd7677f..0000000
--- a/ash/wm/window_selector_delegate.h
+++ /dev/null
@@ -1,32 +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_WM_WINDOW_SELECTOR_DELEGATE_H_
-#define ASH_WM_WINDOW_SELECTOR_DELEGATE_H_
-
-#include "ash/ash_export.h"
-#include "base/compiler_specific.h"
-
-namespace aura {
-class Window;
-}
-
-namespace ash {
-
-// Implement this class to handle the selection event from WindowSelector.
-class ASH_EXPORT WindowSelectorDelegate {
- public:
-  // Invoked when a window is selected.
-  virtual void OnWindowSelected(aura::Window* window) = 0;
-
-  // Invoked if selection is canceled.
-  virtual void OnSelectionCanceled() = 0;
-
- protected:
-  virtual ~WindowSelectorDelegate() {}
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_WINDOW_SELECTOR_DELEGATE_H_
diff --git a/ash/wm/window_selector_unittest.cc b/ash/wm/window_selector_unittest.cc
deleted file mode 100644
index 9ac15d6..0000000
--- a/ash/wm/window_selector_unittest.cc
+++ /dev/null
@@ -1,250 +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/root_window_controller.h"
-#include "ash/screen_ash.h"
-#include "ash/shell.h"
-#include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/wm/mru_window_tracker.h"
-#include "ash/wm/window_selector_controller.h"
-#include "ash/wm/window_util.h"
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_vector.h"
-#include "base/run_loop.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/event_generator.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/test/test_windows.h"
-#include "ui/aura/window.h"
-#include "ui/compositor/layer_animator.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/transform.h"
-
-namespace ash {
-namespace internal {
-
-namespace {
-
-class LayerAnimationObserver : public ui::LayerAnimationObserver {
- public:
-  LayerAnimationObserver(ui::Layer* layer)
-      : layer_(layer), animating_(false), message_loop_running_(false) {
-    layer_->GetAnimator()->AddObserver(this);
-  }
-
-  virtual ~LayerAnimationObserver() {
-    layer_->GetAnimator()->RemoveObserver(this);
-  }
-
-  virtual void OnLayerAnimationEnded(
-      ui::LayerAnimationSequence* sequence) OVERRIDE {
-    AnimationDone();
-  }
-
-  virtual void OnLayerAnimationScheduled(
-      ui::LayerAnimationSequence* sequence) OVERRIDE {
-    animating_ = true;
-  }
-
-  virtual void OnLayerAnimationAborted(
-      ui::LayerAnimationSequence* sequence) OVERRIDE {
-    AnimationDone();
-  }
-
-  void WaitUntilDone() {
-    while (animating_) {
-      message_loop_running_ = true;
-      base::MessageLoop::current()->Run();
-      message_loop_running_ = false;
-    }
-  }
-
- private:
-  void AnimationDone() {
-    animating_ = false;
-    if (message_loop_running_)
-      base::MessageLoop::current()->Quit();
-  }
-
-  ui::Layer* layer_;
-  bool animating_;
-  bool message_loop_running_;
-
-  DISALLOW_COPY_AND_ASSIGN(LayerAnimationObserver);
-};
-
-}  // namespace
-
-class WindowSelectorTest : public test::AshTestBase {
- public:
-  WindowSelectorTest() {}
-  virtual ~WindowSelectorTest() {}
-
-  aura::Window* CreateWindow(const gfx::Rect& bounds) {
-    return CreateTestWindowInShellWithDelegate(&wd, -1, bounds);
-  }
-
-  bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) {
-    gfx::RectF window1_bounds = GetTransformedTargetBounds(window1);
-    gfx::RectF window2_bounds = GetTransformedTargetBounds(window2);
-    return window1_bounds.Intersects(window2_bounds);
-  }
-
-  void ToggleOverview() {
-    std::vector<aura::Window*> windows = ash::Shell::GetInstance()->
-        mru_window_tracker()->BuildMruWindowList();
-    ScopedVector<LayerAnimationObserver> animations;
-    for (size_t i = 0; i < windows.size(); ++i) {
-      animations.push_back(new LayerAnimationObserver(windows[i]->layer()));
-    }
-    ash::Shell::GetInstance()->window_selector_controller()->ToggleOverview();
-    for (size_t i = 0; i < animations.size(); ++i) {
-      animations[i]->WaitUntilDone();
-    }
-  }
-
-  void Cycle(WindowSelector::Direction direction) {
-    if (!IsSelecting()) {
-      std::vector<aura::Window*> windows = ash::Shell::GetInstance()->
-          mru_window_tracker()->BuildMruWindowList();
-      ScopedVector<LayerAnimationObserver> animations;
-      for (size_t i = 0; i < windows.size(); ++i)
-        animations.push_back(new LayerAnimationObserver(windows[i]->layer()));
-      ash::Shell::GetInstance()->window_selector_controller()->
-          HandleCycleWindow(direction);
-      for (size_t i = 0; i < animations.size(); ++i)
-        animations[i]->WaitUntilDone();
-    } else {
-      ash::Shell::GetInstance()->window_selector_controller()->
-          HandleCycleWindow(direction);
-    }
-  }
-
-  void StopCycling() {
-    ash::Shell::GetInstance()->window_selector_controller()->AltKeyReleased();
-  }
-
-  gfx::RectF GetTransformedBounds(aura::Window* window) {
-    gfx::RectF bounds(window->layer()->bounds());
-    window->layer()->transform().TransformRect(&bounds);
-    return bounds;
-  }
-
-  gfx::RectF GetTransformedTargetBounds(aura::Window* window) {
-    gfx::RectF bounds(window->layer()->GetTargetBounds());
-    window->layer()->GetTargetTransform().TransformRect(&bounds);
-    return bounds;
-  }
-
-  void ClickWindow(aura::Window* window) {
-    aura::test::EventGenerator event_generator(window->GetRootWindow(), window);
-    gfx::RectF target = GetTransformedBounds(window);
-    event_generator.ClickLeftButton();
-  }
-
-  bool IsSelecting() {
-    return ash::Shell::GetInstance()->window_selector_controller()->
-        IsSelecting();
-  }
-
- private:
-  aura::test::TestWindowDelegate wd;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest);
-};
-
-// Tests entering overview mode with two windows and selecting one.
-TEST_F(WindowSelectorTest, Basic) {
-  gfx::Rect bounds(0, 0, 400, 400);
-  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
-  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
-  EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
-  wm::ActivateWindow(window2.get());
-  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
-  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
-
-  // In overview mode the windows should no longer overlap.
-  ToggleOverview();
-  EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
-
-  // Clicking window 1 should activate it.
-  ClickWindow(window1.get());
-  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
-  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
-}
-
-// Tests entering overview mode with three windows and cycling through them.
-TEST_F(WindowSelectorTest, BasicCycle) {
-  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());
-  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
-  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
-  EXPECT_FALSE(wm::IsActiveWindow(window3.get()));
-
-  Cycle(WindowSelector::FORWARD);
-  EXPECT_TRUE(IsSelecting());
-  Cycle(WindowSelector::FORWARD);
-  StopCycling();
-  EXPECT_FALSE(IsSelecting());
-  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
-  EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
-  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
-}
-
-// Tests that overview mode is exited if the last remaining window is destroyed.
-TEST_F(WindowSelectorTest, LastWindowDestroyed) {
-  gfx::Rect bounds(0, 0, 400, 400);
-  scoped_ptr<aura::Window> window1(CreateWindow(bounds));
-  scoped_ptr<aura::Window> window2(CreateWindow(bounds));
-  ToggleOverview();
-
-  window1.reset();
-  window2.reset();
-  EXPECT_FALSE(IsSelecting());
-}
-
-// Tests that windows remain on the display they are currently on in overview
-// mode.
-TEST_F(WindowSelectorTest, MultipleDisplays) {
-  if (!SupportsMultipleDisplays())
-    return;
-
-  UpdateDisplay("400x400,400x400");
-  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
-
-  scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 100, 100)));
-  scoped_ptr<aura::Window> window2(CreateWindow(gfx::Rect(0, 0, 100, 100)));
-  scoped_ptr<aura::Window> window3(CreateWindow(gfx::Rect(450, 0, 100, 100)));
-  scoped_ptr<aura::Window> window4(CreateWindow(gfx::Rect(450, 0, 100, 100)));
-  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
-  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
-  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
-  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
-
-  // In overview mode, each window remains in the same root window.
-  ToggleOverview();
-  EXPECT_EQ(root_windows[0], window1->GetRootWindow());
-  EXPECT_EQ(root_windows[0], window2->GetRootWindow());
-  EXPECT_EQ(root_windows[1], window3->GetRootWindow());
-  EXPECT_EQ(root_windows[1], window4->GetRootWindow());
-  root_windows[0]->bounds().Contains(
-      ToEnclosingRect(GetTransformedBounds(window1.get())));
-  root_windows[0]->bounds().Contains(
-      ToEnclosingRect(GetTransformedBounds(window2.get())));
-  root_windows[1]->bounds().Contains(
-      ToEnclosingRect(GetTransformedBounds(window3.get())));
-  root_windows[1]->bounds().Contains(
-      ToEnclosingRect(GetTransformedBounds(window4.get())));
-}
-
-}  // namespace internal
-}  // namespace ash
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index 67dcd95..7b8e616 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -161,29 +161,29 @@
                       new gfx::Rect(bounds));
 }
 
-void AdjustBoundsToEnsureMinimumWindowVisibility(const gfx::Rect& work_area,
+void AdjustBoundsToEnsureMinimumWindowVisibility(const gfx::Rect& visible_area,
                                                  gfx::Rect* bounds) {
   AdjustBoundsToEnsureWindowVisibility(
-      work_area, kMinimumOnScreenArea, kMinimumOnScreenArea, bounds);
+      visible_area, kMinimumOnScreenArea, kMinimumOnScreenArea, bounds);
 }
 
-void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& work_area,
+void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& visible_area,
                                           int min_width,
                                           int min_height,
                                           gfx::Rect* bounds) {
-  bounds->set_width(std::min(bounds->width(), work_area.width()));
-  bounds->set_height(std::min(bounds->height(), work_area.height()));
+  bounds->set_width(std::min(bounds->width(), visible_area.width()));
+  bounds->set_height(std::min(bounds->height(), visible_area.height()));
 
-  min_width = std::min(min_width, work_area.width());
-  min_height = std::min(min_height, work_area.height());
+  min_width = std::min(min_width, visible_area.width());
+  min_height = std::min(min_height, visible_area.height());
 
-  if (bounds->x() + min_width > work_area.right()) {
-    bounds->set_x(work_area.right() - min_width);
+  if (bounds->x() + min_width > visible_area.right()) {
+    bounds->set_x(visible_area.right() - min_width);
   } else if (bounds->right() - min_width < 0) {
     bounds->set_x(min_width - bounds->width());
   }
-  if (bounds->y() + min_height > work_area.bottom()) {
-    bounds->set_y(work_area.bottom() - min_height);
+  if (bounds->y() + min_height > visible_area.bottom()) {
+    bounds->set_y(visible_area.bottom() - min_height);
   } else if (bounds->bottom() - min_height < 0) {
     bounds->set_y(min_height - bounds->height());
   }
diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h
index 1ffeb7d..659d3e1 100644
--- a/ash/wm/window_util.h
+++ b/ash/wm/window_util.h
@@ -108,16 +108,16 @@
 ASH_EXPORT void SetPreAutoManageWindowBounds(aura::Window* window,
                                              const gfx::Rect& bounds);
 
-// Move the given bounds inside the given work area, including a safety margin
-// given by |kMinimumOnScreenArea|.
+// Move the given bounds inside the given |visible_area|, including a
+// safety margin given by |kMinimumOnScreenArea|.
 ASH_EXPORT void AdjustBoundsToEnsureMinimumWindowVisibility(
-    const gfx::Rect& work_area,
+    const gfx::Rect& visible_area,
     gfx::Rect* bounds);
 
-// Move the given bounds inside the given work area, including a safety margin
-// given by |min_width| and |min_height|.
+// Move the given bounds inside the given |visible_area|, including a
+// safety margin given by |min_width| and |min_height|.
 ASH_EXPORT void AdjustBoundsToEnsureWindowVisibility(
-    const gfx::Rect& work_area,
+    const gfx::Rect& visible_area,
     int min_width,
     int min_height,
     gfx::Rect* bounds);
diff --git a/ash/wm/workspace/auto_window_management.cc b/ash/wm/workspace/auto_window_management.cc
index 64a4564..07073ff 100644
--- a/ash/wm/workspace/auto_window_management.cc
+++ b/ash/wm/workspace/auto_window_management.cc
@@ -26,10 +26,8 @@
 const int kWindowAutoMoveDurationMS = 125;
 
 // Check if any management should be performed (with a given |window|).
-bool UseAutoWindowMagerForWindow(const aura::Window* window) {
-  return !CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kAshDisableAutoWindowPlacement) &&
-         GetTrackedByWorkspace(window) &&
+bool UseAutoWindowManager(const aura::Window* window) {
+  return GetTrackedByWorkspace(window) &&
          wm::IsWindowPositionManaged(window);
 }
 
@@ -142,7 +140,7 @@
 } // namespace
 
 void RearrangeVisibleWindowOnHideOrRemove(const aura::Window* removed_window) {
-  if (!UseAutoWindowMagerForWindow(removed_window))
+  if (!UseAutoWindowManager(removed_window))
     return;
   // Find a single open browser window.
   aura::Window* other_shown_window = NULL;
@@ -154,7 +152,7 @@
 }
 
 void RearrangeVisibleWindowOnShow(aura::Window* added_window) {
-  if (!UseAutoWindowMagerForWindow(added_window) ||
+  if (!UseAutoWindowManager(added_window) ||
       wm::HasUserChangedWindowPositionOrSize(added_window) ||
       !added_window->TargetVisibility())
     return;
diff --git a/ash/wm/workspace/frame_caption_button_container_view.cc b/ash/wm/workspace/frame_caption_button_container_view.cc
new file mode 100644
index 0000000..7f1d020
--- /dev/null
+++ b/ash/wm/workspace/frame_caption_button_container_view.cc
@@ -0,0 +1,135 @@
+// Copyright 2013 The Chromium Authors. 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/workspace/frame_caption_button_container_view.h"
+
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#include "ash/wm/workspace/frame_maximize_button.h"
+#include "grit/ash_resources.h"
+#include "grit/ui_strings.h"  // Accessibility names
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/non_client_view.h"
+
+namespace ash {
+
+namespace {
+
+// The space between the buttons.
+const int kButtonGap = -1;
+
+}  // namespace
+
+// static
+const char FrameCaptionButtonContainerView::kViewClassName[] =
+    "FrameCaptionButtonContainerView";
+
+FrameCaptionButtonContainerView::FrameCaptionButtonContainerView(
+    views::NonClientFrameView* frame_view,
+    views::Widget* frame)
+    : frame_(frame),
+      size_button_(new FrameMaximizeButton(this, frame_view)),
+      close_button_(new views::ImageButton(this)) {
+  // Insert the buttons left to right.
+  size_button_->SetAccessibleName(
+      l10n_util::GetStringUTF16(IDS_APP_ACCNAME_MAXIMIZE));
+  if (ash::Shell::IsForcedMaximizeMode())
+    size_button_->SetVisible(false);
+  AddChildView(size_button_);
+
+  close_button_->SetAccessibleName(
+      l10n_util::GetStringUTF16(IDS_APP_ACCNAME_CLOSE));
+  AddChildView(close_button_);
+}
+
+FrameCaptionButtonContainerView::~FrameCaptionButtonContainerView() {
+}
+
+void FrameCaptionButtonContainerView::ResetWindowControls() {
+  size_button_->SetState(views::CustomButton::STATE_NORMAL);
+}
+
+gfx::Size FrameCaptionButtonContainerView::GetPreferredSize() {
+  int width = 0;
+  bool first_visible = true;
+  for (int i = 0; i < child_count(); ++i) {
+    views::View* child = child_at(i);
+    if (!child->visible())
+      continue;
+
+    width += child_at(i)->GetPreferredSize().width();
+    if (!first_visible)
+      width += kButtonGap;
+    first_visible = false;
+  }
+  gfx::Insets insets(GetInsets());
+  return gfx::Size(
+      width + insets.width(),
+      close_button_->GetPreferredSize().height() + insets.height());
+}
+
+void FrameCaptionButtonContainerView::Layout() {
+  SetButtonImages(size_button_,
+                  IDR_AURA_WINDOW_FULLSCREEN_RESTORE,
+                  IDR_AURA_WINDOW_FULLSCREEN_RESTORE_H,
+                  IDR_AURA_WINDOW_FULLSCREEN_RESTORE_P);
+  SetButtonImages(close_button_,
+                  IDR_AURA_WINDOW_FULLSCREEN_CLOSE,
+                  IDR_AURA_WINDOW_FULLSCREEN_CLOSE_H,
+                  IDR_AURA_WINDOW_FULLSCREEN_CLOSE_P);
+
+  gfx::Insets insets(GetInsets());
+  int x = insets.left();
+  int y_inset = insets.top();
+  for (int i = 0; i < child_count(); ++i) {
+    views::View* child = child_at(i);
+    if (!child->visible())
+      continue;
+
+    gfx::Size size = child->GetPreferredSize();
+    child->SetBounds(x, y_inset, size.width(), size.height());
+    x += size.width() + kButtonGap;
+  }
+}
+
+const char* FrameCaptionButtonContainerView::GetClassName() const {
+  return kViewClassName;
+}
+
+void FrameCaptionButtonContainerView::SetButtonImages(
+    views::ImageButton* button,
+    int normal_image_id,
+    int hot_image_id,
+    int pushed_image_id) {
+  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
+  button->SetImage(views::CustomButton::STATE_NORMAL,
+                   resource_bundle.GetImageSkiaNamed(normal_image_id));
+  button->SetImage(views::CustomButton::STATE_HOVERED,
+                   resource_bundle.GetImageSkiaNamed(hot_image_id));
+  button->SetImage(views::CustomButton::STATE_PRESSED,
+                   resource_bundle.GetImageSkiaNamed(pushed_image_id));
+}
+
+void FrameCaptionButtonContainerView::ButtonPressed(views::Button* sender,
+                                                    const ui::Event& event) {
+  ash::UserMetricsAction action =
+      ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE;
+  if (sender == size_button_) {
+    // The maximize button may move out from under the cursor.
+    ResetWindowControls();
+    frame_->Restore();
+  } else if (sender == close_button_) {
+    action = ash::UMA_WINDOW_CLOSE_BUTTON_CLICK;
+    frame_->Close();
+  } else {
+    return;
+  }
+  ash::Shell::GetInstance()->delegate()->RecordUserMetricsAction(action);
+}
+
+}  // namespace ash
diff --git a/ash/wm/workspace/frame_caption_button_container_view.h b/ash/wm/workspace/frame_caption_button_container_view.h
new file mode 100644
index 0000000..0fe256b
--- /dev/null
+++ b/ash/wm/workspace/frame_caption_button_container_view.h
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium Authors. 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_WORKSPACE_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_
+#define ASH_WM_WORKSPACE_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_
+
+#include "ash/ash_export.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+
+namespace views {
+class ImageButton;
+class NonClientFrameView;
+class Widget;
+}
+
+namespace ash {
+
+// Container view for the frame caption buttons. It performs the appropriate
+// action when a caption button is clicked.
+class ASH_EXPORT FrameCaptionButtonContainerView
+    : public views::View,
+      public views::ButtonListener {
+ public:
+  static const char kViewClassName[];
+
+  // |frame_view| and |frame| are the NonClientFrameView and the views::Widget
+  // that the caption buttons act on.
+  // TODO(pkotwicz): Remove the |frame_view| parameter once FrameMaximizeButton
+  // is refactored to take in a views::Widget instead.
+  FrameCaptionButtonContainerView(views::NonClientFrameView* frame_view,
+                                  views::Widget* frame);
+  virtual ~FrameCaptionButtonContainerView();
+
+  // For testing.
+  class TestApi {
+   public:
+    explicit TestApi(FrameCaptionButtonContainerView* container_view)
+        : container_view_(container_view) {
+    }
+
+    views::ImageButton* size_button() const {
+      return container_view_->size_button_;
+    }
+
+    views::ImageButton* close_button() const {
+      return container_view_->close_button_;
+    }
+
+   private:
+    FrameCaptionButtonContainerView* container_view_;
+
+    DISALLOW_COPY_AND_ASSIGN(TestApi);
+  };
+
+  // Tell the window controls to reset themselves to the normal state.
+  void ResetWindowControls();
+
+  // views::View overrides:
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void Layout() OVERRIDE;
+  virtual const char* GetClassName() const OVERRIDE;
+
+ private:
+  // Sets the images for a button based on the given ids.
+  void SetButtonImages(views::ImageButton* button,
+                       int normal_image_id,
+                       int hot_image_id,
+                       int pushed_image_id);
+
+  // views::ButtonListener override:
+  virtual void ButtonPressed(views::Button* sender,
+                             const ui::Event& event) OVERRIDE;
+
+  // The widget that the buttons act on.
+  views::Widget* frame_;
+
+  // The buttons.
+  views::ImageButton* size_button_;
+  views::ImageButton* close_button_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameCaptionButtonContainerView);
+};
+
+}  // namesapace ash
+
+#endif  // ASH_WM_WORKSPACE_FRAME_CAPTION_BUTTON_CONTAINER_VIEW_H_
diff --git a/ash/wm/workspace/frame_caption_button_container_view_unittest.cc b/ash/wm/workspace/frame_caption_button_container_view_unittest.cc
new file mode 100644
index 0000000..69bb97b
--- /dev/null
+++ b/ash/wm/workspace/frame_caption_button_container_view_unittest.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 "ash/wm/workspace/frame_caption_button_container_view.h"
+
+#include "ash/ash_switches.h"
+#include "base/command_line.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/button/image_button.h"
+
+namespace ash {
+
+typedef testing::Test FrameCaptionButtonContainerViewTest;
+
+TEST_F(FrameCaptionButtonContainerViewTest, Sanity) {
+  // 1) Test the layout and the caption button visibility in the default case.
+  // Both the size button and the close button should be visible.
+  FrameCaptionButtonContainerView c1(NULL, NULL);
+  c1.Layout();
+  FrameCaptionButtonContainerView::TestApi t1(&c1);
+  views::ImageButton* size_button = t1.size_button();
+  views::ImageButton* close_button = t1.close_button();
+  EXPECT_TRUE(size_button->visible());
+  EXPECT_TRUE(close_button->visible());
+
+  // The size button should be left of the close button. (in non-RTL)
+  EXPECT_LT(size_button->x(), close_button->x());
+
+  // The container's bounds should be flush with the caption buttons.
+  EXPECT_EQ(0, size_button->x());
+  EXPECT_EQ(c1.GetPreferredSize().width(), close_button->bounds().right());
+  EXPECT_EQ(c1.GetPreferredSize().height(), close_button->bounds().height());
+
+  // 2) Test the layout and the caption button visibility when the
+  // "force-maximize-mode" experiment is turned on. Only the close button
+  // should be visible.
+  CommandLine::ForCurrentProcess()->AppendSwitch(switches::kForcedMaximizeMode);
+
+  FrameCaptionButtonContainerView c2(NULL, NULL);
+  c2.Layout();
+  FrameCaptionButtonContainerView::TestApi t2(&c2);
+  size_button = t2.size_button();
+  close_button = t2.close_button();
+
+  EXPECT_FALSE(size_button->visible());
+  EXPECT_TRUE(close_button->visible());
+  EXPECT_EQ(c2.GetPreferredSize().width(), close_button->width());
+  EXPECT_EQ(c2.GetPreferredSize().height(), close_button->height());
+}
+
+// Test the layout when a border is set on the container.
+TEST_F(FrameCaptionButtonContainerViewTest, Border) {
+  const int kTopInset = 1;
+  const int kLeftInset = 2;
+  const int kBottomInset = 3;
+  const int kRightInset = 4;
+
+  FrameCaptionButtonContainerView c(NULL, NULL);
+  c.set_border(views::Border::CreateEmptyBorder(
+      kTopInset, kLeftInset, kBottomInset, kRightInset));
+  c.Layout();
+  FrameCaptionButtonContainerView::TestApi t(&c);
+
+  EXPECT_EQ(kLeftInset, t.size_button()->x());
+  EXPECT_EQ(kTopInset, t.close_button()->y());
+  EXPECT_EQ(c.GetPreferredSize().height(),
+            t.close_button()->bounds().bottom() + kBottomInset);
+  EXPECT_EQ(c.GetPreferredSize().width(),
+            t.close_button()->bounds().right() + kRightInset);
+}
+
+}  // namespace ash
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc
index 4287d5b..67272c1 100644
--- a/ash/wm/workspace/phantom_window_controller.cc
+++ b/ash/wm/workspace/phantom_window_controller.cc
@@ -8,6 +8,7 @@
 #include "ash/shell_window_ids.h"
 #include "ash/wm/coordinate_conversion.h"
 #include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/base/animation/slide_animation.h"
 #include "ui/compositor/layer.h"
@@ -91,25 +92,56 @@
 PhantomWindowController::PhantomWindowController(aura::Window* window)
     : window_(window),
       phantom_below_window_(NULL),
-      phantom_widget_(NULL) {
+      phantom_widget_(NULL),
+      phantom_widget_start_(NULL) {
 }
 
 PhantomWindowController::~PhantomWindowController() {
   Hide();
 }
 
-void PhantomWindowController::Show(const gfx::Rect& bounds) {
-  if (bounds == bounds_)
+void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) {
+  if (bounds_in_screen == bounds_in_screen_)
     return;
-  bounds_ = bounds;
-  if (!phantom_widget_) {
-    // Show the phantom at the bounds of the window. We'll animate to the target
-    // bounds.
+  bounds_in_screen_ = bounds_in_screen;
+  aura::RootWindow* 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_)
     start_bounds_ = window_->GetBoundsInScreen();
-    CreatePhantomWidget(start_bounds_);
-  } else {
+  else
     start_bounds_ = phantom_widget_->GetWindowBoundsInScreen();
+  if (phantom_widget_ &&
+      phantom_widget_->GetNativeWindow()->GetRootWindow() != target_root) {
+    phantom_widget_->Close();
+    phantom_widget_ = NULL;
   }
+  if (!phantom_widget_)
+    phantom_widget_ = CreatePhantomWidget(target_root, start_bounds_);
+
+  // 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_);
+  if (start_root == target_root) {
+    Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
+    for (size_t i = 0; i < root_windows.size(); ++i) {
+      if (root_windows[i] != target_root &&
+          root_windows[i]->GetBoundsInScreen().Intersects(start_bounds_)) {
+        start_root = root_windows[i];
+        break;
+      }
+    }
+  }
+  if (phantom_widget_start_ &&
+      (phantom_widget_start_->GetNativeWindow()->GetRootWindow() != start_root
+       || start_root == target_root)) {
+    phantom_widget_start_->Close();
+    phantom_widget_start_ = NULL;
+  }
+  if (!phantom_widget_start_ && start_root != target_root)
+    phantom_widget_start_ = CreatePhantomWidget(start_root, start_bounds_);
+
   animation_.reset(new ui::SlideAnimation(this));
   animation_->SetTweenType(ui::Tween::EASE_IN);
   const int kAnimationDurationMS = 200;
@@ -121,6 +153,9 @@
   if (phantom_widget_)
     phantom_widget_->Close();
   phantom_widget_ = NULL;
+  if (phantom_widget_start_)
+    phantom_widget_start_->Close();
+  phantom_widget_start_ = NULL;
 }
 
 bool PhantomWindowController::IsShowing() const {
@@ -129,45 +164,50 @@
 
 void PhantomWindowController::AnimationProgressed(
     const ui::Animation* animation) {
-  phantom_widget_->SetBounds(
-      animation->CurrentValueBetween(start_bounds_, bounds_));
+  const gfx::Rect current_bounds =
+      animation->CurrentValueBetween(start_bounds_, bounds_in_screen_);
+  if (phantom_widget_start_)
+    phantom_widget_start_->SetBounds(current_bounds);
+  phantom_widget_->SetBounds(current_bounds);
 }
 
-void PhantomWindowController::CreatePhantomWidget(const gfx::Rect& bounds) {
-  DCHECK(!phantom_widget_);
-  phantom_widget_ = new views::Widget;
+views::Widget* PhantomWindowController::CreatePhantomWidget(
+    aura::RootWindow* root_window,
+    const gfx::Rect& bounds_in_screen) {
+  views::Widget* phantom_widget = new views::Widget;
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   // PhantomWindowController is used by FrameMaximizeButton to highlight the
   // launcher button. Put the phantom in the same window as the launcher so that
   // the phantom is visible.
-  params.parent = Shell::GetContainer(wm::GetRootWindowMatching(bounds),
+  params.parent = Shell::GetContainer(root_window,
                                       kShellWindowId_ShelfContainer);
   params.can_activate = false;
   params.keep_on_top = true;
-  phantom_widget_->set_focus_on_creation(false);
-  phantom_widget_->Init(params);
-  phantom_widget_->SetVisibilityChangedAnimationsEnabled(false);
-  phantom_widget_->GetNativeWindow()->SetName("PhantomWindow");
-  phantom_widget_->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow);
+  phantom_widget->set_focus_on_creation(false);
+  phantom_widget->Init(params);
+  phantom_widget->SetVisibilityChangedAnimationsEnabled(false);
+  phantom_widget->GetNativeWindow()->SetName("PhantomWindow");
+  phantom_widget->GetNativeWindow()->set_id(kShellWindowId_PhantomWindow);
   views::View* content_view = new views::View;
   content_view->set_background(
       views::Background::CreateBackgroundPainter(true, new EdgePainter));
-  phantom_widget_->SetContentsView(content_view);
-  phantom_widget_->SetBounds(bounds);
+  phantom_widget->SetContentsView(content_view);
+  phantom_widget->SetBounds(bounds_in_screen);
   if (phantom_below_window_)
-    phantom_widget_->StackBelow(phantom_below_window_);
+    phantom_widget->StackBelow(phantom_below_window_);
   else
-    phantom_widget_->StackAbove(window_);
+    phantom_widget->StackAbove(window_);
 
   // Show the widget after all the setups.
-  phantom_widget_->Show();
+  phantom_widget->Show();
 
   // Fade the window in.
-  ui::Layer* widget_layer = phantom_widget_->GetNativeWindow()->layer();
+  ui::Layer* widget_layer = phantom_widget->GetNativeWindow()->layer();
   widget_layer->SetOpacity(0);
   ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator());
   widget_layer->SetOpacity(1);
+  return phantom_widget;
 }
 
 }  // namespace internal
diff --git a/ash/wm/workspace/phantom_window_controller.h b/ash/wm/workspace/phantom_window_controller.h
index d7622fc..5cd40da 100644
--- a/ash/wm/workspace/phantom_window_controller.h
+++ b/ash/wm/workspace/phantom_window_controller.h
@@ -13,6 +13,7 @@
 #include "ui/gfx/rect.h"
 
 namespace aura {
+class RootWindow;
 class Window;
 }
 
@@ -35,13 +36,14 @@
   virtual ~PhantomWindowController();
 
   // Bounds last passed to Show().
-  const gfx::Rect& bounds() const { return bounds_; }
+  const gfx::Rect& bounds_in_screen() const { return bounds_in_screen_; }
 
-  // Shows the phantom window at the specified location (coordinates of the
-  // parent). If |layer| is non-NULL, it is shown on top of the phantom window.
-  // |layer| is owned by the caller.
+  // Animates the phantom window towards |bounds_in_screen|.
+  // Creates two (if start bounds intersect any root window other than the
+  // root window that matches the target bounds) or one (otherwise) phantom
+  // widgets to display animated rectangle in each root.
   // This does not immediately show the window.
-  void Show(const gfx::Rect& bounds);
+  void Show(const gfx::Rect& bounds_in_screen);
 
   // Hides the phantom.
   void Hide();
@@ -59,12 +61,12 @@
   virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, PhantomStyle);
+  FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, PhantomWindowShow);
 
-  // Creates and shows the |phantom_widget_| at |bounds|.
-  // |layer| is shown on top of the phantom window if it is non-NULL.
-  // |layer| is not owned by this object.
-  void CreatePhantomWidget(const gfx::Rect& bounds);
+  // 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,
+                                     const gfx::Rect& bounds_in_screen);
 
   // Window the phantom is placed beneath.
   aura::Window* window_;
@@ -72,15 +74,24 @@
   // If set, the phantom window should get stacked below this window.
   aura::Window* phantom_below_window_;
 
-  // Initially the bounds of |window_|. Each time Show() is invoked
-  // |start_bounds_| is then reset to the bounds of |phantom_widget_| and
-  // |bounds_| is set to the value passed into Show(). The animation animates
-  // between these two values.
+  // Initially the bounds of |window_| (in screen coordinates).
+  // Each time Show() is invoked |start_bounds_| is then reset to the bounds of
+  // |phantom_widget_| and |bounds_| is set to the value passed into Show().
+  // The animation animates between these two values.
   gfx::Rect start_bounds_;
-  gfx::Rect bounds_;
 
+  // Target bounds of the animation in screen coordinates.
+  gfx::Rect bounds_in_screen_;
+
+  // The primary phantom representation of the window. It is parented by the
+  // root window matching the target bounds.
   views::Widget* phantom_widget_;
 
+  // If the animation starts on another display, this is the secondary phantom
+  // representation of the window used on the initial display, otherwise this is
+  // NULL. This allows animation to progress from one display into the other.
+  views::Widget* phantom_widget_start_;
+
   // Used to transition the bounds.
   scoped_ptr<ui::SlideAnimation> animation_;
 
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index c748d9a..0dd9dbf 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -48,13 +48,15 @@
     return;
 
   // Move only if the restore bounds is outside of
-  // the root window. There is no information about in which
+  // the display. There is no information about in which
   // display it should be restored, so this is best guess.
   // TODO(oshima): Restore information should contain the
   // work area information like WindowResizer does for the
   // last window location.
-  if (!window->GetRootWindow()->GetBoundsInScreen().Intersects(
-          *restore_bounds)) {
+  gfx::Rect display_area =
+      Shell::GetScreen()->GetDisplayNearestWindow(window).bounds();
+
+  if (!display_area.Intersects(*restore_bounds)) {
     DisplayController* display_controller =
         Shell::GetInstance()->display_controller();
     const gfx::Display& display =
@@ -87,14 +89,7 @@
 }
 
 void WorkspaceLayoutManager::OnWindowAddedToLayout(Window* child) {
-  // Adjust window bounds in case that the new child is given the bounds that
-  // is out of the workspace. Exclude the case where bounds is empty
-  // (this happens when a views::Widget is created), or the window
-  // is added with the bounds because a user explicitly moved to
-  // this position (drag and drop for example).
-  if (!child->bounds().IsEmpty() &&
-      !wm::HasUserChangedWindowPositionOrSize(child))
-    AdjustWindowBoundsWhenAdded(child);
+  AdjustWindowBoundsWhenAdded(child);
   BaseLayoutManager::OnWindowAddedToLayout(child);
   UpdateDesktopVisibility();
   RearrangeVisibleWindowOnShow(child);
@@ -252,6 +247,14 @@
 
 void WorkspaceLayoutManager::AdjustWindowBoundsWhenAdded(
     Window* window) {
+  // Don't adjust window bounds if the bounds are empty as this
+  // happens when a new views::Widget is created.
+  // When a window is dragged and dropped onto a different
+  // root window, the bounds will be updated after they are added
+  // to the root window.
+  if (window->bounds().IsEmpty())
+    return;
+
   if (!GetTrackedByWorkspace(window))
     return;
 
@@ -261,9 +264,14 @@
   gfx::Rect bounds = window->bounds();
   int min_width = bounds.width() * kMinimumPercentOnScreenArea;
   int min_height = bounds.height() * kMinimumPercentOnScreenArea;
+  // Use entire display instead of workarea because the workarea can
+  // be further shrunk by the docked area. The logic ensures 30%
+  // visibility which should be enough to see where the window gets
+  // moved.
+  gfx::Rect display_area =
+      Shell::GetScreen()->GetDisplayNearestWindow(window).bounds();
   ash::wm::AdjustBoundsToEnsureWindowVisibility(
-      work_area_, min_width, min_height, &bounds);
-
+      display_area, min_width, min_height, &bounds);
   if (window->bounds() != bounds)
     window->SetBounds(bounds);
 }
@@ -319,7 +327,7 @@
       break;
     case ui::SHOW_STATE_FULLSCREEN:
       MoveToDisplayForRestore(window);
-      CrossFadeToBounds(window, ScreenAsh::GetDisplayBoundsInParent(
+      SetChildBoundsDirect(window, ScreenAsh::GetDisplayBoundsInParent(
           window->parent()->parent()));
       break;
     default:
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 3dce5b0..13cfdea 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -304,6 +304,15 @@
   EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
   EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
 
+  aura::Window* parent = out_window->parent();
+  parent->RemoveChild(out_window.get());
+  out_window->SetBounds(gfx::Rect(-200, -200, 200, 200));
+  // UserHasChangedWindowPositionOrSize flag shouldn't turn off this behavior.
+  wm::SetUserHasChangedWindowPositionOrSize(window.get(), true);
+  parent->AddChild(out_window.get());
+  EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
+  EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
+
   // Make sure we always make more than 1/3 of the window edge visible even
   // if the initial bounds intersects with display.
   window_bounds.SetRect(-150, -150, 200, 200);
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 2143e45..4b8c0aa 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -87,8 +87,13 @@
     window_resizer = PanelWindowResizer::Create(
         window_resizer, window, point_in_parent, window_component, source);
   }
-  if (window_resizer) {
-    window_resizer = DockedWindowResizer::Create(
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAshEnableDockedWindows) &&
+      window_resizer && window->parent() &&
+      (window->parent()->id() == internal::kShellWindowId_DefaultContainer ||
+       window->parent()->id() == internal::kShellWindowId_DockedContainer ||
+       window->parent()->id() == internal::kShellWindowId_PanelContainer)) {
+    window_resizer = internal::DockedWindowResizer::Create(
         window_resizer, window, point_in_parent, window_component, source);
   }
   return make_scoped_ptr<WindowResizer>(window_resizer);
@@ -98,10 +103,6 @@
 
 namespace {
 
-// Distance in pixels that the cursor must move past an edge for a window
-// to move or resize beyond that edge.
-const int kStickyDistancePixels = 64;
-
 // Snapping distance used instead of WorkspaceWindowResizer::kScreenEdgeInset
 // when resizing a window using touchscreen.
 const int kScreenEdgeInsetForTouchResize = 32;
@@ -116,7 +117,7 @@
            distance_from_edge > -sticky_size;
   }
   return distance_from_edge < sticky_size &&
-                              distance_from_edge > -sticky_size * 2;
+         distance_from_edge > -sticky_size * 2;
 }
 
 // Returns the coordinate along the secondary axis to snap to.
@@ -259,6 +260,9 @@
 // static
 const int WorkspaceWindowResizer::kScreenEdgeInset = 8;
 
+// static
+const int WorkspaceWindowResizer::kStickyDistancePixels = 64;
+
 // Represents the width or height of a window with constraints on its minimum
 // and maximum size. 0 represents a lack of a constraint.
 class WindowSize {
@@ -505,7 +509,7 @@
     const gfx::Rect& bounds) const {
   if (snap_phantom_window_controller_.get() &&
       snap_phantom_window_controller_->IsShowing()) {
-    return snap_phantom_window_controller_->bounds();
+    return snap_phantom_window_controller_->bounds_in_screen();
   }
   return bounds;
 }
@@ -746,8 +750,12 @@
     }
 
     if (sticky_size > 0) {
-      if (!StickToWorkAreaOnMove(work_area, sticky_size, bounds))
+      // Possibly stick to edge except when a mouse pointer is outside the
+      // work area.
+      if (!(display.work_area().Contains(last_mouse_location_in_screen) &&
+            StickToWorkAreaOnMove(work_area, sticky_size, bounds))) {
         MagneticallySnapToOtherWindows(bounds);
+      }
     }
   } else if (sticky_size > 0) {
     MagneticallySnapResizeToOtherWindows(bounds);
diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h
index 61f1896..76176b1 100644
--- a/ash/wm/workspace/workspace_window_resizer.h
+++ b/ash/wm/workspace/workspace_window_resizer.h
@@ -41,6 +41,10 @@
   // this close to an edge of the screen it snaps to the edge.
   static const int kScreenEdgeInset;
 
+  // Distance in pixels that the cursor must move past an edge for a window
+  // to move or resize beyond that edge.
+  static const int kStickyDistancePixels;
+
   virtual ~WorkspaceWindowResizer();
 
   static WorkspaceWindowResizer* Create(
@@ -65,6 +69,7 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, CancelSnapPhantom);
   FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, PhantomSnapMaxSize);
+  FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, PhantomWindowShow);
 
   // Type of snapping.
   enum SnapType {
diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc
index a00d012..8459c54 100644
--- a/ash/wm/workspace/workspace_window_resizer_unittest.cc
+++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc
@@ -30,6 +30,36 @@
 #include "ui/gfx/screen.h"
 #include "ui/views/widget/widget.h"
 
+namespace ui {
+
+// Class to provide access to SlideAnimation internals for testing.
+class SlideAnimation::TestApi {
+ public:
+  explicit TestApi(SlideAnimation* animation) : animation_(animation) {}
+
+  void SetStartTime(base::TimeTicks ticks) {
+    animation_->SetStartTime(ticks);
+  }
+
+  void Step(base::TimeTicks ticks) {
+    animation_->Step(ticks);
+  }
+
+  void RunTillComplete() {
+    SetStartTime(base::TimeTicks());
+    Step(base::TimeTicks() +
+         base::TimeDelta::FromMilliseconds(animation_->GetSlideDuration()));
+    EXPECT_EQ(1.0, animation_->GetCurrentValue());
+  }
+
+ private:
+  SlideAnimation* animation_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestApi);
+};
+
+}
+
 namespace ash {
 namespace internal {
 namespace {
@@ -170,6 +200,12 @@
     touch_resize_window_->set_hit_test_bounds_override_inner(mouse_insets);
   }
 
+  // Simulate running the animation.
+  void RunAnimationTillComplete(ui::SlideAnimation* animation) {
+    ui::SlideAnimation::TestApi test_api(animation);
+    test_api.RunTillComplete();
+  }
+
   TestWindowDelegate delegate_;
   TestWindowDelegate delegate2_;
   TestWindowDelegate delegate3_;
@@ -842,8 +878,12 @@
   Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
       SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
   window_->SetBounds(gfx::Rect(96, 112, 320, 160));
+  // Click 50px to the right so that the mouse pointer does not leave the
+  // workspace ensuring sticky behavior.
   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
-      window_.get(), gfx::Point(), HTCAPTION,
+      window_.get(),
+      window_->bounds().origin() + gfx::Vector2d(50, 0),
+      HTCAPTION,
       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
   ASSERT_TRUE(resizer.get());
   // Move to an x-coordinate of 15, which should not snap.
@@ -958,8 +998,12 @@
   Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
       SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
   window_->SetBounds(gfx::Rect(96, 112, 320, 160));
+  // Click 50px to the right so that the mouse pointer does not leave the
+  // workspace ensuring sticky behavior.
   scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
-      window_.get(), gfx::Point(), HTCAPTION,
+      window_.get(),
+      window_->bounds().origin() + gfx::Vector2d(50, 0),
+      HTCAPTION,
       aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
   ASSERT_TRUE(resizer.get());
   // Move to an x-coordinate of 15, which should not stick.
@@ -994,6 +1038,22 @@
   // No need to test dragging < 0 as we force that to 0.
 }
 
+// Verifies not sticking to edges when a mouse pointer is outside of work area.
+TEST_F(WorkspaceWindowResizerTestSticky, NoStickToEdgeWhenOutside) {
+  Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
+      SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  window_->SetBounds(gfx::Rect(96, 112, 320, 160));
+  scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+      window_.get(), gfx::Point(), HTCAPTION,
+      aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
+  ASSERT_TRUE(resizer.get());
+  // Move to an x-coordinate of 15, which should not stick.
+  resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0);
+  // Move to -15, should still stick to 0.
+  resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0);
+  EXPECT_EQ("-15,112 320x160", window_->bounds().ToString());
+}
+
 // Verifies a resize sticks when dragging TOPLEFT.
 TEST_F(WorkspaceWindowResizerTestSticky, StickToWorkArea_TOPLEFT) {
   window_->SetBounds(gfx::Rect(100, 200, 20, 30));
@@ -1805,5 +1865,114 @@
   EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 100).ToString(),
             touch_resize_window_->bounds().ToString());
 }
+
+TEST_F(WorkspaceWindowResizerTest, PhantomWindowShow) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("500x400,500x400");
+  window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
+                             Shell::GetScreen()->GetPrimaryDisplay());
+  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
+  EXPECT_EQ(root_windows[0], window_->GetRootWindow());
+
+  scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create(
+      window_.get(), gfx::Point(), HTCAPTION,
+      aura::client::WINDOW_MOVE_SOURCE_MOUSE, empty_windows()));
+  ASSERT_TRUE(resizer.get());
+  EXPECT_FALSE(resizer->snap_phantom_window_controller_.get());
+
+  // The pointer is on the edge but not shared. The snap phantom window
+  // controller should be non-NULL.
+  resizer->Drag(CalculateDragPoint(*resizer, 499, 0), 0);
+  EXPECT_TRUE(resizer->snap_phantom_window_controller_.get());
+  PhantomWindowController* phantom_controller(
+      resizer->snap_phantom_window_controller_.get());
+
+  // phantom widget only in the left screen.
+  phantom_controller->Show(gfx::Rect(100, 100, 50, 60));
+  EXPECT_TRUE(phantom_controller->phantom_widget_);
+  EXPECT_FALSE(phantom_controller->phantom_widget_start_);
+  EXPECT_EQ(
+      root_windows[0],
+      phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
+
+  // Move phantom widget into the right screen. Test that 2 widgets got created.
+  phantom_controller->Show(gfx::Rect(600, 100, 50, 60));
+  EXPECT_TRUE(phantom_controller->phantom_widget_);
+  EXPECT_TRUE(phantom_controller->phantom_widget_start_);
+  EXPECT_EQ(
+      root_windows[1],
+      phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
+  EXPECT_EQ(
+      root_windows[0],
+      phantom_controller->phantom_widget_start_->GetNativeWindow()->
+          GetRootWindow());
+  RunAnimationTillComplete(phantom_controller->animation_.get());
+
+  // Move phantom widget only in the right screen. Start widget should close.
+  phantom_controller->Show(gfx::Rect(700, 100, 50, 60));
+  EXPECT_TRUE(phantom_controller->phantom_widget_);
+  EXPECT_FALSE(phantom_controller->phantom_widget_start_);
+  EXPECT_EQ(
+      root_windows[1],
+      phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
+  RunAnimationTillComplete(phantom_controller->animation_.get());
+
+  // Move phantom widget into the left screen. Start widget should open.
+  phantom_controller->Show(gfx::Rect(100, 100, 50, 60));
+  EXPECT_TRUE(phantom_controller->phantom_widget_);
+  EXPECT_TRUE(phantom_controller->phantom_widget_start_);
+  EXPECT_EQ(
+      root_windows[0],
+      phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
+  EXPECT_EQ(
+      root_windows[1],
+      phantom_controller->phantom_widget_start_->GetNativeWindow()->
+          GetRootWindow());
+  RunAnimationTillComplete(phantom_controller->animation_.get());
+
+  // Move phantom widget while in the left screen. Start widget should close.
+  phantom_controller->Show(gfx::Rect(200, 100, 50, 60));
+  EXPECT_TRUE(phantom_controller->phantom_widget_);
+  EXPECT_FALSE(phantom_controller->phantom_widget_start_);
+  EXPECT_EQ(
+      root_windows[0],
+      phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
+  RunAnimationTillComplete(phantom_controller->animation_.get());
+
+  // Move phantom widget spanning both screens with most of the window in the
+  // right screen. Two widgets are created.
+  phantom_controller->Show(gfx::Rect(495, 100, 50, 60));
+  EXPECT_TRUE(phantom_controller->phantom_widget_);
+  EXPECT_TRUE(phantom_controller->phantom_widget_start_);
+  EXPECT_EQ(
+      root_windows[1],
+      phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
+  EXPECT_EQ(
+      root_windows[0],
+      phantom_controller->phantom_widget_start_->GetNativeWindow()->
+          GetRootWindow());
+  RunAnimationTillComplete(phantom_controller->animation_.get());
+
+  // Move phantom widget back into the left screen. Phantom widgets should swap.
+  phantom_controller->Show(gfx::Rect(200, 100, 50, 60));
+  EXPECT_TRUE(phantom_controller->phantom_widget_);
+  EXPECT_TRUE(phantom_controller->phantom_widget_start_);
+  EXPECT_EQ(
+      root_windows[0],
+      phantom_controller->phantom_widget_->GetNativeWindow()->GetRootWindow());
+  EXPECT_EQ(
+      root_windows[1],
+      phantom_controller->phantom_widget_start_->GetNativeWindow()->
+          GetRootWindow());
+  RunAnimationTillComplete(phantom_controller->animation_.get());
+
+  // Hide phantom controller. Both widgets should close.
+  phantom_controller->Hide();
+  EXPECT_FALSE(phantom_controller->phantom_widget_);
+  EXPECT_FALSE(phantom_controller->phantom_widget_start_);
+}
+
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc
index e2ee3f5..7fbbda2 100644
--- a/ash/wm/workspace_controller.cc
+++ b/ash/wm/workspace_controller.cc
@@ -39,8 +39,6 @@
       event_handler_(new WorkspaceEventHandler(viewport_)) {
   SetWindowVisibilityAnimationTransition(
       viewport_, views::corewm::ANIMATE_NONE);
-  // Do this so when animating out windows don't extend beyond the bounds.
-  viewport_->layer()->SetMasksToBounds(true);
 
   // The layout-manager cannot be created in the initializer list since it
   // depends on the window to have been initialized.
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index f6a4ffb..7dca75a 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -1118,8 +1118,16 @@
   }
 
   // aura::WindowObserver overrides:
+  // Counts number of times a window is reparented. Ignores reparenting into and
+  // from a docked container which is expected when a tab is dragged.
   virtual void OnWindowHierarchyChanged(
       const HierarchyChangeParams& params) OVERRIDE {
+    if ((params.old_parent->id() == kShellWindowId_DefaultContainer &&
+         params.new_parent->id() == kShellWindowId_DockedContainer) ||
+        (params.old_parent->id() == kShellWindowId_DockedContainer &&
+         params.new_parent->id() == kShellWindowId_DefaultContainer)) {
+      return;
+    }
     change_count_++;
   }
 
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index eb33091..8c4ac0f 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -56,6 +56,17 @@
     }
 
     /**
+     * @see android.view.ViewGroup.MarginLayoutParams#getMarginEnd()
+     */
+    public static int getMarginEnd(MarginLayoutParams layoutParams) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return layoutParams.getMarginEnd();
+        } else {
+            return layoutParams.rightMargin;
+        }
+    }
+
+    /**
      * @see android.view.ViewGroup.MarginLayoutParams#setMarginStart(int)
      */
     public static void setMarginStart(MarginLayoutParams layoutParams, int start) {
diff --git a/base/android/java/src/org/chromium/base/CollectionUtil.java b/base/android/java/src/org/chromium/base/CollectionUtil.java
new file mode 100644
index 0000000..c0f6b1c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CollectionUtil.java
@@ -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.
+
+package org.chromium.base;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+/**
+ * Functions used for easier initialization of Java collections. Inspired by
+ * functionality in com.google.common.collect in Guava but cherry-picked to
+ * bare-minimum functionality to avoid bloat. (http://crbug.com/272790 provides
+ * further details)
+ */
+public final class CollectionUtil {
+    private CollectionUtil() {}
+
+    public static <E> HashSet<E> newHashSet(E... elements) {
+        HashSet<E> set = new HashSet<E>(elements.length);
+        Collections.addAll(set, elements);
+        return set;
+    }
+
+    public static <E> ArrayList<E> newArrayList(E... elements) {
+        ArrayList<E> list = new ArrayList<E>(elements.length);
+        Collections.addAll(list, elements);
+        return list;
+    }
+
+    public static <E> ArrayList<E> newArrayList(Iterable<E> iterable) {
+        ArrayList<E> list = new ArrayList<E>();
+        for (E element : iterable)
+            list.add(element);
+        return list;
+    }
+}
\ No newline at end of file
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
index fc89b54..0b13699 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -124,6 +124,10 @@
   g_jvm = vm;
 }
 
+bool IsVMInitialized() {
+  return g_jvm != NULL;
+}
+
 void InitApplicationContext(const JavaRef<jobject>& context) {
   DCHECK(g_application_context.Get().is_null());
   g_application_context.Get().Reset(context);
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
index e8f68ac..83c9bc8 100644
--- a/base/android/jni_android.h
+++ b/base/android/jni_android.h
@@ -35,6 +35,9 @@
 // InitApplicationContext().
 BASE_EXPORT void InitVM(JavaVM* vm);
 
+// Returns true if the global JVM has been initialized.
+BASE_EXPORT bool IsVMInitialized();
+
 // Initializes the global application context object. The |context| can be any
 // valid reference to the application context. Internally holds a global ref to
 // the context. InitVM and InitApplicationContext maybe called in either order.
diff --git a/base/async_socket_io_handler.h b/base/async_socket_io_handler.h
new file mode 100644
index 0000000..562ae25
--- /dev/null
+++ b/base/async_socket_io_handler.h
@@ -0,0 +1,112 @@
+// Copyright 2013 The Chromium Authors. 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_ASYNC_SOCKET_IO_HANDLER_H_
+#define BASE_ASYNC_SOCKET_IO_HANDLER_H_
+
+#include "base/message_loop/message_loop.h"
+#include "base/sync_socket.h"
+#include "base/threading/non_thread_safe.h"
+
+namespace media {
+
+// The message loop callback interface is different based on platforms.
+#if defined(OS_WIN)
+typedef base::MessageLoopForIO::IOHandler MessageLoopIOHandler;
+#elif defined(OS_POSIX)
+typedef base::MessageLoopForIO::Watcher MessageLoopIOHandler;
+#endif
+
+// Extends the CancelableSyncSocket class to allow reading from a socket
+// asynchronously on a TYPE_IO message loop thread.  This makes it easy to share
+// a thread that uses a message loop (e.g. for IPC and other things) and not
+// require a separate thread to read from the socket.
+//
+// Example usage (also see the unit tests):
+//
+// class SocketReader {
+//  public:
+//   SocketReader(base::CancelableSyncSocket* socket)
+//       : socket_(socket), buffer_() {
+//     io_handler.Initialize(socket_->handle(),
+//                           base::Bind(&SocketReader::OnDataAvailable,
+//                                      base::Unretained(this));
+//   }
+//
+//   void AsyncRead() {
+//     CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
+//   }
+//
+//  private:
+//   void OnDataAvailable(int bytes_read) {
+//     if (ProcessData(&buffer_[0], bytes_read)) {
+//       // Issue another read.
+//       CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
+//     }
+//   }
+//
+//   media::AsyncSocketIoHandler io_handler;
+//   base::CancelableSyncSocket* socket_;
+//   char buffer_[kBufferSize];
+// };
+//
+class BASE_EXPORT AsyncSocketIoHandler
+    : public NON_EXPORTED_BASE(base::NonThreadSafe),
+      public NON_EXPORTED_BASE(MessageLoopIOHandler) {
+ public:
+  AsyncSocketIoHandler();
+  virtual ~AsyncSocketIoHandler();
+
+  // Type definition for the callback. The parameter tells how many
+  // bytes were read and is 0 if an error occurred.
+  typedef base::Callback<void(int)> ReadCompleteCallback;
+
+  // Initializes the AsyncSocketIoHandler by hooking it up to the current
+  // thread's message loop (must be TYPE_IO), to do async reads from the socket
+  // on the current thread.  The |callback| will be invoked whenever a Read()
+  // has completed.
+  bool Initialize(base::SyncSocket::Handle socket,
+                  const ReadCompleteCallback& callback);
+
+  // Attempts to read from the socket.  The return value will be |false|
+  // if an error occurred and |true| if data was read or a pending read
+  // was issued.  Regardless of async or sync operation, the
+  // ReadCompleteCallback (see above) will be called when data is available.
+  bool Read(char* buffer, int buffer_len);
+
+ private:
+#if defined(OS_WIN)
+  // Implementation of IOHandler on Windows.
+  virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
+                             DWORD bytes_transfered,
+                             DWORD error) OVERRIDE;
+#elif defined(OS_POSIX)
+  // Implementation of base::MessageLoopForIO::Watcher.
+  virtual void OnFileCanWriteWithoutBlocking(int socket) OVERRIDE {}
+  virtual void OnFileCanReadWithoutBlocking(int socket) OVERRIDE;
+
+  void EnsureWatchingSocket();
+#endif
+
+  base::SyncSocket::Handle socket_;
+#if defined(OS_WIN)
+  base::MessageLoopForIO::IOContext* context_;
+  bool is_pending_;
+#elif defined(OS_POSIX)
+  base::MessageLoopForIO::FileDescriptorWatcher socket_watcher_;
+  // |pending_buffer_| and |pending_buffer_len_| are valid only between
+  // Read() and OnFileCanReadWithoutBlocking().
+  char* pending_buffer_;
+  int pending_buffer_len_;
+  // |true| iff the message loop is watching the socket for IO events.
+  bool is_watching_;
+#endif
+  ReadCompleteCallback read_complete_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncSocketIoHandler);
+};
+
+}  // namespace media.
+
+#endif  // BASE_ASYNC_SOCKET_IO_HANDLER_H_
diff --git a/base/async_socket_io_handler_posix.cc b/base/async_socket_io_handler_posix.cc
new file mode 100644
index 0000000..34c1c53
--- /dev/null
+++ b/base/async_socket_io_handler_posix.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 "base/async_socket_io_handler.h"
+
+#include <fcntl.h>
+
+#include "base/posix/eintr_wrapper.h"
+
+namespace media {
+
+AsyncSocketIoHandler::AsyncSocketIoHandler()
+    : socket_(base::SyncSocket::kInvalidHandle),
+      pending_buffer_(NULL),
+      pending_buffer_len_(0),
+      is_watching_(false) {
+}
+
+AsyncSocketIoHandler::~AsyncSocketIoHandler() {
+  DCHECK(CalledOnValidThread());
+}
+
+void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(socket, socket_);
+  DCHECK(!read_complete_.is_null());
+
+  if (pending_buffer_) {
+    int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
+                                       pending_buffer_len_));
+    DCHECK_GE(bytes_read, 0);
+    pending_buffer_ = NULL;
+    pending_buffer_len_ = 0;
+    read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
+  } else {
+    // We're getting notifications that we can read from the socket while
+    // we're not waiting for data.  In order to not starve the message loop,
+    // let's stop watching the fd and restart the watch when Read() is called.
+    is_watching_ = false;
+    socket_watcher_.StopWatchingFileDescriptor();
+  }
+}
+
+bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!read_complete_.is_null());
+  DCHECK(!pending_buffer_);
+
+  EnsureWatchingSocket();
+
+  int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
+  if (bytes_read < 0) {
+    if (errno == EAGAIN) {
+      pending_buffer_ = buffer;
+      pending_buffer_len_ = buffer_len;
+    } else {
+      NOTREACHED() << "read(): " << errno;
+      return false;
+    }
+  } else {
+    read_complete_.Run(bytes_read);
+  }
+  return true;
+}
+
+bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
+                                      const ReadCompleteCallback& callback) {
+  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
+
+  DetachFromThread();
+
+  socket_ = socket;
+  read_complete_ = callback;
+
+  // SyncSocket is blocking by default, so let's convert it to non-blocking.
+  int value = fcntl(socket, F_GETFL);
+  if (!(value & O_NONBLOCK)) {
+    // Set the socket to be non-blocking so we can do async reads.
+    if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
+      NOTREACHED();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void AsyncSocketIoHandler::EnsureWatchingSocket() {
+  DCHECK(CalledOnValidThread());
+  if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
+    is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
+        socket_, true, base::MessageLoopForIO::WATCH_READ,
+        &socket_watcher_, this);
+  }
+}
+
+}  // namespace media.
diff --git a/base/async_socket_io_handler_unittest.cc b/base/async_socket_io_handler_unittest.cc
new file mode 100644
index 0000000..e8bdacd
--- /dev/null
+++ b/base/async_socket_io_handler_unittest.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 "base/async_socket_io_handler.h"
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const char kAsyncSocketIoTestString[] = "Hello, AsyncSocketIoHandler";
+const size_t kAsyncSocketIoTestStringLength =
+    arraysize(kAsyncSocketIoTestString);
+
+class TestSocketReader {
+ public:
+  // Set |number_of_reads_before_quit| to >0 when you expect a specific number
+  // of Read operations to complete.  Once that number is reached, the current
+  // message loop will be Quit().  Set |number_of_reads_before_quit| to -1 if
+  // callbacks should not be counted.
+  TestSocketReader(base::CancelableSyncSocket* socket,
+                   int number_of_reads_before_quit,
+                   bool issue_reads_from_callback,
+                   bool expect_eof)
+      : socket_(socket), buffer_(),
+        number_of_reads_before_quit_(number_of_reads_before_quit),
+        callbacks_received_(0),
+        issue_reads_from_callback_(issue_reads_from_callback),
+        expect_eof_(expect_eof) {
+    io_handler.Initialize(socket_->handle(),
+                          base::Bind(&TestSocketReader::OnRead,
+                                     base::Unretained(this)));
+  }
+  ~TestSocketReader() {}
+
+  bool IssueRead() {
+    return io_handler.Read(&buffer_[0], sizeof(buffer_));
+  }
+
+  const char* buffer() const { return &buffer_[0]; }
+
+  int callbacks_received() const { return callbacks_received_; }
+
+ private:
+  void OnRead(int bytes_read) {
+    if (!expect_eof_) {
+      EXPECT_GT(bytes_read, 0);
+    } else {
+      EXPECT_GE(bytes_read, 0);
+    }
+    ++callbacks_received_;
+    if (number_of_reads_before_quit_ == callbacks_received_) {
+      base::MessageLoop::current()->Quit();
+    } else if (issue_reads_from_callback_) {
+      IssueRead();
+    }
+  }
+
+  media::AsyncSocketIoHandler io_handler;
+  base::CancelableSyncSocket* socket_;  // Ownership lies outside the class.
+  char buffer_[kAsyncSocketIoTestStringLength];
+  int number_of_reads_before_quit_;
+  int callbacks_received_;
+  bool issue_reads_from_callback_;
+  bool expect_eof_;
+};
+
+// Workaround to be able to use a base::Closure for sending data.
+// Send() returns int but a closure must return void.
+void SendData(base::CancelableSyncSocket* socket,
+              const void* buffer,
+              size_t length) {
+  socket->Send(buffer, length);
+}
+
+}  // end namespace.
+
+// Tests doing a pending read from a socket and use an IO handler to get
+// notified of data.
+TEST(AsyncSocketIoHandlerTest, AsynchronousReadWithMessageLoop) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  TestSocketReader reader(&pair[0], 1, false, false);
+  EXPECT_TRUE(reader.IssueRead());
+
+  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
+  EXPECT_EQ(1, reader.callbacks_received());
+}
+
+// Tests doing a read from a socket when we know that there is data in the
+// socket.  Here we want to make sure that any async 'can read' notifications
+// won't trip us off and that the synchronous case works as well.
+TEST(AsyncSocketIoHandlerTest, SynchronousReadWithMessageLoop) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  TestSocketReader reader(&pair[0], -1, false, false);
+
+  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
+  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      base::MessageLoop::QuitClosure(),
+      base::TimeDelta::FromMilliseconds(100));
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(reader.IssueRead());
+  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
+  // We've now verified that the read happened synchronously, but it's not
+  // guaranteed that the callback has been issued since the callback will be
+  // called asynchronously even though the read may have been done.
+  // So we call RunUntilIdle() to allow any event notifications or APC's on
+  // Windows, to execute before checking the count of how many callbacks we've
+  // received.
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(1, reader.callbacks_received());
+}
+
+// Calls Read() from within a callback to test that simple read "loops" work.
+TEST(AsyncSocketIoHandlerTest, ReadFromCallback) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  const int kReadOperationCount = 10;
+  TestSocketReader reader(&pair[0], kReadOperationCount, true, false);
+  EXPECT_TRUE(reader.IssueRead());
+
+  // Issue sends on an interval to satisfy the Read() requirements.
+  int64 milliseconds = 0;
+  for (int i = 0; i < kReadOperationCount; ++i) {
+    base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+        base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
+            kAsyncSocketIoTestStringLength),
+        base::TimeDelta::FromMilliseconds(milliseconds));
+    milliseconds += 10;
+  }
+
+  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      base::MessageLoop::QuitClosure(),
+      base::TimeDelta::FromMilliseconds(100 + milliseconds));
+
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
+}
+
+// Calls Read() then close other end, check that a correct callback is received.
+TEST(AsyncSocketIoHandlerTest, ReadThenClose) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  const int kReadOperationCount = 1;
+  TestSocketReader reader(&pair[0], kReadOperationCount, false, true);
+  EXPECT_TRUE(reader.IssueRead());
+
+  pair[1].Close();
+
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
+}
diff --git a/base/async_socket_io_handler_win.cc b/base/async_socket_io_handler_win.cc
new file mode 100644
index 0000000..f974d6e
--- /dev/null
+++ b/base/async_socket_io_handler_win.cc
@@ -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.
+
+#include "base/async_socket_io_handler.h"
+
+namespace media {
+
+AsyncSocketIoHandler::AsyncSocketIoHandler()
+    : socket_(base::SyncSocket::kInvalidHandle),
+      context_(NULL),
+      is_pending_(false) {}
+
+AsyncSocketIoHandler::~AsyncSocketIoHandler() {
+  // We need to be deleted on the correct thread to avoid racing with the
+  // message loop thread.
+  DCHECK(CalledOnValidThread());
+
+  if (context_) {
+    if (is_pending_) {
+      // Make the context be deleted by the message pump when done.
+      context_->handler = NULL;
+    } else {
+      delete context_;
+    }
+  }
+}
+
+// Implementation of IOHandler on Windows.
+void AsyncSocketIoHandler::OnIOCompleted(
+    base::MessageLoopForIO::IOContext* context,
+    DWORD bytes_transfered,
+    DWORD error) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(context_, context);
+  DCHECK(!read_complete_.is_null());
+  is_pending_ = false;
+  read_complete_.Run(error == ERROR_SUCCESS ? bytes_transfered : 0);
+}
+
+bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!read_complete_.is_null());
+  DCHECK(!is_pending_);
+  DCHECK_NE(socket_, base::SyncSocket::kInvalidHandle);
+
+  DWORD bytes_read = 0;
+  BOOL ok = ::ReadFile(socket_, buffer, buffer_len, &bytes_read,
+                       &context_->overlapped);
+  // The completion port will be signaled regardless of completing the read
+  // straight away or asynchronously (ERROR_IO_PENDING). OnIOCompleted() will
+  // be called regardless and we don't need to explicitly run the callback
+  // in the case where ok is FALSE and GLE==ERROR_IO_PENDING.
+  is_pending_ = !ok && (GetLastError() == ERROR_IO_PENDING);
+  return ok || is_pending_;
+}
+
+bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
+                                      const ReadCompleteCallback& callback) {
+  DCHECK(!context_);
+  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
+
+  DetachFromThread();
+
+  socket_ = socket;
+  read_complete_ = callback;
+
+  base::MessageLoopForIO::current()->RegisterIOHandler(socket, this);
+
+  context_ = new base::MessageLoopForIO::IOContext();
+  context_->handler = this;
+  memset(&context_->overlapped, 0, sizeof(context_->overlapped));
+
+  return true;
+}
+
+}  // namespace media.
diff --git a/base/base.gyp b/base/base.gyp
index e2af06b..2600754 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -237,6 +237,9 @@
         'third_party/nspr/prtypes.h',
         'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
         'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+        'async_socket_io_handler.h',
+        'async_socket_io_handler_posix.cc',
+        'async_socket_io_handler_win.cc',
         'auto_reset.h',
         'event_recorder.h',
         'event_recorder_stubs.cc',
@@ -447,6 +450,7 @@
         'android/jni_string_unittest.cc',
         'android/path_utils_unittest.cc',
         'android/scoped_java_ref_unittest.cc',
+        'async_socket_io_handler_unittest.cc',
         'at_exit_unittest.cc',
         'atomicops_unittest.cc',
         'base64_unittest.cc',
@@ -834,6 +838,7 @@
         'base_i18n',
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
+        '../third_party/libxml/libxml.gyp:libxml',
         'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
       ],
       'export_dependent_settings': [
@@ -864,6 +869,8 @@
         'test/expectations/expectation.h',
         'test/expectations/parser.cc',
         'test/expectations/parser.h',
+        'test/gtest_xml_util.cc',
+        'test/gtest_xml_util.h',
         'test/mock_chrome_application_mac.h',
         'test/mock_chrome_application_mac.mm',
         'test/mock_devices_changed_observer.cc',
@@ -927,6 +934,9 @@
         'test/thread_test_helper.h',
         'test/trace_event_analyzer.cc',
         'test/trace_event_analyzer.h',
+        'test/unit_test_launcher_ios.cc',
+        'test/unit_test_launcher.cc',
+        'test/unit_test_launcher.h',
         'test/values_test_util.cc',
         'test/values_test_util.h',
       ],
@@ -937,6 +947,10 @@
             # by file name rules).
             ['include', '^test/test_file_util_mac\\.cc$'],
           ],
+          'sources!': [
+            # iOS uses its own unit test launcher.
+            'test/unit_test_launcher.cc',
+          ],
         }],
       ],  # target_conditions
     },
diff --git a/base/base.gypi b/base/base.gypi
index 6d82ee3..e22aa2e 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -427,6 +427,7 @@
           'process/process_iterator_win.cc',
           'process/process_linux.cc',
           'process/process_metrics.h',
+          'process/process_metrics.cc',
           'process/process_metrics_freebsd.cc',
           'process/process_metrics_ios.cc',
           'process/process_metrics_linux.cc',
diff --git a/base/base.target.darwin-arm.mk b/base/base.target.darwin-arm.mk
index 27dc2e8..3ecb816 100644
--- a/base/base.target.darwin-arm.mk
+++ b/base/base.target.darwin-arm.mk
@@ -26,6 +26,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	base/async_socket_io_handler_posix.cc \
 	base/event_recorder_stubs.cc \
 	base/linux_util.cc \
 	base/md5.cc \
@@ -157,6 +158,7 @@
 	base/process/process_handle_posix.cc \
 	base/process/process_iterator.cc \
 	base/process/process_iterator_linux.cc \
+	base/process/process_metrics.cc \
 	base/process/process_metrics_linux.cc \
 	base/process/process_metrics_posix.cc \
 	base/process/process_posix.cc \
diff --git a/base/base.target.darwin-mips.mk b/base/base.target.darwin-mips.mk
index acca7ec..bfa2447 100644
--- a/base/base.target.darwin-mips.mk
+++ b/base/base.target.darwin-mips.mk
@@ -26,6 +26,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	base/async_socket_io_handler_posix.cc \
 	base/event_recorder_stubs.cc \
 	base/linux_util.cc \
 	base/md5.cc \
@@ -157,6 +158,7 @@
 	base/process/process_handle_posix.cc \
 	base/process/process_iterator.cc \
 	base/process/process_iterator_linux.cc \
+	base/process/process_metrics.cc \
 	base/process/process_metrics_linux.cc \
 	base/process/process_metrics_posix.cc \
 	base/process/process_posix.cc \
diff --git a/base/base.target.darwin-x86.mk b/base/base.target.darwin-x86.mk
index 293ec02..3d8c404 100644
--- a/base/base.target.darwin-x86.mk
+++ b/base/base.target.darwin-x86.mk
@@ -26,6 +26,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	base/async_socket_io_handler_posix.cc \
 	base/event_recorder_stubs.cc \
 	base/linux_util.cc \
 	base/md5.cc \
@@ -158,6 +159,7 @@
 	base/process/process_handle_posix.cc \
 	base/process/process_iterator.cc \
 	base/process/process_iterator_linux.cc \
+	base/process/process_metrics.cc \
 	base/process/process_metrics_linux.cc \
 	base/process/process_metrics_posix.cc \
 	base/process/process_posix.cc \
diff --git a/base/base.target.linux-arm.mk b/base/base.target.linux-arm.mk
index 27dc2e8..3ecb816 100644
--- a/base/base.target.linux-arm.mk
+++ b/base/base.target.linux-arm.mk
@@ -26,6 +26,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	base/async_socket_io_handler_posix.cc \
 	base/event_recorder_stubs.cc \
 	base/linux_util.cc \
 	base/md5.cc \
@@ -157,6 +158,7 @@
 	base/process/process_handle_posix.cc \
 	base/process/process_iterator.cc \
 	base/process/process_iterator_linux.cc \
+	base/process/process_metrics.cc \
 	base/process/process_metrics_linux.cc \
 	base/process/process_metrics_posix.cc \
 	base/process/process_posix.cc \
diff --git a/base/base.target.linux-mips.mk b/base/base.target.linux-mips.mk
index acca7ec..bfa2447 100644
--- a/base/base.target.linux-mips.mk
+++ b/base/base.target.linux-mips.mk
@@ -26,6 +26,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	base/async_socket_io_handler_posix.cc \
 	base/event_recorder_stubs.cc \
 	base/linux_util.cc \
 	base/md5.cc \
@@ -157,6 +158,7 @@
 	base/process/process_handle_posix.cc \
 	base/process/process_iterator.cc \
 	base/process/process_iterator_linux.cc \
+	base/process/process_metrics.cc \
 	base/process/process_metrics_linux.cc \
 	base/process/process_metrics_posix.cc \
 	base/process/process_posix.cc \
diff --git a/base/base.target.linux-x86.mk b/base/base.target.linux-x86.mk
index 293ec02..3d8c404 100644
--- a/base/base.target.linux-x86.mk
+++ b/base/base.target.linux-x86.mk
@@ -26,6 +26,7 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	base/async_socket_io_handler_posix.cc \
 	base/event_recorder_stubs.cc \
 	base/linux_util.cc \
 	base/md5.cc \
@@ -158,6 +159,7 @@
 	base/process/process_handle_posix.cc \
 	base/process/process_iterator.cc \
 	base/process/process_iterator_linux.cc \
+	base/process/process_metrics.cc \
 	base/process/process_metrics_linux.cc \
 	base/process/process_metrics_posix.cc \
 	base/process/process_posix.cc \
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
index 852997b..0b140dd 100644
--- a/base/base_unittests.isolate
+++ b/base/base_unittests.isolate
@@ -29,10 +29,11 @@
       'variables': {
         'isolate_dependency_tracked': [
           '../testing/test_env.py',
-          '../tools/swarm_client/run_isolated.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
         ],
+        'isolate_dependency_untracked': [
+          '../tools/swarm_client/',
+        ],
       },
     }],
     ['OS=="mac" or OS=="win"', {
diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h
index d6ffa91..376d011 100644
--- a/base/debug/crash_logging.h
+++ b/base/debug/crash_logging.h
@@ -23,7 +23,8 @@
 
 class StackTrace;
 
-// Set or clear a specific key-value pair from the crash metadata.
+// Set or clear a specific key-value pair from the crash metadata. Keys and
+// values are terminated at the null byte.
 BASE_EXPORT void SetCrashKeyValue(const base::StringPiece& key,
                                   const base::StringPiece& value);
 BASE_EXPORT void ClearCrashKey(const base::StringPiece& key);
@@ -75,6 +76,8 @@
 // Returns the correspnding crash key object or NULL for a given key.
 BASE_EXPORT const CrashKey* LookupCrashKey(const base::StringPiece& key);
 
+// In the platform crash reporting implementation, these functions set and
+// clear the NUL-termianted key-value pairs.
 typedef void (*SetCrashKeyValueFuncT)(const base::StringPiece&,
                                       const base::StringPiece&);
 typedef void (*ClearCrashKeyValueFuncT)(const base::StringPiece&);
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index cc22424..2f63f91 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -50,7 +50,8 @@
 
 // Controls the number of trace events we will buffer in-memory
 // before throwing them away.
-const size_t kTraceEventBufferSize = 500000;
+const size_t kTraceEventVectorBufferSize = 250000;
+const size_t kTraceEventRingBufferSize = kTraceEventVectorBufferSize / 4;
 const size_t kTraceEventBatchSize = 1000;
 const size_t kTraceEventInitialBufferSize = 1024;
 
@@ -88,13 +89,6 @@
 const char kRecordContinuously[] = "record-continuously";
 const char kEnableSampling[] = "enable-sampling";
 
-size_t NextIndex(size_t index) {
-  index++;
-  if (index >= kTraceEventBufferSize)
-    index = 0;
-  return index;
-}
-
 }  // namespace
 
 class TraceBufferRingBuffer : public TraceBuffer {
@@ -160,7 +154,18 @@
     return logged_events_.size();
   }
 
+  virtual size_t Capacity() const OVERRIDE {
+    return kTraceEventRingBufferSize;
+  }
+
  private:
+  static size_t NextIndex(size_t index) {
+    index++;
+    if (index >= kTraceEventRingBufferSize)
+      index = 0;
+    return index;
+  }
+
   size_t unused_event_index_;
   size_t oldest_event_index_;
   std::vector<TraceEvent> logged_events_;
@@ -196,7 +201,7 @@
   }
 
   virtual bool IsFull() const OVERRIDE {
-    return Size() >= kTraceEventBufferSize;
+    return Size() >= kTraceEventVectorBufferSize;
   }
 
   virtual size_t CountEnabledByName(
@@ -222,6 +227,10 @@
     return logged_events_.size();
   }
 
+  virtual size_t Capacity() const OVERRIDE {
+    return kTraceEventVectorBufferSize;
+  }
+
  private:
   size_t current_iteration_index_;
   std::vector<TraceEvent> logged_events_;
@@ -251,6 +260,9 @@
 
   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 const TraceEvent& GetEventAt(size_t index) const OVERRIDE {
     NOTREACHED();
     return *static_cast<TraceEvent*>(NULL);
@@ -297,6 +309,7 @@
 TraceEvent::TraceEvent(
     int thread_id,
     TimeTicks timestamp,
+    TimeTicks thread_timestamp,
     char phase,
     const unsigned char* category_group_enabled,
     const char* name,
@@ -308,12 +321,14 @@
     scoped_ptr<ConvertableToTraceFormat> convertable_values[],
     unsigned char flags)
     : timestamp_(timestamp),
+      thread_timestamp_(thread_timestamp),
       id_(id),
       category_group_enabled_(category_group_enabled),
       name_(name),
       thread_id_(thread_id),
       phase_(phase),
       flags_(flags) {
+
   // Clamp num_args since it may have been set by a third_party library.
   num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
   int i = 0;
@@ -379,6 +394,7 @@
 
 TraceEvent::TraceEvent(const TraceEvent& other)
     : timestamp_(other.timestamp_),
+      thread_timestamp_(other.thread_timestamp_),
       id_(other.id_),
       category_group_enabled_(other.category_group_enabled_),
       name_(other.name_),
@@ -406,6 +422,7 @@
     return *this;
 
   timestamp_ = other.timestamp_;
+  thread_timestamp_ = other.thread_timestamp_;
   id_ = other.id_;
   category_group_enabled_ = other.category_group_enabled_;
   name_ = other.name_;
@@ -507,6 +524,12 @@
   }
   *out += "}";
 
+  // Output tts if thread_timestamp is valid.
+  if (!thread_timestamp_.is_null()) {
+    int64 thread_time_int64 = thread_timestamp_.ToInternalValue();
+    StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
+  }
+
   // If id_ is set, print it out as a hex string so we don't loose any
   // bits (it might be a 64-bit pointer).
   if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
@@ -1088,7 +1111,8 @@
 }
 
 float TraceLog::GetBufferPercentFull() const {
-  return (float)((double)logged_events_->Size()/(double)kTraceEventBufferSize);
+  return static_cast<float>(static_cast<double>(logged_events_->Size()) /
+                            logged_events_->Capacity());
 }
 
 void TraceLog::SetNotificationCallback(
@@ -1187,6 +1211,9 @@
     return;
 
   TimeTicks now = timestamp - time_offset_;
+  base::TimeTicks thread_now;
+  if (base::TimeTicks::IsThreadNowSupported())
+    thread_now = base::TimeTicks::ThreadNow();
   EventCallback event_callback_copy;
 
   NotificationHelper notifier(this);
@@ -1227,7 +1254,7 @@
   }
 
   TraceEvent trace_event(thread_id,
-      now, phase, category_group_enabled, name, id,
+      now, thread_now, phase, category_group_enabled, name, id,
       num_args, arg_names, arg_types, arg_values,
       convertable_values, flags);
 
@@ -1357,7 +1384,7 @@
   trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
   logged_events->AddEvent(TraceEvent(
       thread_id,
-      TimeTicks(), TRACE_EVENT_PHASE_METADATA,
+      TimeTicks(), TimeTicks(), TRACE_EVENT_PHASE_METADATA,
       &g_category_group_enabled[g_category_metadata],
       metadata_name, trace_event_internal::kNoEventId,
       num_args, &arg_name, &arg_type, &arg_value, NULL,
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index be1a104..e1bf148 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -81,6 +81,7 @@
   TraceEvent();
   TraceEvent(int thread_id,
              TimeTicks timestamp,
+             TimeTicks thread_timestamp,
              char phase,
              const unsigned char* category_group_enabled,
              const char* name,
@@ -108,6 +109,7 @@
                                 std::string* out);
 
   TimeTicks timestamp() const { return timestamp_; }
+  TimeTicks thread_timestamp() const { return thread_timestamp_; }
 
   // Exposed for unittesting:
 
@@ -124,6 +126,7 @@
  private:
   // Note: these are ordered by size (largest first) for optimal packing.
   TimeTicks timestamp_;
+  TimeTicks thread_timestamp_;
   // id_ can be used to store phase-specific data.
   unsigned long long id_;
   TraceValue arg_values_[kTraceMaxNumArgs];
@@ -150,6 +153,7 @@
   virtual size_t CountEnabledByName(const unsigned char* category,
                                     const std::string& event_name) const = 0;
   virtual size_t Size() const = 0;
+  virtual size_t Capacity() const = 0;
   virtual const TraceEvent& GetEventAt(size_t index) const = 0;
 };
 
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index ea295c0..b590984 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -54,7 +54,7 @@
   void OnTraceNotification(int notification) {
     if (notification & TraceLog::EVENT_WATCH_NOTIFICATION)
       ++event_watch_notification_;
-      notifications_received_ |= notification;
+    notifications_received_ |= notification;
   }
   DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values);
   DictionaryValue* FindNamePhase(const char* name, const char* phase);
diff --git a/base/file_util_unittest.cc b/base/file_util_unittest.cc
index e523920..787b6d5 100644
--- a/base/file_util_unittest.cc
+++ b/base/file_util_unittest.cc
@@ -30,6 +30,7 @@
 
 #if defined(OS_WIN)
 #include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
 #endif
 
 // This macro helps avoid wrapped lines in the test structs.
@@ -116,6 +117,36 @@
   }
   return true;
 }
+
+// Manages a reparse point for a test.
+class ReparsePoint {
+ public:
+  // Creates a reparse point from |source| (an empty directory) to |target|.
+  ReparsePoint(const FilePath& source, const FilePath& target) {
+    dir_.Set(
+      ::CreateFile(source.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+    created_ = dir_.IsValid() && SetReparsePoint(dir_, target);
+  }
+
+  ~ReparsePoint() {
+    if (created_)
+      DeleteReparsePoint(dir_);
+  }
+
+  bool IsValid() { return created_; }
+
+ private:
+  base::win::ScopedHandle dir_;
+  bool created_;
+  DISALLOW_COPY_AND_ASSIGN(ReparsePoint);
+};
+
 #endif
 
 #if defined(OS_POSIX)
@@ -431,86 +462,61 @@
 
   FilePath to_sub_a = base_b.Append(FPL("to_sub_a"));
   ASSERT_TRUE(file_util::CreateDirectory(to_sub_a));
-  base::win::ScopedHandle reparse_to_sub_a(
-      ::CreateFile(to_sub_a.value().c_str(),
-                   FILE_ALL_ACCESS,
-                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                   NULL,
-                   OPEN_EXISTING,
-                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
-                   NULL));
-  ASSERT_TRUE(reparse_to_sub_a.IsValid());
-  ASSERT_TRUE(SetReparsePoint(reparse_to_sub_a, sub_a));
-
-  FilePath to_base_b = base_b.Append(FPL("to_base_b"));
-  ASSERT_TRUE(file_util::CreateDirectory(to_base_b));
-  base::win::ScopedHandle reparse_to_base_b(
-      ::CreateFile(to_base_b.value().c_str(),
-                   FILE_ALL_ACCESS,
-                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                   NULL,
-                   OPEN_EXISTING,
-                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
-                   NULL));
-  ASSERT_TRUE(reparse_to_base_b.IsValid());
-  ASSERT_TRUE(SetReparsePoint(reparse_to_base_b, base_b));
-
-  FilePath to_sub_long = base_b.Append(FPL("to_sub_long"));
-  ASSERT_TRUE(file_util::CreateDirectory(to_sub_long));
-  base::win::ScopedHandle reparse_to_sub_long(
-      ::CreateFile(to_sub_long.value().c_str(),
-                   FILE_ALL_ACCESS,
-                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
-                   NULL,
-                   OPEN_EXISTING,
-                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
-                   NULL));
-  ASSERT_TRUE(reparse_to_sub_long.IsValid());
-  ASSERT_TRUE(SetReparsePoint(reparse_to_sub_long, sub_long));
-
-  // Normalize a junction free path: base_a\sub_a\file.txt .
   FilePath normalized_path;
-  ASSERT_TRUE(file_util::NormalizeFilePath(file_txt, &normalized_path));
-  ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+  {
+    ReparsePoint reparse_to_sub_a(to_sub_a, sub_a);
+    ASSERT_TRUE(reparse_to_sub_a.IsValid());
 
-  // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude
-  // the junction to_sub_a.
-  ASSERT_TRUE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
-                                           &normalized_path));
-  ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+    FilePath to_base_b = base_b.Append(FPL("to_base_b"));
+    ASSERT_TRUE(file_util::CreateDirectory(to_base_b));
+    ReparsePoint reparse_to_base_b(to_base_b, base_b);
+    ASSERT_TRUE(reparse_to_base_b.IsValid());
 
-  // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be
-  // normalized to exclude junctions to_base_b and to_sub_a .
-  ASSERT_TRUE(file_util::NormalizeFilePath(base_b.Append(FPL("to_base_b"))
-                                                 .Append(FPL("to_base_b"))
-                                                 .Append(FPL("to_sub_a"))
-                                                 .Append(FPL("file.txt")),
-                                           &normalized_path));
-  ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+    FilePath to_sub_long = base_b.Append(FPL("to_sub_long"));
+    ASSERT_TRUE(file_util::CreateDirectory(to_sub_long));
+    ReparsePoint reparse_to_sub_long(to_sub_long, sub_long);
+    ASSERT_TRUE(reparse_to_sub_long.IsValid());
 
-  // A long enough path will cause NormalizeFilePath() to fail.  Make a long
-  // path using to_base_b many times, and check that paths long enough to fail
-  // do not cause a crash.
-  FilePath long_path = base_b;
-  const int kLengthLimit = MAX_PATH + 200;
-  while (long_path.value().length() <= kLengthLimit) {
-    long_path = long_path.Append(FPL("to_base_b"));
+    // Normalize a junction free path: base_a\sub_a\file.txt .
+    ASSERT_TRUE(file_util::NormalizeFilePath(file_txt, &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude
+    // the junction to_sub_a.
+    ASSERT_TRUE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
+                                             &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be
+    // normalized to exclude junctions to_base_b and to_sub_a .
+    ASSERT_TRUE(file_util::NormalizeFilePath(base_b.Append(FPL("to_base_b"))
+                                                   .Append(FPL("to_base_b"))
+                                                   .Append(FPL("to_sub_a"))
+                                                   .Append(FPL("file.txt")),
+                                             &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // A long enough path will cause NormalizeFilePath() to fail.  Make a long
+    // path using to_base_b many times, and check that paths long enough to fail
+    // do not cause a crash.
+    FilePath long_path = base_b;
+    const int kLengthLimit = MAX_PATH + 200;
+    while (long_path.value().length() <= kLengthLimit) {
+      long_path = long_path.Append(FPL("to_base_b"));
+    }
+    long_path = long_path.Append(FPL("to_sub_a"))
+                         .Append(FPL("file.txt"));
+
+    ASSERT_FALSE(file_util::NormalizeFilePath(long_path, &normalized_path));
+
+    // Normalizing the junction to deep.txt should fail, because the expanded
+    // path to deep.txt is longer than MAX_PATH.
+    ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_long.Append(deep_txt),
+                                              &normalized_path));
+
+    // Delete the reparse points, and see that NormalizeFilePath() fails
+    // to traverse them.
   }
-  long_path = long_path.Append(FPL("to_sub_a"))
-                       .Append(FPL("file.txt"));
-
-  ASSERT_FALSE(file_util::NormalizeFilePath(long_path, &normalized_path));
-
-  // Normalizing the junction to deep.txt should fail, because the expanded
-  // path to deep.txt is longer than MAX_PATH.
-  ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_long.Append(deep_txt),
-                                            &normalized_path));
-
-  // Delete the reparse points, and see that NormalizeFilePath() fails
-  // to traverse them.
-  ASSERT_TRUE(DeleteReparsePoint(reparse_to_sub_a));
-  ASSERT_TRUE(DeleteReparsePoint(reparse_to_base_b));
-  ASSERT_TRUE(DeleteReparsePoint(reparse_to_sub_long));
 
   ASSERT_FALSE(file_util::NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
                                             &normalized_path));
@@ -1821,36 +1827,35 @@
 TEST_F(FileUtilTest, FileEnumeratorTest) {
   // Test an empty directory.
   FileEnumerator f0(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
-  EXPECT_EQ(f0.Next().value(), FILE_PATH_LITERAL(""));
-  EXPECT_EQ(f0.Next().value(), FILE_PATH_LITERAL(""));
+  EXPECT_EQ(f0.Next().value(), FPL(""));
+  EXPECT_EQ(f0.Next().value(), FPL(""));
 
   // Test an empty directory, non-recursively, including "..".
   FileEnumerator f0_dotdot(temp_dir_.path(), false,
       FILES_AND_DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT);
-  EXPECT_EQ(temp_dir_.path().Append(FILE_PATH_LITERAL("..")).value(),
+  EXPECT_EQ(temp_dir_.path().Append(FPL("..")).value(),
             f0_dotdot.Next().value());
-  EXPECT_EQ(FILE_PATH_LITERAL(""),
-            f0_dotdot.Next().value());
+  EXPECT_EQ(FPL(""), f0_dotdot.Next().value());
 
   // create the directories
-  FilePath dir1 = temp_dir_.path().Append(FILE_PATH_LITERAL("dir1"));
+  FilePath dir1 = temp_dir_.path().Append(FPL("dir1"));
   EXPECT_TRUE(file_util::CreateDirectory(dir1));
-  FilePath dir2 = temp_dir_.path().Append(FILE_PATH_LITERAL("dir2"));
+  FilePath dir2 = temp_dir_.path().Append(FPL("dir2"));
   EXPECT_TRUE(file_util::CreateDirectory(dir2));
-  FilePath dir2inner = dir2.Append(FILE_PATH_LITERAL("inner"));
+  FilePath dir2inner = dir2.Append(FPL("inner"));
   EXPECT_TRUE(file_util::CreateDirectory(dir2inner));
 
   // create the files
-  FilePath dir2file = dir2.Append(FILE_PATH_LITERAL("dir2file.txt"));
+  FilePath dir2file = dir2.Append(FPL("dir2file.txt"));
   CreateTextFile(dir2file, std::wstring());
-  FilePath dir2innerfile = dir2inner.Append(FILE_PATH_LITERAL("innerfile.txt"));
+  FilePath dir2innerfile = dir2inner.Append(FPL("innerfile.txt"));
   CreateTextFile(dir2innerfile, std::wstring());
-  FilePath file1 = temp_dir_.path().Append(FILE_PATH_LITERAL("file1.txt"));
+  FilePath file1 = temp_dir_.path().Append(FPL("file1.txt"));
   CreateTextFile(file1, std::wstring());
   FilePath file2_rel = dir2.Append(FilePath::kParentDirectory)
-      .Append(FILE_PATH_LITERAL("file2.txt"));
+      .Append(FPL("file2.txt"));
   CreateTextFile(file2_rel, std::wstring());
-  FilePath file2_abs = temp_dir_.path().Append(FILE_PATH_LITERAL("file2.txt"));
+  FilePath file2_abs = temp_dir_.path().Append(FPL("file2.txt"));
 
   // Only enumerate files.
   FileEnumerator f1(temp_dir_.path(), true, FileEnumerator::FILES);
@@ -1884,8 +1889,7 @@
   FindResultCollector c2_dotdot(f2_dotdot);
   EXPECT_TRUE(c2_dotdot.HasFile(dir1));
   EXPECT_TRUE(c2_dotdot.HasFile(dir2));
-  EXPECT_TRUE(c2_dotdot.HasFile(
-      temp_dir_.path().Append(FILE_PATH_LITERAL(".."))));
+  EXPECT_TRUE(c2_dotdot.HasFile(temp_dir_.path().Append(FPL(".."))));
   EXPECT_EQ(c2_dotdot.size(), 3);
 
   // Enumerate files and directories.
@@ -1910,8 +1914,7 @@
   EXPECT_EQ(c4.size(), 4);
 
   // Enumerate with a pattern.
-  FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES,
-      FILE_PATH_LITERAL("dir*"));
+  FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES, FPL("dir*"));
   FindResultCollector c5(f5);
   EXPECT_TRUE(c5.HasFile(dir1));
   EXPECT_TRUE(c5.HasFile(dir2));
@@ -1920,10 +1923,52 @@
   EXPECT_TRUE(c5.HasFile(dir2innerfile));
   EXPECT_EQ(c5.size(), 5);
 
+#if defined(OS_WIN)
+  {
+    // Make dir1 point to dir2.
+    ReparsePoint reparse_point(dir1, dir2);
+    EXPECT_TRUE(reparse_point.IsValid());
+
+    if ((base::win::GetVersion() >= base::win::VERSION_VISTA)) {
+      // There can be a delay for the enumeration code to see the change on
+      // the file system so skip this test for XP.
+      // Enumerate the reparse point.
+      FileEnumerator f6(dir1, true, FILES_AND_DIRECTORIES);
+      FindResultCollector c6(f6);
+      FilePath inner2 = dir1.Append(FPL("inner"));
+      EXPECT_TRUE(c6.HasFile(inner2));
+      EXPECT_TRUE(c6.HasFile(inner2.Append(FPL("innerfile.txt"))));
+      EXPECT_TRUE(c6.HasFile(dir1.Append(FPL("dir2file.txt"))));
+      EXPECT_EQ(c6.size(), 3);
+    }
+
+    // No changes for non recursive operation.
+    FileEnumerator f7(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
+    FindResultCollector c7(f7);
+    EXPECT_TRUE(c7.HasFile(dir2));
+    EXPECT_TRUE(c7.HasFile(dir2));
+    EXPECT_TRUE(c7.HasFile(file1));
+    EXPECT_TRUE(c7.HasFile(file2_abs));
+    EXPECT_EQ(c7.size(), 4);
+
+    // Should not enumerate inside dir1 when using recursion.
+    FileEnumerator f8(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+    FindResultCollector c8(f8);
+    EXPECT_TRUE(c8.HasFile(dir1));
+    EXPECT_TRUE(c8.HasFile(dir2));
+    EXPECT_TRUE(c8.HasFile(file1));
+    EXPECT_TRUE(c8.HasFile(file2_abs));
+    EXPECT_TRUE(c8.HasFile(dir2file));
+    EXPECT_TRUE(c8.HasFile(dir2inner));
+    EXPECT_TRUE(c8.HasFile(dir2innerfile));
+    EXPECT_EQ(c8.size(), 7);
+  }
+#endif
+
   // Make sure the destructor closes the find handle while in the middle of a
   // query to allow TearDown to delete the directory.
-  FileEnumerator f6(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
-  EXPECT_FALSE(f6.Next().value().empty());  // Should have found something
+  FileEnumerator f9(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  EXPECT_FALSE(f9.Next().value().empty());  // Should have found something
                                             // (we don't care what).
 }
 
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
index 64c9845..e47f542 100644
--- a/base/files/file_enumerator_win.cc
+++ b/base/files/file_enumerator_win.cc
@@ -133,8 +133,10 @@
       if (recursive_) {
         // If |cur_file| is a directory, and we are doing recursive searching,
         // add it to pending_paths_ so we scan it after we finish scanning this
-        // directory.
-        pending_paths_.push(cur_file);
+        // directory. However, don't do recursion through reparse points or we
+        // may end up with an infinite cycle.
+        if (!(find_data_.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+          pending_paths_.push(cur_file);
       }
       if (file_type_ & FileEnumerator::DIRECTORIES)
         return cur_file;
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index 76016d0..3e1353b4 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -50,11 +50,10 @@
 #endif
 #endif
 
-using base::FilePath;
+namespace base {
+namespace i18n {
 
-namespace icu_util {
-
-bool Initialize() {
+bool InitializeICU() {
 #ifndef NDEBUG
   // Assert that we are not called more than once.  Even though calling this
   // function isn't harmful (ICU can handle it), being called twice probably
@@ -132,4 +131,5 @@
 #endif
 }
 
-}  // namespace icu_util
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
index f6356f1..ef5dede 100644
--- a/base/i18n/icu_util.h
+++ b/base/i18n/icu_util.h
@@ -7,12 +7,14 @@
 
 #include "base/i18n/base_i18n_export.h"
 
-namespace icu_util {
+namespace base {
+namespace i18n {
 
 // Call this function to load ICU's data tables for the current process.  This
 // function should be called before ICU is used.
-BASE_I18N_EXPORT bool Initialize();
+BASE_I18N_EXPORT bool InitializeICU();
 
-}  // namespace icu_util
+}  // namespace i18n
+}  // namespace base
 
 #endif  // BASE_I18N_ICU_UTIL_H_
diff --git a/base/i18n/icu_util_nacl_win64.cc b/base/i18n/icu_util_nacl_win64.cc
index 6e0bb6b..9ba8640 100644
--- a/base/i18n/icu_util_nacl_win64.cc
+++ b/base/i18n/icu_util_nacl_win64.cc
@@ -4,10 +4,12 @@
 
 #include "base/i18n/icu_util.h"
 
-namespace icu_util {
+namespace base {
+namespace i18n {
 
-bool Initialize() {
+BASE_I18N_EXPORT bool InitializeICU() {
   return true;
 }
 
-}  // namespace icu_util
+}  // namespace i18n
+}  // namespace base
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 826c757..92039e2 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -539,7 +539,7 @@
 
 uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) {
   return (static_cast<uint64>(task.sequence_num) << 32) |
-         static_cast<uint64>(reinterpret_cast<intptr_t>(this));
+         ((static_cast<uint64>(reinterpret_cast<intptr_t>(this)) << 32) >> 32);
 }
 
 void MessageLoop::ReloadWorkQueue() {
diff --git a/base/posix/file_descriptor_shuffle.h b/base/posix/file_descriptor_shuffle.h
index 6888c3e..9cd918f 100644
--- a/base/posix/file_descriptor_shuffle.h
+++ b/base/posix/file_descriptor_shuffle.h
@@ -47,7 +47,7 @@
 
 // An implementation of the InjectionDelegate interface using the file
 // descriptor table of the current process as the domain.
-class FileDescriptorTableInjection : public InjectionDelegate {
+class BASE_EXPORT FileDescriptorTableInjection : public InjectionDelegate {
   virtual bool Duplicate(int* result, int fd) OVERRIDE;
   virtual bool Move(int src, int dest) OVERRIDE;
   virtual void Close(int fd) OVERRIDE;
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
new file mode 100644
index 0000000..9ba3fb4
--- /dev/null
+++ b/base/process/process_metrics.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 "base/process/process_metrics.h"
+
+#include "base/values.h"
+
+namespace base {
+
+SystemMetrics SystemMetrics::Sample() {
+  SystemMetrics system_metrics;
+
+  system_metrics.committed_memory_ = GetSystemCommitCharge();
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  GetSystemMemoryInfo(&system_metrics.memory_info_);
+#endif
+
+  return system_metrics;
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index e329b4e..8a7fb13 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -216,12 +216,27 @@
 // Returns 0 if it can't compute the commit charge.
 BASE_EXPORT size_t GetSystemCommitCharge();
 
+#if defined(OS_POSIX)
+// Returns the maximum number of file descriptors that can be open by a process
+// at once. If the number is unavailable, a conservative best guess is returned.
+size_t GetMaxFds();
+#endif  // defined(OS_POSIX)
+
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 // Parse the data found in /proc/<pid>/stat and return the sum of the
 // CPU-related ticks.  Returns -1 on parse error.
 // Exposed for testing.
 BASE_EXPORT int ParseProcStatCPU(const std::string& input);
 
+// Get the number of threads of |process| as available in /proc/<pid>/stat.
+// This should be used with care as no synchronization with running threads is
+// done. This is mostly useful to guarantee being single-threaded.
+// Returns 0 on failure.
+BASE_EXPORT int GetNumberOfThreads(ProcessHandle process);
+
+// /proc/self/exe refers to the current executable.
+BASE_EXPORT extern const char kProcSelfExe[];
+
 // Data from /proc/meminfo about system-wide memory consumption.
 // Values are in KB.
 struct BASE_EXPORT SystemMemoryInfoKB {
@@ -241,28 +256,28 @@
   int gem_objects;
   long long gem_size;
 };
+
 // Retrieves data from /proc/meminfo about system-wide memory consumption.
 // Fills in the provided |meminfo| structure. Returns true on success.
 // Exposed for memory debugging widget.
 BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo);
 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
+// Collects and holds performance metrics for system memory and disk.
+// Provides functionality to retrieve the data on various platforms and
+// to serialize the stored data.
+class SystemMetrics {
+ public:
+  SystemMetrics() : committed_memory_(0) { }
+
+  static SystemMetrics Sample();
+
+ private:
+  size_t committed_memory_;
 #if defined(OS_LINUX) || defined(OS_ANDROID)
-// Get the number of threads of |process| as available in /proc/<pid>/stat.
-// This should be used with care as no synchronization with running threads is
-// done. This is mostly useful to guarantee being single-threaded.
-// Returns 0 on failure.
-BASE_EXPORT int GetNumberOfThreads(ProcessHandle process);
-
-// /proc/self/exe refers to the current executable.
-BASE_EXPORT extern const char kProcSelfExe[];
-#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
-
-#if defined(OS_POSIX)
-// Returns the maximum number of file descriptors that can be open by a process
-// at once. If the number is unavailable, a conservative best guess is returned.
-size_t GetMaxFds();
-#endif  // defined(OS_POSIX)
+  SystemMemoryInfoKB memory_info_;
+#endif
+};
 
 }  // namespace base
 
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
index 1c86ee4..8d1a57c 100644
--- a/base/process/process_metrics_linux.cc
+++ b/base/process/process_metrics_linux.cc
@@ -382,6 +382,13 @@
   return utime + stime;
 }
 
+const char kProcSelfExe[] = "/proc/self/exe";
+
+int GetNumberOfThreads(ProcessHandle process) {
+  return internal::ReadProcStatsAndGetFieldAsInt(process,
+                                                 internal::VM_NUMTHREADS);
+}
+
 namespace {
 
 // The format of /proc/meminfo is:
@@ -506,11 +513,4 @@
   return true;
 }
 
-const char kProcSelfExe[] = "/proc/self/exe";
-
-int GetNumberOfThreads(ProcessHandle process) {
-  return internal::ReadProcStatsAndGetFieldAsInt(process,
-                                                 internal::VM_NUMTHREADS);
-}
-
 }  // namespace base
diff --git a/base/synchronization/lock_impl_posix.cc b/base/synchronization/lock_impl_posix.cc
index f638fcd..8615876 100644
--- a/base/synchronization/lock_impl_posix.cc
+++ b/base/synchronization/lock_impl_posix.cc
@@ -5,6 +5,7 @@
 #include "base/synchronization/lock_impl.h"
 
 #include <errno.h>
+#include <string.h>
 
 #include "base/logging.h"
 
@@ -16,13 +17,13 @@
   // In debug, setup attributes for lock error checking.
   pthread_mutexattr_t mta;
   int rv = pthread_mutexattr_init(&mta);
-  DCHECK_EQ(rv, 0);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
   rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
-  DCHECK_EQ(rv, 0);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
   rv = pthread_mutex_init(&os_lock_, &mta);
-  DCHECK_EQ(rv, 0);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
   rv = pthread_mutexattr_destroy(&mta);
-  DCHECK_EQ(rv, 0);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
 #else
   // In release, go with the default lock attributes.
   pthread_mutex_init(&os_lock_, NULL);
@@ -31,23 +32,23 @@
 
 LockImpl::~LockImpl() {
   int rv = pthread_mutex_destroy(&os_lock_);
-  DCHECK_EQ(rv, 0);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
 }
 
 bool LockImpl::Try() {
   int rv = pthread_mutex_trylock(&os_lock_);
-  DCHECK(rv == 0 || rv == EBUSY);
+  DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
   return rv == 0;
 }
 
 void LockImpl::Lock() {
   int rv = pthread_mutex_lock(&os_lock_);
-  DCHECK_EQ(rv, 0);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
 }
 
 void LockImpl::Unlock() {
   int rv = pthread_mutex_unlock(&os_lock_);
-  DCHECK_EQ(rv, 0);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
 }
 
 }  // namespace internal
diff --git a/base/test/DEPS b/base/test/DEPS
new file mode 100644
index 0000000..5827c26
--- /dev/null
+++ b/base/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/libxml",
+]
diff --git a/base/test/gtest_xml_util.cc b/base/test/gtest_xml_util.cc
new file mode 100644
index 0000000..6187d9f
--- /dev/null
+++ b/base/test/gtest_xml_util.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 "base/test/gtest_xml_util.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/test/test_launcher.h"
+#include "third_party/libxml/chromium/libxml_utils.h"
+
+namespace base {
+
+bool ProcessGTestOutput(const base::FilePath& output_file,
+                        std::vector<TestResult>* results) {
+  DCHECK(results);
+
+  std::string xml_contents;
+  if (!file_util::ReadFileToString(output_file, &xml_contents))
+    return false;
+
+  XmlReader xml_reader;
+  if (!xml_reader.Load(xml_contents))
+    return false;
+
+  enum {
+    STATE_INIT,
+    STATE_TESTSUITE,
+    STATE_TESTCASE,
+    STATE_FAILURE,
+    STATE_END,
+  } state = STATE_INIT;
+
+  while (xml_reader.Read()) {
+    xml_reader.SkipToElement();
+    std::string node_name(xml_reader.NodeName());
+
+    switch (state) {
+      case STATE_INIT:
+        if (node_name == "testsuites" && !xml_reader.IsClosingElement())
+          state = STATE_TESTSUITE;
+        else
+          return false;
+        break;
+      case STATE_TESTSUITE:
+        if (node_name == "testsuites" && xml_reader.IsClosingElement())
+          state = STATE_END;
+        else if (node_name == "testsuite" && !xml_reader.IsClosingElement())
+          state = STATE_TESTCASE;
+        else
+          return false;
+        break;
+      case STATE_TESTCASE:
+        if (node_name == "testsuite" && xml_reader.IsClosingElement()) {
+          state = STATE_TESTSUITE;
+        } else if (node_name == "testcase" && !xml_reader.IsClosingElement()) {
+          std::string test_status;
+          if (!xml_reader.NodeAttribute("status", &test_status))
+            return false;
+
+          if (test_status != "run" && test_status != "notrun")
+            return false;
+          if (test_status != "run")
+            break;
+
+          TestResult result;
+          if (!xml_reader.NodeAttribute("classname", &result.test_case_name))
+            return false;
+          if (!xml_reader.NodeAttribute("name", &result.test_name))
+            return false;
+
+          std::string test_time_str;
+          if (!xml_reader.NodeAttribute("time", &test_time_str))
+            return false;
+          result.elapsed_time =
+              TimeDelta::FromMicroseconds(strtod(test_time_str.c_str(), NULL) *
+                                          Time::kMicrosecondsPerSecond);
+
+          result.success = true;
+
+          results->push_back(result);
+        } else if (node_name == "failure" && !xml_reader.IsClosingElement()) {
+          std::string failure_message;
+          if (!xml_reader.NodeAttribute("message", &failure_message))
+            return false;
+
+          DCHECK(!results->empty());
+          results->at(results->size() - 1).success = false;
+
+          state = STATE_FAILURE;
+        } else if (node_name == "testcase" && xml_reader.IsClosingElement()) {
+          // Deliberately empty.
+        } else {
+          return false;
+        }
+        break;
+      case STATE_FAILURE:
+        if (node_name == "failure" && xml_reader.IsClosingElement())
+          state = STATE_TESTCASE;
+        else
+          return false;
+        break;
+      case STATE_END:
+        // If we are here and there are still XML elements, the file has wrong
+        // format.
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace base
\ No newline at end of file
diff --git a/base/test/gtest_xml_util.h b/base/test/gtest_xml_util.h
new file mode 100644
index 0000000..0aecfb1
--- /dev/null
+++ b/base/test/gtest_xml_util.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 BASE_TEST_GTEST_XML_UTIL_H_
+#define BASE_TEST_GTEST_XML_UTIL_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+
+namespace base {
+
+class FilePath;
+struct TestResult;
+
+// Produces a vector of test results based on GTest output file.
+// Returns true iff the output file exists and has been successfully parsed.
+bool ProcessGTestOutput(const base::FilePath& output_file,
+                        std::vector<TestResult>* results) WARN_UNUSED_RESULT;
+
+}  // namespace base
+
+#endif  // BASE_TEST_GTEST_XML_UTIL_H_
\ No newline at end of file
diff --git a/base/test/run_all_unittests.cc b/base/test/run_all_unittests.cc
index 2c8d29c..51f504d 100644
--- a/base/test/run_all_unittests.cc
+++ b/base/test/run_all_unittests.cc
@@ -2,8 +2,31 @@
 // 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/test/test_suite.h"
+#include "base/test/unit_test_launcher.h"
+
+namespace {
+
+class NoAtExitBaseTestSuite : public base::TestSuite {
+ public:
+  NoAtExitBaseTestSuite(int argc, char** argv)
+      : base::TestSuite(argc, argv, false) {
+  }
+};
+
+int RunTestSuite(int argc, char** argv) {
+  return NoAtExitBaseTestSuite(argc, argv).Run();
+}
+
+}  // namespace
 
 int main(int argc, char** argv) {
-  return base::TestSuite(argc, argv).Run();
+#if !defined(OS_ANDROID)
+  base::AtExitManager at_exit;
+#endif
+  return base::LaunchUnitTests(argc,
+                               argv,
+                               base::Bind(&RunTestSuite, argc, argv));
 }
diff --git a/base/test/test_launcher.cc b/base/test/test_launcher.cc
index b217d63..a70570c 100644
--- a/base/test/test_launcher.cc
+++ b/base/test/test_launcher.cc
@@ -358,10 +358,6 @@
   CommandLine new_command_line(command_line.GetProgram());
   CommandLine::SwitchMap switches = command_line.GetSwitches();
 
-  // Strip out gtest_output flag because otherwise we would overwrite results
-  // of the other tests.
-  switches.erase(kGTestOutputFlag);
-
   // Strip out gtest_repeat flag - this is handled by the launcher process.
   switches.erase(kGTestRepeatFlag);
 
diff --git a/base/test/test_launcher.h b/base/test/test_launcher.h
index 9b4413d..264454f 100644
--- a/base/test/test_launcher.h
+++ b/base/test/test_launcher.h
@@ -30,6 +30,8 @@
 
 // Structure containing result of a single test.
 struct TestResult {
+  std::string GetFullName() const { return test_case_name + "." + test_name; }
+
   TestResult();
 
   // Name of the test case (before the dot, e.g. "A" for test "A.B").
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index 27c00c9..e394381 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -246,7 +246,7 @@
     logging::SetLogAssertHandler(UnitTestAssertHandler);
   }
 
-  icu_util::Initialize();
+  base::i18n::InitializeICU();
 
   CatchMaybeTests();
   ResetCommandLine();
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index 94d49a4..d070ecd 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -94,9 +94,9 @@
     else if (it.value().GetAsDouble(&double_num))
       arg_numbers[it.key()] = double_num;
     else {
-      LOG(ERROR) << "Value type of argument is not supported: " <<
+      LOG(WARNING) << "Value type of argument is not supported: " <<
           static_cast<int>(it.value().GetType());
-      return false;  // Invalid trace event JSON format.
+      continue;  // Skip non-supported arguments.
     }
   }
 
@@ -869,7 +869,7 @@
     sum_mean_offsets_squared += offset * offset;
   }
   stats->standard_deviation_us =
-      sum_mean_offsets_squared / static_cast<double>(num_deltas - 1);
+      sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
 
   return true;
 }
diff --git a/base/test/unit_test_launcher.cc b/base/test/unit_test_launcher.cc
new file mode 100644
index 0000000..ebf3d40
--- /dev/null
+++ b/base/test/unit_test_launcher.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/test/unit_test_launcher.h"
+
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/file_util.h"
+#include "base/format_macros.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/test/gtest_xml_util.h"
+#include "base/test/test_launcher.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// This constant controls how many tests are run in a single batch.
+const size_t kTestBatchLimit = 10;
+
+// Flag to enable the new launcher logic.
+// TODO(phajdan.jr): Remove it, http://crbug.com/236893 .
+const char kBraveNewTestLauncherFlag[] = "brave-new-test-launcher";
+
+// Flag to run all tests in a single process.
+const char kSingleProcessTestsFlag[] = "single-process-tests";
+
+// Returns command line for child GTest process based on the command line
+// of current process. |test_names| is a vector of test full names
+// (e.g. "A.B"), |output_file| is path to the GTest XML output file.
+CommandLine GetCommandLineForChildGTestProcess(
+    const std::vector<std::string>& test_names,
+    const base::FilePath& output_file) {
+  CommandLine new_cmd_line(CommandLine::ForCurrentProcess()->GetProgram());
+  CommandLine::SwitchMap switches =
+      CommandLine::ForCurrentProcess()->GetSwitches();
+
+  switches.erase(kGTestOutputFlag);
+  new_cmd_line.AppendSwitchPath(
+      kGTestOutputFlag,
+      base::FilePath(FILE_PATH_LITERAL("xml:") + output_file.value()));
+
+  for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
+        iter != switches.end(); ++iter) {
+    new_cmd_line.AppendSwitchNative(iter->first, iter->second);
+  }
+
+  new_cmd_line.AppendSwitchASCII(kGTestFilterFlag,
+                                  JoinString(test_names, ":"));
+  new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
+  new_cmd_line.AppendSwitch(kBraveNewTestLauncherFlag);
+
+  return new_cmd_line;
+}
+
+class UnitTestLauncherDelegate : public TestLauncherDelegate {
+ private:
+  struct TestLaunchInfo {
+    std::string GetFullName() const {
+      return test_case_name + "." + test_name;
+    }
+
+    std::string test_case_name;
+    std::string test_name;
+    TestResultCallback callback;
+  };
+
+  virtual bool ShouldRunTest(const testing::TestCase* test_case,
+                             const testing::TestInfo* test_info) OVERRIDE {
+    // There is no additional logic to disable specific tests.
+    return true;
+  }
+
+  virtual void RunTest(const testing::TestCase* test_case,
+                       const testing::TestInfo* test_info,
+                       const TestResultCallback& callback) OVERRIDE {
+    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);
+
+    // Run tests in batches no larger than the limit.
+    if (tests_.size() >= kTestBatchLimit)
+      RunRemainingTests();
+  }
+
+  virtual void RunRemainingTests() OVERRIDE {
+    if (tests_.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;
+    base::ScopedTempDir temp_dir;
+    CHECK(temp_dir.CreateUniqueTempDir());
+    output_file = temp_dir.path().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());
+
+    CommandLine cmd_line(
+        GetCommandLineForChildGTestProcess(test_names, output_file));
+
+    // Adjust the timeout depending on how many tests we're running
+    // (note that e.g. the last batch of tests will be smaller).
+    // TODO(phajdan.jr): Consider an adaptive timeout, which can change
+    // depending on how many tests ran and how many remain.
+    // Note: do NOT parse child's stdout to do that, it's known to be
+    // unreliable (e.g. buffering issues can mix up the output).
+    base::TimeDelta timeout =
+        test_names.size() * TestTimeouts::action_timeout();
+
+    // TODO(phajdan.jr): Distinguish between test failures and crashes.
+    bool was_timeout = false;
+    int exit_code = LaunchChildGTestProcess(cmd_line,
+                                            std::string(),
+                                            timeout,
+                                            &was_timeout);
+
+    ProcessTestResults(output_file, exit_code);
+
+    tests_.clear();
+  }
+
+  void ProcessTestResults(const base::FilePath& output_file, int exit_code) {
+    std::vector<TestResult> test_results;
+    bool have_test_results = ProcessGTestOutput(output_file, &test_results);
+
+    if (have_test_results) {
+      // TODO(phajdan.jr): Check for duplicates and mismatches between
+      // the results we got from XML file and tests we intended to run.
+      std::map<std::string, bool> results_map;
+      for (size_t i = 0; i < test_results.size(); i++)
+        results_map[test_results[i].GetFullName()] = test_results[i].success;
+
+      for (size_t i = 0; i < tests_.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.success = results_map[tests_[i].GetFullName()];
+        tests_[i].callback.Run(test_result);
+      }
+
+      // TODO(phajdan.jr): Handle the case where the exit code is non-zero
+      // but results file indicates that all tests passed (e.g. crash during
+      // shutdown).
+    } else {
+      // We do not have reliable details about test results (parsing test
+      // stdout is known to be unreliable), apply the executable exit code
+      // 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++) {
+        TestResult test_result;
+        test_result.test_case_name = tests_[i].test_case_name;
+        test_result.test_name = tests_[i].test_name;
+        test_result.success = (exit_code == 0);
+        tests_[i].callback.Run(test_result);
+      }
+    }
+  }
+
+  std::vector<TestLaunchInfo> tests_;
+};
+
+}  // namespace
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CommandLine::Init(argc, argv);
+  if (CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
+      !CommandLine::ForCurrentProcess()->HasSwitch(kBraveNewTestLauncherFlag)) {
+    return run_test_suite.Run();
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  fprintf(stdout,
+      "Starting tests...\n"
+      "IMPORTANT DEBUGGING NOTE: batches of tests are run inside their own \n"
+      "process. For debugging a test inside a debugger, use the\n"
+      "--gtest_filter=<your_test_name> flag along with \n"
+      "--single-process-tests.\n");
+  fflush(stdout);
+
+  testing::InitGoogleTest(&argc, argv);
+  TestTimeouts::Initialize();
+
+  base::UnitTestLauncherDelegate delegate;
+  int exit_code = base::LaunchTests(&delegate, argc, argv);
+
+  fprintf(stdout,
+          "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+
+  return exit_code;
+}
+
+}  // namespace base
\ No newline at end of file
diff --git a/base/test/unit_test_launcher.h b/base/test/unit_test_launcher.h
new file mode 100644
index 0000000..ceac298
--- /dev/null
+++ b/base/test/unit_test_launcher.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 BASE_TEST_UNIT_TEST_LAUNCHER_H_
+#define BASE_TEST_UNIT_TEST_LAUNCHER_H_
+
+#include "base/callback.h"
+
+namespace base {
+
+// Callback that runs a test suite and returns exit code.
+typedef base::Callback<int(void)> RunTestSuiteCallback;
+
+// Launches unit tests in given test suite. Returns exit code.
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite);
+
+}   // namespace base
+
+#endif  // BASE_TEST_UNIT_TEST_LAUNCHER_H_
\ No newline at end of file
diff --git a/base/test/unit_test_launcher_ios.cc b/base/test/unit_test_launcher_ios.cc
new file mode 100644
index 0000000..9709a70
--- /dev/null
+++ b/base/test/unit_test_launcher_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/test/unit_test_launcher.h"
+
+namespace base {
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  // Stub implementation - iOS doesn't support features we need for
+  // the full test launcher (e.g. process_util).
+  return run_test_suite.Run();
+}
+
+}  // namespace base
\ No newline at end of file
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index 00f303d..aca4ddb 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -173,14 +173,16 @@
 void Thread::ThreadMain() {
   {
     // The message loop for this thread.
-    MessageLoop message_loop(startup_data_->options.message_loop_type);
+    // Allocated on the heap to centralize any leak reports at this line.
+    scoped_ptr<MessageLoop> message_loop(
+        new MessageLoop(startup_data_->options.message_loop_type));
 
     // Complete the initialization of our Thread object.
     thread_id_ = PlatformThread::CurrentId();
     PlatformThread::SetName(name_.c_str());
     ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
-    message_loop.set_thread_name(name_);
-    message_loop_ = &message_loop;
+    message_loop->set_thread_name(name_);
+    message_loop_ = message_loop.get();
 
 #if defined(OS_WIN)
     scoped_ptr<win::ScopedCOMInitializer> com_initializer;
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index cdfff8f..11398bf 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -21,6 +21,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/win/metro.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_handle.h"
@@ -320,6 +321,30 @@
   return false;
 }
 
+typedef HWND (*MetroRootWindow) ();
+
+// As for 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.
+// TODO(shrikant): Remove detour code once GetMonitorInfo is fixed for 8.1.
+BOOL GetMonitorInfoWrapper(HMONITOR monitor, MONITORINFO* mi) {
+  BOOL ret = ::GetMonitorInfo(monitor, mi);
+#if !defined(USE_ASH)
+  if (base::win::IsMetroProcess() &&
+      base::win::GetVersion() >= base::win::VERSION_WIN8_1) {
+    static MetroRootWindow root_window = NULL;
+    if (!root_window) {
+      HMODULE metro = base::win::GetMetroModule();
+      root_window = reinterpret_cast<MetroRootWindow>(
+          ::GetProcAddress(metro, "GetRootWindow"));
+    }
+    ret = ::GetWindowRect(root_window(), &(mi->rcWork));
+  }
+#endif
+  return ret;
+}
+
 }  // namespace win
 }  // namespace base
 
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 7577ab8..a91183a 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -121,6 +121,10 @@
 // above. Returns true on success.
 BASE_EXPORT bool DismissVirtualKeyboard();
 
+// Returns monitor info after correcting rcWorkArea based on metro version.
+// see bug #247430 for more details.
+BASE_EXPORT BOOL GetMonitorInfoWrapper(HMONITOR monitor, MONITORINFO* mi);
+
 }  // namespace win
 }  // namespace base
 
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
index 9564d0b..817a2bc 100644
--- a/base/win/windows_version.cc
+++ b/base/win/windows_version.cc
@@ -51,11 +51,14 @@
         // Treat Windows Server 2008 R2 the same as Windows 7.
         version_ = VERSION_WIN7;
         break;
-      default:
-        DCHECK_EQ(version_number_.minor, 2);
+      case 2:
         // Treat Windows Server 2012 the same as Windows 8.
         version_ = VERSION_WIN8;
         break;
+      default:
+        DCHECK_EQ(version_number_.minor, 3);
+        version_ = VERSION_WIN8_1;
+        break;
     }
   } else if (version_number_.major > 6) {
     NOTREACHED();
diff --git a/base/win/windows_version.h b/base/win/windows_version.h
index d466dad..718ba35 100644
--- a/base/win/windows_version.h
+++ b/base/win/windows_version.h
@@ -26,6 +26,7 @@
   VERSION_VISTA,       // Also includes Windows Server 2008.
   VERSION_WIN7,        // Also includes Windows Server 2008 R2.
   VERSION_WIN8,        // Also includes Windows Server 2012.
+  VERSION_WIN8_1,      // Code named Windows Blue
   VERSION_WIN_LAST,    // Indicates error condition.
 };
 
diff --git a/build/all.gyp b/build/all.gyp
index d90b5a5..e81c9c8 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -342,6 +342,14 @@
             '../chrome/chrome.gyp:performance_browser_tests',
             '../chrome/chrome.gyp:performance_ui_tests',
             '../chrome/chrome.gyp:sync_performance_tests',
+            '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
+          ],
+          'conditions': [
+            ['OS!="ios" and OS!="win"', {
+              'dependencies': [
+                '../breakpad/breakpad.gyp:minidump_stackwalk',
+              ],
+            }],
           ],
         }, # target_name: chromium_builder_perf
         {
@@ -466,8 +474,8 @@
 
             # We refer to content_shell directly rather than all_webkit
             # because we don't want the _unittests binaries.
-            '../content/content.gyp:content_browsertests',  
-            '../content/content.gyp:content_shell',  
+            '../content/content.gyp:content_browsertests',
+            '../content/content.gyp:content_shell',
 
             '../net/net.gyp:dns_fuzz_stub',
          ],
@@ -514,6 +522,7 @@
             '../sync/sync.gyp:sync_unit_tests',
             '../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',
             '../url/url.gyp:url_unittests',
             '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests',
@@ -545,6 +554,7 @@
             '../sync/sync.gyp:sync_unit_tests',
             '../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',
             '../url/url.gyp:url_unittests',
             '../webkit/renderer/compositor_bindings/compositor_bindings_tests.gyp:webkit_compositor_bindings_unittests',
@@ -613,6 +623,7 @@
           'dependencies': [
             '../cc/cc_tests.gyp:cc_unittests',
             '../chrome/chrome.gyp:browser_tests',
+            '../chrome/chrome.gyp:gcapi_test',
             '../chrome/chrome.gyp:installer_util_unittests',
             '../chrome/chrome.gyp:interactive_ui_tests',
             '../chrome/chrome.gyp:mini_installer_test',
@@ -641,6 +652,7 @@
             '../sync/sync.gyp:sync_unit_tests',
             '../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/views/views.gyp:views_unittests',
             '../url/url.gyp:url_unittests',
@@ -743,7 +755,9 @@
               'type': 'none',
               'dependencies': [
                 '../chrome/chrome.gyp:crash_service',
+                '../chrome/chrome.gyp:gcapi_dll',
                 '../chrome/chrome.gyp:policy_templates',
+                '../courgette/courgette.gyp:courgette64',
                 '../chrome/installer/mini_installer.gyp:mini_installer',
                 '../courgette/courgette.gyp:courgette',
                 '../cloud_print/cloud_print.gyp:cloud_print',
@@ -767,7 +781,6 @@
                   'dependencies': [
                     '../chrome/chrome.gyp:crash_service_win64',
                     '../chrome_frame/chrome_frame.gyp:npchrome_frame',
-                    '../courgette/courgette.gyp:courgette64',
                     # Omitting tests from Win64 to speed up cycle times.
                     '../chrome/chrome.gyp:automated_ui_tests',
                     '../chrome/chrome.gyp:chromedriver',
diff --git a/build/all_android.gyp b/build/all_android.gyp
index 0296580..70124e0 100644
--- a/build/all_android.gyp
+++ b/build/all_android.gyp
@@ -40,8 +40,8 @@
     {
       # The current list of tests for android.  This is temporary
       # until the full set supported.  If adding a new test here,
-      # please also add it to build/android/run_tests.py, else the
-      # test is not run.
+      # please also add it to build/android/pylib/gtest/gtest_config.py,
+      # else the test is not run.
       #
       # WARNING:
       # Do not add targets here without communicating the implications
@@ -116,6 +116,22 @@
       ],
     },
     {
+      # WebRTC Android APK tests.
+      'target_name': 'android_builder_webrtc',
+      'type': 'none',
+      'variables': {
+        # WebRTC tests are normally not built by Chromium bots.
+        'include_tests%': 0,
+      },
+      'conditions': [
+        ['"<(gtest_target_type)"=="shared_library" and include_tests==1', {
+          'dependencies': [
+            '../third_party/webrtc/build/apk_tests.gyp:*',
+          ],
+        }],
+      ],
+    },  # target_name: android_builder_webrtc
+    {
       # Experimental / in-progress targets that are expected to fail
       # but we still try to compile them on bots (turning the stage
       # orange, not red).
diff --git a/build/android/adb_profile_chrome b/build/android/adb_profile_chrome
index c4445d1..79a3d5d 100755
--- a/build/android/adb_profile_chrome
+++ b/build/android/adb_profile_chrome
@@ -22,6 +22,8 @@
   echo "                     (Default is /sdcard/Download/chrome-profile-results-*)"
   echo "  --categories|-c C  Select categories to trace with comma-delimited wildcards."
   echo "                     e.g. '*', 'cat1*,-cat1a'. Default is '*'."
+  echo "  --continuous       Using the trace buffer as a ring buffer, continuously"
+  echo "                     profile until stopped."
   echo "  --stop             Stop profiling."
   echo "  --download|-d      Download latest trace."
   echo "  --time|-t N        Profile for N seconds and download the resulting trace."
@@ -110,6 +112,7 @@
       CATEGORIES="-e categories '$2'"
       shift
       ;;
+    --continuous) CONTINUOUS="-e continuous ." ;;
     -t|--time)
       shift
       if [ -z "$1" ] ; then
@@ -131,9 +134,9 @@
   if [ -z "${FUNCTION}" ] ; then
     usage
   else
-    send_intent ${PACKAGE} ${FUNCTION} ${OUTPUT} ${CATEGORIES}
+    send_intent ${PACKAGE} ${FUNCTION} ${OUTPUT} ${CATEGORIES} ${CONTINUOUS}
   fi
 else
-  do_timed_capture ${PACKAGE} ${INTERVAL} ${CATEGORIES}
+  do_timed_capture ${PACKAGE} ${INTERVAL} ${CATEGORIES} ${CONTINUOUS}
 fi
 exit 0
diff --git a/build/android/ant/apk-package.xml b/build/android/ant/apk-package.xml
index eeb156c..69f5501 100644
--- a/build/android/ant/apk-package.xml
+++ b/build/android/ant/apk-package.xml
@@ -21,6 +21,11 @@
   <property name="out.absolute.dir" location="${out.dir}" />
 
   <property name="sdk.dir" location="${ANDROID_SDK_ROOT}"/>
+  <property name="emma.device.jar" location="${EMMA_DEVICE_JAR}" />
+
+  <condition property="emma.enabled" value="true" else="false">
+    <equals arg1="${EMMA_INSTRUMENT}" arg2="1"/>
+  </condition>
 
   <!-- jar file from where the tasks are loaded -->
   <path id="android.antlibs">
@@ -54,21 +59,43 @@
   <property name="source.dir" value="${SOURCE_DIR}" />
   <property name="source.absolute.dir" location="${source.dir}" />
 
+  <!-- Macro that enables passing a variable list of external jar files
+       to ApkBuilder. -->
+  <macrodef name="package-helper">
+    <element name="extra-jars" optional="yes" />
+    <sequential>
+      <apkbuilder
+          outfolder="${out.absolute.dir}"
+          resourcefile="${resource.package.file.name}"
+          apkfilepath="${out.packaged.file}"
+          debugpackaging="${build.is.packaging.debug}"
+          debugsigning="${build.is.signing.debug}"
+          verbose="${verbose}"
+          hascode="true"
+          previousBuildType="/"
+          buildType="${build.is.packaging.debug}/${build.is.signing.debug}">
+        <dex path="${intermediate.dex.file}"/>
+        <sourcefolder path="${source.absolute.dir}"/>
+        <nativefolder path="${native.libs.absolute.dir}" />
+        <extra-jars/>
+      </apkbuilder>
+    </sequential>
+  </macrodef>
+
+
   <!-- Packages the application. -->
   <target name="-package">
-    <apkbuilder
-        outfolder="${out.absolute.dir}"
-        resourcefile="${resource.package.file.name}"
-        apkfilepath="${out.packaged.file}"
-        debugpackaging="${build.is.packaging.debug}"
-        debugsigning="${build.is.signing.debug}"
-        verbose="${verbose}"
-        hascode="true"
-        previousBuildType="/"
-        buildType="${build.is.packaging.debug}/${build.is.signing.debug}">
-      <dex path="${intermediate.dex.file}"/>
-      <sourcefolder path="${source.absolute.dir}"/>
-      <nativefolder path="${native.libs.absolute.dir}" />
-    </apkbuilder>
+    <if condition="${emma.enabled}">
+      <then>
+        <package-helper>
+          <extra-jars>
+            <jarfile path="${emma.device.jar}" />
+          </extra-jars>
+        </package-helper>
+      </then>
+      <else>
+        <package-helper />
+      </else>
+    </if>
   </target>
 </project>
diff --git a/build/android/bb_run_sharded_steps.py b/build/android/bb_run_sharded_steps.py
index 9b36957..6124819 100755
--- a/build/android/bb_run_sharded_steps.py
+++ b/build/android/bb_run_sharded_steps.py
@@ -4,187 +4,16 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Helper script to shard build bot steps and save results to disk.
-
-Our buildbot infrastructure requires each slave to run steps serially.
-This is sub-optimal for android, where these steps can run independently on
-multiple connected devices.
-
-The buildbots will run this script multiple times per cycle:
-- First: all steps listed in -s in will be executed in parallel using all
-connected devices. Step results will be pickled to disk. Each step has a unique
-name. The result code will be ignored if the step name is listed in
---flaky_steps.
-The buildbot will treat this step as a regular step, and will not process any
-graph data.
-
-- Then, with -p STEP_NAME: at this stage, we'll simply print the file with the
-step results previously saved. The buildbot will then process the graph data
-accordingly.
-
-The JSON steps file contains a dictionary in the format:
-{
-  "step_name_foo": "script_to_execute foo",
-  "step_name_bar": "script_to_execute bar"
-}
-
-The JSON flaky steps file contains a list with step names which results should
-be ignored:
-[
-  "step_name_foo",
-  "step_name_bar"
-]
-
-Note that script_to_execute necessarily have to take at least the following
-options:
-  --device: the serial number to be passed to all adb commands.
-  --keep_test_server_ports: indicates it's being run as a shard, and shouldn't
-  reset test server port allocation.
+"""DEPRECATED!
+TODO(bulach): remove me once all other repositories reference
+'test_runner.py perf' directly.
 """
 
-
-import datetime
-import json
-import logging
-import multiprocessing
 import optparse
-import pexpect
-import pickle
 import os
-import signal
-import shutil
 import sys
-import time
 
-from pylib import android_commands
 from pylib import cmd_helper
-from pylib import constants
-from pylib import forwarder
-from pylib import ports
-
-
-_OUTPUT_DIR = os.path.join(constants.DIR_SOURCE_ROOT, 'out', 'step_results')
-
-
-def _SaveResult(result):
-  with file(os.path.join(_OUTPUT_DIR, result['name']), 'w') as f:
-    f.write(pickle.dumps(result))
-
-
-def _RunStepsPerDevice(steps):
-  results = []
-  for step in steps:
-    start_time = datetime.datetime.now()
-    print 'Starting %s: %s %s at %s' % (step['name'], step['cmd'],
-                                        start_time, step['device'])
-    output, exit_code  = pexpect.run(
-        step['cmd'], cwd=os.path.abspath(constants.DIR_SOURCE_ROOT),
-        withexitstatus=True, logfile=sys.stdout, timeout=1800,
-        env=os.environ)
-    exit_code = exit_code or 0
-    end_time = datetime.datetime.now()
-    exit_msg = '%s %s' % (exit_code,
-                          '(ignored, flaky step)' if step['is_flaky'] else '')
-    print 'Finished %s: %s %s %s at %s' % (step['name'], exit_msg, step['cmd'],
-                                           end_time, step['device'])
-    if step['is_flaky']:
-      exit_code = 0
-    result = {'name': step['name'],
-              'output': output,
-              'exit_code': exit_code,
-              'total_time': (end_time - start_time).seconds,
-              'device': step['device']}
-    _SaveResult(result)
-    results += [result]
-  return results
-
-
-def _RunShardedSteps(steps, flaky_steps, devices):
-  assert steps
-  assert devices, 'No devices connected?'
-  if os.path.exists(_OUTPUT_DIR):
-    assert '/step_results' in _OUTPUT_DIR
-    shutil.rmtree(_OUTPUT_DIR)
-  if not os.path.exists(_OUTPUT_DIR):
-    os.makedirs(_OUTPUT_DIR)
-  step_names = sorted(steps.keys())
-  all_params = []
-  num_devices = len(devices)
-  shard_size = (len(steps) + num_devices - 1) / num_devices
-  for i, device in enumerate(devices):
-    steps_per_device = []
-    for s in steps.keys()[i * shard_size:(i + 1) * shard_size]:
-      steps_per_device += [{'name': s,
-                            'device': device,
-                            'is_flaky': s in flaky_steps,
-                            'cmd': steps[s] + ' --device ' + device +
-                            ' --keep_test_server_ports'}]
-    all_params += [steps_per_device]
-  print 'Start sharding (note: output is not synchronized...)'
-  print '*' * 80
-  start_time = datetime.datetime.now()
-  pool = multiprocessing.Pool(processes=num_devices)
-  async_results = pool.map_async(_RunStepsPerDevice, all_params)
-  results_per_device = async_results.get(999999)
-  end_time = datetime.datetime.now()
-  print '*' * 80
-  print 'Finished sharding.'
-  print 'Summary'
-  total_time = 0
-  for results in results_per_device:
-    for result in results:
-      print('%s : exit_code=%d in %d secs at %s' %
-            (result['name'], result['exit_code'], result['total_time'],
-             result['device']))
-      total_time += result['total_time']
-  print 'Step time: %d secs' % ((end_time - start_time).seconds)
-  print 'Bots time: %d secs' % total_time
-  # No exit_code for the sharding step: the individual _PrintResults step
-  # will return the corresponding exit_code.
-  return 0
-
-
-def _PrintStepOutput(step_name):
-  file_name = os.path.join(_OUTPUT_DIR, step_name)
-  if not os.path.exists(file_name):
-    print 'File not found ', file_name
-    return 1
-  with file(file_name, 'r') as f:
-    result = pickle.loads(f.read())
-  print result['output']
-  return result['exit_code']
-
-
-def _PrintAllStepsOutput(steps):
-  with file(steps, 'r') as f:
-    steps = json.load(f)
-  ret = 0
-  for step_name in steps.keys():
-    ret |= _PrintStepOutput(step_name)
-  return ret
-
-
-def _KillPendingServers():
-  for retry in range(5):
-    for server in ['lighttpd', 'web-page-replay']:
-      pids = cmd_helper.GetCmdOutput(['pgrep', '-f', server])
-      pids = [pid.strip() for pid in pids.split('\n') if pid.strip()]
-      for pid in pids:
-        try:
-          logging.warning('Killing %s %s', server, pid)
-          os.kill(int(pid), signal.SIGQUIT)
-        except Exception as e:
-          logging.warning('Failed killing %s %s %s', server, pid, e)
-  # Restart the adb server with taskset to set a single CPU affinity.
-  cmd_helper.RunCmd(['adb', 'kill-server'])
-  cmd_helper.RunCmd(['taskset', '-c', '0', 'adb', 'start-server'])
-  cmd_helper.RunCmd(['taskset', '-c', '0', 'adb', 'root'])
-  i = 1
-  while not android_commands.GetAttachedDevices():
-    time.sleep(i)
-    i *= 2
-    if i > 10:
-      break
 
 
 def main(argv):
@@ -198,39 +27,15 @@
   parser.add_option('-p', '--print_results',
                     help='Only prints the results for the previously '
                          'executed step, do not run it again.')
-  parser.add_option('-P', '--print_all',
-                    help='Only prints the results for the previously '
-                         'executed steps, do not run them again.')
   options, urls = parser.parse_args(argv)
   if options.print_results:
-    return _PrintStepOutput(options.print_results)
-  if options.print_all:
-    return _PrintAllStepsOutput(options.print_all)
-
-  # At this point, we should kill everything that may have been left over from
-  # previous runs.
-  _KillPendingServers()
-
-  forwarder.Forwarder.UseMultiprocessing()
-
-  # Reset the test port allocation. It's important to do it before starting
-  # to dispatch any step.
-  if not ports.ResetTestServerPortAllocation():
-    raise Exception('Failed to reset test server port.')
-
-  # Sort the devices so that we'll try to always run a step in the same device.
-  devices = sorted(android_commands.GetAttachedDevices())
-  if not devices:
-    print 'You must attach a device'
-    return 1
-
-  with file(options.steps, 'r') as f:
-    steps = json.load(f)
-  flaky_steps = []
+    return cmd_helper.RunCmd(['build/android/test_runner.py', 'perf',
+                              '--print-step', options.print_results])
+  flaky_options = []
   if options.flaky_steps:
-    with file(options.flaky_steps, 'r') as f:
-      flaky_steps = json.load(f)
-  return _RunShardedSteps(steps, flaky_steps, devices)
+    flaky_options = ['--flaky-steps', options.flaky_steps]
+  return cmd_helper.RunCmd(['build/android/test_runner.py', 'perf', '-v',
+                            '--steps', options.steps] + flaky_options)
 
 
 if __name__ == '__main__':
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
index 32438ae..2cb431e 100755
--- a/build/android/buildbot/bb_device_steps.py
+++ b/build/android/buildbot/bb_device_steps.py
@@ -5,8 +5,10 @@
 
 import collections
 import glob
+import hashlib
 import multiprocessing
 import os
+import random
 import shutil
 import sys
 
@@ -124,7 +126,10 @@
   """Run all the steps for running chromedriver tests."""
   bb_annotations.PrintNamedStep('chromedriver_annotation')
   RunCmd(['chrome/test/chromedriver/run_buildbot_steps.py',
-          '--android-package=%s' % constants.CHROMIUM_TEST_SHELL_PACKAGE])
+          '--android-packages=%s,%s,%s' %
+           (constants.CHROMIUM_TEST_SHELL_PACKAGE,
+            constants.CHROME_STABLE_PACKAGE,
+            constants.CHROME_BETA_PACKAGE)])
 
 def InstallApk(options, test, print_step=False):
   """Install an apk to all phones.
@@ -165,8 +170,10 @@
   if options.flakiness_server:
     args.append('--flakiness-dashboard-server=%s' %
                 options.flakiness_server)
+  if options.coverage_bucket:
+    args.append('--coverage-dir=%s' % options.coverage_dir)
   if test.host_driven_root:
-    args.append('--python_test_root=%s' % test.host_driven_root)
+    args.append('--host-driven-root=%s' % test.host_driven_root)
   if test.annotation:
     args.extend(['-A', test.annotation])
   if test.exclude_annotation:
@@ -223,8 +230,7 @@
     cmd_args.extend(
         ['--additional-expectations=%s' % os.path.join(CHROME_SRC, *f)])
 
-  RunCmd(['webkit/tools/layout_tests/run_webkit_tests.py'] + cmd_args,
-         flunk_on_failure=False)
+  RunCmd(['webkit/tools/layout_tests/run_webkit_tests.py'] + cmd_args)
 
 
 def SpawnLogcatMonitor():
@@ -237,12 +243,14 @@
   RunCmd(['sleep', '5'])
 
 def ProvisionDevices(options):
-  # Restart adb to work around bugs, sleep to wait for usb discovery.
-  RunCmd(['adb', 'kill-server'])
-  RunCmd(['adb', 'start-server'])
-  RunCmd(['sleep', '1'])
-
   bb_annotations.PrintNamedStep('provision_devices')
+
+  if not bb_utils.TESTING:
+    # Restart adb to work around bugs, sleep to wait for usb discovery.
+    adb = android_commands.AndroidCommands()
+    adb.RestartAdbServer()
+    RunCmd(['sleep', '1'])
+
   if options.reboot:
     RebootDevices()
   provision_cmd = ['build/android/provision_devices.py', '-t', options.target]
@@ -293,6 +301,45 @@
   ]
 
 
+def UploadCoverageData(options, path, coverage_type):
+  """Uploads directory at |path| to Google Storage.
+
+  The directory at path should ostensibly contain HTML coverage data.
+
+  Args:
+    options: Command line options.
+    path: Path to the directory to be uploaded.
+    coverage_type: String used as the first component of the url.
+
+  Returns:
+    None.
+  """
+  revision = options.build_properties.get('got_revision')
+  if not revision:
+    revision = options.build_properties.get('revision', 'testing')
+  bot_id = options.build_properties.get('buildername', 'testing')
+  randhash = hashlib.sha1(str(random.random())).hexdigest()
+  gs_path = '%s/%s/%s/%s/%s' % (options.coverage_bucket, coverage_type,
+                                bot_id, revision, randhash)
+
+  RunCmd([bb_utils.GSUTIL_PATH, 'cp', '-R', path, 'gs://%s' % gs_path])
+  bb_annotations.PrintLink(
+      'Coverage report',
+      'https://storage.googleapis.com/%s/index.html' % gs_path)
+
+
+def GenerateJavaCoverageReport(options):
+  """Generates an HTML coverage report using EMMA and uploads it."""
+  bb_annotations.PrintNamedStep('java_coverage_report')
+
+  coverage_html = os.path.join(options.coverage_dir, 'coverage_html')
+  RunCmd(['build/android/generate_emma_html.py',
+          '--coverage-dir', options.coverage_dir,
+          '--metadata-dir', os.path.join(CHROME_SRC, 'out', options.target),
+          '--output', os.path.join(coverage_html, 'index.html')])
+  UploadCoverageData(options, coverage_html, 'java')
+
+
 def LogcatDump(options):
   # Print logcat, kill logcat monitor
   bb_annotations.PrintNamedStep('logcat_dump')
@@ -328,6 +375,9 @@
     if options.test_filter:
       bb_utils.RunSteps(options.test_filter, GetTestStepCmds(), options)
 
+    if options.coverage_bucket:
+      GenerateJavaCoverageReport(options)
+
     if options.experimental:
       RunTestSuites(options, gtest_config.EXPERIMENTAL_TEST_SUITES)
 
@@ -353,6 +403,9 @@
                     help='Install an apk by name')
   parser.add_option('--reboot', action='store_true',
                     help='Reboot devices before running tests')
+  parser.add_option('--coverage-bucket',
+                    help=('Bucket name to store coverage results. Coverage is '
+                          'only run if this is set.'))
   parser.add_option(
       '--flakiness-server',
       help='The flakiness dashboard server to which the results should be '
@@ -379,6 +432,9 @@
     return sys.exit('Unknown tests %s' % list(unknown_tests))
 
   setattr(options, 'target', options.factory_properties.get('target', 'Debug'))
+  if options.coverage_bucket:
+    setattr(options, 'coverage_dir',
+            os.path.join(CHROME_SRC, 'out', options.target, 'coverage'))
 
   MainTestWrapper(options)
 
diff --git a/build/android/buildbot/bb_host_steps.py b/build/android/buildbot/bb_host_steps.py
index a28f576..adb9ca0 100755
--- a/build/android/buildbot/bb_host_steps.py
+++ b/build/android/buildbot/bb_host_steps.py
@@ -96,7 +96,6 @@
 
 
 def BisectPerfRegression(_):
-  bb_annotations.PrintNamedStep('Bisect Perf Regression')
   RunCmd([SrcPath('tools', 'prepare-bisect-perf-regression.py'),
           '-w', os.path.join(constants.DIR_SOURCE_ROOT, os.pardir)])
   RunCmd([SrcPath('tools', 'run-bisect-perf-regression.py'),
diff --git a/build/android/buildbot/bb_run_bot.py b/build/android/buildbot/bb_run_bot.py
index 7637024..23db7ec 100755
--- a/build/android/buildbot/bb_run_bot.py
+++ b/build/android/buildbot/bb_run_bot.py
@@ -19,6 +19,8 @@
 from pylib import constants
 
 
+CHROMIUM_COVERAGE_BUCKET = 'chromium-code-coverage'
+
 _BotConfig = collections.namedtuple(
     'BotConfig', ['bot_id', 'host_obj', 'test_obj'])
 
@@ -144,12 +146,14 @@
       B('fyi-x86-builder-dbg',
         H(compile_step + std_host_tests, experimental, target_arch='x86')),
       B('fyi-builder-dbg',
-        H(std_build_steps + std_host_tests, experimental)),
+        H(std_build_steps + std_host_tests, experimental,
+          extra_gyp='emma_coverage=1')),
       B('x86-builder-dbg',
         H(compile_step + std_host_tests, target_arch='x86')),
       B('fyi-builder-rel', H(std_build_steps,  experimental)),
       B('fyi-tests', H(std_test_steps),
-        T(std_tests, ['--experimental', flakiness_server])),
+        T(std_tests, ['--experimental', flakiness_server,
+                      '--coverage-bucket', CHROMIUM_COVERAGE_BUCKET])),
       B('fyi-component-builder-tests-dbg',
         H(compile_step, extra_gyp='component=shared_library'),
         T(std_tests, ['--experimental', flakiness_server])),
@@ -161,6 +165,10 @@
       B('webkit-latest-contentshell', H(compile_step),
         T(['webkit_layout'], ['--auto-reconnect'])),
       B('builder-unit-tests', H(compile_step), T(['unit'])),
+      B('webrtc-builder',
+        H(std_build_steps,
+          extra_args=['--build-targets=android_builder_webrtc'],
+          extra_gyp='include_tests=1 enable_tracing=1')),
       B('webrtc-tests', H(std_test_steps), T(['webrtc'], [flakiness_server])),
 
       # Generic builder config (for substring match).
@@ -180,7 +188,6 @@
       ('try-tests', 'main-tests'),
       ('try-fyi-tests', 'fyi-tests'),
       ('webkit-latest-tests', 'main-tests'),
-      ('webrtc-builder', 'main-builder-rel'),
   ]
   for to_id, from_id in copy_map:
     assert to_id not in bot_map
diff --git a/build/android/buildbot/bb_utils.py b/build/android/buildbot/bb_utils.py
index f16540b..4aa9b47 100644
--- a/build/android/buildbot/bb_utils.py
+++ b/build/android/buildbot/bb_utils.py
@@ -26,6 +26,8 @@
 
 GOMA_DIR = os.environ.get('GOMA_DIR', os.path.join(BB_BUILD_DIR, 'goma'))
 
+GSUTIL_PATH = os.path.join(BB_BUILD_DIR, 'third_party', 'gsutil', 'gsutil')
+
 def CommandToString(command):
   """Returns quoted command that can be run in bash shell."""
   return ' '.join(map(pipes.quote, command))
diff --git a/build/android/dex_action.gypi b/build/android/dex_action.gypi
index ac956b6..9b640d6 100644
--- a/build/android/dex_action.gypi
+++ b/build/android/dex_action.gypi
@@ -33,6 +33,7 @@
     'input_paths': [],
     'proguard_enabled%': 'false',
     'proguard_enabled_input_path%': '',
+    'dex_no_locals%': 0,
   },
   'inputs': [
     '<(DEPTH)/build/android/gyp/util/build_utils.py',
@@ -51,6 +52,7 @@
     '--configuration-name=<(CONFIGURATION_NAME)',
     '--proguard-enabled=<(proguard_enabled)',
     '--proguard-enabled-input-path=<(proguard_enabled_input_path)',
+    '--no-locals=<(dex_no_locals)',
 
     # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
     '--ignore=>!(echo \'>(_inputs)\' | md5sum)',
diff --git a/build/android/envsetup.sh b/build/android/envsetup.sh
index f9e3e5e..cacfafc 100755
--- a/build/android/envsetup.sh
+++ b/build/android/envsetup.sh
@@ -143,6 +143,14 @@
 ANDROID_GOMA_WRAPPER=""
 if [[ -d $GOMA_DIR ]]; then
   ANDROID_GOMA_WRAPPER="$GOMA_DIR/gomacc"
+  num_cores="$(grep --count ^processor /proc/cpuinfo)"
+# Goma is IO-ish you want more threads than you have cores.
+  let goma_threads=num_cores*2
+  if [ -z "${GOMA_COMPILER_PROXY_THREADS}" -a "${goma_threads}" -gt 16 ]; then
+# The default is 16 threads, if the machine has many cores we crank it up a bit
+    GOMA_COMPILER_PROXY_THREADS="${goma_threads}"
+    export GOMA_COMPILER_PROXY_THREADS
+  fi
 fi
 export ANDROID_GOMA_WRAPPER
 
diff --git a/build/android/envsetup_functions.sh b/build/android/envsetup_functions.sh
index 9554bc9..fef07ef 100755
--- a/build/android/envsetup_functions.sh
+++ b/build/android/envsetup_functions.sh
@@ -125,6 +125,7 @@
       ;;
     "mips")
       DEFINES+=" target_arch=mipsel"
+      DEFINES+=" mips_arch_variant=mips32r1"
       ;;
     *)
       echo "TARGET_ARCH: ${TARGET_ARCH} is not supported." >& 2
@@ -218,23 +219,24 @@
 #  > make
 ################################################################################
 sdk_build_init() {
-  export ANDROID_SDK_VERSION=18
-  export ANDROID_SDK_BUILD_TOOLS_VERSION=18.0.1
 
-  # If ANDROID_NDK_ROOT is set when envsetup is run, use the ndk pointed to by
-  # the environment variable.  Otherwise, use the default ndk from the tree.
+  # Allow the caller to override a few environment variables. If any of them is
+  # unset, we default to a sane value that's known to work. This allows for
+  # experimentation with a custom SDK.
   if [[ -z "${ANDROID_NDK_ROOT}" || ! -d "${ANDROID_NDK_ROOT}" ]]; then
     export ANDROID_NDK_ROOT="${CHROME_SRC}/third_party/android_tools/ndk/"
   fi
-
-  # If ANDROID_SDK_ROOT is set when envsetup is run, and if it has the
-  # right SDK-compatible directory layout, use the sdk pointed to by the
-  # environment variable.  Otherwise, use the default sdk from the tree.
+  if [[ -z "${ANDROID_SDK_VERSION}" ]]; then
+    export ANDROID_SDK_VERSION=18
+  fi
   local sdk_suffix=platforms/android-${ANDROID_SDK_VERSION}
   if [[ -z "${ANDROID_SDK_ROOT}" || \
        ! -d "${ANDROID_SDK_ROOT}/${sdk_suffix}" ]]; then
     export ANDROID_SDK_ROOT="${CHROME_SRC}/third_party/android_tools/sdk/"
   fi
+  if [[ -z "${ANDROID_SDK_BUILD_TOOLS_VERSION}" ]]; then
+    export ANDROID_SDK_BUILD_TOOLS_VERSION=18.0.1
+  fi
 
   unset ANDROID_BUILD_TOP
 
diff --git a/build/android/findbugs_filter/findbugs_exclude.xml b/build/android/findbugs_filter/findbugs_exclude.xml
index 7b6860d..2f7bde5 100644
--- a/build/android/findbugs_filter/findbugs_exclude.xml
+++ b/build/android/findbugs_filter/findbugs_exclude.xml
@@ -21,6 +21,14 @@
   <Match>
     <Class name="~org\.chromium\.content\..*\.NativeLibraries.*?" />
   </Match>
+  <!--
+  Ignore bugs in CleanupReferenceTest.java (redundant null check)
+  TODO(joth): Group all GC related tests and filter them out, since the null
+  check is necessary to make sure the nullification is flushed to memory.
+  -->
+  <Match>
+    <Class name="~org\.chromium\.content\..*\.CleanupReferenceTest.*?" />
+  </Match>
   <!-- Ignore errors in JavaBridge due to reflection. -->
   <Match>
     <Class name="~.*\.JavaBridge.*"/>
diff --git a/build/android/generate_emma_html.py b/build/android/generate_emma_html.py
new file mode 100755
index 0000000..a226343
--- /dev/null
+++ b/build/android/generate_emma_html.py
@@ -0,0 +1,100 @@
+#!/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.
+
+"""Aggregates EMMA coverage files to produce html output."""
+
+import fnmatch
+import json
+import optparse
+import os
+import sys
+import traceback
+
+from pylib import cmd_helper
+from pylib import constants
+
+
+def _GetFilesWithExt(root_dir, ext):
+  """Gets all files with a given extension.
+
+  Args:
+    root_dir: Directory in which to search for files.
+    ext: Extension to look for (including dot)
+
+  Returns:
+    A list of absolute paths to files that match.
+  """
+  files = []
+  for root, _, filenames in os.walk(root_dir):
+    basenames = fnmatch.filter(filenames, '*.' + ext)
+    files.extend([os.path.join(root, basename)
+                  for basename in basenames])
+
+  return files
+
+
+def main(argv):
+  option_parser = optparse.OptionParser()
+  option_parser.add_option('-o', '--output', help='HTML output filename.')
+  option_parser.add_option('-c', '--coverage-dir', default=None,
+                           help=('Root of the directory in which to search for '
+                                 'coverage data (.ec) files.'))
+  option_parser.add_option('-m', '--metadata-dir', default=None,
+                           help=('Root of the directory in which to search for '
+                                 'coverage metadata (.em) files.'))
+  options, args = option_parser.parse_args()
+
+  if not (options.coverage_dir and options.metadata_dir and options.output):
+    option_parser.error('All arguments are required.')
+
+  coverage_files = _GetFilesWithExt(options.coverage_dir, 'ec')
+  metadata_files = _GetFilesWithExt(options.metadata_dir, 'em')
+  print 'Found coverage files: %s' % str(coverage_files)
+  print 'Found metadata files: %s' % str(metadata_files)
+  sources_files = []
+  final_metadata_files = []
+  err = None
+  for f in metadata_files:
+    sources_file = os.path.splitext(f)[0] + '_sources.txt'
+    # TODO(gkanwar): Remove this once old coverage.em files have been cleaned
+    # from all bots.
+    # Warn if we have old metadata files lying around that don't correspond
+    # to a *_sources.txt (these should be manually cleaned).
+    try:
+      with open(sources_file, 'r') as sf:
+        sources_files.extend(json.load(sf))
+    except IOError as e:
+      traceback.print_exc()
+      err = e
+    else:
+      final_metadata_files.append(f)
+  sources_files = [os.path.join(constants.DIR_SOURCE_ROOT, s)
+                   for s in sources_files]
+
+  input_args = []
+  for f in coverage_files + final_metadata_files:
+    input_args.append('-in')
+    input_args.append(f)
+
+  output_args = ['-Dreport.html.out.file', options.output]
+  source_args = ['-sp', ','.join(sources_files)]
+
+  exit_code = cmd_helper.RunCmd(
+      ['java', '-cp',
+       os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'lib', 'emma.jar'),
+       'emma', 'report', '-r', 'html']
+      + input_args + output_args + source_args)
+
+  if exit_code > 0:
+    return exit_code
+  elif err:
+    return constants.WARNING_EXIT_CODE
+  else:
+    return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/gyp/ant.py b/build/android/gyp/ant.py
index acf3dcc..45ed3ed 100755
--- a/build/android/gyp/ant.py
+++ b/build/android/gyp/ant.py
@@ -3,7 +3,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.
-"""An Ant wrapper that suppresses useless Ant output
+
+"""An Ant wrapper that suppresses useless Ant output.
 
 Ant build scripts output "BUILD SUCCESSFUL" and build timing at the end of
 every build. In the Android build, this just adds a lot of useless noise to the
@@ -27,4 +28,3 @@
 
 if __name__ == '__main__':
   sys.exit(main(sys.argv))
-
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
index 21e1183..f90de95 100755
--- a/build/android/gyp/dex.py
+++ b/build/android/gyp/dex.py
@@ -4,7 +4,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import fnmatch
 import optparse
 import os
 import sys
@@ -15,7 +14,11 @@
 
 def DoDex(options, paths):
   dx_binary = os.path.join(options.android_sdk_tools, 'dx')
-  dex_cmd = [dx_binary, '--dex', '--output', options.dex_path] + paths
+  # See http://crbug.com/272064 for context on --force-jumbo.
+  dex_cmd = [dx_binary, '--dex', '--force-jumbo', '--output', options.dex_path]
+  if options.no_locals != '0':
+    dex_cmd.append('--no-locals')
+  dex_cmd += paths
 
   record_path = '%s.md5.stamp' % options.dex_path
   md5_check.CallAndRecordIfStale(
@@ -33,11 +36,14 @@
                     help='Android sdk build tools directory.')
   parser.add_option('--dex-path', help='Dex output path.')
   parser.add_option('--configuration-name',
-      help='The build CONFIGURATION_NAME.')
+                    help='The build CONFIGURATION_NAME.')
   parser.add_option('--proguard-enabled',
-      help='"true" if proguard is enabled.')
+                    help='"true" if proguard is enabled.')
   parser.add_option('--proguard-enabled-input-path',
-      help='Path to dex in Release mode when proguard is enabled.')
+                    help=('Path to dex in Release mode when proguard '
+                          'is enabled.'))
+  parser.add_option('--no-locals',
+                    help='Exclude locals list from the dex file.')
   parser.add_option('--stamp', help='Path to touch on success.')
 
   # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
@@ -45,8 +51,8 @@
 
   options, paths = parser.parse_args()
 
-  if (options.proguard_enabled == "true"
-      and options.configuration_name == "Release"):
+  if (options.proguard_enabled == 'true'
+      and options.configuration_name == 'Release'):
     paths = [options.proguard_enabled_input_path]
 
   DoDex(options, paths)
@@ -57,4 +63,3 @@
 
 if __name__ == '__main__':
   sys.exit(main(sys.argv))
-
diff --git a/build/android/gyp/emma_instr.py b/build/android/gyp/emma_instr.py
new file mode 100755
index 0000000..8e69f39
--- /dev/null
+++ b/build/android/gyp/emma_instr.py
@@ -0,0 +1,188 @@
+#!/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.
+
+"""Instruments classes and jar files.
+
+This script corresponds to the 'emma_instr' action in the java build process.
+Depending on whether emma_instrument is set, the 'emma_instr' action will either
+call one of the instrument commands, or the copy command.
+
+Possible commands are:
+- instrument_jar: Accepts a jar and instruments it using emma.jar.
+- instrument_classes: Accepts a directory contains java classes and instruments
+      it using emma.jar.
+- copy: Triggered instead of an instrumentation command when we don't have EMMA
+      coverage enabled. This allows us to make this a required step without
+      necessarily instrumenting on every build.
+"""
+
+import collections
+import json
+import os
+import shutil
+import sys
+import tempfile
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from pylib.utils import command_option_parser
+
+from util import build_utils
+
+
+def _AddCommonOptions(option_parser):
+  """Adds common options to |option_parser|."""
+  option_parser.add_option('--input-path',
+                           help=('Path to input file(s). Either the classes '
+                                 'directory, or the path to a jar.'))
+  option_parser.add_option('--output-path',
+                           help=('Path to output final file(s) to. Either the '
+                                 'final classes directory, or the directory in '
+                                 'which to place the instrumented/copied jar.'))
+  option_parser.add_option('--stamp', help='Path to touch when done.')
+
+
+def _AddInstrumentOptions(option_parser):
+  """Adds options related to instrumentation to |option_parser|."""
+  _AddCommonOptions(option_parser)
+  option_parser.add_option('--coverage-file',
+                           help='File to create with coverage metadata.')
+  option_parser.add_option('--sources-file',
+                           help='File to create with the list of sources.')
+  option_parser.add_option('--sources',
+                           help='Space separated list of sources.')
+  option_parser.add_option('--src-root',
+                           help='Root of the src repository.')
+  option_parser.add_option('--emma-jar',
+                           help='Path to emma.jar.')
+
+
+def _RunCopyCommand(command, options, args, option_parser):
+  """Just copies the jar from input to output locations.
+
+  Args:
+    command: String indicating the command that was received to trigger
+        this function.
+    options: optparse options dictionary.
+    args: List of extra args from optparse.
+    option_parser: optparse.OptionParser object.
+
+  Returns:
+    An exit code.
+  """
+  if not (options.input_path and options.output_path):
+    option_parser.error('All arguments are required.')
+
+  if os.path.isdir(options.input_path):
+    shutil.rmtree(options.output_path, ignore_errors=True)
+    shutil.copytree(options.input_path, options.output_path)
+  else:
+    shutil.copy(options.input_path, options.output_path)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+def _CreateSourcesFile(sources_string, sources_file, src_root):
+  """Adds all normalized source directories to |sources_file|.
+
+  Args:
+    sources_string: String generated from gyp containing the list of sources.
+    sources_file: File into which to write the JSON list of sources.
+    src_root: Root which sources added to the file should be relative to.
+
+  Returns:
+    An exit code.
+  """
+  src_root = os.path.abspath(src_root)
+  sources = build_utils.ParseGypList(sources_string)
+  relative_sources = []
+  for s in sources:
+    abs_source = os.path.abspath(s)
+    if abs_source[:len(src_root)] != src_root:
+      print ('Error: found source directory not under repository root: %s %s'
+             % (abs_source, src_root))
+      return 1
+    rel_source = os.path.relpath(abs_source, src_root)
+
+    relative_sources.append(rel_source)
+
+  with open(sources_file, 'w') as f:
+    json.dump(relative_sources, f)
+
+
+def _RunInstrumentCommand(command, options, args, option_parser):
+  """Instruments the classes/jar files using EMMA.
+
+  Args:
+    command: 'instrument_jar' or 'instrument_classes'. This distinguishes
+        whether we copy the output from the created lib/ directory, or classes/
+        directory.
+    options: optparse options dictionary.
+    args: List of extra args from optparse.
+    option_parser: optparse.OptionParser object.
+
+  Returns:
+    An exit code.
+  """
+  if not (options.input_path and options.output_path and
+          options.coverage_file and options.sources_file and options.sources and
+          options.src_root and options.emma_jar):
+    option_parser.error('All arguments are required.')
+
+  coverage_file = os.path.join(os.path.dirname(options.output_path),
+                               options.coverage_file)
+  sources_file = os.path.join(os.path.dirname(options.output_path),
+                              options.sources_file)
+  temp_dir = tempfile.mkdtemp()
+  try:
+    # TODO(gkanwar): Add '-ix' option to filter out useless classes.
+    build_utils.CheckCallDie(['java', '-cp', options.emma_jar,
+                              'emma', 'instr',
+                              '-ip', options.input_path,
+                              '-d', temp_dir,
+                              '-out', coverage_file,
+                              '-m', 'fullcopy'], suppress_output=True)
+
+    if command == 'instrument_jar':
+      for jar in os.listdir(os.path.join(temp_dir, 'lib')):
+        shutil.copy(os.path.join(temp_dir, 'lib', jar),
+                    options.output_path)
+    else:  # 'instrument_classes'
+      if os.path.isdir(options.output_path):
+        shutil.rmtree(options.output_path, ignore_errors=True)
+      shutil.copytree(os.path.join(temp_dir, 'classes'),
+                      options.output_path)
+  finally:
+    shutil.rmtree(temp_dir)
+
+  _CreateSourcesFile(options.sources, sources_file, options.src_root)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+  return 0
+
+
+CommandFunctionTuple = collections.namedtuple(
+    'CommandFunctionTuple', ['add_options_func', 'run_command_func'])
+VALID_COMMANDS = {
+    'copy': CommandFunctionTuple(_AddCommonOptions,
+                                 _RunCopyCommand),
+    'instrument_jar': CommandFunctionTuple(_AddInstrumentOptions,
+                                           _RunInstrumentCommand),
+    'instrument_classes': CommandFunctionTuple(_AddInstrumentOptions,
+                                               _RunInstrumentCommand),
+}
+
+
+def main(argv):
+  option_parser = command_option_parser.CommandOptionParser(
+      commands_dict=VALID_COMMANDS)
+  command_option_parser.ParseAndExecute(option_parser)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
new file mode 100755
index 0000000..6268caf
--- /dev/null
+++ b/build/android/gyp/proguard.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 fnmatch
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+def DoProguard(options):
+  injars = options.input_path
+  outjars = options.output_path
+  classpath = build_utils.ParseGypList(options.classpath)
+  classpath = list(set(classpath))
+  libraryjars = ':'.join(classpath)
+  # proguard does its own dependency checking, which can be avoided by deleting
+  # the output.
+  if os.path.exists(options.output_path):
+    os.remove(options.output_path)
+  proguard_cmd = [options.proguard_path,
+                  '-injars', injars,
+                  '-outjars', outjars,
+                  '-libraryjars', libraryjars,
+                  '@' + options.proguard_config]
+  build_utils.CheckCallDie(proguard_cmd)
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('--proguard-path',
+                    help='Path to the proguard executable.')
+  parser.add_option('--input-path',
+                    help='Path to the .jar file proguard should run on.')
+  parser.add_option('--output-path', help='Path to the generated .jar file.')
+  parser.add_option('--proguard-config',
+                    help='Path to the proguard configuration file.')
+  parser.add_option('--classpath', help="Classpath for proguard.")
+  parser.add_option('--stamp', help='Path to touch on success.')
+
+  # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
+  parser.add_option('--ignore', help='Ignored.')
+
+  options, _ = parser.parse_args()
+
+  DoProguard(options)
+
+  if options.stamp:
+    build_utils.Touch(options.stamp)
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/build/android/instr_action.gypi b/build/android/instr_action.gypi
new file mode 100644
index 0000000..b4164f6
--- /dev/null
+++ b/build/android/instr_action.gypi
@@ -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.
+
+# This file is meant to be included into an action to provide a rule that
+# instruments either java class files, or jars.
+
+{
+  'variables': {
+    'instr_type%': 'jar',
+    'input_path%': '',
+    'output_path%': '',
+    'stamp_path%': '',
+    'extra_instr_args': [],
+    'emma_jar': '<(android_sdk_root)/tools/lib/emma.jar',
+    'conditions': [
+      ['emma_instrument != 0', {
+        'extra_instr_args': [
+          '--coverage-file=<(_target_name).em',
+          '--sources-file=<(_target_name)_sources.txt',
+          '--sources=<(java_in_dir)/src >(additional_src_dirs) >(generated_src_dirs)',
+          '--src-root=<(DEPTH)',
+          '--emma-jar=<(emma_jar)',
+        ],
+        'conditions': [
+          ['instr_type == "jar"', {
+            'instr_action': 'instrument_jar',
+          }, {
+            'instr_action': 'instrument_classes',
+          }]
+        ],
+      }, {
+        'instr_action': 'copy',
+        'extra_instr_args': [],
+      }]
+    ]
+  },
+  'inputs': [
+    '<(DEPTH)/build/android/gyp/emma_instr.py',
+    '<(DEPTH)/build/android/gyp/util/build_utils.py',
+    '<(DEPTH)/build/android/pylib/utils/command_option_parser.py',
+  ],
+  'action': [
+    'python', '<(DEPTH)/build/android/gyp/emma_instr.py',
+    '<(instr_action)',
+    '--input-path=<(input_path)',
+    '--output-path=<(output_path)',
+    '--stamp=<(stamp_path)',
+    '<@(extra_instr_args)',
+  ]
+}
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py
index f8c0747..c407ffd 100644
--- a/build/android/pylib/android_commands.py
+++ b/build/android/pylib/android_commands.py
@@ -459,18 +459,41 @@
 
   def RestartAdbServer(self):
     """Restart the adb server."""
-    self.KillAdbServer()
-    self.StartAdbServer()
+    ret = self.KillAdbServer()
+    if ret != 0:
+      raise errors.MsgException('KillAdbServer: %d' % ret)
+
+    ret = self.StartAdbServer()
+    if ret != 0:
+      raise errors.MsgException('StartAdbServer: %d' % ret)
 
   def KillAdbServer(self):
     """Kill adb server."""
     adb_cmd = [constants.ADB_PATH, 'kill-server']
-    return cmd_helper.RunCmd(adb_cmd)
+    ret = cmd_helper.RunCmd(adb_cmd)
+    retry = 0
+    while retry < 3:
+      ret = cmd_helper.RunCmd(['pgrep', 'adb'])
+      if ret != 0:
+        # pgrep didn't find adb, kill-server succeeded.
+        return 0
+      retry += 1
+      time.sleep(retry)
+    return ret
 
   def StartAdbServer(self):
     """Start adb server."""
-    adb_cmd = [constants.ADB_PATH, 'start-server']
-    return cmd_helper.RunCmd(adb_cmd)
+    adb_cmd = ['taskset', '-c', '0', constants.ADB_PATH, 'start-server']
+    ret = cmd_helper.RunCmd(adb_cmd)
+    retry = 0
+    while retry < 3:
+      ret = cmd_helper.RunCmd(['pgrep', 'adb'])
+      if ret == 0:
+        # pgrep fonud adb, start-server succeeded.
+        return 0
+      retry += 1
+      time.sleep(retry)
+    return ret
 
   def WaitForSystemBootCompleted(self, wait_time):
     """Waits for targeted system's boot_completed flag to be set.
@@ -612,7 +635,8 @@
     return processes_killed
 
   def _GetActivityCommand(self, package, activity, wait_for_completion, action,
-                          category, data, extras, trace_file_name, force_stop):
+                          category, data, extras, trace_file_name, force_stop,
+                          flags):
     """Creates command to start |package|'s activity on the device.
 
     Args - as for StartActivity
@@ -646,13 +670,15 @@
         cmd += ' %s %s' % (key, value)
     if trace_file_name:
       cmd += ' --start-profiler ' + trace_file_name
+    if flags:
+      cmd += ' -f %s' % flags
     return cmd
 
   def StartActivity(self, package, activity, wait_for_completion=False,
                     action='android.intent.action.VIEW',
                     category=None, data=None,
                     extras=None, trace_file_name=None,
-                    force_stop=False):
+                    force_stop=False, flags=None):
     """Starts |package|'s activity on the device.
 
     Args:
@@ -670,14 +696,14 @@
     """
     cmd = self._GetActivityCommand(package, activity, wait_for_completion,
                                    action, category, data, extras,
-                                   trace_file_name, force_stop)
+                                   trace_file_name, force_stop, flags)
     self.RunShellCommand(cmd)
 
   def StartActivityTimed(self, package, activity, wait_for_completion=False,
                          action='android.intent.action.VIEW',
                          category=None, data=None,
                          extras=None, trace_file_name=None,
-                         force_stop=False):
+                         force_stop=False, flags=None):
     """Starts |package|'s activity on the device, returning the start time
 
     Args - as for StartActivity
@@ -687,7 +713,7 @@
     """
     cmd = self._GetActivityCommand(package, activity, wait_for_completion,
                                    action, category, data, extras,
-                                   trace_file_name, force_stop)
+                                   trace_file_name, force_stop, flags)
     self.StartMonitoringLogcat()
     self.RunShellCommand('log starting activity; ' + cmd)
     activity_started_re = re.compile('.*starting activity.*')
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py
index 9173b72..bd8fefe 100644
--- a/build/android/pylib/base/base_test_runner.py
+++ b/build/android/pylib/base/base_test_runner.py
@@ -30,13 +30,11 @@
 class BaseTestRunner(object):
   """Base class for running tests on a single device."""
 
-  def __init__(self, device, tool, build_type, push_deps=True,
-               cleanup_test_files=False):
+  def __init__(self, device, tool, push_deps=True, cleanup_test_files=False):
     """
       Args:
         device: Tests will run on the device of this ID.
         tool: Name of the Valgrind tool.
-        build_type: 'Release' or 'Debug'.
         push_deps: If True, push all dependencies to the device.
         cleanup_test_files: Whether or not to cleanup test files on device.
     """
@@ -55,7 +53,6 @@
     # starting it in TestServerThread.
     self.test_server_spawner_port = 0
     self.test_server_port = 0
-    self.build_type = build_type
     self._push_deps = push_deps
     self._cleanup_test_files = cleanup_test_files
 
@@ -130,7 +127,7 @@
 
   def _ForwardPorts(self, port_pairs):
     """Forwards a port."""
-    Forwarder.Map(port_pairs, self.adb, self.build_type, self.tool)
+    Forwarder.Map(port_pairs, self.adb, constants.GetBuildType(), self.tool)
 
   def _UnmapPorts(self, port_pairs):
     """Unmap previously forwarded ports."""
@@ -194,8 +191,7 @@
           [(self.test_server_spawner_port, self.test_server_spawner_port)])
       self._spawning_server = SpawningServer(self.test_server_spawner_port,
                                              self.adb,
-                                             self.tool,
-                                             self.build_type)
+                                             self.tool)
       self._spawning_server.Start()
       server_ready, error_msg = ports.IsHttpServerConnectable(
           '127.0.0.1', self.test_server_spawner_port, path='/ping',
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
index a8363c2..31fa078 100644
--- a/build/android/pylib/base/test_dispatcher.py
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -4,16 +4,15 @@
 
 """Dispatches tests, either sharding or replicating them.
 
-To dispatch, performs the following steps:
+Performs the following steps:
 * Create a test collection factory, using the given tests
   - If sharding: test collection factory returns the same shared test collection
     to all test runners
   - If replciating: test collection factory returns a unique test collection to
     each test runner, with the same set of tests in each.
-* Get the list of devices to run on
-* Create test runners
-* Run each test runner in its own thread, pulling tests from the test collection
-  generated from the test collection factory until there are no tests left.
+* Create a test runner for each device.
+* Run each test runner in its own thread, grabbing tests from the test
+  collection until there are no tests left.
 """
 
 import logging
@@ -304,40 +303,8 @@
   threads.JoinAll(watchdog_timer.WatchdogTimer(timeout))
 
 
-
-def _GetAttachedDevices(wait_for_debugger=False, test_device=None):
-  """Get all attached devices.
-
-  If we are using a debugger, limit to only one device.
-
-  Args:
-    wait_for_debugger: True if this run will use a debugger.
-    test_device: Name of a specific device to use.
-
-  Returns:
-    A list of attached devices.
-  """
-  attached_devices = []
-
-  attached_devices = android_commands.GetAttachedDevices()
-  if test_device:
-    assert test_device in attached_devices, (
-        'Did not find device %s among attached device. Attached devices: %s'
-        % (test_device, ', '.join(attached_devices)))
-    attached_devices = [test_device]
-
-  if len(attached_devices) > 1 and wait_for_debugger:
-    logging.warning('Debugger can not be sharded, using first available device')
-    attached_devices = attached_devices[:1]
-
-  return attached_devices
-
-
-def RunTests(tests, runner_factory, wait_for_debugger, test_device,
-             shard=True,
-             build_type='Debug',
-             test_timeout=DEFAULT_TIMEOUT,
-             setup_timeout=DEFAULT_TIMEOUT,
+def RunTests(tests, runner_factory, devices, shard=True,
+             test_timeout=DEFAULT_TIMEOUT, setup_timeout=DEFAULT_TIMEOUT,
              num_retries=2):
   """Run all tests on attached devices, retrying tests that don't pass.
 
@@ -345,14 +312,12 @@
     tests: List of tests to run.
     runner_factory: Callable that takes a device and index and returns a
         TestRunner object.
-    wait_for_debugger: True if this test is using a debugger.
-    test_device: A specific device to run tests on, or None.
+    devices: List of attached devices.
     shard: True if we should shard, False if we should replicate tests.
       - Sharding tests will distribute tests across all test runners through a
         shared test collection.
       - Replicating tests will copy all tests to each test runner through a
         unique test collection for each test runner.
-    build_type: Either 'Debug' or 'Release'.
     test_timeout: Watchdog timeout in seconds for running tests.
     setup_timeout: Watchdog timeout in seconds for creating and cleaning up
         test runners.
@@ -362,7 +327,7 @@
     A tuple of (base_test_result.TestRunResults object, exit code).
   """
   if not tests:
-    logging.error('No tests to run.')
+    logging.critical('No tests to run.')
     return (base_test_result.TestRunResults(), constants.ERROR_EXIT_CODE)
 
   if shard:
@@ -379,8 +344,6 @@
     tag_results_with_device = True
     log_string = 'replicated on each device'
 
-  devices = _GetAttachedDevices(wait_for_debugger, test_device)
-
   logging.info('Will run %d tests (%s): %s', len(tests), log_string, str(tests))
   runners = _CreateRunners(runner_factory, devices, setup_timeout)
   try:
diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
index 253826c..88dfda6 100644
--- a/build/android/pylib/base/test_dispatcher_unittest.py
+++ b/build/android/pylib/base/test_dispatcher_unittest.py
@@ -167,7 +167,7 @@
   @staticmethod
   def _RunShard(runner_factory):
     return test_dispatcher.RunTests(
-        ['a', 'b', 'c'], runner_factory, False, None, shard=True)
+        ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=True)
 
   def testShard(self):
     results, exit_code = TestShard._RunShard(MockRunner)
@@ -182,7 +182,7 @@
 
   def testNoTests(self):
     results, exit_code = test_dispatcher.RunTests(
-        [], MockRunner, False, None, shard=True)
+        [], MockRunner, ['0', '1'], shard=True)
     self.assertEqual(len(results.GetAll()), 0)
     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
 
@@ -192,7 +192,7 @@
   @staticmethod
   def _RunReplicate(runner_factory):
     return test_dispatcher.RunTests(
-        ['a', 'b', 'c'], runner_factory, False, None, shard=False)
+        ['a', 'b', 'c'], runner_factory, ['0', '1'], shard=False)
 
   def testReplicate(self):
     results, exit_code = TestReplicate._RunReplicate(MockRunner)
@@ -208,7 +208,7 @@
 
   def testNoTests(self):
     results, exit_code = test_dispatcher.RunTests(
-        [], MockRunner, False, None, shard=False)
+        [], MockRunner, ['0', '1'], shard=False)
     self.assertEqual(len(results.GetAll()), 0)
     self.assertEqual(exit_code, constants.ERROR_EXIT_CODE)
 
diff --git a/build/android/pylib/chrome_test_server_spawner.py b/build/android/pylib/chrome_test_server_spawner.py
index 0ff7997..b15f291 100644
--- a/build/android/pylib/chrome_test_server_spawner.py
+++ b/build/android/pylib/chrome_test_server_spawner.py
@@ -100,7 +100,7 @@
 class TestServerThread(threading.Thread):
   """A thread to run the test server in a separate process."""
 
-  def __init__(self, ready_event, arguments, adb, tool, build_type):
+  def __init__(self, ready_event, arguments, adb, tool):
     """Initialize TestServerThread with the following argument.
 
     Args:
@@ -108,7 +108,6 @@
       arguments: dictionary of arguments to run the test server.
       adb: instance of AndroidCommands.
       tool: instance of runtime error detection tool.
-      build_type: 'Release' or 'Debug'.
     """
     threading.Thread.__init__(self)
     self.wait_event = threading.Event()
@@ -128,7 +127,6 @@
     self.pipe_in = None
     self.pipe_out = None
     self.command_line = []
-    self.build_type = build_type
 
   def _WaitToStartAndGetPortFromTestServer(self):
     """Waits for the Python test server to start and gets the port it is using.
@@ -251,7 +249,8 @@
       else:
         self.is_ready = _CheckPortStatus(self.host_port, True)
     if self.is_ready:
-      Forwarder.Map([(0, self.host_port)], self.adb, self.build_type, self.tool)
+      Forwarder.Map([(0, self.host_port)], self.adb, constants.GetBuildType(),
+                    self.tool)
       # Check whether the forwarder is ready on the device.
       self.is_ready = False
       device_port = Forwarder.DevicePortForHostPort(self.host_port)
@@ -333,8 +332,7 @@
         ready_event,
         json.loads(test_server_argument_json),
         self.server.adb,
-        self.server.tool,
-        self.server.build_type)
+        self.server.tool)
     self.server.test_server_instance.setDaemon(True)
     self.server.test_server_instance.start()
     ready_event.wait()
@@ -401,14 +399,14 @@
 class SpawningServer(object):
   """The class used to start/stop a http server."""
 
-  def __init__(self, test_server_spawner_port, adb, tool, build_type):
+  def __init__(self, test_server_spawner_port, adb, tool):
     logging.info('Creating new spawner on port: %d.', test_server_spawner_port)
     self.server = BaseHTTPServer.HTTPServer(('', test_server_spawner_port),
                                             SpawningServerRequestHandler)
     self.server.adb = adb
     self.server.tool = tool
     self.server.test_server_instance = None
-    self.server.build_type = build_type
+    self.server.build_type = constants.GetBuildType()
 
   def _Listen(self):
     logging.info('Starting test server spawner')
diff --git a/build/android/pylib/constants.py b/build/android/pylib/constants.py
index 6cbe727..59ffcd4 100644
--- a/build/android/pylib/constants.py
+++ b/build/android/pylib/constants.py
@@ -14,11 +14,13 @@
 ISOLATE_DEPS_DIR = os.path.join(DIR_SOURCE_ROOT, 'isolate_deps_dir')
 EMULATOR_SDK_ROOT = os.path.abspath(os.path.join(DIR_SOURCE_ROOT, os.pardir,
                                                  os.pardir))
-
 CHROME_PACKAGE = 'com.google.android.apps.chrome'
 CHROME_ACTIVITY = 'com.google.android.apps.chrome.Main'
 CHROME_DEVTOOLS_SOCKET = 'chrome_devtools_remote'
 
+CHROME_STABLE_PACKAGE = 'com.android.chrome'
+CHROME_BETA_PACKAGE = 'com.chrome.beta'
+
 CHROME_TESTS_PACKAGE = 'com.google.android.apps.chrome.tests'
 
 LEGACY_BROWSER_PACKAGE = 'com.google.android.browser'
@@ -52,6 +54,7 @@
 LIGHTTPD_RANDOM_PORT_FIRST = 8001
 LIGHTTPD_RANDOM_PORT_LAST = 8999
 TEST_SYNC_SERVER_PORT = 9031
+TEST_SEARCH_BY_IMAGE_SERVER_PORT = 9041
 
 # The net test server is started from port 10201.
 # TODO(pliard): http://crbug.com/239014. Remove this dirty workaround once
@@ -83,6 +86,17 @@
 UPSTREAM_FLAKINESS_SERVER = 'test-results.appspot.com'
 
 
+def GetBuildType():
+  try:
+    return os.environ['BUILDTYPE']
+  except KeyError:
+    raise Exception('The BUILDTYPE environment variable has not been set')
+
+
+def SetBuildType(build_type):
+  os.environ['BUILDTYPE'] = build_type
+
+
 def _GetADBPath():
   if os.environ.get('ANDROID_SDK_ROOT'):
     return 'adb'
diff --git a/build/android/pylib/device_stats_monitor.py b/build/android/pylib/device_stats_monitor.py
index 000632b..482965f 100644
--- a/build/android/pylib/device_stats_monitor.py
+++ b/build/android/pylib/device_stats_monitor.py
@@ -29,10 +29,11 @@
   RESULT_VIEWER_PATH = os.path.abspath(os.path.join(
       os.path.dirname(os.path.realpath(__file__)), 'device_stats_monitor.html'))
 
-  def __init__(self, adb, hz, build_type):
+  def __init__(self, adb, hz):
     self._adb = adb
     host_path = os.path.abspath(os.path.join(
-        constants.DIR_SOURCE_ROOT, 'out', build_type, 'device_stats_monitor'))
+        constants.DIR_SOURCE_ROOT, 'out', constants.GetBuildType(),
+        'device_stats_monitor'))
     self._adb.PushIfNeeded(host_path, DeviceStatsMonitor.DEVICE_PATH)
     self._hz = hz
 
diff --git a/build/android/pylib/fake_dns.py b/build/android/pylib/fake_dns.py
index b119d76..ed99d20 100644
--- a/build/android/pylib/fake_dns.py
+++ b/build/android/pylib/fake_dns.py
@@ -14,14 +14,12 @@
   """Wrapper class for the fake_dns tool."""
   _FAKE_DNS_PATH = constants.TEST_EXECUTABLE_DIR + '/fake_dns'
 
-  def __init__(self, adb, build_type):
+  def __init__(self, adb):
     """
       Args:
         adb: the AndroidCommands to use.
-        build_type: 'Release' or 'Debug'.
     """
     self._adb = adb
-    self._build_type = build_type
     self._fake_dns = None
     self._original_dns = None
 
@@ -32,7 +30,7 @@
       subprocess instance connected to the fake_dns process on the device.
     """
     self._adb.PushIfNeeded(
-        os.path.join(constants.DIR_SOURCE_ROOT, 'out', self._build_type,
+        os.path.join(constants.DIR_SOURCE_ROOT, 'out', constants.GetBuildType(),
                      'fake_dns'),
         FakeDns._FAKE_DNS_PATH)
     return subprocess.Popen(
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py
index f77d858..64cdbaf 100644
--- a/build/android/pylib/gtest/gtest_config.py
+++ b/build/android/pylib/gtest/gtest_config.py
@@ -12,6 +12,7 @@
 # This list determines which suites are run by default, both for local
 # testing and on android trybots running on commit-queue.
 STABLE_TEST_SUITES = [
+    'content_browsertests',
     'android_webview_unittests',
     'base_unittests',
     'cc_unittests',
@@ -29,7 +30,6 @@
     'webkit_unit_tests',
     'breakpad_unittests',
     'sandbox_linux_unittests',
-    'content_browsertests',
 ]
 
 WEBRTC_TEST_SUITES = [
@@ -37,7 +37,7 @@
     'common_audio_unittests',
     'common_video_unittests',
     'metrics_unittests',
-    'modules_integrationtests',
+    'modules_tests',
     'modules_unittests',
     'neteq_unittests',
     'system_wrappers_unittests',
diff --git a/build/android/pylib/gtest/setup.py b/build/android/pylib/gtest/setup.py
index 2e70dd0..f139c97 100644
--- a/build/android/pylib/gtest/setup.py
+++ b/build/android/pylib/gtest/setup.py
@@ -15,9 +15,7 @@
 from pylib import cmd_helper
 from pylib import constants
 from pylib import ports
-from pylib.base import base_test_result
 
-import gtest_config
 import test_package_apk
 import test_package_exe
 import test_runner
@@ -69,14 +67,14 @@
     constants.DIR_SOURCE_ROOT, 'tools', 'swarm_client', 'isolate.py')
 
 
-def _GenerateDepsDirUsingIsolate(suite_name, build_type):
+def _GenerateDepsDirUsingIsolate(suite_name):
   """Generate the dependency dir for the test suite using isolate.
 
   Args:
     suite_name: Name of the test suite (e.g. base_unittests).
-    build_type: Release/Debug
   """
-  product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type)
+  product_dir = os.path.join(cmd_helper.OutDirectory.get(),
+      constants.GetBuildType())
   assert os.path.isabs(product_dir)
 
   if os.path.isdir(constants.ISOLATE_DEPS_DIR):
@@ -142,7 +140,8 @@
       shutil.move(os.path.join(root, filename), paks_dir)
 
   # Move everything in PRODUCT_DIR to top level.
-  deps_product_dir = os.path.join(constants.ISOLATE_DEPS_DIR, 'out', build_type)
+  deps_product_dir = os.path.join(constants.ISOLATE_DEPS_DIR, 'out',
+      constants.GetBuildType())
   if os.path.isdir(deps_product_dir):
     for p in os.listdir(deps_product_dir):
       shutil.move(os.path.join(deps_product_dir, p), constants.ISOLATE_DEPS_DIR)
@@ -257,11 +256,12 @@
   return tests
 
 
-def Setup(test_options):
+def Setup(test_options, devices):
   """Create the test runner factory and tests.
 
   Args:
     test_options: A GTestOptions object.
+    devices: A list of attached devices.
 
   Returns:
     A tuple of (TestRunnerFactory, tests).
@@ -270,19 +270,17 @@
   if not ports.ResetTestServerPortAllocation():
     raise Exception('Failed to reset test server port.')
 
-  test_package = test_package_apk.TestPackageApk(test_options.suite_name,
-                                                 test_options.build_type)
+  test_package = test_package_apk.TestPackageApk(test_options.suite_name)
   if not os.path.exists(test_package.suite_path):
     test_package = test_package_exe.TestPackageExecutable(
-        test_options.suite_name, test_options.build_type)
+        test_options.suite_name)
     if not os.path.exists(test_package.suite_path):
       raise Exception(
           'Did not find %s target. Ensure it has been built.'
           % test_options.suite_name)
   logging.warning('Found target %s', test_package.suite_path)
 
-  _GenerateDepsDirUsingIsolate(test_options.suite_name,
-                               test_options.build_type)
+  _GenerateDepsDirUsingIsolate(test_options.suite_name)
 
   # Constructs a new TestRunner with the current options.
   def TestRunnerFactory(device, shard_index):
@@ -291,12 +289,11 @@
         device,
         test_package)
 
-  attached_devices = android_commands.GetAttachedDevices()
   tests = _GetTestsFiltered(test_options.suite_name, test_options.gtest_filter,
-                            TestRunnerFactory, attached_devices)
+                            TestRunnerFactory, devices)
   # Coalesce unit tests into a single test per device
   if test_options.suite_name != 'content_browsertests':
-    num_devices = len(attached_devices)
+    num_devices = len(devices)
     tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)]
     tests = [t for t in tests if t]
 
diff --git a/build/android/pylib/gtest/test_options.py b/build/android/pylib/gtest/test_options.py
index c414671..4a9ce12 100644
--- a/build/android/pylib/gtest/test_options.py
+++ b/build/android/pylib/gtest/test_options.py
@@ -7,7 +7,6 @@
 import collections
 
 GTestOptions = collections.namedtuple('GTestOptions', [
-    'build_type',
     'tool',
     'cleanup_test_files',
     'push_deps',
diff --git a/build/android/pylib/gtest/test_package_apk.py b/build/android/pylib/gtest/test_package_apk.py
index 7fb55f6..5944147 100644
--- a/build/android/pylib/gtest/test_package_apk.py
+++ b/build/android/pylib/gtest/test_package_apk.py
@@ -23,14 +23,14 @@
 class TestPackageApk(TestPackage):
   """A helper class for running APK-based native tests."""
 
-  def __init__(self, suite_name, build_type):
+  def __init__(self, suite_name):
     """
     Args:
       suite_name: Name of the test suite (e.g. base_unittests).
-      build_type: 'Release' or 'Debug'.
     """
     TestPackage.__init__(self, suite_name)
-    product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type)
+    product_dir = os.path.join(cmd_helper.OutDirectory.get(),
+        constants.GetBuildType())
     if suite_name == 'content_browsertests':
       self.suite_path = os.path.join(
           product_dir, 'apks', '%s.apk' % suite_name)
diff --git a/build/android/pylib/gtest/test_package_exe.py b/build/android/pylib/gtest/test_package_exe.py
index f0238b8..7aa39d8 100644
--- a/build/android/pylib/gtest/test_package_exe.py
+++ b/build/android/pylib/gtest/test_package_exe.py
@@ -22,14 +22,14 @@
 
   _TEST_RUNNER_RET_VAL_FILE = 'gtest_retval'
 
-  def __init__(self, suite_name, build_type):
+  def __init__(self, suite_name):
     """
     Args:
       suite_name: Name of the test suite (e.g. base_unittests).
-      build_type: 'Release' or 'Debug'.
     """
     TestPackage.__init__(self, suite_name)
-    product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type)
+    product_dir = os.path.join(cmd_helper.OutDirectory.get(),
+        constants.GetBuildType())
     self.suite_path = os.path.join(product_dir, suite_name)
     self._symbols_dir = os.path.join(product_dir, 'lib.target')
 
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 8db2f83..7312c36 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -33,7 +33,6 @@
     """
 
     super(TestRunner, self).__init__(device, test_options.tool,
-                                     test_options.build_type,
                                      test_options.push_deps,
                                      test_options.cleanup_test_files)
 
diff --git a/build/android/pylib/host_driven/setup.py b/build/android/pylib/host_driven/setup.py
index ae7860a..a087bf1 100644
--- a/build/android/pylib/host_driven/setup.py
+++ b/build/android/pylib/host_driven/setup.py
@@ -196,7 +196,6 @@
     return test_runner.HostDrivenTestRunner(
         device, shard_index,
         instrumentation_options.tool,
-        instrumentation_options.build_type,
         instrumentation_options.push_deps,
         instrumentation_options.cleanup_test_files)
 
diff --git a/build/android/pylib/host_driven/test_case.py b/build/android/pylib/host_driven/test_case.py
index 2bf5f0a..3387c94 100644
--- a/build/android/pylib/host_driven/test_case.py
+++ b/build/android/pylib/host_driven/test_case.py
@@ -15,8 +15,9 @@
 itself, collecting the result, and calls TearDown.
 
 Tests can perform arbitrary Python commands and asserts in test methods. Tests
-that run instrumentation tests can make use of the _RunJavaTests helper function
-to trigger Java tests and convert results into a single host-driven test result.
+that run instrumentation tests can make use of the _RunJavaTestFilters helper
+function to trigger Java tests and convert results into a single host-driven
+test result.
 """
 
 import logging
@@ -24,6 +25,7 @@
 import time
 
 from pylib import android_commands
+from pylib import constants
 from pylib.base import base_test_result
 from pylib.instrumentation import test_package
 from pylib.instrumentation import test_result
@@ -55,11 +57,10 @@
     self.instrumentation_options = instrumentation_options
     self.ports_to_forward = []
 
-  def SetUp(self, device, shard_index, build_type, push_deps,
+  def SetUp(self, device, shard_index, push_deps,
             cleanup_test_files):
     self.device_id = device
     self.shard_index = shard_index
-    self.build_type = build_type
     self.adb = android_commands.AndroidCommands(self.device_id)
     self.push_deps = push_deps
     self.cleanup_test_files = cleanup_test_files
@@ -69,29 +70,23 @@
 
   def GetOutDir(self):
     return os.path.join(os.environ['CHROME_SRC'], 'out',
-                        self.build_type)
+                        constants.GetBuildType())
 
   def Run(self):
     logging.info('Running host-driven test: %s', self.tagged_name)
     # Get the test method on the derived class and execute it
     return getattr(self, self.test_name)()
 
-  def __RunJavaTest(self, package_name, test_case, test_method):
-    """Runs a single Java test method with a Java TestRunner.
+  def __RunJavaTest(self, test, test_pkg):
+    """Runs a single Java test in a Java TestRunner.
 
     Args:
-      package_name: Package name in which the java tests live
-          (e.g. foo.bar.baz.tests)
-      test_case: Name of the Java test case (e.g. FooTest)
-      test_method: Name of the test method to run (e.g. testFooBar)
+      test: Fully qualified test name (ex. foo.bar.TestClass#testMethod)
+      test_pkg: TestPackage object.
 
     Returns:
       TestRunResults object with a single test result.
     """
-    test = '%s.%s#%s' % (package_name, test_case, test_method)
-    test_pkg = test_package.TestPackage(
-        self.instrumentation_options.test_apk_path,
-        self.instrumentation_options.test_apk_jar_path)
     java_test_runner = test_runner.TestRunner(self.instrumentation_options,
                                               self.device_id,
                                               self.shard_index, test_pkg,
@@ -102,7 +97,7 @@
     finally:
       java_test_runner.TearDown()
 
-  def _RunJavaTests(self, package_name, tests):
+  def _RunJavaTestFilters(self, test_filters):
     """Calls a list of tests and stops at the first test failure.
 
     This method iterates until either it encounters a non-passing test or it
@@ -113,9 +108,7 @@
     being defined.
 
     Args:
-      package_name: Package name in which the java tests live
-          (e.g. foo.bar.baz.tests)
-      tests: A list of Java test names which will be run
+      test_filters: A list of Java test filters.
 
     Returns:
       A TestRunResults object containing an overall result for this set of Java
@@ -124,17 +117,30 @@
     test_type = base_test_result.ResultType.PASS
     log = ''
 
+    test_pkg = test_package.TestPackage(
+        self.instrumentation_options.test_apk_path,
+        self.instrumentation_options.test_apk_jar_path)
+
     start_ms = int(time.time()) * 1000
-    for test in tests:
-      # We're only running one test at a time, so this TestRunResults object
-      # will hold only one result.
-      suite, test_name = test.split('.')
-      java_result = self.__RunJavaTest(package_name, suite, test_name)
-      assert len(java_result.GetAll()) == 1
-      if not java_result.DidRunPass():
-        result = java_result.GetNotPass().pop()
-        log = result.GetLog()
-        test_type = result.GetType()
+    done = False
+    for test_filter in test_filters:
+      tests = test_pkg._GetAllMatchingTests(None, None, test_filter)
+      # Filters should always result in >= 1 test.
+      if len(tests) == 0:
+        raise Exception('Java test filter "%s" returned no tests.'
+                        % test_filter)
+      for test in tests:
+        # We're only running one test at a time, so this TestRunResults object
+        # will hold only one result.
+        java_result = self.__RunJavaTest(test, test_pkg)
+        assert len(java_result.GetAll()) == 1
+        if not java_result.DidRunPass():
+          result = java_result.GetNotPass().pop()
+          log = result.GetLog()
+          test_type = result.GetType()
+          done = True
+          break
+      if done:
         break
     duration_ms = int(time.time()) * 1000 - start_ms
 
diff --git a/build/android/pylib/host_driven/test_runner.py b/build/android/pylib/host_driven/test_runner.py
index 9a9acdd..53fd70f 100644
--- a/build/android/pylib/host_driven/test_runner.py
+++ b/build/android/pylib/host_driven/test_runner.py
@@ -49,7 +49,7 @@
   """
 
   #override
-  def __init__(self, device, shard_index, tool, build_type, push_deps,
+  def __init__(self, device, shard_index, tool, push_deps,
                cleanup_test_files):
     """Creates a new HostDrivenTestRunner.
 
@@ -57,13 +57,12 @@
       device: Attached android device.
       shard_index: Shard index.
       tool: Name of the Valgrind tool.
-      build_type: 'Release' or 'Debug'.
       push_deps: If True, push all dependencies to the device.
       cleanup_test_files: Whether or not to cleanup test files on device.
     """
 
-    super(HostDrivenTestRunner, self).__init__(device, tool, build_type,
-                                               push_deps, cleanup_test_files)
+    super(HostDrivenTestRunner, self).__init__(device, tool, push_deps,
+                                               cleanup_test_files)
 
     # The shard index affords the ability to create unique port numbers (e.g.
     # DEFAULT_PORT + shard_index) if the test so wishes.
@@ -87,8 +86,8 @@
     exception_raised = False
 
     try:
-      test.SetUp(self.device, self.shard_index, self.build_type,
-                 self._push_deps, self._cleanup_test_files)
+      test.SetUp(self.device, self.shard_index, self._push_deps,
+                 self._cleanup_test_files)
     except Exception:
       logging.exception(
           'Caught exception while trying to run SetUp() for test: ' +
diff --git a/build/android/pylib/host_driven/tests_annotations.py b/build/android/pylib/host_driven/tests_annotations.py
index 2654e32..d5f557d 100644
--- a/build/android/pylib/host_driven/tests_annotations.py
+++ b/build/android/pylib/host_driven/tests_annotations.py
@@ -88,6 +88,6 @@
 def Feature(feature_list):
   def _AddFeatures(function):
     for feature in feature_list:
-      AnnotatedFunctions._AddFunction('Feature' + feature, function)
+      AnnotatedFunctions._AddFunction('Feature:%s' % feature, function)
     return AnnotatedFunctions._AddFunction('Feature', function)
   return _AddFeatures
diff --git a/build/android/pylib/instrumentation/test_options.py b/build/android/pylib/instrumentation/test_options.py
index 0c9ac00..4077ba1 100644
--- a/build/android/pylib/instrumentation/test_options.py
+++ b/build/android/pylib/instrumentation/test_options.py
@@ -7,7 +7,6 @@
 import collections
 
 InstrumentationOptions = collections.namedtuple('InstrumentationOptions', [
-    'build_type',
     'tool',
     'cleanup_test_files',
     'push_deps',
@@ -18,6 +17,7 @@
     'save_perf_json',
     'screenshot_failures',
     'wait_for_debugger',
+    'coverage_dir',
     'test_apk',
     'test_apk_path',
     'test_apk_jar_path'])
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 5e2b67e..73440f5 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -44,6 +44,7 @@
   """Responsible for running a series of tests connected to a single device."""
 
   _DEVICE_DATA_DIR = 'chrome/test/data'
+  _DEVICE_COVERAGE_DIR = 'chrome/test/coverage'
   _HOSTMACHINE_PERF_OUTPUT_FILE = '/tmp/chrome-profile'
   _DEVICE_PERF_OUTPUT_SEARCH_PREFIX = (constants.DEVICE_PERF_OUTPUT_DIR +
                                        '/chrome-profile*')
@@ -62,7 +63,6 @@
           Can be optionally requested by a test case.
     """
     super(TestRunner, self).__init__(device, test_options.tool,
-                                     test_options.build_type,
                                      test_options.push_deps,
                                      test_options.cleanup_test_files)
     self._lighttp_port = constants.LIGHTTPD_RANDOM_PORT_FIRST + shard_index
@@ -70,6 +70,7 @@
     self.options = test_options
     self.test_pkg = test_pkg
     self.ports_to_forward = ports_to_forward
+    self.coverage_dir = test_options.coverage_dir
 
   #override
   def InstallTestPackage(self):
@@ -99,11 +100,11 @@
       dst_src = dest_host_pair.split(':',1)
       dst_layer = dst_src[0]
       host_src = dst_src[1]
-      host_test_files_path = constants.DIR_SOURCE_ROOT + '/' + host_src
+      host_test_files_path = '%s/%s' % (constants.DIR_SOURCE_ROOT, host_src)
       if os.path.exists(host_test_files_path):
-        self.adb.PushIfNeeded(host_test_files_path,
-                              self.adb.GetExternalStorage() + '/' +
-                              TestRunner._DEVICE_DATA_DIR + '/' + dst_layer)
+        self.adb.PushIfNeeded(host_test_files_path, '%s/%s/%s' % (
+            self.adb.GetExternalStorage(), TestRunner._DEVICE_DATA_DIR,
+            dst_layer))
     self.tool.CopyFiles()
     TestRunner._DEVICE_HAS_TEST_FILES[self.device] = True
 
@@ -111,11 +112,15 @@
     ret = {}
     if self.options.wait_for_debugger:
       ret['debug'] = 'true'
+    if self.coverage_dir:
+      ret['coverage'] = 'true'
+      ret['coverageFile'] = self.coverage_device_file
+
     return ret
 
   def _TakeScreenshot(self, test):
     """Takes a screenshot from the device."""
-    screenshot_name = os.path.join(constants.SCREENSHOTS_DIR, test + '.png')
+    screenshot_name = os.path.join(constants.SCREENSHOTS_DIR, '%s.png' % test)
     logging.info('Taking screenshot named %s', screenshot_name)
     self.adb.TakeScreenshot(screenshot_name)
 
@@ -157,6 +162,14 @@
     # Make sure the forwarder is still running.
     self._RestartHttpServerForwarderIfNecessary()
 
+    if self.coverage_dir:
+      coverage_basename = '%s.ec' % test
+      self.coverage_device_file = '%s/%s/%s' % (self.adb.GetExternalStorage(),
+                                                TestRunner._DEVICE_COVERAGE_DIR,
+                                                coverage_basename)
+      self.coverage_host_file = os.path.join(
+          self.coverage_dir, coverage_basename)
+
   def _IsPerfTest(self, test):
     """Determines whether a test is a performance test.
 
@@ -199,6 +212,10 @@
 
     self.TearDownPerfMonitoring(test)
 
+    if self.coverage_dir:
+      self.adb.Adb().Pull(self.coverage_device_file, self.coverage_host_file)
+      self.adb.RunShellCommand('rm -f %s' % self.coverage_device_file)
+
   def TearDownPerfMonitoring(self, test):
     """Cleans up performance monitoring if the specified test required it.
 
diff --git a/build/android/pylib/monkey/test_options.py b/build/android/pylib/monkey/test_options.py
index 6b095f3..31a91bb 100644
--- a/build/android/pylib/monkey/test_options.py
+++ b/build/android/pylib/monkey/test_options.py
@@ -7,7 +7,6 @@
 import collections
 
 MonkeyOptions = collections.namedtuple('MonkeyOptions', [
-    'build_type',
     'verbose_count',
     'package_name',
     'activity_name',
diff --git a/build/android/pylib/monkey/test_runner.py b/build/android/pylib/monkey/test_runner.py
index 99bc2e6..6db9ea9 100644
--- a/build/android/pylib/monkey/test_runner.py
+++ b/build/android/pylib/monkey/test_runner.py
@@ -14,7 +14,7 @@
   """A TestRunner instance runs a monkey test on a single device."""
 
   def __init__(self, test_options, device, shard_index):
-    super(TestRunner, self).__init__(device, None, test_options.build_type)
+    super(TestRunner, self).__init__(device, None)
     self.options = test_options
 
   def _LaunchMonkeyTest(self):
diff --git a/build/android/pylib/perf/__init__.py b/build/android/pylib/perf/__init__.py
new file mode 100644
index 0000000..9228df8
--- /dev/null
+++ b/build/android/pylib/perf/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2013 The Chromium 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/build/android/pylib/perf/setup.py b/build/android/pylib/perf/setup.py
new file mode 100644
index 0000000..5d0272d
--- /dev/null
+++ b/build/android/pylib/perf/setup.py
@@ -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.
+
+"""Generates test runner factory and tests for performance tests."""
+
+import json
+import logging
+import os
+import psutil
+import signal
+import time
+
+from pylib import android_commands
+from pylib import cmd_helper
+from pylib import forwarder
+from pylib import ports
+
+import test_runner
+
+
+def _KillPendingServers():
+  for retry in range(5):
+    for server in ['lighttpd', 'web-page-replay']:
+      pids = [p.pid for p in psutil.process_iter() if server in p.name]
+      for pid in pids:
+        try:
+          logging.warning('Killing %s %s', server, pid)
+          os.kill(pid, signal.SIGQUIT)
+        except Exception as e:
+          logging.warning('Failed killing %s %s %s', server, pid, e)
+  # Restart the adb server with taskset to set a single CPU affinity.
+  cmd_helper.RunCmd(['adb', 'kill-server'])
+  cmd_helper.RunCmd(['taskset', '-c', '0', 'adb', 'start-server'])
+  cmd_helper.RunCmd(['taskset', '-c', '0', 'adb', 'root'])
+  i = 1
+  while not android_commands.GetAttachedDevices():
+    time.sleep(i)
+    i *= 2
+    if i > 10:
+      break
+  # Reset the test port allocation. It's important to do it before starting
+  # to dispatch any step.
+  if not ports.ResetTestServerPortAllocation():
+    raise Exception('Failed to reset test server port.')
+
+  forwarder.Forwarder.UseMultiprocessing()
+
+
+def Setup(test_options):
+  """Create and return the test runner factory and tests.
+
+  Args:
+    test_options: A PerformanceOptions object.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+  # Before running the tests, kill any leftover server.
+  _KillPendingServers()
+
+  with file(test_options.steps, 'r') as f:
+    tests = json.load(f)
+
+  flaky_steps = []
+  if test_options.flaky_steps:
+    with file(test_options.flaky_steps, 'r') as f:
+      flaky_steps = json.load(f)
+
+  def TestRunnerFactory(device, shard_index):
+    return test_runner.TestRunner(
+        test_options, device, tests, flaky_steps)
+
+  return (TestRunnerFactory, sorted(tests.keys()))
diff --git a/build/android/pylib/perf/test_options.py b/build/android/pylib/perf/test_options.py
new file mode 100644
index 0000000..6664ba2
--- /dev/null
+++ b/build/android/pylib/perf/test_options.py
@@ -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.
+
+"""Defines the PerfOptions named tuple."""
+
+import collections
+
+PerfOptions = collections.namedtuple('PerfOptions', [
+    'steps',
+    'flaky_steps',
+    'print_step',
+])
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py
new file mode 100644
index 0000000..bf09dfe
--- /dev/null
+++ b/build/android/pylib/perf/test_runner.py
@@ -0,0 +1,155 @@
+# Copyright 2013 The Chromium 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 a perf test on a single device.
+
+Our buildbot infrastructure requires each slave to run steps serially.
+This is sub-optimal for android, where these steps can run independently on
+multiple connected devices.
+
+The buildbots will run this script multiple times per cycle:
+- First: all steps listed in --steps in will be executed in parallel using all
+connected devices. Step results will be pickled to disk. Each step has a unique
+name. The result code will be ignored if the step name is listed in
+--flaky-steps.
+The buildbot will treat this step as a regular step, and will not process any
+graph data.
+
+- Then, with -print-step STEP_NAME: at this stage, we'll simply print the file
+with the step results previously saved. The buildbot will then process the graph
+data accordingly.
+
+The JSON steps file contains a dictionary in the format:
+{
+  "step_name_foo": "script_to_execute foo",
+  "step_name_bar": "script_to_execute bar"
+}
+
+The JSON flaky steps file contains a list with step names which results should
+be ignored:
+[
+  "step_name_foo",
+  "step_name_bar"
+]
+
+Note that script_to_execute necessarily have to take at least the following
+options:
+  --device: the serial number to be passed to all adb commands.
+  --keep_test_server_ports: indicates it's being run as a shard, and shouldn't
+  reset test server port allocation.
+"""
+
+import datetime
+import logging
+import pexpect
+import pickle
+import os
+import sys
+import time
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+
+
+_OUTPUT_DIR = os.path.join(constants.DIR_SOURCE_ROOT, 'out', 'step_results')
+
+
+def PrintTestOutput(test_name):
+  """Helper method to print the output of previously executed test_name.
+
+  Args:
+    test_name: name of the test that has been previously executed.
+
+  Returns:
+    exit code generated by the test step.
+  """
+  file_name = os.path.join(_OUTPUT_DIR, test_name)
+  if not os.path.exists(file_name):
+    logging.error('File not found %s', file_name)
+    return 1
+
+  with file(file_name, 'r') as f:
+    persisted_result = pickle.loads(f.read())
+  print persisted_result['output']
+
+  return persisted_result['exit_code']
+
+
+class TestRunner(base_test_runner.BaseTestRunner):
+  def __init__(self, test_options, device, tests, flaky_tests):
+    """A TestRunner instance runs a perf test on a single device.
+
+    Args:
+      test_options: A PerfOptions object.
+      device: Device to run the tests.
+      tests: a dict mapping test_name to command.
+      flaky_tests: a list of flaky test_name.
+    """
+    super(TestRunner, self).__init__(device, None, 'Release')
+    self._options = test_options
+    self._tests = tests
+    self._flaky_tests = flaky_tests
+
+  @staticmethod
+  def _SaveResult(result):
+    with file(os.path.join(_OUTPUT_DIR, result['name']), 'w') as f:
+      f.write(pickle.dumps(result))
+
+  def _LaunchPerfTest(self, test_name):
+    """Runs a perf test.
+
+    Args:
+      test_name: the name of the test to be executed.
+
+    Returns:
+      A tuple containing (Output, base_test_result.ResultType)
+    """
+    cmd = ('%s --device %s --keep_test_server_ports' %
+           (self._tests[test_name], self.device))
+    logging.info('%s : %s', test_name, cmd)
+    start_time = datetime.datetime.now()
+    output, exit_code = pexpect.run(
+        cmd, cwd=os.path.abspath(constants.DIR_SOURCE_ROOT),
+        withexitstatus=True, logfile=sys.stdout, timeout=1800,
+        env=os.environ)
+    end_time = datetime.datetime.now()
+    logging.info('%s : exit_code=%d in %d secs at %s',
+                 test_name, exit_code, (end_time - start_time).seconds,
+                 self.device)
+    result_type = base_test_result.ResultType.FAIL
+    if exit_code == 0:
+      result_type = base_test_result.ResultType.PASS
+    if test_name in self._flaky_tests:
+      exit_code = 0
+      result_type = base_test_result.ResultType.PASS
+
+    persisted_result = {
+        'name': test_name,
+        'output': output,
+        'exit_code': exit_code,
+        'result_type': result_type,
+        'total_time': (end_time - start_time).seconds,
+        'device': self.device,
+    }
+    self._SaveResult(persisted_result)
+
+    return (output, result_type)
+
+  def RunTest(self, test_name):
+    """Run a perf test on the device.
+
+    Args:
+      test_name: String to use for logging the test result.
+
+    Returns:
+      A tuple of (TestRunResults, retry).
+    """
+    output, result_type = self._LaunchPerfTest(test_name)
+    results = base_test_result.TestRunResults()
+    results.AddResult(base_test_result.BaseTestResult(test_name, result_type))
+    retry = None
+    if not results.DidRunPass():
+      retry = test_name
+    return results, retry
diff --git a/build/android/pylib/uiautomator/test_options.py b/build/android/pylib/uiautomator/test_options.py
index 2ce5eb0..99098a1 100644
--- a/build/android/pylib/uiautomator/test_options.py
+++ b/build/android/pylib/uiautomator/test_options.py
@@ -7,7 +7,6 @@
 import collections
 
 UIAutomatorOptions = collections.namedtuple('UIAutomatorOptions', [
-    'build_type',
     'tool',
     'cleanup_test_files',
     'push_deps',
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
index 58cdd45..fcd2cc6 100644
--- a/build/android/pylib/uiautomator/test_runner.py
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -25,7 +25,6 @@
     """
     # Create an InstrumentationOptions object to pass to the super class
     instrumentation_options = instr_test_options.InstrumentationOptions(
-        test_options.build_type,
         test_options.tool,
         test_options.cleanup_test_files,
         test_options.push_deps,
@@ -36,6 +35,7 @@
         test_options.save_perf_json,
         test_options.screenshot_failures,
         wait_for_debugger=False,
+        coverage_dir=None,
         test_apk=None,
         test_apk_path=None,
         test_apk_jar_path=None)
diff --git a/build/android/pylib/utils/command_option_parser.py b/build/android/pylib/utils/command_option_parser.py
new file mode 100644
index 0000000..636d7e1
--- /dev/null
+++ b/build/android/pylib/utils/command_option_parser.py
@@ -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.
+
+"""An option parser which handles the first arg as a command.
+
+Add other nice functionality such as printing a list of commands
+and an example in usage.
+"""
+
+import optparse
+import sys
+
+
+class CommandOptionParser(optparse.OptionParser):
+  """Wrapper class for OptionParser to help with listing commands."""
+
+  def __init__(self, *args, **kwargs):
+    """Creates a CommandOptionParser.
+
+    Args:
+      commands_dict: A dictionary mapping command strings to an object defining
+          - add_options_func: Adds options to the option parser
+          - run_command_func: Runs the command itself.
+      example: An example command.
+      everything else: Passed to optparse.OptionParser contructor.
+    """
+    self.commands_dict = kwargs.pop('commands_dict', [])
+    self.example = kwargs.pop('example', '')
+    if not 'usage' in kwargs:
+      kwargs['usage'] = 'Usage: %prog <command> [options]'
+    optparse.OptionParser.__init__(self, *args, **kwargs)
+
+  #override
+  def get_usage(self):
+    normal_usage = optparse.OptionParser.get_usage(self)
+    command_list = self.get_command_list()
+    example = self.get_example()
+    return self.expand_prog_name(normal_usage + example + command_list)
+
+  #override
+  def get_command_list(self):
+    if self.commands_dict.keys():
+      return '\nCommands:\n  %s\n' % '\n  '.join(
+          sorted(self.commands_dict.keys()))
+    return ''
+
+  def get_example(self):
+    if self.example:
+      return '\nExample:\n  %s\n' % self.example
+    return ''
+
+
+def ParseAndExecute(option_parser, argv=None):
+  """Parses options/args from argv and runs the specified command.
+
+  Args:
+    option_parser: A CommandOptionParser object.
+    argv: Command line arguments. If None, automatically draw from sys.argv.
+
+  Returns:
+    An exit code.
+  """
+  if not argv:
+    argv = sys.argv
+
+    if len(argv) < 2 or argv[1] not in option_parser.commands_dict:
+      # Parse args first, if this is '--help', optparse will print help and exit
+      option_parser.parse_args(argv)
+      option_parser.error('Invalid command.')
+
+    command = argv[1]
+    option_parser.commands_dict[command].add_options_func(option_parser)
+    options, args = option_parser.parse_args(argv)
+    return option_parser.commands_dict[command].run_command_func(
+        command, options, args, option_parser)
diff --git a/build/android/pylib/utils/report_results.py b/build/android/pylib/utils/report_results.py
index 673ab2e..75ef322 100644
--- a/build/android/pylib/utils/report_results.py
+++ b/build/android/pylib/utils/report_results.py
@@ -13,10 +13,10 @@
 import flakiness_dashboard_results_uploader
 
 
-def _LogToFile(results, test_type, suite_name, build_type):
+def _LogToFile(results, test_type, suite_name):
   """Log results to local files which can be used for aggregation later."""
   log_file_path = os.path.join(constants.DIR_SOURCE_ROOT, 'out',
-                               build_type, 'test_logs')
+                               constants.GetBuildType(), 'test_logs')
   if not os.path.exists(log_file_path):
     os.mkdir(log_file_path)
   full_file_name = os.path.join(
@@ -64,7 +64,7 @@
 
 
 def LogFull(results, test_type, test_package, annotation=None,
-            build_type='Debug', flakiness_server=None):
+            flakiness_server=None):
   """Log the tests results for the test suite.
 
   The results will be logged three different ways:
@@ -80,7 +80,6 @@
                   'ContentShellTest' for instrumentation tests)
     annotation: If instrumenation test type, this is a list of annotations
                 (e.g. ['Smoke', 'SmallTest']).
-    build_type: Release/Debug
     flakiness_server: If provider, upload the results to flakiness dashboard
                       with this URL.
     """
@@ -104,7 +103,7 @@
       suite_name = annotation[0]
     else:
       suite_name = test_package
-    _LogToFile(results, test_type, suite_name, build_type)
+    _LogToFile(results, test_type, suite_name)
 
     if flakiness_server:
       _LogToFlakinessDashboard(results, test_type, test_package,
diff --git a/build/android/run_browser_tests.py b/build/android/run_browser_tests.py
deleted file mode 100755
index c536a29..0000000
--- a/build/android/run_browser_tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/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.
-
-"""Runs content_browsertests."""
-
-import logging
-import os
-import sys
-
-from pylib import cmd_helper
-
-
-if __name__ == '__main__':
-  args = [os.path.join(os.path.dirname(__file__), 'test_runner.py'),
-          'gtest', '-s', 'content_browsertests'] + sys.argv[1:]
-  logging.warning('*' * 80)
-  logging.warning('This script is deprecated and will be removed soon.')
-  logging.warning('Use the following instead: %s', ' '.join(args))
-  logging.warning('*' * 80)
-  sys.exit(1)
diff --git a/build/android/run_instrumentation_tests.py b/build/android/run_instrumentation_tests.py
deleted file mode 100755
index 7a9fa1e..0000000
--- a/build/android/run_instrumentation_tests.py
+++ /dev/null
@@ -1,23 +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.
-
-"""Runs both the Python and Java instrumentation tests."""
-
-import logging
-import os
-import sys
-
-from pylib import cmd_helper
-
-
-if __name__ == '__main__':
-  args = [os.path.join(os.path.dirname(__file__), 'test_runner.py'),
-          'instrumentation'] + sys.argv[1:]
-  logging.warning('*' * 80)
-  logging.warning('This script is deprecated and will be removed soon.')
-  logging.warning('Use the following instead: %s', ' '.join(args))
-  logging.warning('*' * 80)
-  sys.exit(1)
diff --git a/build/android/run_tests.py b/build/android/run_tests.py
deleted file mode 100755
index 59118cf..0000000
--- a/build/android/run_tests.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/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.
-
-"""Runs all the native unit tests."""
-
-import logging
-import os
-import sys
-
-from pylib import cmd_helper
-
-
-if __name__ == '__main__':
-  args = [os.path.join(os.path.dirname(__file__), 'test_runner.py'),
-          'gtest'] + sys.argv[1:]
-  logging.warning('*' * 80)
-  logging.warning('This script is deprecated and will be removed soon.')
-  logging.warning('Use the following instead: %s', ' '.join(args))
-  logging.warning('*' * 80)
-  sys.exit(1)
diff --git a/build/android/run_uiautomator_tests.py b/build/android/run_uiautomator_tests.py
deleted file mode 100755
index 4a94a83..0000000
--- a/build/android/run_uiautomator_tests.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/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.
-
-"""Runs both the Python and Java UIAutomator tests."""
-
-import logging
-import os
-import sys
-
-from pylib import cmd_helper
-
-
-if __name__ == '__main__':
-  args = ['python',
-          os.path.join(os.path.dirname(__file__), 'test_runner.py'),
-          'uiautomator'] + sys.argv[1:]
-  logging.warning('*' * 80)
-  logging.warning('This script is deprecated and will be removed soon.')
-  logging.warning('Use the following instead: %s', ' '.join(args))
-  logging.warning('*' * 80)
-  sys.exit(cmd_helper.RunCmd(args))
diff --git a/build/android/run_update_verification.py b/build/android/run_update_verification.py
deleted file mode 100755
index 5f62f3e..0000000
--- a/build/android/run_update_verification.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/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.
-
-"""Runs semi-automated update testing on a non-rooted device."""
-import logging
-import optparse
-import os
-import shutil
-import sys
-import time
-
-from pylib import android_commands
-
-
-def _SaveAppData(adb, package_name, from_apk=None, data_dir=None):
-  def _BackupAppData(data_dir=None):
-    adb.Adb().SendCommand('backup %s' % package_name)
-    backup_file = os.path.join(os.getcwd(), 'backup.ab')
-    assert os.path.exists(backup_file), 'Backup failed.'
-    if data_dir:
-      if not os.path.isdir(data_dir):
-        os.makedirs(data_dir)
-      shutil.move(backup_file, data_dir)
-      backup_file = os.path.join(data_dir, 'backup.ab')
-    print 'Application data saved to %s' % backup_file
-
-  if from_apk:
-    logging.info('Installing %s...', from_apk)
-    output = adb.Install(from_apk, reinstall=True)
-    if 'Success' not in output:
-      raise Exception('Unable to install %s. output: %s' % (from_apk, output))
-
-  raw_input('Set the application state. Once ready, press enter and '
-            'select "Backup my data" on the device.')
-  _BackupAppData(data_dir)
-
-
-def _VerifyAppUpdate(adb, to_apk, app_data, from_apk=None):
-  def _RestoreAppData():
-    assert os.path.exists(app_data), 'Backup file does not exist!'
-    adb.Adb().SendCommand('restore %s' % app_data)
-    # It seems restore command is not synchronous.
-    time.sleep(15)
-
-  if from_apk:
-    logging.info('Installing %s...', from_apk)
-    output = adb.Install(from_apk, reinstall=True)
-    if 'Success' not in output:
-      raise Exception('Unable to install %s. output: %s' % (from_apk, output))
-
-  logging.info('Restoring the application data...')
-  raw_input('Press enter and select "Restore my data" on the device.')
-  _RestoreAppData()
-
-  logging.info('Verifying that %s cannot be installed side-by-side...',
-               to_apk)
-  output = adb.Install(to_apk)
-  if 'INSTALL_FAILED_ALREADY_EXISTS' not in output:
-    if 'Success' in output:
-      raise Exception('Package name has changed! output: %s' % output)
-    else:
-      raise Exception(output)
-
-  logging.info('Verifying that %s can be overinstalled...', to_apk)
-  output = adb.Install(to_apk, reinstall=True)
-  if 'Success' not in output:
-    raise Exception('Unable to install %s.\n output: %s' % (to_apk, output))
-  logging.info('Successfully updated to the new apk. Please verify that the '
-               'the application data is preserved.')
-
-
-def main():
-  logger = logging.getLogger()
-  logger.setLevel(logging.DEBUG)
-  desc = (
-      'Performs semi-automated application update verification testing. '
-      'When given --save, it takes a snapshot of the application data '
-      'on the device. (A dialog on the device will prompt the user to grant '
-      'permission to backup the data.) Otherwise, it performs the update '
-      'testing as follows: '
-      '1. Installs the |from-apk| (optional). '
-      '2. Restores the previously stored snapshot of application data '
-      'given by |app-data| '
-      '(A dialog on the device will prompt the user to grant permission to '
-      'restore the data.) '
-      '3. Verifies that |to-apk| cannot be installed side-by-side. '
-      '4. Verifies that |to-apk| can replace |from-apk|.')
-  parser = optparse.OptionParser(description=desc)
-  parser.add_option('--package-name', help='Package name for the application.')
-  parser.add_option('--save', action='store_true',
-                    help=('Save a snapshot of application data. '
-                          'This will be saved as backup.db in the '
-                          'current directory if |app-data| directory '
-                          'is not specifid.'))
-  parser.add_option('--from-apk',
-                    help=('APK to update from. This is optional if you already '
-                          'have the app installed.'))
-  parser.add_option('--to-apk', help='APK to update to.')
-  parser.add_option('--app-data',
-                    help=('Path to the application data to be restored or the '
-                          'directory where the data should be saved.'))
-  (options, args) = parser.parse_args()
-
-  if args:
-    parser.print_help(sys.stderr)
-    parser.error('Unknown arguments: %s.' % args)
-
-  if len(android_commands.GetAttachedDevices()) != 1:
-    parser.error('Exactly 1 device must be attached.')
-  adb = android_commands.AndroidCommands()
-
-  if options.from_apk:
-    assert os.path.isfile(options.from_apk)
-
-  if options.save:
-    if not options.package_name:
-      parser.print_help(sys.stderr)
-      parser.error('Missing --package-name.')
-    _SaveAppData(adb, options.package_name, from_apk=options.from_apk,
-                 data_dir=options.app_data)
-  else:
-    if not options.to_apk or not options.app_data:
-      parser.print_help(sys.stderr)
-      parser.error('Missing --to-apk or --app-data.')
-    assert os.path.isfile(options.to_apk)
-    assert os.path.isfile(options.app_data)
-    _VerifyAppUpdate(adb, options.to_apk, options.app_data,
-                     from_apk=options.from_apk)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 705eec4..2c87df9 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -11,11 +11,13 @@
 """
 
 import collections
+import logging
 import optparse
 import os
 import shutil
 import sys
 
+from pylib import android_commands
 from pylib import constants
 from pylib import ports
 from pylib.base import base_test_result
@@ -28,8 +30,12 @@
 from pylib.instrumentation import test_options as instrumentation_test_options
 from pylib.monkey import setup as monkey_setup
 from pylib.monkey import test_options as monkey_test_options
+from pylib.perf import setup as perf_setup
+from pylib.perf import test_options as perf_test_options
+from pylib.perf import test_runner as perf_test_runner
 from pylib.uiautomator import setup as uiautomator_setup
 from pylib.uiautomator import test_options as uiautomator_test_options
+from pylib.utils import command_option_parser
 from pylib.utils import report_results
 from pylib.utils import run_tests_helper
 
@@ -91,6 +97,7 @@
 def ProcessCommonOptions(options):
   """Processes and handles all common options."""
   run_tests_helper.SetLogLevel(options.verbose_count)
+  constants.SetBuildType(options.build_type)
 
 
 def AddGTestOptions(option_parser):
@@ -214,7 +221,7 @@
   option_parser.add_option('-p', '--python_only', action='store_true',
                            default=False,
                            help='Run only the host-driven tests.')
-  option_parser.add_option('--python_test_root',
+  option_parser.add_option('--host-driven-root',
                            help='Root of the host-driven tests.')
   option_parser.add_option('-w', '--wait_debugger', dest='wait_for_debugger',
                            action='store_true',
@@ -224,6 +231,9 @@
       help=('The name of the apk containing the tests '
             '(without the .apk extension; e.g. "ContentShellTest"). '
             'Alternatively, this can be a full path to the apk.'))
+  option_parser.add_option('--coverage-dir',
+                           help=('Directory in which to place all generated '
+                                 'EMMA coverage files.'))
 
 
 def ProcessInstrumentationOptions(options, error_func):
@@ -250,7 +260,7 @@
   elif options.python_only:
     options.run_java_tests = False
 
-  if not options.python_test_root:
+  if not options.host_driven_root:
     options.run_python_tests = False
 
   if not options.test_apk:
@@ -271,7 +281,6 @@
         '%s.jar' %  options.test_apk)
 
   return instrumentation_test_options.InstrumentationOptions(
-      options.build_type,
       options.tool,
       options.cleanup_test_files,
       options.push_deps,
@@ -282,6 +291,7 @@
       options.save_perf_json,
       options.screenshot_failures,
       options.wait_for_debugger,
+      options.coverage_dir,
       options.test_apk,
       options.test_apk_path,
       options.test_apk_jar_path)
@@ -340,7 +350,6 @@
       '_java.jar')
 
   return uiautomator_test_options.UIAutomatorOptions(
-      options.build_type,
       options.tool,
       options.cleanup_test_files,
       options.push_deps,
@@ -407,7 +416,6 @@
     category = options.category.split(',')
 
   return monkey_test_options.MonkeyOptions(
-      options.build_type,
       options.verbose_count,
       options.package_name,
       options.activity_name,
@@ -418,7 +426,42 @@
       options.extra_args)
 
 
-def _RunGTests(options, error_func):
+def AddPerfTestOptions(option_parser):
+  """Adds perf test options to |option_parser|."""
+
+  option_parser.usage = '%prog perf [options]'
+  option_parser.command_list = []
+  option_parser.example = ('%prog perf --steps perf_steps.json')
+
+  option_parser.add_option('--steps', help='JSON file containing the list '
+      'of perf steps to run.')
+  option_parser.add_option('--flaky-steps',
+                           help='A JSON file containing steps that are flaky '
+                                'and will have its exit code ignored.')
+  option_parser.add_option('--print-step', help='The name of a previously '
+      'executed perf step to print.')
+
+  AddCommonOptions(option_parser)
+
+
+def ProcessPerfTestOptions(options, error_func):
+  """Processes all perf test options.
+
+  Args:
+    options: optparse.Options object.
+    error_func: Function to call with the error message in case of an error.
+
+  Returns:
+    A PerfOptions named tuple which contains all options relevant to
+    perf tests.
+  """
+  if not options.steps and not options.print_step:
+    error_func('Please specify --steps or --print-step')
+  return perf_test_options.PerfOptions(
+      options.steps, options.flaky_steps, options.print_step)
+
+
+def _RunGTests(options, error_func, devices):
   """Subcommand of RunTestsCommands which runs gtests."""
   ProcessGTestOptions(options)
 
@@ -427,7 +470,6 @@
     # TODO(gkanwar): Move this into ProcessGTestOptions once we require -s for
     # the gtest command.
     gtest_options = gtest_test_options.GTestOptions(
-        options.build_type,
         options.tool,
         options.cleanup_test_files,
         options.push_deps,
@@ -435,13 +477,10 @@
         options.test_arguments,
         options.timeout,
         suite_name)
-    runner_factory, tests = gtest_setup.Setup(gtest_options)
+    runner_factory, tests = gtest_setup.Setup(gtest_options, devices)
 
     results, test_exit_code = test_dispatcher.RunTests(
-        tests, runner_factory, False, options.test_device,
-        shard=True,
-        build_type=options.build_type,
-        test_timeout=None,
+        tests, runner_factory, devices, shard=True, test_timeout=None,
         num_retries=options.num_retries)
 
     if test_exit_code and exit_code != constants.ERROR_EXIT_CODE:
@@ -451,7 +490,6 @@
         results=results,
         test_type='Unit test',
         test_package=suite_name,
-        build_type=options.build_type,
         flakiness_server=options.flakiness_dashboard_server)
 
   if os.path.isdir(constants.ISOLATE_DEPS_DIR):
@@ -460,10 +498,14 @@
   return exit_code
 
 
-def _RunInstrumentationTests(options, error_func):
+def _RunInstrumentationTests(options, error_func, devices):
   """Subcommand of RunTestsCommands which runs instrumentation tests."""
   instrumentation_options = ProcessInstrumentationOptions(options, error_func)
 
+  if len(devices) > 1 and options.wait_for_debugger:
+    logging.warning('Debugger can not be sharded, using first available device')
+    devices = devices[:1]
+
   results = base_test_result.TestRunResults()
   exit_code = 0
 
@@ -471,27 +513,19 @@
     runner_factory, tests = instrumentation_setup.Setup(instrumentation_options)
 
     test_results, exit_code = test_dispatcher.RunTests(
-        tests, runner_factory, options.wait_for_debugger,
-        options.test_device,
-        shard=True,
-        build_type=options.build_type,
-        test_timeout=None,
+        tests, runner_factory, devices, shard=True, test_timeout=None,
         num_retries=options.num_retries)
 
     results.AddTestRunResults(test_results)
 
   if options.run_python_tests:
     runner_factory, tests = host_driven_setup.InstrumentationSetup(
-        options.python_test_root, options.official_build,
+        options.host_driven_root, options.official_build,
         instrumentation_options)
 
     if tests:
       test_results, test_exit_code = test_dispatcher.RunTests(
-          tests, runner_factory, False,
-          options.test_device,
-          shard=True,
-          build_type=options.build_type,
-          test_timeout=None,
+          tests, runner_factory, devices, shard=True, test_timeout=None,
           num_retries=options.num_retries)
 
       results.AddTestRunResults(test_results)
@@ -505,23 +539,19 @@
       test_type='Instrumentation',
       test_package=os.path.basename(options.test_apk),
       annotation=options.annotations,
-      build_type=options.build_type,
       flakiness_server=options.flakiness_dashboard_server)
 
   return exit_code
 
 
-def _RunUIAutomatorTests(options, error_func):
+def _RunUIAutomatorTests(options, error_func, devices):
   """Subcommand of RunTestsCommands which runs uiautomator tests."""
   uiautomator_options = ProcessUIAutomatorOptions(options, error_func)
 
   runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
 
   results, exit_code = test_dispatcher.RunTests(
-      tests, runner_factory, False, options.test_device,
-      shard=True,
-      build_type=options.build_type,
-      test_timeout=None,
+      tests, runner_factory, devices, shard=True, test_timeout=None,
       num_retries=options.num_retries)
 
   report_results.LogFull(
@@ -529,30 +559,71 @@
       test_type='UIAutomator',
       test_package=os.path.basename(options.test_jar),
       annotation=options.annotations,
-      build_type=options.build_type,
       flakiness_server=options.flakiness_dashboard_server)
 
   return exit_code
 
 
-def _RunMonkeyTests(options, error_func):
+def _RunMonkeyTests(options, error_func, devices):
   """Subcommand of RunTestsCommands which runs monkey tests."""
   monkey_options = ProcessMonkeyTestOptions(options, error_func)
 
   runner_factory, tests = monkey_setup.Setup(monkey_options)
 
   results, exit_code = test_dispatcher.RunTests(
-      tests, runner_factory, False, None, shard=False, test_timeout=None)
+      tests, runner_factory, devices, shard=False, test_timeout=None)
 
   report_results.LogFull(
       results=results,
       test_type='Monkey',
-      test_package='Monkey',
-      build_type=options.build_type)
+      test_package='Monkey')
 
   return exit_code
 
 
+def _RunPerfTests(options, error_func, devices):
+  """Subcommand of RunTestsCommands which runs perf tests."""
+  perf_options = ProcessPerfTestOptions(options, error_func)
+    # Just print the results from a single previously executed step.
+  if perf_options.print_step:
+    return perf_test_runner.PrintTestOutput(perf_options.print_step)
+
+  runner_factory, tests = perf_setup.Setup(perf_options)
+
+  results, _ = test_dispatcher.RunTests(
+      tests, runner_factory, devices, shard=True, test_timeout=None)
+
+  report_results.LogFull(
+      results=results,
+      test_type='Perf',
+      test_package='Perf')
+  # Always return 0 on the sharding stage. Individual tests exit_code
+  # will be returned on the print_step stage.
+  return 0
+
+
+def _GetAttachedDevices(test_device=None):
+  """Get all attached devices.
+
+  Args:
+    test_device: Name of a specific device to use.
+
+  Returns:
+    A list of attached devices.
+  """
+  attached_devices = []
+
+  attached_devices = android_commands.GetAttachedDevices()
+  if test_device:
+    assert test_device in attached_devices, (
+        'Did not find device %s among attached device. Attached devices: %s'
+        % (test_device, ', '.join(attached_devices)))
+    attached_devices = [test_device]
+
+  assert attached_devices, 'No devices attached.'
+
+  return sorted(attached_devices)
+
 
 def RunTestsCommand(command, options, args, option_parser):
   """Checks test type and dispatches to the appropriate function.
@@ -579,14 +650,18 @@
 
   ProcessCommonOptions(options)
 
+  devices = _GetAttachedDevices(options.test_device)
+
   if command == 'gtest':
-    return _RunGTests(options, option_parser.error)
+    return _RunGTests(options, option_parser.error, devices)
   elif command == 'instrumentation':
-    return _RunInstrumentationTests(options, option_parser.error)
+    return _RunInstrumentationTests(options, option_parser.error, devices)
   elif command == 'uiautomator':
-    return _RunUIAutomatorTests(options, option_parser.error)
+    return _RunUIAutomatorTests(options, option_parser.error, devices)
   elif command == 'monkey':
-    return _RunMonkeyTests(options, option_parser.error)
+    return _RunMonkeyTests(options, option_parser.error, devices)
+  elif command == 'perf':
+    return _RunPerfTests(options, option_parser.error, devices)
   else:
     raise Exception('Unknown test type.')
 
@@ -645,49 +720,16 @@
         AddUIAutomatorTestOptions, RunTestsCommand),
     'monkey': CommandFunctionTuple(
         AddMonkeyTestOptions, RunTestsCommand),
+    'perf': CommandFunctionTuple(
+        AddPerfTestOptions, RunTestsCommand),
     'help': CommandFunctionTuple(lambda option_parser: None, HelpCommand)
     }
 
 
-class CommandOptionParser(optparse.OptionParser):
-  """Wrapper class for OptionParser to help with listing commands."""
-
-  def __init__(self, *args, **kwargs):
-    self.command_list = kwargs.pop('command_list', [])
-    self.example = kwargs.pop('example', '')
-    optparse.OptionParser.__init__(self, *args, **kwargs)
-
-  #override
-  def get_usage(self):
-    normal_usage = optparse.OptionParser.get_usage(self)
-    command_list = self.get_command_list()
-    example = self.get_example()
-    return self.expand_prog_name(normal_usage + example + command_list)
-
-  #override
-  def get_command_list(self):
-    if self.command_list:
-      return '\nCommands:\n  %s\n' % '\n  '.join(sorted(self.command_list))
-    return ''
-
-  def get_example(self):
-    if self.example:
-      return '\nExample:\n  %s\n' % self.example
-    return ''
-
-
 def main(argv):
-  option_parser = CommandOptionParser(
-      usage='Usage: %prog <command> [options]',
-      command_list=VALID_COMMANDS.keys())
-
-  if len(argv) < 2 or argv[1] not in VALID_COMMANDS:
-    option_parser.error('Invalid command.')
-  command = argv[1]
-  VALID_COMMANDS[command].add_options_func(option_parser)
-  options, args = option_parser.parse_args(argv)
-  return VALID_COMMANDS[command].run_command_func(
-      command, options, args, option_parser)
+  option_parser = command_option_parser.CommandOptionParser(
+      commands_dict=VALID_COMMANDS)
+  return command_option_parser.ParseAndExecute(option_parser)
 
 
 if __name__ == '__main__':
diff --git a/build/android/update_verification.py b/build/android/update_verification.py
new file mode 100755
index 0000000..0c349c3
--- /dev/null
+++ b/build/android/update_verification.py
@@ -0,0 +1,135 @@
+#!/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.
+
+"""Runs semi-automated update testing on a non-rooted device."""
+import logging
+import optparse
+import os
+import shutil
+import sys
+import time
+
+from pylib import android_commands
+
+
+def _SaveAppData(adb, package_name, from_apk=None, data_dir=None):
+  def _BackupAppData(data_dir=None):
+    adb.Adb().SendCommand('backup %s' % package_name)
+    backup_file = os.path.join(os.getcwd(), 'backup.ab')
+    assert os.path.exists(backup_file), 'Backup failed.'
+    if data_dir:
+      if not os.path.isdir(data_dir):
+        os.makedirs(data_dir)
+      shutil.move(backup_file, data_dir)
+      backup_file = os.path.join(data_dir, 'backup.ab')
+    print 'Application data saved to %s' % backup_file
+
+  if from_apk:
+    logging.info('Installing %s...', from_apk)
+    output = adb.Install(from_apk, reinstall=True)
+    if 'Success' not in output:
+      raise Exception('Unable to install %s. output: %s' % (from_apk, output))
+
+  raw_input('Set the application state. Once ready, press enter and '
+            'select "Backup my data" on the device.')
+  _BackupAppData(data_dir)
+
+
+def _VerifyAppUpdate(adb, to_apk, app_data, from_apk=None):
+  def _RestoreAppData():
+    assert os.path.exists(app_data), 'Backup file does not exist!'
+    adb.Adb().SendCommand('restore %s' % app_data)
+    # It seems restore command is not synchronous.
+    time.sleep(15)
+
+  if from_apk:
+    logging.info('Installing %s...', from_apk)
+    output = adb.Install(from_apk, reinstall=True)
+    if 'Success' not in output:
+      raise Exception('Unable to install %s. output: %s' % (from_apk, output))
+
+  logging.info('Restoring the application data...')
+  raw_input('Press enter and select "Restore my data" on the device.')
+  _RestoreAppData()
+
+  logging.info('Verifying that %s cannot be installed side-by-side...',
+               to_apk)
+  output = adb.Install(to_apk)
+  if 'INSTALL_FAILED_ALREADY_EXISTS' not in output:
+    if 'Success' in output:
+      raise Exception('Package name has changed! output: %s' % output)
+    else:
+      raise Exception(output)
+
+  logging.info('Verifying that %s can be overinstalled...', to_apk)
+  output = adb.Install(to_apk, reinstall=True)
+  if 'Success' not in output:
+    raise Exception('Unable to install %s.\n output: %s' % (to_apk, output))
+  logging.info('Successfully updated to the new apk. Please verify that the '
+               'the application data is preserved.')
+
+
+def main():
+  logger = logging.getLogger()
+  logger.setLevel(logging.DEBUG)
+  desc = (
+      'Performs semi-automated application update verification testing. '
+      'When given --save, it takes a snapshot of the application data '
+      'on the device. (A dialog on the device will prompt the user to grant '
+      'permission to backup the data.) Otherwise, it performs the update '
+      'testing as follows: '
+      '1. Installs the |from-apk| (optional). '
+      '2. Restores the previously stored snapshot of application data '
+      'given by |app-data| '
+      '(A dialog on the device will prompt the user to grant permission to '
+      'restore the data.) '
+      '3. Verifies that |to-apk| cannot be installed side-by-side. '
+      '4. Verifies that |to-apk| can replace |from-apk|.')
+  parser = optparse.OptionParser(description=desc)
+  parser.add_option('--package-name', help='Package name for the application.')
+  parser.add_option('--save', action='store_true',
+                    help=('Save a snapshot of application data. '
+                          'This will be saved as backup.db in the '
+                          'current directory if |app-data| directory '
+                          'is not specifid.'))
+  parser.add_option('--from-apk',
+                    help=('APK to update from. This is optional if you already '
+                          'have the app installed.'))
+  parser.add_option('--to-apk', help='APK to update to.')
+  parser.add_option('--app-data',
+                    help=('Path to the application data to be restored or the '
+                          'directory where the data should be saved.'))
+  (options, args) = parser.parse_args()
+
+  if args:
+    parser.print_help(sys.stderr)
+    parser.error('Unknown arguments: %s.' % args)
+
+  if len(android_commands.GetAttachedDevices()) != 1:
+    parser.error('Exactly 1 device must be attached.')
+  adb = android_commands.AndroidCommands()
+
+  if options.from_apk:
+    assert os.path.isfile(options.from_apk)
+
+  if options.save:
+    if not options.package_name:
+      parser.print_help(sys.stderr)
+      parser.error('Missing --package-name.')
+    _SaveAppData(adb, options.package_name, from_apk=options.from_apk,
+                 data_dir=options.app_data)
+  else:
+    if not options.to_apk or not options.app_data:
+      parser.print_help(sys.stderr)
+      parser.error('Missing --to-apk or --app-data.')
+    assert os.path.isfile(options.to_apk)
+    assert os.path.isfile(options.app_data)
+    _VerifyAppUpdate(adb, options.to_apk, options.app_data,
+                     from_apk=options.from_apk)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build/common.gypi b/build/common.gypi
index e95efab..e70eaac 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -523,10 +523,8 @@
           'enable_automation%': 0,
           'enable_extensions%': 0,
           'enable_google_now%': 0,
-          'enable_printing%': 0,
           'enable_spellcheck%': 0,
           'enable_themes%': 0,
-          'proprietary_codecs%': 1,
           'remoting%': 0,
           'arm_neon%': 0,
           'arm_neon_optional%': 1,
@@ -534,6 +532,22 @@
           'native_memory_pressure_signals%': 1,
         }],
 
+        # Enable basic printing for Chrome for Android but disable printing
+        # completely for WebView.
+        ['OS=="android" and android_webview_build==0', {
+          'enable_printing%': 2,
+        }],
+        ['OS=="android" and android_webview_build==1', {
+          'enable_printing%': 0,
+        }],
+
+        # Android OS includes support for proprietary codecs regardless of
+        # building Chromium or Google Chrome. We also ship Google Chrome with
+        # proprietary codecs.
+        ['OS=="android" or branding=="Chrome"', {
+          'proprietary_codecs%': 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
@@ -910,6 +924,10 @@
     # Currently ignored on Windows.
     'coverage%': 0,
 
+    # Set to 1 to enable java code coverage. Instruments classes during build
+    # to produce .ec files during runtime.
+    'emma_coverage%': 0,
+
     # Set to 1 to force Visual C++ to use legacy debug information format /Z7.
     # This is useful for parallel compilation tools which can't support /Zi.
     # Only used on Windows.
@@ -923,9 +941,6 @@
     # to ~/.gyp/include.gypi, gclient runhooks --force, and do a release build.
     'win_use_allocator_shim%': 1, # 1 = shim allocator via libcmt; 0 = msvcrt
 
-    # Whether usage of OpenMAX is enabled.
-    'enable_openmax%': 0,
-
     # Whether proprietary audio/video codecs are assumed to be included with
     # this build (only meaningful if branding!=Chrome).
     'proprietary_codecs%': 0,
@@ -1435,6 +1450,9 @@
           }],
           ['component=="shared_library"', {
             'win_use_allocator_shim%': 0,
+          },{
+            # Turn on multiple dll by default on Windows when in static_library.
+            'chrome_multiple_dll%': 1,
           }],
           ['component=="shared_library" and "<(GENERATOR)"=="ninja"', {
             # Only enabled by default for ninja because it's buggy in VS.
@@ -1571,8 +1589,7 @@
       }],
       ['OS == "ios"', {
         'grit_defines': [
-          # define for iOS specific resources.
-          '-D', 'ios',
+          '-t', 'ios',
           # iOS uses a whitelist to filter resources.
           '-w', '<(DEPTH)/build/ios/grit_whitelist.txt'
         ],
@@ -1899,9 +1916,6 @@
           '<(DEPTH)/base/allocator/allocator.gyp:type_profiler',
         ],
       }],
-      ['chrome_multiple_dll', {
-        'defines': ['CHROME_MULTIPLE_DLL'],
-      }],
       ['OS=="linux" and clang==1 and host_arch=="ia32"', {
         # TODO(dmikurube): Remove -Wno-sentinel when Clang/LLVM is fixed.
         # See http://crbug.com/162818.
@@ -2989,6 +3003,7 @@
                   ['chromeos==1 and disable_sse2==0', {
                     'cflags': [
                       '-msse2',
+                      '-mfpmath=sse',
                     ],
                   }],
                   # Use gold linker for Android ia32 target.
diff --git a/build/filename_rules.gypi b/build/filename_rules.gypi
index a8d429b..cf8c357 100644
--- a/build/filename_rules.gypi
+++ b/build/filename_rules.gypi
@@ -86,7 +86,7 @@
       ]
     }],
     ['<(use_aura)==0 or <(use_x11)==0 or >(nacl_untrusted_build)==1', {
-      'sources/': [ ['exclude', '_aurax11\\.(h|cc)$'] ]
+      'sources/': [ ['exclude', '_aurax11(_browsertest|_unittest)?\\.(h|cc)$'] ]
     }],
     ['<(use_aura)==0 or OS!="win" or >(nacl_untrusted_build)==1', {
       'sources/': [ ['exclude', '_aurawin\\.(h|cc)$'] ]
diff --git a/build/gdb-add-index b/build/gdb-add-index
index 4975532..0d66d8d 100755
--- a/build/gdb-add-index
+++ b/build/gdb-add-index
@@ -4,8 +4,84 @@
 # found in the LICENSE file.
 #
 # Saves the gdb index for a given binary and its shared library dependencies.
+#
+# This will run gdb index in parallel on a number of binaries using SIGUSR1
+# as the communication mechanism to simulate a semaphore. Because of the
+# nature of this technique, using "set -e" is very difficult. The SIGUSR1
+# terminates a "wait" with an error which we need to interpret.
+#
+# When modifying this code, most of the real logic is in the index_one_file
+# function. The rest is cleanup + sempahore plumbing.
 
-set -e
+# Cleanup temp directory and ensure all child jobs are dead-dead.
+function on_exit {
+  trap "" EXIT USR1  # Avoid reentrancy.
+
+  local jobs=$(jobs -p)
+  if [ -n "$jobs" ]; then
+    echo -n "Killing outstanding index jobs..."
+    kill -KILL $(jobs -p)
+    wait
+    echo "done"
+  fi
+
+  if [ -f "$DIRECTORY" ]; then
+    echo -n "Removing temp directory $DIRECTORY..."
+    rm -rf $DIRECTORY
+    echo done
+  fi
+}
+
+# Add index to one binary.
+function index_one_file {
+  local file=$1
+  local basename=$(basename "$file")
+
+  local readelf_out=$(readelf -S "$file")
+  if [[ $readelf_out =~ "gdb_index" ]]; then
+    echo "Skipped $basename -- already contains index."
+  else
+    local start=$(date +"%s%N")
+    echo "Adding index to $basename..."
+
+    gdb -batch "$file" -ex "save gdb-index $DIRECTORY" -ex "quit"
+    local index_file="$DIRECTORY/$basename.gdb-index"
+    if [ -f "$index_file" ]; then
+      objcopy --add-section .gdb_index="$index_file" \
+        --set-section-flags .gdb_index=readonly "$file" "$file"
+      local finish=$(date +"%s%N")
+      local elappsed=$(((finish - start)/1000000))
+      echo "   ...$basename indexed. [${elappsed}ms]"
+    else
+      echo "   ...$basename unindexable."
+    fi
+  fi
+}
+
+# Functions that when combined, concurrently index all files in FILES_TO_INDEX
+# array. The global FILES_TO_INDEX is declared in the main body of the script.
+function async_index {
+  # Start a background subshell to run the index command.
+  {
+    index_one_file $1
+    kill -SIGUSR1 $$  # $$ resolves to the parent script.
+    exit 129  # See comment above wait loop at bottom.
+  } &
+}
+
+CUR_FILE_NUM=0
+function index_next {
+  if (( CUR_FILE_NUM >= ${#FILES_TO_INDEX[@]} )); then
+    return
+  fi
+
+  async_index "${FILES_TO_INDEX[CUR_FILE_NUM]}"
+  ((CUR_FILE_NUM += 1)) || true
+}
+
+
+########
+### Main body of the script.
 
 if [[ ! $# == 1 ]]; then
   echo "Usage: $0 path-to-binary"
@@ -18,30 +94,38 @@
   exit 1
 fi
 
+# Ensure we cleanup on on exit.
+trap on_exit EXIT
+
 # We're good to go! Create temp directory for index files.
 DIRECTORY=$(mktemp -d)
 echo "Made temp directory $DIRECTORY."
 
-# Always remove directory on exit.
-trap "{ echo -n Removing temp directory $DIRECTORY...;
-  rm -rf $DIRECTORY; echo done; }" EXIT
-
-# Grab all the chromium shared library files.
-so_files=$(ldd "$FILENAME" 2>/dev/null \
+# Create array with the filename and all shared libraries that
+# have the same dirname. The dirname is a signal that these
+# shared libraries were part of the same build as the binary.
+declare -a FILES_TO_INDEX=($FILENAME
+ $(ldd "$FILENAME" 2>/dev/null \
   | grep $(dirname "$FILENAME") \
   | sed "s/.*[ \t]\(.*\) (.*/\1/")
+)
 
-# Add index to binary and the shared library dependencies.
-for file in "$FILENAME" $so_files; do
-  basename=$(basename "$file")
-  echo -n "Adding index to $basename..."
-  readelf_out=$(readelf -S "$file")
-  if [[ $readelf_out =~ "gdb_index" ]]; then
-    echo "already contains index. Skipped."
-  else
-    gdb -batch "$file" -ex "save gdb-index $DIRECTORY" -ex "quit"
-    objcopy --add-section .gdb_index="$DIRECTORY"/$basename.gdb-index \
-      --set-section-flags .gdb_index=readonly "$file" "$file"
-    echo "done."
-  fi
+# Start concurrent indexing.
+trap index_next USR1
+
+# 4 is an arbitrary default. When changing, remember we are likely IO bound
+# so basing this off the number of cores is not sensible.
+INDEX_TASKS=${INDEX_TASKS:-4}
+for ((i=0;i<${INDEX_TASKS};i++)); do
+  index_next
+done
+
+# Do a wait loop. Bash waits that terminate due a trap have an exit
+# code > 128. We also ensure that our subshell's "normal" exit occurs with
+# an exit code > 128. This allows us to do consider a > 128 exit code as
+# an indication that the loop should continue. Unfortunately, it also means
+# we cannot use set -e since technically the "wait" is failing.
+wait
+while (( $? > 128 )); do
+  wait
 done
diff --git a/build/get_landmines.py b/build/get_landmines.py
new file mode 100755
index 0000000..05c9de6
--- /dev/null
+++ b/build/get_landmines.py
@@ -0,0 +1,63 @@
+#!/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.
+
+"""
+This file emits the list of reasons why a particular build needs to be clobbered
+(or a list of 'landmines').
+"""
+
+import optparse
+import sys
+
+import landmine_utils
+
+
+builder = landmine_utils.platform
+distributor = landmine_utils.distributor
+gyp_defines = landmine_utils.gyp_defines
+gyp_msvs_version = landmine_utils.gyp_msvs_version
+platform = landmine_utils.platform
+
+
+def print_landmines(target):
+  """
+  ALL LANDMINES ARE EMITTED FROM HERE.
+  target can be one of {'Release', 'Debug', 'Debug_x64', 'Release_x64'}.
+  """
+  if (distributor() == 'goma' and platform() == 'win32' and
+      builder() == 'ninja'):
+    print 'Need to clobber winja goma due to backend cwd cache fix.'
+  if platform() == 'android':
+    print 'Clobber: Resources removed in r195014 require clobber.'
+  if platform() == 'win' and builder() == 'ninja':
+    print 'Compile on cc_unittests fails due to symbols removed in r185063.'
+  if platform() == 'linux' and builder() == 'ninja':
+    print 'Builders switching from make to ninja will clobber on this.'
+  if platform() == 'mac':
+    print 'Switching from bundle to unbundled dylib (issue 14743002).'
+  if (platform() == 'win' and builder() == 'ninja' and
+      gyp_msvs_version() == '2012' and
+      gyp_defines().get('target_arch') == 'x64' and
+      gyp_defines().get('dcheck_always_on') == '1'):
+    print "Switched win x64 trybots from VS2010 to VS2012."
+  print 'Need to clobber everything due to an IDL change in r154579 (blink)'
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('-t', '--target',
+                    help=='Target for which the landmines have to be emitted')
+
+  options, args = parser.parse_args()
+
+  if args:
+    parser.error('Unknown arguments %s' % args)
+
+  print_landmines(options.target)
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index c72022c..ed15d46 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -565,8 +565,6 @@
 IDS_FLAGS_ENABLE_PASSWORD_GENERATION_NAME
 IDS_FLAGS_ENABLE_PINCH_SCALE_DESCRIPTION
 IDS_FLAGS_ENABLE_PINCH_SCALE_NAME
-IDS_FLAGS_ENABLE_PNACL_DESCRIPTION
-IDS_FLAGS_ENABLE_PNACL_NAME
 IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_DESCRIPTION
 IDS_FLAGS_ENABLE_REQUEST_TABLET_SITE_NAME
 IDS_FLAGS_ENABLE_RICH_NOTIFICATIONS_DESCRIPTION
@@ -672,6 +670,8 @@
 IDS_FLAGS_PERFORMANCE_MONITOR_GATHERING_NAME
 IDS_FLAGS_PER_TILE_PAINTING_DESCRIPTION
 IDS_FLAGS_PER_TILE_PAINTING_NAME
+IDS_FLAGS_PNACL_DESCRIPTION
+IDS_FLAGS_PNACL_NAME
 IDS_FLAGS_PRESENT_WITH_GDI_ALL_SHOW
 IDS_FLAGS_PRESENT_WITH_GDI_DESCRIPTION
 IDS_FLAGS_PRESENT_WITH_GDI_FIRST_SHOW
diff --git a/build/java.gypi b/build/java.gypi
index 1635c71..95858ee 100644
--- a/build/java.gypi
+++ b/build/java.gypi
@@ -55,8 +55,11 @@
     'additional_src_dirs': [],
     'javac_includes': [],
     'jar_name': '<(_target_name).jar',
-    'jar_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
+    'jar_dir': '<(PRODUCT_DIR)/lib.java',
+    'jar_path': '<(intermediate_dir)/<(jar_name)',
+    'jar_final_path': '<(jar_dir)/<(jar_name)',
     'jar_excluded_classes': [ '*/R.class', '*/R##*.class' ],
+    'instr_stamp': '<(intermediate_dir)/instr.stamp',
     'additional_input_paths': [],
     'dex_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).dex.jar',
     'generated_src_dirs': ['>@(generated_R_dirs)'],
@@ -70,12 +73,34 @@
     'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
     'classes_dir': '<(intermediate_dir)/classes',
     'compile_stamp': '<(intermediate_dir)/compile.stamp',
+    'proguard_config%': '',
+    'proguard_preprocess%': '0',
+    'variables': {
+      'variables': {
+        'proguard_preprocess%': 0,
+      },
+      'conditions': [
+        ['proguard_preprocess == 1', {
+          'javac_jar_path': '<(intermediate_dir)/<(_target_name).pre.jar'
+        }, {
+          'javac_jar_path': '<(jar_path)'
+        }],
+      ],
+    },
+    'javac_jar_path': '<(javac_jar_path)',
+    'conditions': [
+      ['chromium_code != 0 and emma_coverage != 0', {
+        'emma_instrument': 1,
+      }, {
+        'emma_instrument': 0,
+      }],
+    ],
   },
   # This all_dependent_settings is used for java targets only. This will add the
   # jar path to the classpath of dependent java targets.
   'all_dependent_settings': {
     'variables': {
-      'input_jars_paths': ['<(jar_path)'],
+      'input_jars_paths': ['<(jar_final_path)'],
       'library_dexed_jars_paths': ['<(dex_path)'],
     },
   },
@@ -218,6 +243,35 @@
         },
       ],
     }],
+    ['proguard_preprocess == 1', {
+      'actions': [
+        {
+          'action_name': 'proguard_<(_target_name)',
+          'message': 'Proguard preprocessing <(_target_name) jar',
+          'inputs': [
+            '<(android_sdk_root)/tools/proguard/bin/proguard.sh',
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/proguard.py',
+            '<(javac_jar_path)',
+            '<(proguard_config)',
+          ],
+          'outputs': [
+            '<(jar_path)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/proguard.py',
+            '--proguard-path=<(android_sdk_root)/tools/proguard/bin/proguard.sh',
+            '--input-path=<(javac_jar_path)',
+            '--output-path=<(jar_path)',
+            '--proguard-config=<(proguard_config)',
+            '--classpath=<(android_sdk_jar) >(input_jars_paths)',
+
+            # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
+            '--ignore=>!(echo \'>(_inputs)\' | md5sum)',
+          ]
+        },
+      ],
+    }],
   ],
   'actions': [
     {
@@ -263,12 +317,12 @@
         '<(compile_stamp)',
       ],
       'outputs': [
-        '<(jar_path)',
+        '<(javac_jar_path)',
       ],
       'action': [
         'python', '<(DEPTH)/build/android/gyp/jar.py',
         '--classes-dir=<(classes_dir)',
-        '--jar-path=<(jar_path)',
+        '--jar-path=<(javac_jar_path)',
         '--excluded-classes=<(jar_excluded_classes)',
 
         # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
@@ -276,21 +330,38 @@
       ]
     },
     {
+      'action_name': 'instr_jar_<(_target_name)',
+      'message': 'Instrumenting <(_target_name) jar',
+      'variables': {
+        'input_path': '<(jar_path)',
+        'output_path': '<(jar_final_path)',
+        'stamp_path': '<(instr_stamp)',
+        'instr_type': 'jar',
+      },
+      'outputs': [
+        '<(jar_final_path)',
+      ],
+      'inputs': [
+        '<(jar_path)',
+      ],
+      'includes': [ 'android/instr_action.gypi' ],
+    },
+    {
       'action_name': 'jar_toc_<(_target_name)',
       'message': 'Creating <(_target_name) jar.TOC',
       'inputs': [
         '<(DEPTH)/build/android/gyp/util/build_utils.py',
         '<(DEPTH)/build/android/gyp/util/md5_check.py',
         '<(DEPTH)/build/android/gyp/jar_toc.py',
-        '<(jar_path)',
+        '<(jar_final_path)',
       ],
       'outputs': [
-        '<(jar_path).TOC',
+        '<(jar_final_path).TOC',
       ],
       'action': [
         'python', '<(DEPTH)/build/android/gyp/jar_toc.py',
-        '--jar-path=<(jar_path)',
-        '--toc-path=<(jar_path).TOC',
+        '--jar-path=<(jar_final_path)',
+        '--toc-path=<(jar_final_path).TOC',
 
         # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
         '--ignore=>!(echo \'>(_inputs)\' | md5sum)',
@@ -299,7 +370,12 @@
     {
       'action_name': 'dex_<(_target_name)',
       'variables': {
-        'dex_input_paths': [ '<(jar_path)' ],
+        'conditions': [
+          ['emma_instrument != 0', {
+            'dex_no_locals': 1,
+          }],
+        ],
+        'dex_input_paths': [ '<(jar_final_path)' ],
         'output_path': '<(dex_path)',
       },
       'includes': [ 'android/dex_action.gypi' ],
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 2457d3a..d8a6cac 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -87,15 +87,18 @@
     'native_libraries_template_data_file': '<(native_libraries_template_data_dir)/native_libraries_array.h',
     'native_libraries_template_data_stamp': '<(intermediate_dir)/native_libraries_template_data.stamp',
     'compile_stamp': '<(intermediate_dir)/compile.stamp',
+    'instr_stamp': '<(intermediate_dir)/instr.stamp',
     'jar_stamp': '<(intermediate_dir)/jar.stamp',
     'obfuscate_stamp': '<(intermediate_dir)/obfuscate.stamp',
     'strip_stamp': '<(intermediate_dir)/strip.stamp',
     'classes_dir': '<(intermediate_dir)/classes',
+    'classes_final_dir': '<(intermediate_dir)/classes_instr',
     'javac_includes': [],
     'jar_excluded_classes': [],
     'jar_path': '<(PRODUCT_DIR)/lib.java/<(jar_name)',
     'obfuscated_jar_path': '<(intermediate_dir)/obfuscated.jar',
     'dex_path': '<(intermediate_dir)/classes.dex',
+    'emma_device_jar': '<(android_sdk_root)/tools/lib/emma_device.jar',
     'android_manifest_path%': '<(java_in_dir)/AndroidManifest.xml',
     'push_stamp': '<(intermediate_dir)/push.stamp',
     'link_stamp': '<(intermediate_dir)/link.stamp',
@@ -128,6 +131,7 @@
       ],
     },
     'native_lib_target%': '',
+    'emma_instrument': '<(emma_coverage)',
     'apk_package_native_libs_dir': '<(apk_package_native_libs_dir)',
     'unsigned_standalone_apk_path': '<(unsigned_standalone_apk_path)',
   },
@@ -371,6 +375,11 @@
         },
       ],
     }],
+    ['is_test_apk == 1', {
+      'dependencies': [
+        '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
+      ]
+    }],
   ],
   'actions': [
     {
@@ -461,20 +470,37 @@
       ],
     },
     {
+      'action_name': 'instr_classes_<(_target_name)',
+      'message': 'Instrumenting <(_target_name) classes',
+      'variables': {
+        'input_path': '<(classes_dir)',
+        'output_path': '<(classes_final_dir)',
+        'stamp_path': '<(instr_stamp)',
+        'instr_type': 'classes',
+      },
+      'outputs': [
+        '<(instr_stamp)',
+      ],
+      'inputs': [
+        '<(compile_stamp)',
+      ],
+      'includes': [ 'android/instr_action.gypi' ],
+    },
+    {
       'action_name': 'jar_<(_target_name)',
       'message': 'Creating <(_target_name) jar',
       'inputs': [
+        '<(instr_stamp)',
         '<(DEPTH)/build/android/gyp/util/build_utils.py',
         '<(DEPTH)/build/android/gyp/util/md5_check.py',
         '<(DEPTH)/build/android/gyp/jar.py',
-        '<(compile_stamp)',
       ],
       'outputs': [
         '<(jar_stamp)',
       ],
       'action': [
         'python', '<(DEPTH)/build/android/gyp/jar.py',
-        '--classes-dir=<(classes_dir)',
+        '--classes-dir=<(classes_final_dir)',
         '--jar-path=<(jar_path)',
         '--excluded-classes=<(jar_excluded_classes)',
         '--stamp=<(jar_stamp)',
@@ -491,7 +517,7 @@
         '<(DEPTH)/build/android/ant/create-test-jar.js',
         '<(DEPTH)/build/android/gyp/util/build_utils.py',
         '<(DEPTH)/build/android/gyp/ant.py',
-        '<(compile_stamp)',
+        '<(instr_stamp)',
         '>@(proguard_flags_paths)',
       ],
       'outputs': [
@@ -537,10 +563,16 @@
             'input_paths': [ '<(obfuscate_stamp)' ],
             'proguard_enabled_input_path': '<(obfuscated_jar_path)',
           }],
+          ['emma_instrument != 0', {
+            'dex_no_locals': 1,
+          }],
+          ['emma_instrument != 0 and is_test_apk == 0', {
+            'dex_input_paths': [ '<(emma_device_jar)' ],
+          }],
         ],
-        'input_paths': [ '<(compile_stamp)' ],
+        'input_paths': [ '<(instr_stamp)' ],
         'dex_input_paths': [ '>@(library_dexed_jars_paths)' ],
-        'dex_generated_input_dirs': [ '<(classes_dir)' ],
+        'dex_generated_input_dirs': [ '<(classes_final_dir)' ],
         'output_path': '<(dex_path)',
       },
       'includes': [ 'android/dex_action.gypi' ],
@@ -625,6 +657,8 @@
         '-DOUT_DIR=<(intermediate_dir)',
         '-DSOURCE_DIR=<(source_dir)',
         '-DUNSIGNED_APK_PATH=<(unsigned_apk_path)',
+        '-DEMMA_INSTRUMENT=<(emma_instrument)',
+        '-DEMMA_DEVICE_JAR=<(emma_device_jar)',
 
         '-Dbasedir=.',
         '-buildfile',
diff --git a/build/java_prebuilt.gypi b/build/java_prebuilt.gypi
index 8000374..cec881d 100644
--- a/build/java_prebuilt.gypi
+++ b/build/java_prebuilt.gypi
@@ -24,13 +24,62 @@
   ],
   'variables': {
     'dex_path': '<(PRODUCT_DIR)/lib.java/<(_target_name).dex.jar',
+    'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
+    'android_jar': '<(android_sdk)/android.jar',
+    'input_jars_paths': [ '<(android_jar)' ],
+    'proguard_config%': '',
+    'proguard_preprocess%': '0',
+    'variables': {
+      'variables': {
+        'proguard_preprocess%': 0,
+      },
+      'conditions': [
+        ['proguard_preprocess == 1', {
+          'dex_input_jar_path': '<(intermediate_dir)/<(_target_name).pre.jar'
+        }, {
+          'dex_input_jar_path': '<(jar_path)'
+        }],
+      ],
+    },
+    'dex_input_jar_path': '<(dex_input_jar_path)',
   },
   'all_dependent_settings': {
     'variables': {
-      'input_jars_paths': ['<(jar_path)'],
+      'input_jars_paths': ['<(dex_input_jar_path)'],
       'library_dexed_jars_paths': ['<(dex_path)'],
     },
   },
+  'conditions' : [
+    ['proguard_preprocess == 1', {
+      'actions': [
+        {
+          'action_name': 'proguard_<(_target_name)',
+          'message': 'Proguard preprocessing <(_target_name) jar',
+          'inputs': [
+            '<(android_sdk_root)/tools/proguard/bin/proguard.sh',
+            '<(DEPTH)/build/android/gyp/util/build_utils.py',
+            '<(DEPTH)/build/android/gyp/proguard.py',
+            '<(jar_path)',
+            '<(proguard_config)',
+          ],
+          'outputs': [
+            '<(dex_input_jar_path)',
+          ],
+          'action': [
+            'python', '<(DEPTH)/build/android/gyp/proguard.py',
+            '--proguard-path=<(android_sdk_root)/tools/proguard/bin/proguard.sh',
+            '--input-path=<(jar_path)',
+            '--output-path=<(dex_input_jar_path)',
+            '--proguard-config=<(proguard_config)',
+            '--classpath=>(input_jars_paths)',
+
+            # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
+            '--ignore=>!(echo \'>(_inputs)\' | md5sum)',
+          ]
+        },
+      ],
+    }],
+  ],
   'actions': [
     {
       'action_name': 'dex_<(_target_name)',
@@ -38,7 +87,7 @@
       'inputs': [
         '<(DEPTH)/build/android/gyp/util/build_utils.py',
         '<(DEPTH)/build/android/gyp/dex.py',
-        '<(jar_path)',
+        '<(dex_input_jar_path)',
       ],
       'outputs': [
         '<(dex_path)',
@@ -51,7 +100,7 @@
         # TODO(newt): remove this once http://crbug.com/177552 is fixed in ninja.
         '--ignore=>!(echo \'>(_inputs)\' | md5sum)',
 
-        '<(jar_path)',
+        '<(dex_input_jar_path)',
       ]
     },
 
diff --git a/build/landmine_utils.py b/build/landmine_utils.py
new file mode 100644
index 0000000..021fc9b
--- /dev/null
+++ b/build/landmine_utils.py
@@ -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.
+
+
+import functools
+import logging
+import os
+import shlex
+import sys
+
+
+def memoize(default=None):
+  """This decorator caches the return value of a parameterless pure function"""
+  def memoizer(func):
+    val = []
+    @functools.wraps(func)
+    def inner():
+      if not val:
+        ret = func()
+        val.append(ret if ret is not None else default)
+        if logging.getLogger().isEnabledFor(logging.INFO):
+          print '%s -> %r' % (func.__name__, val[0])
+      return val[0]
+    return inner
+  return memoizer
+
+
+@memoize()
+def IsWindows():
+  return sys.platform in ['win32', 'cygwin']
+
+
+@memoize()
+def IsLinux():
+  return sys.platform.startswith('linux')
+
+
+@memoize()
+def IsMac():
+  return sys.platform == 'darwin'
+
+
+@memoize()
+def gyp_defines():
+  """Parses and returns GYP_DEFINES env var as a dictionary."""
+  return dict(arg.split('=', 1)
+      for arg in shlex.split(os.environ.get('GYP_DEFINES', '')))
+
+@memoize()
+def gyp_msvs_version():
+  return os.environ.get('GYP_MSVS_VERSION', '')
+
+@memoize()
+def distributor():
+  """
+  Returns a string which is the distributed build engine in use (if any).
+  Possible values: 'goma', 'ib', ''
+  """
+  if 'goma' in gyp_defines():
+    return 'goma'
+  elif IsWindows():
+    if 'CHROME_HEADLESS' in os.environ:
+      return 'ib' # use (win and !goma and headless) as approximation of ib
+
+
+@memoize()
+def platform():
+  """
+  Returns a string representing the platform this build is targetted for.
+  Possible values: 'win', 'mac', 'linux', 'ios', 'android'
+  """
+  if 'OS' in gyp_defines():
+    if 'android' in gyp_defines()['OS']:
+      return 'android'
+    else:
+      return gyp_defines()['OS']
+  elif IsWindows():
+    return 'win'
+  elif IsLinux():
+    return 'linux'
+  else:
+    return 'mac'
+
+
+@memoize()
+def builder():
+  """
+  Returns a string representing the build engine (not compiler) to use.
+  Possible values: 'make', 'ninja', 'xcode', 'msvs', 'scons'
+  """
+  if 'GYP_GENERATORS' in os.environ:
+    # for simplicity, only support the first explicit generator
+    generator = os.environ['GYP_GENERATORS'].split(',')[0]
+    if generator.endswith('-android'):
+      return generator.split('-')[0]
+    elif generator.endswith('-ninja'):
+      return 'ninja'
+    else:
+      return generator
+  else:
+    if platform() == 'android':
+      # Good enough for now? Do any android bots use make?
+      return 'ninja'
+    elif platform() == 'ios':
+      return 'xcode'
+    elif IsWindows():
+      return 'msvs'
+    elif IsLinux():
+      return 'ninja'
+    elif IsMac():
+      return 'xcode'
+    else:
+      assert False, 'Don\'t know what builder we\'re using!'
diff --git a/build/landmines.py b/build/landmines.py
index c09ffb8..f1a514c 100755
--- a/build/landmines.py
+++ b/build/landmines.py
@@ -4,9 +4,6 @@
 # found in the LICENSE file.
 
 """
-This file holds a list of reasons why a particular build needs to be clobbered
-(or a list of 'landmines').
-
 This script runs every build as a hook. If it detects that the build should
 be clobbered, it will touch the file <build_dir>/.landmine_triggered. The
 various build scripts will then check for the presence of this file and clobber
@@ -18,149 +15,19 @@
 """
 
 import difflib
-import functools
 import gyp_helper
 import logging
 import optparse
 import os
-import shlex
 import sys
+import subprocess
 import time
 
+import landmine_utils
+
+
 SRC_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
 
-def memoize(default=None):
-  """This decorator caches the return value of a parameterless pure function"""
-  def memoizer(func):
-    val = []
-    @functools.wraps(func)
-    def inner():
-      if not val:
-        ret = func()
-        val.append(ret if ret is not None else default)
-        if logging.getLogger().isEnabledFor(logging.INFO):
-          print '%s -> %r' % (func.__name__, val[0])
-      return val[0]
-    return inner
-  return memoizer
-
-
-@memoize()
-def IsWindows():
-  return sys.platform in ['win32', 'cygwin']
-
-
-@memoize()
-def IsLinux():
-  return sys.platform.startswith('linux')
-
-
-@memoize()
-def IsMac():
-  return sys.platform == 'darwin'
-
-
-@memoize()
-def gyp_defines():
-  """Parses and returns GYP_DEFINES env var as a dictionary."""
-  return dict(arg.split('=', 1)
-      for arg in shlex.split(os.environ.get('GYP_DEFINES', '')))
-
-@memoize()
-def gyp_msvs_version():
-  return os.environ.get('GYP_MSVS_VERSION', '')
-
-@memoize()
-def distributor():
-  """
-  Returns a string which is the distributed build engine in use (if any).
-  Possible values: 'goma', 'ib', ''
-  """
-  if 'goma' in gyp_defines():
-    return 'goma'
-  elif IsWindows():
-    if 'CHROME_HEADLESS' in os.environ:
-      return 'ib' # use (win and !goma and headless) as approximation of ib
-
-
-@memoize()
-def platform():
-  """
-  Returns a string representing the platform this build is targetted for.
-  Possible values: 'win', 'mac', 'linux', 'ios', 'android'
-  """
-  if 'OS' in gyp_defines():
-    if 'android' in gyp_defines()['OS']:
-      return 'android'
-    else:
-      return gyp_defines()['OS']
-  elif IsWindows():
-    return 'win'
-  elif IsLinux():
-    return 'linux'
-  else:
-    return 'mac'
-
-
-@memoize()
-def builder():
-  """
-  Returns a string representing the build engine (not compiler) to use.
-  Possible values: 'make', 'ninja', 'xcode', 'msvs', 'scons'
-  """
-  if 'GYP_GENERATORS' in os.environ:
-    # for simplicity, only support the first explicit generator
-    generator = os.environ['GYP_GENERATORS'].split(',')[0]
-    if generator.endswith('-android'):
-      return generator.split('-')[0]
-    elif generator.endswith('-ninja'):
-      return 'ninja'
-    else:
-      return generator
-  else:
-    if platform() == 'android':
-      # Good enough for now? Do any android bots use make?
-      return 'ninja'
-    elif platform() == 'ios':
-      return 'xcode'
-    elif IsWindows():
-      return 'msvs'
-    elif IsLinux():
-      return 'ninja'
-    elif IsMac():
-      return 'xcode'
-    else:
-      assert False, 'Don\'t know what builder we\'re using!'
-
-
-def get_landmines(target):
-  """
-  ALL LANDMINES ARE DEFINED HERE.
-  target is 'Release' or 'Debug'
-  """
-  landmines = []
-  add = lambda item: landmines.append(item + '\n')
-
-  if (distributor() == 'goma' and platform() == 'win32' and
-      builder() == 'ninja'):
-    add('Need to clobber winja goma due to backend cwd cache fix.')
-  if platform() == 'android':
-    add('Clobber: Resources removed in r195014 require clobber.')
-  if platform() == 'win' and builder() == 'ninja':
-    add('Compile on cc_unittests fails due to symbols removed in r185063.')
-  if platform() == 'linux' and builder() == 'ninja':
-    add('Builders switching from make to ninja will clobber on this.')
-  if platform() == 'mac':
-    add('Switching from bundle to unbundled dylib (issue 14743002).')
-  if (platform() == 'win' and builder() == 'ninja' and
-      gyp_msvs_version() == '2012' and
-      gyp_defines().get('target_arch') == 'x64' and
-      gyp_defines().get('dcheck_always_on') == '1'):
-    add("Switched win x64 trybots from VS2010 to VS2012.")
-  add('Need to clobber everything due to an IDL change in r154579 (blink)')
-
-  return landmines
-
 
 def get_target_build_dir(build_tool, target, is_iphone=False):
   """
@@ -187,16 +54,15 @@
   return os.path.abspath(ret)
 
 
-def set_up_landmines(target):
+def set_up_landmines(target, new_landmines):
   """Does the work of setting, planting, and triggering landmines."""
-  out_dir = get_target_build_dir(builder(), target, platform() == 'ios')
+  out_dir = get_target_build_dir(landmine_utils.builder(), target,
+                                 landmine_utils.platform() == 'ios')
 
   landmines_path = os.path.join(out_dir, '.landmines')
   if not os.path.exists(out_dir):
     os.makedirs(out_dir)
 
-  new_landmines = get_landmines(target)
-
   if not os.path.exists(landmines_path):
     with open(landmines_path, 'w') as f:
       f.writelines(new_landmines)
@@ -219,11 +85,17 @@
 
 def main():
   parser = optparse.OptionParser()
+  parser.add_option(
+      '-s', '--landmine-scripts', action='append',
+      default=[os.path.join(SRC_DIR, 'build', 'get_landmines.py')],
+      help='Path to the script which emits landmines to stdout. The target '
+           'is passed to this script via option -t.')
   parser.add_option('-v', '--verbose', action='store_true',
       default=('LANDMINES_VERBOSE' in os.environ),
       help=('Emit some extra debugging information (default off). This option '
           'is also enabled by the presence of a LANDMINES_VERBOSE environment '
           'variable.'))
+
   options, args = parser.parse_args()
 
   if args:
@@ -235,7 +107,13 @@
   gyp_helper.apply_chromium_gyp_env()
 
   for target in ('Debug', 'Release', 'Debug_x64', 'Release_x64'):
-    set_up_landmines(target)
+    landmines = []
+    for s in options.landmine_scripts:
+      proc = subprocess.Popen([sys.executable, s, '-t', target],
+                              stdout=subprocess.PIPE)
+      output, _ = proc.communicate()
+      landmines.extend([('%s\n' % l.strip()) for l in output.splitlines()])
+    set_up_landmines(target, landmines)
 
   return 0
 
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 1db278f..c81bc35 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -122,9 +122,6 @@
         {
           'target_name': 'libgps',
           'type': 'static_library',
-          'dependencies': [
-            '../../base/base.gyp:base',
-          ],
           'all_dependent_settings': {
             'defines': [
               'USE_LIBGPS',
@@ -148,6 +145,9 @@
               }],
             ],
           },
+          'include_dirs': [
+            '../..',
+          ],
           'hard_dependency': 1,
           'actions': [
             {
@@ -202,7 +202,6 @@
             ['use_openssl==0 and use_system_ssl==0', {
               'dependencies': [
                 '../../net/third_party/nss/ssl.gyp:libssl',
-                '../../third_party/zlib/zlib.gyp:zlib',
               ],
               'direct_dependent_settings': {
                 'include_dirs+': [
@@ -325,9 +324,6 @@
       'type': 'static_library',
       'conditions': [
         ['use_gio==1 and _toolset=="target"', {
-          'dependencies': [
-            '../../base/base.gyp:base',
-          ],
           'cflags': [
             '<!@(<(pkg-config) --cflags gio-2.0)',
           ],
@@ -342,6 +338,9 @@
               '<(SHARED_INTERMEDIATE_DIR)',
             ],
           },
+          'include_dirs': [
+            '../..',
+          ],
           'link_settings': {
             'ldflags': [
               '<!@(<(pkg-config) --libs-only-L --libs-only-other gio-2.0)',
@@ -401,9 +400,6 @@
       'cflags': [
         '<!@(<(pkg-config) --cflags libpci)',
       ],
-      'dependencies': [
-        '../../base/base.gyp:base',
-      ],
       'direct_dependent_settings': {
         'include_dirs': [
           '<(SHARED_INTERMEDIATE_DIR)',
@@ -421,6 +417,9 @@
           }],
         ],
       },
+      'include_dirs': [
+        '../..',
+      ],
       'hard_dependency': 1,
       'actions': [
         {
@@ -462,9 +461,6 @@
     {
       'target_name': 'libspeechd',
       'type': 'static_library',
-      'dependencies': [
-        '../../base/base.gyp:base',
-      ],
       'direct_dependent_settings': {
         'include_dirs': [
           '<(SHARED_INTERMEDIATE_DIR)',
@@ -479,6 +475,9 @@
           }],
         ],
       },
+      'include_dirs': [
+        '../..',
+      ],
       'hard_dependency': 1,
       'actions': [
         {
diff --git a/build/linux/unbundle/README b/build/linux/unbundle/README
index 7027b9a..d1b2a96 100644
--- a/build/linux/unbundle/README
+++ b/build/linux/unbundle/README
@@ -17,12 +17,28 @@
 
 Usage:
 
-replace_gyp_files.py <gyp-flags>
+1. remove_bundled_libraries.py <preserved-directories>
 
-For example: replace_gyp_files.py -Duse_system_harfbuzz=1
+   For example: remove_bundled_libraries.py third_party/mesa
 
-The script ignores flags other than -D for convenience. This makes it possible
-to have a variable e.g. ${myconf} with all the options, and execute:
+   The script scans sources looking for third_party directories.
+   Everything that is not explicitly preserved is removed (except for
+   gyp files), and the script fails if any directory passed on command
+   line does not exist (to ensure list is kept up to date).
 
-build/linux/unbundle/replace_gyp_files.py ${myconf}
-build/gyp_chromium ${myconf}
+   This is intended to be used on sources extracted from a tarball,
+   not a repository.
+
+   NOTE: by default this will not remove anything (for safety). Pass
+   --do-remove flag to actually remove files.
+
+2. replace_gyp_files.py <gyp-flags>
+
+   For example: replace_gyp_files.py -Duse_system_harfbuzz=1
+
+   The script ignores flags other than -D for convenience. This makes it
+   possible to have a variable e.g. ${myconf} with all the options, and
+   execute:
+
+   build/linux/unbundle/replace_gyp_files.py ${myconf}
+   build/gyp_chromium ${myconf}
diff --git a/build/linux/unbundle/openssl.gyp b/build/linux/unbundle/openssl.gyp
new file mode 100644
index 0000000..d832ba7
--- /dev/null
+++ b/build/linux/unbundle/openssl.gyp
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'openssl',
+      'type': 'none',
+      'direct_dependent_settings': {
+        'cflags': [
+          '<!@(pkg-config --cflags openssl)',
+        ],
+      },
+      'link_settings': {
+        'ldflags': [
+          '<!@(pkg-config --libs-only-L --libs-only-other openssl)',
+        ],
+        'libraries': [
+          '<!@(pkg-config --libs-only-l openssl)',
+        ],
+      },
+    }
+  ],
+}
diff --git a/build/linux/unbundle/remove_bundled_libraries.py b/build/linux/unbundle/remove_bundled_libraries.py
new file mode 100755
index 0000000..09a9c62
--- /dev/null
+++ b/build/linux/unbundle/remove_bundled_libraries.py
@@ -0,0 +1,87 @@
+#!/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.
+
+"""
+Removes bundled libraries to make sure they are not used.
+
+See README for more details.
+"""
+
+
+import optparse
+import os.path
+import sys
+
+
+def DoMain(argv):
+  my_dirname = os.path.abspath(os.path.dirname(__file__))
+  source_tree_root = os.path.abspath(
+    os.path.join(my_dirname, '..', '..', '..'))
+
+  if os.path.join(source_tree_root, 'build', 'linux', 'unbundle') != my_dirname:
+    print ('Sanity check failed: please run this script from ' +
+           'build/linux/unbundle directory.')
+    return 1
+
+  parser = optparse.OptionParser()
+  parser.add_option('--do-remove', action='store_true')
+
+  options, args = parser.parse_args(argv)
+
+  exclusion_used = {}
+  for exclusion in args:
+    exclusion_used[exclusion] = False
+
+  for root, dirs, files in os.walk(source_tree_root, topdown=False):
+    # Only look at paths which contain a "third_party" component
+    # (note that e.g. third_party.png doesn't count).
+    root_relpath = os.path.relpath(root, source_tree_root)
+    if 'third_party' not in root_relpath.split(os.sep):
+      continue
+
+    for f in files:
+      path = os.path.join(root, f)
+      relpath = os.path.relpath(path, source_tree_root)
+
+      excluded = False
+      for exclusion in args:
+        if relpath.startswith(exclusion):
+          # Multiple exclusions can match the same path. Go through all of them
+          # and mark each one as used.
+          exclusion_used[exclusion] = True
+          excluded = True
+      if excluded:
+        continue
+
+      # Deleting gyp files almost always leads to gyp failures.
+      # These files come from Chromium project, and can be replaced if needed.
+      if f.endswith('.gyp') or f.endswith('.gypi'):
+        continue
+
+      if options.do_remove:
+        # Delete the file - best way to ensure it's not used during build.
+        os.remove(path)
+      else:
+        # By default just print paths that would be removed.
+        print path
+
+  exit_code = 0
+
+  # Fail if exclusion list contains stale entries - this helps keep it
+  # up to date.
+  for exclusion, used in exclusion_used.iteritems():
+    if not used:
+      print '%s does not exist' % exclusion
+      exit_code = 1
+
+  if not options.do_remove:
+    print ('To actually remove files printed above, please pass ' +
+           '--do-remove flag.')
+
+  return exit_code
+
+
+if __name__ == '__main__':
+  sys.exit(DoMain(sys.argv[1:]))
diff --git a/build/linux/unbundle/replace_gyp_files.py b/build/linux/unbundle/replace_gyp_files.py
index 1436711..c0fcc49 100755
--- a/build/linux/unbundle/replace_gyp_files.py
+++ b/build/linux/unbundle/replace_gyp_files.py
@@ -30,6 +30,7 @@
   'use_system_libwebp': 'third_party/libwebp/libwebp.gyp',
   'use_system_libxml': 'third_party/libxml/libxml.gyp',
   'use_system_libxslt': 'third_party/libxslt/libxslt.gyp',
+  'use_system_openssl': 'third_party/openssl/openssl.gyp',
   'use_system_opus': 'third_party/opus/opus.gyp',
   'use_system_re2': 'third_party/re2/re2.gyp',
   'use_system_snappy': 'third_party/snappy/snappy.gyp',
diff --git a/build/shim_headers.gypi b/build/shim_headers.gypi
index 4291468..997a4d0 100644
--- a/build/shim_headers.gypi
+++ b/build/shim_headers.gypi
@@ -17,12 +17,19 @@
     '<(shim_headers_path)',
   ],
   'all_dependent_settings': {
+    # Repeating this with different numbers of plusses is unfortunately required
+    # to make sure that even if this include is inside nested conditions/etc, it
+    # still gets inserted at the beginning of the include_dirs list. See
+    # http://crbug.com/263818 for details.
     'include_dirs+++': [
       '<(shim_headers_path)',
     ],
     'include_dirs++++': [
       '<(shim_headers_path)',
     ],
+    'include_dirs+++++': [
+      '<(shim_headers_path)',
+    ],
   },
   'actions': [
     {
diff --git a/build/slave/OWNERS b/build/slave/OWNERS
new file mode 100644
index 0000000..c367f57
--- /dev/null
+++ b/build/slave/OWNERS
@@ -0,0 +1,24 @@
+set noparent
+agable@chromium.org
+agable@google.com
+bevc@chromium.org
+bevc@google.com
+cmp@chromium.org
+cmp@google.com
+dpranke@chromium.org
+iannucci@chromium.org
+iannucci@google.com
+ilevy@chromium.org
+ilevy@google.com
+johnw@chromium.org
+johnw@google.com
+maruel@chromium.org
+maruel@google.com
+mmoss@chromium.org
+mmoss@google.com
+pschmidt@chromium.org
+pschmidt@google.com
+szager@chromium.org
+szager@google.com
+xusydoc@chromium.org
+xusydoc@google.com
diff --git a/build/slave/README b/build/slave/README
new file mode 100644
index 0000000..e3718b2
--- /dev/null
+++ b/build/slave/README
@@ -0,0 +1,8 @@
+This is a directory which contains configuration information for the
+buildsystem.
+
+* Under recipes, the buildsystem should use only this directory as an
+  entry point into src/.
+
+* Scripts in this directory must not import from outside this directory or shell
+  to scripts outside this directory.
diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE
index 0ef7af5..9422be6 100644
--- a/build/util/LASTCHANGE
+++ b/build/util/LASTCHANGE
@@ -1 +1 @@
-LASTCHANGE=217147
+LASTCHANGE=219274
diff --git a/build/util/LASTCHANGE.blink b/build/util/LASTCHANGE.blink
index 2b4cc5a..d36e8c4 100644
--- a/build/util/LASTCHANGE.blink
+++ b/build/util/LASTCHANGE.blink
@@ -1 +1 @@
-LASTCHANGE=155942
+LASTCHANGE=156598
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 405a489..79e805d 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -71,3 +71,4 @@
 NO ONE SHOULD EVER USE SVN
 AN INFLEXIBLE POSITION SOMETIMES IS A SIGN OF PARALYSIS
 IT IS MANS FATE TO OUTSMART HIMSELF
+BEING SURE OF YOURSELF MEANS YOU'RE A FOOL
diff --git a/cc/DEPS b/cc/DEPS
index ad58eba..e0482b6 100644
--- a/cc/DEPS
+++ b/cc/DEPS
@@ -12,5 +12,4 @@
   # DO NOT ADD ANY NEW WEBKIT HEADERS TO THIS LIST.
   # TODO(danakj): Drop dependencies on WebKit Platform API from cc.
   "+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
-  "+third_party/WebKit/public/platform/WebGraphicsMemoryAllocation.h",
 ]
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h
index 3860234..f4cdb10 100644
--- a/cc/animation/animation_curve.h
+++ b/cc/animation/animation_curve.h
@@ -10,6 +10,10 @@
 #include "cc/output/filter_operations.h"
 #include "ui/gfx/transform.h"
 
+namespace gfx {
+class BoxF;
+}
+
 namespace cc {
 
 class FilterAnimationCurve;
@@ -49,6 +53,12 @@
 
   virtual gfx::Transform GetValue(double t) const = 0;
 
+  // Sets |bounds| to be the bounding box for the region within which |box|
+  // will move during this animation. If this region cannot be computed,
+  // returns false.
+  virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
+                                    gfx::BoxF* bounds) const = 0;
+
   // Partial Animation implementation.
   virtual CurveType Type() const OVERRIDE;
 };
diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc
index c016c91..14dfd9c 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/box_f.h"
 
 namespace cc {
 
@@ -231,6 +232,28 @@
   return GetCurveValue<gfx::Transform, TransformKeyframe>(&keyframes_, t);
 }
 
+bool KeyframedTransformAnimationCurve::AnimatedBoundsForBox(
+    const gfx::BoxF& box,
+    gfx::BoxF* bounds) const {
+  DCHECK_GE(keyframes_.size(), 2ul);
+  *bounds = gfx::BoxF();
+  for (size_t i = 0; i < keyframes_.size() - 1; ++i) {
+    gfx::BoxF bounds_for_step;
+    float min_progress = 0.0;
+    float max_progress = 1.0;
+    if (keyframes_[i]->timing_function())
+      keyframes_[i]->timing_function()->Range(&min_progress, &max_progress);
+    if (!keyframes_[i+1]->Value().BlendedBoundsForBox(box,
+                                                      keyframes_[i]->Value(),
+                                                      min_progress,
+                                                      max_progress,
+                                                      &bounds_for_step))
+      return false;
+    bounds->Union(bounds_for_step);
+  }
+  return true;
+}
+
 scoped_ptr<KeyframedFilterAnimationCurve> KeyframedFilterAnimationCurve::
     Create() {
   return make_scoped_ptr(new KeyframedFilterAnimationCurve);
diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h
index 9dda773..5892dc7 100644
--- a/cc/animation/keyframed_animation_curve.h
+++ b/cc/animation/keyframed_animation_curve.h
@@ -135,6 +135,8 @@
 
   // TransformAnimationCurve implementation
   virtual gfx::Transform GetValue(double t) const OVERRIDE;
+  virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
+                                    gfx::BoxF* bounds) const OVERRIDE;
 
  private:
   KeyframedTransformAnimationCurve();
diff --git a/cc/animation/keyframed_animation_curve_unittest.cc b/cc/animation/keyframed_animation_curve_unittest.cc
index 32efc14..48f511c 100644
--- a/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/cc/animation/keyframed_animation_curve_unittest.cc
@@ -7,6 +7,7 @@
 #include "cc/animation/transform_operations.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/box_f.h"
 
 namespace cc {
 namespace {
@@ -332,5 +333,29 @@
   EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f));
 }
 
+// Tests that animated bounds are computed as expected.
+TEST(KeyframedAnimationCurveTest, AnimatedBounds) {
+  scoped_ptr<KeyframedTransformAnimationCurve> curve(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations1;
+  curve->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations1, scoped_ptr<TimingFunction>()));
+  operations1.AppendTranslate(2.0, 3.0, -1.0);
+  curve->AddKeyframe(TransformKeyframe::Create(
+      0.5, operations1, scoped_ptr<TimingFunction>()));
+  TransformOperations operations2;
+  operations2.AppendTranslate(4.0, 1.0, 2.0);
+  curve->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations2, EaseTimingFunction::Create()));
+
+  gfx::BoxF box(2.f, 3.f, 4.f, 1.f, 3.f, 2.f);
+  gfx::BoxF bounds;
+
+  EXPECT_TRUE(curve->AnimatedBoundsForBox(box, &bounds));
+  EXPECT_EQ(gfx::BoxF(2.f, 3.f, 3.f, 5.f, 6.f, 5.f).ToString(),
+            bounds.ToString());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc
index 5823b79..08e2db7 100644
--- a/cc/animation/layer_animation_controller.cc
+++ b/cc/animation/layer_animation_controller.cc
@@ -12,6 +12,7 @@
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/layer_animation_value_observer.h"
 #include "cc/base/scoped_ptr_algorithm.h"
+#include "ui/gfx/box_f.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -343,6 +344,31 @@
   event_observers_.RemoveObserver(observer);
 }
 
+bool LayerAnimationController::AnimatedBoundsForBox(const gfx::BoxF& box,
+                                                    gfx::BoxF* bounds) {
+  // Compute bounds based on animations for which is_finished() is false.
+  // Do nothing if there are no such animations; in this case, it is assumed
+  // that callers will take care of computing bounds based on the owning layer's
+  // actual transform.
+  *bounds = gfx::BoxF();
+  for (size_t i = 0; i < active_animations_.size(); ++i) {
+    if (active_animations_[i]->is_finished() ||
+        active_animations_[i]->target_property() != Animation::Transform)
+      continue;
+
+    const TransformAnimationCurve* transform_animation_curve =
+        active_animations_[i]->curve()->ToTransformAnimationCurve();
+    gfx::BoxF animation_bounds;
+    bool success =
+        transform_animation_curve->AnimatedBoundsForBox(box, &animation_bounds);
+    if (!success)
+      return false;
+    bounds->Union(animation_bounds);
+  }
+
+  return true;
+}
+
 void LayerAnimationController::PushNewAnimationsToImplThread(
     LayerAnimationController* controller_impl) const {
   // Any new animations owned by the main thread's controller are cloned and
diff --git a/cc/animation/layer_animation_controller.h b/cc/animation/layer_animation_controller.h
index e450f15..4138704 100644
--- a/cc/animation/layer_animation_controller.h
+++ b/cc/animation/layer_animation_controller.h
@@ -17,7 +17,10 @@
 #include "cc/base/scoped_ptr_vector.h"
 #include "ui/gfx/transform.h"
 
-namespace gfx { class Transform; }
+namespace gfx {
+class BoxF;
+class Transform;
+}
 
 namespace cc {
 
@@ -100,6 +103,8 @@
     layer_animation_delegate_ = delegate;
   }
 
+  bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds);
+
  protected:
   friend class base::RefCounted<LayerAnimationController>;
 
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc
index 2e06f5c..6e94734 100644
--- a/cc/animation/layer_animation_controller_unittest.cc
+++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -12,6 +12,7 @@
 #include "cc/test/animation_test_common.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/box_f.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -1117,5 +1118,74 @@
   EXPECT_NE(0.5f, dummy.opacity());
 }
 
+TEST(LayerAnimationControllerTest, AnimatedBounds) {
+  scoped_refptr<LayerAnimationController> controller_impl(
+      LayerAnimationController::Create(0));
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations1;
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations1, scoped_ptr<TimingFunction>()));
+  operations1.AppendTranslate(10.0, 15.0, 0.0);
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations1, scoped_ptr<TimingFunction>()));
+
+  scoped_ptr<Animation> animation(Animation::Create(
+      curve1.PassAs<AnimationCurve>(), 1, 1, Animation::Transform));
+  controller_impl->AddAnimation(animation.Pass());
+
+  scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+      KeyframedTransformAnimationCurve::Create());
+
+  TransformOperations operations2;
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations2, scoped_ptr<TimingFunction>()));
+  operations2.AppendScale(2.0, 3.0, 4.0);
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations2, scoped_ptr<TimingFunction>()));
+
+  animation = Animation::Create(
+      curve2.PassAs<AnimationCurve>(), 2, 2, Animation::Transform);
+  controller_impl->AddAnimation(animation.Pass());
+
+  gfx::BoxF box(1.f, 2.f, -1.f, 3.f, 4.f, 5.f);
+  gfx::BoxF bounds;
+
+  EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds));
+  EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 13.f, 19.f, 20.f).ToString(),
+            bounds.ToString());
+
+  controller_impl->GetAnimation(1, Animation::Transform)->SetRunState(
+      cc::Animation::Finished, 0.0);
+
+  // Only the unfinished animation should affect the animated bounds.
+  EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds));
+  EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 7.f, 16.f, 20.f).ToString(),
+            bounds.ToString());
+
+  controller_impl->GetAnimation(2, Animation::Transform)->SetRunState(
+      cc::Animation::Finished, 0.0);
+
+  // There are no longer any running animations.
+  EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds));
+  EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString());
+
+  // Add an animation whose bounds we don't yet support computing.
+  scoped_ptr<KeyframedTransformAnimationCurve> curve3(
+      KeyframedTransformAnimationCurve::Create());
+  TransformOperations operations3;
+  curve3->AddKeyframe(TransformKeyframe::Create(
+      0.0, operations3, scoped_ptr<TimingFunction>()));
+  operations3.AppendSkew(1.0, 2.0);
+  curve3->AddKeyframe(TransformKeyframe::Create(
+      1.0, operations3, scoped_ptr<TimingFunction>()));
+  animation = Animation::Create(
+      curve3.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
+  controller_impl->AddAnimation(animation.Pass());
+  EXPECT_FALSE(controller_impl->AnimatedBoundsForBox(box, &bounds));
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
index a8365e8..4a11ba6 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "cc/animation/scrollbar_animation_controller_linear_fade.h"
 
-#include "cc/layers/scrollbar_layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/test/fake_impl_proxy.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -19,7 +19,7 @@
  protected:
   virtual void SetUp() {
     scroll_layer_ = LayerImpl::Create(host_impl_.active_tree(), 1);
-    scrollbar_layer_ = ScrollbarLayerImpl::Create(
+    scrollbar_layer_ = PaintedScrollbarLayerImpl::Create(
         host_impl_.active_tree(), 2, HORIZONTAL);
 
     scroll_layer_->SetMaxScrollOffset(gfx::Vector2d(50, 50));
@@ -36,7 +36,7 @@
   FakeLayerTreeHostImpl host_impl_;
   scoped_ptr<ScrollbarAnimationControllerLinearFade> scrollbar_controller_;
   scoped_ptr<LayerImpl> scroll_layer_;
-  scoped_ptr<ScrollbarLayerImpl> scrollbar_layer_;
+  scoped_ptr<PaintedScrollbarLayerImpl> scrollbar_layer_;
 };
 
 TEST_F(ScrollbarAnimationControllerLinearFadeTest, HiddenInBegin) {
diff --git a/cc/animation/timing_function.cc b/cc/animation/timing_function.cc
index 65d607f..7fdb37f 100644
--- a/cc/animation/timing_function.cc
+++ b/cc/animation/timing_function.cc
@@ -12,7 +12,7 @@
 
 namespace {
 
-static const double BEZIER_EPSILON = 1e-7;
+static const double kBezierEpsilon = 1e-7;
 static const int MAX_STEPS = 30;
 
 static double eval_bezier(double x1, double x2, double t) {
@@ -48,14 +48,14 @@
   double step = 1.0;
   for (int i = 0; i < MAX_STEPS; ++i, step *= 0.5) {
     const double error = eval_bezier(x1, x2, t) - x;
-    if (std::abs(error) < BEZIER_EPSILON)
+    if (std::abs(error) < kBezierEpsilon)
       break;
     t += error > 0.0 ? -step : step;
   }
 
   // We should have terminated the above loop because we got close to x, not
   // because we exceeded MAX_STEPS. Do a DCHECK here to confirm.
-  DCHECK_GT(BEZIER_EPSILON, std::abs(eval_bezier(x1, x2, t) - x));
+  DCHECK_GT(kBezierEpsilon, std::abs(eval_bezier(x1, x2, t) - x));
 
   // Step 2. Return the interpolated y values at the t we computed above.
   return eval_bezier(y1, y2, t);
@@ -93,6 +93,53 @@
       new CubicBezierTimingFunction(*this)).PassAs<AnimationCurve>();
 }
 
+void CubicBezierTimingFunction::Range(float* min, float* max) const {
+  *min = 0.f;
+  *max = 1.f;
+  if (0.f <= y1_ && y1_ < 1.f && 0.f <= y2_ && y2_ <= 1.f)
+    return;
+
+  // Represent the function's derivative in the form at^2 + bt + c.
+  float a = 3.f * (y1_ - y2_) + 1.f;
+  float b = 2.f * (y2_ - 2.f * y1_);
+  float c = y1_;
+
+  // Check if the derivative is constant.
+  if (std::abs(a) < kBezierEpsilon &&
+      std::abs(b) < kBezierEpsilon)
+    return;
+
+  // Zeros of the function's derivative.
+  float t_1 = 0.f;
+  float t_2 = 0.f;
+
+  if (std::abs(a) < kBezierEpsilon) {
+    // The function's derivative is linear.
+    t_1 = -c / b;
+  } else {
+    // The function's derivative is a quadratic. We find the zeros of this
+    // quadratic using the quadratic formula.
+    float discriminant = b * b - 4 * a * c;
+    if (discriminant < 0.f)
+      return;
+    float discriminant_sqrt = sqrt(discriminant);
+    t_1 = (-b + discriminant_sqrt) / (2.f * a);
+    t_2 = (-b - discriminant_sqrt) / (2.f * a);
+  }
+
+  float sol_1 = 0.f;
+  float sol_2 = 0.f;
+
+  if (0.f < t_1 && t_1 < 1.f)
+    sol_1 = eval_bezier(y1_, y2_, t_1);
+
+  if (0.f < t_2 && t_2 < 1.f)
+    sol_2 = eval_bezier(y1_, y2_, t_2);
+
+  *min = std::min(std::min(*min, sol_1), sol_2);
+  *max = std::max(std::max(*max, sol_1), sol_2);
+}
+
 // These numbers come from
 // http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag.
 scoped_ptr<TimingFunction> EaseTimingFunction::Create() {
diff --git a/cc/animation/timing_function.h b/cc/animation/timing_function.h
index 3aa2f25..056ad41 100644
--- a/cc/animation/timing_function.h
+++ b/cc/animation/timing_function.h
@@ -19,6 +19,10 @@
   // Partial implementation of FloatAnimationCurve.
   virtual double Duration() const OVERRIDE;
 
+  // The smallest and largest values returned by GetValue for inputs in
+  // [0, 1].
+  virtual void Range(float* min, float* max) const = 0;
+
  protected:
   TimingFunction();
 
@@ -36,6 +40,8 @@
   virtual float GetValue(double time) const OVERRIDE;
   virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE;
 
+  virtual void Range(float* min, float* max) const OVERRIDE;
+
  protected:
   CubicBezierTimingFunction(double x1, double y1, double x2, double y2);
 
diff --git a/cc/animation/timing_function_unittest.cc b/cc/animation/timing_function_unittest.cc
index 2caa12d..4be225f 100644
--- a/cc/animation/timing_function_unittest.cc
+++ b/cc/animation/timing_function_unittest.cc
@@ -67,5 +67,75 @@
   EXPECT_NEAR(function->GetValue(1.0), 1.0, epsilon);
 }
 
+TEST(TimingFunctionTest, CubicBezierTimingFunctionRange) {
+  double epsilon = 0.00015;
+  float min, max;
+
+  // Derivative is a constant.
+  scoped_ptr<CubicBezierTimingFunction> function =
+      CubicBezierTimingFunction::Create(0.25, (1.0 / 3.0), 0.75, (2.0 / 3.0));
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative is linear.
+  function = CubicBezierTimingFunction::Create(0.25, -0.5, 0.75, (-1.0 / 6.0));
+  function->Range(&min, &max);
+  EXPECT_NEAR(min, -0.225, epsilon);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative has no real roots.
+  function = CubicBezierTimingFunction::Create(0.25, 0.25, 0.75, 0.5);
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative has exactly one real root.
+  function = CubicBezierTimingFunction::Create(0.0, 1.0, 1.0, 0.0);
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative has one root < 0 and one root > 1.
+  function = CubicBezierTimingFunction::Create(0.25, 0.1, 0.75, 0.9);
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative has two roots in [0,1].
+  function = CubicBezierTimingFunction::Create(0.25, 2.5, 0.75, 0.5);
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_NEAR(max, 1.28818, epsilon);
+  function = CubicBezierTimingFunction::Create(0.25, 0.5, 0.75, -1.5);
+  function->Range(&min, &max);
+  EXPECT_NEAR(min, -0.28818, epsilon);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative has one root < 0 and one root in [0,1].
+  function = CubicBezierTimingFunction::Create(0.25, 0.1, 0.75, 1.5);
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_NEAR(max, 1.10755, epsilon);
+
+  // Derivative has one root in [0,1] and one root > 1.
+  function = CubicBezierTimingFunction::Create(0.25, -0.5, 0.75, 0.9);
+  function->Range(&min, &max);
+  EXPECT_NEAR(min, -0.10755, epsilon);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative has two roots < 0.
+  function = CubicBezierTimingFunction::Create(0.25, 0.3, 0.75, 0.633);
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_EQ(1.f, max);
+
+  // Derivative has two roots > 1.
+  function = CubicBezierTimingFunction::Create(0.25, 0.367, 0.75, 0.7);
+  function->Range(&min, &max);
+  EXPECT_EQ(0.f, min);
+  EXPECT_EQ(1.f, max);
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/animation/transform_operation.cc b/cc/animation/transform_operation.cc
index dacea06..b7bb063 100644
--- a/cc/animation/transform_operation.cc
+++ b/cc/animation/transform_operation.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <algorithm>
 #include <cmath>
 #include <limits>
 
 #include "cc/animation/transform_operation.h"
+#include "ui/gfx/box_f.h"
 #include "ui/gfx/vector3d_f.h"
 
 namespace {
@@ -177,4 +179,123 @@
   return true;
 }
 
+static void ApplyScaleToBox(float x_scale,
+                            float y_scale,
+                            float z_scale,
+                            gfx::BoxF* box) {
+  if (x_scale < 0)
+    box->set_x(-box->right());
+  if (y_scale < 0)
+    box->set_y(-box->bottom());
+  if (z_scale < 0)
+    box->set_z(-box->front());
+  box->Scale(std::abs(x_scale), std::abs(y_scale), std::abs(z_scale));
+}
+
+static void UnionBoxWithZeroScale(gfx::BoxF* box) {
+  float min_x = std::min(box->x(), 0.f);
+  float min_y = std::min(box->y(), 0.f);
+  float min_z = std::min(box->z(), 0.f);
+  float max_x = std::max(box->right(), 0.f);
+  float max_y = std::max(box->bottom(), 0.f);
+  float max_z = std::max(box->front(), 0.f);
+  *box = gfx::BoxF(
+      min_x, min_y, min_z, max_x - min_x, max_y - min_y, max_z - min_z);
+}
+
+bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box,
+                                             const TransformOperation* from,
+                                             const TransformOperation* to,
+                                             double min_progress,
+                                             double max_progress,
+                                             gfx::BoxF* bounds) {
+  bool is_identity_from = IsOperationIdentity(from);
+  bool is_identity_to = IsOperationIdentity(to);
+  if (is_identity_from && is_identity_to) {
+    *bounds = box;
+    return true;
+  }
+
+  TransformOperation::Type interpolation_type =
+      TransformOperation::TransformOperationIdentity;
+  if (is_identity_to)
+    interpolation_type = from->type;
+  else
+    interpolation_type = to->type;
+
+  switch (interpolation_type) {
+    case TransformOperation::TransformOperationTranslate: {
+      double from_x, from_y, from_z;
+      if (is_identity_from) {
+        from_x = from_y = from_z = 0.0;
+      } else {
+        from_x = from->translate.x;
+        from_y = from->translate.y;
+        from_z = from->translate.z;
+      }
+      double to_x, to_y, to_z;
+      if (is_identity_to) {
+        to_x = to_y = to_z = 0.0;
+      } else {
+        to_x = to->translate.x;
+        to_y = to->translate.y;
+        to_z = to->translate.z;
+      }
+      *bounds = box;
+      *bounds += gfx::Vector3dF(BlendDoubles(from_x, to_x, min_progress),
+                                BlendDoubles(from_y, to_y, min_progress),
+                                BlendDoubles(from_z, to_z, min_progress));
+      gfx::BoxF bounds_max = box;
+      bounds_max += gfx::Vector3dF(BlendDoubles(from_x, to_x, max_progress),
+                                   BlendDoubles(from_y, to_y, max_progress),
+                                   BlendDoubles(from_z, to_z, max_progress));
+      bounds->Union(bounds_max);
+      return true;
+    }
+    case TransformOperation::TransformOperationScale: {
+      double from_x, from_y, from_z;
+      if (is_identity_from) {
+        from_x = from_y = from_z = 1.0;
+      } else {
+        from_x = from->scale.x;
+        from_y = from->scale.y;
+        from_z = from->scale.z;
+      }
+      double to_x, to_y, to_z;
+      if (is_identity_to) {
+        to_x = to_y = to_z = 1.0;
+      } else {
+        to_x = to->scale.x;
+        to_y = to->scale.y;
+        to_z = to->scale.z;
+      }
+      *bounds = box;
+      ApplyScaleToBox(BlendDoubles(from_x, to_x, min_progress),
+                      BlendDoubles(from_y, to_y, min_progress),
+                      BlendDoubles(from_z, to_z, min_progress),
+                      bounds);
+      gfx::BoxF bounds_max = box;
+      ApplyScaleToBox(BlendDoubles(from_x, to_x, max_progress),
+                      BlendDoubles(from_y, to_y, max_progress),
+                      BlendDoubles(from_z, to_z, max_progress),
+                      &bounds_max);
+      if (!bounds->IsEmpty() && !bounds_max.IsEmpty()) {
+        bounds->Union(bounds_max);
+      } else if (!bounds->IsEmpty()) {
+        UnionBoxWithZeroScale(bounds);
+      } else if (!bounds_max.IsEmpty()) {
+        UnionBoxWithZeroScale(&bounds_max);
+        *bounds = bounds_max;
+      }
+
+      return true;
+    }
+    case TransformOperation::TransformOperationIdentity:
+      *bounds = box;
+      return true;
+    default:
+      return false;
+  }
+}
+
 }  // namespace cc
diff --git a/cc/animation/transform_operation.h b/cc/animation/transform_operation.h
index 74673ab..d5f2830 100644
--- a/cc/animation/transform_operation.h
+++ b/cc/animation/transform_operation.h
@@ -7,6 +7,10 @@
 
 #include "ui/gfx/transform.h"
 
+namespace gfx {
+class BoxF;
+}
+
 namespace cc {
 
 struct TransformOperation {
@@ -56,6 +60,13 @@
                                        const TransformOperation* to,
                                        double progress,
                                        gfx::Transform* result);
+
+  static bool BlendedBoundsForBox(const gfx::BoxF& box,
+                                  const TransformOperation* from,
+                                  const TransformOperation* to,
+                                  double min_progress,
+                                  double max_progress,
+                                  gfx::BoxF* bounds);
 };
 
 }  // namespace cc
diff --git a/cc/animation/transform_operations.cc b/cc/animation/transform_operations.cc
index d74f1a5..42b3559 100644
--- a/cc/animation/transform_operations.cc
+++ b/cc/animation/transform_operations.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "ui/gfx/box_f.h"
 #include "ui/gfx/transform_util.h"
 #include "ui/gfx/vector3d_f.h"
 
@@ -41,6 +42,42 @@
   return to_return;
 }
 
+bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box,
+                                              const TransformOperations& from,
+                                              double min_progress,
+                                              double max_progress,
+                                              gfx::BoxF* bounds) const {
+  *bounds = box;
+
+  bool from_identity = from.IsIdentity();
+  bool to_identity = IsIdentity();
+  if (from_identity && to_identity)
+    return true;
+
+  if (!MatchesTypes(from))
+    return false;
+
+  size_t num_operations =
+      std::max(from_identity ? 0 : from.operations_.size(),
+               to_identity ? 0 : operations_.size());
+  for (size_t i = 0; i < num_operations; ++i) {
+    gfx::BoxF bounds_for_operation;
+    const TransformOperation* from_op =
+        from_identity ? NULL : &from.operations_[i];
+    const TransformOperation* to_op = to_identity ? NULL : &operations_[i];
+    if (!TransformOperation::BlendedBoundsForBox(*bounds,
+                                                 from_op,
+                                                 to_op,
+                                                 min_progress,
+                                                 max_progress,
+                                                 &bounds_for_operation))
+      return false;
+    *bounds = bounds_for_operation;
+  }
+
+  return true;
+}
+
 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
   if (IsIdentity() || other.IsIdentity())
     return true;
diff --git a/cc/animation/transform_operations.h b/cc/animation/transform_operations.h
index b5f960f..96bf1d1 100644
--- a/cc/animation/transform_operations.h
+++ b/cc/animation/transform_operations.h
@@ -13,6 +13,7 @@
 #include "ui/gfx/transform.h"
 
 namespace gfx {
+class BoxF;
 struct DecomposedTransform;
 }
 
@@ -45,6 +46,16 @@
   // http://www.w3.org/TR/2011/WD-css3-2d-transforms-20111215/#matrix-decomposition.
   gfx::Transform Blend(const TransformOperations& from, double progress) const;
 
+  // Sets |bounds| be the bounding box for the region within which |box| will
+  // exist when it is transformed by the result of calling Blend on |from| and
+  // with progress in the range [min_progress, max_progress]. If this region
+  // cannot be computed, returns false.
+  bool BlendedBoundsForBox(const gfx::BoxF& box,
+                           const TransformOperations& from,
+                           double min_progress,
+                           double max_progress,
+                           gfx::BoxF* bounds) const;
+
   // Returns true if this operation and its descendants have the same types
   // as other and its descendants.
   bool MatchesTypes(const TransformOperations& other) const;
diff --git a/cc/animation/transform_operations_unittest.cc b/cc/animation/transform_operations_unittest.cc
index 8fc9b94..b82d911 100644
--- a/cc/animation/transform_operations_unittest.cc
+++ b/cc/animation/transform_operations_unittest.cc
@@ -8,6 +8,7 @@
 #include "cc/animation/transform_operations.h"
 #include "cc/test/geometry_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/box_f.h"
 #include "ui/gfx/vector3d_f.h"
 
 namespace cc {
@@ -707,5 +708,176 @@
       expected, operations1.Blend(operations2, -0.5));
 }
 
+TEST(TransformOperationTest, BlendedBoundsWhenTypesDoNotMatch) {
+  TransformOperations operations_from;
+  operations_from.AppendScale(2.0, 4.0, 8.0);
+  operations_from.AppendTranslate(1.0, 2.0, 3.0);
+
+  TransformOperations operations_to;
+  operations_to.AppendTranslate(10.0, 20.0, 30.0);
+  operations_to.AppendScale(4.0, 8.0, 16.0);
+
+  gfx::BoxF box(1.f, 1.f, 1.f);
+  gfx::BoxF bounds;
+
+  double min_progress = 0.0;
+  double max_progress = 1.0;
+
+  EXPECT_FALSE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+}
+
+TEST(TransformOperationTest, BlendedBoundsForIdentity) {
+  TransformOperations operations_from;
+  operations_from.AppendIdentity();
+  TransformOperations operations_to;
+  operations_to.AppendIdentity();
+
+  gfx::BoxF box(1.f, 2.f, 3.f);
+  gfx::BoxF bounds;
+
+  double min_progress = 0.0;
+  double max_progress = 1.0;
+
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(box.ToString(), bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForTranslate) {
+  TransformOperations operations_from;
+  operations_from.AppendTranslate(3.0, -4.0, 2.0);
+  TransformOperations operations_to;
+  operations_to.AppendTranslate(7.0, 4.0, -2.0);
+
+  gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+  gfx::BoxF bounds;
+
+  double min_progress = -0.5;
+  double max_progress = 1.5;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(2.f, -6.f, -1.f, 12.f, 20.f, 12.f).ToString(),
+            bounds.ToString());
+
+  min_progress = 0.0;
+  max_progress = 1.0;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(4.f, -2.f, 1.f, 8.f, 12.f, 8.f).ToString(),
+            bounds.ToString());
+
+  TransformOperations identity;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+        box, identity, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(1.f, 2.f, 1.f, 11.f, 8.f, 6.f).ToString(),
+            bounds.ToString());
+
+  EXPECT_TRUE(identity.BlendedBoundsForBox(
+        box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(1.f, -2.f, 3.f, 7.f, 8.f, 6.f).ToString(),
+            bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForScale) {
+  TransformOperations operations_from;
+  operations_from.AppendScale(3.0, 0.5, 2.0);
+  TransformOperations operations_to;
+  operations_to.AppendScale(7.0, 4.0, -2.0);
+
+  gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+  gfx::BoxF bounds;
+
+  double min_progress = -0.5;
+  double max_progress = 1.5;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(1.f, -7.5f, -28.f, 44.f, 42.f, 56.f).ToString(),
+            bounds.ToString());
+
+  min_progress = 0.0;
+  max_progress = 1.0;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(3.f, 1.f, -14.f, 32.f, 23.f, 28.f).ToString(),
+            bounds.ToString());
+
+  TransformOperations identity;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+        box, identity, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(1.f, 2.f, -14.f, 34.f, 22.f, 21.f).ToString(),
+            bounds.ToString());
+
+  EXPECT_TRUE(identity.BlendedBoundsForBox(
+        box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(1.f, 1.f, 3.f, 14.f, 5.f, 11.f).ToString(),
+            bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsWithZeroScale) {
+  TransformOperations zero_scale;
+  zero_scale.AppendScale(0.0, 0.0, 0.0);
+  TransformOperations non_zero_scale;
+  non_zero_scale.AppendScale(2.0, -4.0, 5.0);
+
+  gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+  gfx::BoxF bounds;
+
+  double min_progress = 0.0;
+  double max_progress = 1.0;
+  EXPECT_TRUE(zero_scale.BlendedBoundsForBox(
+      box, non_zero_scale, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
+            bounds.ToString());
+
+  EXPECT_TRUE(non_zero_scale.BlendedBoundsForBox(
+      box, zero_scale, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
+            bounds.ToString());
+
+  EXPECT_TRUE(zero_scale.BlendedBoundsForBox(
+      box, zero_scale, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString());
+}
+
+TEST(TransformOperationTest, BlendedBoundsForSequence) {
+  TransformOperations operations_from;
+  operations_from.AppendTranslate(2.0, 4.0, -1.0);
+  operations_from.AppendScale(-1.0, 2.0, 3.0);
+  operations_from.AppendTranslate(1.0, -5.0, 1.0);
+  TransformOperations operations_to;
+  operations_to.AppendTranslate(6.0, -2.0, 3.0);
+  operations_to.AppendScale(-3.0, -2.0, 5.0);
+  operations_to.AppendTranslate(13.0, -1.0, 5.0);
+
+  gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
+  gfx::BoxF bounds;
+
+  double min_progress = -0.5;
+  double max_progress = 1.5;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(-57.f, -59.f, -1.f, 76.f, 112.f, 80.f).ToString(),
+            bounds.ToString());
+
+  min_progress = 0.0;
+  max_progress = 1.0;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+      box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(-32.f, -25.f, 7.f, 42.f, 44.f, 48.f).ToString(),
+            bounds.ToString());
+
+  TransformOperations identity;
+  EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+        box, identity, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(-33.f, -13.f, 3.f, 57.f, 19.f, 52.f).ToString(),
+            bounds.ToString());
+
+  EXPECT_TRUE(identity.BlendedBoundsForBox(
+        box, operations_from, min_progress, max_progress, &bounds));
+  EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(),
+            bounds.ToString());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 78060a4..c6f3355 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -86,6 +86,10 @@
         'debug/rendering_stats_instrumentation.cc',
         'debug/rendering_stats_instrumentation.h',
         'debug/ring_buffer.h',
+        'debug/test_context_provider.cc',
+        'debug/test_context_provider.h',
+        'debug/test_web_graphics_context_3d.cc',
+        'debug/test_web_graphics_context_3d.h',
         'debug/traced_picture.cc',
         'debug/traced_picture.h',
         'debug/traced_value.cc',
@@ -121,6 +125,7 @@
         'layers/io_surface_layer_impl.h',
         'layers/layer.cc',
         'layers/layer.h',
+        'layers/layer_client.h',
         'layers/layer_impl.cc',
         'layers/layer_impl.h',
         'layers/layer_iterator.cc',
@@ -134,6 +139,10 @@
         'layers/nine_patch_layer_impl.cc',
         'layers/nine_patch_layer_impl.h',
         'layers/paint_properties.h',
+        'layers/painted_scrollbar_layer.cc',
+        'layers/painted_scrollbar_layer.h',
+        'layers/painted_scrollbar_layer_impl.cc',
+        'layers/painted_scrollbar_layer_impl.h',
         'layers/picture_image_layer.cc',
         'layers/picture_image_layer.h',
         'layers/picture_image_layer_impl.cc',
@@ -148,10 +157,6 @@
         'layers/render_surface.h',
         'layers/render_surface_impl.cc',
         'layers/render_surface_impl.h',
-        'layers/scrollbar_layer.cc',
-        'layers/scrollbar_layer.h',
-        'layers/scrollbar_layer_impl.cc',
-        'layers/scrollbar_layer_impl.h',
         'layers/solid_color_layer.cc',
         'layers/solid_color_layer.h',
         'layers/solid_color_layer_impl.cc',
@@ -312,6 +317,7 @@
         'resources/resource_update_controller.h',
         'resources/resource_update_queue.cc',
         'resources/resource_update_queue.h',
+        'resources/returned_resource.h',
         'resources/scoped_resource.cc',
         'resources/scoped_resource.h',
         'resources/scoped_ui_resource.cc',
diff --git a/cc/cc.target.darwin-arm.mk b/cc/cc.target.darwin-arm.mk
index 85ba891..8ef4d17 100644
--- a/cc/cc.target.darwin-arm.mk
+++ b/cc/cc.target.darwin-arm.mk
@@ -54,6 +54,8 @@
 	cc/debug/paint_time_counter.cc \
 	cc/debug/rendering_stats.cc \
 	cc/debug/rendering_stats_instrumentation.cc \
+	cc/debug/test_context_provider.cc \
+	cc/debug/test_web_graphics_context_3d.cc \
 	cc/debug/traced_picture.cc \
 	cc/debug/traced_value.cc \
 	cc/input/page_scale_animation.cc \
@@ -74,14 +76,14 @@
 	cc/layers/layer_position_constraint.cc \
 	cc/layers/nine_patch_layer.cc \
 	cc/layers/nine_patch_layer_impl.cc \
+	cc/layers/painted_scrollbar_layer.cc \
+	cc/layers/painted_scrollbar_layer_impl.cc \
 	cc/layers/picture_image_layer.cc \
 	cc/layers/picture_image_layer_impl.cc \
 	cc/layers/picture_layer.cc \
 	cc/layers/picture_layer_impl.cc \
 	cc/layers/render_surface.cc \
 	cc/layers/render_surface_impl.cc \
-	cc/layers/scrollbar_layer.cc \
-	cc/layers/scrollbar_layer_impl.cc \
 	cc/layers/solid_color_layer.cc \
 	cc/layers/solid_color_layer_impl.cc \
 	cc/layers/texture_layer.cc \
diff --git a/cc/cc.target.darwin-mips.mk b/cc/cc.target.darwin-mips.mk
index 8ef2344..6880650 100644
--- a/cc/cc.target.darwin-mips.mk
+++ b/cc/cc.target.darwin-mips.mk
@@ -54,6 +54,8 @@
 	cc/debug/paint_time_counter.cc \
 	cc/debug/rendering_stats.cc \
 	cc/debug/rendering_stats_instrumentation.cc \
+	cc/debug/test_context_provider.cc \
+	cc/debug/test_web_graphics_context_3d.cc \
 	cc/debug/traced_picture.cc \
 	cc/debug/traced_value.cc \
 	cc/input/page_scale_animation.cc \
@@ -74,14 +76,14 @@
 	cc/layers/layer_position_constraint.cc \
 	cc/layers/nine_patch_layer.cc \
 	cc/layers/nine_patch_layer_impl.cc \
+	cc/layers/painted_scrollbar_layer.cc \
+	cc/layers/painted_scrollbar_layer_impl.cc \
 	cc/layers/picture_image_layer.cc \
 	cc/layers/picture_image_layer_impl.cc \
 	cc/layers/picture_layer.cc \
 	cc/layers/picture_layer_impl.cc \
 	cc/layers/render_surface.cc \
 	cc/layers/render_surface_impl.cc \
-	cc/layers/scrollbar_layer.cc \
-	cc/layers/scrollbar_layer_impl.cc \
 	cc/layers/solid_color_layer.cc \
 	cc/layers/solid_color_layer_impl.cc \
 	cc/layers/texture_layer.cc \
diff --git a/cc/cc.target.darwin-x86.mk b/cc/cc.target.darwin-x86.mk
index 55f7a8c..3e7af3c 100644
--- a/cc/cc.target.darwin-x86.mk
+++ b/cc/cc.target.darwin-x86.mk
@@ -54,6 +54,8 @@
 	cc/debug/paint_time_counter.cc \
 	cc/debug/rendering_stats.cc \
 	cc/debug/rendering_stats_instrumentation.cc \
+	cc/debug/test_context_provider.cc \
+	cc/debug/test_web_graphics_context_3d.cc \
 	cc/debug/traced_picture.cc \
 	cc/debug/traced_value.cc \
 	cc/input/page_scale_animation.cc \
@@ -74,14 +76,14 @@
 	cc/layers/layer_position_constraint.cc \
 	cc/layers/nine_patch_layer.cc \
 	cc/layers/nine_patch_layer_impl.cc \
+	cc/layers/painted_scrollbar_layer.cc \
+	cc/layers/painted_scrollbar_layer_impl.cc \
 	cc/layers/picture_image_layer.cc \
 	cc/layers/picture_image_layer_impl.cc \
 	cc/layers/picture_layer.cc \
 	cc/layers/picture_layer_impl.cc \
 	cc/layers/render_surface.cc \
 	cc/layers/render_surface_impl.cc \
-	cc/layers/scrollbar_layer.cc \
-	cc/layers/scrollbar_layer_impl.cc \
 	cc/layers/solid_color_layer.cc \
 	cc/layers/solid_color_layer_impl.cc \
 	cc/layers/texture_layer.cc \
diff --git a/cc/cc.target.linux-arm.mk b/cc/cc.target.linux-arm.mk
index 85ba891..8ef4d17 100644
--- a/cc/cc.target.linux-arm.mk
+++ b/cc/cc.target.linux-arm.mk
@@ -54,6 +54,8 @@
 	cc/debug/paint_time_counter.cc \
 	cc/debug/rendering_stats.cc \
 	cc/debug/rendering_stats_instrumentation.cc \
+	cc/debug/test_context_provider.cc \
+	cc/debug/test_web_graphics_context_3d.cc \
 	cc/debug/traced_picture.cc \
 	cc/debug/traced_value.cc \
 	cc/input/page_scale_animation.cc \
@@ -74,14 +76,14 @@
 	cc/layers/layer_position_constraint.cc \
 	cc/layers/nine_patch_layer.cc \
 	cc/layers/nine_patch_layer_impl.cc \
+	cc/layers/painted_scrollbar_layer.cc \
+	cc/layers/painted_scrollbar_layer_impl.cc \
 	cc/layers/picture_image_layer.cc \
 	cc/layers/picture_image_layer_impl.cc \
 	cc/layers/picture_layer.cc \
 	cc/layers/picture_layer_impl.cc \
 	cc/layers/render_surface.cc \
 	cc/layers/render_surface_impl.cc \
-	cc/layers/scrollbar_layer.cc \
-	cc/layers/scrollbar_layer_impl.cc \
 	cc/layers/solid_color_layer.cc \
 	cc/layers/solid_color_layer_impl.cc \
 	cc/layers/texture_layer.cc \
diff --git a/cc/cc.target.linux-mips.mk b/cc/cc.target.linux-mips.mk
index 8ef2344..6880650 100644
--- a/cc/cc.target.linux-mips.mk
+++ b/cc/cc.target.linux-mips.mk
@@ -54,6 +54,8 @@
 	cc/debug/paint_time_counter.cc \
 	cc/debug/rendering_stats.cc \
 	cc/debug/rendering_stats_instrumentation.cc \
+	cc/debug/test_context_provider.cc \
+	cc/debug/test_web_graphics_context_3d.cc \
 	cc/debug/traced_picture.cc \
 	cc/debug/traced_value.cc \
 	cc/input/page_scale_animation.cc \
@@ -74,14 +76,14 @@
 	cc/layers/layer_position_constraint.cc \
 	cc/layers/nine_patch_layer.cc \
 	cc/layers/nine_patch_layer_impl.cc \
+	cc/layers/painted_scrollbar_layer.cc \
+	cc/layers/painted_scrollbar_layer_impl.cc \
 	cc/layers/picture_image_layer.cc \
 	cc/layers/picture_image_layer_impl.cc \
 	cc/layers/picture_layer.cc \
 	cc/layers/picture_layer_impl.cc \
 	cc/layers/render_surface.cc \
 	cc/layers/render_surface_impl.cc \
-	cc/layers/scrollbar_layer.cc \
-	cc/layers/scrollbar_layer_impl.cc \
 	cc/layers/solid_color_layer.cc \
 	cc/layers/solid_color_layer_impl.cc \
 	cc/layers/texture_layer.cc \
diff --git a/cc/cc.target.linux-x86.mk b/cc/cc.target.linux-x86.mk
index 55f7a8c..3e7af3c 100644
--- a/cc/cc.target.linux-x86.mk
+++ b/cc/cc.target.linux-x86.mk
@@ -54,6 +54,8 @@
 	cc/debug/paint_time_counter.cc \
 	cc/debug/rendering_stats.cc \
 	cc/debug/rendering_stats_instrumentation.cc \
+	cc/debug/test_context_provider.cc \
+	cc/debug/test_web_graphics_context_3d.cc \
 	cc/debug/traced_picture.cc \
 	cc/debug/traced_value.cc \
 	cc/input/page_scale_animation.cc \
@@ -74,14 +76,14 @@
 	cc/layers/layer_position_constraint.cc \
 	cc/layers/nine_patch_layer.cc \
 	cc/layers/nine_patch_layer_impl.cc \
+	cc/layers/painted_scrollbar_layer.cc \
+	cc/layers/painted_scrollbar_layer_impl.cc \
 	cc/layers/picture_image_layer.cc \
 	cc/layers/picture_image_layer_impl.cc \
 	cc/layers/picture_layer.cc \
 	cc/layers/picture_layer_impl.cc \
 	cc/layers/render_surface.cc \
 	cc/layers/render_surface_impl.cc \
-	cc/layers/scrollbar_layer.cc \
-	cc/layers/scrollbar_layer_impl.cc \
 	cc/layers/solid_color_layer.cc \
 	cc/layers/solid_color_layer_impl.cc \
 	cc/layers/texture_layer.cc \
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 7e2ff87..c84b11b 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -100,8 +100,6 @@
       'test/fake_content_layer_client.h',
       'test/fake_content_layer_impl.cc',
       'test/fake_content_layer_impl.h',
-      'test/fake_context_provider.cc',
-      'test/fake_context_provider.h',
       'test/fake_delegated_renderer_layer.cc',
       'test/fake_delegated_renderer_layer.h',
       'test/fake_delegated_renderer_layer_impl.cc',
@@ -113,6 +111,8 @@
       'test/fake_layer_tree_host_impl_client.cc',
       'test/fake_layer_tree_host_impl_client.h',
       'test/fake_layer_tree_host_impl.h',
+      'test/fake_painted_scrollbar_layer.cc',
+      'test/fake_painted_scrollbar_layer.h',
       'test/fake_picture_layer.cc',
       'test/fake_picture_layer.h',
       'test/fake_picture_layer_impl.cc',
@@ -126,8 +126,6 @@
       'test/fake_rendering_stats_instrumentation.h',
       'test/fake_scrollbar.cc',
       'test/fake_scrollbar.h',
-      'test/fake_scrollbar_layer.cc',
-      'test/fake_scrollbar_layer.h',
       'test/fake_tile_manager.cc',
       'test/fake_tile_manager.h',
       'test/fake_tile_manager_client.h',
@@ -174,8 +172,6 @@
       'test/skia_common.h',
       'test/test_tile_priorities.cc',
       'test/test_tile_priorities.h',
-      'test/test_web_graphics_context_3d.cc',
-      'test/test_web_graphics_context_3d.h',
       'test/tiled_layer_test_common.cc',
       'test/tiled_layer_test_common.h',
     ],
diff --git a/cc/debug/fake_web_graphics_context_3d.h b/cc/debug/fake_web_graphics_context_3d.h
index 3c8a6f5..04c983d 100644
--- a/cc/debug/fake_web_graphics_context_3d.h
+++ b/cc/debug/fake_web_graphics_context_3d.h
@@ -67,9 +67,6 @@
       WebKit::WGC3Dsizei num_attachments,
       const WebKit::WGC3Denum* attachments) {}
 
-  virtual void setMemoryAllocationChangedCallbackCHROMIUM(
-      WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) {}
-
   virtual WebKit::WebString getRequestableExtensionsCHROMIUM();
   virtual void requestExtensionCHROMIUM(const char*) {}
 
diff --git a/cc/debug/rendering_stats.cc b/cc/debug/rendering_stats.cc
index 12c5453..e6875ce 100644
--- a/cc/debug/rendering_stats.cc
+++ b/cc/debug/rendering_stats.cc
@@ -2,98 +2,179 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/values.h"
 #include "cc/debug/rendering_stats.h"
 
 namespace cc {
 
-RenderingStats::RenderingStats()
-    : animation_frame_count(0),
-      screen_frame_count(0),
+MainThreadRenderingStats::MainThreadRenderingStats()
+  : animation_frame_count(0),
+    screen_frame_count(0),
+    commit_count(0),
+    painted_pixel_count(0),
+    recorded_pixel_count(0),
+    image_gathering_count(0) {}
+
+ImplThreadRenderingStats::ImplThreadRenderingStats()
+    : screen_frame_count(0),
       dropped_frame_count(0),
-      total_commit_count(0),
-      total_pixels_painted(0),
-      total_pixels_recorded(0),
-      total_pixels_rasterized(0),
-      num_impl_thread_scrolls(0),
-      num_main_thread_scrolls(0),
-      num_layers_drawn(0),
-      num_missing_tiles(0),
-      total_deferred_image_decode_count(0),
-      total_deferred_image_cache_hit_count(0),
-      total_image_gathering_count(0),
-      total_tiles_analyzed(0),
-      solid_color_tiles_analyzed(0) {}
+      rasterized_pixel_count(0),
+      impl_thread_scroll_count(0),
+      main_thread_scroll_count(0),
+      drawn_layer_count(0),
+      missing_tile_count(0),
+      deferred_image_decode_count(0),
+      deferred_image_cache_hit_count(0),
+      tile_analysis_count(0),
+      solid_color_tile_analysis_count(0) {}
 
 void RenderingStats::EnumerateFields(Enumerator* enumerator) const {
-  enumerator->AddInt64("numAnimationFrames", animation_frame_count);
-  enumerator->AddInt64("numFramesSentToScreen", screen_frame_count);
-  enumerator->AddInt64("droppedFrameCount", dropped_frame_count);
+  enumerator->AddInt64("numAnimationFrames",
+                       main_stats.animation_frame_count);
+  enumerator->AddInt64("numFramesSentToScreen", main_stats.screen_frame_count +
+                       impl_stats.screen_frame_count);
   enumerator->AddDouble("totalPaintTimeInSeconds",
-                        total_paint_time.InSecondsF());
+                        main_stats.paint_time.InSecondsF());
   enumerator->AddDouble("totalRecordTimeInSeconds",
-                        total_record_time.InSecondsF());
+                        main_stats.record_time.InSecondsF());
+  enumerator->AddDouble("totalCommitTimeInSeconds",
+                        main_stats.commit_time.InSecondsF());
+  enumerator->AddInt64("totalCommitCount", main_stats.commit_count);
+  enumerator->AddInt64("totalPixelsPainted", main_stats.painted_pixel_count);
+  enumerator->AddInt64("totalPixelsRecorded", main_stats.recorded_pixel_count);
+  enumerator->AddInt64("totalImageGatheringCount",
+                       main_stats.image_gathering_count);
+  enumerator->AddDouble("totalImageGatheringTimeInSeconds",
+                        main_stats.image_gathering_time.InSecondsF());
+  enumerator->AddInt64("droppedFrameCount", impl_stats.dropped_frame_count);
   enumerator->AddDouble("totalRasterizeTimeInSeconds",
-                        total_rasterize_time.InSecondsF());
+                        impl_stats.rasterize_time.InSecondsF());
   enumerator->AddDouble(
       "totalRasterizeTimeForNowBinsOnPendingTree",
-      total_rasterize_time_for_now_bins_on_pending_tree.InSecondsF());
-  enumerator->AddDouble("totalCommitTimeInSeconds",
-                        total_commit_time.InSecondsF());
+      impl_stats.rasterize_time_for_now_bins_on_pending_tree.InSecondsF());
   enumerator->AddDouble("bestRasterizeTimeInSeconds",
-                        best_rasterize_time.InSecondsF());
-  enumerator->AddInt64("totalCommitCount", total_commit_count);
-  enumerator->AddInt64("totalPixelsPainted", total_pixels_painted);
-  enumerator->AddInt64("totalPixelsRecorded", total_pixels_recorded);
-  enumerator->AddInt64("totalPixelsRasterized", total_pixels_rasterized);
-  enumerator->AddInt64("numImplThreadScrolls", num_impl_thread_scrolls);
-  enumerator->AddInt64("numMainThreadScrolls", num_main_thread_scrolls);
-  enumerator->AddInt64("numLayersDrawn", num_layers_drawn);
-  enumerator->AddInt64("numMissingTiles", num_missing_tiles);
+                        impl_stats.best_rasterize_time.InSecondsF());
+  enumerator->AddInt64("totalPixelsRasterized",
+                       impl_stats.rasterized_pixel_count);
+  enumerator->AddInt64("numImplThreadScrolls",
+                       impl_stats.impl_thread_scroll_count);
+  enumerator->AddInt64("numMainThreadScrolls",
+                       impl_stats.main_thread_scroll_count);
+  enumerator->AddInt64("numLayersDrawn", impl_stats.drawn_layer_count);
+  enumerator->AddInt64("numMissingTiles", impl_stats.missing_tile_count);
   enumerator->AddInt64("totalDeferredImageDecodeCount",
-                       total_deferred_image_decode_count);
-  enumerator->AddInt64("totalTilesAnalyzed", total_tiles_analyzed);
+                       impl_stats.deferred_image_decode_count);
+  enumerator->AddInt64("totalTilesAnalyzed", impl_stats.tile_analysis_count);
   enumerator->AddInt64("solidColorTilesAnalyzed",
-                       solid_color_tiles_analyzed);
+                       impl_stats.solid_color_tile_analysis_count);
   enumerator->AddInt64("totalDeferredImageCacheHitCount",
-                       total_deferred_image_cache_hit_count);
-  enumerator->AddInt64("totalImageGatheringCount",
-                       total_image_gathering_count);
+                       impl_stats.deferred_image_cache_hit_count);
   enumerator->AddDouble("totalDeferredImageDecodeTimeInSeconds",
-                        total_deferred_image_decode_time.InSecondsF());
-  enumerator->AddDouble("totalImageGatheringTimeInSeconds",
-                        total_image_gathering_time.InSecondsF());
+                        impl_stats.deferred_image_decode_time.InSecondsF());
   enumerator->AddDouble("totalTileAnalysisTimeInSeconds",
-                        total_tile_analysis_time.InSecondsF());
+                        impl_stats.tile_analysis_time.InSecondsF());
+}
+
+scoped_ptr<base::debug::ConvertableToTraceFormat>
+MainThreadRenderingStats::AsTraceableData() const {
+  scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
+  record_data->SetInteger("animation_frame_count",
+                          animation_frame_count);
+  record_data->SetInteger("screen_frame_count",
+                          screen_frame_count);
+  record_data->SetDouble("paint_time",
+                         paint_time.InSecondsF());
+  record_data->SetDouble("record_time",
+                         record_time.InSecondsF());
+  record_data->SetDouble("commit_time",
+                         commit_time.InSecondsF());
+  record_data->SetInteger("commit_count",
+                          commit_count);
+  record_data->SetInteger("painted_pixel_count",
+                          painted_pixel_count);
+  record_data->SetInteger("recorded_pixel_count",
+                          recorded_pixel_count);
+  record_data->SetInteger("image_gathering_count",
+                          image_gathering_count);
+  return TracedValue::FromValue(record_data.release());
+}
+
+scoped_ptr<base::debug::ConvertableToTraceFormat>
+ImplThreadRenderingStats::AsTraceableData() const {
+  scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
+  record_data->SetInteger("screen_frame_count",
+                          screen_frame_count);
+  record_data->SetInteger("dropped_frame_count",
+                          dropped_frame_count);
+  record_data->SetDouble("rasterize_time",
+                         rasterize_time.InSecondsF());
+  record_data->SetDouble(
+      "rasterize_time_for_now_bins_on_pending_tree",
+      rasterize_time_for_now_bins_on_pending_tree.InSecondsF());
+  record_data->SetDouble("best_rasterize_time",
+                         best_rasterize_time.InSecondsF());
+  record_data->SetInteger("rasterized_pixel_count",
+                          rasterized_pixel_count);
+  record_data->SetInteger("impl_thread_scroll_count",
+                          impl_thread_scroll_count);
+  record_data->SetInteger("main_thread_scroll_count",
+                          main_thread_scroll_count);
+  record_data->SetInteger("drawn_layer_count",
+                          drawn_layer_count);
+  record_data->SetInteger("missing_tile_count",
+                          missing_tile_count);
+  record_data->SetInteger("deferred_image_decode_count",
+                          deferred_image_decode_count);
+  record_data->SetInteger("deferred_image_cache_hit_count",
+                          deferred_image_cache_hit_count);
+  record_data->SetInteger("tile_analysis_count",
+                          tile_analysis_count);
+  record_data->SetInteger("solid_color_tile_analysis_count",
+                          solid_color_tile_analysis_count);
+  record_data->SetDouble("deferred_image_decode_time",
+                         deferred_image_decode_time.InSecondsF());
+  record_data->SetDouble("tile_analysis_time",
+                         tile_analysis_time.InSecondsF());
+  return TracedValue::FromValue(record_data.release());
+}
+
+
+void MainThreadRenderingStats::Add(const MainThreadRenderingStats& other) {
+  animation_frame_count += other.animation_frame_count;
+  screen_frame_count += other.screen_frame_count;
+  paint_time += other.paint_time;
+  record_time += other.record_time;
+  commit_time += other.commit_time;
+  commit_count += other.commit_count;
+  painted_pixel_count += other.painted_pixel_count;
+  recorded_pixel_count += other.recorded_pixel_count;
+  image_gathering_count += other.image_gathering_count;
+  image_gathering_time += other.image_gathering_time;
+}
+
+void ImplThreadRenderingStats::Add(const ImplThreadRenderingStats& other) {
+  screen_frame_count += other.screen_frame_count;
+  dropped_frame_count += other.dropped_frame_count;
+  rasterize_time += other.rasterize_time;
+  rasterize_time_for_now_bins_on_pending_tree +=
+      other.rasterize_time_for_now_bins_on_pending_tree;
+  best_rasterize_time += other.best_rasterize_time;
+  rasterized_pixel_count += other.rasterized_pixel_count;
+  impl_thread_scroll_count += other.impl_thread_scroll_count;
+  main_thread_scroll_count += other.main_thread_scroll_count;
+  drawn_layer_count += other.drawn_layer_count;
+  missing_tile_count += other.missing_tile_count;
+  deferred_image_decode_count += other.deferred_image_decode_count;
+  deferred_image_cache_hit_count += other.deferred_image_cache_hit_count;
+  deferred_image_decode_time += other.deferred_image_decode_time;
+  tile_analysis_count += other.tile_analysis_count;
+  solid_color_tile_analysis_count += other.solid_color_tile_analysis_count;
+  tile_analysis_time += other.tile_analysis_time;
 }
 
 void RenderingStats::Add(const RenderingStats& other) {
-  animation_frame_count += other.animation_frame_count;
-  screen_frame_count += other.screen_frame_count;
-  dropped_frame_count += other.dropped_frame_count;
-  total_paint_time += other.total_paint_time;
-  total_record_time += other.total_record_time;
-  total_rasterize_time += other.total_rasterize_time;
-  total_rasterize_time_for_now_bins_on_pending_tree +=
-      other.total_rasterize_time_for_now_bins_on_pending_tree;
-  total_commit_time += other.total_commit_time;
-  best_rasterize_time += other.best_rasterize_time;
-  total_commit_count += other.total_commit_count;
-  total_pixels_painted += other.total_pixels_painted;
-  total_pixels_recorded += other.total_pixels_recorded;
-  total_pixels_rasterized += other.total_pixels_rasterized;
-  num_impl_thread_scrolls += other.num_impl_thread_scrolls;
-  num_main_thread_scrolls += other.num_main_thread_scrolls;
-  num_layers_drawn += other.num_layers_drawn;
-  num_missing_tiles += other.num_missing_tiles;
-  total_deferred_image_decode_count += other.total_deferred_image_decode_count;
-  total_deferred_image_cache_hit_count +=
-      other.total_deferred_image_cache_hit_count;
-  total_image_gathering_count += other.total_image_gathering_count;
-  total_deferred_image_decode_time += other.total_deferred_image_decode_time;
-  total_image_gathering_time += other.total_image_gathering_time;
-  total_tiles_analyzed += other.total_tiles_analyzed;
-  solid_color_tiles_analyzed += other.solid_color_tiles_analyzed;
-  total_tile_analysis_time += other.total_tile_analysis_time;
+  main_stats.Add(other.main_stats);
+  impl_stats.Add(other.impl_stats);
 }
 
 }  // namespace cc
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index eb01a57..c3647d5 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -8,55 +8,77 @@
 #include "base/basictypes.h"
 #include "base/time/time.h"
 #include "cc/base/cc_export.h"
+#include "cc/debug/traced_value.h"
 
 namespace cc {
 
-struct CC_EXPORT RenderingStats {
-  int64 animation_frame_count;
-  int64 screen_frame_count;
-  int64 dropped_frame_count;
-  base::TimeDelta total_paint_time;
-  base::TimeDelta total_record_time;
-  base::TimeDelta total_rasterize_time;
-  base::TimeDelta total_rasterize_time_for_now_bins_on_pending_tree;
-  base::TimeDelta total_commit_time;
-  base::TimeDelta best_rasterize_time;
-  int64 total_commit_count;
-  int64 total_pixels_painted;
-  int64 total_pixels_recorded;
-  int64 total_pixels_rasterized;
-  int64 num_impl_thread_scrolls;
-  int64 num_main_thread_scrolls;
-  int64 num_layers_drawn;
-  int64 num_missing_tiles;
-  int64 total_deferred_image_decode_count;
-  int64 total_deferred_image_cache_hit_count;
-  int64 total_image_gathering_count;
-  int64 total_tiles_analyzed;
-  int64 solid_color_tiles_analyzed;
-  base::TimeDelta total_deferred_image_decode_time;
-  base::TimeDelta total_image_gathering_time;
-  base::TimeDelta total_tile_analysis_time;
+// In conjunction with EnumerateFields, this allows the embedder to
+// enumerate the values in this structure without
+// having to embed references to its specific member variables. This
+// simplifies the addition of new fields to this type.
+class RenderingStatsEnumerator {
+ public:
+  virtual void AddInt64(const char* name, int64 value) = 0;
+  virtual void AddDouble(const char* name, double value) = 0;
+  virtual void AddInt(const char* name, int value) = 0;
+  virtual void AddTimeDeltaInSecondsF(const char* name,
+                                      const base::TimeDelta& value) = 0;
+
+ protected:
+  virtual ~RenderingStatsEnumerator() {}
+};
+
+struct CC_EXPORT MainThreadRenderingStats {
   // Note: when adding new members, please remember to update EnumerateFields
   // and Add in rendering_stats.cc.
 
-  RenderingStats();
+  int64 animation_frame_count;
+  int64 screen_frame_count;
+  base::TimeDelta paint_time;
+  base::TimeDelta record_time;
+  base::TimeDelta commit_time;
+  int64 commit_count;
+  int64 painted_pixel_count;
+  int64 recorded_pixel_count;
+  int64 image_gathering_count;
+  base::TimeDelta image_gathering_time;
 
-  // In conjunction with EnumerateFields, this allows the embedder to
-  // enumerate the values in this structure without
-  // having to embed references to its specific member variables. This
-  // simplifies the addition of new fields to this type.
-  class Enumerator {
-   public:
-    virtual void AddInt64(const char* name, int64 value) = 0;
-    virtual void AddDouble(const char* name, double value) = 0;
-    virtual void AddInt(const char* name, int value) = 0;
-    virtual void AddTimeDeltaInSecondsF(const char* name,
-                                        const base::TimeDelta& value) = 0;
+  MainThreadRenderingStats();
+  scoped_ptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const;
+  void Add(const MainThreadRenderingStats& other);
+};
 
-   protected:
-    virtual ~Enumerator() {}
-  };
+struct CC_EXPORT ImplThreadRenderingStats {
+  // Note: when adding new members, please remember to update EnumerateFields
+  // and Add in rendering_stats.cc.
+
+  int64 screen_frame_count;
+  int64 dropped_frame_count;
+  base::TimeDelta rasterize_time;
+  base::TimeDelta rasterize_time_for_now_bins_on_pending_tree;
+  base::TimeDelta best_rasterize_time;
+  int64 rasterized_pixel_count;
+  int64 impl_thread_scroll_count;
+  int64 main_thread_scroll_count;
+  int64 drawn_layer_count;
+  int64 missing_tile_count;
+  int64 deferred_image_decode_count;
+  int64 deferred_image_cache_hit_count;
+  int64 tile_analysis_count;
+  int64 solid_color_tile_analysis_count;
+  base::TimeDelta deferred_image_decode_time;
+  base::TimeDelta tile_analysis_time;
+
+  ImplThreadRenderingStats();
+  scoped_ptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const;
+  void Add(const ImplThreadRenderingStats& other);
+};
+
+struct CC_EXPORT RenderingStats {
+  typedef RenderingStatsEnumerator Enumerator;
+
+  MainThreadRenderingStats main_stats;
+  ImplThreadRenderingStats impl_stats;
 
   // Outputs the fields in this structure to the provided enumerator.
   void EnumerateFields(Enumerator* enumerator) const;
diff --git a/cc/debug/rendering_stats_instrumentation.cc b/cc/debug/rendering_stats_instrumentation.cc
index b3886af..3c164f9 100644
--- a/cc/debug/rendering_stats_instrumentation.cc
+++ b/cc/debug/rendering_stats_instrumentation.cc
@@ -20,7 +20,22 @@
 
 RenderingStats RenderingStatsInstrumentation::GetRenderingStats() {
   base::AutoLock scoped_lock(lock_);
-  return rendering_stats_;
+  RenderingStats rendering_stats;
+  rendering_stats.main_stats = main_stats_accu_;
+  rendering_stats.main_stats.Add(main_stats_);
+  rendering_stats.impl_stats = impl_stats_accu_;
+  rendering_stats.impl_stats.Add(impl_stats_);
+  return rendering_stats;
+}
+
+void RenderingStatsInstrumentation::AccumulateAndClearMainThreadStats() {
+  main_stats_accu_.Add(main_stats_);
+  main_stats_ = MainThreadRenderingStats();
+}
+
+void RenderingStatsInstrumentation::AccumulateAndClearImplThreadStats() {
+  impl_stats_accu_.Add(impl_stats_);
+  impl_stats_ = ImplThreadRenderingStats();
 }
 
 base::TimeTicks RenderingStatsInstrumentation::StartRecording() const {
@@ -41,23 +56,23 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.animation_frame_count++;
+  main_stats_.animation_frame_count++;
 }
 
-void RenderingStatsInstrumentation::SetScreenFrameCount(int64 count) {
+void RenderingStatsInstrumentation::IncrementScreenFrameCount(int64 count) {
   if (!record_rendering_stats_)
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.screen_frame_count = count;
+  impl_stats_.screen_frame_count += count;
 }
 
-void RenderingStatsInstrumentation::SetDroppedFrameCount(int64 count) {
+void RenderingStatsInstrumentation::IncrementDroppedFrameCount(int64 count) {
   if (!record_rendering_stats_)
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.dropped_frame_count = count;
+  impl_stats_.dropped_frame_count += count;
 }
 
 void RenderingStatsInstrumentation::AddCommit(base::TimeDelta duration) {
@@ -65,8 +80,8 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_commit_time += duration;
-  rendering_stats_.total_commit_count++;
+  main_stats_.commit_time += duration;
+  main_stats_.commit_count++;
 }
 
 void RenderingStatsInstrumentation::AddPaint(base::TimeDelta duration,
@@ -75,8 +90,8 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_paint_time += duration;
-  rendering_stats_.total_pixels_painted += pixels;
+  main_stats_.paint_time += duration;
+  main_stats_.painted_pixel_count += pixels;
 }
 
 void RenderingStatsInstrumentation::AddRecord(base::TimeDelta duration,
@@ -85,8 +100,8 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_record_time += duration;
-  rendering_stats_.total_pixels_recorded += pixels;
+  main_stats_.record_time += duration;
+  main_stats_.recorded_pixel_count += pixels;
 }
 
 void RenderingStatsInstrumentation::AddRaster(base::TimeDelta total_duration,
@@ -97,12 +112,12 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_rasterize_time += total_duration;
-  rendering_stats_.best_rasterize_time += best_duration;
-  rendering_stats_.total_pixels_rasterized += pixels;
+  impl_stats_.rasterize_time += total_duration;
+  impl_stats_.best_rasterize_time += best_duration;
+  impl_stats_.rasterized_pixel_count += pixels;
 
   if (is_in_pending_tree_now_bin) {
-    rendering_stats_.total_rasterize_time_for_now_bins_on_pending_tree +=
+    impl_stats_.rasterize_time_for_now_bins_on_pending_tree +=
         total_duration;
   }
 }
@@ -112,7 +127,7 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.num_impl_thread_scrolls++;
+  impl_stats_.impl_thread_scroll_count++;
 }
 
 void RenderingStatsInstrumentation::IncrementMainThreadScrolls() {
@@ -120,7 +135,7 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.num_main_thread_scrolls++;
+  impl_stats_.main_thread_scroll_count++;
 }
 
 void RenderingStatsInstrumentation::AddLayersDrawn(int64 amount) {
@@ -128,7 +143,7 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.num_layers_drawn += amount;
+  impl_stats_.drawn_layer_count += amount;
 }
 
 void RenderingStatsInstrumentation::AddMissingTiles(int64 amount) {
@@ -136,7 +151,7 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.num_missing_tiles += amount;
+  impl_stats_.missing_tile_count += amount;
 }
 
 void RenderingStatsInstrumentation::AddDeferredImageDecode(
@@ -145,8 +160,8 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_deferred_image_decode_time += duration;
-  rendering_stats_.total_deferred_image_decode_count++;
+  impl_stats_.deferred_image_decode_time += duration;
+  impl_stats_.deferred_image_decode_count++;
 }
 
 void RenderingStatsInstrumentation::AddImageGathering(
@@ -155,8 +170,8 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_image_gathering_time += duration;
-  rendering_stats_.total_image_gathering_count++;
+  main_stats_.image_gathering_time += duration;
+  main_stats_.image_gathering_count++;
 }
 
 void RenderingStatsInstrumentation::IncrementDeferredImageCacheHitCount() {
@@ -164,7 +179,7 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_deferred_image_cache_hit_count++;
+  impl_stats_.deferred_image_cache_hit_count++;
 }
 
 void RenderingStatsInstrumentation::AddAnalysisResult(
@@ -174,10 +189,10 @@
     return;
 
   base::AutoLock scoped_lock(lock_);
-  rendering_stats_.total_tiles_analyzed++;
-  rendering_stats_.total_tile_analysis_time += duration;
+  impl_stats_.tile_analysis_count++;
+  impl_stats_.tile_analysis_time += duration;
   if (is_solid_color)
-    rendering_stats_.solid_color_tiles_analyzed++;
+    impl_stats_.solid_color_tile_analysis_count++;
 }
 
 }  // namespace cc
diff --git a/cc/debug/rendering_stats_instrumentation.h b/cc/debug/rendering_stats_instrumentation.h
index 6f7515a..a7f9b30 100644
--- a/cc/debug/rendering_stats_instrumentation.h
+++ b/cc/debug/rendering_stats_instrumentation.h
@@ -18,8 +18,24 @@
   static scoped_ptr<RenderingStatsInstrumentation> Create();
   virtual ~RenderingStatsInstrumentation();
 
+  // Return current main thread rendering stats.
+  MainThreadRenderingStats GetMainThreadRenderingStats() {
+    return main_stats_;
+  }
+  // Return current impl thread rendering stats.
+  ImplThreadRenderingStats GetImplThreadRenderingStats() {
+    return impl_stats_;
+  }
+  // Return the accumulated, combined rendering stats.
   RenderingStats GetRenderingStats();
 
+  // Add current main thread rendering stats to accumulator and
+  // clear current stats
+  void AccumulateAndClearMainThreadStats();
+  // Add current impl thread rendering stats to accumulator and
+  // clear current stats
+  void AccumulateAndClearImplThreadStats();
+
   // Read and write access to the record_rendering_stats_ flag is not locked to
   // improve performance. The flag is commonly turned off and hardly changes
   // it's value during runtime.
@@ -33,8 +49,8 @@
   base::TimeDelta EndRecording(base::TimeTicks start_time) const;
 
   void IncrementAnimationFrameCount();
-  void SetScreenFrameCount(int64 count);
-  void SetDroppedFrameCount(int64 count);
+  void IncrementScreenFrameCount(int64 count);
+  void IncrementDroppedFrameCount(int64 count);
 
   void AddCommit(base::TimeDelta duration);
   void AddPaint(base::TimeDelta duration, int64 pixels);
@@ -61,7 +77,11 @@
   RenderingStatsInstrumentation();
 
  private:
-  RenderingStats rendering_stats_;
+  MainThreadRenderingStats main_stats_;
+  MainThreadRenderingStats main_stats_accu_;
+  ImplThreadRenderingStats impl_stats_;
+  ImplThreadRenderingStats impl_stats_accu_;
+
   bool record_rendering_stats_;
 
   base::Lock lock_;
diff --git a/cc/debug/test_context_provider.cc b/cc/debug/test_context_provider.cc
new file mode 100644
index 0000000..613ef53
--- /dev/null
+++ b/cc/debug/test_context_provider.cc
@@ -0,0 +1,223 @@
+// Copyright 2013 The Chromium Authors. 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/debug/test_context_provider.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
+
+namespace cc {
+
+class TestContextProvider::LostContextCallbackProxy
+    : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
+ public:
+  explicit LostContextCallbackProxy(TestContextProvider* provider)
+      : provider_(provider) {
+    provider_->context3d_->setContextLostCallback(this);
+  }
+
+  virtual ~LostContextCallbackProxy() {
+    provider_->context3d_->setContextLostCallback(NULL);
+  }
+
+  virtual void onContextLost() {
+    provider_->OnLostContext();
+  }
+
+ private:
+  TestContextProvider* provider_;
+};
+
+class TestContextProvider::SwapBuffersCompleteCallbackProxy
+    : public WebKit::WebGraphicsContext3D::
+          WebGraphicsSwapBuffersCompleteCallbackCHROMIUM {
+ public:
+  explicit SwapBuffersCompleteCallbackProxy(TestContextProvider* provider)
+      : provider_(provider) {
+    provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(this);
+  }
+
+  virtual ~SwapBuffersCompleteCallbackProxy() {
+    provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(NULL);
+  }
+
+  virtual void onSwapBuffersComplete() {
+    provider_->OnSwapBuffersComplete();
+  }
+
+ private:
+  TestContextProvider* provider_;
+};
+
+// static
+scoped_refptr<TestContextProvider> TestContextProvider::Create() {
+  return Create(TestWebGraphicsContext3D::Create().Pass());
+}
+
+// static
+scoped_refptr<TestContextProvider> TestContextProvider::Create(
+    const CreateCallback& create_callback) {
+  scoped_refptr<TestContextProvider> provider = new TestContextProvider;
+  if (!provider->InitializeOnMainThread(create_callback))
+    return NULL;
+  return provider;
+}
+
+scoped_ptr<TestWebGraphicsContext3D> ReturnScopedContext(
+    scoped_ptr<TestWebGraphicsContext3D> context) {
+  return context.Pass();
+}
+
+// static
+scoped_refptr<TestContextProvider> TestContextProvider::Create(
+    scoped_ptr<TestWebGraphicsContext3D> context) {
+  return Create(base::Bind(&ReturnScopedContext, base::Passed(&context)));
+}
+
+TestContextProvider::TestContextProvider()
+    : bound_(false),
+      destroyed_(false) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+  context_thread_checker_.DetachFromThread();
+}
+
+TestContextProvider::~TestContextProvider() {
+  DCHECK(main_thread_checker_.CalledOnValidThread() ||
+         context_thread_checker_.CalledOnValidThread());
+}
+
+bool TestContextProvider::InitializeOnMainThread(
+    const CreateCallback& create_callback) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+
+  DCHECK(!context3d_);
+  DCHECK(!create_callback.is_null());
+  context3d_ = create_callback.Run();
+  return context3d_;
+}
+
+bool TestContextProvider::BindToCurrentThread() {
+  DCHECK(context3d_);
+
+  // This is called on the thread the context will be used.
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+
+  if (bound_)
+    return true;
+
+  bound_ = true;
+  if (!context3d_->makeContextCurrent()) {
+    base::AutoLock lock(destroyed_lock_);
+    destroyed_ = true;
+    return false;
+  }
+
+  lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
+  swap_buffers_complete_callback_proxy_.reset(
+      new SwapBuffersCompleteCallbackProxy(this));
+
+  return true;
+}
+
+WebKit::WebGraphicsContext3D* TestContextProvider::Context3d() {
+  DCHECK(context3d_);
+  DCHECK(bound_);
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+
+  return context3d_.get();
+}
+
+class GrContext* TestContextProvider::GrContext() {
+  DCHECK(context3d_);
+  DCHECK(bound_);
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+
+  // TODO(danakj): Make a test GrContext that works with a test Context3d.
+  return NULL;
+}
+
+void TestContextProvider::VerifyContexts() {
+  DCHECK(context3d_);
+  DCHECK(bound_);
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+
+  if (context3d_->isContextLost()) {
+    base::AutoLock lock(destroyed_lock_);
+    destroyed_ = true;
+  }
+}
+
+bool TestContextProvider::DestroyedOnMainThread() {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+
+  base::AutoLock lock(destroyed_lock_);
+  return destroyed_;
+}
+
+void TestContextProvider::OnLostContext() {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+  {
+    base::AutoLock lock(destroyed_lock_);
+    if (destroyed_)
+      return;
+    destroyed_ = true;
+  }
+  if (!lost_context_callback_.is_null())
+    base::ResetAndReturn(&lost_context_callback_).Run();
+}
+
+void TestContextProvider::OnSwapBuffersComplete() {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+  if (!swap_buffers_complete_callback_.is_null())
+    swap_buffers_complete_callback_.Run();
+}
+
+TestWebGraphicsContext3D* TestContextProvider::TestContext3d() {
+  DCHECK(context3d_);
+  DCHECK(bound_);
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+
+  return context3d_.get();
+}
+
+TestWebGraphicsContext3D* TestContextProvider::UnboundTestContext3d() {
+  DCHECK(context3d_);
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+
+  return context3d_.get();
+}
+
+void TestContextProvider::SetMemoryAllocation(
+    const ManagedMemoryPolicy& policy,
+    bool discard_backbuffer_when_not_visible) {
+  if (memory_policy_changed_callback_.is_null())
+    return;
+  memory_policy_changed_callback_.Run(
+      policy, discard_backbuffer_when_not_visible);
+}
+
+void TestContextProvider::SetLostContextCallback(
+    const LostContextCallback& cb) {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+  DCHECK(lost_context_callback_.is_null() || cb.is_null());
+  lost_context_callback_ = cb;
+}
+
+void TestContextProvider::SetSwapBuffersCompleteCallback(
+    const SwapBuffersCompleteCallback& cb) {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+  DCHECK(swap_buffers_complete_callback_.is_null() || cb.is_null());
+  swap_buffers_complete_callback_ = cb;
+}
+
+void TestContextProvider::SetMemoryPolicyChangedCallback(
+    const MemoryPolicyChangedCallback& cb) {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+  DCHECK(memory_policy_changed_callback_.is_null() || cb.is_null());
+  memory_policy_changed_callback_ = cb;
+}
+
+}  // namespace cc
diff --git a/cc/debug/test_context_provider.h b/cc/debug/test_context_provider.h
new file mode 100644
index 0000000..af3e599
--- /dev/null
+++ b/cc/debug/test_context_provider.h
@@ -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.
+
+#ifndef CC_DEBUG_TEST_CONTEXT_PROVIDER_H_
+#define CC_DEBUG_TEST_CONTEXT_PROVIDER_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "cc/base/cc_export.h"
+#include "cc/output/context_provider.h"
+
+namespace WebKit { class WebGraphicsContext3D; }
+
+namespace cc {
+class TestWebGraphicsContext3D;
+
+class CC_EXPORT TestContextProvider
+    : public NON_EXPORTED_BASE(cc::ContextProvider) {
+ public:
+  typedef base::Callback<scoped_ptr<TestWebGraphicsContext3D>(void)>
+    CreateCallback;
+
+  static scoped_refptr<TestContextProvider> Create();
+  static scoped_refptr<TestContextProvider> Create(
+      const CreateCallback& create_callback);
+  static scoped_refptr<TestContextProvider> Create(
+      scoped_ptr<TestWebGraphicsContext3D> context);
+
+  virtual bool BindToCurrentThread() OVERRIDE;
+  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE;
+  virtual class GrContext* GrContext() OVERRIDE;
+  virtual void VerifyContexts() OVERRIDE;
+  virtual bool DestroyedOnMainThread() OVERRIDE;
+  virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE;
+  virtual void SetSwapBuffersCompleteCallback(
+      const SwapBuffersCompleteCallback& cb) OVERRIDE;
+  virtual void SetMemoryPolicyChangedCallback(
+      const MemoryPolicyChangedCallback& cb) OVERRIDE;
+
+  TestWebGraphicsContext3D* TestContext3d();
+
+  // This returns the TestWebGraphicsContext3D but is valid to call
+  // before the context is bound to a thread. This is needed to set up
+  // state on the test context before binding. Don't call
+  // makeContextCurrent on the context returned from this method.
+  TestWebGraphicsContext3D* UnboundTestContext3d();
+
+  void SetMemoryAllocation(const ManagedMemoryPolicy& policy,
+                           bool discard_backbuffer_when_not_visible);
+
+ protected:
+  TestContextProvider();
+  virtual ~TestContextProvider();
+
+  bool InitializeOnMainThread(const CreateCallback& create_callback);
+
+  void OnLostContext();
+  void OnSwapBuffersComplete();
+
+  scoped_ptr<TestWebGraphicsContext3D> context3d_;
+  bool bound_;
+
+  base::ThreadChecker main_thread_checker_;
+  base::ThreadChecker context_thread_checker_;
+
+  base::Lock destroyed_lock_;
+  bool destroyed_;
+
+  LostContextCallback lost_context_callback_;
+  SwapBuffersCompleteCallback swap_buffers_complete_callback_;
+  MemoryPolicyChangedCallback memory_policy_changed_callback_;
+
+  class LostContextCallbackProxy;
+  scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_;
+
+  class SwapBuffersCompleteCallbackProxy;
+  scoped_ptr<SwapBuffersCompleteCallbackProxy>
+      swap_buffers_complete_callback_proxy_;
+};
+
+}  // namespace cc
+
+#endif  // CC_DEBUG_TEST_CONTEXT_PROVIDER_H_
+
diff --git a/cc/debug/test_web_graphics_context_3d.cc b/cc/debug/test_web_graphics_context_3d.cc
new file mode 100644
index 0000000..11d1ed8
--- /dev/null
+++ b/cc/debug/test_web_graphics_context_3d.cc
@@ -0,0 +1,627 @@
+// Copyright 2013 The Chromium Authors. 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/debug/test_web_graphics_context_3d.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+
+using WebKit::WGC3Dboolean;
+using WebKit::WGC3Dchar;
+using WebKit::WGC3Denum;
+using WebKit::WGC3Dint;
+using WebKit::WGC3Dsizei;
+using WebKit::WGC3Dsizeiptr;
+using WebKit::WGC3Duint;
+using WebKit::WebGLId;
+using WebKit::WebGraphicsContext3D;
+
+namespace cc {
+
+static const WebGLId kFramebufferId = 1;
+static const WebGLId kProgramId = 2;
+static const WebGLId kRenderbufferId = 3;
+static const WebGLId kShaderId = 4;
+
+static unsigned s_context_id = 1;
+
+const WebGLId TestWebGraphicsContext3D::kExternalTextureId = 1337;
+
+static base::LazyInstance<base::Lock>::Leaky
+    g_shared_namespace_lock = LAZY_INSTANCE_INITIALIZER;
+
+TestWebGraphicsContext3D::Namespace*
+    TestWebGraphicsContext3D::shared_namespace_ = NULL;
+
+TestWebGraphicsContext3D::Namespace::Namespace()
+    : next_buffer_id(1),
+      next_image_id(1),
+      next_texture_id(1) {
+}
+
+TestWebGraphicsContext3D::Namespace::~Namespace() {
+  g_shared_namespace_lock.Get().AssertAcquired();
+  if (shared_namespace_ == this)
+    shared_namespace_ = NULL;
+}
+
+// static
+scoped_ptr<TestWebGraphicsContext3D> TestWebGraphicsContext3D::Create() {
+  return make_scoped_ptr(new TestWebGraphicsContext3D());
+}
+
+TestWebGraphicsContext3D::TestWebGraphicsContext3D()
+    : FakeWebGraphicsContext3D(),
+      context_id_(s_context_id++),
+      support_swapbuffers_complete_callback_(true),
+      have_extension_io_surface_(false),
+      have_extension_egl_image_(false),
+      times_make_current_succeeds_(-1),
+      times_bind_texture_succeeds_(-1),
+      times_end_query_succeeds_(-1),
+      times_gen_mailbox_succeeds_(-1),
+      context_lost_(false),
+      times_map_image_chromium_succeeds_(-1),
+      times_map_buffer_chromium_succeeds_(-1),
+      context_lost_callback_(NULL),
+      swap_buffers_callback_(NULL),
+      max_texture_size_(2048),
+      width_(0),
+      height_(0),
+      bound_buffer_(0),
+      weak_ptr_factory_(this) {
+  CreateNamespace();
+}
+
+TestWebGraphicsContext3D::TestWebGraphicsContext3D(
+    const WebGraphicsContext3D::Attributes& attributes)
+    : FakeWebGraphicsContext3D(),
+      context_id_(s_context_id++),
+      attributes_(attributes),
+      support_swapbuffers_complete_callback_(true),
+      have_extension_io_surface_(false),
+      have_extension_egl_image_(false),
+      times_make_current_succeeds_(-1),
+      times_bind_texture_succeeds_(-1),
+      times_end_query_succeeds_(-1),
+      times_gen_mailbox_succeeds_(-1),
+      context_lost_(false),
+      times_map_image_chromium_succeeds_(-1),
+      times_map_buffer_chromium_succeeds_(-1),
+      context_lost_callback_(NULL),
+      swap_buffers_callback_(NULL),
+      max_texture_size_(2048),
+      width_(0),
+      height_(0),
+      bound_buffer_(0),
+      weak_ptr_factory_(this) {
+  CreateNamespace();
+}
+
+void TestWebGraphicsContext3D::CreateNamespace() {
+  if (attributes_.shareResources) {
+    base::AutoLock lock(g_shared_namespace_lock.Get());
+    if (shared_namespace_) {
+      namespace_ = shared_namespace_;
+    } else {
+      namespace_ = new Namespace;
+      shared_namespace_ = namespace_.get();
+    }
+  } else {
+    namespace_ = new Namespace;
+  }
+}
+
+TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
+  for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) {
+    if (sync_point_callbacks_[i] != NULL)
+      delete sync_point_callbacks_[i];
+  }
+  base::AutoLock lock(g_shared_namespace_lock.Get());
+  namespace_ = NULL;
+}
+
+bool TestWebGraphicsContext3D::makeContextCurrent() {
+  if (times_make_current_succeeds_ >= 0) {
+    if (!times_make_current_succeeds_) {
+      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                          GL_INNOCENT_CONTEXT_RESET_ARB);
+    }
+    --times_make_current_succeeds_;
+  }
+  return !context_lost_;
+}
+
+int TestWebGraphicsContext3D::width() {
+  return width_;
+}
+
+int TestWebGraphicsContext3D::height() {
+  return height_;
+}
+
+void TestWebGraphicsContext3D::reshapeWithScaleFactor(
+    int width, int height, float scale_factor) {
+  width_ = width;
+  height_ = height;
+}
+
+bool TestWebGraphicsContext3D::isContextLost() {
+  return context_lost_;
+}
+
+WGC3Denum TestWebGraphicsContext3D::getGraphicsResetStatusARB() {
+  return context_lost_ ? GL_UNKNOWN_CONTEXT_RESET_ARB : GL_NO_ERROR;
+}
+
+WGC3Denum TestWebGraphicsContext3D::checkFramebufferStatus(
+    WGC3Denum target) {
+  if (context_lost_)
+    return GL_FRAMEBUFFER_UNDEFINED_OES;
+  return GL_FRAMEBUFFER_COMPLETE;
+}
+
+WebGraphicsContext3D::Attributes
+    TestWebGraphicsContext3D::getContextAttributes() {
+  return attributes_;
+}
+
+WebKit::WebString TestWebGraphicsContext3D::getString(WGC3Denum name) {
+  std::string string;
+
+  if (support_swapbuffers_complete_callback_)
+    string += "GL_CHROMIUM_swapbuffers_complete_callback";
+
+  if (name == GL_EXTENSIONS) {
+    if (have_extension_io_surface_)
+      string += " GL_CHROMIUM_iosurface GL_ARB_texture_rectangle";
+    if (have_extension_egl_image_)
+      string += " GL_OES_EGL_image_external";
+  }
+
+  return WebKit::WebString::fromUTF8(string.c_str());
+}
+
+WGC3Dint TestWebGraphicsContext3D::getUniformLocation(
+    WebGLId program,
+    const WGC3Dchar* name) {
+  return 0;
+}
+
+WGC3Dsizeiptr TestWebGraphicsContext3D::getVertexAttribOffset(
+    WGC3Duint index,
+    WGC3Denum pname) {
+  return 0;
+}
+
+WGC3Dboolean TestWebGraphicsContext3D::isBuffer(
+    WebGLId buffer) {
+  return false;
+}
+
+WGC3Dboolean TestWebGraphicsContext3D::isEnabled(
+    WGC3Denum cap) {
+  return false;
+}
+
+WGC3Dboolean TestWebGraphicsContext3D::isFramebuffer(
+    WebGLId framebuffer) {
+  return false;
+}
+
+WGC3Dboolean TestWebGraphicsContext3D::isProgram(
+    WebGLId program) {
+  return false;
+}
+
+WGC3Dboolean TestWebGraphicsContext3D::isRenderbuffer(
+    WebGLId renderbuffer) {
+  return false;
+}
+
+WGC3Dboolean TestWebGraphicsContext3D::isShader(
+    WebGLId shader) {
+  return false;
+}
+
+WGC3Dboolean TestWebGraphicsContext3D::isTexture(
+    WebGLId texture) {
+  return false;
+}
+
+WebGLId TestWebGraphicsContext3D::createBuffer() {
+  return NextBufferId();
+}
+
+void TestWebGraphicsContext3D::deleteBuffer(WebGLId id) {
+  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_);
+}
+
+WebGLId TestWebGraphicsContext3D::createFramebuffer() {
+  return kFramebufferId | context_id_ << 16;
+}
+
+void TestWebGraphicsContext3D::deleteFramebuffer(WebGLId id) {
+  DCHECK_EQ(kFramebufferId | context_id_ << 16, 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.push_back(texture_id);
+  return texture_id;
+}
+
+void TestWebGraphicsContext3D::deleteTexture(WebGLId texture_id) {
+  base::AutoLock lock(namespace_->lock);
+  std::vector<WebKit::WebGLId>& textures = namespace_->textures;
+  DCHECK(std::find(textures.begin(), textures.end(), texture_id) !=
+         textures.end());
+  textures.erase(std::find(textures.begin(), textures.end(), texture_id));
+}
+
+void TestWebGraphicsContext3D::attachShader(WebGLId program, WebGLId shader) {
+  DCHECK_EQ(kProgramId | context_id_ << 16, program);
+  DCHECK_EQ(kShaderId | context_id_ << 16, shader);
+}
+
+void TestWebGraphicsContext3D::useProgram(WebGLId program) {
+  if (!program)
+    return;
+  DCHECK_EQ(kProgramId | context_id_ << 16, program);
+}
+
+void TestWebGraphicsContext3D::bindFramebuffer(
+    WGC3Denum target, WebGLId framebuffer) {
+  if (!framebuffer)
+    return;
+  DCHECK_EQ(kFramebufferId | context_id_ << 16, framebuffer);
+}
+
+void TestWebGraphicsContext3D::bindRenderbuffer(
+      WGC3Denum target, WebGLId renderbuffer) {
+  if (!renderbuffer)
+    return;
+  DCHECK_EQ(kRenderbufferId | context_id_ << 16, renderbuffer);
+}
+
+void TestWebGraphicsContext3D::bindTexture(
+    WGC3Denum target, WebGLId texture_id) {
+  if (times_bind_texture_succeeds_ >= 0) {
+    if (!times_bind_texture_succeeds_) {
+      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                          GL_INNOCENT_CONTEXT_RESET_ARB);
+    }
+    --times_bind_texture_succeeds_;
+  }
+
+  if (!texture_id)
+    return;
+  if (texture_id == kExternalTextureId)
+    return;
+  base::AutoLock lock(namespace_->lock);
+  std::vector<WebKit::WebGLId>& textures = namespace_->textures;
+  DCHECK(std::find(textures.begin(), textures.end(), texture_id) !=
+         textures.end());
+  used_textures_.insert(texture_id);
+}
+
+void TestWebGraphicsContext3D::endQueryEXT(WGC3Denum target) {
+  if (times_end_query_succeeds_ >= 0) {
+    if (!times_end_query_succeeds_) {
+      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                          GL_INNOCENT_CONTEXT_RESET_ARB);
+    }
+    --times_end_query_succeeds_;
+  }
+}
+
+void TestWebGraphicsContext3D::getQueryObjectuivEXT(
+    WebGLId query,
+    WGC3Denum pname,
+    WGC3Duint* params) {
+  // If the context is lost, behave as if result is available.
+  if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
+    *params = 1;
+}
+
+void TestWebGraphicsContext3D::getIntegerv(
+    WGC3Denum pname,
+    WebKit::WGC3Dint* value) {
+  if (pname == GL_MAX_TEXTURE_SIZE)
+    *value = max_texture_size_;
+  else if (pname == GL_ACTIVE_TEXTURE)
+    *value = GL_TEXTURE0;
+}
+
+void TestWebGraphicsContext3D::genMailboxCHROMIUM(WebKit::WGC3Dbyte* mailbox) {
+  if (times_gen_mailbox_succeeds_ >= 0) {
+    if (!times_gen_mailbox_succeeds_) {
+      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                          GL_INNOCENT_CONTEXT_RESET_ARB);
+    }
+    --times_gen_mailbox_succeeds_;
+  }
+  if (context_lost_) {
+    memset(mailbox, 0, 64);
+    return;
+  }
+
+  static char mailbox_name1 = '1';
+  static char mailbox_name2 = '1';
+  mailbox[0] = mailbox_name1;
+  mailbox[1] = mailbox_name2;
+  mailbox[2] = '\0';
+  if (++mailbox_name1 == 0) {
+    mailbox_name1 = '1';
+    ++mailbox_name2;
+  }
+}
+
+void TestWebGraphicsContext3D::setContextLostCallback(
+    WebGraphicsContextLostCallback* callback) {
+  context_lost_callback_ = callback;
+}
+
+void TestWebGraphicsContext3D::loseContextCHROMIUM(WGC3Denum current,
+                                                   WGC3Denum other) {
+  if (context_lost_)
+    return;
+  context_lost_ = true;
+  if (context_lost_callback_)
+    context_lost_callback_->onContextLost();
+
+  for (size_t i = 0; i < shared_contexts_.size(); ++i)
+    shared_contexts_[i]->loseContextCHROMIUM(current, other);
+  shared_contexts_.clear();
+}
+
+void TestWebGraphicsContext3D::signalSyncPoint(
+    unsigned sync_point,
+    WebGraphicsSyncPointCallback* callback) {
+  sync_point_callbacks_.push_back(callback);
+}
+
+void TestWebGraphicsContext3D::signalQuery(
+    WebKit::WebGLId query,
+    WebGraphicsSyncPointCallback* callback) {
+  sync_point_callbacks_.push_back(callback);
+}
+
+void TestWebGraphicsContext3D::setSwapBuffersCompleteCallbackCHROMIUM(
+    WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback) {
+  if (support_swapbuffers_complete_callback_)
+    swap_buffers_callback_ = callback;
+}
+
+void TestWebGraphicsContext3D::prepareTexture() {
+  if (swap_buffers_callback_) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE, base::Bind(&TestWebGraphicsContext3D::SwapBuffersComplete,
+                              weak_ptr_factory_.GetWeakPtr()));
+  }
+  CallAllSyncPointCallbacks();
+}
+
+void TestWebGraphicsContext3D::finish() {
+  CallAllSyncPointCallbacks();
+}
+
+void TestWebGraphicsContext3D::flush() {
+  CallAllSyncPointCallbacks();
+}
+
+static void CallAndDestroy(
+    WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback* callback) {
+  if (!callback)
+    return;
+  callback->onSyncPointReached();
+  delete callback;
+}
+
+void TestWebGraphicsContext3D::CallAllSyncPointCallbacks() {
+  for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&CallAndDestroy,
+                   sync_point_callbacks_[i]));
+  }
+  sync_point_callbacks_.clear();
+}
+
+void TestWebGraphicsContext3D::SwapBuffersComplete() {
+  if (swap_buffers_callback_)
+    swap_buffers_callback_->onSwapBuffersComplete();
+}
+
+void TestWebGraphicsContext3D::bindBuffer(WebKit::WGC3Denum target,
+                                          WebKit::WebGLId buffer) {
+  bound_buffer_ = buffer;
+  if (!bound_buffer_)
+    return;
+  unsigned context_id = buffer >> 17;
+  unsigned buffer_id = buffer & 0x1ffff;
+  base::AutoLock lock(namespace_->lock);
+  DCHECK(buffer_id && buffer_id < namespace_->next_buffer_id);
+  DCHECK_EQ(context_id, context_id_);
+
+  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
+  if (buffers.count(bound_buffer_) == 0)
+    buffers.set(bound_buffer_, make_scoped_ptr(new Buffer).Pass());
+
+  buffers.get(bound_buffer_)->target = target;
+}
+
+void TestWebGraphicsContext3D::bufferData(WebKit::WGC3Denum target,
+                                          WebKit::WGC3Dsizeiptr size,
+                                          const void* data,
+                                          WebKit::WGC3Denum usage) {
+  base::AutoLock lock(namespace_->lock);
+  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
+  DCHECK_GT(buffers.count(bound_buffer_), 0u);
+  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
+  if (context_lost_) {
+    buffers.get(bound_buffer_)->pixels.reset();
+    return;
+  }
+  buffers.get(bound_buffer_)->pixels.reset(new uint8[size]);
+  if (data != NULL)
+    memcpy(buffers.get(bound_buffer_)->pixels.get(), data, size);
+}
+
+void* TestWebGraphicsContext3D::mapBufferCHROMIUM(WebKit::WGC3Denum target,
+                                                  WebKit::WGC3Denum access) {
+  base::AutoLock lock(namespace_->lock);
+  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
+  DCHECK_GT(buffers.count(bound_buffer_), 0u);
+  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
+  if (times_map_buffer_chromium_succeeds_ >= 0) {
+    if (!times_map_buffer_chromium_succeeds_) {
+      return NULL;
+    }
+    --times_map_buffer_chromium_succeeds_;
+  }
+  return buffers.get(bound_buffer_)->pixels.get();
+}
+
+WebKit::WGC3Dboolean TestWebGraphicsContext3D::unmapBufferCHROMIUM(
+    WebKit::WGC3Denum target) {
+  base::AutoLock lock(namespace_->lock);
+  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
+  DCHECK_GT(buffers.count(bound_buffer_), 0u);
+  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
+  buffers.get(bound_buffer_)->pixels.reset();
+  return true;
+}
+
+WebKit::WGC3Duint TestWebGraphicsContext3D::createImageCHROMIUM(
+      WebKit::WGC3Dsizei width, WebKit::WGC3Dsizei height,
+      WebKit::WGC3Denum internalformat) {
+  DCHECK_EQ(GL_RGBA8_OES, static_cast<int>(internalformat));
+  WebKit::WGC3Duint image_id = NextImageId();
+  base::AutoLock lock(namespace_->lock);
+  ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
+  images.set(image_id, make_scoped_ptr(new Image).Pass());
+  images.get(image_id)->pixels.reset(new uint8[width * height * 4]);
+  return image_id;
+}
+
+void TestWebGraphicsContext3D::destroyImageCHROMIUM(
+    WebKit::WGC3Duint id) {
+  base::AutoLock lock(namespace_->lock);
+  unsigned context_id = id >> 17;
+  unsigned image_id = id & 0x1ffff;
+  DCHECK(image_id && image_id < namespace_->next_image_id);
+  DCHECK_EQ(context_id, context_id_);
+}
+
+void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
+    WebKit::WGC3Duint image_id,
+    WebKit::WGC3Denum pname,
+    WebKit::WGC3Dint* params) {
+  base::AutoLock lock(namespace_->lock);
+  DCHECK_GT(namespace_->images.count(image_id), 0u);
+  DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM, static_cast<int>(pname));
+  *params = 0;
+}
+
+void* TestWebGraphicsContext3D::mapImageCHROMIUM(WebKit::WGC3Duint image_id,
+                                                 WebKit::WGC3Denum access) {
+  base::AutoLock lock(namespace_->lock);
+  ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
+  DCHECK_GT(images.count(image_id), 0u);
+  if (times_map_image_chromium_succeeds_ >= 0) {
+    if (!times_map_image_chromium_succeeds_) {
+      return NULL;
+    }
+    --times_map_image_chromium_succeeds_;
+  }
+  return images.get(image_id)->pixels.get();
+}
+
+void TestWebGraphicsContext3D::unmapImageCHROMIUM(
+    WebKit::WGC3Duint image_id) {
+  base::AutoLock lock(namespace_->lock);
+  DCHECK_GT(namespace_->images.count(image_id), 0u);
+}
+
+size_t TestWebGraphicsContext3D::NumTextures() const {
+  base::AutoLock lock(namespace_->lock);
+  return namespace_->textures.size();
+}
+
+WebKit::WebGLId TestWebGraphicsContext3D::TextureAt(int i) const {
+  base::AutoLock lock(namespace_->lock);
+  return namespace_->textures[i];
+}
+
+WebGLId TestWebGraphicsContext3D::NextTextureId() {
+  base::AutoLock lock(namespace_->lock);
+  WebGLId texture_id = namespace_->next_texture_id++;
+  DCHECK(texture_id < (1 << 16));
+  texture_id |= context_id_ << 16;
+  return texture_id;
+}
+
+WebGLId TestWebGraphicsContext3D::NextBufferId() {
+  base::AutoLock lock(namespace_->lock);
+  WebGLId buffer_id = namespace_->next_buffer_id++;
+  DCHECK(buffer_id < (1 << 17));
+  buffer_id |= context_id_ << 17;
+  return buffer_id;
+}
+
+WebKit::WGC3Duint TestWebGraphicsContext3D::NextImageId() {
+  base::AutoLock lock(namespace_->lock);
+  WGC3Duint image_id = namespace_->next_image_id++;
+  DCHECK(image_id < (1 << 17));
+  image_id |= context_id_ << 17;
+  return image_id;
+}
+
+TestWebGraphicsContext3D::Buffer::Buffer() : target(0) {}
+
+TestWebGraphicsContext3D::Buffer::~Buffer() {}
+
+TestWebGraphicsContext3D::Image::Image() {}
+
+TestWebGraphicsContext3D::Image::~Image() {}
+
+}  // namespace cc
diff --git a/cc/debug/test_web_graphics_context_3d.h b/cc/debug/test_web_graphics_context_3d.h
new file mode 100644
index 0000000..5910d03
--- /dev/null
+++ b/cc/debug/test_web_graphics_context_3d.h
@@ -0,0 +1,279 @@
+// Copyright 2013 The Chromium Authors. 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_DEBUG_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
+#define CC_DEBUG_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/stl_util.h"
+#include "base/synchronization/lock.h"
+#include "cc/base/cc_export.h"
+#include "cc/base/scoped_ptr_hash_map.h"
+#include "cc/debug/fake_web_graphics_context_3d.h"
+#include "third_party/khronos/GLES2/gl2.h"
+
+namespace cc {
+
+class CC_EXPORT TestWebGraphicsContext3D : public FakeWebGraphicsContext3D {
+ public:
+  static scoped_ptr<TestWebGraphicsContext3D> Create();
+
+  virtual ~TestWebGraphicsContext3D();
+
+  virtual bool makeContextCurrent();
+
+  virtual int width();
+  virtual int height();
+
+  virtual void reshapeWithScaleFactor(
+      int width, int height, float scale_factor);
+
+  virtual bool isContextLost();
+  virtual WebKit::WGC3Denum getGraphicsResetStatusARB();
+
+  virtual void attachShader(WebKit::WebGLId program, WebKit::WebGLId shader);
+  virtual void bindFramebuffer(
+      WebKit::WGC3Denum target, WebKit::WebGLId framebuffer);
+  virtual void bindRenderbuffer(
+      WebKit::WGC3Denum target, WebKit::WebGLId renderbuffer);
+  virtual void bindTexture(
+      WebKit::WGC3Denum target,
+      WebKit::WebGLId texture_id);
+
+  virtual WebKit::WGC3Denum checkFramebufferStatus(WebKit::WGC3Denum target);
+
+  virtual Attributes getContextAttributes();
+
+  virtual WebKit::WebString getString(WebKit::WGC3Denum name);
+  virtual WebKit::WGC3Dint getUniformLocation(
+      WebKit::WebGLId program,
+      const WebKit::WGC3Dchar* name);
+  virtual WebKit::WGC3Dsizeiptr getVertexAttribOffset(
+      WebKit::WGC3Duint index,
+      WebKit::WGC3Denum pname);
+
+  virtual WebKit::WGC3Dboolean isBuffer(WebKit::WebGLId buffer);
+  virtual WebKit::WGC3Dboolean isEnabled(WebKit::WGC3Denum cap);
+  virtual WebKit::WGC3Dboolean isFramebuffer(WebKit::WebGLId framebuffer);
+  virtual WebKit::WGC3Dboolean isProgram(WebKit::WebGLId program);
+  virtual WebKit::WGC3Dboolean isRenderbuffer(WebKit::WebGLId renderbuffer);
+  virtual WebKit::WGC3Dboolean isShader(WebKit::WebGLId shader);
+  virtual WebKit::WGC3Dboolean isTexture(WebKit::WebGLId texture);
+
+  virtual void useProgram(WebKit::WebGLId program);
+
+  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 deleteShader(WebKit::WebGLId id);
+  virtual void deleteTexture(WebKit::WebGLId texture_id);
+
+  virtual void endQueryEXT(WebKit::WGC3Denum target);
+  virtual void getQueryObjectuivEXT(
+      WebKit::WebGLId query,
+      WebKit::WGC3Denum pname,
+      WebKit::WGC3Duint* params);
+
+  virtual void getIntegerv(
+      WebKit::WGC3Denum pname,
+      WebKit::WGC3Dint* value);
+
+  virtual void genMailboxCHROMIUM(WebKit::WGC3Dbyte* mailbox);
+  virtual void produceTextureCHROMIUM(WebKit::WGC3Denum target,
+                                      const WebKit::WGC3Dbyte* mailbox) { }
+  virtual void consumeTextureCHROMIUM(WebKit::WGC3Denum target,
+                                      const WebKit::WGC3Dbyte* mailbox) { }
+
+  virtual void setContextLostCallback(
+      WebGraphicsContextLostCallback* callback);
+
+  virtual void loseContextCHROMIUM(WebKit::WGC3Denum current,
+                                   WebKit::WGC3Denum other);
+
+  // Takes ownership of the |callback|.
+  virtual void signalSyncPoint(unsigned sync_point,
+                               WebGraphicsSyncPointCallback* callback);
+  virtual void signalQuery(WebKit::WebGLId query,
+                           WebGraphicsSyncPointCallback* callback);
+
+  virtual void setSwapBuffersCompleteCallbackCHROMIUM(
+      WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback);
+
+  virtual void prepareTexture();
+  virtual void finish();
+  virtual void flush();
+
+  virtual void bindBuffer(WebKit::WGC3Denum target, WebKit::WebGLId buffer);
+  virtual void bufferData(WebKit::WGC3Denum target,
+                          WebKit::WGC3Dsizeiptr size,
+                          const void* data,
+                          WebKit::WGC3Denum usage);
+  virtual void* mapBufferCHROMIUM(WebKit::WGC3Denum target,
+                                  WebKit::WGC3Denum access);
+  virtual WebKit::WGC3Dboolean unmapBufferCHROMIUM(WebKit::WGC3Denum target);
+
+  virtual WebKit::WGC3Duint createImageCHROMIUM(
+      WebKit::WGC3Dsizei width,
+      WebKit::WGC3Dsizei height,
+      WebKit::WGC3Denum internalformat);
+  virtual void destroyImageCHROMIUM(WebKit::WGC3Duint image_id);
+  virtual void getImageParameterivCHROMIUM(
+      WebKit::WGC3Duint image_id,
+      WebKit::WGC3Denum pname,
+      WebKit::WGC3Dint* params);
+  virtual void* mapImageCHROMIUM(
+      WebKit::WGC3Duint image_id,
+      WebKit::WGC3Denum access);
+  virtual void unmapImageCHROMIUM(WebKit::WGC3Duint image_id);
+
+  // When set, MakeCurrent() will fail after this many times.
+  void set_times_make_current_succeeds(int times) {
+    times_make_current_succeeds_ = times;
+  }
+  void set_times_bind_texture_succeeds(int times) {
+    times_bind_texture_succeeds_ = times;
+  }
+  void set_times_end_query_succeeds(int times) {
+    times_end_query_succeeds_ = times;
+  }
+  void set_times_gen_mailbox_succeeds(int times) {
+    times_gen_mailbox_succeeds_ = times;
+  }
+
+  // When set, mapImageCHROMIUM and mapBufferCHROMIUM will return NULL after
+  // this many times.
+  void set_times_map_image_chromium_succeeds(int times) {
+    times_map_image_chromium_succeeds_ = times;
+  }
+  void set_times_map_buffer_chromium_succeeds(int times) {
+    times_map_buffer_chromium_succeeds_ = times;
+  }
+
+  size_t NumTextures() const;
+  WebKit::WebGLId TextureAt(int i) const;
+
+  size_t NumUsedTextures() const { return used_textures_.size(); }
+  bool UsedTexture(int texture) const {
+    return ContainsKey(used_textures_, texture);
+  }
+  void ResetUsedTextures() { used_textures_.clear(); }
+
+  void set_support_swapbuffers_complete_callback(bool support) {
+    support_swapbuffers_complete_callback_ = support;
+  }
+  void set_have_extension_io_surface(bool have) {
+    have_extension_io_surface_ = have;
+  }
+  void set_have_extension_egl_image(bool have) {
+    have_extension_egl_image_ = have;
+  }
+
+  // When this context is lost, all contexts in its share group are also lost.
+  void add_share_group_context(WebKit::WebGraphicsContext3D* context3d) {
+    shared_contexts_.push_back(context3d);
+  }
+
+  void set_max_texture_size(int size) { max_texture_size_ = size; }
+
+  static const WebKit::WebGLId kExternalTextureId;
+  virtual WebKit::WebGLId NextTextureId();
+
+  virtual WebKit::WebGLId NextBufferId();
+
+  virtual WebKit::WebGLId NextImageId();
+
+ protected:
+  struct Buffer {
+    Buffer();
+    ~Buffer();
+
+    WebKit::WGC3Denum target;
+    scoped_ptr<uint8[]> pixels;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Buffer);
+  };
+
+  struct Image {
+    Image();
+    ~Image();
+
+    scoped_ptr<uint8[]> pixels;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Image);
+  };
+
+  struct Namespace : public base::RefCountedThreadSafe<Namespace> {
+    Namespace();
+
+    // Protects all fields.
+    base::Lock lock;
+    unsigned next_buffer_id;
+    unsigned next_image_id;
+    unsigned next_texture_id;
+    std::vector<WebKit::WebGLId> textures;
+    ScopedPtrHashMap<unsigned, Buffer> buffers;
+    ScopedPtrHashMap<unsigned, Image> images;
+
+   private:
+    friend class base::RefCountedThreadSafe<Namespace>;
+    ~Namespace();
+    DISALLOW_COPY_AND_ASSIGN(Namespace);
+  };
+
+  TestWebGraphicsContext3D();
+  TestWebGraphicsContext3D(
+      const WebKit::WebGraphicsContext3D::Attributes& attributes);
+
+  void CallAllSyncPointCallbacks();
+  void SwapBuffersComplete();
+  void CreateNamespace();
+
+  unsigned context_id_;
+  Attributes attributes_;
+  bool support_swapbuffers_complete_callback_;
+  bool have_extension_io_surface_;
+  bool have_extension_egl_image_;
+  int times_make_current_succeeds_;
+  int times_bind_texture_succeeds_;
+  int times_end_query_succeeds_;
+  int times_gen_mailbox_succeeds_;
+  bool context_lost_;
+  int times_map_image_chromium_succeeds_;
+  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_;
+  int width_;
+  int height_;
+
+  unsigned bound_buffer_;
+
+  scoped_refptr<Namespace> namespace_;
+  static Namespace* shared_namespace_;
+
+  base::WeakPtrFactory<TestWebGraphicsContext3D> weak_ptr_factory_;
+};
+
+}  // namespace cc
+
+#endif  // CC_DEBUG_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
diff --git a/cc/layers/compositing_reasons.h b/cc/layers/compositing_reasons.h
index 28c2f7b..4c9f633 100644
--- a/cc/layers/compositing_reasons.h
+++ b/cc/layers/compositing_reasons.h
@@ -52,6 +52,8 @@
 const uint64 kCompositingReasonLayerForForeground = GG_UINT64_C(1) << 29;
 const uint64 kCompositingReasonLayerForBackground = GG_UINT64_C(1) << 30;
 const uint64 kCompositingReasonLayerForMask = GG_UINT64_C(1) << 31;
+const uint64 kCompositingReasonOverflowScrollingParent = GG_UINT64_C(1) << 32;
+const uint64 kCompositingReasonOutOfFlowClipping = GG_UINT64_C(1) << 33;
 
 typedef uint64 CompositingReasons;
 
diff --git a/cc/layers/content_layer.cc b/cc/layers/content_layer.cc
index 2053ecb..01a8922 100644
--- a/cc/layers/content_layer.cc
+++ b/cc/layers/content_layer.cc
@@ -29,6 +29,12 @@
   base::TimeTicks paint_start = base::TimeTicks::HighResNow();
   client_->PaintContents(canvas, content_rect, opaque);
   base::TimeTicks paint_end = base::TimeTicks::HighResNow();
+  // The start and end times might be the same if the paint was very fast or if
+  // our timer granularity is poor. Treat this as a very short time duration
+  // instead of none to avoid dividing by zero.
+  if (paint_end == paint_start)
+    paint_end += base::TimeDelta::FromMicroseconds(1);
+
   double pixels_per_sec = (content_rect.width() * content_rect.height()) /
                           (paint_end - paint_start).InSecondsF();
   UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.AccelContentPaintDurationMS",
@@ -145,4 +151,19 @@
   return true;
 }
 
+skia::RefPtr<SkPicture> ContentLayer::GetPicture() const {
+  if (!DrawsContent())
+    return skia::RefPtr<SkPicture>();
+
+  int width = bounds().width();
+  int height = bounds().height();
+  gfx::RectF opaque;
+
+  skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
+  SkCanvas* canvas = picture->beginRecording(width, height);
+  client_->PaintContents(canvas, gfx::Rect(width, height), &opaque);
+  picture->endRecording();
+  return picture;
+}
+
 }  // namespace cc
diff --git a/cc/layers/content_layer.h b/cc/layers/content_layer.h
index f49215b..a076c31 100644
--- a/cc/layers/content_layer.h
+++ b/cc/layers/content_layer.h
@@ -52,6 +52,8 @@
 
   virtual bool SupportsLCDText() const OVERRIDE;
 
+  virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE;
+
  protected:
   explicit ContentLayer(ContentLayerClient* client);
   virtual ~ContentLayer();
diff --git a/cc/layers/delegated_renderer_layer.cc b/cc/layers/delegated_renderer_layer.cc
index 66064d9..0ffa54a 100644
--- a/cc/layers/delegated_renderer_layer.cc
+++ b/cc/layers/delegated_renderer_layer.cc
@@ -68,27 +68,17 @@
 void DelegatedRendererLayer::SetFrameData(
     scoped_ptr<DelegatedFrameData> new_frame_data) {
   if (frame_data_) {
-    // Copy the resources from the last provided frame into the new frame, as
-    // it may use resources that were transferred in the last frame.
-    new_frame_data->resource_list.insert(new_frame_data->resource_list.end(),
-                                         frame_data_->resource_list.begin(),
-                                         frame_data_->resource_list.end());
+    // Copy the resources from the last provided frame into the unused resources
+    // list, as the new frame will provide its own resources.
+    TransferableResource::ReturnResources(
+        frame_data_->resource_list,
+        &unused_resources_for_child_compositor_);
   }
   frame_data_ = new_frame_data.Pass();
   if (!frame_data_->render_pass_list.empty()) {
     RenderPass* root_pass = frame_data_->render_pass_list.back();
     damage_in_frame_.Union(root_pass->damage_rect);
     frame_size_ = root_pass->output_rect.size();
-
-    // TODO(danakj): This could be optimized to only add resources to the
-    // frame_data_ if they are actually used in the frame. For now, it will
-    // cause the parent (this layer) to hold onto some resources it doesn't
-    // need to for an extra frame.
-    for (size_t i = 0; i < unused_resources_for_child_compositor_.size(); ++i) {
-      frame_data_->resource_list.push_back(
-          unused_resources_for_child_compositor_[i]);
-    }
-    unused_resources_for_child_compositor_.clear();
   } else {
     frame_size_ = gfx::Size();
   }
@@ -96,7 +86,7 @@
 }
 
 void DelegatedRendererLayer::TakeUnusedResourcesForChildCompositor(
-    TransferableResourceArray* array) {
+    ReturnedResourceArray* array) {
   DCHECK(array->empty());
   array->clear();
 
diff --git a/cc/layers/delegated_renderer_layer.h b/cc/layers/delegated_renderer_layer.h
index 3f5280e..f16217b 100644
--- a/cc/layers/delegated_renderer_layer.h
+++ b/cc/layers/delegated_renderer_layer.h
@@ -7,7 +7,7 @@
 
 #include "cc/base/cc_export.h"
 #include "cc/layers/layer.h"
-#include "cc/resources/transferable_resource.h"
+#include "cc/resources/returned_resource.h"
 
 namespace cc {
 
@@ -34,7 +34,7 @@
 
   // Passes ownership of any unused resources that had been given by the child
   // compositor to the given array, so they can be given back to the child.
-  void TakeUnusedResourcesForChildCompositor(TransferableResourceArray* array);
+  void TakeUnusedResourcesForChildCompositor(ReturnedResourceArray* array);
 
   virtual bool BlocksPendingCommit() const OVERRIDE;
 
@@ -47,7 +47,7 @@
   gfx::RectF damage_in_frame_;
   gfx::Size frame_size_;
   gfx::Size display_size_;
-  TransferableResourceArray unused_resources_for_child_compositor_;
+  ReturnedResourceArray unused_resources_for_child_compositor_;
 
   DelegatedRendererLayerClient* client_;
 
diff --git a/cc/layers/delegated_renderer_layer_impl.cc b/cc/layers/delegated_renderer_layer_impl.cc
index 2dfdac6..426dcbb 100644
--- a/cc/layers/delegated_renderer_layer_impl.cc
+++ b/cc/layers/delegated_renderer_layer_impl.cc
@@ -145,7 +145,7 @@
 }
 
 void DelegatedRendererLayerImpl::CollectUnusedResources(
-    TransferableResourceArray* resources_for_ack) {
+    ReturnedResourceArray* resources_for_ack) {
   CreateChildIdIfNeeded();
   DCHECK(child_id_);
 
@@ -163,7 +163,7 @@
     if (!resource_is_in_current_frame && !resource_is_in_use)
       unused_resources.push_back(it->second);
   }
-  resource_provider->PrepareSendToChild(
+  resource_provider->PrepareSendReturnsToChild(
       child_id_, unused_resources, resources_for_ack);
 }
 
diff --git a/cc/layers/delegated_renderer_layer_impl.h b/cc/layers/delegated_renderer_layer_impl.h
index 9cfdcb6..89b2537 100644
--- a/cc/layers/delegated_renderer_layer_impl.h
+++ b/cc/layers/delegated_renderer_layer_impl.h
@@ -43,7 +43,7 @@
   void SetFrameData(scoped_ptr<DelegatedFrameData> frame_data,
                     gfx::RectF damage_in_frame);
 
-  void CollectUnusedResources(TransferableResourceArray* resources_for_ack);
+  void CollectUnusedResources(ReturnedResourceArray* resources_for_ack);
 
   void SetDisplaySize(gfx::Size size);
 
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index 1584782..401ac3c 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include "cc/layers/delegated_renderer_layer_impl.h"
 
 #include "cc/base/scoped_ptr_vector.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/quad_sink.h"
 #include "cc/layers/solid_color_layer_impl.h"
@@ -20,7 +21,6 @@
 #include "cc/test/mock_quad_culler.h"
 #include "cc/test/render_pass_test_common.h"
 #include "cc/test/render_pass_test_utils.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
@@ -38,20 +38,15 @@
     LayerTreeSettings settings;
     settings.minimum_occlusion_tracking_size = gfx::Size();
 
-    host_impl_ = LayerTreeHostImpl::Create(settings,
-                                           &client_,
-                                           &proxy_,
-                                           &stats_instrumentation_);
+    host_impl_.reset(new FakeLayerTreeHostImpl(settings, &proxy_));
     host_impl_->InitializeRenderer(CreateFakeOutputSurface());
     host_impl_->SetViewportSize(gfx::Size(10, 10));
   }
 
  protected:
   FakeProxy proxy_;
-  FakeLayerTreeHostImplClient client_;
   DebugScopedSetImplThreadAndMainThreadBlocked
       always_impl_thread_and_main_thread_blocked_;
-  FakeRenderingStatsInstrumentation stats_instrumentation_;
   scoped_ptr<LayerTreeHostImpl> host_impl_;
 };
 
diff --git a/cc/layers/heads_up_display_layer.cc b/cc/layers/heads_up_display_layer.cc
index 92486cc..d9fab90 100644
--- a/cc/layers/heads_up_display_layer.cc
+++ b/cc/layers/heads_up_display_layer.cc
@@ -55,4 +55,8 @@
       PassAs<LayerImpl>();
 }
 
+std::string HeadsUpDisplayLayer::DebugName() {
+  return std::string("Heads Up Display Layer");
+}
+
 }  // namespace cc
diff --git a/cc/layers/heads_up_display_layer.h b/cc/layers/heads_up_display_layer.h
index 7038cd4..f13d56b 100644
--- a/cc/layers/heads_up_display_layer.h
+++ b/cc/layers/heads_up_display_layer.h
@@ -5,6 +5,8 @@
 #ifndef CC_LAYERS_HEADS_UP_DISPLAY_LAYER_H_
 #define CC_LAYERS_HEADS_UP_DISPLAY_LAYER_H_
 
+#include <string>
+
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
 #include "cc/layers/contents_scaling_layer.h"
@@ -23,6 +25,8 @@
   virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
       OVERRIDE;
 
+  virtual std::string DebugName() OVERRIDE;
+
  protected:
   HeadsUpDisplayLayer();
 
diff --git a/cc/layers/io_surface_layer_impl.cc b/cc/layers/io_surface_layer_impl.cc
index f8577a3..e8c627b 100644
--- a/cc/layers/io_surface_layer_impl.cc
+++ b/cc/layers/io_surface_layer_impl.cc
@@ -39,11 +39,11 @@
   }
 
   if (io_surface_texture_id_) {
-    OutputSurface* output_surface = layer_tree_impl()->output_surface();
+    ContextProvider* context_provider =
+        layer_tree_impl()->output_surface()->context_provider().get();
     // TODO(skaslev): Implement this path for software compositing.
-    WebKit::WebGraphicsContext3D* context3d = output_surface->context3d();
-    if (context3d)
-      context3d->deleteTexture(io_surface_texture_id_);
+    if (context_provider)
+      context_provider->Context3d()->deleteTexture(io_surface_texture_id_);
     io_surface_texture_id_ = 0;
   }
 }
@@ -67,13 +67,15 @@
     return false;
 
   if (io_surface_changed_) {
-    WebKit::WebGraphicsContext3D* context3d =
-        resource_provider->GraphicsContext3D();
-    if (!context3d) {
+    ContextProvider* context_provider =
+        layer_tree_impl()->output_surface()->context_provider().get();
+    if (!context_provider) {
       // TODO(skaslev): Implement this path for software compositing.
       return false;
     }
 
+    WebKit::WebGraphicsContext3D* context3d = context_provider->Context3d();
+
     // TODO(ernstm): Do this in a way that we can track memory usage.
     if (!io_surface_texture_id_) {
       io_surface_texture_id_ = context3d->createTexture();
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index aa4a002..6b71982 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -6,12 +6,14 @@
 
 #include <algorithm>
 
+#include "base/debug/trace_event.h"
 #include "base/location.h"
 #include "base/metrics/histogram.h"
 #include "base/single_thread_task_runner.h"
 #include "cc/animation/animation.h"
 #include "cc/animation/animation_events.h"
 #include "cc/animation/layer_animation_controller.h"
+#include "cc/layers/layer_client.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
@@ -54,8 +56,11 @@
       use_parent_backface_visibility_(false),
       draw_checkerboard_for_missing_tiles_(false),
       force_render_surface_(false),
+      scroll_parent_(NULL),
+      clip_parent_(NULL),
       replica_layer_(NULL),
-      raster_scale_(0.f) {
+      raster_scale_(0.f),
+      client_(NULL) {
   if (layer_id_ < 0) {
     s_next_layer_id = 1;
     layer_id_ = s_next_layer_id++;
@@ -85,6 +90,9 @@
     DCHECK_EQ(this, replica_layer_->parent());
     replica_layer_->RemoveFromParent();
   }
+
+  RemoveFromScrollTree();
+  RemoveFromClipTree();
 }
 
 void Layer::SetLayerTreeHost(LayerTreeHost* host) {
@@ -192,6 +200,10 @@
   return false;
 }
 
+skia::RefPtr<SkPicture> Layer::GetPicture() const {
+  return skia::RefPtr<SkPicture>();
+}
+
 bool Layer::CanClipSelf() const {
   return false;
 }
@@ -559,6 +571,66 @@
   return layer_animation_controller_->IsAnimatingProperty(Animation::Transform);
 }
 
+void Layer::SetScrollParent(Layer* parent) {
+  DCHECK(IsPropertyChangeAllowed());
+  if (scroll_parent_ == parent)
+    return;
+
+  if (scroll_parent_)
+    scroll_parent_->RemoveScrollChild(this);
+
+  scroll_parent_ = parent;
+
+  if (scroll_parent_)
+    scroll_parent_->AddScrollChild(this);
+
+  SetNeedsCommit();
+}
+
+void Layer::AddScrollChild(Layer* child) {
+  if (!scroll_children_)
+    scroll_children_.reset(new std::set<Layer*>);
+  scroll_children_->insert(child);
+  SetNeedsCommit();
+}
+
+void Layer::RemoveScrollChild(Layer* child) {
+  scroll_children_->erase(child);
+  if (scroll_children_->empty())
+    scroll_children_.reset();
+  SetNeedsCommit();
+}
+
+void Layer::SetClipParent(Layer* ancestor) {
+  DCHECK(IsPropertyChangeAllowed());
+  if (clip_parent_ == ancestor)
+    return;
+
+  if (clip_parent_)
+    clip_parent_->RemoveClipChild(this);
+
+  clip_parent_ = ancestor;
+
+  if (clip_parent_)
+    clip_parent_->AddClipChild(this);
+
+  SetNeedsCommit();
+}
+
+void Layer::AddClipChild(Layer* child) {
+  if (!clip_children_)
+    clip_children_.reset(new std::set<Layer*>);
+  clip_children_->insert(child);
+  SetNeedsCommit();
+}
+
+void Layer::RemoveClipChild(Layer* child) {
+  clip_children_->erase(child);
+  if (clip_children_->empty())
+    clip_children_.reset();
+  SetNeedsCommit();
+}
+
 void Layer::SetScrollOffset(gfx::Vector2d scroll_offset) {
   DCHECK(IsPropertyChangeAllowed());
   if (scroll_offset_ == scroll_offset)
@@ -627,6 +699,7 @@
   if (touch_event_handler_region_ == region)
     return;
   touch_event_handler_region_ = region;
+  SetNeedsCommit();
 }
 
 void Layer::SetDrawCheckerboardForMissingTiles(bool checkerboard) {
@@ -742,7 +815,15 @@
                                         : bounds_);
   layer->SetContentBounds(content_bounds());
   layer->SetContentsScale(contents_scale_x(), contents_scale_y());
-  layer->SetDebugName(debug_name_);
+
+  bool is_tracing;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+                                     &is_tracing);
+  if (is_tracing)
+      layer->SetDebugName(DebugName());
+  else
+      layer->SetDebugName(std::string());
+
   layer->SetCompositingReasons(compositing_reasons_);
   layer->SetDoubleSided(double_sided_);
   layer->SetDrawCheckerboardForMissingTiles(
@@ -778,6 +859,37 @@
   layer->SetScrollOffset(scroll_offset_);
   layer->SetMaxScrollOffset(max_scroll_offset_);
 
+  LayerImpl* scroll_parent = NULL;
+  if (scroll_parent_)
+    scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
+
+  layer->SetScrollParent(scroll_parent);
+  if (scroll_children_) {
+    std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>;
+    for (std::set<Layer*>::iterator it = scroll_children_->begin();
+        it != scroll_children_->end(); ++it)
+      scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+    layer->SetScrollChildren(scroll_children);
+  }
+
+  LayerImpl* clip_parent = NULL;
+  if (clip_parent_) {
+    clip_parent =
+        layer->layer_tree_impl()->LayerById(clip_parent_->id());
+  }
+
+  layer->SetClipParent(clip_parent);
+  if (clip_children_) {
+    std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>;
+    for (std::set<Layer*>::iterator it = clip_children_->begin();
+        it != clip_children_->end(); ++it) {
+      LayerImpl* clip_child = layer->layer_tree_impl()->LayerById((*it)->id());
+      DCHECK(clip_child);
+      clip_children->insert(clip_child);
+    }
+    layer->SetClipChildren(clip_children);
+  }
+
   // Wrap the copy_requests_ in a PostTask to the main thread.
   ScopedPtrVector<CopyOutputRequest> main_thread_copy_requests;
   for (ScopedPtrVector<CopyOutputRequest>::iterator it = copy_requests_.begin();
@@ -805,19 +917,10 @@
   update_rect_.Union(layer->update_rect());
   layer->set_update_rect(update_rect_);
 
-  if (layer->layer_tree_impl()->settings().impl_side_painting) {
-    DCHECK(layer->layer_tree_impl()->IsPendingTree());
-    LayerImpl* active_twin =
-        layer->layer_tree_impl()->FindActiveTreeLayerById(id());
-    // Update the scroll delta from the active layer, which may have
-    // adjusted its scroll delta prior to this pending layer being created.
-    // This code is identical to that in LayerImpl::SetScrollDelta.
-    if (active_twin) {
-      DCHECK(layer->sent_scroll_delta().IsZero());
-      layer->SetScrollDelta(active_twin->ScrollDelta() -
-                            active_twin->sent_scroll_delta());
-    }
-  } else {
+  // 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.
+  if (!layer->layer_tree_impl()->settings().impl_side_painting) {
     layer->SetScrollDelta(layer->ScrollDelta() - layer->sent_scroll_delta());
     layer->SetSentScrollDelta(gfx::Vector2d());
   }
@@ -868,9 +971,8 @@
   return false;
 }
 
-void Layer::SetDebugName(const std::string& debug_name) {
-  debug_name_ = debug_name;
-  SetNeedsCommit();
+std::string Layer::DebugName() {
+  return client_ ? client_->DebugName() : std::string();
 }
 
 void Layer::SetCompositingReasons(CompositingReasons reasons) {
@@ -967,7 +1069,7 @@
   return Region();
 }
 
-ScrollbarLayer* Layer::ToScrollbarLayer() {
+PaintedScrollbarLayer* Layer::ToScrollbarLayer() {
   return NULL;
 }
 
@@ -979,4 +1081,30 @@
   return false;
 }
 
+void Layer::RemoveFromScrollTree() {
+  if (scroll_children_.get()) {
+    for (std::set<Layer*>::iterator it = scroll_children_->begin();
+        it != scroll_children_->end(); ++it)
+      (*it)->scroll_parent_ = NULL;
+  }
+
+  if (scroll_parent_)
+    scroll_parent_->RemoveScrollChild(this);
+
+  scroll_parent_ = NULL;
+}
+
+void Layer::RemoveFromClipTree() {
+  if (clip_children_.get()) {
+    for (std::set<Layer*>::iterator it = clip_children_->begin();
+        it != clip_children_->end(); ++it)
+      (*it)->clip_parent_ = NULL;
+  }
+
+  if (clip_parent_)
+    clip_parent_->RemoveClipChild(this);
+
+  clip_parent_ = NULL;
+}
+
 }  // namespace cc
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 035e071..5519651 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -5,6 +5,7 @@
 #ifndef CC_LAYERS_LAYER_H_
 #define CC_LAYERS_LAYER_H_
 
+#include <set>
 #include <string>
 
 #include "base/callback.h"
@@ -26,10 +27,15 @@
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkPicture.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/rect_f.h"
 #include "ui/gfx/transform.h"
 
+namespace gfx {
+class BoxF;
+}
+
 namespace cc {
 
 class Animation;
@@ -38,13 +44,14 @@
 class CopyOutputRequest;
 class LayerAnimationDelegate;
 class LayerAnimationEventObserver;
+class LayerClient;
 class LayerImpl;
 class LayerTreeHost;
 class LayerTreeImpl;
+class PaintedScrollbarLayer;
 class PriorityCalculator;
 class RenderingStatsInstrumentation;
 class ResourceUpdateQueue;
-class ScrollbarLayer;
 struct AnimationEvent;
 
 // Base class for composited layers. Special layer types are derived from
@@ -151,6 +158,34 @@
   const gfx::Transform& transform() const { return transform_; }
   bool TransformIsAnimating() const;
 
+  void SetScrollParent(Layer* parent);
+
+  Layer* scroll_parent() { return scroll_parent_; }
+  const Layer* scroll_parent() const { return scroll_parent_; }
+
+  void AddScrollChild(Layer* child);
+  void RemoveScrollChild(Layer* child);
+
+  std::set<Layer*>* scroll_children() { return scroll_children_.get(); }
+  const std::set<Layer*>* scroll_children() const {
+    return scroll_children_.get();
+  }
+
+  void SetClipParent(Layer* ancestor);
+
+  Layer* clip_parent() { return clip_parent_; }
+  const Layer* clip_parent() const {
+    return clip_parent_;
+  }
+
+  void AddClipChild(Layer* child);
+  void RemoveClipChild(Layer* child);
+
+  std::set<Layer*>* clip_children() { return clip_children_.get(); }
+  const std::set<Layer*>* clip_children() const {
+    return clip_children_.get();
+  }
+
   DrawProperties<Layer, RenderSurface>& draw_properties() {
     return draw_properties_;
   }
@@ -292,7 +327,10 @@
   virtual void SetIsMask(bool is_mask) {}
   virtual void ReduceMemoryUsage() {}
 
-  void SetDebugName(const std::string& debug_name);
+  virtual std::string DebugName();
+
+  void SetLayerClient(LayerClient* client) { client_ = client; }
+
   void SetCompositingReasons(CompositingReasons reasons);
 
   virtual void PushPropertiesTo(LayerImpl* layer);
@@ -328,6 +366,10 @@
   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);
+  }
+
   LayerAnimationController* layer_animation_controller() {
     return layer_animation_controller_.get();
   }
@@ -347,7 +389,7 @@
 
   virtual Region VisibleContentOpaqueRegion() const;
 
-  virtual ScrollbarLayer* ToScrollbarLayer();
+  virtual PaintedScrollbarLayer* ToScrollbarLayer();
 
   gfx::Rect LayerRectToContentRect(const gfx::RectF& layer_rect) const;
 
@@ -358,6 +400,8 @@
   // Returns true if anything in this tree blocksPendingCommit.
   bool BlocksPendingCommitRecursive() const;
 
+  virtual skia::RefPtr<SkPicture> GetPicture() const;
+
   virtual bool CanClipSelf() const;
 
   // Constructs a LayerImpl of the correct runtime type for this Layer type.
@@ -416,6 +460,14 @@
     return needs_push_properties() || descendant_needs_push_properties();
   }
 
+  // If this layer has a scroll parent, it removes |this| from its list of
+  // scroll children.
+  void RemoveFromScrollTree();
+
+  // If this layer has a clip parent, it removes |this| from its list of clip
+  // children.
+  void RemoveFromClipTree();
+
   void reset_raster_scale_to_unknown() { raster_scale_ = 0.f; }
 
   // This flag is set when the layer needs to push properties to the impl
@@ -504,6 +556,11 @@
   bool use_parent_backface_visibility_;
   bool draw_checkerboard_for_missing_tiles_;
   bool force_render_surface_;
+  Layer* scroll_parent_;
+  scoped_ptr<std::set<Layer*> > scroll_children_;
+
+  Layer* clip_parent_;
+  scoped_ptr<std::set<Layer*> > clip_children_;
 
   gfx::Transform transform_;
   gfx::Transform sublayer_transform_;
@@ -514,6 +571,8 @@
   // Transient properties.
   float raster_scale_;
 
+  LayerClient* client_;
+
   ScopedPtrVector<CopyOutputRequest> copy_requests_;
 
   base::Closure did_scroll_callback_;
diff --git a/cc/layers/layer_client.h b/cc/layers/layer_client.h
new file mode 100644
index 0000000..73c0fd2
--- /dev/null
+++ b/cc/layers/layer_client.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 CC_LAYERS_LAYER_CLIENT_H_
+#define CC_LAYERS_LAYER_CLIENT_H_
+
+#include <string>
+
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+class CC_EXPORT LayerClient {
+ public:
+  virtual std::string DebugName() = 0;
+
+ protected:
+  virtual ~LayerClient() {}
+};
+
+}  // namespace cc
+
+#endif  // CC_LAYERS_LAYER_CLIENT_H_
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 480cee0..d77f8f7 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -14,8 +14,8 @@
 #include "cc/debug/layer_tree_debug_state.h"
 #include "cc/debug/traced_value.h"
 #include "cc/input/layer_scroll_offset_delegate.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/layers/quad_sink.h"
-#include "cc/layers/scrollbar_layer_impl.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/quads/debug_border_draw_quad.h"
 #include "cc/trees/layer_tree_impl.h"
@@ -29,6 +29,8 @@
 
 LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
     : parent_(NULL),
+      scroll_parent_(NULL),
+      clip_parent_(NULL),
       mask_layer_id_(-1),
       replica_layer_id_(-1),
       layer_id_(id),
@@ -73,6 +75,24 @@
 
   layer_tree_impl_->UnregisterLayer(this);
   layer_animation_controller_->RemoveValueObserver(this);
+
+  if (scroll_children_) {
+    for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
+        it != scroll_children_->end(); ++it)
+      (*it)->scroll_parent_ = NULL;
+  }
+
+  if (scroll_parent_)
+    scroll_parent_->RemoveScrollChild(this);
+
+  if (clip_children_) {
+    for (std::set<LayerImpl*>::iterator it = clip_children_->begin();
+        it != clip_children_->end(); ++it)
+      (*it)->clip_parent_ = NULL;
+  }
+
+  if (clip_parent_)
+    clip_parent_->RemoveClipChild(this);
 }
 
 void LayerImpl::AddChild(scoped_ptr<LayerImpl> child) {
@@ -104,6 +124,64 @@
   layer_tree_impl()->set_needs_update_draw_properties();
 }
 
+bool LayerImpl::HasAncestor(const LayerImpl* ancestor) const {
+  if (!ancestor)
+    return false;
+
+  for (const LayerImpl* layer = this; layer; layer = layer->parent()) {
+    if (layer == ancestor)
+      return true;
+  }
+
+  return false;
+}
+
+void LayerImpl::SetScrollParent(LayerImpl* parent) {
+  if (scroll_parent_ == parent)
+    return;
+
+  if (scroll_parent_)
+    scroll_parent_->RemoveScrollChild(this);
+
+  scroll_parent_ = parent;
+}
+
+void LayerImpl::SetScrollChildren(std::set<LayerImpl*>* children) {
+  if (scroll_children_.get() == children)
+    return;
+  scroll_children_.reset(children);
+}
+
+void LayerImpl::RemoveScrollChild(LayerImpl* child) {
+  DCHECK(scroll_children_);
+  scroll_children_->erase(child);
+  if (scroll_children_->empty())
+    scroll_children_.reset();
+}
+
+void LayerImpl::SetClipParent(LayerImpl* ancestor) {
+  if (clip_parent_ == ancestor)
+    return;
+
+  if (clip_parent_)
+    clip_parent_->RemoveClipChild(this);
+
+  clip_parent_ = ancestor;
+}
+
+void LayerImpl::SetClipChildren(std::set<LayerImpl*>* children) {
+  if (clip_children_.get() == children)
+    return;
+  clip_children_.reset(children);
+}
+
+void LayerImpl::RemoveClipChild(LayerImpl* child) {
+  DCHECK(clip_children_);
+  clip_children_->erase(child);
+  if (clip_children_->empty())
+    clip_children_.reset();
+}
+
 void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) {
   if (requests->empty())
     return;
@@ -272,7 +350,7 @@
   return unscrolled;
 }
 
-void LayerImpl::ApplySentScrollDeltas() {
+void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() {
   // Pending tree never has sent scroll deltas
   DCHECK(layer_tree_impl()->IsActiveTree());
 
@@ -292,6 +370,25 @@
   sent_scroll_delta_ = gfx::Vector2d();
 }
 
+void LayerImpl::ApplyScrollDeltasSinceBeginFrame() {
+  // Only the pending tree can have missing scrolls.
+  DCHECK(layer_tree_impl()->IsPendingTree());
+  if (!scrollable())
+    return;
+
+  // Pending tree should never have sent scroll deltas.
+  DCHECK(sent_scroll_delta().IsZero());
+
+  LayerImpl* active_twin = layer_tree_impl()->FindActiveTreeLayerById(id());
+  if (active_twin) {
+    // Scrolls that happens after begin frame (where the sent scroll delta
+    // comes from) and commit need to be applied to the pending tree
+    // so that it is up to date with the total scroll.
+    SetScrollDelta(active_twin->ScrollDelta() -
+                   active_twin->sent_scroll_delta());
+  }
+}
+
 InputHandler::ScrollStatus LayerImpl::TryScroll(
     gfx::PointF screen_space_point,
     InputHandler::ScrollInputType type) const {
@@ -422,6 +519,34 @@
   layer->SetScrollOffset(scroll_offset_);
   layer->SetMaxScrollOffset(max_scroll_offset_);
 
+  LayerImpl* scroll_parent = NULL;
+  if (scroll_parent_)
+    scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
+
+  layer->SetScrollParent(scroll_parent);
+  if (scroll_children_) {
+    std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>;
+    for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
+        it != scroll_children_->end(); ++it)
+      scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+    layer->SetScrollChildren(scroll_children);
+  }
+
+  LayerImpl* clip_parent = NULL;
+  if (clip_parent_) {
+    clip_parent = layer->layer_tree_impl()->LayerById(
+        clip_parent_->id());
+  }
+
+  layer->SetClipParent(clip_parent);
+  if (clip_children_) {
+    std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>;
+    for (std::set<LayerImpl*>::iterator it = clip_children_->begin();
+        it != clip_children_->end(); ++it)
+      clip_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+    layer->SetClipChildren(clip_children);
+  }
+
   layer->PassCopyRequests(&copy_requests_);
 
   // If the main thread commits multiple times before the impl thread actually
@@ -622,7 +747,7 @@
   return replica_layer_.Pass();
 }
 
-ScrollbarLayerImpl* LayerImpl::ToScrollbarLayer() {
+PaintedScrollbarLayerImpl* LayerImpl::ToScrollbarLayer() {
   return NULL;
 }
 
@@ -833,13 +958,13 @@
   if (horizontal_scrollbar_layer_) {
     horizontal_scrollbar_layer_->SetCurrentPos(current_offset.x());
     horizontal_scrollbar_layer_->SetMaximum(max_scroll_offset_.x());
-    horizontal_scrollbar_layer_->set_visible_to_total_length_ratio(
+    horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(
         viewport.width() / scrollable_size.width());
   }
   if (vertical_scrollbar_layer_) {
     vertical_scrollbar_layer_->SetCurrentPos(current_offset.y());
     vertical_scrollbar_layer_->SetMaximum(max_scroll_offset_.y());
-    vertical_scrollbar_layer_->set_visible_to_total_length_ratio(
+    vertical_scrollbar_layer_->SetVisibleToTotalLengthRatio(
         viewport.height() / scrollable_size.height());
   }
 
@@ -980,13 +1105,14 @@
   }
 }
 void LayerImpl::SetHorizontalScrollbarLayer(
-    ScrollbarLayerImpl* scrollbar_layer) {
+    PaintedScrollbarLayerImpl* scrollbar_layer) {
   horizontal_scrollbar_layer_ = scrollbar_layer;
   if (horizontal_scrollbar_layer_)
     horizontal_scrollbar_layer_->set_scroll_layer_id(id());
 }
 
-void LayerImpl::SetVerticalScrollbarLayer(ScrollbarLayerImpl* scrollbar_layer) {
+void LayerImpl::SetVerticalScrollbarLayer(
+    PaintedScrollbarLayerImpl* scrollbar_layer) {
   vertical_scrollbar_layer_ = scrollbar_layer;
   if (vertical_scrollbar_layer_)
     vertical_scrollbar_layer_->set_scroll_layer_id(id());
@@ -1109,12 +1235,19 @@
   if (reasons & kCompositingReasonLayerForMask)
     reason_list->AppendString("Is a mask layer");
 
+  if (reasons & kCompositingReasonOverflowScrollingParent)
+    reason_list->AppendString("Scroll parent is not an ancestor");
+
+  if (reasons & kCompositingReasonOutOfFlowClipping)
+    reason_list->AppendString("Has clipping ancestor");
+
   return reason_list.PassAs<base::Value>();
 }
 
 void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
   TracedValue::MakeDictIntoImplicitSnapshot(state, LayerTypeAsString(), this);
   state->SetInteger("layer_id", id());
+  state->SetString("layer_name", debug_name());
   state->Set("bounds", MathUtil::AsValue(bounds()).release());
   state->SetInteger("draws_content", DrawsContent());
   state->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
@@ -1137,6 +1270,12 @@
     state->Set("mask_layer", mask_layer_->AsValue().release());
   if (replica_layer_)
     state->Set("replica_layer", replica_layer_->AsValue().release());
+
+  if (scroll_parent_)
+    state->SetInteger("scroll_parent", scroll_parent_->id());
+
+  if (clip_parent_)
+    state->SetInteger("clip_parent", clip_parent_->id());
 }
 
 size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; }
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 90da41a..cdb6526 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -5,6 +5,7 @@
 #ifndef CC_LAYERS_LAYER_IMPL_H_
 #define CC_LAYERS_LAYER_IMPL_H_
 
+#include <set>
 #include <string>
 
 #include "base/logging.h"
@@ -41,10 +42,10 @@
 
 class LayerTreeHostImpl;
 class LayerTreeImpl;
+class PaintedScrollbarLayerImpl;
 class QuadSink;
 class Renderer;
 class ScrollbarAnimationController;
-class ScrollbarLayerImpl;
 class Layer;
 
 struct AppendQuadsData;
@@ -83,6 +84,38 @@
   // Warning: This does not preserve tree structure invariants.
   void ClearChildList();
 
+  bool HasAncestor(const LayerImpl* ancestor) const;
+
+  void SetScrollParent(LayerImpl* parent);
+
+  LayerImpl* scroll_parent() { return scroll_parent_; }
+  const LayerImpl* scroll_parent() const { return scroll_parent_; }
+
+  void SetScrollChildren(std::set<LayerImpl*>* children);
+  void RemoveScrollChild(LayerImpl* child);
+
+  std::set<LayerImpl*>* scroll_children() { return scroll_children_.get(); }
+  const std::set<LayerImpl*>* scroll_children() const {
+    return scroll_children_.get();
+  }
+
+  void SetClipParent(LayerImpl* ancestor);
+
+  LayerImpl* clip_parent() {
+    return clip_parent_;
+  }
+  const LayerImpl* clip_parent() const {
+    return clip_parent_;
+  }
+
+  void SetClipChildren(std::set<LayerImpl*>* children);
+  void RemoveClipChild(LayerImpl* child);
+
+  std::set<LayerImpl*>* clip_children() { return clip_children_.get(); }
+  const std::set<LayerImpl*>* clip_children() const {
+    return clip_children_.get();
+  }
+
   void PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests);
   void TakeCopyRequestsAndTransformToTarget(
       ScopedPtrVector<CopyOutputRequest>* request);
@@ -128,7 +161,7 @@
 
   virtual void UpdateTilePriorities() {}
 
-  virtual ScrollbarLayerImpl* ToScrollbarLayer();
+  virtual PaintedScrollbarLayerImpl* ToScrollbarLayer();
 
   // Returns true if this layer has content to draw.
   void SetDrawsContent(bool draws_content);
@@ -330,7 +363,8 @@
   void SetScrollable(bool scrollable) { scrollable_ = scrollable; }
   bool scrollable() const { return scrollable_; }
 
-  void ApplySentScrollDeltas();
+  void ApplySentScrollDeltasFromAbortedCommit();
+  void ApplyScrollDeltasSinceBeginFrame();
 
   void SetShouldScrollOnMainThread(bool should_scroll_on_main_thread) {
     should_scroll_on_main_thread_ = should_scroll_on_main_thread;
@@ -415,13 +449,13 @@
 
   void SetScrollbarOpacity(float opacity);
 
-  void SetHorizontalScrollbarLayer(ScrollbarLayerImpl* scrollbar_layer);
-  ScrollbarLayerImpl* horizontal_scrollbar_layer() {
+  void SetHorizontalScrollbarLayer(PaintedScrollbarLayerImpl* scrollbar_layer);
+  PaintedScrollbarLayerImpl* horizontal_scrollbar_layer() {
     return horizontal_scrollbar_layer_;
   }
 
-  void SetVerticalScrollbarLayer(ScrollbarLayerImpl* scrollbar_layer);
-  ScrollbarLayerImpl* vertical_scrollbar_layer() {
+  void SetVerticalScrollbarLayer(PaintedScrollbarLayerImpl* scrollbar_layer);
+  PaintedScrollbarLayerImpl* vertical_scrollbar_layer() {
     return vertical_scrollbar_layer_;
   }
 
@@ -475,6 +509,18 @@
   // Properties internal to LayerImpl
   LayerImpl* parent_;
   OwnedLayerImplList children_;
+
+  LayerImpl* scroll_parent_;
+
+  // Storing a pointer to a set rather than a set since this will be rarely
+  // used. If this pointer turns out to be too heavy, we could have this (and
+  // the scroll parent above) be stored in a LayerImpl -> scroll_info
+  // map somewhere.
+  scoped_ptr<std::set<LayerImpl*> > scroll_children_;
+
+  LayerImpl* clip_parent_;
+  scoped_ptr<std::set<LayerImpl*> > clip_children_;
+
   // mask_layer_ can be temporarily stolen during tree sync, we need this ID to
   // confirm newly assigned layer is still the previous one
   int mask_layer_id_;
@@ -567,8 +613,8 @@
 
   // Weak pointers to this layer's scrollbars, if it has them. Updated during
   // tree synchronization.
-  ScrollbarLayerImpl* horizontal_scrollbar_layer_;
-  ScrollbarLayerImpl* vertical_scrollbar_layer_;
+  PaintedScrollbarLayerImpl* horizontal_scrollbar_layer_;
+  PaintedScrollbarLayerImpl* vertical_scrollbar_layer_;
 
   ScopedPtrVector<CopyOutputRequest> copy_requests_;
 
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc
index 9c6dbfe..1ab7a71 100644
--- a/cc/layers/layer_impl_unittest.cc
+++ b/cc/layers/layer_impl_unittest.cc
@@ -502,7 +502,7 @@
   EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
   EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
 
-  layer()->ApplySentScrollDeltas();
+  layer()->ApplySentScrollDeltasFromAbortedCommit();
 
   EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
   EXPECT_VECTOR_EQ(scroll_delta - sent_scroll_delta, layer()->ScrollDelta());
@@ -527,7 +527,7 @@
   EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
   EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
 
-  layer()->ApplySentScrollDeltas();
+  layer()->ApplySentScrollDeltasFromAbortedCommit();
 
   EXPECT_VECTOR_EQ(fixed_offset, layer()->TotalScrollOffset());
   EXPECT_VECTOR_EQ(scroll_offset + sent_scroll_delta, layer()->scroll_offset());
@@ -551,7 +551,7 @@
   EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
   EXPECT_VECTOR_EQ(sent_scroll_delta, layer()->sent_scroll_delta());
 
-  layer()->ApplySentScrollDeltas();
+  layer()->ApplySentScrollDeltasFromAbortedCommit();
 
   EXPECT_VECTOR_EQ(scroll_offset + scroll_delta, layer()->TotalScrollOffset());
   EXPECT_VECTOR_EQ(scroll_offset + sent_scroll_delta, layer()->scroll_offset());
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index bd1e16f..c5c5286 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -559,7 +559,8 @@
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(
       gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)));
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDoubleSided(false));
-  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDebugName("Test Layer"));
+  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTouchEventHandlerRegion(
+      gfx::Rect(10, 10)));
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDrawCheckerboardForMissingTiles(
       !test_layer->DrawCheckerboardForMissingTiles()));
   EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurface(true));
diff --git a/cc/layers/nine_patch_layer.cc b/cc/layers/nine_patch_layer.cc
index e32f6e0..517b49b 100644
--- a/cc/layers/nine_patch_layer.cc
+++ b/cc/layers/nine_patch_layer.cc
@@ -72,6 +72,7 @@
     bitmap_dirty_ = false;
     updated = true;
   }
+
   return updated;
 }
 
@@ -111,6 +112,11 @@
     layer_impl->SetLayout(
         gfx::Size(bitmap_.width(), bitmap_.height()), image_aperture_);
   }
+
+  // NinePatchLayer must push properties every commit to make sure
+  // NinePatchLayerImpl::resource_id_ is valid.
+  // http://crbug.com/276482
+  needs_push_properties_ = true;
 }
 
 }  // namespace cc
diff --git a/cc/layers/nine_patch_layer_impl.cc b/cc/layers/nine_patch_layer_impl.cc
index 103f765..4274bf0 100644
--- a/cc/layers/nine_patch_layer_impl.cc
+++ b/cc/layers/nine_patch_layer_impl.cc
@@ -64,12 +64,13 @@
 
 void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
                                      AppendQuadsData* append_quads_data) {
-  DCHECK(resource_id_);
-
   SharedQuadState* shared_quad_state =
       quad_sink->UseSharedQuadState(CreateSharedQuadState());
   AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
 
+  if (!resource_id_)
+    return;
+
   static const bool flipped = false;
   static const bool premultiplied_alpha = true;
 
diff --git a/cc/layers/nine_patch_layer_unittest.cc b/cc/layers/nine_patch_layer_unittest.cc
index 5268d02..f918efb 100644
--- a/cc/layers/nine_patch_layer_unittest.cc
+++ b/cc/layers/nine_patch_layer_unittest.cc
@@ -11,6 +11,7 @@
 #include "cc/scheduler/texture_uploader.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/occlusion_tracker.h"
@@ -95,12 +96,14 @@
       1024 * 1024);
   layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
 
+  FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface;
   scoped_ptr<ResourceProvider> resource_provider;
   {
     DebugScopedSetImplThread impl_thread(Proxy());
     DebugScopedSetMainThreadBlocked main_thread_blocked(Proxy());
-    output_surface = CreateFakeOutputSurface();
+    output_surface = FakeOutputSurface::Create3d();
+    CHECK(output_surface->BindToClient(&output_surface_client));
     resource_provider = ResourceProvider::Create(output_surface.get(), 0);
     params.texture->AcquireBackingTexture(resource_provider.get());
     ASSERT_TRUE(params.texture->have_backing_texture());
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
new file mode 100644
index 0000000..8346d04
--- /dev/null
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -0,0 +1,258 @@
+// Copyright 2013 The Chromium Authors. 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/painted_scrollbar_layer.h"
+
+#include "base/auto_reset.h"
+#include "base/basictypes.h"
+#include "base/debug/trace_event.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/resources/ui_resource_bitmap.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "skia/ext/platform_canvas.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSize.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+scoped_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl(
+    LayerTreeImpl* tree_impl) {
+  return PaintedScrollbarLayerImpl::Create(
+      tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>();
+}
+
+scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create(
+    scoped_ptr<Scrollbar> scrollbar,
+    int scroll_layer_id) {
+  return make_scoped_refptr(
+      new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer_id));
+}
+
+PaintedScrollbarLayer::PaintedScrollbarLayer(
+    scoped_ptr<Scrollbar> scrollbar,
+    int scroll_layer_id)
+    : scrollbar_(scrollbar.Pass()),
+      scroll_layer_id_(scroll_layer_id) {
+  if (!scrollbar_->IsOverlay())
+    SetShouldScrollOnMainThread(true);
+}
+
+PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
+
+void PaintedScrollbarLayer::SetScrollLayerId(int id) {
+  if (id == scroll_layer_id_)
+    return;
+
+  scroll_layer_id_ = id;
+  SetNeedsFullTreeSync();
+}
+
+bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const {
+  return scrollbar_->IsOverlay();
+}
+
+ScrollbarOrientation PaintedScrollbarLayer::Orientation() const {
+  return scrollbar_->Orientation();
+}
+
+int PaintedScrollbarLayer::MaxTextureSize() {
+  DCHECK(layer_tree_host());
+  return layer_tree_host()->GetRendererCapabilities().max_texture_size;
+}
+
+float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
+  if (layer_tree_host()->settings().solid_color_scrollbars)
+    return scale;
+
+  // If the scaled content_bounds() is bigger than the max texture size of the
+  // device, we need to clamp it by rescaling, since content_bounds() is used
+  // below to set the texture size.
+  gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
+  if (scaled_bounds.width() > MaxTextureSize() ||
+      scaled_bounds.height() > MaxTextureSize()) {
+    if (scaled_bounds.width() > scaled_bounds.height())
+      return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
+    else
+      return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
+  }
+  return scale;
+}
+
+void PaintedScrollbarLayer::CalculateContentsScale(
+    float ideal_contents_scale,
+    float device_scale_factor,
+    float page_scale_factor,
+    bool animating_transform_to_screen,
+    float* contents_scale_x,
+    float* contents_scale_y,
+    gfx::Size* content_bounds) {
+  ContentsScalingLayer::CalculateContentsScale(
+      ClampScaleToMaxTextureSize(ideal_contents_scale),
+      device_scale_factor,
+      page_scale_factor,
+      animating_transform_to_screen,
+      contents_scale_x,
+      contents_scale_y,
+      content_bounds);
+}
+
+void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
+  ContentsScalingLayer::PushPropertiesTo(layer);
+
+  PaintedScrollbarLayerImpl* scrollbar_layer =
+      static_cast<PaintedScrollbarLayerImpl*>(layer);
+
+  if (layer_tree_host() &&
+      layer_tree_host()->settings().solid_color_scrollbars) {
+    int thickness_override =
+        layer_tree_host()->settings().solid_color_scrollbar_thickness_dip;
+    if (thickness_override != -1) {
+      scrollbar_layer->SetThumbThickness(thickness_override);
+    } else {
+      if (Orientation() == HORIZONTAL)
+        scrollbar_layer->SetThumbThickness(bounds().height());
+      else
+        scrollbar_layer->SetThumbThickness(bounds().width());
+    }
+  } else {
+    scrollbar_layer->SetThumbThickness(thumb_thickness_);
+  }
+  scrollbar_layer->SetThumbLength(thumb_length_);
+  if (Orientation() == HORIZONTAL) {
+    scrollbar_layer->SetTrackStart(
+        track_rect_.x() - scrollbar_->Location().x());
+    scrollbar_layer->SetTrackLength(track_rect_.width());
+  } else {
+    scrollbar_layer->SetTrackStart(
+        track_rect_.y() - scrollbar_->Location().y());
+    scrollbar_layer->SetTrackLength(track_rect_.height());
+  }
+
+  if (track_resource_.get())
+    scrollbar_layer->set_track_ui_resource_id(track_resource_->id());
+  if (thumb_resource_.get())
+    scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id());
+
+  scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay());
+
+  // PaintedScrollbarLayer must push properties every frame. crbug.com/259095
+  needs_push_properties_ = true;
+}
+
+PaintedScrollbarLayer* PaintedScrollbarLayer::ToScrollbarLayer() {
+  return this;
+}
+
+void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
+  // When the LTH is set to null or has changed, then this layer should remove
+  // all of its associated resources.
+  if (!host || host != layer_tree_host()) {
+    track_resource_.reset();
+    thumb_resource_.reset();
+  }
+
+  ContentsScalingLayer::SetLayerTreeHost(host);
+}
+
+gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
+    gfx::Rect layer_rect) const {
+  // Don't intersect with the bounds as in LayerRectToContentRect() because
+  // layer_rect here might be in coordinates of the containing layer.
+  gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
+      layer_rect, contents_scale_y(), contents_scale_y());
+  // We should never return a rect bigger than the content_bounds().
+  gfx::Size clamped_size = expanded_rect.size();
+  clamped_size.SetToMin(content_bounds());
+  expanded_rect.set_size(clamped_size);
+  return expanded_rect;
+}
+
+gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const {
+  gfx::Size thumb_size;
+  if (Orientation() == HORIZONTAL) {
+    thumb_size =
+        gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness());
+  } else {
+    thumb_size =
+        gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength());
+  }
+  return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size));
+}
+
+void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
+  track_rect_ = scrollbar_->TrackRect();
+  if (scrollbar_->HasThumb()) {
+    thumb_thickness_ = scrollbar_->ThumbThickness();
+    thumb_length_ = scrollbar_->ThumbLength();
+  }
+}
+
+bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
+                            const OcclusionTracker* occlusion) {
+  UpdateThumbAndTrackGeometry();
+
+  gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect(
+      gfx::Rect(scrollbar_->Location(), bounds()));
+
+  if (layer_tree_host()->settings().solid_color_scrollbars ||
+      track_rect_.IsEmpty() || scaled_track_rect.IsEmpty())
+    return false;
+
+  {
+    base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
+                                                  true);
+    ContentsScalingLayer::Update(queue, occlusion);
+  }
+
+  track_resource_ = ScopedUIResource::Create(
+      layer_tree_host(), RasterizeScrollbarPart(scaled_track_rect, TRACK));
+  gfx::Rect thumb_rect = OriginThumbRect();
+
+  if (scrollbar_->HasThumb() && !thumb_rect.IsEmpty()) {
+    thumb_resource_ = ScopedUIResource::Create(
+        layer_tree_host(), RasterizeScrollbarPart(thumb_rect, THUMB));
+  }
+
+  return true;
+}
+
+scoped_refptr<UIResourceBitmap> PaintedScrollbarLayer::RasterizeScrollbarPart(
+    gfx::Rect rect,
+    ScrollbarPart part) {
+  DCHECK(!layer_tree_host()->settings().solid_color_scrollbars);
+  DCHECK(!rect.size().IsEmpty());
+
+  scoped_refptr<UIResourceBitmap> bitmap =
+      UIResourceBitmap::Create(new uint8_t[rect.width() * rect.height() * 4],
+                               UIResourceBitmap::RGBA8,
+                               rect.size());
+
+  SkBitmap skbitmap;
+  skbitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
+  skbitmap.setPixels(bitmap->GetPixels());
+
+  SkCanvas skcanvas(skbitmap);
+  skcanvas.translate(SkFloatToScalar(-rect.x()), SkFloatToScalar(-rect.y()));
+  skcanvas.scale(SkFloatToScalar(contents_scale_x()),
+                 SkFloatToScalar(contents_scale_y()));
+
+  gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
+      rect, 1.f / contents_scale_x(), 1.f / contents_scale_y());
+  SkRect layer_skrect = RectToSkRect(layer_rect);
+  SkPaint paint;
+  paint.setAntiAlias(false);
+  paint.setXfermodeMode(SkXfermode::kClear_Mode);
+  skcanvas.drawRect(layer_skrect, paint);
+  skcanvas.clipRect(layer_skrect);
+
+  scrollbar_->PaintPart(&skcanvas, part, layer_rect);
+
+  return bitmap;
+}
+
+}  // namespace cc
diff --git a/cc/layers/painted_scrollbar_layer.h b/cc/layers/painted_scrollbar_layer.h
new file mode 100644
index 0000000..48fb376
--- /dev/null
+++ b/cc/layers/painted_scrollbar_layer.h
@@ -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.
+
+#ifndef CC_LAYERS_PAINTED_SCROLLBAR_LAYER_H_
+#define CC_LAYERS_PAINTED_SCROLLBAR_LAYER_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/input/scrollbar.h"
+#include "cc/layers/contents_scaling_layer.h"
+#include "cc/layers/scrollbar_theme_painter.h"
+#include "cc/resources/layer_updater.h"
+#include "cc/resources/scoped_ui_resource.h"
+
+namespace cc {
+class ScrollbarThemeComposite;
+
+class CC_EXPORT PaintedScrollbarLayer : public ContentsScalingLayer {
+ public:
+  virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+      OVERRIDE;
+
+  static scoped_refptr<PaintedScrollbarLayer> Create(
+      scoped_ptr<Scrollbar> scrollbar,
+      int scroll_layer_id);
+
+  int scroll_layer_id() const { return scroll_layer_id_; }
+  void SetScrollLayerId(int id);
+
+  virtual bool OpacityCanAnimateOnImplThread() const OVERRIDE;
+
+  ScrollbarOrientation Orientation() const;
+
+  // Layer interface
+  virtual bool Update(ResourceUpdateQueue* queue,
+                      const OcclusionTracker* occlusion) OVERRIDE;
+  virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
+  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+  virtual void CalculateContentsScale(float ideal_contents_scale,
+                                      float device_scale_factor,
+                                      float page_scale_factor,
+                                      bool animating_transform_to_screen,
+                                      float* contents_scale_x,
+                                      float* contents_scale_y,
+                                      gfx::Size* content_bounds) OVERRIDE;
+
+  virtual PaintedScrollbarLayer* ToScrollbarLayer() OVERRIDE;
+
+ protected:
+  PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, int scroll_layer_id);
+  virtual ~PaintedScrollbarLayer();
+
+  // For unit tests
+  UIResourceId track_resource_id() {
+    return track_resource_.get() ? track_resource_->id() : 0;
+  }
+  UIResourceId thumb_resource_id() {
+    return thumb_resource_.get() ? thumb_resource_->id() : 0;
+  }
+  void UpdateThumbAndTrackGeometry();
+
+ private:
+  gfx::Rect ScrollbarLayerRectToContentRect(gfx::Rect layer_rect) const;
+  gfx::Rect OriginThumbRect() const;
+
+  int MaxTextureSize();
+  float ClampScaleToMaxTextureSize(float scale);
+
+  scoped_refptr<UIResourceBitmap> RasterizeScrollbarPart(gfx::Rect rect,
+                                                         ScrollbarPart part);
+
+  scoped_ptr<Scrollbar> scrollbar_;
+
+  int thumb_thickness_;
+  int thumb_length_;
+  gfx::Rect track_rect_;
+  int scroll_layer_id_;
+
+  scoped_ptr<ScopedUIResource> track_resource_;
+  scoped_ptr<ScopedUIResource> thumb_resource_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaintedScrollbarLayer);
+};
+
+}  // namespace cc
+
+#endif  // CC_LAYERS_PAINTED_SCROLLBAR_LAYER_H_
diff --git a/cc/layers/painted_scrollbar_layer_impl.cc b/cc/layers/painted_scrollbar_layer_impl.cc
new file mode 100644
index 0000000..621cf39
--- /dev/null
+++ b/cc/layers/painted_scrollbar_layer_impl.cc
@@ -0,0 +1,322 @@
+// Copyright 2013 The Chromium Authors. 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/painted_scrollbar_layer_impl.h"
+
+#include <algorithm>
+
+#include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/quad_sink.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/layer_tree_settings.h"
+#include "ui/gfx/rect_conversions.h"
+
+namespace cc {
+
+scoped_ptr<PaintedScrollbarLayerImpl> PaintedScrollbarLayerImpl::Create(
+    LayerTreeImpl* tree_impl,
+    int id,
+    ScrollbarOrientation orientation) {
+  return make_scoped_ptr(
+      new PaintedScrollbarLayerImpl(tree_impl, id, orientation));
+}
+
+PaintedScrollbarLayerImpl::PaintedScrollbarLayerImpl(
+    LayerTreeImpl* tree_impl,
+    int id,
+    ScrollbarOrientation orientation)
+    : LayerImpl(tree_impl, id),
+      track_ui_resource_id_(0),
+      thumb_ui_resource_id_(0),
+      current_pos_(0.f),
+      maximum_(0),
+      thumb_thickness_(0),
+      thumb_length_(0),
+      track_start_(0),
+      track_length_(0),
+      orientation_(orientation),
+      vertical_adjust_(0.f),
+      visible_to_total_length_ratio_(1.f),
+      scroll_layer_id_(Layer::INVALID_ID),
+      is_overlay_scrollbar_(false) {}
+
+PaintedScrollbarLayerImpl::~PaintedScrollbarLayerImpl() {}
+
+PaintedScrollbarLayerImpl* PaintedScrollbarLayerImpl::ToScrollbarLayer() {
+  return this;
+}
+
+scoped_ptr<LayerImpl> PaintedScrollbarLayerImpl::CreateLayerImpl(
+    LayerTreeImpl* tree_impl) {
+  return PaintedScrollbarLayerImpl::Create(tree_impl, id(), orientation_)
+      .PassAs<LayerImpl>();
+}
+
+void PaintedScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
+  LayerImpl::PushPropertiesTo(layer);
+
+  PaintedScrollbarLayerImpl* scrollbar_layer =
+      static_cast<PaintedScrollbarLayerImpl*>(layer);
+
+  scrollbar_layer->SetThumbThickness(thumb_thickness_);
+  scrollbar_layer->SetThumbLength(thumb_length_);
+  scrollbar_layer->SetTrackStart(track_start_);
+  scrollbar_layer->SetTrackLength(track_length_);
+  scrollbar_layer->set_is_overlay_scrollbar(is_overlay_scrollbar_);
+
+  scrollbar_layer->set_track_ui_resource_id(track_ui_resource_id_);
+  scrollbar_layer->set_thumb_ui_resource_id(thumb_ui_resource_id_);
+}
+
+bool PaintedScrollbarLayerImpl::WillDraw(DrawMode draw_mode,
+                                  ResourceProvider* resource_provider) {
+  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE &&
+      !layer_tree_impl()->settings().solid_color_scrollbars)
+    return false;
+  return LayerImpl::WillDraw(draw_mode, resource_provider);
+}
+
+void PaintedScrollbarLayerImpl::AppendQuads(
+    QuadSink* quad_sink,
+    AppendQuadsData* append_quads_data) {
+  bool premultipled_alpha = true;
+  bool flipped = false;
+  gfx::PointF uv_top_left(0.f, 0.f);
+  gfx::PointF uv_bottom_right(1.f, 1.f);
+  gfx::Rect bounds_rect(bounds());
+  gfx::Rect content_bounds_rect(content_bounds());
+
+  SharedQuadState* shared_quad_state =
+      quad_sink->UseSharedQuadState(CreateSharedQuadState());
+  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+
+  gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
+
+  if (layer_tree_impl()->settings().solid_color_scrollbars) {
+    scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
+    quad->SetNew(shared_quad_state,
+                 thumb_quad_rect,
+                 layer_tree_impl()->settings().solid_color_scrollbar_color,
+                 false);
+    quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+    return;
+  }
+
+  ResourceProvider::ResourceId thumb_resource_id =
+      layer_tree_impl()->ResourceIdForUIResource(thumb_ui_resource_id_);
+  ResourceProvider::ResourceId track_resource_id =
+      layer_tree_impl()->ResourceIdForUIResource(track_ui_resource_id_);
+
+  if (thumb_resource_id && !thumb_quad_rect.IsEmpty()) {
+    gfx::Rect opaque_rect;
+    const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+    scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
+    quad->SetNew(shared_quad_state,
+                 thumb_quad_rect,
+                 opaque_rect,
+                 thumb_resource_id,
+                 premultipled_alpha,
+                 uv_top_left,
+                 uv_bottom_right,
+                 SK_ColorTRANSPARENT,
+                 opacity,
+                 flipped);
+    quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+  }
+
+  gfx::Rect track_quad_rect = content_bounds_rect;
+  if (track_resource_id && !track_quad_rect.IsEmpty()) {
+    gfx::Rect opaque_rect(contents_opaque() ? track_quad_rect : gfx::Rect());
+    const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+    scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
+    quad->SetNew(shared_quad_state,
+                 track_quad_rect,
+                 opaque_rect,
+                 track_resource_id,
+                 premultipled_alpha,
+                 uv_top_left,
+                 uv_bottom_right,
+                 SK_ColorTRANSPARENT,
+                 opacity,
+                 flipped);
+    quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+  }
+}
+
+ScrollbarOrientation PaintedScrollbarLayerImpl::Orientation() const {
+  return orientation_;
+}
+
+float PaintedScrollbarLayerImpl::CurrentPos() const {
+  return current_pos_;
+}
+
+int PaintedScrollbarLayerImpl::Maximum() const {
+  return maximum_;
+}
+
+gfx::Rect PaintedScrollbarLayerImpl::ScrollbarLayerRectToContentRect(
+    gfx::RectF layer_rect) const {
+  // Don't intersect with the bounds as in layerRectToContentRect() because
+  // layer_rect here might be in coordinates of the containing layer.
+  gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
+                                           contents_scale_x(),
+                                           contents_scale_y());
+  return gfx::ToEnclosingRect(content_rect);
+}
+
+void PaintedScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) {
+  if (thumb_thickness_ == thumb_thickness)
+    return;
+  thumb_thickness_ = thumb_thickness;
+  NoteLayerPropertyChanged();
+}
+
+void PaintedScrollbarLayerImpl::SetThumbLength(int thumb_length) {
+  if (thumb_length_ == thumb_length)
+    return;
+  thumb_length_ = thumb_length;
+  NoteLayerPropertyChanged();
+}
+void PaintedScrollbarLayerImpl::SetTrackStart(int track_start) {
+  if (track_start_ == track_start)
+    return;
+  track_start_ = track_start;
+  NoteLayerPropertyChanged();
+}
+
+void PaintedScrollbarLayerImpl::SetTrackLength(int track_length) {
+  if (track_length_ == track_length)
+    return;
+  track_length_ = track_length;
+  NoteLayerPropertyChanged();
+}
+
+void PaintedScrollbarLayerImpl::SetVerticalAdjust(float vertical_adjust) {
+  if (vertical_adjust_ == vertical_adjust)
+    return;
+  vertical_adjust_ = vertical_adjust;
+  NoteLayerPropertyChanged();
+}
+
+void PaintedScrollbarLayerImpl::SetVisibleToTotalLengthRatio(float ratio) {
+  if (visible_to_total_length_ratio_ == ratio)
+    return;
+  visible_to_total_length_ratio_ = ratio;
+  NoteLayerPropertyChanged();
+}
+
+void PaintedScrollbarLayerImpl::SetCurrentPos(float current_pos) {
+  if (current_pos_ == current_pos)
+    return;
+  current_pos_ = current_pos;
+  NoteLayerPropertyChanged();
+}
+
+void PaintedScrollbarLayerImpl::SetMaximum(int maximum) {
+  if (maximum_ == maximum)
+    return;
+  maximum_ = maximum;
+  NoteLayerPropertyChanged();
+}
+
+gfx::Rect PaintedScrollbarLayerImpl::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
+  // horizontal scrollbar - inputs are above the scrollbar, computed values
+  // below:
+  //
+  //    |<------------------- track_length_ ------------------->|
+  //
+  // |--| <-- start_offset
+  //
+  // +--+----------------------------+------------------+-------+--+
+  // |<||                            |##################|       ||>|
+  // +--+----------------------------+------------------+-------+--+
+  //
+  //                                 |<- thumb_length ->|
+  //
+  // |<------- thumb_offset -------->|
+  //
+  // For painted, scrollbars, the length is fixed. For solid color scrollbars we
+  // have to compute it. The ratio of the thumb's length to the track's length
+  // is the same as that of the visible viewport to the total viewport, unless
+  // that would make the thumb's length less than its thickness.
+  //
+  // vertical_adjust_ is used when the layer geometry from the main thread is
+  // not in sync with what the user sees. For instance on Android scrolling the
+  // top bar controls out of view reveals more of the page content. We want the
+  // root layer scrollbars to reflect what the user sees even if we haven't
+  // received new layer geometry from the main thread.  If the user has scrolled
+  // down by 50px and the initial viewport size was 950px the geometry would
+  // look something like this:
+  //
+  // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
+  // Layer geometry:             Desired thumb positions:
+  // +--------------------+-+   +----------------------+   <-- 0px
+  // |                    |v|   |                     #|
+  // |                    |e|   |                     #|
+  // |                    |r|   |                     #|
+  // |                    |t|   |                     #|
+  // |                    |i|   |                     #|
+  // |                    |c|   |                     #|
+  // |                    |a|   |                     #|
+  // |                    |l|   |                     #|
+  // |                    | |   |                     #|
+  // |                    |l|   |                     #|
+  // |                    |a|   |                     #|
+  // |                    |y|   |                     #|
+  // |                    |e|   |                     #|
+  // |                    |r|   |                     #|
+  // +--------------------+-+   |                     #|
+  // | horizontal  layer  | |   |                     #|
+  // +--------------------+-+   |                     #|  <-- 950px
+  // |                      |   |                     #|
+  // |                      |   |##################### |
+  // +----------------------+   +----------------------+  <-- 1000px
+  //
+  // The layer geometry is set up for a 950px tall viewport, but the user can
+  // actually see down to 1000px. Thus we have to move the quad for the
+  // horizontal scrollbar down by the vertical_adjust_ factor and lay the
+  // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
+  // means the quads may extend outside the layer's bounds.
+
+  int thumb_length = thumb_length_;
+  float track_length = track_length_;
+  if (orientation_ == VERTICAL)
+    track_length += vertical_adjust_;
+
+  if (layer_tree_impl()->settings().solid_color_scrollbars) {
+    thumb_length = std::max(
+        static_cast<int>(visible_to_total_length_ratio_ * track_length),
+        thumb_thickness_);
+  }
+
+  // With the length known, we can compute the thumb's position.
+  float clamped_current_pos =
+      std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_));
+  float ratio = clamped_current_pos / maximum_;
+  float max_offset = track_length - thumb_length;
+  int thumb_offset = static_cast<int>(ratio * max_offset) + track_start_;
+
+  gfx::RectF thumb_rect;
+  if (orientation_ == HORIZONTAL) {
+    thumb_rect = gfx::RectF(thumb_offset, vertical_adjust_,
+                            thumb_length, thumb_thickness_);
+  } else {
+    thumb_rect = gfx::RectF(0.f, thumb_offset,
+                            thumb_thickness_, thumb_length);
+  }
+
+  return ScrollbarLayerRectToContentRect(thumb_rect);
+}
+
+const char* PaintedScrollbarLayerImpl::LayerTypeAsString() const {
+  return "cc::PaintedScrollbarLayerImpl";
+}
+
+}  // namespace cc
diff --git a/cc/layers/painted_scrollbar_layer_impl.h b/cc/layers/painted_scrollbar_layer_impl.h
new file mode 100644
index 0000000..1fb7972
--- /dev/null
+++ b/cc/layers/painted_scrollbar_layer_impl.h
@@ -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.
+
+#ifndef CC_LAYERS_PAINTED_SCROLLBAR_LAYER_IMPL_H_
+#define CC_LAYERS_PAINTED_SCROLLBAR_LAYER_IMPL_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/input/scrollbar.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/resources/ui_resource_client.h"
+
+namespace cc {
+
+class LayerTreeImpl;
+class ScrollView;
+
+class CC_EXPORT PaintedScrollbarLayerImpl : public LayerImpl {
+ public:
+  static scoped_ptr<PaintedScrollbarLayerImpl> Create(
+      LayerTreeImpl* tree_impl,
+      int id,
+      ScrollbarOrientation orientation);
+  virtual ~PaintedScrollbarLayerImpl();
+
+  // LayerImpl implementation.
+  virtual PaintedScrollbarLayerImpl* ToScrollbarLayer() OVERRIDE;
+  virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+      OVERRIDE;
+  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+
+  virtual bool WillDraw(DrawMode draw_mode,
+                        ResourceProvider* resource_provider) OVERRIDE;
+  virtual void AppendQuads(QuadSink* quad_sink,
+                           AppendQuadsData* append_quads_data) OVERRIDE;
+
+  int scroll_layer_id() const { return scroll_layer_id_; }
+  void set_scroll_layer_id(int id) { scroll_layer_id_ = id; }
+
+  ScrollbarOrientation Orientation() const;
+  float CurrentPos() const;
+  int Maximum() const;
+
+  void SetThumbThickness(int thumb_thickness);
+  int thumb_thickness() const { return thumb_thickness_; }
+  void SetThumbLength(int thumb_length);
+  void SetTrackStart(int track_start);
+  void SetTrackLength(int track_length);
+  void SetVerticalAdjust(float vertical_adjust);
+  void set_track_ui_resource_id(UIResourceId uid) {
+    track_ui_resource_id_ = uid;
+  }
+  void set_thumb_ui_resource_id(UIResourceId uid) {
+    thumb_ui_resource_id_ = uid;
+  }
+  void SetVisibleToTotalLengthRatio(float ratio);
+  void set_is_overlay_scrollbar(bool is_overlay_scrollbar) {
+    is_overlay_scrollbar_ = is_overlay_scrollbar;
+  }
+  bool is_overlay_scrollbar() const { return is_overlay_scrollbar_; }
+
+  void SetCurrentPos(float current_pos);
+  void SetMaximum(int maximum);
+
+  gfx::Rect ComputeThumbQuadRect() const;
+
+ protected:
+  PaintedScrollbarLayerImpl(LayerTreeImpl* tree_impl,
+                            int id,
+                            ScrollbarOrientation orientation);
+
+ private:
+  virtual const char* LayerTypeAsString() const OVERRIDE;
+
+  gfx::Rect ScrollbarLayerRectToContentRect(gfx::RectF layer_rect) const;
+
+  UIResourceId track_ui_resource_id_;
+  UIResourceId thumb_ui_resource_id_;
+
+  float current_pos_;
+  int maximum_;
+  int thumb_thickness_;
+  int thumb_length_;
+  int track_start_;
+  int track_length_;
+  ScrollbarOrientation orientation_;
+
+  // Difference between the clip layer's height and the visible viewport
+  // height (which may differ in the presence of top-controls hiding).
+  float vertical_adjust_;
+
+  float visible_to_total_length_ratio_;
+
+  int scroll_layer_id_;
+
+  bool is_overlay_scrollbar_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaintedScrollbarLayerImpl);
+};
+
+}  // namespace cc
+#endif  // CC_LAYERS_PAINTED_SCROLLBAR_LAYER_IMPL_H_
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 889e2fb..1c12664 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -6,6 +6,7 @@
 
 #include "cc/debug/benchmark_instrumentation.h"
 #include "cc/debug/devtools_instrumentation.h"
+#include "cc/layers/content_layer_client.h"
 #include "cc/layers/picture_layer_impl.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "ui/gfx/rect_conversions.h"
@@ -36,25 +37,14 @@
 
 void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
   Layer::PushPropertiesTo(base_layer);
-
   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
-  // This should be first so others can use it.
-  layer_impl->UpdateTwinLayer();
 
   layer_impl->SetIsMask(is_mask_);
-  layer_impl->CreateTilingSetIfNeeded();
   // Unlike other properties, invalidation must always be set on layer_impl.
   // See PictureLayerImpl::PushPropertiesTo for more details.
   layer_impl->invalidation_.Clear();
   layer_impl->invalidation_.Swap(&pile_invalidation_);
   layer_impl->pile_ = PicturePileImpl::CreateFromOther(pile_.get());
-  layer_impl->SyncFromActiveLayer();
-
-  // PictureLayer must push properties every frame.
-  // TODO(danakj): If we can avoid requiring to do CreateTilingSetIfNeeded() and
-  // SyncFromActiveLayer() on every commit then this could go away, maybe
-  // conditionally. crbug.com/259402
-  needs_push_properties_ = true;
 }
 
 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
@@ -114,11 +104,14 @@
                            pile_invalidation_,
                            visible_layer_rect,
                            rendering_stats_instrumentation());
-  if (!updated) {
+  if (updated) {
+    SetNeedsPushProperties();
+  } else {
     // If this invalidation did not affect the pile, then it can be cleared as
     // an optimization.
     pile_invalidation_.Clear();
   }
+
   return updated;
 }
 
@@ -130,4 +123,22 @@
   return true;
 }
 
+skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
+  // We could either flatten the PicturePile into a single SkPicture,
+  // or paint a fresh one depending on what we intend to do with the
+  // picture. For now we just paint a fresh one to get consistent results.
+  if (!DrawsContent())
+    return skia::RefPtr<SkPicture>();
+
+  int width = bounds().width();
+  int height = bounds().height();
+  gfx::RectF opaque;
+
+  skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
+  SkCanvas* canvas = picture->beginRecording(width, height);
+  client_->PaintContents(canvas, gfx::Rect(width, height), &opaque);
+  picture->endRecording();
+  return picture;
+}
+
 }  // namespace cc
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 7a9a427..d794330 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -34,6 +34,7 @@
       const OcclusionTracker* occlusion) OVERRIDE;
   virtual void SetIsMask(bool is_mask) OVERRIDE;
   virtual bool SupportsLCDText() const OVERRIDE;
+  virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE;
 
  protected:
   explicit PictureLayer(ContentLayerClient* client);
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 2f1878b..8b7ed9c 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -45,8 +45,8 @@
       raster_contents_scale_(0.f),
       low_res_raster_contents_scale_(0.f),
       raster_source_scale_was_animating_(false),
-      is_using_lcd_text_(tree_impl->settings().can_use_lcd_text) {
-}
+      is_using_lcd_text_(tree_impl->settings().can_use_lcd_text),
+      needs_post_commit_initialization_(true) {}
 
 PictureLayerImpl::~PictureLayerImpl() {
 }
@@ -60,13 +60,11 @@
   return PictureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
 }
 
-void PictureLayerImpl::CreateTilingSetIfNeeded() {
-  DCHECK(layer_tree_impl()->IsPendingTree());
-  if (!tilings_)
-    tilings_.reset(new PictureLayerTilingSet(this, bounds()));
-}
-
 void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
+  // It's possible this layer was never drawn or updated (e.g. because it was
+  // a descendant of an opacity 0 layer).
+  DoPostCommitInitializationIfNeeded();
+
   LayerImpl::PushPropertiesTo(base_layer);
 
   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
@@ -78,8 +76,9 @@
 
   layer_impl->SetIsMask(is_mask_);
   layer_impl->pile_ = pile_;
-  pile_ = NULL;
 
+  // Tilings would be expensive to push, so we swap.  This optimization requires
+  // an extra invalidation in SyncFromActiveLayer.
   layer_impl->tilings_.swap(tilings_);
   layer_impl->tilings_->SetClient(layer_impl);
   if (tilings_)
@@ -92,19 +91,19 @@
   layer_impl->low_res_raster_contents_scale_ = low_res_raster_contents_scale_;
 
   layer_impl->UpdateLCDTextStatus(is_using_lcd_text_);
+  layer_impl->needs_post_commit_initialization_ = false;
 
-  // As an optimization, don't make a copy of this potentially complex region,
-  // and swap it directly from the pending to the active layer.  In general, any
-  // property pushed to a LayerImpl continues to live on that LayerImpl.
-  // However, invalidation is the difference between two main thread frames, so
-  // it no longer makes sense once the pending tree gets recycled.  It will
-  // always get pushed during PictureLayer::PushPropertiesTo.
+  // The invalidation on this soon-to-be-recycled layer must be cleared to
+  // mirror clearing the invalidation in PictureLayer's version of this function
+  // in case push properties is skipped.
   layer_impl->invalidation_.Swap(&invalidation_);
   invalidation_.Clear();
+  needs_post_commit_initialization_ = true;
 }
 
 void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
                                    AppendQuadsData* append_quads_data) {
+  DCHECK(!needs_post_commit_initialization_);
   gfx::Rect rect(visible_content_rect());
   gfx::Rect content_rect(content_bounds());
 
@@ -296,6 +295,7 @@
 }
 
 void PictureLayerImpl::UpdateTilePriorities() {
+  DCHECK(!needs_post_commit_initialization_);
   if (!tilings_->num_tilings())
     return;
 
@@ -380,6 +380,7 @@
     float* contents_scale_x,
     float* contents_scale_y,
     gfx::Size* content_bounds) {
+  DoPostCommitInitializationIfNeeded();
   if (!CanHaveTilings()) {
     ideal_page_scale_ = page_scale_factor;
     ideal_device_scale_ = device_scale_factor;
@@ -525,14 +526,10 @@
   return default_tile_size;
 }
 
-void PictureLayerImpl::SyncFromActiveLayer() {
-  DCHECK(layer_tree_impl()->IsPendingTree());
-
-  if (twin_layer_)
-    SyncFromActiveLayer(twin_layer_);
-}
-
 void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
+  DCHECK(!other->needs_post_commit_initialization_);
+  DCHECK(other->tilings_);
+
   UpdateLCDTextStatus(other->is_using_lcd_text_);
 
   if (!DrawsContent()) {
@@ -597,15 +594,6 @@
     UpdateTilePriorities();
 }
 
-void PictureLayerImpl::UpdateTwinLayer() {
-  DCHECK(layer_tree_impl()->IsPendingTree());
-
-  twin_layer_ = static_cast<PictureLayerImpl*>(
-      layer_tree_impl()->FindActiveTreeLayerById(id()));
-  if (twin_layer_)
-    twin_layer_->twin_layer_ = this;
-}
-
 void PictureLayerImpl::SetIsMask(bool is_mask) {
   if (is_mask_ == is_mask)
     return;
@@ -617,27 +605,24 @@
 ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
   gfx::Rect content_rect(content_bounds());
   float scale = contents_scale_x();
-  for (PictureLayerTilingSet::CoverageIterator
-           iter(tilings_.get(), scale, content_rect, ideal_contents_scale_);
-       iter;
-       ++iter) {
-    // Mask resource not ready yet.
-    if (!*iter)
-      return 0;
+  PictureLayerTilingSet::CoverageIterator iter(
+      tilings_.get(), scale, content_rect, ideal_contents_scale_);
 
-    const ManagedTileState::TileVersion& tile_version =
-        iter->GetTileVersionForDrawing();
-    if (!tile_version.IsReadyToDraw() ||
-        tile_version.mode() != ManagedTileState::TileVersion::RESOURCE_MODE)
-      return 0;
+  // Mask resource not ready yet.
+  if (!iter || !*iter)
+    return 0;
 
-    // Masks only supported if they fit on exactly one tile.
-    if (iter.geometry_rect() != content_rect)
-      return 0;
+  // Masks only supported if they fit on exactly one tile.
+  if (iter.geometry_rect() != content_rect)
+    return 0;
 
-    return tile_version.get_resource_id();
-  }
-  return 0;
+  const ManagedTileState::TileVersion& tile_version =
+      iter->GetTileVersionForDrawing();
+  if (!tile_version.IsReadyToDraw() ||
+      tile_version.mode() != ManagedTileState::TileVersion::RESOURCE_MODE)
+    return 0;
+
+  return tile_version.get_resource_id();
 }
 
 void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
@@ -695,7 +680,7 @@
         continue;
 
       missing_region.Subtract(iter.geometry_rect());
-      iter->mark_required_for_activation();
+      iter->MarkRequiredForActivation();
     }
   }
 
@@ -720,10 +705,32 @@
     if (!missing_region.Intersects(iter.geometry_rect()))
       continue;
 
-    iter->mark_required_for_activation();
+    iter->MarkRequiredForActivation();
   }
 }
 
+void PictureLayerImpl::DoPostCommitInitialization() {
+  DCHECK(needs_post_commit_initialization_);
+  DCHECK(layer_tree_impl()->IsPendingTree());
+
+  if (!tilings_)
+    tilings_.reset(new PictureLayerTilingSet(this, bounds()));
+
+  DCHECK(!twin_layer_);
+  twin_layer_ = static_cast<PictureLayerImpl*>(
+      layer_tree_impl()->FindActiveTreeLayerById(id()));
+  if (twin_layer_) {
+    DCHECK(!twin_layer_->twin_layer_);
+    twin_layer_->twin_layer_ = this;
+    // If the twin has never been pushed to, do not sync from it.
+    // This can happen if this function is called during activation.
+    if (!twin_layer_->needs_post_commit_initialization_)
+      SyncFromActiveLayer(twin_layer_);
+  }
+
+  needs_post_commit_initialization_ = false;
+}
+
 PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) {
   DCHECK(CanHaveTilingWithScale(contents_scale)) <<
       "contents_scale: " << contents_scale;
@@ -775,6 +782,7 @@
   DCHECK(ideal_device_scale_);
   DCHECK(ideal_source_scale_);
   DCHECK(CanHaveTilings());
+  DCHECK(!needs_post_commit_initialization_);
 
   bool change_target_tiling =
       raster_page_scale_ == 0.f ||
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 25cc5d0..42efa72 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -62,11 +62,7 @@
       const PictureLayerTiling* tiling) OVERRIDE;
 
   // PushPropertiesTo active tree => pending tree.
-  void SyncFromActiveLayer();
   void SyncTiling(const PictureLayerTiling* tiling);
-  void UpdateTwinLayer();
-
-  void CreateTilingSetIfNeeded();
 
   // Mask-related functions
   void SetIsMask(bool is_mask);
@@ -92,6 +88,11 @@
   void UpdateLCDTextStatus(bool new_status);
   void ResetRasterScale();
   void MarkVisibleResourcesAsRequired() const;
+  void DoPostCommitInitializationIfNeeded() {
+    if (needs_post_commit_initialization_)
+      DoPostCommitInitialization();
+  }
+  void DoPostCommitInitialization();
 
   bool CanHaveTilings() const;
   bool CanHaveTilingWithScale(float contents_scale) const;
@@ -124,6 +125,7 @@
 
   bool raster_source_scale_was_animating_;
   bool is_using_lcd_text_;
+  bool needs_post_commit_initialization_;
 
   friend class PictureLayer;
   DISALLOW_COPY_AND_ASSIGN(PictureLayerImpl);
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 047a529..56f6d50 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/picture_layer.h"
 #include "cc/test/fake_content_layer_client.h"
@@ -69,7 +70,6 @@
         host_impl_.active_tree()->LayerById(id_));
 
     SetupPendingTree(pending_pile);
-    pending_layer_->UpdateTwinLayer();
   }
 
   void AddDefaultTilingsWithInvalidation(const Region& invalidation) {
@@ -79,7 +79,6 @@
     for (size_t i = 0; i < active_layer_->tilings()->num_tilings(); ++i)
       active_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
     pending_layer_->set_invalidation(invalidation);
-    pending_layer_->SyncFromActiveLayer();
     for (size_t i = 0; i < pending_layer_->tilings()->num_tilings(); ++i)
       pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
   }
@@ -98,6 +97,7 @@
 
     pending_layer_ = static_cast<FakePictureLayerImpl*>(
         host_impl_.pending_tree()->LayerById(id_));
+    pending_layer_->DoPostCommitInitializationIfNeeded();
   }
 
   static void VerifyAllTilesExistAndHavePile(
@@ -822,7 +822,7 @@
       TestWebGraphicsContext3D::Create();
   context->set_max_texture_size(140);
   host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
-      context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>());
+      context.Pass()).PassAs<OutputSurface>());
 
   pending_layer_->CalculateContentsScale(
       1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
@@ -873,7 +873,7 @@
       TestWebGraphicsContext3D::Create();
   context->set_max_texture_size(140);
   host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
-      context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>());
+      context.Pass()).PassAs<OutputSurface>());
 
   pending_layer_->CalculateContentsScale(
       1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
@@ -1007,5 +1007,40 @@
   EXPECT_GT(num_offscreen, 0);
 }
 
+TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(400, 400);
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  host_impl_.CreatePendingTree();
+  LayerTreeImpl* pending_tree = host_impl_.pending_tree();
+
+  scoped_ptr<FakePictureLayerImpl> pending_layer =
+      FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pending_pile);
+  pending_layer->SetDrawsContent(true);
+  pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>());
+
+  pending_layer_ = static_cast<FakePictureLayerImpl*>(
+      host_impl_.pending_tree()->LayerById(id_));
+
+  // Set some state on the pending layer, make sure it is not clobbered
+  // by a sync from the active layer.  This could happen because if the
+  // pending layer has not been post-commit initialized it will attempt
+  // to sync from the active layer.
+  bool default_lcd_text_setting = pending_layer_->is_using_lcd_text();
+  pending_layer_->force_set_lcd_text(!default_lcd_text_setting);
+  EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
+
+  host_impl_.ActivatePendingTree();
+
+  active_layer_ = static_cast<FakePictureLayerImpl*>(
+      host_impl_.active_tree()->LayerById(id_));
+
+  EXPECT_EQ(0u, active_layer_->num_tilings());
+  EXPECT_EQ(!default_lcd_text_setting, active_layer_->is_using_lcd_text());
+  EXPECT_FALSE(active_layer_->needs_post_commit_initialization());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/layers/scrollbar_layer.cc b/cc/layers/scrollbar_layer.cc
deleted file mode 100644
index 4a63835..0000000
--- a/cc/layers/scrollbar_layer.cc
+++ /dev/null
@@ -1,352 +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 "cc/layers/scrollbar_layer.h"
-
-#include "base/auto_reset.h"
-#include "base/basictypes.h"
-#include "base/debug/trace_event.h"
-#include "cc/layers/scrollbar_layer_impl.h"
-#include "cc/resources/caching_bitmap_content_layer_updater.h"
-#include "cc/resources/layer_painter.h"
-#include "cc/resources/prioritized_resource.h"
-#include "cc/resources/resource_update_queue.h"
-#include "cc/trees/layer_tree_host.h"
-#include "ui/gfx/rect_conversions.h"
-
-namespace cc {
-
-scoped_ptr<LayerImpl> ScrollbarLayer::CreateLayerImpl(
-    LayerTreeImpl* tree_impl) {
-  return ScrollbarLayerImpl::Create(
-      tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>();
-}
-
-scoped_refptr<ScrollbarLayer> ScrollbarLayer::Create(
-    scoped_ptr<Scrollbar> scrollbar,
-    int scroll_layer_id) {
-  return make_scoped_refptr(new ScrollbarLayer(scrollbar.Pass(),
-                                               scroll_layer_id));
-}
-
-ScrollbarLayer::ScrollbarLayer(
-    scoped_ptr<Scrollbar> scrollbar,
-    int scroll_layer_id)
-    : scrollbar_(scrollbar.Pass()),
-      scroll_layer_id_(scroll_layer_id),
-      texture_format_(GL_INVALID_ENUM) {
-  if (!scrollbar_->IsOverlay())
-    SetShouldScrollOnMainThread(true);
-}
-
-ScrollbarLayer::~ScrollbarLayer() {}
-
-void ScrollbarLayer::SetScrollLayerId(int id) {
-  if (id == scroll_layer_id_)
-    return;
-
-  scroll_layer_id_ = id;
-  SetNeedsFullTreeSync();
-}
-
-bool ScrollbarLayer::OpacityCanAnimateOnImplThread() const {
-  return scrollbar_->IsOverlay();
-}
-
-ScrollbarOrientation ScrollbarLayer::Orientation() const {
-  return scrollbar_->Orientation();
-}
-
-int ScrollbarLayer::MaxTextureSize() {
-  DCHECK(layer_tree_host());
-  return layer_tree_host()->GetRendererCapabilities().max_texture_size;
-}
-
-float ScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
-  if (layer_tree_host()->settings().solid_color_scrollbars)
-    return scale;
-
-  // If the scaled content_bounds() is bigger than the max texture size of the
-  // device, we need to clamp it by rescaling, since content_bounds() is used
-  // below to set the texture size.
-  gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
-  if (scaled_bounds.width() > MaxTextureSize() ||
-      scaled_bounds.height() > MaxTextureSize()) {
-    if (scaled_bounds.width() > scaled_bounds.height())
-      return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
-    else
-      return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
-  }
-  return scale;
-}
-
-void ScrollbarLayer::CalculateContentsScale(float ideal_contents_scale,
-                                            float device_scale_factor,
-                                            float page_scale_factor,
-                                            bool animating_transform_to_screen,
-                                            float* contents_scale_x,
-                                            float* contents_scale_y,
-                                            gfx::Size* content_bounds) {
-  ContentsScalingLayer::CalculateContentsScale(
-      ClampScaleToMaxTextureSize(ideal_contents_scale),
-      device_scale_factor,
-      page_scale_factor,
-      animating_transform_to_screen,
-      contents_scale_x,
-      contents_scale_y,
-      content_bounds);
-}
-
-void ScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
-  ContentsScalingLayer::PushPropertiesTo(layer);
-
-  ScrollbarLayerImpl* scrollbar_layer = static_cast<ScrollbarLayerImpl*>(layer);
-
-  if (layer_tree_host() &&
-      layer_tree_host()->settings().solid_color_scrollbars) {
-    int thickness_override =
-        layer_tree_host()->settings().solid_color_scrollbar_thickness_dip;
-    if (thickness_override != -1) {
-      scrollbar_layer->set_thumb_thickness(thickness_override);
-    } else {
-      if (Orientation() == HORIZONTAL)
-        scrollbar_layer->set_thumb_thickness(bounds().height());
-      else
-        scrollbar_layer->set_thumb_thickness(bounds().width());
-    }
-  } else {
-    scrollbar_layer->set_thumb_thickness(thumb_thickness_);
-  }
-  scrollbar_layer->set_thumb_length(thumb_length_);
-  if (Orientation() == HORIZONTAL) {
-    scrollbar_layer->set_track_start(track_rect_.x());
-    scrollbar_layer->set_track_length(track_rect_.width());
-  } else {
-    scrollbar_layer->set_track_start(track_rect_.y());
-    scrollbar_layer->set_track_length(track_rect_.height());
-  }
-
-  if (track_ && track_->texture()->have_backing_texture())
-    scrollbar_layer->set_track_resource_id(track_->texture()->resource_id());
-  else
-    scrollbar_layer->set_track_resource_id(0);
-
-  if (thumb_ && thumb_->texture()->have_backing_texture())
-    scrollbar_layer->set_thumb_resource_id(thumb_->texture()->resource_id());
-  else
-    scrollbar_layer->set_thumb_resource_id(0);
-
-  scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay());
-
-  // ScrollbarLayer must push properties every frame. crbug.com/259095
-  needs_push_properties_ = true;
-}
-
-ScrollbarLayer* ScrollbarLayer::ToScrollbarLayer() {
-  return this;
-}
-
-void ScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
-  if (!host || host != layer_tree_host()) {
-    track_updater_ = NULL;
-    track_.reset();
-    thumb_updater_ = NULL;
-    thumb_.reset();
-  }
-
-  ContentsScalingLayer::SetLayerTreeHost(host);
-}
-
-class ScrollbarPartPainter : public LayerPainter {
- public:
-  ScrollbarPartPainter(Scrollbar* scrollbar, ScrollbarPart part)
-      : scrollbar_(scrollbar),
-        part_(part) {}
-  virtual ~ScrollbarPartPainter() {}
-
-  // LayerPainter implementation
-  virtual void Paint(SkCanvas* canvas,
-                     gfx::Rect content_rect,
-                     gfx::RectF* opaque) OVERRIDE {
-    scrollbar_->PaintPart(canvas, part_, content_rect);
-  }
-
- private:
-  Scrollbar* scrollbar_;
-  ScrollbarPart part_;
-};
-
-void ScrollbarLayer::CreateUpdaterIfNeeded() {
-  if (layer_tree_host()->settings().solid_color_scrollbars)
-    return;
-
-  texture_format_ =
-      layer_tree_host()->GetRendererCapabilities().best_texture_format;
-
-  if (!track_updater_.get()) {
-    track_updater_ = CachingBitmapContentLayerUpdater::Create(
-        scoped_ptr<LayerPainter>(
-            new ScrollbarPartPainter(scrollbar_.get(), TRACK))
-            .Pass(),
-        rendering_stats_instrumentation(),
-        id());
-  }
-  if (!track_) {
-    track_ = track_updater_->CreateResource(
-        layer_tree_host()->contents_texture_manager());
-  }
-
-  if (!thumb_updater_.get()) {
-    thumb_updater_ = CachingBitmapContentLayerUpdater::Create(
-        scoped_ptr<LayerPainter>(
-            new ScrollbarPartPainter(scrollbar_.get(), THUMB))
-            .Pass(),
-        rendering_stats_instrumentation(),
-        id());
-  }
-  if (!thumb_ && scrollbar_->HasThumb()) {
-    thumb_ = thumb_updater_->CreateResource(
-        layer_tree_host()->contents_texture_manager());
-  }
-}
-
-bool ScrollbarLayer::UpdatePart(CachingBitmapContentLayerUpdater* painter,
-                                LayerUpdater::Resource* resource,
-                                gfx::Rect rect,
-                                ResourceUpdateQueue* queue) {
-  if (layer_tree_host()->settings().solid_color_scrollbars)
-    return false;
-
-  // Skip painting and uploading if there are no invalidations and
-  // we already have valid texture data.
-  if (resource->texture()->have_backing_texture() &&
-      resource->texture()->size() == rect.size() &&
-      !is_dirty())
-    return false;
-
-  // We should always have enough memory for UI.
-  DCHECK(resource->texture()->can_acquire_backing_texture());
-  if (!resource->texture()->can_acquire_backing_texture())
-    return false;
-
-  // Paint and upload the entire part.
-  gfx::Rect painted_opaque_rect;
-  painter->PrepareToUpdate(rect,
-                           rect.size(),
-                           contents_scale_x(),
-                           contents_scale_y(),
-                           &painted_opaque_rect);
-  if (!painter->pixels_did_change() &&
-      resource->texture()->have_backing_texture()) {
-    TRACE_EVENT_INSTANT0("cc",
-                         "ScrollbarLayer::UpdatePart no texture upload needed",
-                         TRACE_EVENT_SCOPE_THREAD);
-    return false;
-  }
-
-  bool partial_updates_allowed =
-      layer_tree_host()->settings().max_partial_texture_updates > 0;
-  if (!partial_updates_allowed)
-    resource->texture()->ReturnBackingTexture();
-
-  gfx::Vector2d dest_offset(0, 0);
-  resource->Update(queue, rect, dest_offset, partial_updates_allowed);
-  return true;
-}
-
-gfx::Rect ScrollbarLayer::ScrollbarLayerRectToContentRect(
-    gfx::Rect layer_rect) const {
-  // Don't intersect with the bounds as in LayerRectToContentRect() because
-  // layer_rect here might be in coordinates of the containing layer.
-  gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
-      layer_rect, contents_scale_y(), contents_scale_y());
-  // We should never return a rect bigger than the content_bounds().
-  gfx::Size clamped_size = expanded_rect.size();
-  clamped_size.SetToMin(content_bounds());
-  expanded_rect.set_size(clamped_size);
-  return expanded_rect;
-}
-
-void ScrollbarLayer::SetTexturePriorities(
-    const PriorityCalculator& priority_calc) {
-  if (layer_tree_host()->settings().solid_color_scrollbars)
-    return;
-
-  if (content_bounds().IsEmpty())
-    return;
-  DCHECK_LE(content_bounds().width(), MaxTextureSize());
-  DCHECK_LE(content_bounds().height(), MaxTextureSize());
-
-  CreateUpdaterIfNeeded();
-
-  bool draws_to_root = !render_target()->parent();
-  if (track_) {
-    track_->texture()->SetDimensions(content_bounds(), texture_format_);
-    track_->texture()->set_request_priority(
-        PriorityCalculator::UIPriority(draws_to_root));
-  }
-  if (thumb_) {
-    gfx::Size thumb_size = OriginThumbRect().size();
-    thumb_->texture()->SetDimensions(thumb_size, texture_format_);
-    thumb_->texture()->set_request_priority(
-        PriorityCalculator::UIPriority(draws_to_root));
-  }
-}
-
-bool ScrollbarLayer::Update(ResourceUpdateQueue* queue,
-                            const OcclusionTracker* occlusion) {
-  track_rect_ = scrollbar_->TrackRect();
-
-  if (layer_tree_host()->settings().solid_color_scrollbars)
-    return false;
-
-  bool updated = false;
-
-  {
-    base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
-                                                  true);
-    updated = ContentsScalingLayer::Update(queue, occlusion);
-  }
-
-  dirty_rect_.Union(update_rect_);
-  if (content_bounds().IsEmpty())
-    return false;
-  if (visible_content_rect().IsEmpty())
-    return false;
-
-  CreateUpdaterIfNeeded();
-
-  gfx::Rect content_rect = ScrollbarLayerRectToContentRect(
-      gfx::Rect(scrollbar_->Location(), bounds()));
-  updated |= UpdatePart(track_updater_.get(), track_.get(), content_rect,
-                        queue);
-
-  if (scrollbar_->HasThumb()) {
-    thumb_thickness_ = scrollbar_->ThumbThickness();
-    thumb_length_ = scrollbar_->ThumbLength();
-    gfx::Rect origin_thumb_rect = OriginThumbRect();
-    if (!origin_thumb_rect.IsEmpty()) {
-      updated |= UpdatePart(thumb_updater_.get(), thumb_.get(),
-                            origin_thumb_rect, queue);
-    }
-  }
-
-  dirty_rect_ = gfx::RectF();
-  return updated;
-}
-
-gfx::Rect ScrollbarLayer::OriginThumbRect() const {
-  gfx::Size thumb_size;
-  if (Orientation() == HORIZONTAL) {
-    thumb_size = gfx::Size(scrollbar_->ThumbLength(),
-                           scrollbar_->ThumbThickness());
-  } else {
-    thumb_size = gfx::Size(scrollbar_->ThumbThickness(),
-                           scrollbar_->ThumbLength());
-  }
-  return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size));
-}
-
-}  // namespace cc
diff --git a/cc/layers/scrollbar_layer.h b/cc/layers/scrollbar_layer.h
deleted file mode 100644
index f500dcc..0000000
--- a/cc/layers/scrollbar_layer.h
+++ /dev/null
@@ -1,94 +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 CC_LAYERS_SCROLLBAR_LAYER_H_
-#define CC_LAYERS_SCROLLBAR_LAYER_H_
-
-#include "cc/base/cc_export.h"
-#include "cc/input/scrollbar.h"
-#include "cc/layers/contents_scaling_layer.h"
-#include "cc/layers/scrollbar_theme_painter.h"
-#include "cc/resources/layer_updater.h"
-
-namespace cc {
-class CachingBitmapContentLayerUpdater;
-class ResourceUpdateQueue;
-class ScrollbarThemeComposite;
-
-class CC_EXPORT ScrollbarLayer : public ContentsScalingLayer {
- public:
-  virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
-      OVERRIDE;
-
-  static scoped_refptr<ScrollbarLayer> Create(
-      scoped_ptr<Scrollbar> scrollbar,
-      int scroll_layer_id);
-
-  int scroll_layer_id() const { return scroll_layer_id_; }
-  void SetScrollLayerId(int id);
-
-  virtual bool OpacityCanAnimateOnImplThread() const OVERRIDE;
-
-  ScrollbarOrientation Orientation() const;
-
-  // Layer interface
-  virtual void SetTexturePriorities(const PriorityCalculator& priority_calc)
-      OVERRIDE;
-  virtual bool Update(ResourceUpdateQueue* queue,
-                      const OcclusionTracker* occlusion) OVERRIDE;
-  virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
-  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
-  virtual void CalculateContentsScale(float ideal_contents_scale,
-                                      float device_scale_factor,
-                                      float page_scale_factor,
-                                      bool animating_transform_to_screen,
-                                      float* contents_scale_x,
-                                      float* contents_scale_y,
-                                      gfx::Size* content_bounds) OVERRIDE;
-
-  virtual ScrollbarLayer* ToScrollbarLayer() OVERRIDE;
-
- protected:
-  ScrollbarLayer(scoped_ptr<Scrollbar> scrollbar,
-                 int scroll_layer_id);
-  virtual ~ScrollbarLayer();
-
- private:
-  bool UpdatePart(CachingBitmapContentLayerUpdater* painter,
-                  LayerUpdater::Resource* resource,
-                  gfx::Rect rect,
-                  ResourceUpdateQueue* queue);
-  void CreateUpdaterIfNeeded();
-  gfx::Rect ScrollbarLayerRectToContentRect(gfx::Rect layer_rect) const;
-  gfx::Rect OriginThumbRect() const;
-
-  bool is_dirty() const { return !dirty_rect_.IsEmpty(); }
-
-  int MaxTextureSize();
-  float ClampScaleToMaxTextureSize(float scale);
-
-  scoped_ptr<Scrollbar> scrollbar_;
-
-  int thumb_thickness_;
-  int thumb_length_;
-  gfx::Rect track_rect_;
-  int scroll_layer_id_;
-
-  unsigned texture_format_;
-
-  gfx::RectF dirty_rect_;
-
-  scoped_refptr<CachingBitmapContentLayerUpdater> track_updater_;
-  scoped_refptr<CachingBitmapContentLayerUpdater> thumb_updater_;
-
-  // All the parts of the scrollbar except the thumb
-  scoped_ptr<LayerUpdater::Resource> track_;
-  scoped_ptr<LayerUpdater::Resource> thumb_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScrollbarLayer);
-};
-
-}  // namespace cc
-
-#endif  // CC_LAYERS_SCROLLBAR_LAYER_H_
diff --git a/cc/layers/scrollbar_layer_impl.cc b/cc/layers/scrollbar_layer_impl.cc
deleted file mode 100644
index 0dcfcde..0000000
--- a/cc/layers/scrollbar_layer_impl.cc
+++ /dev/null
@@ -1,273 +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 "cc/layers/scrollbar_layer_impl.h"
-
-#include <algorithm>
-
-#include "cc/animation/scrollbar_animation_controller.h"
-#include "cc/layers/layer.h"
-#include "cc/layers/quad_sink.h"
-#include "cc/quads/solid_color_draw_quad.h"
-#include "cc/quads/texture_draw_quad.h"
-#include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/layer_tree_settings.h"
-#include "ui/gfx/rect_conversions.h"
-
-namespace cc {
-
-scoped_ptr<ScrollbarLayerImpl> ScrollbarLayerImpl::Create(
-    LayerTreeImpl* tree_impl,
-    int id,
-    ScrollbarOrientation orientation) {
-  return make_scoped_ptr(new ScrollbarLayerImpl(tree_impl,
-                                                id,
-                                                orientation));
-}
-
-ScrollbarLayerImpl::ScrollbarLayerImpl(
-    LayerTreeImpl* tree_impl,
-    int id,
-    ScrollbarOrientation orientation)
-    : LayerImpl(tree_impl, id),
-      track_resource_id_(0),
-      thumb_resource_id_(0),
-      current_pos_(0.f),
-      maximum_(0),
-      thumb_thickness_(0),
-      thumb_length_(0),
-      track_start_(0),
-      track_length_(0),
-      orientation_(orientation),
-      vertical_adjust_(0.f),
-      visible_to_total_length_ratio_(1.f),
-      scroll_layer_id_(Layer::INVALID_ID),
-      is_overlay_scrollbar_(false) {}
-
-ScrollbarLayerImpl::~ScrollbarLayerImpl() {}
-
-ScrollbarLayerImpl* ScrollbarLayerImpl::ToScrollbarLayer() {
-  return this;
-}
-
-scoped_ptr<LayerImpl> ScrollbarLayerImpl::CreateLayerImpl(
-    LayerTreeImpl* tree_impl) {
-  return ScrollbarLayerImpl::Create(tree_impl,
-                                    id(),
-                                    orientation_).PassAs<LayerImpl>();
-}
-
-void ScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
-  LayerImpl::PushPropertiesTo(layer);
-
-  ScrollbarLayerImpl* scrollbar_layer = static_cast<ScrollbarLayerImpl*>(layer);
-
-  scrollbar_layer->set_thumb_thickness(thumb_thickness_);
-  scrollbar_layer->set_thumb_length(thumb_length_);
-  scrollbar_layer->set_track_start(track_start_);
-  scrollbar_layer->set_track_length(track_length_);
-  scrollbar_layer->set_is_overlay_scrollbar(is_overlay_scrollbar_);
-
-  scrollbar_layer->set_track_resource_id(track_resource_id_);
-  scrollbar_layer->set_thumb_resource_id(thumb_resource_id_);
-}
-
-bool ScrollbarLayerImpl::WillDraw(DrawMode draw_mode,
-                                  ResourceProvider* resource_provider) {
-  if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE &&
-      !layer_tree_impl()->settings().solid_color_scrollbars)
-    return false;
-  return LayerImpl::WillDraw(draw_mode, resource_provider);
-}
-
-void ScrollbarLayerImpl::AppendQuads(QuadSink* quad_sink,
-                                     AppendQuadsData* append_quads_data) {
-  bool premultipled_alpha = true;
-  bool flipped = false;
-  gfx::PointF uv_top_left(0.f, 0.f);
-  gfx::PointF uv_bottom_right(1.f, 1.f);
-  gfx::Rect bounds_rect(bounds());
-  gfx::Rect content_bounds_rect(content_bounds());
-
-  SharedQuadState* shared_quad_state =
-      quad_sink->UseSharedQuadState(CreateSharedQuadState());
-  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
-
-  gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
-
-  if (layer_tree_impl()->settings().solid_color_scrollbars) {
-    scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
-    quad->SetNew(shared_quad_state,
-                 thumb_quad_rect,
-                 layer_tree_impl()->settings().solid_color_scrollbar_color,
-                 false);
-    quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-    return;
-  }
-
-  if (thumb_resource_id_ && !thumb_quad_rect.IsEmpty()) {
-    gfx::Rect opaque_rect;
-    const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
-    quad->SetNew(shared_quad_state,
-                 thumb_quad_rect,
-                 opaque_rect,
-                 thumb_resource_id_,
-                 premultipled_alpha,
-                 uv_top_left,
-                 uv_bottom_right,
-                 SK_ColorTRANSPARENT,
-                 opacity,
-                 flipped);
-    quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-  }
-
-  if (!track_resource_id_)
-    return;
-
-  // Order matters here: since the back track texture is being drawn to the
-  // entire contents rect, we must append it after the thumb and fore track
-  // quads. The back track texture contains (and displays) the buttons.
-  if (!content_bounds_rect.IsEmpty()) {
-    gfx::Rect quad_rect(content_bounds_rect);
-    gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
-    const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
-    quad->SetNew(shared_quad_state,
-                 quad_rect,
-                 opaque_rect,
-                 track_resource_id_,
-                 premultipled_alpha,
-                 uv_top_left,
-                 uv_bottom_right,
-                 SK_ColorTRANSPARENT,
-                 opacity,
-                 flipped);
-    quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-  }
-}
-
-ScrollbarOrientation ScrollbarLayerImpl::Orientation() const {
-  return orientation_;
-}
-
-float ScrollbarLayerImpl::CurrentPos() const {
-  return current_pos_;
-}
-
-int ScrollbarLayerImpl::Maximum() const {
-  return maximum_;
-}
-
-gfx::Rect ScrollbarLayerImpl::ScrollbarLayerRectToContentRect(
-    gfx::RectF layer_rect) const {
-  // Don't intersect with the bounds as in layerRectToContentRect() because
-  // layer_rect here might be in coordinates of the containing layer.
-  gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
-                                           contents_scale_x(),
-                                           contents_scale_y());
-  return gfx::ToEnclosingRect(content_rect);
-}
-
-gfx::Rect ScrollbarLayerImpl::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
-  // horizontal scrollbar - inputs are above the scrollbar, computed values
-  // below:
-  //
-  //    |<------------------- track_length_ ------------------->|
-  //
-  // |--| <-- start_offset
-  //
-  // +--+----------------------------+------------------+-------+--+
-  // |<||                            |##################|       ||>|
-  // +--+----------------------------+------------------+-------+--+
-  //
-  //                                 |<- thumb_length ->|
-  //
-  // |<------- thumb_offset -------->|
-  //
-  // For painted, scrollbars, the length is fixed. For solid color scrollbars we
-  // have to compute it. The ratio of the thumb's length to the track's length
-  // is the same as that of the visible viewport to the total viewport, unless
-  // that would make the thumb's length less than its thickness.
-  //
-  // vertical_adjust_ is used when the layer geometry from the main thread is
-  // not in sync with what the user sees. For instance on Android scrolling the
-  // top bar controls out of view reveals more of the page content. We want the
-  // root layer scrollbars to reflect what the user sees even if we haven't
-  // received new layer geometry from the main thread.  If the user has scrolled
-  // down by 50px and the initial viewport size was 950px the geometry would
-  // look something like this:
-  //
-  // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
-  // Layer geometry:             Desired thumb positions:
-  // +--------------------+-+   +----------------------+   <-- 0px
-  // |                    |v|   |                     #|
-  // |                    |e|   |                     #|
-  // |                    |r|   |                     #|
-  // |                    |t|   |                     #|
-  // |                    |i|   |                     #|
-  // |                    |c|   |                     #|
-  // |                    |a|   |                     #|
-  // |                    |l|   |                     #|
-  // |                    | |   |                     #|
-  // |                    |l|   |                     #|
-  // |                    |a|   |                     #|
-  // |                    |y|   |                     #|
-  // |                    |e|   |                     #|
-  // |                    |r|   |                     #|
-  // +--------------------+-+   |                     #|
-  // | horizontal  layer  | |   |                     #|
-  // +--------------------+-+   |                     #|  <-- 950px
-  // |                      |   |                     #|
-  // |                      |   |##################### |
-  // +----------------------+   +----------------------+  <-- 1000px
-  //
-  // The layer geometry is set up for a 950px tall viewport, but the user can
-  // actually see down to 1000px. Thus we have to move the quad for the
-  // horizontal scrollbar down by the vertical_adjust_ factor and lay the
-  // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
-  // means the quads may extend outside the layer's bounds.
-
-  int thumb_length = thumb_length_;
-  float track_length = track_length_;
-  if (orientation_ == VERTICAL)
-    track_length += vertical_adjust_;
-
-  if (layer_tree_impl()->settings().solid_color_scrollbars) {
-    thumb_length = std::max(
-        static_cast<int>(visible_to_total_length_ratio_ * track_length),
-        thumb_thickness_);
-  }
-
-  // With the length known, we can compute the thumb's position.
-  float clamped_current_pos =
-      std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_));
-  float ratio = clamped_current_pos / maximum_;
-  float max_offset = track_length - thumb_length;
-  int thumb_offset = static_cast<int>(ratio * max_offset) + track_start_;
-
-  gfx::RectF thumb_rect;
-  if (orientation_ == HORIZONTAL) {
-    thumb_rect = gfx::RectF(thumb_offset, vertical_adjust_,
-                            thumb_length, thumb_thickness_);
-  } else {
-    thumb_rect = gfx::RectF(0.f, thumb_offset,
-                            thumb_thickness_, thumb_length);
-  }
-
-  return ScrollbarLayerRectToContentRect(thumb_rect);
-}
-
-void ScrollbarLayerImpl::DidLoseOutputSurface() {
-  track_resource_id_ = 0;
-  thumb_resource_id_ = 0;
-}
-
-const char* ScrollbarLayerImpl::LayerTypeAsString() const {
-  return "cc::ScrollbarLayerImpl";
-}
-
-}  // namespace cc
diff --git a/cc/layers/scrollbar_layer_impl.h b/cc/layers/scrollbar_layer_impl.h
deleted file mode 100644
index f61b660..0000000
--- a/cc/layers/scrollbar_layer_impl.h
+++ /dev/null
@@ -1,115 +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 CC_LAYERS_SCROLLBAR_LAYER_IMPL_H_
-#define CC_LAYERS_SCROLLBAR_LAYER_IMPL_H_
-
-#include "cc/base/cc_export.h"
-#include "cc/input/scrollbar.h"
-#include "cc/layers/layer_impl.h"
-
-namespace cc {
-
-class LayerTreeImpl;
-class ScrollView;
-
-class CC_EXPORT ScrollbarLayerImpl : public LayerImpl {
- public:
-  static scoped_ptr<ScrollbarLayerImpl> Create(
-      LayerTreeImpl* tree_impl,
-      int id,
-      ScrollbarOrientation orientation);
-  virtual ~ScrollbarLayerImpl();
-
-  // LayerImpl implementation.
-  virtual ScrollbarLayerImpl* ToScrollbarLayer() OVERRIDE;
-  virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
-      OVERRIDE;
-  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
-
-  virtual bool WillDraw(DrawMode draw_mode,
-                        ResourceProvider* resource_provider) OVERRIDE;
-  virtual void AppendQuads(QuadSink* quad_sink,
-                           AppendQuadsData* append_quads_data) OVERRIDE;
-
-  virtual void DidLoseOutputSurface() OVERRIDE;
-
-  int scroll_layer_id() const { return scroll_layer_id_; }
-  void set_scroll_layer_id(int id) { scroll_layer_id_ = id; }
-
-  ScrollbarOrientation Orientation() const;
-  float CurrentPos() const;
-  int Maximum() const;
-
-  void set_thumb_thickness(int thumb_thickness) {
-    thumb_thickness_ = thumb_thickness;
-  }
-  int thumb_thickness() const { return thumb_thickness_; }
-  void set_thumb_length(int thumb_length) {
-    thumb_length_ = thumb_length;
-  }
-  void set_track_start(int track_start) {
-    track_start_ = track_start;
-  }
-  void set_track_length(int track_length) {
-    track_length_ = track_length;
-  }
-  void set_vertical_adjust(float vertical_adjust) {
-    vertical_adjust_ = vertical_adjust;
-  }
-  void set_track_resource_id(ResourceProvider::ResourceId id) {
-    track_resource_id_ = id;
-  }
-  void set_thumb_resource_id(ResourceProvider::ResourceId id) {
-    thumb_resource_id_ = id;
-  }
-  void set_visible_to_total_length_ratio(float ratio) {
-    visible_to_total_length_ratio_ = ratio;
-  }
-  void set_is_overlay_scrollbar(bool is_overlay_scrollbar) {
-    is_overlay_scrollbar_ = is_overlay_scrollbar;
-  }
-  bool is_overlay_scrollbar() const { return is_overlay_scrollbar_; }
-
-  void SetCurrentPos(float current_pos) { current_pos_ = current_pos; }
-  void SetMaximum(int maximum) { maximum_ = maximum; }
-
-  gfx::Rect ComputeThumbQuadRect() const;
-
- protected:
-  ScrollbarLayerImpl(LayerTreeImpl* tree_impl,
-                     int id,
-                     ScrollbarOrientation orientation);
-
- private:
-  virtual const char* LayerTypeAsString() const OVERRIDE;
-
-  gfx::Rect ScrollbarLayerRectToContentRect(gfx::RectF layer_rect) const;
-
-  ResourceProvider::ResourceId track_resource_id_;
-  ResourceProvider::ResourceId thumb_resource_id_;
-
-  float current_pos_;
-  int maximum_;
-  int thumb_thickness_;
-  int thumb_length_;
-  int track_start_;
-  int track_length_;
-  ScrollbarOrientation orientation_;
-
-  // Difference between the clip layer's height and the visible viewport
-  // height (which may differ in the presence of top-controls hiding).
-  float vertical_adjust_;
-
-  float visible_to_total_length_ratio_;
-
-  int scroll_layer_id_;
-
-  bool is_overlay_scrollbar_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScrollbarLayerImpl);
-};
-
-}  // namespace cc
-#endif  // CC_LAYERS_SCROLLBAR_LAYER_IMPL_H_
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 0c160c4..809e4f8 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -2,24 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/layers/scrollbar_layer.h"
-
+#include "base/containers/hash_tables.h"
 #include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/layers/append_quads_data.h"
-#include "cc/layers/scrollbar_layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/quads/solid_color_draw_quad.h"
-#include "cc/resources/prioritized_resource_manager.h"
-#include "cc/resources/priority_calculator.h"
 #include "cc/resources/resource_update_queue.h"
 #include "cc/test/fake_impl_proxy.h"
 #include "cc/test/fake_layer_tree_host.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_painted_scrollbar_layer.h"
 #include "cc/test/fake_scrollbar.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/mock_quad_culler.h"
-#include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/tree_synchronizer.h"
@@ -36,8 +36,7 @@
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   scoped_refptr<Layer> child1 = Layer::Create();
   scoped_refptr<Layer> child2 =
-      ScrollbarLayer::Create(scrollbar.Pass(),
-                             child1->id());
+      PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id());
   layer_tree_root->AddChild(child1);
   layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
   host->SetRootLayer(layer_tree_root);
@@ -51,8 +50,9 @@
       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
 
   LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
-  ScrollbarLayerImpl* cc_child2 = static_cast<ScrollbarLayerImpl*>(
-      layer_impl_tree_root->children()[1]);
+  PaintedScrollbarLayerImpl* cc_child2 =
+      static_cast<PaintedScrollbarLayerImpl*>(
+          layer_impl_tree_root->children()[1]);
 
   EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2);
 }
@@ -63,8 +63,9 @@
   LayerImpl* layer_impl_tree_root =
       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), true);
 
-  ScrollbarLayerImpl* cc_child1 = static_cast<ScrollbarLayerImpl*>(
-      layer_impl_tree_root->children()[0]);
+  PaintedScrollbarLayerImpl* cc_child1 =
+      static_cast<PaintedScrollbarLayerImpl*>(
+          layer_impl_tree_root->children()[0]);
   LayerImpl* cc_child2 = layer_impl_tree_root->children()[1];
 
   EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1);
@@ -77,8 +78,9 @@
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   LayerImpl* layer_impl_tree_root =
       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
-  ScrollbarLayerImpl* scrollbar_layer_impl =
-      static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+  PaintedScrollbarLayerImpl* scrollbar_layer_impl =
+      static_cast<PaintedScrollbarLayerImpl*>(
+          layer_impl_tree_root->children()[1]);
 
   // When the scrollbar is not an overlay scrollbar, the scroll should be
   // responded to on the main thread as the compositor does not yet implement
@@ -92,8 +94,8 @@
 
   layer_impl_tree_root =
       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
-  scrollbar_layer_impl =
-      static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+  scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+      layer_impl_tree_root->children()[1]);
 
   // The user shouldn't be able to drag an overlay scrollbar and the scroll
   // may be handled in the compositor.
@@ -102,15 +104,14 @@
                                             InputHandler::Gesture));
 }
 
-TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) {
+TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
 
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   scoped_refptr<Layer> content_layer = Layer::Create();
   scoped_refptr<Layer> scrollbar_layer =
-      ScrollbarLayer::Create(scrollbar.Pass(),
-                             layer_tree_root->id());
+      PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
 
   layer_tree_root->SetScrollable(true);
   layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
@@ -127,8 +128,9 @@
 
   LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
 
-  ScrollbarLayerImpl* cc_scrollbar_layer =
-      static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+  PaintedScrollbarLayerImpl* cc_scrollbar_layer =
+      static_cast<PaintedScrollbarLayerImpl*>(
+          layer_impl_tree_root->children()[1]);
 
   EXPECT_EQ(10.f, cc_scrollbar_layer->CurrentPos());
   EXPECT_EQ(30, cc_scrollbar_layer->Maximum());
@@ -155,6 +157,98 @@
   EXPECT_EQ(300, cc_scrollbar_layer->Maximum());
 }
 
+TEST(ScrollbarLayerTest, ThumbRect) {
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  scoped_refptr<Layer> root_layer = Layer::Create();
+  scoped_refptr<Layer> content_layer = Layer::Create();
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
+      FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
+
+  root_layer->SetScrollable(true);
+  root_layer->SetMaxScrollOffset(gfx::Vector2d(80, 0));
+  root_layer->SetBounds(gfx::Size(100, 50));
+  content_layer->SetBounds(gfx::Size(100, 50));
+
+  host->SetRootLayer(root_layer);
+  root_layer->AddChild(content_layer);
+  root_layer->AddChild(scrollbar_layer);
+
+  root_layer->SetScrollOffset(gfx::Vector2d(0, 0));
+  scrollbar_layer->SetBounds(gfx::Size(70, 10));
+  scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
+  scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  LayerImpl* root_layer_impl = NULL;
+  PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL;
+
+  // Thumb is at the edge of the scrollbar (should be inset to
+  // the start of the track within the scrollbar layer's
+  // position).
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  root_layer_impl = host->CommitAndCreateLayerImplTree();
+  scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+      root_layer_impl->children()[1]);
+  EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+  // Under-scroll (thumb position should clamp and be unchanged).
+  root_layer->SetScrollOffset(gfx::Vector2d(-5, 0));
+
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  root_layer_impl = host->CommitAndCreateLayerImplTree();
+  scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+      root_layer_impl->children()[1]);
+  EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+  // Over-scroll (thumb position should clamp on the far side).
+  root_layer->SetScrollOffset(gfx::Vector2d(85, 0));
+
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  root_layer_impl = host->CommitAndCreateLayerImplTree();
+  scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+      root_layer_impl->children()[1]);
+  EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+  // Change thumb thickness and length.
+  scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4);
+  scrollbar_layer->fake_scrollbar()->set_thumb_length(6);
+
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  root_layer_impl = host->CommitAndCreateLayerImplTree();
+  scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+      root_layer_impl->children()[1]);
+  EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+  // Shrink the scrollbar layer to cover only the track.
+  scrollbar_layer->SetBounds(gfx::Size(50, 10));
+  scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10));
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  root_layer_impl = host->CommitAndCreateLayerImplTree();
+  scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+      root_layer_impl->children()[1]);
+  EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+  // Shrink the track in the non-scrolling dimension so that it only covers the
+  // middle third of the scrollbar layer (this does not affect the thumb
+  // position).
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6));
+
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  root_layer_impl = host->CommitAndCreateLayerImplTree();
+  scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
+      root_layer_impl->children()[1]);
+  EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+}
+
 TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
   LayerTreeSettings layer_tree_settings;
   layer_tree_settings.solid_color_scrollbars = true;
@@ -165,13 +259,14 @@
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
   LayerImpl* layer_impl_tree_root =
       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
-  ScrollbarLayerImpl* scrollbar_layer_impl =
-      static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
-  scrollbar_layer_impl->set_thumb_thickness(3);
+  PaintedScrollbarLayerImpl* scrollbar_layer_impl =
+      static_cast<PaintedScrollbarLayerImpl*>(
+          layer_impl_tree_root->children()[1]);
+  scrollbar_layer_impl->SetThumbThickness(3);
   scrollbar_layer_impl->SetCurrentPos(10.f);
   scrollbar_layer_impl->SetMaximum(100);
-  scrollbar_layer_impl->set_track_length(100);
-  scrollbar_layer_impl->set_visible_to_total_length_ratio(0.4f);
+  scrollbar_layer_impl->SetTrackLength(100);
+  scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.4f);
 
   // Thickness should be overridden to 3.
   {
@@ -203,7 +298,7 @@
 
   // For solid color scrollbars, position and size should reflect the
   // current viewport state.
-  scrollbar_layer_impl->set_visible_to_total_length_ratio(0.2f);
+  scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.2f);
   {
     MockQuadCuller quad_culler;
     AppendQuadsData data;
@@ -226,11 +321,12 @@
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
   LayerImpl* layer_impl_tree_root =
       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
-  ScrollbarLayerImpl* scrollbar_layer_impl =
-      static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
+  PaintedScrollbarLayerImpl* scrollbar_layer_impl =
+      static_cast<PaintedScrollbarLayerImpl*>(
+          layer_impl_tree_root->children()[1]);
 
-  scrollbar_layer_impl->set_thumb_thickness(3);
-  scrollbar_layer_impl->set_track_length(10);
+  scrollbar_layer_impl->SetThumbThickness(3);
+  scrollbar_layer_impl->SetTrackLength(10);
   scrollbar_layer_impl->SetCurrentPos(4.f);
   scrollbar_layer_impl->SetMaximum(8);
 
@@ -259,40 +355,40 @@
     layer_tree_settings.solid_color_scrollbars = true;
     host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_));
 
-    horizontal_scrollbar_layer_ = ScrollbarLayerImpl::Create(
+    horizontal_scrollbar_layer_ = PaintedScrollbarLayerImpl::Create(
         host_impl_->active_tree(), 1, HORIZONTAL);
-    vertical_scrollbar_layer_ = ScrollbarLayerImpl::Create(
+    vertical_scrollbar_layer_ = PaintedScrollbarLayerImpl::Create(
         host_impl_->active_tree(), 2, VERTICAL);
   }
 
  protected:
   FakeImplProxy proxy_;
   scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
-  scoped_ptr<ScrollbarLayerImpl> horizontal_scrollbar_layer_;
-  scoped_ptr<ScrollbarLayerImpl> vertical_scrollbar_layer_;
+  scoped_ptr<PaintedScrollbarLayerImpl> horizontal_scrollbar_layer_;
+  scoped_ptr<PaintedScrollbarLayerImpl> vertical_scrollbar_layer_;
 };
 
 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbLength) {
   horizontal_scrollbar_layer_->SetCurrentPos(0);
   horizontal_scrollbar_layer_->SetMaximum(10);
-  horizontal_scrollbar_layer_->set_thumb_thickness(3);
+  horizontal_scrollbar_layer_->SetThumbThickness(3);
 
   // Simple case - one third of the scrollable area is visible, so the thumb
   // should be one third as long as the track.
-  horizontal_scrollbar_layer_->set_visible_to_total_length_ratio(0.33f);
-  horizontal_scrollbar_layer_->set_track_length(100);
+  horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.33f);
+  horizontal_scrollbar_layer_->SetTrackLength(100);
   EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
 
   // The thumb's length should never be less than its thickness.
-  horizontal_scrollbar_layer_->set_visible_to_total_length_ratio(0.01f);
-  horizontal_scrollbar_layer_->set_track_length(100);
+  horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.01f);
+  horizontal_scrollbar_layer_->SetTrackLength(100);
   EXPECT_EQ(3, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
 }
 
 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) {
-  horizontal_scrollbar_layer_->set_track_length(100);
-  horizontal_scrollbar_layer_->set_visible_to_total_length_ratio(0.1f);
-  horizontal_scrollbar_layer_->set_thumb_thickness(3);
+  horizontal_scrollbar_layer_->SetTrackLength(100);
+  horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.1f);
+  horizontal_scrollbar_layer_->SetThumbThickness(3);
 
   horizontal_scrollbar_layer_->SetCurrentPos(0);
   horizontal_scrollbar_layer_->SetMaximum(100);
@@ -311,12 +407,12 @@
 }
 
 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
-  ScrollbarLayerImpl* layers[2] =
+  PaintedScrollbarLayerImpl* layers[2] =
       { horizontal_scrollbar_layer_.get(), vertical_scrollbar_layer_.get() };
   for (size_t i = 0; i < 2; ++i) {
-    layers[i]->set_track_length(100);
-    layers[i]->set_visible_to_total_length_ratio(0.2f);
-    layers[i]->set_thumb_thickness(3);
+    layers[i]->SetTrackLength(100);
+    layers[i]->SetVisibleToTotalLengthRatio(0.2f);
+    layers[i]->SetThumbThickness(3);
     layers[i]->SetCurrentPos(25);
     layers[i]->SetMaximum(100);
   }
@@ -326,8 +422,8 @@
   EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
                  vertical_scrollbar_layer_->ComputeThumbQuadRect());
 
-  horizontal_scrollbar_layer_->set_vertical_adjust(10.f);
-  vertical_scrollbar_layer_->set_vertical_adjust(10.f);
+  horizontal_scrollbar_layer_->SetVerticalAdjust(10.f);
+  vertical_scrollbar_layer_->SetVerticalAdjust(10.f);
 
   // The vertical adjustment factor has two effects:
   // 1.) Moves the horizontal scrollbar down
@@ -347,7 +443,7 @@
 
   virtual void BeginTest() OVERRIDE {
     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
-    scrollbar_layer_ = ScrollbarLayer::Create(scrollbar.Pass(), 1);
+    scrollbar_layer_ = PaintedScrollbarLayer::Create(scrollbar.Pass(), 1);
     scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
     scrollbar_layer_->SetBounds(bounds_);
     layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
@@ -377,7 +473,7 @@
   virtual void AfterTest() OVERRIDE {}
 
  private:
-  scoped_refptr<ScrollbarLayer> scrollbar_layer_;
+  scoped_refptr<PaintedScrollbarLayer> scrollbar_layer_;
   scoped_refptr<Layer> scroll_layer_;
   gfx::Size bounds_;
 };
@@ -404,9 +500,48 @@
  public:
   MockLayerTreeHost(LayerTreeHostClient* client,
                     const LayerTreeSettings& settings)
-      : LayerTreeHost(client, settings) {
+      : LayerTreeHost(client, settings),
+        next_id_(1),
+        total_ui_resource_created_(0),
+        total_ui_resource_deleted_(0) {
     Initialize(NULL);
   }
+
+  virtual UIResourceId CreateUIResource(UIResourceClient* content) OVERRIDE {
+    total_ui_resource_created_++;
+    UIResourceId nid = next_id_++;
+    ui_resource_bitmap_map_[nid] = content->GetBitmap(nid, false);
+    return nid;
+  }
+
+  // Deletes a UI resource.  May safely be called more than once.
+  virtual void DeleteUIResource(UIResourceId id) OVERRIDE {
+    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+    if (iter != ui_resource_bitmap_map_.end()) {
+      ui_resource_bitmap_map_.erase(iter);
+      total_ui_resource_deleted_++;
+    }
+  }
+
+  size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
+  int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
+  int TotalUIResourceCreated() { return total_ui_resource_created_; }
+
+  gfx::Size ui_resource_size(UIResourceId id) {
+    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+    if (iter != ui_resource_bitmap_map_.end() && iter->second.get())
+      return iter->second->GetSize();
+    return gfx::Size();
+  }
+
+ private:
+  typedef base::hash_map<UIResourceId, scoped_refptr<UIResourceBitmap> >
+      UIResourceBitmapMap;
+  UIResourceBitmapMap ui_resource_bitmap_map_;
+
+  int next_id_;
+  int total_ui_resource_created_;
+  int total_ui_resource_deleted_;
 };
 
 
@@ -415,7 +550,10 @@
   ScrollbarLayerTestResourceCreation()
       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
 
-  void TestResourceUpload(size_t expected_resources) {
+  void TestResourceUpload(int num_updates,
+                          size_t expected_resources,
+                          int expected_created,
+                          int expected_deleted) {
     layer_tree_host_.reset(
         new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
 
@@ -423,13 +561,11 @@
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
     scoped_refptr<Layer> content_layer = Layer::Create();
     scoped_refptr<Layer> scrollbar_layer =
-        ScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
+      PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
     layer_tree_root->AddChild(content_layer);
     layer_tree_root->AddChild(scrollbar_layer);
 
     layer_tree_host_->InitializeOutputSurfaceIfNeeded();
-    layer_tree_host_->contents_texture_manager()->
-        SetMaxMemoryLimitBytes(1024 * 1024);
     layer_tree_host_->SetRootLayer(layer_tree_root);
 
     scrollbar_layer->SetIsDrawable(true);
@@ -447,16 +583,17 @@
     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
 
-    PriorityCalculator calculator;
     ResourceUpdateQueue queue;
     OcclusionTracker occlusion_tracker(gfx::Rect(), false);
 
     scrollbar_layer->SavePaintProperties();
-    scrollbar_layer->SetTexturePriorities(calculator);
-    layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
-    scrollbar_layer->Update(&queue, &occlusion_tracker);
-    EXPECT_EQ(0u, queue.FullUploadSize());
-    EXPECT_EQ(expected_resources, queue.PartialUploadSize());
+    for (int update_counter = 0; update_counter < num_updates; update_counter++)
+      scrollbar_layer->Update(&queue, &occlusion_tracker);
+
+    // A non-solid-color scrollbar should have requested two textures.
+    EXPECT_EQ(expected_resources, layer_tree_host_->UIResourceCount());
+    EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+    EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
 
     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
 
@@ -471,12 +608,18 @@
 
 TEST_F(ScrollbarLayerTestResourceCreation, ResourceUpload) {
   layer_tree_settings_.solid_color_scrollbars = false;
-  TestResourceUpload(2);
+  TestResourceUpload(0, 0, 0, 0);
+  int num_updates[3] = {1, 5, 10};
+  for (int j = 0; j < 3; j++) {
+    TestResourceUpload(
+        num_updates[j], 2, num_updates[j] * 2, (num_updates[j] - 1) * 2);
+  }
 }
 
 TEST_F(ScrollbarLayerTestResourceCreation, SolidColorNoResourceUpload) {
   layer_tree_settings_.solid_color_scrollbars = true;
-  TestResourceUpload(0);
+  TestResourceUpload(0, 0, 0, 0);
+  TestResourceUpload(1, 0, 0, 0);
 }
 
 class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
@@ -484,25 +627,20 @@
   ScaledScrollbarLayerTestResourceCreation()
       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
 
-  void TestResourceUpload(size_t expected_resources, const float test_scale) {
+  void TestResourceUpload(const float test_scale) {
     layer_tree_host_.reset(
         new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
 
     gfx::Point scrollbar_location(0, 185);
-    scoped_ptr<FakeScrollbar> scrollbar(new FakeScrollbar(false, true, false));
-    scrollbar->set_location(scrollbar_location);
-
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
     scoped_refptr<Layer> content_layer = Layer::Create();
-    scoped_refptr<Layer> scrollbar_layer =
-        ScrollbarLayer::Create(scrollbar.PassAs<cc::Scrollbar>(),
-                               layer_tree_root->id());
+    scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
+        FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
+
     layer_tree_root->AddChild(content_layer);
     layer_tree_root->AddChild(scrollbar_layer);
 
     layer_tree_host_->InitializeOutputSurfaceIfNeeded();
-    layer_tree_host_->contents_texture_manager()->
-        SetMaxMemoryLimitBytes(1024 * 1024);
     layer_tree_host_->SetRootLayer(layer_tree_root);
 
     scrollbar_layer->SetIsDrawable(true);
@@ -529,30 +667,23 @@
     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
 
-    PriorityCalculator calculator;
     ResourceUpdateQueue queue;
     OcclusionTracker occlusion_tracker(gfx::Rect(), false);
-
     scrollbar_layer->SavePaintProperties();
-    scrollbar_layer->SetTexturePriorities(calculator);
-    layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
     scrollbar_layer->Update(&queue, &occlusion_tracker);
-    EXPECT_EQ(expected_resources, queue.PartialUploadSize());
 
     // Verify that we have not generated any content uploads that are larger
     // than their destination textures.
-    while (queue.HasMoreUpdates()) {
-      ResourceUpdate update = queue.TakeFirstPartialUpload();
-      EXPECT_LE(update.texture->size().width(),
-                scrollbar_layer->content_bounds().width());
-      EXPECT_LE(update.texture->size().height(),
-                scrollbar_layer->content_bounds().height());
 
-      EXPECT_LE(update.dest_offset.x() + update.content_rect.width(),
-                update.texture->size().width());
-      EXPECT_LE(update.dest_offset.y() + update.content_rect.height(),
-                update.texture->size().height());
-    }
+    gfx::Size track_size = layer_tree_host_->ui_resource_size(
+        scrollbar_layer->track_resource_id());
+    gfx::Size thumb_size = layer_tree_host_->ui_resource_size(
+        scrollbar_layer->thumb_resource_id());
+
+    EXPECT_LE(track_size.width(), scrollbar_layer->content_bounds().width());
+    EXPECT_LE(track_size.height(), scrollbar_layer->content_bounds().height());
+    EXPECT_LE(thumb_size.width(), scrollbar_layer->content_bounds().width());
+    EXPECT_LE(thumb_size.height(), scrollbar_layer->content_bounds().height());
 
     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
 
@@ -569,7 +700,9 @@
   layer_tree_settings_.solid_color_scrollbars = false;
   // Pick a test scale that moves the scrollbar's (non-zero) position to
   // a non-pixel-aligned location.
-  TestResourceUpload(2, 1.41f);
+  TestResourceUpload(.041f);
+  TestResourceUpload(1.41f);
+  TestResourceUpload(4.1f);
 }
 
 }  // namespace
diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc
index 316042b..2759473 100644
--- a/cc/layers/texture_layer.cc
+++ b/cc/layers/texture_layer.cc
@@ -189,8 +189,8 @@
         updated = true;
       }
     } else {
-      DCHECK(client_->Context3d());
       texture_id_ = client_->PrepareTexture();
+      DCHECK_EQ(!!texture_id_, !!client_->Context3d());
       if (client_->Context3d() &&
           client_->Context3d()->getGraphicsResetStatusARB() != GL_NO_ERROR)
         texture_id_ = 0;
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index aa08e9f..8fb2a15 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -7,11 +7,14 @@
 #include <string>
 
 #include "base/callback.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/layers/texture_layer_client.h"
 #include "cc/layers/texture_layer_impl.h"
+#include "cc/resources/returned_resource.h"
 #include "cc/test/fake_impl_proxy.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
 #include "cc/test/layer_test_common.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/trees/layer_tree_host.h"
@@ -618,8 +621,10 @@
   {
     scoped_ptr<TextureLayerImpl> impl_layer =
         TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+    ContextProvider* context_provider =
+        host_impl_.output_surface()->context_provider();
     unsigned texture =
-        host_impl_.output_surface()->context3d()->createTexture();
+        context_provider->Context3d()->createTexture();
     impl_layer->set_texture_id(texture);
     EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
   }
@@ -657,8 +662,10 @@
   {
     scoped_ptr<TextureLayerImpl> impl_layer =
         TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+    ContextProvider* context_provider =
+        host_impl_.output_surface()->context_provider();
     unsigned texture =
-        host_impl_.output_surface()->context3d()->createTexture();
+        context_provider->Context3d()->createTexture();
     impl_layer->set_texture_id(texture);
     EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
   }
@@ -681,8 +688,10 @@
   {
     scoped_ptr<TextureLayerImpl> impl_layer =
         TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
+    ContextProvider* context_provider =
+        host_impl_.output_surface()->context_provider();
     unsigned texture =
-        host_impl_.output_surface()->context3d()->createTexture();
+        context_provider->Context3d()->createTexture();
     impl_layer->set_texture_id(texture);
     EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
   }
@@ -777,7 +786,9 @@
   EXPECT_CALL(test_data_.mock_callback_,
               Release(test_data_.mailbox_name1_, _, false))
       .Times(1);
-  provider->ReceiveFromParent(list);
+  ReturnedResourceArray returned;
+  TransferableResource::ReturnResources(list, &returned);
+  provider->ReceiveReturnsFromParent(returned);
 }
 
 // Check that ClearClient correctly clears the state so that the impl side
@@ -799,8 +810,7 @@
         TestWebGraphicsContext3D::Create());
     context_ = context.get();
     texture_ = context->createTexture();
-    return FakeOutputSurface::Create3d(
-        context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
+    return FakeOutputSurface::Create3d(context.Pass()).PassAs<OutputSurface>();
   }
 
   virtual unsigned PrepareTexture() OVERRIDE {
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index a2f0ca7..daae39b 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -16,6 +16,7 @@
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_proxy.h"
 #include "cc/test/fake_rendering_stats_instrumentation.h"
 #include "cc/test/geometry_test_utils.h"
@@ -47,7 +48,7 @@
  public:
   TiledLayerTest()
       : proxy_(NULL),
-        output_surface_(CreateFakeOutputSurface()),
+        output_surface_(FakeOutputSurface::Create3d()),
         queue_(make_scoped_ptr(new ResourceUpdateQueue)),
         fake_layer_impl_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D),
         occlusion_(NULL) {
@@ -64,8 +65,10 @@
     layer_tree_host_->InitializeOutputSurfaceIfNeeded();
     layer_tree_host_->SetRootLayer(Layer::Create());
 
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
     DebugScopedSetImplThreadAndMainThreadBlocked
-    impl_thread_and_main_thread_blocked(proxy_);
+        impl_thread_and_main_thread_blocked(proxy_);
     resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
     host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(proxy_));
   }
@@ -183,6 +186,7 @@
  public:
   Proxy* proxy_;
   LayerTreeSettings settings_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<OutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
   scoped_ptr<ResourceUpdateQueue> queue_;
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index 4b5671f..4328067 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -93,8 +93,11 @@
   if (!LayerImpl::WillDraw(draw_mode, resource_provider))
     return false;
 
-  if (!updater_)
-    updater_.reset(new VideoResourceUpdater(resource_provider));
+  if (!updater_) {
+    updater_.reset(
+        new VideoResourceUpdater(layer_tree_impl()->context_provider(),
+                                 layer_tree_impl()->resource_provider()));
+  }
 
   VideoFrameExternalResources external_resources =
       updater_->CreateExternalResourcesFromVideoFrame(frame_);
diff --git a/cc/output/compositor_frame_ack.h b/cc/output/compositor_frame_ack.h
index 276ecf0..943a206 100644
--- a/cc/output/compositor_frame_ack.h
+++ b/cc/output/compositor_frame_ack.h
@@ -8,7 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
 #include "cc/output/gl_frame_data.h"
-#include "cc/resources/transferable_resource.h"
+#include "cc/resources/returned_resource.h"
 
 namespace cc {
 
@@ -17,7 +17,7 @@
   CompositorFrameAck();
   ~CompositorFrameAck();
 
-  TransferableResourceArray resources;
+  ReturnedResourceArray resources;
   scoped_ptr<GLFrameData> gl_frame_data;
   unsigned last_software_frame_id;
 
diff --git a/cc/output/context_provider.h b/cc/output/context_provider.h
index 13b7df5..7d61763 100644
--- a/cc/output/context_provider.h
+++ b/cc/output/context_provider.h
@@ -12,6 +12,7 @@
 namespace WebKit { class WebGraphicsContext3D; }
 
 namespace cc {
+struct ManagedMemoryPolicy;
 
 class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
  public:
@@ -41,6 +42,20 @@
   virtual void SetLostContextCallback(
       const LostContextCallback& lost_context_callback) = 0;
 
+  // Sets a callback to be called when the context is lost. This should be
+  // called from the same thread that the context is bound to.
+  typedef base::Closure SwapBuffersCompleteCallback;
+  virtual void SetSwapBuffersCompleteCallback(
+      const SwapBuffersCompleteCallback& swap_buffers_complete_callback) = 0;
+
+  // Sets a callback to be called when the memory policy changes. This should be
+  // called from the same thread that the context is bound to.
+  typedef base::Callback<void(
+    const cc::ManagedMemoryPolicy& policy,
+    bool discard_backbuffer_when_not_visible)> MemoryPolicyChangedCallback;
+  virtual void SetMemoryPolicyChangedCallback(
+      const MemoryPolicyChangedCallback& memory_policy_changed_callback) = 0;
+
  protected:
   friend class base::RefCountedThreadSafe<ContextProvider>;
   virtual ~ContextProvider() {}
diff --git a/cc/output/delegating_renderer.cc b/cc/output/delegating_renderer.cc
index bd1c5d1..226fddb 100644
--- a/cc/output/delegating_renderer.cc
+++ b/cc/output/delegating_renderer.cc
@@ -58,13 +58,14 @@
   capabilities_.allow_partial_texture_updates = false;
   capabilities_.using_offscreen_context3d = false;
 
-  WebGraphicsContext3D* context3d = resource_provider_->GraphicsContext3D();
-
-  if (!context3d) {
-    // Software compositing.
+  if (!output_surface_->context_provider()) {
+    // TODO(danakj): Make software compositing work.
     return true;
   }
 
+  WebGraphicsContext3D* context3d =
+      output_surface_->context_provider()->Context3d();
+
   if (!context3d->makeContextCurrent())
     return false;
 
@@ -167,14 +168,15 @@
 
 void DelegatingRenderer::ReceiveSwapBuffersAck(
     const CompositorFrameAck& ack) {
-  resource_provider_->ReceiveFromParent(ack.resources);
+  resource_provider_->ReceiveReturnsFromParent(ack.resources);
 }
 
 bool DelegatingRenderer::IsContextLost() {
-  WebGraphicsContext3D* context3d = resource_provider_->GraphicsContext3D();
-  if (!context3d)
+  ContextProvider* context_provider = output_surface_->context_provider();
+  if (!context_provider)
     return false;
-  return context3d->getGraphicsResetStatusARB() != GL_NO_ERROR;
+  return context_provider->Context3d()->getGraphicsResetStatusARB() !=
+         GL_NO_ERROR;
 }
 
 void DelegatingRenderer::SetVisible(bool visible) {
@@ -182,27 +184,27 @@
     return;
 
   visible_ = visible;
-  WebGraphicsContext3D* context = resource_provider_->GraphicsContext3D();
+  ContextProvider* context_provider = output_surface_->context_provider();
   if (!visible_) {
     TRACE_EVENT0("cc", "DelegatingRenderer::SetVisible dropping resources");
     resource_provider_->ReleaseCachedData();
-    if (context)
-      context->flush();
+    if (context_provider)
+      context_provider->Context3d()->flush();
   }
   if (capabilities_.using_set_visibility) {
     // We loop visibility to the GPU process, since that's what manages memory.
     // That will allow it to feed us with memory allocations that we can act
     // upon.
-    DCHECK(context);
-    context->setVisibilityCHROMIUM(visible);
+    DCHECK(context_provider);
+    context_provider->Context3d()->setVisibilityCHROMIUM(visible);
   }
 }
 
 void DelegatingRenderer::SendManagedMemoryStats(size_t bytes_visible,
                                                 size_t bytes_visible_and_nearby,
                                                 size_t bytes_allocated) {
-  WebGraphicsContext3D* context = resource_provider_->GraphicsContext3D();
-  if (!context) {
+  ContextProvider* context_provider = output_surface_->context_provider();
+  if (!context_provider) {
     // TODO(piman): software path.
     NOTIMPLEMENTED();
     return;
@@ -212,7 +214,7 @@
   stats.bytesVisibleAndNearby = bytes_visible_and_nearby;
   stats.bytesAllocated = bytes_allocated;
   stats.backbufferRequested = false;
-  context->sendManagedMemoryStatsCHROMIUM(&stats);
+  context_provider->Context3d()->sendManagedMemoryStatsCHROMIUM(&stats);
 }
 
 void DelegatingRenderer::SetDiscardBackBufferWhenNotVisible(bool discard) {
diff --git a/cc/output/delegating_renderer_unittest.cc b/cc/output/delegating_renderer_unittest.cc
index 6cb532f..b1e7c77 100644
--- a/cc/output/delegating_renderer_unittest.cc
+++ b/cc/output/delegating_renderer_unittest.cc
@@ -129,11 +129,12 @@
 
     EXPECT_EQ(2u, last_frame.delegated_frame_data->render_pass_list.size());
     // Each render pass has 10 resources in it. And the root render pass has a
-    // mask resource used when drawing the child render pass. The number 10 may
-    // change if AppendOneOfEveryQuadType() is updated, and the value here
-    // should be updated accordingly.
+    // mask resource used when drawing the child render pass, as well as its
+    // replica (it's added twice). The number 10 may change if
+    // AppendOneOfEveryQuadType() is updated, and the value here should be
+    // updated accordingly.
     EXPECT_EQ(
-        21u, last_frame.delegated_frame_data->resource_list.size());
+        22u, last_frame.delegated_frame_data->resource_list.size());
 
     EndTest();
   }
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 61d0eaa..c9b6c58 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -151,7 +151,7 @@
     : DirectRenderer(client, output_surface, resource_provider),
       offscreen_framebuffer_id_(0),
       shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)),
-      context_(output_surface->context3d()),
+      context_(output_surface->context_provider()->Context3d()),
       is_backbuffer_discarded_(false),
       discard_backbuffer_when_not_visible_(false),
       is_using_bind_uniform_(false),
@@ -162,8 +162,7 @@
       highp_threshold_min_(highp_threshold_min),
       highp_threshold_cache_(0),
       offscreen_context_labelled_(false),
-      on_demand_tile_raster_resource_id_(0),
-      weak_factory_(this) {
+      on_demand_tile_raster_resource_id_(0) {
   DCHECK(context_);
 }
 
@@ -510,7 +509,7 @@
   offscreen_contexts->Context3d()->flush();
 
   // Use the compositor's GL context again.
-  renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent();
+  renderer->Context()->makeContextCurrent();
   return source;
 }
 
@@ -592,7 +591,7 @@
   offscreen_contexts->Context3d()->flush();
 
   // Use the compositor's GL context again.
-  renderer->resource_provider()->GraphicsContext3D()->makeContextCurrent();
+  renderer->Context()->makeContextCurrent();
 
   return device.accessBitmap(false);
 }
@@ -2178,25 +2177,26 @@
                          AsyncGetFramebufferPixelsCleanupCallback());
 }
 
-void GLRenderer::DeleteTextureReleaseCallbackOnImplThread(unsigned texture_id,
-                                                          unsigned sync_point,
-                                                          bool lost_resource) {
+static void DeleteTextureReleaseCallbackOnImplThread(
+    const scoped_refptr<ContextProvider>& context_provider,
+    unsigned texture_id,
+    unsigned sync_point,
+    bool lost_resource) {
   if (sync_point)
-    context_->waitSyncPoint(sync_point);
-  context_->deleteTexture(texture_id);
+    context_provider->Context3d()->waitSyncPoint(sync_point);
+  context_provider->Context3d()->deleteTexture(texture_id);
 }
 
-// static
-void GLRenderer::DeleteTextureReleaseCallback(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    base::WeakPtr<GLRenderer> gl_renderer,
+static void DeleteTextureReleaseCallback(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+    const scoped_refptr<ContextProvider>& context_provider,
     unsigned texture_id,
     unsigned sync_point,
     bool lost_resource) {
   task_runner->PostTask(
       FROM_HERE,
-      base::Bind(&GLRenderer::DeleteTextureReleaseCallbackOnImplThread,
-                 gl_renderer,
+      base::Bind(&DeleteTextureReleaseCallbackOnImplThread,
+                 context_provider,
                  texture_id,
                  sync_point,
                  lost_resource));
@@ -2245,9 +2245,9 @@
     sync_point = context_->insertSyncPoint();
     scoped_ptr<TextureMailbox> texture_mailbox = make_scoped_ptr(
         new TextureMailbox(mailbox,
-                           base::Bind(&GLRenderer::DeleteTextureReleaseCallback,
+                           base::Bind(&DeleteTextureReleaseCallback,
                                       base::MessageLoopProxy::current(),
-                                      weak_factory_.GetWeakPtr(),
+                                      output_surface_->context_provider(),
                                       texture_id),
                            GL_TEXTURE_2D,
                            sync_point));
@@ -2348,7 +2348,7 @@
   if (is_async) {
     query = context_->createQueryEXT();
     GLC(context_, context_->beginQueryEXT(
-        GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM,
+        GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM,
         query));
   }
 
@@ -2389,7 +2389,7 @@
 
   if (is_async) {
     GLC(context_, context_->endQueryEXT(
-        GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM));
+        GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM));
     SyncPointHelper::SignalQuery(
         context_,
         query,
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index b1a3643..3969423 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -212,16 +212,6 @@
                       scoped_ptr<CopyOutputRequest> request,
                       bool success);
 
-  static void DeleteTextureReleaseCallback(
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-      base::WeakPtr<GLRenderer> gl_renderer,
-      unsigned texture_id,
-      unsigned sync_point,
-      bool lost_resource);
-  void DeleteTextureReleaseCallbackOnImplThread(unsigned texture_id,
-                                                unsigned sync_point,
-                                                bool lost_resource);
-
   void ReinitializeGrCanvas();
   void ReinitializeGLState();
 
@@ -459,8 +449,6 @@
   SkBitmap on_demand_tile_raster_bitmap_;
   ResourceProvider::ResourceId on_demand_tile_raster_resource_id_;
 
-  base::WeakPtrFactory<GLRenderer> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(GLRenderer);
 };
 
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index e4213d6..0c90b64 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -7,6 +7,7 @@
 #include <set>
 
 #include "cc/base/math_util.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/output/compositor_frame_metadata.h"
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/resource_provider.h"
@@ -14,11 +15,11 @@
 #include "cc/test/fake_impl_proxy.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/mock_quad_culler.h"
 #include "cc/test/pixel_test.h"
 #include "cc/test/render_pass_test_common.h"
 #include "cc/test/render_pass_test_utils.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -232,27 +233,32 @@
 
 class GLRendererTest : public testing::Test {
  protected:
-  GLRendererTest()
-      : output_surface_(FakeOutputSurface::Create3d(
-            scoped_ptr<WebKit::WebGraphicsContext3D>(
-                new FrameCountingContext()))),
-        resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)),
-        renderer_(&mock_client_,
-                  output_surface_.get(),
-                  resource_provider_.get()) {}
+  GLRendererTest() {
+    scoped_ptr<FrameCountingContext> context3d(new FrameCountingContext);
+    context3d_ = context3d.get();
 
-  virtual void SetUp() { renderer_.Initialize(); }
+    output_surface_ = FakeOutputSurface::Create3d(
+        context3d.PassAs<TestWebGraphicsContext3D>()).Pass();
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
 
-  void SwapBuffers() { renderer_.SwapBuffers(); }
-
-  FrameCountingContext* Context() {
-    return static_cast<FrameCountingContext*>(output_surface_->context3d());
+    resource_provider_ =
+        ResourceProvider::Create(output_surface_.get(), 0).Pass();
+    renderer_ = make_scoped_ptr(new FakeRendererGL(
+        &renderer_client_,
+        output_surface_.get(),
+        resource_provider_.get()));
   }
 
-  scoped_ptr<OutputSurface> output_surface_;
-  FakeRendererClient mock_client_;
+  virtual void SetUp() { renderer_->Initialize(); }
+
+  void SwapBuffers() { renderer_->SwapBuffers(); }
+
+  FrameCountingContext* context3d_;
+  FakeOutputSurfaceClient output_surface_client_;
+  scoped_ptr<FakeOutputSurface> output_surface_;
+  FakeRendererClient renderer_client_;
   scoped_ptr<ResourceProvider> resource_provider_;
-  FakeRendererGL renderer_;
+  scoped_ptr<FakeRendererGL> renderer_;
 };
 
 // Closing the namespace here so that GLRendererShaderTest can take advantage
@@ -320,15 +326,17 @@
 
 class GLRendererShaderTest : public testing::Test {
  protected:
-  GLRendererShaderTest()
-      : output_surface_(FakeOutputSurface::Create3d(
-            scoped_ptr<WebKit::WebGraphicsContext3D>(
-                new ShaderCreatorMockGraphicsContext()))),
-        resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)),
-        renderer_(scoped_ptr<FakeRendererGL>(
-            new FakeRendererGL(&mock_client_,
-                               output_surface_.get(),
-                               resource_provider_.get()))) {
+  GLRendererShaderTest() {
+    output_surface_ = FakeOutputSurface::Create3d(
+        scoped_ptr<TestWebGraphicsContext3D>(
+            new ShaderCreatorMockGraphicsContext())).Pass();
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+    resource_provider_ = ResourceProvider::Create(output_surface_.get(),
+                                                  0).Pass();
+    renderer_.reset(new FakeRendererGL(&renderer_client_,
+                                       output_surface_.get(),
+                                       resource_provider_.get()));
     renderer_->Initialize();
   }
 
@@ -386,8 +394,9 @@
               renderer_->program_shadow_);
   }
 
-  scoped_ptr<OutputSurface> output_surface_;
-  FakeRendererClient mock_client_;
+  FakeOutputSurfaceClient output_surface_client_;
+  scoped_ptr<FakeOutputSurface> output_surface_;
+  FakeRendererClient renderer_client_;
   scoped_ptr<ResourceProvider> resource_provider_;
   scoped_ptr<FakeRendererGL> renderer_;
 };
@@ -398,12 +407,12 @@
 // Suggest recreating framebuffer when one already exists.
 // Expected: it does nothing.
 TEST_F(GLRendererTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing) {
-  renderer_.SetDiscardBackBufferWhenNotVisible(false);
-  EXPECT_EQ(0, mock_client_.set_full_root_layer_damage_count());
-  EXPECT_FALSE(renderer_.IsBackbufferDiscarded());
+  renderer_->SetDiscardBackBufferWhenNotVisible(false);
+  EXPECT_EQ(0, renderer_client_.set_full_root_layer_damage_count());
+  EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
 
   SwapBuffers();
-  EXPECT_EQ(1, Context()->frame_count());
+  EXPECT_EQ(1, context3d_->frame_count());
 }
 
 // Test GLRenderer DiscardBackbuffer functionality:
@@ -413,76 +422,76 @@
 TEST_F(
     GLRendererTest,
     SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerIfNotVisible) {
-  renderer_.SetVisible(false);
-  renderer_.SetDiscardBackBufferWhenNotVisible(true);
-  EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count());
-  EXPECT_TRUE(renderer_.IsBackbufferDiscarded());
+  renderer_->SetVisible(false);
+  renderer_->SetDiscardBackBufferWhenNotVisible(true);
+  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
+  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
 }
 
 // Test GLRenderer DiscardBackbuffer functionality:
 // Suggest discarding framebuffer when one exists and the renderer is visible.
 // Expected: the allocation is ignored.
 TEST_F(GLRendererTest, SuggestBackbufferNoDoNothingWhenVisible) {
-  renderer_.SetVisible(true);
-  renderer_.SetDiscardBackBufferWhenNotVisible(true);
-  EXPECT_EQ(0, mock_client_.set_full_root_layer_damage_count());
-  EXPECT_FALSE(renderer_.IsBackbufferDiscarded());
+  renderer_->SetVisible(true);
+  renderer_->SetDiscardBackBufferWhenNotVisible(true);
+  EXPECT_EQ(0, renderer_client_.set_full_root_layer_damage_count());
+  EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
 }
 
 // Test GLRenderer DiscardBackbuffer functionality:
 // Suggest discarding framebuffer when one does not exist.
 // Expected: it does nothing.
 TEST_F(GLRendererTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing) {
-  renderer_.SetVisible(false);
-  renderer_.SetDiscardBackBufferWhenNotVisible(true);
-  EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count());
-  EXPECT_TRUE(renderer_.IsBackbufferDiscarded());
+  renderer_->SetVisible(false);
+  renderer_->SetDiscardBackBufferWhenNotVisible(true);
+  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
+  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
 
-  renderer_.SetDiscardBackBufferWhenNotVisible(true);
-  EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count());
-  EXPECT_TRUE(renderer_.IsBackbufferDiscarded());
+  renderer_->SetDiscardBackBufferWhenNotVisible(true);
+  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
+  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
 }
 
 // Test GLRenderer DiscardBackbuffer functionality:
 // Begin drawing a frame while a framebuffer is discarded.
 // Expected: will recreate framebuffer.
 TEST_F(GLRendererTest, DiscardedBackbufferIsRecreatedForScopeDuration) {
-  renderer_.SetVisible(false);
-  renderer_.SetDiscardBackBufferWhenNotVisible(true);
-  EXPECT_TRUE(renderer_.IsBackbufferDiscarded());
-  EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count());
+  renderer_->SetVisible(false);
+  renderer_->SetDiscardBackBufferWhenNotVisible(true);
+  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
+  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
 
-  renderer_.SetVisible(true);
-  renderer_.DrawFrame(mock_client_.render_passes_in_draw_order());
-  EXPECT_FALSE(renderer_.IsBackbufferDiscarded());
+  renderer_->SetVisible(true);
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
+  EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
 
   SwapBuffers();
-  EXPECT_EQ(1, Context()->frame_count());
+  EXPECT_EQ(1, context3d_->frame_count());
 }
 
 TEST_F(GLRendererTest, FramebufferDiscardedAfterReadbackWhenNotVisible) {
-  renderer_.SetVisible(false);
-  renderer_.SetDiscardBackBufferWhenNotVisible(true);
-  EXPECT_TRUE(renderer_.IsBackbufferDiscarded());
-  EXPECT_EQ(1, mock_client_.set_full_root_layer_damage_count());
+  renderer_->SetVisible(false);
+  renderer_->SetDiscardBackBufferWhenNotVisible(true);
+  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
+  EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
 
   char pixels[4];
-  renderer_.DrawFrame(mock_client_.render_passes_in_draw_order());
-  EXPECT_FALSE(renderer_.IsBackbufferDiscarded());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
+  EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
 
-  renderer_.GetFramebufferPixels(pixels, gfx::Rect(0, 0, 1, 1));
-  EXPECT_TRUE(renderer_.IsBackbufferDiscarded());
-  EXPECT_EQ(2, mock_client_.set_full_root_layer_damage_count());
+  renderer_->GetFramebufferPixels(pixels, gfx::Rect(0, 0, 1, 1));
+  EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
+  EXPECT_EQ(2, renderer_client_.set_full_root_layer_damage_count());
 }
 
 TEST_F(GLRendererTest, ExternalStencil) {
-  EXPECT_FALSE(renderer_.stencil_enabled());
+  EXPECT_FALSE(renderer_->stencil_enabled());
 
-  mock_client_.EnableExternalStencilTest();
-  mock_client_.root_render_pass()->has_transparent_background = false;
+  renderer_client_.EnableExternalStencilTest();
+  renderer_client_.root_render_pass()->has_transparent_background = false;
 
-  renderer_.DrawFrame(mock_client_.render_passes_in_draw_order());
-  EXPECT_TRUE(renderer_.stencil_enabled());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
+  EXPECT_TRUE(renderer_->stencil_enabled());
 }
 
 class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
@@ -638,14 +647,17 @@
 // This test isn't using the same fixture as GLRendererTest, and you can't mix
 // TEST() and TEST_F() with the same name, Hence LRC2.
 TEST(GLRendererTest2, InitializationDoesNotMakeSynchronousCalls) {
-  FakeRendererClient mock_client;
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new ForbidSynchronousCallContext)));
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new ForbidSynchronousCallContext)));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
+
+  FakeRendererClient renderer_client;
   FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
+      &renderer_client, output_surface.get(), resource_provider.get());
 
   EXPECT_TRUE(renderer.Initialize());
 }
@@ -677,14 +689,17 @@
 };
 
 TEST(GLRendererTest2, InitializationWithQuicklyLostContextDoesNotAssert) {
-  FakeRendererClient mock_client;
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new LoseContextOnFirstGetContext)));
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new LoseContextOnFirstGetContext)));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
+
+  FakeRendererClient renderer_client;
   FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
+      &renderer_client, output_surface.get(), resource_provider.get());
 
   renderer.Initialize();
 }
@@ -702,21 +717,26 @@
 };
 
 TEST(GLRendererTest2, OpaqueBackground) {
-  FakeRendererClient mock_client;
+  scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+  ClearCountingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
-      scoped_ptr<WebKit::WebGraphicsContext3D>(new ClearCountingContext)));
-  ClearCountingContext* context =
-      static_cast<ClearCountingContext*>(output_surface->context3d());
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
-  FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
 
-  mock_client.root_render_pass()->has_transparent_background = false;
+  FakeRendererClient renderer_client;
+  FakeRendererGL renderer(
+      &renderer_client, output_surface.get(), resource_provider.get());
+
+  renderer_client.root_render_pass()->has_transparent_background = false;
 
   EXPECT_TRUE(renderer.Initialize());
 
-  renderer.DrawFrame(mock_client.render_passes_in_draw_order());
+  renderer.DrawFrame(renderer_client.render_passes_in_draw_order());
 
 // On DEBUG builds, render passes with opaque background clear to blue to
 // easily see regions that were not drawn on the screen.
@@ -728,21 +748,26 @@
 }
 
 TEST(GLRendererTest2, TransparentBackground) {
-  FakeRendererClient mock_client;
+  scoped_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
+  ClearCountingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
-      scoped_ptr<WebKit::WebGraphicsContext3D>(new ClearCountingContext)));
-  ClearCountingContext* context =
-      static_cast<ClearCountingContext*>(output_surface->context3d());
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
-  FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
 
-  mock_client.root_render_pass()->has_transparent_background = true;
+  FakeRendererClient renderer_client;
+  FakeRendererGL renderer(
+      &renderer_client, output_surface.get(), resource_provider.get());
+
+  renderer_client.root_render_pass()->has_transparent_background = true;
 
   EXPECT_TRUE(renderer.Initialize());
 
-  renderer.DrawFrame(mock_client.render_passes_in_draw_order());
+  renderer.DrawFrame(renderer_client.render_passes_in_draw_order());
 
   EXPECT_EQ(1, context->clear_count());
 }
@@ -799,17 +824,21 @@
 };
 
 TEST(GLRendererTest2, VisibilityChangeIsLastCall) {
-  FakeRendererClient mock_client;
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new VisibilityChangeIsLastCallTrackingContext)));
-  VisibilityChangeIsLastCallTrackingContext* context =
-      static_cast<VisibilityChangeIsLastCallTrackingContext*>(
-          output_surface->context3d());
+  scoped_ptr<VisibilityChangeIsLastCallTrackingContext> context_owned(
+      new VisibilityChangeIsLastCallTrackingContext);
+  VisibilityChangeIsLastCallTrackingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
+
+  FakeRendererClient renderer_client;
   FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
+      &renderer_client, output_surface.get(), resource_provider.get());
 
   EXPECT_TRUE(renderer.Initialize());
 
@@ -819,7 +848,7 @@
   // RenderClient and the Context by giving them both a pointer to a variable on
   // the stack.
   renderer.SetVisible(true);
-  renderer.DrawFrame(mock_client.render_passes_in_draw_order());
+  renderer.DrawFrame(renderer_client.render_passes_in_draw_order());
   renderer.SetVisible(false);
   EXPECT_TRUE(context->last_call_was_set_visibility());
 }
@@ -854,16 +883,21 @@
 };
 
 TEST(GLRendererTest2, ActiveTextureState) {
-  FakeRendererClient fake_client;
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new TextureStateTrackingContext)));
-  TextureStateTrackingContext* context =
-      static_cast<TextureStateTrackingContext*>(output_surface->context3d());
+  scoped_ptr<TextureStateTrackingContext> context_owned(
+      new TextureStateTrackingContext);
+  TextureStateTrackingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
+
+  FakeRendererClient renderer_client;
   FakeRendererGL renderer(
-      &fake_client, output_surface.get(), resource_provider.get());
+      &renderer_client, output_surface.get(), resource_provider.get());
 
   // During initialization we are allowed to set any texture parameters.
   EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber());
@@ -938,22 +972,26 @@
 };
 
 TEST(GLRendererTest2, ShouldClearRootRenderPass) {
-  NoClearRootRenderPassFakeClient mock_client;
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new NoClearRootRenderPassMockContext)));
-  NoClearRootRenderPassMockContext* mock_context =
-      static_cast<NoClearRootRenderPassMockContext*>(
-          output_surface->context3d());
+  scoped_ptr<NoClearRootRenderPassMockContext> mock_context_owned(
+      new NoClearRootRenderPassMockContext);
+  NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+          mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
+
+  NoClearRootRenderPassFakeClient renderer_client;
   FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
+      &renderer_client, output_surface.get(), resource_provider.get());
   EXPECT_TRUE(renderer.Initialize());
 
-  gfx::Rect viewport_rect(mock_client.DeviceViewport());
+  gfx::Rect viewport_rect(renderer_client.DeviceViewport());
   ScopedPtrVector<RenderPass>& render_passes =
-      *mock_client.render_passes_in_draw_order();
+      *renderer_client.render_passes_in_draw_order();
   render_passes.clear();
 
   RenderPass::Id root_pass_id(1, 0);
@@ -988,8 +1026,8 @@
       .After(first_render_pass);
 
   renderer.DecideRenderPassAllocationsForFrame(
-      *mock_client.render_passes_in_draw_order());
-  renderer.DrawFrame(mock_client.render_passes_in_draw_order());
+      *renderer_client.render_passes_in_draw_order());
+  renderer.DrawFrame(renderer_client.render_passes_in_draw_order());
 
   // In multiple render passes all but the root pass should clear the
   // framebuffer.
@@ -1017,20 +1055,26 @@
 };
 
 TEST(GLRendererTest2, ScissorTestWhenClearing) {
-  FakeRendererClient mock_client;
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new ScissorTestOnClearCheckingContext)));
+  scoped_ptr<ScissorTestOnClearCheckingContext> context_owned(
+      new ScissorTestOnClearCheckingContext);
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
+
+  FakeRendererClient renderer_client;
   FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
+      &renderer_client, output_surface.get(), resource_provider.get());
   EXPECT_TRUE(renderer.Initialize());
   EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
 
-  gfx::Rect viewport_rect(mock_client.DeviceViewport());
+  gfx::Rect viewport_rect(renderer_client.DeviceViewport());
   ScopedPtrVector<RenderPass>& render_passes =
-      *mock_client.render_passes_in_draw_order();
+      *renderer_client.render_passes_in_draw_order();
   render_passes.clear();
 
   gfx::Rect grand_child_rect(25, 25);
@@ -1054,15 +1098,17 @@
   AddRenderPassQuad(child_pass, grand_child_pass);
 
   renderer.DecideRenderPassAllocationsForFrame(
-      *mock_client.render_passes_in_draw_order());
-  renderer.DrawFrame(mock_client.render_passes_in_draw_order());
+      *renderer_client.render_passes_in_draw_order());
+  renderer.DrawFrame(renderer_client.render_passes_in_draw_order());
 }
 
 class NonReshapableOutputSurface : public FakeOutputSurface {
  public:
   explicit NonReshapableOutputSurface(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
-      : FakeOutputSurface(context3d.Pass(), false) {}
+      scoped_ptr<TestWebGraphicsContext3D> context3d)
+      : FakeOutputSurface(
+          TestContextProvider::Create(context3d.Pass()),
+          false) {}
   virtual gfx::Size SurfaceSize() const OVERRIDE { return gfx::Size(500, 500); }
 };
 
@@ -1108,21 +1154,27 @@
   // and maintains a fixed size. This test verifies that glViewport and
   // glScissor's Y coordinate is flipped correctly in this environment, and that
   // the glViewport can be at a nonzero origin within the surface.
-  OffsetViewportRendererClient mock_client;
-  scoped_ptr<OutputSurface> output_surface(make_scoped_ptr(
-      new NonReshapableOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new FlippedScissorAndViewportContext))));
+  scoped_ptr<FlippedScissorAndViewportContext> context_owned(
+      new FlippedScissorAndViewportContext);
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(new NonReshapableOutputSurface(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
+
+  OffsetViewportRendererClient renderer_client;
   FakeRendererGL renderer(
-      &mock_client, output_surface.get(), resource_provider.get());
+      &renderer_client, output_surface.get(), resource_provider.get());
   EXPECT_TRUE(renderer.Initialize());
   EXPECT_FALSE(renderer.Capabilities().using_partial_swap);
 
-  gfx::Rect viewport_rect(mock_client.DeviceViewport().size());
+  gfx::Rect viewport_rect(renderer_client.DeviceViewport().size());
   gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
   ScopedPtrVector<RenderPass>& render_passes =
-      *mock_client.render_passes_in_draw_order();
+      *renderer_client.render_passes_in_draw_order();
   render_passes.clear();
 
   RenderPass::Id root_pass_id(1, 0);
@@ -1131,14 +1183,14 @@
   AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
 
   renderer.DecideRenderPassAllocationsForFrame(
-      *mock_client.render_passes_in_draw_order());
-  renderer.DrawFrame(mock_client.render_passes_in_draw_order());
+      *renderer_client.render_passes_in_draw_order());
+  renderer.DrawFrame(renderer_client.render_passes_in_draw_order());
 }
 
 TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
-  gfx::Rect viewport_rect(mock_client_.DeviceViewport());
+  gfx::Rect viewport_rect(renderer_client_.DeviceViewport());
   ScopedPtrVector<RenderPass>* render_passes =
-      mock_client_.render_passes_in_draw_order();
+      renderer_client_.render_passes_in_draw_order();
 
   gfx::Rect child_rect(50, 50);
   RenderPass::Id child_pass_id(2, 0);
@@ -1193,8 +1245,8 @@
                     gfx::Transform());
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassProgram();
 
   // RenderPassColorMatrixProgram
@@ -1209,8 +1261,8 @@
   AddRenderPassQuad(root_pass, child_pass, 0, filter, gfx::Transform());
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassColorMatrixProgram();
 
   // RenderPassMaskProgram
@@ -1229,8 +1281,8 @@
                     gfx::Transform());
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassMaskProgram();
 
   // RenderPassMaskColorMatrixProgram
@@ -1245,8 +1297,8 @@
   AddRenderPassQuad(root_pass, child_pass, mask, filter, gfx::Transform());
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassMaskColorMatrixProgram();
 
   // RenderPassProgramAA
@@ -1265,8 +1317,8 @@
                     transform_causing_aa);
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassProgramAA();
 
   // RenderPassColorMatrixProgramAA
@@ -1281,8 +1333,8 @@
   AddRenderPassQuad(root_pass, child_pass, 0, filter, transform_causing_aa);
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassColorMatrixProgramAA();
 
   // RenderPassMaskProgramAA
@@ -1298,8 +1350,8 @@
       transform_causing_aa);
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassMaskProgramAA();
 
   // RenderPassMaskColorMatrixProgramAA
@@ -1314,8 +1366,8 @@
   AddRenderPassQuad(root_pass, child_pass, mask, filter, transform_causing_aa);
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
   TestRenderPassMaskColorMatrixProgramAA();
 }
 
@@ -1326,7 +1378,7 @@
   RenderPass::Id child_pass_id(2, 0);
   TestRenderPass* child_pass;
 
-  gfx::Rect viewport_rect(mock_client_.DeviceViewport());
+  gfx::Rect viewport_rect(renderer_client_.DeviceViewport());
   RenderPass::Id root_pass_id(1, 0);
   TestRenderPass* root_pass;
 
@@ -1345,7 +1397,7 @@
 
   // Set up the render pass quad to be drawn
   ScopedPtrVector<RenderPass>* render_passes =
-      mock_client_.render_passes_in_draw_order();
+      renderer_client_.render_passes_in_draw_order();
 
   render_passes->clear();
 
@@ -1362,8 +1414,8 @@
                     transform_preventing_aa);
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
 
   // If use_aa incorrectly ignores clipping, it will use the
   // RenderPassProgramAA shader instead of the RenderPassProgram.
@@ -1371,9 +1423,9 @@
 }
 
 TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
-  gfx::Rect viewport_rect(mock_client_.DeviceViewport());
+  gfx::Rect viewport_rect(renderer_client_.DeviceViewport());
   ScopedPtrVector<RenderPass>* render_passes =
-      mock_client_.render_passes_in_draw_order();
+      renderer_client_.render_passes_in_draw_order();
 
   RenderPass::Id root_pass_id(1, 0);
   TestRenderPass* root_pass;
@@ -1392,8 +1444,8 @@
                      pixel_aligned_transform_causing_aa);
 
   renderer_->DecideRenderPassAllocationsForFrame(
-      *mock_client_.render_passes_in_draw_order());
-  renderer_->DrawFrame(mock_client_.render_passes_in_draw_order());
+      *renderer_client_.render_passes_in_draw_order());
+  renderer_->DrawFrame(renderer_client_.render_passes_in_draw_order());
 
   TestSolidColorProgramAA();
 }
@@ -1427,8 +1479,9 @@
 class MockOutputSurface : public OutputSurface {
  public:
   MockOutputSurface()
-      : OutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D>(
-            new StrictMock<OutputSurfaceMockContext>)) {
+      : OutputSurface(TestContextProvider::Create(
+          scoped_ptr<TestWebGraphicsContext3D>(
+              new StrictMock<OutputSurfaceMockContext>))) {
     surface_size_ = gfx::Size(100, 100);
   }
   virtual ~MockOutputSurface() {}
@@ -1442,13 +1495,19 @@
 
 class MockOutputSurfaceTest : public testing::Test, public FakeRendererClient {
  protected:
-  MockOutputSurfaceTest()
-      : resource_provider_(ResourceProvider::Create(&output_surface_, 0)),
-        renderer_(this, &output_surface_, resource_provider_.get()) {}
+  virtual void SetUp() {
+    FakeOutputSurfaceClient output_surface_client_;
+    CHECK(output_surface_.BindToClient(&output_surface_client_));
 
-  virtual void SetUp() { EXPECT_TRUE(renderer_.Initialize()); }
+    resource_provider_ = ResourceProvider::Create(&output_surface_, 0).Pass();
 
-  void SwapBuffers() { renderer_.SwapBuffers(); }
+    renderer_.reset(new FakeRendererGL(this,
+                                       &output_surface_,
+                                       resource_provider_.get()));
+    EXPECT_TRUE(renderer_->Initialize());
+  }
+
+  void SwapBuffers() { renderer_->SwapBuffers(); }
 
   void DrawFrame() {
     gfx::Rect viewport_rect(DeviceViewport());
@@ -1469,49 +1528,51 @@
 
     EXPECT_CALL(*Context(), drawElements(_, _, _, _)).Times(1);
 
-    renderer_.DecideRenderPassAllocationsForFrame(
+    renderer_->DecideRenderPassAllocationsForFrame(
         *render_passes_in_draw_order());
-    renderer_.DrawFrame(render_passes_in_draw_order());
+    renderer_->DrawFrame(render_passes_in_draw_order());
   }
 
   OutputSurfaceMockContext* Context() {
-    return static_cast<OutputSurfaceMockContext*>(output_surface_.context3d());
+    return static_cast<OutputSurfaceMockContext*>(
+        output_surface_.context_provider()->Context3d());
   }
 
+  FakeOutputSurfaceClient output_surface_client_;
   StrictMock<MockOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
-  FakeRendererGL renderer_;
+  scoped_ptr<FakeRendererGL> renderer_;
 };
 
 TEST_F(MockOutputSurfaceTest, DrawFrameAndSwap) {
   DrawFrame();
 
   EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
-  renderer_.SwapBuffers();
+  renderer_->SwapBuffers();
 }
 
 TEST_F(MockOutputSurfaceTest, DrawFrameAndResizeAndSwap) {
   DrawFrame();
   EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
-  renderer_.SwapBuffers();
+  renderer_->SwapBuffers();
 
   set_viewport_and_scale(gfx::Size(2, 2), 2.f);
-  renderer_.ViewportChanged();
+  renderer_->ViewportChanged();
 
   DrawFrame();
   EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
-  renderer_.SwapBuffers();
+  renderer_->SwapBuffers();
 
   DrawFrame();
   EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
-  renderer_.SwapBuffers();
+  renderer_->SwapBuffers();
 
   set_viewport_and_scale(gfx::Size(1, 1), 1.f);
-  renderer_.ViewportChanged();
+  renderer_->ViewportChanged();
 
   DrawFrame();
   EXPECT_CALL(output_surface_, SwapBuffers(_)).Times(1);
-  renderer_.SwapBuffers();
+  renderer_->SwapBuffers();
 }
 
 class GLRendererTestSyncPoint : public GLRendererPixelTest {
@@ -1531,20 +1592,21 @@
 TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) {
   int sync_point_callback_count = 0;
   int other_callback_count = 0;
-  unsigned sync_point = output_surface_->context3d()->insertSyncPoint();
+  unsigned sync_point =
+      output_surface_->context_provider()->Context3d()->insertSyncPoint();
 
-  output_surface_->context3d()->loseContextCHROMIUM(
+  output_surface_->context_provider()->Context3d()->loseContextCHROMIUM(
       GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
 
   SyncPointHelper::SignalSyncPoint(
-      output_surface_->context3d(),
+      output_surface_->context_provider()->Context3d(),
       sync_point,
       base::Bind(&SyncPointCallback, &sync_point_callback_count));
   EXPECT_EQ(0, sync_point_callback_count);
   EXPECT_EQ(0, other_callback_count);
 
   // Make the sync point happen.
-  output_surface_->context3d()->finish();
+  output_surface_->context_provider()->Context3d()->finish();
   // Post a task after the sync point.
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
@@ -1560,17 +1622,18 @@
 TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) {
   int sync_point_callback_count = 0;
   int other_callback_count = 0;
-  unsigned sync_point = output_surface_->context3d()->insertSyncPoint();
+  unsigned sync_point =
+      output_surface_->context_provider()->Context3d()->insertSyncPoint();
 
   SyncPointHelper::SignalSyncPoint(
-      output_surface_->context3d(),
+      output_surface_->context_provider()->Context3d(),
       sync_point,
       base::Bind(&SyncPointCallback, &sync_point_callback_count));
   EXPECT_EQ(0, sync_point_callback_count);
   EXPECT_EQ(0, other_callback_count);
 
   // Make the sync point happen.
-  output_surface_->context3d()->finish();
+  output_surface_->context_provider()->Context3d()->finish();
   // Post a task after the sync point.
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc
index be990cc..f085d49 100644
--- a/cc/output/output_surface.cc
+++ b/cc/output/output_surface.cc
@@ -19,7 +19,6 @@
 #include "cc/output/output_surface_client.h"
 #include "cc/scheduler/delay_based_time_source.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-#include "third_party/WebKit/public/platform/WebGraphicsMemoryAllocation.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "ui/gfx/rect.h"
@@ -30,67 +29,10 @@
 using std::vector;
 
 namespace cc {
-namespace {
-
-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 ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
-    case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly:
-      return ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY;
-    case WebKit::WebGraphicsMemoryAllocation::
-        PriorityCutoffAllowVisibleAndNearby:
-      return ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE;
-    case WebKit::WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything:
-      return ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING;
-  }
-  NOTREACHED();
-  return ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
-}
-
-}  // anonymous namespace
-
-class OutputSurfaceCallbacks
-    : public WebKit::WebGraphicsContext3D::
-        WebGraphicsSwapBuffersCompleteCallbackCHROMIUM,
-      public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback,
-    public WebKit::WebGraphicsContext3D::
-      WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
- public:
-  explicit OutputSurfaceCallbacks(OutputSurface* client)
-      : client_(client) {
-    DCHECK(client_);
-  }
-
-  // WK:WGC3D::WGSwapBuffersCompleteCallbackCHROMIUM implementation.
-  virtual void onSwapBuffersComplete() { client_->OnSwapBuffersComplete(NULL); }
-
-  // WK:WGC3D::WGContextLostCallback implementation.
-  virtual void onContextLost() { client_->DidLoseOutputSurface(); }
-
-  // WK:WGC3D::WGMemoryAllocationChangedCallbackCHROMIUM implementation.
-  virtual void onMemoryAllocationChanged(
-      WebKit::WebGraphicsMemoryAllocation allocation) {
-    ManagedMemoryPolicy policy(
-        allocation.bytesLimitWhenVisible,
-        ConvertPriorityCutoff(allocation.priorityCutoffWhenVisible),
-        allocation.bytesLimitWhenNotVisible,
-        ConvertPriorityCutoff(allocation.priorityCutoffWhenNotVisible),
-        ManagedMemoryPolicy::kDefaultNumResourcesLimit);
-    bool discard_backbuffer = !allocation.suggestHaveBackbuffer;
-    client_->SetMemoryPolicy(policy, discard_backbuffer);
-  }
-
- private:
-  OutputSurface* client_;
-};
 
 OutputSurface::OutputSurface(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
-    : context3d_(context3d.Pass()),
+    scoped_refptr<ContextProvider> context_provider)
+    : context_provider_(context_provider),
       has_gl_discard_backbuffer_(false),
       has_swap_buffers_complete_callback_(false),
       device_scale_factor_(-1),
@@ -119,9 +61,9 @@
 }
 
 OutputSurface::OutputSurface(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+    scoped_refptr<ContextProvider> context_provider,
     scoped_ptr<cc::SoftwareOutputDevice> software_device)
-    : context3d_(context3d.Pass()),
+    : context_provider_(context_provider),
       software_device_(software_device.Pass()),
       has_gl_discard_backbuffer_(false),
       has_swap_buffers_complete_callback_(false),
@@ -219,7 +161,7 @@
   }
 }
 
-base::TimeDelta OutputSurface::RetroactiveBeginFramePeriod() {
+base::TimeDelta OutputSurface::AlternateRetroactiveBeginFramePeriod() {
   return BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
 }
 
@@ -239,9 +181,11 @@
   TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginFrame");
   check_for_retroactive_begin_frame_pending_ = false;
   base::TimeTicks now = base::TimeTicks::Now();
+  // TODO(brianderson): Remove the alternative deadline once we have better
+  // deadline estimations.
   base::TimeTicks alternative_deadline =
       skipped_begin_frame_args_.frame_time +
-      RetroactiveBeginFramePeriod();
+      AlternateRetroactiveBeginFramePeriod();
   if (now < skipped_begin_frame_args_.deadline ||
       now < alternative_deadline) {
     BeginFrame(skipped_begin_frame_args_);
@@ -287,12 +231,7 @@
 OutputSurface::~OutputSurface() {
   if (frame_rate_controller_)
     frame_rate_controller_->SetActive(false);
-
-  if (context3d_) {
-    context3d_->setSwapBuffersCompleteCallbackCHROMIUM(NULL);
-    context3d_->setContextLostCallback(NULL);
-    context3d_->setMemoryAllocationChangedCallbackCHROMIUM(NULL);
-  }
+  ResetContext3d();
 }
 
 bool OutputSurface::ForcedDrawToSoftwareDevice() const {
@@ -304,10 +243,10 @@
   client_ = client;
   bool success = true;
 
-  if (context3d_) {
-    success = context3d_->makeContextCurrent();
+  if (context_provider_) {
+    success = context_provider_->BindToCurrentThread();
     if (success)
-      SetContext3D(context3d_.Pass());
+      SetUpContext3d();
   }
 
   if (!success)
@@ -316,40 +255,42 @@
   return success;
 }
 
-bool OutputSurface::InitializeAndSetContext3D(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+bool OutputSurface::InitializeAndSetContext3d(
+    scoped_refptr<ContextProvider> context_provider,
     scoped_refptr<ContextProvider> offscreen_context_provider) {
-  DCHECK(!context3d_);
-  DCHECK(context3d);
+  DCHECK(!context_provider_);
+  DCHECK(context_provider);
   DCHECK(client_);
 
   bool success = false;
-  if (context3d->makeContextCurrent()) {
-    SetContext3D(context3d.Pass());
+  if (context_provider->BindToCurrentThread()) {
+    context_provider_ = context_provider;
+    SetUpContext3d();
     if (client_->DeferredInitialize(offscreen_context_provider))
       success = true;
   }
 
   if (!success)
-    ResetContext3D();
+    ResetContext3d();
 
   return success;
 }
 
 void OutputSurface::ReleaseGL() {
   DCHECK(client_);
-  DCHECK(context3d_);
+  DCHECK(context_provider_);
   client_->ReleaseGL();
-  ResetContext3D();
+  ResetContext3d();
 }
 
-void OutputSurface::SetContext3D(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d) {
-  DCHECK(!context3d_);
-  DCHECK(context3d);
+void OutputSurface::SetUpContext3d() {
+  DCHECK(context_provider_);
   DCHECK(client_);
 
-  string extensions_string = UTF16ToASCII(context3d->getString(GL_EXTENSIONS));
+  WebKit::WebGraphicsContext3D* context3d = context_provider_->Context3d();
+
+  string extensions_string =
+      UTF16ToASCII(context3d->getString(GL_EXTENSIONS));
   vector<string> extensions_list;
   base::SplitString(extensions_string, ' ', &extensions_list);
   set<string> extensions(extensions_list.begin(), extensions_list.end());
@@ -358,29 +299,38 @@
   has_swap_buffers_complete_callback_ =
        extensions.count("GL_CHROMIUM_swapbuffers_complete_callback") > 0;
 
-
-  context3d_ = context3d.Pass();
-  callbacks_.reset(new OutputSurfaceCallbacks(this));
-  context3d_->setSwapBuffersCompleteCallbackCHROMIUM(callbacks_.get());
-  context3d_->setContextLostCallback(callbacks_.get());
-  context3d_->setMemoryAllocationChangedCallbackCHROMIUM(callbacks_.get());
+  context_provider_->SetLostContextCallback(
+      base::Bind(&OutputSurface::DidLoseOutputSurface,
+                 base::Unretained(this)));
+  context_provider_->SetSwapBuffersCompleteCallback(
+      base::Bind(&OutputSurface::OnSwapBuffersComplete,
+                 base::Unretained(this),
+                 static_cast<CompositorFrameAck*>(NULL)));
+  context_provider_->SetMemoryPolicyChangedCallback(
+      base::Bind(&OutputSurface::SetMemoryPolicy,
+                 base::Unretained(this)));
 }
 
-void OutputSurface::ResetContext3D() {
-  context3d_.reset();
-  callbacks_.reset();
+void OutputSurface::ResetContext3d() {
+  if (context_provider_.get()) {
+    context_provider_->SetLostContextCallback(
+        ContextProvider::LostContextCallback());
+    context_provider_->SetSwapBuffersCompleteCallback(
+        ContextProvider::SwapBuffersCompleteCallback());
+    context_provider_->SetMemoryPolicyChangedCallback(
+        ContextProvider::MemoryPolicyChangedCallback());
+  }
+  context_provider_ = NULL;
 }
 
 void OutputSurface::EnsureBackbuffer() {
-  DCHECK(context3d_);
-  if (has_gl_discard_backbuffer_)
-    context3d_->ensureBackbufferCHROMIUM();
+  if (context_provider_ && has_gl_discard_backbuffer_)
+    context_provider_->Context3d()->ensureBackbufferCHROMIUM();
 }
 
 void OutputSurface::DiscardBackbuffer() {
-  DCHECK(context3d_);
-  if (has_gl_discard_backbuffer_)
-    context3d_->discardBackbufferCHROMIUM();
+  if (context_provider_ && has_gl_discard_backbuffer_)
+    context_provider_->Context3d()->discardBackbufferCHROMIUM();
 }
 
 void OutputSurface::Reshape(gfx::Size size, float scale_factor) {
@@ -389,8 +339,8 @@
 
   surface_size_ = size;
   device_scale_factor_ = scale_factor;
-  if (context3d_) {
-    context3d_->reshapeWithScaleFactor(
+  if (context_provider_) {
+    context_provider_->Context3d()->reshapeWithScaleFactor(
         size.width(), size.height(), scale_factor);
   }
   if (software_device_)
@@ -402,8 +352,8 @@
 }
 
 void OutputSurface::BindFramebuffer() {
-  DCHECK(context3d_);
-  context3d_->bindFramebuffer(GL_FRAMEBUFFER, 0);
+  DCHECK(context_provider_);
+  context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
 void OutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
@@ -413,20 +363,21 @@
     return;
   }
 
-  DCHECK(context3d_);
+  DCHECK(context_provider_);
   DCHECK(frame->gl_frame_data);
 
   if (frame->gl_frame_data->sub_buffer_rect ==
       gfx::Rect(frame->gl_frame_data->size)) {
     // Note that currently this has the same effect as SwapBuffers; we should
     // consider exposing a different entry point on WebGraphicsContext3D.
-    context3d()->prepareTexture();
+    context_provider_->Context3d()->prepareTexture();
   } else {
     gfx::Rect sub_buffer_rect = frame->gl_frame_data->sub_buffer_rect;
-    context3d()->postSubBufferCHROMIUM(sub_buffer_rect.x(),
-                                       sub_buffer_rect.y(),
-                                       sub_buffer_rect.width(),
-                                       sub_buffer_rect.height());
+    context_provider_->Context3d()->postSubBufferCHROMIUM(
+        sub_buffer_rect.x(),
+        sub_buffer_rect.y(),
+        sub_buffer_rect.width(),
+        sub_buffer_rect.height());
   }
 
   if (!has_swap_buffers_complete_callback_)
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 86d4dc8..a94d41e 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -13,7 +13,6 @@
 #include "cc/output/context_provider.h"
 #include "cc/output/software_output_device.h"
 #include "cc/scheduler/frame_rate_controller.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 
 namespace base { class SingleThreadTaskRunner; }
 
@@ -31,7 +30,6 @@
 class CompositorFrameAck;
 struct ManagedMemoryPolicy;
 class OutputSurfaceClient;
-class OutputSurfaceCallbacks;
 
 // Represents the output surface for a compositor. The compositor owns
 // and manages its destruction. Its lifetime is:
@@ -46,11 +44,11 @@
     DEFAULT_MAX_FRAMES_PENDING = 2
   };
 
-  explicit OutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d);
+  explicit OutputSurface(scoped_refptr<ContextProvider> context_provider);
 
   explicit OutputSurface(scoped_ptr<cc::SoftwareOutputDevice> software_device);
 
-  OutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+  OutputSurface(scoped_refptr<ContextProvider> context_provider,
                 scoped_ptr<cc::SoftwareOutputDevice> software_device);
 
   virtual ~OutputSurface();
@@ -79,10 +77,9 @@
   // surface. Either of these may return a null pointer, but not both.
   // In the event of a lost context, the entire output surface should be
   // recreated.
-  WebKit::WebGraphicsContext3D* context3d() const {
-    return context3d_.get();
+  scoped_refptr<ContextProvider> context_provider() const {
+    return context_provider_.get();
   }
-
   SoftwareOutputDevice* software_device() const {
     return software_device_.get();
   }
@@ -127,21 +124,22 @@
   // OutputSurfaceClient::BeginFrame until the callback is disabled.
   virtual void SetNeedsBeginFrame(bool enable);
 
+  bool HasClient() { return !!client_; }
+
  protected:
   // Synchronously initialize context3d and enter hardware mode.
   // This can only supported in threaded compositing mode.
   // |offscreen_context_provider| should match what is returned by
   // LayerTreeClient::OffscreenContextProviderForCompositorThread.
-  bool InitializeAndSetContext3D(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+  bool InitializeAndSetContext3d(
+      scoped_refptr<ContextProvider> context_provider,
       scoped_refptr<ContextProvider> offscreen_context_provider);
   void ReleaseGL();
 
   void PostSwapBuffersComplete();
 
   struct cc::OutputSurface::Capabilities capabilities_;
-  scoped_ptr<OutputSurfaceCallbacks> callbacks_;
-  scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
+  scoped_refptr<ContextProvider> context_provider_;
   scoped_ptr<cc::SoftwareOutputDevice> software_device_;
   bool has_gl_discard_backbuffer_;
   bool has_swap_buffers_complete_callback_;
@@ -163,7 +161,6 @@
 
   // Forwarded to OutputSurfaceClient but threaded through OutputSurface
   // first so OutputSurface has a chance to update the FrameRateController
-  bool HasClient() { return !!client_; }
   void SetNeedsRedrawRect(gfx::Rect damage_rect);
   void BeginFrame(const BeginFrameArgs& args);
   void DidSwapBuffers();
@@ -174,7 +171,7 @@
                                   gfx::Rect viewport);
 
   // virtual for testing.
-  virtual base::TimeDelta RetroactiveBeginFramePeriod();
+  virtual base::TimeDelta AlternateRetroactiveBeginFramePeriod();
   virtual void PostCheckForRetroactiveBeginFrame();
   void CheckForRetroactiveBeginFrame();
 
@@ -182,8 +179,8 @@
   OutputSurfaceClient* client_;
   friend class OutputSurfaceCallbacks;
 
-  void SetContext3D(scoped_ptr<WebKit::WebGraphicsContext3D> context3d);
-  void ResetContext3D();
+  void SetUpContext3d();
+  void ResetContext3d();
   void SetMemoryPolicy(const ManagedMemoryPolicy& policy,
                        bool discard_backbuffer_when_not_visible);
 
diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc
index 276828c..54fd3a1 100644
--- a/cc/output/output_surface_unittest.cc
+++ b/cc/output/output_surface_unittest.cc
@@ -5,47 +5,41 @@
 #include "cc/output/output_surface.h"
 
 #include "base/test/test_simple_task_runner.h"
+#include "cc/debug/test_context_provider.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/output/managed_memory_policy.h"
 #include "cc/output/output_surface_client.h"
 #include "cc/output/software_output_device.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_output_surface_client.h"
 #include "cc/test/scheduler_test_common.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebGraphicsMemoryAllocation.h"
-
-using WebKit::WebGraphicsMemoryAllocation;
 
 namespace cc {
 namespace {
 
 class TestOutputSurface : public OutputSurface {
  public:
-  explicit TestOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
-      : OutputSurface(context3d.Pass()) {}
+  explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider)
+      : OutputSurface(context_provider) {}
 
   explicit TestOutputSurface(
       scoped_ptr<cc::SoftwareOutputDevice> software_device)
       : OutputSurface(software_device.Pass()) {}
 
-  TestOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+  TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
                     scoped_ptr<cc::SoftwareOutputDevice> software_device)
-      : OutputSurface(context3d.Pass(), software_device.Pass()) {}
+      : OutputSurface(context_provider, software_device.Pass()) {}
 
-  bool InitializeNewContext3D(
-      scoped_ptr<WebKit::WebGraphicsContext3D> new_context3d) {
-    return InitializeAndSetContext3D(new_context3d.Pass(),
+  bool InitializeNewContext3d(
+      scoped_refptr<ContextProvider> new_context_provider) {
+    return InitializeAndSetContext3d(new_context_provider,
                                      scoped_refptr<ContextProvider>());
   }
 
   using OutputSurface::ReleaseGL;
 
-  bool HasClientForTesting() {
-    return HasClient();
-  }
-
   void OnVSyncParametersChangedForTesting(base::TimeTicks timebase,
                                           base::TimeDelta interval) {
     OnVSyncParametersChanged(timebase, interval);
@@ -67,8 +61,8 @@
     OnSwapBuffersComplete(NULL);
   }
 
-  void SetRetroactiveBeginFramePeriod(base::TimeDelta period) {
-    retroactive_begin_frame_period_ = period;
+  void SetAlternateRetroactiveBeginFramePeriod(base::TimeDelta period) {
+    alternate_retroactive_begin_frame_period_ = period;
   }
 
  protected:
@@ -77,116 +71,108 @@
     CheckForRetroactiveBeginFrame();
   }
 
-  virtual base::TimeDelta RetroactiveBeginFramePeriod() OVERRIDE {
-    return retroactive_begin_frame_period_;
+  virtual base::TimeDelta AlternateRetroactiveBeginFramePeriod() OVERRIDE {
+    return alternate_retroactive_begin_frame_period_;
   }
 
-  base::TimeDelta retroactive_begin_frame_period_;
+  base::TimeDelta alternate_retroactive_begin_frame_period_;
 };
 
 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) {
-  scoped_ptr<TestWebGraphicsContext3D> context3d =
-      TestWebGraphicsContext3D::Create();
-
-  TestOutputSurface output_surface(
-      context3d.PassAs<WebKit::WebGraphicsContext3D>());
-  EXPECT_FALSE(output_surface.HasClientForTesting());
+  TestOutputSurface output_surface(TestContextProvider::Create());
+  EXPECT_FALSE(output_surface.HasClient());
 
   FakeOutputSurfaceClient client;
   EXPECT_TRUE(output_surface.BindToClient(&client));
-  EXPECT_TRUE(output_surface.HasClientForTesting());
+  EXPECT_TRUE(output_surface.HasClient());
   EXPECT_FALSE(client.deferred_initialize_called());
 
   // Verify DidLoseOutputSurface callback is hooked up correctly.
   EXPECT_FALSE(client.did_lose_output_surface_called());
-  output_surface.context3d()->loseContextCHROMIUM(
+  output_surface.context_provider()->Context3d()->loseContextCHROMIUM(
       GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
   EXPECT_TRUE(client.did_lose_output_surface_called());
 }
 
 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) {
-  scoped_ptr<TestWebGraphicsContext3D> context3d =
-      TestWebGraphicsContext3D::Create();
+  scoped_refptr<TestContextProvider> context_provider =
+      TestContextProvider::Create();
 
   // Lose the context so BindToClient fails.
-  context3d->set_times_make_current_succeeds(0);
+  context_provider->UnboundTestContext3d()->set_times_make_current_succeeds(0);
 
-  TestOutputSurface output_surface(
-      context3d.PassAs<WebKit::WebGraphicsContext3D>());
-  EXPECT_FALSE(output_surface.HasClientForTesting());
+  TestOutputSurface output_surface(context_provider);
+  EXPECT_FALSE(output_surface.HasClient());
 
   FakeOutputSurfaceClient client;
   EXPECT_FALSE(output_surface.BindToClient(&client));
-  EXPECT_FALSE(output_surface.HasClientForTesting());
+  EXPECT_FALSE(output_surface.HasClient());
 }
 
-class InitializeNewContext3D : public ::testing::Test {
+class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test {
  public:
-  InitializeNewContext3D()
-      : context3d_(TestWebGraphicsContext3D::Create()),
+  OutputSurfaceTestInitializeNewContext3d()
+      : context_provider_(TestContextProvider::Create()),
         output_surface_(
             scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {}
 
  protected:
   void BindOutputSurface() {
     EXPECT_TRUE(output_surface_.BindToClient(&client_));
-    EXPECT_TRUE(output_surface_.HasClientForTesting());
+    EXPECT_TRUE(output_surface_.HasClient());
   }
 
   void InitializeNewContextExpectFail() {
-    EXPECT_FALSE(output_surface_.InitializeNewContext3D(
-        context3d_.PassAs<WebKit::WebGraphicsContext3D>()));
-    EXPECT_TRUE(output_surface_.HasClientForTesting());
+    EXPECT_FALSE(output_surface_.InitializeNewContext3d(context_provider_));
+    EXPECT_TRUE(output_surface_.HasClient());
 
-    EXPECT_FALSE(output_surface_.context3d());
+    EXPECT_FALSE(output_surface_.context_provider());
     EXPECT_TRUE(output_surface_.software_device());
   }
 
-  scoped_ptr<TestWebGraphicsContext3D> context3d_;
+  scoped_refptr<TestContextProvider> context_provider_;
   TestOutputSurface output_surface_;
   FakeOutputSurfaceClient client_;
 };
 
-TEST_F(InitializeNewContext3D, Success) {
+TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) {
   BindOutputSurface();
   EXPECT_FALSE(client_.deferred_initialize_called());
 
-  EXPECT_TRUE(output_surface_.InitializeNewContext3D(
-      context3d_.PassAs<WebKit::WebGraphicsContext3D>()));
+  EXPECT_TRUE(output_surface_.InitializeNewContext3d(context_provider_));
   EXPECT_TRUE(client_.deferred_initialize_called());
+  EXPECT_EQ(context_provider_, output_surface_.context_provider());
 
   EXPECT_FALSE(client_.did_lose_output_surface_called());
-  output_surface_.context3d()->loseContextCHROMIUM(
+  context_provider_->Context3d()->loseContextCHROMIUM(
       GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
   EXPECT_TRUE(client_.did_lose_output_surface_called());
 
   output_surface_.ReleaseGL();
-  EXPECT_FALSE(output_surface_.context3d());
+  EXPECT_FALSE(output_surface_.context_provider());
 }
 
-TEST_F(InitializeNewContext3D, Context3dMakeCurrentFails) {
+TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) {
   BindOutputSurface();
-  context3d_->set_times_make_current_succeeds(0);
+
+  context_provider_->UnboundTestContext3d()
+      ->set_times_make_current_succeeds(0);
   InitializeNewContextExpectFail();
 }
 
-TEST_F(InitializeNewContext3D, ClientDeferredInitializeFails) {
+TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) {
   BindOutputSurface();
   client_.set_deferred_initialize_result(false);
   InitializeNewContextExpectFail();
 }
 
 TEST(OutputSurfaceTest, BeginFrameEmulation) {
-  scoped_ptr<TestWebGraphicsContext3D> context3d =
-      TestWebGraphicsContext3D::Create();
-
-  TestOutputSurface output_surface(
-      context3d.PassAs<WebKit::WebGraphicsContext3D>());
-  EXPECT_FALSE(output_surface.HasClientForTesting());
+  TestOutputSurface output_surface(TestContextProvider::Create());
+  EXPECT_FALSE(output_surface.HasClient());
 
   FakeOutputSurfaceClient client;
   EXPECT_TRUE(output_surface.BindToClient(&client));
-  EXPECT_TRUE(output_surface.HasClientForTesting());
+  EXPECT_TRUE(output_surface.HasClient());
   EXPECT_FALSE(client.deferred_initialize_called());
 
   // Initialize BeginFrame emulation
@@ -202,7 +188,7 @@
       display_refresh_interval);
 
   output_surface.SetMaxFramesPending(2);
-  output_surface.SetRetroactiveBeginFramePeriod(
+  output_surface.SetAlternateRetroactiveBeginFramePeriod(
       base::TimeDelta::FromSeconds(-1));
 
   // We should start off with 0 BeginFrames
@@ -264,22 +250,18 @@
 }
 
 TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginFrames) {
-  scoped_ptr<TestWebGraphicsContext3D> context3d =
-      TestWebGraphicsContext3D::Create();
-
-  TestOutputSurface output_surface(
-      context3d.PassAs<WebKit::WebGraphicsContext3D>());
-  EXPECT_FALSE(output_surface.HasClientForTesting());
+  TestOutputSurface output_surface(TestContextProvider::Create());
+  EXPECT_FALSE(output_surface.HasClient());
 
   FakeOutputSurfaceClient client;
   EXPECT_TRUE(output_surface.BindToClient(&client));
-  EXPECT_TRUE(output_surface.HasClientForTesting());
+  EXPECT_TRUE(output_surface.HasClient());
   EXPECT_FALSE(client.deferred_initialize_called());
 
   output_surface.SetMaxFramesPending(2);
 
   // Enable retroactive BeginFrames.
-  output_surface.SetRetroactiveBeginFramePeriod(
+  output_surface.SetAlternateRetroactiveBeginFramePeriod(
     base::TimeDelta::FromSeconds(100000));
 
   // Optimistically injected BeginFrames should be throttled if
@@ -317,28 +299,83 @@
   EXPECT_EQ(client.begin_frame_count(), 4);
 }
 
-TEST(OutputSurfaceTest, MemoryAllocation) {
-  scoped_ptr<TestWebGraphicsContext3D> scoped_context =
-      TestWebGraphicsContext3D::Create();
-  TestWebGraphicsContext3D* context = scoped_context.get();
+TEST(OutputSurfaceTest, RetroactiveBeginFrameDoesNotDoubleTickWhenEmulating) {
+  scoped_refptr<TestContextProvider> context_provider =
+      TestContextProvider::Create();
 
-  TestOutputSurface output_surface(
-      scoped_context.PassAs<WebKit::WebGraphicsContext3D>());
+  TestOutputSurface output_surface(context_provider);
+  EXPECT_FALSE(output_surface.HasClient());
+
+  FakeOutputSurfaceClient client;
+  EXPECT_TRUE(output_surface.BindToClient(&client));
+  EXPECT_TRUE(output_surface.HasClient());
+  EXPECT_FALSE(client.deferred_initialize_called());
+
+  base::TimeDelta big_interval = base::TimeDelta::FromSeconds(1000);
+
+  // Initialize BeginFrame 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(
+      task_runner.get(),
+      throttle_frame_production,
+      display_refresh_interval);
+
+  // We need to subtract an epsilon from Now() because some platforms have
+  // a slow clock.
+  output_surface.OnVSyncParametersChangedForTesting(
+      base::TimeTicks::Now() - base::TimeDelta::FromMilliseconds(1),
+      display_refresh_interval);
+
+  output_surface.SetMaxFramesPending(2);
+  output_surface.SetAlternateRetroactiveBeginFramePeriod(
+      base::TimeDelta::FromSeconds(-1));
+
+  // We should start off with 0 BeginFrames
+  EXPECT_EQ(client.begin_frame_count(), 0);
+  EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
+
+  // The first SetNeedsBeginFrame(true) should start a retroactive BeginFrame.
+  output_surface.SetNeedsBeginFrame(true);
+  EXPECT_TRUE(task_runner->HasPendingTask());
+  EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2);
+  EXPECT_EQ(client.begin_frame_count(), 1);
+
+  output_surface.SetNeedsBeginFrame(false);
+  EXPECT_TRUE(task_runner->HasPendingTask());
+  EXPECT_EQ(client.begin_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);
+  EXPECT_TRUE(task_runner->HasPendingTask());
+  EXPECT_EQ(client.begin_frame_count(), 1);
+}
+
+TEST(OutputSurfaceTest, MemoryAllocation) {
+  scoped_refptr<TestContextProvider> context_provider =
+      TestContextProvider::Create();
+
+  TestOutputSurface output_surface(context_provider);
 
   FakeOutputSurfaceClient client;
   EXPECT_TRUE(output_surface.BindToClient(&client));
 
-  WebGraphicsMemoryAllocation allocation;
-  allocation.suggestHaveBackbuffer = true;
-  allocation.bytesLimitWhenVisible = 1234;
-  allocation.priorityCutoffWhenVisible =
-      WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleOnly;
-  allocation.bytesLimitWhenNotVisible = 4567;
-  allocation.priorityCutoffWhenNotVisible =
-      WebGraphicsMemoryAllocation::PriorityCutoffAllowNothing;
+  ManagedMemoryPolicy policy(0);
+  policy.bytes_limit_when_visible = 1234;
+  policy.priority_cutoff_when_visible =
+      ManagedMemoryPolicy::CUTOFF_ALLOW_REQUIRED_ONLY;
+  policy.bytes_limit_when_not_visible = 4567;
+  policy.priority_cutoff_when_not_visible =
+      ManagedMemoryPolicy::CUTOFF_ALLOW_NOTHING;
 
-  context->SetMemoryAllocation(allocation);
+  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,
             client.memory_policy().priority_cutoff_when_visible);
@@ -347,23 +384,26 @@
             client.memory_policy().priority_cutoff_when_not_visible);
   EXPECT_FALSE(client.discard_backbuffer_when_not_visible());
 
-  allocation.suggestHaveBackbuffer = false;
-  context->SetMemoryAllocation(allocation);
+  discard_backbuffer_when_not_visible = true;
+  context_provider->SetMemoryAllocation(policy,
+                                        discard_backbuffer_when_not_visible);
   EXPECT_TRUE(client.discard_backbuffer_when_not_visible());
 
-  allocation.priorityCutoffWhenVisible =
-      WebGraphicsMemoryAllocation::PriorityCutoffAllowEverything;
-  allocation.priorityCutoffWhenNotVisible =
-      WebGraphicsMemoryAllocation::PriorityCutoffAllowVisibleAndNearby;
-  context->SetMemoryAllocation(allocation);
+  policy.priority_cutoff_when_visible =
+      ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING;
+  policy.priority_cutoff_when_not_visible =
+      ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE;
+  context_provider->SetMemoryAllocation(policy,
+                                        discard_backbuffer_when_not_visible);
   EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_EVERYTHING,
             client.memory_policy().priority_cutoff_when_visible);
   EXPECT_EQ(ManagedMemoryPolicy::CUTOFF_ALLOW_NICE_TO_HAVE,
             client.memory_policy().priority_cutoff_when_not_visible);
 
   // 0 bytes limit should be ignored.
-  allocation.bytesLimitWhenVisible = 0;
-  context->SetMemoryAllocation(allocation);
+  policy.bytes_limit_when_visible = 0;
+  context_provider->SetMemoryAllocation(policy,
+                                        discard_backbuffer_when_not_visible);
   EXPECT_EQ(1234u, client.memory_policy().bytes_limit_when_visible);
 }
 
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index 9508aa2..ba76f16 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -13,6 +13,7 @@
 #include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/pixel_test.h"
 #include "gpu/GLES2/gl2extchromium.h"
+#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/skia/include/core/SkImageFilter.h"
 #include "third_party/skia/include/core/SkMatrix.h"
 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
@@ -1003,7 +1004,8 @@
 class ExternalStencilPixelTest : public GLRendererPixelTest {
  protected:
   void ClearBackgroundToGreen() {
-    WebKit::WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebKit::WebGraphicsContext3D* context3d =
+        output_surface_->context_provider()->Context3d();
     output_surface_->EnsureBackbuffer();
     output_surface_->Reshape(device_viewport_size_, 1);
     context3d->clearColor(0.f, 1.f, 0.f, 1.f);
@@ -1012,7 +1014,8 @@
 
   void PopulateStencilBuffer() {
     // Set two quadrants of the stencil buffer to 1.
-    WebKit::WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebKit::WebGraphicsContext3D* context3d =
+        output_surface_->context_provider()->Context3d();
     ASSERT_TRUE(context3d->getContextAttributes().stencil);
     output_surface_->EnsureBackbuffer();
     output_surface_->Reshape(device_viewport_size_, 1);
diff --git a/cc/output/software_output_device.h b/cc/output/software_output_device.h
index fbada74..c1a97dc 100644
--- a/cc/output/software_output_device.h
+++ b/cc/output/software_output_device.h
@@ -37,6 +37,9 @@
   virtual void Scroll(gfx::Vector2d delta,
                       gfx::Rect clip_rect);
 
+  virtual void DiscardBackbuffer() {}
+  virtual void EnsureBackbuffer() {}
+
   // TODO(skaslev) Remove this after UberCompositor lands.
   virtual void ReclaimSoftwareFrame(unsigned id);
 
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 7735e3c..b62f5a0 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -63,6 +63,7 @@
   : DirectRenderer(client, output_surface, resource_provider),
     visible_(true),
     is_scissor_enabled_(false),
+    is_backbuffer_discarded_(false),
     output_device_(output_surface->software_device()),
     current_canvas_(NULL) {
   if (resource_provider_) {
@@ -497,6 +498,26 @@
   request->SendBitmapResult(bitmap.Pass());
 }
 
+void SoftwareRenderer::DiscardBackbuffer() {
+  if (is_backbuffer_discarded_)
+    return;
+
+  output_surface_->DiscardBackbuffer();
+
+  is_backbuffer_discarded_ = true;
+
+  // Damage tracker needs a full reset every time framebuffer is discarded.
+  client_->SetFullRootLayerDamage();
+}
+
+void SoftwareRenderer::EnsureBackbuffer() {
+  if (!is_backbuffer_discarded_)
+    return;
+
+  output_surface_->EnsureBackbuffer();
+  is_backbuffer_discarded_ = false;
+}
+
 void SoftwareRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
   TRACE_EVENT0("cc", "SoftwareRenderer::GetFramebufferPixels");
   SkBitmap subset_bitmap;
@@ -511,12 +532,15 @@
   if (visible_ == visible)
     return;
   visible_ = visible;
+
+  if (visible_)
+    EnsureBackbuffer();
+  else
+    DiscardBackbuffer();
 }
 
 void SoftwareRenderer::SetDiscardBackBufferWhenNotVisible(bool discard) {
-  // TODO(piman, skaslev): Can we release the backbuffer? We don't currently
-  // receive memory policy yet anyway.
-  NOTIMPLEMENTED();
+  // The software renderer always discards the backbuffer when not visible.
 }
 
 }  // namespace cc
diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h
index f810b68..e07b237 100644
--- a/cc/output/software_renderer.h
+++ b/cc/output/software_renderer.h
@@ -45,6 +45,8 @@
   virtual void ReceiveSwapBuffersAck(
       const CompositorFrameAck& ack) OVERRIDE;
   virtual void SetDiscardBackBufferWhenNotVisible(bool discard) OVERRIDE;
+  virtual void DiscardBackbuffer() OVERRIDE;
+  virtual void EnsureBackbuffer() OVERRIDE;
 
  protected:
   virtual void BindFramebufferToOutputSurface(DrawingFrame* frame) OVERRIDE;
@@ -95,6 +97,7 @@
   RendererCapabilities capabilities_;
   bool visible_;
   bool is_scissor_enabled_;
+  bool is_backbuffer_discarded_;
   gfx::Rect scissor_rect_;
 
   SoftwareOutputDevice* output_device_;
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index 238d654..a3361a9 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -13,6 +13,7 @@
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/test/animation_test_common.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/render_pass_test_common.h"
 #include "cc/test/render_pass_test_utils.h"
@@ -32,6 +33,8 @@
       scoped_ptr<SoftwareOutputDevice> software_output_device) {
     output_surface_ = FakeOutputSurface::CreateSoftware(
         software_output_device.Pass());
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
     resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
     renderer_ = SoftwareRenderer::Create(
         this, output_surface_.get(), resource_provider());
@@ -75,6 +78,7 @@
   virtual bool ExternalStencilTestEnabled() const OVERRIDE { return false; }
 
  protected:
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<FakeOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
   scoped_ptr<SoftwareRenderer> renderer_;
diff --git a/cc/resources/image_raster_worker_pool.cc b/cc/resources/image_raster_worker_pool.cc
index 408459c..7e524f6 100644
--- a/cc/resources/image_raster_worker_pool.cc
+++ b/cc/resources/image_raster_worker_pool.cc
@@ -156,6 +156,10 @@
       "state", TracedValue::FromValue(StateAsValue().release()));
 }
 
+GLenum ImageRasterWorkerPool::GetResourceFormat() const {
+  return GL_RGBA;  // Only format supported by CHROMIUM_map_image
+}
+
 void ImageRasterWorkerPool::OnRasterTasksFinished() {
   DCHECK(raster_tasks_pending_);
   raster_tasks_pending_ = false;
diff --git a/cc/resources/image_raster_worker_pool.h b/cc/resources/image_raster_worker_pool.h
index d4f4d74..1816b27 100644
--- a/cc/resources/image_raster_worker_pool.h
+++ b/cc/resources/image_raster_worker_pool.h
@@ -21,6 +21,7 @@
 
   // Overridden from RasterWorkerPool:
   virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE;
+  virtual GLenum GetResourceFormat() const OVERRIDE;
   virtual void OnRasterTasksFinished() OVERRIDE;
   virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE;
 
diff --git a/cc/resources/managed_tile_state.h b/cc/resources/managed_tile_state.h
index c6065f9..113c532 100644
--- a/cc/resources/managed_tile_state.h
+++ b/cc/resources/managed_tile_state.h
@@ -86,12 +86,6 @@
 
       size_t GPUMemoryUsageInBytes() const;
 
-      void SetResourceForTesting(scoped_ptr<ResourcePool::Resource> resource) {
-        resource_ = resource.Pass();
-      }
-      const ResourcePool::Resource* GetResourceForTesting() const {
-        return resource_.get();
-      }
       void SetSolidColorForTesting(SkColor color) {
         set_solid_color(color);
       }
diff --git a/cc/resources/picture_layer_tiling_set_unittest.cc b/cc/resources/picture_layer_tiling_set_unittest.cc
index c47cf4b..db72ade 100644
--- a/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -10,6 +10,7 @@
 #include "cc/resources/resource_pool.h"
 #include "cc/resources/resource_provider.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_picture_layer_tiling_client.h"
 #include "cc/test/fake_tile_manager_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -59,8 +60,11 @@
       float scale_increment,
       float ideal_contents_scale,
       float expected_scale) {
+    FakeOutputSurfaceClient output_surface_client;
     scoped_ptr<FakeOutputSurface> output_surface =
         FakeOutputSurface::Create3d();
+    CHECK(output_surface->BindToClient(&output_surface_client));
+
     scoped_ptr<ResourceProvider> resource_provider =
         ResourceProvider::Create(output_surface.get(), 0);
 
@@ -74,17 +78,8 @@
       PictureLayerTiling* tiling = set.AddTiling(scale);
       tiling->CreateAllTilesForTesting();
       std::vector<Tile*> tiles = tiling->AllTilesForTesting();
-      for (size_t i = 0; i < tiles.size(); ++i) {
-        ManagedTileState::TileVersion& tile_version =
-            tiles[i]->GetTileVersionForTesting(HIGH_QUALITY_NO_LCD_RASTER_MODE);
-        EXPECT_FALSE(tile_version.GetResourceForTesting());
-
-        tile_version.SetResourceForTesting(
-            make_scoped_ptr(new ResourcePool::Resource(
-                resource_provider.get(),
-                gfx::Size(1, 1),
-                resource_provider->best_texture_format())));
-      }
+      client.tile_manager()->InitializeTilesWithResourcesForTesting(
+          tiles, resource_provider.get());
     }
 
     float max_contents_scale = scale;
diff --git a/cc/resources/pixel_buffer_raster_worker_pool.cc b/cc/resources/pixel_buffer_raster_worker_pool.cc
index a03ed81..b0e74c1 100644
--- a/cc/resources/pixel_buffer_raster_worker_pool.cc
+++ b/cc/resources/pixel_buffer_raster_worker_pool.cc
@@ -11,6 +11,10 @@
 #include "cc/resources/resource.h"
 #include "third_party/skia/include/core/SkDevice.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/sys_utils.h"
+#endif
+
 namespace cc {
 
 namespace {
@@ -62,22 +66,6 @@
   DISALLOW_COPY_AND_ASSIGN(PixelBufferWorkerPoolTaskImpl);
 };
 
-// If we raster too fast we become upload bound, and pending
-// uploads consume memory. For maximum upload throughput, we would
-// want to allow for upload_throughput * pipeline_time of pending
-// uploads, after which we are just wasting memory. Since we don't
-// know our upload throughput yet, this just caps our memory usage.
-#if defined(OS_ANDROID)
-// For reference Nexus10 can upload 1MB in about 2.5ms.
-const size_t kMaxBytesUploadedPerMs = (2 * 1024 * 1024) / 5;
-#else
-// For reference Chromebook Pixel can upload 1MB in about 0.5ms.
-const size_t kMaxBytesUploadedPerMs = 1024 * 1024 * 2;
-#endif
-
-// Assuming a two frame deep pipeline.
-const size_t kMaxPendingUploadBytes = 16 * 2 * kMaxBytesUploadedPerMs;
-
 const int kCheckForCompletedRasterTasksDelayMs = 6;
 
 const size_t kMaxScheduledRasterTasks = 48;
@@ -116,6 +104,25 @@
       should_notify_client_if_no_tasks_are_pending_(false),
       should_notify_client_if_no_tasks_required_for_activation_are_pending_(
           false) {
+// If we raster too fast we become upload bound, and pending
+// uploads consume memory. For maximum upload throughput, we would
+// want to allow for upload_throughput * pipeline_time of pending
+// uploads, after which we are just wasting memory. Since we don't
+// know our upload throughput yet, this just caps our memory usage.
+#if defined(OS_ANDROID)
+  size_t divider = 1;
+  if (base::android::SysUtils::IsLowEndDevice())
+    divider = 3;
+
+  // For reference Nexus10 can upload 1MB in about 2.5ms.
+  const size_t kMaxBytesUploadedPerMs = (2 * 1024 * 1024) / (5 * divider);
+#else
+  // For reference Chromebook Pixel can upload 1MB in about 0.5ms.
+  const size_t kMaxBytesUploadedPerMs = 1024 * 1024 * 2;
+#endif
+
+  // Assuming a two frame deep pipeline.
+  max_bytes_pending_upload_ = 16 * 2 * kMaxBytesUploadedPerMs;
 }
 
 PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
@@ -236,6 +243,10 @@
       "state", TracedValue::FromValue(StateAsValue().release()));
 }
 
+GLenum PixelBufferRasterWorkerPool::GetResourceFormat() const {
+  return resource_provider()->best_texture_format();
+}
+
 void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
   TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::CheckForCompletedTasks");
 
@@ -470,7 +481,7 @@
     // All raster tasks need to be throttled by bytes of pending uploads.
     size_t new_bytes_pending_upload = bytes_pending_upload;
     new_bytes_pending_upload += task->resource()->bytes();
-    if (new_bytes_pending_upload > kMaxPendingUploadBytes)
+    if (new_bytes_pending_upload > max_bytes_pending_upload_)
       break;
 
     internal::WorkerPoolTask* pixel_buffer_task = pixel_buffer_it->second.get();
@@ -590,6 +601,11 @@
     scoped_refptr<internal::RasterWorkerPoolTask> task,
     bool was_canceled,
     bool needs_upload) {
+  TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc"),
+               "PixelBufferRasterWorkerPool::OnRasterTaskCompleted",
+               "was_canceled", was_canceled,
+               "needs_upload", needs_upload);
+
   DCHECK(pixel_buffer_tasks_.find(task.get()) != pixel_buffer_tasks_.end());
 
   // Balanced with MapPixelBuffer() call in ScheduleMoreTasks().
@@ -673,7 +689,7 @@
   scoped_ptr<base::DictionaryValue> throttle_state(new base::DictionaryValue);
 
   throttle_state->SetInteger("bytes_available_for_upload",
-                             kMaxPendingUploadBytes - bytes_pending_upload_);
+                             max_bytes_pending_upload_ - bytes_pending_upload_);
   throttle_state->SetInteger("bytes_pending_upload", bytes_pending_upload_);
   throttle_state->SetInteger("scheduled_raster_task_count",
                              scheduled_raster_task_count_);
diff --git a/cc/resources/pixel_buffer_raster_worker_pool.h b/cc/resources/pixel_buffer_raster_worker_pool.h
index d9613f7..94a2f95 100644
--- a/cc/resources/pixel_buffer_raster_worker_pool.h
+++ b/cc/resources/pixel_buffer_raster_worker_pool.h
@@ -29,6 +29,7 @@
 
   // Overridden from RasterWorkerPool:
   virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE;
+  virtual GLenum GetResourceFormat() const OVERRIDE;
   virtual void OnRasterTasksFinished() OVERRIDE;
   virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE;
 
@@ -67,6 +68,7 @@
 
   size_t scheduled_raster_task_count_;
   size_t bytes_pending_upload_;
+  size_t max_bytes_pending_upload_;
   bool has_performed_uploads_since_last_flush_;
   base::CancelableClosure check_for_completed_raster_tasks_callback_;
   bool check_for_completed_raster_tasks_pending_;
diff --git a/cc/resources/prioritized_resource_unittest.cc b/cc/resources/prioritized_resource_unittest.cc
index 92ce9ff..91b1c2e 100644
--- a/cc/resources/prioritized_resource_unittest.cc
+++ b/cc/resources/prioritized_resource_unittest.cc
@@ -7,6 +7,7 @@
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/resource.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_proxy.h"
 #include "cc/test/tiled_layer_test_common.h"
 #include "cc/trees/single_thread_proxy.h"  // For DebugScopedSetImplThread
@@ -19,8 +20,9 @@
   PrioritizedResourceTest()
       : texture_size_(256, 256),
         texture_format_(GL_RGBA),
-        output_surface_(CreateFakeOutputSurface()) {
+        output_surface_(FakeOutputSurface::Create3d()) {
     DebugScopedSetImplThread impl_thread(&proxy_);
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
     resource_provider_ = cc::ResourceProvider::Create(output_surface_.get(), 0);
   }
 
@@ -92,6 +94,7 @@
   FakeProxy proxy_;
   const gfx::Size texture_size_;
   const GLenum texture_format_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<OutputSurface> output_surface_;
   scoped_ptr<cc::ResourceProvider> resource_provider_;
 };
diff --git a/cc/resources/prioritized_tile_set.cc b/cc/resources/prioritized_tile_set.cc
index 5b40945..d1cc5b7 100644
--- a/cc/resources/prioritized_tile_set.cc
+++ b/cc/resources/prioritized_tile_set.cc
@@ -13,8 +13,8 @@
 
 class BinComparator {
  public:
-  bool operator()(const scoped_refptr<Tile>& a,
-                  const scoped_refptr<Tile>& b) const {
+  bool operator()(const Tile* a,
+                  const Tile* b) const {
     const ManagedTileState& ams = a->managed_state();
     const ManagedTileState& bms = b->managed_state();
 
@@ -46,7 +46,7 @@
 
 namespace {
 
-typedef std::vector<scoped_refptr<Tile> > TileVector;
+typedef std::vector<Tile*> TileVector;
 
 void SortBinTiles(ManagedTileBin bin, TileVector* tiles) {
   switch (bin) {
@@ -67,37 +67,52 @@
 
 }  // namespace
 
-PrioritizedTileSet::PrioritizedTileSet() {}
+PrioritizedTileSet::PrioritizedTileSet() {
+  for (int bin = 0; bin < NUM_BINS; ++bin)
+    bin_sorted_[bin] = true;
+}
 
 PrioritizedTileSet::~PrioritizedTileSet() {}
 
 void PrioritizedTileSet::InsertTile(Tile* tile, ManagedTileBin bin) {
-  tiles_[bin].push_back(make_scoped_refptr(tile));
+  tiles_[bin].push_back(tile);
+  bin_sorted_[bin] = false;
 }
 
 void PrioritizedTileSet::Clear() {
-  for (int bin = 0; bin < NUM_BINS; ++bin)
+  for (int bin = 0; bin < NUM_BINS; ++bin) {
     tiles_[bin].clear();
+    bin_sorted_[bin] = true;
+  }
 }
 
-void PrioritizedTileSet::Sort() {
-  for (int bin = 0; bin < NUM_BINS; ++bin)
-    SortBinTiles(static_cast<ManagedTileBin>(bin), &tiles_[bin]);
+void PrioritizedTileSet::SortBinIfNeeded(ManagedTileBin bin) {
+  if (!bin_sorted_[bin]) {
+    SortBinTiles(bin, &tiles_[bin]);
+    bin_sorted_[bin] = true;
+  }
 }
 
-PrioritizedTileSet::PriorityIterator::PriorityIterator(
-    PrioritizedTileSet* tile_set)
+PrioritizedTileSet::Iterator::Iterator(
+    PrioritizedTileSet* tile_set, bool use_priority_ordering)
     : tile_set_(tile_set),
       current_bin_(NOW_AND_READY_TO_DRAW_BIN),
-      iterator_(tile_set->tiles_[current_bin_].begin()) {
+      use_priority_ordering_(use_priority_ordering) {
+  if (use_priority_ordering_)
+    tile_set_->SortBinIfNeeded(current_bin_);
+  iterator_ = tile_set->tiles_[current_bin_].begin();
   if (iterator_ == tile_set_->tiles_[current_bin_].end())
     AdvanceList();
 }
 
-PrioritizedTileSet::PriorityIterator::~PriorityIterator() {}
+PrioritizedTileSet::Iterator::~Iterator() {}
 
-PrioritizedTileSet::PriorityIterator&
-PrioritizedTileSet::PriorityIterator::operator++() {
+void PrioritizedTileSet::Iterator::DisablePriorityOrdering() {
+  use_priority_ordering_ = false;
+}
+
+PrioritizedTileSet::Iterator&
+PrioritizedTileSet::Iterator::operator++() {
   // We can't increment past the end of the tiles.
   DCHECK(iterator_ != tile_set_->tiles_[current_bin_].end());
 
@@ -107,16 +122,20 @@
   return *this;
 }
 
-Tile* PrioritizedTileSet::PriorityIterator::operator*() {
+Tile* PrioritizedTileSet::Iterator::operator*() {
   DCHECK(iterator_ != tile_set_->tiles_[current_bin_].end());
-  return iterator_->get();
+  return *iterator_;
 }
 
-void PrioritizedTileSet::PriorityIterator::AdvanceList() {
+void PrioritizedTileSet::Iterator::AdvanceList() {
   DCHECK(iterator_ == tile_set_->tiles_[current_bin_].end());
 
   while (current_bin_ != NEVER_BIN) {
     current_bin_ = static_cast<ManagedTileBin>(current_bin_ + 1);
+
+    if (use_priority_ordering_)
+      tile_set_->SortBinIfNeeded(current_bin_);
+
     iterator_ = tile_set_->tiles_[current_bin_].begin();
     if (iterator_ != tile_set_->tiles_[current_bin_].end())
       break;
diff --git a/cc/resources/prioritized_tile_set.h b/cc/resources/prioritized_tile_set.h
index fe1b2a0..15d0e4f 100644
--- a/cc/resources/prioritized_tile_set.h
+++ b/cc/resources/prioritized_tile_set.h
@@ -7,8 +7,6 @@
 
 #include <vector>
 
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
 #include "cc/resources/managed_tile_state.h"
 
@@ -22,14 +20,16 @@
 
   void InsertTile(Tile* tile, ManagedTileBin bin);
   void Clear();
-  void Sort();
 
-  class CC_EXPORT PriorityIterator {
+  class CC_EXPORT Iterator {
    public:
-    explicit PriorityIterator(PrioritizedTileSet* set);
-    ~PriorityIterator();
+    Iterator(PrioritizedTileSet* set, bool use_priority_ordering);
 
-    PriorityIterator& operator++();
+    ~Iterator();
+
+    void DisablePriorityOrdering();
+
+    Iterator& operator++();
     Tile* operator->() { return *(*this); }
     Tile* operator*();
     operator bool() const {
@@ -41,14 +41,17 @@
 
     PrioritizedTileSet* tile_set_;
     ManagedTileBin current_bin_;
-    std::vector<scoped_refptr<Tile> >::iterator iterator_;
+    std::vector<Tile*>::iterator iterator_;
+    bool use_priority_ordering_;
   };
 
  private:
-  friend class PriorityIterator;
+  friend class Iterator;
 
-  typedef scoped_refptr<Tile> TileRef;
-  std::vector<TileRef> tiles_[NUM_BINS];
+  void SortBinIfNeeded(ManagedTileBin bin);
+
+  std::vector<Tile*> tiles_[NUM_BINS];
+  bool bin_sorted_[NUM_BINS];
 };
 
 }  // namespace cc
diff --git a/cc/resources/prioritized_tile_set_unittest.cc b/cc/resources/prioritized_tile_set_unittest.cc
index 645fa04..9325691 100644
--- a/cc/resources/prioritized_tile_set_unittest.cc
+++ b/cc/resources/prioritized_tile_set_unittest.cc
@@ -9,6 +9,7 @@
 #include "cc/resources/prioritized_tile_set.h"
 #include "cc/resources/tile.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/fake_tile_manager.h"
 #include "cc/test/fake_tile_manager_client.h"
@@ -54,12 +55,16 @@
 
 class PrioritizedTileSetTest : public testing::Test {
  public:
-  PrioritizedTileSetTest()
-      : output_surface_(FakeOutputSurface::Create3d()),
-        resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)),
-        tile_manager_(new FakeTileManager(&tile_manager_client_,
-                                          resource_provider_.get())),
-        picture_pile_(FakePicturePileImpl::CreatePile()) {}
+  PrioritizedTileSetTest() {
+    output_surface_ = FakeOutputSurface::Create3d().Pass();
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+    resource_provider_ = ResourceProvider::Create(output_surface_.get(),
+                                                  0).Pass();
+    tile_manager_.reset(new FakeTileManager(&tile_manager_client_,
+                                            resource_provider_.get()));
+    picture_pile_ = FakePicturePileImpl::CreatePile();
+  }
 
   scoped_refptr<Tile> CreateTile() {
     return make_scoped_refptr(new Tile(tile_manager_.get(),
@@ -74,19 +79,22 @@
   }
 
  private:
-  FakeTileManagerClient tile_manager_client_;
   LayerTreeSettings settings_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<FakeOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
+  FakeTileManagerClient tile_manager_client_;
   scoped_ptr<FakeTileManager> tile_manager_;
   scoped_refptr<FakePicturePileImpl> picture_pile_;
 };
 
 TEST_F(PrioritizedTileSetTest, EmptyIterator) {
-  PrioritizedTileSet set;
-  set.Sort();
+  // Creating an iterator to an empty set should work (but create iterator that
+  // isn't valid).
 
-  PrioritizedTileSet::PriorityIterator it(&set);
+  PrioritizedTileSet set;
+
+  PrioritizedTileSet::Iterator it(&set, true);
   EXPECT_FALSE(it);
 }
 
@@ -94,9 +102,8 @@
   PrioritizedTileSet set;
   scoped_refptr<Tile> tile = CreateTile();
   set.InsertTile(tile, NOW_BIN);
-  set.Sort();
 
-  PrioritizedTileSet::PriorityIterator it(&set);
+  PrioritizedTileSet::Iterator it(&set, true);
   EXPECT_TRUE(it);
   EXPECT_TRUE(*it == tile.get());
   ++it;
@@ -104,6 +111,8 @@
 }
 
 TEST_F(PrioritizedTileSetTest, NowAndReadyToDrawBin) {
+  // Ensure that tiles in NOW_AND_READY_TO_DRAW_BIN aren't sorted.
+
   PrioritizedTileSet set;
   TilePriority priorities[4] = {
       TilePriorityForEventualBin(),
@@ -122,11 +131,9 @@
     }
   }
 
-  set.Sort();
-
   // Tiles should appear in the same order as inserted.
   int i = 0;
-  for (PrioritizedTileSet::PriorityIterator it(&set);
+  for (PrioritizedTileSet::Iterator it(&set, true);
        it;
        ++it) {
     EXPECT_TRUE(*it == tiles[i].get());
@@ -136,6 +143,8 @@
 }
 
 TEST_F(PrioritizedTileSetTest, NowBin) {
+  // Ensure that tiles in NOW_BIN are sorted according to BinComparator.
+
   PrioritizedTileSet set;
   TilePriority priorities[4] = {
       TilePriorityForEventualBin(),
@@ -154,13 +163,11 @@
     }
   }
 
-  set.Sort();
-
   // Tiles should appear in BinComparator order.
   std::sort(tiles.begin(), tiles.end(), BinComparator());
 
   int i = 0;
-  for (PrioritizedTileSet::PriorityIterator it(&set);
+  for (PrioritizedTileSet::Iterator it(&set, true);
        it;
        ++it) {
     EXPECT_TRUE(*it == tiles[i].get());
@@ -170,6 +177,8 @@
 }
 
 TEST_F(PrioritizedTileSetTest, SoonBin) {
+  // Ensure that tiles in SOON_BIN are sorted according to BinComparator.
+
   PrioritizedTileSet set;
   TilePriority priorities[4] = {
       TilePriorityForEventualBin(),
@@ -188,13 +197,43 @@
     }
   }
 
-  set.Sort();
-
   // Tiles should appear in BinComparator order.
   std::sort(tiles.begin(), tiles.end(), BinComparator());
 
   int i = 0;
-  for (PrioritizedTileSet::PriorityIterator it(&set);
+  for (PrioritizedTileSet::Iterator it(&set, true);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, SoonBinNoPriority) {
+  // Ensure that when not using priority iterator, SOON_BIN tiles
+  // are not sorted.
+
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, SOON_BIN);
+    }
+  }
+
+  int i = 0;
+  for (PrioritizedTileSet::Iterator it(&set, false);
        it;
        ++it) {
     EXPECT_TRUE(*it == tiles[i].get());
@@ -204,6 +243,8 @@
 }
 
 TEST_F(PrioritizedTileSetTest, EventuallyAndActiveBin) {
+  // Ensure that EVENTUALLY_AND_ACTIVE_BIN tiles are sorted.
+
   PrioritizedTileSet set;
   TilePriority priorities[4] = {
       TilePriorityForEventualBin(),
@@ -222,13 +263,11 @@
     }
   }
 
-  set.Sort();
-
   // Tiles should appear in BinComparator order.
   std::sort(tiles.begin(), tiles.end(), BinComparator());
 
   int i = 0;
-  for (PrioritizedTileSet::PriorityIterator it(&set);
+  for (PrioritizedTileSet::Iterator it(&set, true);
        it;
        ++it) {
     EXPECT_TRUE(*it == tiles[i].get());
@@ -238,6 +277,8 @@
 }
 
 TEST_F(PrioritizedTileSetTest, EventuallyBin) {
+  // Ensure that EVENTUALLY_BIN tiles are sorted.
+
   PrioritizedTileSet set;
   TilePriority priorities[4] = {
       TilePriorityForEventualBin(),
@@ -256,13 +297,11 @@
     }
   }
 
-  set.Sort();
-
   // Tiles should appear in BinComparator order.
   std::sort(tiles.begin(), tiles.end(), BinComparator());
 
   int i = 0;
-  for (PrioritizedTileSet::PriorityIterator it(&set);
+  for (PrioritizedTileSet::Iterator it(&set, true);
        it;
        ++it) {
     EXPECT_TRUE(*it == tiles[i].get());
@@ -272,6 +311,8 @@
 }
 
 TEST_F(PrioritizedTileSetTest, NeverAndActiveBin) {
+  // Ensure that NEVER_AND_ACTIVE_BIN tiles are sorted.
+
   PrioritizedTileSet set;
   TilePriority priorities[4] = {
       TilePriorityForEventualBin(),
@@ -290,13 +331,11 @@
     }
   }
 
-  set.Sort();
-
   // Tiles should appear in BinComparator order.
   std::sort(tiles.begin(), tiles.end(), BinComparator());
 
   int i = 0;
-  for (PrioritizedTileSet::PriorityIterator it(&set);
+  for (PrioritizedTileSet::Iterator it(&set, true);
        it;
        ++it) {
     EXPECT_TRUE(*it == tiles[i].get());
@@ -306,6 +345,9 @@
 }
 
 TEST_F(PrioritizedTileSetTest, NeverBin) {
+  // Ensure that NEVER_BIN tiles are sorted, since they might not
+  // be NEVER_BIN on a LOW_PRIORITY tree.
+
   PrioritizedTileSet set;
   TilePriority priorities[4] = {
       TilePriorityForEventualBin(),
@@ -324,13 +366,11 @@
     }
   }
 
-  set.Sort();
-
   // Tiles should appear in BinComparator order.
   std::sort(tiles.begin(), tiles.end(), BinComparator());
 
   int i = 0;
-  for (PrioritizedTileSet::PriorityIterator it(&set);
+  for (PrioritizedTileSet::Iterator it(&set, true);
        it;
        ++it) {
     EXPECT_TRUE(*it == tiles[i].get());
@@ -340,6 +380,9 @@
 }
 
 TEST_F(PrioritizedTileSetTest, TilesForEachBin) {
+  // Aggregate test with one tile for each of the bins, which
+  // should appear in order of the bins.
+
   scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile();
   scoped_refptr<Tile> now_bin = CreateTile();
   scoped_refptr<Tile> soon_bin = CreateTile();
@@ -357,10 +400,8 @@
   set.InsertTile(never_bin, NEVER_BIN);
   set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN);
 
-  set.Sort();
-
   // Tiles should appear in order.
-  PrioritizedTileSet::PriorityIterator it(&set);
+  PrioritizedTileSet::Iterator it(&set, true);
   EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get());
   ++it;
   EXPECT_TRUE(*it == now_bin.get());
@@ -378,7 +419,229 @@
   EXPECT_FALSE(it);
 }
 
+TEST_F(PrioritizedTileSetTest, ManyTilesForEachBin) {
+  // Aggregate test with many tiles in each of the bins of various
+  // priorities. Ensure that they are all returned in a sorted order.
+
+  std::vector<scoped_refptr<Tile> > now_and_ready_to_draw_bins;
+  std::vector<scoped_refptr<Tile> > now_bins;
+  std::vector<scoped_refptr<Tile> > soon_bins;
+  std::vector<scoped_refptr<Tile> > eventually_and_active_bins;
+  std::vector<scoped_refptr<Tile> > eventually_bins;
+  std::vector<scoped_refptr<Tile> > never_bins;
+  std::vector<scoped_refptr<Tile> > never_and_active_bins;
+
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  PrioritizedTileSet set;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+
+      now_and_ready_to_draw_bins.push_back(tile);
+      now_bins.push_back(tile);
+      soon_bins.push_back(tile);
+      eventually_and_active_bins.push_back(tile);
+      eventually_bins.push_back(tile);
+      never_bins.push_back(tile);
+      never_and_active_bins.push_back(tile);
+
+      set.InsertTile(tile, NOW_AND_READY_TO_DRAW_BIN);
+      set.InsertTile(tile, NOW_BIN);
+      set.InsertTile(tile, SOON_BIN);
+      set.InsertTile(tile, EVENTUALLY_AND_ACTIVE_BIN);
+      set.InsertTile(tile, EVENTUALLY_BIN);
+      set.InsertTile(tile, NEVER_BIN);
+      set.InsertTile(tile, NEVER_AND_ACTIVE_BIN);
+    }
+  }
+
+  PrioritizedTileSet::Iterator it(&set, true);
+  std::vector<scoped_refptr<Tile> >::iterator vector_it;
+
+  // Now and ready are not sorted.
+  for (vector_it = now_and_ready_to_draw_bins.begin();
+       vector_it != now_and_ready_to_draw_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Now bins are sorted.
+  std::sort(now_bins.begin(), now_bins.end(), BinComparator());
+  for (vector_it = now_bins.begin(); vector_it != now_bins.end(); ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Soon bins are sorted.
+  std::sort(soon_bins.begin(), soon_bins.end(), BinComparator());
+  for (vector_it = soon_bins.begin(); vector_it != soon_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Eventually and active bins are sorted.
+  std::sort(eventually_and_active_bins.begin(),
+            eventually_and_active_bins.end(),
+            BinComparator());
+  for (vector_it = eventually_and_active_bins.begin();
+       vector_it != eventually_and_active_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Eventually bins are sorted.
+  std::sort(eventually_bins.begin(), eventually_bins.end(), BinComparator());
+  for (vector_it = eventually_bins.begin(); vector_it != eventually_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Never and active bins are sorted.
+  std::sort(never_and_active_bins.begin(),
+            never_and_active_bins.end(),
+            BinComparator());
+  for (vector_it = never_and_active_bins.begin();
+       vector_it != never_and_active_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Never bins are sorted.
+  std::sort(never_bins.begin(), never_bins.end(), BinComparator());
+  for (vector_it = never_bins.begin(); vector_it != never_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  EXPECT_FALSE(it);
+}
+
+TEST_F(PrioritizedTileSetTest, ManyTilesForEachBinDisablePriority) {
+  // Aggregate test with many tiles for each of the bins. Tiles should
+  // appear in order, until DisablePriorityOrdering is called. After that
+  // tiles should appear in the order they were inserted.
+
+  std::vector<scoped_refptr<Tile> > now_and_ready_to_draw_bins;
+  std::vector<scoped_refptr<Tile> > now_bins;
+  std::vector<scoped_refptr<Tile> > soon_bins;
+  std::vector<scoped_refptr<Tile> > eventually_and_active_bins;
+  std::vector<scoped_refptr<Tile> > eventually_bins;
+  std::vector<scoped_refptr<Tile> > never_bins;
+  std::vector<scoped_refptr<Tile> > never_and_active_bins;
+
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  PrioritizedTileSet set;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+
+      now_and_ready_to_draw_bins.push_back(tile);
+      now_bins.push_back(tile);
+      soon_bins.push_back(tile);
+      eventually_and_active_bins.push_back(tile);
+      eventually_bins.push_back(tile);
+      never_bins.push_back(tile);
+      never_and_active_bins.push_back(tile);
+
+      set.InsertTile(tile, NOW_AND_READY_TO_DRAW_BIN);
+      set.InsertTile(tile, NOW_BIN);
+      set.InsertTile(tile, SOON_BIN);
+      set.InsertTile(tile, EVENTUALLY_AND_ACTIVE_BIN);
+      set.InsertTile(tile, EVENTUALLY_BIN);
+      set.InsertTile(tile, NEVER_BIN);
+      set.InsertTile(tile, NEVER_AND_ACTIVE_BIN);
+    }
+  }
+
+  PrioritizedTileSet::Iterator it(&set, true);
+  std::vector<scoped_refptr<Tile> >::iterator vector_it;
+
+  // Now and ready are not sorted.
+  for (vector_it = now_and_ready_to_draw_bins.begin();
+       vector_it != now_and_ready_to_draw_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Now bins are sorted.
+  std::sort(now_bins.begin(), now_bins.end(), BinComparator());
+  for (vector_it = now_bins.begin(); vector_it != now_bins.end(); ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Soon bins are sorted.
+  std::sort(soon_bins.begin(), soon_bins.end(), BinComparator());
+  for (vector_it = soon_bins.begin(); vector_it != soon_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // After we disable priority ordering, we already have sorted the next vector.
+  it.DisablePriorityOrdering();
+
+  // Eventually and active bins are sorted.
+  std::sort(eventually_and_active_bins.begin(),
+            eventually_and_active_bins.end(),
+            BinComparator());
+  for (vector_it = eventually_and_active_bins.begin();
+       vector_it != eventually_and_active_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Eventually bins are not sorted.
+  for (vector_it = eventually_bins.begin(); vector_it != eventually_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Never and active bins are not sorted.
+  for (vector_it = never_and_active_bins.begin();
+       vector_it != never_and_active_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  // Never bins are not sorted.
+  for (vector_it = never_bins.begin(); vector_it != never_bins.end();
+       ++vector_it) {
+    EXPECT_TRUE(*vector_it == *it);
+    ++it;
+  }
+
+  EXPECT_FALSE(it);
+}
+
 TEST_F(PrioritizedTileSetTest, TilesForFirstAndLastBins) {
+  // Make sure that if we have empty lists between two non-empty lists,
+  // we just get two tiles from the iterator.
+
   scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile();
   scoped_refptr<Tile> never_bin = CreateTile();
 
@@ -386,10 +649,8 @@
   set.InsertTile(never_bin, NEVER_BIN);
   set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN);
 
-  set.Sort();
-
   // Only two tiles should appear and they should appear in order.
-  PrioritizedTileSet::PriorityIterator it(&set);
+  PrioritizedTileSet::Iterator it(&set, true);
   EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get());
   ++it;
   EXPECT_TRUE(*it == never_bin.get());
@@ -398,6 +659,8 @@
 }
 
 TEST_F(PrioritizedTileSetTest, MultipleIterators) {
+  // Ensure that multiple iterators don't interfere with each other.
+
   scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile();
   scoped_refptr<Tile> now_bin = CreateTile();
   scoped_refptr<Tile> soon_bin = CreateTile();
@@ -411,10 +674,8 @@
   set.InsertTile(never_bin, NEVER_BIN);
   set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN);
 
-  set.Sort();
-
   // Tiles should appear in order.
-  PrioritizedTileSet::PriorityIterator it(&set);
+  PrioritizedTileSet::Iterator it(&set, true);
   EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get());
   ++it;
   EXPECT_TRUE(*it == now_bin.get());
@@ -428,7 +689,7 @@
   EXPECT_FALSE(it);
 
   // Creating multiple iterators shouldn't affect old iterators.
-  PrioritizedTileSet::PriorityIterator second_it(&set);
+  PrioritizedTileSet::Iterator second_it(&set, true);
   EXPECT_TRUE(second_it);
   EXPECT_FALSE(it);
 
@@ -438,7 +699,7 @@
   EXPECT_TRUE(second_it);
   EXPECT_FALSE(it);
 
-  PrioritizedTileSet::PriorityIterator third_it(&set);
+  PrioritizedTileSet::Iterator third_it(&set, true);
   EXPECT_TRUE(third_it);
   ++second_it;
   ++second_it;
@@ -461,7 +722,7 @@
 
   set.Clear();
 
-  PrioritizedTileSet::PriorityIterator empty_it(&set);
+  PrioritizedTileSet::Iterator empty_it(&set, true);
   EXPECT_FALSE(empty_it);
 }
 
diff --git a/cc/resources/raster_worker_pool.h b/cc/resources/raster_worker_pool.h
index d0e1e7c..8c4b493 100644
--- a/cc/resources/raster_worker_pool.h
+++ b/cc/resources/raster_worker_pool.h
@@ -13,6 +13,7 @@
 #include "cc/resources/raster_mode.h"
 #include "cc/resources/tile_priority.h"
 #include "cc/resources/worker_pool.h"
+#include "third_party/khronos/GLES2/gl2.h"
 
 class SkDevice;
 
@@ -183,6 +184,9 @@
   // even if they later get canceled by another call to ScheduleTasks().
   virtual void ScheduleTasks(RasterTask::Queue* queue) = 0;
 
+  // Returns the format that needs to be used for raster task resources.
+  virtual GLenum GetResourceFormat() const = 0;
+
   // TODO(vmpstr): Figure out an elegant way to not pass this many parameters.
   static RasterTask CreateRasterTask(
       const Resource* resource,
diff --git a/cc/resources/raster_worker_pool_perftest.cc b/cc/resources/raster_worker_pool_perftest.cc
index a4a258b..9215950 100644
--- a/cc/resources/raster_worker_pool_perftest.cc
+++ b/cc/resources/raster_worker_pool_perftest.cc
@@ -38,6 +38,10 @@
   virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {
     NOTREACHED();
   }
+  virtual GLenum GetResourceFormat() const OVERRIDE {
+    NOTREACHED();
+    return GL_RGBA;
+  }
   virtual void OnRasterTasksFinished() OVERRIDE {
     NOTREACHED();
   }
diff --git a/cc/resources/raster_worker_pool_unittest.cc b/cc/resources/raster_worker_pool_unittest.cc
index 3d27c41..39a8a48 100644
--- a/cc/resources/raster_worker_pool_unittest.cc
+++ b/cc/resources/raster_worker_pool_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <vector>
 
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/resources/image_raster_worker_pool.h"
 #include "cc/resources/picture_pile.h"
 #include "cc/resources/picture_pile_impl.h"
@@ -13,6 +14,7 @@
 #include "cc/resources/resource_provider.h"
 #include "cc/resources/scoped_resource.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
@@ -55,12 +57,15 @@
                              public RasterWorkerPoolClient  {
  public:
   RasterWorkerPoolTest()
-      : output_surface_(FakeOutputSurface::Create3d()),
-        resource_provider_(
-            ResourceProvider::Create(output_surface_.get(), 0)),
+      : context_provider_(TestContextProvider::Create()),
         check_interval_milliseconds_(1),
         timeout_seconds_(5),
         timed_out_(false) {
+    output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+    resource_provider_ = ResourceProvider::Create(output_surface_.get(),
+                                                  0).Pass();
   }
   virtual ~RasterWorkerPoolTest() {
     resource_provider_.reset();
@@ -190,6 +195,8 @@
   }
 
  protected:
+  scoped_refptr<TestContextProvider> context_provider_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<FakeOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
   scoped_ptr<RasterWorkerPool> raster_worker_pool_;
@@ -259,8 +266,7 @@
 
   // Overridden from RasterWorkerPoolTest:
   virtual void BeginTest() OVERRIDE {
-    TestWebGraphicsContext3D* context3d =
-        static_cast<TestWebGraphicsContext3D*>(output_surface_->context3d());
+    TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
     context3d->set_times_map_image_chromium_succeeds(0);
     context3d->set_times_map_buffer_chromium_succeeds(0);
     AppendTask(0u);
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 5835db5..2d455a0 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -31,19 +31,20 @@
     : resource_provider_(resource_provider),
       max_memory_usage_bytes_(0),
       max_unused_memory_usage_bytes_(0),
+      max_resource_count_(0),
       memory_usage_bytes_(0),
       unused_memory_usage_bytes_(0),
-      num_resources_limit_(0) {
+      resource_count_(0) {
 }
 
 ResourcePool::~ResourcePool() {
-  SetMemoryUsageLimits(0, 0, 0);
+  SetResourceUsageLimits(0, 0, 0);
 }
 
 scoped_ptr<ResourcePool::Resource> ResourcePool::AcquireResource(
     gfx::Size size, GLenum format) {
-  for (ResourceList::iterator it = resources_.begin();
-       it != resources_.end(); ++it) {
+  for (ResourceList::iterator it = unused_resources_.begin();
+       it != unused_resources_.end(); ++it) {
     Resource* resource = *it;
 
     // TODO(epenner): It would be nice to DCHECK that this
@@ -57,14 +58,13 @@
     if (resource->format() != format)
       continue;
 
-    resources_.erase(it);
+    unused_resources_.erase(it);
     unused_memory_usage_bytes_ -= resource->bytes();
     return make_scoped_ptr(resource);
   }
 
   // Create new resource.
-  Resource* resource = new Resource(
-      resource_provider_, size, format);
+  Resource* resource = new Resource(resource_provider_, size, format);
 
   // Extend all read locks on all resources until the resource is
   // finished being used, such that we know when resources are
@@ -72,44 +72,56 @@
   resource_provider_->EnableReadLockFences(resource->id(), true);
 
   memory_usage_bytes_ += resource->bytes();
+  ++resource_count_;
   return make_scoped_ptr(resource);
 }
 
 void ResourcePool::ReleaseResource(
     scoped_ptr<ResourcePool::Resource> resource) {
-  if (MemoryUsageTooHigh()) {
+  if (ResourceUsageTooHigh()) {
     memory_usage_bytes_ -= resource->bytes();
+    --resource_count_;
     return;
   }
 
   unused_memory_usage_bytes_ += resource->bytes();
-  resources_.push_back(resource.release());
+  unused_resources_.push_back(resource.release());
 }
 
-void ResourcePool::SetMemoryUsageLimits(
+void ResourcePool::SetResourceUsageLimits(
     size_t max_memory_usage_bytes,
     size_t max_unused_memory_usage_bytes,
-    size_t num_resources_limit) {
+    size_t max_resource_count) {
   max_memory_usage_bytes_ = max_memory_usage_bytes;
   max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes;
-  num_resources_limit_ = num_resources_limit;
+  max_resource_count_ = max_resource_count;
 
-  while (!resources_.empty()) {
-    if (!MemoryUsageTooHigh())
+  ReduceResourceUsage();
+}
+
+void ResourcePool::ReduceResourceUsage() {
+  while (!unused_resources_.empty()) {
+    if (!ResourceUsageTooHigh())
       break;
 
-    // MRU eviction pattern as least recently used is less likely to
-    // be blocked by read lock fence.
-    Resource* resource = resources_.back();
-    resources_.pop_back();
+    // LRU eviction pattern. Most recently used might be blocked by
+    // a read lock fence but it's still better to evict the least
+    // recently used as it prevents a resource that is hard to reuse
+    // because of unique size from being kept around. Resources that
+    // can't be locked for write might also not be truly free-able.
+    // We can free the resource here but it doesn't mean that the
+    // memory is necessarily returned to the OS.
+    Resource* resource = unused_resources_.front();
+    unused_resources_.pop_front();
     memory_usage_bytes_ -= resource->bytes();
     unused_memory_usage_bytes_ -= resource->bytes();
+    --resource_count_;
     delete resource;
   }
 }
 
-bool ResourcePool::MemoryUsageTooHigh() {
-  if (resources_.size() > num_resources_limit_)
+bool ResourcePool::ResourceUsageTooHigh() {
+  if (resource_count_ > max_resource_count_)
     return true;
   if (memory_usage_bytes_ > max_memory_usage_bytes_)
     return true;
diff --git a/cc/resources/resource_pool.h b/cc/resources/resource_pool.h
index 2304a50..771650e 100644
--- a/cc/resources/resource_pool.h
+++ b/cc/resources/resource_pool.h
@@ -40,30 +40,38 @@
                                                      GLenum format);
   void ReleaseResource(scoped_ptr<ResourcePool::Resource>);
 
-  void SetMemoryUsageLimits(size_t max_memory_usage_bytes,
-                            size_t max_unused_memory_usage_bytes,
-                            size_t num_resources_limit);
+  void SetResourceUsageLimits(size_t max_memory_usage_bytes,
+                              size_t max_unused_memory_usage_bytes,
+                              size_t max_resource_count);
 
+  void ReduceResourceUsage();
+
+  size_t total_memory_usage_bytes() const {
+    return memory_usage_bytes_;
+  }
   size_t acquired_memory_usage_bytes() const {
     return memory_usage_bytes_ - unused_memory_usage_bytes_;
   }
-  size_t NumResources() const { return resources_.size(); }
+  size_t acquired_resource_count() const {
+    return resource_count_ - unused_resources_.size();
+  }
 
  protected:
   explicit ResourcePool(ResourceProvider* resource_provider);
 
-  bool MemoryUsageTooHigh();
+  bool ResourceUsageTooHigh();
 
  private:
   ResourceProvider* resource_provider_;
   size_t max_memory_usage_bytes_;
   size_t max_unused_memory_usage_bytes_;
+  size_t max_resource_count_;
   size_t memory_usage_bytes_;
   size_t unused_memory_usage_bytes_;
-  size_t num_resources_limit_;
+  size_t resource_count_;
 
   typedef std::list<Resource*> ResourceList;
-  ResourceList resources_;
+  ResourceList unused_resources_;
 
   DISALLOW_COPY_AND_ASSIGN(ResourcePool);
 };
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 11eaab0..1911d86 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #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/transferable_resource.h"
 #include "cc/scheduler/texture_uploader.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -29,6 +30,10 @@
 
 namespace {
 
+// Measured in seconds.
+const double kSoftwareUploadTickRate = 0.000250;
+const double kTextureUploadTickRate = 0.004;
+
 GLenum TextureToStorageFormat(GLenum texture_format) {
   GLenum storage_format = GL_RGBA8_OES;
   switch (texture_format) {
@@ -73,9 +78,10 @@
       pixels(NULL),
       pixel_buffer(NULL),
       lock_for_read_count(0),
+      imported_count(0),
+      exported_count(0),
       locked_for_write(false),
       external(false),
-      exported(false),
       marked_for_deletion(false),
       pending_set_pixels(false),
       set_pixels_completion_forced(false),
@@ -105,9 +111,10 @@
       pixels(NULL),
       pixel_buffer(NULL),
       lock_for_read_count(0),
+      imported_count(0),
+      exported_count(0),
       locked_for_write(false),
       external(false),
-      exported(false),
       marked_for_deletion(false),
       pending_set_pixels(false),
       set_pixels_completion_forced(false),
@@ -130,9 +137,10 @@
       pixels(pixels),
       pixel_buffer(NULL),
       lock_for_read_count(0),
+      imported_count(0),
+      exported_count(0),
       locked_for_write(false),
       external(false),
-      exported(false),
       marked_for_deletion(false),
       pending_set_pixels(false),
       set_pixels_completion_forced(false),
@@ -158,7 +166,7 @@
       new ResourceProvider(output_surface, highp_threshold_min));
 
   bool success = false;
-  if (output_surface->context3d()) {
+  if (resource_provider->Context3d()) {
     success = resource_provider->InitializeGL();
   } else {
     resource_provider->InitializeSoftware();
@@ -179,17 +187,9 @@
   CleanUpGLIfNeeded();
 }
 
-WebGraphicsContext3D* ResourceProvider::GraphicsContext3D() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return output_surface_->context3d();
-}
-
 bool ResourceProvider::InUseByConsumer(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-  return !!resource->lock_for_read_count || resource->exported;
+  Resource* resource = GetResource(id);
+  return resource->lock_for_read_count > 0 || resource->exported_count > 0;
 }
 
 ResourceProvider::ResourceId ResourceProvider::CreateResource(
@@ -259,7 +259,7 @@
     unsigned texture_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   DCHECK(context3d);
   GLC(context3d, context3d->bindTexture(texture_target, texture_id));
   GLC(context3d, context3d->texParameteri(
@@ -309,9 +309,10 @@
   Resource* resource = &it->second;
   DCHECK(!resource->lock_for_read_count);
   DCHECK(!resource->marked_for_deletion);
+  DCHECK_EQ(resource->imported_count, 0);
   DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
 
-  if (resource->exported) {
+  if (resource->exported_count > 0) {
     resource->marked_for_deletion = true;
     return;
   } else {
@@ -324,35 +325,35 @@
   Resource* resource = &it->second;
   bool lost_resource = lost_output_surface_;
 
-  DCHECK(!resource->exported || style != Normal);
-  if (style == ForShutdown && resource->exported)
+  DCHECK(resource->exported_count == 0 || style != Normal);
+  if (style == ForShutdown && resource->exported_count > 0)
     lost_resource = true;
 
   if (resource->image_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     GLC(context3d, context3d->destroyImageCHROMIUM(resource->image_id));
   }
 
   if (resource->gl_id && !resource->external) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     GLC(context3d, context3d->deleteTexture(resource->gl_id));
   }
   if (resource->gl_upload_query_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     GLC(context3d, context3d->deleteQueryEXT(resource->gl_upload_query_id));
   }
   if (resource->gl_pixel_buffer_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     GLC(context3d, context3d->deleteBuffer(resource->gl_pixel_buffer_id));
   }
   if (resource->mailbox.IsValid() && resource->external) {
     unsigned sync_point = resource->mailbox.sync_point();
     if (resource->mailbox.IsTexture()) {
-      WebGraphicsContext3D* context3d = output_surface_->context3d();
+      WebGraphicsContext3D* context3d = Context3d();
       DCHECK(context3d);
       if (resource->gl_id)
         GLC(context3d, context3d->deleteTexture(resource->gl_id));
@@ -378,10 +379,7 @@
 
 ResourceProvider::ResourceType ResourceProvider::GetResourceType(
     ResourceId id) {
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-  return resource->type;
+  return GetResource(id)->type;
 }
 
 void ResourceProvider::SetPixels(ResourceId id,
@@ -389,20 +387,17 @@
                                  gfx::Rect image_rect,
                                  gfx::Rect source_rect,
                                  gfx::Vector2d dest_offset) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(!resource->locked_for_write);
   DCHECK(!resource->lock_for_read_count);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   DCHECK(ReadLockFenceHasPassed(resource));
   LazyAllocate(resource);
 
   if (resource->gl_id) {
     DCHECK(!resource->pending_set_pixels);
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     DCHECK(texture_uploader_.get());
     context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id);
@@ -470,23 +465,32 @@
   texture_uploader_->ReleaseCachedQueries();
 }
 
+base::TimeDelta ResourceProvider::TextureUpdateTickRate() {
+  // Software resource uploads happen on impl thread, so don't bother batching
+  // them up and trying to wait for them to complete.
+  double rate =
+      texture_uploader_ ? kTextureUploadTickRate : kSoftwareUploadTickRate;
+  return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond *
+                                           rate);
+}
+
 void ResourceProvider::Flush() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (context3d)
     context3d->flush();
 }
 
 void ResourceProvider::Finish() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (context3d)
     context3d->finish();
 }
 
 bool ResourceProvider::ShallowFlushIfSupported() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (!context3d || !use_shallow_flush_)
     return false;
 
@@ -494,16 +498,20 @@
   return true;
 }
 
-const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
+ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
   DCHECK(thread_checker_.CalledOnValidThread());
   ResourceMap::iterator it = resources_.find(id);
   CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  return &it->second;
+}
+
+const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
+  Resource* resource = GetResource(id);
   DCHECK(!resource->locked_for_write ||
          resource->set_pixels_completion_forced) <<
       "locked for write: " << resource->locked_for_write <<
       " pixels completion forced: " << resource->set_pixels_completion_forced;
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   // Uninitialized! Call SetPixels or LockForWrite first.
   DCHECK(resource->allocated);
 
@@ -511,7 +519,7 @@
 
   if (resource->external) {
     if (!resource->gl_id && resource->mailbox.IsTexture()) {
-      WebGraphicsContext3D* context3d = output_surface_->context3d();
+      WebGraphicsContext3D* context3d = Context3d();
       DCHECK(context3d);
       if (resource->mailbox.sync_point()) {
         GLC(context3d,
@@ -534,24 +542,18 @@
 }
 
 void ResourceProvider::UnlockForRead(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK_GT(resource->lock_for_read_count, 0);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   resource->lock_for_read_count--;
 }
 
 const ResourceProvider::Resource* ResourceProvider::LockForWrite(
     ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(!resource->locked_for_write);
   DCHECK(!resource->lock_for_read_count);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   DCHECK(!resource->external);
   DCHECK(ReadLockFenceHasPassed(resource));
   LazyAllocate(resource);
@@ -561,24 +563,18 @@
 }
 
 bool ResourceProvider::CanLockForWrite(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   return !resource->locked_for_write &&
       !resource->lock_for_read_count &&
-      !resource->exported &&
+      !resource->exported_count &&
       !resource->external &&
       ReadLockFenceHasPassed(resource);
 }
 
 void ResourceProvider::UnlockForWrite(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(resource->locked_for_write);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   DCHECK(!resource->external);
   resource->locked_for_write = false;
 }
@@ -685,7 +681,9 @@
       use_texture_usage_hint_(false),
       use_shallow_flush_(false),
       max_texture_size_(0),
-      best_texture_format_(0) {}
+      best_texture_format_(0) {
+  DCHECK(output_surface_->HasClient());
+}
 
 void ResourceProvider::InitializeSoftware() {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -703,7 +701,7 @@
   DCHECK(!texture_uploader_);
   DCHECK_NE(GLTexture, default_resource_type_);
 
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   DCHECK(context3d);
 
   if (!context3d->makeContextCurrent())
@@ -740,7 +738,7 @@
 }
 
 void ResourceProvider::CleanUpGLIfNeeded() {
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (default_resource_type_ != GLTexture) {
     // We are not in GL mode, but double check before returning.
     DCHECK(!context3d);
@@ -769,8 +767,15 @@
   Child& child = it->second;
   for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
        child_it != child.child_to_parent_map.end();
-       ++child_it)
-    DeleteResource(child_it->second);
+       ++child_it) {
+    ResourceId id = child_it->second;
+    // We're abandoning this resource, it will not get recycled.
+    // crbug.com/224062
+    ResourceMap::iterator resource_it = resources_.find(id);
+    CHECK(resource_it != resources_.end());
+    resource_it->second.imported_count = 0;
+    DeleteResource(id);
+  }
   children_.erase(it);
 }
 
@@ -785,7 +790,7 @@
 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
                                            TransferableResourceArray* list) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (!context3d || !context3d->makeContextCurrent()) {
     // TODO(skaslev): Implement this path for software compositing.
     return;
@@ -795,12 +800,11 @@
        it != resources.end();
        ++it) {
     TransferableResource resource;
-    if (TransferResource(context3d, *it, &resource)) {
-      if (!resource.sync_point)
-        need_sync_point = true;
-      resources_.find(*it)->second.exported = true;
-      list->push_back(resource);
-    }
+    TransferResource(context3d, *it, &resource);
+    if (!resource.sync_point)
+      need_sync_point = true;
+    ++resources_.find(*it)->second.exported_count;
+    list->push_back(resource);
   }
   if (need_sync_point) {
     unsigned int sync_point = context3d->insertSyncPoint();
@@ -813,11 +817,12 @@
   }
 }
 
-void ResourceProvider::PrepareSendToChild(int child,
-                                          const ResourceIdArray& resources,
-                                          TransferableResourceArray* list) {
+void ResourceProvider::PrepareSendReturnsToChild(
+    int child,
+    const ResourceIdArray& resources,
+    ReturnedResourceArray* list) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (!context3d || !context3d->makeContextCurrent()) {
     // TODO(skaslev): Implement this path for software compositing.
     return;
@@ -825,26 +830,31 @@
   Child& child_info = children_.find(child)->second;
   bool need_sync_point = false;
   for (ResourceIdArray::const_iterator it = resources.begin();
-       it != resources.end();
-       ++it) {
-    TransferableResource resource;
-    if (!TransferResource(context3d, *it, &resource))
-      NOTREACHED();
-    if (!resource.sync_point)
-      need_sync_point = true;
+       it != resources.end(); ++it) {
+    Resource* resource = GetResource(*it);
+    DCHECK(!resource->locked_for_write);
+    DCHECK(!resource->lock_for_read_count);
     DCHECK(child_info.parent_to_child_map.find(*it) !=
            child_info.parent_to_child_map.end());
-    resource.id = child_info.parent_to_child_map[*it];
+
+    ReturnedResource returned;
+    returned.id = child_info.parent_to_child_map[*it];
+    returned.filter = resource->filter;
+    returned.sync_point = resource->mailbox.sync_point();
+    if (!returned.sync_point)
+      need_sync_point = true;
+    returned.count = resource->imported_count;
+    list->push_back(returned);
+
     child_info.parent_to_child_map.erase(*it);
-    child_info.child_to_parent_map.erase(resource.id);
-    list->push_back(resource);
+    child_info.child_to_parent_map.erase(returned.id);
+    resources_[*it].imported_count = 0;
     DeleteResource(*it);
   }
   if (need_sync_point) {
     unsigned int sync_point = context3d->insertSyncPoint();
-    for (TransferableResourceArray::iterator it = list->begin();
-         it != list->end();
-         ++it) {
+    for (ReturnedResourceArray::iterator it = list->begin();
+         it != list->end(); ++it) {
       if (!it->sync_point)
         it->sync_point = sync_point;
     }
@@ -854,7 +864,7 @@
 void ResourceProvider::ReceiveFromChild(
     int child, const TransferableResourceArray& resources) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (!context3d || !context3d->makeContextCurrent()) {
     // TODO(skaslev): Implement this path for software compositing.
     return;
@@ -863,6 +873,12 @@
   for (TransferableResourceArray::const_iterator it = resources.begin();
        it != resources.end();
        ++it) {
+    ResourceIdMap::iterator resource_in_map_it =
+        child_info.child_to_parent_map.find(it->id);
+    if (resource_in_map_it != child_info.child_to_parent_map.end()) {
+      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
@@ -882,30 +898,32 @@
     resource.mailbox.SetName(it->mailbox);
     // Don't allocate a texture for a child.
     resource.allocated = true;
+    resource.imported_count = 1;
     resources_[id] = resource;
     child_info.parent_to_child_map[id] = it->id;
     child_info.child_to_parent_map[it->id] = id;
   }
 }
 
-void ResourceProvider::ReceiveFromParent(
-    const TransferableResourceArray& resources) {
+void ResourceProvider::ReceiveReturnsFromParent(
+    const ReturnedResourceArray& resources) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   if (!context3d || !context3d->makeContextCurrent()) {
     // TODO(skaslev): Implement this path for software compositing.
     return;
   }
-  for (TransferableResourceArray::const_iterator it = resources.begin();
+  for (ReturnedResourceArray::const_iterator it = resources.begin();
        it != resources.end();
        ++it) {
     ResourceMap::iterator map_iterator = resources_.find(it->id);
     DCHECK(map_iterator != resources_.end());
     Resource* resource = &map_iterator->second;
-    DCHECK(resource->exported);
-    resource->exported = false;
+    CHECK_GE(resource->exported_count, it->count);
+    resource->exported_count -= it->count;
+    if (resource->exported_count)
+      continue;
     resource->filter = it->filter;
-    DCHECK(resource->mailbox.ContainsMailbox(it->mailbox));
     if (resource->gl_id) {
       if (it->sync_point)
         GLC(context3d, context3d->waitSyncPoint(it->sync_point));
@@ -919,19 +937,14 @@
   }
 }
 
-bool ResourceProvider::TransferResource(WebGraphicsContext3D* context,
+void ResourceProvider::TransferResource(WebGraphicsContext3D* context,
                                         ResourceId id,
                                         TransferableResource* resource) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* source = &it->second;
+  Resource* source = GetResource(id);
   DCHECK(!source->locked_for_write);
   DCHECK(!source->lock_for_read_count);
   DCHECK(!source->external || (source->external && source->mailbox.IsValid()));
   DCHECK(source->allocated);
-  if (source->exported)
-    return false;
   resource->id = id;
   resource->format = source->format;
   resource->filter = source->filter;
@@ -956,21 +969,16 @@
     resource->sync_point = source->mailbox.sync_point();
     source->mailbox.ResetSyncPoint();
   }
-
-  return true;
 }
 
 void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   DCHECK(!resource->image_id);
 
   if (resource->type == GLTexture) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     if (!resource->gl_pixel_buffer_id)
       resource->gl_pixel_buffer_id = context3d->createBuffer();
@@ -994,12 +1002,9 @@
 }
 
 void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   DCHECK(!resource->image_id);
 
   // The pixel buffer can be released while there is a pending "set pixels"
@@ -1017,7 +1022,7 @@
   if (resource->type == GLTexture) {
     if (!resource->gl_pixel_buffer_id)
       return;
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     context3d->bindBuffer(
         GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
@@ -1039,16 +1044,13 @@
 }
 
 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   DCHECK(!resource->image_id);
 
   if (resource->type == GLTexture) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     DCHECK(resource->gl_pixel_buffer_id);
     context3d->bindBuffer(
@@ -1070,16 +1072,13 @@
 }
 
 void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
   DCHECK(!resource->image_id);
 
   if (resource->type == GLTexture) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     DCHECK(resource->gl_pixel_buffer_id);
     context3d->bindBuffer(
@@ -1095,7 +1094,7 @@
                                        GLenum unit,
                                        GLenum filter) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   ResourceMap::iterator it = resources_.find(resource_id);
   DCHECK(it != resources_.end());
   Resource* resource = &it->second;
@@ -1134,7 +1133,7 @@
   if (!resource->image_id)
     return;
 
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(context3d));
   if (unit != GL_TEXTURE0)
     GLC(context3d, context3d->activeTexture(unit));
@@ -1145,10 +1144,7 @@
 }
 
 void ResourceProvider::BeginSetPixels(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(!resource->pending_set_pixels);
 
   LazyCreate(resource);
@@ -1161,7 +1157,7 @@
   LockForWrite(id);
 
   if (resource->gl_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     DCHECK(resource->gl_pixel_buffer_id);
     context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id);
@@ -1213,16 +1209,13 @@
 }
 
 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(resource->locked_for_write);
   DCHECK(resource->pending_set_pixels);
   DCHECK(!resource->set_pixels_completion_forced);
 
   if (resource->gl_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id));
     GLC(context3d, context3d->waitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D));
     GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, 0));
@@ -1232,15 +1225,12 @@
 }
 
 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   DCHECK(resource->locked_for_write);
   DCHECK(resource->pending_set_pixels);
 
   if (resource->gl_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     DCHECK(resource->gl_upload_query_id);
     unsigned complete = 1;
@@ -1259,10 +1249,7 @@
 }
 
 void ResourceProvider::CreateForTesting(ResourceId id) {
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-  LazyCreate(resource);
+  LazyCreate(GetResource(id));
 }
 
 void ResourceProvider::LazyCreate(Resource* resource) {
@@ -1273,7 +1260,7 @@
   if (resource->texture_pool == 0)
     return;
 
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   DCHECK(context3d);
   // Create and set texture properties. Allocation is delayed until needed.
   resource->gl_id = CreateTextureId(context3d);
@@ -1288,10 +1275,7 @@
 }
 
 void ResourceProvider::AllocateForTesting(ResourceId id) {
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-  LazyAllocate(resource);
+  LazyAllocate(GetResource(id));
 }
 
 void ResourceProvider::LazyAllocate(Resource* resource) {
@@ -1302,7 +1286,7 @@
   if (resource->allocated || !resource->gl_id)
     return;
   resource->allocated = true;
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   gfx::Size& size = resource->size;
   GLenum format = resource->format;
   GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id));
@@ -1328,21 +1312,14 @@
 
 void ResourceProvider::EnableReadLockFences(ResourceProvider::ResourceId id,
                                             bool enable) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
+  Resource* resource = GetResource(id);
   resource->enable_read_lock_fences = enable;
 }
 
 void ResourceProvider::AcquireImage(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
 
   if (resource->type != GLTexture)
     return;
@@ -1351,26 +1328,23 @@
     return;
 
   resource->allocated = true;
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   DCHECK(context3d);
+  DCHECK_EQ(static_cast<GLenum>(GL_RGBA), resource->format);
   resource->image_id = context3d->createImageCHROMIUM(
       resource->size.width(), resource->size.height(), GL_RGBA8_OES);
   DCHECK(resource->image_id);
 }
 
 void ResourceProvider::ReleaseImage(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
 
   if (!resource->image_id)
     return;
 
-  WebGraphicsContext3D* context3d = output_surface_->context3d();
+  WebGraphicsContext3D* context3d = Context3d();
   DCHECK(context3d);
   context3d->destroyImageCHROMIUM(resource->image_id);
   resource->image_id = 0;
@@ -1378,17 +1352,13 @@
 }
 
 uint8_t* ResourceProvider::MapImage(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-
+  Resource* resource = GetResource(id);
   DCHECK(ReadLockFenceHasPassed(resource));
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
 
   if (resource->image_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     return static_cast<uint8_t*>(
         context3d->mapImageCHROMIUM(resource->image_id, GL_READ_WRITE));
@@ -1401,34 +1371,26 @@
 }
 
 void ResourceProvider::UnmapImage(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
 
   if (resource->image_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     context3d->unmapImageCHROMIUM(resource->image_id);
   }
 }
 
 int ResourceProvider::GetImageStride(ResourceId id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ResourceMap::iterator it = resources_.find(id);
-  CHECK(it != resources_.end());
-  Resource* resource = &it->second;
-
+  Resource* resource = GetResource(id);
   DCHECK(!resource->external);
-  DCHECK(!resource->exported);
+  DCHECK_EQ(resource->exported_count, 0);
 
   int stride = 0;
 
   if (resource->image_id) {
-    WebGraphicsContext3D* context3d = output_surface_->context3d();
+    WebGraphicsContext3D* context3d = Context3d();
     DCHECK(context3d);
     context3d->getImageParameterivCHROMIUM(
         resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, &stride);
@@ -1443,4 +1405,9 @@
   return active_unit;
 }
 
+WebKit::WebGraphicsContext3D* ResourceProvider::Context3d() const {
+  ContextProvider* context_provider = output_surface_->context_provider();
+  return context_provider ? context_provider->Context3d() : NULL;
+}
+
 }  // namespace cc
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index b5dccc8..146ceb1 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -63,7 +63,6 @@
 
   void DidLoseOutputSurface() { lost_output_surface_ = true; }
 
-  WebKit::WebGraphicsContext3D* GraphicsContext3D();
   int max_texture_size() const { return max_texture_size_; }
   GLenum best_texture_format() const { return best_texture_format_; }
   size_t num_resources() const { return resources_.size(); }
@@ -119,6 +118,7 @@
   double EstimatedUploadsPerSecond();
   void FlushUploads();
   void ReleaseCachedData();
+  base::TimeDelta TextureUpdateTickRate();
 
   // Flush all context operations, kicking uploads and ensuring ordering with
   // respect to other contexts.
@@ -153,9 +153,9 @@
   // Resources are removed from the ResourceProvider. Note: the resource IDs
   // passed are in the parent namespace and will be translated to the child
   // namespace when returned.
-  void PrepareSendToChild(int child,
-                          const ResourceIdArray& resources,
-                          TransferableResourceArray* transferable_resources);
+  void PrepareSendReturnsToChild(int child,
+                                 const ResourceIdArray& resources,
+                                 ReturnedResourceArray* returned_resources);
 
   // Receives resources from a child, moving them from mailboxes. Resource IDs
   // passed are in the child namespace, and will be translated to the parent
@@ -169,8 +169,8 @@
   // IDs passed are in the child namespace.
   // NOTE: if the sync_point is set on any TransferableResource, this will
   // wait on it.
-  void ReceiveFromParent(
-      const TransferableResourceArray& transferable_resources);
+  void ReceiveReturnsFromParent(
+      const ReturnedResourceArray& transferable_resources);
 
   // The following lock classes are part of the ResourceProvider API and are
   // needed to read and write the resource contents. The user must ensure
@@ -324,11 +324,11 @@
   // Indicates if we can currently lock this resource for write.
   bool CanLockForWrite(ResourceId id);
 
-  cc::ContextProvider* offscreen_context_provider() {
+  ContextProvider* offscreen_context_provider() {
     return offscreen_context_provider_.get();
   }
   void set_offscreen_context_provider(
-      scoped_refptr<cc::ContextProvider> offscreen_context_provider) {
+      scoped_refptr<ContextProvider> offscreen_context_provider) {
     offscreen_context_provider_ = offscreen_context_provider;
   }
   static GLint GetActiveTextureUnit(WebKit::WebGraphicsContext3D* context);
@@ -354,9 +354,10 @@
     uint8_t* pixels;
     uint8_t* pixel_buffer;
     int lock_for_read_count;
+    int imported_count;
+    int exported_count;
     bool locked_for_write;
     bool external;
-    bool exported;
     bool marked_for_deletion;
     bool pending_set_pixels;
     bool set_pixels_completion_forced;
@@ -392,6 +393,7 @@
 
   void CleanUpGLIfNeeded();
 
+  Resource* GetResource(ResourceId id);
   const Resource* LockForRead(ResourceId id);
   void UnlockForRead(ResourceId id);
   const Resource* LockForWrite(ResourceId id);
@@ -399,7 +401,7 @@
   static void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap,
                                            const Resource* resource);
 
-  bool TransferResource(WebKit::WebGraphicsContext3D* context,
+  void TransferResource(WebKit::WebGraphicsContext3D* context,
                         ResourceId id,
                         TransferableResource* resource);
   enum DeleteStyle {
@@ -421,6 +423,9 @@
                          GLenum target,
                          GLenum unit);
 
+  // Returns NULL if the output_surface_ does not have a ContextProvider.
+  WebKit::WebGraphicsContext3D* Context3d() const;
+
   OutputSurface* output_surface_;
   bool lost_output_surface_;
   int highp_threshold_min_;
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index a23af0b..dec66d6 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -11,10 +11,11 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "cc/base/scoped_ptr_deque.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/output/output_surface.h"
+#include "cc/resources/returned_resource.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_output_surface_client.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -366,13 +367,21 @@
     : public testing::TestWithParam<ResourceProvider::ResourceType> {
  public:
   ResourceProviderTest()
-      : shared_data_(ContextSharedData::Create()) {
+      : shared_data_(ContextSharedData::Create()),
+        context3d_(NULL) {
     switch (GetParam()) {
-      case ResourceProvider::GLTexture:
-        output_surface_ =
-            FakeOutputSurface::Create3d(ResourceProviderContext::Create(
-                shared_data_.get()).PassAs<WebKit::WebGraphicsContext3D>());
+      case ResourceProvider::GLTexture: {
+        scoped_ptr<ResourceProviderContext> context3d(
+            ResourceProviderContext::Create(shared_data_.get()));
+        context3d_ = context3d.get();
+
+        scoped_refptr<TestContextProvider> context_provider =
+            TestContextProvider::Create(
+                context3d.PassAs<TestWebGraphicsContext3D>());
+
+        output_surface_ = FakeOutputSurface::Create3d(context_provider);
         break;
+      }
       case ResourceProvider::Bitmap:
         output_surface_ = FakeOutputSurface::CreateSoftware(
             make_scoped_ptr(new SoftwareOutputDevice));
@@ -381,13 +390,10 @@
         NOTREACHED();
         break;
     }
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
     resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
   }
 
-  ResourceProviderContext* context() {
-    return static_cast<ResourceProviderContext*>(output_surface_->context3d());
-  }
-
   void SetResourceFilter(ResourceProvider* resource_provider,
                          ResourceProvider::ResourceId id,
                          WGC3Denum filter) {
@@ -396,18 +402,21 @@
   }
 
   WGC3Denum GetResourceFilter(ResourceProvider* resource_provider,
+                              ResourceProviderContext* context,
                               ResourceProvider::ResourceId id) {
     DCHECK_EQ(GetParam(), ResourceProvider::GLTexture);
     ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id);
     EXPECT_NE(0u, lock_gl.texture_id());
-    ResourceProviderContext* context = static_cast<ResourceProviderContext*>(
-        resource_provider->GraphicsContext3D());
     context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id());
     return context->GetTextureFilter();
   }
 
+  ResourceProviderContext* context() { return context3d_; }
+
  protected:
   scoped_ptr<ContextSharedData> shared_data_;
+  ResourceProviderContext* context3d_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<OutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
 };
@@ -520,9 +529,16 @@
   if (GetParam() != ResourceProvider::GLTexture)
     return;
 
-  scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
-      ResourceProviderContext::Create(shared_data_.get())
-          .PassAs<WebKit::WebGraphicsContext3D>()));
+  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));
 
@@ -579,32 +595,37 @@
   EXPECT_EQ(0, memcmp(data2, result, pixel_size));
   {
     // Check that transfering again the same resource from the child to the
-    // parent is a noop.
+    // 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(0u, list.size());
+    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));
   }
   {
     // Transfer resources back from the parent to the child.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(mapped_id1);
     resource_ids_to_transfer.push_back(mapped_id2);
-    TransferableResourceArray list;
-    resource_provider_->PrepareSendToChild(
+    ReturnedResourceArray list;
+    resource_provider_->PrepareSendReturnsToChild(
         child_id, resource_ids_to_transfer, &list);
     ASSERT_EQ(2u, list.size());
     EXPECT_NE(0u, list[0].sync_point);
     EXPECT_NE(0u, list[1].sync_point);
-    child_resource_provider->ReceiveFromParent(list);
+    child_resource_provider->ReceiveReturnsFromParent(list);
   }
   EXPECT_FALSE(child_resource_provider->InUseByConsumer(id1));
   EXPECT_FALSE(child_resource_provider->InUseByConsumer(id2));
 
-  ResourceProviderContext* child_context =
-      static_cast<ResourceProviderContext*>(child_output_surface->context3d());
   {
     ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id1);
     ASSERT_NE(0U, lock.texture_id());
@@ -645,9 +666,15 @@
   if (GetParam() != ResourceProvider::GLTexture)
     return;
 
-  scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
-      ResourceProviderContext::Create(shared_data_.get())
-          .PassAs<WebKit::WebGraphicsContext3D>()));
+  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));
 
@@ -687,12 +714,12 @@
     EXPECT_NE(0u, mapped_id);
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(mapped_id);
-    TransferableResourceArray list;
-    resource_provider_->PrepareSendToChild(
+    ReturnedResourceArray list;
+    resource_provider_->PrepareSendReturnsToChild(
         child_id, resource_ids_to_transfer, &list);
     ASSERT_EQ(1u, list.size());
     EXPECT_NE(0u, list[0].sync_point);
-    child_resource_provider->ReceiveFromParent(list);
+    child_resource_provider->ReceiveReturnsFromParent(list);
   }
   EXPECT_EQ(0u, child_resource_provider->num_resources());
 }
@@ -702,9 +729,15 @@
   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(
-      ResourceProviderContext::Create(shared_data_.get())
-          .PassAs<WebKit::WebGraphicsContext3D>()));
+      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));
 
@@ -719,10 +752,14 @@
   gfx::Rect rect(size);
   child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
   EXPECT_EQ(static_cast<unsigned>(GL_LINEAR),
-            GetResourceFilter(child_resource_provider.get(), id));
+            GetResourceFilter(child_resource_provider.get(),
+                              child_context,
+                              id));
   SetResourceFilter(child_resource_provider.get(), id, GL_NEAREST);
   EXPECT_EQ(static_cast<unsigned>(GL_NEAREST),
-            GetResourceFilter(child_resource_provider.get(), id));
+            GetResourceFilter(child_resource_provider.get(),
+                              child_context,
+                              id));
 
   int child_id = resource_provider_->CreateChild();
   {
@@ -741,26 +778,30 @@
   ResourceProvider::ResourceId mapped_id = resource_map[id];
   EXPECT_NE(0u, mapped_id);
   EXPECT_EQ(static_cast<unsigned>(GL_NEAREST),
-            GetResourceFilter(resource_provider_.get(), mapped_id));
+            GetResourceFilter(resource_provider_.get(), context(), mapped_id));
   SetResourceFilter(resource_provider_.get(), mapped_id, GL_LINEAR);
   EXPECT_EQ(static_cast<unsigned>(GL_LINEAR),
-            GetResourceFilter(resource_provider_.get(), mapped_id));
+            GetResourceFilter(resource_provider_.get(), context(), mapped_id));
   {
     // Transfer resources back from the parent to the child.
     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
     resource_ids_to_transfer.push_back(mapped_id);
-    TransferableResourceArray list;
-    resource_provider_->PrepareSendToChild(
+    ReturnedResourceArray list;
+    resource_provider_->PrepareSendReturnsToChild(
         child_id, resource_ids_to_transfer, &list);
     ASSERT_EQ(1u, list.size());
     EXPECT_EQ(static_cast<unsigned>(GL_LINEAR), list[0].filter);
-    child_resource_provider->ReceiveFromParent(list);
+    child_resource_provider->ReceiveReturnsFromParent(list);
   }
   EXPECT_EQ(static_cast<unsigned>(GL_LINEAR),
-            GetResourceFilter(child_resource_provider.get(), id));
+            GetResourceFilter(child_resource_provider.get(),
+                              child_context,
+                              id));
   SetResourceFilter(child_resource_provider.get(), id, GL_NEAREST);
   EXPECT_EQ(static_cast<unsigned>(GL_NEAREST),
-            GetResourceFilter(child_resource_provider.get(), id));
+            GetResourceFilter(child_resource_provider.get(),
+                              child_context,
+                              id));
 }
 
 void ReleaseTextureMailbox(unsigned* release_sync_point,
@@ -823,7 +864,9 @@
 
     // Receive the resource, then delete it, expect the sync points to be
     // consistent.
-    resource_provider_->ReceiveFromParent(list);
+    ReturnedResourceArray returned;
+    TransferableResource::ReturnResources(list, &returned);
+    resource_provider_->ReceiveReturnsFromParent(returned);
     EXPECT_EQ(1, context()->texture_count());
     EXPECT_EQ(0u, release_sync_point);
 
@@ -872,7 +915,9 @@
 
     // Then receive the resource which should release the mailbox, expect the
     // sync points to be consistent.
-    resource_provider_->ReceiveFromParent(list);
+    ReturnedResourceArray returned;
+    TransferableResource::ReturnResources(list, &returned);
+    resource_provider_->ReceiveReturnsFromParent(returned);
     EXPECT_LE(list[0].sync_point, release_sync_point);
     EXPECT_FALSE(lost_resource);
   }
@@ -1035,11 +1080,15 @@
   if (GetParam() != ResourceProvider::GLTexture)
     return;
 
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new TextureStateTrackingContext)));
-  TextureStateTrackingContext* context =
-      static_cast<TextureStateTrackingContext*>(output_surface->context3d());
+  scoped_ptr<TextureStateTrackingContext> context_owned(
+      new TextureStateTrackingContext);
+  TextureStateTrackingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1108,11 +1157,15 @@
   if (GetParam() != ResourceProvider::GLTexture)
     return;
 
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new TextureStateTrackingContext)));
-  TextureStateTrackingContext* context =
-      static_cast<TextureStateTrackingContext*>(output_surface->context3d());
+  scoped_ptr<TextureStateTrackingContext> context_owned(
+      new TextureStateTrackingContext);
+  TextureStateTrackingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1155,9 +1208,12 @@
   scoped_ptr<base::SharedMemory> shared_memory(
       CreateAndFillSharedMemory(size, kBadBeef));
 
+  FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface(
       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
           new SoftwareOutputDevice)));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1182,11 +1238,15 @@
   if (GetParam() != ResourceProvider::GLTexture)
     return;
 
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new TextureStateTrackingContext)));
-  TextureStateTrackingContext* context =
-      static_cast<TextureStateTrackingContext*>(output_surface->context3d());
+  scoped_ptr<TextureStateTrackingContext> context_owned(
+      new TextureStateTrackingContext);
+  TextureStateTrackingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1242,11 +1302,15 @@
   if (GetParam() != ResourceProvider::GLTexture)
     return;
 
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new TextureStateTrackingContext)));
-  TextureStateTrackingContext* context =
-      static_cast<TextureStateTrackingContext*>(output_surface->context3d());
+  scoped_ptr<TextureStateTrackingContext> context_owned(
+      new TextureStateTrackingContext);
+  TextureStateTrackingContext* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1359,11 +1423,17 @@
   // Only for GL textures.
   if (GetParam() != ResourceProvider::GLTexture)
     return;
-  scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
-      static_cast<WebKit::WebGraphicsContext3D*>(
-          new StrictMock<AllocationTrackingContext3D>));
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(mock_context.Pass()));
+  scoped_ptr<AllocationTrackingContext3D> context_owned(
+      new StrictMock<AllocationTrackingContext3D>);
+  AllocationTrackingContext3D* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
+  scoped_ptr<ResourceProvider> resource_provider(
+      ResourceProvider::Create(output_surface.get(), 0));
 
   gfx::Size size(2, 2);
   gfx::Vector2d offset(0, 0);
@@ -1373,11 +1443,6 @@
   uint8_t pixels[16] = { 0 };
   int texture_id = 123;
 
-  AllocationTrackingContext3D* context =
-      static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
-  scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(output_surface.get(), 0));
-
   // Lazy allocation. Don't allocate when creating the resource.
   id = resource_provider->CreateResource(
       size, format, ResourceProvider::TextureUsageAny);
@@ -1429,19 +1494,20 @@
 TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
   if (GetParam() != ResourceProvider::GLTexture)
     return;
-  scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
-      static_cast<WebKit::WebGraphicsContext3D*>(
-          new StrictMock<AllocationTrackingContext3D>));
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(mock_context.Pass()));
+  scoped_ptr<AllocationTrackingContext3D> context_owned(
+      new StrictMock<AllocationTrackingContext3D>);
+  AllocationTrackingContext3D* context = context_owned.get();
+
+  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(2, 2);
   WGC3Denum format = GL_RGBA;
   ResourceProvider::ResourceId id = 0;
   int texture_id = 123;
 
-  AllocationTrackingContext3D* context =
-      static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1468,9 +1534,11 @@
 TEST_P(ResourceProviderTest, PixelBuffer_Bitmap) {
   if (GetParam() != ResourceProvider::Bitmap)
     return;
+  FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface(
       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
           new SoftwareOutputDevice)));
+  CHECK(output_surface->BindToClient(&output_surface_client));
 
   gfx::Size size(1, 1);
   WGC3Denum format = GL_RGBA;
@@ -1509,19 +1577,20 @@
   // Only for GL textures.
   if (GetParam() != ResourceProvider::GLTexture)
     return;
-  scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
-      static_cast<WebKit::WebGraphicsContext3D*>(
-          new StrictMock<AllocationTrackingContext3D>));
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(mock_context.Pass()));
+  scoped_ptr<AllocationTrackingContext3D> context_owned(
+      new StrictMock<AllocationTrackingContext3D>);
+  AllocationTrackingContext3D* context = context_owned.get();
+
+  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(2, 2);
   WGC3Denum format = GL_RGBA;
   ResourceProvider::ResourceId id = 0;
   int texture_id = 123;
 
-  AllocationTrackingContext3D* context =
-      static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1549,19 +1618,20 @@
 }
 
 TEST_P(ResourceProviderTest, PixelBufferLostContext) {
-  scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
-      static_cast<WebKit::WebGraphicsContext3D*>(
-          new NiceMock<AllocationTrackingContext3D>));
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(mock_context.Pass()));
+  scoped_ptr<AllocationTrackingContext3D> context_owned(
+      new NiceMock<AllocationTrackingContext3D>);
+  AllocationTrackingContext3D* context = context_owned.get();
+
+  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(2, 2);
   WGC3Denum format = GL_RGBA;
   ResourceProvider::ResourceId id = 0;
   int texture_id = 123;
 
-  AllocationTrackingContext3D* context =
-      static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1583,11 +1653,14 @@
   // Only for GL textures.
   if (GetParam() != ResourceProvider::GLTexture)
     return;
-  scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
-      static_cast<WebKit::WebGraphicsContext3D*>(
-          new StrictMock<AllocationTrackingContext3D>));
-  scoped_ptr<OutputSurface> output_surface(
-      FakeOutputSurface::Create3d(mock_context.Pass()));
+  scoped_ptr<AllocationTrackingContext3D> context_owned(
+      new StrictMock<AllocationTrackingContext3D>);
+  AllocationTrackingContext3D* context = context_owned.get();
+
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
+  CHECK(output_surface->BindToClient(&output_surface_client));
 
   const int kWidth = 2;
   const int kHeight = 2;
@@ -1597,8 +1670,6 @@
   const unsigned kTextureId = 123u;
   const unsigned kImageId = 234u;
 
-  AllocationTrackingContext3D* context =
-      static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   scoped_ptr<ResourceProvider> resource_provider(
       ResourceProvider::Create(output_surface.get(), 0));
 
@@ -1659,9 +1730,11 @@
 TEST_P(ResourceProviderTest, Image_Bitmap) {
   if (GetParam() != ResourceProvider::Bitmap)
     return;
+  FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface(
       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
           new SoftwareOutputDevice)));
+  CHECK(output_surface->BindToClient(&output_surface_client));
 
   gfx::Size size(1, 1);
   WGC3Denum format = GL_RGBA;
@@ -1699,15 +1772,17 @@
 void InitializeGLAndCheck(ContextSharedData* shared_data,
                           ResourceProvider* resource_provider,
                           FakeOutputSurface* output_surface) {
-  scoped_ptr<ResourceProviderContext> context =
+  scoped_ptr<ResourceProviderContext> context_owned =
       ResourceProviderContext::Create(shared_data);
-  output_surface->SetAndInitializeContext3D(
-      context.PassAs<WebKit::WebGraphicsContext3D>());
+  ResourceProviderContext* context = context_owned.get();
+
+  scoped_refptr<TestContextProvider> context_provider =
+      TestContextProvider::Create(
+          context_owned.PassAs<TestWebGraphicsContext3D>());
+  output_surface->InitializeAndSetContext3d(context_provider, NULL);
   EXPECT_TRUE(resource_provider->InitializeGL());
-  CheckCreateResource(
-      ResourceProvider::GLTexture,
-      resource_provider,
-      static_cast<ResourceProviderContext*>(output_surface->context3d()));
+
+  CheckCreateResource(ResourceProvider::GLTexture, resource_provider, context);
 }
 
 TEST(ResourceProviderTest, BasicInitializeGLSoftware) {
@@ -1727,6 +1802,7 @@
                        output_surface.get());
 
   resource_provider->InitializeSoftware();
+  output_surface->ReleaseGL();
   CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
 
   InitializeGLAndCheck(shared_data.get(),
diff --git a/cc/resources/resource_update_controller.cc b/cc/resources/resource_update_controller.cc
index a46a7d1..3c8b1e7 100644
--- a/cc/resources/resource_update_controller.cc
+++ b/cc/resources/resource_update_controller.cc
@@ -16,9 +16,6 @@
 const size_t kPartialTextureUpdatesMax = 12;
 
 // Measured in seconds.
-const double kTextureUpdateTickRate = 0.004;
-
-// Measured in seconds.
 const double kUploaderBusyTickRate = 0.001;
 
 // Number of blocking update intervals to allow.
@@ -36,7 +33,8 @@
     ResourceProvider* resource_provider) {
   double textures_per_second = resource_provider->EstimatedUploadsPerSecond();
   size_t textures_per_tick =
-      floor(kTextureUpdateTickRate * textures_per_second);
+      floor(resource_provider->TextureUpdateTickRate().InSecondsF() *
+            textures_per_second);
   return textures_per_tick ? textures_per_tick : 1;
 }
 
@@ -119,7 +117,7 @@
 }
 
 base::TimeDelta ResourceUpdateController::UpdateMoreTexturesTime() const {
-  return base::TimeDelta::FromMilliseconds(kTextureUpdateTickRate * 1000);
+  return resource_provider_->TextureUpdateTickRate();
 }
 
 size_t ResourceUpdateController::UpdateMoreTexturesSize() const {
diff --git a/cc/resources/resource_update_controller_unittest.cc b/cc/resources/resource_update_controller_unittest.cc
index 1060801..e7c59bf 100644
--- a/cc/resources/resource_update_controller_unittest.cc
+++ b/cc/resources/resource_update_controller_unittest.cc
@@ -5,11 +5,12 @@
 #include "cc/resources/resource_update_controller.h"
 
 #include "base/test/test_simple_task_runner.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_proxy.h"
 #include "cc/test/scheduler_test_common.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/test/tiled_layer_test_common.h"
 #include "cc/trees/single_thread_proxy.h"  // For DebugScopedSetImplThread
 #include "testing/gtest/include/gtest/gtest.h"
@@ -124,9 +125,6 @@
 
  protected:
   virtual void SetUp() {
-    output_surface_ =
-        FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-            new WebGraphicsContext3DForUploadTest(this)));
     bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 300, 150);
     bitmap_.allocPixels();
 
@@ -138,6 +136,11 @@
     }
     resource_manager_->PrioritizeTextures();
 
+    output_surface_ = FakeOutputSurface::Create3d(
+        scoped_ptr<TestWebGraphicsContext3D>(
+            new WebGraphicsContext3DForUploadTest(this)));
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
     resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
   }
 
@@ -193,6 +196,7 @@
  protected:
   // Classes required to interact and test the ResourceUpdateController
   FakeProxy proxy_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<OutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
   scoped_ptr<ResourceUpdateQueue> queue_;
diff --git a/cc/resources/returned_resource.h b/cc/resources/returned_resource.h
new file mode 100644
index 0000000..aa6b99a
--- /dev/null
+++ b/cc/resources/returned_resource.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 CC_RESOURCES_RETURNED_RESOURCE_H_
+#define CC_RESOURCES_RETURNED_RESOURCE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+struct CC_EXPORT ReturnedResource {
+  ReturnedResource() : id(0), sync_point(0), filter(0), count(0) {}
+  unsigned id;
+  unsigned sync_point;
+  uint32 filter;
+  int count;
+};
+
+typedef std::vector<ReturnedResource> ReturnedResourceArray;
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_RETURNED_RESOURCE_H_
diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc
index b08c1e2..9c66180 100644
--- a/cc/resources/scoped_resource_unittest.cc
+++ b/cc/resources/scoped_resource_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "cc/output/renderer.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/tiled_layer_test_common.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/khronos/GLES2/gl2.h"
@@ -14,9 +15,12 @@
 namespace {
 
 TEST(ScopedResourceTest, NewScopedResource) {
-  scoped_ptr<OutputSurface> context(CreateFakeOutputSurface());
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(context.get(), 0));
+      ResourceProvider::Create(output_surface.get(), 0));
   scoped_ptr<ScopedResource> texture =
       ScopedResource::create(resource_provider.get());
 
@@ -29,9 +33,12 @@
 }
 
 TEST(ScopedResourceTest, CreateScopedResource) {
-  scoped_ptr<OutputSurface> context(CreateFakeOutputSurface());
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(context.get(), 0));
+      ResourceProvider::Create(output_surface.get(), 0));
   scoped_ptr<ScopedResource> texture =
       ScopedResource::create(resource_provider.get());
   texture->Allocate(
@@ -47,9 +54,12 @@
 }
 
 TEST(ScopedResourceTest, ScopedResourceIsDeleted) {
-  scoped_ptr<OutputSurface> context(CreateFakeOutputSurface());
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(context.get(), 0));
+      ResourceProvider::Create(output_surface.get(), 0));
   {
     scoped_ptr<ScopedResource> texture =
         ScopedResource::create(resource_provider.get());
@@ -76,9 +86,12 @@
 }
 
 TEST(ScopedResourceTest, LeakScopedResource) {
-  scoped_ptr<OutputSurface> context(CreateFakeOutputSurface());
+  FakeOutputSurfaceClient output_surface_client;
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
+  CHECK(output_surface->BindToClient(&output_surface_client));
+
   scoped_ptr<ResourceProvider> resource_provider(
-      ResourceProvider::Create(context.get(), 0));
+      ResourceProvider::Create(output_surface.get(), 0));
   {
     scoped_ptr<ScopedResource> texture =
         ScopedResource::create(resource_provider.get());
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index ab4fe7a..26e7841 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -41,6 +41,16 @@
   tile_manager_->UnregisterTile(this);
 }
 
+void Tile::SetPriority(WhichTree tree, const TilePriority& priority) {
+  priority_[tree] = priority;
+  tile_manager_->DidChangeTilePriority(this);
+}
+
+void Tile::MarkRequiredForActivation() {
+  priority_[PENDING_TREE].required_for_activation = true;
+  tile_manager_->DidChangeTilePriority(this);
+}
+
 scoped_ptr<base::Value> Tile::AsValue() const {
   scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
   TracedValue::MakeDictIntoImplicitSnapshot(res.get(), "cc::Tile", this);
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index be9b19a..30916fa 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -53,13 +53,9 @@
                         priority_[PENDING_TREE]);
   }
 
-  void SetPriority(WhichTree tree, const TilePriority& priority) {
-    priority_[tree] = priority;
-  }
+  void SetPriority(WhichTree tree, const TilePriority& priority);
 
-  void mark_required_for_activation() {
-    priority_[PENDING_TREE].required_for_activation = true;
-  }
+  void MarkRequiredForActivation();
 
   bool required_for_activation() const {
     return priority_[PENDING_TREE].required_for_activation;
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index aa6c1ad..6b108d8 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -130,8 +130,7 @@
                       PixelBufferRasterWorkerPool::Create(
                           resource_provider, num_raster_threads),
                       num_raster_threads,
-                      rendering_stats_instrumentation,
-                      resource_provider->best_texture_format()));
+                      rendering_stats_instrumentation));
 }
 
 TileManager::TileManager(
@@ -139,18 +138,19 @@
     ResourceProvider* resource_provider,
     scoped_ptr<RasterWorkerPool> raster_worker_pool,
     size_t num_raster_threads,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation,
-    GLenum texture_format)
+    RenderingStatsInstrumentation* rendering_stats_instrumentation)
     : client_(client),
       resource_pool_(ResourcePool::Create(resource_provider)),
       raster_worker_pool_(raster_worker_pool.Pass()),
+      prioritized_tiles_dirty_(false),
       all_tiles_that_need_to_be_rasterized_have_memory_(true),
       all_tiles_required_for_activation_have_memory_(true),
       all_tiles_required_for_activation_have_been_initialized_(true),
+      bytes_releasable_(0),
+      resources_releasable_(0),
       ever_exceeded_memory_budget_(false),
       rendering_stats_instrumentation_(rendering_stats_instrumentation),
-      did_initialize_visible_tile_(false),
-      texture_format_(texture_format) {
+      did_initialize_visible_tile_(false) {
   raster_worker_pool_->SetClient(this);
 }
 
@@ -159,8 +159,6 @@
   // our memory usage to drop to zero.
   global_state_ = GlobalStateThatImpactsTilePriority();
 
-  // Clear |prioritized_tiles_| so that tiles kept alive by it can be freed.
-  prioritized_tiles_.Clear();
   DCHECK_EQ(0u, tiles_.size());
 
   TileVector empty;
@@ -170,12 +168,15 @@
   // resources.
   raster_worker_pool_->Shutdown();
   raster_worker_pool_->CheckForCompletedTasks();
+
+  DCHECK_EQ(0u, bytes_releasable_);
+  DCHECK_EQ(0u, resources_releasable_);
 }
 
 void TileManager::SetGlobalState(
     const GlobalStateThatImpactsTilePriority& global_state) {
   global_state_ = global_state;
-  resource_pool_->SetMemoryUsageLimits(
+  resource_pool_->SetResourceUsageLimits(
       global_state_.memory_limit_in_bytes,
       global_state_.unused_memory_limit_in_bytes,
       global_state_.num_resources_limit);
@@ -186,6 +187,7 @@
   DCHECK(tiles_.find(tile->id()) == tiles_.end());
 
   tiles_[tile->id()] = tile;
+  prioritized_tiles_dirty_ = true;
 }
 
 void TileManager::UnregisterTile(Tile* tile) {
@@ -193,12 +195,27 @@
 
   DCHECK(tiles_.find(tile->id()) != tiles_.end());
   tiles_.erase(tile->id());
+  prioritized_tiles_dirty_ = true;
+}
+
+void TileManager::DidChangeTilePriority(Tile* tile) {
+  prioritized_tiles_dirty_ = true;
 }
 
 bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const {
   return GlobalState().tree_priority != SMOOTHNESS_TAKES_PRIORITY;
 }
 
+PrioritizedTileSet* TileManager::GetPrioritizedTileSet() {
+  if (!prioritized_tiles_dirty_)
+    return &prioritized_tiles_;
+
+  prioritized_tiles_.Clear();
+  GetTilesWithAssignedBins(&prioritized_tiles_);
+  prioritized_tiles_dirty_ = false;
+  return &prioritized_tiles_;
+}
+
 void TileManager::DidFinishRunningTasks() {
   TRACE_EVENT0("cc", "TileManager::DidFinishRunningTasks");
 
@@ -210,7 +227,7 @@
   raster_worker_pool_->CheckForCompletedTasks();
 
   TileVector tiles_that_need_to_be_rasterized;
-  AssignGpuMemoryToTiles(&prioritized_tiles_,
+  AssignGpuMemoryToTiles(GetPrioritizedTileSet(),
                          &tiles_that_need_to_be_rasterized);
 
   // |tiles_that_need_to_be_rasterized| will be empty when we reach a
@@ -259,67 +276,60 @@
     Tile* tile = it->second;
     ManagedTileState& mts = tile->managed_state();
 
-    TilePriority prio[NUM_BIN_PRIORITIES];
-    switch (tree_priority) {
-      case SAME_PRIORITY_FOR_BOTH_TREES:
-        prio[HIGH_PRIORITY_BIN] = prio[LOW_PRIORITY_BIN] =
-            tile->combined_priority();
-        break;
-      case SMOOTHNESS_TAKES_PRIORITY:
-        prio[HIGH_PRIORITY_BIN] = tile->priority(ACTIVE_TREE);
-        prio[LOW_PRIORITY_BIN] = tile->priority(PENDING_TREE);
-        break;
-      case NEW_CONTENT_TAKES_PRIORITY:
-        prio[HIGH_PRIORITY_BIN] = tile->priority(PENDING_TREE);
-        prio[LOW_PRIORITY_BIN] = tile->priority(ACTIVE_TREE);
-        break;
-    }
-
     bool tile_is_ready_to_draw = tile->IsReadyToDraw();
     bool tile_is_active =
         tile_is_ready_to_draw ||
         !mts.tile_versions[mts.raster_mode].raster_task_.is_null();
 
-    mts.resolution = prio[HIGH_PRIORITY_BIN].resolution;
-    mts.time_to_needed_in_seconds =
-        prio[HIGH_PRIORITY_BIN].time_to_visible_in_seconds;
-    mts.distance_to_visible_in_pixels =
-        prio[HIGH_PRIORITY_BIN].distance_to_visible_in_pixels;
-    mts.required_for_activation =
-        prio[HIGH_PRIORITY_BIN].required_for_activation;
-
-    mts.bin[HIGH_PRIORITY_BIN] =
-        BinFromTilePriority(prio[HIGH_PRIORITY_BIN],
-                            tree_priority,
-                            tile_is_ready_to_draw,
-                            tile_is_active);
-    mts.bin[LOW_PRIORITY_BIN] =
-        BinFromTilePriority(prio[LOW_PRIORITY_BIN],
-                            tree_priority,
-                            tile_is_ready_to_draw,
-                            tile_is_active);
-    mts.gpu_memmgr_stats_bin =
-        BinFromTilePriority(tile->combined_priority(),
-                            tree_priority,
-                            tile_is_ready_to_draw,
-                            tile_is_active);
-
-    ManagedTileBin active_bin =
-        BinFromTilePriority(tile->priority(ACTIVE_TREE),
-                            tree_priority,
-                            tile_is_ready_to_draw,
-                            tile_is_active);
+    // Get the active priority and bin.
+    TilePriority active_priority = tile->priority(ACTIVE_TREE);
+    ManagedTileBin active_bin = BinFromTilePriority(
+        active_priority, tree_priority, tile_is_ready_to_draw, tile_is_active);
     mts.tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin];
 
-    ManagedTileBin pending_bin =
-        BinFromTilePriority(tile->priority(PENDING_TREE),
-                            tree_priority,
-                            tile_is_ready_to_draw,
-                            tile_is_active);
+    // Get the pending priority and bin.
+    TilePriority pending_priority = tile->priority(PENDING_TREE);
+    ManagedTileBin pending_bin = BinFromTilePriority(
+        pending_priority, tree_priority, tile_is_ready_to_draw, tile_is_active);
     mts.tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin];
 
-    for (int i = 0; i < NUM_BIN_PRIORITIES; ++i)
-      mts.bin[i] = kBinPolicyMap[memory_policy][mts.bin[i]];
+    // Get the combined priority and bin.
+    TilePriority combined_priority = tile->combined_priority();
+    ManagedTileBin combined_bin = BinFromTilePriority(combined_priority,
+                                                      tree_priority,
+                                                      tile_is_ready_to_draw,
+                                                      tile_is_active);
+    // Note that |gpu_memmgr_stats_bin| does not care about memory_policy, so we
+    // have to save it first.
+    mts.gpu_memmgr_stats_bin = combined_bin;
+
+    combined_bin = kBinPolicyMap[memory_policy][combined_bin];
+
+    TilePriority* high_priority = NULL;
+    switch (tree_priority) {
+      case SAME_PRIORITY_FOR_BOTH_TREES:
+        mts.bin[HIGH_PRIORITY_BIN] = mts.bin[LOW_PRIORITY_BIN] = combined_bin;
+        high_priority = &combined_priority;
+        break;
+      case SMOOTHNESS_TAKES_PRIORITY:
+        mts.bin[HIGH_PRIORITY_BIN] = mts.tree_bin[ACTIVE_TREE];
+        mts.bin[LOW_PRIORITY_BIN] = mts.tree_bin[PENDING_TREE];
+        high_priority = &active_priority;
+        break;
+      case NEW_CONTENT_TAKES_PRIORITY:
+        mts.bin[HIGH_PRIORITY_BIN] = mts.tree_bin[PENDING_TREE];
+        mts.bin[LOW_PRIORITY_BIN] = mts.tree_bin[ACTIVE_TREE];
+        high_priority = &pending_priority;
+        break;
+    }
+
+    DCHECK(high_priority != NULL);
+
+    mts.resolution = high_priority->resolution;
+    mts.time_to_needed_in_seconds = high_priority->time_to_visible_in_seconds;
+    mts.distance_to_visible_in_pixels =
+        high_priority->distance_to_visible_in_pixels;
+    mts.required_for_activation = high_priority->required_for_activation;
 
     mts.visible_and_ready_to_draw =
         mts.tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN;
@@ -343,32 +353,24 @@
   }
 }
 
-void TileManager::GetPrioritizedTileSet(PrioritizedTileSet* tiles) {
-  TRACE_EVENT0("cc", "TileManager::GetPrioritizedTileSet");
-
-  GetTilesWithAssignedBins(tiles);
-  tiles->Sort();
-}
-
 void TileManager::ManageTiles() {
   TRACE_EVENT0("cc", "TileManager::ManageTiles");
 
-  // Clear |prioritized_tiles_| so that tiles kept alive by it can be freed.
-  prioritized_tiles_.Clear();
-
-  GetPrioritizedTileSet(&prioritized_tiles_);
-
   TileVector tiles_that_need_to_be_rasterized;
-  AssignGpuMemoryToTiles(&prioritized_tiles_,
+  AssignGpuMemoryToTiles(GetPrioritizedTileSet(),
                          &tiles_that_need_to_be_rasterized);
   CleanUpUnusedImageDecodeTasks();
 
+  // Finally, schedule rasterizer tasks.
+  ScheduleTasks(tiles_that_need_to_be_rasterized);
+
   TRACE_EVENT_INSTANT1(
       "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD,
       "state", TracedValue::FromValue(BasicStateAsValue().release()));
 
-  // Finally, schedule rasterizer tasks.
-  ScheduleTasks(tiles_that_need_to_be_rasterized);
+  TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
+                    resource_pool_->total_memory_usage_bytes() -
+                    resource_pool_->acquired_memory_usage_bytes());
 }
 
 bool TileManager::UpdateVisibleTiles() {
@@ -391,9 +393,11 @@
 void TileManager::GetMemoryStats(
     size_t* memory_required_bytes,
     size_t* memory_nice_to_have_bytes,
+    size_t* memory_allocated_bytes,
     size_t* memory_used_bytes) const {
   *memory_required_bytes = 0;
   *memory_nice_to_have_bytes = 0;
+  *memory_allocated_bytes = resource_pool_->total_memory_usage_bytes();
   *memory_used_bytes = resource_pool_->acquired_memory_usage_bytes();
   for (TileMap::const_iterator it = tiles_.begin();
        it != tiles_.end();
@@ -440,13 +444,16 @@
 
   size_t memory_required_bytes;
   size_t memory_nice_to_have_bytes;
+  size_t memory_allocated_bytes;
   size_t memory_used_bytes;
   GetMemoryStats(&memory_required_bytes,
                  &memory_nice_to_have_bytes,
+                 &memory_allocated_bytes,
                  &memory_used_bytes);
   requirements->SetInteger("memory_required_bytes", memory_required_bytes);
   requirements->SetInteger("memory_nice_to_have_bytes",
                            memory_nice_to_have_bytes);
+  requirements->SetInteger("memory_allocated_bytes", memory_allocated_bytes);
   requirements->SetInteger("memory_used_bytes", memory_used_bytes);
   return requirements.PassAs<base::Value>();
 }
@@ -477,33 +484,19 @@
 
   // Now give memory out to the tiles until we're out, and build
   // the needs-to-be-rasterized queue.
-  size_t bytes_releasable = 0;
-  size_t resources_releasable = 0;
-  for (PrioritizedTileSet::PriorityIterator it(tiles);
-       it;
-       ++it) {
-    const Tile* tile = *it;
-    const ManagedTileState& mts = tile->managed_state();
-    for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
-      if (mts.tile_versions[mode].resource_) {
-        bytes_releasable += tile->bytes_consumed_if_allocated();
-        resources_releasable++;
-      }
-    }
-  }
-
   all_tiles_that_need_to_be_rasterized_have_memory_ = true;
   all_tiles_required_for_activation_have_memory_ = true;
   all_tiles_required_for_activation_have_been_initialized_ = true;
 
   // Cast to prevent overflow.
   int64 bytes_available =
-      static_cast<int64>(bytes_releasable) +
+      static_cast<int64>(bytes_releasable_) +
       static_cast<int64>(global_state_.memory_limit_in_bytes) -
       static_cast<int64>(resource_pool_->acquired_memory_usage_bytes());
-  int resources_available = resources_releasable +
-                            global_state_.num_resources_limit -
-                            resource_pool_->NumResources();
+  int resources_available =
+      resources_releasable_ +
+      global_state_.num_resources_limit -
+      resource_pool_->acquired_resource_count();
 
   size_t bytes_allocatable =
       std::max(static_cast<int64>(0), bytes_available);
@@ -515,7 +508,7 @@
   bool oomed = false;
 
   unsigned schedule_priority = 1u;
-  for (PrioritizedTileSet::PriorityIterator it(tiles);
+  for (PrioritizedTileSet::Iterator it(tiles, true);
        it;
        ++it) {
     Tile* tile = *it;
@@ -598,6 +591,7 @@
       all_tiles_that_need_to_be_rasterized_have_memory_ = false;
       if (tile->required_for_activation())
         all_tiles_required_for_activation_have_memory_ = false;
+      it.DisablePriorityOrdering();
       continue;
     }
 
@@ -615,7 +609,7 @@
   memory_stats_from_last_assign_.bytes_allocated =
       bytes_allocatable - bytes_left;
   memory_stats_from_last_assign_.bytes_unreleasable =
-      bytes_allocatable - bytes_releasable;
+      bytes_allocatable - bytes_releasable_;
   memory_stats_from_last_assign_.bytes_over =
       bytes_that_exceeded_memory_budget;
 }
@@ -649,6 +643,12 @@
   if (mts.tile_versions[mode].resource_) {
     resource_pool_->ReleaseResource(
         mts.tile_versions[mode].resource_.Pass());
+
+    DCHECK_GE(bytes_releasable_, tile->bytes_consumed_if_allocated());
+    DCHECK_GE(resources_releasable_, 1u);
+
+    bytes_releasable_ -= tile->bytes_consumed_if_allocated();
+    --resources_releasable_;
   }
 }
 
@@ -700,6 +700,10 @@
     tasks.Append(tile_version.raster_task_, tile->required_for_activation());
   }
 
+  // We must reduce the amount of unused resoruces before calling
+  // ScheduleTasks to prevent usage from rising above limits.
+  resource_pool_->ReduceResourceUsage();
+
   // Schedule running of |tasks|. This replaces any previously
   // scheduled tasks and effectively cancels all tasks not present
   // in |tasks|.
@@ -722,8 +726,9 @@
   ManagedTileState& mts = tile->managed_state();
 
   scoped_ptr<ResourcePool::Resource> resource =
-      resource_pool_->AcquireResource(tile->tile_size_.size(),
-                                      texture_format_);
+      resource_pool_->AcquireResource(
+          tile->tile_size_.size(),
+          raster_worker_pool_->GetResourceFormat());
   const Resource* const_resource = resource.get();
 
   // Create and queue all image decode tasks that this tile depends on.
@@ -828,6 +833,9 @@
   } else {
     tile_version.set_use_resource();
     tile_version.resource_ = resource.Pass();
+
+    bytes_releasable_ += tile->bytes_consumed_if_allocated();
+    ++resources_releasable_;
   }
 
   FreeUnusedResourcesForTile(tile);
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 2e226c9..3b6f2e8 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -69,6 +69,7 @@
   scoped_ptr<base::Value> AllTilesAsValue() const;
   void GetMemoryStats(size_t* memory_required_bytes,
                       size_t* memory_nice_to_have_bytes,
+                      size_t* memory_allocated_bytes,
                       size_t* memory_used_bytes) const;
 
   const MemoryHistory::Entry& memory_stats_from_last_assign() const {
@@ -79,18 +80,36 @@
     return all_tiles_required_for_activation_have_been_initialized_;
   }
 
+  void InitializeTilesWithResourcesForTesting(
+      const std::vector<Tile*>& tiles,
+      ResourceProvider* resource_provider) {
+    for (size_t i = 0; i < tiles.size(); ++i) {
+      ManagedTileState& mts = tiles[i]->managed_state();
+      ManagedTileState::TileVersion& tile_version =
+          mts.tile_versions[HIGH_QUALITY_NO_LCD_RASTER_MODE];
+
+      tile_version.resource_ = make_scoped_ptr(
+          new ResourcePool::Resource(resource_provider,
+                                     gfx::Size(1, 1),
+                                     resource_provider->best_texture_format()));
+
+      bytes_releasable_ += tiles[i]->bytes_consumed_if_allocated();
+      ++resources_releasable_;
+    }
+  }
+
  protected:
   TileManager(TileManagerClient* client,
               ResourceProvider* resource_provider,
               scoped_ptr<RasterWorkerPool> raster_worker_pool,
               size_t num_raster_threads,
-              RenderingStatsInstrumentation* rendering_stats_instrumentation,
-              GLenum texture_format);
+              RenderingStatsInstrumentation* rendering_stats_instrumentation);
 
   // Methods called by Tile
   friend class Tile;
   void RegisterTile(Tile* tile);
   void UnregisterTile(Tile* tile);
+  void DidChangeTilePriority(Tile* tile);
 
   // Overriden from RasterWorkerPoolClient:
   virtual bool ShouldForceTasksRequiredForActivationToComplete() const
@@ -109,7 +128,6 @@
       PrioritizedTileSet* tiles,
       TileVector* tiles_that_need_to_be_rasterized);
   void GetTilesWithAssignedBins(PrioritizedTileSet* tiles);
-  void GetPrioritizedTileSet(PrioritizedTileSet* tiles);
 
  private:
   void OnImageDecodeTaskCompleted(
@@ -132,6 +150,7 @@
       Tile* tile, skia::LazyPixelRef* pixel_ref);
   RasterWorkerPool::RasterTask CreateRasterTask(Tile* tile);
   scoped_ptr<base::Value> GetMemoryRequirementsAsValue() const;
+  PrioritizedTileSet* GetPrioritizedTileSet();
 
   TileManagerClient* client_;
   scoped_ptr<ResourcePool> resource_pool_;
@@ -142,11 +161,15 @@
   TileMap tiles_;
 
   PrioritizedTileSet prioritized_tiles_;
+  bool prioritized_tiles_dirty_;
 
   bool all_tiles_that_need_to_be_rasterized_have_memory_;
   bool all_tiles_required_for_activation_have_memory_;
   bool all_tiles_required_for_activation_have_been_initialized_;
 
+  size_t bytes_releasable_;
+  size_t resources_releasable_;
+
   bool ever_exceeded_memory_budget_;
   MemoryHistory::Entry memory_stats_from_last_assign_;
 
@@ -154,8 +177,6 @@
 
   bool did_initialize_visible_tile_;
 
-  GLenum texture_format_;
-
   typedef base::hash_map<uint32_t, RasterWorkerPool::Task> PixelRefTaskMap;
   typedef base::hash_map<int, PixelRefTaskMap> LayerPixelRefTaskMap;
   LayerPixelRefTaskMap image_decode_tasks_;
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index ca6f997..89a3092 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -6,6 +6,7 @@
 #include "cc/resources/tile.h"
 #include "cc/resources/tile_priority.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/fake_tile_manager.h"
 #include "cc/test/fake_tile_manager_client.h"
@@ -30,6 +31,8 @@
   // Overridden from testing::Test:
   virtual void SetUp() OVERRIDE {
     output_surface_ = FakeOutputSurface::Create3d();
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
     resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
     tile_manager_ = make_scoped_ptr(
         new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
@@ -122,6 +125,7 @@
   LayerTreeSettings settings_;
   scoped_ptr<FakeTileManager> tile_manager_;
   scoped_refptr<FakePicturePileImpl> picture_pile_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<FakeOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
 
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 6fb0690..d3b9fac 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "cc/resources/tile.h"
 #include "cc/resources/tile_priority.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/fake_tile_manager.h"
 #include "cc/test/fake_tile_manager_client.h"
@@ -22,6 +23,8 @@
                   TileMemoryLimitPolicy memory_limit_policy,
                   TreePriority tree_priority) {
     output_surface_ = FakeOutputSurface::Create3d();
+    CHECK(output_surface_->BindToClient(&output_surface_client_));
+
     resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
     tile_manager_ = make_scoped_ptr(
         new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
@@ -41,6 +44,7 @@
       state.memory_limit_in_bytes = 100 * 1000 * 1000;
       state.num_resources_limit = max_tiles;
     }
+    state.unused_memory_limit_in_bytes = state.memory_limit_in_bytes;
     state.memory_limit_policy = memory_limit_policy;
     state.tree_priority = tree_priority;
 
@@ -53,6 +57,7 @@
     gfx::Size tile_size = settings_.default_tile_size;
     state.memory_limit_in_bytes =
         max_memory_tiles_ * 4 * tile_size.width() * tile_size.height();
+    state.unused_memory_limit_in_bytes = state.memory_limit_in_bytes;
     state.memory_limit_policy = memory_limit_policy_;
     state.num_resources_limit = 100;
     state.tree_priority = tree_priority;
@@ -66,15 +71,16 @@
     testing::Test::TearDown();
   }
 
-  TileVector CreateTiles(int count,
-                         TilePriority active_priority,
-                         TilePriority pending_priority) {
+  TileVector CreateTilesWithSize(int count,
+                                 TilePriority active_priority,
+                                 TilePriority pending_priority,
+                                 gfx::Size tile_size) {
     TileVector tiles;
     for (int i = 0; i < count; ++i) {
       scoped_refptr<Tile> tile =
           make_scoped_refptr(new Tile(tile_manager_.get(),
                                       picture_pile_.get(),
-                                      settings_.default_tile_size,
+                                      tile_size,
                                       gfx::Rect(),
                                       gfx::Rect(),
                                       1.0,
@@ -88,6 +94,15 @@
     return tiles;
   }
 
+  TileVector CreateTiles(int count,
+                         TilePriority active_priority,
+                         TilePriority pending_priority) {
+    return CreateTilesWithSize(count,
+                               active_priority,
+                               pending_priority,
+                               settings_.default_tile_size);
+  }
+
   FakeTileManager* tile_manager() {
     return tile_manager_.get();
   }
@@ -119,6 +134,7 @@
   LayerTreeSettings settings_;
   scoped_ptr<FakeTileManager> tile_manager_;
   scoped_refptr<FakePicturePileImpl> picture_pile_;
+  FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<FakeOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
   TileMemoryLimitPolicy memory_limit_policy_;
@@ -461,6 +477,48 @@
   EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
 }
 
+TEST_P(TileManagerTest, RespectMemoryLimit) {
+  Initialize(5, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
+  TileVector large_tiles = CreateTiles(
+      5, TilePriorityForNowBin(), TilePriority());
+
+  size_t memory_required_bytes;
+  size_t memory_nice_to_have_bytes;
+  size_t memory_allocated_bytes;
+  size_t memory_used_bytes;
+
+  tile_manager()->ManageTiles();
+  tile_manager()->GetMemoryStats(&memory_required_bytes,
+                                 &memory_nice_to_have_bytes,
+                                 &memory_allocated_bytes,
+                                 &memory_used_bytes);
+  // Allocated bytes should never be more than the memory limit.
+  EXPECT_LE(memory_allocated_bytes,
+            tile_manager()->GlobalState().memory_limit_in_bytes);
+
+  // Finish raster of large tiles.
+  tile_manager()->UpdateVisibleTiles();
+
+  // Remove all large tiles. This will leave the memory currently
+  // used by these tiles as unused when ManageTiles() is called.
+  large_tiles.clear();
+
+  // Create a new set of tiles using a different size. These tiles
+  // can use the memory currently assigned to the lerge tiles but
+  // they can't use the same resources as the size doesn't match.
+  TileVector small_tiles = CreateTilesWithSize(
+      5, TilePriorityForNowBin(), TilePriority(), gfx::Size(128, 128));
+
+  tile_manager()->ManageTiles();
+  tile_manager()->GetMemoryStats(&memory_required_bytes,
+                                 &memory_nice_to_have_bytes,
+                                 &memory_allocated_bytes,
+                                 &memory_used_bytes);
+  // Allocated bytes should never be more than the memory limit.
+  EXPECT_LE(memory_allocated_bytes,
+            tile_manager()->GlobalState().memory_limit_in_bytes);
+}
+
 // If true, the max tile limit should be applied as bytes; if false,
 // as num_resources_limit.
 INSTANTIATE_TEST_CASE_P(TileManagerTests,
diff --git a/cc/resources/transferable_resource.cc b/cc/resources/transferable_resource.cc
index be2be1a..9e90696 100644
--- a/cc/resources/transferable_resource.cc
+++ b/cc/resources/transferable_resource.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/logging.h"
+#include "cc/resources/returned_resource.h"
 #include "cc/resources/transferable_resource.h"
 
 namespace cc {
@@ -17,4 +18,22 @@
 TransferableResource::~TransferableResource() {
 }
 
+ReturnedResource TransferableResource::ToReturnedResource() const {
+  ReturnedResource returned;
+  returned.id = id;
+  returned.sync_point = sync_point;
+  returned.filter = filter;
+  returned.count = 1;
+  return returned;
+}
+
+// static
+void TransferableResource::ReturnResources(
+    const TransferableResourceArray& input,
+    ReturnedResourceArray* output) {
+  for (TransferableResourceArray::const_iterator it = input.begin();
+       it != input.end(); ++it)
+    output->push_back(it->ToReturnedResource());
+}
+
 }  // namespace cc
diff --git a/cc/resources/transferable_resource.h b/cc/resources/transferable_resource.h
index 5c979433..be6902c 100644
--- a/cc/resources/transferable_resource.h
+++ b/cc/resources/transferable_resource.h
@@ -14,10 +14,19 @@
 
 namespace cc {
 
+struct ReturnedResource;
+typedef std::vector<ReturnedResource> ReturnedResourceArray;
+struct TransferableResource;
+typedef std::vector<TransferableResource> TransferableResourceArray;
+
 struct CC_EXPORT TransferableResource {
   TransferableResource();
   ~TransferableResource();
 
+  ReturnedResource ToReturnedResource() const;
+  static void ReturnResources(const TransferableResourceArray& input,
+                              ReturnedResourceArray* output);
+
   unsigned id;
   unsigned sync_point;
   uint32 format;
@@ -26,8 +35,6 @@
   gpu::Mailbox mailbox;
 };
 
-typedef std::vector<TransferableResource> TransferableResourceArray;
-
 }  // namespace cc
 
 #endif  // CC_RESOURCES_TRANSFERABLE_RESOURCE_H_
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 4239e98..33682eb 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -10,6 +10,7 @@
 #include "gpu/GLES2/gl2extchromium.h"
 #include "media/base/video_frame.h"
 #include "media/filters/skcanvas_video_renderer.h"
+#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/size_conversions.h"
@@ -23,8 +24,10 @@
 
 VideoFrameExternalResources::~VideoFrameExternalResources() {}
 
-VideoResourceUpdater::VideoResourceUpdater(ResourceProvider* resource_provider)
-    : resource_provider_(resource_provider) {
+VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
+                                           ResourceProvider* resource_provider)
+    : context_provider_(context_provider),
+      resource_provider_(resource_provider) {
 }
 
 VideoResourceUpdater::~VideoResourceUpdater() {
@@ -138,7 +141,7 @@
       input_frame_format != media::VideoFrame::YV16)
     return VideoFrameExternalResources();
 
-  bool software_compositor = !resource_provider_->GraphicsContext3D();
+  bool software_compositor = context_provider_ == NULL;
 
   GLenum output_resource_format = kYUVResourceFormat;
   size_t output_plane_count =
@@ -197,9 +200,10 @@
       DCHECK(mailbox.IsZero());
 
       if (!software_compositor) {
+        DCHECK(context_provider_);
+
         WebKit::WebGraphicsContext3D* context =
-            resource_provider_->GraphicsContext3D();
-        DCHECK(context);
+            context_provider_->Context3d();
 
         GLC(context, context->genMailboxCHROMIUM(mailbox.name));
         if (mailbox.IsZero()) {
@@ -330,9 +334,7 @@
   if (frame_format != media::VideoFrame::NATIVE_TEXTURE)
       return VideoFrameExternalResources();
 
-  WebKit::WebGraphicsContext3D* context =
-      resource_provider_->GraphicsContext3D();
-  if (!context)
+  if (!context_provider_)
     return VideoFrameExternalResources();
 
   VideoFrameExternalResources external_resources;
@@ -377,10 +379,11 @@
     return;
   }
 
-  WebKit::WebGraphicsContext3D* context =
-      updater->resource_provider_->GraphicsContext3D();
-  if (context && sync_point)
-    GLC(context, context->waitSyncPoint(sync_point));
+  ContextProvider* context_provider = updater->context_provider_;
+  if (context_provider && sync_point) {
+    GLC(context_provider->Context3d(),
+        context_provider->Context3d()->waitSyncPoint(sync_point));
+  }
 
   if (lost_resource) {
     updater->DeleteResource(data.resource_id);
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 9be79d1..cf71cfa 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -21,6 +21,7 @@
 }
 
 namespace cc {
+class ContextProvider;
 class ResourceProvider;
 
 class CC_EXPORT VideoFrameExternalResources {
@@ -61,7 +62,8 @@
 class CC_EXPORT VideoResourceUpdater
     : public base::SupportsWeakPtr<VideoResourceUpdater> {
  public:
-  explicit VideoResourceUpdater(ResourceProvider* resource_provider);
+  explicit VideoResourceUpdater(ContextProvider* context_provider,
+                                ResourceProvider* resource_provider);
   ~VideoResourceUpdater();
 
   VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
@@ -102,6 +104,7 @@
                               unsigned sync_point,
                               bool lost_resource);
 
+  ContextProvider* context_provider_;
   ResourceProvider* resource_provider_;
   scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_;
 
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index ff574ff..60673ed 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -5,9 +5,10 @@
 #include "cc/resources/video_resource_updater.h"
 
 #include "base/memory/shared_memory.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/resources/resource_provider.h"
 #include "cc/test/fake_output_surface.h"
-#include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "media/base/video_frame.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -21,8 +22,9 @@
         TestWebGraphicsContext3D::Create();
     context3d_ = context3d.get();
 
-    output_surface3d_ = FakeOutputSurface::Create3d(
-        context3d.PassAs<WebKit::WebGraphicsContext3D>());
+    output_surface3d_ =
+        FakeOutputSurface::Create3d(context3d.Pass());
+    CHECK(output_surface3d_->BindToClient(&client_));
     resource_provider3d_ =
         ResourceProvider::Create(output_surface3d_.get(), 0);
   }
@@ -50,12 +52,14 @@
   }
 
   TestWebGraphicsContext3D* context3d_;
+  FakeOutputSurfaceClient client_;
   scoped_ptr<FakeOutputSurface> output_surface3d_;
   scoped_ptr<ResourceProvider> resource_provider3d_;
 };
 
 TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
-  VideoResourceUpdater updater(resource_provider3d_.get());
+  VideoResourceUpdater updater(output_surface3d_->context_provider().get(),
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
@@ -64,7 +68,8 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, LostContextForSoftwareFrame) {
-  VideoResourceUpdater updater(resource_provider3d_.get());
+  VideoResourceUpdater updater(output_surface3d_->context_provider().get(),
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
 
   // Fail while creating the mailbox for the second YUV plane.
diff --git a/cc/scheduler/delay_based_time_source.cc b/cc/scheduler/delay_based_time_source.cc
index 1b162c9..a5b6f73 100644
--- a/cc/scheduler/delay_based_time_source.cc
+++ b/cc/scheduler/delay_based_time_source.cc
@@ -20,7 +20,7 @@
 // kDoubleTickDivisor prevents ticks from running within the specified
 // fraction of an interval.  This helps account for jitter in the timebase as
 // well as quick timer reactivation.
-static const int kDoubleTickDivisor = 4;
+static const int kDoubleTickDivisor = 2;
 
 // kIntervalChangeThreshold is the fraction of the interval that will trigger an
 // immediate interval change.  kPhaseChangeThreshold is the fraction of the
@@ -51,18 +51,30 @@
 
 DelayBasedTimeSource::~DelayBasedTimeSource() {}
 
-void DelayBasedTimeSource::SetActive(bool active) {
+base::TimeTicks DelayBasedTimeSource::SetActive(bool active) {
   TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active);
   if (active == active_)
-    return;
+    return base::TimeTicks();
   active_ = active;
 
   if (!active_) {
     weak_factory_.InvalidateWeakPtrs();
-    return;
+    return base::TimeTicks();
   }
 
   PostNextTickTask(Now());
+
+  // Determine if there was a tick that was missed while not active.
+  base::TimeTicks last_tick_time_if_always_active =
+    current_parameters_.tick_target - current_parameters_.interval;
+  base::TimeTicks new_tick_time_threshold =
+    last_tick_time_ + current_parameters_.interval / kDoubleTickDivisor;
+  if (last_tick_time_if_always_active >  new_tick_time_threshold) {
+    last_tick_time_ = last_tick_time_if_always_active;
+    return last_tick_time_;
+  }
+
+  return base::TimeTicks();
 }
 
 bool DelayBasedTimeSource::Active() const { return active_; }
@@ -193,9 +205,17 @@
 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) {
   const base::TimeDelta epsilon(base::TimeDelta::FromMicroseconds(1));
   base::TimeDelta new_interval = next_parameters_.interval;
-  int intervals_elapsed =
-      (now - next_parameters_.tick_target + new_interval - epsilon) /
-      new_interval;
+
+  // Integer division rounds towards 0, but we always want to round down the
+  // number of intervals_elapsed, so we need the extra condition here.
+  int intervals_elapsed;
+  if (next_parameters_.tick_target < now) {
+    intervals_elapsed =
+        (now - next_parameters_.tick_target + new_interval - epsilon) /
+        new_interval;
+  } else {
+    intervals_elapsed = (now - next_parameters_.tick_target) / new_interval;
+  }
   base::TimeTicks new_tick_target =
       next_parameters_.tick_target + new_interval * intervals_elapsed;
   DCHECK(now <= new_tick_target)
diff --git a/cc/scheduler/delay_based_time_source.h b/cc/scheduler/delay_based_time_source.h
index 009b9a3..55aac5a 100644
--- a/cc/scheduler/delay_based_time_source.h
+++ b/cc/scheduler/delay_based_time_source.h
@@ -27,7 +27,7 @@
   virtual void SetTimebaseAndInterval(base::TimeTicks timebase,
                                       base::TimeDelta interval) OVERRIDE;
 
-  virtual void SetActive(bool active) OVERRIDE;
+  virtual base::TimeTicks SetActive(bool active) OVERRIDE;
   virtual bool Active() const OVERRIDE;
 
   // Get the last and next tick times. nextTimeTime() returns null when
diff --git a/cc/scheduler/delay_based_time_source_unittest.cc b/cc/scheduler/delay_based_time_source_unittest.cc
index ac54f57..77d570f 100644
--- a/cc/scheduler/delay_based_time_source_unittest.cc
+++ b/cc/scheduler/delay_based_time_source_unittest.cc
@@ -246,10 +246,10 @@
   timer->SetTimebaseAndInterval(timer->Now() + jitter, Interval());
 
   EXPECT_FALSE(client.TickCalled());  // Make sure pending tasks were canceled.
-  EXPECT_EQ(7, task_runner->NextPendingTaskDelay().InMilliseconds());
+  EXPECT_EQ(16 + 7, task_runner->NextPendingTaskDelay().InMilliseconds());
 
   // Tick, then shift timebase by -7ms.
-  timer->SetNow(timer->Now() + jitter);
+  timer->SetNow(timer->Now() + Interval() + jitter);
   task_runner->RunPendingTasks();
 
   EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
@@ -305,6 +305,115 @@
   EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
 }
 
+TEST(DelayBasedTimeSource, JitteryRuntimeWithFutureTimebases) {
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner =
+      new base::TestSimpleTaskRunner;
+  FakeTimeSourceClient client;
+  scoped_refptr<FakeDelayBasedTimeSource> timer =
+      FakeDelayBasedTimeSource::Create(Interval(), task_runner.get());
+  timer->SetClient(&client);
+  timer->SetActive(true);
+
+  // Run the first tick.
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  base::TimeTicks future_timebase = timer->Now() + Interval() * 10;
+
+  // 1ms jitter
+  base::TimeDelta jitter1 = base::TimeDelta::FromMilliseconds(1);
+
+  // Tick with +1ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() + jitter1);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(15, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with 0ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() - jitter1);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with -1ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() - jitter1);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(17, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with 0ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() + jitter1);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // 8 ms jitter
+  base::TimeDelta jitter8 = base::TimeDelta::FromMilliseconds(8);
+
+  // Tick with +8ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() + jitter8);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(8, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with 0ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() - jitter8);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with -8ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() - jitter8);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(24, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with 0ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() + jitter8);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // 15 ms jitter
+  base::TimeDelta jitter15  = base::TimeDelta::FromMilliseconds(15);
+
+  // Tick with +15ms jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() + jitter15);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(1, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with 0ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() - jitter15);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with -15ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() - jitter15);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(31, task_runner->NextPendingTaskDelay().InMilliseconds());
+
+  // Tick with 0ms of jitter
+  future_timebase += Interval();
+  timer->SetTimebaseAndInterval(future_timebase, Interval());
+  timer->SetNow(timer->Now() + Interval() + jitter15);
+  task_runner->RunPendingTasks();
+  EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
+}
+
 TEST(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) {
   int num_iterations = 10;
 
diff --git a/cc/scheduler/frame_rate_controller.cc b/cc/scheduler/frame_rate_controller.cc
index 4844b16..54c1bda 100644
--- a/cc/scheduler/frame_rate_controller.cc
+++ b/cc/scheduler/frame_rate_controller.cc
@@ -70,11 +70,16 @@
   if (active_ == active)
     return BeginFrameArgs();
   TRACE_EVENT1("cc", "FrameRateController::SetActive", "active", active);
-  bool just_activated = active && !active_;
   active_ = active;
 
   if (is_time_source_throttling_) {
-    time_source_->SetActive(active);
+    base::TimeTicks missed_tick_time = time_source_->SetActive(active);
+    if (!missed_tick_time.is_null()) {
+      base::TimeTicks deadline = NextTickTime();
+      return BeginFrameArgs::Create(missed_tick_time,
+                                    deadline,
+                                    interval_);
+    }
   } else {
     if (active)
       PostManualTick();
@@ -82,12 +87,6 @@
       weak_factory_.InvalidateWeakPtrs();
   }
 
-  if (just_activated) {
-    // TODO(brianderson): Use an adaptive parent compositor deadline.
-    base::TimeTicks frame_time = NextTickTime() - interval_;
-    base::TimeTicks deadline = NextTickTime();
-    return BeginFrameArgs::Create(frame_time, deadline, interval_);
-  }
   return BeginFrameArgs();
 }
 
diff --git a/cc/scheduler/frame_rate_controller.h b/cc/scheduler/frame_rate_controller.h
index ed76923..b68c73d 100644
--- a/cc/scheduler/frame_rate_controller.h
+++ b/cc/scheduler/frame_rate_controller.h
@@ -61,12 +61,6 @@
   int MaxSwapsPending() const { return max_swaps_pending_; }
   int NumSwapsPendingForTesting() const { return num_frames_pending_; }
 
-  // This returns null for unthrottled frame-rate.
-  base::TimeTicks NextTickTime();
-
-  // This returns now for unthrottled frame-rate.
-  base::TimeTicks LastTickTime();
-
   void SetTimebaseAndInterval(base::TimeTicks timebase,
                               base::TimeDelta interval);
   void SetDeadlineAdjustment(base::TimeDelta delta);
@@ -78,6 +72,11 @@
   void PostManualTick();
   void ManualTick();
 
+    // This returns null for unthrottled frame-rate.
+  base::TimeTicks NextTickTime();
+  // This returns now for unthrottled frame-rate.
+  base::TimeTicks LastTickTime();
+
   FrameRateControllerClient* client_;
   int num_frames_pending_;
   int max_swaps_pending_;
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 010cc99..3e8833f 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -7,6 +7,7 @@
 #include "base/auto_reset.h"
 #include "base/debug/trace_event.h"
 #include "base/logging.h"
+#include "cc/debug/traced_value.h"
 
 namespace cc {
 
@@ -199,8 +200,13 @@
 
   base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
 
-  SchedulerStateMachine::Action action = state_machine_.NextAction();
-  while (action != SchedulerStateMachine::ACTION_NONE) {
+  SchedulerStateMachine::Action action;
+  do {
+    action = state_machine_.NextAction();
+    TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
+                 "SchedulerStateMachine",
+                 "state",
+                 TracedValue::FromValue(state_machine_.AsValue().release()));
     state_machine_.UpdateState(action);
     switch (action) {
       case SchedulerStateMachine::ACTION_NONE:
@@ -223,6 +229,10 @@
       case SchedulerStateMachine::ACTION_DRAW_FORCED:
         DrawAndSwapForced();
         break;
+      case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
+        // No action is actually performed, but this allows the state machine to
+        // advance out of its waiting to draw state without actually drawing.
+        break;
       case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
         client_->ScheduledActionBeginOutputSurfaceCreation();
         break;
@@ -230,15 +240,14 @@
         client_->ScheduledActionAcquireLayerTexturesForMainThread();
         break;
     }
-    action = state_machine_.NextAction();
-  }
+  } while (action != SchedulerStateMachine::ACTION_NONE);
 
   SetupNextBeginFrameIfNeeded();
   client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
 }
 
 bool Scheduler::WillDrawIfNeeded() const {
-  return !state_machine_.DrawSuspendedUntilCommit();
+  return !state_machine_.PendingDrawsShouldBeAborted();
 }
 
 }  // namespace cc
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 230f20d..c64dad0 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -105,7 +105,9 @@
 
   void BeginFrame(const BeginFrameArgs& args);
 
-  std::string StateAsStringForTesting() { return state_machine_.ToString(); }
+  scoped_ptr<base::Value> StateAsValueForTesting() {
+    return state_machine_.AsValue().Pass();
+  }
 
  private:
   Scheduler(SchedulerClient* client,
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index ed9c15f..5108a11 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -7,6 +7,7 @@
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "base/values.h"
 
 namespace cc {
 
@@ -40,68 +41,159 @@
       output_surface_state_(OUTPUT_SURFACE_LOST),
       did_create_and_initialize_first_output_surface_(false) {}
 
-std::string SchedulerStateMachine::ToString() {
-  std::string str;
-  base::StringAppendF(&str,
-                      "settings_.impl_side_painting = %d; ",
-                      settings_.impl_side_painting);
-  base::StringAppendF(&str, "commit_state_ = %d; ", commit_state_);
-  base::StringAppendF(&str, "commit_count_ = %d; ", commit_count_);
-  base::StringAppendF(
-      &str, "current_frame_number_ = %d; ", current_frame_number_);
-  base::StringAppendF(&str,
-                      "last_frame_number_where_draw_was_called_ = %d; ",
-                      last_frame_number_where_draw_was_called_);
-  base::StringAppendF(
-      &str,
-      "last_frame_number_where_tree_activation_attempted_ = %d; ",
-      last_frame_number_where_tree_activation_attempted_);
-  base::StringAppendF(
-      &str,
-      "last_frame_number_where_update_visible_tiles_was_called_ = %d; ",
+const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
+  switch (state) {
+    case COMMIT_STATE_IDLE:
+      return "COMMIT_STATE_IDLE";
+    case COMMIT_STATE_FRAME_IN_PROGRESS:
+      return "COMMIT_STATE_FRAME_IN_PROGRESS";
+    case COMMIT_STATE_READY_TO_COMMIT:
+      return "COMMIT_STATE_READY_TO_COMMIT";
+    case COMMIT_STATE_WAITING_FOR_FIRST_DRAW:
+      return "COMMIT_STATE_WAITING_FOR_FIRST_DRAW";
+    case COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW:
+      return "COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW";
+  }
+  NOTREACHED();
+  return "???";
+}
+
+const char* SchedulerStateMachine::TextureStateToString(TextureState state) {
+  switch (state) {
+    case LAYER_TEXTURE_STATE_UNLOCKED:
+      return "LAYER_TEXTURE_STATE_UNLOCKED";
+    case LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD:
+      return "LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD";
+    case LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD:
+      return "LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD";
+  }
+  NOTREACHED();
+  return "???";
+}
+
+const char* SchedulerStateMachine::OutputSurfaceStateToString(
+    OutputSurfaceState state) {
+  switch (state) {
+    case OUTPUT_SURFACE_ACTIVE:
+      return "OUTPUT_SURFACE_ACTIVE";
+    case OUTPUT_SURFACE_LOST:
+      return "OUTPUT_SURFACE_LOST";
+    case OUTPUT_SURFACE_CREATING:
+      return "OUTPUT_SURFACE_CREATING";
+  }
+  NOTREACHED();
+  return "???";
+}
+
+const char* SchedulerStateMachine::ActionToString(Action action) {
+  switch (action) {
+    case ACTION_NONE:
+      return "ACTION_NONE";
+    case ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
+      return "ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD";
+    case ACTION_COMMIT:
+      return "ACTION_COMMIT";
+    case ACTION_UPDATE_VISIBLE_TILES:
+      return "ACTION_UPDATE_VISIBLE_TILES";
+    case ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:
+      return "ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED";
+    case ACTION_DRAW_IF_POSSIBLE:
+      return "ACTION_DRAW_IF_POSSIBLE";
+    case ACTION_DRAW_FORCED:
+      return "ACTION_DRAW_FORCED";
+    case ACTION_DRAW_AND_SWAP_ABORT:
+      return "ACTION_DRAW_AND_SWAP_ABORT";
+    case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
+      return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
+    case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
+      return "ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD";
+  }
+  NOTREACHED();
+  return "???";
+}
+
+scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const  {
+  scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+
+  scoped_ptr<base::DictionaryValue> major_state(new base::DictionaryValue);
+  major_state->SetString("next_action", ActionToString(NextAction()));
+  major_state->SetString("commit_state", CommitStateToString(commit_state_));
+  major_state->SetString("texture_state_",
+                         TextureStateToString(texture_state_));
+  major_state->SetString("output_surface_state_",
+                         OutputSurfaceStateToString(output_surface_state_));
+  state->Set("major_state", major_state.release());
+
+  scoped_ptr<base::DictionaryValue> timestamps_state(new base::DictionaryValue);
+  base::TimeTicks now = base::TimeTicks::Now();
+  timestamps_state->SetDouble(
+      "0_interval", last_begin_frame_args_.interval.InMicroseconds() / 1000.0L);
+  timestamps_state->SetDouble(
+      "1_now_to_deadline",
+      (last_begin_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
+  timestamps_state->SetDouble(
+      "2_frame_time_to_now",
+      (last_begin_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
+  timestamps_state->SetDouble(
+      "3_frame_time_to_deadline",
+      (last_begin_frame_args_.deadline - last_begin_frame_args_.frame_time)
+              .InMicroseconds() /
+          1000.0L);
+  timestamps_state->SetDouble(
+      "4_now", (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
+  timestamps_state->SetDouble(
+      "5_frame_time",
+      (last_begin_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() /
+          1000.0L);
+  timestamps_state->SetDouble(
+      "6_deadline",
+      (last_begin_frame_args_.deadline - base::TimeTicks()).InMicroseconds() /
+          1000.0L);
+  state->Set("major_timestamps_in_ms", timestamps_state.release());
+
+  scoped_ptr<base::DictionaryValue> minor_state(new base::DictionaryValue);
+  minor_state->SetInteger("commit_count", commit_count_);
+  minor_state->SetInteger("current_frame_number", current_frame_number_);
+  minor_state->SetInteger(
+      "last_frame_number_where_begin_frame_sent_to_main_thread",
+      last_frame_number_where_begin_frame_sent_to_main_thread_);
+  minor_state->SetInteger("last_frame_number_where_draw_was_called",
+                          last_frame_number_where_draw_was_called_);
+  minor_state->SetInteger("last_frame_number_where_tree_activation_attempted",
+                          last_frame_number_where_tree_activation_attempted_);
+  minor_state->SetInteger(
+      "last_frame_number_where_update_visible_tiles_was_called",
       last_frame_number_where_update_visible_tiles_was_called_);
-  base::StringAppendF(
-      &str, "consecutive_failed_draws_ = %d; ", consecutive_failed_draws_);
-  base::StringAppendF(
-      &str,
-      "maximum_number_of_failed_draws_before_draw_is_forced_ = %d; ",
+  minor_state->SetInteger("consecutive_failed_draws",
+                          consecutive_failed_draws_);
+  minor_state->SetInteger(
+      "maximum_number_of_failed_draws_before_draw_is_forced",
       maximum_number_of_failed_draws_before_draw_is_forced_);
-  base::StringAppendF(&str, "needs_redraw_ = %d; ", needs_redraw_);
-  base::StringAppendF(
-      &str, "swap_used_incomplete_tile_ = %d; ", swap_used_incomplete_tile_);
-  base::StringAppendF(
-      &str, "needs_forced_redraw_ = %d; ", needs_forced_redraw_);
-  base::StringAppendF(&str,
-                      "needs_forced_redraw_after_next_commit_ = %d; ",
-                      needs_forced_redraw_after_next_commit_);
-  base::StringAppendF(&str, "needs_commit_ = %d; ", needs_commit_);
-  base::StringAppendF(
-      &str, "needs_forced_commit_ = %d; ", needs_forced_commit_);
-  base::StringAppendF(&str,
-                      "expect_immediate_begin_frame_for_main_thread_ = %d; ",
-                      expect_immediate_begin_frame_for_main_thread_);
-  base::StringAppendF(&str,
-                      "main_thread_needs_layer_textures_ = %d; ",
-                      main_thread_needs_layer_textures_);
-  base::StringAppendF(&str, "inside_begin_frame_ = %d; ",
-      inside_begin_frame_);
-  base::StringAppendF(&str, "last_frame_time_ = %" PRId64 "; ",
-      (last_begin_frame_args_.frame_time - base::TimeTicks())
-          .InMilliseconds());
-  base::StringAppendF(&str, "last_deadline_ = %" PRId64 "; ",
-      (last_begin_frame_args_.deadline - base::TimeTicks()).InMilliseconds());
-  base::StringAppendF(&str, "last_interval_ = %" PRId64 "; ",
-      last_begin_frame_args_.interval.InMilliseconds());
-  base::StringAppendF(&str, "visible_ = %d; ", visible_);
-  base::StringAppendF(&str, "can_start_ = %d; ", can_start_);
-  base::StringAppendF(&str, "can_draw_ = %d; ", can_draw_);
-  base::StringAppendF(
-      &str, "draw_if_possible_failed_ = %d; ", draw_if_possible_failed_);
-  base::StringAppendF(&str, "has_pending_tree_ = %d; ", has_pending_tree_);
-  base::StringAppendF(&str, "texture_state_ = %d; ", texture_state_);
-  base::StringAppendF(
-      &str, "output_surface_state_ = %d; ", output_surface_state_);
-  return str;
+  minor_state->SetBoolean("needs_redraw", needs_redraw_);
+  minor_state->SetBoolean("swap_used_incomplete_tile",
+                          swap_used_incomplete_tile_);
+  minor_state->SetBoolean("needs_forced_redraw", needs_forced_redraw_);
+  minor_state->SetBoolean("needs_forced_redraw_after_next_commit",
+                          needs_forced_redraw_after_next_commit_);
+  minor_state->SetBoolean("needs_redraw_after_next_commit",
+                          needs_redraw_after_next_commit_);
+  minor_state->SetBoolean("needs_commit", needs_commit_);
+  minor_state->SetBoolean("needs_forced_commit", needs_forced_commit_);
+  minor_state->SetBoolean("expect_immediate_begin_frame_for_main_thread",
+                          expect_immediate_begin_frame_for_main_thread_);
+  minor_state->SetBoolean("main_thread_needs_layer_textures",
+                          main_thread_needs_layer_textures_);
+  minor_state->SetBoolean("inside_begin_frame", inside_begin_frame_);
+  minor_state->SetBoolean("visible", visible_);
+  minor_state->SetBoolean("can_start", can_start_);
+  minor_state->SetBoolean("can_draw", can_draw_);
+  minor_state->SetBoolean("has_pending_tree", has_pending_tree_);
+  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_);
+  state->Set("minor_state", minor_state.release());
+
+  return state.PassAs<base::Value>();
 }
 
 bool SchedulerStateMachine::HasDrawnThisFrame() const {
@@ -118,8 +210,24 @@
          last_frame_number_where_update_visible_tiles_was_called_;
 }
 
-void SchedulerStateMachine::SetPostCommitFlags() {
+void SchedulerStateMachine::HandleCommitInternal(bool commit_was_aborted) {
+  commit_count_++;
+
+  if (commit_was_aborted) {
+    commit_state_ = COMMIT_STATE_IDLE;
+  } else if (expect_immediate_begin_frame_for_main_thread_) {
+    commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW;
+  } else {
+    commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
+  }
+
+  if (!settings_.impl_side_painting && !commit_was_aborted)
+    needs_redraw_ = true;
+
   // This post-commit work is common to both completed and aborted commits.
+  if (draw_if_possible_failed_)
+    last_frame_number_where_draw_was_called_ = -1;
+
   if (needs_forced_redraw_after_next_commit_) {
     needs_forced_redraw_after_next_commit_ = false;
     needs_forced_redraw_ = true;
@@ -128,40 +236,52 @@
     needs_redraw_after_next_commit_ = false;
     needs_redraw_ = true;
   }
-  texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
+
+  // If we are planing to draw with the new commit, lock the layer textures for
+  // use on the impl thread. Otherwise, leave them unlocked.
+  if (!commit_was_aborted || needs_redraw_ || needs_forced_redraw_)
+    texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
+  else
+    texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
 }
 
-bool SchedulerStateMachine::DrawSuspendedUntilCommit() const {
+bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
+  // These are all the cases where, if we do not abort draws to make
+  // forward progress, we might deadlock with the main thread.
   if (!can_draw_)
     return true;
   if (!visible_)
     return true;
+  if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
+    return true;
   if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
     return true;
   return false;
 }
 
-bool SchedulerStateMachine::ScheduledToDraw() const {
-  if (!needs_redraw_)
-    return false;
-  if (DrawSuspendedUntilCommit())
-    return false;
-  return true;
-}
-
 bool SchedulerStateMachine::ShouldDraw() const {
+  // Always handle forced draws ASAP.
   if (needs_forced_redraw_)
     return true;
 
-  if (!ScheduledToDraw())
-    return false;
-  if (!inside_begin_frame_)
-    return false;
+  // If we are going to abort draws, we should do so ASAP.
+  if (PendingDrawsShouldBeAborted()) {
+    // TODO(brianderson): Remove the !has_pending_tree_ condition once
+    // the Scheduler controls activation. It's dangerous for us to rely on
+    // an eventual activation if we've lost the output surface.
+    return commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW &&
+           !has_pending_tree_;
+  }
+
+  // After this line, we only want to draw once per frame.
   if (HasDrawnThisFrame())
     return false;
-  if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
+
+  // We currently only draw within the BeginFrame.
+  if (!inside_begin_frame_)
     return false;
-  return true;
+
+  return needs_redraw_;
 }
 
 bool SchedulerStateMachine::ShouldAttemptTreeActivation() const {
@@ -185,12 +305,6 @@
   if (texture_state_ == LAYER_TEXTURE_STATE_UNLOCKED)
     return true;
   DCHECK_EQ(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
-  // Transfer the lock from impl thread to main thread immediately if the
-  // impl thread is not even scheduled to draw. Guards against deadlocking.
-  if (!ScheduledToDraw())
-    return true;
-  if (!BeginFrameNeededToDrawByImplThread())
-    return true;
   return false;
 }
 
@@ -251,21 +365,14 @@
         return ACTION_UPDATE_VISIBLE_TILES;
       if (ShouldAttemptTreeActivation())
         return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
-      if (ShouldDraw() || output_surface_state_ == OUTPUT_SURFACE_LOST) {
-        return needs_forced_redraw_ ? ACTION_DRAW_FORCED
-                                    : ACTION_DRAW_IF_POSSIBLE;
+      if (ShouldDraw()) {
+        if (needs_forced_redraw_)
+          return ACTION_DRAW_FORCED;
+        else if (PendingDrawsShouldBeAborted())
+          return ACTION_DRAW_AND_SWAP_ABORT;
+        else
+          return ACTION_DRAW_IF_POSSIBLE;
       }
-      // COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If
-      // can_draw_ is false or textures are not available, proceed to the next
-      // step (similar as in COMMIT_STATE_IDLE).
-      bool can_commit =
-          needs_forced_commit_ ||
-          (visible_ &&
-           current_frame_number_ >
-               last_frame_number_where_begin_frame_sent_to_main_thread_);
-      if (needs_commit_ && can_commit && DrawSuspendedUntilCommit())
-        return has_pending_tree_ ? ACTION_NONE
-                                 : ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
       return ACTION_NONE;
     }
 
@@ -311,38 +418,24 @@
           current_frame_number_;
       return;
 
-    case ACTION_COMMIT:
-      commit_count_++;
-      if (expect_immediate_begin_frame_for_main_thread_)
-        commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW;
-      else
-        commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
-      // When impl-side painting, we draw on activation instead of on commit.
-      if (!settings_.impl_side_painting)
-        needs_redraw_ = true;
-      if (draw_if_possible_failed_)
-        last_frame_number_where_draw_was_called_ = -1;
-      SetPostCommitFlags();
+    case ACTION_COMMIT: {
+      bool commit_was_aborted = false;
+      HandleCommitInternal(commit_was_aborted);
       return;
+    }
 
     case ACTION_DRAW_FORCED:
-    case ACTION_DRAW_IF_POSSIBLE:
-      needs_redraw_ = false;
-      needs_forced_redraw_ = false;
-      draw_if_possible_failed_ = false;
-      swap_used_incomplete_tile_ = false;
-      if (inside_begin_frame_)
-        last_frame_number_where_draw_was_called_ = current_frame_number_;
-      if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW) {
-        DCHECK(expect_immediate_begin_frame_for_main_thread_);
-        commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
-        expect_immediate_begin_frame_for_main_thread_ = false;
-      } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
-        commit_state_ = COMMIT_STATE_IDLE;
-      }
-      if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
-        texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
+    case ACTION_DRAW_IF_POSSIBLE: {
+      bool did_swap = true;
+      UpdateStateOnDraw(did_swap);
       return;
+    }
+
+    case ACTION_DRAW_AND_SWAP_ABORT: {
+      bool did_swap = false;
+      UpdateStateOnDraw(did_swap);
+      return;
+    }
 
     case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
       DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
@@ -357,6 +450,27 @@
   }
 }
 
+void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
+  if (inside_begin_frame_)
+    last_frame_number_where_draw_was_called_ = current_frame_number_;
+  if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW) {
+    DCHECK(expect_immediate_begin_frame_for_main_thread_);
+    commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
+    expect_immediate_begin_frame_for_main_thread_ = false;
+  } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
+    commit_state_ = COMMIT_STATE_IDLE;
+  }
+  if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
+    texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
+
+  needs_redraw_ = false;
+  needs_forced_redraw_ = false;
+  draw_if_possible_failed_ = false;
+
+  if (did_swap)
+    swap_used_incomplete_tile_ = false;
+}
+
 void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
   DCHECK(!main_thread_needs_layer_textures_);
   DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
@@ -441,17 +555,17 @@
   DCHECK(commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
          (expect_immediate_begin_frame_for_main_thread_ &&
           commit_state_ != COMMIT_STATE_IDLE))
-      << ToString();
+      << *AsValue();
   commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
 }
 
 void SchedulerStateMachine::BeginFrameAbortedByMainThread(bool did_handle) {
   DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
-  if (expect_immediate_begin_frame_for_main_thread_) {
+  if (did_handle) {
+    bool commit_was_aborted = true;
+    HandleCommitInternal(commit_was_aborted);
+  } else if (expect_immediate_begin_frame_for_main_thread_) {
     expect_immediate_begin_frame_for_main_thread_ = false;
-  } else if (did_handle) {
-    commit_state_ = COMMIT_STATE_IDLE;
-    SetPostCommitFlags();
   } else {
     commit_state_ = COMMIT_STATE_IDLE;
     SetNeedsCommit();
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 5c7d5b5..eeae995 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -8,11 +8,16 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "cc/base/cc_export.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/scheduler/scheduler_settings.h"
 
+namespace base {
+class Value;
+}
+
 namespace cc {
 
 // The SchedulerStateMachine decides how to coordinate main thread activites
@@ -38,18 +43,21 @@
     COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
     COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW,
   };
+  static const char* CommitStateToString(CommitState state);
 
   enum TextureState {
     LAYER_TEXTURE_STATE_UNLOCKED,
     LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD,
     LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD,
   };
+  static const char* TextureStateToString(TextureState state);
 
   enum OutputSurfaceState {
     OUTPUT_SURFACE_ACTIVE,
     OUTPUT_SURFACE_LOST,
     OUTPUT_SURFACE_CREATING,
   };
+  static const char* OutputSurfaceStateToString(OutputSurfaceState state);
 
   bool CommitPending() const {
     return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
@@ -66,9 +74,14 @@
     ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED,
     ACTION_DRAW_IF_POSSIBLE,
     ACTION_DRAW_FORCED,
+    ACTION_DRAW_AND_SWAP_ABORT,
     ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
     ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD,
   };
+  static const char* ActionToString(Action action);
+
+  scoped_ptr<base::Value> AsValue() const;
+
   Action NextAction() const;
   void UpdateState(Action action);
 
@@ -153,23 +166,22 @@
   // Exposed for testing purposes.
   void SetMaximumNumberOfFailedDrawsBeforeDrawIsForced(int num_draws);
 
-  // False if drawing is not being prevented, true if drawing won't happen
-  // for some reason, such as not being visible.
-  bool DrawSuspendedUntilCommit() const;
-
-  std::string ToString();
+  // True if we need to abort draws to make forward progress.
+  bool PendingDrawsShouldBeAborted() const;
 
  protected:
   bool ShouldDrawForced() const;
-  bool ScheduledToDraw() const;
   bool ShouldDraw() const;
   bool ShouldAttemptTreeActivation() const;
   bool ShouldAcquireLayerTexturesForMainThread() const;
   bool ShouldUpdateVisibleTiles() const;
+
   bool HasDrawnThisFrame() const;
   bool HasAttemptedTreeActivationThisFrame() const;
   bool HasUpdatedVisibleTilesThisFrame() const;
-  void SetPostCommitFlags();
+
+  void HandleCommitInternal(bool commit_was_aborted);
+  void UpdateStateOnDraw(bool did_swap);
 
   const SchedulerSettings settings_;
 
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index c7210eb..c9454ce 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -449,12 +449,12 @@
 
       // Case 1: needs_commit=false.
       EXPECT_TRUE(state.BeginFrameNeededToDrawByImplThread());
-      EXPECT_EQ(expected_action, state.NextAction());
+      EXPECT_EQ(expected_action, state.NextAction()) << *state.AsValue();
 
       // Case 2: needs_commit=true.
       state.SetNeedsCommit();
       EXPECT_TRUE(state.BeginFrameNeededToDrawByImplThread());
-      EXPECT_EQ(expected_action, state.NextAction());
+      EXPECT_EQ(expected_action, state.NextAction()) << *state.AsValue();
     }
   }
 }
@@ -529,6 +529,9 @@
   state.SetNeedsRedraw(true);
   state.SetVisible(true);
   state.SetCanDraw(false);
+  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
+            state.NextAction());
+  state.UpdateState(state.NextAction());
   EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD,
             state.NextAction());
 }
@@ -888,7 +891,8 @@
   state.DidEnterBeginFrame(BeginFrameArgs::CreateForTesting());
   EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE, state.NextAction());
   state.SetCanDraw(false);
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
+            state.NextAction());
   state.SetCanDraw(true);
   state.DidLeaveBeginFrame();
 }
@@ -931,7 +935,8 @@
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
             state.CommitState());
 
-  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE, state.NextAction());
+  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
+            state.NextAction());
   state.UpdateState(state.NextAction());
 
   // Expect to be told to begin context recreation, independent of
@@ -984,7 +989,8 @@
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
             state.CommitState());
 
-  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE, state.NextAction());
+  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
+            state.NextAction());
   state.UpdateState(state.NextAction());
 
   // Expect to be told to begin context recreation, independent of
@@ -1096,6 +1102,9 @@
 
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
             state.CommitState());
+  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
+            state.NextAction());
+  state.UpdateState(state.NextAction());
 
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
 }
@@ -1209,7 +1218,8 @@
 
   // Should be waiting for the normal begin frame from the main thread.
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
-            state.CommitState()) << state.ToString();
+            state.CommitState())
+      << *state.AsValue();
 }
 
 TEST(SchedulerStateMachineTest,
@@ -1248,7 +1258,8 @@
 
   // Should be waiting for the main thread's begin frame.
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
-            state.CommitState()) << state.ToString();
+            state.CommitState())
+      << *state.AsValue();
 
   // Become invisible and abort the main thread's begin frame.
   state.SetVisible(false);
@@ -1296,26 +1307,29 @@
 TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
   SchedulerSettings default_scheduler_settings;
   SchedulerStateMachine state(default_scheduler_settings);
+  state.SetCanStart();
+  state.UpdateState(state.NextAction());
+  state.DidCreateAndInitializeOutputSurface();
 
   state.SetCanDraw(true);
   state.SetVisible(true);
-  EXPECT_FALSE(state.DrawSuspendedUntilCommit());
+  EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
 
   state.SetCanDraw(false);
   state.SetVisible(true);
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   state.SetCanDraw(true);
   state.SetVisible(false);
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   state.SetCanDraw(false);
   state.SetVisible(false);
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   state.SetCanDraw(true);
   state.SetVisible(true);
-  EXPECT_FALSE(state.DrawSuspendedUntilCommit());
+  EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
 }
 
 TEST(SchedulerStateMachineTest, ReportIfNotDrawingFromAcquiredTextures) {
@@ -1326,14 +1340,14 @@
   state.DidCreateAndInitializeOutputSurface();
   state.SetCanDraw(true);
   state.SetVisible(true);
-  EXPECT_FALSE(state.DrawSuspendedUntilCommit());
+  EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
 
   state.SetMainThreadNeedsLayerTextures();
   EXPECT_EQ(
       SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD,
       state.NextAction());
   state.UpdateState(state.NextAction());
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
 
@@ -1342,17 +1356,17 @@
             state.NextAction());
 
   state.UpdateState(state.NextAction());
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
 
   state.FinishCommit();
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
 
   state.UpdateState(state.NextAction());
-  EXPECT_FALSE(state.DrawSuspendedUntilCommit());
+  EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
 }
 
 TEST(SchedulerStateMachineTest, AcquireTexturesWithAbort) {
@@ -1369,7 +1383,7 @@
       SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD,
       state.NextAction());
   state.UpdateState(state.NextAction());
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
 
@@ -1377,14 +1391,14 @@
   EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD,
             state.NextAction());
   state.UpdateState(state.NextAction());
-  EXPECT_TRUE(state.DrawSuspendedUntilCommit());
+  EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
 
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
 
   state.BeginFrameAbortedByMainThread(true);
 
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-  EXPECT_FALSE(state.DrawSuspendedUntilCommit());
+  EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
 }
 
 }  // namespace
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 930111c..0c60131 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "base/memory/scoped_vector.h"
 #include "cc/test/scheduler_test_common.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -52,7 +53,7 @@
   int num_draws() const { return num_draws_; }
   int num_actions_() const { return static_cast<int>(actions_.size()); }
   const char* Action(int i) const { return actions_[i]; }
-  std::string StateForAction(int i) const { return states_[i]; }
+  base::Value& StateForAction(int i) const { return *states_[i]; }
 
   bool HasAction(const char* action) const {
     for (size_t i = 0; i < actions_.size(); i++)
@@ -71,17 +72,17 @@
   // Scheduler Implementation.
   virtual void SetNeedsBeginFrameOnImplThread(bool enable) OVERRIDE {
     actions_.push_back("SetNeedsBeginFrameOnImplThread");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
     needs_begin_frame_ = enable;
   }
   virtual void ScheduledActionSendBeginFrameToMainThread() OVERRIDE {
     actions_.push_back("ScheduledActionSendBeginFrameToMainThread");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
   }
   virtual ScheduledActionDrawAndSwapResult
   ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
     actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
     num_draws_++;
     return ScheduledActionDrawAndSwapResult(draw_will_happen_,
                                             draw_will_happen_ &&
@@ -90,29 +91,29 @@
   virtual ScheduledActionDrawAndSwapResult ScheduledActionDrawAndSwapForced()
       OVERRIDE {
     actions_.push_back("ScheduledActionDrawAndSwapForced");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
     return ScheduledActionDrawAndSwapResult(true,
                                             swap_will_happen_if_draw_happens_);
   }
   virtual void ScheduledActionCommit() OVERRIDE {
     actions_.push_back("ScheduledActionCommit");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
   }
   virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
     actions_.push_back("ScheduledActionUpdateVisibleTiles");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
   }
   virtual void ScheduledActionActivatePendingTreeIfNeeded() OVERRIDE {
     actions_.push_back("ScheduledActionActivatePendingTreeIfNeeded");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
   }
   virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
     actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
   }
   virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
     actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
-    states_.push_back(scheduler_->StateAsStringForTesting());
+    states_.push_back(scheduler_->StateAsValueForTesting().release());
   }
   virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {}
   virtual base::TimeDelta DrawDurationEstimate() OVERRIDE {
@@ -131,7 +132,7 @@
   bool swap_will_happen_if_draw_happens_;
   int num_draws_;
   std::vector<const char*> actions_;
-  std::vector<std::string> states_;
+  ScopedVector<base::Value> states_;
   scoped_ptr<Scheduler> scheduler_;
 };
 
diff --git a/cc/scheduler/texture_uploader_unittest.cc b/cc/scheduler/texture_uploader_unittest.cc
index f4b4ce6..0595917 100644
--- a/cc/scheduler/texture_uploader_unittest.cc
+++ b/cc/scheduler/texture_uploader_unittest.cc
@@ -5,8 +5,8 @@
 #include "cc/scheduler/texture_uploader.h"
 
 #include "cc/base/util.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/resources/prioritized_resource.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/khronos/GLES2/gl2.h"
diff --git a/cc/scheduler/time_source.h b/cc/scheduler/time_source.h
index c02d490..e45ffbb 100644
--- a/cc/scheduler/time_source.h
+++ b/cc/scheduler/time_source.h
@@ -27,7 +27,12 @@
 class CC_EXPORT TimeSource : public base::RefCounted<TimeSource> {
  public:
   virtual void SetClient(TimeSourceClient* client) = 0;
-  virtual void SetActive(bool active) = 0;
+
+  // If transitioning from not active to active, SetActive will return the
+  // timestamp of the most recenly missed tick that did not have OnTimerTick
+  // called.
+  virtual base::TimeTicks SetActive(bool active) = 0;
+
   virtual bool Active() const = 0;
   virtual void SetTimebaseAndInterval(base::TimeTicks timebase,
                                       base::TimeDelta interval) = 0;
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc
index a667c1b..cfab637 100644
--- a/cc/test/animation_test_common.cc
+++ b/cc/test/animation_test_common.cc
@@ -124,6 +124,11 @@
   return gfx::Transform();
 }
 
+bool FakeTransformTransition::AnimatedBoundsForBox(const gfx::BoxF& box,
+                                                   gfx::BoxF* bounds) const {
+  return false;
+}
+
 scoped_ptr<cc::AnimationCurve> FakeTransformTransition::Clone() const {
   return make_scoped_ptr(
       new FakeTransformTransition(*this)).PassAs<cc::AnimationCurve>();
diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h
index cab2ccf..4d3efa6 100644
--- a/cc/test/animation_test_common.h
+++ b/cc/test/animation_test_common.h
@@ -38,6 +38,8 @@
 
   virtual double Duration() const OVERRIDE;
   virtual gfx::Transform GetValue(double time) const OVERRIDE;
+  virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
+                                    gfx::BoxF* bounds) const OVERRIDE;
 
   virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE;
 
diff --git a/cc/test/fake_context_provider.cc b/cc/test/fake_context_provider.cc
index d49fa89..806eb4f 100644
--- a/cc/test/fake_context_provider.cc
+++ b/cc/test/fake_context_provider.cc
@@ -4,43 +4,71 @@
 
 #include "cc/test/fake_context_provider.h"
 
+#include "base/bind.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 
 namespace cc {
 
-FakeContextProvider::FakeContextProvider()
-    : bound_(false),
-      destroyed_(false) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  context_thread_checker_.DetachFromThread();
+// static
+scoped_refptr<FakeContextProvider> FakeContextProvider::
+    CreateForOtherThread() {
+  scoped_refptr<FakeContextProvider> provider = new FakeContextProvider();
+  if (!provider->InitializeOnMainThread())
+    return NULL;
+  return provider;
 }
 
-FakeContextProvider::~FakeContextProvider() {
-  DCHECK(main_thread_checker_.CalledOnValidThread() ||
-         context_thread_checker_.CalledOnValidThread());
+static scoped_ptr<TestWebGraphicsContext3D> ReturnContext(
+    scoped_ptr<TestWebGraphicsContext3D> context3d) {
+  return context3d.Pass();
 }
 
-bool FakeContextProvider::InitializeOnMainThread(
+// static
+scoped_refptr<FakeContextProvider> FakeContextProvider::CreateForOtherThread(
+    scoped_ptr<TestWebGraphicsContext3D> context3d) {
+  CreateCallback create_callback =
+      base::Bind(&ReturnContext, base::Passed(&context3d));
+  scoped_refptr<FakeContextProvider> provider =
+      new FakeContextProvider(create_callback);
+  if (!provider->InitializeOnMainThread())
+    return NULL;
+  return provider;
+}
+
+// static
+scoped_refptr<FakeContextProvider> FakeContextProvider::CreateForOtherThread(
     const CreateCallback& create_callback) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  scoped_refptr<FakeContextProvider> provider =
+      new FakeContextProvider(create_callback);
+  if (!provider->InitializeOnMainThread())
+    return NULL;
+  return provider;
+}
 
+FakeContextProvider::FakeContextProvider()
+    : destroyed_(false) {
+}
+
+FakeContextProvider::FakeContextProvider(
+    const CreateCallback& create_callback)
+    : create_callback_(create_callback),
+      bound_(false),
+      destroyed_(false) {
+}
+
+FakeContextProvider::~FakeContextProvider() {}
+
+bool FakeContextProvider::InitializeOnMainThread() {
   DCHECK(!context3d_);
-  if (create_callback.is_null())
+
+  if (create_callback_.is_null())
     context3d_ = TestWebGraphicsContext3D::Create().Pass();
   else
-    context3d_ = create_callback.Run();
+    context3d_ = create_callback_.Run();
   return context3d_;
 }
 
 bool FakeContextProvider::BindToCurrentThread() {
-  DCHECK(context3d_);
-
-  // This is called on the thread the context will be used.
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-
-  if (bound_)
-    return true;
-
   bound_ = true;
   if (!context3d_->makeContextCurrent()) {
     base::AutoLock lock(destroyed_lock_);
@@ -53,14 +81,12 @@
 WebKit::WebGraphicsContext3D* FakeContextProvider::Context3d() {
   DCHECK(context3d_);
   DCHECK(bound_);
-  DCHECK(context_thread_checker_.CalledOnValidThread());
 
   return context3d_.get();
 }
 class GrContext* FakeContextProvider::GrContext() {
   DCHECK(context3d_);
   DCHECK(bound_);
-  DCHECK(context_thread_checker_.CalledOnValidThread());
 
   // TODO(danakj): Make a fake GrContext.
   return NULL;
@@ -69,7 +95,6 @@
 void FakeContextProvider::VerifyContexts() {
   DCHECK(context3d_);
   DCHECK(bound_);
-  DCHECK(context_thread_checker_.CalledOnValidThread());
 
   if (context3d_->isContextLost()) {
     base::AutoLock lock(destroyed_lock_);
@@ -78,16 +103,8 @@
 }
 
 bool FakeContextProvider::DestroyedOnMainThread() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
   base::AutoLock lock(destroyed_lock_);
   return destroyed_;
 }
 
-void FakeContextProvider::SetLostContextCallback(
-    const LostContextCallback& cb) {
-  DCHECK(context_thread_checker_.CalledOnValidThread());
-  NOTIMPLEMENTED();
-}
-
 }  // namespace cc
diff --git a/cc/test/fake_context_provider.h b/cc/test/fake_context_provider.h
deleted file mode 100644
index 4a18e4a..0000000
--- a/cc/test/fake_context_provider.h
+++ /dev/null
@@ -1,60 +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 CC_TEST_FAKE_CONTEXT_PROVIDER_H_
-#define CC_TEST_FAKE_CONTEXT_PROVIDER_H_
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-#include "cc/output/context_provider.h"
-
-namespace cc {
-class TestWebGraphicsContext3D;
-
-class FakeContextProvider : public cc::ContextProvider {
- public:
-  typedef base::Callback<scoped_ptr<TestWebGraphicsContext3D>(void)>
-    CreateCallback;
-
-  static scoped_refptr<FakeContextProvider> Create() {
-    return Create(CreateCallback());
-  }
-
-  static scoped_refptr<FakeContextProvider> Create(
-      const CreateCallback& create_callback) {
-    scoped_refptr<FakeContextProvider> provider = new FakeContextProvider;
-    if (!provider->InitializeOnMainThread(create_callback))
-      return NULL;
-    return provider;
-  }
-
-  virtual bool BindToCurrentThread() OVERRIDE;
-  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE;
-  virtual class GrContext* GrContext() OVERRIDE;
-  virtual void VerifyContexts() OVERRIDE;
-  virtual bool DestroyedOnMainThread() OVERRIDE;
-  virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE;
-
- protected:
-  FakeContextProvider();
-  virtual ~FakeContextProvider();
-
-  bool InitializeOnMainThread(const CreateCallback& create_callback);
-
-  scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
-  bool bound_;
-
-  base::ThreadChecker main_thread_checker_;
-  base::ThreadChecker context_thread_checker_;
-
-  base::Lock destroyed_lock_;
-  bool destroyed_;
-};
-
-}  // namespace cc
-
-#endif  // CC_TEST_FAKE_CONTEXT_PROVIDER_H_
-
diff --git a/cc/test/fake_delegated_renderer_layer_impl.cc b/cc/test/fake_delegated_renderer_layer_impl.cc
index c6a639e..782bc1c 100644
--- a/cc/test/fake_delegated_renderer_layer_impl.cc
+++ b/cc/test/fake_delegated_renderer_layer_impl.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "cc/output/delegated_frame_data.h"
 #include "cc/quads/draw_quad.h"
+#include "cc/resources/returned_resource.h"
 
 namespace cc {
 
@@ -45,7 +46,7 @@
       pass->quad_list[j]->IterateResources(add_resource_to_frame_callback);
   }
 
-  TransferableResourceArray resources_for_ack;
+  ReturnedResourceArray resources_for_ack;
   SetFrameData(delegated_frame.Pass(), gfx::RectF());
   CollectUnusedResources(&resources_for_ack);
 }
diff --git a/cc/test/fake_layer_tree_host_client.cc b/cc/test/fake_layer_tree_host_client.cc
index 40dabe3..621fc99 100644
--- a/cc/test/fake_layer_tree_host_client.cc
+++ b/cc/test/fake_layer_tree_host_client.cc
@@ -4,8 +4,9 @@
 
 #include "cc/test/fake_layer_tree_host_client.h"
 
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/output/context_provider.h"
-#include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/test/fake_output_surface.h"
 
 namespace cc {
 
@@ -31,26 +32,25 @@
 
   if (use_delegating_renderer_)
     return FakeOutputSurface::CreateDelegating3d().PassAs<OutputSurface>();
-
-  return CreateFakeOutputSurface();
+  return FakeOutputSurface::Create3d().PassAs<OutputSurface>();
 }
 
-scoped_refptr<cc::ContextProvider> FakeLayerTreeHostClient::
+scoped_refptr<ContextProvider> FakeLayerTreeHostClient::
     OffscreenContextProviderForMainThread() {
   if (!main_thread_contexts_.get() ||
       main_thread_contexts_->DestroyedOnMainThread()) {
-    main_thread_contexts_ = FakeContextProvider::Create();
-    if (!main_thread_contexts_->BindToCurrentThread())
+    main_thread_contexts_ = TestContextProvider::Create();
+    if (main_thread_contexts_ && !main_thread_contexts_->BindToCurrentThread())
       main_thread_contexts_ = NULL;
   }
   return main_thread_contexts_;
 }
 
-scoped_refptr<cc::ContextProvider> FakeLayerTreeHostClient::
+scoped_refptr<ContextProvider> FakeLayerTreeHostClient::
     OffscreenContextProviderForCompositorThread() {
   if (!compositor_thread_contexts_.get() ||
       compositor_thread_contexts_->DestroyedOnMainThread())
-    compositor_thread_contexts_ = FakeContextProvider::Create();
+    compositor_thread_contexts_ = TestContextProvider::Create();
   return compositor_thread_contexts_;
 }
 
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index 5c174eb..bc47459 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -6,12 +6,12 @@
 #define CC_TEST_FAKE_LAYER_TREE_HOST_CLIENT_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "cc/debug/test_context_provider.h"
 #include "cc/input/input_handler.h"
-#include "cc/test/fake_context_provider.h"
-#include "cc/test/fake_output_surface.h"
 #include "cc/trees/layer_tree_host.h"
 
 namespace cc {
+class OutputSurface;
 
 class FakeLayerTreeHostClient : public LayerTreeHostClient {
  public:
@@ -50,8 +50,8 @@
   bool use_software_rendering_;
   bool use_delegating_renderer_;
 
-  scoped_refptr<FakeContextProvider> main_thread_contexts_;
-  scoped_refptr<FakeContextProvider> compositor_thread_contexts_;
+  scoped_refptr<TestContextProvider> main_thread_contexts_;
+  scoped_refptr<TestContextProvider> compositor_thread_contexts_;
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc
index 9ae7552..bc94f19 100644
--- a/cc/test/fake_output_surface.cc
+++ b/cc/test/fake_output_surface.cc
@@ -8,14 +8,15 @@
 #include "base/message_loop/message_loop.h"
 #include "cc/output/compositor_frame_ack.h"
 #include "cc/output/output_surface_client.h"
+#include "cc/resources/returned_resource.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
 
 FakeOutputSurface::FakeOutputSurface(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+    scoped_refptr<ContextProvider> context_provider,
     bool delegated_rendering)
-    : OutputSurface(context3d.Pass()),
+    : OutputSurface(context_provider),
       client_(NULL),
       num_sent_frames_(0),
       needs_begin_frame_(false),
@@ -41,10 +42,10 @@
 }
 
 FakeOutputSurface::FakeOutputSurface(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+    scoped_refptr<ContextProvider> context_provider,
     scoped_ptr<SoftwareOutputDevice> software_device,
     bool delegated_rendering)
-    : OutputSurface(context3d.Pass(), software_device.Pass()),
+    : OutputSurface(context_provider, software_device.Pass()),
       client_(NULL),
       num_sent_frames_(0),
       forced_draw_to_software_device_(false),
@@ -59,7 +60,7 @@
 
 void FakeOutputSurface::SwapBuffers(CompositorFrame* frame) {
   if (frame->software_frame_data || frame->delegated_frame_data ||
-      !context3d()) {
+      !context_provider()) {
     frame->AssignTo(&last_sent_frame_);
 
     if (last_sent_frame_.delegated_frame_data) {
@@ -111,13 +112,6 @@
   }
 }
 
-bool FakeOutputSurface::SetAndInitializeContext3D(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d) {
-  context3d_.reset();
-  return InitializeAndSetContext3D(context3d.Pass(),
-                                   scoped_refptr<ContextProvider>());
-}
-
 void FakeOutputSurface::SetTreeActivationCallback(
     const base::Closure& callback) {
   DCHECK(client_);
@@ -133,7 +127,7 @@
       break;
   }
   DCHECK(it != resources_held_by_parent_.end());
-  ack->resources.push_back(*it);
+  ack->resources.push_back(it->ToReturnedResource());
   resources_held_by_parent_.erase(it);
 }
 
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 5091dff..3f87bd3 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -6,13 +6,14 @@
 #define CC_TEST_FAKE_OUTPUT_SURFACE_H_
 
 #include "base/callback.h"
+#include "base/logging.h"
 #include "base/time/time.h"
+#include "cc/debug/test_context_provider.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/output_surface.h"
 #include "cc/output/software_output_device.h"
-#include "cc/test/test_web_graphics_context_3d.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 
 namespace cc {
 
@@ -20,34 +21,42 @@
  public:
   virtual ~FakeOutputSurface();
 
-  static scoped_ptr<FakeOutputSurface> Create3d(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d) {
-    return make_scoped_ptr(new FakeOutputSurface(context3d.Pass(), false));
+  static scoped_ptr<FakeOutputSurface> Create3d() {
+    return make_scoped_ptr(new FakeOutputSurface(
+        TestContextProvider::Create(), false));
   }
 
-  static scoped_ptr<FakeOutputSurface> Create3d() {
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d =
-        TestWebGraphicsContext3D::Create()
-        .PassAs<WebKit::WebGraphicsContext3D>();
-    return make_scoped_ptr(new FakeOutputSurface(context3d.Pass(), false));
+  static scoped_ptr<FakeOutputSurface> Create3d(
+      scoped_refptr<TestContextProvider> context_provider) {
+    return make_scoped_ptr(new FakeOutputSurface(context_provider, false));
+  }
+
+  static scoped_ptr<FakeOutputSurface> Create3d(
+      scoped_ptr<TestWebGraphicsContext3D> context) {
+    return make_scoped_ptr(new FakeOutputSurface(
+        TestContextProvider::Create(context.Pass()), false));
   }
 
   static scoped_ptr<FakeOutputSurface> CreateSoftware(
       scoped_ptr<SoftwareOutputDevice> software_device) {
-    return make_scoped_ptr(
-        new FakeOutputSurface(software_device.Pass(), false));
-  }
-
-  static scoped_ptr<FakeOutputSurface> CreateDelegating3d(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d) {
-    return make_scoped_ptr(new FakeOutputSurface(context3d.Pass(), true));
+    return make_scoped_ptr(new FakeOutputSurface(software_device.Pass(),
+                                                 false));
   }
 
   static scoped_ptr<FakeOutputSurface> CreateDelegating3d() {
-    scoped_ptr<WebKit::WebGraphicsContext3D> context3d =
-        TestWebGraphicsContext3D::Create()
-        .PassAs<WebKit::WebGraphicsContext3D>();
-    return make_scoped_ptr(new FakeOutputSurface(context3d.Pass(), true));
+    return make_scoped_ptr(new FakeOutputSurface(
+        TestContextProvider::Create(), true));
+  }
+
+  static scoped_ptr<FakeOutputSurface> CreateDelegating3d(
+      scoped_refptr<TestContextProvider> context_provider) {
+    return make_scoped_ptr(new FakeOutputSurface(context_provider, true));
+  }
+
+  static scoped_ptr<FakeOutputSurface> CreateDelegating3d(
+      scoped_ptr<TestWebGraphicsContext3D> context) {
+    return make_scoped_ptr(new FakeOutputSurface(
+        TestContextProvider::Create(context.Pass()), true));
   }
 
   static scoped_ptr<FakeOutputSurface> CreateDelegatingSoftware(
@@ -66,9 +75,9 @@
   }
 
   static scoped_ptr<FakeOutputSurface> CreateAlwaysDrawAndSwap3d() {
-    scoped_ptr<FakeOutputSurface> result(Create3d());
-    result->capabilities_.draw_and_swap_full_viewport_every_frame = true;
-    return result.Pass();
+    scoped_ptr<FakeOutputSurface> surface(Create3d());
+    surface->capabilities_.draw_and_swap_full_viewport_every_frame = true;
+    return surface.Pass();
   }
 
   CompositorFrame& last_sent_frame() { return last_sent_frame_; }
@@ -88,10 +97,8 @@
 
   virtual bool BindToClient(OutputSurfaceClient* client) OVERRIDE;
 
-  bool SetAndInitializeContext3D(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d);
-
   using OutputSurface::ReleaseGL;
+  using OutputSurface::InitializeAndSetContext3d;
 
   void SetTreeActivationCallback(const base::Closure& callback);
 
@@ -103,7 +110,7 @@
 
  protected:
   FakeOutputSurface(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+      scoped_refptr<ContextProvider> context_provider,
       bool delegated_rendering);
 
   FakeOutputSurface(
@@ -111,7 +118,7 @@
       bool delegated_rendering);
 
   FakeOutputSurface(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d,
+      scoped_refptr<ContextProvider> context_provider,
       scoped_ptr<SoftwareOutputDevice> software_device,
       bool delegated_rendering);
 
@@ -126,8 +133,8 @@
   TransferableResourceArray resources_held_by_parent_;
 };
 
-static inline scoped_ptr<cc::OutputSurface> CreateFakeOutputSurface() {
-  return FakeOutputSurface::Create3d().PassAs<cc::OutputSurface>();
+static inline scoped_ptr<OutputSurface> CreateFakeOutputSurface() {
+  return FakeOutputSurface::Create3d().PassAs<OutputSurface>();
 }
 
 }  // namespace cc
diff --git a/cc/test/fake_painted_scrollbar_layer.cc b/cc/test/fake_painted_scrollbar_layer.cc
new file mode 100644
index 0000000..72ef420
--- /dev/null
+++ b/cc/test/fake_painted_scrollbar_layer.cc
@@ -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.
+
+#include "cc/test/fake_painted_scrollbar_layer.h"
+
+#include "base/auto_reset.h"
+#include "cc/resources/resource_update_queue.h"
+#include "cc/test/fake_scrollbar.h"
+
+namespace cc {
+
+scoped_refptr<FakePaintedScrollbarLayer> FakePaintedScrollbarLayer::Create(
+    bool paint_during_update,
+    bool has_thumb,
+    int scrolling_layer_id) {
+  FakeScrollbar* fake_scrollbar = new FakeScrollbar(
+      paint_during_update, has_thumb, false);
+  return make_scoped_refptr(new FakePaintedScrollbarLayer(
+      fake_scrollbar, scrolling_layer_id));
+}
+
+FakePaintedScrollbarLayer::FakePaintedScrollbarLayer(
+    FakeScrollbar* fake_scrollbar,
+    int scrolling_layer_id)
+    : PaintedScrollbarLayer(scoped_ptr<Scrollbar>(fake_scrollbar).Pass(),
+                            scrolling_layer_id),
+      update_count_(0),
+      push_properties_count_(0),
+      fake_scrollbar_(fake_scrollbar) {
+  SetAnchorPoint(gfx::PointF(0.f, 0.f));
+  SetBounds(gfx::Size(1, 1));
+  SetIsDrawable(true);
+}
+
+FakePaintedScrollbarLayer::~FakePaintedScrollbarLayer() {}
+
+bool FakePaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
+                                       const OcclusionTracker* occlusion) {
+  bool updated = PaintedScrollbarLayer::Update(queue, occlusion);
+  ++update_count_;
+  return updated;
+}
+
+void FakePaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
+  PaintedScrollbarLayer::PushPropertiesTo(layer);
+  ++push_properties_count_;
+}
+
+scoped_ptr<base::AutoReset<bool> >
+FakePaintedScrollbarLayer::IgnoreSetNeedsCommit() {
+  return make_scoped_ptr(
+      new base::AutoReset<bool>(&ignore_set_needs_commit_, true));
+}
+
+}  // namespace cc
diff --git a/cc/test/fake_painted_scrollbar_layer.h b/cc/test/fake_painted_scrollbar_layer.h
new file mode 100644
index 0000000..9b1b13d
--- /dev/null
+++ b/cc/test/fake_painted_scrollbar_layer.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 CC_TEST_FAKE_PAINTED_SCROLLBAR_LAYER_H_
+#define CC_TEST_FAKE_PAINTED_SCROLLBAR_LAYER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/layers/painted_scrollbar_layer.h"
+#include "cc/test/fake_scrollbar.h"
+
+namespace base { template<typename T> class AutoReset; }
+
+namespace cc {
+
+class FakePaintedScrollbarLayer : public PaintedScrollbarLayer {
+ public:
+  static scoped_refptr<FakePaintedScrollbarLayer>
+      Create(bool paint_during_update, bool has_thumb, int scrolling_layer_id);
+  int update_count() const { return update_count_; }
+  void reset_update_count() { update_count_ = 0; }
+
+  virtual bool Update(ResourceUpdateQueue* queue,
+                      const OcclusionTracker* occlusion) OVERRIDE;
+
+  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+
+  scoped_ptr<base::AutoReset<bool> > IgnoreSetNeedsCommit();
+
+  size_t push_properties_count() const { return push_properties_count_; }
+  void reset_push_properties_count() { push_properties_count_ = 0; }
+
+  // For unit tests
+  UIResourceId track_resource_id() {
+    return PaintedScrollbarLayer::track_resource_id();
+  }
+  UIResourceId thumb_resource_id() {
+    return PaintedScrollbarLayer::thumb_resource_id();
+  }
+  FakeScrollbar* fake_scrollbar() {
+    return fake_scrollbar_;
+  }
+  using PaintedScrollbarLayer::UpdateThumbAndTrackGeometry;
+
+ private:
+  FakePaintedScrollbarLayer(FakeScrollbar* fake_scrollbar,
+                            int scrolling_layer_id);
+  virtual ~FakePaintedScrollbarLayer();
+
+  int update_count_;
+  size_t push_properties_count_;
+  FakeScrollbar* fake_scrollbar_;
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_FAKE_PAINTED_SCROLLBAR_LAYER_H_
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index dd383a6..bdf40a5 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -14,7 +14,6 @@
       append_quads_count_(0) {
   pile_ = pile;
   SetBounds(pile_->size());
-  CreateTilingSetIfNeeded();
 }
 
 FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id)
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index a0c7829..2eeaeef 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -32,6 +32,14 @@
   using PictureLayerImpl::CleanUpTilingsOnActiveLayer;
   using PictureLayerImpl::CanHaveTilings;
   using PictureLayerImpl::MarkVisibleResourcesAsRequired;
+  using PictureLayerImpl::DoPostCommitInitializationIfNeeded;
+
+  bool needs_post_commit_initialization() const {
+    return needs_post_commit_initialization_;
+  }
+
+  bool is_using_lcd_text() const { return is_using_lcd_text_; }
+  void force_set_lcd_text(bool enabled) { is_using_lcd_text_ = enabled; }
 
   PictureLayerTiling* HighResTiling() const;
   PictureLayerTiling* LowResTiling() const;
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h
index cacfd66..0d0ab27 100644
--- a/cc/test/fake_picture_layer_tiling_client.h
+++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -40,6 +40,10 @@
   void set_allow_create_tile(bool allow) { allow_create_tile_ = allow; }
   void set_invalidation(const Region& region) { invalidation_ = region; }
 
+  TileManager* tile_manager() const {
+    return tile_manager_.get();
+  }
+
  protected:
   FakeTileManagerClient tile_manager_client_;
   scoped_ptr<TileManager> tile_manager_;
diff --git a/cc/test/fake_scrollbar.cc b/cc/test/fake_scrollbar.cc
index e6b4253..67166f6 100644
--- a/cc/test/fake_scrollbar.cc
+++ b/cc/test/fake_scrollbar.cc
@@ -12,12 +12,18 @@
     : paint_(false),
       has_thumb_(false),
       is_overlay_(false),
+      thumb_thickness_(10),
+      thumb_length_(5),
+      track_rect_(0, 0, 100, 10),
       fill_color_(SK_ColorGREEN) {}
 
 FakeScrollbar::FakeScrollbar(bool paint, bool has_thumb, bool is_overlay)
     : paint_(paint),
       has_thumb_(has_thumb),
       is_overlay_(is_overlay),
+      thumb_thickness_(10),
+      thumb_length_(5),
+      track_rect_(0, 0, 100, 10),
       fill_color_(SK_ColorGREEN) {}
 
 FakeScrollbar::~FakeScrollbar() {}
@@ -33,15 +39,15 @@
 bool FakeScrollbar::HasThumb() const { return has_thumb_; }
 
 int FakeScrollbar::ThumbThickness() const {
-  return 10;
+  return thumb_thickness_;
 }
 
 int FakeScrollbar::ThumbLength() const {
-  return 10;
+  return thumb_length_;
 }
 
 gfx::Rect FakeScrollbar::TrackRect() const {
-  return gfx::Rect(0, 0, 100, 10);
+  return track_rect_;
 }
 
 void FakeScrollbar::PaintPart(SkCanvas* canvas,
diff --git a/cc/test/fake_scrollbar.h b/cc/test/fake_scrollbar.h
index b9ac409..0f068b0 100644
--- a/cc/test/fake_scrollbar.h
+++ b/cc/test/fake_scrollbar.h
@@ -30,12 +30,20 @@
                          gfx::Rect content_rect) OVERRIDE;
 
   void set_location(gfx::Point location) { location_ = location; }
+  void set_track_rect(gfx::Rect track_rect) { track_rect_ = track_rect; }
+  void set_thumb_thickness(int thumb_thickness) {
+      thumb_thickness_ = thumb_thickness;
+  }
+  void set_thumb_length(int thumb_length) { thumb_length_ = thumb_length; }
 
  private:
   bool paint_;
   bool has_thumb_;
   bool is_overlay_;
+  int thumb_thickness_;
+  int thumb_length_;
   gfx::Point location_;
+  gfx::Rect track_rect_;
   SkColor fill_color_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeScrollbar);
diff --git a/cc/test/fake_scrollbar_layer.cc b/cc/test/fake_scrollbar_layer.cc
deleted file mode 100644
index 64e08ad..0000000
--- a/cc/test/fake_scrollbar_layer.cc
+++ /dev/null
@@ -1,52 +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 "cc/test/fake_scrollbar_layer.h"
-
-#include "base/auto_reset.h"
-#include "cc/resources/resource_update_queue.h"
-#include "cc/test/fake_scrollbar.h"
-
-namespace cc {
-
-FakeScrollbarLayer::FakeScrollbarLayer(bool paint_during_update,
-                                       bool has_thumb,
-                                       int scrolling_layer_id)
-    : ScrollbarLayer(
-          scoped_ptr<Scrollbar>(
-              new FakeScrollbar(paint_during_update, has_thumb, false)).Pass(),
-          scrolling_layer_id),
-      update_count_(0),
-      push_properties_count_(0),
-      last_update_full_upload_size_(0),
-      last_update_partial_upload_size_(0) {
-  SetAnchorPoint(gfx::PointF(0.f, 0.f));
-  SetBounds(gfx::Size(1, 1));
-  SetIsDrawable(true);
-}
-
-FakeScrollbarLayer::~FakeScrollbarLayer() {}
-
-bool FakeScrollbarLayer::Update(ResourceUpdateQueue* queue,
-                                const OcclusionTracker* occlusion) {
-  size_t full = queue->FullUploadSize();
-  size_t partial = queue->PartialUploadSize();
-  bool updated = ScrollbarLayer::Update(queue, occlusion);
-  update_count_++;
-  last_update_full_upload_size_ = queue->FullUploadSize() - full;
-  last_update_partial_upload_size_ = queue->PartialUploadSize() - partial;
-  return updated;
-}
-
-void FakeScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
-  ScrollbarLayer::PushPropertiesTo(layer);
-  ++push_properties_count_;
-}
-
-scoped_ptr<base::AutoReset<bool> > FakeScrollbarLayer::IgnoreSetNeedsCommit() {
-  return make_scoped_ptr(
-      new base::AutoReset<bool>(&ignore_set_needs_commit_, true));
-}
-
-}  // namespace cc
diff --git a/cc/test/fake_scrollbar_layer.h b/cc/test/fake_scrollbar_layer.h
deleted file mode 100644
index 43be832..0000000
--- a/cc/test/fake_scrollbar_layer.h
+++ /dev/null
@@ -1,57 +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 CC_TEST_FAKE_SCROLLBAR_LAYER_H_
-#define CC_TEST_FAKE_SCROLLBAR_LAYER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "cc/layers/scrollbar_layer.h"
-
-namespace base { template<typename T> class AutoReset; }
-
-namespace cc {
-
-class FakeScrollbarLayer : public ScrollbarLayer {
- public:
-  static scoped_refptr<FakeScrollbarLayer> Create(bool paint_during_update,
-                                                  bool has_thumb,
-                                                  int scrolling_layer_id) {
-    return make_scoped_refptr(new FakeScrollbarLayer(
-        paint_during_update, has_thumb, scrolling_layer_id));
-  }
-
-  int update_count() const { return update_count_; }
-  void reset_update_count() { update_count_ = 0; }
-  size_t last_update_full_upload_size() const {
-    return last_update_full_upload_size_;
-  }
-  size_t last_update_partial_upload_size() const {
-    return last_update_partial_upload_size_;
-  }
-
-  virtual bool Update(ResourceUpdateQueue* queue,
-                      const OcclusionTracker* occlusion) OVERRIDE;
-
-  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
-
-  scoped_ptr<base::AutoReset<bool> > IgnoreSetNeedsCommit();
-
-  size_t push_properties_count() const { return push_properties_count_; }
-  void reset_push_properties_count() { push_properties_count_ = 0; }
-
- private:
-  FakeScrollbarLayer(bool paint_during_update,
-                     bool has_thumb,
-                     int scrolling_layer_id);
-  virtual ~FakeScrollbarLayer();
-
-  int update_count_;
-  size_t push_properties_count_;
-  size_t last_update_full_upload_size_;
-  size_t last_update_partial_upload_size_;
-};
-
-}  // namespace cc
-
-#endif  // CC_TEST_FAKE_SCROLLBAR_LAYER_H_
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index c132254..d35e9f7 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -4,6 +4,8 @@
 
 #include "cc/test/fake_tile_manager.h"
 
+#include <deque>
+
 #include "cc/resources/raster_worker_pool.h"
 
 namespace cc {
@@ -14,9 +16,29 @@
  public:
   FakeRasterWorkerPool() : RasterWorkerPool(NULL, 1) {}
 
-  virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {}
+  virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {
+    RasterWorkerPool::SetRasterTasks(queue);
+    for (RasterTaskVector::const_iterator it = raster_tasks().begin();
+         it != raster_tasks().end(); ++it) {
+      completed_tasks_.push_back(it->get());
+    }
+  }
+  virtual void CheckForCompletedTasks() OVERRIDE {
+    while (!completed_tasks_.empty()) {
+      internal::RasterWorkerPoolTask* task = completed_tasks_.front().get();
+      task->WillComplete();
+      task->CompleteOnOriginThread();
+      task->DidComplete();
+      completed_tasks_.pop_front();
+    }
+  }
+  virtual GLenum GetResourceFormat() const OVERRIDE { return GL_RGBA; }
   virtual void OnRasterTasksFinished() OVERRIDE {}
   virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE {}
+
+ private:
+  typedef std::deque<scoped_refptr<internal::RasterWorkerPoolTask> > TaskDeque;
+  TaskDeque completed_tasks_;
 };
 
 }  // namespace
@@ -26,8 +48,7 @@
                   NULL,
                   make_scoped_ptr<RasterWorkerPool>(new FakeRasterWorkerPool),
                   1,
-                  NULL,
-                  GL_RGBA) {}
+                  NULL) {}
 
 FakeTileManager::FakeTileManager(TileManagerClient* client,
                                  ResourceProvider* resource_provider)
@@ -35,8 +56,7 @@
                   resource_provider,
                   make_scoped_ptr<RasterWorkerPool>(new FakeRasterWorkerPool),
                   1,
-                  NULL,
-                  resource_provider->best_texture_format()) {}
+                  NULL) {}
 
 FakeTileManager::~FakeTileManager() {}
 
@@ -44,7 +64,7 @@
   tiles_for_raster.clear();
   all_tiles.Clear();
 
-  GetPrioritizedTileSet(&all_tiles);
+  GetTilesWithAssignedBins(&all_tiles);
   AssignGpuMemoryToTiles(&all_tiles, &tiles_for_raster);
 }
 
diff --git a/cc/test/fake_web_graphics_context_3d_unittest.cc b/cc/test/fake_web_graphics_context_3d_unittest.cc
index 3d119ee..ef0f143 100644
--- a/cc/test/fake_web_graphics_context_3d_unittest.cc
+++ b/cc/test/fake_web_graphics_context_3d_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
-#include "cc/test/test_web_graphics_context_3d.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 0324200..16d7187 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -52,11 +52,9 @@
     case GL_WITH_BITMAP: {
       CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
 
-      using WebKit::WebGraphicsContext3D;
-      using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+      using webkit::gpu::ContextProviderInProcess;
       output_surface = make_scoped_ptr(new PixelTestOutputSurface(
-          WebGraphicsContext3DInProcessCommandBufferImpl::
-              CreateOffscreenContext(WebGraphicsContext3D::Attributes())));
+          ContextProviderInProcess::CreateOffscreen()));
       break;
     }
   }
@@ -69,7 +67,7 @@
 scoped_refptr<cc::ContextProvider>
 LayerTreePixelTest::OffscreenContextProviderForMainThread() {
   scoped_refptr<webkit::gpu::ContextProviderInProcess> provider =
-      webkit::gpu::ContextProviderInProcess::Create();
+      webkit::gpu::ContextProviderInProcess::CreateOffscreen();
   CHECK(provider->BindToCurrentThread());
   return provider;
 }
@@ -77,7 +75,7 @@
 scoped_refptr<cc::ContextProvider>
 LayerTreePixelTest::OffscreenContextProviderForCompositorThread() {
   scoped_refptr<webkit::gpu::ContextProviderInProcess> provider =
-      webkit::gpu::ContextProviderInProcess::Create();
+      webkit::gpu::ContextProviderInProcess::CreateOffscreen();
   CHECK(provider.get());
   return provider;
 }
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 224e2cf..6795f90 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -10,12 +10,12 @@
 #include "cc/animation/layer_animation_controller.h"
 #include "cc/animation/timing_function.h"
 #include "cc/base/switches.h"
+#include "cc/debug/test_context_provider.h"
 #include "cc/input/input_handler.h"
 #include "cc/layers/content_layer.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/test/animation_test_common.h"
-#include "cc/test/fake_context_provider.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/occlusion_tracker_test_common.h"
@@ -615,8 +615,8 @@
     OffscreenContextProviderForMainThread() {
   if (!main_thread_contexts_.get() ||
       main_thread_contexts_->DestroyedOnMainThread()) {
-    main_thread_contexts_ = FakeContextProvider::Create();
-    if (!main_thread_contexts_->BindToCurrentThread())
+    main_thread_contexts_ = TestContextProvider::Create();
+    if (main_thread_contexts_ && !main_thread_contexts_->BindToCurrentThread())
       main_thread_contexts_ = NULL;
   }
   return main_thread_contexts_;
@@ -626,7 +626,7 @@
     OffscreenContextProviderForCompositorThread() {
   if (!compositor_thread_contexts_.get() ||
       compositor_thread_contexts_->DestroyedOnMainThread())
-    compositor_thread_contexts_ = FakeContextProvider::Create();
+    compositor_thread_contexts_ = TestContextProvider::Create();
   return compositor_thread_contexts_;
 }
 
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index fd46acc..3191e5b 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -15,13 +15,13 @@
 namespace Webkit { class WebGraphicsContext3D; }
 
 namespace cc {
-class FakeContextProvider;
 class FakeLayerTreeHostClient;
+class FakeOutputSurface;
 class LayerImpl;
 class LayerTreeHost;
 class LayerTreeHostClient;
 class LayerTreeHostImpl;
-class FakeOutputSurface;
+class TestContextProvider;
 
 // Used by test stubs to notify the test when something interesting happens.
 class TestHooks : public AnimationDelegate {
@@ -184,8 +184,8 @@
   base::CancelableClosure timeout_;
   base::WeakPtr<LayerTreeTest> main_thread_weak_ptr_;
   base::WeakPtrFactory<LayerTreeTest> weak_factory_;
-  scoped_refptr<FakeContextProvider> main_thread_contexts_;
-  scoped_refptr<FakeContextProvider> compositor_thread_contexts_;
+  scoped_refptr<TestContextProvider> main_thread_contexts_;
+  scoped_refptr<TestContextProvider> compositor_thread_contexts_;
 };
 
 }  // namespace cc
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 266af36..dffe378 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -148,12 +148,9 @@
   CHECK(fake_client_);
   CHECK(gfx::InitializeGLBindings(gfx::kGLImplementationOSMesaGL));
 
-  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
-  scoped_ptr<WebKit::WebGraphicsContext3D> context3d(
-      WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
-          WebKit::WebGraphicsContext3D::Attributes()));
+  using webkit::gpu::ContextProviderInProcess;
   output_surface_.reset(new PixelTestOutputSurface(
-      context3d.PassAs<WebKit::WebGraphicsContext3D>()));
+      ContextProviderInProcess::CreateOffscreen()));
   output_surface_->BindToClient(fake_client_.get());
 
   resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
@@ -164,7 +161,7 @@
                                  use_skia_gpu_backend).PassAs<DirectRenderer>();
 
   scoped_refptr<webkit::gpu::ContextProviderInProcess> offscreen_contexts =
-      webkit::gpu::ContextProviderInProcess::Create();
+      webkit::gpu::ContextProviderInProcess::CreateOffscreen();
   ASSERT_TRUE(offscreen_contexts->BindToCurrentThread());
   resource_provider_->set_offscreen_context_provider(offscreen_contexts);
 }
diff --git a/cc/test/pixel_test_output_surface.h b/cc/test/pixel_test_output_surface.h
index ec7a828..e9052fe 100644
--- a/cc/test/pixel_test_output_surface.h
+++ b/cc/test/pixel_test_output_surface.h
@@ -12,8 +12,8 @@
 class PixelTestOutputSurface : public OutputSurface {
  public:
   explicit PixelTestOutputSurface(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
-      : OutputSurface(context3d.Pass()) {}
+      scoped_refptr<ContextProvider> context_provider)
+      : OutputSurface(context_provider) {}
   explicit PixelTestOutputSurface(
       scoped_ptr<cc::SoftwareOutputDevice> software_device)
       : OutputSurface(software_device.Pass()) {}
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc
deleted file mode 100644
index 7e82612..0000000
--- a/cc/test/test_web_graphics_context_3d.cc
+++ /dev/null
@@ -1,644 +0,0 @@
-// Copyright 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 "cc/test/test_web_graphics_context_3d.h"
-
-#include <algorithm>
-#include <string>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-
-using WebKit::WGC3Dboolean;
-using WebKit::WGC3Dchar;
-using WebKit::WGC3Denum;
-using WebKit::WGC3Dint;
-using WebKit::WGC3Dsizei;
-using WebKit::WGC3Dsizeiptr;
-using WebKit::WGC3Duint;
-using WebKit::WebGLId;
-using WebKit::WebGraphicsContext3D;
-
-namespace cc {
-
-static const WebGLId kFramebufferId = 1;
-static const WebGLId kProgramId = 2;
-static const WebGLId kRenderbufferId = 3;
-static const WebGLId kShaderId = 4;
-
-static unsigned s_context_id = 1;
-
-const WebGLId TestWebGraphicsContext3D::kExternalTextureId = 1337;
-
-static base::LazyInstance<base::Lock>::Leaky
-    g_shared_namespace_lock = LAZY_INSTANCE_INITIALIZER;
-
-TestWebGraphicsContext3D::Namespace*
-    TestWebGraphicsContext3D::shared_namespace_ = NULL;
-
-TestWebGraphicsContext3D::Namespace::Namespace()
-    : next_buffer_id(1),
-      next_image_id(1),
-      next_texture_id(1) {
-}
-
-TestWebGraphicsContext3D::Namespace::~Namespace() {
-  g_shared_namespace_lock.Get().AssertAcquired();
-  if (shared_namespace_ == this)
-    shared_namespace_ = NULL;
-}
-
-TestWebGraphicsContext3D::TestWebGraphicsContext3D()
-    : FakeWebGraphicsContext3D(),
-      context_id_(s_context_id++),
-      support_swapbuffers_complete_callback_(true),
-      have_extension_io_surface_(false),
-      have_extension_egl_image_(false),
-      times_make_current_succeeds_(-1),
-      times_bind_texture_succeeds_(-1),
-      times_end_query_succeeds_(-1),
-      times_gen_mailbox_succeeds_(-1),
-      context_lost_(false),
-      times_map_image_chromium_succeeds_(-1),
-      times_map_buffer_chromium_succeeds_(-1),
-      context_lost_callback_(NULL),
-      swap_buffers_callback_(NULL),
-      memory_allocation_changed_callback_(NULL),
-      max_texture_size_(1024),
-      width_(0),
-      height_(0),
-      bound_buffer_(0),
-      weak_ptr_factory_(this) {
-  CreateNamespace();
-}
-
-TestWebGraphicsContext3D::TestWebGraphicsContext3D(
-    const WebGraphicsContext3D::Attributes& attributes)
-    : FakeWebGraphicsContext3D(),
-      context_id_(s_context_id++),
-      attributes_(attributes),
-      support_swapbuffers_complete_callback_(true),
-      have_extension_io_surface_(false),
-      have_extension_egl_image_(false),
-      times_make_current_succeeds_(-1),
-      times_bind_texture_succeeds_(-1),
-      times_end_query_succeeds_(-1),
-      times_gen_mailbox_succeeds_(-1),
-      context_lost_(false),
-      times_map_image_chromium_succeeds_(-1),
-      times_map_buffer_chromium_succeeds_(-1),
-      context_lost_callback_(NULL),
-      swap_buffers_callback_(NULL),
-      memory_allocation_changed_callback_(NULL),
-      max_texture_size_(1024),
-      width_(0),
-      height_(0),
-      bound_buffer_(0),
-      weak_ptr_factory_(this) {
-  CreateNamespace();
-}
-
-void TestWebGraphicsContext3D::CreateNamespace() {
-  if (attributes_.shareResources) {
-    base::AutoLock lock(g_shared_namespace_lock.Get());
-    if (shared_namespace_) {
-      namespace_ = shared_namespace_;
-    } else {
-      namespace_ = new Namespace;
-      shared_namespace_ = namespace_.get();
-    }
-  } else {
-    namespace_ = new Namespace;
-  }
-}
-
-TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
-  for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) {
-    if (sync_point_callbacks_[i] != NULL)
-      delete sync_point_callbacks_[i];
-  }
-  base::AutoLock lock(g_shared_namespace_lock.Get());
-  namespace_ = NULL;
-}
-
-bool TestWebGraphicsContext3D::makeContextCurrent() {
-  if (times_make_current_succeeds_ >= 0) {
-    if (!times_make_current_succeeds_) {
-      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                          GL_INNOCENT_CONTEXT_RESET_ARB);
-    }
-    --times_make_current_succeeds_;
-  }
-  return !context_lost_;
-}
-
-int TestWebGraphicsContext3D::width() {
-  return width_;
-}
-
-int TestWebGraphicsContext3D::height() {
-  return height_;
-}
-
-void TestWebGraphicsContext3D::reshapeWithScaleFactor(
-    int width, int height, float scale_factor) {
-  width_ = width;
-  height_ = height;
-}
-
-bool TestWebGraphicsContext3D::isContextLost() {
-  return context_lost_;
-}
-
-WGC3Denum TestWebGraphicsContext3D::getGraphicsResetStatusARB() {
-  return context_lost_ ? GL_UNKNOWN_CONTEXT_RESET_ARB : GL_NO_ERROR;
-}
-
-WGC3Denum TestWebGraphicsContext3D::checkFramebufferStatus(
-    WGC3Denum target) {
-  if (context_lost_)
-    return GL_FRAMEBUFFER_UNDEFINED_OES;
-  return GL_FRAMEBUFFER_COMPLETE;
-}
-
-WebGraphicsContext3D::Attributes
-    TestWebGraphicsContext3D::getContextAttributes() {
-  return attributes_;
-}
-
-WebKit::WebString TestWebGraphicsContext3D::getString(WGC3Denum name) {
-  std::string string;
-
-  if (support_swapbuffers_complete_callback_)
-    string += "GL_CHROMIUM_swapbuffers_complete_callback";
-
-  if (name == GL_EXTENSIONS) {
-    if (have_extension_io_surface_)
-      string += " GL_CHROMIUM_iosurface GL_ARB_texture_rectangle";
-    if (have_extension_egl_image_)
-      string += " GL_OES_EGL_image_external";
-  }
-
-  return WebKit::WebString::fromUTF8(string.c_str());
-}
-
-WGC3Dint TestWebGraphicsContext3D::getUniformLocation(
-    WebGLId program,
-    const WGC3Dchar* name) {
-  return 0;
-}
-
-WGC3Dsizeiptr TestWebGraphicsContext3D::getVertexAttribOffset(
-    WGC3Duint index,
-    WGC3Denum pname) {
-  return 0;
-}
-
-WGC3Dboolean TestWebGraphicsContext3D::isBuffer(
-    WebGLId buffer) {
-  return false;
-}
-
-WGC3Dboolean TestWebGraphicsContext3D::isEnabled(
-    WGC3Denum cap) {
-  return false;
-}
-
-WGC3Dboolean TestWebGraphicsContext3D::isFramebuffer(
-    WebGLId framebuffer) {
-  return false;
-}
-
-WGC3Dboolean TestWebGraphicsContext3D::isProgram(
-    WebGLId program) {
-  return false;
-}
-
-WGC3Dboolean TestWebGraphicsContext3D::isRenderbuffer(
-    WebGLId renderbuffer) {
-  return false;
-}
-
-WGC3Dboolean TestWebGraphicsContext3D::isShader(
-    WebGLId shader) {
-  return false;
-}
-
-WGC3Dboolean TestWebGraphicsContext3D::isTexture(
-    WebGLId texture) {
-  return false;
-}
-
-WebGLId TestWebGraphicsContext3D::createBuffer() {
-  return NextBufferId();
-}
-
-void TestWebGraphicsContext3D::deleteBuffer(WebGLId id) {
-  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_);
-}
-
-WebGLId TestWebGraphicsContext3D::createFramebuffer() {
-  return kFramebufferId | context_id_ << 16;
-}
-
-void TestWebGraphicsContext3D::deleteFramebuffer(WebGLId id) {
-  EXPECT_EQ(kFramebufferId | context_id_ << 16, id);
-}
-
-WebGLId TestWebGraphicsContext3D::createProgram() {
-  return kProgramId | context_id_ << 16;
-}
-
-void TestWebGraphicsContext3D::deleteProgram(WebGLId id) {
-  EXPECT_EQ(kProgramId | context_id_ << 16, id);
-}
-
-WebGLId TestWebGraphicsContext3D::createRenderbuffer() {
-  return kRenderbufferId | context_id_ << 16;
-}
-
-void TestWebGraphicsContext3D::deleteRenderbuffer(WebGLId id) {
-  EXPECT_EQ(kRenderbufferId | context_id_ << 16, id);
-}
-
-WebGLId TestWebGraphicsContext3D::createShader(WGC3Denum) {
-  return kShaderId | context_id_ << 16;
-}
-
-void TestWebGraphicsContext3D::deleteShader(WebGLId id) {
-  EXPECT_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.push_back(texture_id);
-  return texture_id;
-}
-
-void TestWebGraphicsContext3D::deleteTexture(WebGLId texture_id) {
-  base::AutoLock lock(namespace_->lock);
-  std::vector<WebKit::WebGLId>& textures = namespace_->textures;
-  DCHECK(std::find(textures.begin(), textures.end(), texture_id) !=
-         textures.end());
-  textures.erase(std::find(textures.begin(), textures.end(), texture_id));
-}
-
-void TestWebGraphicsContext3D::attachShader(WebGLId program, WebGLId shader) {
-  EXPECT_EQ(kProgramId | context_id_ << 16, program);
-  EXPECT_EQ(kShaderId | context_id_ << 16, shader);
-}
-
-void TestWebGraphicsContext3D::useProgram(WebGLId program) {
-  if (!program)
-    return;
-  EXPECT_EQ(kProgramId | context_id_ << 16, program);
-}
-
-void TestWebGraphicsContext3D::bindFramebuffer(
-    WGC3Denum target, WebGLId framebuffer) {
-  if (!framebuffer)
-    return;
-  EXPECT_EQ(kFramebufferId | context_id_ << 16, framebuffer);
-}
-
-void TestWebGraphicsContext3D::bindRenderbuffer(
-      WGC3Denum target, WebGLId renderbuffer) {
-  if (!renderbuffer)
-    return;
-  EXPECT_EQ(kRenderbufferId | context_id_ << 16, renderbuffer);
-}
-
-void TestWebGraphicsContext3D::bindTexture(
-    WGC3Denum target, WebGLId texture_id) {
-  if (times_bind_texture_succeeds_ >= 0) {
-    if (!times_bind_texture_succeeds_) {
-      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                          GL_INNOCENT_CONTEXT_RESET_ARB);
-    }
-    --times_bind_texture_succeeds_;
-  }
-
-  if (!texture_id)
-    return;
-  if (texture_id == kExternalTextureId)
-    return;
-  base::AutoLock lock(namespace_->lock);
-  std::vector<WebKit::WebGLId>& textures = namespace_->textures;
-  DCHECK(std::find(textures.begin(), textures.end(), texture_id) !=
-         textures.end());
-  used_textures_.insert(texture_id);
-}
-
-void TestWebGraphicsContext3D::endQueryEXT(WGC3Denum target) {
-  if (times_end_query_succeeds_ >= 0) {
-    if (!times_end_query_succeeds_) {
-      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                          GL_INNOCENT_CONTEXT_RESET_ARB);
-    }
-    --times_end_query_succeeds_;
-  }
-}
-
-void TestWebGraphicsContext3D::getQueryObjectuivEXT(
-    WebGLId query,
-    WGC3Denum pname,
-    WGC3Duint* params) {
-  // If the context is lost, behave as if result is available.
-  if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
-    *params = 1;
-}
-
-void TestWebGraphicsContext3D::getIntegerv(
-    WGC3Denum pname,
-    WebKit::WGC3Dint* value) {
-  if (pname == GL_MAX_TEXTURE_SIZE)
-    *value = max_texture_size_;
-  else if (pname == GL_ACTIVE_TEXTURE)
-    *value = GL_TEXTURE0;
-}
-
-void TestWebGraphicsContext3D::genMailboxCHROMIUM(WebKit::WGC3Dbyte* mailbox) {
-  if (times_gen_mailbox_succeeds_ >= 0) {
-    if (!times_gen_mailbox_succeeds_) {
-      loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                          GL_INNOCENT_CONTEXT_RESET_ARB);
-    }
-    --times_gen_mailbox_succeeds_;
-  }
-  if (context_lost_) {
-    memset(mailbox, 0, 64);
-    return;
-  }
-
-  static char mailbox_name1 = '1';
-  static char mailbox_name2 = '1';
-  mailbox[0] = mailbox_name1;
-  mailbox[1] = mailbox_name2;
-  mailbox[2] = '\0';
-  if (++mailbox_name1 == 0) {
-    mailbox_name1 = '1';
-    ++mailbox_name2;
-  }
-}
-
-void TestWebGraphicsContext3D::setContextLostCallback(
-    WebGraphicsContextLostCallback* callback) {
-  context_lost_callback_ = callback;
-}
-
-void TestWebGraphicsContext3D::loseContextCHROMIUM(WGC3Denum current,
-                                                   WGC3Denum other) {
-  if (context_lost_)
-    return;
-  context_lost_ = true;
-  if (context_lost_callback_)
-    context_lost_callback_->onContextLost();
-
-  for (size_t i = 0; i < shared_contexts_.size(); ++i)
-    shared_contexts_[i]->loseContextCHROMIUM(current, other);
-  shared_contexts_.clear();
-}
-
-void TestWebGraphicsContext3D::signalSyncPoint(
-    unsigned sync_point,
-    WebGraphicsSyncPointCallback* callback) {
-  sync_point_callbacks_.push_back(callback);
-}
-
-void TestWebGraphicsContext3D::signalQuery(
-    WebKit::WebGLId query,
-    WebGraphicsSyncPointCallback* callback) {
-  sync_point_callbacks_.push_back(callback);
-}
-
-void TestWebGraphicsContext3D::setSwapBuffersCompleteCallbackCHROMIUM(
-    WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback) {
-  if (support_swapbuffers_complete_callback_)
-    swap_buffers_callback_ = callback;
-}
-
-void TestWebGraphicsContext3D::setMemoryAllocationChangedCallbackCHROMIUM(
-    WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) {
-  memory_allocation_changed_callback_ = callback;
-}
-
-void TestWebGraphicsContext3D::prepareTexture() {
-  if (swap_buffers_callback_) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(&TestWebGraphicsContext3D::SwapBuffersComplete,
-                              weak_ptr_factory_.GetWeakPtr()));
-  }
-  CallAllSyncPointCallbacks();
-}
-
-void TestWebGraphicsContext3D::finish() {
-  CallAllSyncPointCallbacks();
-}
-
-void TestWebGraphicsContext3D::flush() {
-  CallAllSyncPointCallbacks();
-}
-
-static void CallAndDestroy(
-    WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback* callback) {
-  if (!callback)
-    return;
-  callback->onSyncPointReached();
-  delete callback;
-}
-
-void TestWebGraphicsContext3D::CallAllSyncPointCallbacks() {
-  for (size_t i = 0; i < sync_point_callbacks_.size(); ++i) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&CallAndDestroy,
-                   sync_point_callbacks_[i]));
-  }
-  sync_point_callbacks_.clear();
-}
-
-void TestWebGraphicsContext3D::SwapBuffersComplete() {
-  if (swap_buffers_callback_)
-    swap_buffers_callback_->onSwapBuffersComplete();
-}
-
-void TestWebGraphicsContext3D::bindBuffer(WebKit::WGC3Denum target,
-                                          WebKit::WebGLId buffer) {
-  bound_buffer_ = buffer;
-  if (!bound_buffer_)
-    return;
-  unsigned context_id = buffer >> 17;
-  unsigned buffer_id = buffer & 0x1ffff;
-  base::AutoLock lock(namespace_->lock);
-  DCHECK(buffer_id && buffer_id < namespace_->next_buffer_id);
-  DCHECK_EQ(context_id, context_id_);
-
-  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
-  if (buffers.count(bound_buffer_) == 0)
-    buffers.set(bound_buffer_, make_scoped_ptr(new Buffer).Pass());
-
-  buffers.get(bound_buffer_)->target = target;
-}
-
-void TestWebGraphicsContext3D::bufferData(WebKit::WGC3Denum target,
-                                          WebKit::WGC3Dsizeiptr size,
-                                          const void* data,
-                                          WebKit::WGC3Denum usage) {
-  base::AutoLock lock(namespace_->lock);
-  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
-  DCHECK_GT(buffers.count(bound_buffer_), 0u);
-  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
-  if (context_lost_) {
-    buffers.get(bound_buffer_)->pixels.reset();
-    return;
-  }
-  buffers.get(bound_buffer_)->pixels.reset(new uint8[size]);
-  if (data != NULL)
-    memcpy(buffers.get(bound_buffer_)->pixels.get(), data, size);
-}
-
-void* TestWebGraphicsContext3D::mapBufferCHROMIUM(WebKit::WGC3Denum target,
-                                                  WebKit::WGC3Denum access) {
-  base::AutoLock lock(namespace_->lock);
-  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
-  DCHECK_GT(buffers.count(bound_buffer_), 0u);
-  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
-  if (times_map_buffer_chromium_succeeds_ >= 0) {
-    if (!times_map_buffer_chromium_succeeds_) {
-      return NULL;
-    }
-    --times_map_buffer_chromium_succeeds_;
-  }
-  return buffers.get(bound_buffer_)->pixels.get();
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::unmapBufferCHROMIUM(
-    WebKit::WGC3Denum target) {
-  base::AutoLock lock(namespace_->lock);
-  ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
-  DCHECK_GT(buffers.count(bound_buffer_), 0u);
-  DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
-  buffers.get(bound_buffer_)->pixels.reset();
-  return true;
-}
-
-void TestWebGraphicsContext3D::bindTexImage2DCHROMIUM(
-    WebKit::WGC3Denum target,
-    WebKit::WGC3Dint image_id) {
-  base::AutoLock lock(namespace_->lock);
-  DCHECK_GT(namespace_->images.count(image_id), 0u);
-}
-
-WebKit::WGC3Duint TestWebGraphicsContext3D::createImageCHROMIUM(
-      WebKit::WGC3Dsizei width, WebKit::WGC3Dsizei height,
-      WebKit::WGC3Denum internalformat) {
-  DCHECK_EQ(GL_RGBA8_OES, static_cast<int>(internalformat));
-  WebKit::WGC3Duint image_id = NextImageId();
-  base::AutoLock lock(namespace_->lock);
-  ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
-  images.set(image_id, make_scoped_ptr(new Image).Pass());
-  images.get(image_id)->pixels.reset(new uint8[width * height * 4]);
-  return image_id;
-}
-
-void TestWebGraphicsContext3D::destroyImageCHROMIUM(
-    WebKit::WGC3Duint id) {
-  base::AutoLock lock(namespace_->lock);
-  unsigned context_id = id >> 17;
-  unsigned image_id = id & 0x1ffff;
-  DCHECK(image_id && image_id < namespace_->next_image_id);
-  DCHECK_EQ(context_id, context_id_);
-}
-
-void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
-    WebKit::WGC3Duint image_id,
-    WebKit::WGC3Denum pname,
-    WebKit::WGC3Dint* params) {
-  base::AutoLock lock(namespace_->lock);
-  DCHECK_GT(namespace_->images.count(image_id), 0u);
-  DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM, static_cast<int>(pname));
-  *params = 0;
-}
-
-void* TestWebGraphicsContext3D::mapImageCHROMIUM(WebKit::WGC3Duint image_id,
-                                                 WebKit::WGC3Denum access) {
-  base::AutoLock lock(namespace_->lock);
-  ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
-  DCHECK_GT(images.count(image_id), 0u);
-  if (times_map_image_chromium_succeeds_ >= 0) {
-    if (!times_map_image_chromium_succeeds_) {
-      return NULL;
-    }
-    --times_map_image_chromium_succeeds_;
-  }
-  return images.get(image_id)->pixels.get();
-}
-
-void TestWebGraphicsContext3D::unmapImageCHROMIUM(
-    WebKit::WGC3Duint image_id) {
-  base::AutoLock lock(namespace_->lock);
-  DCHECK_GT(namespace_->images.count(image_id), 0u);
-}
-
-size_t TestWebGraphicsContext3D::NumTextures() const {
-  base::AutoLock lock(namespace_->lock);
-  return namespace_->textures.size();
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::TextureAt(int i) const {
-  base::AutoLock lock(namespace_->lock);
-  return namespace_->textures[i];
-}
-
-WebGLId TestWebGraphicsContext3D::NextTextureId() {
-  base::AutoLock lock(namespace_->lock);
-  WebGLId texture_id = namespace_->next_texture_id++;
-  DCHECK(texture_id < (1 << 16));
-  texture_id |= context_id_ << 16;
-  return texture_id;
-}
-
-WebGLId TestWebGraphicsContext3D::NextBufferId() {
-  base::AutoLock lock(namespace_->lock);
-  WebGLId buffer_id = namespace_->next_buffer_id++;
-  DCHECK(buffer_id < (1 << 17));
-  buffer_id |= context_id_ << 17;
-  return buffer_id;
-}
-
-WebKit::WGC3Duint TestWebGraphicsContext3D::NextImageId() {
-  base::AutoLock lock(namespace_->lock);
-  WGC3Duint image_id = namespace_->next_image_id++;
-  DCHECK(image_id < (1 << 17));
-  image_id |= context_id_ << 17;
-  return image_id;
-}
-
-void TestWebGraphicsContext3D::SetMemoryAllocation(
-    WebKit::WebGraphicsMemoryAllocation allocation) {
-  if (!memory_allocation_changed_callback_)
-    return;
-  memory_allocation_changed_callback_->onMemoryAllocationChanged(allocation);
-}
-
-TestWebGraphicsContext3D::Buffer::Buffer() : target(0) {}
-
-TestWebGraphicsContext3D::Buffer::~Buffer() {}
-
-TestWebGraphicsContext3D::Image::Image() {}
-
-TestWebGraphicsContext3D::Image::~Image() {}
-
-}  // namespace cc
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
deleted file mode 100644
index b182fe6..0000000
--- a/cc/test/test_web_graphics_context_3d.h
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 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 CC_TEST_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
-#define CC_TEST_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
-
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/stl_util.h"
-#include "base/synchronization/lock.h"
-#include "cc/base/scoped_ptr_hash_map.h"
-#include "cc/debug/fake_web_graphics_context_3d.h"
-#include "third_party/khronos/GLES2/gl2.h"
-
-namespace WebKit { struct WebGraphicsMemoryAllocation; }
-
-namespace cc {
-
-class TestWebGraphicsContext3D : public FakeWebGraphicsContext3D {
- public:
-  static scoped_ptr<TestWebGraphicsContext3D> Create() {
-    return make_scoped_ptr(new TestWebGraphicsContext3D());
-  }
-  static scoped_ptr<TestWebGraphicsContext3D> Create(
-      const WebKit::WebGraphicsContext3D::Attributes& attributes) {
-    return make_scoped_ptr(new TestWebGraphicsContext3D(attributes));
-  }
-  virtual ~TestWebGraphicsContext3D();
-
-  virtual bool makeContextCurrent();
-
-  virtual int width();
-  virtual int height();
-
-  virtual void reshapeWithScaleFactor(
-      int width, int height, float scale_factor);
-
-  virtual bool isContextLost();
-  virtual WebKit::WGC3Denum getGraphicsResetStatusARB();
-
-  virtual void attachShader(WebKit::WebGLId program, WebKit::WebGLId shader);
-  virtual void bindFramebuffer(
-      WebKit::WGC3Denum target, WebKit::WebGLId framebuffer);
-  virtual void bindRenderbuffer(
-      WebKit::WGC3Denum target, WebKit::WebGLId renderbuffer);
-  virtual void bindTexture(
-      WebKit::WGC3Denum target,
-      WebKit::WebGLId texture_id);
-
-  virtual WebKit::WGC3Denum checkFramebufferStatus(WebKit::WGC3Denum target);
-
-  virtual Attributes getContextAttributes();
-
-  virtual WebKit::WebString getString(WebKit::WGC3Denum name);
-  virtual WebKit::WGC3Dint getUniformLocation(
-      WebKit::WebGLId program,
-      const WebKit::WGC3Dchar* name);
-  virtual WebKit::WGC3Dsizeiptr getVertexAttribOffset(
-      WebKit::WGC3Duint index,
-      WebKit::WGC3Denum pname);
-
-  virtual WebKit::WGC3Dboolean isBuffer(WebKit::WebGLId buffer);
-  virtual WebKit::WGC3Dboolean isEnabled(WebKit::WGC3Denum cap);
-  virtual WebKit::WGC3Dboolean isFramebuffer(WebKit::WebGLId framebuffer);
-  virtual WebKit::WGC3Dboolean isProgram(WebKit::WebGLId program);
-  virtual WebKit::WGC3Dboolean isRenderbuffer(WebKit::WebGLId renderbuffer);
-  virtual WebKit::WGC3Dboolean isShader(WebKit::WebGLId shader);
-  virtual WebKit::WGC3Dboolean isTexture(WebKit::WebGLId texture);
-
-  virtual void useProgram(WebKit::WebGLId program);
-
-  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 deleteShader(WebKit::WebGLId id);
-  virtual void deleteTexture(WebKit::WebGLId texture_id);
-
-  virtual void endQueryEXT(WebKit::WGC3Denum target);
-  virtual void getQueryObjectuivEXT(
-      WebKit::WebGLId query,
-      WebKit::WGC3Denum pname,
-      WebKit::WGC3Duint* params);
-
-  virtual void getIntegerv(
-      WebKit::WGC3Denum pname,
-      WebKit::WGC3Dint* value);
-
-  virtual void genMailboxCHROMIUM(WebKit::WGC3Dbyte* mailbox);
-  virtual void produceTextureCHROMIUM(WebKit::WGC3Denum target,
-                                      const WebKit::WGC3Dbyte* mailbox) { }
-  virtual void consumeTextureCHROMIUM(WebKit::WGC3Denum target,
-                                      const WebKit::WGC3Dbyte* mailbox) { }
-
-  virtual void setContextLostCallback(
-      WebGraphicsContextLostCallback* callback);
-
-  virtual void loseContextCHROMIUM(WebKit::WGC3Denum current,
-                                   WebKit::WGC3Denum other);
-
-  // Takes ownership of the |callback|.
-  virtual void signalSyncPoint(unsigned sync_point,
-                               WebGraphicsSyncPointCallback* callback);
-  virtual void signalQuery(WebKit::WebGLId query,
-                           WebGraphicsSyncPointCallback* callback);
-
-  virtual void setSwapBuffersCompleteCallbackCHROMIUM(
-      WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* callback);
-
-  virtual void setMemoryAllocationChangedCallbackCHROMIUM(
-      WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback);
-
-  virtual void prepareTexture();
-  virtual void finish();
-  virtual void flush();
-
-  virtual void bindBuffer(WebKit::WGC3Denum target, WebKit::WebGLId buffer);
-  virtual void bufferData(WebKit::WGC3Denum target,
-                          WebKit::WGC3Dsizeiptr size,
-                          const void* data,
-                          WebKit::WGC3Denum usage);
-  virtual void* mapBufferCHROMIUM(WebKit::WGC3Denum target,
-                                  WebKit::WGC3Denum access);
-  virtual WebKit::WGC3Dboolean unmapBufferCHROMIUM(WebKit::WGC3Denum target);
-
-  virtual void bindTexImage2DCHROMIUM(WebKit::WGC3Denum target,
-                                      WebKit::WGC3Dint image_id);
-  virtual WebKit::WGC3Duint createImageCHROMIUM(
-      WebKit::WGC3Dsizei width,
-      WebKit::WGC3Dsizei height,
-      WebKit::WGC3Denum internalformat);
-  virtual void destroyImageCHROMIUM(WebKit::WGC3Duint image_id);
-  virtual void getImageParameterivCHROMIUM(
-      WebKit::WGC3Duint image_id,
-      WebKit::WGC3Denum pname,
-      WebKit::WGC3Dint* params);
-  virtual void* mapImageCHROMIUM(
-      WebKit::WGC3Duint image_id,
-      WebKit::WGC3Denum access);
-  virtual void unmapImageCHROMIUM(WebKit::WGC3Duint image_id);
-
-  // When set, MakeCurrent() will fail after this many times.
-  void set_times_make_current_succeeds(int times) {
-    times_make_current_succeeds_ = times;
-  }
-  void set_times_bind_texture_succeeds(int times) {
-    times_bind_texture_succeeds_ = times;
-  }
-  void set_times_end_query_succeeds(int times) {
-    times_end_query_succeeds_ = times;
-  }
-  void set_times_gen_mailbox_succeeds(int times) {
-    times_gen_mailbox_succeeds_ = times;
-  }
-
-  // When set, mapImageCHROMIUM and mapBufferCHROMIUM will return NULL after
-  // this many times.
-  void set_times_map_image_chromium_succeeds(int times) {
-    times_map_image_chromium_succeeds_ = times;
-  }
-  void set_times_map_buffer_chromium_succeeds(int times) {
-    times_map_buffer_chromium_succeeds_ = times;
-  }
-
-  size_t NumTextures() const;
-  WebKit::WebGLId TextureAt(int i) const;
-
-  size_t NumUsedTextures() const { return used_textures_.size(); }
-  bool UsedTexture(int texture) const {
-    return ContainsKey(used_textures_, texture);
-  }
-  void ResetUsedTextures() { used_textures_.clear(); }
-
-  void set_support_swapbuffers_complete_callback(bool support) {
-    support_swapbuffers_complete_callback_ = support;
-  }
-  void set_have_extension_io_surface(bool have) {
-    have_extension_io_surface_ = have;
-  }
-  void set_have_extension_egl_image(bool have) {
-    have_extension_egl_image_ = have;
-  }
-
-  // When this context is lost, all contexts in its share group are also lost.
-  void add_share_group_context(WebKit::WebGraphicsContext3D* context3d) {
-    shared_contexts_.push_back(context3d);
-  }
-
-  void set_max_texture_size(int size) { max_texture_size_ = size; }
-
-  static const WebKit::WebGLId kExternalTextureId;
-  virtual WebKit::WebGLId NextTextureId();
-
-  virtual WebKit::WebGLId NextBufferId();
-
-  virtual WebKit::WebGLId NextImageId();
-
-  void SetMemoryAllocation(WebKit::WebGraphicsMemoryAllocation allocation);
-
- protected:
-  struct Buffer {
-    Buffer();
-    ~Buffer();
-
-    WebKit::WGC3Denum target;
-    scoped_ptr<uint8[]> pixels;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Buffer);
-  };
-
-  struct Image {
-    Image();
-    ~Image();
-
-    scoped_ptr<uint8[]> pixels;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Image);
-  };
-
-  struct Namespace : public base::RefCountedThreadSafe<Namespace> {
-    Namespace();
-
-    // Protects all fields.
-    base::Lock lock;
-    unsigned next_buffer_id;
-    unsigned next_image_id;
-    unsigned next_texture_id;
-    std::vector<WebKit::WebGLId> textures;
-    ScopedPtrHashMap<unsigned, Buffer> buffers;
-    ScopedPtrHashMap<unsigned, Image> images;
-
-   private:
-    friend class base::RefCountedThreadSafe<Namespace>;
-    ~Namespace();
-    DISALLOW_COPY_AND_ASSIGN(Namespace);
-  };
-
-  TestWebGraphicsContext3D();
-  TestWebGraphicsContext3D(
-      const WebKit::WebGraphicsContext3D::Attributes& attributes);
-
-  void CallAllSyncPointCallbacks();
-  void SwapBuffersComplete();
-  void CreateNamespace();
-
-  unsigned context_id_;
-  Attributes attributes_;
-  bool support_swapbuffers_complete_callback_;
-  bool have_extension_io_surface_;
-  bool have_extension_egl_image_;
-  int times_make_current_succeeds_;
-  int times_bind_texture_succeeds_;
-  int times_end_query_succeeds_;
-  int times_gen_mailbox_succeeds_;
-  bool context_lost_;
-  int times_map_image_chromium_succeeds_;
-  int times_map_buffer_chromium_succeeds_;
-  WebGraphicsContextLostCallback* context_lost_callback_;
-  WebGraphicsSwapBuffersCompleteCallbackCHROMIUM* swap_buffers_callback_;
-  WebGraphicsMemoryAllocationChangedCallbackCHROMIUM*
-      memory_allocation_changed_callback_;
-  std::vector<WebGraphicsSyncPointCallback*> sync_point_callbacks_;
-  base::hash_set<WebKit::WebGLId> used_textures_;
-  std::vector<WebKit::WebGraphicsContext3D*> shared_contexts_;
-  int max_texture_size_;
-  int width_;
-  int height_;
-
-  unsigned bound_buffer_;
-
-  scoped_refptr<Namespace> namespace_;
-  static Namespace* shared_namespace_;
-
-  base::WeakPtrFactory<TestWebGraphicsContext3D> weak_ptr_factory_;
-};
-
-}  // namespace cc
-
-#endif  // CC_TEST_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 9956f4c..cb76b46 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -26,8 +26,8 @@
 #include "cc/layers/heads_up_display_layer_impl.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_iterator.h"
+#include "cc/layers/painted_scrollbar_layer.h"
 #include "cc/layers/render_surface.h"
-#include "cc/layers/scrollbar_layer.h"
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/ui_resource_client.h"
 #include "cc/trees/layer_tree_host_client.h"
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 68dadd5..dba7b50 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -58,6 +58,9 @@
   gfx::Rect minimal_surface_rect = target_surface_rect;
   minimal_surface_rect.Intersect(layer_rect_in_target_space);
 
+  if (minimal_surface_rect.IsEmpty())
+      return gfx::Rect();
+
   // Project the corners of the target surface rect into the layer space.
   // This bounding rectangle may be larger than it needs to be (being
   // axis-aligned), but is a reasonable filter on the space to consider.
@@ -65,11 +68,10 @@
 
   gfx::Transform surface_to_layer(gfx::Transform::kSkipInitialization);
   if (!transform.GetInverse(&surface_to_layer)) {
-    // TODO(shawnsingh): Some uninvertible transforms may be visible, but
-    // their behaviour is undefined thoughout the compositor. Make their
-    // behaviour well-defined and allow the visible content rect to be non-
-    // empty when needed.
-    return gfx::Rect();
+    // Because we cannot use the surface bounds to determine what portion of
+    // the layer is visible, we must conservatively assume the full layer is
+    // visible.
+    return layer_bound_rect;
   }
 
   gfx::Rect layer_rect = gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
@@ -1414,29 +1416,6 @@
     }
   }
 
-  if (layer == globals.page_scale_application_layer) {
-    data_for_children.parent_matrix.Scale(
-        globals.page_scale_factor,
-        globals.page_scale_factor);
-    data_for_children.in_subtree_of_page_scale_application_layer = true;
-  }
-
-  // Flatten to 2D if the layer doesn't preserve 3D.
-  if (!layer->preserves_3d())
-    data_for_children.parent_matrix.FlattenTo2d();
-
-  // Apply the sublayer transform at the anchor point of the layer.
-  if (!layer->sublayer_transform().IsIdentity()) {
-    data_for_children.parent_matrix.Translate(
-        layer->anchor_point().x() * bounds.width(),
-        layer->anchor_point().y() * bounds.height());
-    data_for_children.parent_matrix.PreconcatTransform(
-        layer->sublayer_transform());
-    data_for_children.parent_matrix.Translate(
-        -layer->anchor_point().x() * bounds.width(),
-        -layer->anchor_point().y() * bounds.height());
-  }
-
   LayerListType& descendants =
       (layer->render_surface() ? layer->render_surface()->layer_list()
                                : *layer_list);
@@ -1448,23 +1427,48 @@
   if (!LayerShouldBeSkipped(layer, layer_is_visible))
     descendants.push_back(layer);
 
-  data_for_children.scroll_compensation_matrix =
-      ComputeScrollCompensationMatrixForChildren(
-          layer,
-          data_from_ancestor.parent_matrix,
-          data_from_ancestor.scroll_compensation_matrix);
-  data_for_children.fixed_container =
-      layer->IsContainerForFixedPositionLayers() ?
-          layer : data_from_ancestor.fixed_container;
+  if (!layer->children().empty()) {
+    if (layer == globals.page_scale_application_layer) {
+      data_for_children.parent_matrix.Scale(
+          globals.page_scale_factor,
+          globals.page_scale_factor);
+      data_for_children.in_subtree_of_page_scale_application_layer = true;
+    }
 
-  data_for_children.clip_rect_in_target_space = clip_rect_in_target_space;
-  data_for_children.clip_rect_of_target_surface_in_target_space =
-      clip_rect_of_target_surface_in_target_space;
-  data_for_children.ancestor_clips_subtree =
-      layer_or_ancestor_clips_descendants;
-  data_for_children.nearest_ancestor_surface_that_moves_pixels =
-      nearest_ancestor_surface_that_moves_pixels;
-  data_for_children.subtree_is_visible_from_ancestor = layer_is_visible;
+    // Flatten to 2D if the layer doesn't preserve 3D.
+    if (!layer->preserves_3d())
+      data_for_children.parent_matrix.FlattenTo2d();
+
+    // Apply the sublayer transform at the anchor point of the layer.
+    if (!layer->sublayer_transform().IsIdentity()) {
+      data_for_children.parent_matrix.Translate(
+          layer->anchor_point().x() * bounds.width(),
+          layer->anchor_point().y() * bounds.height());
+      data_for_children.parent_matrix.PreconcatTransform(
+          layer->sublayer_transform());
+      data_for_children.parent_matrix.Translate(
+          -layer->anchor_point().x() * bounds.width(),
+          -layer->anchor_point().y() * bounds.height());
+    }
+
+    data_for_children.scroll_compensation_matrix =
+        ComputeScrollCompensationMatrixForChildren(
+            layer,
+            data_from_ancestor.parent_matrix,
+            data_from_ancestor.scroll_compensation_matrix);
+    data_for_children.fixed_container =
+        layer->IsContainerForFixedPositionLayers() ?
+            layer : data_from_ancestor.fixed_container;
+
+    data_for_children.clip_rect_in_target_space = clip_rect_in_target_space;
+    data_for_children.clip_rect_of_target_surface_in_target_space =
+        clip_rect_of_target_surface_in_target_space;
+    data_for_children.ancestor_clips_subtree =
+        layer_or_ancestor_clips_descendants;
+    data_for_children.nearest_ancestor_surface_that_moves_pixels =
+        nearest_ancestor_surface_that_moves_pixels;
+    data_for_children.subtree_is_visible_from_ancestor = layer_is_visible;
+  }
 
   gfx::Rect accumulated_drawable_content_rect_of_children;
   for (size_t i = 0; i < layer->children().size(); ++i) {
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index fa5450d..49b80e8 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -3185,8 +3185,10 @@
   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
   host->SetRootLayer(root);
 
+  // Case 1: a truly degenerate matrix
   gfx::Transform identity_matrix;
   gfx::Transform uninvertible_matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+  ASSERT_FALSE(uninvertible_matrix.IsInvertible());
 
   SetLayerPropertiesForTesting(root.get(),
                                identity_matrix,
@@ -3207,6 +3209,48 @@
 
   EXPECT_TRUE(child->visible_content_rect().IsEmpty());
   EXPECT_TRUE(child->drawable_content_rect().IsEmpty());
+
+  // Case 2: a matrix with flattened z, technically uninvertible but still
+  // drawable and visible. In this case, we must assume that the entire layer
+  // bounds are visible since there is no way to inverse-project the surface
+  // bounds to intersect.
+  uninvertible_matrix.MakeIdentity();
+  uninvertible_matrix.matrix().setDouble(2, 2, 0.0);
+  ASSERT_FALSE(uninvertible_matrix.IsInvertible());
+
+  SetLayerPropertiesForTesting(child.get(),
+                               uninvertible_matrix,
+                               identity_matrix,
+                               gfx::PointF(),
+                               gfx::PointF(5.f, 5.f),
+                               gfx::Size(50, 50),
+                               false);
+
+  ExecuteCalculateDrawProperties(root.get());
+
+  EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child->visible_content_rect());
+  EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child->drawable_content_rect());
+
+  // Case 3: a matrix with flattened z, technically uninvertible but still
+  // drawable, but not visible. In this case, we don't need to conservatively
+  // assume that the whole layer is visible.
+  uninvertible_matrix.MakeIdentity();
+  uninvertible_matrix.Translate(500.0, 0.0);
+  uninvertible_matrix.matrix().setDouble(2, 2, 0.0);
+  ASSERT_FALSE(uninvertible_matrix.IsInvertible());
+
+  SetLayerPropertiesForTesting(child.get(),
+                               uninvertible_matrix,
+                               identity_matrix,
+                               gfx::PointF(),
+                               gfx::PointF(5.f, 5.f),
+                               gfx::Size(50, 50),
+                               false);
+
+  ExecuteCalculateDrawProperties(root.get());
+
+  EXPECT_TRUE(child->visible_content_rect().IsEmpty());
+  EXPECT_RECT_EQ(gfx::Rect(505, 5, 50, 50), child->drawable_content_rect());
 }
 
 TEST_F(LayerTreeHostCommonTest,
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index d4a9498..9f664fc 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -28,8 +28,8 @@
 #include "cc/layers/heads_up_display_layer_impl.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/layers/layer_iterator.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/layers/render_surface_impl.h"
-#include "cc/layers/scrollbar_layer_impl.h"
 #include "cc/output/compositor_frame_metadata.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/delegating_renderer.h"
@@ -246,10 +246,11 @@
 void LayerTreeHostImpl::CommitComplete() {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete");
 
-  // 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.
   if (settings_.impl_side_painting) {
+    // 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_->set_needs_update_draw_properties();
     pending_tree_->UpdateDrawProperties();
     // Start working on newly created tiles immediately if needed.
@@ -327,9 +328,11 @@
 
   size_t memory_required_bytes;
   size_t memory_nice_to_have_bytes;
+  size_t memory_allocated_bytes;
   size_t memory_used_bytes;
   tile_manager_->GetMemoryStats(&memory_required_bytes,
                                 &memory_nice_to_have_bytes,
+                                &memory_allocated_bytes,
                                 &memory_used_bytes);
   SendManagedMemoryStats(memory_required_bytes,
                          memory_nice_to_have_bytes,
@@ -466,7 +469,7 @@
 static DrawMode GetDrawMode(OutputSurface* output_surface) {
   if (output_surface->ForcedDrawToSoftwareDevice()) {
     return DRAW_MODE_RESOURCELESS_SOFTWARE;
-  } else if (output_surface->context3d()) {
+  } else if (output_surface->context_provider()) {
     return DRAW_MODE_HARDWARE;
   } else {
     DCHECK(output_surface->software_device());
@@ -1224,24 +1227,25 @@
 
 void LayerTreeHostImpl::DrawLayers(FrameData* frame,
                                    base::TimeTicks frame_begin_time) {
-  TRACE_EVENT0("cc", "LayerTreeHostImpl::DrawLayers");
+  TRACE_EVENT_BEGIN0("cc", "LayerTreeHostImpl::DrawLayers");
   DCHECK(CanDraw());
 
   if (frame->has_no_damage) {
     TRACE_EVENT0("cc", "EarlyOut_NoDamage");
     DCHECK(!output_surface_->capabilities()
                .draw_and_swap_full_viewport_every_frame);
+    TRACE_EVENT_END0("cc", "LayerTreeHostImpl::DrawLayers");
     return;
   }
 
   DCHECK(!frame->render_passes.empty());
 
+  int old_dropped_frame_count = fps_counter_->dropped_frame_count();
   fps_counter_->SaveTimeStamp(frame_begin_time);
 
-  rendering_stats_instrumentation_->SetScreenFrameCount(
-      fps_counter_->current_frame_number());
-  rendering_stats_instrumentation_->SetDroppedFrameCount(
-      fps_counter_->dropped_frame_count());
+  rendering_stats_instrumentation_->IncrementScreenFrameCount(1);
+  rendering_stats_instrumentation_->IncrementDroppedFrameCount(
+      fps_counter_->dropped_frame_count() - old_dropped_frame_count);
 
   if (tile_manager_) {
     memory_history_->SaveEntry(
@@ -1260,7 +1264,7 @@
   if (!settings_.impl_side_painting && debug_state_.continuous_painting) {
     const RenderingStats& stats =
         rendering_stats_instrumentation_->GetRenderingStats();
-    paint_time_counter_->SavePaintTime(stats.total_paint_time);
+    paint_time_counter_->SavePaintTime(stats.main_stats.paint_time);
   }
 
   bool is_new_trace;
@@ -1305,6 +1309,10 @@
         DidDrawDamagedArea();
   }
   active_tree_->root_layer()->ResetAllChangeTrackingForSubtree();
+  TRACE_EVENT_END1("cc", "LayerTreeHostImpl::DrawLayers",
+                   "data", rendering_stats_instrumentation_->
+                   GetImplThreadRenderingStats().AsTraceableData());
+  rendering_stats_instrumentation_->AccumulateAndClearImplThreadStats();
 }
 
 void LayerTreeHostImpl::DidDrawAllLayers(const FrameData& frame) {
@@ -1509,8 +1517,8 @@
     const RenderingStats& stats =
         rendering_stats_instrumentation_->GetRenderingStats();
     paint_time_counter_->SavePaintTime(
-        stats.total_paint_time + stats.total_record_time +
-            stats.total_rasterize_time_for_now_bins_on_pending_tree);
+        stats.main_stats.paint_time + stats.main_stats.record_time +
+            stats.impl_stats.rasterize_time_for_now_bins_on_pending_tree);
   }
 
   client_->DidActivatePendingTree();
@@ -1527,6 +1535,11 @@
   DidVisibilityChange(this, visible_);
   EnforceManagedMemoryPolicy(ActualManagedMemoryPolicy());
 
+  // Evict tiles immediately if invisible since this tab may never get another
+  // draw or timer tick.
+  if (!visible_)
+    ManageTiles();
+
   if (!renderer_)
     return;
 
@@ -1574,7 +1587,7 @@
   if (output_surface->capabilities().delegated_rendering) {
     renderer_ =
         DelegatingRenderer::Create(this, output_surface, resource_provider);
-  } else if (output_surface->context3d() && !skip_gl_renderer) {
+  } else if (output_surface->context_provider() && !skip_gl_renderer) {
     renderer_ = GLRenderer::Create(this,
                                    output_surface,
                                    resource_provider,
@@ -1685,7 +1698,7 @@
   DCHECK(output_surface_->capabilities().deferred_gl_initialization);
   DCHECK(settings_.impl_side_painting);
   DCHECK(settings_.solid_color_scrollbars);
-  DCHECK(output_surface_->context3d());
+  DCHECK(output_surface_->context_provider());
 
   ReleaseTreeResources();
   renderer_.reset();
@@ -1708,7 +1721,7 @@
   DCHECK(output_surface_->capabilities().deferred_gl_initialization);
   DCHECK(settings_.impl_side_painting);
   DCHECK(settings_.solid_color_scrollbars);
-  DCHECK(output_surface_->context3d());
+  DCHECK(output_surface_->context_provider());
 
   ReleaseTreeResources();
   renderer_.reset();
@@ -2500,7 +2513,9 @@
   if (id)
     DeleteUIResource(uid);
   id = resource_provider_->CreateResource(
-      bitmap->GetSize(), GL_RGBA, ResourceProvider::TextureUsageAny);
+      bitmap->GetSize(),
+      resource_provider_->best_texture_format(),
+      ResourceProvider::TextureUsageAny);
 
   ui_resource_map_[uid] = id;
   resource_provider_->SetPixels(id,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index ab81c67..98f4866 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -10,14 +10,15 @@
 #include "base/command_line.h"
 #include "base/containers/hash_tables.h"
 #include "cc/base/math_util.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/input/top_controls_manager.h"
 #include "cc/layers/delegated_renderer_layer_impl.h"
 #include "cc/layers/heads_up_display_layer_impl.h"
 #include "cc/layers/io_surface_layer_impl.h"
 #include "cc/layers/layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/layers/quad_sink.h"
 #include "cc/layers/render_surface_impl.h"
-#include "cc/layers/scrollbar_layer_impl.h"
 #include "cc/layers/solid_color_layer_impl.h"
 #include "cc/layers/texture_layer_impl.h"
 #include "cc/layers/tiled_layer_impl.h"
@@ -33,13 +34,13 @@
 #include "cc/resources/layer_tiling_data.h"
 #include "cc/test/animation_test_common.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_proxy.h"
 #include "cc/test/fake_rendering_stats_instrumentation.h"
 #include "cc/test/fake_video_frame_provider.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/layer_test_common.h"
 #include "cc/test/render_pass_test_common.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "media/base/media.h"
@@ -372,20 +373,18 @@
   settings.impl_side_painting = true;
   host_impl_ = LayerTreeHostImpl::Create(
       settings, this, &proxy_, &stats_instrumentation_);
+
+  scoped_ptr<FakeOutputSurface> output_surface(
+      FakeOutputSurface::CreateAlwaysDrawAndSwap3d());
+
   host_impl_->InitializeRenderer(
-      FakeOutputSurface::CreateAlwaysDrawAndSwap3d().PassAs<OutputSurface>());
+      output_surface.PassAs<OutputSurface>());
   host_impl_->SetViewportSize(gfx::Size(10, 10));
 
   bool always_draw = true;
   CheckNotifyCalledIfCanDrawChanged(always_draw);
 }
 
-class TestWebGraphicsContext3DMakeCurrentFails
-    : public TestWebGraphicsContext3D {
- public:
-  virtual bool makeContextCurrent() OVERRIDE { return false; }
-};
-
 TEST_F(LayerTreeHostImplTest, ScrollDeltaNoLayers) {
   ASSERT_FALSE(host_impl_->active_tree()->root_layer());
 
@@ -480,12 +479,15 @@
                                          this,
                                          &proxy_,
                                          &stats_instrumentation_);
+  scoped_ptr<TestWebGraphicsContext3D> context_owned =
+      TestWebGraphicsContext3D::Create();
+  context_owned->set_times_make_current_succeeds(0);
+
+  scoped_ptr<FakeOutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.Pass()));
 
   // Initialization will fail here.
-  host_impl_->InitializeRenderer(FakeOutputSurface::Create3d(
-      scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new TestWebGraphicsContext3DMakeCurrentFails))
-      .PassAs<OutputSurface>());
+  host_impl_->InitializeRenderer(output_surface.PassAs<OutputSurface>());
   host_impl_->SetViewportSize(gfx::Size(10, 10));
 
   SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -721,8 +723,8 @@
   EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
       gfx::Point(), SCROLL_BACKWARD));
 
-  scoped_ptr<cc::ScrollbarLayerImpl> vertical_scrollbar(
-      cc::ScrollbarLayerImpl::Create(
+  scoped_ptr<cc::PaintedScrollbarLayerImpl> vertical_scrollbar(
+      cc::PaintedScrollbarLayerImpl::Create(
           host_impl_->active_tree(),
           20,
           VERTICAL));
@@ -1121,10 +1123,8 @@
   contents->SetBounds(content_size);
   contents->SetContentBounds(content_size);
 
-  scoped_ptr<ScrollbarLayerImpl> scrollbar = ScrollbarLayerImpl::Create(
-      host_impl_->active_tree(),
-      4,
-      VERTICAL);
+  scoped_ptr<PaintedScrollbarLayerImpl> scrollbar =
+      PaintedScrollbarLayerImpl::Create(host_impl_->active_tree(), 4, VERTICAL);
   scroll->SetVerticalScrollbarLayer(scrollbar.get());
 
   scroll->AddChild(contents.Pass());
@@ -2850,14 +2850,14 @@
     settings.impl_side_painting = true;
     host_impl_ = LayerTreeHostImpl::Create(
         settings, this, &proxy_, &stats_instrumentation_);
-    scoped_ptr<OutputSurface> output_surface;
-    if (always_draw) {
-      output_surface = FakeOutputSurface::CreateAlwaysDrawAndSwap3d()
-          .PassAs<OutputSurface>();
-    } else {
-      output_surface = CreateFakeOutputSurface();
-    }
-    host_impl_->InitializeRenderer(output_surface.Pass());
+
+    scoped_ptr<FakeOutputSurface> output_surface;
+    if (always_draw)
+      output_surface = FakeOutputSurface::CreateAlwaysDrawAndSwap3d().Pass();
+    else
+      output_surface = FakeOutputSurface::Create3d().Pass();
+
+    host_impl_->InitializeRenderer(output_surface.PassAs<OutputSurface>());
     viewport_size_ = gfx::Size(1000, 1000);
   }
 
@@ -3081,11 +3081,11 @@
 // can leave the window at the wrong size if we never draw and the proper
 // viewport size is never set.
 TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
-  scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
-      scoped_ptr<WebKit::WebGraphicsContext3D>(new ReshapeTrackerContext))
-      .PassAs<OutputSurface>();
-  ReshapeTrackerContext* reshape_tracker =
-      static_cast<ReshapeTrackerContext*>(output_surface->context3d());
+  scoped_ptr<ReshapeTrackerContext> owned_reshape_tracker(
+      new ReshapeTrackerContext);
+  ReshapeTrackerContext* reshape_tracker = owned_reshape_tracker.get();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      owned_reshape_tracker.PassAs<TestWebGraphicsContext3D>()));
   host_impl_->InitializeRenderer(output_surface.Pass());
 
   scoped_ptr<LayerImpl> root =
@@ -3175,11 +3175,11 @@
 // Make sure damage tracking propagates all the way to the graphics context,
 // where it should request to swap only the sub-buffer that is damaged.
 TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new SwapTrackerContext)).PassAs<OutputSurface>();
-  SwapTrackerContext* swap_tracker =
-      static_cast<SwapTrackerContext*>(output_surface->context3d());
+  scoped_ptr<SwapTrackerContext> context(new SwapTrackerContext);
+  SwapTrackerContext* swap_tracker = context.get();
+
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context.PassAs<TestWebGraphicsContext3D>()));
 
   // This test creates its own LayerTreeHostImpl, so
   // that we can force partial swap enabled.
@@ -3414,11 +3414,11 @@
 };
 
 TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new MockContext)).PassAs<OutputSurface>();
-  MockContext* mock_context =
-      static_cast<MockContext*>(output_surface->context3d());
+  scoped_ptr<MockContext> mock_context_owned(new MockContext);
+  MockContext* mock_context = mock_context_owned.get();
+
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
   MockContextHarness harness(mock_context);
 
   // Run test case
@@ -3451,11 +3451,10 @@
 }
 
 TEST_F(LayerTreeHostImplTest, PartialSwap) {
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new MockContext)).PassAs<OutputSurface>();
-  MockContext* mock_context =
-      static_cast<MockContext*>(output_surface->context3d());
+  scoped_ptr<MockContext> context_owned(new MockContext);
+  MockContext* mock_context = context_owned.get();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      context_owned.PassAs<TestWebGraphicsContext3D>()));
   MockContextHarness harness(mock_context);
 
   CreateLayerTreeHost(true, output_surface.Pass());
@@ -3515,9 +3514,8 @@
     LayerTreeHostImplClient* client,
     Proxy* proxy,
     RenderingStatsInstrumentation* stats_instrumentation) {
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
 
   LayerTreeSettings settings;
   settings.partial_swap_enabled = partial_swap;
@@ -3672,8 +3670,8 @@
   scoped_ptr<TestWebGraphicsContext3D> context =
       TestWebGraphicsContext3D::Create();
   TestWebGraphicsContext3D* context3d = context.get();
-  scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
-      context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(
+      FakeOutputSurface::Create3d(context.Pass()));
   host_impl_->InitializeRenderer(output_surface.Pass());
 
   scoped_ptr<LayerImpl> root_layer =
@@ -3732,12 +3730,12 @@
 };
 
 TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new MockDrawQuadsToFillScreenContext)).PassAs<OutputSurface>();
-  MockDrawQuadsToFillScreenContext* mock_context =
-      static_cast<MockDrawQuadsToFillScreenContext*>(
-          output_surface->context3d());
+  scoped_ptr<MockDrawQuadsToFillScreenContext> mock_context_owned(
+      new MockDrawQuadsToFillScreenContext);
+  MockDrawQuadsToFillScreenContext* mock_context = mock_context_owned.get();
+
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
 
   // Run test case
   CreateLayerTreeHost(false, output_surface.Pass());
@@ -3790,9 +3788,8 @@
     LayerImpl*& surface_layer_ptr,
     LayerImpl*& child_ptr,
     gfx::Size root_size) {
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
 
   layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
   layer_tree_host_impl->SetViewportSize(root_size);
@@ -3869,9 +3866,8 @@
   LayerImpl* layer_s1_ptr;
   LayerImpl* layer_s2_ptr;
 
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
 
   gfx::Size root_size(1000, 1000);
 
@@ -3988,9 +3984,8 @@
   LayerImpl* layer_s1_ptr;
   LayerImpl* layer_s2_ptr;
 
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
 
   gfx::Size root_size(1000, 1000);
 
@@ -4109,9 +4104,8 @@
   LayerImpl* layer_s1_ptr;
   LayerImpl* layer_s2_ptr;
 
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
 
   gfx::Size root_size(1000, 1000);
 
@@ -4199,9 +4193,8 @@
   LayerImpl* root_ptr;
   LayerImpl* layer_s1_ptr;
 
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
 
   gfx::Size root_size(1000, 1000);
 
@@ -4290,9 +4283,8 @@
   LayerImpl* layer_s1_ptr;
   LayerImpl* layer_s2_ptr;
 
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
 
   gfx::Size root_size(1000, 1000);
 
@@ -4420,9 +4412,8 @@
   gfx::Rect child_rect(10, 10, 50, 50);
   gfx::Rect grand_child_rect(5, 5, 150, 150);
 
-  scoped_ptr<OutputSurface> output_surface =
-      FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new PartialSwapContext)).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+      scoped_ptr<TestWebGraphicsContext3D>(new PartialSwapContext)));
   my_host_impl->InitializeRenderer(output_surface.Pass());
 
   root->SetAnchorPoint(gfx::PointF());
@@ -5296,8 +5287,11 @@
 }
 
 TEST_F(LayerTreeHostImplTest, TestRemoveRenderPasses) {
+  FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface(CreateOutputSurface());
-  ASSERT_TRUE(output_surface->context3d());
+  ASSERT_TRUE(output_surface->BindToClient(&output_surface_client));
+  ASSERT_TRUE(output_surface->context_provider());
+
   scoped_ptr<ResourceProvider> resource_provider =
       ResourceProvider::Create(output_surface.get(), 0);
 
@@ -6213,9 +6207,8 @@
 
   // DeferredInitialize and hardware draw.
   EXPECT_FALSE(did_try_initialize_renderer_);
-  EXPECT_TRUE(output_surface_ptr->SetAndInitializeContext3D(
-      scoped_ptr<WebKit::WebGraphicsContext3D>(
-          TestWebGraphicsContext3D::Create())));
+  EXPECT_TRUE(output_surface_ptr->InitializeAndSetContext3d(
+      TestContextProvider::Create(), NULL));
   EXPECT_TRUE(did_try_initialize_renderer_);
 
   // Defer intialized GL draw.
@@ -6246,10 +6239,10 @@
                                          &proxy_,
                                          &stats_instrumentation_);
 
-  host_impl_->InitializeRenderer(FakeOutputSurface::Create3d(
-      scoped_ptr<WebKit::WebGraphicsContext3D>(
-          new ContextThatDoesNotSupportMemoryManagmentExtensions))
-      .PassAs<OutputSurface>());
+  scoped_ptr<OutputSurface> output_surface(
+      FakeOutputSurface::Create3d(scoped_ptr<TestWebGraphicsContext3D>(
+          new ContextThatDoesNotSupportMemoryManagmentExtensions)));
+  host_impl_->InitializeRenderer(output_surface.Pass());
   EXPECT_LT(0ul, host_impl_->memory_allocation_limit_bytes());
 }
 
@@ -6280,8 +6273,7 @@
   scoped_ptr<TestWebGraphicsContext3D> context =
       TestWebGraphicsContext3D::Create();
   TestWebGraphicsContext3D* context3d = context.get();
-  scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
-      context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
+  scoped_ptr<OutputSurface> output_surface = CreateFakeOutputSurface();
   host_impl_->InitializeRenderer(output_surface.Pass());
 
   EXPECT_EQ(0u, context3d->NumTextures());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index b18a88a..73033a1 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -10,12 +10,13 @@
 #include "base/synchronization/lock.h"
 #include "cc/animation/timing_function.h"
 #include "cc/debug/frame_rate_counter.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/layers/content_layer.h"
 #include "cc/layers/content_layer_client.h"
 #include "cc/layers/io_surface_layer.h"
 #include "cc/layers/layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer.h"
 #include "cc/layers/picture_layer.h"
-#include "cc/layers/scrollbar_layer.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/layers/video_layer.h"
 #include "cc/output/begin_frame_args.h"
@@ -30,11 +31,11 @@
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_painted_scrollbar_layer.h"
 #include "cc/test/fake_picture_layer.h"
 #include "cc/test/fake_picture_layer_impl.h"
 #include "cc/test/fake_proxy.h"
 #include "cc/test/fake_scoped_ui_resource.h"
-#include "cc/test/fake_scrollbar_layer.h"
 #include "cc/test/fake_video_frame_provider.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/layer_tree_test.h"
@@ -393,9 +394,8 @@
 
     bool paint_scrollbar = true;
     bool has_thumb = false;
-    scrollbar_ = FakeScrollbarLayer::Create(paint_scrollbar,
-                                            has_thumb,
-                                            root_layer_->id());
+    scrollbar_ = FakePaintedScrollbarLayer::Create(
+        paint_scrollbar, has_thumb, root_layer_->id());
     scrollbar_->SetPosition(gfx::Point(0, 10));
     scrollbar_->SetBounds(gfx::Size(10, 10));
 
@@ -436,7 +436,7 @@
  private:
   FakeContentLayerClient client_;
   scoped_refptr<Layer> root_layer_;
-  scoped_refptr<FakeScrollbarLayer> scrollbar_;
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -1111,7 +1111,7 @@
 MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers);
 
 // Verify atomicity of commits and reuse of textures.
-class LayerTreeHostTestAtomicCommit : public LayerTreeHostTest {
+class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
  public:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
     // Make sure partial texture updates are turned off.
@@ -1126,8 +1126,8 @@
 
     bool paint_scrollbar = true;
     bool has_thumb = false;
-    scrollbar_ =
-        FakeScrollbarLayer::Create(paint_scrollbar, has_thumb, layer_->id());
+    scrollbar_ = FakePaintedScrollbarLayer::Create(
+        paint_scrollbar, has_thumb, layer_->id());
     scrollbar_->SetPosition(gfx::Point(0, 10));
     scrollbar_->SetBounds(gfx::Size(10, 10));
 
@@ -1146,7 +1146,7 @@
     ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
 
     TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context3d());
+        impl->output_surface()->context_provider()->Context3d());
 
     switch (impl->active_tree()->source_frame_number()) {
       case 0:
@@ -1162,19 +1162,18 @@
         PostSetNeedsCommitToMainThread();
         break;
       case 1:
-        // Number of textures should be doubled as the first textures
-        // are used by impl thread and cannot by used for update.
-        ASSERT_EQ(4u, context->NumTextures());
-        // Number of textures used for commit should still be
-        // one for each layer.
+        // Number of textures should be one for scrollbar layer since it was
+        // requested and deleted on the impl-thread, and double for the content
+        // layer since its first texture is used by impl thread and cannot by
+        // used for update.
+        ASSERT_EQ(3u, context->NumTextures());
+        // Number of textures used for commit should be one for each layer.
         EXPECT_EQ(2u, context->NumUsedTextures());
         // First textures should not have been used.
         EXPECT_FALSE(context->UsedTexture(context->TextureAt(0)));
-        EXPECT_FALSE(context->UsedTexture(context->TextureAt(1)));
+        EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
         // New textures should have been used.
         EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
-        EXPECT_TRUE(context->UsedTexture(context->TextureAt(3)));
-
         context->ResetUsedTextures();
         PostSetNeedsCommitToMainThread();
         break;
@@ -1189,7 +1188,7 @@
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
     TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context3d());
+        impl->output_surface()->context_provider()->Context3d());
 
     if (drew_frame_ == impl->active_tree()->source_frame_number()) {
       EXPECT_EQ(0u, context->NumUsedTextures()) << "For frame " << drew_frame_;
@@ -1209,14 +1208,68 @@
 
   virtual void AfterTest() OVERRIDE {}
 
- private:
+ protected:
   FakeContentLayerClient client_;
   scoped_refptr<FakeContentLayer> layer_;
-  scoped_refptr<FakeScrollbarLayer> scrollbar_;
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_;
   int drew_frame_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestAtomicCommit);
+MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+    LayerTreeHostTestDirectRendererAtomicCommit);
+
+class LayerTreeHostTestDelegatingRendererAtomicCommit
+    : public LayerTreeHostTestDirectRendererAtomicCommit {
+ public:
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
+
+    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
+        impl->output_surface()->context_provider()->Context3d());
+
+    switch (impl->active_tree()->source_frame_number()) {
+      case 0:
+        // Number of textures should be one for each layer
+        ASSERT_EQ(2u, context->NumTextures());
+        // Number of textures used for commit should be one for each layer.
+        EXPECT_EQ(2u, context->NumUsedTextures());
+        // Verify that used texture is correct.
+        EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
+        EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
+        context->ResetUsedTextures();
+        PostSetNeedsCommitToMainThread();
+        break;
+      case 1:
+        // Number of textures should be doubled as the first context layer
+        // texture is being used by the impl-thread and cannot be used for
+        // update.  The scrollbar behavior is different direct renderer because
+        // UI resource deletion with delegating renderer occurs after tree
+        // activation.
+        ASSERT_EQ(4u, context->NumTextures());
+        // Number of textures used for commit should still be
+        // one for each layer.
+        EXPECT_EQ(2u, context->NumUsedTextures());
+        // First textures should not have been used.
+        EXPECT_FALSE(context->UsedTexture(context->TextureAt(0)));
+        EXPECT_FALSE(context->UsedTexture(context->TextureAt(1)));
+        // New textures should have been used.
+        EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
+        EXPECT_TRUE(context->UsedTexture(context->TextureAt(3)));
+        context->ResetUsedTextures();
+        PostSetNeedsCommitToMainThread();
+        break;
+      case 2:
+        EndTest();
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+};
+
+MULTI_THREAD_DELEGATING_RENDERER_TEST_F(
+    LayerTreeHostTestDelegatingRendererAtomicCommit);
 
 static void SetLayerPropertiesForTesting(Layer* layer,
                                          Layer* parent,
@@ -1294,7 +1347,7 @@
     ASSERT_EQ(1u, layer_tree_host()->settings().max_partial_texture_updates);
 
     TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context3d());
+        impl->output_surface()->context_provider()->Context3d());
 
     switch (impl->active_tree()->source_frame_number()) {
       case 0:
@@ -1359,7 +1412,7 @@
     EXPECT_LT(impl->active_tree()->source_frame_number(), 5);
 
     TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context3d());
+        impl->output_surface()->context_provider()->Context3d());
 
     // Number of textures used for drawing should one per layer except for
     // frame 3 where the viewport only contains one layer.
@@ -2317,23 +2370,12 @@
 
 SINGLE_THREAD_TEST_F(LayerTreeHostTestChangeLayerPropertiesInPaintContents);
 
-class MockIOSurfaceWebGraphicsContext3D : public FakeWebGraphicsContext3D {
+class MockIOSurfaceWebGraphicsContext3D : public TestWebGraphicsContext3D {
  public:
-  MockIOSurfaceWebGraphicsContext3D()
-      : FakeWebGraphicsContext3D() {}
-
   virtual WebKit::WebGLId createTexture() OVERRIDE {
     return 1;
   }
 
-  virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE {
-    if (name == GL_EXTENSIONS) {
-      return WebKit::WebString(
-          "GL_CHROMIUM_iosurface GL_ARB_texture_rectangle");
-    }
-    return WebKit::WebString();
-  }
-
   MOCK_METHOD1(activeTexture, void(WebKit::WGC3Denum texture));
   MOCK_METHOD2(bindTexture, void(WebKit::WGC3Denum target,
                                  WebKit::WebGLId texture_id));
@@ -2349,6 +2391,7 @@
                                   WebKit::WGC3Dsizei count,
                                   WebKit::WGC3Denum type,
                                   WebKit::WGC3Dintptr offset));
+  MOCK_METHOD1(deleteTexture, void(WebKit::WGC3Denum texture));
 };
 
 
@@ -2356,11 +2399,14 @@
  protected:
   virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
       OVERRIDE {
-    scoped_ptr<MockIOSurfaceWebGraphicsContext3D> context(
+    scoped_ptr<MockIOSurfaceWebGraphicsContext3D> mock_context_owned(
         new MockIOSurfaceWebGraphicsContext3D);
-    mock_context_ = context.get();
-    scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d(
-        context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>();
+    mock_context_ = mock_context_owned.get();
+
+    mock_context_->set_have_extension_io_surface(true);
+
+    scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+        mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
     return output_surface.Pass();
   }
 
@@ -2439,6 +2485,8 @@
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     Mock::VerifyAndClearExpectations(&mock_context_);
+
+    EXPECT_CALL(*mock_context_, deleteTexture(1)).Times(1);
     EndTest();
   }
 
@@ -2542,10 +2590,14 @@
 
   virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
       OVERRIDE {
-    if (use_gl_renderer_)
-      return FakeOutputSurface::Create3d().PassAs<OutputSurface>();
-    return FakeOutputSurface::CreateSoftware(
-        make_scoped_ptr(new SoftwareOutputDevice)).PassAs<OutputSurface>();
+    scoped_ptr<FakeOutputSurface> output_surface;
+    if (use_gl_renderer_) {
+      output_surface = FakeOutputSurface::Create3d().Pass();
+    } else {
+      output_surface = FakeOutputSurface::CreateSoftware(
+          make_scoped_ptr(new SoftwareOutputDevice)).Pass();
+    }
+    return output_surface.PassAs<OutputSurface>();
   }
 
   bool use_gl_renderer_;
@@ -2984,6 +3036,144 @@
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
     LayerTreeHostTestAsyncTwoReadbacksWithoutDraw);
 
+class LayerTreeHostTestAsyncReadbackLostOutputSurface
+    : public LayerTreeHostTest {
+ protected:
+  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+      OVERRIDE {
+    if (!first_context_provider_.get()) {
+      first_context_provider_ = TestContextProvider::Create();
+      return FakeOutputSurface::Create3d(first_context_provider_)
+          .PassAs<OutputSurface>();
+    }
+
+    EXPECT_FALSE(second_context_provider_.get());
+    second_context_provider_ = TestContextProvider::Create();
+    return FakeOutputSurface::Create3d(second_context_provider_)
+        .PassAs<OutputSurface>();
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    root_ = FakeContentLayer::Create(&client_);
+    root_->SetBounds(gfx::Size(20, 20));
+
+    copy_layer_ = FakeContentLayer::Create(&client_);
+    copy_layer_->SetBounds(gfx::Size(10, 10));
+    root_->AddChild(copy_layer_);
+
+    layer_tree_host()->SetRootLayer(root_);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
+    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
+    EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString());
+    EXPECT_TRUE(result->HasTexture());
+
+    // Save the result for later.
+    EXPECT_FALSE(result_);
+    result_ = result.Pass();
+
+    // Post a commit to lose the output surface.
+    layer_tree_host()->SetNeedsCommit();
+  }
+
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        // The layers have been pushed to the impl side. The layer textures have
+        // been allocated.
+
+        // Request a copy of the layer. This will use another texture.
+        copy_layer_->RequestCopyOfOutput(
+            CopyOutputRequest::CreateRequest(base::Bind(
+                &LayerTreeHostTestAsyncReadbackLostOutputSurface::
+                CopyOutputCallback,
+                base::Unretained(this))));
+        break;
+      case 4:
+        // With SingleThreadProxy it takes two commits to finally swap after a
+        // context loss.
+      case 5:
+        // Now destroy the CopyOutputResult, releasing the texture inside back
+        // to the compositor.
+        EXPECT_TRUE(result_);
+        result_.reset();
+
+        // Check that it is released.
+        base::SingleThreadTaskRunner* task_runner =
+            HasImplThread() ? ImplThreadTaskRunner()
+                            : base::MessageLoopProxy::current();
+        task_runner->PostTask(
+            FROM_HERE,
+            base::Bind(&LayerTreeHostTestAsyncReadbackLostOutputSurface::
+                           CheckNumTextures,
+                       base::Unretained(this),
+                       num_textures_after_loss_ - 1));
+        break;
+    }
+  }
+
+  virtual void SwapBuffersOnThread(LayerTreeHostImpl *impl, bool result)
+      OVERRIDE {
+    switch (impl->active_tree()->source_frame_number()) {
+      case 0:
+        // The layers have been drawn, so their textures have been allocated.
+        EXPECT_FALSE(result_);
+        num_textures_without_readback_ =
+            first_context_provider_->TestContext3d()->NumTextures();
+        break;
+      case 1:
+        // We did a readback, so there will be a readback texture around now.
+        EXPECT_LT(num_textures_without_readback_,
+                  first_context_provider_->TestContext3d()->NumTextures());
+        break;
+      case 2:
+        // The readback texture is collected.
+        EXPECT_TRUE(result_);
+
+        // Lose the output surface.
+        first_context_provider_->TestContext3d()->loseContextCHROMIUM(
+            GL_GUILTY_CONTEXT_RESET_ARB,
+            GL_INNOCENT_CONTEXT_RESET_ARB);
+        break;
+      case 3:
+        // With SingleThreadProxy it takes two commits to finally swap after a
+        // context loss.
+      case 4:
+        // The output surface has been recreated.
+        EXPECT_TRUE(second_context_provider_.get());
+
+        num_textures_after_loss_ =
+            first_context_provider_->TestContext3d()->NumTextures();
+        break;
+    }
+  }
+
+  void CheckNumTextures(size_t expected_num_textures) {
+    EXPECT_EQ(expected_num_textures,
+              first_context_provider_->TestContext3d()->NumTextures());
+    EndTest();
+  }
+
+  virtual void AfterTest() OVERRIDE {}
+
+  scoped_refptr<TestContextProvider> first_context_provider_;
+  scoped_refptr<TestContextProvider> second_context_provider_;
+  size_t num_textures_without_readback_;
+  size_t num_textures_after_loss_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakeContentLayer> root_;
+  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_ptr<CopyOutputResult> result_;
+};
+
+// No output to copy for delegated renderers.
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+    LayerTreeHostTestAsyncReadbackLostOutputSurface);
+
 class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
  public:
   virtual void BeginTest() OVERRIDE {
@@ -3130,10 +3320,12 @@
   void DeferredInitializeAndRedraw(LayerTreeHostImpl* host_impl) {
     EXPECT_FALSE(did_initialize_gl_);
     // SetAndInitializeContext3D calls SetNeedsCommit.
-    EXPECT_TRUE(static_cast<FakeOutputSurface*>(host_impl->output_surface())
-                    ->SetAndInitializeContext3D(
-                          scoped_ptr<WebKit::WebGraphicsContext3D>(
-                              TestWebGraphicsContext3D::Create())));
+    FakeOutputSurface* fake_output_surface =
+        static_cast<FakeOutputSurface*>(host_impl->output_surface());
+    scoped_refptr<TestContextProvider> context_provider =
+        TestContextProvider::Create();  // Not bound to thread.
+    EXPECT_TRUE(fake_output_surface->InitializeAndSetContext3d(
+        context_provider, NULL));
     did_initialize_gl_ = true;
   }
 
@@ -3201,7 +3393,7 @@
 
   void PerformTest(LayerTreeHostImpl* impl) {
     TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context3d());
+        impl->output_surface()->context_provider()->Context3d());
 
     int frame = num_commits_;
     switch (frame) {
@@ -3313,19 +3505,13 @@
     child_ = PushPropertiesCountingLayer::Create();
     child2_ = PushPropertiesCountingLayer::Create();
     grandchild_ = PushPropertiesCountingLayer::Create();
-
-    if (layer_tree_host()->settings().impl_side_painting)
-      leaf_picture_layer_ = FakePictureLayer::Create(&client_);
-    else
-      leaf_content_layer_ = FakeContentLayer::Create(&client_);
+    leaf_scrollbar_layer_ =
+        FakePaintedScrollbarLayer::Create(false, false, root_->id());
 
     root_->AddChild(child_);
     root_->AddChild(child2_);
     child_->AddChild(grandchild_);
-    if (leaf_picture_layer_)
-      child2_->AddChild(leaf_picture_layer_);
-    if (leaf_content_layer_)
-      child2_->AddChild(leaf_content_layer_);
+    child2_->AddChild(leaf_scrollbar_layer_);
 
     other_root_ = PushPropertiesCountingLayer::Create();
 
@@ -3344,16 +3530,10 @@
               child2_->push_properties_count());
     EXPECT_EQ(expected_push_properties_other_root_,
               other_root_->push_properties_count());
-    if (leaf_content_layer_) {
-      EXPECT_EQ(expected_push_properties_leaf_layer_,
-                leaf_content_layer_->push_properties_count());
-    }
-    if (leaf_picture_layer_) {
-      EXPECT_EQ(expected_push_properties_leaf_layer_,
-                leaf_picture_layer_->push_properties_count());
-    }
+    EXPECT_EQ(expected_push_properties_leaf_layer_,
+              leaf_scrollbar_layer_->push_properties_count());
 
-    // The content/picture layer always needs to be pushed.
+    // The scrollbar layer always needs to be pushed.
     if (root_->layer_tree_host()) {
       EXPECT_TRUE(root_->descendant_needs_push_properties());
       EXPECT_FALSE(root_->needs_push_properties());
@@ -3362,13 +3542,9 @@
       EXPECT_TRUE(child2_->descendant_needs_push_properties());
       EXPECT_FALSE(child2_->needs_push_properties());
     }
-    if (leaf_content_layer_.get() && leaf_content_layer_->layer_tree_host()) {
-      EXPECT_FALSE(leaf_content_layer_->descendant_needs_push_properties());
-      EXPECT_TRUE(leaf_content_layer_->needs_push_properties());
-    }
-    if (leaf_picture_layer_.get() && leaf_picture_layer_->layer_tree_host()) {
-      EXPECT_FALSE(leaf_picture_layer_->descendant_needs_push_properties());
-      EXPECT_TRUE(leaf_picture_layer_->needs_push_properties());
+    if (leaf_scrollbar_layer_->layer_tree_host()) {
+      EXPECT_FALSE(leaf_scrollbar_layer_->descendant_needs_push_properties());
+      EXPECT_TRUE(leaf_scrollbar_layer_->needs_push_properties());
     }
 
     // child_ and grandchild_ don't persist their need to push properties.
@@ -3479,8 +3655,7 @@
 
     // Content/Picture layers require PushProperties every commit that they are
     // in the tree.
-    if ((leaf_content_layer_.get() && leaf_content_layer_->layer_tree_host()) ||
-        (leaf_picture_layer_.get() && leaf_picture_layer_->layer_tree_host()))
+    if (leaf_scrollbar_layer_->layer_tree_host())
       ++expected_push_properties_leaf_layer_;
   }
 
@@ -3493,8 +3668,7 @@
   scoped_refptr<PushPropertiesCountingLayer> child2_;
   scoped_refptr<PushPropertiesCountingLayer> grandchild_;
   scoped_refptr<PushPropertiesCountingLayer> other_root_;
-  scoped_refptr<FakeContentLayer> leaf_content_layer_;
-  scoped_refptr<FakePictureLayer> leaf_picture_layer_;
+  scoped_refptr<FakePaintedScrollbarLayer> leaf_scrollbar_layer_;
   size_t expected_push_properties_root_;
   size_t expected_push_properties_child_;
   size_t expected_push_properties_child2_;
@@ -3518,8 +3692,8 @@
 
     bool paint_scrollbar = true;
     bool has_thumb = false;
-    scrollbar_layer_ =
-        FakeScrollbarLayer::Create(paint_scrollbar, has_thumb, root_->id());
+    scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
+        paint_scrollbar, has_thumb, root_->id());
 
     root_->AddChild(scrollbar_layer_);
 
@@ -3559,7 +3733,7 @@
   virtual void AfterTest() OVERRIDE {}
 
   scoped_refptr<Layer> root_;
-  scoped_refptr<FakeScrollbarLayer> scrollbar_layer_;
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestPropertyChangesDuringUpdateArePushed);
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 1787d31..d9ae64c 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -5,12 +5,14 @@
 #include "cc/trees/layer_tree_host.h"
 
 #include "base/basictypes.h"
+#include "cc/debug/test_context_provider.h"
+#include "cc/debug/test_web_graphics_context_3d.h"
 #include "cc/layers/content_layer.h"
 #include "cc/layers/heads_up_display_layer.h"
 #include "cc/layers/io_surface_layer.h"
 #include "cc/layers/layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer.h"
 #include "cc/layers/picture_layer.h"
-#include "cc/layers/scrollbar_layer.h"
 #include "cc/layers/texture_layer.h"
 #include "cc/layers/texture_layer_impl.h"
 #include "cc/layers/video_layer.h"
@@ -19,18 +21,16 @@
 #include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_content_layer_impl.h"
-#include "cc/test/fake_context_provider.h"
 #include "cc/test/fake_delegated_renderer_layer.h"
 #include "cc/test/fake_delegated_renderer_layer_impl.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_painted_scrollbar_layer.h"
 #include "cc/test/fake_scoped_ui_resource.h"
 #include "cc/test/fake_scrollbar.h"
-#include "cc/test/fake_scrollbar_layer.h"
 #include "cc/test/fake_video_frame_provider.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/render_pass_test_common.h"
-#include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "cc/trees/single_thread_proxy.h"
@@ -108,11 +108,11 @@
     }
 
     if (delegating_renderer()) {
-      return FakeOutputSurface::CreateDelegating3d(
-          context3d.PassAs<WebGraphicsContext3D>()).PassAs<OutputSurface>();
+      return FakeOutputSurface::CreateDelegating3d(context3d.Pass())
+          .PassAs<OutputSurface>();
     }
-    return FakeOutputSurface::Create3d(
-        context3d.PassAs<WebGraphicsContext3D>()).PassAs<OutputSurface>();
+    return FakeOutputSurface::Create3d(context3d.Pass())
+        .PassAs<OutputSurface>();
   }
 
   scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
@@ -141,10 +141,11 @@
 
     if (!offscreen_contexts_main_thread_.get() ||
         offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
-      offscreen_contexts_main_thread_ = FakeContextProvider::Create(
-          base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
-                     base::Unretained(this)));
-      if (offscreen_contexts_main_thread_.get() &&
+      offscreen_contexts_main_thread_ =
+          TestContextProvider::Create(
+              base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
+                         base::Unretained(this)));
+      if (offscreen_contexts_main_thread_ &&
           !offscreen_contexts_main_thread_->BindToCurrentThread())
         offscreen_contexts_main_thread_ = NULL;
     }
@@ -157,9 +158,10 @@
 
     if (!offscreen_contexts_compositor_thread_.get() ||
         offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
-      offscreen_contexts_compositor_thread_ = FakeContextProvider::Create(
-          base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
-                     base::Unretained(this)));
+      offscreen_contexts_compositor_thread_ =
+          TestContextProvider::Create(
+              base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
+                         base::Unretained(this)));
     }
     return offscreen_contexts_compositor_thread_;
   }
@@ -236,8 +238,8 @@
   bool context_should_support_io_surface_;
   bool fallback_context_works_;
 
-  scoped_refptr<FakeContextProvider> offscreen_contexts_main_thread_;
-  scoped_refptr<FakeContextProvider> offscreen_contexts_compositor_thread_;
+  scoped_refptr<TestContextProvider> offscreen_contexts_main_thread_;
+  scoped_refptr<TestContextProvider> offscreen_contexts_compositor_thread_;
 };
 
 class LayerTreeHostContextTestLostContextSucceeds
@@ -1198,9 +1200,9 @@
     debug_state.show_property_changed_rects = true;
     layer_tree_host()->SetDebugState(debug_state);
 
-    scoped_refptr<ScrollbarLayer> scrollbar_ = ScrollbarLayer::Create(
-        scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(),
-        content_->id());
+    scoped_refptr<PaintedScrollbarLayer> scrollbar_ =
+        PaintedScrollbarLayer::Create(
+            scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content_->id());
     scrollbar_->SetBounds(gfx::Size(10, 10));
     scrollbar_->SetAnchorPoint(gfx::PointF());
     scrollbar_->SetIsDrawable(true);
@@ -1219,6 +1221,10 @@
     LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
 
     ResourceProvider* resource_provider = host_impl->resource_provider();
+    ContextProvider* context_provider =
+        host_impl->output_surface()->context_provider();
+
+    DCHECK(context_provider);
 
     if (host_impl->active_tree()->source_frame_number() == 0) {
       // Set up impl resources on the first commit.
@@ -1255,9 +1261,8 @@
           static_cast<TextureLayerImpl*>(
               host_impl->active_tree()->root_layer()->children()[2]);
       texture_impl->set_texture_id(
-          resource_provider->GraphicsContext3D()->createTexture());
+          context_provider->Context3d()->createTexture());
 
-      DCHECK(resource_provider->GraphicsContext3D());
       ResourceProvider::ResourceId texture = resource_provider->CreateResource(
           gfx::Size(4, 4),
           resource_provider->default_resource_type(),
@@ -1265,9 +1270,8 @@
       ResourceProvider::ScopedWriteLockGL lock(resource_provider, texture);
 
       gpu::Mailbox mailbox;
-      resource_provider->GraphicsContext3D()->genMailboxCHROMIUM(mailbox.name);
-      unsigned sync_point =
-          resource_provider->GraphicsContext3D()->insertSyncPoint();
+      context_provider->Context3d()->genMailboxCHROMIUM(mailbox.name);
+      unsigned sync_point = context_provider->Context3d()->insertSyncPoint();
 
       color_video_frame_ = VideoFrame::CreateColorFrame(
           gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
@@ -1343,7 +1347,7 @@
   scoped_refptr<VideoLayer> video_hw_;
   scoped_refptr<VideoLayer> video_scaled_hw_;
   scoped_refptr<IOSurfaceLayer> io_surface_;
-  scoped_refptr<ScrollbarLayer> scrollbar_;
+  scoped_refptr<PaintedScrollbarLayer> scrollbar_;
 
   scoped_refptr<VideoFrame> color_video_frame_;
   scoped_refptr<VideoFrame> hw_video_frame_;
@@ -1515,7 +1519,7 @@
 
   virtual void BeginTest() OVERRIDE {
     scoped_refptr<Layer> scroll_layer = Layer::Create();
-    scrollbar_layer_ = FakeScrollbarLayer::Create(
+    scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
         false, true, scroll_layer->id());
     scrollbar_layer_->SetBounds(gfx::Size(10, 100));
     layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
@@ -1549,7 +1553,7 @@
 
  private:
   int commits_;
-  scoped_refptr<FakeScrollbarLayer> scrollbar_layer_;
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index e8ae7a2..a3a8af3 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -6,6 +6,7 @@
 
 #include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_painted_scrollbar_layer.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/trees/damage_tracker.h"
 #include "cc/trees/layer_tree_impl.h"
@@ -285,5 +286,108 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestForcedFullDamage);
 
+class LayerTreeHostDamageTestScrollbarDoesDamage
+    : public LayerTreeHostDamageTest {
+  virtual void BeginTest() OVERRIDE {
+    did_swaps_ = 0;
+    PostSetNeedsCommitToMainThread();
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    scoped_refptr<Layer> root_layer = Layer::Create();
+    root_layer->SetBounds(gfx::Size(400, 400));
+    layer_tree_host()->SetRootLayer(root_layer);
+
+    scoped_refptr<Layer> content_layer = FakeContentLayer::Create(&client_);
+    content_layer->SetScrollable(true);
+    content_layer->SetScrollOffset(gfx::Vector2d(10, 20));
+    content_layer->SetMaxScrollOffset(gfx::Vector2d(30, 50));
+    content_layer->SetBounds(gfx::Size(100, 200));
+    root_layer->AddChild(content_layer);
+
+    scoped_refptr<Layer> scrollbar_layer =
+        FakePaintedScrollbarLayer::Create(false, true, content_layer->id());
+    scrollbar_layer->SetPosition(gfx::Point(300, 300));
+    scrollbar_layer->SetBounds(gfx::Size(10, 100));
+    root_layer->AddChild(scrollbar_layer);
+
+    gfx::RectF content_rect(content_layer->position(),
+                            content_layer->bounds());
+    gfx::RectF scrollbar_rect(scrollbar_layer->position(),
+                              scrollbar_layer->bounds());
+    EXPECT_FALSE(content_rect.Intersects(scrollbar_rect));
+
+    LayerTreeHostDamageTest::SetupTree();
+  }
+
+  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                     LayerTreeHostImpl::FrameData* frame_data,
+                                     bool result) OVERRIDE {
+    EXPECT_TRUE(result);
+    RenderSurfaceImpl* root_surface =
+        host_impl->active_tree()->root_layer()->render_surface();
+    gfx::RectF root_damage =
+        root_surface->damage_tracker()->current_damage_rect();
+    root_damage.Intersect(root_surface->content_rect());
+    switch (did_swaps_) {
+      case 0:
+        // The first frame has damage, so we should draw and swap.
+        break;
+      case 1:
+        // The second frame should not damage the scrollbars.
+        EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100)));
+        break;
+      case 2:
+        // The third frame should damage the scrollbars.
+        EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100)));
+        break;
+      case 3:
+        // The fourth frame should damage the scrollbars.
+        EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100)));
+        EndTest();
+        break;
+    }
+    return result;
+  }
+
+  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+                                   bool result) OVERRIDE {
+    ++did_swaps_;
+    EXPECT_TRUE(result);
+    LayerImpl* root = host_impl->active_tree()->root_layer();
+    LayerImpl* scroll_layer = root->children()[0];
+    switch (did_swaps_) {
+      case 1:
+        // Test that modifying the position of the content layer (not
+        // scrolling) won't damage the scrollbar. Do this before the other
+        // tests, as they can cause commits that will later damage the
+        // scrollbar. http://crbug.com/276657
+        scroll_layer->SetPosition(gfx::Point(1, 1));
+        scroll_layer->SetScrollOffset(scroll_layer->scroll_offset());
+        host_impl->SetNeedsRedraw();
+        break;
+      case 2:
+        host_impl->ScrollBegin(gfx::Point(1, 1), InputHandler::Wheel);
+        EXPECT_TRUE(host_impl->ScrollBy(gfx::Point(),
+                                        gfx::Vector2dF(10.0, 10.0)));
+        break;
+      case 3:
+        scroll_layer->SetMaxScrollOffset(gfx::Vector2d(60, 100));
+        host_impl->SetNeedsRedraw();
+        break;
+    }
+  }
+
+  virtual void AfterTest() OVERRIDE {
+    // Extra commits may happen and cause swaps: http://crbug.com/276657
+    EXPECT_LE(4, did_swaps_);
+  }
+
+  FakeContentLayerClient client_;
+  int did_swaps_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarDoesDamage);
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_delegated.cc b/cc/trees/layer_tree_host_unittest_delegated.cc
index d489313..721613a 100644
--- a/cc/trees/layer_tree_host_unittest_delegated.cc
+++ b/cc/trees/layer_tree_host_unittest_delegated.cc
@@ -4,6 +4,8 @@
 
 #include "cc/trees/layer_tree_host.h"
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "cc/layers/delegated_renderer_layer.h"
 #include "cc/layers/delegated_renderer_layer_client.h"
@@ -13,16 +15,57 @@
 #include "cc/output/delegated_frame_data.h"
 #include "cc/quads/shared_quad_state.h"
 #include "cc/quads/texture_draw_quad.h"
+#include "cc/resources/returned_resource.h"
 #include "cc/test/fake_delegated_renderer_layer.h"
 #include "cc/test/fake_delegated_renderer_layer_impl.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "gpu/GLES2/gl2extchromium.h"
+#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 
 namespace cc {
 namespace {
 
+bool ReturnedResourceLower(const ReturnedResource& a,
+                           const ReturnedResource& b) {
+  return a.id < b.id;
+}
+
+// Tests if the list of resources matches an expectation, modulo the order.
+bool ResourcesMatch(ReturnedResourceArray actual,
+                    unsigned* expected,
+                    size_t expected_count) {
+  std::sort(actual.begin(), actual.end(), ReturnedResourceLower);
+  std::sort(expected, expected + expected_count);
+  size_t actual_index = 0;
+
+  // for each element of the expected array, count off one of the actual array
+  // (after checking it matches).
+  for (size_t expected_index = 0; expected_index < expected_count;
+       ++expected_index) {
+    EXPECT_LT(actual_index, actual.size());
+    if (actual_index >= actual.size())
+      return false;
+    EXPECT_EQ(actual[actual_index].id, expected[expected_index]);
+    if (actual[actual_index].id != expected[expected_index])
+      return false;
+    EXPECT_GT(actual[actual_index].count, 0);
+    if (actual[actual_index].count <= 0) {
+      return false;
+    } else {
+      --actual[actual_index].count;
+      if (actual[actual_index].count == 0)
+        ++actual_index;
+    }
+  }
+  EXPECT_EQ(actual_index, actual.size());
+  return actual_index == actual.size();
+}
+
+#define EXPECT_RESOURCES(expected, actual) \
+    EXPECT_TRUE(ResourcesMatch(actual, expected, arraysize(expected)));
+
 // These tests deal with delegated renderer layers.
 class LayerTreeHostDelegatedTest : public LayerTreeTest {
  protected:
@@ -246,8 +289,8 @@
     FakeDelegatedRendererLayerImpl* delegated_impl =
         static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
 
-    WebKit::WebGraphicsContext3D* context =
-        host_impl->resource_provider()->GraphicsContext3D();
+    ContextProvider* context_provider =
+        host_impl->output_surface()->context_provider();
 
     ++num_activates_;
     switch (num_activates_) {
@@ -255,8 +298,9 @@
         EXPECT_TRUE(delegated_impl->ChildId());
         EXPECT_FALSE(did_reset_child_id_);
 
-        context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
-                                     GL_INNOCENT_CONTEXT_RESET_ARB);
+        context_provider->Context3d()->loseContextCHROMIUM(
+            GL_GUILTY_CONTEXT_RESET_ARB,
+            GL_INNOCENT_CONTEXT_RESET_ARB);
         break;
       case 3:
         EXPECT_TRUE(delegated_impl->ChildId());
@@ -492,10 +536,20 @@
     scoped_ptr<DelegatedFrameData> frame2 =
         CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
     AddTextureQuad(frame2.get(), 999);
+    AddTransferableResource(frame2.get(), 999);
     AddTextureQuad(frame2.get(), 555);
     AddTransferableResource(frame2.get(), 555);
     delegated_->SetFrameData(frame2.Pass());
 
+    // The resource 999 from frame1 is returned since it is still on the main
+    // thread.
+    ReturnedResourceArray returned_resources;
+    delegated_->TakeUnusedResourcesForChildCompositor(&returned_resources);
+    {
+      unsigned expected[] = {999};
+      EXPECT_RESOURCES(expected, returned_resources);
+    }
+
     PostSetNeedsCommitToMainThread();
   }
 
@@ -585,7 +639,7 @@
 
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -623,8 +677,10 @@
       case 5:
         // 555 is no longer in use.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(555u, resources[0].id);
+        {
+          unsigned expected[] = {555};
+          EXPECT_RESOURCES(expected, resources);
+        }
 
         // Stop using any resources.
         frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
@@ -638,20 +694,16 @@
       case 7:
         // 444 and 999 are no longer in use.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(2u, resources.size());
-        if (resources[0].id == 999) {
-          EXPECT_EQ(999u, resources[0].id);
-          EXPECT_EQ(444u, resources[1].id);
-        } else {
-          EXPECT_EQ(444u, resources[0].id);
-          EXPECT_EQ(999u, resources[1].id);
+        {
+          unsigned expected[] = {444, 999};
+          EXPECT_RESOURCES(expected, resources);
         }
         EndTest();
         break;
     }
 
     // Resource are never immediately released.
-    TransferableResourceArray empty_resources;
+    ReturnedResourceArray empty_resources;
     delegated_->TakeUnusedResourcesForChildCompositor(&empty_resources);
     EXPECT_TRUE(empty_resources.empty());
   }
@@ -676,7 +728,7 @@
 
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -724,8 +776,10 @@
       case 5:
         // The 999 resource is the only unused one.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(999u, resources[0].id);
+        {
+          unsigned expected[] = {999};
+          EXPECT_RESOURCES(expected, resources);
+        }
         EndTest();
         break;
     }
@@ -750,7 +804,7 @@
 
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -793,13 +847,9 @@
         return;
       case 5:
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(2u, resources.size());
-        if (resources[0].id == 555) {
-          EXPECT_EQ(555u, resources[0].id);
-          EXPECT_EQ(444u, resources[1].id);
-        } else {
-          EXPECT_EQ(444u, resources[0].id);
-          EXPECT_EQ(555u, resources[1].id);
+        {
+          unsigned expected[] = {444, 555};
+          EXPECT_RESOURCES(expected, resources);
         }
 
         // The child compositor sends a frame before receiving an for the
@@ -862,7 +912,7 @@
 
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -890,6 +940,7 @@
         // Keep using 999 but stop using 555 and 444.
         frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
         AddTextureQuad(frame.get(), 999);
+        AddTransferableResource(frame.get(), 999);
         delegated_->SetFrameData(frame.Pass());
 
         // Resource are not immediately released.
@@ -909,13 +960,20 @@
         // and 444, which were just released during commit.
         frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
         AddTextureQuad(frame.get(), 999);
+        AddTransferableResource(frame.get(), 999);
         AddTextureQuad(frame.get(), 555);
+        AddTransferableResource(frame.get(), 555);
         AddTextureQuad(frame.get(), 444);
+        AddTransferableResource(frame.get(), 444);
         delegated_->SetFrameData(frame.Pass());
 
-        // The resources are used by the new frame so are not returned.
+        // The resources are used by the new frame but are returned anyway since
+        // we passed them again.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(0u, resources.size());
+        {
+          unsigned expected[] = {444, 555};
+          EXPECT_RESOURCES(expected, resources);
+        }
         break;
       case 6:
         // Retrieve unused resources to the main thread.
@@ -987,7 +1045,7 @@
 
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -1032,8 +1090,10 @@
       case 5:
         // The bad frame's resource is given back to the child compositor.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(444u, resources[0].id);
+        {
+          unsigned expected[] = {444};
+          EXPECT_RESOURCES(expected, resources);
+        }
 
         // Now send a good frame with 999 again.
         frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
@@ -1048,8 +1108,10 @@
       case 7:
         // The unused 555 from the last good frame is now released.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(555u, resources[0].id);
+        {
+          unsigned expected[] = {555};
+          EXPECT_RESOURCES(expected, resources);
+        }
 
         EndTest();
         break;
@@ -1154,7 +1216,7 @@
 
   virtual void DidCommit() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -1169,8 +1231,10 @@
       case 2:
         // The unused resource should be returned.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(999u, resources[0].id);
+        {
+          unsigned expected[] = {999};
+          EXPECT_RESOURCES(expected, resources);
+        }
 
         EndTest();
         break;
@@ -1211,7 +1275,7 @@
 
   virtual void DidCommit() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -1227,14 +1291,34 @@
         // But then we immediately stop using 999.
         frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
         AddTextureQuad(frame.get(), 555);
+        AddTransferableResource(frame.get(), 555);
         delegated_->SetFrameData(frame.Pass());
         break;
       case 2:
-        // The unused resource should be returned.
+        // The unused resources should be returned. 555 is still used, but it's
+        // returned once to account for the first frame.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(999u, resources[0].id);
-
+        {
+          unsigned expected[] = {555, 999};
+          EXPECT_RESOURCES(expected, resources);
+        }
+        // Send a frame with no resources in it.
+        frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+        delegated_->SetFrameData(frame.Pass());
+        break;
+      case 3:
+        // The impl side will get back the resource at some point.
+        // TODO(piman): The test should work without this.
+        layer_tree_host()->SetNeedsCommit();
+        break;
+      case 4:
+        // The now unused resource 555 should be returned.
+        resources.clear();
+        delegated_->TakeUnusedResourcesForChildCompositor(&resources);
+        {
+          unsigned expected[] = {555};
+          EXPECT_RESOURCES(expected, resources);
+        }
         EndTest();
         break;
     }
@@ -1260,6 +1344,11 @@
     EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second));
   }
 
+  virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+                                   bool result) OVERRIDE {
+    ReturnUnusedResourcesFromParent(host_impl);
+  }
+
   virtual void AfterTest() OVERRIDE {}
 };
 
@@ -1270,7 +1359,7 @@
  public:
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -1305,8 +1394,10 @@
       case 4:
         // 999 was returned from the grandparent and could be released.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(999u, resources[0].id);
+        {
+          unsigned expected[] = {999};
+          EXPECT_RESOURCES(expected, resources);
+        }
 
         EndTest();
         break;
@@ -1383,7 +1474,7 @@
 
   virtual void DidCommit() OVERRIDE {
     scoped_ptr<DelegatedFrameData> frame;
-    TransferableResourceArray resources;
+    ReturnedResourceArray resources;
 
     int next_source_frame_number = layer_tree_host()->source_frame_number();
     switch (next_source_frame_number) {
@@ -1404,20 +1495,40 @@
         // Stop using 999 and 444 in this frame and commit.
         frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
         AddTextureQuad(frame.get(), 555);
+        AddTransferableResource(frame.get(), 555);
         delegated_->SetFrameData(frame.Pass());
+        // 999 and 444 will be returned for frame 1, but not 555 since it's in
+        // the current frame.
         break;
       case 3:
         // Don't take resources here, but set a new frame that uses 999 again.
         frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
         AddTextureQuad(frame.get(), 999);
+        AddTransferableResource(frame.get(), 999);
         AddTextureQuad(frame.get(), 555);
+        AddTransferableResource(frame.get(), 555);
         delegated_->SetFrameData(frame.Pass());
         break;
       case 4:
-        // 999 and 555 are in use, but 444 should be returned now.
+        // 555 from frame 1 and 2 isn't returned since it's still in use. 999
+        // from frame 1 is returned though.
         delegated_->TakeUnusedResourcesForChildCompositor(&resources);
-        EXPECT_EQ(1u, resources.size());
-        EXPECT_EQ(444u, resources[0].id);
+        {
+          unsigned expected[] = {444, 999};
+          EXPECT_RESOURCES(expected, resources);
+        }
+
+        frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+        delegated_->SetFrameData(frame.Pass());
+        // 555 will be returned 3 times for frames 1 2 and 3, and 999 will be
+        // returned once for frame 3.
+        break;
+      case 5:
+        delegated_->TakeUnusedResourcesForChildCompositor(&resources);
+        {
+          unsigned expected[] = {555, 555, 555, 999};
+          EXPECT_RESOURCES(expected, resources);
+        }
 
         EndTest();
         break;
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index 303e924..585d5bf 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -833,6 +833,114 @@
 
 MULTI_THREAD_TEST_F(ImplSidePaintingScrollTestSimple);
 
+// This test makes sure that layers pick up scrolls that occur between
+// beginning a commit and finishing a commit (aka scroll deltas not
+// included in sent scroll delta) still apply to layers that don't
+// push properties.
+class ImplSidePaintingScrollTestImplOnlyScroll
+    : public ImplSidePaintingScrollTest {
+ public:
+  ImplSidePaintingScrollTestImplOnlyScroll()
+      : initial_scroll_(20, 10), impl_thread_scroll_(-2, 3) {}
+
+  virtual void BeginTest() OVERRIDE {
+    layer_tree_host()->root_layer()->SetScrollable(true);
+    layer_tree_host()->root_layer()->SetMaxScrollOffset(
+        gfx::Vector2d(100, 100));
+    layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_);
+    PostSetNeedsCommitToMainThread();
+  }
+
+  virtual void WillCommit() OVERRIDE {
+    Layer* root = layer_tree_host()->root_layer();
+    switch (layer_tree_host()->source_frame_number()) {
+      case 0:
+        EXPECT_TRUE(root->needs_push_properties());
+        break;
+      case 1:
+        // Even if this layer doesn't need push properties, it should
+        // still pick up scrolls that happen on the active layer during
+        // commit.
+        EXPECT_FALSE(root->needs_push_properties());
+        break;
+    }
+  }
+
+  virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    // Scroll after the 2nd commit has started.
+    if (impl->active_tree()->source_frame_number() == 0) {
+      LayerImpl* active_root = impl->active_tree()->root_layer();
+      ASSERT_TRUE(active_root);
+      active_root->ScrollBy(impl_thread_scroll_);
+    }
+  }
+
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    // We force a second draw here of the first commit before activating
+    // the second commit.
+    LayerImpl* active_root = impl->active_tree()->root_layer();
+    LayerImpl* pending_root = impl->pending_tree()->root_layer();
+
+    ASSERT_TRUE(pending_root);
+    switch (impl->pending_tree()->source_frame_number()) {
+      case 0:
+        EXPECT_VECTOR_EQ(pending_root->scroll_offset(), initial_scroll_);
+        EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), gfx::Vector2d());
+        EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d());
+        EXPECT_FALSE(active_root);
+        break;
+      case 1:
+        // Even though the scroll happened during the commit, both layers
+        // should have the appropriate scroll delta.
+        EXPECT_VECTOR_EQ(pending_root->scroll_offset(), initial_scroll_);
+        EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), impl_thread_scroll_);
+        EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d());
+        ASSERT_TRUE(active_root);
+        EXPECT_VECTOR_EQ(active_root->scroll_offset(), initial_scroll_);
+        EXPECT_VECTOR_EQ(active_root->ScrollDelta(), impl_thread_scroll_);
+        EXPECT_VECTOR_EQ(active_root->sent_scroll_delta(), gfx::Vector2d());
+        break;
+      case 2:
+        // On the next commit, this delta should have been sent and applied.
+        EXPECT_VECTOR_EQ(pending_root->scroll_offset(),
+                         initial_scroll_ + impl_thread_scroll_);
+        EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), gfx::Vector2d());
+        EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d());
+        EndTest();
+        break;
+    }
+  }
+
+  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    ImplSidePaintingScrollTest::DrawLayersOnThread(impl);
+
+    LayerImpl* root = impl->active_tree()->root_layer();
+
+    switch (impl->active_tree()->source_frame_number()) {
+      case 0:
+        EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
+        EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d());
+        EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d());
+        PostSetNeedsCommitToMainThread();
+        break;
+      case 1:
+        EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
+        EXPECT_VECTOR_EQ(root->ScrollDelta(), impl_thread_scroll_);
+        EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d());
+        PostSetNeedsCommitToMainThread();
+        break;
+    }
+  }
+
+  virtual void AfterTest() OVERRIDE {}
+
+ private:
+  gfx::Vector2d initial_scroll_;
+  gfx::Vector2d impl_thread_scroll_;
+};
+
+MULTI_THREAD_TEST_F(ImplSidePaintingScrollTestImplOnlyScroll);
+
 class LayerTreeHostScrollTestScrollZeroMaxScrollOffset
     : public LayerTreeHostScrollTest {
  public:
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index be25e65..f9b294b 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -9,8 +9,8 @@
 #include "cc/animation/scrollbar_animation_controller.h"
 #include "cc/debug/traced_value.h"
 #include "cc/layers/heads_up_display_layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/layers/render_surface_impl.h"
-#include "cc/layers/scrollbar_layer_impl.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "ui/gfx/size_conversions.h"
@@ -226,11 +226,11 @@
   root_scroll_layer_->SetMaxScrollOffset(gfx::ToFlooredVector2d(max_scroll));
 }
 
-static void ApplySentScrollDeltasOn(LayerImpl* layer) {
-  layer->ApplySentScrollDeltas();
+static void ApplySentScrollDeltasFromAbortedCommitTo(LayerImpl* layer) {
+  layer->ApplySentScrollDeltasFromAbortedCommit();
 }
 
-void LayerTreeImpl::ApplySentScrollAndScaleDeltas() {
+void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() {
   DCHECK(IsActiveTree());
 
   page_scale_factor_ *= sent_page_scale_delta_;
@@ -241,7 +241,20 @@
     return;
 
   LayerTreeHostCommon::CallFunctionForSubtree(
-      root_layer(), base::Bind(&ApplySentScrollDeltasOn));
+      root_layer(), base::Bind(&ApplySentScrollDeltasFromAbortedCommitTo));
+}
+
+static void ApplyScrollDeltasSinceBeginFrameTo(LayerImpl* layer) {
+  layer->ApplyScrollDeltasSinceBeginFrame();
+}
+
+void LayerTreeImpl::ApplyScrollDeltasSinceBeginFrame() {
+  DCHECK(IsPendingTree());
+  if (!root_layer())
+    return;
+
+  LayerTreeHostCommon::CallFunctionForSubtree(
+      root_layer(), base::Bind(&ApplyScrollDeltasSinceBeginFrameTo));
 }
 
 void LayerTreeImpl::UpdateSolidColorScrollbars() {
@@ -258,14 +271,16 @@
   if (RootContainerLayer())
     vertical_adjust = layer_tree_host_impl_->VisibleViewportSize().height() -
                       RootContainerLayer()->bounds().height();
-  if (ScrollbarLayerImpl* horiz = root_scroll->horizontal_scrollbar_layer()) {
-    horiz->set_vertical_adjust(vertical_adjust);
-    horiz->set_visible_to_total_length_ratio(
+  if (PaintedScrollbarLayerImpl* horiz =
+          root_scroll->horizontal_scrollbar_layer()) {
+    horiz->SetVerticalAdjust(vertical_adjust);
+    horiz->SetVisibleToTotalLengthRatio(
         scrollable_viewport.width() / ScrollableSize().width());
   }
-  if (ScrollbarLayerImpl* vertical = root_scroll->vertical_scrollbar_layer()) {
-    vertical->set_vertical_adjust(vertical_adjust);
-    vertical->set_visible_to_total_length_ratio(
+  if (PaintedScrollbarLayerImpl* vertical =
+          root_scroll->vertical_scrollbar_layer()) {
+    vertical->SetVerticalAdjust(vertical_adjust);
+    vertical->SetVisibleToTotalLengthRatio(
         scrollable_viewport.height() / ScrollableSize().height());
   }
 }
@@ -408,6 +423,10 @@
   return layer_tree_host_impl_->GetRendererCapabilities();
 }
 
+ContextProvider* LayerTreeImpl::context_provider() const {
+  return output_surface()->context_provider();
+}
+
 OutputSurface* LayerTreeImpl::output_surface() const {
   return layer_tree_host_impl_->output_surface();
 }
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 7e66da8..4dfc511 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -28,6 +28,7 @@
 
 namespace cc {
 
+class ContextProvider;
 class DebugRectHistory;
 class FrameRateCounter;
 class HeadsUpDisplayLayerImpl;
@@ -58,6 +59,7 @@
   // ---------------------------------------------------------------------------
   const LayerTreeSettings& settings() const;
   const RendererCapabilities& GetRendererCapabilities() const;
+  ContextProvider* context_provider() const;
   OutputSurface* output_surface() const;
   ResourceProvider* resource_provider() const;
   TileManager* tile_manager() const;
@@ -114,7 +116,8 @@
 
   void FindRootScrollLayer();
   void UpdateMaxScrollOffset();
-  void ApplySentScrollAndScaleDeltas();
+  void ApplySentScrollAndScaleDeltasFromAbortedCommit();
+  void ApplyScrollDeltasSinceBeginFrame();
 
   SkColor background_color() const { return background_color_; }
   void set_background_color(SkColor color) { background_color_ = color; }
diff --git a/cc/trees/proxy.cc b/cc/trees/proxy.cc
index c8dacaf..9315f31 100644
--- a/cc/trees/proxy.cc
+++ b/cc/trees/proxy.cc
@@ -77,8 +77,8 @@
   DCHECK(IsMainThread());
 }
 
-std::string Proxy::SchedulerStateAsStringForTesting() {
-  return "";
+scoped_ptr<base::Value> Proxy::SchedulerStateAsValueForTesting() {
+  return make_scoped_ptr(base::Value::CreateNullValue());
 }
 
 }  // namespace cc
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index c5f9d55..9845b0f 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -98,7 +98,7 @@
 
   // Testing hooks
   virtual bool CommitPendingForTesting() = 0;
-  virtual std::string SchedulerStateAsStringForTesting();
+  virtual scoped_ptr<base::Value> SchedulerStateAsValueForTesting();
 
  protected:
   explicit Proxy(
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 3a26a07..65d7980 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -221,6 +221,7 @@
 
     base::TimeDelta duration = stats_instrumentation->EndRecording(start_time);
     stats_instrumentation->AddCommit(duration);
+    stats_instrumentation->AccumulateAndClearMainThreadStats();
   }
   layer_tree_host_->CommitComplete();
   next_frame_is_newly_committed_frame_ = true;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index a0bd4bf..955ce25 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -52,7 +52,7 @@
 
 struct ThreadProxy::SchedulerStateRequest {
   CompletionEvent completion;
-  std::string state;
+  scoped_ptr<base::Value> state;
 };
 
 scoped_ptr<Proxy> ThreadProxy::Create(
@@ -695,6 +695,7 @@
     scoped_ptr<BeginFrameAndCommitState> begin_frame_state) {
   TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnMainThread");
   DCHECK(IsMainThread());
+
   if (!layer_tree_host_)
     return;
 
@@ -816,7 +817,7 @@
   // point of view, but asynchronously performed on the impl thread,
   // coordinated by the Scheduler.
   {
-    TRACE_EVENT0("cc", "ThreadProxy::BeginFrameOnMainThread::commit");
+    TRACE_EVENT_BEGIN0("cc", "ThreadProxy::BeginFrameOnMainThread::commit");
 
     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
 
@@ -836,6 +837,10 @@
 
     base::TimeDelta duration = stats_instrumentation->EndRecording(start_time);
     stats_instrumentation->AddCommit(duration);
+    TRACE_EVENT_END1("cc", "ThreadProxy::BeginFrameOnMainThread::commit",
+                     "data", stats_instrumentation->
+                     GetMainThreadRenderingStats().AsTraceableData());
+    stats_instrumentation->AccumulateAndClearMainThreadStats();
   }
 
   layer_tree_host_->CommitComplete();
@@ -902,7 +907,8 @@
   // by the main thread, so the active tree needs to be updated as if these sent
   // values were applied and committed.
   if (did_handle) {
-    layer_tree_host_impl_->active_tree()->ApplySentScrollAndScaleDeltas();
+    layer_tree_host_impl_->active_tree()
+        ->ApplySentScrollAndScaleDeltasFromAbortedCommit();
     layer_tree_host_impl_->active_tree()->ResetContentsTexturesPurged();
     SetInputThrottledUntilCommitOnImplThread(false);
   }
@@ -968,6 +974,7 @@
 
 void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
   DCHECK(IsImplThread());
+  TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionBeginOutputSurfaceCreation");
   Proxy::MainThreadTaskRunner()->PostTask(
       FROM_HERE,
       base::Bind(&ThreadProxy::CreateAndInitializeOutputSurface,
@@ -1398,27 +1405,27 @@
   request->completion.Signal();
 }
 
-std::string ThreadProxy::SchedulerStateAsStringForTesting() {
+scoped_ptr<base::Value> ThreadProxy::SchedulerStateAsValueForTesting() {
   if (IsImplThread())
-    return scheduler_on_impl_thread_->StateAsStringForTesting();
+    return scheduler_on_impl_thread_->StateAsValueForTesting().Pass();
 
   SchedulerStateRequest scheduler_state_request;
   {
     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
     Proxy::ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&ThreadProxy::SchedulerStateAsStringOnImplThreadForTesting,
+        base::Bind(&ThreadProxy::SchedulerStateAsValueOnImplThreadForTesting,
                    impl_thread_weak_ptr_,
                    &scheduler_state_request));
     scheduler_state_request.completion.Wait();
   }
-  return scheduler_state_request.state;
+  return scheduler_state_request.state.Pass();
 }
 
-void ThreadProxy::SchedulerStateAsStringOnImplThreadForTesting(
+void ThreadProxy::SchedulerStateAsValueOnImplThreadForTesting(
     SchedulerStateRequest* request) {
   DCHECK(IsImplThread());
-  request->state = scheduler_on_impl_thread_->StateAsStringForTesting();
+  request->state = scheduler_on_impl_thread_->StateAsValueForTesting();
   request->completion.Signal();
 }
 
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index 1f5f29e..7a8a146 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -63,7 +63,7 @@
   virtual void ForceSerializeOnSwapBuffers() OVERRIDE;
   virtual scoped_ptr<base::Value> AsValue() const OVERRIDE;
   virtual bool CommitPendingForTesting() OVERRIDE;
-  virtual std::string SchedulerStateAsStringForTesting() OVERRIDE;
+  virtual scoped_ptr<base::Value> SchedulerStateAsValueForTesting() OVERRIDE;
 
   // LayerTreeHostImplClient implementation
   virtual void DidTryInitializeRendererOnImplThread(
@@ -173,7 +173,7 @@
   void ForceSerializeOnSwapBuffersOnImplThread(CompletionEvent* completion);
   void CheckOutputSurfaceStatusOnImplThread();
   void CommitPendingOnImplThreadForTesting(CommitPendingRequest* request);
-  void SchedulerStateAsStringOnImplThreadForTesting(
+  void SchedulerStateAsValueOnImplThreadForTesting(
       SchedulerStateRequest* request);
   void AsValueOnImplThread(CompletionEvent* completion,
                            base::DictionaryValue* state) const;
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc
index f307257..aed4de0 100644
--- a/cc/trees/tree_synchronizer.cc
+++ b/cc/trees/tree_synchronizer.cc
@@ -11,8 +11,8 @@
 #include "cc/input/scrollbar.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
-#include "cc/layers/scrollbar_layer.h"
-#include "cc/layers/scrollbar_layer_impl.h"
+#include "cc/layers/painted_scrollbar_layer.h"
+#include "cc/layers/painted_scrollbar_layer_impl.h"
 
 namespace cc {
 
@@ -155,9 +155,10 @@
 
   RawPtrLayerImplMap::const_iterator iter =
       new_layers->find(scrollbar_layer->id());
-  ScrollbarLayerImpl* scrollbar_layer_impl =
-      iter != new_layers->end() ? static_cast<ScrollbarLayerImpl*>(iter->second)
-                               : NULL;
+  PaintedScrollbarLayerImpl* scrollbar_layer_impl =
+      iter != new_layers->end()
+          ? static_cast<PaintedScrollbarLayerImpl*>(iter->second)
+          : NULL;
   iter = new_layers->find(scrollbar_layer->scroll_layer_id());
   LayerImpl* scroll_layer_impl =
       iter != new_layers->end() ? iter->second : NULL;
@@ -173,14 +174,15 @@
 
 void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers,
                                            Layer* layer) {
-  UpdateScrollbarLayerPointersRecursiveInternal<Layer, ScrollbarLayer>(
+  UpdateScrollbarLayerPointersRecursiveInternal<Layer, PaintedScrollbarLayer>(
       new_layers, layer);
 }
 
 void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers,
                                            LayerImpl* layer) {
-  UpdateScrollbarLayerPointersRecursiveInternal<LayerImpl, ScrollbarLayerImpl>(
-      new_layers, layer);
+  UpdateScrollbarLayerPointersRecursiveInternal<
+      LayerImpl,
+      PaintedScrollbarLayerImpl>(new_layers, layer);
 }
 
 // static
diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc
index f1b6d32..4e0c89f 100644
--- a/cc/trees/tree_synchronizer_unittest.cc
+++ b/cc/trees/tree_synchronizer_unittest.cc
@@ -5,6 +5,7 @@
 #include "cc/trees/tree_synchronizer.h"
 
 #include <algorithm>
+#include <set>
 #include <vector>
 
 #include "cc/animation/layer_animation_controller.h"
@@ -124,6 +125,56 @@
 
   ASSERT_EQ(layer_children.size(), layer_impl_children.size());
 
+  const std::set<Layer*>* layer_scroll_children = layer->scroll_children();
+  const std::set<LayerImpl*>* layer_impl_scroll_children =
+      layer_impl->scroll_children();
+
+  ASSERT_EQ(!!layer_scroll_children, !!layer_impl_scroll_children);
+
+  if (layer_scroll_children) {
+    ASSERT_EQ(
+        layer_scroll_children->size(),
+        layer_impl_scroll_children->size());
+  }
+
+  const Layer* layer_scroll_parent = layer->scroll_parent();
+  const LayerImpl* layer_impl_scroll_parent = layer_impl->scroll_parent();
+
+  ASSERT_EQ(!!layer_scroll_parent, !!layer_impl_scroll_parent);
+
+  if (layer_scroll_parent) {
+    ASSERT_EQ(layer_scroll_parent->id(), layer_impl_scroll_parent->id());
+    ASSERT_TRUE(layer_scroll_parent->scroll_children()->find(layer) !=
+        layer_scroll_parent->scroll_children()->end());
+    ASSERT_TRUE(layer_impl_scroll_parent->scroll_children()->find(layer_impl) !=
+        layer_impl_scroll_parent->scroll_children()->end());
+  }
+
+  const std::set<Layer*>* layer_clip_children = layer->clip_children();
+  const std::set<LayerImpl*>* layer_impl_clip_children =
+      layer_impl->clip_children();
+
+  ASSERT_EQ(!!layer_clip_children, !!layer_impl_clip_children);
+
+  if (layer_clip_children)
+    ASSERT_EQ(layer_clip_children->size(), layer_impl_clip_children->size());
+
+  const Layer* layer_clip_parent = layer->clip_parent();
+  const LayerImpl* layer_impl_clip_parent = layer_impl->clip_parent();
+
+  ASSERT_EQ(!!layer_clip_parent, !!layer_impl_clip_parent);
+
+  if (layer_clip_parent) {
+    const std::set<LayerImpl*>* clip_children_impl =
+        layer_impl_clip_parent->clip_children();
+    const std::set<Layer*>* clip_children =
+        layer_clip_parent->clip_children();
+    ASSERT_EQ(layer_clip_parent->id(), layer_impl_clip_parent->id());
+    ASSERT_TRUE(clip_children->find(layer) != clip_children->end());
+    ASSERT_TRUE(clip_children_impl->find(layer_impl) !=
+                clip_children_impl->end());
+  }
+
   for (size_t i = 0; i < layer_children.size(); ++i) {
     ExpectTreesAreIdentical(
         layer_children[i].get(), layer_impl_children[i], tree_impl);
@@ -531,5 +582,167 @@
       layer_tree_root->layer_animation_controller())->SynchronizedAnimations());
 }
 
+TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) {
+  LayerTreeSettings settings;
+  FakeProxy proxy;
+  DebugScopedSetImplThread impl(&proxy);
+  FakeRenderingStatsInstrumentation stats_instrumentation;
+  scoped_ptr<LayerTreeHostImpl> host_impl =
+      LayerTreeHostImpl::Create(settings,
+                                NULL,
+                                &proxy,
+                                &stats_instrumentation);
+
+  scoped_refptr<Layer> layer_tree_root = Layer::Create();
+  scoped_refptr<Layer> scroll_parent = Layer::Create();
+  layer_tree_root->AddChild(scroll_parent);
+  layer_tree_root->AddChild(Layer::Create());
+  layer_tree_root->AddChild(Layer::Create());
+
+  host_->SetRootLayer(layer_tree_root);
+
+  // First child is the second and third child's scroll parent.
+  layer_tree_root->children()[1]->SetScrollParent(scroll_parent);
+  layer_tree_root->children()[2]->SetScrollParent(scroll_parent);
+
+  scoped_ptr<LayerImpl> layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         scoped_ptr<LayerImpl>(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // Remove the first scroll child.
+  layer_tree_root->children()[1]->RemoveFromParent();
+  layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         layer_impl_tree_root.Pass(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // Add an additional scroll layer.
+  scoped_refptr<Layer> additional_scroll_child = Layer::Create();
+  layer_tree_root->AddChild(additional_scroll_child);
+  additional_scroll_child->SetScrollParent(scroll_parent);
+  layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         layer_impl_tree_root.Pass(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // Remove the scroll parent.
+  scroll_parent->RemoveFromParent();
+  scroll_parent = NULL;
+  layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         layer_impl_tree_root.Pass(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // The scroll children should have been unhooked.
+  EXPECT_EQ(2u, layer_tree_root->children().size());
+  EXPECT_FALSE(layer_tree_root->children()[0]->scroll_parent());
+  EXPECT_FALSE(layer_tree_root->children()[1]->scroll_parent());
+}
+
+TEST_F(TreeSynchronizerTest, SynchronizeClipParent) {
+  LayerTreeSettings settings;
+  FakeProxy proxy;
+  DebugScopedSetImplThread impl(&proxy);
+  FakeRenderingStatsInstrumentation stats_instrumentation;
+  scoped_ptr<LayerTreeHostImpl> host_impl =
+      LayerTreeHostImpl::Create(settings,
+                                NULL,
+                                &proxy,
+                                &stats_instrumentation);
+
+  scoped_refptr<Layer> layer_tree_root = Layer::Create();
+  scoped_refptr<Layer> clip_parent = Layer::Create();
+  scoped_refptr<Layer> intervening = Layer::Create();
+  scoped_refptr<Layer> clip_child1 = Layer::Create();
+  scoped_refptr<Layer> clip_child2 = Layer::Create();
+  layer_tree_root->AddChild(clip_parent);
+  clip_parent->AddChild(intervening);
+  intervening->AddChild(clip_child1);
+  intervening->AddChild(clip_child2);
+
+  host_->SetRootLayer(layer_tree_root);
+
+  // First child is the second and third child's scroll parent.
+  clip_child1->SetClipParent(clip_parent);
+  clip_child2->SetClipParent(clip_parent);
+
+  scoped_ptr<LayerImpl> layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         scoped_ptr<LayerImpl>(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // Remove the first clip child.
+  clip_child1->RemoveFromParent();
+  clip_child1 = NULL;
+
+  layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         layer_impl_tree_root.Pass(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // Add an additional clip child.
+  scoped_refptr<Layer> additional_clip_child = Layer::Create();
+  intervening->AddChild(additional_clip_child);
+  additional_clip_child->SetClipParent(clip_parent);
+  layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         layer_impl_tree_root.Pass(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // Remove the nearest clipping ancestor.
+  clip_parent->RemoveFromParent();
+  clip_parent = NULL;
+  layer_impl_tree_root =
+      TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
+                                         layer_impl_tree_root.Pass(),
+                                         host_impl->active_tree());
+  TreeSynchronizer::PushProperties(layer_tree_root.get(),
+                                   layer_impl_tree_root.get());
+  ExpectTreesAreIdentical(layer_tree_root.get(),
+                          layer_impl_tree_root.get(),
+                          host_impl->active_tree());
+
+  // The clip children should have been unhooked.
+  EXPECT_EQ(2u, intervening->children().size());
+  EXPECT_FALSE(clip_child2->clip_parent());
+  EXPECT_FALSE(additional_clip_child->clip_parent());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/chrome/DEPS b/chrome/DEPS
index 520629f..07ac7d3 100644
--- a/chrome/DEPS
+++ b/chrome/DEPS
@@ -28,6 +28,7 @@
   "-chrome",
   "+chrome/common",
   "+chrome/test",
+  "+components/json_schema",
   "+components/sessions",
   "+components/visitedlink/common",
   "+content/public/common",
diff --git a/chrome/VERSION b/chrome/VERSION
index c0cd403..e1956ba 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
-MAJOR=30
+MAJOR=31
 MINOR=0
-BUILD=1599
+BUILD=1610
 PATCH=0
diff --git a/chrome/android/host_driven_tests/DummyTest.py b/chrome/android/host_driven_tests/DummyTest.py
index c73599d..0ef28d8 100644
--- a/chrome/android/host_driven_tests/DummyTest.py
+++ b/chrome/android/host_driven_tests/DummyTest.py
@@ -13,5 +13,4 @@
 
   @tests_annotations.Smoke
   def testPass(self):
-    return self._RunJavaTests(
-        'org.chromium.chrome.browser.test', ['DummyTest.testPass'])
+    return self._RunJavaTestFilters(['DummyTest.testPass'])
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java
index 5ad155c..0adba92 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java
@@ -44,6 +44,27 @@
     /**
      * Creates an intent that will add a shortcut to the home screen.
      * @param context Context used to create the intent.
+     * @param shortcutIntent Intent to fire when the shortcut is activated.
+     * @param title Title of the bookmark.
+     * @param favicon Bookmark favicon.
+     * @param rValue Red component of the dominant favicon color.
+     * @param gValue Green component of the dominant favicon color.
+     * @param bValue Blue component of the dominant favicon color.
+     * @return Intent for the shortcut.
+     */
+    public static Intent createAddToHomeIntent(Context context, Intent shortcutIntent, String title,
+            Bitmap favicon, int rValue, int gValue, int bValue) {
+        Intent i = new Intent(INSTALL_SHORTCUT);
+        i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+        i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
+        i.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(context, favicon, rValue,
+                gValue, bValue));
+        return i;
+    }
+
+    /**
+     * Creates an intent that will add a shortcut to the home screen.
+     * @param context Context used to create the intent.
      * @param url Url of the bookmark.
      * @param title Title of the bookmark.
      * @param favicon Bookmark favicon.
@@ -54,13 +75,9 @@
      */
     public static Intent createAddToHomeIntent(Context context, String url, String title,
             Bitmap favicon, int rValue, int gValue, int bValue) {
-        Intent i = new Intent(INSTALL_SHORTCUT);
         Intent shortcutIntent = createShortcutIntent(context, url);
-        i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
-        i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
-        i.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(context, favicon, rValue,
-                gValue, bValue));
-        return i;
+        return createAddToHomeIntent(
+                context, shortcutIntent, title, favicon, rValue, gValue, bValue);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BookmarksBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/BookmarksBridge.java
new file mode 100644
index 0000000..db0c485
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BookmarksBridge.java
@@ -0,0 +1,227 @@
+// Copyright 2013 The Chromium 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;
+
+/**
+ * Handler to fetch the bookmarks, titles, urls and folder hierarchy.
+ */
+public class BookmarksBridge {
+
+    private final Profile mProfile;
+    private int mNativeBookmarksBridge;
+    private boolean mIsNativeBookmarkModelLoaded;
+    private List<DelayedBookmarkCallback> mDelayedBookmarkCallbacks =
+            new ArrayList<DelayedBookmarkCallback>();
+
+    /**
+     * Interface for callback object for fetching bookmarks and folder hierarchy.
+     */
+    public interface BookmarksCallback {
+
+        /**
+         * Callback method for fetching bookmarks for a folder and the folder hierarchy.
+         * @param folderId The folder id to which the bookmarks belong.
+         * @param bookmarksList List holding the fetched bookmarks and details.
+         */
+        @CalledByNative("BookmarksCallback")
+        public void onBookmarksAvailable(long folderId, List<BookmarkItem> bookmarksList);
+
+        /**
+         * Callback method for fetching the folder hierarchy.
+         * @param folderId The folder id to which the bookmarks belong.
+         * @param bookmarksList List holding the fetched folder details.
+         */
+        @CalledByNative("BookmarksCallback")
+        public void onBookmarksFolderHierarchyAvailable(long folderId,
+                List<BookmarkItem> bookmarksList);
+
+   }
+
+    /**
+     * Handler to fetch the bookmarks, titles, urls and folder hierarchy.
+     * @param profile Profile instance corresponding to the active profile.
+     */
+    public BookmarksBridge(Profile profile) {
+        mProfile = profile;
+        mNativeBookmarksBridge = nativeInit(profile);
+    }
+
+    /**
+     * Destroys this instance so no further calls can be executed.
+     */
+    public void destroy() {
+        if (mNativeBookmarksBridge != 0) {
+            nativeDestroy(mNativeBookmarksBridge);
+            mNativeBookmarksBridge = 0;
+            mIsNativeBookmarkModelLoaded = false;
+        }
+    }
+
+    /**
+     * Fetches the bookmarks of the current folder. Callback will be
+     * synchronous if the bookmark model is already loaded and async if it is loaded in the
+     * background.
+     * @param folderId The current folder id.
+     * @param callback Instance of a callback object.
+     */
+    public void getBookmarksForFolder(long folderId, BookmarksCallback callback) {
+        if (mIsNativeBookmarkModelLoaded) {
+            nativeGetBookmarksForFolder(mNativeBookmarksBridge, folderId, callback,
+                    new ArrayList<BookmarkItem>());
+        } else {
+            mDelayedBookmarkCallbacks.add(new DelayedBookmarkCallback(folderId, callback,
+                    DelayedBookmarkCallback.GET_BOOKMARKS_FOR_FOLDER, this));
+        }
+    }
+
+    /**
+     * Fetches the folder hierarchy of the given folder. Callback will be
+     * synchronous if the bookmark model is already loaded and async if it is loaded in the
+     * background.
+     * @param folderId The current folder id.
+     * @param callback Instance of a callback object.
+     */
+    public void getCurrentFolderHierarchy(long folderId, BookmarksCallback callback) {
+        if (mIsNativeBookmarkModelLoaded) {
+            nativeGetCurrentFolderHierarchy(mNativeBookmarksBridge, folderId, callback,
+                    new ArrayList<BookmarkItem>());
+        } else {
+            mDelayedBookmarkCallbacks.add(new DelayedBookmarkCallback(folderId, callback,
+                    DelayedBookmarkCallback.GET_CURRENT_FOLDER_HIERARCHY, this));
+        }
+    }
+
+    @CalledByNative
+    public void bookmarkModelLoaded() {
+        mIsNativeBookmarkModelLoaded = true;
+        if (!mDelayedBookmarkCallbacks.isEmpty()) {
+            for (int i = 0; i < mDelayedBookmarkCallbacks.size(); i++) {
+                mDelayedBookmarkCallbacks.get(i).callCallbackMethod();
+            }
+            mDelayedBookmarkCallbacks.clear();
+        }
+    }
+
+    @CalledByNative
+    public void bookmarkModelDeleted() {
+        destroy();
+    }
+
+    @CalledByNative
+    private static void create(List<BookmarkItem> bookmarksList, long id, String title, String url,
+            boolean isFolder, long parentId) {
+        bookmarksList.add(new BookmarkItem(id, title, url, isFolder, parentId));
+    }
+
+    private native void nativeGetBookmarksForFolder(int nativeBookmarksBridge,
+            long folderId, BookmarksCallback callback,
+            List<BookmarkItem> bookmarksList);
+    private native void nativeGetCurrentFolderHierarchy(int nativeBookmarksBridge,
+            long folderId, BookmarksCallback callback,
+            List<BookmarkItem> bookmarksList);
+    private native int nativeInit(Profile profile);
+    private native void nativeDestroy(int nativeBookmarksBridge);
+
+    /**
+     * Simple object representing the bookmark item.
+     */
+    public static class BookmarkItem {
+
+        private final String mTitle;
+        private final String mUrl;
+        private final long mId;
+        private final boolean mIsFolder;
+        private final long mParentId;
+
+        private BookmarkItem(long id, String title, String url, boolean isFolder, long parentId) {
+            mId = id;
+            mTitle = title;
+            mUrl = url;
+            mIsFolder = isFolder;
+            mParentId = parentId;
+        }
+
+        /**
+         * @return Title of the bookmark item.
+         */
+        public String getTitle() {
+            return mTitle;
+        }
+
+        /**
+         * @return Url of the bookmark item.
+         */
+        public String getUrl() {
+            return mUrl;
+        }
+
+        /**
+         * @return Id of the bookmark item.
+         */
+        public long getId() {
+            return mId;
+        }
+
+        /**
+         * @return Whether item is a folder or a bookmark.
+         */
+        public boolean isFolder() {
+            return mIsFolder;
+        }
+
+        /**
+         * @return Parent id of the bookmark item.
+         */
+        public long getParentId() {
+            return mParentId;
+        }
+    }
+
+    /**
+     * Details about callbacks that need to be called once the bookmark model has loaded.
+     */
+    private static class DelayedBookmarkCallback {
+
+        private static final int GET_BOOKMARKS_FOR_FOLDER = 0;
+        private static final int GET_CURRENT_FOLDER_HIERARCHY = 1;
+
+        private final BookmarksCallback mCallback;
+        private final long mFolderId;
+        private final int mCallbackMethod;
+        private final BookmarksBridge mHandler;
+
+        private DelayedBookmarkCallback(long folderId, BookmarksCallback callback, int method,
+                BookmarksBridge handler) {
+            mFolderId = folderId;
+            mCallback = callback;
+            mCallbackMethod = method;
+            mHandler = handler;
+        }
+
+        /**
+         * Invoke the callback method.
+         */
+        private void callCallbackMethod() {
+            switch(mCallbackMethod) {
+                case GET_BOOKMARKS_FOR_FOLDER:
+                    mHandler.getBookmarksForFolder(mFolderId, mCallback);
+                    break;
+                case GET_CURRENT_FOLDER_HIERARCHY:
+                    mHandler.getCurrentFolderHierarchy(mFolderId, mCallback);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+}
+
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
new file mode 100644
index 0000000..3544546
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -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.
+
+package org.chromium.chrome.browser;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.chrome.browser.BookmarkUtils;
+
+import java.util.UUID;
+
+/**
+ * This is a helper class to create shortcuts on the Android home screen.
+ */
+public class ShortcutHelper {
+    public static final String EXTRA_ID = "webapp_id";
+    public static final String EXTRA_URL = "webapp_url";
+
+    private static String sWebappActivityPackageName;
+    private static String sWebappActivityClassName;
+
+    /**
+     * Sets the Activity that gets launched when a webapp shortcut is clicked.
+     * @param packageName Package of the Activity to launch.
+     * @param className Class name of the Activity to launch.
+     */
+    public static void setWebappActivityInfo(String packageName, String className) {
+        sWebappActivityPackageName = packageName;
+        sWebappActivityClassName = className;
+    }
+
+    /**
+     * Adds a shortcut for the current Tab.
+     * @param tab Tab to create a shortcut for.
+     */
+    public static void addShortcut(TabBase tab) {
+        if (sWebappActivityPackageName == null || sWebappActivityClassName == null) {
+            Log.e("ShortcutHelper", "ShortcutHelper is uninitialized.  Aborting.");
+            return;
+        }
+        nativeAddShortcut(tab.getNativePtr());
+    }
+
+    /**
+     * Called when we have to fire an Intent to add a shortcut to the homescreen.
+     * If the webpage indicated that it was capable of functioning as a webapp, it is added as a
+     * shortcut to a webapp Activity rather than as a general bookmark.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static void addShortcut(Context context, String url, String title, Bitmap favicon,
+            int red, int green, int blue, boolean isWebappCapable) {
+        Intent addIntent;
+        if (isWebappCapable && !sWebappActivityPackageName.isEmpty()
+                && !sWebappActivityClassName.isEmpty()) {
+            // Add the shortcut as a launcher icon for a Webapp.
+            String id = UUID.randomUUID().toString();
+
+            Intent shortcutIntent = new Intent();
+            shortcutIntent.setClassName(sWebappActivityPackageName, sWebappActivityClassName);
+            shortcutIntent.putExtra(EXTRA_URL, url);
+            shortcutIntent.putExtra(EXTRA_ID, id);
+
+            addIntent = BookmarkUtils.createAddToHomeIntent(context, shortcutIntent, title, favicon,
+                            red, green, blue);
+        } else {
+            // Add the shortcut as a regular bookmark.
+            addIntent = BookmarkUtils.createAddToHomeIntent(context, url, title, favicon, red,
+                            green, blue);
+        }
+        context.sendBroadcast(addIntent);
+    }
+
+    private static native void nativeAddShortcut(int tabAndroidPtr);
+}
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 278a9cb..7f73cac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
@@ -41,6 +41,10 @@
         mNativeTabAndroid = nativePtr;
     }
 
+    int getNativePtr() {
+        return mNativeTabAndroid;
+    }
+
     protected WindowAndroid getWindowAndroid() {
         return mWindowAndroid;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java
new file mode 100644
index 0000000..268813b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java
@@ -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.
+
+package org.chromium.chrome.browser.identity;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.UUID;
+
+import javax.annotation.Nullable;
+
+/**
+ * Generates unique IDs that are {@link UUID} strings.
+ */
+public class UuidBasedUniqueIdentificationGenerator implements UniqueIdentificationGenerator {
+    private final Context mContext;
+    private final String mPreferenceKey;
+
+    public UuidBasedUniqueIdentificationGenerator(Context context, String preferenceKey) {
+        mContext = context;
+        mPreferenceKey = preferenceKey;
+    }
+
+    @Override
+    public String getUniqueId(@Nullable String salt) {
+        SharedPreferences preferences = PreferenceManager
+                .getDefaultSharedPreferences(mContext);
+        String storedUniqueId = preferences.getString(mPreferenceKey, null);
+        if (storedUniqueId != null) {
+            return storedUniqueId;
+        }
+
+        // Generate a new unique ID.
+        String uniqueId = getUUID();
+
+        // Store the field so we ensure we always return the same unique ID.
+        SharedPreferences.Editor editor = preferences.edit();
+        editor.putString(mPreferenceKey, uniqueId);
+        editor.apply();
+        return uniqueId;
+
+    }
+
+    @VisibleForTesting
+    String getUUID() {
+        return UUID.randomUUID().toString();
+    }
+}
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 36fb859..0876130 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
@@ -52,6 +52,8 @@
     private ProgressDialog mSignOutProgressDialog;
     private Runnable mSignOutCallback;
 
+    private AlertDialog mPolicyConfirmationDialog;
+
     /**
      * The Observer of startSignIn() will be notified when sign-in completes.
      */
@@ -142,6 +144,12 @@
             return;
         }
 
+        if (mSignInActivity.isDestroyed()) {
+            // The activity is no longer running, cancel sign in.
+            cancelSignIn();
+            return;
+        }
+
         Log.d(TAG, "Account has policy management");
         AlertDialog.Builder builder = new AlertDialog.Builder(mSignInActivity);
         builder.setTitle(R.string.policy_dialog_title);
@@ -155,6 +163,7 @@
                         Log.d(TAG, "Accepted policy management, proceeding with sign-in");
                         // This will call back to onPolicyFetchedBeforeSignIn.
                         nativeFetchPolicyBeforeSignIn(mNativeSigninManagerAndroid);
+                        mPolicyConfirmationDialog = null;
                     }
                 });
         builder.setNegativeButton(
@@ -164,9 +173,22 @@
                     public void onClick(DialogInterface dialog, int id) {
                         Log.d(TAG, "Cancelled sign-in");
                         cancelSignIn();
+                        mPolicyConfirmationDialog = null;
                     }
                 });
-        builder.create().show();
+        builder.setOnDismissListener(
+                new DialogInterface.OnDismissListener() {
+                    @Override
+                    public void onDismiss(DialogInterface dialog) {
+                        if (mPolicyConfirmationDialog != null) {
+                            Log.d(TAG, "Policy dialog dismissed, cancelling sign-in.");
+                            cancelSignIn();
+                            mPolicyConfirmationDialog = null;
+                        }
+                    }
+                });
+        mPolicyConfirmationDialog = builder.create();
+        mPolicyConfirmationDialog.show();
     }
 
     @CalledByNative
@@ -244,6 +266,10 @@
         return nativeGetManagementDomain(mNativeSigninManagerAndroid);
     }
 
+    public void logInSignedInUser() {
+        nativeLogInSignedInUser(mNativeSigninManagerAndroid);
+    }
+
     private void cancelSignIn() {
         if (mSignInObserver != null)
             mSignInObserver.onSigninCancelled();
@@ -292,4 +318,5 @@
     private native void nativeSignOut(int nativeSigninManagerAndroid);
     private native String nativeGetManagementDomain(int nativeSigninManagerAndroid);
     private native void nativeWipeProfileData(int nativeSigninManagerAndroid);
+    private native void nativeLogInSignedInUser(int nativeSigninManagerAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java
new file mode 100644
index 0000000..01c6540
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java
@@ -0,0 +1,169 @@
+// Copyright 2013 The Chromium 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.sync;
+
+import android.accounts.Account;
+import android.app.Application;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.content.browser.AndroidBrowserProcess;
+import org.chromium.content.browser.BrowserStartupController;
+import org.chromium.content.common.ProcessInitException;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * A sync adapter for Chromium.
+ */
+public abstract class ChromiumSyncAdapter extends AbstractThreadedSyncAdapter {
+    private static final String TAG = "ChromiumSyncAdapter";
+
+    // TODO(nyquist) Make these fields package protected once downstream sync adapter tests are
+    // removed.
+    @VisibleForTesting
+    public static final String INVALIDATION_OBJECT_ID_KEY = "objectId";
+    @VisibleForTesting
+    public static final String INVALIDATION_VERSION_KEY = "version";
+    @VisibleForTesting
+    public static final String INVALIDATION_PAYLOAD_KEY = "payload";
+
+    private final Application mApplication;
+    private final boolean mAsyncStartup;
+
+    public ChromiumSyncAdapter(Context context, Application application) {
+        super(context, false);
+        mApplication = application;
+        mAsyncStartup = useAsyncStartup();
+    }
+
+    protected abstract boolean useAsyncStartup();
+
+    protected abstract void initCommandLine();
+
+    @Override
+    public void onPerformSync(Account account, Bundle extras, String authority,
+                              ContentProviderClient provider, SyncResult syncResult) {
+        if (!DelayedSyncController.getInstance().shouldPerformSync(getContext(), extras, account)) {
+            return;
+        }
+
+        // Browser startup is asynchronous, so we will need to wait for startup to finish.
+        Semaphore semaphore = new Semaphore(0);
+
+        // Configure the callback with all the data it needs.
+        BrowserStartupController.StartupCallback callback =
+                getStartupCallback(mApplication, account, extras, syncResult, semaphore);
+        startBrowserProcess(callback, syncResult, semaphore);
+
+        try {
+            // Wait for startup to complete.
+            semaphore.acquire();
+        } catch (InterruptedException e) {
+            Log.w(TAG, "Got InterruptedException when trying to request a sync.", e);
+            // Using numIoExceptions so Android will treat this as a soft error.
+            syncResult.stats.numIoExceptions++;
+        }
+    }
+
+    private void startBrowserProcess(
+            final BrowserStartupController.StartupCallback callback,
+            final SyncResult syncResult, Semaphore semaphore) {
+        try {
+            ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                @Override
+                public void run() {
+                    initCommandLine();
+                    if (mAsyncStartup) {
+                        BrowserStartupController.get(mApplication)
+                                .startBrowserProcessesAsync(callback);
+                    } else {
+                        startBrowserProcessesSync(callback);
+                    }
+                }
+            });
+        } catch (RuntimeException e) {
+            // It is still unknown why we ever experience this. See http://crbug.com/180044.
+            Log.w(TAG, "Got exception when trying to request a sync. Informing Android system.", e);
+            // Using numIoExceptions so Android will treat this as a soft error.
+            syncResult.stats.numIoExceptions++;
+            semaphore.release();
+        }
+    }
+
+    private void startBrowserProcessesSync(
+            final BrowserStartupController.StartupCallback callback) {
+        try {
+            AndroidBrowserProcess.init(
+                    mApplication, AndroidBrowserProcess.MAX_RENDERERS_LIMIT);
+            new Handler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onSuccess(false);
+                }
+            });
+        } catch (ProcessInitException e) {
+            Log.e(TAG, "Unable to start browser process.", e);
+            new Handler().post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onFailure();
+                }
+            });
+        }
+    }
+
+    private BrowserStartupController.StartupCallback getStartupCallback(
+            final Context context, final Account acct, Bundle extras,
+            final SyncResult syncResult, final Semaphore semaphore) {
+        final boolean syncAllTypes = extras.getString(INVALIDATION_OBJECT_ID_KEY) == null;
+        final String objectId = syncAllTypes ? "" : extras.getString(INVALIDATION_OBJECT_ID_KEY);
+        final long version = syncAllTypes ? 0 : extras.getLong(INVALIDATION_VERSION_KEY);
+        final String payload = syncAllTypes ? "" : extras.getString(INVALIDATION_PAYLOAD_KEY);
+
+        return new BrowserStartupController.StartupCallback() {
+            @Override
+            public void onSuccess(boolean alreadyStarted) {
+                // Startup succeeded, so we can tickle the sync engine.
+                if (syncAllTypes) {
+                    Log.v(TAG, "Received sync tickle for all types.");
+                    requestSyncForAllTypes();
+                } else {
+                    Log.v(TAG, "Received sync tickle for " + objectId + ".");
+                    requestSync(objectId, version, payload);
+                }
+                semaphore.release();
+            }
+
+            @Override
+            public void onFailure() {
+                // The startup failed, so we reset the delayed sync state.
+                DelayedSyncController.getInstance().setDelayedSync(context, acct.name);
+                // Using numIoExceptions so Android will treat this as a soft error.
+                syncResult.stats.numIoExceptions++;
+                semaphore.release();
+            }
+        };
+    }
+
+    @VisibleForTesting
+    public void requestSync(String objectId, long version, String payload) {
+        ProfileSyncService.get(mApplication)
+                .requestSyncFromNativeChrome(objectId, version, payload);
+    }
+
+    @VisibleForTesting
+    public void requestSyncForAllTypes() {
+        ProfileSyncService.get(mApplication).requestSyncFromNativeChromeForAllTypes();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterService.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterService.java
new file mode 100644
index 0000000..2e641e4
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterService.java
@@ -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.
+
+package org.chromium.chrome.browser.sync;
+
+import android.app.Application;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+public abstract class ChromiumSyncAdapterService extends Service {
+    private static ChromiumSyncAdapter sSyncAdapter = null;
+    private static final Object LOCK = new Object();
+
+    /**
+     * Get the sync adapter reference, creating an instance if necessary.
+     */
+    private ChromiumSyncAdapter getOrCreateSyncAdapter(Context applicationContext) {
+        synchronized (LOCK) {
+            if (sSyncAdapter == null) {
+                sSyncAdapter = createChromiumSyncAdapter(applicationContext, getApplication());
+            }
+        }
+        return sSyncAdapter;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return getOrCreateSyncAdapter(getApplicationContext()).getSyncAdapterBinder();
+    }
+
+    protected abstract ChromiumSyncAdapter createChromiumSyncAdapter(Context applicationContext,
+                                                                     Application application);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/DelayedSyncController.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/DelayedSyncController.java
new file mode 100644
index 0000000..baa7120
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/DelayedSyncController.java
@@ -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.
+
+package org.chromium.chrome.browser.sync;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.chromium.base.ActivityStatus;
+import org.chromium.sync.notifier.SyncStatusHelper;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+/**
+ * A class for controlling when a sync should be performed immediately, and when it should be
+ * delayed until Chrome comes to the foreground again.
+ */
+public class DelayedSyncController {
+    private static final String TAG = "DelayedSyncController";
+    private static final String DELAYED_ACCOUNT_NAME = "delayed_account";
+
+    private static class LazyHolder {
+        private static final DelayedSyncController INSTANCE = new DelayedSyncController();
+    }
+
+    public static DelayedSyncController getInstance() {
+        return LazyHolder.INSTANCE;
+    }
+
+    @VisibleForTesting
+    DelayedSyncController() {}
+
+    /**
+     * Resume any syncs that were delayed while Chromium was backgrounded.
+     */
+    public boolean resumeDelayedSyncs(final Context context) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        String accountName = prefs.getString(DELAYED_ACCOUNT_NAME, null);
+        if (accountName == null) {
+            Log.d(TAG, "No delayed sync.");
+            return false;
+        } else {
+            Log.d(TAG, "Handling delayed sync.");
+            Account account = AccountManagerHelper.createAccountFromName(accountName);
+            requestSyncOnBackgroundThread(context, account);
+            return true;
+        }
+    }
+
+    /**
+     * Calls ContentResolver.requestSync() in a separate thread as it performs some blocking
+     * IO operations.
+     */
+    @VisibleForTesting
+    void requestSyncOnBackgroundThread(final Context context, final Account account) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... unused) {
+                String contractAuthority =
+                        SyncStatusHelper.get(context).getContractAuthority();
+                ContentResolver.requestSync(account, contractAuthority, new Bundle());
+                return null;
+            }
+        }.execute();
+    }
+
+    /**
+     * Stores preferences to indicate that an invalidation has arrived, but dropped on the floor.
+     */
+    void setDelayedSync(Context ctx, String accountName) {
+        SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(ctx).edit();
+        editor.putString(DELAYED_ACCOUNT_NAME, accountName);
+        editor.apply();
+    }
+
+    /**
+     * If there is a delayed sync, it will be cleared.
+     */
+    @VisibleForTesting
+    void clearDelayedSyncs(Context context) {
+        setDelayedSync(context, null);
+    }
+
+    @VisibleForTesting
+    boolean shouldPerformSync(Context ctx, Bundle extras, Account account) {
+        boolean manualSync = isManualSync(extras);
+
+        if (manualSync || ActivityStatus.getState() == ActivityStatus.RESUMED) {
+            clearDelayedSyncs(ctx);
+            return true;
+        } else {
+            Log.d(TAG, "Delaying sync.");
+            setDelayedSync(ctx, account.name);
+            return false;
+        }
+    }
+
+    private static boolean isManualSync(Bundle extras) {
+        boolean manualSync = false;
+        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
+            manualSync = true;
+            Log.d(TAG, "Manual sync requested.");
+        }
+        return manualSync;
+    }
+}
diff --git a/chrome/android/javatests/DEPS b/chrome/android/javatests/DEPS
index 136005d..3ab779c 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/notifier",
   "+sync/android/java/src/org/chromium/sync/signin",
   # We should only depend on the util package of something that lives in
   # javatests.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ShortcutHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ShortcutHelperTest.java
new file mode 100644
index 0000000..cf0afd5
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ShortcutHelperTest.java
@@ -0,0 +1,120 @@
+// Copyright 2013 The Chromium 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.content.Intent;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.UrlUtils;
+import org.chromium.chrome.testshell.ChromiumTestShellActivity;
+import org.chromium.chrome.testshell.ChromiumTestShellApplication;
+import org.chromium.chrome.testshell.ChromiumTestShellApplicationObserver;
+import org.chromium.chrome.testshell.ChromiumTestShellTestBase;
+import org.chromium.chrome.testshell.TestShellTab;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+
+public class ShortcutHelperTest extends ChromiumTestShellTestBase {
+    private static final String WEBAPP_PACKAGE_NAME = "packageName";
+    private static final String WEBAPP_CLASS_NAME = "className";
+
+    private static final String WEBAPP_TITLE = "Webapp shortcut";
+    private static final String WEBAPP_HTML = UrlUtils.encodeHtmlDataUri(
+            "<html><head>"
+            + "<meta name=\"mobile-web-app-capable\" content=\"yes\" />"
+            + "<title>" + WEBAPP_TITLE + "</title>"
+            + "</head><body>Webapp capable</body></html>");
+
+    private static final String NORMAL_TITLE = "Plain shortcut";
+    private static final String NORMAL_HTML = UrlUtils.encodeHtmlDataUri(
+            "<html>"
+            + "<head><title>" + NORMAL_TITLE + "</title></head>"
+            + "<body>Not Webapp capable</body></html>");
+
+    private static class TestObserver implements ChromiumTestShellApplicationObserver {
+        Intent firedIntent;
+
+        @Override
+        public boolean onSendBroadcast(Intent intent) {
+            if (intent.hasExtra(Intent.EXTRA_SHORTCUT_NAME)) {
+                // Stop a shortcut from really being added.
+                firedIntent = intent;
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    private ChromiumTestShellActivity mActivity;
+    private TestObserver mTestObserver;
+
+    @Override
+    public void setUp() throws Exception {
+        ShortcutHelper.setWebappActivityInfo(WEBAPP_PACKAGE_NAME, WEBAPP_CLASS_NAME);
+        mActivity = launchChromiumTestShellWithBlankPage();
+
+        // Set up the observer.
+        mTestObserver = new TestObserver();
+        ChromiumTestShellApplication application =
+                (ChromiumTestShellApplication) mActivity.getApplication();
+        application.addObserver(mTestObserver);
+
+        super.setUp();
+    }
+
+    @MediumTest
+    @Feature("{Webapp}")
+    public void testAddWebappShortcut() throws InterruptedException {
+        addShortcutToURL(WEBAPP_HTML);
+
+        // Make sure the intent's parameters make sense.
+        Intent firedIntent = mTestObserver.firedIntent;
+        assertEquals(WEBAPP_TITLE, firedIntent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
+
+        Intent launchIntent = firedIntent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+        assertEquals(WEBAPP_HTML, launchIntent.getStringExtra(ShortcutHelper.EXTRA_URL));
+        assertEquals(WEBAPP_PACKAGE_NAME, launchIntent.getComponent().getPackageName());
+        assertEquals(WEBAPP_CLASS_NAME, launchIntent.getComponent().getClassName());
+    }
+
+    @MediumTest
+    @Feature("{Webapp}")
+    public void testAddBookmarkShortcut() throws InterruptedException {
+        addShortcutToURL(NORMAL_HTML);
+
+        // Make sure the intent's parameters make sense.
+        Intent firedIntent = mTestObserver.firedIntent;
+        assertEquals(NORMAL_TITLE, firedIntent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
+
+        Intent launchIntent = firedIntent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+        assertEquals(Intent.ACTION_VIEW, launchIntent.getAction());
+        assertEquals(NORMAL_HTML, launchIntent.getDataString());
+        assertNull(launchIntent.getComponent());
+    }
+
+    private void addShortcutToURL(String url) throws InterruptedException {
+        loadUrlWithSanitization(url);
+        assertTrue(waitForActiveShellToBeDoneLoading());
+
+        // Add the shortcut.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ShortcutHelper.addShortcut(mActivity.getActiveTab());
+            }
+        });
+
+        // Make sure that the shortcut was added.
+        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return mTestObserver.firedIntent != null;
+            }
+        }));
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGeneratorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGeneratorTest.java
new file mode 100644
index 0000000..224e8b9
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGeneratorTest.java
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium 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.identity;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.Assert;
+
+import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.Feature;
+
+public class UuidBasedUniqueIdentificationGeneratorTest extends InstrumentationTestCase {
+    private static final String FLAG_UUID = "uuid";
+
+    private AdvancedMockContext mContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = new AdvancedMockContext(getInstrumentation().getTargetContext());
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testGenerationAndRestorationOfUuid() {
+        String preferenceKey = "some_preference_key";
+        String expectedUniqueId = "myUuid";
+        TestGenerator generator = new TestGenerator(mContext, preferenceKey, expectedUniqueId);
+
+        // Get a unique ID and ensure it is as expected.
+        Assert.assertEquals(expectedUniqueId, generator.getUniqueId(null));
+
+        // Asking for a unique ID again, should not try to regenerate it.
+        mContext.clearFlag(FLAG_UUID);
+        Assert.assertEquals(expectedUniqueId, generator.getUniqueId(null));
+        assertFalse(mContext.isFlagSet(FLAG_UUID));
+
+        // After a restart, the TestGenerator should read the UUID from a preference, instead of
+        // asking for it.
+        mContext.clearFlag(FLAG_UUID);
+        generator = new TestGenerator(mContext, preferenceKey, null);
+        Assert.assertEquals(expectedUniqueId, generator.getUniqueId(null));
+        assertFalse(mContext.isFlagSet(FLAG_UUID));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testTwoDifferentGeneratorsShouldUseDifferentPreferences() {
+        String preferenceKey1 = "some_preference_key";
+        String preferenceKey2 = "some_other_preference_key";
+        String expectedUniqueId1 = "myUuid";
+        String expectedUniqueId2 = "myOtherUuid";
+        TestGenerator generator1 = new TestGenerator(mContext, preferenceKey1, expectedUniqueId1);
+        TestGenerator generator2 = new TestGenerator(mContext, preferenceKey2, expectedUniqueId2);
+
+        // Get a unique ID and ensure it is as expected.
+        Assert.assertEquals(expectedUniqueId1, generator1.getUniqueId(null));
+        Assert.assertEquals(expectedUniqueId2, generator2.getUniqueId(null));
+
+        // Asking for a unique ID again, should not try to regenerate it.
+        mContext.clearFlag(FLAG_UUID);
+        Assert.assertEquals(expectedUniqueId1, generator1.getUniqueId(null));
+        assertFalse(mContext.isFlagSet(FLAG_UUID));
+        mContext.clearFlag(FLAG_UUID);
+        Assert.assertEquals(expectedUniqueId2, generator2.getUniqueId(null));
+        assertFalse(mContext.isFlagSet(FLAG_UUID));
+   }
+
+    private static class TestGenerator extends UuidBasedUniqueIdentificationGenerator {
+        private final AdvancedMockContext mContext;
+        private final String mUuid;
+
+        TestGenerator(AdvancedMockContext context, String preferenceKey, String uuid) {
+            super(context, preferenceKey);
+            mContext = context;
+            mUuid = uuid;
+        }
+
+        @Override
+        String getUUID() {
+            mContext.setFlag(FLAG_UUID);
+            return mUuid;
+        }
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java
new file mode 100644
index 0000000..112cb77
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java
@@ -0,0 +1,110 @@
+// Copyright 2013 The Chromium 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.sync;
+
+import android.accounts.Account;
+import android.app.Application;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.testshell.ChromiumTestShellTestBase;
+import org.chromium.sync.notifier.SyncStatusHelper;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+public class ChromiumSyncAdapterTest extends ChromiumTestShellTestBase {
+
+    private static final Account TEST_ACCOUNT =
+            AccountManagerHelper.createAccountFromName("test@gmail.com");
+
+    private TestChromiumSyncAdapter mSyncAdapter;
+
+    private static class TestChromiumSyncAdapter extends ChromiumSyncAdapter {
+        private boolean mCommandlineInitialized;
+        private boolean mSyncRequested;
+        private boolean mSyncRequestedForAllTypes;
+        private String mObjectId;
+        private long mVersion;
+        private String mPayload;
+
+        public TestChromiumSyncAdapter(Context context, Application application) {
+            super(context, application);
+        }
+
+        @Override
+        protected boolean useAsyncStartup() {
+            return true;
+        }
+
+        @Override
+        protected void initCommandLine() {
+            mCommandlineInitialized = true;
+        }
+
+        @Override
+        public void requestSync( String objectId, long version, String payload) {
+            mObjectId = objectId;
+            mVersion = version;
+            mPayload = payload;
+            mSyncRequested = true;
+        }
+
+        @Override
+        public void requestSyncForAllTypes() {
+            mSyncRequestedForAllTypes = true;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        launchChromiumTestShellWithBlankPage();
+        mSyncAdapter = new TestChromiumSyncAdapter(getInstrumentation().getTargetContext(),
+                getActivity().getApplication());
+    }
+
+    @MediumTest
+    @Feature({"Sync"})
+    public void testRequestSyncNoInvalidationData() {
+        SyncResult syncResult = new SyncResult();
+        mSyncAdapter.onPerformSync(TEST_ACCOUNT, new Bundle(),
+                SyncStatusHelper.get(getActivity()).getContractAuthority(), null, syncResult);
+        assertTrue(mSyncAdapter.mSyncRequestedForAllTypes);
+        assertFalse(mSyncAdapter.mSyncRequested);
+        assertTrue(mSyncAdapter.mCommandlineInitialized);
+    }
+
+    @MediumTest
+    @Feature({"Sync"})
+    public void testRequestSyncSpecificDataType() {
+        SyncResult syncResult = new SyncResult();
+        Bundle extras = new Bundle();
+        extras.putString(ChromiumSyncAdapter.INVALIDATION_OBJECT_ID_KEY, "objectid_value");
+        extras.putLong(ChromiumSyncAdapter.INVALIDATION_VERSION_KEY, 42);
+        extras.putString(ChromiumSyncAdapter.INVALIDATION_PAYLOAD_KEY, "payload_value");
+        mSyncAdapter.onPerformSync(TEST_ACCOUNT, extras,
+                SyncStatusHelper.get(getActivity()).getContractAuthority(), null, syncResult);
+        assertFalse(mSyncAdapter.mSyncRequestedForAllTypes);
+        assertTrue(mSyncAdapter.mSyncRequested);
+        assertEquals("objectid_value", mSyncAdapter.mObjectId);
+        assertEquals(42, mSyncAdapter.mVersion);
+        assertEquals("payload_value", mSyncAdapter.mPayload);
+        assertTrue(mSyncAdapter.mCommandlineInitialized);
+    }
+
+    @MediumTest
+    @Feature({"Sync"})
+    public void testRequestSyncWhenChromeInBackground() throws InterruptedException {
+        DelayedSyncControllerTest.sendChromeToBackground(getActivity());
+        SyncResult syncResult = new SyncResult();
+        mSyncAdapter.onPerformSync(TEST_ACCOUNT, new Bundle(),
+                SyncStatusHelper.get(getActivity()).getContractAuthority(), null, syncResult);
+        assertFalse(mSyncAdapter.mSyncRequestedForAllTypes);
+        assertFalse(mSyncAdapter.mSyncRequested);
+        assertFalse(mSyncAdapter.mCommandlineInitialized);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/DelayedSyncControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/DelayedSyncControllerTest.java
new file mode 100644
index 0000000..851e571
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/DelayedSyncControllerTest.java
@@ -0,0 +1,117 @@
+// Copyright 2013 The Chromium 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.sync;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.chromium.base.ActivityStatus;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.testshell.ChromiumTestShellTestBase;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+public class DelayedSyncControllerTest extends ChromiumTestShellTestBase {
+    private static final Account TEST_ACCOUNT =
+            AccountManagerHelper.createAccountFromName("something@gmail.com");
+    private static final long WAIT_FOR_LAUNCHER_MS = 10 * 1000;
+    private static final long POLL_INTERVAL_MS = 100;
+    private TestDelayedSyncController mController;
+
+    private static class TestDelayedSyncController extends DelayedSyncController {
+        private boolean mSyncRequested;
+
+        private TestDelayedSyncController() {}
+
+        @Override
+        void requestSyncOnBackgroundThread(Context context, Account account) {
+            mSyncRequested = true;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mController = new TestDelayedSyncController();
+        launchChromiumTestShellWithBlankPage();
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testManualSyncRequestsShouldAlwaysTriggerSync() throws InterruptedException {
+        // Sync should trigger for manual requests when Chrome is in the foreground.
+        assertTrue(isActivityResumed());
+        Bundle extras = new Bundle();
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        assertTrue(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
+
+        // Sync should trigger for manual requests when Chrome is in the background.
+        sendChromeToBackground(getActivity());
+        extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        assertTrue(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testSyncRequestsShouldTriggerSyncWhenChromeIsInForeground() {
+        assertTrue(isActivityResumed());
+        Bundle extras = new Bundle();
+        assertTrue(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testSyncRequestsWhenChromeIsInBackgroundShouldBeDelayed()
+            throws InterruptedException {
+        sendChromeToBackground(getActivity());
+        Bundle extras = new Bundle();
+        assertFalse(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
+    }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testDelayedSyncRequestsShouldBeTriggeredOnResume() throws InterruptedException {
+        // First make sure there are no delayed syncs.
+        mController.clearDelayedSyncs(getActivity());
+        assertFalse(mController.resumeDelayedSyncs(getActivity()));
+        assertFalse(mController.mSyncRequested);
+
+        // Trying to perform sync when Chrome is in the background should create a delayed sync.
+        sendChromeToBackground(getActivity());
+        Bundle extras = new Bundle();
+        assertFalse(mController.shouldPerformSync(getActivity(), extras, TEST_ACCOUNT));
+
+        // Make sure the delayed sync can be resumed.
+        assertTrue(mController.resumeDelayedSyncs(getActivity()));
+        assertTrue(mController.mSyncRequested);
+    }
+
+    @VisibleForTesting
+    static void sendChromeToBackground(Activity activity) throws InterruptedException {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        activity.startActivity(intent);
+
+        assertTrue("Activity should have been resumed",
+                CriteriaHelper.pollForCriteria(new Criteria() {
+                    @Override
+                    public boolean isSatisfied() {
+                        return !isActivityResumed();
+                    }
+                }, WAIT_FOR_LAUNCHER_MS, POLL_INTERVAL_MS));
+    }
+
+    private static boolean isActivityResumed() {
+        return ActivityStatus.getState() == ActivityStatus.RESUMED;
+    }
+}
diff --git a/chrome/android/testshell/DEPS b/chrome/android/testshell/DEPS
index 8b0f526..09339a2 100644
--- a/chrome/android/testshell/DEPS
+++ b/chrome/android/testshell/DEPS
@@ -4,5 +4,7 @@
   "+content/public/android",
   "+content/public/browser",
   "+content/public/browser/android",
+  "+sync/android/java/src/org/chromium/sync/notifier",
+  "+sync/android/java/src/org/chromium/sync/signin",
 ]
 
diff --git a/chrome/android/testshell/java/AndroidManifest.xml b/chrome/android/testshell/java/AndroidManifest.xml
index 7b2ef86..4d8f7a5 100644
--- a/chrome/android/testshell/java/AndroidManifest.xml
+++ b/chrome/android/testshell/java/AndroidManifest.xml
@@ -96,6 +96,16 @@
                  android:isolatedProcess="true"
                  android:exported="false" />
 
+        <!-- Sync adapter for browser sync. -->
+        <service android:exported="false"
+                 android:name="org.chromium.chrome.testshell.sync.ChromiumTestShellSyncAdapterService">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter" />
+            </intent-filter>
+            <meta-data android:name="android.content.SyncAdapter"
+                       android:resource="@xml/syncadapter" />
+        </service>
+
         <!-- Name of the class implementing the invalidation client, for sync notifications. -->
         <meta-data android:name="org.chromium.sync.notifier.IMPLEMENTING_CLASS_NAME"
                    android:value="org.chromium.sync.notifier.TEST_VALUE" />
@@ -111,4 +121,8 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
+    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 </manifest>
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java
index b53c80d..fe7a904 100644
--- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java
@@ -4,34 +4,35 @@
 
 package org.chromium.chrome.testshell;
 
-import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.Toast;
 
 import org.chromium.base.ChromiumActivity;
 import org.chromium.base.MemoryPressureListener;
 import org.chromium.chrome.browser.DevToolsServer;
+import org.chromium.chrome.testshell.sync.SyncController;
 import org.chromium.content.browser.ActivityContentVideoViewClient;
-import org.chromium.content.browser.AndroidBrowserProcess;
-import org.chromium.content.browser.BrowserStartupConfig;
+import org.chromium.content.browser.BrowserStartupController;
 import org.chromium.content.browser.ContentVideoViewClient;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.DeviceUtils;
 import org.chromium.content.common.CommandLine;
-import org.chromium.content.common.ProcessInitException;
+import org.chromium.sync.signin.ChromeSigninController;
 import org.chromium.ui.WindowAndroid;
 
 /**
- * The {@link Activity} component of a basic test shell to test Chrome features.
+ * The {@link android.app.Activity} component of a basic test shell to test Chrome features.
  */
-public class ChromiumTestShellActivity extends ChromiumActivity {
+public class ChromiumTestShellActivity extends ChromiumActivity implements MenuHandler {
     private static final String TAG = "ChromiumTestShellActivity";
-    private static final String COMMAND_LINE_FILE =
-            "/data/local/tmp/chromium-testshell-command-line";
     /**
      * Sending an intent with this action will simulate a memory pressure signal
      * at a critical level.
@@ -54,33 +55,28 @@
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        if (!CommandLine.isInitialized()) CommandLine.initFromFile(COMMAND_LINE_FILE);
+        ChromiumTestShellApplication.initCommandLine();
         waitForDebuggerIfNeeded();
 
         DeviceUtils.addDeviceSpecificUserAgentSwitch(this);
 
-        BrowserStartupConfig.setAsync(new BrowserStartupConfig.StartupCallback() {
-            @Override
-            public void run(int startupResult) {
-                if (startupResult > 0) {
-                    // TODO: Show error message.
-                    Log.e(TAG, "Chromium browser process initialization failed");
-                    finish();
-                } else {
-                    finishInitialization(savedInstanceState);
-                }
-            }
-        });
+        BrowserStartupController.StartupCallback callback =
+                new BrowserStartupController.StartupCallback() {
+                    @Override
+                    public void onSuccess(boolean alreadyStarted) {
+                        finishInitialization(savedInstanceState);
+                    }
 
-        try {
-            if (!AndroidBrowserProcess.init(this, AndroidBrowserProcess.MAX_RENDERERS_LIMIT)) {
-                // Process was already running, finish initialization now.
-                finishInitialization(savedInstanceState);
-            }
-        } catch (ProcessInitException e) {
-            Log.e(TAG, "Chromium browser process initialization failed", e);
-            finish();
-        }
+                    @Override
+                    public void onFailure() {
+                        Toast.makeText(ChromiumTestShellActivity.this,
+                                       R.string.browser_process_initialization_failed,
+                                       Toast.LENGTH_SHORT).show();
+                        Log.e(TAG, "Chromium browser process initialization failed");
+                        finish();
+                    }
+                };
+        BrowserStartupController.get(this).startBrowserProcessesAsync(callback);
     }
 
     private void finishInitialization(final Bundle savedInstanceState) {
@@ -90,6 +86,8 @@
         if (!TextUtils.isEmpty(startupUrl)) {
             mTabManager.setStartupUrl(startupUrl);
         }
+        TestShellToolbar mToolbar = (TestShellToolbar) findViewById(R.id.toolbar);
+        mToolbar.setMenuHandler(this);
 
         mWindow = new WindowAndroid(this);
         mWindow.restoreInstanceState(savedInstanceState);
@@ -103,7 +101,8 @@
     protected void onDestroy() {
         super.onDestroy();
 
-        mDevToolsServer.destroy();
+        if (mDevToolsServer != null)
+            mDevToolsServer.destroy();
         mDevToolsServer = null;
     }
 
@@ -194,6 +193,46 @@
         });
     }
 
+    /**
+     * From {@link MenuHandler}.
+     */
+    @Override
+    public void showPopupMenu() {
+        openOptionsMenu();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.main_menu, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.signin:
+                if (ChromeSigninController.get(this).isSignedIn())
+                    SyncController.openSignOutDialog(getFragmentManager());
+                else
+                    SyncController.openSigninDialog(getFragmentManager());
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        menu.setGroupVisible(R.id.MAIN_MENU, true);
+        MenuItem signinItem = menu.findItem(R.id.signin);
+        if (ChromeSigninController.get(this).isSignedIn())
+            signinItem.setTitle(ChromeSigninController.get(this).getSignedInAccountName());
+        else
+            signinItem.setTitle(R.string.signin_sign_in);
+        return true;
+    }
+
     private void waitForDebuggerIfNeeded() {
         if (CommandLine.getInstance().hasSwitch(CommandLine.WAIT_FOR_JAVA_DEBUGGER)) {
             Log.e(TAG, "Waiting for Java debugger to connect...");
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 98c5f0a..ba09992 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
@@ -5,24 +5,29 @@
 package org.chromium.chrome.testshell;
 
 import android.app.Application;
+import android.content.Intent;
 
 import org.chromium.base.PathUtils;
-import org.chromium.content.app.LibraryLoader;
 import org.chromium.content.browser.ResourceExtractor;
+import org.chromium.content.common.CommandLine;
+
+import java.util.ArrayList;
 
 /**
  * A basic test shell {@link Application}.  Handles setting up the native library and
  * loading the right resources.
  */
 public class ChromiumTestShellApplication extends Application {
-    private static final String TAG = "ChromiumTestShellApplication";
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "chromiumtestshell";
     private static final String[] CHROME_MANDATORY_PAKS = {
-        "chrome.pak",
         "en-US.pak",
         "resources.pak",
         "chrome_100_percent.pak",
     };
+    private static final String COMMAND_LINE_FILE =
+            "/data/local/tmp/chromium-testshell-command-line";
+
+    ArrayList<ChromiumTestShellApplicationObserver> mObservers;
 
     @Override
     public void onCreate() {
@@ -30,5 +35,32 @@
 
         ResourceExtractor.setMandatoryPaksToExtract(CHROME_MANDATORY_PAKS);
         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
+
+        mObservers = new ArrayList<ChromiumTestShellApplicationObserver>();
+    }
+
+    @Override
+    public void sendBroadcast(Intent intent) {
+        boolean shouldFire = true;
+        for (ChromiumTestShellApplicationObserver observer : mObservers) {
+            shouldFire &= observer.onSendBroadcast(intent);
+        }
+
+        if (shouldFire) {
+            super.sendBroadcast(intent);
+        }
+    }
+
+    public void addObserver(ChromiumTestShellApplicationObserver observer) {
+        mObservers.add(observer);
+    }
+
+    public void removeObserver(ChromiumTestShellApplicationObserver observer) {
+        mObservers.remove(observer);
+    }
+
+    public static void initCommandLine() {
+        if (!CommandLine.isInitialized())
+            CommandLine.initFromFile(COMMAND_LINE_FILE);
     }
 }
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplicationObserver.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplicationObserver.java
new file mode 100644
index 0000000..a56b401
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplicationObserver.java
@@ -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.
+
+package org.chromium.chrome.testshell;
+
+import android.content.Intent;
+
+/**
+ * Monitors events happening in {@link ChromiumTestShellApplication}.
+ */
+public interface ChromiumTestShellApplicationObserver {
+    /**
+     * Called when an Intent is about to be broadcast.
+     * @return Whether or not the Application should really fire the broadcast.
+     */
+    public boolean onSendBroadcast(Intent intent);
+}
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/MenuHandler.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/MenuHandler.java
new file mode 100644
index 0000000..679e12d
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/MenuHandler.java
@@ -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.
+
+package org.chromium.chrome.testshell;
+
+/**
+ * By implementing this interface the class declares that it has functionality available to open a
+ * popup menu visible to the user.
+ */
+public interface MenuHandler {
+    public void showPopupMenu();
+}
\ No newline at end of file
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellToolbar.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellToolbar.java
index 023b13b..3a3ad0c 100644
--- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellToolbar.java
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/TestShellToolbar.java
@@ -42,6 +42,7 @@
 
     private TestShellTab mTab;
     private TestShellTabObserver mTabObserver = new TestShellTabObserverImpl();
+    private MenuHandler mMenuHandler;
 
     /**
      * @param context The Context the view is running in.
@@ -79,6 +80,11 @@
         mProgressDrawable = (ClipDrawable) findViewById(R.id.toolbar).getBackground();
         initializeUrlField();
         initializeNavigationButtons();
+        initializeMenuButton();
+    }
+
+    public void setMenuHandler(MenuHandler menuHandler) {
+        mMenuHandler = menuHandler;
     }
 
     private void initializeUrlField() {
@@ -130,6 +136,16 @@
         });
     }
 
+    private void initializeMenuButton() {
+        ImageButton menuButton = (ImageButton) findViewById(R.id.menu_button);
+        menuButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mMenuHandler != null) mMenuHandler.showPopupMenu();
+            }
+        });
+    }
+
     private void setKeyboardVisibilityForUrl(boolean visible) {
         InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
                 Context.INPUT_METHOD_SERVICE);
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/AccountChooserFragment.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/AccountChooserFragment.java
new file mode 100644
index 0000000..20e34f7
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/AccountChooserFragment.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.chrome.testshell.sync;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import org.chromium.chrome.testshell.R;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+import java.util.List;
+
+/**
+ * The fragment to show when the user is given the option to sign in to Chromium.
+ *
+ * It lists the available Google accounts on the device and makes the user choose one.
+ */
+public class AccountChooserFragment extends DialogFragment
+        implements DialogInterface.OnClickListener {
+
+    private String[] mAccounts;
+    private int mSelectedAccount;
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        List<String> accountsList = AccountManagerHelper.get(getActivity()).getGoogleAccountNames();
+        mAccounts = accountsList.toArray(new String[accountsList.size()]);
+        return new AlertDialog.Builder(getActivity(), AlertDialog.THEME_HOLO_LIGHT)
+                .setTitle(R.string.signin_select_account)
+                .setSingleChoiceItems(mAccounts, mSelectedAccount, this)
+                .setPositiveButton(R.string.signin_sign_in, this)
+                .setNegativeButton(R.string.signin_cancel, this)
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case DialogInterface.BUTTON_POSITIVE: {
+                selectAccount(mAccounts[mSelectedAccount]);
+                break;
+            }
+            case DialogInterface.BUTTON_NEGATIVE: {
+                dismiss();
+                break;
+            }
+            default: {
+                mSelectedAccount = which;
+                break;
+            }
+        }
+    }
+
+    private void selectAccount(String accountName) {
+        SyncController.get(getActivity()).signIn(getActivity(), accountName);
+    }
+}
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/ChromiumTestShellSyncAdapter.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/ChromiumTestShellSyncAdapter.java
new file mode 100644
index 0000000..7d8c04e
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/ChromiumTestShellSyncAdapter.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.chrome.testshell.sync;
+
+import android.app.Application;
+import android.content.Context;
+
+import org.chromium.chrome.browser.sync.ChromiumSyncAdapter;
+import org.chromium.chrome.testshell.ChromiumTestShellApplication;
+
+public class ChromiumTestShellSyncAdapter extends ChromiumSyncAdapter {
+    public ChromiumTestShellSyncAdapter(Context appContext, Application application) {
+        super(appContext, application);
+    }
+
+    @Override
+    protected boolean useAsyncStartup() {
+        return true;
+    }
+
+    @Override
+    protected void initCommandLine() {
+        ChromiumTestShellApplication.initCommandLine();
+    }
+}
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/ChromiumTestShellSyncAdapterService.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/ChromiumTestShellSyncAdapterService.java
new file mode 100644
index 0000000..f89e0e2
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/ChromiumTestShellSyncAdapterService.java
@@ -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.
+
+package org.chromium.chrome.testshell.sync;
+
+import android.app.Application;
+import android.content.Context;
+
+import org.chromium.chrome.browser.sync.ChromiumSyncAdapter;
+import org.chromium.chrome.browser.sync.ChromiumSyncAdapterService;
+
+public class ChromiumTestShellSyncAdapterService extends ChromiumSyncAdapterService {
+    @Override
+    protected ChromiumSyncAdapter createChromiumSyncAdapter(
+            Context context, Application application) {
+        return new ChromiumTestShellSyncAdapter(context, getApplication());
+    }
+}
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SignoutFragment.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SignoutFragment.java
new file mode 100644
index 0000000..39dd70d
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SignoutFragment.java
@@ -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.
+
+package org.chromium.chrome.testshell.sync;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import org.chromium.chrome.browser.signin.SigninManager;
+import org.chromium.chrome.testshell.R;
+
+/**
+ * The fragment to show when the user is given the option to sign out of Chromium.
+ */
+public class SignoutFragment extends DialogFragment implements DialogInterface.OnClickListener {
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new AlertDialog.Builder(getActivity(), AlertDialog.THEME_HOLO_LIGHT)
+                .setTitle(R.string.signout_title)
+                .setPositiveButton(R.string.signout_sign_out, this)
+                .setNegativeButton(R.string.signout_cancel, this)
+                .create();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case DialogInterface.BUTTON_POSITIVE: {
+                SigninManager.get(getActivity()).signOut(getActivity(), null);
+                break;
+            }
+            case DialogInterface.BUTTON_NEGATIVE: {
+                dismiss();
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
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
new file mode 100644
index 0000000..9799ee3
--- /dev/null
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/sync/SyncController.java
@@ -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.
+
+package org.chromium.chrome.testshell.sync;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.FragmentManager;
+import android.content.Context;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.signin.SigninManager;
+import org.chromium.chrome.browser.sync.ProfileSyncService;
+import org.chromium.sync.notifier.SyncStatusHelper;
+import org.chromium.sync.signin.AccountManagerHelper;
+
+/**
+ * A helper class for signing in and out of Chromium.
+ */
+public class SyncController {
+
+    private static SyncController sInstance;
+
+    private final Context mContext;
+
+    private SyncController(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Retrieve the singleton instance of this class.
+     *
+     * @param context the current context.
+     * @return the singleton instance.
+     */
+    public static SyncController get(Context context) {
+        ThreadUtils.assertOnUiThread();
+        if (sInstance == null) {
+            sInstance = new SyncController(context.getApplicationContext());
+        }
+        return sInstance;
+    }
+
+    /**
+     * Open a dialog that gives the user the option to sign in from a list of available accounts.
+     *
+     * @param fragmentManager the FragmentManager.
+     */
+    public static void openSigninDialog(FragmentManager fragmentManager) {
+        AccountChooserFragment chooserFragment = new AccountChooserFragment();
+        chooserFragment.show(fragmentManager, null);
+    }
+
+    /**
+     * Open a dialog that gives the user the option to sign out.
+     *
+     * @param fragmentManager the FragmentManager.
+     */
+    public static void openSignOutDialog(FragmentManager fragmentManager) {
+        SignoutFragment signoutFragment = new SignoutFragment();
+        signoutFragment.show(fragmentManager, null);
+    }
+
+    /**
+     * Trigger Chromium sign in of the given account.
+     *
+     * This also ensure that sync setup is not in progress anymore, so sync will start after
+     * sync initialization has happened.
+     *
+     * @param activity the current activity.
+     * @param accountName the full account name.
+     */
+    public void signIn(Activity activity, String accountName) {
+        final Account account = AccountManagerHelper.createAccountFromName(accountName);
+
+        // The SigninManager handles most of the sign-in flow, and doFinishSignIn handles the
+        // Chromium testshell specific details.
+        SigninManager signinManager = SigninManager.get(mContext);
+        final boolean passive = false;
+        signinManager.startSignIn(activity, account, passive, new SigninManager.Observer() {
+            @Override
+            public void onSigninComplete() {
+                ProfileSyncService.get(mContext).setSetupInProgress(false);
+                // The SigninManager does not control the Android sync state.
+                SyncStatusHelper.get(mContext).enableAndroidSync(account);
+            }
+
+            @Override
+            public void onSigninCancelled() {
+            }
+        });
+    }
+}
diff --git a/chrome/android/testshell/res/drawable/menu_dots.png b/chrome/android/testshell/res/drawable/menu_dots.png
new file mode 100644
index 0000000..01d6816
--- /dev/null
+++ b/chrome/android/testshell/res/drawable/menu_dots.png
Binary files differ
diff --git a/chrome/android/testshell/res/layout/testshell_activity.xml b/chrome/android/testshell/res/layout/testshell_activity.xml
index 4346e59..a228b54 100644
--- a/chrome/android/testshell/res/layout/testshell_activity.xml
+++ b/chrome/android/testshell/res/layout/testshell_activity.xml
@@ -39,6 +39,11 @@
             android:layout_height="38dp"
             android:src="@android:drawable/ic_media_next"
             android:scaleType="center" />
+        <ImageButton android:id="@+id/menu_button"
+            android:layout_width="38dp"
+            android:layout_height="38dp"
+            android:src="@drawable/menu_dots"
+            android:scaleType="center" />
     </org.chromium.chrome.testshell.TestShellToolbar>
     <FrameLayout android:id="@+id/content_container"
         android:layout_width="match_parent"
diff --git a/chrome/android/testshell/res/menu/main_menu.xml b/chrome/android/testshell/res/menu/main_menu.xml
new file mode 100644
index 0000000..2a3e6fe
--- /dev/null
+++ b/chrome/android/testshell/res/menu/main_menu.xml
@@ -0,0 +1,15 @@
+<?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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <group android:id="@+id/MAIN_MENU"
+           android:visible="false">
+        <item android:id="@+id/signin"
+              android:title="@string/signin_sign_in" />
+    </group>
+</menu>
+
diff --git a/chrome/android/testshell/res/values/strings.xml b/chrome/android/testshell/res/values/strings.xml
index 6eaaaec..bd9c1b0 100644
--- a/chrome/android/testshell/res/values/strings.xml
+++ b/chrome/android/testshell/res/values/strings.xml
@@ -8,4 +8,11 @@
 
 <resources>
     <string name="url_hint">Type URL Here</string>
+    <string name="signin_select_account">Select Account</string>
+    <string name="signin_sign_in">Sign in</string>
+    <string name="signin_cancel">Cancel</string>
+    <string name="signout_title">Do you want to sign out?</string>
+    <string name="signout_sign_out">Sign out</string>
+    <string name="signout_cancel">Cancel</string>
+    <string name="browser_process_initialization_failed">Initialization failed.</string>
 </resources>
diff --git a/chrome/android/testshell/res/xml/syncadapter.xml b/chrome/android/testshell/res/xml/syncadapter.xml
new file mode 100644
index 0000000..65c2747
--- /dev/null
+++ b/chrome/android/testshell/res/xml/syncadapter.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the SyncAdapter. -->
+
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+    android:contentAuthority="org.chromium.chrome.testshell"
+    android:accountType="com.google"
+/>
diff --git a/chrome/android/testshell/testshell_stubs.cc b/chrome/android/testshell/testshell_stubs.cc
index 01c665a..eeb71d7 100644
--- a/chrome/android/testshell/testshell_stubs.cc
+++ b/chrome/android/testshell/testshell_stubs.cc
@@ -8,6 +8,8 @@
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/browser/ui/auto_login_infobar_delegate.h"
 #include "chrome/browser/ui/auto_login_infobar_delegate_android.h"
+#include "printing/printing_context.h"
+#include "printing/printing_context_android.h"
 
 // This file contains temporary stubs to allow the libtestshell target to
 // compile. They will be removed once real implementations are
@@ -57,3 +59,14 @@
 InfoBar* TranslateInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
   return NULL;
 }
+
+// static
+printing::PrintingContext* printing::PrintingContext::Create(
+    const std::string& app_locale) {
+  return NULL;
+}
+
+// static
+void printing::PrintingContextAndroid::PdfWritingDone(int fd, bool success) {
+}
+
diff --git a/chrome/app/breakpad_linux.cc b/chrome/app/breakpad_linux.cc
index cf9d0c7..60e4fda 100644
--- a/chrome/app/breakpad_linux.cc
+++ b/chrome/app/breakpad_linux.cc
@@ -192,26 +192,19 @@
   return len;
 }
 
-// Populates the passed in allocated strings and their sizes with the GUID,
-// crash url and distro of the crashing process.
-// The passed strings are expected to be at least kGuidSize, kMaxActiveURLSize
+// Populates the passed in allocated strings and their sizes with the GUID
+// and distro of the crashing process.
+// The passed strings are expected to be at least kGuidSize
 // and kDistroSize bytes long respectively.
-void PopulateGUIDAndURLAndDistro(char* guid, size_t* guid_len_param,
-                                 char* crash_url, size_t* crash_url_len_param,
-                                 char* distro, size_t* distro_len_param) {
+void PopulateGUIDAndDistro(char* guid, size_t* guid_len_param,
+                           char* distro, size_t* distro_len_param) {
   size_t guid_len = std::min(my_strlen(child_process_logging::g_client_id),
                              kGuidSize);
-  size_t crash_url_len =
-      std::min(my_strlen(child_process_logging::g_active_url),
-               kMaxActiveURLSize);
   size_t distro_len = std::min(my_strlen(base::g_linux_distro), kDistroSize);
   memcpy(guid, child_process_logging::g_client_id, guid_len);
-  memcpy(crash_url, child_process_logging::g_active_url, crash_url_len);
   memcpy(distro, base::g_linux_distro, distro_len);
   if (guid_len_param)
     *guid_len_param = guid_len;
-  if (crash_url_len_param)
-    *crash_url_len_param = crash_url_len;
   if (distro_len_param)
     *distro_len_param = distro_len;
 }
@@ -594,8 +587,6 @@
 #endif
   info.process_type = "browser";
   info.process_type_length = 7;
-  info.crash_url = NULL;
-  info.crash_url_length = 0;
   info.guid = child_process_logging::g_client_id;
   info.guid_length = my_strlen(child_process_logging::g_client_id);
   info.distro = base::g_linux_distro;
@@ -700,26 +691,22 @@
 
   // Start constructing the message to send to the browser.
   char guid[kGuidSize + 1] = {0};
-  char crash_url[kMaxActiveURLSize + 1] = {0};
   char distro[kDistroSize + 1] = {0};
   size_t guid_length = 0;
-  size_t crash_url_length = 0;
   size_t distro_length = 0;
-  PopulateGUIDAndURLAndDistro(guid, &guid_length, crash_url, &crash_url_length,
-                              distro, &distro_length);
+  PopulateGUIDAndDistro(guid, &guid_length, distro, &distro_length);
   BreakpadInfo info = {0};
   info.filename = NULL;
   info.fd = descriptor.fd();
   info.process_type = g_process_type;
   info.process_type_length = my_strlen(g_process_type);
-  info.crash_url = crash_url;
-  info.crash_url_length = crash_url_length;
   info.guid = guid;
   info.guid_length = guid_length;
   info.distro = distro;
   info.distro_length = distro_length;
   info.upload = false;
   info.process_start_time = g_process_start_time;
+  info.crash_keys = g_crash_keys;
   HandleCrashDump(info);
   return FinalizeCrashDoneAndroid();
 }
@@ -771,9 +758,8 @@
 
   // Start constructing the message to send to the browser.
   char guid[kGuidSize + 1] = {0};
-  char crash_url[kMaxActiveURLSize + 1] = {0};
   char distro[kDistroSize + 1] = {0};
-  PopulateGUIDAndURLAndDistro(guid, NULL, crash_url, NULL, distro, NULL);
+  PopulateGUIDAndDistro(guid, NULL, distro, NULL);
 
   char b;  // Dummy variable for sys_read below.
   const char* b_addr = &b;  // Get the address of |b| so we can create the
@@ -792,26 +778,24 @@
   iov[0].iov_len = crash_context_size;
   iov[1].iov_base = guid;
   iov[1].iov_len = kGuidSize + 1;
-  iov[2].iov_base = crash_url;
-  iov[2].iov_len = kMaxActiveURLSize + 1;
-  iov[3].iov_base = distro;
-  iov[3].iov_len = kDistroSize + 1;
-  iov[4].iov_base = &b_addr;
-  iov[4].iov_len = sizeof(b_addr);
-  iov[5].iov_base = &fds[0];
-  iov[5].iov_len = sizeof(fds[0]);
-  iov[6].iov_base = &g_process_start_time;
-  iov[6].iov_len = sizeof(g_process_start_time);
-  iov[7].iov_base = &base::g_oom_size;
-  iov[7].iov_len = sizeof(base::g_oom_size);
+  iov[2].iov_base = distro;
+  iov[2].iov_len = kDistroSize + 1;
+  iov[3].iov_base = &b_addr;
+  iov[3].iov_len = sizeof(b_addr);
+  iov[4].iov_base = &fds[0];
+  iov[4].iov_len = sizeof(fds[0]);
+  iov[5].iov_base = &g_process_start_time;
+  iov[5].iov_len = sizeof(g_process_start_time);
+  iov[6].iov_base = &base::g_oom_size;
+  iov[6].iov_len = sizeof(base::g_oom_size);
   google_breakpad::SerializedNonAllocatingMap* serialized_map;
-  iov[8].iov_len = g_crash_keys->Serialize(
+  iov[7].iov_len = g_crash_keys->Serialize(
       const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
           &serialized_map));
-  iov[8].iov_base = serialized_map;
+  iov[7].iov_base = serialized_map;
 #if defined(ADDRESS_SANITIZER)
-  iov[9].iov_base = const_cast<char*>(g_asan_report_str);
-  iov[9].iov_len = kMaxAsanReportSize + 1;
+  iov[8].iov_base = const_cast<char*>(g_asan_report_str);
+  iov[8].iov_len = kMaxAsanReportSize + 1;
 #endif
 
   msg.msg_iov = iov;
@@ -1178,11 +1162,6 @@
   //   abcdef \r\n
   //   BOUNDARY \r\n
   //
-  //   zero or more:
-  //   Content-Disposition: form-data; name="url-chunk-1" \r\n \r\n
-  //   abcdef \r\n
-  //   BOUNDARY \r\n
-  //
   //   zero or one:
   //   Content-Disposition: form-data; name="channel" \r\n \r\n
   //   beta \r\n
@@ -1357,15 +1336,6 @@
     writer.Flush();
   }
 
-  // For renderers and plugins.
-  if (info.crash_url_length) {
-    static const char url_chunk_msg[] = "url-chunk-";
-    static const unsigned kMaxUrlLength = 8 * MimeWriter::kMaxCrashChunkSize;
-    writer.AddPairDataInChunks(url_chunk_msg, sizeof(url_chunk_msg) - 1,
-        info.crash_url, std::min(info.crash_url_length, kMaxUrlLength),
-        MimeWriter::kMaxCrashChunkSize, false /* Don't strip whitespaces. */);
-  }
-
   if (*child_process_logging::g_channel) {
     writer.AddPairString("channel", child_process_logging::g_channel);
     writer.AddBoundary();
diff --git a/chrome/app/breakpad_linux_impl.h b/chrome/app/breakpad_linux_impl.h
index f9c9d92..f82f81d 100644
--- a/chrome/app/breakpad_linux_impl.h
+++ b/chrome/app/breakpad_linux_impl.h
@@ -17,7 +17,6 @@
 
 typedef google_breakpad::NonAllocatingMap<256, 256, 64> CrashKeyStorage;
 
-static const size_t kMaxActiveURLSize = 1024;
 static const size_t kGuidSize = 32;  // 128 bits = 32 chars in hex.
 static const size_t kDistroSize = 128;
 #if defined(ADDRESS_SANITIZER)
@@ -31,10 +30,10 @@
 // The size of the iovec used to transfer crash data from a child back to the
 // browser.
 #if !defined(ADDRESS_SANITIZER)
-const size_t kCrashIovSize = 9;
+const size_t kCrashIovSize = 8;
 #else
 // Additional field to pass the AddressSanitizer log to the crash handler.
-const size_t kCrashIovSize = 10;
+const size_t kCrashIovSize = 9;
 #endif
 
 // BreakpadInfo describes a crash report.
@@ -50,8 +49,6 @@
 #endif
   const char* process_type;        // Process type, e.g. "renderer".
   unsigned process_type_length;    // Length of |process_type|.
-  const char* crash_url;           // Active URL in the crashing process.
-  unsigned crash_url_length;       // Length of |crash_url|.
   const char* guid;                // Client ID.
   unsigned guid_length;            // Length of |guid|.
   const char* distro;              // Linux distro string.
diff --git a/chrome/app/breakpad_win.cc b/chrome/app/breakpad_win.cc
index 6e58e15..11c634b 100644
--- a/chrome/app/breakpad_win.cc
+++ b/chrome/app/breakpad_win.cc
@@ -31,6 +31,7 @@
 #include "chrome/app/breakpad_field_trial_win.h"
 #include "chrome/app/hard_error_handler_win.h"
 #include "chrome/common/child_process_logging.h"
+#include "chrome/common/chrome_constants.h"
 #include "components/breakpad/breakpad_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
@@ -100,7 +101,6 @@
                                                  NTSTATUS ExitStatus);
 char* g_real_terminate_process_stub = NULL;
 
-static size_t g_url_chunks_offset = 0;
 static size_t g_num_of_extensions_offset = 0;
 static size_t g_extension_ids_offset = 0;
 static size_t g_client_id_offset = 0;
@@ -110,23 +110,74 @@
 static size_t g_num_switches_offset = 0;
 static size_t g_switches_offset = 0;
 static size_t g_dynamic_keys_offset = 0;
-typedef std::map<std::string, google_breakpad::CustomInfoEntry*>
+typedef std::map<std::wstring, google_breakpad::CustomInfoEntry*>
     DynamicEntriesMap;
 DynamicEntriesMap* g_dynamic_entries = NULL;
-static size_t g_dynamic_entries_count = 0;
+// Allow for 128 entries. POSIX uses 64 entries of 256 bytes, so Windows needs
+// 256 entries of 64 bytes to match. See CustomInfoEntry::kValueMaxLength in
+// Breakpad.
+const size_t kMaxDynamicEntries = 256;
 
 // Maximum length for plugin path to include in plugin crash reports.
 const size_t kMaxPluginPathLength = 256;
 
+// These values track the browser crash dump registry key and pre-computed
+// registry value name, which we use as a "smoke-signal" for counting dumps.
+static HKEY g_browser_crash_dump_regkey = NULL;
+static const wchar_t kBrowserCrashDumpValueFormatStr[] = L"%08x-%08x";
+static const int kBrowserCrashDumpValueLength = 17;
+static wchar_t g_browser_crash_dump_value[kBrowserCrashDumpValueLength+1] = {0};
+
+void InitBrowserCrashDumpsRegKey() {
+  DCHECK(g_browser_crash_dump_regkey == NULL);
+
+  base::string16 key_str(chrome::kBrowserCrashDumpAttemptsRegistryPath);
+  key_str += L"\\";
+  key_str += UTF8ToWide(chrome::kChromeVersion);
+
+  base::win::RegKey regkey;
+  if (regkey.Create(HKEY_CURRENT_USER,
+                    key_str.c_str(),
+                    KEY_ALL_ACCESS) != ERROR_SUCCESS) {
+    return;
+  }
+
+  g_browser_crash_dump_regkey = regkey.Take();
+
+  // We use the current process id and the curren tick count as a (hopefully)
+  // unique combination for the crash dump value. There's a small chance that
+  // across a reboot we might have a crash dump signal written, and the next
+  // browser process might have the same process id and tick count, but crash
+  // before consuming the signal (overwriting the signal with an identical one).
+  // For now, we're willing to live with that risk.
+  int length = swprintf(g_browser_crash_dump_value,
+                        sizeof(g_browser_crash_dump_value),
+                        kBrowserCrashDumpValueFormatStr,
+                        ::GetCurrentProcessId(),
+                        ::GetTickCount());
+  DCHECK_EQ(kBrowserCrashDumpValueLength, length);
+}
+
+void SendSmokeSignalForCrashDump() {
+  if (g_browser_crash_dump_regkey != NULL) {
+    base::win::RegKey regkey(g_browser_crash_dump_regkey);
+    regkey.WriteValue(g_browser_crash_dump_value, 1);
+    g_browser_crash_dump_regkey = NULL;
+  }
+}
+
 // Dumps the current process memory.
 extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
-  if (g_breakpad)
+  if (g_breakpad) {
+    SendSmokeSignalForCrashDump();
     g_breakpad->WriteMinidump();
+  }
 }
 
 // Used for dumping a process state when there is no crash.
 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() {
   if (g_dumphandler_no_crash) {
+    SendSmokeSignalForCrashDump();
     g_dumphandler_no_crash->WriteMinidump();
   }
 }
@@ -173,6 +224,7 @@
 extern "C" void DumpProcessAbnormalSignature() {
   if (!g_breakpad)
     return;
+  SendSmokeSignalForCrashDump();
   g_custom_entries->push_back(
       google_breakpad::CustomInfoEntry(L"unusual-crash-signature", L""));
   g_breakpad->WriteMinidump();
@@ -458,15 +510,6 @@
     g_num_of_views_offset = g_custom_entries->size();
     g_custom_entries->push_back(
         google_breakpad::CustomInfoEntry(L"num-views", L""));
-    // Create entries for the URL. Currently we only allow each chunk to be 64
-    // characters, which isn't enough for a URL. As a hack we create 8 entries
-    // and split the URL across the g_custom_entries.
-    g_url_chunks_offset = g_custom_entries->size();
-    // one-based index for the name suffix.
-    for (int i = 1; i <= kMaxUrlChunks; ++i) {
-      g_custom_entries->push_back(google_breakpad::CustomInfoEntry(
-          base::StringPrintf(L"url-chunk-%i", i).c_str(), L""));
-    }
 
     if (type == L"plugin" || type == L"ppapi") {
       std::wstring plugin_path =
@@ -508,9 +551,8 @@
 
   // Create space for dynamic ad-hoc keys. The names and values are set using
   // the API defined in base/debug/crash_logging.h.
-  g_dynamic_entries_count = breakpad::GetBreakpadClient()->RegisterCrashKeys();
   g_dynamic_keys_offset = g_custom_entries->size();
-  for (size_t i = 0; i < g_dynamic_entries_count; ++i) {
+  for (size_t i = 0; i < kMaxDynamicEntries; ++i) {
     // The names will be mutated as they are set. Un-numbered since these are
     // merely placeholders. The name cannot be empty because Breakpad's
     // HTTPUpload will interpret that as an invalid parameter.
@@ -613,38 +655,6 @@
   return EXCEPTION_EXECUTE_HANDLER;
 }
 
-extern "C" void __declspec(dllexport) __cdecl SetActiveURL(
-    const wchar_t* url_cstring) {
-  DCHECK(url_cstring);
-
-  if (!g_custom_entries)
-    return;
-
-  std::wstring url(url_cstring);
-  size_t chunk_index = 0;
-  size_t url_size = url.size();
-
-  // Split the url across all the chunks.
-  for (size_t url_offset = 0;
-       chunk_index < kMaxUrlChunks && url_offset < url_size; ++chunk_index) {
-    size_t current_chunk_size = std::min(url_size - url_offset,
-        static_cast<size_t>(
-            google_breakpad::CustomInfoEntry::kValueMaxLength - 1));
-
-    wchar_t* entry_value =
-        (*g_custom_entries)[g_url_chunks_offset + chunk_index].value;
-    url._Copy_s(entry_value,
-                google_breakpad::CustomInfoEntry::kValueMaxLength,
-                current_chunk_size, url_offset);
-    entry_value[current_chunk_size] = L'\0';
-    url_offset += current_chunk_size;
-  }
-
-  // And null terminate any unneeded chunks.
-  for (; chunk_index < kMaxUrlChunks; ++chunk_index)
-    (*g_custom_entries)[g_url_chunks_offset + chunk_index].value[0] = L'\0';
-}
-
 extern "C" void __declspec(dllexport) __cdecl SetClientId(
     const wchar_t* client_id) {
   if (client_id == NULL)
@@ -718,43 +728,41 @@
   SetIntegerValue(g_num_of_views_offset, number_of_views);
 }
 
-void SetCrashKeyValue(const base::StringPiece& key,
-                      const base::StringPiece& value) {
+// NOTE: This function is used by SyzyASAN to annotate crash reports. If you
+// change the name or signature of this function you will break SyzyASAN
+// instrumented releases of Chrome. Please contact syzygy-team@chromium.org
+// before doing so!
+extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
+    const wchar_t* key, const wchar_t* value) {
   // 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.
-  base::StringPiece safe_key(key.substr(
+  std::wstring safe_key(std::wstring(key).substr(
       0, google_breakpad::CustomInfoEntry::kNameMaxLength  - 1));
-  base::StringPiece safe_value(value.substr(
+  std::wstring safe_value(std::wstring(value).substr(
       0, google_breakpad::CustomInfoEntry::kValueMaxLength - 1));
 
-  // Keep a copy of the safe key as a std::string, we'll reuse it later.
-  std::string key_string(safe_key.begin(), safe_key.end());
-
   // If we already have a value for this key, update it; otherwise, insert
   // the new value if we have not exhausted the pre-allocated slots for dynamic
   // entries.
-  DynamicEntriesMap::iterator it = g_dynamic_entries->find(key_string);
+  DynamicEntriesMap::iterator it = g_dynamic_entries->find(safe_key);
   google_breakpad::CustomInfoEntry* entry = NULL;
   if (it == g_dynamic_entries->end()) {
-    if (g_dynamic_entries->size() >= g_dynamic_entries_count)
+    if (g_dynamic_entries->size() >= kMaxDynamicEntries)
       return;
     entry = &(*g_custom_entries)[g_dynamic_keys_offset++];
-    g_dynamic_entries->insert(std::make_pair(key_string, entry));
+    g_dynamic_entries->insert(std::make_pair(safe_key, entry));
   } else {
     entry = it->second;
   }
 
-  entry->set(UTF8ToWide(safe_key).data(), UTF8ToWide(safe_value).data());
+  entry->set(safe_key.data(), safe_value.data());
 }
 
-extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValuePair(
-    const char* key, const char* value) {
-  SetCrashKeyValue(base::StringPiece(key), base::StringPiece(value));
-}
-
-void ClearCrashKeyValue(const base::StringPiece& key) {
-  DynamicEntriesMap::iterator it = g_dynamic_entries->find(key.as_string());
+extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(
+    const wchar_t* key) {
+  std::wstring key_string(key);
+  DynamicEntriesMap::iterator it = g_dynamic_entries->find(key_string);
   if (it == g_dynamic_entries->end())
     return;
 
@@ -827,9 +835,13 @@
 // Crashes the process after generating a dump for the provided exception. Note
 // that the crash reporter should be initialized before calling this function
 // for it to do anything.
+// NOTE: This function is used by SyzyASAN to invoke a crash. If you change the
+// the name or signature of this function you will break SyzyASAN instrumented
+// releases of Chrome. Please contact syzygy-team@chromium.org before doing so!
 extern "C" int __declspec(dllexport) CrashForException(
     EXCEPTION_POINTERS* info) {
   if (g_breakpad) {
+    SendSmokeSignalForCrashDump();
     g_breakpad->WriteMinidumpForException(info);
     // Patched stub exists based on conditions (See InitCrashReporter).
     // As a side note this function also gets called from
@@ -991,9 +1003,6 @@
   bool is_per_user_install = breakpad::GetBreakpadClient()->GetIsPerUserInstall(
       base::FilePath(exe_path));
 
-  base::debug::SetCrashKeyReportingFunctions(
-      &SetCrashKeyValue, &ClearCrashKeyValue);
-
   google_breakpad::CustomClientInfo* custom_info =
       GetCustomInfo(exe_path, process_type);
 
@@ -1011,6 +1020,7 @@
 
   if (process_type == L"browser") {
     InitPipeNameEnvVar(is_per_user_install);
+    InitBrowserCrashDumpsRegKey();
   }
 
   scoped_ptr<base::Environment> env(base::Environment::Create());
@@ -1070,7 +1080,6 @@
     g_breakpad->set_handle_debug_exceptions(true);
 
 #ifndef _WIN64
-    std::string headless;
     if (process_type != L"browser" &&
         !breakpad::GetBreakpadClient()->IsRunningUnattended()) {
       // Initialize the hook TerminateProcess to catch unexpected exits.
diff --git a/chrome/app/breakpad_win.h b/chrome/app/breakpad_win.h
index 96e0ef3..0514d4e 100644
--- a/chrome/app/breakpad_win.h
+++ b/chrome/app/breakpad_win.h
@@ -28,9 +28,6 @@
 
 }  // namespace breakpad_win
 
-// The maximum number of 64-char URL chunks we will report.
-static const int kMaxUrlChunks = 8;
-
 void InitCrashReporter();
 
 // Intercepts a crash but does not process it, just ask if we want to restart
diff --git a/chrome/app/chrome_breakpad_client.cc b/chrome/app/chrome_breakpad_client.cc
index 967d609..2c0936e 100644
--- a/chrome/app/chrome_breakpad_client.cc
+++ b/chrome/app/chrome_breakpad_client.cc
@@ -234,6 +234,9 @@
 #endif
 
 size_t ChromeBreakpadClient::RegisterCrashKeys() {
+  // Note: This is not called on Windows because Breakpad is initialized in the
+  // EXE module, but code that uses crash keys is in the DLL module.
+  // RegisterChromeCrashKeys() will be called after the DLL is loaded.
   return crash_keys::RegisterChromeCrashKeys();
 }
 
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index e5dafb5..b041077 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -41,6 +41,7 @@
 #include <atlbase.h>
 #include <malloc.h>
 #include "base/strings/string_util.h"
+#include "chrome/common/child_process_logging.h"
 #include "sandbox/win/src/sandbox.h"
 #include "tools/memory_watcher/memory_watcher.h"
 #include "ui/base/resource/resource_bundle_win.h"
@@ -587,6 +588,10 @@
   InitMacCrashReporter(command_line, process_type);
 #endif
 
+#if defined(OS_WIN)
+  child_process_logging::Init();
+#endif
+
   // Notice a user data directory override if any
   base::FilePath user_data_dir =
       command_line.GetSwitchValuePath(switches::kUserDataDir);
@@ -662,7 +667,6 @@
     ResourceBundle::InitSharedInstanceWithPakFile(locale_pak_fd, false);
 
     int extra_pak_keys[] = {
-      kAndroidChromePakDescriptor,
       kAndroidChrome100PercentPakDescriptor,
       kAndroidUIResourcesPakDescriptor,
     };
@@ -739,10 +743,9 @@
     const content::MainFunctionParams& main_function_params) {
   // ANDROID doesn't support "service", so no ServiceProcessMain, and arraysize
   // doesn't support empty array. So we comment out the block for Android.
-#if !defined(OS_ANDROID) && \
-    (!defined(CHROME_MULTIPLE_DLL) || defined(CHROME_MULTIPLE_DLL_BROWSER))
+#if !defined(OS_ANDROID)
   static const MainFunction kMainFunctions[] = {
-#if defined(ENABLE_FULL_PRINTING)
+#if defined(ENABLE_FULL_PRINTING) && !defined(CHROME_MULTIPLE_DLL_CHILD)
     { switches::kServiceProcess,     ServiceProcessMain },
 #endif
 
@@ -751,9 +754,8 @@
       mac_relauncher::internal::RelauncherMain },
 #endif
 
-#if !defined(DISABLE_NACL) && \
-    (!defined(CHROME_MULTIPLE_DLL) || defined(CHROME_MULTIPLE_DLL_CHILD))
-    { switches::kNaClLoaderProcess, NaClMain },
+#if !defined(DISABLE_NACL) && !defined(CHROME_MULTIPLE_DLL_BROWSER)
+    { switches::kNaClLoaderProcess,  NaClMain },
 #endif  // DISABLE_NACL
   };
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 92a0ad4..8ccc4fd 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -179,18 +179,6 @@
   <message name="IDS_NETWORK_ENROLLMENT_HANDLER_BUTTON" desc="Text of the accept button for generating a new network certificate.">
     Get new certificate
   </message>
-  <message name="IDS_NETWORK_ACTIVATION_ERROR_TITLE" desc="Title for network connection error notification">
-    Network Activation Error
-  </message>
-  <message name="IDS_NETWORK_ACTIVATION_NEEDS_CONNECTION" desc="Message when attempting to activate a mobile network that requries a connection">
-    Activation of '<ph name="name">$1<ex>Generic Wireless</ex></ph>' requires a network connection.
-  </message>
-  <message name="IDS_NETWORK_CELLULAR_ACTIVATED_TITLE" desc="Title for cellular activated notification">
-    Cellular Activated
-  </message>
-  <message name="IDS_NETWORK_CELLULAR_ACTIVATED" desc="Text of the cellular activated notification">
-    Congratulations! Your '<ph name="name">$1<ex>Generic Wireless</ex></ph>' data service has been activated and is ready to go.
-  </message>
   <message name="IDS_LOW_BATTERY_TITLE" desc="Title for low battery notification">
     Battery Low
   </message>
@@ -1292,6 +1280,9 @@
   <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_ADVANCED_BUTTON" desc="In settings Internet options, Join other network, the text on the button to show advanced settings.">
     Advanced
   </message>
+  <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_EAP_SUBJECT_MATCH" desc="In settings Internet options, the label for the EAP Subject Match field.">
+    Subject Match:
+  </message>
   <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE" desc="In settings Internet options, the label for the bad passphrase.">
     Incorrect password.
   </message>
@@ -2534,6 +2525,9 @@
   <message name="IDS_PROXY_BYPASS" desc="Label for the proxy bypass list.">
     Do not use the proxy settings for these hosts and domains:
   </message>
+  <message name="IDS_PROXY_WEB_PROXY_AUTO_DISCOVERY" desc="Label for the web proxy auto discovery url.">
+    Web Proxy Auto Discovery URL
+  </message>
 
   <!-- Accessibility strings, to be spoken -->
   <message name="IDS_CHROMEOS_ACC_BUTTON" desc="Label indicating that a control is a pushbutton.">
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 9e97135..ca2fef6 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -79,11 +79,11 @@
     <output filename="chromium_strings_nb.pak" type="data_package" lang="no" />
     <!-- 'no' for Norwegian Bokmål. It should be 'nb'. -->
     <output filename="chromium_strings_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="chromium_strings_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="chromium_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="chromium_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
@@ -290,13 +290,13 @@
       <message name="IDS_CERT_ERROR_NOT_YET_VALID_DETAILS" desc="Details for an X509 certificate that is not yet valid">
         You attempted to reach &lt;strong&gt;<ph name="DOMAIN">$1<ex>paypal.com</ex></ph>&lt;/strong&gt;, but the server presented a certificate that is not yet valid. No information is available to indicate whether that certificate can be trusted. Chromium cannot reliably guarantee that you are communicating with &lt;strong&gt;<ph name="DOMAIN2">$2<ex>paypal.com</ex></ph>&lt;/strong&gt; and not an attacker. Your computer's clock is currently set to <ph name="CURRENT_TIME">$3<ex>Monday, July 18th, 2012 12:31PM</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page.
       </message>
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
           You attempted to reach &lt;strong&gt;<ph
 name="DOMAIN">$1<ex>paypal.com</ex></ph>&lt;/strong&gt;, but the server presented a certificate issued by an entity that is not trusted by Chromium. This may mean that the server has generated its own security credentials, which Chromium cannot rely on for identity information, or an attacker may be trying to intercept your communications.
         </message>
       </if>
-      <if expr="not pp_ifdef('ios')">
+      <if expr="not is_ios">
         <message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
           You attempted to reach &lt;strong&gt;<ph name="DOMAIN">$1<ex>paypal.com</ex></ph>&lt;/strong&gt;, but the server presented a certificate issued by an entity that is not trusted by your computer's operating system. This may mean that the server has generated its own security credentials, which Chromium cannot rely on for identity information, or an attacker may be trying to intercept your communications.
         </message>
@@ -393,13 +393,13 @@
           Get Started with Chromium OS
         </message>
       </if>
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE"
                  desc="Title for the hard-coded thumbnail that represents the Google Chrome Welcome page.  This is used on the NTP when there aren't enough thumbnails to show. [Length: 14em]">
           Welcome
         </message>
       </if>
-      <if expr="not pp_ifdef('chromeos') and not pp_ifdef('ios')">
+      <if expr="not pp_ifdef('chromeos') and not is_ios">
         <message name="IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE"
                  desc="Title for the hard-coded thumbnail that represents the Google Chrome Welcome page.  This is used on the NTP when there aren't enough thumbnails to show.">
           Welcome to Chromium
@@ -671,7 +671,7 @@
       </message>
 
       <!-- "Create application shortcuts" dialog -->
-      <if expr="is_posix and not is_macosx">
+      <if expr="is_posix and not is_macosx and not is_ios">
         <message name="IDS_CREATE_SHORTCUTS_ERROR_LABEL" desc="Contents of the main label in the error dialog box when creating an application shortcut failed for unknown reasons.">
           Chromium could not create an application shortcut.
         </message>
@@ -766,7 +766,7 @@
       </if>
 
       <!-- iOS Upgrade available info bar-->
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_UPGRADE_AVAILABLE" desc="Text to inform the user of the presence of a new version of the application">
           Chromium just got better! A new version is available.
         </message>
@@ -856,10 +856,10 @@
       <if expr="not pp_ifdef('chromeos')">
         <!-- New one-click signin dialog contents for SAML support -->
         <message name="IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW" desc="The title of the modal dialog window that opens when the user chooses to use one click sign in.">
-          Sign in to Chromium with <ph name="USER_EMAIL_ADDRESS">$1<ex>foo@gmail.com</ex></ph>?
+          You're signed in to Chromium!
         </message>
         <message name="IDS_ONE_CLICK_SIGNIN_DIALOG_MESSAGE_NEW" desc="The message of the one click sign in dialog.">
-          You're signing in to Chromium using your <ph name="USER_EMAIL_ADDRESS">$1<ex>foo@gmail.com</ex></ph> account. You will be able to access your bookmarks, history, and other settings on all of your signed in devices.
+          You're signed in as <ph name="USER_EMAIL_ADDRESS">$1<ex>foo@gmail.com</ex></ph>. Now you can access your bookmarks, history, and other settings on all your signed in devices.
         </message>
         <message name="IDS_ONE_CLICK_SIGNIN_BUBBLE_MESSAGE" desc="The body of the sync promo NTP bubble.">
           You're now signed in to Chromium! Your bookmarks, history, and other settings will be synced to your Google Account.
@@ -903,6 +903,13 @@
         You are signing in with a managed account and giving its administrator control over your Chromium profile. Your Chromium data, such as your apps, bookmarks, history, passwords, and other settings will become permanently tied to <ph name="USER_NAME">$1<ex>pat@example.com</ex></ph>. You will be able to delete this data via the Google Accounts Dashboard, but you will not be able to associate this data with another account. You can optionally create a new profile to keep your existing Chromium data separate. <ph name="LEARN_MORE">$2<ex>Learn more</ex></ph>
       </message>
 
+      <message name="IDS_OPTIONS_PASSWORDS_MAC_WARNING" desc="The warning for OS X that passwords are shared across profiles in the keychain.">
+        On Mac, passwords are saved to your Keychain and may be accessed or synced by other Chromium users sharing this OS X account.
+      </message>
+
+      <message name="IDS_AUTOFILL_CC_INFOBAR_TEXT" desc="Text to show in the Autofill credit card request infobar.">
+        Do you want Chromium to save this credit card information for completing web forms?
+      </message>
       <message name="IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX" desc="Checkbox that controls whether info the user types into the autofill dialog is saved by chrome.">
         Save details in Chromium
       </message>
@@ -912,6 +919,9 @@
       <message name="IDS_AUTOFILL_NEW_CREDIT_CARD_BUBBLE_TITLE" desc="Title text of the new credit card bubble informing a user their billing information has been saved in chrome.">
         Your billing details have been saved in Chromium.
       </message>
+      <message name="IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR" desc="Text explaining that user must upgrade Chrome to use Wallet.">
+        You must upgrade Chromium to use Google Wallet [<ph name="ERROR_CODE">$1<ex>54</ex></ph>].
+      </message>
 
       <!-- Network Error Pages -->
       <message name="IDS_ERRORPAGES_SUGGESTION_NETWORK_PREDICTION_BODY" desc="When a page fails to load, sometimes we suggest disabling predicting network actions.  These are details below a header.">
@@ -928,18 +938,18 @@
         Allow Chromium to access the network in your firewall or antivirus
         settings.
       </message>
-      <if expr="is_macosx and not pp_ifdef('ios')">
+      <if expr="is_macosx">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Mac OSX instructions for disabling use of a proxy server.">
           Go to
           Applications &gt; System Preferences &gt; Network &gt; Advanced &gt; Proxies
           and deselect any proxies that have been selected.
         </message>
       </if>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Instructions for disabling use of a proxy server (leave empty for Android and iOS).">
         </message>
       </if>
-      <if expr="not pp_ifdef('chromeos') and is_posix and not is_macosx and not is_android and not pp_ifdef('ios')">
+      <if expr="not pp_ifdef('chromeos') and is_posix and not is_macosx and not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Linux instructions for disabling use of a proxy server.">
           Go to
           the Chromium menu &gt;
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 381f484..43b728b 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -84,11 +84,11 @@
          be 'nb'. -->
     <output filename="generated_resources_nb.pak" type="data_package" lang="no" />
     <output filename="generated_resources_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="generated_resources_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="generated_resources_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="generated_resources_pt-PT.pak" type="data_package" lang="pt-PT" />
@@ -2309,12 +2309,12 @@
       <message name="IDS_CERT_ERROR_EXTRA_INFO_TITLE" desc="The title for the extra information section displayed when a page contains a certificate error">
         Help me understand
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_CERT_ERROR_EXTRA_INFO_1" desc="Mobile: 1st paragraph of extra information for any certificate error">
           When you connect to a secure website, the server hosting that site presents your browser with something called a "certificate" to verify its identity. This certificate contains identity information, such as the address of the website, which is verified by a third party that your device trusts. By checking that the address in the certificate matches the address of the website, it is possible to verify that you are securely communicating with the website you intended, and not a third party (such as an attacker on your network).
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_CERT_ERROR_EXTRA_INFO_1" desc="1st paragraph of extra information for any certificate error">
           When you connect to a secure website, the server hosting that site presents your browser with something called a "certificate" to verify its identity. This certificate contains identity information, such as the address of the website, which is verified by a third party that your computer trusts. By checking that the address in the certificate matches the address of the website, it is possible to verify that you are securely communicating with the website you intended, and not a third party (such as an attacker on your network).
         </message>
@@ -2352,7 +2352,7 @@
       <message name="IDS_CERT_ERROR_AUTHORITY_INVALID_TITLE" desc="Title for an X509 certificate with an invalid authority">
         The site's security certificate is not trusted!
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_CERT_ERROR_AUTHORITY_INVALID_EXTRA_INFO_2" desc="Mobile: 2nd paragraph of extra information for a X509 certificate with an invalid authority">
           In this case, the certificate has not been verified by a third party that your device trusts. Anyone can create a certificate claiming to be whatever website they choose, which is why it must be verified by a trusted third party. Without that verification, the identity information in the certificate is meaningless. It is therefore not possible to verify that you are communicating with <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph> instead of an attacker who generated his own certificate claiming to be <ph name="DOMAIN2">&lt;strong&gt;$2<ex>paypal.com</ex>&lt;/strong&gt;</ph>. You should not proceed past this point.
         </message>
@@ -2362,7 +2362,7 @@
           If, however, you work in an organization that generates its own certificates, and you are trying to connect to an internal website of that organization using such a certificate, you may be able to solve this problem securely. You can import your organization's root certificate as a "root certificate", and then certificates issued or verified by your organization will be trusted and you will not see this error next time you try to connect to an internal website. Contact your organization's help staff for assistance in adding a new root certificate to your device.
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_CERT_ERROR_AUTHORITY_INVALID_EXTRA_INFO_2" desc="2nd paragraph of extra information for a X509 certificate with an invalid authority">
           In this case, the certificate has not been verified by a third party that your computer trusts. Anyone can create a certificate claiming to be whatever website they choose, which is why it must be verified by a trusted third party. Without that verification, the identity information in the certificate is meaningless. It is therefore not possible to verify that you are communicating with <ph name="DOMAIN">&lt;strong&gt;$1<ex>paypal.com</ex>&lt;/strong&gt;</ph> instead of an attacker who generated his own certificate claiming to be <ph name="DOMAIN2">&lt;strong&gt;$2<ex>paypal.com</ex>&lt;/strong&gt;</ph>. You should not proceed past this point.
         </message>
@@ -4198,6 +4198,12 @@
       <message name="IDS_EXTENSION_PROMPT_WARNING_NETWORKING_PRIVATE" desc="Permission string for Networking Private API.">
         Manage network connections
       </message>
+      <message name="IDS_EXTENSION_PROMPT_WARNING_DESKTOP_CAPTURE" desc="Permission string for Desktop Capture API.">
+        Capture content of your screen
+      </message>
+      <message name="IDS_EXTENSION_PROMPT_WARNING_DECLARATIVE_WEB_REQUEST" desc="Permission string for Declarative Web Request API.">
+        Block parts of web pages
+      </message>
 
       <!-- Extension/App error messages -->
       <message name="IDS_EXTENSION_CANT_GET_ABSOLUTE_PATH" desc="Warning displayed in pack dialog when the absolute path to the extension directory can not be found.">
@@ -4477,7 +4483,7 @@
         Update
       </message>
       <message name="IDS_APPS_DEVTOOL_SEARCH" desc="Placeholder text that appears inside the search box until the user inputs data.">
-        Search
+        search
       </message>
       <message name="IDS_APPS_DEVTOOL_APPS_INSTALLED" desc="Text for the word 'Apps'.">
         Apps
@@ -4536,6 +4542,9 @@
       <message name="IDS_EXTENSIONS_VIEW_INACTIVE" desc="Text that signifies that the extension view is an inactive transient page.">
         (Inactive)
       </message>
+      <message name="IDS_EXTENSIONS_BACKGROUND_PAGE" desc="Display name for an autogenerated background page.">
+        background page
+      </message>
       <message name="IDS_EXTENSIONS_ID" desc="The ID label in front of the extension ID.">
         ID:
       </message>
@@ -4588,6 +4597,16 @@
           Reload (Ctrl+R)
         </message>
       </if>
+      <if expr="is_macosx">
+        <message name="IDS_APPS_DEV_TOOLS_RELOAD_UNPACKED" desc="The link for reloading unpacked apps/extensions.">
+          Reload
+        </message>
+      </if>
+      <if expr="not is_macosx">
+        <message name="IDS_APPS_DEV_TOOLS_RELOAD_UNPACKED" desc="The link for reloading unpacked apps/extensions.">
+          Reload
+        </message>
+      </if>
       <message name="IDS_EXTENSIONS_OPTIONS_LINK" desc="The link text for the Options link.">
         Options
       </message>
@@ -4640,7 +4659,7 @@
         Extensions cannot be modified by supervised users.
       </message>
       <message name="IDS_EXTENSIONS_USE_APPS_DEV_TOOLS" desc="The message in the banner to invite people to use Apps Developer Tools.">
-        The new Apps Developer Tools makes it easier than ever to manage and debug your apps and extensions. It's also been added to the application list.
+        The new Apps Developer Tools makes it easier than ever to manage and debug your apps and extensions. It's now available in the Chrome App Launcher.
       </message>
       <message name="IDS_EXTENSIONS_OPEN_APPS_DEV_TOOLS" desc="The text of the button to open Apps Developer Tools in the banner to invite people to use Apps Developer Tools.">
         Open
@@ -4675,15 +4694,24 @@
       <message name="IDS_EXTENSION_PACK_DIALOG_TITLE" desc="Title of pack extension dialog">
         Pack Extension
       </message>
+      <message name="IDS_EXTENSION_PACK_APP_DIALOG_TITLE" desc="Title of pack application dialog">
+        Pack Application
+      </message>
       <message name="IDS_EXTENSION_PACK_BUTTON" desc="Text of the pack extension button">
         Pack Extension
       </message>
+      <message name="IDS_EXTENSION_ADT_PACK_BUTTON" desc="Text of the pack button in apps developer tool.">
+        Pack
+      </message>
       <message name="IDS_EXTENSION_PACK_DIALOG_HEADING" desc="The heading of the pack extension dialog.">
         Select the root directory of the extension to pack. To update an extension, also select the private key file to reuse.
       </message>
       <message name="IDS_EXTENSION_ADT_PACK_DIALOG_HEADING" desc="The heading of the pack extension dialog in the Apps Developer Tool.">
         The packed extension and the private key will be written in the parent directory of the root directory of the extension to pack. To update an extension, select the private key file to reuse.
       </message>
+      <message name="IDS_EXTENSION_ADT_PACK_APP_DIALOG_HEADING" desc="The heading of the pack application dialog in the Apps Developer Tool.">
+        The packed application and the private key will be written in the parent directory of the root directory of the application to pack. To update an application, select the private key file to reuse.
+      </message>
       <message name="IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL" desc="Label in the pack extension dialog for the control that lets the user select the extension to pack.">
         Extension root directory:
       </message>
@@ -4859,6 +4887,23 @@
         </message>
       </if>
 
+      <!-- Components -->
+      <message name="IDS_COMPONENTS_TITLE" desc="Title for the chrome://components page.">
+        Components
+      </message>
+      <message name="IDS_COMPONENTS_VERSION" desc="The label in front of a component version number.">
+        Version:
+      </message>
+      <message name="IDS_COMPONENTS_NONE_INSTALLED" desc="Text that lets the user know that no components are installed.">
+        No components installed.
+      </message>
+      <message name="IDS_COMPONENTS_NO_COMPONENTS" desc="Text that indicates that no components are installed">
+        No components are installed
+      </message>
+      <message name="IDS_COMPONENTS_CHECK_FOR_UPDATE" desc="The button label for triggering update check.">
+        Check for update
+      </message>
+
       <!-- Plugins -->
       <message name="IDS_PLUGINS_TITLE" desc="Title for the chrome://plugins page.">
         Plug-ins
@@ -5326,10 +5371,10 @@
       <message name="IDS_NACL_DEBUG_MASK_CHOICE_EXCLUDE_UTILS">
         Debug everything except secure shell
       </message>
-      <message name="IDS_FLAGS_ENABLE_PNACL_NAME" desc="Name of the 'Enable Portable Native Client' lab.">
+      <message name="IDS_FLAGS_PNACL_NAME" desc="Name of the 'Portable Native Client' lab.">
         Portable Native Client.
       </message>
-      <message name="IDS_FLAGS_ENABLE_PNACL_DESCRIPTION" desc="Description of the 'Enable Portable Native Client' lab.">
+      <message name="IDS_FLAGS_PNACL_DESCRIPTION" desc="Description of the 'Portable Native Client' lab.">
         Enable support for Portable Native Client.
       </message>
       <message name="IDS_FLAGS_SAVE_PAGE_AS_MHTML_NAME" desc="Name of the 'Save Page as MHTML' lab.">
@@ -5356,6 +5401,14 @@
       <message name="IDS_FLAGS_ENABLE_SCROLL_PREDICTION_DESCRIPTION" desc="Description of the flag to enable scroll prediction.">
         Predicts the finger's future position during scrolls allowing time to render the frame before the finger is there.
       </message>
+      <if expr="is_android">
+        <message name="IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_NAME" desc="Name of the flag to enable the accessibility tab switcher.">
+          Enable Accessibility Tab Switcher.
+        </message>
+        <message name="IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_DESCRIPTION" desc="Description of the flag to enable the accessibility tab switcher.">
+          Enable the accessibility tab switcher for Android.
+        </message>
+      </if>
       <message name="IDS_TOUCH_EVENTS_NAME" desc="Title of the touch-events flag." >
         Enable touch events
       </message>
@@ -5519,6 +5572,12 @@
       <message name="IDS_FLAGS_ENABLE_APP_WINDOW_CONTROLS_DESCRIPTION" desc="Description of the 'Enable 'window-controls' element' lab.">
         Enables using 'window-controls' HTML elements in packaged apps.
       </message>
+      <message name="IDS_FLAGS_ENABLE_BATCHED_SHUTDOWN_DESCRIPTION" desc="Description of the 'Batched shutdown' lab.">
+        Enabling this options delays closing browser windows during shutdown until the shutdown is no longer cancellable.
+      </message>
+      <message name="IDS_FLAGS_ENABLE_BATCHED_SHUTDOWN_NAME" desc="Name of the 'Batched shutdown' lab.">
+        Enable batched browser shutdown
+      </message>
       <message name="IDS_FLAGS_SCRIPT_BADGES_NAME" desc="Name of the 'Script Badges' lab.">
         Script badges
       </message>
@@ -5592,6 +5651,12 @@
       <message name="IDS_FLAGS_ENABLE_NEW_NTP_DESCRIPTION" desc="Description for the flag to enable the new NTP.">
         Whether or not the new style New Tab Page is enabled.
       </message>
+      <message name="IDS_FLAGS_ENABLE_NO_TOUCH_TO_RENDERER_WHILE_SCROLLING_NAME" desc="Name of the flag that enables not sending touch events to renderer while scrolling.">
+        Enable not sending touch events to renderer while scrolling
+      </message>
+      <message name="IDS_FLAGS_ENABLE_NO_TOUCH_TO_RENDERER_WHILE_SCROLLING_DESCRIPTION" desc="Description of the flag to enable not sending touch events to renderer while scrolling.">
+        Enable not sending touch events to renderer while scrolling.
+      </message>
       <message name="IDS_FLAGS_ENABLE_GESTURE_TAP_HIGHLIGHTING_NAME" desc="Title for the flag to turn on gesture tap highlighting">
         Gesture Tap Highlighting
       </message>
@@ -5915,12 +5980,6 @@
       <message name="IDS_FLAGS_ASH_AUTO_MAXIMIZING_DESCRIPTION" desc="Description for the option to disable the auto window maximizing functionality.">
         Disable automatic window maximization for browser / app windows if they are started the first time.
       </message>
-      <message name="IDS_FLAGS_ASH_DISABLE_PER_APP_LAUNCHER_NAME" desc="Name for the option to enable/disable the per application sorting launcher functionality.">
-        Disable per application sorting in the launcher.
-      </message>
-      <message name="IDS_FLAGS_ASH_DISABLE_PER_APP_LAUNCHER_DESCRIPTION" desc="Description for the option to enable/disable the per application sorting launcher functionality.">
-        Disable the per application sorting mode of the launcher.
-      </message>
       <message name="IDS_FLAGS_DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_NAME" desc="Title for the flag to disable gesture requiment for media playback">
         Disable gesture requirement for media playback.
       </message>
@@ -6440,6 +6499,12 @@
       <message name="IDS_FLAGS_ENABLE_DEVICE_MOTION_DESCRIPTION" desc="Description for the flag to enable device motion.">
         Enables device motion DOM events in JavaScript.
       </message>
+      <message name="IDS_FLAGS_DISABLE_USER_IMAGE_SYNC_NAME" desc="Name of the flag to disable sync of user account image.">
+        Disable avatar sync.
+      </message>
+      <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>
 
       <!-- Crashes -->
       <message name="IDS_CRASHES_TITLE" desc="Title for the chrome://crashes page.">
@@ -6952,7 +7017,7 @@
       <message name="IDS_OMNIBOX_KEYWORD_TEXT" desc="Text shown in the search button at the front of the omnibox when the user has selected a keyword">
         Search <ph name="SITE_NAME">$1<ex>google.com</ex></ph>:
       </message>
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_OMNIBOX_EMPTY_HINT" desc="The text displayed in the omnibox when it is empty.">
           Search or type URL
         </message>
@@ -7104,7 +7169,7 @@
       <message name="IDS_ACCNAME_WEB_CONTENTS" desc="The accessible name for the web contents.">
         Web Contents
       </message>
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_ACCNAME_CLEAR_TEXT" desc="The accessibility label for the clear text button in the location bar [Length: unlimited].">
           Clear Text
         </message>
@@ -7317,59 +7382,30 @@
         Skip Import
       </message>
 
-      <!-- Report Bug or Broken Website Dialog -->
-      <message name="IDS_FEEDBACK_TITLE" desc="Dialog title for bug report dialog">
-        Whoops. Let's fix that.
-      </message>
+      <!-- Feedback Dialog -->
       <message name="IDS_FEEDBACK_REPORT_PAGE_TITLE" desc="Label showing the title of the page that will be reported">
-        Feedback
+        Tell us what is happening.
       </message>
       <message name="IDS_FEEDBACK_REPORT_URL_LABEL" desc="Label showing the URL that will be reported">
-        Include this URL:
+        URL (optional):
       </message>
       <message name="IDS_FEEDBACK_USER_EMAIL_LABEL" desc="Label showing the e-mail address that will be reported">
-        Include this email:
+        Email (optional):
       </message>
-      <message name="IDS_FEEDBACK_DESCRIPTION_LABEL" desc="Label for the description field">
-        Tell us what is happening. (required)
-      </message>
-      <if expr="pp_ifdef('chromeos')">
-      <message name="IDS_FEEDBACK_SCREENSHOT_LABEL" desc="Label for the screenshot field if current screenshots are being shown">
-        Include the current screenshot:
-      </message>
-      </if>
-      <if expr="not pp_ifdef('chromeos')">
       <message name="IDS_FEEDBACK_SCREENSHOT_LABEL" desc="Label for the screenshot field if current screenshots are being shown">
         Include this screenshot:
       </message>
-      </if>
-      <message name="IDS_FEEDBACK_SAVED_SCREENSHOT_LABEL" desc="Label for the screenshot field if saved screenshots are being shown">
-        Include a saved screenshot:
-      </message>
-      <message name="IDS_FEEDBACK_CURRENT_SCREENSHOTS" desc="Radio button for including the last screen image on the bug report dialog box">
-        Send a current page screen shot
-      </message>
-      <message name="IDS_FEEDBACK_SAVED_SCREENSHOTS" desc="Radio button for including the last screen image on the bug report dialog box">
-        Send a saved screen shot
-      </message>
       <message name="IDS_FEEDBACK_INCLUDE_PERFORMANCE_TRACE_CHECKBOX" desc="Checkbox for including system information on the bug report dialog box">
         Send performance trace data
       </message>
       <message name="IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_CHKBOX" desc="Checkbox for including system information on the bug report dialog box">
         Send system information
       </message>
-      <message name="IDS_FEEDBACK_CHOOSE_DIFFERENT_SCREENSHOT" desc="Text for changing the screenshot selection from current to saved">
-        (Choose a different screenshot)
-      </message>
-      <message name="IDS_FEEDBACK_CHOOSE_ORIGINAL_SCREENSHOT" desc="Text for changing the screenshot selection from saved to current">
-        (Go back to original screenshot)
-      </message>
       <message name="IDS_FEEDBACK_ATTACH_FILE_NOTE" desc="Text for describing the maximum size for an attached file">
-        The attached file is uploaded to Google servers for debugging.&lt;br&gt;
-        Note: You can attach one file per feedback report (3 MB limit)
+        The attached file is uploaded to Google servers for debugging.
       </message>
       <message name="IDS_FEEDBACK_ATTACH_FILE_LABEL" desc="Text for the label for the attached filename">
-        Include this file:
+        Attach file:
       </message>
       <message name="IDS_FEEDBACK_READING_FILE" desc="Text to display if reading a file when the user clicks the send report button">
         Reading file..
@@ -7387,18 +7423,9 @@
         that you provide to improve any Google product or service.
         <ph name="END_BOLD">&lt;/strong&gt;</ph>
       </message>
-      <message name="IDS_FEEDBACK_INCLUDE_NEW_SCREEN_IMAGE" desc="Radio button for including a new screen image on the bug report dialog box">
-        Send last active tab screen shot
-      </message>
-      <message name="IDS_FEEDBACK_INCLUDE_NO_SCREENSHOT" desc="Radio button for not including a screen image on the bug report dialog box">
-        Do not send a screen shot
-      </message>
       <message name="IDS_FEEDBACK_NO_DESCRIPTION" desc="Message shown when no text is entered before hitting send feedback">
         Please tell us what is happening before sending the feedback.
       </message>
-      <message name="IDS_FEEDBACK_NO_SAVED_SCREENSHOTS_HELP" desc="Message shown when no screenshots are available for selection">
-        You can select saved screenshots from here. Currently there are no screenshots available. You can press Ctrl + the "Window Switch" key together to take a screenshot. The last three screenshots that you have taken will appear here.
-      </message>
       <message name="IDS_FEEDBACK_SEND_REPORT" desc="Text for OK button of the send feedback dialog">
         Send feedback
       </message>
@@ -8387,14 +8414,14 @@
       <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_HEADER" desc="When a webpage fails to load, in some cases we suggest checking the proxy server configuration, or disabling the proxy server.  This is a header above some details.">
         If you use a proxy server...
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_BODY" desc="When a webpage fails to load, in some cases we suggest checking the proxy server configuration, or disabling the proxy server.  These are instructions below a header.">
           Check your proxy settings or contact your network administrator to
           make sure the proxy server is working.
           <ph name="PLATFORM_TEXT">$1<ex>Goto the wrench menu and choose Fix It.</ex></ph>
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_CONFIG_BODY" desc="When a webpage fails to load, in some cases we suggest checking the proxy server configuration, or disabling the proxy server.  These are instructions below a header.">
           Check your proxy settings or contact your network administrator to
           make sure the proxy server is working. If you don't believe you should
@@ -8530,7 +8557,7 @@
       <message name="IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED" desc="Summary in the error page when we can't open a file.">
         The file at <ph name="URL">&lt;strong jscontent="failedUrl"&gt;&lt;/strong&gt;<ex>http://www.google.com/</ex></ph> is not readable.  It may have been removed, moved, or file permissions may be preventing access.
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_NETWORK_ACCESS_DENIED" desc="Mobile: Summary in the error page when we're not being allowed to access the network.">
           <ph name="PRODUCT_NAME">&lt;span jscontent="productName"&gt;&lt;/span&gt;<ex>Google Chrome</ex></ph>
           is having trouble accessing the network.
@@ -8551,7 +8578,7 @@
           The page can be loaded once you connect to a network.
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_NETWORK_ACCESS_DENIED" desc="Summary in the error page when we're not being allowed to access the network.">
           <ph name="PRODUCT_NAME">&lt;span jscontent="productName"&gt;&lt;/span&gt;<ex>Google Chrome</ex></ph>
           is having trouble accessing the network.
@@ -8640,7 +8667,7 @@
         If the problem persists, try clearing the cache.  In some cases, this
         can also be a symptom of hardware starting to fail.
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_NETWORK_IO_SUSPENDED" desc="Mobile: Summary in the error page when a page load failed due to the device entering sleep/suspend mode.">
           Unable to load the webpage because your device entered sleep or
           hibernate mode.  When this happens, network connections are shut
@@ -8648,7 +8675,7 @@
           resolve this.
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_NETWORK_IO_SUSPENDED" desc="Summary in the error page when a page load failed due to the computer entering sleep/suspend mode.">
           Unable to load the webpage because your computer entered sleep or
           hibernate mode.  When this happens, network connections are shut
@@ -8659,7 +8686,7 @@
       <message name="IDS_ERRORPAGES_SUMMARY_NOT_FOUND" desc="Summary in the error page when the server returns a 404.">
         No webpage was found for the web address: <ph name="URL">&lt;strong jscontent="failedUrl"&gt;&lt;/strong&gt;</ph>
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS" desc="Mobile: Summary in the error page when there are too many URL redirects.">
           The webpage at <ph name="URL">&lt;strong jscontent="failedUrl"&gt;&lt;/strong&gt;</ph> has resulted in
           too many redirects.  Clearing your cookies for this site or allowing third-party cookies may fix the problem.  If
@@ -8667,7 +8694,7 @@
           device.
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS" desc="Summary in the error page when there are too many URL redirects.">
           The webpage at <ph name="URL">&lt;strong jscontent="failedUrl"&gt;&lt;/strong&gt;</ph> has resulted in
           too many redirects.  Clearing your cookies for this site or allowing third-party cookies may fix the problem.  If
@@ -8916,7 +8943,7 @@
       </message>
 
       <!-- iOS specific error page messages -->
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_ERRORPAGES_HEADING_DOWNLOAD_FILE_TYPE_ERROR" desc="A one-line title for error message to tell user that the requested type of file cannot be downloaded. [Length: 20em]">
           Download Failed
         </message>
@@ -9019,7 +9046,7 @@
       <message name="IDS_PAGE_INFO_SITE_INFO_TITLE" desc="The name of the site information section.">
         Site information
       </message>
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_PAGE_INFO_SECURITY_BUTTON_ACCESSIBILITY_LABEL" desc="The accessibility text for the page security info button">
           Page Security Info
         </message>
@@ -9673,15 +9700,9 @@
       <message name="IDS_OPTIONS_PASSWORDS_MANAGE_PASSWORDS" desc="The label of the 'Manage saved passwords' button">
         Manage saved passwords...
       </message>
-      <message name="IDS_OPTIONS_PASSWORDS_MAC_WARNING" desc="The warning for OS X that passwords are shared across profiles in the keychain.">
-          On Mac, passwords are saved to your Keychain and may be accessed or synced by other Chrome users sharing this OS X account.
-      </message>
       <message name="IDS_OPTIONS_PASSWORDS_AUTOLOGIN" desc="The label of the 'autologinEnabled' checkbox">
         Offer to sign into Google sites automatically with this account
       </message>
-      <message name="IDS_AUTOFILL_CC_INFOBAR_TEXT" desc="Text to show in the Autofill credit card request infobar.">
-        Do you want Chrome to save this credit card information for completing web forms?
-      </message>
       <message name="IDS_OPTIONS_AUTOFILL_ENABLE" desc="The label of the 'Ask me to enable Autofill' radio button">
         Enable Autofill to fill out web forms in a single click.
       </message>
@@ -9697,6 +9718,9 @@
       <message name="IDS_OPTIONS_MANAGE_AUTOFILL_SETTINGS_LINK" desc="The label of the 'Manage Autofill settings' link">
         Manage Autofill settings
       </message>
+      <message name="IDS_AUTOFILL_HELP_LABEL" desc="The label of the Help link in the Autofill settings overlay.">
+        About Autofill
+      </message>
       <message name="IDS_AUTOFILL_ADD_ADDRESS_BUTTON" desc="The label of the button that adds a new Autofill address.">
         Add new street address...
       </message>
@@ -9818,10 +9842,6 @@
         Phone number
       </message>
 
-      <message name="IDS_AUTOFILL_HELP_LABEL" desc="The label of the Help link on the Autofill dialog.">
-        About Autofill
-      </message>
-
       <!-- Autofill dialog: title bar -->
       <message name="IDS_AUTOFILL_DIALOG_TITLE" desc="Title for autofill dialog which asks user to input address + payment info.">
         Pay
@@ -9907,9 +9927,6 @@
       <message name="IDS_AUTOFILL_WALLET_UNSUPPORTED_MERCHANT" desc="Text explaining that the merchant is blacklisted for Google Wallet Chrome Payments due to compliance violation.">
         lorem ipsum - unsupported_merchant.
       </message>
-      <message name="IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR" desc="Text explaining that user must upgrade Chrome to use Wallet.">
-        You must upgrade Chrome to use Google Wallet [<ph name="ERROR_CODE">$1<ex>54</ex></ph>].
-      </message>
       <message name="IDS_AUTOFILL_WALLET_SERVICE_UNAVAILABLE_ERROR" desc="Text explaining that Wallet is currently unavailable.">
         Google Wallet is currently unavailable [61].
       </message>
@@ -10114,7 +10131,7 @@
       <message name="IDS_THEMES_RESET_BUTTON" desc="The button to reset your theme">
         Reset to default theme
       </message>
-      <if expr="is_posix and not is_macosx">
+      <if expr="is_posix and not is_macosx and not is_ios">
         <message name="IDS_THEMES_GTK_BUTTON" desc="The button to choose GTK colors and icons as the current theme.">
           Use GTK+ theme
         </message>
@@ -10129,12 +10146,12 @@
         Get themes
       </message>
 
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_OPTIONS_SYSTEM_PROXIES_LABEL" desc="Mobile: The info label for the 'Proxy settings' button when managed by the system.">
           <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is using your device's system proxy settings to connect to the network.
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_OPTIONS_SYSTEM_PROXIES_LABEL" desc="The info label for the 'Proxy settings' button when managed by the system.">
           <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> is using your computer's system proxy settings to connect to the network.
         </message>
@@ -10328,7 +10345,7 @@
       </message>
 
       <!-- Auto-login infobar -->
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_AUTOLOGIN_INFOBAR_MESSAGE" desc="The string shown in the infobar explaining that they can press one button to auto-login instead of entering their user name and password. [length: 60em]">
           Automatic sign-in is available <ph name="EMAIL_ADDRESS">$1</ph>
         </message>
@@ -10336,7 +10353,7 @@
           Login
         </message>
       </if>
-      <if expr="not pp_ifdef('ios')">
+      <if expr="not is_ios">
         <message name="IDS_AUTOLOGIN_INFOBAR_MESSAGE" desc="The string shown in the infobar explaining that they can press one button to auto-login instead of entering their user name and password.">
           Sign in to this site as: <ph name="EMAIL_ADDRESS">$1</ph>
         </message>
@@ -10344,12 +10361,12 @@
           Sign in
         </message>
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <message name="IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON" desc="The string used in the infobar button that the user presses to never see this infobar again.">
           Never offer to sign me in
         </message>
       </if>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON" desc="Mobile: The string used in the autologin infobar button that the user presses to close the infobar without logging in.">
           Cancel
         </message>
@@ -12048,7 +12065,7 @@
         Remove shortcut
       </message>
       <message name="IDS_FILE_BROWSER_SHORTCUT_TARGET_UNAVAILABLE" desc="The message which is shown when the user selects a shortcut to a missing folder and ask whether to remove said shortcut.">
-        The folder referred by this shortcut has been changed or deleted. Do you want to remove it?
+        This folder shortcut has been modified and no longer works. Do you want to remove it?
       </message>
       <message name="IDS_FILE_BROWSER_SHARE_BUTTON_LABEL" desc="Menu item label, showing dialog to share the selected file.">
         Share
@@ -12997,7 +13014,7 @@
           Sign in again...
         </message>
         <message name="IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM" desc="The sync error wrench menu item when the user needs to sign in again.">
-            Sync Error: Sign in again...
+            Sign in again...
         </message>
       </if>
       <if expr="not pp_ifdef('use_titlecase') and pp_ifdef('chromeos')">
@@ -13005,7 +13022,7 @@
           Sign out then sign in again...
         </message>
         <message name="IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM" desc="The sync error wrench menu item when the user needs to sign out and sign in again to Chrome OS.">
-          Sync Error: Sign out then sign in again...
+          Sign out then sign in again...
         </message>
       </if>
 
@@ -13025,7 +13042,7 @@
           Sign in Again...
         </message>
         <message name="IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM" desc="The sync error wrench menu item when the user needs to sign in again.">
-          Sync Error: Sign in Again...
+          Sign in Again...
         </message>
       </if>
       <if expr="pp_ifdef('use_titlecase') and pp_ifdef('chromeos')">
@@ -13033,7 +13050,7 @@
           Sign out then Sign in Again...
         </message>
         <message name="IDS_SYNC_SIGN_IN_ERROR_WRENCH_MENU_ITEM" desc="The sync error wrench menu item when the user needs to sign out and sign in again to Chrome OS.">
-          Sync Error: Sign out then Sign in Again...
+          Sign out then Sign in Again...
         </message>
       </if>
 
@@ -13109,7 +13126,7 @@
       <message name="IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE" desc="Message that page is in specified language and ask if should translate">
         This page is in<ph name="original_language">$1<ex>French</ex></ph>Would you like to translate it?
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE_MOBILE" desc="Mobile: Message that page is in specified language and ask if should translate.">
           Translate from <ph name="original_language">$1<ex>French</ex></ph> to <ph name="target_language">$2<ex>English</ex></ph>?
         </message>
@@ -13135,7 +13152,7 @@
       <message name="IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_AUTODETERMINED_SOURCE_LANGUAGE" desc="Message that page has been translated to another with server side auto language detection">
         This page has been translated to <ph name="target_language">$1<ex>German</ex></ph>
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
       <message name="IDS_TRANSLATE_INFOBAR_AFTER_MESSAGE_MOBILE" desc="Mobile: Message that page has been translated from one language to another">
         This page has been translated to <ph name="target_language">$1<ex>German</ex></ph>
       </message>
@@ -13161,7 +13178,7 @@
       <message name="IDS_TRANSLATE_INFOBAR_UNSUPPORTED_PAGE_LANGUAGE" desc="Error message shown when the translate server translated the page and returned the page was in a language the browser does not know.">
         This page has been translated from an unknown language to <ph name="language_language">$1<ex>English</ex></ph>
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
       <message name="IDS_TRANSLATE_INFOBAR_ERROR_MOBILE" desc="Mobile: Translate Error message">
         The translation to <ph name="target_language">$1<ex>German</ex></ph> failed.
       </message>
@@ -13255,7 +13272,7 @@
 
 
       <!-- Mac Menubar Menus -->
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <!-- Menubar Menu Titles -->
         <!-- NOTE: Some of these exist in context menus with Title Case support, but we use different IDs in case we need slightly different strings in some language due to the different context. -->
         <message name="IDS_FILE_MENU_MAC" desc="The menu title of the Mac file menu.">
@@ -13520,7 +13537,7 @@
       </if> <!-- is_macosx -->
 
       <!-- Linux Global Menubar Menus -->
-      <if expr="is_posix and not is_macosx">
+      <if expr="is_posix and not is_macosx and not is_ios">
         <!-- Unity and some other GNOME configurations now have a permanent,
              Mac-like menu bar that lives outside the window at the top of the
              screen. The following strings should be in Linux style, not Mac
@@ -13731,6 +13748,10 @@
       New camera and microphone settings will take effect after reloading the page.
     </message>
 
+    <message name="IDS_SAVE_PASSWORD" desc="The status text that is used as tooltip text for the save password icon and as status text of the save password bubble when a password can be saved.">
+      Would you like to save this password?
+    </message>
+
     <!-- ProcessSingleton -->
     <message name="IDS_PROFILE_IN_USE_LINUX" desc="Message shown when the browser cannot start because the profile is in use on a different host.">
       The profile appears to be in use by process <ph name="PROCESS_ID">$1<ex>12345</ex></ph> on host <ph name="HOST_NAME">$2<ex>example.com</ex></ph>.  If you are sure no other processes are using this profile, delete the file <ph name="LOCK_FILE">$3<ex>/home/user/.config/google-chrome/SingletonLock</ex></ph> and relaunch <ph name="PRODUCT_NAME">$4<ex>Google Chrome</ex></ph>.
@@ -13814,7 +13835,7 @@
       <part file="chromeos_strings.grdp" />
     </if>
 
-    <if expr="is_posix and not is_macosx">
+    <if expr="is_posix and not is_macosx and not is_ios">
       <!-- Linux proxy configuration fallback help -->
       <message name="IDS_ABOUT_LINUX_PROXY_CONFIG_TITLE" desc="Title of HTML page shown on systems where system proxy configuration is unsupported.">
         Proxy Configuration Help
@@ -14301,7 +14322,7 @@
       Switch to <ph name="NEW_PROFILE_NAME">$1<ex>New User</ex></ph>
     </message>
 
-    <if expr="not is_android and not pp_ifdef('ios') and not pp_ifdef('chromeos')">
+    <if expr="not is_android and not is_ios and not pp_ifdef('chromeos')">
       <!-- User manager web UI -->
       <if expr="pp_ifdef('use_titlecase')">
         <message name="IDS_ADD_USER_BUTTON" desc="Text shown on an add user button on login/locker screen">
@@ -14735,7 +14756,7 @@
     </if>
 
     <!-- iOS Chrome to Device strings-->
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <message name="IDS_CHROME_TO_DEVICE_PRINT_TO_PHONE" desc="The message indicating print-to-phone jobs are now available. [Length: 30em]">
         Your document is ready to view.
       </message>
@@ -14745,7 +14766,7 @@
     </if>
 
       <!-- iOS Net-Export strings -->
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_NET_EXPORT_NO_EMAIL_ACCOUNTS_ALERT_MESSAGE" desc="The message of the alert informing a user with no email accounts that he or she needs to configure an email account to send net-export data. [Length: 70em]">
           To send net-export data, please configure your email account in System Settings.
         </message>
@@ -14875,9 +14896,91 @@
       Screen
     </message>
 
-    </messages>
+    <!-- About network UI display strings -->
+    <if expr="pp_ifdef('chromeos')">
+      <message name="IDS_NETWORK_TITLE" desc="Title of the page">
+        Network
+      </message>
+      <message name="IDS_NETWORK_AUTO_REFRESH" desc="A instruction of how to auto-refresh the page">
+        Add a query param in URL to auto-refresh the page: chrome://network/?refresh=&lt;sec&gt;
+      </message>
+      <message name="IDS_NETWORK_LOG_REFRESH" desc="Button to refresh network log">
+        Refresh
+      </message>
+      <message name="IDS_NETWORK_LOG_LEVEL_SHOW" desc="'Show' label before logging level checkboxes">
+        Show:
+      </message>
+      <message name="IDS_NETWORK_LOG_LEVEL_ERROR" desc="Error logging level checkbox">
+        Error
+      </message>
+      <message name="IDS_NETWORK_LOG_LEVEL_USER" desc="User logging level checkbox">
+        User
+      </message>
+      <message name="IDS_NETWORK_LOG_LEVEL_EVENT" desc="Event logging level checkbox">
+        Event
+      </message>
+      <message name="IDS_NETWORK_LOG_LEVEL_DEBUG" desc="Debug logging level checkbox">
+        Debug
+      </message>
+      <message name="IDS_NETWORK_LOG_ENTRY" desc="The log entry displayed in network event log table.">
+        [<ph name="TIMESTAMP">$1<ex>Timestamp</ex></ph>]
+        <ph name="EVENT_NAME">$2<ex>Event Name</ex></ph>
+        <ph name="DESCRIPTION">$3<ex>Description</ex></ph>
+      </message>
+    </if>
 
-    <structures fallback_to_english="true">
+    <!-- Local Device Discovery display strings -->
+    <message name="IDS_LOCAL_DISCOVERY_SERVICE_NAME" desc="Table header for service name">
+      Name
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_SERVICE_DOMAIN" desc="Table header for service domain">
+      Domain
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_SERVICE_PORT" desc="Table header for service port">
+      Port
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_SERVICE_IP" desc="Table header for IP">
+      IP
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_SERVICE_LASTSEEN" desc="Table header for when a service was last seen">
+      Last seen
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_SERVICE_REGISTER" desc="Table header for registering a service">
+      Register
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_REGISTERING_SERVICE" desc="Message to indicate a service is being registered">
+      Registering <ph name="DEVICE_NAME">$1</ph>...
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_REGISTRATION_FAILED" desc="Message to indicate service registration has failed">
+      Registration failed: <ph name="ERROR_STRING">$1</ph>.
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_REGISTRATION_SUCCEEDED" desc="Message to indicate service registration has succeeded">
+      Successfully registered device with ID <ph name="DEVICE_ID">$1</ph>.
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_REGISTERED" desc="Message to show that a listed service has already been registered">
+      Registered
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_INFO_STARTED" desc="Message to show that a listed service is being asked for info">
+      Info request started for <ph name="DEVICE_NAME">$1</ph>...
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_INFO_FAILED" desc="Message to show that an info request has failed">
+      Info request failed: <ph name="ERROR_STRING">$1</ph>...
+    </message>
+    <message name="IDS_LOCAL_DISCOVERY_SERVICE_INFO" desc="Table header and button for info requests">
+      Info
+    </message>
+    <message name="IDS_LOCAL_DISOCVERY_NOTIFICATION_TITLE_PRINTER" desc="Title of notification for a new printer showing up on your network">
+      New printer on your network
+    </message>
+    <message name="IDS_LOCAL_DISOCVERY_NOTIFICATION_CONTENTS_PRINTER" desc="Contents of notification for a new printer showing up on your network">
+      Add <ph name="PRINTER_NAME">$1</ph> to Cloud Print so you can print from anywhere.
+    </message>
+    <message name="IDS_LOCAL_DISOCVERY_NOTIFICATION_DISPLAY_SOURCE_PRINTER" desc="Display name for notification for a new printer showing up on your network">
+      Google Cloud Print
+    </message>
+  </messages>
+
+  <structures fallback_to_english="true">
       <!-- Make sure these stay in sync with the structures in generated_resources.grd. -->
       <structure name="IDD_CHROME_FRAME_FIND_DIALOG" file="cf_resources.rc" type="dialog" >
       </structure>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 10e8dc7..114568e 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -46,11 +46,11 @@
     <output filename="google_chrome_strings_nb.pak" type="data_package" lang="no" />
     <!-- 'no' for Norwegian Bokmål. It should be 'nb'. -->
     <output filename="google_chrome_strings_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="google_chrome_strings_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="google_chrome_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="google_chrome_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
@@ -213,13 +213,13 @@
       <message name="IDS_CERT_ERROR_NOT_YET_VALID_DETAILS" desc="Details for an X509 certificate that is not yet valid">
         You attempted to reach &lt;strong&gt;<ph name="DOMAIN">$1<ex>paypal.com</ex></ph>&lt;/strong&gt;, but the server presented a certificate that is not yet valid. No information is available to indicate whether that certificate can be trusted. Google Chrome cannot reliably guarantee that you are communicating with &lt;strong&gt;<ph name="DOMAIN2">$2<ex>paypal.com</ex></ph>&lt;/strong&gt; and not an attacker. Your computer's clock is currently set to <ph name="CURRENT_TIME">$3<ex>Monday, July 18th, 2012 12:31PM</ex></ph>. Does that look right? If not, you should correct your system's clock and then refresh this page.
       </message>
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
           You attempted to reach &lt;strong&gt;<ph
 name="DOMAIN">$1<ex>paypal.com</ex></ph>&lt;/strong&gt;, but the server presented a certificate issued by an entity that is not trusted by Google Chrome. This may mean that the server has generated its own security credentials, which Chrome cannot rely on for identity information, or an attacker may be trying to intercept your communications.
         </message>
       </if>
-      <if expr="not pp_ifdef('ios')">
+      <if expr="not is_ios">
         <message name="IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS" desc="Details for an X509 certificate with an invalid authority">
           You attempted to reach &lt;strong&gt;<ph name="DOMAIN">$1<ex>paypal.com</ex></ph>&lt;/strong&gt;, but the server presented a certificate issued by an entity that is not trusted by your computer's operating system. This may mean that the server has generated its own security credentials, which Chrome cannot rely on for identity information, or an attacker may be trying to intercept your communications.
         </message>
@@ -316,13 +316,13 @@
           Get Started with Chrome OS
         </message>
       </if>
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE"
                  desc="Title for the hard-coded thumbnail that represents the Google Chrome Welcome page.  This is used on the NTP when there aren't enough thumbnails to show. [Length: 14em]">
           Welcome
         </message>
       </if>
-      <if expr="not pp_ifdef('chromeos') and not pp_ifdef('ios')">
+      <if expr="not pp_ifdef('chromeos') and not is_ios">
         <message name="IDS_NEW_TAB_CHROME_WELCOME_PAGE_TITLE"
                  desc="Title for the hard-coded thumbnail that represents the Google Chrome OS Welcome page. This is used on the NTP when there aren't enough thumbnails to show.">
           Welcome to Google Chrome
@@ -595,7 +595,7 @@
       </message>
 
       <!-- "Create application shortcuts" dialog -->
-      <if expr="is_posix and not is_macosx">
+      <if expr="is_posix and not is_macosx and not is_ios">
         <message name="IDS_CREATE_SHORTCUTS_ERROR_LABEL" desc="Contents of the main label in the error dialog box when creating an application shortcut failed for unknown reasons.">
           Google Chrome could not create an application shortcut.
         </message>
@@ -690,7 +690,7 @@
       </if>
 
       <!-- iOS Upgrade available info bar-->
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_UPGRADE_AVAILABLE" desc="Text to inform the user of the presence of a new version of the application">
           Chrome just got better! A new version is available.
         </message>
@@ -780,10 +780,10 @@
       <if expr="not pp_ifdef('chromeos')">
         <!-- New one-click signin dialog contents for SAML support -->
         <message name="IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW" desc="The title of the modal dialog window that opens when the user chooses to use one click sign in.">
-          Sign in to Chrome with <ph name="USER_EMAIL_ADDRESS">$1<ex>foo@gmail.com</ex></ph>?
+          You're signed in to Chrome!
         </message>
         <message name="IDS_ONE_CLICK_SIGNIN_DIALOG_MESSAGE_NEW" desc="The message of the one click sign in dialog.">
-          You're signing in to Chrome using your <ph name="USER_EMAIL_ADDRESS">$1<ex>foo@gmail.com</ex></ph> account. You will be able to access your bookmarks, history, and other settings on all of your signed in devices.
+          You're signed in as <ph name="USER_EMAIL_ADDRESS">$1<ex>foo@gmail.com</ex></ph>. Now you can access your bookmarks, history, and other settings on all your signed in devices.
         </message>
         <message name="IDS_ONE_CLICK_SIGNIN_BUBBLE_MESSAGE" desc="The body of the sync promo NTP bubble.">
           You're now signed in to Chrome! Your bookmarks, history, and other settings will be synced to your Google Account.
@@ -827,6 +827,13 @@
         You are signing in with a managed account and giving its administrator control over your Google Chrome profile. Your Chrome data, such as your apps, bookmarks, history, passwords, and other settings will become permanently tied to <ph name="USER_NAME">$1<ex>pat@example.com</ex></ph>. You will be able to delete this data via the Google Accounts Dashboard, but you will not be able to associate this data with another account. You can optionally create a new profile to keep your existing Chrome data separate. <ph name="LEARN_MORE">$2<ex>Learn more</ex></ph>
       </message>
 
+      <message name="IDS_OPTIONS_PASSWORDS_MAC_WARNING" desc="The warning for OS X that passwords are shared across profiles in the keychain.">
+        On Mac, passwords are saved to your Keychain and may be accessed or synced by other Chrome users sharing this OS X account.
+      </message>
+
+      <message name="IDS_AUTOFILL_CC_INFOBAR_TEXT" desc="Text to show in the Autofill credit card request infobar.">
+        Do you want Chrome to save this credit card information for completing web forms?
+      </message>
       <message name="IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX" desc="Checkbox that controls whether info the user types into the autofill dialog is saved by chrome.">
         Save details in Chrome
       </message>
@@ -836,6 +843,9 @@
       <message name="IDS_AUTOFILL_NEW_CREDIT_CARD_BUBBLE_TITLE" desc="Title text of the new credit card bubble informing a user their billing information has been saved in chrome.">
         Your billing details have been saved in Chrome.
       </message>
+      <message name="IDS_AUTOFILL_WALLET_UPGRADE_CHROME_ERROR" desc="Text explaining that user must upgrade Chrome to use Wallet.">
+        You must upgrade Chrome to use Google Wallet [<ph name="ERROR_CODE">$1<ex>54</ex></ph>].
+      </message>
 
       <!-- Network Error Pages -->
       <message name="IDS_ERRORPAGES_SUGGESTION_NETWORK_PREDICTION_BODY" desc="When a page fails to load, sometimes we suggest disabling predicting network actions.  These are details below a header.">
@@ -852,18 +862,18 @@
         Allow Chrome to access the network in your firewall or antivirus
         settings.
       </message>
-      <if expr="is_macosx and not pp_ifdef('ios')">
+      <if expr="is_macosx">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Mac OSX instructions for disabling use of a proxy server.">
           Go to
           Applications &gt; System Preferences &gt; Network &gt; Advanced &gt; Proxies
           and deselect any proxies that have been selected.
         </message>
       </if>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Instructions for disabling use of a proxy server (leave empty for Android and iOS).">
         </message>
       </if>
-      <if expr="not pp_ifdef('chromeos') and is_posix and not is_macosx and not is_android and not pp_ifdef('ios')">
+      <if expr="not pp_ifdef('chromeos') and is_posix and not is_macosx and not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUGGESTION_PROXY_DISABLE_PLATFORM" desc="Linux instructions for disabling use of a proxy server.">
           Go to
           the Chrome menu &gt;
diff --git a/chrome/app/nibs/HttpAuthLoginSheet.xib b/chrome/app/nibs/HttpAuthLoginSheet.xib
index ed94082..3d71d3c 100644
--- a/chrome/app/nibs/HttpAuthLoginSheet.xib
+++ b/chrome/app/nibs/HttpAuthLoginSheet.xib
@@ -2,13 +2,13 @@
 <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
 	<data>
 		<int key="IBDocument.SystemTarget">1050</int>
-		<string key="IBDocument.SystemVersion">12C54</string>
-		<string key="IBDocument.InterfaceBuilderVersion">2549</string>
-		<string key="IBDocument.AppKitVersion">1187.34</string>
-		<string key="IBDocument.HIToolboxVersion">625.00</string>
+		<string key="IBDocument.SystemVersion">12E55</string>
+		<string key="IBDocument.InterfaceBuilderVersion">3084</string>
+		<string key="IBDocument.AppKitVersion">1187.39</string>
+		<string key="IBDocument.HIToolboxVersion">626.00</string>
 		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
 			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
-			<string key="NS.object.0">2549</string>
+			<string key="NS.object.0">3084</string>
 		</object>
 		<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
 			<bool key="EncodedWithXMLCoder">YES</bool>
@@ -178,6 +178,7 @@
 									<string key="NSFrame">{{116, 12}, {96, 32}}</string>
 									<reference key="NSSuperview" ref="110431333"/>
 									<reference key="NSWindow"/>
+									<reference key="NSNextKeyView"/>
 									<bool key="NSEnabled">YES</bool>
 									<object class="NSButtonCell" key="NSCell" id="895775734">
 										<int key="NSCellFlags">67108864</int>
@@ -452,6 +453,14 @@
 				</object>
 				<object class="IBConnectionRecord">
 					<object class="IBOutletConnection" key="connection">
+						<string key="label">initialFirstResponder</string>
+						<reference key="source" ref="370721286"/>
+						<reference key="destination" ref="488177356"/>
+					</object>
+					<int key="connectionID">56</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
 						<string key="label">viewToResize_</string>
 						<reference key="source" ref="333395907"/>
 						<reference key="destination" ref="370721286"/>
@@ -800,7 +809,7 @@
 				<reference key="dict.values" ref="0"/>
 			</object>
 			<nil key="sourceID"/>
-			<int key="maxID">55</int>
+			<int key="maxID">56</int>
 		</object>
 		<object class="IBClassDescriber" key="IBDocument.Classes">
 			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -1134,10 +1143,6 @@
 			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
 			<integer value="1050" key="NS.object.0"/>
 		</object>
-		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
-			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
-			<real value="1070" key="NS.object.0"/>
-		</object>
 		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
 			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
 			<integer value="3000" key="NS.object.0"/>
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json
index 10ad804..c4444fb 100644
--- a/chrome/app/policy/policy_templates.json
+++ b/chrome/app/policy/policy_templates.json
@@ -117,7 +117,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: 236
+#   For your editing convenience: highest ID currently used: 239
 #
 # Placeholders:
 #   The following placeholder strings are automatically substituted:
@@ -1888,6 +1888,24 @@
           This policy is only respected if the 'DefaultSearchProviderEnabled' policy is enabled.''',
         },
         {
+          'name': 'DefaultSearchProviderNewTabURL',
+          'type': 'string',
+          'schema': { 'type': 'string' },
+          'supported_on': ['chrome.*:30-', 'chrome_os:0.30-', 'android:30-'],
+          'features': {
+            'dynamic_refresh': True,
+            'per_profile': True,
+          },
+          'example_value': 'http://search.my.company/newtab',
+          'id': 237,
+          'caption': '''Default search provider new tab page URL''',
+          'desc': '''Specifies the URL that a search engine uses to provide a new tab page.
+
+          This policy is optional. If not set, no new tab page will be provided.
+
+          This policy is only respected if the 'DefaultSearchProviderEnabled' policy is enabled.''',
+        },
+        {
           'name': 'DefaultSearchProviderSearchURLPostParams',
           'type': 'string',
           'schema': { 'type': 'string' },
@@ -2657,6 +2675,25 @@
 
           If this policy is not set the default command line will be used.''',
         },
+        {
+          'name': 'SkipMetadataCheck',
+          'type': 'main',
+          'schema': { 'type': 'boolean' },
+          'supported_on': ['chrome_frame:31-'],
+          'features': {
+            'dynamic_refresh': False,
+          },
+          'example_value': False,
+          'id': 238,
+          'caption': '''Skip the meta tag check in <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph>''',
+          'desc': '''Normally pages with X-UA-Compatible set to chrome=1 will be rendered in <ph name="PRODUCT_FRAME_NAME">$3<ex>Google Chrome Frame</ex></ph> regardless of the 'ChromeFrameRendererSettings' policy.
+
+          If you enable this setting, pages will not be scanned for meta tags.
+
+          If you disable this setting, pages will be scanned for meta tags.
+
+          If this policy is not set, pages will be scanned for meta tags.'''
+        },
       ],
     },
     {
@@ -4076,7 +4113,13 @@
       'example_value': True,
       'id': 236,
       'caption': '''Use 24 hour clock by default''',
-      'desc': '''Specifies the clock format be used for the device. Users can override clock format for the current session. However, on logout it is set back to the specified value. If an empty string is provided, device owner preference is used.''',
+      'desc': '''Specifies the clock format be used for the device.
+
+      This policy configures the clock format to use on the login screen and as a default for user sessions. Users can still override the clock format for their account.
+
+      If the policy is not set to true, the device will use a 24 hour clock format. If the policy is set to false, the device will use 12 hour clock format.
+
+      If this policy is not set, the device will default to a 24 hour clock format.''',
     },
     {
       'name': 'ShowLogoutButtonInTray',
@@ -5270,6 +5313,24 @@
 
           If an extension is not in the list, or the list is not set, the call to the API will fail with an error code.''',
         },
+        {
+          'name': 'AttestationForContentProtectionEnabled',
+          'type': 'main',
+          'schema': { 'type': 'boolean' },
+          'supported_on': ['chrome_os:31-'],
+          'features': {
+            'dynamic_refresh': True,
+          },
+          'device_only': True,
+          'example_value': True,
+          'id': 239,
+          'caption': '''Enable the use of remote attestation for content protection for the device.''',
+          'desc': '''Chrome OS devices can use remote attestation (Verified Access) to get a certificate issued by the Chrome OS CA that asserts the device is eligible to play protected content.  This process involves sending hardware endorsement information to the Chrome OS CA which uniquely identifies the device.
+
+          If this setting is false, the device will not use remote attestation for content protection and the device may be unable to play protected content.
+
+          If this setting is true, or if it is not set, remote attestation may be used for content protection.''',
+        },
       ],
     },
     {
diff --git a/chrome/app/resources/chromium_strings_da.xtb b/chrome/app/resources/chromium_strings_da.xtb
index ad5436f..a3a4e8b 100644
--- a/chrome/app/resources/chromium_strings_da.xtb
+++ b/chrome/app/resources/chromium_strings_da.xtb
@@ -152,7 +152,7 @@
 <translation id="1691304614444223855">Chromium Frame er opdateret. Genstart browseren. Chromium-version: <ph name="TODO_0001"/>, Chromium Frame-version: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">Dine ændringer træder i kraft, næste gang du genstarter din enhed.</translation>
 <translation id="3244477511402911926">Chromium Underretningscenter</translation>
-<translation id="1105130903706696483">Chromium lukkede ikke korrekt ned. Klik på Gendan for at genåbne de sider, du havde åben.</translation>
+<translation id="1105130903706696483">Chromium lukkede ikke korrekt ned. Klik på Gendan for at genåbne de sider, du havde åbne.</translation>
 <translation id="1531452407274881270">Du logger ind på Chromium med kontoen <ph name="USER_EMAIL_ADDRESS"/>. Du har adgang til dine bogmærker, din historik og andre indstillinger på alle de enheder, hvor du er logget ind.</translation>
 <translation id="1929939181775079593">Chromium svarer ikke. Vil du genstarte nu?</translation>
 <translation id="1414495520565016063">Du er logget ind på Chromium.</translation>
@@ -193,7 +193,7 @@
 <translation id="2739631515503418643">Downloads er i øjeblikket i gang. Vil du afslutte Chromium og annullere downloads?</translation>
 <translation id="9013262824292842194">Chromium kræver Windows Vista eller Windows XP med SP2 eller højere.</translation>
 <translation id="7673212349590566645">Vil du logge ind på Chromium med <ph name="USER_EMAIL_ADDRESS"/>?</translation>
-<translation id="1967743265616885482">Et modul med samme navn er i modstrid med Chromium.</translation>
+<translation id="1967743265616885482">Et modul med samme navn er i strid med Chromium.</translation>
 <translation id="4224199872375172890">Chromium er opdateret.</translation>
 <translation id="374481098568514319">Denne computer har allerede en nyere version af Chromium-komponenterne. Brug et nyere installationsprogram.</translation>
 <translation id="6240281849816458190">Du forsøgte at gå til &lt;strong&gt;<ph name="DOMAIN"/>&lt;/strong&gt;, men serveren viste et certifikat, der endnu ikke er gyldigt. Der er ingen tilgængelige oplysninger, der indikerer, om certifikatet stammer fra en kilde, der er tillid til. Chromium kan ikke med sikkerhed garantere, at du kommunikerer med &lt;strong&gt;<ph name="DOMAIN2"/>&lt;/strong&gt; og ikke en angriber. Uret på din computer viser i øjeblikket <ph name="CURRENT_TIME"/>. Ser det rigtigt ud? Hvis ikke, skal du rette systemuret og derefter opdatere siden.</translation>
diff --git a/chrome/app/resources/chromium_strings_en-GB.xtb b/chrome/app/resources/chromium_strings_en-GB.xtb
index 8e5a0b5..d9dc351 100644
--- a/chrome/app/resources/chromium_strings_en-GB.xtb
+++ b/chrome/app/resources/chromium_strings_en-GB.xtb
@@ -154,7 +154,7 @@
 <translation id="1691304614444223855">Chromium Frame has been updated. Please relaunch your browser. Chromium version: <ph name="TODO_0001"/>, Chromium Frame version: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">Your changes will take effect the next time that you restart your device.</translation>
 <translation id="3244477511402911926">Chromium Notification Center</translation>
-<translation id="1105130903706696483">Chromium didn't shut down correctly. To re-open the pages you had open, click Restore.</translation>
+<translation id="1105130903706696483">Chromium didn't shut down correctly. To re-open the pages that you had open, click Restore.</translation>
 <translation id="1531452407274881270">You're signing in to Chromium using your <ph name="USER_EMAIL_ADDRESS"/> account. You will be able to access your bookmarks, history and other settings on all of your signed in devices.</translation>
 <translation id="1929939181775079593">Chromium is unresponsive. Relaunch now?</translation>
 <translation id="1414495520565016063">You're signed in to Chromium!</translation>
diff --git a/chrome/app/resources/chromium_strings_et.xtb b/chrome/app/resources/chromium_strings_et.xtb
index d7b9022..e018d12 100644
--- a/chrome/app/resources/chromium_strings_et.xtb
+++ b/chrome/app/resources/chromium_strings_et.xtb
@@ -152,7 +152,7 @@
 <translation id="1691304614444223855">Chromium Frame on värskendatud. Taaskäivitage brauser. Chromiumi versioon: <ph name="TODO_0001"/>, Chromium Frame'i versioon: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">Muudatused jõustuvad järgmine kord, kui seadme taaskäivitate.</translation>
 <translation id="3244477511402911926">Chromiumi märguandekeskus</translation>
-<translation id="1105130903706696483">Chromium ei sulgunud korralikult. Lehtede taasavamiseks klõpsake käsul taasta.</translation>
+<translation id="1105130903706696483">Chromium ei sulgunud korralikult. Lehtede taasavamiseks klõpsake käsul Taasta.</translation>
 <translation id="1531452407274881270">Logite Chromiumi sisse kontoga <ph name="USER_EMAIL_ADDRESS"/>. Pääsete kõigis sisselogitud seadmetes juurde oma järjehoidjatele, ajaloole ja muudele seadetele.</translation>
 <translation id="1929939181775079593">Chromium ei reageeri. Kas soovite kohe taaskäivitada?</translation>
 <translation id="1414495520565016063">Olete Chromiumi sisse logitud.</translation>
diff --git a/chrome/app/resources/chromium_strings_iw.xtb b/chrome/app/resources/chromium_strings_iw.xtb
index de70887..0eb8586 100644
--- a/chrome/app/resources/chromium_strings_iw.xtb
+++ b/chrome/app/resources/chromium_strings_iw.xtb
@@ -150,7 +150,7 @@
 <translation id="1691304614444223855">Chromium Frame עודכן. הפעל מחדש את הדפדפן. גרסת Chromium‏ : <ph name="TODO_0001"/>, גרסת Chromium Frame‏: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">השינויים ייכנסו לתוקף בפעם הבאה שתפעיל מחדש את המכשיר.</translation>
 <translation id="3244477511402911926">מרכז ההתראות של Chromium</translation>
-<translation id="1105130903706696483">Chromium לא נסגר כראוי. לפתיחה מחדש של הדפים שפתחת, לחץ על שחזר.</translation>
+<translation id="1105130903706696483">Chromium לא נסגר כראוי. לפתיחה מחדש של הדפים שפתחת, לחץ על 'שחזר'.</translation>
 <translation id="1531452407274881270">אתה נכנס ל-Chromium באמצעות חשבון <ph name="USER_EMAIL_ADDRESS"/> שלך. תוכל לגשת אל הסימניות, ההיסטוריה והגדרות אחרות בכל המכשירים שבהם אתה מחובר לחשבון.</translation>
 <translation id="1929939181775079593">Chromium אינו מגיב. להפעיל מחדש עכשיו?</translation>
 <translation id="1414495520565016063">נכנסת ל-Chromium!</translation>
diff --git a/chrome/app/resources/chromium_strings_kn.xtb b/chrome/app/resources/chromium_strings_kn.xtb
index 2ae2868..f657259 100644
--- a/chrome/app/resources/chromium_strings_kn.xtb
+++ b/chrome/app/resources/chromium_strings_kn.xtb
@@ -148,7 +148,7 @@
 <translation id="1691304614444223855">Chromium Frame ಅನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ. ದಯವಿಟ್ಟು ನಿಮ್ಮ ಬ್ರೌಸರ್ ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಿ. Chromium ಆವೃತ್ತಿ: <ph name="TODO_0001"/>, Chromium Frame ಆವೃತ್ತಿ: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">ನಿಮ್ಮ ಸಾಧನವನ್ನು ನೀವು ಮುಂದಿನ ಬಾರಿ ಮರುಪ್ರಾರಂಭಿಸಿದಾಗ ನಿಮ್ಮ ಬದಲಾವಣೆಗಳು ಕಾರ್ಯಗತಗೊಳ್ಳುತ್ತವೆ.</translation>
 <translation id="3244477511402911926">Chromium ಅಧಿಸೂಚನೆ ಕೇಂದ್ರ</translation>
-<translation id="1105130903706696483">Chromium ಸರಿಯಾಗಿ ಶಟ್‌ಡೌನ್ ಮಾಡಲಿಲ್ಲ. ನೀವು ತೆರೆದಿರುವಂತಹ ಪುಟಗಳನ್ನು ಪುನಃ ತೆರೆಯಲು, ಮರುಸ್ಥಾಪನೆಯನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ.</translation>
+<translation id="1105130903706696483">Chromium ಅನ್ನು ಸರಿಯಾಗಿ ಶಟ್‌ಡೌನ್ ಮಾಡಿರಲಿಲ್ಲ. ನೀವು ತೆರೆದ ಪುಟಗಳನ್ನು ಪುನಃ ತೆರೆಯಲು, ಪುನಃಸ್ಥಾಪನೆ ಕ್ಲಿಕ್‌ ಮಾಡಿ.</translation>
 <translation id="1531452407274881270">ನಿಮ್ಮ <ph name="USER_EMAIL_ADDRESS"/> ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನೀವು Chromium ಗೆ ಸೈನ್ ಇನ್ ಮಾಡುತ್ತಿರುವಿರಿ. ನಿಮ್ಮ ಸೈನ್ ಇನ್ ಮಾಡಿದ ಎಲ್ಲ ಸಾಧನಗಳಲ್ಲಿ ನಿಮ್ಮ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು, ಇತಿಹಾಸ, ಮತ್ತು ಇತರ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನಿಮಗೆ ಸಾಧ್ಯವಾಗಬಹುದು.</translation>
 <translation id="1929939181775079593">Chromium ಸ್ಪಂದಿಸುತ್ತಿಲ್ಲ. ಇದೀಗ ಮರುಪ್ರಾರಂಭಿಸುವುದೇ?</translation>
 <translation id="1414495520565016063">ನೀವು Chromium ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿರುವಿರಿ!</translation>
diff --git a/chrome/app/resources/chromium_strings_pt-BR.xtb b/chrome/app/resources/chromium_strings_pt-BR.xtb
index 82afbc2..7280b7e 100644
--- a/chrome/app/resources/chromium_strings_pt-BR.xtb
+++ b/chrome/app/resources/chromium_strings_pt-BR.xtb
@@ -148,7 +148,7 @@
 <translation id="1691304614444223855">O Chromium Frame foi atualizado. Reinicie seu navegador. Versão do Chromium: <ph name="TODO_0001"/>, versão do Chromium Frame: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">As alterações entrarão em vigor na próxima vez que você reiniciar o dispositivo.</translation>
 <translation id="3244477511402911926">Central de notificações do Chromium</translation>
-<translation id="1105130903706696483">O Chromium não foi encerrado corretamente. Para reabrir as páginas que você tinha aberto, clique em Restaurar.</translation>
+<translation id="1105130903706696483">O Chromium não foi encerrado corretamente. Para reabrir as páginas que você tinha aberto, clique em &quot;Restaurar&quot;.</translation>
 <translation id="1531452407274881270">Você está fazendo login no Chromium usando sua conta <ph name="USER_EMAIL_ADDRESS"/>. Assim, poderá acessar seus favoritos, histórico e outras configurações em todos os dispositivos conectados.</translation>
 <translation id="1929939181775079593">O Chromium não está respondendo. Reiniciar agora?</translation>
 <translation id="1414495520565016063">Você está conectado ao Chromium.</translation>
diff --git a/chrome/app/resources/chromium_strings_sr.xtb b/chrome/app/resources/chromium_strings_sr.xtb
index 2c2a899..3fee08f 100644
--- a/chrome/app/resources/chromium_strings_sr.xtb
+++ b/chrome/app/resources/chromium_strings_sr.xtb
@@ -152,7 +152,7 @@
 <translation id="1691304614444223855">Chromium Frame је ажуриран. Покрените поново прегледач. Верзија Chromium-а: <ph name="TODO_0001"/>, Верзија Chromium Frame-а: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">Промене ће ступити на снагу када следећи пут поново покренете уређај.</translation>
 <translation id="3244477511402911926">Chromium центар за обавештења</translation>
-<translation id="1105130903706696483">Chromium се није исправно затворио. Да бисте поново отворили странице које су биле отворене, кликните на Врати.</translation>
+<translation id="1105130903706696483">Chromium се није исправно затворио. Да бисте поново отворили странице које су биле отворене, кликните на Поново отвори.</translation>
 <translation id="1531452407274881270">Пријављујете се на Chromium помоћу налога <ph name="USER_EMAIL_ADDRESS"/>. Моћи ћете да приступате обележивачима, историји и другим подешавањима на свим уређајима на којима сте пријављени.</translation>
 <translation id="1929939181775079593">Chromium не реагује. Желите ли да га одмах поново покренете?</translation>
 <translation id="1414495520565016063">Пријављени сте на Chromium!</translation>
diff --git a/chrome/app/resources/chromium_strings_sw.xtb b/chrome/app/resources/chromium_strings_sw.xtb
index 582a50d..10f449e 100644
--- a/chrome/app/resources/chromium_strings_sw.xtb
+++ b/chrome/app/resources/chromium_strings_sw.xtb
@@ -152,7 +152,7 @@
 <translation id="1691304614444223855">Fremu ya Chromium imesasishwa. Tafadhali zindua upya kivinjari chako. Toleo la Chromium: <ph name="TODO_0001"/>, Toleo la Fremu ya Chromium: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">Mabadiliko yako yatatekelezwa utakapowasha upya tena kifaa chako.</translation>
 <translation id="3244477511402911926">Kituo cha Chromium cha Taarifa</translation>
-<translation id="1105130903706696483">Chromium haikuzimika vizuri. Ili kufungua upya kurasa zilizokuwa wazi, bofya Onyesha upya.</translation>
+<translation id="1105130903706696483">Chromium haikuzimika vizuri. Ili kufungua tena kurasa ulizokuwa umefungua, bofya Rejesha.</translation>
 <translation id="1531452407274881270">Unaingia kwenye Chromium ukitumia akaunti yako ya <ph name="USER_EMAIL_ADDRESS"/>. Utaweza kufikia alamisho zako, historia, na mipangilio mingine kwenye vifaa vyako vyote ulivyoingia.</translation>
 <translation id="1929939181775079593">Chromium haiamiliki. Zindua upya sasa?</translation>
 <translation id="1414495520565016063">Umeingia kwenye Chromium!</translation>
diff --git a/chrome/app/resources/chromium_strings_tr.xtb b/chrome/app/resources/chromium_strings_tr.xtb
index 23ccc64..d0e194e 100644
--- a/chrome/app/resources/chromium_strings_tr.xtb
+++ b/chrome/app/resources/chromium_strings_tr.xtb
@@ -146,7 +146,7 @@
 <translation id="1691304614444223855">Chromium Frame güncellendi. Lütfen tarayıcınızı yeniden başlatın. Chromium sürümü: <ph name="TODO_0001"/>, Chromium Frame sürümü: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">Yaptığınız değişiklikler cihazı yeniden başlattığınızda etkinleşecektir.</translation>
 <translation id="3244477511402911926">Chromium Bildirim Merkezi</translation>
-<translation id="1105130903706696483">Chromium düzgün şekilde kapatılmadı. Daha önce açık olan sayfaların tekrar açılması için Geri Yükle'yi tıklatın.</translation>
+<translation id="1105130903706696483">Chromium düzgün şekilde kapatılmadı. Daha önce açık olan sayfaların tekrar açılması için Geri yükle'yi tıklayın.</translation>
 <translation id="1531452407274881270"><ph name="USER_EMAIL_ADDRESS"/> hesabınızı kullanarak Chromium'da oturum açıyorsunuz. Oturum açtığınız tüm cihazlardan yer işaretlerinize, geçmişinize ve diğer ayarlarınıza erişebileceksiniz.</translation>
 <translation id="1929939181775079593">Chromium yanıt vermiyor. Şimdi yeniden başlatılsın mı?</translation>
 <translation id="1414495520565016063">Chromium'da oturum açtınız!</translation>
diff --git a/chrome/app/resources/chromium_strings_uk.xtb b/chrome/app/resources/chromium_strings_uk.xtb
index 7c52660..5ea2e14 100644
--- a/chrome/app/resources/chromium_strings_uk.xtb
+++ b/chrome/app/resources/chromium_strings_uk.xtb
@@ -152,7 +152,7 @@
 <translation id="1691304614444223855">Chromium Frame оновлено. Перезапустіть свій веб-переглядач. Версія Chromium: <ph name="TODO_0001"/>, версія Chromium Frame: <ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">Ваші зміни почнуть діяти під час наступного перезапуску пристрою.</translation>
 <translation id="3244477511402911926">Центр сповіщень Chromium</translation>
-<translation id="1105130903706696483">Роботу Chromium було завершено неправильно. Щоб знову відкрити сторінки, які ви відкривали, натисніть &quot;Відновити&quot;.</translation>
+<translation id="1105130903706696483">Chromium завершив роботу неправильно. Щоб повернутися до відкритих сторінок, натисніть &quot;Відновити&quot;.</translation>
 <translation id="1531452407274881270">Ви входите в Chromium, використовуючи обліковий запис <ph name="USER_EMAIL_ADDRESS"/>. Ваші закладки, історія й інші налаштування будуть доступні на всіх пристроях, на яких ви ввійдете в цей обліковий запис.</translation>
 <translation id="1929939181775079593">Chromium не відповідає. Перезапустити зараз?</translation>
 <translation id="1414495520565016063">Ви ввійшли в Chromium.</translation>
diff --git a/chrome/app/resources/chromium_strings_zh-CN.xtb b/chrome/app/resources/chromium_strings_zh-CN.xtb
index 97bf489..ff3a01f 100644
--- a/chrome/app/resources/chromium_strings_zh-CN.xtb
+++ b/chrome/app/resources/chromium_strings_zh-CN.xtb
@@ -127,7 +127,7 @@
 <translation id="1691304614444223855">Chromium 内嵌框架已更新。请重新启动浏览器。Chromium 版本:<ph name="TODO_0001"/>,Chromium 内嵌框架版本:<ph name="TODO_0002"/></translation>
 <translation id="130631256467250065">您所做的更改会在下次重新启动设备时生效。</translation>
 <translation id="3244477511402911926">Chromium 通知中心</translation>
-<translation id="1105130903706696483">Chromium 未正确关闭。要重新打开曾经打开过的网页,请点击“恢复”。</translation>
+<translation id="1105130903706696483">Chromium 未正确关闭。要重新打开您之前浏览的网页,请点击“恢复”。</translation>
 <translation id="1531452407274881270">您正在使用 <ph name="USER_EMAIL_ADDRESS"/> 帐户登录 Chromium。您将能够访问自己在所有登录过的设备上保存的书签、历史记录和其他设置。</translation>
 <translation id="1929939181775079593">Chromium 未响应。要立即重新启动吗?</translation>
 <translation id="1414495520565016063">您已登录 Chromium!</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb
index 31b2dbf..84f35d1 100644
--- a/chrome/app/resources/generated_resources_da.xtb
+++ b/chrome/app/resources/generated_resources_da.xtb
@@ -1785,7 +1785,7 @@
 <translation id="4258748452823770588">Forkert signatur</translation>
 <translation id="7434823369735508263">Britisk (Dvorak) tastatur</translation>
 <translation id="1572103024875503863"><ph name="NUMBER_MANY"/> dage</translation>
-<translation id="8825366169884721447">Denne udvidelse kunne ikke ændre anmodningsheaderen &quot;<ph name="HEADER_NAME"/>&quot; for en netværksanmodning, fordi ændringen var i modstrid med en anden udvidelse. (<ph name="EXTENSION_NAME"/>).</translation>
+<translation id="8825366169884721447">Denne udvidelse kunne ikke ændre anmodningsheaderen &quot;<ph name="HEADER_NAME"/>&quot; for en netværksanmodning, fordi ændringen var i strid med en anden udvidelse. (<ph name="EXTENSION_NAME"/>).</translation>
 <translation id="5308845175611284862">Synkronisering med <ph name="PRODUCT_NAME"/> gør det nemt at dele data (såsom bogmærker og indstillinger) mellem dine computere. <ph name="PRODUCT_NAME"/> synkroniserer dine data ved at gemme dem på nettet hos Google, når du logger ind med din Google-konto.</translation>
 <translation id="1707463636381878959">Del dette netværk med andre brugere</translation>
 <translation id="112817597702985620">Altid maksimeret tilstand</translation>
@@ -3401,7 +3401,7 @@
 <translation id="1859234291848436338">Skriveretning</translation>
 <translation id="5045550434625856497">Ugyldig adgangskode</translation>
 <translation id="6397592254427394018">Åbn alle bogmærker i &amp;inkognitovindue</translation>
-<translation id="27822970480436970">Denne udvidelse kunne ikke ændre en netværksanmodning, fordi ændringen var i modstrid med en anden udvidelse.</translation>
+<translation id="27822970480436970">Denne udvidelse kunne ikke ændre en netværksanmodning, fordi ændringen var i strid med en anden udvidelse.</translation>
 <translation id="756445078718366910">Åbn browservindue</translation>
 <translation id="6132383530370527946">Det med småt</translation>
 <translation id="9033780830059217187">Proxyen håndhæves af en udvidelse.</translation>
@@ -3688,7 +3688,7 @@
 <translation id="4647697156028544508">Indtast pinkoden for &quot;<ph name="DEVICE_NAME"/>&quot;:</translation>
 <translation id="5604961908909363516">Få adgang til alt det, som du skriver.</translation>
 <translation id="7671130400130574146">Brug systemets titellinje og rammer</translation>
-<translation id="9111791539553342076">Denne udvidelse kunne ikke ændre anmodningsheaderen &quot;<ph name="HEADER_NAME"/>&quot; for en netværksanmodning, fordi ændringen var i modstrid med en anden udvidelse. (<ph name="EXTENSION_NAME"/>).</translation>
+<translation id="9111791539553342076">Denne udvidelse kunne ikke ændre anmodningsheaderen &quot;<ph name="HEADER_NAME"/>&quot; for en netværksanmodning, fordi ændringen var i strid med en anden udvidelse. (<ph name="EXTENSION_NAME"/>).</translation>
 <translation id="9170848237812810038">&amp;Fortryd</translation>
 <translation id="284970761985428403"><ph name="ASCII_NAME"/> (<ph name="UNICODE_NAME"/>)</translation>
 <translation id="3903912596042358459">Serveren afviste at gennemføre anmodningen.</translation>
@@ -4411,7 +4411,7 @@
 <translation id="3695919544155087829">Angiv den adgangskode, der blev brugt til at kryptere denne certifikatfil.</translation>
 <translation id="2230051135190148440">CHAP</translation>
 <translation id="2509857212037838238">Installer <ph name="PLUGIN_NAME"/></translation>
-<translation id="2943400156390503548">Præsentation</translation>
+<translation id="2943400156390503548">Præsentationer</translation>
 <translation id="3790146417033334899"><ph name="PLUGIN_NAME"/> fungerer kun på skrivebordet.</translation>
 <translation id="5117930984404104619">Overvåg adfærden for andre udvidelser, herunder de webadresser, du har besøgt.</translation>
 <translation id="33022249435934718">GDI-håndtag</translation>
@@ -4920,7 +4920,7 @@
 <translation id="445923051607553918">Tilmeld dig et Wi-Fi-netværk</translation>
 <translation id="4215898373199266584">Psst! Prøv at bruge Inkognitotilstand (<ph name="INCOGNITO_MODE_SHORTCUT"/>) næste gang.</translation>
 <translation id="9087725134750123268">Slet cookies og andre websitedata</translation>
-<translation id="2925966894897775835">Ark</translation>
+<translation id="2925966894897775835">Regneark</translation>
 <translation id="2563856802393254086">Datatjenesten &quot;<ph name="NAME"/>&quot; er blevet aktiveret og er klar til brug.</translation>
 <translation id="756631359159530168">Aktivér tegning efter flise af sideindholdet, når komposition er aktiveret.</translation>
 <translation id="3349155901412833452">Brug tasterne , og . til at bladre igennem en kandidatliste</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index 2a395d3..2002f39 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -1355,7 +1355,7 @@
 <translation id="5171045022955879922">Suchen oder URL eingeben</translation>
 <translation id="6830600606572693159">Die Webseite unter <ph name="URL"/> ist zurzeit nicht verfügbar. Möglicherweise ist sie überlastet oder wird gerade gewartet.</translation>
 <translation id="6776310961830589430">Verschieben abgebrochen</translation>
-<translation id="5299109548848736476">Nicht erfassen</translation>
+<translation id="5299109548848736476">Do Not Track</translation>
 <translation id="4421932782753506458">Miez</translation>
 <translation id="7197910855372448411">Auswahlkontrollkästchen zeigen</translation>
 <translation id="1885118447093706945">Deaktiviert den Wechsel zwischen Tabs durch waagrechtes Scrollen mit drei Fingern.</translation>
@@ -1657,7 +1657,7 @@
 <translation id="4349181486102621992"><ph name="NUMBER_ZERO"/> Sekunden</translation>
 <translation id="8053278772142718589">PKCS #12-Dateien</translation>
 <translation id="6662016084451426657">Synchronisierungsfehler: Bitten Sie Ihren Administrator, die Synchronisierung zu aktivieren.</translation>
-<translation id="1425751983380462633">Die Aktivierung der Option &quot;Nicht erfassen&quot; bedeutet, dass mit Ihrem Datenverkehr beim Surfen eine Aufforderung gesendet wird. Das Ergebnis hängt davon ab, ob eine Webseite auf die Aufforderung reagiert und wie die Aufforderung ausgelegt wird. Einige Webseiten reagieren beispielsweise so auf diese Aufforderung, dass sie Ihnen Werbeanzeigen zeigen, die nicht auf anderen von Ihnen besuchten Webseiten basieren. Viele Webseiten werden Ihren Datenverkehr beim Surfen dennoch sammeln und verwenden – beispielsweise, um die Sicherheit zu verbessern, um Inhalte, Dienste, Werbeanzeigen und Empfehlungen auf ihren Webseiten zur Verfügung zu stellen und um Berichtsstatistiken zu erstellen.</translation>
+<translation id="1425751983380462633">Die Aktivierung der Option &quot;Do Not Track&quot; bedeutet, dass mit Ihrem Datenverkehr beim Surfen eine Aufforderung gesendet wird. Das Ergebnis hängt davon ab, ob eine Webseite auf die Aufforderung reagiert und wie die Aufforderung ausgelegt wird. Einige Webseiten reagieren beispielsweise so auf diese Aufforderung, dass sie Ihnen Werbeanzeigen zeigen, die nicht auf anderen von Ihnen besuchten Webseiten basieren. Viele Webseiten werden Ihren Datenverkehr beim Surfen dennoch sammeln und verwenden – beispielsweise, um die Sicherheit zu verbessern, um Inhalte, Dienste, Werbeanzeigen und Empfehlungen auf ihren Webseiten zur Verfügung zu stellen und um Berichtsstatistiken zu erstellen.</translation>
 <translation id="2129904043921227933">Synchronisierungsfehler: Aktualisieren Sie die Passphrase für die Synchronisierung...</translation>
 <translation id="1476949146811612304">Legen Sie fest, welche Suchmaschine bei einer Suche über die <ph name="BEGIN_LINK"/>Omnibox<ph name="END_LINK"/> verwendet werden soll.</translation>
 <translation id="4114360727879906392">Vorheriges Fenster</translation>
@@ -2145,7 +2145,7 @@
 <translation id="4763830802490665879">Cookies von mehreren Websites werden beim Beenden gelöscht.</translation>
 <translation id="1358032944105037487">Japanische Tastatur </translation>
 <translation id="3897224341549769789">Aktivierungen</translation>
-<translation id="2317866052221803936">Mit Browserzugriffen eine &quot;Nicht erfassen&quot;-Anforderung senden</translation>
+<translation id="2317866052221803936">Mit Browserzugriffen eine &quot;Do Not Track&quot;-Anforderung senden</translation>
 <translation id="4648491805942548247">Unzureichende Berechtigungen</translation>
 <translation id="1183083053288481515">Vom Administrator bereitgestelltes Zertifikat verwenden</translation>
 <translation id="6231782223312638214">Vorgeschlagen</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index f321d3d..fd3704f 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -3514,7 +3514,7 @@
 <translation id="1056898198331236512">Avertissement</translation>
 <translation id="8432745813735585631">Clavier Colemak américain</translation>
 <translation id="2608770217409477136">Utiliser les paramètres par défaut</translation>
-<translation id="3157931365184549694">Rétablir</translation>
+<translation id="3157931365184549694">Restaurer</translation>
 <translation id="996250603853062861">Établissement de la connexion sécurisée...</translation>
 <translation id="6059232451013891645">Dossier :</translation>
 <translation id="760537465793895946">Consultez les conflits connus avec des modules tiers.</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index 5d54f9e..0fac517 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -3472,7 +3472,7 @@
 <translation id="1056898198331236512">Peringatan</translation>
 <translation id="8432745813735585631">Keyboard Colemak AS</translation>
 <translation id="2608770217409477136">Gunakan setelan default</translation>
-<translation id="3157931365184549694">Kembalikan</translation>
+<translation id="3157931365184549694">Pulihkan</translation>
 <translation id="996250603853062861">Membuat koneksi aman...</translation>
 <translation id="6059232451013891645">Folder:</translation>
 <translation id="760537465793895946">Periksa konflik yang diketahui dengan modul pihak ketiga.</translation>
diff --git a/chrome/app/resources/generated_resources_ml.xtb b/chrome/app/resources/generated_resources_ml.xtb
index 9f31d39..257c3b3 100644
--- a/chrome/app/resources/generated_resources_ml.xtb
+++ b/chrome/app/resources/generated_resources_ml.xtb
@@ -3517,7 +3517,7 @@
 <translation id="1056898198331236512">മുന്നറിയിപ്പ്</translation>
 <translation id="8432745813735585631">യുഎസ് കോള്‍മാക്ക് കീബോര്‍ഡ്</translation>
 <translation id="2608770217409477136">സ്ഥിരസ്ഥിതി ക്രമീകരണങ്ങള്‍ ഉപയോഗിക്കുക</translation>
-<translation id="3157931365184549694">പുനസ്ഥാപിക്കുക</translation>
+<translation id="3157931365184549694">പുനഃസ്ഥാപിക്കുക</translation>
 <translation id="996250603853062861">സുരക്ഷിത കണക്ഷന്‍‌ സ്ഥാപിക്കുന്നു...</translation>
 <translation id="6059232451013891645">ഫോള്‍ഡര്‍:</translation>
 <translation id="760537465793895946">അറിയപ്പെടുന്ന വൈരുദ്ധ്യങ്ങള്‍ മൂന്നാം കക്ഷി മൊഡ്യൂളുകള്‍ ഉപയോഗിച്ച് പരിശോധിക്കുക.</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb
index fef66a5..8982f4a 100644
--- a/chrome/app/resources/generated_resources_ro.xtb
+++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -2450,7 +2450,7 @@
 <translation id="2526590354069164005">Desktop</translation>
 <translation id="4165738236481494247">Rulați acest plugin</translation>
 <translation id="7983301409776629893">Doresc să se traducă întotdeauna din <ph name="ORIGINAL_LANGUAGE"/> în <ph name="TARGET_LANGUAGE"/></translation>
-<translation id="4890284164788142455">Thailandeză</translation>
+<translation id="4890284164788142455">Thai</translation>
 <translation id="6049065490165456785">Fotografii de pe camera foto internă</translation>
 <translation id="4312207540304900419">Activați următoarea filă</translation>
 <translation id="7648048654005891115">Stil hartă taste</translation>
diff --git a/chrome/app/resources/generated_resources_ru.xtb b/chrome/app/resources/generated_resources_ru.xtb
index 190a0b1..269d86b 100644
--- a/chrome/app/resources/generated_resources_ru.xtb
+++ b/chrome/app/resources/generated_resources_ru.xtb
@@ -9,7 +9,7 @@
 <translation id="3314762460582564620">Простой режим чжуинь. Автоматический выбор варианта и соответствующие параметры отключены или игнорируются.</translation>
 <translation id="166179487779922818">Слишком короткий пароль.</translation>
 <translation id="2345460471437425338">Неверный сертификат для хоста.</translation>
-<translation id="3595596368722241419">Аккумулятор заряжен.</translation>
+<translation id="3595596368722241419">Аккумулятор заряжен</translation>
 <translation id="8130276680150879341">Отключить частную сеть</translation>
 <translation id="5028012205542821824">Установка не разрешена.</translation>
 <translation id="1058418043520174283"><ph name="INDEX"/> из <ph name="COUNT"/></translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb
index cac6627..463899c 100644
--- a/chrome/app/resources/generated_resources_sv.xtb
+++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -4429,7 +4429,7 @@
 <translation id="3695919544155087829">Ange lösenordet som användes vid krypteringen av certifikatfilen.</translation>
 <translation id="2230051135190148440">CHAP</translation>
 <translation id="2509857212037838238">Installera <ph name="PLUGIN_NAME"/></translation>
-<translation id="2943400156390503548">Bilder</translation>
+<translation id="2943400156390503548">Presentationer</translation>
 <translation id="3790146417033334899"><ph name="PLUGIN_NAME"/> fungerar bara på skrivbordet.</translation>
 <translation id="5117930984404104619">Bevaka hur övriga tillägg fungerar, däribland besökta webbadresser</translation>
 <translation id="33022249435934718">GDI-handtag</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index 9005ae2..5404e21 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -2618,7 +2618,7 @@
 <translation id="4521805507184738876">(muda wake umekwisha)</translation>
 <translation id="111844081046043029">Je, una hakika kuwa ungependa kuondoka kwenye ukurasa huu?</translation>
 <translation id="7622994733745016847">Matumizi  Binafsi ya Kumbukumbu</translation>
-<translation id="1951615167417147110">Tembeza juu ukurasa mmoja</translation>
+<translation id="1951615167417147110">Sogeza ukurasa mmoja juu</translation>
 <translation id="488726935215981469">Data yako imesimbwa kwa njia fiche kwa kaulisiri yako ya ulinganishaji. Tafadhali iingize hapo chini.</translation>
 <translation id="6786193060495187988">Niulize ikiwa ningependa kurasa zisizo katika lugha ninayoisoma zitafsiriwe</translation>
 <translation id="6147020289383635445">Uhakiki wa chapa umeshindwa.</translation>
@@ -4525,7 +4525,7 @@
 <translation id="5567989639534621706">Akiba za programu</translation>
 <translation id="9141716082071217089">Haiwezekani kuchunguza ikiwa cheti cha seva kimebatilishwa.</translation>
 <translation id="4304224509867189079">Ingia</translation>
-<translation id="5332624210073556029">Majira ya saa:</translation>
+<translation id="5332624210073556029">Saa za eneo:</translation>
 <translation id="3936768791051458634">Badili kituo...</translation>
 <translation id="6198102561359457428">Ondoka na kisha uingie tena...</translation>
 <translation id="4799797264838369263">Chaguo hili linadhibitiwa na sera ya biashara. Tafadhali wasiliana na msimamizi wako kwa maelezo zaidi.</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index 46ec838..7c7f1b8 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -3437,7 +3437,7 @@
 <translation id="1056898198331236512">คำเตือน</translation>
 <translation id="8432745813735585631">แป้นพิมพ์ Colemak สหรัฐอเมริกา</translation>
 <translation id="2608770217409477136">ใช้การตั้งค่าเริ่มต้น</translation>
-<translation id="3157931365184549694">คืนสภาพ</translation>
+<translation id="3157931365184549694">คืนค่า</translation>
 <translation id="996250603853062861">กำลังทำการเชื่อมต่ออย่างปลอดภัย...</translation>
 <translation id="6059232451013891645">โฟลเดอร์:</translation>
 <translation id="760537465793895946">ตรวจดูความขัดแย้งที่ทราบกับโมดูลของบุคคลที่สาม</translation>
diff --git a/chrome/app/resources/locale_settings.grd b/chrome/app/resources/locale_settings.grd
index d5b3d39..8033ab1 100644
--- a/chrome/app/resources/locale_settings.grd
+++ b/chrome/app/resources/locale_settings.grd
@@ -75,11 +75,11 @@
          be 'nb'. -->
     <output filename="locale_settings_nb.pak" type="data_package" lang="no" />
     <output filename="locale_settings_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="locale_settings_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="locale_settings_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="locale_settings_pt-PT.pak" type="data_package" lang="pt-PT" />
@@ -350,14 +350,14 @@
       <message name="IDS_CHROME_WELCOME_URL" translateable="false">
         http://www.google.com/chrome/intl/[GRITLANGCODE]/welcome.html
       </message>
-      <if expr="is_android or pp_ifdef('ios')">
+      <if expr="is_android or is_ios">
         <message name="IDS_MOBILE_WELCOME_URL" translateable="false">
           chrome://welcome
         </message>
       </if>
 
       <!-- The URL for Google Chrome privacy policy. -->
-      <if expr="pp_ifdef('ios')">
+      <if expr="is_ios">
         <message name="IDS_PRIVACY_POLICY_URL" translateable="false">
           http://www.google.com/chrome/intl/[GRITLANGCODE]/privacy.html
         </message>
@@ -390,7 +390,7 @@
       </message>
 
       <!-- The width and height for the "create application shortcuts error" dialog. -->
-      <if expr="is_posix and not is_macosx">
+      <if expr="is_posix and not is_macosx and not is_ios">
         <message name="IDS_CREATE_SHORTCUTS_ERROR_DIALOG_WIDTH_CHARS" use_name_for_id="true">
          60
         </message>
diff --git a/chrome/app/resources/locale_settings_mac.grd b/chrome/app/resources/locale_settings_mac.grd
index e762d5d..e1635cd 100644
--- a/chrome/app/resources/locale_settings_mac.grd
+++ b/chrome/app/resources/locale_settings_mac.grd
@@ -42,11 +42,11 @@
          be 'nb'. -->
     <output filename="platform_locale_settings_nb.pak" type="data_package" lang="no" />
     <output filename="platform_locale_settings_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="platform_locale_settings_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="platform_locale_settings_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="platform_locale_settings_pt-PT.pak" type="data_package" lang="pt-PT" />
diff --git a/chrome/app/theme/chromium/app_list_128.png b/chrome/app/theme/chromium/app_list_128.png
index 2a0eede..17916f4 100644
--- a/chrome/app/theme/chromium/app_list_128.png
+++ b/chrome/app/theme/chromium/app_list_128.png
Binary files differ
diff --git a/chrome/app/theme/chromium/app_list_16.png b/chrome/app/theme/chromium/app_list_16.png
index 1212a8d..8e5839e 100644
--- a/chrome/app/theme/chromium/app_list_16.png
+++ b/chrome/app/theme/chromium/app_list_16.png
Binary files differ
diff --git a/chrome/app/theme/chromium/app_list_256.png b/chrome/app/theme/chromium/app_list_256.png
index db45b57..5acdd92 100644
--- a/chrome/app/theme/chromium/app_list_256.png
+++ b/chrome/app/theme/chromium/app_list_256.png
Binary files differ
diff --git a/chrome/app/theme/chromium/app_list_32.png b/chrome/app/theme/chromium/app_list_32.png
index 6a91450..fa8b860 100644
--- a/chrome/app/theme/chromium/app_list_32.png
+++ b/chrome/app/theme/chromium/app_list_32.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/chromium/ic_gplus_color_16.png b/chrome/app/theme/default_100_percent/chromium/ic_gplus_color_16.png
new file mode 100644
index 0000000..00aa546
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/chromium/ic_gplus_color_16.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/browser_tools_badge_ash.png b/chrome/app/theme/default_100_percent/common/browser_tools_badge_aura.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/browser_tools_badge_ash.png
rename to chrome/app/theme/default_100_percent/common/browser_tools_badge_aura.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/browser_tools_normal_ash.png b/chrome/app/theme/default_100_percent/common/browser_tools_normal_aura.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/browser_tools_normal_ash.png
rename to chrome/app/theme/default_100_percent/common/browser_tools_normal_aura.png
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/save_password.png b/chrome/app/theme/default_100_percent/common/save_password.png
new file mode 100644
index 0000000..368127e
--- /dev/null
+++ b/chrome/app/theme/default_100_percent/common/save_password.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/chromium/ic_gplus_color_16.png b/chrome/app/theme/default_200_percent/chromium/ic_gplus_color_16.png
new file mode 100644
index 0000000..f940834
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/chromium/ic_gplus_color_16.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/browser_tools_badge_ash.png b/chrome/app/theme/default_200_percent/common/browser_tools_badge_aura.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/browser_tools_badge_ash.png
rename to chrome/app/theme/default_200_percent/common/browser_tools_badge_aura.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/browser_tools_normal_ash.png b/chrome/app/theme/default_200_percent/common/browser_tools_normal_aura.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/browser_tools_normal_ash.png
rename to chrome/app/theme/default_200_percent/common/browser_tools_normal_aura.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/save_password.png b/chrome/app/theme/default_200_percent/common/save_password.png
new file mode 100644
index 0000000..31341dd
--- /dev/null
+++ b/chrome/app/theme/default_200_percent/common/save_password.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 1dbbf35..ed45386 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -76,7 +76,7 @@
       <structure type="chrome_scaled_image" name="IDR_AUTOFILL_GENERATED_CARD" file="common/autofill_generated_card.png" />
       <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON" file="common/autofill_tooltip_icon.png" />
       <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON_H" file="common/autofill_tooltip_icon_hover.png" />
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_BACK" file="back.png" />
         <structure type="chrome_scaled_image" name="IDR_BACK_D" file="back_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_BACK_H" file="back_hover.png" />
@@ -84,7 +84,7 @@
       </if>
       <!-- TODO(jamescook): Update all Chrome platforms to use the new art and metrics
            from Ash, crbug.com/118228 -->
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_BACK" file="common/browser_back_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_BACK_D" file="common/browser_back_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_BACK_H" file="common/browser_back_hover.png" />
@@ -100,6 +100,7 @@
       <structure type="chrome_scaled_image" name="IDR_BLOCKED_JAVASCRIPT" file="common/blocked_script.png" />
       <structure type="chrome_scaled_image" name="IDR_BLOCKED_LOCATION" file="common/blocked_location.png" />
       <structure type="chrome_scaled_image" name="IDR_BLOCKED_MEDIA" file="common/blocked_media.png" />
+      <structure type="chrome_scaled_image" name="IDR_SAVE_PASSWORD" file="common/infobar_savepassword.png" />
       <structure type="chrome_scaled_image" name="IDR_BLOCKED_MICROPHONE" file="common/blocked_mic_only.png" />
       <structure type="chrome_scaled_image" name="IDR_BLOCKED_MIDI_SYSEX" file="common/blocked_midi.png" />
       <structure type="chrome_scaled_image" name="IDR_BLOCKED_MOUSE_CURSOR" file="common/blocked_mouse_cursor.png" />
@@ -110,10 +111,10 @@
       <structure type="chrome_scaled_image" name="IDR_BLOCKED_PPAPI_BROKER" file="common/blocked_pepper_broker.png" />
       <structure type="chrome_scaled_image" name="IDR_BOOKMARKS_FAVICON" file="common/favicon_bookmarks.png" />
       <structure type="chrome_scaled_image" name="IDR_BOOKMARK_BAR_CHEVRONS" file="common/chevron.png" />
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_BOOKMARK_BAR_FOLDER" file="mac/bookmark_bar_folder.png" />
       </if>
-      <if expr="not is_macosx">
+      <if expr="not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_BOOKMARK_BAR_FOLDER" file="common/bookmark_bar_folder.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_BOOKMARK_BAR_APPS_SHORTCUT" file="common/apps_bookmark_bar_icon.png" />
@@ -122,12 +123,12 @@
         <structure type="chrome_scaled_image" name="IDR_BUTTON_USER_IMAGE_RECORD_VIDEO" file="record_video.png" />
         <structure type="chrome_scaled_image" name="IDR_BUTTON_USER_IMAGE_TAKE_PHOTO" file="take_photo.png" />
       </if>
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION" file="browser_action.png" />
         <structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION_H" file="browser_action_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION_P" file="browser_action_pressed.png" />
       </if>
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION" file="common/browser_action_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION_H" file="common/browser_action_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_BROWSER_ACTION_P" file="common/browser_action_pressed.png" />
@@ -317,13 +318,13 @@
       <structure type="chrome_scaled_image" name="IDR_FIND_DLG_MIDDLE_BACKGROUND" file="common/find_dlg_middle_bg.png" />
       <structure type="chrome_scaled_image" name="IDR_FIND_DLG_RIGHT_BACKGROUND" file="common/find_dlg_right_bg.png" />
       <structure type="chrome_scaled_image" name="IDR_FLAGS_FAVICON" file="common/favicon_flags.png" />
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_FORWARD" file="forward.png" />
         <structure type="chrome_scaled_image" name="IDR_FORWARD_D" file="forward_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_FORWARD_H" file="forward_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_FORWARD_P" file="forward_pressed.png" />
       </if>
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_FORWARD" file="common/browser_forward_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_FORWARD_D" file="common/browser_forward_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_FORWARD_H" file="common/browser_forward_hover.png" />
@@ -332,30 +333,31 @@
       <structure type="chrome_scaled_image" name="IDR_FROZEN_TAB_ICON" file="frozen_tab.png" />
       <structure type="chrome_scaled_image" name="IDR_FULLSCREEN_MENU_BUTTON" file="fullscreen_menu_button.png" />
       <structure type="chrome_scaled_image" name="IDR_GEOLOCATION_INFOBAR_ICON" file="infobar_geolocation.png" />
+      <structure type="chrome_scaled_image" name="IDR_GUEST_ICON" file="common/guest_icon.png" />
       <if expr="pp_ifdef('chromeos')">
         <structure type="chrome_scaled_image" name="IDR_HELP_MENU" file="help_16.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_HISTORY_FAVICON" file="common/favicon_history.png" />
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_HOME" file="home.png" />
       </if>
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_HOME" file="common/browser_home_normal.png" />
       </if>
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_HOME_H" file="home_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_HOME_P" file="home_pressed.png" />
       </if>
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_HOME_H" file="common/browser_home_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_HOME_P" file="common/browser_home_pressed.png" />
       </if>
-      <if expr="not is_android and not pp_ifdef('ios')">
+      <if expr="not is_android and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_ICON_ADD_USER24" file="icon_add_user24.png" />
         <structure type="chrome_scaled_image" name="IDR_ICON_ADD_USER_WHITE" file="icon_add_user_white.png" />
         <structure type="chrome_scaled_image" name="IDR_ICON_GUEST_WHITE" file="icon_guest_white.png" />
       </if>
-      <if expr="not is_android and not pp_ifdef('ios') and not pp_ifdef('chromeos')">
+      <if expr="not is_android and not is_ios and not pp_ifdef('chromeos')">
         <!-- TODO(noms): Remove this once local profile avatars are migrated -->
         <structure type="chrome_scaled_image" name="IDR_USER_MANAGER_DEFAULT_AVATAR" file="avatar_user_color.png" />
       </if>
@@ -490,13 +492,13 @@
         <structure type="chrome_scaled_image" name="IDR_NETWORK_SHOW_PASSWORD" file="cros/network_show_password.png" />
         <structure type="chrome_scaled_image" name="IDR_NETWORK_SHOW_PASSWORD_HOVER" file="cros/network_show_password_hover.png" />
       </if>
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON" file="newtab.png" />
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON_H" file="newtab_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON_MASK" file="newtab_button_mask.png" />
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON_P" file="newtab_pressed.png" />
       </if>
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON" file="common/newtab_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON_H" file="common/newtab_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_NEWTAB_BUTTON_MASK" file="common/newtab_button_mask.png" />
@@ -564,10 +566,10 @@
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_HTTPS_WARNING" file="common/omnibox_https_warning.png" />
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_HTTP_DARK" file="common/omnibox_http_dark.png" />
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_HTTP_SELECTED" file="common/omnibox_http_selected.png" />
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_OMNIBOX_KEYWORD_HINT_TAB" file="mac/omnibox_keyword_hint_tab.png" />
       </if>
-      <if expr="not is_macosx">
+      <if expr="not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_OMNIBOX_KEYWORD_HINT_TAB" file="common/omnibox_keyword_hint_tab.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_MIC_SEARCH" file="common/omnibox_mic_search.png" />
@@ -600,7 +602,7 @@
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_TTS" file="common/omnibox_tts.png" />
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_TTS_DARK" file="common/omnibox_tts_dark.png" />
       <structure type="chrome_scaled_image" name="IDR_OMNIBOX_TTS_SELECTED" file="common/omnibox_tts_selected.png" />
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_OTR_ICON" file="common/otr_icon.png" />
       </if>
       <if expr="pp_ifdef('toolkit_views')">
@@ -614,7 +616,7 @@
           </if>
         </if>
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_OTR_ICON" file="mac/otr_icon.png" />
       </if>
       <if expr="context.startswith('default_')">
@@ -657,7 +659,7 @@
         <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_NAME_48" file="google_chrome/product_logo_name_48.png" />
         <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_WHITE" file="google_chrome/product_logo_white.png" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_0" file="profile_avatar_generic_mac.png" />
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_1" file="profile_avatar_generic_aqua_mac.png" />
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_2" file="profile_avatar_generic_blue_mac.png" />
@@ -685,7 +687,7 @@
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_24" file="profile_avatar_note_mac.png" />
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_25" file="profile_avatar_sun_cloud_mac.png" />
       </if>
-      <if expr="not is_macosx">
+      <if expr="not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_0" file="profile_avatar_generic.png" />
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_1" file="profile_avatar_generic_aqua.png" />
         <structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_2" file="profile_avatar_generic_blue.png" />
@@ -719,13 +721,13 @@
       </if>
       <structure type="chrome_scaled_image" name="IDR_PROFILE_SELECTED" file="common/profile_selected.png" />
       <structure type="chrome_scaled_image" name="IDR_REGISTER_PROTOCOL_HANDLER" file="register_protocol_handler.png" />
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_RELOAD" file="reload.png" />
         <structure type="chrome_scaled_image" name="IDR_RELOAD_H" file="reload_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_RELOAD_P" file="reload_pressed.png" />
         <structure type="chrome_scaled_image" name="IDR_RELOAD_DIMMED" file="reload_dimmed.png" />
       </if>
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_RELOAD" file="common/browser_reload_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_RELOAD_D" file="common/browser_reload_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_RELOAD_H" file="common/browser_reload_hover.png" />
@@ -755,7 +757,7 @@
         <structure type="chrome_scaled_image" name="IDR_SPEECH_INPUT_TRAY_MIC_EMPTY" file="speech_input_tray_linux_mic_empty.png" />
         <structure type="chrome_scaled_image" name="IDR_SPEECH_INPUT_TRAY_MIC_FULL" file="speech_input_tray_linux_mic_full.png" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_SPEECH_INPUT_TRAY_MIC_EMPTY" file="speech_input_tray_macosx_mic_empty.png" />
         <structure type="chrome_scaled_image" name="IDR_SPEECH_INPUT_TRAY_MIC_FULL" file="speech_input_tray_macosx_mic_full.png" />
       </if>
@@ -769,13 +771,13 @@
       <structure type="chrome_scaled_image" name="IDR_SHARE" file="share.png" />
       <structure type="chrome_scaled_image" name="IDR_STAR" file="star.png" />
       <structure type="chrome_scaled_image" name="IDR_STAR_LIT" file="star_lit.png" />
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_STOP" file="stop.png" />
         <structure type="chrome_scaled_image" name="IDR_STOP_D" file="stop_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_STOP_H" file="stop_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_STOP_P" file="stop_pressed.png" />
       </if>
-      <if expr="pp_ifdef('toolkit_views') or is_macosx">
+      <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_STOP" file="common/browser_stop_normal.png" />
         <structure type="chrome_scaled_image" name="IDR_STOP_D" file="common/browser_stop_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_STOP_H" file="common/browser_stop_hover.png" />
@@ -785,7 +787,7 @@
         <structure type="chrome_scaled_image" name="IDR_SUPERVISED_ILLUSTRATION_START" file="cros/supervised_illustration_start.png" />
         <structure type="chrome_scaled_image" name="IDR_SUPERVISED_ILLUSTRATION_DONE" file="cros/supervised_illsutration_done.png" />
       </if>
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_CENTER" file="tab_active_center.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_LEFT" file="tab_active_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_RIGHT" file="tab_active_right.png" />
@@ -795,7 +797,7 @@
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_LEFT" file="common/tab_active_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_RIGHT" file="common/tab_active_right.png" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_CENTER" file="mac/tab_active_center.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_LEFT" file="mac/tab_active_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ACTIVE_RIGHT" file="mac/tab_active_right.png" />
@@ -806,7 +808,7 @@
       <!-- Note: Tab close buttons are not traditional buttons.  Tab close buttons
            fill a background with a color from the theme, tile IDR_CLOSE_1 over it,
            then apply IDR_CLOSE_1_MASK.  See chrome/browser/ui/views/tabs/tab.cc -->
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_TAB_ALPHA_LEFT" file="tab_alpha_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ALPHA_RIGHT" file="tab_alpha_right.png" />
       </if>
@@ -814,7 +816,7 @@
         <structure type="chrome_scaled_image" name="IDR_TAB_ALPHA_LEFT" file="common/tab_alpha_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ALPHA_RIGHT" file="common/tab_alpha_right.png" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_TAB_ALPHA_LEFT" file="mac/tab_alpha_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_ALPHA_RIGHT" file="mac/tab_alpha_right.png" />
       </if>
@@ -824,7 +826,7 @@
       <structure type="chrome_scaled_image" name="IDR_CLOSE_1_P" file="common/close_1_pressed.png" />
       <structure type="chrome_scaled_image" name="IDR_TAB_DROP_DOWN" file="tab_drop_down.png" />
       <structure type="chrome_scaled_image" name="IDR_TAB_DROP_UP" file="tab_drop_up.png" />
-      <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_CENTER" file="tab_inactive_center.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_LEFT" file="tab_inactive_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_RIGHT" file="tab_inactive_right.png" />
@@ -834,7 +836,7 @@
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_LEFT" file="common/tab_inactive_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_RIGHT" file="common/tab_inactive_right.png" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_CENTER" file="mac/tab_inactive_center.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_LEFT" file="mac/tab_inactive_left.png" />
         <structure type="chrome_scaled_image" name="IDR_TAB_INACTIVE_RIGHT" file="mac/tab_inactive_right.png" />
@@ -869,7 +871,7 @@
       <structure type="chrome_scaled_image" name="IDR_THEME_NTP_ATTRIBUTION" file="notused.png" />
       <structure type="chrome_scaled_image" name="IDR_THEME_NTP_BACKGROUND" file="common/ntp_background.png" />
       <structure type="chrome_scaled_image" name="IDR_THEME_NTP_BACKGROUND_WHITE" file="common/ntp_background_white.png" />
-      <if expr="not pp_ifdef('use_ash') and not is_macosx">
+      <if expr="not pp_ifdef('use_ash') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_THEME_TAB_BACKGROUND" file="theme_tab_background.png" />
         <structure type="chrome_scaled_image" name="IDR_THEME_TAB_BACKGROUND_INCOGNITO" file="theme_tab_background_incognito.png" />
       </if>
@@ -882,12 +884,12 @@
           <structure type="chrome_scaled_image" name="IDR_THEME_TAB_BACKGROUND_INCOGNITO_WIN" file="theme_tab_background_incognito.png" />
         </if>
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_THEME_TAB_BACKGROUND" file="mac/theme_default_inactive.png" />
         <structure type="chrome_scaled_image" name="IDR_THEME_TAB_BACKGROUND_INACTIVE" file="mac/theme_default_inactive_background.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_THEME_TAB_BACKGROUND_V" file="theme_tab_background_glass.png" />
-      <if expr="not pp_ifdef('use_ash') and not is_macosx">
+      <if expr="not pp_ifdef('use_ash') and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_THEME_TOOLBAR" file="theme_toolbar_default.png" />
       </if>
       <if expr="pp_ifdef('use_ash')">
@@ -897,7 +899,7 @@
           <structure type="chrome_scaled_image" name="IDR_THEME_TOOLBAR_WIN" file="theme_toolbar_default.png" />
         </if>
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_THEME_TOOLBAR" file="mac/theme_default_active.png" />
         <structure type="chrome_scaled_image" name="IDR_THEME_TOOLBAR_INACTIVE" file="mac/theme_default_active_background.png" />
       </if>
@@ -916,25 +918,25 @@
         <structure type="chrome_scaled_image" name="IDR_TOOLBAR_SHADE_RIGHT" file="common/toolbar_shade_right.png" />
         <structure type="chrome_scaled_image" name="IDR_TOOLBAR_SHADE_TOP" file="common/toolbar_shade_top.png" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_TOOLBAR_SHADE_TOP" file="mac/toolbar_shade_top.png" />
       </if>
       <!-- For non-chromeos aura the tools menu button in the normal state is slightly different -->
-      <if expr="not pp_ifdef('use_ash') or pp_ifdef('chromeos')">
-        <if expr="not pp_ifdef('toolkit_views') and not is_macosx">
+      <if expr="not pp_ifdef('use_aura') or pp_ifdef('chromeos')">
+        <if expr="not pp_ifdef('toolkit_views') and not is_macosx and not is_ios">
           <structure type="chrome_scaled_image" name="IDR_TOOLS" file="tools.png" />
           <structure type="chrome_scaled_image" name="IDR_TOOLS_H" file="tools_hover.png" />
           <structure type="chrome_scaled_image" name="IDR_TOOLS_P" file="tools_pressed.png" />
         </if>
-        <if expr="pp_ifdef('toolkit_views') or is_macosx">
+        <if expr="pp_ifdef('toolkit_views') or is_macosx or is_ios">
           <structure type="chrome_scaled_image" name="IDR_TOOLS" file="common/browser_tools_normal.png" />
           <structure type="chrome_scaled_image" name="IDR_TOOLS_H" file="common/browser_tools_hover.png" />
           <structure type="chrome_scaled_image" name="IDR_TOOLS_P" file="common/browser_tools_pressed.png" />
         </if>
       </if>
-      <if expr="pp_ifdef('use_ash') and not pp_ifdef('chromeos')">
-        <structure type="chrome_scaled_image" name="IDR_TOOLS_BADGE_ASH" file="common/browser_tools_badge_ash.png" />
-        <structure type="chrome_scaled_image" name="IDR_TOOLS" file="common/browser_tools_normal_ash.png" />
+      <if expr="pp_ifdef('use_aura') and not pp_ifdef('chromeos')">
+        <structure type="chrome_scaled_image" name="IDR_TOOLS_BADGE_AURA" file="common/browser_tools_badge_aura.png" />
+        <structure type="chrome_scaled_image" name="IDR_TOOLS" file="common/browser_tools_normal_aura.png" />
         <structure type="chrome_scaled_image" name="IDR_TOOLS_H" file="common/browser_tools_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_TOOLS_P" file="common/browser_tools_pressed.png" />
       </if>
@@ -946,7 +948,7 @@
       <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_UP_ARROW" file="common/up_arrow.png" />
-      <if expr="not is_macosx and not pp_ifdef('toolkit_views')">
+      <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" />
         <structure type="chrome_scaled_image" name="IDR_UPDATE_BADGE2" file="update_badge2.png" />
         <structure type="chrome_scaled_image" name="IDR_UPDATE_BADGE3" file="update_badge3.png" />
diff --git a/chrome/app/theme/touch_100_percent/common/browser_tools_normal_ash.png b/chrome/app/theme/touch_100_percent/common/browser_tools_normal_aura.png
similarity index 100%
rename from chrome/app/theme/touch_100_percent/common/browser_tools_normal_ash.png
rename to chrome/app/theme/touch_100_percent/common/browser_tools_normal_aura.png
Binary files differ
diff --git a/chrome/app/theme/touch_140_percent/common/browser_tools_normal_ash.png b/chrome/app/theme/touch_140_percent/common/browser_tools_normal_aura.png
similarity index 100%
rename from chrome/app/theme/touch_140_percent/common/browser_tools_normal_ash.png
rename to chrome/app/theme/touch_140_percent/common/browser_tools_normal_aura.png
Binary files differ
diff --git a/chrome/app/theme/touch_180_percent/common/browser_tools_normal_ash.png b/chrome/app/theme/touch_180_percent/common/browser_tools_normal_aura.png
similarity index 100%
rename from chrome/app/theme/touch_180_percent/common/browser_tools_normal_ash.png
rename to chrome/app/theme/touch_180_percent/common/browser_tools_normal_aura.png
Binary files differ
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 09f2cd0..6e3345c 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -12,6 +12,7 @@
   "+components/browser_context_keyed_service",
   "+components/nacl/common",
   "+components/navigation_interception",
+  "+components/policy",
   "+components/user_prefs",
   "+components/visitedlink/browser",
   "+components/webdata",
@@ -49,6 +50,9 @@
   "+win8/viewer",
   "+xib_localizers", # For generated mac localization helpers
 
+  # Unsafe to use from //chrome, see http://goo.gl/QQG5wo
+  "-content/public/test/test_browser_context.h",
+
   # TODO(stuartmorgan): Remove these by refactoring necessary code out of
   # webkit/. See crbug.com/146251
   # DO NOT ADD ANY MORE ITEMS TO THE LIST BELOW!
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0f597a5..59ecd61 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -10,6 +10,7 @@
 #include <set>
 #include <utility>
 
+#include "ash/ash_switches.h"
 #include "base/command_line.h"
 #include "base/memory/singleton.h"
 #include "base/strings/string_number_conversions.h"
@@ -513,11 +514,11 @@
     MULTI_VALUE_TYPE(kNaClDebugMaskChoices)
   },
   {
-    "enable-pnacl",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_ENABLE_PNACL_NAME,
-    IDS_FLAGS_ENABLE_PNACL_DESCRIPTION,
+    "disable-pnacl",  // FLAGS:RECORD_UMA
+    IDS_FLAGS_PNACL_NAME,
+    IDS_FLAGS_PNACL_DESCRIPTION,
     kOsDesktop,
-    SINGLE_VALUE_TYPE(switches::kEnablePnacl)
+    ENABLE_DISABLE_VALUE_TYPE("", switches::kDisablePnacl)
   },
   {
     "extension-apis",  // FLAGS:RECORD_UMA
@@ -591,13 +592,6 @@
     SINGLE_VALUE_TYPE(switches::kNoPings)
   },
   {
-    "experimental-location-features",  // FLAGS:RECORD_UMA
-    IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_NAME,
-    IDS_FLAGS_EXPERIMENTAL_LOCATION_FEATURES_DESCRIPTION,
-    kOsMac,
-    SINGLE_VALUE_TYPE(switches::kExperimentalLocationFeatures)
-  },
-  {
     "tab-groups-context-menu",
     IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_NAME,
     IDS_FLAGS_TAB_GROUPS_CONTEXT_MENU_DESCRIPTION,
@@ -782,20 +776,6 @@
     kOsWin | kOsLinux | kOsCrOS,
     SINGLE_VALUE_TYPE(ash::switches::kAshDisableAutoMaximizing)
   },
-  {
-    "ash-disable-auto-window-placement",
-    IDS_FLAGS_ASH_AUTO_WINDOW_PLACEMENT_NAME,
-    IDS_FLAGS_ASH_AUTO_WINDOW_PLACEMENT_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshDisableAutoWindowPlacement)
-  },
-  {
-    "ash-disable-per-app-launcher",
-    IDS_FLAGS_ASH_DISABLE_PER_APP_LAUNCHER_NAME,
-    IDS_FLAGS_ASH_DISABLE_PER_APP_LAUNCHER_DESCRIPTION,
-    kOsWin | kOsLinux | kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshDisablePerAppLauncher)
-  },
 #endif
   {
     "per-tile-painting",
@@ -1009,7 +989,9 @@
     IDS_FLAGS_SHOW_SHELF_ALIGNMENT_MENU_NAME,
     IDS_FLAGS_SHOW_SHELF_ALIGNMENT_MENU_DESCRIPTION,
     kOsAll,
-    SINGLE_VALUE_TYPE(switches::kShowShelfAlignmentMenu)
+    ENABLE_DISABLE_VALUE_TYPE(
+        ash::switches::kShowShelfAlignmentMenu,
+        ash::switches::kHideShelfAlignmentMenu)
   },
   {
     "disable-minimize-on-second-launcher-item-click",
@@ -1256,7 +1238,7 @@
     "enable-interactive-autocomplete",
     IDS_FLAGS_ENABLE_INTERACTIVE_AUTOCOMPLETE_NAME,
     IDS_FLAGS_ENABLE_INTERACTIVE_AUTOCOMPLETE_DESCRIPTION,
-    kOsWin | kOsCrOS | kOsMac,
+    kOsWin | kOsCrOS | kOsAndroid | kOsMac,
     ENABLE_DISABLE_VALUE_TYPE(
         autofill::switches::kEnableInteractiveAutocomplete,
         autofill::switches::kDisableInteractiveAutocomplete)
@@ -1291,6 +1273,15 @@
         switches::kTouchSideBezels, "0")
   },
   {
+    "enable-no-touch-to-renderer-while-scrolling",
+    IDS_FLAGS_ENABLE_NO_TOUCH_TO_RENDERER_WHILE_SCROLLING_NAME,
+    IDS_FLAGS_ENABLE_NO_TOUCH_TO_RENDERER_WHILE_SCROLLING_DESCRIPTION,
+    kOsDesktop,
+    ENABLE_DISABLE_VALUE_TYPE_AND_VALUE(
+        switches::kNoTouchToRendererWhileScrolling, "1",
+        switches::kNoTouchToRendererWhileScrolling, "0")
+  },
+  {
     "enable-touch-drag-drop",
     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_NAME,
     IDS_FLAGS_ENABLE_TOUCH_DRAG_DROP_DESCRIPTION,
@@ -1598,15 +1589,38 @@
     kOsMac | kOsWin | kOsLinux,
     SINGLE_VALUE_TYPE(switches::kGaiaProfileInfo)
   },
-#if defined(OS_WIN)
   {
     "disable-app-launcher",
     IDS_FLAGS_DISABLE_APP_LIST_NAME,
     IDS_FLAGS_DISABLE_APP_LIST_DESCRIPTION,
-    kOsAll,
+    kOsMac | kOsWin,
     SINGLE_VALUE_TYPE(switches::kDisableAppList)
   },
+#if defined(OS_CHROMEOS)
+  {
+    "disable-user-image-sync",
+    IDS_FLAGS_DISABLE_USER_IMAGE_SYNC_NAME,
+    IDS_FLAGS_DISABLE_USER_IMAGE_SYNC_DESCRIPTION,
+    kOsCrOS,
+    SINGLE_VALUE_TYPE(chromeos::switches::kDisableUserImageSync)
+  },
 #endif
+#if defined(OS_ANDROID)
+  {
+    "enable-accessibility-tab-switcher",
+    IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_NAME,
+    IDS_FLAGS_ENABLE_ACCESSIBILITY_TAB_SWITCHER_DESCRIPTION,
+    kOsAndroid,
+    SINGLE_VALUE_TYPE(switches::kEnableAccessibilityTabSwitcher)
+  },
+#endif
+  {
+    "enable-batched-shutdown",
+    IDS_FLAGS_ENABLE_BATCHED_SHUTDOWN_NAME,
+    IDS_FLAGS_ENABLE_BATCHED_SHUTDOWN_DESCRIPTION,
+    kOsDesktop,
+    SINGLE_VALUE_TYPE(switches::kEnableBatchedShutdown)
+  },
 };
 
 const Experiment* experiments = kExperiments;
diff --git a/chrome/browser/accessibility/accessibility_events.cc b/chrome/browser/accessibility/accessibility_events.cc
index 53c8c8d..0b31906 100644
--- a/chrome/browser/accessibility/accessibility_events.cc
+++ b/chrome/browser/accessibility/accessibility_events.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/accessibility/accessibility_events.h"
 
 #include "base/values.h"
-
+#include "chrome/browser/accessibility/accessibility_extension_api.h"
 #include "chrome/browser/accessibility/accessibility_extension_api_constants.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
@@ -15,16 +15,40 @@
 
 namespace keys = extension_accessibility_api_constants;
 
-void SendAccessibilityNotification(int type, AccessibilityEventInfo* info) {
+void SendControlAccessibilityNotification(
+  ui::AccessibilityTypes::Event event,
+  AccessibilityControlInfo* info) {
   Profile *profile = info->profile();
   if (profile->ShouldSendAccessibilityEvents()) {
-    content::NotificationService::current()->Notify(
-        type,
-        content::Source<Profile>(profile),
-        content::Details<AccessibilityEventInfo>(info));
+    ExtensionAccessibilityEventRouter::GetInstance()->HandleControlEvent(
+        event,
+        info);
   }
 }
 
+void SendMenuAccessibilityNotification(
+  ui::AccessibilityTypes::Event event,
+  AccessibilityMenuInfo* info) {
+  Profile *profile = info->profile();
+  if (profile->ShouldSendAccessibilityEvents()) {
+    ExtensionAccessibilityEventRouter::GetInstance()->HandleMenuEvent(
+        event,
+        info);
+  }
+}
+
+void SendWindowAccessibilityNotification(
+  ui::AccessibilityTypes::Event event,
+  AccessibilityWindowInfo* info) {
+  Profile *profile = info->profile();
+  if (profile->ShouldSendAccessibilityEvents()) {
+    ExtensionAccessibilityEventRouter::GetInstance()->HandleWindowEvent(
+        event,
+        info);
+  }
+}
+
+
 AccessibilityControlInfo::AccessibilityControlInfo(
     Profile* profile, const std::string& name)
     : AccessibilityEventInfo(profile),
diff --git a/chrome/browser/accessibility/accessibility_events.h b/chrome/browser/accessibility/accessibility_events.h
index 6c5cf86..d028c7d 100644
--- a/chrome/browser/accessibility/accessibility_events.h
+++ b/chrome/browser/accessibility/accessibility_events.h
@@ -7,19 +7,31 @@
 
 #include <string>
 #include "base/compiler_specific.h"
+#include "ui/base/accessibility/accessibility_types.h"
 
-class AccessibilityEventInfo;
+class AccessibilityControlInfo;
+class AccessibilityMenuInfo;
+class AccessibilityWindowInfo;
 class Profile;
 
 namespace base {
 class DictionaryValue;
 }
 
-// Use the NotificationService to post the given accessibility
-// notification type with AccessibilityEventInfo details to any
-// listeners.  Will not send if the profile's pause level is nonzero
-// (using profile->PauseAccessibilityEvents).
-void SendAccessibilityNotification(int type, AccessibilityEventInfo* info);
+// Notify the ExtensionAccessibilityEventRouter of the given accessibility
+// event and AccessibilityEventInfo details. Will not send if the profile's
+// pause level is nonzero (using profile->PauseAccessibilityEvents).
+void SendControlAccessibilityNotification(
+    ui::AccessibilityTypes::Event event,
+    AccessibilityControlInfo* info);
+
+void SendMenuAccessibilityNotification(
+    ui::AccessibilityTypes::Event event,
+    AccessibilityMenuInfo* info);
+
+void SendWindowAccessibilityNotification(
+    ui::AccessibilityTypes::Event event,
+    AccessibilityWindowInfo* info);
 
 // Abstract parent class for accessibility event information passed to event
 // listeners.
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc
index 033a843..9726a5d 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -8,7 +8,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/accessibility/accessibility_extension_api_constants.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -17,11 +16,13 @@
 #include "chrome/browser/infobars/infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/experimental_accessibility.h"
 #include "content/public/browser/browser_accessibility_state.h"
-#include "content/public/browser/notification_service.h"
 #include "extensions/common/error_utils.h"
 
 namespace keys = extension_accessibility_api_constants;
+namespace experimental_accessibility =
+    extensions::api::experimental_accessibility;
 
 // Returns the AccessibilityControlInfo serialized into a JSON string,
 // consisting of an array of a single object of type AccessibilityObject,
@@ -43,68 +44,10 @@
 
 ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter()
     : enabled_(false) {
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_OPENED,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_CLOSED,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_ACTION,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_ACCESSIBILITY_TEXT_CHANGED,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED,
-                 content::NotificationService::AllSources());
 }
 
 ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() {
-}
-
-void ExtensionAccessibilityEventRouter::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  switch (type) {
-    case chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_OPENED:
-      OnWindowOpened(
-          content::Details<const AccessibilityWindowInfo>(details).ptr());
-      break;
-    case chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_CLOSED:
-      OnWindowClosed(
-          content::Details<const AccessibilityWindowInfo>(details).ptr());
-      break;
-    case chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED:
-      OnControlFocused(
-          content::Details<const AccessibilityControlInfo>(details).ptr());
-      break;
-    case chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_ACTION:
-      OnControlAction(
-          content::Details<const AccessibilityControlInfo>(details).ptr());
-      break;
-    case chrome::NOTIFICATION_ACCESSIBILITY_TEXT_CHANGED:
-      OnTextChanged(
-          content::Details<const AccessibilityControlInfo>(details).ptr());
-      break;
-    case chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED:
-      OnMenuOpened(
-          content::Details<const AccessibilityMenuInfo>(details).ptr());
-      break;
-    case chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED:
-      OnMenuClosed(
-          content::Details<const AccessibilityMenuInfo>(details).ptr());
-      break;
-    default:
-      NOTREACHED();
-  }
+  control_event_callback_.Reset();
 }
 
 void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled) {
@@ -115,16 +58,68 @@
   return enabled_;
 }
 
+void ExtensionAccessibilityEventRouter::SetControlEventCallbackForTesting(
+    ControlEventCallback control_event_callback) {
+  DCHECK(control_event_callback_.is_null());
+  control_event_callback_ = control_event_callback;
+}
+
+void ExtensionAccessibilityEventRouter::ClearControlEventCallback() {
+  control_event_callback_.Reset();
+}
+
+void ExtensionAccessibilityEventRouter::HandleWindowEvent(
+    ui::AccessibilityTypes::Event event,
+    const AccessibilityWindowInfo* info) {
+  if (event == ui::AccessibilityTypes::EVENT_ALERT)
+    OnWindowOpened(info);
+}
+
+void ExtensionAccessibilityEventRouter::HandleMenuEvent(
+    ui::AccessibilityTypes::Event event,
+    const AccessibilityMenuInfo* info) {
+  switch (event) {
+    case ui::AccessibilityTypes::EVENT_MENUSTART:
+    case ui::AccessibilityTypes::EVENT_MENUPOPUPSTART:
+      OnMenuOpened(info);
+      break;
+    case ui::AccessibilityTypes::EVENT_MENUEND:
+    case ui::AccessibilityTypes::EVENT_MENUPOPUPEND:
+      OnMenuClosed(info);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void ExtensionAccessibilityEventRouter::HandleControlEvent(
+    ui::AccessibilityTypes::Event event,
+    const AccessibilityControlInfo* info) {
+  if (!control_event_callback_.is_null())
+    control_event_callback_.Run(event, info);
+
+  switch (event) {
+    case ui::AccessibilityTypes::EVENT_TEXT_CHANGED:
+    case ui::AccessibilityTypes::EVENT_SELECTION_CHANGED:
+      OnTextChanged(info);
+      break;
+    case ui::AccessibilityTypes::EVENT_VALUE_CHANGED:
+      OnControlAction(info);
+      break;
+    case ui::AccessibilityTypes::EVENT_FOCUS:
+      OnControlFocused(info);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
 void ExtensionAccessibilityEventRouter::OnWindowOpened(
     const AccessibilityWindowInfo* info) {
   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
-  DispatchEvent(info->profile(), keys::kOnWindowOpened, args.Pass());
-}
-
-void ExtensionAccessibilityEventRouter::OnWindowClosed(
-    const AccessibilityWindowInfo* info) {
-  scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
-  DispatchEvent(info->profile(), keys::kOnWindowClosed, args.Pass());
+  DispatchEvent(info->profile(),
+                experimental_accessibility::OnWindowOpened::kEventName,
+                args.Pass());
 }
 
 void ExtensionAccessibilityEventRouter::OnControlFocused(
@@ -132,31 +127,41 @@
   last_focused_control_dict_.Clear();
   info->SerializeToDict(&last_focused_control_dict_);
   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
-  DispatchEvent(info->profile(), keys::kOnControlFocused, args.Pass());
+  DispatchEvent(info->profile(),
+                experimental_accessibility::OnControlFocused::kEventName,
+                args.Pass());
 }
 
 void ExtensionAccessibilityEventRouter::OnControlAction(
     const AccessibilityControlInfo* info) {
   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
-  DispatchEvent(info->profile(), keys::kOnControlAction, args.Pass());
+  DispatchEvent(info->profile(),
+                experimental_accessibility::OnControlAction::kEventName,
+                args.Pass());
 }
 
 void ExtensionAccessibilityEventRouter::OnTextChanged(
     const AccessibilityControlInfo* info) {
   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
-  DispatchEvent(info->profile(), keys::kOnTextChanged, args.Pass());
+  DispatchEvent(info->profile(),
+                experimental_accessibility::OnTextChanged::kEventName,
+                args.Pass());
 }
 
 void ExtensionAccessibilityEventRouter::OnMenuOpened(
     const AccessibilityMenuInfo* info) {
   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
-  DispatchEvent(info->profile(), keys::kOnMenuOpened, args.Pass());
+  DispatchEvent(info->profile(),
+                experimental_accessibility::OnMenuOpened::kEventName,
+                args.Pass());
 }
 
 void ExtensionAccessibilityEventRouter::OnMenuClosed(
     const AccessibilityMenuInfo* info) {
   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
-  DispatchEvent(info->profile(), keys::kOnMenuClosed, args.Pass());
+  DispatchEvent(info->profile(),
+                experimental_accessibility::OnMenuClosed::kEventName,
+                args.Pass());
 }
 
 void ExtensionAccessibilityEventRouter::DispatchEvent(
diff --git a/chrome/browser/accessibility/accessibility_extension_api.h b/chrome/browser/accessibility/accessibility_extension_api.h
index d1132c0..61c3930 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.h
+++ b/chrome/browser/accessibility/accessibility_extension_api.h
@@ -12,13 +12,15 @@
 #include "base/values.h"
 #include "chrome/browser/accessibility/accessibility_events.h"
 #include "chrome/browser/extensions/extension_function.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
+#include "ui/base/accessibility/accessibility_types.h"
 
 // Observes the profile and routes accessibility notifications as events
 // to the extension system.
-class ExtensionAccessibilityEventRouter : public content::NotificationObserver {
+class ExtensionAccessibilityEventRouter {
  public:
+  typedef base::Callback<void(ui::AccessibilityTypes::Event,
+                              const AccessibilityControlInfo*)>
+      ControlEventCallback;
   // Single instance of the event router.
   static ExtensionAccessibilityEventRouter* GetInstance();
 
@@ -35,19 +37,30 @@
   void SetAccessibilityEnabled(bool enabled);
   bool IsAccessibilityEnabled() const;
 
+  // Set and remove callbacks (used for testing, to confirm that events are
+  // getting through).
+  void SetControlEventCallbackForTesting(ControlEventCallback callback);
+  void ClearControlEventCallback();
+
+  // Route a window-related accessibility event.
+  void HandleWindowEvent(ui::AccessibilityTypes::Event event,
+                         const AccessibilityWindowInfo* info);
+
+  // Route a menu-related accessibility event.
+  void HandleMenuEvent(ui::AccessibilityTypes::Event event,
+                       const AccessibilityMenuInfo* info);
+
+  // Route a control-related accessibility event.
+  void HandleControlEvent(ui::AccessibilityTypes::Event event,
+                          const AccessibilityControlInfo* info);
+
  private:
   friend struct DefaultSingletonTraits<ExtensionAccessibilityEventRouter>;
 
   ExtensionAccessibilityEventRouter();
   virtual ~ExtensionAccessibilityEventRouter();
 
-  // content::NotificationObserver::Observe.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
   void OnWindowOpened(const AccessibilityWindowInfo* details);
-  void OnWindowClosed(const AccessibilityWindowInfo* details);
   void OnControlFocused(const AccessibilityControlInfo* details);
   void OnControlAction(const AccessibilityControlInfo* details);
   void OnTextChanged(const AccessibilityControlInfo* details);
@@ -58,13 +71,13 @@
                      const char* event_name,
                      scoped_ptr<base::ListValue> event_args);
 
-  // Used for tracking registrations to history service notifications.
-  content::NotificationRegistrar registrar_;
-
   DictionaryValue last_focused_control_dict_;
 
   bool enabled_;
 
+  // For testing.
+  ControlEventCallback control_event_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionAccessibilityEventRouter);
 };
 
diff --git a/chrome/browser/accessibility/accessibility_extension_api_constants.cc b/chrome/browser/accessibility/accessibility_extension_api_constants.cc
index cecaec8..b1be6a3 100644
--- a/chrome/browser/accessibility/accessibility_extension_api_constants.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api_constants.cc
@@ -22,15 +22,6 @@
 const char kMessageKey[] = "message";
 const char kStringValueKey[] = "details.stringValue";
 
-// Events.
-const char kOnWindowOpened[] = "experimental.accessibility.onWindowOpened";
-const char kOnWindowClosed[] = "experimental.accessibility.onWindowClosed";
-const char kOnControlFocused[] = "experimental.accessibility.onControlFocused";
-const char kOnControlAction[] = "experimental.accessibility.onControlAction";
-const char kOnTextChanged[] = "experimental.accessibility.onTextChanged";
-const char kOnMenuOpened[] = "experimental.accessibility.onMenuOpened";
-const char kOnMenuClosed[] = "experimental.accessibility.onMenuClosed";
-
 // Types of controls that can receive accessibility events.
 const char kTypeButton[] = "button";
 const char kTypeCheckbox[] = "checkbox";
diff --git a/chrome/browser/android/bookmarks_bridge.cc b/chrome/browser/android/bookmarks_bridge.cc
new file mode 100644
index 0000000..c957358
--- /dev/null
+++ b/chrome/browser/android/bookmarks_bridge.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/android/bookmarks_bridge.h"
+
+#include "base/android/jni_string.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/profiles/profile_android.h"
+#include "content/public/browser/browser_thread.h"
+#include "jni/BookmarksBridge_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ScopedJavaGlobalRef;
+using content::BrowserThread;
+
+BookmarksBridge::BookmarksBridge(JNIEnv* env,
+                                 jobject obj,
+                                 jobject j_profile)
+    : weak_java_ref_(env, obj) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+  bookmark_model_ = BookmarkModelFactory::GetForProfile(profile);
+  // Registers the notifications we are interested.
+  bookmark_model_->AddObserver(this);
+  if (bookmark_model_->loaded()) {
+    Java_BookmarksBridge_bookmarkModelLoaded(env, obj);
+  }
+}
+
+BookmarksBridge::~BookmarksBridge() {
+  bookmark_model_->RemoveObserver(this);
+}
+
+void BookmarksBridge::Destroy(JNIEnv*, jobject) {
+  delete this;
+}
+
+// static
+bool BookmarksBridge::RegisterBookmarksBridge(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+static jint Init(JNIEnv* env, jobject obj, jobject j_profile) {
+  BookmarksBridge* delegate = new BookmarksBridge(env, obj, j_profile);
+  return reinterpret_cast<jint>(delegate);
+}
+
+void BookmarksBridge::GetBookmarksForFolder(JNIEnv* env,
+                                            jobject obj,
+                                            jlong folder_id,
+                                            jobject j_callback_obj,
+                                            jobject j_result_obj) {
+  DCHECK(bookmark_model_->loaded());
+  const BookmarkNode* folder = GetFolderNodeFromId(folder_id);
+  // Get the folder contents
+  for (int i = 0; i < folder->child_count(); ++i) {
+    const BookmarkNode* node = folder->GetChild(i);
+    ExtractBookmarkNodeInformation(node, j_result_obj);
+  }
+
+  Java_BookmarksCallback_onBookmarksAvailable(
+      env, j_callback_obj, folder->id(), j_result_obj);
+}
+
+void BookmarksBridge::GetCurrentFolderHierarchy(JNIEnv* env,
+                                                jobject obj,
+                                                jlong folder_id,
+                                                jobject j_callback_obj,
+                                                jobject j_result_obj) {
+  DCHECK(bookmark_model_->loaded());
+  const BookmarkNode* folder = GetFolderNodeFromId(folder_id);
+  // Get the folder heirarchy
+  const BookmarkNode* node = folder;
+  while (node) {
+    ExtractBookmarkNodeInformation(node, j_result_obj);
+    node = node->parent();
+  }
+
+  Java_BookmarksCallback_onBookmarksFolderHierarchyAvailable(
+      env, j_callback_obj, folder->id(), j_result_obj);
+}
+
+void BookmarksBridge::ExtractBookmarkNodeInformation(
+    const BookmarkNode* node,
+    jobject j_result_obj) {
+  JNIEnv* env = AttachCurrentThread();
+  const BookmarkNode* parent = node->parent();
+  int64 parent_id = -1;
+  if (parent)
+    parent_id = node->parent()->id();
+  std::string url;
+  if (node->is_url())
+    url = node->url().spec();
+  Java_BookmarksBridge_create(
+      env, j_result_obj, node->id(),
+      ConvertUTF16ToJavaString(env, node->GetTitle()).obj(),
+      ConvertUTF8ToJavaString(env, url).obj(),
+      node->is_folder(), parent_id);
+}
+
+const BookmarkNode* BookmarksBridge::GetFolderNodeFromId(jlong folder_id) {
+  const BookmarkNode* folder;
+  if (folder_id == -1) {
+    folder = bookmark_model_->mobile_node();
+  } else {
+    folder = bookmark_model_->GetNodeByID(
+        static_cast<int64>(folder_id));
+  }
+  if (!folder)
+    folder = bookmark_model_->mobile_node();
+  return folder;
+}
+
+// ------------- Observer-related methods ------------- //
+
+void BookmarksBridge::BookmarkModelChanged() {
+}
+
+void BookmarksBridge::Loaded(BookmarkModel* model, bool ids_reassigned) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
+  if (obj.is_null())
+    return;
+  Java_BookmarksBridge_bookmarkModelLoaded(env, obj.obj());
+}
+
+void BookmarksBridge::BookmarkModelBeingDeleted(BookmarkModel* model) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
+  if (obj.is_null())
+    return;
+  Java_BookmarksBridge_bookmarkModelDeleted(env, obj.obj());
+}
diff --git a/chrome/browser/android/bookmarks_bridge.h b/chrome/browser/android/bookmarks_bridge.h
new file mode 100644
index 0000000..ad8d8f6
--- /dev/null
+++ b/chrome/browser/android/bookmarks_bridge.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_ANDROID_BOOKMARKS_BRIDGE_H_
+#define CHROME_BROWSER_ANDROID_BOOKMARKS_BRIDGE_H_
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_helper.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
+
+class Profile;
+
+// The delegate to fetch bookmarks information for the Android native
+// bookmark page. This fetches the bookmarks, title, urls, folder
+// hierarchy.
+class BookmarksBridge : public BaseBookmarkModelObserver {
+ public:
+  BookmarksBridge(JNIEnv* env, jobject obj, jobject j_profile);
+  void Destroy(JNIEnv*, jobject);
+
+  static bool RegisterBookmarksBridge(JNIEnv* env);
+
+  void GetBookmarksForFolder(JNIEnv* env,
+                             jobject obj,
+                             jlong folder_id,
+                             jobject j_callback_obj,
+                             jobject j_result_obj);
+
+  void GetCurrentFolderHierarchy(JNIEnv* env,
+                                 jobject obj,
+                                 jlong folder_id,
+                                 jobject j_callback_obj,
+                                 jobject j_result_obj);
+
+ private:
+  virtual ~BookmarksBridge();
+
+  void ExtractBookmarkNodeInformation(
+      const BookmarkNode* node,
+      jobject j_result_obj);
+  const BookmarkNode* GetFolderNodeFromId(jlong folder_id);
+
+  // Override BaseBookmarkModelObserver.
+  virtual void BookmarkModelChanged() OVERRIDE;
+  virtual void Loaded(BookmarkModel* model, bool ids_reassigned) OVERRIDE;
+  virtual void BookmarkModelBeingDeleted(BookmarkModel* model) OVERRIDE;
+
+  JavaObjectWeakGlobalRef weak_java_ref_;
+  BookmarkModel* bookmark_model_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarksBridge);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_BOOKMARKS_BRIDGE_H_
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 1675c62..b1afd29 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -7,6 +7,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_registrar.h"
 #include "base/debug/trace_event.h"
+#include "chrome/browser/android/bookmarks_bridge.h"
 #include "chrome/browser/android/chrome_web_contents_delegate_android.h"
 #include "chrome/browser/android/content_view_util.h"
 #include "chrome/browser/android/dev_tools_server.h"
@@ -17,6 +18,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/shortcut_helper.h"
 #include "chrome/browser/android/signin/signin_manager_android.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
@@ -63,6 +65,7 @@
     autofill::AutofillDialogResult::RegisterAutofillDialogResult },
   { "AutofillPopup",
     autofill::AutofillPopupViewAndroid::RegisterAutofillPopupViewAndroid },
+  { "BookmarksBridge", BookmarksBridge::RegisterBookmarksBridge },
   { "CertificateViewer", RegisterCertificateViewer },
   { "ChromeBrowserProvider",
     ChromeBrowserProvider::RegisterChromeBrowserProvider },
@@ -76,6 +79,7 @@
   { "FieldTrialHelper", RegisterFieldTrialHelper },
   { "ForeignSessionHelper",
     ForeignSessionHelper::RegisterForeignSessionHelper },
+  { "ShortcutHelper", ShortcutHelper::RegisterShortcutHelper },
   { "IntentHelper", RegisterIntentHelper },
   { "JavascriptAppModalDialog",
     JavascriptAppModalDialogAndroid::RegisterJavascriptAppModalDialog },
diff --git a/chrome/browser/android/intercept_download_resource_throttle.cc b/chrome/browser/android/intercept_download_resource_throttle.cc
index c901a3a..5700ff9 100644
--- a/chrome/browser/android/intercept_download_resource_throttle.cc
+++ b/chrome/browser/android/intercept_download_resource_throttle.cc
@@ -42,7 +42,7 @@
     return;
 
   GURL url = request_->url_chain().back();
-  if (!url.SchemeIs("http") && !url.SchemeIs("https"))
+  if (!url.SchemeIsHTTPOrHTTPS())
     return;
 
   content::DownloadControllerAndroid::Get()->CreateGETDownload(
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
new file mode 100644
index 0000000..58206be
--- /dev/null
+++ b/chrome/browser/android/shortcut_helper.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/android/shortcut_helper.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/basictypes.h"
+#include "base/location.h"
+#include "base/strings/string16.h"
+#include "base/threading/worker_pool.h"
+#include "chrome/browser/android/tab_android.h"
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/common/cancelable_task_tracker.h"
+#include "chrome/common/render_messages.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/frame_navigate_params.h"
+#include "jni/ShortcutHelper_jni.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/color_analysis.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Adds a shortcut to the current URL to the Android home screen.
+// This proceeds over three phases:
+// 1) The renderer is asked to parse out webapp related meta tags with an async
+//    IPC message.
+// 2) The highest-resolution favicon available is retrieved for use as the
+//    icon on the home screen.
+// 3) A JNI call is made to fire an Intent at the Android launcher, which adds
+//    adds the shortcut.
+class ShortcutBuilder : public content::WebContentsObserver {
+ public:
+  explicit ShortcutBuilder(content::WebContents* web_contents);
+  virtual ~ShortcutBuilder();
+
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+  virtual void WebContentsDestroyed(content::WebContents* contents) OVERRIDE;
+
+ private:
+  void OnDidRetrieveWebappInformation(bool success, bool is_webapp_capable);
+
+  Profile* profile_;
+  GURL url_;
+  string16 title_;
+  bool is_webapp_capable_;
+  CancelableTaskTracker cancelable_task_tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShortcutBuilder);
+};
+
+ShortcutBuilder::ShortcutBuilder(content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents) {
+  profile_ =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  url_ = web_contents->GetURL();
+  title_ = web_contents->GetTitle();
+
+  // Send a message to the renderer to retrieve information about the page.
+  Send(new ChromeViewMsg_RetrieveWebappInformation(routing_id(), url_));
+}
+
+ShortcutBuilder::~ShortcutBuilder() {
+}
+
+void ShortcutBuilder::OnDidRetrieveWebappInformation(bool success,
+                                                     bool is_webapp_capable) {
+  // Abort adding the shortcut if the renderer failed to process the page or
+  // if a navigation was instantiated before the process finished.
+  if (!success) {
+    LOG(ERROR) << "Failed to parse webpage.";
+    return;
+  }
+  is_webapp_capable_ = is_webapp_capable;
+
+  // 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);
+
+  FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
+      profile_, Profile::EXPLICIT_ACCESS);
+
+  favicon_service->GetRawFaviconForURL(
+      favicon_params,
+      ui::SCALE_FACTOR_100P,
+      base::Bind(&ShortcutHelper::FinishAddingShortcut,
+                 url_,
+                 title_,
+                 is_webapp_capable_),
+      &cancelable_task_tracker_);
+}
+
+void ShortcutBuilder::WebContentsDestroyed(content::WebContents* web_contents) {
+  if (cancelable_task_tracker_.HasTrackedTasks())
+    cancelable_task_tracker_.TryCancelAll();
+  delete this;
+}
+
+bool ShortcutBuilder::OnMessageReceived(const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(ShortcutBuilder, message)
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidRetrieveWebappInformation,
+                        OnDidRetrieveWebappInformation)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+}  // namespace
+
+void ShortcutHelper::AddShortcut(content::WebContents* web_contents) {
+  // The ShortcutBuilder deletes itself when it's done.
+  new ShortcutBuilder(web_contents);
+}
+
+bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+void ShortcutHelper::FinishAddingShortcut(
+    const GURL& url,
+    const string16& title,
+    bool is_webapp_capable,
+    const chrome::FaviconBitmapResult& bitmap_result) {
+  base::WorkerPool::PostTask(
+      FROM_HERE,
+      base::Bind(&ShortcutHelper::FinishAddingShortcutInBackground,
+                 url,
+                 title,
+                 is_webapp_capable,
+                 bitmap_result),
+      true);
+}
+
+void ShortcutHelper::FinishAddingShortcutInBackground(
+    const GURL& url,
+    const string16& title,
+    bool is_webapp_capable,
+    const chrome::FaviconBitmapResult& bitmap_result) {
+  DCHECK(base::WorkerPool::RunsTasksOnCurrentThread());
+
+  // Grab the average color from the bitmap.
+  SkColor color = SK_ColorWHITE;
+  SkBitmap favicon_bitmap;
+  if (bitmap_result.is_valid()) {
+    color_utils::GridSampler sampler;
+    color = color_utils::CalculateKMeanColorOfPNG(bitmap_result.bitmap_data,
+                                                  100,
+                                                  665,
+                                                  &sampler);
+    gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(),
+                          bitmap_result.bitmap_data->size(),
+                          &favicon_bitmap);
+  }
+
+  int r_value = SkColorGetR(color);
+  int g_value = SkColorGetG(color);
+  int b_value = SkColorGetB(color);
+
+  // Send the data to the Java side to create the shortcut.
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> java_url =
+      base::android::ConvertUTF8ToJavaString(env, url.spec());
+  ScopedJavaLocalRef<jstring> java_title =
+      base::android::ConvertUTF16ToJavaString(env, title);
+  ScopedJavaLocalRef<jobject> java_bitmap;
+  if (favicon_bitmap.getSize())
+    java_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap);
+
+  Java_ShortcutHelper_addShortcut(env,
+                                  base::android::GetApplicationContext(),
+                                  java_url.obj(),
+                                  java_title.obj(),
+                                  java_bitmap.obj(),
+                                  r_value,
+                                  g_value,
+                                  b_value,
+                                  is_webapp_capable);
+}
+
+// Adds a shortcut to the current URL to the Android home screen, firing
+// background tasks to pull all the data required.
+// Note that we don't actually care about the tab here -- we just want
+// its otherwise inaccessible WebContents.
+static void AddShortcut(JNIEnv* env, jclass clazz, jint tab_android_ptr) {
+  TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr);
+  ShortcutHelper::AddShortcut(tab->GetWebContents());
+}
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h
new file mode 100644
index 0000000..90543da
--- /dev/null
+++ b/chrome/browser/android/shortcut_helper.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 CHROME_BROWSER_ANDROID_SHORTCUT_HELPER_H_
+#define CHROME_BROWSER_ANDROID_SHORTCUT_HELPER_H_
+
+#include "base/android/jni_helper.h"
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/android/tab_android.h"
+
+namespace chrome {
+struct FaviconBitmapResult;
+}  // namespace chrome
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+class GURL;
+
+// Adds a shortcut to the current URL to the Android home screen.
+class ShortcutHelper {
+ public:
+  // 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);
+
+  // Registers JNI hooks.
+  static bool RegisterShortcutHelper(JNIEnv* env);
+
+  // Adds a shortcut to the launcher.
+  static void FinishAddingShortcut(
+      const GURL& url,
+      const base::string16& title,
+      bool is_webapp_capable,
+      const chrome::FaviconBitmapResult& bitmap_result);
+
+ private:
+  // Adds a shortcut to the launcher in the background.
+  static void FinishAddingShortcutInBackground(
+      const GURL& url,
+      const base::string16& title,
+      bool is_webapp_capable,
+      const chrome::FaviconBitmapResult& bitmap_result);
+
+  DISALLOW_COPY_AND_ASSIGN(ShortcutHelper);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_SHORTCUT_HELPER_H_
diff --git a/chrome/browser/android/signin/google_auto_login_helper.cc b/chrome/browser/android/signin/google_auto_login_helper.cc
new file mode 100644
index 0000000..ea4f4bd
--- /dev/null
+++ b/chrome/browser/android/signin/google_auto_login_helper.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 "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
new file mode 100644
index 0000000..aa94945
--- /dev/null
+++ b/chrome/browser/android/signin/google_auto_login_helper.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 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 ca9621c..f4a249a 100644
--- a/chrome/browser/android/signin/signin_manager_android.cc
+++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -11,6 +11,7 @@
 #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"
@@ -198,6 +199,12 @@
                                         java_signin_manager_.obj());
 }
 
+void SigninManagerAndroid::LogInSignedInUser(JNIEnv* env, jobject obj) {
+  // AutoLogin deletes itself.
+  GoogleAutoLoginHelper* autoLogin = new GoogleAutoLoginHelper(profile_);
+  autoLogin->LogIn();
+}
+
 static int Init(JNIEnv* env, jobject obj) {
   SigninManagerAndroid* signin_manager_android =
       new SigninManagerAndroid(env, obj);
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h
index 70edd53..8d2710a 100644
--- a/chrome/browser/android/signin/signin_manager_android.h
+++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -48,6 +48,8 @@
 
   void WipeProfileData(JNIEnv* env, jobject obj);
 
+  void LogInSignedInUser(JNIEnv* env, jobject obj);
+
  private:
   virtual ~SigninManagerAndroid();
 
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 3b5b2b1..d4da9b7 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -78,7 +78,8 @@
   PasswordManager::CreateForWebContentsAndDelegate(
       contents, PasswordManagerDelegateImpl::FromWebContents(contents));
   PrefsTabHelper::CreateForWebContents(contents);
-  prerender::PrerenderTabHelper::CreateForWebContents(contents);
+  prerender::PrerenderTabHelper::CreateForWebContentsWithPasswordManager(
+      contents, PasswordManager::FromWebContents(contents));
   SSLTabHelper::CreateForWebContents(contents);
   TabSpecificContentSettings::CreateForWebContents(contents);
   TranslateTabHelper::CreateForWebContents(contents);
diff --git a/chrome/browser/android/tab_android_test_stubs.cc b/chrome/browser/android/tab_android_test_stubs.cc
index 414ca10..823e59e 100644
--- a/chrome/browser/android/tab_android_test_stubs.cc
+++ b/chrome/browser/android/tab_android_test_stubs.cc
@@ -10,6 +10,8 @@
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/browser/ui/auto_login_infobar_delegate.h"
 #include "chrome/browser/ui/auto_login_infobar_delegate_android.h"
+#include "printing/printing_context.h"
+#include "printing/printing_context_android.h"
 
 // static
 TabAndroid* TabAndroid::FromWebContents(content::WebContents* web_contents) {
@@ -57,3 +59,14 @@
 InfoBar* TranslateInfoBarDelegate::CreateInfoBar(InfoBarService* owner) {
   return NULL;
 }
+
+// static
+printing::PrintingContext* printing::PrintingContext::Create(
+    const std::string& app_locale) {
+  return NULL;
+}
+
+// static
+void printing::PrintingContextAndroid::PdfWritingDone(int fd, bool success) {
+}
+
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index 4e66e35..224374d 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -9,8 +9,8 @@
 #include "base/mac/scoped_nsobject.h"
 #include "chrome/app/chrome_command_ids.h"
 #import "chrome/browser/app_controller_mac.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.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/apps/OWNERS b/chrome/browser/apps/OWNERS
index 8391787..a0d7aac 100644
--- a/chrome/browser/apps/OWNERS
+++ b/chrome/browser/apps/OWNERS
@@ -4,3 +4,8 @@
 koz@chromium.org
 miket@chromium.org
 tapted@chromium.org
+
+per-file web_view_*.cc=fsamuel@chromium.org
+per-file web_view_*.cc=lazyboy@chromium.org
+per-file ad_view_*.cc=fsamuel@chromium.org
+per-file ad_view_*.cc=lazyboy@chromium.org
diff --git a/chrome/browser/apps/ad_view_browsertest.cc b/chrome/browser/apps/ad_view_browsertest.cc
new file mode 100644
index 0000000..7c15b3e
--- /dev/null
+++ b/chrome/browser/apps/ad_view_browsertest.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 "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/test/net/url_request_prepackaged_interceptor.h"
+#include "net/url_request/url_fetcher.h"
+
+class AdViewTest : public extensions::PlatformAppBrowserTest {
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kEnableAdview);
+    command_line->AppendSwitch(switches::kEnableAdviewSrcAttribute);
+  }
+};
+
+// This test checks the "loadcommit" event is called when the page inside an
+// <adview> is loaded.
+IN_PROC_BROWSER_TEST_F(AdViewTest, LoadCommitEventIsCalled) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/loadcommit_event")) << message_;
+}
+
+// This test checks the "loadabort" event is called when the "src" attribute
+// of an <adview> is an invalid URL.
+IN_PROC_BROWSER_TEST_F(AdViewTest, LoadAbortEventIsCalled) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/loadabort_event")) << message_;
+}
+
+// This test checks the page loaded inside an <adview> has the ability to
+// 1) receive "message" events from the application, and 2) use
+// "window.postMessage" to post back a message to the application.
+#if defined(OS_WIN)
+// Flaky, or takes too long time on Win7. (http://crbug.com/230271)
+#define MAYBE_CommitMessageFromAdNetwork DISABLED_CommitMessageFromAdNetwork
+#else
+#define MAYBE_CommitMessageFromAdNetwork CommitMessageFromAdNetwork
+#endif
+IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_CommitMessageFromAdNetwork) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/onloadcommit_ack")) << message_;
+}
+
+// This test checks the page running inside an <adview> has the ability to load
+// and display an image inside an <iframe>.
+// Note: Disabled for initial checkin because the test depends on a binary
+//       file (image035.png) which the trybots don't process correctly when
+//       first checked-in.
+IN_PROC_BROWSER_TEST_F(AdViewTest, DISABLED_DisplayFirstAd) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/display_first_ad")) << message_;
+}
+
+// This test checks that <adview> attributes are also exposed as properties
+// (with the same name and value).
+#if defined(OS_WIN)
+// Flaky on Win XP. (http://crbug.com/264362)
+#define MAYBE_PropertiesAreInSyncWithAttributes \
+    DISABLED_PropertiesAreInSyncWithAttributes
+#else
+#define MAYBE_PropertiesAreInSyncWithAttributes \
+    PropertiesAreInSyncWithAttributes
+#endif
+IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_PropertiesAreInSyncWithAttributes) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/properties_exposed")) << message_;
+}
+
+// This test checks an <adview> element has no behavior when the "adview"
+// permission is missing from the application manifest.
+IN_PROC_BROWSER_TEST_F(AdViewTest, AdViewPermissionIsRequired) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/permission_required")) << message_;
+}
+
+// This test checks that 1) it is possible change the value of the "ad-network"
+// attribute of an <adview> element and 2) changing the value will reset the
+// "src" attribute.
+// Broken test: http://crbug.com/257465.
+IN_PROC_BROWSER_TEST_F(AdViewTest, DISABLED_ChangeAdNetworkValue) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/change_ad_network")) << message_;
+}
+
+class AdViewNoSrcTest : public extensions::PlatformAppBrowserTest {
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kEnableAdview);
+    //Note: The "kEnableAdviewSrcAttribute" flag is not here!
+  }
+};
+
+// This test checks an invalid "ad-network" value (i.e. not whitelisted)
+// is ignored.
+IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, InvalidAdNetworkIsIgnored) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/invalid_ad_network")) << message_;
+}
+
+// This test checks the "src" attribute is ignored when the
+// "kEnableAdviewSrcAttribute" is missing.
+IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, EnableAdviewSrcAttributeFlagRequired) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/src_flag_required")) << message_;
+}
+
+// This test checks 1) an <adview> works end-to-end (i.e. page is loaded) when
+// using a whitelisted ad-network, and 2) the "src" attribute is never exposed
+// to the application.
+IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, SrcNotExposed) {
+  base::FilePath file_path = test_data_dir_
+    .AppendASCII("platform_apps")
+    .AppendASCII("ad_view/src_not_exposed")
+    .AppendASCII("ad_network_fake_website.html");
+
+  // Note: The following URL is identical to the whitelisted url
+  //       for "admob" (see ad_view.js).
+  GURL url = GURL("https://admob-sdk.doubleclick.net/chromeapps");
+  std::string scheme = url.scheme();
+  std::string hostname = url.host();
+
+  content::URLRequestPrepackagedInterceptor interceptor(scheme, hostname);
+  interceptor.SetResponse(url, file_path);
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/src_not_exposed")) << message_;
+  ASSERT_EQ(1, interceptor.GetHitCount());
+}
+
+class AdViewNotEnabledTest : public extensions::PlatformAppBrowserTest {
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    //Note: The "kEnableAdview" flag is not here!
+  }
+};
+
+// This test checks an <adview> element has no behavior when the "kEnableAdview"
+// flag is missing.
+IN_PROC_BROWSER_TEST_F(AdViewNotEnabledTest, EnableAdviewFlagRequired) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/ad_view/flag_required")) << message_;
+}
diff --git a/chrome/browser/apps/app_browsertest.cc b/chrome/browser/apps/app_browsertest.cc
new file mode 100644
index 0000000..d21586b
--- /dev/null
+++ b/chrome/browser/apps/app_browsertest.cc
@@ -0,0 +1,1090 @@
+// Copyright 2013 The Chromium Authors. 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/launcher.h"
+#include "apps/native_app_window.h"
+#include "apps/shell_window.h"
+#include "apps/shell_window_registry.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/prefs/pref_service.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/automation/automation_util.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/extensions/api/permissions/permissions_api.h"
+#include "chrome/browser/extensions/component_loader.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/tab_contents/render_view_context_menu.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/api/app_runtime.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/base/test_switches.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/test/test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
+
+using apps::ShellWindow;
+using apps::ShellWindowRegistry;
+using content::WebContents;
+using web_modal::WebContentsModalDialogManager;
+
+namespace extensions {
+
+namespace app_runtime = api::app_runtime;
+
+namespace {
+
+// Non-abstract RenderViewContextMenu class.
+class PlatformAppContextMenu : public RenderViewContextMenu {
+ public:
+  PlatformAppContextMenu(WebContents* web_contents,
+                         const content::ContextMenuParams& params)
+      : RenderViewContextMenu(web_contents, params) {}
+
+  bool HasCommandWithId(int command_id) {
+    return menu_model_.GetIndexOfCommandId(command_id) != -1;
+  }
+
+ protected:
+  // RenderViewContextMenu implementation.
+  virtual bool GetAcceleratorForCommandId(
+      int command_id,
+      ui::Accelerator* accelerator) OVERRIDE {
+    return false;
+  }
+  virtual void PlatformInit() OVERRIDE {}
+  virtual void PlatformCancel() OVERRIDE {}
+};
+
+// This class keeps track of tabs as they are added to the browser. It will be
+// "done" (i.e. won't block on Wait()) once |observations| tabs have been added.
+class TabsAddedNotificationObserver
+    : public content::WindowedNotificationObserver {
+ public:
+  explicit TabsAddedNotificationObserver(size_t observations)
+      : content::WindowedNotificationObserver(
+            chrome::NOTIFICATION_TAB_ADDED,
+            content::NotificationService::AllSources()),
+        observations_(observations) {
+  }
+
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE {
+    observed_tabs_.push_back(
+        content::Details<WebContents>(details).ptr());
+    if (observed_tabs_.size() == observations_)
+      content::WindowedNotificationObserver::Observe(type, source, details);
+  }
+
+  const std::vector<content::WebContents*>& tabs() { return observed_tabs_; }
+
+ private:
+  size_t observations_;
+  std::vector<content::WebContents*> observed_tabs_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabsAddedNotificationObserver);
+};
+
+bool CopyTestDataAndSetCommandLineArg(
+    const base::FilePath& test_data_file,
+    const base::FilePath& temp_dir,
+    const char* filename) {
+  base::FilePath path = temp_dir.AppendASCII(
+      filename).NormalizePathSeparators();
+  if (!(base::CopyFile(test_data_file, path)))
+    return false;
+
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendArgPath(path);
+  return true;
+}
+
+const char kTestFilePath[] = "platform_apps/launch_files/test.txt";
+
+}  // namespace
+
+// Tests that CreateShellWindow doesn't crash if you close it straight away.
+// LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
+// ash, so we test that it works here.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseShellWindow) {
+  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
+  ShellWindow* window = CreateShellWindow(extension);
+  CloseShellWindow(window);
+}
+
+// Tests that platform apps received the "launch" event when launched.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OnLaunchedEvent) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch")) << message_;
+}
+
+// Tests that platform apps cannot use certain disabled window properties, but
+// can override them and then use them.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisabledWindowProperties) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/disabled_window_properties"))
+      << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("minimal");
+
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  // The empty app doesn't add any context menu items, so its menu should
+  // only include the developer tools.
+  WebContents* web_contents = GetFirstShellWindowWebContents();
+  ASSERT_TRUE(web_contents);
+  content::ContextMenuParams params;
+  scoped_ptr<PlatformAppContextMenu> menu;
+  menu.reset(new PlatformAppContextMenu(web_contents, params));
+  menu->Init();
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
+  ASSERT_TRUE(
+      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("context_menu");
+
+  // Wait for the extension to tell us it's initialized its context menus and
+  // launched a window.
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  // The context_menu app has two context menu items. These, along with a
+  // separator and the developer tools, is all that should be in the menu.
+  WebContents* web_contents = GetFirstShellWindowWebContents();
+  ASSERT_TRUE(web_contents);
+  content::ContextMenuParams params;
+  scoped_ptr<PlatformAppContextMenu> menu;
+  menu.reset(new PlatformAppContextMenu(web_contents, params));
+  menu->Init();
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
+  ASSERT_TRUE(
+      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, InstalledAppWithContextMenu) {
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  InstallAndLaunchPlatformApp("context_menu");
+
+  // Wait for the extension to tell us it's initialized its context menus and
+  // launched a window.
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  // The context_menu app has two context menu items. For an installed app
+  // these are all that should be in the menu.
+  WebContents* web_contents = GetFirstShellWindowWebContents();
+  ASSERT_TRUE(web_contents);
+  content::ContextMenuParams params;
+  scoped_ptr<PlatformAppContextMenu> menu;
+  menu.reset(new PlatformAppContextMenu(web_contents, params));
+  menu->Init();
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
+  ASSERT_FALSE(
+      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("context_menu");
+
+  // Wait for the extension to tell us it's initialized its context menus and
+  // launched a window.
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  // The context_menu app has one context menu item. This, along with a
+  // separator and the developer tools, is all that should be in the menu.
+  WebContents* web_contents = GetFirstShellWindowWebContents();
+  ASSERT_TRUE(web_contents);
+  content::ContextMenuParams params;
+  params.is_editable = true;
+  scoped_ptr<PlatformAppContextMenu> menu;
+  menu.reset(new PlatformAppContextMenu(web_contents, params));
+  menu->Init();
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
+  ASSERT_TRUE(
+      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuSelection) {
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("context_menu");
+
+  // Wait for the extension to tell us it's initialized its context menus and
+  // launched a window.
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  // The context_menu app has one context menu item. This, along with a
+  // separator and the developer tools, is all that should be in the menu.
+  WebContents* web_contents = GetFirstShellWindowWebContents();
+  ASSERT_TRUE(web_contents);
+  content::ContextMenuParams params;
+  params.selection_text = ASCIIToUTF16("Hello World");
+  scoped_ptr<PlatformAppContextMenu> menu;
+  menu.reset(new PlatformAppContextMenu(web_contents, params));
+  menu->Init();
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
+  ASSERT_TRUE(
+      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
+  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuClicked) {
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("context_menu_click");
+
+  // Wait for the extension to tell us it's initialized its context menus and
+  // launched a window.
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  // Test that the menu item shows up
+  WebContents* web_contents = GetFirstShellWindowWebContents();
+  ASSERT_TRUE(web_contents);
+  content::ContextMenuParams params;
+  params.page_url = GURL("http://foo.bar");
+  scoped_ptr<PlatformAppContextMenu> menu;
+  menu.reset(new PlatformAppContextMenu(web_contents, params));
+  menu->Init();
+  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
+
+  // Execute the menu item
+  ExtensionTestMessageListener onclicked_listener("onClicked fired for id1",
+                                                  false);
+  menu->ExecuteCommand(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, 0);
+
+  ASSERT_TRUE(onclicked_listener.WaitUntilSatisfied());
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
+  TabsAddedNotificationObserver observer(2);
+
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
+
+  observer.Wait();
+  ASSERT_EQ(2U, observer.tabs().size());
+  EXPECT_EQ(std::string(chrome::kExtensionInvalidRequestURL),
+            observer.tabs()[0]->GetURL().spec());
+  EXPECT_EQ("http://chromium.org/",
+            observer.tabs()[1]->GetURL().spec());
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
+}
+
+// Tests that localStorage and WebSQL are disabled for platform apps.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowStorage) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/storage")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Restrictions) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restrictions")) << message_;
+}
+
+// Tests that platform apps can use the chrome.app.window.* API.
+// It is flaky: http://crbug.com/223467
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DISABLED_WindowsApi) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/windows_api")) << message_;
+}
+
+// Tests that extensions can't use platform-app-only APIs.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, PlatformAppsOnly) {
+  ASSERT_TRUE(RunExtensionTestIgnoreManifestWarnings(
+      "platform_apps/apps_only")) << message_;
+}
+
+// Tests that platform apps have isolated storage by default.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  // Load a (non-app) page under the "localhost" origin that sets a cookie.
+  GURL set_cookie_url = embedded_test_server()->GetURL(
+      "/extensions/platform_apps/isolation/set_cookie.html");
+  GURL::Replacements replace_host;
+  std::string host_str("localhost");  // Must stay in scope with replace_host.
+  replace_host.SetHostStr(host_str);
+  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
+
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), set_cookie_url,
+      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  // Make sure the cookie is set.
+  int cookie_size;
+  std::string cookie_value;
+  automation_util::GetCookies(
+      set_cookie_url,
+      browser()->tab_strip_model()->GetWebContentsAt(0),
+      &cookie_size,
+      &cookie_value);
+  ASSERT_EQ("testCookie=1", cookie_value);
+
+  // Let the platform app request the same URL, and make sure that it doesn't
+  // see the cookie.
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/isolation")) << message_;
+}
+
+// See crbug.com/248441
+#if defined(OS_WIN)
+#define MAYBE_ExtensionWindowingApis DISABLED_ExtensionWindowingApis
+#else
+#define MAYBE_ExtensionWindowingApis ExtensionWindowingApis
+#endif
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ExtensionWindowingApis) {
+  // Initially there should be just the one browser window visible to the
+  // extensions API.
+  const Extension* extension = LoadExtension(
+      test_data_dir_.AppendASCII("common/background_page"));
+  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
+
+  // And no shell windows.
+  ASSERT_EQ(0U, GetShellWindowCount());
+
+  // Launch a platform app that shows a window.
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("minimal");
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+  ASSERT_EQ(1U, GetShellWindowCount());
+  ShellWindowRegistry::ShellWindowList shell_windows =
+      ShellWindowRegistry::Get(browser()->profile())->shell_windows();
+  int shell_window_id = (*shell_windows.begin())->session_id().id();
+
+  // But it's not visible to the extensions API, it still thinks there's just
+  // one browser window.
+  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
+  // It can't look it up by ID either
+  ASSERT_FALSE(RunGetWindowFunctionForExtension(shell_window_id, extension));
+
+  // The app can also only see one window (its own).
+  // TODO(jeremya): add an extension function to get a shell window by ID, and
+  // to get a list of all the shell windows, so we can test this.
+
+  // Launch another platform app that also shows a window.
+  ExtensionTestMessageListener launched_listener2("Launched", false);
+  LoadAndLaunchPlatformApp("context_menu");
+  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
+
+  // There are two total shell windows, but each app can only see its own.
+  ASSERT_EQ(2U, GetShellWindowCount());
+  // TODO(jeremya): as above, this requires more extension functions.
+}
+
+// ChromeOS does not support passing arguments on the command line, so the tests
+// that rely on this functionality are disabled.
+#if !defined(OS_CHROMEOS)
+// Tests that command line parameters get passed through to platform apps
+// via launchData correctly when launching with a file.
+// TODO(benwells/jeremya): tests need a way to specify a handler ID.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
+      << message_;
+}
+
+// Tests that relative paths can be passed through to the platform app.
+// This test doesn't use the normal test infrastructure as it needs to open
+// the application differently to all other platform app tests, by setting
+// the chrome::AppLaunchParams.current_directory field.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithRelativeFile) {
+  // Setup the command line
+  ClearCommandLineArgs();
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  base::FilePath relative_test_doc =
+      base::FilePath::FromUTF8Unsafe(kTestFilePath);
+  relative_test_doc = relative_test_doc.NormalizePathSeparators();
+  command_line->AppendArgPath(relative_test_doc);
+
+  // Load the extension
+  ResultCatcher catcher;
+  const Extension* extension = LoadExtension(
+      test_data_dir_.AppendASCII("platform_apps/launch_file"));
+  ASSERT_TRUE(extension);
+
+  // Run the test
+  chrome::AppLaunchParams params(browser()->profile(), extension,
+                                 extension_misc::LAUNCH_NONE, NEW_WINDOW);
+  params.command_line = CommandLine::ForCurrentProcess();
+  params.current_directory = test_data_dir_;
+  chrome::OpenApplication(params);
+
+  if (!catcher.GetNextResult()) {
+    message_ = catcher.message();
+    ASSERT_TRUE(0);
+  }
+}
+
+// Tests that launch data is sent through if the file extension matches.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileExtension) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_by_extension"))
+      << message_;
+}
+
+// Tests that launch data is sent through if the file extension and MIME type
+// both match.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       LaunchWithFileExtensionAndMimeType) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/launch_file_by_extension_and_type")) << message_;
+}
+
+// Tests that launch data is sent through for a file with no extension if a
+// handler accepts "".
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileWithoutExtension) {
+  SetCommandLineArg("platform_apps/launch_files/test");
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
+      << message_;
+}
+
+#if !defined(OS_WIN)
+// Tests that launch data is sent through for a file with an empty extension if
+// a handler accepts "".
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileEmptyExtension) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  ClearCommandLineArgs();
+  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
+      test_data_dir_.AppendASCII(kTestFilePath),
+      temp_dir.path(),
+      "test."));
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
+      << message_;
+}
+
+// Tests that launch data is sent through for a file with an empty extension if
+// a handler accepts *.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       LaunchWithFileEmptyExtensionAcceptAny) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  ClearCommandLineArgs();
+  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
+      test_data_dir_.AppendASCII(kTestFilePath),
+      temp_dir.path(),
+      "test."));
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/launch_file_with_any_extension")) << message_;
+}
+#endif
+
+// Tests that launch data is sent through for a file with no extension if a
+// handler accepts *.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       LaunchWithFileWithoutExtensionAcceptAny) {
+  SetCommandLineArg("platform_apps/launch_files/test");
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/launch_file_with_any_extension")) << message_;
+}
+
+// Tests that launch data is sent through for a file with an extension if a
+// handler accepts *.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       LaunchWithFileAcceptAnyExtension) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/launch_file_with_any_extension")) << message_;
+}
+
+// Tests that no launch data is sent through if the file has the wrong
+// extension.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongExtension) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
+      << message_;
+}
+
+// Tests that no launch data is sent through if the file has no extension but
+// the handler requires a specific extension.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongEmptyExtension) {
+  SetCommandLineArg("platform_apps/launch_files/test");
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
+      << message_;
+}
+
+// Tests that no launch data is sent through if the file is of the wrong MIME
+// type.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
+      << message_;
+}
+
+// Tests that no launch data is sent through if the platform app does not
+// provide an intent.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
+      << message_;
+}
+
+// Tests that launch data is sent through with the MIME type set to
+// application/octet-stream if the file MIME type cannot be read.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
+  SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
+  ASSERT_TRUE(RunPlatformAppTest(
+      "platform_apps/launch_application_octet_stream")) << message_;
+}
+
+// Tests that no launch data is sent through if the file does not exist.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
+  SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
+      << message_;
+}
+
+// Tests that no launch data is sent through if the argument is a directory.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
+  SetCommandLineArg("platform_apps/launch_files");
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
+      << message_;
+}
+
+// Tests that no launch data is sent through if there are no arguments passed
+// on the command line
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
+  ClearCommandLineArgs();
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
+      << message_;
+}
+
+// Test that platform apps can use the chrome.fileSystem.getDisplayPath
+// function to get the native file system path of a file they are launched with.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) {
+  SetCommandLineArg(kTestFilePath);
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path"))
+      << message_;
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  content::WindowedNotificationObserver observer(
+      chrome::NOTIFICATION_TAB_ADDED,
+      content::Source<content::WebContentsDelegate>(browser()));
+  LoadAndLaunchPlatformApp("open_link");
+  observer.Wait();
+  ASSERT_EQ(2, browser()->tab_strip_model()->count());
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MutationEventsDisabled) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/mutation_events")) << message_;
+}
+
+// Test that windows created with an id will remember and restore their
+// geometry when opening new windows.
+// Originally disabled due to flakiness (see http://crbug.com/155459)
+// but now because a regression breaks the test (http://crbug.com/160343).
+#if defined(TOOLKIT_GTK)
+#define MAYBE_ShellWindowRestorePosition DISABLED_ShellWindowRestorePosition
+#else
+#define MAYBE_ShellWindowRestorePosition ShellWindowRestorePosition
+#endif
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       MAYBE_ShellWindowRestorePosition) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/geometry"));
+}
+
+// This appears to be unreliable on linux.
+// TODO(stevenjb): Investigate and enable
+#if defined(OS_LINUX) && !defined(USE_ASH)
+#define MAYBE_ShellWindowRestoreState DISABLED_ShellWindowRestoreState
+#else
+#define MAYBE_ShellWindowRestoreState ShellWindowRestoreState
+#endif
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       MAYBE_ShellWindowRestoreState) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restore_state"));
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       ShellWindowAdjustBoundsToBeVisibleOnScreen) {
+  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
+  ShellWindow* window = CreateShellWindow(extension);
+
+  // The screen bounds didn't change, the cached bounds didn't need to adjust.
+  gfx::Rect cached_bounds(80, 100, 400, 400);
+  gfx::Rect cached_screen_bounds(0, 0, 1600, 900);
+  gfx::Rect current_screen_bounds(0, 0, 1600, 900);
+  gfx::Size minimum_size(200, 200);
+  gfx::Rect bounds;
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
+                                                    cached_bounds,
+                                                    cached_screen_bounds,
+                                                    current_screen_bounds,
+                                                    minimum_size,
+                                                    &bounds);
+  EXPECT_EQ(bounds, cached_bounds);
+
+  // We have an empty screen bounds, the cached bounds didn't need to adjust.
+  gfx::Rect empty_screen_bounds;
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
+                                                    cached_bounds,
+                                                    empty_screen_bounds,
+                                                    current_screen_bounds,
+                                                    minimum_size,
+                                                    &bounds);
+  EXPECT_EQ(bounds, cached_bounds);
+
+  // Cached bounds is completely off the new screen bounds in horizontal
+  // locations. Expect to reposition the bounds.
+  gfx::Rect horizontal_out_of_screen_bounds(-800, 100, 400, 400);
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      horizontal_out_of_screen_bounds,
+      gfx::Rect(-1366, 0, 1600, 900),
+      current_screen_bounds,
+      minimum_size,
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(0, 100, 400, 400));
+
+  // Cached bounds is completely off the new screen bounds in vertical
+  // locations. Expect to reposition the bounds.
+  gfx::Rect vertical_out_of_screen_bounds(10, 1000, 400, 400);
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      vertical_out_of_screen_bounds,
+      gfx::Rect(-1366, 0, 1600, 900),
+      current_screen_bounds,
+      minimum_size,
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(10, 500, 400, 400));
+
+  // From a large screen resulotion to a small one. Expect it fit on screen.
+  gfx::Rect big_cache_bounds(10, 10, 1000, 1000);
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      big_cache_bounds,
+      gfx::Rect(0, 0, 1600, 1000),
+      gfx::Rect(0, 0, 800, 600),
+      minimum_size,
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(0, 0, 800, 600));
+
+  // Don't resize the bounds smaller than minimum size, when the minimum size is
+  // larger than the screen.
+  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      window,
+      big_cache_bounds,
+      gfx::Rect(0, 0, 1600, 1000),
+      gfx::Rect(0, 0, 800, 600),
+      gfx::Size(900, 900),
+      &bounds);
+  EXPECT_EQ(bounds, gfx::Rect(0, 0, 900, 900));
+}
+
+namespace {
+
+class PlatformAppDevToolsBrowserTest : public PlatformAppBrowserTest {
+ protected:
+  enum TestFlags {
+    RELAUNCH = 0x1,
+    HAS_ID = 0x2,
+  };
+  // Runs a test inside a harness that opens DevTools on a shell window.
+  void RunTestWithDevTools(const char* name, int test_flags);
+};
+
+void PlatformAppDevToolsBrowserTest::RunTestWithDevTools(
+    const char* name, int test_flags) {
+  using content::DevToolsAgentHost;
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  const Extension* extension = LoadAndLaunchPlatformApp(name);
+  ASSERT_TRUE(extension);
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+  ShellWindow* window = GetFirstShellWindow();
+  ASSERT_TRUE(window);
+  ASSERT_EQ(window->window_key().empty(), (test_flags & HAS_ID) == 0);
+  content::RenderViewHost* rvh = window->web_contents()->GetRenderViewHost();
+  ASSERT_TRUE(rvh);
+
+  // Ensure no DevTools open for the ShellWindow, then open one.
+  ASSERT_FALSE(DevToolsAgentHost::HasFor(rvh));
+  DevToolsWindow* devtools_window = DevToolsWindow::OpenDevToolsWindow(rvh);
+  content::WindowedNotificationObserver loaded_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &devtools_window->web_contents()->GetController()));
+  loaded_observer.Wait();
+  ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
+
+  if (test_flags & RELAUNCH) {
+    // Close the ShellWindow, and ensure it is gone.
+    CloseShellWindow(window);
+    ASSERT_FALSE(GetFirstShellWindow());
+
+    // Relaunch the app and get a new ShellWindow.
+    content::WindowedNotificationObserver app_loaded_observer(
+        content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+        content::NotificationService::AllSources());
+    chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
+                                                    extension,
+                                                    extension_misc::LAUNCH_NONE,
+                                                    NEW_WINDOW));
+    app_loaded_observer.Wait();
+    window = GetFirstShellWindow();
+    ASSERT_TRUE(window);
+
+    // DevTools should have reopened with the relaunch.
+    rvh = window->web_contents()->GetRenderViewHost();
+    ASSERT_TRUE(rvh);
+    ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
+  }
+}
+
+}  // namespace
+
+// http://crbug.com/246634
+#if defined(OS_CHROMEOS)
+#define MAYBE_ReOpenedWithID DISABLED_ReOpenedWithID
+#else
+#define MAYBE_ReOpenedWithID ReOpenedWithID
+#endif
+IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithID) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
+    return;
+#endif
+  RunTestWithDevTools("minimal_id", RELAUNCH | HAS_ID);
+}
+
+// http://crbug.com/246999
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#define MAYBE_ReOpenedWithURL DISABLED_ReOpenedWithURL
+#else
+#define MAYBE_ReOpenedWithURL ReOpenedWithURL
+#endif
+IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithURL) {
+  RunTestWithDevTools("minimal", RELAUNCH);
+}
+
+// Test that showing a permission request as a constrained window works and is
+// correctly parented.
+#if defined(OS_MACOSX)
+#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
+#else
+// TODO(sail): Enable this on other platforms once http://crbug.com/95455 is
+// fixed.
+#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
+#endif
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ConstrainedWindowRequest) {
+  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
+  const Extension* extension =
+      LoadAndLaunchPlatformApp("optional_permission_request");
+  ASSERT_TRUE(extension) << "Failed to load extension.";
+
+  WebContents* web_contents = GetFirstShellWindowWebContents();
+  ASSERT_TRUE(web_contents);
+
+  // Verify that the shell window has a dialog attached.
+  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents);
+  EXPECT_TRUE(web_contents_modal_dialog_manager->IsShowingDialog());
+
+  // Close the constrained window and wait for the reply to the permission
+  // request.
+  ExtensionTestMessageListener listener("PermissionRequestDone", false);
+  WebContentsModalDialogManager::TestApi test_api(
+      web_contents_modal_dialog_manager);
+  test_api.CloseAllDialogs();
+  ASSERT_TRUE(listener.WaitUntilSatisfied());
+}
+
+// Tests that an app calling chrome.runtime.reload will reload the app and
+// relaunch it if it was running.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReloadRelaunches) {
+  ExtensionTestMessageListener launched_listener("Launched", true);
+  const Extension* extension = LoadAndLaunchPlatformApp("reload");
+  ASSERT_TRUE(extension);
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+  ASSERT_TRUE(GetFirstShellWindow());
+
+  // Now tell the app to reload itself
+  ExtensionTestMessageListener launched_listener2("Launched", false);
+  launched_listener.Reply("reload");
+  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
+  ASSERT_TRUE(GetFirstShellWindow());
+}
+
+namespace {
+
+// Simple observer to check for NOTIFICATION_EXTENSION_INSTALLED events to
+// ensure installation does or does not occur in certain scenarios.
+class CheckExtensionInstalledObserver : public content::NotificationObserver {
+ public:
+  CheckExtensionInstalledObserver() : seen_(false) {
+    registrar_.Add(this,
+                   chrome::NOTIFICATION_EXTENSION_INSTALLED,
+                   content::NotificationService::AllSources());
+  }
+
+  bool seen() const {
+    return seen_;
+  };
+
+  // NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE {
+    EXPECT_FALSE(seen_);
+    seen_ = true;
+  }
+
+ private:
+  bool seen_;
+  content::NotificationRegistrar registrar_;
+};
+
+}  // namespace
+
+// Component App Test 1 of 3: ensure that the initial load of a component
+// extension utilizing a background page (e.g. a v2 platform app) has its
+// background page run and is launchable. Waits for the Launched response from
+// the script resource in the opened shell window.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       PRE_PRE_ComponentAppBackgroundPage) {
+  CheckExtensionInstalledObserver should_install;
+
+  // Ensure that we wait until the background page is run (to register the
+  // OnLaunched listener) before trying to open the application. This is similar
+  // to LoadAndLaunchPlatformApp, but we want to load as a component extension.
+  content::WindowedNotificationObserver app_loaded_observer(
+      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+      content::NotificationService::AllSources());
+
+  const Extension* extension = LoadExtensionAsComponent(
+      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
+  ASSERT_TRUE(extension);
+
+  app_loaded_observer.Wait();
+  ASSERT_TRUE(should_install.seen());
+
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
+                                                  extension,
+                                                  extension_misc::LAUNCH_NONE,
+                                                  NEW_WINDOW));
+
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+}
+
+// Component App Test 2 of 3: ensure an installed component app can be launched
+// on a subsequent browser start, without requiring any install/upgrade logic
+// to be run, then perform setup for step 3.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       PRE_ComponentAppBackgroundPage) {
+
+  // Since the component app is now installed, re-adding it in the same profile
+  // should not cause it to be re-installed. Instead, we wait for the OnLaunched
+  // in a different observer (which would timeout if not the app was not
+  // previously installed properly) and then check this observer to make sure it
+  // never saw the NOTIFICATION_EXTENSION_INSTALLED event.
+  CheckExtensionInstalledObserver should_not_install;
+  const Extension* extension = LoadExtensionAsComponent(
+      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
+  ASSERT_TRUE(extension);
+
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
+                                                  extension,
+                                                  extension_misc::LAUNCH_NONE,
+                                                  NEW_WINDOW));
+
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+  ASSERT_FALSE(should_not_install.seen());
+
+  // Simulate a "downgrade" from version 2 in the test manifest.json to 1.
+  ExtensionPrefs* extension_prefs =
+      extensions::ExtensionSystem::Get(browser()->profile())->
+      extension_service()->extension_prefs();
+
+  // Clear the registered events to ensure they are updated.
+  extensions::ExtensionSystem::Get(browser()->profile())->event_router()->
+      SetRegisteredEvents(extension->id(), std::set<std::string>());
+
+  DictionaryPrefUpdate update(extension_prefs->pref_service(),
+                              prefs::kExtensionsPref);
+  DictionaryValue* dict = update.Get();
+  std::string key(extension->id());
+  key += ".manifest.version";
+  dict->SetString(key, "1");
+}
+
+// Component App Test 3 of 3: simulate a component extension upgrade that
+// re-adds the OnLaunched event, and allows the app to be launched.
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ComponentAppBackgroundPage) {
+  CheckExtensionInstalledObserver should_install;
+  // Since we are forcing an upgrade, we need to wait for the load again.
+  content::WindowedNotificationObserver app_loaded_observer(
+      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+      content::NotificationService::AllSources());
+
+  const Extension* extension = LoadExtensionAsComponent(
+      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
+  ASSERT_TRUE(extension);
+  app_loaded_observer.Wait();
+  ASSERT_TRUE(should_install.seen());
+
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
+                                                  extension,
+                                                  extension_misc::LAUNCH_NONE,
+                                                  NEW_WINDOW));
+
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+}
+
+// Flakes on Windows: http://crbug.com/171450
+#if defined(OS_WIN)
+#define MAYBE_Messaging DISABLED_Messaging
+#else
+#define MAYBE_Messaging Messaging
+#endif
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_Messaging) {
+  ExtensionApiTest::ResultCatcher result_catcher;
+  LoadAndLaunchPlatformApp("messaging/app2");
+  LoadAndLaunchPlatformApp("messaging/app1");
+  EXPECT_TRUE(result_catcher.GetNextResult());
+}
+
+// TODO(linux_aura) http://crbug.com/163931
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
+#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
+#else
+// This test depends on focus and so needs to be in interactive_ui_tests.
+// http://crbug.com/227041
+#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
+#endif
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_WebContentsHasFocus) {
+  ExtensionTestMessageListener launched_listener("Launched", true);
+  LoadAndLaunchPlatformApp("minimal");
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  EXPECT_EQ(1LU, GetShellWindowCount());
+  ShellWindowRegistry::ShellWindowList shell_windows = ShellWindowRegistry::Get(
+      browser()->profile())->shell_windows();
+  EXPECT_TRUE((*shell_windows.begin())->web_contents()->
+      GetRenderWidgetHostView()->HasFocus());
+}
+
+
+#if defined(OS_CHROMEOS)
+
+class PlatformAppIncognitoBrowserTest : public PlatformAppBrowserTest,
+                                        public ShellWindowRegistry::Observer {
+ public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    // Tell chromeos to launch in Guest mode, aka incognito.
+    command_line->AppendSwitch(switches::kIncognito);
+    PlatformAppBrowserTest::SetUpCommandLine(command_line);
+  }
+  virtual void SetUp() OVERRIDE {
+    // Make sure the file manager actually gets loaded.
+    ComponentLoader::EnableBackgroundExtensionsForTesting();
+    PlatformAppBrowserTest::SetUp();
+  }
+
+  // ShellWindowRegistry::Observer implementation.
+  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE {
+    opener_app_ids_.insert(shell_window->extension()->id());
+  }
+  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {}
+  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE {}
+
+ protected:
+  // A set of ids of apps we've seen open a shell window.
+  std::set<std::string> opener_app_ids_;
+};
+
+IN_PROC_BROWSER_TEST_F(PlatformAppIncognitoBrowserTest, IncognitoComponentApp) {
+  // Get the file manager app.
+  const Extension* file_manager = extension_service()->GetExtensionById(
+      "hhaomjibdihmijegdhdafkllkbggdgoj", false);
+  ASSERT_TRUE(file_manager != NULL);
+  Profile* incognito_profile = profile()->GetOffTheRecordProfile();
+  ASSERT_TRUE(incognito_profile != NULL);
+
+  // Wait until the file manager has had a chance to register its listener
+  // for the launch event.
+  EventRouter* router = ExtensionSystem::Get(incognito_profile)->event_router();
+  ASSERT_TRUE(router != NULL);
+  while (!router->ExtensionHasEventListener(
+      file_manager->id(), app_runtime::OnLaunched::kEventName)) {
+    content::RunAllPendingInMessageLoop();
+  }
+
+  // Listen for new shell windows so we see the file manager app launch itself.
+  ShellWindowRegistry* registry = ShellWindowRegistry::Get(incognito_profile);
+  ASSERT_TRUE(registry != NULL);
+  registry->AddObserver(this);
+
+  chrome::AppLaunchParams params(incognito_profile, file_manager, 0);
+  chrome::OpenApplication(params);
+
+  while (!ContainsKey(opener_app_ids_, file_manager->id())) {
+    content::RunAllPendingInMessageLoop();
+  }
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+
+}  // namespace extensions
diff --git a/chrome/browser/apps/app_browsertest_util.cc b/chrome/browser/apps/app_browsertest_util.cc
new file mode 100644
index 0000000..7a2f9ce
--- /dev/null
+++ b/chrome/browser/apps/app_browsertest_util.cc
@@ -0,0 +1,194 @@
+// Copyright 2013 The Chromium Authors. 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_browsertest_util.h"
+
+#include "apps/app_window_contents.h"
+#include "apps/native_app_window.h"
+#include "apps/shell_window_registry.h"
+#include "base/command_line.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/api/tabs/tabs_api.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_utils.h"
+#include "extensions/common/switches.h"
+
+using apps::ShellWindow;
+using apps::ShellWindowRegistry;
+using content::WebContents;
+
+namespace utils = extension_function_test_utils;
+
+namespace extensions {
+
+PlatformAppBrowserTest::PlatformAppBrowserTest() {
+  ChromeShellWindowDelegate::DisableExternalOpenForTesting();
+}
+
+void PlatformAppBrowserTest::SetUpCommandLine(CommandLine* command_line) {
+  // Skips ExtensionApiTest::SetUpCommandLine.
+  ExtensionBrowserTest::SetUpCommandLine(command_line);
+
+  // Make event pages get suspended quicker.
+  command_line->AppendSwitchASCII(::switches::kEventPageIdleTime, "1");
+  command_line->AppendSwitchASCII(::switches::kEventPageSuspendingTime, "1");
+}
+
+const Extension* PlatformAppBrowserTest::LoadAndLaunchPlatformApp(
+    const char* name) {
+  content::WindowedNotificationObserver app_loaded_observer(
+      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+      content::NotificationService::AllSources());
+
+  const Extension* extension = LoadExtension(
+      test_data_dir_.AppendASCII("platform_apps").AppendASCII(name));
+  EXPECT_TRUE(extension);
+
+  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
+                                                  extension,
+                                                  extension_misc::LAUNCH_NONE,
+                                                  NEW_WINDOW));
+
+  app_loaded_observer.Wait();
+
+  return extension;
+}
+
+const Extension* PlatformAppBrowserTest::InstallAndLaunchPlatformApp(
+    const char* name) {
+  content::WindowedNotificationObserver app_loaded_observer(
+      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
+      content::NotificationService::AllSources());
+
+  const Extension* extension = InstallExtension(
+      test_data_dir_.AppendASCII("platform_apps").AppendASCII(name), 1);
+  EXPECT_TRUE(extension);
+
+  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
+                                                  extension,
+                                                  extension_misc::LAUNCH_NONE,
+                                                  NEW_WINDOW));
+
+  app_loaded_observer.Wait();
+
+  return extension;
+}
+
+WebContents* PlatformAppBrowserTest::GetFirstShellWindowWebContents() {
+  ShellWindow* window = GetFirstShellWindow();
+  if (window)
+    return window->web_contents();
+
+  return NULL;
+}
+
+ShellWindow* PlatformAppBrowserTest::GetFirstShellWindow() {
+  ShellWindowRegistry* app_registry =
+      ShellWindowRegistry::Get(browser()->profile());
+  const ShellWindowRegistry::ShellWindowList& shell_windows =
+      app_registry->shell_windows();
+
+  ShellWindowRegistry::const_iterator iter = shell_windows.begin();
+  if (iter != shell_windows.end())
+    return *iter;
+
+  return NULL;
+}
+
+size_t PlatformAppBrowserTest::RunGetWindowsFunctionForExtension(
+    const Extension* extension) {
+  scoped_refptr<WindowsGetAllFunction> function = new WindowsGetAllFunction();
+  function->set_extension(extension);
+  scoped_ptr<base::ListValue> result(utils::ToList(
+      utils::RunFunctionAndReturnSingleResult(function.get(),
+                                              "[]",
+                                              browser())));
+  return result->GetSize();
+}
+
+bool PlatformAppBrowserTest::RunGetWindowFunctionForExtension(
+    int window_id,
+    const Extension* extension) {
+  scoped_refptr<WindowsGetFunction> function = new WindowsGetFunction();
+  function->set_extension(extension);
+  utils::RunFunction(
+          function.get(),
+          base::StringPrintf("[%u]", window_id),
+          browser(),
+          utils::NONE);
+  return function->GetResultList() != NULL;
+}
+
+size_t PlatformAppBrowserTest::GetShellWindowCount() {
+  return ShellWindowRegistry::Get(browser()->profile())->
+      shell_windows().size();
+}
+
+void PlatformAppBrowserTest::ClearCommandLineArgs() {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  CommandLine::StringVector args = command_line->GetArgs();
+  CommandLine::StringVector argv = command_line->argv();
+  for (size_t i = 0; i < args.size(); i++)
+    argv.pop_back();
+  command_line->InitFromArgv(argv);
+}
+
+void PlatformAppBrowserTest::SetCommandLineArg(const std::string& test_file) {
+  ClearCommandLineArgs();
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  base::FilePath test_doc(test_data_dir_.AppendASCII(test_file));
+  test_doc = test_doc.NormalizePathSeparators();
+  command_line->AppendArgPath(test_doc);
+}
+
+ShellWindow* PlatformAppBrowserTest::CreateShellWindow(
+    const Extension* extension) {
+  return CreateShellWindowFromParams(extension, ShellWindow::CreateParams());
+}
+
+ShellWindow* PlatformAppBrowserTest::CreateShellWindowFromParams(
+    const Extension* extension, const ShellWindow::CreateParams& params) {
+  ShellWindow* window = new ShellWindow(browser()->profile(),
+                                        new ChromeShellWindowDelegate(),
+                                        extension);
+  window->Init(GURL(std::string()),
+               new apps::AppWindowContents(window),
+               params);
+  return window;
+}
+
+void PlatformAppBrowserTest::CloseShellWindow(ShellWindow* window) {
+  content::WindowedNotificationObserver destroyed_observer(
+      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+      content::NotificationService::AllSources());
+  window->GetBaseWindow()->Close();
+  destroyed_observer.Wait();
+}
+
+void PlatformAppBrowserTest::CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+    ShellWindow* window,
+    const gfx::Rect& cached_bounds,
+    const gfx::Rect& cached_screen_bounds,
+    const gfx::Rect& current_screen_bounds,
+    const gfx::Size& minimum_size,
+    gfx::Rect* bounds) {
+  window->AdjustBoundsToBeVisibleOnScreen(cached_bounds,
+                                          cached_screen_bounds,
+                                          current_screen_bounds,
+                                          minimum_size,
+                                          bounds);
+}
+
+void ExperimentalPlatformAppBrowserTest::SetUpCommandLine(
+    CommandLine* command_line) {
+  PlatformAppBrowserTest::SetUpCommandLine(command_line);
+  command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/apps/app_browsertest_util.h b/chrome/browser/apps/app_browsertest_util.h
new file mode 100644
index 0000000..aa4efcd
--- /dev/null
+++ b/chrome/browser/apps/app_browsertest_util.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 CHROME_BROWSER_APPS_APP_BROWSERTEST_UTIL_H_
+#define CHROME_BROWSER_APPS_APP_BROWSERTEST_UTIL_H_
+
+
+#include "apps/shell_window.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+
+namespace content {
+class WebContents;
+}
+
+class CommandLine;
+
+namespace extensions {
+class Extension;
+
+class PlatformAppBrowserTest : public ExtensionApiTest {
+ public:
+  PlatformAppBrowserTest();
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+
+ protected:
+  // Runs the app named |name| out of the platform_apps subdirectory. Waits
+  // until it is launched.
+  const Extension* LoadAndLaunchPlatformApp(const char* name);
+
+  // Installs and runs the app named |name| out of the platform_apps
+  // subdirectory. Waits until it is launched.
+  const Extension* InstallAndLaunchPlatformApp(const char* name);
+
+  // Gets the WebContents associated with the first shell window that is found
+  // (most tests only deal with one platform app window, so this is good
+  // enough).
+  content::WebContents* GetFirstShellWindowWebContents();
+
+  // Gets the first shell window that is found (most tests only deal with one
+  // platform app window, so this is good enough).
+  apps::ShellWindow* GetFirstShellWindow();
+
+  // Runs chrome.windows.getAll for the given extension and returns the number
+  // of windows that the function returns.
+  size_t RunGetWindowsFunctionForExtension(const Extension* extension);
+
+  // Runs chrome.windows.get(|window_id|) for the the given extension and
+  // returns whether or not a window was found.
+  bool RunGetWindowFunctionForExtension(int window_id,
+                                        const Extension* extension);
+
+  // Returns the number of shell windows.
+  size_t GetShellWindowCount();
+
+  // The command line already has an argument on it - about:blank, which
+  // is set by InProcessBrowserTest::PrepareTestCommandLine. For platform app
+  // launch tests we need to clear this.
+  void ClearCommandLineArgs();
+
+  // Sets up the command line for running platform apps.
+  void SetCommandLineArg(const std::string& test_file);
+
+  // Creates an empty shell window for |extension|.
+  apps::ShellWindow* CreateShellWindow(const Extension* extension);
+
+  apps::ShellWindow* CreateShellWindowFromParams(
+      const Extension* extension,
+      const apps::ShellWindow::CreateParams& params);
+
+  // Closes |window| and waits until it's gone.
+  void CloseShellWindow(apps::ShellWindow* window);
+
+  // Call AdjustBoundsToBeVisibleOnScreen of |window|.
+  void CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
+      apps::ShellWindow* window,
+      const gfx::Rect& cached_bounds,
+      const gfx::Rect& cached_screen_bounds,
+      const gfx::Rect& current_screen_bounds,
+      const gfx::Size& minimum_size,
+      gfx::Rect* bounds);
+};
+
+class ExperimentalPlatformAppBrowserTest : public PlatformAppBrowserTest {
+ public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_APPS_APP_BROWSERTEST_UTIL_H_
diff --git a/chrome/browser/apps/web_view_browsertest.cc b/chrome/browser/apps/web_view_browsertest.cc
new file mode 100644
index 0000000..a75b301
--- /dev/null
+++ b/chrome/browser/apps/web_view_browsertest.cc
@@ -0,0 +1,1621 @@
+// Copyright 2013 The Chromium Authors. 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/native_app_window.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/automation/automation_util.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/prerender/prerender_link_manager.h"
+#include "chrome/browser/prerender/prerender_link_manager_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/interstitial_page.h"
+#include "content/public/browser/interstitial_page_delegate.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/fake_speech_recognition_manager.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"
+#include "ui/gl/gl_switches.h"
+
+// For fine-grained suppression on flaky tests.
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+using prerender::PrerenderLinkManager;
+using prerender::PrerenderLinkManagerFactory;
+
+namespace {
+const char kEmptyResponsePath[] = "/close-socket";
+const char kRedirectResponsePath[] = "/server-redirect";
+const char kRedirectResponseFullPath[] =
+    "/extensions/platform_apps/web_view/shim/guest_redirect.html";
+
+class EmptyHttpResponse : public net::test_server::HttpResponse {
+ public:
+  virtual std::string ToResponseString() const OVERRIDE {
+    return std::string();
+  }
+};
+
+class TestInterstitialPageDelegate : public content::InterstitialPageDelegate {
+ public:
+  TestInterstitialPageDelegate() {
+  }
+  virtual ~TestInterstitialPageDelegate() {}
+  virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
+};
+
+class WebContentsCreatedListener {
+ public:
+  WebContentsCreatedListener() : web_contents_(NULL) {
+    content::WebContents::AddCreatedCallback(
+        base::Bind(&WebContentsCreatedListener::CreatedCallback,
+                   base::Unretained(this)));
+  }
+
+  content::WebContents* WaitForWebContentsCreated() {
+    if (web_contents_)
+      return web_contents_;
+
+    message_loop_runner_ = new content::MessageLoopRunner;
+    message_loop_runner_->Run();
+    return web_contents_;
+  }
+
+ private:
+  void CreatedCallback(content::WebContents* web_contents) {
+    web_contents_ = web_contents;
+
+    if (message_loop_runner_)
+      message_loop_runner_->Quit();
+  }
+
+ private:
+  content::WebContents* web_contents_;
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentsCreatedListener);
+};
+
+class InterstitialObserver : public content::WebContentsObserver {
+ public:
+  InterstitialObserver(content::WebContents* web_contents,
+                       const base::Closure& attach_callback,
+                       const base::Closure& detach_callback)
+      : WebContentsObserver(web_contents),
+        attach_callback_(attach_callback),
+        detach_callback_(detach_callback) {
+  }
+
+  virtual void DidAttachInterstitialPage() OVERRIDE {
+    attach_callback_.Run();
+  }
+
+  virtual void DidDetachInterstitialPage() OVERRIDE {
+    detach_callback_.Run();
+  }
+
+ private:
+  base::Closure attach_callback_;
+  base::Closure detach_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
+};
+
+}  // namespace
+
+// This class intercepts media access request from the embedder. The request
+// should be triggered only if the embedder API (from tests) allows the request
+// in Javascript.
+// We do not issue the actual media request; the fact that the request reached
+// embedder's WebContents is good enough for our tests. This is also to make
+// the test run successfully on trybots.
+class MockWebContentsDelegate : public content::WebContentsDelegate {
+ public:
+  MockWebContentsDelegate() : requested_(false) {}
+  virtual ~MockWebContentsDelegate() {}
+
+  virtual void RequestMediaAccessPermission(
+      content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback) OVERRIDE {
+    requested_ = true;
+    if (message_loop_runner_.get())
+      message_loop_runner_->Quit();
+  }
+
+  void WaitForSetMediaPermission() {
+    if (requested_)
+      return;
+    message_loop_runner_ = new content::MessageLoopRunner;
+    message_loop_runner_->Run();
+  }
+
+ private:
+  bool requested_;
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockWebContentsDelegate);
+};
+
+// This class intercepts download request from the guest.
+class MockDownloadWebContentsDelegate : public content::WebContentsDelegate {
+ public:
+  explicit MockDownloadWebContentsDelegate(
+      content::WebContentsDelegate* orig_delegate)
+      : orig_delegate_(orig_delegate),
+        waiting_for_decision_(false),
+        expect_allow_(false),
+        decision_made_(false),
+        last_download_allowed_(false) {}
+  virtual ~MockDownloadWebContentsDelegate() {}
+
+  virtual void CanDownload(
+      content::RenderViewHost* render_view_host,
+      int request_id,
+      const std::string& request_method,
+      const base::Callback<void(bool)>& callback) OVERRIDE {
+    orig_delegate_->CanDownload(
+        render_view_host, request_id, request_method,
+        base::Bind(&MockDownloadWebContentsDelegate::DownloadDecided,
+                   base::Unretained(this)));
+  }
+
+  void WaitForCanDownload(bool expect_allow) {
+    EXPECT_FALSE(waiting_for_decision_);
+    waiting_for_decision_ = true;
+
+    if (decision_made_) {
+      EXPECT_EQ(expect_allow, last_download_allowed_);
+      return;
+    }
+
+    expect_allow_ = expect_allow;
+    message_loop_runner_ = new content::MessageLoopRunner;
+    message_loop_runner_->Run();
+  }
+
+  void DownloadDecided(bool allow) {
+    EXPECT_FALSE(decision_made_);
+    decision_made_ = true;
+
+    if (waiting_for_decision_) {
+      EXPECT_EQ(expect_allow_, allow);
+      if (message_loop_runner_.get())
+        message_loop_runner_->Quit();
+      return;
+    }
+    last_download_allowed_ = allow;
+  }
+
+  void Reset() {
+    waiting_for_decision_ = false;
+    decision_made_ = false;
+  }
+
+ private:
+  content::WebContentsDelegate* orig_delegate_;
+  bool waiting_for_decision_;
+  bool expect_allow_;
+  bool decision_made_;
+  bool last_download_allowed_;
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockDownloadWebContentsDelegate);
+};
+
+class WebViewTest : public extensions::PlatformAppBrowserTest {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+
+    // SpeechRecognition test specific SetUp.
+    if (!strcmp(test_info->name(), "SpeechRecognition")) {
+      fake_speech_recognition_manager_.reset(
+          new content::FakeSpeechRecognitionManager());
+      fake_speech_recognition_manager_->set_should_send_fake_response(true);
+      // Inject the fake manager factory so that the test result is returned to
+      // the web page.
+      content::SpeechRecognitionManager::SetManagerForTests(
+          fake_speech_recognition_manager_.get());
+    }
+
+    extensions::PlatformAppBrowserTest::SetUp();
+  }
+
+  virtual void TearDown() OVERRIDE {
+    // SpeechRecognition test specific TearDown.
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    if (!strcmp(test_info->name(), "SpeechRecognition"))
+      content::SpeechRecognitionManager::SetManagerForTests(NULL);
+
+    extensions::PlatformAppBrowserTest::TearDown();
+  }
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    const testing::TestInfo* const test_info =
+        testing::UnitTest::GetInstance()->current_test_info();
+    // Mock out geolocation for geolocation specific tests.
+    if (!strncmp(test_info->name(), "GeolocationAPI",
+            strlen("GeolocationAPI"))) {
+      ui_test_utils::OverrideGeolocation(10, 20);
+    }
+  }
+
+  // This method is responsible for initializing a packaged app, which contains
+  // multiple webview tags. The tags have different partition identifiers and
+  // their WebContent objects are returned as output. The method also verifies
+  // the expected process allocation and storage partition assignment.
+  // The |navigate_to_url| parameter is used to navigate the main browser
+  // window.
+  //
+  // TODO(ajwong): This function is getting to be too large. Either refactor it
+  // so the test can specify a configuration of WebView tags that we will
+  // dynamically inject JS to generate, or move this test wholesale into
+  // something that RunPlatformAppTest() can execute purely in Javascript. This
+  // won't let us do a white-box examination of the StoragePartition equivalence
+  // directly, but we will be able to view the black box effects which is good
+  // enough.  http://crbug.com/160361
+  void NavigateAndOpenAppForIsolation(
+      GURL navigate_to_url,
+      content::WebContents** default_tag_contents1,
+      content::WebContents** default_tag_contents2,
+      content::WebContents** named_partition_contents1,
+      content::WebContents** named_partition_contents2,
+      content::WebContents** persistent_partition_contents1,
+      content::WebContents** persistent_partition_contents2,
+      content::WebContents** persistent_partition_contents3) {
+    GURL::Replacements replace_host;
+    std::string host_str("localhost");  // Must stay in scope with replace_host.
+    replace_host.SetHostStr(host_str);
+
+    navigate_to_url = navigate_to_url.ReplaceComponents(replace_host);
+
+    GURL tag_url1 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/cookie.html");
+    tag_url1 = tag_url1.ReplaceComponents(replace_host);
+    GURL tag_url2 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/cookie2.html");
+    tag_url2 = tag_url2.ReplaceComponents(replace_host);
+    GURL tag_url3 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html");
+    tag_url3 = tag_url3.ReplaceComponents(replace_host);
+    GURL tag_url4 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage2.html");
+    tag_url4 = tag_url4.ReplaceComponents(replace_host);
+    GURL tag_url5 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html#p1");
+    tag_url5 = tag_url5.ReplaceComponents(replace_host);
+    GURL tag_url6 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html#p2");
+    tag_url6 = tag_url6.ReplaceComponents(replace_host);
+    GURL tag_url7 = embedded_test_server()->GetURL(
+        "/extensions/platform_apps/web_view/isolation/storage1.html#p3");
+    tag_url7 = tag_url7.ReplaceComponents(replace_host);
+
+    ui_test_utils::NavigateToURLWithDisposition(
+        browser(), navigate_to_url, CURRENT_TAB,
+        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+    ui_test_utils::UrlLoadObserver observer1(
+        tag_url1, content::NotificationService::AllSources());
+    ui_test_utils::UrlLoadObserver observer2(
+        tag_url2, content::NotificationService::AllSources());
+    ui_test_utils::UrlLoadObserver observer3(
+        tag_url3, content::NotificationService::AllSources());
+    ui_test_utils::UrlLoadObserver observer4(
+        tag_url4, content::NotificationService::AllSources());
+    ui_test_utils::UrlLoadObserver observer5(
+        tag_url5, content::NotificationService::AllSources());
+    ui_test_utils::UrlLoadObserver observer6(
+        tag_url6, content::NotificationService::AllSources());
+    ui_test_utils::UrlLoadObserver observer7(
+        tag_url7, content::NotificationService::AllSources());
+    LoadAndLaunchPlatformApp("web_view/isolation");
+    observer1.Wait();
+    observer2.Wait();
+    observer3.Wait();
+    observer4.Wait();
+    observer5.Wait();
+    observer6.Wait();
+    observer7.Wait();
+
+    content::Source<content::NavigationController> source1 = observer1.source();
+    EXPECT_TRUE(source1->GetWebContents()->GetRenderProcessHost()->IsGuest());
+    content::Source<content::NavigationController> source2 = observer2.source();
+    EXPECT_TRUE(source2->GetWebContents()->GetRenderProcessHost()->IsGuest());
+    content::Source<content::NavigationController> source3 = observer3.source();
+    EXPECT_TRUE(source3->GetWebContents()->GetRenderProcessHost()->IsGuest());
+    content::Source<content::NavigationController> source4 = observer4.source();
+    EXPECT_TRUE(source4->GetWebContents()->GetRenderProcessHost()->IsGuest());
+    content::Source<content::NavigationController> source5 = observer5.source();
+    EXPECT_TRUE(source5->GetWebContents()->GetRenderProcessHost()->IsGuest());
+    content::Source<content::NavigationController> source6 = observer6.source();
+    EXPECT_TRUE(source6->GetWebContents()->GetRenderProcessHost()->IsGuest());
+    content::Source<content::NavigationController> source7 = observer7.source();
+    EXPECT_TRUE(source7->GetWebContents()->GetRenderProcessHost()->IsGuest());
+
+    // Check that the first two tags use the same process and it is different
+    // than the process used by the other two.
+    EXPECT_EQ(source1->GetWebContents()->GetRenderProcessHost()->GetID(),
+              source2->GetWebContents()->GetRenderProcessHost()->GetID());
+    EXPECT_EQ(source3->GetWebContents()->GetRenderProcessHost()->GetID(),
+              source4->GetWebContents()->GetRenderProcessHost()->GetID());
+    EXPECT_NE(source1->GetWebContents()->GetRenderProcessHost()->GetID(),
+              source3->GetWebContents()->GetRenderProcessHost()->GetID());
+
+    // The two sets of tags should also be isolated from the main browser.
+    EXPECT_NE(source1->GetWebContents()->GetRenderProcessHost()->GetID(),
+              browser()->tab_strip_model()->GetWebContentsAt(0)->
+                  GetRenderProcessHost()->GetID());
+    EXPECT_NE(source3->GetWebContents()->GetRenderProcessHost()->GetID(),
+              browser()->tab_strip_model()->GetWebContentsAt(0)->
+                  GetRenderProcessHost()->GetID());
+
+    // Check that the storage partitions of the first two tags match and are
+    // different than the other two.
+    EXPECT_EQ(
+        source1->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition(),
+        source2->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition());
+    EXPECT_EQ(
+        source3->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition(),
+        source4->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition());
+    EXPECT_NE(
+        source1->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition(),
+        source3->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition());
+
+    // Ensure the persistent storage partitions are different.
+    EXPECT_EQ(
+        source5->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition(),
+        source6->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition());
+    EXPECT_NE(
+        source5->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition(),
+        source7->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition());
+    EXPECT_NE(
+        source1->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition(),
+        source5->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition());
+    EXPECT_NE(
+        source1->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition(),
+        source7->GetWebContents()->GetRenderProcessHost()->
+            GetStoragePartition());
+
+    *default_tag_contents1 = source1->GetWebContents();
+    *default_tag_contents2 = source2->GetWebContents();
+    *named_partition_contents1 = source3->GetWebContents();
+    *named_partition_contents2 = source4->GetWebContents();
+    if (persistent_partition_contents1) {
+      *persistent_partition_contents1 = source5->GetWebContents();
+    }
+    if (persistent_partition_contents2) {
+      *persistent_partition_contents2 = source6->GetWebContents();
+    }
+    if (persistent_partition_contents3) {
+      *persistent_partition_contents3 = source7->GetWebContents();
+    }
+  }
+
+  void ExecuteScriptWaitForTitle(content::WebContents* web_contents,
+                                 const char* script,
+                                 const char* title) {
+    string16 expected_title(ASCIIToUTF16(title));
+    string16 error_title(ASCIIToUTF16("error"));
+
+    content::TitleWatcher title_watcher(web_contents, expected_title);
+    title_watcher.AlsoWaitForTitle(error_title);
+    EXPECT_TRUE(content::ExecuteScript(web_contents, script));
+    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+  }
+
+  // Handles |request| by serving a redirect response.
+  static scoped_ptr<net::test_server::HttpResponse> RedirectResponseHandler(
+      const std::string& path,
+      const GURL& redirect_target,
+      const net::test_server::HttpRequest& request) {
+    if (!StartsWithASCII(path, request.relative_url, true))
+      return scoped_ptr<net::test_server::HttpResponse>();
+
+    scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+        new net::test_server::BasicHttpResponse);
+    http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+    http_response->AddCustomHeader("Location", redirect_target.spec());
+    return http_response.PassAs<net::test_server::HttpResponse>();
+  }
+
+  // Handles |request| by serving an empty response.
+  static scoped_ptr<net::test_server::HttpResponse> EmptyResponseHandler(
+      const std::string& path,
+      const net::test_server::HttpRequest& request) {
+    if (StartsWithASCII(path, request.relative_url, true)) {
+      return scoped_ptr<net::test_server::HttpResponse>(
+          new EmptyHttpResponse);
+    }
+
+    return scoped_ptr<net::test_server::HttpResponse>();
+  }
+
+  void TestHelper(const std::string& test_name,
+                  const std::string& test_passed_msg,
+                  const std::string& test_failed_msg,
+                  const std::string& app_location) {
+    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+    ExtensionTestMessageListener launched_listener("Launched", false);
+    LoadAndLaunchPlatformApp(app_location.c_str());
+    ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+    embedded_test_server()->RegisterRequestHandler(
+        base::Bind(&WebViewTest::RedirectResponseHandler,
+                   kRedirectResponsePath,
+                   embedded_test_server()->GetURL(kRedirectResponseFullPath)));
+
+    embedded_test_server()->RegisterRequestHandler(
+        base::Bind(&WebViewTest::EmptyResponseHandler, kEmptyResponsePath));
+
+    content::WebContents* embedder_web_contents =
+        GetFirstShellWindowWebContents();
+    ASSERT_TRUE(embedder_web_contents);
+
+    ExtensionTestMessageListener done_listener(test_passed_msg, false);
+    done_listener.AlsoListenForFailureMessage(test_failed_msg);
+    EXPECT_TRUE(content::ExecuteScript(
+                    embedder_web_contents,
+                    base::StringPrintf("runTest('%s')", test_name.c_str())));
+    ASSERT_TRUE(done_listener.WaitUntilSatisfied());
+  }
+
+  content::WebContents* LoadGuest(const std::string& guest_path,
+                                  const std::string& app_path) {
+    GURL::Replacements replace_host;
+    std::string host_str("localhost");  // Must stay in scope with replace_host.
+    replace_host.SetHostStr(host_str);
+
+    GURL guest_url = embedded_test_server()->GetURL(guest_path);
+    guest_url = guest_url.ReplaceComponents(replace_host);
+
+    ui_test_utils::UrlLoadObserver guest_observer(
+        guest_url, content::NotificationService::AllSources());
+
+    ExtensionTestMessageListener guest_loaded_listener("guest-loaded", false);
+    LoadAndLaunchPlatformApp(app_path.c_str());
+    guest_observer.Wait();
+
+    content::Source<content::NavigationController> source =
+        guest_observer.source();
+    EXPECT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());
+
+    bool satisfied = guest_loaded_listener.WaitUntilSatisfied();
+    if (!satisfied)
+      return NULL;
+
+    content::WebContents* guest_web_contents = source->GetWebContents();
+    return guest_web_contents;
+  }
+
+  // Runs media_access/allow tests.
+  void MediaAccessAPIAllowTestHelper(const std::string& test_name);
+
+  // Runs media_access/deny tests, each of them are run separately otherwise
+  // they timeout (mostly on Windows).
+  void MediaAccessAPIDenyTestHelper(const std::string& test_name) {
+    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+    ExtensionTestMessageListener loaded_listener("loaded", false);
+    LoadAndLaunchPlatformApp("web_view/media_access/deny");
+    ASSERT_TRUE(loaded_listener.WaitUntilSatisfied());
+
+    content::WebContents* embedder_web_contents =
+        GetFirstShellWindowWebContents();
+    ASSERT_TRUE(embedder_web_contents);
+
+    ExtensionTestMessageListener test_run_listener("PASSED", false);
+    test_run_listener.AlsoListenForFailureMessage("FAILED");
+    EXPECT_TRUE(
+        content::ExecuteScript(
+            embedder_web_contents,
+            base::StringPrintf("startDenyTest('%s')", test_name.c_str())));
+    ASSERT_TRUE(test_run_listener.WaitUntilSatisfied());
+  }
+
+  void WaitForInterstitial(content::WebContents* web_contents) {
+    scoped_refptr<content::MessageLoopRunner> loop_runner(
+        new content::MessageLoopRunner);
+    InterstitialObserver observer(web_contents,
+                                  loop_runner->QuitClosure(),
+                                  base::Closure());
+    if (!content::InterstitialPage::GetInterstitialPage(web_contents))
+      loop_runner->Run();
+  }
+
+ private:
+  scoped_ptr<content::FakeSpeechRecognitionManager>
+      fake_speech_recognition_manager_;
+};
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAutosizeAfterNavigation) {
+  TestHelper("testAutosizeAfterNavigation",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAutosizeBeforeNavigation) {
+  TestHelper("testAutosizeBeforeNavigation",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAutosizeRemoveAttributes) {
+  TestHelper("testAutosizeRemoveAttributes",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAutosizeWithPartialAttributes) {
+  TestHelper("testAutosizeWithPartialAttributes",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAPIMethodExistence) {
+  TestHelper("testAPIMethodExistence",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+// Tests the existence of WebRequest API event objects on the request
+// object, on the webview element, and hanging directly off webview.
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestWebRequestAPIExistence) {
+  TestHelper("testWebRequestAPIExistence",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestEventName) {
+  TestHelper("testEventName",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+// WebViewTest.Shim_TestDestroyOnEventListener is flaky, so disable it.
+// http://crbug.com/255106
+IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_Shim_TestDestroyOnEventListener) {
+  TestHelper("testDestroyOnEventListener",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestCannotMutateEventName) {
+  TestHelper("testCannotMutateEventName",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestPartitionRaisesException) {
+#if defined(OS_WIN)
+  // Flaky on XP bot http://crbug.com/267304
+  if (base::win::GetVersion() <= base::win::VERSION_XP)
+    return;
+#endif
+
+  TestHelper("testPartitionRaisesException",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestExecuteScriptFail) {
+#if defined(OS_WIN)
+  // Flaky on XP bot http://crbug.com/266185
+  if (base::win::GetVersion() <= base::win::VERSION_XP)
+    return;
+#endif
+
+  TestHelper("testExecuteScriptFail",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestExecuteScript) {
+  TestHelper("testExecuteScript",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestTerminateAfterExit) {
+  TestHelper("testTerminateAfterExit",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAssignSrcAfterCrash) {
+  TestHelper("testAssignSrcAfterCrash",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveSrcAttribute) {
+  TestHelper("testRemoveSrcAttribute",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestBrowserPluginNotAllowed) {
+#if defined(OS_WIN)
+  // Flaky on XP bots. http://crbug.com/267300
+  if (base::win::GetVersion() <= base::win::VERSION_XP)
+    return;
+#endif
+
+  TestHelper("testBrowserPluginNotAllowed",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindow) {
+  TestHelper("testNewWindow",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowTwoListeners) {
+  TestHelper("testNewWindowTwoListeners",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowNoPreventDefault) {
+  TestHelper("testNewWindowNoPreventDefault",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowNoReferrerLink) {
+  TestHelper("testNewWindowNoReferrerLink",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestContentLoadEvent) {
+  TestHelper("testContentLoadEvent",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestWebRequestAPI) {
+  TestHelper("testWebRequestAPI",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestWebRequestAPIGoogleProperty) {
+  TestHelper("testWebRequestAPIGoogleProperty",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadStartLoadRedirect) {
+  TestHelper("testLoadStartLoadRedirect",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadAbortEmptyResponse) {
+  TestHelper("testLoadAbortEmptyResponse",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadAbortIllegalChromeURL) {
+  TestHelper("testLoadAbortIllegalChromeURL",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadAbortIllegalFileURL) {
+  TestHelper("testLoadAbortIllegalFileURL",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestReload) {
+  TestHelper("testReload",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestGetProcessId) {
+  TestHelper("testGetProcessId",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveWebviewOnExit) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+
+  // Launch the app and wait until it's ready to load a test.
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("web_view/shim");
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  content::WebContents* embedder_web_contents =
+      GetFirstShellWindowWebContents();
+  ASSERT_TRUE(embedder_web_contents);
+
+  GURL::Replacements replace_host;
+  std::string host_str("localhost");  // Must stay in scope with replace_host.
+  replace_host.SetHostStr(host_str);
+
+  std::string guest_path(
+      "/extensions/platform_apps/web_view/shim/empty_guest.html");
+  GURL guest_url = embedded_test_server()->GetURL(guest_path);
+  guest_url = guest_url.ReplaceComponents(replace_host);
+
+  ui_test_utils::UrlLoadObserver guest_observer(
+      guest_url, content::NotificationService::AllSources());
+
+  // Run the test and wait until the guest WebContents is available and has
+  // finished loading.
+  ExtensionTestMessageListener guest_loaded_listener("guest-loaded", false);
+  EXPECT_TRUE(content::ExecuteScript(
+                  embedder_web_contents,
+                  "runTest('testRemoveWebviewOnExit')"));
+  guest_observer.Wait();
+
+  content::Source<content::NavigationController> source =
+      guest_observer.source();
+  EXPECT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());
+
+  ASSERT_TRUE(guest_loaded_listener.WaitUntilSatisfied());
+
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+      content::Source<content::WebContents>(source->GetWebContents()));
+
+  // Tell the embedder to kill the guest.
+  EXPECT_TRUE(content::ExecuteScript(
+                  embedder_web_contents,
+                  "removeWebviewOnExitDoCrash();"));
+
+  // Wait until the guest WebContents is destroyed.
+  observer.Wait();
+}
+
+// Remove <webview> immediately after navigating it.
+// This is a regression test for http://crbug.com/276023.
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveWebviewAfterNavigation) {
+  TestHelper("testRemoveWebviewAfterNavigation",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestResizeWebviewResizesContent) {
+  TestHelper("testResizeWebviewResizesContent",
+             "DoneShimTest.PASSED",
+             "DoneShimTest.FAILED",
+             "web_view/shim");
+}
+
+// This test makes sure we do not crash if app is closed while interstitial
+// page is being shown in guest.
+IN_PROC_BROWSER_TEST_F(WebViewTest, InterstitialTeardown) {
+  // Start a HTTPS server so we can load an interstitial page inside guest.
+  net::SpawnedTestServer::SSLOptions ssl_options;
+  ssl_options.server_certificate =
+      net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
+  net::SpawnedTestServer https_server(
+      net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
+      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+  ASSERT_TRUE(https_server.Start());
+
+  net::HostPortPair host_and_port = https_server.host_port_pair();
+
+  ExtensionTestMessageListener embedder_loaded_listener("EmbedderLoaded",
+                                                        false);
+  LoadAndLaunchPlatformApp("web_view/interstitial_teardown");
+  ASSERT_TRUE(embedder_loaded_listener.WaitUntilSatisfied());
+
+  WebContentsCreatedListener web_contents_created_listener;
+
+  // Now load the guest.
+  content::WebContents* embedder_web_contents =
+      GetFirstShellWindowWebContents();
+  ExtensionTestMessageListener second("GuestAddedToDom", false);
+  EXPECT_TRUE(content::ExecuteScript(
+      embedder_web_contents,
+      base::StringPrintf("loadGuest(%d);\n", host_and_port.port())));
+  ASSERT_TRUE(second.WaitUntilSatisfied());
+
+  // Wait for interstitial page to be shown in guest.
+  content::WebContents* guest_web_contents =
+      web_contents_created_listener.WaitForWebContentsCreated();
+  ASSERT_TRUE(guest_web_contents->GetRenderProcessHost()->IsGuest());
+  WaitForInterstitial(guest_web_contents);
+
+  // Now close the app while interstitial page being shown in guest.
+  apps::ShellWindow* window = GetFirstShellWindow();
+  window->GetBaseWindow()->Close();
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, ShimSrcAttribute) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/src_attribute"))
+      << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Size) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/size")) << message_;
+}
+
+// This test verifies that prerendering has been disabled inside <webview>.
+// This test is here rather than in PrerenderBrowserTest for testing convenience
+// only. If it breaks then this is a bug in the prerenderer.
+IN_PROC_BROWSER_TEST_F(WebViewTest, NoPrerenderer) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  content::WebContents* guest_web_contents =
+      LoadGuest(
+          "/extensions/platform_apps/web_view/noprerenderer/guest.html",
+          "web_view/noprerenderer");
+  ASSERT_TRUE(guest_web_contents != NULL);
+
+  PrerenderLinkManager* prerender_link_manager =
+      PrerenderLinkManagerFactory::GetForProfile(
+          Profile::FromBrowserContext(guest_web_contents->GetBrowserContext()));
+  ASSERT_TRUE(prerender_link_manager != NULL);
+  EXPECT_TRUE(prerender_link_manager->IsEmpty());
+}
+
+// This tests cookie isolation for packaged apps with webview tags. It navigates
+// the main browser window to a page that sets a cookie and loads an app with
+// multiple webview tags. Each tag sets a cookie and the test checks the proper
+// storage isolation is enforced.
+IN_PROC_BROWSER_TEST_F(WebViewTest, CookieIsolation) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  const std::string kExpire =
+      "var expire = new Date(Date.now() + 24 * 60 * 60 * 1000);";
+  std::string cookie_script1(kExpire);
+  cookie_script1.append(
+      "document.cookie = 'guest1=true; path=/; expires=' + expire + ';';");
+  std::string cookie_script2(kExpire);
+  cookie_script2.append(
+      "document.cookie = 'guest2=true; path=/; expires=' + expire + ';';");
+
+  GURL::Replacements replace_host;
+  std::string host_str("localhost");  // Must stay in scope with replace_host.
+  replace_host.SetHostStr(host_str);
+
+  GURL set_cookie_url = embedded_test_server()->GetURL(
+      "/extensions/platform_apps/isolation/set_cookie.html");
+  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
+
+  // The first two partitions will be used to set cookies and ensure they are
+  // shared. The named partition is used to ensure that cookies are isolated
+  // between partitions within the same app.
+  content::WebContents* cookie_contents1;
+  content::WebContents* cookie_contents2;
+  content::WebContents* named_partition_contents1;
+  content::WebContents* named_partition_contents2;
+
+  NavigateAndOpenAppForIsolation(set_cookie_url, &cookie_contents1,
+                                 &cookie_contents2, &named_partition_contents1,
+                                 &named_partition_contents2, NULL, NULL, NULL);
+
+  EXPECT_TRUE(content::ExecuteScript(cookie_contents1, cookie_script1));
+  EXPECT_TRUE(content::ExecuteScript(cookie_contents2, cookie_script2));
+
+  int cookie_size;
+  std::string cookie_value;
+
+  // Test the regular browser context to ensure we have only one cookie.
+  automation_util::GetCookies(GURL("http://localhost"),
+                              browser()->tab_strip_model()->GetWebContentsAt(0),
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("testCookie=1", cookie_value);
+
+  // The default behavior is to combine webview tags with no explicit partition
+  // declaration into the same in-memory partition. Test the webview tags to
+  // ensure we have properly set the cookies and we have both cookies in both
+  // tags.
+  automation_util::GetCookies(GURL("http://localhost"),
+                              cookie_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("guest1=true; guest2=true", cookie_value);
+
+  automation_util::GetCookies(GURL("http://localhost"),
+                              cookie_contents2,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("guest1=true; guest2=true", cookie_value);
+
+  // The third tag should not have any cookies as it is in a separate partition.
+  automation_util::GetCookies(GURL("http://localhost"),
+                              named_partition_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("", cookie_value);
+}
+
+// This tests that in-memory storage partitions are reset on browser restart,
+// but persistent ones maintain state for cookies and HTML5 storage.
+IN_PROC_BROWSER_TEST_F(WebViewTest, PRE_StoragePersistence) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  const std::string kExpire =
+      "var expire = new Date(Date.now() + 24 * 60 * 60 * 1000);";
+  std::string cookie_script1(kExpire);
+  cookie_script1.append(
+      "document.cookie = 'inmemory=true; path=/; expires=' + expire + ';';");
+  std::string cookie_script2(kExpire);
+  cookie_script2.append(
+      "document.cookie = 'persist1=true; path=/; expires=' + expire + ';';");
+  std::string cookie_script3(kExpire);
+  cookie_script3.append(
+      "document.cookie = 'persist2=true; path=/; expires=' + expire + ';';");
+
+  // We don't care where the main browser is on this test.
+  GURL blank_url("about:blank");
+
+  // The first two partitions will be used to set cookies and ensure they are
+  // shared. The named partition is used to ensure that cookies are isolated
+  // between partitions within the same app.
+  content::WebContents* cookie_contents1;
+  content::WebContents* cookie_contents2;
+  content::WebContents* named_partition_contents1;
+  content::WebContents* named_partition_contents2;
+  content::WebContents* persistent_partition_contents1;
+  content::WebContents* persistent_partition_contents2;
+  content::WebContents* persistent_partition_contents3;
+  NavigateAndOpenAppForIsolation(blank_url, &cookie_contents1,
+                                 &cookie_contents2, &named_partition_contents1,
+                                 &named_partition_contents2,
+                                 &persistent_partition_contents1,
+                                 &persistent_partition_contents2,
+                                 &persistent_partition_contents3);
+
+  // Set the inmemory=true cookie for tags with inmemory partitions.
+  EXPECT_TRUE(content::ExecuteScript(cookie_contents1, cookie_script1));
+  EXPECT_TRUE(content::ExecuteScript(named_partition_contents1,
+                                     cookie_script1));
+
+  // For the two different persistent storage partitions, set the
+  // two different cookies so we can check that they aren't comingled below.
+  EXPECT_TRUE(content::ExecuteScript(persistent_partition_contents1,
+                                     cookie_script2));
+
+  EXPECT_TRUE(content::ExecuteScript(persistent_partition_contents3,
+                                     cookie_script3));
+
+  int cookie_size;
+  std::string cookie_value;
+
+  // Check that all in-memory partitions have a cookie set.
+  automation_util::GetCookies(GURL("http://localhost"),
+                              cookie_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("inmemory=true", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              cookie_contents2,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("inmemory=true", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              named_partition_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("inmemory=true", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              named_partition_contents2,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("inmemory=true", cookie_value);
+
+  // Check that all persistent partitions kept their state.
+  automation_util::GetCookies(GURL("http://localhost"),
+                              persistent_partition_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("persist1=true", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              persistent_partition_contents2,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("persist1=true", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              persistent_partition_contents3,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("persist2=true", cookie_value);
+}
+
+// This is the post-reset portion of the StoragePersistence test.  See
+// PRE_StoragePersistence for main comment.
+IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_StoragePersistence) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  // We don't care where the main browser is on this test.
+  GURL blank_url("about:blank");
+
+  // The first two partitions will be used to set cookies and ensure they are
+  // shared. The named partition is used to ensure that cookies are isolated
+  // between partitions within the same app.
+  content::WebContents* cookie_contents1;
+  content::WebContents* cookie_contents2;
+  content::WebContents* named_partition_contents1;
+  content::WebContents* named_partition_contents2;
+  content::WebContents* persistent_partition_contents1;
+  content::WebContents* persistent_partition_contents2;
+  content::WebContents* persistent_partition_contents3;
+  NavigateAndOpenAppForIsolation(blank_url, &cookie_contents1,
+                                 &cookie_contents2, &named_partition_contents1,
+                                 &named_partition_contents2,
+                                 &persistent_partition_contents1,
+                                 &persistent_partition_contents2,
+                                 &persistent_partition_contents3);
+
+  int cookie_size;
+  std::string cookie_value;
+
+  // Check that all in-memory partitions lost their state.
+  automation_util::GetCookies(GURL("http://localhost"),
+                              cookie_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              cookie_contents2,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              named_partition_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              named_partition_contents2,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("", cookie_value);
+
+  // Check that all persistent partitions kept their state.
+  automation_util::GetCookies(GURL("http://localhost"),
+                              persistent_partition_contents1,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("persist1=true", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              persistent_partition_contents2,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("persist1=true", cookie_value);
+  automation_util::GetCookies(GURL("http://localhost"),
+                              persistent_partition_contents3,
+                              &cookie_size, &cookie_value);
+  EXPECT_EQ("persist2=true", cookie_value);
+}
+
+#if defined(OS_WIN)
+// This test is very flaky on Win Aura, Win XP, Win 7. http://crbug.com/248873
+#define MAYBE_DOMStorageIsolation DISABLED_DOMStorageIsolation
+#else
+#define MAYBE_DOMStorageIsolation DOMStorageIsolation
+#endif
+
+// This tests DOM storage isolation for packaged apps with webview tags. It
+// loads an app with multiple webview tags and each tag sets DOM storage
+// entries, which the test checks to ensure proper storage isolation is
+// enforced.
+IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_DOMStorageIsolation) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  GURL regular_url = embedded_test_server()->GetURL("/title1.html");
+
+  std::string output;
+  std::string get_local_storage("window.domAutomationController.send("
+      "window.localStorage.getItem('foo') || 'badval')");
+  std::string get_session_storage("window.domAutomationController.send("
+      "window.sessionStorage.getItem('bar') || 'badval')");
+
+  content::WebContents* default_tag_contents1;
+  content::WebContents* default_tag_contents2;
+  content::WebContents* storage_contents1;
+  content::WebContents* storage_contents2;
+
+  NavigateAndOpenAppForIsolation(regular_url, &default_tag_contents1,
+                                 &default_tag_contents2, &storage_contents1,
+                                 &storage_contents2, NULL, NULL, NULL);
+
+  // Initialize the storage for the first of the two tags that share a storage
+  // partition.
+  EXPECT_TRUE(content::ExecuteScript(storage_contents1,
+                                     "initDomStorage('page1')"));
+
+  // Let's test that the expected values are present in the first tag, as they
+  // will be overwritten once we call the initDomStorage on the second tag.
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
+                                            get_local_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("local-page1", output.c_str());
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
+                                            get_session_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("session-page1", output.c_str());
+
+  // Now, init the storage in the second tag in the same storage partition,
+  // which will overwrite the shared localStorage.
+  EXPECT_TRUE(content::ExecuteScript(storage_contents2,
+                                     "initDomStorage('page2')"));
+
+  // The localStorage value now should reflect the one written through the
+  // second tag.
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
+                                            get_local_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("local-page2", output.c_str());
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
+                                            get_local_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("local-page2", output.c_str());
+
+  // Session storage is not shared though, as each webview tag has separate
+  // instance, even if they are in the same storage partition.
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
+                                            get_session_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("session-page1", output.c_str());
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
+                                            get_session_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("session-page2", output.c_str());
+
+  // Also, let's check that the main browser and another tag that doesn't share
+  // the same partition don't have those values stored.
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      browser()->tab_strip_model()->GetWebContentsAt(0),
+      get_local_storage.c_str(),
+      &output));
+  EXPECT_STREQ("badval", output.c_str());
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      browser()->tab_strip_model()->GetWebContentsAt(0),
+      get_session_storage.c_str(),
+      &output));
+  EXPECT_STREQ("badval", output.c_str());
+  EXPECT_TRUE(ExecuteScriptAndExtractString(default_tag_contents1,
+                                            get_local_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("badval", output.c_str());
+  EXPECT_TRUE(ExecuteScriptAndExtractString(default_tag_contents1,
+                                            get_session_storage.c_str(),
+                                            &output));
+  EXPECT_STREQ("badval", output.c_str());
+}
+
+// See crbug.com/248500
+#if defined(OS_WIN)
+#define MAYBE_IndexedDBIsolation DISABLED_IndexedDBIsolation
+#else
+#define MAYBE_IndexedDBIsolation IndexedDBIsolation
+#endif
+
+// This tests IndexedDB isolation for packaged apps with webview tags. It loads
+// an app with multiple webview tags and each tag creates an IndexedDB record,
+// which the test checks to ensure proper storage isolation is enforced.
+IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_IndexedDBIsolation) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  GURL regular_url = embedded_test_server()->GetURL("/title1.html");
+
+  content::WebContents* default_tag_contents1;
+  content::WebContents* default_tag_contents2;
+  content::WebContents* storage_contents1;
+  content::WebContents* storage_contents2;
+
+  NavigateAndOpenAppForIsolation(regular_url, &default_tag_contents1,
+                                 &default_tag_contents2, &storage_contents1,
+                                 &storage_contents2, NULL, NULL, NULL);
+
+  // Initialize the storage for the first of the two tags that share a storage
+  // partition.
+  ExecuteScriptWaitForTitle(storage_contents1, "initIDB()", "idb created");
+  ExecuteScriptWaitForTitle(storage_contents1, "addItemIDB(7, 'page1')",
+                            "addItemIDB complete");
+  ExecuteScriptWaitForTitle(storage_contents1, "readItemIDB(7)",
+                            "readItemIDB complete");
+
+  std::string output;
+  std::string get_value(
+      "window.domAutomationController.send(getValueIDB() || 'badval')");
+
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
+                                            get_value.c_str(), &output));
+  EXPECT_STREQ("page1", output.c_str());
+
+  // Initialize the db in the second tag.
+  ExecuteScriptWaitForTitle(storage_contents2, "initIDB()", "idb open");
+
+  // Since we share a partition, reading the value should return the existing
+  // one.
+  ExecuteScriptWaitForTitle(storage_contents2, "readItemIDB(7)",
+                            "readItemIDB complete");
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
+                                            get_value.c_str(), &output));
+  EXPECT_STREQ("page1", output.c_str());
+
+  // Now write through the second tag and read it back.
+  ExecuteScriptWaitForTitle(storage_contents2, "addItemIDB(7, 'page2')",
+                            "addItemIDB complete");
+  ExecuteScriptWaitForTitle(storage_contents2, "readItemIDB(7)",
+                            "readItemIDB complete");
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
+                                            get_value.c_str(), &output));
+  EXPECT_STREQ("page2", output.c_str());
+
+  // Reset the document title, otherwise the next call will not see a change and
+  // will hang waiting for it.
+  EXPECT_TRUE(content::ExecuteScript(storage_contents1,
+                                     "document.title = 'foo'"));
+
+  // Read through the first tag to ensure we have the second value.
+  ExecuteScriptWaitForTitle(storage_contents1, "readItemIDB(7)",
+                            "readItemIDB complete");
+  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
+                                            get_value.c_str(), &output));
+  EXPECT_STREQ("page2", output.c_str());
+
+  // Now, let's confirm there is no database in the main browser and another
+  // tag that doesn't share the same partition. Due to the IndexedDB API design,
+  // open will succeed, but the version will be 1, since it creates the database
+  // if it is not found. The two tags use database version 3, so we avoid
+  // ambiguity.
+  const char* script =
+      "indexedDB.open('isolation').onsuccess = function(e) {"
+      "  if (e.target.result.version == 1)"
+      "    document.title = 'db not found';"
+      "  else "
+      "    document.title = 'error';"
+      "}";
+  ExecuteScriptWaitForTitle(browser()->tab_strip_model()->GetWebContentsAt(0),
+                            script, "db not found");
+  ExecuteScriptWaitForTitle(default_tag_contents1, script, "db not found");
+}
+
+// This test ensures that closing app window on 'loadcommit' does not crash.
+// The test launches an app with guest and closes the window on loadcommit. It
+// then launches the app window again. The process is repeated 3 times.
+IN_PROC_BROWSER_TEST_F(WebViewTest, CloseOnLoadcommit) {
+  ExtensionTestMessageListener done_test_listener(
+      "done-close-on-loadcommit", false);
+  LoadAndLaunchPlatformApp("web_view/close_on_loadcommit");
+  ASSERT_TRUE(done_test_listener.WaitUntilSatisfied());
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIDeny_TestDeny) {
+  MediaAccessAPIDenyTestHelper("testDeny");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest,
+                       MediaAccessAPIDeny_TestDenyThenAllowThrows) {
+  MediaAccessAPIDenyTestHelper("testDenyThenAllowThrows");
+
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest,
+                       MediaAccessAPIDeny_TestDenyWithPreventDefault) {
+  MediaAccessAPIDenyTestHelper("testDenyWithPreventDefault");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest,
+                       MediaAccessAPIDeny_TestNoListenersImplyDeny) {
+  MediaAccessAPIDenyTestHelper("testNoListenersImplyDeny");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest,
+                       MediaAccessAPIDeny_TestNoPreventDefaultImpliesDeny) {
+  MediaAccessAPIDenyTestHelper("testNoPreventDefaultImpliesDeny");
+}
+
+void WebViewTest::MediaAccessAPIAllowTestHelper(const std::string& test_name) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("web_view/media_access/allow");
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  content::WebContents* embedder_web_contents =
+      GetFirstShellWindowWebContents();
+  ASSERT_TRUE(embedder_web_contents);
+  MockWebContentsDelegate* mock = new MockWebContentsDelegate;
+  embedder_web_contents->SetDelegate(mock);
+
+  ExtensionTestMessageListener done_listener("DoneMediaTest.PASSED", false);
+  done_listener.AlsoListenForFailureMessage("DoneMediaTest.FAILED");
+  EXPECT_TRUE(
+      content::ExecuteScript(
+          embedder_web_contents,
+          base::StringPrintf("startAllowTest('%s')",
+                             test_name.c_str())));
+  ASSERT_TRUE(done_listener.WaitUntilSatisfied());
+
+  mock->WaitForSetMediaPermission();
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllow) {
+  MediaAccessAPIAllowTestHelper("testAllow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllowAndThenDeny) {
+  MediaAccessAPIAllowTestHelper("testAllowAndThenDeny");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllowTwice) {
+  MediaAccessAPIAllowTestHelper("testAllowTwice");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllowAsync) {
+  MediaAccessAPIAllowTestHelper("testAllowAsync");
+}
+
+// Checks that window.screenX/screenY/screenLeft/screenTop works correctly for
+// guests.
+IN_PROC_BROWSER_TEST_F(WebViewTest, ScreenCoordinates) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTestWithArg(
+      "platform_apps/web_view/common", "screen_coordinates"))
+          << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, SpeechRecognition) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+  content::WebContents* guest_web_contents = LoadGuest(
+      "/extensions/platform_apps/web_view/speech/guest.html",
+      "web_view/speech");
+  ASSERT_TRUE(guest_web_contents);
+
+  // Click on the guest (center of the WebContents), the guest is rendered in a
+  // way that this will trigger clicking on speech recognition input mic.
+  SimulateMouseClick(guest_web_contents, 0, WebKit::WebMouseEvent::ButtonLeft);
+
+  string16 expected_title(ASCIIToUTF16("PASSED"));
+  string16 error_title(ASCIIToUTF16("FAILED"));
+  content::TitleWatcher title_watcher(guest_web_contents, expected_title);
+  title_watcher.AlsoWaitForTitle(error_title);
+  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, TearDownTest) {
+  ExtensionTestMessageListener first_loaded_listener("guest-loaded", false);
+  const extensions::Extension* extension =
+      LoadAndLaunchPlatformApp("web_view/teardown");
+  ASSERT_TRUE(first_loaded_listener.WaitUntilSatisfied());
+  apps::ShellWindow* window = NULL;
+  if (!GetShellWindowCount())
+    window = CreateShellWindow(extension);
+  else
+    window = GetFirstShellWindow();
+  CloseShellWindow(window);
+
+  // Load the app again.
+  ExtensionTestMessageListener second_loaded_listener("guest-loaded", false);
+  LoadAndLaunchPlatformApp("web_view/teardown");
+  ASSERT_TRUE(second_loaded_listener.WaitUntilSatisfied());
+}
+
+// In following GeolocationAPIEmbedderHasNoAccess* tests, embedder (i.e. the
+// platform app) does not have geolocation permission for this test.
+// No matter what the API does, geolocation permission would be denied.
+// Note that the test name prefix must be "GeolocationAPI".
+IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasNoAccessAllow) {
+  TestHelper("testDenyDenies",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_no_permission");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasNoAccessDeny) {
+  TestHelper("testDenyDenies",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_no_permission");
+}
+
+// In following GeolocationAPIEmbedderHasAccess* tests, embedder (i.e. the
+// platform app) has geolocation permission
+//
+// Note that these test names must be "GeolocationAPI" prefixed (b/c we mock out
+// geolocation in this case).
+//
+// Also note that these are run separately because OverrideGeolocation() doesn't
+// mock out geolocation for multiple navigator.geolocation calls properly and
+// the tests become flaky.
+// GeolocationAPI* test 1 of 3.
+IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasAccessAllow) {
+  TestHelper("testAllow",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_permission");
+}
+
+// GeolocationAPI* test 2 of 3.
+IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasAccessDeny) {
+  TestHelper("testDeny",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_permission");
+}
+
+// GeolocationAPI* test 3 of 3.
+IN_PROC_BROWSER_TEST_F(WebViewTest,
+                       GeolocationAPIEmbedderHasAccessMultipleBridgeIdAllow) {
+  TestHelper("testMultipleBridgeIdAllow",
+             "DoneGeolocationTest.PASSED",
+             "DoneGeolocationTest.FAILED",
+             "web_view/geolocation/embedder_has_permission");
+}
+
+// Tests that
+// BrowserPluginGeolocationPermissionContext::CancelGeolocationPermissionRequest
+// is handled correctly (and does not crash).
+IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPICancelGeolocation) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTest(
+        "platform_apps/web_view/geolocation/cancel_request")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationRequestGone) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTest(
+        "platform_apps/web_view/geolocation/geolocation_request_gone"))
+            << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, ClearData) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTestWithArg(
+      "platform_apps/web_view/common", "cleardata"))
+          << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, ConsoleMessage) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTestWithArg(
+      "platform_apps/web_view/common", "console_messages"))
+          << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, DownloadPermission) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  content::WebContents* guest_web_contents =
+      LoadGuest("/extensions/platform_apps/web_view/download/guest.html",
+                "web_view/download");
+  ASSERT_TRUE(guest_web_contents);
+
+  // Replace WebContentsDelegate with mock version so we can intercept download
+  // requests.
+  content::WebContentsDelegate* delegate = guest_web_contents->GetDelegate();
+  MockDownloadWebContentsDelegate* mock_delegate =
+      new MockDownloadWebContentsDelegate(delegate);
+  guest_web_contents->SetDelegate(mock_delegate);
+
+  // Start test.
+  // 1. Guest requests a download that its embedder denies.
+  EXPECT_TRUE(content::ExecuteScript(guest_web_contents,
+                                     "startDownload('download-link-1')"));
+  mock_delegate->WaitForCanDownload(false); // Expect to not allow.
+  mock_delegate->Reset();
+
+  // 2. Guest requests a download that its embedder allows.
+  EXPECT_TRUE(content::ExecuteScript(guest_web_contents,
+                                     "startDownload('download-link-2')"));
+  mock_delegate->WaitForCanDownload(true); // Expect to allow.
+  mock_delegate->Reset();
+
+  // 3. Guest requests a download that its embedder ignores, this implies deny.
+  EXPECT_TRUE(content::ExecuteScript(guest_web_contents,
+                                     "startDownload('download-link-3')"));
+  mock_delegate->WaitForCanDownload(false); // Expect to not allow.
+}
+
+// This test makes sure loading <webview> does not crash when there is an
+// 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;
+  const std::string extension_id = "imeongpbjoodlnmlakaldhlcmijmhpbb";
+  whitelist.push_back(extension_id);
+  extensions::Extension::SetScriptingWhitelist(whitelist);
+
+  // Load the extension.
+  const extensions::Extension* content_script_whitelisted_extension =
+      LoadExtension(test_data_dir_.AppendASCII(
+                        "platform_apps/web_view/legacy/content_script"));
+  ASSERT_TRUE(content_script_whitelisted_extension);
+  ASSERT_EQ(extension_id, content_script_whitelisted_extension->id());
+
+  // Now load an app with <webview>.
+  ExtensionTestMessageListener done_listener("DoneTest", false);
+  LoadAndLaunchPlatformApp("web_view/content_script_whitelisted");
+  ASSERT_TRUE(done_listener.WaitUntilSatisfied());
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, SetPropertyOnDocumentReady) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/document_ready"))
+                  << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, SetPropertyOnDocumentInteractive) {
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/document_interactive"))
+                  << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestAlertDialog) {
+  TestHelper("testAlertDialog",
+             "DoneDialogTest.PASSED",
+             "DoneDialogTest.FAILED",
+             "web_view/dialog");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialog) {
+  TestHelper("testConfirmDialog",
+             "DoneDialogTest.PASSED",
+             "DoneDialogTest.FAILED",
+             "web_view/dialog");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialogCancel) {
+  TestHelper("testConfirmDialogCancel",
+             "DoneDialogTest.PASSED",
+             "DoneDialogTest.FAILED",
+             "web_view/dialog");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialogDefaultCancel) {
+  TestHelper("testConfirmDialogDefaultCancel",
+             "DoneDialogTest.PASSED",
+             "DoneDialogTest.FAILED",
+             "web_view/dialog");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialogDefaultGCCancel) {
+  TestHelper("testConfirmDialogDefaultGCCancel",
+             "DoneDialogTest.PASSED",
+             "DoneDialogTest.FAILED",
+             "web_view/dialog");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestPromptDialog) {
+  TestHelper("testPromptDialog",
+             "DoneDialogTest.PASSED",
+             "DoneDialogTest.FAILED",
+             "web_view/dialog");
+}
diff --git a/chrome/browser/apps/web_view_interactive_browsertest.cc b/chrome/browser/apps/web_view_interactive_browsertest.cc
new file mode 100644
index 0000000..4e0607d
--- /dev/null
+++ b/chrome/browser/apps/web_view_interactive_browsertest.cc
@@ -0,0 +1,678 @@
+// Copyright 2013 The Chromium Authors. 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/shell_window.h"
+#include "apps/shell_window_registry.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "chrome/test/base/test_launcher_utils.h"
+#include "chrome/test/base/ui_test_utils.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/render_widget_host_view.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/public/test/browser_test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/base/test/ui_controls.h"
+
+using apps::ShellWindow;
+
+class WebViewInteractiveTest
+    : public extensions::PlatformAppBrowserTest {
+ public:
+  WebViewInteractiveTest()
+      : corner_(gfx::Point()),
+        mouse_click_result_(false),
+        first_click_(true) {}
+
+  void MoveMouseInsideWindowWithListener(gfx::Point point,
+                                         const std::string& message) {
+    ExtensionTestMessageListener move_listener(message, false);
+    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
+        gfx::Point(corner_.x() + point.x(), corner_.y() + point.y())));
+    ASSERT_TRUE(move_listener.WaitUntilSatisfied());
+  }
+
+  void SendMouseClickWithListener(ui_controls::MouseButton button,
+                                  const std::string& message) {
+    ExtensionTestMessageListener listener(message, false);
+    SendMouseClick(button);
+    ASSERT_TRUE(listener.WaitUntilSatisfied());
+  }
+
+  void SendMouseClick(ui_controls::MouseButton button) {
+    SendMouseEvent(button, ui_controls::DOWN);
+    SendMouseEvent(button, ui_controls::UP);
+  }
+
+  void MoveMouseInsideWindow(const gfx::Point& point) {
+    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
+        gfx::Point(corner_.x() + point.x(), corner_.y() + point.y())));
+  }
+
+  gfx::NativeWindow GetPlatformAppWindow() {
+    const apps::ShellWindowRegistry::ShellWindowList& shell_windows =
+        apps::ShellWindowRegistry::Get(
+            browser()->profile())->shell_windows();
+    return (*shell_windows.begin())->GetNativeWindow();
+  }
+
+  void SendKeyPressToPlatformApp(ui::KeyboardCode key) {
+    ASSERT_EQ(1U, GetShellWindowCount());
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), key, false, false, false, false));
+  }
+
+  void SendCopyKeyPressToPlatformApp() {
+    ASSERT_EQ(1U, GetShellWindowCount());
+#if defined(OS_MACOSX)
+    // Send Cmd+C on MacOSX.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_C, false, false, false, true));
+#else
+    // Send Ctrl+C on Windows and Linux/ChromeOS.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_C, true, false, false, false));
+#endif
+  }
+
+  void SendStartOfLineKeyPressToPlatformApp() {
+#if defined(OS_MACOSX)
+    // Send Cmd+Left on MacOSX.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_LEFT, false, false, false, true));
+#else
+    // Send Ctrl+Left on Windows and Linux/ChromeOS.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_LEFT, true, false, false, false));
+#endif
+  }
+
+  void SendBackShortcutToPlatformApp() {
+#if defined(OS_MACOSX)
+    // Send Cmd+[ on MacOSX.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_OEM_4, false, false, false, true));
+#else
+    // Send browser back key on Linux/Windows.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_BROWSER_BACK,
+        false, false, false, false));
+#endif
+  }
+
+  void SendForwardShortcutToPlatformApp() {
+#if defined(OS_MACOSX)
+    // Send Cmd+] on MacOSX.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_OEM_6, false, false, false, true));
+#else
+    // Send browser back key on Linux/Windows.
+    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
+        GetPlatformAppWindow(), ui::VKEY_BROWSER_FORWARD,
+        false, false, false, false));
+#endif
+  }
+
+  void SendMouseEvent(ui_controls::MouseButton button,
+                      ui_controls::MouseButtonState state) {
+    if (first_click_) {
+      mouse_click_result_ = ui_test_utils::SendMouseEventsSync(button,
+                                                                state);
+      first_click_ = false;
+    } else {
+      ASSERT_EQ(mouse_click_result_, ui_test_utils::SendMouseEventsSync(
+          button, state));
+    }
+  }
+
+  void TestHelper(const std::string& test_name,
+                  const std::string& test_passed_msg,
+                  const std::string& test_failed_msg,
+                  const std::string& app_location) {
+    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+    ExtensionTestMessageListener launched_listener("Launched", false);
+    LoadAndLaunchPlatformApp(app_location.c_str());
+    ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+    ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
+        GetPlatformAppWindow()));
+
+    // Flush any pending events to make sure we start with a clean slate.
+    content::RunAllPendingInMessageLoop();
+
+    content::WebContents* embedder_web_contents =
+        GetFirstShellWindowWebContents();
+    ASSERT_TRUE(embedder_web_contents);
+
+    ExtensionTestMessageListener done_listener(test_passed_msg, false);
+    done_listener.AlsoListenForFailureMessage(test_failed_msg);
+    EXPECT_TRUE(content::ExecuteScript(
+                    embedder_web_contents,
+                    base::StringPrintf("runTest('%s')", test_name.c_str())));
+    ASSERT_TRUE(done_listener.WaitUntilSatisfied());
+  }
+
+  void SetupTest(const std::string& app_name,
+                 const std::string& guest_url_spec) {
+    ASSERT_TRUE(StartEmbeddedTestServer());
+    GURL::Replacements replace_host;
+    std::string host_str("localhost");  // Must stay in scope with replace_host.
+    replace_host.SetHostStr(host_str);
+
+    GURL guest_url = embedded_test_server()->GetURL(guest_url_spec);
+    guest_url = guest_url.ReplaceComponents(replace_host);
+
+    ui_test_utils::UrlLoadObserver guest_observer(
+        guest_url, content::NotificationService::AllSources());
+
+    ExtensionTestMessageListener guest_connected_listener("connected", false);
+    LoadAndLaunchPlatformApp(app_name.c_str());
+
+    guest_observer.Wait();
+
+    // Wait until the guest process reports that it has established a message
+    // channel with the app.
+    ASSERT_TRUE(guest_connected_listener.WaitUntilSatisfied());
+    content::Source<content::NavigationController> source =
+        guest_observer.source();
+    EXPECT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());
+
+    guest_web_contents_ = source->GetWebContents();
+    embedder_web_contents_ = guest_web_contents_->GetEmbedderWebContents();
+
+    gfx::Rect offset;
+    embedder_web_contents_->GetView()->GetContainerBounds(&offset);
+    corner_ = gfx::Point(offset.x(), offset.y());
+
+    const testing::TestInfo* const test_info =
+            testing::UnitTest::GetInstance()->current_test_info();
+    const std::string& prefix = "DragDropWithinWebView";
+    if (!strncmp(test_info->name(), prefix.c_str(), prefix.size())) {
+      // In the drag drop test we add 20px padding to the page body because on
+      // windows if we get too close to the edge of the window the resize cursor
+      // appears and we start dragging the window edge.
+      corner_.Offset(20, 20);
+    }
+  }
+
+  content::WebContents* guest_web_contents() {
+    return guest_web_contents_;
+  }
+
+  content::WebContents* embedder_web_contents() {
+    return embedder_web_contents_;
+  }
+
+  gfx::Point corner() {
+    return corner_;
+  }
+
+  void SimulateRWHMouseClick(content::RenderWidgetHost* rwh, int x, int y) {
+    WebKit::WebMouseEvent mouse_event;
+    mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
+    mouse_event.x = mouse_event.windowX = x;
+    mouse_event.y = mouse_event.windowY = y;
+    mouse_event.modifiers = 0;
+
+    mouse_event.type = WebKit::WebInputEvent::MouseDown;
+    rwh->ForwardMouseEvent(mouse_event);
+    mouse_event.type = WebKit::WebInputEvent::MouseUp;
+    rwh->ForwardMouseEvent(mouse_event);
+  }
+
+  class PopupCreatedObserver {
+   public:
+    PopupCreatedObserver() : created_(false), last_render_widget_host_(NULL) {
+      created_callback_ = base::Bind(
+          &PopupCreatedObserver::CreatedCallback, base::Unretained(this));
+      content::RenderWidgetHost::AddCreatedCallback(created_callback_);
+    }
+    virtual ~PopupCreatedObserver() {
+      content::RenderWidgetHost::RemoveCreatedCallback(created_callback_);
+    }
+    void Reset() {
+      created_ = false;
+    }
+    void Start() {
+      if (created_)
+        return;
+      message_loop_ = new content::MessageLoopRunner;
+      message_loop_->Run();
+    }
+    content::RenderWidgetHost* last_render_widget_host() {
+      return last_render_widget_host_;
+    }
+
+   private:
+    void CreatedCallback(content::RenderWidgetHost* rwh) {
+      last_render_widget_host_ = rwh;
+      if (message_loop_.get())
+        message_loop_->Quit();
+      else
+        created_ = true;
+    }
+    content::RenderWidgetHost::CreatedCallback created_callback_;
+    scoped_refptr<content::MessageLoopRunner> message_loop_;
+    bool created_;
+    content::RenderWidgetHost* last_render_widget_host_;
+  };
+
+  void WaitForTitle(const char* title) {
+    string16 expected_title(ASCIIToUTF16(title));
+    string16 error_title(ASCIIToUTF16("FAILED"));
+    content::TitleWatcher title_watcher(guest_web_contents(), expected_title);
+    title_watcher.AlsoWaitForTitle(error_title);
+    ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+  }
+
+  void PopupTestHelper(const gfx::Point& padding) {
+    PopupCreatedObserver popup_created_observer;
+    popup_created_observer.Reset();
+
+    content::SimulateKeyPress(
+        guest_web_contents(),
+        ui::VKEY_C,  // C to autocomplete.
+        false, false, false, false);
+
+    WaitForTitle("PASSED1");
+
+    popup_created_observer.Start();
+
+    content::RenderWidgetHost* popup_rwh = NULL;
+    popup_rwh = popup_created_observer.last_render_widget_host();
+    // Popup must be present.
+    ASSERT_TRUE(popup_rwh);
+    ASSERT_TRUE(!popup_rwh->IsRenderView());
+    ASSERT_TRUE(popup_rwh->GetView());
+
+    string16 expected_title = ASCIIToUTF16("PASSED2");
+    string16 error_title = ASCIIToUTF16("FAILED");
+    content::TitleWatcher title_watcher(guest_web_contents(), expected_title);
+    title_watcher.AlsoWaitForTitle(error_title);
+    EXPECT_TRUE(content::ExecuteScript(guest_web_contents(),
+                                       "changeTitle();"));
+    ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+
+    gfx::Rect popup_bounds = popup_rwh->GetView()->GetViewBounds();
+    // (2, 2) is expected to lie on the first datalist element.
+    SimulateRWHMouseClick(popup_rwh, 2, 2);
+
+    content::RenderViewHost* embedder_rvh =
+        GetFirstShellWindowWebContents()->GetRenderViewHost();
+    gfx::Rect embedder_bounds = embedder_rvh->GetView()->GetViewBounds();
+    gfx::Vector2d diff = popup_bounds.origin() - embedder_bounds.origin();
+    LOG(INFO) << "DIFF: x = " << diff.x() << ", y = " << diff.y();
+
+    const int left_spacing = 40 + padding.x();  // div.style.paddingLeft = 40px.
+    // div.style.paddingTop = 50px + (input box height = 26px).
+    const int top_spacing = 50 + 26 + padding.y();
+
+    // If the popup is placed within |threshold_px| of the expected position,
+    // then we consider the test as a pass.
+    const int threshold_px = 10;
+
+    EXPECT_LE(std::abs(diff.x() - left_spacing), threshold_px);
+    EXPECT_LE(std::abs(diff.y() - top_spacing), threshold_px);
+
+    WaitForTitle("PASSED3");
+  }
+
+  void DragTestStep1() {
+    // Move mouse to start of text.
+    MoveMouseInsideWindow(gfx::Point(45, 8));
+    SendMouseEvent(ui_controls::LEFT, ui_controls::DOWN);
+    MoveMouseInsideWindow(gfx::Point(76, 12));
+
+    // Now wait a bit before moving mouse to initiate drag/drop.
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&WebViewInteractiveTest::DragTestStep2,
+                   base::Unretained(this)),
+        base::TimeDelta::FromMilliseconds(200));
+  }
+
+  void DragTestStep2() {
+    // Drag source over target.
+    MoveMouseInsideWindow(gfx::Point(76, 76));
+
+    // Create a second mouse over the source to trigger the drag over event.
+    MoveMouseInsideWindow(gfx::Point(76, 77));
+
+    // Release mouse to drop.
+    SendMouseEvent(ui_controls::LEFT, ui_controls::UP);
+    SendMouseClick(ui_controls::LEFT);
+
+    quit_closure_.Run();
+
+    // Note that following ExtensionTestMessageListener and ExecuteScript*
+    // call must be after we quit |quit_closure_|. Otherwise the class
+    // here won't be able to receive messages sent by chrome.test.sendMessage.
+    // This is because of the nature of drag and drop code (esp. the
+    // MessageLoop) in it.
+
+    // Now verify we got a drop and correct drop data.
+    ExtensionTestMessageListener drop_listener("guest-got-drop", false);
+    EXPECT_TRUE(content::ExecuteScript(guest_web_contents_,
+                                       "window.pingEmbedder()"));
+    EXPECT_TRUE(drop_listener.WaitUntilSatisfied());
+
+    std::string last_drop_data;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        embedder_web_contents_,
+        "window.domAutomationController.send(getLastDropData())",
+        &last_drop_data));
+    EXPECT_EQ(last_drop_data, "Drop me");
+  }
+
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    command_line->AppendSwitch(switches::kEnableBrowserPluginDragDrop);
+    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
+  }
+
+  content::WebContents* guest_web_contents_;
+  content::WebContents* embedder_web_contents_;
+  gfx::Point corner_;
+  bool mouse_click_result_;
+  bool first_click_;
+  // Only used in drag/drop test.
+  base::Closure quit_closure_;
+};
+
+// ui_test_utils::SendMouseMoveSync doesn't seem to work on OS_MACOSX, and
+// likely won't work on many other platforms as well, so for now this test
+// is for Windows and Linux only.
+#if (defined(OS_WIN) || defined(OS_LINUX))
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PointerLock) {
+  SetupTest("web_view/pointer_lock",
+            "/extensions/platform_apps/web_view/pointer_lock/guest.html");
+
+  // Move the mouse over the Lock Pointer button.
+  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
+      gfx::Point(corner().x() + 75, corner().y() + 25)));
+
+  // Click the Lock Pointer button. The first two times the button is clicked
+  // the permission API will deny the request (intentional).
+  ExtensionTestMessageListener exception_listener("request exception", false);
+  SendMouseClickWithListener(ui_controls::LEFT, "lock error");
+  ASSERT_TRUE(exception_listener.WaitUntilSatisfied());
+  SendMouseClickWithListener(ui_controls::LEFT, "lock error");
+
+  // Click the Lock Pointer button, locking the mouse to lockTarget1.
+  SendMouseClickWithListener(ui_controls::LEFT, "locked");
+
+  // Attempt to move the mouse off of the lock target, and onto lockTarget2,
+  // (which would trigger a test failure).
+  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
+      gfx::Point(corner().x() + 74, corner().y() + 74)));
+  MoveMouseInsideWindowWithListener(gfx::Point(75, 75), "mouse-move");
+
+#if (defined(OS_WIN) && defined(USE_AURA))
+  // When the mouse is unlocked on win aura, sending a test mouse click clicks
+  // where the mouse moved to while locked. I was unable to figure out why, and
+  // since the issue only occurs with the test mouse events, just fix it with
+  // a simple workaround - moving the mouse back to where it should be.
+  // TODO(mthiesse): Fix Win Aura simulated mouse events while mouse locked.
+  MoveMouseInsideWindowWithListener(gfx::Point(75, 25), "mouse-move");
+#endif
+
+  ExtensionTestMessageListener unlocked_listener("unlocked", false);
+  // Send a key press to unlock the mouse.
+  SendKeyPressToPlatformApp(ui::VKEY_ESCAPE);
+
+  // Wait for page to receive (successful) mouse unlock response.
+  ASSERT_TRUE(unlocked_listener.WaitUntilSatisfied());
+
+  // After the second lock, guest.js sends a message to main.js to remove the
+  // webview object. main.js then removes the div containing the webview, which
+  // should unlock, and leave the mouse over the mousemove-capture-container
+  // div. We then move the mouse over that div to ensure the mouse was properly
+  // unlocked and that the div receieves the message.
+  ExtensionTestMessageListener move_captured_listener("move-captured", false);
+  move_captured_listener.AlsoListenForFailureMessage("timeout");
+
+  // Mouse should already be over lock button (since we just unlocked), so send
+  // click to re-lock the mouse.
+  SendMouseClickWithListener(ui_controls::LEFT, "deleted");
+
+  // A mousemove event is triggered on the mousemove-capture-container element
+  // when we delete the webview container (since the mouse moves onto the
+  // element), but just in case, send an explicit mouse movement to be safe.
+  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
+      gfx::Point(corner().x() + 50, corner().y() + 10)));
+
+  // Wait for page to receive second (successful) mouselock response.
+  bool success = move_captured_listener.WaitUntilSatisfied();
+  if (!success) {
+    fprintf(stderr, "TIMEOUT - retrying\n");
+    // About 1 in 40 tests fail to detect mouse moves at this point (why?).
+    // Sending a right click seems to fix this (why?).
+    ExtensionTestMessageListener move_listener2("move-captured", false);
+    SendMouseClick(ui_controls::RIGHT);
+    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
+        gfx::Point(corner().x() + 51, corner().y() + 11)));
+    ASSERT_TRUE(move_listener2.WaitUntilSatisfied());
+  }
+}
+
+#endif  // (defined(OS_WIN) || defined(OS_LINUX))
+
+// Tests that setting focus on the <webview> sets focus on the guest.
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_Focus) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/focus"))
+      << message_;
+}
+
+// Tests that guests receive edit commands and respond appropriately.
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommands) {
+  SetupTest("web_view/edit_commands",
+            "/extensions/platform_apps/web_view/edit_commands/guest.html");
+
+  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
+      GetPlatformAppWindow()));
+
+  // Flush any pending events to make sure we start with a clean slate.
+  content::RunAllPendingInMessageLoop();
+
+  ExtensionTestMessageListener copy_listener("copy", false);
+  SendCopyKeyPressToPlatformApp();
+
+  // Wait for the guest to receive a 'copy' edit command.
+  ASSERT_TRUE(copy_listener.WaitUntilSatisfied());
+}
+
+// Tests that guests receive edit commands and respond appropriately.
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommandsNoMenu) {
+  SetupTest("web_view/edit_commands_no_menu",
+      "/extensions/platform_apps/web_view/edit_commands_no_menu/"
+      "guest.html");
+
+  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
+      GetPlatformAppWindow()));
+
+  // Flush any pending events to make sure we start with a clean slate.
+  content::RunAllPendingInMessageLoop();
+
+  ExtensionTestMessageListener start_of_line_listener("StartOfLine", false);
+  SendStartOfLineKeyPressToPlatformApp();
+  // Wait for the guest to receive a 'copy' edit command.
+  ASSERT_TRUE(start_of_line_listener.WaitUntilSatisfied());
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
+                       NewWindow_NewWindowNameTakesPrecedence) {
+  TestHelper("testNewWindowNameTakesPrecedence",
+             "DoneNewWindowTest.PASSED",
+             "DoneNewWindowTest.FAILED",
+             "web_view/newwindow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
+                       NewWindow_WebViewNameTakesPrecedence) {
+  TestHelper("testWebViewNameTakesPrecedence",
+             "DoneNewWindowTest.PASSED",
+             "DoneNewWindowTest.FAILED",
+             "web_view/newwindow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_NoName) {
+  TestHelper("testNoName",
+             "DoneNewWindowTest.PASSED",
+             "DoneNewWindowTest.FAILED",
+             "web_view/newwindow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_Redirect) {
+  TestHelper("testNewWindowRedirect",
+             "DoneNewWindowTest.PASSED",
+             "DoneNewWindowTest.FAILED",
+             "web_view/newwindow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_Close) {
+  TestHelper("testNewWindowClose",
+             "DoneNewWindowTest.PASSED",
+             "DoneNewWindowTest.FAILED",
+             "web_view/newwindow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_ExecuteScript) {
+  TestHelper("testNewWindowExecuteScript",
+             "DoneNewWindowTest.PASSED",
+             "DoneNewWindowTest.FAILED",
+             "web_view/newwindow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_WebRequest) {
+  TestHelper("testNewWindowWebRequest",
+             "DoneNewWindowTest.PASSED",
+             "DoneNewWindowTest.FAILED",
+             "web_view/newwindow");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, ExecuteCode) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTestWithArg(
+      "platform_apps/web_view/common", "execute_code")) << message_;
+}
+
+// This test used the old Autofill UI, which has been removed.
+// See crbug.com/259438
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_PopupPositioning) {
+  SetupTest(
+      "web_view/popup_positioning",
+      "/extensions/platform_apps/web_view/popup_positioning/guest.html");
+  ASSERT_TRUE(guest_web_contents());
+
+  PopupTestHelper(gfx::Point());
+
+  // moveTo a random location and run the steps again.
+  EXPECT_TRUE(content::ExecuteScript(embedder_web_contents(),
+                                     "window.moveTo(16, 20);"));
+  PopupTestHelper(gfx::Point());
+}
+
+// Tests that moving browser plugin (without resize/UpdateRects) correctly
+// repositions popup.
+// Started flakily failing after a Blink roll: http://crbug.com/245332
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_PopupPositioningMoved) {
+  SetupTest(
+      "web_view/popup_positioning_moved",
+      "/extensions/platform_apps/web_view/popup_positioning_moved"
+      "/guest.html");
+  ASSERT_TRUE(guest_web_contents());
+
+  PopupTestHelper(gfx::Point(20, 0));
+}
+
+// Drag and drop inside a webview is currently only enabled for linux and mac,
+// but the tests don't work on anything except chromeos for now. This is because
+// of simulating mouse drag code's dependency on platforms.
+#if defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DragDropWithinWebView) {
+  SetupTest(
+      "web_view/dnd_within_webview",
+      "/extensions/platform_apps/web_view/dnd_within_webview/guest.html");
+  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
+
+  // Flush any pending events to make sure we start with a clean slate.
+  content::RunAllPendingInMessageLoop();
+  base::RunLoop run_loop;
+  quit_closure_ = run_loop.QuitClosure();
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&WebViewInteractiveTest::DragTestStep1,
+                 base::Unretained(this)));
+  run_loop.Run();
+}
+#endif  // (defined(OS_CHROMEOS))
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation) {
+  TestHelper("testNavigation",
+             "DoneNavigationTest.PASSED",
+             "DoneNavigationTest.FAILED",
+             "web_view/navigation");
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation_BackForwardKeys) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  LoadAndLaunchPlatformApp("web_view/navigation");
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
+      GetPlatformAppWindow()));
+  // Flush any pending events to make sure we start with a clean slate.
+  content::RunAllPendingInMessageLoop();
+
+  content::WebContents* embedder_web_contents =
+      GetFirstShellWindowWebContents();
+  ASSERT_TRUE(embedder_web_contents);
+
+  ExtensionTestMessageListener done_listener(
+      "DoneNavigationTest.PASSED", false);
+  done_listener.AlsoListenForFailureMessage("DoneNavigationTest.FAILED");
+  ExtensionTestMessageListener ready_back_key_listener(
+      "ReadyForBackKey", false);
+  ExtensionTestMessageListener ready_forward_key_listener(
+      "ReadyForForwardKey", false);
+
+  EXPECT_TRUE(content::ExecuteScript(
+                  embedder_web_contents,
+                  "runTest('testBackForwardKeys')"));
+
+  ASSERT_TRUE(ready_back_key_listener.WaitUntilSatisfied());
+  SendBackShortcutToPlatformApp();
+
+  ASSERT_TRUE(ready_forward_key_listener.WaitUntilSatisfied());
+  SendForwardShortcutToPlatformApp();
+
+  ASSERT_TRUE(done_listener.WaitUntilSatisfied());
+}
+
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
+                       PointerLock_PointerLockLostWithFocus) {
+  TestHelper("testPointerLockLostWithFocus",
+             "DonePointerLockTest.PASSED",
+             "DonePointerLockTest.FAILED",
+             "web_view/pointerlock");
+}
+
+// Currently re-adding a webview doesn't work. See http://crbug.com/260622
+IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
+                       AddRemoveWebView_AddRemoveWebView) {
+  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
+  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/addremove"))
+      << message_;
+}
diff --git a/chrome/browser/apps/window_controls_browsertest.cc b/chrome/browser/apps/window_controls_browsertest.cc
new file mode 100644
index 0000000..f5b5025
--- /dev/null
+++ b/chrome/browser/apps/window_controls_browsertest.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 "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/test/browser_test_utils.h"
+
+class WindowControlsTest : public extensions::PlatformAppBrowserTest {
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kEnableAppWindowControls);
+  }
+  content::WebContents* GetWebContentsForExtensionWindow(
+      const extensions::Extension* extension);
+};
+
+content::WebContents* WindowControlsTest::GetWebContentsForExtensionWindow(
+    const extensions::Extension* extension) {
+  ExtensionProcessManager* process_manager =
+      extensions::ExtensionSystem::Get(profile())->process_manager();
+
+  // Lookup render view host for background page.
+  const extensions::ExtensionHost* extension_host =
+      process_manager->GetBackgroundHostForExtension(extension->id());
+  content::RenderViewHost* background_view_host =
+      extension_host->render_view_host();
+
+  // Go through all active views, looking for the first window of the extension
+  const ExtensionProcessManager::ViewSet all_views =
+      process_manager->GetAllViews();
+  ExtensionProcessManager::ViewSet::const_iterator it = all_views.begin();
+  for (; it != all_views.end(); ++it) {
+    content::RenderViewHost* host = *it;
+
+    // Filter out views not part of this extension
+    if (process_manager->GetExtensionForRenderViewHost(host) == extension) {
+      // Filter out the background page view
+      if (host != background_view_host) {
+        content::WebContents* web_contents =
+            content::WebContents::FromRenderViewHost(host);
+        return web_contents;
+      }
+    }
+  }
+  return NULL;
+}
+
+IN_PROC_BROWSER_TEST_F(WindowControlsTest, CloseControlWorks) {
+  // Launch app and wait for window to show up
+  ExtensionTestMessageListener window_opened("window-opened", false);
+  const extensions::Extension* extension =
+      LoadAndLaunchPlatformApp("window_controls/buttons");
+  ASSERT_TRUE(window_opened.WaitUntilSatisfied());
+
+  // Find WebContents of window
+  content::WebContents* web_contents =
+      GetWebContentsForExtensionWindow(extension);
+  ASSERT_TRUE(web_contents != NULL);
+
+  // Send a left click on the "Close" button and wait for the close action
+  // to happen.
+  ExtensionTestMessageListener window_closed("window-closed", false);
+
+  // Send mouse click somewhere inside the [x] button
+  const int controlOffset = 25;
+  int x = web_contents->GetView()->GetContainerSize().width() - controlOffset;
+  int y = controlOffset;
+  content::SimulateMouseClickAt(web_contents,
+                                0,
+                                WebKit::WebMouseEvent::ButtonLeft,
+                                gfx::Point(x, y));
+
+  ASSERT_TRUE(window_closed.WaitUntilSatisfied());
+}
diff --git a/chrome/browser/autocomplete/autocomplete_controller.cc b/chrome/browser/autocomplete/autocomplete_controller.cc
index 4d5b8e5..915df7e 100644
--- a/chrome/browser/autocomplete/autocomplete_controller.cc
+++ b/chrome/browser/autocomplete/autocomplete_controller.cc
@@ -346,6 +346,7 @@
     result_.Reset();
     result_.AppendMatches(zero_suggest_provider_->matches());
     result_.SortAndCull(input_, profile_);
+    UpdateAssistedQueryStats(&result_);
     NotifyChanged(true);
   } else {
     CheckIfDone();
@@ -376,6 +377,33 @@
   in_zero_suggest_ = false;
 }
 
+GURL AutocompleteController::GetDestinationURL(
+    const AutocompleteMatch& match,
+    base::TimeDelta query_formulation_time) const {
+  GURL destination_url(match.destination_url);
+  TemplateURL* template_url = match.GetTemplateURL(profile_, false);
+
+  // Append the query formulation time (time from when the user first typed a
+  // character into the omnibox to when the user selected a query) and whether
+  // a field trial has triggered to the AQS parameter, if other AQS parameters
+  // were already populated.
+  if (template_url && match.search_terms_args.get() &&
+      !match.search_terms_args->assisted_query_stats.empty()) {
+    TemplateURLRef::SearchTermsArgs search_terms_args(*match.search_terms_args);
+    search_terms_args.assisted_query_stats += base::StringPrintf(
+        ".%" PRId64 "j%dj%d",
+        query_formulation_time.InMilliseconds(),
+        (search_provider_ &&
+         search_provider_->field_trial_triggered_in_session()) ||
+        (zero_suggest_provider_ &&
+         zero_suggest_provider_->field_trial_triggered_in_session()),
+        input_.current_page_classification());
+    destination_url = GURL(template_url->url_ref().
+                           ReplaceSearchTerms(search_terms_args));
+  }
+  return destination_url;
+}
+
 void AutocompleteController::UpdateResult(
     bool regenerate_result,
     bool force_notify_default_match_changed) {
@@ -482,6 +510,40 @@
   }
 }
 
+void AutocompleteController::UpdateKeywordDescriptions(
+    AutocompleteResult* result) {
+  string16 last_keyword;
+  for (AutocompleteResult::iterator i(result->begin()); i != result->end();
+       ++i) {
+    if ((i->provider->type() == AutocompleteProvider::TYPE_KEYWORD &&
+         !i->keyword.empty()) ||
+        (i->provider->type() == AutocompleteProvider::TYPE_SEARCH &&
+         AutocompleteMatch::IsSearchType(i->type))) {
+      i->description.clear();
+      i->description_class.clear();
+      DCHECK(!i->keyword.empty());
+      if (i->keyword != last_keyword) {
+        const TemplateURL* template_url = i->GetTemplateURL(profile_, false);
+        if (template_url) {
+          // For extension keywords, just make the description the extension
+          // name -- don't assume that the normal search keyword description is
+          // applicable.
+          i->description = template_url->AdjustedShortNameForLocaleDirection();
+          if (!template_url->IsExtensionKeyword()) {
+            i->description = l10n_util::GetStringFUTF16(
+                IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION, i->description);
+          }
+          i->description_class.push_back(
+              ACMatchClassification(0, ACMatchClassification::DIM));
+        }
+        last_keyword = i->keyword;
+      }
+    } else {
+      last_keyword.clear();
+    }
+  }
+}
+
 void AutocompleteController::UpdateAssistedQueryStats(
     AutocompleteResult* result) {
   if (result->empty())
@@ -529,65 +591,6 @@
   }
 }
 
-GURL AutocompleteController::GetDestinationURL(
-    const AutocompleteMatch& match,
-    base::TimeDelta query_formulation_time) const {
-  GURL destination_url(match.destination_url);
-  TemplateURL* template_url = match.GetTemplateURL(profile_, false);
-
-  // Append the query formulation time (time from when the user first typed a
-  // character into the omnibox to when the user selected a query) and whether
-  // a field trial has triggered to the AQS parameter, if other AQS parameters
-  // were already populated.
-  if (template_url && match.search_terms_args.get() &&
-      !match.search_terms_args->assisted_query_stats.empty()) {
-    TemplateURLRef::SearchTermsArgs search_terms_args(*match.search_terms_args);
-    search_terms_args.assisted_query_stats += base::StringPrintf(
-        ".%" PRId64 "j%dj%d",
-        query_formulation_time.InMilliseconds(),
-        search_provider_ &&
-        search_provider_->field_trial_triggered_in_session(),
-        input_.current_page_classification());
-    destination_url = GURL(template_url->url_ref().
-                           ReplaceSearchTerms(search_terms_args));
-  }
-  return destination_url;
-}
-
-void AutocompleteController::UpdateKeywordDescriptions(
-    AutocompleteResult* result) {
-  string16 last_keyword;
-  for (AutocompleteResult::iterator i(result->begin()); i != result->end();
-       ++i) {
-    if ((i->provider->type() == AutocompleteProvider::TYPE_KEYWORD &&
-         !i->keyword.empty()) ||
-        (i->provider->type() == AutocompleteProvider::TYPE_SEARCH &&
-         AutocompleteMatch::IsSearchType(i->type))) {
-      i->description.clear();
-      i->description_class.clear();
-      DCHECK(!i->keyword.empty());
-      if (i->keyword != last_keyword) {
-        const TemplateURL* template_url = i->GetTemplateURL(profile_, false);
-        if (template_url) {
-          // For extension keywords, just make the description the extension
-          // name -- don't assume that the normal search keyword description is
-          // applicable.
-          i->description = template_url->AdjustedShortNameForLocaleDirection();
-          if (!template_url->IsExtensionKeyword()) {
-            i->description = l10n_util::GetStringFUTF16(
-                IDS_AUTOCOMPLETE_SEARCH_DESCRIPTION, i->description);
-          }
-          i->description_class.push_back(
-              ACMatchClassification(0, ACMatchClassification::DIM));
-        }
-        last_keyword = i->keyword;
-      }
-    } else {
-      last_keyword.clear();
-    }
-  }
-}
-
 void AutocompleteController::NotifyChanged(bool notify_default_match) {
   if (delegate_)
     delegate_->OnResultChanged(notify_default_match);
diff --git a/chrome/browser/autocomplete/autocomplete_input.cc b/chrome/browser/autocomplete/autocomplete_input.cc
index 0edb4d9..e192a89 100644
--- a/chrome/browser/autocomplete/autocomplete_input.cc
+++ b/chrome/browser/autocomplete/autocomplete_input.cc
@@ -183,7 +183,7 @@
     // reaching the net::URLRequest logic.  We thus won't catch these above, but
     // we should still claim to handle them.
     if (LowerCaseEqualsASCII(parsed_scheme, content::kViewSourceScheme) ||
-        LowerCaseEqualsASCII(parsed_scheme, chrome::kJavaScriptScheme) ||
+        LowerCaseEqualsASCII(parsed_scheme, content::kJavaScriptScheme) ||
         LowerCaseEqualsASCII(parsed_scheme, chrome::kDataScheme))
       return URL;
 
diff --git a/chrome/browser/autocomplete/bookmark_provider.cc b/chrome/browser/autocomplete/bookmark_provider.cc
index 3e8443f..0ed0f22 100644
--- a/chrome/browser/autocomplete/bookmark_provider.cc
+++ b/chrome/browser/autocomplete/bookmark_provider.cc
@@ -111,8 +111,9 @@
   // Sort and clip the resulting matches.
   size_t max_matches = best_match ? 1 : AutocompleteProvider::kMaxMatches;
   if (matches_.size() > max_matches) {
-    std::partial_sort(matches_.begin(), matches_.end(),
+    std::partial_sort(matches_.begin(),
                       matches_.begin() + max_matches,
+                      matches_.end(),
                       AutocompleteMatch::MoreRelevant);
     matches_.resize(max_matches);
   } else {
diff --git a/chrome/browser/autocomplete/builtin_provider.cc b/chrome/browser/autocomplete/builtin_provider.cc
index d61743d..ed76f77 100644
--- a/chrome/browser/autocomplete/builtin_provider.cc
+++ b/chrome/browser/autocomplete/builtin_provider.cc
@@ -82,9 +82,9 @@
     if (highlight)
       styles.push_back(ACMatchClassification(offset, kUrl));
     // Include some common builtin chrome URLs as the user types the scheme.
-    AddMatch(ASCIIToUTF16(chrome::kChromeUIChromeURLsURL), styles);
-    AddMatch(ASCIIToUTF16(chrome::kChromeUISettingsURL), styles);
-    AddMatch(ASCIIToUTF16(chrome::kChromeUIVersionURL), styles);
+    AddMatch(ASCIIToUTF16(chrome::kChromeUIChromeURLsURL), string16(), styles);
+    AddMatch(ASCIIToUTF16(chrome::kChromeUISettingsURL), string16(), styles);
+    AddMatch(ASCIIToUTF16(chrome::kChromeUIVersionURL), string16(), styles);
   } else {
     // Match input about: or chrome: URL input against builtin chrome URLs.
     GURL url = URLFixerUpper::FixupURL(UTF16ToUTF8(text), std::string());
@@ -102,7 +102,7 @@
           string16 match_string = kChrome + *i;
           if (match_string.length() > match_length)
             styles.push_back(ACMatchClassification(match_length, kUrl));
-          AddMatch(match_string, styles);
+          AddMatch(match_string, match_string.substr(match_length), styles);
         }
       }
     }
@@ -110,15 +110,24 @@
 
   for (size_t i = 0; i < matches_.size(); ++i)
     matches_[i].relevance = kRelevance + matches_.size() - (i + 1);
+  if (!input.prevent_inline_autocomplete() && (matches_.size() == 1)) {
+    // If there's only one possible completion of the user's input and
+    // allowing completions is okay, give the match a high enough score to
+    // allow it to beat url-what-you-typed and be inlined.
+    matches_[0].relevance = 1250;
+    matches_[0].allowed_to_be_default_match = true;
+  }
 }
 
 BuiltinProvider::~BuiltinProvider() {}
 
 void BuiltinProvider::AddMatch(const string16& match_string,
+                               const string16& inline_completion,
                                const ACMatchClassifications& styles) {
   AutocompleteMatch match(this, kRelevance, false,
                           AutocompleteMatchType::NAVSUGGEST);
   match.fill_into_edit = match_string;
+  match.inline_autocompletion = inline_completion;
   match.destination_url = GURL(match_string);
   match.contents = match_string;
   match.contents_class = styles;
diff --git a/chrome/browser/autocomplete/builtin_provider.h b/chrome/browser/autocomplete/builtin_provider.h
index 10a522a..260a3aa 100644
--- a/chrome/browser/autocomplete/builtin_provider.h
+++ b/chrome/browser/autocomplete/builtin_provider.h
@@ -31,6 +31,7 @@
   static const int kRelevance;
 
   void AddMatch(const string16& match_string,
+                const string16& inline_completion,
                 const ACMatchClassifications& styles);
 
   Builtins builtins_;
diff --git a/chrome/browser/autocomplete/keyword_provider_unittest.cc b/chrome/browser/autocomplete/keyword_provider_unittest.cc
index 5c7cf84..2e00025 100644
--- a/chrome/browser/autocomplete/keyword_provider_unittest.cc
+++ b/chrome/browser/autocomplete/keyword_provider_unittest.cc
@@ -49,13 +49,13 @@
 
 // static
 const TemplateURLService::Initializer KeywordProviderTest::kTestData[] = {
-  { "aa", "aa.com?foo=%s", "aa" },
-  { "aaaa", "http://aaaa/?aaaa=1&b=%s&c", "aaaa" },
-  { "aaaaa", "%s", "aaaaa" },
-  { "ab", "bogus URL %s", "ab" },
-  { "weasel", "weasel%sweasel", "weasel" },
-  { "www", " +%2B?=%sfoo ", "www" },
-  { "z", "%s=z", "z" },
+  { "aa", "aa.com?foo={searchTerms}", "aa" },
+  { "aaaa", "http://aaaa/?aaaa=1&b={searchTerms}&c", "aaaa" },
+  { "aaaaa", "{searchTerms}", "aaaaa" },
+  { "ab", "bogus URL {searchTerms}", "ab" },
+  { "weasel", "weasel{searchTerms}weasel", "weasel" },
+  { "www", " +%2B?={searchTerms}foo ", "www" },
+  { "z", "{searchTerms}=z", "z" },
 };
 
 void KeywordProviderTest::SetUp() {
diff --git a/chrome/browser/autocomplete/search_provider.cc b/chrome/browser/autocomplete/search_provider.cc
index c561490..05b49e6 100644
--- a/chrome/browser/autocomplete/search_provider.cc
+++ b/chrome/browser/autocomplete/search_provider.cc
@@ -572,7 +572,7 @@
   // non-keyword mode.
   const TemplateURL* default_url = providers_.GetDefaultProviderURL();
   if (!is_keyword && default_url &&
-      (TemplateURLPrepopulateData::GetEngineType(default_url->url()) ==
+      (TemplateURLPrepopulateData::GetEngineType(*default_url) ==
        SEARCH_ENGINE_GOOGLE)) {
     const base::TimeDelta elapsed_time =
         base::TimeTicks::Now() - time_suggest_request_sent_;
diff --git a/chrome/browser/autocomplete/shortcuts_provider.cc b/chrome/browser/autocomplete/shortcuts_provider.cc
index b3d9d2c..6dcb6ed 100644
--- a/chrome/browser/autocomplete/shortcuts_provider.cc
+++ b/chrome/browser/autocomplete/shortcuts_provider.cc
@@ -129,7 +129,10 @@
 }
 
 void ShortcutsProvider::DeleteMatchesWithURLs(const std::set<GURL>& urls) {
-  std::remove_if(matches_.begin(), matches_.end(), RemoveMatchPredicate(urls));
+  matches_.erase(
+      std::remove_if(
+          matches_.begin(), matches_.end(), RemoveMatchPredicate(urls)),
+      matches_.end());
   listener_->OnProviderUpdate(true);
 }
 
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.h b/chrome/browser/autocomplete/zero_suggest_provider.h
index f6fafa5..3f12e70 100644
--- a/chrome/browser/autocomplete/zero_suggest_provider.h
+++ b/chrome/browser/autocomplete/zero_suggest_provider.h
@@ -78,6 +78,10 @@
       AutocompleteInput::PageClassification page_classification,
       const string16& permanent_text);
 
+  bool field_trial_triggered_in_session() const {
+    return field_trial_triggered_in_session_;
+  }
+
  private:
   ZeroSuggestProvider(AutocompleteProviderListener* listener,
                       Profile* profile);
diff --git a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
index fd6cdd4..91842cd 100644
--- a/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
+++ b/chrome/browser/autofill/autofill_cc_infobar_delegate.cc
@@ -13,10 +13,10 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "grit/generated_resources.h"
+#include "grit/google_chrome_strings.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
-
 namespace autofill {
 
 // static
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index 50e84ae..798202e 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -363,7 +363,8 @@
         "      };"
         "    }"
         "  };"
-        "})();";
+        "})();"
+        "cr.googleTranslate.onTranslateElementLoad();";
 
     fetcher->set_url(fetcher->GetOriginalURL());
     fetcher->set_status(status);
@@ -818,9 +819,7 @@
   TryBasicFormFill();
 }
 
-// DISABLED: http://crbug.com/150084
-IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest,
-                       DISABLED_AutofillAfterTranslate) {
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, AutofillAfterTranslate) {
   CreateTestProfile();
 
   GURL url(std::string(kDataURIPrefix) +
@@ -853,15 +852,20 @@
                " </select><br>"
                "<label for=\"ph\">Phone number:</label>"
                " <input type=\"text\" id=\"ph\"><br>"
-               "</form>");
-  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url));
+               "</form>"
+               // Add additional Japanese characters to ensure the translate bar
+               // will appear.
+               "我々は重要な、興味深いものになるが、時折状況が発生するため苦労や痛みは"
+               "彼にいくつかの素晴らしいを調達することができます。それから、いくつかの利");
 
-  // Get translation bar.
-  LanguageDetectionDetails details;
-  details.adopted_language = "ja";
-  content::RenderViewHostTester::TestOnMessageReceived(
-      GetRenderViewHost(),
-      ChromeViewHostMsg_TranslateLanguageDetermined(0, details, true));
+  content::WindowedNotificationObserver infobar(
+      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
+      content::NotificationService::AllSources());
+  ASSERT_NO_FATAL_FAILURE(
+      ui_test_utils::NavigateToURL(browser(), url));
+
+  // Wait for the translation bar to appear and get it.
+  infobar.Wait();
   TranslateInfoBarDelegate* delegate = InfoBarService::FromWebContents(
       browser()->tab_strip_model()->GetActiveWebContents())->infobar_at(0)->
           AsTranslateInfoBarDelegate();
@@ -880,12 +884,6 @@
       chrome::NOTIFICATION_PAGE_TRANSLATED,
       content::NotificationService::AllSources());
 
-  // Simulate translation to kick onTranslateElementLoad.
-  // But right now, the call stucks here.
-  // Once click the text field, it starts again.
-  ASSERT_TRUE(content::ExecuteScript(
-      GetRenderViewHost(), "cr.googleTranslate.onTranslateElementLoad();"));
-
   // Simulate the render notifying the translation has been done.
   translation_observer.Wait();
 
diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc
index 7fe896e..b2c00ab 100644
--- a/chrome/browser/automation/automation_provider_observers.cc
+++ b/chrome/browser/automation/automation_provider_observers.cc
@@ -70,7 +70,6 @@
 #include "chrome/common/automation_messages.h"
 #include "chrome/common/content_settings_types.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/browser/dom_operation_notification_details.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/notification_service.h"
@@ -78,6 +77,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/process_type.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/view_type.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/rect.h"
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index f2c995d..064df01 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -5458,16 +5458,16 @@
     return;
   }
   Browser* browser = automation_util::GetBrowserForTab(tab);
+  if (!browser) {
+    reply.SendError("Tab does not belong to an open browser");
+    return;
+  }
   const Extension* extension;
   if (!GetEnabledExtensionFromJSONArgs(
           args, "extension_id", browser->profile(), &extension, &error)) {
     reply.SendError(error);
     return;
   }
-  if (!browser) {
-    reply.SendError("Tab does not belong to an open browser");
-    return;
-  }
   ExtensionAction* page_action =
       ExtensionActionManager::Get(browser->profile())->
       GetPageAction(*extension);
diff --git a/chrome/browser/automation/testing_automation_provider_chromeos.cc b/chrome/browser/automation/testing_automation_provider_chromeos.cc
index 598da8d..f1b91d5 100644
--- a/chrome/browser/automation/testing_automation_provider_chromeos.cc
+++ b/chrome/browser/automation/testing_automation_provider_chromeos.cc
@@ -338,12 +338,12 @@
   WizardControllerObserver* observer =
       new WizardControllerObserver(wizard_controller, this, reply_message);
   if (image_type == "profile") {
-    image_screen->OnImageSelected("", image_type);
+    image_screen->OnImageSelected("", image_type, true);
     image_screen->OnImageAccepted();
   } else if (image_type.empty() && image_number >= 0 &&
              image_number < chromeos::kDefaultImagesCount) {
     image_screen->OnImageSelected(
-        chromeos::GetDefaultImageUrl(image_number), image_type);
+        chromeos::GetDefaultImageUrl(image_number), image_type, true);
     image_screen->OnImageAccepted();
   } else {
     AutomationJSONReply(this, reply_message).SendError(
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index 0858e73..2e410c0 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/extension_manifest_constants.h"
 #include "chrome/common/extensions/permissions/api_permission.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 "testing/gtest/include/gtest/gtest.h"
 
 // This value is used to seed the PRNG at the beginning of a sequence of
@@ -62,11 +62,11 @@
 static scoped_refptr<Extension> CreateExtension(const std::string& name,
                                                 bool background_permission) {
   DictionaryValue manifest;
-  manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
-  manifest.SetString(extension_manifest_keys::kName, name);
+  manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
+  manifest.SetString(extensions::manifest_keys::kName, name);
   if (background_permission) {
     ListValue* permissions = new ListValue();
-    manifest.Set(extension_manifest_keys::kPermissions, permissions);
+    manifest.Set(extensions::manifest_keys::kPermissions, permissions);
     permissions->Append(Value::CreateStringValue("background"));
   }
   std::string error;
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index e9889f7..1e81d64 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -56,7 +56,7 @@
 
 const char kNotificationPrefix[] = "app.background.crashed.";
 
-void CloseBalloon(const std::string id) {
+void CloseBalloon(const std::string& id) {
   g_browser_process->notification_ui_manager()->CancelById(id);
 }
 
@@ -188,7 +188,7 @@
 #endif
 }
 
-}
+}  // namespace
 
 // Keys for the information we store about individual BackgroundContents in
 // prefs. There is one top-level DictionaryValue (stored at
@@ -554,7 +554,9 @@
       MSG_ROUTING_NONE,
       profile,
       frame_name,
-      application_id);
+      application_id,
+      std::string(),
+      NULL);
 
   // TODO(atwilson): Create RenderViews asynchronously to avoid increasing
   // startup latency (http://crbug.com/47236).
@@ -567,8 +569,11 @@
     int routing_id,
     Profile* profile,
     const string16& frame_name,
-    const string16& application_id) {
-  BackgroundContents* contents = new BackgroundContents(site, routing_id, this);
+    const string16& application_id,
+    const std::string& partition_id,
+    content::SessionStorageNamespace* session_storage_namespace) {
+  BackgroundContents* contents = new BackgroundContents(
+      site, routing_id, this, partition_id, session_storage_namespace);
 
   // Register the BackgroundContents internally, then send out a notification
   // to external listeners.
diff --git a/chrome/browser/background/background_contents_service.h b/chrome/browser/background/background_contents_service.h
index 50057cf..0d99a92 100644
--- a/chrome/browser/background/background_contents_service.h
+++ b/chrome/browser/background/background_contents_service.h
@@ -27,6 +27,10 @@
 class DictionaryValue;
 }
 
+namespace content {
+class SessionStorageNamespace;
+}
+
 namespace gfx {
 class Rect;
 }
@@ -79,11 +83,14 @@
   // A BACKGROUND_CONTENTS_OPENED notification will be generated with the passed
   // |frame_name| and |application_id| values, using the passed |profile| as the
   // Source..
-  BackgroundContents* CreateBackgroundContents(content::SiteInstance* site,
-                                               int route_id,
-                                               Profile* profile,
-                                               const string16& frame_name,
-                                               const string16& application_id);
+  BackgroundContents* CreateBackgroundContents(
+      content::SiteInstance* site,
+      int route_id,
+      Profile* profile,
+      const string16& frame_name,
+      const string16& application_id,
+      const std::string& partition_id,
+      content::SessionStorageNamespace* session_storage_namespace);
 
   // Load the manifest-specified background page for the specified hosted app.
   // If the manifest doesn't specify one, then load the BackgroundContents
diff --git a/chrome/browser/bookmarks/bookmark_model.cc b/chrome/browser/bookmarks/bookmark_model.cc
index 304218e..f118e55 100644
--- a/chrome/browser/bookmarks/bookmark_model.cc
+++ b/chrome/browser/bookmarks/bookmark_model.cc
@@ -404,7 +404,7 @@
   std::vector<BookmarkNodeData::Element> elements(drag_data.elements);
   // CloneBookmarkNode will use BookmarkModel methods to do the job, so we
   // don't need to send notifications here.
-  bookmark_utils::CloneBookmarkNode(this, elements, new_parent, index);
+  bookmark_utils::CloneBookmarkNode(this, elements, new_parent, index, true);
 
   if (store_.get())
     store_->ScheduleSave();
diff --git a/chrome/browser/bookmarks/bookmark_node_data.cc b/chrome/browser/bookmarks/bookmark_node_data.cc
index 6981db0..4ec9c74 100644
--- a/chrome/browser/bookmarks/bookmark_node_data.cc
+++ b/chrome/browser/bookmarks/bookmark_node_data.cc
@@ -26,6 +26,8 @@
     : is_url(node->is_url()),
       url(node->url()),
       title(node->GetTitle()),
+      date_added(node->date_added()),
+      date_folder_modified(node->date_folder_modified()),
       id_(node->id()) {
   for (int i = 0; i < node->child_count(); ++i)
     children.push_back(Element(node->GetChild(i)));
@@ -58,6 +60,8 @@
     return false;
   }
   url = GURL(url_spec);
+  date_added = base::Time();
+  date_folder_modified = base::Time();
   children.clear();
   if (!is_url) {
     uint64 children_count;
diff --git a/chrome/browser/bookmarks/bookmark_node_data.h b/chrome/browser/bookmarks/bookmark_node_data.h
index 1401e70..c1cb7b8 100644
--- a/chrome/browser/bookmarks/bookmark_node_data.h
+++ b/chrome/browser/bookmarks/bookmark_node_data.h
@@ -9,6 +9,7 @@
 
 #include "base/files/file_path.h"
 #include "base/strings/string16.h"
+#include "base/time/time.h"
 #include "url/gurl.h"
 
 #if defined(TOOLKIT_VIEWS)
@@ -54,6 +55,12 @@
     // Title of the entry, used for both urls and folders.
     string16 title;
 
+    // Date of when this node was created.
+    base::Time date_added;
+
+    // Date of the last modification. Only used for folders.
+    base::Time date_folder_modified;
+
     // Children, only used for non-URL nodes.
     std::vector<Element> children;
 
diff --git a/chrome/browser/bookmarks/bookmark_node_data_unittest.cc b/chrome/browser/bookmarks/bookmark_node_data_unittest.cc
index 23d99f2..c600fd5 100644
--- a/chrome/browser/bookmarks/bookmark_node_data_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_node_data_unittest.cc
@@ -64,6 +64,8 @@
   EXPECT_TRUE(drag_data.elements[0].is_url);
   EXPECT_EQ(url, drag_data.elements[0].url);
   EXPECT_EQ(title, drag_data.elements[0].title);
+  EXPECT_TRUE(drag_data.elements[0].date_added.is_null());
+  EXPECT_TRUE(drag_data.elements[0].date_folder_modified.is_null());
   EXPECT_EQ(0, drag_data.elements[0].children.size());
 }
 
@@ -84,6 +86,9 @@
   EXPECT_TRUE(drag_data.elements[0].is_url);
   EXPECT_EQ(url, drag_data.elements[0].url);
   EXPECT_EQ(title, drag_data.elements[0].title);
+  EXPECT_EQ(node->date_added(), drag_data.elements[0].date_added);
+  EXPECT_EQ(node->date_folder_modified(),
+            drag_data.elements[0].date_folder_modified);
   ui::OSExchangeData data;
   drag_data.Write(&profile, &data);
 
@@ -96,6 +101,8 @@
   EXPECT_TRUE(read_data.elements[0].is_url);
   EXPECT_EQ(url, read_data.elements[0].url);
   EXPECT_EQ(title, read_data.elements[0].title);
+  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
+  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
   EXPECT_TRUE(read_data.GetFirstNode(&profile) == node);
 
   // Make sure asking for the node with a different profile returns NULL.
@@ -129,6 +136,9 @@
   ASSERT_EQ(1, drag_data.elements.size());
   EXPECT_EQ(g12->GetTitle(), drag_data.elements[0].title);
   EXPECT_FALSE(drag_data.elements[0].is_url);
+  EXPECT_EQ(g12->date_added(), drag_data.elements[0].date_added);
+  EXPECT_EQ(g12->date_folder_modified(),
+            drag_data.elements[0].date_folder_modified);
 
   ui::OSExchangeData data;
   drag_data.Write(&profile, &data);
@@ -141,6 +151,8 @@
   ASSERT_EQ(1, read_data.elements.size());
   EXPECT_EQ(g12->GetTitle(), read_data.elements[0].title);
   EXPECT_FALSE(read_data.elements[0].is_url);
+  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
+  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
 
   // We should get back the same node when asking for the same profile.
   const BookmarkNode* r_g12 = read_data.GetFirstNode(&profile);
@@ -185,6 +197,8 @@
   EXPECT_TRUE(read_child.is_url);
   EXPECT_EQ(title, read_child.title);
   EXPECT_EQ(url, read_child.url);
+  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
+  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
   EXPECT_TRUE(read_child.is_url);
 
   // And make sure we get the node back.
@@ -224,6 +238,8 @@
   EXPECT_TRUE(read_data.is_valid());
   ASSERT_EQ(2, read_data.elements.size());
   ASSERT_EQ(1, read_data.elements[0].children.size());
+  EXPECT_TRUE(read_data.elements[0].date_added.is_null());
+  EXPECT_TRUE(read_data.elements[0].date_folder_modified.is_null());
 
   const BookmarkNodeData::Element& read_folder = read_data.elements[0];
   EXPECT_FALSE(read_folder.is_url);
diff --git a/chrome/browser/bookmarks/bookmark_node_data_views.cc b/chrome/browser/bookmarks/bookmark_node_data_views.cc
index 845b735..70d15e9 100644
--- a/chrome/browser/bookmarks/bookmark_node_data_views.cc
+++ b/chrome/browser/bookmarks/bookmark_node_data_views.cc
@@ -27,7 +27,7 @@
   // If there is only one element and it is a URL, write the URL to the
   // clipboard.
   if (elements.size() == 1 && elements[0].is_url) {
-    if (elements[0].url.SchemeIs(chrome::kJavaScriptScheme)) {
+    if (elements[0].url.SchemeIs(content::kJavaScriptScheme)) {
       data->SetString(UTF8ToUTF16(elements[0].url.spec()));
     } else {
       data->SetURL(elements[0].url, elements[0].title);
diff --git a/chrome/browser/bookmarks/bookmark_utils.cc b/chrome/browser/bookmarks/bookmark_utils.cc
index b05a872..a8a1515 100644
--- a/chrome/browser/bookmarks/bookmark_utils.cc
+++ b/chrome/browser/bookmarks/bookmark_utils.cc
@@ -33,15 +33,27 @@
 void CloneBookmarkNodeImpl(BookmarkModel* model,
                            const BookmarkNodeData::Element& element,
                            const BookmarkNode* parent,
-                           int index_to_add_at) {
+                           int index_to_add_at,
+                           bool reset_node_times) {
   if (element.is_url) {
-    model->AddURL(parent, index_to_add_at, element.title, element.url);
+    if (reset_node_times) {
+      model->AddURL(parent, index_to_add_at, element.title, element.url);
+    } else {
+      DCHECK(!element.date_added.is_null());
+      model->AddURLWithCreationTime(parent, index_to_add_at, element.title,
+                                    element.url, element.date_added);
+    }
   } else {
     const BookmarkNode* new_folder = model->AddFolder(parent,
                                                       index_to_add_at,
                                                       element.title);
+    if (!reset_node_times) {
+      DCHECK(!element.date_folder_modified.is_null());
+      model->SetDateFolderModified(new_folder, element.date_folder_modified);
+    }
     for (int i = 0; i < static_cast<int>(element.children.size()); ++i)
-      CloneBookmarkNodeImpl(model, element.children[i], new_folder, i);
+      CloneBookmarkNodeImpl(model, element.children[i], new_folder, i,
+                            reset_node_times);
   }
 }
 
@@ -83,13 +95,16 @@
 void CloneBookmarkNode(BookmarkModel* model,
                        const std::vector<BookmarkNodeData::Element>& elements,
                        const BookmarkNode* parent,
-                       int index_to_add_at) {
+                       int index_to_add_at,
+                       bool reset_node_times) {
   if (!parent->is_folder() || !model) {
     NOTREACHED();
     return;
   }
-  for (size_t i = 0; i < elements.size(); ++i)
-    CloneBookmarkNodeImpl(model, elements[i], parent, index_to_add_at + i);
+  for (size_t i = 0; i < elements.size(); ++i) {
+    CloneBookmarkNodeImpl(model, elements[i], parent, index_to_add_at + i,
+                          reset_node_times);
+  }
 }
 
 
@@ -122,7 +137,7 @@
 
   if (index == -1)
     index = parent->child_count();
-  CloneBookmarkNode(model, bookmark_data.elements, parent, index);
+  CloneBookmarkNode(model, bookmark_data.elements, parent, index, true);
 }
 
 bool CanPasteFromClipboard(const BookmarkNode* node) {
@@ -226,18 +241,6 @@
   }
 }
 
-bool DoesBookmarkContainText(const BookmarkNode* node,
-                             const string16& text,
-                             const std::string& languages) {
-  std::vector<string16> words;
-  QueryParser parser;
-  parser.ParseQueryWords(base::i18n::ToLower(text), &words);
-  if (words.empty())
-    return false;
-
-  return (node->is_url() && DoesBookmarkContainWords(node, words, languages));
-}
-
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterBooleanPref(
       prefs::kShowBookmarkBar,
diff --git a/chrome/browser/bookmarks/bookmark_utils.h b/chrome/browser/bookmarks/bookmark_utils.h
index 0bbdcc5..7c60471 100644
--- a/chrome/browser/bookmarks/bookmark_utils.h
+++ b/chrome/browser/bookmarks/bookmark_utils.h
@@ -23,11 +23,14 @@
 namespace bookmark_utils {
 
 // Clones bookmark node, adding newly created nodes to |parent| starting at
-// |index_to_add_at|.
+// |index_to_add_at|. If |reset_node_times| is true cloned bookmarks and
+// folders will receive new creation times and folder modification times
+// instead of using the values stored in |elements|.
 void CloneBookmarkNode(BookmarkModel* model,
                        const std::vector<BookmarkNodeData::Element>& elements,
                        const BookmarkNode* parent,
-                       int index_to_add_at);
+                       int index_to_add_at,
+                       bool reset_node_times);
 
 // Copies nodes onto the clipboard. If |remove_nodes| is true the nodes are
 // removed after copied to the clipboard. The nodes are copied in such a way
@@ -69,12 +72,6 @@
                                 const std::string& languages,
                                 std::vector<const BookmarkNode*>* nodes);
 
-// Returns true if |node|'s url or title contains the string |text|.
-// |languages| is user's accept-language setting to decode IDN.
-bool DoesBookmarkContainText(const BookmarkNode* node,
-                             const string16& text,
-                             const std::string& languages);
-
 // Register user preferences for Bookmarks Bar.
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
diff --git a/chrome/browser/bookmarks/bookmark_utils_unittest.cc b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
index 9a801ac..f135f48 100644
--- a/chrome/browser/bookmarks/bookmark_utils_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_utils_unittest.cc
@@ -45,90 +45,21 @@
       &model, ASCIIToUTF16("foo"), 100, string(), &nodes);
   ASSERT_EQ(1U, nodes.size());
   EXPECT_TRUE(nodes[0] == n1);
-  EXPECT_TRUE(DoesBookmarkContainText(n1, ASCIIToUTF16("foo"), string()));
   nodes.clear();
 
   GetBookmarksContainingText(
       &model, ASCIIToUTF16("cnn"), 100, string(), &nodes);
   ASSERT_EQ(1U, nodes.size());
   EXPECT_TRUE(nodes[0] == n2);
-  EXPECT_TRUE(DoesBookmarkContainText(n2, ASCIIToUTF16("cnn"), string()));
   nodes.clear();
 
   GetBookmarksContainingText(
       &model, ASCIIToUTF16("foo bar"), 100, string(), &nodes);
   ASSERT_EQ(1U, nodes.size());
   EXPECT_TRUE(nodes[0] == n1);
-  EXPECT_TRUE(DoesBookmarkContainText(n1, ASCIIToUTF16("foo bar"), string()));
   nodes.clear();
 }
 
-TEST_F(BookmarkUtilsTest, DoesBookmarkContainText) {
-  BookmarkModel model(NULL);
-  const BookmarkNode* node = model.AddURL(model.other_node(),
-                                          0,
-                                          ASCIIToUTF16("foo bar"),
-                                          GURL("http://www.google.com"));
-  // Matches to the title.
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("ar"), string()));
-  // Matches to the URL.
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("www"), string()));
-  // No match.
-  EXPECT_FALSE(DoesBookmarkContainText(node, ASCIIToUTF16("cnn"), string()));
-
-  // Tests for a Japanese IDN.
-  const string16 kDecodedIdn = WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB");
-  node = model.AddURL(model.other_node(),
-                      0,
-                      ASCIIToUTF16("foo bar"),
-                      GURL("http://xn--qcka1pmc.jp"));
-  // Unicode query doesn't match if languages have no "ja".
-  EXPECT_FALSE(DoesBookmarkContainText(node, kDecodedIdn, "en"));
-  // Unicode query matches if languages have "ja".
-  EXPECT_TRUE(DoesBookmarkContainText(node, kDecodedIdn, "ja"));
-  // Punycode query also matches as ever.
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("qcka1pmc"), "ja"));
-
-  // Tests with various lower/upper case characters.
-  node = model.AddURL(model.other_node(),
-                      0,
-                      ASCIIToUTF16("FOO bar"),
-                      GURL("http://www.google.com/search?q=ABC"));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("foo"), string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("Foo"), string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("FOO"), string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("google abc"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("google ABC"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(
-      node, ASCIIToUTF16("http://www.google.com/search?q=A"), string()));
-
-  // Test with accents.
-  node = model.AddURL(model.other_node(),
-                      0,
-                      WideToUTF16(L"fr\u00E4n\u00E7\u00F3s\u00EA"),
-                      GURL("http://www.google.com/search?q=FBA"));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("francose"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("FrAnCoSe"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, WideToUTF16(L"fr\u00E4ncose"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, WideToUTF16(L"fran\u00E7ose"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, WideToUTF16(L"franc\u00F3se"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, WideToUTF16(L"francos\u00EA"),
-                                      string()));
-  EXPECT_TRUE(DoesBookmarkContainText(
-      node, WideToUTF16(L"Fr\u00C4n\u00C7\u00F3S\u00EA"), string()));
-  EXPECT_TRUE(DoesBookmarkContainText(
-      node, WideToUTF16(L"fr\u00C4n\u00C7\u00D3s\u00CA"), string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("fba"), string()));
-  EXPECT_TRUE(DoesBookmarkContainText(node, ASCIIToUTF16("FBA"), string()));
-}
-
 TEST_F(BookmarkUtilsTest, CopyPaste) {
   BookmarkModel model(NULL);
   const BookmarkNode* node = model.AddURL(model.other_node(),
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 6d6a0b9..49ba340 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -9,10 +9,10 @@
   </outputs>
   <release seq="1">
     <structures>
-      <if expr="is_posix and not is_macosx">
+      <if expr="is_posix and not is_macosx and not is_ios">
         <structure name="IDR_ABOUT_MEMORY_HTML" file="resources\about_memory_linux.html" flattenhtml="true" type="chrome_html" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure name="IDR_ABOUT_MEMORY_HTML" file="resources\about_memory_mac.html" flattenhtml="true" type="chrome_html" />
       </if>
       <if expr="is_win">
@@ -27,8 +27,6 @@
       <if expr="pp_ifdef('chromeos')">
         <structure name="IDR_DEMO_USER_LOGIN_HTML" file="resources\chromeos\login\demo_user_login.html" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_DEMO_USER_LOGIN_JS" file="resources\chromeos\login\demo_user_login.js" flattenhtml="true" type="chrome_html" />
-        <structure name="IDR_APP_LAUNCH_SPLASH_HTML" file="resources\chromeos\app_launch\app_launch.html" flattenhtml="true" type="chrome_html" />
-        <structure name="IDR_APP_LAUNCH_SPLASH_JS" file="resources\chromeos\app_launch\app_launch.js" flattenhtml="true" type="chrome_html" />
       </if>
       <structure name="IDR_DOWNLOADS_CSS" file="resources\downloads\downloads.css" flattenhtml="true" type="chrome_html" />
       <structure name="IDR_DOWNLOADS_HTML" file="resources\downloads\downloads.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" />
@@ -37,12 +35,14 @@
       <structure name="IDR_HELP_HTML" file="resources\help\help.html" flattenhtml="true" type="chrome_html" />
       <structure name="IDR_HELP_CHANNEL_CHANGE_PAGE_CSS" file="resources\help\channel_change_page.css" flattenhtml="true" type="chrome_html" />
       <structure name="IDR_HELP_CHANNEL_CHANGE_PAGE_HTML" file="resources\help\channel_change_page.html" flattenhtml="true" type="chrome_html" />
-      <structure name="IDR_INCOGNITO_TAB_HTML" file="resources\incognito_tab.html" flattenhtml="true" type="chrome_html" />
+      <structure name="IDR_INCOGNITO_TAB_HTML" file="resources\ntp4\incognito_tab.html" flattenhtml="true" type="chrome_html" />
+      <structure name="IDR_GUEST_TAB_HTML" file="resources\ntp4\guest_tab.html" flattenhtml="true" type="chrome_html" />
       <if expr="pp_ifdef('chromeos')">
         <structure name="IDR_LOGIN_HTML" file="resources\chromeos\login\login.html" flattenhtml="true" type="chrome_html" variables="OOBE=login" expand_variables="true"/>
         <structure name="IDR_LOGIN_JS" file="resources\chromeos\login\login.js" flattenhtml="true" type="chrome_html" />
       </if>
-      <structure name="IDR_NEW_INCOGNITO_TAB_THEME_CSS" file="resources\new_incognito_tab_theme.css" flattenhtml="true" type="chrome_html" />
+      <structure name="IDR_NEW_INCOGNITO_TAB_THEME_CSS" file="resources\ntp4\new_incognito_tab_theme.css" flattenhtml="true" type="chrome_html" />
+      <structure name="IDR_NEW_GUEST_TAB_THEME_CSS" file="resources\ntp4\new_guest_tab_theme.css" flattenhtml="true" type="chrome_html" />
       <if expr="not is_android">
         <structure name="IDR_NEW_TAB_4_HTML" file="resources\ntp4\new_tab.html" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_NEW_TAB_4_THEME_CSS" file="resources\ntp4\new_tab_theme.css" flattenhtml="true" type="chrome_html" />
@@ -53,10 +53,10 @@
       <if expr="pp_ifdef('chromeos')">
         <structure name="IDR_OOBE_HTML" file="resources\chromeos\login\oobe.html" flattenhtml="true" type="chrome_html" variables="OOBE=oobe" expand_variables="true"/>
         <structure name="IDR_OOBE_JS" file="resources\chromeos\login\oobe.js" flattenhtml="true" type="chrome_html" />
-	<structure name="IDR_OOBE_RESOURCE_LOADER_JS" file="resources\chromeos\login\resource_loader.js" flattenhtml="true" type="chrome_html" />
-	<structure name="IDR_OOBE_ENROLLMENT_HTML" file="resources\chromeos\login\oobe_screen_oauth_enrollment.html" flattenhtml="true" type="chrome_html" />
-	<structure name="IDR_OOBE_ENROLLMENT_CSS" file="resources\chromeos\login\oobe_screen_oauth_enrollment.css" flattenhtml="true" type="chrome_html" />
-	<structure name="IDR_OOBE_ENROLLMENT_JS" file="resources\chromeos\login\oobe_screen_oauth_enrollment.js" flattenhtml="true" type="chrome_html" />
+        <structure name="IDR_OOBE_RESOURCE_LOADER_JS" file="resources\chromeos\login\resource_loader.js" flattenhtml="true" type="chrome_html" />
+        <structure name="IDR_OOBE_ENROLLMENT_HTML" file="resources\chromeos\login\oobe_screen_oauth_enrollment.html" flattenhtml="true" type="chrome_html" />
+        <structure name="IDR_OOBE_ENROLLMENT_CSS" file="resources\chromeos\login\oobe_screen_oauth_enrollment.css" flattenhtml="true" type="chrome_html" />
+        <structure name="IDR_OOBE_ENROLLMENT_JS" file="resources\chromeos\login\oobe_screen_oauth_enrollment.js" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_KEYBOARD_UTILS_JS" file="resources\chromeos\keyboard\keyboard_utils.js" flattenhtml="true" type="chrome_html" />
       </if>
       <structure name="IDR_READER_OUT_OF_DATE_HTML" file="resources\reader_out_of_date.html" flattenhtml="true" type="chrome_html" />
@@ -85,7 +85,7 @@
       </if>
       <include name="IDR_BOOKMARKS_MANIFEST" file="resources\bookmark_manager\manifest.json" type="BINDATA" />
       <include name="IDR_APPS_DEBUGGER_MANIFEST" file="resources\apps_debugger\manifest.json" type="BINDATA" />
-      <if expr="is_posix and not is_macosx">
+      <if expr="is_posix and not is_macosx and not is_ios">
         <include name="IDR_CERTIFICATE_VIEWER_HTML" file="resources\certificate_viewer.html" type="BINDATA" />
         <include name="IDR_CERTIFICATE_VIEWER_JS" file="resources\certificate_viewer.js" type="BINDATA" />
         <include name="IDR_CERTIFICATE_VIEWER_CSS" file="resources\certificate_viewer.css" type="BINDATA" />
@@ -117,6 +117,7 @@
         <include name="IDR_EXTENSION_INFO_JS" file="resources\extensions\extension_info.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_EXTENSIONS_JS" file="resources\extensions\extensions.js" flattenhtml="true" type="BINDATA" />
       </if>
+      <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_HELP_JS" file="resources\help\help.js" flattenhtml="true" type="BINDATA" />
@@ -177,6 +178,10 @@
         <include name="IDR_PLUGINS_HTML" file="resources\plugins.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
         <include name="IDR_PLUGINS_JS" file="resources\plugins.js" type="BINDATA" />
       </if>
+      <if expr="not is_android or pp_ifdef('google_tv')">
+        <include name="IDR_COMPONENTS_HTML" file="resources\components.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+        <include name="IDR_COMPONENTS_JS" file="resources\components.js" type="BINDATA" />
+      </if>
       <if expr="is_android and pp_ifdef('google_tv')">
         <include name="IDR_PLUGIN_DB_JSON" file="resources\plugin_metadata\plugins_tv.json" type="BINDATA" />
       </if>
@@ -202,8 +207,7 @@
       </if>
       <include name="IDR_POLICY_HTML" file="resources\policy.html" flattenhtml="true" allowexternalscript="true" type="BINDATA"/>
       <include name="IDR_POLICY_JS" file="resources\policy.js" type="BINDATA"/>
-      <include name="IDR_PRERENDER_URL_WHITELIST"
-	       file="resources\prerender_url_whitelist.dat" type="BINDATA"/>
+      <include name="IDR_PRERENDER_URL_WHITELIST" file="resources\prerender_url_whitelist.dat" type="BINDATA"/>
       <if expr="pp_ifdef('enable_printing')">
         <include name="IDR_PRINT_PREVIEW_HTML" file="resources\print_preview\print_preview.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
         <include name="IDR_PRINT_PREVIEW_PAGE" file="resources\print_preview\print_preview_page.html" flattenhtml="true" allowexternalscript="false" type="BINDATA" />
@@ -242,9 +246,6 @@
         <include name="IDR_SUGGESTIONS_PAGE_JS" file="resources\ntp4\suggestions_page.js" type="BINDATA" />
       </if>
       <include name="IDR_TRANSLATE_JS" file="resources\translate.js" type="BINDATA" />
-      <include name="IDR_FEEDBACK_HTML" file="resources\feedback.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
-      <include name="IDR_FEEDBACK_HTML_INVALID" file="resources\feedback_invalid.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_FEEDBACK_JS" file="resources\feedback.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_UBER_HTML" file="resources\uber\uber.html" flattenhtml="true" type="BINDATA" />
       <include name="IDR_UBER_JS" file="resources\uber\uber.js" type="BINDATA" />
       <include name="IDR_UBER_FRAME_HTML" file="resources\uber\uber_frame.html" flattenhtml="true" type="BINDATA" />
@@ -356,7 +357,7 @@
         <include name="IDR_SET_AS_DEFAULT_BROWSER_JS" file="resources\set_as_default_browser.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_SET_AS_DEFAULT_BROWSER_HTML" file="resources\set_as_default_browser.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       </if>
-      <if expr="not is_android and not pp_ifdef('ios') and not pp_ifdef('chromeos')">
+      <if expr="not is_android and not is_ios and not pp_ifdef('chromeos')">
         <include name="IDR_USER_MANAGER_JS" file="resources\user_manager\user_manager.js" flattenhtml="true" type="BINDATA" />
         <include name="IDR_USER_MANAGER_HTML" file="resources\user_manager\user_manager.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       </if>
@@ -370,6 +371,11 @@
         <include name="IDR_IDENTITY_INTERNALS_CSS" file="resources\identity_internals.css" type="BINDATA" />
         <include name="IDR_IDENTITY_INTERNALS_JS" file="resources\identity_internals.js" type="BINDATA" />
       </if>
+      <if expr="pp_ifdef('chromeos')">
+        <include name="IDR_NETWORK_HTML" file="resources\chromeos\network.html" type="BINDATA" />
+        <include name="IDR_NETWORK_JS" file="resources\chromeos\network.js" type="BINDATA" />
+        <include name="IDR_NETWORK_CSS" file="resources\chromeos\network.css" type="BINDATA" />
+      </if>
     </includes>
   </release>
 </grit>
diff --git a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
index 5fe25ce..d0fbd04 100644
--- a/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_helper_unittest.cc
@@ -74,7 +74,7 @@
   EXPECT_FALSE(IsWebScheme(chrome::kChromeDevToolsScheme));
   EXPECT_FALSE(IsWebScheme(chrome::kChromeInternalScheme));
   EXPECT_FALSE(IsWebScheme(chrome::kChromeUIScheme));
-  EXPECT_FALSE(IsWebScheme(chrome::kJavaScriptScheme));
+  EXPECT_FALSE(IsWebScheme(content::kJavaScriptScheme));
   EXPECT_FALSE(IsWebScheme(content::kMailToScheme));
   EXPECT_FALSE(IsWebScheme(content::kMetadataScheme));
   EXPECT_FALSE(IsWebScheme(content::kSwappedOutScheme));
@@ -99,7 +99,7 @@
   EXPECT_FALSE(IsExtensionScheme(chrome::kChromeDevToolsScheme));
   EXPECT_FALSE(IsExtensionScheme(chrome::kChromeInternalScheme));
   EXPECT_FALSE(IsExtensionScheme(chrome::kChromeUIScheme));
-  EXPECT_FALSE(IsExtensionScheme(chrome::kJavaScriptScheme));
+  EXPECT_FALSE(IsExtensionScheme(content::kJavaScriptScheme));
   EXPECT_FALSE(IsExtensionScheme(content::kMailToScheme));
   EXPECT_FALSE(IsExtensionScheme(content::kMetadataScheme));
   EXPECT_FALSE(IsExtensionScheme(content::kSwappedOutScheme));
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index d8f7f9f..380aa2a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -31,7 +31,7 @@
 #include "chrome/browser/content_settings/host_content_settings_map.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/defaults.h"
-#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
 #include "chrome/browser/extensions/browser_permissions_policy_delegate.h"
@@ -115,7 +115,6 @@
 #include "content/public/browser/browser_url_handler.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/compositor_util.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/resource_context.h"
@@ -204,7 +203,7 @@
 #endif
 
 #if defined(FILE_MANAGER_EXTENSION)
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #endif
 
 #if defined(TOOLKIT_GTK)
@@ -562,16 +561,6 @@
   if (!tab)
     return;
 
-  prerender::PrerenderManager* prerender_manager =
-      prerender::PrerenderManagerFactory::GetForProfile(
-          Profile::FromBrowserContext(tab->GetBrowserContext()));
-  if (prerender_manager) {
-    prerender_manager->DestroyPrerenderForRenderView(
-        params.render_process_id,
-        params.opener_id,
-        prerender::FINAL_STATUS_CREATE_NEW_WINDOW);
-  }
-
   PopupBlockerTabHelper* popup_helper =
       PopupBlockerTabHelper::FromWebContents(tab);
   if (!popup_helper)
@@ -791,13 +780,6 @@
   return chrome::CreateWebContentsViewDelegate(web_contents);
 }
 
-// Check if the extension activity log is enabled for the profile.
-static bool IsExtensionActivityLogEnabledForProfile(Profile* profile) {
-  // crbug.com/247908 - This should be IsLogEnabled except for an issue
-  // in chrome_frame_net_tests
-  return extensions::ActivityLog::IsLogEnabledOnAnyProfile();
-}
-
 void ChromeContentBrowserClient::GuestWebContentsCreated(
     WebContents* guest_web_contents,
     WebContents* opener_web_contents,
@@ -870,9 +852,7 @@
     NOTREACHED();
     return;
   }
-  guest->Attach(embedder_web_contents,
-                extension->id(),
-                extra_params);
+  guest->Attach(embedder_web_contents, extension->id(), extra_params);
 }
 
 void ChromeContentBrowserClient::RenderProcessHostCreated(
@@ -920,7 +900,7 @@
       profile->IsOffTheRecord()));
 
   host->Send(new ChromeViewMsg_SetExtensionActivityLogEnabled(
-      IsExtensionActivityLogEnabledForProfile(profile)));
+      extensions::ActivityLog::GetInstance(profile)->IsLogEnabled()));
 
   SendExtensionWebRequestStatusToHost(host);
 
@@ -1423,9 +1403,6 @@
 #endif
     }
 
-    if (content::IsThreadedCompositingEnabled())
-      command_line->AppendSwitch(switches::kEnableThreadedCompositing);
-
     if (message_center::IsRichNotificationEnabled())
       command_line->AppendSwitch(switches::kDisableHTMLNotifications);
 
@@ -1448,6 +1425,7 @@
       switches::kDebugPrint,
       switches::kDisableBundledPpapiFlash,
       switches::kDisableExtensionsResourceWhitelist,
+      switches::kDisablePnacl,
       switches::kDisableScriptedPrintThrottling,
       switches::kEnableAdview,
       switches::kEnableAdviewSrcAttribute,
@@ -1457,7 +1435,6 @@
       switches::kEnableNaCl,
       switches::kEnableNetBenchmarking,
       switches::kEnablePasswordGeneration,
-      switches::kEnablePnacl,
       switches::kEnableWatchdog,
       switches::kMemoryProfiling,
       switches::kMessageLoopHistogrammer,
@@ -2011,12 +1988,15 @@
     return false;
   }
 
-#if !defined(OS_ANDROID)
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableBetterPopupBlocking)) {
-    return true;
+  if (g_browser_process->prerender_tracker() &&
+      g_browser_process->prerender_tracker()->TryCancelOnIOThread(
+          render_process_id,
+          opener_id,
+          prerender::FINAL_STATUS_CREATE_NEW_WINDOW)) {
+    return false;
   }
 
+#if !defined(OS_ANDROID)
   if (is_guest)
     return true;
 
@@ -2221,9 +2201,6 @@
   }
   DCHECK(!web_prefs->default_encoding.empty());
 
-  if (content::IsForceCompositingModeEnabled())
-    web_prefs->force_compositing_mode = true;
-
   WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
   extensions::ViewType view_type = extensions::GetViewType(web_contents);
   ExtensionService* service =
@@ -2255,7 +2232,7 @@
   // file manager, which is implemented using WebUI but wants HW acceleration
   // for video decode & render.
   if (url.SchemeIs(extensions::kExtensionScheme) &&
-      url.host() == kFileBrowserDomain) {
+      url.host() == file_manager::kFileManagerAppId) {
     web_prefs->accelerated_compositing_enabled = true;
     web_prefs->accelerated_2d_canvas_enabled = true;
   }
@@ -2317,7 +2294,7 @@
 }
 
 base::FilePath ChromeContentBrowserClient::GetDefaultDownloadDirectory() {
-  return download_util::GetDefaultDownloadDirectory();
+  return DownloadPrefs::GetDefaultDownloadDirectory();
 }
 
 std::string ChromeContentBrowserClient::GetDefaultDownloadName() {
@@ -2466,16 +2443,10 @@
   DCHECK(!data_path.empty());
 
   int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
-  base::FilePath chrome_pak = data_path.AppendASCII("chrome.pak");
-  base::PlatformFile f =
-      base::CreatePlatformFile(chrome_pak, flags, NULL, NULL);
-  DCHECK(f != base::kInvalidPlatformFileValue);
-  mappings->push_back(FileDescriptorInfo(kAndroidChromePakDescriptor,
-                                         FileDescriptor(f, true)));
-
   base::FilePath chrome_resources_pak =
       data_path.AppendASCII("chrome_100_percent.pak");
-  f = base::CreatePlatformFile(chrome_resources_pak, flags, NULL, NULL);
+  base::PlatformFile f =
+      base::CreatePlatformFile(chrome_resources_pak, flags, NULL, NULL);
   DCHECK(f != base::kInvalidPlatformFileValue);
   mappings->push_back(FileDescriptorInfo(kAndroidChrome100PercentPakDescriptor,
                                          FileDescriptor(f, true)));
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc
index 9d4b494..46e9072 100644
--- a/chrome/browser/chrome_content_browser_client_browsertest.cc
+++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/metrics/field_trial.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/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
@@ -25,6 +28,20 @@
     return browser()->tab_strip_model()->GetWebContentsAt(0)->
         GetController().GetLastCommittedEntry();
   }
+
+  void InstallTemplateURLWithNewTabPage(GURL new_tab_page_url) {
+    TemplateURLService* template_url_service =
+        TemplateURLServiceFactory::GetForProfile(browser()->profile());
+    ui_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
+
+    TemplateURLData data;
+    data.SetURL("http://foo.com/url?bar={searchTerms}");
+    data.new_tab_url = new_tab_page_url.spec();
+    TemplateURL* template_url = new TemplateURL(browser()->profile(), data);
+    // Takes ownership.
+    template_url_service->Add(template_url);
+    template_url_service->SetDefaultSearchProvider(template_url);
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(ChromeContentBrowserClientBrowserTest,
@@ -81,8 +98,9 @@
                        UberURLHandler_InstantExtendedNewTabPage) {
   const GURL url_original("chrome://newtab");
   const GURL url_rewritten("http://example.com/newtab");
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kInstantNewTabURL, url_rewritten.spec());
+  InstallTemplateURLWithNewTabPage(url_rewritten);
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+      "Group1 use_cacheable_ntp:1"));
   chrome::EnableInstantExtendedAPIForTesting();
 
   ui_test_utils::NavigateToURL(browser(), url_original);
@@ -97,8 +115,10 @@
                        UberURLHandler_InstantExtendedNewTabPageDisabled) {
   const GURL url_original("chrome://newtab");
   const GURL url_rewritten("http://example.com/newtab");
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kInstantNewTabURL, url_rewritten.spec());
+  InstallTemplateURLWithNewTabPage(url_rewritten);
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+      "Group1 use_cacheable_ntp:1"));
+  chrome::DisableInstantExtendedAPIForTesting();
 
   ui_test_utils::NavigateToURL(browser(), url_original);
   NavigationEntry* entry = GetLastCommittedEntry();
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h
index f6ecc44..77203a6 100644
--- a/chrome/browser/chrome_notification_types.h
+++ b/chrome/browser/chrome_notification_types.h
@@ -161,11 +161,6 @@
   // invoked on.
   NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
 
-  // Notification posted when the element that is focused has been touched. A
-  // bool parameter is passed in this notification which indicates if this node
-  // accepts. The source is the RenderViewHost.
-  NOTIFICATION_FOCUSED_NODE_TOUCHED,
-
   // Tabs --------------------------------------------------------------------
 
   // Sent when a tab is added to a WebContentsDelegate. The source is the
@@ -336,12 +331,6 @@
 
   // Task Manager ------------------------------------------------------------
 
-  // The TaskManagerChildProcessResourceProvider collects the list of child
-  // processes when StartUpdating is called. This data is collected on the IO
-  // thread and passed back to the UI thread. Once all entries are added to the
-  // task manager, this notification is sent.
-  NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
-
   // Sent when a renderer process is notified of new v8 heap statistics. The
   // source is the ID of the renderer process, and the details are a
   // V8HeapStatsDetails object.
@@ -426,13 +415,6 @@
   // pointer to SharedMemory containing the new scripts.
   NOTIFICATION_USER_SCRIPTS_UPDATED,
 
-#if !defined(OS_ANDROID)
-  // User Style Sheet --------------------------------------------------------
-
-  // Sent when the user style sheet has changed.
-  NOTIFICATION_USER_STYLE_SHEET_UPDATED,
-#endif
-
   // Extensions --------------------------------------------------------------
 
   // Sent when a CrxInstaller finishes. Source is the CrxInstaller that
@@ -670,40 +652,6 @@
   // acknowledged the module incompatibility. No details are expected.
   NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,
 
-  // Accessibility Notifications ---------------------------------------------
-
-  // Notification that a window in the browser UI (not the web content)
-  // was opened, for propagating to an accessibility extension.
-  // Details will be an AccessibilityWindowInfo.
-  NOTIFICATION_ACCESSIBILITY_WINDOW_OPENED,
-
-  // Notification that a window in the browser UI was closed.
-  // Details will be an AccessibilityWindowInfo.
-  NOTIFICATION_ACCESSIBILITY_WINDOW_CLOSED,
-
-  // Notification that a control in the browser UI was focused.
-  // Details will be an AccessibilityControlInfo.
-  NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED,
-
-  // Notification that a control in the browser UI had its action taken,
-  // like pressing a button or toggling a checkbox.
-  // Details will be an AccessibilityControlInfo.
-  NOTIFICATION_ACCESSIBILITY_CONTROL_ACTION,
-
-  // Notification that text box in the browser UI had text change.
-  // Details will be an AccessibilityControlInfo.
-  NOTIFICATION_ACCESSIBILITY_TEXT_CHANGED,
-
-  // Notification that a pop-down menu was opened, for propagating
-  // to an accessibility extension.
-  // Details will be an AccessibilityMenuInfo.
-  NOTIFICATION_ACCESSIBILITY_MENU_OPENED,
-
-  // Notification that a pop-down menu was closed, for propagating
-  // to an accessibility extension.
-  // Details will be an AccessibilityMenuInfo.
-  NOTIFICATION_ACCESSIBILITY_MENU_CLOSED,
-
   // Content Settings --------------------------------------------------------
 
   // Sent when content settings change. The source is a HostContentSettings
@@ -851,12 +799,6 @@
   // all and the details are AuthenticationNotificationDetails.
   NOTIFICATION_LOGIN_AUTHENTICATION,
 
-  // Sent when webui lock screen is ready.
-  NOTIFICATION_LOCK_WEBUI_READY,
-
-  // Sent when webui lock screen wallpaper is loaded and displayed.
-  NOTIFICATION_LOCK_BACKGROUND_DISPLAYED,
-
   // Sent when GAIA iframe has been loaded. First paint event after this fires
   // NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE.
   // Possible scenarios:
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
index 8c44adc..ca71445 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager_browsertest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
@@ -20,6 +19,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/chromeos_switches.h"
 #include "content/public/browser/notification_service.h"
@@ -151,7 +151,7 @@
 
 }  // anonymouse namespace
 
-class AccessibilityManagerTest : public CrosInProcessBrowserTest {
+class AccessibilityManagerTest : public InProcessBrowserTest {
  protected:
   AccessibilityManagerTest() {}
   virtual ~AccessibilityManagerTest() {}
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
index d26100f..d207565 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager_browsertest.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
@@ -21,6 +20,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/user_prefs/user_prefs.h"
@@ -107,7 +107,7 @@
 
 }  // namespace
 
-class MagnificationManagerTest : public CrosInProcessBrowserTest,
+class MagnificationManagerTest : public InProcessBrowserTest,
                                  public content::NotificationObserver {
  protected:
   MagnificationManagerTest() : observed_(false),
diff --git a/chrome/browser/chromeos/app_mode/app_launch_utils.cc b/chrome/browser/chromeos/app_mode/app_launch_utils.cc
new file mode 100644
index 0000000..9b993e4
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/app_launch_utils.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 "chrome/browser/chromeos/app_mode/app_launch_utils.h"
+
+#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
+#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+
+namespace chromeos {
+
+// A simple manager for the app launch that starts the launch
+// and deletes itself when the launch finishes. On launch failure,
+// it exits the browser process.
+class AppLaunchManager : public StartupAppLauncher::Observer {
+ public:
+  AppLaunchManager(Profile* profile, const std::string& app_id) {
+    startup_app_launcher_.reset(new StartupAppLauncher(profile, app_id));
+  }
+
+  void Start() {
+    startup_app_launcher_->AddObserver(this);
+    startup_app_launcher_->Start();
+  }
+
+ private:
+  virtual ~AppLaunchManager() {}
+
+  void Cleanup() { delete this; }
+
+  virtual void OnLoadingOAuthFile() OVERRIDE {}
+  virtual void OnInitializingTokenService() OVERRIDE {}
+  virtual void OnInitializingNetwork() OVERRIDE {}
+  virtual void OnNetworkWaitTimedout() OVERRIDE {}
+  virtual void OnInstallingApp() OVERRIDE {}
+  virtual void OnLaunchSucceeded() OVERRIDE { Cleanup(); }
+  virtual void OnLaunchFailed(KioskAppLaunchError::Error error) OVERRIDE {
+    KioskAppLaunchError::Save(error);
+    chrome::AttemptUserExit();
+    Cleanup();
+  }
+
+  scoped_ptr<StartupAppLauncher> startup_app_launcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppLaunchManager);
+};
+
+void LaunchAppOrDie(Profile* profile, const std::string& app_id) {
+  // AppLaunchManager manages its own lifetime.
+  (new AppLaunchManager(profile, app_id))->Start();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/app_launch_utils.h b/chrome/browser/chromeos/app_mode/app_launch_utils.h
new file mode 100644
index 0000000..ac30933
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/app_launch_utils.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_BROWSER_CHROMEOS_APP_MODE_APP_LAUNCH_UTILS_H_
+#define CHROME_BROWSER_CHROMEOS_APP_MODE_APP_LAUNCH_UTILS_H_
+
+#include <string>
+
+class Profile;
+
+namespace chromeos {
+
+// Attempts to launch the app given by |app_id| in app mode
+// or exit on failure. This function will not show any launch UI
+// during the launch. Use StartupAppLauncher for finer control
+// over the app launch processes.
+void LaunchAppOrDie(Profile *profile, const std::string& app_id);
+
+}  // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_APP_MODE_APP_LAUNCH_UTILS_H_
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
index 524c98b..acedc21 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc
@@ -20,9 +20,9 @@
 #include "chrome/browser/image_decoder.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #include "ui/gfx/codec/png_codec.h"
 
 using content::BrowserThread;
@@ -63,7 +63,7 @@
 // Returns true for valid kiosk app manifest.
 bool IsValidKioskAppManifest(const extensions::Manifest& manifest) {
   bool kiosk_enabled;
-  if (manifest.GetBoolean(extension_manifest_keys::kKioskEnabled,
+  if (manifest.GetBoolean(extensions::manifest_keys::kKioskEnabled,
                           &kiosk_enabled)) {
     return kiosk_enabled;
   }
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_launcher.cc b/chrome/browser/chromeos/app_mode/kiosk_app_launcher.cc
deleted file mode 100644
index a2cac72..0000000
--- a/chrome/browser/chromeos/app_mode/kiosk_app_launcher.cc
+++ /dev/null
@@ -1,273 +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/chromeos/app_mode/kiosk_app_launcher.h"
-
-#include "base/chromeos/chromeos_version.h"
-#include "base/logging.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
-#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
-#include "chrome/browser/chromeos/login/login_display_host_impl.h"
-#include "chrome/browser/chromeos/login/login_utils.h"
-#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/ui/app_launch_view.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
-#include "chromeos/cryptohome/async_method_caller.h"
-#include "chromeos/cryptohome/cryptohome_library.h"
-#include "chromeos/dbus/cryptohome_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace chromeos {
-
-namespace {
-
-void IgnoreResult(bool mount_success, cryptohome::MountError mount_error) {}
-
-}  // namespace
-
-// static
-KioskAppLauncher* KioskAppLauncher::running_instance_ = NULL;
-
-////////////////////////////////////////////////////////////////////////////////
-// KioskAppLauncher::CryptohomedChecker ensures cryptohome daemon is up
-// and running by issuing an IsMounted call. If the call does not go through
-// and chromeos::DBUS_METHOD_CALL_SUCCESS is not returned, it will retry after
-// some time out and at the maximum five times before it gives up. Upon
-// success, it resumes the launch by calling KioskAppLauncher::StartMount.
-
-class KioskAppLauncher::CryptohomedChecker
-    : public base::SupportsWeakPtr<CryptohomedChecker> {
- public:
-  explicit CryptohomedChecker(KioskAppLauncher* launcher)
-      : launcher_(launcher),
-        retry_count_(0) {
-  }
-  ~CryptohomedChecker() {}
-
-  void StartCheck() {
-    chromeos::DBusThreadManager::Get()->GetCryptohomeClient()->IsMounted(
-        base::Bind(&CryptohomedChecker::OnCryptohomeIsMounted,
-                   AsWeakPtr()));
-  }
-
- private:
-  void OnCryptohomeIsMounted(chromeos::DBusMethodCallStatus call_status,
-                             bool is_mounted) {
-    if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
-      const int kMaxRetryTimes = 5;
-      ++retry_count_;
-      if (retry_count_ > kMaxRetryTimes) {
-        LOG(ERROR) << "Could not talk to cryptohomed for launching kiosk app.";
-        ReportCheckResult(KioskAppLaunchError::CRYPTOHOMED_NOT_RUNNING);
-        return;
-      }
-
-      const int retry_delay_in_milliseconds = 500 * (1 << retry_count_);
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&CryptohomedChecker::StartCheck, AsWeakPtr()),
-          base::TimeDelta::FromMilliseconds(retry_delay_in_milliseconds));
-      return;
-    }
-
-    if (is_mounted)
-      LOG(ERROR) << "Cryptohome is mounted before launching kiosk app.";
-
-    // Proceed only when cryptohome is not mounded or running on dev box.
-    if (!is_mounted || !base::chromeos::IsRunningOnChromeOS())
-      ReportCheckResult(KioskAppLaunchError::NONE);
-    else
-      ReportCheckResult(KioskAppLaunchError::ALREADY_MOUNTED);
-  }
-
-  void ReportCheckResult(KioskAppLaunchError::Error error) {
-    if (error == KioskAppLaunchError::NONE)
-      launcher_->StartMount();
-    else
-      launcher_->ReportLaunchResult(error);
-  }
-
-  KioskAppLauncher* launcher_;
-  int retry_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(CryptohomedChecker);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// KioskAppLauncher::ProfileLoader creates or loads the app profile.
-
-class KioskAppLauncher::ProfileLoader : public LoginUtils::Delegate {
- public:
-  ProfileLoader(KioskAppManager* kiosk_app_manager,
-                KioskAppLauncher* kiosk_app_launcher)
-      : kiosk_app_launcher_(kiosk_app_launcher),
-        user_id_(kiosk_app_launcher->user_id_) {
-    CHECK(!user_id_.empty());
-  }
-
-  virtual ~ProfileLoader() {
-    LoginUtils::Get()->DelegateDeleted(this);
-  }
-
-  void Start() {
-    cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
-        user_id_,
-        base::Bind(&ProfileLoader::OnUsernameHashRetrieved,
-                   base::Unretained(this)));
-  }
-
- private:
-  void OnUsernameHashRetrieved(bool success,
-                               const std::string& username_hash) {
-    if (!success) {
-      LOG(ERROR) << "Unable to retrieve username hash for user '" << user_id_
-                 << "'.";
-      kiosk_app_launcher_->ReportLaunchResult(
-          KioskAppLaunchError::UNABLE_TO_RETRIEVE_HASH);
-      return;
-    }
-    LoginUtils::Get()->PrepareProfile(
-        UserContext(user_id_,
-                    std::string(),   // password
-                    std::string(),   // auth_code
-                    username_hash),
-        std::string(),  // display email
-        false,  // using_oauth
-        false,  // has_cookies
-        false,  // has_active_session
-        this);
-  }
-
-  // LoginUtils::Delegate overrides:
-  virtual void OnProfilePrepared(Profile* profile) OVERRIDE {
-    kiosk_app_launcher_->OnProfilePrepared(profile);
-  }
-
-  KioskAppLauncher* kiosk_app_launcher_;
-  std::string user_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(ProfileLoader);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// KioskAppLauncher
-
-KioskAppLauncher::KioskAppLauncher(KioskAppManager* kiosk_app_manager,
-                                   const std::string& app_id)
-    : kiosk_app_manager_(kiosk_app_manager),
-      app_id_(app_id),
-      remove_attempted_(false) {
-  KioskAppManager::App app;
-  CHECK(kiosk_app_manager_->GetApp(app_id_, &app));
-  user_id_ = app.user_id;
-}
-
-KioskAppLauncher::~KioskAppLauncher() {}
-
-void KioskAppLauncher::Start() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (running_instance_) {
-    LOG(WARNING) << "Unable to launch " << app_id_ << "with a pending launch.";
-    ReportLaunchResult(KioskAppLaunchError::HAS_PENDING_LAUNCH);
-    return;
-  }
-
-  running_instance_ = this;  // Reset in ReportLaunchResult.
-
-  // Show app launch splash. The spash is removed either after a successful
-  // launch or chrome exit because of launch failure.
-  chromeos::ShowAppLaunchSplashScreen(app_id_);
-
-  // Check cryptohomed. If all goes good, flow goes to StartMount. Otherwise
-  // it goes to ReportLaunchResult with failure.
-  crytohomed_checker.reset(new CryptohomedChecker(this));
-  crytohomed_checker->StartCheck();
-}
-
-void KioskAppLauncher::ReportLaunchResult(KioskAppLaunchError::Error error) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  running_instance_ = NULL;
-
-  if (error != KioskAppLaunchError::NONE) {
-    // Saves the error and ends the session to go back to login screen.
-    KioskAppLaunchError::Save(error);
-    chrome::AttemptUserExit();
-  }
-
-  delete this;
-}
-
-void KioskAppLauncher::StartMount() {
-  // Nuke old home that uses |app_id_| as cryptohome user id.
-  // TODO(xiyuan): Remove this after all clients migrated to new home.
-  cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
-      app_id_,
-      base::Bind(&IgnoreResult));
-
-  cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
-      user_id_,
-      cryptohome::CREATE_IF_MISSING,
-      base::Bind(&KioskAppLauncher::MountCallback,
-                 base::Unretained(this)));
-}
-
-void KioskAppLauncher::MountCallback(bool mount_success,
-                                     cryptohome::MountError mount_error) {
-  if (mount_success) {
-    profile_loader_.reset(new ProfileLoader(kiosk_app_manager_, this));
-    profile_loader_->Start();
-    return;
-  }
-
-  if (!remove_attempted_) {
-    LOG(ERROR) << "Attempt to remove app cryptohome because of mount failure"
-               << ", mount error=" << mount_error;
-
-    remove_attempted_ = true;
-    AttemptRemove();
-    return;
-  }
-
-  LOG(ERROR) << "Failed to mount app cryptohome, error=" << mount_error;
-  ReportLaunchResult(KioskAppLaunchError::UNABLE_TO_MOUNT);
-}
-
-void KioskAppLauncher::AttemptRemove() {
-  cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
-      user_id_,
-      base::Bind(&KioskAppLauncher::RemoveCallback,
-                 base::Unretained(this)));
-}
-
-void KioskAppLauncher::RemoveCallback(bool success,
-                                      cryptohome::MountError return_code) {
-  if (success) {
-    StartMount();
-    return;
-  }
-
-  LOG(ERROR) << "Failed to remove app cryptohome, erro=" << return_code;
-  ReportLaunchResult(KioskAppLaunchError::UNABLE_TO_REMOVE);
-}
-
-void KioskAppLauncher::OnProfilePrepared(Profile* profile) {
-  // StartupAppLauncher deletes itself when done.
-  (new chromeos::StartupAppLauncher(profile, app_id_))->Start();
-
-  if (LoginDisplayHostImpl::default_host())
-    LoginDisplayHostImpl::default_host()->Finalize();
-  UserManager::Get()->SessionStarted();
-
-  ReportLaunchResult(KioskAppLaunchError::NONE);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_launcher.h b/chrome/browser/chromeos/app_mode/kiosk_app_launcher.h
deleted file mode 100644
index 5b9908f..0000000
--- a/chrome/browser/chromeos/app_mode/kiosk_app_launcher.h
+++ /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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_APP_MODE_KIOSK_APP_LAUNCHER_H_
-#define CHROME_BROWSER_CHROMEOS_APP_MODE_KIOSK_APP_LAUNCHER_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
-
-class Profile;
-
-namespace chromeos {
-
-class KioskAppManager;
-
-// KioskAppLauncher launches a given app from login screen. It first attempts
-// to mount a cryptohome for the app. If the mount is successful, it prepares
-// app profile then calls StartupAppLauncher to finish the launch. If mount
-// fails, it sets relevant launch error and restart chrome to gets back to
-// the login screen. Note that there should only be one launch attempt in
-// progress.
-class KioskAppLauncher {
- public:
-  KioskAppLauncher(KioskAppManager* kiosk_app_manager,
-                   const std::string& app_id);
-
-  // Starts a launch attempt. Fails immediately if there is already a launch
-  // attempt running.
-  void Start();
-
- private:
-  class CryptohomedChecker;
-  class ProfileLoader;
-
-  // Private dtor because this class manages its own lifetime.
-  ~KioskAppLauncher();
-
-  void ReportLaunchResult(KioskAppLaunchError::Error error);
-
-  void StartMount();
-  void MountCallback(bool mount_success, cryptohome::MountError mount_error);
-
-  void AttemptRemove();
-  void RemoveCallback(bool success,
-                      cryptohome::MountError return_code);
-
-  void OnProfilePrepared(Profile* profile);
-
-  // The instance of the current running launch.
-  static KioskAppLauncher* running_instance_;
-
-  KioskAppManager* kiosk_app_manager_;
-  const std::string app_id_;
-  std::string user_id_;
-
-  scoped_ptr<CryptohomedChecker> crytohomed_checker;
-  scoped_ptr<ProfileLoader> profile_loader_;
-
-  // Whether remove existing cryptohome has attempted.
-  bool remove_attempted_;
-
-  DISALLOW_COPY_AND_ASSIGN(KioskAppLauncher);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_APP_MODE_KIOSK_APP_LAUNCHER_H_
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc
index f37386d..2532fdf 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc
@@ -17,12 +17,12 @@
 #include "base/test/scoped_path_override.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_update_service.h"
 #include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
diff --git a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
new file mode 100644
index 0000000..530cc4d
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.cc
@@ -0,0 +1,247 @@
+// Copyright 2013 The Chromium Authors. 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/app_mode/kiosk_profile_loader.h"
+
+#include "base/chromeos/chromeos_version.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+#include "chrome/browser/chromeos/login/login_display_host_impl.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chromeos/cryptohome/async_method_caller.h"
+#include "chromeos/cryptohome/cryptohome_library.h"
+#include "chromeos/dbus/cryptohome_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace chromeos {
+
+namespace {
+
+void IgnoreResult(bool mount_success, cryptohome::MountError mount_error) {}
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// KioskProfileLoader::CryptohomedChecker ensures cryptohome daemon is up
+// and running by issuing an IsMounted call. If the call does not go through
+// and chromeos::DBUS_METHOD_CALL_SUCCESS is not returned, it will retry after
+// some time out and at the maximum five times before it gives up. Upon
+// success, it resumes the launch by calling KioskProfileLoader::StartMount.
+
+class KioskProfileLoader::CryptohomedChecker
+    : public base::SupportsWeakPtr<CryptohomedChecker> {
+ public:
+  explicit CryptohomedChecker(KioskProfileLoader* loader)
+      : loader_(loader),
+        retry_count_(0) {
+  }
+  ~CryptohomedChecker() {}
+
+  void StartCheck() {
+    chromeos::DBusThreadManager::Get()->GetCryptohomeClient()->IsMounted(
+        base::Bind(&CryptohomedChecker::OnCryptohomeIsMounted,
+                   AsWeakPtr()));
+  }
+
+ private:
+  void OnCryptohomeIsMounted(chromeos::DBusMethodCallStatus call_status,
+                             bool is_mounted) {
+    if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
+      const int kMaxRetryTimes = 5;
+      ++retry_count_;
+      if (retry_count_ > kMaxRetryTimes) {
+        LOG(ERROR) << "Could not talk to cryptohomed for launching kiosk app.";
+        ReportCheckResult(KioskAppLaunchError::CRYPTOHOMED_NOT_RUNNING);
+        return;
+      }
+
+      const int retry_delay_in_milliseconds = 500 * (1 << retry_count_);
+      base::MessageLoop::current()->PostDelayedTask(
+          FROM_HERE,
+          base::Bind(&CryptohomedChecker::StartCheck, AsWeakPtr()),
+          base::TimeDelta::FromMilliseconds(retry_delay_in_milliseconds));
+      return;
+    }
+
+    if (is_mounted)
+      LOG(ERROR) << "Cryptohome is mounted before launching kiosk app.";
+
+    // Proceed only when cryptohome is not mounded or running on dev box.
+    if (!is_mounted || !base::chromeos::IsRunningOnChromeOS())
+      ReportCheckResult(KioskAppLaunchError::NONE);
+    else
+      ReportCheckResult(KioskAppLaunchError::ALREADY_MOUNTED);
+  }
+
+  void ReportCheckResult(KioskAppLaunchError::Error error) {
+    if (error == KioskAppLaunchError::NONE)
+      loader_->StartMount();
+    else
+      loader_->ReportLaunchResult(error);
+  }
+
+  KioskProfileLoader* loader_;
+  int retry_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(CryptohomedChecker);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// KioskProfileLoader::ProfileLoader actually creates or loads the app profile.
+
+class KioskProfileLoader::ProfileLoader : public LoginUtils::Delegate {
+ public:
+  ProfileLoader(KioskAppManager* kiosk_app_manager,
+                KioskProfileLoader* kiosk_profile_loader)
+      : kiosk_profile_loader_(kiosk_profile_loader),
+        user_id_(kiosk_profile_loader->user_id_) {
+    CHECK(!user_id_.empty());
+  }
+
+  virtual ~ProfileLoader() {
+    LoginUtils::Get()->DelegateDeleted(this);
+  }
+
+  void Start() {
+    cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
+        user_id_,
+        base::Bind(&ProfileLoader::OnUsernameHashRetrieved,
+                   base::Unretained(this)));
+  }
+
+ private:
+  void OnUsernameHashRetrieved(bool success,
+                               const std::string& username_hash) {
+    if (!success) {
+      LOG(ERROR) << "Unable to retrieve username hash for user '" << user_id_
+                 << "'.";
+      kiosk_profile_loader_->ReportLaunchResult(
+          KioskAppLaunchError::UNABLE_TO_RETRIEVE_HASH);
+      return;
+    }
+    LoginUtils::Get()->PrepareProfile(
+        UserContext(user_id_,
+                    std::string(),   // password
+                    std::string(),   // auth_code
+                    username_hash),
+        std::string(),  // display email
+        false,  // using_oauth
+        false,  // has_cookies
+        false,  // has_active_session
+        this);
+  }
+
+  // LoginUtils::Delegate overrides:
+  virtual void OnProfilePrepared(Profile* profile) OVERRIDE {
+    kiosk_profile_loader_->OnProfilePrepared(profile);
+  }
+
+  KioskProfileLoader* kiosk_profile_loader_;
+  std::string user_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProfileLoader);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// KioskProfileLoader
+
+KioskProfileLoader::KioskProfileLoader(KioskAppManager* kiosk_app_manager,
+                                       const std::string& app_id,
+                                       Delegate* delegate)
+    : kiosk_app_manager_(kiosk_app_manager),
+      app_id_(app_id),
+      delegate_(delegate),
+      remove_attempted_(false) {
+  KioskAppManager::App app;
+  CHECK(kiosk_app_manager_->GetApp(app_id_, &app));
+  user_id_ = app.user_id;
+}
+
+KioskProfileLoader::~KioskProfileLoader() {}
+
+void KioskProfileLoader::Start() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  // Check cryptohomed. If all goes good, flow goes to StartMount. Otherwise
+  // it goes to ReportLaunchResult with failure.
+  crytohomed_checker.reset(new CryptohomedChecker(this));
+  crytohomed_checker->StartCheck();
+}
+
+void KioskProfileLoader::ReportLaunchResult(KioskAppLaunchError::Error error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (error != KioskAppLaunchError::NONE) {
+    delegate_->OnProfileLoadFailed(error);
+  }
+}
+
+void KioskProfileLoader::StartMount() {
+  // Nuke old home that uses |app_id_| as cryptohome user id.
+  // TODO(xiyuan): Remove this after all clients migrated to new home.
+  cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
+      app_id_,
+      base::Bind(&IgnoreResult));
+
+  cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
+      user_id_,
+      cryptohome::CREATE_IF_MISSING,
+      base::Bind(&KioskProfileLoader::MountCallback,
+                 base::Unretained(this)));
+}
+
+void KioskProfileLoader::MountCallback(bool mount_success,
+                                       cryptohome::MountError mount_error) {
+  if (mount_success) {
+    profile_loader_.reset(new ProfileLoader(kiosk_app_manager_, this));
+    profile_loader_->Start();
+    return;
+  }
+
+  if (!remove_attempted_) {
+    LOG(ERROR) << "Attempt to remove app cryptohome because of mount failure"
+               << ", mount error=" << mount_error;
+
+    remove_attempted_ = true;
+    AttemptRemove();
+    return;
+  }
+
+  LOG(ERROR) << "Failed to mount app cryptohome, error=" << mount_error;
+  ReportLaunchResult(KioskAppLaunchError::UNABLE_TO_MOUNT);
+}
+
+void KioskProfileLoader::AttemptRemove() {
+  cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
+      user_id_,
+      base::Bind(&KioskProfileLoader::RemoveCallback,
+                 base::Unretained(this)));
+}
+
+void KioskProfileLoader::RemoveCallback(bool success,
+                                      cryptohome::MountError return_code) {
+  if (success) {
+    StartMount();
+    return;
+  }
+
+  LOG(ERROR) << "Failed to remove app cryptohome, error=" << return_code;
+  ReportLaunchResult(KioskAppLaunchError::UNABLE_TO_REMOVE);
+}
+
+void KioskProfileLoader::OnProfilePrepared(Profile* profile) {
+  UserManager::Get()->SessionStarted();
+  delegate_->OnProfileLoaded(profile);
+  ReportLaunchResult(KioskAppLaunchError::NONE);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/kiosk_profile_loader.h b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.h
new file mode 100644
index 0000000..7c54304
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/kiosk_profile_loader.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 CHROME_BROWSER_CHROMEOS_APP_MODE_KIOSK_PROFILE_LOADER_H_
+#define CHROME_BROWSER_CHROMEOS_APP_MODE_KIOSK_PROFILE_LOADER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+class Profile;
+
+namespace chromeos {
+
+class KioskAppManager;
+
+// KioskProfileLoader loads a special profile for a given app. It first attempts
+// to mount a cryptohome for the app. If the mount is successful, it prepares
+// app profile then calls the delegate.
+class KioskProfileLoader {
+ public:
+  class Delegate {
+   public:
+    virtual void OnProfileLoaded(Profile* profile) = 0;
+    virtual void OnProfileLoadFailed(KioskAppLaunchError::Error error) = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
+  KioskProfileLoader(KioskAppManager* kiosk_app_manager,
+                     const std::string& app_id,
+                     Delegate* delegate);
+
+  ~KioskProfileLoader();
+
+  // Starts profile load. Calls delegate on success or failure.
+  void Start();
+
+ private:
+  class CryptohomedChecker;
+  class ProfileLoader;
+
+  void ReportLaunchResult(KioskAppLaunchError::Error error);
+
+  void StartMount();
+  void MountCallback(bool mount_success, cryptohome::MountError mount_error);
+
+  void AttemptRemove();
+  void RemoveCallback(bool success,
+                      cryptohome::MountError return_code);
+
+  void OnProfilePrepared(Profile* profile);
+
+  KioskAppManager* kiosk_app_manager_;
+  const std::string app_id_;
+  std::string user_id_;
+  Delegate* delegate_;
+
+  scoped_ptr<CryptohomedChecker> crytohomed_checker;
+  scoped_ptr<ProfileLoader> profile_loader_;
+
+  // Whether remove existing cryptohome has attempted.
+  bool remove_attempted_;
+
+  DISALLOW_COPY_AND_ASSIGN(KioskProfileLoader);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_APP_MODE_KIOSK_PROFILE_LOADER_H_
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
index 8308bf0..9f6bc11 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
 
-#include "ash/shell.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
@@ -15,7 +14,6 @@
 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/ui/app_launch_view.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/webstore_startup_installer.h"
@@ -49,9 +47,6 @@
 const base::FilePath::CharType kOAuthFileName[] =
     FILE_PATH_LITERAL("kiosk_auth");
 
-// Application install splash screen minimum show time in milliseconds.
-const int kAppInstallSplashScreenMinTimeMS = 3000;
-
 bool IsAppInstalled(Profile* profile, const std::string& app_id) {
   return extensions::ExtensionSystem::Get(profile)->extension_service()->
       GetInstalledExtension(app_id);
@@ -59,31 +54,35 @@
 
 }  // namespace
 
+
 StartupAppLauncher::StartupAppLauncher(Profile* profile,
                                        const std::string& app_id)
     : profile_(profile),
-      app_id_(app_id),
-      launch_splash_start_time_(0) {
+      app_id_(app_id) {
   DCHECK(profile_);
   DCHECK(Extension::IdIsValid(app_id_));
-  DCHECK(ash::Shell::HasInstance());
-  ash::Shell::GetInstance()->AddPreTargetHandler(this);
 }
 
 StartupAppLauncher::~StartupAppLauncher() {
-  DCHECK(ash::Shell::HasInstance());
-  ash::Shell::GetInstance()->RemovePreTargetHandler(this);
 }
 
 void StartupAppLauncher::Start() {
-  launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
   DVLOG(1) << "Starting... connection = "
            <<  net::NetworkChangeNotifier::GetConnectionType();
-  chromeos::ShowAppLaunchSplashScreen(app_id_);
   StartLoadingOAuthFile();
 }
 
+void StartupAppLauncher::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void StartupAppLauncher::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
 void StartupAppLauncher::StartLoadingOAuthFile() {
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnLoadingOAuthFile());
+
   KioskOAuthParams* auth_params = new KioskOAuthParams();
   BrowserThread::PostBlockingPoolTaskAndReply(
       FROM_HERE,
@@ -134,8 +133,8 @@
 }
 
 void StartupAppLauncher::InitializeNetwork() {
-  chromeos::UpdateAppLaunchSplashScreenState(
-      chromeos::APP_LAUNCH_STATE_PREPARING_NETWORK);
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnInitializingNetwork());
+
   // Set a maximum allowed wait time for network.
   const int kMaxNetworkWaitSeconds = 5 * 60;
   network_wait_timer_.Start(
@@ -148,8 +147,8 @@
 }
 
 void StartupAppLauncher::InitializeTokenService() {
-  chromeos::UpdateAppLaunchSplashScreenState(
-      chromeos::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnInitializingTokenService());
+
   ProfileOAuth2TokenService* profile_token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
   if (profile_token_service->RefreshTokenIsAvailable()) {
@@ -199,40 +198,15 @@
   InitializeNetwork();
 }
 
-void StartupAppLauncher::Cleanup() {
-  chromeos::CloseAppLaunchSplashScreen();
-
-  delete this;
-}
-
 void StartupAppLauncher::OnLaunchSuccess() {
-  const int64 time_taken_ms = (base::TimeTicks::Now() -
-      base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
-      InMilliseconds();
-
-  // Enforce that we show app install splash screen for some minimum amount
-  // of time.
-  if (time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
-    BrowserThread::PostDelayedTask(
-        BrowserThread::UI,
-        FROM_HERE,
-        base::Bind(&StartupAppLauncher::OnLaunchSuccess, AsWeakPtr()),
-        base::TimeDelta::FromMilliseconds(
-            kAppInstallSplashScreenMinTimeMS - time_taken_ms));
-    return;
-  }
-
-  Cleanup();
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnLaunchSucceeded());
 }
 
 void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) {
+  LOG(ERROR) << "App launch failed";
   DCHECK_NE(KioskAppLaunchError::NONE, error);
 
-  // Saves the error and ends the session to go back to login screen.
-  KioskAppLaunchError::Save(error);
-  chrome::AttemptUserExit();
-
-  Cleanup();
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnLaunchFailed(error));
 }
 
 void StartupAppLauncher::Launch() {
@@ -261,12 +235,11 @@
 }
 
 void StartupAppLauncher::BeginInstall() {
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnInstallingApp());
+
   DVLOG(1) << "BeginInstall... connection = "
            <<  net::NetworkChangeNotifier::GetConnectionType();
 
-  chromeos::UpdateAppLaunchSplashScreenState(
-      chromeos::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
-
   if (IsAppInstalled(profile_, app_id_)) {
     Launch();
     return;
@@ -293,13 +266,18 @@
     return;
   }
 
-  LOG(ERROR) << "Failed to install app with error: " << error;
+  // TODO: revert this.
+  LOG(ERROR) << "Failed to install app with error: " << error << ".";
+  LOG(ERROR) << "            " << app_id_;
   OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
 }
 
 void StartupAppLauncher::OnNetworkWaitTimedout() {
   LOG(WARNING) << "OnNetworkWaitTimedout... connection = "
                <<  net::NetworkChangeNotifier::GetConnectionType();
+
+  FOR_EACH_OBSERVER(Observer, observer_list_, OnNetworkWaitTimedout());
+
   // Timeout in waiting for online. Try the install anyway.
   net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
   BeginInstall();
@@ -320,20 +298,4 @@
   }
 }
 
-void StartupAppLauncher::OnKeyEvent(ui::KeyEvent* event) {
-  if (event->type() != ui::ET_KEY_PRESSED)
-    return;
-
-  if (KioskAppManager::Get()->GetDisableBailoutShortcut())
-    return;
-
-  if (event->key_code() != ui::VKEY_S ||
-      !(event->flags() & ui::EF_CONTROL_DOWN) ||
-      !(event->flags() & ui::EF_ALT_DOWN)) {
-    return;
-  }
-
-  OnLaunchFailure(KioskAppLaunchError::USER_CANCEL);
-}
-
 }   // namespace chromeos
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.h b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
index ac7e5ae..5ed968e 100644
--- a/chrome/browser/chromeos/app_mode/startup_app_launcher.h
+++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.h
@@ -10,11 +10,11 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/signin/oauth2_token_service.h"
 #include "net/base/network_change_notifier.h"
-#include "ui/base/events/event_handler.h"
 
 class Profile;
 
@@ -25,26 +25,43 @@
 namespace chromeos {
 
 // Launches the app at startup. The flow roughly looks like this:
-// - Starts the app launch splash screen;
 // - Checks if the app is installed in user profile (aka app profile);
 // - If the app is installed, launch it and finish the flow;
 // - If not installed, prepare to start install by checking network online
 //   state;
 // - If network gets online in time, start to install the app from web store;
 // - If all goes good, launches the app and finish the flow;
-// If anything goes wrong, it exits app mode and goes back to login screen.
 class StartupAppLauncher
     : public base::SupportsWeakPtr<StartupAppLauncher>,
       public OAuth2TokenService::Observer,
-      public net::NetworkChangeNotifier::NetworkChangeObserver,
-      public ui::EventHandler {
+      public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
+  class Observer {
+   public:
+    virtual void OnLoadingOAuthFile() = 0;
+    virtual void OnInitializingTokenService() = 0;
+    virtual void OnInitializingNetwork() = 0;
+    virtual void OnNetworkWaitTimedout() = 0;
+    virtual void OnInstallingApp() = 0;
+    virtual void OnLaunchSucceeded() = 0;
+    virtual void OnLaunchFailed(KioskAppLaunchError::Error error) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
   StartupAppLauncher(Profile* profile, const std::string& app_id);
 
+  virtual ~StartupAppLauncher();
+
   // Starts app launcher. If |skip_auth_setup| is set, we will skip
   // TokenService initialization.
   void Start();
 
+  // Add and remove observers for app launch procedure.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
  private:
   // OAuth parameters from /home/chronos/kiosk_auth file.
   struct KioskOAuthParams {
@@ -53,10 +70,6 @@
     std::string client_secret;
   };
 
-  // Private dtor because this class manages its own lifetime.
-  virtual ~StartupAppLauncher();
-
-  void Cleanup();
   void OnLaunchSuccess();
   void OnLaunchFailure(KioskAppLaunchError::Error error);
 
@@ -82,13 +95,9 @@
   virtual void OnNetworkChanged(
       net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
 
-  // ui::EventHandler overrides:
-  virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
-
   Profile* profile_;
   const std::string app_id_;
-
-  int64 launch_splash_start_time_;
+  ObserverList<Observer> observer_list_;
 
   scoped_refptr<extensions::WebstoreStandaloneInstaller> installer_;
   base::OneShotTimer<StartupAppLauncher> network_wait_timer_;
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
index 04df748..d28dc3f 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc
@@ -189,6 +189,8 @@
   // We can reuse the dbus callback handler logic.
   attestation_flow_->GetCertificate(
       PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
+      std::string(),  // Not used.
+      std::string(),  // Not used.
       true,  // Force a new key to be generated.
       base::Bind(DBusStringCallback,
                  base::Bind(&AttestationPolicyObserver::UploadCertificate,
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
index 44b9173..ec12232 100644
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer_unittest.cc
@@ -183,8 +183,8 @@
     // another costly operation and if it gets triggered more than once during
     // a single pass this indicates a logical problem in the observer.
     if (new_key) {
-      EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _))
-          .WillOnce(WithArgs<2>(Invoke(CertCallbackSuccess)));
+      EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _))
+          .WillOnce(WithArgs<4>(Invoke(CertCallbackSuccess)));
     }
   }
 
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.cc b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
new file mode 100644
index 0000000..023d667
--- /dev/null
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
@@ -0,0 +1,189 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform_verification_flow.h"
+
+#include "base/logging.h"
+#include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chromeos/attestation/attestation_flow.h"
+#include "chromeos/cryptohome/async_method_caller.h"
+#include "chromeos/dbus/cryptohome_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
+// A callback method to handle DBus errors.
+void DBusCallback(const base::Callback<void(bool)>& on_success,
+                  const base::Closure& on_failure,
+                  chromeos::DBusMethodCallStatus call_status,
+                  bool result) {
+  if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS) {
+    on_success.Run(result);
+  } else {
+    LOG(ERROR) << "PlatformVerificationFlow: DBus call failed!";
+    on_failure.Run();
+  }
+}
+}  // namespace
+
+namespace chromeos {
+namespace attestation {
+
+PlatformVerificationFlow::PlatformVerificationFlow(
+    AttestationFlow* attestation_flow,
+    cryptohome::AsyncMethodCaller* async_caller,
+    CryptohomeClient* cryptohome_client,
+    UserManager* user_manager,
+    Delegate* delegate)
+    : attestation_flow_(attestation_flow),
+      async_caller_(async_caller),
+      cryptohome_client_(cryptohome_client),
+      user_manager_(user_manager),
+      delegate_(delegate),
+      weak_factory_(this) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+}
+
+PlatformVerificationFlow::~PlatformVerificationFlow() {
+}
+
+void PlatformVerificationFlow::ChallengePlatformKey(
+    content::WebContents* web_contents,
+    const std::string& service_id,
+    const std::string& challenge,
+    const ChallengeCallback& callback) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  if (delegate_->IsAttestationDisabled()) {
+    LOG(INFO) << "PlatformVerificationFlow: Feature disabled.";
+    callback.Run(POLICY_REJECTED, std::string(), std::string());
+    return;
+  }
+  BoolDBusMethodCallback dbus_callback = base::Bind(
+      &DBusCallback,
+      base::Bind(&PlatformVerificationFlow::CheckConsent,
+                 weak_factory_.GetWeakPtr(),
+                 web_contents,
+                 service_id,
+                 challenge,
+                 callback),
+      base::Bind(callback, INTERNAL_ERROR, std::string(), std::string()));
+  cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback);
+}
+
+void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents,
+                                            const std::string& service_id,
+                                            const std::string& challenge,
+                                            const ChallengeCallback& callback,
+                                            bool attestation_enrolled) {
+  ConsentType consent_type = CONSENT_TYPE_NONE;
+  if (!attestation_enrolled) {
+    consent_type = CONSENT_TYPE_ATTESTATION;
+  } else if (delegate_->IsOriginConsentRequired(web_contents)) {
+    consent_type = CONSENT_TYPE_ORIGIN;
+  } else if (delegate_->IsAlwaysAskRequired(web_contents)) {
+    consent_type = CONSENT_TYPE_ALWAYS;
+  }
+  Delegate::ConsentCallback consent_callback = base::Bind(
+      &PlatformVerificationFlow::OnConsentResponse,
+      weak_factory_.GetWeakPtr(),
+      web_contents,
+      service_id,
+      challenge,
+      callback,
+      consent_type);
+  if (consent_type == CONSENT_TYPE_NONE) {
+    consent_callback.Run(CONSENT_RESPONSE_NONE);
+  } else {
+    delegate_->ShowConsentPrompt(consent_type,
+                                 web_contents,
+                                 consent_callback);
+  }
+}
+
+void PlatformVerificationFlow::OnConsentResponse(
+    content::WebContents* web_contents,
+    const std::string& service_id,
+    const std::string& challenge,
+    const ChallengeCallback& callback,
+    ConsentType consent_type,
+    ConsentResponse consent_response) {
+  if (consent_type != CONSENT_TYPE_NONE) {
+    if (consent_response == CONSENT_RESPONSE_NONE) {
+      // No user response - do not proceed and do not modify any settings.
+      LOG(WARNING) << "PlatformVerificationFlow: No response from user.";
+      callback.Run(USER_REJECTED, std::string(), std::string());
+      return;
+    }
+    if (!delegate_->UpdateSettings(web_contents,
+                                   consent_type,
+                                   consent_response)) {
+      callback.Run(INTERNAL_ERROR, std::string(), std::string());
+      return;
+    }
+    if (consent_response == CONSENT_RESPONSE_DENY) {
+      LOG(INFO) << "PlatformVerificationFlow: User rejected request.";
+      callback.Run(USER_REJECTED, std::string(), std::string());
+      return;
+    }
+  }
+
+  // At this point all user interaction is complete and we can proceed with the
+  // certificate request.
+  AttestationFlow::CertificateCallback certificate_callback = base::Bind(
+      &PlatformVerificationFlow::OnCertificateReady,
+      weak_factory_.GetWeakPtr(),
+      service_id,
+      challenge,
+      callback);
+  attestation_flow_->GetCertificate(
+      PROFILE_CONTENT_PROTECTION_CERTIFICATE,
+      user_manager_->GetActiveUser()->email(),
+      service_id,
+      false,  // Don't force a new key.
+      certificate_callback);
+}
+
+void PlatformVerificationFlow::OnCertificateReady(
+    const std::string& service_id,
+    const std::string& challenge,
+    const ChallengeCallback& callback,
+    bool operation_success,
+    const std::string& certificate) {
+  if (!operation_success) {
+    LOG(WARNING) << "PlatformVerificationFlow: Failed to certify platform.";
+    callback.Run(PLATFORM_NOT_VERIFIED, std::string(), std::string());
+    return;
+  }
+  cryptohome::AsyncMethodCaller::DataCallback cryptohome_callback = base::Bind(
+      &PlatformVerificationFlow::OnChallengeReady,
+      weak_factory_.GetWeakPtr(),
+      certificate,
+      callback);
+  std::string key_name = kContentProtectionKeyPrefix;
+  key_name += service_id;
+  async_caller_->TpmAttestationSignSimpleChallenge(KEY_USER,
+                                                   key_name,
+                                                   challenge,
+                                                   cryptohome_callback);
+}
+
+void PlatformVerificationFlow::OnChallengeReady(
+    const std::string& certificate,
+    const ChallengeCallback& callback,
+    bool operation_success,
+    const std::string& response_data) {
+  if (!operation_success) {
+    LOG(ERROR) << "PlatformVerificationFlow: Failed to sign challenge.";
+    callback.Run(INTERNAL_ERROR, std::string(), std::string());
+    return;
+  }
+  LOG(INFO) << "PlatformVerificationFlow: Platform successfully verified.";
+  callback.Run(SUCCESS, response_data, certificate);
+}
+
+}  // namespace attestation
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.h b/chrome/browser/chromeos/attestation/platform_verification_flow.h
new file mode 100644
index 0000000..c5ffeab
--- /dev/null
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow.h
@@ -0,0 +1,205 @@
+// Copyright 2013 The Chromium Authors. 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_ATTESTATION_PLATFORM_VERIFICATION_FLOW_H_
+#define CHROME_BROWSER_CHROMEOS_ATTESTATION_PLATFORM_VERIFICATION_FLOW_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace cryptohome {
+class AsyncMethodCaller;
+}
+
+namespace chromeos {
+
+class CryptohomeClient;
+class UserManager;
+
+namespace attestation {
+
+class AttestationFlow;
+
+// This class allows platform verification for the content protection use case.
+// All methods must only be called on the UI thread.  Example:
+//   PlatformVerificationFlow verifier;
+//   PlatformVerificationFlow::Callback callback = base::Bind(&MyCallback);
+//   verifier.ChallengePlatformKey(my_web_contents, "my_id", "some_challenge",
+//                                 callback);
+class PlatformVerificationFlow {
+ public:
+  enum Result {
+    SUCCESS,                // The operation succeeded.
+    INTERNAL_ERROR,         // The operation failed unexpectedly.
+    PLATFORM_NOT_VERIFIED,  // The platform cannot be verified.  For example:
+                            // - It is not a Chrome device.
+                            // - It is not running a verified OS image.
+    USER_REJECTED,          // The user explicitly rejected the operation.
+    POLICY_REJECTED,        // The operation is not allowed by policy/settings.
+  };
+
+  enum ConsentType {
+    CONSENT_TYPE_NONE,         // No consent necessary.
+    CONSENT_TYPE_ATTESTATION,  // Consent to use attestation.
+    CONSENT_TYPE_ORIGIN,       // Consent to proceed with an unfamiliar origin.
+    CONSENT_TYPE_ALWAYS,       // Consent because 'Always Ask' was requested.
+  };
+
+  enum ConsentResponse {
+    CONSENT_RESPONSE_NONE,
+    CONSENT_RESPONSE_ALLOW,
+    CONSENT_RESPONSE_DENY,
+    CONSENT_RESPONSE_ALWAYS_ASK,
+  };
+
+  // An interface which allows settings and UI to be abstracted for testing
+  // purposes.  For normal operation the default implementation should be used.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // This callback will be called when a user has given a |response| to a
+    // consent request of the specified |type|.
+    typedef base::Callback<void(ConsentResponse response)> ConsentCallback;
+
+    // Invokes consent UI of the given |type| within the context of
+    // |web_contents| and calls |callback| when the user responds.
+    virtual void ShowConsentPrompt(ConsentType type,
+                                   content::WebContents* web_contents,
+                                   const ConsentCallback& callback) = 0;
+
+    // Returns true if settings indicate that attestation should be disabled.
+    virtual bool IsAttestationDisabled() = 0;
+
+    // Checks if the web origin represented by |web_contents| is unfamiliar and
+    // requires special user consent.
+    virtual bool IsOriginConsentRequired(
+        content::WebContents* web_contents) = 0;
+
+    // Checks if settings indicate that consent is required for the web origin
+    // represented by |web_contents| because the user requested to be prompted.
+    virtual bool IsAlwaysAskRequired(content::WebContents* web_contents) = 0;
+
+    // Updates user settings based on their response to the consent request.
+    virtual bool UpdateSettings(content::WebContents* web_contents,
+                                ConsentType consent_type,
+                                ConsentResponse consent_response) = 0;
+  };
+
+  // This callback will be called when a challenge operation completes.  If
+  // |result| is SUCCESS then |challenge_response| holds the challenge response
+  // as specified by the protocol.  The |platform_key_certificate| is for the
+  // key which was used to create the challenge response.  This key may be
+  // generated on demand and is not guaranteed to persist across multiple calls
+  // to this method.  Both the response and the certificate are opaque to
+  // the browser; they are intended for validation by an external application or
+  // service.
+  typedef base::Callback<void(Result result,
+                              const std::string& challenge_response,
+                              const std::string& platform_key_certificate)>
+      ChallengeCallback;
+
+  // A constructor that uses the default implementation of all dependencies
+  // including Delegate.
+  // TODO(dkrahn): Enable this when the default delegate has been implemented.
+  // PlatformVerificationFlow();
+
+  // An alternate constructor which specifies dependent objects explicitly.
+  // This is useful in testing.  The caller retains ownership of all pointers.
+  PlatformVerificationFlow(AttestationFlow* attestation_flow,
+                           cryptohome::AsyncMethodCaller* async_caller,
+                           CryptohomeClient* cryptohome_client,
+                           UserManager* user_manager,
+                           Delegate* delegate);
+
+  virtual ~PlatformVerificationFlow();
+
+  // Invokes an asynchronous operation to challenge a platform key.  Any user
+  // interaction will be associated with |web_contents|.  The |service_id| is an
+  // arbitrary value but it should uniquely identify the origin of the request
+  // and should not be determined by that origin; its purpose is to prevent
+  // collusion between multiple services.  The |challenge| is also an arbitrary
+  // value but it should be time sensitive or associated to some kind of session
+  // because its purpose is to prevent certificate replay.  The |callback| will
+  // be called when the operation completes.  The duration of the operation can
+  // vary depending on system state, hardware capabilities, and interaction with
+  // the user.
+  void ChallengePlatformKey(content::WebContents* web_contents,
+                            const std::string& service_id,
+                            const std::string& challenge,
+                            const ChallengeCallback& callback);
+
+ private:
+  // Checks whether we need to prompt the user for consent before proceeding and
+  // invokes the consent UI if so.  All parameters are the same as in
+  // ChallengePlatformKey except for the additional |attestation_enrolled| which
+  // specifies whether attestation has been enrolled for this device.
+  void CheckConsent(content::WebContents* web_contents,
+                    const std::string& service_id,
+                    const std::string& challenge,
+                    const ChallengeCallback& callback,
+                    bool attestation_enrolled);
+
+  // A callback called when the user has given their consent response.  All
+  // parameters are the same as in ChallengePlatformKey except for the
+  // additional |consent_type| and |consent_response| which indicate the consent
+  // type and user response, respectively.  If the response indicates that the
+  // operation should proceed, this method invokes a certificate request.
+  void OnConsentResponse(content::WebContents* web_contents,
+                         const std::string& service_id,
+                         const std::string& challenge,
+                         const ChallengeCallback& callback,
+                         ConsentType consent_type,
+                         ConsentResponse consent_response);
+
+  // A callback called when an attestation certificate request operation
+  // completes.  |service_id|, |challenge|, and |callback| are the same as in
+  // ChallengePlatformKey.  |operation_success| is true iff the certificate
+  // request operation succeeded.  |certificate| holds the certificate for the
+  // platform key on success.  If the certificate request was successful, this
+  // method invokes a request to sign the challenge.
+  void OnCertificateReady(const std::string& service_id,
+                          const std::string& challenge,
+                          const ChallengeCallback& callback,
+                          bool operation_success,
+                          const std::string& certificate);
+
+  // A callback called when a challenge signing request has completed.  The
+  // |certificate| is the platform certificate for the key which signed the
+  // challenge.  |callback| is the same as in ChallengePlatformKey.
+  // |operation_success| is true iff the challenge signing operation was
+  // successful.  If it was successful, |response_data| holds the challenge
+  // response and the method will invoke |callback|.
+  void OnChallengeReady(const std::string& certificate,
+                        const ChallengeCallback& callback,
+                        bool operation_success,
+                        const std::string& response_data);
+
+  AttestationFlow* attestation_flow_;
+  scoped_ptr<AttestationFlow> default_attestation_flow_;
+  cryptohome::AsyncMethodCaller* async_caller_;
+  CryptohomeClient* cryptohome_client_;
+  UserManager* user_manager_;
+  Delegate* delegate_;
+  scoped_ptr<Delegate> default_delegate_;
+
+  // Note: This should remain the last member so it'll be destroyed and
+  // invalidate the weak pointers before any other members are destroyed.
+  base::WeakPtrFactory<PlatformVerificationFlow> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PlatformVerificationFlow);
+};
+
+}  // namespace attestation
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_ATTESTATION_PLATFORM_VERIFICATION_FLOW_H_
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
new file mode 100644
index 0000000..45b71ab
--- /dev/null
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
@@ -0,0 +1,339 @@
+// Copyright 2013 The Chromium Authors. 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/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/attestation/platform_verification_flow.h"
+#include "chrome/browser/chromeos/login/mock_user_manager.h"
+#include "chromeos/attestation/mock_attestation_flow.h"
+#include "chromeos/cryptohome/mock_async_method_caller.h"
+#include "chromeos/dbus/fake_cryptohome_client.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::StrictMock;
+using testing::WithArgs;
+
+namespace chromeos {
+namespace attestation {
+
+namespace {
+
+const char kTestID[] = "test_id";
+const char kTestChallenge[] = "test_challenge";
+const char kTestResponse[] = "test_challenge_response";
+const char kTestCertificate[] = "test_certificate";
+const char kTestEmail[] = "test_email@chromium.org";
+
+class FakeDelegate : public PlatformVerificationFlow::Delegate {
+ public:
+  FakeDelegate() : response_(PlatformVerificationFlow::CONSENT_RESPONSE_ALLOW),
+                   num_consent_calls_(0),
+                   attestation_disabled_(false),
+                   origin_consent_required_(false),
+                   always_ask_required_(false),
+                   update_settings_result_(true) {}
+  virtual ~FakeDelegate() {}
+
+  virtual void ShowConsentPrompt(
+      PlatformVerificationFlow::ConsentType type,
+      content::WebContents* web_contents,
+      const PlatformVerificationFlow::Delegate::ConsentCallback& callback)
+      OVERRIDE {
+    num_consent_calls_++;
+    callback.Run(response_);
+  }
+
+  virtual bool IsAttestationDisabled() OVERRIDE {
+    return attestation_disabled_;
+  }
+
+  virtual bool IsOriginConsentRequired(
+      content::WebContents* web_contents) OVERRIDE {
+    return origin_consent_required_;
+  }
+
+  virtual bool IsAlwaysAskRequired(
+      content::WebContents* web_contents) OVERRIDE {
+    return always_ask_required_;
+  }
+
+  virtual bool UpdateSettings(
+      content::WebContents* web_contents,
+      PlatformVerificationFlow::ConsentType consent_type,
+      PlatformVerificationFlow::ConsentResponse consent_response) OVERRIDE {
+    return update_settings_result_;
+  }
+
+  void set_response(PlatformVerificationFlow::ConsentResponse response) {
+    response_ = response;
+  }
+
+  int num_consent_calls() {
+    return num_consent_calls_;
+  }
+
+  void set_attestation_disabled(bool attestation_disabled) {
+    attestation_disabled_ = attestation_disabled;
+  }
+
+  void set_origin_consent_required(bool origin_consent_required) {
+    origin_consent_required_ = origin_consent_required;
+  }
+
+  void set_always_ask_required(bool always_ask_required) {
+    always_ask_required_ = always_ask_required;
+  }
+
+  void set_update_settings_result(bool update_settings_result) {
+    update_settings_result_ = update_settings_result;
+  }
+
+ private:
+  PlatformVerificationFlow::ConsentResponse response_;
+  int num_consent_calls_;
+  bool attestation_disabled_;
+  bool origin_consent_required_;
+  bool always_ask_required_;
+  bool update_settings_result_;
+
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDelegate);
+};
+
+class CustomFakeCryptohomeClient : public FakeCryptohomeClient {
+ public:
+  CustomFakeCryptohomeClient() : call_status_(DBUS_METHOD_CALL_SUCCESS),
+                                 attestation_enrolled_(true) {}
+  virtual void TpmAttestationIsEnrolled(
+      const BoolDBusMethodCallback& callback) OVERRIDE {
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::Bind(callback,
+                                                      call_status_,
+                                                      attestation_enrolled_));
+  }
+
+  void set_call_status(DBusMethodCallStatus call_status) {
+    call_status_ = call_status;
+  }
+
+  void set_attestation_enrolled(bool attestation_enrolled) {
+    attestation_enrolled_ = attestation_enrolled;
+  }
+
+ private:
+  DBusMethodCallStatus call_status_;
+  bool attestation_enrolled_;
+};
+
+}  // namespace
+
+class PlatformVerificationFlowTest : public ::testing::Test {
+ public:
+  PlatformVerificationFlowTest()
+      : message_loop_(base::MessageLoop::TYPE_UI),
+        ui_thread_(content::BrowserThread::UI, &message_loop_),
+        certificate_success_(true),
+        sign_challenge_success_(true),
+        result_(PlatformVerificationFlow::INTERNAL_ERROR) {}
+
+  void SetUp() {
+    // Configure a user for the mock user manager.
+    mock_user_manager_.SetActiveUser(kTestEmail);
+
+    // Create a verifier for tests to call.
+    verifier_.reset(new PlatformVerificationFlow(&mock_attestation_flow_,
+                                                 &mock_async_caller_,
+                                                 &fake_cryptohome_client_,
+                                                 &mock_user_manager_,
+                                                 &fake_delegate_));
+
+    // Create a callback for tests to use with verifier_.
+    callback_ = base::Bind(&PlatformVerificationFlowTest::FakeChallengeCallback,
+                           base::Unretained(this));
+  }
+
+  void TearDown() {
+    verifier_.reset();
+  }
+
+  void ExpectAttestationFlow() {
+    // When consent is not given or the feature is disabled, it is important
+    // that there are no calls to the attestation service.  Thus, a test must
+    // explicitly expect these calls or the mocks will fail the test.
+
+    // Configure the mock AttestationFlow to call FakeGetCertificate.
+    EXPECT_CALL(mock_attestation_flow_,
+                GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE,
+                               kTestEmail, kTestID, _, _))
+        .WillRepeatedly(WithArgs<4>(Invoke(
+            this, &PlatformVerificationFlowTest::FakeGetCertificate)));
+
+    // Configure the mock AsyncMethodCaller to call FakeSignChallenge.
+    std::string expected_key_name = std::string(kContentProtectionKeyPrefix) +
+                                    std::string(kTestID);
+    EXPECT_CALL(mock_async_caller_,
+                TpmAttestationSignSimpleChallenge(KEY_USER, expected_key_name,
+                                                  kTestChallenge, _))
+        .WillRepeatedly(WithArgs<3>(Invoke(
+            this, &PlatformVerificationFlowTest::FakeSignChallenge)));
+  }
+
+  void FakeGetCertificate(
+      const AttestationFlow::CertificateCallback& callback) {
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::Bind(callback,
+                                                      certificate_success_,
+                                                      kTestCertificate));
+  }
+
+  void FakeSignChallenge(
+      const cryptohome::AsyncMethodCaller::DataCallback& callback) {
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::Bind(callback,
+                                                      sign_challenge_success_,
+                                                      kTestResponse));
+  }
+
+  void FakeChallengeCallback(PlatformVerificationFlow::Result result,
+                             const std::string& response,
+                             const std::string& certificate) {
+    result_ = result;
+    challenge_response_ = response;
+    certificate_ = certificate;
+  }
+
+ protected:
+  base::MessageLoop message_loop_;
+  content::TestBrowserThread ui_thread_;
+  StrictMock<MockAttestationFlow> mock_attestation_flow_;
+  cryptohome::MockAsyncMethodCaller mock_async_caller_;
+  CustomFakeCryptohomeClient fake_cryptohome_client_;
+  MockUserManager mock_user_manager_;
+  FakeDelegate fake_delegate_;
+  scoped_ptr<PlatformVerificationFlow> verifier_;
+
+  // Controls result of FakeGetCertificate.
+  bool certificate_success_;
+
+  // Controls result of FakeSignChallenge.
+  bool sign_challenge_success_;
+
+  // Callback function and data.
+  PlatformVerificationFlow::ChallengeCallback callback_;
+  PlatformVerificationFlow::Result result_;
+  std::string challenge_response_;
+  std::string certificate_;
+};
+
+TEST_F(PlatformVerificationFlowTest, SuccessNoConsent) {
+  // Make sure the call will fail if consent is requested.
+  fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_DENY);
+  ExpectAttestationFlow();
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
+  EXPECT_EQ(kTestResponse, challenge_response_);
+  EXPECT_EQ(kTestCertificate, certificate_);
+  EXPECT_EQ(0, fake_delegate_.num_consent_calls());
+}
+
+TEST_F(PlatformVerificationFlowTest, SuccessWithOriginConsent) {
+  // Enable two conditions and make sure consent is not requested twice.
+  fake_delegate_.set_origin_consent_required(true);
+  fake_delegate_.set_always_ask_required(true);
+  ExpectAttestationFlow();
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
+  EXPECT_EQ(kTestResponse, challenge_response_);
+  EXPECT_EQ(kTestCertificate, certificate_);
+  EXPECT_EQ(1, fake_delegate_.num_consent_calls());
+}
+
+TEST_F(PlatformVerificationFlowTest, SuccessWithAlwaysAskConsent) {
+  fake_delegate_.set_always_ask_required(true);
+  ExpectAttestationFlow();
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
+  EXPECT_EQ(kTestResponse, challenge_response_);
+  EXPECT_EQ(kTestCertificate, certificate_);
+  EXPECT_EQ(1, fake_delegate_.num_consent_calls());
+}
+
+TEST_F(PlatformVerificationFlowTest, SuccessWithAttestationConsent) {
+  fake_cryptohome_client_.set_attestation_enrolled(false);
+  ExpectAttestationFlow();
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::SUCCESS, result_);
+  EXPECT_EQ(kTestResponse, challenge_response_);
+  EXPECT_EQ(kTestCertificate, certificate_);
+  EXPECT_EQ(1, fake_delegate_.num_consent_calls());
+}
+
+TEST_F(PlatformVerificationFlowTest, ConsentRejected) {
+  fake_delegate_.set_always_ask_required(true);
+  fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_DENY);
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_);
+  EXPECT_EQ(1, fake_delegate_.num_consent_calls());
+}
+
+TEST_F(PlatformVerificationFlowTest, FeatureDisabled) {
+  fake_delegate_.set_attestation_disabled(true);
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::POLICY_REJECTED, result_);
+  EXPECT_EQ(0, fake_delegate_.num_consent_calls());
+}
+
+TEST_F(PlatformVerificationFlowTest, NotVerified) {
+  certificate_success_ = false;
+  ExpectAttestationFlow();
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::PLATFORM_NOT_VERIFIED, result_);
+}
+
+TEST_F(PlatformVerificationFlowTest, ChallengeSigningError) {
+  sign_challenge_success_ = false;
+  ExpectAttestationFlow();
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_);
+}
+
+TEST_F(PlatformVerificationFlowTest, DBusFailure) {
+  fake_cryptohome_client_.set_call_status(DBUS_METHOD_CALL_FAILURE);
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_);
+}
+
+TEST_F(PlatformVerificationFlowTest, UpdateSettingsFailure) {
+  fake_delegate_.set_origin_consent_required(true);
+  fake_delegate_.set_update_settings_result(false);
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::INTERNAL_ERROR, result_);
+}
+
+TEST_F(PlatformVerificationFlowTest, ConsentNoResponse) {
+  fake_delegate_.set_response(PlatformVerificationFlow::CONSENT_RESPONSE_NONE);
+  fake_delegate_.set_origin_consent_required(true);
+  verifier_->ChallengePlatformKey(NULL, kTestID, kTestChallenge, callback_);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(PlatformVerificationFlow::USER_REJECTED, result_);
+}
+
+}  // namespace attestation
+}  // namespace chromeos
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 a027e41..2d25fb8 100644
--- a/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
+++ b/chrome/browser/chromeos/audio/audio_devices_pref_handler_impl.cc
@@ -21,7 +21,7 @@
 namespace {
 
 std::string GetDeviceIdString(const chromeos::AudioDevice& device) {
-  return device.display_name + " : " +
+  return device.device_name + " : " +
          base::Uint64ToString(device.id & static_cast<uint64>(0xffffffff));
 }
 
@@ -45,7 +45,6 @@
 
 void AudioDevicesPrefHandlerImpl::SetVolumeGainValue(
     const AudioDevice& device, double value) {
-  value = std::min(std::max(value, 0.0), 100.0);
   device_volume_settings_->SetDouble(GetDeviceIdString(device), value);
 
   SaveDevicesVolumePref();
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index d6a251e..08261d2 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_launcher.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/boot_times_loader.h"
 #include "chrome/browser/chromeos/contacts/contact_manager.h"
@@ -202,9 +201,20 @@
       KioskAppLaunchError::Get() == KioskAppLaunchError::NONE;
 }
 
+void RunAutoLaunchKioskApp() {
+  ShowLoginWizard(chromeos::WizardController::kAppLaunchSplashScreenName);
+
+  // Login screen is skipped but 'login-prompt-visible' signal is still needed.
+  LOG(INFO) << "Kiosk app auto launch >> login-prompt-visible";
+  DBusThreadManager::Get()->GetSessionManagerClient()->
+      EmitLoginPromptVisible();
+}
+
 void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line,
                                        Profile* profile) {
-  if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
+  if (ShouldAutoLaunchKioskApp(parsed_command_line)) {
+    RunAutoLaunchKioskApp();
+  } else if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
     const std::string first_screen =
         parsed_command_line.HasSwitch(switches::kLoginScreen) ?
             WizardController::kLoginScreenName : std::string();
@@ -234,17 +244,6 @@
   }
 }
 
-void RunAutoLaunchKioskApp() {
-  // KioskAppLauncher deletes itself when done.
-  (new KioskAppLauncher(KioskAppManager::Get(),
-                        KioskAppManager::Get()->GetAutoLaunchApp()))->Start();
-
-  // Login screen is skipped but 'login-prompt-visible' signal is still needed.
-  LOG(INFO) << "Kiosk app auto launch >> login-prompt-visible";
-  DBusThreadManager::Get()->GetSessionManagerClient()->
-      EmitLoginPromptVisible();
-}
-
 }  // namespace
 
 namespace internal {
@@ -597,11 +596,7 @@
   // Thus only show login manager in normal (non-testing) mode.
   if (!parameters().ui_task ||
       parsed_command_line().HasSwitch(switches::kForceLoginManagerInTests)) {
-    if (ShouldAutoLaunchKioskApp(parsed_command_line())) {
-      RunAutoLaunchKioskApp();
-    } else {
-      OptionallyRunChromeOSLoginManager(parsed_command_line(), profile());
-    }
+    OptionallyRunChromeOSLoginManager(parsed_command_line(), profile());
   }
 
   // These observers must be initialized after the profile because
diff --git a/chrome/browser/chromeos/cros/cros_in_process_browser_test.cc b/chrome/browser/chromeos/cros/cros_in_process_browser_test.cc
deleted file mode 100644
index e83174f..0000000
--- a/chrome/browser/chromeos/cros/cros_in_process_browser_test.cc
+++ /dev/null
@@ -1,171 +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/chromeos/cros/cros_in_process_browser_test.h"
-#include "chrome/browser/chromeos/cros/mock_network_library.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace chromeos {
-
-using ::testing::AnyNumber;
-using ::testing::AtMost;
-using ::testing::InSequence;
-using ::testing::InvokeWithoutArgs;
-using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::StrictMock;
-using ::testing::_;
-
-CrosInProcessBrowserTest::CrosInProcessBrowserTest() :
-    mock_network_library_(NULL) {
-}
-
-CrosInProcessBrowserTest::~CrosInProcessBrowserTest() {
-}
-
-void CrosInProcessBrowserTest::InitStatusAreaMocks() {
-  if (mock_network_library_)
-    return;
-  mock_network_library_ = new StrictMock<MockNetworkLibrary>();
-  NetworkLibrary::SetForTesting(mock_network_library_);
-}
-
-void CrosInProcessBrowserTest::SetStatusAreaMocksExpectations() {
-  // We don't care how often these are called, just set their return values:
-  EXPECT_CALL(*mock_network_library_, AddNetworkProfileObserver(_))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_network_library_, AddNetworkManagerObserver(_))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_network_library_, AddNetworkDeviceObserver(_, _))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_network_library_, RemoveNetworkProfileObserver(_))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_network_library_, RemoveNetworkManagerObserver(_))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_network_library_, RemoveNetworkDeviceObserver(_, _))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_network_library_, RemoveObserverForAllNetworks(_))
-      .Times(AnyNumber());
-  EXPECT_CALL(*mock_network_library_, FindCellularDevice())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const NetworkDevice*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, FindEthernetDevice())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const NetworkDevice*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, ethernet_available())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(true)));
-  EXPECT_CALL(*mock_network_library_, wifi_available())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, wimax_available())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, cellular_available())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, ethernet_enabled())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(true)));
-  EXPECT_CALL(*mock_network_library_, wifi_enabled())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, wimax_enabled())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, cellular_enabled())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, active_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const Network*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, active_nonvirtual_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const Network*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, ethernet_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const EthernetNetwork*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, wifi_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const WifiNetwork*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, wimax_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const WimaxNetwork*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, cellular_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const CellularNetwork*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, virtual_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const VirtualNetwork*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, wifi_networks())
-      .Times(AnyNumber())
-      .WillRepeatedly((ReturnRef(wifi_networks_)));
-  EXPECT_CALL(*mock_network_library_, wimax_networks())
-      .Times(AnyNumber())
-      .WillRepeatedly((ReturnRef(wimax_networks_)));
-  EXPECT_CALL(*mock_network_library_, cellular_networks())
-      .Times(AnyNumber())
-      .WillRepeatedly((ReturnRef(cellular_networks_)));
-  EXPECT_CALL(*mock_network_library_, virtual_networks())
-      .Times(AnyNumber())
-      .WillRepeatedly((ReturnRef(virtual_networks_)));
-  EXPECT_CALL(*mock_network_library_, connected_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const Network*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, connecting_network())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return((const Network*)(NULL))));
-  EXPECT_CALL(*mock_network_library_, virtual_network_connected())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, wifi_scanning())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, cellular_initializing())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)));
-  EXPECT_CALL(*mock_network_library_, LoadOncNetworks(_, _))
-        .Times(AnyNumber());
-
-  // Set specific expectations for interesting functions:
-
-  // NetworkMenuButton::OnNetworkChanged() calls:
-  EXPECT_CALL(*mock_network_library_, Connected())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)))
-      .RetiresOnSaturation();
-  EXPECT_CALL(*mock_network_library_, Connecting())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)))
-      .RetiresOnSaturation();
-  EXPECT_CALL(*mock_network_library_, cellular_connected())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)))
-      .RetiresOnSaturation();
-
-  // NetworkMenu::InitMenuItems() calls:
-  EXPECT_CALL(*mock_network_library_, ethernet_connected())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)))
-      .RetiresOnSaturation();
-  EXPECT_CALL(*mock_network_library_, ethernet_connecting())
-      .Times(AnyNumber())
-      .WillRepeatedly((Return(false)))
-      .RetiresOnSaturation();
-}
-
-void CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture() {
-  InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
-
-  InitStatusAreaMocks();
-  SetStatusAreaMocksExpectations();
-}
-
-void CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture() {
-  // Prevent bogus gMock leak check from firing.
-  NetworkLibrary::Shutdown();
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/cros/cros_in_process_browser_test.h b/chrome/browser/chromeos/cros/cros_in_process_browser_test.h
deleted file mode 100644
index f75a973..0000000
--- a/chrome/browser/chromeos/cros/cros_in_process_browser_test.h
+++ /dev/null
@@ -1,52 +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_BROWSER_CHROMEOS_CROS_CROS_IN_PROCESS_BROWSER_TEST_H_
-#define CHROME_BROWSER_CHROMEOS_CROS_CROS_IN_PROCESS_BROWSER_TEST_H_
-
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/test/base/in_process_browser_test.h"
-
-namespace chromeos {
-
-class MockNetworkLibrary;
-
-// Base class for Chromium OS tests wanting to bring up a browser in the
-// browser test process and provide MockNetworkLibrary with preset behaviors.
-class CrosInProcessBrowserTest : public InProcessBrowserTest {
- public:
-  CrosInProcessBrowserTest();
-  virtual ~CrosInProcessBrowserTest();
-
-  // InProcessBrowserTest overrides:
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
-  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE;
-
- private:
-  // Sets up basic mocks that are used by status area items.
-  void InitStatusAreaMocks();
-
-  // Sets up corresponding expectations for basic mocks that
-  // are used by status area items.
-  // Make sure that InitStatusAreaMocks was called before.
-  // They are all configured with RetiresOnSaturation().
-  // Once such expectation is used it won't block expectations you've defined.
-  void SetStatusAreaMocksExpectations();
-
-  // Destroyed by NetworkLibrary::Shutdown().
-  MockNetworkLibrary* mock_network_library_;
-
-  // Stuff used for mock_network_library_.
-  WifiNetworkVector wifi_networks_;
-  WimaxNetworkVector wimax_networks_;
-  CellularNetworkVector cellular_networks_;
-  VirtualNetworkVector virtual_networks_;
-  std::string empty_string_;
-
-  DISALLOW_COPY_AND_ASSIGN(CrosInProcessBrowserTest);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_CROS_CROS_IN_PROCESS_BROWSER_TEST_H_
diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc
index 14c18ff..df2cebb 100644
--- a/chrome/browser/chromeos/display/display_preferences.cc
+++ b/chrome/browser/chromeos/display/display_preferences.cc
@@ -175,7 +175,7 @@
   if (!IsValidUser() || GetDisplayManager()->num_connected_displays() < 2)
     return;
 
-  ash::DisplayIdPair pair = GetDisplayController()->GetCurrentDisplayIdPair();
+  ash::DisplayIdPair pair = GetDisplayManager()->GetCurrentDisplayIdPair();
   ash::DisplayLayout display_layout =
       GetDisplayManager()->layout_store()->GetRegisteredDisplayLayout(pair);
   StoreDisplayLayoutPref(pair, display_layout);
diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc
index 8299957..fe2d5f9 100644
--- a/chrome/browser/chromeos/display/display_preferences_unittest.cc
+++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc
@@ -175,11 +175,10 @@
   shell->display_manager()->UpdateDisplays();
   // Check if the layout settings are notified to the system properly.
   // The paired layout overrides old layout.
-  ash::DisplayController* display_controller = shell->display_controller();
   // Inverted one of for specified pair (id1, id2).  Not used for the pair
   // (id1, dummy_id) since dummy_id is not connected right now.
   EXPECT_EQ("top, 20",
-            display_controller->GetCurrentDisplayLayout().ToString());
+            shell->display_manager()->GetCurrentDisplayLayout().ToString());
   EXPECT_EQ("top, 20", GetRegisteredDisplayLayoutStr(id1, id2));
   EXPECT_EQ("left, 30", GetRegisteredDisplayLayoutStr(id1, dummy_id));
 }
@@ -190,7 +189,7 @@
   ash::internal::DisplayManager* display_manager =
       ash::Shell::GetInstance()->display_manager();
 
-  UpdateDisplay("200x200*2,400x300");
+  UpdateDisplay("200x200*2, 400x300#400x400|300x200");
   int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
   gfx::Display::SetInternalDisplayId(id1);
   int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
@@ -271,7 +270,7 @@
   EXPECT_FALSE(property->GetInteger("width", &width));
   EXPECT_FALSE(property->GetInteger("height", &height));
 
-  display_manager->SetDisplayResolution(id2, gfx::Size(400, 300));
+  display_manager->SetDisplayResolution(id2, gfx::Size(300, 200));
 
   display_controller->SetPrimaryDisplayId(id2);
 
@@ -282,12 +281,13 @@
   EXPECT_FALSE(property->GetInteger("width", &width));
   EXPECT_FALSE(property->GetInteger("height", &height));
 
-  // External dispaly's resolution must be stored this time.
+  // External dispaly's resolution must be stored this time because
+  // it's not best.
   EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
   EXPECT_TRUE(property->GetInteger("width", &width));
   EXPECT_TRUE(property->GetInteger("height", &height));
-  EXPECT_EQ(400, width);
-  EXPECT_EQ(300, height);
+  EXPECT_EQ(300, width);
+  EXPECT_EQ(200, height);
 
   // The layout remains the same.
   EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
@@ -331,12 +331,18 @@
   EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
   EXPECT_TRUE(property->GetInteger("width", &width));
   EXPECT_TRUE(property->GetInteger("height", &height));
-  EXPECT_EQ(400, width);
-  EXPECT_EQ(300, height);
+  EXPECT_EQ(300, width);
+  EXPECT_EQ(200, height);
 
   // Set new display's selected resolution.
-  display_manager->SetDisplayResolution(id2 + 1, gfx::Size(500, 400));
-  UpdateDisplay("200x200*2,500x400");
+  display_manager->RegisterDisplayProperty(id2 + 1,
+                                           gfx::Display::ROTATE_0,
+                                           1.0f,
+                                           NULL,
+                                           gfx::Size(500, 400));
+
+  UpdateDisplay("200x200*2, 600x500#600x500|500x400");
+
   // Update key as the 2nd display gets new id.
   id2 = ash::ScreenAsh::GetSecondaryDisplay().id();
   key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
@@ -362,14 +368,14 @@
 TEST_F(DisplayPreferencesTest, PreventStore) {
   ResolutionNotificationController::SuppressTimerForTest();
   LoggedInAsUser();
-  UpdateDisplay("400x300");
+  UpdateDisplay("400x300#500x400|400x300|300x200");
   int64 id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
   // Set display's resolution in single display. It creates the notification and
   // display preferences should not stored meanwhile.
   ash::Shell::GetInstance()->resolution_notification_controller()->
       SetDisplayResolutionAndNotify(
           id, gfx::Size(400, 300), gfx::Size(500, 400), base::Closure());
-  UpdateDisplay("500x400");
+  UpdateDisplay("500x400#500x400|400x300|300x200");
 
   const base::DictionaryValue* properties =
       local_state()->GetDictionary(prefs::kDisplayProperties);
@@ -390,7 +396,7 @@
   // by SetDisplayResolution.
   ash::Shell::GetInstance()->display_manager()->SetDisplayResolution(
       id, gfx::Size(300, 200));
-  UpdateDisplay("300x200");
+  UpdateDisplay("300x200#500x400|400x300|300x200");
 
   property = NULL;
   EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id), &property));
@@ -468,8 +474,8 @@
   gfx::Screen* screen = gfx::Screen::GetNativeScreen();
   EXPECT_EQ(id2, screen->GetPrimaryDisplay().id());
   EXPECT_EQ(ash::DisplayLayout::BOTTOM,
-            display_controller->GetCurrentDisplayLayout().position);
-  EXPECT_EQ(-10, display_controller->GetCurrentDisplayLayout().offset);
+            display_manager->GetCurrentDisplayLayout().position);
+  EXPECT_EQ(-10, display_manager->GetCurrentDisplayLayout().offset);
   const gfx::Display& primary_display = screen->GetPrimaryDisplay();
   EXPECT_EQ("178x176", primary_display.bounds().size().ToString());
   EXPECT_EQ(gfx::Display::ROTATE_90, primary_display.rotation());
diff --git a/chrome/browser/chromeos/drive/change_list_loader.cc b/chrome/browser/chromeos/drive/change_list_loader.cc
index bd0f423..3e33a6a 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.cc
+++ b/chrome/browser/chromeos/drive/change_list_loader.cc
@@ -556,21 +556,22 @@
     return;
   }
 
-  // Build entry map for grand root directory, which has two entries;
-  // "/drive/root" and "/drive/other".
-  ResourceEntryMap grand_root_entry_map;
+  // Grand root will be changed.
+  base::FilePath* changed_directory_path =
+      new base::FilePath(util::GetDriveGrandRootPath());
+  // Add "My Drive".
   const std::string& root_resource_id = about_resource->root_folder_id();
-  grand_root_entry_map[root_resource_id] =
-      util::CreateMyDriveRootEntry(root_resource_id);
-  grand_root_entry_map[util::kDriveOtherDirSpecialResourceId] =
-      util::CreateOtherDirEntry();
-  resource_metadata_->RefreshDirectoryOnUIThread(
-      directory_fetch_info,
-      grand_root_entry_map,
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_,
+      FROM_HERE,
+      base::Bind(&ResourceMetadata::AddEntry,
+                 base::Unretained(resource_metadata_),
+                 util::CreateMyDriveRootEntry(root_resource_id)),
       base::Bind(&ChangeListLoader::DoLoadDirectoryFromServerAfterRefresh,
                  weak_ptr_factory_.GetWeakPtr(),
                  directory_fetch_info,
-                 callback));
+                 callback,
+                 base::Owned(changed_directory_path)));
 }
 
 void ChangeListLoader::DoLoadDirectoryFromServerAfterLoad(
@@ -592,20 +593,27 @@
 
   ChangeListProcessor::ResourceEntryMap entry_map;
   ChangeListProcessor::ConvertToMap(change_lists.Pass(), &entry_map, NULL);
-  resource_metadata_->RefreshDirectoryOnUIThread(
-      directory_fetch_info,
-      entry_map,
+  base::FilePath* directory_path = new base::FilePath;
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_,
+      FROM_HERE,
+      base::Bind(&ChangeListProcessor::RefreshDirectory,
+                 resource_metadata_,
+                 directory_fetch_info,
+                 entry_map,
+                 directory_path),
       base::Bind(&ChangeListLoader::DoLoadDirectoryFromServerAfterRefresh,
                  weak_ptr_factory_.GetWeakPtr(),
                  directory_fetch_info,
-                 callback));
+                 callback,
+                 base::Owned(directory_path)));
 }
 
 void ChangeListLoader::DoLoadDirectoryFromServerAfterRefresh(
     const DirectoryFetchInfo& directory_fetch_info,
     const FileOperationCallback& callback,
-    FileError error,
-    const base::FilePath& directory_path) {
+    const base::FilePath* directory_path,
+    FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
@@ -614,7 +622,7 @@
   // Also notify the observers.
   if (error == FILE_ERROR_OK) {
     FOR_EACH_OBSERVER(ChangeListLoaderObserver, observers_,
-                      OnDirectoryChanged(directory_path));
+                      OnDirectoryChanged(*directory_path));
   }
 }
 
diff --git a/chrome/browser/chromeos/drive/change_list_loader.h b/chrome/browser/chromeos/drive/change_list_loader.h
index cb12079..307fde3 100644
--- a/chrome/browser/chromeos/drive/change_list_loader.h
+++ b/chrome/browser/chromeos/drive/change_list_loader.h
@@ -31,7 +31,6 @@
 
 namespace drive {
 
-class DirectoryFetchInfo;
 class JobScheduler;
 class ResourceEntry;
 
@@ -40,6 +39,7 @@
 class ChangeList;
 class ChangeListLoaderObserver;
 class ChangeListProcessor;
+class DirectoryFetchInfo;
 class ResourceMetadata;
 
 // Callback run as a response to SearchFromServer.
@@ -210,8 +210,8 @@
   void DoLoadDirectoryFromServerAfterRefresh(
       const DirectoryFetchInfo& directory_fetch_info,
       const FileOperationCallback& callback,
-      FileError error,
-      const base::FilePath& directory_path);
+      const base::FilePath* directory_path,
+      FileError error);
 
   // ================= Implementation for other stuff =================
 
diff --git a/chrome/browser/chromeos/drive/change_list_loader_unittest.cc b/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
index f3cf147..fc3643c 100644
--- a/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
+++ b/chrome/browser/chromeos/drive/change_list_loader_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/drive/change_list_loader_observer.h"
+#include "chrome/browser/chromeos/drive/change_list_processor.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
diff --git a/chrome/browser/chromeos/drive/change_list_processor.cc b/chrome/browser/chromeos/drive/change_list_processor.cc
index 9a6eebe..181dc9d 100644
--- a/chrome/browser/chromeos/drive/change_list_processor.cc
+++ b/chrome/browser/chromeos/drive/change_list_processor.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/drive/change_list_processor.h"
 
 #include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
@@ -15,6 +16,11 @@
 namespace drive {
 namespace internal {
 
+std::string DirectoryFetchInfo::ToString() const {
+  return ("resource_id: " + resource_id_ +
+          ", changestamp: " + base::Int64ToString(changestamp_));
+}
+
 ChangeList::ChangeList(const google_apis::ResourceList& resource_list)
     : largest_changestamp_(resource_list.largest_changestamp()) {
   resource_list.GetNextFeedURL(&next_url_);
@@ -143,15 +149,62 @@
     ApplyEntry(util::CreateMyDriveRootEntry(about_resource->root_folder_id()));
   }
 
-  // Apply all entries to the metadata.
+  // Gather the set of changes in the old path.
+  // Note that we want to notify the change in both old and new paths (suppose
+  // /a/b/c is moved to /x/y/c. We want to notify both "/a/b" and "/x/y".)
+  // The old paths must be calculated before we apply any actual changes.
+  // The new paths are calculated after each change is applied. It correctly
+  // sets the new path because we apply changes in such an order (see below).
+  for (ResourceEntryMap::iterator it = entry_map_.begin();
+       it != entry_map_.end(); ++it) {
+    UpdateChangedDirs(it->second);
+  }
+
+  // Apply all entries except deleted ones to the metadata.
+  std::vector<ResourceEntry> deleted_entries;
+  deleted_entries.reserve(entry_map_.size());
   while (!entry_map_.empty()) {
-    // Start from entry_map_.begin() and traverse ancestors.
+    ResourceEntryMap::iterator it = entry_map_.begin();
+
+    // Process deleted entries later to avoid deleting moved entries under it.
+    if (it->second.deleted()) {
+      deleted_entries.push_back(ResourceEntry());
+      deleted_entries.back().Swap(&it->second);
+      entry_map_.erase(it);
+      continue;
+    }
+
+    // Start from entry_map_.begin() and traverse ancestors using the
+    // parent-child relashonships in the result (after this apply) tree.
+    // Then apply the topmost change first.
+    //
+    // By doing this, assuming the result tree does not contain any cycles, we
+    // can guarantee that no cycle is made during this apply (i.e. no entry gets
+    // moved under any of its descendants) because the following conditions are
+    // always satisfied in any move:
+    // - The new parent entry is not a descendant of the moved entry.
+    // - The new parent and its ancestors will no longer move during this apply.
     std::vector<ResourceEntryMap::iterator> entries;
-    for (ResourceEntryMap::iterator it = entry_map_.begin();
-         it != entry_map_.end();
-         it = entry_map_.find(it->second.parent_resource_id())) {
-      DCHECK_EQ(it->first, it->second.resource_id());
-      entries.push_back(it);
+    entries.push_back(entry_map_.begin());
+    for (std::string parent_id = entries.back()->second.parent_local_id();
+         !parent_id.empty();) {
+      ResourceEntryMap::iterator it_parent = entry_map_.find(parent_id);
+      if (it_parent != entry_map_.end()) {
+        // This entry is going to be updated, get the parent from the new data.
+        entries.push_back(it_parent);
+        parent_id = it_parent->second.parent_local_id();
+      } else {
+        // This entry is already updated or not going to be updated, get the
+        // parent from the current tree.
+        ResourceEntry parent_entry;
+        FileError error =
+            resource_metadata_->GetResourceEntryById(parent_id, &parent_entry);
+        if (error != FILE_ERROR_OK) {
+          LOG(ERROR) << "Cannot get the parent: " << FileErrorToString(error);
+          break;
+        }
+        parent_id = parent_entry.parent_local_id();
+      }
     }
 
     // Apply the parent first.
@@ -162,6 +215,10 @@
       entry_map_.erase(it);
     }
   }
+
+  // Apply deleted entries.
+  for (size_t i = 0; i < deleted_entries.size(); ++i)
+    ApplyEntry(deleted_entries[i]);
 }
 
 void ChangeListProcessor::ApplyEntry(const ResourceEntry& entry) {
@@ -187,67 +244,20 @@
 void ChangeListProcessor::AddEntry(const ResourceEntry& entry) {
   FileError error = resource_metadata_->AddEntry(entry);
 
-  if (error == FILE_ERROR_OK) {
-    base::FilePath file_path =
-        resource_metadata_->GetFilePath(entry.resource_id());
-    // Notify if a directory has been created.
-    if (entry.file_info().is_directory())
-      changed_dirs_.insert(file_path);
-
-    // Notify parent.
-    changed_dirs_.insert(file_path.DirName());
-  }
+  if (error == FILE_ERROR_OK)
+    UpdateChangedDirs(entry);
 }
 
 void ChangeListProcessor::RemoveEntry(const ResourceEntry& entry) {
-  std::set<base::FilePath> child_directories;
-  if (entry.file_info().is_directory()) {
-    resource_metadata_->GetChildDirectories(entry.resource_id(),
-                                            &child_directories);
-  }
-
-  base::FilePath file_path =
-      resource_metadata_->GetFilePath(entry.resource_id());
-
-  FileError error = resource_metadata_->RemoveEntry(entry.resource_id());
-
-  if (error == FILE_ERROR_OK) {
-    // Notify parent.
-    changed_dirs_.insert(file_path.DirName());
-
-    // Notify children, if any.
-    changed_dirs_.insert(child_directories.begin(), child_directories.end());
-
-    // If entry is a directory, notify self.
-    if (entry.file_info().is_directory())
-      changed_dirs_.insert(file_path);
-  }
+  resource_metadata_->RemoveEntry(entry.resource_id());
 }
 
 void ChangeListProcessor::RefreshEntry(const ResourceEntry& entry) {
-  base::FilePath old_file_path =
-      resource_metadata_->GetFilePath(entry.resource_id());
+  FileError error =
+      resource_metadata_->RefreshEntry(entry.resource_id(), entry);
 
-  FileError error = resource_metadata_->RefreshEntry(entry);
-
-  if (error == FILE_ERROR_OK) {
-    base::FilePath new_file_path =
-        resource_metadata_->GetFilePath(entry.resource_id());
-
-    // Notify old parent.
-    changed_dirs_.insert(old_file_path.DirName());
-
-    // Notify new parent.
-    changed_dirs_.insert(new_file_path.DirName());
-
-    // Notify self if entry is a directory.
-    if (entry.file_info().is_directory()) {
-      // Notify new self.
-      changed_dirs_.insert(new_file_path);
-      // Notify old self.
-      changed_dirs_.insert(old_file_path);
-    }
-  }
+  if (error == FILE_ERROR_OK)
+    UpdateChangedDirs(entry);
 }
 
 // static
@@ -282,10 +292,63 @@
   }
 }
 
+// static
+FileError ChangeListProcessor::RefreshDirectory(
+    ResourceMetadata* resource_metadata,
+    const DirectoryFetchInfo& directory_fetch_info,
+    const ResourceEntryMap& entry_map,
+    base::FilePath* out_file_path) {
+  DCHECK(!directory_fetch_info.empty());
+
+  ResourceEntry directory;
+  FileError error = resource_metadata->GetResourceEntryById(
+      directory_fetch_info.resource_id(), &directory);
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  if (!directory.file_info().is_directory())
+    return FILE_ERROR_NOT_A_DIRECTORY;
+
+  // Go through the entry map. Handle existing entries and new entries.
+  for (ResourceEntryMap::const_iterator it = entry_map.begin();
+       it != entry_map.end(); ++it) {
+    const ResourceEntry& entry = it->second;
+    // Skip if the parent resource ID does not match. This is needed to
+    // handle entries with multiple parents. For such entries, the first
+    // parent is picked and other parents are ignored, hence some entries may
+    // have a parent resource ID which does not match the target directory's.
+    if (entry.parent_local_id() != directory_fetch_info.resource_id()) {
+      DVLOG(1) << "Wrong-parent entry rejected: " << entry.resource_id();
+      continue;
+    }
+
+    error = resource_metadata->RefreshEntry(it->first, entry);
+    if (error == FILE_ERROR_NOT_FOUND)  // If refreshing fails, try adding.
+      error = resource_metadata->AddEntry(entry);
+
+    if (error != FILE_ERROR_OK)
+      return error;
+  }
+
+  directory.mutable_directory_specific_info()->set_changestamp(
+      directory_fetch_info.changestamp());
+  error = resource_metadata->RefreshEntry(directory_fetch_info.resource_id(),
+                                          directory);
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  *out_file_path = resource_metadata->GetFilePath(directory.resource_id());
+  return FILE_ERROR_OK;
+}
+
 void ChangeListProcessor::UpdateRootEntry(int64 largest_changestamp) {
+  std::string root_local_id;
+  FileError error = resource_metadata_->GetIdByPath(
+      util::GetDriveMyDriveRootPath(), &root_local_id);
+
   ResourceEntry root;
-  FileError error = resource_metadata_->GetResourceEntryByPath(
-      util::GetDriveMyDriveRootPath(), &root);
+  if (error == FILE_ERROR_OK)
+    error = resource_metadata_->GetResourceEntryById(root_local_id, &root);
 
   if (error != FILE_ERROR_OK) {
     // TODO(satorux): Need to trigger recovery if root is corrupt.
@@ -296,10 +359,33 @@
   // The changestamp should always be updated.
   root.mutable_directory_specific_info()->set_changestamp(largest_changestamp);
 
-  error = resource_metadata_->RefreshEntry(root);
+  error = resource_metadata_->RefreshEntry(root_local_id, root);
 
   LOG_IF(WARNING, error != FILE_ERROR_OK) << "Failed to refresh root directory";
 }
 
+void ChangeListProcessor::UpdateChangedDirs(const ResourceEntry& entry) {
+  base::FilePath file_path =
+      resource_metadata_->GetFilePath(entry.resource_id());
+
+  if (!file_path.empty()) {
+    // Notify parent.
+    changed_dirs_.insert(file_path.DirName());
+
+    if (entry.file_info().is_directory()) {
+      // Notify self if entry is a directory.
+      changed_dirs_.insert(file_path);
+
+      // Notify all descendants if it is a directory deletion.
+      if (entry.deleted()) {
+        std::set<base::FilePath> sub_directories;
+        resource_metadata_->GetSubDirectoriesRecursively(entry.resource_id(),
+                                                         &sub_directories);
+        changed_dirs_.insert(sub_directories.begin(), sub_directories.end());
+      }
+    }
+  }
+}
+
 }  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/change_list_processor.h b/chrome/browser/chromeos/drive/change_list_processor.h
index a80e3c7..ed921ae 100644
--- a/chrome/browser/chromeos/drive/change_list_processor.h
+++ b/chrome/browser/chromeos/drive/change_list_processor.h
@@ -28,6 +28,35 @@
 
 class ResourceMetadata;
 
+// Holds information needed to fetch contents of a directory.
+// This object is copyable.
+class DirectoryFetchInfo {
+ public:
+  DirectoryFetchInfo() : changestamp_(0) {}
+  DirectoryFetchInfo(const std::string& resource_id,
+                     int64 changestamp)
+      : resource_id_(resource_id),
+        changestamp_(changestamp) {
+  }
+
+  // Returns true if the object is empty.
+  bool empty() const { return resource_id_.empty(); }
+
+  // Resource ID of the directory.
+  const std::string& resource_id() const { return resource_id_; }
+
+  // Changestamp of the directory. The changestamp is used to determine if
+  // the directory contents should be fetched.
+  int64 changestamp() const { return changestamp_; }
+
+  // Returns a string representation of this object.
+  std::string ToString() const;
+
+ private:
+  const std::string resource_id_;
+  const int64 changestamp_;
+};
+
 // Class to represent a change list.
 class ChangeList {
  public:
@@ -82,6 +111,14 @@
   // The set of changed directories as a result of change list processing.
   const std::set<base::FilePath>& changed_dirs() const { return changed_dirs_; }
 
+  // Updates the changestamp of a directory according to |directory_fetch_info|
+  // and adds or refreshes the child entries from |entry_map|.
+  static FileError RefreshDirectory(
+      ResourceMetadata* resource_metadata,
+      const DirectoryFetchInfo& directory_fetch_info,
+      const ResourceEntryMap& entry_map,
+      base::FilePath* out_file_path);
+
  private:
   // Applies the pre-processed metadata from entry_map_ onto the resource
   // metadata. If this is not delta update (i.e. |is_delta_update| is false),
@@ -111,6 +148,9 @@
   // Updates the root directory entry. changestamp will be updated.
   void UpdateRootEntry(int64 largest_changestamp);
 
+  // Adds the directories changed by the update on |entry| to |changed_dirs_|.
+  void UpdateChangedDirs(const ResourceEntry& entry);
+
   ResourceMetadata* resource_metadata_;  // Not owned.
 
   ResourceEntryMap entry_map_;
diff --git a/chrome/browser/chromeos/drive/change_list_processor_unittest.cc b/chrome/browser/chromeos/drive/change_list_processor_unittest.cc
index 6f9d756..221ff98 100644
--- a/chrome/browser/chromeos/drive/change_list_processor_unittest.cc
+++ b/chrome/browser/chromeos/drive/change_list_processor_unittest.cc
@@ -24,6 +24,7 @@
 
 const int64 kBaseResourceListChangestamp = 123;
 const char kBaseResourceListFile[] = "gdata/root_feed.json";
+const char kRootId[] = "fake_root";
 
 enum FileOrDirectory {
   FILE,
@@ -68,7 +69,7 @@
     scoped_ptr<google_apis::AboutResource> about_resource(
         new google_apis::AboutResource);
     about_resource->set_largest_change_id(kBaseResourceListChangestamp);
-    about_resource->set_root_folder_id("fake_root");
+    about_resource->set_root_folder_id(kRootId);
 
     ChangeListProcessor processor(metadata_.get());
     processor.Apply(about_resource.Pass(),
@@ -112,25 +113,25 @@
   const EntryExpectation kExpected[] = {
       // Root files
       {"drive/root",
-          "fake_root", util::kDriveGrandRootSpecialResourceId, DIRECTORY},
+          kRootId, util::kDriveGrandRootSpecialResourceId, DIRECTORY},
       {"drive/root/File 1.txt",
-          "file:2_file_resource_id", "fake_root", FILE},
+          "file:2_file_resource_id", kRootId, FILE},
       {"drive/root/Slash \xE2\x88\x95 in file 1.txt",
-          "file:slash_file_resource_id", "fake_root", FILE},
+          "file:slash_file_resource_id", kRootId, FILE},
       {"drive/root/Document 1 excludeDir-test.gdoc",
-          "document:5_document_resource_id", "fake_root", FILE},
+          "document:5_document_resource_id", kRootId, FILE},
       // Subdirectory files
       {"drive/root/Directory 1",
-          "folder:1_folder_resource_id", "fake_root", DIRECTORY},
+          "folder:1_folder_resource_id", kRootId, DIRECTORY},
       {"drive/root/Directory 1/SubDirectory File 1.txt",
           "file:subdirectory_file_1_id", "folder:1_folder_resource_id", FILE},
       {"drive/root/Directory 1/Shared To The Account Owner.txt",
           "file:subdirectory_unowned_file_1_id",
           "folder:1_folder_resource_id", FILE},
       {"drive/root/Directory 2 excludeDir-test",
-          "folder:sub_dir_folder_2_self_link", "fake_root", DIRECTORY},
+          "folder:sub_dir_folder_2_self_link", kRootId, DIRECTORY},
       {"drive/root/Slash \xE2\x88\x95 in directory",
-          "folder:slash_dir_folder_resource_id", "fake_root", DIRECTORY},
+          "folder:slash_dir_folder_resource_id", kRootId, DIRECTORY},
       {"drive/root/Slash \xE2\x88\x95 in directory/Slash SubDir File.txt",
           "file:slash_subdir_file",
           "folder:slash_dir_folder_resource_id", FILE},
@@ -151,7 +152,7 @@
     scoped_ptr<ResourceEntry> entry = GetResourceEntry(kExpected[i].path);
     ASSERT_TRUE(entry) << "for path: " << kExpected[i].path;
     EXPECT_EQ(kExpected[i].id, entry->resource_id());
-    EXPECT_EQ(kExpected[i].parent_id, entry->parent_resource_id());
+    EXPECT_EQ(kExpected[i].parent_id, entry->parent_local_id());
     EXPECT_EQ(kExpected[i].type,
               entry->file_info().is_directory() ? DIRECTORY : FILE);
   }
@@ -167,7 +168,6 @@
   ChangeListProcessor::ConvertToMap(
       ParseChangeList(kTestJson), &entry_map, NULL);
 
-  const std::string kRootId("fake_root");
   const std::string kNewFolderId("folder:new_folder_resource_id");
   const std::string kNewFileId("document:file_added_in_new_dir_id");
 
@@ -175,8 +175,8 @@
   EXPECT_EQ(2U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kNewFolderId));
   EXPECT_TRUE(entry_map.count(kNewFileId));
-  EXPECT_EQ(kRootId, entry_map[kNewFolderId].parent_resource_id());
-  EXPECT_EQ(kNewFolderId, entry_map[kNewFileId].parent_resource_id());
+  EXPECT_EQ(kRootId, entry_map[kNewFolderId].parent_local_id());
+  EXPECT_EQ(kNewFolderId, entry_map[kNewFileId].parent_local_id());
   EXPECT_TRUE(entry_map[kNewFolderId].file_info().is_directory());
   EXPECT_FALSE(entry_map[kNewFileId].file_info().is_directory());
   EXPECT_EQ("New Directory", entry_map[kNewFolderId].title());
@@ -215,7 +215,7 @@
   EXPECT_EQ(2U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kMovedId));
   EXPECT_TRUE(entry_map.count(kDestId));
-  EXPECT_EQ(kDestId, entry_map[kMovedId].parent_resource_id());
+  EXPECT_EQ(kDestId, entry_map[kMovedId].parent_local_id());
 
   // Apply the changelist and check the effect.
   ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
@@ -249,7 +249,6 @@
   ChangeListProcessor::ConvertToMap(
       ParseChangeList(kTestJson), &entry_map, NULL);
 
-  const std::string kRootId("fake_root");
   const std::string kMovedId("file:subdirectory_file_1_id");
   const std::string kSrcId("folder:1_folder_resource_id");
 
@@ -257,7 +256,7 @@
   EXPECT_EQ(2U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kMovedId));
   EXPECT_TRUE(entry_map.count(kSrcId));
-  EXPECT_EQ(kRootId, entry_map[kMovedId].parent_resource_id());
+  EXPECT_EQ(kRootId, entry_map[kMovedId].parent_local_id());
 
   // Apply the changelist and check the effect.
   ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
@@ -285,7 +284,6 @@
   ChangeListProcessor::ConvertToMap(
       ParseChangeList(kTestJson), &entry_map, NULL);
 
-  const std::string kRootId("fake_root");
   const std::string kRenamedId("file:subdirectory_file_1_id");
   const std::string kParentId("folder:1_folder_resource_id");
 
@@ -293,7 +291,7 @@
   EXPECT_EQ(2U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kRenamedId));
   EXPECT_TRUE(entry_map.count(kParentId));
-  EXPECT_EQ(kParentId, entry_map[kRenamedId].parent_resource_id());
+  EXPECT_EQ(kParentId, entry_map[kRenamedId].parent_local_id());
   EXPECT_EQ("New SubDirectory File 1.txt", entry_map[kRenamedId].title());
 
   // Apply the changelist and check the effect.
@@ -321,7 +319,7 @@
   const char kTestJsonDelete[] =
       "gdata/delta_file_deleted_in_root.json";
 
-  const std::string kParentId("fake_root");
+  const std::string kParentId(kRootId);
   const std::string kFileId("document:added_in_root_id");
 
   ChangeListProcessor::ResourceEntryMap entry_map;
@@ -331,7 +329,7 @@
       ParseChangeList(kTestJsonAdd), &entry_map, NULL);
   EXPECT_EQ(1U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kFileId));
-  EXPECT_EQ(kParentId, entry_map[kFileId].parent_resource_id());
+  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
   EXPECT_EQ("Added file", entry_map[kFileId].title());
   EXPECT_FALSE(entry_map[kFileId].deleted());
 
@@ -351,7 +349,7 @@
       ParseChangeList(kTestJsonDelete), &entry_map, NULL);
   EXPECT_EQ(1U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kFileId));
-  EXPECT_EQ(kParentId, entry_map[kFileId].parent_resource_id());
+  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
   EXPECT_EQ("Added file", entry_map[kFileId].title());
   EXPECT_TRUE(entry_map[kFileId].deleted());
 
@@ -382,7 +380,7 @@
   EXPECT_EQ(2U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kFileId));
   EXPECT_TRUE(entry_map.count(kParentId));
-  EXPECT_EQ(kParentId, entry_map[kFileId].parent_resource_id());
+  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
   EXPECT_EQ("Added file", entry_map[kFileId].title());
   EXPECT_FALSE(entry_map[kFileId].deleted());
 
@@ -405,7 +403,7 @@
       ParseChangeList(kTestJsonDelete), &entry_map, NULL);
   EXPECT_EQ(1U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kFileId));
-  EXPECT_EQ(kParentId, entry_map[kFileId].parent_resource_id());
+  EXPECT_EQ(kParentId, entry_map[kFileId].parent_local_id());
   EXPECT_EQ("Added file", entry_map[kFileId].title());
   EXPECT_TRUE(entry_map[kFileId].deleted());
 
@@ -431,7 +429,6 @@
   ChangeListProcessor::ConvertToMap(
       ParseChangeList(kTestJson), &entry_map, NULL);
 
-  const std::string kRootId("fake_root");
   const std::string kDirId("folder:new_folder_resource_id");
   const std::string kFileId("pdf:file_added_in_deleted_dir_id");
 
@@ -439,7 +436,7 @@
   EXPECT_EQ(2U, entry_map.size());
   EXPECT_TRUE(entry_map.count(kDirId));
   EXPECT_TRUE(entry_map.count(kFileId));
-  EXPECT_EQ(kDirId, entry_map[kFileId].parent_resource_id());
+  EXPECT_EQ(kDirId, entry_map[kFileId].parent_local_id());
   EXPECT_TRUE(entry_map[kDirId].deleted());
 
   // Apply the changelist and check the effect.
@@ -454,5 +451,80 @@
   EXPECT_TRUE(changed_dirs.empty());
 }
 
+TEST_F(ChangeListProcessorTest, RefreshDirectory) {
+  // Prepare metadata.
+  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
+
+  // Create a map.
+  ChangeListProcessor::ResourceEntryMap entry_map;
+
+  // Add a new file to the map.
+  ResourceEntry new_file;
+  new_file.set_title("new_file");
+  new_file.set_resource_id("new_file_id");
+  new_file.set_parent_local_id(kRootId);
+  entry_map["new_file_id"] = new_file;
+
+  // Add "Directory 1" to the map with a new name.
+  ResourceEntry dir1;
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
+      util::GetDriveMyDriveRootPath().AppendASCII("Directory 1"), &dir1));
+  dir1.set_title(dir1.title() + " (renamed)");
+  entry_map[dir1.resource_id()] = dir1;
+
+  // Update the directory with the map.
+  const int64 kNewChangestamp = 12345;
+  base::FilePath file_path;
+  EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory(
+      metadata_.get(),
+      DirectoryFetchInfo(kRootId, kNewChangestamp),
+      entry_map,
+      &file_path));
+  EXPECT_EQ(util::GetDriveMyDriveRootPath().value(), file_path.value());
+
+  // The new changestamp should be set.
+  ResourceEntry entry;
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
+      util::GetDriveMyDriveRootPath(), &entry));
+  EXPECT_EQ(kNewChangestamp, entry.directory_specific_info().changestamp());
+
+  // "new_file" should be added.
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
+      util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry));
+
+  // "Directory 1" should be renamed.
+  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
+      util::GetDriveMyDriveRootPath().AppendASCII(dir1.title()), &entry));
+}
+
+TEST_F(ChangeListProcessorTest, RefreshDirectory_WrongParentId) {
+  // Prepare metadata.
+  ApplyFullResourceList(ParseChangeList(kBaseResourceListFile));
+
+  // Create a map and add a new file to it.
+  ChangeListProcessor::ResourceEntryMap entry_map;
+  ResourceEntry new_file;
+  new_file.set_title("new_file");
+  new_file.set_resource_id("new_file_id");
+  // This entry should not be added because the parent ID does not match.
+  new_file.set_parent_local_id("some-random-resource-id");
+  entry_map["new_file_id"] = new_file;
+
+  // Update the directory with the map.
+  const int64 kNewChangestamp = 12345;
+  base::FilePath file_path;
+  EXPECT_EQ(FILE_ERROR_OK, ChangeListProcessor::RefreshDirectory(
+      metadata_.get(),
+      DirectoryFetchInfo(kRootId, kNewChangestamp),
+      entry_map,
+      &file_path));
+  EXPECT_EQ(util::GetDriveMyDriveRootPath().value(), file_path.value());
+
+  // "new_file" should not be added.
+  ResourceEntry entry;
+  EXPECT_EQ(FILE_ERROR_NOT_FOUND, metadata_->GetResourceEntryByPath(
+      util::GetDriveMyDriveRootPath().AppendASCII(new_file.title()), &entry));
+}
+
 }  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/download_handler.cc b/chrome/browser/chromeos/drive/download_handler.cc
index 850caf9..2dd6c0f 100644
--- a/chrome/browser/chromeos/drive/download_handler.cc
+++ b/chrome/browser/chromeos/drive/download_handler.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "chrome/browser/chromeos/drive/file_write_helper.h"
+#include "chrome/browser/chromeos/drive/write_on_cache_file.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
@@ -95,11 +95,8 @@
 
 }  // namespace
 
-DownloadHandler::DownloadHandler(
-    FileWriteHelper* file_write_helper,
-    FileSystemInterface* file_system)
-    : file_write_helper_(file_write_helper),
-      file_system_(file_system),
+DownloadHandler::DownloadHandler(FileSystemInterface* file_system)
+    : file_system_(file_system),
       weak_ptr_factory_(this) {
 }
 
@@ -303,8 +300,10 @@
 
 void DownloadHandler::UploadDownloadItem(DownloadItem* download) {
   DCHECK_EQ(DownloadItem::COMPLETE, download->GetState());
-  file_write_helper_->PrepareWritableFileAndRun(
+  WriteOnCacheFile(
+      file_system_,
       util::ExtractDrivePath(GetTargetPath(download)),
+      download->GetMimeType(),
       base::Bind(&MoveDownloadedFile, download->GetTargetFilePath()));
 }
 
diff --git a/chrome/browser/chromeos/drive/download_handler.h b/chrome/browser/chromeos/drive/download_handler.h
index 4289a5f..4f2ec20 100644
--- a/chrome/browser/chromeos/drive/download_handler.h
+++ b/chrome/browser/chromeos/drive/download_handler.h
@@ -21,15 +21,13 @@
 namespace drive {
 
 class FileSystemInterface;
-class FileWriteHelper;
 class ResourceEntry;
 
 // Observes downloads to temporary local drive folder. Schedules these
 // downloads for upload to drive service.
 class DownloadHandler : public AllDownloadItemNotifier::Observer {
  public:
-  DownloadHandler(FileWriteHelper* file_write_helper,
-                  FileSystemInterface* file_system);
+  explicit DownloadHandler(FileSystemInterface* file_system);
   virtual ~DownloadHandler();
 
   // Utility method to get DownloadHandler with profile.
@@ -91,7 +89,6 @@
   // Starts the upload of a downloaded/downloading file.
   void UploadDownloadItem(content::DownloadItem* download);
 
-  FileWriteHelper* file_write_helper_;
   FileSystemInterface* file_system_;  // Owned by DriveIntegrationService.
   // Observe the DownloadManager for new downloads.
   scoped_ptr<AllDownloadItemNotifier> notifier_;
diff --git a/chrome/browser/chromeos/drive/download_handler_unittest.cc b/chrome/browser/chromeos/drive/download_handler_unittest.cc
index ce069be..b096a19 100644
--- a/chrome/browser/chromeos/drive/download_handler_unittest.cc
+++ b/chrome/browser/chromeos/drive/download_handler_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "chrome/browser/chromeos/drive/dummy_file_system.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "chrome/browser/chromeos/drive/file_write_helper.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
 #include "content/public/test/mock_download_item.h"
 #include "content/public/test/mock_download_manager.h"
@@ -77,9 +76,7 @@
     EXPECT_CALL(download_item_, GetState())
         .WillRepeatedly(testing::Return(content::DownloadItem::IN_PROGRESS));
 
-    file_write_helper_.reset(new FileWriteHelper(&test_file_system_));
-    download_handler_.reset(
-        new DownloadHandler(file_write_helper_.get(), &test_file_system_));
+    download_handler_.reset(new DownloadHandler(&test_file_system_));
     download_handler_->Initialize(download_manager_.get(), temp_dir_.path());
   }
 
@@ -88,7 +85,6 @@
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<content::MockDownloadManager> download_manager_;
   DownloadHandlerTestFileSystem test_file_system_;
-  scoped_ptr<FileWriteHelper> file_write_helper_;
   scoped_ptr<DownloadHandler> download_handler_;
   content::MockDownloadItem download_item_;
 };
diff --git a/chrome/browser/chromeos/drive/drive.proto b/chrome/browser/chromeos/drive/drive.proto
index 3ab2da1..5eef041 100644
--- a/chrome/browser/chromeos/drive/drive.proto
+++ b/chrome/browser/chromeos/drive/drive.proto
@@ -75,18 +75,8 @@
   // Resource ID of the entry. Guaranteed to be unique.
   optional string resource_id = 4;
 
-  // Resource ID of the parent entry. Every entry is guaranteed to have the
-  // single parent resource ID in ResourceMetadata. This requirement is
-  // needed to represent contents in Drive as a file system tree, and
-  // achieved as follows:
-  //
-  // 1) Entries without parents are allowed on drive.google.com. These
-  // entries are collected to "drive/other", and have the resource ID of
-  // "drive/other" as the parent resource ID.
-  //
-  // 2) Entries with multiple parents are allowed on drive.google.com. For
-  // these entries, the first parent resource ID is chosen.
-  optional string parent_resource_id = 7;
+  // Local ID of the parent entry.
+  optional string parent_local_id = 7;
 
   // This field is used for processing the change list from the
   // server. Deleted entries won't be stored in ResourceMetadata.
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index 8ea55a5..e6be3df 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -16,15 +16,13 @@
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_system.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "chrome/browser/chromeos/drive/file_write_helper.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
 #include "chrome/browser/chromeos/drive/logging.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
-#include "chrome/browser/chromeos/profiles/profile_util.h"
+#include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/download/download_service.h"
 #include "chrome/browser/download/download_service_factory.h"
-#include "chrome/browser/download/download_util.h"
 #include "chrome/browser/drive/drive_api_service.h"
 #include "chrome/browser/drive/drive_api_util.h"
 #include "chrome/browser/drive/drive_notification_manager.h"
@@ -49,22 +47,6 @@
 namespace drive {
 namespace {
 
-// Returns true if Drive is enabled for the given Profile.
-bool IsDriveEnabledForProfile(Profile* profile) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (!chromeos::IsProfileAssociatedWithGaiaAccount(profile))
-    return false;
-
-  // Disable Drive if preference is set.  This can happen with commandline flag
-  // --disable-gdata or enterprise policy, or probably with user settings too
-  // in the future.
-  if (profile->GetPrefs()->GetBoolean(prefs::kDisableDrive))
-    return false;
-
-  return true;
-}
-
 // Returns a user agent string used for communicating with the Drive backend,
 // both WAPI and Drive API.  The user agent looks like:
 //
@@ -145,7 +127,7 @@
     const base::FilePath& test_cache_root,
     FileSystemInterface* test_file_system)
     : profile_(profile),
-      drive_disabled_(false),
+      is_initialized_(false),
       cache_root_directory_(!test_cache_root.empty() ?
                             test_cache_root : util::GetCacheRootPath(profile)),
       weak_ptr_factory_(this) {
@@ -204,9 +186,7 @@
           resource_metadata_.get(),
           blocking_task_runner_.get(),
           cache_root_directory_.Append(util::kTemporaryFileDirectory)));
-  file_write_helper_.reset(new FileWriteHelper(file_system()));
-  download_handler_.reset(new DownloadHandler(file_write_helper(),
-                                              file_system()));
+  download_handler_.reset(new DownloadHandler(file_system()));
   debug_info_collector_.reset(
       new DebugInfoCollector(file_system(), cache_.get()));
 }
@@ -243,7 +223,6 @@
   RemoveDriveMountPoint();
   debug_info_collector_.reset();
   download_handler_.reset();
-  file_write_helper_.reset();
   file_system_.reset();
   drive_app_registry_.reset();
   scheduler_.reset();
@@ -278,14 +257,10 @@
 bool DriveIntegrationService::IsDriveEnabled() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  if (!IsDriveEnabledForProfile(profile_))
+  if (!util::IsDriveEnabledForProfile(profile_))
     return false;
 
-  // Drive may be disabled for cache initialization failure, etc.
-  if (drive_disabled_)
-    return false;
-
-  return true;
+  return is_initialized_;
 }
 
 void DriveIntegrationService::ClearCacheAndRemountFileSystem(
@@ -365,11 +340,19 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   if (error != FILE_ERROR_OK) {
-    LOG(WARNING) << "Failed to initialize. Disabling Drive : "
-                 << FileErrorToString(error);
-    DisableDrive();
+    LOG(WARNING) << "Failed to initialize: " << FileErrorToString(error);
+
+    // Change the download directory to the default value if the download
+    // destination is set to under Drive mount point.
+    PrefService* pref_service = profile_->GetPrefs();
+    if (util::IsUnderDriveMountPoint(
+            pref_service->GetFilePath(prefs::kDownloadDefaultDirectory))) {
+      pref_service->SetFilePath(prefs::kDownloadDefaultDirectory,
+                                DownloadPrefs::GetDefaultDownloadDirectory());
+    }
     return;
   }
+  is_initialized_ = true;
 
   content::DownloadManager* download_manager =
       g_browser_process->download_status_updater() ?
@@ -395,20 +378,6 @@
   AddDriveMountPoint();
 }
 
-void DriveIntegrationService::DisableDrive() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  drive_disabled_ = true;
-  // Change the download directory to the default value if the download
-  // destination is set to under Drive mount point.
-  PrefService* pref_service = profile_->GetPrefs();
-  if (util::IsUnderDriveMountPoint(
-          pref_service->GetFilePath(prefs::kDownloadDefaultDirectory))) {
-    pref_service->SetFilePath(prefs::kDownloadDefaultDirectory,
-                              download_util::GetDefaultDownloadDirectory());
-  }
-}
-
 //===================== DriveIntegrationServiceFactory =======================
 
 // static
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index 56e15a9..943c4ad 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -29,7 +29,6 @@
 class DriveAppRegistry;
 class DriveServiceInterface;
 class FileSystemInterface;
-class FileWriteHelper;
 class JobListInterface;
 
 namespace internal {
@@ -99,7 +98,6 @@
     return debug_info_collector_.get();
   }
   FileSystemInterface* file_system() { return file_system_.get(); }
-  FileWriteHelper* file_write_helper() { return file_write_helper_.get(); }
   DownloadHandler* download_handler() { return download_handler_.get(); }
   DriveAppRegistry* drive_app_registry() { return drive_app_registry_.get(); }
   JobListInterface* job_list() { return scheduler_.get(); }
@@ -130,16 +128,10 @@
   // the metadata initialization is successful.
   void InitializeAfterMetadataInitialized(FileError error);
 
-  // Disables Drive. Used to disable Drive when needed (ex. initialization of
-  // the Drive cache failed).
-  // Must be called on UI thread.
-  void DisableDrive();
-
   friend class DriveIntegrationServiceFactory;
 
   Profile* profile_;
-  // True if Drive is disabled due to initialization errors.
-  bool drive_disabled_;
+  bool is_initialized_;
 
   base::FilePath cache_root_directory_;
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
@@ -152,7 +144,6 @@
   scoped_ptr<internal::ResourceMetadata,
              util::DestroyHelper> resource_metadata_;
   scoped_ptr<FileSystemInterface> file_system_;
-  scoped_ptr<FileWriteHelper> file_write_helper_;
   scoped_ptr<DownloadHandler> download_handler_;
   scoped_ptr<DebugInfoCollector> debug_info_collector_;
 
diff --git a/chrome/browser/chromeos/drive/dummy_file_system.h b/chrome/browser/chromeos/drive/dummy_file_system.h
index c0fe931..6a10c27 100644
--- a/chrome/browser/chromeos/drive/dummy_file_system.h
+++ b/chrome/browser/chromeos/drive/dummy_file_system.h
@@ -17,16 +17,13 @@
   virtual void AddObserver(FileSystemObserver* observer) OVERRIDE {}
   virtual void RemoveObserver(FileSystemObserver* observer) OVERRIDE {}
   virtual void CheckForUpdates() OVERRIDE {}
-  virtual void TransferFileFromRemoteToLocal(
-      const base::FilePath& remote_src_file_path,
-      const base::FilePath& local_dest_file_path,
-      const FileOperationCallback& callback) OVERRIDE {}
   virtual void TransferFileFromLocalToRemote(
       const base::FilePath& local_src_file_path,
       const base::FilePath& remote_dest_file_path,
       const FileOperationCallback& callback) OVERRIDE {}
   virtual void OpenFile(const base::FilePath& file_path,
                         OpenMode open_mode,
+                        const std::string& mime_type,
                         const OpenFileCallback& callback) OVERRIDE {}
   virtual void Copy(const base::FilePath& src_file_path,
                     const base::FilePath& dest_file_path,
@@ -44,6 +41,7 @@
       const FileOperationCallback& callback) OVERRIDE {}
   virtual void CreateFile(const base::FilePath& file_path,
                           bool is_exclusive,
+                          const std::string& mime_type,
                           const FileOperationCallback& callback) OVERRIDE {}
   virtual void TouchFile(const base::FilePath& file_path,
                          const base::Time& last_access_time,
diff --git a/chrome/browser/chromeos/drive/fake_file_system.cc b/chrome/browser/chromeos/drive/fake_file_system.cc
index 6211872..b34b24b 100644
--- a/chrome/browser/chromeos/drive/fake_file_system.cc
+++ b/chrome/browser/chromeos/drive/fake_file_system.cc
@@ -54,13 +54,6 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
-void FakeFileSystem::TransferFileFromRemoteToLocal(
-    const base::FilePath& remote_src_file_path,
-    const base::FilePath& local_dest_file_path,
-    const FileOperationCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
 void FakeFileSystem::TransferFileFromLocalToRemote(
     const base::FilePath& local_src_file_path,
     const base::FilePath& remote_dest_file_path,
@@ -70,6 +63,7 @@
 
 void FakeFileSystem::OpenFile(const base::FilePath& file_path,
                               OpenMode open_mode,
+                              const std::string& mime_type,
                               const OpenFileCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
@@ -102,6 +96,7 @@
 
 void FakeFileSystem::CreateFile(const base::FilePath& file_path,
                                 bool is_exclusive,
+                                const std::string& mime_type,
                                 const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
diff --git a/chrome/browser/chromeos/drive/fake_file_system.h b/chrome/browser/chromeos/drive/fake_file_system.h
index 6b20d34..052e672 100644
--- a/chrome/browser/chromeos/drive/fake_file_system.h
+++ b/chrome/browser/chromeos/drive/fake_file_system.h
@@ -51,16 +51,13 @@
   virtual void AddObserver(FileSystemObserver* observer) OVERRIDE;
   virtual void RemoveObserver(FileSystemObserver* observer) OVERRIDE;
   virtual void CheckForUpdates() OVERRIDE;
-  virtual void TransferFileFromRemoteToLocal(
-      const base::FilePath& remote_src_file_path,
-      const base::FilePath& local_dest_file_path,
-      const FileOperationCallback& callback) OVERRIDE;
   virtual void TransferFileFromLocalToRemote(
       const base::FilePath& local_src_file_path,
       const base::FilePath& remote_dest_file_path,
       const FileOperationCallback& callback) OVERRIDE;
   virtual void OpenFile(const base::FilePath& file_path,
                         OpenMode open_mode,
+                        const std::string& mime_type,
                         const OpenFileCallback& callback) OVERRIDE;
   virtual void Copy(const base::FilePath& src_file_path,
                     const base::FilePath& dest_file_path,
@@ -77,6 +74,7 @@
                                const FileOperationCallback& callback) OVERRIDE;
   virtual void CreateFile(const base::FilePath& file_path,
                           bool is_exclusive,
+                          const std::string& mime_type,
                           const FileOperationCallback& callback) OVERRIDE;
   virtual void TouchFile(const base::FilePath& file_path,
                          const base::Time& last_access_time,
diff --git a/chrome/browser/chromeos/drive/file_cache.cc b/chrome/browser/chromeos/drive/file_cache.cc
index 7b190c0..b5a562f 100644
--- a/chrome/browser/chromeos/drive/file_cache.cc
+++ b/chrome/browser/chromeos/drive/file_cache.cc
@@ -14,7 +14,6 @@
 #include "base/sys_info.h"
 #include "base/task_runner_util.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
-#include "chrome/browser/chromeos/drive/file_cache_metadata.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 #include "chrome/browser/google_apis/task_util.h"
@@ -92,9 +91,6 @@
 
 }  // namespace
 
-const base::FilePath::CharType FileCache::kOldCacheMetadataDBName[] =
-    FILE_PATH_LITERAL("cache_metadata.db");
-
 FileCache::FileCache(ResourceMetadataStorage* storage,
                      const base::FilePath& cache_file_directory,
                      base::SequencedTaskRunner* blocking_task_runner,
@@ -472,9 +468,7 @@
 
   RenameCacheFilesToNewFormat();
 
-  if (!ImportOldDB(storage_->directory_path().Append(
-          kOldCacheMetadataDBName)) &&
-      !storage_->opened_existing_db()) {
+  if (!storage_->opened_existing_db()) {
     CacheMap cache_map;
     ScanCacheDirectory(cache_file_directory_, &cache_map);
     for (CacheMap::const_iterator it = cache_map.begin();
@@ -642,33 +636,6 @@
   return (free_space >= num_bytes);
 }
 
-bool FileCache::ImportOldDB(const base::FilePath& old_db_path) {
-  if (!base::PathExists(old_db_path))  // Old DB is not there, do nothing.
-    return false;
-
-  // Copy all entries stored in the old DB.
-  bool imported = false;
-  {
-    FileCacheMetadata old_data(blocking_task_runner_.get());
-    if (old_data.Initialize(old_db_path) ==
-        FileCacheMetadata::INITIALIZE_OPENED) {
-      scoped_ptr<FileCacheMetadata::Iterator> it = old_data.GetIterator();
-      for (; !it->IsAtEnd(); it->Advance()) {
-        FileCacheEntry entry;
-        if (storage_->GetCacheEntry(it->GetKey(), &entry))
-          continue;  // Do not overwrite.
-
-        storage_->PutCacheEntry(it->GetKey(), it->GetValue());
-      }
-      imported = true;
-    }
-  }
-
-  // Delete old DB.
-  base::DeleteFile(old_db_path, true /* recursive */ );
-  return imported;
-}
-
 void FileCache::RenameCacheFilesToNewFormat() {
   // First, remove all files with multiple extensions just in case.
   {
diff --git a/chrome/browser/chromeos/drive/file_cache.h b/chrome/browser/chromeos/drive/file_cache.h
index 41573ee..4adc25e 100644
--- a/chrome/browser/chromeos/drive/file_cache.h
+++ b/chrome/browser/chromeos/drive/file_cache.h
@@ -70,10 +70,6 @@
 
   typedef ResourceMetadataStorage::CacheEntryIterator Iterator;
 
-  // Name of the cache metadata DB previously used.
-  // TODO(hashimoto): Remove this at some point.
-  static const base::FilePath::CharType kOldCacheMetadataDBName[];
-
   // |cache_file_directory| stores cached files.
   //
   // |blocking_task_runner| is used to post a task to the blocking worker
@@ -264,10 +260,6 @@
   // bytes, while keeping kMinFreeSpace bytes on the disk.
   bool HasEnoughSpaceFor(int64 num_bytes, const base::FilePath& path);
 
-  // Imports old format DB from |old_db_path| and deletes it.
-  // TODO(hashimoto): Remove this method and FileCacheMetadata at some point.
-  bool ImportOldDB(const base::FilePath& old_db_path);
-
   // Renames cache files from old "resource_id.md5" format to the new format.
   // TODO(hashimoto): Remove this method at some point.
   void RenameCacheFilesToNewFormat();
diff --git a/chrome/browser/chromeos/drive/file_cache_metadata.cc b/chrome/browser/chromeos/drive/file_cache_metadata.cc
deleted file mode 100644
index 3213512..0000000
--- a/chrome/browser/chromeos/drive/file_cache_metadata.cc
+++ /dev/null
@@ -1,191 +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/chromeos/drive/file_cache_metadata.h"
-
-#include "base/callback.h"
-#include "base/file_util.h"
-#include "base/files/file_enumerator.h"
-#include "base/metrics/histogram.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/thread_restrictions.h"
-#include "chrome/browser/chromeos/drive/drive.pb.h"
-#include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "third_party/leveldatabase/src/include/leveldb/db.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-enum DBOpenStatus {
-  DB_OPEN_SUCCESS,
-  DB_OPEN_FAILURE_CORRUPTION,
-  DB_OPEN_FAILURE_OTHER,
-  DB_OPEN_FAILURE_UNRECOVERABLE,
-  DB_OPEN_MAX_VALUE,
-};
-
-}  // namespace
-
-FileCacheMetadata::Iterator::Iterator(scoped_ptr<leveldb::Iterator> it)
-    : it_(it.Pass()) {
-  base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(it_);
-
-  it_->SeekToFirst();
-  AdvanceInternal();
-}
-
-FileCacheMetadata::Iterator::~Iterator() {
-  base::ThreadRestrictions::AssertIOAllowed();
-}
-
-bool FileCacheMetadata::Iterator::IsAtEnd() const {
-  base::ThreadRestrictions::AssertIOAllowed();
-  return !it_->Valid();
-}
-
-std::string FileCacheMetadata::Iterator::GetKey() const {
-  base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!IsAtEnd());
-  return it_->key().ToString();
-}
-
-const FileCacheEntry& FileCacheMetadata::Iterator::GetValue() const {
-  base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!IsAtEnd());
-  return entry_;
-}
-
-void FileCacheMetadata::Iterator::Advance() {
-  base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!IsAtEnd());
-
-  it_->Next();
-  AdvanceInternal();
-}
-
-bool FileCacheMetadata::Iterator::HasError() const {
-  base::ThreadRestrictions::AssertIOAllowed();
-  return !it_->status().ok();
-}
-
-void FileCacheMetadata::Iterator::AdvanceInternal() {
-  for (; it_->Valid(); it_->Next()) {
-    // Skip unparsable broken entries.
-    // TODO(hashimoto): Broken entries should be cleaned up at some point.
-    if (entry_.ParseFromArray(it_->value().data(), it_->value().size()))
-      break;
-  }
-}
-
-FileCacheMetadata::FileCacheMetadata(
-    base::SequencedTaskRunner* blocking_task_runner)
-    : blocking_task_runner_(blocking_task_runner) {
-  AssertOnSequencedWorkerPool();
-}
-
-FileCacheMetadata::~FileCacheMetadata() {
-  AssertOnSequencedWorkerPool();
-}
-
-FileCacheMetadata::InitializeResult FileCacheMetadata::Initialize(
-    const base::FilePath& db_path) {
-  AssertOnSequencedWorkerPool();
-
-  bool created = !base::PathExists(db_path);
-
-  leveldb::DB* level_db = NULL;
-  leveldb::Options options;
-  options.create_if_missing = true;
-  options.max_open_files = 0;  // Use minimum.
-  leveldb::Status db_status = leveldb::DB::Open(options, db_path.AsUTF8Unsafe(),
-                                                &level_db);
-
-  // Delete the db and scan the physical cache. This will fix a corrupt db, but
-  // perhaps not other causes of failed DB::Open.
-  DBOpenStatus uma_status = DB_OPEN_SUCCESS;
-  if (!db_status.ok()) {
-    LOG(WARNING) << "Cache db failed to open: " << db_status.ToString();
-    uma_status = db_status.IsCorruption() ?
-        DB_OPEN_FAILURE_CORRUPTION : DB_OPEN_FAILURE_OTHER;
-    const bool deleted = base::DeleteFile(db_path, true);
-    DCHECK(deleted);
-    db_status = leveldb::DB::Open(options, db_path.value(), &level_db);
-    if (!db_status.ok()) {
-      LOG(WARNING) << "Still failed to open: " << db_status.ToString();
-      UMA_HISTOGRAM_ENUMERATION("Drive.CacheDBOpenStatus",
-                                DB_OPEN_FAILURE_UNRECOVERABLE,
-                                DB_OPEN_MAX_VALUE);
-      return INITIALIZE_FAILED;
-    }
-
-    created = true;
-  }
-  UMA_HISTOGRAM_ENUMERATION("Drive.CacheDBOpenStatus", uma_status,
-                            DB_OPEN_MAX_VALUE);
-  DCHECK(level_db);
-  level_db_.reset(level_db);
-
-  return created ? INITIALIZE_CREATED : INITIALIZE_OPENED;
-}
-
-void FileCacheMetadata::AddOrUpdateCacheEntry(
-    const std::string& resource_id,
-    const FileCacheEntry& cache_entry) {
-  AssertOnSequencedWorkerPool();
-
-  DVLOG(1) << "AddOrUpdateCacheEntry, resource_id=" << resource_id;
-  std::string serialized;
-  const bool ok = cache_entry.SerializeToString(&serialized);
-  if (ok)
-    level_db_->Put(leveldb::WriteOptions(),
-                   leveldb::Slice(resource_id),
-                   leveldb::Slice(serialized));
-}
-
-void FileCacheMetadata::RemoveCacheEntry(const std::string& resource_id) {
-  AssertOnSequencedWorkerPool();
-
-  DVLOG(1) << "RemoveCacheEntry, resource_id=" << resource_id;
-  level_db_->Delete(leveldb::WriteOptions(), leveldb::Slice(resource_id));
-}
-
-bool FileCacheMetadata::GetCacheEntry(const std::string& resource_id,
-                                      FileCacheEntry* entry) {
-  DCHECK(entry);
-  AssertOnSequencedWorkerPool();
-
-  std::string serialized;
-  const leveldb::Status status = level_db_->Get(
-      leveldb::ReadOptions(),
-      leveldb::Slice(resource_id), &serialized);
-  if (!status.ok()) {
-    DVLOG(1) << "Can't find " << resource_id << " in cache db";
-    return false;
-  }
-
-  if (!entry->ParseFromString(serialized)) {
-    LOG(ERROR) << "Failed to parse " << serialized;
-    return false;
-  }
-  return true;
-}
-
-scoped_ptr<FileCacheMetadata::Iterator> FileCacheMetadata::GetIterator() {
-  AssertOnSequencedWorkerPool();
-
-  scoped_ptr<leveldb::Iterator> iter(level_db_->NewIterator(
-      leveldb::ReadOptions()));
-  return make_scoped_ptr(new Iterator(iter.Pass()));
-}
-
-void FileCacheMetadata::AssertOnSequencedWorkerPool() {
-  DCHECK(!blocking_task_runner_.get() ||
-         blocking_task_runner_->RunsTasksOnCurrentThread());
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_cache_metadata.h b/chrome/browser/chromeos/drive/file_cache_metadata.h
deleted file mode 100644
index 7baf395..0000000
--- a/chrome/browser/chromeos/drive/file_cache_metadata.h
+++ /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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_DRIVE_FILE_CACHE_METADATA_H_
-#define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_CACHE_METADATA_H_
-
-#include <string>
-#include <vector>
-
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/chromeos/drive/drive.pb.h"
-
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace leveldb {
-class DB;
-class Iterator;
-}  // namespace leveldb
-
-namespace drive {
-namespace internal {
-
-// FileCacheMetadata maintains metadata of FileCache's cached files.
-// This class only manages metadata. File operations are done by FileCache.
-// All member access including ctor and dtor must be made on the blocking pool.
-//
-// OBSOLETE: This class is maintained only for importing old data.
-// TODO(hashimoto): Remove this class at some point.
-class FileCacheMetadata {
- public:
-  // Result of Initialize().
-  enum InitializeResult {
-    INITIALIZE_FAILED,  // Could not open nor create DB.
-    INITIALIZE_OPENED,  // Opened an existing DB.
-    INITIALIZE_CREATED,  // Created a new DB.
-  };
-
-  // Object to iterate over entries stored in the cache metadata.
-  class Iterator {
-   public:
-    explicit Iterator(scoped_ptr<leveldb::Iterator> it);
-    ~Iterator();
-
-    // Returns true if this iterator cannot advance any more and does not point
-    // to a valid entry. GetKey(), GetValue() and Advance() should not be called
-    // in such cases.
-    bool IsAtEnd() const;
-
-    // Returns the key of the entry currently pointed by this object.
-    std::string GetKey() const;
-
-    // Returns the value of the entry currently pointed by this object.
-    const FileCacheEntry& GetValue() const;
-
-    // Advances to the next entry.
-    void Advance();
-
-    // Returns true if this object has encountered any error.
-    bool HasError() const;
-
-   private:
-    // Used to implement Advance().
-    void AdvanceInternal();
-
-    scoped_ptr<leveldb::Iterator> it_;
-    FileCacheEntry entry_;
-
-    DISALLOW_COPY_AND_ASSIGN(Iterator);
-  };
-
-  // Tests are allowed to pass NULL as |blocking_task_runner|.
-  explicit FileCacheMetadata(base::SequencedTaskRunner* blocking_task_runner);
-
-  ~FileCacheMetadata();
-
-  // Initialize the cache metadata store. Returns true on success.
-  InitializeResult Initialize(const base::FilePath& db_path);
-  // Adds a new cache entry corresponding to |resource_id| if it doesn't
-  // exist, otherwise update the existing entry.
-  void AddOrUpdateCacheEntry(const std::string& resource_id,
-                             const FileCacheEntry& cache_entry);
-
-  // Removes entry corresponding to |resource_id| from cache map.
-  void RemoveCacheEntry(const std::string& resource_id);
-
-  // Gets the cache entry for file corresponding to |resource_id| and returns
-  // true if entry exists in cache map.  Otherwise, returns false.
-  bool GetCacheEntry(const std::string& resource_id, FileCacheEntry* entry);
-
-  // Returns an object to iterate over entries.
-  scoped_ptr<Iterator> GetIterator();
-
- private:
-  // Checks whether the current thread is on the right sequenced worker pool
-  // with the right sequence ID. If not, DCHECK will fail.
-  void AssertOnSequencedWorkerPool();
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  scoped_ptr<leveldb::DB> level_db_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileCacheMetadata);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_FILE_CACHE_METADATA_H_
diff --git a/chrome/browser/chromeos/drive/file_cache_metadata_unittest.cc b/chrome/browser/chromeos/drive/file_cache_metadata_unittest.cc
deleted file mode 100644
index 7ceadf6..0000000
--- a/chrome/browser/chromeos/drive/file_cache_metadata_unittest.cc
+++ /dev/null
@@ -1,127 +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/chromeos/drive/file_cache_metadata.h"
-
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "chrome/browser/chromeos/drive/drive.pb.h"
-#include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "chrome/browser/chromeos/drive/test_util.h"
-#include "chrome/browser/google_apis/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-class FileCacheMetadataTest : public testing::Test {
- public:
-  virtual void SetUp() OVERRIDE {
-    // Create cache directories.
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    metadata_.reset(new FileCacheMetadata(NULL));
-  }
-
- protected:
-  base::ScopedTempDir temp_dir_;
-  scoped_ptr<FileCacheMetadata> metadata_;
-};
-
-// Test all the methods of FileCacheMetadata except for
-// RemoveTemporaryFiles.
-TEST_F(FileCacheMetadataTest, CacheTest) {
-  ASSERT_EQ(FileCacheMetadata::INITIALIZE_CREATED,
-            metadata_->Initialize(temp_dir_.path().AppendASCII("test.db")));
-
-  // Save an initial entry.
-  std::string test_resource_id("test_resource_id");
-  std::string test_md5("test_md5");
-  {
-    FileCacheEntry new_cache_entry;
-    new_cache_entry.set_md5(test_md5);
-    new_cache_entry.set_is_present(true);
-    metadata_->AddOrUpdateCacheEntry(test_resource_id, new_cache_entry);
-  }
-
-  // Test that the entry can be retrieved.
-  FileCacheEntry cache_entry;
-  ASSERT_TRUE(metadata_->GetCacheEntry(test_resource_id, &cache_entry));
-  EXPECT_EQ(test_md5, cache_entry.md5());
-  EXPECT_TRUE(cache_entry.is_present());
-
-  // resource_id doesn't exist.
-  EXPECT_FALSE(metadata_->GetCacheEntry("not_found_resource_id", &cache_entry));
-
-  // Update all attributes.
-  test_md5 = "test_md5_2";
-  {
-    FileCacheEntry updated_cache_entry;
-    updated_cache_entry.set_md5(test_md5);
-    updated_cache_entry.set_is_pinned(true);
-    metadata_->AddOrUpdateCacheEntry(test_resource_id, updated_cache_entry);
-  }
-
-  // Make sure the values took.
-  ASSERT_TRUE(metadata_->GetCacheEntry(test_resource_id, &cache_entry));
-  EXPECT_EQ(test_md5, cache_entry.md5());
-  EXPECT_TRUE(cache_entry.is_pinned());
-
-  // Test dirty cache.
-  test_md5 = "test_md5_3";
-  {
-    FileCacheEntry new_cache_entry;
-    new_cache_entry.set_md5(test_md5);
-    new_cache_entry.set_is_dirty(true);
-    metadata_->AddOrUpdateCacheEntry(test_resource_id, new_cache_entry);
-  }
-
-  // Make sure the values took.
-  ASSERT_TRUE(metadata_->GetCacheEntry(test_resource_id, &cache_entry));
-  EXPECT_EQ(test_md5, cache_entry.md5());
-  EXPECT_TRUE(cache_entry.is_dirty());
-
-  // Remove the entry.
-  metadata_->RemoveCacheEntry(test_resource_id);
-  EXPECT_FALSE(metadata_->GetCacheEntry(test_resource_id, &cache_entry));
-
-  // Add another one.
-  test_resource_id = "test_resource_id_2";
-  test_md5 = "test_md5_4";
-  {
-    FileCacheEntry new_cache_entry;
-    new_cache_entry.set_md5(test_md5);
-    new_cache_entry.set_is_present(true);
-    metadata_->AddOrUpdateCacheEntry(test_resource_id, new_cache_entry);
-  }
-
-  // Make sure the values took.
-  ASSERT_TRUE(metadata_->GetCacheEntry(test_resource_id, &cache_entry));
-  EXPECT_EQ(test_md5, cache_entry.md5());
-  EXPECT_TRUE(cache_entry.is_present());
-}
-
-TEST_F(FileCacheMetadataTest, Initialize) {
-  const base::FilePath db_path = temp_dir_.path().AppendASCII("test.db");
-
-  // Try to open a bogus file.
-  ASSERT_TRUE(
-      google_apis::test_util::WriteStringToFile(db_path, "Hello world"));
-  ASSERT_EQ(FileCacheMetadata::INITIALIZE_CREATED,
-            metadata_->Initialize(db_path));
-
-  // Open an existing DB.
-  metadata_.reset(new FileCacheMetadata(NULL));
-  EXPECT_EQ(FileCacheMetadata::INITIALIZE_OPENED,
-            metadata_->Initialize(db_path));
-
-  // Try to open a nonexistent path.
-  base::FilePath non_existent_path(FILE_PATH_LITERAL(
-      "/somewhere/nonexistent/test.db"));
-  metadata_.reset(new FileCacheMetadata(NULL));
-  EXPECT_EQ(FileCacheMetadata::INITIALIZE_FAILED,
-            metadata_->Initialize(non_existent_path));
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_cache_unittest.cc b/chrome/browser/chromeos/drive/file_cache_unittest.cc
index 3443506..ecd79a1 100644
--- a/chrome/browser/chromeos/drive/file_cache_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_cache_unittest.cc
@@ -15,7 +15,6 @@
 #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"
-#include "chrome/browser/chromeos/drive/file_cache_metadata.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 #include "chrome/browser/chromeos/drive/test_util.h"
@@ -826,10 +825,6 @@
     ASSERT_TRUE(cache_->Initialize());
   }
 
-  static bool ImportOldDB(FileCache* cache, const base::FilePath& old_db_path) {
-    return cache->ImportOldDB(old_db_path);
-  }
-
   static void RenameCacheFilesToNewFormat(FileCache* cache) {
     cache->RenameCacheFilesToNewFormat();
   }
@@ -855,12 +850,6 @@
       temp_dir_.path().Append(util::kMetadataDirectory);
   ASSERT_TRUE(base::DeleteFile(metadata_directory, true /* recursive */));
 
-  // Put an empty file with the same name as old DB.
-  // This file cannot be opened by ImportOldDB() and will be dismissed.
-  ASSERT_TRUE(file_util::CreateDirectory(metadata_directory));
-  ASSERT_TRUE(google_apis::test_util::WriteStringToFile(
-      metadata_directory.Append(FileCache::kOldCacheMetadataDBName), ""));
-
   // Create a new cache and initialize it.
   metadata_storage_.reset(new ResourceMetadataStorage(
       metadata_directory, base::MessageLoopProxy::current().get()));
@@ -919,42 +908,6 @@
   EXPECT_FALSE(cache_->FreeDiskSpaceIfNeededFor(kNeededBytes));
 }
 
-TEST_F(FileCacheTest, ImportOldDB) {
-  const base::FilePath old_db_path = temp_dir_.path().AppendASCII("old_db.db");
-
-  const std::string key1 = "key1";
-  const std::string md5_1 = "md5_1";
-  const std::string key2 = "key2";
-  const std::string md5_2 = "md5_2";
-
-  // Set up data to be imported.
-  {
-    FileCacheMetadata old_metadata(NULL);
-    ASSERT_TRUE(old_metadata.Initialize(old_db_path));
-
-    FileCacheEntry entry;
-    entry.set_md5(md5_1);
-    old_metadata.AddOrUpdateCacheEntry(key1, entry);
-
-    entry.set_md5(md5_2);
-    old_metadata.AddOrUpdateCacheEntry(key2, entry);
-  }
-  EXPECT_TRUE(base::PathExists(old_db_path));
-
-  // Do import.
-  EXPECT_TRUE(ImportOldDB(cache_.get(), old_db_path));
-
-  // Old DB should be removed.
-  EXPECT_FALSE(base::PathExists(old_db_path));
-
-  // Data is imported correctly.
-  FileCacheEntry entry;
-  EXPECT_TRUE(cache_->GetCacheEntry(key1, &entry));
-  EXPECT_EQ(md5_1, entry.md5());
-  EXPECT_TRUE(cache_->GetCacheEntry(key2, &entry));
-  EXPECT_EQ(md5_2, entry.md5());
-}
-
 TEST_F(FileCacheTest, RenameCacheFilesToNewFormat) {
   const base::FilePath file_directory =
       temp_dir_.path().Append(util::kCacheFileDirectory);
diff --git a/chrome/browser/chromeos/drive/file_system.cc b/chrome/browser/chromeos/drive/file_system.cc
index b6f4e93..2d527f9 100644
--- a/chrome/browser/chromeos/drive/file_system.cc
+++ b/chrome/browser/chromeos/drive/file_system.cc
@@ -171,7 +171,10 @@
                                            resource_metadata_,
                                            cache_));
   move_operation_.reset(
-      new file_system::MoveOperation(observer, scheduler_, resource_metadata_));
+      new file_system::MoveOperation(blocking_task_runner_.get(),
+                                     observer,
+                                     scheduler_,
+                                     resource_metadata_));
   open_file_operation_.reset(
       new file_system::OpenFileOperation(blocking_task_runner_.get(),
                                          observer,
@@ -239,7 +242,7 @@
   SetupChangeListLoader();
 
   change_list_loader_->LoadIfNeeded(
-      DirectoryFetchInfo(),
+      internal::DirectoryFetchInfo(),
       base::Bind(&FileSystem::OnUpdateChecked,
                  weak_ptr_factory_.GetWeakPtr()));
 }
@@ -286,17 +289,6 @@
   observers_.RemoveObserver(observer);
 }
 
-void FileSystem::TransferFileFromRemoteToLocal(
-    const base::FilePath& remote_src_file_path,
-    const base::FilePath& local_dest_file_path,
-    const FileOperationCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-  copy_operation_->TransferFileFromRemoteToLocal(remote_src_file_path,
-                                                 local_dest_file_path,
-                                                 callback);
-}
-
 void FileSystem::TransferFileFromLocalToRemote(
     const base::FilePath& local_src_file_path,
     const base::FilePath& remote_dest_file_path,
@@ -341,7 +333,7 @@
   DCHECK(!callback.is_null());
 
   change_list_loader_->LoadIfNeeded(
-      DirectoryFetchInfo(),
+      internal::DirectoryFetchInfo(),
       base::Bind(&FileSystem::CreateDirectoryAfterLoad,
                  weak_ptr_factory_.GetWeakPtr(),
                  directory_path, is_exclusive, is_recursive, callback));
@@ -367,10 +359,12 @@
 
 void FileSystem::CreateFile(const base::FilePath& file_path,
                             bool is_exclusive,
+                            const std::string& mime_type,
                             const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
-  create_file_operation_->CreateFile(file_path, is_exclusive, callback);
+  create_file_operation_->CreateFile(
+      file_path, is_exclusive, mime_type, callback);
 }
 
 void FileSystem::TouchFile(const base::FilePath& file_path,
@@ -641,7 +635,7 @@
     // If we don't know about the directory, or it is the "drive/other"
     // directory that has to gather all orphan entries, start loading full
     // resource list.
-    change_list_loader_->LoadIfNeeded(DirectoryFetchInfo(), callback);
+    change_list_loader_->LoadIfNeeded(internal::DirectoryFetchInfo(), callback);
     return;
   }
 
@@ -652,7 +646,7 @@
 
   // Pass the directory fetch info so we can fetch the contents of the
   // directory before loading change lists.
-  DirectoryFetchInfo directory_fetch_info(
+  internal::DirectoryFetchInfo directory_fetch_info(
       entry->resource_id(),
       entry->directory_specific_info().changestamp());
   change_list_loader_->LoadIfNeeded(directory_fetch_info, callback);
@@ -954,11 +948,12 @@
 
 void FileSystem::OpenFile(const base::FilePath& file_path,
                           OpenMode open_mode,
+                          const std::string& mime_type,
                           const OpenFileCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  open_file_operation_->OpenFile(file_path, open_mode, callback);
+  open_file_operation_->OpenFile(file_path, open_mode, mime_type, callback);
 }
 
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system.h b/chrome/browser/chromeos/drive/file_system.h
index dacc522..bc20e69 100644
--- a/chrome/browser/chromeos/drive/file_system.h
+++ b/chrome/browser/chromeos/drive/file_system.h
@@ -83,16 +83,13 @@
                               int options,
                               int at_most_num_matches,
                               const SearchMetadataCallback& callback) OVERRIDE;
-  virtual void TransferFileFromRemoteToLocal(
-      const base::FilePath& remote_src_file_path,
-      const base::FilePath& local_dest_file_path,
-      const FileOperationCallback& callback) OVERRIDE;
   virtual void TransferFileFromLocalToRemote(
       const base::FilePath& local_src_file_path,
       const base::FilePath& remote_dest_file_path,
       const FileOperationCallback& callback) OVERRIDE;
   virtual void OpenFile(const base::FilePath& file_path,
                         OpenMode open_mode,
+                        const std::string& mime_type,
                         const OpenFileCallback& callback) OVERRIDE;
   virtual void Copy(const base::FilePath& src_file_path,
                     const base::FilePath& dest_file_path,
@@ -109,6 +106,7 @@
                                const FileOperationCallback& callback) OVERRIDE;
   virtual void CreateFile(const base::FilePath& file_path,
                           bool is_exclusive,
+                          const std::string& mime_type,
                           const FileOperationCallback& callback) OVERRIDE;
   virtual void TouchFile(const base::FilePath& file_path,
                          const base::Time& last_access_time,
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation.cc b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
index a38adb5..62e8380 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation.cc
@@ -27,26 +27,38 @@
 
 namespace {
 
-// Copies a file from |src_file_path| to |dest_file_path| on the local
-// file system using base::CopyFile.
-// Returns FILE_ERROR_OK on success or FILE_ERROR_FAILED otherwise.
-FileError CopyLocalFileOnBlockingPool(
-    const base::FilePath& src_file_path,
-    const base::FilePath& dest_file_path) {
-  return base::CopyFile(src_file_path, dest_file_path) ?
-      FILE_ERROR_OK : FILE_ERROR_FAILED;
+int64 GetFileSize(const base::FilePath& file_path) {
+  int64 file_size;
+  if (!file_util::GetFileSize(file_path, &file_size))
+    return -1;
+  return file_size;
 }
 
-// Stores a file to the cache and mark it dirty.
-FileError StoreAndMarkDirty(internal::FileCache* cache,
-                            const std::string& resource_id,
-                            const std::string& md5,
-                            const base::FilePath& local_file_path) {
-  FileError error = cache->Store(resource_id, md5, local_file_path,
-                                 internal::FileCache::FILE_OPERATION_COPY);
+// Stores the file at |local_file_path| to the cache as a content of entry at
+// |remote_dest_path|, and marks it dirty.
+FileError UpdateLocalStateForScheduleTransfer(
+    internal::ResourceMetadata* metadata,
+    internal::FileCache* cache,
+    const base::FilePath& local_src_path,
+    const base::FilePath& remote_dest_path,
+    std::string* resource_id) {
+  ResourceEntry entry;
+  FileError error = metadata->GetResourceEntryByPath(remote_dest_path, &entry);
   if (error != FILE_ERROR_OK)
     return error;
-  return cache->MarkDirty(resource_id);
+
+  error = cache->Store(
+      entry.resource_id(), entry.file_specific_info().md5(), local_src_path,
+      internal::FileCache::FILE_OPERATION_COPY);
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  error = cache->MarkDirty(entry.resource_id());
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  *resource_id = entry.resource_id();
+  return FILE_ERROR_OK;
 }
 
 // Gets the file size of the |local_path|, and the ResourceEntry for the parent
@@ -55,17 +67,23 @@
     internal::ResourceMetadata* metadata,
     const base::FilePath& local_path,
     const base::FilePath& remote_path,
-    int64* local_file_size,
     ResourceEntry* parent_entry) {
   DCHECK(metadata);
-  DCHECK(local_file_size);
   DCHECK(parent_entry);
 
-  if (!file_util::GetFileSize(local_path, local_file_size))
-      return FILE_ERROR_NOT_FOUND;
   return metadata->GetResourceEntryByPath(remote_path.DirName(), parent_entry);
 }
 
+FileError AddEntryToLocalMetadata(internal::ResourceMetadata* metadata,
+                                  const ResourceEntry& entry) {
+  FileError error = metadata->AddEntry(entry);
+  // Depending on timing, the metadata may have inserted via change list
+  // already. So, FILE_ERROR_EXISTS is not an error.
+  if (error == FILE_ERROR_EXISTS)
+    error = FILE_ERROR_OK;
+  return error;
+}
+
 }  // namespace
 
 CopyOperation::CopyOperation(base::SequencedTaskRunner* blocking_task_runner,
@@ -92,7 +110,10 @@
                                               metadata,
                                               cache,
                                               temporary_file_directory)),
-    move_operation_(new MoveOperation(observer, scheduler, metadata)),
+    move_operation_(new MoveOperation(blocking_task_runner,
+                                      observer,
+                                      scheduler,
+                                      metadata)),
     weak_ptr_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
@@ -116,49 +137,6 @@
                  callback));
 }
 
-void CopyOperation::TransferFileFromRemoteToLocal(
-    const base::FilePath& remote_src_file_path,
-    const base::FilePath& local_dest_file_path,
-    const FileOperationCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-
-  download_operation_->EnsureFileDownloadedByPath(
-      remote_src_file_path,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      base::Bind(&CopyOperation::OnGetFileCompleteForTransferFile,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 local_dest_file_path,
-                 callback));
-}
-
-void CopyOperation::OnGetFileCompleteForTransferFile(
-    const base::FilePath& local_dest_file_path,
-    const FileOperationCallback& callback,
-    FileError error,
-    const base::FilePath& local_file_path,
-    scoped_ptr<ResourceEntry> entry) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  // GetFileByPath downloads the file from Drive to a local cache, which is then
-  // copied to the actual destination path on the local file system using
-  // CopyLocalFileOnBlockingPool.
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(
-          &CopyLocalFileOnBlockingPool, local_file_path, local_dest_file_path),
-      callback);
-}
-
 void CopyOperation::TransferFileFromLocalToRemote(
     const base::FilePath& local_src_file_path,
     const base::FilePath& remote_dest_file_path,
@@ -166,7 +144,6 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  int64* local_file_size = new int64(-1);
   ResourceEntry* parent_entry = new ResourceEntry;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
@@ -175,7 +152,6 @@
                  metadata_,
                  local_src_file_path,
                  remote_dest_file_path,
-                 local_file_size,
                  parent_entry),
       base::Bind(
           &CopyOperation::TransferFileFromLocalToRemoteAfterPrepare,
@@ -183,100 +159,133 @@
           local_src_file_path,
           remote_dest_file_path,
           callback,
-          base::Owned(local_file_size),
           base::Owned(parent_entry)));
 }
 
 void CopyOperation::ScheduleTransferRegularFile(
-    const base::FilePath& local_file_path,
-    const base::FilePath& remote_dest_file_path,
+    const base::FilePath& local_src_path,
+    const base::FilePath& remote_dest_path,
     const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  const bool fail_if_file_already_exists = true;
-  create_file_operation_->CreateFile(
-      remote_dest_file_path,
-      fail_if_file_already_exists,
-      base::Bind(&CopyOperation::ScheduleTransferRegularFileAfterCreate,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 local_file_path,
-                 remote_dest_file_path,
-                 callback));
-}
-
-void CopyOperation::ScheduleTransferRegularFileAfterCreate(
-    const base::FilePath& local_file_path,
-    const base::FilePath& remote_dest_file_path,
-    const FileOperationCallback& callback,
-    FileError error) {
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  metadata_->GetResourceEntryByPathOnUIThread(
-      remote_dest_file_path,
-      base::Bind(
-          &CopyOperation::ScheduleTransferRegularFileAfterGetResourceEntry,
-          weak_ptr_factory_.GetWeakPtr(),
-          local_file_path,
-          callback));
-}
-
-void CopyOperation::ScheduleTransferRegularFileAfterGetResourceEntry(
-    const base::FilePath& local_file_path,
-    const FileOperationCallback& callback,
-    FileError error,
-    scoped_ptr<ResourceEntry> entry) {
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  ResourceEntry* entry_ptr = entry.get();
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
-      base::Bind(&StoreAndMarkDirty,
-                 cache_,
-                 entry_ptr->resource_id(),
-                 entry_ptr->file_specific_info().md5(),
-                 local_file_path),
-      base::Bind(&CopyOperation::ScheduleTransferRegularFileAfterStore,
+      base::Bind(&GetFileSize, local_src_path),
+      base::Bind(&CopyOperation::ScheduleTransferRegularFileAfterGetFileSize,
                  weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(&entry),
-                 callback));
+                 local_src_path, remote_dest_path, callback));
 }
 
-void CopyOperation::ScheduleTransferRegularFileAfterStore(
-    scoped_ptr<ResourceEntry> entry,
+void CopyOperation::ScheduleTransferRegularFileAfterGetFileSize(
+    const base::FilePath& local_src_path,
+    const base::FilePath& remote_dest_path,
+    const FileOperationCallback& callback,
+    int64 local_file_size) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  if (local_file_size < 0) {
+    callback.Run(FILE_ERROR_NOT_FOUND);
+    return;
+  }
+
+  // For regular files, check the server-side quota whether sufficient space
+  // is available for the file to be uploaded.
+  scheduler_->GetAboutResource(
+      base::Bind(
+          &CopyOperation::ScheduleTransferRegularFileAfterGetAboutResource,
+          weak_ptr_factory_.GetWeakPtr(),
+          local_src_path, remote_dest_path, callback, local_file_size));
+}
+
+void CopyOperation::ScheduleTransferRegularFileAfterGetAboutResource(
+    const base::FilePath& local_src_path,
+    const base::FilePath& remote_dest_path,
+    const FileOperationCallback& callback,
+    int64 local_file_size,
+    google_apis::GDataErrorCode status,
+    scoped_ptr<google_apis::AboutResource> about_resource) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  FileError error = GDataToFileError(status);
+  if (error != FILE_ERROR_OK) {
+    callback.Run(error);
+    return;
+  }
+
+  DCHECK(about_resource);
+  const int64 space =
+      about_resource->quota_bytes_total() - about_resource->quota_bytes_used();
+  if (space < local_file_size) {
+    callback.Run(FILE_ERROR_NO_SERVER_SPACE);
+    return;
+  }
+
+  create_file_operation_->CreateFile(
+      remote_dest_path,
+      true,  // Exclusive (i.e. fail if a file already exists).
+      std::string(),  // no specific mime type; CreateFile should guess it.
+      base::Bind(&CopyOperation::ScheduleTransferRegularFileAfterCreate,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 local_src_path, remote_dest_path, callback));
+}
+
+void CopyOperation::ScheduleTransferRegularFileAfterCreate(
+    const base::FilePath& local_src_path,
+    const base::FilePath& remote_dest_path,
     const FileOperationCallback& callback,
     FileError error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  if (error != FILE_ERROR_OK) {
+    callback.Run(error);
+    return;
+  }
+
+  std::string* resource_id = new std::string;
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(
+          &UpdateLocalStateForScheduleTransfer,
+          metadata_, cache_, local_src_path, remote_dest_path, resource_id),
+      base::Bind(
+          &CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState,
+          weak_ptr_factory_.GetWeakPtr(), callback, base::Owned(resource_id)));
+}
+
+void CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState(
+    const FileOperationCallback& callback,
+    std::string* resource_id,
+    FileError error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
   if (error == FILE_ERROR_OK)
-    observer_->OnCacheFileUploadNeededByOperation(entry->resource_id());
+    observer_->OnCacheFileUploadNeededByOperation(*resource_id);
   callback.Run(error);
 }
 
 void CopyOperation::CopyHostedDocumentToDirectory(
-    const base::FilePath& dir_path,
+    const base::FilePath& dest_path,
     const std::string& resource_id,
-    const base::FilePath::StringType& new_name,
     const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   scheduler_->CopyHostedDocument(
       resource_id,
-      base::FilePath(new_name).AsUTF8Unsafe(),
+      dest_path.BaseName().AsUTF8Unsafe(),
       base::Bind(&CopyOperation::OnCopyHostedDocumentCompleted,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 dir_path,
-                 callback));
+                 weak_ptr_factory_.GetWeakPtr(), dest_path, callback));
 }
 
 void CopyOperation::OnCopyHostedDocumentCompleted(
-    const base::FilePath& dir_path,
+    const base::FilePath& dest_path,
     const FileOperationCallback& callback,
     google_apis::GDataErrorCode status,
     scoped_ptr<google_apis::ResourceEntry> resource_entry) {
@@ -302,22 +311,25 @@
   metadata_->AddEntryOnUIThread(
       entry,
       base::Bind(&CopyOperation::MoveEntryFromRootDirectory,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 dir_path,
-                 callback));
+                 weak_ptr_factory_.GetWeakPtr(), dest_path, callback));
 }
 
 void CopyOperation::MoveEntryFromRootDirectory(
-    const base::FilePath& directory_path,
+    const base::FilePath& dest_path,
     const FileOperationCallback& callback,
     FileError error,
     const base::FilePath& file_path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
+  // Depending on timing, the metadata may have inserted via change list
+  // already. So, FILE_ERROR_EXISTS is not an error.
+  if (error == FILE_ERROR_EXISTS)
+    error = FILE_ERROR_OK;
+
   // Return if there is an error or |dir_path| is the root directory.
   if (error != FILE_ERROR_OK ||
-      directory_path == util::GetDriveMyDriveRootPath()) {
+      dest_path.DirName() == util::GetDriveMyDriveRootPath()) {
     callback.Run(error);
     return;
   }
@@ -325,9 +337,7 @@
   DCHECK_EQ(util::GetDriveMyDriveRootPath().value(),
             file_path.DirName().value()) << file_path.value();
 
-  move_operation_->Move(file_path,
-                        directory_path.Append(file_path.BaseName()),
-                        callback);
+  move_operation_->Move(file_path, dest_path, callback);
 }
 
 void CopyOperation::CopyAfterGetResourceEntryPair(
@@ -381,11 +391,10 @@
 
   if (src_file_proto->file_specific_info().is_hosted_document()) {
     CopyHostedDocumentToDirectory(
-        dest_file_path.DirName(),
-        src_file_proto->resource_id(),
         // Drop the document extension, which should not be in the title.
         // TODO(yoshiki): Remove this code with crbug.com/223304.
-        dest_file_path.BaseName().RemoveExtension().value(),
+        dest_file_path.RemoveExtension(),
+        src_file_proto->resource_id(),
         callback);
     return;
   }
@@ -427,14 +436,12 @@
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::AddEntry,
-                 base::Unretained(metadata_),
-                 entry),
+      base::Bind(&AddEntryToLocalMetadata, metadata_, entry),
       callback);
 }
 
 void CopyOperation::OnGetFileCompleteForCopy(
-    const base::FilePath& remote_dest_file_path,
+    const base::FilePath& remote_dest_path,
     const FileOperationCallback& callback,
     FileError error,
     const base::FilePath& local_file_path,
@@ -449,20 +456,18 @@
 
   // This callback is only triggered for a regular file via Copy().
   DCHECK(entry && !entry->file_specific_info().is_hosted_document());
-  ScheduleTransferRegularFile(local_file_path, remote_dest_file_path, callback);
+  ScheduleTransferRegularFile(local_file_path, remote_dest_path, callback);
 }
 
 void CopyOperation::TransferFileFromLocalToRemoteAfterPrepare(
     const base::FilePath& local_src_file_path,
     const base::FilePath& remote_dest_file_path,
     const FileOperationCallback& callback,
-    int64* local_file_size,
     ResourceEntry* parent_entry,
     FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
   DCHECK(parent_entry);
-  DCHECK(local_file_size);
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error);
@@ -476,6 +481,8 @@
   }
 
   if (util::HasGDocFileExtension(local_src_file_path)) {
+    // TODO(hidehiko): This should be a part of
+    // PrepareTransferFileFromLocalToRemote.
     base::PostTaskAndReplyWithResult(
         blocking_task_runner_.get(),
         FROM_HERE,
@@ -486,45 +493,11 @@
                    remote_dest_file_path,
                    callback));
   } else {
-    // For regular files, check the server-side quota whether sufficient space
-    // is available for the file to be uploaded.
-    scheduler_->GetAboutResource(
-        base::Bind(&CopyOperation::TransferFileFromLocalToRemoteAfterGetQuota,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   local_src_file_path,
-                   remote_dest_file_path,
-                   callback,
-                   *local_file_size));
+    ScheduleTransferRegularFile(
+        local_src_file_path, remote_dest_file_path, callback);
   }
 }
 
-void CopyOperation::TransferFileFromLocalToRemoteAfterGetQuota(
-    const base::FilePath& local_src_file_path,
-    const base::FilePath& remote_dest_file_path,
-    const FileOperationCallback& callback,
-    int64 local_file_size,
-    google_apis::GDataErrorCode status,
-    scoped_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK(!callback.is_null());
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  DCHECK(about_resource);
-  const int64 space =
-      about_resource->quota_bytes_total() - about_resource->quota_bytes_used();
-  if (space < local_file_size) {
-    callback.Run(FILE_ERROR_NO_SERVER_SPACE);
-    return;
-  }
-
-  ScheduleTransferRegularFile(local_src_file_path, remote_dest_file_path,
-                              callback);
-}
-
 void CopyOperation::TransferFileForResourceId(
     const base::FilePath& local_file_path,
     const base::FilePath& remote_dest_file_path,
@@ -535,8 +508,8 @@
 
   if (resource_id.empty()) {
     // If |resource_id| is empty, upload the local file as a regular file.
-    ScheduleTransferRegularFile(local_file_path, remote_dest_file_path,
-                                callback);
+    ScheduleTransferRegularFile(
+        local_file_path, remote_dest_file_path, callback);
     return;
   }
 
@@ -544,15 +517,16 @@
   const std::string canonicalized_resource_id =
       drive_service_->CanonicalizeResourceId(resource_id);
 
+  // TODO(hidehiko): Use CopyResource for Drive API v2.
+
   // Otherwise, copy the document on the server side and add the new copy
   // to the destination directory (collection).
   CopyHostedDocumentToDirectory(
-      remote_dest_file_path.DirName(),
-      canonicalized_resource_id,
       // Drop the document extension, which should not be
       // in the document title.
       // TODO(yoshiki): Remove this code with crbug.com/223304.
-      remote_dest_file_path.BaseName().RemoveExtension().value(),
+      remote_dest_file_path.RemoveExtension(),
+      canonicalized_resource_id,
       callback);
 }
 
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation.h b/chrome/browser/chromeos/drive/file_system/copy_operation.h
index 41be0cf..43513c4 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation.h
@@ -60,15 +60,6 @@
             const base::FilePath& dest_file_path,
             const FileOperationCallback& callback);
 
-  // Initiates transfer of |remote_src_file_path| to |local_dest_file_path|.
-  // |remote_src_file_path| is the virtual source path on the Drive file system.
-  // |local_dest_file_path| is the destination path on the local file system.
-  //
-  // |callback| must not be null.
-  void TransferFileFromRemoteToLocal(const base::FilePath& remote_src_file_path,
-                                     const base::FilePath& local_dest_file_path,
-                                     const FileOperationCallback& callback);
-
   // Initiates transfer of |local_src_file_path| to |remote_dest_file_path|.
   // |local_src_file_path| must be a file from the local file system.
   // |remote_dest_file_path| is the virtual destination path within Drive file
@@ -81,55 +72,61 @@
       const FileOperationCallback& callback);
 
  private:
-  // Stores |local_file_path| in cache and mark as dirty so that SyncClient will
-  // upload the content to |remote_dest_file_path|.
-  void ScheduleTransferRegularFile(const base::FilePath& local_file_path,
-                                   const base::FilePath& remote_dest_file_path,
+  // Creates an empty file on the server at |remote_dest_path| to ensure
+  // the location, stores a file at |local_file_path| in cache and marks it
+  // dirty, so that SyncClient will upload the data later.
+  void ScheduleTransferRegularFile(const base::FilePath& local_src_path,
+                                   const base::FilePath& remote_dest_path,
                                    const FileOperationCallback& callback);
+
+  // Part of ScheduleTransferRegularFile(). Called after GetFileSize() is
+  // completed.
+  void ScheduleTransferRegularFileAfterGetFileSize(
+      const base::FilePath& local_src_path,
+      const base::FilePath& remote_dest_path,
+      const FileOperationCallback& callback,
+      int64 local_file_size);
+
+  // Part of ScheduleTransferRegularFile(). Called after GetAboutResource()
+  // is completed.
+  void ScheduleTransferRegularFileAfterGetAboutResource(
+      const base::FilePath& local_src_path,
+      const base::FilePath& remote_dest_path,
+      const FileOperationCallback& callback,
+      int64 local_file_size,
+      google_apis::GDataErrorCode status,
+      scoped_ptr<google_apis::AboutResource> about_resource);
+
+  // Part of ScheduleTransferRegularFile(). Called after file creation.
   void ScheduleTransferRegularFileAfterCreate(
-      const base::FilePath& local_file_path,
-      const base::FilePath& remote_dest_file_path,
-      const FileOperationCallback& callback,
-      FileError error);
-  void ScheduleTransferRegularFileAfterGetResourceEntry(
-      const base::FilePath& local_file_path,
-      const FileOperationCallback& callback,
-      FileError error,
-      scoped_ptr<ResourceEntry> entry);
-  void ScheduleTransferRegularFileAfterStore(
-      scoped_ptr<ResourceEntry> entry,
+      const base::FilePath& local_src_path,
+      const base::FilePath& remote_dest_path,
       const FileOperationCallback& callback,
       FileError error);
 
-  // Invoked upon completion of GetFileByPath initiated by
-  // TransferFileFromRemoteToLocal. If GetFileByPath reports no error, calls
-  // CopyLocalFileOnBlockingPool to copy |local_file_path| to
-  // |local_dest_file_path|.
-  void OnGetFileCompleteForTransferFile(
-      const base::FilePath& local_dest_file_path,
+  // Part of ScheduleTransferRegularFile(). Called after updating local state
+  // is completed.
+  void ScheduleTransferRegularFileAfterUpdateLocalState(
       const FileOperationCallback& callback,
-      FileError error,
-      const base::FilePath& local_file_path,
-      scoped_ptr<ResourceEntry> entry);
+      std::string* resource_id,
+      FileError error);
 
-  // Copies a hosted document with |resource_id| to the directory at |dir_path|
-  // and names the copied document as |new_name|.
-  void CopyHostedDocumentToDirectory(const base::FilePath& dir_path,
+  // Copies a hosted document with |resource_id| to |dest_path|
+  void CopyHostedDocumentToDirectory(const base::FilePath& dest_path,
                                      const std::string& resource_id,
-                                     const base::FilePath::StringType& new_name,
                                      const FileOperationCallback& callback);
 
   // Callback for handling document copy attempt.
   void OnCopyHostedDocumentCompleted(
-      const base::FilePath& dir_path,
+      const base::FilePath& dest_path,
       const FileOperationCallback& callback,
       google_apis::GDataErrorCode status,
       scoped_ptr<google_apis::ResourceEntry> resource_entry);
 
   // Moves a file or directory at |file_path| in the root directory to
-  // another directory at |dir_path|. This function does nothing if
-  // |dir_path| points to the root directory.
-  void MoveEntryFromRootDirectory(const base::FilePath& directory_path,
+  // |dest_path|. This function does nothing if |dest_path| points to a
+  // resource directly under the root directory.
+  void MoveEntryFromRootDirectory(const base::FilePath& dest_path,
                                   const FileOperationCallback& callback,
                                   FileError error,
                                   const base::FilePath& file_path);
@@ -155,13 +152,12 @@
                                 const base::FilePath& local_file_path,
                                 scoped_ptr<ResourceEntry> entry);
 
-  // Part of TransferFileFromLocalToRemote(). Called after |parent_entry| and
-  // |local_file_size| are retrieved in the blocking pool.
+  // Part of TransferFileFromLocalToRemote(). Called after |parent_entry| is
+  // retrieved in the blocking pool.
   void TransferFileFromLocalToRemoteAfterPrepare(
       const base::FilePath& local_src_file_path,
       const base::FilePath& remote_dest_file_path,
       const FileOperationCallback& callback,
-      int64* local_file_size,
       ResourceEntry* parent_entry,
       FileError error);
 
@@ -171,7 +167,6 @@
       const base::FilePath& local_src_file_path,
       const base::FilePath& remote_dest_file_path,
       const FileOperationCallback& callback,
-      int64 local_file_size,
       google_apis::GDataErrorCode status,
       scoped_ptr<google_apis::AboutResource> about_resource);
 
diff --git a/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
index 433c57d..cefdeba 100644
--- a/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/copy_operation_unittest.cc
@@ -144,66 +144,6 @@
       remote_dest_path.DirName()));
 }
 
-TEST_F(CopyOperationTest, TransferFileFromRemoteToLocal_RegularFile) {
-  base::FilePath remote_src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath local_dest_path = temp_dir().AppendASCII("local_copy.txt");
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_src_path, &entry));
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->TransferFileFromRemoteToLocal(
-      remote_src_path,
-      local_dest_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // The content is "x"s of the file size.
-  base::FilePath cache_path;
-  cache()->GetFileOnUIThread(entry.resource_id(),
-                             google_apis::test_util::CreateCopyResultCallback(
-                                 &error, &cache_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  const std::string kExpectedContent = "This is some test content.";
-  std::string cache_file_data;
-  EXPECT_TRUE(file_util::ReadFileToString(cache_path, &cache_file_data));
-  EXPECT_EQ(kExpectedContent, cache_file_data);
-
-  std::string local_dest_file_data;
-  EXPECT_TRUE(file_util::ReadFileToString(local_dest_path,
-                                          &local_dest_file_data));
-  EXPECT_EQ(kExpectedContent, local_dest_file_data);
-
-  // The transfered file is cached and the change of "offline available"
-  // attribute is notified.
-  EXPECT_EQ(1U, observer()->get_changed_paths().size());
-  EXPECT_TRUE(observer()->get_changed_paths().count(remote_src_path.DirName()));
-}
-
-TEST_F(CopyOperationTest, TransferFileFromRemoteToLocal_HostedDocument) {
-  base::FilePath local_dest_path = temp_dir().AppendASCII("local_copy.txt");
-  base::FilePath remote_src_path(
-      FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->TransferFileFromRemoteToLocal(
-      remote_src_path,
-      local_dest_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_src_path, &entry));
-  EXPECT_EQ(GURL(entry.file_specific_info().alternate_url()),
-            util::ReadUrlFromGDocFile(local_dest_path));
-  EXPECT_EQ(entry.resource_id(),
-            util::ReadResourceIdFromGDocFile(local_dest_path));
-  EXPECT_TRUE(observer()->get_changed_paths().empty());
-}
 
 TEST_F(CopyOperationTest, CopyNotExistingFile) {
   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
diff --git a/chrome/browser/chromeos/drive/file_system/create_file_operation.cc b/chrome/browser/chromeos/drive/file_system/create_file_operation.cc
index 404cf4d..2188e34 100644
--- a/chrome/browser/chromeos/drive/file_system/create_file_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/create_file_operation.cc
@@ -61,9 +61,12 @@
     // Here, populate them.
     *parent_resource_id = parent.resource_id();
 
-    // If mime type is unsure, use octet stream by default.
-    if (!net::GetMimeTypeFromFile(file_path, mime_type))
+    // If mime_type is not set or "application/octet-stream", guess from the
+    // |file_path|. If it is still unsure, use octet-stream by default.
+    if ((mime_type->empty() || *mime_type == kMimeTypeOctetStream) &&
+        !net::GetMimeTypeFromFile(file_path, mime_type)) {
       *mime_type = kMimeTypeOctetStream;
+    }
   }
 
   return error;
@@ -140,12 +143,13 @@
 
 void CreateFileOperation::CreateFile(const base::FilePath& file_path,
                                      bool is_exclusive,
+                                     const std::string& mime_type,
                                      const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
   std::string* parent_resource_id = new std::string;
-  std::string* mime_type = new std::string;
+  std::string* determined_mime_type = new std::string(mime_type);
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
@@ -154,13 +158,13 @@
                  file_path,
                  is_exclusive,
                  parent_resource_id,
-                 mime_type),
+                 determined_mime_type),
       base::Bind(&CreateFileOperation::CreateFileAfterCheckPreCondition,
                  weak_ptr_factory_.GetWeakPtr(),
                  file_path,
                  callback,
                  base::Owned(parent_resource_id),
-                 base::Owned(mime_type)));
+                 base::Owned(determined_mime_type)));
 }
 
 void CreateFileOperation::CreateFileAfterCheckPreCondition(
diff --git a/chrome/browser/chromeos/drive/file_system/create_file_operation.h b/chrome/browser/chromeos/drive/file_system/create_file_operation.h
index 05d35dd..6d9e193 100644
--- a/chrome/browser/chromeos/drive/file_system/create_file_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/create_file_operation.h
@@ -51,10 +51,13 @@
   // Creates an empty file at |file_path| in the remote server. When the file
   // already exists at that path, the operation fails if |is_exclusive| is true,
   // and it succeeds without doing anything if the flag is false.
+  // If |mime_type| is non-empty, it is used as the mime type of the entry. If
+  // the parameter is empty, the type is guessed from |file_path|.
   //
   // |callback| must not be null.
   void CreateFile(const base::FilePath& file_path,
                   bool is_exclusive,
+                  const std::string& mime_type,
                   const FileOperationCallback& callback);
 
  private:
diff --git a/chrome/browser/chromeos/drive/file_system/create_file_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/create_file_operation_unittest.cc
index 791a106..3ec2c43 100644
--- a/chrome/browser/chromeos/drive/file_system/create_file_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/create_file_operation_unittest.cc
@@ -34,6 +34,7 @@
   operation.CreateFile(
       kExistingFile,
       true,  // is_exclusive
+      std::string(),  // no predetermined mime type
       google_apis::test_util::CreateCopyResultCallback(&error));
   test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_EXISTS, error);
@@ -42,6 +43,7 @@
   operation.CreateFile(
       kExistingFile,
       false,  // is_exclusive
+      std::string(),  // no predetermined mime type
       google_apis::test_util::CreateCopyResultCallback(&error));
   test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_OK, error);
@@ -50,6 +52,7 @@
   operation.CreateFile(
       kExistingDirectory,
       false,  // is_exclusive
+      std::string(),  // no predetermined mime type
       google_apis::test_util::CreateCopyResultCallback(&error));
   test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_EXISTS, error);
@@ -58,6 +61,7 @@
   operation.CreateFile(
       kNonExistingFile,
       true,   // is_exclusive
+      std::string(),  // no predetermined mime type
       google_apis::test_util::CreateCopyResultCallback(&error));
   test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_OK, error);
@@ -66,10 +70,66 @@
   operation.CreateFile(
       kFileInNonExistingDirectory,
       false,  // is_exclusive
+      std::string(),  // no predetermined mime type
       google_apis::test_util::CreateCopyResultCallback(&error));
   test_util::RunBlockingPoolTask();
   EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
 }
 
+TEST_F(CreateFileOperationTest, CreateFileMimeType) {
+  CreateFileOperation operation(blocking_task_runner(),
+                                observer(),
+                                scheduler(),
+                                metadata(),
+                                cache());
+
+  const base::FilePath kPng1(FILE_PATH_LITERAL("drive/root/1.png"));
+  const base::FilePath kPng2(FILE_PATH_LITERAL("drive/root/2.png"));
+  const base::FilePath kUnknown(FILE_PATH_LITERAL("drive/root/3.unknown"));
+  const std::string kSpecialMimeType("application/x-createfile-test");
+
+  FileError error = FILE_ERROR_FAILED;
+  operation.CreateFile(
+      kPng1,
+      false,  // is_exclusive
+      std::string(),  // no predetermined mime type
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_OK, error);
+
+  // If no mime type is specified, it is guessed from the file name.
+  ResourceEntry entry;
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPng1, &entry));
+  EXPECT_EQ("image/png", entry.file_specific_info().content_mime_type());
+
+  error = FILE_ERROR_FAILED;
+  operation.CreateFile(
+      kPng2,
+      false,  // is_exclusive
+      kSpecialMimeType,
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_OK, error);
+
+  // If the mime type is explicitly set, respect it.
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPng2, &entry));
+  EXPECT_EQ(kSpecialMimeType, entry.file_specific_info().content_mime_type());
+
+  error = FILE_ERROR_FAILED;
+  operation.CreateFile(
+      kUnknown,
+      false,  // is_exclusive
+      std::string(),  // no predetermined mime type
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_OK, error);
+
+  // If the mime type is not set and unknown, default to octet-stream.
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kUnknown, &entry));
+  EXPECT_EQ("application/octet-stream",
+            entry.file_specific_info().content_mime_type());
+}
+
+
 }  // namespace file_system
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
index 7964876..881598b 100644
--- a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.cc
@@ -5,8 +5,10 @@
 #include "chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h"
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "chrome/browser/chromeos/drive/file_system/create_file_operation.h"
 #include "chrome/browser/chromeos/drive/file_system/download_operation.h"
+#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
 #include "chrome/browser/chromeos/drive/file_write_watcher.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -33,7 +35,9 @@
                                                 metadata,
                                                 cache,
                                                 temporary_file_directory)),
-      file_write_watcher_(new internal::FileWriteWatcher(observer)),
+      file_write_watcher_(new internal::FileWriteWatcher),
+      blocking_task_runner_(blocking_task_runner),
+      observer_(observer),
       cache_(cache),
       weak_ptr_factory_(this) {
 }
@@ -50,6 +54,7 @@
   create_file_operation_->CreateFile(
       file_path,
       false,  // error_if_already_exists
+      std::string(),  // no specific mime type
       base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterCreate,
                  weak_ptr_factory_.GetWeakPtr(),
                  file_path,
@@ -117,12 +122,14 @@
   const std::string& resource_id = entry->resource_id();
   file_write_watcher_->StartWatch(
       cache_path,
-      resource_id,
       base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterWatch,
                  weak_ptr_factory_.GetWeakPtr(),
                  callback,
                  cache_path,
-                 base::Passed(&entry)));
+                 base::Passed(&entry)),
+      base::Bind(&GetFileForSavingOperation::OnWriteEvent,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 resource_id));
 }
 
 void GetFileForSavingOperation::GetFileForSavingAfterWatch(
@@ -142,5 +149,18 @@
   callback.Run(FILE_ERROR_OK, cache_path, entry.Pass());
 }
 
+void GetFileForSavingOperation::OnWriteEvent(const std::string& resource_id) {
+  observer_->OnCacheFileUploadNeededByOperation(resource_id);
+
+  // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
+  // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
+  blocking_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(
+          base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor,
+                     base::Unretained(cache_),
+                     0))));
+}
+
 }  // namespace file_system
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h
index 3215cc2..1bcefa7 100644
--- a/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/get_file_for_saving_operation.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_
 
 #include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
@@ -74,10 +75,14 @@
                                   const base::FilePath& cache_path,
                                   scoped_ptr<ResourceEntry> entry,
                                   bool success);
+  // Called when the cache file for |resource_id| is written.
+  void OnWriteEvent(const std::string& resource_id);
 
   scoped_ptr<CreateFileOperation> create_file_operation_;
   scoped_ptr<DownloadOperation> download_operation_;
   scoped_ptr<internal::FileWriteWatcher> file_write_watcher_;
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+  OperationObserver* observer_;
   internal::FileCache* cache_;
 
   // Note: This should remain the last member so it'll be destroyed and
diff --git a/chrome/browser/chromeos/drive/file_system/move_operation.cc b/chrome/browser/chromeos/drive/file_system/move_operation.cc
index ded4aac..0f9a2d9 100644
--- a/chrome/browser/chromeos/drive/file_system/move_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/move_operation.cc
@@ -8,20 +8,67 @@
 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/drive/job_scheduler.h"
+#include "chrome/browser/chromeos/drive/resource_entry_conversion.h"
+#include "chrome/browser/drive/drive_api_util.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
 
 namespace drive {
 namespace file_system {
+namespace {
 
-MoveOperation::MoveOperation(OperationObserver* observer,
+// Looks up ResourceEntry for source entry and the destination directory.
+FileError PrepareMove(internal::ResourceMetadata* metadata,
+                      const base::FilePath& src_path,
+                      const base::FilePath& dest_parent_path,
+                      ResourceEntry* src_entry,
+                      ResourceEntry* dest_parent_entry) {
+  FileError error = metadata->GetResourceEntryByPath(src_path, src_entry);
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  return metadata->GetResourceEntryByPath(dest_parent_path, dest_parent_entry);
+}
+
+// Applies renaming to the local metadata.
+FileError RenameLocally(internal::ResourceMetadata* metadata,
+                        const std::string& resource_id,
+                        const std::string& new_title) {
+  ResourceEntry entry;
+  FileError error = metadata->GetResourceEntryById(resource_id, &entry);
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  entry.set_title(new_title);
+  return metadata->RefreshEntry(resource_id, entry);
+}
+
+// Applies directory-moving to the local metadata.
+FileError MoveDirectoryLocally(internal::ResourceMetadata* metadata,
+                               const std::string& resource_id,
+                               const std::string& parent_resource_id) {
+  ResourceEntry entry;
+  FileError error = metadata->GetResourceEntryById(resource_id, &entry);
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  // TODO(hidehiko,hashimoto): Set local id, instead of resource id.
+  entry.set_parent_local_id(parent_resource_id);
+  return metadata->RefreshEntry(resource_id, entry);
+}
+
+}  // namespace
+
+MoveOperation::MoveOperation(base::SequencedTaskRunner* blocking_task_runner,
+                             OperationObserver* observer,
                              JobScheduler* scheduler,
                              internal::ResourceMetadata* metadata)
-  : observer_(observer),
-    scheduler_(scheduler),
-    metadata_(metadata),
-    weak_ptr_factory_(this) {
+    : blocking_task_runner_(blocking_task_runner),
+      observer_(observer),
+      scheduler_(scheduler),
+      metadata_(metadata),
+      weak_ptr_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
@@ -35,175 +82,254 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  metadata_->GetResourceEntryPairByPathsOnUIThread(
-      src_file_path,
-      dest_file_path.DirName(),
-      base::Bind(&MoveOperation::MoveAfterGetResourceEntryPair,
+  scoped_ptr<ResourceEntry> src_entry(new ResourceEntry);
+  scoped_ptr<ResourceEntry> dest_parent_entry(new ResourceEntry);
+  ResourceEntry* src_entry_ptr = src_entry.get();
+  ResourceEntry* dest_parent_entry_ptr = dest_parent_entry.get();
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(&PrepareMove,
+                 metadata_, src_file_path, dest_file_path.DirName(),
+                 src_entry_ptr, dest_parent_entry_ptr),
+      base::Bind(&MoveOperation::MoveAfterPrepare,
                  weak_ptr_factory_.GetWeakPtr(),
-                 dest_file_path,
-                 callback));
+                 src_file_path, dest_file_path, callback,
+                 base::Passed(&src_entry),
+                 base::Passed(&dest_parent_entry)));
 }
 
-void MoveOperation::MoveAfterGetResourceEntryPair(
+void MoveOperation::MoveAfterPrepare(
+    const base::FilePath& src_file_path,
     const base::FilePath& dest_file_path,
     const FileOperationCallback& callback,
-    scoped_ptr<EntryInfoPairResult> src_dest_info) {
+    scoped_ptr<ResourceEntry> src_entry,
+    scoped_ptr<ResourceEntry> dest_parent_entry,
+    FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
-  DCHECK(src_dest_info.get());
 
-  if (src_dest_info->first.error != FILE_ERROR_OK) {
-    callback.Run(src_dest_info->first.error);
+  if (error != FILE_ERROR_OK) {
+    callback.Run(error);
     return;
   }
-  if (src_dest_info->second.error != FILE_ERROR_OK) {
-    callback.Run(src_dest_info->second.error);
-    return;
-  }
-  if (!src_dest_info->second.entry->file_info().is_directory()) {
+
+  if (!dest_parent_entry->file_info().is_directory()) {
+    // The parent of the destination is not a directory.
     callback.Run(FILE_ERROR_NOT_A_DIRECTORY);
     return;
   }
 
-  const std::string& src_id = src_dest_info->first.entry->resource_id();
-  const base::FilePath& src_path = src_dest_info->first.path;
-  const base::FilePath new_name = dest_file_path.BaseName();
-  const bool new_name_has_hosted_extension =
-      src_dest_info->first.entry->has_file_specific_info() &&
-      src_dest_info->first.entry->file_specific_info().is_hosted_document() &&
-      new_name.Extension() ==
-          src_dest_info->first.entry->file_specific_info().document_extension();
+  // Strip the extension for a hosted document if necessary.
+  const bool has_hosted_document_extension =
+      src_entry->has_file_specific_info() &&
+      src_entry->file_specific_info().is_hosted_document() &&
+      dest_file_path.Extension() ==
+      src_entry->file_specific_info().document_extension();
+  const std::string new_title =
+      has_hosted_document_extension ?
+      dest_file_path.BaseName().RemoveExtension().AsUTF8Unsafe() :
+      dest_file_path.BaseName().AsUTF8Unsafe();
 
-  Rename(src_id, src_path, new_name, new_name_has_hosted_extension,
+  // If Drive API v2 is enabled, we can move the file on server side by one
+  // request.
+  if (util::IsDriveV2ApiEnabled()) {
+    scheduler_->MoveResource(
+        src_entry->resource_id(), dest_parent_entry->resource_id(), new_title,
+        base::Bind(&MoveOperation::MoveAfterMoveResource,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   src_file_path, dest_file_path, callback));
+    return;
+  }
+
+  ResourceEntry* src_entry_ptr = src_entry.get();
+  Rename(*src_entry_ptr, new_title,
          base::Bind(&MoveOperation::MoveAfterRename,
                     weak_ptr_factory_.GetWeakPtr(),
-                    callback,
-                    base::Passed(&src_dest_info)));
+                    src_file_path, dest_file_path, callback,
+                    base::Passed(&src_entry),
+                    base::Passed(&dest_parent_entry)));
+}
+
+void MoveOperation::MoveAfterMoveResource(
+    const base::FilePath& src_file_path,
+    const base::FilePath& dest_file_path,
+    const FileOperationCallback& callback,
+    google_apis::GDataErrorCode status,
+    scoped_ptr<google_apis::ResourceEntry> resource_entry) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  const FileError error = GDataToFileError(status);
+  if (error != FILE_ERROR_OK) {
+    callback.Run(error);
+    return;
+  }
+
+  ResourceEntry entry;
+  if (!ConvertToResourceEntry(*resource_entry, &entry)) {
+    callback.Run(FILE_ERROR_FAILED);
+    return;
+  }
+
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(&internal::ResourceMetadata::RefreshEntry,
+                 base::Unretained(metadata_), entry.resource_id(), entry),
+      base::Bind(&MoveOperation::MoveAfterRefreshEntry,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 src_file_path, dest_file_path, callback));
+}
+
+void MoveOperation::MoveAfterRefreshEntry(
+    const base::FilePath& src_file_path,
+    const base::FilePath& dest_file_path,
+    const FileOperationCallback& callback,
+    FileError error) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (error == FILE_ERROR_OK) {
+    // Notify the change of directory.
+    observer_->OnDirectoryChangedByOperation(src_file_path.DirName());
+    observer_->OnDirectoryChangedByOperation(dest_file_path.DirName());
+  }
+
+  callback.Run(error);
 }
 
 void MoveOperation::MoveAfterRename(
+    const base::FilePath& src_file_path,
+    const base::FilePath& dest_file_path,
     const FileOperationCallback& callback,
-    scoped_ptr<EntryInfoPairResult> src_dest_info,
-    FileError error,
-    const base::FilePath& src_path) {
+    scoped_ptr<ResourceEntry> src_entry,
+    scoped_ptr<ResourceEntry> dest_parent_entry,
+    FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error);
     return;
   }
 
-  const std::string& src_id = src_dest_info->first.entry->resource_id();
-  const std::string& dest_dir_id = src_dest_info->second.entry->resource_id();
-  const base::FilePath& dest_dir_path = src_dest_info->second.path;
-
   // The source and the destination directory are the same. Nothing more to do.
-  if (src_path.DirName() == dest_dir_path) {
-    observer_->OnDirectoryChangedByOperation(dest_dir_path);
+  // TODO(hidehiko,hashimoto): Replace resource_id to local_id.
+  if (src_entry->parent_local_id() == dest_parent_entry->resource_id()) {
+    observer_->OnDirectoryChangedByOperation(dest_file_path.DirName());
     callback.Run(FILE_ERROR_OK);
     return;
   }
 
-  AddToDirectory(src_id, dest_dir_id, src_path, dest_dir_path,
+  // TODO(hidehiko,hashimoto): For MoveAfterAddToDirectory, it will be
+  // necessary to resolve local id to resource id.
+  AddToDirectory(src_entry->resource_id(),
+                 dest_parent_entry->resource_id(),
                  base::Bind(&MoveOperation::MoveAfterAddToDirectory,
                             weak_ptr_factory_.GetWeakPtr(),
-                            callback,
-                            base::Passed(&src_dest_info)));
+                            src_file_path, dest_file_path, callback,
+                            src_entry->resource_id(),
+                            src_entry->parent_local_id()));
 }
 
 void MoveOperation::MoveAfterAddToDirectory(
+    const base::FilePath& src_file_path,
+    const base::FilePath& dest_file_path,
     const FileOperationCallback& callback,
-    scoped_ptr<EntryInfoPairResult> src_dest_info,
-    FileError error,
-    const base::FilePath& new_path) {
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
 
   if (error != FILE_ERROR_OK) {
     callback.Run(error);
     return;
   }
 
-  const base::FilePath& src_path = src_dest_info->first.path;
-  observer_->OnDirectoryChangedByOperation(src_path.DirName());
-  observer_->OnDirectoryChangedByOperation(new_path.DirName());
+  // Notify to the observers.
+  observer_->OnDirectoryChangedByOperation(src_file_path.DirName());
+  observer_->OnDirectoryChangedByOperation(dest_file_path.DirName());
 
-  RemoveFromDirectory(src_dest_info->first.entry->resource_id(),
-                      src_dest_info->first.entry->parent_resource_id(),
-                      callback);
+  RemoveFromDirectory(resource_id, parent_resource_id, callback);
 }
 
-void MoveOperation::Rename(const std::string& src_id,
-                           const base::FilePath& src_path,
-                           const base::FilePath& new_name,
-                           bool new_name_has_hosted_extension,
-                           const FileMoveCallback& callback) {
+void MoveOperation::Rename(const ResourceEntry& entry,
+                           const std::string& new_title,
+                           const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
 
-  // It is a no-op if the file is renamed to the same name.
-  if (src_path.BaseName() == new_name) {
-    callback.Run(FILE_ERROR_OK, src_path);
+  if (entry.title() == new_title) {
+    // We have nothing to do.
+    callback.Run(FILE_ERROR_OK);
     return;
   }
 
-  // Drop the .g<something> extension from |new_name| if the file being
-  // renamed is a hosted document and |new_name| has the same .g<something>
-  // extension as the file.
-  const std::string new_title = new_name_has_hosted_extension ?
-      new_name.RemoveExtension().AsUTF8Unsafe() :
-      new_name.AsUTF8Unsafe();
-
-  // Rename on the server.
-  scheduler_->RenameResource(src_id,
-                             new_title,
-                             base::Bind(&MoveOperation::RenameLocally,
-                                        weak_ptr_factory_.GetWeakPtr(),
-                                        src_path,
-                                        new_title,
-                                        callback));
+  // Send a rename request to the server.
+  scheduler_->RenameResource(
+      entry.resource_id(),
+      new_title,
+      base::Bind(&MoveOperation::RenameAfterRenameResource,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 entry.resource_id(), new_title, callback));
 }
 
-void MoveOperation::RenameLocally(const base::FilePath& src_path,
-                                  const std::string& new_title,
-                                  const FileMoveCallback& callback,
-                                  google_apis::GDataErrorCode status) {
+void MoveOperation::RenameAfterRenameResource(
+    const std::string& resource_id,
+    const std::string& new_title,
+    const FileOperationCallback& callback,
+    google_apis::GDataErrorCode status) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
 
   const FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
-    callback.Run(error, base::FilePath());
+    callback.Run(error);
     return;
   }
-  metadata_->RenameEntryOnUIThread(src_path, new_title, callback);
+
+  // Server side renaming is done. Update the local metadata.
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(&RenameLocally, metadata_, resource_id, new_title),
+      callback);
 }
 
-void MoveOperation::AddToDirectory(const std::string& src_id,
-                                   const std::string& dest_dir_id,
-                                   const base::FilePath& src_path,
-                                   const base::FilePath& dest_dir_path,
-                                   const FileMoveCallback& callback) {
+void MoveOperation::AddToDirectory(
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
 
   scheduler_->AddResourceToDirectory(
-      dest_dir_id, src_id,
-      base::Bind(&MoveOperation::AddToDirectoryLocally,
+      parent_resource_id, resource_id,
+      base::Bind(&MoveOperation::AddToDirectoryAfterAddResourceToDirectory,
                  weak_ptr_factory_.GetWeakPtr(),
-                 src_path,
-                 dest_dir_path,
-                 callback));
+                 resource_id, parent_resource_id, callback));
 }
 
-void MoveOperation::AddToDirectoryLocally(const base::FilePath& src_path,
-                                          const base::FilePath& dest_dir_path,
-                                          const FileMoveCallback& callback,
-                                          google_apis::GDataErrorCode status) {
+void MoveOperation::AddToDirectoryAfterAddResourceToDirectory(
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const FileOperationCallback& callback,
+    google_apis::GDataErrorCode status) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
 
   const FileError error = GDataToFileError(status);
   if (error != FILE_ERROR_OK) {
-    callback.Run(error, base::FilePath());
+    callback.Run(error);
     return;
   }
-  metadata_->MoveEntryToDirectoryOnUIThread(src_path, dest_dir_path, callback);
+
+  // Server side moving is done. Update the local metadata.
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(&MoveDirectoryLocally,
+                 metadata_, resource_id, parent_resource_id),
+      callback);
 }
 
 void MoveOperation::RemoveFromDirectory(
@@ -211,9 +337,10 @@
     const std::string& directory_resource_id,
     const FileOperationCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
 
-  // Moving files out from "drive/other" special folder for storing orphan files
-  // has no meaning in the server. Just skip the step.
+  // Moving files out from "drive/other" special folder for storing orphan
+  // files has no meaning in the server. Just skip the step.
   if (util::IsSpecialResourceId(directory_resource_id)) {
     callback.Run(FILE_ERROR_OK);
     return;
@@ -222,15 +349,16 @@
   scheduler_->RemoveResourceFromDirectory(
       directory_resource_id,
       resource_id,
-      base::Bind(&MoveOperation::RemoveFromDirectoryCompleted,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback));
+      base::Bind(
+          &MoveOperation::RemoveFromDirectoryAfterRemoveResourceFromDirectory,
+          weak_ptr_factory_.GetWeakPtr(), callback));
 }
 
-void MoveOperation::RemoveFromDirectoryCompleted(
+void MoveOperation::RemoveFromDirectoryAfterRemoveResourceFromDirectory(
     const FileOperationCallback& callback,
     google_apis::GDataErrorCode status) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
   callback.Run(GDataToFileError(status));
 }
 
diff --git a/chrome/browser/chromeos/drive/file_system/move_operation.h b/chrome/browser/chromeos/drive/file_system/move_operation.h
index 792aca8..3c43372 100644
--- a/chrome/browser/chromeos/drive/file_system/move_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/move_operation.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_SYSTEM_MOVE_OPERATION_H_
 
 #include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/drive/resource_metadata.h"
@@ -13,8 +14,13 @@
 
 namespace base {
 class FilePath;
+class SequencedTaskRunner;
 }  // namespace base
 
+namespace google_apis {
+class ResourceEntry;
+}  // namespace google_apis
+
 namespace drive {
 
 class JobScheduler;
@@ -29,7 +35,8 @@
 // metadata to reflect the new state.
 class MoveOperation {
  public:
-  MoveOperation(OperationObserver* observer,
+  MoveOperation(base::SequencedTaskRunner* blocking_task_runner,
+                OperationObserver* observer,
                 JobScheduler* scheduler,
                 internal::ResourceMetadata* metadata);
   ~MoveOperation();
@@ -40,81 +47,91 @@
   void Move(const base::FilePath& src_file_path,
             const base::FilePath& dest_file_path,
             const FileOperationCallback& callback);
+
  private:
-  // Step 1 of Move(), called after the resource entry of the source and the
-  // destination directory is obtained. It renames the resource in the source
-  // directory, before moving between directories.
-  void MoveAfterGetResourceEntryPair(
+  // Part of Move(). Called after local metadata look up.
+  void MoveAfterPrepare(const base::FilePath& src_file_path,
+                        const base::FilePath& dest_file_path,
+                        const FileOperationCallback& callback,
+                        scoped_ptr<ResourceEntry> src_entry,
+                        scoped_ptr<ResourceEntry> dest_parent_entry,
+                        FileError error);
+
+  // Part of Move(). Called after MoveResource is completed. This is only for
+  // Drive API v2.
+  void MoveAfterMoveResource(
+      const base::FilePath& src_file_path,
       const base::FilePath& dest_file_path,
       const FileOperationCallback& callback,
-      scoped_ptr<EntryInfoPairResult> src_dest_info);
+      google_apis::GDataErrorCode status,
+      scoped_ptr<google_apis::ResourceEntry> resource_entry);
 
-  // Step 2 of Move(), called after renaming is completed. It adds the resource
-  // to the destination directory.
-  void MoveAfterRename(const FileOperationCallback& callback,
-                       scoped_ptr<EntryInfoPairResult> src_dest_info,
-                       FileError error,
-                       const base::FilePath& src_path);
+  // Part of Move(). Called after ResourceMetadata::RefreshEntry is completed.
+  // This is only for Drive API v2.
+  void MoveAfterRefreshEntry(const base::FilePath& src_file_path,
+                             const base::FilePath& dest_file_path,
+                             const FileOperationCallback& callback,
+                             FileError error);
 
-  // Step 3 of Move(), called after the resource is added to the new directory.
-  // It removes the resource from the old directory in the remote server. While
-  // our local metadata assumes tree structure, on the server side a resource
-  // can belong to multiple collections (directories). At this point the
-  // resource is contained in both the new and the old directories.
-  void MoveAfterAddToDirectory(const FileOperationCallback& callback,
-                               scoped_ptr<EntryInfoPairResult> src_dest_info,
-                               FileError error,
-                               const base::FilePath& src_path);
+  // Part of Move(). Called after renaming (without moving the directory)
+  // is completed.
+  void MoveAfterRename(const base::FilePath& src_file_path,
+                       const base::FilePath& dest_file_path,
+                       const FileOperationCallback& callback,
+                       scoped_ptr<ResourceEntry> src_entry,
+                       scoped_ptr<ResourceEntry> dest_parent_entry,
+                       FileError error);
 
-  // Step 4 of Move(), called after the resource is removed from the old
-  // directory. It calls back to the caller of Move().
-  void MoveAfterRemoveFromDirectory(
+  // Part of Move(). Called after adding the entry to the parent is done.
+  void MoveAfterAddToDirectory(const base::FilePath& src_file_path,
+                               const base::FilePath& dest_file_path,
+                               const FileOperationCallback& callback,
+                               const std::string& resource_id,
+                               const std::string& parent_resource_id,
+                               FileError error);
+
+
+  // Renames the |entry| to |new_title|. Upon completion, |callback| will be
+  // called. Note that if |entry|'s title is same as |new_title|, does nothing
+  // and calls |callback|.
+  // |callback| must not be null.
+  void Rename(const ResourceEntry& entry,
+              const std::string& new_title,
+              const FileOperationCallback& callback);
+
+  // Part of Rename(). Called after server side renaming is done.
+  void RenameAfterRenameResource(const std::string& resource_id,
+                                 const std::string& new_title,
+                                 const FileOperationCallback& callback,
+                                 google_apis::GDataErrorCode status);
+
+
+  // Adds the entry with |resource_id| to the directory |parent_resource_id|.
+  // Upon completion, |callback| will be called.
+  void AddToDirectory(const std::string& resource_id,
+                      const std::string& parent_resource_id,
+                      const FileOperationCallback& callback);
+
+  // Part of AddToDirectory(). Called after server side updating is done.
+  void AddToDirectoryAfterAddResourceToDirectory(
+      const std::string& resource_id,
+      const std::string& parent_resource_id,
       const FileOperationCallback& callback,
-      scoped_ptr<EntryInfoPairResult> src_dest_info,
       google_apis::GDataErrorCode status);
 
-  // Renames a resource |src_id| at |src_path| to |new_name| in the same
-  // directory. |callback| will receive the new file path if the operation is
-  // successful. If the new name already exists in the same directory, the file
-  // name is uniquified by adding a parenthesized serial number like
-  // "foo (2).txt".
-  void Rename(const std::string& src_id,
-              const base::FilePath& src_path,
-              const base::FilePath& new_name,
-              bool new_name_has_hosted_extension,
-              const FileMoveCallback& callback);
-
-  // Called in Rename() to reflect the rename on the local metadata.
-  void RenameLocally(const base::FilePath& src_path,
-                     const std::string& new_title,
-                     const FileMoveCallback& callback,
-                     google_apis::GDataErrorCode status);
-
-
-  // Moves a resource |src_id| at |src_path| to another directory |dest_dir_id|
-  // at |dest_dir_path|. |callback| will receive the new file path if the
-  // operation is successful.
-  void AddToDirectory(const std::string& src_id,
-                      const std::string& dest_dir_id,
-                      const base::FilePath& src_path,
-                      const base::FilePath& dest_dir_path,
-                      const FileMoveCallback& callback);
-
-  // Called in AddToDirectory() to reflect the move on the local metadata.
-  void AddToDirectoryLocally(const base::FilePath& src_path,
-                             const base::FilePath& dest_dir_path,
-                             const FileMoveCallback& callback,
-                             google_apis::GDataErrorCode status);
-
-  // Removes a resource |resource_id| from |directory_resource_id|.
+  // Removes the resource with |resource_id| from the directory with
+  // |directory_resource_id|.
+  // Upon completion, |callback| will be called.
   void RemoveFromDirectory(const std::string& resource_id,
                            const std::string& directory_resource_id,
                            const FileOperationCallback& callback);
 
-  // Called in RemoveFromDirectory().
-  void RemoveFromDirectoryCompleted(const FileOperationCallback& callback,
-                                    google_apis::GDataErrorCode status);
+  // Part of RemoveFromDirectory(). Called after server side updating is done.
+  void RemoveFromDirectoryAfterRemoveResourceFromDirectory(
+      const FileOperationCallback& callback,
+      google_apis::GDataErrorCode status);
 
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
   OperationObserver* observer_;
   JobScheduler* scheduler_;
   internal::ResourceMetadata* metadata_;
diff --git a/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc
index 4f9430e..0cd4040 100644
--- a/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/move_operation_unittest.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/chromeos/drive/file_system/move_operation.h"
 
+#include "chrome/browser/chromeos/drive/file_system/copy_operation.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_test_base.h"
+#include "chrome/browser/drive/fake_drive_service.h"
 #include "chrome/browser/google_apis/test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -15,10 +17,21 @@
  protected:
   virtual void SetUp() OVERRIDE {
    OperationTestBase::SetUp();
-   operation_.reset(new MoveOperation(observer(), scheduler(), metadata()));
- }
+   operation_.reset(new MoveOperation(blocking_task_runner(),
+                                      observer(),
+                                      scheduler(),
+                                      metadata()));
+   copy_operation_.reset(new CopyOperation(blocking_task_runner(),
+                                           observer(),
+                                           scheduler(),
+                                           metadata(),
+                                           cache(),
+                                           fake_service(),
+                                           temp_dir()));
+  }
 
- scoped_ptr<MoveOperation> operation_;
+  scoped_ptr<MoveOperation> operation_;
+  scoped_ptr<CopyOperation> copy_operation_;
 };
 
 TEST_F(MoveOperationTest, MoveFileInSameDirectory) {
@@ -153,6 +166,51 @@
   EXPECT_TRUE(observer()->get_changed_paths().count(dest_path.DirName()));
 }
 
+TEST_F(MoveOperationTest, MoveFileBetweenSubDirectoriesRenameWithTitle) {
+  base::FilePath src_path(
+      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
+  base::FilePath dest_path(FILE_PATH_LITERAL(
+      "drive/root/Directory 1/Sub Directory Folder/"
+      "SubDirectory File 1 (1).txt"));
+
+  ResourceEntry src_entry, dest_entry;
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
+  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
+            GetLocalResourceEntry(dest_path, &dest_entry));
+
+  FileError error = FILE_ERROR_FAILED;
+  // Copy the src file into the same directory. This will make inconsistency
+  // between title and path of the copied file.
+  copy_operation_->Copy(
+      src_path,
+      src_path,
+      google_apis::test_util::CreateCopyResultCallback(&error));
+  test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_OK, error);
+  base::FilePath copied_path(
+      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1 (1).txt"));
+  ResourceEntry copied_entry;
+  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(copied_path, &copied_entry));
+  ASSERT_EQ("SubDirectory File 1.txt", copied_entry.title());
+
+  // Move the copied file.
+  operation_->Move(copied_path,
+                   dest_path,
+                   google_apis::test_util::CreateCopyResultCallback(&error));
+  test_util::RunBlockingPoolTask();
+  EXPECT_EQ(FILE_ERROR_OK, error);
+
+  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
+  EXPECT_EQ("SubDirectory File 1 (1).txt", dest_entry.title());
+  EXPECT_EQ(copied_entry.resource_id(), dest_entry.resource_id());
+  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
+            GetLocalResourceEntry(copied_path, &copied_entry));
+
+  EXPECT_EQ(2U, observer()->get_changed_paths().size());
+  EXPECT_TRUE(observer()->get_changed_paths().count(copied_path.DirName()));
+  EXPECT_TRUE(observer()->get_changed_paths().count(dest_path.DirName()));
+}
+
 TEST_F(MoveOperationTest, MoveNotExistingFile) {
   base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
   base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Test.log"));
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
index 25d6348..95fedf3 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/drive/file_system/open_file_operation.h"
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop_proxy.h"
@@ -46,6 +47,7 @@
 
 void OpenFileOperation::OpenFile(const base::FilePath& file_path,
                                  OpenMode open_mode,
+                                 const std::string& mime_type,
                                  const OpenFileCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
@@ -60,14 +62,16 @@
     case CREATE_FILE:
       create_file_operation_->CreateFile(
           file_path,
-          true /* exclusive */,
+          true,  // exclusive: fail if already exists
+          mime_type,
           base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
                      weak_ptr_factory_.GetWeakPtr(), file_path, callback));
       break;
     case OPEN_OR_CREATE_FILE:
       create_file_operation_->CreateFile(
           file_path,
-          false /* not-exclusive */,
+          false,  // not-exclusive
+          mime_type,
           base::Bind(&OpenFileOperation::OpenFileAfterCreateFile,
                      weak_ptr_factory_.GetWeakPtr(), file_path, callback));
       break;
@@ -157,6 +161,15 @@
     // All clients closes this file, so notify to upload the file.
     open_files_.erase(resource_id);
     observer_->OnCacheFileUploadNeededByOperation(resource_id);
+
+    // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
+    // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
+    blocking_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(base::IgnoreResult(
+            base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor,
+                       base::Unretained(cache_),
+                       0))));
   }
 }
 
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation.h b/chrome/browser/chromeos/drive/file_system/open_file_operation.h
index 7055eea..771df3c 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation.h
@@ -48,11 +48,14 @@
   // Opens the file at |file_path|.
   // If the file is not actually downloaded, this method starts
   // to download it to the cache, and then runs |callback| upon the
-  // completation with the path to the local cache file.
+  // completion with the path to the local cache file.
   // See also the definition of OpenMode for its meaning.
+  // If |mime_type| is non empty and the file is created by this OpenFile()
+  // call, the mime type is used as the file's property.
   // |callback| must not be null.
   void OpenFile(const base::FilePath& file_path,
                 OpenMode open_mode,
+                const std::string& mime_type,
                 const OpenFileCallback& callback);
 
  private:
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc b/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc
index 3628166..fceaf38 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation_unittest.cc
@@ -44,6 +44,7 @@
   operation_->OpenFile(
       file_in_root,
       OPEN_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
@@ -71,6 +72,7 @@
   operation_->OpenFile(
       file_in_root,
       OPEN_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
@@ -90,6 +92,7 @@
   operation_->OpenFile(
       file_in_root,
       CREATE_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
@@ -108,6 +111,7 @@
   operation_->OpenFile(
       file_in_root,
       CREATE_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
@@ -138,6 +142,7 @@
   operation_->OpenFile(
       file_in_root,
       OPEN_OR_CREATE_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
@@ -165,6 +170,7 @@
   operation_->OpenFile(
       file_in_root,
       OPEN_OR_CREATE_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
@@ -195,6 +201,7 @@
   operation_->OpenFile(
       file_in_root,
       OPEN_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
@@ -211,6 +218,7 @@
   operation_->OpenFile(
       file_in_root,
       OPEN_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback2));
   test_util::RunBlockingPoolTask();
diff --git a/chrome/browser/chromeos/drive/file_system/operation_test_base.cc b/chrome/browser/chromeos/drive/file_system/operation_test_base.cc
index 324858d..ccacced 100644
--- a/chrome/browser/chromeos/drive/file_system/operation_test_base.cc
+++ b/chrome/browser/chromeos/drive/file_system/operation_test_base.cc
@@ -7,6 +7,7 @@
 #include "base/prefs/testing_pref_service.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/chromeos/drive/change_list_loader.h"
+#include "chrome/browser/chromeos/drive/change_list_processor.h"
 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
@@ -113,7 +114,7 @@
       blocking_task_runner_.get(), metadata_.get(), scheduler_.get());
 
   change_list_loader.LoadIfNeeded(
-      DirectoryFetchInfo(),
+      internal::DirectoryFetchInfo(),
       google_apis::test_util::CreateCopyResultCallback(&error));
   test_util::RunBlockingPoolTask();
   ASSERT_EQ(FILE_ERROR_OK, error);
diff --git a/chrome/browser/chromeos/drive/file_system/search_operation.cc b/chrome/browser/chromeos/drive/file_system/search_operation.cc
index fd9fb34..d1972d2 100644
--- a/chrome/browser/chromeos/drive/file_system/search_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/search_operation.cc
@@ -43,7 +43,7 @@
       continue;  // Skip non-file entries.
 
     const std::string id = entry.resource_id();
-    FileError error = resource_metadata->RefreshEntry(entry);
+    FileError error = resource_metadata->RefreshEntry(id, entry);
     if (error == FILE_ERROR_NOT_FOUND) {
       // The result is absent in local resource metadata. This can happen if
       // the metadata is not synced to the latest server state yet. In that
@@ -53,7 +53,7 @@
       //
       // It will be moved to the right place when the metadata gets synced
       // in normal loading process in ChangeListProcessor.
-      entry.set_parent_resource_id(util::kDriveOtherDirSpecialResourceId);
+      entry.set_parent_local_id(util::kDriveOtherDirSpecialResourceId);
       error = resource_metadata->AddEntry(entry);
 
       // FILE_ERROR_EXISTS may happen if we have already added the entry to
diff --git a/chrome/browser/chromeos/drive/file_system/touch_operation.cc b/chrome/browser/chromeos/drive/file_system/touch_operation.cc
index b2ce74f..1c7d7de 100644
--- a/chrome/browser/chromeos/drive/file_system/touch_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/touch_operation.cc
@@ -110,6 +110,7 @@
       FROM_HERE,
       base::Bind(&internal::ResourceMetadata::RefreshEntry,
                  base::Unretained(metadata_),
+                 entry.resource_id(),
                  entry),
       base::Bind(&TouchOperation::TouchFileAfterRefreshMetadata,
                  weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/chromeos/drive/file_system/update_operation.cc b/chrome/browser/chromeos/drive/file_system/update_operation.cc
index f528f79..f787e17 100644
--- a/chrome/browser/chromeos/drive/file_system/update_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/update_operation.cc
@@ -76,7 +76,7 @@
   if (!ConvertToResourceEntry(*resource_entry, &entry))
     return FILE_ERROR_NOT_A_FILE;
 
-  FileError error = metadata->RefreshEntry(entry);
+  FileError error = metadata->RefreshEntry(entry.resource_id(), entry);
   if (error != FILE_ERROR_OK)
     return error;
 
diff --git a/chrome/browser/chromeos/drive/file_system_interface.h b/chrome/browser/chromeos/drive/file_system_interface.h
index 4df3c8f..a038060 100644
--- a/chrome/browser/chromeos/drive/file_system_interface.h
+++ b/chrome/browser/chromeos/drive/file_system_interface.h
@@ -182,16 +182,6 @@
   // Checks for updates on the server.
   virtual void CheckForUpdates() = 0;
 
-  // Initiates transfer of |remote_src_file_path| to |local_dest_file_path|.
-  // |remote_src_file_path| is the virtual source path on the Drive file system.
-  // |local_dest_file_path| is the destination path on the local file system.
-  //
-  // |callback| must not be null.
-  virtual void TransferFileFromRemoteToLocal(
-      const base::FilePath& remote_src_file_path,
-      const base::FilePath& local_dest_file_path,
-      const FileOperationCallback& callback) = 0;
-
   // Initiates transfer of |local_src_file_path| to |remote_dest_file_path|.
   // |local_src_file_path| must be a file from the local file system.
   // |remote_dest_file_path| is the virtual destination path within Drive file
@@ -207,10 +197,14 @@
   // onto the cache, and mark it dirty. The local path to the cache file is
   // returned to |callback|. After opening the file, both read and write
   // on the file can be done with normal local file operations.
+  // If |mime_type| is set and the file is newly created, the mime type is
+  // set to the specified value. If |mime_type| is empty, it is guessed from
+  // |file_path|.
   //
   // |callback| must not be null.
   virtual void OpenFile(const base::FilePath& file_path,
                         OpenMode open_mode,
+                        const std::string& mime_type,
                         const OpenFileCallback& callback) = 0;
 
   // Copies |src_file_path| to |dest_file_path| on the file system.
@@ -281,10 +275,14 @@
   // error is raised when a file already exists at the path. It is
   // an error if a directory or a hosted document is already present at the
   // path, or the parent directory of the path is not present yet.
+  // If |mime_type| is set and the file is newly created, the mime type is
+  // set to the specified value. If |mime_type| is empty, it is guessed from
+  // |file_path|.
   //
   // |callback| must not be null.
   virtual void CreateFile(const base::FilePath& file_path,
                           bool is_exclusive,
+                          const std::string& mime_type,
                           const FileOperationCallback& callback) = 0;
 
   // Touches the file at |file_path| by updating the timestamp to
diff --git a/chrome/browser/chromeos/drive/file_system_unittest.cc b/chrome/browser/chromeos/drive/file_system_unittest.cc
index 0f0ca56..769200d 100644
--- a/chrome/browser/chromeos/drive/file_system_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/prefs/testing_pref_service.h"
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/drive/change_list_loader.h"
+#include "chrome/browser/chromeos/drive/change_list_processor.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
 #include "chrome/browser/chromeos/drive/file_system_observer.h"
@@ -150,7 +151,7 @@
   bool LoadFullResourceList() {
     FileError error = FILE_ERROR_FAILED;
     file_system_->change_list_loader_for_testing()->LoadIfNeeded(
-        DirectoryFetchInfo(),
+        internal::DirectoryFetchInfo(),
         google_apis::test_util::CreateCopyResultCallback(&error));
     test_util::RunBlockingPoolTask();
     return error == FILE_ERROR_OK;
@@ -242,7 +243,7 @@
     ResourceEntry file1;
     file1.set_title("File1");
     file1.set_resource_id("resource_id:File1");
-    file1.set_parent_resource_id(root_resource_id);
+    file1.set_parent_local_id(root_resource_id);
     file1.mutable_file_specific_info()->set_md5("md5");
     file1.mutable_file_info()->set_is_directory(false);
     file1.mutable_file_info()->set_size(1048576);
@@ -253,7 +254,7 @@
     ResourceEntry dir1;
     dir1.set_title("Dir1");
     dir1.set_resource_id("resource_id:Dir1");
-    dir1.set_parent_resource_id(root_resource_id);
+    dir1.set_parent_local_id(root_resource_id);
     dir1.mutable_file_info()->set_is_directory(true);
     if (resource_metadata->AddEntry(dir1) != FILE_ERROR_OK)
       return false;
@@ -262,7 +263,7 @@
     ResourceEntry file2;
     file2.set_title("File2");
     file2.set_resource_id("resource_id:File2");
-    file2.set_parent_resource_id(dir1.resource_id());
+    file2.set_parent_local_id(dir1.resource_id());
     file2.mutable_file_specific_info()->set_md5("md5");
     file2.mutable_file_info()->set_is_directory(false);
     file2.mutable_file_info()->set_size(555);
@@ -273,7 +274,7 @@
     ResourceEntry dir2;
     dir2.set_title("SubDir2");
     dir2.set_resource_id("resource_id:SubDir2");
-    dir2.set_parent_resource_id(dir1.resource_id());
+    dir2.set_parent_local_id(dir1.resource_id());
     dir2.mutable_file_info()->set_is_directory(true);
     if (resource_metadata->AddEntry(dir2) != FILE_ERROR_OK)
       return false;
@@ -282,7 +283,7 @@
     ResourceEntry file3;
     file3.set_title("File3");
     file3.set_resource_id("resource_id:File3");
-    file3.set_parent_resource_id(dir2.resource_id());
+    file3.set_parent_local_id(dir2.resource_id());
     file3.mutable_file_specific_info()->set_md5("md5");
     file3.mutable_file_info()->set_is_directory(false);
     file3.mutable_file_info()->set_size(12345);
@@ -741,6 +742,7 @@
   file_system_->OpenFile(
       kFileInRoot,
       OPEN_FILE,
+      std::string(),  // mime_type
       google_apis::test_util::CreateCopyResultCallback(
           &error, &file_path, &close_callback));
   test_util::RunBlockingPoolTask();
diff --git a/chrome/browser/chromeos/drive/file_system_util.cc b/chrome/browser/chromeos/drive/file_system_util.cc
index e84c860..e0eb448 100644
--- a/chrome/browser/chromeos/drive/file_system_util.cc
+++ b/chrome/browser/chromeos/drive/file_system_util.cc
@@ -19,6 +19,7 @@
 #include "base/md5.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
+#include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -27,13 +28,15 @@
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
-#include "chrome/browser/chromeos/drive/file_write_helper.h"
 #include "chrome/browser/chromeos/drive/job_list.h"
+#include "chrome/browser/chromeos/drive/write_on_cache_file.h"
+#include "chrome/browser/chromeos/profiles/profile_util.h"
 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths_internal.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chromeos/chromeos_constants.h"
 #include "content/public/browser/browser_thread.h"
@@ -73,12 +76,6 @@
   return integration_service ? integration_service->file_system() : NULL;
 }
 
-FileWriteHelper* GetFileWriteHelper(Profile* profile) {
-  DriveIntegrationService* integration_service =
-      DriveIntegrationServiceFactory::GetForProfile(profile);
-  return integration_service ? integration_service->file_write_helper() : NULL;
-}
-
 std::string ReadStringFromGDocFile(const base::FilePath& file_path,
                                    const std::string& key) {
   const int64 kMaxGDocSize = 4096;
@@ -163,20 +160,11 @@
   ResourceEntry mydrive_root;
   mydrive_root.mutable_file_info()->set_is_directory(true);
   mydrive_root.set_resource_id(root_resource_id);
-  mydrive_root.set_parent_resource_id(util::kDriveGrandRootSpecialResourceId);
+  mydrive_root.set_parent_local_id(util::kDriveGrandRootSpecialResourceId);
   mydrive_root.set_title(util::kDriveMyDriveRootDirName);
   return mydrive_root;
 }
 
-ResourceEntry CreateOtherDirEntry() {
-  ResourceEntry other_dir;
-  other_dir.mutable_file_info()->set_is_directory(true);
-  other_dir.set_resource_id(util::kDriveOtherDirSpecialResourceId);
-  other_dir.set_parent_resource_id(util::kDriveGrandRootSpecialResourceId);
-  other_dir.set_title(util::kDriveOtherDirName);
-  return other_dir;
-}
-
 const std::string& GetDriveMountPointPathAsString() {
   CR_DEFINE_STATIC_LOCAL(std::string, drive_mount_path_string,
       (kDriveMountPointPath));
@@ -327,19 +315,21 @@
 
 void PrepareWritableFileAndRun(Profile* profile,
                                const base::FilePath& path,
-                               const OpenFileCallback& callback) {
+                               const PrepareWritableFileCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
-  if (IsUnderDriveMountPoint(path)) {
-    FileWriteHelper* file_write_helper = GetFileWriteHelper(profile);
-    if (!file_write_helper)
-      return;
-    base::FilePath remote_path(ExtractDrivePath(path));
-    file_write_helper->PrepareWritableFileAndRun(remote_path, callback);
-  } else {
+
+  FileSystemInterface* file_system = GetFileSystem(profile);
+  if (!file_system || !IsUnderDriveMountPoint(path)) {
     content::BrowserThread::GetBlockingPool()->PostTask(
-        FROM_HERE, base::Bind(callback, FILE_ERROR_OK, path));
+        FROM_HERE, base::Bind(callback, FILE_ERROR_FAILED, base::FilePath()));
+    return;
   }
+
+  WriteOnCacheFile(file_system,
+                   ExtractDrivePath(path),
+                   std::string(), // mime_type
+                   callback);
 }
 
 void EnsureDirectoryExists(Profile* profile,
@@ -424,5 +414,19 @@
   return MD5DigestToBase16(digest);
 }
 
+bool IsDriveEnabledForProfile(Profile* profile) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (!chromeos::IsProfileAssociatedWithGaiaAccount(profile))
+    return false;
+
+  // Disable Drive if preference is set. This can happen with commandline flag
+  // --disable-drive or enterprise policy, or with user settings.
+  if (profile->GetPrefs()->GetBoolean(prefs::kDisableDrive))
+    return false;
+
+  return true;
+}
+
 }  // namespace util
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_system_util.h b/chrome/browser/chromeos/drive/file_system_util.h
index e9879ad..165ddd9 100644
--- a/chrome/browser/chromeos/drive/file_system_util.h
+++ b/chrome/browser/chromeos/drive/file_system_util.h
@@ -88,9 +88,6 @@
 // Returns a ResourceEntry for "/drive/root" directory.
 ResourceEntry CreateMyDriveRootEntry(const std::string& root_resource_id);
 
-// Returns a ResourceEntry for "/drive/other" directory.
-ResourceEntry CreateOtherDirEntry();
-
 // Returns the Drive mount path as string.
 const std::string& GetDriveMountPointPathAsString();
 
@@ -151,19 +148,16 @@
 
 // Callback type for PrepareWritableFileAndRun.
 typedef base::Callback<void (FileError, const base::FilePath& path)>
-    OpenFileCallback;
+    PrepareWritableFileCallback;
 
 // Invokes |callback| on blocking thread pool, after converting virtual |path|
 // string like "/special/drive/foo.txt" to the concrete local cache file path.
 // After |callback| returns, the written content is synchronized to the server.
 //
-// If |path| is not a Drive path, it is regarded as a local path and no path
-// conversion takes place.
-//
-// Must be called from UI thread.
+// The |path| must be a path under Drive. Must be called from UI thread.
 void PrepareWritableFileAndRun(Profile* profile,
                                const base::FilePath& path,
-                               const OpenFileCallback& callback);
+                               const PrepareWritableFileCallback& callback);
 
 // Ensures the existence of |directory| of '/special/drive/foo'.  This will
 // create |directory| and its ancestors if they don't exist.  |callback| is
@@ -213,6 +207,9 @@
 // or an empty string if an error is found.
 std::string GetMd5Digest(const base::FilePath& file_path);
 
+// Returns true if Drive is enabled for the given Profile.
+bool IsDriveEnabledForProfile(Profile* profile);
+
 }  // namespace util
 }  // namespace drive
 
diff --git a/chrome/browser/chromeos/drive/file_write_helper.cc b/chrome/browser/chromeos/drive/file_write_helper.cc
deleted file mode 100644
index b5623ed..0000000
--- a/chrome/browser/chromeos/drive/file_write_helper.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 "chrome/browser/chromeos/drive/file_write_helper.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/threading/sequenced_worker_pool.h"
-#include "chrome/browser/chromeos/drive/file_system_interface.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
-
-namespace drive {
-
-FileWriteHelper::FileWriteHelper(FileSystemInterface* file_system)
-    : file_system_(file_system),
-      weak_ptr_factory_(this) {
-  // Must be created in DriveIntegrationService.
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-FileWriteHelper::~FileWriteHelper() {
-  // Must be destroyed in DriveIntegrationService.
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-void FileWriteHelper::PrepareWritableFileAndRun(
-    const base::FilePath& file_path,
-    const OpenFileCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-
-  file_system_->OpenFile(
-      file_path, OPEN_OR_CREATE_FILE,
-      base::Bind(&FileWriteHelper::PrepareWritableFileAndRunAfterOpenFile,
-                 weak_ptr_factory_.GetWeakPtr(), file_path, callback));
-}
-
-void FileWriteHelper::PrepareWritableFileAndRunAfterOpenFile(
-    const base::FilePath& file_path,
-    const OpenFileCallback& callback,
-    FileError error,
-    const base::FilePath& local_cache_path,
-    const base::Closure& close_callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-
-  if (error != FILE_ERROR_OK) {
-    content::BrowserThread::GetBlockingPool()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, error, base::FilePath()));
-    return;
-  }
-
-  content::BrowserThread::GetBlockingPool()->PostTaskAndReply(
-      FROM_HERE,
-      base::Bind(callback, FILE_ERROR_OK, local_cache_path),
-      close_callback);
-}
-
-}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_write_helper.h b/chrome/browser/chromeos/drive/file_write_helper.h
deleted file mode 100644
index 8a440ef..0000000
--- a/chrome/browser/chromeos/drive/file_write_helper.h
+++ /dev/null
@@ -1,64 +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_CHROMEOS_DRIVE_FILE_WRITE_HELPER_H_
-#define CHROME_BROWSER_CHROMEOS_DRIVE_FILE_WRITE_HELPER_H_
-
-#include "base/callback_forward.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/drive/file_errors.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace drive {
-
-class FileSystemInterface;
-
-// This class provides higher level operations for writing to Drive files over
-// FileSystemInterface.
-class FileWriteHelper {
- public:
-  // Callback for PrepareWritableFileAndRun.
-  typedef base::Callback<void(FileError error,
-                              const base::FilePath& file_path)>
-      OpenFileCallback;
-
-  explicit FileWriteHelper(FileSystemInterface* file_system);
-  ~FileWriteHelper();
-
-  // Prepares a local temporary file path and passes it to |callback| on the
-  // blocking thread pool that allows file operations. The modification to
-  // the file is reflected to GData |path|. If |path| does not exist, a new
-  // file is created.
-  //
-  // Must be called from UI thread.
-  void PrepareWritableFileAndRun(const base::FilePath& path,
-                                 const OpenFileCallback& callback);
-
- private:
-  // Part of PrepareWritableFilePathAndRun(). It tries CreateFile for the case
-  // file does not exist yet, does OpenFile to download and mark the file as
-  // dirty, runs |callback|, and finally closes the file.
-  void PrepareWritableFileAndRunAfterOpenFile(
-      const base::FilePath& file_path,
-      const OpenFileCallback& callback,
-      FileError result,
-      const base::FilePath& local_cache_path,
-      const base::Closure& close_callback);
-
-  FileSystemInterface* file_system_;  // Owned by DriveIntegrationService.
-
-  // WeakPtrFactory bound to the UI thread.
-  // 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<FileWriteHelper> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileWriteHelper);
-};
-
-}  // namespace drive
-
-#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_FILE_WRITE_HELPER_H_
diff --git a/chrome/browser/chromeos/drive/file_write_helper_unittest.cc b/chrome/browser/chromeos/drive/file_write_helper_unittest.cc
deleted file mode 100644
index 4270349..0000000
--- a/chrome/browser/chromeos/drive/file_write_helper_unittest.cc
+++ /dev/null
@@ -1,103 +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/chromeos/drive/file_write_helper.h"
-
-#include "base/bind.h"
-#include "chrome/browser/chromeos/drive/dummy_file_system.h"
-#include "chrome/browser/chromeos/drive/test_util.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-
-namespace {
-
-const base::FilePath::CharType kDrivePath[] =
-    FILE_PATH_LITERAL("drive/root/file.txt");
-const base::FilePath::CharType kInvalidPath[] =
-    FILE_PATH_LITERAL("drive/invalid/path");
-const base::FilePath::CharType kLocalPath[] =
-    FILE_PATH_LITERAL("/tmp/local.txt");
-
-class TestFileSystem : public DummyFileSystem {
- public:
-  TestFileSystem() : num_closed_(0) {
-  }
-
-  int num_closed() const { return num_closed_; }
-
-  // Mimics OpenFile. It fails if the |file_path| points to a hosted document.
-  virtual void OpenFile(const base::FilePath& file_path,
-                        OpenMode open_mode,
-                        const OpenFileCallback& callback) OVERRIDE {
-    EXPECT_EQ(OPEN_OR_CREATE_FILE, open_mode);
-
-    // Emulate a case of opening a hosted document.
-    if (file_path == base::FilePath(kInvalidPath)) {
-      callback.Run(FILE_ERROR_INVALID_OPERATION, base::FilePath(),
-                   base::Closure());
-      return;
-    }
-
-    callback.Run(FILE_ERROR_OK, base::FilePath(kLocalPath),
-                 base::Bind(&TestFileSystem::CloseFile,
-                            base::Unretained(this)));
-  }
-
- private:
-
-  void CloseFile() {
-    ++num_closed_;
-  }
-
-  int num_closed_;
-};
-
-}  // namespace
-
-class FileWriteHelperTest : public testing::Test {
- public:
-  FileWriteHelperTest()
-      : test_file_system_(new TestFileSystem) {
-  }
-
- protected:
-  content::TestBrowserThreadBundle thread_bundle_;
-  scoped_ptr<TestFileSystem> test_file_system_;
-};
-
-TEST_F(FileWriteHelperTest, PrepareFileForWritingSuccess) {
-  FileWriteHelper file_write_helper(test_file_system_.get());
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath path;
-  // The file should successfully be opened.
-  file_write_helper.PrepareWritableFileAndRun(
-      base::FilePath(kDrivePath),
-      google_apis::test_util::CreateCopyResultCallback(&error, &path));
-  test_util::RunBlockingPoolTask();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(kLocalPath, path.value());
-
-  // Make sure that the file is actually closed.
-  EXPECT_EQ(1, test_file_system_->num_closed());
-}
-
-TEST_F(FileWriteHelperTest, PrepareFileForWritingCreateFail) {
-  FileWriteHelper file_write_helper(test_file_system_.get());
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath path;
-  // Access to kInvalidPath should fail, and FileWriteHelper should not try to
-  // open or close the file.
-  file_write_helper.PrepareWritableFileAndRun(
-      base::FilePath(kInvalidPath),
-      google_apis::test_util::CreateCopyResultCallback(&error, &path));
-  test_util::RunBlockingPoolTask();
-
-  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
-  EXPECT_TRUE(path.empty());
-}
-
-}   // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_write_watcher.cc b/chrome/browser/chromeos/drive/file_write_watcher.cc
index 97c64d4..267eda2 100644
--- a/chrome/browser/chromeos/drive/file_write_watcher.cc
+++ b/chrome/browser/chromeos/drive/file_write_watcher.cc
@@ -5,13 +5,13 @@
 #include "chrome/browser/chromeos/drive/file_write_watcher.h"
 
 #include <map>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/file_path_watcher.h"
 #include "base/stl_util.h"
 #include "base/timer/timer.h"
-#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
 #include "chrome/browser/chromeos/drive/logging.h"
 #include "chrome/browser/google_apis/task_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -36,12 +36,12 @@
   // destruct the instance.
   void Destroy();
 
-  // Forwards the call to StartWatchOnFileThread(). |callback| is called back
-  // on the caller (UI) thread when the watch has started.
-  // |on_write_event_callback| is called when a write has happened to the path.
+  // Forwards the call to StartWatchOnFileThread(). |on_start_callback| is
+  // called back on the caller (UI) thread when the watch has started.
+  // |on_write_callback| is called when a write has happened to the path.
   void StartWatch(const base::FilePath& path,
-                  const StartWatchCallback& callback,
-                  const base::Closure& on_write_event_callback);
+                  const StartWatchCallback& on_start_callback,
+                  const base::Closure& on_write_callback);
 
   void set_delay(base::TimeDelta delay) { delay_ = delay; }
 
@@ -51,20 +51,20 @@
   void DestroyOnFileThread();
 
   void StartWatchOnFileThread(const base::FilePath& path,
-                              const StartWatchCallback& callback,
-                              const base::Closure& on_write_event_callback);
+                              const StartWatchCallback& on_start_callback,
+                              const base::Closure& on_write_callback);
 
   void OnWriteEvent(const base::FilePath& path, bool error);
 
   void InvokeCallback(const base::FilePath& path);
 
   struct PathWatchInfo {
-    base::Closure on_write_event_callback;
+    std::vector<base::Closure> on_write_callbacks;
     base::FilePathWatcher watcher;
     base::Timer timer;
 
-    explicit PathWatchInfo(const base::Closure& callback)
-        : on_write_event_callback(callback),
+    explicit PathWatchInfo(const base::Closure& on_write_callback)
+        : on_write_callbacks(1, on_write_callback),
           timer(false /* retain_closure_on_reset */, false /* is_repeating */) {
     }
   };
@@ -96,8 +96,8 @@
 
 void FileWriteWatcher::FileWriteWatcherImpl::StartWatch(
     const base::FilePath& path,
-    const StartWatchCallback& callback,
-    const base::Closure& on_write_event_callback) {
+    const StartWatchCallback& on_start_callback,
+    const base::Closure& on_write_callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   // Forwarding the call to FILE thread and relaying the |callback|.
@@ -106,8 +106,8 @@
       base::Bind(&FileWriteWatcherImpl::StartWatchOnFileThread,
                  base::Unretained(this),
                  path,
-                 google_apis::CreateRelayCallback(callback),
-                 google_apis::CreateRelayCallback(on_write_event_callback)));
+                 google_apis::CreateRelayCallback(on_start_callback),
+                 google_apis::CreateRelayCallback(on_write_callback)));
 }
 
 FileWriteWatcher::FileWriteWatcherImpl::~FileWriteWatcherImpl() {
@@ -124,28 +124,29 @@
 
 void FileWriteWatcher::FileWriteWatcherImpl::StartWatchOnFileThread(
     const base::FilePath& path,
-    const StartWatchCallback& callback,
-    const base::Closure& on_write_event_callback) {
+    const StartWatchCallback& on_start_callback,
+    const base::Closure& on_write_callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   util::Log(logging::LOG_INFO, "Started watching modification to %s.",
             path.AsUTF8Unsafe().c_str());
 
   std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
   if (it != watchers_.end()) {
-    // Do nothing if we are already watching the path.
-    callback.Run(true);
+    // We are already watching the path.
+    on_start_callback.Run(true);
+    it->second->on_write_callbacks.push_back(on_write_callback);
     return;
   }
 
   // Start watching |path|.
-  scoped_ptr<PathWatchInfo> info(new PathWatchInfo(on_write_event_callback));
+  scoped_ptr<PathWatchInfo> info(new PathWatchInfo(on_write_callback));
   bool ok = info->watcher.Watch(
       path,
       false,  // recursive
       base::Bind(&FileWriteWatcherImpl::OnWriteEvent,
                  weak_ptr_factory_.GetWeakPtr()));
   watchers_[path] = info.release();
-  callback.Run(ok);
+  on_start_callback.Run(ok);
 }
 
 void FileWriteWatcher::FileWriteWatcherImpl::OnWriteEvent(
@@ -181,17 +182,17 @@
   std::map<base::FilePath, PathWatchInfo*>::iterator it = watchers_.find(path);
   DCHECK(it != watchers_.end());
 
-  base::Closure callback = it->second->on_write_event_callback;
+  std::vector<base::Closure> callbacks;
+  callbacks.swap(it->second->on_write_callbacks);
   delete it->second;
   watchers_.erase(it);
 
-  callback.Run();
+  for (size_t i = 0; i < callbacks.size(); ++i)
+    callbacks[i].Run();
 }
 
-FileWriteWatcher::FileWriteWatcher(file_system::OperationObserver* observer)
-    : watcher_impl_(new FileWriteWatcherImpl),
-      operation_observer_(observer),
-      weak_ptr_factory_(this) {
+FileWriteWatcher::FileWriteWatcher()
+    : watcher_impl_(new FileWriteWatcherImpl) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 }
 
@@ -200,26 +201,15 @@
 }
 
 void FileWriteWatcher::StartWatch(const base::FilePath& file_path,
-                                  const std::string& resource_id,
-                                  const StartWatchCallback& callback) {
+                                  const StartWatchCallback& on_start_callback,
+                                  const base::Closure& on_write_callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  watcher_impl_->StartWatch(file_path,
-                            callback,
-                            base::Bind(&FileWriteWatcher::OnWriteEvent,
-                                       weak_ptr_factory_.GetWeakPtr(),
-                                       resource_id));
+  watcher_impl_->StartWatch(file_path, on_start_callback, on_write_callback);
 }
 
 void FileWriteWatcher::DisableDelayForTesting() {
   watcher_impl_->set_delay(base::TimeDelta());
 }
 
-void FileWriteWatcher::OnWriteEvent(const std::string& resource_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  operation_observer_->OnCacheFileUploadNeededByOperation(resource_id);
-}
-
 }  // namespace internal
 }  // namespace drive
diff --git a/chrome/browser/chromeos/drive/file_write_watcher.h b/chrome/browser/chromeos/drive/file_write_watcher.h
index 13523df..965ea66 100644
--- a/chrome/browser/chromeos/drive/file_write_watcher.h
+++ b/chrome/browser/chromeos/drive/file_write_watcher.h
@@ -7,7 +7,6 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 
 namespace base {
@@ -16,10 +15,6 @@
 
 namespace drive {
 
-namespace file_system {
-class OperationObserver;
-}  // namespace file_system
-
 namespace internal {
 
 typedef base::Callback<void(bool)> StartWatchCallback;
@@ -30,14 +25,13 @@
 // without any special handling about Drive.
 class FileWriteWatcher {
  public:
-  explicit FileWriteWatcher(file_system::OperationObserver* observer);
+  FileWriteWatcher();
   ~FileWriteWatcher();
 
   // Starts watching the modification to |path|. When it successfully started
-  // watching, it runs |callback| by passing true as the argument. Or if it
-  // failed, the callback is run with false.
-  // When modification is detected, it is notified to the |observer| passed to
-  // the constructor by calling OnCacheFileUploadNeededByOperation(resource_id).
+  // watching, it runs |on_start_callback| by passing true as the argument.
+  // Or if it failed, the callback is run with false.
+  // Detected modification is notified by calling |on_write_callback|.
   //
   // Currently, the modification is watched in "one-shot" manner. That is, once
   // a modification is notified, the watch is deactivated for freeing system
@@ -48,24 +42,17 @@
   // TODO(kinaba): investigate the possibility to continuously watch the whole
   // cache directory. http://crbug.com/269424
   void StartWatch(const base::FilePath& path,
-                  const std::string& resource_id,
-                  const StartWatchCallback& callback);
+                  const StartWatchCallback& on_start_callback,
+                  const base::Closure& on_write_callback);
 
   // For testing purpose, stops inserting delay between the write detection and
-  // notification to the observer.
+  // notification to the |on_write_callback|.
   void DisableDelayForTesting();
 
  private:
-  // Invoked when a modification is observed.
-  void OnWriteEvent(const std::string& resource_id);
-
   class FileWriteWatcherImpl;
   scoped_ptr<FileWriteWatcherImpl, util::DestroyHelper> watcher_impl_;
-  file_system::OperationObserver* operation_observer_;
 
-  // 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<FileWriteWatcher> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(FileWriteWatcher);
 };
 
diff --git a/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc b/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc
index 23be2a8..3bb06b1 100644
--- a/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_write_watcher_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/drive/file_system/operation_observer.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -19,7 +18,7 @@
 
 namespace {
 
-class TestObserver : public file_system::OperationObserver {
+class TestObserver {
  public:
   // After all the resource_ids in |expected_upload| are notified for the
   // need of uploading, runs |quit_closure|. Also checks that each id is
@@ -30,13 +29,9 @@
         quit_closure_(quit_closure) {
   }
 
-  virtual void OnDirectoryChangedByOperation(
-      const base::FilePath& path) OVERRIDE {}
-
-  virtual void OnCacheFileUploadNeededByOperation(
-      const std::string& resource_id) OVERRIDE {
-    EXPECT_EQ(1U, expected_upload_.count(resource_id)) << resource_id;
-    expected_upload_.erase(resource_id);
+  void OnWrite(const std::string& id) {
+    EXPECT_EQ(1U, expected_upload_.count(id)) << id;
+    expected_upload_.erase(id);
     if (expected_upload_.empty())
       quit_closure_.Run();
   }
@@ -93,7 +88,7 @@
   TestObserver observer(expected, loop.QuitClosure());
 
   // Set up the watcher.
-  FileWriteWatcher watcher(&observer);
+  FileWriteWatcher watcher;
   watcher.DisableDelayForTesting();
 
   // Start watching and running.
@@ -101,12 +96,18 @@
   base::FilePath path2 = GetTempPath("bar.png");
   base::FilePath path3 = GetTempPath("buz.doc");
   base::FilePath path4 = GetTempPath("mya.mp3");
-  watcher.StartWatch(path1, "1",
-                     base::Bind(&WriteSomethingAfterStartWatch, path1));
-  watcher.StartWatch(path2, "2",
-                     base::Bind(&WriteSomethingAfterStartWatch, path2));
-  watcher.StartWatch(path3, "3",
-                     base::Bind(&WriteSomethingAfterStartWatch, path3));
+  watcher.StartWatch(
+      path1,
+      base::Bind(&WriteSomethingAfterStartWatch, path1),
+      base::Bind(&TestObserver::OnWrite, base::Unretained(&observer), "1"));
+  watcher.StartWatch(
+      path2,
+      base::Bind(&WriteSomethingAfterStartWatch, path2),
+      base::Bind(&TestObserver::OnWrite, base::Unretained(&observer), "2"));
+  watcher.StartWatch(
+      path3,
+      base::Bind(&WriteSomethingAfterStartWatch, path3),
+      base::Bind(&TestObserver::OnWrite, base::Unretained(&observer), "3"));
 
   // Unwatched write. It shouldn't be notified.
   WriteSomethingAfterStartWatch(path4, true);
diff --git a/chrome/browser/chromeos/drive/fileapi_worker.cc b/chrome/browser/chromeos/drive/fileapi_worker.cc
index a9039d0..7cdab85 100644
--- a/chrome/browser/chromeos/drive/fileapi_worker.cc
+++ b/chrome/browser/chromeos/drive/fileapi_worker.cc
@@ -283,6 +283,7 @@
                 FileSystemInterface* file_system) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   file_system->CreateFile(file_path, is_exclusive,
+                          std::string(),  // no mime type; guess from file_path
                           base::Bind(&RunStatusCallbackByFileError, callback));
 }
 
@@ -313,6 +314,7 @@
   file_system->OpenFile(
       file_path,
       OPEN_FILE,
+      std::string(),  // no mime type; we never create a new file here.
       base::Bind(&RunCreateWritableSnapshotFileCallback, callback));
 }
 
@@ -343,6 +345,7 @@
 
   file_system->OpenFile(
       file_path, GetOpenMode(file_flags),
+      std::string(),  // no mime type; guess from file_path
       base::Bind(&OpenFileAfterFileSystemOpenFile, file_flags, callback));
 }
 
diff --git a/chrome/browser/chromeos/drive/job_list.cc b/chrome/browser/chromeos/drive/job_list.cc
index accb090..0ae803c 100644
--- a/chrome/browser/chromeos/drive/job_list.cc
+++ b/chrome/browser/chromeos/drive/job_list.cc
@@ -36,6 +36,8 @@
       return "TYPE_COPY_RESOURCE";
     case TYPE_COPY_HOSTED_DOCUMENT:
       return "TYPE_COPY_HOSTED_DOCUMENT";
+    case TYPE_MOVE_RESOURCE:
+      return "TYPE_MOVE_RESOURCE";
     case TYPE_RENAME_RESOURCE:
       return "TYPE_RENAME_RESOURCE";
     case TYPE_TOUCH_RESOURCE:
@@ -121,6 +123,7 @@
     case TYPE_DELETE_RESOURCE:
     case TYPE_COPY_RESOURCE:
     case TYPE_COPY_HOSTED_DOCUMENT:
+    case TYPE_MOVE_RESOURCE:
     case TYPE_RENAME_RESOURCE:
     case TYPE_TOUCH_RESOURCE:
     case TYPE_ADD_RESOURCE_TO_DIRECTORY:
diff --git a/chrome/browser/chromeos/drive/job_list.h b/chrome/browser/chromeos/drive/job_list.h
index dbd74b9..8318ec4 100644
--- a/chrome/browser/chromeos/drive/job_list.h
+++ b/chrome/browser/chromeos/drive/job_list.h
@@ -27,6 +27,7 @@
   TYPE_DELETE_RESOURCE,
   TYPE_COPY_RESOURCE,
   TYPE_COPY_HOSTED_DOCUMENT,
+  TYPE_MOVE_RESOURCE,
   TYPE_RENAME_RESOURCE,
   TYPE_TOUCH_RESOURCE,
   TYPE_ADD_RESOURCE_TO_DIRECTORY,
diff --git a/chrome/browser/chromeos/drive/job_scheduler.cc b/chrome/browser/chromeos/drive/job_scheduler.cc
index 682b3c1..079139d 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.cc
+++ b/chrome/browser/chromeos/drive/job_scheduler.cc
@@ -427,6 +427,29 @@
   StartJob(new_job);
 }
 
+void JobScheduler::MoveResource(
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const std::string& new_title,
+    const google_apis::GetResourceEntryCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  JobEntry* new_job = CreateNewJob(TYPE_MOVE_RESOURCE);
+  new_job->task = base::Bind(
+      &DriveServiceInterface::MoveResource,
+      base::Unretained(drive_service_),
+      resource_id,
+      parent_resource_id,
+      new_title,
+      base::Bind(&JobScheduler::OnGetResourceEntryJobDone,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 new_job->job_info.job_id,
+                 callback));
+  new_job->abort_callback = google_apis::CreateErrorRunCallback(callback);
+  StartJob(new_job);
+}
+
 void JobScheduler::RenameResource(
     const std::string& resource_id,
     const std::string& new_title,
@@ -1032,6 +1055,7 @@
     case TYPE_DELETE_RESOURCE:
     case TYPE_COPY_RESOURCE:
     case TYPE_COPY_HOSTED_DOCUMENT:
+    case TYPE_MOVE_RESOURCE:
     case TYPE_RENAME_RESOURCE:
     case TYPE_TOUCH_RESOURCE:
     case TYPE_ADD_RESOURCE_TO_DIRECTORY:
diff --git a/chrome/browser/chromeos/drive/job_scheduler.h b/chrome/browser/chromeos/drive/job_scheduler.h
index acd51ae..9d25786 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.h
+++ b/chrome/browser/chromeos/drive/job_scheduler.h
@@ -125,6 +125,13 @@
       const std::string& new_title,
       const google_apis::GetResourceEntryCallback& callback);
 
+  // Adds a MoveResource operation to the queue.
+  void MoveResource(
+      const std::string& resource_id,
+      const std::string& parent_resource_id,
+      const std::string& new_title,
+      const google_apis::GetResourceEntryCallback& callback);
+
   // Adds a RenameResource operation to the queue.
   void RenameResource(const std::string& resource_id,
                       const std::string& new_title,
diff --git a/chrome/browser/chromeos/drive/job_scheduler_unittest.cc b/chrome/browser/chromeos/drive/job_scheduler_unittest.cc
index 40050a3..920918a 100644
--- a/chrome/browser/chromeos/drive/job_scheduler_unittest.cc
+++ b/chrome/browser/chromeos/drive/job_scheduler_unittest.cc
@@ -367,6 +367,23 @@
   ASSERT_TRUE(entry);
 }
 
+TEST_F(JobSchedulerTest, MoveResource) {
+  ConnectToWifi();
+
+  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
+  scoped_ptr<google_apis::ResourceEntry> entry;
+
+  scheduler_->MoveResource(
+      "file:2_file_resource_id",  // resource ID
+      "folder:1_folder_resource_id",  // parent resource ID
+      "New Document",  // new title
+      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
+  ASSERT_TRUE(entry);
+}
+
 TEST_F(JobSchedulerTest, RenameResource) {
   ConnectToWifi();
 
diff --git a/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc b/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc
index 99ee919..bca7672 100644
--- a/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc
+++ b/chrome/browser/chromeos/drive/remove_stale_cache_files_unittest.cc
@@ -108,7 +108,7 @@
   ResourceEntry entry;
   entry.set_resource_id(resource_id_2);
   entry.mutable_file_specific_info()->set_md5(md5_2_metadata);
-  entry.set_parent_resource_id(util::kDriveGrandRootSpecialResourceId);
+  entry.set_parent_local_id(util::kDriveGrandRootSpecialResourceId);
   resource_metadata_->AddEntry(entry);
 
   // Remove stale cache files.
diff --git a/chrome/browser/chromeos/drive/resource_entry_conversion.cc b/chrome/browser/chromeos/drive/resource_entry_conversion.cc
index 216ff90..1b7b3c4 100644
--- a/chrome/browser/chromeos/drive/resource_entry_conversion.cc
+++ b/chrome/browser/chromeos/drive/resource_entry_conversion.cc
@@ -36,13 +36,15 @@
                             ResourceEntry* output) {
   DCHECK(output);
 
+  ResourceEntry converted;
+
   // For regular files, the 'filename' and 'title' attribute in the metadata
   // may be different (e.g. due to rename). To be consistent with the web
   // interface and other client to use the 'title' attribute, instead of
   // 'filename', as the file name in the local snapshot.
-  output->set_title(input.title());
-  output->set_base_name(util::NormalizeFileName(output->title()));
-  output->set_resource_id(input.resource_id());
+  converted.set_title(input.title());
+  converted.set_base_name(util::NormalizeFileName(converted.title()));
+  converted.set_resource_id(input.resource_id());
 
   // Sets parent Resource ID. On drive.google.com, a file can have multiple
   // parents or no parent, but we are forcing a tree-shaped structure (i.e. no
@@ -52,17 +54,17 @@
   const google_apis::Link* parent_link =
       input.GetLinkByType(google_apis::Link::LINK_PARENT);
   if (parent_link) {
-    output->set_parent_resource_id(util::ExtractResourceIdFromUrl(
+    converted.set_parent_local_id(util::ExtractResourceIdFromUrl(
         parent_link->href()));
   }
   // Apply mapping from an empty parent to the special dummy directory.
-  if (output->parent_resource_id().empty())
-    output->set_parent_resource_id(util::kDriveOtherDirSpecialResourceId);
+  if (converted.parent_local_id().empty())
+    converted.set_parent_local_id(util::kDriveOtherDirSpecialResourceId);
 
-  output->set_deleted(input.deleted());
-  output->set_shared_with_me(HasSharedWithMeLabel(input));
+  converted.set_deleted(input.deleted());
+  converted.set_shared_with_me(HasSharedWithMeLabel(input));
 
-  PlatformFileInfoProto* file_info = output->mutable_file_info();
+  PlatformFileInfoProto* file_info = converted.mutable_file_info();
 
   file_info->set_last_modified(input.updated_time().ToInternalValue());
   // If the file has never been viewed (last_viewed_time().is_null() == true),
@@ -71,7 +73,8 @@
   file_info->set_creation_time(input.published_time().ToInternalValue());
 
   if (input.is_file() || input.is_hosted_document()) {
-    FileSpecificInfo* file_specific_info = output->mutable_file_specific_info();
+    FileSpecificInfo* file_specific_info =
+        converted.mutable_file_specific_info();
     if (input.is_file()) {
       file_info->set_size(input.file_size());
       file_specific_info->set_md5(input.file_md5());
@@ -85,8 +88,8 @@
       // to UI through the File API stack.
       const std::string document_extension = input.GetHostedDocumentExtension();
       file_specific_info->set_document_extension(document_extension);
-      output->set_base_name(
-          util::NormalizeFileName(output->title() + document_extension));
+      converted.set_base_name(
+          util::NormalizeFileName(converted.title() + document_extension));
 
       // We don't know the size of hosted docs and it does not matter since
       // is has no effect on the quota.
@@ -115,9 +118,11 @@
     //   get an entry with only deleted() and resource_id() fields are
     //   filled. Since we want to delete such entries locally as well,
     //   in that case we need to return true to proceed.
-    return input.deleted();
+    if (!input.deleted())
+      return false;
   }
 
+  output->Swap(&converted);
   return true;
 }
 
diff --git a/chrome/browser/chromeos/drive/resource_entry_conversion.h b/chrome/browser/chromeos/drive/resource_entry_conversion.h
index 06a6730..7de8ef7 100644
--- a/chrome/browser/chromeos/drive/resource_entry_conversion.h
+++ b/chrome/browser/chromeos/drive/resource_entry_conversion.h
@@ -18,6 +18,18 @@
 class ResourceEntry;
 
 // Converts a google_apis::ResourceEntry into a drive::ResourceEntry.
+// If the conversion succeeded, return true and sets the result to |output|.
+// If failed, it returns false and keeps |*output| untouched.
+//
+// Every entry is guaranteed to have one parent resource ID in ResourceMetadata.
+// This requirement is needed to represent contents in Drive as a file system
+// tree, and achieved as follows:
+//
+// 1) Entries without parents are allowed on drive.google.com. These entries are
+// collected to "drive/other", and have "drive/other" as the parent.
+//
+// 2) Entries with multiple parents are allowed on drive.google.com. For these
+// entries, the first parent is chosen.
 bool ConvertToResourceEntry(const google_apis::ResourceEntry& input,
                             ResourceEntry* output);
 
diff --git a/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc b/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
index 372be9b..ff65313 100644
--- a/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_entry_conversion_unittest.cc
@@ -27,11 +27,10 @@
   ResourceEntry entry;
   EXPECT_TRUE(ConvertToResourceEntry(*gdata_resource_entry, &entry));
 
-  EXPECT_EQ("File 1.mp3",  entry.title());
-  EXPECT_EQ("File 1.mp3",  entry.base_name());
-  EXPECT_EQ("file:2_file_resource_id",  entry.resource_id());
-  EXPECT_EQ(util::kDriveOtherDirSpecialResourceId,
-            entry.parent_resource_id());
+  EXPECT_EQ("File 1.mp3", entry.title());
+  EXPECT_EQ("File 1.mp3", entry.base_name());
+  EXPECT_EQ("file:2_file_resource_id", entry.resource_id());
+  EXPECT_EQ(util::kDriveOtherDirSpecialResourceId, entry.parent_local_id());
 
   EXPECT_FALSE(entry.deleted());
   EXPECT_FALSE(entry.shared_with_me());
@@ -83,7 +82,7 @@
             entry.file_specific_info().alternate_url());
 
   // Regular file specific fields.
-  EXPECT_EQ(892721,  entry.file_info().size());
+  EXPECT_EQ(892721, entry.file_info().size());
   EXPECT_EQ("3b4382ebefec6e743578c76bbd0575ce",
             entry.file_specific_info().md5());
   EXPECT_FALSE(entry.file_info().is_directory());
@@ -103,12 +102,11 @@
   ResourceEntry entry;
   EXPECT_TRUE(ConvertToResourceEntry(*gdata_resource_entry, &entry));
 
-  EXPECT_EQ("Document 1",  entry.title());
-  EXPECT_EQ("Document 1.gdoc",  entry.base_name());  // The suffix added.
+  EXPECT_EQ("Document 1", entry.title());
+  EXPECT_EQ("Document 1.gdoc", entry.base_name());  // The suffix added.
   EXPECT_EQ(".gdoc", entry.file_specific_info().document_extension());
-  EXPECT_EQ("document:5_document_resource_id",  entry.resource_id());
-  EXPECT_EQ(util::kDriveOtherDirSpecialResourceId,
-            entry.parent_resource_id());
+  EXPECT_EQ("document:5_document_resource_id", entry.resource_id());
+  EXPECT_EQ(util::kDriveOtherDirSpecialResourceId, entry.parent_local_id());
 
   EXPECT_FALSE(entry.deleted());
   EXPECT_FALSE(entry.shared_with_me());
@@ -166,7 +164,7 @@
             entry.file_specific_info().alternate_url());
 
   // The size should be 0 for a hosted document.
-  EXPECT_EQ(0,  entry.file_info().size());
+  EXPECT_EQ(0, entry.file_info().size());
   EXPECT_FALSE(entry.file_info().is_directory());
 }
 
@@ -184,12 +182,12 @@
   ResourceEntry entry;
   EXPECT_TRUE(ConvertToResourceEntry(*gdata_resource_entry, &entry));
 
-  EXPECT_EQ("Sub Directory Folder",  entry.title());
-  EXPECT_EQ("Sub Directory Folder",  entry.base_name());
-  EXPECT_EQ("folder:sub_dir_folder_resource_id",  entry.resource_id());
+  EXPECT_EQ("Sub Directory Folder", entry.title());
+  EXPECT_EQ("Sub Directory Folder", entry.base_name());
+  EXPECT_EQ("folder:sub_dir_folder_resource_id", entry.resource_id());
   // The parent resource ID should be obtained as this is a sub directory
   // under a non-root directory.
-  EXPECT_EQ("folder:1_folder_resource_id",  entry.parent_resource_id());
+  EXPECT_EQ("folder:1_folder_resource_id", entry.parent_local_id());
 
   EXPECT_FALSE(entry.deleted());
   EXPECT_FALSE(entry.shared_with_me());
@@ -255,11 +253,10 @@
   ResourceEntry entry;
   EXPECT_TRUE(ConvertToResourceEntry(*gdata_resource_entry, &entry));
 
-  EXPECT_EQ("Deleted document",  entry.title());
-  EXPECT_EQ("Deleted document.gdoc",  entry.base_name());
-  EXPECT_EQ("document:deleted_in_root_id",  entry.resource_id());
-  EXPECT_EQ(util::kDriveOtherDirSpecialResourceId,
-            entry.parent_resource_id());
+  EXPECT_EQ("Deleted document", entry.title());
+  EXPECT_EQ("Deleted document.gdoc", entry.base_name());
+  EXPECT_EQ("document:deleted_in_root_id", entry.resource_id());
+  EXPECT_EQ(util::kDriveOtherDirSpecialResourceId, entry.parent_local_id());
 
   EXPECT_TRUE(entry.deleted());  // The document was deleted.
   EXPECT_FALSE(entry.shared_with_me());
@@ -317,7 +314,7 @@
             entry.file_specific_info().alternate_url());
 
   // The size should be 0 for a hosted document.
-  EXPECT_EQ(0,  entry.file_info().size());
+  EXPECT_EQ(0, entry.file_info().size());
 }
 
 TEST(ResourceEntryConversionTest,
diff --git a/chrome/browser/chromeos/drive/resource_metadata.cc b/chrome/browser/chromeos/drive/resource_metadata.cc
index 1bfc8f0..b942b0e 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata.cc
@@ -27,13 +27,6 @@
   entry->set_base_name(util::NormalizeFileName(base_name));
 }
 
-// Creates an entry by copying |source|, and setting the base name properly.
-ResourceEntry CreateEntryWithProperBaseName(const ResourceEntry& source) {
-  ResourceEntry entry(source);
-  SetBaseNameFromTitle(&entry);
-  return entry;
-}
-
 // Returns true if enough disk space is available for DB operation.
 // TODO(hashimoto): Merge this with FileCache's FreeDiskSpaceGetterInterface.
 bool EnoughDiskSpaceIsAvailableForDBOperation(const base::FilePath& path) {
@@ -105,11 +98,6 @@
 
 }  // namespace
 
-std::string DirectoryFetchInfo::ToString() const {
-  return ("resource_id: " + resource_id_ +
-          ", changestamp: " + base::Int64ToString(changestamp_));
-}
-
 EntryInfoResult::EntryInfoResult() : error(FILE_ERROR_FAILED) {
 }
 
@@ -188,18 +176,24 @@
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   // Initialize the grand root and "other" entries. "/drive" and "/drive/other".
-  // As an intermediate change, "/drive/root" is also added here.
   ResourceEntry entry;
   if (!storage_->GetEntry(util::kDriveGrandRootSpecialResourceId, &entry)) {
     ResourceEntry root;
     root.mutable_file_info()->set_is_directory(true);
     root.set_resource_id(util::kDriveGrandRootSpecialResourceId);
     root.set_title(util::kDriveGrandRootDirName);
-    if (!storage_->PutEntry(CreateEntryWithProperBaseName(root)))
+    SetBaseNameFromTitle(&root);
+    if (!storage_->PutEntry(util::kDriveGrandRootSpecialResourceId, root))
       return false;
   }
   if (!storage_->GetEntry(util::kDriveOtherDirSpecialResourceId, &entry)) {
-    if (!PutEntryUnderDirectory(util::CreateOtherDirEntry()))
+    ResourceEntry other_dir;
+    other_dir.mutable_file_info()->set_is_directory(true);
+    other_dir.set_resource_id(util::kDriveOtherDirSpecialResourceId);
+    other_dir.set_parent_local_id(util::kDriveGrandRootSpecialResourceId);
+    other_dir.set_title(util::kDriveOtherDirName);
+    if (!PutEntryUnderDirectory(util::kDriveOtherDirSpecialResourceId,
+                                other_dir))
       return false;
   }
   return true;
@@ -247,8 +241,8 @@
   if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_LOCAL_SPACE;
 
-  storage_->SetLargestChangestamp(value);
-  return FILE_ERROR_OK;
+  return storage_->SetLargestChangestamp(value) ?
+      FILE_ERROR_OK : FILE_ERROR_FAILED;
 }
 
 void ResourceMetadata::AddEntryOnUIThread(const ResourceEntry& entry,
@@ -273,66 +267,41 @@
     return FILE_ERROR_EXISTS;
 
   ResourceEntry parent;
-  if (!storage_->GetEntry(entry.parent_resource_id(), &parent) ||
+  if (!storage_->GetEntry(entry.parent_local_id(), &parent) ||
       !parent.file_info().is_directory())
     return FILE_ERROR_NOT_FOUND;
 
-  if (!PutEntryUnderDirectory(entry))
+  // TODO(hashimoto): Generate local ID here and pass it to the caller.
+  // crbug.com/26051
+  const std::string& id = entry.resource_id();
+
+  if (!PutEntryUnderDirectory(id, entry))
     return FILE_ERROR_FAILED;
 
   return FILE_ERROR_OK;
 }
 
-void ResourceMetadata::MoveEntryToDirectoryOnUIThread(
-    const base::FilePath& file_path,
-    const base::FilePath& directory_path,
-    const FileMoveCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-
-  PostFileMoveTask(blocking_task_runner_.get(),
-                   base::Bind(&ResourceMetadata::MoveEntryToDirectory,
-                              base::Unretained(this),
-                              file_path,
-                              directory_path),
-                   callback);
-}
-
-void ResourceMetadata::RenameEntryOnUIThread(const base::FilePath& file_path,
-                                             const std::string& new_name,
-                                             const FileMoveCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-
-  PostFileMoveTask(blocking_task_runner_.get(),
-                   base::Bind(&ResourceMetadata::RenameEntry,
-                              base::Unretained(this),
-                              file_path,
-                              new_name),
-                   callback);
-}
-
-FileError ResourceMetadata::RemoveEntry(const std::string& resource_id) {
+FileError ResourceMetadata::RemoveEntry(const std::string& id) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_LOCAL_SPACE;
 
   // Disallow deletion of special entries "/drive" and "/drive/other".
-  if (util::IsSpecialResourceId(resource_id))
+  if (util::IsSpecialResourceId(id))
     return FILE_ERROR_ACCESS_DENIED;
 
   ResourceEntry entry;
-  if (!storage_->GetEntry(resource_id, &entry))
+  if (!storage_->GetEntry(id, &entry))
     return FILE_ERROR_NOT_FOUND;
 
-  if (!RemoveEntryRecursively(entry.resource_id()))
+  if (!RemoveEntryRecursively(id))
     return FILE_ERROR_FAILED;
   return FILE_ERROR_OK;
 }
 
 void ResourceMetadata::GetResourceEntryByIdOnUIThread(
-    const std::string& resource_id,
+    const std::string& id,
     const GetResourceEntryCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
@@ -344,19 +313,18 @@
       FROM_HERE,
       base::Bind(&ResourceMetadata::GetResourceEntryById,
                  base::Unretained(this),
-                 resource_id,
+                 id,
                  entry_ptr),
       base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry)));
 }
 
-FileError ResourceMetadata::GetResourceEntryById(
-    const std::string& resource_id,
-    ResourceEntry* out_entry) {
+FileError ResourceMetadata::GetResourceEntryById(const std::string& id,
+                                                 ResourceEntry* out_entry) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(!resource_id.empty());
+  DCHECK(!id.empty());
   DCHECK(out_entry);
 
-  return storage_->GetEntry(resource_id, out_entry) ?
+  return storage_->GetEntry(id, out_entry) ?
       FILE_ERROR_OK : FILE_ERROR_NOT_FOUND;
 }
 
@@ -383,8 +351,12 @@
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
   DCHECK(out_entry);
 
-  return FindEntryByPathSync(path, out_entry) ?
-      FILE_ERROR_OK : FILE_ERROR_NOT_FOUND;
+  std::string id;
+  FileError error = GetIdByPath(path, &id);
+  if (error != FILE_ERROR_OK)
+    return error;
+
+  return GetResourceEntryById(id, out_entry);
 }
 
 void ResourceMetadata::ReadDirectoryByPathOnUIThread(
@@ -411,15 +383,21 @@
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
   DCHECK(out_entries);
 
+  std::string id;
+  FileError error = GetIdByPath(path, &id);
+  if (error != FILE_ERROR_OK)
+    return error;
+
   ResourceEntry entry;
-  if (!FindEntryByPathSync(path, &entry))
-    return FILE_ERROR_NOT_FOUND;
+  error = GetResourceEntryById(id, &entry);
+  if (error != FILE_ERROR_OK)
+    return error;
 
   if (!entry.file_info().is_directory())
     return FILE_ERROR_NOT_A_DIRECTORY;
 
   std::vector<std::string> children;
-  storage_->GetChildren(entry.resource_id(), &children);
+  storage_->GetChildren(id, &children);
 
   ResourceEntryVector entries(children.size());
   for (size_t i = 0; i < children.size(); ++i) {
@@ -430,69 +408,58 @@
   return FILE_ERROR_OK;
 }
 
-FileError ResourceMetadata::RefreshEntry(const ResourceEntry& entry) {
+FileError ResourceMetadata::RefreshEntry(const std::string& id,
+                                         const ResourceEntry& entry) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
     return FILE_ERROR_NO_LOCAL_SPACE;
 
   ResourceEntry old_entry;
-  if (!storage_->GetEntry(entry.resource_id(), &old_entry))
+  if (!storage_->GetEntry(id, &old_entry))
     return FILE_ERROR_NOT_FOUND;
 
-  if (old_entry.parent_resource_id().empty() ||  // Reject root.
+  if (old_entry.parent_local_id().empty() ||  // Reject root.
       old_entry.file_info().is_directory() !=  // Reject incompatible input.
       entry.file_info().is_directory())
     return FILE_ERROR_INVALID_OPERATION;
 
-  // Update data.
+  // Make sure that the new parent exists and it is a directory.
   ResourceEntry new_parent;
-  if (!storage_->GetEntry(entry.parent_resource_id(), &new_parent) ||
-      !new_parent.file_info().is_directory())
+  if (!storage_->GetEntry(entry.parent_local_id(), &new_parent))
     return FILE_ERROR_NOT_FOUND;
 
+  if (!new_parent.file_info().is_directory())
+    return FILE_ERROR_NOT_A_DIRECTORY;
+
   // Remove from the old parent and add it to the new parent with the new data.
-  if (!PutEntryUnderDirectory(CreateEntryWithProperBaseName(entry)))
+  if (!PutEntryUnderDirectory(id, entry))
     return FILE_ERROR_FAILED;
   return FILE_ERROR_OK;
 }
 
-void ResourceMetadata::RefreshDirectoryOnUIThread(
-    const DirectoryFetchInfo& directory_fetch_info,
-    const ResourceEntryMap& entry_map,
-    const FileMoveCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK(!callback.is_null());
-
-  PostFileMoveTask(blocking_task_runner_.get(),
-                   base::Bind(&ResourceMetadata::RefreshDirectory,
-                              base::Unretained(this),
-                              directory_fetch_info,
-                              entry_map),
-                   callback);
-}
-
-void ResourceMetadata::GetChildDirectories(
-    const std::string& resource_id,
-    std::set<base::FilePath>* child_directories) {
+void ResourceMetadata::GetSubDirectoriesRecursively(
+    const std::string& id,
+    std::set<base::FilePath>* sub_directories) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   std::vector<std::string> children;
-  storage_->GetChildren(resource_id, &children);
+  storage_->GetChildren(id, &children);
   for (size_t i = 0; i < children.size(); ++i) {
     ResourceEntry entry;
     if (storage_->GetEntry(children[i], &entry) &&
         entry.file_info().is_directory()) {
-      child_directories->insert(GetFilePath(entry.resource_id()));
-      GetChildDirectories(entry.resource_id(), child_directories);
+      sub_directories->insert(GetFilePath(children[i]));
+      GetSubDirectoriesRecursively(children[i], sub_directories);
     }
   }
 }
 
 std::string ResourceMetadata::GetChildResourceId(
-    const std::string& parent_resource_id, const std::string& base_name) {
+    const std::string& parent_local_id,
+    const std::string& base_name) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
-  return storage_->GetChild(parent_resource_id, base_name);
+  return storage_->GetChild(parent_local_id, base_name);
 }
 
 scoped_ptr<ResourceMetadata::Iterator> ResourceMetadata::GetIterator() {
@@ -501,104 +468,39 @@
   return storage_->GetIterator();
 }
 
-base::FilePath ResourceMetadata::GetFilePath(
-    const std::string& resource_id) {
+base::FilePath ResourceMetadata::GetFilePath(const std::string& id) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   base::FilePath path;
   ResourceEntry entry;
-  if (storage_->GetEntry(resource_id, &entry)) {
-    if (!entry.parent_resource_id().empty())
-      path = GetFilePath(entry.parent_resource_id());
+  if (storage_->GetEntry(id, &entry)) {
+    if (!entry.parent_local_id().empty())
+      path = GetFilePath(entry.parent_local_id());
     path = path.Append(base::FilePath::FromUTF8Unsafe(entry.base_name()));
   }
   return path;
 }
 
-FileError ResourceMetadata::MoveEntryToDirectory(
-    const base::FilePath& file_path,
-    const base::FilePath& directory_path,
-    base::FilePath* out_file_path) {
-  DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(!directory_path.empty());
-  DCHECK(!file_path.empty());
-  DCHECK(out_file_path);
-
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
-    return FILE_ERROR_NO_LOCAL_SPACE;
-
-  ResourceEntry entry, destination;
-  if (!FindEntryByPathSync(file_path, &entry) ||
-      !FindEntryByPathSync(directory_path, &destination))
-    return FILE_ERROR_NOT_FOUND;
-  if (!destination.file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  entry.set_parent_resource_id(destination.resource_id());
-
-  FileError error = RefreshEntry(entry);
-  if (error == FILE_ERROR_OK)
-    *out_file_path = GetFilePath(entry.resource_id());
-  return error;
-}
-
-FileError ResourceMetadata::RenameEntry(
-    const base::FilePath& file_path,
-    const std::string& new_title,
-    base::FilePath* out_file_path) {
-  DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(!file_path.empty());
-  DCHECK(!new_title.empty());
-  DCHECK(out_file_path);
-
-  DVLOG(1) << "RenameEntry " << file_path.value() << " to " << new_title;
-
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
-    return FILE_ERROR_NO_LOCAL_SPACE;
-
-  ResourceEntry entry;
-  if (!FindEntryByPathSync(file_path, &entry))
-    return FILE_ERROR_NOT_FOUND;
-
-  if (base::FilePath::FromUTF8Unsafe(new_title) == file_path.BaseName())
-    return FILE_ERROR_EXISTS;
-
-  entry.set_title(new_title);
-
-  FileError error = RefreshEntry(entry);
-  if (error == FILE_ERROR_OK)
-    *out_file_path = GetFilePath(entry.resource_id());
-  return error;
-}
-
-bool ResourceMetadata::FindEntryByPathSync(const base::FilePath& file_path,
-                                           ResourceEntry* out_entry) {
+FileError ResourceMetadata::GetIdByPath(const base::FilePath& file_path,
+                                        std::string* out_id) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   // Start from the root.
-  ResourceEntry entry;
-  if (!storage_->GetEntry(util::kDriveGrandRootSpecialResourceId, &entry))
-    return false;
-  DCHECK(entry.parent_resource_id().empty());
-
-  // Check the first component.
   std::vector<base::FilePath::StringType> components;
   file_path.GetComponents(&components);
-  if (components.empty() ||
-      base::FilePath(components[0]).AsUTF8Unsafe() != entry.base_name())
-    return scoped_ptr<ResourceEntry>();
+  if (components.empty() || components[0] != util::kDriveGrandRootDirName)
+    return FILE_ERROR_NOT_FOUND;
 
   // Iterate over the remaining components.
+  std::string id = util::kDriveGrandRootSpecialResourceId;
   for (size_t i = 1; i < components.size(); ++i) {
     const std::string component = base::FilePath(components[i]).AsUTF8Unsafe();
-    const std::string resource_id = storage_->GetChild(entry.resource_id(),
-                                                       component);
-    if (resource_id.empty() || !storage_->GetEntry(resource_id, &entry))
-      return false;
-    DCHECK_EQ(entry.base_name(), component);
+    id = storage_->GetChild(id, component);
+    if (id.empty())
+      return FILE_ERROR_NOT_FOUND;
   }
-  out_entry->Swap(&entry);
-  return true;
+  *out_id = id;
+  return FILE_ERROR_OK;
 }
 
 void ResourceMetadata::GetResourceEntryPairByPathsOnUIThread(
@@ -619,57 +521,6 @@
           callback));
 }
 
-FileError ResourceMetadata::RefreshDirectory(
-    const DirectoryFetchInfo& directory_fetch_info,
-    const ResourceEntryMap& entry_map,
-    base::FilePath* out_file_path) {
-  DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
-  DCHECK(!directory_fetch_info.empty());
-
-  if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
-    return FILE_ERROR_NO_LOCAL_SPACE;
-
-  ResourceEntry directory;
-  if (!storage_->GetEntry(directory_fetch_info.resource_id(), &directory))
-    return FILE_ERROR_NOT_FOUND;
-
-  if (!directory.file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  directory.mutable_directory_specific_info()->set_changestamp(
-      directory_fetch_info.changestamp());
-  storage_->PutEntry(directory);
-
-  // Go through the entry map. Handle existing entries and new entries.
-  for (ResourceEntryMap::const_iterator it = entry_map.begin();
-       it != entry_map.end(); ++it) {
-    if (!EnoughDiskSpaceIsAvailableForDBOperation(storage_->directory_path()))
-      return FILE_ERROR_NO_LOCAL_SPACE;
-
-    const ResourceEntry& entry = it->second;
-    // Skip if the parent resource ID does not match. This is needed to
-    // handle entries with multiple parents. For such entries, the first
-    // parent is picked and other parents are ignored, hence some entries may
-    // have a parent resource ID which does not match the target directory's.
-    //
-    // TODO(satorux): Move the filtering logic to somewhere more appropriate.
-    // crbug.com/193525.
-    if (entry.parent_resource_id() !=
-        directory_fetch_info.resource_id()) {
-      DVLOG(1) << "Wrong-parent entry rejected: " << entry.resource_id();
-      continue;
-    }
-
-    if (!PutEntryUnderDirectory(CreateEntryWithProperBaseName(entry)))
-      return FILE_ERROR_FAILED;
-  }
-
-  if (out_file_path)
-    *out_file_path = GetFilePath(directory.resource_id());
-
-  return FILE_ERROR_OK;
-}
-
 void ResourceMetadata::GetResourceEntryPairByPathsOnUIThreadAfterGetFirst(
     const base::FilePath& first_path,
     const base::FilePath& second_path,
@@ -719,8 +570,8 @@
   callback.Run(result.Pass());
 }
 
-bool ResourceMetadata::PutEntryUnderDirectory(
-    const ResourceEntry& entry) {
+bool ResourceMetadata::PutEntryUnderDirectory(const std::string& id,
+                                              const ResourceEntry& entry) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   ResourceEntry updated_entry(entry);
@@ -736,8 +587,8 @@
   std::string new_base_name = updated_entry.base_name();
   while (true) {
     const std::string existing_entry_id =
-        storage_->GetChild(entry.parent_resource_id(), new_base_name);
-    if (existing_entry_id.empty() || existing_entry_id == entry.resource_id())
+        storage_->GetChild(entry.parent_local_id(), new_base_name);
+    if (existing_entry_id.empty() || existing_entry_id == id)
       break;
 
     base::FilePath new_path =
@@ -751,26 +602,25 @@
   updated_entry.set_base_name(new_base_name);
 
   // Add the entry to resource map.
-  return storage_->PutEntry(updated_entry);
+  return storage_->PutEntry(id, updated_entry);
 }
 
-bool ResourceMetadata::RemoveEntryRecursively(
-    const std::string& resource_id) {
+bool ResourceMetadata::RemoveEntryRecursively(const std::string& id) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
 
   ResourceEntry entry;
-  if (!storage_->GetEntry(resource_id, &entry))
+  if (!storage_->GetEntry(id, &entry))
     return false;
 
   if (entry.file_info().is_directory()) {
     std::vector<std::string> children;
-    storage_->GetChildren(resource_id, &children);
+    storage_->GetChildren(id, &children);
     for (size_t i = 0; i < children.size(); ++i) {
       if (!RemoveEntryRecursively(children[i]))
         return false;
     }
   }
-  return storage_->RemoveEntry(resource_id);
+  return storage_->RemoveEntry(id);
 }
 
 }  // namespace internal
diff --git a/chrome/browser/chromeos/drive/resource_metadata.h b/chrome/browser/chromeos/drive/resource_metadata.h
index 848c2b2..06c9bea 100644
--- a/chrome/browser/chromeos/drive/resource_metadata.h
+++ b/chrome/browser/chromeos/drive/resource_metadata.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_DRIVE_RESOURCE_METADATA_H_
 #define CHROME_BROWSER_CHROMEOS_DRIVE_RESOURCE_METADATA_H_
 
-#include <map>
 #include <set>
 #include <string>
 #include <vector>
@@ -14,7 +13,6 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
 #include "chrome/browser/chromeos/drive/file_errors.h"
 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
 
@@ -24,40 +22,8 @@
 
 namespace drive {
 
-class ResourceEntry;
-
 typedef std::vector<ResourceEntry> ResourceEntryVector;
-typedef std::map<std::string /* resource_id */, ResourceEntry>
-    ResourceEntryMap;
 
-// Holds information needed to fetch contents of a directory.
-// This object is copyable.
-class DirectoryFetchInfo {
- public:
-  DirectoryFetchInfo() : changestamp_(0) {}
-  DirectoryFetchInfo(const std::string& resource_id,
-                     int64 changestamp)
-      : resource_id_(resource_id),
-        changestamp_(changestamp) {
-  }
-
-  // Returns true if the object is empty.
-  bool empty() const { return resource_id_.empty(); }
-
-  // Resource ID of the directory.
-  const std::string& resource_id() const { return resource_id_; }
-
-  // Changestamp of the directory. The changestamp is used to determine if
-  // the directory contents should be fetched.
-  int64 changestamp() const { return changestamp_; }
-
-  // Returns a string representation of this object.
-  std::string ToString() const;
-
- private:
-  const std::string resource_id_;
-  const int64 changestamp_;
-};
 
 // Callback similar to FileOperationCallback but with a given |file_path|.
 // Used for operations that change a file path like moving files.
@@ -151,36 +117,21 @@
   void AddEntryOnUIThread(const ResourceEntry& entry,
                           const FileMoveCallback& callback);
 
-  // Adds |entry| to the metadata tree based on its parent_resource_id
+  // Adds |entry| to the metadata tree based on its parent_local_id
   // synchronously.
   FileError AddEntry(const ResourceEntry& entry);
 
-  // Moves entry specified by |file_path| to the directory specified by
-  // |directory_path| and calls the callback asynchronously. Removes the entry
-  // from the previous parent. |callback| must not be null.
-  // Must be called on the UI thread.
-  void MoveEntryToDirectoryOnUIThread(const base::FilePath& file_path,
-                                      const base::FilePath& directory_path,
-                                      const FileMoveCallback& callback);
+  // Removes entry with |id| from its parent.
+  FileError RemoveEntry(const std::string& id);
 
-  // Renames entry specified by |file_path| with the new name |new_name| and
-  // calls |callback| asynchronously. |callback| must not be null.
-  // Must be called on the UI thread.
-  void RenameEntryOnUIThread(const base::FilePath& file_path,
-                             const std::string& new_name,
-                             const FileMoveCallback& callback);
-
-  // Removes entry with |resource_id| from its parent.
-  FileError RemoveEntry(const std::string& resource_id);
-
-  // Finds an entry (a file or a directory) by |resource_id|.
+  // Finds an entry (a file or a directory) by |id|.
   // |callback| must not be null.
   // Must be called on the UI thread.
-  void GetResourceEntryByIdOnUIThread(const std::string& resource_id,
+  void GetResourceEntryByIdOnUIThread(const std::string& id,
                                       const GetResourceEntryCallback& callback);
 
   // Synchronous version of GetResourceEntryByIdOnUIThread().
-  FileError GetResourceEntryById(const std::string& resource_id,
+  FileError GetResourceEntryById(const std::string& id,
                                  ResourceEntry* out_entry);
 
   // Finds an entry (a file or a directory) by |file_path|.
@@ -214,35 +165,27 @@
       const base::FilePath& second_path,
       const GetResourceEntryPairCallback& callback);
 
-  // Replaces an existing entry whose ID is |entry.resource_id()| with |entry|.
-  FileError RefreshEntry(const ResourceEntry& entry);
+  // Replaces an existing entry whose ID is |id| with |entry|.
+  FileError RefreshEntry(const std::string& id, const ResourceEntry& entry);
 
-  // Removes all child files of the directory pointed by
-  // |directory_fetch_info| and replaces them with
-  // |entry_map|. The changestamp of the directory will be updated per
-  // |directory_fetch_info|. |callback| is called with the directory path.
-  // |callback| must not be null.
-  // Must be called on the UI thread.
-  void RefreshDirectoryOnUIThread(
-      const DirectoryFetchInfo& directory_fetch_info,
-      const ResourceEntryMap& entry_map,
-      const FileMoveCallback& callback);
-
-  // Recursively get child directories of entry pointed to by |resource_id|.
-  void GetChildDirectories(const std::string& resource_id,
-                           std::set<base::FilePath>* child_directories);
+  // Recursively gets directories under the entry pointed to by |id|.
+  void GetSubDirectoriesRecursively(const std::string& id,
+                                    std::set<base::FilePath>* sub_directories);
 
   // Returns the resource id of the resource named |base_name| directly under
-  // the directory with |parent_resource_id|.
+  // the directory with |parent_local_id|.
   // If not found, empty string will be returned.
-  std::string GetChildResourceId(
-      const std::string& parent_resource_id, const std::string& base_name);
+  std::string GetChildResourceId(const std::string& parent_local_id,
+                                 const std::string& base_name);
 
   // Returns an object to iterate over entries.
   scoped_ptr<Iterator> GetIterator();
 
   // Returns virtual file path of the entry.
-  base::FilePath GetFilePath(const std::string& resource_id);
+  base::FilePath GetFilePath(const std::string& id);
+
+  // Returns ID of the entry at the given path.
+  FileError GetIdByPath(const base::FilePath& file_path, std::string* out_id);
 
  private:
   // Note: Use Destroy() to delete this object.
@@ -254,21 +197,6 @@
   // Used to implement Destroy().
   void DestroyOnBlockingPool();
 
-  // Used to implement MoveEntryToDirectoryOnUIThread().
-  FileError MoveEntryToDirectory(const base::FilePath& file_path,
-                                 const base::FilePath& directory_path,
-                                 base::FilePath* out_file_path);
-
-  // Used to implement RenameEntryOnUIThread().
-  FileError RenameEntry(const base::FilePath& file_path,
-                        const std::string& new_name,
-                        base::FilePath* out_file_path);
-
-  // Used to implement RefreshDirectoryOnUIThread().
-  FileError RefreshDirectory(const DirectoryFetchInfo& directory_fetch_info,
-                             const ResourceEntryMap& entry_map,
-                             base::FilePath* out_file_path);
-
   // Continues with GetResourceEntryPairByPathsOnUIThread after the first
   // entry has been asynchronously fetched. This fetches the second entry
   // only if the first was found.
@@ -288,18 +216,16 @@
       FileError error,
       scoped_ptr<ResourceEntry> entry);
 
-  // Searches for |file_path| synchronously.
-  bool FindEntryByPathSync(const base::FilePath& file_path,
-                           ResourceEntry* out_entry);
-
   // Puts an entry under its parent directory. Removes the child from the old
   // parent if there is. This method will also do name de-duplication to ensure
   // that the exposed presentation path does not have naming conflicts. Two
-  // files with the same name "Foo" will be renames to "Foo (1)" and "Foo (2)".
-  bool PutEntryUnderDirectory(const ResourceEntry& entry);
+  // files with the same name "Foo" will be renamed to "Foo (1)" and "Foo (2)".
+  // |id| is used as the ID of the entry.
+  bool PutEntryUnderDirectory(const std::string& id,
+                              const ResourceEntry& entry);
 
   // Removes the entry and its descendants.
-  bool RemoveEntryRecursively(const std::string& resource_id);
+  bool RemoveEntryRecursively(const std::string& id);
 
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
 
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage.cc b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
index 48505a5..71ac3ee 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.cc
@@ -12,6 +12,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
+#include "third_party/leveldatabase/env_chromium.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 
@@ -37,7 +38,7 @@
 const base::FilePath::CharType kChildMapDBName[] =
     FILE_PATH_LITERAL("resource_metadata_child_map.db");
 
-// Meant to be a character which never happen to be in real resource IDs.
+// Meant to be a character which never happen to be in real IDs.
 const char kDBKeyDelimeter = '\0';
 
 // String used as a suffix of a key for a cache entry.
@@ -57,8 +58,8 @@
 }
 
 // Returns a string to be used as a key for a cache entry.
-std::string GetCacheEntryKey(const std::string& resource_id) {
-  std::string key(resource_id);
+std::string GetCacheEntryKey(const std::string& id) {
+  std::string key(id);
   key.push_back(kDBKeyDelimeter);
   key.append(kCacheEntryKeySuffix);
   return key;
@@ -91,6 +92,39 @@
   return DB_INIT_FAILED;
 }
 
+// Returns true when the status indicates an unrecoverable error.
+bool IsUnrecoverableError(const leveldb::Status& status) {
+  leveldb_env::MethodID method;
+  int error = 0;
+  leveldb_env::ErrorParsingResult result = leveldb_env::ParseMethodAndError(
+      status.ToString().c_str(), &method, &error);
+  switch (result) {
+    case leveldb_env::METHOD_ONLY:
+    case leveldb_env::NONE:
+      return false;
+    case leveldb_env::METHOD_AND_PFE:
+      switch (static_cast<base::PlatformFileError>(error)) {
+        case base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED:
+        case base::PLATFORM_FILE_ERROR_NO_MEMORY:
+        case base::PLATFORM_FILE_ERROR_NO_SPACE:
+          return true;
+        default:
+          return false;
+      }
+    case leveldb_env::METHOD_AND_ERRNO:
+      switch (error) {
+        case EMFILE:
+        case ENOMEM:
+        case ENOSPC:
+          return true;
+        default:
+          return false;
+      }
+  }
+  NOTREACHED();
+  return false;
+}
+
 }  // namespace
 
 ResourceMetadataStorage::Iterator::Iterator(scoped_ptr<leveldb::Iterator> it)
@@ -115,7 +149,11 @@
   return !it_->Valid();
 }
 
-const ResourceEntry& ResourceMetadataStorage::Iterator::Get() const {
+std::string ResourceMetadataStorage::Iterator::GetID() const {
+  return it_->key().ToString();
+}
+
+const ResourceEntry& ResourceMetadataStorage::Iterator::GetValue() const {
   base::ThreadRestrictions::AssertIOAllowed();
   DCHECK(!IsAtEnd());
   return entry_;
@@ -181,7 +219,7 @@
 const std::string& ResourceMetadataStorage::CacheEntryIterator::GetID() const {
   base::ThreadRestrictions::AssertIOAllowed();
   DCHECK(!IsAtEnd());
-  return resource_id_;
+  return id_;
 }
 
 const FileCacheEntry&
@@ -213,7 +251,7 @@
       // Drop the suffix |kDBKeyDelimeter + kCacheEntryKeySuffix| from the key.
       const size_t kSuffixLength = arraysize(kCacheEntryKeySuffix) - 1;
       const int id_length = it_->key().size() - 1 - kSuffixLength;
-      resource_id_.assign(it_->key().data(), id_length);
+      id_.assign(it_->key().data(), id_length);
       break;
     }
   }
@@ -253,9 +291,9 @@
   options.create_if_missing = false;
 
   DBInitStatus open_existing_result = DB_INIT_NOT_FOUND;
+  leveldb::Status status;
   if (base::PathExists(resource_map_path)) {
-    leveldb::Status status =
-        leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
+    status = leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
     open_existing_result = LevelDBStatusToDBInitStatus(status);
   }
 
@@ -282,12 +320,13 @@
                             open_existing_result,
                             DB_INIT_MAX_VALUE);
 
+  if (IsUnrecoverableError(status))
+    return false;
+
   DBInitStatus init_result = DB_INIT_SUCCESS;
 
   // Failed to open the existing DB, create new DB.
   if (!resource_map_) {
-    resource_map_.reset();
-
     // Clean up the destination.
     const bool kRecursive = true;
     base::DeleteFile(resource_map_path, kRecursive);
@@ -296,8 +335,7 @@
     options.max_open_files = 0;  // Use minimum.
     options.create_if_missing = true;
 
-    leveldb::Status status =
-        leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
+    status = leveldb::DB::Open(options, resource_map_path.AsUTF8Unsafe(), &db);
     if (status.ok()) {
       resource_map_.reset(db);
 
@@ -343,13 +381,14 @@
   return header.largest_changestamp();
 }
 
-bool ResourceMetadataStorage::PutEntry(const ResourceEntry& entry) {
+bool ResourceMetadataStorage::PutEntry(const std::string& id,
+                                       const ResourceEntry& entry) {
   base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!entry.resource_id().empty());
+  DCHECK(!id.empty());
 
   std::string serialized_entry;
   if (!entry.SerializeToString(&serialized_entry)) {
-    DLOG(ERROR) << "Failed to serialize the entry: " << entry.resource_id();
+    DLOG(ERROR) << "Failed to serialize the entry: " << id;
     return false;
   }
 
@@ -357,55 +396,51 @@
 
   // Remove from the old parent.
   ResourceEntry old_entry;
-  if (GetEntry(entry.resource_id(), &old_entry) &&
-      !old_entry.parent_resource_id().empty()) {
-    batch.Delete(GetChildEntryKey(old_entry.parent_resource_id(),
+  if (GetEntry(id, &old_entry) && !old_entry.parent_local_id().empty()) {
+    batch.Delete(GetChildEntryKey(old_entry.parent_local_id(),
                                   old_entry.base_name()));
   }
 
   // Add to the new parent.
-  if (!entry.parent_resource_id().empty()) {
-    batch.Put(GetChildEntryKey(entry.parent_resource_id(), entry.base_name()),
-              entry.resource_id());
-  }
+  if (!entry.parent_local_id().empty())
+    batch.Put(GetChildEntryKey(entry.parent_local_id(), entry.base_name()), id);
 
   // Put the entry itself.
-  batch.Put(entry.resource_id(), serialized_entry);
+  batch.Put(id, serialized_entry);
 
   const leveldb::Status status = resource_map_->Write(leveldb::WriteOptions(),
                                                       &batch);
   return status.ok();
 }
 
-bool ResourceMetadataStorage::GetEntry(const std::string& resource_id,
+bool ResourceMetadataStorage::GetEntry(const std::string& id,
                                        ResourceEntry* out_entry) {
   base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!resource_id.empty());
+  DCHECK(!id.empty());
 
   std::string serialized_entry;
   const leveldb::Status status = resource_map_->Get(leveldb::ReadOptions(),
-                                                    leveldb::Slice(resource_id),
+                                                    leveldb::Slice(id),
                                                     &serialized_entry);
   return status.ok() && out_entry->ParseFromString(serialized_entry);
 }
 
-bool ResourceMetadataStorage::RemoveEntry(const std::string& resource_id) {
+bool ResourceMetadataStorage::RemoveEntry(const std::string& id) {
   base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!resource_id.empty());
+  DCHECK(!id.empty());
 
   ResourceEntry entry;
-  if (!GetEntry(resource_id, &entry))
+  if (!GetEntry(id, &entry))
     return false;
 
   leveldb::WriteBatch batch;
 
   // Remove from the parent.
-  if (!entry.parent_resource_id().empty()) {
-    batch.Delete(GetChildEntryKey(entry.parent_resource_id(),
-                                  entry.base_name()));
-  }
+  if (!entry.parent_local_id().empty())
+    batch.Delete(GetChildEntryKey(entry.parent_local_id(), entry.base_name()));
+
   // Remove the entry itself.
-  batch.Delete(resource_id);
+  batch.Delete(id);
 
   const leveldb::Status status = resource_map_->Write(leveldb::WriteOptions(),
                                                       &batch);
@@ -421,28 +456,26 @@
   return make_scoped_ptr(new Iterator(it.Pass()));
 }
 
-std::string ResourceMetadataStorage::GetChild(
-    const std::string& parent_resource_id,
-    const std::string& child_name) {
+std::string ResourceMetadataStorage::GetChild(const std::string& parent_id,
+                                              const std::string& child_name) {
   base::ThreadRestrictions::AssertIOAllowed();
 
-  std::string child_resource_id;
-  resource_map_->Get(
-      leveldb::ReadOptions(),
-      leveldb::Slice(GetChildEntryKey(parent_resource_id, child_name)),
-      &child_resource_id);
-  return child_resource_id;
+  std::string child_id;
+  resource_map_->Get(leveldb::ReadOptions(),
+                     leveldb::Slice(GetChildEntryKey(parent_id, child_name)),
+                     &child_id);
+  return child_id;
 }
 
-void ResourceMetadataStorage::GetChildren(const std::string& parent_resource_id,
+void ResourceMetadataStorage::GetChildren(const std::string& parent_id,
                                           std::vector<std::string>* children) {
   base::ThreadRestrictions::AssertIOAllowed();
 
-  // Iterate over all entries with keys starting with |parent_resource_id|.
+  // Iterate over all entries with keys starting with |parent_id|.
   scoped_ptr<leveldb::Iterator> it(
       resource_map_->NewIterator(leveldb::ReadOptions()));
-  for (it->Seek(parent_resource_id);
-       it->Valid() && it->key().starts_with(leveldb::Slice(parent_resource_id));
+  for (it->Seek(parent_id);
+       it->Valid() && it->key().starts_with(leveldb::Slice(parent_id));
        it->Next()) {
     if (IsChildEntryKey(it->key()))
       children->push_back(it->value().ToString());
@@ -450,10 +483,10 @@
   DCHECK(it->status().ok());
 }
 
-bool ResourceMetadataStorage::PutCacheEntry(const std::string& resource_id,
+bool ResourceMetadataStorage::PutCacheEntry(const std::string& id,
                                             const FileCacheEntry& entry) {
   base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!resource_id.empty());
+  DCHECK(!id.empty());
 
   std::string serialized_entry;
   if (!entry.SerializeToString(&serialized_entry)) {
@@ -463,31 +496,31 @@
 
   const leveldb::Status status = resource_map_->Put(
       leveldb::WriteOptions(),
-      leveldb::Slice(GetCacheEntryKey(resource_id)),
+      leveldb::Slice(GetCacheEntryKey(id)),
       leveldb::Slice(serialized_entry));
   return status.ok();
 }
 
-bool ResourceMetadataStorage::GetCacheEntry(const std::string& resource_id,
+bool ResourceMetadataStorage::GetCacheEntry(const std::string& id,
                                             FileCacheEntry* out_entry) {
   base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!resource_id.empty());
+  DCHECK(!id.empty());
 
   std::string serialized_entry;
   const leveldb::Status status = resource_map_->Get(
       leveldb::ReadOptions(),
-      leveldb::Slice(GetCacheEntryKey(resource_id)),
+      leveldb::Slice(GetCacheEntryKey(id)),
       &serialized_entry);
   return status.ok() && out_entry->ParseFromString(serialized_entry);
 }
 
-bool ResourceMetadataStorage::RemoveCacheEntry(const std::string& resource_id) {
+bool ResourceMetadataStorage::RemoveCacheEntry(const std::string& id) {
   base::ThreadRestrictions::AssertIOAllowed();
-  DCHECK(!resource_id.empty());
+  DCHECK(!id.empty());
 
   const leveldb::Status status = resource_map_->Delete(
       leveldb::WriteOptions(),
-      leveldb::Slice(GetCacheEntryKey(resource_id)));
+      leveldb::Slice(GetCacheEntryKey(id)));
   return status.ok();
 }
 
@@ -510,9 +543,9 @@
 
 // static
 std::string ResourceMetadataStorage::GetChildEntryKey(
-    const std::string& parent_resource_id,
+    const std::string& parent_id,
     const std::string& child_name) {
-  std::string key = parent_resource_id;
+  std::string key = parent_id;
   key.push_back(kDBKeyDelimeter);
   key.append(child_name);
   key.push_back(kDBKeyDelimeter);
@@ -586,7 +619,7 @@
   size_t num_child_entries = 0;
   ResourceEntry entry;
   std::string serialized_parent_entry;
-  std::string child_resource_id;
+  std::string child_id;
   for (it->Next(); it->Valid(); it->Next()) {
     // Count child entries.
     if (IsChildEntryKey(it->key())) {
@@ -599,17 +632,16 @@
       continue;
 
     // Check if stored data is broken.
-    if (!entry.ParseFromArray(it->value().data(), it->value().size()) ||
-        entry.resource_id() != it->key()) {
+    if (!entry.ParseFromArray(it->value().data(), it->value().size())) {
       DLOG(ERROR) << "Broken entry detected";
       return false;
     }
 
-    if (!entry.parent_resource_id().empty()) {
+    if (!entry.parent_local_id().empty()) {
       // Check if the parent entry is stored.
       leveldb::Status status = resource_map_->Get(
           options,
-          leveldb::Slice(entry.parent_resource_id()),
+          leveldb::Slice(entry.parent_local_id()),
           &serialized_parent_entry);
       if (!status.ok()) {
         DLOG(ERROR) << "Can't get parent entry. status = " << status.ToString();
@@ -619,10 +651,10 @@
       // Check if parent-child relationship is stored correctly.
       status = resource_map_->Get(
           options,
-          leveldb::Slice(GetChildEntryKey(entry.parent_resource_id(),
+          leveldb::Slice(GetChildEntryKey(entry.parent_local_id(),
                                           entry.base_name())),
-          &child_resource_id);
-      if (!status.ok() || child_resource_id != entry.resource_id()) {
+          &child_id);
+      if (!status.ok() || leveldb::Slice(child_id) != it->key()) {
         DLOG(ERROR) << "Child map is broken. 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 9c4621a..1635d1e 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage.h
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage.h
@@ -36,10 +36,7 @@
  public:
   // This should be incremented when incompatibility change is made to DB
   // format.
-  //
-  // Note: Skip '7' when incrementing this value next time. '7' has been used
-  // in the period between r208686 and r213797.
-  static const int kDBVersion = 6;
+  static const int kDBVersion = 8;
 
   // Object to iterate over entries stored in this storage.
   class Iterator {
@@ -51,8 +48,11 @@
     // to a valid entry. Get() and Advance() should not be called in such cases.
     bool IsAtEnd() const;
 
+    // Returns the ID of the entry currently pointed by this object.
+    std::string GetID() const;
+
     // Returns the entry currently pointed by this object.
-    const ResourceEntry& Get() const;
+    const ResourceEntry& GetValue() const;
 
     // Gets the cache entry which corresponds to |entry_| if available.
     bool GetCacheEntry(FileCacheEntry* cache_entry);
@@ -98,7 +98,7 @@
     void AdvanceInternal();
 
     scoped_ptr<leveldb::Iterator> it_;
-    std::string resource_id_;
+    std::string id_;
     FileCacheEntry entry_;
 
     DISALLOW_COPY_AND_ASSIGN(CacheEntryIterator);
@@ -126,34 +126,33 @@
   int64 GetLargestChangestamp();
 
   // Puts the entry to this storage.
-  bool PutEntry(const ResourceEntry& entry);
+  bool PutEntry(const std::string& id, const ResourceEntry& entry);
 
   // Gets an entry stored in this storage.
-  bool GetEntry(const std::string& resource_id, ResourceEntry* out_entry);
+  bool GetEntry(const std::string& id, ResourceEntry* out_entry);
 
   // Removes an entry from this storage.
-  bool RemoveEntry(const std::string& resource_id);
+  bool RemoveEntry(const std::string& id);
 
   // Returns an object to iterate over entries stored in this storage.
   scoped_ptr<Iterator> GetIterator();
 
-  // Returns resource ID of the parent's child.
-  std::string GetChild(const std::string& parent_resource_id,
+  // Returns the ID of the parent's child.
+  std::string GetChild(const std::string& parent_id,
                        const std::string& child_name);
 
-  // Returns resource IDs of the parent's children.
-  void GetChildren(const std::string& parent_resource_id,
+  // Returns the IDs of the parent's children.
+  void GetChildren(const std::string& parent_id,
                    std::vector<std::string>* children);
 
   // Puts the cache entry to this storage.
-  bool PutCacheEntry(const std::string& resource_id,
-                     const FileCacheEntry& entry);
+  bool PutCacheEntry(const std::string& id, const FileCacheEntry& entry);
 
   // Gets a cache entry stored in this storage.
-  bool GetCacheEntry(const std::string& resource_id, FileCacheEntry* out_entry);
+  bool GetCacheEntry(const std::string& id, FileCacheEntry* out_entry);
 
   // Removes a cache entry from this storage.
-  bool RemoveCacheEntry(const std::string& resource_id);
+  bool RemoveCacheEntry(const std::string& id);
 
   // Returns an object to iterate over cache entries stored in this storage.
   scoped_ptr<CacheEntryIterator> GetCacheEntryIterator();
@@ -168,7 +167,7 @@
   void DestroyOnBlockingPool();
 
   // Returns a string to be used as a key for child entry.
-  static std::string GetChildEntryKey(const std::string& parent_resource_id,
+  static std::string GetChildEntryKey(const std::string& parent_id,
                                       const std::string& child_name);
 
   // Puts header.
diff --git a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
index 667f920..b5d3825 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_storage_unittest.cc
@@ -40,23 +40,21 @@
   }
 
   // Puts a child entry.
-  void PutChild(const std::string& parent_resource_id,
+  void PutChild(const std::string& parent_id,
                 const std::string& child_base_name,
-                const std::string& child_resource_id) {
+                const std::string& child_id) {
     storage_->resource_map_->Put(
         leveldb::WriteOptions(),
-        ResourceMetadataStorage::GetChildEntryKey(parent_resource_id,
-                                                  child_base_name),
-        child_resource_id);
+        ResourceMetadataStorage::GetChildEntryKey(parent_id, child_base_name),
+        child_id);
   }
 
   // Removes a child entry.
-  void RemoveChild(const std::string& parent_resource_id,
+  void RemoveChild(const std::string& parent_id,
                    const std::string& child_base_name) {
     storage_->resource_map_->Delete(
         leveldb::WriteOptions(),
-        ResourceMetadataStorage::GetChildEntryKey(parent_resource_id,
-                                                  child_base_name));
+        ResourceMetadataStorage::GetChildEntryKey(parent_id, child_base_name));
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
@@ -79,28 +77,25 @@
   const std::string name3 = "EFGH";
 
   ResourceEntry entry1;
-  entry1.set_resource_id(key1);
 
   // key1 not found.
   ResourceEntry result;
   EXPECT_FALSE(storage_->GetEntry(key1, &result));
 
   // Put entry1.
-  EXPECT_TRUE(storage_->PutEntry(entry1));
+  EXPECT_TRUE(storage_->PutEntry(key1, entry1));
 
   // key1 found.
-  ASSERT_TRUE(storage_->GetEntry(key1, &result));
-  EXPECT_EQ(key1, result.resource_id());
+  EXPECT_TRUE(storage_->GetEntry(key1, &result));
 
   // key2 not found.
   EXPECT_FALSE(storage_->GetEntry(key2, &result));
 
   // Put entry2 as a child of entry1.
   ResourceEntry entry2;
-  entry2.set_parent_resource_id(key1);
-  entry2.set_resource_id(key2);
+  entry2.set_parent_local_id(key1);
   entry2.set_base_name(name2);
-  EXPECT_TRUE(storage_->PutEntry(entry2));
+  EXPECT_TRUE(storage_->PutEntry(key2, entry2));
 
   // key2 found.
   EXPECT_TRUE(storage_->GetEntry(key2, &result));
@@ -108,18 +103,17 @@
 
   // Put entry3 as a child of entry2.
   ResourceEntry entry3;
-  entry3.set_parent_resource_id(key2);
-  entry3.set_resource_id(key3);
+  entry3.set_parent_local_id(key2);
   entry3.set_base_name(name3);
-  EXPECT_TRUE(storage_->PutEntry(entry3));
+  EXPECT_TRUE(storage_->PutEntry(key3, entry3));
 
   // key3 found.
   EXPECT_TRUE(storage_->GetEntry(key3, &result));
   EXPECT_EQ(key3, storage_->GetChild(key2, name3));
 
   // Change entry3's parent to entry1.
-  entry3.set_parent_resource_id(key1);
-  EXPECT_TRUE(storage_->PutEntry(entry3));
+  entry3.set_parent_local_id(key1);
+  EXPECT_TRUE(storage_->PutEntry(key3, entry3));
 
   // entry3 is a child of entry1 now.
   EXPECT_TRUE(storage_->GetChild(key2, name3).empty());
@@ -136,25 +130,20 @@
 
 TEST_F(ResourceMetadataStorageTest, Iterator) {
   // Prepare data.
-  std::vector<ResourceEntry> entries;
-  ResourceEntry entry;
+  std::vector<std::string> keys;
 
-  entry.set_resource_id("entry1");
-  entries.push_back(entry);
-  entry.set_resource_id("entry2");
-  entries.push_back(entry);
-  entry.set_resource_id("entry3");
-  entries.push_back(entry);
-  entry.set_resource_id("entry4");
-  entries.push_back(entry);
+  keys.push_back("entry1");
+  keys.push_back("entry2");
+  keys.push_back("entry3");
+  keys.push_back("entry4");
 
-  for (size_t i = 0; i < entries.size(); ++i)
-    EXPECT_TRUE(storage_->PutEntry(entries[i]));
+  for (size_t i = 0; i < keys.size(); ++i)
+    EXPECT_TRUE(storage_->PutEntry(keys[i], ResourceEntry()));
 
   // Insert some cache entries.
   std::map<std::string, FileCacheEntry> cache_entries;
-  cache_entries[entries[0].resource_id()].set_md5("aaaaaa");
-  cache_entries[entries[1].resource_id()].set_md5("bbbbbb");
+  cache_entries[keys[0]].set_md5("aaaaaa");
+  cache_entries[keys[1]].set_md5("bbbbbb");
   for (std::map<std::string, FileCacheEntry>::iterator it =
            cache_entries.begin(); it != cache_entries.end(); ++it)
     EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
@@ -165,18 +154,18 @@
   scoped_ptr<ResourceMetadataStorage::Iterator> it = storage_->GetIterator();
   ASSERT_TRUE(it);
   for (; !it->IsAtEnd(); it->Advance()) {
-    const ResourceEntry& entry = it->Get();
-    found_entries[entry.resource_id()] = entry;
+    const ResourceEntry& entry = it->GetValue();
+    found_entries[it->GetID()] = entry;
 
     FileCacheEntry cache_entry;
     if (it->GetCacheEntry(&cache_entry))
-      found_cache_entries[entry.resource_id()] = cache_entry;
+      found_cache_entries[it->GetID()] = cache_entry;
   }
   EXPECT_FALSE(it->HasError());
 
-  EXPECT_EQ(entries.size(), found_entries.size());
-  for (size_t i = 0; i < entries.size(); ++i)
-    EXPECT_EQ(1U, found_entries.count(entries[i].resource_id()));
+  EXPECT_EQ(keys.size(), found_entries.size());
+  for (size_t i = 0; i < keys.size(); ++i)
+    EXPECT_EQ(1U, found_entries.count(keys[i]));
 
   EXPECT_EQ(cache_entries.size(), found_cache_entries.size());
   for (std::map<std::string, FileCacheEntry>::iterator it =
@@ -232,11 +221,8 @@
     EXPECT_TRUE(storage_->PutCacheEntry(it->first, it->second));
 
   // Insert some dummy entries.
-  ResourceEntry entry;
-  entry.set_resource_id("entry1");
-  EXPECT_TRUE(storage_->PutEntry(entry));
-  entry.set_resource_id("entry2");
-  EXPECT_TRUE(storage_->PutEntry(entry));
+  EXPECT_TRUE(storage_->PutEntry("entry1", ResourceEntry()));
+  EXPECT_TRUE(storage_->PutEntry("entry2", ResourceEntry()));
 
   // Iterate and check the result.
   scoped_ptr<ResourceMetadataStorage::CacheEntryIterator> it =
@@ -273,20 +259,16 @@
   children_name_id[4].push_back(std::make_pair("iapetus", "saturn_vii"));
 
   // Put parents.
-  for (size_t i = 0; i < arraysize(parents_id); ++i) {
-    ResourceEntry entry;
-    entry.set_resource_id(parents_id[i]);
-    EXPECT_TRUE(storage_->PutEntry(entry));
-  }
+  for (size_t i = 0; i < arraysize(parents_id); ++i)
+    EXPECT_TRUE(storage_->PutEntry(parents_id[i], ResourceEntry()));
 
   // Put children.
   for (size_t i = 0; i < children_name_id.size(); ++i) {
     for (size_t j = 0; j < children_name_id[i].size(); ++j) {
       ResourceEntry entry;
-      entry.set_parent_resource_id(parents_id[i]);
+      entry.set_parent_local_id(parents_id[i]);
       entry.set_base_name(children_name_id[i][j].first);
-      entry.set_resource_id(children_name_id[i][j].second);
-      EXPECT_TRUE(storage_->PutEntry(entry));
+      EXPECT_TRUE(storage_->PutEntry(children_name_id[i][j].second, entry));
     }
   }
 
@@ -315,15 +297,13 @@
   const std::string child_id1 = "qwerty";
 
   ResourceEntry entry1;
-  entry1.set_resource_id(parent_id1);
   ResourceEntry entry2;
-  entry2.set_resource_id(child_id1);
-  entry2.set_parent_resource_id(parent_id1);
+  entry2.set_parent_local_id(parent_id1);
   entry2.set_base_name(child_name1);
 
   // Put some data.
-  EXPECT_TRUE(storage_->PutEntry(entry1));
-  EXPECT_TRUE(storage_->PutEntry(entry2));
+  EXPECT_TRUE(storage_->PutEntry(parent_id1, entry1));
+  EXPECT_TRUE(storage_->PutEntry(child_id1, entry2));
 
   // Close DB and reopen.
   storage_.reset(new ResourceMetadataStorage(
@@ -332,12 +312,10 @@
 
   // Can read data.
   ResourceEntry result;
-  ASSERT_TRUE(storage_->GetEntry(parent_id1, &result));
-  EXPECT_EQ(parent_id1, result.resource_id());
+  EXPECT_TRUE(storage_->GetEntry(parent_id1, &result));
 
-  ASSERT_TRUE(storage_->GetEntry(child_id1, &result));
-  EXPECT_EQ(child_id1, result.resource_id());
-  EXPECT_EQ(parent_id1, result.parent_resource_id());
+  EXPECT_TRUE(storage_->GetEntry(child_id1, &result));
+  EXPECT_EQ(parent_id1, result.parent_local_id());
   EXPECT_EQ(child_name1, result.base_name());
 
   EXPECT_EQ(child_id1, storage_->GetChild(parent_id1, child_name1));
@@ -347,14 +325,11 @@
   const int64 kLargestChangestamp = 1234567890;
   const std::string key1 = "abcd";
 
-  ResourceEntry entry;
-  entry.set_resource_id(key1);
-
   // Put some data.
-  ResourceEntry result;
+  ResourceEntry entry;
   EXPECT_TRUE(storage_->SetLargestChangestamp(kLargestChangestamp));
-  EXPECT_TRUE(storage_->PutEntry(entry));
-  EXPECT_TRUE(storage_->GetEntry(key1, &result));
+  EXPECT_TRUE(storage_->PutEntry(key1, ResourceEntry()));
+  EXPECT_TRUE(storage_->GetEntry(key1, &entry));
 
   // Set incompatible version and reopen DB.
   SetDBVersion(ResourceMetadataStorage::kDBVersion - 1);
@@ -364,7 +339,7 @@
 
   // Data is erased because of the incompatible version.
   EXPECT_EQ(0, storage_->GetLargestChangestamp());
-  EXPECT_FALSE(storage_->GetEntry(key1, &result));
+  EXPECT_FALSE(storage_->GetEntry(key1, &entry));
 }
 
 TEST_F(ResourceMetadataStorageTest, WrongPath) {
@@ -391,16 +366,14 @@
 
   // Put entry with key1.
   ResourceEntry entry;
-  entry.set_resource_id(key1);
   entry.set_base_name(name1);
-  EXPECT_TRUE(storage_->PutEntry(entry));
+  EXPECT_TRUE(storage_->PutEntry(key1, entry));
   EXPECT_TRUE(CheckValidity());
 
   // Put entry with key2 under key1.
-  entry.set_resource_id(key2);
-  entry.set_parent_resource_id(key1);
+  entry.set_parent_local_id(key1);
   entry.set_base_name(name2);
-  EXPECT_TRUE(storage_->PutEntry(entry));
+  EXPECT_TRUE(storage_->PutEntry(key2, entry));
   EXPECT_TRUE(CheckValidity());
 
   RemoveChild(key1, name2);
@@ -415,10 +388,9 @@
   EXPECT_FALSE(CheckValidity());  // key3 is not stored in the storage.
 
   // Put entry with key3 under key2.
-  entry.set_resource_id(key3);
-  entry.set_parent_resource_id(key2);
+  entry.set_parent_local_id(key2);
   entry.set_base_name(name3);
-  EXPECT_TRUE(storage_->PutEntry(entry));
+  EXPECT_TRUE(storage_->PutEntry(key3, entry));
   EXPECT_TRUE(CheckValidity());
 
   // Parent-child relationship with wrong name.
diff --git a/chrome/browser/chromeos/drive/resource_metadata_unittest.cc b/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
index 4392c84..851c75b 100644
--- a/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
+++ b/chrome/browser/chromeos/drive/resource_metadata_unittest.cc
@@ -43,11 +43,11 @@
 
 // Creates a ResourceEntry for a directory.
 ResourceEntry CreateDirectoryEntry(const std::string& title,
-                                   const std::string& parent_resource_id) {
+                                   const std::string& parent_local_id) {
   ResourceEntry entry;
   entry.set_title(title);
   entry.set_resource_id("resource_id:" + title);
-  entry.set_parent_resource_id(parent_resource_id);
+  entry.set_parent_local_id(parent_local_id);
   entry.mutable_file_info()->set_is_directory(true);
   entry.mutable_directory_specific_info()->set_changestamp(kTestChangestamp);
   return entry;
@@ -55,11 +55,11 @@
 
 // Creates a ResourceEntry for a file.
 ResourceEntry CreateFileEntry(const std::string& title,
-                              const std::string& parent_resource_id) {
+                              const std::string& parent_local_id) {
   ResourceEntry entry;
   entry.set_title(title);
   entry.set_resource_id("resource_id:" + title);
-  entry.set_parent_resource_id(parent_resource_id);
+  entry.set_parent_local_id(parent_local_id);
   entry.mutable_file_info()->set_is_directory(false);
   entry.mutable_file_info()->set_size(1024);
   entry.mutable_file_specific_info()->set_md5("md5:" + title);
@@ -399,369 +399,6 @@
   ASSERT_FALSE(pair_result->second.entry.get());
 }
 
-TEST_F(ResourceMetadataTestOnUIThread, MoveEntryToDirectory) {
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath drive_file_path;
-  scoped_ptr<ResourceEntry> entry;
-
-  // Move file8 to drive/dir1.
-  resource_metadata_->MoveEntryToDirectoryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"),
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1"),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"),
-            drive_file_path);
-
-  // Look up the entry by its resource id and make sure it really moved.
-  resource_metadata_->GetResourceEntryByIdOnUIThread(
-      "resource_id:file8",
-      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Move non-existent file to drive/dir1. This should fail.
-  resource_metadata_->MoveEntryToDirectoryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"),
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1"),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-  EXPECT_EQ(base::FilePath(), drive_file_path);
-
-  // Move existing file to non-existent directory. This should fail.
-  resource_metadata_->MoveEntryToDirectoryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"),
-      base::FilePath::FromUTF8Unsafe("drive/root/dir4"),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-  EXPECT_EQ(base::FilePath(), drive_file_path);
-
-  // Move existing file to existing file (non-directory). This should fail.
-  resource_metadata_->MoveEntryToDirectoryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"),
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/file4"),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
-  EXPECT_EQ(base::FilePath(), drive_file_path);
-
-  // Move the file to root.
-  resource_metadata_->MoveEntryToDirectoryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/file8"),
-      base::FilePath::FromUTF8Unsafe("drive/root"),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/file8"),
-            drive_file_path);
-
-  // Move the file from root.
-  resource_metadata_->MoveEntryToDirectoryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/file8"),
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2"),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"),
-            drive_file_path);
-
-  // Make sure file is still ok.
-  resource_metadata_->GetResourceEntryByIdOnUIThread(
-      "resource_id:file8",
-      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-}
-
-TEST_F(ResourceMetadataTestOnUIThread, RenameEntry) {
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath drive_file_path;
-  scoped_ptr<ResourceEntry> entry;
-
-  // Rename file8 to file11.
-  resource_metadata_->RenameEntryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file8"),
-      "file11",
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file11"),
-            drive_file_path);
-
-  // Lookup the file by resource id to make sure the file actually got renamed.
-  resource_metadata_->GetResourceEntryByIdOnUIThread(
-      "resource_id:file8",
-      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Rename to file7 to force a duplicate name.
-  resource_metadata_->RenameEntryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file11"),
-      "file7",
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (1)"),
-            drive_file_path);
-
-  // Rename to same name. This should fail.
-  resource_metadata_->RenameEntryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file7 (1)"),
-      "file7 (1)",
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_EXISTS, error);
-  EXPECT_EQ(base::FilePath(), drive_file_path);
-
-  // Rename non-existent.
-  resource_metadata_->RenameEntryOnUIThread(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2/file11"),
-      "file11",
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &drive_file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-  EXPECT_EQ(base::FilePath(), drive_file_path);
-}
-
-TEST_F(ResourceMetadataTestOnUIThread, RefreshDirectory_EmptyMap) {
-  base::FilePath kDirectoryPath(FILE_PATH_LITERAL("drive/root/dir1"));
-  const int64 kNewChangestamp = kTestChangestamp + 1;
-
-  // Read the directory.
-  FileError error = FILE_ERROR_FAILED;
-  scoped_ptr<ResourceEntryVector> entries;
-  entries = ReadDirectoryByPathSync(base::FilePath(kDirectoryPath));
-  ASSERT_TRUE(entries.get());
-  // "file4", "file5", "dir3" should exist in drive/dir1.
-  ASSERT_EQ(3U, entries->size());
-  std::vector<std::string> base_names = GetSortedBaseNames(*entries);
-  EXPECT_EQ("dir3", base_names[0]);
-  EXPECT_EQ("file4", base_names[1]);
-  EXPECT_EQ("file5", base_names[2]);
-
-  // Get the directory.
-  scoped_ptr<ResourceEntry> dir1_proto;
-  dir1_proto = GetResourceEntryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(dir1_proto.get());
-  // The changestamp should be initially kTestChangestamp.
-  EXPECT_EQ(kTestChangestamp,
-            dir1_proto->directory_specific_info().changestamp());
-
-  // Update the directory with an empty map.
-  base::FilePath file_path;
-  ResourceEntryMap entry_map;
-  resource_metadata_->RefreshDirectoryOnUIThread(
-      DirectoryFetchInfo(dir1_proto->resource_id(), kNewChangestamp),
-      entry_map,
-      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(kDirectoryPath, file_path);
-
-  // Get the directory again.
-  dir1_proto = GetResourceEntryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(dir1_proto.get());
-  // The new changestamp should be set.
-  EXPECT_EQ(kNewChangestamp,
-            dir1_proto->directory_specific_info().changestamp());
-
-  // Read the directory again.
-  entries = ReadDirectoryByPathSync(base::FilePath(kDirectoryPath));
-  ASSERT_TRUE(entries.get());
-}
-
-TEST_F(ResourceMetadataTestOnUIThread, RefreshDirectory_NonEmptyMap) {
-  base::FilePath kDirectoryPath(FILE_PATH_LITERAL("drive/root/dir1"));
-  const int64 kNewChangestamp = kTestChangestamp + 1;
-
-  // Read the directory.
-  FileError error = FILE_ERROR_FAILED;
-  scoped_ptr<ResourceEntryVector> entries;
-  entries = ReadDirectoryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(entries.get());
-  // "file4", "file5", "dir3" should exist in drive/dir1.
-  ASSERT_EQ(3U, entries->size());
-  std::vector<std::string> base_names = GetSortedBaseNames(*entries);
-  EXPECT_EQ("dir3", base_names[0]);
-  EXPECT_EQ("file4", base_names[1]);
-  EXPECT_EQ("file5", base_names[2]);
-
-  // Get the directory dir1.
-  scoped_ptr<ResourceEntry> dir1_proto;
-  dir1_proto = GetResourceEntryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(dir1_proto.get());
-  // The changestamp should be initially kTestChangestamp.
-  EXPECT_EQ(kTestChangestamp,
-            dir1_proto->directory_specific_info().changestamp());
-
-  // Get the directory dir2 (existing non-child directory).
-  // This directory will be moved to "drive/dir1/dir2".
-  scoped_ptr<ResourceEntry> dir2_proto;
-  dir2_proto = GetResourceEntryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2"));
-  ASSERT_TRUE(dir2_proto.get());
-  EXPECT_EQ(kTestChangestamp,
-            dir2_proto->directory_specific_info().changestamp());
-  // Change the parent resource ID, as dir2 will be moved to "drive/dir1/dir2".
-  dir2_proto->set_parent_resource_id(dir1_proto->resource_id());
-
-  // Get the directory dir3 (existing child directory).
-  // This directory will remain as "drive/dir1/dir3".
-  scoped_ptr<ResourceEntry> dir3_proto;
-  dir3_proto = GetResourceEntryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"));
-  ASSERT_TRUE(dir3_proto.get());
-  EXPECT_EQ(kTestChangestamp,
-            dir3_proto->directory_specific_info().changestamp());
-
-  // Create a map.
-  ResourceEntryMap entry_map;
-
-  // Add a new file to the map.
-  ResourceEntry new_file;
-  new_file.set_title("new_file");
-  new_file.set_resource_id("new_file_id");
-  new_file.set_parent_resource_id(dir1_proto->resource_id());
-  entry_map["new_file_id"] = new_file;
-
-  // Add a new directory to the map.
-  ResourceEntry new_directory;
-  new_directory.set_title("new_directory");
-  new_directory.set_resource_id("new_directory_id");
-  new_directory.set_parent_resource_id(dir1_proto->resource_id());
-  new_directory.mutable_file_info()->set_is_directory(true);
-  entry_map["new_directory_id"] = new_directory;
-
-  // Add dir2 and dir3 as well.
-  entry_map[dir2_proto->resource_id()] = *dir2_proto;
-  entry_map[dir3_proto->resource_id()] = *dir3_proto;
-
-  // Update the directory with the map.
-  base::FilePath file_path;
-  resource_metadata_->RefreshDirectoryOnUIThread(
-      DirectoryFetchInfo(dir1_proto->resource_id(), kNewChangestamp),
-      entry_map,
-      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(kDirectoryPath, file_path);
-
-  // Get the directory again.
-  dir1_proto = GetResourceEntryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(dir1_proto.get());
-  // The new changestamp should be set.
-  EXPECT_EQ(kNewChangestamp,
-            dir1_proto->directory_specific_info().changestamp());
-
-  // Read the directory again.
-  entries = ReadDirectoryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(entries.get());
-  // "new_file", "new_directory", "dir2" should now be added.
-  base_names = GetSortedBaseNames(*entries);
-  EXPECT_EQ(1, std::count(base_names.begin(), base_names.end(), "dir2"));
-  EXPECT_EQ(1,
-            std::count(base_names.begin(), base_names.end(), "new_directory"));
-  EXPECT_EQ(1,
-            std::count(base_names.begin(), base_names.end(), "new_file"));
-
-  // Get the new directory.
-  scoped_ptr<ResourceEntry> new_directory_proto;
-  new_directory_proto = GetResourceEntryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/new_directory"));
-  ASSERT_TRUE(new_directory_proto.get());
-  // The changestamp should be 0 for a new directory.
-  EXPECT_EQ(0, new_directory_proto->directory_specific_info().changestamp());
-
-  // Get the directory dir3 (existing child directory) again.
-  dir3_proto = GetResourceEntryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"));
-  ASSERT_TRUE(dir3_proto.get());
-  // The changestamp should not be changed.
-  EXPECT_EQ(kTestChangestamp,
-            dir3_proto->directory_specific_info().changestamp());
-
-  // Read the directory dir3. The contents should remain.
-  // See the comment at Init() for the contents of the dir3.
-  entries = ReadDirectoryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3"));
-  ASSERT_TRUE(entries.get());
-  ASSERT_EQ(2U, entries->size());
-
-  // Get the directory dir2 (existing non-child directory) again using the
-  // old path.  This should fail, as dir2 is now moved to drive/dir1/dir2.
-  dir2_proto = GetResourceEntryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2"));
-  ASSERT_FALSE(dir2_proto.get());
-
-  // Get the directory dir2 (existing non-child directory) again using the
-  // new path. This should succeed.
-  dir2_proto = GetResourceEntryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir2"));
-  ASSERT_TRUE(dir2_proto.get());
-  // The changestamp should not be changed.
-  EXPECT_EQ(kTestChangestamp,
-            dir2_proto->directory_specific_info().changestamp());
-
-  // Read the directory dir2. The contents should remain.
-  // See the comment at Init() for the contents of the dir2.
-  entries = ReadDirectoryByPathSync(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir2"));
-  ASSERT_TRUE(entries.get());
-  ASSERT_EQ(3U, entries->size());
-}
-
-TEST_F(ResourceMetadataTestOnUIThread, RefreshDirectory_WrongParentResourceId) {
-  base::FilePath kDirectoryPath(FILE_PATH_LITERAL("drive/root/dir1"));
-  const int64 kNewChangestamp = kTestChangestamp + 1;
-
-  // Get the directory dir1.
-  scoped_ptr<ResourceEntry> dir1_proto;
-  dir1_proto = GetResourceEntryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(dir1_proto.get());
-
-  // Create a map and add a new file to it.
-  ResourceEntryMap entry_map;
-  ResourceEntry new_file;
-  new_file.set_title("new_file");
-  new_file.set_resource_id("new_file_id");
-  // Set a random parent resource ID. This entry should not be added because
-  // the parent resource ID does not match dir1_proto->resource_id().
-  new_file.set_parent_resource_id("some-random-resource-id");
-  entry_map["new_file_id"] = new_file;
-
-  // Update the directory with the map.
-  base::FilePath file_path;
-  FileError error = FILE_ERROR_FAILED;
-  resource_metadata_->RefreshDirectoryOnUIThread(
-      DirectoryFetchInfo(dir1_proto->resource_id(), kNewChangestamp),
-      entry_map,
-      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
-  test_util::RunBlockingPoolTask();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(kDirectoryPath, file_path);
-
-  // Read the directory. Confirm that the new file is not added.
-  scoped_ptr<ResourceEntryVector> entries;
-  entries = ReadDirectoryByPathSync(kDirectoryPath);
-  ASSERT_TRUE(entries.get());
-  std::vector<std::string> base_names = GetSortedBaseNames(*entries);
-  EXPECT_EQ(0, std::count(base_names.begin(), base_names.end(), "new_file"));
-}
-
 TEST_F(ResourceMetadataTestOnUIThread, AddEntry) {
   FileError error = FILE_ERROR_FAILED;
   base::FilePath drive_file_path;
@@ -880,8 +517,11 @@
   ResourceEntry entry;
 
   // Get file9.
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &entry));
+  std::string file_id;
+  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
+      base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3/file9"), &file_id));
+  EXPECT_EQ(FILE_ERROR_OK,
+            resource_metadata_->GetResourceEntryById(file_id, &entry));
   EXPECT_EQ("file9", entry.base_name());
   EXPECT_TRUE(!entry.file_info().is_directory());
   EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
@@ -889,14 +529,14 @@
   // Rename it.
   ResourceEntry file_entry(entry);
   file_entry.set_title("file100");
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(file_entry));
+  EXPECT_EQ(FILE_ERROR_OK,
+            resource_metadata_->RefreshEntry(file_id, file_entry));
 
-  EXPECT_EQ(
-      "drive/root/dir1/dir3/file100",
-      resource_metadata_->GetFilePath(file_entry.resource_id()).AsUTF8Unsafe());
+  EXPECT_EQ("drive/root/dir1/dir3/file100",
+            resource_metadata_->GetFilePath(file_id).AsUTF8Unsafe());
   entry.Clear();
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
-      file_entry.resource_id(), &entry));
+  EXPECT_EQ(FILE_ERROR_OK,
+            resource_metadata_->GetResourceEntryById(file_id, &entry));
   EXPECT_EQ("file100", entry.base_name());
   EXPECT_TRUE(!entry.file_info().is_directory());
   EXPECT_EQ("md5:file9", entry.file_specific_info().md5());
@@ -905,14 +545,14 @@
   const std::string updated_md5("md5:updated");
   file_entry = entry;
   file_entry.mutable_file_specific_info()->set_md5(updated_md5);
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(file_entry));
+  EXPECT_EQ(FILE_ERROR_OK,
+            resource_metadata_->RefreshEntry(file_id, file_entry));
 
-  EXPECT_EQ(
-      "drive/root/dir1/dir3/file100",
-      resource_metadata_->GetFilePath(file_entry.resource_id()).AsUTF8Unsafe());
+  EXPECT_EQ("drive/root/dir1/dir3/file100",
+            resource_metadata_->GetFilePath(file_id).AsUTF8Unsafe());
   entry.Clear();
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
-      file_entry.resource_id(), &entry));
+  EXPECT_EQ(FILE_ERROR_OK,
+            resource_metadata_->GetResourceEntryById(file_id, &entry));
   EXPECT_EQ("file100", entry.base_name());
   EXPECT_TRUE(!entry.file_info().is_directory());
   EXPECT_EQ(updated_md5, entry.file_specific_info().md5());
@@ -927,23 +567,25 @@
 
   // Get dir2.
   entry.Clear();
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryByPath(
-      base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry));
+  std::string dir_id;
+  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetIdByPath(
+      base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &dir_id));
+  EXPECT_EQ(FILE_ERROR_OK,
+            resource_metadata_->GetResourceEntryById(dir_id, &entry));
   EXPECT_EQ("dir2", entry.base_name());
   ASSERT_TRUE(entry.file_info().is_directory());
 
   // Change the name to dir100 and change the parent to drive/dir1/dir3.
   ResourceEntry dir_entry(entry);
   dir_entry.set_title("dir100");
-  dir_entry.set_parent_resource_id("resource_id:dir3");
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_entry));
+  dir_entry.set_parent_local_id("resource_id:dir3");
+  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->RefreshEntry(dir_id, dir_entry));
 
-  EXPECT_EQ(
-      "drive/root/dir1/dir3/dir100",
-      resource_metadata_->GetFilePath(dir_entry.resource_id()).AsUTF8Unsafe());
+  EXPECT_EQ("drive/root/dir1/dir3/dir100",
+            resource_metadata_->GetFilePath(dir_id).AsUTF8Unsafe());
   entry.Clear();
-  EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->GetResourceEntryById(
-      dir_entry.resource_id(), &entry));
+  EXPECT_EQ(FILE_ERROR_OK,
+            resource_metadata_->GetResourceEntryById(dir_id, &entry));
   EXPECT_EQ("dir100", entry.base_name());
   EXPECT_TRUE(entry.file_info().is_directory());
   EXPECT_EQ("resource_id:dir2", entry.resource_id());
@@ -959,35 +601,40 @@
   EXPECT_EQ(FILE_ERROR_NOT_FOUND, resource_metadata_->GetResourceEntryByPath(
       base::FilePath::FromUTF8Unsafe("drive/root/dir2"), &entry));
 
+  // Make sure that directory cannot move under a file.
+  dir_entry.set_parent_local_id(file_id);
+  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY,
+            resource_metadata_->RefreshEntry(dir_id, dir_entry));
+
   // Cannot refresh root.
   dir_entry.Clear();
   dir_entry.set_resource_id(util::kDriveGrandRootSpecialResourceId);
   dir_entry.set_title("new-root-name");
-  dir_entry.set_parent_resource_id("resource_id:dir1");
-  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION,
-            resource_metadata_->RefreshEntry(dir_entry));
+  dir_entry.set_parent_local_id("resource_id:dir1");
+  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, resource_metadata_->RefreshEntry(
+      util::kDriveGrandRootSpecialResourceId, dir_entry));
 }
 
-TEST_F(ResourceMetadataTest, GetChildDirectories) {
-  std::set<base::FilePath> child_directories;
+TEST_F(ResourceMetadataTest, GetSubDirectoriesRecursively) {
+  std::set<base::FilePath> sub_directories;
 
   // file9: not a directory, so no children.
-  resource_metadata_->GetChildDirectories("resource_id:file9",
-                                          &child_directories);
-  EXPECT_TRUE(child_directories.empty());
+  resource_metadata_->GetSubDirectoriesRecursively("resource_id:file9",
+                                                   &sub_directories);
+  EXPECT_TRUE(sub_directories.empty());
 
   // dir2: no child directories.
-  resource_metadata_->GetChildDirectories("resource_id:dir2",
-                                          &child_directories);
-  EXPECT_TRUE(child_directories.empty());
+  resource_metadata_->GetSubDirectoriesRecursively("resource_id:dir2",
+                                                   &sub_directories);
+  EXPECT_TRUE(sub_directories.empty());
 
   // dir1: dir3 is the only child
-  resource_metadata_->GetChildDirectories("resource_id:dir1",
-                                          &child_directories);
-  EXPECT_EQ(1u, child_directories.size());
-  EXPECT_EQ(1u, child_directories.count(
+  resource_metadata_->GetSubDirectoriesRecursively("resource_id:dir1",
+                                                   &sub_directories);
+  EXPECT_EQ(1u, sub_directories.size());
+  EXPECT_EQ(1u, sub_directories.count(
       base::FilePath::FromUTF8Unsafe("drive/root/dir1/dir3")));
-  child_directories.clear();
+  sub_directories.clear();
 
   // Add a few more directories to make sure deeper nesting works.
   // dir2/dir100
@@ -1015,14 +662,14 @@
   EXPECT_EQ(FILE_ERROR_OK, resource_metadata_->AddEntry(
       CreateDirectoryEntry("dir107", "resource_id:dir106")));
 
-  resource_metadata_->GetChildDirectories("resource_id:dir2",
-                                          &child_directories);
-  EXPECT_EQ(8u, child_directories.size());
-  EXPECT_EQ(1u, child_directories.count(base::FilePath::FromUTF8Unsafe(
+  resource_metadata_->GetSubDirectoriesRecursively("resource_id:dir2",
+                                                   &sub_directories);
+  EXPECT_EQ(8u, sub_directories.size());
+  EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
       "drive/root/dir2/dir101")));
-  EXPECT_EQ(1u, child_directories.count(base::FilePath::FromUTF8Unsafe(
+  EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
       "drive/root/dir2/dir101/dir104")));
-  EXPECT_EQ(1u, child_directories.count(base::FilePath::FromUTF8Unsafe(
+  EXPECT_EQ(1u, sub_directories.count(base::FilePath::FromUTF8Unsafe(
       "drive/root/dir2/dir101/dir102/dir105/dir106/dir107")));
 }
 
@@ -1068,7 +715,7 @@
 
   int file_count = 0, directory_count = 0;
   for (; !it->IsAtEnd(); it->Advance()) {
-    if (!it->Get().file_info().is_directory())
+    if (!it->GetValue().file_info().is_directory())
       ++file_count;
     else
       ++directory_count;
diff --git a/chrome/browser/chromeos/drive/search_metadata.cc b/chrome/browser/chromeos/drive/search_metadata.cc
index a167830..dc38f04 100644
--- a/chrome/browser/chromeos/drive/search_metadata.cc
+++ b/chrome/browser/chromeos/drive/search_metadata.cc
@@ -105,7 +105,7 @@
 
   // Exclude "drive", "drive/root", and "drive/other".
   if (entry.resource_id() == util::kDriveGrandRootSpecialResourceId ||
-      entry.parent_resource_id() == util::kDriveGrandRootSpecialResourceId) {
+      entry.parent_local_id() == util::kDriveGrandRootSpecialResourceId) {
     return false;
   }
 
@@ -126,7 +126,7 @@
                         MetadataSearchResultComparator>* result_candidates) {
   DCHECK_GE(at_most_num_matches, result_candidates->size());
 
-  const ResourceEntry& entry = it->Get();
+  const ResourceEntry& entry = it->GetValue();
 
   // If the candidate set is already full, and this |entry| is old, do nothing.
   // We perform this check first in order to avoid the costly find-and-highlight
diff --git a/chrome/browser/chromeos/drive/search_metadata_unittest.cc b/chrome/browser/chromeos/drive/search_metadata_unittest.cc
index 9e1ff21..87a9e6b 100644
--- a/chrome/browser/chromeos/drive/search_metadata_unittest.cc
+++ b/chrome/browser/chromeos/drive/search_metadata_unittest.cc
@@ -180,11 +180,11 @@
   ResourceEntry GetFileEntry(const std::string& name,
                                const std::string& resource_id,
                                int64 last_accessed,
-                               const std::string& parent_resource_id) {
+                               const std::string& parent_local_id) {
     ResourceEntry entry;
     entry.set_title(name);
     entry.set_resource_id(resource_id);
-    entry.set_parent_resource_id(parent_resource_id);
+    entry.set_parent_local_id(parent_local_id);
     entry.mutable_file_info()->set_last_accessed(last_accessed);
     return entry;
   }
@@ -192,11 +192,11 @@
   ResourceEntry GetDirectoryEntry(const std::string& name,
                                     const std::string& resource_id,
                                     int64 last_accessed,
-                                    const std::string& parent_resource_id) {
+                                    const std::string& parent_local_id) {
     ResourceEntry entry;
     entry.set_title(name);
     entry.set_resource_id(resource_id);
-    entry.set_parent_resource_id(parent_resource_id);
+    entry.set_parent_local_id(parent_local_id);
     entry.mutable_file_info()->set_last_accessed(last_accessed);
     entry.mutable_file_info()->set_is_directory(true);
     return entry;
diff --git a/chrome/browser/chromeos/drive/sync_client_unittest.cc b/chrome/browser/chromeos/drive/sync_client_unittest.cc
index 4fe3ad1..e4d48ec 100644
--- a/chrome/browser/chromeos/drive/sync_client_unittest.cc
+++ b/chrome/browser/chromeos/drive/sync_client_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "base/test/test_timeouts.h"
 #include "chrome/browser/chromeos/drive/change_list_loader.h"
+#include "chrome/browser/chromeos/drive/change_list_processor.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/fake_free_disk_space_getter.h"
 #include "chrome/browser/chromeos/drive/file_cache.h"
diff --git a/chrome/browser/chromeos/drive/write_on_cache_file.cc b/chrome/browser/chromeos/drive/write_on_cache_file.cc
new file mode 100644
index 0000000..ca47a21
--- /dev/null
+++ b/chrome/browser/chromeos/drive/write_on_cache_file.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/browser/chromeos/drive/write_on_cache_file.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/chromeos/drive/file_system_interface.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace drive {
+
+namespace {
+
+// Runs |file_io_task_callback| in blocking pool and runs |close_callback|
+// in the UI thread after that.
+void WriteOnCacheFileAfterOpenFile(
+    const base::FilePath& drive_path,
+    const WriteOnCacheFileCallback& file_io_task_callback,
+    FileError error,
+    const base::FilePath& local_cache_path,
+    const base::Closure& close_callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  if (error == FILE_ERROR_OK) {
+    DCHECK(!close_callback.is_null());
+    BrowserThread::GetBlockingPool()->PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(file_io_task_callback, error, local_cache_path),
+        close_callback);
+  } else {
+    BrowserThread::GetBlockingPool()->PostTask(
+        FROM_HERE,
+        base::Bind(file_io_task_callback, error, local_cache_path));
+
+  }
+}
+
+}  // namespace
+
+void WriteOnCacheFile(FileSystemInterface* file_system,
+                      const base::FilePath& path,
+                      const std::string& mime_type,
+                      const WriteOnCacheFileCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(file_system);
+  DCHECK(!callback.is_null());
+
+  file_system->OpenFile(
+      path,
+      OPEN_OR_CREATE_FILE,
+      mime_type,
+      base::Bind(&WriteOnCacheFileAfterOpenFile, path, callback));
+}
+
+}  // namespace drive
diff --git a/chrome/browser/chromeos/drive/write_on_cache_file.h b/chrome/browser/chromeos/drive/write_on_cache_file.h
new file mode 100644
index 0000000..ae981ac
--- /dev/null
+++ b/chrome/browser/chromeos/drive/write_on_cache_file.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_CHROMEOS_DRIVE_WRITE_ON_CACHE_FILE_H_
+#define CHROME_BROWSER_CHROMEOS_DRIVE_WRITE_ON_CACHE_FILE_H_
+
+#include "base/callback_forward.h"
+#include "chrome/browser/chromeos/drive/file_errors.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace drive {
+
+class FileSystemInterface;
+
+// Callback type for WriteOnCacheFile.
+typedef base::Callback<void (FileError, const base::FilePath& path)>
+    WriteOnCacheFileCallback;
+
+// Creates (if needed) a file at |path|, brings it to the local cache,
+// and invokes |callback| on blocking thread pool with the cache file path.
+// The |callback| can write to the file at the path by normal local file I/O
+// operations. After it returns, the written content is synced to the server.
+//
+// If non-empty |mime_type| is set and the file is created by this function
+// call, the mime type for the entry is set to |mime_type|. Otherwise the type
+// is automatically determined from |path|.
+//
+// Must be called from UI thread.
+void WriteOnCacheFile(FileSystemInterface* file_system,
+                      const base::FilePath& path,
+                      const std::string& mime_type,
+                      const WriteOnCacheFileCallback& callback);
+
+}  // namespace drive
+
+#endif  // CHROME_BROWSER_CHROMEOS_DRIVE_WRITE_ON_CACHE_FILE_H_
diff --git a/chrome/browser/chromeos/drive/write_on_cache_file_unittest.cc b/chrome/browser/chromeos/drive/write_on_cache_file_unittest.cc
new file mode 100644
index 0000000..486d7c2
--- /dev/null
+++ b/chrome/browser/chromeos/drive/write_on_cache_file_unittest.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 "chrome/browser/chromeos/drive/write_on_cache_file.h"
+
+#include "base/bind.h"
+#include "chrome/browser/chromeos/drive/dummy_file_system.h"
+#include "chrome/browser/chromeos/drive/test_util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace drive {
+
+namespace {
+
+const base::FilePath::CharType kDrivePath[] =
+    FILE_PATH_LITERAL("drive/root/file.txt");
+const base::FilePath::CharType kInvalidPath[] =
+    FILE_PATH_LITERAL("drive/invalid/path");
+const base::FilePath::CharType kLocalPath[] =
+    FILE_PATH_LITERAL("/tmp/local.txt");
+
+class TestFileSystem : public DummyFileSystem {
+ public:
+  TestFileSystem() : num_closed_(0) {
+  }
+
+  int num_closed() const { return num_closed_; }
+
+  // Mimics OpenFile. It fails if the |file_path| points to a hosted document.
+  virtual void OpenFile(const base::FilePath& file_path,
+                        OpenMode open_mode,
+                        const std::string& mime_type,
+                        const OpenFileCallback& callback) OVERRIDE {
+    EXPECT_EQ(OPEN_OR_CREATE_FILE, open_mode);
+
+    // Emulate a case of opening a hosted document.
+    if (file_path == base::FilePath(kInvalidPath)) {
+      callback.Run(FILE_ERROR_INVALID_OPERATION, base::FilePath(),
+                   base::Closure());
+      return;
+    }
+
+    callback.Run(FILE_ERROR_OK, base::FilePath(kLocalPath),
+                 base::Bind(&TestFileSystem::CloseFile,
+                            base::Unretained(this)));
+  }
+
+ private:
+
+  void CloseFile() {
+    ++num_closed_;
+  }
+
+  int num_closed_;
+};
+
+}  // namespace
+
+TEST(WriteOnCacheFileTest, PrepareFileForWritingSuccess) {
+  content::TestBrowserThreadBundle thread_bundle;
+  TestFileSystem test_file_system;
+
+  FileError error = FILE_ERROR_FAILED;
+  base::FilePath path;
+  // The file should successfully be opened.
+  WriteOnCacheFile(
+      &test_file_system,
+      base::FilePath(kDrivePath),
+      std::string(),  // mime_type
+      google_apis::test_util::CreateCopyResultCallback(&error, &path));
+  test_util::RunBlockingPoolTask();
+
+  EXPECT_EQ(FILE_ERROR_OK, error);
+  EXPECT_EQ(kLocalPath, path.value());
+
+  // Make sure that the file is actually closed.
+  EXPECT_EQ(1, test_file_system.num_closed());
+}
+
+TEST(WriteOnCacheFileTest, PrepareFileForWritingCreateFail) {
+  content::TestBrowserThreadBundle thread_bundle;
+  TestFileSystem test_file_system;
+
+  FileError error = FILE_ERROR_FAILED;
+  base::FilePath path;
+  // Access to kInvalidPath should fail, and FileWriteHelper should not try to
+  // open or close the file.
+  WriteOnCacheFile(
+      &test_file_system,
+      base::FilePath(kInvalidPath),
+      std::string(),  // mime_type
+      google_apis::test_util::CreateCopyResultCallback(&error, &path));
+  test_util::RunBlockingPoolTask();
+
+  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
+  EXPECT_TRUE(path.empty());
+}
+
+}   // namespace drive
diff --git a/chrome/browser/chromeos/enrollment_dialog_view.cc b/chrome/browser/chromeos/enrollment_dialog_view.cc
index 29cff16..04f65bd 100644
--- a/chrome/browser/chromeos/enrollment_dialog_view.cc
+++ b/chrome/browser/chromeos/enrollment_dialog_view.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_navigator.h"
diff --git a/chrome/browser/chromeos/extensions/file_manager/action_choice_dialog.cc b/chrome/browser/chromeos/extensions/file_manager/action_choice_dialog.cc
new file mode 100644
index 0000000..53323ae
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/action_choice_dialog.cc
@@ -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.
+
+#include "chrome/browser/chromeos/extensions/file_manager/action_choice_dialog.h"
+
+#include "ash/shell.h"
+#include "base/files/file_path.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
+#include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_iterator.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/gfx/screen.h"
+
+namespace file_manager {
+namespace util {
+namespace {
+
+// Finds a browser instance showing the target URL. Returns NULL if not
+// found.
+Browser* FindBrowserForUrl(GURL target_url) {
+  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
+    Browser* browser = *it;
+    TabStripModel* tab_strip = browser->tab_strip_model();
+    for (int idx = 0; idx < tab_strip->count(); idx++) {
+      content::WebContents* web_contents = tab_strip->GetWebContentsAt(idx);
+      const GURL& url = web_contents->GetLastCommittedURL();
+      if (url == target_url)
+        return browser;
+    }
+  }
+  return NULL;
+}
+
+}  // namespace
+
+void OpenActionChoiceDialog(const base::FilePath& file_path,
+                            bool advanced_mode) {
+  const int kDialogWidth = 394;
+  // TODO(dgozman): remove 50, which is a title height once popup window
+  // will have no title.
+  const int kDialogHeight = 316 + 50;
+
+  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
+
+  base::FilePath virtual_path;
+  if (!ConvertAbsoluteFilePathToRelativeFileSystemPath(
+          profile, kFileManagerAppId, file_path, &virtual_path))
+    return;
+  GURL dialog_url = GetActionChoiceUrl(virtual_path, advanced_mode);
+
+  const gfx::Size screen = ash::Shell::GetScreen()->GetPrimaryDisplay().size();
+  const gfx::Rect bounds((screen.width() - kDialogWidth) / 2,
+                         (screen.height() - kDialogHeight) / 2,
+                         kDialogWidth,
+                         kDialogHeight);
+
+  Browser* browser = FindBrowserForUrl(dialog_url);
+
+  if (browser) {
+    browser->window()->Show();
+    return;
+  }
+
+  ExtensionService* service = extensions::ExtensionSystem::Get(profile)->
+      extension_service();
+  if (!service)
+    return;
+
+  const extensions::Extension* extension =
+      service->GetExtensionById(kFileManagerAppId, false);
+  if (!extension)
+    return;
+
+  chrome::AppLaunchParams params(profile, extension,
+                                 extension_misc::LAUNCH_WINDOW,
+                                 NEW_FOREGROUND_TAB);
+  params.override_url = dialog_url;
+  params.override_bounds = bounds;
+  chrome::OpenApplication(params);
+}
+
+}  // namespace util
+}  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/action_choice_dialog.h b/chrome/browser/chromeos/extensions/file_manager/action_choice_dialog.h
new file mode 100644
index 0000000..b95f86c
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/action_choice_dialog.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.
+//
+// This file provides the action choice dialog. The dialog is shown when an
+// removable drive, such as an SD card, is inserted, to ask the user what to
+// do with the drive (ex. open the file manager, or open some other app).
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_ACTION_CHOICE_DIALOG_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_ACTION_CHOICE_DIALOG_H_
+
+namespace base {
+class FilePath;
+}
+
+namespace file_manager {
+namespace util {
+
+// Opens an action choice dialog for a removable drive.
+// One of the actions is opening the File Manager. Passes |advanced_mode|
+// flag to the dialog. If it is enabled, then auto-choice gets disabled.
+void OpenActionChoiceDialog(const base::FilePath& file_path,
+                            bool advanced_mode);
+
+}  // namespace util
+}  // namespace file_manager
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_ACTION_CHOICE_DIALOG_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager/app_id.h b/chrome/browser/chromeos/extensions/file_manager/app_id.h
new file mode 100644
index 0000000..0c1259a
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/app_id.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_CHROMEOS_EXTENSIONS_FILE_MANAGER_APP_ID_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_APP_ID_H_
+
+namespace file_manager {
+
+// The file manager's app ID.
+//
+// Note that file_manager::kFileManagerAppId is a bit redundant but a shorter
+// name like kAppId would be cryptic inside "file_manager" namespace.
+const char kFileManagerAppId[] = "hhaomjibdihmijegdhdafkllkbggdgoj";
+
+}  // namespace file_manager
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_APP_ID_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager/desktop_notifications.cc b/chrome/browser/chromeos/extensions/file_manager/desktop_notifications.cc
index 0f249c7..dc6c581 100644
--- a/chrome/browser/chromeos/extensions/file_manager/desktop_notifications.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/desktop_notifications.cc
@@ -8,7 +8,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
 #include "chrome/browser/notifications/desktop_notification_service.h"
 #include "chrome/browser/notifications/notification_delegate.h"
 #include "grit/generated_resources.h"
@@ -170,7 +170,7 @@
     // TODO(mukai): refactor here to invoke NotificationUIManager directly.
     const string16 replace_id = UTF8ToUTF16(notification_id);
     DesktopNotificationService::AddIconNotification(
-        util::GetFileBrowserExtensionUrl(), GetTitle(type),
+        util::GetFileManagerBaseUrl(), GetTitle(type),
         message, icon, replace_id,
         new Delegate(host->AsWeakPtr(), notification_id), profile);
   }
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index df5ef07..ab460cf 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -16,8 +16,10 @@
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/drive/file_system_interface.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #include "chrome/browser/chromeos/extensions/file_manager/desktop_notifications.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/mounted_disk_monitor.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
 #include "chrome/browser/chromeos/login/screen_locker.h"
@@ -167,7 +169,7 @@
   DCHECK(IsActiveFileTransferJobInfo(job_info));
 
   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
-  GURL url = util::ConvertRelativePathToFileSystemUrl(
+  GURL url = util::ConvertRelativeFilePathToFileSystemUrl(
       job_info.file_path, extension_id);
   result->SetString("fileUrl", url.spec());
   result->SetString("transferState", job_status);
@@ -578,7 +580,7 @@
            iter = drive_jobs_.begin(); iter != drive_jobs_.end(); ++iter) {
 
     scoped_ptr<base::DictionaryValue> job_info_dict(
-        JobInfoToDictionaryValue(kFileBrowserDomain,
+        JobInfoToDictionaryValue(kFileManagerAppId,
                                  iter->second.status,
                                  iter->second.job_info));
     event_list->Append(job_info_dict.release());
@@ -589,7 +591,7 @@
   scoped_ptr<extensions::Event> event(new extensions::Event(
       extensions::event_names::kOnFileTransfersUpdated, args.Pass()));
   extensions::ExtensionSystem::Get(profile_)->event_router()->
-      DispatchEventToExtension(kFileBrowserDomain, event.Pass());
+      DispatchEventToExtension(kFileManagerAppId, event.Pass());
 
   last_file_transfer_event_ = now;
 }
@@ -715,9 +717,9 @@
       mount_info.mount_condition) {
     // Convert mount point path to relative path with the external file system
     // exposed within File API.
-    if (util::ConvertFileToRelativeFileSystemPath(
+    if (util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
             profile_,
-            kFileBrowserDomain,
+            kFileManagerAppId,
             base::FilePath(mount_info.mount_path),
             &relative_mount_path)) {
       mount_info_value->SetString("mountPath",
@@ -755,8 +757,8 @@
       dcim_path,
       IsGooglePhotosInstalled(profile_) ?
       base::Bind(&base::DoNothing) :
-      base::Bind(&util::ViewRemovableDrive, mount_path),
-      base::Bind(&util::ViewRemovableDrive, mount_path));
+      base::Bind(&util::OpenRemovableDrive, mount_path),
+      base::Bind(&util::OpenRemovableDrive, mount_path));
 }
 
 void EventRouter::OnDiskAdded(const DiskMountManager::Disk* disk) {
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.cc
index 771a5ac..889d933 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.cc
@@ -9,6 +9,7 @@
 #include "base/i18n/case_conversion.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
@@ -18,6 +19,7 @@
 #include "chrome/browser/extensions/extension_system.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"
 #include "chrome/common/extensions/background_info.h"
 #include "content/public/browser/browser_thread.h"
@@ -298,7 +300,7 @@
   // Get file system context for the extension to which onExecute event will be
   // sent. The file access permissions will be granted to the extension in the
   // file system context for the files in |file_urls|.
-  fileapi_util::GetFileSystemContextForExtensionId(
+  util::GetFileSystemContextForExtensionId(
       profile_, extension_->id())->OpenFileSystem(
           Extension::GetBaseURLFromExtensionId(extension_->id()).GetOrigin(),
           fileapi::kFileSystemTypeExternal,
@@ -319,7 +321,7 @@
   }
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context(
-      fileapi_util::GetFileSystemContextForExtensionId(
+      util::GetFileSystemContextForExtensionId(
           profile_, extension_->id()));
   BrowserThread::PostTaskAndReplyWithResult(
       BrowserThread::FILE,
@@ -460,6 +462,45 @@
   }
 }
 
+// Returns true if |extension_id| and |action_id| indicate that the file
+// currently being handled should be opened with the browser. This function
+// is used to handle certain action IDs of the file manager.
+bool ShouldBeOpenedWithBrowser(const std::string& extension_id,
+                               const std::string& action_id) {
+
+  return (extension_id == kFileManagerAppId &&
+          (action_id == "view-pdf" ||
+           action_id == "view-swf" ||
+           action_id == "view-in-browser" ||
+           action_id == "install-crx" ||
+           action_id == "open-hosted-generic" ||
+           action_id == "open-hosted-gdoc" ||
+           action_id == "open-hosted-gsheet" ||
+           action_id == "open-hosted-gslides"));
+}
+
+// Opens the files specified by |file_urls| with the browser. |profile| is
+// used for finding an active browser. Returns true on success. It's a
+// failure if no files are opened.
+bool OpenFilesWithBrowser(Profile* profile,
+                          const std::vector<FileSystemURL>& file_urls) {
+  Browser* browser = chrome::FindLastActiveWithProfile(
+      profile,
+      chrome::HOST_DESKTOP_TYPE_ASH);
+  if (!browser)
+    return false;
+
+  int num_opened = 0;
+  for (size_t i = 0; i < file_urls.size(); ++i) {
+    const FileSystemURL& file_url = file_urls[i];
+    if (chromeos::FileSystemBackend::CanHandleURL(file_url)) {
+      const base::FilePath& file_path = file_url.path();
+      num_opened += util::OpenFileWithBrowser(browser, file_path);
+    }
+  }
+  return num_opened > 0;
+}
+
 }  // namespace
 
 bool ExecuteFileBrowserHandler(
@@ -473,6 +514,12 @@
   if (!FindFileBrowserHandlerForActionId(extension, action_id))
     return false;
 
+  // Some action IDs of the file manager's file browser handlers require the
+  // files to be directly opened with the browser.
+  if (ShouldBeOpenedWithBrowser(extension->id(), action_id)) {
+    return OpenFilesWithBrowser(profile, file_urls);
+  }
+
   // The executor object will be self deleted on completion.
   (new FileBrowserHandlerExecutor(
       profile, extension, tab_id, action_id))->Execute(file_urls, done);
@@ -481,7 +528,7 @@
 
 bool IsFallbackFileBrowserHandler(const FileBrowserHandler* handler) {
   const std::string& extension_id = handler->extension_id();
-  return (extension_id == kFileBrowserDomain ||
+  return (extension_id == kFileManagerAppId ||
           extension_id == extension_misc::kQuickOfficeComponentExtensionId ||
           extension_id == extension_misc::kQuickOfficeDevExtensionId ||
           extension_id == extension_misc::kQuickOfficeExtensionId);
@@ -509,7 +556,7 @@
     const FileBrowserHandler* handler = common_handlers[i];
     std::string task_id = file_tasks::MakeTaskID(
         handler->extension_id(),
-        file_tasks::kFileBrowserHandlerTaskType,
+        file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
         handler->id());
     std::set<std::string>::iterator default_iter = default_ids.find(task_id);
     if (default_iter != default_ids.end()) {
@@ -558,12 +605,13 @@
     }
   }
 
+  // "watch" and "gallery" are defined in the file manager's manifest.json.
   FileBrowserHandlerList::iterator watch_iter =
       FindFileBrowserHandlerForExtensionIdAndActionId(
-          &common_handlers, kFileBrowserDomain, kFileBrowserWatchTaskId);
+          &common_handlers, kFileManagerAppId, "watch");
   FileBrowserHandlerList::iterator gallery_iter =
       FindFileBrowserHandlerForExtensionIdAndActionId(
-          &common_handlers, kFileBrowserDomain, kFileBrowserGalleryTaskId);
+          &common_handlers, kFileManagerAppId, "gallery");
   if (watch_iter != common_handlers.end() &&
       gallery_iter != common_handlers.end()) {
     // Both "watch" and "gallery" actions are applicable which means that the
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc
index ffaf714..9e370d6 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_browsertest.cc
@@ -462,6 +462,7 @@
                       TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDrive")));
 
 // TODO(mtomasz): Fix this test. crbug.com/252561
+/*
 INSTANTIATE_TEST_CASE_P(
     OpenSpecialTypes,
     FileManagerBrowserTest,
@@ -475,6 +476,7 @@
                       TestParameter(NOT_IN_GUEST_MODE,
                                     "galleryOpenDownloads"),
                       TestParameter(NOT_IN_GUEST_MODE, "galleryOpenDrive")));
+*/
 
 INSTANTIATE_TEST_CASE_P(
     KeyboardOperations,
@@ -536,5 +538,11 @@
     ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "shareFile"),
                       TestParameter(NOT_IN_GUEST_MODE, "shareDirectory")));
 
+INSTANTIATE_TEST_CASE_P(
+    restoreGeometry,
+    FileManagerBrowserTest,
+    ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "restoreGeometry"),
+                      TestParameter(IN_GUEST_MODE, "restoreGeometry")));
+
 }  // namespace
 }  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
index ebd5180..48702c4 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
@@ -1,27 +1,26 @@
 // 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/chromeos/extensions/file_manager/file_manager_util.h"
 
-#include "ash/shell.h"
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "base/values.h"
 #include "chrome/browser/chromeos/drive/drive.pb.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/drive/file_system.h"
 #include "chrome/browser/chromeos/drive/file_system_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handlers.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_tasks.h"
 #include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
-#include "chrome/browser/chromeos/media/media_player.h"
+#include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_install_prompt.h"
@@ -33,13 +32,10 @@
 #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_iterator.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/simple_message_box.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
@@ -49,7 +45,6 @@
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/user_metrics.h"
-#include "content/public/browser/web_contents.h"
 #include "content/public/common/pepper_plugin_info.h"
 #include "content/public/common/webplugininfo.h"
 #include "grit/generated_resources.h"
@@ -57,67 +52,57 @@
 #include "net/base/mime_util.h"
 #include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/screen.h"
 #include "webkit/browser/fileapi/file_system_backend.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_operation_runner.h"
 #include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/common/fileapi/file_system_util.h"
 
-using base::DictionaryValue;
-using base::ListValue;
 using content::BrowserContext;
 using content::BrowserThread;
 using content::PluginService;
 using content::UserMetricsAction;
+using extensions::Extension;
 using extensions::app_file_handler_util::FindFileHandlersForFiles;
 using extensions::app_file_handler_util::PathAndMimeTypeSet;
-using extensions::Extension;
 using fileapi::FileSystemURL;
 
-const char kFileBrowserDomain[] = "hhaomjibdihmijegdhdafkllkbggdgoj";
-
-const char kFileBrowserGalleryTaskId[] = "gallery";
-const char kFileBrowserMountArchiveTaskId[] = "mount-archive";
-const char kFileBrowserWatchTaskId[] = "watch";
-const char kFileBrowserPlayTaskId[] = "play";
-
-const char kVideoPlayerAppName[] = "videoplayer";
-
 namespace file_manager {
 namespace util {
 namespace {
 
-const char kCRXExtension[] = ".crx";
-const char kPdfExtension[] = ".pdf";
-const char kSwfExtension[] = ".swf";
-// List of file extension we can open in tab.
-const char* kBrowserSupportedExtensions[] = {
+const base::FilePath::CharType kCRXExtension[] = FILE_PATH_LITERAL(".crx");
+const base::FilePath::CharType kPdfExtension[] = FILE_PATH_LITERAL(".pdf");
+const base::FilePath::CharType kSwfExtension[] = FILE_PATH_LITERAL(".swf");
+
+// List of file extensions viewable in the browser.
+const base::FilePath::CharType* kFileExtensionsViewableInBrowser[] = {
 #if defined(GOOGLE_CHROME_BUILD)
-    ".pdf", ".swf",
+  FILE_PATH_LITERAL(".pdf"),
+  FILE_PATH_LITERAL(".swf"),
 #endif
-    ".bmp", ".jpg", ".jpeg", ".png", ".webp", ".gif", ".txt", ".html", ".htm",
-    ".mhtml", ".mht", ".svg"
+  FILE_PATH_LITERAL(".bmp"),
+  FILE_PATH_LITERAL(".jpg"),
+  FILE_PATH_LITERAL(".jpeg"),
+  FILE_PATH_LITERAL(".png"),
+  FILE_PATH_LITERAL(".webp"),
+  FILE_PATH_LITERAL(".gif"),
+  FILE_PATH_LITERAL(".txt"),
+  FILE_PATH_LITERAL(".html"),
+  FILE_PATH_LITERAL(".htm"),
+  FILE_PATH_LITERAL(".mhtml"),
+  FILE_PATH_LITERAL(".mht"),
+  FILE_PATH_LITERAL(".svg"),
 };
 
-// Returns a file manager URL for the given |path|.
-GURL GetFileManagerUrl(const char* path) {
-  return GURL(std::string("chrome-extension://") + kFileBrowserDomain + path);
-}
-
-bool IsSupportedBrowserExtension(const char* file_extension) {
-  for (size_t i = 0; i < arraysize(kBrowserSupportedExtensions); i++) {
-    if (base::strcasecmp(file_extension, kBrowserSupportedExtensions[i]) == 0) {
+// Returns true if |file_path| is viewable in the browser (ex. HTML file).
+bool IsViewableInBrowser(const base::FilePath& file_path) {
+  for (size_t i = 0; i < arraysize(kFileExtensionsViewableInBrowser); i++) {
+    if (file_path.MatchesExtension(kFileExtensionsViewableInBrowser[i]))
       return true;
-    }
   }
   return false;
 }
 
-bool IsCRXFile(const char* file_extension) {
-  return base::strcasecmp(file_extension, kCRXExtension) == 0;
-}
-
 bool IsPepperPluginEnabled(Profile* profile,
                            const base::FilePath& plugin_path) {
   content::PepperPluginInfo* pepper_info =
@@ -147,42 +132,6 @@
   return IsPepperPluginEnabled(profile, plugin_path);
 }
 
-// Convert numeric dialog type to a string.
-std::string GetDialogTypeAsString(
-    ui::SelectFileDialog::Type dialog_type) {
-  std::string type_str;
-  switch (dialog_type) {
-    case ui::SelectFileDialog::SELECT_NONE:
-      type_str = "full-page";
-      break;
-
-    case ui::SelectFileDialog::SELECT_FOLDER:
-      type_str = "folder";
-      break;
-
-    case ui::SelectFileDialog::SELECT_UPLOAD_FOLDER:
-      type_str = "upload-folder";
-      break;
-
-    case ui::SelectFileDialog::SELECT_SAVEAS_FILE:
-      type_str = "saveas-file";
-      break;
-
-    case ui::SelectFileDialog::SELECT_OPEN_FILE:
-      type_str = "open-file";
-      break;
-
-    case ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE:
-      type_str = "open-multi-file";
-      break;
-
-    default:
-      NOTREACHED();
-  }
-
-  return type_str;
-}
-
 void OpenNewTab(Profile* profile, const GURL& url) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   Browser* browser = chrome::FindOrCreateTabbedBrowser(
@@ -195,7 +144,7 @@
 }
 
 // Shows a warning message box saying that the file could not be opened.
-void ShowWarningMessageBox(Profile* profile, const base::FilePath& path) {
+void ShowWarningMessageBox(Profile* profile, const base::FilePath& file_path) {
   // TODO: if FindOrCreateTabbedBrowser creates a new browser the returned
   // browser is leaked.
   Browser* browser =
@@ -205,12 +154,12 @@
       browser->window()->GetNativeWindow(),
       l10n_util::GetStringFUTF16(
           IDS_FILE_BROWSER_ERROR_VIEWING_FILE_TITLE,
-          UTF8ToUTF16(path.BaseName().value())),
+          UTF8ToUTF16(file_path.BaseName().value())),
       l10n_util::GetStringUTF16(IDS_FILE_BROWSER_ERROR_VIEWING_FILE),
       chrome::MESSAGE_BOX_TYPE_WARNING);
 }
 
-void InstallCRX(Browser* browser, const base::FilePath& path) {
+void InstallCRX(Browser* browser, const base::FilePath& file_path) {
   ExtensionService* service =
       extensions::ExtensionSystem::Get(browser->profile())->extension_service();
   CHECK(service);
@@ -223,7 +172,7 @@
   installer->set_error_on_unsupported_requirements(true);
   installer->set_is_gallery_install(false);
   installer->set_allow_silent_install(false);
-  installer->InstallCrx(path);
+  installer->InstallCrx(file_path);
 }
 
 // Called when a crx file on Drive was downloaded.
@@ -236,53 +185,59 @@
   InstallCRX(browser, file);
 }
 
-// Grants file system access to the file browser.
+// Grants file system access to the file manager.
 bool GrantFileSystemAccessToFileBrowser(Profile* profile) {
-  // File browser always runs in the site for its extension id, so that is the
-  // site for which file access permissions should be granted.
+  // The file manager always runs in the site for its extension id, so that
+  // is the site for which file access permissions should be granted.
   GURL site = extensions::ExtensionSystem::Get(profile)->extension_service()->
-      GetSiteForExtensionId(kFileBrowserDomain);
+      GetSiteForExtensionId(kFileManagerAppId);
   fileapi::ExternalFileSystemBackend* backend =
       BrowserContext::GetStoragePartitionForSite(profile, site)->
           GetFileSystemContext()->external_backend();
   if (!backend)
     return false;
-  backend->GrantFullAccessToExtension(GetFileBrowserUrl().host());
+  backend->GrantFullAccessToExtension(kFileManagerAppId);
   return true;
 }
 
-// Opens the file specified by |url| with |task|.
-void OpenFileWithTask(Profile* profile,
-                      const file_tasks::TaskDescriptor& task,
-                      const GURL& url) {
-  // If File Browser has not been open yet then it did not request access
+// Executes the |task| for the file specified by |url|.
+void ExecuteFileTaskForUrl(Profile* profile,
+                           const file_tasks::TaskDescriptor& task,
+                           const GURL& url) {
+  // If the file manager has not been open yet then it did not request access
   // to the file system. Do it now.
   if (!GrantFileSystemAccessToFileBrowser(profile))
     return;
 
   fileapi::FileSystemContext* file_system_context =
-      fileapi_util::GetFileSystemContextForExtensionId(
-          profile, kFileBrowserDomain);
+      GetFileSystemContextForExtensionId(
+          profile, kFileManagerAppId);
 
-  // We are executing the task on behalf of File Browser extension.
-  const GURL source_url = GetFileBrowserUrl();
+  // We are executing the task on behalf of the file manager.
+  const GURL source_url = GetFileManagerMainPageUrl();
   std::vector<FileSystemURL> urls;
   urls.push_back(file_system_context->CrackURL(url));
 
   file_tasks::ExecuteFileTask(
       profile,
       source_url,
-      kFileBrowserDomain,
+      kFileManagerAppId,
       0, // no tab id
       task,
       urls,
       file_tasks::FileTaskFinishedCallback());
 }
 
-// Opens the file specified with |path|. Used to implement internal handlers
-// of special action IDs such as "auto-open", "open", and "select".
-void OpenFileWithInternalActionId(const base::FilePath& path,
-                                  const std::string& action_id) {
+// Opens the file manager for the specified |file_path|. Used to implement
+// internal handlers of special action IDs:
+//
+// "open" - Open the file manager for the given folder.
+// "auto-open" - Open the file manager for the given removal drive and close
+//               the file manager when the removal drive is unmounted.
+// "select" - Open the file manager for the given file. The folder containing
+//            the file will be opened with the file selected.
+void OpenFileManagerWithInternalActionId(const base::FilePath& file_path,
+                                         const std::string& action_id) {
   DCHECK(action_id == "auto-open" ||
          action_id == "open" ||
          action_id == "select");
@@ -291,34 +246,21 @@
   Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
 
   GURL url;
-  if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url))
+  if (!ConvertAbsoluteFilePathToFileSystemUrl(
+          profile, file_path, kFileManagerAppId, &url))
     return;
 
-  file_tasks::TaskDescriptor task(kFileBrowserDomain,
-                                  file_tasks::kFileBrowserHandlerTaskType,
+  file_tasks::TaskDescriptor task(kFileManagerAppId,
+                                  file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
                                   action_id);
-  OpenFileWithTask(profile, task, url);
+  ExecuteFileTaskForUrl(profile, task, url);
 }
 
-Browser* GetBrowserForUrl(GURL target_url) {
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    Browser* browser = *it;
-    TabStripModel* tab_strip = browser->tab_strip_model();
-    for (int idx = 0; idx < tab_strip->count(); idx++) {
-      content::WebContents* web_contents = tab_strip->GetWebContentsAt(idx);
-      const GURL& url = web_contents->GetLastCommittedURL();
-      if (url == target_url)
-        return browser;
-    }
-  }
-  return NULL;
-}
-
-// Opens the file specified by |path| and |url| with a file handler,
+// Opens the file specified by |file_path| and |url| with a file handler,
 // preferably the default handler for the type of the file.  Returns false if
 // no file handler is found.
 bool OpenFileWithFileHandler(Profile* profile,
-                              const base::FilePath& path,
+                              const base::FilePath& file_path,
                               const GURL& url,
                               const std::string& mime_type,
                               const std::string& default_task_id) {
@@ -327,7 +269,7 @@
     return false;
 
   PathAndMimeTypeSet files;
-  files.insert(std::make_pair(path, mime_type));
+  files.insert(std::make_pair(file_path, mime_type));
   const extensions::FileHandlerInfo* first_handler = NULL;
   const extensions::Extension* extension_for_first_handler = NULL;
 
@@ -356,13 +298,13 @@
       const extensions::FileHandlerInfo* handler = *i;
       std::string task_id = file_tasks::MakeTaskID(
           extension->id(),
-          file_tasks::kFileHandlerTaskType,
+          file_tasks::TASK_TYPE_FILE_HANDLER,
           handler->id);
       if (task_id == default_task_id) {
         file_tasks::TaskDescriptor task(extension->id(),
-                                        file_tasks::kFileHandlerTaskType,
+                                        file_tasks::TASK_TYPE_FILE_HANDLER,
                                         handler->id);
-        OpenFileWithTask(profile, task, url);
+        ExecuteFileTaskForUrl(profile, task, url);
         return true;
 
       } else if (!first_handler) {
@@ -373,71 +315,40 @@
   }
   if (first_handler) {
     file_tasks::TaskDescriptor task(extension_for_first_handler->id(),
-                                    file_tasks::kFileHandlerTaskType,
+                                    file_tasks::TASK_TYPE_FILE_HANDLER,
                                     first_handler->id);
-    OpenFileWithTask(profile, task, url);
+    ExecuteFileTaskForUrl(profile, task, url);
     return true;
   }
   return false;
 }
 
-// Returns true if |action_id| indicates that the file currently being
-// handled should be opened with the browser (i.e. should be opened with
-// OpenFileWithBrowser()).
-bool ShouldBeOpenedWithBrowser(const std::string& action_id) {
-  return (action_id == "view-pdf" ||
-          action_id == "view-swf" ||
-          action_id == "view-in-browser" ||
-          action_id == "install-crx" ||
-          action_id == "open-hosted-generic" ||
-          action_id == "open-hosted-gdoc" ||
-          action_id == "open-hosted-gsheet" ||
-          action_id == "open-hosted-gslides");
-}
-
-// Opens the file specified by |path| and |url| with the file browser handler
-// specified by |handler|. Returns false if failed to open the file.
+// Opens the file specified by |file_path| and |url| with the file browser
+// handler specified by |handler|. Returns false if failed to open the file.
 bool OpenFileWithFileBrowserHandler(Profile* profile,
-                                    const base::FilePath& path,
+                                    const base::FilePath& file_path,
                                     const FileBrowserHandler& handler,
                                     const GURL& url) {
-  std::string extension_id = handler.extension_id();
-  std::string action_id = handler.id();
-  Browser* browser = chrome::FindLastActiveWithProfile(profile,
-      chrome::HOST_DESKTOP_TYPE_ASH);
-
-  // If there is no browsers for the profile, bail out. Return true so warning
-  // about file type not being supported is not displayed.
-  if (!browser)
-    return true;
-
-  // Some action IDs of the file manager's file browser handlers require the
-  // file to be directly opened with the browser.
-  if (extension_id == kFileBrowserDomain &&
-      ShouldBeOpenedWithBrowser(action_id)) {
-    return OpenFileWithBrowser(browser, path);
-  }
-
-  file_tasks::TaskDescriptor task(extension_id,
-                                  file_tasks::kFileBrowserHandlerTaskType,
-                                  action_id);
-  OpenFileWithTask(profile, task, url);
+  file_tasks::TaskDescriptor task(handler.extension_id(),
+                                  file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
+                                  handler.id());
+  ExecuteFileTaskForUrl(profile, task, url);
   return true;
 }
 
-// Opens the file specified by |path| with a handler (either of file browser
-// handler or file handler, preferably the default handler for the type of
-// the file), or opens the file with the browser. Returns false if failed to
-// open the file.
-bool OpenFileWithHandlerOrBrowser(Profile* profile,
-                                  const base::FilePath& path) {
+// Opens the file specified by |file_path| with a handler (either of file
+// browser handler or file handler, preferably the default handler for the
+// type of the file), or opens the file with the browser. Returns false if
+// failed to open the file.
+bool OpenFileWithHandler(Profile* profile, const base::FilePath& file_path) {
   GURL url;
-  if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url))
+  if (!ConvertAbsoluteFilePathToFileSystemUrl(
+          profile, file_path, kFileManagerAppId, &url))
     return false;
 
-  std::string mime_type = GetMimeTypeForPath(path);
+  std::string mime_type = GetMimeTypeForPath(file_path);
   std::string default_task_id = file_tasks::GetDefaultTaskIdFromPrefs(
-      profile, mime_type, path.Extension());
+      profile, mime_type, file_path.Extension());
 
   // We choose the file handler from the following in decreasing priority or
   // fail if none support the file type:
@@ -449,23 +360,23 @@
   // Note that there can be at most one of default extension and default app.
   const FileBrowserHandler* handler =
       file_browser_handlers::FindFileBrowserHandlerForURLAndPath(
-          profile, url, path);
+          profile, url, file_path);
   if (!handler) {
     return OpenFileWithFileHandler(
-        profile, path, url, mime_type, default_task_id);
+        profile, file_path, url, mime_type, default_task_id);
   }
 
   std::string handler_task_id = file_tasks::MakeTaskID(
         handler->extension_id(),
-        file_tasks::kFileBrowserHandlerTaskType,
+        file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
         handler->id());
   if (handler_task_id != default_task_id &&
       !file_browser_handlers::IsFallbackFileBrowserHandler(handler) &&
       OpenFileWithFileHandler(
-          profile, path, url, mime_type, default_task_id)) {
+          profile, file_path, url, mime_type, default_task_id)) {
     return true;
   }
-  return OpenFileWithFileBrowserHandler(profile, path, *handler, url);
+  return OpenFileWithFileBrowserHandler(profile, file_path, *handler, url);
 }
 
 // Reads the alternate URL from a GDoc file. When it fails, returns a file URL
@@ -478,19 +389,19 @@
   return url;
 }
 
-// Used to implement ViewItem().
-void ContinueViewItem(Profile* profile,
-                      const base::FilePath& path,
+// Used to implement OpenItem().
+void ContinueOpenItem(Profile* profile,
+                      const base::FilePath& file_path,
                       base::PlatformFileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   if (error == base::PLATFORM_FILE_OK) {
-    // A directory exists at |path|. Open it with the file manager.
-    OpenFileWithInternalActionId(path, "open");
+    // A directory exists at |file_path|. Open it with the file manager.
+    OpenFileManagerWithInternalActionId(file_path, "open");
   } else {
-    // |path| should be a file. Open it with a handler or the browser.
-    if (!OpenFileWithHandlerOrBrowser(profile, path))
-      ShowWarningMessageBox(profile, path);
+    // |file_path| should be a file. Open it with a handler.
+    if (!OpenFileWithHandler(profile, file_path))
+      ShowWarningMessageBox(profile, file_path);
   }
 }
 
@@ -523,136 +434,6 @@
 
 }  // namespace
 
-GURL GetFileBrowserExtensionUrl() {
-  return GetFileManagerUrl("/");
-}
-
-GURL GetFileBrowserUrl() {
-  return GetFileManagerUrl("/main.html");
-}
-
-GURL GetMediaPlayerUrl() {
-  return GetFileManagerUrl("/mediaplayer.html");
-}
-
-GURL GetActionChoiceUrl(const base::FilePath& virtual_path,
-                        bool advanced_mode) {
-  std::string url = GetFileManagerUrl("/action_choice.html").spec();
-  if (advanced_mode)
-    url += "?advanced-mode";
-  url += "#/" + net::EscapeUrlEncodedData(virtual_path.value(),
-                                          false);  // Space to %20 instead of +.
-  return GURL(url);
-}
-
-GURL ConvertRelativePathToFileSystemUrl(const base::FilePath& relative_path,
-                                        const std::string& extension_id) {
-  GURL base_url = fileapi::GetFileSystemRootURI(
-      Extension::GetBaseURLFromExtensionId(extension_id),
-      fileapi::kFileSystemTypeExternal);
-  return GURL(base_url.spec() +
-              net::EscapeUrlEncodedData(relative_path.AsUTF8Unsafe(),
-                                        false));  // Space to %20 instead of +.
-}
-
-bool ConvertFileToFileSystemUrl(Profile* profile,
-                                const base::FilePath& full_file_path,
-                                const std::string& extension_id,
-                                GURL* url) {
-  base::FilePath relative_path;
-  if (!ConvertFileToRelativeFileSystemPath(profile, extension_id,
-           full_file_path, &relative_path)) {
-    return false;
-  }
-  *url = ConvertRelativePathToFileSystemUrl(relative_path, extension_id);
-  return true;
-}
-
-bool ConvertFileToRelativeFileSystemPath(
-    Profile* profile,
-    const std::string& extension_id,
-    const base::FilePath& full_file_path,
-    base::FilePath* virtual_path) {
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  // May be NULL during unit_tests.
-  if (!service)
-    return false;
-
-  // File browser APIs are meant to be used only from extension context, so the
-  // extension's site is the one in whose file system context the virtual path
-  // should be found.
-  GURL site = service->GetSiteForExtensionId(extension_id);
-  fileapi::ExternalFileSystemBackend* backend =
-      BrowserContext::GetStoragePartitionForSite(profile, site)->
-          GetFileSystemContext()->external_backend();
-  if (!backend)
-    return false;
-
-  // Find if this file path is managed by the external backend.
-  if (!backend->GetVirtualPath(full_file_path, virtual_path))
-    return false;
-
-  return true;
-}
-
-GURL GetFileBrowserUrlWithParams(
-    ui::SelectFileDialog::Type type,
-    const string16& title,
-    const base::FilePath& default_virtual_path,
-    const ui::SelectFileDialog::FileTypeInfo* file_types,
-    int file_type_index,
-    const base::FilePath::StringType& default_extension) {
-  DictionaryValue arg_value;
-  arg_value.SetString("type", GetDialogTypeAsString(type));
-  arg_value.SetString("title", title);
-  arg_value.SetString("defaultPath", default_virtual_path.value());
-  arg_value.SetString("defaultExtension", default_extension);
-
-  if (file_types) {
-    ListValue* types_list = new ListValue();
-    for (size_t i = 0; i < file_types->extensions.size(); ++i) {
-      ListValue* extensions_list = new ListValue();
-      for (size_t j = 0; j < file_types->extensions[i].size(); ++j) {
-        extensions_list->Append(
-            new base::StringValue(file_types->extensions[i][j]));
-      }
-
-      DictionaryValue* dict = new DictionaryValue();
-      dict->Set("extensions", extensions_list);
-
-      if (i < file_types->extension_description_overrides.size()) {
-        string16 desc = file_types->extension_description_overrides[i];
-        dict->SetString("description", desc);
-      }
-
-      // file_type_index is 1-based. 0 means no selection at all.
-      dict->SetBoolean("selected",
-                       (static_cast<size_t>(file_type_index) == (i + 1)));
-
-      types_list->Set(i, dict);
-    }
-    arg_value.Set("typeList", types_list);
-
-    arg_value.SetBoolean("includeAllFiles", file_types->include_all_files);
-  }
-
-  // If the caller cannot handle Drive path, the file chooser dialog need to
-  // return resolved local native paths to the selected files.
-  arg_value.SetBoolean("shouldReturnLocalPath",
-                       !file_types || !file_types->support_drive);
-
-  std::string json_args;
-  base::JSONWriter::Write(&arg_value, &json_args);
-
-  // kChromeUIFileManagerURL could not be used since query parameters are not
-  // supported for it.
-  std::string url = GetFileBrowserUrl().spec() + '?' +
-      net::EscapeUrlEncodedData(json_args,
-                                false);  // Space to %20 instead of +.
-  return GURL(url);
-}
-
 string16 GetTitleFromType(ui::SelectFileDialog::Type dialog_type) {
   string16 title;
   switch (dialog_type) {
@@ -692,104 +473,58 @@
   return title;
 }
 
-void ViewRemovableDrive(const base::FilePath& path) {
-  OpenFileWithInternalActionId(path, "auto-open");
+void OpenRemovableDrive(const base::FilePath& file_path) {
+  OpenFileManagerWithInternalActionId(file_path, "auto-open");
 }
 
-void OpenActionChoiceDialog(const base::FilePath& path, bool advanced_mode) {
-  const int kDialogWidth = 394;
-  // TODO(dgozman): remove 50, which is a title height once popup window
-  // will have no title.
-  const int kDialogHeight = 316 + 50;
-
-  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-
-  base::FilePath virtual_path;
-  if (!ConvertFileToRelativeFileSystemPath(profile, kFileBrowserDomain, path,
-                                           &virtual_path))
-    return;
-  GURL dialog_url = GetActionChoiceUrl(virtual_path, advanced_mode);
-
-  const gfx::Size screen = ash::Shell::GetScreen()->GetPrimaryDisplay().size();
-  const gfx::Rect bounds((screen.width() - kDialogWidth) / 2,
-                         (screen.height() - kDialogHeight) / 2,
-                         kDialogWidth,
-                         kDialogHeight);
-
-  Browser* browser = GetBrowserForUrl(dialog_url);
-
-  if (browser) {
-    browser->window()->Show();
-    return;
-  }
-
-  ExtensionService* service = extensions::ExtensionSystem::Get(
-    profile ? profile : ProfileManager::GetDefaultProfileOrOffTheRecord())->
-        extension_service();
-  if (!service)
-    return;
-
-  const extensions::Extension* extension =
-      service->GetExtensionById(kFileBrowserDomain, false);
-  if (!extension)
-    return;
-
-  chrome::AppLaunchParams params(profile, extension,
-                                 extension_misc::LAUNCH_WINDOW,
-                                 NEW_FOREGROUND_TAB);
-  params.override_url = dialog_url;
-  params.override_bounds = bounds;
-  chrome::OpenApplication(params);
-}
-
-void ViewItem(const base::FilePath& path) {
+void OpenItem(const base::FilePath& file_path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
   GURL url;
-  if (!ConvertFileToFileSystemUrl(profile, path, kFileBrowserDomain, &url) ||
+  if (!ConvertAbsoluteFilePathToFileSystemUrl(
+          profile, file_path, kFileManagerAppId, &url) ||
       !GrantFileSystemAccessToFileBrowser(profile)) {
-    ShowWarningMessageBox(profile, path);
+    ShowWarningMessageBox(profile, file_path);
     return;
   }
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      fileapi_util::GetFileSystemContextForExtensionId(
-          profile, kFileBrowserDomain);
+      GetFileSystemContextForExtensionId(
+          profile, kFileManagerAppId);
 
   CheckIfDirectoryExists(file_system_context, url,
-                         base::Bind(&ContinueViewItem, profile, path));
+                         base::Bind(&ContinueOpenItem, profile, file_path));
 }
 
-void ShowFileInFolder(const base::FilePath& path) {
+void ShowItemInFolder(const base::FilePath& file_path) {
   // This action changes the selection so we do not reuse existing tabs.
-  OpenFileWithInternalActionId(path, "select");
+  OpenFileManagerWithInternalActionId(file_path, "select");
 }
 
-bool OpenFileWithBrowser(Browser* browser, const base::FilePath& path) {
+bool OpenFileWithBrowser(Browser* browser, const base::FilePath& file_path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   Profile* profile = browser->profile();
-  std::string file_extension = path.Extension();
   // For things supported natively by the browser, we should open it
   // in a tab.
-  if (IsSupportedBrowserExtension(file_extension.data()) ||
-      ShouldBeOpenedWithPlugin(profile, file_extension.data())) {
-    GURL page_url = net::FilePathToFileURL(path);
+  if (IsViewableInBrowser(file_path) ||
+      ShouldBeOpenedWithPlugin(profile, file_path.Extension())) {
+    GURL page_url = net::FilePathToFileURL(file_path);
     // Override drive resource to point to internal handler instead of file URL.
-    if (drive::util::IsUnderDriveMountPoint(path)) {
+    if (drive::util::IsUnderDriveMountPoint(file_path)) {
       page_url = drive::util::FilePathToDriveURL(
-          drive::util::ExtractDrivePath(path));
+          drive::util::ExtractDrivePath(file_path));
     }
     OpenNewTab(profile, page_url);
     return true;
   }
 
-  if (drive::util::HasGDocFileExtension(path)) {
-    if (drive::util::IsUnderDriveMountPoint(path)) {
+  if (drive::util::HasGDocFileExtension(file_path)) {
+    if (drive::util::IsUnderDriveMountPoint(file_path)) {
       // The file is on Google Docs. Open with drive URL.
       GURL url = drive::util::FilePathToDriveURL(
-          drive::util::ExtractDrivePath(path));
+          drive::util::ExtractDrivePath(file_path));
       OpenNewTab(profile, url);
     } else {
       // The file is local (downloaded from an attachment or otherwise copied).
@@ -797,37 +532,41 @@
       base::PostTaskAndReplyWithResult(
           BrowserThread::GetBlockingPool(),
           FROM_HERE,
-          base::Bind(&ReadUrlFromGDocOnBlockingPool, path),
+          base::Bind(&ReadUrlFromGDocOnBlockingPool, file_path),
           base::Bind(&OpenNewTab, static_cast<Profile*>(NULL)));
     }
     return true;
   }
 
-  if (IsCRXFile(file_extension.data())) {
-    if (drive::util::IsUnderDriveMountPoint(path)) {
+  if (file_path.MatchesExtension(kCRXExtension)) {
+    if (drive::util::IsUnderDriveMountPoint(file_path)) {
       drive::DriveIntegrationService* integration_service =
           drive::DriveIntegrationServiceFactory::GetForProfile(profile);
       if (!integration_service)
         return false;
       integration_service->file_system()->GetFileByPath(
-          drive::util::ExtractDrivePath(path),
+          drive::util::ExtractDrivePath(file_path),
           base::Bind(&OnCRXDownloadCallback, browser));
     } else {
-      InstallCRX(browser, path);
+      InstallCRX(browser, file_path);
     }
     return true;
   }
 
   // Failed to open the file of unknown type.
-  LOG(WARNING) << "Unknown file type: " << path.value();
+  LOG(WARNING) << "Unknown file type: " << file_path.value();
   return false;
 }
 
 // If a bundled plugin is enabled, we should open pdf/swf files in a tab.
-bool ShouldBeOpenedWithPlugin(Profile* profile, const char* file_extension) {
-  if (LowerCaseEqualsASCII(file_extension, kPdfExtension))
+bool ShouldBeOpenedWithPlugin(
+    Profile* profile,
+    const base::FilePath::StringType& file_extension) {
+  const base::FilePath file_path =
+      base::FilePath::FromUTF8Unsafe("dummy").AddExtension(file_extension);
+  if (file_path.MatchesExtension(kPdfExtension))
     return IsPdfPluginEnabled(profile);
-  if (LowerCaseEqualsASCII(file_extension, kSwfExtension))
+  if (file_path.MatchesExtension(kSwfExtension))
     return IsFlashPluginEnabled(profile);
   return false;
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
index 8d65c63..681ef4c 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
@@ -14,76 +14,35 @@
 class GURL;
 class Profile;
 
-extern const char kFileBrowserDomain[];
-extern const char kFileBrowserGalleryTaskId[];
-extern const char kFileBrowserWatchTaskId[];
-
 // File manager helper methods.
 namespace file_manager {
 namespace util {
 
-// Gets base file browser url.
-GURL GetFileBrowserExtensionUrl();
-GURL GetFileBrowserUrl();
-GURL GetMediaPlayerUrl();
-
-// Converts |relative_path| (e.g., "drive/root" or "Downloads") into external
-// filesystem URL (e.g., filesystem://id/external/drive/root).
-GURL ConvertRelativePathToFileSystemUrl(const base::FilePath& relative_path,
-                                        const std::string& extension_id);
-
-// Converts |full_file_path| (e.g., "/special/drive/root" or
-// "/home/chronos/user/Downloads") into external filesystem URL. Returns false
-// if |full_file_path| is not managed by the external filesystem provider.
-bool ConvertFileToFileSystemUrl(Profile* profile,
-                                const base::FilePath& full_file_path,
-                                const std::string& extension_id,
-                                GURL* url);
-
-// Converts |full_file_path| into |relative_path| within the external provider
-// in File API. Returns false if |full_file_path| is not managed by the
-// external filesystem provider.
-bool ConvertFileToRelativeFileSystemPath(Profile* profile,
-                                         const std::string& extension_id,
-                                         const base::FilePath& full_file_path,
-                                         base::FilePath* relative_path);
-
-// Gets base file browser url for.
-GURL GetFileBrowserUrlWithParams(
-    ui::SelectFileDialog::Type type,
-    const string16& title,
-    const base::FilePath& default_virtual_path,
-    const ui::SelectFileDialog::FileTypeInfo* file_types,
-    int file_type_index,
-    const base::FilePath::StringType& default_extension);
-
 // Get file dialog title string from its type.
 string16 GetTitleFromType(ui::SelectFileDialog::Type type);
 
-// Shows a freshly mounted removable drive.
-// If there is another File Browser instance open this call does nothing.
-// The mount event will cause file_manager.js to show the new drive in
-// the left panel, and that is all we want.
-// If there is no File Browser open, this call opens a new one pointing to
-// |path|. In this case the tab will automatically close on |path| unmount.
-void ViewRemovableDrive(const base::FilePath& path);
-
-// Opens an action choice dialog for an external drive.
-// One of the actions is opening the File Manager. Passes |advanced_mode|
-// flag to the dialog. If it is enabled, then auto-choice gets disabled.
-void OpenActionChoiceDialog(const base::FilePath& path, bool advanced_mode);
+// Opens the file manager for the freshly mounted removable drive specified
+// by |file_path|.
+// If there is another file manager instance open, this call does nothing.
+// The mount event will cause the file manager to show the new drive in
+// the left panel.
+// If there is no file manager open, this call opens a new one pointing to
+// |file_path|. In this case the tab will automatically close on |file_path|
+// unmount.
+void OpenRemovableDrive(const base::FilePath& file_path);
 
 // Opens an item (file or directory). If the target is a directory, the
 // directory will be opened in the file manager. If the target is a file, the
 // file will be opened using a file handler, a file browser handler, or the
 // browser (open in a tab). The default handler has precedence over other
 // handlers, if defined for the type of the target file.
-void ViewItem(const base::FilePath& path);
+void OpenItem(const base::FilePath& file_path);
 
-// Opens file browser on the folder containing the file, with the file selected.
-void ShowFileInFolder(const base::FilePath& path);
+// Opens the file manager for the folder containing the item specified by
+// |file_path|, with the item selected.
+void ShowItemInFolder(const base::FilePath& file_path);
 
-// Opens the file specified by |path| with the browser. This function takes
+// Opens the file specified by |file_path| with the browser. This function takes
 // care of the following intricacies:
 //
 // - If the file is a Drive hosted document, the hosted document will be
@@ -93,12 +52,15 @@
 //   needed.
 //
 // Returns false if failed to open. This happens if the file type is unknown.
-bool OpenFileWithBrowser(Browser* browser, const base::FilePath& path);
+bool OpenFileWithBrowser(Browser* browser, const base::FilePath& file_path);
 
 // Checks whether a pepper plugin for |file_extension| is enabled.
-bool ShouldBeOpenedWithPlugin(Profile* profile, const char* file_extension);
+bool ShouldBeOpenedWithPlugin(
+    Profile* profile,
+    const base::FilePath::StringType& file_extension);
 
-// Returns the MIME type of |file_path|.
+// Returns the MIME type of |file_path|. Returns "" if the MIME type is
+// unknown.
 std::string GetMimeTypeForPath(const base::FilePath& file_path);
 
 }  // namespace util
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_util_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_util_unittest.cc
new file mode 100644
index 0000000..4ecba07
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util_unittest.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/chromeos/extensions/file_manager/file_manager_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace file_manager {
+namespace util {
+
+TEST(FileManagerUtilTest, GetMimeTypeForPath) {
+  EXPECT_EQ("image/jpeg",
+            GetMimeTypeForPath(base::FilePath::FromUTF8Unsafe("foo.jpg")));
+  EXPECT_EQ("image/jpeg",
+            GetMimeTypeForPath(base::FilePath::FromUTF8Unsafe("FOO.JPG")));
+  EXPECT_EQ("",
+            GetMimeTypeForPath(base::FilePath::FromUTF8Unsafe("foo.zzz")));
+}
+
+}  // namespace util
+}  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc
index 00f1cd1..cc899fa 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc
@@ -27,6 +27,8 @@
 namespace file_manager {
 namespace file_tasks {
 
+namespace {
+
 // The values "file" and "app" are confusing, but cannot be changed easily as
 // these are used in default task IDs stored in preferences.
 //
@@ -35,9 +37,34 @@
 // chrome.storage crbug.com/267359
 const char kFileBrowserHandlerTaskType[] = "file";
 const char kFileHandlerTaskType[] = "app";
-const char kDriveTaskType[] = "drive";
+const char kDriveAppTaskType[] = "drive";
 
-namespace {
+// Converts a TaskType to a string.
+std::string TaskTypeToString(TaskType task_type) {
+  switch (task_type) {
+    case TASK_TYPE_FILE_BROWSER_HANDLER:
+      return kFileBrowserHandlerTaskType;
+    case TASK_TYPE_FILE_HANDLER:
+      return kFileHandlerTaskType;
+    case TASK_TYPE_DRIVE_APP:
+      return kDriveAppTaskType;
+    case TASK_TYPE_UNKNOWN:
+      break;
+  }
+  NOTREACHED();
+  return "";
+}
+
+// Converts a string to a TaskType. Returns TASK_TYPE_UNKNOWN on error.
+TaskType StringToTaskType(const std::string& str) {
+  if (str == kFileBrowserHandlerTaskType)
+    return TASK_TYPE_FILE_BROWSER_HANDLER;
+  if (str == kFileHandlerTaskType)
+    return TASK_TYPE_FILE_HANDLER;
+  if (str == kDriveAppTaskType)
+    return TASK_TYPE_DRIVE_APP;
+  return TASK_TYPE_UNKNOWN;
+}
 
 // Legacy Drive task extension prefix, used by CrackTaskID.
 const char kDriveTaskExtensionPrefix[] = "drive-app:";
@@ -52,7 +79,7 @@
     const std::string& file_browser_id,
     const std::vector<FileSystemURL>& files) {
   fileapi::ExternalFileSystemBackend* backend =
-      fileapi_util::GetFileSystemContextForExtensionId(
+      util::GetFileSystemContextForExtensionId(
           profile, file_browser_id)->external_backend();
   if (!backend)
     return false;
@@ -133,19 +160,16 @@
 }
 
 std::string MakeTaskID(const std::string& extension_id,
-                       const std::string& task_type,
+                       TaskType task_type,
                        const std::string& action_id) {
-  DCHECK(task_type == kFileBrowserHandlerTaskType ||
-         task_type == kDriveTaskType ||
-         task_type == kFileHandlerTaskType);
   return base::StringPrintf("%s|%s|%s",
                             extension_id.c_str(),
-                            task_type.c_str(),
+                            TaskTypeToString(task_type).c_str(),
                             action_id.c_str());
 }
 
 std::string MakeDriveAppTaskId(const std::string& app_id) {
-  return MakeTaskID(app_id, kDriveTaskType, "open-with");
+  return MakeTaskID(app_id, TASK_TYPE_DRIVE_APP, "open-with");
 }
 
 bool ParseTaskID(const std::string& task_id, TaskDescriptor* task) {
@@ -160,10 +184,10 @@
   // TODO(satorux): We should get rid of this code: crbug.com/267359.
   if (count == 2) {
     if (StartsWithASCII(result[0], kDriveTaskExtensionPrefix, true)) {
-      task->task_type = kDriveTaskType;
+      task->task_type = TASK_TYPE_DRIVE_APP;
       task->app_id = result[0].substr(kDriveTaskExtensionPrefixLength);
     } else {
-      task->task_type = kFileBrowserHandlerTaskType;
+      task->task_type = TASK_TYPE_FILE_BROWSER_HANDLER;
       task->app_id = result[0];
     }
 
@@ -175,29 +199,30 @@
   if (count != 3)
     return false;
 
- task->app_id = result[0];
- task->task_type = result[1];
- DCHECK(task->task_type == kFileBrowserHandlerTaskType ||
-        task->task_type == kDriveTaskType ||
-        task->task_type == kFileHandlerTaskType);
- task->action_id = result[2];
+  TaskType task_type = StringToTaskType(result[1]);
+  if (task_type == TASK_TYPE_UNKNOWN)
+    return false;
+
+  task->app_id = result[0];
+  task->task_type = task_type;
+  task->action_id = result[2];
 
   return true;
 }
 
 bool ExecuteFileTask(Profile* profile,
                      const GURL& source_url,
-                     const std::string& file_browser_id,
+                     const std::string& app_id,
                      int32 tab_id,
                      const TaskDescriptor& task,
                      const std::vector<FileSystemURL>& file_urls,
                      const FileTaskFinishedCallback& done) {
   if (!FileBrowserHasAccessPermissionForFiles(profile, source_url,
-                                              file_browser_id, file_urls))
+                                              app_id, file_urls))
     return false;
 
   // drive::FileTaskExecutor is responsible to handle drive tasks.
-  if (task.task_type == kDriveTaskType) {
+  if (task.task_type == TASK_TYPE_DRIVE_APP) {
     DCHECK_EQ("open-with", task.action_id);
     drive::FileTaskExecutor* executor =
         new drive::FileTaskExecutor(profile, task.app_id);
@@ -214,7 +239,7 @@
     return false;
 
   // Execute the task.
-  if (task.task_type == kFileBrowserHandlerTaskType) {
+  if (task.task_type == TASK_TYPE_FILE_BROWSER_HANDLER) {
     return file_browser_handlers::ExecuteFileBrowserHandler(
         profile,
         extension,
@@ -222,7 +247,7 @@
         task.action_id,
         file_urls,
         done);
-  } else if (task.task_type == kFileHandlerTaskType) {
+  } else if (task.task_type == TASK_TYPE_FILE_HANDLER) {
     for (size_t i = 0; i != file_urls.size(); ++i) {
       apps::LaunchPlatformAppWithFileHandler(
           profile, extension, task.action_id, file_urls[i].path());
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_tasks.h b/chrome/browser/chromeos/extensions/file_manager/file_tasks.h
index 50a3e13..8d37fcb 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_tasks.h
@@ -127,17 +127,19 @@
 namespace file_manager {
 namespace file_tasks {
 
-// Task types encoded in task IDs. See also the comment at the beginning of
-// the file about <task-type>.
-extern const char kFileBrowserHandlerTaskType[];
-extern const char kFileHandlerTaskType[];
-extern const char kDriveTaskType[];
+// Task types as explained in the comment above. Search for <task-type>.
+enum TaskType {
+  TASK_TYPE_FILE_BROWSER_HANDLER,
+  TASK_TYPE_FILE_HANDLER,
+  TASK_TYPE_DRIVE_APP,
+  TASK_TYPE_UNKNOWN,  // Used only for handling errors.
+};
 
 // Describes a task.
 // See the comment above for <app-id>, <task-type>, and <action-id>.
 struct TaskDescriptor {
   TaskDescriptor(const std::string& in_app_id,
-                 const std::string& in_task_type,
+                 TaskType in_task_type,
                  const std::string& in_action_id)
       : app_id(in_app_id),
         task_type(in_task_type),
@@ -147,7 +149,7 @@
   }
 
   std::string app_id;
-  std::string task_type;
+  TaskType task_type;
   std::string action_id;
 };
 
@@ -167,11 +169,12 @@
                                       const std::string& suffix);
 
 // Generates task id for the task specified by |app_id|, |task_type| and
-// |action_id|. The |task_type| must be one of kFileBrowserHandlerTaskType,
-// kDriveTaskType or kFileHandlerTaskType.
-// <app-id> is either of Chrome Extension/App ID or Drive App ID.
+// |action_id|.
+//
+// |app_id| is either of Chrome Extension/App ID or Drive App ID.
+// |action_id| is a free-form string ID for the action.
 std::string MakeTaskID(const std::string& extension_id,
-                       const std::string& task_type,
+                       TaskType task_type,
                        const std::string& action_id);
 
 // Returns a task id for the Drive app with |app_id|.
@@ -198,6 +201,7 @@
 //
 // Parameters:
 // profile    - The profile used for making this function call.
+// app_id     - The ID of the app requesting the file task execution.
 // source_url - The source URL which originates this function call.
 // tab_id     - The ID of the tab which originates this function call.
 //              This can be 0 if no tab is associated.
@@ -208,7 +212,7 @@
 //              false.
 bool ExecuteFileTask(Profile* profile,
                      const GURL& source_url,
-                     const std::string& file_browser_id,
+                     const std::string& app_id,
                      int32 tab_id,
                      const TaskDescriptor& task,
                      const std::vector<fileapi::FileSystemURL>& file_urls,
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/file_tasks_unittest.cc
index c9d7146..ebd249f 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_tasks_unittest.cc
@@ -10,28 +10,49 @@
 namespace file_tasks {
 
 TEST(FileManagerFileTasksTest, MakeTaskID) {
-  EXPECT_EQ("app-id|app|action-id", MakeTaskID("app-id", "app", "action-id"));
+  EXPECT_EQ("app-id|file|action-id",
+            MakeTaskID("app-id", TASK_TYPE_FILE_BROWSER_HANDLER, "action-id"));
+  EXPECT_EQ("app-id|app|action-id",
+            MakeTaskID("app-id", TASK_TYPE_FILE_HANDLER, "action-id"));
+  EXPECT_EQ("app-id|drive|action-id",
+            MakeTaskID("app-id", TASK_TYPE_DRIVE_APP, "action-id"));
 }
 
 TEST(FileManagerFileTasksTest, MakeDriveAppTaskId) {
   EXPECT_EQ("app-id|drive|open-with", MakeDriveAppTaskId("app-id"));
 }
 
-TEST(FileManagerFileTasksTest, ParseTaskID_Basic) {
+TEST(FileManagerFileTasksTest, ParseTaskID_FileBrowserHandler) {
   TaskDescriptor task;
-  // A task ID usually has three parts.
+  EXPECT_TRUE(ParseTaskID("app-id|file|action-id", &task));
+  EXPECT_EQ("app-id", task.app_id);
+  EXPECT_EQ(TASK_TYPE_FILE_BROWSER_HANDLER, task.task_type);
+  EXPECT_EQ("action-id", task.action_id);
+}
+
+TEST(FileManagerFileTasksTest, ParseTaskID_FileHandler) {
+  TaskDescriptor task;
   EXPECT_TRUE(ParseTaskID("app-id|app|action-id", &task));
   EXPECT_EQ("app-id", task.app_id);
-  EXPECT_EQ("app", task.task_type);
+  EXPECT_EQ(TASK_TYPE_FILE_HANDLER, task.task_type);
+  EXPECT_EQ("action-id", task.action_id);
+}
+
+TEST(FileManagerFileTasksTest, ParseTaskID_DriveApp) {
+  TaskDescriptor task;
+  EXPECT_TRUE(ParseTaskID("app-id|drive|action-id", &task));
+  EXPECT_EQ("app-id", task.app_id);
+  EXPECT_EQ(TASK_TYPE_DRIVE_APP, task.task_type);
   EXPECT_EQ("action-id", task.action_id);
 }
 
 TEST(FileManagerFileTasksTest, ParseTaskID_Legacy) {
   TaskDescriptor task;
-  // A legacy task ID only has two parts. The task type should be to "file".
+  // A legacy task ID only has two parts. The task type should be
+  // TASK_TYPE_FILE_BROWSER_HANDLER.
   EXPECT_TRUE(ParseTaskID("app-id|action-id", &task));
   EXPECT_EQ("app-id", task.app_id);
-  EXPECT_EQ("file", task.task_type);
+  EXPECT_EQ(TASK_TYPE_FILE_BROWSER_HANDLER, task.task_type);
   EXPECT_EQ("action-id", task.action_id);
 }
 
@@ -41,7 +62,7 @@
   // prefixed with "drive-app:".
   EXPECT_TRUE(ParseTaskID("drive-app:app-id|action-id", &task));
   EXPECT_EQ("app-id", task.app_id);
-  EXPECT_EQ("drive", task.task_type);
+  EXPECT_EQ(TASK_TYPE_DRIVE_APP, task.task_type);
   EXPECT_EQ("action-id", task.action_id);
 }
 
@@ -50,5 +71,10 @@
   EXPECT_FALSE(ParseTaskID("invalid", &task));
 }
 
+TEST(FileManagerFileTasksTest, ParseTaskID_UnknownTaskType) {
+  TaskDescriptor task;
+  EXPECT_FALSE(ParseTaskID("app-id|unknown|action-id", &task));
+}
+
 }  // namespace file_tasks
 }  // namespace file_manager.
diff --git a/chrome/browser/chromeos/extensions/file_manager/fileapi_util.cc b/chrome/browser/chromeos/extensions/file_manager/fileapi_util.cc
index 52a93e4..fdabc2d 100644
--- a/chrome/browser/chromeos/extensions/file_manager/fileapi_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/fileapi_util.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
 
+#include "base/files/file_path.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
@@ -11,11 +12,13 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
+#include "net/base/escape.h"
 #include "url/gurl.h"
 #include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/common/fileapi/file_system_util.h"
 
 namespace file_manager {
-namespace fileapi_util {
+namespace util {
 
 fileapi::FileSystemContext* GetFileSystemContextForExtensionId(
     Profile* profile,
@@ -34,5 +37,60 @@
       GetFileSystemContext();
 }
 
-}  // namespace fileapi_util
+GURL ConvertRelativeFilePathToFileSystemUrl(const base::FilePath& relative_path,
+                                            const std::string& extension_id) {
+  GURL base_url = fileapi::GetFileSystemRootURI(
+      extensions::Extension::GetBaseURLFromExtensionId(extension_id),
+      fileapi::kFileSystemTypeExternal);
+  return GURL(base_url.spec() +
+              net::EscapeUrlEncodedData(relative_path.AsUTF8Unsafe(),
+                                        false));  // Space to %20 instead of +.
+}
+
+bool ConvertAbsoluteFilePathToFileSystemUrl(
+    Profile* profile,
+    const base::FilePath& absolute_path,
+    const std::string& extension_id,
+    GURL* url) {
+  base::FilePath relative_path;
+  if (!ConvertAbsoluteFilePathToRelativeFileSystemPath(
+          profile,
+          extension_id,
+          absolute_path,
+          &relative_path)) {
+    return false;
+  }
+  *url = ConvertRelativeFilePathToFileSystemUrl(relative_path, extension_id);
+  return true;
+}
+
+bool ConvertAbsoluteFilePathToRelativeFileSystemPath(
+    Profile* profile,
+    const std::string& extension_id,
+    const base::FilePath& absolute_path,
+    base::FilePath* virtual_path) {
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile)->extension_service();
+  // May be NULL during unit_tests.
+  if (!service)
+    return false;
+
+  // File browser APIs are meant to be used only from extension context, so the
+  // extension's site is the one in whose file system context the virtual path
+  // should be found.
+  GURL site = service->GetSiteForExtensionId(extension_id);
+  fileapi::ExternalFileSystemBackend* backend =
+      content::BrowserContext::GetStoragePartitionForSite(profile, site)->
+          GetFileSystemContext()->external_backend();
+  if (!backend)
+    return false;
+
+  // Find if this file path is managed by the external backend.
+  if (!backend->GetVirtualPath(absolute_path, virtual_path))
+    return false;
+
+  return true;
+}
+
+}  // namespace util
 }  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/fileapi_util.h b/chrome/browser/chromeos/extensions/file_manager/fileapi_util.h
index 415fb2c..0d6e08f 100644
--- a/chrome/browser/chromeos/extensions/file_manager/fileapi_util.h
+++ b/chrome/browser/chromeos/extensions/file_manager/fileapi_util.h
@@ -8,9 +8,14 @@
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_FILEAPI_UTIL_H_
 
 #include <string>
+#include "url/gurl.h"
 
 class Profile;
 
+namespace base {
+class FilePath;
+}
+
 namespace content {
 class RenderViewHost;
 }
@@ -20,7 +25,7 @@
 }
 
 namespace file_manager {
-namespace fileapi_util {
+namespace util {
 
 // Returns a file system context associated with the given profile and the
 // extension ID.
@@ -34,7 +39,30 @@
     Profile* profile,
     content::RenderViewHost* render_view_host);
 
-}  // namespace fileapi_util
+// Converts |relative_path| (e.g., "drive/root" or "Downloads") into external
+// filesystem URL (e.g., filesystem://id/external/drive/root).
+GURL ConvertRelativeFilePathToFileSystemUrl(const base::FilePath& relative_path,
+                                            const std::string& extension_id);
+
+// Converts |absolute_path| (e.g., "/special/drive/root" or
+// "/home/chronos/user/Downloads") into external filesystem URL. Returns false
+// if |absolute_path| is not managed by the external filesystem provider.
+bool ConvertAbsoluteFilePathToFileSystemUrl(
+    Profile* profile,
+    const base::FilePath& absolute_path,
+    const std::string& extension_id,
+    GURL* url);
+
+// Converts |absolute_path| into |relative_path| within the external
+// provider in File API. Returns false if |absolute_path| is not managed
+// by the external filesystem provider.
+bool ConvertAbsoluteFilePathToRelativeFileSystemPath(
+    Profile* profile,
+    const std::string& extension_id,
+    const base::FilePath& absolute_path,
+    base::FilePath* relative_path);
+
+}  // namespace util
 }  // namespace file_manager
 
 #endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_FILEAPI_UTIL_H_
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 91dcbfd..0032cdb 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -9,9 +9,9 @@
 #include "chrome/browser/chromeos/drive/drive_app_registry.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/drive/logging.h"
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_tasks.h"
 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -25,7 +25,6 @@
 namespace file_manager {
 namespace {
 
-
 // List of connection types of drive.
 // Keep this in sync with the DriveConnectionType in volume_manager.js.
 const char kDriveConnectionTypeOffline[] = "offline";
@@ -677,7 +676,7 @@
 
   integration_service->file_system()->GetShareUrl(
       drive_path,
-      util::GetFileBrowserExtensionUrl(),  // embed origin
+      util::GetFileManagerBaseUrl(),  // embed origin
       base::Bind(&GetShareUrlFunction::OnGetShareUrl, this));
   return true;
 }
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 c77c7c4..f709142 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
@@ -73,7 +73,7 @@
   std::string mount_path;
   if (!volume->mount_path().empty()) {
     base::FilePath relative_mount_path;
-    util::ConvertFileToRelativeFileSystemPath(
+    util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
         profile, extension_id, base::FilePath(volume->mount_path()),
         &relative_mount_path);
     mount_path = relative_mount_path.value();
@@ -145,7 +145,7 @@
 // Returns 0 if it could not be queried.
 size_t GetFileNameMaxLengthOnBlockingPool(const std::string& path) {
   struct statvfs stat = {};
-  if (statvfs(path.c_str(), &stat) != 0) {
+  if (HANDLE_EINTR(statvfs(path.c_str(), &stat)) != 0) {
     // The filesystem seems not supporting statvfs(). Assume it to be a commonly
     // used bound 255, and log the failure.
     LOG(ERROR) << "Cannot statvfs() the name length limit for: " << path;
@@ -274,7 +274,7 @@
   set_log_on_completion(true);
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      fileapi_util::GetFileSystemContextForRenderViewHost(
+      util::GetFileSystemContextForRenderViewHost(
           profile(), render_view_host());
 
   const GURL origin_url = source_url_.GetOrigin();
@@ -313,7 +313,7 @@
     return false;
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      fileapi_util::GetFileSystemContextForRenderViewHost(
+      util::GetFileSystemContextForRenderViewHost(
           profile(), render_view_host());
 
   FileSystemURL file_watch_url = file_system_context->CrackURL(GURL(url));
@@ -538,7 +538,7 @@
     return false;
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      fileapi_util::GetFileSystemContextForRenderViewHost(
+      util::GetFileSystemContextForRenderViewHost(
           profile(), render_view_host());
 
   fileapi::FileSystemURL filesystem_url(
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 115b18c..e102016 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -42,11 +42,8 @@
 
   const PrefService* service = profile_->GetPrefs();
 
-  drive::DriveIntegrationService* integration_service =
-      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
-  bool drive_enabled = (integration_service != NULL);
-
-  value->SetBoolean("driveEnabled", drive_enabled);
+  value->SetBoolean("driveEnabled",
+                    drive::util::IsDriveEnabledForProfile(profile_));
 
   value->SetBoolean("cellularDisabled",
                     service->GetBoolean(prefs::kDisableDriveOverCellular));
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 d42b751..52c47fe 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_mount.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/disks/disk_mount_manager.h"
@@ -41,7 +42,7 @@
   base::FilePath relative_mount_path;
   // Convert mount point path to relative path with the external file system
   // exposed within File API.
-  if (util::ConvertFileToRelativeFileSystemPath(
+  if (util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
           profile,
           extension_id,
           base::FilePath(mount_point_info.mount_path),
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 465d4f3..fe21f77 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -503,9 +503,11 @@
 #undef SET_STRING
 
   dict->SetBoolean("PDF_VIEW_ENABLED",
-                   util::ShouldBeOpenedWithPlugin(profile(), ".pdf"));
+                   util::ShouldBeOpenedWithPlugin(profile(),
+                                                  FILE_PATH_LITERAL(".pdf")));
   dict->SetBoolean("SWF_VIEW_ENABLED",
-                   util::ShouldBeOpenedWithPlugin(profile(), ".swf"));
+                   util::ShouldBeOpenedWithPlugin(profile(),
+                                                  FILE_PATH_LITERAL(".swf")));
 
   webui::SetFontAndTextDirection(dict);
 
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 e05a072..2456b40 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -378,7 +378,7 @@
          i != file_handlers.end(); ++i) {
       DictionaryValue* task = new DictionaryValue;
       std::string task_id = file_tasks::MakeTaskID(
-          extension->id(), file_tasks::kFileHandlerTaskType, (*i)->id);
+          extension->id(), file_tasks::TASK_TYPE_FILE_HANDLER, (*i)->id);
       task->SetString("taskId", task_id);
       task->SetString("title", (*i)->title);
       if (!(*default_already_set) && ContainsKey(default_tasks, task_id)) {
@@ -435,7 +435,9 @@
     CHECK(extension);
     DictionaryValue* task = new DictionaryValue;
     task->SetString("taskId", file_tasks::MakeTaskID(
-        extension_id, file_tasks::kFileBrowserHandlerTaskType, handler->id()));
+        extension_id,
+        file_tasks::TASK_TYPE_FILE_BROWSER_HANDLER,
+        handler->id()));
     task->SetString("title", handler->title());
     // TODO(zelidrag): Figure out how to expose icon URL that task defined in
     // manifest instead of the default extension icon.
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 771b8ab..e076861 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
@@ -158,7 +158,7 @@
   DCHECK(profile);
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context =
-      fileapi_util::GetFileSystemContextForRenderViewHost(
+      util::GetFileSystemContextForRenderViewHost(
           profile, render_view_host);
 
   const fileapi::FileSystemURL filesystem_url(
diff --git a/chrome/browser/chromeos/extensions/file_manager/url_util.cc b/chrome/browser/chromeos/extensions/file_manager/url_util.cc
new file mode 100644
index 0000000..5f178fb
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/url_util.cc
@@ -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.
+
+#include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
+
+#include "base/json/json_writer.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
+#include "net/base/escape.h"
+
+namespace file_manager {
+namespace util {
+namespace {
+
+// Returns a file manager URL for the given |path|.
+GURL GetFileManagerUrl(const char* path) {
+  return GURL(std::string("chrome-extension://") + kFileManagerAppId + path);
+}
+
+// Converts a numeric dialog type to a string.
+std::string GetDialogTypeAsString(
+    ui::SelectFileDialog::Type dialog_type) {
+  std::string type_str;
+  switch (dialog_type) {
+    case ui::SelectFileDialog::SELECT_NONE:
+      type_str = "full-page";
+      break;
+
+    case ui::SelectFileDialog::SELECT_FOLDER:
+      type_str = "folder";
+      break;
+
+    case ui::SelectFileDialog::SELECT_UPLOAD_FOLDER:
+      type_str = "upload-folder";
+      break;
+
+    case ui::SelectFileDialog::SELECT_SAVEAS_FILE:
+      type_str = "saveas-file";
+      break;
+
+    case ui::SelectFileDialog::SELECT_OPEN_FILE:
+      type_str = "open-file";
+      break;
+
+    case ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE:
+      type_str = "open-multi-file";
+      break;
+
+    default:
+      NOTREACHED();
+  }
+
+  return type_str;
+}
+
+}  // namespace
+
+GURL GetFileManagerBaseUrl() {
+  return GetFileManagerUrl("/");
+}
+
+GURL GetFileManagerMainPageUrl() {
+  return GetFileManagerUrl("/main.html");
+}
+
+GURL GetFileManagerMainPageUrlWithParams(
+    ui::SelectFileDialog::Type type,
+    const string16& title,
+    const base::FilePath& default_virtual_path,
+    const ui::SelectFileDialog::FileTypeInfo* file_types,
+    int file_type_index,
+    const base::FilePath::StringType& default_extension) {
+  base::DictionaryValue arg_value;
+  arg_value.SetString("type", GetDialogTypeAsString(type));
+  arg_value.SetString("title", title);
+  arg_value.SetString("defaultPath", default_virtual_path.value());
+  arg_value.SetString("defaultExtension", default_extension);
+
+  if (file_types) {
+    base::ListValue* types_list = new base::ListValue();
+    for (size_t i = 0; i < file_types->extensions.size(); ++i) {
+      base::ListValue* extensions_list = new base::ListValue();
+      for (size_t j = 0; j < file_types->extensions[i].size(); ++j) {
+        extensions_list->Append(
+            new base::StringValue(file_types->extensions[i][j]));
+      }
+
+      base::DictionaryValue* dict = new base::DictionaryValue();
+      dict->Set("extensions", extensions_list);
+
+      if (i < file_types->extension_description_overrides.size()) {
+        string16 desc = file_types->extension_description_overrides[i];
+        dict->SetString("description", desc);
+      }
+
+      // file_type_index is 1-based. 0 means no selection at all.
+      dict->SetBoolean("selected",
+                       (static_cast<size_t>(file_type_index) == (i + 1)));
+
+      types_list->Set(i, dict);
+    }
+    arg_value.Set("typeList", types_list);
+
+    arg_value.SetBoolean("includeAllFiles", file_types->include_all_files);
+  }
+
+  // If the caller cannot handle Drive path, the file chooser dialog need to
+  // return resolved local native paths to the selected files.
+  arg_value.SetBoolean("shouldReturnLocalPath",
+                       !file_types || !file_types->support_drive);
+
+  std::string json_args;
+  base::JSONWriter::Write(&arg_value, &json_args);
+
+  // kChromeUIFileManagerURL could not be used since query parameters are not
+  // supported for it.
+  std::string url = GetFileManagerMainPageUrl().spec() + '?' +
+      net::EscapeUrlEncodedData(json_args,
+                                false);  // Space to %20 instead of +.
+  return GURL(url);
+}
+
+GURL GetActionChoiceUrl(const base::FilePath& virtual_path,
+                        bool advanced_mode) {
+  std::string url = GetFileManagerUrl("/action_choice.html").spec();
+  if (advanced_mode)
+    url += "?advanced-mode";
+  url += "#/" + net::EscapeUrlEncodedData(virtual_path.value(),
+                                          false);  // Space to %20 instead of +.
+  return GURL(url);
+}
+
+}  // namespace util
+}  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/file_manager/url_util.h b/chrome/browser/chromeos/extensions/file_manager/url_util.h
new file mode 100644
index 0000000..d14bb1c
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/url_util.h
@@ -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.
+//
+// This file provides URL-related utilities.
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_URL_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_URL_UTIL_H_
+
+#include <string>
+
+#include "base/strings/string16.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+#include "url/gurl.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace file_manager {
+namespace util {
+
+// Returns the file manager's base URL, which just looks like
+// chrome-extension://<app-id>/.
+GURL GetFileManagerBaseUrl();
+
+// Returns the file manager's main page URL.
+GURL GetFileManagerMainPageUrl();
+
+// Returns the file manager's main page URL with parameters encoded as JSON
+// in the query string section. |file_types| is optional.
+GURL GetFileManagerMainPageUrlWithParams(
+    ui::SelectFileDialog::Type type,
+    const string16& title,
+    const base::FilePath& default_virtual_path,
+    const ui::SelectFileDialog::FileTypeInfo* file_types,
+    int file_type_index,
+    const base::FilePath::StringType& default_extension);
+
+// Returns the file manager's action choice URL.
+GURL GetActionChoiceUrl(const base::FilePath& virtual_path,
+                        bool advanced_mode);
+
+}  // namespace util
+}  // namespace file_manager
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_URL_UTIL_H_
diff --git a/chrome/browser/chromeos/extensions/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/url_util_unittest.cc
new file mode 100644
index 0000000..88b327e
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/url_util_unittest.cc
@@ -0,0 +1,135 @@
+// Copyright 2013 The Chromium Authors. 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/extensions/file_manager/url_util.h"
+
+#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "net/base/escape.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace file_manager {
+namespace util {
+namespace {
+
+// Pretty print the JSON escaped in the query string.
+std::string PrettyPrintEscapedJson(const std::string& query) {
+  const std::string json = net::UnescapeURLComponent(
+      query, net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS);
+  scoped_ptr<base::Value> value(base::JSONReader::Read(json));
+  std::string pretty_json;
+  base::JSONWriter::WriteWithOptions(value.get(),
+                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
+                                     &pretty_json);
+  return pretty_json;
+}
+
+TEST(FileManagerUrlUtilTest, GetFileManagerBaseUrl) {
+  EXPECT_EQ("chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/",
+            GetFileManagerBaseUrl().spec());
+}
+
+TEST(FileManagerUrlUtilTest, GetFileManagerMainPageUrl) {
+  EXPECT_EQ("chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/main.html",
+            GetFileManagerMainPageUrl().spec());
+}
+
+TEST(FileManagerUrlUtilTest, GetFileManagerMainPageUrlWithParams_NoFileTypes) {
+  const GURL url = GetFileManagerMainPageUrlWithParams(
+      ui::SelectFileDialog::SELECT_OPEN_FILE,
+      base::UTF8ToUTF16("some title"),
+      base::FilePath::FromUTF8Unsafe("foo.txt"),
+      NULL,  // No file types
+      0,  // Hence no file type index.
+      FILE_PATH_LITERAL("txt"));
+  EXPECT_EQ("chrome-extension", url.scheme());
+  EXPECT_EQ("hhaomjibdihmijegdhdafkllkbggdgoj", url.host());
+  EXPECT_EQ("/main.html", url.path());
+  // Confirm that "%20" is used instead of "+" in the query.
+  EXPECT_TRUE(url.query().find("+") == std::string::npos);
+  EXPECT_TRUE(url.query().find("%20") != std::string::npos);
+  // The escaped query is hard to read. Pretty print the escaped JSON.
+  EXPECT_EQ("{\n"
+            "   \"defaultExtension\": \"txt\",\n"
+            "   \"defaultPath\": \"foo.txt\",\n"
+            "   \"shouldReturnLocalPath\": true,\n"
+            "   \"title\": \"some title\",\n"
+            "   \"type\": \"open-file\"\n"
+            "}\n",
+            PrettyPrintEscapedJson(url.query()));
+}
+
+TEST(FileManagerUrlUtilTest,
+     GetFileManagerMainPageUrlWithParams_WithFileTypes) {
+  // Create a FileTypeInfo which looks like:
+  // extensions: [["htm", "html"], ["txt"]]
+  // descriptions: ["HTML", "TEXT"]
+  ui::SelectFileDialog::FileTypeInfo file_types;
+  file_types.extensions.push_back(std::vector<base::FilePath::StringType>());
+  file_types.extensions[0].push_back(FILE_PATH_LITERAL("htm"));
+  file_types.extensions[0].push_back(FILE_PATH_LITERAL("html"));
+  file_types.extensions.push_back(std::vector<base::FilePath::StringType>());
+  file_types.extensions[1].push_back(FILE_PATH_LITERAL("txt"));
+  file_types.extension_description_overrides.push_back(
+      base::UTF8ToUTF16("HTML"));
+  file_types.extension_description_overrides.push_back(
+      base::UTF8ToUTF16("TEXT"));
+  // "shouldReturnLocalPath" will be false if drive is supported.
+  file_types.support_drive = true;
+
+  const GURL url = GetFileManagerMainPageUrlWithParams(
+      ui::SelectFileDialog::SELECT_OPEN_FILE,
+      base::UTF8ToUTF16("some title"),
+      base::FilePath::FromUTF8Unsafe("foo.txt"),
+      &file_types,
+      1,  // The file type index is 1-based.
+      FILE_PATH_LITERAL("txt"));
+  EXPECT_EQ("chrome-extension", url.scheme());
+  EXPECT_EQ("hhaomjibdihmijegdhdafkllkbggdgoj", url.host());
+  EXPECT_EQ("/main.html", url.path());
+  // Confirm that "%20" is used instead of "+" in the query.
+  EXPECT_TRUE(url.query().find("+") == std::string::npos);
+  EXPECT_TRUE(url.query().find("%20") != std::string::npos);
+  // The escaped query is hard to read. Pretty print the escaped JSON.
+  EXPECT_EQ("{\n"
+            "   \"defaultExtension\": \"txt\",\n"
+            "   \"defaultPath\": \"foo.txt\",\n"
+            "   \"includeAllFiles\": false,\n"
+            "   \"shouldReturnLocalPath\": false,\n"
+            "   \"title\": \"some title\",\n"
+            "   \"type\": \"open-file\",\n"
+            "   \"typeList\": [ {\n"
+            "      \"description\": \"HTML\",\n"
+            "      \"extensions\": [ \"htm\", \"html\" ],\n"
+            "      \"selected\": true\n"
+            "   }, {\n"
+            "      \"description\": \"TEXT\",\n"
+            "      \"extensions\": [ \"txt\" ],\n"
+            "      \"selected\": false\n"
+            "   } ]\n"
+            "}\n",
+            PrettyPrintEscapedJson(url.query()));
+}
+
+TEST(FileManagerUrlUtilTest, GetActionChoiceUrl_RegularMode) {
+  EXPECT_EQ("chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/"
+            "action_choice.html#/foo.txt",
+            GetActionChoiceUrl(base::FilePath::FromUTF8Unsafe("foo.txt"),
+                               false).spec());
+}
+
+TEST(FileManagerUrlUtilTest, GetActionChoiceUrl_AdvancedMode) {
+  EXPECT_EQ("chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/"
+            "action_choice.html?advanced-mode#/foo.txt",
+            GetActionChoiceUrl(base::FilePath::FromUTF8Unsafe("foo.txt"),
+                               true).spec());
+}
+
+}  // namespace
+}  // namespace util
+}  // namespace file_manager
diff --git a/chrome/browser/chromeos/extensions/media_player_api.cc b/chrome/browser/chromeos/extensions/media_player_api.cc
index dfb783d..dae8a2c 100644
--- a/chrome/browser/chromeos/extensions/media_player_api.cc
+++ b/chrome/browser/chromeos/extensions/media_player_api.cc
@@ -7,87 +7,10 @@
 #include "base/lazy_instance.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/extensions/media_player_event_router.h"
-#include "chrome/browser/chromeos/media/media_player.h"
-
-namespace {
-
-static const char kPropertyItems[] = "items";
-static const char kPropertyPosition[] = "position";
-
-}  // namespace
 
 namespace extensions {
 
-bool MediaPlayerPrivatePlayFunction::RunImpl() {
-  if (args_->GetSize() < 2) {
-    return false;
-  }
-
-  ListValue* url_list = NULL;
-  if (!args_->GetList(0, &url_list))
-    return false;
-
-  int position;
-  if (!args_->GetInteger(1, &position))
-    return false;
-
-  MediaPlayer* player = MediaPlayer::GetInstance();
-
-  player->PopupMediaPlayer();
-  player->ClearPlaylist();
-
-  size_t len = url_list->GetSize();
-  for (size_t i = 0; i < len; ++i) {
-    std::string path;
-    url_list->GetString(i, &path);
-    player->EnqueueMediaFileUrl(GURL(path));
-  }
-
-  player->SetPlaylistPosition(position);
-  player->NotifyPlaylistChanged();
-
-  return true;
-}
-
-static ListValue* GetPlaylistItems() {
-  ListValue* result = new ListValue();
-
-  MediaPlayer::UrlVector const& src = MediaPlayer::GetInstance()->GetPlaylist();
-
-  for (size_t i = 0; i < src.size(); i++) {
-    result->Append(new base::StringValue(src[i].spec()));
-  }
-  return result;
-}
-
-bool MediaPlayerPrivateGetPlaylistFunction::RunImpl() {
-  DictionaryValue* result = new DictionaryValue();
-  MediaPlayer* player = MediaPlayer::GetInstance();
-
-  result->Set(kPropertyItems, GetPlaylistItems());
-  result->SetInteger(kPropertyPosition, player->GetPlaylistPosition());
-
-  SetResult(result);
-  return true;
-}
-
-// TODO(kaznacheev): rename the API method to adjustWindowHeight here and in
-// media_player_private.json.
-bool MediaPlayerPrivateSetWindowHeightFunction::RunImpl() {
-  int height_diff;
-  if (!args_->GetInteger(0, &height_diff))
-    return false;
-  MediaPlayer::GetInstance()->AdjustWindowHeight(height_diff);
-  return true;
-}
-
-bool MediaPlayerPrivateCloseWindowFunction::RunImpl() {
-  MediaPlayer::GetInstance()->CloseWindow();
-  return true;
-}
-
-MediaPlayerAPI::MediaPlayerAPI(Profile* profile)
-    : profile_(profile) {
+MediaPlayerAPI::MediaPlayerAPI(Profile* profile) : profile_(profile) {
 }
 
 MediaPlayerAPI::~MediaPlayerAPI() {
diff --git a/chrome/browser/chromeos/extensions/media_player_api.h b/chrome/browser/chromeos/extensions/media_player_api.h
index 466d066..24df282 100644
--- a/chrome/browser/chromeos/extensions/media_player_api.h
+++ b/chrome/browser/chromeos/extensions/media_player_api.h
@@ -18,57 +18,6 @@
 namespace extensions {
 class MediaPlayerEventRouter;
 
-// Implements the chrome.mediaPlayerPrivate.play method.
-class MediaPlayerPrivatePlayFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("mediaPlayerPrivate.play", MEDIAPLAYERPRIVATE_PLAY)
-
- protected:
-  virtual ~MediaPlayerPrivatePlayFunction() {}
-
-  // SyncExtensionFunction overrides.
-  virtual bool RunImpl() OVERRIDE;
-};
-
-// Implements the chrome.mediaPlayerPrivate.getPlaylist method.
-class MediaPlayerPrivateGetPlaylistFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("mediaPlayerPrivate.getPlaylist",
-                             MEDIAPLAYERPRIVATE_GETPLAYLIST)
-
- protected:
-  virtual ~MediaPlayerPrivateGetPlaylistFunction() {}
-
-  // SyncExtensionFunction overrides.
-  virtual bool RunImpl() OVERRIDE;
-};
-
-// Implements the chrome.mediaPlayerPrivate.setWindowHeight method.
-class MediaPlayerPrivateSetWindowHeightFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("mediaPlayerPrivate.setWindowHeight",
-                             MEDIAPLAYERPRIVATE_SETWINDOWHEIGHT)
-
- protected:
-  virtual ~MediaPlayerPrivateSetWindowHeightFunction() {}
-
-  // SyncExtensionFunction overrides.
-  virtual bool RunImpl() OVERRIDE;
-};
-
-// Implements the chrome.mediaPlayerPrivate.closeWindow method.
-class MediaPlayerPrivateCloseWindowFunction : public SyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("mediaPlayerPrivate.closeWindow",
-                             MEDIAPLAYERPRIVATE_CLOSEWINDOW)
-
- protected:
-  virtual ~MediaPlayerPrivateCloseWindowFunction() {}
-
-  // SyncExtensionFunction overrides.
-  virtual bool RunImpl() OVERRIDE;
-};
-
 class MediaPlayerAPI : public ProfileKeyedAPI {
  public:
   explicit MediaPlayerAPI(Profile* profile);
diff --git a/chrome/browser/chromeos/extensions/media_player_event_router.cc b/chrome/browser/chromeos/extensions/media_player_event_router.cc
index 619535c..0f81293 100644
--- a/chrome/browser/chromeos/extensions/media_player_event_router.cc
+++ b/chrome/browser/chromeos/extensions/media_player_event_router.cc
@@ -32,10 +32,6 @@
   BroadcastEvent(profile_, "mediaPlayerPrivate.onNextTrack");
 }
 
-void MediaPlayerEventRouter::NotifyPlaylistChanged() {
-  BroadcastEvent(profile_, "mediaPlayerPrivate.onPlaylistChanged");
-}
-
 void MediaPlayerEventRouter::NotifyPrevTrack() {
   BroadcastEvent(profile_, "mediaPlayerPrivate.onPrevTrack");
 }
diff --git a/chrome/browser/chromeos/extensions/media_player_event_router.h b/chrome/browser/chromeos/extensions/media_player_event_router.h
index 2fcbe7d..d872405 100644
--- a/chrome/browser/chromeos/extensions/media_player_event_router.h
+++ b/chrome/browser/chromeos/extensions/media_player_event_router.h
@@ -20,10 +20,7 @@
   // Send notification that next-track shortcut key was pressed.
   void NotifyNextTrack();
 
-  // Send notification that playlist changed.
-  void NotifyPlaylistChanged();
-
-  // Send notification that previous-track shortcut key was pressed.
+ // Send notification that previous-track shortcut key was pressed.
   void NotifyPrevTrack();
 
   // Send notification that play/pause shortcut key was pressed.
diff --git a/chrome/browser/chromeos/fileapi/file_system_backend.cc b/chrome/browser/chromeos/fileapi/file_system_backend.cc
index f25daa0..43a62c1 100644
--- a/chrome/browser/chromeos/fileapi/file_system_backend.cc
+++ b/chrome/browser/chromeos/fileapi/file_system_backend.cc
@@ -142,6 +142,13 @@
     return false;
 
   std::string extension_id = origin_url.host();
+  // TODO(mtomasz): Temporarily whitelist TimeScapes. Remove this in M-31.
+  // See: crbug.com/271946
+  if (extension_id == "mppoamgbcpnkpacolchbacppkflagjbp" &&
+      url.type() == fileapi::kFileSystemTypeRestrictedNativeLocal) {
+    return true;
+  }
+
   // Check first to make sure this extension has fileBrowserHander permissions.
   if (!special_storage_policy_->IsFileHandler(extension_id))
     return false;
diff --git a/chrome/browser/chromeos/input_method/candidate_window_controller_impl.h b/chrome/browser/chromeos/input_method/candidate_window_controller_impl.h
index 743cd52..caa4d45 100644
--- a/chrome/browser/chromeos/input_method/candidate_window_controller_impl.h
+++ b/chrome/browser/chromeos/input_method/candidate_window_controller_impl.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/chromeos/input_method/candidate_window_view.h"
 #include "chrome/browser/chromeos/input_method/infolist_window_view.h"
 #include "chromeos/dbus/ibus/ibus_panel_service.h"
+#include "chromeos/ime/ibus_bridge.h"
 #include "chromeos/ime/ibus_daemon_controller.h"
 
 namespace views {
diff --git a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
index 376b90a..2a61f89 100644
--- a/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.cc
@@ -14,8 +14,8 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/common/manifest_constants.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace chromeos {
@@ -177,18 +177,18 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
   DCHECK(out);
   std::string type;
-  if (!dict.GetString(extension_manifest_keys::kType, &type))
+  if (!dict.GetString(extensions::manifest_keys::kType, &type))
     return false;
   if (type != "ime")
     return false;
-  if (!dict.GetString(extension_manifest_keys::kId, &out->engine_id))
+  if (!dict.GetString(extensions::manifest_keys::kId, &out->engine_id))
     return false;
-  if (!dict.GetString(extension_manifest_keys::kName, &out->display_name))
+  if (!dict.GetString(extensions::manifest_keys::kName, &out->display_name))
     return false;
 
   std::set<std::string> languages;
   const base::Value* language_value = NULL;
-  if (dict.Get(extension_manifest_keys::kLanguage, &language_value)) {
+  if (dict.Get(extensions::manifest_keys::kLanguage, &language_value)) {
     if (language_value->GetType() == base::Value::TYPE_STRING) {
       std::string language_str;
       language_value->GetAsString(&language_str);
@@ -207,7 +207,7 @@
   out->language_codes.assign(languages.begin(), languages.end());
 
   const ListValue* layouts = NULL;
-  if (!dict.GetList(extension_manifest_keys::kLayouts, &layouts))
+  if (!dict.GetList(extensions::manifest_keys::kLayouts, &layouts))
     return false;
 
   for (size_t i = 0; i < layouts->GetSize(); ++i) {
@@ -224,11 +224,11 @@
     const std::string& extension_id,
     ComponentExtensionIME* out) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  if (!manifest.GetString(extension_manifest_keys::kDescription,
+  if (!manifest.GetString(extensions::manifest_keys::kDescription,
                           &out->description))
     return false;
   std::string url_string;
-  if (!manifest.GetString(extension_manifest_keys::kOptionsPage, &url_string))
+  if (!manifest.GetString(extensions::manifest_keys::kOptionsPage, &url_string))
     return true;  // It's okay to return true on no option page case.
 
   GURL url = extensions::Extension::GetResourceURL(
@@ -271,7 +271,7 @@
     component_ime.id = whitelisted_component_extension[i].id;
 
     const ListValue* component_list;
-    if (!manifest->GetList(extension_manifest_keys::kInputComponents,
+    if (!manifest->GetList(extensions::manifest_keys::kInputComponents,
                            &component_list))
       continue;
 
diff --git a/chrome/browser/chromeos/input_method/ibus_controller.h b/chrome/browser/chromeos/input_method/ibus_controller.h
index 0c3830a..1645b08 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller.h
+++ b/chrome/browser/chromeos/input_method/ibus_controller.h
@@ -12,14 +12,11 @@
 namespace chromeos {
 namespace input_method {
 
-struct InputMethodConfigValue;
 struct InputMethodProperty;
 typedef std::vector<InputMethodProperty> InputMethodPropertyList;
 
 // IBusController is used to interact with the system input method framework
 // (which is currently IBus).
-// TODO(nona): Split this class into IBusPropertyHandler and IBusConfigHandler.
-//             Note: IBusConfig will be deprecated once ibus-daemon is gone.
 class IBusController {
  public:
   class Observer {
@@ -39,14 +36,6 @@
 
   virtual void ClearProperties() = 0;
 
-  // Sets a configuration of an input method engine. Returns true if the
-  // configuration is successfully set. For example, when you set
-  // "engine/Mozc/history_learning_level", |section| should be "engine/Mozc",
-  // and |config_name| should be "history_learning_level".
-  virtual bool SetInputMethodConfig(const std::string& section,
-                                    const std::string& config_name,
-                                    const InputMethodConfigValue& value) = 0;
-
   // Activates the input method property specified by the |key|. Returns true on
   // success.
   virtual bool ActivateInputMethodProperty(const std::string& key) = 0;
diff --git a/chrome/browser/chromeos/input_method/ibus_controller_base.cc b/chrome/browser/chromeos/input_method/ibus_controller_base.cc
index be8592b..0f16084 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller_base.cc
+++ b/chrome/browser/chromeos/input_method/ibus_controller_base.cc
@@ -21,39 +21,11 @@
   observers_.RemoveObserver(observer);
 }
 
-bool IBusControllerBase::SetInputMethodConfig(
-    const std::string& section,
-    const std::string& config_name,
-    const InputMethodConfigValue& value) {
-  DCHECK(!section.empty());
-  DCHECK(!config_name.empty());
-
-  const ConfigKeyType key(section, config_name);
-  if (!SetInputMethodConfigInternal(key, value))
-    return false;
-  current_config_values_[key] = value;
-  return true;
-}
-
 const InputMethodPropertyList&
 IBusControllerBase::GetCurrentProperties() const {
   return current_property_list_;
 }
 
-bool IBusControllerBase::GetInputMethodConfigForTesting(
-    const std::string& section,
-    const std::string& config_name,
-    InputMethodConfigValue* out_value) {
-  DCHECK(out_value);
-  const ConfigKeyType key(section, config_name);
-  InputMethodConfigRequests::const_iterator iter =
-      current_config_values_.find(key);
-  if (iter == current_config_values_.end())
-    return false;
-  *out_value = iter->second;
-  return true;
-}
-
 void IBusControllerBase::ClearProperties() {
   current_property_list_.clear();
 }
diff --git a/chrome/browser/chromeos/input_method/ibus_controller_base.h b/chrome/browser/chromeos/input_method/ibus_controller_base.h
index 2503b51..83b0f93 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller_base.h
+++ b/chrome/browser/chromeos/input_method/ibus_controller_base.h
@@ -10,7 +10,6 @@
 
 #include "base/observer_list.h"
 #include "chrome/browser/chromeos/input_method/ibus_controller.h"
-#include "chromeos/ime/input_method_config.h"
 #include "chromeos/ime/input_method_property.h"
 
 namespace chromeos {
@@ -27,18 +26,9 @@
   // functions.
   virtual void AddObserver(Observer* observer) OVERRIDE;
   virtual void RemoveObserver(Observer* observer) OVERRIDE;
-  virtual bool SetInputMethodConfig(
-      const std::string& section,
-      const std::string& config_name,
-      const InputMethodConfigValue& value) OVERRIDE;
   virtual const InputMethodPropertyList& GetCurrentProperties() const OVERRIDE;
   virtual void ClearProperties() OVERRIDE;
 
-  // Gets the current input method configuration.
-  bool GetInputMethodConfigForTesting(const std::string& section,
-                                      const std::string& config_name,
-                                      InputMethodConfigValue* out_value);
-
   // Notifies all |observers_|.
   void NotifyPropertyChangedForTesting();
 
@@ -47,20 +37,8 @@
       const InputMethodPropertyList& current_property_list);
 
  protected:
-  typedef std::pair<std::string, std::string> ConfigKeyType;
-  typedef std::map<
-    ConfigKeyType, InputMethodConfigValue> InputMethodConfigRequests;
-
-  virtual bool SetInputMethodConfigInternal(
-      const ConfigKeyType& key,
-      const InputMethodConfigValue& value) = 0;
-
   ObserverList<Observer> observers_;
 
-  // Values that have been set via SetInputMethodConfig(). We keep a copy
-  // available to (re)send when the system input method framework (re)starts.
-  InputMethodConfigRequests current_config_values_;
-
   // The value which will be returned by GetCurrentProperties(). Derived classes
   // should update this variable when needed.
   InputMethodPropertyList current_property_list_;
diff --git a/chrome/browser/chromeos/input_method/ibus_controller_base_unittest.cc b/chrome/browser/chromeos/input_method/ibus_controller_base_unittest.cc
index 611cf3d..353b109 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller_base_unittest.cc
+++ b/chrome/browser/chromeos/input_method/ibus_controller_base_unittest.cc
@@ -5,7 +5,6 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/input_method/ibus_controller_base.h"
-#include "chromeos/ime/input_method_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -17,9 +16,7 @@
 // RemoveObserver() methods in IBusControllerBase.
 class TestIBusController : public IBusControllerBase {
  public:
-  TestIBusController()
-      : set_input_method_config_internal_count_(0),
-        set_input_method_config_internal_return_(true) {
+  TestIBusController() {
   }
   virtual ~TestIBusController() {
   }
@@ -34,28 +31,7 @@
     return observers_.size();
   }
 
-  int set_input_method_config_internal_count() const {
-    return set_input_method_config_internal_count_;
-  }
-  void set_set_input_method_config_internal_return(bool new_value) {
-    set_input_method_config_internal_return_ = new_value;
-  }
-  const ConfigKeyType& last_key() const { return last_key_; }
-
- protected:
-  virtual bool SetInputMethodConfigInternal(
-      const ConfigKeyType& key,
-      const InputMethodConfigValue& value) OVERRIDE {
-    ++set_input_method_config_internal_count_;
-    last_key_ = key;
-    return set_input_method_config_internal_return_;
-  }
-
  private:
-  int set_input_method_config_internal_count_;
-  bool set_input_method_config_internal_return_;
-  ConfigKeyType last_key_;
-
   DISALLOW_COPY_AND_ASSIGN(TestIBusController);
 };
 
@@ -80,85 +56,6 @@
 
 }  // namespace
 
-TEST_F(IBusControllerBaseTest, TestSetInputMethodConfig) {
-  InputMethodConfigValue value_set;
-  InputMethodConfigValue value_get;
-  EXPECT_FALSE(controller_->GetInputMethodConfigForTesting("section",
-                                                           "name",
-                                                           &value_get));
-  EXPECT_EQ(0, controller_->set_input_method_config_internal_count());
-
-  // Set a value.
-  value_set.type = InputMethodConfigValue::kValueTypeInt;
-  value_set.int_value = 12345;
-  EXPECT_TRUE(controller_->SetInputMethodConfig("section",
-                                                "name",
-                                                value_set));
-  EXPECT_EQ(1, controller_->set_input_method_config_internal_count());
-  EXPECT_EQ("section", controller_->last_key().first);
-  EXPECT_EQ("name", controller_->last_key().second);
-
-  // Get the value.
-  EXPECT_TRUE(controller_->GetInputMethodConfigForTesting("section",
-                                                          "name",
-                                                          &value_get));
-  EXPECT_EQ(value_set.type, value_get.type);
-  EXPECT_EQ(value_set.int_value, value_get.int_value);
-
-  // Set another value.
-  value_set.type = InputMethodConfigValue::kValueTypeBool;
-  value_set.bool_value = true;
-  EXPECT_TRUE(controller_->SetInputMethodConfig("section/2",
-                                                "name2",
-                                                value_set));
-  EXPECT_EQ(2, controller_->set_input_method_config_internal_count());
-  EXPECT_EQ("section/2", controller_->last_key().first);
-  EXPECT_EQ("name2", controller_->last_key().second);
-
-  // Overwrite the first value.
-  value_set.type = InputMethodConfigValue::kValueTypeInt;
-  value_set.int_value = 54321;
-  EXPECT_TRUE(controller_->SetInputMethodConfig("section",
-                                                "name",
-                                                value_set));
-  EXPECT_EQ(3, controller_->set_input_method_config_internal_count());
-  EXPECT_EQ("section", controller_->last_key().first);
-  EXPECT_EQ("name", controller_->last_key().second);
-
-  // Get the value.
-  EXPECT_TRUE(controller_->GetInputMethodConfigForTesting("section",
-                                                          "name",
-                                                          &value_get));
-  EXPECT_EQ(value_set.type, value_get.type);
-  EXPECT_EQ(value_set.int_value, value_get.int_value);
-
-  // Get a non existent value.
-  EXPECT_FALSE(controller_->GetInputMethodConfigForTesting("sectionX",
-                                                           "name",
-                                                           &value_get));
-  EXPECT_FALSE(controller_->GetInputMethodConfigForTesting("section",
-                                                           "nameX",
-                                                           &value_get));
-}
-
-TEST_F(IBusControllerBaseTest, TestSetInputMethodConfigInternal) {
-  InputMethodConfigValue value_set;
-  InputMethodConfigValue value_get;
-  // Set a value. In this case, SetInputMethodConfigInternal returns false.
-  controller_->set_set_input_method_config_internal_return(false);
-  value_set.type = InputMethodConfigValue::kValueTypeInt;
-  value_set.int_value = 12345;
-  EXPECT_FALSE(controller_->SetInputMethodConfig("section",
-                                                 "name",
-                                                 value_set));
-  EXPECT_EQ(1, controller_->set_input_method_config_internal_count());
-
-  // Getting the value should fail.
-  EXPECT_FALSE(controller_->GetInputMethodConfigForTesting("section",
-                                                           "name",
-                                                           &value_get));
-}
-
 TEST_F(IBusControllerBaseTest, TestAddRemoveObserver) {
   TestObserver observer1;
   TestObserver observer2;
diff --git a/chrome/browser/chromeos/input_method/ibus_controller_impl.cc b/chrome/browser/chromeos/input_method/ibus_controller_impl.cc
index 9f08aa8..1bd85f9 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller_impl.cc
+++ b/chrome/browser/chromeos/input_method/ibus_controller_impl.cc
@@ -22,15 +22,11 @@
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/ibus/ibus_client.h"
-#include "chromeos/dbus/ibus/ibus_config_client.h"
-#include "chromeos/dbus/ibus/ibus_constants.h"
-#include "chromeos/dbus/ibus/ibus_input_context_client.h"
-#include "chromeos/dbus/ibus/ibus_panel_service.h"
 #include "chromeos/dbus/ibus/ibus_property.h"
 #include "chromeos/ime/component_extension_ime_manager.h"
 #include "chromeos/ime/extension_ime_util.h"
+#include "chromeos/ime/ibus_bridge.h"
+#include "chromeos/ime/ime_constants.h"
 #include "chromeos/ime/input_method_config.h"
 #include "chromeos/ime/input_method_property.h"
 #include "ui/aura/client/aura_constants.h"
@@ -54,10 +50,6 @@
   return false;
 }
 
-void ConfigSetValueErrorCallback() {
-  DVLOG(1) << "IBusConfig: SetValue is failed.";
-}
-
 }  // namespace
 
 namespace chromeos {
@@ -189,21 +181,15 @@
 
 }  // namespace
 
-IBusControllerImpl::IBusControllerImpl()
-    : weak_ptr_factory_(this) {
-  IBusDaemonController::GetInstance()->AddObserver(this);
+IBusControllerImpl::IBusControllerImpl() {
+  IBusBridge::Get()->SetPropertyHandler(this);
 }
 
 IBusControllerImpl::~IBusControllerImpl() {
-  IBusDaemonController::GetInstance()->RemoveObserver(this);
+  IBusBridge::Get()->SetPropertyHandler(NULL);
 }
 
 bool IBusControllerImpl::ActivateInputMethodProperty(const std::string& key) {
-  if (!IBusConnectionsAreAlive()) {
-    DVLOG(1) << "ActivateInputMethodProperty: IBus connection is not alive";
-    return false;
-  }
-
   // The third parameter of ibus_input_context_property_activate() has to be
   // true when the |key| points to a radio button. false otherwise.
   bool is_radio = true;
@@ -219,68 +205,13 @@
     return false;
   }
 
-  IBusInputContextClient* client
-      = DBusThreadManager::Get()->GetIBusInputContextClient();
-  if (client)
-    client->PropertyActivate(key,
+  IBusEngineHandlerInterface* engine = IBusBridge::Get()->GetEngineHandler();
+  if (engine)
+    engine->PropertyActivate(key,
                              static_cast<ibus::IBusPropertyState>(is_radio));
   return true;
 }
 
-bool IBusControllerImpl::IBusConnectionsAreAlive() {
-  return DBusThreadManager::Get() &&
-      DBusThreadManager::Get()->GetIBusBus() != NULL;
-}
-
-bool IBusControllerImpl::SetInputMethodConfigInternal(
-    const ConfigKeyType& key,
-    const InputMethodConfigValue& value) {
-  if (value.type != InputMethodConfigValue::kValueTypeString &&
-      value.type != InputMethodConfigValue::kValueTypeInt &&
-      value.type != InputMethodConfigValue::kValueTypeBool &&
-      value.type != InputMethodConfigValue::kValueTypeStringList) {
-    DVLOG(1) << "SendInputMethodConfig: unknown value.type";
-    return false;
-  }
-
-  IBusConfigClient* client = DBusThreadManager::Get()->GetIBusConfigClient();
-  if (!client) {
-    // Should return true if the ibus-memconf is not ready to use, otherwise IME
-    // configuration will not be initialized.
-    return true;
-  }
-
-  switch (value.type) {
-    case InputMethodConfigValue::kValueTypeString:
-      client->SetStringValue(key.first,
-                             key.second,
-                             value.string_value,
-                             base::Bind(&ConfigSetValueErrorCallback));
-      return true;
-    case InputMethodConfigValue::kValueTypeInt:
-      client->SetIntValue(key.first,
-                          key.second,
-                          value.int_value,
-                          base::Bind(&ConfigSetValueErrorCallback));
-      return true;
-    case InputMethodConfigValue::kValueTypeBool:
-      client->SetBoolValue(key.first,
-                           key.second,
-                           value.bool_value,
-                           base::Bind(&ConfigSetValueErrorCallback));
-      return true;
-    case InputMethodConfigValue::kValueTypeStringList:
-      client->SetStringListValue(key.first,
-                                 key.second,
-                                 value.string_list_value,
-                                 base::Bind(&ConfigSetValueErrorCallback));
-      return true;
-    default:
-      NOTREACHED() << "SendInputMethodConfig: unknown value.type";
-      return false;
-  }
-}
-
 void IBusControllerImpl::RegisterProperties(
     const IBusPropertyList& ibus_prop_list) {
   current_property_list_.clear();
@@ -306,29 +237,6 @@
   }
 }
 
-void IBusControllerImpl::OnIBusConfigClientInitialized() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  InputMethodConfigRequests::const_iterator iter =
-      current_config_values_.begin();
-  for (; iter != current_config_values_.end(); ++iter) {
-    SetInputMethodConfigInternal(iter->first, iter->second);
-  }
-}
-
-void IBusControllerImpl::OnConnected() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  DBusThreadManager::Get()->GetIBusPanelService()->SetUpPropertyHandler(this);
-
-  DBusThreadManager::Get()->GetIBusConfigClient()->InitializeAsync(
-      base::Bind(&IBusControllerImpl::OnIBusConfigClientInitialized,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void IBusControllerImpl::OnDisconnected() {
-  DBusThreadManager::Get()->GetIBusPanelService()->SetUpPropertyHandler(NULL);
-}
-
 // static
 bool IBusControllerImpl::FindAndUpdatePropertyForTesting(
     const chromeos::input_method::InputMethodProperty& new_prop,
diff --git a/chrome/browser/chromeos/input_method/ibus_controller_impl.h b/chrome/browser/chromeos/input_method/ibus_controller_impl.h
index af0892a..e262e8d 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller_impl.h
+++ b/chrome/browser/chromeos/input_method/ibus_controller_impl.h
@@ -8,19 +8,12 @@
 #include <string>
 #include <vector>
 
-#include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/input_method/ibus_controller_base.h"
-#include "chromeos/dbus/ibus/ibus_panel_service.h"
-#include "chromeos/ime/ibus_daemon_controller.h"
-
-namespace ui {
-class InputMethodIBus;
-}  // namespace ui
+#include "chromeos/ime/ibus_bridge.h"
 
 namespace chromeos {
 namespace input_method {
 
-struct InputMethodConfigValue;
 struct InputMethodProperty;
 typedef std::vector<InputMethodProperty> InputMethodPropertyList;
 
@@ -28,8 +21,7 @@
 // TODO(nona): Merge to IBusControllerBase, there is no longer reason to split
 //             this class into Impl and Base.
 class IBusControllerImpl : public IBusControllerBase,
-                           public IBusPanelPropertyHandlerInterface,
-                           public IBusDaemonController::Observer {
+                           public IBusPanelPropertyHandlerInterface {
  public:
   IBusControllerImpl();
   virtual ~IBusControllerImpl();
@@ -44,35 +36,11 @@
       InputMethodPropertyList* prop_list);
 
  private:
-  // IBusDaemonController overrides:
-  virtual void OnConnected() OVERRIDE;
-  virtual void OnDisconnected() OVERRIDE;
-
-  // IBusControllerBase overrides:
-  virtual bool SetInputMethodConfigInternal(
-      const ConfigKeyType& key,
-      const InputMethodConfigValue& value) OVERRIDE;
-
   // IBusPanelPropertyHandlerInterface overrides:
   virtual void RegisterProperties(
       const IBusPropertyList& properties) OVERRIDE;
   virtual void UpdateProperty(const IBusProperty& property) OVERRIDE;
 
-  // Checks if |ibus_| and |ibus_config_| connections are alive.
-  bool IBusConnectionsAreAlive();
-
-  // Called when the IBusConfigClient is initialized.
-  void OnIBusConfigClientInitialized();
-
-  // Current input context path.
-  std::string current_input_context_path_;
-
-  // IBusControllerImpl should be used only on UI thread.
-  base::ThreadChecker thread_checker_;
-
-  // Used for making callbacks for PostTask.
-  base::WeakPtrFactory<IBusControllerImpl> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(IBusControllerImpl);
 };
 
diff --git a/chrome/browser/chromeos/input_method/ibus_controller_unittest.cc b/chrome/browser/chromeos/input_method/ibus_controller_unittest.cc
index fd32f51..7b74d96 100644
--- a/chrome/browser/chromeos/input_method/ibus_controller_unittest.cc
+++ b/chrome/browser/chromeos/input_method/ibus_controller_unittest.cc
@@ -5,20 +5,19 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/chromeos/input_method/ibus_controller.h"
-#include "chromeos/ime/mock_ibus_daemon_controller.h"
+#include "chromeos/ime/ibus_bridge.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
 namespace input_method {
 
 TEST(IBusControllerTest, TestCreate) {
-  chromeos::IBusDaemonController::InitializeForTesting(
-      new chromeos::MockIBusDaemonController());
+  IBusBridge::Initialize();
   {
     scoped_ptr<IBusController> controller(IBusController::Create());
     EXPECT_TRUE(controller.get());
   }
-  chromeos::IBusDaemonController::Shutdown();
+  IBusBridge::Shutdown();
 }
 
 }  // namespace input_method
diff --git a/chrome/browser/chromeos/input_method/input_method_configuration.cc b/chrome/browser/chromeos/input_method/input_method_configuration.cc
index 5bac0d2..b132793 100644
--- a/chrome/browser/chromeos/input_method/input_method_configuration.cc
+++ b/chrome/browser/chromeos/input_method/input_method_configuration.cc
@@ -33,14 +33,8 @@
     const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner,
     const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) {
   IBusDaemonController::Initialize(ui_task_runner, file_task_runner);
-  if (!base::chromeos::IsRunningOnChromeOS()) {
-    // IBusBridge is for ChromeOS on desktop Linux not for ChromeOS Devices or
-    // production at this moment.
-    // TODO(nona): Remove this condition when ibus-daemon is gone.
-    //             (crbug.com/170671)
-    IBusBridge::Initialize();
-    IBusDaemonController::GetInstance()->Start();
-  }
+  IBusBridge::Initialize();
+  IBusDaemonController::GetInstance()->Start();
 
   InputMethodManagerImpl* impl = new InputMethodManagerImpl(
       scoped_ptr<InputMethodDelegate>(new InputMethodDelegateImpl));
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 5fd408f..aeb8080 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_ibus.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine_ibus.h
@@ -11,6 +11,7 @@
 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
 #include "chromeos/dbus/ibus/ibus_engine_factory_service.h"
 #include "chromeos/dbus/ibus/ibus_engine_service.h"
+#include "chromeos/ime/ibus_bridge.h"
 #include "dbus/object_path.h"
 
 namespace chromeos {
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 cda8462..7c8cd42 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
@@ -11,6 +11,7 @@
 #include "chromeos/dbus/ibus/mock_ibus_engine_factory_service.h"
 #include "chromeos/dbus/ibus/mock_ibus_engine_service.h"
 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
+#include "chromeos/ime/ibus_bridge.h"
 #include "chromeos/ime/input_method_descriptor.h"
 #include "chromeos/ime/input_method_manager.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index 20fba08..5a41b15 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -381,19 +381,6 @@
   return false;
 }
 
-bool InputMethodManagerImpl::SetInputMethodConfig(
-    const std::string& section,
-    const std::string& config_name,
-    const InputMethodConfigValue& value) {
-  DCHECK(section != language_prefs::kGeneralSectionName ||
-         config_name != language_prefs::kPreloadEnginesConfigName);
-
-  if (state_ == STATE_TERMINATING)
-    return false;
-
-  return ibus_controller_->SetInputMethodConfig(section, config_name, value);
-}
-
 void InputMethodManagerImpl::ChangeInputMethod(
     const std::string& input_method_id) {
   ChangeInputMethodInternal(input_method_id, false);
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
index 1d0d417..88f1875 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -73,10 +73,6 @@
   virtual bool MigrateKoreanKeyboard(
       const std::string& keyboard_id,
       std::vector<std::string>* input_method_ids) OVERRIDE;
-  virtual bool SetInputMethodConfig(
-      const std::string& section,
-      const std::string& config_name,
-      const InputMethodConfigValue& value) OVERRIDE;
   virtual void ChangeInputMethod(const std::string& input_method_id) OVERRIDE;
   virtual void ActivateInputMethodProperty(const std::string& key) OVERRIDE;
   virtual void AddInputMethodExtension(
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
index d0547bd..e68fe3e 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl_unittest.cc
@@ -346,28 +346,6 @@
   EXPECT_TRUE(Contain(*methods.get(), *id_to_find));
 }
 
-TEST_F(InputMethodManagerImplTest, TestSetInputMethodConfig) {
-  InputMethodConfigValue config;
-  config.type = InputMethodConfigValue::kValueTypeString;
-  config.string_value = "string";
-  EXPECT_EQ(0, controller_->set_input_method_config_internal_count_);
-  EXPECT_TRUE(manager_->SetInputMethodConfig("section", "name", config));
-  EXPECT_EQ(1, controller_->set_input_method_config_internal_count_);
-  EXPECT_EQ("section",
-            controller_->set_input_method_config_internal_key_.first);
-  EXPECT_EQ("name",
-            controller_->set_input_method_config_internal_key_.second);
-  EXPECT_EQ(config.type,
-            controller_->set_input_method_config_internal_value_.type);
-  EXPECT_EQ(config.string_value,
-            controller_->set_input_method_config_internal_value_.string_value);
-
-  // SetInputMethodConfig should be no-op in STATE_TERMINATING.
-  manager_->SetState(InputMethodManager::STATE_TERMINATING);
-  EXPECT_FALSE(manager_->SetInputMethodConfig("section", "name", config));
-  EXPECT_EQ(1, controller_->set_input_method_config_internal_count_);
-}
-
 TEST_F(InputMethodManagerImplTest, TestEnableTwoLayouts) {
   // For http://crbug.com/19655#c11 - (8), step 6.
   TestObserver observer;
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc
index fc91b63..e8ed45b 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -293,32 +293,6 @@
 const size_t kEnglishToResourceIdArraySize =
     arraysize(kEnglishToResourceIdArray);
 
-// The list of language that do not have associated input methods in IBus.
-// For these languages, we associate input methods here.
-const struct ExtraLanguage {
-  const char* language_code;
-  const char* input_method_id;
-} kExtraLanguages[] = {
-  // Language Code  Input Method ID
-  { "en-AU", "xkb:us::eng" },  // For Austrailia, use US keyboard layout.
-  { "id", "xkb:us::eng" },  // For Indonesian, use US keyboard layout.
-  // The code "fil" comes from l10_util.cc.
-  { "fil", "xkb:us::eng" },  // For Filipino, use US keyboard layout.
-  // For Netherlands, use US international keyboard layout.
-  { "nl", "xkb:us:intl:eng" },
-  // The code "es-419" comes from l10_util.cc.
-  // For Spanish in Latin America, use Latin American keyboard layout.
-  { "es-419", "xkb:latam::spa" },
-  // For Malay, use US keyboard layout. crosbug.com/p/8288
-  { "ms", "xkb:us::eng" },
-  // For Brazil, it is common to use US-international keyboard layout.
-  { "pt-BR", "xkb:us:intl:eng" },
-
-  // TODO(yusukes): Add {"sw", "xkb:us::eng"} once Swahili is removed from the
-  // blacklist in src/ui/base/l10n/l10n_util_posix.cc.
-};
-const size_t kExtraLanguagesLength = arraysize(kExtraLanguages);
-
 }  // namespace
 
 InputMethodUtil::InputMethodUtil(
@@ -509,23 +483,6 @@
   return (iter == id_to_descriptor_.end()) ? NULL : &(iter->second);
 }
 
-std::vector<std::string> InputMethodUtil::GetExtraLanguageCodesFromId(
-    const std::string& input_method_id) const {
-  std::vector<std::string> result;
-  for (size_t i = 0; i < kExtraLanguagesLength; ++i) {
-    if (input_method_id == kExtraLanguages[i].input_method_id)
-      result.push_back(kExtraLanguages[i].language_code);
-  }
-  return result;
-}
-
-std::vector<std::string> InputMethodUtil::GetExtraLanguageCodeList() const {
-  std::vector<std::string> result;
-  for (size_t i = 0; i < kExtraLanguagesLength; ++i)
-    result.push_back(kExtraLanguages[i].language_code);
-  return result;
-}
-
 bool InputMethodUtil::GetInputMethodIdsFromLanguageCode(
     const std::string& normalized_language_code,
     InputMethodType type,
@@ -715,21 +672,6 @@
                          input_method));
     }
   }
-
-  // Go through the languages listed in kExtraLanguages.
-  for (size_t i = 0; i < kExtraLanguagesLength; ++i) {
-    const char* language_code = kExtraLanguages[i].language_code;
-    const char* input_method_id = kExtraLanguages[i].input_method_id;
-    InputMethodIdToDescriptorMap::const_iterator iter =
-        id_to_descriptor_.find(input_method_id);
-    // If the associated input method descriptor is found, add the language
-    // code and the input method.
-    if (iter != id_to_descriptor_.end()) {
-      const InputMethodDescriptor& input_method = iter->second;
-      language_code_to_ids_.insert(
-          std::make_pair(language_code, input_method.id()));
-    }
-  }
 }
 
 }  // namespace input_method
diff --git a/chrome/browser/chromeos/input_method/input_method_util.h b/chrome/browser/chromeos/input_method/input_method_util.h
index ac1fdf7..6f70fea 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.h
+++ b/chrome/browser/chromeos/input_method/input_method_util.h
@@ -103,14 +103,6 @@
   // Returns true if the given input method id is for a keyboard layout.
   static bool IsKeyboardLayout(const std::string& input_method_id);
 
-  // Returns extra language code list associated with |input_method_id|. If
-  // there is no associated langauge code, this function returns empty list.
-  std::vector<std::string> GetExtraLanguageCodesFromId(
-      const std::string& input_method_id) const;
-
-  // Returns all extra language code list.
-  std::vector<std::string> GetExtraLanguageCodeList() const;
-
   // Sets the list of component extension IMEs.
   void SetComponentExtensions(const InputMethodDescriptors& imes);
 
diff --git a/chrome/browser/chromeos/input_method/mock_ibus_controller.cc b/chrome/browser/chromeos/input_method/mock_ibus_controller.cc
index 05f067c..babc5d9 100644
--- a/chrome/browser/chromeos/input_method/mock_ibus_controller.cc
+++ b/chrome/browser/chromeos/input_method/mock_ibus_controller.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/chromeos/input_method/mock_ibus_controller.h"
 
-#include "chromeos/ime/input_method_config.h"
 #include "chromeos/ime/input_method_property.h"
 
 namespace chromeos {
@@ -12,9 +11,7 @@
 
 MockIBusController::MockIBusController()
     : activate_input_method_property_count_(0),
-      activate_input_method_property_return_(true),
-      set_input_method_config_internal_count_(0),
-      set_input_method_config_internal_return_(true) {
+      activate_input_method_property_return_(true) {
 }
 
 MockIBusController::~MockIBusController() {
@@ -26,14 +23,5 @@
   return activate_input_method_property_return_;
 }
 
-bool MockIBusController::SetInputMethodConfigInternal(
-    const ConfigKeyType& key,
-    const InputMethodConfigValue& value) {
-  ++set_input_method_config_internal_count_;
-  set_input_method_config_internal_key_ = key;
-  set_input_method_config_internal_value_ = value;
-  return set_input_method_config_internal_return_;
-}
-
 }  // namespace input_method
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/mock_ibus_controller.h b/chrome/browser/chromeos/input_method/mock_ibus_controller.h
index c405d8e..e27c336 100644
--- a/chrome/browser/chromeos/input_method/mock_ibus_controller.h
+++ b/chrome/browser/chromeos/input_method/mock_ibus_controller.h
@@ -10,7 +10,6 @@
 namespace chromeos {
 namespace input_method {
 
-struct InputMethodConfigValue;
 struct InputMethodProperty;
 
 // Mock IBusController implementation.
@@ -26,16 +25,6 @@
   int activate_input_method_property_count_;
   std::string activate_input_method_property_key_;
   bool activate_input_method_property_return_;
-  int set_input_method_config_internal_count_;
-  ConfigKeyType set_input_method_config_internal_key_;
-  InputMethodConfigValue set_input_method_config_internal_value_;
-  bool set_input_method_config_internal_return_;
-
- protected:
-  // IBusControllerBase overrides:
-  virtual bool SetInputMethodConfigInternal(
-      const ConfigKeyType& key,
-      const InputMethodConfigValue& value) OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockIBusController);
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager.cc b/chrome/browser/chromeos/input_method/mock_input_method_manager.cc
index 4aeef61..da33694 100644
--- a/chrome/browser/chromeos/input_method/mock_input_method_manager.cc
+++ b/chrome/browser/chromeos/input_method/mock_input_method_manager.cc
@@ -85,13 +85,6 @@
   return false;
 }
 
-bool MockInputMethodManager::SetInputMethodConfig(
-    const std::string& section,
-    const std::string& config_name,
-    const InputMethodConfigValue& value) {
-  return true;
-}
-
 void MockInputMethodManager::ChangeInputMethod(
     const std::string& input_method_id) {
 }
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager.h b/chrome/browser/chromeos/input_method/mock_input_method_manager.h
index 5db4950..0534b8a 100644
--- a/chrome/browser/chromeos/input_method/mock_input_method_manager.h
+++ b/chrome/browser/chromeos/input_method/mock_input_method_manager.h
@@ -45,10 +45,6 @@
   virtual bool MigrateKoreanKeyboard(
       const std::string& keyboard_id,
       std::vector<std::string>* input_method_ids) OVERRIDE;
-  virtual bool SetInputMethodConfig(
-      const std::string& section,
-      const std::string& config_name,
-      const InputMethodConfigValue& value) OVERRIDE;
   virtual void ChangeInputMethod(const std::string& input_method_id) OVERRIDE;
   virtual void ActivateInputMethodProperty(const std::string& key) OVERRIDE;
   virtual void AddInputMethodExtension(
diff --git a/chrome/browser/chromeos/login/OWNERS b/chrome/browser/chromeos/login/OWNERS
index f64866a..c09b412 100644
--- a/chrome/browser/chromeos/login/OWNERS
+++ b/chrome/browser/chromeos/login/OWNERS
@@ -1,8 +1,7 @@
 nkostylev@chromium.org
-ivankr@chromium.org
 dpolukhin@chromium.org
-glotov@chromium.org
 davemoore@chromium.org
 piman@chromium.org
 ygorshenin@chromium.org
 antrim@chromium.org
+dzhioev@chromium.org
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
new file mode 100644
index 0000000..65819ec
--- /dev/null
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -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.
+
+#include "chrome/browser/chromeos/login/app_launch_controller.h"
+
+#include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
+#include "chrome/browser/chromeos/login/login_display_host.h"
+#include "chrome/browser/chromeos/login/oobe_display.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace chromeos {
+
+namespace {
+
+// Application install splash screen minimum show time in milliseconds.
+const int kAppInstallSplashScreenMinTimeMS = 3000;
+
+}  // namespace
+
+// static
+bool AppLaunchController::skip_splash_wait_ = false;
+
+AppLaunchController::AppLaunchController(const std::string& app_id,
+                                         LoginDisplayHost* host,
+                                         OobeDisplay* oobe_display)
+    : profile_(NULL),
+      app_id_(app_id),
+      host_(host),
+      oobe_display_(oobe_display),
+      app_launch_splash_screen_actor_(
+          oobe_display_->GetAppLaunchSplashScreenActor()),
+      launch_splash_start_time_(0) {
+}
+
+AppLaunchController::~AppLaunchController() {
+}
+
+void AppLaunchController::StartAppLaunch() {
+  DVLOG(1) << "Starting kiosk mode...";
+  launch_splash_start_time_ = base::TimeTicks::Now().ToInternalValue();
+
+  // TODO(tengs): Add a loading profile app launch state.
+  app_launch_splash_screen_actor_->SetDelegate(this);
+  app_launch_splash_screen_actor_->Show(app_id_);
+
+  // KioskProfileLoader manages its own lifetime.
+  kiosk_profile_loader_.reset(
+      new KioskProfileLoader(KioskAppManager::Get(), app_id_, this));
+  kiosk_profile_loader_->Start();
+}
+
+// static
+void AppLaunchController::SkipSplashWaitForTesting() {
+  skip_splash_wait_ = true;
+}
+
+void AppLaunchController::OnConfigureNetwork() {
+  // TODO(tengs): Implement network configuration in app launch.
+}
+
+void AppLaunchController::OnCancelAppLaunch() {
+  if (KioskAppManager::Get()->GetDisableBailoutShortcut())
+    return;
+
+  OnLaunchFailed(KioskAppLaunchError::USER_CANCEL);
+}
+
+void AppLaunchController::OnProfileLoaded(Profile* profile) {
+  DVLOG(1) << "Profile loaded... Starting app launch.";
+  profile_ = profile;
+
+  // StartupAppLauncher manages its own lifetime.
+  startup_app_launcher_.reset(new StartupAppLauncher(profile_, app_id_));
+  startup_app_launcher_->AddObserver(this);
+  startup_app_launcher_->Start();
+}
+
+void AppLaunchController::OnProfileLoadFailed(
+    KioskAppLaunchError::Error error) {
+  OnLaunchFailed(error);
+}
+
+void AppLaunchController::Cleanup() {
+  kiosk_profile_loader_.reset();
+  startup_app_launcher_.reset();
+
+  if (host_)
+    host_->Finalize();
+}
+
+void AppLaunchController::OnLoadingOAuthFile() {
+  app_launch_splash_screen_actor_->UpdateAppLaunchState(
+      AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_AUTH_FILE);
+}
+
+void AppLaunchController::OnInitializingTokenService() {
+  app_launch_splash_screen_actor_->UpdateAppLaunchState(
+      AppLaunchSplashScreenActor::APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE);
+}
+
+void AppLaunchController::OnInitializingNetwork() {
+  app_launch_splash_screen_actor_->UpdateAppLaunchState(
+      AppLaunchSplashScreenActor::APP_LAUNCH_STATE_PREPARING_NETWORK);
+}
+
+void AppLaunchController::OnNetworkWaitTimedout() {
+}
+
+void AppLaunchController::OnInstallingApp() {
+  app_launch_splash_screen_actor_->UpdateAppLaunchState(
+      AppLaunchSplashScreenActor::APP_LAUNCH_STATE_INSTALLING_APPLICATION);
+}
+
+void AppLaunchController::OnLaunchSucceeded() {
+  const int64 time_taken_ms = (base::TimeTicks::Now() -
+      base::TimeTicks::FromInternalValue(launch_splash_start_time_)).
+      InMilliseconds();
+
+  // Enforce that we show app install splash screen for some minimum amount
+  // of time.
+  if (!skip_splash_wait_ && time_taken_ms < kAppInstallSplashScreenMinTimeMS) {
+    content::BrowserThread::PostDelayedTask(
+        content::BrowserThread::UI,
+        FROM_HERE,
+        base::Bind(&AppLaunchController::OnLaunchSucceeded, AsWeakPtr()),
+        base::TimeDelta::FromMilliseconds(
+            kAppInstallSplashScreenMinTimeMS - time_taken_ms));
+    return;
+  }
+
+  DVLOG(1) << "Kiosk launch succeeded!";
+  Cleanup();
+}
+
+void AppLaunchController::OnLaunchFailed(KioskAppLaunchError::Error error) {
+  LOG(ERROR) << "Kiosk launch failed. Will now shut down.";
+  DCHECK_NE(KioskAppLaunchError::NONE, error);
+
+  // Saves the error and ends the session to go back to login screen.
+  KioskAppLaunchError::Save(error);
+  chrome::AttemptUserExit();
+  Cleanup();
+}
+
+
+}   // namespace chromeos
diff --git a/chrome/browser/chromeos/login/app_launch_controller.h b/chrome/browser/chromeos/login/app_launch_controller.h
new file mode 100644
index 0000000..f1bb749
--- /dev/null
+++ b/chrome/browser/chromeos/login/app_launch_controller.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 CHROME_BROWSER_CHROMEOS_LOGIN_APP_LAUNCH_CONTROLLER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_APP_LAUNCH_CONTROLLER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_profile_loader.h"
+#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
+#include "chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h"
+
+class Profile;
+
+namespace chromeos {
+
+class LoginDisplayHost;
+class OobeDisplay;
+
+// Controller for the kiosk app launch process, responsible for
+// coordinating loading the kiosk profile, launching the app, and
+// updating the splash screen UI.
+class AppLaunchController
+    : public base::SupportsWeakPtr<AppLaunchController>,
+      public AppLaunchSplashScreenActor::Delegate,
+      public KioskProfileLoader::Delegate,
+      public StartupAppLauncher::Observer {
+ public:
+  AppLaunchController(const std::string& app_id,
+                      LoginDisplayHost* host,
+                      OobeDisplay* oobe_display);
+
+  virtual ~AppLaunchController();
+
+  void StartAppLaunch();
+
+  static void SkipSplashWaitForTesting();
+
+ private:
+  void Cleanup();
+
+  // KioskProfileLoader::Delegate overrides:
+  virtual void OnProfileLoaded(Profile* profile) OVERRIDE;
+  virtual void OnProfileLoadFailed(KioskAppLaunchError::Error error) OVERRIDE;
+
+  // AppLaunchSplashScreenActor::Delegate overrides:
+  virtual void OnConfigureNetwork() OVERRIDE;
+  virtual void OnCancelAppLaunch() OVERRIDE;
+
+  // StartupAppLauncher::Observer overrides:
+  virtual void OnLoadingOAuthFile() OVERRIDE;
+  virtual void OnInitializingTokenService() OVERRIDE;
+  virtual void OnInitializingNetwork() OVERRIDE;
+  virtual void OnNetworkWaitTimedout() OVERRIDE;
+  virtual void OnInstallingApp() OVERRIDE;
+  virtual void OnLaunchSucceeded() OVERRIDE;
+  virtual void OnLaunchFailed(KioskAppLaunchError::Error error) OVERRIDE;
+
+  Profile* profile_;
+  const std::string app_id_;
+  LoginDisplayHost* host_;
+  OobeDisplay* oobe_display_;
+  AppLaunchSplashScreenActor* app_launch_splash_screen_actor_;
+  scoped_ptr<KioskProfileLoader> kiosk_profile_loader_;
+  scoped_ptr<StartupAppLauncher> startup_app_launcher_;
+
+  int64 launch_splash_start_time_;
+
+  static bool skip_splash_wait_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppLaunchController);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_APP_LAUNCH_CONTROLLER_H_
diff --git a/chrome/browser/chromeos/login/captive_portal_view.cc b/chrome/browser/chromeos/login/captive_portal_view.cc
index 05bae47..c6dc73e 100644
--- a/chrome/browser/chromeos/login/captive_portal_view.cc
+++ b/chrome/browser/chromeos/login/captive_portal_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/login/captive_portal_view.h"
 
+#include "ash/wm/custom_frame_view_ash.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/captive_portal/captive_portal_detector.h"
 #include "chrome/browser/chromeos/login/captive_portal_window_proxy.h"
@@ -13,6 +14,7 @@
 #include "content/public/browser/web_contents.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/views/window/dialog_delegate.h"
 #include "url/gurl.h"
 
 namespace {
@@ -68,6 +70,20 @@
   return true;
 }
 
+views::NonClientFrameView* CaptivePortalView::CreateNonClientFrameView(
+    views::Widget* widget) {
+  if (views::DialogDelegate::UseNewStyle()) {
+    const bool force_opaque_border = false;
+    return views::DialogDelegate::CreateNewStyleFrameView(widget,
+                                                          force_opaque_border);
+  }
+  ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh;
+  frame->Init(widget);
+  // Always use "active" look.
+  frame->SetInactiveRenderingDisabled(true);
+  return frame;
+}
+
 void CaptivePortalView::NavigationStateChanged(
     const content::WebContents* source, unsigned changed_flags) {
   SimpleWebViewDialog::NavigationStateChanged(source, changed_flags);
diff --git a/chrome/browser/chromeos/login/captive_portal_view.h b/chrome/browser/chromeos/login/captive_portal_view.h
index b0dadef..4913b8b 100644
--- a/chrome/browser/chromeos/login/captive_portal_view.h
+++ b/chrome/browser/chromeos/login/captive_portal_view.h
@@ -25,6 +25,8 @@
   virtual ui::ModalType GetModalType() const OVERRIDE;
   virtual string16 GetWindowTitle() const OVERRIDE;
   virtual bool ShouldShowWindowTitle() const OVERRIDE;
+  virtual views::NonClientFrameView* CreateNonClientFrameView(
+      views::Widget* widget) OVERRIDE;
 
   // Overridden from content::WebContentsDelegate:
   virtual void NavigationStateChanged(const content::WebContents* source,
@@ -41,6 +43,6 @@
   DISALLOW_COPY_AND_ASSIGN(CaptivePortalView);
 };
 
-}  // chromeos
+}  // namespace chromeos
 
 #endif  // CHROME_BROWSER_CHROMEOS_LOGIN_CAPTIVE_PORTAL_VIEW_H_
diff --git a/chrome/browser/chromeos/login/captive_portal_window_browsertest.cc b/chrome/browser/chromeos/login/captive_portal_window_browsertest.cc
index 98155da..0e1a20d 100644
--- a/chrome/browser/chromeos/login/captive_portal_window_browsertest.cc
+++ b/chrome/browser/chromeos/login/captive_portal_window_browsertest.cc
@@ -6,9 +6,10 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/captive_portal_window_proxy.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
+#include "chrome/browser/chromeos/login/webui_login_view.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/chromeos_switches.h"
 
 namespace chromeos {
@@ -38,7 +39,7 @@
 
 }  // namespace
 
-class CaptivePortalWindowTest : public CrosInProcessBrowserTest {
+class CaptivePortalWindowTest : public InProcessBrowserTest {
  protected:
   void ShowIfRedirected() {
     captive_portal_window_proxy_->ShowIfRedirected();
@@ -76,8 +77,11 @@
     CHECK(LoginDisplayHostImpl::default_host());
     gfx::NativeWindow native_window =
         LoginDisplayHostImpl::default_host()->GetNativeWindow();
+    content::WebContents* web_contents =
+        LoginDisplayHostImpl::default_host()->GetWebUILoginView()->
+            GetWebContents();
     captive_portal_window_proxy_.reset(
-        new CaptivePortalWindowProxy(&delegate_, native_window));
+        new CaptivePortalWindowProxy(&delegate_, native_window, web_contents));
   }
 
  private:
diff --git a/chrome/browser/chromeos/login/captive_portal_window_proxy.cc b/chrome/browser/chromeos/login/captive_portal_window_proxy.cc
index 9a5789d..f05b3ca 100644
--- a/chrome/browser/chromeos/login/captive_portal_window_proxy.cc
+++ b/chrome/browser/chromeos/login/captive_portal_window_proxy.cc
@@ -8,8 +8,14 @@
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/proxy_settings_dialog.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.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 "ui/views/widget/widget.h"
 
+using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
+
 namespace {
 
 int kMargin = 50;
@@ -18,11 +24,14 @@
 
 namespace chromeos {
 
-CaptivePortalWindowProxy::CaptivePortalWindowProxy(Delegate* delegate,
-                                                   gfx::NativeWindow parent)
+CaptivePortalWindowProxy::CaptivePortalWindowProxy(
+    Delegate* delegate,
+    gfx::NativeWindow parent,
+    content::WebContents* web_contents)
     : delegate_(delegate),
       widget_(NULL),
-      parent_(parent) {
+      parent_(parent),
+      web_contents_(web_contents) {
   DCHECK(GetState() == STATE_IDLE);
 }
 
@@ -54,9 +63,17 @@
   InitCaptivePortalView();
 
   CaptivePortalView* captive_portal_view = captive_portal_view_.release();
-  widget_ = views::Widget::CreateWindowWithParent(
+  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
+      WebContentsModalDialogManager::FromWebContents(web_contents_);
+  DCHECK(web_contents_modal_dialog_manager);
+  WebContentsModalDialogManagerDelegate* delegate =
+      web_contents_modal_dialog_manager->delegate();
+  DCHECK(delegate);
+
+  widget_ = views::Widget::CreateWindowAsFramelessChild(
       captive_portal_view,
-      parent_);
+      parent_,
+      delegate->GetWebContentsModalDialogHost()->GetHostView());
   captive_portal_view->Init();
 
   gfx::Rect bounds(CalculateScreenBounds(gfx::Size()));
@@ -64,7 +81,7 @@
   widget_->SetBounds(bounds);
 
   widget_->AddObserver(this);
-  widget_->Show();
+  web_contents_modal_dialog_manager->ShowDialog(widget_->GetNativeView());
   DCHECK(GetState() == STATE_DISPLAYED);
 }
 
diff --git a/chrome/browser/chromeos/login/captive_portal_window_proxy.h b/chrome/browser/chromeos/login/captive_portal_window_proxy.h
index ac62a75..05d75e2 100644
--- a/chrome/browser/chromeos/login/captive_portal_window_proxy.h
+++ b/chrome/browser/chromeos/login/captive_portal_window_proxy.h
@@ -10,6 +10,10 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/views/widget/widget_observer.h"
 
+namespace content {
+class WebContents;
+}
+
 namespace views {
 class Widget;
 }
@@ -33,7 +37,9 @@
  public:
   typedef CaptivePortalWindowProxyDelegate Delegate;
 
-  CaptivePortalWindowProxy(Delegate* delegate, gfx::NativeWindow parent);
+  CaptivePortalWindowProxy(Delegate* delegate,
+                           gfx::NativeWindow parent,
+                           content::WebContents* web_contents);
   virtual ~CaptivePortalWindowProxy();
 
   // Shows captive portal window only after a redirection has happened. So it is
@@ -87,11 +93,16 @@
   // Returns symbolic state name based on internal state.
   State GetState() const;
 
+  // Not owned by this class.
   Delegate* delegate_;
+  // Not owned by this class.
   views::Widget* widget_;
   scoped_ptr<CaptivePortalView> captive_portal_view_;
   gfx::NativeWindow parent_;
 
+  // Not owned by this class.
+  content::WebContents* web_contents_;
+
   DISALLOW_COPY_AND_ASSIGN(CaptivePortalWindowProxy);
 };
 
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index 342776a..3de6a5a 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -134,7 +134,12 @@
       ::switches::kUseGL,
       ::switches::kUserDataDir,
       ::switches::kV,
+      ::switches::kVModule,
       ::switches::kEnableWebGLDraftExtensions,
+#if defined(ENABLE_WEBRTC)
+      ::switches::kEnableWebRtcHWDecoding,
+      ::switches::kEnableWebRtcHWEncoding,
+#endif
       ash::switches::kAshDefaultGuestWallpaperLarge,
       ash::switches::kAshDefaultGuestWallpaperSmall,
       ash::switches::kAshDefaultWallpaperLarge,
diff --git a/chrome/browser/chromeos/login/crash_restore_browsertest.cc b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
index 60002af..6062fd8 100644
--- a/chrome/browser/chromeos/login/crash_restore_browsertest.cc
+++ b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
@@ -8,10 +8,10 @@
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
@@ -31,7 +31,7 @@
 
 }  // namespace
 
-class CrashRestoreSimpleTest : public CrosInProcessBrowserTest {
+class CrashRestoreSimpleTest : public InProcessBrowserTest {
  protected:
   CrashRestoreSimpleTest() {}
 
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index f0e2e8b..4078fde 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -216,14 +216,6 @@
   resume_login_callback_.Reset();
 }
 
-void ExistingUserController::PrepareKioskAppLaunch() {
-  // Disable login UI while waiting for the kiosk app launch. There is no
-  // balanced UI enable call because this very login screen will not be
-  // accessed again. If app is launched, it will be destroyed. If app fails to
-  // launch, chrome is restarted to go back to a new login screen.
-  login_display_->SetUIEnabled(false);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // ExistingUserController, content::NotificationObserver implementation:
 //
@@ -442,11 +434,6 @@
   is_login_in_progress_ = true;
   if (gaia::ExtractDomainName(user_context.username) ==
           UserManager::kLocallyManagedUserDomain) {
-    if (!UserManager::Get()->AreLocallyManagedUsersAllowed()) {
-      LOG(ERROR) << "Login attempt of locally managed user detected.";
-      login_display_->SetUIEnabled(true);
-      return;
-    }
     login_performer_->LoginAsLocallyManagedUser(
         UserContext(user_context.username,
                     user_context.password,
@@ -585,6 +572,10 @@
       l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_PUBLIC_ACCOUNT));
 }
 
+void ExistingUserController::LoginAsKioskApp(const std::string& app_id) {
+  host_->StartAppLaunch(app_id);
+}
+
 void ExistingUserController::OnSigninScreenReady() {
   signin_screen_ready_ = true;
   StartPublicSessionAutoLoginTimer();
@@ -815,8 +806,15 @@
   // Reenable clicking on other windows and status area.
   login_display_->SetUIEnabled(true);
 
-  if (UserManager::Get()->IsCurrentUserNew() &&
-      !UserManager::Get()->GetCurrentUserFlow()->ShouldSkipPostLoginScreens() &&
+  UserManager* user_manager = UserManager::Get();
+  if (user_manager->IsCurrentUserNew() &&
+      user_manager->IsLoggedInAsLocallyManagedUser()) {
+    // Supervised users should launch into empty desktop on first run.
+    CommandLine::ForCurrentProcess()->AppendSwitch(::switches::kSilentLaunch);
+  }
+
+  if (user_manager->IsCurrentUserNew() &&
+      !user_manager->GetCurrentUserFlow()->ShouldSkipPostLoginScreens() &&
       !WizardController::default_controller()->skip_post_login_screens()) {
     // Don't specify start URLs if the administrator has configured the start
     // URLs via policy.
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index 7a2ff11..0580c0b 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -67,9 +67,6 @@
   // Tells the controller to resume a pending login.
   void ResumeLogin();
 
-  // Invoked to prepare for a kiosk app launch attempt.
-  void PrepareKioskAppLaunch();
-
   // Start the public session auto-login timer.
   void StartPublicSessionAutoLoginTimer();
 
@@ -87,6 +84,7 @@
   virtual void LoginAsRetailModeUser() OVERRIDE;
   virtual void LoginAsGuest() OVERRIDE;
   virtual void LoginAsPublicAccount(const std::string& username) OVERRIDE;
+  virtual void LoginAsKioskApp(const std::string& app_id) OVERRIDE;
   virtual void OnSigninScreenReady() OVERRIDE;
   virtual void OnUserSelected(const std::string& username) OVERRIDE;
   virtual void OnStartEnterpriseEnrollment() OVERRIDE;
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index d9a2914..12f30a3 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -33,6 +33,7 @@
 #include "chrome/browser/policy/cloud/cloud_policy_store.h"
 #include "chrome/browser/policy/cloud/mock_cloud_policy_store.h"
 #include "chrome/browser/policy/cloud/policy_builder.h"
+#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
@@ -184,7 +185,7 @@
     // deletes its OnlineAttemptHost instance.  However, OnlineAttemptHost must
     // be deleted on the UI thread.
     existing_user_controller_.reset();
-    CrosInProcessBrowserTest::CleanUpOnMainThread();
+    DevicePolicyCrosBrowserTest::InProcessBrowserTest::CleanUpOnMainThread();
     testing_profile_.reset(NULL);
     user_manager_enabler_.reset();
   }
diff --git a/chrome/browser/chromeos/login/fake_login_utils.cc b/chrome/browser/chromeos/login/fake_login_utils.cc
index 675c9e2..f0e68c3 100644
--- a/chrome/browser/chromeos/login/fake_login_utils.cc
+++ b/chrome/browser/chromeos/login/fake_login_utils.cc
@@ -25,6 +25,7 @@
 
 void FakeLoginUtils::DoBrowserLaunch(Profile* profile,
                                      LoginDisplayHost* login_host) {
+  login_host->BeforeSessionStart();
   if (should_launch_browser_) {
     StartupBrowserCreator browser_creator;
     chrome::startup::IsFirstRun first_run =
@@ -40,6 +41,7 @@
   }
   if (login_host)
     login_host->Finalize();
+  UserManager::Get()->SessionStarted();
 }
 
 void FakeLoginUtils::PrepareProfile(const UserContext& user_context,
diff --git a/chrome/browser/chromeos/login/kiosk_browsertest.cc b/chrome/browser/chromeos/login/kiosk_browsertest.cc
index 5604c22..c1fcf41 100644
--- a/chrome/browser/chromeos/login/kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/kiosk_browsertest.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/browser_process.h"
@@ -12,7 +14,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
+#include "chrome/browser/chromeos/login/app_launch_controller.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/webui_login_display.h"
@@ -58,7 +60,7 @@
 //       detail/ggbflgnkafappblpkiflbgpmkfdpnhhe
 const char kTestKioskApp[] = "ggbflgnkafappblpkiflbgpmkfdpnhhe";
 
-// Helper method for GetConsumerKioskModeStatusCallback.
+// Helper function for GetConsumerKioskModeStatusCallback.
 void ConsumerKioskModeStatusCheck(
     KioskAppManager::ConsumerKioskModeStatus* out_status,
     const base::Closure& runner_quit_task,
@@ -78,345 +80,23 @@
   runner_quit_task.Run();
 }
 
-class TestBrowserMainExtraParts
-    : public ChromeBrowserMainExtraParts,
-      public content::NotificationObserver {
- public:
-  TestBrowserMainExtraParts() {}
-  virtual ~TestBrowserMainExtraParts() {}
-
-  void set_quit_task(const base::Closure& quit_task) { quit_task_ = quit_task; }
-
-  void SetupSigninScreen() {
-    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");
-  }
-
- protected:
-  content::NotificationRegistrar registrar_;
-  base::Closure quit_task_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestBrowserMainExtraParts);
-};
-
-// Used to add an observer to NotificationService after it's created.
-class KioskAppLaunchScenarioHandler : public TestBrowserMainExtraParts {
- public:
-  KioskAppLaunchScenarioHandler() {}
-
-  virtual ~KioskAppLaunchScenarioHandler() {}
-
- private:
-  // ChromeBrowserMainExtraParts implementation.
-  virtual void PreEarlyInitialization() OVERRIDE {
-    registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_APPS_LOADED,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
-                   content::NotificationService::AllSources());
-  }
-
-  // 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";
-      SetupSigninScreen();
-    } else if (type == chrome::NOTIFICATION_KIOSK_APPS_LOADED) {
-      LOG(INFO) << "chrome::NOTIFICATION_KIOSK_APPS_LOADED";
-      content::WebUI* web_ui = static_cast<chromeos::LoginDisplayHostImpl*>(
-          chromeos::LoginDisplayHostImpl::default_host())->
-              GetOobeUI()->web_ui();
-      web_ui->CallJavascriptFunction("login.AppsMenuButton.runAppForTesting",
-                                     base::StringValue(kTestKioskApp));
-    } else if (type == chrome::NOTIFICATION_KIOSK_APP_LAUNCHED) {
-      LOG(INFO) << "chrome::NOTIFICATION_KIOSK_APP_LAUNCHED";
-      registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                     content::NotificationService::AllSources());
-      quit_task_.Run();
-    } else if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
-      LOG(INFO) << "content::NOTIFICATION_RENDERER_PROCESS_CLOSED";
-      quit_task_.Run();
-    } else {
-      NOTREACHED();
-    }
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(KioskAppLaunchScenarioHandler);
-};
-
-class AutostartWarningCancelScenarioHandler : public TestBrowserMainExtraParts {
- public:
-  AutostartWarningCancelScenarioHandler() {
-  }
-
-  virtual ~AutostartWarningCancelScenarioHandler() {}
-
- private:
-  // ChromeBrowserMainExtraParts implementation.
-  virtual void PreEarlyInitialization() OVERRIDE {
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
-                   content::NotificationService::AllSources());
-  }
-
-  // Overridden from content::NotificationObserver:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    switch (type) {
-      case chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE: {
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE";
-        content::WebUI* web_ui = static_cast<chromeos::LoginDisplayHostImpl*>(
-            chromeos::LoginDisplayHostImpl::default_host())->
-                GetOobeUI()->web_ui();
-        web_ui->CallJavascriptFunction(
-            "login.AutolaunchScreen.confirmAutoLaunchForTesting",
-            base::FundamentalValue(false));
-        break;
-      }
-      case chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED: {
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED";
-        quit_task_.Run();
-        break;
-      }
-      case chrome::NOTIFICATION_KIOSK_APP_LAUNCHED: {
-        LOG(FATAL) << "chrome::NOTIFICATION_KIOSK_APP_LAUNCHED";
-        break;
-      }
-      default: {
-        NOTREACHED();
-      }
-    }
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(AutostartWarningCancelScenarioHandler);
-};
-
-class AutostartWarningConfirmScenarioHandler
-    : public TestBrowserMainExtraParts {
- public:
-  AutostartWarningConfirmScenarioHandler() : first_pass_(true) {
-  }
-
-  virtual ~AutostartWarningConfirmScenarioHandler() {}
-
- private:
-  // ChromeBrowserMainExtraParts implementation.
-  virtual void PreEarlyInitialization() OVERRIDE {
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
-                   content::NotificationService::AllSources());
-  }
-
-  // Overridden from content::NotificationObserver:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    switch (type) {
-      case chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE: {
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE";
-        if (!first_pass_)
-          break;
-
-        content::WebUI* web_ui = static_cast<chromeos::LoginDisplayHostImpl*>(
-            chromeos::LoginDisplayHostImpl::default_host())->
-                GetOobeUI()->web_ui();
-        web_ui->CallJavascriptFunction(
-            "login.AutolaunchScreen.confirmAutoLaunchForTesting",
-            base::FundamentalValue(true));
-      }
-      case chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED: {
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED";
-        first_pass_ = false;
-        break;
-      }
-      case chrome::NOTIFICATION_KIOSK_APP_LAUNCHED:
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_APP_LAUNCHED";
-        registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                       content::NotificationService::AllSources());
-        quit_task_.Run();
-       break;
-      case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
-        LOG(INFO) << "chrome::NOTIFICATION_RENDERER_PROCESS_CLOSED";
-        quit_task_.Run();
-        break;
-      }
-      default: {
-        NOTREACHED();
-      }
-    }
-  }
-
-  bool first_pass_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutostartWarningConfirmScenarioHandler);
-};
-
-
-class KioskEnableScenarioHandler
-    : public TestBrowserMainExtraParts {
- public:
-  explicit KioskEnableScenarioHandler(bool enable_kiosk)
-      : enable_kiosk_(enable_kiosk) {
-  }
-
-  virtual ~KioskEnableScenarioHandler() {}
-
- private:
-  // ChromeBrowserMainExtraParts implementation.
-  virtual void PreEarlyInitialization() OVERRIDE {
-    registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED,
-                   content::NotificationService::AllSources());
-    registrar_.Add(this, chrome::NOTIFICATION_KIOSK_ENABLED,
-                   content::NotificationService::AllSources());
-  }
-
-  // Overridden from content::NotificationObserver:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    switch (type) {
-      case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
-        LOG(INFO) << "NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE";
-        SetupSigninScreen();
-        content::WebUI* web_ui = static_cast<chromeos::LoginDisplayHostImpl*>(
-            chromeos::LoginDisplayHostImpl::default_host())->
-                GetOobeUI()->web_ui();
-        web_ui->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator",
-                                       base::StringValue("kiosk_enable"));
-        break;
-      }
-      case chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE: {
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE";
-        content::WebUI* web_ui = static_cast<chromeos::LoginDisplayHostImpl*>(
-            chromeos::LoginDisplayHostImpl::default_host())->
-                GetOobeUI()->web_ui();
-        web_ui->CallJavascriptFunction(
-            "login.KioskEnableScreen.enableKioskForTesting",
-            base::FundamentalValue(enable_kiosk_));
-        break;
-      }
-      case chrome::NOTIFICATION_KIOSK_ENABLED: {
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_ENABLED";
-        ASSERT_TRUE(enable_kiosk_);
-        quit_task_.Run();
-        break;
-      }
-      case chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED: {
-        LOG(INFO) << "chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED";
-        quit_task_.Run();
-        break;
-      }
-      default: {
-        NOTREACHED();
-        break;
-      }
-    }
-  }
-
-  bool enable_kiosk_;
-  DISALLOW_COPY_AND_ASSIGN(KioskEnableScenarioHandler);
-};
-
-class TestContentBrowserClient : public chrome::ChromeContentBrowserClient {
- public:
-  enum LaunchEventSequence {
-    KioskAppLaunch,
-    AutostartWarningCanceled,
-    AutostartWarningConfirmed,
-    KioskEnableRejected,
-    KioskEnableConfirmed,
-  };
-
-  explicit TestContentBrowserClient(LaunchEventSequence sequence)
-      : browser_main_extra_parts_(NULL), sequence_(sequence) {
-  }
-
-  virtual ~TestContentBrowserClient() {}
-
-  virtual content::BrowserMainParts* CreateBrowserMainParts(
-      const content::MainFunctionParams& parameters) OVERRIDE {
-    ChromeBrowserMainParts* main_parts = static_cast<ChromeBrowserMainParts*>(
-        ChromeContentBrowserClient::CreateBrowserMainParts(parameters));
-
-    switch (sequence_) {
-      case KioskAppLaunch:
-        browser_main_extra_parts_ = new KioskAppLaunchScenarioHandler();
-        break;
-      case AutostartWarningCanceled:
-        browser_main_extra_parts_ = new AutostartWarningCancelScenarioHandler();
-        break;
-      case AutostartWarningConfirmed:
-        browser_main_extra_parts_ =
-            new AutostartWarningConfirmScenarioHandler();
-        break;
-      case KioskEnableRejected:
-        browser_main_extra_parts_ =
-            new KioskEnableScenarioHandler(false);
-        break;
-      case KioskEnableConfirmed:
-        browser_main_extra_parts_ =
-            new KioskEnableScenarioHandler(true);
-        break;
-    }
-
-    main_parts->AddParts(browser_main_extra_parts_);
-    return main_parts;
-  }
-
-  TestBrowserMainExtraParts* browser_main_extra_parts_;
-
- private:
-  LaunchEventSequence sequence_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestContentBrowserClient);
-};
-
 }  // namespace
 
-
-class KioskTest : public chromeos::CrosInProcessBrowserTest,
+class KioskTest : public InProcessBrowserTest,
                   // Param defining is multi-profiles enabled.
                   public testing::WithParamInterface<bool> {
  public:
-  KioskTest()
-     : chromeos::CrosInProcessBrowserTest(),
-       original_content_browser_client_(NULL),
-       test_server_(NULL) {
+  KioskTest() {
     set_exit_when_last_browser_closes(false);
   }
 
   virtual ~KioskTest() {}
 
  protected:
-  virtual void InitializeKioskTest() = 0;
-
   virtual void SetUpOnMainThread() OVERRIDE {
-    test_server_ = new EmbeddedTestServer(
+    test_server_.reset(new EmbeddedTestServer(
         content::BrowserThread::GetMessageLoopProxyForThread(
-            content::BrowserThread::IO));
+            content::BrowserThread::IO)));
     CHECK(test_server_->InitializeAndWaitUntilReady());
     test_server_->RegisterRequestHandler(
         base::Bind(&KioskTest::HandleRequest, base::Unretained(this)));
@@ -428,13 +108,20 @@
   }
 
   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();
+    }
+
     // Clean up while main thread still runs.
     // See http://crbug.com/176659.
     KioskAppManager::Get()->CleanUp();
 
     LOG(INFO) << "Stopping the http server.";
     EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
-    delete test_server_;  // Destructor wants UI thread.
+    test_server_.reset();  // Destructor wants UI thread.
   }
 
   scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
@@ -492,10 +179,6 @@
   }
 
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    InitializeKioskTest();
-    original_content_browser_client_ = content::SetBrowserClientForTesting(
-        content_browser_client_.get());
-
     base::FilePath test_data_dir;
     PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
     CHECK(file_util::ReadFileToString(test_data_dir.Append(kServiceLogin),
@@ -525,27 +208,32 @@
     EXPECT_TRUE(*locked.get());
   }
 
-  scoped_ptr<TestContentBrowserClient> content_browser_client_;
-  content::ContentBrowserClient* original_content_browser_client_;
+  KioskAppManager::ConsumerKioskModeStatus GetConsumerKioskModeStatus() {
+    KioskAppManager::ConsumerKioskModeStatus status =
+        static_cast<KioskAppManager::ConsumerKioskModeStatus>(-1);
+    scoped_refptr<content::MessageLoopRunner> runner =
+        new content::MessageLoopRunner;
+    KioskAppManager::Get()->GetConsumerKioskModeStatus(
+        base::Bind(&ConsumerKioskModeStatusCheck,
+                   &status,
+                   runner->QuitClosure()));
+    runner->Run();
+    CHECK_NE(status, static_cast<KioskAppManager::ConsumerKioskModeStatus>(-1));
+    return status;
+  }
+
+  content::WebUI* GetLoginUI() {
+    return static_cast<chromeos::LoginDisplayHostImpl*>(
+        chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI()->web_ui();
+  }
+
   std::string service_login_response_;
-  EmbeddedTestServer* test_server_;  // cant use scoped_ptr because destructor
-                                     // needs UI thread.
+  scoped_ptr<EmbeddedTestServer> test_server_;
  };
 
-class KioskLaunchTest : public KioskTest {
- public:
-  KioskLaunchTest() : KioskTest() {}
-  virtual ~KioskLaunchTest() {}
-
-  // KioskTest overrides.
-  virtual void InitializeKioskTest() OVERRIDE {
-    content_browser_client_.reset(
-        new TestContentBrowserClient(TestContentBrowserClient::KioskAppLaunch));
-  }
-};
-
-IN_PROC_BROWSER_TEST_P(KioskLaunchTest, InstallAndLaunchApp) {
+IN_PROC_BROWSER_TEST_P(KioskTest, InstallAndLaunchApp) {
   EnableConsumerKioskMode();
+  chromeos::AppLaunchController::SkipSplashWaitForTesting();
   // Start UI, find menu entry for this app and launch it.
   chromeos::WizardController::SkipPostLoginScreensForTesting();
   chromeos::WizardController* wizard_controller =
@@ -555,13 +243,17 @@
 
   ReloadKioskApps();
 
-  // The first loop exits after we receive NOTIFICATION_KIOSK_APP_LAUNCHED
-  // notification - right at app launch.
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner->QuitClosure());
-  runner->Run();
+  // Wait for the Kiosk App configuration to reload, then launch the app.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_APPS_LOADED,
+      content::NotificationService::AllSources()).Wait();
+  GetLoginUI()->CallJavascriptFunction("login.AppsMenuButton.runAppForTesting",
+                                       base::StringValue(kTestKioskApp));
+
+  // 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,
@@ -574,43 +266,11 @@
       extension_service()->GetInstalledExtension(kTestKioskApp);
   EXPECT_TRUE(app);
 
-  // The second loop exits when kiosk app terminates and we receive
-  // NOTIFICATION_RENDERER_PROCESS_CLOSED.
-  scoped_refptr<content::MessageLoopRunner> runner2 =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner2->QuitClosure());
-  runner2->Run();
+  // Wait until the app terminates.
+  content::RunMessageLoop();
 }
 
-class KioskAutolaunchCancelTest : public KioskTest {
- public:
-  KioskAutolaunchCancelTest() : KioskTest(), login_display_host_(NULL) {}
-  virtual ~KioskAutolaunchCancelTest() {}
-
- private:
-  // Overrides from KioskTest.
-  virtual void InitializeKioskTest() OVERRIDE {
-    content_browser_client_.reset(new TestContentBrowserClient(
-            TestContentBrowserClient::AutostartWarningCanceled));
-  }
-
-  virtual void SetUpOnMainThread() OVERRIDE {
-    login_display_host_ = LoginDisplayHostImpl::default_host();
-    KioskTest::SetUpOnMainThread();
-  }
-
-  virtual void CleanUpOnMainThread() OVERRIDE {
-    // LoginDisplayHost owns controllers and all windows.
-    base::MessageLoopForUI::current()->DeleteSoon(FROM_HERE,
-                                                  login_display_host_);
-    KioskTest::CleanUpOnMainThread();
-  }
-
-  LoginDisplayHost* login_display_host_;
-};
-
-IN_PROC_BROWSER_TEST_P(KioskAutolaunchCancelTest, AutolaunchWarningCancel) {
+IN_PROC_BROWSER_TEST_P(KioskTest, AutolaunchWarningCancel) {
   EnableConsumerKioskMode();
   // Start UI, find menu entry for this app and launch it.
   chromeos::WizardController::SkipPostLoginScreensForTesting();
@@ -620,39 +280,26 @@
   ReloadAutolaunchKioskApps();
   wizard_controller->SkipToLoginForTesting();
 
-  EXPECT_FALSE(
-      KioskAppManager::Get()->GetAutoLaunchApp().empty());
-  EXPECT_FALSE(
-      KioskAppManager::Get()->IsAutoLaunchEnabled());
+  EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
+  EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
 
-  // The loop exits after we receive
-  // NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED after
-  // NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE notification - right after
-  // auto launch is canceled.
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner->QuitClosure());
-  runner->Run();
+  // Wait for the auto launch warning come up.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
+      content::NotificationService::AllSources()).Wait();
+  GetLoginUI()->CallJavascriptFunction(
+      "login.AutolaunchScreen.confirmAutoLaunchForTesting",
+      base::FundamentalValue(false));
 
-  EXPECT_FALSE(
-      KioskAppManager::Get()->IsAutoLaunchEnabled());
+  // Wait for the auto launch warning to go away.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
+      content::NotificationService::AllSources()).Wait();
+
+  EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
 }
 
-class KioskAutolaunchConfirmTest : public KioskTest {
- public:
-  KioskAutolaunchConfirmTest() : KioskTest() {}
-  virtual ~KioskAutolaunchConfirmTest() {}
-
- private:
-  // Overrides from KioskTest.
-  virtual void InitializeKioskTest() OVERRIDE {
-    content_browser_client_.reset(new TestContentBrowserClient(
-            TestContentBrowserClient::AutostartWarningConfirmed));
-  }
-};
-
-IN_PROC_BROWSER_TEST_P(KioskAutolaunchConfirmTest, AutolaunchWarningConfirm) {
+IN_PROC_BROWSER_TEST_P(KioskTest, AutolaunchWarningConfirm) {
   EnableConsumerKioskMode();
   // Start UI, find menu entry for this app and launch it.
   chromeos::WizardController::SkipPostLoginScreensForTesting();
@@ -662,23 +309,29 @@
   wizard_controller->SkipToLoginForTesting();
 
   ReloadAutolaunchKioskApps();
-  EXPECT_FALSE(
-      KioskAppManager::Get()->GetAutoLaunchApp().empty());
-  EXPECT_FALSE(
-      KioskAppManager::Get()->IsAutoLaunchEnabled());
+  EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
+  EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
 
-  // The loop exits after we receive NOTIFICATION_KIOSK_APP_LAUNCHED
-  // notification - right at app launch.
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner->QuitClosure());
-  runner->Run();
+  // Wait for the auto launch warning come up.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
+      content::NotificationService::AllSources()).Wait();
+  GetLoginUI()->CallJavascriptFunction(
+      "login.AutolaunchScreen.confirmAutoLaunchForTesting",
+      base::FundamentalValue(true));
 
-  EXPECT_FALSE(
-      KioskAppManager::Get()->GetAutoLaunchApp().empty());
-  EXPECT_TRUE(
-      KioskAppManager::Get()->IsAutoLaunchEnabled());
+  // Wait for the auto launch warning to go away.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
+      content::NotificationService::AllSources()).Wait();
+
+  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,
@@ -691,166 +344,82 @@
       extension_service()->GetInstalledExtension(kTestKioskApp);
   EXPECT_TRUE(app);
 
-  // The second loop exits when kiosk app terminates and we receive
-  // NOTIFICATION_RENDERER_PROCESS_CLOSED.
-  scoped_refptr<content::MessageLoopRunner> runner2 =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner2->QuitClosure());
-  runner2->Run();
+  // Wait until the app terminates.
+  content::RunMessageLoop();
 }
 
-class KioskEnableTest : public KioskTest {
- public:
-  KioskEnableTest() : login_display_host_(NULL) {}
-  virtual ~KioskEnableTest() {}
+IN_PROC_BROWSER_TEST_P(KioskTest, KioskEnableCancel) {
+  chromeos::WizardController::SkipPostLoginScreensForTesting();
+  chromeos::WizardController* wizard_controller =
+      chromeos::WizardController::default_controller();
+  CHECK(wizard_controller);
 
- private:
-  // Overrides from KioskTest.
-  virtual void SetUpOnMainThread() OVERRIDE {
-    login_display_host_ = LoginDisplayHostImpl::default_host();
-    KioskTest::SetUpOnMainThread();
-  }
+  // Check Kiosk mode status.
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+            GetConsumerKioskModeStatus());
 
-  virtual void CleanUpOnMainThread() OVERRIDE {
-    // LoginDisplayHost owns controllers and all windows.
-    base::MessageLoopForUI::current()->DeleteSoon(FROM_HERE,
-                                                  login_display_host_);
-    KioskTest::CleanUpOnMainThread();
-  }
+  // 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"));
 
-  LoginDisplayHost* login_display_host_;
-};
+  // Wait for the kiosk_enable screen to show and cancel the screen.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
+      content::NotificationService::AllSources()).Wait();
+  GetLoginUI()->CallJavascriptFunction(
+      "login.KioskEnableScreen.enableKioskForTesting",
+      base::FundamentalValue(false));
 
-class KioskEnableCancelTest : public KioskEnableTest {
- public:
-  KioskEnableCancelTest() {}
-  virtual ~KioskEnableCancelTest() {}
+  // Wait for the kiosk_enable screen to disappear.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED,
+      content::NotificationService::AllSources()).Wait();
 
- private:
-  // Overrides from KioskTest.
-  virtual void InitializeKioskTest() OVERRIDE {
-    content_browser_client_.reset(new TestContentBrowserClient(
-            TestContentBrowserClient::KioskEnableRejected));
-  }
-};
+  // Check that the status still says configurable.
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+            GetConsumerKioskModeStatus());
+}
 
-IN_PROC_BROWSER_TEST_P(KioskEnableCancelTest, KioskEnableCancel) {
+IN_PROC_BROWSER_TEST_P(KioskTest, KioskEnableConfirmed) {
   // 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);
 
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  // Check the intial state of the consumer kiosk.
-  scoped_ptr<KioskAppManager::ConsumerKioskModeStatus> status(
-      new KioskAppManager::ConsumerKioskModeStatus(
-          KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED));
-  KioskAppManager::Get()->GetConsumerKioskModeStatus(
-      base::Bind(&ConsumerKioskModeStatusCheck,
-                 status.get(),
-                 runner->QuitClosure()));
-  runner->Run();
-  EXPECT_EQ(*status.get(),  KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE);
-
+  // Check Kiosk mode status.
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+            GetConsumerKioskModeStatus());
   wizard_controller->SkipToLoginForTesting();
-  // The loop exits after we receive
-  // NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED after
-  // NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE notification - right after
-  // enable consumer kiosk screen is canceled.
-  scoped_refptr<content::MessageLoopRunner> runner2 =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner2->QuitClosure());
-  runner2->Run();
 
-  scoped_refptr<content::MessageLoopRunner> runner3 =
-      new content::MessageLoopRunner;
-  // Check the end state of the consumer kiosk after disabling the feature.
-  KioskAppManager::Get()->GetConsumerKioskModeStatus(
-      base::Bind(&ConsumerKioskModeStatusCheck,
-                 status.get(),
-                 runner3->QuitClosure()));
-  runner3->Run();
-  EXPECT_EQ(*status.get(),  KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE);
+  // 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"));
+
+  // Wait for the kiosk_enable screen to show and cancel the screen.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
+      content::NotificationService::AllSources()).Wait();
+  GetLoginUI()->CallJavascriptFunction(
+      "login.KioskEnableScreen.enableKioskForTesting",
+      base::FundamentalValue(true));
+
+  // Wait for the signal that indicates Kiosk Mode is enabled.
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_KIOSK_ENABLED,
+      content::NotificationService::AllSources()).Wait();
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_ENABLED,
+            GetConsumerKioskModeStatus());
 }
 
-
-class KioskEnableConfirmedTest : public KioskEnableTest {
- public:
-  KioskEnableConfirmedTest() {}
-  virtual ~KioskEnableConfirmedTest() {}
-
- private:
-  // Overrides from KioskTest.
-  virtual void InitializeKioskTest() OVERRIDE {
-    content_browser_client_.reset(new TestContentBrowserClient(
-            TestContentBrowserClient::KioskEnableConfirmed));
-  }
-};
-
-IN_PROC_BROWSER_TEST_P(KioskEnableConfirmedTest, KioskEnableConfirmed) {
-  // 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);
-
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  // Check the intial state of the consumer kiosk.
-  scoped_ptr<KioskAppManager::ConsumerKioskModeStatus> status(
-      new KioskAppManager::ConsumerKioskModeStatus(
-          KioskAppManager::CONSUMER_KIOSK_MODE_DISABLED));
-  KioskAppManager::Get()->GetConsumerKioskModeStatus(
-      base::Bind(&ConsumerKioskModeStatusCheck,
-                 status.get(),
-                 runner->QuitClosure()));
-  runner->Run();
-  EXPECT_EQ(*status.get(),  KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE);
-
-  wizard_controller->SkipToLoginForTesting();
-  // The loop exits after we receive
-  // NOTIFICATION_KIOSK_ENABLED after
-  // NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE notification - right after
-  // enable consumer kiosk screen is canceled.
-  scoped_refptr<content::MessageLoopRunner> runner2 =
-      new content::MessageLoopRunner;
-  content_browser_client_->browser_main_extra_parts_->set_quit_task(
-      runner2->QuitClosure());
-  runner2->Run();
-
-  scoped_refptr<content::MessageLoopRunner> runner3 =
-      new content::MessageLoopRunner;
-  // Check the end state of the consumer kiosk after disabling the feature.
-  KioskAppManager::Get()->GetConsumerKioskModeStatus(
-      base::Bind(&ConsumerKioskModeStatusCheck,
-                 status.get(),
-                 runner3->QuitClosure()));
-  runner3->Run();
-  EXPECT_EQ(*status.get(),  KioskAppManager::CONSUMER_KIOSK_MODE_ENABLED);
-}
-
-INSTANTIATE_TEST_CASE_P(KioskLaunchTestInstantiation,
-                        KioskLaunchTest,
-                        testing::Bool());
-
-INSTANTIATE_TEST_CASE_P(KioskAutolaunchCancelTestInstantiation,
-                        KioskAutolaunchCancelTest,
-                        testing::Bool());
-
-INSTANTIATE_TEST_CASE_P(KioskAutolaunchConfirmTestInstantiation,
-                        KioskAutolaunchConfirmTest,
-                        testing::Bool());
-
-INSTANTIATE_TEST_CASE_P(KioskEnableCancelTestInstantiation,
-                        KioskEnableCancelTest,
-                        testing::Bool());
-
-INSTANTIATE_TEST_CASE_P(KioskEnableConfirmedTestInstantiation,
-                        KioskEnableConfirmedTest,
-                        testing::Bool());
+INSTANTIATE_TEST_CASE_P(KioskTestInstantiation, KioskTest, testing::Bool());
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/language_switch_menu.h b/chrome/browser/chromeos/login/language_switch_menu.h
index 1677359..e95f7fa 100644
--- a/chrome/browser/chromeos/login/language_switch_menu.h
+++ b/chrome/browser/chromeos/login/language_switch_menu.h
@@ -48,9 +48,9 @@
   static void SwitchLanguageAndEnableKeyboardLayouts(
       const std::string& locale);
 
- private:
   static void LoadFontsForCurrentLocale();
 
+ private:
   // Overridden from views::MenuButtonListener:
   virtual void OnMenuButtonClicked(views::View* source,
                                    const gfx::Point& point) OVERRIDE;
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index 3bf47c8..4db9cb0 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -8,7 +8,6 @@
 #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/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
@@ -34,13 +33,13 @@
 
 namespace {
 
-class LoginTestBase : public chromeos::CrosInProcessBrowserTest {
+class LoginTestBase : public InProcessBrowserTest {
  public:
   LoginTestBase() {}
 
  protected:
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
 
     mock_cryptohome_library_.reset(new chromeos::MockCryptohomeLibrary());
     EXPECT_CALL(*(mock_cryptohome_library_.get()), GetSystemSalt())
@@ -136,7 +135,7 @@
 };
 
 
-class LoginSigninTest : public chromeos::CrosInProcessBrowserTest {
+class LoginSigninTest : public InProcessBrowserTest {
  protected:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     command_line->AppendSwitch(chromeos::switches::kLoginManager);
diff --git a/chrome/browser/chromeos/login/login_display.h b/chrome/browser/chromeos/login/login_display.h
index 12db78d..763a66e 100644
--- a/chrome/browser/chromeos/login/login_display.h
+++ b/chrome/browser/chromeos/login/login_display.h
@@ -64,6 +64,9 @@
     // Sign in into the public account identified by |username|.
     virtual void LoginAsPublicAccount(const std::string& username) = 0;
 
+    // Login to kiosk mode for app with |app_id|.
+    virtual void LoginAsKioskApp(const std::string& app_id) = 0;
+
     // Notify the delegate when the sign-in UI is finished loading.
     virtual void OnSigninScreenReady() = 0;
 
diff --git a/chrome/browser/chromeos/login/login_display_host.h b/chrome/browser/chromeos/login/login_display_host.h
index 72b83c5..cb9d6f4 100644
--- a/chrome/browser/chromeos/login/login_display_host.h
+++ b/chrome/browser/chromeos/login/login_display_host.h
@@ -98,6 +98,9 @@
 
   // Initiates authentication network prewarming.
   virtual void PrewarmAuthentication() = 0;
+
+  // Starts app launch splash screen.
+  virtual void StartAppLaunch(const std::string& app_id) = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.cc b/chrome/browser/chromeos/login/login_display_host_impl.cc
index 4148d9c..8da65b4 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/login_display_host_impl.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/customization_document.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
@@ -77,13 +78,16 @@
 namespace {
 
 // URL which corresponds to the login WebUI.
-const char kLoginURL[] = "chrome://oobe/login#login";
+const char kLoginURL[] = "chrome://oobe/login";
 
 // URL which corresponds to the OOBE WebUI.
-const char kOobeURL[] = "chrome://oobe#login";
+const char kOobeURL[] = "chrome://oobe/oobe";
 
 // URL which corresponds to the user adding WebUI.
-const char kUserAddingURL[] = "chrome://oobe/login#user-adding";
+const char kUserAddingURL[] = "chrome://oobe/user-adding";
+
+// URL which corresponds to the app launch splash WebUI.
+const char kAppLaunchSplashURL[] = "chrome://oobe/app-launch-splash";
 
 // Duration of sign-in transition animation.
 const int kLoginFadeoutTransitionDurationMs = 700;
@@ -509,6 +513,20 @@
                  pointer_factory_.GetWeakPtr()));
 }
 
+void LoginDisplayHostImpl::StartAppLaunch(const std::string& app_id) {
+  LOG(WARNING) << "Login WebUI >> start app launch.";
+  SetStatusAreaVisible(false);
+  if (!login_window_)
+    LoadURL(GURL(kAppLaunchSplashURL));
+
+  login_view_->set_should_emit_login_prompt_visible(false);
+
+  app_launch_controller_.reset(new AppLaunchController(
+      app_id, this, GetOobeUI()));
+
+  app_launch_controller_->StartAppLaunch();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // LoginDisplayHostImpl, public
 
@@ -773,7 +791,7 @@
   }
   login_view_ = new WebUILoginView();
 
-  login_view_->Init(login_window_);
+  login_view_->Init();
 
   views::corewm::SetWindowVisibilityAnimationDuration(
       login_window_->GetNativeView(),
@@ -783,7 +801,6 @@
       views::corewm::ANIMATE_HIDE);
 
   login_window_->SetContentsView(login_view_);
-  login_view_->UpdateWindowType();
 
   // If WebUI is initialized in hidden state, show it only if we're no
   // longer waiting for wallpaper animation/user images loading. Otherwise,
@@ -797,7 +814,6 @@
     login_view_->set_is_hidden(true);
   }
   login_window_->GetNativeView()->SetName("WebUILoginView");
-  login_view_->OnWindowCreated();
 }
 
 void LoginDisplayHostImpl::ResetLoginWindowAndView() {
@@ -852,6 +868,13 @@
           manager->GetInputMethodUtil()->GetHardwareInputMethodId();
     }
     manager->EnableLayouts(locale, initial_input_method_id);
+
+    // Apply owner preferences for tap-to-click and mouse buttons swap for
+    // login screen.
+    system::mouse_settings::SetPrimaryButtonRight(
+        prefs->GetBoolean(prefs::kOwnerPrimaryMouseButtonRight));
+    system::touchpad_settings::SetTapToClick(
+      prefs->GetBoolean(prefs::kOwnerTapToClickEnabled));
   }
 
   ui::SetNaturalScroll(CommandLine::ForCurrentProcess()->HasSwitch(
@@ -868,13 +891,23 @@
     LoginState::Get()->SetLoggedInState(
         LoginState::LOGGED_IN_NONE, LoginState::LOGGED_IN_USER_NONE);
   }
+
+  LoginDisplayHost* display_host = new LoginDisplayHostImpl(screen_bounds);
+
+  bool show_app_launch_splash_screen = (first_screen_name ==
+      chromeos::WizardController::kAppLaunchSplashScreenName);
+
+  if (show_app_launch_splash_screen) {
+    const std::string& auto_launch_app_id =
+        chromeos::KioskAppManager::Get()->GetAutoLaunchApp();
+    display_host->StartAppLaunch(auto_launch_app_id);
+    return;
+  }
+
   bool show_login_screen =
       (first_screen_name.empty() && oobe_complete) ||
       first_screen_name == chromeos::WizardController::kLoginScreenName;
 
-  chromeos::LoginDisplayHost* display_host =
-      new chromeos::LoginDisplayHostImpl(screen_bounds);
-
   if (show_login_screen) {
     // R11 > R12 migration fix. See http://crosbug.com/p/4898.
     // If user has manually changed locale during R11 OOBE, locale will be set.
@@ -938,6 +971,9 @@
       // Set the application locale here so that the language switch
       // menu works properly with the newly loaded locale.
       g_browser_process->SetApplicationLocale(loaded_locale);
+
+      // Reload font settings here to use correct font for initial_locale.
+      LanguageSwitchMenu::LoadFontsForCurrentLocale();
     }
   }
 
diff --git a/chrome/browser/chromeos/login/login_display_host_impl.h b/chrome/browser/chromeos/login/login_display_host_impl.h
index 8d25d3f..fd1f0ec 100644
--- a/chrome/browser/chromeos/login/login_display_host_impl.h
+++ b/chrome/browser/chromeos/login/login_display_host_impl.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/login/app_launch_controller.h"
 #include "chrome/browser/chromeos/login/auth_prewarmer.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/login_display.h"
@@ -72,6 +73,7 @@
   virtual void ResumeSignInScreen() OVERRIDE;
   virtual void OnPreferencesChanged() OVERRIDE;
   virtual void PrewarmAuthentication() OVERRIDE;
+  virtual void StartAppLaunch(const std::string& app_id) OVERRIDE;
 
   // Creates WizardController instance.
   WizardController* CreateWizardController();
@@ -153,6 +155,9 @@
   // OOBE and some screens (camera, recovery) controller.
   scoped_ptr<WizardController> wizard_controller_;
 
+  // App launch controller.
+  scoped_ptr<AppLaunchController> app_launch_controller_;
+
   // Client for enterprise auto-enrollment check.
   scoped_ptr<policy::AutoEnrollmentClient> auto_enrollment_client_;
 
diff --git a/chrome/browser/chromeos/login/login_manager_test.cc b/chrome/browser/chromeos/login/login_manager_test.cc
new file mode 100644
index 0000000..6196c83
--- /dev/null
+++ b/chrome/browser/chromeos/login/login_manager_test.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 "chrome/browser/chromeos/login/login_manager_test.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/user_manager.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"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+LoginManagerTest::LoginManagerTest(bool should_launch_browser)
+    : should_launch_browser_(should_launch_browser) {
+  set_exit_when_last_browser_closes(false);
+}
+
+void LoginManagerTest::SetUpCommandLine(CommandLine* command_line) {
+  command_line->AppendSwitch(chromeos::switches::kLoginManager);
+  command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
+  command_line->AppendSwitch(::switches::kMultiProfiles);
+}
+
+void LoginManagerTest::SetUpInProcessBrowserTestFixture() {
+  mock_login_utils_ = new testing::NiceMock<MockLoginUtils>();
+  mock_login_utils_->DelegateToFake();
+  mock_login_utils_->GetFakeLoginUtils()->set_should_launch_browser(
+      should_launch_browser_);
+  LoginUtils::Set(mock_login_utils_);
+}
+
+void LoginManagerTest::RegisterUser(const std::string& username) {
+  ListPrefUpdate users_pref(g_browser_process->local_state(), "LoggedInUsers");
+  users_pref->AppendIfNotPresent(new base::StringValue(username));
+}
+
+void LoginManagerTest::SetExpectedCredentials(const std::string& username,
+                                              const std::string& password) {
+  login_utils().GetFakeLoginUtils()->SetExpectedCredentials(username, password);
+}
+
+bool LoginManagerTest::TryToLogin(const std::string& username,
+                                  const std::string& password) {
+  ExistingUserController* controller =
+      ExistingUserController::current_controller();
+  EXPECT_TRUE(controller != NULL);
+  controller->Login(UserContext(username, password, std::string()));
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_SESSION_STARTED,
+      content::NotificationService::AllSources()).Wait();
+  if (const User* active_user = UserManager::Get()->GetActiveUser())
+    return active_user->email() == username;
+  return false;
+}
+
+void LoginManagerTest::LoginUser(const std::string& username) {
+  SetExpectedCredentials(username, "password");
+  EXPECT_TRUE(TryToLogin(username, "password"));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_manager_test.h b/chrome/browser/chromeos/login/login_manager_test.h
new file mode 100644
index 0000000..e88634f
--- /dev/null
+++ b/chrome/browser/chromeos/login/login_manager_test.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 CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_MANAGER_TEST_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_MANAGER_TEST_H_
+
+#include "chrome/browser/chromeos/login/mock_login_utils.h"
+#include "chrome/test/base/in_process_browser_test.h"
+
+namespace chromeos {
+
+class LoginManagerTest : public InProcessBrowserTest {
+ public:
+  explicit LoginManagerTest(bool should_launch_browser);
+
+  // Overriden from InProcessBrowserTest.
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
+
+  // Registers user with given |username| on device.
+  // Should be called in PRE_* test.
+  // TODO(dzhioev): add ability to register users without PRE_* test.
+  void RegisterUser(const std::string& username);
+
+  // Set expected credentials for next login attempt.
+  void SetExpectedCredentials(const std::string& username,
+                              const std::string& password);
+
+  // Tries to login with |username| and |password|. Returns false if attempt
+  // has failed.
+  bool TryToLogin(const std::string& username, const std::string& password);
+
+  // Login user with |username|. User should be registered using RegisterUser().
+  void LoginUser(const std::string& username);
+
+  MockLoginUtils& login_utils() { return *mock_login_utils_; }
+
+ private:
+  MockLoginUtils* mock_login_utils_;
+  bool should_launch_browser_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoginManagerTest);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_LOGIN_MANAGER_TEST_H_
diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc
index e09221a..2819ee6 100644
--- a/chrome/browser/chromeos/login/login_performer.cc
+++ b/chrome/browser/chromeos/login/login_performer.cc
@@ -201,7 +201,32 @@
     const UserContext& user_context) {
   DCHECK_EQ(UserManager::kLocallyManagedUserDomain,
             gaia::ExtractDomainName(user_context.username));
-  // TODO(nkostylev): Check that policy allows locally managed user login.
+
+  CrosSettings* cros_settings = CrosSettings::Get();
+  CrosSettingsProvider::TrustedStatus status =
+        cros_settings->PrepareTrustedValues(
+            base::Bind(&LoginPerformer::LoginAsLocallyManagedUser,
+                       weak_factory_.GetWeakPtr(),
+                       user_context_));
+  // Must not proceed without signature verification.
+  if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
+    if (delegate_)
+      delegate_->PolicyLoadFailed();
+    else
+      NOTREACHED();
+    return;
+  } else if (status != CrosSettingsProvider::TRUSTED) {
+    // Value of kAccountsPrefSupervisedUsersEnabled setting is still not
+    // verified. Another attempt will be invoked after verification completion.
+    return;
+  }
+
+  if (!UserManager::Get()->AreLocallyManagedUsersAllowed()) {
+    LOG(ERROR) << "Login attempt of locally managed user detected.";
+    delegate_->WhiteListCheckFailed(user_context.username);
+    return;
+  }
+
   UserFlow* new_flow = new LocallyManagedUserLoginFlow(user_context.username);
   new_flow->set_host(
       UserManager::Get()->GetUserFlow(user_context.username)->host());
diff --git a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
new file mode 100644
index 0000000..8467736
--- /dev/null
+++ b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
@@ -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.
+
+#include "base/command_line.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/cros_settings_names.h"
+#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
+#include "chrome/common/chrome_switches.h"
+#include "chromeos/chromeos_switches.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/mock_notification_observer.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace em = enterprise_management;
+
+namespace chromeos {
+
+class LoginScreenPolicyTest : public policy::DevicePolicyCrosBrowserTest {
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    command_line->AppendSwitch(switches::kLoginManager);
+    command_line->AppendSwitch(::switches::kEnableManagedUsers);
+  }
+
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
+    InstallOwnerKey();
+    MarkAsEnterpriseOwned();
+    DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture();
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, DisableSupervisedUsers) {
+  EXPECT_FALSE(chromeos::UserManager::Get()->AreLocallyManagedUsersAllowed());
+
+  content::WindowedNotificationObserver windowed_observer(
+       chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED,
+       content::NotificationService::AllSources());
+  chromeos::CrosSettings::Get()->AddSettingsObserver(
+      chromeos::kAccountsPrefSupervisedUsersEnabled, &windowed_observer);
+  em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
+  proto.mutable_supervised_users_settings()->set_supervised_users_enabled(true);
+  RefreshDevicePolicy();
+  windowed_observer.Wait();
+
+  EXPECT_TRUE(chromeos::UserManager::Get()->AreLocallyManagedUsersAllowed());
+
+  chromeos::CrosSettings::Get()->RemoveSettingsObserver(
+      chromeos::kAccountsPrefSupervisedUsersEnabled, &windowed_observer);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index f3c8e3e..cbcc973 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -349,7 +349,17 @@
     SetFirstLoginPrefs(user_profile->GetPrefs());
 
   if (UserManager::Get()->IsLoggedInAsLocallyManagedUser()) {
-    user_profile->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
+    User* active_user = UserManager::Get()->GetActiveUser();
+    std::string managed_user_sync_id =
+        UserManager::Get()->GetManagedUserSyncId(active_user->email());
+
+    // TODO(ibraaaa): Remove that when 97% of our users are using M31.
+    // http://crbug.com/276163
+    if (managed_user_sync_id.empty())
+      managed_user_sync_id = "DUMMY_ID";
+
+    user_profile->GetPrefs()->SetString(prefs::kManagedUserId,
+                                        managed_user_sync_id);
   } else {
     // Make sure that the google service username is properly set (we do this
     // on every sign in, not just the first login, to deal with existing
diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc
index 0b9d798..e10db7a 100644
--- a/chrome/browser/chromeos/login/login_utils_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc
@@ -17,7 +17,6 @@
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h"
 #include "chrome/browser/chromeos/login/authenticator.h"
@@ -272,16 +271,18 @@
     test_cros_settings_.reset(new ScopedTestCrosSettings);
     test_user_manager_.reset(new ScopedTestUserManager);
 
+    // IOThread creates ProxyConfigServiceImpl and
+    // BrowserPolicyConnector::Init() creates a NetworkConfigurationUpdater,
+    // which both access NetworkHandler. Thus initialize it here before creating
+    // IOThread and before calling BrowserPolicyConnector::Init().
+    NetworkHandler::Initialize();
+
     browser_process_->SetProfileManager(
         new ProfileManagerWithoutInit(scoped_temp_dir_.path()));
     connector_ = browser_process_->browser_policy_connector();
     connector_->Init(local_state_.Get(),
                      browser_process_->system_request_context());
 
-    // IOThread creates ProxyConfigServiceImpl which in turn needs
-    // NetworkHandler. Thus initialize it here before creating IOThread.
-    NetworkHandler::Initialize();
-
     io_thread_state_.reset(new IOThread(local_state_.Get(),
                                         browser_process_->policy_service(),
                                         NULL, NULL));
@@ -503,8 +504,6 @@
   }
 
  protected:
-  ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
-
   base::Closure fake_io_thread_work_;
   base::WaitableEvent fake_io_thread_completion_;
   base::Thread fake_io_thread_;
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
index 242a5a5..92a0c31 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.cc
@@ -97,18 +97,22 @@
   UserManager::Get()->StartLocallyManagedUserCreationTransaction(
       creation_context_->display_name);
 
-  std::string new_id = UserManager::Get()->GenerateUniqueLocallyManagedUserId();
+  creation_context_->local_user_id =
+        UserManager::Get()->GenerateUniqueLocallyManagedUserId();
+  creation_context_->sync_user_id =
+      ManagedUserRegistrationUtility::GenerateNewManagedUserId();
 
-  const User* user = UserManager::Get()->CreateLocallyManagedUserRecord(
-      creation_context_->manager_id, new_id, creation_context_->display_name);
-
-  creation_context_->user_id = user->email();
+  UserManager::Get()->CreateLocallyManagedUserRecord(
+      creation_context_->manager_id,
+      creation_context_->local_user_id,
+      creation_context_->sync_user_id,
+      creation_context_->display_name);
 
   UserManager::Get()->SetLocallyManagedUserCreationTransactionUserId(
-      creation_context_->user_id);
+      creation_context_->local_user_id);
   VLOG(1) << "Creating cryptohome";
   authenticator_ = new ManagedUserAuthenticator(this);
-  authenticator_->AuthenticateToCreate(user->email(),
+  authenticator_->AuthenticateToCreate(creation_context_->local_user_id,
                                        creation_context_->password);
 }
 
@@ -144,7 +148,7 @@
       reinterpret_cast<const void*>(master_key_bytes),
       sizeof(master_key_bytes)));
   VLOG(1) << "Adding master key";
-  authenticator_->AddMasterKey(creation_context_->user_id,
+  authenticator_->AddMasterKey(creation_context_->local_user_id,
                                creation_context_->password,
                                creation_context_->master_key);
 }
@@ -158,7 +162,7 @@
   ManagedUserRegistrationInfo info(creation_context_->display_name);
   info.master_key = creation_context_->master_key;
   creation_context_->registration_utility->Register(
-      ManagedUserRegistrationUtility::GenerateNewManagedUserId(),
+      creation_context_->sync_user_id,
       info,
       base::Bind(&LocallyManagedUserCreationController::RegistrationCallback,
                  weak_factory_.GetWeakPtr()));
@@ -194,7 +198,7 @@
 
 std::string LocallyManagedUserCreationController::GetManagedUserId() {
   DCHECK(creation_context_);
-  return creation_context_->user_id;
+  return creation_context_->local_user_id;
 }
 
 void LocallyManagedUserCreationController::TokenFetched(
@@ -221,6 +225,10 @@
       consumer_->OnCreationError(TOKEN_WRITE_FAILED);
     return;
   }
+  // Assume that new token is valid. It will be automatically invalidated if
+  // sync service fails to use it.
+  UserManager::Get()->SaveUserOAuthStatus(creation_context_->local_user_id,
+                                          User::OAUTH2_TOKEN_STATUS_VALID);
   UserManager::Get()->CommitLocallyManagedUserCreationTransaction();
   if (consumer_)
     consumer_->OnCreationSuccess();
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
index 3736544..f80fae7 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h
@@ -79,7 +79,8 @@
 
     string16 display_name;
     std::string manager_id;
-    std::string user_id;
+    std::string local_user_id; // Used to identify cryptohome.
+    std::string sync_user_id;  // Used to identify user in manager's sync data.
     std::string password;
     std::string mount_hash;
     std::string master_key;
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.cc b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.cc
index 5218544..cff2c37 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.cc
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.cc
@@ -32,6 +32,10 @@
 
 LocallyManagedUserCreationFlow::~LocallyManagedUserCreationFlow() {}
 
+bool LocallyManagedUserCreationFlow::ShouldShowSettings() {
+  return false;
+}
+
 bool LocallyManagedUserCreationFlow::ShouldLaunchBrowser() {
   return false;
 }
diff --git a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.h b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.h
index 4db9977..73e3f45 100644
--- a/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.h
+++ b/chrome/browser/chromeos/login/managed/locally_managed_user_creation_flow.h
@@ -20,6 +20,7 @@
   explicit LocallyManagedUserCreationFlow(const std::string& manager_id);
   virtual ~LocallyManagedUserCreationFlow();
 
+  virtual bool ShouldShowSettings() OVERRIDE;
   virtual bool ShouldLaunchBrowser() OVERRIDE;
   virtual bool ShouldSkipPostLoginScreens() OVERRIDE;
   virtual bool HandleLoginFailure(const LoginFailure& failure) OVERRIDE;
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 78fe1b1..04ab0f4 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
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h"
 
+#include "ash/desktop_background/desktop_background_controller.h"
+#include "ash/shell.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/camera_detector.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
@@ -179,6 +181,11 @@
 void LocallyManagedUserCreationScreen::OnManagerFullyAuthenticated(
     Profile* manager_profile) {
   DCHECK(controller_.get());
+  // For manager user, move desktop to locked container so that windows created
+  // during the user image picker step are below it.
+  ash::Shell::GetInstance()->
+      desktop_background_controller()->MoveDesktopToLockedContainer();
+
   controller_->SetManagerProfile(manager_profile);
   if (actor_)
     actor_->ShowUsernamePage();
diff --git a/chrome/browser/chromeos/login/merge_session_load_page_unittest.cc b/chrome/browser/chromeos/login/merge_session_load_page_unittest.cc
index eb651e0..9b85e81 100644
--- a/chrome/browser/chromeos/login/merge_session_load_page_unittest.cc
+++ b/chrome/browser/chromeos/login/merge_session_load_page_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/merge_session_load_page.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -81,7 +80,6 @@
   }
 
  private:
-  ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
   ScopedTestDeviceSettingsService test_device_settings_service_;
   ScopedTestCrosSettings test_cros_settings_;
   scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
diff --git a/chrome/browser/chromeos/login/mock_login_display_host.h b/chrome/browser/chromeos/login/mock_login_display_host.h
index 1a03afb..89ff5a1 100644
--- a/chrome/browser/chromeos/login/mock_login_display_host.h
+++ b/chrome/browser/chromeos/login/mock_login_display_host.h
@@ -42,6 +42,7 @@
   MOCK_METHOD0(ResumeSignInScreen, void(void));
   MOCK_METHOD0(OnPreferencesChanged, void(void));
   MOCK_METHOD0(PrewarmAuthentication, void(void));
+  MOCK_METHOD1(StartAppLaunch, void(const std::string&));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockLoginDisplayHost);
diff --git a/chrome/browser/chromeos/login/mock_user_manager.h b/chrome/browser/chromeos/login/mock_user_manager.h
index 0901f56..5fb3064 100644
--- a/chrome/browser/chromeos/login/mock_user_manager.h
+++ b/chrome/browser/chromeos/login/mock_user_manager.h
@@ -74,12 +74,13 @@
   MOCK_METHOD1(SetMergeSessionState, void(MergeSessionState));
   MOCK_METHOD2(SetUserFlow, void(const std::string&, UserFlow*));
   MOCK_METHOD1(ResetUserFlow, void(const std::string&));
-  MOCK_CONST_METHOD1(GetManagerForManagedUser, std::string(
-      const std::string& managed_user_id));
-  MOCK_METHOD3(CreateLocallyManagedUserRecord, const User*(
+  MOCK_METHOD4(CreateLocallyManagedUserRecord, const User*(
+      const std::string&,
       const std::string&,
       const std::string&,
       const string16&));
+  MOCK_CONST_METHOD1(GetManagedUserSyncId, std::string(
+      const std::string& managed_user_id));
   MOCK_CONST_METHOD1(GetManagerDisplayNameForManagedUser, string16(
       const std::string&));
   MOCK_CONST_METHOD1(GetManagerUserIdForManagedUser, std::string(
diff --git a/chrome/browser/chromeos/login/online_attempt_unittest.cc b/chrome/browser/chromeos/login/online_attempt_unittest.cc
index 24f6f17..b0ffec6 100644
--- a/chrome/browser/chromeos/login/online_attempt_unittest.cc
+++ b/chrome/browser/chromeos/login/online_attempt_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/auth_attempt_state.h"
 #include "chrome/browser/chromeos/login/mock_auth_attempt_state_resolver.h"
 #include "chrome/browser/chromeos/login/mock_url_fetchers.h"
@@ -64,9 +63,6 @@
   TestAttemptState state_;
   MockAuthAttemptStateResolver resolver_;
   scoped_ptr<OnlineAttempt> attempt_;
-
-  // Initializes / shuts down a stub NetworkLibrary.
-  ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
 };
 
 TEST_F(OnlineAttemptTest, LoginSuccess) {
diff --git a/chrome/browser/chromeos/login/oobe_browsertest.cc b/chrome/browser/chromeos/login/oobe_browsertest.cc
index b07497d..ea19642 100644
--- a/chrome/browser/chromeos/login/oobe_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_browsertest.cc
@@ -8,7 +8,6 @@
 #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/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/chromeos/login/webui_login_display.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
@@ -128,7 +127,7 @@
 
 const base::FilePath kServiceLogin("chromeos/service_login.html");
 
-class OobeTest : public chromeos::CrosInProcessBrowserTest {
+class OobeTest : public InProcessBrowserTest {
  protected:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     command_line->AppendSwitch(chromeos::switches::kLoginManager);
diff --git a/chrome/browser/chromeos/login/oobe_display.h b/chrome/browser/chromeos/login/oobe_display.h
index b1f5485..c0f7942 100644
--- a/chrome/browser/chromeos/login/oobe_display.h
+++ b/chrome/browser/chromeos/login/oobe_display.h
@@ -12,6 +12,7 @@
 
 namespace chromeos {
 
+class AppLaunchSplashScreenActor;
 class EnrollmentScreenActor;
 class ErrorScreenActor;
 class EulaScreenActor;
@@ -49,6 +50,7 @@
     SCREEN_CREATE_MANAGED_USER_FLOW,
     SCREEN_TERMS_OF_SERVICE,
     SCREEN_WRONG_HWID,
+    SCREEN_APP_LAUNCH_SPLASH,
     SCREEN_UNKNOWN
   };
 
@@ -75,6 +77,7 @@
   virtual WrongHWIDScreenActor* GetWrongHWIDScreenActor() = 0;
   virtual LocallyManagedUserCreationScreenHandler*
       GetLocallyManagedUserCreationScreenActor() = 0;
+  virtual AppLaunchSplashScreenActor* GetAppLaunchSplashScreenActor() = 0;
 
   // Returns if JS side is fully loaded and ready to accept messages.
   // If |false| is returned, then |display_is_ready_callback| is stored
diff --git a/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc b/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc
index 9875995..7569a9d 100644
--- a/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc
+++ b/chrome/browser/chromeos/login/parallel_authenticator_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
 #include "chrome/browser/chromeos/login/mock_url_fetchers.h"
 #include "chrome/browser/chromeos/login/mock_user_manager.h"
@@ -194,7 +193,6 @@
   std::string username_hash_;
   std::string hash_ascii_;
 
-  ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
   ScopedDeviceSettingsTestHelper device_settings_test_helper_;
   ScopedTestCrosSettings test_cros_settings_;
 
diff --git a/chrome/browser/chromeos/login/screen_locker_browsertest.cc b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
index ad5ee63..87b5aeb 100644
--- a/chrome/browser/chromeos/login/screen_locker_browsertest.cc
+++ b/chrome/browser/chromeos/login/screen_locker_browsertest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/chromeos/login/screen_locker.h"
+
 #include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/mock_authenticator.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"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/fake_session_manager_client.h"
@@ -88,7 +89,7 @@
 
 namespace chromeos {
 
-class ScreenLockerTest : public CrosInProcessBrowserTest {
+class ScreenLockerTest : public InProcessBrowserTest {
  public:
   ScreenLockerTest() : fake_session_manager_client_(NULL) {
   }
@@ -118,7 +119,7 @@
     MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
         new MockDBusThreadManagerWithoutGMock;
     DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
-    CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
     fake_session_manager_client_ =
         mock_dbus_thread_manager->fake_session_manager_client();
     zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode(
diff --git a/chrome/browser/chromeos/login/screen_locker_delegate.h b/chrome/browser/chromeos/login/screen_locker_delegate.h
index a7b91d9..589f042 100644
--- a/chrome/browser/chromeos/login/screen_locker_delegate.h
+++ b/chrome/browser/chromeos/login/screen_locker_delegate.h
@@ -60,6 +60,12 @@
   // there isn't one.
   virtual content::WebUI* GetAssociatedWebUI();
 
+  // Called when webui lock screen is ready.
+  virtual void OnLockWebUIReady() = 0;
+
+  // Called when webui lock screen wallpaper is loaded and displayed.
+  virtual void OnLockBackgroundDisplayed() = 0;
+
   // Returns screen locker associated with delegate.
   ScreenLocker* screen_locker() { return screen_locker_; }
 
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
new file mode 100644
index 0000000..234ce71
--- /dev/null
+++ b/chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.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 CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_APP_LAUNCH_SPLASH_SCREEN_ACTOR_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_APP_LAUNCH_SPLASH_SCREEN_ACTOR_H_
+
+#include "base/strings/string16.h"
+
+namespace chromeos {
+
+// Interface for UI implemenations of the ApplaunchSplashScreen.
+class AppLaunchSplashScreenActor {
+ public:
+  enum AppLaunchState {
+    APP_LAUNCH_STATE_LOADING_AUTH_FILE,
+    APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE,
+    APP_LAUNCH_STATE_PREPARING_NETWORK,
+    APP_LAUNCH_STATE_INSTALLING_APPLICATION,
+  };
+
+  class Delegate {
+   public:
+    virtual void OnConfigureNetwork() = 0;
+    virtual void OnCancelAppLaunch() = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
+  virtual ~AppLaunchSplashScreenActor() {}
+
+  // Sets screen this actor belongs to.
+  virtual void SetDelegate(Delegate* screen) = 0;
+
+  // Prepare the contents to showing.
+  virtual void PrepareToShow() = 0;
+
+  // Shows the contents of the screen.
+  virtual void Show(const std::string& app_id) = 0;
+
+  // Hides the contents of the screen.
+  virtual void Hide() = 0;
+
+  // Set the current app launch state.
+  virtual void UpdateAppLaunchState(AppLaunchState state) = 0;
+
+  // Sets whether continue control is enabled.
+  virtual void ToggleNetworkConfig(bool visible) = 0;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_APP_LAUNCH_SPLASH_SCREEN_ACTOR_H_
diff --git a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
index 92b94bf..7c88c21 100644
--- a/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/network_screen_browsertest.cc
@@ -78,7 +78,7 @@
   }
 
   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
-    CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
+    InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
     DBusThreadManager::Shutdown();
   }
 
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.cc b/chrome/browser/chromeos/login/screens/user_image_screen.cc
index 9542be3..a245be3 100644
--- a/chrome/browser/chromeos/login/screens/user_image_screen.cc
+++ b/chrome/browser/chromeos/login/screens/user_image_screen.cc
@@ -6,6 +6,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/metrics/histogram.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/camera_detector.h"
@@ -36,6 +37,10 @@
 // Time histogram suffix for profile image download.
 const char kProfileDownloadReason[] = "OOBE";
 
+// Maximum ammount of time to wait for the user image to sync.
+// The screen is shown iff sync failed or time limit exceeded.
+const int kSyncTimeoutSeconds = 10;
+
 }  // namespace
 
 UserImageScreen::UserImageScreen(ScreenObserver* screen_observer,
@@ -47,9 +52,13 @@
       selected_image_(User::kInvalidImageIndex),
       profile_picture_enabled_(false),
       profile_picture_data_url_(content::kAboutBlankURL),
-      profile_picture_absent_(false) {
+      profile_picture_absent_(false),
+      is_screen_ready_(false),
+      user_has_selected_image_(false) {
   actor_->SetDelegate(this);
   SetProfilePictureEnabled(true);
+  registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
+      content::NotificationService::AllSources());
 }
 
 UserImageScreen::~UserImageScreen() {
@@ -59,6 +68,24 @@
     image_decoder_->set_delegate(NULL);
 }
 
+void UserImageScreen::OnScreenReady() {
+  is_screen_ready_ = true;
+  if (actor_ && !IsWaitingForSync())
+    actor_->HideCurtain();
+}
+
+void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  user_photo_ = gfx::ImageSkia();
+  if (image_decoder_.get())
+    image_decoder_->set_delegate(NULL);
+  image_decoder_ = new ImageDecoder(this, raw_data,
+                                    ImageDecoder::DEFAULT_CODEC);
+  scoped_refptr<base::MessageLoopProxy> task_runner =
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
+  image_decoder_->Start(task_runner);
+}
+
 void UserImageScreen::CheckCameraPresence() {
   CameraDetector::StartPresenceCheck(
       base::Bind(&UserImageScreen::OnCameraPresenceCheckDone,
@@ -72,17 +99,6 @@
   }
 }
 
-void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  user_photo_ = gfx::ImageSkia();
-  if (image_decoder_.get())
-    image_decoder_->set_delegate(NULL);
-  image_decoder_ = new ImageDecoder(this, raw_data,
-                                    ImageDecoder::DEFAULT_CODEC);
-  scoped_refptr<base::MessageLoopProxy> task_runner =
-      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
-  image_decoder_->Start(task_runner);
-}
 
 void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder,
                                      const SkBitmap& decoded_image) {
@@ -96,8 +112,38 @@
   NOTREACHED() << "Failed to decode PNG image from WebUI";
 }
 
+void UserImageScreen::OnInitialSync(bool local_image_updated) {
+  DCHECK(sync_timer_.get());
+  sync_timer_->Stop();
+  sync_timer_.reset();
+  UserManager::Get()->GetUserImageManager()->GetSyncObserver()->
+      RemoveObserver(this);
+  if (!local_image_updated) {
+    if (is_screen_ready_ && actor_)
+      actor_->HideCurtain();
+    return;
+  }
+  get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
+}
+
+void UserImageScreen::OnSyncTimeout() {
+  sync_timer_.reset();
+  UserManager::Get()->GetUserImageManager()->GetSyncObserver()->
+      RemoveObserver(this);
+  if (is_screen_ready_ && actor_)
+    actor_->HideCurtain();
+}
+
+bool UserImageScreen::IsWaitingForSync() const {
+  return sync_timer_.get() && sync_timer_->IsRunning();
+}
+
 void UserImageScreen::OnImageSelected(const std::string& image_type,
-                                      const std::string& image_url) {
+                                      const std::string& image_url,
+                                      bool is_user_selection) {
+  if (is_user_selection) {
+    user_has_selected_image_ = true;
+  }
   if (image_url.empty())
     return;
   int user_image_index = User::kInvalidImageIndex;
@@ -139,9 +185,11 @@
       uma_index = GetDefaultImageHistogramValue(selected_image_);
       break;
   }
-  UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
-                            uma_index,
-                            kHistogramImagesCount);
+  if (user_has_selected_image_) {
+    UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
+                              uma_index,
+                              kHistogramImagesCount);
+  }
   get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
 }
 
@@ -186,7 +234,23 @@
 void UserImageScreen::Show() {
   if (!actor_)
     return;
-
+  if (GetUser()->CanSyncImage()) {
+    if (UserImageSyncObserver* sync_observer =
+          UserManager::Get()->GetUserImageManager()->GetSyncObserver()) {
+      // We have synced image already.
+      if (sync_observer->is_synced()) {
+        get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
+        return;
+      }
+      sync_observer->AddObserver(this);
+      sync_timer_.reset(new base::Timer(
+            FROM_HERE,
+            base::TimeDelta::FromSeconds(kSyncTimeoutSeconds),
+            base::Bind(&UserImageScreen::OnSyncTimeout, base::Unretained(this)),
+            false));
+      sync_timer_->Reset();
+    }
+  }
   actor_->Show();
   actor_->SetProfilePictureEnabled(profile_picture_enabled_);
 
@@ -237,6 +301,11 @@
         actor_->OnProfileImageAbsent();
       break;
     }
+    case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
+      if (actor_)
+        actor_->SelectImage(GetUser()->image_index());
+      break;
+    }
     default:
       NOTREACHED();
   }
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen.h b/chrome/browser/chromeos/login/screens/user_image_screen.h
index 28c61df..21780cc 100644
--- a/chrome/browser/chromeos/login/screens/user_image_screen.h
+++ b/chrome/browser/chromeos/login/screens/user_image_screen.h
@@ -10,16 +10,22 @@
 #include "chrome/browser/chromeos/login/screens/user_image_screen_actor.h"
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_image_sync_observer.h"
 #include "chrome/browser/image_decoder.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
+namespace base {
+class Timer;
+};
+
 namespace chromeos {
 
 class UserImageScreen: public WizardScreen,
                        public UserImageScreenActor::Delegate,
                        public ImageDecoder::Delegate,
-                       public content::NotificationObserver {
+                       public content::NotificationObserver,
+                       public UserImageSyncObserver::Observer {
  public:
   UserImageScreen(ScreenObserver* screen_observer,
                   UserImageScreenActor* actor);
@@ -37,10 +43,12 @@
   virtual std::string GetName() const OVERRIDE;
 
   // UserImageScreenActor::Delegate implementation:
-  virtual void CheckCameraPresence() OVERRIDE;
+  virtual void OnScreenReady() OVERRIDE;
   virtual void OnPhotoTaken(const std::string& raw_data) OVERRIDE;
+  virtual void CheckCameraPresence() OVERRIDE;
   virtual void OnImageSelected(const std::string& image_url,
-                               const std::string& image_type) OVERRIDE;
+                               const std::string& image_type,
+                               bool is_user_selection) OVERRIDE;
   virtual void OnImageAccepted() OVERRIDE;
   virtual void OnActorDestroyed(UserImageScreenActor* actor) OVERRIDE;
 
@@ -53,12 +61,22 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
-  // Overriden from ImageDecoder::Delegate:
+  // ImageDecoder::Delegate implementation:
   virtual void OnImageDecoded(const ImageDecoder* decoder,
                               const SkBitmap& decoded_image) OVERRIDE;
   virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE;
 
+  // UserImageSyncObserver::Observer implementation:
+  virtual void OnInitialSync(bool local_image_updated) OVERRIDE;
+
+  bool user_selected_image() const { return user_has_selected_image_; }
+
  private:
+  // Called when whaiting for sync timed out.
+  void OnSyncTimeout();
+
+  bool IsWaitingForSync() const;
+
   const User* GetUser();
 
   // Called when the camera presence check has been completed.
@@ -95,6 +113,15 @@
 
   std::string user_id_;
 
+  // Timer used for waiting for user image sync.
+  scoped_ptr<base::Timer> sync_timer_;
+
+  // If screen ready to be shown.
+  bool is_screen_ready_;
+
+  // True if user has explicitly selected some image.
+  bool user_has_selected_image_;
+
   DISALLOW_COPY_AND_ASSIGN(UserImageScreen);
 };
 
diff --git a/chrome/browser/chromeos/login/screens/user_image_screen_actor.h b/chrome/browser/chromeos/login/screens/user_image_screen_actor.h
index 8f99e98..5e5d073 100644
--- a/chrome/browser/chromeos/login/screens/user_image_screen_actor.h
+++ b/chrome/browser/chromeos/login/screens/user_image_screen_actor.h
@@ -23,13 +23,17 @@
    public:
     virtual ~Delegate() {}
 
+    // Called when UI ready to be shown.
+    virtual void OnScreenReady() = 0;
     // Called when user accepts photo as login user image.
     virtual void OnPhotoTaken(const std::string& raw_data) = 0;
     // Called to check camera presence.
     virtual void CheckCameraPresence() = 0;
-    // Called when user selects some image
+    // Called when some image was selected. |is_user_selection| indicates if
+    // it was user selection or image was selected programmatically.
     virtual void OnImageSelected(const std::string& image_url,
-                                 const std::string& image_type) = 0;
+                                 const std::string& image_type,
+                                 bool is_user_selection) = 0;
     // Called when user accepts currently selected image
     virtual void OnImageAccepted() = 0;
 
@@ -70,6 +74,9 @@
 
   // Sends result of camera check
   virtual void SetCameraPresent(bool enabled) = 0;
+
+  // Hides curtain with spinner.
+  virtual void HideCurtain() = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session_login_browsertest.cc b/chrome/browser/chromeos/login/session_login_browsertest.cc
new file mode 100644
index 0000000..77ccc7b
--- /dev/null
+++ b/chrome/browser/chromeos/login/session_login_browsertest.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/chromeos/login/login_manager_test.h"
+#include "chrome/browser/chromeos/login/startup_utils.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/view_ids.h"
+#include "chrome/common/chrome_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/view.h"
+
+namespace chromeos {
+
+namespace {
+
+const char kTestUser[] = "test-user@gmail.com";
+
+}  // anonymous namespace
+
+class BrowserLoginTest : public chromeos::LoginManagerTest {
+ public:
+  BrowserLoginTest() : LoginManagerTest(true) {}
+  virtual ~BrowserLoginTest() {}
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    LoginManagerTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(::switches::kCreateBrowserOnStartupForTests);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserLoginTest, PRE_BrowserActive) {
+  RegisterUser(kTestUser);
+  chromeos::StartupUtils::MarkOobeCompleted();
+}
+
+IN_PROC_BROWSER_TEST_F(BrowserLoginTest, BrowserActive) {
+  LoginUser(kTestUser);
+  Browser* browser = FindAnyBrowser(ProfileManager::GetDefaultProfile(),
+                                    false,
+                                    chrome::HOST_DESKTOP_TYPE_ASH);
+  EXPECT_TRUE(browser != NULL);
+  EXPECT_TRUE(browser->window()->IsActive());
+
+  views::FocusManager* focus_manager = browser->window()->
+      GetBrowserWindowTesting()->GetTabContentsContainerView()->
+          GetFocusManager();
+  EXPECT_TRUE(focus_manager != NULL);
+
+  const views::View* focused_view = focus_manager->GetFocusedView();
+  EXPECT_TRUE(focused_view != NULL);
+  EXPECT_EQ(VIEW_ID_OMNIBOX, focused_view->id());
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/simple_web_view_dialog.cc b/chrome/browser/chromeos/login/simple_web_view_dialog.cc
index 02596e4..0640ddd 100644
--- a/chrome/browser/chromeos/login/simple_web_view_dialog.cc
+++ b/chrome/browser/chromeos/login/simple_web_view_dialog.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
 #include "chrome/browser/ui/views/reload_button.h"
-#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/web_contents.h"
@@ -38,7 +37,6 @@
 
 using content::WebContents;
 using views::GridLayout;
-using web_modal::WebContentsModalDialogManager;
 
 namespace {
 
@@ -156,14 +154,11 @@
   PasswordManagerDelegateImpl::CreateForWebContents(web_contents);
   PasswordManager::CreateForWebContentsAndDelegate(
       web_contents, PasswordManagerDelegateImpl::FromWebContents(web_contents));
-
-  // LoginHandlerViews uses a constrained window for the password manager view.
-  WebContentsModalDialogManager::CreateForWebContents(web_contents);
-  WebContentsModalDialogManager::FromWebContents(web_contents)->
-      set_delegate(this);
 }
 
 void SimpleWebViewDialog::Init() {
+  toolbar_model_.reset(new ToolbarModelImpl(this));
+
   set_background(views::Background::CreateSolidBackground(SK_ColorWHITE));
 
   // Back/Forward buttons.
@@ -185,11 +180,9 @@
   forward_->SetAccessibleName(l10n_util::GetStringUTF16(IDS_ACCNAME_FORWARD));
   forward_->set_id(VIEW_ID_FORWARD_BUTTON);
 
-  toolbar_model_.reset(new ToolbarModelImpl(this));
-
   // Location bar.
   location_bar_ = new LocationBarView(NULL, profile_, command_updater_.get(),
-                                      toolbar_model_.get(), this, true);
+                                      this, true);
 
   // Reload button.
   reload_ = new ReloadButton(location_bar_, command_updater_.get());
@@ -238,10 +231,6 @@
 
 void SimpleWebViewDialog::Layout() {
   views::WidgetDelegateView::Layout();
-
-  FOR_EACH_OBSERVER(web_modal::WebContentsModalDialogHostObserver,
-                    observer_list_,
-                    OnPositionRequiresUpdate());
 }
 
 views::View* SimpleWebViewDialog::GetContentsView() {
@@ -278,10 +267,18 @@
   command_updater_->UpdateCommandEnabled(IDC_STOP, is_loading);
 }
 
-WebContents* SimpleWebViewDialog::GetWebContents() const {
+WebContents* SimpleWebViewDialog::GetWebContents() {
   return NULL;
 }
 
+ToolbarModel* SimpleWebViewDialog::GetToolbarModel() {
+  return toolbar_model_.get();
+}
+
+const ToolbarModel* SimpleWebViewDialog::GetToolbarModel() const {
+  return toolbar_model_.get();
+}
+
 InstantController* SimpleWebViewDialog::GetInstant() {
   return NULL;
 }
@@ -351,33 +348,6 @@
   }
 }
 
-web_modal::WebContentsModalDialogHost*
-    SimpleWebViewDialog::GetWebContentsModalDialogHost() {
-  return this;
-}
-
-gfx::NativeView SimpleWebViewDialog::GetHostView() const {
-  return GetWidget()->GetNativeView();
-}
-
-gfx::Point SimpleWebViewDialog::GetDialogPosition(const gfx::Size& size) {
-  // Center the widget.
-  gfx::Size widget_size = GetWidget()->GetWindowBoundsInScreen().size();
-  return gfx::Point(widget_size.width() / 2 - size.width() / 2,
-                    widget_size.height() / 2 - size.height() / 2);
-}
-
-void SimpleWebViewDialog::AddObserver(
-    web_modal::WebContentsModalDialogHostObserver* observer) {
-  if (observer && !observer_list_.HasObserver(observer))
-    observer_list_.AddObserver(observer);
-}
-
-void SimpleWebViewDialog::RemoveObserver(
-    web_modal::WebContentsModalDialogHostObserver* observer) {
-  observer_list_.RemoveObserver(observer);
-}
-
 void SimpleWebViewDialog::LoadImages() {
   ui::ThemeProvider* tp = GetThemeProvider();
 
diff --git a/chrome/browser/chromeos/login/simple_web_view_dialog.h b/chrome/browser/chromeos/login/simple_web_view_dialog.h
index cc867c5..8d7db38 100644
--- a/chrome/browser/chromeos/login/simple_web_view_dialog.h
+++ b/chrome/browser/chromeos/login/simple_web_view_dialog.h
@@ -7,12 +7,9 @@
 
 #include <string>
 #include "base/memory/scoped_ptr.h"
-#include "base/observer_list.h"
 #include "chrome/browser/command_updater_delegate.h"
-#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
 #include "chrome/browser/ui/toolbar/toolbar_model_delegate.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
-#include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "ui/views/controls/button/image_button.h"
@@ -44,9 +41,7 @@
                             public ToolbarModelDelegate,
                             public CommandUpdaterDelegate,
                             public content::PageNavigator,
-                            public content::WebContentsDelegate,
-                            public ChromeWebModalDialogManagerDelegate,
-                            public web_modal::WebContentsModalDialogHost {
+                            public content::WebContentsDelegate {
  public:
   explicit SimpleWebViewDialog(Profile* profile);
   virtual ~SimpleWebViewDialog();
@@ -78,7 +73,9 @@
   // Implements LocationBarView::Delegate:
   virtual void NavigationStateChanged(const content::WebContents* source,
                                       unsigned changed_flags) OVERRIDE;
-  virtual content::WebContents* GetWebContents() const OVERRIDE;
+  virtual content::WebContents* GetWebContents() OVERRIDE;
+  virtual ToolbarModel* GetToolbarModel() OVERRIDE;
+  virtual const ToolbarModel* GetToolbarModel() const OVERRIDE;
   virtual InstantController* GetInstant() OVERRIDE;
   virtual views::Widget* CreateViewsBubble(
       views::BubbleDelegateView* bubble_delegate) OVERRIDE;
@@ -100,18 +97,6 @@
       int id,
       WindowOpenDisposition) OVERRIDE;
 
-  // Implements ChromeWebModalDialogManagerDelegate:
-  virtual web_modal::WebContentsModalDialogHost*
-      GetWebContentsModalDialogHost() OVERRIDE;
-
-  // Implements web_modal::WebContentsModalDialogHost:
-  virtual gfx::NativeView GetHostView() const OVERRIDE;
-  virtual gfx::Point GetDialogPosition(const gfx::Size& size) OVERRIDE;
-  virtual void AddObserver(
-      web_modal::WebContentsModalDialogHostObserver* observer) OVERRIDE;
-  virtual void RemoveObserver(
-      web_modal::WebContentsModalDialogHostObserver* observer) OVERRIDE;
-
  private:
   void LoadImages();
   void UpdateButtons();
@@ -133,8 +118,6 @@
 
   scoped_ptr<StubBubbleModelDelegate> bubble_model_delegate_;
 
-  ObserverList<web_modal::WebContentsModalDialogHostObserver> observer_list_;
-
   DISALLOW_COPY_AND_ASSIGN(SimpleWebViewDialog);
 };
 
diff --git a/chrome/browser/chromeos/login/startup_utils.cc b/chrome/browser/chromeos/login/startup_utils.cc
index 73fd8a6..7977d0e 100644
--- a/chrome/browser/chromeos/login/startup_utils.cc
+++ b/chrome/browser/chromeos/login/startup_utils.cc
@@ -7,10 +7,12 @@
 #include "base/bind.h"
 #include "base/chromeos/chromeos_version.h"
 #include "base/file_util.h"
+#include "base/path_service.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -88,7 +90,7 @@
 // Returns the path to flag file indicating that both parts of OOBE were
 // completed.
 // On chrome device, returns /home/chronos/.oobe_completed.
-// On Linux desktop, returns $HOME/.oobe_completed.
+// On Linux desktop, returns {DIR_USER_DATA}/.oobe_completed.
 static base::FilePath GetOobeCompleteFlagPath() {
   // The constant is defined here so it won't be referenced directly.
   const char kOobeCompleteFlagFilePath[] = "/home/chronos/.oobe_completed";
@@ -96,11 +98,9 @@
   if (base::chromeos::IsRunningOnChromeOS()) {
     return base::FilePath(kOobeCompleteFlagFilePath);
   } else {
-    const char* home = getenv("HOME");
-    // Unlikely but if HOME is not defined, use the current directory.
-    if (!home)
-      home = "";
-    return base::FilePath(home).AppendASCII(".oobe_completed");
+    base::FilePath user_data_dir;
+    PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+    return user_data_dir.AppendASCII(".oobe_completed");
   }
 }
 
diff --git a/chrome/browser/chromeos/login/user.cc b/chrome/browser/chromeos/login/user.cc
index 5e47a5a..ffe6c47 100644
--- a/chrome/browser/chromeos/login/user.cc
+++ b/chrome/browser/chromeos/login/user.cc
@@ -34,6 +34,7 @@
 
   // Overridden from User:
   virtual UserType GetType() const OVERRIDE;
+  virtual bool CanSyncImage() const OVERRIDE;
   virtual bool can_lock() const OVERRIDE;
 
  private:
@@ -151,6 +152,10 @@
   return image_index_ >= 0 && image_index_ < kDefaultImagesCount;
 }
 
+bool User::CanSyncImage() const {
+  return false;
+}
+
 std::string User::display_email() const {
   return display_email_;
 }
@@ -238,6 +243,10 @@
   return USER_TYPE_REGULAR;
 }
 
+bool RegularUser::CanSyncImage() const {
+  return true;
+}
+
 bool RegularUser::can_lock() const {
   return true;
 }
diff --git a/chrome/browser/chromeos/login/user.h b/chrome/browser/chromeos/login/user.h
index 35911bb..4465aab 100644
--- a/chrome/browser/chromeos/login/user.h
+++ b/chrome/browser/chromeos/login/user.h
@@ -112,6 +112,9 @@
   // Whether the user has a default image.
   bool HasDefaultImage() const;
 
+  // True if user image can be synced.
+  virtual bool CanSyncImage() const;
+
   int image_index() const { return image_index_; }
   bool has_raw_image() const { return user_image_.has_raw_image(); }
   // Returns raw representation of static user image.
diff --git a/chrome/browser/chromeos/login/user_adding_screen_browsertest.cc b/chrome/browser/chromeos/login/user_adding_screen_browsertest.cc
index 40726a9..91b6c3e 100644
--- a/chrome/browser/chromeos/login/user_adding_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/user_adding_screen_browsertest.cc
@@ -2,16 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
-#include "chrome/browser/chromeos/login/mock_login_utils.h"
+#include "chrome/browser/chromeos/login/login_manager_test.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/user_adding_screen.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 "chromeos/chromeos_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -27,66 +24,35 @@
 
 namespace chromeos {
 
-class UserAddingScreenTest : public CrosInProcessBrowserTest,
+class UserAddingScreenTest : public LoginManagerTest,
                              public UserAddingScreen::Observer {
  public:
-  UserAddingScreenTest() : user_adding_started_(0), user_adding_finished_(0) {
-    set_exit_when_last_browser_closes(false);
+  UserAddingScreenTest() : LoginManagerTest(false),
+                           user_adding_started_(0),
+                           user_adding_finished_(0) {
   }
 
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    LoginManagerTest::SetUpCommandLine(command_line);
     command_line->AppendSwitch(::switches::kMultiProfiles);
-    command_line->AppendSwitch(chromeos::switches::kLoginManager);
-    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
   }
 
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
+    LoginManagerTest::SetUpInProcessBrowserTestFixture();
     UserAddingScreen::Get()->AddObserver(this);
-    mock_login_utils_ = new NiceMock<MockLoginUtils>();
-    mock_login_utils_->DelegateToFake();
-    LoginUtils::Set(mock_login_utils_);
   }
 
   virtual void OnUserAddingFinished() OVERRIDE { ++user_adding_finished_; }
 
   virtual void OnUserAddingStarted() OVERRIDE { ++user_adding_started_; }
 
-  void RegisterUser(const std::string& username) {
-    ListPrefUpdate users_pref(g_browser_process->local_state(),
-                              "LoggedInUsers");
-    users_pref->AppendIfNotPresent(new base::StringValue(username));
-  }
-
-  void SetExpectedCredentials(const std::string& username,
-                              const std::string& password) {
-    mock_login_utils_->GetFakeLoginUtils()->
-        SetExpectedCredentials(username, password);
-  }
-
-  bool TryToLogin(const std::string& username, const std::string& password) {
-    ExistingUserController* controller =
-        ExistingUserController::current_controller();
-    EXPECT_TRUE(controller != NULL);
-    controller->Login(UserContext(username, password, ""));
-    content::RunAllPendingInMessageLoop();
-    return UserManager::Get()->GetActiveUser()->email() == username;
-  }
-
-  void LoginUser(const std::string& username) {
-    SetExpectedCredentials(username, "password");
-    EXPECT_TRUE(TryToLogin(username, "password"));
-  }
-
   int user_adding_started() { return user_adding_started_; }
 
   int user_adding_finished() { return user_adding_finished_; }
 
-  MockLoginUtils& login_utils() { return *mock_login_utils_; }
-
  private:
   int user_adding_started_;
   int user_adding_finished_;
-  MockLoginUtils* mock_login_utils_;
 
   DISALLOW_COPY_AND_ASSIGN(UserAddingScreenTest);
 };
diff --git a/chrome/browser/chromeos/login/user_flow.cc b/chrome/browser/chromeos/login/user_flow.cc
index 2f01ea5..038d61d 100644
--- a/chrome/browser/chromeos/login/user_flow.cc
+++ b/chrome/browser/chromeos/login/user_flow.cc
@@ -24,6 +24,10 @@
 
 DefaultUserFlow::~DefaultUserFlow() {}
 
+bool DefaultUserFlow::ShouldShowSettings() {
+  return true;
+}
+
 bool DefaultUserFlow::ShouldLaunchBrowser() {
   return true;
 }
@@ -54,6 +58,10 @@
 ExtendedUserFlow::~ExtendedUserFlow() {
 }
 
+bool ExtendedUserFlow::ShouldShowSettings() {
+  return true;
+}
+
 void ExtendedUserFlow::UnregisterFlowSoon() {
   std::string id_copy(user_id());
   base::MessageLoop::current()->PostTask(FROM_HERE,
diff --git a/chrome/browser/chromeos/login/user_flow.h b/chrome/browser/chromeos/login/user_flow.h
index 9132e4a..cfb64b0 100644
--- a/chrome/browser/chromeos/login/user_flow.h
+++ b/chrome/browser/chromeos/login/user_flow.h
@@ -19,6 +19,7 @@
  public:
   UserFlow();
   virtual ~UserFlow() = 0;
+  virtual bool ShouldShowSettings() = 0;
   virtual bool ShouldLaunchBrowser() = 0;
   virtual bool ShouldSkipPostLoginScreens() = 0;
   virtual bool HandleLoginFailure(const LoginFailure& failure) = 0;
@@ -43,6 +44,7 @@
  public:
   virtual ~DefaultUserFlow();
 
+  virtual bool ShouldShowSettings() OVERRIDE;
   virtual bool ShouldLaunchBrowser() OVERRIDE;
   virtual bool ShouldSkipPostLoginScreens() OVERRIDE;
   virtual bool HandleLoginFailure(const LoginFailure& failure) OVERRIDE;
@@ -58,6 +60,8 @@
   explicit ExtendedUserFlow(const std::string& user_id);
   virtual ~ExtendedUserFlow();
 
+  virtual bool ShouldShowSettings() OVERRIDE;
+
  protected:
   // Subclasses can call this method to unregister flow in the next event.
   virtual void UnregisterFlowSoon();
diff --git a/chrome/browser/chromeos/login/user_image_manager.h b/chrome/browser/chromeos/login/user_image_manager.h
index eeec8a0..383fafe 100644
--- a/chrome/browser/chromeos/login/user_image_manager.h
+++ b/chrome/browser/chromeos/login/user_image_manager.h
@@ -22,6 +22,7 @@
 namespace chromeos {
 
 class UserImage;
+class UserImageSyncObserver;
 
 // Base class that provides a mechanism for updating user images.
 class UserImageManager {
@@ -74,6 +75,13 @@
   // Returns the result of the last successful profile image download, if any.
   // Otherwise, returns an empty bitmap.
   virtual const gfx::ImageSkia& DownloadedProfileImage() const = 0;
+
+  // Returns sync observer attached to current user. Returns NULL if current
+  // user can't sync images or user is not logged in.
+  virtual UserImageSyncObserver* GetSyncObserver() const = 0;
+
+  // Unregisters preference observers before browser process shutdown.
+  virtual void Shutdown() = 0;
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
index 19eb7a5..f89e905 100644
--- a/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_browsertest.cc
@@ -11,7 +11,6 @@
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.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"
@@ -19,6 +18,7 @@
 #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"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chromeos/chromeos_switches.h"
 #include "content/public/browser/notification_observer.h"
@@ -34,14 +34,14 @@
 const char kTestUser1[] = "test-user@example.com";
 const char kTestUser2[] = "test-user2@example.com";
 
-class UserImageManagerTest : public CrosInProcessBrowserTest,
+class UserImageManagerTest : public InProcessBrowserTest,
                              public content::NotificationObserver,
                              public UserManager::Observer {
  protected:
   UserImageManagerTest() {
   }
 
-  // CrosInProcessBrowserTest overrides:
+  // InProcessBrowserTest overrides:
   virtual void SetUpOnMainThread() OVERRIDE {
     UserManager::Get()->AddObserver(this);
     user_image_manager_ = UserManager::Get()->GetUserImageManager();
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.cc b/chrome/browser/chromeos/login/user_image_manager_impl.cc
index f66f0f0..ec9f7d6 100644
--- a/chrome/browser/chromeos/login/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/login/user_image_manager_impl.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/debug/trace_event.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
@@ -22,11 +23,14 @@
 #include "chrome/browser/chromeos/login/default_user_images.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #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"
+#include "chrome/common/chrome_switches.h"
+#include "chromeos/chromeos_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/url_constants.h"
@@ -266,12 +270,11 @@
 void UserImageManagerImpl::UserLoggedIn(const std::string& email,
                                         bool user_is_new,
                                         bool user_is_local) {
+  User* user = UserManager::Get()->GetLoggedInUser();
   if (user_is_new) {
     if (!user_is_local)
       SetInitialUserImage(email);
   } else {
-    User* user = UserManager::Get()->GetLoggedInUser();
-
     if (!user_is_local) {
       // If current user image is profile image, it needs to be refreshed.
       bool download_profile_image =
@@ -334,6 +337,14 @@
         FROM_HERE, base::TimeDelta::FromSeconds(kProfileRefreshIntervalSec),
         this, &UserImageManagerImpl::DownloadProfileDataScheduled);
   }
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (user->CanSyncImage() &&
+      !command_line->HasSwitch(chromeos::switches::kDisableUserImageSync)) {
+    if (user_image_sync_observer_.get() &&
+        !command_line->HasSwitch(::switches::kMultiProfiles))
+      NOTREACHED() << "User logged in second time.";
+    user_image_sync_observer_.reset(new UserImageSyncObserver(user));
+  }
 }
 
 void UserImageManagerImpl::SaveUserDefaultImageIndex(
@@ -401,6 +412,14 @@
   DownloadProfileData(reason, true);
 }
 
+UserImageSyncObserver* UserImageManagerImpl::GetSyncObserver() const {
+  return user_image_sync_observer_.get();
+}
+
+void UserImageManagerImpl::Shutdown() {
+  user_image_sync_observer_.reset();
+}
+
 const gfx::ImageSkia& UserImageManagerImpl::DownloadedProfileImage() const {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   return downloaded_profile_image_;
diff --git a/chrome/browser/chromeos/login/user_image_manager_impl.h b/chrome/browser/chromeos/login/user_image_manager_impl.h
index ef6da72..3b09c47 100644
--- a/chrome/browser/chromeos/login/user_image_manager_impl.h
+++ b/chrome/browser/chromeos/login/user_image_manager_impl.h
@@ -26,6 +26,10 @@
 }
 
 namespace chromeos {
+class UserImageSyncObserver;
+}
+
+namespace chromeos {
 
 class UserImageManagerImpl : public UserImageManager,
                              public ProfileDownloaderDelegate {
@@ -49,6 +53,8 @@
   virtual void DeleteUserImage(const std::string& username) OVERRIDE;
   virtual void DownloadProfileImage(const std::string& reason) OVERRIDE;
   virtual const gfx::ImageSkia& DownloadedProfileImage() const OVERRIDE;
+  virtual UserImageSyncObserver* GetSyncObserver() const OVERRIDE;
+  virtual void Shutdown() OVERRIDE;
 
  private:
   friend class UserImageManagerTest;
@@ -175,6 +181,9 @@
   // If |true|, current user image should be migrated right after it is loaded.
   bool migrate_current_user_on_load_;
 
+  // Sync observer attached to current user.
+  scoped_ptr<UserImageSyncObserver> user_image_sync_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(UserImageManagerImpl);
 };
 
diff --git a/chrome/browser/chromeos/login/user_image_sync_observer.cc b/chrome/browser/chromeos/login/user_image_sync_observer.cc
new file mode 100644
index 0000000..8f22012
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_sync_observer.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 "chrome/browser/chromeos/login/user_image_sync_observer.h"
+
+#include "base/bind.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/chromeos/login/default_user_images.h"
+#include "chrome/browser/chromeos/login/screens/user_image_screen.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_image_manager.h"
+#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"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+
+namespace chromeos {
+namespace {
+
+// A dictionary containing info about user image.
+const char kUserImageInfo[] = "user_image_info";
+// Path to value with image index.
+const char kImageIndex[] = "image_index";
+
+bool IsIndexSupported(int index) {
+  return (index >= kFirstDefaultImageIndex && index < kDefaultImagesCount) ||
+      (index == User::kProfileImageIndex);
+}
+
+Profile* GetUserProfile() {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  if (!profile_manager || !profile_manager->IsLoggedIn())
+    return NULL;
+  base::FilePath profile_path = profile_manager->user_data_dir().Append(
+      profile_manager->GetInitialProfileDir());
+  return profile_manager->GetProfileByPath(profile_path);
+}
+
+}  // anonymous namespace
+
+UserImageSyncObserver::Observer::~Observer() {}
+
+UserImageSyncObserver::UserImageSyncObserver(const User* user)
+    : user_(user),
+      prefs_(NULL),
+      is_synced_(false),
+      local_image_changed_(false) {
+  notification_registrar_.reset(new content::NotificationRegistrar);
+  notification_registrar_->Add(this,
+      chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
+      content::NotificationService::AllSources());
+  Profile* profile = GetUserProfile();
+  if (profile) {
+    OnProfileGained(profile);
+  } else {
+    notification_registrar_->Add(this,
+        chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
+        content::NotificationService::AllSources());
+  }
+}
+
+UserImageSyncObserver::~UserImageSyncObserver() {
+  if (!is_synced_ && prefs_)
+    prefs_->RemoveObserver(this);
+  if (pref_change_registrar_)
+    pref_change_registrar_->RemoveAll();
+}
+
+// static
+void UserImageSyncObserver::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry_) {
+  registry_->RegisterDictionaryPref(
+      kUserImageInfo,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+}
+
+void UserImageSyncObserver::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void UserImageSyncObserver::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
+void UserImageSyncObserver::OnProfileGained(Profile* profile) {
+  prefs_ = PrefServiceSyncable::FromProfile(profile);
+  pref_change_registrar_.reset(new PrefChangeRegistrar);
+  pref_change_registrar_->Init(prefs_);
+  pref_change_registrar_->Add(kUserImageInfo,
+      base::Bind(&UserImageSyncObserver::OnPreferenceChanged,
+                 base::Unretained(this)));
+  is_synced_ = prefs_->IsPrioritySyncing();
+  if (!is_synced_) {
+    prefs_->AddObserver(this);
+  } else {
+    OnInitialSync();
+  }
+}
+
+void UserImageSyncObserver::OnInitialSync() {
+  int synced_index;
+  bool local_image_updated = false;
+  if (!GetSyncedImageIndex(&synced_index) || local_image_changed_) {
+    UpdateSyncedImageFromLocal();
+  } else if (IsIndexSupported(synced_index) && CanUpdateLocalImageNow()) {
+    UpdateLocalImageFromSynced();
+    local_image_updated = true;
+  }
+  FOR_EACH_OBSERVER(UserImageSyncObserver::Observer, observer_list_,
+      OnInitialSync(local_image_updated));
+}
+
+void UserImageSyncObserver::OnPreferenceChanged(const std::string& pref_name) {
+  // OnPreferenceChanged can be called before OnIsSyncingChanged.
+  if (!is_synced_) {
+    is_synced_ = true;
+    prefs_->RemoveObserver(this);
+    OnInitialSync();
+  } else if (CanUpdateLocalImageNow()) {
+    UpdateLocalImageFromSynced();
+  }
+}
+
+void UserImageSyncObserver::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  if (type == chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED) {
+    Profile* profile = content::Details<Profile>(details).ptr();
+    if (GetUserProfile() != profile)
+      return;
+    notification_registrar_->Remove(
+        this,
+        chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
+        content::NotificationService::AllSources());
+    OnProfileGained(profile);
+  } else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) {
+    if (is_synced_)
+      UpdateSyncedImageFromLocal();
+    else
+      local_image_changed_ = true;
+  } else {
+    NOTREACHED();
+  }
+}
+
+void UserImageSyncObserver::OnIsSyncingChanged() {
+  is_synced_ = prefs_->IsPrioritySyncing();
+  if (is_synced_) {
+    prefs_->RemoveObserver(this);
+    OnInitialSync();
+  }
+}
+
+void UserImageSyncObserver::UpdateSyncedImageFromLocal() {
+  int local_index = user_->image_index();
+  if (!IsIndexSupported(local_index)) {
+    local_index = User::kInvalidImageIndex;
+  }
+  int synced_index;
+  if (GetSyncedImageIndex(&synced_index) && (synced_index == local_index))
+    return;
+  DictionaryPrefUpdate update(prefs_, kUserImageInfo);
+  DictionaryValue* dict = update.Get();
+  dict->SetInteger(kImageIndex, local_index);
+  LOG(INFO) << "Saved avatar index " << local_index << " to sync.";
+}
+
+void UserImageSyncObserver::UpdateLocalImageFromSynced() {
+  int synced_index;
+  GetSyncedImageIndex(&synced_index);
+  int local_index = user_->image_index();
+  if ((synced_index == local_index) || !IsIndexSupported(synced_index))
+    return;
+  UserImageManager* image_manager = UserManager::Get()->GetUserImageManager();
+  if (synced_index == User::kProfileImageIndex) {
+    image_manager->SaveUserImageFromProfileImage(user_->email());
+  } else {
+    image_manager->SaveUserDefaultImageIndex(user_->email(), synced_index);
+  }
+  LOG(INFO) << "Loaded avatar index " << synced_index << " from sync.";
+}
+
+bool UserImageSyncObserver::GetSyncedImageIndex(int* index) {
+  *index = User::kInvalidImageIndex;
+  const DictionaryValue* dict = prefs_->GetDictionary(kUserImageInfo);
+  return dict && dict->GetInteger(kImageIndex, index);
+}
+
+bool UserImageSyncObserver::CanUpdateLocalImageNow() {
+  if (WizardController* wizard_controller =
+          WizardController::default_controller()) {
+    UserImageScreen* screen = wizard_controller->GetUserImageScreen();
+    if (wizard_controller->current_screen() == screen) {
+      if (screen->user_selected_image())
+        return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace chromeos
+
diff --git a/chrome/browser/chromeos/login/user_image_sync_observer.h b/chrome/browser/chromeos/login/user_image_sync_observer.h
new file mode 100644
index 0000000..16a9eb7
--- /dev/null
+++ b/chrome/browser/chromeos/login/user_image_sync_observer.h
@@ -0,0 +1,104 @@
+// Copyright 2013 The Chromium Authors. 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_USER_IMAGE_SYNC_OBSERVER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_SYNC_OBSERVER_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/prefs/pref_service_syncable_observer.h"
+#include "content/public/browser/notification_observer.h"
+
+class PrefChangeRegistrar;
+class PrefServiceSyncable;
+class Profile;
+namespace chromeos {
+class User;
+}
+namespace content {
+class NotificationRegistrar;
+}
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace chromeos {
+
+// This class is responsible for keeping local user image synced with
+// image saved in syncable preference.
+class UserImageSyncObserver: public PrefServiceSyncableObserver,
+                             public content::NotificationObserver {
+ public:
+  class Observer {
+   public:
+    // Called right after image info synced (i.e. |is_synced| became |true|).
+    // |local_image_updated| indicates if we desided to update local image in
+    // result of sync.
+    virtual void OnInitialSync(bool local_image_updated) = 0;
+    virtual ~Observer();
+  };
+
+ public:
+  explicit UserImageSyncObserver(const User* user);
+  virtual ~UserImageSyncObserver();
+
+  // Register syncable preference for profile.
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+  // Returns |true| if sync was initialized and prefs have actual state.
+  bool is_synced() const { return is_synced_; }
+
+  // Adds |observer| into observers list.
+  void AddObserver(Observer* observer);
+  // Removes |observer| from observers list.
+  void RemoveObserver(Observer* observer);
+
+ private:
+  // PrefServiceSyncableObserver implementation.
+  virtual void OnIsSyncingChanged() OVERRIDE;
+
+  // content::NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // Called after user profile was loaded.
+  void OnProfileGained(Profile* profile);
+
+  // Called when sync servise started it's work and we are able to sync needed
+  // preferences.
+  void OnInitialSync();
+
+  // Called when preference |pref_name| was changed.j
+  void OnPreferenceChanged(const std::string& pref_name);
+
+  // Saves local image preferences to sync.
+  void UpdateSyncedImageFromLocal();
+
+  // Saves sync preferences to local state and updates user image.
+  void UpdateLocalImageFromSynced();
+
+  // Gets synced image index. Returns false if user has no needed preferences.
+  bool GetSyncedImageIndex(int* result);
+
+  // If it is allowed to change user image now.
+  bool CanUpdateLocalImageNow();
+
+  const User* user_;
+  scoped_ptr<PrefChangeRegistrar> pref_change_registrar_;
+  scoped_ptr<content::NotificationRegistrar> notification_registrar_;
+  PrefServiceSyncable* prefs_;
+  bool is_synced_;
+  // Indicates if local user image changed during initialization.
+  bool local_image_changed_;
+  ObserverList<Observer> observer_list_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_USER_IMAGE_SYNC_OBSERVER_H_
+
diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h
index 08b0300..2601726 100644
--- a/chrome/browser/chromeos/login/user_manager.h
+++ b/chrome/browser/chromeos/login/user_manager.h
@@ -152,13 +152,16 @@
   // and notifies observers.
   virtual void RestoreActiveSessions() = 0;
 
-  // Creates locally managed user with given display name, and id (e-mail), and
-  // sets |display_name| for created user and stores it to
-  // persistent list. Returns created user, or existing user if there already
+  // Creates locally managed user with given |display_name| and|local_user_id|
+  // and persists that to user list. Also links this user identified by
+  // |sync_user_id| to manager with a |manager_id|.
+  // Returns created user, or existing user if there already
   // was locally managed user with such display name.
+  // TODO(antrim): Refactor into a single struct to have only 1 getter.
   virtual const User* CreateLocallyManagedUserRecord(
       const std::string& manager_id,
-      const std::string& e_mail,
+      const std::string& local_user_id,
+      const std::string& sync_user_id,
       const string16& display_name) = 0;
 
   // Generates unique username for locally managed user.
@@ -226,6 +229,12 @@
   virtual std::string GetUserDisplayEmail(
       const std::string& username) const = 0;
 
+  // Returns sync_user_id for locally managed user with |managed_user_id| or
+  // empty string if such user is not found or it doesn't have
+  // sync_user_id defined.
+  virtual std::string GetManagedUserSyncId(
+        const std::string& managed_user_id) const = 0;
+
   // Returns the display name for manager of user |managed_user_id| if it is
   // known (was previously set by a |SaveUserDisplayName| call).
   // Otherwise, returns a manager id.
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index cdcf4bb..66a448f 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -68,6 +68,10 @@
 // A vector pref of the public accounts defined on this device.
 const char kPublicAccounts[] = "PublicAccounts";
 
+// A map from locally managed user local user id to sync user id.
+const char kManagedUserSyncId[] =
+    "ManagedUserSyncId";
+
 // A map from locally managed user id to manager user id.
 const char kManagedUserManagers[] =
     "ManagedUserManagers";
@@ -202,6 +206,7 @@
   registry->RegisterDictionaryPref(kUserOAuthTokenStatus);
   registry->RegisterDictionaryPref(kUserDisplayName);
   registry->RegisterDictionaryPref(kUserDisplayEmail);
+  registry->RegisterDictionaryPref(kManagedUserSyncId);
   registry->RegisterDictionaryPref(kManagedUserManagers);
   registry->RegisterDictionaryPref(kManagedUserManagerNames);
   registry->RegisterDictionaryPref(kManagedUserManagerDisplayEmails);
@@ -220,7 +225,6 @@
       is_current_user_new_(false),
       is_current_user_ephemeral_regular_user_(false),
       ephemeral_users_enabled_(false),
-      locally_managed_users_enabled_by_policy_(false),
       merge_session_state_(MERGE_STATUS_NOT_STARTED),
       observed_sync_service_(NULL),
       user_image_manager_(new UserImageManagerImpl),
@@ -269,6 +273,7 @@
 
   if (observed_sync_service_)
     observed_sync_service_->RemoveObserver(this);
+  user_image_manager_->Shutdown();
 }
 
 UserImageManager* UserManagerImpl::GetUserImageManager() {
@@ -339,7 +344,7 @@
                (AreEphemeralUsersEnabled() || browser_restart)) {
       RegularUserLoggedInAsEphemeral(email);
     } else {
-      RegularUserLoggedIn(email, browser_restart);
+      RegularUserLoggedIn(email);
     }
 
     // Initialize the session length limiter and start it only if
@@ -449,7 +454,8 @@
 
 const User* UserManagerImpl::CreateLocallyManagedUserRecord(
       const std::string& manager_id,
-      const std::string& e_mail,
+      const std::string& local_user_id,
+      const std::string& sync_user_id,
       const string16& display_name) {
   const User* user = FindLocallyManagedUser(display_name);
   DCHECK(!user);
@@ -458,34 +464,47 @@
 
   PrefService* local_state = g_browser_process->local_state();
 
-  User* new_user = User::CreateLocallyManagedUser(e_mail);
+  User* new_user = User::CreateLocallyManagedUser(local_user_id);
   ListPrefUpdate prefs_users_update(local_state, kRegularUsers);
-  prefs_users_update->Insert(0, new base::StringValue(e_mail));
+  prefs_users_update->Insert(0, new base::StringValue(local_user_id));
   ListPrefUpdate prefs_new_users_update(local_state,
                                         kLocallyManagedUsersFirstRun);
-  prefs_new_users_update->Insert(0, new base::StringValue(e_mail));
+  prefs_new_users_update->Insert(0, new base::StringValue(local_user_id));
   users_.insert(users_.begin(), new_user);
 
   const User* manager = FindUser(manager_id);
   CHECK(manager);
 
+  DictionaryPrefUpdate sync_id_update(local_state, kManagedUserSyncId);
   DictionaryPrefUpdate manager_update(local_state, kManagedUserManagers);
   DictionaryPrefUpdate manager_name_update(local_state,
                                            kManagedUserManagerNames);
   DictionaryPrefUpdate manager_email_update(local_state,
                                             kManagedUserManagerDisplayEmails);
-  manager_update->SetWithoutPathExpansion(e_mail,
+  sync_id_update->SetWithoutPathExpansion(local_user_id,
+      new base::StringValue(sync_user_id));
+  manager_update->SetWithoutPathExpansion(local_user_id,
       new base::StringValue(manager->email()));
-  manager_name_update->SetWithoutPathExpansion(e_mail,
+  manager_name_update->SetWithoutPathExpansion(local_user_id,
       new base::StringValue(manager->GetDisplayName()));
-  manager_email_update->SetWithoutPathExpansion(e_mail,
+  manager_email_update->SetWithoutPathExpansion(local_user_id,
       new base::StringValue(manager->display_email()));
 
-  SaveUserDisplayName(e_mail, display_name);
+  SaveUserDisplayName(local_user_id, display_name);
   g_browser_process->local_state()->CommitPendingWrite();
   return new_user;
 }
 
+std::string UserManagerImpl::GetManagedUserSyncId(
+    const std::string& managed_user_id) const {
+  PrefService* local_state = g_browser_process->local_state();
+  const DictionaryValue* sync_user_ids =
+      local_state->GetDictionary(kManagedUserSyncId);
+  std::string result;
+  sync_user_ids->GetStringWithoutPathExpansion(managed_user_id, &result);
+  return result;
+}
+
 string16 UserManagerImpl::GetManagerDisplayNameForManagedUser(
     const std::string& managed_user_id) const {
   PrefService* local_state = g_browser_process->local_state();
@@ -740,7 +759,6 @@
     case chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED:
       if (IsUserLoggedIn() &&
           !IsLoggedInAsGuest() &&
-          !IsLoggedInAsLocallyManagedUser() &&
           !IsLoggedInAsKioskApp()) {
         Profile* profile = content::Details<Profile>(details).ptr();
         if (!profile->IsOffTheRecord() &&
@@ -781,16 +799,15 @@
       state != GoogleServiceAuthError::REQUEST_CANCELED) {
     // Invalidate OAuth token to force Gaia sign-in flow. This is needed
     // because sign-out/sign-in solution is suggested to the user.
-    // TODO(altimofeev): this code isn't needed after crosbug.com/25978 is
-    // implemented.
-    DVLOG(1) << "Invalidate OAuth token because of a sync error.";
+    // TODO(nkostylev): Remove after crosbug.com/25978 is implemented.
+    LOG(ERROR) << "Invalidate OAuth token because of a sync error: "
+               << observed_sync_service_->GetAuthError().ToString();
     // http://crbug.com/230860
     // TODO(nkostylev): Figure out whether we want to have observers
     // for each logged in user.
     // TODO(nkostyelv): Change observer after active user has changed.
-    SaveUserOAuthStatus(
-        active_user_->email(),
-        User::OAUTH2_TOKEN_STATUS_INVALID);
+    SaveUserOAuthStatus(active_user_->email(),
+                        User::OAUTH2_TOKEN_STATUS_INVALID);
   }
 }
 
@@ -1021,12 +1038,11 @@
        it != regular_users.end(); ++it) {
     User* user = NULL;
     const std::string domain = gaia::ExtractDomainName(*it);
-    if (domain == UserManager::kLocallyManagedUserDomain) {
+    if (domain == UserManager::kLocallyManagedUserDomain)
       user = User::CreateLocallyManagedUser(*it);
-    } else {
+    else
       user = User::CreateRegularUser(*it);
-      user->set_oauth_token_status(LoadUserOAuthStatus(*it));
-    }
+    user->set_oauth_token_status(LoadUserOAuthStatus(*it));
     users_.push_back(user);
 
     string16 display_name;
@@ -1058,7 +1074,6 @@
 
 void UserManagerImpl::RetrieveTrustedDevicePolicies() {
   ephemeral_users_enabled_ = false;
-  locally_managed_users_enabled_by_policy_ = false;
   owner_email_ = "";
 
   // Schedule a callback if device policy has not yet been verified.
@@ -1070,8 +1085,6 @@
 
   cros_settings_->GetBoolean(kAccountsPrefEphemeralUsersEnabled,
                              &ephemeral_users_enabled_);
-  cros_settings_->GetBoolean(kAccountsPrefSupervisedUsersEnabled,
-                             &locally_managed_users_enabled_by_policy_);
   cros_settings_->GetString(kDeviceOwner, &owner_email_);
 
   EnsureUsersLoaded();
@@ -1153,8 +1166,7 @@
                                                    false);
 }
 
-void UserManagerImpl::RegularUserLoggedIn(const std::string& email,
-                                          bool browser_restart) {
+void UserManagerImpl::RegularUserLoggedIn(const std::string& email) {
   // Remove the user from the user list.
   active_user_ = RemoveRegularOrLocallyManagedUserFromList(email);
 
@@ -1176,10 +1188,7 @@
 
   user_image_manager_->UserLoggedIn(email, is_current_user_new_, false);
 
-  if (!browser_restart) {
-    // For GAIA login flow, logged in user wallpaper may not be loaded.
-    WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
-  }
+  WallpaperManager::Get()->EnsureLoggedInUserWallpaperLoaded();
 
   default_pinned_apps_field_trial::SetupForUser(email, is_current_user_new_);
 
@@ -1640,8 +1649,11 @@
 }
 
 bool UserManagerImpl::AreLocallyManagedUsersAllowed() const {
+  bool locally_managed_users_allowed = false;
+  cros_settings_->GetBoolean(kAccountsPrefSupervisedUsersEnabled,
+                             &locally_managed_users_allowed);
   return ManagedUserService::AreManagedUsersEnabled() &&
-        (locally_managed_users_enabled_by_policy_ ||
+        (locally_managed_users_allowed ||
          !g_browser_process->browser_policy_connector()->IsEnterpriseManaged());
 }
 
diff --git a/chrome/browser/chromeos/login/user_manager_impl.h b/chrome/browser/chromeos/login/user_manager_impl.h
index 577e1d6..08f2d4c 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.h
+++ b/chrome/browser/chromeos/login/user_manager_impl.h
@@ -84,6 +84,8 @@
                                     const std::string& display_email) OVERRIDE;
   virtual std::string GetUserDisplayEmail(
       const std::string& username) const OVERRIDE;
+  virtual std::string GetManagedUserSyncId(
+      const std::string& managed_user_id) const OVERRIDE;
   virtual string16 GetManagerDisplayNameForManagedUser(
       const std::string& managed_user_id) const OVERRIDE;
   virtual std::string GetManagerUserIdForManagedUser(
@@ -118,7 +120,8 @@
   virtual void NotifyLocalStateChanged() OVERRIDE;
   virtual const User* CreateLocallyManagedUserRecord(
       const std::string& manager_id,
-      const std::string& e_mail,
+      const std::string& local_user_id,
+      const std::string& sync_user_id,
       const string16& display_name) OVERRIDE;
   virtual std::string GenerateUniqueLocallyManagedUserId() OVERRIDE;
   virtual void StartLocallyManagedUserCreationTransaction(
@@ -196,7 +199,7 @@
   void GuestUserLoggedIn();
 
   // Indicates that a regular user just logged in.
-  void RegularUserLoggedIn(const std::string& email, bool browser_restart);
+  void RegularUserLoggedIn(const std::string& email);
 
   // Indicates that a regular user just logged in as ephemeral.
   void RegularUserLoggedInAsEphemeral(const std::string& email);
@@ -365,11 +368,6 @@
   // policy yet.
   bool ephemeral_users_enabled_;
 
-  // Cached flag indicating whether the locally managed users are enabled by
-  // policy. Defaults to |false| if the value has not been read from trusted
-  // device policy yet.
-  bool locally_managed_users_enabled_by_policy_;
-
   // Merge session state (cookie restore process state).
   MergeSessionState merge_session_state_;
 
diff --git a/chrome/browser/chromeos/login/user_manager_unittest.cc b/chrome/browser/chromeos/login/user_manager_unittest.cc
index c26a764..19a17e7 100644
--- a/chrome/browser/chromeos/login/user_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/user_manager_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/run_loop.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/user_manager_impl.h"
@@ -77,10 +76,6 @@
     return GetUserManagerImpl()->ephemeral_users_enabled_;
   }
 
-  bool GetUserManagerLocallyManagedUsersEnabledByPolicy() const {
-    return GetUserManagerImpl()->locally_managed_users_enabled_by_policy_;
-  }
-
   void SetUserManagerEphemeralUsersEnabled(bool ephemeral_users_enabled) {
     GetUserManagerImpl()->ephemeral_users_enabled_ = ephemeral_users_enabled;
   }
@@ -127,7 +122,6 @@
   scoped_ptr<TestingPrefServiceSimple> local_state_;
 
   ScopedTestDeviceSettingsService test_device_settings_service_;
-  ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
   ScopedTestCrosSettings test_cros_settings_;
 
   scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_;
@@ -185,13 +179,4 @@
   EXPECT_EQ((*users)[0]->email(), "owner@invalid.domain");
 }
 
-TEST_F(UserManagerTest, DisablingLMUByDeviceSettings) {
-  SetDeviceSettings(false, "owner@invalid.domain", false);
-  RetrieveTrustedDevicePolicies();
-  EXPECT_EQ(GetUserManagerLocallyManagedUsersEnabledByPolicy(), false);
-  SetDeviceSettings(false, "owner@invalid.domain", true);
-  RetrieveTrustedDevicePolicies();
-  EXPECT_EQ(GetUserManagerLocallyManagedUsersEnabledByPolicy(), true);
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index 03dd8c4..09ebcc8 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -577,6 +577,7 @@
 
   if (GetUserWallpaperInfo(email, &info)) {
     gfx::ImageSkia user_wallpaper;
+    current_user_wallpaper_info_ = info;
     if (GetWallpaperFromCache(email, &user_wallpaper)) {
       ash::Shell::GetInstance()->desktop_background_controller()->
           SetCustomWallpaper(user_wallpaper, info.layout);
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
index fe126d8..b2ced1d 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_browsertest.cc
@@ -16,13 +16,14 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.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"
 #include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/cryptohome_client.h"
 #include "ui/aura/env.h"
 #include "ui/base/resource/resource_bundle.h"
 
@@ -44,7 +45,7 @@
 
 }  // namespace
 
-class WallpaperManagerBrowserTest : public CrosInProcessBrowserTest,
+class WallpaperManagerBrowserTest : public InProcessBrowserTest,
                                     public DesktopBackgroundControllerObserver {
  public:
   WallpaperManagerBrowserTest () : controller_(NULL),
@@ -421,4 +422,29 @@
   // can not handle pre migrated user profile (M21 profile or older).
 }
 
+class WallpaperManagerBrowserTestCrashRestore
+    : public WallpaperManagerBrowserTest {
+ public:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    command_line->AppendSwitch(chromeos::switches::kDisableLoginAnimations);
+    command_line->AppendSwitch(chromeos::switches::kDisableBootAnimation);
+    command_line->AppendSwitch(::switches::kMultiProfiles);
+    command_line->AppendSwitchASCII(switches::kLoginUser, kTestUser1);
+    command_line->AppendSwitchASCII(switches::kLoginProfile,
+        CryptohomeClient::GetStubSanitizedUsername(kTestUser1));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestCrashRestore,
+                       PRE_RestoreWallpaper) {
+  LogIn(kTestUser1);
+}
+
+// Test for crbug.com/270278. It simulates a browser crash and verifies if user
+// wallpaper is loaded.
+IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTestCrashRestore,
+                       RestoreWallpaper) {
+  EXPECT_EQ(1, LoadedWallpapers());
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc b/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
index 5ed7c9f..4dc6cbe 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/prefs/testing_pref_service.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/user_manager_impl.h"
@@ -95,7 +94,6 @@
   scoped_ptr<TestingPrefServiceSimple> local_state_;
 
   ScopedTestDeviceSettingsService test_device_settings_service_;
-  ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
   ScopedTestCrosSettings test_cros_settings_;
 
   scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_;
diff --git a/chrome/browser/chromeos/login/webui_login_display.cc b/chrome/browser/chromeos/login/webui_login_display.cc
index 48bcbc4..e9a8675 100644
--- a/chrome/browser/chromeos/login/webui_login_display.cc
+++ b/chrome/browser/chromeos/login/webui_login_display.cc
@@ -364,6 +364,10 @@
   delegate_->Signout();
 }
 
+void WebUILoginDisplay::LoginAsKioskApp(const std::string& app_id) {
+  delegate_->LoginAsKioskApp(app_id);
+}
+
 void WebUILoginDisplay::OnUserActivity(const ui::Event* event) {
   if (!password_clear_timer_.IsRunning())
     StartPasswordClearTimer();
diff --git a/chrome/browser/chromeos/login/webui_login_display.h b/chrome/browser/chromeos/login/webui_login_display.h
index f8a0341..db33fdc 100644
--- a/chrome/browser/chromeos/login/webui_login_display.h
+++ b/chrome/browser/chromeos/login/webui_login_display.h
@@ -84,6 +84,7 @@
   virtual bool IsUserSigninCompleted() const OVERRIDE;
   virtual void SetDisplayEmail(const std::string& email) OVERRIDE;
   virtual void Signout() OVERRIDE;
+  virtual void LoginAsKioskApp(const std::string& app_id) OVERRIDE;
 
   // UserActivityDetector implementation:
   virtual void OnUserActivity(const ui::Event* event) OVERRIDE;
diff --git a/chrome/browser/chromeos/login/webui_login_view.cc b/chrome/browser/chromeos/login/webui_login_view.cc
index 590a943..28fcd18 100644
--- a/chrome/browser/chromeos/login/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/webui_login_view.cc
@@ -48,7 +48,8 @@
 
 namespace {
 
-// These strings must be kept in sync with handleAccelerator() in oobe.js.
+// These strings must be kept in sync with handleAccelerator()
+// in display_manager.js.
 const char kAccelNameCancel[] = "cancel";
 const char kAccelNameEnrollment[] = "enrollment";
 const char kAccelNameKioskEnable[] = "kiosk_enable";
@@ -58,6 +59,7 @@
 const char kAccelNameRight[] = "right";
 const char kAccelNameDeviceRequisition[] = "device_requisition";
 const char kAccelNameDeviceRequisitionRemora[] = "device_requisition_remora";
+const char kAccelNameAppLaunchBailout[] = "app_launch_bailout";
 
 // Observes IPC messages from the FrameSniffer and notifies JS if error
 // appears.
@@ -92,26 +94,6 @@
   content::WebUI* webui_;
 };
 
-// A View class which places its first child at the right most position.
-class RightAlignedView : public views::View {
- public:
-  virtual void Layout() OVERRIDE;
-  virtual void ChildPreferredSizeChanged(View* child) OVERRIDE;
-};
-
-void RightAlignedView::Layout() {
-  if (has_children()) {
-    views::View* child = child_at(0);
-    gfx::Size preferred_size = child->GetPreferredSize();
-    child->SetBounds(width() - preferred_size.width(),
-                     0, preferred_size.width(), preferred_size.height());
-  }
-}
-
-void RightAlignedView::ChildPreferredSizeChanged(View* child) {
-  Layout();
-}
-
 // A class to change arrow key traversal behavior when it's alive.
 class ScopedArrowKeyTraversal {
  public:
@@ -143,8 +125,6 @@
 
 WebUILoginView::WebUILoginView()
     : webui_login_(NULL),
-      login_window_(NULL),
-      host_window_frozen_(false),
       is_hidden_(false),
       login_prompt_visible_handled_(false),
       should_emit_login_prompt_visible_(true),
@@ -183,20 +163,26 @@
       ui::Accelerator(ui::VKEY_H, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
       kAccelNameDeviceRequisitionRemora;
 
+  accel_map_[ui::Accelerator(ui::VKEY_S,
+                             ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
+      kAccelNameAppLaunchBailout;
+
   for (AccelMap::iterator i(accel_map_.begin()); i != accel_map_.end(); ++i)
     AddAccelerator(i->first);
 }
 
 WebUILoginView::~WebUILoginView() {
+  FOR_EACH_OBSERVER(web_modal::WebContentsModalDialogHostObserver,
+                    observer_list_,
+                    OnHostDestroying());
+
   if (ash::Shell::GetInstance()->HasPrimaryStatusArea()) {
     ash::Shell::GetInstance()->GetPrimarySystemTray()->
         SetNextFocusableView(NULL);
   }
 }
 
-void WebUILoginView::Init(views::Widget* login_window) {
-  login_window_ = login_window;
-
+void WebUILoginView::Init() {
   Profile* signin_profile = ProfileHelper::GetSigninProfile();
   auth_extension_.reset(new ScopedGaiaAuthExtension(signin_profile));
   webui_login_ = new views::WebView(signin_profile);
@@ -212,7 +198,7 @@
   // LoginHandlerViews uses a constrained window for the password manager view.
   WebContentsModalDialogManager::CreateForWebContents(web_contents);
   WebContentsModalDialogManager::FromWebContents(web_contents)->
-      set_delegate(this);
+      SetDelegate(this);
 
   web_contents->SetDelegate(this);
   renderer_preferences_util::UpdateFromSystemSettings(
@@ -278,12 +264,6 @@
   return GetWidget()->GetNativeWindow();
 }
 
-void WebUILoginView::OnWindowCreated() {
-}
-
-void WebUILoginView::UpdateWindowType() {
-}
-
 void WebUILoginView::LoadURL(const GURL & url) {
   webui_login_->LoadInitialURL(url);
   webui_login_->RequestFocus();
diff --git a/chrome/browser/chromeos/login/webui_login_view.h b/chrome/browser/chromeos/login/webui_login_view.h
index b1f4828..86c47a5 100644
--- a/chrome/browser/chromeos/login/webui_login_view.h
+++ b/chrome/browser/chromeos/login/webui_login_view.h
@@ -49,7 +49,7 @@
   virtual ~WebUILoginView();
 
   // Initializes the webui login view.
-  virtual void Init(views::Widget* login_window);
+  virtual void Init();
 
   // Overridden from views::Views:
   virtual bool AcceleratorPressed(
@@ -68,16 +68,9 @@
   virtual void RemoveObserver(
       web_modal::WebContentsModalDialogHostObserver* observer) OVERRIDE;
 
-  // Called when WebUI window is created.
-  virtual void OnWindowCreated();
-
   // Gets the native window from the view widget.
   gfx::NativeWindow GetNativeWindow() const;
 
-  // Invokes SetWindowType for the window. This is invoked during startup and
-  // after we've painted.
-  void UpdateWindowType();
-
   // Loads given page. Should be called after Init() has been called.
   void LoadURL(const GURL& url);
 
@@ -151,18 +144,12 @@
 
   content::NotificationRegistrar registrar_;
 
-  // Login window which shows the view.
-  views::Widget* login_window_;
-
   // Converts keyboard events on the WebContents to accelerators.
   views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
 
   // Maps installed accelerators to OOBE webui accelerator identifiers.
   AccelMap accel_map_;
 
-  // Whether the host window is frozen.
-  bool host_window_frozen_;
-
   // True when WebUI is being initialized hidden.
   bool is_hidden_;
 
diff --git a/chrome/browser/chromeos/login/webui_screen_locker.cc b/chrome/browser/chromeos/login/webui_screen_locker.cc
index adee217..a61f54a 100644
--- a/chrome/browser/chromeos/login/webui_screen_locker.cc
+++ b/chrome/browser/chromeos/login/webui_screen_locker.cc
@@ -35,7 +35,7 @@
 namespace {
 
 // URL which corresponds to the login WebUI.
-const char kLoginURL[] = "chrome://oobe/login#lock";
+const char kLoginURL[] = "chrome://oobe/lock";
 
 }  // namespace
 
@@ -63,10 +63,9 @@
   lock_window->set_observer(this);
   lock_window_ = lock_window->GetWidget();
   lock_window_->AddObserver(this);
-  WebUILoginView::Init(lock_window_);
+  WebUILoginView::Init();
   lock_window_->SetContentsView(this);
   lock_window_->Show();
-  OnWindowCreated();
   LoadURL(GURL(kLoginURL));
   lock_window->Grab();
 
@@ -84,12 +83,6 @@
   registrar_.Add(this,
                  chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
                  content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_LOCK_WEBUI_READY,
-                 content::NotificationService::AllSources());
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_LOCK_BACKGROUND_DISPLAYED,
-                 content::NotificationService::AllSources());
 }
 
 void WebUIScreenLocker::ScreenLockReady() {
@@ -154,6 +147,19 @@
   }
 }
 
+void WebUIScreenLocker::OnLockWebUIReady() {
+  VLOG(1) << "WebUI ready; lock window is "
+          << (lock_ready_ ? "too" : "not");
+  webui_ready_ = true;
+  if (lock_ready_)
+    ScreenLockReady();
+}
+
+void WebUIScreenLocker::OnLockBackgroundDisplayed() {
+  UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady",
+                      base::TimeTicks::Now() - lock_time_);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // WebUIScreenLocker, content::NotificationObserver implementation:
 
@@ -167,19 +173,6 @@
       login_display_->OnUserImageChanged(user);
       break;
     }
-    case chrome::NOTIFICATION_LOCK_WEBUI_READY: {
-      VLOG(1) << "WebUI ready; lock window is "
-              << (lock_ready_ ? "too" : "not");
-      webui_ready_ = true;
-      if (lock_ready_)
-        ScreenLockReady();
-      break;
-    }
-    case chrome::NOTIFICATION_LOCK_BACKGROUND_DISPLAYED: {
-      UMA_HISTOGRAM_TIMES("LockScreen.BackgroundReady",
-                          base::TimeTicks::Now() - lock_time_);
-      break;
-    }
     default:
       WebUILoginView::Observe(type, source, details);
   }
@@ -271,6 +264,10 @@
   chromeos::ScreenLocker::default_screen_locker()->Signout();
 }
 
+void WebUIScreenLocker::LoginAsKioskApp(const std::string& app_id) {
+  NOTREACHED();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // LockWindow::Observer implementation:
 
diff --git a/chrome/browser/chromeos/login/webui_screen_locker.h b/chrome/browser/chromeos/login/webui_screen_locker.h
index 4521525..ad49795 100644
--- a/chrome/browser/chromeos/login/webui_screen_locker.h
+++ b/chrome/browser/chromeos/login/webui_screen_locker.h
@@ -66,6 +66,8 @@
   virtual void AnimateAuthenticationSuccess() OVERRIDE;
   virtual gfx::NativeWindow GetNativeWindow() const OVERRIDE;
   virtual content::WebUI* GetAssociatedWebUI() OVERRIDE;
+  virtual void OnLockWebUIReady() OVERRIDE;
+  virtual void OnLockBackgroundDisplayed() OVERRIDE;
 
   // LoginDisplay::Delegate: implementation
   virtual void CancelPasswordChangedFlow() OVERRIDE;
@@ -89,6 +91,7 @@
   virtual void ResyncUserData() OVERRIDE;
   virtual void SetDisplayEmail(const std::string& email) OVERRIDE;
   virtual void Signout() OVERRIDE;
+  virtual void LoginAsKioskApp(const std::string& app_id) OVERRIDE;
 
   // content::NotificationObserver (via WebUILoginView) implementation.
   virtual void Observe(int type,
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index bc83452..ab32260 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -21,7 +21,7 @@
 #include "base/values.h"
 #include "chrome/app/breakpad_linux.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_launcher.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/customization_document.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
@@ -122,6 +122,8 @@
 const char WizardController::kWrongHWIDScreenName[] = "wrong-hwid";
 const char WizardController::kLocallyManagedUserCreationScreenName[] =
   "locally-managed-user-creation-flow";
+const char WizardController::kAppLaunchSplashScreenName[] =
+  "app-launch-splash";
 
 // Passing this parameter as a "first screen" initiates full OOBE flow.
 const char WizardController::kOutOfBoxScreenName[] = "oobe";
@@ -717,6 +719,8 @@
     ShowWrongHWIDScreen();
   } else if (screen_name == kLocallyManagedUserCreationScreenName) {
     ShowLocallyManagedUserCreationScreen();
+  } else if (screen_name == kAppLaunchSplashScreenName) {
+    AutoLaunchKioskApp();
   } else if (screen_name != kTestNoScreenName) {
     if (is_out_of_box_) {
       ShowNetworkScreen();
@@ -825,11 +829,8 @@
   KioskAppManager::App app_data;
   std::string app_id = KioskAppManager::Get()->GetAutoLaunchApp();
   CHECK(KioskAppManager::Get()->GetApp(app_id, &app_data));
-  if (ExistingUserController::current_controller())
-    ExistingUserController::current_controller()->PrepareKioskAppLaunch();
 
-  // KioskAppLauncher deletes itself when done.
-  (new KioskAppLauncher(KioskAppManager::Get(), app_id))->Start();
+  host_->StartAppLaunch(app_id);
 }
 
 // static
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 8022003..d4fb70c 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -145,6 +145,7 @@
   static const char kTermsOfServiceScreenName[];
   static const char kWrongHWIDScreenName[];
   static const char kLocallyManagedUserCreationScreenName[];
+  static const char kAppLaunchSplashScreenName[];
 
  private:
   // Show specific screen.
diff --git a/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc b/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc
index daff36b..adf341d 100644
--- a/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc
+++ b/chrome/browser/chromeos/login/wizard_in_process_browser_test.cc
@@ -25,7 +25,7 @@
 
 void WizardInProcessBrowserTest::SetUp() {
   WizardController::SetZeroDelays();
-  CrosInProcessBrowserTest::SetUp();
+  InProcessBrowserTest::SetUp();
 }
 
 void WizardInProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
diff --git a/chrome/browser/chromeos/login/wizard_in_process_browser_test.h b/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
index 8b888e3..019edf8 100644
--- a/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
+++ b/chrome/browser/chromeos/login/wizard_in_process_browser_test.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
+#include "chrome/test/base/in_process_browser_test.h"
 
 class Browser;
 class Profile;
@@ -22,11 +22,11 @@
 // Instead of creating Chrome browser window it creates login wizard window
 // with specified parameters and allows to customize environment at the
 // right moment in time before wizard is created.
-class WizardInProcessBrowserTest : public CrosInProcessBrowserTest {
+class WizardInProcessBrowserTest : public InProcessBrowserTest {
  public:
   explicit WizardInProcessBrowserTest(const char* screen_name);
 
-  // Overridden from CrosInProcessBrowserTest:
+  // Overridden from InProcessBrowserTest:
   virtual void SetUp() OVERRIDE;
 
  protected:
diff --git a/chrome/browser/chromeos/media/OWNERS b/chrome/browser/chromeos/media/OWNERS
deleted file mode 100644
index 89bc7d0..0000000
--- a/chrome/browser/chromeos/media/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-dgozman@chromium.org
-kaznacheev@chromium.org
-oleg@chromium.org
-serya@chromium.org
-zvorygin@chromium.org
diff --git a/chrome/browser/chromeos/media/media_player.cc b/chrome/browser/chromeos/media/media_player.cc
deleted file mode 100644
index ce6f47a..0000000
--- a/chrome/browser/chromeos/media/media_player.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 "chrome/browser/chromeos/media/media_player.h"
-
-#include <string>
-
-#include "ash/shell.h"
-#include "base/bind.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
-#include "chrome/browser/chromeos/extensions/media_player_api.h"
-#include "chrome/browser/chromeos/extensions/media_player_event_router.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_iterator.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/gfx/screen.h"
-
-using content::BrowserThread;
-
-namespace {
-
-const char kMediaPlayerAppName[] = "mediaplayer";
-const int kPopupRight = 20;
-const int kPopupBottom = 80;
-const int kPopupWidth = 280;
-
-// Set the initial height to the minimum possible height. Keep the constants
-// in sync with chrome/browser/resources/file_manager/css/audio_player.css.
-// SetWindowHeight will be called soon after the popup creation with the correct
-// height which will cause a nice slide-up animation.
-// TODO(kaznacheev): Remove kTitleHeight when MediaPlayer becomes chromeless.
-// kTitleHeight is an approximate value. May be different for touch-enabled UI.
-const int kTitleHeight = 35;
-const int kTrackHeight = 58;
-const int kControlsHeight = 35;
-const int kPopupHeight = kTitleHeight + kTrackHeight + kControlsHeight;
-
-}  // namespace
-
-const MediaPlayer::UrlVector& MediaPlayer::GetPlaylist() const {
-  return current_playlist_;
-}
-
-int MediaPlayer::GetPlaylistPosition() const {
-  return current_position_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// Mediaplayer
-//
-////////////////////////////////////////////////////////////////////////////////
-
-MediaPlayer::~MediaPlayer() {
-}
-
-// static
-MediaPlayer* MediaPlayer::GetInstance() {
-  return Singleton<MediaPlayer>::get();
-}
-
-// The client knows how high the client part of the window should be but
-// cannot translate it to the window height (because the window title bar height
-// is unknown). Instead it passes the height difference which this method
-// applies to the window height.
-void MediaPlayer::AdjustWindowHeight(int height_diff) {
-  Browser* browser = GetBrowser();
-  if (browser != NULL) {
-    gfx::Rect bounds = browser->window()->GetBounds();
-    int window_height = bounds.height() + height_diff;
-    browser->window()->SetBounds(gfx::Rect(
-        bounds.x(),
-        std::max(0, bounds.bottom() - window_height),
-        bounds.width(),
-        window_height));
-  }
-}
-
-void MediaPlayer::CloseWindow() {
-  Browser* browser = GetBrowser();
-  if (browser != NULL) {
-    browser->window()->Close();
-  }
-}
-
-void MediaPlayer::ClearPlaylist() {
-  current_playlist_.clear();
-}
-
-void MediaPlayer::EnqueueMediaFileUrl(const GURL& url) {
-  current_playlist_.push_back(url);
-}
-
-void MediaPlayer::ForcePlayMediaURL(const GURL& url) {
-  ClearPlaylist();
-  EnqueueMediaFileUrl(url);
-  SetPlaylistPosition(0);
-  NotifyPlaylistChanged();
-}
-
-void MediaPlayer::SetPlaylistPosition(int position) {
-  current_position_ = position;
-}
-
-void MediaPlayer::NotifyPlaylistChanged() {
-  Browser* browser = GetBrowser();
-  if (browser) {
-    extensions::MediaPlayerAPI::Get(browser->profile())->
-        media_player_event_router()->NotifyPlaylistChanged();
-  }
-}
-
-void MediaPlayer::PopupMediaPlayer() {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&MediaPlayer::PopupMediaPlayer,
-                   base::Unretained(this) /*this class is a singleton*/));
-    return;
-  }
-
-  Browser* browser = GetBrowser();
-  if (!browser) {
-    const gfx::Size screen =
-        ash::Shell::GetScreen()->GetPrimaryDisplay().size();
-    const gfx::Rect bounds(screen.width() - kPopupRight - kPopupWidth,
-                           screen.height() - kPopupBottom - kPopupHeight,
-                           kPopupWidth,
-                           kPopupHeight);
-
-    Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-    Browser::CreateParams params(Browser::TYPE_POPUP, profile,
-                                 chrome::HOST_DESKTOP_TYPE_ASH);
-    params.app_name = kMediaPlayerAppName;
-    params.initial_bounds = bounds;
-    browser = new Browser(params);
-
-    chrome::AddSelectedTabWithURL(browser, GetMediaPlayerUrl(),
-                                  content::PAGE_TRANSITION_LINK);
-  }
-  browser->window()->Show();
-}
-
-GURL MediaPlayer::GetMediaPlayerUrl() {
-  return file_manager::util::GetMediaPlayerUrl();
-}
-
-Browser* MediaPlayer::GetBrowser() {
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    Browser* browser = *it;
-    TabStripModel* tab_strip = browser->tab_strip_model();
-    for (int idx = 0; idx < tab_strip->count(); idx++) {
-      const GURL& url = tab_strip->GetWebContentsAt(idx)->GetVisibleURL();
-      GURL base_url(url.GetOrigin().spec() + url.path().substr(1));
-      if (base_url == GetMediaPlayerUrl())
-        return browser;
-    }
-  }
-  return NULL;
-}
-
-MediaPlayer::MediaPlayer()
-    : current_position_(0) {
-};
diff --git a/chrome/browser/chromeos/media/media_player.h b/chrome/browser/chromeos/media/media_player.h
deleted file mode 100644
index 20940e0..0000000
--- a/chrome/browser/chromeos/media/media_player.h
+++ /dev/null
@@ -1,78 +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_CHROMEOS_MEDIA_MEDIA_PLAYER_H_
-#define CHROME_BROWSER_CHROMEOS_MEDIA_MEDIA_PLAYER_H_
-
-#include <vector>
-
-#include "base/memory/singleton.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-class Browser;
-class GURL;
-
-class MediaPlayer {
- public:
-  typedef std::vector<GURL> UrlVector;
-
-  virtual ~MediaPlayer();
-
-  // Adjusts the mediaplayer window height.
-  void AdjustWindowHeight(int height_diff);
-
-  // Forces the mediaplayer window to be closed.
-  void CloseWindow();
-
-  // Clears the current playlist.
-  void ClearPlaylist();
-
-  // Enqueues this fileschema url into the current playlist.
-  void EnqueueMediaFileUrl(const GURL& url);
-
-  // Clears out the current playlist, and start playback of the given url.
-  void ForcePlayMediaURL(const GURL& url);
-
-  // Popup the mediaplayer, this shows the browser, and sets up its
-  // locations correctly.
-  void PopupMediaPlayer();
-
-  // Sets the currently playing element to the given positions.
-  void SetPlaylistPosition(int position);
-
-  // Returns current playlist.
-  const UrlVector& GetPlaylist() const;
-
-  // Returns current playlist position.
-  int GetPlaylistPosition() const;
-
-  // Notfies the mediaplayer that the playlist changed. This could be
-  // called from the mediaplayer itself for example.
-  void NotifyPlaylistChanged();
-
-  // Getter for the singleton.
-  static MediaPlayer* GetInstance();
-
- private:
-  friend class MediaPlayerBrowserTest;
-  friend struct DefaultSingletonTraits<MediaPlayer>;
-
-  // The current playlist of urls.
-  UrlVector current_playlist_;
-
-  // The position into the current_playlist_ of the currently playing item.
-  int current_position_;
-
-  MediaPlayer();
-
-  static GURL GetMediaPlayerUrl();
-
-  // Browser containing the Mediaplayer.
-  static Browser* GetBrowser();
-
-  DISALLOW_COPY_AND_ASSIGN(MediaPlayer);
-};
-
-#endif  // CHROME_BROWSER_CHROMEOS_MEDIA_MEDIA_PLAYER_H_
diff --git a/chrome/browser/chromeos/media/media_player_browsertest.cc b/chrome/browser/chromeos/media/media_player_browsertest.cc
deleted file mode 100644
index 6590705..0000000
--- a/chrome/browser/chromeos/media/media_player_browsertest.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 "base/command_line.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/media/media_player.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_iterator.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
-
-class MediaPlayerBrowserTest : public InProcessBrowserTest {
- public:
-  MediaPlayerBrowserTest() {}
-
-  GURL GetMusicTestURL() {
-    return GURL("http://localhost:1337/files/plugin/sample_mp3.mp3");
-  }
-
-  bool IsBrowserVisible(Browser* browser) {
-    if (browser == NULL)
-      return false;
-    for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-      if (it->is_type_popup() && it->is_app() && (*it) == browser)
-        return true;
-    }
-    return false;
-  }
-
-  bool IsPlayerVisible() {
-    return IsBrowserVisible(MediaPlayer::GetInstance()->GetBrowser());
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(MediaPlayerBrowserTest, Popup) {
-  ASSERT_TRUE(test_server()->Start());
-  // Doing this so we have a valid profile.
-  ui_test_utils::NavigateToURL(browser(),
-                               GURL("chrome://downloads"));
-
-  MediaPlayer* player = MediaPlayer::GetInstance();
-  // Check that its not currently visible
-  ASSERT_FALSE(IsPlayerVisible());
-
-  player->PopupMediaPlayer();
-  player->ForcePlayMediaURL(GetMusicTestURL());
-
-  ASSERT_TRUE(IsPlayerVisible());
-}
diff --git a/chrome/browser/chromeos/net/network_change_notifier_network_library.cc b/chrome/browser/chromeos/net/network_change_notifier_network_library.cc
deleted file mode 100644
index d221b66..0000000
--- a/chrome/browser/chromeos/net/network_change_notifier_network_library.cc
+++ /dev/null
@@ -1,348 +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/chromeos/net/network_change_notifier_network_library.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/dns/dns_config_service_posix.h"
-
-using content::BrowserThread;
-
-namespace {
-
-// Delay for online change notification reporting.
-const int kOnlineNotificationDelayMS = 500;
-const int kInitialNotificationCheckDelayMS = 1000;
-
-bool IsOnline(chromeos::ConnectionState state) {
-  return state == chromeos::STATE_ONLINE ||
-         state == chromeos::STATE_PORTAL;
-}
-
-}  // namespace
-
-namespace chromeos {
-
-class NetworkChangeNotifierNetworkLibrary::DnsConfigServiceChromeos
-    : public net::internal::DnsConfigServicePosix {
- public:
-  DnsConfigServiceChromeos() {}
-
-  virtual ~DnsConfigServiceChromeos() {}
-
-  // net::DnsConfigServicePosix:
-  virtual bool StartWatching() OVERRIDE {
-    // Notifications from NetworkLibrary are sent to
-    // NetworkChangeNotifierNetworkLibrary.
-    return true;
-  }
-
-  void OnNetworkChange() {
-    InvalidateConfig();
-    InvalidateHosts();
-    ReadNow();
-  }
-};
-
-NetworkChangeNotifierNetworkLibrary::NetworkChangeNotifierNetworkLibrary()
-    : NetworkChangeNotifier(NetworkChangeCalculatorParamsChromeos()),
-      has_active_network_(false),
-      connection_state_(chromeos::STATE_UNKNOWN),
-      connection_type_(CONNECTION_NONE),
-      weak_factory_(this) {
-  BrowserThread::PostDelayedTask(
-         BrowserThread::UI, FROM_HERE,
-         base::Bind(
-             &NetworkChangeNotifierNetworkLibrary::UpdateInitialState, this),
-         base::TimeDelta::FromMilliseconds(kInitialNotificationCheckDelayMS));
-}
-
-NetworkChangeNotifierNetworkLibrary::~NetworkChangeNotifierNetworkLibrary() {
-}
-
-void NetworkChangeNotifierNetworkLibrary::Init() {
-  chromeos::NetworkLibrary* network_library =
-      chromeos::NetworkLibrary::Get();
-  network_library->AddNetworkManagerObserver(this);
-  DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
-
-  dns_config_service_.reset(new DnsConfigServiceChromeos());
-  dns_config_service_->WatchConfig(
-      base::Bind(NetworkChangeNotifier::SetDnsConfig));
-
-  UpdateNetworkState(network_library);
-}
-
-void NetworkChangeNotifierNetworkLibrary::Shutdown() {
-  weak_factory_.InvalidateWeakPtrs();
-
-  dns_config_service_.reset();
-
-  if (!NetworkLibrary::Get())
-    return;
-
-  chromeos::NetworkLibrary* lib =
-      chromeos::NetworkLibrary::Get();
-  lib->RemoveNetworkManagerObserver(this);
-  lib->RemoveObserverForAllNetworks(this);
-
-  DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
-}
-
-void NetworkChangeNotifierNetworkLibrary::SystemResumed(
-    const base::TimeDelta& sleep_duration) {
-  // Force invalidation of various net resources on system resume.
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(
-          &NetworkChangeNotifier::NotifyObserversOfIPAddressChange));
-}
-
-void NetworkChangeNotifierNetworkLibrary::OnNetworkManagerChanged(
-    chromeos::NetworkLibrary* cros) {
-  UpdateNetworkState(cros);
-}
-
-net::NetworkChangeNotifier::ConnectionType
-NetworkChangeNotifierNetworkLibrary::GetCurrentConnectionType() const {
-  return connection_type_;
-}
-
-void NetworkChangeNotifierNetworkLibrary::OnNetworkChanged(
-    chromeos::NetworkLibrary* cros,
-    const chromeos::Network* network) {
-  CHECK(network);
-
-  // Active network changed?
-  if (network->service_path() != service_path_)
-    UpdateNetworkState(cros);
-  else
-    UpdateConnectivityState(network);
-}
-
-void NetworkChangeNotifierNetworkLibrary::UpdateNetworkState(
-    chromeos::NetworkLibrary* lib) {
-  const chromeos::Network* network = lib->active_network();
-  // For VPN networks, the device path is empty. See crbug.com/222251
-  if (network && network->type() != TYPE_VPN) {
-    lib->GetIPConfigs(
-        network->device_path(),
-        chromeos::NetworkLibrary::FORMAT_COLON_SEPARATED_HEX,
-        base::Bind(
-            &NetworkChangeNotifierNetworkLibrary::UpdateNetworkStateCallback,
-            weak_factory_.GetWeakPtr(),
-            lib));
-  } else {
-    // If we don't have a network, then we can't fetch ipconfigs, but we still
-    // need to process state updates when we lose a network (i.e. when
-    // has_active_network_ is still set, but we don't have one anymore).
-    NetworkIPConfigVector empty_ipconfigs;
-    UpdateNetworkStateCallback(lib, empty_ipconfigs, "");
-  }
-}
-
-void NetworkChangeNotifierNetworkLibrary::UpdateNetworkStateCallback(
-    chromeos::NetworkLibrary* lib,
-    const NetworkIPConfigVector& ipconfigs,
-    const std::string& hardware_address) {
-  const chromeos::Network* network = lib->active_network();
-
-  if (network) {
-    VLOG(1) << "UpdateNetworkStateCallback: " << network->name()
-            << ", type= " << network->type()
-            << ", device= " << network->device_path()
-            << ", state= " << network->state();
-  }
-
-  // Find the DNS servers currently in use. This code assumes that the order of
-  // the |ipconfigs| is stable.
-  std::vector<std::string> ipconfig_name_servers;
-  for (chromeos::NetworkIPConfigVector::const_iterator it = ipconfigs.begin();
-       it != ipconfigs.end(); ++it) {
-    const chromeos::NetworkIPConfig& ipconfig = *it;
-    if (!ipconfig.name_servers.empty())
-      ipconfig_name_servers.push_back(ipconfig.name_servers);
-  }
-
-  // Did we loose the active network?
-  bool lost_active_network = !network && has_active_network_;
-
-  // Did we have a change on the current active network?
-  bool changed_active_network = network && (
-      !has_active_network_ ||
-      network->service_path() != service_path_ ||
-      ipconfig_name_servers != name_servers_ ||
-      network->ip_address() != ip_address_);
-
-  // If just the current active network's state changed, update it if necessary.
-  if (!lost_active_network && !changed_active_network &&
-      network && network->state() != connection_state_) {
-    UpdateConnectivityState(network);
-  }
-
-  if (lost_active_network || changed_active_network) {
-    if (has_active_network_)
-      lib->RemoveObserverForAllNetworks(this);
-    if (!network) {
-      has_active_network_ = false;
-      service_path_.clear();
-      ip_address_.clear();
-      name_servers_.clear();
-    } else {
-      has_active_network_ = true;
-      service_path_ = network->service_path();
-      ip_address_ = network->ip_address();
-      name_servers_.swap(ipconfig_name_servers);
-    }
-    dns_config_service_->OnNetworkChange();
-    UpdateConnectivityState(network);
-    // If there is an active network, add observer to track its changes.
-    if (network)
-      lib->AddNetworkObserver(network->service_path(), this);
-
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::Bind(
-            &NetworkChangeNotifier::NotifyObserversOfIPAddressChange));
-  }
-}
-
-void NetworkChangeNotifierNetworkLibrary::UpdateConnectivityState(
-      const chromeos::Network* network) {
-  if (network) {
-    VLOG(1) << "UpdateConnectivityState: " << network->name()
-            << ", type= " << network->type()
-            << ", device= " << network->device_path()
-            << ", state= " << network->state()
-            << ", connect= " << connection_state_
-            << ", type= " << connection_type_;
-  }
-
-  // We don't care about all transitions of ConnectionState.  OnlineStateChange
-  // notification should trigger if ConnectionType is changed.
-  chromeos::ConnectionState new_connection_state =
-      network ? network->connection_state() : chromeos::STATE_UNKNOWN;
-
-  ConnectionType prev_connection_type = connection_type_;
-  ConnectionType new_connection_type = GetNetworkConnectionType(network);
-
-  bool is_online = (new_connection_state == chromeos::STATE_ONLINE);
-  bool was_online = (connection_state_ == chromeos::STATE_ONLINE);
-  bool is_portal = (new_connection_state == chromeos::STATE_PORTAL);
-  bool was_portal = (connection_state_ == chromeos::STATE_PORTAL);
-  VLOG(2) << " UpdateConnectivityState2: "
-          << "new_cs = " << new_connection_state
-          << ", is_online = " << is_online
-          << ", was_online = " << was_online
-          << ", is_portal = " << is_portal
-          << ", was_portal = " << was_portal;
-  connection_state_ = new_connection_state;
-  connection_type_ = new_connection_type;
-  if (new_connection_type != prev_connection_type) {
-    VLOG(1) << "UpdateConnectivityState3: "
-            << "prev_connection_type = " << prev_connection_type
-            << ", new_connection_type = " << new_connection_type;
-    ReportConnectionChange();
-  }
-  VLOG(2) << " UpdateConnectivityState4: "
-          << "new_cs = " << new_connection_state
-          << ", end_cs_ = " << connection_state_
-          << "prev_type = " << prev_connection_type
-          << ", new_type_ = " << new_connection_type;
-}
-
-void NetworkChangeNotifierNetworkLibrary::ReportConnectionChange() {
-  if (weak_factory_.HasWeakPtrs()) {
-    // If we have a pending task, cancel it.
-    DVLOG(1) << "ReportConnectionChange: has pending task";
-    weak_factory_.InvalidateWeakPtrs();
-    DVLOG(1) << "ReportConnectionChange: canceled pending task";
-  }
-  // Posting task with delay allows us to cancel it when connection type is
-  // changed frequently. This should help us avoid transient edge reporting
-  // while switching between connection types (e.g. ethernet->wifi).
-  base::Closure task = base::Bind(
-      &NetworkChangeNotifierNetworkLibrary::ReportConnectionChangeOnUIThread,
-      weak_factory_.GetWeakPtr());
-
-  BrowserThread::PostDelayedTask(
-      BrowserThread::UI, FROM_HERE, task,
-      base::TimeDelta::FromMilliseconds(kOnlineNotificationDelayMS));
-}
-
-void NetworkChangeNotifierNetworkLibrary::ReportConnectionChangeOnUIThread() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(
-         &NetworkChangeNotifierNetworkLibrary::
-             NotifyObserversOfConnectionTypeChange));
-}
-
-// static
-void NetworkChangeNotifierNetworkLibrary::UpdateInitialState(
-    NetworkChangeNotifierNetworkLibrary* self) {
-  chromeos::NetworkLibrary* net = chromeos::NetworkLibrary::Get();
-  self->UpdateNetworkState(net);
-}
-
-// static
-net::NetworkChangeNotifier::ConnectionType
-NetworkChangeNotifierNetworkLibrary::GetNetworkConnectionType(
-    const chromeos::Network* network) {
-  if (!network || !IsOnline(network->connection_state()))
-    return net::NetworkChangeNotifier::CONNECTION_NONE;
-
-  switch (network->type()) {
-    case chromeos::TYPE_ETHERNET:
-      return CONNECTION_ETHERNET;
-    case chromeos::TYPE_WIFI:
-      return CONNECTION_WIFI;
-    case chromeos::TYPE_WIMAX:
-      return CONNECTION_4G;
-    case chromeos::TYPE_CELLULAR:
-      switch (static_cast<const chromeos::CellularNetwork*>(
-          network)->network_technology()) {
-        case chromeos::NETWORK_TECHNOLOGY_UNKNOWN:
-        case chromeos::NETWORK_TECHNOLOGY_1XRTT:
-        case chromeos::NETWORK_TECHNOLOGY_GPRS:
-        case chromeos::NETWORK_TECHNOLOGY_EDGE:
-          return CONNECTION_2G;
-        case chromeos::NETWORK_TECHNOLOGY_GSM:
-        case chromeos::NETWORK_TECHNOLOGY_UMTS:
-        case chromeos::NETWORK_TECHNOLOGY_EVDO:
-        case chromeos::NETWORK_TECHNOLOGY_HSPA:
-          return CONNECTION_3G;
-        case chromeos::NETWORK_TECHNOLOGY_HSPA_PLUS:
-        case chromeos::NETWORK_TECHNOLOGY_LTE:
-        case chromeos::NETWORK_TECHNOLOGY_LTE_ADVANCED:
-          return CONNECTION_4G;
-      }
-    case chromeos::TYPE_BLUETOOTH:
-    case chromeos::TYPE_VPN:
-    case chromeos::TYPE_UNKNOWN:
-      break;
-  }
-  return net::NetworkChangeNotifier::CONNECTION_UNKNOWN;
-}
-
-// static
-net::NetworkChangeNotifier::NetworkChangeCalculatorParams
-NetworkChangeNotifierNetworkLibrary::NetworkChangeCalculatorParamsChromeos() {
-  NetworkChangeCalculatorParams params;
-  // Delay values arrived at by simple experimentation and adjusted so as to
-  // produce a single signal when switching between network connections.
-  params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(4000);
-  params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(1000);
-  params.connection_type_offline_delay_ = base::TimeDelta::FromMilliseconds(0);
-  params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(0);
-  return params;
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/network_change_notifier_network_library.h b/chrome/browser/chromeos/net/network_change_notifier_network_library.h
deleted file mode 100644
index 8cd9eaf..0000000
--- a/chrome/browser/chromeos/net/network_change_notifier_network_library.h
+++ /dev/null
@@ -1,109 +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_CHROMEOS_NET_NETWORK_CHANGE_NOTIFIER_NETWORK_LIBRARY_H_
-#define CHROME_BROWSER_CHROMEOS_NET_NETWORK_CHANGE_NOTIFIER_NETWORK_LIBRARY_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chromeos/dbus/power_manager_client.h"
-#include "net/base/network_change_notifier.h"
-
-namespace chromeos {
-
-class OnlineStatusReportThreadTask;
-
-class NetworkChangeNotifierNetworkLibrary
-    : public net::NetworkChangeNotifier,
-      public chromeos::PowerManagerClient::Observer,
-      public chromeos::NetworkLibrary::NetworkObserver,
-      public chromeos::NetworkLibrary::NetworkManagerObserver {
- public:
-  NetworkChangeNotifierNetworkLibrary();
-  virtual ~NetworkChangeNotifierNetworkLibrary();
-
-  // Initializes the network change notifier. Starts to observe changes
-  // from the power manager and the network manager.
-  void Init();
-
-  // Shutdowns the network change notifier. Stops observing changes from
-  // the power manager and the network manager.
-  void Shutdown();
-
- private:
-  friend class OnlineStatusReportThreadTask;
-
-  class DnsConfigServiceChromeos;
-
-  // PowerManagerClient::Observer overrides:
-  virtual void SystemResumed(const base::TimeDelta& sleep_duration) OVERRIDE;
-
-  // NetworkChangeNotifier overrides:
-  virtual net::NetworkChangeNotifier::ConnectionType
-      GetCurrentConnectionType() const OVERRIDE;
-
-  // NetworkManagerObserver overrides:
-  virtual void OnNetworkManagerChanged(chromeos::NetworkLibrary* obj) OVERRIDE;
-
-  // NetworkObserver overrides:
-  virtual void OnNetworkChanged(chromeos::NetworkLibrary* cros,
-                                const chromeos::Network* network) OVERRIDE;
-
-  // Initiate online status change reporting.
-  void ReportConnectionChange();
-  void ReportConnectionChangeOnUIThread();
-  // Callback from online_notification_task_ when online state notification
-  // is actually scheduled.
-  void OnOnlineStateNotificationFired();
-
-  // Initiates an update of data members that keep the track the network stack
-  // state.
-  void UpdateNetworkState(chromeos::NetworkLibrary* cros);
-  // Called when a network state update has completed. Updates data members that
-  // keep the track the network stack state.
-  void UpdateNetworkStateCallback(chromeos::NetworkLibrary* cros,
-                                  const NetworkIPConfigVector& ip_configs,
-                                  const std::string& hardware_address);
-  // Updates network connectivity state.
-  void UpdateConnectivityState(const chromeos::Network* network);
-
-  // Updates the initial state. Lets us trigger initial eval of the
-  // connectivity status without waiting for an event from the connection
-  // manager.
-  static void UpdateInitialState(NetworkChangeNotifierNetworkLibrary* self);
-
-  // Gets connection type for given |network|.
-  static net::NetworkChangeNotifier::ConnectionType GetNetworkConnectionType(
-      const chromeos::Network* network);
-
-  // Get parameters for calculating new combined signal.
-  static NetworkChangeCalculatorParams NetworkChangeCalculatorParamsChromeos();
-
-  // True if we previously had an active network around.
-  bool has_active_network_;
-  // Current active network's connection state.
-  chromeos::ConnectionState connection_state_;
-  // Current active network's connection type.
-  net::NetworkChangeNotifier::ConnectionType connection_type_;
-  // Current active network's service path.
-  std::string service_path_;
-  // Current active network's IP address.
-  std::string ip_address_;
-  // Current active network's name servers.
-  std::vector<std::string> name_servers_;
-
-  scoped_ptr<DnsConfigServiceChromeos> dns_config_service_;
-
-  base::WeakPtrFactory<NetworkChangeNotifierNetworkLibrary> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierNetworkLibrary);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_NET_NETWORK_CHANGE_NOTIFIER_NETWORK_LIBRARY_H_
diff --git a/chrome/browser/chromeos/net/onc_utils.cc b/chrome/browser/chromeos/net/onc_utils.cc
index 80ec98c..853d52b 100644
--- a/chrome/browser/chromeos/net/onc_utils.cc
+++ b/chrome/browser/chromeos/net/onc_utils.cc
@@ -4,16 +4,28 @@
 
 #include "chrome/browser/chromeos/net/onc_utils.h"
 
+#include "base/bind_helpers.h"
+#include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/ui_proxy_config.h"
 #include "chrome/browser/prefs/proxy_config_dictionary.h"
+#include "chromeos/network/managed_network_configuration_handler.h"
+#include "chromeos/network/network_configuration_handler.h"
+#include "chromeos/network/network_handler.h"
+#include "chromeos/network/network_profile.h"
+#include "chromeos/network/network_profile_handler.h"
+#include "chromeos/network/network_ui_data.h"
+#include "chromeos/network/onc/onc_normalizer.h"
+#include "chromeos/network/onc/onc_signature.h"
+#include "chromeos/network/onc/onc_translator.h"
 #include "chromeos/network/onc/onc_utils.h"
 #include "net/base/host_port_pair.h"
 #include "net/proxy/proxy_bypass_rules.h"
 #include "net/proxy/proxy_server.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
 #include "url/gurl.h"
 
 namespace chromeos {
@@ -153,23 +165,11 @@
   DISALLOW_COPY_AND_ASSIGN(UserStringSubstitution);
 };
 
-const chromeos::User* GetLoggedInUserByHash(const std::string& userhash) {
-  const chromeos::UserList& users =
-      chromeos::UserManager::Get()->GetLoggedInUsers();
-  for (chromeos::UserList::const_iterator it = users.begin(); it != users.end();
-       ++it) {
-    if ((*it)->username_hash() == userhash)
-      return *it;
-  }
-  return NULL;
-}
-
 }  // namespace
 
 void ExpandStringPlaceholdersInNetworksForUser(
-    const std::string& hashed_username,
+    const chromeos::User* user,
     base::ListValue* network_configs) {
-  const chromeos::User* user = GetLoggedInUserByHash(hashed_username);
   if (!user) {
     // In tests no user may be logged in. It's not harmful if we just don't
     // expand the strings.
@@ -179,5 +179,66 @@
   chromeos::onc::ExpandStringsInNetworks(substitution, network_configs);
 }
 
+void ImportNetworksForUser(const chromeos::User* user,
+                           const base::ListValue& network_configs,
+                           std::string* error) {
+  error->clear();
+
+  scoped_ptr<base::ListValue> expanded_networks(network_configs.DeepCopy());
+  ExpandStringPlaceholdersInNetworksForUser(user, expanded_networks.get());
+
+  const NetworkProfile* profile =
+      NetworkHandler::Get()->network_profile_handler()->GetProfileForUserhash(
+          user->username_hash());
+  if (!profile) {
+    *error = "User profile doesn't exist.";
+    return;
+  }
+
+  for (base::ListValue::const_iterator it = expanded_networks->begin();
+       it != expanded_networks->end();
+       ++it) {
+    const base::DictionaryValue* network = NULL;
+    (*it)->GetAsDictionary(&network);
+    DCHECK(network);
+
+    // Remove irrelevant fields.
+    onc::Normalizer normalizer(true /* remove recommended fields */);
+    scoped_ptr<base::DictionaryValue> normalized_network =
+        normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
+                                   *network);
+
+    scoped_ptr<base::DictionaryValue> shill_dict =
+        onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
+                                       *normalized_network);
+
+    scoped_ptr<NetworkUIData> ui_data = NetworkUIData::CreateFromONC(
+        onc::ONC_SOURCE_USER_IMPORT, *normalized_network);
+    base::DictionaryValue ui_data_dict;
+    ui_data->FillDictionary(&ui_data_dict);
+    std::string ui_data_json;
+    base::JSONWriter::Write(&ui_data_dict, &ui_data_json);
+    shill_dict->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
+                                              ui_data_json);
+
+    shill_dict->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
+                                              profile->path);
+
+    NetworkHandler::Get()->network_configuration_handler()->CreateConfiguration(
+        *shill_dict,
+        network_handler::StringResultCallback(),
+        network_handler::ErrorCallback());
+  }
+}
+
+const base::DictionaryValue* FindPolicyForActiveUser(
+    const std::string& guid,
+    onc::ONCSource* onc_source) {
+  const User* user = UserManager::Get()->GetActiveUser();
+  std::string username_hash = user ? user->username_hash() : std::string();
+  return NetworkHandler::Get()->managed_network_configuration_handler()->
+      FindPolicyByGUID(username_hash, guid, onc_source);
+}
+
 }  // namespace onc
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/net/onc_utils.h b/chrome/browser/chromeos/net/onc_utils.h
index e855494..20ff9c6 100644
--- a/chrome/browser/chromeos/net/onc_utils.h
+++ b/chrome/browser/chromeos/net/onc_utils.h
@@ -16,6 +16,10 @@
 }
 
 namespace chromeos {
+
+class NetworkState;
+class User;
+
 namespace onc {
 
 // Translates |onc_proxy_settings|, which has to be a valid ONC ProxySettings
@@ -32,9 +36,19 @@
 // implemented, which are replaced by attributes of the logged-in user with
 // |hashed_username|.
 void ExpandStringPlaceholdersInNetworksForUser(
-    const std::string& hashed_username,
+    const chromeos::User* user,
     base::ListValue* network_configs);
 
+void ImportNetworksForUser(const chromeos::User* user,
+                           const base::ListValue& network_configs,
+                           std::string* error);
+
+// Looks up the policy for |guid| for the current active user and sets
+// |onc_source| accordingly.
+const base::DictionaryValue* FindPolicyForActiveUser(
+    const std::string& guid,
+    onc::ONCSource* onc_source);
+
 }  // namespace onc
 }  // namespace chromeos
 
diff --git a/chrome/browser/chromeos/net/proxy_config_handler.cc b/chrome/browser/chromeos/net/proxy_config_handler.cc
index 865d664..3586af3 100644
--- a/chrome/browser/chromeos/net/proxy_config_handler.cc
+++ b/chrome/browser/chromeos/net/proxy_config_handler.cc
@@ -89,6 +89,13 @@
   return make_scoped_ptr(new ProxyConfigDictionary(proxy_dict.get()));
 }
 
+void NotifyNetworkStateHandler(const std::string& service_path) {
+  if (NetworkHandler::IsInitialized()) {
+    NetworkHandler::Get()->network_state_handler()->RequestUpdateForNetwork(
+        service_path);
+  }
+}
+
 }  // namespace
 
 namespace proxy_config {
@@ -157,12 +164,12 @@
 
   ProxyPrefs::ProxyMode mode;
   if (!proxy_config.GetMode(&mode) || mode == ProxyPrefs::MODE_DIRECT) {
-    // TODO(pneubeck): Consider removing this legacy code.  Return empty string
-    // for direct mode for portal check to work correctly.
+    // Return empty string for direct mode for portal check to work correctly.
+    // TODO(pneubeck): Consider removing this legacy code.
     shill_service_client->ClearProperty(
         dbus::ObjectPath(network.path()),
         flimflam::kProxyConfigProperty,
-        base::Bind(&base::DoNothing),
+        base::Bind(&NotifyNetworkStateHandler, network.path()),
         base::Bind(&network_handler::ShillErrorCallbackFunction,
                    "SetProxyConfig.ClearProperty Failed",
                    network.path(),
@@ -174,17 +181,12 @@
         dbus::ObjectPath(network.path()),
         flimflam::kProxyConfigProperty,
         base::StringValue(proxy_config_str),
-        base::Bind(&base::DoNothing),
+        base::Bind(&NotifyNetworkStateHandler, network.path()),
         base::Bind(&network_handler::ShillErrorCallbackFunction,
                    "SetProxyConfig.SetProperty Failed",
                    network.path(),
                    network_handler::ErrorCallback()));
   }
-
-  if (NetworkHandler::IsInitialized()) {
-    NetworkHandler::Get()->network_state_handler()
-        ->RequestUpdateForNetwork(network.path());
-  }
 }
 
 void RegisterPrefs(PrefRegistrySimple* registry) {
diff --git a/chrome/browser/chromeos/options/network_connect.cc b/chrome/browser/chromeos/options/network_connect.cc
deleted file mode 100644
index 7305e4b..0000000
--- a/chrome/browser/chromeos/options/network_connect.cc
+++ /dev/null
@@ -1,171 +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/browser/chromeos/options/network_connect.h"
-
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
-#include "ash/system/chromeos/network/network_connect.h"
-#include "ash/system/chromeos/network/network_observer.h"
-#include "ash/system/tray/system_tray_notifier.h"
-#include "base/command_line.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/enrollment_dialog_view.h"
-#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/options/network_config_view.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/webui/chromeos/mobile_setup_dialog.h"
-#include "chrome/common/url_constants.h"
-#include "chromeos/chromeos_switches.h"
-#include "chromeos/network/certificate_pattern.h"
-#include "chromeos/network/managed_network_configuration_handler.h"
-#include "chromeos/network/network_event_log.h"
-#include "chromeos/network/network_handler.h"
-#include "chromeos/network/network_state.h"
-#include "chromeos/network/network_state_handler.h"
-#include "content/public/browser/user_metrics.h"
-#include "grit/generated_resources.h"
-#include "net/base/escape.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace chromeos {
-
-namespace {
-
-void EnrollmentComplete(const std::string& service_path) {
-  NET_LOG_USER("Enrollment Complete", service_path);
-}
-
-}
-
-namespace network_connect {
-
-void ShowMobileSetup(const std::string& service_path) {
-  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
-  const NetworkState* cellular = handler->GetNetworkState(service_path);
-  if (cellular && cellular->type() == flimflam::kTypeCellular &&
-      cellular->activation_state() != flimflam::kActivationStateActivated &&
-      cellular->activate_over_non_cellular_networks() &&
-      !handler->DefaultNetwork()) {
-    std::string technology = cellular->network_technology();
-    ash::NetworkObserver::NetworkType network_type =
-        (technology == flimflam::kNetworkTechnologyLte ||
-         technology == flimflam::kNetworkTechnologyLteAdvanced)
-        ? ash::NetworkObserver::NETWORK_CELLULAR_LTE
-        : ash::NetworkObserver::NETWORK_CELLULAR;
-    ash::Shell::GetInstance()->system_tray_notifier()->NotifySetNetworkMessage(
-        NULL,
-        ash::NetworkObserver::ERROR_CONNECT_FAILED,
-        network_type,
-        l10n_util::GetStringUTF16(IDS_NETWORK_ACTIVATION_ERROR_TITLE),
-        l10n_util::GetStringFUTF16(IDS_NETWORK_ACTIVATION_NEEDS_CONNECTION,
-                                   UTF8ToUTF16((cellular->name()))),
-        std::vector<string16>());
-    return;
-  }
-  MobileSetupDialog::Show(service_path);
-}
-
-void ShowNetworkSettings(const std::string& service_path) {
-  std::string page = chrome::kInternetOptionsSubPage;
-  const NetworkState* network = service_path.empty() ? NULL :
-      NetworkHandler::Get()->network_state_handler()->GetNetworkState(
-          service_path);
-  if (network) {
-    std::string name(network->name());
-    if (name.empty() && network->type() == flimflam::kTypeEthernet)
-      name = l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
-    page += base::StringPrintf(
-        "?servicePath=%s&networkType=%s&networkName=%s",
-        net::EscapeUrlEncodedData(service_path, true).c_str(),
-        net::EscapeUrlEncodedData(network->type(), true).c_str(),
-        net::EscapeUrlEncodedData(name, false).c_str());
-  }
-  content::RecordAction(
-      content::UserMetricsAction("OpenInternetOptionsDialog"));
-  Browser* browser = chrome::FindOrCreateTabbedBrowser(
-      ProfileManager::GetDefaultProfileOrOffTheRecord(),
-      chrome::HOST_DESKTOP_TYPE_ASH);
-  chrome::ShowSettingsSubPage(browser, page);
-}
-
-void HandleUnconfiguredNetwork(const std::string& service_path,
-                               gfx::NativeWindow parent_window) {
-  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
-      GetNetworkState(service_path);
-  if (!network) {
-    NET_LOG_ERROR("Configuring unknown network", service_path);
-    return;
-  }
-
-  if (network->type() == flimflam::kTypeWifi) {
-    // Only show the config view for secure networks, otherwise do nothing.
-    if (network->security() != flimflam::kSecurityNone)
-      NetworkConfigView::Show(service_path, parent_window);
-    return;
-  }
-
-  if (network->type() == flimflam::kTypeWimax ||
-      network->type() == flimflam::kTypeVPN) {
-    NetworkConfigView::Show(service_path, parent_window);
-    return;
-  }
-
-  if (network->type() == flimflam::kTypeCellular) {
-    if (network->activation_state() != flimflam::kActivationStateActivated) {
-      ash::network_connect::ActivateCellular(service_path);
-      return;
-    }
-    if (network->cellular_out_of_credits()) {
-      ShowMobileSetup(service_path);
-      return;
-    }
-    // No special configure or setup for |network|, show the settings UI.
-    ShowNetworkSettings(service_path);
-  }
-  NOTREACHED();
-}
-
-bool EnrollNetwork(const std::string& service_path,
-                   gfx::NativeWindow parent_window) {
-  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
-      GetNetworkState(service_path);
-  if (!network) {
-    NET_LOG_ERROR("Enrolling Unknown network", service_path);
-    return false;
-  }
-  // We skip certificate patterns for device policy ONC so that an unmanaged
-  // user can't get to the place where a cert is presented for them
-  // involuntarily.
-  if (network->ui_data().onc_source() == onc::ONC_SOURCE_DEVICE_POLICY)
-    return false;
-
-  const CertificatePattern& certificate_pattern =
-      network->ui_data().certificate_pattern();
-  if (certificate_pattern.Empty())
-    return false;
-
-  NET_LOG_USER("Enrolling", service_path);
-
-  EnrollmentDelegate* enrollment = CreateEnrollmentDelegate(
-      parent_window, network->name(), ProfileManager::GetDefaultProfile());
-  return enrollment->Enroll(certificate_pattern.enrollment_uri_list(),
-                            base::Bind(&EnrollmentComplete, service_path));
-}
-
-const base::DictionaryValue* FindPolicyForActiveUser(
-    const NetworkState* network,
-    onc::ONCSource* onc_source) {
-  const User* user = UserManager::Get()->GetActiveUser();
-  std::string username_hash = user ? user->username_hash() : std::string();
-  return NetworkHandler::Get()->managed_network_configuration_handler()->
-      FindPolicyByGUID(username_hash, network->guid(), onc_source);
-}
-
-}  // namespace network_connect
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/options/network_connect.h b/chrome/browser/chromeos/options/network_connect.h
deleted file mode 100644
index 2d8acbe..0000000
--- a/chrome/browser/chromeos/options/network_connect.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 CHROME_BROWSER_CHROMEOS_OPTIONS_NETWORK_CONNECT_H_
-#define CHROME_BROWSER_CHROMEOS_OPTIONS_NETWORK_CONNECT_H_
-
-#include <string>
-#include <vector>
-
-#include "chromeos/network/onc/onc_constants.h"
-#include "ui/gfx/native_widget_types.h"  // gfx::NativeWindow
-
-namespace base {
-class DictionaryValue;
-}
-
-namespace chromeos {
-
-class NetworkState;
-
-namespace network_connect {
-
-// Shows the mobile setup dialog which handles:
-// * Activation for non direct-activation networks
-// * Showing network plan info
-void ShowMobileSetup(const std::string& service_path);
-
-// Shows the network settings subpage for |service_path| (or the main
-// network settings page if empty).
-void ShowNetworkSettings(const std::string& service_path);
-
-// Handle an unconfigured network:
-// * Show the Configure dialog for wifi/wimax/VPN
-// * Show the Activation, MobileSetup dialog, or settings page for cellular
-void HandleUnconfiguredNetwork(const std::string& service_path,
-                               gfx::NativeWindow parent_window);
-
-// If the network UIData has a matching enrollment URL, triggers the enrollment
-// dialog and returns true.
-bool EnrollNetwork(const std::string& service_path,
-                   gfx::NativeWindow parent_window);
-
-// Looks up the policy for |network| for the current active user and sets
-// |onc_source| accordingly.
-const base::DictionaryValue* FindPolicyForActiveUser(
-    const NetworkState* network,
-    onc::ONCSource* onc_source);
-
-}  // namespace network_connect
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_OPTIONS_NETWORK_CONNECT_H_
diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc
index 4aa6682..e247b77 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.cc
+++ b/chrome/browser/chromeos/options/vpn_config_view.cc
@@ -9,7 +9,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
-#include "chrome/browser/chromeos/options/network_connect.h"
+#include "chrome/browser/chromeos/net/onc_utils.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/net/x509_certificate_model.h"
 #include "chromeos/network/network_configuration_handler.h"
@@ -275,21 +275,26 @@
 }
 
 views::View* VPNConfigView::GetInitiallyFocusedView() {
-  // Put focus in the first editable field.
-  if (server_textfield_)
-    return server_textfield_;
-  else if (service_textfield_)
-    return service_textfield_;
-  else if (provider_type_combobox_)
-    return provider_type_combobox_;
-  else if (psk_passphrase_textfield_ && psk_passphrase_textfield_->enabled())
-    return psk_passphrase_textfield_;
-  else if (user_cert_combobox_ && user_cert_combobox_->enabled())
-    return user_cert_combobox_;
-  else if (server_ca_cert_combobox_ && server_ca_cert_combobox_->enabled())
-    return server_ca_cert_combobox_;
-  else
-    return NULL;
+  if (service_path_.empty()) {
+    // Put focus in the first editable field.
+    if (server_textfield_)
+      return server_textfield_;
+    else if (service_textfield_)
+      return service_textfield_;
+    else if (provider_type_combobox_)
+      return provider_type_combobox_;
+    else if (psk_passphrase_textfield_ && psk_passphrase_textfield_->enabled())
+      return psk_passphrase_textfield_;
+    else if (user_cert_combobox_ && user_cert_combobox_->enabled())
+      return user_cert_combobox_;
+    else if (server_ca_cert_combobox_ && server_ca_cert_combobox_->enabled())
+      return server_ca_cert_combobox_;
+  }
+  if (user_passphrase_textfield_)
+    return user_passphrase_textfield_;
+  else if (otp_textfield_)
+    return otp_textfield_;
+  return NULL;
 }
 
 bool VPNConfigView::CanLogin() {
@@ -518,17 +523,18 @@
   enable_group_name_ = true;
 
   // Server label and input.
-  // Only provide Server name when configuring a new VPN.
-  if (service_path_.empty()) {
-    layout_->StartRow(0, 0);
-    layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
-      IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME)));
-    server_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
-    server_textfield_->SetController(this);
-    layout_->AddView(server_textfield_);
-    layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
-  } else {
-    server_textfield_ = NULL;
+  layout_->StartRow(0, 0);
+  views::View* server_label =
+      new views::Label(l10n_util::GetStringUTF16(
+          IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME));
+  layout_->AddView(server_label);
+  server_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
+  server_textfield_->SetController(this);
+  layout_->AddView(server_textfield_);
+  layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+  if (!service_path_.empty()) {
+    server_label->SetEnabled(false);
+    server_textfield_->SetEnabled(false);
   }
 
   // Service label and name or input.
@@ -818,8 +824,10 @@
     case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: {
       std::string ca_cert_pem = GetServerCACertPEM();
       if (!ca_cert_pem.empty()) {
-        properties->SetStringWithoutPathExpansion(
-            shill::kL2tpIpsecCaCertPemProperty, ca_cert_pem);
+        base::ListValue* pem_list = new base::ListValue;
+        pem_list->AppendString(ca_cert_pem);
+        properties->SetWithoutPathExpansion(
+            shill::kL2tpIpsecCaCertPemProperty, pem_list);
       }
       properties->SetStringWithoutPathExpansion(
           flimflam::kL2tpIpsecClientCertIdProperty, GetUserCertID());
@@ -841,7 +849,7 @@
       std::string ca_cert_pem = GetServerCACertPEM();
       if (!ca_cert_pem.empty()) {
         base::ListValue* pem_list = new base::ListValue;
-        pem_list->AppendString(GetServerCACertPEM());
+        pem_list->AppendString(ca_cert_pem);
         properties->SetWithoutPathExpansion(
             shill::kOpenVPNCaCertPemProperty, pem_list);
       }
@@ -1037,7 +1045,7 @@
     NetworkPropertyUIData* property_ui_data) {
   onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
   const base::DictionaryValue* onc =
-      network_connect::FindPolicyForActiveUser(network, &onc_source);
+      onc::FindPolicyForActiveUser(network->guid(), &onc_source);
 
   VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->guid();
   property_ui_data->ParseOncProperty(
diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc
index 9827218..ae52f47 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view.cc
@@ -9,7 +9,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
-#include "chrome/browser/chromeos/options/network_connect.h"
+#include "chrome/browser/chromeos/net/onc_utils.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/login/login_state.h"
 #include "chromeos/network/network_configuration_handler.h"
@@ -342,6 +342,8 @@
       user_cert_combobox_(NULL),
       server_ca_cert_label_(NULL),
       server_ca_cert_combobox_(NULL),
+      subject_match_label_(NULL),
+      subject_match_textfield_(NULL),
       identity_label_(NULL),
       identity_textfield_(NULL),
       identity_anonymous_label_(NULL),
@@ -506,6 +508,15 @@
   server_ca_cert_combobox_->ModelChanged();
   server_ca_cert_combobox_->SetSelectedIndex(0);
 
+  // Subject Match
+  bool subject_match_enabled =
+      ca_cert_enabled && eap_method_combobox_ &&
+      eap_method_combobox_->selected_index() == EAP_METHOD_INDEX_TLS;
+  subject_match_label_->SetEnabled(subject_match_enabled);
+  subject_match_textfield_->SetEnabled(subject_match_enabled);
+  if (!subject_match_enabled)
+    subject_match_textfield_->SetText(string16());
+
   // No anonymous identity if no phase 2 auth.
   bool identity_anonymous_enabled = phase_2_auth_enabled;
   identity_anonymous_textfield_->SetEnabled(
@@ -785,6 +796,11 @@
   return server_ca_cert_combobox_->selected_index() == 0;
 }
 
+std::string WifiConfigView::GetEapSubjectMatch() const {
+  DCHECK(subject_match_textfield_);
+  return UTF16ToUTF8(subject_match_textfield_->text());
+}
+
 std::string WifiConfigView::GetEapClientCertPkcs11Id() const {
   DCHECK(user_cert_combobox_);
   if (!HaveUserCerts()) {
@@ -816,6 +832,8 @@
       flimflam::kEapPhase2AuthProperty, GetEapPhase2Auth());
   properties->SetStringWithoutPathExpansion(
       flimflam::kEapAnonymousIdentityProperty, GetEapAnonymousIdentity());
+  properties->SetStringWithoutPathExpansion(
+      shill::kEapSubjectMatchProperty, GetEapSubjectMatch());
 
   // shill requires both CertID and KeyID for TLS connections, despite
   // the fact that by convention they are the same ID.
@@ -979,6 +997,19 @@
         new ControlledSettingIndicatorView(server_ca_cert_ui_data_));
     layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
+    // Subject Match
+    layout->StartRow(0, column_view_set_id);
+    string16 subject_match_label_text = l10n_util::GetStringUTF16(
+        IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_EAP_SUBJECT_MATCH);
+    subject_match_label_ = new views::Label(subject_match_label_text);
+    layout->AddView(subject_match_label_);
+    subject_match_textfield_ =
+        new views::Textfield(views::Textfield::STYLE_DEFAULT);
+    subject_match_textfield_->SetAccessibleName(subject_match_label_text);
+    subject_match_textfield_->SetController(this);
+    layout->AddView(subject_match_textfield_);
+    layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
     // User certificate
     layout->StartRow(0, column_view_set_id);
     string16 user_cert_label_text = l10n_util::GetStringUTF16(
@@ -1001,8 +1032,7 @@
         IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_IDENTITY);
     identity_label_ = new views::Label(identity_label_text);
     layout->AddView(identity_label_);
-    identity_textfield_ = new views::Textfield(
-        views::Textfield::STYLE_DEFAULT);
+    identity_textfield_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
     identity_textfield_->SetAccessibleName(identity_label_text);
     identity_textfield_->SetController(this);
     identity_textfield_->SetEnabled(identity_ui_data_.IsEditable());
@@ -1179,6 +1209,12 @@
     identity_anonymous_textfield_->SetText(UTF8ToUTF16(eap_anonymous_identity));
   }
 
+  // Subject match
+  std::string subject_match;
+  properties.GetStringWithoutPathExpansion(
+      shill::kEapSubjectMatchProperty, &subject_match);
+  subject_match_textfield_->SetText(UTF8ToUTF16(subject_match));
+
   // Server CA certificate.
   if (CaCertActive()) {
     std::string eap_ca_cert_pem;
@@ -1265,7 +1301,7 @@
     const std::string& key) {
   onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
   const base::DictionaryValue* onc =
-      network_connect::FindPolicyForActiveUser(network, &onc_source);
+      onc::FindPolicyForActiveUser(network->guid(), &onc_source);
 
   property_ui_data->ParseOncProperty(
       onc_source,
diff --git a/chrome/browser/chromeos/options/wifi_config_view.h b/chrome/browser/chromeos/options/wifi_config_view.h
index 7956499..497671e 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.h
+++ b/chrome/browser/chromeos/options/wifi_config_view.h
@@ -113,6 +113,7 @@
   std::string GetEapPhase2Auth() const;
   std::string GetEapServerCaCertPEM() const;
   bool GetEapUseSystemCas() const;
+  std::string GetEapSubjectMatch() const;
   std::string GetEapClientCertPkcs11Id() const;
   std::string GetEapIdentity() const;
   std::string GetEapAnonymousIdentity() const;
@@ -175,6 +176,8 @@
   scoped_ptr<internal::ServerCACertComboboxModel>
       server_ca_cert_combobox_model_;
   views::Combobox* server_ca_cert_combobox_;
+  views::Label* subject_match_label_;
+  views::Textfield* subject_match_textfield_;
   views::Label* identity_label_;
   views::Textfield* identity_textfield_;
   views::Label* identity_anonymous_label_;
diff --git a/chrome/browser/chromeos/options/wimax_config_view.cc b/chrome/browser/chromeos/options/wimax_config_view.cc
index 8ea3788..f792b33 100644
--- a/chrome/browser/chromeos/options/wimax_config_view.cc
+++ b/chrome/browser/chromeos/options/wimax_config_view.cc
@@ -10,7 +10,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
-#include "chrome/browser/chromeos/options/network_connect.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/login/login_state.h"
 #include "chromeos/network/network_configuration_handler.h"
diff --git a/chrome/browser/chromeos/policy/cros_enterprise_test_utils.cc b/chrome/browser/chromeos/policy/cros_enterprise_test_utils.cc
new file mode 100644
index 0000000..7c7acaa
--- /dev/null
+++ b/chrome/browser/chromeos/policy/cros_enterprise_test_utils.cc
@@ -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.
+
+#include "chrome/browser/chromeos/policy/cros_enterprise_test_utils.h"
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
+#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h"
+#include "chromeos/chromeos_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace test_utils {
+
+void MarkAsEnterpriseOwned(const std::string& username,
+                           const base::FilePath& temp_dir) {
+  cryptohome::SerializedInstallAttributes install_attrs_proto;
+  cryptohome::SerializedInstallAttributes::Attribute* attribute = NULL;
+
+  attribute = install_attrs_proto.add_attributes();
+  attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseOwned);
+  attribute->set_value("true");
+
+  attribute = install_attrs_proto.add_attributes();
+  attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseUser);
+  attribute->set_value(username);
+
+  const base::FilePath install_attrs_file =
+      temp_dir.AppendASCII("install_attributes.pb");
+  const std::string install_attrs_blob(install_attrs_proto.SerializeAsString());
+  ASSERT_EQ(static_cast<int>(install_attrs_blob.size()),
+            file_util::WriteFile(install_attrs_file,
+                                 install_attrs_blob.c_str(),
+                                 install_attrs_blob.size()));
+  ASSERT_TRUE(PathService::Override(chromeos::FILE_INSTALL_ATTRIBUTES,
+                                    install_attrs_file));
+}
+
+}  // namespace test_utils
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/cros_enterprise_test_utils.h b/chrome/browser/chromeos/policy/cros_enterprise_test_utils.h
new file mode 100644
index 0000000..f3544c2
--- /dev/null
+++ b/chrome/browser/chromeos/policy/cros_enterprise_test_utils.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_CHROMEOS_POLICY_CROS_ENTERPRISE_TEST_UTILS_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_CROS_ENTERPRISE_TEST_UTILS_H_
+
+#include <string>
+
+namespace base {
+class FilePath;
+}
+
+namespace policy {
+
+namespace test_utils {
+
+// Marks the device as enterprise-owned.
+void MarkAsEnterpriseOwned(const std::string& username,
+                           const base::FilePath& temp_dir);
+
+}  // namespace test_utils
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_CROS_ENTERPRISE_TEST_UTILS_H_
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index 77951ff..b3d0c74 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -7,12 +7,18 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
 #include "base/run_loop.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/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
@@ -22,6 +28,7 @@
 #include "chrome/browser/chromeos/login/screens/wizard_screen.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/login/webui_login_view.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
@@ -38,6 +45,8 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/cryptohome_client.h"
@@ -46,10 +55,17 @@
 #include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "crypto/rsa_private_key.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
 
 namespace em = enterprise_management;
 
@@ -61,6 +77,7 @@
 
 namespace {
 
+const char kDomain[] = "example.com";
 const char kAccountId1[] = "dla1@example.com";
 const char kAccountId2[] = "dla2@example.com";
 const char kDisplayName[] = "display name";
@@ -68,6 +85,8 @@
   "chrome://policy",
   "chrome://about",
 };
+const char kExistentTermsOfServicePath[] = "chromeos/enterprise/tos.txt";
+const char kNonexistentTermsOfServicePath[] = "chromeos/enterprise/tos404.txt";
 
 }  // namespace
 
@@ -146,12 +165,6 @@
     device_local_account_policy_.Build();
   }
 
-  void InstallDeviceLocalAccountPolicy() {
-    BuildDeviceLocalAccountPolicy();
-    session_manager_client()->set_device_local_account_policy(
-        kAccountId1, device_local_account_policy_.GetBlob());
-  }
-
   void UploadDeviceLocalAccountPolicy() {
     BuildDeviceLocalAccountPolicy();
     ASSERT_TRUE(session_manager_client()->device_local_account_policy(
@@ -161,6 +174,12 @@
         device_local_account_policy_.payload().SerializeAsString());
   }
 
+  void UploadAndInstallDeviceLocalAccountPolicy() {
+    UploadDeviceLocalAccountPolicy();
+    session_manager_client()->set_device_local_account_policy(
+        kAccountId1, device_local_account_policy_.GetBlob());
+  }
+
   void AddPublicSessionToDevicePolicy(const std::string& username) {
     em::ChromeDeviceSettingsProto& proto(device_policy()->payload());
     em::DeviceLocalAccountInfoProto* account =
@@ -217,7 +236,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DisplayName) {
-  InstallDeviceLocalAccountPolicy();
+  UploadAndInstallDeviceLocalAccountPolicy();
   AddPublicSessionToDevicePolicy(kAccountId1);
 
   content::WindowedNotificationObserver(
@@ -292,7 +311,7 @@
       device_local_account_policy_.payload().mutable_restoreonstartupurls();
   for (size_t i = 0; i < arraysize(kStartupURLs); ++i)
     startup_urls_proto->mutable_value()->add_entries(kStartupURLs[i]);
-  InstallDeviceLocalAccountPolicy();
+  UploadAndInstallDeviceLocalAccountPolicy();
   AddPublicSessionToDevicePolicy(kAccountId1);
 
   // This observes the display name becoming available as this indicates
@@ -302,9 +321,19 @@
       chrome::NOTIFICATION_USER_LIST_CHANGED,
       base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
 
-  chromeos::LoginDisplayHost* host =
-      chromeos::LoginDisplayHostImpl::default_host();
+  // Wait for the login UI to be ready.
+  chromeos::LoginDisplayHostImpl* host =
+      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
+          chromeos::LoginDisplayHostImpl::default_host());
   ASSERT_TRUE(host);
+  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
+  ASSERT_TRUE(oobe_ui);
+  base::RunLoop run_loop;
+  const bool oobe_ui_ready = oobe_ui->IsJSReady(run_loop.QuitClosure());
+  if (!oobe_ui_ready)
+    run_loop.Run();
+
+  // Start login into the device-local account.
   host->StartSignInScreen();
   chromeos::ExistingUserController* controller =
       chromeos::ExistingUserController::current_controller();
@@ -332,12 +361,19 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, TermsOfService) {
-  // Specify Terms of Service. The URL does not really matter as the test does
-  // not wait for the terms to load.
+class TermsOfServiceTest : public DeviceLocalAccountTest,
+                           public testing::WithParamInterface<bool> {
+};
+
+IN_PROC_BROWSER_TEST_P(TermsOfServiceTest, TermsOfServiceScreen) {
+  // Specify Terms of Service URL.
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
   device_local_account_policy_.payload().mutable_termsofserviceurl()->set_value(
-      "http://localhost/tos");
-  InstallDeviceLocalAccountPolicy();
+      embedded_test_server()->GetURL(
+            std::string("/") +
+                (GetParam() ? kExistentTermsOfServicePath
+                            : kNonexistentTermsOfServicePath)).spec());
+  UploadAndInstallDeviceLocalAccountPolicy();
   AddPublicSessionToDevicePolicy(kAccountId1);
 
   // Wait for the device-local account policy to be fully loaded.
@@ -345,10 +381,20 @@
       chrome::NOTIFICATION_USER_LIST_CHANGED,
       base::Bind(&DisplayNameMatches, user_id_1_, kDisplayName)).Wait();
 
-  // Start login into the device-local account.
-  chromeos::LoginDisplayHost* host =
-      chromeos::LoginDisplayHostImpl::default_host();
+  // Wait for the login UI to be ready.
+  chromeos::LoginDisplayHostImpl* host =
+      reinterpret_cast<chromeos::LoginDisplayHostImpl*>(
+          chromeos::LoginDisplayHostImpl::default_host());
   ASSERT_TRUE(host);
+  chromeos::OobeUI* oobe_ui = host->GetOobeUI();
+  ASSERT_TRUE(oobe_ui);
+  base::RunLoop oobe_ui_wait_run_loop;
+  const bool oobe_ui_ready =
+      oobe_ui->IsJSReady(oobe_ui_wait_run_loop.QuitClosure());
+  if (!oobe_ui_ready)
+    oobe_ui_wait_run_loop.Run();
+
+  // Start login into the device-local account.
   host->StartSignInScreen();
   chromeos::ExistingUserController* controller =
       chromeos::ExistingUserController::current_controller();
@@ -357,15 +403,15 @@
 
   // Set up an observer that will quit the message loop when login has succeeded
   // and the first wizard screen, if any, is being shown.
-  base::RunLoop run_loop;
+  base::RunLoop login_wait_run_loop;
   chromeos::MockConsumer login_status_consumer;
   EXPECT_CALL(login_status_consumer, OnLoginSuccess(_, false, false))
       .Times(1)
-      .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+      .WillOnce(InvokeWithoutArgs(&login_wait_run_loop, &base::RunLoop::Quit));
 
   // Spin the loop until the observer fires. Then, unregister the observer.
   controller->set_login_status_consumer(&login_status_consumer);
-  run_loop.Run();
+  login_wait_run_loop.Run();
   controller->set_login_status_consumer(NULL);
 
   // Verify that the Terms of Service screen is being shown.
@@ -375,6 +421,104 @@
   ASSERT_TRUE(wizard_controller->current_screen());
   EXPECT_EQ(chromeos::WizardController::kTermsOfServiceScreenName,
             wizard_controller->current_screen()->GetName());
+
+  // Wait for the Terms of Service to finish downloading, then get the status of
+  // the screen's UI elements.
+  chromeos::WebUILoginView* web_ui_login_view = host->GetWebUILoginView();
+  ASSERT_TRUE(web_ui_login_view);
+  content::WebUI* web_ui = web_ui_login_view->GetWebUI();
+  ASSERT_TRUE(web_ui);
+  content::WebContents* contents = web_ui->GetWebContents();
+  ASSERT_TRUE(contents);
+  std::string json;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents,
+      "var screen = document.getElementById('terms-of-service');"
+      "function SendReplyIfDownloadDone() {"
+      "  if (screen.classList.contains('tos-loading'))"
+      "    return false;"
+      "  var status = {};"
+      "  status.heading = document.getElementById('tos-heading').textContent;"
+      "  status.subheading ="
+      "      document.getElementById('tos-subheading').textContent;"
+      "  status.contentHeading ="
+      "      document.getElementById('tos-content-heading').textContent;"
+      "  status.content ="
+      "      document.getElementById('tos-content-main').textContent;"
+      "  status.error = screen.classList.contains('error');"
+      "  status.acceptEnabled ="
+      "      !document.getElementById('tos-accept-button').disabled;"
+      "  domAutomationController.send(JSON.stringify(status));"
+      "  observer.disconnect();"
+      "  return true;"
+      "}"
+      "var observer = new MutationObserver(SendReplyIfDownloadDone);"
+      "if (!SendReplyIfDownloadDone()) {"
+      "  var options = { attributes: true, attributeFilter: [ 'class' ] };"
+      "  observer.observe(screen, options);"
+      "}",
+      &json));
+  scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
+  const base::DictionaryValue* status = NULL;
+  ASSERT_TRUE(value_ptr.get());
+  ASSERT_TRUE(value_ptr->GetAsDictionary(&status));
+  std::string heading;
+  EXPECT_TRUE(status->GetString("heading", &heading));
+  std::string subheading;
+  EXPECT_TRUE(status->GetString("subheading", &subheading));
+  std::string content_heading;
+  EXPECT_TRUE(status->GetString("contentHeading", &content_heading));
+  std::string content;
+  EXPECT_TRUE(status->GetString("content", &content));
+  bool error;
+  EXPECT_TRUE(status->GetBoolean("error", &error));
+  bool accept_enabled;
+  EXPECT_TRUE(status->GetBoolean("acceptEnabled", &accept_enabled));
+
+  // Verify that the screen's headings have been set correctly.
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_HEADING,
+                                UTF8ToUTF16(kDomain)),
+      heading);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_SUBHEADING,
+                                UTF8ToUTF16(kDomain)),
+      subheading);
+  EXPECT_EQ(
+      l10n_util::GetStringFUTF8(IDS_TERMS_OF_SERVICE_SCREEN_CONTENT_HEADING,
+                                UTF8ToUTF16(kDomain)),
+      content_heading);
+
+  if (!GetParam()) {
+    // The Terms of Service URL was invalid. Verify that the screen is showing
+    // an error and the accept button is disabled.
+    EXPECT_TRUE(error);
+    EXPECT_FALSE(accept_enabled);
+    return;
+  }
+
+  // The Terms of Service URL was valid. Verify that the screen is showing the
+  // downloaded Terms of Service and the accept button is enabled.
+  base::FilePath test_dir;
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
+  std::string terms_of_service;
+  ASSERT_TRUE(file_util::ReadFileToString(
+      test_dir.Append(kExistentTermsOfServicePath), &terms_of_service));
+  EXPECT_EQ(terms_of_service, content);
+  EXPECT_FALSE(error);
+  EXPECT_TRUE(accept_enabled);
+
+  // Click the accept button.
+  ASSERT_TRUE(content::ExecuteScript(contents,
+                                     "$('tos-accept-button').click();"));
+
+  // Wait for the session to start.
+  if (!IsSessionStarted()) {
+    content::WindowedNotificationObserver(chrome::NOTIFICATION_SESSION_STARTED,
+                                          base::Bind(IsSessionStarted)).Wait();
+  }
 }
 
+INSTANTIATE_TEST_CASE_P(TermsOfServiceTestInstance,
+                        TermsOfServiceTest, testing::Bool());
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
index 1ee5ae9..d368d53 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.cc
@@ -4,18 +4,17 @@
 
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 
-#include <string>
 #include <vector>
 
 #include "base/file_util.h"
 #include "base/files/file_path.h"
-#include "base/files/scoped_temp_dir.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
+#include "chrome/browser/chromeos/policy/cros_enterprise_test_utils.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
-#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
-#include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h"
+#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
 #include "chromeos/chromeos_paths.h"
+#include "chromeos/dbus/fake_session_manager_client.h"
 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
 #include "crypto/rsa_private_key.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -28,27 +27,9 @@
 namespace policy {
 
 void DevicePolicyCrosBrowserTest::MarkAsEnterpriseOwned() {
-  cryptohome::SerializedInstallAttributes install_attrs_proto;
-  cryptohome::SerializedInstallAttributes::Attribute* attribute = NULL;
-
-  attribute = install_attrs_proto.add_attributes();
-  attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseOwned);
-  attribute->set_value("true");
-
-  attribute = install_attrs_proto.add_attributes();
-  attribute->set_name(EnterpriseInstallAttributes::kAttrEnterpriseUser);
-  attribute->set_value(DevicePolicyBuilder::kFakeUsername);
-
-  base::FilePath install_attrs_file =
-      temp_dir_.path().AppendASCII("install_attributes.pb");
-  const std::string install_attrs_blob(
-      install_attrs_proto.SerializeAsString());
-  ASSERT_EQ(static_cast<int>(install_attrs_blob.size()),
-            file_util::WriteFile(install_attrs_file,
-                                 install_attrs_blob.c_str(),
-                                 install_attrs_blob.size()));
-  ASSERT_TRUE(PathService::Override(chromeos::FILE_INSTALL_ATTRIBUTES,
-                                    install_attrs_file));
+  ASSERT_TRUE(temp_dir_.IsValid());
+  test_utils::MarkAsEnterpriseOwned(DevicePolicyBuilder::kFakeUsername,
+                                    temp_dir_.path());
 }
 
 DevicePolicyCrosBrowserTest::DevicePolicyCrosBrowserTest()
@@ -61,7 +42,7 @@
 
 void DevicePolicyCrosBrowserTest::SetUpInProcessBrowserTestFixture() {
   chromeos::DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager_);
-  CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+  InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
 }
 
 void DevicePolicyCrosBrowserTest::InstallOwnerKey() {
@@ -88,7 +69,7 @@
 }
 
 void DevicePolicyCrosBrowserTest::TearDownInProcessBrowserTestFixture() {
-  CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
+  InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
   chromeos::DBusThreadManager::Shutdown();
 }
 
diff --git a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
index 41efb7f..d00becc 100644
--- a/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
+++ b/chrome/browser/chromeos/policy/device_policy_cros_browser_test.h
@@ -8,18 +8,19 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/files/scoped_temp_dir.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
-#include "chrome/browser/policy/proto/chromeos/chrome_device_policy.pb.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace chromeos {
+class FakeSessionManagerClient;
+}
+
 namespace policy {
 
 // Used to test Device policy changes in Chrome OS.
-class DevicePolicyCrosBrowserTest :
-    public chromeos::CrosInProcessBrowserTest {
+class DevicePolicyCrosBrowserTest : public InProcessBrowserTest {
  public:
   // Marks the device as enterprise-owned. Must be called to make device
   // policies apply Chrome-wide. If this is not called, device policies will
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index a0438e0..3af92ae 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -640,6 +640,15 @@
                         policy.attestation_settings().attestation_enabled()),
                     NULL);
     }
+    if (policy.attestation_settings().has_content_protection_enabled()) {
+      policies->Set(
+          key::kAttestationForContentProtectionEnabled,
+          POLICY_LEVEL_MANDATORY,
+          POLICY_SCOPE_MACHINE,
+          Value::CreateBooleanValue(
+              policy.attestation_settings().content_protection_enabled()),
+          NULL);
+    }
   }
 
   if (policy.has_login_screen_power_management()) {
diff --git a/chrome/browser/chromeos/policy/enterprise_install_attributes.cc b/chrome/browser/chromeos/policy/enterprise_install_attributes.cc
index 26dfb2b..64d7f42 100644
--- a/chrome/browser/chromeos/policy/enterprise_install_attributes.cc
+++ b/chrome/browser/chromeos/policy/enterprise_install_attributes.cc
@@ -241,6 +241,9 @@
   }
 
   std::string mode = GetDeviceModeString(device_mode);
+  std::string registration_user;
+  if (!user.empty())
+    registration_user = gaia::CanonicalizeEmail(user);
 
   if (device_mode == DEVICE_MODE_CONSUMER_KIOSK) {
     // Set values in the InstallAttrs and lock it.
@@ -250,10 +253,11 @@
       return;
     }
   } else {
-    std::string domain = gaia::ExtractDomainName(user);
+    std::string domain = gaia::ExtractDomainName(registration_user);
     // Set values in the InstallAttrs and lock it.
     if (!cryptohome_->InstallAttributesSet(kAttrEnterpriseOwned, "true") ||
-        !cryptohome_->InstallAttributesSet(kAttrEnterpriseUser, user) ||
+        !cryptohome_->InstallAttributesSet(kAttrEnterpriseUser,
+                                           registration_user) ||
         !cryptohome_->InstallAttributesSet(kAttrEnterpriseDomain, domain) ||
         !cryptohome_->InstallAttributesSet(kAttrEnterpriseMode, mode) ||
         !cryptohome_->InstallAttributesSet(kAttrEnterpriseDeviceId,
@@ -274,15 +278,15 @@
   ReadImmutableAttributes(
       base::Bind(&EnterpriseInstallAttributes::OnReadImmutableAttributes,
                  weak_ptr_factory_.GetWeakPtr(),
-                 user,
+                 registration_user,
                  callback));
 }
 
 void EnterpriseInstallAttributes::OnReadImmutableAttributes(
-    const std::string& user,
+    const std::string& registration_user,
     const LockResultCallback& callback) {
 
-  if (GetRegistrationUser() != user) {
+  if (GetRegistrationUser() != registration_user) {
     LOG(ERROR) << "Locked data doesn't match";
     callback.Run(LOCK_BACKEND_ERROR);
     return;
diff --git a/chrome/browser/chromeos/policy/enterprise_install_attributes_unittest.cc b/chrome/browser/chromeos/policy/enterprise_install_attributes_unittest.cc
index d68c396..5014997 100644
--- a/chrome/browser/chromeos/policy/enterprise_install_attributes_unittest.cc
+++ b/chrome/browser/chromeos/policy/enterprise_install_attributes_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/policy/proto/chromeos/install_attributes.pb.h"
 #include "chromeos/cryptohome/cryptohome_library.h"
 #include "chromeos/dbus/cryptohome_client.h"
+#include "google_apis/gaia/gaia_auth_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace policy {
@@ -28,6 +29,7 @@
 }  // namespace
 
 static const char kTestUser[] = "test@example.com";
+static const char kTestUserCanonicalize[] = "UPPER.CASE@example.com";
 static const char kTestDomain[] = "example.com";
 static const char kTestDeviceId[] = "133750519";
 
@@ -102,6 +104,16 @@
                 kTestDeviceId));
 }
 
+TEST_F(EnterpriseInstallAttributesTest, LockCanonicalize) {
+  EXPECT_EQ(EnterpriseInstallAttributes::LOCK_SUCCESS,
+            LockDeviceAndWaitForResult(
+                kTestUserCanonicalize,
+                DEVICE_MODE_ENTERPRISE,
+                kTestDeviceId));
+  EXPECT_EQ(gaia::CanonicalizeEmail(kTestUserCanonicalize),
+            install_attributes_.GetRegistrationUser());
+}
+
 TEST_F(EnterpriseInstallAttributesTest, IsEnterpriseDevice) {
   install_attributes_.ReadCacheFile(GetTempPath());
   EXPECT_FALSE(install_attributes_.IsEnterpriseDevice());
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater.h b/chrome/browser/chromeos/policy/network_configuration_updater.h
index 5c336c5..4916107 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater.h
+++ b/chrome/browser/chromeos/policy/network_configuration_updater.h
@@ -9,6 +9,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "net/cert/x509_certificate.h"
 
+namespace chromeos {
+class User;
+}
+
 namespace net {
 class CertTrustAnchorProvider;
 }
@@ -30,10 +34,10 @@
   // not applied. This function may trigger immediate policy applications.  Web
   // trust isn't given to certificates imported from ONC by default. Setting
   // |allow_trust_certs_from_policy| to true allows giving Web trust to the
-  // certificates that request it. The pointer |user_policy_service| is
-  // stored until UnsetUserPolicyService is called.
+  // certificates that request it. References to |user_policy_service| and
+  // |user| are stored until UnsetUserPolicyService() is called.
   virtual void SetUserPolicyService(bool allow_trusted_certs_from_policy,
-                                    const std::string& hashed_username,
+                                    const chromeos::User* user,
                                     PolicyService* user_policy_service) = 0;
 
   // Unregisters from the PolicyService previously provided by
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
index de3a821..c14a358 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl.cc
@@ -10,6 +10,7 @@
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/net/onc_utils.h"
 #include "chrome/browser/policy/policy_map.h"
 #include "chromeos/network/managed_network_configuration_handler.h"
@@ -22,12 +23,15 @@
 
 NetworkConfigurationUpdaterImpl::NetworkConfigurationUpdaterImpl(
     PolicyService* device_policy_service,
+    chromeos::ManagedNetworkConfigurationHandler* network_config_handler,
     scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer)
     : device_policy_change_registrar_(device_policy_service,
                                       PolicyNamespace(POLICY_DOMAIN_CHROME,
                                                       std::string())),
       user_policy_service_(NULL),
       device_policy_service_(device_policy_service),
+      user_(NULL),
+      network_config_handler_(network_config_handler),
       certificate_importer_(certificate_importer.Pass()) {
   device_policy_change_registrar_.Observe(
       key::kDeviceOpenNetworkConfiguration,
@@ -52,11 +56,11 @@
 
 void NetworkConfigurationUpdaterImpl::SetUserPolicyService(
     bool allow_trusted_certs_from_policy,
-    const std::string& hashed_username,
+    const chromeos::User* user,
     PolicyService* user_policy_service) {
   VLOG(1) << "Got user policy service.";
   user_policy_service_ = user_policy_service;
-  hashed_username_ = hashed_username;
+  user_ = user;
   if (allow_trusted_certs_from_policy)
     SetAllowTrustedCertsFromPolicy();
 
@@ -160,14 +164,13 @@
       certificates, onc_source, web_trust_certs.get());
 
   std::string userhash;
-  if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY) {
-    userhash = hashed_username_;
-    chromeos::onc::ExpandStringPlaceholdersInNetworksForUser(hashed_username_,
+  if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY && user_) {
+    userhash = user_->username_hash();
+    chromeos::onc::ExpandStringPlaceholdersInNetworksForUser(user_,
                                                              &network_configs);
   }
 
-  chromeos::NetworkHandler::Get()->managed_network_configuration_handler()->
-      SetPolicy(onc_source, userhash, network_configs);
+  network_config_handler_->SetPolicy(onc_source, userhash, network_configs);
 
   if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY)
     SetTrustAnchors(web_trust_certs.Pass());
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl.h b/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
index ad54c63..3cbc216 100644
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl.h
@@ -14,6 +14,8 @@
 }
 
 namespace chromeos {
+class ManagedNetworkConfigurationHandler;
+
 namespace onc {
 class CertificateImporter;
 }
@@ -31,13 +33,14 @@
  public:
   NetworkConfigurationUpdaterImpl(
       PolicyService* device_policy_service,
+      chromeos::ManagedNetworkConfigurationHandler* network_config_handler,
       scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer);
   virtual ~NetworkConfigurationUpdaterImpl();
 
   // NetworkConfigurationUpdater overrides.
   virtual void SetUserPolicyService(
       bool allow_trusted_certs_from_policy,
-      const std::string& hashed_username,
+      const chromeos::User* user,
       PolicyService* user_policy_service) OVERRIDE;
 
   virtual void UnsetUserPolicyService() OVERRIDE;
@@ -68,8 +71,12 @@
    // Used to retrieve device policies.
    PolicyService* device_policy_service_;
 
-   // User hash of the user that the user policy applies to.
-   std::string hashed_username_;
+   // The user for whom the user policy will be applied. The User object must be
+   // valid until UnsetUserPolicyService() is called.
+   const chromeos::User* user_;
+
+   // Pointer to the global singleton or a test instance.
+   chromeos::ManagedNetworkConfigurationHandler* network_config_handler_;
 
    scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer_;
 
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.cc
deleted file mode 100644
index ebcf484..0000000
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.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/chromeos/policy/network_configuration_updater_impl_cros.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/policy/policy_map.h"
-#include "chromeos/network/onc/onc_certificate_importer.h"
-#include "chromeos/network/onc/onc_constants.h"
-#include "chromeos/network/onc/onc_utils.h"
-#include "policy/policy_constants.h"
-
-namespace policy {
-
-NetworkConfigurationUpdaterImplCros::NetworkConfigurationUpdaterImplCros(
-    PolicyService* device_policy_service,
-    chromeos::NetworkLibrary* network_library,
-    scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer)
-    : policy_change_registrar_(
-          device_policy_service,
-          PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())),
-      network_library_(network_library),
-      certificate_importer_(certificate_importer.Pass()),
-      user_policy_service_(NULL),
-      device_policy_service_(device_policy_service) {
-  DCHECK(network_library_);
-  policy_change_registrar_.Observe(
-      key::kDeviceOpenNetworkConfiguration,
-      base::Bind(&NetworkConfigurationUpdaterImplCros::OnPolicyChanged,
-                 base::Unretained(this),
-                 chromeos::onc::ONC_SOURCE_DEVICE_POLICY));
-  policy_change_registrar_.Observe(
-      key::kOpenNetworkConfiguration,
-      base::Bind(&NetworkConfigurationUpdaterImplCros::OnPolicyChanged,
-                 base::Unretained(this),
-                 chromeos::onc::ONC_SOURCE_USER_POLICY));
-
-  network_library_->AddNetworkProfileObserver(this);
-  if (device_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
-    // Apply the current policies immediately.
-    VLOG(1) << "Device policy service is already initialized.";
-    ApplyNetworkConfigurations();
-  } else {
-    device_policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this);
-  }
-}
-
-NetworkConfigurationUpdaterImplCros::~NetworkConfigurationUpdaterImplCros() {
-  network_library_->RemoveNetworkProfileObserver(this);
-  DCHECK(!user_policy_service_);
-  device_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
-}
-
-void NetworkConfigurationUpdaterImplCros::OnProfileListChanged() {
-  VLOG(1) << "Network profile list changed, applying policies.";
-  ApplyNetworkConfigurations();
-}
-
-void NetworkConfigurationUpdaterImplCros::SetUserPolicyService(
-    bool allow_trust_certs_from_policy,
-    const std::string& hashed_username,
-    PolicyService* user_policy_service) {
-  VLOG(1) << "Got user policy service.";
-  user_policy_service_ = user_policy_service;
-  if (allow_trust_certs_from_policy)
-    SetAllowTrustedCertsFromPolicy();
-
-  if (user_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
-    VLOG(1) << "User policy service is already initialized.";
-    ApplyNetworkConfigurations();
-  } else {
-    user_policy_service_->AddObserver(POLICY_DOMAIN_CHROME, this);
-  }
-}
-
-void NetworkConfigurationUpdaterImplCros::UnsetUserPolicyService() {
-  if (!user_policy_service_)
-    return;
-
-  user_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
-  user_policy_service_ = NULL;
-}
-
-void NetworkConfigurationUpdaterImplCros::OnPolicyUpdated(
-    const PolicyNamespace& ns,
-    const PolicyMap& previous,
-    const PolicyMap& current) {
-  // Ignore this call. Policy changes are already observed by the registrar.
-}
-
-void NetworkConfigurationUpdaterImplCros::OnPolicyServiceInitialized(
-    PolicyDomain domain) {
-  if (domain != POLICY_DOMAIN_CHROME)
-    return;
-
-  // We don't know which policy service called this function, thus check
-  // both. Multiple removes are handled gracefully.
-  if (device_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
-    VLOG(1) << "Device policy service initialized.";
-    device_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
-  }
-  if (user_policy_service_ &&
-      user_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
-    VLOG(1) << "User policy service initialized.";
-    user_policy_service_->RemoveObserver(POLICY_DOMAIN_CHROME, this);
-  }
-
-  ApplyNetworkConfigurations();
-}
-
-void NetworkConfigurationUpdaterImplCros::OnPolicyChanged(
-    chromeos::onc::ONCSource onc_source,
-    const base::Value* previous,
-    const base::Value* current) {
-  VLOG(1) << "Policy for ONC source "
-          << chromeos::onc::GetSourceAsString(onc_source) << " changed.";
-  ApplyNetworkConfigurations();
-}
-
-void NetworkConfigurationUpdaterImplCros::ApplyNetworkConfigurations() {
-  if (!device_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME))
-    return;
-
-  ApplyNetworkConfiguration(key::kDeviceOpenNetworkConfiguration,
-                            chromeos::onc::ONC_SOURCE_DEVICE_POLICY,
-                            device_policy_service_);
-  if (user_policy_service_ &&
-      user_policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME)) {
-    ApplyNetworkConfiguration(key::kOpenNetworkConfiguration,
-                              chromeos::onc::ONC_SOURCE_USER_POLICY,
-                              user_policy_service_);
-  }
-}
-
-void NetworkConfigurationUpdaterImplCros::ApplyNetworkConfiguration(
-    const std::string& policy_key,
-    chromeos::onc::ONCSource onc_source,
-    PolicyService* policy_service) {
-  VLOG(1) << "Apply policy for ONC source "
-          << chromeos::onc::GetSourceAsString(onc_source);
-  const PolicyMap& policies = policy_service->GetPolicies(
-      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
-  const base::Value* policy_value = policies.GetValue(policy_key);
-
-  std::string onc_blob;
-  if (policy_value != NULL) {
-    // If the policy is not a string, we issue a warning, but still clear the
-    // network configuration.
-    if (!policy_value->GetAsString(&onc_blob)) {
-      LOG(WARNING) << "ONC policy for source "
-                   << chromeos::onc::GetSourceAsString(onc_source)
-                   << " is not a string value.";
-    }
-  }
-
-  base::ListValue network_configs;
-  base::ListValue certificates;
-  chromeos::onc::ParseAndValidateOncForImport(
-      onc_blob, onc_source, "", &network_configs, &certificates);
-
-  scoped_ptr<net::CertificateList> web_trust_certs(new net::CertificateList);
-  certificate_importer_->ImportCertificates(
-      certificates, onc_source, web_trust_certs.get());
-
-  network_library_->LoadOncNetworks(network_configs, onc_source);
-
-  if (onc_source == chromeos::onc::ONC_SOURCE_USER_POLICY)
-    SetTrustAnchors(web_trust_certs.Pass());
-}
-
-}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h
deleted file mode 100644
index 142e61d..0000000
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h
+++ /dev/null
@@ -1,109 +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_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_CROS_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_CROS_H_
-
-#include <string>
-
-#include "chrome/browser/chromeos/cros/network_constants.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
-#include "chrome/browser/chromeos/policy/network_configuration_updater.h"
-#include "chrome/browser/policy/policy_service.h"
-#include "chromeos/network/network_ui_data.h"
-#include "chromeos/network/onc/onc_constants.h"
-
-namespace base {
-class Value;
-}
-
-namespace chromeos {
-namespace onc {
-class CertificateImporter;
-}
-}
-
-namespace policy {
-
-class PolicyMap;
-
-// DEPRECATED: will be replaced by NetworkConfigurationImpl.
-// This implementation pushes policies through the NetworkLibrary. It applies
-// network policies every time one of the relevant policies or Shill's profiles
-// changed or OnUserPolicyInitialized() is called. If the user policy is
-// available, always both the device and the user policy are applied. Otherwise
-// only the device policy is applied.
-class NetworkConfigurationUpdaterImplCros
-    : public NetworkConfigurationUpdater,
-      public chromeos::NetworkLibrary::NetworkProfileObserver,
-      public PolicyService::Observer {
- public:
-  // The pointer |device_policy_service| is stored. The caller must guarantee
-  // that it's outliving the updater.
-  NetworkConfigurationUpdaterImplCros(
-      PolicyService* device_policy_service,
-      chromeos::NetworkLibrary* network_library,
-      scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer);
-  virtual ~NetworkConfigurationUpdaterImplCros();
-
-  // NetworkProfileObserver overrides.
-  virtual void OnProfileListChanged() OVERRIDE;
-
-  // NetworkConfigurationUpdater overrides.
-
-  // In this implementation, this function applies both device and user policy.
-  virtual void SetUserPolicyService(
-      bool allow_trusted_certs_from_policy,
-      const std::string& hashed_username,
-      PolicyService* user_policy_service) OVERRIDE;
-
-  virtual void UnsetUserPolicyService() OVERRIDE;
-
-  // PolicyService::Observer overrides for both device and user policies.
-  virtual void OnPolicyUpdated(const PolicyNamespace& ns,
-                               const PolicyMap& previous,
-                               const PolicyMap& current) OVERRIDE;
-  virtual void OnPolicyServiceInitialized(PolicyDomain domain) OVERRIDE;
-
- private:
-  // Callback that's called by |policy_service_| if the respective ONC policy
-  // changed.
-  void OnPolicyChanged(chromeos::onc::ONCSource onc_source,
-                       const base::Value* previous,
-                       const base::Value* current);
-
-  // Retrieves the ONC policies from |policy_service_| and pushes the
-  // configurations to |network_library_|. Ensures that a device policy is
-  // always overwritten by a user policy.
-  void ApplyNetworkConfigurations();
-
-  // Push the policy stored at |policy_key| for |onc_source| to
-  // |network_library_|.
-  void ApplyNetworkConfiguration(const std::string& policy_key,
-                                 chromeos::onc::ONCSource onc_source,
-                                 PolicyService* policy_service);
-
-  // Wraps the policy service we read network configuration from.
-  PolicyChangeRegistrar policy_change_registrar_;
-
-  // Network library to write network configuration to.
-  chromeos::NetworkLibrary* network_library_;
-
-  scoped_ptr<chromeos::onc::CertificateImporter> certificate_importer_;
-
-  // Needed to check whether user policies are ready.
-  // Unowned.
-  PolicyService* user_policy_service_;
-
-  // The device policy service storing the ONC policies. Also needed to check
-  // whether device policies are ready.
-  // Unowned.
-  PolicyService* device_policy_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(NetworkConfigurationUpdaterImplCros);
-};
-
-}  // namespace policy
-
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_NETWORK_CONFIGURATION_UPDATER_IMPL_CROS_H_
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc
deleted file mode 100644
index 6208711..0000000
--- a/chrome/browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc
+++ /dev/null
@@ -1,418 +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/chromeos/policy/network_configuration_updater_impl_cros.h"
-
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/values.h"
-#include "chrome/browser/chromeos/cros/mock_network_library.h"
-#include "chrome/browser/policy/external_data_fetcher.h"
-#include "chrome/browser/policy/mock_configuration_policy_provider.h"
-#include "chrome/browser/policy/policy_map.h"
-#include "chrome/browser/policy/policy_service_impl.h"
-#include "chromeos/network/onc/mock_certificate_importer.h"
-#include "chromeos/network/onc/onc_constants.h"
-#include "chromeos/network/onc/onc_test_utils.h"
-#include "chromeos/network/onc/onc_utils.h"
-#include "content/public/test/test_browser_thread.h"
-#include "content/public/test/test_utils.h"
-#include "net/base/test_data_directory.h"
-#include "net/cert/cert_trust_anchor_provider.h"
-#include "net/cert/x509_certificate.h"
-#include "net/test/cert_test_util.h"
-#include "policy/policy_constants.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::AnyNumber;
-using testing::Mock;
-using testing::Ne;
-using testing::Return;
-using testing::StrictMock;
-using testing::_;
-
-namespace onc = ::chromeos::onc;
-
-namespace policy {
-
-namespace {
-
-const char kFakeONC[] =
-    "{ \"NetworkConfigurations\": ["
-    "    { \"GUID\": \"{485d6076-dd44-6b6d-69787465725f5040}\","
-    "      \"Type\": \"WiFi\","
-    "      \"Name\": \"My WiFi Network\","
-    "      \"WiFi\": {"
-    "        \"SSID\": \"ssid-none\","
-    "        \"Security\": \"None\" }"
-    "    }"
-    "  ],"
-    "  \"Certificates\": ["
-    "    { \"GUID\": \"{f998f760-272b-6939-4c2beffe428697ac}\","
-    "      \"PKCS12\": \"abc\","
-    "       \"Type\": \"Client\" }"
-    "  ],"
-    "  \"Type\": \"UnencryptedConfiguration\""
-    "}";
-
-std::string ValueToString(const base::Value* value) {
-    std::stringstream str;
-    str << *value;
-    return str.str();
-}
-
-// Matcher to match base::Value.
-MATCHER_P(IsEqualTo,
-          value,
-          std::string(negation ? "isn't" : "is") + " equal to " +
-          ValueToString(value)) {
-  return value->Equals(&arg);
-}
-
-ACTION_P(SetCertificateList, list) {
-  *arg2 = list;
-  return true;
-}
-
-ACTION_P(SetImportedCerts, map) {
-  *arg3 = map;
-  return true;
-}
-
-}  // namespace
-
-// Tests of NetworkConfigurationUpdaterImplCros
-class NetworkConfigurationUpdaterTest : public testing::Test {
- protected:
-  NetworkConfigurationUpdaterTest()
-      : ui_thread_(content::BrowserThread::UI, &loop_),
-        io_thread_(content::BrowserThread::IO, &loop_) {}
-
-  virtual void SetUp() OVERRIDE {
-    EXPECT_CALL(provider_, IsInitializationComplete(_))
-        .WillRepeatedly(Return(true));
-    provider_.Init();
-    PolicyServiceImpl::Providers providers;
-    providers.push_back(&provider_);
-    policy_service_.reset(new PolicyServiceImpl(providers));
-
-    empty_network_configs_.reset(new base::ListValue);
-    empty_certificates_.reset(new base::ListValue);
-
-    scoped_ptr<base::DictionaryValue> fake_toplevel_onc =
-        onc::ReadDictionaryFromJson(kFakeONC);
-
-    scoped_ptr<base::Value> network_configs_value;
-    base::ListValue* network_configs = NULL;
-    fake_toplevel_onc->RemoveWithoutPathExpansion(
-        onc::toplevel_config::kNetworkConfigurations,
-        &network_configs_value);
-    network_configs_value.release()->GetAsList(&network_configs);
-    fake_network_configs_.reset(network_configs);
-
-    scoped_ptr<base::Value> certs_value;
-    base::ListValue* certs = NULL;
-    fake_toplevel_onc->RemoveWithoutPathExpansion(
-        onc::toplevel_config::kCertificates,
-        &certs_value);
-    certs_value.release()->GetAsList(&certs);
-    fake_certificates_.reset(certs);
-  }
-
-  virtual void TearDown() OVERRIDE {
-    provider_.Shutdown();
-    content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
-  }
-
-  void UpdateProviderPolicy(const PolicyMap& policy) {
-    provider_.UpdateChromePolicy(policy);
-    base::RunLoop loop;
-    loop.RunUntilIdle();
-  }
-
-  // Maps configuration policy name to corresponding ONC source.
-  static onc::ONCSource NameToONCSource(
-      const std::string& name) {
-    if (name == key::kDeviceOpenNetworkConfiguration)
-      return onc::ONC_SOURCE_DEVICE_POLICY;
-    if (name == key::kOpenNetworkConfiguration)
-      return onc::ONC_SOURCE_USER_POLICY;
-    return onc::ONC_SOURCE_NONE;
-  }
-
-  scoped_ptr<base::ListValue> empty_network_configs_;
-  scoped_ptr<base::ListValue> empty_certificates_;
-  scoped_ptr<base::ListValue> fake_network_configs_;
-  scoped_ptr<base::ListValue> fake_certificates_;
-  StrictMock<chromeos::MockNetworkLibrary> network_library_;
-  StrictMock<MockConfigurationPolicyProvider> provider_;
-  scoped_ptr<PolicyServiceImpl> policy_service_;
-  base::MessageLoop loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread io_thread_;
-};
-
-TEST_F(NetworkConfigurationUpdaterTest, PolicyIsValidatedAndRepaired) {
-  std::string onc_policy =
-      onc::test_utils::ReadTestData("toplevel_partially_invalid.onc");
-
-  scoped_ptr<base::DictionaryValue> onc_repaired =
-      onc::test_utils::ReadTestDictionary(
-          "repaired_toplevel_partially_invalid.onc");
-
-  base::ListValue* network_configs_repaired = NULL;
-  onc_repaired->GetListWithoutPathExpansion(
-      onc::toplevel_config::kNetworkConfigurations,
-      &network_configs_repaired);
-  ASSERT_TRUE(network_configs_repaired);
-
-  PolicyMap policy;
-  policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
-             POLICY_SCOPE_USER, Value::CreateStringValue(onc_policy), NULL);
-  UpdateProviderPolicy(policy);
-
-  EXPECT_CALL(network_library_, AddNetworkProfileObserver(_));
-
-  // Ignore the device policy update.
-  EXPECT_CALL(network_library_, LoadOncNetworks(_, _));
-  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
-      new StrictMock<chromeos::onc::MockCertificateImporter>();
-  EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _));
-
-  NetworkConfigurationUpdaterImplCros updater(
-      policy_service_.get(),
-      &network_library_,
-      make_scoped_ptr<chromeos::onc::CertificateImporter>(
-          certificate_importer));
-  Mock::VerifyAndClearExpectations(&network_library_);
-  Mock::VerifyAndClearExpectations(&certificate_importer);
-
-  // After the user policy is initialized, we always push both policies to the
-  // NetworkLibrary. Ignore the device policy.
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      _, onc::ONC_SOURCE_DEVICE_POLICY));
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(network_configs_repaired),
-      onc::ONC_SOURCE_USER_POLICY));
-  EXPECT_CALL(*certificate_importer,
-              ImportCertificates(_, chromeos::onc::ONC_SOURCE_DEVICE_POLICY,
-                                 _));
-  EXPECT_CALL(*certificate_importer,
-              ImportCertificates(_, chromeos::onc::ONC_SOURCE_USER_POLICY,
-                                 _));
-
-  EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_));
-
-  updater.SetUserPolicyService(false, "hash", policy_service_.get());
-  updater.UnsetUserPolicyService();
-}
-
-class NetworkConfigurationUpdaterTestWithParam
-    : public NetworkConfigurationUpdaterTest,
-      public testing::WithParamInterface<const char*> {
-};
-
-TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) {
-  PolicyMap policy;
-  policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             Value::CreateStringValue(kFakeONC), NULL);
-  UpdateProviderPolicy(policy);
-
-  EXPECT_CALL(network_library_, AddNetworkProfileObserver(_));
-
-  // Initially, only the device policy is applied. The user policy is only
-  // applied after the user profile was initialized.
-  base::ListValue* device_networks;
-  base::ListValue* device_certs;
-  base::ListValue* user_networks;
-  base::ListValue* user_certs;
-  if (GetParam() == key::kDeviceOpenNetworkConfiguration) {
-    device_networks = fake_network_configs_.get();
-    device_certs = fake_certificates_.get();
-    user_networks = empty_network_configs_.get();
-    user_certs = empty_certificates_.get();
-  } else {
-    device_networks = empty_network_configs_.get();
-    device_certs = empty_certificates_.get();
-    user_networks = fake_network_configs_.get();
-    user_certs = fake_certificates_.get();
-  }
-
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(device_networks), onc::ONC_SOURCE_DEVICE_POLICY));
-  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
-      new StrictMock<chromeos::onc::MockCertificateImporter>();
-  EXPECT_CALL(*certificate_importer, ImportCertificates(
-      IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _));
-
-  NetworkConfigurationUpdaterImplCros updater(
-      policy_service_.get(),
-      &network_library_,
-      make_scoped_ptr<chromeos::onc::CertificateImporter>(
-          certificate_importer));
-  Mock::VerifyAndClearExpectations(&network_library_);
-  Mock::VerifyAndClearExpectations(&certificate_importer);
-
-  // After the user policy is initialized, we always push both policies to the
-  // NetworkLibrary.
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(device_networks), onc::ONC_SOURCE_DEVICE_POLICY));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(
-      IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _));
-
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(user_networks), onc::ONC_SOURCE_USER_POLICY));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(
-      IsEqualTo(user_certs), onc::ONC_SOURCE_USER_POLICY, _));
-
-  EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_));
-
-  // We just need an initialized PolicyService, so we can reuse
-  // |policy_service_|.
-  updater.SetUserPolicyService(false, "hash", policy_service_.get());
-  updater.UnsetUserPolicyService();
-}
-
-TEST_P(NetworkConfigurationUpdaterTestWithParam,
-       AllowTrustedCertificatesFromPolicy) {
-  EXPECT_CALL(network_library_, AddNetworkProfileObserver(_));
-
-  const net::CertificateList empty_cert_list;
-
-  const net::CertificateList cert_list =
-      net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
-                                         "ok_cert.pem",
-                                         net::X509Certificate::FORMAT_AUTO);
-  ASSERT_EQ(1u, cert_list.size());
-
-  EXPECT_CALL(network_library_, LoadOncNetworks(_, _)).Times(AnyNumber());
-  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
-      new StrictMock<chromeos::onc::MockCertificateImporter>();
-  EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _))
-      .WillRepeatedly(SetCertificateList(empty_cert_list));
-  NetworkConfigurationUpdaterImplCros updater(
-      policy_service_.get(),
-      &network_library_,
-      make_scoped_ptr<chromeos::onc::CertificateImporter>(
-          certificate_importer));
-  net::CertTrustAnchorProvider* trust_provider =
-      updater.GetCertTrustAnchorProvider();
-  ASSERT_TRUE(trust_provider);
-  // The initial list of trust anchors is empty.
-  content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
-  EXPECT_TRUE(trust_provider->GetAdditionalTrustAnchors().empty());
-
-  // Initially, certificates imported from policy don't have trust flags.
-  updater.SetUserPolicyService(false, "hash", policy_service_.get());
-  content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
-  Mock::VerifyAndClearExpectations(&network_library_);
-  Mock::VerifyAndClearExpectations(&certificate_importer);
-  EXPECT_TRUE(trust_provider->GetAdditionalTrustAnchors().empty());
-
-  // Certificates with the "Web" trust flag set should be forwarded to the
-  // trust provider.
-  EXPECT_CALL(network_library_, LoadOncNetworks(_, _));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _))
-      .WillRepeatedly(SetCertificateList(empty_cert_list));
-  onc::ONCSource current_source = NameToONCSource(GetParam());
-  EXPECT_CALL(network_library_, LoadOncNetworks(_, current_source));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(_, current_source, _))
-      .WillRepeatedly(SetCertificateList(cert_list));
-  // Trigger a new policy load, and spin the IO message loop to pass the
-  // certificates to the |trust_provider| on the IO thread.
-  updater.SetUserPolicyService(true, "hash", policy_service_.get());
-  base::RunLoop loop;
-  loop.RunUntilIdle();
-  Mock::VerifyAndClearExpectations(&network_library_);
-  Mock::VerifyAndClearExpectations(&certificate_importer);
-
-  // Certificates are only provided as trust anchors if they come from user
-  // policy.
-  size_t expected_certs = 0u;
-  if (GetParam() == key::kOpenNetworkConfiguration)
-    expected_certs = 1u;
-  EXPECT_EQ(expected_certs,
-            trust_provider->GetAdditionalTrustAnchors().size());
-
-  EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_));
-  updater.UnsetUserPolicyService();
-}
-
-TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) {
-  EXPECT_CALL(network_library_, AddNetworkProfileObserver(_));
-
-  // Ignore the initial updates.
-  EXPECT_CALL(network_library_, LoadOncNetworks(_, _))
-      .Times(AnyNumber());
-  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
-      new StrictMock<chromeos::onc::MockCertificateImporter>();
-  EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _))
-      .Times(AnyNumber());
-  NetworkConfigurationUpdaterImplCros updater(
-      policy_service_.get(),
-      &network_library_,
-      make_scoped_ptr<chromeos::onc::CertificateImporter>(
-          certificate_importer));
-  updater.SetUserPolicyService(false, "hash", policy_service_.get());
-  Mock::VerifyAndClearExpectations(&network_library_);
-  Mock::VerifyAndClearExpectations(&certificate_importer);
-
-  // We should update if policy changes.
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(fake_network_configs_.get()), NameToONCSource(GetParam())));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(
-      IsEqualTo(fake_certificates_.get()), NameToONCSource(GetParam()), _));
-
-  // In the current implementation, we always apply both policies.
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(empty_network_configs_.get()),
-      Ne(NameToONCSource(GetParam()))));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(
-      IsEqualTo(empty_certificates_.get()),
-      Ne(NameToONCSource(GetParam())),
-      _));
-
-  PolicyMap policy;
-  policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
-             Value::CreateStringValue(kFakeONC), NULL);
-  UpdateProviderPolicy(policy);
-  Mock::VerifyAndClearExpectations(&network_library_);
-  Mock::VerifyAndClearExpectations(&certificate_importer);
-
-  // Another update is expected if the policy goes away. In the current
-  // implementation, we always apply both policies.
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(empty_network_configs_.get()),
-      onc::ONC_SOURCE_DEVICE_POLICY));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(
-      IsEqualTo(empty_certificates_.get()),
-      onc::ONC_SOURCE_DEVICE_POLICY,
-      _));
-
-  EXPECT_CALL(network_library_, LoadOncNetworks(
-      IsEqualTo(empty_network_configs_.get()),
-      onc::ONC_SOURCE_USER_POLICY));
-  EXPECT_CALL(*certificate_importer, ImportCertificates(
-      IsEqualTo(empty_certificates_.get()),
-      onc::ONC_SOURCE_USER_POLICY,
-      _));
-
-  EXPECT_CALL(network_library_, RemoveNetworkProfileObserver(_));
-
-  policy.Erase(GetParam());
-  UpdateProviderPolicy(policy);
-  updater.UnsetUserPolicyService();
-}
-
-INSTANTIATE_TEST_CASE_P(
-    NetworkConfigurationUpdaterTestWithParamInstance,
-    NetworkConfigurationUpdaterTestWithParam,
-    testing::Values(key::kDeviceOpenNetworkConfiguration,
-                    key::kOpenNetworkConfiguration));
-
-}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_impl_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_impl_unittest.cc
new file mode 100644
index 0000000..3d60a72
--- /dev/null
+++ b/chrome/browser/chromeos/policy/network_configuration_updater_impl_unittest.cc
@@ -0,0 +1,395 @@
+// Copyright 2013 The Chromium Authors. 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/policy/network_configuration_updater_impl.h"
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/policy/external_data_fetcher.h"
+#include "chrome/browser/policy/mock_configuration_policy_provider.h"
+#include "chrome/browser/policy/policy_map.h"
+#include "chrome/browser/policy/policy_service_impl.h"
+#include "chromeos/network/mock_managed_network_configuration_handler.h"
+#include "chromeos/network/onc/mock_certificate_importer.h"
+#include "chromeos/network/onc/onc_constants.h"
+#include "chromeos/network/onc/onc_test_utils.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_utils.h"
+#include "net/base/test_data_directory.h"
+#include "net/cert/cert_trust_anchor_provider.h"
+#include "net/cert/x509_certificate.h"
+#include "net/test/cert_test_util.h"
+#include "policy/policy_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::AnyNumber;
+using testing::Mock;
+using testing::Ne;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace onc = ::chromeos::onc;
+
+namespace policy {
+
+namespace {
+const char kFakeUserEmail[] = "fake email";
+const char kFakeUsernameHash[] = "fake hash";
+
+class FakeUser : public chromeos::User {
+ public:
+  FakeUser() : User(kFakeUserEmail) {
+    set_display_email(kFakeUserEmail);
+    set_username_hash(kFakeUsernameHash);
+  }
+  virtual ~FakeUser() {}
+
+  // User overrides
+  virtual UserType GetType() const OVERRIDE {
+    return USER_TYPE_REGULAR;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeUser);
+};
+
+const char kFakeONC[] =
+    "{ \"NetworkConfigurations\": ["
+    "    { \"GUID\": \"{485d6076-dd44-6b6d-69787465725f5040}\","
+    "      \"Type\": \"WiFi\","
+    "      \"Name\": \"My WiFi Network\","
+    "      \"WiFi\": {"
+    "        \"SSID\": \"ssid-none\","
+    "        \"Security\": \"None\" }"
+    "    }"
+    "  ],"
+    "  \"Certificates\": ["
+    "    { \"GUID\": \"{f998f760-272b-6939-4c2beffe428697ac}\","
+    "      \"PKCS12\": \"abc\","
+    "       \"Type\": \"Client\" }"
+    "  ],"
+    "  \"Type\": \"UnencryptedConfiguration\""
+    "}";
+
+std::string ValueToString(const base::Value* value) {
+    std::stringstream str;
+    str << *value;
+    return str.str();
+}
+
+// Matcher to match base::Value.
+MATCHER_P(IsEqualTo,
+          value,
+          std::string(negation ? "isn't" : "is") + " equal to " +
+          ValueToString(value)) {
+  return value->Equals(&arg);
+}
+
+ACTION_P(SetCertificateList, list) {
+  *arg2 = list;
+  return true;
+}
+
+ACTION_P(SetImportedCerts, map) {
+  *arg3 = map;
+  return true;
+}
+
+}  // namespace
+
+class NetworkConfigurationUpdaterTest : public testing::Test {
+ protected:
+  NetworkConfigurationUpdaterTest()
+      : ui_thread_(content::BrowserThread::UI, &loop_),
+        io_thread_(content::BrowserThread::IO, &loop_) {}
+
+  virtual void SetUp() OVERRIDE {
+    EXPECT_CALL(provider_, IsInitializationComplete(_))
+        .WillRepeatedly(Return(true));
+    provider_.Init();
+    PolicyServiceImpl::Providers providers;
+    providers.push_back(&provider_);
+    policy_service_.reset(new PolicyServiceImpl(providers));
+
+    empty_network_configs_.reset(new base::ListValue);
+    empty_certificates_.reset(new base::ListValue);
+
+    scoped_ptr<base::DictionaryValue> fake_toplevel_onc =
+        onc::ReadDictionaryFromJson(kFakeONC);
+
+    scoped_ptr<base::Value> network_configs_value;
+    base::ListValue* network_configs = NULL;
+    fake_toplevel_onc->RemoveWithoutPathExpansion(
+        onc::toplevel_config::kNetworkConfigurations, &network_configs_value);
+    network_configs_value.release()->GetAsList(&network_configs);
+    fake_network_configs_.reset(network_configs);
+
+    scoped_ptr<base::Value> certs_value;
+    base::ListValue* certs = NULL;
+    fake_toplevel_onc->RemoveWithoutPathExpansion(
+        onc::toplevel_config::kCertificates, &certs_value);
+    certs_value.release()->GetAsList(&certs);
+    fake_certificates_.reset(certs);
+  }
+
+  virtual void TearDown() OVERRIDE {
+    provider_.Shutdown();
+    content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
+  }
+
+  void UpdateProviderPolicy(const PolicyMap& policy) {
+    provider_.UpdateChromePolicy(policy);
+    base::RunLoop loop;
+    loop.RunUntilIdle();
+  }
+
+  scoped_ptr<base::ListValue> empty_network_configs_;
+  scoped_ptr<base::ListValue> empty_certificates_;
+  scoped_ptr<base::ListValue> fake_network_configs_;
+  scoped_ptr<base::ListValue> fake_certificates_;
+  StrictMock<chromeos::MockManagedNetworkConfigurationHandler>
+      network_config_handler_;
+  StrictMock<MockConfigurationPolicyProvider> provider_;
+  scoped_ptr<PolicyServiceImpl> policy_service_;
+  FakeUser fake_user_;
+  base::MessageLoop loop_;
+  content::TestBrowserThread ui_thread_;
+  content::TestBrowserThread io_thread_;
+};
+
+TEST_F(NetworkConfigurationUpdaterTest, PolicyIsValidatedAndRepaired) {
+  std::string onc_policy =
+      onc::test_utils::ReadTestData("toplevel_partially_invalid.onc");
+
+  scoped_ptr<base::DictionaryValue> onc_repaired =
+      onc::test_utils::ReadTestDictionary(
+          "repaired_toplevel_partially_invalid.onc");
+
+  base::ListValue* network_configs_repaired = NULL;
+  onc_repaired->GetListWithoutPathExpansion(
+      onc::toplevel_config::kNetworkConfigurations, &network_configs_repaired);
+  ASSERT_TRUE(network_configs_repaired);
+
+  PolicyMap policy;
+  policy.Set(key::kOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
+             POLICY_SCOPE_USER, Value::CreateStringValue(onc_policy), NULL);
+  UpdateProviderPolicy(policy);
+
+  // Ignore the device policy update.
+  EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _));
+  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
+      new StrictMock<chromeos::onc::MockCertificateImporter>();
+  EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _));
+
+  NetworkConfigurationUpdaterImpl updater(
+      policy_service_.get(),
+      &network_config_handler_,
+      make_scoped_ptr<chromeos::onc::CertificateImporter>(
+          certificate_importer));
+  Mock::VerifyAndClearExpectations(&network_config_handler_);
+  Mock::VerifyAndClearExpectations(&certificate_importer);
+
+  // After the user policy is initialized.
+  EXPECT_CALL(
+      network_config_handler_,
+      SetPolicy(
+          onc::ONC_SOURCE_USER_POLICY, _, IsEqualTo(network_configs_repaired)));
+  EXPECT_CALL(*certificate_importer,
+              ImportCertificates(_, chromeos::onc::ONC_SOURCE_USER_POLICY, _));
+
+  updater.SetUserPolicyService(false, &fake_user_, policy_service_.get());
+  updater.UnsetUserPolicyService();
+}
+
+class NetworkConfigurationUpdaterTestWithParam
+    : public NetworkConfigurationUpdaterTest,
+      public testing::WithParamInterface<const char*> {
+ public:
+  // Returns the currently tested ONC source.
+  onc::ONCSource CurrentONCSource() {
+    if (GetParam() == key::kDeviceOpenNetworkConfiguration)
+      return onc::ONC_SOURCE_DEVICE_POLICY;
+    if (GetParam() == key::kOpenNetworkConfiguration)
+      return onc::ONC_SOURCE_USER_POLICY;
+    return onc::ONC_SOURCE_NONE;
+  }
+};
+
+TEST_P(NetworkConfigurationUpdaterTestWithParam, InitialUpdates) {
+  PolicyMap policy;
+  policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+             Value::CreateStringValue(kFakeONC), NULL);
+  UpdateProviderPolicy(policy);
+
+  // Initially, only the device policy is applied. The user policy is only
+  // applied after the user profile was initialized.
+  base::ListValue* device_networks;
+  base::ListValue* device_certs;
+  base::ListValue* user_networks;
+  base::ListValue* user_certs;
+  if (GetParam() == key::kDeviceOpenNetworkConfiguration) {
+    device_networks = fake_network_configs_.get();
+    device_certs = fake_certificates_.get();
+    user_networks = empty_network_configs_.get();
+    user_certs = empty_certificates_.get();
+  } else {
+    device_networks = empty_network_configs_.get();
+    device_certs = empty_certificates_.get();
+    user_networks = fake_network_configs_.get();
+    user_certs = fake_certificates_.get();
+  }
+
+  EXPECT_CALL(
+      network_config_handler_,
+      SetPolicy(onc::ONC_SOURCE_DEVICE_POLICY, _, IsEqualTo(device_networks)));
+  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
+      new StrictMock<chromeos::onc::MockCertificateImporter>();
+  EXPECT_CALL(*certificate_importer, ImportCertificates(
+      IsEqualTo(device_certs), onc::ONC_SOURCE_DEVICE_POLICY, _));
+
+  NetworkConfigurationUpdaterImpl updater(
+      policy_service_.get(),
+      &network_config_handler_,
+      make_scoped_ptr<chromeos::onc::CertificateImporter>(
+          certificate_importer));
+  Mock::VerifyAndClearExpectations(&network_config_handler_);
+  Mock::VerifyAndClearExpectations(&certificate_importer);
+
+  EXPECT_CALL(
+      network_config_handler_,
+      SetPolicy(onc::ONC_SOURCE_USER_POLICY, _, IsEqualTo(user_networks)));
+  EXPECT_CALL(*certificate_importer, ImportCertificates(
+      IsEqualTo(user_certs), onc::ONC_SOURCE_USER_POLICY, _));
+
+  // We just need an initialized PolicyService, so we can reuse
+  // |policy_service_|.
+  updater.SetUserPolicyService(false, &fake_user_, policy_service_.get());
+  updater.UnsetUserPolicyService();
+}
+
+TEST_P(NetworkConfigurationUpdaterTestWithParam,
+       AllowTrustedCertificatesFromPolicy) {
+  const net::CertificateList empty_cert_list;
+
+  EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _)).Times(AnyNumber());
+  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
+      new StrictMock<chromeos::onc::MockCertificateImporter>();
+  EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _))
+      .WillRepeatedly(SetCertificateList(empty_cert_list));
+  NetworkConfigurationUpdaterImpl updater(
+      policy_service_.get(),
+      &network_config_handler_,
+      make_scoped_ptr<chromeos::onc::CertificateImporter>(
+          certificate_importer));
+  net::CertTrustAnchorProvider* trust_provider =
+      updater.GetCertTrustAnchorProvider();
+  ASSERT_TRUE(trust_provider);
+  // The initial list of trust anchors is empty.
+  content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
+  EXPECT_TRUE(trust_provider->GetAdditionalTrustAnchors().empty());
+
+  // Initially, certificates imported from policy don't have trust flags.
+  updater.SetUserPolicyService(false, &fake_user_, policy_service_.get());
+  content::RunAllPendingInMessageLoop(content::BrowserThread::IO);
+  Mock::VerifyAndClearExpectations(&network_config_handler_);
+  Mock::VerifyAndClearExpectations(&certificate_importer);
+  EXPECT_TRUE(trust_provider->GetAdditionalTrustAnchors().empty());
+
+  // Certificates with the "Web" trust flag set should be forwarded to the
+  // trust provider.
+  EXPECT_CALL(network_config_handler_,
+              SetPolicy(chromeos::onc::ONC_SOURCE_USER_POLICY, _, _));
+
+  net::CertificateList cert_list;
+  if (GetParam() == key::kOpenNetworkConfiguration) {
+    cert_list =
+        net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
+                                           "ok_cert.pem",
+                                           net::X509Certificate::FORMAT_AUTO);
+    ASSERT_EQ(1u, cert_list.size());
+  }
+  EXPECT_CALL(*certificate_importer,
+              ImportCertificates(_, chromeos::onc::ONC_SOURCE_USER_POLICY, _))
+      .WillRepeatedly(SetCertificateList(cert_list));
+
+  // Trigger a new policy load, and spin the IO message loop to pass the
+  // certificates to the |trust_provider| on the IO thread.
+  updater.SetUserPolicyService(true, &fake_user_, policy_service_.get());
+  base::RunLoop loop;
+  loop.RunUntilIdle();
+  Mock::VerifyAndClearExpectations(&network_config_handler_);
+  Mock::VerifyAndClearExpectations(&certificate_importer);
+
+  // Certificates are only provided as trust anchors if they come from user
+  // policy.
+  size_t expected_certs = 0u;
+  if (GetParam() == key::kOpenNetworkConfiguration)
+    expected_certs = 1u;
+  EXPECT_EQ(expected_certs,
+            trust_provider->GetAdditionalTrustAnchors().size());
+
+  updater.UnsetUserPolicyService();
+}
+
+TEST_P(NetworkConfigurationUpdaterTestWithParam, PolicyChange) {
+  // Ignore the initial updates.
+  EXPECT_CALL(network_config_handler_, SetPolicy(_, _, _)).Times(AnyNumber());
+  StrictMock<chromeos::onc::MockCertificateImporter>* certificate_importer =
+      new StrictMock<chromeos::onc::MockCertificateImporter>();
+  EXPECT_CALL(*certificate_importer, ImportCertificates(_, _, _))
+      .Times(AnyNumber());
+  NetworkConfigurationUpdaterImpl updater(
+      policy_service_.get(),
+      &network_config_handler_,
+      make_scoped_ptr<chromeos::onc::CertificateImporter>(
+          certificate_importer));
+  updater.SetUserPolicyService(false, &fake_user_, policy_service_.get());
+  Mock::VerifyAndClearExpectations(&network_config_handler_);
+  Mock::VerifyAndClearExpectations(&certificate_importer);
+
+  // We should update if policy changes.
+  EXPECT_CALL(network_config_handler_,
+              SetPolicy(CurrentONCSource(),
+                        _,
+                        IsEqualTo(fake_network_configs_.get())));
+  EXPECT_CALL(*certificate_importer, ImportCertificates(
+      IsEqualTo(fake_certificates_.get()), CurrentONCSource(), _));
+
+  PolicyMap policy;
+  policy.Set(GetParam(), POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+             Value::CreateStringValue(kFakeONC), NULL);
+  UpdateProviderPolicy(policy);
+  Mock::VerifyAndClearExpectations(&network_config_handler_);
+  Mock::VerifyAndClearExpectations(&certificate_importer);
+
+  // Another update is expected if the policy goes away.
+  EXPECT_CALL(network_config_handler_,
+              SetPolicy(CurrentONCSource(),
+                        _,
+                        IsEqualTo(empty_network_configs_.get())));
+  EXPECT_CALL(*certificate_importer, ImportCertificates(
+      IsEqualTo(empty_certificates_.get()),
+      CurrentONCSource(),
+      _));
+
+  policy.Erase(GetParam());
+  UpdateProviderPolicy(policy);
+  updater.UnsetUserPolicyService();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    NetworkConfigurationUpdaterTestWithParamInstance,
+    NetworkConfigurationUpdaterTestWithParam,
+    testing::Values(key::kDeviceOpenNetworkConfiguration,
+                    key::kOpenNetworkConfiguration));
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
index eb1f266..9d2056d 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
@@ -91,11 +91,11 @@
         chrome::kInitialProfile, scoped_ptr<PrefServiceSyncable>(),
         UTF8ToUTF16("testing_profile"), 0, std::string());
     signin_profile_ = profile_manager_->CreateTestingProfile(kSigninProfile);
-    signin_profile_->set_incognito(true);
+    signin_profile_->ForceIncognito(true);
     // Usually the signin Profile and the main Profile are separate, but since
     // the signin Profile is an OTR Profile then for this test it suffices to
     // attach it to the main Profile.
-    profile_->SetOffTheRecordProfile(signin_profile_);
+    profile_->SetOffTheRecordProfile(scoped_ptr<Profile>(signin_profile_));
     signin_profile_->SetOriginalProfile(profile_);
     ASSERT_EQ(signin_profile_, chromeos::ProfileHelper::GetSigninProfile());
 
diff --git a/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc b/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc
index 852d11c..4e8a0a2 100644
--- a/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc
+++ b/chrome/browser/chromeos/power/peripheral_battery_observer_browsertest.cc
@@ -7,8 +7,8 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread.h"
@@ -31,7 +31,7 @@
 
 namespace chromeos {
 
-class PeripheralBatteryObserverTest : public CrosInProcessBrowserTest {
+class PeripheralBatteryObserverTest : public InProcessBrowserTest {
  public:
   PeripheralBatteryObserverTest () {}
   virtual ~PeripheralBatteryObserverTest () {}
@@ -40,7 +40,7 @@
     MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager =
         new MockDBusThreadManagerWithoutGMock;
     DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
-    CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
   }
 
   virtual void SetUpOnMainThread() OVERRIDE {
@@ -52,7 +52,7 @@
   }
 
   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
-    CrosInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
+    InProcessBrowserTest::TearDownInProcessBrowserTestFixture();
     DBusThreadManager::Shutdown();
   }
 
diff --git a/chrome/browser/chromeos/power/power_prefs_unittest.cc b/chrome/browser/chromeos/power/power_prefs_unittest.cc
index 6b3cd2d..7a28e04 100644
--- a/chrome/browser/chromeos/power/power_prefs_unittest.cc
+++ b/chrome/browser/chromeos/power/power_prefs_unittest.cc
@@ -152,17 +152,19 @@
   scoped_ptr<TestingPrefServiceSyncable> login_profile_prefs(
       new TestingPrefServiceSyncable);
   chrome::RegisterLoginProfilePrefs(login_profile_prefs->registry());
-  scoped_ptr<TestingProfile> login_profile_owner(new TestingProfile(
-      profile_manager_.profiles_dir().AppendASCII(chrome::kInitialProfile),
-      NULL,
-      scoped_refptr<ExtensionSpecialStoragePolicy>(),
-      scoped_ptr<PrefServiceSyncable>(login_profile_prefs.release())));
+  TestingProfile::Builder builder;
+  builder.SetPath(
+      profile_manager_.profiles_dir().AppendASCII(chrome::kInitialProfile));
+  builder.SetPrefService(login_profile_prefs.PassAs<PrefServiceSyncable>());
+  builder.SetIncognito();
+  scoped_ptr<TestingProfile> login_profile_owner(builder.Build());
+
   TestingProfile* login_profile = login_profile_owner.get();
   TestingProfile* login_profile_parent = profile_manager_.CreateTestingProfile(
       chrome::kInitialProfile);
-  login_profile_parent->SetOffTheRecordProfile(login_profile_owner.release());
+  login_profile_parent->SetOffTheRecordProfile(
+      login_profile_owner.PassAs<Profile>());
   login_profile->SetOriginalProfile(login_profile_parent);
-  login_profile->set_incognito(true);
 
   // Inform power_prefs_ that the login screen is being shown.
   power_prefs_->Observe(chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index bc82310..a031a16 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -24,7 +24,7 @@
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
-#include "chrome/browser/download/download_util.h"
+#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"
@@ -141,7 +141,7 @@
   registry->RegisterBooleanPref(
       prefs::kSpokenFeedbackEnabled,
       false,
-      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterBooleanPref(
       prefs::kHighContrastEnabled,
       false,
@@ -656,113 +656,6 @@
     input_method_manager_->SetEnabledExtensionImes(&split_values);
   }
 
-  // Do not check |*pref_name| of the prefs for remembering current/previous
-  // input methods here. We're only interested in initial values of the prefs.
-
-  // TODO(nona): remove all IME preference entries. crbug.com/256102
-  for (size_t i = 0; i < language_prefs::kNumChewingBooleanPrefs; ++i) {
-    if (!pref_name ||
-        *pref_name == language_prefs::kChewingBooleanPrefs[i].pref_name) {
-      SetLanguageConfigBoolean(
-          language_prefs::kChewingSectionName,
-          language_prefs::kChewingBooleanPrefs[i].ibus_config_name,
-          chewing_boolean_prefs_[i].GetValue());
-    }
-  }
-  for (size_t i = 0; i < language_prefs::kNumChewingMultipleChoicePrefs; ++i) {
-    if (!pref_name ||
-        *pref_name ==
-        language_prefs::kChewingMultipleChoicePrefs[i].pref_name) {
-      SetLanguageConfigString(
-          language_prefs::kChewingSectionName,
-          language_prefs::kChewingMultipleChoicePrefs[i].ibus_config_name,
-          chewing_multiple_choice_prefs_[i].GetValue());
-    }
-  }
-  if (!pref_name ||
-      *pref_name == language_prefs::kChewingHsuSelKeyType.pref_name) {
-    SetLanguageConfigInteger(
-        language_prefs::kChewingSectionName,
-        language_prefs::kChewingHsuSelKeyType.ibus_config_name,
-        chewing_hsu_sel_key_type_.GetValue());
-  }
-  for (size_t i = 0; i < language_prefs::kNumChewingIntegerPrefs; ++i) {
-    if (!pref_name ||
-        *pref_name == language_prefs::kChewingIntegerPrefs[i].pref_name) {
-      SetLanguageConfigInteger(
-          language_prefs::kChewingSectionName,
-          language_prefs::kChewingIntegerPrefs[i].ibus_config_name,
-          chewing_integer_prefs_[i].GetValue());
-    }
-  }
-  if (!pref_name ||
-      *pref_name == prefs::kLanguageHangulKeyboard) {
-    std::vector<std::string> new_input_method_ids;
-    if (input_method_manager_->MigrateKoreanKeyboard(
-            hangul_keyboard_.GetValue(),
-            &new_input_method_ids)) {
-      preload_engines_.SetValue(JoinString(new_input_method_ids, ','));
-      hangul_keyboard_.SetValue("dummy_value_already_migrated");
-    }
-  }
-  if (!pref_name || *pref_name == prefs::kLanguageHangulHanjaBindingKeys) {
-    SetLanguageConfigString(language_prefs::kHangulSectionName,
-                            language_prefs::kHangulHanjaBindingKeysConfigName,
-                            hangul_hanja_binding_keys_.GetValue());
-  }
-  for (size_t i = 0; i < language_prefs::kNumPinyinBooleanPrefs; ++i) {
-    if (!pref_name ||
-        *pref_name == language_prefs::kPinyinBooleanPrefs[i].pref_name) {
-      SetLanguageConfigBoolean(
-          language_prefs::kPinyinSectionName,
-          language_prefs::kPinyinBooleanPrefs[i].ibus_config_name,
-          pinyin_boolean_prefs_[i].GetValue());
-    }
-  }
-  for (size_t i = 0; i < language_prefs::kNumPinyinIntegerPrefs; ++i) {
-    if (!pref_name ||
-        *pref_name == language_prefs::kPinyinIntegerPrefs[i].pref_name) {
-      SetLanguageConfigInteger(
-          language_prefs::kPinyinSectionName,
-          language_prefs::kPinyinIntegerPrefs[i].ibus_config_name,
-          pinyin_int_prefs_[i].GetValue());
-    }
-  }
-  if (!pref_name ||
-      *pref_name == language_prefs::kPinyinDoublePinyinSchema.pref_name) {
-    SetLanguageConfigInteger(
-        language_prefs::kPinyinSectionName,
-        language_prefs::kPinyinDoublePinyinSchema.ibus_config_name,
-        pinyin_double_pinyin_schema_.GetValue());
-  }
-  for (size_t i = 0; i < language_prefs::kNumMozcBooleanPrefs; ++i) {
-    if (!pref_name ||
-        *pref_name == language_prefs::kMozcBooleanPrefs[i].pref_name) {
-      SetLanguageConfigBoolean(
-          language_prefs::kMozcSectionName,
-          language_prefs::kMozcBooleanPrefs[i].ibus_config_name,
-          mozc_boolean_prefs_[i].GetValue());
-    }
-  }
-  for (size_t i = 0; i < language_prefs::kNumMozcMultipleChoicePrefs; ++i) {
-    if (!pref_name ||
-        *pref_name == language_prefs::kMozcMultipleChoicePrefs[i].pref_name) {
-      SetLanguageConfigString(
-          language_prefs::kMozcSectionName,
-          language_prefs::kMozcMultipleChoicePrefs[i].ibus_config_name,
-          mozc_multiple_choice_prefs_[i].GetValue());
-    }
-  }
-  for (size_t i = 0; i < language_prefs::kNumMozcIntegerPrefs; ++i) {
-    if (!pref_name ||
-        *pref_name == language_prefs::kMozcIntegerPrefs[i].pref_name) {
-      SetLanguageConfigInteger(
-          language_prefs::kMozcSectionName,
-          language_prefs::kMozcIntegerPrefs[i].ibus_config_name,
-          mozc_integer_prefs_[i].GetValue());
-    }
-  }
-
   // Change the download directory to the default value if a Drive directory is
   // selected and Drive is disabled.
   if (!pref_name || *pref_name == prefs::kDisableDrive) {
@@ -770,7 +663,7 @@
       if (drive::util::IsUnderDriveMountPoint(
           download_default_directory_.GetValue())) {
         prefs_->SetFilePath(prefs::kDownloadDefaultDirectory,
-                            download_util::GetDefaultDownloadDirectory());
+                            DownloadPrefs::GetDefaultDownloadDirectory());
       }
     }
   }
@@ -793,45 +686,6 @@
   }
 }
 
-void Preferences::SetLanguageConfigBoolean(const char* section,
-                                           const char* name,
-                                           bool value) {
-  input_method::InputMethodConfigValue config;
-  config.type = input_method::InputMethodConfigValue::kValueTypeBool;
-  config.bool_value = value;
-  input_method_manager_->SetInputMethodConfig(section, name, config);
-}
-
-void Preferences::SetLanguageConfigInteger(const char* section,
-                                           const char* name,
-                                           int value) {
-  input_method::InputMethodConfigValue config;
-  config.type = input_method::InputMethodConfigValue::kValueTypeInt;
-  config.int_value = value;
-  input_method_manager_->SetInputMethodConfig(section, name, config);
-}
-
-void Preferences::SetLanguageConfigString(const char* section,
-                                          const char* name,
-                                          const std::string& value) {
-  input_method::InputMethodConfigValue config;
-  config.type = input_method::InputMethodConfigValue::kValueTypeString;
-  config.string_value = value;
-  input_method_manager_->SetInputMethodConfig(section, name, config);
-}
-
-void Preferences::SetLanguageConfigStringList(
-    const char* section,
-    const char* name,
-    const std::vector<std::string>& values) {
-  input_method::InputMethodConfigValue config;
-  config.type = input_method::InputMethodConfigValue::kValueTypeStringList;
-  for (size_t i = 0; i < values.size(); ++i)
-    config.string_list_value.push_back(values[i]);
-
-  input_method_manager_->SetInputMethodConfig(section, name, config);
-}
-
 void Preferences::SetLanguageConfigStringListAsCSV(const char* section,
                                                    const char* name,
                                                    const std::string& value) {
@@ -850,10 +704,6 @@
     input_method_manager_->EnableInputMethods(split_values);
     return;
   }
-
-  // We should call the cros API even when |value| is empty, to disable default
-  // config.
-  SetLanguageConfigStringList(section, name, split_values);
 }
 
 void Preferences::SetInputMethodList() {
diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h
index 9c98650..dda3427 100644
--- a/chrome/browser/chromeos/preferences.h
+++ b/chrome/browser/chromeos/preferences.h
@@ -64,31 +64,6 @@
   // stored in the preferences.
   void NotifyPrefChanged(const std::string* pref_name);
 
-  // Writes boolean |value| to the input method (IBus) configuration daemon.
-  // |section| (e.g. "general") and |name| (e.g. "use_global_engine") should
-  // not be NULL.
-  void SetLanguageConfigBoolean(const char* section,
-                                const char* name,
-                                bool value);
-
-  // Writes integer |value| to the input method (IBus) configuration daemon.
-  // |section| and |name| should not be NULL.
-  void SetLanguageConfigInteger(const char* section,
-                                const char* name,
-                                int value);
-
-  // Writes string |value| to the input method (IBus) configuration daemon.
-  // |section| and |name| should not be NULL.
-  void SetLanguageConfigString(const char* section,
-                               const char* name,
-                               const std::string& value);
-
-  // Writes a string list to the input method (IBus) configuration daemon.
-  // |section| and |name| should not be NULL.
-  void SetLanguageConfigStringList(const char* section,
-                                   const char* name,
-                                   const std::vector<std::string>& values);
-
   // A variant of SetLanguageConfigStringList. You can pass comma-separated
   // values. Examples of |value|: "", "Control+space,Hiragana"
   void SetLanguageConfigStringListAsCSV(const char* section,
diff --git a/chrome/browser/chromeos/preferences_unittest.cc b/chrome/browser/chromeos/preferences_unittest.cc
index cbab4a6..979e154 100644
--- a/chrome/browser/chromeos/preferences_unittest.cc
+++ b/chrome/browser/chromeos/preferences_unittest.cc
@@ -25,16 +25,6 @@
   virtual ~MyMockInputMethodManager() {
   }
 
-  virtual bool SetInputMethodConfig(
-      const std::string& section,
-      const std::string& config_name,
-      const input_method::InputMethodConfigValue& value) OVERRIDE {
-    // Assume the preload engines list is "KeyboardC,KeyboardA,KeyboardB".
-    // Switch to the first one, C.
-    ChangeInputMethod("KeyboardC");
-    return true;
-  }
-
   virtual void ChangeInputMethod(const std::string& input_method_id) OVERRIDE {
     last_input_method_id_ = input_method_id;
     // Do the same thing as BrowserStateMonitor::UpdateUserPreferences.
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index 9ec1de9..5815d34 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -8,9 +8,7 @@
 #include "base/command_line.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/sms_observer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_constants.h"
@@ -106,11 +104,6 @@
   profile->InitChromeOSPreferences();
 
   if (process_startup) {
-    static chromeos::SmsObserver* sms_observer =
-        new chromeos::SmsObserver();
-    chromeos::NetworkLibrary::Get()->
-        AddNetworkManagerObserver(sms_observer);
-
     profile->SetupChromeOSEnterpriseExtensionObserver();
   }
 }
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.cc b/chrome/browser/chromeos/settings/cros_settings_names.cc
index ac3369d..560f36d 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.cc
+++ b/chrome/browser/chromeos/settings/cros_settings_names.cc
@@ -130,7 +130,13 @@
 const char kVariationsRestrictParameter[] =
     "cros.variations_restrict_parameter";
 
-// A boolean pref that indicates whether attestation is enabled for the device.
+// A boolean pref that indicates whether enterprise attestation is enabled for
+// the device.
 const char kDeviceAttestationEnabled[] = "cros.device.attestation_enabled";
 
+// A boolean pref that indicates whether attestation for content protection is
+// enabled for the device.
+const char kAttestationForContentProtectionEnabled[] =
+    "cros.device.attestation_for_content_protection_enabled";
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.h b/chrome/browser/chromeos/settings/cros_settings_names.h
index eff6785..ece245d 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.h
+++ b/chrome/browser/chromeos/settings/cros_settings_names.h
@@ -73,6 +73,8 @@
 extern const char kVariationsRestrictParameter[];
 
 extern const char kDeviceAttestationEnabled[];
+extern const char kAttestationForContentProtectionEnabled[];
+
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_CHROMEOS_SETTINGS_CROS_SETTINGS_NAMES_H_
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index adcf750..dbcf249 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -220,10 +220,6 @@
 DeviceOAuth2TokenService::~DeviceOAuth2TokenService() {
 }
 
-net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() {
-  return url_request_context_getter_.get();
-}
-
 scoped_ptr<OAuth2TokenService::Request> DeviceOAuth2TokenService::StartRequest(
     const OAuth2TokenService::ScopeSet& scopes,
     OAuth2TokenService::Consumer* consumer) {
@@ -283,4 +279,8 @@
   return std::string();
 }
 
+net::URLRequestContextGetter* DeviceOAuth2TokenService::GetRequestContext() {
+  return url_request_context_getter_.get();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.h b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
index ca6f41e..24f8529 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.h
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
@@ -54,6 +54,9 @@
   // Pull the robot account ID from device policy.
   virtual std::string GetRobotAccountId();
 
+  // Implementation of OAuth2TokenService.
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+
  private:
   class ValidatingConsumer;
   friend class ValidatingConsumer;
@@ -66,9 +69,6 @@
                                     PrefService* local_state);
   virtual ~DeviceOAuth2TokenService();
 
-  // Implementation of OAuth2TokenService.
-  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
-
   void OnValidationComplete(bool token_is_valid);
 
   bool refresh_token_is_valid_;
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index 7816dc7..547854b 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -56,6 +56,7 @@
   kAllowRedeemChromeOsRegistrationOffers,
   kAllowedConnectionTypesForUpdate,
   kAppPack,
+  kAttestationForContentProtectionEnabled,
   kDeviceAttestationEnabled,
   kDeviceOwner,
   kIdleLogoutTimeout,
@@ -386,6 +387,15 @@
     } else {
       NOTREACHED();
     }
+  } else if (prop == kAttestationForContentProtectionEnabled) {
+    em::AttestationSettingsProto* attestation_settings =
+        device_settings_.mutable_attestation_settings();
+    bool setting_enabled;
+    if (value->GetAsBoolean(&setting_enabled)) {
+      attestation_settings->set_content_protection_enabled(setting_enabled);
+    } else {
+      NOTREACHED();
+    }
   } else {
     // The remaining settings don't support Set(), since they are not
     // intended to be customizable by the user:
@@ -741,6 +751,12 @@
   new_values_cache->SetBoolean(
       kDeviceAttestationEnabled,
       policy.attestation_settings().attestation_enabled());
+
+  new_values_cache->SetBoolean(
+      kAttestationForContentProtectionEnabled,
+      !(policy.has_attestation_settings() &&
+        policy.attestation_settings().has_content_protection_enabled() &&
+        policy.attestation_settings().content_protection_enabled()));
 }
 
 void DeviceSettingsProvider::UpdateValuesCache(
diff --git a/chrome/browser/chromeos/sms_observer.cc b/chrome/browser/chromeos/sms_observer.cc
deleted file mode 100644
index 6a29b04..0000000
--- a/chrome/browser/chromeos/sms_observer.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 "chrome/browser/chromeos/sms_observer.h"
-
-#include "ash/shell.h"
-#include "ash/system/chromeos/network/sms_observer.h"
-#include "ash/system/tray/system_tray.h"
-#include "ash/system/tray/system_tray_notifier.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chromeos/network/cros_network_functions.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace chromeos {
-
-SmsObserver::SmsObserver() {
-  UpdateObservers(chromeos::NetworkLibrary::Get());
-}
-
-SmsObserver::~SmsObserver() {
-  NetworkLibrary* library = chromeos::NetworkLibrary::Get();
-  library->RemoveNetworkManagerObserver(this);
-  DisconnectAll();
-}
-
-void SmsObserver::UpdateObservers(NetworkLibrary* library) {
-  const CellularNetworkVector& networks = library->cellular_networks();
-  // Remove monitors for networks that are not in the list anymore.
-  for (ObserversMap::iterator it_observer = observers_.begin();
-       it_observer != observers_.end();) {
-    bool found = false;
-    for (CellularNetworkVector::const_iterator it_network = networks.begin();
-        it_network != networks.end(); ++it_network) {
-      if (it_observer->first == (*it_network)->device_path()) {
-        found = true;
-        break;
-      }
-    }
-    if (!found) {
-      VLOG(1) << "Remove SMS monitor for " << it_observer->first;
-      delete it_observer->second;
-      observers_.erase(it_observer++);
-    } else {
-      ++it_observer;
-    }
-  }
-
-  // Add monitors for new networks.
-  for (CellularNetworkVector::const_iterator it_network = networks.begin();
-       it_network != networks.end(); ++it_network) {
-    const std::string& device_path((*it_network)->device_path());
-    if (device_path.empty()) {
-      LOG(WARNING) << "Cellular Network has empty device path: "
-                   << (*it_network)->name();
-      continue;
-    }
-    ObserversMap::iterator it_observer = observers_.find(device_path);
-    if (it_observer == observers_.end()) {
-      VLOG(1) << "Add SMS monitor for " << device_path;
-      CrosNetworkWatcher* watcher =
-          CrosMonitorSMS(device_path,
-                         base::Bind(&SmsObserver::OnNewMessage,
-                                    base::Unretained(this)));
-      observers_.insert(ObserversMap::value_type(device_path, watcher));
-    } else {
-      VLOG(1) << "Already has SMS monitor for " << device_path;
-    }
-  }
-}
-
-void SmsObserver::DisconnectAll() {
-  for (ObserversMap::iterator it = observers_.begin();
-       it != observers_.end(); ++it) {
-    VLOG(1) << "Remove SMS monitor for " << it->first;
-    delete it->second;
-  }
-  observers_.clear();
-}
-
-void SmsObserver::OnNetworkManagerChanged(NetworkLibrary* library) {
-  UpdateObservers(library);
-}
-
-void SmsObserver::OnNewMessage(const std::string& modem_device_path,
-                               const SMS& message) {
-  VLOG(1) << "New message notification from " << message.number
-          << " text: " << message.text;
-
-  // Don't show empty messages. Such messages most probably "Message Waiting
-  // Indication" and it should be determined by data-coding-scheme,
-  // see crosbug.com/27883. But this field is not exposed from libcros.
-  // TODO(dpokuhin): when libcros refactoring done, implement check for
-  // "Message Waiting Indication" to filter out such messages.
-  if (message.text.empty())
-    return;
-
-  // Add an Ash SMS notification. TODO(stevenjb): Replace this code with
-  // NetworkSmsHandler when fixed: crbug.com/133416.
-  base::DictionaryValue dict;
-  dict.SetString(ash::kSmsNumberKey, message.number);
-  dict.SetString(ash::kSmsTextKey, message.text);
-  ash::Shell::GetInstance()->system_tray_notifier()->NotifyAddSmsMessage(dict);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/sms_observer.h b/chrome/browser/chromeos/sms_observer.h
deleted file mode 100644
index 2ac4475..0000000
--- a/chrome/browser/chromeos/sms_observer.h
+++ /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.
-
-#ifndef CHROME_BROWSER_CHROMEOS_SMS_OBSERVER_H_
-#define CHROME_BROWSER_CHROMEOS_SMS_OBSERVER_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
-
-class Profile;
-
-namespace chromeos {
-
-class CrosNetworkWatcher;
-struct SMS;
-
-// Performs monitoring of incoming SMS and shows system notifications.
-class SmsObserver : public NetworkLibrary::NetworkManagerObserver {
- public:
-  SmsObserver();
-  virtual ~SmsObserver();
-
- private:
-  typedef std::map<std::string, CrosNetworkWatcher*> ObserversMap;
-
-  // NetworkLibrary:NetworkManagerObserver implementation:
-  virtual void OnNetworkManagerChanged(NetworkLibrary* obj) OVERRIDE;
-
-  void OnNewMessage(const std::string& modem_device_path, const SMS& message);
-
-  void UpdateObservers(NetworkLibrary* library);
-  void DisconnectAll();
-
-  ObserversMap observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(SmsObserver);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_SMS_OBSERVER_H_
diff --git a/chrome/browser/chromeos/status/data_promo_notification.cc b/chrome/browser/chromeos/status/data_promo_notification.cc
index 7c1f57b..3ea4dce 100644
--- a/chrome/browser/chromeos/status/data_promo_notification.cc
+++ b/chrome/browser/chromeos/status/data_promo_notification.cc
@@ -6,29 +6,41 @@
 
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
-#include "ash/system/chromeos/network/network_observer.h"
+#include "ash/system/chromeos/network/network_connect.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/mobile_config.h"
 #include "chrome/browser/profiles/profile.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_list.h"
+#include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/login/login_state.h"
+#include "chromeos/network/device_state.h"
+#include "chromeos/network/network_connection_handler.h"
+#include "chromeos/network/network_event_log.h"
+#include "chromeos/network/network_state.h"
+#include "chromeos/network/network_state_handler.h"
+#include "grit/ash_resources.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
+namespace chromeos {
+
 namespace {
 
 // Time in milliseconds to delay showing of promo
@@ -59,8 +71,7 @@
   prefs->SetInteger(pref_name, value);
 }
 
-// Returns prefs::kShow3gPromoNotification or false
-// if there's no active browser.
+// Returns prefs::kShow3gPromoNotification or false if no active browser.
 bool ShouldShow3gPromoNotification() {
   return GetBooleanPref(prefs::kShow3gPromoNotification);
 }
@@ -80,10 +91,13 @@
 }
 
 const chromeos::MobileConfig::Carrier* GetCarrier(
-    chromeos::NetworkLibrary* cros) {
-  std::string carrier_id = cros->GetCellularHomeCarrierId();
+    const NetworkState* cellular) {
+  const DeviceState* device = NetworkHandler::Get()->network_state_handler()->
+      GetDeviceState(cellular->device_path());
+  std::string carrier_id = device ? device->home_provider_id() : "";
   if (carrier_id.empty()) {
-    LOG(ERROR) << "Empty carrier ID with a cellular connected.";
+    NET_LOG_ERROR("Empty carrier ID for cellular network",
+                  device ? device->path(): "No device");
     return NULL;
   }
 
@@ -105,15 +119,27 @@
     const std::string locale = g_browser_process->GetApplicationLocale();
     std::string deal_text = deal->GetLocalizedString(locale,
                                                      "notification_text");
+    NET_LOG_DEBUG("Carrier Deal Found", deal_text);
     if (deal_text.empty())
       return NULL;
   }
   return deal;
 }
 
-}  // namespace
+void NotificationClicked(const std::string& service_path,
+                         const std::string& info_url) {
+  if (info_url.empty())
+    ash::network_connect::ShowNetworkSettings(service_path);
 
-namespace chromeos {
+  Browser* browser = chrome::FindOrCreateTabbedBrowser(
+      ProfileManager::GetDefaultProfileOrOffTheRecord(),
+      chrome::HOST_DESKTOP_TYPE_ASH);
+  if (!browser)
+    return;
+  chrome::ShowSingletonTab(browser, GURL(info_url));
+}
+
+}  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
 // DataPromoNotification
@@ -121,10 +147,14 @@
 DataPromoNotification::DataPromoNotification()
     : check_for_promo_(true),
       weak_ptr_factory_(this) {
+  NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE);
 }
 
 DataPromoNotification::~DataPromoNotification() {
-  CloseNotification();
+  if (NetworkHandler::IsInitialized()) {
+    NetworkHandler::Get()->network_state_handler()->RemoveObserver(
+        this, FROM_HERE);
+  }
 }
 
 void DataPromoNotification::RegisterPrefs(PrefRegistrySimple* registry) {
@@ -132,77 +162,77 @@
   registry->RegisterIntegerPref(prefs::kCarrierDealPromoShown, 0);
 }
 
-void DataPromoNotification::ShowOptionalMobileDataPromoNotification(
-    NetworkLibrary* cros,
-    views::View* host,
-    ash::NetworkTrayDelegate* listener) {
-  // Display one-time notification for regular users on first use
-  // of Mobile Data connection or if there's a carrier deal defined
-  // show that even if user has already seen generic promo.
-  if (LoginState::Get()->IsUserAuthenticated() &&
-      check_for_promo_ &&
-      cros->cellular_connected() && !cros->ethernet_connected() &&
-      !cros->wifi_connected() && !cros->wimax_connected()) {
-    std::string deal_text;
-    int carrier_deal_promo_pref = kNotificationCountPrefDefault;
-    const MobileConfig::CarrierDeal* deal = NULL;
-    const MobileConfig::Carrier* carrier = GetCarrier(cros);
-    if (carrier)
-      deal = GetCarrierDeal(carrier);
-    deal_info_url_.clear();
-    deal_topup_url_.clear();
-    if (deal) {
-      carrier_deal_promo_pref = GetCarrierDealPromoShown();
-      const std::string locale = g_browser_process->GetApplicationLocale();
-      deal_text = deal->GetLocalizedString(locale, "notification_text");
-      deal_info_url_ = deal->info_url();
-      deal_topup_url_ = carrier->top_up_url();
-    } else if (!ShouldShow3gPromoNotification()) {
-      check_for_promo_ = false;
-      return;
-    }
-
-    const chromeos::CellularNetwork* cellular = cros->cellular_network();
-    DCHECK(cellular);
-    // If we do not know the technology type, do not show the notification yet.
-    // The next NetworkLibrary Manager update should trigger it.
-    if (cellular->network_technology() == NETWORK_TECHNOLOGY_UNKNOWN)
-      return;
-
-    string16 message = l10n_util::GetStringUTF16(IDS_3G_NOTIFICATION_MESSAGE);
-    if (!deal_text.empty())
-      message = UTF8ToUTF16(deal_text + "\n\n") + message;
-
-    // Use deal URL if it's defined or general "Network Settings" URL.
-    int link_message_id;
-    if (deal_topup_url_.empty())
-      link_message_id = IDS_OFFLINE_NETWORK_SETTINGS;
-    else
-      link_message_id = IDS_STATUSBAR_NETWORK_VIEW_ACCOUNT;
-
-    ash::NetworkObserver::NetworkType type =
-        (cellular->network_technology() == NETWORK_TECHNOLOGY_LTE ||
-         cellular->network_technology() == NETWORK_TECHNOLOGY_LTE_ADVANCED)
-        ? ash::NetworkObserver::NETWORK_CELLULAR_LTE
-        : ash::NetworkObserver::NETWORK_CELLULAR;
-
-    std::vector<string16> links;
-    links.push_back(l10n_util::GetStringUTF16(link_message_id));
-    if (!deal_info_url_.empty())
-      links.push_back(l10n_util::GetStringUTF16(IDS_LEARN_MORE));
-    ash::Shell::GetInstance()->system_tray_notifier()->NotifySetNetworkMessage(
-        listener, ash::NetworkObserver::MESSAGE_DATA_PROMO,
-        type, string16(), message, links);
-    check_for_promo_ = false;
-    SetShow3gPromoNotification(false);
-    if (carrier_deal_promo_pref != kNotificationCountPrefDefault)
-      SetCarrierDealPromoShown(carrier_deal_promo_pref + 1);
-  }
+void DataPromoNotification::NetworkPropertiesUpdated(
+    const NetworkState* network) {
+  if (!network || network->type() != flimflam::kTypeCellular)
+    return;
+  ShowOptionalMobileDataPromoNotification();
 }
 
-void DataPromoNotification::CloseNotification() {
-  ash::Shell::GetInstance()->system_tray_notifier()->NotifyClearNetworkMessage(
-      ash::NetworkObserver::MESSAGE_DATA_PROMO);
+void DataPromoNotification::DefaultNetworkChanged(const NetworkState* network) {
+  // Call NetworkPropertiesUpdated in case the Cellular network became the
+  // default network.
+  NetworkPropertiesUpdated(network);
+}
+
+void DataPromoNotification::ShowOptionalMobileDataPromoNotification() {
+  // Display a one-time notification for authenticated users on first use
+  // of Mobile Data connection or if there is a carrier deal defined
+  // show that even if user has already seen generic promo.
+  if (!check_for_promo_ || !LoginState::Get()->IsUserAuthenticated())
+    return;
+  const NetworkState* default_network =
+      NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
+  if (!default_network || default_network->type() != flimflam::kTypeCellular)
+    return;
+  // When requesting a network connection, do not show the notification.
+  if (NetworkHandler::Get()->network_connection_handler()->
+      HasPendingConnectRequest())
+    return;
+
+  int carrier_deal_promo_pref = kNotificationCountPrefDefault;
+  const MobileConfig::CarrierDeal* deal = NULL;
+  const MobileConfig::Carrier* carrier = GetCarrier(default_network);
+  if (carrier)
+    deal = GetCarrierDeal(carrier);
+
+  string16 message = l10n_util::GetStringUTF16(IDS_3G_NOTIFICATION_MESSAGE);
+  std::string info_url;
+  if (deal) {
+    carrier_deal_promo_pref = GetCarrierDealPromoShown();
+    const std::string locale = g_browser_process->GetApplicationLocale();
+    std::string deal_text =
+        deal->GetLocalizedString(locale, "notification_text");
+    message = UTF8ToUTF16(deal_text + "\n\n") + message;
+    info_url = deal->info_url();
+    if (info_url.empty() && carrier)
+      info_url = carrier->top_up_url();
+  } else if (!ShouldShow3gPromoNotification()) {
+    check_for_promo_ = false;
+    return;
+  }
+
+  int icon_id;
+  if (default_network->network_technology() == flimflam::kNetworkTechnologyLte)
+    icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_LTE;
+  else
+    icon_id = IDR_AURA_UBER_TRAY_NOTIFICATION_3G;
+  const gfx::Image& icon =
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon_id);
+
+  message_center::MessageCenter::Get()->AddNotification(
+      message_center::Notification::CreateSystemNotification(
+          ash::network_connect::kNetworkActivateNotificationId,
+          base::string16() /* title */,
+          message,
+          icon,
+          base::Bind(&NotificationClicked,
+                     default_network->path(), info_url)));
+
+  check_for_promo_ = false;
+  SetShow3gPromoNotification(false);
+  if (carrier_deal_promo_pref != kNotificationCountPrefDefault)
+    SetCarrierDealPromoShown(carrier_deal_promo_pref + 1);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/status/data_promo_notification.h b/chrome/browser/chromeos/status/data_promo_notification.h
index 072bd48..d78dfed 100644
--- a/chrome/browser/chromeos/status/data_promo_notification.h
+++ b/chrome/browser/chromeos/status/data_promo_notification.h
@@ -7,50 +7,40 @@
 
 #include "base/basictypes.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/network/network_state_handler_observer.h"
 
 class PrefRegistrySimple;
 
-namespace ash {
-class NetworkTrayDelegate;
-}
-
 namespace views {
 class View;
 }
 
 namespace chromeos {
-class NetworkLibrary;
 
-class DataPromoNotification {
+// This class is responsible for triggering cellular network related
+// notifications, specifically:
+// * "Chrome will use mobile data..." when Cellular is the Default network
+//   for the first time.
+// * Data Promotion notifications when available / appropriate.
+class DataPromoNotification : public NetworkStateHandlerObserver {
  public:
   DataPromoNotification();
   virtual ~DataPromoNotification();
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
-  const std::string& deal_info_url() const { return deal_info_url_; }
-  const std::string& deal_topup_url() const { return deal_topup_url_; }
+ private:
+  // NetworkStateHandlerObserver
+  virtual void NetworkPropertiesUpdated(const NetworkState* network) OVERRIDE;
+  virtual void DefaultNetworkChanged(const NetworkState* network) OVERRIDE;
 
   // Shows 3G promo notification if needed.
-  void ShowOptionalMobileDataPromoNotification(
-      NetworkLibrary* cros,
-      views::View* host,
-      ash::NetworkTrayDelegate* listener);
+  void ShowOptionalMobileDataPromoNotification();
 
-  // Closes message bubble.
-  void CloseNotification();
-
- private:
-  // True if check for promo needs to be done,
-  // otherwise just ignore it for current session.
+  // True if check for promo needs to be done, otherwise ignore it for the
+  // current session.
   bool check_for_promo_;
 
-  // Current carrier deal info URL.
-  std::string deal_info_url_;
-
-  // Current carrier deal top-up URL.
-  std::string deal_topup_url_;
-
   // Factory for delaying showing promo notification.
   base::WeakPtrFactory<DataPromoNotification> weak_ptr_factory_;
 
diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc
index 2701f92..e4ebe74 100644
--- a/chrome/browser/chromeos/status/network_menu.cc
+++ b/chrome/browser/chromeos/status/network_menu.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/mobile_config.h"
 #include "chrome/browser/chromeos/options/network_config_view.h"
+#include "chrome/browser/chromeos/sim_dialog_delegate.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/url_constants.h"
@@ -61,8 +62,7 @@
 void ToggleTechnology(const std::string& technology) {
   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
   bool is_enabled = handler->IsTechnologyEnabled(technology);
-  handler->SetTechnologyEnabled(technology, !is_enabled,
-                                network_handler::ErrorCallback());
+  ash::network_connect::SetTechnologyEnabled(technology, !is_enabled);
 }
 
 }  // namespace
@@ -161,13 +161,6 @@
   // Weak pointer to NetworkMenu that owns this MenuModel.
   base::WeakPtr<NetworkMenu> owner_;
 
-  // Top up URL of the current carrier on empty string if there's none.
-  std::string top_up_url_;
-
-  // Carrier ID which top up URL is initialized for.
-  // Used to update top up URL only when cellular carrier has changed.
-  std::string carrier_id_;
-
  private:
   // Open a dialog to set up and connect to a network.
   void ShowOther(const std::string& type) const;
@@ -388,7 +381,6 @@
   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
 
   // Populate our MenuItems with the current list of networks.
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   string16 label;
 
   // Ethernet
@@ -570,8 +562,6 @@
       label = l10n_util::GetStringFUTF16(id,
           l10n_util::GetStringUTF16(IDS_STATUSBAR_NETWORK_DEVICE_CELLULAR));
       gfx::ImageSkia icon;
-      if (is_locked)
-        icon = *rb.GetImageSkiaNamed(IDR_AURA_UBER_TRAY_NETWORK_SECURE_DARK);
       int flag = FLAG_TOGGLE_MOBILE;
       if (mobile_state == NetworkStateHandler::TECHNOLOGY_ENABLING)
         flag |= FLAG_DISABLED;
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index eb0b9a7..1669cd4 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -18,8 +18,7 @@
 #include "ash/shell_window_ids.h"
 #include "ash/system/bluetooth/bluetooth_observer.h"
 #include "ash/system/brightness/brightness_observer.h"
-#include "ash/system/chromeos/network/network_observer.h"
-#include "ash/system/chromeos/network/network_tray_delegate.h"
+#include "ash/system/chromeos/network/network_connect.h"
 #include "ash/system/date/clock_observer.h"
 #include "ash/system/drive/drive_observer.h"
 #include "ash/system/ime/ime_observer.h"
@@ -49,9 +48,9 @@
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/bluetooth/bluetooth_pairing_dialog.h"
 #include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/drive/job_list.h"
+#include "chrome/browser/chromeos/enrollment_dialog_view.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
 #include "chrome/browser/chromeos/login/help_app_launcher.h"
@@ -62,9 +61,7 @@
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_adding_screen.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/mobile_config.h"
 #include "chrome/browser/chromeos/options/network_config_view.h"
-#include "chrome/browser/chromeos/options/network_connect.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/sim_dialog_delegate.h"
@@ -85,6 +82,7 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/chromeos/mobile_setup_dialog.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -97,6 +95,7 @@
 #include "chromeos/ime/input_method_manager.h"
 #include "chromeos/ime/xkeyboard.h"
 #include "chromeos/login/login_state.h"
+#include "chromeos/network/network_event_log.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
 #include "content/public/browser/browser_thread.h"
@@ -221,18 +220,101 @@
   // TODO(sad): Do something?
 }
 
-ash::NetworkObserver::NetworkType NetworkTypeForCellular(
-    const CellularNetwork* cellular) {
-  if (cellular->network_technology() == NETWORK_TECHNOLOGY_LTE ||
-      cellular->network_technology() == NETWORK_TECHNOLOGY_LTE_ADVANCED)
-    return ash::NetworkObserver::NETWORK_CELLULAR_LTE;
-  return ash::NetworkObserver::NETWORK_CELLULAR;
+void ShowNetworkSettingsPage(const std::string& service_path) {
+  std::string page = chrome::kInternetOptionsSubPage;
+  const NetworkState* network = service_path.empty() ? NULL :
+      NetworkHandler::Get()->network_state_handler()->GetNetworkState(
+          service_path);
+  if (network) {
+    std::string name(network->name());
+    if (name.empty() && network->type() == flimflam::kTypeEthernet)
+      name = l10n_util::GetStringUTF8(IDS_STATUSBAR_NETWORK_DEVICE_ETHERNET);
+    page += base::StringPrintf(
+        "?servicePath=%s&networkType=%s&networkName=%s",
+        net::EscapeUrlEncodedData(service_path, true).c_str(),
+        net::EscapeUrlEncodedData(network->type(), true).c_str(),
+        net::EscapeUrlEncodedData(name, false).c_str());
+  }
+  content::RecordAction(
+      content::UserMetricsAction("OpenInternetOptionsDialog"));
+  Browser* browser = chrome::FindOrCreateTabbedBrowser(
+      ProfileManager::GetDefaultProfileOrOffTheRecord(),
+      chrome::HOST_DESKTOP_TYPE_ASH);
+  chrome::ShowSettingsSubPage(browser, page);
+}
+
+void HandleUnconfiguredNetwork(const std::string& service_path,
+                               gfx::NativeWindow parent_window) {
+  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
+      GetNetworkState(service_path);
+  if (!network) {
+    NET_LOG_ERROR("Configuring unknown network", service_path);
+    return;
+  }
+
+  if (network->type() == flimflam::kTypeWifi) {
+    // Only show the config view for secure networks, otherwise do nothing.
+    if (network->security() != flimflam::kSecurityNone)
+      NetworkConfigView::Show(service_path, parent_window);
+    return;
+  }
+
+  if (network->type() == flimflam::kTypeWimax ||
+      network->type() == flimflam::kTypeVPN) {
+    NetworkConfigView::Show(service_path, parent_window);
+    return;
+  }
+
+  if (network->type() == flimflam::kTypeCellular) {
+    if (network->activation_state() != flimflam::kActivationStateActivated) {
+      ash::network_connect::ActivateCellular(service_path);
+      return;
+    }
+    if (network->cellular_out_of_credits()) {
+      ash::network_connect::ShowMobileSetup(service_path);
+      return;
+    }
+    // No special configure or setup for |network|, show the settings UI.
+    ShowNetworkSettingsPage(service_path);
+    return;
+  }
+  NOTREACHED();
+}
+
+void EnrollmentComplete(const std::string& service_path) {
+  NET_LOG_USER("Enrollment Complete", service_path);
+}
+
+bool EnrollNetwork(const std::string& service_path,
+                   gfx::NativeWindow parent_window) {
+  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
+      GetNetworkState(service_path);
+  if (!network) {
+    NET_LOG_ERROR("Enrolling Unknown network", service_path);
+    return false;
+  }
+  // We skip certificate patterns for device policy ONC so that an unmanaged
+  // user can't get to the place where a cert is presented for them
+  // involuntarily.
+  if (network->ui_data().onc_source() == onc::ONC_SOURCE_DEVICE_POLICY)
+    return false;
+
+  const CertificatePattern& certificate_pattern =
+      network->ui_data().certificate_pattern();
+  if (certificate_pattern.Empty())
+    return false;
+
+  NET_LOG_USER("Enrolling", service_path);
+
+  EnrollmentDelegate* enrollment = CreateEnrollmentDelegate(
+      parent_window, network->name(), ProfileManager::GetDefaultProfile());
+  return enrollment->Enroll(certificate_pattern.enrollment_uri_list(),
+                            base::Bind(&EnrollmentComplete, service_path));
 }
 
 class SystemTrayDelegate : public ash::SystemTrayDelegate,
                            public PowerManagerClient::Observer,
                            public SessionManagerClient::Observer,
-                           public NetworkLibrary::NetworkManagerObserver,
                            public drive::JobListObserver,
                            public content::NotificationObserver,
                            public input_method::InputMethodManager::Observer,
@@ -240,7 +322,6 @@
                            public chromeos::SystemClockClient::Observer,
                            public device::BluetoothAdapter::Observer,
                            public SystemKeyEventListener::CapsLockObserver,
-                           public ash::NetworkTrayDelegate,
                            public policy::CloudPolicyStore::Observer,
                            public ash::SessionStateObserver {
  public:
@@ -254,8 +335,6 @@
         have_session_start_time_(false),
         have_session_length_limit_(false),
         data_promo_notification_(new DataPromoNotification()),
-        cellular_activating_(false),
-        cellular_out_of_credits_(false),
         volume_control_delegate_(new VolumeController()) {
     // Register notifications on construction so that events such as
     // PROFILE_CREATED do not get missed if they happen before Initialize().
@@ -295,10 +374,6 @@
     DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
     DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this);
 
-    NetworkLibrary* crosnet = NetworkLibrary::Get();
-    crosnet->AddNetworkManagerObserver(this);
-    OnNetworkManagerChanged(crosnet);
-
     input_method::InputMethodManager::Get()->AddObserver(this);
     UpdateClockType();
 
@@ -361,9 +436,6 @@
     DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this);
     DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
     DBusThreadManager::Get()->GetSystemClockClient()->RemoveObserver(this);
-    NetworkLibrary* crosnet = NetworkLibrary::Get();
-    if (crosnet)
-      crosnet->RemoveNetworkManagerObserver(this);
     input_method::InputMethodManager::Get()->RemoveObserver(this);
     system::TimezoneSettings::GetInstance()->RemoveObserver(this);
     if (SystemKeyEventListener::GetInstance())
@@ -481,6 +553,10 @@
     chrome::ShowSettings(GetAppropriateBrowser());
   }
 
+  virtual bool ShouldShowSettings() OVERRIDE {
+    return UserManager::Get()->GetCurrentUserFlow()->ShouldShowSettings();
+  }
+
   virtual void ShowDateSettings() OVERRIDE {
     content::RecordAction(content::UserMetricsAction("ShowDateOptions"));
     std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
@@ -491,7 +567,7 @@
   virtual void ShowNetworkSettings(const std::string& service_path) OVERRIDE {
     if (!LoginState::Get()->IsUserLoggedIn())
       return;
-    network_connect::ShowNetworkSettings(service_path);
+    ShowNetworkSettingsPage(service_path);
   }
 
   virtual void ShowBluetoothSettings() OVERRIDE {
@@ -753,15 +829,15 @@
   }
 
   virtual void ConfigureNetwork(const std::string& network_id) OVERRIDE {
-    network_connect::HandleUnconfiguredNetwork(network_id, GetNativeWindow());
+    HandleUnconfiguredNetwork(network_id, GetNativeWindow());
   }
 
   virtual void EnrollOrConfigureNetwork(
       const std::string& network_id,
       gfx::NativeWindow parent_window) OVERRIDE {
-    if (network_connect::EnrollNetwork(network_id, parent_window))
+    if (EnrollNetwork(network_id, parent_window))
       return;
-    network_connect::HandleUnconfiguredNetwork(network_id, parent_window);
+    HandleUnconfiguredNetwork(network_id, parent_window);
   }
 
   virtual void ManageBluetoothDevices() OVERRIDE {
@@ -783,8 +859,8 @@
                                   SimDialogDelegate::SIM_DIALOG_UNLOCK);
   }
 
-  virtual void ShowMobileSetup(const std::string& network_id) OVERRIDE {
-    network_connect::ShowMobileSetup(network_id);
+  virtual void ShowMobileSetupDialog(const std::string& service_path) OVERRIDE {
+    MobileSetupDialog::Show(service_path);
   }
 
   virtual void ShowOtherWifi() OVERRIDE {
@@ -807,40 +883,6 @@
     return bluetooth_adapter_->IsPowered();
   }
 
-  virtual bool GetCellularCarrierInfo(std::string* carrier_id,
-                                      std::string* topup_url,
-                                      std::string* setup_url) OVERRIDE {
-    bool result = false;
-    NetworkLibrary* crosnet = NetworkLibrary::Get();
-    const NetworkDevice* cellular = crosnet->FindCellularDevice();
-    if (!cellular)
-      return false;
-
-    MobileConfig* config = MobileConfig::GetInstance();
-    if (config->IsReady()) {
-      *carrier_id = crosnet->GetCellularHomeCarrierId();
-      const MobileConfig::Carrier* carrier = config->GetCarrier(*carrier_id);
-      if (carrier) {
-        *topup_url = carrier->top_up_url();
-        result = true;
-      }
-      const MobileConfig::LocaleConfig* locale_config =
-          config->GetLocaleConfig();
-      if (locale_config) {
-        // Only link to setup URL if SIM card is not inserted.
-        if (cellular->is_sim_absent()) {
-          *setup_url = locale_config->setup_url();
-          result = true;
-        }
-      }
-    }
-    return result;
-  }
-
-  virtual void ShowCellularURL(const std::string& url) OVERRIDE {
-    chrome::ShowSingletonTab(GetAppropriateBrowser(), GURL(url));
-  }
-
   virtual void ChangeProxySettings() OVERRIDE {
     CHECK(GetUserLoginStatus() == ash::user::LOGGED_IN_NONE);
     LoginDisplayHostImpl::default_host()->OpenProxySettings();
@@ -873,11 +915,6 @@
         IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
   }
 
-  virtual string16 FormatTimeDuration(
-      const base::TimeDelta& delta) const OVERRIDE {
-    return ui::TimeFormat::TimeDurationLong(delta);
-  }
-
   virtual void MaybeSpeak(const std::string& utterance) const OVERRIDE {
     AccessibilityManager::Get()->MaybeSpeak(utterance);
   }
@@ -969,7 +1006,6 @@
   bool ShouldUse24HourClock() const {
     // On login screen and in guest mode owner default is used for
     // kUse24HourClock preference.
-    // All other modes default to the default locale value.
     const ash::user::LoginStatus status = GetUserLoginStatus();
     const CrosSettings* const cros_settings = CrosSettings::Get();
     bool system_use_24_hour_clock = true;
@@ -1066,14 +1102,6 @@
     return GetNativeWindowByStatus(GetUserLoginStatus());
   }
 
-  // Overridden from NetworkLibrary::NetworkManagerObserver.
-  virtual void OnNetworkManagerChanged(NetworkLibrary* crosnet) OVERRIDE {
-    // TODO(stevenjb): Migrate to NetworkStateHandler.
-    data_promo_notification_->ShowOptionalMobileDataPromoNotification(
-        crosnet, GetPrimarySystemTray(), this);
-    UpdateCellular();
-  }
-
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
                        const content::NotificationSource& source,
@@ -1251,56 +1279,7 @@
         enabled, search_mapped_to_caps_lock);
   }
 
-  // Overridden from ash::NetworkTrayDelegate
-  virtual void NotificationLinkClicked(
-      ash::NetworkObserver::MessageType message_type,
-      size_t link_index) OVERRIDE {
-    if (message_type == ash::NetworkObserver::ERROR_OUT_OF_CREDITS) {
-      const NetworkState* cellular =
-          NetworkHandler::Get()->network_state_handler()->
-          FirstNetworkByType(flimflam::kTypeCellular);
-      std::string service_path = cellular ? cellular->path() : "";
-      ShowNetworkSettings(service_path);
-
-      ash::Shell::GetInstance()->system_tray_notifier()->
-          NotifyClearNetworkMessage(message_type);
-    }
-    if (message_type != ash::NetworkObserver::MESSAGE_DATA_PROMO)
-      return;
-    // If we have deal info URL defined that means that there're
-    // 2 links in bubble. Let the user close it manually then thus giving
-    // ability to navigate to second link.
-    // mobile_data_bubble_ will be set to NULL in BubbleClosing callback.
-    std::string deal_info_url = data_promo_notification_->deal_info_url();
-    std::string deal_topup_url = data_promo_notification_->deal_topup_url();
-    if (deal_info_url.empty())
-      data_promo_notification_->CloseNotification();
-
-    std::string deal_url_to_open;
-    if (link_index == 0) {
-      if (!deal_topup_url.empty()) {
-        deal_url_to_open = deal_topup_url;
-      } else {
-        const Network* cellular =
-            NetworkLibrary::Get()->cellular_network();
-        if (!cellular)
-          return;
-        ShowNetworkSettings(cellular->service_path());
-        return;
-      }
-    } else if (link_index == 1) {
-      deal_url_to_open = deal_info_url;
-    }
-
-    if (!deal_url_to_open.empty()) {
-      Browser* browser = GetAppropriateBrowser();
-      if (!browser)
-        return;
-      chrome::ShowSingletonTab(browser, GURL(deal_url_to_open));
-    }
-  }
-
-  virtual void UpdateEnterpriseDomain() {
+  void UpdateEnterpriseDomain() {
     std::string enterprise_domain =
         g_browser_process->browser_policy_connector()->GetEnterpriseDomain();
     if (enterprise_domain_ != enterprise_domain) {
@@ -1323,31 +1302,6 @@
     GetSystemTrayNotifier()->NotifyUserUpdate();
   }
 
-  void UpdateCellular() {
-    const CellularNetworkVector& cellular_networks =
-        NetworkLibrary::Get()->cellular_networks();
-    if (cellular_networks.empty())
-      return;
-    // We only care about the first cellular network (in practice there will
-    // only ever be one)
-    const CellularNetwork* cellular = cellular_networks[0];
-    if (cellular->activation_state() == ACTIVATION_STATE_ACTIVATING) {
-      cellular_activating_ = true;
-    } else if (cellular->activated() && cellular_activating_) {
-      cellular_activating_ = false;
-      ash::NetworkObserver::NetworkType type = NetworkTypeForCellular(cellular);
-      ash::Shell::GetInstance()->system_tray_notifier()->
-          NotifySetNetworkMessage(
-              NULL,
-              ash::NetworkObserver::MESSAGE_DATA_PROMO,
-              type,
-              l10n_util::GetStringUTF16(IDS_NETWORK_CELLULAR_ACTIVATED_TITLE),
-              l10n_util::GetStringFUTF16(IDS_NETWORK_CELLULAR_ACTIVATED,
-                                         UTF8ToUTF16((cellular->name()))),
-              std::vector<string16>());
-    }
-  }
-
   scoped_ptr<base::WeakPtrFactory<SystemTrayDelegate> > ui_weak_ptr_factory_;
   scoped_ptr<content::NotificationRegistrar> registrar_;
   scoped_ptr<PrefChangeRegistrar> local_state_registrar_;
@@ -1364,11 +1318,7 @@
   std::string enterprise_domain_;
 
   scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
-
   scoped_ptr<DataPromoNotification> data_promo_notification_;
-  bool cellular_activating_;
-  bool cellular_out_of_credits_;
-
   scoped_ptr<ash::VolumeControlDelegate> volume_control_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(SystemTrayDelegate);
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc b/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc
index 2f1e53e..6f76b35 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager_unittest.cc
@@ -309,7 +309,7 @@
 bool MockTimeSingleThreadTaskRunner::TemporalOrder::operator()(
     const std::pair<base::TimeTicks, base::Closure>& first_task,
     const std::pair<base::TimeTicks, base::Closure>& second_task) const {
-  return first_task.first >= second_task.first;
+  return first_task.first > second_task.first;
 }
 
 MockTimeSingleThreadTaskRunner::~MockTimeSingleThreadTaskRunner() {
diff --git a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
index 5370b98..47649cf 100644
--- a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
+++ b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
-#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
@@ -29,6 +28,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
+#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"
@@ -54,7 +54,7 @@
 }
 
 class TrayAccessibilityTest
-    : public CrosInProcessBrowserTest,
+    : public InProcessBrowserTest,
       public WithParamInterface<PrefSettingMechanism> {
  protected:
   TrayAccessibilityTest() {}
@@ -83,7 +83,7 @@
   virtual void RunTestOnMainThreadLoop() OVERRIDE {
     // Need to mark oobe completed to show detailed views.
     StartupUtils::MarkOobeCompleted();
-    CrosInProcessBrowserTest::RunTestOnMainThreadLoop();
+    InProcessBrowserTest::RunTestOnMainThreadLoop();
   }
 
   void SetShowAccessibilityOptionsInSystemTrayMenu(bool value) {
diff --git a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
index 8a8aeb5..7127c76 100644
--- a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.cc
@@ -131,24 +131,27 @@
     const KeyValueMap& user_log_files) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   if (succeeded) {
+    SystemLogsResponse* response = new SystemLogsResponse;
+    std::vector<Profile*> last_used = ProfileManager::GetLastOpenedProfiles();
     content::BrowserThread::PostBlockingPoolTaskAndReply(
         FROM_HERE,
-        base::Bind(
-            &DebugDaemonLogSource::ReadUserLogFiles,
-            weak_ptr_factory_.GetWeakPtr(),
-            user_log_files),
-        base::Bind(&DebugDaemonLogSource::RequestCompleted,
-                   weak_ptr_factory_.GetWeakPtr()));
+        base::Bind(&DebugDaemonLogSource::ReadUserLogFiles,
+                   user_log_files, last_used, response),
+        base::Bind(&DebugDaemonLogSource::MergeResponse,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   base::Owned(response)));
   } else {
     (*response_)[kUserLogFileKeyName] = kNotAvailable;
     RequestCompleted();
   }
 }
 
-void DebugDaemonLogSource::ReadUserLogFiles(const KeyValueMap& user_log_files) {
-  std::vector<Profile*> last_used = ProfileManager::GetLastOpenedProfiles();
-
-  for (size_t i = 0; i < last_used.size(); ++i) {
+// static
+void DebugDaemonLogSource::ReadUserLogFiles(
+    const KeyValueMap& user_log_files,
+    const std::vector<Profile*>& last_used_profiles,
+    SystemLogsResponse* response) {
+  for (size_t i = 0; i < last_used_profiles.size(); ++i) {
     std::string profile_prefix = "Profile[" + base::UintToString(i) + "] ";
     for (KeyValueMap::const_iterator it = user_log_files.begin();
          it != user_log_files.end();
@@ -156,18 +159,25 @@
       std::string key = it->first;
       std::string value;
       std::string filename = it->second;
-      base::FilePath profile_dir = last_used[i]->GetPath();
+      base::FilePath profile_dir = last_used_profiles[i]->GetPath();
       bool read_success = file_util::ReadFileToString(
           profile_dir.Append(filename), &value);
 
       if (read_success && !value.empty())
-        (*response_)[profile_prefix + key] = value;
+        (*response)[profile_prefix + key] = value;
       else
-        (*response_)[profile_prefix + filename] = kNotAvailable;
+        (*response)[profile_prefix + filename] = kNotAvailable;
     }
   }
 }
 
+void DebugDaemonLogSource::MergeResponse(SystemLogsResponse* response) {
+  for (SystemLogsResponse::const_iterator it = response->begin();
+       it != response->end(); ++it)
+    response_->insert(*it);
+  RequestCompleted();
+}
+
 void DebugDaemonLogSource::RequestCompleted() {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   DCHECK(!callback_.is_null());
diff --git a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h
index e68e60d..a842379 100644
--- a/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h
+++ b/chrome/browser/chromeos/system_logs/debug_daemon_log_source.h
@@ -12,6 +12,8 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/system_logs/system_logs_fetcher_base.h"
 
+class Profile;
+
 namespace chromeos {
 
 // Gathers log data from Debug Daemon.
@@ -40,8 +42,15 @@
                          const KeyValueMap& logs);
 
   // Read the contents of the specified user logs files and adds it to
-  // the response.
-  void ReadUserLogFiles(const KeyValueMap& user_log_files);
+  // the response parameter.
+  static void ReadUserLogFiles(
+      const KeyValueMap& user_log_files,
+      const std::vector<Profile*>& last_used_profiles,
+      SystemLogsResponse* response);
+
+  // Merge the responses from ReadUserLogFiles into the main response dict and
+  // call RequestComplete to indicate that the user log files read is complete.
+  void MergeResponse(SystemLogsResponse* response);
 
   // Sends the data to the callback_ when all the requests are completed
   void RequestCompleted();
diff --git a/chrome/browser/chromeos/system_logs/network_event_log_source.cc b/chrome/browser/chromeos/system_logs/network_event_log_source.cc
index 76c743b..56fd82e 100644
--- a/chrome/browser/chromeos/system_logs/network_event_log_source.cc
+++ b/chrome/browser/chromeos/system_logs/network_event_log_source.cc
@@ -17,7 +17,7 @@
   DCHECK(!callback.is_null());
 
   scoped_ptr<SystemLogsResponse> response(new SystemLogsResponse);
-  const int kMaxNetworkEventsForAboutSystem = 200;
+  const int kMaxNetworkEventsForAboutSystem = 400;
   (*response)[kNetworkEventLogEntry] = network_event_log::GetAsString(
       network_event_log::OLDEST_FIRST,
       "time,file,desc",
diff --git a/chrome/browser/chromeos/ui/app_launch_view.cc b/chrome/browser/chromeos/ui/app_launch_view.cc
deleted file mode 100644
index 9b8da56..0000000
--- a/chrome/browser/chromeos/ui/app_launch_view.cc
+++ /dev/null
@@ -1,194 +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/browser/chromeos/ui/app_launch_view.h"
-
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
-#include "ash/shell_window_ids.h"
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "chrome/browser/ui/webui/chromeos/app_launch_ui.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
-#include "grit/generated_resources.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/aura/root_window.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/screen.h"
-#include "ui/views/controls/webview/webview.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/widget/widget.h"
-
-using content::BrowserThread;
-
-namespace chromeos {
-
-internal::AppLaunchView* g_instance = NULL;
-
-void ShowAppLaunchSplashScreen(const std::string& app_id) {
-  // TODO(zelidrag): Come up with a better UI for this purpose.
-  internal::AppLaunchView::ShowAppLaunchSplashScreen(app_id);
-}
-
-void UpdateAppLaunchSplashScreenState(AppLaunchState state) {
-  internal::AppLaunchView::UpdateAppLaunchState(state);
-}
-
-void CloseAppLaunchSplashScreen() {
-  internal::AppLaunchView::CloseAppLaunchSplashScreen();
-}
-
-namespace internal {
-
-int GetProgressMessageFromState(AppLaunchState state) {
-  switch (state) {
-    case APP_LAUNCH_STATE_LOADING_AUTH_FILE:
-    case APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE:
-      // TODO(zelidrag): Add better string for this one than "Please wait..."
-      return IDS_SYNC_SETUP_SPINNER_TITLE;
-    case APP_LAUNCH_STATE_PREPARING_NETWORK:
-      return IDS_APP_START_NETWORK_WAIT_MESSAGE;
-    case APP_LAUNCH_STATE_INSTALLING_APPLICATION:
-      return IDS_APP_START_APP_WAIT_MESSAGE;
-  }
-  return IDS_APP_START_NETWORK_WAIT_MESSAGE;
-}
-
-// static
-void AppLaunchView::ShowAppLaunchSplashScreen(const std::string& app_id) {
-  if (!g_instance) {
-    g_instance = new AppLaunchView(app_id);
-    g_instance->Show();
-  }
-}
-
-void AppLaunchView::UpdateAppLaunchState(AppLaunchState state) {
-  if (g_instance)
-    g_instance->UpdateState(state);
-}
-
-
-// static
-void AppLaunchView::CloseAppLaunchSplashScreen() {
-  if (g_instance) {
-    g_instance->GetWidget()->Close();
-    g_instance = NULL;
-  }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AppLaunchView, views::WidgetDelegateView implementation.
-views::View* AppLaunchView::GetContentsView() {
-  return this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AppLaunchView, content::WebContentsObserver implementation.
-void AppLaunchView::RenderProcessGone(
-    base::TerminationStatus status) {
-  LOG(ERROR) << "Splash screen terminated with status " << status;
-  AppLaunchView::CloseAppLaunchSplashScreen();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AppLaunchView private methods.
-AppLaunchView::AppLaunchView(const std::string& app_id)
-    : app_launch_webview_(NULL),
-      container_window_(NULL),
-      app_id_(app_id),
-      state_(APP_LAUNCH_STATE_LOADING_AUTH_FILE),
-      app_launch_ui_(NULL) {
-}
-
-AppLaunchView::~AppLaunchView() {
-}
-
-void AppLaunchView::Show() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  // Add the WebView to our view.
-  AddChildWebContents();
-  // Initialize container window.
-  InitializeWindow();
-  // Show the window.
-  ShowWindow();
-}
-
-void AppLaunchView::AddChildWebContents() {
-  content::BrowserContext* context =
-      ash::Shell::GetInstance()->delegate()->GetCurrentBrowserContext();
-  app_launch_webview_ = new views::WebView(context);
-  SetLayoutManager(new views::FillLayout);
-  AddChildView(app_launch_webview_);
-
-  LoadSplashScreen();
-  content::WebContentsObserver::Observe(
-      app_launch_webview_->GetWebContents());
-}
-
-void AppLaunchView::UpdateState(AppLaunchState state) {
-  if (state == state_)
-    return;
-
-  state_ = state;
-  if (!app_launch_ui_)
-    return;
-
-  app_launch_ui_->SetLaunchText(
-      l10n_util::GetStringUTF8(GetProgressMessageFromState(state_)));
-}
-
-void AppLaunchView::LoadSplashScreen() {
-  std::string url = chrome::kChromeUIAppLaunchURL;
-  url += "?app=" + app_id_;
-
-  app_launch_webview_->GetWebContents()->GetController().LoadURL(
-      GURL(url),
-      content::Referrer(),
-      content::PAGE_TRANSITION_AUTO_TOPLEVEL,
-      std::string());
-
-  app_launch_ui_ = static_cast<AppLaunchUI*>(
-      app_launch_webview_->GetWebContents()->GetWebUI()->GetController());
-
-  // Use a background with transparency to trigger transparency in Webkit.
-  SkBitmap background;
-  background.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
-  background.allocPixels();
-  background.eraseARGB(0x00, 0x00, 0x00, 0x00);
-  content::RenderViewHost* host =
-      app_launch_webview_->GetWebContents()->GetRenderViewHost();
-  host->GetView()->SetBackground(background);
-}
-
-void AppLaunchView::InitializeWindow() {
-  DCHECK(!container_window_);
-  aura::RootWindow* root_window = ash::Shell::GetPrimaryRootWindow();
-
-  // We want to be the fullscreen topmost child of the root window.
-  // There should be nothing ever really that should show up on top of us.
-  container_window_ = new views::Widget();
-  views::Widget::InitParams params(
-      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
-  params.delegate = this;
-  params.parent = ash::Shell::GetContainer(
-      root_window,
-      ash::internal::kShellWindowId_LockScreenContainer);
-  params.show_state = ui::SHOW_STATE_FULLSCREEN;
-  container_window_->Init(params);
-}
-
-void AppLaunchView::ShowWindow() {
-  DCHECK(container_window_);
-  container_window_->Show();
-}
-
-}  // namespace internal
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/ui/app_launch_view.h b/chrome/browser/chromeos/ui/app_launch_view.h
deleted file mode 100644
index f4c4382..0000000
--- a/chrome/browser/chromeos/ui/app_launch_view.h
+++ /dev/null
@@ -1,97 +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 CHROME_BROWSER_CHROMEOS_UI_APP_LAUNCH_VIEW_H_
-#define CHROME_BROWSER_CHROMEOS_UI_APP_LAUNCH_VIEW_H_
-
-#include <string>
-
-#include "ash/ash_export.h"
-#include "base/callback.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "url/gurl.h"
-
-namespace content {
-class BrowserContent;
-}
-
-namespace views {
-class WebView;
-}
-
-namespace chromeos {
-
-class AppLaunchUI;
-
-enum AppLaunchState {
-  APP_LAUNCH_STATE_LOADING_AUTH_FILE,
-  APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE,
-  APP_LAUNCH_STATE_PREPARING_NETWORK,
-  APP_LAUNCH_STATE_INSTALLING_APPLICATION,
-};
-
-void ShowAppLaunchSplashScreen(const std::string& app_id);
-void CloseAppLaunchSplashScreen();
-void UpdateAppLaunchSplashScreenState(AppLaunchState state);
-
-namespace internal {
-
-// Shows application launch/install splash screen in exclusive app mode (kiosk).
-class AppLaunchView : public views::WidgetDelegateView,
-                      public content::WebContentsObserver {
- public:
-  static void ShowAppLaunchSplashScreen(const std::string& app_id);
-  static void CloseAppLaunchSplashScreen();
-  static void UpdateAppLaunchState(AppLaunchState state);
-
- private:
-  explicit AppLaunchView(const std::string& app_id);
-  virtual ~AppLaunchView();
-
-  // views::WidgetDelegate overrides.
-  virtual views::View* GetContentsView() OVERRIDE;
-
-  // content::WebContentsObserver overrides.
-  virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
-
-  void Show();
-
-  // Updates UI state of the app launch splash screen.
-  void UpdateState(AppLaunchState state);
-
-  // Creates and adds web contents to our view.
-  void AddChildWebContents();
-
-  // Loads the splash screen in the WebView's webcontent. If the webcontents
-  // don't exist, they'll be created by WebView.
-  void LoadSplashScreen();
-
-  // Initializes container window.
-  void InitializeWindow();
-
-  // Creates and shows a frameless full screen window containing our view.
-  void ShowWindow();
-
-  // Host for the extension that implements this dialog.
-  views::WebView* app_launch_webview_;
-
-  // Window that holds the webview.
-  views::Widget* container_window_;
-
-  const std::string app_id_;
-
-  // Launch state.
-  AppLaunchState state_;
-
-  AppLaunchUI* app_launch_ui_;  // Not owned.
-
-  DISALLOW_COPY_AND_ASSIGN(AppLaunchView);
-};
-
-}  // namespace internal
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_UI_APP_LAUNCH_VIEW_H_
diff --git a/chrome/browser/component_updater/component_updater_configurator.cc b/chrome/browser/component_updater/component_updater_configurator.cc
index f85c7db..bc814f2 100644
--- a/chrome/browser/component_updater/component_updater_configurator.cc
+++ b/chrome/browser/component_updater/component_updater_configurator.cc
@@ -92,6 +92,7 @@
   virtual int InitialDelay() OVERRIDE;
   virtual int NextCheckDelay() OVERRIDE;
   virtual int StepDelay() OVERRIDE;
+  virtual int StepDelayMedium() OVERRIDE;
   virtual int MinimumReCheckWait() OVERRIDE;
   virtual int OnDemandDelay() OVERRIDE;
   virtual GURL UpdateUrl() OVERRIDE;
@@ -159,6 +160,10 @@
   return fast_update_ ? 3 : (2 * kDelayOneHour);
 }
 
+int ChromeConfigurator::StepDelayMedium() {
+  return fast_update_ ? 3 : (15 * kDelayOneMinute);
+}
+
 int ChromeConfigurator::StepDelay() {
   return fast_update_ ? 1 : 4;
 }
diff --git a/chrome/browser/component_updater/component_updater_service.cc b/chrome/browser/component_updater/component_updater_service.cc
index 1a6f935..8bc0756 100644
--- a/chrome/browser/component_updater/component_updater_service.cc
+++ b/chrome/browser/component_updater/component_updater_service.cc
@@ -224,6 +224,17 @@
 CrxComponent::~CrxComponent() {
 }
 
+std::string GetCrxComponentID(const CrxComponent& component) {
+  return HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
+                                          component.pk_hash.size()/2)));
+}
+
+CrxComponentInfo::CrxComponentInfo() {
+}
+
+CrxComponentInfo::~CrxComponentInfo() {
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // The one and only implementation of the ComponentUpdateService interface. In
 // charge of running the show. The main method is ProcessPendingItems() which
@@ -247,7 +258,9 @@
   virtual Status Start() OVERRIDE;
   virtual Status Stop() OVERRIDE;
   virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
-  virtual Status CheckForUpdateSoon(const CrxComponent& component) OVERRIDE;
+  virtual Status CheckForUpdateSoon(const std::string& component_id) OVERRIDE;
+  virtual void GetComponents(
+      std::vector<CrxComponentInfo>* components) OVERRIDE;
 
   // The only purpose of this class is to forward the
   // UtilityProcessHostClient callbacks so CrxUpdateService does
@@ -314,6 +327,12 @@
     kInstallError,
   };
 
+  enum StepDelayInterval {
+    kStepDelayShort = 0,
+    kStepDelayMedium,
+    kStepDelayLong,
+  };
+
   // See ManifestParserBridge.
   void OnParseUpdateManifestSucceeded(const UpdateManifest::Results& results);
 
@@ -324,7 +343,7 @@
 
   void ProcessPendingItems();
 
-  void ScheduleNextRun(bool step_delay);
+  void ScheduleNextRun(StepDelayInterval step_delay);
 
   void ParseManifest(const std::string& xml);
 
@@ -411,10 +430,13 @@
 
 // This function sets the timer which will call ProcessPendingItems() or
 // ProcessRequestedItem() if there is an important requested item.  There
-// are two kinds of waits: a short step_delay (when step_status is
-// kPrevInProgress) and a long one when a full check/update cycle
-// has completed either successfully or with an error.
-void CrxUpdateService::ScheduleNextRun(bool step_delay) {
+// 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
+//    update cycle, or there are components that are still unchecked.
+//  - a long delay when a full check/update cycle has completed for all
+//    components.
+void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(url_fetcher_.get() == NULL);
   CHECK(!timer_.IsRunning());
@@ -426,18 +448,32 @@
 
   // 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 = (step_delay || requested_work_items_.size() > 0)
-      ? config_->StepDelay() : config_->NextCheckDelay();
+  int64 delay_seconds = 0;
+  if (requested_work_items_.empty()) {
+    switch (step_delay) {
+      case kStepDelayShort:
+        delay_seconds = config_->StepDelay();
+        break;
+      case kStepDelayMedium:
+        delay_seconds = config_->StepDelayMedium();
+        break;
+      case kStepDelayLong:
+        delay_seconds = config_->NextCheckDelay();
+        break;
+    }
+  } else {
+    delay_seconds = config_->StepDelay();
+  }
 
-  if (!step_delay) {
+  if (step_delay != kStepDelayShort) {
     NotifyComponentObservers(ComponentObserver::COMPONENT_UPDATER_SLEEPING, 0);
 
     // Zero is only used for unit tests.
-    if (0 == delay)
+    if (0 == delay_seconds)
       return;
   }
 
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay),
+  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(delay_seconds),
                this, &CrxUpdateService::ProcessPendingItems);
 }
 
@@ -540,19 +576,11 @@
 
 // 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(
-    const CrxComponent& component) {
-  if (component.pk_hash.empty() ||
-      !component.version.IsValid() ||
-      !component.installer)
-    return kError;
-
-  std::string id =
-    HexStringToID(StringToLowerASCII(base::HexEncode(&component.pk_hash[0],
-                                     component.pk_hash.size()/2)));
-
+    const std::string& component_id) {
   CrxUpdateItem* uit;
-  uit = FindUpdateItemById(id);
+  uit = FindUpdateItemById(component_id);
   if (!uit)
     return kError;
 
@@ -595,6 +623,20 @@
   return kOk;
 }
 
+void CrxUpdateService::GetComponents(
+    std::vector<CrxComponentInfo>* components) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  for (UpdateItems::const_iterator it = work_items_.begin();
+       it != work_items_.end(); ++it) {
+    const CrxUpdateItem* item = *it;
+    CrxComponentInfo info;
+    info.id = GetCrxComponentID(item->component);
+    info.version = item->component.version.GetString();
+    info.name = item->component.name;
+    components->push_back(info);
+  }
+}
+
 // 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.
 void CrxUpdateService::ProcessPendingItems() {
@@ -693,7 +735,7 @@
   }
 
   // No components to update. Next check after the long sleep.
-  ScheduleNextRun(false);
+  ScheduleNextRun(kStepDelayLong);
 }
 
 // Called when we got a response from the update server. It consists of an xml
@@ -786,8 +828,9 @@
   // consider them up to date.
   ChangeItemStatus(CrxUpdateItem::kChecking, CrxUpdateItem::kUpToDate);
 
-  // If there are updates pending we do a short wait.
-  ScheduleNextRun(update_pending > 0);
+  // If there are updates pending we do a short wait, otherwise we take
+  // a longer delay until we check the components again.
+  ScheduleNextRun(update_pending > 0 ? kStepDelayShort : kStepDelayMedium);
 }
 
 void CrxUpdateService::OnParseUpdateManifestFailed(
@@ -796,7 +839,7 @@
   size_t count = ChangeItemStatus(CrxUpdateItem::kChecking,
                                   CrxUpdateItem::kNoUpdate);
   DCHECK_GT(count, 0ul);
-  ScheduleNextRun(false);
+  ScheduleNextRun(kStepDelayLong);
 }
 
 // Called when the CRX package has been downloaded to a temporary location.
@@ -821,7 +864,7 @@
       DCHECK_EQ(count, 1ul);
       url_fetcher_.reset();
 
-      ScheduleNextRun(true);
+      ScheduleNextRun(kStepDelayShort);
       return;
     }
     crx->error_category = kNetworkError;
@@ -835,7 +878,8 @@
     // the update for this component has finished with an error.
     ping_manager_->OnUpdateComplete(crx);
 
-    ScheduleNextRun(false);
+    // Move on to the next update, if there is one available.
+    ScheduleNextRun(kStepDelayMedium);
   } else {
     base::FilePath temp_crx_path;
     CHECK(source->GetResponseAsFilePath(true, &temp_crx_path));
@@ -925,7 +969,7 @@
       size_t count = ChangeItemStatus(CrxUpdateItem::kUpdatingDiff,
                                       CrxUpdateItem::kCanUpdate);
       DCHECK_EQ(count, 1ul);
-      ScheduleNextRun(true);
+      ScheduleNextRun(kStepDelayShort);
       return;
     }
 
@@ -942,7 +986,8 @@
 
   ping_manager_->OnUpdateComplete(item);
 
-  ScheduleNextRun(false);
+  // Move on to the next update, if there is one available.
+  ScheduleNextRun(kStepDelayMedium);
 }
 
 void CrxUpdateService::NotifyComponentObservers(
diff --git a/chrome/browser/component_updater/component_updater_service.h b/chrome/browser/component_updater/component_updater_service.h
index 4a02157..782f250 100644
--- a/chrome/browser/component_updater/component_updater_service.h
+++ b/chrome/browser/component_updater/component_updater_service.h
@@ -92,6 +92,20 @@
   ~CrxComponent();
 };
 
+// This convenience function returns component id of given CrxComponent.
+std::string GetCrxComponentID(const CrxComponent& component);
+
+// Convenience structure to use with component listing / enumeration.
+struct CrxComponentInfo {
+  // |id| is currently derived from |CrxComponent.pk_hash|, see rest of the
+  // class implementation for details.
+  std::string id;
+  std::string version;
+  std::string name;
+  CrxComponentInfo();
+  ~CrxComponentInfo();
+};
+
 // The component update service is in charge of installing or upgrading
 // select parts of chrome. Each part is called a component and managed by
 // instances of CrxComponent registered using RegisterComponent(). On the
@@ -125,6 +139,9 @@
     virtual int NextCheckDelay() = 0;
     // Delay in seconds from each task step. Used to smooth out CPU/IO usage.
     virtual int StepDelay() = 0;
+    // Delay in seconds between applying updates for different components, if
+    // several updates are available at a given time.
+    virtual int StepDelayMedium() = 0;
     // Minimum delta time in seconds before checking again the same component.
     virtual int MinimumReCheckWait() = 0;
     // Minimum delta time in seconds before an on-demand check is allowed
@@ -171,7 +188,10 @@
   // 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 CrxComponent& component) = 0;
+  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() {}
 };
diff --git a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
index ebbc0a7..5f17042 100644
--- a/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
+++ b/chrome/browser/component_updater/pnacl/pnacl_component_installer.cc
@@ -481,7 +481,7 @@
   set_current_version(Version(kNullVersion));
   CrxComponent pnacl_component = GetCrxComponent();
   ComponentUpdateService::Status status = cus_->CheckForUpdateSoon(
-      pnacl_component);
+      GetCrxComponentID(pnacl_component));
   if (status != ComponentUpdateService::kOk) {
     cb.Run(false);
     return;
diff --git a/chrome/browser/component_updater/ppapi_utils.cc b/chrome/browser/component_updater/ppapi_utils.cc
index 1de518c..9696747 100644
--- a/chrome/browser/component_updater/ppapi_utils.cc
+++ b/chrome/browser/component_updater/ppapi_utils.cc
@@ -83,7 +83,6 @@
 #include "ppapi/c/private/ppb_flash_menu.h"
 #include "ppapi/c/private/ppb_flash_message_loop.h"
 #include "ppapi/c/private/ppb_flash_print.h"
-#include "ppapi/c/private/ppb_gpu_blacklist_private.h"
 #include "ppapi/c/private/ppb_host_resolver_private.h"
 #include "ppapi/c/private/ppb_network_list_private.h"
 #include "ppapi/c/private/ppb_network_monitor_private.h"
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 0f1512f..f4d2ee4 100644
--- a/chrome/browser/component_updater/test/component_updater_service_unittest.cc
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.cc
@@ -4,13 +4,10 @@
 
 #include "chrome/browser/component_updater/test/component_updater_service_unittest.h"
 #include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_vector.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
-#include "chrome/browser/component_updater/component_updater_service.h"
 #include "chrome/browser/component_updater/test/test_installer.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/test/net/url_request_prepackaged_interceptor.h"
@@ -60,7 +57,7 @@
            i = components_to_check_.begin();
        i != components_to_check_.end(); ) {
     if (i->second == times_) {
-      cus_->CheckForUpdateSoon(*i->first);
+      cus_->CheckForUpdateSoon(GetCrxComponentID(*i->first));
       i = components_to_check_.erase(i);
     } else {
       ++i;
@@ -73,6 +70,10 @@
   return 0;
 }
 
+int TestConfigurator::StepDelayMedium() {
+  return NextCheckDelay();
+}
+
 int TestConfigurator::MinimumReCheckWait() {
   return recheck_time_;
 }
@@ -210,6 +211,7 @@
     int size = reader->length();
     scoped_refptr <net::IOBuffer> buffer = new net::IOBuffer(size);
     std::string data(reader->bytes());
+    pings_.push_back(data);
     // For now, we assume that there is only one ping per POST.
     std::string::size_type start = data.find("<o:event");
     if (start != std::string::npos) {
@@ -231,6 +233,16 @@
   return false;
 }
 
+std::string PingChecker::GetPings() const {
+  std::string pings_str = "Pings are:";
+  int i = 0;
+  for (std::vector<std::string>::const_iterator it = pings_.begin();
+      it != pings_.end(); ++it) {
+    pings_str.append(base::StringPrintf("\n  (%d): %s", ++i, it->c_str()));
+  }
+  return pings_str;
+}
+
 // Verify that our test fixture work and the component updater can
 // be created and destroyed with no side effects.
 TEST_F(ComponentUpdaterTest, VerifyFixture) {
@@ -399,8 +411,8 @@
   EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
 
   EXPECT_EQ(3, interceptor.GetHitCount());
-  EXPECT_EQ(1, ping_checker.NumHits());
-  EXPECT_EQ(0, ping_checker.NumMisses());
+  EXPECT_EQ(1, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(0, ping_checker.NumMisses()) << ping_checker.GetPings();
 
   component_updater()->Stop();
 }
@@ -431,8 +443,8 @@
   component_updater()->Start();
   message_loop_.Run();
 
-  EXPECT_EQ(0, ping_checker.NumHits());
-  EXPECT_EQ(0, ping_checker.NumMisses());
+  EXPECT_EQ(0, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(0, ping_checker.NumMisses()) << ping_checker.GetPings();
   EXPECT_EQ(1, interceptor.GetHitCount());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->install_count());
@@ -533,7 +545,7 @@
   // Also check what happens if previous check too soon.
   test_configurator()->SetOnDemandTime(60 * 60);
   EXPECT_EQ(ComponentUpdateService::kError,
-            component_updater()->CheckForUpdateSoon(com2));
+            component_updater()->CheckForUpdateSoon(GetCrxComponentID(com2)));
   // Okay, now reset to 0 for the other tests.
   test_configurator()->SetOnDemandTime(0);
   component_updater()->Stop();
@@ -572,7 +584,7 @@
   test_configurator()->SetLoopCount(1);
   component_updater()->Start();
   EXPECT_EQ(ComponentUpdateService::kOk,
-            component_updater()->CheckForUpdateSoon(com2));
+            component_updater()->CheckForUpdateSoon(GetCrxComponentID(com2)));
 
   message_loop_.Run();
 
@@ -605,12 +617,12 @@
   test_configurator()->SetLoopCount(1);
   component_updater()->Start();
   EXPECT_EQ(ComponentUpdateService::kOk,
-            component_updater()->CheckForUpdateSoon(com2));
+            component_updater()->CheckForUpdateSoon(GetCrxComponentID(com2)));
 
   message_loop_.Run();
 
-  EXPECT_EQ(1, ping_checker.NumHits());
-  EXPECT_EQ(0, ping_checker.NumMisses());
+  EXPECT_EQ(1, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(0, ping_checker.NumMisses()) << ping_checker.GetPings();
 
   component_updater()->Stop();
 }
@@ -701,8 +713,8 @@
   EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->error());
   EXPECT_EQ(0, static_cast<TestInstaller*>(com2.installer)->install_count());
 
-  EXPECT_EQ(1, ping_checker.NumHits());
-  EXPECT_EQ(0, ping_checker.NumMisses());
+  EXPECT_EQ(1, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(0, ping_checker.NumMisses()) << ping_checker.GetPings();
   EXPECT_EQ(3, interceptor.GetHitCount());
 
   component_updater()->Stop();
@@ -822,8 +834,8 @@
   EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count());
 
   // One ping has the diffresult=1, the other does not.
-  EXPECT_EQ(1, ping_checker.NumHits());
-  EXPECT_EQ(1, ping_checker.NumMisses());
+  EXPECT_EQ(1, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(1, ping_checker.NumMisses()) << ping_checker.GetPings();
 
   EXPECT_EQ(5, interceptor.GetHitCount());
 
@@ -889,8 +901,8 @@
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
   EXPECT_EQ(1, static_cast<TestInstaller*>(com.installer)->install_count());
 
-  EXPECT_EQ(1, ping_checker.NumHits());
-  EXPECT_EQ(0, ping_checker.NumMisses());
+  EXPECT_EQ(1, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(0, ping_checker.NumMisses()) << ping_checker.GetPings();
   EXPECT_EQ(4, interceptor.GetHitCount());
 
   component_updater()->Stop();
@@ -950,8 +962,8 @@
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
   EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count());
 
-  EXPECT_EQ(2, ping_checker.NumHits());
-  EXPECT_EQ(0, ping_checker.NumMisses());
+  EXPECT_EQ(2, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(0, ping_checker.NumMisses()) << ping_checker.GetPings();
   EXPECT_EQ(5, interceptor.GetHitCount());
 
   component_updater()->Stop();
@@ -1013,8 +1025,8 @@
   EXPECT_EQ(0, static_cast<TestInstaller*>(com.installer)->error());
   EXPECT_EQ(2, static_cast<TestInstaller*>(com.installer)->install_count());
 
-  EXPECT_EQ(1, ping_checker.NumHits());
-  EXPECT_EQ(1, ping_checker.NumMisses());
+  EXPECT_EQ(1, ping_checker.NumHits()) << ping_checker.GetPings();
+  EXPECT_EQ(1, ping_checker.NumMisses()) << ping_checker.GetPings();
   EXPECT_EQ(6, interceptor.GetHitCount());
 
   component_updater()->Stop();
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 752b17b..8ec30d3 100644
--- a/chrome/browser/component_updater/test/component_updater_service_unittest.h
+++ b/chrome/browser/component_updater/test/component_updater_service_unittest.h
@@ -9,6 +9,7 @@
 #include <map>
 #include <string>
 #include <utility>
+#include <vector>
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
@@ -58,6 +59,8 @@
 
   virtual int StepDelay() OVERRIDE;
 
+  virtual int StepDelayMedium() OVERRIDE;
+
   virtual int MinimumReCheckWait() OVERRIDE;
 
   virtual int OnDemandDelay() OVERRIDE;
@@ -153,8 +156,10 @@
   int NumMisses() const {
     return num_misses_;
   }
+  std::string GetPings() const;
 
  private:
+  std::vector<std::string> pings_;
   int num_hits_;
   int num_misses_;
   const std::map<std::string, std::string> attributes_;
diff --git a/chrome/browser/content_settings/content_settings_default_provider.cc b/chrome/browser/content_settings/content_settings_default_provider.cc
index 7e24ce6..3a7c891 100644
--- a/chrome/browser/content_settings/content_settings_default_provider.cc
+++ b/chrome/browser/content_settings/content_settings_default_provider.cc
@@ -54,6 +54,7 @@
 #if defined(OS_WIN)
   CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP
 #endif
+  CONTENT_SETTING_ASK,      // CONTENT_SETTINGS_TYPE_SAVE_PASSWORD
 };
 COMPILE_ASSERT(arraysize(kDefaultSettings) == CONTENT_SETTINGS_NUM_TYPES,
                default_settings_incorrect_size);
diff --git a/chrome/browser/content_settings/content_settings_policy_provider.cc b/chrome/browser/content_settings/content_settings_policy_provider.cc
index 8e32289..b2dcdea 100644
--- a/chrome/browser/content_settings/content_settings_policy_provider.cc
+++ b/chrome/browser/content_settings/content_settings_policy_provider.cc
@@ -47,6 +47,7 @@
 #if defined(OS_WIN)
   NULL,  // No policy for default value of "switch to desktop"
 #endif
+  NULL,  // No policy for default value of save password
 };
 COMPILE_ASSERT(arraysize(kPrefToManageType) == CONTENT_SETTINGS_NUM_TYPES,
                managed_content_settings_pref_names_array_size_incorrect);
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 b1c8a62..3646541 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -154,11 +154,10 @@
   scoped_ptr<TestingProfile> profile = profile_builder.Build();
 
   TestingProfile::Builder otr_profile_builder;
+  otr_profile_builder.SetIncognito();
   otr_profile_builder.SetPrefService(make_scoped_ptr(otr_prefs));
-  TestingProfile* otr_profile = otr_profile_builder.Build().release();
-
-  otr_profile->set_incognito(true);
-  profile->SetOffTheRecordProfile(otr_profile);
+  scoped_ptr<TestingProfile> otr_profile(otr_profile_builder.Build());
+  profile->SetOffTheRecordProfile(otr_profile.PassAs<Profile>());
 
   PrefProvider pref_content_settings_provider(regular_prefs, false);
   PrefProvider pref_content_settings_provider_incognito(otr_prefs, true);
diff --git a/chrome/browser/content_settings/content_settings_utils.cc b/chrome/browser/content_settings/content_settings_utils.cc
index 7800018..c95b907 100644
--- a/chrome/browser/content_settings/content_settings_utils.cc
+++ b/chrome/browser/content_settings/content_settings_utils.cc
@@ -44,6 +44,7 @@
 #if defined(OS_WIN)
   "metro-switch-to-desktop",
 #endif
+  "save-password",
 };
 COMPILE_ASSERT(arraysize(kTypeNames) == CONTENT_SETTINGS_NUM_TYPES,
                type_names_incorrect_size);
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index d8e4278..1a19e37 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/content_settings/content_settings_details.h"
 #include "chrome/browser/content_settings/content_settings_utils.h"
 #include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/password_manager/password_form_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/render_messages.h"
@@ -240,7 +241,8 @@
       content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA &&
       content_type != CONTENT_SETTINGS_TYPE_PPAPI_BROKER &&
       content_type != CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS &&
-      content_type != CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
+      content_type != CONTENT_SETTINGS_TYPE_MIDI_SYSEX &&
+      content_type != CONTENT_SETTINGS_TYPE_SAVE_PASSWORD) {
     return false;
   }
 
@@ -320,7 +322,8 @@
   DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
       << "Geolocation settings handled by OnGeolocationPermissionSet";
   bool access_changed = false;
-  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
+  if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
+      type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
     // The setting for media is overwritten here because media does not need to
     // reload the page to have the new setting kick in. See issue/175993.
     if (content_blocked_[type]) {
@@ -460,6 +463,21 @@
       content::NotificationService::NoDetails());
 }
 
+// TODO(npentrel): Save the password when user accepts the prompt
+void TabSpecificContentSettings::OnPasswordSubmitted(
+      PasswordFormManager* form_to_save) {
+  OnContentAllowed(CONTENT_SETTINGS_TYPE_SAVE_PASSWORD);
+  NotifySiteDataObservers();
+}
+
+TabSpecificContentSettings::PasswordSavingState
+TabSpecificContentSettings::GetPasswordSavingState() const {
+  if (IsContentAllowed(CONTENT_SETTINGS_TYPE_SAVE_PASSWORD))
+    return PASSWORD_TO_BE_SAVED;
+  else
+    return NO_PASSWORD_TO_BE_SAVED;
+}
+
 TabSpecificContentSettings::MicrophoneCameraState
 TabSpecificContentSettings::GetMicrophoneCameraState() const {
   if (IsContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) &&
@@ -483,20 +501,44 @@
   return MICROPHONE_CAMERA_NOT_ACCESSED;
 }
 
-void TabSpecificContentSettings::OnMicrophoneAccessed() {
-  OnContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
-}
+void TabSpecificContentSettings::OnMediaStreamPermissionSet(
+    const GURL& request_origin,
+    const MediaStreamDevicesController::MediaStreamTypePermissionMap&
+        request_permissions) {
+  media_stream_access_origin_ = request_origin;
 
-void TabSpecificContentSettings::OnMicrophoneAccessBlocked() {
-  OnContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string());
-}
+  MediaStreamDevicesController::MediaStreamTypePermissionMap::const_iterator
+      it = request_permissions.find(content::MEDIA_DEVICE_AUDIO_CAPTURE);
+  if (it != request_permissions.end()) {
+    switch (it->second) {
+      case MediaStreamDevicesController::MEDIA_ALLOWED:
+        OnContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
+        break;
+      // TODO(grunell): UI should show for what reason access has been blocked.
+      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_POLICY:
+      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER_SETTING:
+      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER:
+        OnContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
+                         std::string());
+        break;
+    }
+  }
 
-void TabSpecificContentSettings::OnCameraAccessed() {
-  OnContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
-}
-
-void TabSpecificContentSettings::OnCameraAccessBlocked() {
-  OnContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string());
+  it = request_permissions.find(content::MEDIA_DEVICE_VIDEO_CAPTURE);
+  if (it != request_permissions.end()) {
+    switch (it->second) {
+      case MediaStreamDevicesController::MEDIA_ALLOWED:
+        OnContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
+        break;
+      // TODO(grunell): UI should show for what reason access has been blocked.
+      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_POLICY:
+      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER_SETTING:
+      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER:
+        OnContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
+                         std::string());
+        break;
+    }
+  }
 }
 
 void TabSpecificContentSettings::OnMIDISysExAccessed(
@@ -652,12 +694,12 @@
 
   content::Details<const ContentSettingsDetails> settings_details(details);
   const NavigationController& controller = web_contents()->GetController();
-  NavigationEntry* entry = controller.GetActiveEntry();
+  NavigationEntry* entry = controller.GetVisibleEntry();
   GURL entry_url;
   if (entry)
     entry_url = entry->GetURL();
   if (settings_details.ptr()->update_all() ||
-      // The active NavigationEntry is the URL in the URL field of a tab.
+      // The visible NavigationEntry is the URL in the URL field of a tab.
       // Currently this should be matched by the |primary_pattern|.
       settings_details.ptr()->primary_pattern().Matches(entry_url)) {
     Profile* profile =
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.h b/chrome/browser/content_settings/tab_specific_content_settings.h
index 072b9da..b4873b7 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.h
+++ b/chrome/browser/content_settings/tab_specific_content_settings.h
@@ -14,6 +14,7 @@
 #include "base/observer_list.h"
 #include "chrome/browser/content_settings/content_settings_usages_state.h"
 #include "chrome/browser/content_settings/local_shared_objects_container.h"
+#include "chrome/browser/media/media_stream_devices_controller.h"
 #include "chrome/common/content_settings.h"
 #include "chrome/common/content_settings_types.h"
 #include "chrome/common/custom_handlers/protocol_handler.h"
@@ -21,9 +22,11 @@
 #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 "content/public/common/media_stream_request.h"
 #include "net/cookies/canonical_cookie.h"
 
 class CookiesTreeModel;
+class PasswordFormManager;
 class Profile;
 
 namespace content {
@@ -53,6 +56,11 @@
     MICROPHONE_CAMERA_BLOCKED,
   };
 
+  enum PasswordSavingState {
+    NO_PASSWORD_TO_BE_SAVED = 0,
+    PASSWORD_TO_BE_SAVED,
+  };
+
   // Classes that want to be notified about site data events must implement
   // this abstract class and add themselves as observer to the
   // |TabSpecificContentSettings|.
@@ -188,9 +196,17 @@
   // only tracks cookies.
   bool IsContentAllowed(ContentSettingsType content_type) const;
 
+  const GURL& media_stream_access_origin() const {
+    return media_stream_access_origin_;
+  }
+
   // Returns the state of the camera and microphone usage.
   MicrophoneCameraState GetMicrophoneCameraState() const;
 
+  // TODO(npentrel): Change to bool if not needed once feature is implemented.
+  // Returns the state of whether there is a password to be saved or not.
+  PasswordSavingState GetPasswordSavingState() const;
+
   const std::set<std::string>& BlockedResourcesForType(
       ContentSettingsType content_type) const;
 
@@ -206,6 +222,8 @@
     return midi_usages_state_;
   }
 
+  void OnPasswordSubmitted(PasswordFormManager* form_to_save);
+
   // Call to indicate that there is a protocol handler pending user approval.
   void set_pending_protocol_handler(const ProtocolHandler& handler) {
     pending_protocol_handler_ = handler;
@@ -310,12 +328,13 @@
   void OnGeolocationPermissionSet(const GURL& requesting_frame,
                                   bool allowed);
 
-  // These methods are called to update the status about the microphone and
-  // camera stream access.
-  void OnMicrophoneAccessed();
-  void OnMicrophoneAccessBlocked();
-  void OnCameraAccessed();
-  void OnCameraAccessBlocked();
+  // This method is called to update the status about the microphone and
+  // camera stream access. |request_permissions| contains a list of requested
+  // media stream types and the permission for each type.
+  void OnMediaStreamPermissionSet(
+      const GURL& request_origin,
+      const MediaStreamDevicesController::MediaStreamTypePermissionMap&
+          request_permissions);
 
   // There methods are called to update the status about MIDI access.
   void OnMIDISysExAccessed(const GURL& reqesting_origin);
@@ -393,6 +412,11 @@
 
   content::NotificationRegistrar registrar_;
 
+  // The origin of the media stream request. Note that we only support handling
+  // settings for one request per tab. The latest request's origin will be
+  // stored here. http://crbug.com/259794
+  GURL media_stream_access_origin_;
+
   DISALLOW_COPY_AND_ASSIGN(TabSpecificContentSettings);
 };
 
diff --git a/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc b/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
index ac85f63..a149a49 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings_unittest.cc
@@ -195,13 +195,23 @@
       content_settings->IsContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES));
   ASSERT_TRUE(
       content_settings->IsContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES));
+}
 
+TEST_F(TabSpecificContentSettingsTest, AllowedBlockedMediaContent) {
+  TabSpecificContentSettings* content_settings =
+      TabSpecificContentSettings::FromWebContents(web_contents());
 
   ASSERT_EQ(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED,
             content_settings->GetMicrophoneCameraState());
 
-  // Access microphone.
-  content_settings->OnMicrophoneAccessed();
+  // Request and allow microphone access.
+  GURL security_origin("http://google.com");
+  MediaStreamDevicesController::MediaStreamTypePermissionMap
+      request_permissions;
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
   ASSERT_TRUE(content_settings->IsContentAllowed(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
   ASSERT_FALSE(content_settings->IsContentBlocked(
@@ -209,8 +219,12 @@
   ASSERT_EQ(TabSpecificContentSettings::MICROPHONE_ACCESSED,
             content_settings->GetMicrophoneCameraState());
 
-  // Allow mediastream access.
-  content_settings->OnCameraAccessed();
+  // Request and allow camera access.
+  request_permissions.clear();
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
   ASSERT_TRUE(content_settings->IsContentAllowed(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
   ASSERT_FALSE(content_settings->IsContentBlocked(
@@ -218,34 +232,101 @@
   ASSERT_EQ(TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED,
             content_settings->GetMicrophoneCameraState());
 
-  // Allow mediastream microphone access.
-  content_settings->OnMicrophoneAccessBlocked();
+  // Request and block microphone access.
+  request_permissions.clear();
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
   ASSERT_FALSE(content_settings->IsContentAllowed(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
   ASSERT_TRUE(content_settings->IsContentBlocked(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_EQ(TabSpecificContentSettings::CAMERA_ACCESSED,
+            content_settings->GetMicrophoneCameraState());
 
-  // Allow mediastream camera access.
-  content_settings->OnCameraAccessBlocked();
+  // Request and block camera access.
+  request_permissions.clear();
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
   ASSERT_FALSE(content_settings->IsContentAllowed(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
   ASSERT_TRUE(content_settings->IsContentBlocked(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_EQ(TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED,
+            content_settings->GetMicrophoneCameraState());
 
+  // Request and allow microphone and camera access.
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
+  ASSERT_TRUE(content_settings->IsContentAllowed(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_FALSE(content_settings->IsContentBlocked(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_TRUE(content_settings->IsContentAllowed(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_FALSE(content_settings->IsContentBlocked(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_EQ(TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED,
+            content_settings->GetMicrophoneCameraState());
 
-  // Record a blocked mediastream microphone access request.
-  content_settings->OnMicrophoneAccessBlocked();
+  // Request and block microphone and camera access.
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
   ASSERT_FALSE(content_settings->IsContentAllowed(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
   ASSERT_TRUE(content_settings->IsContentBlocked(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
-
-  // Record a blocked mediastream microphone access request.
-  content_settings->OnCameraAccessBlocked();
   ASSERT_FALSE(content_settings->IsContentAllowed(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
   ASSERT_TRUE(content_settings->IsContentBlocked(
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_EQ(TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED,
+            content_settings->GetMicrophoneCameraState());
+
+  // Request microphone and camera access. Allow microphone, block camera.
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
+  ASSERT_TRUE(content_settings->IsContentAllowed(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_FALSE(content_settings->IsContentBlocked(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_FALSE(content_settings->IsContentAllowed(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_TRUE(content_settings->IsContentBlocked(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_EQ(TabSpecificContentSettings::MICROPHONE_ACCESSED,
+            content_settings->GetMicrophoneCameraState());
+
+  // Request microphone and camera access. Block microphone, allow camera.
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
+  ASSERT_FALSE(content_settings->IsContentAllowed(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_TRUE(content_settings->IsContentBlocked(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC));
+  ASSERT_TRUE(content_settings->IsContentAllowed(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_FALSE(content_settings->IsContentBlocked(
+      CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA));
+  ASSERT_EQ(TabSpecificContentSettings::CAMERA_ACCESSED,
+            content_settings->GetMicrophoneCameraState());
 }
 
 TEST_F(TabSpecificContentSettingsTest, EmptyCookieList) {
@@ -302,50 +383,3 @@
                                           UTF8ToUTF16("display_name"),
                                           blocked_by_policy);
 }
-
-TEST_F(TabSpecificContentSettingsTest, BlockThenAllowMediaAccess) {
-  TabSpecificContentSettings* content_settings =
-      TabSpecificContentSettings::FromWebContents(web_contents());
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED);
-
-  content_settings->OnMicrophoneAccessBlocked();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_BLOCKED);
-  content_settings->OnCameraAccessBlocked();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED);
-
-  // If microphone and camera have opposite settings, like one is allowed,
-  // while the other is denied, we show the allow access in our UI.
-  content_settings->OnMicrophoneAccessed();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_ACCESSED);
-  content_settings->OnCameraAccessed();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED);
-}
-
-TEST_F(TabSpecificContentSettingsTest, AllowThenBlockMediaAccess) {
-  TabSpecificContentSettings* content_settings =
-      TabSpecificContentSettings::FromWebContents(web_contents());
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED);
-
-  content_settings->OnMicrophoneAccessed();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_ACCESSED);
-  content_settings->OnCameraAccessed();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED);
-
-  // If microphone and camera have opposite settings, like one is allowed,
-  // while the other is denied, we show the allow access in our UI.
-  // TODO(xians): Fix the UI to show one allowed icon and one blocked icon.
-  content_settings->OnMicrophoneAccessBlocked();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::CAMERA_ACCESSED);
-  content_settings->OnCameraAccessBlocked();
-  EXPECT_EQ(content_settings->GetMicrophoneCameraState(),
-            TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED);
-}
diff --git a/chrome/browser/crash_handler_host_linux.cc b/chrome/browser/crash_handler_host_linux.cc
index 27ad89b..4fce401 100644
--- a/chrome/browser/crash_handler_host_linux.cc
+++ b/chrome/browser/crash_handler_host_linux.cc
@@ -57,7 +57,6 @@
   HandleCrashDump(*info);
   delete[] info->filename;
   delete[] info->process_type;
-  delete[] info->crash_url;
   delete[] info->guid;
   delete[] info->distro;
   delete info->crash_keys;
@@ -136,7 +135,6 @@
   char* crash_context = new char[kCrashContextSize];
   // Freed in CrashDumpTask();
   char* guid = new char[kGuidSize + 1];
-  char* crash_url = new char[kMaxActiveURLSize + 1];
   char* distro = new char[kDistroSize + 1];
 #if defined(ADDRESS_SANITIZER)
   asan_report_str_ = new char[kMaxAsanReportSize + 1];
@@ -157,7 +155,6 @@
   const ssize_t expected_msg_size =
       kCrashContextSize +
       kGuidSize + 1 +
-      kMaxActiveURLSize + 1 +
       kDistroSize + 1 +
       sizeof(tid_buf_addr) + sizeof(tid_fd) +
       sizeof(uptime) +
@@ -170,23 +167,21 @@
   iov[0].iov_len = kCrashContextSize;
   iov[1].iov_base = guid;
   iov[1].iov_len = kGuidSize + 1;
-  iov[2].iov_base = crash_url;
-  iov[2].iov_len = kMaxActiveURLSize + 1;
-  iov[3].iov_base = distro;
-  iov[3].iov_len = kDistroSize + 1;
-  iov[4].iov_base = &tid_buf_addr;
-  iov[4].iov_len = sizeof(tid_buf_addr);
-  iov[5].iov_base = &tid_fd;
-  iov[5].iov_len = sizeof(tid_fd);
-  iov[6].iov_base = &uptime;
-  iov[6].iov_len = sizeof(uptime);
-  iov[7].iov_base = &oom_size;
-  iov[7].iov_len = sizeof(oom_size);
-  iov[8].iov_base = serialized_crash_keys;
-  iov[8].iov_len = crash_keys_size;
+  iov[2].iov_base = distro;
+  iov[2].iov_len = kDistroSize + 1;
+  iov[3].iov_base = &tid_buf_addr;
+  iov[3].iov_len = sizeof(tid_buf_addr);
+  iov[4].iov_base = &tid_fd;
+  iov[4].iov_len = sizeof(tid_fd);
+  iov[5].iov_base = &uptime;
+  iov[5].iov_len = sizeof(uptime);
+  iov[6].iov_base = &oom_size;
+  iov[6].iov_len = sizeof(oom_size);
+  iov[7].iov_base = serialized_crash_keys;
+  iov[7].iov_len = crash_keys_size;
 #if defined(ADDRESS_SANITIZER)
-  iov[9].iov_base = asan_report_str_;
-  iov[9].iov_len = kMaxAsanReportSize + 1;
+  iov[8].iov_base = asan_report_str_;
+  iov[8].iov_len = kMaxAsanReportSize + 1;
 #endif
   msg.msg_iov = iov;
   msg.msg_iovlen = kCrashIovSize;
@@ -324,7 +319,7 @@
   bad_context->tid = crashing_tid;
 
   // Sanitize the string data a bit more
-  guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0;
+  guid[kGuidSize] = distro[kDistroSize] = 0;
 
   // Freed in CrashDumpTask();
   BreakpadInfo* info = new BreakpadInfo;
@@ -336,9 +331,6 @@
   process_type_str[info->process_type_length] = '\0';
   info->process_type = process_type_str;
 
-  info->crash_url_length = strlen(crash_url);
-  info->crash_url = crash_url;
-
   info->guid_length = strlen(guid);
   info->guid = guid;
 
diff --git a/chrome/browser/devtools/adb/android_usb_device.cc b/chrome/browser/devtools/adb/android_usb_device.cc
index 82af86a..f32b665 100644
--- a/chrome/browser/devtools/adb/android_usb_device.cc
+++ b/chrome/browser/devtools/adb/android_usb_device.cc
@@ -45,7 +45,7 @@
 base::LazyInstance<AndroidUsbDevices>::Leaky g_devices =
     LAZY_INSTANCE_INITIALIZER;
 
-static scoped_refptr<AndroidUsbDevice> ClaimInterface(
+scoped_refptr<AndroidUsbDevice> ClaimInterface(
     crypto::RSAPrivateKey* rsa_key,
     scoped_refptr<UsbDeviceHandle> usb_device,
     const UsbInterface* interface) {
@@ -92,7 +92,7 @@
                               inbound_address, outbound_address, zero_mask);
 }
 
-static uint32 Checksum(const std::string& data) {
+uint32 Checksum(const std::string& data) {
   unsigned char* x = (unsigned char*)data.data();
   int count = data.length();
   uint32 sum = 0;
@@ -101,7 +101,7 @@
   return sum;
 }
 
-static void DumpMessage(bool outgoing, const char* data, size_t length) {
+void DumpMessage(bool outgoing, const char* data, size_t length) {
 #if 0
   std::string result = "";
   if (length == kHeaderSize) {
@@ -130,6 +130,11 @@
 #endif  // 0
 }
 
+void ReleaseInterface(scoped_refptr<UsbDeviceHandle> usb_device) {
+  usb_device->ReleaseInterface(1);
+  usb_device->Close();
+}
+
 }  // namespace
 
 AdbMessage::AdbMessage(uint32 command,
@@ -496,8 +501,9 @@
     it->second->Terminated();
   }
 
-  usb_device_->ReleaseInterface(1);
-  usb_device_->Close();
+  BrowserThread::PostTask(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&ReleaseInterface, usb_device_));
 }
 
 void AndroidUsbDevice::SocketDeleted(uint32 socket_id) {
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index bdec14d..e19910a 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -50,6 +50,7 @@
 static const char kLocalChrome[] = "Local Chrome";
 static const char kChrome[] = "Chrome";
 static const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
+static const char kListProcessesCommand[] = "shell:ps";
 
 static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
 static const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n";
@@ -248,8 +249,7 @@
                        base::Bind(&AdbPagesCommand::ReceivedSockets, this));
   }
 
-  void ReceivedSockets(int result,
-                       const std::string& response) {
+  void ReceivedSockets(int result, const std::string& response) {
     DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current());
     if (result < 0) {
       devices_.pop_back();
@@ -258,6 +258,15 @@
     }
 
     ParseSocketsList(response);
+    scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back();
+    device->RunCommand(kListProcessesCommand,
+                       base::Bind(&AdbPagesCommand::ReceivedProcesses, this));
+  }
+
+  void ReceivedProcesses(int result, const std::string& response) {
+    if (result >= 0)
+      ParseProcessList(response);
+
     if (browsers_.size() == 0) {
       devices_.pop_back();
       ProcessSerials();
@@ -365,7 +374,7 @@
         base::StringPrintf(kDevToolsChannelNameFormat, "");
     for (size_t i = 1; i < entries.size(); ++i) {
       std::vector<std::string> fields;
-      Tokenize(entries[i], " ", &fields);
+      Tokenize(entries[i], " \r", &fields);
       if (fields.size() < 8)
         continue;
       if (fields[3] != "00010000" || fields[5] != "01")
@@ -376,22 +385,50 @@
       size_t socket_name_pos = path_field.find(channel_pattern);
       if (socket_name_pos == std::string::npos)
         continue;
-      std::string socket = path_field.substr(1, path_field.size() - 2);
-      std::string package = path_field.substr(1, socket_name_pos - 1);
-      if (socket_name_pos + channel_pattern.size() < path_field.size() - 1) {
-        package += path_field.substr(
-            socket_name_pos + channel_pattern.size(), path_field.size() - 1);
-      }
-      package[0] = base::ToUpperASCII(package[0]);
+
+      std::string socket = path_field.substr(1);
       scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
           new DevToolsAdbBridge::RemoteBrowser(
               bridge_, remote_device->device(), socket);
-      remote_browser->set_product(package);
+
+      std::string product = path_field.substr(1, socket_name_pos - 1);
+      product[0] = base::ToUpperASCII(product[0]);
+      remote_browser->set_product(product);
+
+      size_t socket_name_end = socket_name_pos + channel_pattern.size();
+      if (socket_name_end < path_field.size() &&
+          path_field[socket_name_end] == '_') {
+        remote_browser->set_pid(path_field.substr(socket_name_end + 1));
+      }
       remote_device->AddBrowser(remote_browser);
     }
     browsers_ = remote_device->browsers();
   }
 
+  void ParseProcessList(const std::string& response) {
+    // On Android, 'ps' output looks like this:
+    // USER PID PPID VSIZE RSS WCHAN PC ? NAME
+    typedef std::map<std::string, std::string> StringMap;
+    StringMap pid_to_package;
+    std::vector<std::string> entries;
+    Tokenize(response, "\n", &entries);
+    for (size_t i = 1; i < entries.size(); ++i) {
+      std::vector<std::string> fields;
+      Tokenize(entries[i], " \r", &fields);
+      if (fields.size() < 9)
+        continue;
+      pid_to_package[fields[1]] = fields[8];
+    }
+    DevToolsAdbBridge::RemoteBrowsers browsers =
+        remote_devices_->back()->browsers();
+    for (DevToolsAdbBridge::RemoteBrowsers::iterator it = browsers.begin();
+        it != browsers.end(); ++it) {
+      StringMap::iterator pit = pid_to_package.find((*it)->pid());
+      if (pit != pid_to_package.end())
+        (*it)->set_package(pit->second);
+    }
+  }
+
   scoped_refptr<DevToolsAdbBridge> bridge_;
   Callback callback_;
   AndroidDevices devices_;
@@ -630,7 +667,7 @@
   value.GetString("id", &id_);
   value.GetString("url", &url_);
   value.GetString("title", &title_);
-  value.GetString("descirption", &description_);
+  value.GetString("description", &description_);
   value.GetString("faviconUrl", &favicon_url_);
   value.GetString("webSocketDebuggerUrl", &debug_url_);
   value.GetString("devtoolsFrontendUrl", &frontend_url_);
@@ -791,7 +828,7 @@
       has_message_loop_(adb_thread_->message_loop() != NULL) {
   rsa_key_.reset(AndroidRSAPrivateKey(profile));
   port_forwarding_controller_.reset(
-      new PortForwardingController(GetAdbMessageLoop(), profile->GetPrefs()));
+      new PortForwardingController(this, profile->GetPrefs()));
 }
 
 void DevToolsAdbBridge::EnumerateUsbDevices(
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index 1023a06..b51b3bd 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -136,6 +136,10 @@
     void set_product(const std::string& product) { product_ = product; }
     std::string version() { return version_; }
     void set_version(const std::string& version) { version_ = version; }
+    std::string pid() { return pid_; }
+    void set_pid(const std::string& pid) { pid_ = pid; }
+    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); }
@@ -157,6 +161,8 @@
     const std::string socket_;
     std::string product_;
     std::string version_;
+    std::string pid_;
+    std::string package_;
     RemotePages pages_;
 
     DISALLOW_COPY_AND_ASSIGN(RemoteBrowser);
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 3cc06c8..e5f185e 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -1304,12 +1304,9 @@
 }
 
 void DevToolsWindow::UpdateBrowserToolbar() {
-  content::WebContents* inspected_web_contents = GetInspectedWebContents();
-  if (!inspected_web_contents)
-    return;
   BrowserWindow* inspected_window = GetInspectedBrowserWindow();
   if (inspected_window)
-    inspected_window->UpdateToolbar(inspected_web_contents, false);
+    inspected_window->UpdateToolbar(NULL);
 }
 
 bool DevToolsWindow::IsDocked() {
diff --git a/chrome/browser/devtools/tethering_adb_filter.cc b/chrome/browser/devtools/tethering_adb_filter.cc
index 8bf35ad..0bb5ad3 100644
--- a/chrome/browser/devtools/tethering_adb_filter.cc
+++ b/chrome/browser/devtools/tethering_adb_filter.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/devtools/tethering_adb_filter.h"
 
+#include <algorithm>
 #include <map>
 
 #include "base/bind.h"
@@ -44,7 +45,7 @@
 static const char kTetheringBind[] = "Tethering.bind";
 static const char kTetheringUnbind[] = "Tethering.unbind";
 
-static const char kDevToolsRemoteSocketName[] = "chrome_devtools_remote";
+static const char kChromeProductName[] = "Chrome";
 static const char kDevToolsRemoteBrowserTarget[] = "/devtools/browser";
 
 class SocketTunnel {
@@ -79,9 +80,12 @@
     net::HostResolver::RequestInfo request_info(
         net::HostPortPair(tokens[0], port));
     result = host_resolver_->Resolve(
-        request_info, &address_list_,
+        request_info,
+        net::DEFAULT_PRIORITY,
+        &address_list_,
         base::Bind(&SocketTunnel::OnResolved, base::Unretained(this)),
-        NULL, net::BoundNetLog());
+        NULL,
+        net::BoundNetLog());
     if (result != net::ERR_IO_PENDING)
       OnResolved(result);
   }
@@ -212,6 +216,43 @@
   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;
+}
+
+static bool IsVersionLower(const ParsedVersion& left,
+                           const ParsedVersion& right) {
+  return std::lexicographical_compare(
+    left.begin(), left.end(), right.begin(), right.end());
+}
+
+static std::string FindBestSocketForTethering(
+    const DevToolsAdbBridge::RemoteBrowsers browsers) {
+  std::string socket;
+  ParsedVersion newest_version;
+  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 &&
+        IsVersionLower(newest_version, current_version)) {
+      socket = browser->socket();
+      newest_version = current_version;
+    }
+  }
+  return socket;
+}
+
 }  // namespace
 
 TetheringAdbFilter::TetheringAdbFilter(
@@ -427,7 +468,8 @@
   Connection(
       Registry* registry,
       scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
-      base::MessageLoop* adb_message_loop,
+      const std::string& socket,
+      scoped_refptr<DevToolsAdbBridge> bridge,
       PrefService* pref_service);
 
   void Shutdown();
@@ -444,7 +486,7 @@
 
   Registry* registry_;
   scoped_refptr<DevToolsAdbBridge::AndroidDevice> device_;
-  base::MessageLoop* adb_message_loop_;
+  scoped_refptr<DevToolsAdbBridge> bridge_;
   PrefService* pref_service_;
 
   scoped_refptr<TetheringAdbFilter> tethering_adb_filter_;
@@ -454,16 +496,17 @@
 PortForwardingController::Connection::Connection(
     Registry* registry,
     scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
-    base::MessageLoop* adb_message_loop,
+    const std::string& socket,
+    scoped_refptr<DevToolsAdbBridge> bridge,
     PrefService* pref_service)
     : registry_(registry),
       device_(device),
-      adb_message_loop_(adb_message_loop),
+      bridge_(bridge),
       pref_service_(pref_service) {
    (*registry_)[device_->serial()] = this;
    web_socket_ = new AdbWebSocket(
-        device, kDevToolsRemoteSocketName, kDevToolsRemoteBrowserTarget,
-        adb_message_loop_, this);
+        device, socket, kDevToolsRemoteBrowserTarget,
+        bridge->GetAdbMessageLoop(), this);
 }
 
 void PortForwardingController::Connection::Shutdown() {
@@ -496,7 +539,7 @@
   }
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   tethering_adb_filter_ = new TetheringAdbFilter(
-      device_, adb_message_loop_, pref_service_, web_socket_);
+      device_, bridge_->GetAdbMessageLoop(), pref_service_, web_socket_);
 }
 
 void PortForwardingController::Connection::OnFrameRead(
@@ -515,9 +558,9 @@
 
 
 PortForwardingController::PortForwardingController(
-    base::MessageLoop* adb_message_loop,
+    scoped_refptr<DevToolsAdbBridge> bridge,
     PrefService* pref_service)
-    : adb_message_loop_(adb_message_loop),
+    : bridge_(bridge),
       pref_service_(pref_service) {
 }
 
@@ -532,9 +575,12 @@
        it != devices.end(); ++it) {
     Registry::iterator rit = registry_.find((*it)->serial());
     if (rit == registry_.end()) {
-      // Will delete itself when disconnected.
-      new Connection(
-          &registry_, (*it)->device(), adb_message_loop_, pref_service_);
+      std::string socket = FindBestSocketForTethering((*it)->browsers());
+      if (!socket.empty() || (*it)->serial().empty()) {
+        // Will delete itself when disconnected.
+        new Connection(
+          &registry_, (*it)->device(), socket, bridge_, pref_service_);
+      }
     } else {
       (*it)->set_port_status((*rit).second->port_status());
     }
diff --git a/chrome/browser/devtools/tethering_adb_filter.h b/chrome/browser/devtools/tethering_adb_filter.h
index 674489a..2a7946d 100644
--- a/chrome/browser/devtools/tethering_adb_filter.h
+++ b/chrome/browser/devtools/tethering_adb_filter.h
@@ -81,7 +81,7 @@
 class PortForwardingController {
  public:
   PortForwardingController(
-      base::MessageLoop* adb_message_loop,
+      scoped_refptr<DevToolsAdbBridge> bridge,
       PrefService* pref_service);
 
   virtual ~PortForwardingController();
@@ -92,7 +92,7 @@
   class Connection;
   typedef std::map<std::string, Connection*> Registry;
 
-  base::MessageLoop* adb_message_loop_;
+  scoped_refptr<DevToolsAdbBridge> bridge_;
   PrefService* pref_service_;
   Registry registry_;
 };
diff --git a/chrome/browser/download/download_danger_prompt.cc b/chrome/browser/download/download_danger_prompt.cc
index d795b71..a22eab1 100644
--- a/chrome/browser/download/download_danger_prompt.cc
+++ b/chrome/browser/download/download_danger_prompt.cc
@@ -8,7 +8,7 @@
 #include "base/metrics/field_trial.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
-#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/download/download_field_trial.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
 #include "content/public/browser/download_danger_type.h"
@@ -20,10 +20,9 @@
 namespace {
 
 // Implements DownloadDangerPrompt using a TabModalConfirmDialog.
-class DownloadDangerPromptImpl
-  : public DownloadDangerPrompt,
-    public content::DownloadItem::Observer,
-    public TabModalConfirmDialogDelegate {
+class DownloadDangerPromptImpl : public DownloadDangerPrompt,
+                                 public content::DownloadItem::Observer,
+                                 public TabModalConfirmDialogDelegate {
  public:
   DownloadDangerPromptImpl(content::DownloadItem* item,
                            content::WebContents* web_contents,
@@ -31,14 +30,14 @@
                            const OnDone& done);
   virtual ~DownloadDangerPromptImpl();
 
-  // DownloadDangerPrompt
+  // DownloadDangerPrompt:
   virtual void InvokeActionForTesting(Action action) OVERRIDE;
 
  private:
-  // content::DownloadItem::Observer
+  // content::DownloadItem::Observer:
   virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
 
-  // TabModalConfirmDialogDelegate
+  // TabModalConfirmDialogDelegate:
   virtual string16 GetTitle() OVERRIDE;
   virtual string16 GetMessage() OVERRIDE;
   virtual string16 GetAcceptButtonTitle() OVERRIDE;
@@ -114,13 +113,13 @@
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
       std::string trial_condition =
-          base::FieldTrialList::FindFullName(download_util::kFinchTrialName);
+          base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
       if (trial_condition.empty()) {
         return l10n_util::GetStringFUTF16(
             IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
             download_->GetFileNameToReportUser().LossyDisplayName());
       }
-      return download_util::AssembleMalwareFinchString(
+      return AssembleMalwareFinchString(
           trial_condition,
           download_->GetFileNameToReportUser().LossyDisplayName());
     }
@@ -159,7 +158,7 @@
 }
 
 void DownloadDangerPromptImpl::OnClosed() {
-  RunDone(CANCEL);
+  RunDone(DISMISS);
 }
 
 void DownloadDangerPromptImpl::RunDone(Action action) {
diff --git a/chrome/browser/download/download_danger_prompt_browsertest.cc b/chrome/browser/download/download_danger_prompt_browsertest.cc
index f203b71..02627ad 100644
--- a/chrome/browser/download/download_danger_prompt_browsertest.cc
+++ b/chrome/browser/download/download_danger_prompt_browsertest.cc
@@ -145,9 +145,7 @@
 
   // If the containing tab is closed, the dialog should DISMISS itself.
   OpenNewTab();
-  // TODO(benjhayden):
-  // SetUpExpectations(DownloadDangerPrompt::DISMISS);
-  SetUpExpectations(DownloadDangerPrompt::CANCEL);
+  SetUpExpectations(DownloadDangerPrompt::DISMISS);
   chrome::CloseTab(browser());
   VerifyExpectations();
 }
diff --git a/chrome/browser/download/download_field_trial.cc b/chrome/browser/download/download_field_trial.cc
new file mode 100644
index 0000000..58d76da
--- /dev/null
+++ b/chrome/browser/download/download_field_trial.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/download/download_field_trial.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace {
+
+const char kCondition1Control[] = "Condition1Control";
+const char kCondition2Control[] = "Condition2Control";
+const char kCondition3Malicious[] = "Condition3Malicious";
+const char kCondition4Unsafe[] = "Condition4Unsafe";
+const char kCondition5Dangerous[] = "Condition5Dangerous";
+const char kCondition6Harmful[] = "Condition6Harmful";
+const char kCondition7DiscardSecond[] = "Condition7DiscardSecond";
+const char kCondition8DiscardFirst[] = "Condition8DiscardFirst";
+const char kCondition9SafeDiscard[] = "Condition9SafeDiscard";
+const char kCondition10SafeDontRun[] = "Condition10SafeDontRun";
+
+}  // namespace
+
+const char kMalwareWarningFinchTrialName[] = "MalwareDownloadWarning";
+
+base::string16 AssembleMalwareFinchString(
+    const std::string& trial_condition,
+    const base::string16& elided_filename) {
+  // Sanity check to make sure we have a filename.
+  base::string16 filename;
+  if (elided_filename.empty()) {
+    filename = ASCIIToUTF16("This file");
+  } else {
+    filename = ReplaceStringPlaceholders(
+        ASCIIToUTF16("File '$1'"), elided_filename, NULL);
+  }
+
+  // Set the message text according to the condition.
+  if (trial_condition == kCondition1Control) {
+    return ASCIIToUTF16("This file appears malicious.");
+  }
+  base::string16 message_text;
+  if (trial_condition == kCondition2Control) {
+    message_text = ASCIIToUTF16("$1 appears malicious.");
+  } else if (trial_condition == kCondition3Malicious) {
+    message_text = ASCIIToUTF16("$1 is malicious.");
+  } else if (trial_condition == kCondition4Unsafe) {
+    message_text = ASCIIToUTF16("$1 is unsafe.");
+  } else if (trial_condition == kCondition5Dangerous) {
+    message_text = ASCIIToUTF16("$1 is dangerous.");
+  } else if (trial_condition == kCondition6Harmful) {
+    message_text = ASCIIToUTF16("$1 is harmful.");
+  } else if (trial_condition == kCondition7DiscardSecond) {
+    message_text = ASCIIToUTF16(
+        "$1 is malicious. Discard this file to stay safe.");
+  } else if (trial_condition == kCondition8DiscardFirst) {
+    message_text = ASCIIToUTF16(
+        "Discard this file to stay safe. $1 is malicious.");
+  } else if (trial_condition == kCondition9SafeDiscard) {
+    message_text = ASCIIToUTF16("$1 is malicious. To stay safe, discard it.");
+  } else if (trial_condition == kCondition10SafeDontRun) {
+    message_text = ASCIIToUTF16("$1 is malicious. To stay safe, don't run it.");
+  } else {
+    // We use the second control as a default for other conditions that don't
+    // change the warning string.
+    message_text = ASCIIToUTF16("$1 appears malicious.");
+  }
+
+  return ReplaceStringPlaceholders(message_text, filename, NULL);
+}
diff --git a/chrome/browser/download/download_field_trial.h b/chrome/browser/download/download_field_trial.h
new file mode 100644
index 0000000..8f5d721
--- /dev/null
+++ b/chrome/browser/download/download_field_trial.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_DOWNLOAD_DOWNLOAD_FIELD_TRIAL_H_
+#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FIELD_TRIAL_H_
+
+#include <string>
+
+#include "base/strings/string16.h"
+
+// Summer/Fall 2013 Finch experiment strings ---------------------------------
+// Only deployed to English speakers, don't need translation.
+
+extern const char kMalwareWarningFinchTrialName[];
+
+// Helper for getting the appropriate message for a Finch trial.
+// You should only invoke this if you believe you're in the kFinchTrialName
+// finch trial; if you aren't, use the default string and don't invoke this.
+base::string16 AssembleMalwareFinchString(
+    const std::string& trial_condition,
+    const base::string16& elided_filename);
+
+#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_FIELD_TRIAL_H_
diff --git a/chrome/browser/download/download_field_trial_unittest.cc b/chrome/browser/download/download_field_trial_unittest.cc
new file mode 100644
index 0000000..314497b
--- /dev/null
+++ b/chrome/browser/download/download_field_trial_unittest.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 "chrome/browser/download/download_field_trial.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(DownloadFieldTrialTest, FinchStrings) {
+  const std::string malicious_condition("Condition3Malicious");
+  EXPECT_EQ(ASCIIToUTF16("This file is malicious."),
+            AssembleMalwareFinchString(malicious_condition, base::string16()));
+  EXPECT_EQ(ASCIIToUTF16("File 'malware.exe' is malicious."),
+            AssembleMalwareFinchString(malicious_condition,
+                                       ASCIIToUTF16("malware.exe")));
+}
diff --git a/chrome/browser/download/download_history_unittest.cc b/chrome/browser/download/download_history_unittest.cc
index 93fdb73..0316883 100644
--- a/chrome/browser/download/download_history_unittest.cc
+++ b/chrome/browser/download/download_history_unittest.cc
@@ -171,13 +171,7 @@
   void ExpectDownloadsRemoved(const IdSet& ids) {
     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     content::RunAllPendingInMessageLoop(content::BrowserThread::UI);
-    IdSet differences;
-    std::insert_iterator<IdSet> differences_iter(
-        differences, differences.begin());
-    std::set_difference(ids.begin(), ids.end(),
-                        remove_downloads_.begin(),
-                        remove_downloads_.end(),
-                        differences_iter);
+    IdSet differences = base::STLSetDifference<IdSet>(ids, remove_downloads_);
     for (IdSet::const_iterator different = differences.begin();
          different != differences.end(); ++different) {
       EXPECT_TRUE(false) << *different;
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 83c62f9..9964b33 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -13,7 +13,7 @@
 #include "base/supports_user_data.h"
 #include "base/time/time.h"
 #include "chrome/browser/download/download_crx_util.h"
-#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/download/download_field_trial.h"
 #include "chrome/browser/safe_browsing/download_feedback_service.h"
 #include "content/public/browser/download_danger_type.h"
 #include "content/public/browser/download_interrupt_reasons.h"
@@ -235,11 +235,9 @@
 // DownloadItemModel
 
 DownloadItemModel::DownloadItemModel(DownloadItem* download)
-    : download_(download) {
-}
+    : download_(download) {}
 
-DownloadItemModel::~DownloadItemModel() {
-}
+DownloadItemModel::~DownloadItemModel() {}
 
 string16 DownloadItemModel::GetInterruptReasonText() const {
   if (download_->GetState() != DownloadItem::INTERRUPTED ||
@@ -285,6 +283,46 @@
   return status_text;
 }
 
+string16 DownloadItemModel::GetTabProgressStatusText() const {
+  int64 total = GetTotalBytes();
+  int64 size = download_->GetReceivedBytes();
+  string16 received_size = ui::FormatBytes(size);
+  string16 amount = received_size;
+
+  // Adjust both strings for the locale direction since we don't yet know which
+  // string we'll end up using for constructing the final progress string.
+  base::i18n::AdjustStringForLocaleDirection(&amount);
+
+  if (total) {
+    string16 total_text = ui::FormatBytes(total);
+    base::i18n::AdjustStringForLocaleDirection(&total_text);
+
+    base::i18n::AdjustStringForLocaleDirection(&received_size);
+    amount = l10n_util::GetStringFUTF16(
+        IDS_DOWNLOAD_TAB_PROGRESS_SIZE, received_size, total_text);
+  } else {
+    amount.assign(received_size);
+  }
+  int64 current_speed = download_->CurrentSpeed();
+  string16 speed_text = ui::FormatSpeed(current_speed);
+  base::i18n::AdjustStringForLocaleDirection(&speed_text);
+
+  base::TimeDelta remaining;
+  string16 time_remaining;
+  if (download_->IsPaused())
+    time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
+  else if (download_->TimeRemaining(&remaining))
+    time_remaining = ui::TimeFormat::TimeRemaining(remaining);
+
+  if (time_remaining.empty()) {
+    base::i18n::AdjustStringForLocaleDirection(&amount);
+    return l10n_util::GetStringFUTF16(
+        IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN, speed_text, amount);
+  }
+  return l10n_util::GetStringFUTF16(
+      IDS_DOWNLOAD_TAB_PROGRESS_STATUS, speed_text, amount, time_remaining);
+}
+
 string16 DownloadItemModel::GetTooltipText(const gfx::Font& font,
                                            int max_width) const {
   string16 tooltip = ui::ElideFilename(
@@ -308,11 +346,10 @@
   switch (download_->GetDangerType()) {
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
       std::string trial_condition =
-          base::FieldTrialList::FindFullName(download_util::kFinchTrialName);
+          base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
       if (trial_condition.empty())
         return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
-      return download_util::AssembleMalwareFinchString(trial_condition,
-                                                       elided_filename);
+      return AssembleMalwareFinchString(trial_condition, elided_filename);
     }
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
       if (download_crx_util::IsExtensionDownload(*download_)) {
@@ -326,13 +363,12 @@
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
     case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
       std::string trial_condition =
-          base::FieldTrialList::FindFullName(download_util::kFinchTrialName);
+          base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
       if (trial_condition.empty()) {
         return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
                                           elided_filename);
       }
-      return download_util::AssembleMalwareFinchString(trial_condition,
-                                                       elided_filename);
+      return AssembleMalwareFinchString(trial_condition, elided_filename);
     }
     case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
       return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h
index 157024f..af3dde8 100644
--- a/chrome/browser/download/download_item_model.h
+++ b/chrome/browser/download/download_item_model.h
@@ -42,6 +42,10 @@
   // Returns a short one-line status string for the download.
   string16 GetStatusText() const;
 
+  // Returns the localized status text for an in-progress download. This
+  // is the progress status used in the WebUI interface.
+  string16 GetTabProgressStatusText() const;
+
   // Returns a string suitable for use as a tooltip. For a regular download, the
   // tooltip is the filename. For an interrupted download, the string states the
   // filename and a short description of the reason for interruption. For
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc
index 130807a..4b7eef2 100644
--- a/chrome/browser/download/download_prefs.cc
+++ b/chrome/browser/download/download_prefs.cc
@@ -10,7 +10,9 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/file_util.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/path_service.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -23,6 +25,7 @@
 #include "chrome/browser/download/download_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
@@ -38,6 +41,61 @@
 using content::BrowserThread;
 using content::DownloadManager;
 
+namespace {
+
+// Consider downloads 'dangerous' if they go to the home directory on Linux and
+// to the desktop on any platform.
+bool DownloadPathIsDangerous(const base::FilePath& download_path) {
+#if defined(OS_LINUX)
+  base::FilePath home_dir = file_util::GetHomeDir();
+  if (download_path == home_dir) {
+    return true;
+  }
+#endif
+
+#if defined(OS_ANDROID)
+  // Android does not have a desktop dir.
+  return false;
+#else
+  base::FilePath desktop_dir;
+  if (!PathService::Get(base::DIR_USER_DESKTOP, &desktop_dir)) {
+    NOTREACHED();
+    return false;
+  }
+  return (download_path == desktop_dir);
+#endif
+}
+
+class DefaultDownloadDirectory {
+ public:
+  const base::FilePath& path() const { return path_; }
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<DefaultDownloadDirectory>;
+
+  DefaultDownloadDirectory() {
+    if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path_)) {
+      NOTREACHED();
+    }
+    if (DownloadPathIsDangerous(path_)) {
+      // This is only useful on platforms that support
+      // DIR_DEFAULT_DOWNLOADS_SAFE.
+      if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE, &path_)) {
+        NOTREACHED();
+      }
+    }
+  }
+
+  base::FilePath path_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultDownloadDirectory);
+};
+
+static base::LazyInstance<DefaultDownloadDirectory>
+    g_default_download_directory = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
 DownloadPrefs::DownloadPrefs(Profile* profile) : profile_(profile) {
   PrefService* prefs = profile->GetPrefs();
 
@@ -47,9 +105,9 @@
   if (!prefs->GetBoolean(prefs::kDownloadDirUpgraded)) {
     base::FilePath current_download_dir = prefs->GetFilePath(
         prefs::kDownloadDefaultDirectory);
-    if (download_util::DownloadPathIsDangerous(current_download_dir)) {
+    if (DownloadPathIsDangerous(current_download_dir)) {
       prefs->SetFilePath(prefs::kDownloadDefaultDirectory,
-                         download_util::GetDefaultDownloadDirectory());
+                         GetDefaultDownloadDirectory());
     }
     prefs->SetBoolean(prefs::kDownloadDirUpgraded, true);
   }
@@ -78,8 +136,7 @@
   }
 }
 
-DownloadPrefs::~DownloadPrefs() {
-}
+DownloadPrefs::~DownloadPrefs() {}
 
 // static
 void DownloadPrefs::RegisterProfilePrefs(
@@ -102,8 +159,7 @@
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 
   // The default download path is userprofile\download.
-  const base::FilePath& default_download_path =
-      download_util::GetDefaultDownloadDirectory();
+  const base::FilePath& default_download_path = GetDefaultDownloadDirectory();
   registry->RegisterFilePathPref(
       prefs::kDownloadDefaultDirectory,
       default_download_path,
@@ -123,6 +179,11 @@
 }
 
 // static
+const base::FilePath& DownloadPrefs::GetDefaultDownloadDirectory() {
+  return g_default_download_directory.Get().path();
+}
+
+// static
 DownloadPrefs* DownloadPrefs::FromDownloadManager(
     DownloadManager* download_manager) {
   ChromeDownloadManagerDelegate* delegate =
@@ -144,7 +205,7 @@
   // default download directory (/Downloads).
   if (drive::util::IsUnderDriveMountPoint(*download_path_) &&
       !drive::DriveIntegrationServiceFactory::GetForProfile(profile_))
-    return download_util::GetDefaultDownloadDirectory();
+    return GetDefaultDownloadDirectory();
 #endif
   return *download_path_;
 }
diff --git a/chrome/browser/download/download_prefs.h b/chrome/browser/download/download_prefs.h
index d186f8d..81b166e 100644
--- a/chrome/browser/download/download_prefs.h
+++ b/chrome/browser/download/download_prefs.h
@@ -30,6 +30,9 @@
 
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
+  // Returns the default download directory.
+  static const base::FilePath& GetDefaultDownloadDirectory();
+
   // Returns the DownloadPrefs corresponding to the given DownloadManager
   // or BrowserContext.
   static DownloadPrefs* FromDownloadManager(
diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc
index 5b85b2a..dd4cf1f 100644
--- a/chrome/browser/download/download_util.cc
+++ b/chrome/browser/download/download_util.cc
@@ -1,47 +1,17 @@
 // 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.
-//
-// Download utility implementation
 
 #include "chrome/browser/download/download_util.h"
 
-#include <cmath>
 #include <string>
 
-#include "base/file_util.h"
-#include "base/i18n/rtl.h"
-#include "base/i18n/time_formatting.h"
-#include "base/lazy_instance.h"
-#include "base/path_service.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/value_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/download/download_extensions.h"
-#include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_paths.h"
 #include "content/public/browser/download_item.h"
-#include "content/public/browser/download_manager.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/common/url_constants.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_util.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/core/SkShader.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/time_format.h"
-#include "ui/base/text/bytes_formatting.h"
 #include "ui/gfx/image/image.h"
-#include "ui/gfx/rect.h"
+#include "ui/gfx/point.h"
+#include "url/gurl.h"
 
 #if defined(TOOLKIT_VIEWS)
 #include "ui/base/dragdrop/drag_drop_types.h"
@@ -70,58 +40,6 @@
 
 using content::DownloadItem;
 
-// Download temporary file creation --------------------------------------------
-
-class DefaultDownloadDirectory {
- public:
-  const base::FilePath& path() const { return path_; }
- private:
-  DefaultDownloadDirectory() {
-    if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &path_)) {
-      NOTREACHED();
-    }
-    if (DownloadPathIsDangerous(path_)) {
-      // This is only useful on platforms that support
-      // DIR_DEFAULT_DOWNLOADS_SAFE.
-      if (!PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS_SAFE, &path_)) {
-        NOTREACHED();
-      }
-    }
-  }
-  friend struct base::DefaultLazyInstanceTraits<DefaultDownloadDirectory>;
-  base::FilePath path_;
-};
-
-static base::LazyInstance<DefaultDownloadDirectory>
-    g_default_download_directory = LAZY_INSTANCE_INITIALIZER;
-
-const base::FilePath& GetDefaultDownloadDirectory() {
-  return g_default_download_directory.Get().path();
-}
-
-// Consider downloads 'dangerous' if they go to the home directory on Linux and
-// to the desktop on any platform.
-bool DownloadPathIsDangerous(const base::FilePath& download_path) {
-#if defined(OS_LINUX)
-  base::FilePath home_dir = file_util::GetHomeDir();
-  if (download_path == home_dir) {
-    return true;
-  }
-#endif
-
-#if defined(OS_ANDROID)
-  // Android does not have a desktop dir.
-  return false;
-#else
-  base::FilePath desktop_dir;
-  if (!PathService::Get(base::DIR_USER_DESKTOP, &desktop_dir)) {
-    NOTREACHED();
-    return false;
-  }
-  return (download_path == desktop_dir);
-#endif
-}
-
 #if defined(TOOLKIT_VIEWS)
 // Download dragging
 void DragDownload(const DownloadItem* download,
@@ -198,105 +116,4 @@
 }
 #endif  // USE_X11
 
-string16 GetProgressStatusText(DownloadItem* download) {
-  int64 total = download->GetTotalBytes();
-  int64 size = download->GetReceivedBytes();
-  string16 received_size = ui::FormatBytes(size);
-  string16 amount = received_size;
-
-  // Adjust both strings for the locale direction since we don't yet know which
-  // string we'll end up using for constructing the final progress string.
-  base::i18n::AdjustStringForLocaleDirection(&amount);
-
-  if (total) {
-    string16 total_text = ui::FormatBytes(total);
-    base::i18n::AdjustStringForLocaleDirection(&total_text);
-
-    base::i18n::AdjustStringForLocaleDirection(&received_size);
-    amount = l10n_util::GetStringFUTF16(IDS_DOWNLOAD_TAB_PROGRESS_SIZE,
-                                        received_size,
-                                        total_text);
-  } else {
-    amount.assign(received_size);
-  }
-  int64 current_speed = download->CurrentSpeed();
-  string16 speed_text = ui::FormatSpeed(current_speed);
-  base::i18n::AdjustStringForLocaleDirection(&speed_text);
-
-  base::TimeDelta remaining;
-  string16 time_remaining;
-  if (download->IsPaused())
-    time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
-  else if (download->TimeRemaining(&remaining))
-    time_remaining = ui::TimeFormat::TimeRemaining(remaining);
-
-  if (time_remaining.empty()) {
-    base::i18n::AdjustStringForLocaleDirection(&amount);
-    return l10n_util::GetStringFUTF16(
-        IDS_DOWNLOAD_TAB_PROGRESS_STATUS_TIME_UNKNOWN, speed_text, amount);
-  }
-  return l10n_util::GetStringFUTF16(IDS_DOWNLOAD_TAB_PROGRESS_STATUS,
-                                    speed_text, amount, time_remaining);
-}
-
-// Finch trial -----------------------------------------------------------------
-
-const char kFinchTrialName[] = "MalwareDownloadWarning";
-const char kCondition1Control[] = "Condition1Control";
-const char kCondition2Control[] = "Condition2Control";
-const char kCondition3Malicious[] = "Condition3Malicious";
-const char kCondition4Unsafe[] = "Condition4Unsafe";
-const char kCondition5Dangerous[] = "Condition5Dangerous";
-const char kCondition6Harmful[] = "Condition6Harmful";
-const char kCondition7DiscardSecond[] = "Condition7DiscardSecond";
-const char kCondition8DiscardFirst[] = "Condition8DiscardFirst";
-const char kCondition9SafeDiscard[] = "Condition9SafeDiscard";
-const char kCondition10SafeDontRun[] = "Condition10SafeDontRun";
-
-base::string16 AssembleMalwareFinchString(
-    const std::string& trial_condition, const base::string16& elided_filename) {
-  // Sanity check to make sure we have a filename.
-  base::string16 filename;
-  if (elided_filename.empty()) {
-    filename = ASCIIToUTF16("This file");
-  } else {
-    filename = ReplaceStringPlaceholders(ASCIIToUTF16("File '$1'"),
-                                         elided_filename,
-                                         NULL);
-  }
-
-  // Set the message text according to the condition.
-  if (trial_condition == kCondition1Control) {
-    return ASCIIToUTF16("This file appears malicious.");
-  }
-  base::string16 message_text;
-  if (trial_condition == kCondition2Control) {
-    message_text = ASCIIToUTF16("$1 appears malicious.");
-  } else if (trial_condition == kCondition3Malicious) {
-    message_text = ASCIIToUTF16("$1 is malicious.");
-  } else if (trial_condition == kCondition4Unsafe) {
-    message_text = ASCIIToUTF16("$1 is unsafe.");
-  } else if (trial_condition == kCondition5Dangerous) {
-    message_text = ASCIIToUTF16("$1 is dangerous.");
-  } else if (trial_condition == kCondition6Harmful) {
-    message_text = ASCIIToUTF16("$1 is harmful.");
-  } else if (trial_condition == kCondition7DiscardSecond) {
-    message_text = ASCIIToUTF16(
-        "$1 is malicious. Discard this file to stay safe.");
-  } else if (trial_condition == kCondition8DiscardFirst) {
-    message_text = ASCIIToUTF16(
-        "Discard this file to stay safe. $1 is malicious.");
-  } else if (trial_condition == kCondition9SafeDiscard) {
-    message_text = ASCIIToUTF16("$1 is malicious. To stay safe, discard it.");
-  } else if (trial_condition == kCondition10SafeDontRun) {
-    message_text = ASCIIToUTF16("$1 is malicious. To stay safe, don't run it.");
-  } else {
-    // We use the second control as a default for other conditions that don't
-    // change the warning string.
-    message_text = ASCIIToUTF16("$1 appears malicious.");
-  }
-
-  return ReplaceStringPlaceholders(message_text, filename, NULL);
-}
-
 }  // namespace download_util
diff --git a/chrome/browser/download/download_util.h b/chrome/browser/download/download_util.h
index 515bd82..900e960 100644
--- a/chrome/browser/download/download_util.h
+++ b/chrome/browser/download/download_util.h
@@ -1,54 +1,22 @@
 // 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.
-//
-// Download utilities.
 
 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UTIL_H_
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UTIL_H_
 
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
 #include "ui/gfx/native_widget_types.h"
 
-#if defined(TOOLKIT_VIEWS)
-#include "ui/views/view.h"
-#endif
-
-class GURL;
-
-namespace base {
-class DictionaryValue;
-}
-
 namespace content {
 class DownloadItem;
 }
 
 namespace gfx {
-class Canvas;
 class Image;
-class ImageSkia;
-class Rect;
 }
 
 namespace download_util {
 
-// Download temporary file creation --------------------------------------------
-
-// Return the default download directory.
-const base::FilePath& GetDefaultDownloadDirectory();
-
-// Return true if the |download_path| is dangerous path.
-bool DownloadPathIsDangerous(const base::FilePath& download_path);
-
-// Drag support ----------------------------------------------------------------
-
 // Helper function for download views to use when acting as a drag source for a
 // DownloadItem. If |icon| is NULL, no image will be accompany the drag. |view|
 // is only required for Mac OS X, elsewhere it can be NULL.
@@ -56,33 +24,6 @@
                   gfx::Image* icon,
                   gfx::NativeView view);
 
-// Helpers ---------------------------------------------------------------------
-
-// Get the localized status text for an in-progress download.
-string16 GetProgressStatusText(content::DownloadItem* download);
-
-// Summer/Fall 2013 Finch experiment strings -----------------------------------
-// Only deployed to English speakers, don't need translation.
-
-// Study and condition names.
-extern const char kFinchTrialName[];
-extern const char kCondition1Control[];
-extern const char kCondition2Control[];
-extern const char kCondition3Malicious[];
-extern const char kCondition4Unsafe[];
-extern const char kCondition5Dangerous[];
-extern const char kCondition6Harmful[];
-extern const char kCondition7DiscardSecond[];
-extern const char kCondition8DiscardFirst[];
-extern const char kCondition9SafeDiscard[];
-extern const char kCondition10SafeDontRun[];
-
-// Helper for getting the appropriate message for a Finch trial.
-// You should only invoke this if you believe you're in the kFinchTrialName
-// finch trial; if you aren't, use the default string and don't invoke this.
-base::string16 AssembleMalwareFinchString(const std::string& trial_condition,
-                                          const string16& elided_filename);
-
 }  // namespace download_util
 
 #endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_UTIL_H_
diff --git a/chrome/browser/download/download_util_unittest.cc b/chrome/browser/download/download_util_unittest.cc
deleted file mode 100644
index 841260b..0000000
--- a/chrome/browser/download/download_util_unittest.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 "chrome/browser/download/download_util.h"
-
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(DownloadUtilTest, FinchStrings) {
-  EXPECT_EQ(
-      ASCIIToUTF16("This file is malicious."),
-      download_util::AssembleMalwareFinchString(
-          download_util::kCondition3Malicious, string16()));
-  EXPECT_EQ(
-      ASCIIToUTF16("File 'malware.exe' is malicious."),
-      download_util::AssembleMalwareFinchString(
-          download_util::kCondition3Malicious, ASCIIToUTF16("malware.exe")));
-}
diff --git a/chrome/browser/drive/drive_api_service.cc b/chrome/browser/drive/drive_api_service.cc
index 71e8b92..48ee6b5 100644
--- a/chrome/browser/drive/drive_api_service.cc
+++ b/chrome/browser/drive/drive_api_service.cc
@@ -65,7 +65,7 @@
 using google_apis::drive::InitiateUploadExistingFileRequest;
 using google_apis::drive::InitiateUploadNewFileRequest;
 using google_apis::drive::InsertResourceRequest;
-using google_apis::drive::RenameResourceRequest;
+using google_apis::drive::MoveResourceRequest;
 using google_apis::drive::ResumeUploadRequest;
 using google_apis::drive::TouchResourceRequest;
 using google_apis::drive::TrashResourceRequest;
@@ -259,6 +259,13 @@
   callback.Run(GDATA_OTHER_ERROR, GURL());
 }
 
+// Ignores the |entry|, and runs the |callback|.
+void EntryActionCallbackAdapter(
+    const EntryActionCallback& callback,
+    GDataErrorCode error, scoped_ptr<FileResource> entry) {
+  callback.Run(error);
+}
+
 // The resource ID for the root directory for Drive API is defined in the spec:
 // https://developers.google.com/drive/folder
 const char kDriveApiRootDirectoryResourceId[] = "root";
@@ -600,6 +607,24 @@
           base::Bind(&ParseResourceEntryAndRun, callback)));
 }
 
+CancelCallback DriveAPIService::MoveResource(
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const std::string& new_title,
+    const GetResourceEntryCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  return sender_->StartRequestWithRetry(
+      new MoveResourceRequest(
+          sender_.get(),
+          url_generator_,
+          resource_id,
+          parent_resource_id,
+          new_title,
+          base::Bind(&ParseResourceEntryAndRun, callback)));
+}
+
 CancelCallback DriveAPIService::RenameResource(
     const std::string& resource_id,
     const std::string& new_title,
@@ -608,12 +633,13 @@
   DCHECK(!callback.is_null());
 
   return sender_->StartRequestWithRetry(
-      new RenameResourceRequest(
+      new MoveResourceRequest(
           sender_.get(),
           url_generator_,
           resource_id,
+          std::string(),
           new_title,
-          callback));
+          base::Bind(&EntryActionCallbackAdapter, callback)));
 }
 
 CancelCallback DriveAPIService::TouchResource(
diff --git a/chrome/browser/drive/drive_api_service.h b/chrome/browser/drive/drive_api_service.h
index 8f506da..b896112 100644
--- a/chrome/browser/drive/drive_api_service.h
+++ b/chrome/browser/drive/drive_api_service.h
@@ -123,6 +123,11 @@
       const std::string& resource_id,
       const std::string& new_title,
       const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback MoveResource(
+      const std::string& resource_id,
+      const std::string& parent_resource_id,
+      const std::string& new_title,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
   virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_title,
diff --git a/chrome/browser/drive/drive_api_util.cc b/chrome/browser/drive/drive_api_util.cc
index cd11548..169bdac 100644
--- a/chrome/browser/drive/drive_api_util.cc
+++ b/chrome/browser/drive/drive_api_util.cc
@@ -26,9 +26,9 @@
 bool IsDriveV2ApiEnabled() {
   const CommandLine* command_line = CommandLine::ForCurrentProcess();
 
-  // Disable Drive API v2 by default.
+  // Enable Drive API v2 by default.
   if (!command_line->HasSwitch(switches::kEnableDriveV2Api))
-    return false;
+    return true;
 
   std::string value =
       command_line->GetSwitchValueASCII(switches::kEnableDriveV2Api);
diff --git a/chrome/browser/drive/drive_service_interface.h b/chrome/browser/drive/drive_service_interface.h
index 4aff1f4..72ee3a8 100644
--- a/chrome/browser/drive/drive_service_interface.h
+++ b/chrome/browser/drive/drive_service_interface.h
@@ -210,6 +210,18 @@
       const std::string& new_title,
       const google_apis::GetResourceEntryCallback& callback) = 0;
 
+  // Moves a resource with |resource_id| to the directory of
+  // |parent_resource_id| with renaming to |new_title|.
+  // This request is supported only on DriveAPIService, because GData WAPI
+  // doesn't support the function unfortunately.
+  // Upon completion, invokes |callback| with results on the calling thread.
+  // |callback| must not be null.
+  virtual google_apis::CancelCallback MoveResource(
+      const std::string& resource_id,
+      const std::string& parent_resource_id,
+      const std::string& new_title,
+      const google_apis::GetResourceEntryCallback& callback) = 0;
+
   // Renames a document or collection identified by its |resource_id|
   // to the UTF-8 encoded |new_title|. Upon completion,
   // invokes |callback| with results on the calling thread.
diff --git a/chrome/browser/drive/dummy_drive_service.cc b/chrome/browser/drive/dummy_drive_service.cc
index a61a182..99b7314 100644
--- a/chrome/browser/drive/dummy_drive_service.cc
+++ b/chrome/browser/drive/dummy_drive_service.cc
@@ -116,6 +116,14 @@
     const std::string& new_title,
     const GetResourceEntryCallback& callback) { return CancelCallback(); }
 
+CancelCallback DummyDriveService::MoveResource(
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const std::string& new_title,
+    const google_apis::GetResourceEntryCallback& callback) {
+  return CancelCallback();
+}
+
 CancelCallback DummyDriveService::RenameResource(
     const std::string& resource_id,
     const std::string& new_title,
diff --git a/chrome/browser/drive/dummy_drive_service.h b/chrome/browser/drive/dummy_drive_service.h
index cb90bf1..c63becd 100644
--- a/chrome/browser/drive/dummy_drive_service.h
+++ b/chrome/browser/drive/dummy_drive_service.h
@@ -79,6 +79,11 @@
       const std::string& resource_id,
       const std::string& new_title,
       const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback MoveResource(
+      const std::string& resource_id,
+      const std::string& parent_resource_id,
+      const std::string& new_title,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
   virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_title,
diff --git a/chrome/browser/drive/fake_drive_service.cc b/chrome/browser/drive/fake_drive_service.cc
index 5fc49e3..7075338 100644
--- a/chrome/browser/drive/fake_drive_service.cc
+++ b/chrome/browser/drive/fake_drive_service.cc
@@ -126,6 +126,12 @@
                  base::Passed(&entry)));
 }
 
+void EntryActionCallbackAdapter(
+    const EntryActionCallback& callback,
+    GDataErrorCode error, scoped_ptr<ResourceEntry> resource_entry) {
+  callback.Run(error);
+}
+
 }  // namespace
 
 struct FakeDriveService::UploadSession {
@@ -742,9 +748,9 @@
 
         // Reset parent directory.
         base::ListValue* links = NULL;
-        if (!entry->GetList("link", &links)) {
+        if (!copied_entry->GetList("link", &links)) {
           links = new base::ListValue;
-          entry->Set("link", links);
+          copied_entry->Set("link", links);
         }
         links->Clear();
 
@@ -789,6 +795,73 @@
   return CopyResource(resource_id, std::string(), new_title, callback);
 }
 
+CancelCallback FakeDriveService::MoveResource(
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const std::string& new_title,
+    const google_apis::GetResourceEntryCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  if (offline_) {
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION,
+                              base::Passed(scoped_ptr<ResourceEntry>())));
+    return CancelCallback();
+  }
+
+  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
+  if (entry) {
+    entry->SetString("title.$t", new_title);
+
+    // Set parent if necessary.
+    if (!parent_resource_id.empty()) {
+      base::ListValue* links = NULL;
+      if (!entry->GetList("link", &links)) {
+        links = new base::ListValue;
+        entry->Set("link", links);
+      }
+
+      // Remove old parent(s).
+      for (size_t i = 0; i < links->GetSize(); ) {
+        base::DictionaryValue* link = NULL;
+        std::string rel;
+        std::string href;
+        if (links->GetDictionary(i, &link) &&
+            link->GetString("rel", &rel) &&
+            link->GetString("href", &href) &&
+            rel == "http://schemas.google.com/docs/2007#parent") {
+          links->Remove(i, NULL);
+        } else {
+          ++i;
+        }
+      }
+
+      base::DictionaryValue* link = new base::DictionaryValue;
+      link->SetString("rel", "http://schemas.google.com/docs/2007#parent");
+      link->SetString(
+          "href", GetFakeLinkUrl(parent_resource_id).spec());
+      links->Append(link);
+    }
+
+    AddNewChangestampAndETag(entry);
+
+    // Parse the new entry.
+    scoped_ptr<ResourceEntry> resource_entry =
+        ResourceEntry::CreateFrom(*entry);
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(callback, HTTP_SUCCESS, base::Passed(&resource_entry)));
+    return CancelCallback();
+  }
+
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, HTTP_NOT_FOUND,
+                 base::Passed(scoped_ptr<ResourceEntry>())));
+  return CancelCallback();
+}
+
 CancelCallback FakeDriveService::RenameResource(
     const std::string& resource_id,
     const std::string& new_title,
@@ -796,24 +869,9 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
 
-  if (offline_) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(callback, GDATA_NO_CONNECTION));
-    return CancelCallback();
-  }
-
-  base::DictionaryValue* entry = FindEntryByResourceId(resource_id);
-  if (entry) {
-    entry->SetString("title.$t", new_title);
-    AddNewChangestampAndETag(entry);
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_SUCCESS));
-    return CancelCallback();
-  }
-
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND));
-  return CancelCallback();
+  return MoveResource(
+      resource_id, std::string(), new_title,
+      base::Bind(&EntryActionCallbackAdapter, callback));
 }
 
 CancelCallback FakeDriveService::TouchResource(
diff --git a/chrome/browser/drive/fake_drive_service.h b/chrome/browser/drive/fake_drive_service.h
index 994bc53..ad7fdc3 100644
--- a/chrome/browser/drive/fake_drive_service.h
+++ b/chrome/browser/drive/fake_drive_service.h
@@ -156,6 +156,11 @@
       const std::string& resource_id,
       const std::string& new_title,
       const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback MoveResource(
+      const std::string& resource_id,
+      const std::string& parent_resource_id,
+      const std::string& new_title,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
   virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_title,
diff --git a/chrome/browser/drive/fake_drive_service_unittest.cc b/chrome/browser/drive/fake_drive_service_unittest.cc
index 51fdce5..efbf716 100644
--- a/chrome/browser/drive/fake_drive_service_unittest.cc
+++ b/chrome/browser/drive/fake_drive_service_unittest.cc
@@ -967,7 +967,7 @@
   int64 old_largest_change_id = GetLargestChangeByAboutResource();
 
   const std::string kResourceId = "file:2_file_resource_id";
-  const std::string kParentResourceId = "folder:1_folder_resource_id";
+  const std::string kParentResourceId = "folder:2_folder_resource_id";
   GDataErrorCode error = GDATA_OTHER_ERROR;
   scoped_ptr<ResourceEntry> resource_entry;
   fake_service_.CopyResource(
@@ -982,7 +982,7 @@
   // The copied entry should have the new resource ID and the title.
   EXPECT_EQ(kResourceId + "_copied", resource_entry->resource_id());
   EXPECT_EQ("new title", resource_entry->title());
-  EXPECT_TRUE(HasParent(kResourceId, kParentResourceId));
+  EXPECT_TRUE(HasParent(resource_entry->resource_id(), kParentResourceId));
   // Should be incremented as a new hosted document was created.
   EXPECT_EQ(old_largest_change_id + 1, fake_service_.largest_changestamp());
   EXPECT_EQ(old_largest_change_id + 1, GetLargestChangeByAboutResource());
@@ -1114,6 +1114,105 @@
   EXPECT_FALSE(resource_entry);
 }
 
+TEST_F(FakeDriveServiceTest, MoveResource) {
+  ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
+      "gdata/root_feed.json"));
+  ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
+      "gdata/account_metadata.json"));
+
+  int64 old_largest_change_id = GetLargestChangeByAboutResource();
+
+  const std::string kResourceId = "file:2_file_resource_id";
+  const std::string kParentResourceId = "folder:2_folder_resource_id";
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceEntry> resource_entry;
+  fake_service_.MoveResource(
+      kResourceId,
+      kParentResourceId,
+      "new title",
+      test_util::CreateCopyResultCallback(&error, &resource_entry));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_TRUE(resource_entry);
+  // The copied entry should have the new resource ID and the title.
+  EXPECT_EQ(kResourceId, resource_entry->resource_id());
+  EXPECT_EQ("new title", resource_entry->title());
+  EXPECT_TRUE(HasParent(kResourceId, kParentResourceId));
+  // Should be incremented as a new hosted document was created.
+  EXPECT_EQ(old_largest_change_id + 1, fake_service_.largest_changestamp());
+  EXPECT_EQ(old_largest_change_id + 1, GetLargestChangeByAboutResource());
+}
+
+TEST_F(FakeDriveServiceTest, MoveResource_NonExisting) {
+  ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
+      "gdata/root_feed.json"));
+
+  const std::string kResourceId = "document:nonexisting_resource_id";
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceEntry> resource_entry;
+  fake_service_.MoveResource(
+      kResourceId,
+      "folder:1_folder_resource_id",
+      "new title",
+      test_util::CreateCopyResultCallback(&error, &resource_entry));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(HTTP_NOT_FOUND, error);
+}
+
+TEST_F(FakeDriveServiceTest, MoveResource_EmptyParentResourceId) {
+  ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
+      "gdata/root_feed.json"));
+  ASSERT_TRUE(fake_service_.LoadAccountMetadataForWapi(
+      "gdata/account_metadata.json"));
+
+  int64 old_largest_change_id = GetLargestChangeByAboutResource();
+
+  const std::string kResourceId = "file:2_file_resource_id";
+
+  // Just make sure that the resource is under root.
+  ASSERT_TRUE(HasParent(kResourceId, "fake_root"));
+
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceEntry> resource_entry;
+  fake_service_.MoveResource(
+      kResourceId,
+      std::string(),
+      "new title",
+      test_util::CreateCopyResultCallback(&error, &resource_entry));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  ASSERT_TRUE(resource_entry);
+  // The copied entry should have the new resource ID and the title.
+  EXPECT_EQ(kResourceId, resource_entry->resource_id());
+  EXPECT_EQ("new title", resource_entry->title());
+  EXPECT_TRUE(HasParent(kResourceId, "fake_root"));
+  // Should be incremented as a new hosted document was created.
+  EXPECT_EQ(old_largest_change_id + 1, fake_service_.largest_changestamp());
+  EXPECT_EQ(old_largest_change_id + 1, GetLargestChangeByAboutResource());
+}
+
+TEST_F(FakeDriveServiceTest, MoveResource_Offline) {
+  ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
+      "gdata/root_feed.json"));
+  fake_service_.set_offline(true);
+
+  const std::string kResourceId = "file:2_file_resource_id";
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<ResourceEntry> resource_entry;
+  fake_service_.CopyResource(
+      kResourceId,
+      "folder:1_folder_resource_id",
+      "new title",
+      test_util::CreateCopyResultCallback(&error, &resource_entry));
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(GDATA_NO_CONNECTION, error);
+  EXPECT_FALSE(resource_entry);
+}
+
 TEST_F(FakeDriveServiceTest, RenameResource_ExistingFile) {
   ASSERT_TRUE(fake_service_.LoadResourceListForWapi(
       "gdata/root_feed.json"));
diff --git a/chrome/browser/drive/gdata_wapi_service.cc b/chrome/browser/drive/gdata_wapi_service.cc
index 218eb6e..8a262a0 100644
--- a/chrome/browser/drive/gdata_wapi_service.cc
+++ b/chrome/browser/drive/gdata_wapi_service.cc
@@ -432,6 +432,22 @@
                                     new_title));
 }
 
+CancelCallback GDataWapiService::MoveResource(
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const std::string& new_title,
+    const google_apis::GetResourceEntryCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  // GData WAPI doesn't support to "move" resources.
+  // This method should never be called if GData WAPI is enabled.
+  // Instead, client code should rename the file, add new parent, and then
+  // remove the old parent.
+  NOTREACHED();
+  return CancelCallback();
+}
+
 CancelCallback GDataWapiService::RenameResource(
     const std::string& resource_id,
     const std::string& new_title,
diff --git a/chrome/browser/drive/gdata_wapi_service.h b/chrome/browser/drive/gdata_wapi_service.h
index 9fa04be..a7139b8 100644
--- a/chrome/browser/drive/gdata_wapi_service.h
+++ b/chrome/browser/drive/gdata_wapi_service.h
@@ -119,6 +119,11 @@
       const std::string& resource_id,
       const std::string& new_title,
       const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
+  virtual google_apis::CancelCallback MoveResource(
+      const std::string& resource_id,
+      const std::string& parent_resource_id,
+      const std::string& new_title,
+      const google_apis::GetResourceEntryCallback& callback) OVERRIDE;
   virtual google_apis::CancelCallback RenameResource(
       const std::string& resource_id,
       const std::string& new_title,
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS
index d16e654..3cc3516 100644
--- a/chrome/browser/extensions/DEPS
+++ b/chrome/browser/extensions/DEPS
@@ -4,11 +4,9 @@
   # chrome/browser/extensions, the restriction of not being able
   # to depend on apps will be lifted.
   "-apps",
-  "+apps/app_window_contents.h",
-  "+apps/launcher.h",
-  "+apps/native_app_window.h",
   "+apps/shell_window.h",
   "+apps/shell_window_registry.h",
+  "-chrome/browser/apps",
 
   # TODO(tfarina): Remove all these. crbug.com/125846.
   # DO NOT ADD ANY MORE ITEMS TO THE LIST BELOW!
diff --git a/chrome/browser/extensions/OWNERS b/chrome/browser/extensions/OWNERS
index bc2836c..b4779a6 100644
--- a/chrome/browser/extensions/OWNERS
+++ b/chrome/browser/extensions/OWNERS
@@ -18,8 +18,3 @@
 miket@chromium.org
 mpcomplete@chromium.org
 yoz@chromium.org
-
-per-file web_view_*.cc=fsamuel@chromium.org
-per-file web_view_*.cc=lazyboy@chromium.org
-per-file ad_view_*.cc=fsamuel@chromium.org
-per-file ad_view_*.cc=lazyboy@chromium.org
diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc
index 312a6c3..a62b181 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/active_tab_permission_granter.cc
@@ -116,7 +116,7 @@
 }
 
 int32 ActiveTabPermissionGranter::GetPageID() {
-  return web_contents()->GetController().GetActiveEntry()->GetPageID();
+  return web_contents()->GetController().GetVisibleEntry()->GetPageID();
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc
index f615724..93bd889 100644
--- a/chrome/browser/extensions/active_tab_unittest.cc
+++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/sessions/session_id.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_builder.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/extensions/value_builder.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -28,6 +27,7 @@
 #include "content/public/common/frame_navigate_params.h"
 #include "content/public/common/page_transition_types.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/features/feature.h"
 
 using base::DictionaryValue;
 using base::ListValue;
diff --git a/chrome/browser/extensions/activity_log/activity_actions.cc b/chrome/browser/extensions/activity_log/activity_actions.cc
index 4baca4c..a871fc9 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.cc
+++ b/chrome/browser/extensions/activity_log/activity_actions.cc
@@ -40,9 +40,6 @@
 
 namespace extensions {
 
-using api::activity_log_private::BlockedChromeActivityDetail;
-using api::activity_log_private::ChromeActivityDetail;
-using api::activity_log_private::DomActivityDetail;
 using api::activity_log_private::ExtensionActivity;
 
 Action::Action(const std::string& extension_id,
@@ -133,83 +130,48 @@
 scoped_ptr<ExtensionActivity> Action::ConvertToExtensionActivity() {
   scoped_ptr<ExtensionActivity> result(new ExtensionActivity);
 
-  result->extension_id.reset(new std::string(extension_id()));
-  result->time.reset(new double(time().ToJsTime()));
-
+  // We do this translation instead of using the same enum because the database
+  // values need to be stable; this allows us to change the extension API
+  // without affecting the database.
   switch (action_type()) {
     case ACTION_API_CALL:
-    case ACTION_API_EVENT: {
-      ChromeActivityDetail* details = new ChromeActivityDetail;
-      if (action_type() == ACTION_API_CALL) {
-        details->api_activity_type =
-            ChromeActivityDetail::API_ACTIVITY_TYPE_CALL;
-      } else {
-        details->api_activity_type =
-            ChromeActivityDetail::API_ACTIVITY_TYPE_EVENT_CALLBACK;
-      }
-      details->api_call.reset(new std::string(api_name()));
-      details->args.reset(new std::string(Serialize(args())));
-      details->extra.reset(new std::string(Serialize(other())));
-
-      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_CHROME;
-      result->chrome_activity_detail.reset(details);
+      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_API_CALL;
       break;
-    }
-
-    case ACTION_API_BLOCKED: {
-      BlockedChromeActivityDetail* details = new BlockedChromeActivityDetail;
-      details->api_call.reset(new std::string(api_name()));
-      details->args.reset(new std::string(Serialize(args())));
-      details->extra.reset(new std::string(Serialize(other())));
-      // TODO(mvrable): details->reason isn't filled in; fix this after
-      // converting logging to using the types from
-      // BlockedChromeActivityDetail::Reason.
-      details->reason = BlockedChromeActivityDetail::REASON_NONE;
-
-      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_BLOCKED_CHROME;
-      result->blocked_chrome_activity_detail.reset(details);
+    case ACTION_API_EVENT:
+      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_API_EVENT;
       break;
-    }
-
-    case ACTION_DOM_EVENT:
-    case ACTION_DOM_ACCESS:
     case ACTION_CONTENT_SCRIPT:
-    case ACTION_WEB_REQUEST: {
-      DomActivityDetail* details = new DomActivityDetail;
-
-      if (action_type() == ACTION_WEB_REQUEST) {
-        details->dom_activity_type =
-            DomActivityDetail::DOM_ACTIVITY_TYPE_WEBREQUEST;
-      } else if (action_type() == ACTION_CONTENT_SCRIPT) {
-        details->dom_activity_type =
-            DomActivityDetail::DOM_ACTIVITY_TYPE_INSERTED;
-      } else {
-        // TODO(mvrable): This ought to be filled in properly, but since the
-        // API will change soon don't worry about it now.
-        details->dom_activity_type =
-            DomActivityDetail::DOM_ACTIVITY_TYPE_NONE;
-      }
-      details->api_call.reset(new std::string(api_name()));
-      details->args.reset(new std::string(Serialize(args())));
-      details->extra.reset(new std::string(Serialize(other())));
-      if (page_incognito()) {
-        details->url.reset(new std::string(constants::kIncognitoUrl));
-      } else {
-        details->url.reset(new std::string(page_url().spec()));
-        if (!page_title().empty())
-          details->url_title.reset(new std::string(page_title()));
-      }
-
-      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM;
-      result->dom_activity_detail.reset(details);
+      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_CONTENT_SCRIPT;
       break;
-    }
-
-    default:
-      LOG(WARNING) << "Bad activity log entry read from database (type="
-                   << action_type_ << ")!";
+    case ACTION_DOM_ACCESS:
+      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM_ACCESS;
+      break;
+    case ACTION_DOM_EVENT:
+      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM_EVENT;
+      break;
+    case ACTION_WEB_REQUEST:
+      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_WEB_REQUEST;
+      break;
+    case UNUSED_ACTION_API_BLOCKED:
+      // Here for legacy reasons. It shouldn't be reached, but some people
+      // might have old db entries. Treat it like an API call if that happens.
+      result->activity_type = ExtensionActivity::ACTIVITY_TYPE_API_CALL;
+      break;
   }
 
+  result->extension_id.reset(new std::string(extension_id()));
+  result->time.reset(new double(time().ToJsTime()));
+  result->api_call.reset(new std::string(api_name()));
+  result->args.reset(new std::string(Serialize(args())));
+  if (page_url().is_valid()) {
+    if (!page_title().empty())
+      result->page_title.reset(new std::string(page_title()));
+    result->page_url.reset(new std::string(page_url().spec()));
+  }
+  if (arg_url().is_valid())
+    result->arg_url.reset(new std::string(arg_url().spec()));
+  result->extra.reset(new std::string(Serialize(other())));
+
   return result.Pass();
 }
 
@@ -228,7 +190,8 @@
     case ACTION_CONTENT_SCRIPT:
       result += "content_script";
       break;
-    case ACTION_API_BLOCKED:
+    case UNUSED_ACTION_API_BLOCKED:
+      // This is deprecated.
       result += "api_blocked";
       break;
     case ACTION_DOM_EVENT:
@@ -268,4 +231,66 @@
   return result;
 }
 
+bool ActionComparator::operator()(
+    const scoped_refptr<Action>& lhs,
+    const scoped_refptr<Action>& rhs) const {
+  if (lhs->time() != rhs->time())
+    return lhs->time() < rhs->time();
+  else
+    return ActionComparatorExcludingTime()(lhs, rhs);
+}
+
+bool ActionComparatorExcludingTime::operator()(
+    const scoped_refptr<Action>& lhs,
+    const scoped_refptr<Action>& rhs) const {
+  if (lhs->extension_id() != rhs->extension_id())
+    return lhs->extension_id() < rhs->extension_id();
+  if (lhs->action_type() != rhs->action_type())
+    return lhs->action_type() < rhs->action_type();
+  if (lhs->api_name() != rhs->api_name())
+    return lhs->api_name() < rhs->api_name();
+
+  // args might be null; treat a null value as less than all non-null values,
+  // including the empty string.
+  if (!lhs->args() && rhs->args())
+    return true;
+  if (lhs->args() && !rhs->args())
+    return false;
+  if (lhs->args() && rhs->args()) {
+    std::string lhs_args = ActivityLogPolicy::Util::Serialize(lhs->args());
+    std::string rhs_args = ActivityLogPolicy::Util::Serialize(rhs->args());
+    if (lhs_args != rhs_args)
+      return lhs_args < rhs_args;
+  }
+
+  // Compare URLs as strings, and treat the incognito flag as a separate field.
+  if (lhs->page_url().spec() != rhs->page_url().spec())
+    return lhs->page_url().spec() < rhs->page_url().spec();
+  if (lhs->page_incognito() != rhs->page_incognito())
+    return lhs->page_incognito() < rhs->page_incognito();
+
+  if (lhs->page_title() != rhs->page_title())
+    return lhs->page_title() < rhs->page_title();
+
+  if (lhs->arg_url().spec() != rhs->arg_url().spec())
+    return lhs->arg_url().spec() < rhs->arg_url().spec();
+  if (lhs->arg_incognito() != rhs->arg_incognito())
+    return lhs->arg_incognito() < rhs->arg_incognito();
+
+  // other is treated much like the args field.
+  if (!lhs->other() && rhs->other())
+    return true;
+  if (lhs->other() && !rhs->other())
+    return false;
+  if (lhs->other() && rhs->other()) {
+    std::string lhs_other = ActivityLogPolicy::Util::Serialize(lhs->other());
+    std::string rhs_other = ActivityLogPolicy::Util::Serialize(rhs->other());
+    if (lhs_other != rhs_other)
+      return lhs_other < rhs_other;
+  }
+
+  // All fields compare as equal if this point is reached.
+  return false;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/activity_log/activity_actions.h b/chrome/browser/extensions/activity_log/activity_actions.h
index 8e3e31c..d9e59a8 100644
--- a/chrome/browser/extensions/activity_log/activity_actions.h
+++ b/chrome/browser/extensions/activity_log/activity_actions.h
@@ -29,7 +29,7 @@
   enum ActionType {
     ACTION_API_CALL = 0,
     ACTION_API_EVENT = 1,
-    ACTION_API_BLOCKED = 2,
+    UNUSED_ACTION_API_BLOCKED = 2,  // Not in use, but reserved for future.
     ACTION_CONTENT_SCRIPT = 3,
     ACTION_DOM_ACCESS = 4,
     ACTION_DOM_EVENT = 5,
@@ -40,8 +40,8 @@
   // objects.
   typedef std::vector<scoped_refptr<Action> > ActionVector;
 
-  // Creates a new activity log Action object.  The extension_id, time, and
-  // type are immutable.  All other fields can be filled in with the
+  // Creates a new activity log Action object.  The extension_id and type
+  // fields are immutable.  All other fields can be filled in with the
   // accessors/mutators below.
   Action(const std::string& extension_id,
          const base::Time& time,
@@ -56,6 +56,7 @@
 
   // The time the record was generated (or some approximation).
   const base::Time& time() const { return time_; }
+  void set_time(const base::Time& time) { time_ = time; }
 
   // The ActionType distinguishes different classes of actions that can be
   // logged, and determines which other fields are expected to be filled in.
@@ -121,7 +122,6 @@
 
   std::string extension_id_;
   base::Time time_;
-  api::activity_log_private::ExtensionActivity::ActivityType activity_type_;
   ActionType action_type_;
   std::string api_name_;
   scoped_ptr<ListValue> args_;
@@ -135,6 +135,22 @@
   DISALLOW_COPY_AND_ASSIGN(Action);
 };
 
+// A comparator for Action class objects; this performs a lexicographic
+// comparison of the fields of the Action object (in an unspecfied order).
+// This can be used to use Action objects as keys in STL containers.
+struct ActionComparator {
+  // Evaluates the comparison lhs < rhs.
+  bool operator()(const scoped_refptr<Action>& lhs,
+                  const scoped_refptr<Action>& rhs) const;
+};
+
+// Like ActionComparator, but ignores the time field in comparisons.
+struct ActionComparatorExcludingTime {
+  // Evaluates the comparison lhs < rhs.
+  bool operator()(const scoped_refptr<Action>& lhs,
+                  const scoped_refptr<Action>& rhs) const;
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_ACTIONS_H_
diff --git a/chrome/browser/extensions/activity_log/activity_database_unittest.cc b/chrome/browser/extensions/activity_log/activity_database_unittest.cc
index 5894999..a2bdd9a 100644
--- a/chrome/browser/extensions/activity_log/activity_database_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_database_unittest.cc
@@ -27,7 +27,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/mock_user_manager.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -161,7 +160,6 @@
 
  private:
 #if defined OS_CHROMEOS
-  chromeos::ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
   chromeos::ScopedTestCrosSettings test_cros_settings_;
   scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc
index bc973e7..d80eedc 100644
--- a/chrome/browser/extensions/activity_log/activity_log.cc
+++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/install_tracker_factory.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/prerender/prerender_manager.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -29,6 +30,7 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/re2/re2/re2.h"
@@ -54,44 +56,6 @@
   return call_signature;
 }
 
-// This is a hack for AL callers who don't have access to a profile object
-// when deciding whether or not to do the work required for logging. The state
-// is accessed through the static ActivityLog::IsLogEnabledOnAnyProfile()
-// method. It returns true if --enable-extension-activity-logging is set on the
-// command line OR *ANY* profile has the activity log whitelisted extension
-// installed.
-class LogIsEnabled {
- public:
-  LogIsEnabled() : any_profile_enabled_(false) {
-    ComputeIsFlagEnabled();
-  }
-
-  void ComputeIsFlagEnabled() {
-    base::AutoLock auto_lock(lock_);
-    cmd_line_enabled_ = CommandLine::ForCurrentProcess()->
-        HasSwitch(switches::kEnableExtensionActivityLogging);
-  }
-
-  static LogIsEnabled* GetInstance() {
-    return Singleton<LogIsEnabled>::get();
-  }
-
-  bool IsEnabled() {
-    base::AutoLock auto_lock(lock_);
-    return cmd_line_enabled_ || any_profile_enabled_;
-  }
-
-  void SetProfileEnabled(bool any_profile_enabled) {
-    base::AutoLock auto_lock(lock_);
-    any_profile_enabled_ = any_profile_enabled;
-  }
-
- private:
-  base::Lock lock_;
-  bool any_profile_enabled_;
-  bool cmd_line_enabled_;
-};
-
 // Gets the URL for a given tab ID.  Helper method for LookupTabId.  Returns
 // true if able to perform the lookup.  The URL is stored to *url, and
 // *is_incognito is set to indicate whether the URL is for an incognito tab.
@@ -183,17 +147,6 @@
 
 namespace extensions {
 
-// static
-bool ActivityLog::IsLogEnabledOnAnyProfile() {
-  return LogIsEnabled::GetInstance()->IsEnabled();
-}
-
-// static
-void ActivityLog::RecomputeLoggingIsEnabled(bool profile_enabled) {
-  LogIsEnabled::GetInstance()->ComputeIsFlagEnabled();
-  LogIsEnabled::GetInstance()->SetProfileEnabled(profile_enabled);
-}
-
 // ActivityLogFactory
 
 ActivityLogFactory* ActivityLogFactory::GetInstance() {
@@ -257,16 +210,22 @@
       policy_type_(ActivityLogPolicy::POLICY_INVALID),
       profile_(profile),
       enabled_(false),
-      initialized_(false),
       policy_chosen_(false),
       testing_mode_(false),
       has_threads_(true),
-      tracker_(NULL) {
+      tracker_(NULL),
+      watchdog_extension_active_(false) {
   // This controls whether logging statements are printed, which policy is set,
   // etc.
   testing_mode_ = CommandLine::ForCurrentProcess()->HasSwitch(
     switches::kEnableExtensionActivityLogTesting);
 
+  // Check if the watchdog extension is previously installed and active.
+  watchdog_extension_active_ =
+    profile_->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive);
+
+  observers_ = new ObserverListThreadSafe<Observer>;
+
   // Check that the right threads exist. If not, we shouldn't try to do things
   // that require them.
   if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) ||
@@ -274,28 +233,24 @@
       !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
     LOG(ERROR) << "Missing threads, disabling Activity Logging!";
     has_threads_ = false;
-  } else {
-    enabled_ = IsLogEnabledOnAnyProfile();
-    ExtensionSystem::Get(profile_)->ready().Post(
-      FROM_HERE, base::Bind(&ActivityLog::Init, base::Unretained(this)));
   }
 
-  observers_ = new ObserverListThreadSafe<Observer>;
+  enabled_ = has_threads_
+      && (CommandLine::ForCurrentProcess()->
+          HasSwitch(switches::kEnableExtensionActivityLogging)
+      || watchdog_extension_active_);
+
+  if (enabled_) enabled_on_any_profile_ = true;
+
+  ExtensionSystem::Get(profile_)->ready().Post(
+      FROM_HERE,
+      base::Bind(&ActivityLog::InitInstallTracker, base::Unretained(this)));
+  ChooseDefaultPolicy();
 }
 
-void ActivityLog::Init() {
-  DCHECK(has_threads_);
-  DCHECK(!initialized_);
-  const Extension* whitelisted_extension = ExtensionSystem::Get(profile_)->
-      extension_service()->GetExtensionById(kActivityLogExtensionId, false);
-  if (whitelisted_extension) {
-    enabled_ = true;
-    LogIsEnabled::GetInstance()->SetProfileEnabled(true);
-  }
+void ActivityLog::InitInstallTracker() {
   tracker_ = InstallTrackerFactory::GetForProfile(profile_);
   tracker_->AddObserver(this);
-  ChooseDefaultPolicy();
-  initialized_ = true;
 }
 
 void ActivityLog::ChooseDefaultPolicy() {
@@ -315,23 +270,45 @@
     policy_->Close();
 }
 
+// static
+bool ActivityLog::enabled_on_any_profile_ = false;
+
+// static
+bool ActivityLog::IsLogEnabledOnAnyProfile() {
+  return enabled_on_any_profile_;
+}
+
 bool ActivityLog::IsLogEnabled() {
-  if (!has_threads_ || !initialized_) return false;
+  // Make sure we are not enabled when there are no threads.
+  DCHECK(has_threads_ || !enabled_);
   return enabled_;
 }
 
 void ActivityLog::OnExtensionLoaded(const Extension* extension) {
   if (extension->id() != kActivityLogExtensionId) return;
-  enabled_ = true;
-  LogIsEnabled::GetInstance()->SetProfileEnabled(true);
+  if (has_threads_) {
+    enabled_ = true;
+    enabled_on_any_profile_ = true;
+  }
+  if (!watchdog_extension_active_) {
+    watchdog_extension_active_ = true;
+    profile_->GetPrefs()->SetBoolean(prefs::kWatchdogExtensionActive, true);
+  }
   ChooseDefaultPolicy();
 }
 
 void ActivityLog::OnExtensionUnloaded(const Extension* extension) {
   if (extension->id() != kActivityLogExtensionId) return;
+  // Make sure we are not enabled when there are no threads.
+  DCHECK(has_threads_ || !enabled_);
   if (!CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnableExtensionActivityLogging))
     enabled_ = false;
+  if (watchdog_extension_active_) {
+    watchdog_extension_active_ = false;
+    profile_->GetPrefs()->SetBoolean(prefs::kWatchdogExtensionActive,
+                                     false);
+  }
 }
 
 // static
@@ -427,4 +404,13 @@
   }
 }
 
+// static
+void ActivityLog::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterBooleanPref(
+      prefs::kWatchdogExtensionActive,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/activity_log/activity_log.h b/chrome/browser/extensions/activity_log/activity_log.h
index 4f75d29..93f61e3 100644
--- a/chrome/browser/extensions/activity_log/activity_log.h
+++ b/chrome/browser/extensions/activity_log/activity_log.h
@@ -29,6 +29,10 @@
 class Profile;
 using content::BrowserThread;
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
 namespace extensions {
 class Extension;
 class ActivityLogPolicy;
@@ -50,16 +54,16 @@
   // use GetInstance instead.
   static ActivityLog* GetInstance(Profile* profile);
 
+  // Specifies if AL was enabled at least for one profile. We use this method to
+  // check if AL possibly enabled when a profile is not available, e.g., when
+  // executing on thread other than UI.
+  static bool IsLogEnabledOnAnyProfile();
+
   // Provides up-to-date information about whether the AL is enabled for a
   // profile. The AL is enabled if the user has installed the whitelisted
   // AL extension *or* set the --enable-extension-activity-logging flag.
   bool IsLogEnabled();
 
-  // If you want to know whether the log is enabled but DON'T have a profile
-  // object yet, use this method. However, it's preferable for the caller to
-  // use IsLogEnabled when possible.
-  static bool IsLogEnabledOnAnyProfile();
-
   // Add/remove observer: the activityLogPrivate API only listens when the
   // ActivityLog extension is registered for an event.
   void AddObserver(Observer* observer);
@@ -83,14 +87,10 @@
   // Extension::InstallObserver
   // We keep track of whether the whitelisted extension is installed; if it is,
   // we want to recompute whether to have logging enabled.
-  virtual void OnExtensionInstalled(
-      const extensions::Extension* extension) OVERRIDE {}
-  virtual void OnExtensionLoaded(
-      const extensions::Extension* extension) OVERRIDE;
-  virtual void OnExtensionUnloaded(
-      const extensions::Extension* extension) OVERRIDE;
-  virtual void OnExtensionUninstalled(
-      const extensions::Extension* extension) OVERRIDE {}
+  virtual void OnExtensionInstalled(const Extension* extension) OVERRIDE {}
+  virtual void OnExtensionLoaded(const Extension* extension) OVERRIDE;
+  virtual void OnExtensionUnloaded(const Extension* extension) OVERRIDE;
+  virtual void OnExtensionUninstalled(const Extension* extension) OVERRIDE {}
   // We also have to list the following from InstallObserver.
   virtual void OnBeginExtensionInstall(const std::string& extension_id,
                                        const std::string& extension_name,
@@ -108,6 +108,8 @@
   // BrowserContextKeyedService
   virtual void Shutdown() OVERRIDE;
 
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
  private:
   friend class ActivityLogFactory;
   friend class ActivityLogTest;
@@ -116,9 +118,9 @@
   explicit ActivityLog(Profile* profile);
   virtual ~ActivityLog();
 
-  // Some setup needs to wait until after the ExtensionSystem/ExtensionService
-  // are done with their own setup.
-  void Init();
+  // Delayed initialization of Install Tracker which waits until after the
+  // ExtensionSystem/ExtensionService are done with their own setup.
+  void InitInstallTracker();
 
   // TabHelper::ScriptExecutionObserver implementation.
   // Fires when a ContentScript is executed.
@@ -128,10 +130,6 @@
       int32 page_id,
       const GURL& on_url) OVERRIDE;
 
-  // For unit tests only. Does not call Init again!
-  // Sets whether logging should be enabled for the whole current profile.
-  static void RecomputeLoggingIsEnabled(bool profile_enabled);
-
   // At the moment, ActivityLog will use only one policy for summarization.
   // These methods are used to choose and set the most appropriate policy.
   void ChooseDefaultPolicy();
@@ -145,14 +143,13 @@
   // be a scoped_ptr since some cleanup work must happen on the database
   // thread.  Calling policy_->Close() will free the object; see the comments
   // on the ActivityDatabase class for full details.
-  extensions::ActivityLogPolicy* policy_;
+  ActivityLogPolicy* policy_;
 
   // TODO(dbabic,felt) change this into a list of policy types later.
   ActivityLogPolicy::PolicyType policy_type_;
 
   Profile* profile_;
   bool enabled_;  // Whether logging is currently enabled.
-  bool initialized_;  // Whether Init() has already been called.
   bool policy_chosen_;  // Whether we've already set the default policy.
   // testing_mode_ controls whether to log API call arguments. By default, we
   // don't log most arguments to avoid saving too much data. In testing mode,
@@ -169,6 +166,13 @@
   // added or removed, enabled_ may change.
   InstallTracker* tracker_;
 
+  // Set if the watchdog extension is present and active. Maintained by
+  // kWatchdogExtensionActive pref variable.
+  bool watchdog_extension_active_;
+
+  // Specifies if AL was enabled at least for one profile.
+  static bool enabled_on_any_profile_;
+
   DISALLOW_COPY_AND_ASSIGN(ActivityLog);
 };
 
diff --git a/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc
new file mode 100644
index 0000000..808618b
--- /dev/null
+++ b/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc
@@ -0,0 +1,190 @@
+// Copyright 2013 The Chromium Authors. 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/run_loop.h"
+#include "chrome/browser/extensions/activity_log/activity_log.h"
+#include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_builder.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+
+#if defined OS_CHROMEOS
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/device_settings_service.h"
+#endif
+
+namespace extensions {
+
+class ActivityLogEnabledTest : public ChromeRenderViewHostTestHarness {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    ChromeRenderViewHostTestHarness::SetUp();
+#if defined OS_CHROMEOS
+    test_user_manager_.reset(new chromeos::ScopedTestUserManager());
+#endif
+  }
+
+  virtual void TearDown() OVERRIDE {
+#if defined OS_CHROMEOS
+    test_user_manager_.reset();
+#endif
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
+#if defined OS_CHROMEOS
+  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
+  chromeos::ScopedTestCrosSettings test_cros_settings_;
+  scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
+#endif
+};
+
+TEST_F(ActivityLogEnabledTest, NoSwitch) {
+  scoped_ptr<TestingProfile> profile(
+    static_cast<TestingProfile*>(CreateBrowserContext()));
+  EXPECT_FALSE(
+      profile->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+
+  ActivityLog* activity_log = ActivityLog::GetInstance(profile.get());
+
+    EXPECT_FALSE(
+      profile->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(activity_log->IsLogEnabled());
+  EXPECT_FALSE(activity_log->IsLogEnabledOnAnyProfile());
+}
+
+TEST_F(ActivityLogEnabledTest, CommandLineSwitch) {
+  scoped_ptr<TestingProfile> profile1(
+    static_cast<TestingProfile*>(CreateBrowserContext()));
+  scoped_ptr<TestingProfile> profile2(
+    static_cast<TestingProfile*>(CreateBrowserContext()));
+
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  CommandLine saved_cmdline_ = *CommandLine::ForCurrentProcess();
+  CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kEnableExtensionActivityLogging);
+  ActivityLog* activity_log1 = ActivityLog::GetInstance(profile1.get());
+  *CommandLine::ForCurrentProcess() = saved_cmdline_;
+  ActivityLog* activity_log2 = ActivityLog::GetInstance(profile2.get());
+
+  EXPECT_FALSE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_TRUE(activity_log1->IsLogEnabled());
+  EXPECT_FALSE(activity_log2->IsLogEnabled());
+  EXPECT_TRUE(activity_log1->IsLogEnabledOnAnyProfile());
+  EXPECT_TRUE(activity_log2->IsLogEnabledOnAnyProfile());
+}
+
+TEST_F(ActivityLogEnabledTest, PrefSwitch) {
+  scoped_ptr<TestingProfile> profile1(
+    static_cast<TestingProfile*>(CreateBrowserContext()));
+  scoped_ptr<TestingProfile> profile2(
+    static_cast<TestingProfile*>(CreateBrowserContext()));
+
+  EXPECT_FALSE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+
+  profile1->GetPrefs()->SetBoolean(prefs::kWatchdogExtensionActive, true);
+  ActivityLog* activity_log1 = ActivityLog::GetInstance(profile1.get());
+  ActivityLog* activity_log2 = ActivityLog::GetInstance(profile2.get());
+
+  EXPECT_TRUE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_TRUE(activity_log1->IsLogEnabled());
+  EXPECT_FALSE(activity_log2->IsLogEnabled());
+  EXPECT_TRUE(activity_log1->IsLogEnabledOnAnyProfile());
+  EXPECT_TRUE(activity_log2->IsLogEnabledOnAnyProfile());
+}
+
+TEST_F(ActivityLogEnabledTest, WatchdogSwitch) {
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  scoped_ptr<TestingProfile> profile1(
+    static_cast<TestingProfile*>(CreateBrowserContext()));
+  scoped_ptr<TestingProfile> profile2(
+    static_cast<TestingProfile*>(CreateBrowserContext()));
+  // Extension service is destroyed by the profile.
+  ExtensionService* extension_service1 =
+    static_cast<TestExtensionSystem*>(
+        ExtensionSystem::Get(profile1.get()))->CreateExtensionService(
+            &command_line, base::FilePath(), false);
+  static_cast<TestExtensionSystem*>(
+      ExtensionSystem::Get(profile1.get()))->SetReady();
+
+  ActivityLog* activity_log1 = ActivityLog::GetInstance(profile1.get());
+  ActivityLog* activity_log2 = ActivityLog::GetInstance(profile2.get());
+
+  // Allow Activity Log to install extension tracker.
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+
+  scoped_refptr<Extension> extension =
+      ExtensionBuilder()
+          .SetManifest(DictionaryBuilder()
+                       .Set("name", "Watchdog Extension ")
+                       .Set("version", "1.0.0")
+                       .Set("manifest_version", 2))
+          .SetID(kActivityLogExtensionId)
+          .Build();
+  extension_service1->AddExtension(extension.get());
+
+  EXPECT_TRUE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_TRUE(activity_log1->IsLogEnabled());
+  EXPECT_FALSE(activity_log2->IsLogEnabled());
+  EXPECT_TRUE(activity_log1->IsLogEnabledOnAnyProfile());
+  EXPECT_TRUE(activity_log2->IsLogEnabledOnAnyProfile());
+
+  extension_service1->DisableExtension(kActivityLogExtensionId,
+                                       Extension::DISABLE_USER_ACTION);
+
+  EXPECT_FALSE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(activity_log1->IsLogEnabled());
+  EXPECT_FALSE(activity_log2->IsLogEnabled());
+  EXPECT_TRUE(activity_log1->IsLogEnabledOnAnyProfile());
+  EXPECT_TRUE(activity_log2->IsLogEnabledOnAnyProfile());
+
+  extension_service1->EnableExtension(kActivityLogExtensionId);
+
+  EXPECT_TRUE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_TRUE(activity_log1->IsLogEnabled());
+  EXPECT_FALSE(activity_log2->IsLogEnabled());
+  EXPECT_TRUE(activity_log1->IsLogEnabledOnAnyProfile());
+  EXPECT_TRUE(activity_log2->IsLogEnabledOnAnyProfile());
+
+  extension_service1->UninstallExtension(kActivityLogExtensionId, false, NULL);
+
+  EXPECT_FALSE(
+      profile1->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(
+      profile2->GetPrefs()->GetBoolean(prefs::kWatchdogExtensionActive));
+  EXPECT_FALSE(activity_log1->IsLogEnabled());
+  EXPECT_FALSE(activity_log2->IsLogEnabled());
+  EXPECT_TRUE(activity_log1->IsLogEnabledOnAnyProfile());
+  EXPECT_TRUE(activity_log2->IsLogEnabledOnAnyProfile());
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/activity_log/activity_log_policy.cc b/chrome/browser/extensions/activity_log/activity_log_policy.cc
index c02da5e..479e640 100644
--- a/chrome/browser/extensions/activity_log/activity_log_policy.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_policy.cc
@@ -57,6 +57,12 @@
   ScheduleAndForget(db_, &ActivityDatabase::Init, database_path);
 }
 
+void ActivityLogDatabasePolicy::Flush() {
+  ScheduleAndForget(activity_database(),
+                    &ActivityDatabase::AdviseFlush,
+                    ActivityDatabase::kFlushImmediately);
+}
+
 sql::Connection* ActivityLogDatabasePolicy::GetDatabaseConnection() const {
   return db_->GetSqlConnection();
 }
@@ -120,7 +126,7 @@
     scoped_refptr<Action> action) {
   if (action->action_type() != Action::ACTION_API_CALL &&
       action->action_type() != Action::ACTION_API_EVENT &&
-      action->action_type() != Action::ACTION_API_BLOCKED)
+      action->action_type() != Action::UNUSED_ACTION_API_BLOCKED)
     return;
 
   if (api_whitelist.find(action->api_name()) == api_whitelist.end())
diff --git a/chrome/browser/extensions/activity_log/activity_log_policy.h b/chrome/browser/extensions/activity_log/activity_log_policy.h
index ebfdf4e..a0d3472 100644
--- a/chrome/browser/extensions/activity_log/activity_log_policy.h
+++ b/chrome/browser/extensions/activity_log/activity_log_policy.h
@@ -161,6 +161,11 @@
   ActivityLogDatabasePolicy(Profile* profile,
                             const base::FilePath& database_name);
 
+  // Requests that in-memory state be written to the database.  This method can
+  // be called from any thread, but the database writes happen asynchronously
+  // on the database thread.
+  virtual void Flush();
+
  protected:
   // The Schedule methods dispatch the calls to the database on a
   // separate thread.
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
index 25c9cea..30ade1f 100644
--- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc
+++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -39,24 +39,19 @@
 
 class ActivityLogTest : public ChromeRenderViewHostTestHarness {
  protected:
-  ActivityLogTest() : saved_cmdline_(CommandLine::NO_PROGRAM) {}
-
   virtual void SetUp() OVERRIDE {
     ChromeRenderViewHostTestHarness::SetUp();
 #if defined OS_CHROMEOS
     test_user_manager_.reset(new chromeos::ScopedTestUserManager());
 #endif
     CommandLine command_line(CommandLine::NO_PROGRAM);
-    saved_cmdline_ = *CommandLine::ForCurrentProcess();
     CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnableExtensionActivityLogging);
     CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnableExtensionActivityLogTesting);
-    ActivityLog::RecomputeLoggingIsEnabled(true);  // Logging now enabled.
     extension_service_ = static_cast<TestExtensionSystem*>(
         ExtensionSystem::Get(profile()))->CreateExtensionService
             (&command_line, base::FilePath(), false);
-    ActivityLog::GetInstance(profile())->Init();
     base::RunLoop().RunUntilIdle();
   }
 
@@ -65,9 +60,6 @@
     test_user_manager_.reset();
 #endif
     base::RunLoop().RunUntilIdle();
-    // Restore the original command line and undo the affects of SetUp().
-    *CommandLine::ForCurrentProcess() = saved_cmdline_;
-    ActivityLog::RecomputeLoggingIsEnabled(false);  // Logging now disabled.
     ChromeRenderViewHostTestHarness::TearDown();
   }
 
@@ -96,11 +88,6 @@
   }
 
   ExtensionService* extension_service_;
-  // Used to preserve a copy of the original command line.
-  // The test framework will do this itself as well. However, by then,
-  // it is too late to call ActivityLog::RecomputeLoggingIsEnabled() in
-  // TearDown().
-  CommandLine saved_cmdline_;
 
 #if defined OS_CHROMEOS
   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
@@ -109,10 +96,6 @@
 #endif
 };
 
-TEST_F(ActivityLogTest, Enabled) {
-  ASSERT_TRUE(ActivityLog::IsLogEnabledOnAnyProfile());
-}
-
 TEST_F(ActivityLogTest, Construct) {
   ActivityLog* activity_log = ActivityLog::GetInstance(profile());
   ASSERT_TRUE(activity_log->IsLogEnabled());
diff --git a/chrome/browser/extensions/activity_log/counting_policy.cc b/chrome/browser/extensions/activity_log/counting_policy.cc
index b82390a..8f9b1a1 100644
--- a/chrome/browser/extensions/activity_log/counting_policy.cc
+++ b/chrome/browser/extensions/activity_log/counting_policy.cc
@@ -107,14 +107,21 @@
 static const char kStringTableCleanup[] =
     "DELETE FROM string_ids WHERE id NOT IN\n"
     "(SELECT extension_id_x FROM activitylog_compressed\n"
+    "    WHERE extension_id_x IS NOT NULL\n"
     " UNION SELECT api_name_x FROM activitylog_compressed\n"
+    "    WHERE api_name_x IS NOT NULL\n"
     " UNION SELECT args_x FROM activitylog_compressed\n"
+    "    WHERE args_x IS NOT NULL\n"
     " UNION SELECT page_title_x FROM activitylog_compressed\n"
-    " UNION SELECT other_x FROM activitylog_compressed)";
+    "    WHERE page_title_x IS NOT NULL\n"
+    " UNION SELECT other_x FROM activitylog_compressed\n"
+    "    WHERE other_x IS NOT NULL)";
 static const char kUrlTableCleanup[] =
     "DELETE FROM url_ids WHERE id NOT IN\n"
     "(SELECT page_url_x FROM activitylog_compressed\n"
-    " UNION SELECT arg_url_x FROM activitylog_compressed)";
+    "    WHERE page_url_x IS NOT NULL\n"
+    " UNION SELECT arg_url_x FROM activitylog_compressed\n"
+    "    WHERE arg_url_x IS NOT NULL)";
 
 }  // namespace
 
@@ -128,7 +135,9 @@
                 const base::Time& time,
                 const ActionType action_type,
                 const std::string& api_name)
-      : Action(extension_id, time, action_type, api_name) {}
+      : Action(extension_id, time, action_type, api_name),
+        count_(0) {
+  }
 
   // Number of merged records for this action.
   int count() const { return count_; }
@@ -196,7 +205,27 @@
     action = action->Clone();
     Util::StripPrivacySensitiveFields(action);
     Util::StripArguments(api_arg_whitelist_, action);
-    queued_actions_.push_back(action);
+
+    // If the current action falls on a different date than the ones in the
+    // queue, flush the queue out now to prevent any false merging (actions
+    // from different days being merged).
+    base::Time new_date = action->time().LocalMidnight();
+    if (new_date != queued_actions_date_)
+      activity_database()->AdviseFlush(ActivityDatabase::kFlushImmediately);
+    queued_actions_date_ = new_date;
+
+    ActionQueue::iterator queued_entry = queued_actions_.find(action);
+    if (queued_entry == queued_actions_.end()) {
+      queued_actions_[action] = 1;
+    } else {
+      // Update the timestamp in the key to be the latest time seen.  Modifying
+      // the time is safe since that field is not involved in key comparisons
+      // in the map.
+      using std::max;
+      queued_entry->first->set_time(
+          max(queued_entry->first->time(), action->time()));
+      queued_entry->second++;
+    }
     activity_database()->AdviseFlush(queued_actions_.size());
   }
 }
@@ -206,7 +235,7 @@
   static const char* matched_columns[] = {
       "extension_id_x", "action_type", "api_name_x", "args_x", "page_url_x",
       "page_title_x", "arg_url_x", "other_x"};
-  Action::ActionVector queue;
+  ActionQueue queue;
   queue.swap(queued_actions_);
 
   // Whether to clean old records out of the activity log database.  Do this
@@ -228,7 +257,7 @@
       "INSERT INTO " + std::string(kTableName) + "(count, time";
   std::string update_str =
       "UPDATE " + std::string(kTableName) +
-      " SET count = count + 1, time = max(?, time)"
+      " SET count = count + ?, time = max(?, time)"
       " WHERE time >= ? AND time < ?";
 
   for (size_t i = 0; i < arraysize(matched_columns); i++) {
@@ -237,15 +266,15 @@
     update_str = base::StringPrintf(
         "%s AND %s IS ?", update_str.c_str(), matched_columns[i]);
   }
-  insert_str += ") VALUES (1, ?";
+  insert_str += ") VALUES (?, ?";
   for (size_t i = 0; i < arraysize(matched_columns); i++) {
     insert_str += ", ?";
   }
   insert_str += ")";
 
-  Action::ActionVector::size_type i;
-  for (i = 0; i != queue.size(); ++i) {
-    const Action& action = *queue[i];
+  for (ActionQueue::iterator i = queue.begin(); i != queue.end(); ++i) {
+    const Action& action = *i->first;
+    int count = i->second;
 
     base::Time day_start = action.time().LocalMidnight();
     base::Time next_day = Util::AddDays(day_start, 1);
@@ -320,9 +349,10 @@
     // count.
     sql::Statement update_statement(db->GetCachedStatement(
         sql::StatementID(SQL_FROM_HERE), update_str.c_str()));
-    update_statement.BindInt64(0, action.time().ToInternalValue());
-    update_statement.BindInt64(1, day_start.ToInternalValue());
-    update_statement.BindInt64(2, next_day.ToInternalValue());
+    update_statement.BindInt(0, count);
+    update_statement.BindInt64(1, action.time().ToInternalValue());
+    update_statement.BindInt64(2, day_start.ToInternalValue());
+    update_statement.BindInt64(3, next_day.ToInternalValue());
     for (size_t j = 0; j < matched_values.size(); j++) {
       // A call to BindNull when matched_values contains -1 is likely not
       // necessary as parameters default to null before they are explicitly
@@ -330,9 +360,9 @@
       // ever comes with some values already bound, we bind all parameters
       // (even null ones) explicitly.
       if (matched_values[j] == -1)
-        update_statement.BindNull(j + 3);
+        update_statement.BindNull(j + 4);
       else
-        update_statement.BindInt64(j + 3, matched_values[j]);
+        update_statement.BindInt64(j + 4, matched_values[j]);
     }
     if (!update_statement.Run())
       return false;
@@ -349,12 +379,13 @@
     }
     sql::Statement insert_statement(db->GetCachedStatement(
         sql::StatementID(SQL_FROM_HERE), insert_str.c_str()));
-    insert_statement.BindInt64(0, action.time().ToInternalValue());
+    insert_statement.BindInt(0, count);
+    insert_statement.BindInt64(1, action.time().ToInternalValue());
     for (size_t j = 0; j < matched_values.size(); j++) {
       if (matched_values[j] == -1)
-        insert_statement.BindNull(j + 1);
+        insert_statement.BindNull(j + 2);
       else
-        insert_statement.BindInt64(j + 1, matched_values[j]);
+        insert_statement.BindInt64(j + 2, matched_values[j]);
     }
     if (!insert_statement.Run())
       return false;
diff --git a/chrome/browser/extensions/activity_log/counting_policy.h b/chrome/browser/extensions/activity_log/counting_policy.h
index 5981bca..3911bca 100644
--- a/chrome/browser/extensions/activity_log/counting_policy.h
+++ b/chrome/browser/extensions/activity_log/counting_policy.h
@@ -50,6 +50,12 @@
   virtual void OnDatabaseClose() OVERRIDE;
 
  private:
+  // A type used to track pending writes to the database.  The key is an action
+  // to write; the value is the amount by which the count field should be
+  // incremented in the database.
+  typedef std::map<scoped_refptr<Action>, int, ActionComparatorExcludingTime>
+      ActionQueue;
+
   // Adds an Action to those to be written out; this is an internal method used
   // by ProcessAction and is called on the database thread.
   void QueueAction(scoped_refptr<Action> action);
@@ -78,8 +84,13 @@
 
   // Tracks any pending updates to be written to the database, if write
   // batching is turned on.  Should only be accessed from the database thread.
-  // TODO(mvrable): Do in-memory aggregation as well.
-  Action::ActionVector queued_actions_;
+  ActionQueue queued_actions_;
+
+  // All queued actions must fall on the same day, so that we do not
+  // accidentally aggregate actions that should be kept separate.
+  // queued_actions_date_ is the date (timestamp at local midnight) of all the
+  // actions in queued_actions_.
+  base::Time queued_actions_date_;
 
   // The amount of time old activity log records should be kept in the
   // database.  This time is subtracted from the current time, rounded down to
@@ -92,7 +103,9 @@
   // on the first database flush, and then every 12 hours subsequently.
   base::Time last_database_cleaning_time_;
 
+  friend class CountingPolicyTest;
   FRIEND_TEST_ALL_PREFIXES(CountingPolicyTest, MergingAndExpiring);
+  FRIEND_TEST_ALL_PREFIXES(CountingPolicyTest, StringTableCleaning);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
index 748b528..c7c364e 100644
--- a/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
+++ b/chrome/browser/extensions/activity_log/counting_policy_unittest.cc
@@ -43,8 +43,6 @@
     profile_.reset(new TestingProfile());
     CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnableExtensionActivityLogging);
-    CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kEnableExtensionActivityLogTesting);
     extension_service_ = static_cast<TestExtensionSystem*>(
         ExtensionSystem::Get(profile_.get()))->CreateExtensionService
             (&command_line, base::FilePath(), false);
@@ -61,12 +59,22 @@
     *CommandLine::ForCurrentProcess() = saved_cmdline_;
   }
 
+  // Wait for the task queue for the specified thread to empty.
+  void WaitOnThread(const content::BrowserThread::ID& thread) {
+    BrowserThread::PostTaskAndReply(
+        thread,
+        FROM_HERE,
+        base::Bind(&base::DoNothing),
+        base::MessageLoop::current()->QuitClosure());
+    base::MessageLoop::current()->Run();
+  }
+
   // A helper function to call ReadData on a policy object and wait for the
   // results to be processed.
   void CheckReadData(
       ActivityLogPolicy* policy,
       const std::string& extension_id,
-      const int day,
+      int day,
       const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker) {
     // Submit a request to the policy to read back some data, and call the
     // checker function when results are available.  This will happen on the
@@ -92,6 +100,23 @@
     timeout.Cancel();
   }
 
+  // A helper function which verifies that the string_ids and url_ids tables in
+  // the database have the specified sizes.
+  static void CheckStringTableSizes(CountingPolicy* policy,
+                                    int string_size,
+                                    int url_size) {
+    sql::Connection* db = policy->GetDatabaseConnection();
+    sql::Statement statement1(db->GetCachedStatement(
+        sql::StatementID(SQL_FROM_HERE), "SELECT COUNT(*) FROM string_ids"));
+    ASSERT_TRUE(statement1.Step());
+    ASSERT_EQ(string_size, statement1.ColumnInt(0));
+
+    sql::Statement statement2(db->GetCachedStatement(
+        sql::StatementID(SQL_FROM_HERE), "SELECT COUNT(*) FROM url_ids"));
+    ASSERT_TRUE(statement2.Step());
+    ASSERT_EQ(url_size, statement2.ColumnInt(0));
+  }
+
   static void CheckWrapper(
       const base::Callback<void(scoped_ptr<Action::ActionVector>)>& checker,
       const base::Closure& done,
@@ -154,6 +179,21 @@
     }
   }
 
+  static void Arguments_CheckMergeCountAndTime(
+      int count,
+      const base::Time& time,
+      scoped_ptr<Action::ActionVector> actions) {
+    std::string api_print = base::StringPrintf(
+        "ID=punky CATEGORY=api_call API=brewster COUNT=%d", count);
+    if (count > 0) {
+      ASSERT_EQ(1u, actions->size());
+      ASSERT_EQ(api_print, actions->at(0)->PrintForDebug());
+      ASSERT_EQ(time, actions->at(0)->time());
+    } else {
+      ASSERT_EQ(0u, actions->size());
+    }
+  }
+
  protected:
   ExtensionService* extension_service_;
   scoped_ptr<TestingProfile> profile_;
@@ -404,4 +444,132 @@
   policy->Close();
 }
 
+// Test cleaning of old data in the string and URL tables.
+TEST_F(CountingPolicyTest, StringTableCleaning) {
+  CountingPolicy* policy = new CountingPolicy(profile_.get());
+  // Initially disable expiration by setting a retention time before any
+  // actions we generate.
+  policy->set_retention_time(base::TimeDelta::FromDays(14));
+
+  base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
+  mock_clock->SetNow(base::Time::Now());
+  policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
+
+  // Insert an action; this should create entries in both the string table (for
+  // the extension and API name) and the URL table (for page_url).
+  scoped_refptr<Action> action =
+      new Action("punky",
+                 mock_clock->Now() - base::TimeDelta::FromDays(7),
+                 Action::ACTION_API_CALL,
+                 "brewster");
+  action->set_page_url(GURL("http://www.google.com/"));
+  policy->ProcessAction(action);
+
+  // Add an action which will not be expired, so that some strings will remain
+  // in use.
+  action = new Action(
+      "punky", mock_clock->Now(), Action::ACTION_API_CALL, "tabs.create");
+  policy->ProcessAction(action);
+
+  // There should now be three strings ("punky", "brewster", "tabs.create") and
+  // one URL in the tables.
+  policy->Flush();
+  policy->ScheduleAndForget(policy,
+                            &CountingPolicyTest::CheckStringTableSizes,
+                            3,
+                            1);
+  WaitOnThread(BrowserThread::DB);
+
+  // Trigger a cleaning.  The oldest action is expired when we submit a
+  // duplicate of the newer action.  After this, there should be two strings
+  // and no URLs.
+  policy->set_retention_time(base::TimeDelta::FromDays(2));
+  policy->last_database_cleaning_time_ = base::Time();
+  policy->ProcessAction(action);
+  policy->Flush();
+  policy->ScheduleAndForget(policy,
+                            &CountingPolicyTest::CheckStringTableSizes,
+                            2,
+                            0);
+  WaitOnThread(BrowserThread::DB);
+
+  policy->Close();
+}
+
+// A stress test for memory- and database-based merging of actions.  Submit
+// multiple items, not in chronological order, spanning a few days.  Check that
+// items are merged properly and final timestamps are correct.
+TEST_F(CountingPolicyTest, MoreMerging) {
+  CountingPolicy* policy = new CountingPolicy(profile_.get());
+  policy->set_retention_time(base::TimeDelta::FromDays(14));
+
+  // Use a mock clock to ensure that events are not recorded on the wrong day
+  // when the test is run close to local midnight.
+  base::SimpleTestClock* mock_clock = new base::SimpleTestClock();
+  mock_clock->SetNow(base::Time::Now().LocalMidnight() +
+                    base::TimeDelta::FromHours(12));
+  policy->SetClockForTesting(scoped_ptr<base::Clock>(mock_clock));
+
+  // Create an action 2 days ago, then 1 day ago, then 2 days ago.  Make sure
+  // that we end up with two merged records (one for each day), and each has
+  // the appropriate timestamp.  These merges should happen in the database
+  // since the date keeps changing.
+  base::Time time1 =
+      mock_clock->Now() - base::TimeDelta::FromDays(2) -
+      base::TimeDelta::FromMinutes(40);
+  base::Time time2 =
+      mock_clock->Now() - base::TimeDelta::FromDays(1) -
+      base::TimeDelta::FromMinutes(40);
+  base::Time time3 =
+      mock_clock->Now() - base::TimeDelta::FromDays(2) -
+      base::TimeDelta::FromMinutes(20);
+
+  scoped_refptr<Action> action =
+      new Action("punky", time1, Action::ACTION_API_CALL, "brewster");
+  policy->ProcessAction(action);
+
+  action = new Action("punky", time2, Action::ACTION_API_CALL, "brewster");
+  policy->ProcessAction(action);
+
+  action = new Action("punky", time3, Action::ACTION_API_CALL, "brewster");
+  policy->ProcessAction(action);
+
+  CheckReadData(
+      policy,
+      "punky",
+      2,
+      base::Bind(
+          &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 2, time3));
+  CheckReadData(
+      policy,
+      "punky",
+      1,
+      base::Bind(
+          &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 1, time2));
+
+  // Create three actions today, where the merges should happen in memory.
+  // Again these are not chronological; timestamp time5 should win out since it
+  // is the latest.
+  base::Time time4 = mock_clock->Now() - base::TimeDelta::FromMinutes(60);
+  base::Time time5 = mock_clock->Now() - base::TimeDelta::FromMinutes(20);
+  base::Time time6 = mock_clock->Now() - base::TimeDelta::FromMinutes(40);
+
+  action = new Action("punky", time4, Action::ACTION_API_CALL, "brewster");
+  policy->ProcessAction(action);
+
+  action = new Action("punky", time5, Action::ACTION_API_CALL, "brewster");
+  policy->ProcessAction(action);
+
+  action = new Action("punky", time6, Action::ACTION_API_CALL, "brewster");
+  policy->ProcessAction(action);
+
+  CheckReadData(
+      policy,
+      "punky",
+      0,
+      base::Bind(
+          &CountingPolicyTest::Arguments_CheckMergeCountAndTime, 3, time5));
+  policy->Close();
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/ad_view_browsertest.cc b/chrome/browser/extensions/ad_view_browsertest.cc
deleted file mode 100644
index 4982cb2..0000000
--- a/chrome/browser/extensions/ad_view_browsertest.cc
+++ /dev/null
@@ -1,168 +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/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
-#include "chrome/common/chrome_switches.h"
-#include "content/test/net/url_request_prepackaged_interceptor.h"
-#include "net/url_request/url_fetcher.h"
-
-class AdViewTest : public extensions::PlatformAppBrowserTest {
- protected:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kEnableAdview);
-    command_line->AppendSwitch(switches::kEnableAdviewSrcAttribute);
-  }
-};
-
-// This test checks the "loadcommit" event is called when the page inside an
-// <adview> is loaded.
-IN_PROC_BROWSER_TEST_F(AdViewTest, LoadCommitEventIsCalled) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/loadcommit_event")) << message_;
-}
-
-// This test checks the "loadabort" event is called when the "src" attribute
-// of an <adview> is an invalid URL.
-IN_PROC_BROWSER_TEST_F(AdViewTest, LoadAbortEventIsCalled) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/loadabort_event")) << message_;
-}
-
-// This test checks the page loaded inside an <adview> has the ability to
-// 1) receive "message" events from the application, and 2) use
-// "window.postMessage" to post back a message to the application.
-#if defined(OS_WIN)
-// Flaky, or takes too long time on Win7. (http://crbug.com/230271)
-#define MAYBE_CommitMessageFromAdNetwork DISABLED_CommitMessageFromAdNetwork
-#else
-#define MAYBE_CommitMessageFromAdNetwork CommitMessageFromAdNetwork
-#endif
-IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_CommitMessageFromAdNetwork) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/onloadcommit_ack")) << message_;
-}
-
-// This test checks the page running inside an <adview> has the ability to load
-// and display an image inside an <iframe>.
-// Note: Disabled for initial checkin because the test depends on a binary
-//       file (image035.png) which the trybots don't process correctly when
-//       first checked-in.
-IN_PROC_BROWSER_TEST_F(AdViewTest, DISABLED_DisplayFirstAd) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/display_first_ad")) << message_;
-}
-
-// This test checks that <adview> attributes are also exposed as properties
-// (with the same name and value).
-#if defined(OS_WIN)
-// Flaky on Win XP. (http://crbug.com/264362)
-#define MAYBE_PropertiesAreInSyncWithAttributes \
-    DISABLED_PropertiesAreInSyncWithAttributes
-#else
-#define MAYBE_PropertiesAreInSyncWithAttributes \
-    PropertiesAreInSyncWithAttributes
-#endif
-IN_PROC_BROWSER_TEST_F(AdViewTest, MAYBE_PropertiesAreInSyncWithAttributes) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/properties_exposed")) << message_;
-}
-
-// This test checks an <adview> element has no behavior when the "adview"
-// permission is missing from the application manifest.
-IN_PROC_BROWSER_TEST_F(AdViewTest, AdViewPermissionIsRequired) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/permission_required")) << message_;
-}
-
-// This test checks that 1) it is possible change the value of the "ad-network"
-// attribute of an <adview> element and 2) changing the value will reset the
-// "src" attribute.
-// Broken test: http://crbug.com/257465.
-IN_PROC_BROWSER_TEST_F(AdViewTest, DISABLED_ChangeAdNetworkValue) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/change_ad_network")) << message_;
-}
-
-class AdViewNoSrcTest : public extensions::PlatformAppBrowserTest {
- protected:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kEnableAdview);
-    //Note: The "kEnableAdviewSrcAttribute" flag is not here!
-  }
-};
-
-// This test checks an invalid "ad-network" value (i.e. not whitelisted)
-// is ignored.
-IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, InvalidAdNetworkIsIgnored) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/invalid_ad_network")) << message_;
-}
-
-// This test checks the "src" attribute is ignored when the
-// "kEnableAdviewSrcAttribute" is missing.
-IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, EnableAdviewSrcAttributeFlagRequired) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/src_flag_required")) << message_;
-}
-
-// This test checks 1) an <adview> works end-to-end (i.e. page is loaded) when
-// using a whitelisted ad-network, and 2) the "src" attribute is never exposed
-// to the application.
-IN_PROC_BROWSER_TEST_F(AdViewNoSrcTest, SrcNotExposed) {
-  base::FilePath file_path = test_data_dir_
-    .AppendASCII("platform_apps")
-    .AppendASCII("ad_view/src_not_exposed")
-    .AppendASCII("ad_network_fake_website.html");
-
-  // Note: The following URL is identical to the whitelisted url
-  //       for "admob" (see ad_view.js).
-  GURL url = GURL("https://admob-sdk.doubleclick.net/chromeapps");
-  std::string scheme = url.scheme();
-  std::string hostname = url.host();
-
-  content::URLRequestPrepackagedInterceptor interceptor(scheme, hostname);
-  interceptor.SetResponse(url, file_path);
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/src_not_exposed")) << message_;
-  ASSERT_EQ(1, interceptor.GetHitCount());
-}
-
-class AdViewNotEnabledTest : public extensions::PlatformAppBrowserTest {
- protected:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
-    //Note: The "kEnableAdview" flag is not here!
-  }
-};
-
-// This test checks an <adview> element has no behavior when the "kEnableAdview"
-// flag is missing.
-IN_PROC_BROWSER_TEST_F(AdViewNotEnabledTest, EnableAdviewFlagRequired) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/ad_view/flag_required")) << message_;
-}
diff --git a/chrome/browser/extensions/admin_policy.cc b/chrome/browser/extensions/admin_policy.cc
index 608fdea..0f1e95c 100644
--- a/chrome/browser/extensions/admin_policy.cc
+++ b/chrome/browser/extensions/admin_policy.cc
@@ -6,7 +6,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -116,5 +116,5 @@
   return ManagementPolicyImpl(extension, error, false);
 }
 
-}  // namespace
-}  // namespace
+}  // namespace admin_policy
+}  // namespace extensions
diff --git a/chrome/browser/extensions/admin_policy_unittest.cc b/chrome/browser/extensions/admin_policy_unittest.cc
index 3818cc6..6774f20 100644
--- a/chrome/browser/extensions/admin_policy_unittest.cc
+++ b/chrome/browser/extensions/admin_policy_unittest.cc
@@ -6,8 +6,8 @@
 
 #include "base/values.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::Value;
@@ -25,16 +25,16 @@
 
   void CreateHostedApp(Manifest::Location location) {
     base::DictionaryValue values;
-    values.Set(extension_manifest_keys::kWebURLs, new base::ListValue());
-    values.SetString(extension_manifest_keys::kLaunchWebURL,
+    values.Set(extensions::manifest_keys::kWebURLs, new base::ListValue());
+    values.SetString(extensions::manifest_keys::kLaunchWebURL,
                      "http://www.example.com");
     CreateExtensionFromValues(location, &values);
   }
 
   void CreateExtensionFromValues(Manifest::Location location,
                                  base::DictionaryValue* values) {
-    values->SetString(extension_manifest_keys::kName, "test");
-    values->SetString(extension_manifest_keys::kVersion, "0.1");
+    values->SetString(extensions::manifest_keys::kName, "test");
+    values->SetString(extensions::manifest_keys::kVersion, "0.1");
     std::string error;
     extension_ = Extension::Create(base::FilePath(), location, *values,
                                    Extension::NO_FLAGS, &error);
@@ -50,13 +50,13 @@
   EXPECT_FALSE(ap::BlacklistedByDefault(NULL));
 
   base::ListValue blacklist;
-  blacklist.Append(Value::CreateStringValue("http://www.google.com"));
+  blacklist.Append(new base::StringValue("http://www.google.com"));
   EXPECT_FALSE(ap::BlacklistedByDefault(&blacklist));
-  blacklist.Append(Value::CreateStringValue("*"));
+  blacklist.Append(new base::StringValue("*"));
   EXPECT_TRUE(ap::BlacklistedByDefault(&blacklist));
 
   blacklist.Clear();
-  blacklist.Append(Value::CreateStringValue("*"));
+  blacklist.Append(new base::StringValue("*"));
   EXPECT_TRUE(ap::BlacklistedByDefault(&blacklist));
 }
 
@@ -71,11 +71,11 @@
 
   // Required extensions may load even if they're on the blacklist.
   base::ListValue blacklist;
-  blacklist.Append(Value::CreateStringValue(extension_->id()));
+  blacklist.Append(new base::StringValue(extension_->id()));
   EXPECT_TRUE(ap::UserMayLoad(&blacklist, NULL, NULL, NULL, extension_.get(),
                               NULL));
 
-  blacklist.Append(Value::CreateStringValue("*"));
+  blacklist.Append(new base::StringValue("*"));
   EXPECT_TRUE(ap::UserMayLoad(&blacklist, NULL, NULL, NULL, extension_.get(),
                               NULL));
 }
@@ -98,12 +98,12 @@
   CreateExtension(Manifest::INTERNAL);
 
   base::ListValue whitelist;
-  whitelist.Append(Value::CreateStringValue(extension_->id()));
+  whitelist.Append(new base::StringValue(extension_->id()));
   EXPECT_TRUE(ap::UserMayLoad(NULL, &whitelist, NULL, NULL, extension_.get(),
                               NULL));
 
   base::ListValue blacklist;
-  blacklist.Append(Value::CreateStringValue(extension_->id()));
+  blacklist.Append(new base::StringValue(extension_->id()));
   EXPECT_TRUE(ap::UserMayLoad(NULL, &whitelist, NULL, NULL, extension_.get(),
                               NULL));
   string16 error;
@@ -118,7 +118,7 @@
 
   // Blacklisted by default.
   base::ListValue blacklist;
-  blacklist.Append(Value::CreateStringValue("*"));
+  blacklist.Append(new base::StringValue("*"));
   EXPECT_FALSE(ap::UserMayLoad(&blacklist, NULL, NULL, NULL, extension_.get(),
                                NULL));
   string16 error;
@@ -127,21 +127,21 @@
   EXPECT_FALSE(error.empty());
 
   // Extension on the blacklist, with and without wildcard.
-  blacklist.Append(Value::CreateStringValue(extension_->id()));
+  blacklist.Append(new base::StringValue(extension_->id()));
   EXPECT_FALSE(ap::UserMayLoad(&blacklist, NULL, NULL, NULL, extension_.get(),
                                NULL));
   blacklist.Clear();
-  blacklist.Append(Value::CreateStringValue(extension_->id()));
+  blacklist.Append(new base::StringValue(extension_->id()));
   EXPECT_FALSE(ap::UserMayLoad(&blacklist, NULL, NULL, NULL, extension_.get(),
                                NULL));
 
   // With a whitelist. There's no such thing as a whitelist wildcard.
   base::ListValue whitelist;
   whitelist.Append(
-      Value::CreateStringValue("behllobkkfkfnphdnhnkndlbkcpglgmj"));
+      new base::StringValue("behllobkkfkfnphdnhnkndlbkcpglgmj"));
   EXPECT_FALSE(ap::UserMayLoad(&blacklist, &whitelist, NULL, NULL,
                                extension_.get(), NULL));
-  whitelist.Append(Value::CreateStringValue("*"));
+  whitelist.Append(new base::StringValue("*"));
   EXPECT_FALSE(ap::UserMayLoad(&blacklist, &whitelist, NULL, NULL,
                                extension_.get(), NULL));
 }
diff --git a/chrome/browser/extensions/api/DEPS b/chrome/browser/extensions/api/DEPS
index 6d699a6..d3338bd 100644
--- a/chrome/browser/extensions/api/DEPS
+++ b/chrome/browser/extensions/api/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+apps",
+  "+chrome/browser/apps",
 ]
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 d9e03fb..f2e18eb 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
@@ -18,11 +18,12 @@
 
 namespace extensions {
 
+namespace activity_log_private = api::activity_log_private;
+
 using api::activity_log_private::ExtensionActivity;
 
 const char kActivityLogExtensionId[] = "acldcpdepobcjbdanifkmfndkjoilgba";
 const char kActivityLogTestExtensionId[] = "ajabfgledjhbabeoojlabelaifmakodf";
-const char kNewActivityEventName[] = "activityLogPrivate.onExtensionActivity";
 
 static base::LazyInstance<ProfileKeyedAPIFactory<ActivityLogAPI> >
     g_factory = LAZY_INSTANCE_INITIALIZER;
@@ -48,7 +49,7 @@
   activity_log_ = extensions::ActivityLog::GetInstance(profile_);
   DCHECK(activity_log_);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, kNewActivityEventName);
+      this, activity_log_private::OnExtensionActivity::kEventName);
   activity_log_->AddObserver(this);
   initialized_ = true;
 }
@@ -84,7 +85,9 @@
   scoped_ptr<ExtensionActivity> activity_arg =
       activity->ConvertToExtensionActivity();
   value->Append(activity_arg->ToValue().release());
-  scoped_ptr<Event> event(new Event(kNewActivityEventName, value.Pass()));
+  scoped_ptr<Event> event(
+      new Event(activity_log_private::OnExtensionActivity::kEventName,
+          value.Pass()));
   event->restrict_to_profile = profile_;
   ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
 }
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 ea74c1f..cab0ccf 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
@@ -24,7 +24,6 @@
 // The ID of the trusted/whitelisted ActivityLog extension.
 extern const char kActivityLogExtensionId[];
 extern const char kActivityLogTestExtensionId[];
-extern const char kNewActivityEventName[];
 
 // Handles interactions between the Activity Log API and implementation.
 class ActivityLogAPI : public ProfileKeyedAPI,
diff --git a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
index 1431259..17f75ad 100644
--- a/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/activity_log_private/activity_log_private_api_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/activity_log/activity_action_constants.h"
 #include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -13,98 +14,52 @@
 
 const char kExtensionId[] = "extensionid";
 const char kApiCall[] = "api.call";
-const char kArgs[] = "1, 2";
-const char kExtra[] = "extra";
+const char kArgs[] = "[\"hello\",\"world\"]";
 
 }  // extensions
 
 namespace extensions {
 
-using api::activity_log_private::BlockedChromeActivityDetail;
-using api::activity_log_private::ChromeActivityDetail;
-using api::activity_log_private::DomActivityDetail;
 using api::activity_log_private::ExtensionActivity;
 
-class ActivityLogApiUnitTest : public testing::Test {
-};
-
-// TODO(felt): These are the old unit tests from before the activity log Action
-// class and database refactoring.  These need to be updated, but since the
-// private API will be reworked anyway these are just disabled for now.
-#if 0
-TEST_F(ActivityLogApiUnitTest, ConvertBlockedAction) {
-  scoped_refptr<Action> action(
-      new BlockedAction(kExtensionId,
-                        base::Time::Now(),
-                        kApiCall,
-                        kArgs,
-                        BlockedAction::ACCESS_DENIED,
-                        kExtra));
-  scoped_ptr<ExtensionActivity> result =
-      action->ConvertToExtensionActivity();
-  ASSERT_EQ(ExtensionActivity::ACTIVITY_TYPE_BLOCKED_CHROME,
-            result->activity_type);
-  ASSERT_EQ(kExtensionId, *(result->extension_id.get()));
-  ASSERT_EQ(kApiCall,
-            *(result->blocked_chrome_activity_detail->api_call.get()));
-  ASSERT_EQ(kArgs,
-            *(result->blocked_chrome_activity_detail->args.get()));
-  ASSERT_EQ(BlockedChromeActivityDetail::REASON_ACCESS_DENIED,
-            result->blocked_chrome_activity_detail->reason);
-  ASSERT_EQ(kExtra,
-            *(result->blocked_chrome_activity_detail->extra.get()));
-}
+typedef testing::Test ActivityLogApiUnitTest;
 
 TEST_F(ActivityLogApiUnitTest, ConvertChromeApiAction) {
-  scoped_refptr<Action> action(
-    new APIAction(kExtensionId,
-                  base::Time::Now(),
-                  APIAction::CALL,
-                  kApiCall,
-                  kArgs,
-                  base::ListValue(),
-                  kExtra));
-  scoped_ptr<ExtensionActivity> result =
-      action->ConvertToExtensionActivity();
-  ASSERT_EQ(ExtensionActivity::ACTIVITY_TYPE_CHROME,
-            result->activity_type);
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  args->Set(0, new base::StringValue("hello"));
+  args->Set(1, new base::StringValue("world"));
+  scoped_refptr<Action> action(new Action(kExtensionId,
+                                          base::Time::Now(),
+                                          Action::ACTION_API_CALL,
+                                          kApiCall));
+  action->set_args(args.Pass());
+  scoped_ptr<ExtensionActivity> result = action->ConvertToExtensionActivity();
+  ASSERT_EQ(ExtensionActivity::ACTIVITY_TYPE_API_CALL, result->activity_type);
   ASSERT_EQ(kExtensionId, *(result->extension_id.get()));
-  ASSERT_EQ(ChromeActivityDetail::API_ACTIVITY_TYPE_CALL,
-            result->chrome_activity_detail->api_activity_type);
-  ASSERT_EQ(kApiCall,
-            *(result->chrome_activity_detail->api_call.get()));
-  ASSERT_EQ(kArgs,
-            *(result->chrome_activity_detail->args.get()));
-  ASSERT_EQ(kExtra,
-            *(result->chrome_activity_detail->extra.get()));
+  ASSERT_EQ(kApiCall, *(result->api_call.get()));
+  ASSERT_EQ(kArgs, *(result->args.get()));
 }
 
 TEST_F(ActivityLogApiUnitTest, ConvertDomAction) {
-  scoped_refptr<Action> action(
-      new DOMAction(kExtensionId,
-                    base::Time::Now(),
-                    DomActionType::SETTER,
-                    GURL("http://www.google.com"),
-                    base::ASCIIToUTF16("Title"),
-                    kApiCall,
-                    kArgs,
-                    kExtra));
-  scoped_ptr<ExtensionActivity> result =
-      action->ConvertToExtensionActivity();
-  ASSERT_EQ(ExtensionActivity::ACTIVITY_TYPE_DOM, result->activity_type);
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  args->Set(0, new base::StringValue("hello"));
+  args->Set(1, new base::StringValue("world"));
+  scoped_refptr<Action> action(new Action(kExtensionId,
+                               base::Time::Now(),
+                               Action::ACTION_DOM_ACCESS,
+                               kApiCall));
+  action->set_args(args.Pass());
+  action->set_page_url(GURL("http://www.google.com"));
+  action->set_page_title("Title");
+  action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb,
+                                      DomActionType::INSERTED);
+  scoped_ptr<ExtensionActivity> result = action->ConvertToExtensionActivity();
   ASSERT_EQ(kExtensionId, *(result->extension_id.get()));
-  ASSERT_EQ(DomActivityDetail::DOM_ACTIVITY_TYPE_SETTER,
-            result->dom_activity_detail->dom_activity_type);
-  ASSERT_EQ("http://www.google.com/",
-            *(result->dom_activity_detail->url.get()));
-  ASSERT_EQ("Title", *(result->dom_activity_detail->url_title.get()));
-  ASSERT_EQ(kApiCall,
-            *(result->dom_activity_detail->api_call.get()));
-  ASSERT_EQ(kArgs,
-            *(result->dom_activity_detail->args.get()));
-  ASSERT_EQ(kExtra,
-            *(result->dom_activity_detail->extra.get()));
+  ASSERT_EQ("http://www.google.com/", *(result->page_url.get()));
+  ASSERT_EQ("Title", *(result->page_title.get()));
+  ASSERT_EQ(kApiCall, *(result->api_call.get()));
+  ASSERT_EQ(kArgs, *(result->args.get()));
+  ASSERT_EQ("{\"dom_verb\":3}", *(result->extra.get()));
 }
-#endif
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/alarms/OWNERS b/chrome/browser/extensions/api/alarms/OWNERS
new file mode 100644
index 0000000..39cb68c
--- /dev/null
+++ b/chrome/browser/extensions/api/alarms/OWNERS
@@ -0,0 +1 @@
+mpcomplete@chromium.org
diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.cc b/chrome/browser/extensions/api/alarms/alarm_manager.cc
index 5e5894c..358fb3d 100644
--- a/chrome/browser/extensions/api/alarms/alarm_manager.cc
+++ b/chrome/browser/extensions/api/alarms/alarm_manager.cc
@@ -19,13 +19,14 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/state_store.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/alarms.h"
 #include "content/public/browser/notification_service.h"
 
 namespace extensions {
 
-namespace {
+namespace alarms = api::alarms;
 
-const char kOnAlarmEvent[] = "alarms.onAlarm";
+namespace {
 
 // A list of alarms that this extension has set.
 const char kRegisteredAlarms[] = "alarms";
@@ -43,7 +44,8 @@
                        const Alarm& alarm) OVERRIDE {
     scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(alarm.js_alarm->ToValue().release());
-    scoped_ptr<Event> event(new Event(kOnAlarmEvent, args.Pass()));
+    scoped_ptr<Event> event(new Event(alarms::OnAlarm::kEventName,
+                                      args.Pass()));
     ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
         extension_id, event.Pass());
   }
@@ -109,25 +111,86 @@
 }
 
 void AlarmManager::AddAlarm(const std::string& extension_id,
-                            const Alarm& alarm) {
+                            const Alarm& alarm,
+                            const AddAlarmCallback& callback) {
+  RunWhenReady(extension_id, base::Bind(
+      &AlarmManager::AddAlarmWhenReady, AsWeakPtr(), alarm, callback));
+}
+
+void AlarmManager::GetAlarm(const std::string& extension_id,
+                            const std::string& name,
+                            const GetAlarmCallback& callback) {
+  RunWhenReady(extension_id, base::Bind(
+      &AlarmManager::GetAlarmWhenReady, AsWeakPtr(), name, callback));
+}
+
+void AlarmManager::GetAllAlarms(
+    const std::string& extension_id, const GetAllAlarmsCallback& callback) {
+  RunWhenReady(extension_id, base::Bind(
+      &AlarmManager::GetAllAlarmsWhenReady, AsWeakPtr(), callback));
+}
+
+void AlarmManager::RemoveAlarm(const std::string& extension_id,
+                               const std::string& name,
+                               const RemoveAlarmCallback& callback) {
+  RunWhenReady(extension_id, base::Bind(
+      &AlarmManager::RemoveAlarmWhenReady, AsWeakPtr(), name, callback));
+}
+
+void AlarmManager::RemoveAllAlarms(const std::string& extension_id,
+                                   const RemoveAllAlarmsCallback& callback) {
+  RunWhenReady(extension_id, base::Bind(
+      &AlarmManager::RemoveAllAlarmsWhenReady, AsWeakPtr(), callback));
+}
+
+void AlarmManager::AddAlarmWhenReady(const Alarm& alarm,
+                                     const AddAlarmCallback& callback,
+                                     const std::string& extension_id) {
   AddAlarmImpl(extension_id, alarm);
   WriteToStorage(extension_id);
+  callback.Run();
 }
 
-const Alarm* AlarmManager::GetAlarm(
-    const std::string& extension_id, const std::string& name) {
+void AlarmManager::GetAlarmWhenReady(const std::string& name,
+                                     const GetAlarmCallback& callback,
+                                     const std::string& extension_id) {
   AlarmIterator it = GetAlarmIterator(extension_id, name);
-  if (it.first == alarms_.end())
-    return NULL;
-  return &*it.second;
+  callback.Run(it.first != alarms_.end() ? &*it.second : NULL);
 }
 
-const AlarmManager::AlarmList* AlarmManager::GetAllAlarms(
-    const std::string& extension_id) {
+void AlarmManager::GetAllAlarmsWhenReady(const GetAllAlarmsCallback& callback,
+                                         const std::string& extension_id) {
   AlarmMap::iterator list = alarms_.find(extension_id);
-  if (list == alarms_.end())
-    return NULL;
-  return &list->second;
+  callback.Run(list != alarms_.end() ? &list->second : NULL);
+}
+
+void AlarmManager::RemoveAlarmWhenReady(const std::string& name,
+                                        const RemoveAlarmCallback& callback,
+                                        const std::string& extension_id) {
+  AlarmIterator it = GetAlarmIterator(extension_id, name);
+  if (it.first == alarms_.end()) {
+    callback.Run(false);
+    return;
+  }
+
+  RemoveAlarmIterator(it);
+  WriteToStorage(extension_id);
+  callback.Run(true);
+}
+
+void AlarmManager::RemoveAllAlarmsWhenReady(
+    const RemoveAllAlarmsCallback& callback, const std::string& extension_id) {
+  AlarmMap::iterator list = alarms_.find(extension_id);
+  if (list != alarms_.end()) {
+    // Note: I'm using indices rather than iterators here because
+    // RemoveAlarmIterator will delete the list when it becomes empty.
+    for (size_t i = 0, size = list->second.size(); i < size; ++i)
+      RemoveAlarmIterator(AlarmIterator(list, list->second.begin()));
+
+    CHECK(alarms_.find(extension_id) == alarms_.end());
+    WriteToStorage(extension_id);
+  }
+  callback.Run();
 }
 
 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator(
@@ -145,31 +208,6 @@
   return make_pair(alarms_.end(), AlarmList::iterator());
 }
 
-bool AlarmManager::RemoveAlarm(const std::string& extension_id,
-                               const std::string& name) {
-  AlarmIterator it = GetAlarmIterator(extension_id, name);
-  if (it.first == alarms_.end())
-    return false;
-
-  RemoveAlarmIterator(it);
-  WriteToStorage(extension_id);
-  return true;
-}
-
-void AlarmManager::RemoveAllAlarms(const std::string& extension_id) {
-  AlarmMap::iterator list = alarms_.find(extension_id);
-  if (list == alarms_.end())
-    return;
-
-  // Note: I'm using indices rather than iterators here because
-  // RemoveAlarmIterator will delete the list when it becomes empty.
-  for (size_t i = 0, size = list->second.size(); i < size; ++i)
-    RemoveAlarmIterator(AlarmIterator(list, list->second.begin()));
-
-  CHECK(alarms_.find(extension_id) == alarms_.end());
-  WriteToStorage(extension_id);
-}
-
 void AlarmManager::SetClockForTesting(base::Clock* clock) {
   clock_.reset(clock);
 }
@@ -248,17 +286,22 @@
 void AlarmManager::ReadFromStorage(const std::string& extension_id,
                                    scoped_ptr<base::Value> value) {
   base::ListValue* list = NULL;
-  if (!value.get() || !value->GetAsList(&list))
-    return;
-
-  std::vector<Alarm> alarm_states = AlarmsFromValue(list);
-  for (size_t i = 0; i < alarm_states.size(); ++i) {
-    AddAlarmImpl(extension_id, alarm_states[i]);
+  if (value.get() && value->GetAsList(&list)) {
+    std::vector<Alarm> alarm_states = AlarmsFromValue(list);
+    for (size_t i = 0; i < alarm_states.size(); ++i)
+      AddAlarmImpl(extension_id, alarm_states[i]);
   }
+
+  ReadyQueue& extension_ready_queue = ready_actions_[extension_id];
+  while (!extension_ready_queue.empty()) {
+    extension_ready_queue.front().Run(extension_id);
+    extension_ready_queue.pop();
+  }
+  ready_actions_.erase(extension_id);
 }
 
 void AlarmManager::ScheduleNextPoll() {
-  // 0. If there are no alarms, stop the timer.
+  // If there are no alarms, stop the timer.
   if (alarms_.empty()) {
     timer_.Stop();
     return;
@@ -283,6 +326,11 @@
         soonest_alarm_time = cur_alarm_time;
       if (l_it->granularity < min_granularity)
         min_granularity = l_it->granularity;
+      base::TimeDelta cur_alarm_delta = cur_alarm_time - clock_->Now();
+      if (cur_alarm_delta < min_granularity)
+        min_granularity = cur_alarm_delta;
+      if (min_granularity < l_it->minimum_granularity)
+        min_granularity = l_it->minimum_granularity;
     }
   }
 
@@ -295,7 +343,7 @@
     next_poll = soonest_alarm_time;
 
   // Schedule the poll.
-  next_poll_time_ = next_poll;
+  test_next_poll_time_ = next_poll;
   base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0),
                                    next_poll - clock_->Now());
   timer_.Start(FROM_HERE,
@@ -321,7 +369,7 @@
     for (size_t i = cur_extension->second.size(); i > 0; --i) {
       AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1;
       if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <=
-          next_poll_time_) {
+          last_poll_time_) {
         OnAlarm(make_pair(cur_extension, cur_alarm));
       }
     }
@@ -330,6 +378,18 @@
   ScheduleNextPoll();
 }
 
+static void RemoveAllOnUninstallCallback() {}
+
+void AlarmManager::RunWhenReady(
+    const std::string& extension_id, const ReadyAction& action) {
+  ReadyMap::iterator it = ready_actions_.find(extension_id);
+
+  if (it == ready_actions_.end())
+    action.Run(extension_id);
+  else
+    it->second.push(action);
+}
+
 void AlarmManager::Observe(
     int type,
     const content::NotificationSource& source,
@@ -340,6 +400,8 @@
           content::Details<const Extension>(details).ptr();
       StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
       if (storage) {
+        ready_actions_.insert(
+            ReadyMap::value_type(extension->id(), ReadyQueue()));
         storage->GetExtensionValue(extension->id(), kRegisteredAlarms,
             base::Bind(&AlarmManager::ReadFromStorage,
                        AsWeakPtr(), extension->id()));
@@ -349,7 +411,8 @@
     case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
       const Extension* extension =
           content::Details<const Extension>(details).ptr();
-      RemoveAllAlarms(extension->id());
+      RemoveAllAlarms(
+          extension->id(), base::Bind(RemoveAllOnUninstallCallback));
       break;
     }
     default:
@@ -370,6 +433,7 @@
              base::Time now)
     : js_alarm(new api::alarms::Alarm()) {
   js_alarm->name = name;
+  minimum_granularity = min_granularity;
 
   if (create_info.when.get()) {
     // Absolute scheduling.
diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.h b/chrome/browser/extensions/api/alarms/alarm_manager.h
index 66ebfc8..b68fe56 100644
--- a/chrome/browser/extensions/api/alarms/alarm_manager.h
+++ b/chrome/browser/extensions/api/alarms/alarm_manager.h
@@ -6,9 +6,11 @@
 #define CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARM_MANAGER_H__
 
 #include <map>
+#include <queue>
 #include <string>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
@@ -42,6 +44,9 @@
   // time.  This will always be at least as large as the min_granularity
   // constructor argument.
   base::TimeDelta granularity;
+  // The minimum granularity is the minimum allowed polling rate. This stops
+  // alarms from polling too often.
+  base::TimeDelta minimum_granularity;
 };
 
 // Manages the currently pending alarms for every extension in a profile.
@@ -67,24 +72,38 @@
   // Override the default delegate. Callee assumes onwership. Used for testing.
   void set_delegate(Delegate* delegate) { delegate_.reset(delegate); }
 
-  // Adds |alarm| for the given extension, and starts the timer.
+  typedef base::Callback<void()> AddAlarmCallback;
+  // Adds |alarm| for the given extension, and starts the timer. Invokes
+  // |callback| when done.
   void AddAlarm(const std::string& extension_id,
-                const Alarm& alarm);
+                const Alarm& alarm,
+                const AddAlarmCallback& callback);
 
-  // Returns the alarm with the given name, or NULL if none exists.
-  const Alarm* GetAlarm(const std::string& extension_id,
-                        const std::string& name);
+  typedef base::Callback<void(Alarm*)> GetAlarmCallback;
+  // Passes the alarm with the given name, or NULL if none exists, to
+  // |callback|.
+  void GetAlarm(const std::string& extension_id,
+                const std::string& name,
+                const GetAlarmCallback& callback);
 
-  // Returns the list of pending alarms for the given extension, or NULL
-  // if none exist.
-  const AlarmList* GetAllAlarms(const std::string& extension_id);
+  typedef base::Callback<void(const AlarmList*)> GetAllAlarmsCallback;
+  // Passes the list of pending alarms for the given extension, or
+  // NULL if none exist, to |callback|.
+  void GetAllAlarms(
+      const std::string& extension_id, const GetAllAlarmsCallback& callback);
 
-  // Cancels and removes the alarm with the given name.
-  bool RemoveAlarm(const std::string& extension_id,
-                   const std::string& name);
+  typedef base::Callback<void(bool)> RemoveAlarmCallback;
+  // Cancels and removes the alarm with the given name. Invokes |callback| when
+  // done.
+  void RemoveAlarm(const std::string& extension_id,
+                   const std::string& name,
+                   const RemoveAlarmCallback& callback);
 
-  // Cancels and removes all alarms for the given extension.
-  void RemoveAllAlarms(const std::string& extension_id);
+  typedef base::Callback<void()> RemoveAllAlarmsCallback;
+  // Cancels and removes all alarms for the given extension. Invokes |callback|
+  // when done.
+  void RemoveAllAlarms(
+      const std::string& extension_id, const RemoveAllAlarmsCallback& callback);
 
   // Replaces AlarmManager's owned clock with |clock| and takes ownership of it.
   void SetClockForTesting(base::Clock* clock);
@@ -96,22 +115,49 @@
   static AlarmManager* Get(Profile* profile);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(ExtensionAlarmsTest, CreateRepeating);
-  FRIEND_TEST_ALL_PREFIXES(ExtensionAlarmsTest, Clear);
+  friend void RunScheduleNextPoll(AlarmManager*);
   friend class ExtensionAlarmsSchedulingTest;
   FRIEND_TEST_ALL_PREFIXES(ExtensionAlarmsSchedulingTest, PollScheduling);
   FRIEND_TEST_ALL_PREFIXES(ExtensionAlarmsSchedulingTest,
                            ReleasedExtensionPollsInfrequently);
   FRIEND_TEST_ALL_PREFIXES(ExtensionAlarmsSchedulingTest, TimerRunning);
+  FRIEND_TEST_ALL_PREFIXES(ExtensionAlarmsSchedulingTest, MinimumGranularity);
   friend class ProfileKeyedAPIFactory<AlarmManager>;
 
   typedef std::string ExtensionId;
   typedef std::map<ExtensionId, AlarmList> AlarmMap;
 
+  typedef base::Callback<void(const std::string&)> ReadyAction;
+  typedef std::queue<ReadyAction> ReadyQueue;
+  typedef std::map<ExtensionId, ReadyQueue> ReadyMap;
+
   // Iterator used to identify a particular alarm within the Map/List pair.
   // "Not found" is represented by <alarms_.end(), invalid_iterator>.
   typedef std::pair<AlarmMap::iterator, AlarmList::iterator> AlarmIterator;
 
+  // Part of AddAlarm that is executed after alarms are loaded.
+  void AddAlarmWhenReady(const Alarm& alarm,
+                         const AddAlarmCallback& callback,
+                         const std::string& extension_id);
+
+  // Part of GetAlarm that is executed after alarms are loaded.
+  void GetAlarmWhenReady(const std::string& name,
+                         const GetAlarmCallback& callback,
+                         const std::string& extension_id);
+
+  // Part of GetAllAlarms that is executed after alarms are loaded.
+  void GetAllAlarmsWhenReady(const GetAllAlarmsCallback& callback,
+                             const std::string& extension_id);
+
+  // Part of RemoveAlarm that is executed after alarms are loaded.
+  void RemoveAlarmWhenReady(const std::string& name,
+                            const RemoveAlarmCallback& callback,
+                            const std::string& extension_id);
+
+  // Part of RemoveAllAlarms that is executed after alarms are loaded.
+  void RemoveAllAlarmsWhenReady(
+      const RemoveAllAlarmsCallback& callback, const std::string& extension_id);
+
   // Helper to return the iterators within the AlarmMap and AlarmList for the
   // matching alarm, or an iterator to the end of the AlarmMap if none were
   // found.
@@ -142,6 +188,10 @@
   // rescheduling repeating alarms, schedule the next poll.
   void PollAlarms();
 
+  // Executes |action| for given extension, making sure that the extension's
+  // alarm data has been synced from the storage.
+  void RunWhenReady(const std::string& extension_id, const ReadyAction& action);
+
   // NotificationObserver:
   virtual void Observe(int type,
                        const content::NotificationSource& source,
@@ -165,9 +215,15 @@
   // Invariant: None of the AlarmLists are empty.
   AlarmMap alarms_;
 
-  // The previous and next time that alarms were and will be run.
+  // A map of actions waiting for alarm data to be synced from storage, per
+  // extension.
+  ReadyMap ready_actions_;
+
+  // The previous time that alarms were run.
   base::Time last_poll_time_;
-  base::Time next_poll_time_;
+
+  // Next poll's time. Used only by unit tests.
+  base::Time test_next_poll_time_;
 
   DISALLOW_COPY_AND_ASSIGN(AlarmManager);
 };
diff --git a/chrome/browser/extensions/api/alarms/alarms_api.cc b/chrome/browser/extensions/api/alarms/alarms_api.cc
index 916a8c2..cc49b6e 100644
--- a/chrome/browser/extensions/api/alarms/alarms_api.cc
+++ b/chrome/browser/extensions/api/alarms/alarms_api.cc
@@ -107,8 +107,9 @@
       params->name.get() ? *params->name : kDefaultAlarmName;
   std::vector<std::string> warnings;
   if (!ValidateAlarmCreateInfo(
-          alarm_name, params->alarm_info, GetExtension(), &error_, &warnings))
+          alarm_name, params->alarm_info, GetExtension(), &error_, &warnings)) {
     return false;
+  }
   for (std::vector<std::string>::const_iterator it = warnings.begin();
        it != warnings.end(); ++it)
     WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING, *it);
@@ -119,31 +120,45 @@
                   Manifest::IsUnpackedLocation(GetExtension()->location()) ?
                   kDevDelayMinimum : kReleaseDelayMinimum),
               clock_->Now());
-  AlarmManager::Get(profile())->AddAlarm(extension_id(), alarm);
+  AlarmManager::Get(profile())->AddAlarm(extension_id(), alarm, base::Bind(
+      &AlarmsCreateFunction::Callback, this));
 
   return true;
 }
 
+void AlarmsCreateFunction::Callback() {
+  SendResponse(true);
+}
+
 bool AlarmsGetFunction::RunImpl() {
   scoped_ptr<alarms::Get::Params> params(alarms::Get::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   std::string name = params->name.get() ? *params->name : kDefaultAlarmName;
-  const Alarm* alarm =
-      AlarmManager::Get(profile())->GetAlarm(extension_id(), name);
+  AlarmManager::Get(profile())->GetAlarm(extension_id(), name, base::Bind(
+      &AlarmsGetFunction::Callback, this, name));
 
-  if (!alarm) {
-    error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name);
-    return false;
-  }
-
-  results_ = alarms::Get::Results::Create(*alarm->js_alarm);
   return true;
 }
 
+void AlarmsGetFunction::Callback(
+    const std::string& name, extensions::Alarm* alarm) {
+  if (alarm) {
+    results_ = alarms::Get::Results::Create(*alarm->js_alarm);
+    SendResponse(true);
+  } else {
+    error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name);
+    SendResponse(false);
+  }
+}
+
 bool AlarmsGetAllFunction::RunImpl() {
-  const AlarmManager::AlarmList* alarms =
-      AlarmManager::Get(profile())->GetAllAlarms(extension_id());
+  AlarmManager::Get(profile())->GetAllAlarms(extension_id(), base::Bind(
+      &AlarmsGetAllFunction::Callback, this));
+  return true;
+}
+
+void AlarmsGetAllFunction::Callback(const AlarmList* alarms) {
   if (alarms) {
     std::vector<linked_ptr<extensions::api::alarms::Alarm> > create_arg;
     create_arg.reserve(alarms->size());
@@ -154,7 +169,7 @@
   } else {
     SetResult(new base::ListValue());
   }
-  return true;
+  SendResponse(true);
 }
 
 bool AlarmsClearFunction::RunImpl() {
@@ -163,20 +178,27 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   std::string name = params->name.get() ? *params->name : kDefaultAlarmName;
-  bool success = AlarmManager::Get(profile())->RemoveAlarm(extension_id(),
-                                                           name);
-
-  if (!success) {
-    error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name);
-    return false;
-  }
+  AlarmManager::Get(profile())->RemoveAlarm(extension_id(), name, base::Bind(
+      &AlarmsClearFunction::Callback, this, name));
 
   return true;
 }
 
+void AlarmsClearFunction::Callback(const std::string& name, bool success) {
+  if (!success)
+    error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name);
+
+  SendResponse(success);
+}
+
 bool AlarmsClearAllFunction::RunImpl() {
-  AlarmManager::Get(profile())->RemoveAllAlarms(extension_id());
+  AlarmManager::Get(profile())->RemoveAllAlarms(extension_id(), base::Bind(
+      &AlarmsClearAllFunction::Callback, this));
   return true;
 }
 
+void AlarmsClearAllFunction::Callback() {
+  SendResponse(true);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/alarms/alarms_api.h b/chrome/browser/extensions/api/alarms/alarms_api.h
index bc694ff..b14a166 100644
--- a/chrome/browser/extensions/api/alarms/alarms_api.h
+++ b/chrome/browser/extensions/api/alarms/alarms_api.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARMS_API_H__
 #define CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARMS_API_H__
 
+#include <vector>
+
 #include "chrome/browser/extensions/extension_function.h"
 
 namespace base {
@@ -12,8 +14,10 @@
 }  // namespace base
 
 namespace extensions {
+struct Alarm;
+typedef std::vector<Alarm> AlarmList;
 
-class AlarmsCreateFunction : public SyncExtensionFunction {
+class AlarmsCreateFunction : public AsyncExtensionFunction {
  public:
   AlarmsCreateFunction();
   // Use |clock| instead of the default clock. Does not take ownership
@@ -26,6 +30,8 @@
   virtual bool RunImpl() OVERRIDE;
   DECLARE_EXTENSION_FUNCTION("alarms.create", ALARMS_CREATE)
  private:
+  void Callback();
+
   base::Clock* const clock_;
   // Whether or not we own |clock_|. This is needed because we own it
   // when we create it ourselves, but not when it's passed in for
@@ -33,39 +39,48 @@
   bool owns_clock_;
 };
 
-class AlarmsGetFunction : public SyncExtensionFunction {
+class AlarmsGetFunction : public AsyncExtensionFunction {
  protected:
   virtual ~AlarmsGetFunction() {}
 
   // ExtensionFunction:
   virtual bool RunImpl() OVERRIDE;
+
+ private:
+  void Callback(const std::string& name, Alarm* alarm);
   DECLARE_EXTENSION_FUNCTION("alarms.get", ALARMS_GET)
 };
 
-class AlarmsGetAllFunction : public SyncExtensionFunction {
+class AlarmsGetAllFunction : public AsyncExtensionFunction {
  protected:
   virtual ~AlarmsGetAllFunction() {}
 
   // ExtensionFunction:
   virtual bool RunImpl() OVERRIDE;
+ private:
+  void Callback(const AlarmList* alarms);
   DECLARE_EXTENSION_FUNCTION("alarms.getAll", ALARMS_GETALL)
 };
 
-class AlarmsClearFunction : public SyncExtensionFunction {
+class AlarmsClearFunction : public AsyncExtensionFunction {
  protected:
   virtual ~AlarmsClearFunction() {}
 
   // ExtensionFunction:
   virtual bool RunImpl() OVERRIDE;
+ private:
+  void Callback(const std::string& name, bool success);
   DECLARE_EXTENSION_FUNCTION("alarms.clear", ALARMS_CLEAR)
 };
 
-class AlarmsClearAllFunction : public SyncExtensionFunction {
+class AlarmsClearAllFunction : public AsyncExtensionFunction {
  protected:
   virtual ~AlarmsClearAllFunction() {}
 
   // ExtensionFunction:
   virtual bool RunImpl() OVERRIDE;
+ private:
+  void Callback();
   DECLARE_EXTENSION_FUNCTION("alarms.clearAll", ALARMS_CLEARALL)
 };
 
diff --git a/chrome/browser/extensions/api/alarms/alarms_api_unittest.cc b/chrome/browser/extensions/api/alarms/alarms_api_unittest.cc
index 6cf0f74..da8d99e 100644
--- a/chrome/browser/extensions/api/alarms/alarms_api_unittest.cc
+++ b/chrome/browser/extensions/api/alarms/alarms_api_unittest.cc
@@ -44,6 +44,10 @@
 
 }  // namespace
 
+void RunScheduleNextPoll(AlarmManager* alarm_manager) {
+  alarm_manager->ScheduleNextPoll();
+}
+
 class ExtensionAlarmsTest : public BrowserWithTestWindowTest {
  public:
   virtual void SetUp() {
@@ -135,21 +139,23 @@
     }
   }
 
- protected:
   base::SimpleTestClock* test_clock_;
   AlarmManager* alarm_manager_;
   AlarmDelegate* alarm_delegate_;
   scoped_refptr<extensions::Extension> extension_;
+
+ protected:
   content::WebContents* contents_;
 };
 
-TEST_F(ExtensionAlarmsTest, Create) {
-  test_clock_->SetNow(base::Time::FromDoubleT(10));
-  // Create 1 non-repeating alarm.
-  CreateAlarm("[null, {\"delayInMinutes\": 0}]");
+void ExtensionAlarmsTestGetAllAlarmsCallback(
+    const AlarmManager::AlarmList* alarms) {
+  // Ensure the alarm is gone.
+  ASSERT_FALSE(alarms);
+}
 
-  const Alarm* alarm =
-      alarm_manager_->GetAlarm(extension_->id(), std::string());
+void ExtensionAlarmsTestGetAlarmCallback(
+    ExtensionAlarmsTest* test, Alarm* alarm) {
   ASSERT_TRUE(alarm);
   EXPECT_EQ("", alarm->js_alarm->name);
   EXPECT_DOUBLE_EQ(10000, alarm->js_alarm->scheduled_time);
@@ -159,15 +165,43 @@
   // MessageLoop when that happens.
   base::MessageLoop::current()->Run();
 
-  ASSERT_EQ(1u, alarm_delegate_->alarms_seen.size());
-  EXPECT_EQ("", alarm_delegate_->alarms_seen[0]);
+  ASSERT_EQ(1u, test->alarm_delegate_->alarms_seen.size());
+  EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
 
   // Ensure the alarm is gone.
-  {
-    const AlarmManager::AlarmList* alarms =
-        alarm_manager_->GetAllAlarms(extension_->id());
-    ASSERT_FALSE(alarms);
-  }
+  test->alarm_manager_->GetAllAlarms(test->extension_->id(), base::Bind(
+      ExtensionAlarmsTestGetAllAlarmsCallback));
+}
+
+TEST_F(ExtensionAlarmsTest, Create) {
+  test_clock_->SetNow(base::Time::FromDoubleT(10));
+  // Create 1 non-repeating alarm.
+  CreateAlarm("[null, {\"delayInMinutes\": 0}]");
+
+  alarm_manager_->GetAlarm(extension_->id(), std::string(), base::Bind(
+      ExtensionAlarmsTestGetAlarmCallback, this));
+}
+
+void ExtensionAlarmsTestCreateRepeatingGetAlarmCallback(
+    ExtensionAlarmsTest* test, Alarm* alarm) {
+  ASSERT_TRUE(alarm);
+  EXPECT_EQ("", alarm->js_alarm->name);
+  EXPECT_DOUBLE_EQ(10060, alarm->js_alarm->scheduled_time);
+  EXPECT_THAT(alarm->js_alarm->period_in_minutes,
+              testing::Pointee(testing::DoubleEq(0.001)));
+
+  test->test_clock_->Advance(base::TimeDelta::FromSeconds(1));
+  // Now wait for the alarm to fire. Our test delegate will quit the
+  // MessageLoop when that happens.
+  base::MessageLoop::current()->Run();
+
+  test->test_clock_->Advance(base::TimeDelta::FromSeconds(1));
+  // Wait again, and ensure the alarm fires again.
+  RunScheduleNextPoll(test->alarm_manager_);
+  base::MessageLoop::current()->Run();
+
+  ASSERT_EQ(2u, test->alarm_delegate_->alarms_seen.size());
+  EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
 }
 
 TEST_F(ExtensionAlarmsTest, CreateRepeating) {
@@ -176,76 +210,97 @@
   // Create 1 repeating alarm.
   CreateAlarm("[null, {\"periodInMinutes\": 0.001}]");
 
-  const Alarm* alarm =
-      alarm_manager_->GetAlarm(extension_->id(), std::string());
-  ASSERT_TRUE(alarm);
-  EXPECT_EQ("", alarm->js_alarm->name);
-  EXPECT_DOUBLE_EQ(10060, alarm->js_alarm->scheduled_time);
-  EXPECT_THAT(alarm->js_alarm->period_in_minutes,
-              testing::Pointee(testing::DoubleEq(0.001)));
-
-  test_clock_->Advance(base::TimeDelta::FromSeconds(1));
-  // Now wait for the alarm to fire. Our test delegate will quit the
-  // MessageLoop when that happens.
-  base::MessageLoop::current()->Run();
-
-  test_clock_->Advance(base::TimeDelta::FromSeconds(1));
-  // Wait again, and ensure the alarm fires again.
-  alarm_manager_->ScheduleNextPoll();
-  base::MessageLoop::current()->Run();
-
-  ASSERT_EQ(2u, alarm_delegate_->alarms_seen.size());
-  EXPECT_EQ("", alarm_delegate_->alarms_seen[0]);
+  alarm_manager_->GetAlarm(extension_->id(), std::string(), base::Bind(
+      ExtensionAlarmsTestCreateRepeatingGetAlarmCallback, this));
 }
 
-TEST_F(ExtensionAlarmsTest, CreateAbsolute) {
-  test_clock_->SetNow(base::Time::FromDoubleT(9.99));
-  CreateAlarm("[null, {\"when\": 10001}]");
+void ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback(
+    ExtensionAlarmsTest* test, Alarm* alarm) {
+  ASSERT_FALSE(alarm);
 
-  const Alarm* alarm =
-      alarm_manager_->GetAlarm(extension_->id(), std::string());
+  ASSERT_EQ(1u, test->alarm_delegate_->alarms_seen.size());
+  EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
+}
+
+void ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback(
+    ExtensionAlarmsTest* test, Alarm* alarm) {
   ASSERT_TRUE(alarm);
   EXPECT_EQ("", alarm->js_alarm->name);
   EXPECT_DOUBLE_EQ(10001, alarm->js_alarm->scheduled_time);
   EXPECT_THAT(alarm->js_alarm->period_in_minutes,
               testing::IsNull());
 
-  test_clock_->SetNow(base::Time::FromDoubleT(10.1));
+  test->test_clock_->SetNow(base::Time::FromDoubleT(10.1));
   // Now wait for the alarm to fire. Our test delegate will quit the
   // MessageLoop when that happens.
   base::MessageLoop::current()->Run();
 
-  ASSERT_FALSE(alarm_manager_->GetAlarm(extension_->id(), std::string()));
-
-  ASSERT_EQ(1u, alarm_delegate_->alarms_seen.size());
-  EXPECT_EQ("", alarm_delegate_->alarms_seen[0]);
+  test->alarm_manager_->GetAlarm(
+      test->extension_->id(), std::string(), base::Bind(
+          ExtensionAlarmsTestCreateAbsoluteGetAlarm2Callback, test));
 }
 
-TEST_F(ExtensionAlarmsTest, CreateRepeatingWithQuickFirstCall) {
+TEST_F(ExtensionAlarmsTest, CreateAbsolute) {
   test_clock_->SetNow(base::Time::FromDoubleT(9.99));
-  CreateAlarm("[null, {\"when\": 10001, \"periodInMinutes\": 0.001}]");
+  CreateAlarm("[null, {\"when\": 10001}]");
 
-  const Alarm* alarm =
-      alarm_manager_->GetAlarm(extension_->id(), std::string());
+  alarm_manager_->GetAlarm(extension_->id(), std::string(), base::Bind(
+      ExtensionAlarmsTestCreateAbsoluteGetAlarm1Callback, this));
+}
+
+void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm3Callback(
+    ExtensionAlarmsTest* test, Alarm* alarm) {
+  ASSERT_TRUE(alarm);
+  EXPECT_THAT(test->alarm_delegate_->alarms_seen, testing::ElementsAre("", ""));
+}
+
+void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm2Callback(
+    ExtensionAlarmsTest* test, Alarm* alarm) {
+  ASSERT_TRUE(alarm);
+  EXPECT_THAT(test->alarm_delegate_->alarms_seen, testing::ElementsAre(""));
+
+  test->test_clock_->SetNow(base::Time::FromDoubleT(10.7));
+  base::MessageLoop::current()->Run();
+
+  test->alarm_manager_->GetAlarm(
+      test->extension_->id(), std::string(), base::Bind(
+          ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm3Callback,
+          test));
+}
+
+void ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm1Callback(
+    ExtensionAlarmsTest* test, Alarm* alarm) {
   ASSERT_TRUE(alarm);
   EXPECT_EQ("", alarm->js_alarm->name);
   EXPECT_DOUBLE_EQ(10001, alarm->js_alarm->scheduled_time);
   EXPECT_THAT(alarm->js_alarm->period_in_minutes,
               testing::Pointee(testing::DoubleEq(0.001)));
 
-  test_clock_->SetNow(base::Time::FromDoubleT(10.1));
+  test->test_clock_->SetNow(base::Time::FromDoubleT(10.1));
   // Now wait for the alarm to fire. Our test delegate will quit the
   // MessageLoop when that happens.
   base::MessageLoop::current()->Run();
 
-  ASSERT_TRUE(alarm_manager_->GetAlarm(extension_->id(), std::string()));
-  EXPECT_THAT(alarm_delegate_->alarms_seen, testing::ElementsAre(""));
+  test->alarm_manager_->GetAlarm(
+      test->extension_->id(), std::string(), base::Bind(
+          ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm2Callback,
+          test));
+}
 
-  test_clock_->SetNow(base::Time::FromDoubleT(10.7));
-  base::MessageLoop::current()->Run();
+TEST_F(ExtensionAlarmsTest, CreateRepeatingWithQuickFirstCall) {
+  test_clock_->SetNow(base::Time::FromDoubleT(9.99));
+  CreateAlarm("[null, {\"when\": 10001, \"periodInMinutes\": 0.001}]");
 
-  ASSERT_TRUE(alarm_manager_->GetAlarm(extension_->id(), std::string()));
-  EXPECT_THAT(alarm_delegate_->alarms_seen, testing::ElementsAre("", ""));
+  alarm_manager_->GetAlarm(extension_->id(), std::string(), base::Bind(
+      ExtensionAlarmsTestCreateRepeatingWithQuickFirstCallGetAlarm1Callback,
+      this));
+}
+
+void ExtensionAlarmsTestCreateDupeGetAllAlarmsCallback(
+    const AlarmManager::AlarmList* alarms) {
+  ASSERT_TRUE(alarms);
+  EXPECT_EQ(1u, alarms->size());
+  EXPECT_DOUBLE_EQ(430000, (*alarms)[0].js_alarm->scheduled_time);
 }
 
 TEST_F(ExtensionAlarmsTest, CreateDupe) {
@@ -255,13 +310,8 @@
   CreateAlarm("[\"dup\", {\"delayInMinutes\": 1}]");
   CreateAlarm("[\"dup\", {\"delayInMinutes\": 7}]");
 
-  {
-    const AlarmManager::AlarmList* alarms =
-        alarm_manager_->GetAllAlarms(extension_->id());
-    ASSERT_TRUE(alarms);
-    EXPECT_EQ(1u, alarms->size());
-    EXPECT_DOUBLE_EQ(430000, (*alarms)[0].js_alarm->scheduled_time);
-  }
+  alarm_manager_->GetAllAlarms(extension_->id(), base::Bind(
+      ExtensionAlarmsTestCreateDupeGetAllAlarmsCallback));
 }
 
 TEST_F(ExtensionAlarmsTest, CreateDelayBelowMinimum) {
@@ -345,6 +395,36 @@
   }
 }
 
+void ExtensionAlarmsTestClearGetAllAlarms2Callback(
+    const AlarmManager::AlarmList* alarms) {
+  // Ensure the 0.001-minute alarm is still there, since it's repeating.
+  ASSERT_TRUE(alarms);
+  EXPECT_EQ(1u, alarms->size());
+  EXPECT_THAT((*alarms)[0].js_alarm->period_in_minutes,
+              testing::Pointee(0.001));
+}
+
+void ExtensionAlarmsTestClearGetAllAlarms1Callback(
+    ExtensionAlarmsTest* test, const AlarmManager::AlarmList* alarms) {
+  ASSERT_TRUE(alarms);
+  EXPECT_EQ(1u, alarms->size());
+  EXPECT_THAT((*alarms)[0].js_alarm->period_in_minutes,
+              testing::Pointee(0.001));
+
+  // Now wait for the alarms to fire, and ensure the cancelled alarms don't
+  // fire.
+  test->test_clock_->Advance(base::TimeDelta::FromMilliseconds(60));
+  RunScheduleNextPoll(test->alarm_manager_);
+  base::MessageLoop::current()->Run();
+
+  ASSERT_EQ(1u, test->alarm_delegate_->alarms_seen.size());
+  EXPECT_EQ("", test->alarm_delegate_->alarms_seen[0]);
+
+  // Ensure the 0.001-minute alarm is still there, since it's repeating.
+  test->alarm_manager_->GetAllAlarms(test->extension_->id(), base::Bind(
+      ExtensionAlarmsTestClearGetAllAlarms2Callback));
+}
+
 TEST_F(ExtensionAlarmsTest, Clear) {
   // Clear a non-existent one.
   {
@@ -357,35 +437,28 @@
   CreateAlarms(3);
 
   // Clear all but the 0.001-minute alarm.
-  {
-    RunFunction(new AlarmsClearFunction(), "[\"7\"]");
-    RunFunction(new AlarmsClearFunction(), "[\"0\"]");
+  RunFunction(new AlarmsClearFunction(), "[\"7\"]");
+  RunFunction(new AlarmsClearFunction(), "[\"0\"]");
 
-    const AlarmManager::AlarmList* alarms =
-        alarm_manager_->GetAllAlarms(extension_->id());
-    ASSERT_TRUE(alarms);
-    EXPECT_EQ(1u, alarms->size());
-    EXPECT_THAT((*alarms)[0].js_alarm->period_in_minutes,
-                testing::Pointee(0.001));
-  }
+  alarm_manager_->GetAllAlarms(extension_->id(), base::Bind(
+      ExtensionAlarmsTestClearGetAllAlarms1Callback, this));
+}
 
-  // Now wait for the alarms to fire, and ensure the cancelled alarms don't
-  // fire.
-  alarm_manager_->ScheduleNextPoll();
-  base::MessageLoop::current()->Run();
+void ExtensionAlarmsTestClearAllGetAllAlarms2Callback(
+    const AlarmManager::AlarmList* alarms) {
+  ASSERT_FALSE(alarms);
+}
 
-  ASSERT_EQ(1u, alarm_delegate_->alarms_seen.size());
-  EXPECT_EQ("", alarm_delegate_->alarms_seen[0]);
+void ExtensionAlarmsTestClearAllGetAllAlarms1Callback(
+    ExtensionAlarmsTest* test, const AlarmManager::AlarmList* alarms) {
+  ASSERT_TRUE(alarms);
+  EXPECT_EQ(3u, alarms->size());
 
-  // Ensure the 0.001-minute alarm is still there, since it's repeating.
-  {
-    const AlarmManager::AlarmList* alarms =
-        alarm_manager_->GetAllAlarms(extension_->id());
-    ASSERT_TRUE(alarms);
-    EXPECT_EQ(1u, alarms->size());
-    EXPECT_THAT((*alarms)[0].js_alarm->period_in_minutes,
-                testing::Pointee(0.001));
-  }
+  // Clear them.
+  test->RunFunction(new AlarmsClearAllFunction(), "[]");
+  test->alarm_manager_->GetAllAlarms(
+      test->extension_->id(), base::Bind(
+          ExtensionAlarmsTestClearAllGetAllAlarms2Callback));
 }
 
 TEST_F(ExtensionAlarmsTest, ClearAll) {
@@ -397,31 +470,39 @@
   }
 
   // Create 3 alarms.
-  {
-    CreateAlarms(3);
-    const AlarmManager::AlarmList* alarms =
-        alarm_manager_->GetAllAlarms(extension_->id());
-    ASSERT_TRUE(alarms);
-    EXPECT_EQ(3u, alarms->size());
-  }
-
-  // Clear them.
-  {
-    RunFunction(new AlarmsClearAllFunction(), "[]");
-    const AlarmManager::AlarmList* alarms =
-        alarm_manager_->GetAllAlarms(extension_->id());
-    ASSERT_FALSE(alarms);
-  }
+  CreateAlarms(3);
+  alarm_manager_->GetAllAlarms(extension_->id(), base::Bind(
+      ExtensionAlarmsTestClearAllGetAllAlarms1Callback, this));
 }
 
 class ExtensionAlarmsSchedulingTest : public ExtensionAlarmsTest {
+  void GetAlarmCallback(Alarm* alarm) {
+    CHECK(alarm);
+    const base::Time scheduled_time =
+        base::Time::FromJsTime(alarm->js_alarm->scheduled_time);
+    EXPECT_EQ(scheduled_time, alarm_manager_->test_next_poll_time_);
+  }
+
+  static void RemoveAlarmCallback (bool success) { EXPECT_TRUE(success); }
+  static void RemoveAllAlarmsCallback () {}
  public:
   // Get the time that the alarm named is scheduled to run.
-  base::Time GetScheduledTime(const std::string& alarm_name) {
-    const extensions::Alarm* alarm =
-        alarm_manager_->GetAlarm(extension_->id(), alarm_name);
-    CHECK(alarm);
-    return base::Time::FromJsTime(alarm->js_alarm->scheduled_time);
+  void VerifyScheduledTime(const std::string& alarm_name) {
+    alarm_manager_->GetAlarm(extension_->id(), alarm_name, base::Bind(
+        &ExtensionAlarmsSchedulingTest::GetAlarmCallback,
+        base::Unretained(this)));
+  }
+
+  void RemoveAlarm(const std::string& name) {
+    alarm_manager_->RemoveAlarm(
+        extension_->id(),
+        name,
+        base::Bind(&ExtensionAlarmsSchedulingTest::RemoveAlarmCallback));
+  }
+
+  void RemoveAllAlarms () {
+    alarm_manager_->RemoveAllAlarms(extension_->id(), base::Bind(
+        &ExtensionAlarmsSchedulingTest::RemoveAllAlarmsCallback));
   }
 };
 
@@ -429,14 +510,14 @@
   {
     CreateAlarm("[\"a\", {\"periodInMinutes\": 6}]");
     CreateAlarm("[\"bb\", {\"periodInMinutes\": 8}]");
-    EXPECT_EQ(GetScheduledTime("a"), alarm_manager_->next_poll_time_);
-    alarm_manager_->RemoveAllAlarms(extension_->id());
+    VerifyScheduledTime("a");
+    RemoveAllAlarms();
   }
   {
     CreateAlarm("[\"a\", {\"delayInMinutes\": 10}]");
     CreateAlarm("[\"bb\", {\"delayInMinutes\": 21}]");
-    EXPECT_EQ(GetScheduledTime("a"), alarm_manager_->next_poll_time_);
-    alarm_manager_->RemoveAllAlarms(extension_->id());
+    VerifyScheduledTime("a");
+    RemoveAllAlarms();
   }
   {
     test_clock_->SetNow(base::Time::FromDoubleT(10));
@@ -446,9 +527,8 @@
     alarm.js_alarm->scheduled_time = 30 * 60000;
     alarm.js_alarm->period_in_minutes.reset(new double(30));
     alarm_manager_->AddAlarmImpl(extension_->id(), alarm);
-    EXPECT_DOUBLE_EQ(GetScheduledTime("a").ToDoubleT(),
-                     alarm_manager_->next_poll_time_.ToDoubleT());
-    alarm_manager_->RemoveAllAlarms(extension_->id());
+    VerifyScheduledTime("a");
+    RemoveAllAlarms();
   }
   {
     test_clock_->SetNow(base::Time::FromDoubleT(3 * 60 + 1));
@@ -459,13 +539,13 @@
     alarm_manager_->AddAlarmImpl(extension_->id(), alarm);
     base::MessageLoop::current()->Run();
     EXPECT_EQ(alarm_manager_->last_poll_time_ + base::TimeDelta::FromMinutes(3),
-              alarm_manager_->next_poll_time_);
-    alarm_manager_->RemoveAllAlarms(extension_->id());
+              alarm_manager_->test_next_poll_time_);
+    RemoveAllAlarms();
   }
   {
     test_clock_->SetNow(base::Time::FromDoubleT(4 * 60 + 1));
     CreateAlarm("[\"a\", {\"periodInMinutes\": 2}]");
-    alarm_manager_->RemoveAlarm(extension_->id(), "a");
+    RemoveAlarm("a");
     Alarm alarm2;
     alarm2.js_alarm->name = "bb";
     alarm2.js_alarm->scheduled_time = 4 * 60000;
@@ -478,8 +558,8 @@
     alarm_manager_->AddAlarmImpl(extension_->id(), alarm3);
     base::MessageLoop::current()->Run();
     EXPECT_EQ(alarm_manager_->last_poll_time_ + base::TimeDelta::FromMinutes(4),
-              alarm_manager_->next_poll_time_);
-    alarm_manager_->RemoveAllAlarms(extension_->id());
+              alarm_manager_->test_next_poll_time_);
+    RemoveAllAlarms();
   }
 }
 
@@ -492,28 +572,48 @@
 
   // On startup (when there's no "last poll"), we let alarms fire as
   // soon as they're scheduled.
-  EXPECT_DOUBLE_EQ(300010, alarm_manager_->next_poll_time_.ToJsTime());
+  EXPECT_DOUBLE_EQ(300010, alarm_manager_->test_next_poll_time_.ToJsTime());
 
   alarm_manager_->last_poll_time_ = base::Time::FromJsTime(290000);
-  // In released extensions, we set the granularity to at least 5
-  // minutes, which makes AddAlarm schedule the next poll after the
+  // In released extensions, we set the granularity to at least 1
+  // minute, which makes AddAlarm schedule the next poll after the
   // extension requested.
   alarm_manager_->ScheduleNextPoll();
   EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
                     base::TimeDelta::FromMinutes(1)).ToJsTime(),
-                   alarm_manager_->next_poll_time_.ToJsTime());
+                    alarm_manager_->test_next_poll_time_.ToJsTime());
 }
 
 TEST_F(ExtensionAlarmsSchedulingTest, TimerRunning) {
   EXPECT_FALSE(alarm_manager_->timer_.IsRunning());
   CreateAlarm("[\"a\", {\"delayInMinutes\": 0.001}]");
   EXPECT_TRUE(alarm_manager_->timer_.IsRunning());
+  test_clock_->Advance(base::TimeDelta::FromMilliseconds(60));
   base::MessageLoop::current()->Run();
   EXPECT_FALSE(alarm_manager_->timer_.IsRunning());
   CreateAlarm("[\"bb\", {\"delayInMinutes\": 10}]");
   EXPECT_TRUE(alarm_manager_->timer_.IsRunning());
-  alarm_manager_->RemoveAllAlarms(extension_->id());
+  RemoveAllAlarms();
   EXPECT_FALSE(alarm_manager_->timer_.IsRunning());
 }
 
+TEST_F(ExtensionAlarmsSchedulingTest, MinimumGranularity) {
+  extension_ = utils::CreateEmptyExtensionWithLocation(
+      extensions::Manifest::INTERNAL);
+  test_clock_->SetNow(base::Time::FromJsTime(0));
+  CreateAlarm("[\"a\", {\"periodInMinutes\": 2}]");
+  test_clock_->Advance(base::TimeDelta::FromSeconds(1));
+  CreateAlarm("[\"b\", {\"periodInMinutes\": 2}]");
+  test_clock_->Advance(base::TimeDelta::FromMinutes(2));
+
+  alarm_manager_->last_poll_time_ = base::Time::FromJsTime(2 * 60000);
+  // In released extensions, we set the granularity to at least 1
+  // minute, which makes scheduler set it to 1 minute, rather than
+  // 1 second later (when b is supposed to go off).
+  alarm_manager_->ScheduleNextPoll();
+  EXPECT_DOUBLE_EQ((alarm_manager_->last_poll_time_ +
+                    base::TimeDelta::FromMinutes(1)).ToJsTime(),
+                    alarm_manager_->test_next_poll_time_.ToJsTime());
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/api_resource.cc b/chrome/browser/extensions/api/api_resource.cc
index 8339367..ccbdd77 100644
--- a/chrome/browser/extensions/api/api_resource.cc
+++ b/chrome/browser/extensions/api/api_resource.cc
@@ -15,4 +15,8 @@
 ApiResource::~ApiResource() {
 }
 
+bool ApiResource::persistent() const {
+    return true;  // backward-compatible behavior.
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/api_resource.h b/chrome/browser/extensions/api/api_resource.h
index 4a21083..2cfdffe 100644
--- a/chrome/browser/extensions/api/api_resource.h
+++ b/chrome/browser/extensions/api/api_resource.h
@@ -23,6 +23,8 @@
     return owner_extension_id_;
   }
 
+  virtual bool persistent() const;
+
   static const content::BrowserThread::ID kThreadId =
       content::BrowserThread::IO;
 
diff --git a/chrome/browser/extensions/api/api_resource_manager.h b/chrome/browser/extensions/api/api_resource_manager.h
index d357ebe..a7c1624 100644
--- a/chrome/browser/extensions/api/api_resource_manager.h
+++ b/chrome/browser/extensions/api/api_resource_manager.h
@@ -7,11 +7,13 @@
 
 #include <map>
 
+#include "base/containers/hash_tables.h"
 #include "base/lazy_instance.h"
 #include "base/memory/linked_ptr.h"
 #include "base/threading/non_thread_safe.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/extension_host.h"
 #include "chrome/common/extensions/extension.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -69,6 +71,10 @@
       this,
       chrome::NOTIFICATION_EXTENSION_UNLOADED,
       content::NotificationService::AllSources());
+    registrar_.Add(
+      this,
+      chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
+      content::NotificationService::AllSources());
   }
 
   // For Testing.
@@ -113,6 +119,10 @@
     return data_->Get(extension_id, api_resource_id);
   }
 
+  base::hash_set<int>* GetResourceIds(const std::string& extension_id) {
+    return data_->GetResourceIds(extension_id);
+  }
+
  protected:
   // content::NotificationObserver:
   virtual void Observe(int type,
@@ -123,7 +133,12 @@
         std::string id =
             content::Details<extensions::UnloadedExtensionInfo>(details)->
                 extension->id();
-        data_->InitiateCleanup(id);
+        data_->InitiateExtensionUnloadedCleanup(id);
+        break;
+      }
+      case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
+        ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
+        data_->InitiateExtensionSuspendedCleanup(host->extension_id());
         break;
       }
     }
@@ -185,9 +200,20 @@
       return GetOwnedResource(extension_id, api_resource_id);
     }
 
-    void InitiateCleanup(const std::string& extension_id) {
+    base::hash_set<int>* GetResourceIds(const std::string& extension_id) {
+      DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+      return GetOwnedResourceIds(extension_id);
+    }
+
+    void InitiateExtensionUnloadedCleanup(const std::string& extension_id) {
       content::BrowserThread::PostTask(thread_id_, FROM_HERE,
-          base::Bind(&ApiResourceData::CleanupResourcesFromExtension,
+          base::Bind(&ApiResourceData::CleanupResourcesFromUnloadedExtension,
+                     base::Unretained(this), extension_id));
+    }
+
+    void InitiateExtensionSuspendedCleanup(const std::string& extension_id) {
+      content::BrowserThread::PostTask(thread_id_, FROM_HERE,
+          base::Bind(&ApiResourceData::CleanupResourcesFromSuspendedExtension,
                      base::Unretained(this), extension_id));
     }
 
@@ -201,16 +227,59 @@
       return NULL;
     }
 
-    void CleanupResourcesFromExtension(const std::string& extension_id) {
+    base::hash_set<int>* GetOwnedResourceIds(const std::string& extension_id) {
       DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
-      if (extension_resource_map_.find(extension_id) !=
+      if (extension_resource_map_.find(extension_id) ==
+          extension_resource_map_.end())
+        return NULL;
+
+      return &extension_resource_map_[extension_id];
+    }
+
+    void CleanupResourcesFromUnloadedExtension(
+        const std::string& extension_id) {
+      CleanupResourcesFromExtension(extension_id, true);
+    }
+
+    void CleanupResourcesFromSuspendedExtension(
+        const std::string& extension_id) {
+      CleanupResourcesFromExtension(extension_id, false);
+    }
+
+    void CleanupResourcesFromExtension(const std::string& extension_id,
+                                       bool remove_all) {
+      DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+
+      if (extension_resource_map_.find(extension_id) ==
           extension_resource_map_.end()) {
-        base::hash_set<int>& resource_ids =
-            extension_resource_map_[extension_id];
-        for (base::hash_set<int>::iterator it = resource_ids.begin();
-             it != resource_ids.end(); ++it) {
-          api_resource_map_.erase(*it);
+        return;
+      }
+
+      // Remove all resources, or the non persistent ones only if |remove_all|
+      // is false.
+      base::hash_set<int>& resource_ids =
+          extension_resource_map_[extension_id];
+      for (base::hash_set<int>::iterator it = resource_ids.begin();
+            it != resource_ids.end(); ) {
+        bool erase = false;
+        if (remove_all) {
+          erase = true;
+        } else {
+          linked_ptr<T> ptr = api_resource_map_[*it];
+          T* resource = ptr.get();
+          erase = (resource && !resource->persistent());
         }
+
+        if (erase) {
+          api_resource_map_.erase(*it);
+          resource_ids.erase(it++);
+        } else {
+          ++it;
+        }
+      }  // end for
+
+      // Remove extension entry if we removed all its resources.
+      if (resource_ids.size() == 0) {
         extension_resource_map_.erase(extension_id);
       }
     }
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 dcda353..d69b2cf 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
@@ -12,11 +12,17 @@
 #include "chrome/common/extensions/api/app_window.h"
 #include "chrome/common/extensions/features/feature_channel.h"
 #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;
 
 using apps::ShellWindow;
-namespace SetBounds = extensions::api::app_current_window_internal::SetBounds;
 using extensions::api::app_current_window_internal::Bounds;
-namespace SetIcon = extensions::api::app_current_window_internal::SetIcon;
+using extensions::api::app_current_window_internal::Region;
+using extensions::api::app_current_window_internal::RegionRect;
 
 namespace extensions {
 
@@ -142,4 +148,44 @@
   return true;
 }
 
+bool AppCurrentWindowInternalSetInputRegionFunction::RunWithWindow(
+    ShellWindow* window) {
+  if (GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV) {
+    error_ = kDevChannelOnly;
+    return false;
+  }
+
+  scoped_ptr<SetInputRegion::Params> params(
+      SetInputRegion::Params::Create(*args_));
+  const Region& inputRegion = params->region;
+
+  // Build a region from the supplied list of rects.
+  // If |rects| is missing, then the input region is removed. This clears the
+  // input region so that the entire window accepts input events.
+  // To specify an empty input region (so the window ignores all input),
+  // |rects| should be an empty list.
+  scoped_ptr<SkRegion> region(new SkRegion);
+  if (inputRegion.rects) {
+    for (std::vector<linked_ptr<RegionRect> >::const_iterator i =
+             inputRegion.rects->begin();
+         i != inputRegion.rects->end();
+         ++i) {
+      const RegionRect& inputRect = **i;
+      int32_t x = inputRect.left;
+      int32_t y = inputRect.top;
+      int32_t width = inputRect.width;
+      int32_t height = inputRect.height;
+
+      SkIRect rect = SkIRect::MakeXYWH(x, y, width, height);
+      region->op(rect, SkRegion::kUnion_Op);
+    }
+  } else {
+    region.reset(NULL);
+  }
+
+  window->UpdateInputRegion(region.Pass());
+
+  return true;
+}
+
 }  // namespace extensions
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 806ae3b..0bf5c4a 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
@@ -144,6 +144,17 @@
   virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
 };
 
+class AppCurrentWindowInternalSetInputRegionFunction
+    : public AppCurrentWindowInternalExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("app.currentWindowInternal.setInputRegion",
+                             APP_CURRENTWINDOWINTERNAL_SETINPUTREGION)
+
+ protected:
+  virtual ~AppCurrentWindowInternalSetInputRegionFunction() {}
+  virtual bool RunWithWindow(apps::ShellWindow* window) OVERRIDE;
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_APP_CURRENT_WINDOW_INTERNAL_APP_CURRENT_WINDOW_INTERNAL_API_H_
diff --git a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
index 5b7bd40..b976dc7 100644
--- a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
+++ b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
@@ -10,27 +10,27 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/app_runtime.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
 namespace extensions {
 
-namespace {
+namespace app_runtime = api::app_runtime;
 
-using event_names::kOnLaunched;
-using event_names::kOnRestarted;
+namespace {
 
 void DispatchOnLaunchedEventImpl(const std::string& extension_id,
                                  scoped_ptr<base::ListValue> args,
                                  Profile* profile) {
   extensions::ExtensionSystem* system =
       extensions::ExtensionSystem::Get(profile);
-  scoped_ptr<Event> event(new Event(kOnLaunched, args.Pass()));
+  scoped_ptr<Event> event(new Event(app_runtime::OnLaunched::kEventName,
+                                    args.Pass()));
   event->restrict_to_profile = profile;
   system->event_router()->DispatchEventWithLazyListener(extension_id,
                                                         event.Pass());
@@ -49,7 +49,8 @@
 void AppEventRouter::DispatchOnRestartedEvent(Profile* profile,
                                               const Extension* extension) {
   scoped_ptr<base::ListValue> arguments(new base::ListValue());
-  scoped_ptr<Event> event(new Event(kOnRestarted, arguments.Pass()));
+  scoped_ptr<Event> event(new Event(app_runtime::OnRestarted::kEventName,
+                                    arguments.Pass()));
   event->restrict_to_profile = profile;
   extensions::ExtensionSystem::Get(profile)->event_router()->
       DispatchEventToExtension(extension->id(), event.Pass());
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 7fa2492..97b52f2 100644
--- a/chrome/browser/extensions/api/app_window/app_window_api.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_api.cc
@@ -164,7 +164,7 @@
 
           window->GetBaseWindow()->Show();
           base::DictionaryValue* result = new base::DictionaryValue;
-          result->Set("viewId", base::Value::CreateIntegerValue(view_id));
+          result->Set("viewId", new base::FundamentalValue(view_id));
           SetCreateResultFromShellWindow(window, result);
           result->SetBoolean("existingWindow", true);
           result->SetBoolean("injectTitlebar", false);
@@ -311,10 +311,10 @@
     view_id = created_view->GetRoutingID();
 
   base::DictionaryValue* result = new base::DictionaryValue;
-  result->Set("viewId", base::Value::CreateIntegerValue(view_id));
+  result->Set("viewId", new base::FundamentalValue(view_id));
   result->Set("injectTitlebar",
-      base::Value::CreateBooleanValue(inject_html_titlebar));
-  result->Set("id", base::Value::CreateStringValue(shell_window->window_key()));
+      new base::FundamentalValue(inject_html_titlebar));
+  result->Set("id", new base::StringValue(shell_window->window_key()));
   SetCreateResultFromShellWindow(shell_window, result);
   SetResult(result);
 
diff --git a/chrome/browser/extensions/api/app_window/app_window_apitest.cc b/chrome/browser/extensions/api/app_window/app_window_apitest.cc
index a4f3909..23d4945 100644
--- a/chrome/browser/extensions/api/app_window/app_window_apitest.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_apitest.cc
@@ -7,8 +7,8 @@
 #include "apps/shell_window_registry.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/testing_profile.h"
 #include "ui/base/base_window.h"
diff --git a/chrome/browser/extensions/api/audio/audio_api.cc b/chrome/browser/extensions/api/audio/audio_api.cc
index b6c37fb..359b48d 100644
--- a/chrome/browser/extensions/api/audio/audio_api.cc
+++ b/chrome/browser/extensions/api/audio/audio_api.cc
@@ -6,12 +6,14 @@
 
 #include "base/lazy_instance.h"
 #include "base/values.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
+#include "chrome/common/extensions/api/audio.h"
 
 namespace extensions {
 
+namespace audio = api::audio;
+
 static base::LazyInstance<ProfileKeyedAPIFactory<AudioAPI> >
 g_factory = LAZY_INSTANCE_INITIALIZER;
 
@@ -39,7 +41,7 @@
 void AudioAPI::OnDeviceChanged() {
   if (profile_ && ExtensionSystem::Get(profile_)->event_router()) {
     scoped_ptr<Event> event(new Event(
-        event_names::kOnAudioDeviceChanged,
+        audio::OnDeviceChanged::kEventName,
         scoped_ptr<base::ListValue>(new base::ListValue())));
     ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(
         event.Pass());
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 86fc7ea..28b0f9b 100644
--- a/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
@@ -96,6 +96,24 @@
   return true;
 }
 
+static int AccessArray(const volatile int arr[], const volatile int *index) {
+  return arr[*index];
+}
+
+bool AutotestPrivateSimulateAsanMemoryBugFunction::RunImpl() {
+  DVLOG(1) << "AutotestPrivateSimulateAsanMemoryBugFunction";
+  if (!AutotestPrivateAPIFactory::GetForProfile(profile())->test_mode()) {
+    // This array is volatile not to let compiler optimize us out.
+    volatile int testarray[3] = {0, 0, 0};
+
+    // Cause Address Sanitizer to abort this process.
+    volatile int index = 5;
+    AccessArray(testarray, &index);
+  }
+  return true;
+}
+
+
 AutotestPrivateAPI::AutotestPrivateAPI() : test_mode_(false) {
 }
 
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 bc0c0a2..176cc20 100644
--- a/chrome/browser/extensions/api/autotest_private/autotest_private_api.h
+++ b/chrome/browser/extensions/api/autotest_private/autotest_private_api.h
@@ -51,6 +51,17 @@
   virtual bool RunImpl() OVERRIDE;
 };
 
+class AutotestPrivateSimulateAsanMemoryBugFunction
+    : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("autotestPrivate.simulateAsanMemoryBug",
+                             AUTOTESTPRIVATE_SIMULATEASANMEMORYBUG)
+
+ private:
+  virtual ~AutotestPrivateSimulateAsanMemoryBugFunction() {}
+  virtual bool RunImpl() OVERRIDE;
+};
+
 // Don't kill the browser when we're in a browser test.
 void SetAutotestPrivateTest();
 
diff --git a/chrome/browser/extensions/api/bluetooth/OWNERS b/chrome/browser/extensions/api/bluetooth/OWNERS
new file mode 100644
index 0000000..beccf04
--- /dev/null
+++ b/chrome/browser/extensions/api/bluetooth/OWNERS
@@ -0,0 +1,3 @@
+ikarienator@chromium.org
+rpaquay@chromium.org
+keybuk@chromium.org
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
index 0055d9b..9532f61 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_api.cc
@@ -65,6 +65,7 @@
 }  // namespace
 
 namespace AddProfile = extensions::api::bluetooth::AddProfile;
+namespace bluetooth = extensions::api::bluetooth;
 namespace Connect = extensions::api::bluetooth::Connect;
 namespace Disconnect = extensions::api::bluetooth::Disconnect;
 namespace GetDevices = extensions::api::bluetooth::GetDevices;
@@ -85,7 +86,7 @@
 
 BluetoothAPI::BluetoothAPI(Profile* profile) : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, extensions::event_names::kBluetoothOnAdapterStateChanged);
+      this, bluetooth::OnAdapterStateChanged::kEventName);
 }
 
 BluetoothAPI::~BluetoothAPI() {
@@ -505,7 +506,7 @@
   success_ = socket_->Send(drainable_io_buffer.get());
   if (success_) {
     if (drainable_io_buffer->BytesConsumed() > 0)
-      SetResult(base::Value::CreateIntegerValue(
+      SetResult(new base::FundamentalValue(
           drainable_io_buffer->BytesConsumed()));
     else
       results_.reset();
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc
index 5147a7b..5162892 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router.cc
@@ -26,6 +26,8 @@
 
 namespace extensions {
 
+namespace bluetooth = api::bluetooth;
+
 ExtensionBluetoothEventRouter::ExtensionBluetoothEventRouter(Profile* profile)
     : send_discovery_events_(false),
       responsible_for_discovery_(false),
@@ -161,7 +163,7 @@
 }
 
 void ExtensionBluetoothEventRouter::DispatchDeviceEvent(
-    const char* event_name, const extensions::api::bluetooth::Device& device) {
+    const char* event_name, const bluetooth::Device& device) {
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(device.ToValue().release());
   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
@@ -185,7 +187,7 @@
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(result_socket.ToValue().release());
   scoped_ptr<Event> event(new Event(
-      extensions::event_names::kBluetoothOnConnection, args.Pass()));
+      bluetooth::OnConnection::kEventName, args.Pass()));
   ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
       extension_id, event.Pass());
 }
@@ -232,9 +234,9 @@
     return;
   }
 
-  extensions::api::bluetooth::Device* extension_device =
-      new extensions::api::bluetooth::Device();
-  extensions::api::bluetooth::BluetoothDeviceToApiDevice(
+  bluetooth::Device* extension_device =
+      new bluetooth::Device();
+  bluetooth::BluetoothDeviceToApiDevice(
       *device, extension_device);
   discovered_devices_.push_back(extension_device);
 
@@ -274,7 +276,7 @@
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(state.ToValue().release());
   scoped_ptr<Event> event(new Event(
-      extensions::event_names::kBluetoothOnAdapterStateChanged,
+      bluetooth::OnAdapterStateChanged::kEventName,
       args.Pass()));
   ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(event.Pass());
 }
diff --git a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router_unittest.cc b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router_unittest.cc
index 60b830a..39d3908 100644
--- a/chrome/browser/extensions/api/bluetooth/bluetooth_event_router_unittest.cc
+++ b/chrome/browser/extensions/api/bluetooth/bluetooth_event_router_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/common/extensions/api/bluetooth.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -79,6 +80,8 @@
 
 namespace extensions {
 
+namespace bluetooth = api::bluetooth;
+
 class ExtensionBluetoothEventRouterTest : public testing::Test {
  public:
   ExtensionBluetoothEventRouterTest()
@@ -166,7 +169,7 @@
       static_cast<FakeEventRouter*>(fake_extension_system->event_router());
 
   EXPECT_STREQ(test_extension_id, fake_event_router->extension_id().c_str());
-  EXPECT_STREQ(event_names::kBluetoothOnConnection,
+  EXPECT_STREQ(bluetooth::OnConnection::kEventName,
                fake_event_router->event()->event_name.c_str());
 
   base::ListValue* event_args = fake_event_router->event()->event_args.get();
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 9d25e6c..62ca111 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
@@ -42,6 +42,7 @@
 namespace extensions {
 
 namespace bookmark_keys = bookmark_api_constants;
+namespace bookmark_manager_private = api::bookmark_manager_private;
 namespace CanPaste = api::bookmark_manager_private::CanPaste;
 namespace Copy = api::bookmark_manager_private::Copy;
 namespace Cut = api::bookmark_manager_private::Cut;
@@ -198,7 +199,7 @@
 
 void BookmarkManagerPrivateEventRouter::OnDragEnter(
     const BookmarkNodeData& data) {
-  DispatchDragEvent(data, manager_keys::kOnBookmarkDragEnter);
+  DispatchDragEvent(data, bookmark_manager_private::OnDragEnter::kEventName);
 }
 
 void BookmarkManagerPrivateEventRouter::OnDragOver(
@@ -209,11 +210,11 @@
 
 void BookmarkManagerPrivateEventRouter::OnDragLeave(
     const BookmarkNodeData& data) {
-  DispatchDragEvent(data, manager_keys::kOnBookmarkDragLeave);
+  DispatchDragEvent(data, bookmark_manager_private::OnDragLeave::kEventName);
 }
 
 void BookmarkManagerPrivateEventRouter::OnDrop(const BookmarkNodeData& data) {
-  DispatchDragEvent(data, manager_keys::kOnBookmarkDrop);
+  DispatchDragEvent(data, bookmark_manager_private::OnDrop::kEventName);
 
   // Make a copy that is owned by this instance.
   ClearBookmarkNodeData();
diff --git a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_constants.cc b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_constants.cc
index d7f7b4e..7818494 100644
--- a/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_constants.cc
+++ b/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api_constants.cc
@@ -11,10 +11,5 @@
 const char kSameProfileKey[] = "sameProfile";
 const char kElementsKey[] = "elements";
 
-// Events.
-const char kOnBookmarkDragEnter[] = "bookmarkManagerPrivate.onDragEnter";
-const char kOnBookmarkDragLeave[] = "bookmarkManagerPrivate.onDragLeave";
-const char kOnBookmarkDrop[] = "bookmarkManagerPrivate.onDrop";
-
 }  // namespace bookmark_manager_api_constants
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/bookmarks/bookmark_api_constants.cc b/chrome/browser/extensions/api/bookmarks/bookmark_api_constants.cc
index 32a03f2..b2bc4ad 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmark_api_constants.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmark_api_constants.cc
@@ -30,13 +30,5 @@
 const char kModifySpecialError[] = "Can't modify the root bookmark folders.";
 const char kEditBookmarksDisabled[] = "Bookmark editing is disabled.";
 
-const char kOnBookmarkCreated[] = "bookmarks.onCreated";
-const char kOnBookmarkRemoved[] = "bookmarks.onRemoved";
-const char kOnBookmarkChanged[] = "bookmarks.onChanged";
-const char kOnBookmarkMoved[] = "bookmarks.onMoved";
-const char kOnBookmarkChildrenReordered[] = "bookmarks.onChildrenReordered";
-const char kOnBookmarkImportBegan[] = "bookmarks.onImportBegan";
-const char kOnBookmarkImportEnded[] = "bookmarks.onImportEnded";
-
 }  // namespace bookmark_api_constants
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
index a6a2d2a..f64299c 100644
--- a/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
+++ b/chrome/browser/extensions/api/bookmarks/bookmarks_api.cc
@@ -189,7 +189,7 @@
   object_args->SetInteger(keys::kOldIndexKey, old_index);
   args->Append(object_args);
 
-  DispatchEvent(keys::kOnBookmarkMoved, args.Pass());
+  DispatchEvent(bookmarks::OnMoved::kEventName, args.Pass());
 }
 
 void BookmarkEventRouter::BookmarkNodeAdded(BookmarkModel* model,
@@ -202,7 +202,7 @@
       bookmark_api_helpers::GetBookmarkTreeNode(node, false, false));
   args->Append(tree_node->ToValue().release());
 
-  DispatchEvent(keys::kOnBookmarkCreated, args.Pass());
+  DispatchEvent(bookmarks::OnCreated::kEventName, args.Pass());
 }
 
 void BookmarkEventRouter::BookmarkNodeRemoved(BookmarkModel* model,
@@ -217,7 +217,7 @@
   object_args->SetInteger(keys::kIndexKey, index);
   args->Append(object_args);
 
-  DispatchEvent(keys::kOnBookmarkRemoved, args.Pass());
+  DispatchEvent(bookmarks::OnRemoved::kEventName, args.Pass());
 }
 
 void BookmarkEventRouter::BookmarkAllNodesRemoved(BookmarkModel* model) {
@@ -243,7 +243,7 @@
     object_args->SetString(keys::kUrlKey, node->url().spec());
   args->Append(object_args);
 
-  DispatchEvent(keys::kOnBookmarkChanged, args.Pass());
+  DispatchEvent(bookmarks::OnChanged::kEventName, args.Pass());
 }
 
 void BookmarkEventRouter::BookmarkNodeFaviconChanged(BookmarkModel* model,
@@ -268,35 +268,35 @@
   reorder_info->Set(keys::kChildIdsKey, children);
   args->Append(reorder_info);
 
-  DispatchEvent(keys::kOnBookmarkChildrenReordered, args.Pass());
+  DispatchEvent(bookmarks::OnChildrenReordered::kEventName, args.Pass());
 }
 
 void BookmarkEventRouter::ExtensiveBookmarkChangesBeginning(
     BookmarkModel* model) {
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  DispatchEvent(keys::kOnBookmarkImportBegan, args.Pass());
+  DispatchEvent(bookmarks::OnImportBegan::kEventName, args.Pass());
 }
 
 void BookmarkEventRouter::ExtensiveBookmarkChangesEnded(BookmarkModel* model) {
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  DispatchEvent(keys::kOnBookmarkImportEnded, args.Pass());
+  DispatchEvent(bookmarks::OnImportEnded::kEventName, args.Pass());
 }
 
 BookmarksAPI::BookmarksAPI(Profile* profile) : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBookmarkCreated);
+      this, bookmarks::OnCreated::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBookmarkRemoved);
+      this, bookmarks::OnRemoved::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBookmarkChanged);
+      this, bookmarks::OnChanged::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBookmarkMoved);
+      this, bookmarks::OnMoved::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBookmarkChildrenReordered);
+      this, bookmarks::OnChildrenReordered::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBookmarkImportBegan);
+      this, bookmarks::OnImportBegan::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBookmarkImportEnded);
+      this, bookmarks::OnImportEnded::kEventName);
 }
 
 BookmarksAPI::~BookmarksAPI() {
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 f4025f2..e44a17d 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
@@ -71,7 +71,7 @@
 }
 
 bool CloudPrintPrivateGetHostNameFunction::RunImpl() {
-  SetResult(Value::CreateStringValue(
+  SetResult(new base::StringValue(
       CloudPrintTestsDelegate::instance() ?
       CloudPrintTestsDelegate::instance()->GetHostName() :
       net::GetHostName()));
@@ -115,7 +115,7 @@
 }
 
 bool CloudPrintPrivateGetClientIdFunction::RunImpl() {
-  SetResult(Value::CreateStringValue(
+  SetResult(new base::StringValue(
       CloudPrintTestsDelegate::instance() ?
       CloudPrintTestsDelegate::instance()->GetClientId() :
       google_apis::GetOAuth2ClientID(google_apis::CLIENT_CLOUD_PRINT)));
diff --git a/chrome/browser/extensions/api/commands/OWNERS b/chrome/browser/extensions/api/commands/OWNERS
new file mode 100644
index 0000000..32f119e
--- /dev/null
+++ b/chrome/browser/extensions/api/commands/OWNERS
@@ -0,0 +1,3 @@
+# Anyone in the parent directories can review changes to this directory,
+# but the following people are the most knowledgeable:
+finnur@chromium.org
diff --git a/chrome/browser/extensions/api/commands/command_service.cc b/chrome/browser/extensions/api/commands/command_service.cc
index 13c70e1..2978a1f 100644
--- a/chrome/browser/extensions/api/commands/command_service.cc
+++ b/chrome/browser/extensions/api/commands/command_service.cc
@@ -43,7 +43,7 @@
 void SetInitialBindingsHaveBeenAssigned(
     ExtensionPrefs* prefs, const std::string& extension_id) {
   prefs->UpdateExtensionPref(extension_id, kInitialBindingsHaveBeenAssigned,
-                             base::Value::CreateBooleanValue(true));
+                             new base::FundamentalValue(true));
 }
 
 bool InitialBindingsHaveBeenAssigned(
diff --git a/chrome/browser/extensions/api/content_settings/content_settings_store.cc b/chrome/browser/extensions/api/content_settings/content_settings_store.cc
index ff58296..3b0c008 100644
--- a/chrome/browser/extensions/api/content_settings/content_settings_store.cc
+++ b/chrome/browser/extensions/api/content_settings/content_settings_store.cc
@@ -105,7 +105,7 @@
       map->DeleteValue(primary_pattern, secondary_pattern, type, identifier);
     } else {
       map->SetValue(primary_pattern, secondary_pattern, type, identifier,
-                    base::Value::CreateIntegerValue(setting));
+                    new base::FundamentalValue(setting));
     }
   }
 
diff --git a/chrome/browser/extensions/api/context_menus/OWNERS b/chrome/browser/extensions/api/context_menus/OWNERS
new file mode 100644
index 0000000..77dc8cc
--- /dev/null
+++ b/chrome/browser/extensions/api/context_menus/OWNERS
@@ -0,0 +1 @@
+yoz@chromium.org
diff --git a/chrome/browser/extensions/api/cookies/cookies_api.cc b/chrome/browser/extensions/api/cookies/cookies_api.cc
index afeaf8e..079be55 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api.cc
@@ -46,6 +46,7 @@
 namespace Set = extensions::api::cookies::Set;
 
 namespace extensions {
+namespace cookies = api::cookies;
 namespace keys = cookies_api_constants;
 
 CookiesEventRouter::CookiesEventRouter(Profile* profile)
@@ -123,7 +124,10 @@
 
   GURL cookie_domain =
       cookies_helpers::GetURLFromCanonicalCookie(*details->cookie);
-  DispatchEvent(profile, keys::kOnChanged, args.Pass(), cookie_domain);
+  DispatchEvent(profile,
+                cookies::OnChanged::kEventName,
+                args.Pass(),
+                cookie_domain);
 }
 
 void CookiesEventRouter::DispatchEvent(
@@ -557,7 +561,7 @@
 CookiesAPI::CookiesAPI(Profile* profile)
     : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnChanged);
+      this, cookies::OnChanged::kEventName);
 }
 
 CookiesAPI::~CookiesAPI() {
diff --git a/chrome/browser/extensions/api/cookies/cookies_api_constants.cc b/chrome/browser/extensions/api/cookies/cookies_api_constants.cc
index ebbde77..58876b8 100644
--- a/chrome/browser/extensions/api/cookies/cookies_api_constants.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_api_constants.cc
@@ -22,9 +22,6 @@
 extern const char kExplicitChangeCause[] = "explicit";
 extern const char kOverwriteChangeCause[] = "overwrite";
 
-// Events
-const char kOnChanged[] = "cookies.onChanged";
-
 // Errors
 const char kCookieSetFailedError[] =
     "Failed to parse or set cookie named \"*\".";
diff --git a/chrome/browser/extensions/api/cookies/cookies_helpers.cc b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
index fc578e8..b68146b 100644
--- a/chrome/browser/extensions/api/cookies/cookies_helpers.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_helpers.cc
@@ -151,7 +151,7 @@
   DCHECK(tab_ids);
   TabStripModel* tab_strip = browser->tab_strip_model();
   for (int i = 0; i < tab_strip->count(); ++i) {
-    tab_ids->Append(Value::CreateIntegerValue(
+    tab_ids->Append(new base::FundamentalValue(
         ExtensionTabUtil::GetTabId(tab_strip->GetWebContentsAt(i))));
   }
 }
@@ -206,4 +206,4 @@
 }
 
 }  // namespace cookies_helpers
-}  // namespace extension
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/cookies/cookies_unittest.cc b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
index 764e028..b5fda79 100644
--- a/chrome/browser/extensions/api/cookies/cookies_unittest.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
@@ -33,82 +33,50 @@
   const bool matches;
 };
 
-// A test profile that supports linking with another profile for incognito
-// support.
-class OtrTestingProfile : public TestingProfile {
- public:
-  OtrTestingProfile() : linked_profile_(NULL) {}
-  virtual Profile* GetOriginalProfile() OVERRIDE {
-    if (IsOffTheRecord())
-      return linked_profile_;
-    else
-      return this;
-  }
-
-  virtual Profile* GetOffTheRecordProfile() OVERRIDE {
-    if (IsOffTheRecord())
-      return this;
-    else
-      return linked_profile_;
-  }
-
-  virtual bool HasOffTheRecordProfile() OVERRIDE {
-    return (!IsOffTheRecord() && linked_profile_);
-  }
-
-  static void LinkProfiles(OtrTestingProfile* profile1,
-                           OtrTestingProfile* profile2) {
-    profile1->set_linked_profile(profile2);
-    profile2->set_linked_profile(profile1);
-  }
-
-  void set_linked_profile(OtrTestingProfile* profile) {
-    linked_profile_ = profile;
-  }
-
- private:
-  OtrTestingProfile* linked_profile_;
-};
-
 }  // namespace
 
 class ExtensionCookiesTest : public testing::Test {
 };
 
 TEST_F(ExtensionCookiesTest, StoreIdProfileConversion) {
-  OtrTestingProfile profile, otrProfile;
-  otrProfile.set_incognito(true);
-  OtrTestingProfile::LinkProfiles(&profile, &otrProfile);
+  TestingProfile::Builder profile_builder;
+  TestingProfile::Builder otr_profile_builder;
+  otr_profile_builder.SetIncognito();
+  scoped_ptr<TestingProfile> profile = profile_builder.Build();
+  scoped_ptr<TestingProfile> otr_profile = otr_profile_builder.Build();
+  otr_profile->SetOriginalProfile(profile.get());
+  profile->SetOffTheRecordProfile(otr_profile.PassAs<Profile>());
 
   EXPECT_EQ(std::string("0"),
-            cookies_helpers::GetStoreIdFromProfile(&profile));
-  EXPECT_EQ(&profile,
+            cookies_helpers::GetStoreIdFromProfile(profile.get()));
+  EXPECT_EQ(profile.get(),
             cookies_helpers::ChooseProfileFromStoreId(
-                "0", &profile, true));
-  EXPECT_EQ(&profile,
+                "0", profile.get(), true));
+  EXPECT_EQ(profile.get(),
             cookies_helpers::ChooseProfileFromStoreId(
-                "0", &profile, false));
-  EXPECT_EQ(&otrProfile,
+                "0", profile.get(), false));
+  EXPECT_EQ(profile->GetOffTheRecordProfile(),
             cookies_helpers::ChooseProfileFromStoreId(
-                "1", &profile, true));
+                "1", profile.get(), true));
   EXPECT_EQ(NULL,
             cookies_helpers::ChooseProfileFromStoreId(
-                "1", &profile, false));
+                "1", profile.get(), false));
 
   EXPECT_EQ(std::string("1"),
-            cookies_helpers::GetStoreIdFromProfile(&otrProfile));
+            cookies_helpers::GetStoreIdFromProfile(
+                profile->GetOffTheRecordProfile()));
   EXPECT_EQ(NULL,
             cookies_helpers::ChooseProfileFromStoreId(
-                "0", &otrProfile, true));
+                "0", profile->GetOffTheRecordProfile(), true));
   EXPECT_EQ(NULL,
             cookies_helpers::ChooseProfileFromStoreId(
-                "0", &otrProfile, false));
-  EXPECT_EQ(&otrProfile,
+                "0", profile->GetOffTheRecordProfile(), false));
+  EXPECT_EQ(profile->GetOffTheRecordProfile(),
             cookies_helpers::ChooseProfileFromStoreId(
-                "1", &otrProfile, true));
-  EXPECT_EQ(&otrProfile,
+                "1", profile->GetOffTheRecordProfile(), true));
+  EXPECT_EQ(profile->GetOffTheRecordProfile(),
             cookies_helpers::ChooseProfileFromStoreId(
-                "1", &otrProfile, false));
+                "1", profile->GetOffTheRecordProfile(), false));
 }
 
 TEST_F(ExtensionCookiesTest, ExtensionTypeCreation) {
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index f29ea9a..b2ca4c1 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -398,7 +398,7 @@
   scoped_ptr<base::ListValue> args(OnDetach::Create(debuggee_,
                                                     detach_reason_));
   scoped_ptr<extensions::Event> event(new extensions::Event(
-      keys::kOnDetach, args.Pass()));
+      OnDetach::kEventName, args.Pass()));
   event->restrict_to_profile = profile_;
   extensions::ExtensionSystem::Get(profile_)->event_router()->
       DispatchEventToExtension(extension_id_, event.Pass());
@@ -448,7 +448,7 @@
 
     scoped_ptr<ListValue> args(OnEvent::Create(debuggee_, method_name, params));
     scoped_ptr<extensions::Event> event(new extensions::Event(
-        keys::kOnEvent, args.Pass()));
+        OnEvent::kEventName, args.Pass()));
     event->restrict_to_profile = profile_;
     extensions::ExtensionSystem::Get(profile_)->event_router()->
         DispatchEventToExtension(extension_id_, event.Pass());
@@ -717,7 +717,7 @@
     dictionary->SetString(kTargetTitleField, web_contents->GetTitle());
 
     content::NavigationController& controller = web_contents->GetController();
-    content::NavigationEntry* entry = controller.GetActiveEntry();
+    content::NavigationEntry* entry = controller.GetVisibleEntry();
     if (entry != NULL && entry->GetURL().is_valid()) {
       dictionary->SetString(kTargetFaviconUrlField,
                             entry->GetFavicon().url.spec());
diff --git a/chrome/browser/extensions/api/debugger/debugger_api_constants.cc b/chrome/browser/extensions/api/debugger/debugger_api_constants.cc
index a9f5c6e..70da45b 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api_constants.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api_constants.cc
@@ -6,9 +6,6 @@
 
 namespace debugger_api_constants {
 
-const char kOnEvent[] = "debugger.onEvent";
-const char kOnDetach[] = "debugger.onDetach";
-
 const char kAlreadyAttachedError[] =
     "Another debugger is already attached to the * with id: *.";
 const char kAttachToWebUIError[] =
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
index 68123b9..07c1b1b 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
@@ -37,7 +37,7 @@
   scoped_refptr<const WebRequestConditionAttribute> result;
   StringValue string_value("main_frame");
   ListValue resource_types;
-  resource_types.Append(Value::CreateStringValue("main_frame"));
+  resource_types.Append(new base::StringValue("main_frame"));
 
   // Test wrong condition name passed.
   error.clear();
@@ -78,7 +78,7 @@
   ListValue resource_types;
   // The 'sub_frame' value is chosen arbitrarily, so as the corresponding
   // ResourceType::Type is not 0, the default value.
-  resource_types.Append(Value::CreateStringValue("sub_frame"));
+  resource_types.Append(new base::StringValue("sub_frame"));
 
   scoped_refptr<const WebRequestConditionAttribute> attribute =
       WebRequestConditionAttribute::Create(
@@ -125,7 +125,7 @@
   base::MessageLoop::current()->Run();
 
   ListValue content_types;
-  content_types.Append(Value::CreateStringValue("text/plain"));
+  content_types.Append(new base::StringValue("text/plain"));
   scoped_refptr<const WebRequestConditionAttribute> attribute_include =
       WebRequestConditionAttribute::Create(
           keys::kContentTypeKey, &content_types, &error);
@@ -149,7 +149,7 @@
                      url_request.response_headers())));
 
   content_types.Clear();
-  content_types.Append(Value::CreateStringValue("something/invalid"));
+  content_types.Append(new base::StringValue("something/invalid"));
   scoped_refptr<const WebRequestConditionAttribute> attribute_unincluded =
       WebRequestConditionAttribute::Create(
           keys::kContentTypeKey, &content_types, &error);
@@ -358,12 +358,12 @@
           // Ignoring return value, we already verified the entry is there.
           dictionary->RemoveWithoutPathExpansion(*name, &entry_owned);
           list->Append(entry_owned.release());
-          list->Append(Value::CreateStringValue(*value));
+          list->Append(new base::StringValue(*value));
           dictionary->SetWithoutPathExpansion(*name, list);
           break;
         case Value::TYPE_LIST:  // Just append to the list.
           CHECK(entry->GetAsList(&list));
-          list->Append(Value::CreateStringValue(*value));
+          list->Append(new base::StringValue(*value));
           break;
         default:
           NOTREACHED();  // We never put other Values here.
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
index aa9bf22..2b34514 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
@@ -95,7 +95,7 @@
   // https://www.example.com and cancels it
   linked_ptr<RulesRegistry::Rule> CreateRule1() {
     base::ListValue* scheme_http = new base::ListValue();
-    scheme_http->Append(Value::CreateStringValue("http"));
+    scheme_http->Append(new base::StringValue("http"));
     base::DictionaryValue* http_condition_dict = new base::DictionaryValue();
     http_condition_dict->Set(keys2::kSchemesKey, scheme_http);
     http_condition_dict->SetString(keys2::kHostSuffixKey, "example.com");
@@ -105,7 +105,7 @@
                                         keys::kRequestMatcherType);
 
     base::ListValue* scheme_https = new base::ListValue();
-    scheme_http->Append(Value::CreateStringValue("https"));
+    scheme_http->Append(new base::StringValue("https"));
     base::DictionaryValue* https_condition_dict = new base::DictionaryValue();
     https_condition_dict->Set(keys2::kSchemesKey, scheme_https);
     https_condition_dict->SetString(keys2::kHostSuffixKey, "example.com");
diff --git a/chrome/browser/extensions/api/desktop_capture/DEPS b/chrome/browser/extensions/api/desktop_capture/DEPS
new file mode 100644
index 0000000..e566fc7
--- /dev/null
+++ b/chrome/browser/extensions/api/desktop_capture/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/webrtc",
+]
diff --git a/chrome/browser/extensions/api/desktop_capture/OWNERS b/chrome/browser/extensions/api/desktop_capture/OWNERS
new file mode 100644
index 0000000..3a3e574
--- /dev/null
+++ b/chrome/browser/extensions/api/desktop_capture/OWNERS
@@ -0,0 +1,2 @@
+sergeyu@chromium.org
+wez@chromium.org
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc
new file mode 100644
index 0000000..f988d7c
--- /dev/null
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.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 "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/media/desktop_streams_registry.h"
+#include "chrome/browser/media/media_capture_devices_dispatcher.h"
+#include "content/public/browser/browser_thread.h"
+#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
+#include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
+
+namespace extensions {
+
+namespace {
+
+const char kNotImplementedError[] =
+    "Desktop Capture API is not yet implemented for this platform.";
+const char kInvalidSourceNameError[] = "Invalid source type specified.";
+const char kEmptySourcesListError[] =
+    "At least one source type must be specified.";
+const char kTabCaptureNotSupportedError[] = "Tab capture is not supported yet.";
+
+DesktopCaptureChooseDesktopMediaFunction::PickerFactory* g_picker_factory =
+    NULL;
+
+}  // namespace
+
+// static
+void DesktopCaptureChooseDesktopMediaFunction::SetPickerFactoryForTests(
+    PickerFactory* factory) {
+  g_picker_factory = factory;
+}
+
+DesktopCaptureChooseDesktopMediaFunction::
+DesktopCaptureChooseDesktopMediaFunction() {
+}
+
+DesktopCaptureChooseDesktopMediaFunction::
+~DesktopCaptureChooseDesktopMediaFunction() {
+}
+
+bool DesktopCaptureChooseDesktopMediaFunction::RunImpl() {
+  scoped_ptr<api::desktop_capture::ChooseDesktopMedia::Params> params =
+      api::desktop_capture::ChooseDesktopMedia::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  scoped_ptr<webrtc::ScreenCapturer> screen_capturer;
+  scoped_ptr<webrtc::WindowCapturer> window_capturer;
+
+  for (std::vector<api::desktop_capture::DesktopCaptureSourceType>::iterator
+       it = params->sources.begin(); it != params->sources.end(); ++it) {
+    switch (*it) {
+      case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_NONE:
+        error_ = kInvalidSourceNameError;
+        return false;
+
+      case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_SCREEN:
+        screen_capturer.reset(webrtc::ScreenCapturer::Create());
+        break;
+
+      case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_WINDOW:
+        window_capturer.reset(webrtc::WindowCapturer::Create());
+        break;
+
+      case api::desktop_capture::DESKTOP_CAPTURE_SOURCE_TYPE_TAB:
+        error_ = kTabCaptureNotSupportedError;
+        return false;
+    }
+  }
+
+  if (!screen_capturer && !window_capturer) {
+    error_ = kEmptySourcesListError;
+    return false;
+  }
+
+  if (params->origin) {
+    origin_ = GURL(*(params->origin));
+  } else {
+    origin_ = GetExtension()->url();
+  }
+
+  scoped_ptr<DesktopMediaPickerModel> model;
+  if (g_picker_factory) {
+    model = g_picker_factory->CreateModel(
+        screen_capturer.Pass(), window_capturer.Pass());
+    picker_ = g_picker_factory->CreatePicker();
+  } else {
+    // Currently DesktopMediaPicker is implemented only for platforms that
+    // use Views.
+#if defined(TOOLKIT_VIEWS)
+    model.reset(new DesktopMediaPickerModel(
+        screen_capturer.Pass(), window_capturer.Pass()));
+    picker_ = DesktopMediaPicker::Create();
+#else
+    error_ = kNotImplementedError;
+    return false;
+#endif
+  }
+  DesktopMediaPicker::DoneCallback callback = base::Bind(
+      &DesktopCaptureChooseDesktopMediaFunction::OnPickerDialogResults, this);
+  picker_->Show(NULL, NULL, UTF8ToUTF16(GetExtension()->name()),
+                model.Pass(), callback);
+  return true;
+}
+
+void DesktopCaptureChooseDesktopMediaFunction::OnPickerDialogResults(
+    content::DesktopMediaID source) {
+  std::string result;
+  if (source.type != content::DesktopMediaID::TYPE_NONE) {
+    DesktopStreamsRegistry* registry =
+        MediaCaptureDevicesDispatcher::GetInstance()->
+        GetDesktopStreamsRegistry();
+    result = registry->RegisterStream(origin_, source);
+  }
+
+  SetResult(new base::StringValue(result));
+  SendResponse(true);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h
new file mode 100644
index 0000000..9efab29
--- /dev/null
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.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_BROWSER_EXTENSIONS_API_DESKTOP_CAPTURE_DESKTOP_CAPTURE_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_DESKTOP_CAPTURE_DESKTOP_CAPTURE_API_H_
+
+#include "chrome/browser/extensions/api/api_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"
+#include "url/gurl.h"
+
+namespace extensions {
+
+class DesktopCaptureChooseDesktopMediaFunction : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("desktopCapture.chooseDesktopMedia",
+                             DESKTOPCAPTURE_CHOOSEDESKTOPMEDIA)
+
+  // Factory creating DesktopMediaPickerModel and DesktopMediaPicker instances.
+  // Used for tests to supply fake picker.
+  class PickerFactory {
+   public:
+    virtual scoped_ptr<DesktopMediaPickerModel> CreateModel(
+        scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
+        scoped_ptr<webrtc::WindowCapturer> window_capturer) = 0;
+    virtual scoped_ptr<DesktopMediaPicker> CreatePicker() = 0;
+   protected:
+    virtual ~PickerFactory() {}
+  };
+
+  // Used to set PickerFactory used to create mock DesktopMediaPicker instances
+  // for tests. Calling tests keep ownership of the factory. Can be called with
+  // |factory| set to NULL at the end of the test.
+  static void SetPickerFactoryForTests(PickerFactory* factory);
+
+  DesktopCaptureChooseDesktopMediaFunction();
+
+ private:
+  virtual ~DesktopCaptureChooseDesktopMediaFunction();
+
+  // ExtensionFunction overrides.
+  virtual bool RunImpl() OVERRIDE;
+
+  void OnPickerDialogResults(content::DesktopMediaID source);
+
+  // Origin parameter specified when chooseDesktopMedia() was called. Indicates
+  // origin of the target page to use the media source chosen by the user.
+  GURL origin_;
+
+  scoped_ptr<DesktopMediaPicker> picker_;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_DESKTOP_CAPTURE_DESKTOP_CAPTURE_API_H_
diff --git a/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.cc
new file mode 100644
index 0000000..9bca4de
--- /dev/null
+++ b/chrome/browser/extensions/api/desktop_capture/desktop_capture_apitest.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 <queue>
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/media/desktop_media_picker.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
+#include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
+
+namespace extensions {
+
+namespace {
+
+class FakeDesktopMediaPicker : public DesktopMediaPicker {
+ public:
+  explicit FakeDesktopMediaPicker(const content::DesktopMediaID& source)
+      : source_(source),
+        weak_factory_(this) {
+  }
+  virtual ~FakeDesktopMediaPicker() {}
+
+  // DesktopMediaPicker interface.
+  virtual void Show(gfx::NativeWindow context,
+                    gfx::NativeWindow parent,
+                    const string16& app_name,
+                    scoped_ptr<DesktopMediaPickerModel> model,
+                    const DoneCallback& done_callback) OVERRIDE {
+    // Post a task to call the callback asynchronously.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&FakeDesktopMediaPicker::CallCallback,
+                            weak_factory_.GetWeakPtr(), done_callback));
+  }
+
+ private:
+  void CallCallback(DoneCallback done_callback) {
+    done_callback.Run(source_);
+  }
+
+  content::DesktopMediaID source_;
+
+  base::WeakPtrFactory<FakeDesktopMediaPicker> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDesktopMediaPicker);
+};
+
+class FakeDesktopMediaPickerFactory :
+    public DesktopCaptureChooseDesktopMediaFunction::PickerFactory {
+ public:
+  struct Expectation {
+    bool screens;
+    bool windows;
+    content::DesktopMediaID selected_source;
+  };
+
+  FakeDesktopMediaPickerFactory() {}
+  virtual ~FakeDesktopMediaPickerFactory() {}
+
+  void SetExpectations(const Expectation* expectation_array, int size) {
+    for (int i = 0; i < size; ++i) {
+      expectations_.push(expectation_array[i]);
+    }
+  }
+
+  // DesktopCaptureChooseDesktopMediaFunction::PickerFactory interface.
+  virtual scoped_ptr<DesktopMediaPickerModel> CreateModel(
+      scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
+      scoped_ptr<webrtc::WindowCapturer> window_capturer) OVERRIDE {
+    EXPECT_TRUE(!expectations_.empty());
+    if (!expectations_.empty()) {
+      EXPECT_EQ(expectations_.front().screens, !!screen_capturer.get());
+      EXPECT_EQ(expectations_.front().windows, !!window_capturer.get());
+    }
+    return scoped_ptr<DesktopMediaPickerModel>(
+        new DesktopMediaPickerModel(screen_capturer.Pass(),
+                                    window_capturer.Pass()));
+  }
+  virtual scoped_ptr<DesktopMediaPicker> CreatePicker() OVERRIDE {
+    content::DesktopMediaID next_source;
+    if (!expectations_.empty()) {
+      next_source = expectations_.front().selected_source;
+      expectations_.pop();
+    }
+    return scoped_ptr<DesktopMediaPicker>(
+        new FakeDesktopMediaPicker(next_source));
+  }
+
+ private:
+  std::queue<Expectation> expectations_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDesktopMediaPickerFactory);
+};
+
+class DesktopCaptureApiTest : public ExtensionApiTest {
+ public:
+  DesktopCaptureApiTest() {
+    DesktopCaptureChooseDesktopMediaFunction::
+        SetPickerFactoryForTests(&picker_factory_);
+  }
+  virtual ~DesktopCaptureApiTest() {
+    DesktopCaptureChooseDesktopMediaFunction::
+        SetPickerFactoryForTests(NULL);
+  }
+
+ protected:
+  GURL GetURLForPath(const std::string& host, const std::string& path) {
+    std::string port = base::IntToString(embedded_test_server()->port());
+    GURL::Replacements replacements;
+    replacements.SetHostStr(host);
+    replacements.SetPortStr(port);
+    return embedded_test_server()->GetURL(path).ReplaceComponents(replacements);
+  }
+
+  FakeDesktopMediaPickerFactory picker_factory_;
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, 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[] = {
+    // pickerUiCanceled()
+    { true, true,
+      content::DesktopMediaID() },
+    // chooseMedia()
+    { true, true,
+      content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
+    // screensOnly()
+    { true, false,
+      content::DesktopMediaID() },
+    // WindowsOnly()
+    { false, true,
+      content::DesktopMediaID() },
+    // chooseMediaAndGetStream()
+    { true, true,
+      content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
+    // chooseMediaAndTryGetStreamWithInvalidId()
+    { true, true,
+      content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
+  };
+  picker_factory_.SetExpectations(picker_expectations,
+                                  arraysize(picker_expectations));
+  ASSERT_TRUE(RunExtensionTest("desktop_capture")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, Delegation) {
+  // Initialize test server.
+  base::FilePath test_data;
+  EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
+  embedded_test_server()->ServeFilesFromDirectory(test_data.AppendASCII(
+      "extensions/api_test/desktop_capture_delegate"));
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
+
+  // Load extension.
+  base::FilePath extension_path =
+      test_data_dir_.AppendASCII("desktop_capture_delegate");
+  const Extension* extension = LoadExtensionWithFlags(
+      extension_path, ExtensionBrowserTest::kFlagNone);
+  ASSERT_TRUE(extension);
+
+  ui_test_utils::NavigateToURL(
+      browser(), GetURLForPath("example.com", "/example.com.html"));
+
+  FakeDesktopMediaPickerFactory::Expectation picker_expectations[] = {
+    { true, true,
+      content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
+    { true, true,
+      content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
+  };
+  picker_factory_.SetExpectations(picker_expectations,
+                                  arraysize(picker_expectations));
+
+  bool result;
+
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "getStream()", &result));
+  EXPECT_TRUE(result);
+
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "getStreamWithInvalidId()", &result));
+  EXPECT_TRUE(result);
+}
+
+}  // namespace extensions
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 a7d8732..e1fd58b 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h"
 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/extension_disabled_ui.h"
 #include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -72,7 +71,7 @@
 
 namespace extensions {
 
-namespace events = event_names;
+namespace developer_private = api::developer_private;
 
 namespace {
 
@@ -212,7 +211,7 @@
   scoped_ptr<ListValue> args(new ListValue());
   args->Append(event_data.ToValue().release());
 
-  event_name = events::kDeveloperPrivateOnItemStateChanged;
+  event_name = developer_private::OnItemStateChanged::kEventName;
   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
   ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
 }
@@ -223,7 +222,7 @@
 
 void DeveloperPrivateAPI::RegisterNotifications() {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, events::kDeveloperPrivateOnItemStateChanged);
+      this, developer_private::OnItemStateChanged::kEventName);
 }
 
 DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
@@ -240,7 +239,7 @@
 void DeveloperPrivateAPI::OnListenerRemoved(
     const EventListenerInfo& details) {
   if (!ExtensionSystem::Get(profile_)->event_router()->HasEventListener(
-          event_names::kDeveloperPrivateOnItemStateChanged))
+          developer_private::OnItemStateChanged::kEventName))
     developer_private_event_router_.reset(NULL);
 }
 
@@ -250,7 +249,7 @@
   ExtensionUpdater* updater = GetExtensionUpdater(profile());
   if (updater)
     updater->CheckNow(ExtensionUpdater::CheckParams());
-  SetResult(Value::CreateBooleanValue(true));
+  SetResult(new base::FundamentalValue(true));
   return true;
 }
 
@@ -304,7 +303,6 @@
              item.install_warnings().begin();
          it != item.install_warnings().end(); ++it) {
       developer::InstallWarning* warning = new developer::InstallWarning();
-      warning->is_html = (it->format == InstallWarning::FORMAT_HTML);
       warning->message = it->message;
       info->install_warnings.push_back(make_linked_ptr(warning));
     }
@@ -362,7 +360,8 @@
         constructInspectView(web_contents->GetURL(),
                              process->GetID(),
                              host->GetRoutingID(),
-                             process->GetBrowserContext()->IsOffTheRecord()));
+                             process->GetBrowserContext()->IsOffTheRecord(),
+                             false));
   }
 }
 
@@ -385,7 +384,8 @@
         constructInspectView(web_contents->GetURL(),
                              process->GetID(),
                              host->GetRoutingID(),
-                             process->GetBrowserContext()->IsOffTheRecord()));
+                             process->GetBrowserContext()->IsOffTheRecord(),
+                             false));
   }
 }
 
@@ -394,7 +394,8 @@
         const GURL& url,
         int render_process_id,
         int render_view_id,
-        bool incognito) {
+        bool incognito,
+        bool generated_background_page) {
   linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView());
 
   if (url.scheme() == kExtensionScheme) {
@@ -408,6 +409,7 @@
   view->render_process_id = render_process_id;
   view->render_view_id = render_view_id;
   view->incognito = incognito;
+  view->generated_background_page = generated_background_page;
   return view;
 }
 
@@ -432,7 +434,11 @@
       extension_is_enabled &&
       !process_manager->GetBackgroundHostForExtension(extension->id())) {
     result.push_back(constructInspectView(
-        BackgroundInfo::GetBackgroundURL(extension), -1, -1, false));
+        BackgroundInfo::GetBackgroundURL(extension),
+        -1,
+        -1,
+        false,
+        BackgroundInfo::HasGeneratedBackgroundPage(extension)));
   }
 
   ExtensionService* service = profile()->GetExtensionService();
@@ -450,7 +456,11 @@
         extension_is_enabled &&
         !process_manager->GetBackgroundHostForExtension(extension->id())) {
     result.push_back(constructInspectView(
-        BackgroundInfo::GetBackgroundURL(extension), -1, -1, false));
+        BackgroundInfo::GetBackgroundURL(extension),
+        -1,
+        -1,
+        false,
+        BackgroundInfo::HasGeneratedBackgroundPage(extension)));
     }
   }
 
@@ -485,20 +495,9 @@
        iter != items.end(); ++iter) {
     const Extension& item = *iter->get();
 
-    // Don't show component extensions because they are only extensions as an
-    // implementation detail of Chrome.
-    if (item.location() == Manifest::COMPONENT &&
-        !CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kShowComponentExtensionOptions)) {
+    // Don't show component extensions and invisible apps.
+    if (item.ShouldNotBeVisible())
       continue;
-    }
-
-    // Don't show apps that aren't visible in either launcher or ntp.
-    if (item.is_app() && !item.ShouldDisplayInAppLauncher() &&
-        !item.ShouldDisplayInNewTabPage() &&
-        !Manifest::IsUnpackedLocation(item.location())) {
-      continue;
-    }
 
     item_list.push_back(make_linked_ptr<developer::ItemInfo>(
         CreateItemInfo(
@@ -1095,7 +1094,7 @@
   const Extension* extension = GetExtensionByPath(extensions, path);
   bool success = true;
   if (extension) {
-    SetResult(base::Value::CreateStringValue(extension->id()));
+    SetResult(new base::StringValue(extension->id()));
   } else {
     SetError("unable to load the project");
     success = false;
@@ -1154,7 +1153,7 @@
 
 void DeveloperPrivateChoosePathFunction::FileSelected(
     const base::FilePath& path) {
-  SetResult(base::Value::CreateStringValue(
+  SetResult(new base::StringValue(
       UTF16ToUTF8(path.LossyDisplayName())));
   SendResponse(true);
   Release();
@@ -1198,6 +1197,7 @@
              IDS_EXTENSIONS_INSTALL_WARNINGS);
   SET_STRING("viewIncognito", IDS_EXTENSIONS_VIEW_INCOGNITO);
   SET_STRING("viewInactive", IDS_EXTENSIONS_VIEW_INACTIVE);
+  SET_STRING("backgroundPage", IDS_EXTENSIONS_BACKGROUND_PAGE);
   SET_STRING("extensionSettingsEnable", IDS_EXTENSIONS_ENABLE);
   SET_STRING("extensionSettingsEnabled", IDS_EXTENSIONS_ENABLED);
   SET_STRING("extensionSettingsRemove", IDS_EXTENSIONS_REMOVE);
@@ -1207,7 +1207,8 @@
              IDS_EXTENSIONS_ALLOW_FILE_ACCESS);
   SET_STRING("extensionSettingsReloadTerminated",
              IDS_EXTENSIONS_RELOAD_TERMINATED);
-  SET_STRING("extensionSettingsReloadUnpacked", IDS_EXTENSIONS_RELOAD_UNPACKED);
+  SET_STRING("extensionSettingsReloadUnpacked",
+             IDS_APPS_DEV_TOOLS_RELOAD_UNPACKED);
   SET_STRING("extensionSettingsLaunch", IDS_EXTENSIONS_LAUNCH);
   SET_STRING("extensionSettingsRestart", IDS_EXTENSIONS_RESTART);
   SET_STRING("extensionSettingsOptions", IDS_EXTENSIONS_OPTIONS_LINK);
@@ -1242,7 +1243,7 @@
 // Pack Extension strings
   SET_STRING("packExtensionOverlay", IDS_EXTENSION_PACK_DIALOG_TITLE);
   SET_STRING("packExtensionHeading", IDS_EXTENSION_ADT_PACK_DIALOG_HEADING);
-  SET_STRING("packExtensionCommit", IDS_EXTENSION_PACK_BUTTON);
+  SET_STRING("packButton", IDS_EXTENSION_ADT_PACK_BUTTON);
   SET_STRING("ok", IDS_OK);
   SET_STRING("cancel", IDS_CANCEL);
   SET_STRING("packExtensionRootDir",
@@ -1253,6 +1254,8 @@
   SET_STRING("packExtensionProceedAnyway", IDS_EXTENSION_PROCEED_ANYWAY);
   SET_STRING("packExtensionWarningTitle", IDS_EXTENSION_PACK_WARNING_TITLE);
   SET_STRING("packExtensionErrorTitle", IDS_EXTENSION_PACK_ERROR_TITLE);
+  SET_STRING("packAppOverlay", IDS_EXTENSION_PACK_APP_DIALOG_TITLE);
+  SET_STRING("packAppHeading", IDS_EXTENSION_ADT_PACK_APP_DIALOG_HEADING);
 
 // Delete confirmation dialog.
   SET_STRING("deleteConfirmationDeleteButton",
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 567f2d9..ce86299 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -166,7 +166,8 @@
       const GURL& url,
       int render_process_id,
       int render_view_id,
-      bool incognito);
+      bool incognito,
+      bool generated_background_page);
 };
 
 class DeveloperPrivateInspectFunction : public SyncExtensionFunction {
diff --git a/chrome/browser/extensions/api/dial/OWNERS b/chrome/browser/extensions/api/dial/OWNERS
new file mode 100644
index 0000000..cb84d70
--- /dev/null
+++ b/chrome/browser/extensions/api/dial/OWNERS
@@ -0,0 +1,2 @@
+justinlin@chromium.org
+mfoltz@chromium.org
diff --git a/chrome/browser/extensions/api/dial/dial_api.cc b/chrome/browser/extensions/api/dial/dial_api.cc
index 2a30d9a..062fc6f 100644
--- a/chrome/browser/extensions/api/dial/dial_api.cc
+++ b/chrome/browser/extensions/api/dial/dial_api.cc
@@ -8,7 +8,6 @@
 
 #include "base/time/time.h"
 #include "chrome/browser/extensions/api/dial/dial_api_factory.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
@@ -35,11 +34,13 @@
 
 namespace extensions {
 
+namespace dial = api::dial;
+
 DialAPI::DialAPI(Profile* profile)
     : RefcountedBrowserContextKeyedService(BrowserThread::IO),
       profile_(profile) {
   ExtensionSystem::Get(profile)->event_router()->RegisterObserver(
-      this, extensions::event_names::kOnDialDeviceList);
+      this, dial::OnDeviceList::kEventName);
 }
 
 DialAPI::~DialAPI() {}
@@ -106,7 +107,7 @@
   }
   scoped_ptr<base::ListValue> results = api::dial::OnDeviceList::Create(args);
   scoped_ptr<Event> event(
-      new Event(event_names::kOnDialDeviceList, results.Pass()));
+      new Event(dial::OnDeviceList::kEventName, results.Pass()));
   extensions::ExtensionSystem::Get(profile_)->event_router()->
       BroadcastEvent(event.Pass());
 }
@@ -137,7 +138,7 @@
   }
 
   scoped_ptr<base::ListValue> results = api::dial::OnError::Create(dial_error);
-  scoped_ptr<Event> event(new Event(event_names::kOnDialError, results.Pass()));
+  scoped_ptr<Event> event(new Event(dial::OnError::kEventName, results.Pass()));
   extensions::ExtensionSystem::Get(profile_)->event_router()->
       BroadcastEvent(event.Pass());
 }
@@ -167,7 +168,7 @@
   if (!result_)
     error_ = kDialServiceError;
 
-  SetResult(base::Value::CreateBooleanValue(result_));
+  SetResult(new base::FundamentalValue(result_));
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/dial/dial_device_data.cc b/chrome/browser/extensions/api/dial/dial_device_data.cc
index 125317d..f8f5540 100644
--- a/chrome/browser/extensions/api/dial/dial_device_data.cc
+++ b/chrome/browser/extensions/api/dial/dial_device_data.cc
@@ -29,8 +29,7 @@
 
 // static
 bool DialDeviceData::IsDeviceDescriptionUrl(const GURL& url) {
-  return url.is_valid() && !url.is_empty() &&
-      (url.SchemeIs("http") || url.SchemeIs("https"));
+  return url.is_valid() && !url.is_empty() && url.SchemeIsHTTPOrHTTPS();
 }
 
 bool DialDeviceData::UpdateFrom(const DialDeviceData& new_data) {
diff --git a/chrome/browser/extensions/api/discovery/discovery_api_unittest.cc b/chrome/browser/extensions/api/discovery/discovery_api_unittest.cc
index 223bc16..c01a226 100644
--- a/chrome/browser/extensions/api/discovery/discovery_api_unittest.cc
+++ b/chrome/browser/extensions/api/discovery/discovery_api_unittest.cc
@@ -58,7 +58,7 @@
 std::string RemoveSuggestionParamsToJSON(const std::string& link_url) {
   std::string result;
   base::ListValue params;
-  params.Append(base::Value::CreateStringValue(link_url));
+  params.Append(new base::StringValue(link_url));
   base::JSONWriter::Write(&params, &result);
   return result;
 }
diff --git a/chrome/browser/extensions/api/dns/dns_api.cc b/chrome/browser/extensions/api/dns/dns_api.cc
index 1c91f41..07eff86 100644
--- a/chrome/browser/extensions/api/dns/dns_api.cc
+++ b/chrome/browser/extensions/api/dns/dns_api.cc
@@ -60,9 +60,12 @@
 
   net::HostResolver::RequestInfo request_info(host_port_pair);
   int resolve_result = host_resolver->Resolve(
-      request_info, addresses_.get(),
+      request_info,
+      net::DEFAULT_PRIORITY,
+      addresses_.get(),
       base::Bind(&DnsResolveFunction::OnLookupFinished, this),
-      request_handle_.get(), net::BoundNetLog());
+      request_handle_.get(),
+      net::BoundNetLog());
 
   // Balanced in OnLookupFinished.
   AddRef();
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 9f7dc63..aeeac02 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -38,7 +38,6 @@
 #include "chrome/browser/download/download_shelf.h"
 #include "chrome/browser/download/download_stats.h"
 #include "chrome/browser/download/download_util.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_info_map.h"
@@ -79,8 +78,6 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/webui/web_ui_util.h"
 
-namespace events = extensions::event_names;
-
 using content::BrowserContext;
 using content::BrowserThread;
 using content::DownloadItem;
@@ -121,6 +118,8 @@
 
 namespace {
 
+namespace downloads = extensions::api::downloads;
+
 // Default icon size for getFileIcon() in pixels.
 const int  kDefaultIconSize = 32;
 
@@ -476,7 +475,7 @@
 }
 
 void RunDownloadQuery(
-    const extensions::api::downloads::DownloadQuery& query_in,
+    const downloads::DownloadQuery& query_in,
     DownloadManager* manager,
     DownloadManager* incognito_manager,
     std::string* error,
@@ -503,7 +502,7 @@
   }
 
   std::string state_string =
-      extensions::api::downloads::ToString(query_in.state);
+      downloads::ToString(query_in.state);
   if (!state_string.empty()) {
     DownloadItem::DownloadState state = StateEnumFromString(state_string);
     if (state == DownloadItem::MAX_DOWNLOAD_STATE) {
@@ -513,7 +512,7 @@
     query_out.AddFilter(state);
   }
   std::string danger_string =
-      extensions::api::downloads::ToString(query_in.danger);
+      downloads::ToString(query_in.danger);
   if (!danger_string.empty()) {
     content::DownloadDangerType danger_type = DangerEnumFromString(
         danger_string);
@@ -559,14 +558,14 @@
 }
 
 DownloadPathReservationTracker::FilenameConflictAction ConvertConflictAction(
-    extensions::api::downloads::FilenameConflictAction action) {
+    downloads::FilenameConflictAction action) {
   switch (action) {
-    case extensions::api::downloads::FILENAME_CONFLICT_ACTION_NONE:
-    case extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY:
+    case downloads::FILENAME_CONFLICT_ACTION_NONE:
+    case downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY:
       return DownloadPathReservationTracker::UNIQUIFY;
-    case extensions::api::downloads::FILENAME_CONFLICT_ACTION_OVERWRITE:
+    case downloads::FILENAME_CONFLICT_ACTION_OVERWRITE:
       return DownloadPathReservationTracker::OVERWRITE;
-    case extensions::api::downloads::FILENAME_CONFLICT_ACTION_PROMPT:
+    case downloads::FILENAME_CONFLICT_ACTION_PROMPT:
       return DownloadPathReservationTracker::PROMPT;
   }
   NOTREACHED();
@@ -592,9 +591,9 @@
         changed_fired_(0),
         json_(json_item.Pass()),
         creator_conflict_action_(
-            extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY),
+            downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY),
         determined_conflict_action_(
-            extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) {
+            downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     download_item->SetUserData(kKey, this);
   }
@@ -630,7 +629,7 @@
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     determined_filename_.clear();
     determined_conflict_action_ =
-      extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
+      downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
     determiner_ = DeterminerInfo();
     filename_no_change_ = base::Closure();
     filename_change_ = ExtensionDownloadsEventRouter::FilenameChangedCallback();
@@ -677,7 +676,7 @@
 
   void CreatorSuggestedFilename(
       const base::FilePath& filename,
-      extensions::api::downloads::FilenameConflictAction conflict_action) {
+      downloads::FilenameConflictAction conflict_action) {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     creator_suggested_filename_ = filename;
     creator_conflict_action_ = conflict_action;
@@ -687,7 +686,7 @@
     return creator_suggested_filename_;
   }
 
-  extensions::api::downloads::FilenameConflictAction
+  downloads::FilenameConflictAction
   creator_conflict_action() const {
     return creator_conflict_action_;
   }
@@ -696,7 +695,7 @@
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     creator_suggested_filename_.clear();
     creator_conflict_action_ =
-      extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
+      downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY;
   }
 
   // Returns false if this |extension_id| was not expected or if this
@@ -706,7 +705,7 @@
       Profile* profile,
       const std::string& extension_id,
       const base::FilePath& filename,
-      extensions::api::downloads::FilenameConflictAction conflict_action) {
+      downloads::FilenameConflictAction conflict_action) {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     bool found_info = false;
     for (size_t index = 0; index < determiners_.size(); ++index) {
@@ -803,10 +802,10 @@
   DeterminerInfoVector determiners_;
 
   base::FilePath creator_suggested_filename_;
-  extensions::api::downloads::FilenameConflictAction
+  downloads::FilenameConflictAction
     creator_conflict_action_;
   base::FilePath determined_filename_;
-  extensions::api::downloads::FilenameConflictAction
+  downloads::FilenameConflictAction
     determined_conflict_action_;
   DeterminerInfo determiner_;
 
@@ -957,10 +956,10 @@
 DownloadsDownloadFunction::~DownloadsDownloadFunction() {}
 
 bool DownloadsDownloadFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Download::Params> params(
-      extensions::api::downloads::Download::Params::Create(*args_));
+  scoped_ptr<downloads::Download::Params> params(
+      downloads::Download::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  const extensions::api::downloads::DownloadOptions& options = params->options;
+  const downloads::DownloadOptions& options = params->options;
   GURL download_url(options.url);
   if (Fault(!download_url.is_valid(), errors::kInvalidURL, &error_))
     return false;
@@ -1000,7 +999,7 @@
     download_params->set_prompt(*options.save_as.get());
 
   if (options.headers.get()) {
-    typedef extensions::api::downloads::HeaderNameValuePair HeaderNameValuePair;
+    typedef downloads::HeaderNameValuePair HeaderNameValuePair;
     for (std::vector<linked_ptr<HeaderNameValuePair> >::const_iterator iter =
          options.headers->begin();
          iter != options.headers->end();
@@ -1015,7 +1014,7 @@
   }
 
   std::string method_string =
-      extensions::api::downloads::ToString(options.method);
+      downloads::ToString(options.method);
   if (!method_string.empty())
     download_params->set_method(method_string);
   if (options.body.get())
@@ -1036,14 +1035,14 @@
 
 void DownloadsDownloadFunction::OnStarted(
     const base::FilePath& creator_suggested_filename,
-    extensions::api::downloads::FilenameConflictAction creator_conflict_action,
+    downloads::FilenameConflictAction creator_conflict_action,
     DownloadItem* item,
     net::Error error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   VLOG(1) << __FUNCTION__ << " " << item << " " << error;
   if (item) {
     DCHECK_EQ(net::OK, error);
-    SetResult(base::Value::CreateIntegerValue(item->GetId()));
+    SetResult(new base::FundamentalValue(static_cast<int>(item->GetId())));
     if (!creator_suggested_filename.empty()) {
       ExtensionDownloadsEventRouterData* data =
           ExtensionDownloadsEventRouterData::Get(item);
@@ -1070,8 +1069,8 @@
 DownloadsSearchFunction::~DownloadsSearchFunction() {}
 
 bool DownloadsSearchFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Search::Params> params(
-      extensions::api::downloads::Search::Params::Create(*args_));
+  scoped_ptr<downloads::Search::Params> params(
+      downloads::Search::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DownloadManager* manager = NULL;
   DownloadManager* incognito_manager = NULL;
@@ -1109,8 +1108,8 @@
 DownloadsPauseFunction::~DownloadsPauseFunction() {}
 
 bool DownloadsPauseFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Pause::Params> params(
-      extensions::api::downloads::Pause::Params::Create(*args_));
+  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);
@@ -1130,8 +1129,8 @@
 DownloadsResumeFunction::~DownloadsResumeFunction() {}
 
 bool DownloadsResumeFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Resume::Params> params(
-      extensions::api::downloads::Resume::Params::Create(*args_));
+  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);
@@ -1151,8 +1150,8 @@
 DownloadsCancelFunction::~DownloadsCancelFunction() {}
 
 bool DownloadsCancelFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Resume::Params> params(
-      extensions::api::downloads::Resume::Params::Create(*args_));
+  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);
@@ -1170,8 +1169,8 @@
 DownloadsEraseFunction::~DownloadsEraseFunction() {}
 
 bool DownloadsEraseFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Erase::Params> params(
-      extensions::api::downloads::Erase::Params::Create(*args_));
+  scoped_ptr<downloads::Erase::Params> params(
+      downloads::Erase::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DownloadManager* manager = NULL;
   DownloadManager* incognito_manager = NULL;
@@ -1187,7 +1186,8 @@
   base::ListValue* json_results = new base::ListValue();
   for (DownloadManager::DownloadVector::const_iterator it = results.begin();
        it != results.end(); ++it) {
-    json_results->Append(base::Value::CreateIntegerValue((*it)->GetId()));
+    json_results->Append(
+        new base::FundamentalValue(static_cast<int>((*it)->GetId())));
     (*it)->Remove();
   }
   SetResult(json_results);
@@ -1205,8 +1205,8 @@
 }
 
 bool DownloadsRemoveFileFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::RemoveFile::Params> params(
-      extensions::api::downloads::RemoveFile::Params::Create(*args_));
+  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);
@@ -1246,8 +1246,8 @@
 DownloadsAcceptDangerFunction::~DownloadsAcceptDangerFunction() {}
 
 bool DownloadsAcceptDangerFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::AcceptDanger::Params> params(
-      extensions::api::downloads::AcceptDanger::Params::Create(*args_));
+  scoped_ptr<downloads::AcceptDanger::Params> params(
+      downloads::AcceptDanger::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
   DownloadItem* download_item = GetDownload(
       profile(), include_incognito(), params->download_id);
@@ -1299,8 +1299,8 @@
 DownloadsShowFunction::~DownloadsShowFunction() {}
 
 bool DownloadsShowFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Show::Params> params(
-      extensions::api::downloads::Show::Params::Create(*args_));
+  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);
@@ -1330,8 +1330,8 @@
 DownloadsOpenFunction::~DownloadsOpenFunction() {}
 
 bool DownloadsOpenFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Open::Params> params(
-      extensions::api::downloads::Open::Params::Create(*args_));
+  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);
@@ -1352,8 +1352,8 @@
 DownloadsDragFunction::~DownloadsDragFunction() {}
 
 bool DownloadsDragFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::Drag::Params> params(
-      extensions::api::downloads::Drag::Params::Create(*args_));
+  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);
@@ -1380,8 +1380,8 @@
 DownloadsSetShelfEnabledFunction::~DownloadsSetShelfEnabledFunction() {}
 
 bool DownloadsSetShelfEnabledFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::SetShelfEnabled::Params> params(
-      extensions::api::downloads::SetShelfEnabled::Params::Create(*args_));
+  scoped_ptr<downloads::SetShelfEnabled::Params> params(
+      downloads::SetShelfEnabled::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
   if (!GetExtension()->HasAPIPermission(
         extensions::APIPermission::kDownloadsShelf)) {
@@ -1446,10 +1446,10 @@
 }
 
 bool DownloadsGetFileIconFunction::RunImpl() {
-  scoped_ptr<extensions::api::downloads::GetFileIcon::Params> params(
-      extensions::api::downloads::GetFileIcon::Params::Create(*args_));
+  scoped_ptr<downloads::GetFileIcon::Params> params(
+      downloads::GetFileIcon::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  const extensions::api::downloads::GetFileIconOptions* options =
+  const downloads::GetFileIconOptions* options =
       params->options.get();
   int icon_size = kDefaultIconSize;
   if (options && options->size.get())
@@ -1479,7 +1479,7 @@
     return;
   }
   RecordApiFunctions(DOWNLOADS_FUNCTION_GET_FILE_ICON);
-  SetResult(base::Value::CreateStringValue(url));
+  SetResult(new base::StringValue(url));
   SendResponse(true);
 }
 
@@ -1495,7 +1495,8 @@
   extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
       event_router();
   if (router)
-    router->RegisterObserver(this, events::kOnDownloadDeterminingFilename);
+    router->RegisterObserver(this,
+                             downloads::OnDeterminingFilename::kEventName);
 }
 
 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
@@ -1565,7 +1566,7 @@
   base::DictionaryValue* json = DownloadItemToJSON(
       item, profile_).release();
   json->SetString(kFilenameKey, suggested_path.LossyDisplayName());
-  DispatchEvent(events::kOnDownloadDeterminingFilename,
+  DispatchEvent(downloads::OnDeterminingFilename::kEventName,
                 false,
                 base::Bind(&OnDeterminingFilenameWillDispatchCallback,
                            &any_determiners,
@@ -1586,14 +1587,14 @@
 
 void ExtensionDownloadsEventRouter::DetermineFilenameInternal(
     const base::FilePath& filename,
-    extensions::api::downloads::FilenameConflictAction conflict_action,
+    downloads::FilenameConflictAction conflict_action,
     const std::string& suggesting_extension_id,
     const base::Time& suggesting_install_time,
     const std::string& incumbent_extension_id,
     const base::Time& incumbent_install_time,
     std::string* winner_extension_id,
     base::FilePath* determined_filename,
-    extensions::api::downloads::FilenameConflictAction*
+    downloads::FilenameConflictAction*
       determined_conflict_action,
     extensions::ExtensionWarningSet* warnings) {
   DCHECK(!filename.empty());
@@ -1634,7 +1635,7 @@
     const std::string& ext_id,
     int download_id,
     const base::FilePath& const_filename,
-    extensions::api::downloads::FilenameConflictAction conflict_action,
+    downloads::FilenameConflictAction conflict_action,
     std::string* error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DownloadItem* item = GetDownload(profile, include_incognito, download_id);
@@ -1677,12 +1678,12 @@
   if (!manager)
     return;
   bool determiner_removed = (
-      details.event_name == events::kOnDownloadDeterminingFilename);
+      details.event_name == downloads::OnDeterminingFilename::kEventName);
   extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
       event_router();
   bool any_listeners =
-    router->HasEventListener(events::kOnDownloadChanged) ||
-    router->HasEventListener(events::kOnDownloadDeterminingFilename);
+    router->HasEventListener(downloads::OnChanged::kEventName) ||
+    router->HasEventListener(downloads::OnDeterminingFilename::kEventName);
   if (!determiner_removed && any_listeners)
     return;
   DownloadManager::DownloadVector items;
@@ -1723,20 +1724,22 @@
   // Avoid allocating a bunch of memory in DownloadItemToJSON if it isn't going
   // to be used.
   if (!router ||
-      (!router->HasEventListener(events::kOnDownloadCreated) &&
-       !router->HasEventListener(events::kOnDownloadChanged) &&
-       !router->HasEventListener(events::kOnDownloadDeterminingFilename))) {
+      (!router->HasEventListener(downloads::OnCreated::kEventName) &&
+       !router->HasEventListener(downloads::OnChanged::kEventName) &&
+       !router->HasEventListener(
+            downloads::OnDeterminingFilename::kEventName))) {
     return;
   }
   scoped_ptr<base::DictionaryValue> json_item(
       DownloadItemToJSON(download_item, profile_));
-  DispatchEvent(events::kOnDownloadCreated,
+  DispatchEvent(downloads::OnCreated::kEventName,
                 true,
                 extensions::Event::WillDispatchCallback(),
                 json_item->DeepCopy());
   if (!ExtensionDownloadsEventRouterData::Get(download_item) &&
-      (router->HasEventListener(events::kOnDownloadChanged) ||
-       router->HasEventListener(events::kOnDownloadDeterminingFilename))) {
+      (router->HasEventListener(downloads::OnChanged::kEventName) ||
+       router->HasEventListener(
+           downloads::OnDeterminingFilename::kEventName))) {
     new ExtensionDownloadsEventRouterData(download_item, json_item.Pass());
   }
 }
@@ -1749,7 +1752,7 @@
   ExtensionDownloadsEventRouterData* data =
     ExtensionDownloadsEventRouterData::Get(download_item);
   if (download_item->IsTemporary() ||
-      !router->HasEventListener(events::kOnDownloadChanged)) {
+      !router->HasEventListener(downloads::OnChanged::kEventName)) {
     return;
   }
   if (!data) {
@@ -1802,7 +1805,7 @@
   // changed. Replace the stored json with the new json.
   data->OnItemUpdated();
   if (changed) {
-    DispatchEvent(events::kOnDownloadChanged,
+    DispatchEvent(downloads::OnChanged::kEventName,
                   true,
                   extensions::Event::WillDispatchCallback(),
                   delta.release());
@@ -1816,10 +1819,11 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (download_item->IsTemporary())
     return;
-  DispatchEvent(events::kOnDownloadErased,
+  DispatchEvent(downloads::OnErased::kEventName,
                 true,
                 extensions::Event::WillDispatchCallback(),
-                base::Value::CreateIntegerValue(download_item->GetId()));
+                new base::FundamentalValue(
+                    static_cast<int>(download_item->GetId())));
 }
 
 void ExtensionDownloadsEventRouter::DispatchEvent(
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index e5962af..98c5f48 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/download/download_service_factory.h"
 #include "chrome/browser/download/download_test_file_activity_observer.h"
 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -58,8 +57,6 @@
 using content::DownloadManager;
 using content::URLRequestSlowDownloadJob;
 
-namespace events = extensions::event_names;
-
 namespace errors = download_extension_errors;
 
 namespace api = extensions::api::downloads;
@@ -116,9 +113,9 @@
       if ((profile_ != other.profile_) ||
           (event_name_ != other.event_name_))
         return false;
-      if (((event_name_ == events::kOnDownloadDeterminingFilename) ||
-           (event_name_ == events::kOnDownloadCreated) ||
-           (event_name_ == events::kOnDownloadChanged)) &&
+      if (((event_name_ == api::OnDeterminingFilename::kEventName) ||
+           (event_name_ == api::OnCreated::kEventName) ||
+           (event_name_ == api::OnChanged::kEventName)) &&
           args_.get() &&
           other.args_.get()) {
         base::ListValue* left_list = NULL;
@@ -140,7 +137,7 @@
           }
         }
         return true;
-      } else if ((event_name_ == events::kOnDownloadErased) &&
+      } else if ((event_name_ == api::OnErased::kEventName) &&
                  args_.get() &&
                  other.args_.get()) {
         int my_id = -1, other_id = -1;
@@ -277,17 +274,17 @@
         content::PAGE_TRANSITION_LINK);
     extensions::ExtensionSystem::Get(current_browser()->profile())->
       event_router()->AddEventListener(
-          extensions::event_names::kOnDownloadCreated,
+          api::OnCreated::kEventName,
           tab->GetRenderProcessHost(),
           GetExtensionId());
     extensions::ExtensionSystem::Get(current_browser()->profile())->
       event_router()->AddEventListener(
-          extensions::event_names::kOnDownloadChanged,
+          api::OnChanged::kEventName,
           tab->GetRenderProcessHost(),
           GetExtensionId());
     extensions::ExtensionSystem::Get(current_browser()->profile())->
       event_router()->AddEventListener(
-          extensions::event_names::kOnDownloadErased,
+          api::OnErased::kEventName,
           tab->GetRenderProcessHost(),
           GetExtensionId());
   }
@@ -299,7 +296,7 @@
         content::PAGE_TRANSITION_LINK);
     extensions::ExtensionSystem::Get(current_browser()->profile())->
       event_router()->AddEventListener(
-          extensions::event_names::kOnDownloadDeterminingFilename,
+          api::OnDeterminingFilename::kEventName,
           tab->GetRenderProcessHost(),
           GetExtensionId());
     return tab->GetRenderProcessHost();
@@ -308,7 +305,7 @@
   void RemoveFilenameDeterminer(content::RenderProcessHost* host) {
     extensions::ExtensionSystem::Get(current_browser()->profile())->
       event_router()->RemoveEventListener(
-          extensions::event_names::kOnDownloadDeterminingFilename,
+          api::OnDeterminingFilename::kEventName,
           host,
           GetExtensionId());
   }
@@ -355,10 +352,10 @@
       DownloadItem* item,
       content::DownloadInterruptReason expected_error,
       const std::string& on_created_event) {
-    if (!WaitFor(events::kOnDownloadCreated, on_created_event))
+    if (!WaitFor(api::OnCreated::kEventName, on_created_event))
       return false;
     // Now, onCreated is always fired before interruption.
-    return WaitFor(events::kOnDownloadChanged,
+    return WaitFor(api::OnChanged::kEventName,
         base::StringPrintf("[{\"id\": %d,"
                            "  \"error\": {\"current\": \"%s\"},"
                            "  \"state\": {"
@@ -814,7 +811,7 @@
   ASSERT_TRUE(download_item);
   EXPECT_FALSE(download_item->GetOpened());
   EXPECT_FALSE(download_item->GetOpenWhenComplete());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"mime\": \"application/octet-stream\","
@@ -1445,21 +1442,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"mime\": \"text/plain\","
                          "  \"paused\": false,"
                          "  \"url\": \"%s\"}]",
                          download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -1489,21 +1486,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": true,"
                          "  \"mime\": \"text/plain\","
                          "  \"paused\": false,"
                          "  \"url\": \"%s\"}]",
                          download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\":%d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\":%d,"
                          "  \"state\": {"
                          "    \"current\": \"complete\","
@@ -1600,21 +1597,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"mime\": \"text/plain\","
                          "  \"paused\": false,"
                          "  \"url\": \"%s\"}]",
                          download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("sub/dir/ect/ory.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -1697,21 +1694,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"mime\": \"text/plain\","
                          "  \"paused\": false,"
                          "  \"url\": \"%s\"}]",
                          download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -1738,21 +1735,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"mime\": \"text/plain\","
                          "  \"paused\": false,"
                          "  \"url\": \"%s\"}]",
                          download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("data.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -1790,21 +1787,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"mime\": \"text/html\","
                           "  \"paused\": false,"
                           "  \"url\": \"%s\"}]",
                           download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"filename\": {"
                           "    \"previous\": \"\","
                           "    \"current\": \"%s\"}}]",
                           result_id,
                           GetFilename("file.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"state\": {"
                           "    \"previous\": \"in_progress\","
@@ -1874,21 +1871,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"mime\": \"application/octet-stream\","
                          "  \"paused\": false,"
                          "  \"url\": \"%s\"}]",
                          download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("headers-succeed.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -1962,13 +1959,13 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"mime\": \"text/html\","
                           "  \"paused\": false,"
                           "  \"url\": \"%s\"}]", download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"state\": {"
                           "    \"previous\": \"in_progress\","
@@ -2001,20 +1998,20 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"mime\": \"application/octet-stream\","
                          "  \"paused\": false,"
                          "  \"url\": \"%s\"}]", download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("post-succeed.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -2128,7 +2125,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"mime\": \"application/octet-stream\","
@@ -2138,7 +2135,7 @@
                           result_id,
                           download_url.c_str())));
   item->Cancel(true);
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"error\": {\"current\":\"USER_CANCELED\"},"
                           "  \"state\": {"
@@ -2178,21 +2175,21 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"mime\": \"text/plain\","
                           "  \"paused\": false,"
                           "  \"url\": \"%s\"}]",
                           download_url.c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"filename\": {"
                           "    \"previous\": \"\","
                           "    \"current\": \"%s\"}}]",
                           result_id,
                           GetFilename("on_record.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"state\": {"
                           "    \"previous\": \"in_progress\","
@@ -2226,7 +2223,7 @@
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
   // Wait for the onCreated and onDeterminingFilename events.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2236,7 +2233,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2256,14 +2253,14 @@
   EXPECT_EQ("", error);
 
   // The download should complete successfully.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -2293,7 +2290,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2303,7 +2300,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2322,7 +2319,7 @@
       &error));
   EXPECT_EQ("", error);
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"danger\": {"
                          "    \"previous\":\"safe\","
@@ -2330,13 +2327,13 @@
                          result_id)));
 
   item->ValidateDangerousDownload();
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"danger\": {"
                          "    \"previous\":\"file\","
                          "    \"current\":\"accepted\"}}]",
                          result_id)));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"state\": {"
                           "    \"previous\": \"in_progress\","
@@ -2368,7 +2365,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2378,7 +2375,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2396,14 +2393,14 @@
       api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"filename\": {"
                           "    \"previous\": \"\","
                           "    \"current\": \"%s\"}}]",
                           result_id,
                           GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"state\": {"
                           "    \"previous\": \"in_progress\","
@@ -2433,7 +2430,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2443,7 +2440,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2461,14 +2458,14 @@
       api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName, base::StringPrintf(
       "[{\"id\": %d,"
       "  \"filename\": {"
       "    \"previous\": \"\","
       "    \"current\": \"%s\"}}]",
       result_id,
       GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName, base::StringPrintf(
       "[{\"id\": %d,"
       "  \"state\": {"
       "    \"previous\": \"in_progress\","
@@ -2498,7 +2495,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2508,7 +2505,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2527,14 +2524,14 @@
       api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName, base::StringPrintf(
       "[{\"id\": %d,"
       "  \"filename\": {"
       "    \"previous\": \"\","
       "    \"current\": \"%s\"}}]",
       result_id,
       GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName, base::StringPrintf(
       "[{\"id\": %d,"
       "  \"state\": {"
       "    \"previous\": \"in_progress\","
@@ -2564,7 +2561,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2574,7 +2571,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2592,14 +2589,14 @@
       api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName, base::StringPrintf(
       "[{\"id\": %d,"
       "  \"filename\": {"
       "    \"previous\": \"\","
       "    \"current\": \"%s\"}}]",
       result_id,
       GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged, base::StringPrintf(
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName, base::StringPrintf(
       "[{\"id\": %d,"
       "  \"state\": {"
       "    \"previous\": \"in_progress\","
@@ -2629,7 +2626,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2639,7 +2636,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2657,14 +2654,14 @@
       api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -2694,7 +2691,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2704,7 +2701,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2722,14 +2719,14 @@
       api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -2759,7 +2756,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2769,7 +2766,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2788,14 +2785,14 @@
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"filename\": {"
                           "    \"previous\": \"\","
                           "    \"current\": \"%s\"}}]",
                           result_id,
                           GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                           "  \"state\": {"
                           "    \"previous\": \"in_progress\","
@@ -2825,7 +2822,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -2835,7 +2832,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2854,14 +2851,14 @@
       &error));
   EXPECT_STREQ(errors::kInvalidFilename, error.c_str());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -2890,7 +2887,7 @@
   ASSERT_TRUE(item);
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"id\": %d,"
@@ -2900,7 +2897,7 @@
                          result_id,
                          download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2919,14 +2916,14 @@
       &error));
   EXPECT_EQ("", error);
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("slow.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -2945,7 +2942,7 @@
   ScopedCancellingItem canceller2(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"id\": %d,"
@@ -2955,7 +2952,7 @@
                          result_id,
                          download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -2977,14 +2974,14 @@
       &error));
   EXPECT_EQ("", error);
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("foo").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -3016,7 +3013,7 @@
   ScopedCancellingItem canceller(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -3026,7 +3023,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\":\"slow.txt\"}]",
                          result_id)));
@@ -3036,7 +3033,7 @@
   // Remove a determiner while waiting for it.
   RemoveFilenameDeterminer(host);
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -3072,7 +3069,7 @@
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
   // Wait for the onCreated and onDeterminingFilename events.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -3082,7 +3079,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"incognito\": false,"
                          "  \"filename\":\"slow.txt\"}]",
@@ -3103,14 +3100,14 @@
   EXPECT_EQ("", error);
 
   // The download should complete successfully.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("42.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -3130,7 +3127,7 @@
   ScopedCancellingItem canceller2(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": true,"
                          "  \"id\": %d,"
@@ -3141,7 +3138,7 @@
                          download_url.c_str())));
   // On-Record renderers should not see events for off-record items.
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"incognito\": true,"
                          "  \"filename\":\"slow.txt\"}]",
@@ -3162,14 +3159,14 @@
   EXPECT_EQ("", error);
 
   // The download should complete successfully.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("5.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -3206,7 +3203,7 @@
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
   // Wait for the onCreated and onDeterminingFilename events.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                           "  \"incognito\": false,"
                           "  \"id\": %d,"
@@ -3216,7 +3213,7 @@
                           result_id,
                           download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"incognito\": false,"
                          "  \"filename\":\"slow.txt\"}]",
@@ -3237,14 +3234,14 @@
   EXPECT_EQ("", error);
 
   // The download should complete successfully.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("42.txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -3264,7 +3261,7 @@
   ScopedCancellingItem canceller2(item);
   ASSERT_EQ(download_url, item->GetOriginalUrl().spec());
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": true,"
                          "  \"id\": %d,"
@@ -3274,7 +3271,7 @@
                          result_id,
                          download_url.c_str())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"incognito\": true,"
                          "  \"filename\":\"slow.txt\"}]",
@@ -3295,14 +3292,14 @@
   EXPECT_EQ("", error);
 
   // The download should complete successfully.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
                          "    \"current\": \"%s\"}}]",
                          result_id,
                          GetFilename("42 (1).txt").c_str())));
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
@@ -3364,7 +3361,7 @@
   ScopedCancellingItem canceller(item);
 
   // Wait for the onCreated and onDeterminingFilename event.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadCreated,
+  ASSERT_TRUE(WaitFor(api::OnCreated::kEventName,
       base::StringPrintf("[{\"danger\": \"safe\","
                          "  \"incognito\": false,"
                          "  \"id\": %d,"
@@ -3372,7 +3369,7 @@
                          "  \"paused\": false}]",
                          item->GetId())));
   ASSERT_TRUE(WaitFor(
-      events::kOnDownloadDeterminingFilename,
+      api::OnDeterminingFilename::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"incognito\": false,"
                          "  \"filename\":\"download-unknown-size\"}]",
@@ -3399,7 +3396,7 @@
       api::FILENAME_CONFLICT_ACTION_UNIQUIFY,
       &error)) << error;
   EXPECT_EQ("", error);
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"filename\": {"
                          "    \"previous\": \"\","
@@ -3410,7 +3407,7 @@
   content::DownloadUpdatedObserver interrupted(item, base::Bind(
       ItemIsInterrupted));
   ASSERT_TRUE(interrupted.WaitForEvent());
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"error\":{\"current\":\"NETWORK_FAILED\"},"
                          "  \"state\":{"
@@ -3429,7 +3426,7 @@
   // does not need to be re-done. So, there will not be a second
   // onDeterminingFilename event.
 
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"error\":{\"previous\":\"NETWORK_FAILED\"},"
                          "  \"state\":{"
@@ -3441,7 +3438,7 @@
   FinishPendingSlowDownloads();
 
   // The download should complete successfully.
-  ASSERT_TRUE(WaitFor(events::kOnDownloadChanged,
+  ASSERT_TRUE(WaitFor(api::OnChanged::kEventName,
       base::StringPrintf("[{\"id\": %d,"
                          "  \"state\": {"
                          "    \"previous\": \"in_progress\","
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
new file mode 100644
index 0000000..14072cb
--- /dev/null
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
@@ -0,0 +1,2 @@
+mnissler@chromium.org
+
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 785016f..3a769b0 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
@@ -205,6 +205,8 @@
   // Generate a new key and have it signed by PCA.
   attestation_flow_->GetCertificate(
       certificate_profile,
+      std::string(),  // Not used.
+      std::string(),  // Not used.
       true,  // Force a new key to be generated.
       base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, this,
                  callback));
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
index 51a0b38..aab40d6 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -95,6 +95,8 @@
 
 void GetCertificateCallbackTrue(
     chromeos::attestation::AttestationCertificateProfile certificate_profile,
+    const std::string& user_email,
+    const std::string& request_origin,
     bool force_new_key,
     const chromeos::attestation::AttestationFlow::CertificateCallback&
         callback) {
@@ -103,6 +105,8 @@
 
 void GetCertificateCallbackFalse(
     chromeos::attestation::AttestationCertificateProfile certificate_profile,
+    const std::string& user_email,
+    const std::string& request_origin,
     bool force_new_key,
     const chromeos::attestation::AttestationFlow::CertificateCallback&
         callback) {
@@ -121,7 +125,7 @@
     ON_CALL(mock_async_method_caller_,
             TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _))
         .WillByDefault(Invoke(SignChallengeCallbackTrue));
-    ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _))
+    ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
         .WillByDefault(Invoke(GetCertificateCallbackTrue));
 
     // Set the Enterprise install attributes.
@@ -236,7 +240,7 @@
 }
 
 TEST_F(EPKPChallengeMachineKeyTest, GetCertificateFailed) {
-  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _))
+  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
       .WillRepeatedly(Invoke(GetCertificateCallbackFalse));
 
   EXPECT_EQ(base::StringPrintf(
@@ -257,7 +261,7 @@
   EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
       .WillRepeatedly(Invoke(DoesKeyExistCallbackTrue));
   // GetCertificate must not be called if the key exists.
-  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _))
+  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
       .Times(0);
 
   EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), utils::NONE));
@@ -268,7 +272,7 @@
   EXPECT_CALL(mock_attestation_flow_,
               GetCertificate(
                   chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
-                  _, _))
+                  _, _, _, _))
       .Times(1);
   // SignEnterpriseChallenge must be called exactly once.
   EXPECT_CALL(mock_async_method_caller_,
@@ -356,7 +360,7 @@
 }
 
 TEST_F(EPKPChallengeUserKeyTest, GetCertificateFailed) {
-  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _))
+  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
       .WillRepeatedly(Invoke(GetCertificateCallbackFalse));
 
   EXPECT_EQ(base::StringPrintf(
@@ -385,7 +389,7 @@
   EXPECT_CALL(mock_cryptohome_client_, TpmAttestationDoesKeyExist(_, _, _))
       .WillRepeatedly(Invoke(DoesKeyExistCallbackTrue));
   // GetCertificate must not be called if the key exists.
-  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _))
+  EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
       .Times(0);
 
   EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), utils::NONE));
@@ -412,7 +416,7 @@
   EXPECT_CALL(mock_attestation_flow_,
               GetCertificate(
                   chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE,
-                  _, _))
+                  _, _, _, _))
       .Times(1);
   // SignEnterpriseChallenge must be called exactly once.
   EXPECT_CALL(mock_async_method_caller_,
diff --git a/chrome/browser/extensions/api/execute_code_function.cc b/chrome/browser/extensions/api/execute_code_function.cc
index d1a0f83..52c70e6 100644
--- a/chrome/browser/extensions/api/execute_code_function.cc
+++ b/chrome/browser/extensions/api/execute_code_function.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/extensions/api/execute_code_function.h"
 
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/image_loader.h"
 #include "chrome/browser/extensions/script_executor.h"
 #include "chrome/common/extensions/api/i18n/default_locale_handler.h"
 #include "chrome/common/extensions/extension_file_util.h"
@@ -12,6 +13,7 @@
 #include "chrome/common/extensions/message_bundle.h"
 #include "extensions/browser/file_reader.h"
 #include "extensions/common/error_utils.h"
+#include "ui/base/resource/resource_bundle.h"
 
 namespace extensions {
 
@@ -161,9 +163,17 @@
     return false;
   }
 
-  scoped_refptr<FileReader> file_reader(new FileReader(
-      resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this)));
-  file_reader->Start();
+  int resource_id;
+  if (ImageLoader::IsComponentExtensionResource(
+          resource_.extension_root(), resource_.relative_path(),
+          &resource_id)) {
+    const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+    DidLoadFile(true, rb.GetRawDataResource(resource_id).as_string());
+  } else {
+    scoped_refptr<FileReader> file_reader(new FileReader(
+        resource_, base::Bind(&ExecuteCodeFunction::DidLoadFile, this)));
+    file_reader->Start();
+  }
 
   return true;
 }
diff --git a/chrome/browser/extensions/api/extension_action/OWNERS b/chrome/browser/extensions/api/extension_action/OWNERS
new file mode 100644
index 0000000..739c305
--- /dev/null
+++ b/chrome/browser/extensions/api/extension_action/OWNERS
@@ -0,0 +1 @@
+jyasskin@chromium.org
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 a4c5a2c..3d4c46d 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -13,6 +13,7 @@
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h"
+#include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_function_registry.h"
@@ -31,6 +32,10 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 
+using content::WebContents;
+
+namespace page_actions_keys = extension_page_actions_api_constants;
+
 namespace extensions {
 
 namespace {
@@ -231,6 +236,11 @@
 }
 
 // static
+ExtensionActionAPI* ExtensionActionAPI::Get(Profile* profile) {
+  return ProfileKeyedAPIFactory<ExtensionActionAPI>::GetForProfile(profile);
+}
+
+// static
 bool ExtensionActionAPI::GetBrowserActionVisibility(
     const ExtensionPrefs* prefs,
     const std::string& extension_id) {
@@ -253,13 +263,121 @@
 
   prefs->UpdateExtensionPref(extension_id,
                              kBrowserActionVisible,
-                             Value::CreateBooleanValue(visible));
+                             new base::FundamentalValue(visible));
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
       content::Source<ExtensionPrefs>(prefs),
       content::Details<const std::string>(&extension_id));
 }
 
+// static
+void ExtensionActionAPI::BrowserActionExecuted(
+    Profile* profile,
+    const ExtensionAction& browser_action,
+    WebContents* web_contents) {
+  ExtensionActionExecuted(profile, browser_action, web_contents);
+}
+
+// static
+void ExtensionActionAPI::PageActionExecuted(Profile* profile,
+                                            const ExtensionAction& page_action,
+                                            int tab_id,
+                                            const std::string& url,
+                                            int button) {
+  DispatchOldPageActionEvent(profile, page_action.extension_id(),
+                             page_action.id(), tab_id, url, button);
+  WebContents* web_contents = NULL;
+  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
+                                    NULL, NULL, &web_contents, NULL)) {
+    return;
+  }
+  ExtensionActionExecuted(profile, page_action, web_contents);
+}
+
+// static
+void ExtensionActionAPI::ScriptBadgeExecuted(
+    Profile* profile,
+    const ExtensionAction& script_badge,
+    int tab_id) {
+  WebContents* web_contents = NULL;
+  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
+                                    NULL, NULL, &web_contents, NULL)) {
+    return;
+  }
+  ExtensionActionExecuted(profile, script_badge, web_contents);
+}
+
+// static
+void ExtensionActionAPI::DispatchEventToExtension(
+    Profile* profile,
+    const std::string& extension_id,
+    const char* event_name,
+    scoped_ptr<base::ListValue> event_args) {
+  if (!extensions::ExtensionSystem::Get(profile)->event_router())
+    return;
+
+  scoped_ptr<Event> event(new Event(event_name, event_args.Pass()));
+  event->restrict_to_profile = profile;
+  event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
+  ExtensionSystem::Get(profile)->event_router()->
+      DispatchEventToExtension(extension_id, event.Pass());
+}
+
+// static
+void ExtensionActionAPI::DispatchOldPageActionEvent(
+    Profile* profile,
+    const std::string& extension_id,
+    const std::string& page_action_id,
+    int tab_id,
+    const std::string& url,
+    int button) {
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+  args->Append(new base::StringValue(page_action_id));
+
+  DictionaryValue* data = new DictionaryValue();
+  data->Set(page_actions_keys::kTabIdKey, new base::FundamentalValue(tab_id));
+  data->Set(page_actions_keys::kTabUrlKey, new base::StringValue(url));
+  data->Set(page_actions_keys::kButtonKey,
+            new base::FundamentalValue(button));
+  args->Append(data);
+
+  DispatchEventToExtension(profile, extension_id, "pageActions", args.Pass());
+}
+
+// static
+void ExtensionActionAPI::ExtensionActionExecuted(
+    Profile* profile,
+    const ExtensionAction& extension_action,
+    WebContents* web_contents) {
+  const char* event_name = NULL;
+  switch (extension_action.action_type()) {
+    case ActionInfo::TYPE_BROWSER:
+      event_name = "browserAction.onClicked";
+      break;
+    case ActionInfo::TYPE_PAGE:
+      event_name = "pageAction.onClicked";
+      break;
+    case ActionInfo::TYPE_SCRIPT_BADGE:
+      event_name = "scriptBadge.onClicked";
+      break;
+    case ActionInfo::TYPE_SYSTEM_INDICATOR:
+      // The System Indicator handles its own clicks.
+      break;
+  }
+
+  if (event_name) {
+    scoped_ptr<base::ListValue> args(new base::ListValue());
+    DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(
+        web_contents);
+    args->Append(tab_value);
+
+    DispatchEventToExtension(profile,
+                             extension_action.extension_id(),
+                             event_name,
+                             args.Pass());
+  }
+}
+
 //
 // ExtensionActionStorageManager
 //
@@ -655,28 +773,32 @@
 }
 
 bool ExtensionActionGetTitleFunction::RunExtensionAction() {
-  SetResult(Value::CreateStringValue(extension_action_->GetTitle(tab_id_)));
+  SetResult(new base::StringValue(extension_action_->GetTitle(tab_id_)));
   return true;
 }
 
 bool ExtensionActionGetPopupFunction::RunExtensionAction() {
   SetResult(
-      Value::CreateStringValue(extension_action_->GetPopupUrl(tab_id_).spec()));
+      new base::StringValue(extension_action_->GetPopupUrl(tab_id_).spec()));
   return true;
 }
 
 bool ExtensionActionGetBadgeTextFunction::RunExtensionAction() {
-  SetResult(Value::CreateStringValue(extension_action_->GetBadgeText(tab_id_)));
+  SetResult(new base::StringValue(extension_action_->GetBadgeText(tab_id_)));
   return true;
 }
 
 bool ExtensionActionGetBadgeBackgroundColorFunction::RunExtensionAction() {
   base::ListValue* list = new base::ListValue();
   SkColor color = extension_action_->GetBadgeBackgroundColor(tab_id_);
-  list->Append(Value::CreateIntegerValue(SkColorGetR(color)));
-  list->Append(Value::CreateIntegerValue(SkColorGetG(color)));
-  list->Append(Value::CreateIntegerValue(SkColorGetB(color)));
-  list->Append(Value::CreateIntegerValue(SkColorGetA(color)));
+  list->Append(
+      new base::FundamentalValue(static_cast<int>(SkColorGetR(color))));
+  list->Append(
+      new base::FundamentalValue(static_cast<int>(SkColorGetG(color))));
+  list->Append(
+      new base::FundamentalValue(static_cast<int>(SkColorGetB(color))));
+  list->Append(
+      new base::FundamentalValue(static_cast<int>(SkColorGetA(color))));
   SetResult(list);
   return true;
 }
@@ -698,8 +820,6 @@
 // PageActionsFunction (deprecated)
 //
 
-namespace keys = extension_page_actions_api_constants;
-
 PageActionsFunction::PageActionsFunction() {
 }
 
@@ -713,14 +833,17 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &action));
 
   int tab_id;
-  EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kTabIdKey, &tab_id));
+  EXTENSION_FUNCTION_VALIDATE(action->GetInteger(
+      page_actions_keys::kTabIdKey, &tab_id));
   std::string url;
-  EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kUrlKey, &url));
+  EXTENSION_FUNCTION_VALIDATE(action->GetString(
+      page_actions_keys::kUrlKey, &url));
 
   std::string title;
   if (enable) {
-    if (action->HasKey(keys::kTitleKey))
-      EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kTitleKey, &title));
+    if (action->HasKey(page_actions_keys::kTitleKey))
+      EXTENSION_FUNCTION_VALIDATE(action->GetString(
+          page_actions_keys::kTitleKey, &title));
   }
 
   ExtensionAction* page_action =
@@ -732,7 +855,7 @@
   }
 
   // Find the WebContents that contains this tab id.
-  content::WebContents* contents = NULL;
+  WebContents* contents = NULL;
   bool result = ExtensionTabUtil::GetTabById(
       tab_id, profile(), include_incognito(), NULL, NULL, &contents, NULL);
   if (!result || !contents) {
@@ -742,7 +865,7 @@
   }
 
   // Make sure the URL hasn't changed.
-  content::NavigationEntry* entry = contents->GetController().GetActiveEntry();
+  content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
   if (!entry || url != entry->GetURL().spec()) {
     error_ = extensions::ErrorUtils::FormatErrorMessage(
         extensions::kUrlNotActiveError, url);
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 2074a37..aa82104 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.h
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.h
@@ -29,18 +29,60 @@
   explicit ExtensionActionAPI(Profile* profile);
   virtual ~ExtensionActionAPI();
 
+  // Convenience method to get the instance for a profile.
+  static ExtensionActionAPI* Get(Profile* profile);
+
   static bool GetBrowserActionVisibility(const ExtensionPrefs* prefs,
                                          const std::string& extension_id);
   static void SetBrowserActionVisibility(ExtensionPrefs* prefs,
                                          const std::string& extension_id,
                                          bool visible);
 
+  // Fires the onClicked event for page_action.
+  static void PageActionExecuted(Profile* profile,
+                                 const ExtensionAction& page_action,
+                                 int tab_id,
+                                 const std::string& url,
+                                 int button);
+
+  // Fires the onClicked event for script_badge.
+  static void ScriptBadgeExecuted(Profile* profile,
+                                  const ExtensionAction& script_badge,
+                                  int tab_id);
+
+  // Fires the onClicked event for browser_action.
+  static void BrowserActionExecuted(Profile* profile,
+                                    const ExtensionAction& browser_action,
+                                    content::WebContents* web_contents);
+
   // ProfileKeyedAPI implementation.
   static ProfileKeyedAPIFactory<ExtensionActionAPI>* GetFactoryInstance();
 
  private:
   friend class ProfileKeyedAPIFactory<ExtensionActionAPI>;
 
+  // The DispatchEvent methods forward events to the |profile|'s event router.
+  static void DispatchEventToExtension(Profile* profile,
+                                       const std::string& extension_id,
+                                       const char* event_name,
+                                       scoped_ptr<base::ListValue> event_args);
+
+  // Called to dispatch a deprecated style page action click event that was
+  // registered like:
+  //   chrome.pageActions["name"].addListener(function(actionId, info){})
+  static void DispatchOldPageActionEvent(Profile* profile,
+    const std::string& extension_id,
+    const std::string& page_action_id,
+    int tab_id,
+    const std::string& url,
+    int button);
+
+  // Called when either a browser or page action is executed. Figures out which
+  // event to send based on what the extension wants.
+  static void ExtensionActionExecuted(Profile* profile,
+                                      const ExtensionAction& extension_action,
+                                      content::WebContents* web_contents);
+
   // ProfileKeyedAPI implementation.
   static const char* service_name() { return "ExtensionActionAPI"; }
 
diff --git a/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.cc b/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.cc
index 029dfcf..8ad3dac 100644
--- a/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.cc
@@ -7,6 +7,7 @@
 namespace extension_page_actions_api_constants {
 
 const char kTabIdKey[] = "tabId";
+const char kTabUrlKey[] = "tabUrl";
 const char kUrlKey[] = "url";
 const char kTitleKey[] = "title";
 const char kButtonKey[] = "button";
diff --git a/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h b/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h
index 5f3ad9f..c8cfcc6 100644
--- a/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h
+++ b/chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h
@@ -11,6 +11,7 @@
 
 // Keys.
 extern const char kTabIdKey[];
+extern const char kTabUrlKey[];
 extern const char kUrlKey[];
 extern const char kTitleKey[];
 extern const char kButtonKey[];
diff --git a/chrome/browser/extensions/api/extension_action/page_action_apitest.cc b/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
index cad5250..f2d0078 100644
--- a/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/page_action_apitest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/browser_event_router.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_icon_factory.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
@@ -60,9 +60,7 @@
     ResultCatcher catcher;
     int tab_id = ExtensionTabUtil::GetTabId(
         browser()->tab_strip_model()->GetActiveWebContents());
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
-    service->browser_event_router()->PageActionExecuted(
+    ExtensionActionAPI::PageActionExecuted(
         browser()->profile(), *action, tab_id, std::string(), 0);
     EXPECT_TRUE(catcher.GetNextResult());
   }
@@ -105,9 +103,7 @@
   // install a page action popup.
   {
     ResultCatcher catcher;
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
-    service->browser_event_router()->PageActionExecuted(
+    ExtensionActionAPI::PageActionExecuted(
         browser()->profile(), *page_action, tab_id, std::string(), 1);
     ASSERT_TRUE(catcher.GetNextResult());
   }
@@ -184,10 +180,8 @@
     ResultCatcher catcher;
     int tab_id = ExtensionTabUtil::GetTabId(
         browser()->tab_strip_model()->GetActiveWebContents());
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
     ExtensionAction* page_action = GetPageAction(*extension);
-    service->browser_event_router()->PageActionExecuted(
+    ExtensionActionAPI::PageActionExecuted(
         browser()->profile(), *page_action, tab_id, std::string(), 1);
     EXPECT_TRUE(catcher.GetNextResult());
   }
@@ -257,9 +251,7 @@
     ResultCatcher catcher;
     int tab_id = ExtensionTabUtil::GetTabId(
         browser()->tab_strip_model()->GetActiveWebContents());
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
-    service->browser_event_router()->PageActionExecuted(
+    ExtensionActionAPI::PageActionExecuted(
         browser()->profile(), *page_action, tab_id, std::string(), 0);
     EXPECT_TRUE(catcher.GetNextResult());
   }
diff --git a/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc b/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc
index fd7264a..5cd0c53 100644
--- a/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/script_badge_apitest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/browser_event_router.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -77,9 +77,7 @@
   {
     // Simulate the script badge being clicked.
     ResultCatcher catcher;
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
-    service->browser_event_router()->ScriptBadgeExecuted(
+    ExtensionActionAPI::ScriptBadgeExecuted(
         browser()->profile(), *script_badge, tab_id);
     EXPECT_TRUE(catcher.GetNextResult());
   }
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 d9db466..fafcbd5 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -6,10 +6,10 @@
 
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/feedback_private/feedback_service.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "grit/generated_resources.h"
@@ -17,11 +17,12 @@
 #include "ui/webui/web_ui_util.h"
 #include "url/url_util.h"
 
-
 namespace extensions {
 
-using api::feedback_private::SystemInformation;
-using api::feedback_private::FeedbackInfo;
+namespace feedback_private = api::feedback_private;
+
+using feedback_private::SystemInformation;
+using feedback_private::FeedbackInfo;
 
 static base::LazyInstance<ProfileKeyedAPIFactory<FeedbackPrivateAPI> >
     g_factory = LAZY_INSTANCE_INITIALIZER;
@@ -49,29 +50,63 @@
 void FeedbackPrivateAPI::RequestFeedback(
     const std::string& description_template,
     const std::string& category_tag,
-    const GURL& page_url) {
+    const GURL& page_url,
+    const gfx::Rect& screen_size) {
   if (profile_ && ExtensionSystem::Get(profile_)->event_router()) {
     FeedbackInfo info;
     info.description = description_template;
     info.category_tag = make_scoped_ptr(new std::string(category_tag));
     info.page_url = make_scoped_ptr(new std::string(page_url.spec()));
+    info.system_information.reset(new SystemInformationList);
+
+    FeedbackService::PopulateSystemInfo(
+        info.system_information.get(), FeedbackData::kScreensizeHeightKey,
+        base::IntToString(screen_size.height()));
+    FeedbackService::PopulateSystemInfo(
+        info.system_information.get(), FeedbackData::kScreensizeWidthKey,
+        base::IntToString(screen_size.width()));
 
     scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(info.ToValue().release());
 
-    scoped_ptr<Event> event(
-        new Event(event_names::kOnFeedbackRequested, args.Pass()));
+    scoped_ptr<Event> event(new Event(
+        feedback_private::OnFeedbackRequested::kEventName, args.Pass()));
     ExtensionSystem::Get(profile_)->event_router()->BroadcastEvent(
         event.Pass());
   }
 }
 
+bool FeedbackPrivateGetStringsFunction::RunImpl() {
+  DictionaryValue* dict = new DictionaryValue();
+  SetResult(dict);
+
+#define SET_STRING(id, idr) \
+  dict->SetString(id, l10n_util::GetStringUTF16(idr))
+  SET_STRING("page-title", IDS_FEEDBACK_REPORT_PAGE_TITLE);
+  SET_STRING("page-url", IDS_FEEDBACK_REPORT_URL_LABEL);
+  SET_STRING("screenshot", IDS_FEEDBACK_SCREENSHOT_LABEL);
+  SET_STRING("user-email", IDS_FEEDBACK_USER_EMAIL_LABEL);
+  SET_STRING("sysinfo", IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_CHKBOX);
+  SET_STRING("attach-file-label", IDS_FEEDBACK_ATTACH_FILE_LABEL);
+  SET_STRING("attach-file-note", IDS_FEEDBACK_ATTACH_FILE_NOTE);
+  SET_STRING("attach-file-to-big", IDS_FEEDBACK_ATTACH_FILE_TO_BIG);
+  SET_STRING("reading-file", IDS_FEEDBACK_READING_FILE);
+  SET_STRING("send-report", IDS_FEEDBACK_SEND_REPORT);
+  SET_STRING("cancel", IDS_CANCEL);
+  SET_STRING("no-description", IDS_FEEDBACK_NO_DESCRIPTION);
+  SET_STRING("privacy-note", IDS_FEEDBACK_PRIVACY_NOTE);
+#undef SET_STRING
+
+  webui::SetFontAndTextDirection(dict);
+  return true;
+}
+
 bool FeedbackPrivateGetUserEmailFunction::RunImpl() {
   FeedbackService* service =
       FeedbackPrivateAPI::GetFactoryInstance()->GetForProfile(
           profile())->GetService();
   DCHECK(service);
-  SetResult(base::Value::CreateStringValue(service->GetUserEmail()));
+  SetResult(new base::StringValue(service->GetUserEmail()));
   return true;
 }
 
@@ -88,30 +123,26 @@
 
 void FeedbackPrivateGetSystemInformationFunction::OnCompleted(
     const SystemInformationList& sys_info) {
-  results_ = api::feedback_private::GetSystemInformation::Results::Create(
+  results_ = feedback_private::GetSystemInformation::Results::Create(
       sys_info);
   SendResponse(true);
 }
 
 bool FeedbackPrivateSendFeedbackFunction::RunImpl() {
-  scoped_ptr<api::feedback_private::SendFeedback::Params> params(
-      api::feedback_private::SendFeedback::Params::Create(*args_));
+  scoped_ptr<feedback_private::SendFeedback::Params> params(
+      feedback_private::SendFeedback::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   const FeedbackInfo &feedback_info = params->feedback;
 
   std::string attached_file_url, screenshot_url;
-  if (feedback_info.attached_file.get() &&
-      feedback_info.attached_file_blob_url.get() &&
-      !feedback_info.attached_file_blob_url->empty()) {
+  if (feedback_info.attached_file_blob_url.get() &&
+      !feedback_info.attached_file_blob_url->empty())
     attached_file_url = *feedback_info.attached_file_blob_url;
-  }
 
-  if (feedback_info.screenshot.get() &&
-      feedback_info.screenshot_blob_url.get() &&
-      !feedback_info.screenshot_blob_url->empty()) {
+  if (feedback_info.screenshot_blob_url.get() &&
+      !feedback_info.screenshot_blob_url->empty())
     screenshot_url = *feedback_info.screenshot_blob_url;
-  }
 
   // Populate feedback data.
   scoped_refptr<FeedbackData> feedback_data(new FeedbackData());
@@ -134,11 +165,8 @@
   if (!screenshot_url.empty())
     feedback_data->set_screenshot_url(GURL(screenshot_url));
 
-  // TODO(rkc): Take this out of OS_CHROMEOS once we have FeedbackData and
-  // FeedbackUtil migrated to handle system logs for both Chrome and ChromeOS.
-#if defined(OS_CHROMEOS)
-  scoped_ptr<chromeos::SystemLogsResponse> sys_logs(
-      new chromeos::SystemLogsResponse);
+  scoped_ptr<FeedbackData::SystemLogsMap> sys_logs(
+      new FeedbackData::SystemLogsMap);
   SystemInformationList* sys_info = feedback_info.system_information.get();
   if (sys_info) {
     for (SystemInformationList::iterator it = sys_info->begin();
@@ -146,7 +174,6 @@
       (*sys_logs.get())[it->get()->key] = it->get()->value;
   }
   feedback_data->set_sys_info(sys_logs.Pass());
-#endif
 
   FeedbackService* service = FeedbackPrivateAPI::GetFactoryInstance()->
       GetForProfile(profile())->GetService();
@@ -160,9 +187,9 @@
 
 void FeedbackPrivateSendFeedbackFunction::OnCompleted(
     bool success) {
-  results_ = api::feedback_private::SendFeedback::Results::Create(
-      success ? api::feedback_private::STATUS_SUCCESS :
-                api::feedback_private::STATUS_DELAYED);
+  results_ = feedback_private::SendFeedback::Results::Create(
+      success ? feedback_private::STATUS_SUCCESS :
+                feedback_private::STATUS_DELAYED);
   SendResponse(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 3bed626..a3def8f 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.h
@@ -5,15 +5,17 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_FEEDBACK_PRIVATE_FEEDBACK_PRIVATE_API_H_
 #define CHROME_BROWSER_EXTENSIONS_API_FEEDBACK_PRIVATE_FEEDBACK_PRIVATE_API_H_
 
-#include "chrome/browser/extensions/api/feedback_private/feedback_service.h"
 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
 #include "chrome/browser/extensions/extension_function.h"
 #include "chrome/common/extensions/api/feedback_private.h"
+#include "ui/gfx/rect.h"
 
 namespace extensions {
 
 class FeedbackService;
 
+using extensions::api::feedback_private::SystemInformation;
+
 class FeedbackPrivateAPI : public ProfileKeyedAPI {
  public:
   explicit FeedbackPrivateAPI(Profile* profile);
@@ -22,7 +24,8 @@
   FeedbackService* GetService() const;
   void RequestFeedback(const std::string& description_template,
                        const std::string& category_tag,
-                       const GURL& page_url);
+                       const GURL& page_url,
+                       const gfx::Rect& screen_size);
 
   // ProfileKeyedAPI implementation.
   static ProfileKeyedAPIFactory<FeedbackPrivateAPI>* GetFactoryInstance();
@@ -39,6 +42,19 @@
   FeedbackService* service_;
 };
 
+// Feedback strings.
+class FeedbackPrivateGetStringsFunction : public SyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("feedbackPrivate.getStrings",
+                             FEEDBACKPRIVATE_GETSTRINGS)
+
+ protected:
+  virtual ~FeedbackPrivateGetStringsFunction() {}
+
+  // SyncExtensionFunction overrides.
+  virtual bool RunImpl() OVERRIDE;
+};
+
 class FeedbackPrivateGetUserEmailFunction : public SyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("feedbackPrivate.getUserEmail",
@@ -60,7 +76,8 @@
   virtual bool RunImpl() OVERRIDE;
 
  private:
-  void OnCompleted(const SystemInformationList& sys_info);
+  void OnCompleted(
+      const std::vector<linked_ptr<SystemInformation> >& sys_info);
 };
 
 class FeedbackPrivateSendFeedbackFunction : public AsyncExtensionFunction {
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_apitest.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_apitest.cc
new file mode 100644
index 0000000..322601d
--- /dev/null
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_apitest.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 "base/command_line.h"
+#include "base/message_loop.h"
+#include "chrome/browser/extensions/api/audio/audio_api.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace extensions {
+
+class AudioApiTest: public ExtensionApiTest {
+ public:
+  AudioApiTest() {}
+  virtual ~AudioApiTest() {}
+};
+
+#if defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(AudioApiTest, Audio) {
+  EXPECT_TRUE(RunExtensionTest("audio")) << message_;
+}
+#endif
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_service.cc b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
index ea207a0..a4102ed 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_service.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_service.cc
@@ -8,23 +8,27 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/screenshot_source.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
 
-namespace {
-
-ScreenshotDataPtr ConvertStringToScreenshotPtr(scoped_ptr<std::string> image) {
-  ScreenshotDataPtr screenshot(new ScreenshotData);
-  std::copy(image->begin(), image->end(), screenshot->begin());
-  return screenshot;
-}
-
-}
-
 namespace extensions {
 
+// static
+void FeedbackService::PopulateSystemInfo(
+    SystemInformationList* sys_info_list,
+    const std::string& key,
+    const std::string& value) {
+  base::DictionaryValue sys_info_value;
+  sys_info_value.Set("key", new base::StringValue(key));
+  sys_info_value.Set("value", new base::StringValue(value));
+
+  linked_ptr<SystemInformation> sys_info(new SystemInformation());
+  SystemInformation::Populate(sys_info_value, sys_info.get());
+
+  sys_info_list->push_back(sys_info);
+}
+
 FeedbackService::FeedbackService() {
 }
 
@@ -39,19 +43,21 @@
   feedback_data_ = feedback_data;
 
   if (feedback_data_->attached_file_url().is_valid()) {
-    attached_file_reader_ = new BlobReader(
+    // Self-deleting object.
+    BlobReader* attached_file_reader = new BlobReader(
         profile, feedback_data_->attached_file_url(),
         base::Bind(&FeedbackService::AttachedFileCallback,
                    GetWeakPtr()));
-    attached_file_reader_->Start();
+    attached_file_reader->Start();
   }
 
   if (feedback_data_->screenshot_url().is_valid()) {
-    attached_file_reader_ = new BlobReader(
+    // Self-deleting object.
+    BlobReader* screenshot_reader = new BlobReader(
         profile, feedback_data_->screenshot_url(),
         base::Bind(&FeedbackService::ScreenshotCallback,
                    GetWeakPtr()));
-    screenshot_reader_->Start();
+    screenshot_reader->Start();
   }
 
   CompleteSendFeedback();
@@ -70,25 +76,30 @@
   if (!data.get())
     feedback_data_->set_screenshot_url(GURL());
   else
-    feedback_data_->set_image(ConvertStringToScreenshotPtr(data.Pass()));
+    feedback_data_->set_image(data.Pass());
 
   CompleteSendFeedback();
 }
 
 void FeedbackService::CompleteSendFeedback() {
-  // If either the blob URL is invalid (we never needed to read it), or if the
-  // data exists in the feedback object (the read is completed).
+  // A particular data collection is considered completed if,
+  // a.) The blob URL is invalid - this will either happen because we never had
+  //     a URL and never needed to read this data, or that the data read failed
+  //     and we set it to invalid in the data read callback.
+  // b.) The associated data object exists, meaning that the data has been read
+  //     and the read callback has updated the associated data on the feedback
+  //     object.
   bool attached_file_completed =
       !feedback_data_->attached_file_url().is_valid() ||
       feedback_data_->attached_filedata();
   bool screenshot_completed =
       !feedback_data_->screenshot_url().is_valid() ||
-      !feedback_data_->image().get();
+      feedback_data_->image();
 
   if (screenshot_completed && attached_file_completed) {
     // Signal the feedback object that the data from the feedback page has been
     // filled - the object will manage sending of the actual report.
-    feedback_data_->FeedbackPageDataComplete();
+    feedback_data_->OnFeedbackPageDataComplete();
     // TODO(rkc): Change this once we have FeedbackData/Util refactored to
     // report the status of the report being sent.
     send_feedback_callback_.Run(true);
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_service.h b/chrome/browser/extensions/api/feedback_private/feedback_service.h
index ba64353..1bb85bf 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_service.h
+++ b/chrome/browser/extensions/api/feedback_private/feedback_service.h
@@ -16,10 +16,11 @@
 
 class Profile;
 
+using extensions::api::feedback_private::SystemInformation;
+
 namespace extensions {
 
-typedef std::vector<linked_ptr<api::feedback_private::SystemInformation> >
-    SystemInformationList;
+typedef std::vector<linked_ptr<SystemInformation> > SystemInformationList;
 
 class FeedbackService {
  public:
@@ -29,6 +30,11 @@
 
   // Creates a platform-specific FeedbackService instance.
   static FeedbackService* CreateInstance();
+  // Convenience method for populating a SystemInformationList structure
+  // with a key/value pair.
+  static void PopulateSystemInfo(SystemInformationList* sys_info_list,
+                                 const std::string& key,
+                                 const std::string& value);
 
   virtual ~FeedbackService();
 
@@ -64,8 +70,6 @@
   SendFeedbackCallback send_feedback_callback_;
 
   scoped_refptr<FeedbackData> feedback_data_;
-  BlobReader* attached_file_reader_;
-  BlobReader* screenshot_reader_;
 
   DISALLOW_COPY_AND_ASSIGN(FeedbackService);
 };
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_service_chromeos.cc b/chrome/browser/extensions/api/feedback_private/feedback_service_chromeos.cc
index 19d6595..d4c2f19 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_service_chromeos.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_service_chromeos.cc
@@ -8,7 +8,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/system_logs/about_system_logs_fetcher.h"
+#include "chrome/browser/chromeos/system_logs/scrubbed_system_logs_fetcher.h"
 
 using extensions::api::feedback_private::SystemInformation;
 
@@ -55,8 +55,8 @@
     const GetSystemInformationCallback& callback) {
   system_information_callback_ = callback;
 
-  chromeos::AboutSystemLogsFetcher* fetcher =
-      new chromeos::AboutSystemLogsFetcher();
+  chromeos::ScrubbedSystemLogsFetcher* fetcher =
+      new chromeos::ScrubbedSystemLogsFetcher();
   fetcher->Fetch(base::Bind(&FeedbackServiceImpl::ProcessSystemLogs,
                             AsWeakPtr()));
 }
@@ -70,16 +70,8 @@
   }
 
   for (chromeos::SystemLogsResponse::iterator it = sys_info_map->begin();
-       it != sys_info_map->end(); ++it) {
-    base::DictionaryValue sys_info_value;
-    sys_info_value.Set("key", new base::StringValue(it->first));
-    sys_info_value.Set("value", new base::StringValue(it->second));
-
-    linked_ptr<SystemInformation> sys_info(new SystemInformation());
-    SystemInformation::Populate(sys_info_value, sys_info.get());
-
-    sys_info_list.push_back(sys_info);
-  }
+       it != sys_info_map->end(); ++it)
+    FeedbackService::PopulateSystemInfo(&sys_info_list, it->first, it->second);
 
   system_information_callback_.Run(sys_info_list);
 }
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc b/chrome/browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc
index 9c05c30..da6cce3 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc
@@ -60,6 +60,8 @@
   system_information_callback_ = callback;
 
   SystemInformationList sys_info_list;
+  // TODO(rkc): Figure out what other Chrome system information we can add and
+  // add it here.
   system_information_callback_.Run(sys_info_list);
 }
 
diff --git a/chrome/browser/extensions/api/file_handlers/OWNERS b/chrome/browser/extensions/api/file_handlers/OWNERS
new file mode 100644
index 0000000..64f6677
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/OWNERS
@@ -0,0 +1,2 @@
+benwells@chromium.org
+sammc@chromium.org
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 7ebf9e2..99e761d 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -490,7 +490,7 @@
     return false;
 
   file_path = PrettifyPath(file_path);
-  SetResult(base::Value::CreateStringValue(file_path.value()));
+  SetResult(new base::StringValue(file_path.value()));
   return true;
 }
 
@@ -613,7 +613,7 @@
   bool is_writable = policy->CanReadWriteFileSystem(renderer_id,
                                                     filesystem_id);
 
-  SetResult(base::Value::CreateBooleanValue(is_writable));
+  SetResult(new base::FundamentalValue(is_writable));
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/file_system/file_system_apitest.cc b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
index 9f1c709..90c90bf 100644
--- a/chrome/browser/extensions/api/file_system/file_system_apitest.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_apitest.cc
@@ -6,10 +6,10 @@
 #include "base/file_util.h"
 #include "base/path_service.h"
 #include "build/build_config.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/extensions/api/font_settings/OWNERS b/chrome/browser/extensions/api/font_settings/OWNERS
new file mode 100644
index 0000000..4794ccc
--- /dev/null
+++ b/chrome/browser/extensions/api/font_settings/OWNERS
@@ -0,0 +1 @@
+falken@chromium.org
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 b5498a1..2152270 100644
--- a/chrome/browser/extensions/api/font_settings/font_settings_api.cc
+++ b/chrome/browser/extensions/api/font_settings/font_settings_api.cc
@@ -49,14 +49,6 @@
 const char kSetFromIncognitoError[] =
     "Can't modify regular settings from an incognito context.";
 
-const char kOnDefaultFixedFontSizeChanged[] =
-    "fontSettings.onDefaultFixedFontSizeChanged";
-const char kOnDefaultFontSizeChanged[] =
-    "fontSettings.onDefaultFontSizeChanged";
-const char kOnFontChanged[] = "fontSettings.onFontChanged";
-const char kOnMinimumFontSizeChanged[] =
-    "fontSettings.onMinimumFontSizeChanged";
-
 // Format for font name preference paths.
 const char kWebKitFontPrefFormat[] = "webkit.webprefs.fonts.%s.%s";
 
@@ -106,13 +98,13 @@
   registrar_.Init(profile_->GetPrefs());
 
   AddPrefToObserve(prefs::kWebKitDefaultFixedFontSize,
-                   kOnDefaultFixedFontSizeChanged,
+                   fonts::OnDefaultFixedFontSizeChanged::kEventName,
                    kPixelSizeKey);
   AddPrefToObserve(prefs::kWebKitDefaultFontSize,
-                   kOnDefaultFontSizeChanged,
+                   fonts::OnDefaultFontSizeChanged::kEventName,
                    kPixelSizeKey);
   AddPrefToObserve(prefs::kWebKitMinimumFontSize,
-                   kOnMinimumFontSizeChanged,
+                   fonts::OnMinimumFontSizeChanged::kEventName,
                    kPixelSizeKey);
 
   PrefChangeRegistrar::NamedChangeCallback callback =
@@ -183,7 +175,7 @@
 
   extensions::preference_helpers::DispatchEventToExtensions(
       profile_,
-      kOnFontChanged,
+      fonts::OnFontChanged::kEventName,
       &args,
       APIPermission::kFontSettings,
       false,
@@ -303,7 +295,7 @@
       extension_id(),
       pref_path.c_str(),
       kExtensionPrefsScopeRegular,
-      Value::CreateStringValue(params->details.font_id));
+      new base::StringValue(params->details.font_id));
   return true;
 }
 
@@ -343,8 +335,8 @@
     }
 
     base::DictionaryValue* font_name = new base::DictionaryValue();
-    font_name->Set(kFontIdKey, Value::CreateStringValue(name));
-    font_name->Set(kDisplayNameKey, Value::CreateStringValue(localized_name));
+    font_name->Set(kFontIdKey, new base::StringValue(name));
+    font_name->Set(kDisplayNameKey, new base::StringValue(localized_name));
     result->Append(font_name);
   }
 
diff --git a/chrome/browser/extensions/api/history/history_api.cc b/chrome/browser/extensions/api/history/history_api.cc
index 0543a27..e387b4f 100644
--- a/chrome/browser/extensions/api/history/history_api.cc
+++ b/chrome/browser/extensions/api/history/history_api.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/cancelable_task_tracker.h"
 #include "chrome/common/extensions/api/experimental_history.h"
+#include "chrome/common/extensions/api/history.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
@@ -52,9 +53,6 @@
 
 namespace {
 
-const char kOnVisited[] = "history.onVisited";
-const char kOnVisitRemoved[] = "history.onVisitRemoved";
-
 const char kInvalidIdError[] = "History item id is invalid.";
 const char kInvalidUrlError[] = "Url is invalid.";
 const char kDeleteProhibitedError[] = "Browsing history is not allowed to be "
@@ -170,7 +168,7 @@
   scoped_ptr<HistoryItem> history_item = GetHistoryItem(details->row);
   scoped_ptr<base::ListValue> args = OnVisited::Create(*history_item);
 
-  DispatchEvent(profile, kOnVisited, args.Pass());
+  DispatchEvent(profile, api::history::OnVisited::kEventName, args.Pass());
 }
 
 void HistoryEventRouter::HistoryUrlsRemoved(
@@ -187,7 +185,7 @@
   removed.urls.reset(urls);
 
   scoped_ptr<base::ListValue> args = OnVisitRemoved::Create(removed);
-  DispatchEvent(profile, kOnVisitRemoved, args.Pass());
+  DispatchEvent(profile, api::history::OnVisitRemoved::kEventName, args.Pass());
 }
 
 void HistoryEventRouter::DispatchEvent(
@@ -205,9 +203,9 @@
 
 HistoryAPI::HistoryAPI(Profile* profile) : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, kOnVisited);
+      this, api::history::OnVisited::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, kOnVisitRemoved);
+      this, api::history::OnVisitRemoved::kEventName);
 }
 
 HistoryAPI::~HistoryAPI() {
diff --git a/chrome/browser/extensions/api/identity/experimental_identity_api.cc b/chrome/browser/extensions/api/identity/experimental_identity_api.cc
index 2e01c4e..11e2408 100644
--- a/chrome/browser/extensions/api/identity/experimental_identity_api.cc
+++ b/chrome/browser/extensions/api/identity/experimental_identity_api.cc
@@ -102,7 +102,7 @@
 
 void ExperimentalIdentityGetAuthTokenFunction::CompleteFunctionWithResult(
     const std::string& access_token) {
-  SetResult(Value::CreateStringValue(access_token));
+  SetResult(new base::StringValue(access_token));
   SendResponse(true);
   Release();  // Balanced in RunImpl.
 }
@@ -385,7 +385,7 @@
 void ExperimentalIdentityLaunchWebAuthFlowFunction::OnAuthFlowURLChange(
     const GURL& redirect_url) {
   if (IsFinalRedirectURL(redirect_url)) {
-    SetResult(Value::CreateStringValue(redirect_url.spec()));
+    SetResult(new base::StringValue(redirect_url.spec()));
     SendResponse(true);
     Release();  // Balanced in RunImpl.
   }
diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc
index 6a8beb7..128fb6e 100644
--- a/chrome/browser/extensions/api/identity/identity_api.cc
+++ b/chrome/browser/extensions/api/identity/identity_api.cc
@@ -129,7 +129,7 @@
 
 void IdentityGetAuthTokenFunction::CompleteFunctionWithResult(
     const std::string& access_token) {
-  SetResult(Value::CreateStringValue(access_token));
+  SetResult(new base::StringValue(access_token));
   SendResponse(true);
   Release();  // Balanced in RunImpl.
 }
@@ -599,7 +599,7 @@
 void IdentityLaunchWebAuthFlowFunction::OnAuthFlowURLChange(
     const GURL& redirect_url) {
   if (redirect_url.GetWithEmptyPath() == final_url_prefix_) {
-    SetResult(Value::CreateStringValue(redirect_url.spec()));
+    SetResult(new base::StringValue(redirect_url.spec()));
     SendResponse(true);
     Release();  // Balanced in RunImpl.
   }
diff --git a/chrome/browser/extensions/api/identity/web_auth_flow.cc b/chrome/browser/extensions/api/identity/web_auth_flow.cc
index 977f1f1..2c50724 100644
--- a/chrome/browser/extensions/api/identity/web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/web_auth_flow.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/identity_private.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
@@ -38,6 +39,8 @@
 
 namespace extensions {
 
+namespace identity_private = api::identity_private;
+
 WebAuthFlow::WebAuthFlow(
     Delegate* delegate,
     Profile* profile,
@@ -86,7 +89,7 @@
     args->AppendString("silent");
 
   scoped_ptr<Event> event(
-      new Event("identityPrivate.onWebFlowRequest", args.Pass()));
+      new Event(identity_private::OnWebFlowRequest::kEventName, args.Pass()));
   event->restrict_to_profile = profile_;
   ExtensionSystem* system = ExtensionSystem::Get(profile_);
 
diff --git a/chrome/browser/extensions/api/identity_private/OWNERS b/chrome/browser/extensions/api/identity_private/OWNERS
new file mode 100644
index 0000000..bc8f8b8
--- /dev/null
+++ b/chrome/browser/extensions/api/identity_private/OWNERS
@@ -0,0 +1 @@
+courage@chromium.org
diff --git a/chrome/browser/extensions/api/idle/idle_api_constants.cc b/chrome/browser/extensions/api/idle/idle_api_constants.cc
index 15d6325..84d42e0 100644
--- a/chrome/browser/extensions/api/idle/idle_api_constants.cc
+++ b/chrome/browser/extensions/api/idle/idle_api_constants.cc
@@ -8,8 +8,6 @@
 
 namespace idle_api_constants {
 
-const char kOnStateChanged[] = "idle.onStateChanged";
-
 const char kStateActive[] = "active";
 const char kStateIdle[] = "idle";
 const char kStateLocked[] = "locked";
diff --git a/chrome/browser/extensions/api/idle/idle_api_unittest.cc b/chrome/browser/extensions/api/idle/idle_api_unittest.cc
index bbffd00..cf6ee66 100644
--- a/chrome/browser/extensions/api/idle/idle_api_unittest.cc
+++ b/chrome/browser/extensions/api/idle/idle_api_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/api/idle/idle_manager_factory.h"
 #include "chrome/browser/extensions/event_router.h"
 #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"
@@ -25,6 +26,7 @@
 using ::testing::_;
 
 namespace utils = extension_function_test_utils;
+namespace idle = extensions::api::idle;
 
 namespace extensions {
 
@@ -107,13 +109,13 @@
                            const std::string& extension_id)
     : idle_manager_(idle_manager),
       extension_id_(extension_id) {
-  const EventListenerInfo details(idle_api_constants::kOnStateChanged,
+  const EventListenerInfo details(idle::OnStateChanged::kEventName,
                                   extension_id_);
   idle_manager_->OnListenerAdded(details);
 }
 
 ScopedListen::~ScopedListen() {
-  const EventListenerInfo details(idle_api_constants::kOnStateChanged,
+  const EventListenerInfo details(idle::OnStateChanged::kEventName,
                                   extension_id_);
   idle_manager_->OnListenerRemoved(details);
 }
diff --git a/chrome/browser/extensions/api/idle/idle_manager.cc b/chrome/browser/extensions/api/idle/idle_manager.cc
index 8b66e86..48785c7 100644
--- a/chrome/browser/extensions/api/idle/idle_manager.cc
+++ b/chrome/browser/extensions/api/idle/idle_manager.cc
@@ -12,12 +12,14 @@
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/idle.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_source.h"
 
 namespace keys = extensions::idle_api_constants;
+namespace idle = extensions::api::idle;
 
 namespace extensions {
 
@@ -51,7 +53,8 @@
                                           IdleState new_state) {
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(IdleManager::CreateIdleValue(new_state));
-  scoped_ptr<Event> event(new Event(keys::kOnStateChanged, args.Pass()));
+  scoped_ptr<Event> event(new Event(idle::OnStateChanged::kEventName,
+                                    args.Pass()));
   event->restrict_to_profile = profile_;
   ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
       extension_id, event.Pass());
@@ -60,7 +63,7 @@
 void DefaultEventDelegate::RegisterObserver(
     EventRouter::Observer* observer) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      observer, idle_api_constants::kOnStateChanged);
+      observer, idle::OnStateChanged::kEventName);
 }
 
 void DefaultEventDelegate::UnregisterObserver(EventRouter::Observer* observer) {
diff --git a/chrome/browser/extensions/api/idltest/idltest_api.cc b/chrome/browser/extensions/api/idltest/idltest_api.cc
index 98ef9b3..63e1efe 100644
--- a/chrome/browser/extensions/api/idltest/idltest_api.cc
+++ b/chrome/browser/extensions/api/idltest/idltest_api.cc
@@ -14,12 +14,12 @@
   base::ListValue* output = new base::ListValue();
   const char* input_buffer = input->GetBuffer();
   for (size_t i = 0; i < input->GetSize(); i++) {
-    output->Append(Value::CreateIntegerValue(input_buffer[i]));
+    output->Append(new base::FundamentalValue(input_buffer[i]));
   }
   return output;
 }
 
-}
+}  // namespace
 
 bool IdltestSendArrayBufferFunction::RunImpl() {
   BinaryValue* input = NULL;
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index e14c620..15baf4b 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -79,21 +79,6 @@
 
 }  // namespace
 
-namespace events {
-
-const char kOnActivate[] = "input.ime.onActivate";
-const char kOnDeactivated[] = "input.ime.onDeactivated";
-const char kOnFocus[] = "input.ime.onFocus";
-const char kOnBlur[] = "input.ime.onBlur";
-const char kOnInputContextUpdate[] = "input.ime.onInputContextUpdate";
-const char kOnKeyEvent[] = "input.ime.onKeyEvent";
-const char kOnCandidateClicked[] = "input.ime.onCandidateClicked";
-const char kOnMenuItemActivated[] = "input.ime.onMenuItemActivated";
-const char kOnSurroundingTextChanged[] = "input.ime.onSurroundingTextChanged";
-const char kOnReset[] = "input.ime.onReset";
-
-}  // namespace events
-
 namespace chromeos {
 class ImeObserver : public chromeos::InputMethodEngine::Observer {
  public:
@@ -111,10 +96,10 @@
       return;
 
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateStringValue(engine_id));
+    args->Append(new base::StringValue(engine_id));
 
     DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnActivate, args.Pass());
+                             input_ime::OnActivate::kEventName, args.Pass());
   }
 
   virtual void OnDeactivated(const std::string& engine_id) OVERRIDE {
@@ -122,10 +107,10 @@
       return;
 
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateStringValue(engine_id));
+    args->Append(new base::StringValue(engine_id));
 
     DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnDeactivated, args.Pass());
+                             input_ime::OnDeactivated::kEventName, args.Pass());
   }
 
   virtual void OnFocus(
@@ -141,7 +126,7 @@
     args->Append(dict);
 
     DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnFocus, args.Pass());
+                             input_ime::OnFocus::kEventName, args.Pass());
   }
 
   virtual void OnBlur(int context_id) OVERRIDE {
@@ -149,10 +134,10 @@
       return;
 
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateIntegerValue(context_id));
+    args->Append(new base::FundamentalValue(context_id));
 
     DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnBlur, args.Pass());
+                             input_ime::OnBlur::kEventName, args.Pass());
   }
 
   virtual void OnInputContextUpdate(
@@ -167,8 +152,10 @@
     scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(dict);
 
-    DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnInputContextUpdate, args.Pass());
+    DispatchEventToExtension(profile_,
+                             extension_id_,
+                             input_ime::OnInputContextUpdate::kEventName,
+                             args.Pass());
   }
 
   virtual void OnKeyEvent(
@@ -193,11 +180,11 @@
     dict->SetBoolean("capsLock", event.caps_lock);
 
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateStringValue(engine_id));
+    args->Append(new base::StringValue(engine_id));
     args->Append(dict);
 
     DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnKeyEvent, args.Pass());
+                             input_ime::OnKeyEvent::kEventName, args.Pass());
   }
 
   virtual void OnCandidateClicked(
@@ -208,26 +195,28 @@
       return;
 
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateStringValue(engine_id));
-    args->Append(Value::CreateIntegerValue(candidate_id));
+    args->Append(new base::StringValue(engine_id));
+    args->Append(new base::FundamentalValue(candidate_id));
     switch (button) {
       case chromeos::InputMethodEngine::MOUSE_BUTTON_MIDDLE:
-        args->Append(Value::CreateStringValue("middle"));
+        args->Append(new base::StringValue("middle"));
         break;
 
       case chromeos::InputMethodEngine::MOUSE_BUTTON_RIGHT:
-        args->Append(Value::CreateStringValue("right"));
+        args->Append(new base::StringValue("right"));
         break;
 
       case chromeos::InputMethodEngine::MOUSE_BUTTON_LEFT:
       // Default to left.
       default:
-        args->Append(Value::CreateStringValue("left"));
+        args->Append(new base::StringValue("left"));
         break;
     }
 
-    DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnCandidateClicked, args.Pass());
+    DispatchEventToExtension(profile_,
+                             extension_id_,
+                             input_ime::OnCandidateClicked::kEventName,
+                             args.Pass());
   }
 
   virtual void OnMenuItemActivated(const std::string& engine_id,
@@ -236,11 +225,13 @@
       return;
 
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateStringValue(engine_id));
-    args->Append(Value::CreateStringValue(menu_id));
+    args->Append(new base::StringValue(engine_id));
+    args->Append(new base::StringValue(menu_id));
 
-    DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnMenuItemActivated, args.Pass());
+    DispatchEventToExtension(profile_,
+                             extension_id_,
+                             input_ime::OnMenuItemActivated::kEventName,
+                             args.Pass());
   }
 
   virtual void OnSurroundingTextChanged(const std::string& engine_id,
@@ -255,21 +246,25 @@
     dict->SetInteger("anchor", anchor_pos);
 
     scoped_ptr<ListValue> args(new base::ListValue);
-    args->Append(Value::CreateStringValue(engine_id));
+    args->Append(new base::StringValue(engine_id));
     args->Append(dict);
 
-    DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnSurroundingTextChanged, args.Pass());
+    DispatchEventToExtension(profile_,
+                             extension_id_,
+                             input_ime::OnSurroundingTextChanged::kEventName,
+                             args.Pass());
   }
 
   virtual void OnReset(const std::string& engine_id) OVERRIDE {
     if (profile_ == NULL || extension_id_.empty())
       return;
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateStringValue(engine_id));
+    args->Append(new base::StringValue(engine_id));
 
-    DispatchEventToExtension(profile_, extension_id_,
-                             events::kOnReset, args.Pass());
+    DispatchEventToExtension(profile_,
+                             extension_id_,
+                             input_ime::OnReset::kEventName,
+                             args.Pass());
   }
 
  private:
@@ -436,7 +431,7 @@
   chromeos::InputMethodEngine* engine =
       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
   if (!engine) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     return true;
   }
 
@@ -471,7 +466,7 @@
   int selection_end =
       params.selection_end ? *params.selection_end : params.cursor;
 
-  SetResult(Value::CreateBooleanValue(
+  SetResult(new base::FundamentalValue(
       engine->SetComposition(params.context_id, params.text.c_str(),
                              selection_start, selection_end, params.cursor,
                              segments, &error_)));
@@ -482,7 +477,7 @@
   chromeos::InputMethodEngine* engine =
       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
   if (!engine) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     return true;
   }
 
@@ -491,7 +486,7 @@
   const ClearComposition::Params::Parameters& params =
       parent_params->parameters;
 
-  SetResult(Value::CreateBooleanValue(
+  SetResult(new base::FundamentalValue(
       engine->ClearComposition(params.context_id, &error_)));
   return true;
 }
@@ -501,7 +496,7 @@
   chromeos::InputMethodEngine* engine =
       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
   if (!engine) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     return true;
   }
 
@@ -510,7 +505,7 @@
   const CommitText::Params::Parameters& params =
       parent_params->parameters;
 
-  SetResult(Value::CreateBooleanValue(
+  SetResult(new base::FundamentalValue(
       engine->CommitText(params.context_id, params.text.c_str(), &error_)));
   return true;
 }
@@ -526,7 +521,7 @@
                                                     params.engine_id);
 
   if (!engine) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     return true;
   }
 
@@ -535,7 +530,7 @@
 
   if (properties.visible &&
       !engine->SetCandidateWindowVisible(*properties.visible, &error_)) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     return true;
   }
 
@@ -568,7 +563,7 @@
         chromeos::InputMethodEngine::WINDOW_POS_CURSOR);
   }
 
-  SetResult(Value::CreateBooleanValue(true));
+  SetResult(new base::FundamentalValue(true));
 
   return true;
 }
@@ -578,7 +573,7 @@
   chromeos::InputMethodEngine* engine =
       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
   if (!engine) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     return true;
   }
 
@@ -605,7 +600,7 @@
     }
   }
 
-  SetResult(Value::CreateBooleanValue(
+  SetResult(new base::FundamentalValue(
       engine->SetCandidates(params.context_id, candidates_out, &error_)));
   return true;
 }
@@ -614,7 +609,7 @@
   chromeos::InputMethodEngine* engine =
       InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id());
   if (!engine) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     return true;
   }
 
@@ -623,7 +618,7 @@
   const SetCursorPosition::Params::Parameters& params =
       parent_params->parameters;
 
-  SetResult(Value::CreateBooleanValue(
+  SetResult(new base::FundamentalValue(
       engine->SetCursorPosition(params.context_id, params.candidate_id,
                                 &error_)));
   return true;
diff --git a/chrome/browser/extensions/api/location/location_manager.cc b/chrome/browser/extensions/api/location/location_manager.cc
index 5611a43..95579a3 100644
--- a/chrome/browser/extensions/api/location/location_manager.cc
+++ b/chrome/browser/extensions/api/location/location_manager.cc
@@ -382,12 +382,12 @@
     location.timestamp = position.timestamp.ToJsTime();
 
     args->Append(location.ToValue().release());
-    event_name = "location.onLocationUpdate";
+    event_name = location::OnLocationUpdate::kEventName;
   } else {
     // Set data for onLocationError event.
     // TODO(vadimt): Set name.
     args->AppendString(position.error_message);
-    event_name = "location.onLocationError";
+    event_name = location::OnLocationError::kEventName;
   }
 
   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
diff --git a/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc b/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
index 2e6e343..eaee867 100644
--- a/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
+++ b/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
@@ -11,6 +11,8 @@
 #include "base/logging.h"
 #include "base/memory/linked_ptr.h"
 #include "base/memory/scoped_ptr.h"
+#include "chrome/browser/chromeos/system_logs/about_system_logs_fetcher.h"
+#include "chrome/browser/chromeos/system_logs/scrubbed_system_logs_fetcher.h"
 #include "chrome/browser/extensions/api/log_private/filter_handler.h"
 #include "chrome/browser/extensions/api/log_private/log_parser.h"
 #include "chrome/browser/extensions/api/log_private/syslog_parser.h"
@@ -61,10 +63,15 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   filter_handler_.reset(new FilterHandler(params->filter));
 
-  chromeos::AboutSystemLogsFetcher* fetcher =
-      new chromeos::AboutSystemLogsFetcher();
+  chromeos::SystemLogsFetcherBase* fetcher;
+  if ((params->filter).scrub) {
+    fetcher = new chromeos::ScrubbedSystemLogsFetcher();
+  } else {
+    fetcher = new chromeos::AboutSystemLogsFetcher();
+  }
   fetcher->Fetch(
       base::Bind(&LogPrivateGetHistoricalFunction::OnSystemLogsLoaded, this));
+
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/management/management_api.cc b/chrome/browser/extensions/api/management/management_api.cc
index 3e6b19e..eb776d1 100644
--- a/chrome/browser/extensions/api/management/management_api.cc
+++ b/chrome/browser/extensions/api/management/management_api.cc
@@ -20,7 +20,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/management/management_api_constants.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -60,7 +59,6 @@
 
 namespace extensions {
 
-namespace events = event_names;
 namespace management = api::management;
 
 namespace {
@@ -209,8 +207,8 @@
        iter != extensions.end(); ++iter) {
     const Extension& extension = *iter->get();
 
-    if (extension.location() == Manifest::COMPONENT)
-      continue;  // Skip built-in extensions.
+    if (extension.ShouldNotBeVisible())
+      continue;  // Skip built-in extensions/apps.
 
     extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
         CreateExtensionInfo(extension, system).release()));
@@ -459,7 +457,7 @@
   extension_id_ = params->id;
 
   const Extension* extension = service()->GetInstalledExtension(extension_id_);
-  if (!extension) {
+  if (!extension || extension->ShouldNotBeVisible()) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kNoExtensionError, extension_id_);
     return false;
@@ -524,7 +522,7 @@
     bool show_confirm_dialog) {
   extension_id_ = extension_id;
   const Extension* extension = service()->GetExtensionById(extension_id_, true);
-  if (!extension) {
+  if (!extension || extension->ShouldNotBeVisible()) {
     error_ = ErrorUtils::FormatErrorMessage(
         keys::kNoExtensionError, extension_id_);
     return false;
@@ -652,20 +650,20 @@
 
   switch (type) {
     case chrome::NOTIFICATION_EXTENSION_INSTALLED:
-      event_name = events::kOnExtensionInstalled;
+      event_name = management::OnInstalled::kEventName;
       extension =
           content::Details<const InstalledExtensionInfo>(details)->extension;
       break;
     case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
-      event_name = events::kOnExtensionUninstalled;
+      event_name = management::OnUninstalled::kEventName;
       extension = content::Details<const Extension>(details).ptr();
       break;
     case chrome::NOTIFICATION_EXTENSION_LOADED:
-      event_name = events::kOnExtensionEnabled;
+      event_name = management::OnEnabled::kEventName;
       extension = content::Details<const Extension>(details).ptr();
       break;
     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
-      event_name = events::kOnExtensionDisabled;
+      event_name = management::OnDisabled::kEventName;
       extension =
           content::Details<const UnloadedExtensionInfo>(details)->extension;
       break;
@@ -676,9 +674,12 @@
   DCHECK(event_name);
   DCHECK(extension);
 
+  if (extension->ShouldNotBeVisible())
+    return; // Don't dispatch events for built-in extensions.
+
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  if (event_name == events::kOnExtensionUninstalled) {
-    args->Append(Value::CreateStringValue(extension->id()));
+  if (event_name == management::OnUninstalled::kEventName) {
+    args->Append(new base::StringValue(extension->id()));
   } else {
     scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo(
         *extension, ExtensionSystem::Get(profile));
@@ -692,13 +693,13 @@
 ManagementAPI::ManagementAPI(Profile* profile)
     : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, events::kOnExtensionInstalled);
+      this, management::OnInstalled::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, events::kOnExtensionUninstalled);
+      this, management::OnUninstalled::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, events::kOnExtensionEnabled);
+      this, management::OnEnabled::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, events::kOnExtensionDisabled);
+      this, management::OnDisabled::kEventName);
 }
 
 ManagementAPI::~ManagementAPI() {
diff --git a/chrome/browser/extensions/api/management/management_apitest.cc b/chrome/browser/extensions/api/management/management_apitest.cc
index 6e98c56..b028805 100644
--- a/chrome/browser/extensions/api/management/management_apitest.cc
+++ b/chrome/browser/extensions/api/management/management_apitest.cc
@@ -17,8 +17,8 @@
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/common/manifest.h"
 
 using extensions::Extension;
 using extensions::Manifest;
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 d89bb6c..73aaeb4 100644
--- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -8,11 +8,11 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/browser/media_galleries/media_file_system_registry.h"
 #include "chrome/browser/media_galleries/media_galleries_preferences.h"
 #include "chrome/browser/media_galleries/media_galleries_test_util.h"
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc
deleted file mode 100644
index ba8407e..0000000
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc
+++ /dev/null
@@ -1,146 +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.
-//
-// MediaGalleriesPrivate eject API browser tests.
-
-#include "base/files/file_path.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/media_galleries/media_galleries_test_util.h"
-#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/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/test/test_utils.h"
-
-namespace {
-
-// Id of test extension from
-// chrome/test/data/extensions/api_test/|kTestExtensionPath|
-const char kTestExtensionId[] = "omeaapacpflbppbhigoacmagclbjhhmo";
-const char kTestExtensionPath[] = "media_galleries_private/eject";
-
-// JS commands.
-const char kAddAttachListenerCmd[] = "addAttachListener()";
-const char kRemoveAttachListenerCmd[] = "removeAttachListener()";
-const char kEjectTestCmd[] = "ejectTest()";
-const char kEjectFailTestCmd[] = "ejectFailTest()";
-
-// And JS reply messages.
-const char kAddAttachListenerOk[] = "add_attach_ok";
-const char kAttachTestOk[] = "attach_test_ok";
-const char kRemoveAttachListenerOk[] = "remove_attach_ok";
-const char kEjectListenerOk[] = "eject_ok";
-const char kEjectFailListenerOk[] = "eject_no_such_device";
-
-const char kDeviceId[] = "testDeviceId";
-const char kDeviceName[] = "foobar";
-base::FilePath::CharType kDevicePath[] = FILE_PATH_LITERAL("/qux");
-
-}  // namespace
-
-
-///////////////////////////////////////////////////////////////////////////////
-//                 MediaGalleriesPrivateEjectApiTest                         //
-///////////////////////////////////////////////////////////////////////////////
-
-class MediaGalleriesPrivateEjectApiTest : public ExtensionApiTest {
- public:
-  MediaGalleriesPrivateEjectApiTest()
-      : device_id_(GetDeviceId()),
-        monitor_(NULL) {}
-  virtual ~MediaGalleriesPrivateEjectApiTest() {}
-
- protected:
-  // ExtensionApiTest overrides.
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    ExtensionApiTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitchASCII(switches::kWhitelistedExtensionID,
-                                    kTestExtensionId);
-  }
-
-  virtual void SetUpOnMainThread() OVERRIDE {
-    monitor_ = chrome::test::TestStorageMonitor::CreateForBrowserTests();
-    ExtensionApiTest::SetUpOnMainThread();
-  }
-
-  content::RenderViewHost* GetHost() {
-    const extensions::Extension* extension =
-        LoadExtension(test_data_dir_.AppendASCII(kTestExtensionPath));
-    return extensions::ExtensionSystem::Get(browser()->profile())->
-        process_manager()->GetBackgroundHostForExtension(extension->id())->
-            render_view_host();
-  }
-
-  void ExecuteCmdAndCheckReply(content::RenderViewHost* host,
-                               const std::string& js_command,
-                               const std::string& ok_message) {
-    ExtensionTestMessageListener listener(ok_message, false);
-    host->ExecuteJavascriptInWebFrame(string16(), ASCIIToUTF16(js_command));
-    EXPECT_TRUE(listener.WaitUntilSatisfied());
-  }
-
-  void Attach() {
-    DCHECK(chrome::StorageMonitor::GetInstance()->IsInitialized());
-    chrome::StorageInfo info(device_id_, ASCIIToUTF16(kDeviceName), kDevicePath,
-                             string16(), string16(), string16(), 0);
-    chrome::StorageMonitor::GetInstance()->receiver()->ProcessAttach(info);
-    content::RunAllPendingInMessageLoop();
-  }
-
-  void Detach() {
-    DCHECK(chrome::StorageMonitor::GetInstance()->IsInitialized());
-    chrome::StorageMonitor::GetInstance()->receiver()->ProcessDetach(
-        device_id_);
-    content::RunAllPendingInMessageLoop();
-  }
-
-  static std::string GetDeviceId() {
-    return chrome::StorageInfo::MakeDeviceId(
-        chrome::StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, kDeviceId);
-  }
-
- protected:
-  const std::string device_id_;
-
-  chrome::test::TestStorageMonitor* monitor_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MediaGalleriesPrivateEjectApiTest);
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-//                               TESTS                                       //
-///////////////////////////////////////////////////////////////////////////////
-
-IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateEjectApiTest, EjectTest) {
-  content::RenderViewHost* host = GetHost();
-  ExecuteCmdAndCheckReply(host, kAddAttachListenerCmd, kAddAttachListenerOk);
-
-  // Attach / detach
-  const std::string expect_attach_msg =
-      base::StringPrintf("%s,%s", kAttachTestOk, kDeviceName);
-  ExtensionTestMessageListener attach_finished_listener(expect_attach_msg,
-                                                        false  /* no reply */);
-  Attach();
-  EXPECT_TRUE(attach_finished_listener.WaitUntilSatisfied());
-
-  ExecuteCmdAndCheckReply(host, kEjectTestCmd, kEjectListenerOk);
-  EXPECT_EQ(device_id_, monitor_->ejected_device());
-
-  Detach();
-}
-
-IN_PROC_BROWSER_TEST_F(MediaGalleriesPrivateEjectApiTest, EjectBadDeviceTest) {
-  ExecuteCmdAndCheckReply(GetHost(), kEjectFailTestCmd, kEjectFailListenerOk);
-
-  EXPECT_EQ("", monitor_->ejected_device());
-}
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 e3e974d..eb503a8 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
@@ -38,8 +38,8 @@
     extensions::api::media_galleries_private::RemoveGalleryWatch;
 namespace GetAllGalleryWatch =
     extensions::api::media_galleries_private::GetAllGalleryWatch;
-namespace EjectDevice =
-    extensions::api::media_galleries_private::EjectDevice;
+namespace media_galleries_private =
+    api::media_galleries_private;
 
 namespace {
 
@@ -87,11 +87,11 @@
       weak_ptr_factory_(this) {
   DCHECK(profile_);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnAttachEventName);
+      this, media_galleries_private::OnDeviceAttached::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnDetachEventName);
+      this, media_galleries_private::OnDeviceDetached::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnGalleryChangedEventName);
+      this, media_galleries_private::OnGalleryChanged::kEventName);
 }
 
 MediaGalleriesPrivateAPI::~MediaGalleriesPrivateAPI() {
@@ -217,7 +217,7 @@
     chrome::MediaGalleryPrefId gallery_id,
     bool success) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  extensions::api::media_galleries_private::AddGalleryWatchResult result;
+  media_galleries_private::AddGalleryWatchResult result;
   result.gallery_id = base::Uint64ToString(gallery_id);
   result.success = success;
   SetResult(result.ToValue().release());
@@ -357,69 +357,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-//              MediaGalleriesPrivateEjectDeviceFunction                     //
-///////////////////////////////////////////////////////////////////////////////
-
-MediaGalleriesPrivateEjectDeviceFunction::
-~MediaGalleriesPrivateEjectDeviceFunction() {
-}
-
-bool MediaGalleriesPrivateEjectDeviceFunction::RunImpl() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
-  scoped_ptr<EjectDevice::Params> params(EjectDevice::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-
-  chrome::StorageMonitor::GetInstance()->EnsureInitialized(base::Bind(
-      &MediaGalleriesPrivateEjectDeviceFunction::OnStorageMonitorInit,
-      this,
-      params->device_id));
-  return true;
-}
-
-void MediaGalleriesPrivateEjectDeviceFunction::OnStorageMonitorInit(
-    const std::string& transient_device_id) {
-  DCHECK(chrome::StorageMonitor::GetInstance()->IsInitialized());
-  chrome::StorageMonitor* monitor = chrome::StorageMonitor::GetInstance();
-  std::string device_id_str =
-      monitor->GetDeviceIdForTransientId(transient_device_id);
-  if (device_id_str == "") {
-    HandleResponse(chrome::StorageMonitor::EJECT_NO_SUCH_DEVICE);
-    return;
-  }
-
-  monitor->EjectDevice(
-      device_id_str,
-      base::Bind(&MediaGalleriesPrivateEjectDeviceFunction::HandleResponse,
-                 this));
-}
-
-void MediaGalleriesPrivateEjectDeviceFunction::HandleResponse(
-    chrome::StorageMonitor::EjectStatus status) {
-  using extensions::api::media_galleries_private::
-      EJECT_DEVICE_RESULT_CODE_FAILURE;
-  using extensions::api::media_galleries_private::
-      EJECT_DEVICE_RESULT_CODE_IN_USE;
-  using extensions::api::media_galleries_private::
-      EJECT_DEVICE_RESULT_CODE_NO_SUCH_DEVICE;
-  using extensions::api::media_galleries_private::
-      EJECT_DEVICE_RESULT_CODE_SUCCESS;
-  using extensions::api::media_galleries_private::EjectDeviceResultCode;
-
-  EjectDeviceResultCode result = EJECT_DEVICE_RESULT_CODE_FAILURE;
-  if (status == chrome::StorageMonitor::EJECT_OK)
-    result = EJECT_DEVICE_RESULT_CODE_SUCCESS;
-  if (status == chrome::StorageMonitor::EJECT_IN_USE)
-    result = EJECT_DEVICE_RESULT_CODE_IN_USE;
-  if (status == chrome::StorageMonitor::EJECT_NO_SUCH_DEVICE)
-    result = EJECT_DEVICE_RESULT_CODE_NO_SUCH_DEVICE;
-
-  SetResult(base::StringValue::CreateStringValue(
-      api::media_galleries_private::ToString(result)));
-  SendResponse(true);
-}
-
-///////////////////////////////////////////////////////////////////////////////
 //              MediaGalleriesPrivateGetHandlersFunction                     //
 ///////////////////////////////////////////////////////////////////////////////
 
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 84dd4fb..d2165b5 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
@@ -15,7 +15,6 @@
 #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/browser/storage_monitor/storage_monitor.h"
 #include "chrome/common/extensions/api/media_galleries_private.h"
 
 class Profile;
@@ -143,26 +142,6 @@
   void OnStorageMonitorInit();
 };
 
-// Implements the chrome.mediaGalleriesPrivate.ejectDevice method.
-class MediaGalleriesPrivateEjectDeviceFunction
-    : public AsyncExtensionFunction {
- public:
-  DECLARE_EXTENSION_FUNCTION("mediaGalleriesPrivate.ejectDevice",
-                             MEDIAGALLERIESPRIVATE_EJECTDEVICE);
-
- protected:
-  virtual ~MediaGalleriesPrivateEjectDeviceFunction();
-
-  // AsyncExtensionFunction overrides.
-  virtual bool RunImpl() OVERRIDE;
-
- private:
-  void OnStorageMonitorInit(const std::string& transient_device_id);
-
-  // Eject device request handler.
-  void HandleResponse(chrome::StorageMonitor::EjectStatus status);
-};
-
 // Implements the chrome.mediaGalleriesPrivate.getHandlers method.
 class MediaGalleriesPrivateGetHandlersFunction
     : public AsyncExtensionFunction {
diff --git a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc
index 2522239..8f0baf3 100644
--- a/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc
+++ b/chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.cc
@@ -18,6 +18,8 @@
 #include "chrome/common/extensions/api/media_galleries_private.h"
 #include "content/public/browser/browser_thread.h"
 
+namespace media_galleries_private = extensions::api::media_galleries_private;
+
 namespace extensions {
 
 namespace {
@@ -29,9 +31,9 @@
 
 }  // namespace
 
-using extensions::api::media_galleries_private::DeviceAttachmentDetails;
-using extensions::api::media_galleries_private::DeviceDetachmentDetails;
-using extensions::api::media_galleries_private::GalleryChangeDetails;
+using media_galleries_private::DeviceAttachmentDetails;
+using media_galleries_private::DeviceDetachmentDetails;
+using media_galleries_private::GalleryChangeDetails;
 
 MediaGalleriesPrivateEventRouter::MediaGalleriesPrivateEventRouter(
     Profile* profile)
@@ -55,7 +57,8 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   EventRouter* router =
       extensions::ExtensionSystem::Get(profile_)->event_router();
-  if (!router->HasEventListener(event_names::kOnGalleryChangedEventName))
+  if (!router->HasEventListener(
+          media_galleries_private::OnGalleryChanged::kEventName))
     return;
 
   for (std::set<std::string>::const_iterator it = extension_ids.begin();
@@ -65,7 +68,7 @@
     scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(details.ToValue().release());
     scoped_ptr<extensions::Event> event(new extensions::Event(
-        event_names::kOnGalleryChangedEventName,
+        media_galleries_private::OnGalleryChanged::kEventName,
         args.Pass()));
     // Use DispatchEventToExtension() instead of BroadcastEvent().
     // BroadcastEvent() sends the gallery changed events to all the extensions
@@ -83,7 +86,8 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   EventRouter* router =
       extensions::ExtensionSystem::Get(profile_)->event_router();
-  if (!router->HasEventListener(event_names::kOnAttachEventName))
+  if (!router->HasEventListener(
+          media_galleries_private::OnDeviceAttached::kEventName))
     return;
 
   chrome::MediaGalleryPrefInfo pref_info;
@@ -102,7 +106,8 @@
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(details.ToValue().release());
-  DispatchEvent(event_names::kOnAttachEventName, args.Pass());
+  DispatchEvent(
+      media_galleries_private::OnDeviceAttached::kEventName, args.Pass());
 }
 
 void MediaGalleriesPrivateEventRouter::OnRemovableStorageDetached(
@@ -110,7 +115,8 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   EventRouter* router =
       extensions::ExtensionSystem::Get(profile_)->event_router();
-  if (!router->HasEventListener(event_names::kOnDetachEventName))
+  if (!router->HasEventListener(
+          media_galleries_private::OnDeviceDetached::kEventName))
     return;
 
   DeviceDetachmentDetails details;
@@ -118,7 +124,8 @@
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(details.ToValue().release());
-  DispatchEvent(event_names::kOnDetachEventName, args.Pass());
+  DispatchEvent(
+      media_galleries_private::OnDeviceDetached::kEventName, args.Pass());
 }
 
 void MediaGalleriesPrivateEventRouter::DispatchEvent(
diff --git a/chrome/browser/extensions/api/messaging/OWNERS b/chrome/browser/extensions/api/messaging/OWNERS
new file mode 100644
index 0000000..784f1a9
--- /dev/null
+++ b/chrome/browser/extensions/api/messaging/OWNERS
@@ -0,0 +1,6 @@
+# For extension/app messaging.
+kalman@chromium.org
+mpcomplete@chromium.org
+
+# For native messaging.
+sergeyu@chromium.org
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index 00e40f7..be6d2fe 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/incognito_handler.h"
 #include "chrome/common/extensions/manifest_handlers/externally_connectable.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/common/manifest_constants.h"
 #include "url/gurl.h"
 
 using content::SiteInstance;
@@ -113,7 +113,7 @@
 static content::RenderProcessHost* GetExtensionProcess(
     Profile* profile, const std::string& extension_id) {
   SiteInstance* site_instance =
-      extensions::ExtensionSystem::Get(profile)->process_manager()->
+      ExtensionSystem::Get(profile)->process_manager()->
           GetSiteInstanceForURL(
               Extension::GetBaseURLFromExtensionId(extension_id));
 
@@ -206,7 +206,7 @@
   }
 
   ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
+      ExtensionSystem::Get(profile)->extension_service();
 
   if (profile->IsOffTheRecord() &&
       !extension_service->IsIncognitoEnabled(target_extension_id)) {
@@ -222,7 +222,7 @@
     ExternallyConnectableInfo* externally_connectable =
         static_cast<ExternallyConnectableInfo*>(
             target_extension->GetManifestData(
-                extension_manifest_keys::kExternallyConnectable));
+                manifest_keys::kExternallyConnectable));
     bool is_externally_connectable = false;
 
     if (externally_connectable) {
@@ -305,7 +305,7 @@
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
   ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
+      ExtensionSystem::Get(profile)->extension_service();
   bool has_permission = false;
   if (extension_service) {
     const Extension* extension =
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.cc b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
index 40535eb..32f3389 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
@@ -13,8 +13,8 @@
 #include "chrome/browser/extensions/api/messaging/native_messaging_host_manifest.h"
 #include "chrome/browser/extensions/api/messaging/native_process_launcher.h"
 #include "chrome/common/chrome_version_info.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/features/feature.h"
 #include "net/base/file_stream.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
index d5d712a..f42cf4a 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_apitest.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
-#include "chrome/common/extensions/features/feature.h"
+#include "extensions/common/features/feature.h"
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, NativeMessageBasic) {
   base::ScopedTempDir temp_dir;
diff --git a/chrome/browser/extensions/api/metrics_private/OWNERS b/chrome/browser/extensions/api/metrics_private/OWNERS
new file mode 100644
index 0000000..feb8271
--- /dev/null
+++ b/chrome/browser/extensions/api/metrics_private/OWNERS
@@ -0,0 +1,2 @@
+asvitkine@chromium.org
+isherman@chromium.org
diff --git a/chrome/browser/extensions/api/module/OWNERS b/chrome/browser/extensions/api/module/OWNERS
new file mode 100644
index 0000000..c35595c
--- /dev/null
+++ b/chrome/browser/extensions/api/module/OWNERS
@@ -0,0 +1 @@
+asargent@chromium.org
diff --git a/chrome/browser/extensions/api/module/module.cc b/chrome/browser/extensions/api/module/module.cc
index d9c11b7..b1295d1 100644
--- a/chrome/browser/extensions/api/module/module.cc
+++ b/chrome/browser/extensions/api/module/module.cc
@@ -41,7 +41,7 @@
   ExtensionPrefs::Get(profile())->UpdateExtensionPref(
       extension_id(),
       extension::kUpdateURLData,
-      base::Value::CreateStringValue(data));
+      new base::StringValue(data));
   return true;
 }
 
@@ -50,7 +50,7 @@
       ExtensionSystem::Get(profile())->extension_service();
   const Extension* extension = GetExtension();
 
-  SetResult(Value::CreateBooleanValue(
+  SetResult(new base::FundamentalValue(
       ext_service->IsIncognitoEnabled(extension->id())));
   return true;
 }
@@ -60,7 +60,7 @@
       ExtensionSystem::Get(profile())->extension_service();
   const Extension* extension = GetExtension();
 
-  SetResult(Value::CreateBooleanValue(
+  SetResult(new base::FundamentalValue(
       ext_service->AllowFileAccess(extension)));
   return true;
 }
diff --git a/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.cc b/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.cc
index 26d989c..5cca660 100644
--- a/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.cc
+++ b/chrome/browser/extensions/api/music_manager_private/music_manager_private_api.cc
@@ -44,7 +44,7 @@
     SetError(kDeviceIdNotSupported);
     response = false;
   } else {
-    SetResult(Value::CreateStringValue(device_id));
+    SetResult(new base::StringValue(device_id));
     response = true;
   }
 
diff --git a/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc b/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
index 553c729..1f9760a 100644
--- a/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
+++ b/chrome/browser/extensions/api/music_manager_private/music_manager_private_browsertest.cc
@@ -2,8 +2,8 @@
 // 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_browsertest_util.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 
 // Supported on all platforms, but on Windows only if RLZ is enabled.
 #if !defined(OS_WIN) || defined(ENABLE_RLZ)
diff --git a/chrome/browser/extensions/api/networking_private/OWNERS b/chrome/browser/extensions/api/networking_private/OWNERS
new file mode 100644
index 0000000..e84ebaf
--- /dev/null
+++ b/chrome/browser/extensions/api/networking_private/OWNERS
@@ -0,0 +1,2 @@
+stevenjb@chromium.org
+gspencer@chromium.org
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 79cb5bd..15adc7a 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
@@ -10,7 +10,6 @@
 #include "base/command_line.h"
 #include "base/json/json_reader.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_function_registry.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -18,8 +17,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/api/networking_private.h"
 
-using extensions::event_names::kOnNetworkListChanged;
-using extensions::event_names::kOnNetworksChanged;
 using extensions::EventRouter;
 using extensions::ExtensionSystem;
 namespace api = extensions::api::networking_private;
@@ -289,7 +286,7 @@
   EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
   scoped_ptr<base::ListValue> args(api::OnNetworkListChanged::Create(changes));
   scoped_ptr<extensions::Event> extension_event(new extensions::Event(
-      kOnNetworkListChanged, args.Pass()));
+      api::OnNetworkListChanged::kEventName, args.Pass()));
   event_router->BroadcastEvent(extension_event.Pass());
 
   return true;
@@ -307,7 +304,7 @@
       api::StartConnect::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params);
   if (params->network_guid == "nonexistent_path") {
-    error_ = "not-found";
+    error_ = "configure-failed";
     SendResponse(false);
   } else {
     SendResponse(true);
@@ -333,7 +330,7 @@
     scoped_ptr<base::ListValue> args(api::OnNetworksChanged::Create(
         std::vector<std::string>(1, params->network_guid)));
     scoped_ptr<extensions::Event> netchanged_event(
-        new extensions::Event(kOnNetworksChanged, args.Pass()));
+        new extensions::Event(api::OnNetworksChanged::kEventName, args.Pass()));
     event_router->BroadcastEvent(netchanged_event.Pass());
 
     // Generate NetworkListChanged event.
@@ -346,7 +343,7 @@
 
     scoped_ptr<base::ListValue> arg2(api::OnNetworkListChanged::Create(list));
     scoped_ptr<extensions::Event> netlist_event(new extensions::Event(
-        kOnNetworkListChanged, arg2.Pass()));
+        api::OnNetworkListChanged::kEventName, arg2.Pass()));
     event_router->BroadcastEvent(netlist_event.Pass());
   }
   return true;
@@ -374,7 +371,7 @@
     scoped_ptr<base::ListValue> args(api::OnNetworksChanged::Create(
         std::vector<std::string>(1, params->network_guid)));
     scoped_ptr<extensions::Event> extension_event(
-        new extensions::Event(kOnNetworksChanged, args.Pass()));
+        new extensions::Event(api::OnNetworksChanged::kEventName, args.Pass()));
     event_router->BroadcastEvent(extension_event.Pass());
   }
   return true;
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
index 3971278..ff5fe1a 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_apitest.cc
@@ -324,7 +324,7 @@
   policy.Set(policy::key::kOpenNetworkConfiguration,
              policy::POLICY_LEVEL_MANDATORY,
              policy::POLICY_SCOPE_USER,
-             Value::CreateStringValue(user_policy_blob),
+             new base::StringValue(user_policy_blob),
              NULL);
   provider_.UpdateChromePolicy(policy);
 
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_event_router_chromeos.cc b/chrome/browser/extensions/api/networking_private/networking_private_event_router_chromeos.cc
index 44d70eb..c431c7f 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_event_router_chromeos.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_event_router_chromeos.cc
@@ -7,7 +7,6 @@
 #include "base/json/json_writer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/networking_private/networking_private_api.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
@@ -22,8 +21,6 @@
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
-using extensions::event_names::kOnNetworkListChanged;
-using extensions::event_names::kOnNetworksChanged;
 using extensions::EventRouter;
 using extensions::ExtensionSystem;
 namespace api = extensions::api::networking_private;
@@ -39,9 +36,9 @@
   EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
   if (event_router) {
     event_router->RegisterObserver(
-        this, extensions::event_names::kOnNetworksChanged);
+        this, api::OnNetworksChanged::kEventName);
     event_router->RegisterObserver(
-        this, extensions::event_names::kOnNetworkListChanged);
+        this, api::OnNetworkListChanged::kEventName);
     StartOrStopListeningForNetworkChanges();
   }
 }
@@ -80,8 +77,9 @@
 
 void NetworkingPrivateEventRouter::StartOrStopListeningForNetworkChanges() {
   EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
-  bool should_listen = event_router->HasEventListener(kOnNetworksChanged) ||
-      event_router->HasEventListener(kOnNetworkListChanged);
+  bool should_listen =
+      event_router->HasEventListener(api::OnNetworksChanged::kEventName) ||
+      event_router->HasEventListener(api::OnNetworkListChanged::kEventName);
 
   if (should_listen && !listening_) {
     NetworkHandler::Get()->network_state_handler()->AddObserver(
@@ -97,7 +95,7 @@
   EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
   NetworkStateHandler::NetworkStateList networks;
   NetworkHandler::Get()->network_state_handler()->GetNetworkList(&networks);
-  if (!event_router->HasEventListener(kOnNetworkListChanged)) {
+  if (!event_router->HasEventListener(api::OnNetworkListChanged::kEventName)) {
     // TODO(stevenjb): Remove logging once crbug.com/256881 is fixed
     // (or at least reduce to LOG_DEBUG). Same with NET_LOG events below.
     NET_LOG_EVENT("NetworkingPrivate.NetworkListChanged: No Listeners", "");
@@ -117,14 +115,14 @@
 
   scoped_ptr<base::ListValue> args(api::OnNetworkListChanged::Create(changes));
   scoped_ptr<extensions::Event> extension_event(new extensions::Event(
-      kOnNetworkListChanged, args.Pass()));
+      api::OnNetworkListChanged::kEventName, args.Pass()));
   event_router->BroadcastEvent(extension_event.Pass());
 }
 
 void NetworkingPrivateEventRouter::NetworkPropertiesUpdated(
     const NetworkState* network) {
   EventRouter* event_router = ExtensionSystem::Get(profile_)->event_router();
-  if (!event_router->HasEventListener(kOnNetworksChanged)) {
+  if (!event_router->HasEventListener(api::OnNetworksChanged::kEventName)) {
     NET_LOG_EVENT("NetworkingPrivate.NetworkPropertiesUpdated: No Listeners",
                   network->path());
     return;
@@ -134,7 +132,7 @@
   scoped_ptr<base::ListValue> args(api::OnNetworksChanged::Create(
       std::vector<std::string>(1, network->path())));
   scoped_ptr<extensions::Event> extension_event(
-      new extensions::Event(kOnNetworksChanged, args.Pass()));
+      new extensions::Event(api::OnNetworksChanged::kEventName, args.Pass()));
   event_router->BroadcastEvent(extension_event.Pass());
 }
 
diff --git a/chrome/browser/extensions/api/notifications/notifications_api.cc b/chrome/browser/extensions/api/notifications/notifications_api.cc
index 257eb1a..9c330aa 100644
--- a/chrome/browser/extensions/api/notifications/notifications_api.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_api.cc
@@ -18,9 +18,9 @@
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "extensions/common/features/feature.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
@@ -32,6 +32,8 @@
 
 namespace extensions {
 
+namespace notifications = api::notifications;
+
 namespace {
 
 const char kResultKey[] = "result";
@@ -149,24 +151,24 @@
 
   virtual void Close(bool by_user) OVERRIDE {
     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
-    args->Append(Value::CreateBooleanValue(by_user));
-    SendEvent(event_names::kOnNotificationClosed, args.Pass());
+    args->Append(new base::FundamentalValue(by_user));
+    SendEvent(notifications::OnClosed::kEventName, args.Pass());
   }
 
   virtual void Click() OVERRIDE {
     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
-    SendEvent(event_names::kOnNotificationClicked, args.Pass());
+    SendEvent(notifications::OnClicked::kEventName, args.Pass());
   }
 
   virtual bool HasClickedListener() OVERRIDE {
     return ExtensionSystem::Get(profile_)->event_router()->HasEventListener(
-        event_names::kOnNotificationClicked);
+        notifications::OnClicked::kEventName);
   }
 
   virtual void ButtonClick(int index) OVERRIDE {
     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
-    args->Append(Value::CreateIntegerValue(index));
-    SendEvent(event_names::kOnNotificationButtonClicked, args.Pass());
+    args->Append(new base::FundamentalValue(index));
+    SendEvent(notifications::OnButtonClicked::kEventName, args.Pass());
   }
 
   virtual std::string id() const OVERRIDE {
@@ -202,7 +204,7 @@
 
   scoped_ptr<base::ListValue> CreateBaseEventArgs() {
     scoped_ptr<base::ListValue> args(new base::ListValue());
-    args->Append(Value::CreateStringValue(id_));
+    args->Append(new base::StringValue(id_));
     return args.Pass();
   }
 
@@ -491,7 +493,7 @@
   else
     notification_id = kNotificationPrefix + base::Uint64ToString(next_id_++);
 
-  SetResult(Value::CreateStringValue(notification_id));
+  SetResult(new base::StringValue(notification_id));
 
   // TODO(dewittj): Add more human-readable error strings if this fails.
   if (!CreateNotification(notification_id, &params_->options))
@@ -518,7 +520,7 @@
       g_browser_process->notification_ui_manager()->FindById(
           CreateScopedIdentifier(extension_->id(), params_->notification_id));
   if (!matched_notification) {
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     SendResponse(true);
     return true;
   }
@@ -530,7 +532,7 @@
   Notification notification = *matched_notification;
   bool could_update_notification = UpdateNotification(
       params_->notification_id, &params_->options, &notification);
-  SetResult(Value::CreateBooleanValue(could_update_notification));
+  SetResult(new base::FundamentalValue(could_update_notification));
   if (!could_update_notification)
     return false;
 
@@ -553,7 +555,7 @@
   bool cancel_result = g_browser_process->notification_ui_manager()->CancelById(
       CreateScopedIdentifier(extension_->id(), params_->notification_id));
 
-  SetResult(Value::CreateBooleanValue(cancel_result));
+  SetResult(new base::FundamentalValue(cancel_result));
   SendResponse(true);
 
   return true;
diff --git a/chrome/browser/extensions/api/notifications/notifications_apitest.cc b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
index c745215..bd85021 100644
--- a/chrome/browser/extensions/api/notifications/notifications_apitest.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
@@ -8,9 +8,9 @@
 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/common/features/feature.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_switches.h"
 #include "ui/message_center/message_center_util.h"
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
index 06db5b8..585b39e 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
@@ -27,13 +27,6 @@
 #include "content/public/browser/notification_service.h"
 #include "ui/gfx/image/image.h"
 
-namespace events {
-const char kOnInputStarted[] = "omnibox.onInputStarted";
-const char kOnInputChanged[] = "omnibox.onInputChanged";
-const char kOnInputEntered[] = "omnibox.onInputEntered";
-const char kOnInputCancelled[] = "omnibox.onInputCancelled";
-}  // namespace events
-
 namespace extensions {
 
 namespace omnibox = api::omnibox;
@@ -112,7 +105,8 @@
 void ExtensionOmniboxEventRouter::OnInputStarted(
     Profile* profile, const std::string& extension_id) {
   scoped_ptr<Event> event(new Event(
-      events::kOnInputStarted, make_scoped_ptr(new base::ListValue())));
+      omnibox::OnInputStarted::kEventName,
+      make_scoped_ptr(new base::ListValue())));
   event->restrict_to_profile = profile;
   ExtensionSystem::Get(profile)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
@@ -123,14 +117,16 @@
     Profile* profile, const std::string& extension_id,
     const std::string& input, int suggest_id) {
   if (!extensions::ExtensionSystem::Get(profile)->event_router()->
-          ExtensionHasEventListener(extension_id, events::kOnInputChanged))
+          ExtensionHasEventListener(extension_id,
+                                    omnibox::OnInputChanged::kEventName))
     return false;
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Set(0, Value::CreateStringValue(input));
-  args->Set(1, Value::CreateIntegerValue(suggest_id));
+  args->Set(0, new base::StringValue(input));
+  args->Set(1, new base::FundamentalValue(suggest_id));
 
-  scoped_ptr<Event> event(new Event(events::kOnInputChanged, args.Pass()));
+  scoped_ptr<Event> event(new Event(omnibox::OnInputChanged::kEventName,
+                                    args.Pass()));
   event->restrict_to_profile = profile;
   ExtensionSystem::Get(profile)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
@@ -154,15 +150,16 @@
       active_tab_permission_granter()->GrantIfRequested(extension);
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Set(0, Value::CreateStringValue(input));
+  args->Set(0, new base::StringValue(input));
   if (disposition == NEW_FOREGROUND_TAB)
-    args->Set(1, Value::CreateStringValue(kForegroundTabDisposition));
+    args->Set(1, new base::StringValue(kForegroundTabDisposition));
   else if (disposition == NEW_BACKGROUND_TAB)
-    args->Set(1, Value::CreateStringValue(kBackgroundTabDisposition));
+    args->Set(1, new base::StringValue(kBackgroundTabDisposition));
   else
-    args->Set(1, Value::CreateStringValue(kCurrentTabDisposition));
+    args->Set(1, new base::StringValue(kCurrentTabDisposition));
 
-  scoped_ptr<Event> event(new Event(events::kOnInputEntered, args.Pass()));
+  scoped_ptr<Event> event(new Event(omnibox::OnInputEntered::kEventName,
+                                    args.Pass()));
   event->restrict_to_profile = profile;
   ExtensionSystem::Get(profile)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
@@ -177,7 +174,8 @@
 void ExtensionOmniboxEventRouter::OnInputCancelled(
     Profile* profile, const std::string& extension_id) {
   scoped_ptr<Event> event(new Event(
-      events::kOnInputCancelled, make_scoped_ptr(new base::ListValue())));
+      omnibox::OnInputCancelled::kEventName,
+      make_scoped_ptr(new base::ListValue())));
   event->restrict_to_profile = profile;
   ExtensionSystem::Get(profile)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
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 22e2015..b327840 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers_unittest.cc
@@ -52,13 +52,13 @@
 
   std::string expected_apis[] = { "tabs", "webRequest" };
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected_apis); ++i) {
-    scoped_ptr<Value> value(Value::CreateStringValue(expected_apis[i]));
+    scoped_ptr<Value> value(new base::StringValue(expected_apis[i]));
     EXPECT_NE(api_list->end(), api_list->Find(*value));
   }
 
   std::string expected_origins[] = { "http://a.com/*", "http://b.com/*" };
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected_origins); ++i) {
-    scoped_ptr<Value> value(Value::CreateStringValue(expected_origins[i]));
+    scoped_ptr<Value> value(new base::StringValue(expected_origins[i]));
     EXPECT_NE(origin_list->end(), origin_list->Find(*value));
   }
 
@@ -78,9 +78,9 @@
 // into PermissionSets.
 TEST(ExtensionPermissionsAPIHelpers, Unpack) {
   scoped_ptr<base::ListValue> apis(new base::ListValue());
-  apis->Append(Value::CreateStringValue("tabs"));
+  apis->Append(new base::StringValue("tabs"));
   scoped_ptr<base::ListValue> origins(new base::ListValue());
-  origins->Append(Value::CreateStringValue("http://a.com/*"));
+  origins->Append(new base::StringValue("http://a.com/*"));
 
   scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
   scoped_refptr<PermissionSet> permissions;
@@ -114,7 +114,7 @@
     Permissions permissions_object;
     value->Clear();
     scoped_ptr<base::ListValue> invalid_apis(apis->DeepCopy());
-    invalid_apis->Append(Value::CreateIntegerValue(3));
+    invalid_apis->Append(new base::FundamentalValue(3));
     value->Set("permissions", invalid_apis->DeepCopy());
     EXPECT_FALSE(Permissions::Populate(*value, &permissions_object));
   }
@@ -124,7 +124,7 @@
     Permissions permissions_object;
     value->Clear();
     scoped_ptr<base::ListValue> invalid_origins(origins->DeepCopy());
-    invalid_origins->Append(Value::CreateIntegerValue(3));
+    invalid_origins->Append(new base::FundamentalValue(3));
     value->Set("origins", invalid_origins->DeepCopy());
     EXPECT_FALSE(Permissions::Populate(*value, &permissions_object));
   }
@@ -133,14 +133,14 @@
   {
     Permissions permissions_object;
     value->Clear();
-    value->Set("origins", Value::CreateIntegerValue(2));
+    value->Set("origins", new base::FundamentalValue(2));
     EXPECT_FALSE(Permissions::Populate(*value, &permissions_object));
   }
 
   {
     Permissions permissions_object;
     value->Clear();
-    value->Set("permissions", Value::CreateIntegerValue(2));
+    value->Set("permissions", new base::FundamentalValue(2));
     EXPECT_FALSE(Permissions::Populate(*value, &permissions_object));
   }
 
@@ -149,7 +149,7 @@
     Permissions permissions_object;
     value->Clear();
     value->Set("origins", origins->DeepCopy());
-    value->Set("random", Value::CreateIntegerValue(3));
+    value->Set("random", new base::FundamentalValue(3));
     EXPECT_TRUE(Permissions::Populate(*value, &permissions_object));
     permissions = UnpackPermissionSet(permissions_object, true, &error);
     EXPECT_TRUE(permissions.get());
@@ -162,7 +162,7 @@
     Permissions permissions_object;
     value->Clear();
     scoped_ptr<base::ListValue> invalid_apis(apis->DeepCopy());
-    invalid_apis->Append(Value::CreateStringValue("unknown_permission"));
+    invalid_apis->Append(new base::StringValue("unknown_permission"));
     value->Set("permissions", invalid_apis->DeepCopy());
     EXPECT_TRUE(Permissions::Populate(*value, &permissions_object));
     permissions = UnpackPermissionSet(permissions_object, true, &error);
diff --git a/chrome/browser/extensions/api/power/OWNERS b/chrome/browser/extensions/api/power/OWNERS
new file mode 100644
index 0000000..3c97e54
--- /dev/null
+++ b/chrome/browser/extensions/api/power/OWNERS
@@ -0,0 +1 @@
+derat@chromium.org
diff --git a/chrome/browser/extensions/api/preference/preference_api.cc b/chrome/browser/extensions/api/preference/preference_api.cc
index b792fd4..ca6f938 100644
--- a/chrome/browser/extensions/api/preference/preference_api.cc
+++ b/chrome/browser/extensions/api/preference/preference_api.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/extensions/api/proxy/proxy_api.h"
 #include "chrome/browser/extensions/extension_pref_value_map.h"
 #include "chrome/browser/extensions/extension_pref_value_map_factory.h"
-#include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_prefs_factory.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -139,7 +138,7 @@
     bool bool_value = false;
     bool result = value->GetAsBoolean(&bool_value);
     DCHECK(result);
-    return Value::CreateBooleanValue(!bool_value);
+    return new base::FundamentalValue(!bool_value);
   }
 };
 
@@ -425,7 +424,7 @@
   std::string key = extension_id + "." + scope_string;
 
   const DictionaryValue* source_dict = prefs->pref_service()->
-      GetDictionary(ExtensionPrefs::kExtensionsPref);
+      GetDictionary(prefs::kExtensionsPref);
   const DictionaryValue* preferences = NULL;
   if (!source_dict->GetDictionary(key, &preferences))
     return;
diff --git a/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc b/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
index 8a69ab3..00272c8 100644
--- a/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
+++ b/chrome/browser/extensions/api/preference/preference_api_prefs_unittest.cc
@@ -12,15 +12,12 @@
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_prefs_unittest.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::Value;
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
 namespace {
@@ -182,7 +179,7 @@
   virtual void Initialize() OVERRIDE {
     InstallExtensionControlledPref(extension1(),
                                    kPref1,
-                                   Value::CreateStringValue("val1"));
+                                   new base::StringValue("val1"));
   }
   virtual void Verify() OVERRIDE {
     std::string actual = prefs()->pref_service()->GetString(kPref1);
@@ -198,9 +195,9 @@
  public:
   virtual void Initialize() OVERRIDE {
     InstallExtensionControlledPref(
-        extension1(), kPref1, Value::CreateStringValue("val1"));
+        extension1(), kPref1, new base::StringValue("val1"));
     InstallExtensionControlledPrefIncognito(
-        extension1(), kPref1, Value::CreateStringValue("val2"));
+        extension1(), kPref1, new base::StringValue("val2"));
     scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService());
     std::string actual = incog_prefs->GetString(kPref1);
     EXPECT_EQ("val2", actual);
@@ -227,9 +224,9 @@
 
   virtual void Initialize() OVERRIDE {
     InstallExtensionControlledPref(
-        extension1(), kPref1, Value::CreateStringValue("val1"));
+        extension1(), kPref1, new base::StringValue("val1"));
     InstallExtensionControlledPrefIncognitoSessionOnly(
-        extension1(), kPref1, Value::CreateStringValue("val2"));
+        extension1(), kPref1, new base::StringValue("val2"));
     scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService());
     std::string actual = incog_prefs->GetString(kPref1);
     EXPECT_EQ("val2", actual);
@@ -258,9 +255,9 @@
 class ControlledPrefsUninstallExtension : public ExtensionControlledPrefsTest {
   virtual void Initialize() OVERRIDE {
     InstallExtensionControlledPref(
-        extension1(), kPref1, Value::CreateStringValue("val1"));
+        extension1(), kPref1, new base::StringValue("val1"));
     InstallExtensionControlledPref(
-        extension1(), kPref2, Value::CreateStringValue("val2"));
+        extension1(), kPref2, new base::StringValue("val2"));
     ContentSettingsStore* store = prefs()->content_settings_store();
     ContentSettingsPattern pattern =
         ContentSettingsPattern::FromString("http://[*.]example.com");
@@ -308,7 +305,7 @@
     EXPECT_CALL(observer, OnPreferenceChanged(_));
     EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
     InstallExtensionControlledPref(extension1(), kPref1,
-        Value::CreateStringValue("https://www.chromium.org"));
+        new base::StringValue("https://www.chromium.org"));
     Mock::VerifyAndClearExpectations(&observer);
     Mock::VerifyAndClearExpectations(&incognito_observer);
 
@@ -316,7 +313,7 @@
     EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0);
     EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)).Times(0);
     InstallExtensionControlledPref(extension1(), kPref1,
-        Value::CreateStringValue("https://www.chromium.org"));
+        new base::StringValue("https://www.chromium.org"));
     Mock::VerifyAndClearExpectations(&observer);
     Mock::VerifyAndClearExpectations(&incognito_observer);
 
@@ -324,14 +321,14 @@
     EXPECT_CALL(observer, OnPreferenceChanged(_));
     EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
     InstallExtensionControlledPref(extension1(), kPref1,
-        Value::CreateStringValue("chrome://newtab"));
+        new base::StringValue("chrome://newtab"));
     Mock::VerifyAndClearExpectations(&observer);
     Mock::VerifyAndClearExpectations(&incognito_observer);
     // Change only incognito persistent value.
     EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0);
     EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
     InstallExtensionControlledPrefIncognito(extension1(), kPref1,
-        Value::CreateStringValue("chrome://newtab2"));
+        new base::StringValue("chrome://newtab2"));
     Mock::VerifyAndClearExpectations(&observer);
     Mock::VerifyAndClearExpectations(&incognito_observer);
 
@@ -339,7 +336,7 @@
     EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0);
     EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
     InstallExtensionControlledPrefIncognito(extension1(), kPref1,
-        Value::CreateStringValue("chrome://newtab3"));
+        new base::StringValue("chrome://newtab3"));
     Mock::VerifyAndClearExpectations(&observer);
     Mock::VerifyAndClearExpectations(&incognito_observer);
 
@@ -365,7 +362,7 @@
 class ControlledPrefsDisableExtension : public ExtensionControlledPrefsTest {
   virtual void Initialize() OVERRIDE {
     InstallExtensionControlledPref(
-        extension1(), kPref1, Value::CreateStringValue("val1"));
+        extension1(), kPref1, new base::StringValue("val1"));
     std::string actual = prefs()->pref_service()->GetString(kPref1);
     EXPECT_EQ("val1", actual);
     prefs()->SetExtensionState(extension1()->id(), Extension::DISABLED);
@@ -381,7 +378,7 @@
 class ControlledPrefsReenableExtension : public ExtensionControlledPrefsTest {
   virtual void Initialize() OVERRIDE {
     InstallExtensionControlledPref(
-        extension1(), kPref1, Value::CreateStringValue("val1"));
+        extension1(), kPref1, new base::StringValue("val1"));
     prefs()->SetExtensionState(extension1()->id(), Extension::DISABLED);
     prefs()->SetExtensionState(extension1()->id(), Extension::ENABLED);
   }
@@ -448,7 +445,7 @@
   virtual ~ControlledPrefsDisableExtensions() {}
   virtual void Initialize() OVERRIDE {
     InstallExtensionControlledPref(
-        extension1(), kPref1, Value::CreateStringValue("val1"));
+        extension1(), kPref1, new base::StringValue("val1"));
     // This becomes only active in the second verification phase.
     prefs_.set_extensions_disabled(true);
   }
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc
index e1ab2a4..b29f3c6 100644
--- a/chrome/browser/extensions/api/processes/processes_api.cc
+++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -125,7 +125,7 @@
     if (contents) {
       tab_id = ExtensionTabUtil::GetTabId(contents);
       if (tab_id != -1)
-        tabs_list->Append(Value::CreateIntegerValue(tab_id));
+        tabs_list->Append(new base::FundamentalValue(tab_id));
     }
   }
 
@@ -401,14 +401,14 @@
   scoped_ptr<base::ListValue> args(new base::ListValue());
 
   // First arg: The id of the process that was closed.
-  args->Append(Value::CreateIntegerValue(
+  args->Append(new base::FundamentalValue(
       model_->GetUniqueChildProcessId(start)));
 
   // Second arg: The exit type for the process.
-  args->Append(Value::CreateIntegerValue(0));
+  args->Append(new base::FundamentalValue(0));
 
   // Third arg: The exit code for the process.
-  args->Append(Value::CreateIntegerValue(0));
+  args->Append(new base::FundamentalValue(0));
 
   DispatchEvent(keys::kOnExited, args.Pass());
 #endif  // defined(ENABLE_TASK_MANAGER)
@@ -452,13 +452,13 @@
   scoped_ptr<base::ListValue> args(new base::ListValue());
 
   // First arg: The id of the process that was closed.
-  args->Append(Value::CreateIntegerValue(rph->GetID()));
+  args->Append(new base::FundamentalValue(rph->GetID()));
 
   // Second arg: The exit type for the process.
-  args->Append(Value::CreateIntegerValue(details->status));
+  args->Append(new base::FundamentalValue(details->status));
 
   // Third arg: The exit code for the process.
-  args->Append(Value::CreateIntegerValue(details->exit_code));
+  args->Append(new base::FundamentalValue(details->exit_code));
 
   DispatchEvent(keys::kOnExited, args.Pass());
 #endif  // defined(ENABLE_TASK_MANAGER)
@@ -554,9 +554,9 @@
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &GetProcessIdForTabFunction::GetProcessIdForTab, this));
   } else {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
-                   content::NotificationService::AllSources());
+    TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
+        base::Bind(&GetProcessIdForTabFunction::GetProcessIdForTab, this));
+
     ProcessesAPI::Get(profile_)->processes_event_router()->
         StartTaskManagerListening();
   }
@@ -568,15 +568,6 @@
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
-void GetProcessIdForTabFunction::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
-  registrar_.RemoveAll();
-  GetProcessIdForTab();
-}
-
 void GetProcessIdForTabFunction::GetProcessIdForTab() {
   content::WebContents* contents = NULL;
   int tab_index = -1;
@@ -585,11 +576,11 @@
     error_ = ErrorUtils::FormatErrorMessage(
         extensions::tabs_constants::kTabNotFoundError,
         base::IntToString(tab_id_));
-    SetResult(Value::CreateIntegerValue(-1));
+    SetResult(new base::FundamentalValue(-1));
     SendResponse(false);
   } else {
     int process_id = contents->GetRenderProcessHost()->GetID();
-    SetResult(Value::CreateIntegerValue(process_id));
+    SetResult(new base::FundamentalValue(process_id));
     SendResponse(true);
   }
 
@@ -617,9 +608,9 @@
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &TerminateFunction::TerminateProcess, this));
   } else {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
-                   content::NotificationService::AllSources());
+    TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
+        base::Bind(&TerminateFunction::TerminateProcess, this));
+
     ProcessesAPI::Get(profile_)->processes_event_router()->
         StartTaskManagerListening();
   }
@@ -631,14 +622,6 @@
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
-void TerminateFunction::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
-  registrar_.RemoveAll();
-  TerminateProcess();
-}
 
 void TerminateFunction::TerminateProcess() {
   TaskManagerModel* model = TaskManager::GetInstance()->model();
@@ -664,7 +647,7 @@
         base::IntToString(process_id_));
     SendResponse(false);
   } else {
-    SetResult(Value::CreateBooleanValue(killed));
+    SetResult(new base::FundamentalValue(killed));
     SendResponse(true);
   }
 
@@ -705,9 +688,9 @@
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &GetProcessInfoFunction::GatherProcessInfo, this));
   } else {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
-                   content::NotificationService::AllSources());
+    TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback(
+        base::Bind(&GetProcessInfoFunction::GatherProcessInfo, this));
+
     ProcessesAPI::Get(profile_)->processes_event_router()->
         StartTaskManagerListening();
   }
@@ -719,15 +702,6 @@
 #endif  // defined(ENABLE_TASK_MANAGER)
 }
 
-void GetProcessInfoFunction::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY);
-  registrar_.RemoveAll();
-  GatherProcessInfo();
-}
-
 void GetProcessInfoFunction::GatherProcessInfo() {
 #if defined(ENABLE_TASK_MANAGER)
   TaskManagerModel* model = TaskManager::GetInstance()->model();
diff --git a/chrome/browser/extensions/api/processes/processes_api.h b/chrome/browser/extensions/api/processes/processes_api.h
index 312dd96..b1599af 100644
--- a/chrome/browser/extensions/api/processes/processes_api.h
+++ b/chrome/browser/extensions/api/processes/processes_api.h
@@ -131,8 +131,7 @@
 
 // This extension function returns the Process object for the renderer process
 // currently in use by the specified Tab.
-class GetProcessIdForTabFunction : public AsyncExtensionFunction,
-                                   public content::NotificationObserver {
+class GetProcessIdForTabFunction : public AsyncExtensionFunction {
  public:
   GetProcessIdForTabFunction();
 
@@ -140,20 +139,13 @@
   virtual ~GetProcessIdForTabFunction() {}
   virtual bool RunImpl() OVERRIDE;
 
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
   void GetProcessIdForTab();
 
-  content::NotificationRegistrar registrar_;
-
   // Storage for the tab ID parameter.
   int tab_id_;
 
-  DECLARE_EXTENSION_FUNCTION("experimental.processes.getProcessIdForTab",
-                             EXPERIMENTAL_PROCESSES_GETPROCESSIDFORTAB)
+  DECLARE_EXTENSION_FUNCTION("processes.getProcessIdForTab",
+                             PROCESSES_GETPROCESSIDFORTAB)
 };
 
 // Extension function that allows terminating Chrome subprocesses, by supplying
@@ -161,8 +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,
-                          public content::NotificationObserver {
+class TerminateFunction : public AsyncExtensionFunction {
  public:
   TerminateFunction();
 
@@ -170,26 +161,19 @@
   virtual ~TerminateFunction() {}
   virtual bool RunImpl() OVERRIDE;
 
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
 
   void TerminateProcess();
 
-  content::NotificationRegistrar registrar_;
-
   // Storage for the process ID parameter.
   int process_id_;
 
-  DECLARE_EXTENSION_FUNCTION("experimental.processes.terminate",
-                             EXPERIMENTAL_PROCESSES_TERMINATE)
+  DECLARE_EXTENSION_FUNCTION("processes.terminate",
+                             PROCESSES_TERMINATE)
 };
 
 // Extension function which returns a set of Process objects, containing the
 // details corresponding to the process IDs supplied as input.
-class GetProcessInfoFunction : public AsyncExtensionFunction,
-                               public content::NotificationObserver {
+class GetProcessInfoFunction : public AsyncExtensionFunction {
  public:
   GetProcessInfoFunction();
 
@@ -197,23 +181,16 @@
   virtual ~GetProcessInfoFunction();
   virtual bool RunImpl() OVERRIDE;
 
-  // content::NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
   void GatherProcessInfo();
 
-  content::NotificationRegistrar registrar_;
-
   // Member variables to store the function parameters
   std::vector<int> process_ids_;
 #if defined(ENABLE_TASK_MANAGER)
   bool memory_;
 #endif
 
-  DECLARE_EXTENSION_FUNCTION("experimental.processes.getProcessInfo",
-                             EXPERIMENTAL_PROCESSES_GETPROCESSINFO)
+  DECLARE_EXTENSION_FUNCTION("processes.getProcessInfo",
+                             PROCESSES_GETPROCESSINFO)
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/processes/processes_api_constants.cc b/chrome/browser/extensions/api/processes/processes_api_constants.cc
index 55edf84..4a087e3 100644
--- a/chrome/browser/extensions/api/processes/processes_api_constants.cc
+++ b/chrome/browser/extensions/api/processes/processes_api_constants.cc
@@ -42,12 +42,11 @@
 const char kCacheSize[] = "size";
 
 // Event names.
-const char kOnCreated[] = "experimental.processes.onCreated";
-const char kOnExited[] = "experimental.processes.onExited";
-const char kOnUnresponsive[] = "experimental.processes.onUnresponsive";
-const char kOnUpdated[] = "experimental.processes.onUpdated";
-const char kOnUpdatedWithMemory[] =
-    "experimental.processes.onUpdatedWithMemory";
+const char kOnCreated[] = "processes.onCreated";
+const char kOnExited[] = "processes.onExited";
+const char kOnUnresponsive[] = "processes.onUnresponsive";
+const char kOnUpdated[] = "processes.onUpdated";
+const char kOnUpdatedWithMemory[] = "processes.onUpdatedWithMemory";
 
 // Error strings.
 const char kExtensionNotSupported[] =
diff --git a/chrome/browser/extensions/api/processes/processes_apitest.cc b/chrome/browser/extensions/api/processes/processes_apitest.cc
index 8342c17..f6e1f0a 100644
--- a/chrome/browser/extensions/api/processes/processes_apitest.cc
+++ b/chrome/browser/extensions/api/processes/processes_apitest.cc
@@ -20,9 +20,6 @@
 #else
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Processes) {
 #endif
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      extensions::switches::kEnableExperimentalExtensionApis);
-
   ASSERT_TRUE(RunExtensionTest("processes/api")) << message_;
 }
 
@@ -31,9 +28,6 @@
 #if !(defined(OS_WIN) && defined(USE_AURA)) && !(defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ProcessesVsTaskManager) {
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      extensions::switches::kEnableExperimentalExtensionApis);
-
   // Ensure task manager is not yet updating
   TaskManagerModel* model = TaskManager::GetInstance()->model();
   EXPECT_EQ(0, model->update_requests_);
diff --git a/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc b/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
index f0fc389..1c0d693 100644
--- a/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
@@ -490,7 +490,7 @@
   base::ListValue* out = new base::ListValue;
   base::StringTokenizer entries(in, delims);
   while (entries.GetNext())
-    out->Append(Value::CreateStringValue(entries.token()));
+    out->Append(new base::StringValue(entries.token()));
   return out;
 }
 
diff --git a/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc b/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc
index f830710..7a92fa4 100644
--- a/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_api_helpers_unittest.cc
@@ -204,8 +204,8 @@
   EXPECT_FALSE(bad_message);
 
   base::ListValue* bypass_list = new base::ListValue;
-  bypass_list->Append(Value::CreateStringValue("host1"));
-  bypass_list->Append(Value::CreateStringValue("host2"));
+  bypass_list->Append(new base::StringValue("host1"));
+  bypass_list->Append(new base::StringValue("host2"));
   base::DictionaryValue* proxy_rules = new base::DictionaryValue;
   proxy_rules->Set(keys::kProxyConfigBypassList, bypass_list);
   proxy_config.Set(keys::kProxyConfigRules, proxy_rules);
@@ -323,9 +323,9 @@
 TEST(ExtensionProxyApiHelpers, JoinUrlList) {
   bool bad_message = false;
   base::ListValue list;
-  list.Append(Value::CreateStringValue("s1"));
-  list.Append(Value::CreateStringValue("s2"));
-  list.Append(Value::CreateStringValue("s3"));
+  list.Append(new base::StringValue("s1"));
+  list.Append(new base::StringValue("s2"));
+  list.Append(new base::StringValue("s3"));
 
   std::string out;
   std::string error;
@@ -355,7 +355,7 @@
   expected->Set("fallbackProxy",
                 CreateTestProxyServerDict("socks4", "proxy4", 80));
   base::ListValue* bypass_list = new base::ListValue;
-  bypass_list->Append(Value::CreateStringValue("localhost"));
+  bypass_list->Append(new base::StringValue("localhost"));
   expected->Set(keys::kProxyConfigBypassList, bypass_list);
 
   EXPECT_TRUE(Value::Equals(expected.get(), extension_pref.get()));
@@ -383,7 +383,7 @@
   expected->Set("fallbackProxy",
                 CreateTestProxyServerDict("socks4", "proxy4", 80));
   base::ListValue* bypass_list = new base::ListValue;
-  bypass_list->Append(Value::CreateStringValue("localhost"));
+  bypass_list->Append(new base::StringValue("localhost"));
   expected->Set(keys::kProxyConfigBypassList, bypass_list);
 
   EXPECT_TRUE(Value::Equals(expected.get(), extension_pref.get()));
@@ -421,9 +421,9 @@
 
 TEST(ExtensionProxyApiHelpers, TokenizeToStringList) {
   base::ListValue expected;
-  expected.Append(Value::CreateStringValue("s1"));
-  expected.Append(Value::CreateStringValue("s2"));
-  expected.Append(Value::CreateStringValue("s3"));
+  expected.Append(new base::StringValue("s1"));
+  expected.Append(new base::StringValue("s2"));
+  expected.Append(new base::StringValue("s3"));
 
   scoped_ptr<base::ListValue> out(TokenizeToStringList("s1;s2;s3", ";"));
   EXPECT_TRUE(Value::Equals(&expected, out.get()));
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 adc41ea..d9fdf77 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_api.cc
@@ -13,7 +13,6 @@
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -78,7 +77,7 @@
 
   scoped_ptr<base::ListValue> args(glue::OnMessage::Create(message));
   scoped_ptr<extensions::Event> event(new extensions::Event(
-      event_names::kOnPushMessage, args.Pass()));
+      glue::OnMessage::kEventName, args.Pass()));
   event->restrict_to_profile = profile_;
   ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
       extension_id, event.Pass());
@@ -117,6 +116,8 @@
     }
   }
 
+  DVLOG(2) << "Logged in profile name: " << profile()->GetProfileName();
+
   StartAccessTokenFetch();
   return true;
 }
@@ -134,6 +135,7 @@
     const std::string& account_id) {
   ProfileOAuth2TokenServiceFactory::GetForProfile(profile())
       ->RemoveObserver(this);
+  DVLOG(2) << "Newly logged in: " << profile()->GetProfileName();
   StartAccessTokenFetch();
 }
 
@@ -156,6 +158,8 @@
   // TODO(fgorski): We are currently ignoring the error passed in upon failure.
   // It should be revisited when we are working on improving general error
   // handling for the identity related code.
+  DVLOG(1) << "Cannot obtain access token for this user "
+           << error.error_message() << " " << error.state();
   error_ = kUserAccessTokenFailure;
   ReportResult(std::string(), error_);
 }
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc
index f9208e5..0535a75 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.cc
@@ -134,12 +134,18 @@
       suppressed_ids_.erase(suppressed_id);
       continue;
     }
+    DVLOG(2) << "Incoming push message, id is: "
+             << syncer::ObjectIdToString(it->first)
+             << " and payload is:" << it->second.payload;
 
     std::string extension_id;
     int subchannel;
     if (ObjectIdToExtensionAndSubchannel(it->first,
                                          &extension_id,
                                          &subchannel)) {
+      DVLOG(2) << "Sending push message to reciever, extension is "
+               << extension_id << ", subchannel is " << subchannel
+               << ", and payload is " << it->second.payload;
       delegate_->OnMessage(extension_id, subchannel, it->second.payload);
     }
   }
diff --git a/chrome/browser/extensions/api/recovery_private/recovery_operation_manager.cc b/chrome/browser/extensions/api/recovery_private/recovery_operation_manager.cc
index 3c80583..3bf999e 100644
--- a/chrome/browser/extensions/api/recovery_private/recovery_operation_manager.cc
+++ b/chrome/browser/extensions/api/recovery_private/recovery_operation_manager.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/extensions/api/recovery_private/recovery_operation_manager.h"
 #include "chrome/browser/extensions/api/recovery_private/write_from_file_operation.h"
 #include "chrome/browser/extensions/api/recovery_private/write_from_url_operation.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -17,6 +16,9 @@
 #include "content/public/browser/notification_service.h"
 
 namespace extensions {
+
+namespace recovery_private = extensions::api::recovery_private;
+
 namespace recovery {
 
 namespace {
@@ -112,8 +114,8 @@
   info.percent_complete = progress;
 
   scoped_ptr<base::ListValue> args(recovery_api::OnWriteProgress::Create(info));
-  scoped_ptr<Event> event(new Event(event_names::kRecoveryOnWriteProgress,
-                                    args.Pass()));
+  scoped_ptr<Event> event(new Event(
+      recovery_private::OnWriteProgress::kEventName, args.Pass()));
 
   ExtensionSystem::Get(profile_)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
@@ -122,8 +124,8 @@
 void RecoveryOperationManager::OnComplete(const ExtensionId& extension_id) {
 
   scoped_ptr<base::ListValue> args(recovery_api::OnWriteComplete::Create());
-  scoped_ptr<Event> event(new Event(event_names::kRecoveryOnWriteComplete,
-                                    args.Pass()));
+  scoped_ptr<Event> event(new Event(
+      recovery_private::OnWriteComplete::kEventName, args.Pass()));
 
   ExtensionSystem::Get(profile_)->event_router()->
       DispatchEventToExtension(extension_id, event.Pass());
@@ -140,7 +142,7 @@
   info.percent_complete = progress;
 
   scoped_ptr<base::ListValue> args(recovery_api::OnWriteError::Create(info));
-  scoped_ptr<Event> event(new Event(event_names::kRecoveryOnWriteError,
+  scoped_ptr<Event> event(new Event(recovery_private::OnWriteError::kEventName,
                                     args.Pass()));
 
   ExtensionSystem::Get(profile_)->event_router()->
diff --git a/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc b/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc
index 642a30a..2fe759d 100644
--- a/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc
+++ b/chrome/browser/extensions/api/rtc_private/rtc_private_api.cc
@@ -30,10 +30,10 @@
 
 namespace extensions {
 
+namespace rtc_private = api::rtc_private;
+
 namespace {
 
-// Launch event name.
-const char kOnLaunchEvent[] = "rtcPrivate.onLaunch";
 // Web intent data payload mimetype.
 const char kMimeTypeJson[] = "application/vnd.chromium.contact";
 // Web intent data structure fields.
@@ -67,7 +67,7 @@
   dict->Set(kPhoneIntentField, phone_list);
   for (int i = 0; i < contact.phone_numbers_size(); i++) {
     const Contact_PhoneNumber& phone_number = contact.phone_numbers(i);
-    StringValue* value = Value::CreateStringValue(phone_number.number());
+    StringValue* value = new base::StringValue(phone_number.number());
     if (phone_number.primary())
       CHECK(phone_list->Insert(0, value));
     else
@@ -78,7 +78,7 @@
   dict->Set(kEmailIntentField, email_list);
   for (int i = 0; i < contact.email_addresses_size(); i++) {
     const Contact_EmailAddress& email_address = contact.email_addresses(i);
-    StringValue* value = Value::CreateStringValue(email_address.address());
+    StringValue* value = new base::StringValue(email_address.address());
     if (email_address.primary())
       CHECK(email_list->Insert(0, value));
     else
@@ -92,7 +92,7 @@
     Profile* profile, LaunchAction action, const Contact* contact) {
   if (action == RtcPrivateEventRouter::LAUNCH_ACTIVATE) {
     scoped_ptr<Event> event(new Event(
-        kOnLaunchEvent, make_scoped_ptr(new ListValue())));
+        rtc_private::OnLaunch::kEventName, make_scoped_ptr(new ListValue())));
     event->restrict_to_profile = profile;
     ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
   } else {
@@ -103,7 +103,8 @@
                          &launch_data.intent.data.additional_properties);
     launch_data.intent.type = kMimeTypeJson;
     scoped_ptr<Event> event(new Event(
-        kOnLaunchEvent, api::rtc_private::OnLaunch::Create(launch_data)));
+        rtc_private::OnLaunch::kEventName,
+        api::rtc_private::OnLaunch::Create(launch_data)));
     event->restrict_to_profile = profile;
     ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
   }
diff --git a/chrome/browser/extensions/api/runtime/runtime_api.cc b/chrome/browser/extensions/api/runtime/runtime_api.cc
index 6143f15..5966e8a 100644
--- a/chrome/browser/extensions/api/runtime/runtime_api.cc
+++ b/chrome/browser/extensions/api/runtime/runtime_api.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/extensions/api/runtime.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/omaha_query_params/omaha_query_params.h"
@@ -38,14 +39,10 @@
 
 namespace extensions {
 
+namespace runtime = api::runtime;
+
 namespace {
 
-const char kOnStartupEvent[] = "runtime.onStartup";
-const char kOnInstalledEvent[] = "runtime.onInstalled";
-const char kOnUpdateAvailableEvent[] = "runtime.onUpdateAvailable";
-const char kOnBrowserUpdateAvailableEvent[] =
-    "runtime.onBrowserUpdateAvailable";
-const char kOnRestartRequiredEvent[] = "runtime.onRestartRequired";
 const char kNoBackgroundPageError[] = "You do not have a background page.";
 const char kPageLoadError[] = "Background page failed to load.";
 const char kInstallReason[] = "reason";
@@ -105,7 +102,8 @@
   }
 
   scoped_ptr<base::ListValue> event_args(new base::ListValue());
-  scoped_ptr<Event> event(new Event(kOnStartupEvent, event_args.Pass()));
+  scoped_ptr<Event> event(new Event(runtime::OnStartup::kEventName,
+                                    event_args.Pass()));
   system->event_router()->DispatchEventToExtension(extension_id, event.Pass());
 }
 
@@ -114,7 +112,7 @@
                      const std::string& url_string) {
   prefs->UpdateExtensionPref(extension_id,
                              kUninstallUrl,
-                             base::Value::CreateStringValue(url_string));
+                             new base::StringValue(url_string));
 }
 
 std::string GetUninstallUrl(ExtensionPrefs* prefs,
@@ -154,7 +152,8 @@
     info->SetString(kInstallReason, kInstallReasonInstall);
   }
   DCHECK(system->event_router());
-  scoped_ptr<Event> event(new Event(kOnInstalledEvent, event_args.Pass()));
+  scoped_ptr<Event> event(new Event(runtime::OnInstalled::kEventName,
+                                    event_args.Pass()));
   system->event_router()->DispatchEventWithLazyListener(extension_id,
                                                         event.Pass());
 }
@@ -171,7 +170,8 @@
   scoped_ptr<base::ListValue> args(new base::ListValue);
   args->Append(manifest->DeepCopy());
   DCHECK(system->event_router());
-  scoped_ptr<Event> event(new Event(kOnUpdateAvailableEvent, args.Pass()));
+  scoped_ptr<Event> event(new Event(runtime::OnUpdateAvailable::kEventName,
+                                    args.Pass()));
   system->event_router()->DispatchEventToExtension(extension_id, event.Pass());
 }
 
@@ -184,8 +184,8 @@
 
   scoped_ptr<base::ListValue> args(new base::ListValue);
   DCHECK(system->event_router());
-  scoped_ptr<Event> event(new Event(kOnBrowserUpdateAvailableEvent,
-                                    args.Pass()));
+  scoped_ptr<Event> event(new Event(
+      runtime::OnBrowserUpdateAvailable::kEventName, args.Pass()));
   system->event_router()->BroadcastEvent(event.Pass());
 }
 
@@ -199,7 +199,7 @@
     return;
 
   scoped_ptr<Event> event(
-      new Event(kOnRestartRequiredEvent,
+      new Event(runtime::OnRestartRequired::kEventName,
                 api::runtime::OnRestartRequired::Create(reason)));
 
   DCHECK(system->event_router());
diff --git a/chrome/browser/extensions/api/serial/OWNERS b/chrome/browser/extensions/api/serial/OWNERS
new file mode 100644
index 0000000..452ae4e
--- /dev/null
+++ b/chrome/browser/extensions/api/serial/OWNERS
@@ -0,0 +1,3 @@
+ikarienator@chromium.org
+miket@chromium.org
+rpaquay@chromium.org
diff --git a/chrome/browser/extensions/api/serial/serial_api.cc b/chrome/browser/extensions/api/serial/serial_api.cc
index b0e7925..b958944 100644
--- a/chrome/browser/extensions/api/serial/serial_api.cc
+++ b/chrome/browser/extensions/api/serial/serial_api.cc
@@ -65,7 +65,7 @@
       SerialPortEnumerator::GenerateValidSerialPortNames();
   SerialPortEnumerator::StringSet::const_iterator i = port_names.begin();
   while (i != port_names.end()) {
-    ports->Append(Value::CreateStringValue(*i++));
+    ports->Append(new base::StringValue(*i++));
   }
 
   SetResult(ports);
@@ -182,7 +182,7 @@
     close_result = true;
   }
 
-  SetResult(Value::CreateBooleanValue(close_result));
+  SetResult(new base::FundamentalValue(close_result));
 }
 
 bool SerialCloseFunction::Respond() {
@@ -294,7 +294,7 @@
     flush_result = true;
   }
 
-  SetResult(Value::CreateBooleanValue(flush_result));
+  SetResult(new base::FundamentalValue(flush_result));
 }
 
 bool SerialFlushFunction::Respond() {
@@ -369,14 +369,14 @@
     if (control_signals.should_set_rts)
       control_signals.rts = *(params_->options.rts);
     if (serial_connection->SetControlSignals(control_signals)) {
-      SetResult(Value::CreateBooleanValue(true));
+      SetResult(new base::FundamentalValue(true));
     } else {
       error_ = kErrorSetControlSignalsFailed;
-      SetResult(Value::CreateBooleanValue(false));
+      SetResult(new base::FundamentalValue(false));
     }
   } else {
     error_ = kSerialConnectionNotFoundError;
-    SetResult(Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
   }
 }
 
diff --git a/chrome/browser/extensions/api/session_restore/session_restore_api.cc b/chrome/browser/extensions/api/session_restore/session_restore_api.cc
deleted file mode 100644
index ed0042c..0000000
--- a/chrome/browser/extensions/api/session_restore/session_restore_api.cc
+++ /dev/null
@@ -1,239 +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/api/session_restore/session_restore_api.h"
-
-#include <vector>
-
-#include "base/i18n/rtl.h"
-#include "base/lazy_instance.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_function_registry.h"
-#include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sessions/session_restore.h"
-#include "chrome/browser/sessions/tab_restore_service_delegate.h"
-#include "chrome/browser/sessions/tab_restore_service_factory.h"
-#include "chrome/browser/sync/glue/session_model_associator.h"
-#include "chrome/browser/sync/glue/synced_session.h"
-#include "chrome/browser/sync/profile_sync_service.h"
-#include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/layout.h"
-
-
-namespace {
-
-const unsigned int kMaxRecentlyClosedSessionResults = 25;
-const char kRecentlyClosedListEmpty[] =
-    "There are no recently closed sessions.";
-const char kInvalidSessionId[] = "Invalid session id.";
-const char kNoBrowserToRestoreSession[] =
-    "There are no browser windows to restore the session.";
-
-}  // namespace
-
-namespace extensions {
-
-namespace GetRecentlyClosed = api::session_restore::GetRecentlyClosed;
-namespace Restore = api::session_restore::Restore;
-namespace tabs = api::tabs;
-namespace windows = api::windows;
-namespace session_restore = api::session_restore;
-
-scoped_ptr<tabs::Tab> SessionRestoreGetRecentlyClosedFunction::CreateTabModel(
-    const TabRestoreService::Tab& tab, int selected_index) {
-  scoped_ptr<tabs::Tab> tab_struct(new tabs::Tab);
-  const sessions::SerializedNavigationEntry& current_navigation =
-      tab.navigations[tab.current_navigation_index];
-  GURL gurl = current_navigation.virtual_url();
-  std::string title = UTF16ToUTF8(current_navigation.title());
-
-  tab_struct->url.reset(new std::string(gurl.spec()));
-  tab_struct->title.reset(new std::string(title.empty() ? gurl.spec() : title));
-  tab_struct->index = tab.tabstrip_index;
-  tab_struct->pinned = tab.pinned;
-  tab_struct->id = tab.id;
-  tab_struct->window_id = tab.browser_id;
-  tab_struct->index = tab.tabstrip_index;
-  tab_struct->pinned = tab.pinned;
-  tab_struct->selected = tab.tabstrip_index == selected_index;
-  tab_struct->active = false;
-  tab_struct->highlighted = false;
-  tab_struct->incognito = false;
-  ExtensionTabUtil::ScrubTabForExtension(GetExtension(),
-                                         tab_struct.get());
-  return tab_struct.Pass();
-}
-
-scoped_ptr<windows::Window>
-    SessionRestoreGetRecentlyClosedFunction::CreateWindowModel(
-        const TabRestoreService::Window& window) {
-  scoped_ptr<windows::Window> window_struct(new windows::Window);
-  DCHECK(!window.tabs.empty());
-
-  scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs(
-      new std::vector<linked_ptr<tabs::Tab> >);
-  for (size_t i = 0; i < window.tabs.size(); ++i) {
-    tabs->push_back(make_linked_ptr(CreateTabModel(window.tabs[i],
-        window.selected_tab_index).release()));
-  }
-  window_struct->tabs.reset(tabs.release());
-  window_struct->incognito = false;
-  window_struct->always_on_top = false;
-  window_struct->focused = false;
-  window_struct->type = windows::Window::TYPE_NORMAL;
-  window_struct->state = windows::Window::STATE_NORMAL;
-  return window_struct.Pass();
-}
-
-scoped_ptr<session_restore::ClosedEntry>
-    SessionRestoreGetRecentlyClosedFunction::CreateEntryModel(
-        const TabRestoreService::Entry* entry) {
-  scoped_ptr<session_restore::ClosedEntry> entry_struct(
-      new session_restore::ClosedEntry);
-  switch (entry->type) {
-    case TabRestoreService::TAB:
-      entry_struct->tab.reset(CreateTabModel(
-          *static_cast<const TabRestoreService::Tab*>(entry), -1).release());
-      break;
-    case TabRestoreService::WINDOW:
-      entry_struct->window.reset(CreateWindowModel(
-          *static_cast<const TabRestoreService::Window*>(entry)).release());
-      break;
-    default:
-      NOTREACHED();
-  }
-  entry_struct->timestamp = entry->timestamp.ToTimeT();
-  entry_struct->id = entry->id;
-  return entry_struct.Pass();
-}
-
-bool SessionRestoreGetRecentlyClosedFunction::RunImpl() {
-  scoped_ptr<GetRecentlyClosed::Params> params(
-      GetRecentlyClosed::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-  unsigned int max_results = kMaxRecentlyClosedSessionResults;
-  if (params->options && params->options->max_results)
-    max_results = *params->options->max_results;
-  EXTENSION_FUNCTION_VALIDATE(max_results >= 0 &&
-                              max_results <= kMaxRecentlyClosedSessionResults);
-
-  std::vector<linked_ptr<session_restore::ClosedEntry> > result;
-  TabRestoreService* tab_restore_service =
-      TabRestoreServiceFactory::GetForProfile(profile());
-  DCHECK(tab_restore_service);
-
-  // List of entries. They are ordered from most to least recent.
-  // We prune the list to contain max 25 entries at any time and removes
-  // uninteresting entries.
-  TabRestoreService::Entries entries = tab_restore_service->entries();
-  for (TabRestoreService::Entries::const_iterator it = entries.begin();
-       it != entries.end() && result.size() < max_results; ++it) {
-    TabRestoreService::Entry* entry = *it;
-    if (!params->options || params->options->entry_type ==
-        GetRecentlyClosed::Params::Options::ENTRY_TYPE_NONE) {
-      // Include both tabs and windows if type is not defined.
-      result.push_back(make_linked_ptr(CreateEntryModel(entry).release()));
-    } else if (
-        (params->options->entry_type ==
-            GetRecentlyClosed::Params::Options::ENTRY_TYPE_TAB &&
-                entry->type == TabRestoreService::TAB) ||
-        (params->options->entry_type ==
-            GetRecentlyClosed::Params::Options::ENTRY_TYPE_WINDOW &&
-                entry->type == TabRestoreService::WINDOW)) {
-      result.push_back(make_linked_ptr(CreateEntryModel(entry).release()));
-    }
-  }
-
-  results_ = GetRecentlyClosed::Results::Create(result);
-  return true;
-}
-
-bool SessionRestoreRestoreFunction::RunImpl() {
-  scoped_ptr<Restore::Params> params(Restore::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-
-  Browser* browser =
-      chrome::FindBrowserWithProfile(profile(),
-                                     chrome::HOST_DESKTOP_TYPE_NATIVE);
-  if (!browser) {
-    error_ = kNoBrowserToRestoreSession;
-    return false;
-  }
-
-  TabRestoreService* tab_restore_service =
-      TabRestoreServiceFactory::GetForProfile(profile());
-  TabRestoreServiceDelegate* delegate =
-      TabRestoreServiceDelegate::FindDelegateForWebContents(
-          browser->tab_strip_model()->GetActiveWebContents());
-  DCHECK(delegate);
-  chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
-  TabRestoreService::Entries entries = tab_restore_service->entries();
-
-  if (entries.empty()) {
-    error_ = kRecentlyClosedListEmpty;
-    return false;
-  }
-
-  if (!params->id) {
-    tab_restore_service->RestoreMostRecentEntry(delegate, host_desktop_type);
-    return true;
-  }
-
-  // Check if the recently closed list contains an entry with the provided id.
-  bool is_valid_id = false;
-  for (TabRestoreService::Entries::iterator it = entries.begin();
-       it != entries.end(); ++it) {
-    if ((*it)->id == *params->id) {
-      is_valid_id = true;
-      break;
-    }
-
-    // For Window entries, see if the ID matches a tab. If so, report true for
-    // the window as the Entry.
-    if ((*it)->type == TabRestoreService::WINDOW) {
-      std::vector<TabRestoreService::Tab>& tabs =
-          static_cast<TabRestoreService::Window*>(*it)->tabs;
-      for (std::vector<TabRestoreService::Tab>::iterator tab_it = tabs.begin();
-           tab_it != tabs.end(); ++tab_it) {
-        if ((*tab_it).id == *params->id) {
-          is_valid_id = true;
-          break;
-        }
-      }
-    }
-  }
-
-  if (!is_valid_id) {
-    error_ = kInvalidSessionId;
-    return false;
-  }
-
-  tab_restore_service->RestoreEntryById(delegate, *params->id,
-      host_desktop_type, UNKNOWN);
-  return true;
-}
-
-SessionRestoreAPI::SessionRestoreAPI(Profile* profile) {
-}
-
-SessionRestoreAPI::~SessionRestoreAPI() {
-}
-
-static base::LazyInstance<ProfileKeyedAPIFactory<SessionRestoreAPI> >
-    g_factory = LAZY_INSTANCE_INITIALIZER;
-
-// static
-ProfileKeyedAPIFactory<SessionRestoreAPI>*
-    SessionRestoreAPI::GetFactoryInstance() {
-  return &g_factory.Get();
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/api/session_restore/session_restore_api.h b/chrome/browser/extensions/api/session_restore/session_restore_api.h
deleted file mode 100644
index 37ab15e..0000000
--- a/chrome/browser/extensions/api/session_restore/session_restore_api.h
+++ /dev/null
@@ -1,61 +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_API_SESSION_RESTORE_SESSION_RESTORE_API_H__
-#define CHROME_BROWSER_EXTENSIONS_API_SESSION_RESTORE_SESSION_RESTORE_API_H__
-
-#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
-#include "chrome/browser/extensions/extension_function.h"
-#include "chrome/browser/sessions/tab_restore_service.h"
-#include "chrome/common/extensions/api/session_restore.h"
-#include "chrome/common/extensions/api/tabs.h"
-#include "chrome/common/extensions/api/windows.h"
-
-class Profile;
-
-namespace extensions {
-
-class SessionRestoreGetRecentlyClosedFunction : public SyncExtensionFunction {
- protected:
-  virtual ~SessionRestoreGetRecentlyClosedFunction() {}
-  virtual bool RunImpl() OVERRIDE;
-  DECLARE_EXTENSION_FUNCTION("sessionRestore.getRecentlyClosed",
-      SESSIONRESTORE_GETRECENTLYCLOSED)
-
- private:
-  scoped_ptr<api::tabs::Tab> CreateTabModel(
-      const TabRestoreService::Tab& tab, int selected_index);
-  scoped_ptr<api::windows::Window> CreateWindowModel(
-      const TabRestoreService::Window& window);
-  scoped_ptr<api::session_restore::ClosedEntry> CreateEntryModel(
-      const TabRestoreService::Entry* entry);
-};
-
-class SessionRestoreRestoreFunction : public SyncExtensionFunction {
- protected:
-  virtual ~SessionRestoreRestoreFunction() {}
-  virtual bool RunImpl() OVERRIDE;
-  DECLARE_EXTENSION_FUNCTION("sessionRestore.restore", SESSIONRESTORE_RESTORE)
-};
-
-class SessionRestoreAPI : public ProfileKeyedAPI {
- public:
-  explicit SessionRestoreAPI(Profile* profile);
-  virtual ~SessionRestoreAPI();
-
-  // ProfileKeyedAPI implementation.
-  static ProfileKeyedAPIFactory<SessionRestoreAPI>* GetFactoryInstance();
- private:
-  friend class ProfileKeyedAPIFactory<SessionRestoreAPI>;
-
-  // ProfileKeyedAPI implementation.
-  static const char* service_name() {
-    return "SessionRestoreAPI";
-  }
-  static const bool kServiceIsNULLWhileTesting = true;
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_SESSION_RESTORE_SESSION_RESTORE_API_H__
diff --git a/chrome/browser/extensions/api/session_restore/session_restore_apitest.cc b/chrome/browser/extensions/api/session_restore/session_restore_apitest.cc
deleted file mode 100644
index 0836d84..0000000
--- a/chrome/browser/extensions/api/session_restore/session_restore_apitest.cc
+++ /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.
-
-#include "base/command_line.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/test/base/test_switches.h"
-
-// Flaky on ChromeOS, times out on OSX Debug http://crbug.com/251199
-#if defined(OS_CHROMEOS) || (defined(OS_MACOSX) && !defined(NDEBUG))
-#define MAYBE_SessionRestoreApis DISABLED_SessionRestoreApis
-#else
-#define MAYBE_SessionRestoreApis SessionRestoreApis
-#endif
-IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_SessionRestoreApis) {
-#if defined(OS_WIN) && defined(USE_ASH)
-  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
-    return;
-#endif
-
-  ASSERT_TRUE(RunExtensionSubtest("session_restore",
-                                  "session_restore.html")) << message_;
-}
diff --git a/chrome/browser/extensions/api/sessions/OWNERS b/chrome/browser/extensions/api/sessions/OWNERS
new file mode 100644
index 0000000..d3c3af2
--- /dev/null
+++ b/chrome/browser/extensions/api/sessions/OWNERS
@@ -0,0 +1 @@
+kalman@chromium.org
diff --git a/chrome/browser/extensions/api/sessions/session_id.cc b/chrome/browser/extensions/api/sessions/session_id.cc
new file mode 100644
index 0000000..cc0f155
--- /dev/null
+++ b/chrome/browser/extensions/api/sessions/session_id.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/api/sessions/session_id.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+
+namespace extensions {
+
+const char kIdSeparator = '.';
+
+// static
+scoped_ptr<SessionId> SessionId::Parse(const std::string& session_id) {
+  std::string session_tag;
+
+  // Populate session_tag if the |session_id| represents a foreign SessionId.
+  std::size_t separator = session_id.find(kIdSeparator);
+  if (separator != std::string::npos) {
+    session_tag = session_id.substr(0, separator);
+  }
+
+  // session_tag will be the empty string for local sessions that have only
+  // a unique integer as the identifier.
+  int id;
+  if (!base::StringToInt(
+      session_tag.empty() ? session_id : session_id.substr(separator + 1),
+      &id)) {
+    return scoped_ptr<SessionId>();
+  }
+  return make_scoped_ptr(new SessionId(session_tag, id));
+}
+
+SessionId::SessionId(const std::string& session_tag, int id)
+    : session_tag_(session_tag), id_(id) {
+}
+
+bool SessionId::IsForeign() const {
+  return !session_tag_.empty();
+}
+
+std::string SessionId::ToString() const {
+  return IsForeign() ?
+      (session_tag_ + kIdSeparator + base::StringPrintf("%d", id_))
+      : base::StringPrintf("%d", id_);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/sessions/session_id.h b/chrome/browser/extensions/api/sessions/session_id.h
new file mode 100644
index 0000000..6cdcb5f
--- /dev/null
+++ b/chrome/browser/extensions/api/sessions/session_id.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 CHROME_BROWSER_EXTENSIONS_API_SESSIONS_SESSION_ID_H__
+#define CHROME_BROWSER_EXTENSIONS_API_SESSIONS_SESSION_ID_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace extensions {
+
+class SessionId {
+ public:
+  // Returns a SessionId, representing either a local or a foreign session.
+  // In the case that the session is local, |session_tag_| will be empty string.
+  // |session_string| should be in the format that ToString() would produce.
+  static scoped_ptr<SessionId> Parse(const std::string& session_string);
+
+  // Constructs a SessionId object for the given session information.
+  // |session_tag| is the string used to uniquely identify a synced foreign
+  // session from the SessionModelAssociator. In the case that SessionId
+  // represents a local session, |session_tag_| will be the empty string. |id|
+  // uniquely identifies either a window or tab object in the local or the
+  // |session_tag| session.
+  SessionId(const std::string& session_tag, int id);
+
+  // Returns true if the SessionId represents a foreign session.
+  bool IsForeign() const;
+
+  // Returns the compressed std::string representation of a SessionId in the
+  // same format that Parse() accepts as its |session_string| parameter.
+  std::string ToString() const;
+
+  const std::string& session_tag() const { return session_tag_; }
+  int id() const { return id_; }
+
+ private:
+  // The unique identifier for a foreign session, given by the
+  // SessionModelAssociator.
+  std::string session_tag_;
+
+  // ID corresponding to a window or tab object.
+  int id_;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionId);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_SESSIONS_SESSION_ID_H__
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.cc b/chrome/browser/extensions/api/sessions/sessions_api.cc
new file mode 100644
index 0000000..7115dcb
--- /dev/null
+++ b/chrome/browser/extensions/api/sessions/sessions_api.cc
@@ -0,0 +1,593 @@
+// Copyright 2013 The Chromium Authors. 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/sessions/sessions_api.h"
+
+#include <vector>
+
+#include "base/i18n/rtl.h"
+#include "base/lazy_instance.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "chrome/browser/extensions/api/sessions/session_id.h"
+#include "chrome/browser/extensions/api/tabs/windows_util.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "chrome/browser/extensions/extension_function_registry.h"
+#include "chrome/browser/extensions/extension_tab_util.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/search/search.h"
+#include "chrome/browser/sessions/session_restore.h"
+#include "chrome/browser/sessions/tab_restore_service_delegate.h"
+#include "chrome/browser/sessions/tab_restore_service_factory.h"
+#include "chrome/browser/sync/glue/session_model_associator.h"
+#include "chrome/browser/sync/glue/synced_session.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/error_utils.h"
+#include "net/base/net_util.h"
+#include "ui/base/layout.h"
+
+namespace extensions {
+
+namespace GetRecentlyClosed = api::sessions::GetRecentlyClosed;
+namespace GetDevices = api::sessions::GetDevices;
+namespace Restore = api::sessions::Restore;
+namespace tabs = api::tabs;
+namespace windows = api::windows;
+
+const char kNoRecentlyClosedSessionsError[] =
+    "There are no recently closed sessions.";
+const char kInvalidSessionIdError[] = "Invalid session id: \"*\".";
+const char kNoBrowserToRestoreSession[] =
+    "There are no browser windows to restore the session.";
+const char kSessionSyncError[] = "Synced sessions are not available.";
+
+// Comparator function for use with std::sort that will sort sessions by
+// descending modified_time (i.e., most recent first).
+bool SortSessionsByRecency(const browser_sync::SyncedSession* s1,
+                           const browser_sync::SyncedSession* s2) {
+  return s1->modified_time > s2->modified_time;
+}
+
+// Comparator function for use with std::sort that will sort tabs in a window
+// by descending timestamp (i.e., most recent first).
+bool SortTabsByRecency(const SessionTab* t1, const SessionTab* t2) {
+  return t1->timestamp > t2->timestamp;
+}
+
+scoped_ptr<tabs::Tab> CreateTabModelHelper(
+    Profile* profile,
+    const sessions::SerializedNavigationEntry& current_navigation,
+    const std::string& session_id,
+    int index,
+    bool pinned,
+    int selected_index,
+    const Extension* extension) {
+  scoped_ptr<tabs::Tab> tab_struct(new tabs::Tab);
+
+  GURL gurl = current_navigation.virtual_url();
+  std::string title = UTF16ToUTF8(current_navigation.title());
+
+  tab_struct->session_id.reset(new std::string(session_id));
+  tab_struct->url.reset(new std::string(gurl.spec()));
+  if (!title.empty()) {
+    tab_struct->title.reset(new std::string(title));
+  } else {
+    const std::string languages =
+        profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
+    tab_struct->title.reset(new std::string(UTF16ToUTF8(
+        net::FormatUrl(gurl, languages))));
+  }
+  tab_struct->index = index;
+  tab_struct->pinned = pinned;
+  tab_struct->selected = index == selected_index;
+  tab_struct->active = false;
+  tab_struct->highlighted = false;
+  tab_struct->incognito = false;
+  ExtensionTabUtil::ScrubTabForExtension(extension, tab_struct.get());
+  return tab_struct.Pass();
+}
+
+scoped_ptr<windows::Window> CreateWindowModelHelper(
+    scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs,
+    const std::string& session_id,
+    const windows::Window::Type& type,
+    const windows::Window::State& state) {
+  scoped_ptr<windows::Window> window_struct(new windows::Window);
+  window_struct->tabs = tabs.Pass();
+  window_struct->session_id.reset(new std::string(session_id));
+  window_struct->incognito = false;
+  window_struct->always_on_top = false;
+  window_struct->focused = false;
+  window_struct->type = type;
+  window_struct->state = state;
+  return window_struct.Pass();
+}
+
+scoped_ptr<api::sessions::Session> CreateSessionModelHelper(
+    int last_modified,
+    scoped_ptr<tabs::Tab> tab,
+    scoped_ptr<windows::Window> window) {
+  scoped_ptr<api::sessions::Session> session_struct(new api::sessions::Session);
+  session_struct->last_modified = last_modified;
+  if (tab)
+    session_struct->tab = tab.Pass();
+  else if (window)
+    session_struct->window = window.Pass();
+  else
+    NOTREACHED();
+  return session_struct.Pass();
+}
+
+bool is_tab_entry(const TabRestoreService::Entry* entry) {
+  return entry->type == TabRestoreService::TAB;
+}
+
+bool is_window_entry(const TabRestoreService::Entry* entry) {
+  return entry->type == TabRestoreService::WINDOW;
+}
+
+scoped_ptr<tabs::Tab> SessionsGetRecentlyClosedFunction::CreateTabModel(
+    const TabRestoreService::Tab& tab, int session_id, int selected_index) {
+  return CreateTabModelHelper(profile(),
+                              tab.navigations[tab.current_navigation_index],
+                              base::IntToString(session_id),
+                              tab.tabstrip_index,
+                              tab.pinned,
+                              selected_index,
+                              GetExtension());
+}
+
+scoped_ptr<windows::Window>
+    SessionsGetRecentlyClosedFunction::CreateWindowModel(
+        const TabRestoreService::Window& window,
+        int session_id) {
+  DCHECK(!window.tabs.empty());
+
+  scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs(
+      new std::vector<linked_ptr<tabs::Tab> >);
+  for (size_t i = 0; i < window.tabs.size(); ++i) {
+    tabs->push_back(make_linked_ptr(
+        CreateTabModel(window.tabs[i], window.tabs[i].id,
+                       window.selected_tab_index).release()));
+  }
+
+  return CreateWindowModelHelper(tabs.Pass(),
+                                 base::IntToString(session_id),
+                                 windows::Window::TYPE_NORMAL,
+                                 windows::Window::STATE_NORMAL);
+}
+
+scoped_ptr<api::sessions::Session>
+    SessionsGetRecentlyClosedFunction::CreateSessionModel(
+        const TabRestoreService::Entry* entry) {
+  scoped_ptr<tabs::Tab> tab;
+  scoped_ptr<windows::Window> window;
+  switch (entry->type) {
+    case TabRestoreService::TAB:
+      tab = CreateTabModel(
+          *static_cast<const TabRestoreService::Tab*>(entry), entry->id, -1);
+      break;
+    case TabRestoreService::WINDOW:
+      window = CreateWindowModel(
+        *static_cast<const TabRestoreService::Window*>(entry), entry->id);
+      break;
+    default:
+      NOTREACHED();
+  }
+  return CreateSessionModelHelper(entry->timestamp.ToTimeT(),
+                                  tab.Pass(),
+                                  window.Pass());
+}
+
+bool SessionsGetRecentlyClosedFunction::RunImpl() {
+  scoped_ptr<GetRecentlyClosed::Params> params(
+      GetRecentlyClosed::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+  int max_results = api::sessions::MAX_SESSION_RESULTS;
+  if (params->filter && params->filter->max_results)
+    max_results = *params->filter->max_results;
+  EXTENSION_FUNCTION_VALIDATE(max_results >= 0 &&
+      max_results <= api::sessions::MAX_SESSION_RESULTS);
+
+  std::vector<linked_ptr<api::sessions::Session> > result;
+  TabRestoreService* tab_restore_service =
+      TabRestoreServiceFactory::GetForProfile(profile());
+  DCHECK(tab_restore_service);
+
+  // List of entries. They are ordered from most to least recent.
+  // We prune the list to contain max 25 entries at any time and removes
+  // uninteresting entries.
+  TabRestoreService::Entries entries = tab_restore_service->entries();
+  for (TabRestoreService::Entries::const_iterator it = entries.begin();
+       it != entries.end() && static_cast<int>(result.size()) < max_results;
+       ++it) {
+    TabRestoreService::Entry* entry = *it;
+    result.push_back(make_linked_ptr(CreateSessionModel(entry).release()));
+  }
+
+  results_ = GetRecentlyClosed::Results::Create(result);
+  return true;
+}
+
+scoped_ptr<tabs::Tab> SessionsGetDevicesFunction::CreateTabModel(
+    const std::string& session_tag,
+    const SessionTab& tab,
+    int tab_index,
+    int selected_index) {
+  std::string session_id = SessionId(session_tag, tab.tab_id.id()).ToString();
+  return CreateTabModelHelper(profile(),
+                              tab.navigations[tab.current_navigation_index],
+                              session_id,
+                              tab_index,
+                              tab.pinned,
+                              selected_index,
+                              GetExtension());
+}
+
+scoped_ptr<windows::Window> SessionsGetDevicesFunction::CreateWindowModel(
+        const SessionWindow& window, const std::string& session_tag) {
+  DCHECK(!window.tabs.empty());
+
+  // Prune tabs that are not syncable or are NewTabPage. Then, sort the tabs
+  // from most recent to least recent.
+  std::vector<const SessionTab*> tabs_in_window;
+  for (size_t i = 0; i < window.tabs.size(); ++i) {
+    const SessionTab* tab = window.tabs[i];
+    if (tab->navigations.empty())
+      continue;
+    const sessions::SerializedNavigationEntry& current_navigation =
+        tab->navigations.at(tab->normalized_navigation_index());
+    if (chrome::IsNTPURL(current_navigation.virtual_url(), profile())) {
+      continue;
+    }
+    tabs_in_window.push_back(tab);
+  }
+  if (tabs_in_window.empty())
+    return scoped_ptr<windows::Window>();
+  std::sort(tabs_in_window.begin(), tabs_in_window.end(), SortTabsByRecency);
+
+  scoped_ptr<std::vector<linked_ptr<tabs::Tab> > > tabs(
+      new std::vector<linked_ptr<tabs::Tab> >);
+  for (size_t i = 0; i < window.tabs.size(); ++i) {
+    tabs->push_back(make_linked_ptr(
+        CreateTabModel(session_tag, *window.tabs[i], i,
+                       window.selected_tab_index).release()));
+  }
+
+  std::string session_id =
+      SessionId(session_tag, window.window_id.id()).ToString();
+
+  windows::Window::Type type = windows::Window::TYPE_NONE;
+  switch (window.type) {
+    case Browser::TYPE_TABBED:
+      type = windows::Window::TYPE_NORMAL;
+      break;
+    case Browser::TYPE_POPUP:
+      type = windows::Window::TYPE_POPUP;
+      break;
+  }
+
+  windows::Window::State state = windows::Window::STATE_NONE;
+  switch (window.show_state) {
+    case ui::SHOW_STATE_NORMAL:
+      state = windows::Window::STATE_NORMAL;
+      break;
+    case ui::SHOW_STATE_MINIMIZED:
+      state = windows::Window::STATE_MINIMIZED;
+      break;
+    case ui::SHOW_STATE_MAXIMIZED:
+      state = windows::Window::STATE_MAXIMIZED;
+      break;
+    case ui::SHOW_STATE_FULLSCREEN:
+      state = windows::Window::STATE_FULLSCREEN;
+      break;
+    case ui::SHOW_STATE_DEFAULT:
+    case ui::SHOW_STATE_INACTIVE:
+    case ui::SHOW_STATE_DETACHED:
+    case ui::SHOW_STATE_END:
+      break;
+  }
+
+  scoped_ptr<windows::Window> window_struct(
+      CreateWindowModelHelper(tabs.Pass(), session_id, type, state));
+  // TODO(dwankri): Dig deeper to resolve bounds not being optional, so closed
+  // windows in GetRecentlyClosed can have set values in Window helper.
+  window_struct->left.reset(new int(window.bounds.x()));
+  window_struct->top.reset(new int(window.bounds.y()));
+  window_struct->width.reset(new int(window.bounds.width()));
+  window_struct->height.reset(new int(window.bounds.height()));
+
+  return window_struct.Pass();
+}
+
+scoped_ptr<api::sessions::Session>
+SessionsGetDevicesFunction::CreateSessionModel(
+    const SessionWindow& window, const std::string& session_tag) {
+  scoped_ptr<windows::Window> window_model(
+      CreateWindowModel(window, session_tag));
+  // There is a chance that after pruning uninteresting tabs the window will be
+  // empty.
+  return !window_model ? scoped_ptr<api::sessions::Session>()
+      : CreateSessionModelHelper(window.timestamp.ToTimeT(),
+                                 scoped_ptr<tabs::Tab>(),
+                                 window_model.Pass());
+}
+
+scoped_ptr<api::sessions::Device> SessionsGetDevicesFunction::CreateDeviceModel(
+    const browser_sync::SyncedSession* session) {
+  int max_results = api::sessions::MAX_SESSION_RESULTS;
+  // Already validated in RunImpl().
+  scoped_ptr<GetDevices::Params> params(GetDevices::Params::Create(*args_));
+  if (params->filter && params->filter->max_results)
+    max_results = *params->filter->max_results;
+
+  scoped_ptr<api::sessions::Device> device_struct(new api::sessions::Device);
+  device_struct->info = session->session_name;
+
+  for (browser_sync::SyncedSession::SyncedWindowMap::const_iterator it =
+       session->windows.begin(); it != session->windows.end() &&
+       static_cast<int>(device_struct->sessions.size()) < max_results; ++it) {
+    scoped_ptr<api::sessions::Session> session_model(CreateSessionModel(
+        *it->second, session->session_tag));
+    if (session_model)
+      device_struct->sessions.push_back(make_linked_ptr(
+          session_model.release()));
+  }
+  return device_struct.Pass();
+}
+
+bool SessionsGetDevicesFunction::RunImpl() {
+  ProfileSyncService* service =
+      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile());
+  if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
+    // Sync not enabled.
+    results_ = GetDevices::Results::Create(
+        std::vector<linked_ptr<api::sessions::Device> >());
+    return true;
+  }
+
+  browser_sync::SessionModelAssociator* associator =
+      service->GetSessionModelAssociator();
+  std::vector<const browser_sync::SyncedSession*> sessions;
+  if (!(associator && associator->GetAllForeignSessions(&sessions))) {
+    results_ = GetDevices::Results::Create(
+        std::vector<linked_ptr<api::sessions::Device> >());
+    return true;
+  }
+
+  scoped_ptr<GetDevices::Params> params(GetDevices::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+  if (params->filter && params->filter->max_results) {
+    EXTENSION_FUNCTION_VALIDATE(*params->filter->max_results >= 0 &&
+        *params->filter->max_results <= api::sessions::MAX_SESSION_RESULTS);
+  }
+
+  std::vector<linked_ptr<api::sessions::Device> > result;
+  // Sort sessions from most recent to least recent.
+  std::sort(sessions.begin(), sessions.end(), SortSessionsByRecency);
+  for (size_t i = 0; i < sessions.size(); ++i) {
+    result.push_back(make_linked_ptr(CreateDeviceModel(sessions[i]).release()));
+  }
+
+  results_ = GetDevices::Results::Create(result);
+  return true;
+}
+
+void SessionsRestoreFunction::SetInvalidIdError(const std::string& invalid_id) {
+  SetError(ErrorUtils::FormatErrorMessage(kInvalidSessionIdError, invalid_id));
+}
+
+
+void SessionsRestoreFunction::SetResultRestoredTab(
+    const content::WebContents* contents) {
+  scoped_ptr<tabs::Tab> tab(tabs::Tab::FromValue(
+      *ExtensionTabUtil::CreateTabValue(contents, GetExtension())));
+  scoped_ptr<api::sessions::Session> restored_session(CreateSessionModelHelper(
+      base::Time::Now().ToTimeT(),
+      tab.Pass(),
+      scoped_ptr<windows::Window>()));
+  results_ = Restore::Results::Create(*restored_session);
+}
+
+bool SessionsRestoreFunction::SetResultRestoredWindow(int window_id) {
+    WindowController* controller = NULL;
+  if (!windows_util::GetWindowFromWindowID(this, window_id, &controller)) {
+    // error_ is set by GetWindowFromWindowId function call.
+    return false;
+  }
+  scoped_ptr<windows::Window> window(windows::Window::FromValue(
+      *controller->CreateWindowValueWithTabs(GetExtension())));
+  results_ = Restore::Results::Create(*CreateSessionModelHelper(
+      base::Time::Now().ToTimeT(),
+      scoped_ptr<tabs::Tab>(),
+      window.Pass()));
+  return true;
+}
+
+bool SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) {
+  TabRestoreService* tab_restore_service =
+      TabRestoreServiceFactory::GetForProfile(profile());
+  chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
+  TabRestoreService::Entries entries = tab_restore_service->entries();
+
+  if (entries.empty()) {
+    SetError(kNoRecentlyClosedSessionsError);
+    return false;
+  }
+
+  bool is_window = is_window_entry(entries.front());
+  TabRestoreServiceDelegate* delegate =
+      TabRestoreServiceDelegate::FindDelegateForWebContents(
+          browser->tab_strip_model()->GetActiveWebContents());
+  std::vector<content::WebContents*> contents =
+      tab_restore_service->RestoreMostRecentEntry(delegate, host_desktop_type);
+  DCHECK(contents.size());
+
+  if (is_window) {
+    return SetResultRestoredWindow(
+        ExtensionTabUtil::GetWindowIdOfTab(contents[0]));
+  }
+
+  SetResultRestoredTab(contents[0]);
+  return true;
+}
+
+bool SessionsRestoreFunction::RestoreLocalSession(const SessionId& session_id,
+                                                  Browser* browser) {
+  TabRestoreService* tab_restore_service =
+      TabRestoreServiceFactory::GetForProfile(profile());
+  chrome::HostDesktopType host_desktop_type = browser->host_desktop_type();
+  TabRestoreService::Entries entries = tab_restore_service->entries();
+
+  if (entries.empty()) {
+    SetInvalidIdError(session_id.ToString());
+    return false;
+  }
+
+  // Check if the recently closed list contains an entry with the provided id.
+  bool is_window = false;
+  for (TabRestoreService::Entries::iterator it = entries.begin();
+       it != entries.end(); ++it) {
+    if ((*it)->id == session_id.id()) {
+      // The only time a full window is being restored is if the entry ID
+      // matches the provided ID and the entry type is Window.
+      is_window = is_window_entry(*it);
+      break;
+    }
+  }
+
+  TabRestoreServiceDelegate* delegate =
+      TabRestoreServiceDelegate::FindDelegateForWebContents(
+          browser->tab_strip_model()->GetActiveWebContents());
+  std::vector<content::WebContents*> contents =
+      tab_restore_service->RestoreEntryById(delegate,
+                                            session_id.id(),
+                                            host_desktop_type,
+                                            UNKNOWN);
+  // If the ID is invalid, contents will be empty.
+  if (!contents.size()) {
+    SetInvalidIdError(session_id.ToString());
+    return false;
+  }
+
+  // Retrieve the window through any of the tabs in contents.
+  if (is_window) {
+    return SetResultRestoredWindow(
+        ExtensionTabUtil::GetWindowIdOfTab(contents[0]));
+  }
+
+  SetResultRestoredTab(contents[0]);
+  return true;
+}
+
+bool SessionsRestoreFunction::RestoreForeignSession(const SessionId& session_id,
+                                                    Browser* browser) {
+  ProfileSyncService* service =
+      ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile());
+  if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) {
+    SetError(kSessionSyncError);
+    return false;
+  }
+  browser_sync::SessionModelAssociator* associator =
+      service->GetSessionModelAssociator();
+  if (!associator) {
+    SetError(kSessionSyncError);
+    return false;
+  }
+
+  const SessionTab* tab = NULL;
+  if (associator->GetForeignTab(session_id.session_tag(),
+                                session_id.id(),
+                                &tab)) {
+    TabStripModel* tab_strip = browser->tab_strip_model();
+    content::WebContents* contents = tab_strip->GetActiveWebContents();
+
+    content::WebContents* tab_contents =
+        SessionRestore::RestoreForeignSessionTab(contents, *tab,
+                                                 NEW_FOREGROUND_TAB);
+    SetResultRestoredTab(tab_contents);
+    return true;
+  }
+
+  // Restoring a full window.
+  std::vector<const SessionWindow*> windows;
+  if (!associator->GetForeignSession(session_id.session_tag(), &windows)) {
+    SetInvalidIdError(session_id.ToString());
+    return false;
+  }
+
+  std::vector<const SessionWindow*>::const_iterator window = windows.begin();
+  while (window != windows.end()
+         && (*window)->window_id.id() != session_id.id()) {
+    ++window;
+  }
+  if (window == windows.end()) {
+    SetInvalidIdError(session_id.ToString());
+    return false;
+  }
+
+  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);
+  // Will always create one browser because we only restore one window per call.
+  DCHECK_EQ(1u, browsers.size());
+  return SetResultRestoredWindow(ExtensionTabUtil::GetWindowId(browsers[0]));
+}
+
+bool SessionsRestoreFunction::RunImpl() {
+  scoped_ptr<Restore::Params> params(Restore::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  Browser* browser =
+      chrome::FindBrowserWithProfile(profile(),
+                                     chrome::HOST_DESKTOP_TYPE_NATIVE);
+  if (!browser) {
+    SetError(kNoBrowserToRestoreSession);
+    return false;
+  }
+
+  if (!params->session_id)
+    return RestoreMostRecentlyClosed(browser);
+
+  scoped_ptr<SessionId> session_id(SessionId::Parse(*params->session_id));
+  if (!session_id) {
+    SetInvalidIdError(*params->session_id);
+    return false;
+  }
+
+  return session_id->IsForeign() ?
+      RestoreForeignSession(*session_id, browser)
+      : RestoreLocalSession(*session_id, browser);
+}
+
+SessionsAPI::SessionsAPI(Profile* profile) {
+}
+
+SessionsAPI::~SessionsAPI() {
+}
+
+static base::LazyInstance<ProfileKeyedAPIFactory<SessionsAPI> >
+    g_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+ProfileKeyedAPIFactory<SessionsAPI>*
+    SessionsAPI::GetFactoryInstance() {
+  return &g_factory.Get();
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/sessions/sessions_api.h b/chrome/browser/extensions/api/sessions/sessions_api.h
new file mode 100644
index 0000000..0498b69
--- /dev/null
+++ b/chrome/browser/extensions/api/sessions/sessions_api.h
@@ -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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_SESSIONS_SESSIONS_API_H__
+#define CHROME_BROWSER_EXTENSIONS_API_SESSIONS_SESSIONS_API_H__
+
+#include <string>
+
+#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
+#include "chrome/browser/extensions/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"
+#include "chrome/common/extensions/api/tabs.h"
+#include "chrome/common/extensions/api/windows.h"
+
+class Profile;
+
+namespace browser_sync {
+struct SyncedSession;
+}
+
+namespace extensions {
+
+class SessionId;
+
+class SessionsGetRecentlyClosedFunction : public SyncExtensionFunction {
+ protected:
+  virtual ~SessionsGetRecentlyClosedFunction() {}
+  virtual bool RunImpl() OVERRIDE;
+  DECLARE_EXTENSION_FUNCTION("sessions.getRecentlyClosed",
+                             SESSIONS_GETRECENTLYCLOSED)
+
+ private:
+  scoped_ptr<api::tabs::Tab> CreateTabModel(const TabRestoreService::Tab& tab,
+                                            int session_id,
+                                            int selected_index);
+  scoped_ptr<api::windows::Window> CreateWindowModel(
+      const TabRestoreService::Window& window,
+      int session_id);
+  scoped_ptr<api::sessions::Session> CreateSessionModel(
+      const TabRestoreService::Entry* entry);
+};
+
+class SessionsGetDevicesFunction : public SyncExtensionFunction {
+ protected:
+  virtual ~SessionsGetDevicesFunction() {}
+  virtual bool RunImpl() OVERRIDE;
+  DECLARE_EXTENSION_FUNCTION("sessions.getDevices", SESSIONS_GETDEVICES)
+
+ private:
+  scoped_ptr<api::tabs::Tab> CreateTabModel(const std::string& session_tag,
+                                            const SessionTab& tab,
+                                            int tab_index,
+                                            int selected_index);
+  scoped_ptr<api::windows::Window> CreateWindowModel(
+      const SessionWindow& window,
+      const std::string& session_tag);
+  scoped_ptr<api::sessions::Session> CreateSessionModel(
+      const SessionWindow& window,
+      const std::string& session_tag);
+  scoped_ptr<api::sessions::Device> CreateDeviceModel(
+      const browser_sync::SyncedSession* session);
+};
+
+class SessionsRestoreFunction : public SyncExtensionFunction {
+ protected:
+  virtual ~SessionsRestoreFunction() {}
+  virtual bool RunImpl() OVERRIDE;
+  DECLARE_EXTENSION_FUNCTION("sessions.restore", SESSIONS_RESTORE)
+
+ private:
+  void SetInvalidIdError(const std::string& invalid_id);
+  void SetResultRestoredTab(const content::WebContents* contents);
+  bool SetResultRestoredWindow(int window_id);
+  bool RestoreMostRecentlyClosed(Browser* browser);
+  bool RestoreLocalSession(const SessionId& session_id, Browser* browser);
+  bool RestoreForeignSession(const SessionId& session_id,
+                             Browser* browser);
+};
+
+class SessionsAPI : public ProfileKeyedAPI {
+ public:
+  explicit SessionsAPI(Profile* profile);
+  virtual ~SessionsAPI();
+
+  // ProfileKeyedAPI implementation.
+  static ProfileKeyedAPIFactory<SessionsAPI>* GetFactoryInstance();
+ private:
+  friend class ProfileKeyedAPIFactory<SessionsAPI>;
+
+  // ProfileKeyedAPI implementation.
+  static const char* service_name() {
+    return "SessionsAPI";
+  }
+  static const bool kServiceIsNULLWhileTesting = true;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_SESSIONS_SESSIONS_API_H__
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
new file mode 100644
index 0000000..4bfc9a0
--- /dev/null
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -0,0 +1,283 @@
+// Copyright 2013 The Chromium Authors. 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/sessions/sessions_api.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/api/tabs/tabs_api.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/sync/glue/session_model_associator.h"
+#include "chrome/browser/sync/profile_sync_service.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/test_switches.h"
+#include "chrome/test/base/testing_browser_process.h"
+
+namespace utils = extension_function_test_utils;
+
+namespace extensions {
+
+namespace {
+
+// If more sessions are added to session tags, num sessions should be updated.
+const char* kSessionTags[] = {"tag0", "tag1", "tag2", "tag3", "tag4"};
+const size_t kNumSessions = 5;
+
+void BuildSessionSpecifics(const std::string& tag,
+                           sync_pb::SessionSpecifics* meta) {
+  meta->set_session_tag(tag);
+  sync_pb::SessionHeader* header = meta->mutable_header();
+  header->set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+  header->set_client_name(tag);
+}
+
+void BuildWindowSpecifics(int window_id,
+                          const std::vector<int>& tab_list,
+                          sync_pb::SessionSpecifics* meta) {
+  sync_pb::SessionHeader* header = meta->mutable_header();
+  sync_pb::SessionWindow* window = header->add_window();
+  window->set_window_id(window_id);
+  window->set_selected_tab_index(0);
+  window->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
+  for (std::vector<int>::const_iterator iter = tab_list.begin();
+       iter != tab_list.end(); ++iter) {
+    window->add_tab(*iter);
+  }
+}
+
+void BuildTabSpecifics(const std::string& tag, int window_id, int tab_id,
+                       sync_pb::SessionSpecifics* tab_base) {
+  tab_base->set_session_tag(tag);
+  tab_base->set_tab_node_id(0);
+  sync_pb::SessionTab* tab = tab_base->mutable_tab();
+  tab->set_tab_id(tab_id);
+  tab->set_tab_visual_index(1);
+  tab->set_current_navigation_index(0);
+  tab->set_pinned(true);
+  tab->set_extension_app_id("app_id");
+  sync_pb::TabNavigation* navigation = tab->add_navigation();
+  navigation->set_virtual_url("http://foo/1");
+  navigation->set_referrer("referrer");
+  navigation->set_title("title");
+  navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
+}
+
+} // namespace
+
+class ExtensionSessionsTest : public InProcessBrowserTest {
+ public:
+  virtual void SetUpOnMainThread() OVERRIDE;
+ protected:
+  void CreateTestProfileSyncService();
+  void CreateTestExtension();
+  void CreateSessionModels();
+
+  template <class T>
+  scoped_refptr<T> CreateFunction(bool has_callback) {
+    scoped_refptr<T> fn(new T());
+    fn->set_extension(extension_.get());
+    fn->set_has_callback(has_callback);
+    return fn;
+  };
+
+  Browser* browser_;
+  browser_sync::SessionModelAssociator* associator_;
+  scoped_refptr<extensions::Extension> extension_;
+};
+
+void ExtensionSessionsTest::SetUpOnMainThread() {
+  CreateTestProfileSyncService();
+  CreateTestExtension();
+}
+
+void ExtensionSessionsTest::CreateTestProfileSyncService() {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  base::FilePath path;
+  PathService::Get(chrome::DIR_USER_DATA, &path);
+  path = path.AppendASCII("test_profile");
+  if (!base::PathExists(path))
+    CHECK(file_util::CreateDirectory(path));
+  Profile* profile =
+      Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
+  profile_manager->RegisterTestingProfile(profile, true, false);
+  browser_ = new Browser(Browser::CreateParams(
+      profile, chrome::HOST_DESKTOP_TYPE_NATIVE));
+  ProfileSyncServiceMock* service = static_cast<ProfileSyncServiceMock*>(
+      ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+      profile, &ProfileSyncServiceMock::BuildMockProfileSyncService));
+
+  associator_ = new browser_sync::SessionModelAssociator(
+      static_cast<ProfileSyncService*>(service), true);
+  syncer::ModelTypeSet preferred_types;
+  preferred_types.Put(syncer::SESSIONS);
+  GoogleServiceAuthError no_error(GoogleServiceAuthError::NONE);
+
+  ON_CALL(*service, GetSessionModelAssociator()).WillByDefault(
+      testing::Return(associator_));
+  ON_CALL(*service, GetPreferredDataTypes()).WillByDefault(
+      testing::Return(preferred_types));
+  EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(
+      testing::ReturnRef(no_error));
+  ON_CALL(*service, GetActiveDataTypes()).WillByDefault(
+      testing::Return(preferred_types));
+  EXPECT_CALL(*service, AddObserver(testing::_)).Times(testing::AnyNumber());
+  EXPECT_CALL(*service, RemoveObserver(testing::_)).Times(testing::AnyNumber());
+
+  service->Initialize();
+}
+
+void ExtensionSessionsTest::CreateTestExtension() {
+  scoped_ptr<base::DictionaryValue> test_extension_value(
+      utils::ParseDictionary(
+      "{\"name\": \"Test\", \"version\": \"1.0\", "
+      "\"permissions\": [\"sessions\", \"tabs\"]}"));
+  extension_ = utils::CreateExtension(test_extension_value.get());
+}
+
+void ExtensionSessionsTest::CreateSessionModels() {
+  for (size_t index = 0; index < kNumSessions; ++index) {
+    // Fill an instance of session specifics with a foreign session's data.
+    sync_pb::SessionSpecifics meta;
+    BuildSessionSpecifics(kSessionTags[index], &meta);
+    SessionID::id_type tab_nums1[] = {5, 10, 13, 17};
+    std::vector<SessionID::id_type> tab_list1(
+        tab_nums1, tab_nums1 + arraysize(tab_nums1));
+    BuildWindowSpecifics(index, tab_list1, &meta);
+    std::vector<sync_pb::SessionSpecifics> tabs1;
+    tabs1.resize(tab_list1.size());
+    for (size_t i = 0; i < tab_list1.size(); ++i) {
+      BuildTabSpecifics(kSessionTags[index], 0, tab_list1[i], &tabs1[i]);
+    }
+
+    associator_->SetCurrentMachineTagForTesting(kSessionTags[index]);
+    // Update associator with the session's meta node containing one window.
+    associator_->AssociateForeignSpecifics(meta, base::Time());
+    // Add tabs for the window.
+    for (std::vector<sync_pb::SessionSpecifics>::iterator iter = tabs1.begin();
+         iter != tabs1.end(); ++iter) {
+      associator_->AssociateForeignSpecifics(*iter, base::Time());
+    }
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevices) {
+  CreateSessionModels();
+
+  scoped_ptr<base::ListValue> result(utils::ToList(
+      utils::RunFunctionAndReturnSingleResult(
+          CreateFunction<SessionsGetDevicesFunction>(true).get(),
+          "[{\"maxResults\": 0}]",
+          browser_)));
+  ASSERT_TRUE(result);
+  ListValue* devices = result.get();
+  EXPECT_EQ(5u, devices->GetSize());
+  DictionaryValue* device = NULL;
+  ListValue* sessions = NULL;
+  for (size_t i = 0; i < devices->GetSize(); ++i) {
+    EXPECT_TRUE(devices->GetDictionary(i, &device));
+    EXPECT_EQ(kSessionTags[i], utils::GetString(device, "info"));
+    EXPECT_TRUE(device->GetList("sessions", &sessions));
+    EXPECT_EQ(0u, sessions->GetSize());
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevicesMaxResults) {
+  CreateSessionModels();
+
+  scoped_ptr<base::ListValue> result(utils::ToList(
+      utils::RunFunctionAndReturnSingleResult(
+          CreateFunction<SessionsGetDevicesFunction>(true).get(),
+          "[]",
+          browser_)));
+  ASSERT_TRUE(result);
+  ListValue* devices = result.get();
+  EXPECT_EQ(5u, devices->GetSize());
+  DictionaryValue* device = NULL;
+  ListValue* sessions = NULL;
+  for (size_t i = 0; i < devices->GetSize(); ++i) {
+    EXPECT_TRUE(devices->GetDictionary(i, &device));
+    EXPECT_EQ(kSessionTags[i], utils::GetString(device, "info"));
+    EXPECT_TRUE(device->GetList("sessions", &sessions));
+    EXPECT_EQ(1u, sessions->GetSize());
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevicesListEmpty) {
+  scoped_ptr<base::ListValue> result(utils::ToList(
+      utils::RunFunctionAndReturnSingleResult(
+          CreateFunction<SessionsGetDevicesFunction>(true).get(),
+          "[]",
+          browser_)));
+
+  ASSERT_TRUE(result);
+  ListValue* devices = result.get();
+  EXPECT_EQ(0u, devices->GetSize());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreForeignSessionWindow) {
+  CreateSessionModels();
+
+  scoped_ptr<base::DictionaryValue> restored_window_session(utils::ToDictionary(
+      utils::RunFunctionAndReturnSingleResult(
+          CreateFunction<SessionsRestoreFunction>(true).get(),
+          "[\"tag3.3\"]",
+          browser_,
+          utils::INCLUDE_INCOGNITO)));
+  ASSERT_TRUE(restored_window_session);
+
+  scoped_ptr<base::ListValue> result(utils::ToList(
+      utils::RunFunctionAndReturnSingleResult(
+          CreateFunction<WindowsGetAllFunction>(true).get(),
+          "[]",
+          browser_)));
+  ASSERT_TRUE(result);
+
+  ListValue* windows = result.get();
+  EXPECT_EQ(2u, windows->GetSize());
+  DictionaryValue* restored_window = NULL;
+  EXPECT_TRUE(restored_window_session->GetDictionary("window",
+                                                     &restored_window));
+  DictionaryValue* window = NULL;
+  int restored_id = utils::GetInteger(restored_window, "id");
+  for (size_t i = 0; i < windows->GetSize(); ++i) {
+    EXPECT_TRUE(windows->GetDictionary(i, &window));
+    if (utils::GetInteger(window, "id") == restored_id)
+      break;
+  }
+  EXPECT_EQ(restored_id, utils::GetInteger(window, "id"));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreForeignSessionInvalidId) {
+  CreateSessionModels();
+
+  EXPECT_TRUE(MatchPattern(utils::RunFunctionAndReturnError(
+      CreateFunction<SessionsRestoreFunction>(true).get(),
+      "[\"tag3.0\"]",
+      browser_), "Invalid session id: \"tag3.0\"."));
+}
+
+// Flaky on ChromeOS, times out on OSX Debug http://crbug.com/251199
+#if defined(OS_CHROMEOS) || (defined(OS_MACOSX) && !defined(NDEBUG))
+#define MAYBE_SessionsApis DISABLED_SessionsApis
+#else
+#define MAYBE_SessionsApis SessionsApis
+#endif
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_SessionsApis) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
+    return;
+#endif
+
+  ASSERT_TRUE(RunExtensionSubtest("sessions",
+                                  "sessions.html")) << message_;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.cc b/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.cc
index 47a132b..5138959 100644
--- a/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.cc
+++ b/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/sync/glue/device_info.h"
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/common/extensions/api/signedin_devices.h"
 
 using base::DictionaryValue;
 using browser_sync::DeviceInfo;
@@ -47,11 +48,11 @@
 // Helper routine to get all signed in devices. The helper takes in
 // the pointers for |ProfileSyncService| and |Extensionprefs|. This
 // makes it easier to test by passing mock values for these pointers.
-ScopedVector<DeviceInfo> GetAllSignedInDevices(
+ScopedVector<DeviceInfo> GetAllSignedinDevices(
     const std::string& extension_id,
     ProfileSyncService* pss,
     ExtensionPrefs* extension_prefs) {
-  ScopedVector<DeviceInfo> devices = pss->GetAllSignedInDevices();
+  ScopedVector<DeviceInfo> devices = pss->GetAllSignedinDevices();
   const DictionaryValue* mapping_dictionary = GetIdMappingDictionary(
       extension_prefs,
       extension_id);
@@ -72,7 +73,7 @@
   return devices.Pass();
 }
 
-ScopedVector<DeviceInfo> GetAllSignedInDevices(
+ScopedVector<DeviceInfo> GetAllSignedinDevices(
     const std::string& extension_id,
     Profile* profile) {
   // Get the profile sync service and extension prefs pointers
@@ -80,10 +81,39 @@
   ProfileSyncService* pss = ProfileSyncServiceFactory::GetForProfile(profile);
   ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile);
 
-  return GetAllSignedInDevices(extension_id,
+  return GetAllSignedinDevices(extension_id,
                                pss,
                                extension_prefs);
 }
 
+bool SignedinDevicesGetFunction::RunImpl() {
+  scoped_ptr<api::signedin_devices::Get::Params> params(
+      api::signedin_devices::Get::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  bool is_local = params->is_local.get() ? *params->is_local : false;
+
+  if (is_local) {
+    // TODO(lipalani): Set the device info for local device.
+    base::ListValue* result = new base::ListValue();
+    SetResult(result);
+    return true;
+  }
+
+  ScopedVector<DeviceInfo> devices = GetAllSignedinDevices(extension_id(),
+                                                           profile());
+
+  scoped_ptr<base::ListValue> result(new base::ListValue());
+
+  for (ScopedVector<DeviceInfo>::const_iterator it = devices.begin();
+       it != devices.end();
+       ++it) {
+    result->Append((*it)->ToValue());
+  }
+
+  SetResult(result.release());
+  return true;
+}
+
 }  // namespace extensions
 
diff --git a/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.h b/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.h
index 7ebc64f..eb04d3a 100644
--- a/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.h
+++ b/chrome/browser/extensions/api/signedin_devices/signedin_devices_api.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/memory/scoped_vector.h"
+#include "chrome/browser/extensions/extension_function.h"
 
 namespace browser_sync {
 class DeviceInfo;
@@ -27,15 +28,24 @@
 // filled with the list of devices associated with the account signed into this
 // |profile|. This function needs the |extension_id| because the
 // public device ids are set per extension.
-ScopedVector<browser_sync::DeviceInfo> GetAllSignedInDevices(
+ScopedVector<browser_sync::DeviceInfo> GetAllSignedinDevices(
     const std::string& extension_id,
     Profile* profile);
 
-ScopedVector<browser_sync::DeviceInfo> GetAllSignedInDevices(
+ScopedVector<browser_sync::DeviceInfo> GetAllSignedinDevices(
     const std::string& extension_id,
     ProfileSyncService* pss,
     ExtensionPrefs* extension_prefs);
 
+class SignedinDevicesGetFunction : public SyncExtensionFunction {
+ protected:
+  virtual ~SignedinDevicesGetFunction() {}
+
+  // ExtensionFunction:
+  virtual bool RunImpl() OVERRIDE;
+  DECLARE_EXTENSION_FUNCTION("SignedinDevices.get", SIGNEDIN_DEVICES_GET)
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_SIGNEDIN_DEVICES_SIGNEDIN_DEVICES_API_H__
diff --git a/chrome/browser/extensions/api/signedin_devices/signedin_devices_api_unittest.cc b/chrome/browser/extensions/api/signedin_devices/signedin_devices_api_unittest.cc
index ab21083..8936680 100644
--- a/chrome/browser/extensions/api/signedin_devices/signedin_devices_api_unittest.cc
+++ b/chrome/browser/extensions/api/signedin_devices/signedin_devices_api_unittest.cc
@@ -8,12 +8,19 @@
 
 #include "base/guid.h"
 #include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "base/values.h"
 #include "chrome/browser/extensions/api/signedin_devices/signedin_devices_api.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/test_extension_prefs.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/glue/device_info.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,6 +31,8 @@
 
 namespace extensions {
 
+namespace utils = extension_function_test_utils;
+
 TEST(SignedinDevicesAPITest, GetSignedInDevices) {
   ProfileSyncServiceMock pss_mock;
   base::MessageLoop message_loop_;
@@ -49,10 +58,10 @@
   devices.push_back(&device_info1);
   devices.push_back(&device_info2);
 
-  EXPECT_CALL(pss_mock, GetAllSignedInDevicesMock()).
+  EXPECT_CALL(pss_mock, GetAllSignedinDevicesMock()).
               WillOnce(Return(&devices));
 
-  ScopedVector<DeviceInfo> output1 = GetAllSignedInDevices(
+  ScopedVector<DeviceInfo> output1 = GetAllSignedinDevices(
       extension_test.get()->id(),
       &pss_mock,
       extension_prefs.prefs());
@@ -77,10 +86,10 @@
 
   devices.push_back(&device_info3);
 
-  EXPECT_CALL(pss_mock, GetAllSignedInDevicesMock()).
+  EXPECT_CALL(pss_mock, GetAllSignedinDevicesMock()).
               WillOnce(Return(&devices));
 
-  ScopedVector<DeviceInfo> output2 = GetAllSignedInDevices(
+  ScopedVector<DeviceInfo> output2 = GetAllSignedinDevices(
       extension_test.get()->id(),
       &pss_mock,
       extension_prefs.prefs());
@@ -98,4 +107,127 @@
   output2.weak_clear();
 }
 
+class ProfileSyncServiceMockForExtensionTests:
+    public ProfileSyncServiceMock {
+ public:
+  ProfileSyncServiceMockForExtensionTests() {}
+  ~ProfileSyncServiceMockForExtensionTests() {}
+  MOCK_METHOD0(Shutdown, void());
+};
+
+BrowserContextKeyedService* CreateProfileSyncServiceMock(
+    content::BrowserContext* profile) {
+  return new ProfileSyncServiceMockForExtensionTests();
+}
+
+class ExtensionSignedinDevicesTest : public BrowserWithTestWindowTest {
+ public:
+  virtual void SetUp() {
+    BrowserWithTestWindowTest::SetUp();
+
+    ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
+        profile(), CreateProfileSyncServiceMock);
+
+    extension_ = utils::CreateEmptyExtensionWithLocation(
+        extensions::Manifest::UNPACKED);
+
+  }
+
+  base::Value* RunFunctionWithExtension(
+      UIThreadExtensionFunction* function,
+      const std::string& args) {
+    scoped_refptr<UIThreadExtensionFunction> delete_function(function);
+    function->set_extension(extension_.get());
+    return utils::RunFunctionAndReturnSingleResult(function, args, browser());
+  }
+
+  base::ListValue* RunFunctionAndReturnList(
+      UIThreadExtensionFunction* function,
+      const std::string& args) {
+    base::Value* result = RunFunctionWithExtension(function, args);
+    return result ? utils::ToList(result) : NULL;
+  }
+
+ protected:
+  scoped_refptr<extensions::Extension> extension_;
+};
+
+DeviceInfo* CreateDeviceInfo(const DeviceInfo& device_info) {
+  return new DeviceInfo(device_info.guid(),
+                        device_info.client_name(),
+                        device_info.chrome_version(),
+                        device_info.sync_user_agent(),
+                        device_info.device_type());
+}
+
+std::string GetPublicId(const base::DictionaryValue* dictionary) {
+  std::string public_id;
+  if (!dictionary->GetString("id", &public_id)) {
+    ADD_FAILURE() << "Not able to find public id in the dictionary";
+  }
+
+  return public_id;
+}
+
+void VerifyDictionaryWithDeviceInfo(const base::DictionaryValue* actual_value,
+                                    DeviceInfo* device_info) {
+  std::string public_id = GetPublicId(actual_value);
+  device_info->set_public_id(public_id);
+
+  scoped_ptr<base::DictionaryValue> expected_value(device_info->ToValue());
+  EXPECT_TRUE(expected_value->Equals(actual_value));
+}
+
+base::DictionaryValue* GetDictionaryFromList(int index,
+                                             base::ListValue* value) {
+  base::DictionaryValue* dictionary;
+  if (!value->GetDictionary(index, &dictionary)) {
+    ADD_FAILURE() << "Expected a list of dictionaries";
+    return NULL;
+  }
+  return dictionary;
+}
+
+TEST_F(ExtensionSignedinDevicesTest, GetAll) {
+  ProfileSyncServiceMockForExtensionTests* pss_mock =
+      static_cast<ProfileSyncServiceMockForExtensionTests*>(
+          ProfileSyncServiceFactory::GetForProfile(profile()));
+
+  DeviceInfo device_info1(
+      base::GenerateGUID(),
+      "abc Device", "XYZ v1", "XYZ SyncAgent v1",
+      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+
+  DeviceInfo device_info2(
+      base::GenerateGUID(),
+      "def Device", "XYZ v2", "XYZ SyncAgent v2",
+      sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+
+  std::vector<DeviceInfo*> devices;
+  devices.push_back(CreateDeviceInfo(device_info1));
+  devices.push_back(CreateDeviceInfo(device_info2));
+
+  EXPECT_CALL(*pss_mock, GetAllSignedinDevicesMock()).
+              WillOnce(Return(&devices));
+
+  EXPECT_CALL(*pss_mock, Shutdown());
+
+  scoped_ptr<base::ListValue> result(RunFunctionAndReturnList(
+      new SignedinDevicesGetFunction(), "[null]"));
+
+  // Ensure dictionary matches device info.
+  VerifyDictionaryWithDeviceInfo(GetDictionaryFromList(0, result.get()),
+                                 &device_info1);
+  VerifyDictionaryWithDeviceInfo(GetDictionaryFromList(1, result.get()),
+                                 &device_info2);
+
+  // Ensure public ids are set and unique.
+  std::string public_id1 = GetPublicId(GetDictionaryFromList(0, result.get()));
+  std::string public_id2 = GetPublicId(GetDictionaryFromList(1, result.get()));
+
+  EXPECT_FALSE(public_id1.empty());
+  EXPECT_FALSE(public_id2.empty());
+  EXPECT_NE(public_id1, public_id2);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/socket/OWNERS b/chrome/browser/extensions/api/socket/OWNERS
new file mode 100644
index 0000000..b0df7e7
--- /dev/null
+++ b/chrome/browser/extensions/api/socket/OWNERS
@@ -0,0 +1,2 @@
+ikarienator@chromium.org
+rpaquay@chromium.org
diff --git a/chrome/browser/extensions/api/socket/socket_api.cc b/chrome/browser/extensions/api/socket/socket_api.cc
index 6a43ce7..c59d97a 100644
--- a/chrome/browser/extensions/api/socket/socket_api.cc
+++ b/chrome/browser/extensions/api/socket/socket_api.cc
@@ -47,30 +47,39 @@
 const char kWildcardAddress[] = "*";
 const int kWildcardPort = 0;
 
-SocketAsyncApiFunction::SocketAsyncApiFunction()
-    : manager_(NULL) {
+SocketAsyncApiFunction::SocketAsyncApiFunction() {
 }
 
 SocketAsyncApiFunction::~SocketAsyncApiFunction() {
 }
 
 bool SocketAsyncApiFunction::PrePrepare() {
-  manager_ = ApiResourceManager<Socket>::Get(profile());
-  DCHECK(manager_) << "There is no socket manager. "
-    "If this assertion is failing during a test, then it is likely that "
-    "TestExtensionSystem is failing to provide an instance of "
-    "ApiResourceManager<Socket>.";
-  return manager_ != NULL;
+  manager_ = CreateSocketResourceManager();
+  return manager_->SetProfile(profile());
 }
 
 bool SocketAsyncApiFunction::Respond() {
   return error_.empty();
 }
 
+scoped_ptr<SocketResourceManagerInterface>
+    SocketAsyncApiFunction::CreateSocketResourceManager() {
+  return scoped_ptr<SocketResourceManagerInterface>(
+      new SocketResourceManager<Socket>()).Pass();
+}
+
+int SocketAsyncApiFunction::AddSocket(Socket* socket) {
+  return manager_->Add(socket);
+}
+
 Socket* SocketAsyncApiFunction::GetSocket(int api_resource_id) {
   return manager_->Get(extension_->id(), api_resource_id);
 }
 
+base::hash_set<int>* SocketAsyncApiFunction::GetSocketIds() {
+  return manager_->GetResourceIds(extension_->id());
+}
+
 void SocketAsyncApiFunction::RemoveSocket(int api_resource_id) {
   manager_->Remove(extension_->id(), api_resource_id);
 }
@@ -99,9 +108,12 @@
 
   net::HostResolver::RequestInfo request_info(host_port_pair);
   int resolve_result = host_resolver->Resolve(
-      request_info, addresses_.get(),
+      request_info,
+      net::DEFAULT_PRIORITY,
+      addresses_.get(),
       base::Bind(&SocketExtensionWithDnsLookupFunction::OnDnsLookup, this),
-      request_handle_.get(), net::BoundNetLog());
+      request_handle_.get(),
+      net::BoundNetLog());
 
   if (resolve_result != net::ERR_IO_PENDING)
     OnDnsLookup(resolve_result);
@@ -152,7 +164,7 @@
   DCHECK(socket);
 
   base::DictionaryValue* result = new base::DictionaryValue();
-  result->SetInteger(kSocketIdKey, manager_->Add(socket));
+  result->SetInteger(kSocketIdKey, AddSocket(socket));
   SetResult(result);
 }
 
@@ -186,7 +198,7 @@
   socket_ = GetSocket(socket_id_);
   if (!socket_) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(-1));
+    SetResult(new base::FundamentalValue(-1));
     AsyncWorkCompleted();
     return;
   }
@@ -209,7 +221,7 @@
   if (!PermissionsData::CheckAPIPermissionWithParam(
           GetExtension(), APIPermission::kSocket, &param)) {
     error_ = kPermissionError;
-    SetResult(Value::CreateIntegerValue(-1));
+    SetResult(new base::FundamentalValue(-1));
     AsyncWorkCompleted();
     return;
   }
@@ -221,7 +233,7 @@
   if (lookup_result == net::OK) {
     StartConnect();
   } else {
-    SetResult(Value::CreateIntegerValue(lookup_result));
+    SetResult(new base::FundamentalValue(lookup_result));
     AsyncWorkCompleted();
   }
 }
@@ -232,7 +244,7 @@
 }
 
 void SocketConnectFunction::OnConnect(int result) {
-  SetResult(Value::CreateIntegerValue(result));
+  SetResult(new base::FundamentalValue(result));
   AsyncWorkCompleted();
 }
 
@@ -263,7 +275,7 @@
 
   if (!socket) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
@@ -275,17 +287,17 @@
             APIPermission::kSocket,
             &param)) {
       error_ = kPermissionError;
-      SetResult(Value::CreateIntegerValue(result));
+      SetResult(new base::FundamentalValue(result));
       return;
     }
   } else if (socket->GetSocketType() == Socket::TYPE_TCP) {
     error_ = kTCPSocketBindError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
   result = socket->Bind(address_, port_);
-  SetResult(Value::CreateIntegerValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketListenFunction::SocketListenFunction() {}
@@ -310,7 +322,7 @@
             APIPermission::kSocket,
             &param)) {
       error_ = kPermissionError;
-      SetResult(Value::CreateIntegerValue(result));
+      SetResult(new base::FundamentalValue(result));
       return;
     }
 
@@ -323,7 +335,7 @@
     error_ = kSocketNotFoundError;
   }
 
-  SetResult(Value::CreateIntegerValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketAcceptFunction::SocketAcceptFunction() {}
@@ -352,7 +364,7 @@
   result->SetInteger(kResultCodeKey, result_code);
   if (socket) {
     Socket *client_socket = new TCPSocket(socket, extension_id(), true);
-    result->SetInteger(kSocketIdKey, manager_->Add(client_socket));
+    result->SetInteger(kSocketIdKey, AddSocket(client_socket));
   }
   SetResult(result);
 
@@ -504,7 +516,7 @@
   socket_ = GetSocket(socket_id_);
   if (!socket_) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(-1));
+    SetResult(new base::FundamentalValue(-1));
     AsyncWorkCompleted();
     return;
   }
@@ -517,7 +529,7 @@
             APIPermission::kSocket,
             &param)) {
       error_ = kPermissionError;
-      SetResult(Value::CreateIntegerValue(-1));
+      SetResult(new base::FundamentalValue(-1));
       AsyncWorkCompleted();
       return;
     }
@@ -530,7 +542,7 @@
   if (lookup_result == net::OK) {
     StartSendTo();
   } else {
-    SetResult(Value::CreateIntegerValue(lookup_result));
+    SetResult(new base::FundamentalValue(lookup_result));
     AsyncWorkCompleted();
   }
 }
@@ -569,7 +581,7 @@
   } else {
     error_ = kSocketNotFoundError;
   }
-  SetResult(Value::CreateBooleanValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketSetNoDelayFunction::SocketSetNoDelayFunction() {}
@@ -589,7 +601,7 @@
     result = socket->SetNoDelay(params_->no_delay);
   else
     error_ = kSocketNotFoundError;
-  SetResult(Value::CreateBooleanValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketGetInfoFunction::SocketGetInfoFunction() {}
@@ -701,13 +713,13 @@
   Socket* socket = GetSocket(params_->socket_id);
   if (!socket) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
   if (socket->GetSocketType() != Socket::TYPE_UDP) {
     error_ = kMulticastSocketTypeError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
@@ -719,7 +731,7 @@
   if (!PermissionsData::CheckAPIPermissionWithParam(
           GetExtension(), APIPermission::kSocket, &param)) {
     error_ = kPermissionError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
@@ -727,7 +739,7 @@
   if (result != 0) {
     error_ = net::ErrorToString(result);
   }
-  SetResult(Value::CreateIntegerValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketLeaveGroupFunction::SocketLeaveGroupFunction() {}
@@ -746,13 +758,13 @@
 
   if (!socket) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
   if (socket->GetSocketType() != Socket::TYPE_UDP) {
     error_ = kMulticastSocketTypeError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
@@ -764,14 +776,14 @@
                                                     APIPermission::kSocket,
                                                     &param)) {
     error_ = kPermissionError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
   result = static_cast<UDPSocket*>(socket)->LeaveGroup(params_->address);
   if (result != 0)
     error_ = net::ErrorToString(result);
-  SetResult(Value::CreateIntegerValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketSetMulticastTimeToLiveFunction::SocketSetMulticastTimeToLiveFunction() {}
@@ -788,13 +800,13 @@
   Socket* socket = GetSocket(params_->socket_id);
   if (!socket) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
   if (socket->GetSocketType() != Socket::TYPE_UDP) {
     error_ = kMulticastSocketTypeError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
@@ -802,7 +814,7 @@
       params_->ttl);
   if (result != 0)
     error_ = net::ErrorToString(result);
-  SetResult(Value::CreateIntegerValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketSetMulticastLoopbackModeFunction::
@@ -822,13 +834,13 @@
   Socket* socket = GetSocket(params_->socket_id);
   if (!socket) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
   if (socket->GetSocketType() != Socket::TYPE_UDP) {
     error_ = kMulticastSocketTypeError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
@@ -836,7 +848,7 @@
       SetMulticastLoopbackMode(params_->enabled);
   if (result != 0)
     error_ = net::ErrorToString(result);
-  SetResult(Value::CreateIntegerValue(result));
+  SetResult(new base::FundamentalValue(result));
 }
 
 SocketGetJoinedGroupsFunction::SocketGetJoinedGroupsFunction() {}
@@ -854,13 +866,13 @@
   Socket* socket = GetSocket(params_->socket_id);
   if (!socket) {
     error_ = kSocketNotFoundError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
   if (socket->GetSocketType() != Socket::TYPE_UDP) {
     error_ = kMulticastSocketTypeError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
@@ -873,7 +885,7 @@
           APIPermission::kSocket,
           &param)) {
     error_ = kPermissionError;
-    SetResult(Value::CreateIntegerValue(result));
+    SetResult(new base::FundamentalValue(result));
     return;
   }
 
diff --git a/chrome/browser/extensions/api/socket/socket_api.h b/chrome/browser/extensions/api/socket/socket_api.h
index 4e68c58..396ddc6 100644
--- a/chrome/browser/extensions/api/socket/socket_api.h
+++ b/chrome/browser/extensions/api/socket/socket_api.h
@@ -27,6 +27,66 @@
 
 class Socket;
 
+// A simple interface to ApiResourceManager<Socket> or derived class. The goal
+// of this interface is to allow Socket API functions to use distinct instances
+// of ApiResourceManager<> depending on the type of socket (old version in
+// "socket" namespace vs new version in "socket.xxx" namespaces).
+class SocketResourceManagerInterface {
+ public:
+  virtual ~SocketResourceManagerInterface() {}
+
+  virtual bool SetProfile(Profile* profile) = 0;
+  virtual int Add(Socket *socket) = 0;
+  virtual Socket* Get(const std::string& extension_id,
+                      int api_resource_id) = 0;
+  virtual void Remove(const std::string& extension_id,
+                      int api_resource_id) = 0;
+  virtual base::hash_set<int>* GetResourceIds(
+      const std::string& extension_id) = 0;
+};
+
+// Implementation of SocketResourceManagerInterface using an
+// ApiResourceManager<T> instance (where T derives from Socket).
+template<typename T>
+class SocketResourceManager : public SocketResourceManagerInterface {
+ public:
+  SocketResourceManager()
+      : manager_(NULL) {
+  }
+
+  virtual bool SetProfile(Profile* profile) OVERRIDE {
+    manager_ = ApiResourceManager<T>::Get(profile);
+    DCHECK(manager_) << "There is no socket manager. "
+      "If this assertion is failing during a test, then it is likely that "
+      "TestExtensionSystem is failing to provide an instance of "
+      "ApiResourceManager<Socket>.";
+    return manager_ != NULL;
+  }
+
+  virtual int Add(Socket *socket) OVERRIDE {
+    // Note: Cast needed here, because "T" may be a subclass of "Socket".
+    return manager_->Add(static_cast<T*>(socket));
+  }
+
+  virtual Socket* Get(const std::string& extension_id,
+                      int api_resource_id) OVERRIDE {
+    return manager_->Get(extension_id, api_resource_id);
+  }
+
+  virtual void Remove(const std::string& extension_id,
+                      int api_resource_id) OVERRIDE {
+    manager_->Remove(extension_id, api_resource_id);
+  }
+
+  virtual base::hash_set<int>* GetResourceIds(
+      const std::string& extension_id) OVERRIDE {
+    return manager_->GetResourceIds(extension_id);
+  }
+
+ private:
+  ApiResourceManager<T>* manager_;
+};
+
 class SocketAsyncApiFunction : public AsyncApiFunction {
  public:
   SocketAsyncApiFunction();
@@ -38,10 +98,16 @@
   virtual bool PrePrepare() OVERRIDE;
   virtual bool Respond() OVERRIDE;
 
+  virtual scoped_ptr<SocketResourceManagerInterface>
+      CreateSocketResourceManager();
+
+  int AddSocket(Socket* socket);
   Socket* GetSocket(int api_resource_id);
   void RemoveSocket(int api_resource_id);
+  base::hash_set<int>* GetSocketIds();
 
-  ApiResourceManager<Socket>* manager_;
+ private:
+  scoped_ptr<SocketResourceManagerInterface> manager_;
 };
 
 class SocketExtensionWithDnsLookupFunction : public SocketAsyncApiFunction {
diff --git a/chrome/browser/extensions/api/socket/udp_socket.cc b/chrome/browser/extensions/api/socket/udp_socket.cc
index 4a77aea..7d36ffc 100644
--- a/chrome/browser/extensions/api/socket/udp_socket.cc
+++ b/chrome/browser/extensions/api/socket/udp_socket.cc
@@ -14,6 +14,17 @@
 
 namespace extensions {
 
+static base::LazyInstance<ProfileKeyedAPIFactory<
+      ApiResourceManager<ResumableUDPSocket> > >
+          g_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+template <>
+ProfileKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> >*
+ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance() {
+  return &g_factory.Get();
+}
+
 UDPSocket::UDPSocket(const std::string& owner_extension_id)
     : Socket(owner_extension_id),
       socket_(net::DatagramSocket::DEFAULT_BIND,
@@ -278,4 +289,34 @@
   return multicast_groups_;
 }
 
+ResumableUDPSocket::ResumableUDPSocket(const std::string& owner_extension_id)
+    : UDPSocket(owner_extension_id),
+      persistent_(false),
+      buffer_size_(0) {
+}
+
+const std::string& ResumableUDPSocket::name() const {
+  return name_;
+}
+
+void ResumableUDPSocket::set_name(const std::string& name) {
+  name_ = name;
+}
+
+bool ResumableUDPSocket::persistent() const {
+  return persistent_;
+}
+
+void ResumableUDPSocket::set_persistent(bool persistent) {
+  persistent_ = persistent;
+}
+
+int ResumableUDPSocket::buffer_size() const {
+  return buffer_size_;
+}
+
+void ResumableUDPSocket::set_buffer_size(int buffer_size) {
+  buffer_size_ = buffer_size;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/socket/udp_socket.h b/chrome/browser/extensions/api/socket/udp_socket.h
index b301cb2..4989e27 100644
--- a/chrome/browser/extensions/api/socket/udp_socket.h
+++ b/chrome/browser/extensions/api/socket/udp_socket.h
@@ -74,6 +74,33 @@
   std::vector<std::string> multicast_groups_;
 };
 
+// UDP Socket instances from the "sockets.udp" namespace. These are regular
+// socket objects with additional properties related to the behavior defined in
+// the "sockets.udp" namespace.
+class ResumableUDPSocket : public UDPSocket {
+ public:
+  explicit ResumableUDPSocket(const std::string& owner_extension_id);
+
+  const std::string& name() const;
+  void set_name(const std::string& name);
+
+  virtual bool persistent() const OVERRIDE;
+  void set_persistent(bool persistent);
+
+  int buffer_size() const;
+  void set_buffer_size(int buffer_size);
+
+ private:
+  friend class ApiResourceManager<ResumableUDPSocket>;
+  static const char* service_name() {
+    return "ResumableUDPSocketManager";
+  }
+
+  std::string name_;
+  bool persistent_;
+  int buffer_size_;
+};
+
 }  //  namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_SOCKET_UDP_SOCKET_H_
diff --git a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
new file mode 100644
index 0000000..c7a6e81
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.cc
@@ -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.
+
+#include "chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h"
+
+#include "chrome/browser/extensions/api/socket/udp_socket.h"
+#include "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.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"
+#include "net/base/net_errors.h"
+
+namespace extensions {
+namespace api {
+
+using content::SocketPermissionRequest;
+
+const char kSocketNotFoundError[] = "Socket not found";
+const char kPermissionError[] = "App does not have permission";
+const char kWildcardAddress[] = "*";
+const int kWildcardPort = 0;
+
+UDPSocketAsyncApiFunction::~UDPSocketAsyncApiFunction() {}
+
+scoped_ptr<SocketResourceManagerInterface>
+    UDPSocketAsyncApiFunction::CreateSocketResourceManager() {
+  return scoped_ptr<SocketResourceManagerInterface>(
+      new SocketResourceManager<ResumableUDPSocket>()).Pass();
+}
+
+ResumableUDPSocket* UDPSocketAsyncApiFunction::GetUdpSocket(int socket_id) {
+  return static_cast<ResumableUDPSocket*>(GetSocket(socket_id));
+}
+
+UDPSocketExtensionWithDnsLookupFunction::
+    ~UDPSocketExtensionWithDnsLookupFunction() {}
+
+scoped_ptr<SocketResourceManagerInterface>
+    UDPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() {
+  return scoped_ptr<SocketResourceManagerInterface>(
+      new SocketResourceManager<ResumableUDPSocket>()).Pass();
+}
+
+ResumableUDPSocket* UDPSocketExtensionWithDnsLookupFunction::GetUdpSocket(
+    int socket_id) {
+  return static_cast<ResumableUDPSocket*>(GetSocket(socket_id));
+}
+
+linked_ptr<sockets_udp::SocketInfo> CreateSocketInfo(
+    int socket_id,
+    ResumableUDPSocket* socket) {
+  linked_ptr<sockets_udp::SocketInfo> socket_info(
+      new sockets_udp::SocketInfo());
+  // This represents what we know about the socket, and does not call through
+  // to the system.
+  socket_info->socket_id = socket_id;
+  if (!socket->name().empty()) {
+    socket_info->name.reset(new std::string(socket->name()));
+  }
+  socket_info->persistent = socket->persistent();
+  if (socket->buffer_size() > 0) {
+    socket_info->buffer_size.reset(new int(socket->buffer_size()));
+  }
+
+  // Grab the local address as known by the OS.
+  net::IPEndPoint localAddress;
+  if (socket->GetLocalAddress(&localAddress)) {
+    socket_info->local_address.reset(
+        new std::string(localAddress.ToStringWithoutPort()));
+    socket_info->local_port.reset(new int(localAddress.port()));
+  }
+
+  return socket_info;
+}
+
+void SetSocketProperties(ResumableUDPSocket* socket,
+                         sockets_udp::SocketProperties* properties) {
+  if (properties->name.get()) {
+    socket->set_name(*properties->name.get());
+  }
+  if (properties->persistent.get()) {
+    socket->set_persistent(*properties->persistent.get());
+  }
+  if (properties->buffer_size.get()) {
+    socket->set_buffer_size(*properties->buffer_size.get());
+  }
+}
+
+SocketsUdpCreateFunction::SocketsUdpCreateFunction() {}
+
+SocketsUdpCreateFunction::~SocketsUdpCreateFunction() {}
+
+bool SocketsUdpCreateFunction::Prepare() {
+  params_ = sockets_udp::Create::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpCreateFunction::Work() {
+  ResumableUDPSocket* socket = new ResumableUDPSocket(extension_->id());
+
+  sockets_udp::SocketProperties* properties = params_.get()->properties.get();
+  if (properties) {
+    SetSocketProperties(socket, properties);
+  }
+
+  sockets_udp::CreateInfo create_info;
+  create_info.socket_id = AddSocket(socket);
+  results_ = sockets_udp::Create::Results::Create(create_info);
+}
+
+SocketsUdpUpdateFunction::SocketsUdpUpdateFunction() {}
+
+SocketsUdpUpdateFunction::~SocketsUdpUpdateFunction() {}
+
+bool SocketsUdpUpdateFunction::Prepare() {
+  params_ = sockets_udp::Update::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpUpdateFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  SetSocketProperties(socket, &params_.get()->properties);
+  results_ = sockets_udp::Update::Results::Create();
+}
+
+SocketsUdpBindFunction::SocketsUdpBindFunction() {}
+
+SocketsUdpBindFunction::~SocketsUdpBindFunction() {}
+
+bool SocketsUdpBindFunction::Prepare() {
+  params_ = sockets_udp::Bind::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpBindFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  SocketPermission::CheckParam param(
+      SocketPermissionRequest::UDP_BIND, params_->address, params_->port);
+  if (!PermissionsData::CheckAPIPermissionWithParam(
+          GetExtension(),
+          APIPermission::kSocket,
+          &param)) {
+    error_ = kPermissionError;
+    return;
+  }
+
+  int net_result = socket->Bind(params_->address, params_->port);
+  if (net_result == net::OK) {
+    UDPSocketEventDispatcher::Get(profile())->OnSocketBind(extension_->id(),
+                                                           params_->socket_id);
+  }
+
+  if (net_result != net::OK)
+    error_ = net::ErrorToString(net_result);
+  results_ = sockets_udp::Bind::Results::Create(net_result);
+}
+
+SocketsUdpSendFunction::SocketsUdpSendFunction()
+    : io_buffer_size_(0) {}
+
+SocketsUdpSendFunction::~SocketsUdpSendFunction() {}
+
+bool SocketsUdpSendFunction::Prepare() {
+  params_ = sockets_udp::Send::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  io_buffer_size_ = params_->data.size();
+  io_buffer_ = new net::WrappedIOBuffer(params_->data.data());
+  return true;
+}
+
+void SocketsUdpSendFunction::AsyncWorkStart() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    AsyncWorkCompleted();
+    return;
+  }
+
+  SocketPermission::CheckParam param(
+      SocketPermissionRequest::UDP_SEND_TO,
+      params_->address,
+      params_->port);
+  if (!PermissionsData::CheckAPIPermissionWithParam(
+          GetExtension(),
+          APIPermission::kSocket,
+          &param)) {
+    error_ = kPermissionError;
+    AsyncWorkCompleted();
+    return;
+  }
+
+  StartDnsLookup(params_->address);
+}
+
+void SocketsUdpSendFunction::AfterDnsLookup(int lookup_result) {
+  if (lookup_result == net::OK) {
+    StartSendTo();
+  } else {
+    SetSendResult(lookup_result, -1);
+  }
+}
+
+void SocketsUdpSendFunction::StartSendTo() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    AsyncWorkCompleted();
+    return;
+  }
+
+  socket->SendTo(io_buffer_, io_buffer_size_, resolved_address_, params_->port,
+                  base::Bind(&SocketsUdpSendFunction::OnCompleted, this));
+}
+
+void SocketsUdpSendFunction::OnCompleted(int net_result) {
+  if (net_result >= net::OK) {
+    SetSendResult(net::OK, net_result);
+  } else {
+    SetSendResult(net_result, -1);
+  }
+}
+
+void SocketsUdpSendFunction::SetSendResult(int net_result, int bytes_written) {
+  CHECK(net_result <= net::OK) << "Network status code must be < 0";
+
+  sockets_udp::SendInfo send_info;
+  send_info.result = net_result;
+  if (net_result == net::OK) {
+    send_info.bytes_written.reset(new int(bytes_written));
+  }
+
+  if (net_result != net::OK)
+    error_ = net::ErrorToString(net_result);
+  results_ = sockets_udp::Send::Results::Create(send_info);
+  AsyncWorkCompleted();
+}
+
+SocketsUdpCloseFunction::SocketsUdpCloseFunction() {}
+
+SocketsUdpCloseFunction::~SocketsUdpCloseFunction() {}
+
+bool SocketsUdpCloseFunction::Prepare() {
+  params_ = sockets_udp::Close::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpCloseFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  RemoveSocket(params_->socket_id);
+  results_ = sockets_udp::Close::Results::Create();
+}
+
+SocketsUdpGetInfoFunction::SocketsUdpGetInfoFunction() {}
+
+SocketsUdpGetInfoFunction::~SocketsUdpGetInfoFunction() {}
+
+bool SocketsUdpGetInfoFunction::Prepare() {
+  params_ = sockets_udp::GetInfo::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpGetInfoFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  linked_ptr<sockets_udp::SocketInfo> socket_info =
+      CreateSocketInfo(params_->socket_id, socket);
+  results_ = sockets_udp::GetInfo::Results::Create(*socket_info);
+}
+
+SocketsUdpGetSocketsFunction::SocketsUdpGetSocketsFunction() {}
+
+SocketsUdpGetSocketsFunction::~SocketsUdpGetSocketsFunction() {}
+
+bool SocketsUdpGetSocketsFunction::Prepare() {
+  return true;
+}
+
+void SocketsUdpGetSocketsFunction::Work() {
+  std::vector<linked_ptr<sockets_udp::SocketInfo> > socket_infos;
+  base::hash_set<int>* resource_ids = GetSocketIds();
+  if (resource_ids != NULL) {
+    for (base::hash_set<int>::iterator it = resource_ids->begin();
+             it != resource_ids->end(); ++it) {
+      int socket_id = *it;
+      ResumableUDPSocket* socket = GetUdpSocket(socket_id);
+      if (socket) {
+        socket_infos.push_back(CreateSocketInfo(socket_id, socket));
+      }
+    }
+  }
+  results_ = sockets_udp::GetSockets::Results::Create(socket_infos);
+}
+
+SocketsUdpJoinGroupFunction::SocketsUdpJoinGroupFunction() {}
+
+SocketsUdpJoinGroupFunction::~SocketsUdpJoinGroupFunction() {}
+
+bool SocketsUdpJoinGroupFunction::Prepare() {
+  params_ = sockets_udp::JoinGroup::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpJoinGroupFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  SocketPermission::CheckParam param(
+      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
+      kWildcardAddress,
+      kWildcardPort);
+
+  if (!PermissionsData::CheckAPIPermissionWithParam(
+          GetExtension(), APIPermission::kSocket, &param)) {
+    error_ = kPermissionError;
+    return;
+  }
+
+  int net_result = socket->JoinGroup(params_->address);
+  if (net_result != net::OK)
+    error_ = net::ErrorToString(net_result);
+  results_ = sockets_udp::JoinGroup::Results::Create(net_result);
+}
+
+SocketsUdpLeaveGroupFunction::SocketsUdpLeaveGroupFunction() {}
+
+SocketsUdpLeaveGroupFunction::~SocketsUdpLeaveGroupFunction() {}
+
+bool SocketsUdpLeaveGroupFunction::Prepare() {
+  params_ = api::sockets_udp::LeaveGroup::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpLeaveGroupFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  SocketPermission::CheckParam param(
+      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
+      kWildcardAddress,
+      kWildcardPort);
+  if (!PermissionsData::CheckAPIPermissionWithParam(GetExtension(),
+                                                    APIPermission::kSocket,
+                                                    &param)) {
+    error_ = kPermissionError;
+    return;
+  }
+
+  int net_result = socket->LeaveGroup(params_->address);
+  if (net_result != net::OK)
+    error_ = net::ErrorToString(net_result);
+  results_ = sockets_udp::LeaveGroup::Results::Create(net_result);
+}
+
+SocketsUdpSetMulticastTimeToLiveFunction::
+    SocketsUdpSetMulticastTimeToLiveFunction() {}
+
+SocketsUdpSetMulticastTimeToLiveFunction::
+    ~SocketsUdpSetMulticastTimeToLiveFunction() {}
+
+bool SocketsUdpSetMulticastTimeToLiveFunction::Prepare() {
+  params_ = api::sockets_udp::SetMulticastTimeToLive::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpSetMulticastTimeToLiveFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  int net_result = socket->SetMulticastTimeToLive(params_->ttl);
+  if (net_result != net::OK)
+    error_ = net::ErrorToString(net_result);
+  results_ = sockets_udp::SetMulticastTimeToLive::Results::Create(net_result);
+}
+
+SocketsUdpSetMulticastLoopbackModeFunction::
+    SocketsUdpSetMulticastLoopbackModeFunction() {}
+
+SocketsUdpSetMulticastLoopbackModeFunction::
+  ~SocketsUdpSetMulticastLoopbackModeFunction() {}
+
+bool SocketsUdpSetMulticastLoopbackModeFunction::Prepare() {
+  params_ = api::sockets_udp::SetMulticastLoopbackMode::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpSetMulticastLoopbackModeFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  int net_result = socket->SetMulticastLoopbackMode(params_->enabled);
+  if (net_result != net::OK)
+    error_ = net::ErrorToString(net_result);
+  results_ = sockets_udp::SetMulticastLoopbackMode::Results::Create(net_result);
+}
+
+SocketsUdpGetJoinedGroupsFunction::SocketsUdpGetJoinedGroupsFunction() {}
+
+SocketsUdpGetJoinedGroupsFunction::~SocketsUdpGetJoinedGroupsFunction() {}
+
+bool SocketsUdpGetJoinedGroupsFunction::Prepare() {
+  params_ = api::sockets_udp::GetJoinedGroups::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_.get());
+  return true;
+}
+
+void SocketsUdpGetJoinedGroupsFunction::Work() {
+  ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id);
+  if (!socket) {
+    error_ = kSocketNotFoundError;
+    return;
+  }
+
+  SocketPermission::CheckParam param(
+      SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
+      kWildcardAddress,
+      kWildcardPort);
+  if (!PermissionsData::CheckAPIPermissionWithParam(
+          GetExtension(),
+          APIPermission::kSocket,
+          &param)) {
+    error_ = kPermissionError;
+    return;
+  }
+
+  const std::vector<std::string>& groups = socket->GetJoinedGroups();
+  results_ = sockets_udp::GetJoinedGroups::Results::Create(groups);
+}
+
+}  // namespace api
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h
new file mode 100644
index 0000000..b971c4f
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h
@@ -0,0 +1,258 @@
+// Copyright 2013 The Chromium Authors. 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_SOCKETS_UDP_SOCKETS_UDP_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SOCKETS_UDP_SOCKETS_UDP_API_H_
+
+#include "chrome/browser/extensions/api/socket/socket_api.h"
+#include "chrome/common/extensions/api/sockets_udp.h"
+
+namespace extensions {
+class ResumableUDPSocket;
+}
+
+namespace extensions {
+namespace api {
+
+class UDPSocketAsyncApiFunction : public SocketAsyncApiFunction {
+ protected:
+  virtual ~UDPSocketAsyncApiFunction();
+
+  virtual scoped_ptr<SocketResourceManagerInterface>
+      CreateSocketResourceManager() OVERRIDE;
+
+  ResumableUDPSocket* GetUdpSocket(int socket_id);
+};
+
+class UDPSocketExtensionWithDnsLookupFunction
+    : public SocketExtensionWithDnsLookupFunction {
+ protected:
+  virtual ~UDPSocketExtensionWithDnsLookupFunction();
+
+  virtual scoped_ptr<SocketResourceManagerInterface>
+      CreateSocketResourceManager() OVERRIDE;
+
+  ResumableUDPSocket* GetUdpSocket(int socket_id);
+};
+
+class SocketsUdpCreateFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.create", SOCKETS_UDP_CREATE)
+
+  SocketsUdpCreateFunction();
+
+ protected:
+  virtual ~SocketsUdpCreateFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(SocketsUdpUnitTest, Create);
+  scoped_ptr<sockets_udp::Create::Params> params_;
+};
+
+class SocketsUdpUpdateFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.update", SOCKETS_UDP_UPDATE)
+
+  SocketsUdpUpdateFunction();
+
+ protected:
+  virtual ~SocketsUdpUpdateFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::Update::Params> params_;
+};
+
+class SocketsUdpBindFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.bind", SOCKETS_UDP_BIND)
+
+  SocketsUdpBindFunction();
+
+ protected:
+  virtual ~SocketsUdpBindFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::Bind::Params> params_;
+};
+
+class SocketsUdpSendFunction : public UDPSocketExtensionWithDnsLookupFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.send", SOCKETS_UDP_SEND)
+
+  SocketsUdpSendFunction();
+
+ protected:
+  virtual ~SocketsUdpSendFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  virtual void AsyncWorkStart() OVERRIDE;
+  void OnCompleted(int net_result);
+  void SetSendResult(int net_result, int bytes_written);
+
+  // SocketExtensionWithDnsLookupFunction:
+  virtual void AfterDnsLookup(int lookup_result) OVERRIDE;
+
+ private:
+  void StartSendTo();
+
+  scoped_ptr<sockets_udp::Send::Params> params_;
+  scoped_refptr<net::IOBuffer> io_buffer_;
+  size_t io_buffer_size_;
+};
+
+class SocketsUdpCloseFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.close", SOCKETS_UDP_CLOSE)
+
+  SocketsUdpCloseFunction();
+
+ protected:
+  virtual ~SocketsUdpCloseFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::Close::Params> params_;
+};
+
+class SocketsUdpGetInfoFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.getInfo", SOCKETS_UDP_GETINFO)
+
+  SocketsUdpGetInfoFunction();
+
+ protected:
+  virtual ~SocketsUdpGetInfoFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::GetInfo::Params> params_;
+};
+
+class SocketsUdpGetSocketsFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.getSockets", SOCKETS_UDP_GETSOCKETS)
+
+  SocketsUdpGetSocketsFunction();
+
+ protected:
+  virtual ~SocketsUdpGetSocketsFunction();
+
+  // AsyncApiFunction:
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+};
+
+class SocketsUdpJoinGroupFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.joinGroup", SOCKETS_UDP_JOINGROUP)
+
+  SocketsUdpJoinGroupFunction();
+
+ protected:
+  virtual ~SocketsUdpJoinGroupFunction();
+
+  // AsyncApiFunction
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::JoinGroup::Params> params_;
+};
+
+class SocketsUdpLeaveGroupFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.leaveGroup", SOCKETS_UDP_LEAVEGROUP)
+
+  SocketsUdpLeaveGroupFunction();
+
+ protected:
+  virtual ~SocketsUdpLeaveGroupFunction();
+
+  // AsyncApiFunction
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::LeaveGroup::Params> params_;
+};
+
+class SocketsUdpSetMulticastTimeToLiveFunction
+    : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.setMulticastTimeToLive",
+                             SOCKETS_UDP_SETMULTICASTTIMETOLIVE)
+
+  SocketsUdpSetMulticastTimeToLiveFunction();
+
+ protected:
+  virtual ~SocketsUdpSetMulticastTimeToLiveFunction();
+
+  // AsyncApiFunction
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::SetMulticastTimeToLive::Params> params_;
+};
+
+class SocketsUdpSetMulticastLoopbackModeFunction
+    : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.setMulticastLoopbackMode",
+                             SOCKETS_UDP_SETMULTICASTLOOPBACKMODE)
+
+  SocketsUdpSetMulticastLoopbackModeFunction();
+
+ protected:
+  virtual ~SocketsUdpSetMulticastLoopbackModeFunction();
+
+  // AsyncApiFunction
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::SetMulticastLoopbackMode::Params> params_;
+};
+
+class SocketsUdpGetJoinedGroupsFunction : public UDPSocketAsyncApiFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("sockets.udp.getJoinedGroups",
+                             SOCKETS_UDP_GETJOINEDGROUPS)
+
+  SocketsUdpGetJoinedGroupsFunction();
+
+ protected:
+  virtual ~SocketsUdpGetJoinedGroupsFunction();
+
+  // AsyncApiFunction
+  virtual bool Prepare() OVERRIDE;
+  virtual void Work() OVERRIDE;
+
+ private:
+  scoped_ptr<sockets_udp::GetJoinedGroups::Params> params_;
+};
+
+}  // namespace api
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_SOCKETS_UDP_SOCKETS_UDP_API_H_
diff --git a/chrome/browser/extensions/api/sockets_udp/sockets_udp_api_unittest.cc b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api_unittest.cc
new file mode 100644
index 0000000..08d3c83
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_udp/sockets_udp_api_unittest.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/values.h"
+#include "chrome/browser/browser_process_impl.h"
+#include "chrome/browser/extensions/api/api_function.h"
+#include "chrome/browser/extensions/api/api_resource_manager.h"
+#include "chrome/browser/extensions/api/socket/socket.h"
+#include "chrome/browser/extensions/api/socket/udp_socket.h"
+#include "chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace utils = extension_function_test_utils;
+
+namespace extensions {
+namespace api {
+
+BrowserContextKeyedService* ApiResourceManagerTestFactory(
+    content::BrowserContext* profile) {
+  content::BrowserThread::ID id;
+  CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
+  return ApiResourceManager<ResumableUDPSocket>::
+      CreateApiResourceManagerForTest(static_cast<Profile*>(profile), id);
+}
+
+class SocketsUdpUnitTest : public BrowserWithTestWindowTest {
+ public:
+  virtual void SetUp() {
+    BrowserWithTestWindowTest::SetUp();
+
+    ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance()->
+        SetTestingFactoryAndUse(browser()->profile(),
+                                ApiResourceManagerTestFactory);
+
+    extension_ = utils::CreateEmptyExtensionWithLocation(
+        extensions::Manifest::UNPACKED);
+  }
+
+  base::Value* RunFunctionWithExtension(
+      UIThreadExtensionFunction* function, const std::string& args) {
+    scoped_refptr<UIThreadExtensionFunction> delete_function(function);
+    function->set_extension(extension_.get());
+    return utils::RunFunctionAndReturnSingleResult(function, args, browser());
+  }
+
+  base::DictionaryValue* RunFunctionAndReturnDict(
+      UIThreadExtensionFunction* function, const std::string& args) {
+    base::Value* result = RunFunctionWithExtension(function, args);
+    return result ? utils::ToDictionary(result) : NULL;
+  }
+
+ protected:
+  scoped_refptr<extensions::Extension> extension_;
+};
+
+TEST_F(SocketsUdpUnitTest, Create) {
+  // Get BrowserThread
+  content::BrowserThread::ID id;
+  CHECK(content::BrowserThread::GetCurrentThreadIdentifier(&id));
+
+  // Create SocketCreateFunction and put it on BrowserThread
+  SocketsUdpCreateFunction *function = new SocketsUdpCreateFunction();
+  function->set_work_thread_id(id);
+
+  // Run tests
+  scoped_ptr<base::DictionaryValue> result(RunFunctionAndReturnDict(
+      function, "[{\"resumable\": true, \"name\": \"foo\"}]"));
+  ASSERT_TRUE(result.get());
+}
+
+}  // namespace api
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/sockets_udp/sockets_udp_apitest.cc b/chrome/browser/extensions/api/sockets_udp/sockets_udp_apitest.cc
new file mode 100644
index 0000000..943bbf1
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_udp/sockets_udp_apitest.cc
@@ -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.
+
+#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/api/dns/host_resolver_wrapper.h"
+#include "chrome/browser/extensions/api/dns/mock_host_resolver_creator.h"
+#include "chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
+
+using extensions::Extension;
+
+namespace utils = extension_function_test_utils;
+
+namespace {
+
+// TODO(jschuh): Hanging plugin tests. crbug.com/244653
+#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
+#define MAYBE(x) DISABLED_##x
+#else
+#define MAYBE(x) x
+#endif
+
+const std::string kHostname = "127.0.0.1";
+const int kPort = 8888;
+
+class SocketsUdpApiTest : public ExtensionApiTest {
+ public:
+  SocketsUdpApiTest() : resolver_event_(true, false),
+                        resolver_creator_(
+                            new extensions::MockHostResolverCreator()) {
+  }
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    extensions::HostResolverWrapper::GetInstance()->SetHostResolverForTesting(
+        resolver_creator_->CreateMockHostResolver());
+  }
+
+  virtual void CleanUpOnMainThread() OVERRIDE {
+    extensions::HostResolverWrapper::GetInstance()->
+        SetHostResolverForTesting(NULL);
+    resolver_creator_->DeleteMockHostResolver();
+  }
+
+ private:
+  base::WaitableEvent resolver_event_;
+
+  // The MockHostResolver asserts that it's used on the same thread on which
+  // it's created, which is actually a stronger rule than its real counterpart.
+  // But that's fine; it's good practice.
+  scoped_refptr<extensions::MockHostResolverCreator> resolver_creator_;
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(SocketsUdpApiTest, SocketsUdpCreateGood) {
+  scoped_refptr<extensions::api::SocketsUdpCreateFunction>
+      socket_create_function(new extensions::api::SocketsUdpCreateFunction());
+  scoped_refptr<Extension> empty_extension(utils::CreateEmptyExtension());
+
+  socket_create_function->set_extension(empty_extension.get());
+  socket_create_function->set_has_callback(true);
+
+  scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
+      socket_create_function.get(), "[]", browser(), utils::NONE));
+  ASSERT_EQ(base::Value::TYPE_DICTIONARY, result->GetType());
+  base::DictionaryValue *value =
+      static_cast<base::DictionaryValue*>(result.get());
+  int socketId = -1;
+  EXPECT_TRUE(value->GetInteger("socketId", &socketId));
+  EXPECT_TRUE(socketId > 0);
+}
+
+IN_PROC_BROWSER_TEST_F(SocketsUdpApiTest, SocketsUdpExtension) {
+  scoped_ptr<net::SpawnedTestServer> test_server(
+      new net::SpawnedTestServer(
+          net::SpawnedTestServer::TYPE_UDP_ECHO,
+          net::SpawnedTestServer::kLocalhost,
+          base::FilePath(FILE_PATH_LITERAL("net/data"))));
+  EXPECT_TRUE(test_server->Start());
+
+  net::HostPortPair host_port_pair = test_server->host_port_pair();
+  int port = host_port_pair.port();
+  ASSERT_TRUE(port > 0);
+
+  // Test that sendTo() is properly resolving hostnames.
+  host_port_pair.set_host("LOCALhost");
+
+  ResultCatcher catcher;
+  catcher.RestrictToProfile(browser()->profile());
+
+  ExtensionTestMessageListener listener("info_please", true);
+
+  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("sockets_udp/api")));
+  EXPECT_TRUE(listener.WaitUntilSatisfied());
+  listener.Reply(
+      base::StringPrintf("udp:%s:%d", host_port_pair.host().c_str(), port));
+
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+IN_PROC_BROWSER_TEST_F(SocketsUdpApiTest, SocketsUdpMulticast) {
+  ResultCatcher catcher;
+  catcher.RestrictToProfile(browser()->profile());
+  ExtensionTestMessageListener listener("info_please", true);
+  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("sockets_udp/api")));
+  EXPECT_TRUE(listener.WaitUntilSatisfied());
+  listener.Reply(
+      base::StringPrintf("multicast:%s:%d", kHostname.c_str(), kPort));
+
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
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
new file mode 100644
index 0000000..2331417
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.cc
@@ -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.
+
+#include "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h"
+
+#include "chrome/browser/extensions/api/socket/udp_socket.h"
+#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "net/base/net_errors.h"
+
+namespace extensions {
+namespace api {
+
+static base::LazyInstance<ProfileKeyedAPIFactory<UDPSocketEventDispatcher> >
+g_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+ProfileKeyedAPIFactory<UDPSocketEventDispatcher>*
+    UDPSocketEventDispatcher::GetFactoryInstance() {
+  return &g_factory.Get();
+}
+
+// static
+UDPSocketEventDispatcher* UDPSocketEventDispatcher::Get(Profile* profile) {
+  return ProfileKeyedAPIFactory<UDPSocketEventDispatcher>::GetForProfile(
+      profile);
+}
+
+UDPSocketEventDispatcher::UDPSocketEventDispatcher(Profile* profile)
+    : thread_id_(Socket::kThreadId),
+      profile_(profile) {
+}
+
+UDPSocketEventDispatcher::~UDPSocketEventDispatcher() {
+}
+
+ResumableUDPSocket* UDPSocketEventDispatcher::GetUdpSocket(
+    const std::string& extension_id,
+    int socket_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+
+  ApiResourceManager<ResumableUDPSocket>* manager =
+    ApiResourceManager<ResumableUDPSocket>::Get(profile_);
+  DCHECK(manager) << "There is no socket manager. "
+    "If this assertion is failing during a test, then it is likely that "
+    "TestExtensionSystem is failing to provide an instance of "
+    "ApiResourceManager<ResumableUDPSocket>.";
+
+  return manager->Get(extension_id, socket_id);
+}
+
+void UDPSocketEventDispatcher::OnSocketBind(const std::string& extension_id,
+                                         int socket_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+  StartReceive(extension_id, socket_id);
+}
+
+void UDPSocketEventDispatcher::StartReceive(const std::string& extension_id,
+                                         int socket_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+  ResumableUDPSocket* socket = GetUdpSocket(extension_id, socket_id);
+  if (socket == NULL) {
+    // This can happen if the socket is closed while our callback is active.
+    return;
+  }
+  DCHECK(extension_id == socket->owner_extension_id())
+    << "Socket has wrong owner.";
+
+  int buffer_size = (socket->buffer_size() <= 0 ? 4096 : socket->buffer_size());
+  socket->RecvFrom(buffer_size,
+                   base::Bind(&UDPSocketEventDispatcher::ReceiveCallback,
+                              AsWeakPtr(),
+                              extension_id,
+                              socket_id));
+}
+
+void UDPSocketEventDispatcher::ReceiveCallback(
+    const std::string& extension_id,
+    const int socket_id,
+    int bytes_read,
+    scoped_refptr<net::IOBuffer> io_buffer,
+    const std::string& address,
+    int port) {
+  DCHECK(content::BrowserThread::CurrentlyOn(thread_id_));
+
+  // Note: if "bytes_read" < 0, there was a network error, and "bytes_read" is
+  // a value from "net::ERR_".
+
+  if (bytes_read >= 0) {
+    // Dispatch event.
+    sockets_udp::ReceiveInfo receive_info;
+    receive_info.socket_id = socket_id;
+    receive_info.data = std::string(io_buffer->data(), bytes_read);
+    receive_info.remote_address = address;
+    receive_info.remote_port = port;
+    scoped_ptr<base::ListValue> args =
+        sockets_udp::OnReceive::Create(receive_info);
+    scoped_ptr<Event> event(
+      new Event(sockets_udp::OnReceive::kEventName, args.Pass()));
+    ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
+        extension_id, event.Pass());
+
+    // Post a task to delay the read until the socket is available, as
+    // calling StartReceive at this point would error with ERR_IO_PENDING.
+    content::BrowserThread::PostTask(thread_id_, FROM_HERE,
+        base::Bind(&UDPSocketEventDispatcher::StartReceive,
+                    AsWeakPtr(), extension_id, socket_id));
+  } else {
+    // Dispatch event but don't start another read to avoid infinite read if
+    // we have a persistent network error.
+    sockets_udp::ReceiveErrorInfo receive_error_info;
+    receive_error_info.socket_id = socket_id;
+    receive_error_info.result = bytes_read;
+    scoped_ptr<base::ListValue> args =
+        sockets_udp::OnReceiveError::Create(receive_error_info);
+    scoped_ptr<Event> event(
+      new Event(sockets_udp::OnReceiveError::kEventName, args.Pass()));
+    ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
+        extension_id, event.Pass());
+  }
+}
+
+}  // namespace api
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h b/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h
new file mode 100644
index 0000000..c5672a9
--- /dev/null
+++ b/chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.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 CHROME_BROWSER_EXTENSIONS_API_SOCKETS_UDP_UDP_SOCKET_EVENT_DISPATCHER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_SOCKETS_UDP_UDP_SOCKET_EVENT_DISPATCHER_H_
+
+#include "chrome/browser/extensions/api/sockets_udp/sockets_udp_api.h"
+
+namespace extensions {
+class ResumableUDPSocket;
+}
+
+namespace extensions {
+namespace api {
+
+// Dispatch events related to "sockets.udp" sockets from callback on native
+// socket instances. There is one instance per profile.
+class UDPSocketEventDispatcher
+    : public ProfileKeyedAPI,
+      public base::SupportsWeakPtr<UDPSocketEventDispatcher> {
+ public:
+  explicit UDPSocketEventDispatcher(Profile* profile);
+  virtual ~UDPSocketEventDispatcher();
+
+  // Socket is active, start receving from it.
+  void OnSocketBind(const std::string& extension_id, int socket_id);
+
+  // ProfileKeyedAPI implementation.
+  static ProfileKeyedAPIFactory<UDPSocketEventDispatcher>* GetFactoryInstance();
+
+  // Convenience method to get the SocketEventDispatcher for a profile.
+  static UDPSocketEventDispatcher* Get(Profile* profile);
+
+ private:
+  friend class ProfileKeyedAPIFactory<UDPSocketEventDispatcher>;
+
+  ResumableUDPSocket* GetUdpSocket(const std::string& extension_id,
+                                   int socket_id);
+
+  // Start a receive and register a callback.
+  void StartReceive(const std::string& extension_id, int socket_id);
+
+  // Called when socket receive data.
+  void ReceiveCallback(const std::string& extension_id,
+                       const int socket_id,
+                       int bytes_read,
+                       scoped_refptr<net::IOBuffer> io_buffer,
+                       const std::string& address,
+                       int port);
+
+  // ProfileKeyedAPI implementation.
+  static const char* service_name() {
+    return "UDPSocketEventDispatcher";
+  }
+  static const bool kServiceHasOwnInstanceInIncognito = true;
+
+  // Usually IO thread (except for unit testing).
+  content::BrowserThread::ID  thread_id_;
+  Profile* const profile_;
+};
+
+}  // namespace api
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_SOCKETS_UDP_UDP_SOCKET_EVENT_DISPATCHER_H_
diff --git a/chrome/browser/extensions/api/spellcheck/spellcheck_api.cc b/chrome/browser/extensions/api/spellcheck/spellcheck_api.cc
index 8c43e53..2c779dc 100644
--- a/chrome/browser/extensions/api/spellcheck/spellcheck_api.cc
+++ b/chrome/browser/extensions/api/spellcheck/spellcheck_api.cc
@@ -15,7 +15,6 @@
 
 namespace extensions {
 
-namespace keys = extension_manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
@@ -24,7 +23,7 @@
     const Extension* extension) {
   SpellcheckDictionaryInfo *spellcheck_info =
       static_cast<SpellcheckDictionaryInfo*>(
-          extension->GetManifestData(keys::kSpellcheck));
+          extension->GetManifestData(manifest_keys::kSpellcheck));
   return spellcheck_info;
 }
 
diff --git a/chrome/browser/extensions/api/storage/OWNERS b/chrome/browser/extensions/api/storage/OWNERS
new file mode 100644
index 0000000..d3c3af2
--- /dev/null
+++ b/chrome/browser/extensions/api/storage/OWNERS
@@ -0,0 +1 @@
+kalman@chromium.org
diff --git a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
index 6184cfc..13a5fde 100644
--- a/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
+++ b/chrome/browser/extensions/api/storage/managed_value_store_cache.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/storage/policy_value_store.h"
 #include "chrome/browser/extensions/api/storage/settings_storage_factory.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -23,22 +22,25 @@
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/value_store/value_store_change.h"
+#include "chrome/common/extensions/api/storage.h"
 #include "chrome/common/extensions/api/storage/storage_schema_manifest_handler.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension_set.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
-#include "chrome/common/policy/policy_schema.h"
+#include "components/policy/core/common/policy_schema.h"
 #include "content/public/browser/browser_thread.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/manifest.h"
+#include "extensions/common/manifest_constants.h"
 
 using content::BrowserThread;
 
 namespace extensions {
 
+namespace storage = api::storage;
+
 namespace {
 
 const char kLoadSchemasBackgroundTaskTokenName[] =
@@ -104,8 +106,7 @@
       ExtensionSystem::Get(profile_)->extension_service()->extensions();
   scoped_ptr<ExtensionSet> managed_extensions(new ExtensionSet());
   for (ExtensionSet::const_iterator it = set->begin(); it != set->end(); ++it) {
-    if ((*it)->manifest()->HasPath(
-            extension_manifest_keys::kStorageManagedSchema)) {
+    if ((*it)->manifest()->HasPath(manifest_keys::kStorageManagedSchema)) {
       managed_extensions->Insert(*it);
     }
 
@@ -135,7 +136,7 @@
        it != extensions->end(); ++it) {
     std::string schema_file;
     if (!(*it)->manifest()->GetString(
-            extension_manifest_keys::kStorageManagedSchema, &schema_file)) {
+            manifest_keys::kStorageManagedSchema, &schema_file)) {
       // TODO(joaodasilva): Remove this for M30. http://crbug.com/240704
       if ((*it)->HasAPIPermission(APIPermission::kStorage)) {
         descriptor->RegisterComponent((*it)->id(),
@@ -181,7 +182,7 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   // |event_router_| can be NULL on unit_tests.
   if (event_router_)
-    event_router_->RegisterObserver(this, event_names::kOnSettingsChanged);
+    event_router_->RegisterObserver(this, storage::OnChanged::kEventName);
 
   GetPolicyService()->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this);
 
@@ -279,7 +280,7 @@
 void ManagedValueStoreCache::OnListenerAdded(
     const EventListenerInfo& details) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_EQ(std::string(event_names::kOnSettingsChanged), details.event_name);
+  DCHECK_EQ(std::string(storage::OnChanged::kEventName), details.event_name);
   // This is invoked on several occasions:
   //
   // 1. when an extension first registers to observe storage.onChanged; in this
diff --git a/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc b/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc
index 56f473e..e554b32 100644
--- a/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc
+++ b/chrome/browser/extensions/api/storage/policy_value_store_unittest.cc
@@ -124,7 +124,7 @@
                policy::POLICY_SCOPE_USER, expected.DeepCopy(), NULL);
   policies.Set("may", policy::POLICY_LEVEL_RECOMMENDED,
                policy::POLICY_SCOPE_USER,
-               base::Value::CreateIntegerValue(456), NULL);
+               new base::FundamentalValue(456), NULL);
   store_->SetCurrentPolicy(policies, false);
   ValueStore::ReadResult result = store_->Get();
   ASSERT_FALSE(result->HasError());
@@ -155,7 +155,7 @@
 TEST_F(PolicyValueStoreTest, NotifyOnChanges) {
   policy::PolicyMap policies;
   policies.Set("aaa", policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
-               base::Value::CreateStringValue("111"), NULL);
+               new base::StringValue("111"), NULL);
   EXPECT_CALL(observer_, OnSettingsChanged(_, _, _)).Times(0);
   // No notification when setting the initial policy.
   store_->SetCurrentPolicy(policies, false);
@@ -164,9 +164,9 @@
 
   // And no notifications on changes when not asked for.
   policies.Set("aaa", policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
-               base::Value::CreateStringValue("222"), NULL);
+               new base::StringValue("222"), NULL);
   policies.Set("bbb", policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
-               base::Value::CreateStringValue("223"), NULL);
+               new base::StringValue("223"), NULL);
   EXPECT_CALL(observer_, OnSettingsChanged(_, _, _)).Times(0);
   store_->SetCurrentPolicy(policies, false);
   loop_.RunUntilIdle();
diff --git a/chrome/browser/extensions/api/storage/settings_frontend.cc b/chrome/browser/extensions/api/storage/settings_frontend.cc
index a14ed69..86f4262 100644
--- a/chrome/browser/extensions/api/storage/settings_frontend.cc
+++ b/chrome/browser/extensions/api/storage/settings_frontend.cc
@@ -29,6 +29,8 @@
 
 namespace extensions {
 
+namespace storage = api::storage;
+
 namespace {
 
 // Settings change Observer which forwards changes on to the extension
@@ -46,10 +48,10 @@
     // string-based event payloads is removed. http://crbug.com/136045
     scoped_ptr<base::ListValue> args(new base::ListValue());
     args->Append(base::JSONReader::Read(change_json));
-    args->Append(Value::CreateStringValue(settings_namespace::ToString(
+    args->Append(new base::StringValue(settings_namespace::ToString(
         settings_namespace)));
     scoped_ptr<Event> event(new Event(
-        event_names::kOnSettingsChanged, args.Pass()));
+        storage::OnChanged::kEventName, args.Pass()));
     ExtensionSystem::Get(profile_)->event_router()->
         DispatchEventToExtension(extension_id, event.Pass());
   }
diff --git a/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc b/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc
index 55bbaeb..9eb8e45 100644
--- a/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_frontend_unittest.cc
@@ -35,7 +35,7 @@
   for (int i = 0; i < 1024; ++i) {
     kilobyte_string += "a";
   }
-  return scoped_ptr<Value>(Value::CreateStringValue(kilobyte_string));
+  return scoped_ptr<Value>(new base::StringValue(kilobyte_string));
 }
 
 // Creates a megabyte of data.
@@ -47,7 +47,7 @@
   return scoped_ptr<Value>(megabyte);
 }
 
-}
+}  // namespace
 
 class ExtensionSettingsFrontendTest : public testing::Test {
  public:
diff --git a/chrome/browser/extensions/api/storage/settings_quota_unittest.cc b/chrome/browser/extensions/api/storage/settings_quota_unittest.cc
index 0e4ea79..d64c42c 100644
--- a/chrome/browser/extensions/api/storage/settings_quota_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_quota_unittest.cc
@@ -25,12 +25,12 @@
 class ExtensionSettingsQuotaTest : public testing::Test {
  public:
   ExtensionSettingsQuotaTest()
-      : byte_value_1_(Value::CreateIntegerValue(1)),
-        byte_value_16_(Value::CreateStringValue("sixteen bytes.")),
+      : byte_value_1_(new base::FundamentalValue(1)),
+        byte_value_16_(new base::StringValue("sixteen bytes.")),
         byte_value_256_(new ListValue()),
         delegate_(new TestingValueStore()) {
     for (int i = 1; i < 89; ++i) {
-      byte_value_256_->Append(Value::CreateIntegerValue(i));
+      byte_value_256_->Append(new base::FundamentalValue(i));
     }
     ValidateByteValues();
   }
diff --git a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
index 9d55bdb..0480062 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
@@ -17,8 +17,8 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/test_extension_service.h"
 #include "chrome/browser/value_store/testing_value_store.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest.h"
 #include "sync/api/sync_change_processor.h"
 #include "sync/api/sync_error_factory.h"
 #include "sync/api/sync_error_factory_mock.h"
@@ -307,7 +307,7 @@
 
   StringValue value1("fooValue");
   ListValue value2;
-  value2.Append(StringValue::CreateStringValue("barValue"));
+  value2.Append(new base::StringValue("barValue"));
 
   ValueStore* storage1 = AddExtensionAndGetStorage("s1", type);
   ValueStore* storage2 = AddExtensionAndGetStorage("s2", type);
@@ -357,7 +357,7 @@
 
   StringValue value1("fooValue");
   ListValue value2;
-  value2.Append(StringValue::CreateStringValue("barValue"));
+  value2.Append(new base::StringValue("barValue"));
 
   ValueStore* storage1 = AddExtensionAndGetStorage("s1", type);
   ValueStore* storage2 = AddExtensionAndGetStorage("s2", type);
@@ -389,7 +389,7 @@
 
   StringValue value1("fooValue");
   ListValue value2;
-  value2.Append(StringValue::CreateStringValue("barValue"));
+  value2.Append(new base::StringValue("barValue"));
 
   // Maintain dictionaries mirrored to the expected values of the settings in
   // each storage area.
@@ -429,7 +429,7 @@
 
   StringValue value1("fooValue");
   ListValue value2;
-  value2.Append(StringValue::CreateStringValue("barValue"));
+  value2.Append(new base::StringValue("barValue"));
 
   // Maintain dictionaries mirrored to the expected values of the settings in
   // each storage area.
@@ -502,7 +502,7 @@
 
   StringValue value1("fooValue");
   ListValue value2;
-  value2.Append(StringValue::CreateStringValue("barValue"));
+  value2.Append(new base::StringValue("barValue"));
 
   // Make storage1/2 initialised from local data, storage3/4 initialised from
   // sync.
@@ -641,7 +641,7 @@
 TEST_F(ExtensionSettingsSyncTest, ExtensionAndAppSettingsSyncSeparately) {
   StringValue value1("fooValue");
   ListValue value2;
-  value2.Append(StringValue::CreateStringValue("barValue"));
+  value2.Append(new base::StringValue("barValue"));
 
   // storage1 is an extension, storage2 is an app.
   ValueStore* storage1 = AddExtensionAndGetStorage(
@@ -1390,7 +1390,7 @@
 
   {
     syncer::SyncDataList sync_data_list;
-    scoped_ptr<Value> string_value(Value::CreateStringValue("value"));
+    scoped_ptr<Value> string_value(new base::StringValue("value"));
     sync_data_list.push_back(settings_sync_util::CreateData(
         "ext", "key.with.dot", *string_value, model_type));
 
@@ -1410,13 +1410,13 @@
     DictionaryValue expected_data;
     expected_data.SetWithoutPathExpansion(
         "key.with.dot",
-        Value::CreateStringValue("value"));
+        new base::StringValue("value"));
     EXPECT_TRUE(Value::Equals(&expected_data, data->settings().get()));
   }
 
   // Test dots in keys going to sync.
   {
-    scoped_ptr<Value> string_value(Value::CreateStringValue("spot"));
+    scoped_ptr<Value> string_value(new base::StringValue("spot"));
     storage->Set(DEFAULTS, "key.with.spot", *string_value);
 
     ASSERT_EQ(1u, sync_processor_->changes().size());
diff --git a/chrome/browser/extensions/api/storage/settings_test_util.cc b/chrome/browser/extensions/api/storage/settings_test_util.cc
index 07b635e..82c1845 100644
--- a/chrome/browser/extensions/api/storage/settings_test_util.cc
+++ b/chrome/browser/extensions/api/storage/settings_test_util.cc
@@ -68,7 +68,7 @@
   scoped_ptr<base::ListValue> permissions(new base::ListValue());
   for (std::set<std::string>::const_iterator it = permissions_set.begin();
       it != permissions_set.end(); ++it) {
-    permissions->Append(Value::CreateStringValue(*it));
+    permissions->Append(new base::StringValue(*it));
   }
   manifest.Set("permissions", permissions.release());
 
diff --git a/chrome/browser/extensions/api/storage/storage_api.cc b/chrome/browser/extensions/api/storage/storage_api.cc
index d86b763..f9c6831 100644
--- a/chrome/browser/extensions/api/storage/storage_api.cc
+++ b/chrome/browser/extensions/api/storage/storage_api.cc
@@ -235,7 +235,7 @@
       return false;
   }
 
-  SetResult(base::Value::CreateIntegerValue(bytes_in_use));
+  SetResult(new base::FundamentalValue(static_cast<int>(bytes_in_use)));
   return true;
 }
 
diff --git a/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc b/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc
index f5a8ae7..3b93044 100644
--- a/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc
+++ b/chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.cc
@@ -65,9 +65,10 @@
   scoped_ptr<base::ListValue> params(
       api::sync_file_system::OnServiceStatusChanged::Create(service_info));
 
-  BroadcastOrDispatchEvent(app_origin,
-                           event_names::kOnServiceStatusChanged,
-                           params.Pass());
+  BroadcastOrDispatchEvent(
+      app_origin,
+      api::sync_file_system::OnServiceStatusChanged::kEventName,
+      params.Pass());
 }
 
 void ExtensionSyncEventObserver::OnFileSynced(
@@ -92,9 +93,10 @@
   params->AppendString(api::sync_file_system::ToString(action_enum));
   params->AppendString(api::sync_file_system::ToString(direction_enum));
 
-  BroadcastOrDispatchEvent(url.origin(),
-                           event_names::kOnFileStatusChanged,
-                           params.Pass());
+  BroadcastOrDispatchEvent(
+      url.origin(),
+      api::sync_file_system::OnFileStatusChanged::kEventName,
+      params.Pass());
 }
 
 void ExtensionSyncEventObserver::BroadcastOrDispatchEvent(
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 f318596..a400971 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
@@ -99,12 +99,12 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (error != base::PLATFORM_FILE_OK) {
     error_ = base::StringPrintf(kFileError, static_cast<int>(error));
-    SetResult(base::Value::CreateBooleanValue(false));
+    SetResult(new base::FundamentalValue(false));
     SendResponse(false);
     return;
   }
 
-  SetResult(base::Value::CreateBooleanValue(true));
+  SetResult(new base::FundamentalValue(true));
   SendResponse(true);
 }
 
@@ -380,7 +380,7 @@
   api::sync_file_system::ConflictResolutionPolicy policy =
       ConflictResolutionPolicyToExtensionEnum(
           service->GetConflictResolutionPolicy());
-  SetResult(Value::CreateStringValue(
+  SetResult(new base::StringValue(
           api::sync_file_system::ToString(policy)));
   return true;
 }
diff --git a/chrome/browser/extensions/api/system_indicator/OWNERS b/chrome/browser/extensions/api/system_indicator/OWNERS
new file mode 100644
index 0000000..6f1cc7b
--- /dev/null
+++ b/chrome/browser/extensions/api/system_indicator/OWNERS
@@ -0,0 +1 @@
+dewittj@chromium.org
diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc
index a7601f0..a8b344d 100644
--- a/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc
+++ b/chrome/browser/extensions/api/system_indicator/system_indicator_manager.cc
@@ -7,7 +7,6 @@
 #include "base/memory/linked_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -24,6 +23,8 @@
 
 namespace extensions {
 
+namespace system_indicator = api::system_indicator;
+
 // Observes clicks on a given status icon and forwards the event to the
 // appropriate extension.  Handles icon updates, and responsible for creating
 // and removing the icon from the notification area during construction and
@@ -86,7 +87,7 @@
   EventRouter* event_router =
       ExtensionSystem::Get(profile_)->event_router();
   scoped_ptr<Event> event(new Event(
-      event_names::kOnSystemIndicatorClicked,
+      system_indicator::OnClicked::kEventName,
       params.Pass(),
       profile_));
   event_router->DispatchEventToExtension(
diff --git a/chrome/browser/extensions/api/system_info/system_info_api.cc b/chrome/browser/extensions/api/system_info/system_info_api.cc
index 546c878..fd0dcaf 100644
--- a/chrome/browser/extensions/api/system_info/system_info_api.cc
+++ b/chrome/browser/extensions/api/system_info/system_info_api.cc
@@ -14,11 +14,11 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/system_storage/storage_info_provider.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/storage_monitor/removable_storage_observer.h"
 #include "chrome/browser/storage_monitor/storage_info.h"
 #include "chrome/browser/storage_monitor/storage_monitor.h"
+#include "chrome/common/extensions/api/system_display.h"
 #include "chrome/common/extensions/api/system_storage.h"
 #include "ui/gfx/display_observer.h"
 
@@ -32,10 +32,13 @@
 using api::system_storage::StorageUnitInfo;
 using content::BrowserThread;
 
+namespace system_display = api::system_display;
+namespace system_storage = api::system_storage;
+
 namespace {
 
 bool IsDisplayChangedEvent(const std::string& event_name) {
-  return event_name == event_names::kOnDisplayChanged;
+  return event_name == system_display::OnDisplayChanged::kEventName;
 }
 
 // Event router for systemInfo API. It is a singleton instance shared by
@@ -136,7 +139,7 @@
   systeminfo::BuildStorageUnitInfo(info, &unit);
   scoped_ptr<base::ListValue> args(new base::ListValue);
   args->Append(unit.ToValue().release());
-  DispatchEvent(event_names::kOnStorageAttached, args.Pass());
+  DispatchEvent(system_storage::OnAttached::kEventName, args.Pass());
 }
 
 void SystemInfoEventRouter::OnRemovableStorageDetached(
@@ -145,7 +148,7 @@
   args->Append(new base::StringValue(chrome::StorageMonitor::GetInstance()->
                    GetTransientIdForDeviceId(info.device_id())));
 
-  DispatchEvent(event_names::kOnStorageDetached, args.Pass());
+  DispatchEvent(system_storage::OnDetached::kEventName, args.Pass());
 }
 
 void SystemInfoEventRouter::OnDisplayBoundsChanged(
@@ -163,7 +166,7 @@
 
 void SystemInfoEventRouter::OnDisplayChanged() {
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  DispatchEvent(event_names::kOnDisplayChanged, args.Pass());
+  DispatchEvent(system_display::OnDisplayChanged::kEventName, args.Pass());
 }
 
 void SystemInfoEventRouter::DispatchEvent(const std::string& event_name,
@@ -184,9 +187,11 @@
 
 SystemInfoAPI::SystemInfoAPI(Profile* profile) : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnStorageAttached);
+      this, system_storage::OnAttached::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnStorageDetached);
+      this, system_storage::OnDetached::kEventName);
+  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
+      this, system_display::OnDisplayChanged::kEventName);
 }
 
 SystemInfoAPI::~SystemInfoAPI() {
diff --git a/chrome/browser/extensions/api/system_private/OWNERS b/chrome/browser/extensions/api/system_private/OWNERS
new file mode 100644
index 0000000..c32e059
--- /dev/null
+++ b/chrome/browser/extensions/api/system_private/OWNERS
@@ -0,0 +1 @@
+dmazzoni@chromium.org
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 55296e3..ec42006 100644
--- a/chrome/browser/extensions/api/system_private/system_private_api.cc
+++ b/chrome/browser/extensions/api/system_private/system_private_api.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/system_private.h"
 #include "chrome/common/pref_names.h"
 
 #if defined(OS_CHROMEOS)
@@ -41,12 +42,6 @@
 const char kUpdatingState[] = "Updating";
 const char kNeedRestartState[] = "NeedRestart";
 
-// Event names.
-const char kOnBrightnessChanged[] = "systemPrivate.onBrightnessChanged";
-const char kOnVolumeChanged[] = "systemPrivate.onVolumeChanged";
-const char kOnScreenUnlocked[] = "systemPrivate.onScreenUnlocked";
-const char kOnWokeUp[] = "systemPrivate.onWokeUp";
-
 // Dispatches an extension event with |argument|
 void DispatchEvent(const std::string& event_name, base::Value* argument) {
   scoped_ptr<base::ListValue> list_args(new base::ListValue());
@@ -61,13 +56,15 @@
 
 namespace extensions {
 
+namespace system_private = api::system_private;
+
 bool SystemPrivateGetIncognitoModeAvailabilityFunction::RunImpl() {
   PrefService* prefs = profile_->GetPrefs();
   int value = prefs->GetInteger(prefs::kIncognitoModeAvailability);
   EXTENSION_FUNCTION_VALIDATE(
       value >= 0 &&
       value < static_cast<int>(arraysize(kIncognitoModeAvailabilityStrings)));
-  SetResult(Value::CreateStringValue(kIncognitoModeAvailabilityStrings[value]));
+  SetResult(new base::StringValue(kIncognitoModeAvailabilityStrings[value]));
   return true;
 }
 
@@ -136,22 +133,22 @@
   base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetDouble(kVolumeKey, volume);
   dict->SetBoolean(kIsVolumeMutedKey, is_volume_muted);
-  DispatchEvent(kOnVolumeChanged, dict);
+  DispatchEvent(system_private::OnVolumeChanged::kEventName, dict);
 }
 
 void DispatchBrightnessChangedEvent(int brightness, bool user_initiated) {
   base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(kBrightnessKey, brightness);
   dict->SetBoolean(kUserInitiatedKey, user_initiated);
-  DispatchEvent(kOnBrightnessChanged, dict);
+  DispatchEvent(system_private::OnBrightnessChanged::kEventName, dict);
 }
 
 void DispatchScreenUnlockedEvent() {
-  DispatchEvent(kOnScreenUnlocked, NULL);
+  DispatchEvent(system_private::OnScreenUnlocked::kEventName, NULL);
 }
 
 void DispatchWokeUpEvent() {
-  DispatchEvent(kOnWokeUp, NULL);
+  DispatchEvent(system_private::OnWokeUp::kEventName, NULL);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/system_storage/system_storage_api.cc b/chrome/browser/extensions/api/system_storage/system_storage_api.cc
index cf640ab..4c2301e 100644
--- a/chrome/browser/extensions/api/system_storage/system_storage_api.cc
+++ b/chrome/browser/extensions/api/system_storage/system_storage_api.cc
@@ -87,7 +87,7 @@
       result = api::system_storage::EJECT_DEVICE_RESULT_CODE_FAILURE;
   }
 
-  SetResult(base::StringValue::CreateStringValue(
+  SetResult(new base::StringValue(
       api::system_storage::ToString(result)));
   SendResponse(true);
 }
diff --git a/chrome/browser/extensions/api/tab_capture/OWNERS b/chrome/browser/extensions/api/tab_capture/OWNERS
new file mode 100644
index 0000000..a24599a
--- /dev/null
+++ b/chrome/browser/extensions/api/tab_capture/OWNERS
@@ -0,0 +1,3 @@
+hubbe@chromium.org
+justinlin@chromium.org
+miu@chromium.org
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 25f17c4..47b2ee7 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc
@@ -21,9 +21,9 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
 
 using extensions::api::tab_capture::MediaStreamConstraint;
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 d1ce841..c8bb5cb 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -20,12 +20,12 @@
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/common/extensions/features/base_feature_provider.h"
 #include "chrome/common/extensions/features/complex_feature.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/common/extensions/features/simple_feature.h"
 #include "chrome/test/base/test_switches.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/common/content_switches.h"
+#include "extensions/common/features/feature.h"
 
 namespace chrome {
 
@@ -56,9 +56,6 @@
 // http://crbug.com/261493 and http://crbug.com/268644
 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_AURA)
 #define MAYBE_ApiTests DISABLED_ApiTests
-#elif defined(OS_WIN)
-// http://crbug.com/263951
-#define MAYBE_ApiTests DISABLED_ApiTests
 #else
 #define MAYBE_ApiTests ApiTests
 #endif
@@ -84,9 +81,6 @@
 // http://crbug.com/268644
 #if defined(USE_AURA)
 #define MAYBE_ApiTestsAudio DISABLED_ApiTestsAudio
-#elif defined(OS_WIN)
-// http://crbug.com/263951
-#define MAYBE_ApiTestsAudio DISABLED_ApiTestsAudio
 #else
 #define MAYBE_ApiTestsAudio ApiTestsAudio
 #endif
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
new file mode 100644
index 0000000..c636038
--- /dev/null
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_performancetest.cc
@@ -0,0 +1,278 @@
+// Copyright 2013 The Chromium Authors. 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/command_line.h"
+#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
+#include "base/strings/stringprintf.h"
+#include "base/test/trace_event_analyzer.h"
+#include "base/win/windows_version.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/extensions/tab_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_version_info.h"
+#include "chrome/common/extensions/feature_switch.h"
+#include "chrome/common/extensions/features/base_feature_provider.h"
+#include "chrome/common/extensions/features/complex_feature.h"
+#include "chrome/common/extensions/features/simple_feature.h"
+#include "chrome/test/base/test_launcher_utils.h"
+#include "chrome/test/base/test_switches.h"
+#include "chrome/test/base/tracing.h"
+#include "chrome/test/perf/perf_test.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/common/content_switches.h"
+#include "extensions/common/features/feature.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/compositor_switches.h"
+#include "ui/gl/gl_switches.h"
+
+namespace chrome {
+
+namespace {
+
+const char kExtensionId[] = "ddchlicdkolnonkihahngkmmmjnjlkkf";
+
+enum TestFlags {
+  kUseGpu              = 1 << 0, // Only execute test if --enable-gpu was given
+                                 // on the command line.  This is required for
+                                 // tests that run on GPU.
+  kForceGpuComposited  = 1 << 1, // Force the test to use the compositor.
+  kDisableVsync        = 1 << 2, // Do not limit framerate to vertical refresh.
+                                 // when on GPU, nor to 60hz when not on GPU.
+  kTestThroughWebRTC   = 1 << 3, // Send captured frames through webrtc
+  kSmallWindow         = 1 << 4, // 1 = 800x600, 0 = 2000x1000
+
+  kScaleQualityMask    = 3 << 5, // two bits select which scaling quality
+  kScaleQualityDefault = 0 << 5, // to use on aura.
+  kScaleQualityFast    = 1 << 5,
+  kScaleQualityGood    = 2 << 5,
+  kScaleQualityBest    = 3 << 5,
+};
+
+
+class TabCapturePerformanceTest
+    : public ExtensionApiTest,
+      public testing::WithParamInterface<int> {
+ public:
+  TabCapturePerformanceTest() {}
+
+  bool HasFlag(TestFlags flag) const {
+    return (GetParam() & flag) == flag;
+  }
+
+  bool IsGpuAvailable() const {
+    return CommandLine::ForCurrentProcess()->HasSwitch("enable-gpu");
+  }
+
+  std::string ScalingMethod() const {
+    switch (GetParam() & kScaleQualityMask) {
+      case kScaleQualityFast:
+        return "fast";
+      case kScaleQualityGood:
+        return "good";
+      case kScaleQualityBest:
+        return "best";
+      default:
+        return "";
+    }
+  }
+
+  std::string GetSuffixForTestFlags() {
+    std::string suffix;
+    if (HasFlag(kForceGpuComposited))
+      suffix += "_comp";
+    if (HasFlag(kUseGpu))
+      suffix += "_gpu";
+    if (HasFlag(kDisableVsync))
+      suffix += "_novsync";
+    if (HasFlag(kTestThroughWebRTC))
+      suffix += "_webrtc";
+    if (!ScalingMethod().empty())
+      suffix += "_scale" + ScalingMethod();
+    if (HasFlag(kSmallWindow))
+      suffix += "_small";
+    return suffix;
+  }
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    if (!ScalingMethod().empty()) {
+      command_line->AppendSwitchASCII(switches::kTabCaptureUpscaleQuality,
+                                      ScalingMethod());
+      command_line->AppendSwitchASCII(switches::kTabCaptureDownscaleQuality,
+                                      ScalingMethod());
+    }
+
+    // UI tests boot up render views starting from about:blank. This causes
+    // the renderer to start up thinking it cannot use the GPU. To work
+    // around that, and allow the frame rate test to use the GPU, we must
+    // pass kAllowWebUICompositing.
+    command_line->AppendSwitch(switches::kAllowWebUICompositing);
+
+    // Some of the tests may launch http requests through JSON or AJAX
+    // which causes a security error (cross domain request) when the page
+    // is loaded from the local file system ( file:// ). The following switch
+    // fixes that error.
+    command_line->AppendSwitch(switches::kAllowFileAccessFromFiles);
+
+    if (HasFlag(kSmallWindow)) {
+      command_line->AppendSwitchASCII(switches::kWindowSize, "800,600");
+    } else {
+      command_line->AppendSwitchASCII(switches::kWindowSize, "2000,1500");
+    }
+
+    command_line->AppendSwitch(switches::kDisableTestCompositor);
+
+    if (!HasFlag(kUseGpu)) {
+      command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
+      command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
+      command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
+    } else {
+      command_line->AppendSwitch(switches::kForceCompositingMode);
+    }
+
+    if (HasFlag(kDisableVsync))
+      command_line->AppendSwitch(switches::kDisableGpuVsync);
+
+    command_line->AppendSwitchASCII(switches::kWhitelistedExtensionID,
+                                    kExtensionId);
+    ExtensionApiTest::SetUpCommandLine(command_line);
+  }
+
+  bool PrintResults(trace_analyzer::TraceAnalyzer *analyzer,
+                    const std::string& test_name,
+                    const std::string& event_name,
+                    const std::string& unit) {
+    trace_analyzer::TraceEventVector events;
+    trace_analyzer::Query query =
+        trace_analyzer::Query::EventNameIs(event_name) &&
+        (trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN) ||
+         trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
+         trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_FLOW_BEGIN) ||
+         trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_INSTANT));
+    analyzer->FindEvents(query, &events);
+    if (events.size() < 20) {
+      LOG(INFO) << "Not enough events of type " << event_name << " found.";
+      return false;
+    }
+
+    // Ignore some events for startup/setup/caching.
+    trace_analyzer::TraceEventVector rate_events(events.begin() + 3,
+                                                 events.end() - 3);
+    trace_analyzer::RateStats stats;
+    if (!GetRateStats(rate_events, &stats, NULL)) {
+      LOG(INFO) << "GetRateStats failed";
+      return false;
+    }
+    double mean_ms = stats.mean_us / 1000.0;
+    double std_dev_ms = stats.standard_deviation_us / 1000.0;
+    std::string mean_and_error = base::StringPrintf("%f,%f", mean_ms,
+                                                    std_dev_ms);
+    perf_test::PrintResultMeanAndError(test_name,
+                                       GetSuffixForTestFlags(),
+                                       event_name,
+                                       mean_and_error,
+                                       unit,
+                                       true);
+    return true;
+  }
+
+  void RunTest(const std::string& test_name) {
+    if (HasFlag(kUseGpu) && !IsGpuAvailable()) {
+      LOG(WARNING) <<
+          "Test skipped: requires gpu. Pass --enable-gpu on the command "
+          "line if use of GPU is desired.";
+      return;
+    }
+
+    std::string json_events;
+    ASSERT_TRUE(tracing::BeginTracing("test_fps,mirroring"));
+    std::string page = "performance.html";
+    page += HasFlag(kTestThroughWebRTC) ? "?WebRTC=1" : "?WebRTC=0";
+    // Ideally we'd like to run a higher capture rate when vsync is disabled,
+    // but libjingle currently doesn't allow that.
+    // page += HasFlag(kDisableVsync) ? "&fps=300" : "&fps=30";
+    page += "&fps=30";
+    ASSERT_TRUE(RunExtensionSubtest("tab_capture/experimental", page))
+        << message_;
+    ASSERT_TRUE(tracing::EndTracing(&json_events));
+    scoped_ptr<trace_analyzer::TraceAnalyzer> analyzer;
+    analyzer.reset(trace_analyzer::TraceAnalyzer::Create(json_events));
+
+    // Only one of these PrintResults should actually print something.
+    // The printed result will be the average time between frames in the
+    // browser window.
+    bool sw_frames = PrintResults(analyzer.get(),
+                                  test_name,
+                                  "TestFrameTickSW",
+                                  "frame_time");
+    bool gpu_frames = PrintResults(analyzer.get(),
+                                   test_name,
+                                   "TestFrameTickGPU",
+                                   "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
+    // cannot get any better than 33.33 ms.
+    EXPECT_TRUE(PrintResults(analyzer.get(),
+                             test_name,
+                             "Capture",
+                             "capture_time"));
+  }
+};
+
+}  // namespace
+
+
+IN_PROC_BROWSER_TEST_P(TabCapturePerformanceTest, Performance) {
+  RunTest("TabCapturePerformance");
+}
+
+// Note: First argument is optional and intentionally left blank.
+// (it's a prefix for the generated test cases)
+INSTANTIATE_TEST_CASE_P(
+    ,
+    TabCapturePerformanceTest,
+    testing::Values(
+        0,
+        kUseGpu | kForceGpuComposited,
+        kDisableVsync,
+        kDisableVsync | kUseGpu | kForceGpuComposited,
+        kTestThroughWebRTC,
+        kTestThroughWebRTC | kUseGpu | kForceGpuComposited,
+        kTestThroughWebRTC | kDisableVsync,
+        kTestThroughWebRTC | kDisableVsync | kUseGpu | kForceGpuComposited));
+
+#ifdef USE_AURA
+// TODO(hubbe):
+// These are temporary tests for the purpose of determining what the
+// appropriate scaling quality is. Once that has been determined,
+// these tests will be removed.
+
+const int kScalingTestBase =
+    kTestThroughWebRTC | kDisableVsync | kUseGpu | kForceGpuComposited;
+
+INSTANTIATE_TEST_CASE_P(
+    ScalingTests,
+    TabCapturePerformanceTest,
+    testing::Values(
+        kScalingTestBase | kScaleQualityFast,
+        kScalingTestBase | kScaleQualityGood,
+        kScalingTestBase | kScaleQualityBest,
+        kScalingTestBase | kScaleQualityFast | kSmallWindow,
+        kScalingTestBase | kScaleQualityGood | kSmallWindow,
+        kScalingTestBase | kScaleQualityBest | kSmallWindow));
+
+#endif  // USE_AURA
+
+}  // namespace chrome
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
index 757db57..1fa0080 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_registry.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/profiles/profile.h"
@@ -28,6 +27,8 @@
 
 namespace extensions {
 
+namespace tab_capture = api::tab_capture;
+
 class FullscreenObserver : public content::WebContentsObserver {
  public:
   FullscreenObserver(TabCaptureRequest* request,
@@ -314,8 +315,8 @@
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
   args->Append(info->ToValue().release());
-  scoped_ptr<Event> event(new Event(
-      extensions::event_names::kOnTabCaptureStatusChanged, args.Pass()));
+  scoped_ptr<Event> event(new Event(tab_capture::OnStatusChanged::kEventName,
+      args.Pass()));
   event->restrict_to_profile = profile_;
 
   router->DispatchEventToExtension(request->extension_id, event.Pass());
diff --git a/chrome/browser/extensions/api/tabs/OWNERS b/chrome/browser/extensions/api/tabs/OWNERS
new file mode 100644
index 0000000..81dbb5a
--- /dev/null
+++ b/chrome/browser/extensions/api/tabs/OWNERS
@@ -0,0 +1,2 @@
+kalman@chromium.org
+mpcomplete@chromium.org
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index d574db9..d6e22c6 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -24,6 +24,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/api/tabs/windows_util.h"
 #include "chrome/browser/extensions/extension_function_dispatcher.h"
 #include "chrome/browser/extensions/extension_function_util.h"
 #include "chrome/browser/extensions/extension_host.h"
@@ -170,36 +171,6 @@
   return true;
 }
 
-bool GetWindowFromWindowID(UIThreadExtensionFunction* function,
-                           int window_id,
-                           WindowController** controller) {
-  if (window_id == extension_misc::kCurrentWindowId) {
-    WindowController* extension_window_controller =
-        function->dispatcher()->delegate()->GetExtensionWindowController();
-    // If there is a window controller associated with this extension, use that.
-    if (extension_window_controller) {
-      *controller = extension_window_controller;
-    } else {
-      // Otherwise get the focused or most recently added window.
-      *controller = WindowControllerList::GetInstance()->
-          CurrentWindowForFunction(function);
-    }
-    if (!(*controller)) {
-      function->SetError(keys::kNoCurrentWindowError);
-      return false;
-    }
-  } else {
-    *controller = WindowControllerList::GetInstance()->
-        FindWindowForFunctionById(function, window_id);
-    if (!(*controller)) {
-      function->SetError(ErrorUtils::FormatErrorMessage(
-          keys::kWindowNotFoundError, base::IntToString(window_id)));
-      return false;
-    }
-  }
-  return true;
-}
-
 // |error_message| can optionally be passed in and will be set with an
 // appropriate message if the tab cannot be found by id.
 bool GetTabById(int tab_id,
@@ -264,8 +235,11 @@
     populate_tabs = *params->get_info->populate;
 
   WindowController* controller;
-  if (!GetWindowFromWindowID(this, params->window_id, &controller))
+  if (!windows_util::GetWindowFromWindowID(this,
+                                           params->window_id,
+                                           &controller)) {
     return false;
+  }
 
   if (populate_tabs)
     SetResult(controller->CreateWindowValueWithTabs(GetExtension()));
@@ -283,9 +257,9 @@
     populate_tabs = *params->get_info->populate;
 
   WindowController* controller;
-  if (!GetWindowFromWindowID(this,
-                             extension_misc::kCurrentWindowId,
-                             &controller)) {
+  if (!windows_util::GetWindowFromWindowID(this,
+                                           extension_misc::kCurrentWindowId,
+                                           &controller)) {
     return false;
   }
   if (populate_tabs)
@@ -694,7 +668,7 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &update_props));
 
   WindowController* controller;
-  if (!GetWindowFromWindowID(this, window_id, &controller))
+  if (!windows_util::GetWindowFromWindowID(this, window_id, &controller))
     return false;
 
 #if defined(OS_WIN)
@@ -838,7 +812,7 @@
   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &window_id));
 
   WindowController* controller;
-  if (!GetWindowFromWindowID(this, window_id, &controller))
+  if (!windows_util::GetWindowFromWindowID(this, window_id, &controller))
     return false;
 
 #if defined(OS_WIN)
@@ -1400,7 +1374,7 @@
 
   // JavaScript URLs can do the same kinds of things as cross-origin XHR, so
   // we need to check host permissions before allowing them.
-  if (url.SchemeIs(chrome::kJavaScriptScheme)) {
+  if (url.SchemeIs(content::kJavaScriptScheme)) {
     content::RenderProcessHost* process = web_contents_->GetRenderProcessHost();
     if (!PermissionsData::CanExecuteScriptOnPage(
             GetExtension(),
@@ -1433,7 +1407,7 @@
 
   // The URL of a tab contents never actually changes to a JavaScript URL, so
   // this check only makes sense in other cases.
-  if (!url.SchemeIs(chrome::kJavaScriptScheme))
+  if (!url.SchemeIs(content::kJavaScriptScheme))
     DCHECK_EQ(url.spec(), web_contents_->GetURL().spec());
 
   return true;
@@ -1631,7 +1605,7 @@
 
   if (web_contents->ShowingInterstitialPage()) {
     // This does as same as Browser::ReloadInternal.
-    NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
+    NavigationEntry* entry = web_contents->GetController().GetVisibleEntry();
     OpenURLParams params(entry->GetURL(), Referrer(), CURRENT_TAB,
                          content::PAGE_TRANSITION_RELOAD, false);
     GetCurrentBrowser()->OpenURL(params);
@@ -1951,7 +1925,7 @@
 }
 
 void TabsDetectLanguageFunction::GotLanguage(const std::string& language) {
-  SetResult(Value::CreateStringValue(language.c_str()));
+  SetResult(new base::StringValue(language.c_str()));
   SendResponse(true);
 
   Release();  // Balanced in Run()
diff --git a/chrome/browser/extensions/api/tabs/tabs_constants.cc b/chrome/browser/extensions/api/tabs/tabs_constants.cc
index 27c2aab..457361e 100644
--- a/chrome/browser/extensions/api/tabs/tabs_constants.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_constants.cc
@@ -40,7 +40,6 @@
 const char kTabIdKey[] = "tabId";
 const char kTabIdsKey[] = "tabIds";
 const char kTabsKey[] = "tabs";
-const char kTabUrlKey[] = "tabUrl";
 const char kTitleKey[] = "title";
 const char kToIndexKey[] = "toIndex";
 const char kTopKey[] = "top";
diff --git a/chrome/browser/extensions/api/tabs/tabs_constants.h b/chrome/browser/extensions/api/tabs/tabs_constants.h
index 6ac0b93..67e862a 100644
--- a/chrome/browser/extensions/api/tabs/tabs_constants.h
+++ b/chrome/browser/extensions/api/tabs/tabs_constants.h
@@ -43,7 +43,6 @@
 extern const char kTabIdKey[];
 extern const char kTabIdsKey[];
 extern const char kTabsKey[];
-extern const char kTabUrlKey[];
 extern const char kTitleKey[];
 extern const char kToIndexKey[];
 extern const char kTopKey[];
diff --git a/chrome/browser/extensions/api/tabs/tabs_windows_api.cc b/chrome/browser/extensions/api/tabs/tabs_windows_api.cc
index 24cb81d..5f40de2 100644
--- a/chrome/browser/extensions/api/tabs/tabs_windows_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_windows_api.cc
@@ -6,20 +6,22 @@
 
 #include "base/lazy_instance.h"
 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_system.h"
+#include "chrome/common/extensions/api/windows.h"
 
 namespace extensions {
 
+namespace windows = api::windows;
+
 TabsWindowsAPI::TabsWindowsAPI(Profile* profile)
     : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnWindowCreated);
+      this, windows::OnCreated::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnWindowRemoved);
+      this, windows::OnRemoved::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, event_names::kOnWindowFocusedChanged);
+      this, windows::OnFocusChanged::kEventName);
 }
 
 TabsWindowsAPI::~TabsWindowsAPI() {
diff --git a/chrome/browser/extensions/api/tabs/windows_event_router.cc b/chrome/browser/extensions/api/tabs/windows_event_router.cc
index 1138a73..efdac24 100644
--- a/chrome/browser/extensions/api/tabs/windows_event_router.cc
+++ b/chrome/browser/extensions/api/tabs/windows_event_router.cc
@@ -6,13 +6,13 @@
 
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/event_names.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/window_controller.h"
 #include "chrome/browser/extensions/window_controller_list.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/windows.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/notification_service.h"
 
@@ -20,10 +20,10 @@
 #include "ui/base/x/active_window_watcher_x.h"
 #endif
 
-namespace event_names = extensions::event_names;
-
 namespace extensions {
 
+namespace windows = extensions::api::windows;
+
 WindowsEventRouter::WindowsEventRouter(Profile* profile)
     : profile_(profile),
       focused_profile_(NULL),
@@ -61,7 +61,7 @@
   base::DictionaryValue* window_dictionary =
       window_controller->CreateWindowValue();
   args->Append(window_dictionary);
-  DispatchEvent(event_names::kOnWindowCreated, window_controller->profile(),
+  DispatchEvent(windows::OnCreated::kEventName, window_controller->profile(),
                 args.Pass());
 }
 
@@ -72,8 +72,9 @@
 
   int window_id = window_controller->GetWindowId();
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateIntegerValue(window_id));
-  DispatchEvent(event_names::kOnWindowRemoved, window_controller->profile(),
+  args->Append(new base::FundamentalValue(window_id));
+  DispatchEvent(windows::OnRemoved::kEventName,
+                window_controller->profile(),
                 args.Pass());
 }
 
@@ -117,11 +118,11 @@
       !extensions::ExtensionSystem::Get(profile)->extension_service()->
           CanCrossIncognito(extension)) {
     event_args->Clear();
-    event_args->Append(Value::CreateIntegerValue(
+    event_args->Append(new base::FundamentalValue(
         extension_misc::kUnknownWindowId));
   } else {
     event_args->Clear();
-    event_args->Append(Value::CreateIntegerValue(window_id));
+    event_args->Append(new base::FundamentalValue(window_id));
   }
 }
 
@@ -143,7 +144,7 @@
   focused_profile_ = window_profile;
   focused_window_id_ = window_id;
 
-  scoped_ptr<Event> event(new Event(event_names::kOnWindowFocusedChanged,
+  scoped_ptr<Event> event(new Event(windows::OnFocusChanged::kEventName,
                                     make_scoped_ptr(new base::ListValue())));
   event->will_dispatch_callback =
       base::Bind(&WillDispatchWindowFocusedEvent, window_profile, window_id);
diff --git a/chrome/browser/extensions/api/tabs/windows_util.cc b/chrome/browser/extensions/api/tabs/windows_util.cc
new file mode 100644
index 0000000..536609e
--- /dev/null
+++ b/chrome/browser/extensions/api/tabs/windows_util.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/extensions/api/tabs/windows_util.h"
+
+#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/extension_function_dispatcher.h"
+#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/extensions/window_controller_list.h"
+#include "extensions/common/error_utils.h"
+
+namespace windows_util {
+
+bool GetWindowFromWindowID(UIThreadExtensionFunction* function,
+                           int window_id,
+                           extensions::WindowController** controller) {
+  if (window_id == extension_misc::kCurrentWindowId) {
+    extensions::WindowController* extension_window_controller =
+        function->dispatcher()->delegate()->GetExtensionWindowController();
+    // If there is a window controller associated with this extension, use that.
+    if (extension_window_controller) {
+      *controller = extension_window_controller;
+    } else {
+      // Otherwise get the focused or most recently added window.
+      *controller = extensions::WindowControllerList::GetInstance()->
+          CurrentWindowForFunction(function);
+    }
+    if (!(*controller)) {
+      function->SetError(extensions::tabs_constants::kNoCurrentWindowError);
+      return false;
+    }
+  } else {
+    *controller = extensions::WindowControllerList::GetInstance()->
+        FindWindowForFunctionById(function, window_id);
+    if (!(*controller)) {
+      function->SetError(extensions::ErrorUtils::FormatErrorMessage(
+          extensions::tabs_constants::kWindowNotFoundError,
+          base::IntToString(window_id)));
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace windows_util
diff --git a/chrome/browser/extensions/api/tabs/windows_util.h b/chrome/browser/extensions/api/tabs/windows_util.h
new file mode 100644
index 0000000..24ab44b
--- /dev/null
+++ b/chrome/browser/extensions/api/tabs/windows_util.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_EXTENSIONS_API_TABS_WINDOWS_UTIL_H__
+#define CHROME_BROWSER_EXTENSIONS_API_TABS_WINDOWS_UTIL_H__
+
+class UIThreadExtensionFunction;
+
+namespace extensions {
+class WindowController;
+}
+
+namespace windows_util {
+
+// Populates |controller| for given |window_id|. If the window is not found,
+// returns false and sets UIThreadExtensionFunction error_.
+bool GetWindowFromWindowID(UIThreadExtensionFunction* function,
+                           int window_id,
+                           extensions::WindowController** controller);
+
+}  // namespace windows_util
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_TABS_WINDOWS_UTIL_H__
diff --git a/chrome/browser/extensions/api/terminal/terminal_private_api.cc b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
index fb5ef8a..a7cfdcb 100644
--- a/chrome/browser/extensions/api/terminal/terminal_private_api.cc
+++ b/chrome/browser/extensions/api/terminal/terminal_private_api.cc
@@ -9,7 +9,6 @@
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h"
-#include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/event_router.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -18,6 +17,7 @@
 #include "chromeos/process_proxy/process_proxy_registry.h"
 #include "content/public/browser/browser_thread.h"
 
+namespace terminal_private = extensions::api::terminal_private;
 namespace OnTerminalResize =
     extensions::api::terminal_private::OnTerminalResize;
 namespace OpenTerminalProcess =
@@ -65,7 +65,7 @@
   if (profile &&
       extensions::ExtensionSystem::Get(profile)->event_router()) {
     scoped_ptr<extensions::Event> event(new extensions::Event(
-        extensions::event_names::kOnTerminalProcessOutput, args.Pass()));
+        terminal_private::OnProcessOutput::kEventName, args.Pass()));
     extensions::ExtensionSystem::Get(profile)->event_router()->
         DispatchEventToExtension(extension_id, event.Pass());
   }
diff --git a/chrome/browser/extensions/api/test/test_api.cc b/chrome/browser/extensions/api/test/test_api.cc
index cd55a58..5cf8051 100644
--- a/chrome/browser/extensions/api/test/test_api.cc
+++ b/chrome/browser/extensions/api/test/test_api.cc
@@ -117,7 +117,7 @@
 TestSendMessageFunction::~TestSendMessageFunction() {}
 
 void TestSendMessageFunction::Reply(const std::string& message) {
-  SetResult(Value::CreateStringValue(message));
+  SetResult(new base::StringValue(message));
   SendResponse(true);
   Release();  // balanced in RunImpl
 }
diff --git a/chrome/browser/extensions/api/usb/usb_api.cc b/chrome/browser/extensions/api/usb/usb_api.cc
index 878e362..6fa3aa2 100644
--- a/chrome/browser/extensions/api/usb/usb_api.cc
+++ b/chrome/browser/extensions/api/usb/usb_api.cc
@@ -65,7 +65,7 @@
 static const char kErrorCannotReleaseInterface[] = "Error releasing interface.";
 static const char kErrorCannotSetInterfaceAlternateSetting[] =
     "Error setting alternate interface setting.";
-static const char kErrorConvertDirection[] = "Invalid transfer direction.";
+static const char kErrorConvertDirection[] = "Invalid transsfer direction.";
 static const char kErrorConvertRecipient[] = "Invalid transfer recipient.";
 static const char kErrorConvertRequestType[] = "Invalid request type.";
 static const char kErrorConvertSynchronizationType[] =
@@ -1041,14 +1041,14 @@
       base::Bind(&UsbResetDeviceFunction::OnError, this));
     return;
   }
-  SetResult(Value::CreateBooleanValue(true));
+  SetResult(new base::FundamentalValue(true));
   AsyncWorkCompleted();
 }
 
 void UsbResetDeviceFunction::OnError() {
   RemoveUsbDeviceResource(parameters_->device.handle);
   SetError(kErrorResetDevice);
-  SetResult(Value::CreateBooleanValue(false));
+  SetResult(new base::FundamentalValue(false));
   AsyncWorkCompleted();
 }
 
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
index 4478010..11092cb 100644
--- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
+++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
@@ -19,7 +19,7 @@
   chrome::kHttpsScheme,
   chrome::kFileScheme,
   chrome::kFtpScheme,
-  chrome::kJavaScriptScheme,
+  content::kJavaScriptScheme,
   chrome::kDataScheme,
   chrome::kFileSystemScheme,
 };
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 73c80f1..7e2c8db 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -41,6 +41,7 @@
 
 namespace helpers = web_navigation_api_helpers;
 namespace keys = web_navigation_api_constants;
+namespace web_navigation = api::web_navigation;
 
 namespace {
 
@@ -453,7 +454,7 @@
 
   if (is_reference_fragment_navigation) {
     helpers::DispatchOnCommitted(
-        keys::kOnReferenceFragmentUpdated,
+        web_navigation::OnReferenceFragmentUpdated::kEventName,
         web_contents(),
         frame_num,
         is_main_frame,
@@ -461,7 +462,7 @@
         transition_type);
   } else if (is_history_state_modification) {
     helpers::DispatchOnCommitted(
-        keys::kOnHistoryStateUpdated,
+        web_navigation::OnHistoryStateUpdated::kEventName,
         web_contents(),
         frame_num,
         is_main_frame,
@@ -473,7 +474,7 @@
           transition_type | content::PAGE_TRANSITION_SERVER_REDIRECT);
     }
     helpers::DispatchOnCommitted(
-        keys::kOnCommitted,
+        web_navigation::OnCommitted::kEventName,
         web_contents(),
         frame_num,
         is_main_frame,
@@ -820,23 +821,23 @@
 WebNavigationAPI::WebNavigationAPI(Profile* profile)
     : profile_(profile) {
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnBeforeNavigate);
+      this, web_navigation::OnBeforeNavigate::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnCommitted);
+      this, web_navigation::OnCommitted::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnCompleted);
+      this, web_navigation::OnCompleted::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnCreatedNavigationTarget);
+      this, web_navigation::OnCreatedNavigationTarget::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnDOMContentLoaded);
+      this, web_navigation::OnDOMContentLoaded::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnHistoryStateUpdated);
+      this, web_navigation::OnHistoryStateUpdated::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnErrorOccurred);
+      this, web_navigation::OnErrorOccurred::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnReferenceFragmentUpdated);
+      this, web_navigation::OnReferenceFragmentUpdated::kEventName);
   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
-      this, keys::kOnTabReplaced);
+      this, web_navigation::OnTabReplaced::kEventName);
 }
 
 WebNavigationAPI::~WebNavigationAPI() {
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.cc
index be8ac77..785cbfa 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api_constants.cc
@@ -22,19 +22,6 @@
 const char kTransitionQualifiersKey[] = "transitionQualifiers";
 const char kUrlKey[] = "url";
 
-const char kOnBeforeNavigate[] = "webNavigation.onBeforeNavigate";
-const char kOnCommitted[] = "webNavigation.onCommitted";
-const char kOnCompleted[] = "webNavigation.onCompleted";
-const char kOnCreatedNavigationTarget[] =
-    "webNavigation.onCreatedNavigationTarget";
-const char kOnDOMContentLoaded[] =
-    "webNavigation.onDOMContentLoaded";
-const char kOnHistoryStateUpdated[] = "webNavigation.onHistoryStateUpdated";
-const char kOnErrorOccurred[] = "webNavigation.onErrorOccurred";
-const char kOnReferenceFragmentUpdated[] =
-    "webNavigation.onReferenceFragmentUpdated";
-const char kOnTabReplaced[] = "webNavigation.onTabReplaced";
-
 }  // namespace web_navigation_api_constants
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
index 86213ee..4648b5f 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api_helpers.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/web_navigation.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
@@ -24,6 +25,7 @@
 namespace extensions {
 
 namespace keys = web_navigation_api_constants;
+namespace web_navigation = api::web_navigation;
 
 namespace web_navigation_api_helpers {
 
@@ -77,7 +79,7 @@
   args->Append(dict);
 
   DispatchEvent(web_contents->GetBrowserContext(),
-                keys::kOnBeforeNavigate,
+                web_navigation::OnBeforeNavigate::kEventName,
                 args.Pass(),
                 validated_url);
 }
@@ -102,13 +104,13 @@
       content::PageTransitionGetCoreTransitionString(transition_type));
   base::ListValue* qualifiers = new base::ListValue();
   if (transition_type & content::PAGE_TRANSITION_CLIENT_REDIRECT)
-    qualifiers->Append(Value::CreateStringValue("client_redirect"));
+    qualifiers->Append(new base::StringValue("client_redirect"));
   if (transition_type & content::PAGE_TRANSITION_SERVER_REDIRECT)
-    qualifiers->Append(Value::CreateStringValue("server_redirect"));
+    qualifiers->Append(new base::StringValue("server_redirect"));
   if (transition_type & content::PAGE_TRANSITION_FORWARD_BACK)
-    qualifiers->Append(Value::CreateStringValue("forward_back"));
+    qualifiers->Append(new base::StringValue("forward_back"));
   if (transition_type & content::PAGE_TRANSITION_FROM_ADDRESS_BAR)
-    qualifiers->Append(Value::CreateStringValue("from_address_bar"));
+    qualifiers->Append(new base::StringValue("from_address_bar"));
   dict->Set(keys::kTransitionQualifiersKey, qualifiers);
   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
   args->Append(dict);
@@ -134,7 +136,7 @@
   args->Append(dict);
 
   DispatchEvent(web_contents->GetBrowserContext(),
-                keys::kOnDOMContentLoaded,
+                web_navigation::OnDOMContentLoaded::kEventName,
                 args.Pass(),
                 url);
 }
@@ -155,7 +157,8 @@
   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
   args->Append(dict);
 
-  DispatchEvent(web_contents->GetBrowserContext(), keys::kOnCompleted,
+  DispatchEvent(web_contents->GetBrowserContext(),
+                web_navigation::OnCompleted::kEventName,
                 args.Pass(), url);
 }
 
@@ -188,7 +191,9 @@
   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
   args->Append(dict);
 
-  DispatchEvent(browser_context, keys::kOnCreatedNavigationTarget, args.Pass(),
+  DispatchEvent(browser_context,
+                web_navigation::OnCreatedNavigationTarget::kEventName,
+                args.Pass(),
                 target_url);
 }
 
@@ -206,10 +211,12 @@
   dict->SetInteger(keys::kProcessIdKey, render_process_id);
   dict->SetInteger(keys::kFrameIdKey, GetFrameId(is_main_frame, frame_id));
   dict->SetString(keys::kErrorKey, net::ErrorToString(error_code));
-  dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
+  dict->SetDouble(keys::kTimeStampKey,
+      MilliSecondsFromTime(base::Time::Now()));
   args->Append(dict);
 
-  DispatchEvent(web_contents->GetBrowserContext(), keys::kOnErrorOccurred,
+  DispatchEvent(web_contents->GetBrowserContext(),
+                web_navigation::OnErrorOccurred::kEventName,
                 args.Pass(), url);
 }
 
@@ -222,12 +229,16 @@
   base::DictionaryValue* dict = new base::DictionaryValue();
   dict->SetInteger(keys::kReplacedTabIdKey,
                    ExtensionTabUtil::GetTabId(old_web_contents));
-  dict->SetInteger(keys::kTabIdKey,
-                   ExtensionTabUtil::GetTabId(new_web_contents));
+  dict->SetInteger(
+      keys::kTabIdKey,
+      ExtensionTabUtil::GetTabId(new_web_contents));
   dict->SetDouble(keys::kTimeStampKey, MilliSecondsFromTime(base::Time::Now()));
   args->Append(dict);
 
-  DispatchEvent(browser_context, keys::kOnTabReplaced, args.Pass(), GURL());
+  DispatchEvent(browser_context,
+                web_navigation::OnTabReplaced::kEventName,
+                args.Pass(),
+                GURL());
 }
 
 }  // namespace web_navigation_api_helpers
diff --git a/chrome/browser/extensions/api/web_request/upload_data_presenter.cc b/chrome/browser/extensions/api/web_request/upload_data_presenter.cc
index 8b34012..2870bc6 100644
--- a/chrome/browser/extensions/api/web_request/upload_data_presenter.cc
+++ b/chrome/browser/extensions/api/web_request/upload_data_presenter.cc
@@ -97,7 +97,7 @@
 void RawDataPresenter::FeedNextFile(const std::string& filename) {
   // Insert the file path instead of the contents, which may be too large.
   subtle::AppendKeyValuePair(keys::kRequestBodyRawFileKey,
-                             Value::CreateStringValue(filename),
+                             new base::StringValue(filename),
                              list_.get());
 }
 
diff --git a/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc b/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc
index c445982..2309d1a 100644
--- a/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/upload_data_presenter_unittest.cc
@@ -23,7 +23,7 @@
 
   // Expected output.
   scoped_ptr<base::ListValue> values(new base::ListValue);
-  values->Append(base::Value::CreateStringValue("value"));
+  values->Append(new base::StringValue("value"));
   base::DictionaryValue expected_form;
   expected_form.SetWithoutPathExpansion("key.with.dots", values.release());
 
@@ -52,7 +52,7 @@
       base::BinaryValue::CreateWithCopiedBuffer(block1, block1_size));
   ASSERT_TRUE(expected_a.get() != NULL);
   scoped_ptr<base::StringValue> expected_b(
-      base::Value::CreateStringValue(kFilename));
+      new base::StringValue(kFilename));
   ASSERT_TRUE(expected_b.get() != NULL);
   scoped_ptr<base::BinaryValue> expected_c(
       base::BinaryValue::CreateWithCopiedBuffer(block2, block2_size));
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 478c990..46fc10a 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api.cc
@@ -44,7 +44,6 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_message_filter.h"
@@ -54,6 +53,7 @@
 #include "content/public/browser/user_metrics.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/event_filtering_info.h"
+#include "extensions/common/features/feature.h"
 #include "extensions/common/url_pattern.h"
 #include "grit/generated_resources.h"
 #include "net/base/auth.h"
@@ -93,10 +93,10 @@
 // List of all the webRequest events.
 const char* const kWebRequestEvents[] = {
   keys::kOnBeforeRedirectEvent,
-  keys::kOnBeforeRequestEvent,
+  web_request::OnBeforeRequest::kEventName,
   keys::kOnBeforeSendHeadersEvent,
   keys::kOnCompletedEvent,
-  keys::kOnErrorOccurredEvent,
+  web_request::OnErrorOccurred::kEventName,
   keys::kOnSendHeadersEvent,
   keys::kOnAuthRequiredEvent,
   keys::kOnResponseStartedEvent,
@@ -631,13 +631,13 @@
 
   initialize_blocked_requests |=
       ProcessDeclarativeRules(profile, extension_info_map,
-                              keys::kOnBeforeRequestEvent, request,
+                              web_request::OnBeforeRequest::kEventName, request,
                               extensions::ON_BEFORE_REQUEST, NULL);
 
   int extra_info_spec = 0;
   std::vector<const EventListener*> listeners =
       GetMatchingListeners(profile, extension_info_map,
-                           keys::kOnBeforeRequestEvent, request,
+                           web_request::OnBeforeRequest::kEventName, request,
                            &extra_info_spec);
   if (!listeners.empty() &&
       !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
@@ -1057,7 +1057,7 @@
   int extra_info_spec = 0;
   std::vector<const EventListener*> listeners =
       GetMatchingListeners(profile, extension_info_map,
-                           keys::kOnErrorOccurredEvent, request,
+                           web_request::OnErrorOccurred::kEventName, request,
                            &extra_info_spec);
   if (listeners.empty())
     return;
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_constants.cc b/chrome/browser/extensions/api/web_request/web_request_api_constants.cc
index ffcd8dd..493a903 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_constants.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_constants.cc
@@ -44,10 +44,8 @@
 const char kPasswordKey[] = "password";
 
 const char kOnBeforeRedirectEvent[] = "webRequest.onBeforeRedirect";
-const char kOnBeforeRequestEvent[] = "webRequest.onBeforeRequest";
 const char kOnBeforeSendHeadersEvent[] = "webRequest.onBeforeSendHeaders";
 const char kOnCompletedEvent[] = "webRequest.onCompleted";
-const char kOnErrorOccurredEvent[] = "webRequest.onErrorOccurred";
 const char kOnHeadersReceivedEvent[] = "webRequest.onHeadersReceived";
 const char kOnResponseStartedEvent[] = "webRequest.onResponseStarted";
 const char kOnSendHeadersEvent[] = "webRequest.onSendHeaders";
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc b/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc
index 5c10c8d..19638b7 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_helpers.cc
@@ -224,7 +224,7 @@
       delta->modified_request_headers);
   while (modification.GetNext()) {
     std::string line = modification.name() + ": " + modification.value();
-    modified_headers->Append(Value::CreateStringValue(line));
+    modified_headers->Append(new base::StringValue(line));
   }
   dict->Set("modified_headers", modified_headers);
 
@@ -233,7 +233,7 @@
            delta->deleted_request_headers.begin();
        key != delta->deleted_request_headers.end();
        ++key) {
-    deleted_headers->Append(Value::CreateStringValue(*key));
+    deleted_headers->Append(new base::StringValue(*key));
   }
   dict->Set("deleted_headers", deleted_headers);
   return dict;
@@ -249,7 +249,7 @@
   base::ListValue* result = new base::ListValue;
   for (size_t i = 0, n = s.size(); i < n; ++i) {
     result->Append(
-        Value::CreateIntegerValue(
+        new base::FundamentalValue(
             *reinterpret_cast<const unsigned char*>(&s[i])));
   }
   return result;
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index 6648611..2c8774f 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -29,8 +29,8 @@
 #include "chrome/browser/extensions/extension_warning_set.h"
 #include "chrome/browser/net/about_protocol_handler.h"
 #include "chrome/browser/net/chrome_network_delegate.h"
+#include "chrome/common/extensions/api/web_request.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_pref_service_syncable.h"
@@ -38,6 +38,7 @@
 #include "chrome/test/base/testing_profile_manager.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/common/features/feature.h"
 #include "net/base/auth.h"
 #include "net/base/capturing_net_log.h"
 #include "net/base/net_util.h"
@@ -52,6 +53,7 @@
 
 namespace helpers = extension_web_request_api_helpers;
 namespace keys = extension_web_request_api_constants;
+namespace web_request = extensions::api::web_request;
 
 using base::BinaryValue;
 using base::DictionaryValue;
@@ -218,7 +220,7 @@
   std::string extension1_id("1");
   std::string extension2_id("2");
   ExtensionWebRequestEventRouter::RequestFilter filter;
-  const std::string kEventName(keys::kOnBeforeRequestEvent);
+  const std::string kEventName(web_request::OnBeforeRequest::kEventName);
   base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
       &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
@@ -353,7 +355,7 @@
   std::string extension1_id("1");
   std::string extension2_id("2");
   ExtensionWebRequestEventRouter::RequestFilter filter;
-  const std::string kEventName(keys::kOnBeforeRequestEvent);
+  const std::string kEventName(web_request::OnBeforeRequest::kEventName);
   base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
     &profile_, extension1_id, extension1_id, kEventName, kEventName + "/1",
@@ -420,8 +422,8 @@
   ExtensionWebRequestEventRouter::RequestFilter filter;
 
   // Subscribe to OnBeforeRequest and OnErrorOccurred.
-  const std::string kEventName(keys::kOnBeforeRequestEvent);
-  const std::string kEventName2(keys::kOnErrorOccurredEvent);
+  const std::string kEventName(web_request::OnBeforeRequest::kEventName);
+  const std::string kEventName2(web_request::OnErrorOccurred::kEventName);
   base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
   ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
     &profile_, extension_id, extension_id, kEventName, kEventName + "/1",
@@ -584,7 +586,7 @@
       &raw);
   extensions::subtle::AppendKeyValuePair(
       keys::kRequestBodyRawFileKey,
-      Value::CreateStringValue(std::string()),
+      new base::StringValue(std::string()),
       &raw);
   extensions::subtle::AppendKeyValuePair(
       keys::kRequestBodyRawBytesKey,
@@ -604,7 +606,7 @@
 #undef kBoundary
 
   // Set up a dummy extension name.
-  const std::string kEventName(keys::kOnBeforeRequestEvent);
+  const std::string kEventName(web_request::OnBeforeRequest::kEventName);
   ExtensionWebRequestEventRouter::RequestFilter filter;
   std::string extension_id("1");
   const std::string string_spec_post("blocking,requestBody");
@@ -695,7 +697,7 @@
   const char* kMethods[] = { "POST", "PUT", "GET" };
 
   // Set up a dummy extension name.
-  const std::string kEventName(keys::kOnBeforeRequestEvent);
+  const std::string kEventName(web_request::OnBeforeRequest::kEventName);
   ExtensionWebRequestEventRouter::RequestFilter filter;
   const std::string extension_id("1");
   int extra_info_spec = 0;
@@ -1165,11 +1167,11 @@
 
 TEST(ExtensionWebRequestHelpersTest, TestStringToCharList) {
   ListValue list_value;
-  list_value.Append(Value::CreateIntegerValue('1'));
-  list_value.Append(Value::CreateIntegerValue('2'));
-  list_value.Append(Value::CreateIntegerValue('3'));
-  list_value.Append(Value::CreateIntegerValue(0xFE));
-  list_value.Append(Value::CreateIntegerValue(0xD1));
+  list_value.Append(new base::FundamentalValue('1'));
+  list_value.Append(new base::FundamentalValue('2'));
+  list_value.Append(new base::FundamentalValue('3'));
+  list_value.Append(new base::FundamentalValue(0xFE));
+  list_value.Append(new base::FundamentalValue(0xD1));
 
   unsigned char char_value[] = {'1', '2', '3', 0xFE, 0xD1};
   std::string string_value(reinterpret_cast<char *>(char_value), 5);
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 7c7acb8..05de8d8 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -13,13 +13,13 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/login/login_prompt.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "extensions/common/features/feature.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
diff --git a/chrome/browser/extensions/api/web_request/web_request_permissions.cc b/chrome/browser/extensions/api/web_request/web_request_permissions.cc
index 7b7e6af..480bf84 100644
--- a/chrome/browser/extensions/api/web_request/web_request_permissions.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_permissions.cc
@@ -7,6 +7,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/extension_info_map.h"
+#include "chrome/browser/extensions/extension_renderer_state.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
@@ -82,12 +83,21 @@
     const net::URLRequest* request) {
   // Hide requests from the Chrome WebStore App or signin process.
   const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
-  if (info && extension_info_map) {
+  if (info) {
     int process_id = info->GetChildID();
-    if (extension_info_map->IsSigninProcess(process_id) ||
+    int route_id = info->GetRouteID();
+    ExtensionRendererState::WebViewInfo webview_info;
+    // Never hide requests from guest processes.
+    if (ExtensionRendererState::GetInstance()->GetWebViewInfo(
+        process_id, route_id, &webview_info)) {
+      return false;
+    }
+    if (extension_info_map && (
+        extension_info_map->IsSigninProcess(process_id) ||
         extension_info_map->process_map().Contains(
-            extension_misc::kWebStoreAppId, process_id))
+            extension_misc::kWebStoreAppId, process_id))) {
       return true;
+    }
   }
 
   const GURL& url = request->url();
diff --git a/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
index d285823..ece2ee2 100644
--- a/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc
@@ -68,10 +68,8 @@
       com_extension_.get(), base::Time::Now(), false /*incognito_enabled*/);
 }
 
-TEST(ExtensionWebRequestHelpersTest, TestHideRequestForURL) {
-  base::MessageLoopForIO message_loop;
+TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) {
   net::TestURLRequestContext context;
-  scoped_refptr<ExtensionInfoMap> extension_info_map(new ExtensionInfoMap);
   const char* sensitive_urls[] = {
       "http://clients2.google.com",
       "http://clients22.google.com",
@@ -88,14 +86,14 @@
       "http://www.google.com/"
   };
   const int kSigninProcessId = 99;
-  extension_info_map->SetSigninProcess(kSigninProcessId);
+  extension_info_map_->SetSigninProcess(kSigninProcessId);
 
   // Check that requests are rejected based on the destination
   for (size_t i = 0; i < arraysize(sensitive_urls); ++i) {
     GURL sensitive_url(sensitive_urls[i]);
     net::TestURLRequest request(sensitive_url, NULL, &context, NULL);
     EXPECT_TRUE(
-        WebRequestPermissions::HideRequest(extension_info_map.get(), &request))
+        WebRequestPermissions::HideRequest(extension_info_map_.get(), &request))
         << sensitive_urls[i];
   }
   // Check that requests are accepted if they don't touch sensitive urls.
@@ -103,7 +101,7 @@
     GURL non_sensitive_url(non_sensitive_urls[i]);
     net::TestURLRequest request(non_sensitive_url, NULL, &context, NULL);
     EXPECT_FALSE(
-        WebRequestPermissions::HideRequest(extension_info_map.get(), &request))
+        WebRequestPermissions::HideRequest(extension_info_map_.get(), &request))
         << non_sensitive_urls[i];
   }
 
@@ -113,7 +111,7 @@
   GURL non_sensitive_url("http://www.google.com/test.js");
   net::TestURLRequest non_sensitive_request(
       non_sensitive_url, NULL, &context, NULL);
-  EXPECT_FALSE(WebRequestPermissions::HideRequest(extension_info_map.get(),
+  EXPECT_FALSE(WebRequestPermissions::HideRequest(extension_info_map_.get(),
                                                   &non_sensitive_request));
   // If the origin is labeled by the WebStoreAppId, it becomes protected.
   {
@@ -124,9 +122,9 @@
         non_sensitive_url, NULL, &context, NULL);
     ResourceRequestInfo::AllocateForTesting(&sensitive_request,
         ResourceType::SCRIPT, NULL, process_id, frame_id);
-    extension_info_map->RegisterExtensionProcess(extension_misc::kWebStoreAppId,
-        process_id, site_instance_id);
-    EXPECT_TRUE(WebRequestPermissions::HideRequest(extension_info_map.get(),
+    extension_info_map_->RegisterExtensionProcess(
+        extension_misc::kWebStoreAppId, process_id, site_instance_id);
+    EXPECT_TRUE(WebRequestPermissions::HideRequest(extension_info_map_.get(),
                                                    &sensitive_request));
   }
   // If the process is the signin process, it becomes protected.
@@ -137,7 +135,7 @@
         non_sensitive_url, NULL, &context, NULL);
     ResourceRequestInfo::AllocateForTesting(&sensitive_request,
         ResourceType::SCRIPT, NULL, process_id, frame_id);
-    EXPECT_TRUE(WebRequestPermissions::HideRequest(extension_info_map.get(),
+    EXPECT_TRUE(WebRequestPermissions::HideRequest(extension_info_map_.get(),
                                                    &sensitive_request));
   }
 }
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 07cc111..d245bd7 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -47,6 +47,17 @@
 
 namespace extensions {
 
+namespace BeginInstallWithManifest3 =
+    api::webstore_private::BeginInstallWithManifest3;
+namespace CompleteInstall = api::webstore_private::CompleteInstall;
+namespace GetBrowserLogin = api::webstore_private::GetBrowserLogin;
+namespace GetIsLauncherEnabled = api::webstore_private::GetIsLauncherEnabled;
+namespace GetStoreLogin = api::webstore_private::GetStoreLogin;
+namespace GetWebGLStatus = api::webstore_private::GetWebGLStatus;
+namespace InstallBundle = api::webstore_private::InstallBundle;
+namespace IsInIncognitoMode = api::webstore_private::IsInIncognitoMode;
+namespace SetStoreLogin = api::webstore_private::SetStoreLogin;
+
 namespace {
 
 // Holds the Approvals between the time we prompt and start the installs.
@@ -142,15 +153,6 @@
 static base::LazyInstance<PendingInstalls> g_pending_installs =
     LAZY_INSTANCE_INITIALIZER;
 
-const char kAppInstallBubbleKey[] = "appInstallBubble";
-const char kEnableLauncherKey[] = "enableLauncher";
-const char kIconDataKey[] = "iconData";
-const char kIconUrlKey[] = "iconUrl";
-const char kIdKey[] = "id";
-const char kLocalizedNameKey[] = "localizedName";
-const char kLoginKey[] = "login";
-const char kManifestKey[] = "manifest";
-
 // A preference set by the web store to indicate login information for
 // purchased apps.
 const char kWebstoreLogin[] = "extensions.webstore_login";
@@ -164,16 +166,6 @@
     "* does not match a previous call to beginInstallWithManifest3";
 const char kUserCancelledError[] = "User cancelled install";
 
-// Helper to create a dictionary with login properties set from the appropriate
-// values in the passed-in |profile|.
-base::DictionaryValue* CreateLoginResult(Profile* profile) {
-  base::DictionaryValue* dictionary = new base::DictionaryValue();
-  std::string username = profile->GetPrefs()->GetString(
-      prefs::kGoogleServicesUsername);
-  dictionary->SetString(kLoginKey, username);
-  return dictionary;
-}
-
 WebstoreInstaller::Delegate* test_webstore_installer_delegate = NULL;
 
 // We allow the web store to set a string containing login information when a
@@ -210,11 +202,12 @@
 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {}
 
 bool WebstorePrivateInstallBundleFunction::RunImpl() {
-  base::ListValue* extensions = NULL;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &extensions));
+  scoped_ptr<InstallBundle::Params> params(
+      InstallBundle::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
 
   BundleInstaller::ItemList items;
-  if (!ReadBundleInfo(extensions, &items))
+  if (!ReadBundleInfo(*params, &items))
     return false;
 
   bundle_ = new BundleInstaller(GetCurrentBrowser(), items);
@@ -226,20 +219,13 @@
 }
 
 bool WebstorePrivateInstallBundleFunction::
-    ReadBundleInfo(base::ListValue* extensions,
+    ReadBundleInfo(const InstallBundle::Params& params,
     BundleInstaller::ItemList* items) {
-  for (size_t i = 0; i < extensions->GetSize(); ++i) {
-    base::DictionaryValue* details = NULL;
-    EXTENSION_FUNCTION_VALIDATE(extensions->GetDictionary(i, &details));
-
+  for (size_t i = 0; i < params.details.size(); ++i) {
     BundleInstaller::Item item;
-    EXTENSION_FUNCTION_VALIDATE(details->GetString(
-        kIdKey, &item.id));
-    EXTENSION_FUNCTION_VALIDATE(details->GetString(
-        kManifestKey, &item.manifest));
-    EXTENSION_FUNCTION_VALIDATE(details->GetString(
-        kLocalizedNameKey, &item.localized_name));
-
+    item.id = params.details[i]->id;
+    item.manifest = params.details[i]->manifest;
+    item.localized_name = params.details[i]->localized_name;
     items->push_back(item);
   }
 
@@ -271,40 +257,31 @@
 }
 
 WebstorePrivateBeginInstallWithManifest3Function::
-    WebstorePrivateBeginInstallWithManifest3Function()
-    : use_app_installed_bubble_(false), enable_launcher_(false) {}
+    WebstorePrivateBeginInstallWithManifest3Function() {}
 
 WebstorePrivateBeginInstallWithManifest3Function::
     ~WebstorePrivateBeginInstallWithManifest3Function() {}
 
 bool WebstorePrivateBeginInstallWithManifest3Function::RunImpl() {
-  base::DictionaryValue* details = NULL;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &details));
-  CHECK(details);
+  params_ = BeginInstallWithManifest3::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params_);
 
-  EXTENSION_FUNCTION_VALIDATE(details->GetString(kIdKey, &id_));
-  if (!extensions::Extension::IdIsValid(id_)) {
+  if (!extensions::Extension::IdIsValid(params_->details.id)) {
     SetResultCode(INVALID_ID);
     error_ = kInvalidIdError;
     return false;
   }
 
-  EXTENSION_FUNCTION_VALIDATE(details->GetString(kManifestKey, &manifest_));
-
-  if (details->HasKey(kIconDataKey) && details->HasKey(kIconUrlKey)) {
+  if (params_->details.icon_data && params_->details.icon_url) {
     SetResultCode(ICON_ERROR);
     error_ = kCannotSpecifyIconDataAndUrlError;
     return false;
   }
 
-  if (details->HasKey(kIconDataKey))
-    EXTENSION_FUNCTION_VALIDATE(details->GetString(kIconDataKey, &icon_data_));
-
   GURL icon_url;
-  if (details->HasKey(kIconUrlKey)) {
+  if (params_->details.icon_url) {
     std::string tmp_url;
-    EXTENSION_FUNCTION_VALIDATE(details->GetString(kIconUrlKey, &tmp_url));
-    icon_url = source_url().Resolve(tmp_url);
+    icon_url = source_url().Resolve(*params_->details.icon_url);
     if (!icon_url.is_valid()) {
       SetResultCode(INVALID_ICON_URL);
       error_ = kInvalidIconUrlError;
@@ -312,22 +289,13 @@
     }
   }
 
-  if (details->HasKey(kLocalizedNameKey))
-    EXTENSION_FUNCTION_VALIDATE(details->GetString(kLocalizedNameKey,
-                                                   &localized_name_));
-
-  if (details->HasKey(kAppInstallBubbleKey))
-    EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(
-        kAppInstallBubbleKey, &use_app_installed_bubble_));
-
-  if (details->HasKey(kEnableLauncherKey))
-    EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(
-        kEnableLauncherKey, &enable_launcher_));
+  std::string icon_data = params_->details.icon_data ?
+      *params_->details.icon_data : std::string();
 
   ExtensionService* service =
     extensions::ExtensionSystem::Get(profile_)->extension_service();
-  if (service->GetInstalledExtension(id_) ||
-      !g_pending_installs.Get().InsertInstall(profile_, id_)) {
+  if (service->GetInstalledExtension(params_->details.id) ||
+      !g_pending_installs.Get().InsertInstall(profile_, params_->details.id)) {
     SetResultCode(ALREADY_INSTALLED);
     error_ = kAlreadyInstalledError;
     return false;
@@ -338,7 +306,8 @@
     context_getter = profile()->GetRequestContext();
 
   scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
-      this, id_, manifest_, icon_data_, icon_url, context_getter);
+      this, params_->details.id, params_->details.manifest, icon_data, icon_url,
+          context_getter);
 
   // The helper will call us back via OnWebstoreParseSuccess or
   // OnWebstoreParseFailure.
@@ -352,65 +321,63 @@
   return true;
 }
 
+const char* WebstorePrivateBeginInstallWithManifest3Function::
+    ResultCodeToString(ResultCode code) {
+  switch (code) {
+    case ERROR_NONE:
+      return "";
+    case UNKNOWN_ERROR:
+      return "unknown_error";
+    case USER_CANCELLED:
+      return "user_cancelled";
+    case MANIFEST_ERROR:
+      return "manifest_error";
+    case ICON_ERROR:
+      return "icon_error";
+    case INVALID_ID:
+      return "invalid_id";
+    case PERMISSION_DENIED:
+      return "permission_denied";
+    case INVALID_ICON_URL:
+      return "invalid_icon_url";
+    case SIGNIN_FAILED:
+      return "signin_failed";
+    case ALREADY_INSTALLED:
+      return "already_installed";
+  }
+  NOTREACHED();
+  return "";
+}
 
 void WebstorePrivateBeginInstallWithManifest3Function::SetResultCode(
     ResultCode code) {
-  switch (code) {
-    case ERROR_NONE:
-      SetResult(Value::CreateStringValue(std::string()));
-      break;
-    case UNKNOWN_ERROR:
-      SetResult(Value::CreateStringValue("unknown_error"));
-      break;
-    case USER_CANCELLED:
-      SetResult(Value::CreateStringValue("user_cancelled"));
-      break;
-    case MANIFEST_ERROR:
-      SetResult(Value::CreateStringValue("manifest_error"));
-      break;
-    case ICON_ERROR:
-      SetResult(Value::CreateStringValue("icon_error"));
-      break;
-    case INVALID_ID:
-      SetResult(Value::CreateStringValue("invalid_id"));
-      break;
-    case PERMISSION_DENIED:
-      SetResult(Value::CreateStringValue("permission_denied"));
-      break;
-    case INVALID_ICON_URL:
-      SetResult(Value::CreateStringValue("invalid_icon_url"));
-      break;
-    case SIGNIN_FAILED:
-      SetResult(Value::CreateStringValue("signin_failed"));
-      break;
-    case ALREADY_INSTALLED:
-      SetResult(Value::CreateStringValue("already_installed"));
-      break;
-    default:
-      CHECK(false);
-  }
+  results_ = BeginInstallWithManifest3::Results::Create(
+      ResultCodeToString(code));
 }
 
 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess(
     const std::string& id,
     const SkBitmap& icon,
     base::DictionaryValue* parsed_manifest) {
-  CHECK_EQ(id_, id);
+  CHECK_EQ(params_->details.id, id);
   CHECK(parsed_manifest);
   icon_ = icon;
   parsed_manifest_.reset(parsed_manifest);
 
+  std::string localized_name = params_->details.localized_name ?
+      *params_->details.localized_name : std::string();
+
   std::string error;
   dummy_extension_ = ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
       parsed_manifest_.get(),
       Extension::FROM_WEBSTORE,
       id,
-      localized_name_,
+      localized_name,
       std::string(),
       &error);
 
   if (!dummy_extension_.get()) {
-    OnWebstoreParseFailure(id_,
+    OnWebstoreParseFailure(params_->details.id,
                            WebstoreInstallHelper::Delegate::MANIFEST_ERROR,
                            kInvalidManifestError);
     return;
@@ -433,7 +400,7 @@
     const std::string& id,
     WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code,
     const std::string& error_message) {
-  CHECK_EQ(id_, id);
+  CHECK_EQ(params_->details.id, id);
 
   // Map from WebstoreInstallHelper's result codes to ours.
   switch (result_code) {
@@ -463,7 +430,7 @@
 
   SetResultCode(SIGNIN_FAILED);
   error_ = error.ToString();
-  g_pending_installs.Get().EraseInstall(profile_, id_);
+  g_pending_installs.Get().EraseInstall(profile_, params_->details.id);
   SendResponse(false);
 
   // Matches the AddRef in RunImpl().
@@ -496,12 +463,12 @@
   // entry is only valid for some number of minutes.
   scoped_ptr<WebstoreInstaller::Approval> approval(
       WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
-          profile(), id_, parsed_manifest_.Pass()));
-  approval->use_app_installed_bubble = use_app_installed_bubble_;
-  approval->enable_launcher = enable_launcher_;
+          profile(), params_->details.id, parsed_manifest_.Pass()));
+  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
   // to train the user to open it themselves at least once.
-  approval->skip_post_install_ui = enable_launcher_;
+  approval->skip_post_install_ui = params_->details.enable_launcher;
   approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
   g_pending_approvals.Get().PushApproval(approval.Pass());
 
@@ -522,7 +489,7 @@
     bool user_initiated) {
   error_ = kUserCancelledError;
   SetResultCode(USER_CANCELLED);
-  g_pending_installs.Get().EraseInstall(profile_, id_);
+  g_pending_installs.Get().EraseInstall(profile_, params_->details.id);
   SendResponse(false);
 
   // The web store install histograms are a subset of the install histograms.
@@ -551,17 +518,19 @@
     ~WebstorePrivateCompleteInstallFunction() {}
 
 bool WebstorePrivateCompleteInstallFunction::RunImpl() {
-  std::string id;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &id));
-  if (!extensions::Extension::IdIsValid(id)) {
+  scoped_ptr<CompleteInstall::Params> params(
+      CompleteInstall::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+  if (!extensions::Extension::IdIsValid(params->expected_id)) {
     error_ = kInvalidIdError;
     return false;
   }
 
-  approval_ = g_pending_approvals.Get().PopApproval(profile(), id).Pass();
+  approval_ = g_pending_approvals.Get().PopApproval(profile(),
+      params->expected_id).Pass();
   if (!approval_) {
     error_ = ErrorUtils::FormatErrorMessage(
-        kNoPreviousBeginInstallWithManifestError, id);
+        kNoPreviousBeginInstallWithManifestError, params->expected_id);
     return false;
   }
 
@@ -585,7 +554,7 @@
   scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
       profile(), this,
       &(dispatcher()->delegate()->GetAssociatedWebContents()->GetController()),
-      id, approval_.Pass(), WebstoreInstaller::FLAG_NONE);
+      params->expected_id, approval_.Pass(), WebstoreInstaller::FLAG_NONE);
   installer->Start();
 
   return true;
@@ -630,24 +599,27 @@
 
 bool WebstorePrivateEnableAppLauncherFunction::RunImpl() {
   AppListService::Get()->EnableAppList(profile());
-  SendResponse(true);
   return true;
 }
 
 bool WebstorePrivateGetBrowserLoginFunction::RunImpl() {
-  SetResult(CreateLoginResult(profile_->GetOriginalProfile()));
+  GetBrowserLogin::Results::Info info;
+  info.login = profile_->GetOriginalProfile()->GetPrefs()->GetString(
+      prefs::kGoogleServicesUsername);
+  results_ = GetBrowserLogin::Results::Create(info);
   return true;
 }
 
 bool WebstorePrivateGetStoreLoginFunction::RunImpl() {
-  SetResult(Value::CreateStringValue(GetWebstoreLogin(profile_)));
+  results_ = GetStoreLogin::Results::Create(GetWebstoreLogin(profile_));
   return true;
 }
 
 bool WebstorePrivateSetStoreLoginFunction::RunImpl() {
-  std::string login;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &login));
-  SetWebstoreLogin(profile_, login);
+  scoped_ptr<SetStoreLogin::Params> params(
+      SetStoreLogin::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+  SetWebstoreLogin(profile_, params->login);
   return true;
 }
 
@@ -662,8 +634,8 @@
     ~WebstorePrivateGetWebGLStatusFunction() {}
 
 void WebstorePrivateGetWebGLStatusFunction::CreateResult(bool webgl_allowed) {
-  SetResult(Value::CreateStringValue(
-      webgl_allowed ? "webgl_allowed" : "webgl_blocked"));
+  results_ = GetWebGLStatus::Results::Create(GetWebGLStatus::Results::
+      ParseWebgl_status(webgl_allowed ? "webgl_allowed" : "webgl_blocked"));
 }
 
 bool WebstorePrivateGetWebGLStatusFunction::RunImpl() {
@@ -678,15 +650,14 @@
 }
 
 bool WebstorePrivateGetIsLauncherEnabledFunction::RunImpl() {
-  SetResult(Value::CreateBooleanValue(apps::IsAppLauncherEnabled()));
-  SendResponse(true);
+  results_ = GetIsLauncherEnabled::Results::Create(
+      apps::IsAppLauncherEnabled());
   return true;
 }
 
 bool WebstorePrivateIsInIncognitoModeFunction::RunImpl() {
-  SetResult(
-      Value::CreateBooleanValue(profile_ != profile_->GetOriginalProfile()));
-  SendResponse(true);
+  results_ = IsInIncognitoMode::Results::Create(
+      profile_ != profile_->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 19320bf..a28fa79 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/extensions/webstore_install_helper.h"
 #include "chrome/browser/extensions/webstore_installer.h"
 #include "chrome/browser/signin/signin_tracker.h"
+#include "chrome/common/extensions/api/webstore_private.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -62,8 +63,9 @@
   virtual bool RunImpl() OVERRIDE;
 
   // Reads the extension |details| into |items|.
-  bool ReadBundleInfo(base::ListValue* details,
-                      extensions::BundleInstaller::ItemList* items);
+  bool ReadBundleInfo(
+      const api::webstore_private::InstallBundle::Params& details,
+          extensions::BundleInstaller::ItemList* items);
 
  private:
   scoped_refptr<extensions::BundleInstaller> bundle_;
@@ -145,13 +147,10 @@
   // Called when signin is complete or not needed.
   void SigninCompletedOrNotNeeded();
 
+  const char* ResultCodeToString(ResultCode code);
+
   // These store the input parameters to the function.
-  std::string id_;
-  std::string manifest_;
-  std::string icon_data_;
-  std::string localized_name_;
-  bool use_app_installed_bubble_;
-  bool enable_launcher_;
+  scoped_ptr<api::webstore_private::BeginInstallWithManifest3::Params> params_;
 
   // The results of parsing manifest_ and icon_data_ go into these two.
   scoped_ptr<base::DictionaryValue> parsed_manifest_;
@@ -194,7 +193,7 @@
 };
 
 class WebstorePrivateEnableAppLauncherFunction
-    : public AsyncExtensionFunction {
+    : public SyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.enableAppLauncher",
                              WEBSTOREPRIVATE_ENABLEAPPLAUNCHER)
@@ -266,7 +265,7 @@
 };
 
 class WebstorePrivateGetIsLauncherEnabledFunction
-    : public AsyncExtensionFunction {
+    : public SyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.getIsLauncherEnabled",
                              WEBSTOREPRIVATE_GETISLAUNCHERENABLED)
@@ -283,7 +282,7 @@
   void OnIsLauncherCheckCompleted(bool is_enabled);
 };
 
-class WebstorePrivateIsInIncognitoModeFunction : public AsyncExtensionFunction {
+class WebstorePrivateIsInIncognitoModeFunction : public SyncExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("webstorePrivate.isInIncognitoMode",
                              WEBSTOREPRIVATE_ISININCOGNITOMODEFUNCTION)
diff --git a/chrome/browser/extensions/api/webview/OWNERS b/chrome/browser/extensions/api/webview/OWNERS
new file mode 100644
index 0000000..057dbdc
--- /dev/null
+++ b/chrome/browser/extensions/api/webview/OWNERS
@@ -0,0 +1,2 @@
+fsamuel@chromium.org
+lazyboy@chromium.org
diff --git a/chrome/browser/extensions/api/webview/webview_api.cc b/chrome/browser/extensions/api/webview/webview_api.cc
index b26b746..706e4ac 100644
--- a/chrome/browser/extensions/api/webview/webview_api.cc
+++ b/chrome/browser/extensions/api/webview/webview_api.cc
@@ -4,16 +4,132 @@
 
 #include "chrome/browser/extensions/api/webview/webview_api.h"
 
+#include "chrome/browser/extensions/api/browsing_data/browsing_data_api.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/guestview/webview/webview_guest.h"
 #include "chrome/common/extensions/api/webview.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/common/error_utils.h"
 
 using extensions::api::tabs::InjectDetails;
+namespace webview = extensions::api::webview;
+
+namespace {
+int MaskForKey(const char* key) {
+  if (strcmp(key, extension_browsing_data_api_constants::kAppCacheKey) == 0)
+    return content::StoragePartition::REMOVE_DATA_MASK_APPCACHE;
+  if (strcmp(key, extension_browsing_data_api_constants::kCookiesKey) == 0)
+    return content::StoragePartition::REMOVE_DATA_MASK_COOKIES;
+  if (strcmp(key, extension_browsing_data_api_constants::kFileSystemsKey) == 0)
+    return content::StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
+  if (strcmp(key, extension_browsing_data_api_constants::kIndexedDBKey) == 0)
+    return content::StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
+  if (strcmp(key, extension_browsing_data_api_constants::kLocalStorageKey) == 0)
+    return content::StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
+  if (strcmp(key, extension_browsing_data_api_constants::kWebSQLKey) == 0)
+    return content::StoragePartition::REMOVE_DATA_MASK_WEBSQL;
+  return 0;
+}
+
+}  // namespace
+
+WebviewClearDataFunction::WebviewClearDataFunction()
+    : remove_mask_(0),
+      bad_message_(false) {
+};
+
+WebviewClearDataFunction::~WebviewClearDataFunction() {
+};
+
+// Parses the |dataToRemove| argument to generate the remove mask. Sets
+// |bad_message_| (like EXTENSION_FUNCTION_VALIDATE would if this were a bool
+// method) if 'dataToRemove' is not present.
+uint32 WebviewClearDataFunction::GetRemovalMask() {
+  base::DictionaryValue* data_to_remove;
+  if (!args_->GetDictionary(2, &data_to_remove)) {
+    bad_message_ = true;
+    return 0;
+  }
+
+  uint32 remove_mask = 0;
+  for (base::DictionaryValue::Iterator i(*data_to_remove);
+       !i.IsAtEnd();
+       i.Advance()) {
+    bool selected = false;
+    if (!i.value().GetAsBoolean(&selected)) {
+      bad_message_ = true;
+      return 0;
+    }
+    if (selected)
+      remove_mask |= MaskForKey(i.key().c_str());
+  }
+
+  return remove_mask;
+}
+
+// TODO(lazyboy): Parameters in this extension function are similar (or a
+// sub-set) to BrowsingDataRemoverFunction. How can we share this code?
+bool WebviewClearDataFunction::RunImpl() {
+  int instance_id = 0;
+  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
+
+  // Grab the initial |options| parameter, and parse out the arguments.
+  base::DictionaryValue* options;
+  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &options));
+  DCHECK(options);
+
+  // If |ms_since_epoch| isn't set, default it to 0.
+  double ms_since_epoch;
+  if (!options->GetDouble(extension_browsing_data_api_constants::kSinceKey,
+                          &ms_since_epoch)) {
+    ms_since_epoch = 0;
+  }
+
+  // base::Time takes a double that represents seconds since epoch. JavaScript
+  // gives developers milliseconds, so do a quick conversion before populating
+  // the object. Also, Time::FromDoubleT converts double time 0 to empty Time
+  // object. So we need to do special handling here.
+  remove_since_ = (ms_since_epoch == 0) ?
+      base::Time::UnixEpoch() :
+      base::Time::FromDoubleT(ms_since_epoch / 1000.0);
+
+  remove_mask_ = GetRemovalMask();
+  if (bad_message_)
+    return false;
+
+  WebViewGuest* guest = WebViewGuest::From(
+      render_view_host()->GetProcess()->GetID(), instance_id);
+  if (!guest)
+    return false;
+
+  AddRef();  // Balanced below or in WebviewClearDataFunction::Done().
+
+  bool scheduled = false;
+  if (remove_mask_) {
+    scheduled = guest->ClearData(
+        remove_since_,
+        remove_mask_,
+        base::Bind(&WebviewClearDataFunction::ClearDataDone,
+                   this));
+  }
+  if (!remove_mask_ || !scheduled) {
+    SendResponse(false);
+    Release();  // Balanced above.
+    return false;
+  }
+
+  // Will finish asynchronously.
+  return true;
+}
+
+void WebviewClearDataFunction::ClearDataDone() {
+  Release();  // Balanced in RunImpl().
+  SendResponse(true);
+}
 
 WebviewExecuteCodeFunction::WebviewExecuteCodeFunction()
     : guest_instance_id_(0) {
@@ -93,18 +209,15 @@
 }
 
 bool WebviewGoFunction::RunImpl() {
-  int instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
-
-  int relative_index = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &relative_index));
+  scoped_ptr<webview::Go::Params> params(webview::Go::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebViewGuest* guest = WebViewGuest::From(
-      render_view_host()->GetProcess()->GetID(), instance_id);
+      render_view_host()->GetProcess()->GetID(), params->instance_id);
   if (!guest)
     return false;
 
-  guest->Go(relative_index);
+  guest->Go(params->relative_index);
   return true;
 }
 
@@ -115,11 +228,12 @@
 }
 
 bool WebviewReloadFunction::RunImpl() {
-  int instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
+  scoped_ptr<webview::Reload::Params> params(
+      webview::Reload::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebViewGuest* guest = WebViewGuest::From(
-      render_view_host()->GetProcess()->GetID(), instance_id);
+      render_view_host()->GetProcess()->GetID(), params->instance_id);
   if (!guest)
     return false;
 
@@ -134,25 +248,19 @@
 }
 
 bool WebviewSetPermissionFunction::RunImpl() {
-  int instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
-
-  int request_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &request_id));
-
-  bool should_allow = false;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(2, &should_allow));
-
-  std::string user_input;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &user_input));
+  scoped_ptr<webview::SetPermission::Params> params(
+      webview::SetPermission::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebViewGuest* guest = WebViewGuest::From(
-      render_view_host()->GetProcess()->GetID(), instance_id);
+      render_view_host()->GetProcess()->GetID(), params->instance_id);
   if (!guest)
     return false;
 
   EXTENSION_FUNCTION_VALIDATE(
-      guest->SetPermission(request_id, should_allow, user_input));
+      guest->SetPermission(params->request_id,
+                           params->should_allow,
+                           params->user_input));
   return true;
 }
 
@@ -163,11 +271,12 @@
 }
 
 bool WebviewStopFunction::RunImpl() {
-  int instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
+  scoped_ptr<webview::Stop::Params> params(
+      webview::Stop::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebViewGuest* guest = WebViewGuest::From(
-      render_view_host()->GetProcess()->GetID(), instance_id);
+      render_view_host()->GetProcess()->GetID(), params->instance_id);
   if (!guest)
     return false;
 
@@ -182,11 +291,12 @@
 }
 
 bool WebviewTerminateFunction::RunImpl() {
-  int instance_id = 0;
-  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &instance_id));
+  scoped_ptr<webview::Terminate::Params> params(
+      webview::Terminate::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
 
   WebViewGuest* guest = WebViewGuest::From(
-      render_view_host()->GetProcess()->GetID(), instance_id);
+      render_view_host()->GetProcess()->GetID(), params->instance_id);
   if (!guest)
     return false;
 
diff --git a/chrome/browser/extensions/api/webview/webview_api.h b/chrome/browser/extensions/api/webview/webview_api.h
index f988ce2..46f3b94 100644
--- a/chrome/browser/extensions/api/webview/webview_api.h
+++ b/chrome/browser/extensions/api/webview/webview_api.h
@@ -7,6 +7,32 @@
 
 #include "chrome/browser/extensions/api/execute_code_function.h"
 
+class WebviewClearDataFunction : public AsyncExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("webview.clearData", WEBVIEW_CLEARDATA);
+
+  WebviewClearDataFunction();
+
+ protected:
+  virtual ~WebviewClearDataFunction();
+
+  // ExtensionFunction implementation.
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  uint32 GetRemovalMask();
+  void ClearDataDone();
+
+  // Removal start time.
+  base::Time remove_since_;
+  // Removal mask, corresponds to StoragePartition::RemoveDataMask enum.
+  uint32 remove_mask_;
+  // Tracks any data related or parse errors.
+  bool bad_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewClearDataFunction);
+};
+
 class WebviewExecuteCodeFunction : public extensions::ExecuteCodeFunction {
  public:
   WebviewExecuteCodeFunction();
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index b1a2b08..380ba1c 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/process_map.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -660,24 +659,16 @@
       browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
 
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-  BlockedContentTabHelper* blocked_content_tab_helper =
-      BlockedContentTabHelper::FromWebContents(tab);
   PopupBlockerTabHelper* popup_blocker_tab_helper =
       PopupBlockerTabHelper::FromWebContents(tab);
-  if (!blocked_content_tab_helper->GetBlockedContentsCount() &&
-      (!popup_blocker_tab_helper ||
-       !popup_blocker_tab_helper->GetBlockedPopupsCount())) {
+  if (!popup_blocker_tab_helper->GetBlockedPopupsCount()) {
     content::WindowedNotificationObserver observer(
         chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
         content::NotificationService::AllSources());
     observer.Wait();
   }
 
-  EXPECT_EQ(1u,
-            blocked_content_tab_helper->GetBlockedContentsCount() +
-                (popup_blocker_tab_helper
-                     ? popup_blocker_tab_helper->GetBlockedPopupsCount()
-                     : 0));
+  EXPECT_EQ(1u, popup_blocker_tab_helper->GetBlockedPopupsCount());
 }
 
 // Tests that if an extension launches an app via chrome.tabs.create with an URL
diff --git a/chrome/browser/extensions/blacklist.cc b/chrome/browser/extensions/blacklist.cc
index e0f6dbb..902bbcd 100644
--- a/chrome/browser/extensions/blacklist.cc
+++ b/chrome/browser/extensions/blacklist.cc
@@ -10,6 +10,7 @@
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/prefs/pref_service.h"
+#include "base/stl_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_prefs.h"
@@ -217,16 +218,12 @@
 
   std::set<std::string> from_prefs = prefs_->GetBlacklistedExtensions();
 
-  std::set<std::string> no_longer_blacklisted;
-  std::set_difference(from_prefs.begin(), from_prefs.end(),
-                      ids_as_set.begin(), ids_as_set.end(),
-                      std::inserter(no_longer_blacklisted,
-                                    no_longer_blacklisted.begin()));
-  std::set<std::string> not_yet_blacklisted;
-  std::set_difference(ids_as_set.begin(), ids_as_set.end(),
-                      from_prefs.begin(), from_prefs.end(),
-                      std::inserter(not_yet_blacklisted,
-                                    not_yet_blacklisted.begin()));
+  std::set<std::string> no_longer_blacklisted =
+      base::STLSetDifference<std::set<std::string> >(from_prefs,
+                                                     ids_as_set);
+  std::set<std::string> not_yet_blacklisted =
+      base::STLSetDifference<std::set<std::string> >(ids_as_set,
+                                                     from_prefs);
 
   for (std::set<std::string>::iterator it = no_longer_blacklisted.begin();
        it != no_longer_blacklisted.end(); ++it) {
diff --git a/chrome/browser/extensions/browser_event_router.cc b/chrome/browser/extensions/browser_event_router.cc
index ebbb8d0..c9a9b07 100644
--- a/chrome/browser/extensions/browser_event_router.cc
+++ b/chrome/browser/extensions/browser_event_router.cc
@@ -7,12 +7,9 @@
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/api/extension_action/extension_page_actions_api_constants.h"
 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
-#include "chrome/browser/extensions/event_names.h"
-#include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
@@ -22,7 +19,6 @@
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_controller.h"
@@ -31,15 +27,15 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
 
-namespace events = extensions::event_names;
 namespace tab_keys = extensions::tabs_constants;
-namespace page_actions_keys = extension_page_actions_api_constants;
 
 using content::NavigationController;
 using content::WebContents;
 
 namespace extensions {
 
+namespace tabs = api::tabs;
+
 BrowserEventRouter::TabEntry::TabEntry()
     : complete_waiting_on_load_(false),
       url_() {
@@ -178,7 +174,7 @@
                                       bool active) {
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  scoped_ptr<Event> event(new Event(events::kOnTabCreated, args.Pass()));
+  scoped_ptr<Event> event(new Event(tabs::OnCreated::kEventName, args.Pass()));
   event->restrict_to_profile = profile;
   event->user_gesture = EventRouter::USER_GESTURE_NOT_ENABLED;
   event->will_dispatch_callback =
@@ -201,17 +197,17 @@
   }
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateIntegerValue(tab_id));
+  args->Append(new base::FundamentalValue(tab_id));
 
   DictionaryValue* object_args = new DictionaryValue();
-  object_args->Set(tab_keys::kNewWindowIdKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kNewWindowIdKey, new base::FundamentalValue(
       ExtensionTabUtil::GetWindowIdOfTab(contents)));
-  object_args->Set(tab_keys::kNewPositionKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kNewPositionKey, new base::FundamentalValue(
       index));
   args->Append(object_args);
 
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  DispatchEvent(profile, events::kOnTabAttached, args.Pass(),
+  DispatchEvent(profile, tabs::OnAttached::kEventName, args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
 }
 
@@ -222,17 +218,18 @@
   }
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
+  args->Append(
+      new base::FundamentalValue(ExtensionTabUtil::GetTabId(contents)));
 
   DictionaryValue* object_args = new DictionaryValue();
-  object_args->Set(tab_keys::kOldWindowIdKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kOldWindowIdKey, new base::FundamentalValue(
       ExtensionTabUtil::GetWindowIdOfTab(contents)));
-  object_args->Set(tab_keys::kOldPositionKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kOldPositionKey, new base::FundamentalValue(
       index));
   args->Append(object_args);
 
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  DispatchEvent(profile, events::kOnTabDetached, args.Pass(),
+  DispatchEvent(profile, tabs::OnDetached::kEventName, args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
 }
 
@@ -242,7 +239,7 @@
   int tab_id = ExtensionTabUtil::GetTabId(contents);
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateIntegerValue(tab_id));
+  args->Append(new base::FundamentalValue(tab_id));
 
   DictionaryValue* object_args = new DictionaryValue();
   object_args->SetInteger(tab_keys::kWindowIdKey,
@@ -252,7 +249,7 @@
   args->Append(object_args);
 
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  DispatchEvent(profile, events::kOnTabRemoved, args.Pass(),
+  DispatchEvent(profile, tabs::OnRemoved::kEventName, args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
 
   int removed_count = tab_entries_.erase(tab_id);
@@ -267,10 +264,10 @@
                                           int reason) {
   scoped_ptr<base::ListValue> args(new base::ListValue());
   int tab_id = ExtensionTabUtil::GetTabId(new_contents);
-  args->Append(Value::CreateIntegerValue(tab_id));
+  args->Append(new base::FundamentalValue(tab_id));
 
   DictionaryValue* object_args = new DictionaryValue();
-  object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kWindowIdKey, new base::FundamentalValue(
       ExtensionTabUtil::GetWindowIdOfTab(new_contents)));
   args->Append(object_args);
 
@@ -282,15 +279,15 @@
       reason & CHANGE_REASON_USER_GESTURE
       ? EventRouter::USER_GESTURE_ENABLED
       : EventRouter::USER_GESTURE_NOT_ENABLED;
-  DispatchEvent(profile, events::kOnTabSelectionChanged,
+  DispatchEvent(profile, tabs::OnSelectionChanged::kEventName,
                 scoped_ptr<base::ListValue>(args->DeepCopy()), gesture);
-  DispatchEvent(profile, events::kOnTabActiveChanged,
+  DispatchEvent(profile, tabs::OnActiveChanged::kEventName,
                 scoped_ptr<base::ListValue>(args->DeepCopy()), gesture);
 
   // The onActivated event takes one argument: {windowId, tabId}.
   args->Remove(0, NULL);
-  object_args->Set(tab_keys::kTabIdKey, Value::CreateIntegerValue(tab_id));
-  DispatchEvent(profile, events::kOnTabActivated, args.Pass(), gesture);
+  object_args->Set(tab_keys::kTabIdKey, new base::FundamentalValue(tab_id));
+  DispatchEvent(profile, tabs::OnActivated::kEventName, args.Pass(), gesture);
 }
 
 void BrowserEventRouter::TabSelectionChanged(
@@ -306,13 +303,13 @@
     if (!contents)
       break;
     int tab_id = ExtensionTabUtil::GetTabId(contents);
-    all->Append(Value::CreateIntegerValue(tab_id));
+    all->Append(new base::FundamentalValue(tab_id));
   }
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
   DictionaryValue* select_info = new DictionaryValue();
 
-  select_info->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
+  select_info->Set(tab_keys::kWindowIdKey, new base::FundamentalValue(
       ExtensionTabUtil::GetWindowIdOfTabStripModel(tab_strip_model)));
 
   select_info->Set(tab_keys::kTabIdsKey, all);
@@ -320,10 +317,10 @@
 
   // The onHighlighted event replaced onHighlightChanged.
   Profile* profile = tab_strip_model->profile();
-  DispatchEvent(profile, events::kOnTabHighlightChanged,
+  DispatchEvent(profile, tabs::OnHighlightChanged::kEventName,
                 scoped_ptr<base::ListValue>(args->DeepCopy()),
                 EventRouter::USER_GESTURE_UNKNOWN);
-  DispatchEvent(profile, events::kOnTabHighlighted, args.Pass(),
+  DispatchEvent(profile, tabs::OnHighlighted::kEventName, args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
 }
 
@@ -331,19 +328,20 @@
                                   int from_index,
                                   int to_index) {
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateIntegerValue(ExtensionTabUtil::GetTabId(contents)));
+  args->Append(
+      new base::FundamentalValue(ExtensionTabUtil::GetTabId(contents)));
 
   DictionaryValue* object_args = new DictionaryValue();
-  object_args->Set(tab_keys::kWindowIdKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kWindowIdKey, new base::FundamentalValue(
       ExtensionTabUtil::GetWindowIdOfTab(contents)));
-  object_args->Set(tab_keys::kFromIndexKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kFromIndexKey, new base::FundamentalValue(
       from_index));
-  object_args->Set(tab_keys::kToIndexKey, Value::CreateIntegerValue(
+  object_args->Set(tab_keys::kToIndexKey, new base::FundamentalValue(
       to_index));
   args->Append(object_args);
 
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
-  DispatchEvent(profile, events::kOnTabMoved, args.Pass(),
+  DispatchEvent(profile, tabs::OnMoved::kEventName, args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
 }
 
@@ -367,7 +365,7 @@
     if (!icon_url_changed || !*icon_url_changed)
       return;
     content::NavigationEntry* entry =
-        contents->GetController().GetActiveEntry();
+        contents->GetController().GetVisibleEntry();
     if (!entry || !entry->GetFavicon().valid)
       return;
     scoped_ptr<DictionaryValue> changed_properties(new DictionaryValue());
@@ -392,30 +390,13 @@
   ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
 }
 
-void BrowserEventRouter::DispatchEventToExtension(
-    Profile* profile,
-    const std::string& extension_id,
-    const char* event_name,
-    scoped_ptr<base::ListValue> event_args,
-    EventRouter::UserGestureState user_gesture) {
-  if (!profile_->IsSameProfile(profile) ||
-      !extensions::ExtensionSystem::Get(profile)->event_router())
-    return;
-
-  scoped_ptr<Event> event(new Event(event_name, event_args.Pass()));
-  event->restrict_to_profile = profile;
-  event->user_gesture = user_gesture;
-  ExtensionSystem::Get(profile)->event_router()->
-      DispatchEventToExtension(extension_id, event.Pass());
-}
-
 void BrowserEventRouter::DispatchSimpleBrowserEvent(
     Profile* profile, const int window_id, const char* event_name) {
   if (!profile_->IsSameProfile(profile))
     return;
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateIntegerValue(window_id));
+  args->Append(new base::FundamentalValue(window_id));
 
   DispatchEvent(profile, event_name, args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
@@ -460,7 +441,8 @@
   // WillDispatchTabUpdatedEvent.
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
 
-  scoped_ptr<Event> event(new Event(events::kOnTabUpdated, args_base.Pass()));
+  scoped_ptr<Event> event(new Event(tabs::OnUpdated::kEventName,
+      args_base.Pass()));
   event->restrict_to_profile = profile;
   event->user_gesture = EventRouter::USER_GESTURE_NOT_ENABLED;
   event->will_dispatch_callback =
@@ -518,11 +500,11 @@
   const int new_tab_id = ExtensionTabUtil::GetTabId(new_contents);
   const int old_tab_id = ExtensionTabUtil::GetTabId(old_contents);
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateIntegerValue(new_tab_id));
-  args->Append(Value::CreateIntegerValue(old_tab_id));
+  args->Append(new base::FundamentalValue(new_tab_id));
+  args->Append(new base::FundamentalValue(old_tab_id));
 
   DispatchEvent(Profile::FromBrowserContext(new_contents->GetBrowserContext()),
-                events::kOnTabReplaced,
+                tabs::OnReplaced::kEventName,
                 args.Pass(),
                 EventRouter::USER_GESTURE_UNKNOWN);
 
@@ -552,97 +534,4 @@
 
 void BrowserEventRouter::TabStripEmpty() {}
 
-void BrowserEventRouter::DispatchOldPageActionEvent(
-    Profile* profile,
-    const std::string& extension_id,
-    const std::string& page_action_id,
-    int tab_id,
-    const std::string& url,
-    int button) {
-  scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateStringValue(page_action_id));
-
-  DictionaryValue* data = new DictionaryValue();
-  data->Set(tab_keys::kTabIdKey, Value::CreateIntegerValue(tab_id));
-  data->Set(tab_keys::kTabUrlKey, Value::CreateStringValue(url));
-  data->Set(page_actions_keys::kButtonKey,
-            Value::CreateIntegerValue(button));
-  args->Append(data);
-
-  DispatchEventToExtension(profile, extension_id, "pageActions", args.Pass(),
-                           EventRouter::USER_GESTURE_ENABLED);
-}
-
-void BrowserEventRouter::BrowserActionExecuted(
-    const ExtensionAction& browser_action,
-    Browser* browser) {
-  Profile* profile = browser->profile();
-  WebContents* web_contents = NULL;
-  int tab_id = 0;
-  if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
-    return;
-  ExtensionActionExecuted(profile, browser_action, web_contents);
-}
-
-void BrowserEventRouter::PageActionExecuted(Profile* profile,
-                                            const ExtensionAction& page_action,
-                                            int tab_id,
-                                            const std::string& url,
-                                            int button) {
-  DispatchOldPageActionEvent(profile, page_action.extension_id(),
-                             page_action.id(), tab_id, url, button);
-  WebContents* web_contents = NULL;
-  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
-                                    NULL, NULL, &web_contents, NULL)) {
-    return;
-  }
-  ExtensionActionExecuted(profile, page_action, web_contents);
-}
-
-void BrowserEventRouter::ScriptBadgeExecuted(
-    Profile* profile,
-    const ExtensionAction& script_badge,
-    int tab_id) {
-  WebContents* web_contents = NULL;
-  if (!ExtensionTabUtil::GetTabById(tab_id, profile, profile->IsOffTheRecord(),
-                                    NULL, NULL, &web_contents, NULL)) {
-    return;
-  }
-  ExtensionActionExecuted(profile, script_badge, web_contents);
-}
-
-void BrowserEventRouter::ExtensionActionExecuted(
-    Profile* profile,
-    const ExtensionAction& extension_action,
-    WebContents* web_contents) {
-  const char* event_name = NULL;
-  switch (extension_action.action_type()) {
-    case ActionInfo::TYPE_BROWSER:
-      event_name = "browserAction.onClicked";
-      break;
-    case ActionInfo::TYPE_PAGE:
-      event_name = "pageAction.onClicked";
-      break;
-    case ActionInfo::TYPE_SCRIPT_BADGE:
-      event_name = "scriptBadge.onClicked";
-      break;
-    case ActionInfo::TYPE_SYSTEM_INDICATOR:
-      // The System Indicator handles its own clicks.
-      break;
-  }
-
-  if (event_name) {
-    scoped_ptr<base::ListValue> args(new base::ListValue());
-    DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(
-        web_contents);
-    args->Append(tab_value);
-
-    DispatchEventToExtension(profile,
-                             extension_action.extension_id(),
-                             event_name,
-                             args.Pass(),
-                             EventRouter::USER_GESTURE_ENABLED);
-  }
-}
-
 }  // namespace extensions
diff --git a/chrome/browser/extensions/browser_event_router.h b/chrome/browser/extensions/browser_event_router.h
index f424f57..7450ccb 100644
--- a/chrome/browser/extensions/browser_event_router.h
+++ b/chrome/browser/extensions/browser_event_router.h
@@ -12,7 +12,6 @@
 #include "base/compiler_specific.h"
 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
 #include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_toolbar_model.h"
 #include "chrome/browser/ui/browser_list_observer.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -69,22 +68,6 @@
                                      int index) OVERRIDE;
   virtual void TabStripEmpty() OVERRIDE;
 
-  // Fires the onClicked event for page_action.
-  void PageActionExecuted(Profile* profile,
-                          const ExtensionAction& page_action,
-                          int tab_id,
-                          const std::string& url,
-                          int button);
-
-  // Fires the onClicked event for script_badge.
-  void ScriptBadgeExecuted(Profile* profile,
-                           const ExtensionAction& script_badge,
-                           int tab_id);
-
-  // Fires the onClicked event for browser_action.
-  void BrowserActionExecuted(const ExtensionAction& browser_action,
-                             Browser* browser);
-
   // content::NotificationObserver.
   virtual void Observe(int type,
                        const content::NotificationSource& source,
@@ -109,12 +92,6 @@
                      scoped_ptr<base::ListValue> args,
                      EventRouter::UserGestureState user_gesture);
 
-  void DispatchEventToExtension(Profile* profile,
-                                const std::string& extension_id,
-                                const char* event_name,
-                                scoped_ptr<base::ListValue> event_args,
-                                EventRouter::UserGestureState user_gesture);
-
   void DispatchEventsAcrossIncognito(
       Profile* profile,
       const char* event_name,
@@ -130,16 +107,6 @@
   void DispatchTabUpdatedEvent(content::WebContents* contents,
                                scoped_ptr<DictionaryValue> changed_properties);
 
-  // Called to dispatch a deprecated style page action click event that was
-  // registered like:
-  //   chrome.pageActions["name"].addListener(function(actionId, info){})
-  void DispatchOldPageActionEvent(Profile* profile,
-    const std::string& extension_id,
-    const std::string& page_action_id,
-    int tab_id,
-    const std::string& url,
-    int button);
-
   // Register ourselves to receive the various notifications we are interested
   // in for a browser.
   void RegisterForBrowserNotifications(Browser* browser);
@@ -192,12 +159,6 @@
   // found, NULL if not.
   TabEntry* GetTabEntry(const content::WebContents* contents);
 
-  // Called when either a browser or page action is executed. Figures out which
-  // event to send based on what the extension wants.
-  void ExtensionActionExecuted(Profile* profile,
-                               const ExtensionAction& extension_action,
-                               content::WebContents* web_contents);
-
   std::map<int, TabEntry> tab_entries_;
 
   // The main profile that owns this event router.
diff --git a/chrome/browser/extensions/chrome_app_api_browsertest.cc b/chrome/browser/extensions/chrome_app_api_browsertest.cc
index 97f923d..1c5e417 100644
--- a/chrome/browser/extensions/chrome_app_api_browsertest.cc
+++ b/chrome/browser/extensions/chrome_app_api_browsertest.cc
@@ -16,10 +16,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/manifest.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "extensions/common/manifest.h"
 #include "net/dns/mock_host_resolver.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 36d6be5..5187b94 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -20,11 +20,11 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "extensions/common/id_util.h"
+#include "extensions/common/manifest_constants.h"
 #include "grit/browser_resources.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -86,11 +86,11 @@
   return l10n_util::GetStringUTF8(string_id);
 }
 
-std::string GenerateId(const DictionaryValue* manifest,
+std::string GenerateId(const base::DictionaryValue* manifest,
                        const base::FilePath& path) {
   std::string raw_key;
   std::string id_input;
-  CHECK(manifest->GetString(extension_manifest_keys::kPublicKey, &raw_key));
+  CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key));
   CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input));
   std::string id = id_util::GenerateId(id_input);
   return id;
@@ -99,7 +99,7 @@
 }  // namespace
 
 ComponentLoader::ComponentExtensionInfo::ComponentExtensionInfo(
-    const DictionaryValue* manifest, const base::FilePath& directory)
+    const base::DictionaryValue* manifest, const base::FilePath& directory)
     : manifest(manifest),
       root_directory(directory) {
   if (!root_directory.IsAbsolute()) {
@@ -128,17 +128,17 @@
   }
 }
 
-DictionaryValue* ComponentLoader::ParseManifest(
+base::DictionaryValue* ComponentLoader::ParseManifest(
     const std::string& manifest_contents) const {
   JSONStringValueSerializer serializer(manifest_contents);
-  scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
+  scoped_ptr<base::Value> manifest(serializer.Deserialize(NULL, NULL));
 
-  if (!manifest.get() || !manifest->IsType(Value::TYPE_DICTIONARY)) {
+  if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) {
     LOG(ERROR) << "Failed to parse extension manifest.";
     return NULL;
   }
   // Transfer ownership to the caller.
-  return static_cast<DictionaryValue*>(manifest.release());
+  return static_cast<base::DictionaryValue*>(manifest.release());
 }
 
 void ComponentLoader::ClearAllRegistered() {
@@ -151,6 +151,19 @@
   component_extensions_.clear();
 }
 
+std::string ComponentLoader::GetExtensionID(
+    int manifest_resource_id,
+    const base::FilePath& root_directory) {
+  std::string manifest_contents = ResourceBundle::GetSharedInstance().
+      GetRawDataResource(manifest_resource_id).as_string();
+  base::DictionaryValue* manifest = ParseManifest(manifest_contents);
+  if (!manifest)
+    return std::string();
+
+  ComponentExtensionInfo info(manifest, root_directory);
+  return info.extension_id;
+}
+
 std::string ComponentLoader::Add(int manifest_resource_id,
                                  const base::FilePath& root_directory) {
   std::string manifest_contents =
@@ -163,13 +176,13 @@
                                  const base::FilePath& root_directory) {
   // The Value is kept for the lifetime of the ComponentLoader. This is
   // required in case LoadAll() is called again.
-  DictionaryValue* manifest = ParseManifest(manifest_contents);
+  base::DictionaryValue* manifest = ParseManifest(manifest_contents);
   if (manifest)
     return Add(manifest, root_directory);
   return std::string();
 }
 
-std::string ComponentLoader::Add(const DictionaryValue* parsed_manifest,
+std::string ComponentLoader::Add(const base::DictionaryValue* parsed_manifest,
                                  const base::FilePath& root_directory) {
   ComponentExtensionInfo info(parsed_manifest, root_directory);
   component_extensions_.push_back(info);
@@ -181,7 +194,7 @@
 std::string ComponentLoader::AddOrReplace(const base::FilePath& path) {
   base::FilePath absolute_path = base::MakeAbsoluteFilePath(path);
   std::string error;
-  scoped_ptr<DictionaryValue> manifest(
+  scoped_ptr<base::DictionaryValue> manifest(
       extension_file_util::LoadManifest(absolute_path, &error));
   if (!manifest) {
     LOG(ERROR) << "Could not load extension from '" <<
@@ -226,14 +239,6 @@
   extension_service_->AddComponentExtension(extension.get());
 }
 
-void ComponentLoader::RemoveAll() {
-  RegisteredComponentExtensions::iterator it = component_extensions_.begin();
-  for (; it != component_extensions_.end(); ++it)
-    UnloadComponent(&(*it));
-
-  component_extensions_.clear();
-}
-
 void ComponentLoader::Remove(const base::FilePath& root_directory) {
   // Find the ComponentExtensionInfo for the extension.
   RegisteredComponentExtensions::iterator it = component_extensions_.begin();
@@ -306,11 +311,11 @@
 
   // The Value is kept for the lifetime of the ComponentLoader. This is
   // required in case LoadAll() is called again.
-  DictionaryValue* manifest = ParseManifest(manifest_contents);
+  base::DictionaryValue* manifest = ParseManifest(manifest_contents);
 
   if (manifest) {
     // Update manifest to use a proper name.
-    manifest->SetString(extension_manifest_keys::kName, name);
+    manifest->SetString(manifest_keys::kName, name);
     Add(manifest, root_directory);
   }
 }
@@ -399,8 +404,8 @@
 
   if (!skip_session_components) {
     // Apps Debugger
-    if (CommandLine::ForCurrentProcess()->HasSwitch(
-        switches::kAppsDevtool)) {
+    if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsDevtool) &&
+        profile_prefs_->GetBoolean(prefs::kExtensionsUIDeveloperMode)) {
       Add(IDR_APPS_DEBUGGER_MANIFEST,
           base::FilePath(FILE_PATH_LITERAL("apps_debugger")));
     }
@@ -414,6 +419,10 @@
 #endif
   }
 
+#if defined(GOOGLE_CHROME_BUILD)
+    Add(IDR_FEEDBACK_MANIFEST, base::FilePath(FILE_PATH_LITERAL("feedback")));
+#endif  // defined(GOOGLE_CHROME_BUILD)
+
 #if defined(OS_CHROMEOS)
   if (!skip_session_components) {
     Add(IDR_WALLPAPERMANAGER_MANIFEST,
@@ -470,7 +479,15 @@
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(ENABLE_GOOGLE_NOW)
-  if (base::FieldTrialList::FindFullName("GoogleNow") == "Enable" ||
+  const char kEnablePrefix[] = "Enable";
+  const char kFieldTrialName[] = "GoogleNow";
+  std::string enable_prefix(kEnablePrefix);
+  std::string field_trial_result =
+      base::FieldTrialList::FindFullName(kFieldTrialName);
+  if ((field_trial_result.compare(
+          0,
+          enable_prefix.length(),
+          enable_prefix) == 0) ||
       CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableGoogleNowIntegration)) {
     Add(IDR_GOOGLE_NOW_MANIFEST,
@@ -484,7 +501,7 @@
   if (extension_service_->is_ready()) {
     extension_service_->
         UnloadExtension(component->extension_id,
-                        extension_misc::UNLOAD_REASON_DISABLE);
+                        extension_misc::UNLOAD_REASON_UNINSTALL);
   }
 }
 
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index ea66106..6a7fb86 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -34,10 +34,6 @@
   // Creates and loads all registered component extensions.
   void LoadAll();
 
-  // Clear the list of all registered extensions and unloads them from the
-  // extension service.
-  void RemoveAll();
-
   // Registers and possibly loads a component extension. If ExtensionService
   // has been initialized, the extension is loaded; otherwise, the load is
   // deferred until LoadAll is called. The ID of the added extension is
@@ -60,6 +56,11 @@
   // extension with the same ID.
   std::string AddOrReplace(const base::FilePath& path);
 
+  // Returns the extension ID of a component extension specified by resource
+  // id of its manifest file.
+  std::string GetExtensionID(int manifest_resource_id,
+                             const base::FilePath& root_directory);
+
   // Returns true if an extension with the specified id has been added.
   bool Exists(const std::string& id) const;
 
diff --git a/chrome/browser/extensions/component_loader_unittest.cc b/chrome/browser/extensions/component_loader_unittest.cc
index 307789f..4bf9f52 100644
--- a/chrome/browser/extensions/component_loader_unittest.cc
+++ b/chrome/browser/extensions/component_loader_unittest.cc
@@ -232,24 +232,6 @@
   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
 }
 
-TEST_F(ComponentLoaderTest, RemoveAll) {
-  extension_service_.set_ready(true);
-  EXPECT_EQ(0u, extension_service_.extensions()->size());
-  // Add all the default extensions. Since the extension service is ready, they
-  // will be loaded immediately.
-  component_loader_.AddDefaultComponentExtensions(false);
-  unsigned int default_count = extension_service_.extensions()->size();
-
-  // And add one more just to make sure there is anything in there in case
-  // there are no defaults for this platform.
-  component_loader_.Add(manifest_contents_, extension_path_);
-  EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
-
-  // Remove all default extensions.
-  component_loader_.RemoveAll();
-  EXPECT_EQ(0u, extension_service_.extensions()->size());
-}
-
 TEST_F(ComponentLoaderTest, AddOrReplace) {
   EXPECT_EQ(0u, component_loader_.registered_extensions_count());
   component_loader_.AddDefaultComponentExtensions(false);
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index f6fbea7..4d8b064 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -25,7 +25,7 @@
 #include "extensions/common/user_script.h"
 #include "url/gurl.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace values = extension_manifest_values;
 
 namespace extensions {
@@ -102,7 +102,7 @@
   root->SetBoolean(keys::kConvertedFromUserScript, true);
 
   base::ListValue* js_files = new base::ListValue();
-  js_files->Append(Value::CreateStringValue("script.js"));
+  js_files->Append(new base::StringValue("script.js"));
 
   // If the script provides its own match patterns, we use those. Otherwise, we
   // generate some using the include globs.
@@ -110,12 +110,12 @@
   if (!script.url_patterns().is_empty()) {
     for (URLPatternSet::const_iterator i = script.url_patterns().begin();
          i != script.url_patterns().end(); ++i) {
-      matches->Append(Value::CreateStringValue(i->GetAsString()));
+      matches->Append(new base::StringValue(i->GetAsString()));
     }
   } else {
     // TODO(aa): Derive tighter matches where possible.
-    matches->Append(Value::CreateStringValue("http://*/*"));
-    matches->Append(Value::CreateStringValue("https://*/*"));
+    matches->Append(new base::StringValue("http://*/*"));
+    matches->Append(new base::StringValue("https://*/*"));
   }
 
   // Read the exclude matches, if any are present.
@@ -124,17 +124,17 @@
     for (URLPatternSet::const_iterator i =
          script.exclude_url_patterns().begin();
          i != script.exclude_url_patterns().end(); ++i) {
-      exclude_matches->Append(Value::CreateStringValue(i->GetAsString()));
+      exclude_matches->Append(new base::StringValue(i->GetAsString()));
     }
   }
 
   base::ListValue* includes = new base::ListValue();
   for (size_t i = 0; i < script.globs().size(); ++i)
-    includes->Append(Value::CreateStringValue(script.globs().at(i)));
+    includes->Append(new base::StringValue(script.globs().at(i)));
 
   base::ListValue* excludes = new base::ListValue();
   for (size_t i = 0; i < script.exclude_globs().size(); ++i)
-    excludes->Append(Value::CreateStringValue(script.exclude_globs().at(i)));
+    excludes->Append(new base::StringValue(script.exclude_globs().at(i)));
 
   DictionaryValue* content_script = new DictionaryValue();
   content_script->Set(keys::kMatches, matches);
diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc
index 5f844ab..39c905b 100644
--- a/chrome/browser/extensions/convert_web_app.cc
+++ b/chrome/browser/extensions/convert_web_app.cc
@@ -22,17 +22,17 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/web_application_info.h"
 #include "crypto/sha2.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/manifest_constants.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "url/gurl.h"
 
 namespace extensions {
 
-namespace keys = extension_manifest_keys;
+namespace keys = manifest_keys;
 
 using base::Time;
 
@@ -57,8 +57,7 @@
   return key;
 }
 
-}
-
+}  // namespace
 
 // Generates a version for the converted app using the current date. This isn't
 // really needed, but it seems like useful information.
@@ -133,14 +132,14 @@
   base::ListValue* permissions = new base::ListValue();
   root->Set(keys::kPermissions, permissions);
   for (size_t i = 0; i < web_app.permissions.size(); ++i) {
-    permissions->Append(Value::CreateStringValue(web_app.permissions[i]));
+    permissions->Append(new base::StringValue(web_app.permissions[i]));
   }
 
   // Add the URLs.
   base::ListValue* urls = new base::ListValue();
   root->Set(keys::kWebURLs, urls);
   for (size_t i = 0; i < web_app.urls.size(); ++i) {
-    urls->Append(Value::CreateStringValue(web_app.urls[i].spec()));
+    urls->Append(new base::StringValue(web_app.urls[i].spec()));
   }
 
   // Write the manifest.
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 68d715b..fac1e88 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -38,13 +38,13 @@
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/feature_switch.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/user_script.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index d2bcbbb..1d40e2a 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -18,7 +18,7 @@
 #include "chrome/browser/extensions/sandboxed_unpacker.h"
 #include "chrome/browser/extensions/webstore_installer.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "sync/api/string_ordinal.h"
 
 class ExtensionService;
diff --git a/chrome/browser/extensions/default_apps.h b/chrome/browser/extensions/default_apps.h
index ea41826..7a950e0 100644
--- a/chrome/browser/extensions/default_apps.h
+++ b/chrome/browser/extensions/default_apps.h
@@ -7,7 +7,7 @@
 
 #include "base/basictypes.h"
 #include "chrome/browser/extensions/external_provider_impl.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class Profile;
 
diff --git a/chrome/browser/extensions/event_listener_map_unittest.cc b/chrome/browser/extensions/event_listener_map_unittest.cc
index d1b657f..1b2959c 100644
--- a/chrome/browser/extensions/event_listener_map_unittest.cc
+++ b/chrome/browser/extensions/event_listener_map_unittest.cc
@@ -6,8 +6,8 @@
 
 #include "chrome/browser/extensions/event_listener_map.h"
 #include "chrome/browser/extensions/event_router.h"
+#include "chrome/test/base/testing_profile.h"
 #include "content/public/test/mock_render_process_host.h"
-#include "content/public/test/test_browser_context.h"
 
 using base::DictionaryValue;
 using base::ListValue;
@@ -32,8 +32,8 @@
   EventListenerMapUnittest()
     : delegate_(new EmptyDelegate),
       listeners_(new EventListenerMap(delegate_.get())),
-      browser_context_(new content::TestBrowserContext),
-      process_(new content::MockRenderProcessHost(browser_context_.get())) {
+      profile_(new TestingProfile),
+      process_(new content::MockRenderProcessHost(profile_.get())) {
   }
 
   scoped_ptr<DictionaryValue> CreateHostSuffixFilter(
@@ -66,7 +66,7 @@
  protected:
   scoped_ptr<EventListenerMap::Delegate> delegate_;
   scoped_ptr<EventListenerMap> listeners_;
-  scoped_ptr<content::TestBrowserContext> browser_context_;
+  scoped_ptr<TestingProfile> profile_;
   scoped_ptr<content::MockRenderProcessHost> process_;
 };
 
diff --git a/chrome/browser/extensions/event_names.cc b/chrome/browser/extensions/event_names.cc
index 2fb55be..5c59a39 100644
--- a/chrome/browser/extensions/event_names.cc
+++ b/chrome/browser/extensions/event_names.cc
@@ -8,28 +8,6 @@
 
 namespace event_names {
 
-const char kOnTabActivated[] = "tabs.onActivated";
-const char kOnTabActiveChanged[] = "tabs.onActiveChanged";
-const char kOnTabAttached[] = "tabs.onAttached";
-const char kOnTabCreated[] = "tabs.onCreated";
-const char kOnTabDetached[] = "tabs.onDetached";
-const char kOnTabHighlightChanged[] = "tabs.onHighlightChanged";
-const char kOnTabHighlighted[] = "tabs.onHighlighted";
-const char kOnTabMoved[] = "tabs.onMoved";
-const char kOnTabRemoved[] = "tabs.onRemoved";
-const char kOnTabReplaced[] = "tabs.onReplaced";
-const char kOnTabSelectionChanged[] = "tabs.onSelectionChanged";
-const char kOnTabUpdated[] = "tabs.onUpdated";
-
-const char kOnWindowCreated[] = "windows.onCreated";
-const char kOnWindowFocusedChanged[] = "windows.onFocusChanged";
-const char kOnWindowRemoved[] = "windows.onRemoved";
-
-const char kOnExtensionInstalled[] = "management.onInstalled";
-const char kOnExtensionUninstalled[] = "management.onUninstalled";
-const char kOnExtensionEnabled[] = "management.onEnabled";
-const char kOnExtensionDisabled[] = "management.onDisabled";
-
 const char kOnDirectoryChanged[] = "fileBrowserPrivate.onDirectoryChanged";
 const char kOnFileBrowserMountCompleted[] =
     "fileBrowserPrivate.onMountCompleted";
@@ -43,72 +21,20 @@
 const char kOnInputMethodChanged[] = "inputMethodPrivate.onChanged";
 
 const char kOnContextMenus[] = "contextMenus";
-const char kOnContextMenuClicked[] = "contextMenus.onClicked";
-
-const char kOnDialDeviceList[] = "dial.onDeviceList";
-const char kOnDialError[] = "dial.onError";
-
-const char kOnDownloadCreated[] = "downloads.onCreated";
-const char kOnDownloadChanged[] = "downloads.onChanged";
-const char kOnDownloadErased[] = "downloads.onErased";
-const char kOnDownloadDeterminingFilename[] = "downloads.onDeterminingFilename";
-
-const char kOnSettingsChanged[] = "storage.onChanged";
-
-const char kOnTerminalProcessOutput[] = "terminalPrivate.onProcessOutput";
 
 const char kOnOffscreenTabUpdated[] = "experimental.offscreenTabs.onUpdated";
 
-const char kOnTabCaptureStatusChanged[] = "tabCapture.onStatusChanged";
-
-const char kBluetoothOnAdapterStateChanged[] =
-    "bluetooth.onAdapterStateChanged";
-const char kBluetoothOnConnection[] = "bluetooth.onConnection";
 const char kBluetoothOnDeviceDiscovered[] = "bluetooth.onDeviceDiscovered";
 const char kBluetoothOnDeviceSearchFinished[] =
     "bluetooth.onDeviceSearchFinished";
 const char kBluetoothOnDeviceSearchResult[] = "bluetooth.onDeviceSearchResult";
 
-const char kOnPushMessage[] = "pushMessaging.onMessage";
-
 const char kOnDisplayChanged[] = "system.display.onDisplayChanged";
 const char kOnStorageAvailableCapacityChanged[] =
     "system.storage.onAvailableCapacityChanged";
-const char kOnStorageAttached[] = "system.storage.onAttached";
-const char kOnStorageDetached[] = "system.storage.onDetached";
-
-const char kOnSystemIndicatorClicked[] = "systemIndicator.onClicked";
-
-const char kOnServiceStatusChanged[] = "syncFileSystem.onServiceStatusChanged";
-const char kOnFileStatusChanged[] = "syncFileSystem.onFileStatusChanged";
-
-const char kOnAttachEventName[] = "mediaGalleriesPrivate.onDeviceAttached";
-const char kOnDetachEventName[] = "mediaGalleriesPrivate.onDeviceDetached";
-const char kOnGalleryChangedEventName[] =
-    "mediaGalleriesPrivate.onGalleryChanged";
 
 const char kOnNotificationDisplayed[] = "notifications.onDisplayed";
 const char kOnNotificationError[] = "notifications.onError";
-const char kOnNotificationClosed[] = "notifications.onClosed";
-const char kOnNotificationClicked[] = "notifications.onClicked";
-const char kOnNotificationButtonClicked[] = "notifications.onButtonClicked";
-
-const char kOnNetworksChanged[] = "networkingPrivate.onNetworksChanged";
-const char kOnNetworkListChanged[] = "networkingPrivate.onNetworkListChanged";
-
-const char kOnAudioDeviceChanged[] = "audio.onDeviceChanged";
-
-const char kOnLaunched[] = "app.runtime.onLaunched";
-const char kOnRestarted[] = "app.runtime.onRestarted";
-
-const char kOnFeedbackRequested[] = "feedbackPrivate.onFeedbackRequested";
-
-const char kDeveloperPrivateOnItemStateChanged[] =
-    "developerPrivate.onItemStateChanged";
-
-const char kRecoveryOnWriteProgress[] = "recoveryPrivate.onWriteProgress";
-const char kRecoveryOnWriteComplete[] = "recoveryPrivate.onWriteComplete";
-const char kRecoveryOnWriteError[] = "recoveryPrivate.onWriteError";
 
 }  // namespace event_names
 
diff --git a/chrome/browser/extensions/event_names.h b/chrome/browser/extensions/event_names.h
index 9e005e2..0a1ebd6 100644
--- a/chrome/browser/extensions/event_names.h
+++ b/chrome/browser/extensions/event_names.h
@@ -11,31 +11,6 @@
 
 namespace event_names {
 
-// Tabs.
-extern const char kOnTabActivated[];
-extern const char kOnTabActiveChanged[];
-extern const char kOnTabAttached[];
-extern const char kOnTabCreated[];
-extern const char kOnTabDetached[];
-extern const char kOnTabHighlightChanged[];
-extern const char kOnTabHighlighted[];
-extern const char kOnTabMoved[];
-extern const char kOnTabRemoved[];
-extern const char kOnTabReplaced[];
-extern const char kOnTabSelectionChanged[];
-extern const char kOnTabUpdated[];
-
-// Windows.
-extern const char kOnWindowCreated[];
-extern const char kOnWindowFocusedChanged[];
-extern const char kOnWindowRemoved[];
-
-// Management.
-extern const char kOnExtensionInstalled[];
-extern const char kOnExtensionUninstalled[];
-extern const char kOnExtensionEnabled[];
-extern const char kOnExtensionDisabled[];
-
 // FileBrowser.
 extern const char kOnDirectoryChanged[];
 extern const char kOnFileBrowserMountCompleted[];
@@ -49,86 +24,22 @@
 
 // Context menus.
 extern const char kOnContextMenus[];
-extern const char kOnContextMenuClicked[];
-
-// DIAL.
-extern const char kOnDialDeviceList[];
-extern const char kOnDialError[];
-
-// Downloads.
-extern const char kOnDownloadCreated[];
-extern const char kOnDownloadChanged[];
-extern const char kOnDownloadErased[];
-extern const char kOnDownloadDeterminingFilename[];
-
-// Settings.
-extern const char kOnSettingsChanged[];
-
-// TerminalPrivate.
-extern const char kOnTerminalProcessOutput[];
 
 // OffscreenTabs.
 extern const char kOnOffscreenTabUpdated[];
 
-// Tab content capture.
-extern const char kOnTabCaptureStatusChanged[];
-
 // Bluetooth.
-extern const char kBluetoothOnAdapterStateChanged[];
-extern const char kBluetoothOnConnection[];
 extern const char kBluetoothOnDeviceDiscovered[];
 extern const char kBluetoothOnDeviceSearchFinished[];
 extern const char kBluetoothOnDeviceSearchResult[];
 
-// Push messaging.
-extern const char kOnPushMessage[];
-
 // systemInfo event names.
 extern const char kOnDisplayChanged[];
 extern const char kOnStorageAvailableCapacityChanged[];
-extern const char kOnStorageAttached[];
-extern const char kOnStorageDetached[];
-
-// System Indicator icon.
-extern const char kOnSystemIndicatorClicked[];
-
-// SyncFileSystem.
-extern const char kOnServiceStatusChanged[];
-extern const char kOnFileStatusChanged[];
-
-// MediaGalleriesPrivate.
-extern const char kOnAttachEventName[];
-extern const char kOnDetachEventName[];
-extern const char kOnGalleryChangedEventName[];
 
 // Notifications.
 extern const char kOnNotificationDisplayed[];
 extern const char kOnNotificationError[];
-extern const char kOnNotificationClosed[];
-extern const char kOnNotificationClicked[];
-extern const char kOnNotificationButtonClicked[];
-
-// NetworkingPrivate
-extern const char kOnNetworksChanged[];
-extern const char kOnNetworkListChanged[];
-
-// Audio
-extern const char kOnAudioDeviceChanged[];
-
-// Runtime.
-extern const char kOnLaunched[];
-extern const char kOnRestarted[];
-
-// FeedbackPrivate
-extern const char kOnFeedbackRequested[];
-
-// DeveloperPrivate.
-extern const char kDeveloperPrivateOnItemStateChanged[];
-
-// ImageWriter
-extern const char kRecoveryOnWriteProgress[];
-extern const char kRecoveryOnWriteComplete[];
-extern const char kRecoveryOnWriteError[];
 
 }  // namespace event_names
 
diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc
index f84b5f3..be3c35d 100644
--- a/chrome/browser/extensions/event_router.cc
+++ b/chrome/browser/extensions/event_router.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/extensions/api/web_request/web_request_api.h"
 #include "chrome/browser/extensions/event_names.h"
 #include "chrome/browser/extensions/extension_host.h"
-#include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -34,6 +33,7 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/incognito_handler.h"
+#include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 
@@ -130,7 +130,7 @@
   }
 
   ListValue args;
-  args.Set(0, Value::CreateStringValue(event_name));
+  args.Set(0, new base::StringValue(event_name));
   args.Set(1, event_args);
   args.Set(2, info.AsValue().release());
   ipc_sender->Send(new ExtensionMsg_MessageInvoke(
@@ -415,15 +415,15 @@
 
   base::Version version;
   PrefService* pref_service = profile_->GetPrefs();
-  if (pref_service->HasPrefPath(ExtensionPrefs::kExtensionsLastChromeVersion)) {
+  if (pref_service->HasPrefPath(prefs::kExtensionsLastChromeVersion)) {
     std::string version_str =
-        pref_service->GetString(ExtensionPrefs::kExtensionsLastChromeVersion);
+        pref_service->GetString(prefs::kExtensionsLastChromeVersion);
     version = Version(version_str);
   }
 
   chrome::VersionInfo current_version_info;
   std::string current_version = current_version_info.Version();
-  pref_service->SetString(ExtensionPrefs::kExtensionsLastChromeVersion,
+  pref_service->SetString(prefs::kExtensionsLastChromeVersion,
                           current_version);
 
   // If there was no version string in prefs, assume we're out of date.
diff --git a/chrome/browser/extensions/event_router_forwarder_unittest.cc b/chrome/browser/extensions/event_router_forwarder_unittest.cc
index 0e6619a..865d74b 100644
--- a/chrome/browser/extensions/event_router_forwarder_unittest.cc
+++ b/chrome/browser/extensions/event_router_forwarder_unittest.cc
@@ -111,10 +111,13 @@
   }
 
   TestingProfile* CreateIncognitoProfile(TestingProfile* base) {
-    TestingProfile* incognito = new TestingProfile;  // Owned by |base|.
-    incognito->set_incognito(true);
-    base->SetOffTheRecordProfile(incognito);
-    return incognito;
+    TestingProfile::Builder builder;
+    builder.SetIncognito();
+    scoped_ptr<TestingProfile> incognito = builder.Build();
+    TestingProfile* incognito_ptr = incognito.get();
+    // Incognito profile now owned by |base|
+    base->SetOffTheRecordProfile(incognito.PassAs<Profile>());
+    return incognito_ptr;
   }
 
   base::MessageLoopForUI message_loop_;
diff --git a/chrome/browser/extensions/extension_bindings_apitest.cc b/chrome/browser/extensions/extension_bindings_apitest.cc
index 61b5799..2fbaeb8 100644
--- a/chrome/browser/extensions/extension_bindings_apitest.cc
+++ b/chrome/browser/extensions/extension_bindings_apitest.cc
@@ -4,8 +4,8 @@
 
 // Contains holistic tests of the bindings infrastructure
 
+#include "chrome/browser/extensions/api/permissions/permissions_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
-
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -20,6 +20,14 @@
 class ExtensionBindingsApiTest : public ExtensionApiTest {};
 
 IN_PROC_BROWSER_TEST_F(ExtensionBindingsApiTest,
+                       UnavailableBindingsNeverRegistered) {
+  // Test will request the 'storage' permission.
+  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
+  ASSERT_TRUE(RunExtensionTest(
+      "bindings/unavailable_bindings_never_registered")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionBindingsApiTest,
                        ExceptionInHandlerShouldNotCrash) {
   ASSERT_TRUE(RunExtensionSubtest(
       "bindings/exception_in_handler_should_not_crash",
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index cc715e7..3c48293 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -17,12 +17,12 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/common/extensions/features/feature_channel.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/common/manifest.h"
 
 class ExtensionProcessManager;
 class ExtensionService;
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index e846c00..056dda4 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -38,7 +38,6 @@
 #include "ipc/ipc_message_macros.h"
 #include "webkit/common/resource_type.h"
 
-using extensions::api::activity_log_private::BlockedChromeActivityDetail;
 using extensions::Extension;
 using extensions::ExtensionAPI;
 using extensions::Feature;
@@ -73,39 +72,6 @@
   }
 }
 
-void LogFailure(const std::string& extension_id,
-                const std::string& api_name,
-                scoped_ptr<base::ListValue> args,
-                BlockedChromeActivityDetail::Reason reason,
-                Profile* profile) {
-  // The ActivityLog can only be accessed from the main (UI) thread.  If we're
-  // running on the wrong thread, re-dispatch from the main thread.
-  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    BrowserThread::PostTask(BrowserThread::UI,
-                            FROM_HERE,
-                            base::Bind(&LogFailure,
-                                       extension_id,
-                                       api_name,
-                                       base::Passed(&args),
-                                       reason,
-                                       profile));
-  } else {
-    extensions::ActivityLog* activity_log =
-        extensions::ActivityLog::GetInstance(profile);
-    scoped_refptr<extensions::Action> action =
-        new extensions::Action(extension_id,
-                               base::Time::Now(),
-                               extensions::Action::ACTION_API_BLOCKED,
-                               api_name);
-    action->set_args(args.Pass());
-    action->mutable_other()
-        ->SetString(activity_log_constants::kActionBlockedReason,
-                    BlockedChromeActivityDetail::ToString(reason));
-    activity_log->LogAction(action);
-  }
-}
-
-
 // Separate copy of ExtensionAPI used for IO thread extension functions. We need
 // this because ExtensionAPI has mutable data. It should be possible to remove
 // this once all the extension APIs are updated to the feature system.
@@ -282,14 +248,8 @@
                               profile, callback));
   scoped_ptr<ListValue> args(params.arguments.DeepCopy());
 
-  if (!function.get()) {
-    LogFailure(extension->id(),
-               params.name,
-               args.Pass(),
-               BlockedChromeActivityDetail::REASON_ACCESS_DENIED,
-               profile_cast);
+  if (!function.get())
     return;
-  }
 
   IOThreadExtensionFunction* function_io =
       function->AsIOThreadExtensionFunction();
@@ -302,14 +262,8 @@
   function->set_include_incognito(
       extension_info_map->IsIncognitoEnabled(extension->id()));
 
-  if (!CheckPermissions(function.get(), extension, params, callback)) {
-    LogFailure(extension->id(),
-               params.name,
-               args.Pass(),
-               BlockedChromeActivityDetail::REASON_ACCESS_DENIED,
-               profile_cast);
+  if (!CheckPermissions(function.get(), extension, params, callback))
     return;
-  }
 
   ExtensionsQuotaService* quota = extension_info_map->GetQuotaService();
   std::string violation_error = quota->Assess(extension->id(),
@@ -323,11 +277,6 @@
                profile_cast);
     function->Run();
   } else {
-    LogFailure(extension->id(),
-               params.name,
-               args.Pass(),
-               BlockedChromeActivityDetail::REASON_QUOTA_EXCEEDED,
-               profile_cast);
     function->OnQuotaExceeded(violation_error);
   }
 }
@@ -385,14 +334,8 @@
                               profile(), callback));
   scoped_ptr<ListValue> args(params.arguments.DeepCopy());
 
-  if (!function.get()) {
-    LogFailure(extension->id(),
-               params.name,
-               args.Pass(),
-               BlockedChromeActivityDetail::REASON_ACCESS_DENIED,
-               profile());
+  if (!function.get())
     return;
-  }
 
   UIThreadExtensionFunction* function_ui =
       function->AsUIThreadExtensionFunction();
@@ -405,14 +348,8 @@
   function_ui->set_profile(profile_);
   function->set_include_incognito(service->CanCrossIncognito(extension));
 
-  if (!CheckPermissions(function.get(), extension, params, callback)) {
-    LogFailure(extension->id(),
-               params.name,
-               args.Pass(),
-               BlockedChromeActivityDetail::REASON_ACCESS_DENIED,
-               profile());
+  if (!CheckPermissions(function.get(), extension, params, callback))
     return;
-  }
 
   ExtensionsQuotaService* quota = service->quota_service();
   std::string violation_error = quota->Assess(extension->id(),
@@ -425,11 +362,6 @@
     LogSuccess(extension->id(), params.name, args.Pass(), profile());
     function->Run();
   } else {
-    LogFailure(extension->id(),
-               params.name,
-               args.Pass(),
-               BlockedChromeActivityDetail::REASON_QUOTA_EXCEEDED,
-               profile());
     function->OnQuotaExceeded(violation_error);
   }
 
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index 447185e..ae24aee 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -96,7 +96,7 @@
   AUTOTESTPRIVATE_RESTART,
   USB_CLAIMINTERFACE,
   MEDIAPLAYERPRIVATE_SETWINDOWHEIGHT,
-  EXPERIMENTAL_PROCESSES_GETPROCESSINFO,
+  DELETED_EXPERIMENTAL_PROCESSES_GETPROCESSINFO,
   HISTORY_GETVISITS,
   SOCKET_BIND,
   TABS_MOVE,
@@ -161,7 +161,7 @@
   WINDOWS_CREATE,
   DEVELOPERPRIVATE_LOADUNPACKED,
   DELETED_DOWNLOADS_SETDESTINATION,
-  EXPERIMENTAL_PROCESSES_GETPROCESSIDFORTAB,
+  DELETED_EXPERIMENTAL_PROCESSES_GETPROCESSIDFORTAB,
   BOOKMARKS_GETCHILDREN,
   BROWSERACTION_GETTITLE,
   TERMINALPRIVATE_OPENTERMINALPROCESS,
@@ -354,7 +354,7 @@
   EXPERIMENTAL_APP_NOTIFY,
   METRICSPRIVATE_RECORDLONGTIME,
   SOCKET_READ,
-  EXPERIMENTAL_PROCESSES_TERMINATE,
+  DELETED_EXPERIMENTAL_PROCESSES_TERMINATE,
   METRICSPRIVATE_RECORDTIME,
   BOOKMARKMANAGERPRIVATE_GETSTRINGS,
   USB_ISOCHRONOUSTRANSFER,
@@ -459,8 +459,8 @@
   WEBVIEW_EXECUTESCRIPT,
   NOTIFICATIONS_UPDATE,
   NOTIFICATIONS_CLEAR,
-  SESSIONRESTORE_GETRECENTLYCLOSED,
-  SESSIONRESTORE_RESTORE,
+  DELETED_SESSIONRESTORE_GETRECENTLYCLOSED,
+  DELETED_SESSIONRESTORE_RESTORE,
   MANAGEMENT_UNINSTALLSELF,
   ECHOPRIVATE_GETOOBETIMESTAMP,
   FILEBROWSERPRIVATE_VALIDATEPATHNAMELENGTH,
@@ -474,7 +474,7 @@
   MEDIAGALLERIESPRIVATE_REMOVEALLGALLERYWATCH,
   FILEBROWSERPRIVATE_SEARCHDRIVEMETADATA,
   ECHOPRIVATE_CHECKALLOWREDEEMOFFERS,
-  MEDIAGALLERIESPRIVATE_EJECTDEVICE,
+  DELETED_MEDIAGALLERIESPRIVATE_EJECTDEVICE,
   FILEBROWSERPRIVATE_LOGOUTUSER,
   DEVELOPERPRIVATE_CHOOSEPATH,
   DEVELOPERPRIVATE_PACKDIRECTORY,
@@ -591,6 +591,29 @@
   EXPERIMENTAL_INPUT_VIRTUALKEYBOARD_MOVECURSOR,
   METRICSPRIVATE_GETVARIATIONPARAMS,
   WEBVIEW_SETPERMISSION,
+  DESKTOPCAPTURE_CHOOSEDESKTOPMEDIA,
+  APP_CURRENTWINDOWINTERNAL_SETINPUTREGION,
+  PROCESSES_GETPROCESSINFO,
+  PROCESSES_GETPROCESSIDFORTAB,
+  PROCESSES_TERMINATE,
+  SOCKETS_UDP_CREATE,
+  SOCKETS_UDP_UPDATE,
+  SOCKETS_UDP_BIND,
+  SOCKETS_UDP_SEND,
+  SOCKETS_UDP_CLOSE,
+  SOCKETS_UDP_GETINFO,
+  SOCKETS_UDP_GETSOCKETS,
+  SOCKETS_UDP_JOINGROUP,
+  SOCKETS_UDP_LEAVEGROUP,
+  SOCKETS_UDP_SETMULTICASTTIMETOLIVE,
+  SOCKETS_UDP_SETMULTICASTLOOPBACKMODE,
+  SOCKETS_UDP_GETJOINEDGROUPS,
+  SIGNEDIN_DEVICES_GET,
+  AUTOTESTPRIVATE_SIMULATEASANMEMORYBUG,
+  WEBVIEW_CLEARDATA,
+  SESSIONS_GETRECENTLYCLOSED,
+  SESSIONS_GETDEVICES,
+  SESSIONS_RESTORE,
   ENUM_BOUNDARY // Last entry: Add new entries above.
 };
 
diff --git a/chrome/browser/extensions/extension_function_test_utils.h b/chrome/browser/extensions/extension_function_test_utils.h
index a711397..b2d7756 100644
--- a/chrome/browser/extensions/extension_function_test_utils.h
+++ b/chrome/browser/extensions/extension_function_test_utils.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class AsyncExtensionFunction;
 class Browser;
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index f6462a2..7388727 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -271,7 +271,7 @@
     web_modal::WebContentsModalDialogManager::CreateForWebContents(
         host_contents_.get());
     web_modal::WebContentsModalDialogManager::FromWebContents(
-        host_contents_.get())->set_delegate(this);
+        host_contents_.get())->SetDelegate(this);
   }
 #endif
 
diff --git a/chrome/browser/extensions/extension_icon_image_unittest.cc b/chrome/browser/extensions/extension_icon_image_unittest.cc
index 346a2ff..0d9b9a7 100644
--- a/chrome/browser/extensions/extension_icon_image_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_image_unittest.cc
@@ -11,10 +11,10 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest.h"
 #include "grit/theme_resources.h"
 #include "skia/ext/image_operations.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/extensions/extension_info_map_unittest.cc b/chrome/browser/extensions/extension_info_map_unittest.cc
index 10dace7..9439cf3 100644
--- a/chrome/browser/extensions/extension_info_map_unittest.cc
+++ b/chrome/browser/extensions/extension_info_map_unittest.cc
@@ -8,8 +8,8 @@
 #include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::BrowserThread;
@@ -17,7 +17,7 @@
 using extensions::Extension;
 using extensions::Manifest;
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace {
 
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index 37154bf..544c04e 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -26,9 +26,7 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_icon_set.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/feature_switch.h"
-#include "chrome/common/extensions/manifest.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"
@@ -36,6 +34,8 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #include "extensions/common/url_pattern.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -457,11 +457,11 @@
   if (!localized_name.empty() || !localized_description.empty()) {
     localized_manifest.reset(manifest->DeepCopy());
     if (!localized_name.empty()) {
-      localized_manifest->SetString(extension_manifest_keys::kName,
+      localized_manifest->SetString(extensions::manifest_keys::kName,
                                     localized_name);
     }
     if (!localized_description.empty()) {
-      localized_manifest->SetString(extension_manifest_keys::kDescription,
+      localized_manifest->SetString(extensions::manifest_keys::kDescription,
                                     localized_description);
     }
   }
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index 7c52b7a..b4c8868 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -3,8 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/extensions/extension_install_ui.h"
-ExtensionInstallUI::ExtensionInstallUI() : profile_(NULL) {
-}
 
-ExtensionInstallUI::~ExtensionInstallUI() {
-}
+ExtensionInstallUI::ExtensionInstallUI(Profile* profile) : profile_(profile) {}
+
+ExtensionInstallUI::~ExtensionInstallUI() {}
diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h
index b29fc9b..a0211ca 100644
--- a/chrome/browser/extensions/extension_install_ui.h
+++ b/chrome/browser/extensions/extension_install_ui.h
@@ -7,23 +7,18 @@
 
 #include <string>
 
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "chrome/browser/extensions/crx_installer_error.h"
+#include "base/basictypes.h"
 
 class Browser;
 class ExtensionInstallPrompt;
 class Profile;
 class SkBitmap;
 
-namespace content {
-class WebContents;
-}
-
 namespace extensions {
+class CrxInstallerError;
 class Extension;
 class ExtensionWebstorePrivateApiTest;
-}  // namespace extensions
+}
 
 // Interface that should be implemented for each platform to display all the UI
 // around extension installation.
@@ -36,6 +31,7 @@
   // Called when an extension was installed.
   virtual void OnInstallSuccess(const extensions::Extension* extension,
                                 SkBitmap* icon) = 0;
+
   // Called when an extension failed to install.
   virtual void OnInstallFailure(const extensions::CrxInstallerError& error) = 0;
 
@@ -61,17 +57,20 @@
       Browser* browser);
 
   // Creates an ExtensionInstallPrompt from |profile|.
-  // Caller assumes ownership. This method is deperecated
-  // and should not be used in new code.
+  // Caller assumes ownership. This method is deprecated and should not be used
+  // in new code.
   static ExtensionInstallPrompt* CreateInstallPromptWithProfile(
       Profile* profile);
 
   Profile* profile() { return profile_; }
 
  protected:
-  ExtensionInstallUI();
+  explicit ExtensionInstallUI(Profile* profile);
 
+ private:
   Profile* profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionInstallUI);
 };
 
 #endif  // CHROME_BROWSER_EXTENSIONS_EXTENSION_INSTALL_UI_H_
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index f38878b..6a1aac8 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -50,8 +50,12 @@
   // Install the given theme from the data dir and verify expected name.
   void InstallThemeAndVerify(const char* theme_name,
                              const std::string& expected_name) {
+    // If there is already a theme installed, the current theme should be
+    // disabled and the new one installed + enabled.
+    int expected_change = GetTheme() ? 0 : 1;
     const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_name);
-    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, 1, browser()));
+    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, expected_change,
+        browser()));
     const Extension* theme = GetTheme();
     ASSERT_TRUE(theme);
     ASSERT_EQ(theme->name(), expected_name);
@@ -88,7 +92,7 @@
   ASSERT_EQ(NULL, GetTheme());
 
   // Set the same theme twice and undo to verify we go back to default theme.
-  ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 1, browser()));
+  ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser()));
   theme = GetTheme();
   ASSERT_TRUE(theme);
   ASSERT_EQ(theme_id, theme->id());
@@ -206,7 +210,12 @@
   DISALLOW_COPY_AND_ASSIGN(NewTabUISortingBrowserTest);
 };
 
-IN_PROC_BROWSER_TEST_F(NewTabUISortingBrowserTest, ReorderDuringInstall) {
+#if defined(OS_WIN)
+#define MAYBE_ReorderDuringInstall DISABLED_ReorderDuringInstall
+#else
+#define MAYBE_ReorderDuringInstall ReorderDuringInstall
+#endif
+IN_PROC_BROWSER_TEST_F(NewTabUISortingBrowserTest, MAYBE_ReorderDuringInstall) {
   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
   ExtensionService* service = extensions::ExtensionSystem::Get(
       browser()->profile())->extension_service();
diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc
index edc6bde..4a87ddd 100644
--- a/chrome/browser/extensions/extension_keybinding_registry.cc
+++ b/chrome/browser/extensions/extension_keybinding_registry.cc
@@ -71,7 +71,7 @@
     granter->GrantIfRequested(extension);
 
   scoped_ptr<base::ListValue> args(new base::ListValue());
-  args->Append(Value::CreateStringValue(command));
+  args->Append(new base::StringValue(command));
 
   scoped_ptr<Event> event(new Event("commands.onCommand", args.Pass()));
   event->restrict_to_profile = profile_;
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 7726d6e..6d18f3b 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -142,21 +142,45 @@
     INCORRECT_RESPONSE_MESSAGE = 6,
   };
 
+  bool AppendIframe(const GURL& src) {
+    bool result;
+    CHECK(content::ExecuteScriptAndExtractBool(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        "actions.appendIframe('" + src.spec() + "');", &result));
+    return result;
+  }
+
   Result CanConnectAndSendMessages(const std::string& extension_id) {
-    return CanConnectAndSendMessages(browser(), extension_id);
+    return CanConnectAndSendMessages(browser(), extension_id, "");
   }
 
   Result CanConnectAndSendMessages(Browser* browser,
                                    const std::string& extension_id) {
+    return CanConnectAndSendMessages(browser, extension_id, "");
+  }
+
+  Result CanConnectAndSendMessages(const std::string& extension_id,
+                                   const char* frame_xpath) {
+    return CanConnectAndSendMessages(browser(), extension_id, frame_xpath);
+  }
+
+  Result CanConnectAndSendMessages(Browser* browser,
+                                   const std::string& extension_id,
+                                   const char* frame_xpath) {
     int result;
-    CHECK(content::ExecuteScriptAndExtractInt(
+    CHECK(content::ExecuteScriptInFrameAndExtractInt(
         browser->tab_strip_model()->GetActiveWebContents(),
+        frame_xpath,
         "assertions.canConnectAndSendMessages('" + extension_id + "')",
         &result));
     return static_cast<Result>(result);
   }
 
   testing::AssertionResult AreAnyNonWebApisDefined() {
+    return AreAnyNonWebApisDefined("");
+  }
+
+  testing::AssertionResult AreAnyNonWebApisDefined(const char* frame_xpath) {
     // All runtime API methods are non-web except for sendRequest and connect.
     const char* non_messaging_apis[] = {
         "getBackgroundPage",
@@ -189,8 +213,9 @@
     as_js_array += "]";
 
     bool any_defined;
-    CHECK(content::ExecuteScriptAndExtractBool(
+    CHECK(content::ExecuteScriptInFrameAndExtractBool(
         browser()->tab_strip_model()->GetActiveWebContents(),
+        frame_xpath,
         "assertions.areAnyRuntimePropertiesDefined(" + as_js_array + ")",
         &any_defined));
     return any_defined ?
@@ -214,24 +239,30 @@
   }
 
   const Extension* LoadChromiumConnectableExtension() {
-    return LoadExtensionIntoDir(&web_connectable_dir_, base::StringPrintf(
-        "{"
-        "  \"name\": \"chromium_connectable\","
-        "  %s,"
-        "  \"externally_connectable\": {"
-        "    \"matches\": [\"*://*.chromium.org:*/*\"]"
-        "  }"
-        "}",
-        common_manifest()));
+    const Extension* extension =
+        LoadExtensionIntoDir(&web_connectable_dir_, base::StringPrintf(
+            "{"
+            "  \"name\": \"chromium_connectable\","
+            "  %s,"
+            "  \"externally_connectable\": {"
+            "    \"matches\": [\"*://*.chromium.org:*/*\"]"
+            "  }"
+            "}",
+            common_manifest()));
+    CHECK(extension);
+    return extension;
   }
 
-  scoped_refptr<const Extension> LoadNotConnectableExtension() {
-    return LoadExtensionIntoDir(&not_connectable_dir_, base::StringPrintf(
-        "{"
-        "  \"name\": \"not_connectable\","
-        "  %s"
-        "}",
-        common_manifest()));
+  const Extension* LoadNotConnectableExtension() {
+    const Extension* extension =
+        LoadExtensionIntoDir(&not_connectable_dir_, base::StringPrintf(
+            "{"
+            "  \"name\": \"not_connectable\","
+            "  %s"
+            "}",
+            common_manifest()));
+    CHECK(extension);
+    return extension;
   }
 
   void InitializeTestServer() {
@@ -295,7 +326,6 @@
   // Install the web connectable extension. chromium.org can connect to it,
   // google.com can't.
   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
-  ASSERT_TRUE(chromium_connectable);
 
   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
   EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
@@ -308,7 +338,6 @@
 
   // Install the non-connectable extension. Nothing can connect to it.
   const Extension* not_connectable = LoadNotConnectableExtension();
-  ASSERT_TRUE(not_connectable);
 
   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
   // Namespace will be defined here because |chromium_connectable| can connect
@@ -333,9 +362,7 @@
   InitializeTestServer();
 
   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
-  ASSERT_TRUE(chromium_connectable);
   const Extension* not_connectable = LoadNotConnectableExtension();
-  ASSERT_TRUE(not_connectable);
 
   ui_test_utils::NavigateToURL(browser(), chromium_org_url());
   EXPECT_EQ(OK, CanConnectAndSendMessages(chromium_connectable->id()));
@@ -361,7 +388,6 @@
   InitializeTestServer();
 
   const Extension* chromium_connectable = LoadChromiumConnectableExtension();
-  ASSERT_TRUE(chromium_connectable);
 
   Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord(
       profile()->GetOffTheRecordProfile(),
@@ -377,5 +403,44 @@
   EXPECT_EQ(OK, CanConnectAndSendMessages(incognito_browser, id));
 }
 
+// Tests a connection from an iframe within a tab which doesn't have
+// permission. Iframe should work.
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
+                       FromIframeWithPermission) {
+  InitializeTestServer();
+
+  const Extension* extension = LoadChromiumConnectableExtension();
+
+  ui_test_utils::NavigateToURL(browser(), google_com_url());
+  EXPECT_EQ(NAMESPACE_NOT_DEFINED, CanConnectAndSendMessages(extension->id()));
+  EXPECT_FALSE(AreAnyNonWebApisDefined());
+
+  ASSERT_TRUE(AppendIframe(chromium_org_url()));
+
+  const char* frame_xpath = "//iframe[1]";
+  EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id(), frame_xpath));
+  EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath));
+}
+
+// Tests connection from an iframe without permission within a tab that does.
+// Iframe shouldn't work.
+IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
+                       FromIframeWithoutPermission) {
+  InitializeTestServer();
+
+  const Extension* extension = LoadChromiumConnectableExtension();
+
+  ui_test_utils::NavigateToURL(browser(), chromium_org_url());
+  EXPECT_EQ(OK, CanConnectAndSendMessages(extension->id()));
+  EXPECT_FALSE(AreAnyNonWebApisDefined());
+
+  ASSERT_TRUE(AppendIframe(google_com_url()));
+
+  const char* frame_xpath = "//iframe[1]";
+  EXPECT_EQ(NAMESPACE_NOT_DEFINED,
+            CanConnectAndSendMessages(extension->id(), frame_xpath));
+  EXPECT_FALSE(AreAnyNonWebApisDefined(frame_xpath));
+}
+
 }  // namespace
-}  // namespace extensions
+};  // namespace extensions
diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc
index dcaa3cd..e25602d 100644
--- a/chrome/browser/extensions/extension_override_apitest.cc
+++ b/chrome/browser/extensions/extension_override_apitest.cc
@@ -55,8 +55,8 @@
     // will call chrome.test.notifyPass() .
     ui_test_utils::NavigateToURL(browser(), GURL("chrome://newtab/"));
     WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
-    ASSERT_TRUE(tab->GetController().GetActiveEntry());
-    EXPECT_TRUE(tab->GetController().GetActiveEntry()->GetURL().
+    ASSERT_TRUE(tab->GetController().GetVisibleEntry());
+    EXPECT_TRUE(tab->GetController().GetVisibleEntry()->GetURL().
                 SchemeIs(extensions::kExtensionScheme));
 
     ASSERT_TRUE(catcher.GetNextResult());
@@ -80,8 +80,8 @@
   Browser* otr_browser = ui_test_utils::OpenURLOffTheRecord(
       browser()->profile(), GURL("chrome://newtab/"));
   WebContents* tab = otr_browser->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(tab->GetController().GetActiveEntry());
-  EXPECT_FALSE(tab->GetController().GetActiveEntry()->GetURL().
+  ASSERT_TRUE(tab->GetController().GetVisibleEntry());
+  EXPECT_FALSE(tab->GetController().GetVisibleEntry()->GetURL().
                SchemeIs(extensions::kExtensionScheme));
 }
 
@@ -127,7 +127,7 @@
   // the file already contains dupes when an extension is loaded.
   base::ListValue* list = new base::ListValue();
   for (size_t i = 0; i < 3; ++i)
-    list->Append(Value::CreateStringValue("http://www.google.com/"));
+    list->Append(new base::StringValue("http://www.google.com/"));
 
   {
     DictionaryPrefUpdate update(browser()->profile()->GetPrefs(),
diff --git a/chrome/browser/extensions/extension_pref_value_map_unittest.cc b/chrome/browser/extensions/extension_pref_value_map_unittest.cc
index 7f1b2d5..a7e3b68 100644
--- a/chrome/browser/extensions/extension_pref_value_map_unittest.cc
+++ b/chrome/browser/extensions/extension_pref_value_map_unittest.cc
@@ -23,7 +23,7 @@
 }  // namespace
 
 static Value* CreateVal(const char* str) {
-  return Value::CreateStringValue(str);
+  return new base::StringValue(str);
 }
 
 static base::Time CreateTime(int64 t) {
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 6447ad3..f8442b0 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/feature_switch.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_info.h"
@@ -31,6 +30,7 @@
 #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/url_pattern.h"
 #include "extensions/common/user_script.h"
 #include "grit/generated_resources.h"
@@ -190,7 +190,7 @@
  public:
   ScopedExtensionPrefUpdate(PrefService* service,
                             const std::string& extension_id) :
-    DictionaryPrefUpdate(service, ExtensionPrefs::kExtensionsPref),
+    DictionaryPrefUpdate(service, prefs::kExtensionsPref),
     extension_id_(extension_id) {}
 
   virtual ~ScopedExtensionPrefUpdate() {
@@ -250,7 +250,7 @@
     ExtensionPrefs* prefs,
     const std::string& extension_id,
     const std::string& key)
-    : update_(prefs->pref_service(), kExtensionsPref),
+    : update_(prefs->pref_service(), prefs::kExtensionsPref),
       extension_id_(extension_id),
       key_(key) {
   DCHECK(Extension::IdIsValid(extension_id_));
@@ -340,12 +340,6 @@
   return ExtensionPrefsFactory::GetInstance()->GetForProfile(profile);
 }
 
-// static
-const char ExtensionPrefs::kExtensionsPref[] = "extensions.settings";
-// static
-const char ExtensionPrefs::kExtensionsLastChromeVersion[] =
-    "extensions.last_chrome_version";
-
 static base::FilePath::StringType MakePathRelative(const base::FilePath& parent,
                                              const base::FilePath& child) {
   if (!parent.IsParent(child))
@@ -360,7 +354,7 @@
 }
 
 void ExtensionPrefs::MakePathsRelative() {
-  const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
+  const DictionaryValue* dict = prefs_->GetDictionary(prefs::kExtensionsPref);
   if (!dict || dict->empty())
     return;
 
@@ -388,7 +382,7 @@
     return;
 
   // Fix these paths.
-  DictionaryPrefUpdate update(prefs_, kExtensionsPref);
+  DictionaryPrefUpdate update(prefs_, prefs::kExtensionsPref);
   DictionaryValue* update_dict = update.Get();
   for (std::set<std::string>::iterator i = absolute_keys.begin();
        i != absolute_keys.end(); ++i) {
@@ -407,7 +401,8 @@
 
 const DictionaryValue* ExtensionPrefs::GetExtensionPref(
     const std::string& extension_id) const {
-  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+  const DictionaryValue* extensions =
+      prefs_->GetDictionary(prefs::kExtensionsPref);
   const DictionaryValue* extension_dict = NULL;
   if (!extensions ||
       !extensions->GetDictionary(extension_id, &extension_dict)) {
@@ -433,7 +428,7 @@
 void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) {
   extension_pref_value_map_->UnregisterExtension(extension_id);
   content_settings_store_->UnregisterExtension(extension_id);
-  DictionaryPrefUpdate update(prefs_, kExtensionsPref);
+  DictionaryPrefUpdate update(prefs_, prefs::kExtensionsPref);
   DictionaryValue* dict = update.Get();
   dict->Remove(extension_id, NULL);
 }
@@ -581,7 +576,7 @@
       tmp->Set(i->name(), detail.release());
       api_values->Append(tmp);
     } else {
-      api_values->Append(Value::CreateStringValue(i->name()));
+      api_values->Append(new base::StringValue(i->name()));
     }
   }
   UpdateExtensionPref(extension_id, api_pref, api_values);
@@ -607,7 +602,7 @@
   ReadPrefAsInteger(extension_id, kPrefAcknowledgePromptCount, &count);
   ++count;
   UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount,
-                      Value::CreateIntegerValue(count));
+                      new base::FundamentalValue(count));
   return count;
 }
 
@@ -620,7 +615,7 @@
     const std::string& extension_id) {
   DCHECK(Extension::IdIsValid(extension_id));
   UpdateExtensionPref(extension_id, kPrefExternalAcknowledged,
-                      Value::CreateBooleanValue(true));
+                      new base::FundamentalValue(true));
   UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount, NULL);
 }
 
@@ -633,7 +628,7 @@
     const std::string& extension_id) {
   DCHECK(Extension::IdIsValid(extension_id));
   UpdateExtensionPref(extension_id, kPrefBlacklistAcknowledged,
-                      Value::CreateBooleanValue(true));
+                      new base::FundamentalValue(true));
   UpdateExtensionPref(extension_id, kPrefAcknowledgePromptCount, NULL);
 }
 
@@ -646,7 +641,7 @@
     const std::string& extension_id) {
   DCHECK(Extension::IdIsValid(extension_id));
   UpdateExtensionPref(extension_id, kPrefExternalInstallFirstRun,
-                      Value::CreateBooleanValue(true));
+                      new base::FundamentalValue(true));
 }
 
 bool ExtensionPrefs::SetAlertSystemFirstRun() {
@@ -671,7 +666,7 @@
 void ExtensionPrefs::SetDidExtensionEscalatePermissions(
     const Extension* extension, bool did_escalate) {
   UpdateExtensionPref(extension->id(), kExtensionDidEscalatePermissions,
-                      Value::CreateBooleanValue(did_escalate));
+                      new base::FundamentalValue(did_escalate));
 }
 
 int ExtensionPrefs::GetDisableReasons(const std::string& extension_id) {
@@ -688,7 +683,7 @@
   int new_value = GetDisableReasons(extension_id) |
       static_cast<int>(disable_reason);
   UpdateExtensionPref(extension_id, kPrefDisableReasons,
-                      Value::CreateIntegerValue(new_value));
+                      new base::FundamentalValue(new_value));
 }
 
 void ExtensionPrefs::RemoveDisableReason(
@@ -700,7 +695,7 @@
     UpdateExtensionPref(extension_id, kPrefDisableReasons, NULL);
   } else {
     UpdateExtensionPref(extension_id, kPrefDisableReasons,
-                        Value::CreateIntegerValue(new_value));
+                        new base::FundamentalValue(new_value));
   }
 }
 
@@ -711,7 +706,8 @@
 std::set<std::string> ExtensionPrefs::GetBlacklistedExtensions() {
   std::set<std::string> ids;
 
-  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+  const DictionaryValue* extensions =
+      prefs_->GetDictionary(prefs::kExtensionsPref);
   if (!extensions)
     return ids;
 
@@ -832,7 +828,7 @@
 void ExtensionPrefs::SetActiveBit(const std::string& extension_id,
                                   bool active) {
   UpdateExtensionPref(extension_id, kActiveBit,
-                      Value::CreateBooleanValue(active));
+                      new base::FundamentalValue(active));
 }
 
 void ExtensionPrefs::MigratePermissions(const ExtensionIdList& extension_ids) {
@@ -866,7 +862,7 @@
 
       std::string plugin_name = info->GetByID(
           APIPermission::kPlugin)->name();
-      new_apis->Append(Value::CreateStringValue(plugin_name));
+      new_apis->Append(new base::StringValue(plugin_name));
       UpdateExtensionPref(*ext_id, granted_apis, new_apis);
     }
 
@@ -909,7 +905,7 @@
       }
 
       UpdateExtensionPref(*ext_id, kPrefDisableReasons,
-                          Value::CreateIntegerValue(new_value));
+                          new base::FundamentalValue(new_value));
       // Remove the old disable reason.
       UpdateExtensionPref(*ext_id, kDeprecatedPrefDisableReason, NULL);
     }
@@ -973,7 +969,7 @@
 
 void ExtensionPrefs::SetExtensionRunning(const std::string& extension_id,
     bool is_running) {
-  Value* value = Value::CreateBooleanValue(is_running);
+  Value* value = new base::FundamentalValue(is_running);
   UpdateExtensionPref(extension_id, kPrefRunning, value);
 }
 
@@ -988,7 +984,7 @@
 
 void ExtensionPrefs::SetIsActive(const std::string& extension_id,
                                  bool is_active) {
-  Value* value = Value::CreateBooleanValue(is_active);
+  Value* value = new base::FundamentalValue(is_active);
   UpdateExtensionPref(extension_id, kIsActive, value);
 }
 
@@ -1008,7 +1004,7 @@
 void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id,
                                            bool enabled) {
   UpdateExtensionPref(extension_id, kPrefIncognitoEnabled,
-                      Value::CreateBooleanValue(enabled));
+                      new base::FundamentalValue(enabled));
 }
 
 bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) {
@@ -1018,7 +1014,7 @@
 void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id,
                                         bool allow) {
   UpdateExtensionPref(extension_id, kPrefAllowFileAccess,
-                      Value::CreateBooleanValue(allow));
+                      new base::FundamentalValue(allow));
 }
 
 bool ExtensionPrefs::HasAllowFileAccessSetting(
@@ -1124,7 +1120,7 @@
 void ExtensionPrefs::SetLaunchType(const std::string& extension_id,
                                    LaunchType launch_type) {
   UpdateExtensionPref(extension_id, kPrefLaunchType,
-      Value::CreateIntegerValue(static_cast<int>(launch_type)));
+      new base::FundamentalValue(static_cast<int>(launch_type)));
 }
 
 bool ExtensionPrefs::DoesExtensionHaveState(
@@ -1186,7 +1182,7 @@
   // no longer lists the extension).
   if (!external_uninstall && Manifest::IsExternalLocation(location)) {
     UpdateExtensionPref(extension_id, kPrefState,
-                        Value::CreateIntegerValue(
+                        new base::FundamentalValue(
                             Extension::EXTERNAL_EXTENSION_UNINSTALLED));
     extension_pref_value_map_->SetExtensionState(extension_id, false);
     content_settings_store_->SetExtensionState(extension_id, false);
@@ -1198,7 +1194,7 @@
 void ExtensionPrefs::SetExtensionState(const std::string& extension_id,
                                        Extension::State state) {
   UpdateExtensionPref(extension_id, kPrefState,
-                      Value::CreateIntegerValue(state));
+                      new base::FundamentalValue(state));
   bool enabled = (state == Extension::ENABLED);
   extension_pref_value_map_->SetExtensionState(extension_id, enabled);
   content_settings_store_->SetExtensionState(extension_id, enabled);
@@ -1288,7 +1284,8 @@
 scoped_ptr<ExtensionInfo> ExtensionPrefs::GetInstalledExtensionInfo(
     const std::string& extension_id) const {
   const DictionaryValue* ext = NULL;
-  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+  const DictionaryValue* extensions =
+      prefs_->GetDictionary(prefs::kExtensionsPref);
   if (!extensions ||
       !extensions->GetDictionaryWithoutPathExpansion(extension_id, &ext))
     return scoped_ptr<ExtensionInfo>();
@@ -1312,7 +1309,8 @@
 ExtensionPrefs::GetInstalledExtensionsInfo() const {
   scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
 
-  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+  const DictionaryValue* extensions =
+      prefs_->GetDictionary(prefs::kExtensionsPref);
   for (DictionaryValue::Iterator extension_id(*extensions);
        !extension_id.IsAtEnd(); extension_id.Advance()) {
     if (!Extension::IdIsValid(extension_id.key()))
@@ -1327,6 +1325,29 @@
   return extensions_info.Pass();
 }
 
+scoped_ptr<ExtensionPrefs::ExtensionsInfo>
+ExtensionPrefs::GetUninstalledExtensionsInfo() const {
+  scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
+
+  const DictionaryValue* extensions =
+      prefs_->GetDictionary(prefs::kExtensionsPref);
+  for (DictionaryValue::Iterator extension_id(*extensions);
+       !extension_id.IsAtEnd(); extension_id.Advance()) {
+    const DictionaryValue* ext = NULL;
+    if (!Extension::IdIsValid(extension_id.key()) ||
+        !IsExternalExtensionUninstalled(extension_id.key()) ||
+        !extension_id.value().GetAsDictionary(&ext))
+      continue;
+
+    scoped_ptr<ExtensionInfo> info =
+        GetInstalledInfoHelper(extension_id.key(), ext);
+    if (info)
+      extensions_info->push_back(linked_ptr<ExtensionInfo>(info.release()));
+  }
+
+  return extensions_info.Pass();
+}
+
 void ExtensionPrefs::SetDelayedInstallInfo(
     const Extension* extension,
     Extension::State initial_state,
@@ -1388,11 +1409,14 @@
   const base::Time install_time = time_provider_->GetCurrentTime();
   pending_install_dict->Set(
       kPrefInstallTime,
-      Value::CreateStringValue(
+      new base::StringValue(
           base::Int64ToString(install_time.ToInternalValue())));
 
   // Commit the delayed install data.
-  extension_dict->MergeDictionary(pending_install_dict);
+  for (DictionaryValue::Iterator it(*pending_install_dict); !it.IsAtEnd();
+       it.Advance()) {
+    extension_dict->Set(it.key(), it.value().DeepCopy());
+  }
   FinishExtensionInfoPrefs(extension_id, install_time, needs_sort_ordinal,
                            suggested_page_ordinal, extension_dict);
   return true;
@@ -1434,7 +1458,8 @@
     GetAllDelayedInstallInfo() const {
   scoped_ptr<ExtensionsInfo> extensions_info(new ExtensionsInfo);
 
-  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
+  const DictionaryValue* extensions =
+      prefs_->GetDictionary(prefs::kExtensionsPref);
   for (DictionaryValue::Iterator extension_id(*extensions);
        !extension_id.IsAtEnd(); extension_id.Advance()) {
     if (!Extension::IdIsValid(extension_id.key()))
@@ -1454,7 +1479,7 @@
 
 void ExtensionPrefs::SetAppDraggedByUser(const std::string& extension_id) {
   UpdateExtensionPref(extension_id, kPrefUserDraggedApp,
-                      Value::CreateBooleanValue(true));
+                      new base::FundamentalValue(true));
 }
 
 bool ExtensionPrefs::IsFromWebStore(
@@ -1544,7 +1569,7 @@
 
   const DictionaryValue* extension_prefs = NULL;
   const Value* extension_prefs_value =
-      pref_service->GetUserPrefValue(kExtensionsPref);
+      pref_service->GetUserPrefValue(prefs::kExtensionsPref);
   if (!extension_prefs_value ||
       !extension_prefs_value->GetAsDictionary(&extension_prefs)) {
     return result;  // Empty set
@@ -1576,7 +1601,7 @@
       const base::Time install_time = time_provider_->GetCurrentTime();
       UpdateExtensionPref(*ext_id,
                           kPrefInstallTime,
-                          Value::CreateStringValue(base::Int64ToString(
+                          new base::StringValue(base::Int64ToString(
                               install_time.ToInternalValue())));
     }
   }
@@ -1688,7 +1713,8 @@
 void ExtensionPrefs::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterDictionaryPref(
-      kExtensionsPref, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+      prefs::kExtensionsPref,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterListPref(prefs::kExtensionToolbar,
                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterIntegerPref(
@@ -1726,7 +1752,7 @@
   registry->RegisterListPref(prefs::kExtensionAllowedInstallSites,
                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterStringPref(
-      kExtensionsLastChromeVersion,
+      prefs::kExtensionsLastChromeVersion,
       std::string(),  // default value
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 
@@ -1761,7 +1787,7 @@
   list_of_values->Clear();
   for (ExtensionIdList::const_iterator iter = strings.begin();
        iter != strings.end(); ++iter)
-    list_of_values->Append(new StringValue(*iter));
+    list_of_values->Append(new base::StringValue(*iter));
 }
 
 void ExtensionPrefs::PopulateExtensionInfoPrefs(
@@ -1774,28 +1800,28 @@
   // loading new profiles do not fail in GetInstalledExtensionInfo. Older
   // Chrome versions would only check for an omitted state.
   if (initial_state != Extension::ENABLED_COMPONENT)
-    extension_dict->Set(kPrefState, Value::CreateIntegerValue(initial_state));
+    extension_dict->Set(kPrefState, new base::FundamentalValue(initial_state));
 
   extension_dict->Set(kPrefLocation,
-                      Value::CreateIntegerValue(extension->location()));
+                      new base::FundamentalValue(extension->location()));
   extension_dict->Set(kPrefCreationFlags,
-                      Value::CreateIntegerValue(extension->creation_flags()));
+                      new base::FundamentalValue(extension->creation_flags()));
   extension_dict->Set(kPrefFromWebStore,
-                      Value::CreateBooleanValue(extension->from_webstore()));
+                      new base::FundamentalValue(extension->from_webstore()));
   extension_dict->Set(kPrefFromBookmark,
-                      Value::CreateBooleanValue(extension->from_bookmark()));
+                      new base::FundamentalValue(extension->from_bookmark()));
   extension_dict->Set(
       kPrefWasInstalledByDefault,
-      Value::CreateBooleanValue(extension->was_installed_by_default()));
+      new base::FundamentalValue(extension->was_installed_by_default()));
   extension_dict->Set(kPrefInstallTime,
-                      Value::CreateStringValue(
+                      new base::StringValue(
                           base::Int64ToString(install_time.ToInternalValue())));
   if (blacklist_state == Blacklist::BLACKLISTED)
-    extension_dict->Set(kPrefBlacklist, Value::CreateBooleanValue(true));
+    extension_dict->Set(kPrefBlacklist, new base::FundamentalValue(true));
 
   base::FilePath::StringType path = MakePathRelative(install_directory_,
                                                      extension->path());
-  extension_dict->Set(kPrefPath, Value::CreateStringValue(path));
+  extension_dict->Set(kPrefPath, new base::StringValue(path));
   // We store prefs about LOAD extensions, but don't cache their manifest
   // since it may change on disk.
   if (!Manifest::IsUnpackedLocation(extension->location())) {
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 6a512a8..1a03127 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -53,14 +53,6 @@
 class ExtensionPrefs : public ExtensionScopedPrefs,
                        public BrowserContextKeyedService {
  public:
-  // Key name for a preference that keeps track of per-extension settings. This
-  // is a dictionary object read from the Preferences file, keyed off of
-  // extension ids.
-  static const char kExtensionsPref[];
-
-  // Key for what version chrome was last time the extension prefs were loaded.
-  static const char kExtensionsLastChromeVersion[];
-
   typedef std::vector<linked_ptr<ExtensionInfo> > ExtensionsInfo;
 
   // Vector containing identifiers for preferences.
@@ -404,6 +396,10 @@
   // Caller takes ownership of returned structure.
   scoped_ptr<ExtensionsInfo> GetInstalledExtensionsInfo() const;
 
+  // Same as above, but only includes external extensions the user has
+  // explicitly uninstalled.
+  scoped_ptr<ExtensionsInfo> GetUninstalledExtensionsInfo() const;
+
   // Returns the ExtensionInfo from the prefs for the given extension. If the
   // extension is not present, NULL is returned.
   scoped_ptr<ExtensionInfo> GetInstalledExtensionInfo(
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index c7034d1..5d5f9c7 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -18,13 +18,13 @@
 #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/extension_manifest_constants.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_info.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 "sync/api/string_ordinal.h"
 
 using base::Time;
@@ -169,9 +169,9 @@
         permission_info->CreateAPIPermission());
     {
       scoped_ptr<base::ListValue> value(new base::ListValue());
-      value->Append(Value::CreateStringValue("tcp-connect:*.example.com:80"));
-      value->Append(Value::CreateStringValue("udp-bind::8080"));
-      value->Append(Value::CreateStringValue("udp-send-to::8888"));
+      value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+      value->Append(new base::StringValue("udp-bind::8080"));
+      value->Append(new base::StringValue("udp-send-to::8888"));
       if (!permission->FromValue(value.get()))
         NOTREACHED();
     }
@@ -441,9 +441,8 @@
   // Sets idle install information for one test extension.
   void SetIdleInfo(std::string id, int num) {
     DictionaryValue manifest;
-    manifest.SetString(extension_manifest_keys::kName, "test");
-    manifest.SetString(extension_manifest_keys::kVersion,
-                       "1." + base::IntToString(num));
+    manifest.SetString(manifest_keys::kName, "test");
+    manifest.SetString(manifest_keys::kVersion, "1." + base::IntToString(num));
     base::FilePath path =
         prefs_.extensions_dir().AppendASCII(base::IntToString(num));
     std::string errors;
@@ -470,7 +469,7 @@
               info->extension_path.BaseName().MaybeAsASCII());
   }
 
-  bool HasInfoForId(extensions::ExtensionPrefs::ExtensionsInfo* info,
+  bool HasInfoForId(ExtensionPrefs::ExtensionsInfo* info,
                     const std::string& id) {
     for (size_t i = 0; i < info->size(); ++i) {
       if (info->at(i)->extension_id == id)
@@ -492,7 +491,7 @@
     SetIdleInfo(id2_, 2);
     VerifyIdleInfo(id1_, 1);
     VerifyIdleInfo(id2_, 2);
-    scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> info(
+    scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
         prefs()->GetAllDelayedInstallInfo());
     EXPECT_EQ(2u, info->size());
     EXPECT_TRUE(HasInfoForId(info.get(), id1_));
@@ -524,7 +523,7 @@
 
   virtual void Verify() OVERRIDE {
     // Make sure the info for the 3 extensions we expect is present.
-    scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> info(
+    scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
         prefs()->GetAllDelayedInstallInfo());
     EXPECT_EQ(3u, info->size());
     EXPECT_TRUE(HasInfoForId(info.get(), id1_));
@@ -548,6 +547,65 @@
 };
 TEST_F(ExtensionPrefsDelayedInstallInfo, DelayedInstallInfo) {}
 
+// Tests the FinishDelayedInstallInfo function.
+class ExtensionPrefsFinishDelayedInstallInfo : public ExtensionPrefsTest {
+ public:
+  virtual void Initialize() OVERRIDE {
+    DictionaryValue dictionary;
+    dictionary.SetString(manifest_keys::kName, "test");
+    dictionary.SetString(manifest_keys::kVersion, "0.1");
+    dictionary.SetString(manifest_keys::kBackgroundPage, "background.html");
+    scoped_refptr<Extension> extension =
+        prefs_.AddExtensionWithManifest(dictionary, Manifest::INTERNAL);
+    id_ = extension->id();
+
+
+    // Set idle info
+    DictionaryValue manifest;
+    manifest.SetString(manifest_keys::kName, "test");
+    manifest.SetString(manifest_keys::kVersion, "0.2");
+    scoped_ptr<ListValue> scripts(new ListValue);
+    scripts->AppendString("test.js");
+    manifest.Set(manifest_keys::kBackgroundScripts, scripts.release());
+    base::FilePath path =
+        prefs_.extensions_dir().AppendASCII("test_0.2");
+    std::string errors;
+    scoped_refptr<Extension> new_extension = Extension::Create(
+        path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, id_, &errors);
+    ASSERT_TRUE(new_extension.get()) << errors;
+    ASSERT_EQ(id_, new_extension->id());
+    prefs()->SetDelayedInstallInfo(new_extension.get(),
+                                   Extension::ENABLED,
+                                   Blacklist::NOT_BLACKLISTED,
+                                   ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE,
+                                   syncer::StringOrdinal());
+
+    // Finish idle installation
+    ASSERT_TRUE(prefs()->FinishDelayedInstallInfo(id_));
+  }
+
+  virtual void Verify() OVERRIDE {
+    EXPECT_FALSE(prefs()->GetDelayedInstallInfo(id_));
+
+    const DictionaryValue* manifest;
+    ASSERT_TRUE(prefs()->ReadPrefAsDictionary(id_, "manifest", &manifest));
+    ASSERT_TRUE(manifest);
+    std::string value;
+    EXPECT_TRUE(manifest->GetString(manifest_keys::kName, &value));
+    EXPECT_EQ("test", value);
+    EXPECT_TRUE(manifest->GetString(manifest_keys::kVersion, &value));
+    EXPECT_EQ("0.2", value);
+    EXPECT_FALSE(manifest->GetString(manifest_keys::kBackgroundPage, &value));
+    const ListValue* scripts;
+    ASSERT_TRUE(manifest->GetList(manifest_keys::kBackgroundScripts, &scripts));
+    EXPECT_EQ(1u, scripts->GetSize());
+  }
+
+ protected:
+  std::string id_;
+};
+TEST_F(ExtensionPrefsFinishDelayedInstallInfo, FinishDelayedInstallInfo) {}
+
 class ExtensionPrefsOnExtensionInstalled : public ExtensionPrefsTest {
  public:
   virtual void Initialize() OVERRIDE {
@@ -600,25 +658,24 @@
   virtual void Initialize() OVERRIDE {
     {
       base::DictionaryValue dictionary;
-      dictionary.SetString(extension_manifest_keys::kName, "from_webstore");
-      dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
+      dictionary.SetString(manifest_keys::kName, "from_webstore");
+      dictionary.SetString(manifest_keys::kVersion, "0.1");
       webstore_extension_ = prefs_.AddExtensionWithManifestAndFlags(
           dictionary, Manifest::INTERNAL, Extension::FROM_WEBSTORE);
     }
 
     {
       base::DictionaryValue dictionary;
-      dictionary.SetString(extension_manifest_keys::kName, "from_bookmark");
-      dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
+      dictionary.SetString(manifest_keys::kName, "from_bookmark");
+      dictionary.SetString(manifest_keys::kVersion, "0.1");
       bookmark_extension_ = prefs_.AddExtensionWithManifestAndFlags(
           dictionary, Manifest::INTERNAL, Extension::FROM_BOOKMARK);
     }
 
     {
       base::DictionaryValue dictionary;
-      dictionary.SetString(extension_manifest_keys::kName,
-                           "was_installed_by_default");
-      dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
+      dictionary.SetString(manifest_keys::kName, "was_installed_by_default");
+      dictionary.SetString(manifest_keys::kVersion, "0.1");
       default_extension_ = prefs_.AddExtensionWithManifestAndFlags(
           dictionary,
           Manifest::INTERNAL,
@@ -648,8 +705,8 @@
   DictionaryValue simple_dict;
   std::string error;
 
-  simple_dict.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
-  simple_dict.SetString(extension_manifest_keys::kName, "unused");
+  simple_dict.SetString(manifest_keys::kVersion, "1.0.0.0");
+  simple_dict.SetString(manifest_keys::kName, "unused");
 
   extension1_ = Extension::Create(
       prefs_.temp_dir().AppendASCII("ext1_"),
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index fdafe9f..25ef06b 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -19,8 +19,8 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/threading/worker_pool.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_info_map.h"
 #include "chrome/browser/extensions/image_loader.h"
@@ -35,6 +35,7 @@
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "chrome/common/extensions/web_accessible_resources_handler.h"
 #include "chrome/common/url_constants.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_resource.h"
@@ -136,7 +137,7 @@
 
     std::string* read_mime_type = new std::string;
     bool* read_result = new bool;
-    bool posted = base::WorkerPool::PostTaskAndReply(
+    bool posted = content::BrowserThread::PostBlockingPoolTaskAndReply(
         FROM_HERE,
         base::Bind(&ReadMimeTypeFromFile, filename_,
                    base::Unretained(read_mime_type),
@@ -146,8 +147,7 @@
                    mime_type, charset, data,
                    base::Owned(read_mime_type),
                    base::Owned(read_result),
-                   callback),
-        true /* task is slow */);
+                   callback));
     DCHECK(posted);
 
     return net::ERR_IO_PENDING;
@@ -251,7 +251,11 @@
                          const base::FilePath& relative_path,
                          const std::string& content_security_policy,
                          bool send_cors_header)
-    : net::URLRequestFileJob(request, network_delegate, base::FilePath()),
+    : net::URLRequestFileJob(
+          request, network_delegate, base::FilePath(),
+          content::BrowserThread::GetBlockingPool()->
+              GetTaskRunnerWithShutdownBehavior(
+                  base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
       // TODO(tc): Move all of these files into resources.pak so we don't break
       // when updating on Linux.
       resource_(extension_id, directory_path, relative_path),
@@ -267,7 +271,7 @@
   virtual void Start() OVERRIDE {
     base::FilePath* read_file_path = new base::FilePath;
     base::Time* last_modified_time = new base::Time();
-    bool posted = base::WorkerPool::PostTaskAndReply(
+    bool posted = content::BrowserThread::PostBlockingPoolTaskAndReply(
         FROM_HERE,
         base::Bind(&ReadResourceFilePathAndLastModifiedTime, resource_,
                    base::Unretained(read_file_path),
@@ -275,8 +279,7 @@
         base::Bind(&URLRequestExtensionJob::OnFilePathAndLastModifiedTimeRead,
                    weak_factory_.GetWeakPtr(),
                    base::Owned(read_file_path),
-                   base::Owned(last_modified_time)),
-        true /* task is slow */);
+                   base::Owned(last_modified_time)));
     DCHECK(posted);
   }
 
diff --git a/chrome/browser/extensions/extension_resource_protocols.cc b/chrome/browser/extensions/extension_resource_protocols.cc
index 565b08b..eb75df9 100644
--- a/chrome/browser/extensions/extension_resource_protocols.cc
+++ b/chrome/browser/extensions/extension_resource_protocols.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "base/path_service.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_checker.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension_file_util.h"
@@ -25,9 +26,12 @@
  public:
   ExtensionResourcesJob(net::URLRequest* request,
                         net::NetworkDelegate* network_delegate)
-    : net::URLRequestFileJob(request, network_delegate, base::FilePath()),
-      weak_ptr_factory_(this) {
-  }
+      : net::URLRequestFileJob(
+            request, network_delegate, base::FilePath(),
+            content::BrowserThread::GetBlockingPool()->
+                GetTaskRunnerWithShutdownBehavior(
+                    base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
+        weak_ptr_factory_(this) {}
 
   virtual void Start() OVERRIDE;
 
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 325bea2..2d0a040 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -64,8 +64,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/themes/theme_service.h"
-#include "chrome/browser/themes/theme_service_factory.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"
@@ -81,7 +79,6 @@
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "chrome/common/extensions/incognito_handler.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
@@ -101,6 +98,7 @@
 #include "content/public/browser/url_data_source.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "sync/api/sync_change.h"
@@ -162,6 +160,34 @@
   return SharedModuleInfo::IsSharedModule(extension);
 }
 
+static bool IsCWSSharedModule(const Extension* extension) {
+  return extension->from_webstore() && IsSharedModule(extension);
+}
+
+class SharedModuleProvider : public extensions::ManagementPolicy::Provider {
+ public:
+  SharedModuleProvider() {}
+  virtual ~SharedModuleProvider() {}
+
+  virtual std::string GetDebugPolicyProviderName() const OVERRIDE {
+    return "SharedModuleProvider";
+  }
+
+  virtual bool UserMayModifySettings(const Extension* extension,
+                                     string16* error) const OVERRIDE {
+    return !IsCWSSharedModule(extension);
+  }
+
+  virtual bool MustRemainEnabled(const Extension* extension,
+                                 string16* error) const OVERRIDE {
+    return IsCWSSharedModule(extension);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SharedModuleProvider);
+};
+
+
 }  // namespace
 
 ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
@@ -413,6 +439,8 @@
       new extensions::ExtensionActionStorageManager(profile_));
 #endif
 
+  shared_module_policy_provider_.reset(new SharedModuleProvider);
+
   // How long is the path to the Extensions directory?
   UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.ExtensionRootPathLength",
                               install_directory_.value().length(), 0, 500, 100);
@@ -481,7 +509,8 @@
 }
 
 void ExtensionService::Shutdown() {
-  // Do nothing for now.
+  system_->management_policy()->UnregisterProvider(
+      shared_module_policy_provider_.get());
 }
 
 const Extension* ExtensionService::GetExtensionById(
@@ -547,6 +576,21 @@
     component_loader_->LoadAll();
     extensions::InstalledLoader(this).LoadAllExtensions();
 
+    // Attempt to re-enable extensions whose only disable reason is reloading.
+    std::vector<std::string> extensions_to_enable;
+    for (ExtensionSet::const_iterator iter = disabled_extensions_.begin();
+        iter != disabled_extensions_.end(); ++iter) {
+      const Extension* e = iter->get();
+      if (extension_prefs_->GetDisableReasons(e->id()) ==
+          Extension::DISABLE_RELOAD) {
+        extensions_to_enable.push_back(e->id());
+      }
+    }
+    for (std::vector<std::string>::iterator it = extensions_to_enable.begin();
+         it != extensions_to_enable.end(); ++it) {
+      EnableExtension(*it);
+    }
+
     // Finish install (if possible) of extensions that were still delayed while
     // the browser was shut down.
     scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> delayed_info(
@@ -590,6 +634,8 @@
       GarbageCollectIsolatedStorage();
       extension_prefs_->SetNeedsStorageGarbageCollection(false);
     }
+    system_->management_policy()->RegisterProvider(
+        shared_module_policy_provider_.get());
   }
 }
 
@@ -1144,16 +1190,6 @@
       content::Source<Profile>(profile_),
       content::Details<UnloadedExtensionInfo>(&details));
 
-#if defined(ENABLE_THEMES)
-  // If the current theme is being unloaded, tell ThemeService to revert back
-  // to the default theme.
-  if (reason != extension_misc::UNLOAD_REASON_UPDATE && extension->is_theme()) {
-    ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
-    if (extension->id() == theme_service->GetThemeID())
-      theme_service->UseDefaultTheme();
-  }
-#endif
-
   for (content::RenderProcessHost::iterator i(
           content::RenderProcessHost::AllHostsIterator());
        !i.IsAtEnd(); i.Advance()) {
@@ -1476,7 +1512,6 @@
 
   // Handle uninstalls first.
   if (extension_sync_data.uninstalled()) {
-    std::string error;
     if (!UninstallExtensionHelper(this, id)) {
       LOG(WARNING) << "Could not uninstall extension " << id
                    << " for sync";
@@ -1983,15 +2018,6 @@
               extension_paths))) {
     NOTREACHED();
   }
-
-#if defined(ENABLE_THEMES)
-  // Also garbage-collect themes.  We check |profile_| to be
-  // defensive; in the future, we may call GarbageCollectExtensions()
-  // from somewhere other than Init() (e.g., in a timer).
-  if (profile_) {
-    ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes();
-  }
-#endif
 }
 
 void ExtensionService::SyncExtensionChangeIfNeeded(const Extension& extension) {
@@ -2352,7 +2378,7 @@
         scoped_ptr<const ExtensionSet> dependents =
             GetDependentExtensions(imported_module);
         if (dependents->size() == 0) {
-          UninstallExtension(i->extension_id, false, NULL);
+          UninstallExtension(i->extension_id, true, NULL);
         }
       }
     }
@@ -2582,24 +2608,10 @@
 
   AddExtension(extension);
 
-#if defined(ENABLE_THEMES)
-  // We do this here since AddExtension() is always called on browser startup,
-  // and we only really care about the last theme installed.
-  // If that ever changes and we have to move this code somewhere
-  // else, it should be somewhere that's not in the startup path.
-  if (extension->is_theme() && extensions_.GetByID(extension->id())) {
-    DCHECK_EQ(extensions_.GetByID(extension->id()), extension);
-    // Now that the theme extension is visible from outside the
-    // ExtensionService, notify the ThemeService about the
-    // newly-installed theme.
-    ThemeServiceFactory::GetForProfile(profile_)->SetTheme(extension);
-  }
-#endif
-
   // If this is a new external extension that was disabled, alert the user
   // so he can reenable it. We do this last so that it has already been
   // added to our list of extensions.
-  if (unacknowledged_external) {
+  if (unacknowledged_external && !is_update) {
     UpdateExternalExtensionAlert();
     UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
                               EXTERNAL_EXTENSION_INSTALLED,
@@ -3112,16 +3124,12 @@
     const std::set<std::string>& new_blacklisted_ids) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  std::set<std::string> no_longer_blacklisted;
-  std::set_difference(old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
-                      new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
-                      std::inserter(no_longer_blacklisted,
-                                    no_longer_blacklisted.begin()));
-  std::set<std::string> not_yet_blacklisted;
-  std::set_difference(new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
-                      old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
-                      std::inserter(not_yet_blacklisted,
-                                    not_yet_blacklisted.begin()));
+  std::set<std::string> no_longer_blacklisted =
+      base::STLSetDifference<std::set<std::string> >(old_blacklisted_ids,
+                                                     new_blacklisted_ids);
+  std::set<std::string> not_yet_blacklisted =
+      base::STLSetDifference<std::set<std::string> >(new_blacklisted_ids,
+                                                     old_blacklisted_ids);
 
   for (std::set<std::string>::iterator it = no_longer_blacklisted.begin();
        it != no_longer_blacklisted.end(); ++it) {
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index d6a837b..01fabca 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -27,6 +27,7 @@
 #include "chrome/browser/extensions/extension_toolbar_model.h"
 #include "chrome/browser/extensions/extensions_quota_service.h"
 #include "chrome/browser/extensions/external_provider_interface.h"
+#include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/extensions/menu_manager.h"
 #include "chrome/browser/extensions/pending_extension_manager.h"
 #include "chrome/browser/extensions/process_map.h"
@@ -34,10 +35,10 @@
 #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.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/notification_observer.h"
 #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"
@@ -949,6 +950,8 @@
   scoped_ptr<extensions::ExtensionActionStorageManager>
       extension_action_storage_manager_;
 #endif
+  scoped_ptr<extensions::ManagementPolicy::Provider>
+      shared_module_policy_provider_;
 
   ObserverList<extensions::UpdateObserver, true> update_observers_;
 
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index c0d461e..4ccc3c1 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -80,6 +80,7 @@
 #include "chrome/common/extensions/value_builder.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
+#include "chrome/test/base/scoped_browser_locale.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/dom_storage_context.h"
@@ -145,7 +146,7 @@
 using extensions::TestExtensionSystem;
 using extensions::URLPatternSet;
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace {
 
@@ -826,7 +827,9 @@
         EXPECT_EQ(0u, loaded_.size()) << path.value();
       } else {
         EXPECT_EQ(1u, loaded_.size()) << path.value();
-        EXPECT_EQ(expected_extensions_count_, service_->extensions()->size()) <<
+        size_t actual_extension_count = service_->extensions()->size() +
+            service_->disabled_extensions()->size();
+        EXPECT_EQ(expected_extensions_count_, actual_extension_count) <<
             path.value();
         extension = loaded_[0].get();
         EXPECT_TRUE(service_->GetExtensionById(extension->id(), false))
@@ -1101,7 +1104,7 @@
     msg += " = ";
     msg += base::IntToString(value);
 
-    SetPref(extension_id, pref_path, Value::CreateIntegerValue(value), msg);
+    SetPref(extension_id, pref_path, new base::FundamentalValue(value), msg);
   }
 
   void SetPrefBool(const std::string& extension_id,
@@ -1112,7 +1115,7 @@
     msg += " = ";
     msg += (value ? "true" : "false");
 
-    SetPref(extension_id, pref_path, Value::CreateBooleanValue(value), msg);
+    SetPref(extension_id, pref_path, new base::FundamentalValue(value), msg);
   }
 
   void ClearPref(const std::string& extension_id,
@@ -1138,7 +1141,7 @@
     ListValue* list_value = new ListValue();
     for (std::set<std::string>::const_iterator iter = value.begin();
          iter != value.end(); ++iter)
-      list_value->Append(Value::CreateStringValue(*iter));
+      list_value->Append(new base::StringValue(*iter));
 
     SetPref(extension_id, pref_path, list_value, msg);
   }
@@ -1588,13 +1591,11 @@
   InstallCRX(path, INSTALL_FAILED);
   ValidatePrefKeyCount(pref_count);
 
-  // Extensions cannot have folders or files that have underscores except in
-  // certain whitelisted cases (eg _locales). This is an example of a broader
-  // class of validation that we do to the directory structure of the extension.
-  // We did not used to handle this correctly for installation.
+  // Packed extensions may have folders or files that have underscores.
+  // This will only cause a warning, rather than a fatal error.
   path = data_dir_.AppendASCII("bad_underscore.crx");
-  InstallCRX(path, INSTALL_FAILED);
-  ValidatePrefKeyCount(pref_count);
+  InstallCRX(path, INSTALL_NEW);
+  ValidatePrefKeyCount(++pref_count);
 
   // TODO(erikkay): add more tests for many of the failure cases.
   // TODO(erikkay): add tests for upgrade cases.
@@ -2103,7 +2104,7 @@
 
   ListValue* api_permissions = new ListValue();
   api_permissions->Append(
-      Value::CreateStringValue("tabs"));
+      new base::StringValue("tabs"));
   SetPref(extension_id, "granted_permissions.api",
           api_permissions, "granted_permissions.api");
   SetPrefStringSet(
@@ -2346,6 +2347,7 @@
 
 TEST_F(ExtensionServiceTest, InstallTheme) {
   InitializeEmptyExtensionService();
+  service_->Init();
 
   // A theme.
   base::FilePath path = data_dir_.AppendASCII("theme.crx");
@@ -2387,6 +2389,8 @@
 TEST_F(ExtensionServiceTest, LoadLocalizedTheme) {
   // Load.
   InitializeEmptyExtensionService();
+  service_->Init();
+
   base::FilePath extension_path = data_dir_
       .AppendASCII("theme_i18n");
 
@@ -2485,8 +2489,20 @@
 }
 #endif
 
+TEST_F(ExtensionServiceTest, UnpackedExtensionMayNotHaveUnderscore) {
+  InitializeEmptyExtensionService();
+  base::FilePath extension_path = data_dir_
+      .AppendASCII("underscore_name");
+  extensions::UnpackedInstaller::Create(service_)->Load(extension_path);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1u, GetErrors().size());
+  EXPECT_EQ(0u, service_->extensions()->size());
+}
+
 TEST_F(ExtensionServiceTest, InstallLocalizedTheme) {
   InitializeEmptyExtensionService();
+  service_->Init();
+
   base::FilePath theme_path = data_dir_
       .AppendASCII("theme_i18n");
 
@@ -3355,7 +3371,7 @@
 
   base::ListValue whitelist;
   PrefService* prefs = service_->extension_prefs()->pref_service();
-  whitelist.Append(base::Value::CreateStringValue(good_crx));
+  whitelist.Append(new base::StringValue(good_crx));
   prefs->Set(prefs::kExtensionInstallAllowList, whitelist);
 
   std::vector<std::string> blacklist;
@@ -3419,7 +3435,7 @@
     ListPrefUpdate update(profile_->GetPrefs(),
                           prefs::kExtensionInstallDenyList);
     ListValue* blacklist = update.Get();
-    blacklist->Append(Value::CreateStringValue("*"));
+    blacklist->Append(new base::StringValue("*"));
   }
 
   // Blacklist prevents us from installing good_crx.
@@ -3432,7 +3448,7 @@
     ListPrefUpdate update(profile_->GetPrefs(),
                           prefs::kExtensionInstallAllowList);
     ListValue* whitelist = update.Get();
-    whitelist->Append(Value::CreateStringValue(good_crx));
+    whitelist->Append(new base::StringValue(good_crx));
   }
 
   // Ensure we can now install good_crx.
@@ -3456,7 +3472,7 @@
     ASSERT_TRUE(blacklist != NULL);
 
     // Blacklist this extension.
-    blacklist->Append(Value::CreateStringValue(good_crx));
+    blacklist->Append(new base::StringValue(good_crx));
   }
 
   // Extension should not be running now.
@@ -3473,7 +3489,7 @@
     ListPrefUpdate update(profile_->GetPrefs(),
                           prefs::kExtensionInstallDenyList);
     ListValue* blacklist = update.Get();
-    blacklist->Append(Value::CreateStringValue("*"));
+    blacklist->Append(new base::StringValue("*"));
   }
 
   // Install a component extension.
@@ -3502,7 +3518,7 @@
     ListPrefUpdate update(profile_->GetPrefs(),
                           prefs::kExtensionInstallDenyList);
     ListValue* blacklist = update.Get();
-    blacklist->Append(Value::CreateStringValue(good0));
+    blacklist->Append(new base::StringValue(good0));
   }
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(1u, service_->extensions()->size());
@@ -3551,7 +3567,7 @@
     ListPrefUpdate update(profile_->GetPrefs(),
                           prefs::kExtensionInstallDenyList);
     ListValue* blacklist = update.Get();
-    blacklist->Append(Value::CreateStringValue(good0));
+    blacklist->Append(new base::StringValue(good0));
   }
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(1u, service_->extensions()->size());
@@ -4662,23 +4678,6 @@
   EXPECT_EQ(0u, loaded_.size());
 }
 
-namespace {
-  class ScopedBrowserLocale {
-   public:
-    explicit ScopedBrowserLocale(const std::string& new_locale)
-      : old_locale_(g_browser_process->GetApplicationLocale()) {
-      g_browser_process->SetApplicationLocale(new_locale);
-    }
-
-    ~ScopedBrowserLocale() {
-      g_browser_process->SetApplicationLocale(old_locale_);
-    }
-
-   private:
-    std::string old_locale_;
-  };
-}  // namespace
-
 TEST_F(ExtensionServiceTest, ExternalPrefProvider) {
   InitializeEmptyExtensionService();
 
diff --git a/chrome/browser/extensions/extension_service_unittest.h b/chrome/browser/extensions/extension_service_unittest.h
index 9db4618..4239714 100644
--- a/chrome/browser/extensions/extension_service_unittest.h
+++ b/chrome/browser/extensions/extension_service_unittest.h
@@ -68,8 +68,10 @@
   void InitializeExtensionServiceHelper(bool autoupdate_enabled,
                                         bool is_first_run);
 
-  content::TestBrowserThreadBundle thread_bundle_;
+  // Destroying at_exit_manager_ will delete all LazyInstances, so it must come
+  // after thread_bundle_ in the destruction order.
   base::ShadowingAtExitManager at_exit_manager_;
+  content::TestBrowserThreadBundle thread_bundle_;
   base::ScopedTempDir temp_dir_;
   scoped_ptr<TestingProfile> profile_;
   base::FilePath extensions_install_dir_;
diff --git a/chrome/browser/extensions/extension_sorting.cc b/chrome/browser/extensions/extension_sorting.cc
index 1af6640..fa17dac 100644
--- a/chrome/browser/extensions/extension_sorting.cc
+++ b/chrome/browser/extensions/extension_sorting.cc
@@ -306,7 +306,7 @@
   AddOrdinalMapping(extension_id, page_ordinal, new_app_launch_ordinal);
 
   Value* new_value = new_app_launch_ordinal.IsValid() ?
-      Value::CreateStringValue(new_app_launch_ordinal.ToInternalValue()) :
+      new base::StringValue(new_app_launch_ordinal.ToInternalValue()) :
       NULL;
 
   extension_scoped_prefs_->UpdateExtensionPref(
@@ -385,7 +385,7 @@
   AddOrdinalMapping(extension_id, new_page_ordinal, app_launch_ordinal);
 
   Value* new_value = new_page_ordinal.IsValid() ?
-      Value::CreateStringValue(new_page_ordinal.ToInternalValue()) :
+      new base::StringValue(new_page_ordinal.ToInternalValue()) :
       NULL;
 
   extension_scoped_prefs_->UpdateExtensionPref(
diff --git a/chrome/browser/extensions/extension_sorting_unittest.cc b/chrome/browser/extensions/extension_sorting_unittest.cc
index b84535e..295ff6a 100644
--- a/chrome/browser/extensions/extension_sorting_unittest.cc
+++ b/chrome/browser/extensions/extension_sorting_unittest.cc
@@ -7,7 +7,7 @@
 #include <map>
 
 #include "chrome/browser/extensions/extension_prefs_unittest.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "extensions/common/manifest_constants.h"
 #include "sync/api/string_ordinal.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -15,7 +15,7 @@
 using extensions::Extension;
 using extensions::Manifest;
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 class ExtensionSortingTest : public extensions::ExtensionPrefsTest {
  protected:
@@ -165,24 +165,24 @@
         static_cast<ExtensionScopedPrefs*>(prefs());
     scoped_prefs->UpdateExtensionPref(extension1()->id(),
                                       kPrefAppLaunchIndexDeprecated,
-                                      Value::CreateIntegerValue(0));
+                                      new base::FundamentalValue(0));
     scoped_prefs->UpdateExtensionPref(extension1()->id(),
                                       kPrefPageIndexDeprecated,
-                                      Value::CreateIntegerValue(0));
+                                      new base::FundamentalValue(0));
 
     scoped_prefs->UpdateExtensionPref(extension2()->id(),
                                       kPrefAppLaunchIndexDeprecated,
-                                      Value::CreateIntegerValue(1));
+                                      new base::FundamentalValue(1));
     scoped_prefs->UpdateExtensionPref(extension2()->id(),
                                       kPrefPageIndexDeprecated,
-                                      Value::CreateIntegerValue(0));
+                                      new base::FundamentalValue(0));
 
     scoped_prefs->UpdateExtensionPref(extension3()->id(),
                                       kPrefAppLaunchIndexDeprecated,
-                                      Value::CreateIntegerValue(0));
+                                      new base::FundamentalValue(0));
     scoped_prefs->UpdateExtensionPref(extension3()->id(),
                                       kPrefPageIndexDeprecated,
-                                      Value::CreateIntegerValue(1));
+                                      new base::FundamentalValue(1));
 
     // We insert the ids in reserve order so that we have to deal with the
     // element on the 2nd page before the 1st page is seen.
@@ -281,10 +281,10 @@
         static_cast<ExtensionScopedPrefs*>(prefs());
     scoped_prefs->UpdateExtensionPref(extension1()->id(),
                                       kPrefAppLaunchIndexDeprecated,
-                                      Value::CreateIntegerValue(0));
+                                      new base::FundamentalValue(0));
     scoped_prefs->UpdateExtensionPref(extension1()->id(),
                                       kPrefPageIndexDeprecated,
-                                      Value::CreateIntegerValue(-1));
+                                      new base::FundamentalValue(-1));
 
     extensions::ExtensionIdList ids;
     ids.push_back(extension1()->id());
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
index 74f34fe..6b23aa8 100644
--- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -9,10 +9,10 @@
 #include "chrome/common/content_settings.h"
 #include "chrome/common/content_settings_types.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::BrowserThread;
@@ -22,7 +22,7 @@
 
 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy;
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 class ExtensionSpecialStoragePolicyTest : public testing::Test {
  protected:
@@ -105,8 +105,8 @@
     manifest.SetString(keys::kVersion, "1");
     manifest.SetString(keys::kLaunchWebURL, "http://explicit/protected/start");
     base::ListValue* list = new base::ListValue();
-    list->Append(Value::CreateStringValue("http://explicit/protected"));
-    list->Append(Value::CreateStringValue("*://*.wildcards/protected"));
+    list->Append(new base::StringValue("http://explicit/protected"));
+    list->Append(new base::StringValue("*://*.wildcards/protected"));
     manifest.Set(keys::kWebURLs, list);
     std::string error;
     scoped_refptr<Extension> protected_app = Extension::Create(
@@ -127,11 +127,11 @@
     manifest.SetString(keys::kVersion, "1");
     manifest.SetString(keys::kLaunchWebURL, "http://explicit/unlimited/start");
     base::ListValue* list = new base::ListValue();
-    list->Append(Value::CreateStringValue("unlimitedStorage"));
+    list->Append(new base::StringValue("unlimitedStorage"));
     manifest.Set(keys::kPermissions, list);
     list = new base::ListValue();
-    list->Append(Value::CreateStringValue("http://explicit/unlimited"));
-    list->Append(Value::CreateStringValue("*://*.wildcards/unlimited"));
+    list->Append(new base::StringValue("http://explicit/unlimited"));
+    list->Append(new base::StringValue("*://*.wildcards/unlimited"));
     manifest.Set(keys::kWebURLs, list);
     std::string error;
     scoped_refptr<Extension> unlimited_app = Extension::Create(
diff --git a/chrome/browser/extensions/extension_system.cc b/chrome/browser/extensions/extension_system.cc
index 0639302..0b75800 100644
--- a/chrome/browser/extensions/extension_system.cc
+++ b/chrome/browser/extensions/extension_system.cc
@@ -41,10 +41,10 @@
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/features/feature_channel.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/url_data_source.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/manifest.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/app_mode/app_mode_utils.h"
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 8b427ab..e1cdda0 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -28,6 +28,7 @@
 #include "content/public/browser/favicon_status.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
 #include "url/gurl.h"
 
 namespace keys = extensions::tabs_constants;
@@ -144,13 +145,17 @@
                      tab_strip && tab_strip->IsTabPinned(tab_index));
   result->SetBoolean(keys::kIncognitoKey,
                      contents->GetBrowserContext()->IsOffTheRecord());
+  result->SetInteger(keys::kWidthKey,
+                     contents->GetView()->GetContainerSize().width());
+  result->SetInteger(keys::kHeightKey,
+                     contents->GetView()->GetContainerSize().height());
 
   // Privacy-sensitive fields: these should be stripped off by
   // ScrubTabValueForExtension if the extension should not see them.
   result->SetString(keys::kUrlKey, contents->GetURL().spec());
   result->SetString(keys::kTitleKey, contents->GetTitle());
   if (!is_loading) {
-    NavigationEntry* entry = contents->GetController().GetActiveEntry();
+    NavigationEntry* entry = contents->GetController().GetVisibleEntry();
     if (entry && entry->GetFavicon().valid)
       result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
   }
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc
index 7a654a5..e8fe924 100644
--- a/chrome/browser/extensions/extension_tabs_apitest.cc
+++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -78,6 +78,10 @@
   ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "duplicate.html")) << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabSize) {
+  ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "tab_size.html")) << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, TabUpdate) {
   ASSERT_TRUE(RunExtensionSubtest("tabs/basics", "update.html")) << message_;
 }
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc
index 8d23097..c869fd9 100644
--- a/chrome/browser/extensions/extension_toolbar_model.cc
+++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -7,7 +7,6 @@
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/browser_event_router.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_prefs.h"
@@ -130,13 +129,9 @@
     const Extension* extension,
     Browser* browser,
     GURL* popup_url_out) {
-  content::WebContents* web_contents =
-      browser->tab_strip_model()->GetActiveWebContents();
-  if (!web_contents)
-    return ACTION_NONE;
-
-  int tab_id = ExtensionTabUtil::GetTabId(web_contents);
-  if (tab_id < 0)
+  content::WebContents* web_contents = NULL;
+  int tab_id = 0;
+  if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
     return ACTION_NONE;
 
   ExtensionAction* browser_action =
@@ -156,8 +151,8 @@
     return ACTION_SHOW_POPUP;
   }
 
-  service_->browser_event_router()->BrowserActionExecuted(
-      *browser_action, browser);
+  extensions::ExtensionActionAPI::BrowserActionExecuted(
+      service_->profile(), *browser_action, web_contents);
   return ACTION_NONE;
 }
 
diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc
index 5b2ebe1..d856cf1 100644
--- a/chrome/browser/extensions/extension_ui_unittest.cc
+++ b/chrome/browser/extensions/extension_ui_unittest.cc
@@ -144,10 +144,10 @@
   std::vector<ExtensionPage> pages;
   pages.push_back(ExtensionPage(
       GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/bar.html"),
-      42, 88, false));
+      42, 88, false, false));
   pages.push_back(ExtensionPage(
       GURL("chrome-extension://behllobkkfkfnphdnhnkndlbkcpglgmj/dog.html"),
-      0, 0, false));
+      0, 0, false, false));
 
   expected_output_path = data_test_dir_path.AppendASCII("extensions")
       .AppendASCII("ui")
diff --git a/chrome/browser/extensions/extension_url_rewrite_browsertest.cc b/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
index 0eb343f..0db2dcb 100644
--- a/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
+++ b/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
@@ -46,7 +46,7 @@
   }
 
   NavigationEntry* GetNavigationEntry() const {
-    return GetNavigationController()->GetActiveEntry();
+    return GetNavigationController()->GetVisibleEntry();
   }
 
   base::FilePath GetTestExtensionPath(const char* extension_name) const {
diff --git a/chrome/browser/extensions/extension_webkit_preferences.cc b/chrome/browser/extensions/extension_webkit_preferences.cc
index 025dcc5..bf9b7a9 100644
--- a/chrome/browser/extensions/extension_webkit_preferences.cc
+++ b/chrome/browser/extensions/extension_webkit_preferences.cc
@@ -7,7 +7,7 @@
 #include "base/command_line.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "webkit/common/webpreferences.h"
 
 namespace extension_webkit_preferences {
@@ -61,4 +61,4 @@
   }
 }
 
-}  // extension_webkit_preferences
+}  // namespace extension_webkit_preferences
diff --git a/chrome/browser/extensions/external_policy_loader_unittest.cc b/chrome/browser/extensions/external_policy_loader_unittest.cc
index 4270a24..fa6039d 100644
--- a/chrome/browser/extensions/external_policy_loader_unittest.cc
+++ b/chrome/browser/extensions/external_policy_loader_unittest.cc
@@ -13,11 +13,11 @@
 #include "chrome/browser/extensions/external_provider_impl.h"
 #include "chrome/browser/extensions/external_provider_interface.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.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/test/test_browser_thread.h"
+#include "extensions/common/manifest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using content::BrowserThread;
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index 41d064a..811adc2 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -28,9 +28,9 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/common/manifest.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/external_provider_impl.h b/chrome/browser/extensions/external_provider_impl.h
index ef6a890..8375826 100644
--- a/chrome/browser/extensions/external_provider_impl.h
+++ b/chrome/browser/extensions/external_provider_impl.h
@@ -11,7 +11,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/extensions/external_loader.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class Profile;
 
diff --git a/chrome/browser/extensions/external_provider_interface.h b/chrome/browser/extensions/external_provider_interface.h
index d82e0b1..e99cd61 100644
--- a/chrome/browser/extensions/external_provider_interface.h
+++ b/chrome/browser/extensions/external_provider_interface.h
@@ -8,7 +8,7 @@
 #include <vector>
 
 #include "base/memory/linked_ptr.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class GURL;
 
diff --git a/chrome/browser/extensions/image_loader_unittest.cc b/chrome/browser/extensions/image_loader_unittest.cc
index 8c541a6..05cea06 100644
--- a/chrome/browser/extensions/image_loader_unittest.cc
+++ b/chrome/browser/extensions/image_loader_unittest.cc
@@ -12,11 +12,11 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_icon_set.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_browser_thread.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/manifest.h"
 #include "grit/component_extension_resources.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/extensions/install_tracker.cc b/chrome/browser/extensions/install_tracker.cc
index 1212c5b..dc4f3c2 100644
--- a/chrome/browser/extensions/install_tracker.cc
+++ b/chrome/browser/extensions/install_tracker.cc
@@ -30,7 +30,7 @@
       content::Source<Profile>(profile));
 
   pref_change_registrar_.Init(prefs->pref_service());
-  pref_change_registrar_.Add(extensions::ExtensionPrefs::kExtensionsPref,
+  pref_change_registrar_.Add(prefs::kExtensionsPref,
                              base::Bind(&InstallTracker::OnAppsReordered,
                                         base::Unretained(this)));
 }
@@ -101,6 +101,9 @@
       const Extension* extension = unload_info->extension;
       FOR_EACH_OBSERVER(InstallObserver, observers_,
                         OnExtensionUnloaded(extension));
+      if (unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL)
+        FOR_EACH_OBSERVER(InstallObserver, observers_,
+                          OnExtensionUninstalled(extension));
       break;
     }
     case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index 3f57865..7b02fba 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -25,11 +25,11 @@
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/common/manifest.h"
 
 using content::BrowserThread;
 using content::UserMetricsAction;
@@ -50,6 +50,7 @@
   NOT_NEEDED = 0,  // Reload not needed.
   UNPACKED_DIR,  // Unpacked directory.
   NEEDS_RELOCALIZATION,  // The locale has changed since we read this extension.
+  CORRUPT_PREFERENCES,  // The manifest in the preferences is corrupt.
   NUM_MANIFEST_RELOAD_REASONS
 };
 
@@ -70,9 +71,25 @@
   EXTERNAL_ITEM_WEBSTORE_ENABLED = 3,
   EXTERNAL_ITEM_NONWEBSTORE_DISABLED = 4,
   EXTERNAL_ITEM_NONWEBSTORE_ENABLED = 5,
-  EXTERNAL_ITEM_MAX_ITEMS = 6
+  EXTERNAL_ITEM_WEBSTORE_UNINSTALLED = 6,
+  EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED = 7,
+  EXTERNAL_ITEM_MAX_ITEMS = 8
 };
 
+bool IsManifestCorrupt(const DictionaryValue* manifest) {
+  if (!manifest)
+    return false;
+
+  // Because of bug #272524 sometimes manifests got mangled in the preferences
+  // file, one particularly bad case resulting in having both a background page
+  // and background scripts values. In those situations we want to reload the
+  // manifest from the extension to fix this.
+  const Value* background_page;
+  const Value* background_scripts;
+  return manifest->Get(manifest_keys::kBackgroundPage, &background_page) &&
+      manifest->Get(manifest_keys::kBackgroundScripts, &background_scripts);
+}
+
 ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
   // Always reload manifests of unpacked extensions, because they can change
   // on disk independent of the manifest in our prefs.
@@ -84,6 +101,10 @@
           info.extension_manifest.get()))
     return NEEDS_RELOCALIZATION;
 
+  // Reload if the copy of the manifest in the preferences is corrupt.
+  if (IsManifestCorrupt(info.extension_manifest.get()))
+    return CORRUPT_PREFERENCES;
+
   return NOT_NEEDED;
 }
 
@@ -392,6 +413,7 @@
     extension_service_->RecordPermissionMessagesHistogram(
         ex->get(), "Extensions.Permissions_Load");
   }
+
   const ExtensionSet* disabled_extensions =
       extension_service_->disabled_extensions();
   for (ex = disabled_extensions->begin();
@@ -414,6 +436,25 @@
     }
   }
 
+  scoped_ptr<ExtensionPrefs::ExtensionsInfo> uninstalled_extensions_info(
+      extension_prefs_->GetUninstalledExtensionsInfo());
+  for (size_t i = 0; i < uninstalled_extensions_info->size(); ++i) {
+    ExtensionInfo* info = uninstalled_extensions_info->at(i).get();
+    if (Manifest::IsExternalLocation(info->extension_location)) {
+      std::string update_url;
+      if (info->extension_manifest->GetString("update_url", &update_url) &&
+          extension_urls::IsWebstoreUpdateUrl(GURL(update_url))) {
+        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
+                                  EXTERNAL_ITEM_WEBSTORE_UNINSTALLED,
+                                  EXTERNAL_ITEM_MAX_ITEMS);
+      } else {
+        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
+                                  EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED,
+                                  EXTERNAL_ITEM_MAX_ITEMS);
+      }
+    }
+  }
+
   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAllUser", item_user_count);
   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
                            app_user_count + app_external_count);
diff --git a/chrome/browser/extensions/menu_manager.cc b/chrome/browser/extensions/menu_manager.cc
index 2091db8..6b0303d 100644
--- a/chrome/browser/extensions/menu_manager.cc
+++ b/chrome/browser/extensions/menu_manager.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/extensions/state_store.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/api/context_menus.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/public/browser/notification_details.h"
@@ -35,6 +36,8 @@
 
 namespace extensions {
 
+namespace context_menus = api::context_menus;
+
 namespace {
 
 // Keys for serialization to and from Value to store in the preferences.
@@ -681,7 +684,7 @@
     event_router->DispatchEventToExtension(item->extension_id(), event.Pass());
   }
   {
-    scoped_ptr<Event> event(new Event(event_names::kOnContextMenuClicked,
+    scoped_ptr<Event> event(new Event(context_menus::OnClicked::kEventName,
                                       args.Pass()));
     event->restrict_to_profile = profile;
     event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
diff --git a/chrome/browser/extensions/menu_manager.h b/chrome/browser/extensions/menu_manager.h
index 764e861..b3d085d 100644
--- a/chrome/browser/extensions/menu_manager.h
+++ b/chrome/browser/extensions/menu_manager.h
@@ -110,7 +110,8 @@
     }
 
     scoped_ptr<base::Value> ToValue() const {
-      return scoped_ptr<base::Value>(base::Value::CreateIntegerValue(value_));
+      return scoped_ptr<base::Value>(
+          new base::FundamentalValue(static_cast<int>(value_)));
     }
 
     bool Populate(const base::Value& value) {
diff --git a/chrome/browser/extensions/menu_manager_unittest.cc b/chrome/browser/extensions/menu_manager_unittest.cc
index e8ad2c6..5fef312 100644
--- a/chrome/browser/extensions/menu_manager_unittest.cc
+++ b/chrome/browser/extensions/menu_manager_unittest.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #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"
@@ -40,6 +41,8 @@
 
 namespace extensions {
 
+namespace context_menus = api::context_menus;
+
 // Base class for tests.
 class MenuManagerTest : public testing::Test {
  public:
@@ -83,10 +86,10 @@
   }
 
  protected:
-  TestingProfile profile_;
   base::MessageLoopForUI message_loop_;
   content::TestBrowserThread ui_thread_;
   content::TestBrowserThread file_thread_;
+  TestingProfile profile_;
 
   MenuManager manager_;
   ExtensionList extensions_;
@@ -216,15 +219,15 @@
 
   base::ListValue* document_url_patterns(new base::ListValue());
   document_url_patterns->Append(
-      Value::CreateStringValue("http://www.google.com/*"));
+      new base::StringValue("http://www.google.com/*"));
   document_url_patterns->Append(
-      Value::CreateStringValue("http://www.reddit.com/*"));
+      new base::StringValue("http://www.reddit.com/*"));
 
   base::ListValue* target_url_patterns(new base::ListValue());
   target_url_patterns->Append(
-      Value::CreateStringValue("http://www.yahoo.com/*"));
+      new base::StringValue("http://www.yahoo.com/*"));
   target_url_patterns->Append(
-      Value::CreateStringValue("http://www.facebook.com/*"));
+      new base::StringValue("http://www.facebook.com/*"));
 
   base::DictionaryValue value;
   value.SetBoolean("incognito", incognito);
@@ -588,7 +591,7 @@
     EXPECT_CALL(*mock_event_router,
               DispatchEventToExtensionMock(
                   item->extension_id(),
-                  extensions::event_names::kOnContextMenuClicked,
+                  context_menus::OnClicked::kEventName,
                   _,
                   &profile,
                   GURL(),
diff --git a/chrome/browser/extensions/navigation_observer.cc b/chrome/browser/extensions/navigation_observer.cc
index 3e3bde3..a4ef5c7 100644
--- a/chrome/browser/extensions/navigation_observer.cc
+++ b/chrome/browser/extensions/navigation_observer.cc
@@ -52,7 +52,7 @@
   if (!in_progress_prompt_extension_id_.empty())
     return;
 
-  NavigationEntry* nav_entry = nav_controller->GetActiveEntry();
+  NavigationEntry* nav_entry = nav_controller->GetVisibleEntry();
   if (!nav_entry)
     return;
 
diff --git a/chrome/browser/extensions/page_action_controller.cc b/chrome/browser/extensions/page_action_controller.cc
index 62dab8f..4c0cb07 100644
--- a/chrome/browser/extensions/page_action_controller.cc
+++ b/chrome/browser/extensions/page_action_controller.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/extensions/page_action_controller.h"
 
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/browser_event_router.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
@@ -72,7 +72,7 @@
       if (page_action->HasPopup(tab_id))
         return ACTION_SHOW_POPUP;
 
-      GetExtensionService()->browser_event_router()->PageActionExecuted(
+      ExtensionActionAPI::PageActionExecuted(
           profile(), *page_action, tab_id,
           web_contents()->GetURL().spec(), mouse_button);
       return ACTION_NONE;
diff --git a/chrome/browser/extensions/pending_extension_info.h b/chrome/browser/extensions/pending_extension_info.h
index dbcf1bd..fbd4666 100644
--- a/chrome/browser/extensions/pending_extension_info.h
+++ b/chrome/browser/extensions/pending_extension_info.h
@@ -9,7 +9,7 @@
 
 #include "base/version.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "url/gurl.h"
 
 FORWARD_DECLARE_TEST(ExtensionServiceTest, AddPendingExtensionFromSync);
diff --git a/chrome/browser/extensions/pending_extension_manager.h b/chrome/browser/extensions/pending_extension_manager.h
index 41bf30c..a8f0270 100644
--- a/chrome/browser/extensions/pending_extension_manager.h
+++ b/chrome/browser/extensions/pending_extension_manager.h
@@ -10,7 +10,7 @@
 
 #include "chrome/browser/extensions/pending_extension_info.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class ExtensionServiceInterface;
 class GURL;
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc
index e52af60..5ca9f53 100644
--- a/chrome/browser/extensions/permissions_updater.cc
+++ b/chrome/browser/extensions/permissions_updater.cc
@@ -27,12 +27,7 @@
 
 namespace extensions {
 
-namespace {
-
-const char kOnAdded[] = "permissions.onAdded";
-const char kOnRemoved[] = "permissions.onRemoved";
-
-}  // namespace
+namespace permissions = api::permissions;
 
 PermissionsUpdater::PermissionsUpdater(Profile* profile)
     : profile_(profile) {}
@@ -123,11 +118,11 @@
 
   if (event_type == REMOVED) {
     reason = UpdatedExtensionPermissionsInfo::REMOVED;
-    event_name = kOnRemoved;
+    event_name = permissions::OnRemoved::kEventName;
   } else {
     CHECK_EQ(ADDED, event_type);
     reason = UpdatedExtensionPermissionsInfo::ADDED;
-    event_name = kOnAdded;
+    event_name = permissions::OnAdded::kEventName;
   }
 
   // Notify other APIs or interested parties.
diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc
deleted file mode 100644
index 8126988..0000000
--- a/chrome/browser/extensions/platform_app_browsertest.cc
+++ /dev/null
@@ -1,1088 +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 "apps/launcher.h"
-#include "apps/native_app_window.h"
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/prefs/pref_service.h"
-#include "base/stl_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/platform_thread.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/automation/automation_util.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/devtools/devtools_window.h"
-#include "chrome/browser/extensions/api/permissions/permissions_api.h"
-#include "chrome/browser/extensions/component_loader.h"
-#include "chrome/browser/extensions/event_names.h"
-#include "chrome/browser/extensions/event_router.h"
-#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_system.h"
-#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
-#include "chrome/browser/tab_contents/render_view_context_menu.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/extensions/application_launch.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/test_switches.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/user_prefs/pref_registry_syncable.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/test/test_utils.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "url/gurl.h"
-
-using apps::ShellWindow;
-using apps::ShellWindowRegistry;
-using content::WebContents;
-using web_modal::WebContentsModalDialogManager;
-
-namespace extensions {
-
-namespace {
-
-// Non-abstract RenderViewContextMenu class.
-class PlatformAppContextMenu : public RenderViewContextMenu {
- public:
-  PlatformAppContextMenu(WebContents* web_contents,
-                         const content::ContextMenuParams& params)
-      : RenderViewContextMenu(web_contents, params) {}
-
-  bool HasCommandWithId(int command_id) {
-    return menu_model_.GetIndexOfCommandId(command_id) != -1;
-  }
-
- protected:
-  // RenderViewContextMenu implementation.
-  virtual bool GetAcceleratorForCommandId(
-      int command_id,
-      ui::Accelerator* accelerator) OVERRIDE {
-    return false;
-  }
-  virtual void PlatformInit() OVERRIDE {}
-  virtual void PlatformCancel() OVERRIDE {}
-};
-
-// This class keeps track of tabs as they are added to the browser. It will be
-// "done" (i.e. won't block on Wait()) once |observations| tabs have been added.
-class TabsAddedNotificationObserver
-    : public content::WindowedNotificationObserver {
- public:
-  explicit TabsAddedNotificationObserver(size_t observations)
-      : content::WindowedNotificationObserver(
-            chrome::NOTIFICATION_TAB_ADDED,
-            content::NotificationService::AllSources()),
-        observations_(observations) {
-  }
-
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    observed_tabs_.push_back(
-        content::Details<WebContents>(details).ptr());
-    if (observed_tabs_.size() == observations_)
-      content::WindowedNotificationObserver::Observe(type, source, details);
-  }
-
-  const std::vector<content::WebContents*>& tabs() { return observed_tabs_; }
-
- private:
-  size_t observations_;
-  std::vector<content::WebContents*> observed_tabs_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabsAddedNotificationObserver);
-};
-
-bool CopyTestDataAndSetCommandLineArg(
-    const base::FilePath& test_data_file,
-    const base::FilePath& temp_dir,
-    const char* filename) {
-  base::FilePath path = temp_dir.AppendASCII(
-      filename).NormalizePathSeparators();
-  if (!(base::CopyFile(test_data_file, path)))
-    return false;
-
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  command_line->AppendArgPath(path);
-  return true;
-}
-
-const char kTestFilePath[] = "platform_apps/launch_files/test.txt";
-
-}  // namespace
-
-// Tests that CreateShellWindow doesn't crash if you close it straight away.
-// LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
-// ash, so we test that it works here.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseShellWindow) {
-  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
-  ShellWindow* window = CreateShellWindow(extension);
-  CloseShellWindow(window);
-}
-
-// Tests that platform apps received the "launch" event when launched.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OnLaunchedEvent) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch")) << message_;
-}
-
-// Tests that platform apps cannot use certain disabled window properties, but
-// can override them and then use them.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisabledWindowProperties) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/disabled_window_properties"))
-      << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("minimal");
-
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  // The empty app doesn't add any context menu items, so its menu should
-  // only include the developer tools.
-  WebContents* web_contents = GetFirstShellWindowWebContents();
-  ASSERT_TRUE(web_contents);
-  content::ContextMenuParams params;
-  scoped_ptr<PlatformAppContextMenu> menu;
-  menu.reset(new PlatformAppContextMenu(web_contents, params));
-  menu->Init();
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
-  ASSERT_TRUE(
-      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("context_menu");
-
-  // Wait for the extension to tell us it's initialized its context menus and
-  // launched a window.
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  // The context_menu app has two context menu items. These, along with a
-  // separator and the developer tools, is all that should be in the menu.
-  WebContents* web_contents = GetFirstShellWindowWebContents();
-  ASSERT_TRUE(web_contents);
-  content::ContextMenuParams params;
-  scoped_ptr<PlatformAppContextMenu> menu;
-  menu.reset(new PlatformAppContextMenu(web_contents, params));
-  menu->Init();
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
-  ASSERT_TRUE(
-      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, InstalledAppWithContextMenu) {
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  InstallAndLaunchPlatformApp("context_menu");
-
-  // Wait for the extension to tell us it's initialized its context menus and
-  // launched a window.
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  // The context_menu app has two context menu items. For an installed app
-  // these are all that should be in the menu.
-  WebContents* web_contents = GetFirstShellWindowWebContents();
-  ASSERT_TRUE(web_contents);
-  content::ContextMenuParams params;
-  scoped_ptr<PlatformAppContextMenu> menu;
-  menu.reset(new PlatformAppContextMenu(web_contents, params));
-  menu->Init();
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
-  ASSERT_FALSE(
-      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("context_menu");
-
-  // Wait for the extension to tell us it's initialized its context menus and
-  // launched a window.
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  // The context_menu app has one context menu item. This, along with a
-  // separator and the developer tools, is all that should be in the menu.
-  WebContents* web_contents = GetFirstShellWindowWebContents();
-  ASSERT_TRUE(web_contents);
-  content::ContextMenuParams params;
-  params.is_editable = true;
-  scoped_ptr<PlatformAppContextMenu> menu;
-  menu.reset(new PlatformAppContextMenu(web_contents, params));
-  menu->Init();
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
-  ASSERT_TRUE(
-      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuSelection) {
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("context_menu");
-
-  // Wait for the extension to tell us it's initialized its context menus and
-  // launched a window.
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  // The context_menu app has one context menu item. This, along with a
-  // separator and the developer tools, is all that should be in the menu.
-  WebContents* web_contents = GetFirstShellWindowWebContents();
-  ASSERT_TRUE(web_contents);
-  content::ContextMenuParams params;
-  params.selection_text = ASCIIToUTF16("Hello World");
-  scoped_ptr<PlatformAppContextMenu> menu;
-  menu.reset(new PlatformAppContextMenu(web_contents, params));
-  menu->Init();
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
-  ASSERT_TRUE(
-      menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
-  ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuClicked) {
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("context_menu_click");
-
-  // Wait for the extension to tell us it's initialized its context menus and
-  // launched a window.
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  // Test that the menu item shows up
-  WebContents* web_contents = GetFirstShellWindowWebContents();
-  ASSERT_TRUE(web_contents);
-  content::ContextMenuParams params;
-  params.page_url = GURL("http://foo.bar");
-  scoped_ptr<PlatformAppContextMenu> menu;
-  menu.reset(new PlatformAppContextMenu(web_contents, params));
-  menu->Init();
-  ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
-
-  // Execute the menu item
-  ExtensionTestMessageListener onclicked_listener("onClicked fired for id1",
-                                                  false);
-  menu->ExecuteCommand(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, 0);
-
-  ASSERT_TRUE(onclicked_listener.WaitUntilSatisfied());
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
-  TabsAddedNotificationObserver observer(2);
-
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
-
-  observer.Wait();
-  ASSERT_EQ(2U, observer.tabs().size());
-  EXPECT_EQ(std::string(chrome::kExtensionInvalidRequestURL),
-            observer.tabs()[0]->GetURL().spec());
-  EXPECT_EQ("http://chromium.org/",
-            observer.tabs()[1]->GetURL().spec());
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
-}
-
-// Tests that localStorage and WebSQL are disabled for platform apps.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowStorage) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/storage")) << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Restrictions) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restrictions")) << message_;
-}
-
-// Tests that platform apps can use the chrome.app.window.* API.
-// It is flaky: http://crbug.com/223467
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DISABLED_WindowsApi) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/windows_api")) << message_;
-}
-
-// Tests that extensions can't use platform-app-only APIs.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, PlatformAppsOnly) {
-  ASSERT_TRUE(RunExtensionTestIgnoreManifestWarnings(
-      "platform_apps/apps_only")) << message_;
-}
-
-// Tests that platform apps have isolated storage by default.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  // Load a (non-app) page under the "localhost" origin that sets a cookie.
-  GURL set_cookie_url = embedded_test_server()->GetURL(
-      "/extensions/platform_apps/isolation/set_cookie.html");
-  GURL::Replacements replace_host;
-  std::string host_str("localhost");  // Must stay in scope with replace_host.
-  replace_host.SetHostStr(host_str);
-  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
-
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), set_cookie_url,
-      CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
-  // Make sure the cookie is set.
-  int cookie_size;
-  std::string cookie_value;
-  automation_util::GetCookies(
-      set_cookie_url,
-      browser()->tab_strip_model()->GetWebContentsAt(0),
-      &cookie_size,
-      &cookie_value);
-  ASSERT_EQ("testCookie=1", cookie_value);
-
-  // Let the platform app request the same URL, and make sure that it doesn't
-  // see the cookie.
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/isolation")) << message_;
-}
-
-// See crbug.com/248441
-#if defined(OS_WIN)
-#define MAYBE_ExtensionWindowingApis DISABLED_ExtensionWindowingApis
-#else
-#define MAYBE_ExtensionWindowingApis ExtensionWindowingApis
-#endif
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ExtensionWindowingApis) {
-  // Initially there should be just the one browser window visible to the
-  // extensions API.
-  const Extension* extension = LoadExtension(
-      test_data_dir_.AppendASCII("common/background_page"));
-  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
-
-  // And no shell windows.
-  ASSERT_EQ(0U, GetShellWindowCount());
-
-  // Launch a platform app that shows a window.
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("minimal");
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-  ASSERT_EQ(1U, GetShellWindowCount());
-  ShellWindowRegistry::ShellWindowList shell_windows =
-      ShellWindowRegistry::Get(browser()->profile())->shell_windows();
-  int shell_window_id = (*shell_windows.begin())->session_id().id();
-
-  // But it's not visible to the extensions API, it still thinks there's just
-  // one browser window.
-  ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
-  // It can't look it up by ID either
-  ASSERT_FALSE(RunGetWindowFunctionForExtension(shell_window_id, extension));
-
-  // The app can also only see one window (its own).
-  // TODO(jeremya): add an extension function to get a shell window by ID, and
-  // to get a list of all the shell windows, so we can test this.
-
-  // Launch another platform app that also shows a window.
-  ExtensionTestMessageListener launched_listener2("Launched", false);
-  LoadAndLaunchPlatformApp("context_menu");
-  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
-
-  // There are two total shell windows, but each app can only see its own.
-  ASSERT_EQ(2U, GetShellWindowCount());
-  // TODO(jeremya): as above, this requires more extension functions.
-}
-
-// ChromeOS does not support passing arguments on the command line, so the tests
-// that rely on this functionality are disabled.
-#if !defined(OS_CHROMEOS)
-// Tests that command line parameters get passed through to platform apps
-// via launchData correctly when launching with a file.
-// TODO(benwells/jeremya): tests need a way to specify a handler ID.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
-      << message_;
-}
-
-// Tests that relative paths can be passed through to the platform app.
-// This test doesn't use the normal test infrastructure as it needs to open
-// the application differently to all other platform app tests, by setting
-// the chrome::AppLaunchParams.current_directory field.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithRelativeFile) {
-  // Setup the command line
-  ClearCommandLineArgs();
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  base::FilePath relative_test_doc =
-      base::FilePath::FromUTF8Unsafe(kTestFilePath);
-  relative_test_doc = relative_test_doc.NormalizePathSeparators();
-  command_line->AppendArgPath(relative_test_doc);
-
-  // Load the extension
-  ResultCatcher catcher;
-  const Extension* extension = LoadExtension(
-      test_data_dir_.AppendASCII("platform_apps/launch_file"));
-  ASSERT_TRUE(extension);
-
-  // Run the test
-  chrome::AppLaunchParams params(browser()->profile(), extension,
-                                 extension_misc::LAUNCH_NONE, NEW_WINDOW);
-  params.command_line = CommandLine::ForCurrentProcess();
-  params.current_directory = test_data_dir_;
-  chrome::OpenApplication(params);
-
-  if (!catcher.GetNextResult()) {
-    message_ = catcher.message();
-    ASSERT_TRUE(0);
-  }
-}
-
-// Tests that launch data is sent through if the file extension matches.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileExtension) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_by_extension"))
-      << message_;
-}
-
-// Tests that launch data is sent through if the file extension and MIME type
-// both match.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       LaunchWithFileExtensionAndMimeType) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/launch_file_by_extension_and_type")) << message_;
-}
-
-// Tests that launch data is sent through for a file with no extension if a
-// handler accepts "".
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileWithoutExtension) {
-  SetCommandLineArg("platform_apps/launch_files/test");
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
-      << message_;
-}
-
-#if !defined(OS_WIN)
-// Tests that launch data is sent through for a file with an empty extension if
-// a handler accepts "".
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileEmptyExtension) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  ClearCommandLineArgs();
-  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
-      test_data_dir_.AppendASCII(kTestFilePath),
-      temp_dir.path(),
-      "test."));
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
-      << message_;
-}
-
-// Tests that launch data is sent through for a file with an empty extension if
-// a handler accepts *.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       LaunchWithFileEmptyExtensionAcceptAny) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  ClearCommandLineArgs();
-  ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
-      test_data_dir_.AppendASCII(kTestFilePath),
-      temp_dir.path(),
-      "test."));
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/launch_file_with_any_extension")) << message_;
-}
-#endif
-
-// Tests that launch data is sent through for a file with no extension if a
-// handler accepts *.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       LaunchWithFileWithoutExtensionAcceptAny) {
-  SetCommandLineArg("platform_apps/launch_files/test");
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/launch_file_with_any_extension")) << message_;
-}
-
-// Tests that launch data is sent through for a file with an extension if a
-// handler accepts *.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       LaunchWithFileAcceptAnyExtension) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/launch_file_with_any_extension")) << message_;
-}
-
-// Tests that no launch data is sent through if the file has the wrong
-// extension.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongExtension) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
-      << message_;
-}
-
-// Tests that no launch data is sent through if the file has no extension but
-// the handler requires a specific extension.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongEmptyExtension) {
-  SetCommandLineArg("platform_apps/launch_files/test");
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
-      << message_;
-}
-
-// Tests that no launch data is sent through if the file is of the wrong MIME
-// type.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
-      << message_;
-}
-
-// Tests that no launch data is sent through if the platform app does not
-// provide an intent.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
-      << message_;
-}
-
-// Tests that launch data is sent through with the MIME type set to
-// application/octet-stream if the file MIME type cannot be read.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
-  SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
-  ASSERT_TRUE(RunPlatformAppTest(
-      "platform_apps/launch_application_octet_stream")) << message_;
-}
-
-// Tests that no launch data is sent through if the file does not exist.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
-  SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
-      << message_;
-}
-
-// Tests that no launch data is sent through if the argument is a directory.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
-  SetCommandLineArg("platform_apps/launch_files");
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
-      << message_;
-}
-
-// Tests that no launch data is sent through if there are no arguments passed
-// on the command line
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
-  ClearCommandLineArgs();
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
-      << message_;
-}
-
-// Test that platform apps can use the chrome.fileSystem.getDisplayPath
-// function to get the native file system path of a file they are launched with.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) {
-  SetCommandLineArg(kTestFilePath);
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path"))
-      << message_;
-}
-
-#endif  // defined(OS_CHROMEOS)
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_TAB_ADDED,
-      content::Source<content::WebContentsDelegate>(browser()));
-  LoadAndLaunchPlatformApp("open_link");
-  observer.Wait();
-  ASSERT_EQ(2, browser()->tab_strip_model()->count());
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MutationEventsDisabled) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/mutation_events")) << message_;
-}
-
-// Test that windows created with an id will remember and restore their
-// geometry when opening new windows.
-// Originally disabled due to flakiness (see http://crbug.com/155459)
-// but now because a regression breaks the test (http://crbug.com/160343).
-#if defined(TOOLKIT_GTK)
-#define MAYBE_ShellWindowRestorePosition DISABLED_ShellWindowRestorePosition
-#else
-#define MAYBE_ShellWindowRestorePosition ShellWindowRestorePosition
-#endif
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       MAYBE_ShellWindowRestorePosition) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/geometry"));
-}
-
-// This appears to be unreliable on linux.
-// TODO(stevenjb): Investigate and enable
-#if defined(OS_LINUX) && !defined(USE_ASH)
-#define MAYBE_ShellWindowRestoreState DISABLED_ShellWindowRestoreState
-#else
-#define MAYBE_ShellWindowRestoreState ShellWindowRestoreState
-#endif
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       MAYBE_ShellWindowRestoreState) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/restore_state"));
-}
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       ShellWindowAdjustBoundsToBeVisibleOnScreen) {
-  const Extension* extension = LoadAndLaunchPlatformApp("minimal");
-  ShellWindow* window = CreateShellWindow(extension);
-
-  // The screen bounds didn't change, the cached bounds didn't need to adjust.
-  gfx::Rect cached_bounds(80, 100, 400, 400);
-  gfx::Rect cached_screen_bounds(0, 0, 1600, 900);
-  gfx::Rect current_screen_bounds(0, 0, 1600, 900);
-  gfx::Size minimum_size(200, 200);
-  gfx::Rect bounds;
-  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
-                                                    cached_bounds,
-                                                    cached_screen_bounds,
-                                                    current_screen_bounds,
-                                                    minimum_size,
-                                                    &bounds);
-  EXPECT_EQ(bounds, cached_bounds);
-
-  // We have an empty screen bounds, the cached bounds didn't need to adjust.
-  gfx::Rect empty_screen_bounds;
-  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
-                                                    cached_bounds,
-                                                    empty_screen_bounds,
-                                                    current_screen_bounds,
-                                                    minimum_size,
-                                                    &bounds);
-  EXPECT_EQ(bounds, cached_bounds);
-
-  // Cached bounds is completely off the new screen bounds in horizontal
-  // locations. Expect to reposition the bounds.
-  gfx::Rect horizontal_out_of_screen_bounds(-800, 100, 400, 400);
-  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
-      window,
-      horizontal_out_of_screen_bounds,
-      gfx::Rect(-1366, 0, 1600, 900),
-      current_screen_bounds,
-      minimum_size,
-      &bounds);
-  EXPECT_EQ(bounds, gfx::Rect(0, 100, 400, 400));
-
-  // Cached bounds is completely off the new screen bounds in vertical
-  // locations. Expect to reposition the bounds.
-  gfx::Rect vertical_out_of_screen_bounds(10, 1000, 400, 400);
-  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
-      window,
-      vertical_out_of_screen_bounds,
-      gfx::Rect(-1366, 0, 1600, 900),
-      current_screen_bounds,
-      minimum_size,
-      &bounds);
-  EXPECT_EQ(bounds, gfx::Rect(10, 500, 400, 400));
-
-  // From a large screen resulotion to a small one. Expect it fit on screen.
-  gfx::Rect big_cache_bounds(10, 10, 1000, 1000);
-  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
-      window,
-      big_cache_bounds,
-      gfx::Rect(0, 0, 1600, 1000),
-      gfx::Rect(0, 0, 800, 600),
-      minimum_size,
-      &bounds);
-  EXPECT_EQ(bounds, gfx::Rect(0, 0, 800, 600));
-
-  // Don't resize the bounds smaller than minimum size, when the minimum size is
-  // larger than the screen.
-  CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
-      window,
-      big_cache_bounds,
-      gfx::Rect(0, 0, 1600, 1000),
-      gfx::Rect(0, 0, 800, 600),
-      gfx::Size(900, 900),
-      &bounds);
-  EXPECT_EQ(bounds, gfx::Rect(0, 0, 900, 900));
-}
-
-namespace {
-
-class PlatformAppDevToolsBrowserTest : public PlatformAppBrowserTest {
- protected:
-  enum TestFlags {
-    RELAUNCH = 0x1,
-    HAS_ID = 0x2,
-  };
-  // Runs a test inside a harness that opens DevTools on a shell window.
-  void RunTestWithDevTools(const char* name, int test_flags);
-};
-
-void PlatformAppDevToolsBrowserTest::RunTestWithDevTools(
-    const char* name, int test_flags) {
-  using content::DevToolsAgentHost;
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  const Extension* extension = LoadAndLaunchPlatformApp(name);
-  ASSERT_TRUE(extension);
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-  ShellWindow* window = GetFirstShellWindow();
-  ASSERT_TRUE(window);
-  ASSERT_EQ(window->window_key().empty(), (test_flags & HAS_ID) == 0);
-  content::RenderViewHost* rvh = window->web_contents()->GetRenderViewHost();
-  ASSERT_TRUE(rvh);
-
-  // Ensure no DevTools open for the ShellWindow, then open one.
-  ASSERT_FALSE(DevToolsAgentHost::HasFor(rvh));
-  DevToolsWindow* devtools_window = DevToolsWindow::OpenDevToolsWindow(rvh);
-  content::WindowedNotificationObserver loaded_observer(
-      content::NOTIFICATION_LOAD_STOP,
-      content::Source<content::NavigationController>(
-          &devtools_window->web_contents()->GetController()));
-  loaded_observer.Wait();
-  ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
-
-  if (test_flags & RELAUNCH) {
-    // Close the ShellWindow, and ensure it is gone.
-    CloseShellWindow(window);
-    ASSERT_FALSE(GetFirstShellWindow());
-
-    // Relaunch the app and get a new ShellWindow.
-    content::WindowedNotificationObserver app_loaded_observer(
-        content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-        content::NotificationService::AllSources());
-    chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
-                                                    extension,
-                                                    extension_misc::LAUNCH_NONE,
-                                                    NEW_WINDOW));
-    app_loaded_observer.Wait();
-    window = GetFirstShellWindow();
-    ASSERT_TRUE(window);
-
-    // DevTools should have reopened with the relaunch.
-    rvh = window->web_contents()->GetRenderViewHost();
-    ASSERT_TRUE(rvh);
-    ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
-  }
-}
-
-}  // namespace
-
-// http://crbug.com/246634
-#if defined(OS_CHROMEOS)
-#define MAYBE_ReOpenedWithID DISABLED_ReOpenedWithID
-#else
-#define MAYBE_ReOpenedWithID ReOpenedWithID
-#endif
-IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithID) {
-#if defined(OS_WIN) && defined(USE_ASH)
-  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
-    return;
-#endif
-  RunTestWithDevTools("minimal_id", RELAUNCH | HAS_ID);
-}
-
-// http://crbug.com/246999
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
-#define MAYBE_ReOpenedWithURL DISABLED_ReOpenedWithURL
-#else
-#define MAYBE_ReOpenedWithURL ReOpenedWithURL
-#endif
-IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithURL) {
-  RunTestWithDevTools("minimal", RELAUNCH);
-}
-
-// Test that showing a permission request as a constrained window works and is
-// correctly parented.
-#if defined(OS_MACOSX)
-#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
-#else
-// TODO(sail): Enable this on other platforms once http://crbug.com/95455 is
-// fixed.
-#define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
-#endif
-
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ConstrainedWindowRequest) {
-  PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
-  const Extension* extension =
-      LoadAndLaunchPlatformApp("optional_permission_request");
-  ASSERT_TRUE(extension) << "Failed to load extension.";
-
-  WebContents* web_contents = GetFirstShellWindowWebContents();
-  ASSERT_TRUE(web_contents);
-
-  // Verify that the shell window has a dialog attached.
-  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
-      WebContentsModalDialogManager::FromWebContents(web_contents);
-  EXPECT_TRUE(web_contents_modal_dialog_manager->IsShowingDialog());
-
-  // Close the constrained window and wait for the reply to the permission
-  // request.
-  ExtensionTestMessageListener listener("PermissionRequestDone", false);
-  WebContentsModalDialogManager::TestApi test_api(
-      web_contents_modal_dialog_manager);
-  test_api.CloseAllDialogs();
-  ASSERT_TRUE(listener.WaitUntilSatisfied());
-}
-
-// Tests that an app calling chrome.runtime.reload will reload the app and
-// relaunch it if it was running.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReloadRelaunches) {
-  ExtensionTestMessageListener launched_listener("Launched", true);
-  const Extension* extension = LoadAndLaunchPlatformApp("reload");
-  ASSERT_TRUE(extension);
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-  ASSERT_TRUE(GetFirstShellWindow());
-
-  // Now tell the app to reload itself
-  ExtensionTestMessageListener launched_listener2("Launched", false);
-  launched_listener.Reply("reload");
-  ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
-  ASSERT_TRUE(GetFirstShellWindow());
-}
-
-namespace {
-
-// Simple observer to check for NOTIFICATION_EXTENSION_INSTALLED events to
-// ensure installation does or does not occur in certain scenarios.
-class CheckExtensionInstalledObserver : public content::NotificationObserver {
- public:
-  CheckExtensionInstalledObserver() : seen_(false) {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_EXTENSION_INSTALLED,
-                   content::NotificationService::AllSources());
-  }
-
-  bool seen() const {
-    return seen_;
-  };
-
-  // NotificationObserver:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    EXPECT_FALSE(seen_);
-    seen_ = true;
-  }
-
- private:
-  bool seen_;
-  content::NotificationRegistrar registrar_;
-};
-
-}  // namespace
-
-// Component App Test 1 of 3: ensure that the initial load of a component
-// extension utilizing a background page (e.g. a v2 platform app) has its
-// background page run and is launchable. Waits for the Launched response from
-// the script resource in the opened shell window.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       PRE_PRE_ComponentAppBackgroundPage) {
-  CheckExtensionInstalledObserver should_install;
-
-  // Ensure that we wait until the background page is run (to register the
-  // OnLaunched listener) before trying to open the application. This is similar
-  // to LoadAndLaunchPlatformApp, but we want to load as a component extension.
-  content::WindowedNotificationObserver app_loaded_observer(
-      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-      content::NotificationService::AllSources());
-
-  const Extension* extension = LoadExtensionAsComponent(
-      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
-  ASSERT_TRUE(extension);
-
-  app_loaded_observer.Wait();
-  ASSERT_TRUE(should_install.seen());
-
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
-                                                  extension,
-                                                  extension_misc::LAUNCH_NONE,
-                                                  NEW_WINDOW));
-
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-}
-
-// Component App Test 2 of 3: ensure an installed component app can be launched
-// on a subsequent browser start, without requiring any install/upgrade logic
-// to be run, then perform setup for step 3.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
-                       PRE_ComponentAppBackgroundPage) {
-
-  // Since the component app is now installed, re-adding it in the same profile
-  // should not cause it to be re-installed. Instead, we wait for the OnLaunched
-  // in a different observer (which would timeout if not the app was not
-  // previously installed properly) and then check this observer to make sure it
-  // never saw the NOTIFICATION_EXTENSION_INSTALLED event.
-  CheckExtensionInstalledObserver should_not_install;
-  const Extension* extension = LoadExtensionAsComponent(
-      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
-  ASSERT_TRUE(extension);
-
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
-                                                  extension,
-                                                  extension_misc::LAUNCH_NONE,
-                                                  NEW_WINDOW));
-
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-  ASSERT_FALSE(should_not_install.seen());
-
-  // Simulate a "downgrade" from version 2 in the test manifest.json to 1.
-  ExtensionPrefs* extension_prefs =
-      extensions::ExtensionSystem::Get(browser()->profile())->
-      extension_service()->extension_prefs();
-
-  // Clear the registered events to ensure they are updated.
-  extensions::ExtensionSystem::Get(browser()->profile())->event_router()->
-      SetRegisteredEvents(extension->id(), std::set<std::string>());
-
-  DictionaryPrefUpdate update(extension_prefs->pref_service(),
-                              ExtensionPrefs::kExtensionsPref);
-  DictionaryValue* dict = update.Get();
-  std::string key(extension->id());
-  key += ".manifest.version";
-  dict->SetString(key, "1");
-}
-
-// Component App Test 3 of 3: simulate a component extension upgrade that
-// re-adds the OnLaunched event, and allows the app to be launched.
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ComponentAppBackgroundPage) {
-  CheckExtensionInstalledObserver should_install;
-  // Since we are forcing an upgrade, we need to wait for the load again.
-  content::WindowedNotificationObserver app_loaded_observer(
-      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-      content::NotificationService::AllSources());
-
-  const Extension* extension = LoadExtensionAsComponent(
-      test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
-  ASSERT_TRUE(extension);
-  app_loaded_observer.Wait();
-  ASSERT_TRUE(should_install.seen());
-
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
-                                                  extension,
-                                                  extension_misc::LAUNCH_NONE,
-                                                  NEW_WINDOW));
-
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-}
-
-// Flakes on Windows: http://crbug.com/171450
-#if defined(OS_WIN)
-#define MAYBE_Messaging DISABLED_Messaging
-#else
-#define MAYBE_Messaging Messaging
-#endif
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_Messaging) {
-  ExtensionApiTest::ResultCatcher result_catcher;
-  LoadAndLaunchPlatformApp("messaging/app2");
-  LoadAndLaunchPlatformApp("messaging/app1");
-  EXPECT_TRUE(result_catcher.GetNextResult());
-}
-
-// TODO(linux_aura) http://crbug.com/163931
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
-#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
-#else
-// This test depends on focus and so needs to be in interactive_ui_tests.
-// http://crbug.com/227041
-#define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
-#endif
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_WebContentsHasFocus) {
-  ExtensionTestMessageListener launched_listener("Launched", true);
-  LoadAndLaunchPlatformApp("minimal");
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  EXPECT_EQ(1LU, GetShellWindowCount());
-  ShellWindowRegistry::ShellWindowList shell_windows = ShellWindowRegistry::Get(
-      browser()->profile())->shell_windows();
-  EXPECT_TRUE((*shell_windows.begin())->web_contents()->
-      GetRenderWidgetHostView()->HasFocus());
-}
-
-
-#if defined(OS_CHROMEOS)
-
-class PlatformAppIncognitoBrowserTest : public PlatformAppBrowserTest,
-                                        public ShellWindowRegistry::Observer {
- public:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    // Tell chromeos to launch in Guest mode, aka incognito.
-    command_line->AppendSwitch(switches::kIncognito);
-    PlatformAppBrowserTest::SetUpCommandLine(command_line);
-  }
-  virtual void SetUp() OVERRIDE {
-    // Make sure the file manager actually gets loaded.
-    ComponentLoader::EnableBackgroundExtensionsForTesting();
-    PlatformAppBrowserTest::SetUp();
-  }
-
-  // ShellWindowRegistry::Observer implementation.
-  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE {
-    opener_app_ids_.insert(shell_window->extension()->id());
-  }
-  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {}
-  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE {}
-
- protected:
-  // A set of ids of apps we've seen open a shell window.
-  std::set<std::string> opener_app_ids_;
-};
-
-IN_PROC_BROWSER_TEST_F(PlatformAppIncognitoBrowserTest, IncognitoComponentApp) {
-  // Get the file manager app.
-  const Extension* file_manager = extension_service()->GetExtensionById(
-      "hhaomjibdihmijegdhdafkllkbggdgoj", false);
-  ASSERT_TRUE(file_manager != NULL);
-  Profile* incognito_profile = profile()->GetOffTheRecordProfile();
-  ASSERT_TRUE(incognito_profile != NULL);
-
-  // Wait until the file manager has had a chance to register its listener
-  // for the launch event.
-  EventRouter* router = ExtensionSystem::Get(incognito_profile)->event_router();
-  ASSERT_TRUE(router != NULL);
-  while (!router->ExtensionHasEventListener(file_manager->id(),
-                                            event_names::kOnLaunched)) {
-    content::RunAllPendingInMessageLoop();
-  }
-
-  // Listen for new shell windows so we see the file manager app launch itself.
-  ShellWindowRegistry* registry = ShellWindowRegistry::Get(incognito_profile);
-  ASSERT_TRUE(registry != NULL);
-  registry->AddObserver(this);
-
-  chrome::AppLaunchParams params(incognito_profile, file_manager, 0);
-  chrome::OpenApplication(params);
-
-  while (!ContainsKey(opener_app_ids_, file_manager->id())) {
-    content::RunAllPendingInMessageLoop();
-  }
-}
-
-#endif  // defined(OS_CHROMEOS)
-
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_browsertest_util.cc b/chrome/browser/extensions/platform_app_browsertest_util.cc
deleted file mode 100644
index 3348a00..0000000
--- a/chrome/browser/extensions/platform_app_browsertest_util.cc
+++ /dev/null
@@ -1,194 +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/platform_app_browsertest_util.h"
-
-#include "apps/app_window_contents.h"
-#include "apps/native_app_window.h"
-#include "apps/shell_window_registry.h"
-#include "base/command_line.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/extensions/api/tabs/tabs_api.h"
-#include "chrome/browser/extensions/extension_function_test_utils.h"
-#include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/common/chrome_switches.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/common/switches.h"
-
-using apps::ShellWindow;
-using apps::ShellWindowRegistry;
-using content::WebContents;
-
-namespace utils = extension_function_test_utils;
-
-namespace extensions {
-
-PlatformAppBrowserTest::PlatformAppBrowserTest() {
-  ChromeShellWindowDelegate::DisableExternalOpenForTesting();
-}
-
-void PlatformAppBrowserTest::SetUpCommandLine(CommandLine* command_line) {
-  // Skips ExtensionApiTest::SetUpCommandLine.
-  ExtensionBrowserTest::SetUpCommandLine(command_line);
-
-  // Make event pages get suspended quicker.
-  command_line->AppendSwitchASCII(::switches::kEventPageIdleTime, "1");
-  command_line->AppendSwitchASCII(::switches::kEventPageSuspendingTime, "1");
-}
-
-const Extension* PlatformAppBrowserTest::LoadAndLaunchPlatformApp(
-    const char* name) {
-  content::WindowedNotificationObserver app_loaded_observer(
-      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-      content::NotificationService::AllSources());
-
-  const Extension* extension = LoadExtension(
-      test_data_dir_.AppendASCII("platform_apps").AppendASCII(name));
-  EXPECT_TRUE(extension);
-
-  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
-                                                  extension,
-                                                  extension_misc::LAUNCH_NONE,
-                                                  NEW_WINDOW));
-
-  app_loaded_observer.Wait();
-
-  return extension;
-}
-
-const Extension* PlatformAppBrowserTest::InstallAndLaunchPlatformApp(
-    const char* name) {
-  content::WindowedNotificationObserver app_loaded_observer(
-      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
-      content::NotificationService::AllSources());
-
-  const Extension* extension = InstallExtension(
-      test_data_dir_.AppendASCII("platform_apps").AppendASCII(name), 1);
-  EXPECT_TRUE(extension);
-
-  chrome::OpenApplication(chrome::AppLaunchParams(browser()->profile(),
-                                                  extension,
-                                                  extension_misc::LAUNCH_NONE,
-                                                  NEW_WINDOW));
-
-  app_loaded_observer.Wait();
-
-  return extension;
-}
-
-WebContents* PlatformAppBrowserTest::GetFirstShellWindowWebContents() {
-  ShellWindow* window = GetFirstShellWindow();
-  if (window)
-    return window->web_contents();
-
-  return NULL;
-}
-
-ShellWindow* PlatformAppBrowserTest::GetFirstShellWindow() {
-  ShellWindowRegistry* app_registry =
-      ShellWindowRegistry::Get(browser()->profile());
-  const ShellWindowRegistry::ShellWindowList& shell_windows =
-      app_registry->shell_windows();
-
-  ShellWindowRegistry::const_iterator iter = shell_windows.begin();
-  if (iter != shell_windows.end())
-    return *iter;
-
-  return NULL;
-}
-
-size_t PlatformAppBrowserTest::RunGetWindowsFunctionForExtension(
-    const Extension* extension) {
-  scoped_refptr<WindowsGetAllFunction> function = new WindowsGetAllFunction();
-  function->set_extension(extension);
-  scoped_ptr<base::ListValue> result(utils::ToList(
-      utils::RunFunctionAndReturnSingleResult(function.get(),
-                                              "[]",
-                                              browser())));
-  return result->GetSize();
-}
-
-bool PlatformAppBrowserTest::RunGetWindowFunctionForExtension(
-    int window_id,
-    const Extension* extension) {
-  scoped_refptr<WindowsGetFunction> function = new WindowsGetFunction();
-  function->set_extension(extension);
-  utils::RunFunction(
-          function.get(),
-          base::StringPrintf("[%u]", window_id),
-          browser(),
-          utils::NONE);
-  return function->GetResultList() != NULL;
-}
-
-size_t PlatformAppBrowserTest::GetShellWindowCount() {
-  return ShellWindowRegistry::Get(browser()->profile())->
-      shell_windows().size();
-}
-
-void PlatformAppBrowserTest::ClearCommandLineArgs() {
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  CommandLine::StringVector args = command_line->GetArgs();
-  CommandLine::StringVector argv = command_line->argv();
-  for (size_t i = 0; i < args.size(); i++)
-    argv.pop_back();
-  command_line->InitFromArgv(argv);
-}
-
-void PlatformAppBrowserTest::SetCommandLineArg(const std::string& test_file) {
-  ClearCommandLineArgs();
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  base::FilePath test_doc(test_data_dir_.AppendASCII(test_file));
-  test_doc = test_doc.NormalizePathSeparators();
-  command_line->AppendArgPath(test_doc);
-}
-
-ShellWindow* PlatformAppBrowserTest::CreateShellWindow(
-    const Extension* extension) {
-  return CreateShellWindowFromParams(extension, ShellWindow::CreateParams());
-}
-
-ShellWindow* PlatformAppBrowserTest::CreateShellWindowFromParams(
-    const Extension* extension, const ShellWindow::CreateParams& params) {
-  ShellWindow* window = new ShellWindow(browser()->profile(),
-                                        new ChromeShellWindowDelegate(),
-                                        extension);
-  window->Init(GURL(std::string()),
-               new apps::AppWindowContents(window),
-               params);
-  return window;
-}
-
-void PlatformAppBrowserTest::CloseShellWindow(ShellWindow* window) {
-  content::WindowedNotificationObserver destroyed_observer(
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::NotificationService::AllSources());
-  window->GetBaseWindow()->Close();
-  destroyed_observer.Wait();
-}
-
-void PlatformAppBrowserTest::CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
-    ShellWindow* window,
-    const gfx::Rect& cached_bounds,
-    const gfx::Rect& cached_screen_bounds,
-    const gfx::Rect& current_screen_bounds,
-    const gfx::Size& minimum_size,
-    gfx::Rect* bounds) {
-  window->AdjustBoundsToBeVisibleOnScreen(cached_bounds,
-                                          cached_screen_bounds,
-                                          current_screen_bounds,
-                                          minimum_size,
-                                          bounds);
-}
-
-void ExperimentalPlatformAppBrowserTest::SetUpCommandLine(
-    CommandLine* command_line) {
-  PlatformAppBrowserTest::SetUpCommandLine(command_line);
-  command_line->AppendSwitch(switches::kEnableExperimentalExtensionApis);
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_browsertest_util.h b/chrome/browser/extensions/platform_app_browsertest_util.h
deleted file mode 100644
index 6cc179b..0000000
--- a/chrome/browser/extensions/platform_app_browsertest_util.h
+++ /dev/null
@@ -1,92 +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_PLATFORM_APP_BROWSERTEST_UTIL_H_
-#define CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_BROWSERTEST_UTIL_H_
-
-
-#include "apps/shell_window.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-
-namespace content {
-class WebContents;
-}
-
-class CommandLine;
-
-namespace extensions {
-class Extension;
-
-class PlatformAppBrowserTest : public ExtensionApiTest {
- public:
-  PlatformAppBrowserTest();
-
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
-
- protected:
-  // Runs the app named |name| out of the platform_apps subdirectory. Waits
-  // until it is launched.
-  const Extension* LoadAndLaunchPlatformApp(const char* name);
-
-  // Installs and runs the app named |name| out of the platform_apps
-  // subdirectory. Waits until it is launched.
-  const Extension* InstallAndLaunchPlatformApp(const char* name);
-
-  // Gets the WebContents associated with the first shell window that is found
-  // (most tests only deal with one platform app window, so this is good
-  // enough).
-  content::WebContents* GetFirstShellWindowWebContents();
-
-  // Gets the first shell window that is found (most tests only deal with one
-  // platform app window, so this is good enough).
-  apps::ShellWindow* GetFirstShellWindow();
-
-  // Runs chrome.windows.getAll for the given extension and returns the number
-  // of windows that the function returns.
-  size_t RunGetWindowsFunctionForExtension(const Extension* extension);
-
-  // Runs chrome.windows.get(|window_id|) for the the given extension and
-  // returns whether or not a window was found.
-  bool RunGetWindowFunctionForExtension(int window_id,
-                                        const Extension* extension);
-
-  // Returns the number of shell windows.
-  size_t GetShellWindowCount();
-
-  // The command line already has an argument on it - about:blank, which
-  // is set by InProcessBrowserTest::PrepareTestCommandLine. For platform app
-  // launch tests we need to clear this.
-  void ClearCommandLineArgs();
-
-  // Sets up the command line for running platform apps.
-  void SetCommandLineArg(const std::string& test_file);
-
-  // Creates an empty shell window for |extension|.
-  apps::ShellWindow* CreateShellWindow(const Extension* extension);
-
-  apps::ShellWindow* CreateShellWindowFromParams(
-      const Extension* extension,
-      const apps::ShellWindow::CreateParams& params);
-
-  // Closes |window| and waits until it's gone.
-  void CloseShellWindow(apps::ShellWindow* window);
-
-  // Call AdjustBoundsToBeVisibleOnScreen of |window|.
-  void CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
-      apps::ShellWindow* window,
-      const gfx::Rect& cached_bounds,
-      const gfx::Rect& cached_screen_bounds,
-      const gfx::Rect& current_screen_bounds,
-      const gfx::Size& minimum_size,
-      gfx::Rect* bounds);
-};
-
-class ExperimentalPlatformAppBrowserTest : public PlatformAppBrowserTest {
- public:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_BROWSERTEST_UTIL_H_
diff --git a/chrome/browser/extensions/requirements_checker.cc b/chrome/browser/extensions/requirements_checker.cc
index 1acc782..d2a3f82 100644
--- a/chrome/browser/extensions/requirements_checker.cc
+++ b/chrome/browser/extensions/requirements_checker.cc
@@ -7,11 +7,11 @@
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/gpu/gpu_feature_checker.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
+#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/manifest_handlers/requirements_handler.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/common/manifest.h"
 #include "gpu/config/gpu_feature_type.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/extensions/sandboxed_unpacker.cc b/chrome/browser/extensions/sandboxed_unpacker.cc
index 30d6c94..1a98850 100644
--- a/chrome/browser/extensions/sandboxed_unpacker.cc
+++ b/chrome/browser/extensions/sandboxed_unpacker.cc
@@ -26,8 +26,6 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/utility_process_host.h"
@@ -36,6 +34,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/crx_file.h"
 #include "extensions/common/id_util.h"
+#include "extensions/common/manifest_constants.h"
 #include "grit/generated_resources.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -607,7 +606,7 @@
   // the original manifest. We do this to ensure the manifest doesn't contain an
   // exploitable bug that could be used to compromise the browser.
   scoped_ptr<DictionaryValue> final_manifest(manifest.DeepCopy());
-  final_manifest->SetString(extension_manifest_keys::kPublicKey, public_key_);
+  final_manifest->SetString(manifest_keys::kPublicKey, public_key_);
 
   std::string manifest_json;
   JSONStringValueSerializer serializer(&manifest_json);
diff --git a/chrome/browser/extensions/sandboxed_unpacker.h b/chrome/browser/extensions/sandboxed_unpacker.h
index 07031da..6f4075f 100644
--- a/chrome/browser/extensions/sandboxed_unpacker.h
+++ b/chrome/browser/extensions/sandboxed_unpacker.h
@@ -11,8 +11,8 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/browser/utility_process_host_client.h"
+#include "extensions/common/manifest.h"
 
 class SkBitmap;
 
diff --git a/chrome/browser/extensions/script_badge_controller.cc b/chrome/browser/extensions/script_badge_controller.cc
index 43aebb1..a2f6e6b 100644
--- a/chrome/browser/extensions/script_badge_controller.cc
+++ b/chrome/browser/extensions/script_badge_controller.cc
@@ -8,7 +8,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/browser_event_router.h"
+#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
 #include "chrome/browser/extensions/extension_action.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -106,7 +106,7 @@
         NotifyChange();
 
       // Fire the scriptBadge.onClicked event.
-      GetExtensionService()->browser_event_router()->ScriptBadgeExecuted(
+      ExtensionActionAPI::ScriptBadgeExecuted(
           profile(), *script_badge, SessionID::IdForTab(web_contents()));
 
       // TODO(jyasskin): The fallback order should be user-defined popup ->
@@ -176,7 +176,7 @@
 
 int32 ScriptBadgeController::GetPageID() {
   content::NavigationEntry* nav_entry =
-      web_contents()->GetController().GetActiveEntry();
+      web_contents()->GetController().GetVisibleEntry();
   return nav_entry ? nav_entry->GetPageID() : -1;
 }
 
diff --git a/chrome/browser/extensions/script_badge_controller_unittest.cc b/chrome/browser/extensions/script_badge_controller_unittest.cc
index 01bfd60..585fe2a 100644
--- a/chrome/browser/extensions/script_badge_controller_unittest.cc
+++ b/chrome/browser/extensions/script_badge_controller_unittest.cc
@@ -154,7 +154,7 @@
   script_badge_controller_->OnScriptsExecuted(
       web_contents(),
       id_map,
-      web_contents()->GetController().GetActiveEntry()->GetPageID(),
+      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
       GURL(std::string()));
   EXPECT_THAT(script_badge_controller_->GetCurrentActions(),
               testing::ElementsAre(GetScriptBadge(*extension.get())));
@@ -183,7 +183,7 @@
     script_badge_controller_->OnScriptsExecuted(
         web_contents(),
         id_map,
-        web_contents()->GetController().GetActiveEntry()->GetPageID(),
+        web_contents()->GetController().GetVisibleEntry()->GetPageID(),
         GURL(std::string()));
 
     EXPECT_THAT(script_badge_controller_->GetCurrentActions(),
diff --git a/chrome/browser/extensions/script_bubble_controller_unittest.cc b/chrome/browser/extensions/script_bubble_controller_unittest.cc
index cce310c..c53dac5 100644
--- a/chrome/browser/extensions/script_bubble_controller_unittest.cc
+++ b/chrome/browser/extensions/script_bubble_controller_unittest.cc
@@ -136,8 +136,8 @@
   script_bubble_controller_->OnScriptsExecuted(
       web_contents(),
       executing_scripts,
-      web_contents()->GetController().GetActiveEntry()->GetPageID(),
-      web_contents()->GetController().GetActiveEntry()->GetURL());
+      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+      web_contents()->GetController().GetVisibleEntry()->GetURL());
   EXPECT_EQ(1u, script_bubble_controller_->extensions_running_scripts().size());
   std::set<std::string> extension_ids;
   extension_ids.insert(extension1->id());
@@ -151,8 +151,8 @@
   script_bubble_controller_->OnScriptsExecuted(
       web_contents(),
       executing_scripts,
-      web_contents()->GetController().GetActiveEntry()->GetPageID(),
-      web_contents()->GetController().GetActiveEntry()->GetURL());
+      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+      web_contents()->GetController().GetVisibleEntry()->GetURL());
   EXPECT_EQ(2u, script_bubble_controller_->extensions_running_scripts().size());
   extension_ids.insert(extension2->id());
   EXPECT_TRUE(extension_ids ==
@@ -165,8 +165,8 @@
   script_bubble_controller_->OnScriptsExecuted(
       web_contents(),
       executing_scripts,
-      web_contents()->GetController().GetActiveEntry()->GetPageID(),
-      web_contents()->GetController().GetActiveEntry()->GetURL());
+      web_contents()->GetController().GetVisibleEntry()->GetPageID(),
+      web_contents()->GetController().GetVisibleEntry()->GetURL());
   EXPECT_EQ(2u, script_bubble_controller_->extensions_running_scripts().size());
 
   // Running tabs.executeScript from an already-seen extension does not affect
diff --git a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
index ae6f6e5..862f95a 100644
--- a/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
+++ b/chrome/browser/extensions/standard_management_policy_provider_unittest.cc
@@ -9,8 +9,8 @@
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/standard_management_policy_provider.h"
 #include "chrome/browser/extensions/test_extension_prefs.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -31,8 +31,8 @@
   scoped_refptr<const Extension> CreateExtension(Manifest::Location location,
                                                  bool required) {
     base::DictionaryValue values;
-    values.SetString(extension_manifest_keys::kName, "test");
-    values.SetString(extension_manifest_keys::kVersion, "0.1");
+    values.SetString(manifest_keys::kName, "test");
+    values.SetString(manifest_keys::kVersion, "0.1");
     std::string error;
     scoped_refptr<const Extension> extension = Extension::Create(
         base::FilePath(), location, values, Extension::NO_FLAGS, &error);
diff --git a/chrome/browser/extensions/startup_helper_browsertest.cc b/chrome/browser/extensions/startup_helper_browsertest.cc
index fef25ee..49a3db5 100644
--- a/chrome/browser/extensions/startup_helper_browsertest.cc
+++ b/chrome/browser/extensions/startup_helper_browsertest.cc
@@ -36,9 +36,9 @@
   expectations.push_back(
       std::make_pair(test_data_dir_.AppendASCII("good2.crx"), true));
   expectations.push_back(
-      std::make_pair(test_data_dir_.AppendASCII("bad_magic.crx"), false));
+      std::make_pair(test_data_dir_.AppendASCII("bad_underscore.crx"), true));
   expectations.push_back(
-      std::make_pair(test_data_dir_.AppendASCII("bad_underscore.crx"), false));
+      std::make_pair(test_data_dir_.AppendASCII("bad_magic.crx"), false));
 
   for (std::vector<std::pair<base::FilePath, bool> >::iterator i =
            expectations.begin();
diff --git a/chrome/browser/extensions/subscribe_page_action_browsertest.cc b/chrome/browser/extensions/subscribe_page_action_browsertest.cc
index d1f5afa..3b077f8 100644
--- a/chrome/browser/extensions/subscribe_page_action_browsertest.cc
+++ b/chrome/browser/extensions/subscribe_page_action_browsertest.cc
@@ -81,7 +81,6 @@
                          const std::string& javascript,
                          const std::string& expected_value) {
   std::string returned_value;
-  std::string error;
 
   if (!content::ExecuteScriptInFrameAndExtractString(tab, frame_xpath,
                                                      javascript,
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 018ff42..c53f136 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -22,9 +22,9 @@
 #include "chrome/browser/prefs/pref_service_mock_builder.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/common/manifest_constants.h"
 #include "sync/api/string_ordinal.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -122,18 +122,17 @@
 
 scoped_refptr<Extension> TestExtensionPrefs::AddExtension(std::string name) {
   DictionaryValue dictionary;
-  dictionary.SetString(extension_manifest_keys::kName, name);
-  dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
+  dictionary.SetString(manifest_keys::kName, name);
+  dictionary.SetString(manifest_keys::kVersion, "0.1");
   return AddExtensionWithManifest(dictionary, Manifest::INTERNAL);
 }
 
 scoped_refptr<Extension> TestExtensionPrefs::AddApp(std::string name) {
   DictionaryValue dictionary;
-  dictionary.SetString(extension_manifest_keys::kName, name);
-  dictionary.SetString(extension_manifest_keys::kVersion, "0.1");
-  dictionary.SetString(extension_manifest_keys::kApp, "true");
-  dictionary.SetString(extension_manifest_keys::kLaunchWebURL,
-                       "http://example.com");
+  dictionary.SetString(manifest_keys::kName, name);
+  dictionary.SetString(manifest_keys::kVersion, "0.1");
+  dictionary.SetString(manifest_keys::kApp, "true");
+  dictionary.SetString(manifest_keys::kLaunchWebURL, "http://example.com");
   return AddExtensionWithManifest(dictionary, Manifest::INTERNAL);
 
 }
@@ -149,7 +148,7 @@
     Manifest::Location location,
     int extra_flags) {
   std::string name;
-  EXPECT_TRUE(manifest.GetString(extension_manifest_keys::kName, &name));
+  EXPECT_TRUE(manifest.GetString(manifest_keys::kName, &name));
   base::FilePath path =  extensions_dir_.AppendASCII(name);
   std::string errors;
   scoped_refptr<Extension> extension = Extension::Create(
diff --git a/chrome/browser/extensions/test_extension_prefs.h b/chrome/browser/extensions/test_extension_prefs.h
index 356bc03..6232089 100644
--- a/chrome/browser/extensions/test_extension_prefs.h
+++ b/chrome/browser/extensions/test_extension_prefs.h
@@ -10,7 +10,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class ExtensionPrefValueMap;
 class PrefService;
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
index adfd3e5..b36afaa 100644
--- a/chrome/browser/extensions/unpacked_installer.cc
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -18,9 +18,9 @@
 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/id_util.h"
+#include "extensions/common/manifest.h"
 #include "sync/api/string_ordinal.h"
 
 using content::BrowserThread;
@@ -214,6 +214,15 @@
 
   extension_path_ = base::MakeAbsoluteFilePath(extension_path_);
 
+  std::string error;
+  if (!extension_file_util::CheckForIllegalFilenames(extension_path_,
+                                                     &error)) {
+    BrowserThread::PostTask(
+        BrowserThread::UI,
+        FROM_HERE,
+        base::Bind(&UnpackedInstaller::ReportExtensionLoadError, this, error));
+    return;
+  }
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index b66f548..6b9cece 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -26,13 +26,13 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_set.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/pref_names.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"
 #include "crypto/sha2.h"
+#include "extensions/common/manifest.h"
 
 using base::RandDouble;
 using base::RandInt;
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 8b8cb2d..7fc96f4 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/google/google_util.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/omaha_query_params/omaha_query_params.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
@@ -54,6 +53,7 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/common/id_util.h"
+#include "extensions/common/manifest_constants.h"
 #include "libxml/globals.h"
 #include "net/base/backoff_entry.h"
 #include "net/base/escape.h"
@@ -271,12 +271,12 @@
                             Manifest::Location location) {
     for (int i = 1; i <= count; i++) {
       DictionaryValue manifest;
-      manifest.SetString(extension_manifest_keys::kVersion,
+      manifest.SetString(manifest_keys::kVersion,
                          base::StringPrintf("%d.0.0.0", i));
-      manifest.SetString(extension_manifest_keys::kName,
+      manifest.SetString(manifest_keys::kName,
                          base::StringPrintf("Extension %d.%d", id, i));
       if (update_url)
-        manifest.SetString(extension_manifest_keys::kUpdateURL, *update_url);
+        manifest.SetString(manifest_keys::kUpdateURL, *update_url);
       scoped_refptr<Extension> e =
           prefs_->AddExtensionWithManifest(manifest, location);
       ASSERT_TRUE(e.get() != NULL);
diff --git a/chrome/browser/extensions/web_view_browsertest.cc b/chrome/browser/extensions/web_view_browsertest.cc
deleted file mode 100644
index 13fe584..0000000
--- a/chrome/browser/extensions/web_view_browsertest.cc
+++ /dev/null
@@ -1,1447 +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/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/automation/automation_util.h"
-#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
-#include "chrome/browser/prerender/prerender_link_manager.h"
-#include "chrome/browser/prerender/prerender_link_manager_factory.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/fake_speech_recognition_manager.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"
-#include "ui/gl/gl_switches.h"
-
-// For fine-grained suppression on flaky tests.
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
-using prerender::PrerenderLinkManager;
-using prerender::PrerenderLinkManagerFactory;
-
-namespace {
-  const char kEmptyResponsePath[] = "/close-socket";
-  const char kRedirectResponsePath[] = "/server-redirect";
-  const char kRedirectResponseFullPath[] =
-      "/extensions/platform_apps/web_view/shim/guest_redirect.html";
-
-  class EmptyHttpResponse : public net::test_server::HttpResponse {
-  public:
-    virtual std::string ToResponseString() const OVERRIDE {
-      return std::string();
-    }
-  };
-}  // namespace
-
-// This class intercepts media access request from the embedder. The request
-// should be triggered only if the embedder API (from tests) allows the request
-// in Javascript.
-// We do not issue the actual media request; the fact that the request reached
-// embedder's WebContents is good enough for our tests. This is also to make
-// the test run successfully on trybots.
-class MockWebContentsDelegate : public content::WebContentsDelegate {
- public:
-  MockWebContentsDelegate() : requested_(false) {}
-  virtual ~MockWebContentsDelegate() {}
-
-  virtual void RequestMediaAccessPermission(
-      content::WebContents* web_contents,
-      const content::MediaStreamRequest& request,
-      const content::MediaResponseCallback& callback) OVERRIDE {
-    requested_ = true;
-    if (message_loop_runner_.get())
-      message_loop_runner_->Quit();
-  }
-
-  void WaitForSetMediaPermission() {
-    if (requested_)
-      return;
-    message_loop_runner_ = new content::MessageLoopRunner;
-    message_loop_runner_->Run();
-  }
-
- private:
-  bool requested_;
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockWebContentsDelegate);
-};
-
-// This class intercepts download request from the guest.
-class MockDownloadWebContentsDelegate : public content::WebContentsDelegate {
- public:
-  explicit MockDownloadWebContentsDelegate(
-      content::WebContentsDelegate* orig_delegate)
-      : orig_delegate_(orig_delegate),
-        waiting_for_decision_(false),
-        expect_allow_(false),
-        decision_made_(false),
-        last_download_allowed_(false) {}
-  virtual ~MockDownloadWebContentsDelegate() {}
-
-  virtual void CanDownload(
-      content::RenderViewHost* render_view_host,
-      int request_id,
-      const std::string& request_method,
-      const base::Callback<void(bool)>& callback) OVERRIDE {
-    orig_delegate_->CanDownload(
-        render_view_host, request_id, request_method,
-        base::Bind(&MockDownloadWebContentsDelegate::DownloadDecided,
-                   base::Unretained(this)));
-  }
-
-  void WaitForCanDownload(bool expect_allow) {
-    EXPECT_FALSE(waiting_for_decision_);
-    waiting_for_decision_ = true;
-
-    if (decision_made_) {
-      EXPECT_EQ(expect_allow, last_download_allowed_);
-      return;
-    }
-
-    expect_allow_ = expect_allow;
-    message_loop_runner_ = new content::MessageLoopRunner;
-    message_loop_runner_->Run();
-  }
-
-  void DownloadDecided(bool allow) {
-    EXPECT_FALSE(decision_made_);
-    decision_made_ = true;
-
-    if (waiting_for_decision_) {
-      EXPECT_EQ(expect_allow_, allow);
-      if (message_loop_runner_.get())
-        message_loop_runner_->Quit();
-      return;
-    }
-    last_download_allowed_ = allow;
-  }
-
-  void Reset() {
-    waiting_for_decision_ = false;
-    decision_made_ = false;
-  }
-
- private:
-  content::WebContentsDelegate* orig_delegate_;
-  bool waiting_for_decision_;
-  bool expect_allow_;
-  bool decision_made_;
-  bool last_download_allowed_;
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockDownloadWebContentsDelegate);
-};
-
-class WebViewTest : public extensions::PlatformAppBrowserTest {
- protected:
-  virtual void SetUp() OVERRIDE {
-    const testing::TestInfo* const test_info =
-        testing::UnitTest::GetInstance()->current_test_info();
-
-    // SpeechRecognition test specific SetUp.
-    if (!strcmp(test_info->name(), "SpeechRecognition")) {
-      fake_speech_recognition_manager_.reset(
-          new content::FakeSpeechRecognitionManager());
-      fake_speech_recognition_manager_->set_should_send_fake_response(true);
-      // Inject the fake manager factory so that the test result is returned to
-      // the web page.
-      content::SpeechRecognitionManager::SetManagerForTests(
-          fake_speech_recognition_manager_.get());
-    }
-
-    extensions::PlatformAppBrowserTest::SetUp();
-  }
-
-  virtual void TearDown() OVERRIDE {
-    // SpeechRecognition test specific TearDown.
-    const testing::TestInfo* const test_info =
-        testing::UnitTest::GetInstance()->current_test_info();
-    if (!strcmp(test_info->name(), "SpeechRecognition"))
-      content::SpeechRecognitionManager::SetManagerForTests(NULL);
-
-    extensions::PlatformAppBrowserTest::TearDown();
-  }
-
-  virtual void SetUpOnMainThread() OVERRIDE {
-    const testing::TestInfo* const test_info =
-        testing::UnitTest::GetInstance()->current_test_info();
-    // Mock out geolocation for geolocation specific tests.
-    if (!strncmp(test_info->name(), "GeolocationAPI",
-            strlen("GeolocationAPI"))) {
-      ui_test_utils::OverrideGeolocation(10, 20);
-    }
-  }
-
-  // This method is responsible for initializing a packaged app, which contains
-  // multiple webview tags. The tags have different partition identifiers and
-  // their WebContent objects are returned as output. The method also verifies
-  // the expected process allocation and storage partition assignment.
-  // The |navigate_to_url| parameter is used to navigate the main browser
-  // window.
-  //
-  // TODO(ajwong): This function is getting to be too large. Either refactor it
-  // so the test can specify a configuration of WebView tags that we will
-  // dynamically inject JS to generate, or move this test wholesale into
-  // something that RunPlatformAppTest() can execute purely in Javascript. This
-  // won't let us do a white-box examination of the StoragePartition equivalence
-  // directly, but we will be able to view the black box effects which is good
-  // enough.  http://crbug.com/160361
-  void NavigateAndOpenAppForIsolation(
-      GURL navigate_to_url,
-      content::WebContents** default_tag_contents1,
-      content::WebContents** default_tag_contents2,
-      content::WebContents** named_partition_contents1,
-      content::WebContents** named_partition_contents2,
-      content::WebContents** persistent_partition_contents1,
-      content::WebContents** persistent_partition_contents2,
-      content::WebContents** persistent_partition_contents3) {
-    GURL::Replacements replace_host;
-    std::string host_str("localhost");  // Must stay in scope with replace_host.
-    replace_host.SetHostStr(host_str);
-
-    navigate_to_url = navigate_to_url.ReplaceComponents(replace_host);
-
-    GURL tag_url1 = embedded_test_server()->GetURL(
-        "/extensions/platform_apps/web_view/isolation/cookie.html");
-    tag_url1 = tag_url1.ReplaceComponents(replace_host);
-    GURL tag_url2 = embedded_test_server()->GetURL(
-        "/extensions/platform_apps/web_view/isolation/cookie2.html");
-    tag_url2 = tag_url2.ReplaceComponents(replace_host);
-    GURL tag_url3 = embedded_test_server()->GetURL(
-        "/extensions/platform_apps/web_view/isolation/storage1.html");
-    tag_url3 = tag_url3.ReplaceComponents(replace_host);
-    GURL tag_url4 = embedded_test_server()->GetURL(
-        "/extensions/platform_apps/web_view/isolation/storage2.html");
-    tag_url4 = tag_url4.ReplaceComponents(replace_host);
-    GURL tag_url5 = embedded_test_server()->GetURL(
-        "/extensions/platform_apps/web_view/isolation/storage1.html#p1");
-    tag_url5 = tag_url5.ReplaceComponents(replace_host);
-    GURL tag_url6 = embedded_test_server()->GetURL(
-        "/extensions/platform_apps/web_view/isolation/storage1.html#p2");
-    tag_url6 = tag_url6.ReplaceComponents(replace_host);
-    GURL tag_url7 = embedded_test_server()->GetURL(
-        "/extensions/platform_apps/web_view/isolation/storage1.html#p3");
-    tag_url7 = tag_url7.ReplaceComponents(replace_host);
-
-    ui_test_utils::NavigateToURLWithDisposition(
-        browser(), navigate_to_url, CURRENT_TAB,
-        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
-    ui_test_utils::UrlLoadObserver observer1(
-        tag_url1, content::NotificationService::AllSources());
-    ui_test_utils::UrlLoadObserver observer2(
-        tag_url2, content::NotificationService::AllSources());
-    ui_test_utils::UrlLoadObserver observer3(
-        tag_url3, content::NotificationService::AllSources());
-    ui_test_utils::UrlLoadObserver observer4(
-        tag_url4, content::NotificationService::AllSources());
-    ui_test_utils::UrlLoadObserver observer5(
-        tag_url5, content::NotificationService::AllSources());
-    ui_test_utils::UrlLoadObserver observer6(
-        tag_url6, content::NotificationService::AllSources());
-    ui_test_utils::UrlLoadObserver observer7(
-        tag_url7, content::NotificationService::AllSources());
-    LoadAndLaunchPlatformApp("web_view/isolation");
-    observer1.Wait();
-    observer2.Wait();
-    observer3.Wait();
-    observer4.Wait();
-    observer5.Wait();
-    observer6.Wait();
-    observer7.Wait();
-
-    content::Source<content::NavigationController> source1 = observer1.source();
-    EXPECT_TRUE(source1->GetWebContents()->GetRenderProcessHost()->IsGuest());
-    content::Source<content::NavigationController> source2 = observer2.source();
-    EXPECT_TRUE(source2->GetWebContents()->GetRenderProcessHost()->IsGuest());
-    content::Source<content::NavigationController> source3 = observer3.source();
-    EXPECT_TRUE(source3->GetWebContents()->GetRenderProcessHost()->IsGuest());
-    content::Source<content::NavigationController> source4 = observer4.source();
-    EXPECT_TRUE(source4->GetWebContents()->GetRenderProcessHost()->IsGuest());
-    content::Source<content::NavigationController> source5 = observer5.source();
-    EXPECT_TRUE(source5->GetWebContents()->GetRenderProcessHost()->IsGuest());
-    content::Source<content::NavigationController> source6 = observer6.source();
-    EXPECT_TRUE(source6->GetWebContents()->GetRenderProcessHost()->IsGuest());
-    content::Source<content::NavigationController> source7 = observer7.source();
-    EXPECT_TRUE(source7->GetWebContents()->GetRenderProcessHost()->IsGuest());
-
-    // Check that the first two tags use the same process and it is different
-    // than the process used by the other two.
-    EXPECT_EQ(source1->GetWebContents()->GetRenderProcessHost()->GetID(),
-              source2->GetWebContents()->GetRenderProcessHost()->GetID());
-    EXPECT_EQ(source3->GetWebContents()->GetRenderProcessHost()->GetID(),
-              source4->GetWebContents()->GetRenderProcessHost()->GetID());
-    EXPECT_NE(source1->GetWebContents()->GetRenderProcessHost()->GetID(),
-              source3->GetWebContents()->GetRenderProcessHost()->GetID());
-
-    // The two sets of tags should also be isolated from the main browser.
-    EXPECT_NE(source1->GetWebContents()->GetRenderProcessHost()->GetID(),
-              browser()->tab_strip_model()->GetWebContentsAt(0)->
-                  GetRenderProcessHost()->GetID());
-    EXPECT_NE(source3->GetWebContents()->GetRenderProcessHost()->GetID(),
-              browser()->tab_strip_model()->GetWebContentsAt(0)->
-                  GetRenderProcessHost()->GetID());
-
-    // Check that the storage partitions of the first two tags match and are
-    // different than the other two.
-    EXPECT_EQ(
-        source1->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition(),
-        source2->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition());
-    EXPECT_EQ(
-        source3->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition(),
-        source4->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition());
-    EXPECT_NE(
-        source1->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition(),
-        source3->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition());
-
-    // Ensure the persistent storage partitions are different.
-    EXPECT_EQ(
-        source5->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition(),
-        source6->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition());
-    EXPECT_NE(
-        source5->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition(),
-        source7->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition());
-    EXPECT_NE(
-        source1->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition(),
-        source5->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition());
-    EXPECT_NE(
-        source1->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition(),
-        source7->GetWebContents()->GetRenderProcessHost()->
-            GetStoragePartition());
-
-    *default_tag_contents1 = source1->GetWebContents();
-    *default_tag_contents2 = source2->GetWebContents();
-    *named_partition_contents1 = source3->GetWebContents();
-    *named_partition_contents2 = source4->GetWebContents();
-    if (persistent_partition_contents1) {
-      *persistent_partition_contents1 = source5->GetWebContents();
-    }
-    if (persistent_partition_contents2) {
-      *persistent_partition_contents2 = source6->GetWebContents();
-    }
-    if (persistent_partition_contents3) {
-      *persistent_partition_contents3 = source7->GetWebContents();
-    }
-  }
-
-  void ExecuteScriptWaitForTitle(content::WebContents* web_contents,
-                                 const char* script,
-                                 const char* title) {
-    string16 expected_title(ASCIIToUTF16(title));
-    string16 error_title(ASCIIToUTF16("error"));
-
-    content::TitleWatcher title_watcher(web_contents, expected_title);
-    title_watcher.AlsoWaitForTitle(error_title);
-    EXPECT_TRUE(content::ExecuteScript(web_contents, script));
-    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
-  }
-
-  // Handles |request| by serving a redirect response.
-  static scoped_ptr<net::test_server::HttpResponse> RedirectResponseHandler(
-      const std::string& path,
-      const GURL& redirect_target,
-      const net::test_server::HttpRequest& request) {
-    if (!StartsWithASCII(path, request.relative_url, true))
-      return scoped_ptr<net::test_server::HttpResponse>();
-
-    scoped_ptr<net::test_server::BasicHttpResponse> http_response(
-        new net::test_server::BasicHttpResponse);
-    http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
-    http_response->AddCustomHeader("Location", redirect_target.spec());
-    return http_response.PassAs<net::test_server::HttpResponse>();
-  }
-
-  // Handles |request| by serving an empty response.
-  static scoped_ptr<net::test_server::HttpResponse> EmptyResponseHandler(
-      const std::string& path,
-      const net::test_server::HttpRequest& request) {
-    if (StartsWithASCII(path, request.relative_url, true)) {
-      return scoped_ptr<net::test_server::HttpResponse>(
-          new EmptyHttpResponse);
-    }
-
-    return scoped_ptr<net::test_server::HttpResponse>();
-  }
-
-  void TestHelper(const std::string& test_name,
-                  const std::string& test_passed_msg,
-                  const std::string& test_failed_msg,
-                  const std::string& app_location) {
-    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-    ExtensionTestMessageListener launched_listener("Launched", false);
-    LoadAndLaunchPlatformApp(app_location.c_str());
-    ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-    embedded_test_server()->RegisterRequestHandler(
-        base::Bind(&WebViewTest::RedirectResponseHandler,
-                   kRedirectResponsePath,
-                   embedded_test_server()->GetURL(kRedirectResponseFullPath)));
-
-    embedded_test_server()->RegisterRequestHandler(
-        base::Bind(&WebViewTest::EmptyResponseHandler, kEmptyResponsePath));
-
-    content::WebContents* embedder_web_contents =
-        GetFirstShellWindowWebContents();
-    ASSERT_TRUE(embedder_web_contents);
-
-    ExtensionTestMessageListener done_listener(test_passed_msg, false);
-    done_listener.AlsoListenForFailureMessage(test_failed_msg);
-    EXPECT_TRUE(content::ExecuteScript(
-                    embedder_web_contents,
-                    base::StringPrintf("runTest('%s')", test_name.c_str())));
-    ASSERT_TRUE(done_listener.WaitUntilSatisfied());
-  }
-
-  content::WebContents* LoadGuest(const std::string& guest_path,
-                                  const std::string& app_path) {
-    GURL::Replacements replace_host;
-    std::string host_str("localhost");  // Must stay in scope with replace_host.
-    replace_host.SetHostStr(host_str);
-
-    GURL guest_url = embedded_test_server()->GetURL(guest_path);
-    guest_url = guest_url.ReplaceComponents(replace_host);
-
-    ui_test_utils::UrlLoadObserver guest_observer(
-        guest_url, content::NotificationService::AllSources());
-
-    ExtensionTestMessageListener guest_loaded_listener("guest-loaded", false);
-    LoadAndLaunchPlatformApp(app_path.c_str());
-    guest_observer.Wait();
-
-    content::Source<content::NavigationController> source =
-        guest_observer.source();
-    EXPECT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());
-
-    bool satisfied = guest_loaded_listener.WaitUntilSatisfied();
-    if (!satisfied)
-      return NULL;
-
-    content::WebContents* guest_web_contents = source->GetWebContents();
-    return guest_web_contents;
-  }
-
-  // Runs media_access/allow tests.
-  void MediaAccessAPIAllowTestHelper(const std::string& test_name);
-
-  // Runs media_access/deny tests, each of them are run separately otherwise
-  // they timeout (mostly on Windows).
-  void MediaAccessAPIDenyTestHelper(const std::string& test_name) {
-    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-    ExtensionTestMessageListener loaded_listener("loaded", false);
-    LoadAndLaunchPlatformApp("web_view/media_access/deny");
-    ASSERT_TRUE(loaded_listener.WaitUntilSatisfied());
-
-    content::WebContents* embedder_web_contents =
-        GetFirstShellWindowWebContents();
-    ASSERT_TRUE(embedder_web_contents);
-
-    ExtensionTestMessageListener test_run_listener("PASSED", false);
-    test_run_listener.AlsoListenForFailureMessage("FAILED");
-    EXPECT_TRUE(
-        content::ExecuteScript(
-            embedder_web_contents,
-            base::StringPrintf("startDenyTest('%s')", test_name.c_str())));
-    ASSERT_TRUE(test_run_listener.WaitUntilSatisfied());
-  }
-
- private:
-  scoped_ptr<content::FakeSpeechRecognitionManager>
-      fake_speech_recognition_manager_;
-};
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestSize) {
-  TestHelper("testSize",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAPIMethodExistence) {
-  TestHelper("testAPIMethodExistence",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-// Tests the existence of WebRequest API event objects on the request
-// object, on the webview element, and hanging directly off webview.
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestWebRequestAPIExistence) {
-  TestHelper("testWebRequestAPIExistence",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestEventName) {
-  TestHelper("testEventName",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-// WebViewTest.Shim_TestDestroyOnEventListener is flaky, so disable it.
-// http://crbug.com/255106
-IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_Shim_TestDestroyOnEventListener) {
-  TestHelper("testDestroyOnEventListener",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestCannotMutateEventName) {
-  TestHelper("testCannotMutateEventName",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestPartitionRaisesException) {
-#if defined(OS_WIN)
-  // Flaky on XP bot http://crbug.com/267304
-  if (base::win::GetVersion() <= base::win::VERSION_XP)
-    return;
-#endif
-
-  TestHelper("testPartitionRaisesException",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestExecuteScriptFail) {
-#if defined(OS_WIN)
-  // Flaky on XP bot http://crbug.com/266185
-  if (base::win::GetVersion() <= base::win::VERSION_XP)
-    return;
-#endif
-
-  TestHelper("testExecuteScriptFail",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestExecuteScript) {
-  TestHelper("testExecuteScript",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestTerminateAfterExit) {
-  TestHelper("testTerminateAfterExit",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestAssignSrcAfterCrash) {
-  TestHelper("testAssignSrcAfterCrash",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveSrcAttribute) {
-  TestHelper("testRemoveSrcAttribute",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestBrowserPluginNotAllowed) {
-#if defined(OS_WIN)
-  // Flaky on XP bots. http://crbug.com/267300
-  if (base::win::GetVersion() <= base::win::VERSION_XP)
-    return;
-#endif
-
-  TestHelper("testBrowserPluginNotAllowed",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindow) {
-  TestHelper("testNewWindow",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowTwoListeners) {
-  TestHelper("testNewWindowTwoListeners",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowNoPreventDefault) {
-  TestHelper("testNewWindowNoPreventDefault",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestNewWindowNoReferrerLink) {
-  TestHelper("testNewWindowNoReferrerLink",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestContentLoadEvent) {
-  TestHelper("testContentLoadEvent",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestWebRequestAPI) {
-  TestHelper("testWebRequestAPI",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadStartLoadRedirect) {
-  TestHelper("testLoadStartLoadRedirect",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadAbortEmptyResponse) {
-  TestHelper("testLoadAbortEmptyResponse",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadAbortIllegalChromeURL) {
-  TestHelper("testLoadAbortIllegalChromeURL",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestLoadAbortIllegalFileURL) {
-  TestHelper("testLoadAbortIllegalFileURL",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestReload) {
-  TestHelper("testReload",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestGetProcessId) {
-  TestHelper("testGetProcessId",
-             "DoneShimTest.PASSED",
-             "DoneShimTest.FAILED",
-             "web_view/shim");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestRemoveWebviewOnExit) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-
-  // Launch the app and wait until it's ready to load a test.
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("web_view/shim");
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  content::WebContents* embedder_web_contents =
-      GetFirstShellWindowWebContents();
-  ASSERT_TRUE(embedder_web_contents);
-
-  GURL::Replacements replace_host;
-  std::string host_str("localhost");  // Must stay in scope with replace_host.
-  replace_host.SetHostStr(host_str);
-
-  std::string guest_path(
-      "/extensions/platform_apps/web_view/shim/empty_guest.html");
-  GURL guest_url = embedded_test_server()->GetURL(guest_path);
-  guest_url = guest_url.ReplaceComponents(replace_host);
-
-  ui_test_utils::UrlLoadObserver guest_observer(
-      guest_url, content::NotificationService::AllSources());
-
-  // Run the test and wait until the guest WebContents is available and has
-  // finished loading.
-  ExtensionTestMessageListener guest_loaded_listener("guest-loaded", false);
-  EXPECT_TRUE(content::ExecuteScript(
-                  embedder_web_contents,
-                  "runTest('testRemoveWebviewOnExit')"));
-  guest_observer.Wait();
-
-  content::Source<content::NavigationController> source =
-      guest_observer.source();
-  EXPECT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());
-
-  ASSERT_TRUE(guest_loaded_listener.WaitUntilSatisfied());
-
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<content::WebContents>(source->GetWebContents()));
-
-  // Tell the embedder to kill the guest.
-  EXPECT_TRUE(content::ExecuteScript(
-                  embedder_web_contents,
-                  "removeWebviewOnExitDoCrash();"));
-
-  // Wait until the guest WebContents is destroyed.
-  observer.Wait();
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, ShimSrcAttribute) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/src_attribute"))
-      << message_;
-}
-
-// This test verifies that prerendering has been disabled inside <webview>.
-// This test is here rather than in PrerenderBrowserTest for testing convenience
-// only. If it breaks then this is a bug in the prerenderer.
-IN_PROC_BROWSER_TEST_F(WebViewTest, NoPrerenderer) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  content::WebContents* guest_web_contents =
-      LoadGuest(
-          "/extensions/platform_apps/web_view/noprerenderer/guest.html",
-          "web_view/noprerenderer");
-  ASSERT_TRUE(guest_web_contents != NULL);
-
-  PrerenderLinkManager* prerender_link_manager =
-      PrerenderLinkManagerFactory::GetForProfile(
-          Profile::FromBrowserContext(guest_web_contents->GetBrowserContext()));
-  ASSERT_TRUE(prerender_link_manager != NULL);
-  EXPECT_TRUE(prerender_link_manager->IsEmpty());
-}
-
-// This tests cookie isolation for packaged apps with webview tags. It navigates
-// the main browser window to a page that sets a cookie and loads an app with
-// multiple webview tags. Each tag sets a cookie and the test checks the proper
-// storage isolation is enforced.
-IN_PROC_BROWSER_TEST_F(WebViewTest, CookieIsolation) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  const std::string kExpire =
-      "var expire = new Date(Date.now() + 24 * 60 * 60 * 1000);";
-  std::string cookie_script1(kExpire);
-  cookie_script1.append(
-      "document.cookie = 'guest1=true; path=/; expires=' + expire + ';';");
-  std::string cookie_script2(kExpire);
-  cookie_script2.append(
-      "document.cookie = 'guest2=true; path=/; expires=' + expire + ';';");
-
-  GURL::Replacements replace_host;
-  std::string host_str("localhost");  // Must stay in scope with replace_host.
-  replace_host.SetHostStr(host_str);
-
-  GURL set_cookie_url = embedded_test_server()->GetURL(
-      "/extensions/platform_apps/isolation/set_cookie.html");
-  set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
-
-  // The first two partitions will be used to set cookies and ensure they are
-  // shared. The named partition is used to ensure that cookies are isolated
-  // between partitions within the same app.
-  content::WebContents* cookie_contents1;
-  content::WebContents* cookie_contents2;
-  content::WebContents* named_partition_contents1;
-  content::WebContents* named_partition_contents2;
-
-  NavigateAndOpenAppForIsolation(set_cookie_url, &cookie_contents1,
-                                 &cookie_contents2, &named_partition_contents1,
-                                 &named_partition_contents2, NULL, NULL, NULL);
-
-  EXPECT_TRUE(content::ExecuteScript(cookie_contents1, cookie_script1));
-  EXPECT_TRUE(content::ExecuteScript(cookie_contents2, cookie_script2));
-
-  int cookie_size;
-  std::string cookie_value;
-
-  // Test the regular browser context to ensure we have only one cookie.
-  automation_util::GetCookies(GURL("http://localhost"),
-                              browser()->tab_strip_model()->GetWebContentsAt(0),
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("testCookie=1", cookie_value);
-
-  // The default behavior is to combine webview tags with no explicit partition
-  // declaration into the same in-memory partition. Test the webview tags to
-  // ensure we have properly set the cookies and we have both cookies in both
-  // tags.
-  automation_util::GetCookies(GURL("http://localhost"),
-                              cookie_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("guest1=true; guest2=true", cookie_value);
-
-  automation_util::GetCookies(GURL("http://localhost"),
-                              cookie_contents2,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("guest1=true; guest2=true", cookie_value);
-
-  // The third tag should not have any cookies as it is in a separate partition.
-  automation_util::GetCookies(GURL("http://localhost"),
-                              named_partition_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("", cookie_value);
-}
-
-// This tests that in-memory storage partitions are reset on browser restart,
-// but persistent ones maintain state for cookies and HTML5 storage.
-IN_PROC_BROWSER_TEST_F(WebViewTest, PRE_StoragePersistence) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  const std::string kExpire =
-      "var expire = new Date(Date.now() + 24 * 60 * 60 * 1000);";
-  std::string cookie_script1(kExpire);
-  cookie_script1.append(
-      "document.cookie = 'inmemory=true; path=/; expires=' + expire + ';';");
-  std::string cookie_script2(kExpire);
-  cookie_script2.append(
-      "document.cookie = 'persist1=true; path=/; expires=' + expire + ';';");
-  std::string cookie_script3(kExpire);
-  cookie_script3.append(
-      "document.cookie = 'persist2=true; path=/; expires=' + expire + ';';");
-
-  // We don't care where the main browser is on this test.
-  GURL blank_url("about:blank");
-
-  // The first two partitions will be used to set cookies and ensure they are
-  // shared. The named partition is used to ensure that cookies are isolated
-  // between partitions within the same app.
-  content::WebContents* cookie_contents1;
-  content::WebContents* cookie_contents2;
-  content::WebContents* named_partition_contents1;
-  content::WebContents* named_partition_contents2;
-  content::WebContents* persistent_partition_contents1;
-  content::WebContents* persistent_partition_contents2;
-  content::WebContents* persistent_partition_contents3;
-  NavigateAndOpenAppForIsolation(blank_url, &cookie_contents1,
-                                 &cookie_contents2, &named_partition_contents1,
-                                 &named_partition_contents2,
-                                 &persistent_partition_contents1,
-                                 &persistent_partition_contents2,
-                                 &persistent_partition_contents3);
-
-  // Set the inmemory=true cookie for tags with inmemory partitions.
-  EXPECT_TRUE(content::ExecuteScript(cookie_contents1, cookie_script1));
-  EXPECT_TRUE(content::ExecuteScript(named_partition_contents1,
-                                     cookie_script1));
-
-  // For the two different persistent storage partitions, set the
-  // two different cookies so we can check that they aren't comingled below.
-  EXPECT_TRUE(content::ExecuteScript(persistent_partition_contents1,
-                                     cookie_script2));
-
-  EXPECT_TRUE(content::ExecuteScript(persistent_partition_contents3,
-                                     cookie_script3));
-
-  int cookie_size;
-  std::string cookie_value;
-
-  // Check that all in-memory partitions have a cookie set.
-  automation_util::GetCookies(GURL("http://localhost"),
-                              cookie_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("inmemory=true", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              cookie_contents2,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("inmemory=true", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              named_partition_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("inmemory=true", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              named_partition_contents2,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("inmemory=true", cookie_value);
-
-  // Check that all persistent partitions kept their state.
-  automation_util::GetCookies(GURL("http://localhost"),
-                              persistent_partition_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("persist1=true", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              persistent_partition_contents2,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("persist1=true", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              persistent_partition_contents3,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("persist2=true", cookie_value);
-}
-
-// This is the post-reset portion of the StoragePersistence test.  See
-// PRE_StoragePersistence for main comment.
-IN_PROC_BROWSER_TEST_F(WebViewTest, DISABLED_StoragePersistence) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-
-  // We don't care where the main browser is on this test.
-  GURL blank_url("about:blank");
-
-  // The first two partitions will be used to set cookies and ensure they are
-  // shared. The named partition is used to ensure that cookies are isolated
-  // between partitions within the same app.
-  content::WebContents* cookie_contents1;
-  content::WebContents* cookie_contents2;
-  content::WebContents* named_partition_contents1;
-  content::WebContents* named_partition_contents2;
-  content::WebContents* persistent_partition_contents1;
-  content::WebContents* persistent_partition_contents2;
-  content::WebContents* persistent_partition_contents3;
-  NavigateAndOpenAppForIsolation(blank_url, &cookie_contents1,
-                                 &cookie_contents2, &named_partition_contents1,
-                                 &named_partition_contents2,
-                                 &persistent_partition_contents1,
-                                 &persistent_partition_contents2,
-                                 &persistent_partition_contents3);
-
-  int cookie_size;
-  std::string cookie_value;
-
-  // Check that all in-memory partitions lost their state.
-  automation_util::GetCookies(GURL("http://localhost"),
-                              cookie_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              cookie_contents2,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              named_partition_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              named_partition_contents2,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("", cookie_value);
-
-  // Check that all persistent partitions kept their state.
-  automation_util::GetCookies(GURL("http://localhost"),
-                              persistent_partition_contents1,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("persist1=true", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              persistent_partition_contents2,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("persist1=true", cookie_value);
-  automation_util::GetCookies(GURL("http://localhost"),
-                              persistent_partition_contents3,
-                              &cookie_size, &cookie_value);
-  EXPECT_EQ("persist2=true", cookie_value);
-}
-
-#if defined(OS_WIN)
-// This test is very flaky on Win Aura, Win XP, Win 7. http://crbug.com/248873
-#define MAYBE_DOMStorageIsolation DISABLED_DOMStorageIsolation
-#else
-#define MAYBE_DOMStorageIsolation DOMStorageIsolation
-#endif
-
-// This tests DOM storage isolation for packaged apps with webview tags. It
-// loads an app with multiple webview tags and each tag sets DOM storage
-// entries, which the test checks to ensure proper storage isolation is
-// enforced.
-IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_DOMStorageIsolation) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  GURL regular_url = embedded_test_server()->GetURL("/title1.html");
-
-  std::string output;
-  std::string get_local_storage("window.domAutomationController.send("
-      "window.localStorage.getItem('foo') || 'badval')");
-  std::string get_session_storage("window.domAutomationController.send("
-      "window.sessionStorage.getItem('bar') || 'badval')");
-
-  content::WebContents* default_tag_contents1;
-  content::WebContents* default_tag_contents2;
-  content::WebContents* storage_contents1;
-  content::WebContents* storage_contents2;
-
-  NavigateAndOpenAppForIsolation(regular_url, &default_tag_contents1,
-                                 &default_tag_contents2, &storage_contents1,
-                                 &storage_contents2, NULL, NULL, NULL);
-
-  // Initialize the storage for the first of the two tags that share a storage
-  // partition.
-  EXPECT_TRUE(content::ExecuteScript(storage_contents1,
-                                     "initDomStorage('page1')"));
-
-  // Let's test that the expected values are present in the first tag, as they
-  // will be overwritten once we call the initDomStorage on the second tag.
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
-                                            get_local_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("local-page1", output.c_str());
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
-                                            get_session_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("session-page1", output.c_str());
-
-  // Now, init the storage in the second tag in the same storage partition,
-  // which will overwrite the shared localStorage.
-  EXPECT_TRUE(content::ExecuteScript(storage_contents2,
-                                     "initDomStorage('page2')"));
-
-  // The localStorage value now should reflect the one written through the
-  // second tag.
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
-                                            get_local_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("local-page2", output.c_str());
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
-                                            get_local_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("local-page2", output.c_str());
-
-  // Session storage is not shared though, as each webview tag has separate
-  // instance, even if they are in the same storage partition.
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
-                                            get_session_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("session-page1", output.c_str());
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
-                                            get_session_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("session-page2", output.c_str());
-
-  // Also, let's check that the main browser and another tag that doesn't share
-  // the same partition don't have those values stored.
-  EXPECT_TRUE(ExecuteScriptAndExtractString(
-      browser()->tab_strip_model()->GetWebContentsAt(0),
-      get_local_storage.c_str(),
-      &output));
-  EXPECT_STREQ("badval", output.c_str());
-  EXPECT_TRUE(ExecuteScriptAndExtractString(
-      browser()->tab_strip_model()->GetWebContentsAt(0),
-      get_session_storage.c_str(),
-      &output));
-  EXPECT_STREQ("badval", output.c_str());
-  EXPECT_TRUE(ExecuteScriptAndExtractString(default_tag_contents1,
-                                            get_local_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("badval", output.c_str());
-  EXPECT_TRUE(ExecuteScriptAndExtractString(default_tag_contents1,
-                                            get_session_storage.c_str(),
-                                            &output));
-  EXPECT_STREQ("badval", output.c_str());
-}
-
-// See crbug.com/248500
-#if defined(OS_WIN)
-#define MAYBE_IndexedDBIsolation DISABLED_IndexedDBIsolation
-#else
-#define MAYBE_IndexedDBIsolation IndexedDBIsolation
-#endif
-
-// This tests IndexedDB isolation for packaged apps with webview tags. It loads
-// an app with multiple webview tags and each tag creates an IndexedDB record,
-// which the test checks to ensure proper storage isolation is enforced.
-IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_IndexedDBIsolation) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  GURL regular_url = embedded_test_server()->GetURL("/title1.html");
-
-  content::WebContents* default_tag_contents1;
-  content::WebContents* default_tag_contents2;
-  content::WebContents* storage_contents1;
-  content::WebContents* storage_contents2;
-
-  NavigateAndOpenAppForIsolation(regular_url, &default_tag_contents1,
-                                 &default_tag_contents2, &storage_contents1,
-                                 &storage_contents2, NULL, NULL, NULL);
-
-  // Initialize the storage for the first of the two tags that share a storage
-  // partition.
-  ExecuteScriptWaitForTitle(storage_contents1, "initIDB()", "idb created");
-  ExecuteScriptWaitForTitle(storage_contents1, "addItemIDB(7, 'page1')",
-                            "addItemIDB complete");
-  ExecuteScriptWaitForTitle(storage_contents1, "readItemIDB(7)",
-                            "readItemIDB complete");
-
-  std::string output;
-  std::string get_value(
-      "window.domAutomationController.send(getValueIDB() || 'badval')");
-
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
-                                            get_value.c_str(), &output));
-  EXPECT_STREQ("page1", output.c_str());
-
-  // Initialize the db in the second tag.
-  ExecuteScriptWaitForTitle(storage_contents2, "initIDB()", "idb open");
-
-  // Since we share a partition, reading the value should return the existing
-  // one.
-  ExecuteScriptWaitForTitle(storage_contents2, "readItemIDB(7)",
-                            "readItemIDB complete");
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
-                                            get_value.c_str(), &output));
-  EXPECT_STREQ("page1", output.c_str());
-
-  // Now write through the second tag and read it back.
-  ExecuteScriptWaitForTitle(storage_contents2, "addItemIDB(7, 'page2')",
-                            "addItemIDB complete");
-  ExecuteScriptWaitForTitle(storage_contents2, "readItemIDB(7)",
-                            "readItemIDB complete");
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents2,
-                                            get_value.c_str(), &output));
-  EXPECT_STREQ("page2", output.c_str());
-
-  // Reset the document title, otherwise the next call will not see a change and
-  // will hang waiting for it.
-  EXPECT_TRUE(content::ExecuteScript(storage_contents1,
-                                     "document.title = 'foo'"));
-
-  // Read through the first tag to ensure we have the second value.
-  ExecuteScriptWaitForTitle(storage_contents1, "readItemIDB(7)",
-                            "readItemIDB complete");
-  EXPECT_TRUE(ExecuteScriptAndExtractString(storage_contents1,
-                                            get_value.c_str(), &output));
-  EXPECT_STREQ("page2", output.c_str());
-
-  // Now, let's confirm there is no database in the main browser and another
-  // tag that doesn't share the same partition. Due to the IndexedDB API design,
-  // open will succeed, but the version will be 1, since it creates the database
-  // if it is not found. The two tags use database version 3, so we avoid
-  // ambiguity.
-  const char* script =
-      "indexedDB.open('isolation').onsuccess = function(e) {"
-      "  if (e.target.result.version == 1)"
-      "    document.title = 'db not found';"
-      "  else "
-      "    document.title = 'error';"
-      "}";
-  ExecuteScriptWaitForTitle(browser()->tab_strip_model()->GetWebContentsAt(0),
-                            script, "db not found");
-  ExecuteScriptWaitForTitle(default_tag_contents1, script, "db not found");
-}
-
-// This test ensures that closing app window on 'loadcommit' does not crash.
-// The test launches an app with guest and closes the window on loadcommit. It
-// then launches the app window again. The process is repeated 3 times.
-IN_PROC_BROWSER_TEST_F(WebViewTest, CloseOnLoadcommit) {
-  ExtensionTestMessageListener done_test_listener(
-      "done-close-on-loadcommit", false);
-  LoadAndLaunchPlatformApp("web_view/close_on_loadcommit");
-  ASSERT_TRUE(done_test_listener.WaitUntilSatisfied());
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIDeny_TestDeny) {
-  MediaAccessAPIDenyTestHelper("testDeny");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest,
-                       MediaAccessAPIDeny_TestDenyThenAllowThrows) {
-  MediaAccessAPIDenyTestHelper("testDenyThenAllowThrows");
-
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest,
-                       MediaAccessAPIDeny_TestDenyWithPreventDefault) {
-  MediaAccessAPIDenyTestHelper("testDenyWithPreventDefault");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest,
-                       MediaAccessAPIDeny_TestNoListenersImplyDeny) {
-  MediaAccessAPIDenyTestHelper("testNoListenersImplyDeny");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest,
-                       MediaAccessAPIDeny_TestNoPreventDefaultImpliesDeny) {
-  MediaAccessAPIDenyTestHelper("testNoPreventDefaultImpliesDeny");
-}
-
-void WebViewTest::MediaAccessAPIAllowTestHelper(const std::string& test_name) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("web_view/media_access/allow");
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  content::WebContents* embedder_web_contents =
-      GetFirstShellWindowWebContents();
-  ASSERT_TRUE(embedder_web_contents);
-  MockWebContentsDelegate* mock = new MockWebContentsDelegate;
-  embedder_web_contents->SetDelegate(mock);
-
-  ExtensionTestMessageListener done_listener("DoneMediaTest.PASSED", false);
-  done_listener.AlsoListenForFailureMessage("DoneMediaTest.FAILED");
-  EXPECT_TRUE(
-      content::ExecuteScript(
-          embedder_web_contents,
-          base::StringPrintf("startAllowTest('%s')",
-                             test_name.c_str())));
-  ASSERT_TRUE(done_listener.WaitUntilSatisfied());
-
-  mock->WaitForSetMediaPermission();
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllow) {
-  MediaAccessAPIAllowTestHelper("testAllow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllowAndThenDeny) {
-  MediaAccessAPIAllowTestHelper("testAllowAndThenDeny");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllowTwice) {
-  MediaAccessAPIAllowTestHelper("testAllowTwice");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, MediaAccessAPIAllow_TestAllowAsync) {
-  MediaAccessAPIAllowTestHelper("testAllowAsync");
-}
-
-// Checks that window.screenX/screenY/screenLeft/screenTop works correctly for
-// guests.
-IN_PROC_BROWSER_TEST_F(WebViewTest, ScreenCoordinates) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ASSERT_TRUE(RunPlatformAppTestWithArg(
-      "platform_apps/web_view/common", "screen_coordinates"))
-          << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, SpeechRecognition) {
-  ASSERT_TRUE(StartEmbeddedTestServer());
-  content::WebContents* guest_web_contents = LoadGuest(
-      "/extensions/platform_apps/web_view/speech/guest.html",
-      "web_view/speech");
-  ASSERT_TRUE(guest_web_contents);
-
-  // Click on the guest (center of the WebContents), the guest is rendered in a
-  // way that this will trigger clicking on speech recognition input mic.
-  SimulateMouseClick(guest_web_contents, 0, WebKit::WebMouseEvent::ButtonLeft);
-
-  string16 expected_title(ASCIIToUTF16("PASSED"));
-  string16 error_title(ASCIIToUTF16("FAILED"));
-  content::TitleWatcher title_watcher(guest_web_contents, expected_title);
-  title_watcher.AlsoWaitForTitle(error_title);
-  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, TearDownTest) {
-  ExtensionTestMessageListener first_loaded_listener("guest-loaded", false);
-  const extensions::Extension* extension =
-      LoadAndLaunchPlatformApp("web_view/teardown");
-  ASSERT_TRUE(first_loaded_listener.WaitUntilSatisfied());
-  apps::ShellWindow* window = NULL;
-  if (!GetShellWindowCount())
-    window = CreateShellWindow(extension);
-  else
-    window = GetFirstShellWindow();
-  CloseShellWindow(window);
-
-  // Load the app again.
-  ExtensionTestMessageListener second_loaded_listener("guest-loaded", false);
-  LoadAndLaunchPlatformApp("web_view/teardown");
-  ASSERT_TRUE(second_loaded_listener.WaitUntilSatisfied());
-}
-
-// In following GeolocationAPIEmbedderHasNoAccess* tests, embedder (i.e. the
-// platform app) does not have geolocation permission for this test.
-// No matter what the API does, geolocation permission would be denied.
-// Note that the test name prefix must be "GeolocationAPI".
-IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasNoAccessAllow) {
-  TestHelper("testDenyDenies",
-             "DoneGeolocationTest.PASSED",
-             "DoneGeolocationTest.FAILED",
-             "web_view/geolocation/embedder_has_no_permission");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasNoAccessDeny) {
-  TestHelper("testDenyDenies",
-             "DoneGeolocationTest.PASSED",
-             "DoneGeolocationTest.FAILED",
-             "web_view/geolocation/embedder_has_no_permission");
-}
-
-// In following GeolocationAPIEmbedderHasAccess* tests, embedder (i.e. the
-// platform app) has geolocation permission
-//
-// Note that these test names must be "GeolocationAPI" prefixed (b/c we mock out
-// geolocation in this case).
-//
-// Also note that these are run separately because OverrideGeolocation() doesn't
-// mock out geolocation for multiple navigator.geolocation calls properly and
-// the tests become flaky.
-// GeolocationAPI* test 1 of 3.
-IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasAccessAllow) {
-  TestHelper("testAllow",
-             "DoneGeolocationTest.PASSED",
-             "DoneGeolocationTest.FAILED",
-             "web_view/geolocation/embedder_has_permission");
-}
-
-// GeolocationAPI* test 2 of 3.
-IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPIEmbedderHasAccessDeny) {
-  TestHelper("testDeny",
-             "DoneGeolocationTest.PASSED",
-             "DoneGeolocationTest.FAILED",
-             "web_view/geolocation/embedder_has_permission");
-}
-
-// GeolocationAPI* test 3 of 3.
-IN_PROC_BROWSER_TEST_F(WebViewTest,
-                       GeolocationAPIEmbedderHasAccessMultipleBridgeIdAllow) {
-  TestHelper("testMultipleBridgeIdAllow",
-             "DoneGeolocationTest.PASSED",
-             "DoneGeolocationTest.FAILED",
-             "web_view/geolocation/embedder_has_permission");
-}
-
-// Tests that
-// BrowserPluginGeolocationPermissionContext::CancelGeolocationPermissionRequest
-// is handled correctly (and does not crash).
-IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationAPICancelGeolocation) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ASSERT_TRUE(RunPlatformAppTest(
-        "platform_apps/web_view/geolocation/cancel_request")) << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, GeolocationRequestGone) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ASSERT_TRUE(RunPlatformAppTest(
-        "platform_apps/web_view/geolocation/geolocation_request_gone"))
-            << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, ConsoleMessage) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ASSERT_TRUE(RunPlatformAppTestWithArg(
-      "platform_apps/web_view/common", "console_messages"))
-          << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, DownloadPermission) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  content::WebContents* guest_web_contents =
-      LoadGuest("/extensions/platform_apps/web_view/download/guest.html",
-                "web_view/download");
-  ASSERT_TRUE(guest_web_contents);
-
-  // Replace WebContentsDelegate with mock version so we can intercept download
-  // requests.
-  content::WebContentsDelegate* delegate = guest_web_contents->GetDelegate();
-  MockDownloadWebContentsDelegate* mock_delegate =
-      new MockDownloadWebContentsDelegate(delegate);
-  guest_web_contents->SetDelegate(mock_delegate);
-
-  // Start test.
-  // 1. Guest requests a download that its embedder denies.
-  EXPECT_TRUE(content::ExecuteScript(guest_web_contents,
-                                     "startDownload('download-link-1')"));
-  mock_delegate->WaitForCanDownload(false); // Expect to not allow.
-  mock_delegate->Reset();
-
-  // 2. Guest requests a download that its embedder allows.
-  EXPECT_TRUE(content::ExecuteScript(guest_web_contents,
-                                     "startDownload('download-link-2')"));
-  mock_delegate->WaitForCanDownload(true); // Expect to allow.
-  mock_delegate->Reset();
-
-  // 3. Guest requests a download that its embedder ignores, this implies deny.
-  EXPECT_TRUE(content::ExecuteScript(guest_web_contents,
-                                     "startDownload('download-link-3')"));
-  mock_delegate->WaitForCanDownload(false); // Expect to not allow.
-}
-
-// This test makes sure loading <webview> does not crash when there is an
-// 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;
-  const std::string extension_id = "imeongpbjoodlnmlakaldhlcmijmhpbb";
-  whitelist.push_back(extension_id);
-  extensions::Extension::SetScriptingWhitelist(whitelist);
-
-  // Load the extension.
-  const extensions::Extension* content_script_whitelisted_extension =
-      LoadExtension(test_data_dir_.AppendASCII(
-                        "platform_apps/web_view/legacy/content_script"));
-  ASSERT_TRUE(content_script_whitelisted_extension);
-  ASSERT_EQ(extension_id, content_script_whitelisted_extension->id());
-
-  // Now load an app with <webview>.
-  ExtensionTestMessageListener done_listener("DoneTest", false);
-  LoadAndLaunchPlatformApp("web_view/content_script_whitelisted");
-  ASSERT_TRUE(done_listener.WaitUntilSatisfied());
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, SetPropertyOnDocumentReady) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/document_ready"))
-                  << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, SetPropertyOnDocumentInteractive) {
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/document_interactive"))
-                  << message_;
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestAlertDialog) {
-  TestHelper("testAlertDialog",
-             "DoneDialogTest.PASSED",
-             "DoneDialogTest.FAILED",
-             "web_view/dialog");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialog) {
-  TestHelper("testConfirmDialog",
-             "DoneDialogTest.PASSED",
-             "DoneDialogTest.FAILED",
-             "web_view/dialog");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialogCancel) {
-  TestHelper("testConfirmDialogCancel",
-             "DoneDialogTest.PASSED",
-             "DoneDialogTest.FAILED",
-             "web_view/dialog");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialogDefaultCancel) {
-  TestHelper("testConfirmDialogDefaultCancel",
-             "DoneDialogTest.PASSED",
-             "DoneDialogTest.FAILED",
-             "web_view/dialog");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestConfirmDialogDefaultGCCancel) {
-  TestHelper("testConfirmDialogDefaultGCCancel",
-             "DoneDialogTest.PASSED",
-             "DoneDialogTest.FAILED",
-             "web_view/dialog");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewTest, Dialog_TestPromptDialog) {
-  TestHelper("testPromptDialog",
-             "DoneDialogTest.PASSED",
-             "DoneDialogTest.FAILED",
-             "web_view/dialog");
-}
diff --git a/chrome/browser/extensions/web_view_interactive_browsertest.cc b/chrome/browser/extensions/web_view_interactive_browsertest.cc
deleted file mode 100644
index 170fb9b..0000000
--- a/chrome/browser/extensions/web_view_interactive_browsertest.cc
+++ /dev/null
@@ -1,671 +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 "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
-#include "chrome/test/base/interactive_test_utils.h"
-#include "chrome/test/base/test_launcher_utils.h"
-#include "chrome/test/base/ui_test_utils.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/render_widget_host_view.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/public/test/browser_test_utils.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "ui/base/keycodes/keyboard_codes.h"
-#include "ui/base/test/ui_controls.h"
-
-using apps::ShellWindow;
-
-class WebViewInteractiveTest
-    : public extensions::PlatformAppBrowserTest {
- public:
-  WebViewInteractiveTest()
-      : corner_(gfx::Point()),
-        mouse_click_result_(false),
-        first_click_(true) {}
-
-  void MoveMouseInsideWindowWithListener(gfx::Point point,
-                                         const std::string& message) {
-    ExtensionTestMessageListener move_listener(message, false);
-    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
-        gfx::Point(corner_.x() + point.x(), corner_.y() + point.y())));
-    ASSERT_TRUE(move_listener.WaitUntilSatisfied());
-  }
-
-  void SendMouseClickWithListener(ui_controls::MouseButton button,
-                                  const std::string& message) {
-    ExtensionTestMessageListener listener(message, false);
-    SendMouseClick(button);
-    ASSERT_TRUE(listener.WaitUntilSatisfied());
-  }
-
-  void SendMouseClick(ui_controls::MouseButton button) {
-    SendMouseEvent(button, ui_controls::DOWN);
-    SendMouseEvent(button, ui_controls::UP);
-  }
-
-  void MoveMouseInsideWindow(const gfx::Point& point) {
-    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
-        gfx::Point(corner_.x() + point.x(), corner_.y() + point.y())));
-  }
-
-  gfx::NativeWindow GetPlatformAppWindow() {
-    const apps::ShellWindowRegistry::ShellWindowList& shell_windows =
-        apps::ShellWindowRegistry::Get(
-            browser()->profile())->shell_windows();
-    return (*shell_windows.begin())->GetNativeWindow();
-  }
-
-  void SendKeyPressToPlatformApp(ui::KeyboardCode key) {
-    ASSERT_EQ(1U, GetShellWindowCount());
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), key, false, false, false, false));
-  }
-
-  void SendCopyKeyPressToPlatformApp() {
-    ASSERT_EQ(1U, GetShellWindowCount());
-#if defined(OS_MACOSX)
-    // Send Cmd+C on MacOSX.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_C, false, false, false, true));
-#else
-    // Send Ctrl+C on Windows and Linux/ChromeOS.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_C, true, false, false, false));
-#endif
-  }
-
-  void SendStartOfLineKeyPressToPlatformApp() {
-#if defined(OS_MACOSX)
-    // Send Cmd+Left on MacOSX.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_LEFT, false, false, false, true));
-#else
-    // Send Ctrl+Left on Windows and Linux/ChromeOS.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_LEFT, true, false, false, false));
-#endif
-  }
-
-  void SendBackShortcutToPlatformApp() {
-#if defined(OS_MACOSX)
-    // Send Cmd+[ on MacOSX.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_OEM_4, false, false, false, true));
-#else
-    // Send browser back key on Linux/Windows.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_BROWSER_BACK,
-        false, false, false, false));
-#endif
-  }
-
-  void SendForwardShortcutToPlatformApp() {
-#if defined(OS_MACOSX)
-    // Send Cmd+] on MacOSX.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_OEM_6, false, false, false, true));
-#else
-    // Send browser back key on Linux/Windows.
-    ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
-        GetPlatformAppWindow(), ui::VKEY_BROWSER_FORWARD,
-        false, false, false, false));
-#endif
-  }
-
-  void SendMouseEvent(ui_controls::MouseButton button,
-                      ui_controls::MouseButtonState state) {
-    if (first_click_) {
-      mouse_click_result_ = ui_test_utils::SendMouseEventsSync(button,
-                                                                state);
-      first_click_ = false;
-    } else {
-      ASSERT_EQ(mouse_click_result_, ui_test_utils::SendMouseEventsSync(
-          button, state));
-    }
-  }
-
-  void TestHelper(const std::string& test_name,
-                  const std::string& test_passed_msg,
-                  const std::string& test_failed_msg,
-                  const std::string& app_location) {
-    ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-    ExtensionTestMessageListener launched_listener("Launched", false);
-    LoadAndLaunchPlatformApp(app_location.c_str());
-    ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-    ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
-        GetPlatformAppWindow()));
-
-    // Flush any pending events to make sure we start with a clean slate.
-    content::RunAllPendingInMessageLoop();
-
-    content::WebContents* embedder_web_contents =
-        GetFirstShellWindowWebContents();
-    ASSERT_TRUE(embedder_web_contents);
-
-    ExtensionTestMessageListener done_listener(test_passed_msg, false);
-    done_listener.AlsoListenForFailureMessage(test_failed_msg);
-    EXPECT_TRUE(content::ExecuteScript(
-                    embedder_web_contents,
-                    base::StringPrintf("runTest('%s')", test_name.c_str())));
-    ASSERT_TRUE(done_listener.WaitUntilSatisfied());
-  }
-
-  void SetupTest(const std::string& app_name,
-                 const std::string& guest_url_spec) {
-    ASSERT_TRUE(StartEmbeddedTestServer());
-    GURL::Replacements replace_host;
-    std::string host_str("localhost");  // Must stay in scope with replace_host.
-    replace_host.SetHostStr(host_str);
-
-    GURL guest_url = embedded_test_server()->GetURL(guest_url_spec);
-    guest_url = guest_url.ReplaceComponents(replace_host);
-
-    ui_test_utils::UrlLoadObserver guest_observer(
-        guest_url, content::NotificationService::AllSources());
-
-    ExtensionTestMessageListener guest_connected_listener("connected", false);
-    LoadAndLaunchPlatformApp(app_name.c_str());
-
-    guest_observer.Wait();
-
-    // Wait until the guest process reports that it has established a message
-    // channel with the app.
-    ASSERT_TRUE(guest_connected_listener.WaitUntilSatisfied());
-    content::Source<content::NavigationController> source =
-        guest_observer.source();
-    EXPECT_TRUE(source->GetWebContents()->GetRenderProcessHost()->IsGuest());
-
-    guest_web_contents_ = source->GetWebContents();
-    embedder_web_contents_ = guest_web_contents_->GetEmbedderWebContents();
-
-    gfx::Rect offset;
-    embedder_web_contents_->GetView()->GetContainerBounds(&offset);
-    corner_ = gfx::Point(offset.x(), offset.y());
-
-    const testing::TestInfo* const test_info =
-            testing::UnitTest::GetInstance()->current_test_info();
-    const std::string& prefix = "DragDropWithinWebView";
-    if (!strncmp(test_info->name(), prefix.c_str(), prefix.size())) {
-      // In the drag drop test we add 20px padding to the page body because on
-      // windows if we get too close to the edge of the window the resize cursor
-      // appears and we start dragging the window edge.
-      corner_.Offset(20, 20);
-    }
-  }
-
-  content::WebContents* guest_web_contents() {
-    return guest_web_contents_;
-  }
-
-  content::WebContents* embedder_web_contents() {
-    return embedder_web_contents_;
-  }
-
-  gfx::Point corner() {
-    return corner_;
-  }
-
-  void SimulateRWHMouseClick(content::RenderWidgetHost* rwh, int x, int y) {
-    WebKit::WebMouseEvent mouse_event;
-    mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
-    mouse_event.x = mouse_event.windowX = x;
-    mouse_event.y = mouse_event.windowY = y;
-    mouse_event.modifiers = 0;
-
-    mouse_event.type = WebKit::WebInputEvent::MouseDown;
-    rwh->ForwardMouseEvent(mouse_event);
-    mouse_event.type = WebKit::WebInputEvent::MouseUp;
-    rwh->ForwardMouseEvent(mouse_event);
-  }
-
-  class PopupCreatedObserver {
-   public:
-    PopupCreatedObserver() : created_(false), last_render_widget_host_(NULL) {
-      created_callback_ = base::Bind(
-          &PopupCreatedObserver::CreatedCallback, base::Unretained(this));
-      content::RenderWidgetHost::AddCreatedCallback(created_callback_);
-    }
-    virtual ~PopupCreatedObserver() {
-      content::RenderWidgetHost::RemoveCreatedCallback(created_callback_);
-    }
-    void Reset() {
-      created_ = false;
-    }
-    void Start() {
-      if (created_)
-        return;
-      message_loop_ = new content::MessageLoopRunner;
-      message_loop_->Run();
-    }
-    content::RenderWidgetHost* last_render_widget_host() {
-      return last_render_widget_host_;
-    }
-
-   private:
-    void CreatedCallback(content::RenderWidgetHost* rwh) {
-      last_render_widget_host_ = rwh;
-      if (message_loop_.get())
-        message_loop_->Quit();
-      else
-        created_ = true;
-    }
-    content::RenderWidgetHost::CreatedCallback created_callback_;
-    scoped_refptr<content::MessageLoopRunner> message_loop_;
-    bool created_;
-    content::RenderWidgetHost* last_render_widget_host_;
-  };
-
-  void WaitForTitle(const char* title) {
-    string16 expected_title(ASCIIToUTF16(title));
-    string16 error_title(ASCIIToUTF16("FAILED"));
-    content::TitleWatcher title_watcher(guest_web_contents(), expected_title);
-    title_watcher.AlsoWaitForTitle(error_title);
-    ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
-  }
-
-  void PopupTestHelper(const gfx::Point& padding) {
-    PopupCreatedObserver popup_created_observer;
-    popup_created_observer.Reset();
-
-    content::SimulateKeyPress(
-        guest_web_contents(),
-        ui::VKEY_C,  // C to autocomplete.
-        false, false, false, false);
-
-    WaitForTitle("PASSED1");
-
-    popup_created_observer.Start();
-
-    content::RenderWidgetHost* popup_rwh = NULL;
-    popup_rwh = popup_created_observer.last_render_widget_host();
-    // Popup must be present.
-    ASSERT_TRUE(popup_rwh);
-    ASSERT_TRUE(!popup_rwh->IsRenderView());
-    ASSERT_TRUE(popup_rwh->GetView());
-
-    string16 expected_title = ASCIIToUTF16("PASSED2");
-    string16 error_title = ASCIIToUTF16("FAILED");
-    content::TitleWatcher title_watcher(guest_web_contents(), expected_title);
-    title_watcher.AlsoWaitForTitle(error_title);
-    EXPECT_TRUE(content::ExecuteScript(guest_web_contents(),
-                                       "changeTitle();"));
-    ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
-
-    gfx::Rect popup_bounds = popup_rwh->GetView()->GetViewBounds();
-    // (2, 2) is expected to lie on the first datalist element.
-    SimulateRWHMouseClick(popup_rwh, 2, 2);
-
-    content::RenderViewHost* embedder_rvh =
-        GetFirstShellWindowWebContents()->GetRenderViewHost();
-    gfx::Rect embedder_bounds = embedder_rvh->GetView()->GetViewBounds();
-    gfx::Vector2d diff = popup_bounds.origin() - embedder_bounds.origin();
-    LOG(INFO) << "DIFF: x = " << diff.x() << ", y = " << diff.y();
-
-    const int left_spacing = 40 + padding.x();  // div.style.paddingLeft = 40px.
-    // div.style.paddingTop = 50px + (input box height = 26px).
-    const int top_spacing = 50 + 26 + padding.y();
-
-    // If the popup is placed within |threshold_px| of the expected position,
-    // then we consider the test as a pass.
-    const int threshold_px = 10;
-
-    EXPECT_LE(std::abs(diff.x() - left_spacing), threshold_px);
-    EXPECT_LE(std::abs(diff.y() - top_spacing), threshold_px);
-
-    WaitForTitle("PASSED3");
-  }
-
-  void DragTestStep1() {
-    // Move mouse to start of text.
-    MoveMouseInsideWindow(gfx::Point(45, 8));
-    SendMouseEvent(ui_controls::LEFT, ui_controls::DOWN);
-    MoveMouseInsideWindow(gfx::Point(76, 12));
-
-    // Now wait a bit before moving mouse to initiate drag/drop.
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&WebViewInteractiveTest::DragTestStep2,
-                   base::Unretained(this)),
-        base::TimeDelta::FromMilliseconds(200));
-  }
-
-  void DragTestStep2() {
-    // Drag source over target.
-    MoveMouseInsideWindow(gfx::Point(76, 76));
-
-    // Create a second mouse over the source to trigger the drag over event.
-    MoveMouseInsideWindow(gfx::Point(76, 77));
-
-    // Release mouse to drop.
-    SendMouseEvent(ui_controls::LEFT, ui_controls::UP);
-    SendMouseClick(ui_controls::LEFT);
-
-    quit_closure_.Run();
-
-    // Note that following ExtensionTestMessageListener and ExecuteScript*
-    // call must be after we quit |quit_closure_|. Otherwise the class
-    // here won't be able to receive messages sent by chrome.test.sendMessage.
-    // This is because of the nature of drag and drop code (esp. the
-    // MessageLoop) in it.
-
-    // Now verify we got a drop and correct drop data.
-    ExtensionTestMessageListener drop_listener("guest-got-drop", false);
-    EXPECT_TRUE(content::ExecuteScript(guest_web_contents_,
-                                       "window.pingEmbedder()"));
-    EXPECT_TRUE(drop_listener.WaitUntilSatisfied());
-
-    std::string last_drop_data;
-    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-        embedder_web_contents_,
-        "window.domAutomationController.send(getLastDropData())",
-        &last_drop_data));
-    EXPECT_EQ(last_drop_data, "Drop me");
-  }
-
- protected:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    command_line->AppendSwitch(switches::kEnableBrowserPluginDragDrop);
-    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
-  }
-
-  content::WebContents* guest_web_contents_;
-  content::WebContents* embedder_web_contents_;
-  gfx::Point corner_;
-  bool mouse_click_result_;
-  bool first_click_;
-  // Only used in drag/drop test.
-  base::Closure quit_closure_;
-};
-
-// ui_test_utils::SendMouseMoveSync doesn't seem to work on OS_MACOSX, and
-// likely won't work on many other platforms as well, so for now this test
-// is for Windows and Linux only.
-#if (defined(OS_WIN) || defined(OS_LINUX))
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, PointerLock) {
-  SetupTest("web_view/pointer_lock",
-            "/extensions/platform_apps/web_view/pointer_lock/guest.html");
-
-  // Move the mouse over the Lock Pointer button.
-  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
-      gfx::Point(corner().x() + 75, corner().y() + 25)));
-
-  // Click the Lock Pointer button. The first two times the button is clicked
-  // the permission API will deny the request (intentional).
-  ExtensionTestMessageListener exception_listener("request exception", false);
-  SendMouseClickWithListener(ui_controls::LEFT, "lock error");
-  ASSERT_TRUE(exception_listener.WaitUntilSatisfied());
-  SendMouseClickWithListener(ui_controls::LEFT, "lock error");
-
-  // Click the Lock Pointer button, locking the mouse to lockTarget1.
-  SendMouseClickWithListener(ui_controls::LEFT, "locked");
-
-  // Attempt to move the mouse off of the lock target, and onto lockTarget2,
-  // (which would trigger a test failure).
-  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
-      gfx::Point(corner().x() + 74, corner().y() + 74)));
-  MoveMouseInsideWindowWithListener(gfx::Point(75, 75), "mouse-move");
-
-#if (defined(OS_WIN) && defined(USE_AURA))
-  // When the mouse is unlocked on win aura, sending a test mouse click clicks
-  // where the mouse moved to while locked. I was unable to figure out why, and
-  // since the issue only occurs with the test mouse events, just fix it with
-  // a simple workaround - moving the mouse back to where it should be.
-  // TODO(mthiesse): Fix Win Aura simulated mouse events while mouse locked.
-  MoveMouseInsideWindowWithListener(gfx::Point(75, 25), "mouse-move");
-#endif
-
-  ExtensionTestMessageListener unlocked_listener("unlocked", false);
-  // Send a key press to unlock the mouse.
-  SendKeyPressToPlatformApp(ui::VKEY_ESCAPE);
-
-  // Wait for page to receive (successful) mouse unlock response.
-  ASSERT_TRUE(unlocked_listener.WaitUntilSatisfied());
-
-  // After the second lock, guest.js sends a message to main.js to remove the
-  // webview object. main.js then removes the div containing the webview, which
-  // should unlock, and leave the mouse over the mousemove-capture-container
-  // div. We then move the mouse over that div to ensure the mouse was properly
-  // unlocked and that the div receieves the message.
-  ExtensionTestMessageListener move_captured_listener("move-captured", false);
-  move_captured_listener.AlsoListenForFailureMessage("timeout");
-
-  // Mouse should already be over lock button (since we just unlocked), so send
-  // click to re-lock the mouse.
-  SendMouseClickWithListener(ui_controls::LEFT, "deleted");
-
-  // A mousemove event is triggered on the mousemove-capture-container element
-  // when we delete the webview container (since the mouse moves onto the
-  // element), but just in case, send an explicit mouse movement to be safe.
-  ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
-      gfx::Point(corner().x() + 50, corner().y() + 10)));
-
-  // Wait for page to receive second (successful) mouselock response.
-  bool success = move_captured_listener.WaitUntilSatisfied();
-  if (!success) {
-    fprintf(stderr, "TIMEOUT - retrying\n");
-    // About 1 in 40 tests fail to detect mouse moves at this point (why?).
-    // Sending a right click seems to fix this (why?).
-    ExtensionTestMessageListener move_listener2("move-captured", false);
-    SendMouseClick(ui_controls::RIGHT);
-    ASSERT_TRUE(ui_test_utils::SendMouseMoveSync(
-        gfx::Point(corner().x() + 51, corner().y() + 11)));
-    ASSERT_TRUE(move_listener2.WaitUntilSatisfied());
-  }
-}
-
-#endif  // (defined(OS_WIN) || defined(OS_LINUX))
-
-// Tests that setting focus on the <webview> sets focus on the guest.
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_Focus) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ASSERT_TRUE(RunPlatformAppTest("platform_apps/web_view/focus"))
-      << message_;
-}
-
-// Tests that guests receive edit commands and respond appropriately.
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommands) {
-  SetupTest("web_view/edit_commands",
-            "/extensions/platform_apps/web_view/edit_commands/guest.html");
-
-  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
-      GetPlatformAppWindow()));
-
-  // Flush any pending events to make sure we start with a clean slate.
-  content::RunAllPendingInMessageLoop();
-
-  ExtensionTestMessageListener copy_listener("copy", false);
-  SendCopyKeyPressToPlatformApp();
-
-  // Wait for the guest to receive a 'copy' edit command.
-  ASSERT_TRUE(copy_listener.WaitUntilSatisfied());
-}
-
-// Tests that guests receive edit commands and respond appropriately.
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, EditCommandsNoMenu) {
-  SetupTest("web_view/edit_commands_no_menu",
-      "/extensions/platform_apps/web_view/edit_commands_no_menu/"
-      "guest.html");
-
-  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
-      GetPlatformAppWindow()));
-
-  // Flush any pending events to make sure we start with a clean slate.
-  content::RunAllPendingInMessageLoop();
-
-  ExtensionTestMessageListener start_of_line_listener("StartOfLine", false);
-  SendStartOfLineKeyPressToPlatformApp();
-  // Wait for the guest to receive a 'copy' edit command.
-  ASSERT_TRUE(start_of_line_listener.WaitUntilSatisfied());
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
-                       NewWindow_NewWindowNameTakesPrecedence) {
-  TestHelper("testNewWindowNameTakesPrecedence",
-             "DoneNewWindowTest.PASSED",
-             "DoneNewWindowTest.FAILED",
-             "web_view/newwindow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
-                       NewWindow_WebViewNameTakesPrecedence) {
-  TestHelper("testWebViewNameTakesPrecedence",
-             "DoneNewWindowTest.PASSED",
-             "DoneNewWindowTest.FAILED",
-             "web_view/newwindow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_NoName) {
-  TestHelper("testNoName",
-             "DoneNewWindowTest.PASSED",
-             "DoneNewWindowTest.FAILED",
-             "web_view/newwindow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_Redirect) {
-  TestHelper("testNewWindowRedirect",
-             "DoneNewWindowTest.PASSED",
-             "DoneNewWindowTest.FAILED",
-             "web_view/newwindow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_Close) {
-  TestHelper("testNewWindowClose",
-             "DoneNewWindowTest.PASSED",
-             "DoneNewWindowTest.FAILED",
-             "web_view/newwindow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_ExecuteScript) {
-  TestHelper("testNewWindowExecuteScript",
-             "DoneNewWindowTest.PASSED",
-             "DoneNewWindowTest.FAILED",
-             "web_view/newwindow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, NewWindow_WebRequest) {
-  TestHelper("testNewWindowWebRequest",
-             "DoneNewWindowTest.PASSED",
-             "DoneNewWindowTest.FAILED",
-             "web_view/newwindow");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, ExecuteCode) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ASSERT_TRUE(RunPlatformAppTestWithArg(
-      "platform_apps/web_view/common", "execute_code")) << message_;
-}
-
-// This test used the old Autofill UI, which has been removed.
-// See crbug.com/259438
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_PopupPositioning) {
-  SetupTest(
-      "web_view/popup_positioning",
-      "/extensions/platform_apps/web_view/popup_positioning/guest.html");
-  ASSERT_TRUE(guest_web_contents());
-
-  PopupTestHelper(gfx::Point());
-
-  // moveTo a random location and run the steps again.
-  EXPECT_TRUE(content::ExecuteScript(embedder_web_contents(),
-                                     "window.moveTo(16, 20);"));
-  PopupTestHelper(gfx::Point());
-}
-
-// Tests that moving browser plugin (without resize/UpdateRects) correctly
-// repositions popup.
-// Started flakily failing after a Blink roll: http://crbug.com/245332
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DISABLED_PopupPositioningMoved) {
-  SetupTest(
-      "web_view/popup_positioning_moved",
-      "/extensions/platform_apps/web_view/popup_positioning_moved"
-      "/guest.html");
-  ASSERT_TRUE(guest_web_contents());
-
-  PopupTestHelper(gfx::Point(20, 0));
-}
-
-// Drag and drop inside a webview is currently only enabled for linux and mac,
-// but the tests don't work on anything except chromeos for now. This is because
-// of simulating mouse drag code's dependency on platforms.
-#if defined(OS_CHROMEOS)
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, DragDropWithinWebView) {
-  SetupTest(
-      "web_view/dnd_within_webview",
-      "/extensions/platform_apps/web_view/dnd_within_webview/guest.html");
-  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
-
-  // Flush any pending events to make sure we start with a clean slate.
-  content::RunAllPendingInMessageLoop();
-  base::RunLoop run_loop;
-  quit_closure_ = run_loop.QuitClosure();
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&WebViewInteractiveTest::DragTestStep1,
-                 base::Unretained(this)));
-  run_loop.Run();
-}
-#endif  // (defined(OS_CHROMEOS))
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation) {
-  TestHelper("testNavigation",
-             "DoneNavigationTest.PASSED",
-             "DoneNavigationTest.FAILED",
-             "web_view/navigation");
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest, Navigation_BackForwardKeys) {
-  ASSERT_TRUE(StartEmbeddedTestServer());  // For serving guest pages.
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  LoadAndLaunchPlatformApp("web_view/navigation");
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-
-  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(
-      GetPlatformAppWindow()));
-  // Flush any pending events to make sure we start with a clean slate.
-  content::RunAllPendingInMessageLoop();
-
-  content::WebContents* embedder_web_contents =
-      GetFirstShellWindowWebContents();
-  ASSERT_TRUE(embedder_web_contents);
-
-  ExtensionTestMessageListener done_listener(
-      "DoneNavigationTest.PASSED", false);
-  done_listener.AlsoListenForFailureMessage("DoneNavigationTest.FAILED");
-  ExtensionTestMessageListener ready_back_key_listener(
-      "ReadyForBackKey", false);
-  ExtensionTestMessageListener ready_forward_key_listener(
-      "ReadyForForwardKey", false);
-
-  EXPECT_TRUE(content::ExecuteScript(
-                  embedder_web_contents,
-                  "runTest('testBackForwardKeys')"));
-
-  ASSERT_TRUE(ready_back_key_listener.WaitUntilSatisfied());
-  SendBackShortcutToPlatformApp();
-
-  ASSERT_TRUE(ready_forward_key_listener.WaitUntilSatisfied());
-  SendForwardShortcutToPlatformApp();
-
-  ASSERT_TRUE(done_listener.WaitUntilSatisfied());
-}
-
-IN_PROC_BROWSER_TEST_F(WebViewInteractiveTest,
-                       PointerLock_PointerLockLostWithFocus) {
-  TestHelper("testPointerLockLostWithFocus",
-             "DonePointerLockTest.PASSED",
-             "DonePointerLockTest.FAILED",
-             "web_view/pointerlock");
-}
-
diff --git a/chrome/browser/extensions/webstore_installer.cc b/chrome/browser/extensions/webstore_installer.cc
index f9bced0..3d455ad 100644
--- a/chrome/browser/extensions/webstore_installer.cc
+++ b/chrome/browser/extensions/webstore_installer.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/download/download_stats.h"
-#include "chrome/browser/download/download_util.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/install_tracker.h"
 #include "chrome/browser/extensions/install_tracker_factory.h"
@@ -28,7 +27,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/omaha_query_params/omaha_query_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_manager.h"
@@ -42,6 +40,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/common/manifest_constants.h"
 #include "net/base/escape.h"
 #include "url/gurl.h"
 
@@ -85,7 +84,7 @@
 #if defined(OS_CHROMEOS)
   // Do not use drive for extension downloads.
   if (drive::util::IsUnderDriveMountPoint(directory))
-    directory = download_util::GetDefaultDownloadDirectory();
+    directory = DownloadPrefs::GetDefaultDownloadDirectory();
 #endif
 
   // Ensure the download directory exists. TODO(asargent) - make this use
@@ -238,8 +237,7 @@
                  base::Bind(&WebstoreInstaller::StartDownload, this)));
 
   std::string name;
-  if (!approval_->manifest->value()->GetString(extension_manifest_keys::kName,
-                                               &name)) {
+  if (!approval_->manifest->value()->GetString(manifest_keys::kName, &name)) {
     NOTREACHED();
   }
   extensions::InstallTracker* tracker =
@@ -435,9 +433,9 @@
       render_view_host_routing_id ,
       resource_context));
   params->set_file_path(file);
-  if (controller_->GetActiveEntry())
+  if (controller_->GetVisibleEntry())
     params->set_referrer(
-        content::Referrer(controller_->GetActiveEntry()->GetURL(),
+        content::Referrer(controller_->GetVisibleEntry()->GetURL(),
                           WebKit::WebReferrerPolicyDefault));
   params->set_callback(base::Bind(&WebstoreInstaller::OnDownloadStarted, this));
   download_manager->DownloadUrl(params.Pass());
diff --git a/chrome/browser/extensions/webstore_standalone_installer.cc b/chrome/browser/extensions/webstore_standalone_installer.cc
index 17414a2..20f8893 100644
--- a/chrome/browser/extensions/webstore_standalone_installer.cc
+++ b/chrome/browser/extensions/webstore_standalone_installer.cc
@@ -212,6 +212,7 @@
           scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy())));
   approval->skip_post_install_ui = !ShouldShowPostInstallUI();
   approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
+  approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
 
   scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
       profile_,
diff --git a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
index a07c564..953ad08 100644
--- a/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
+++ b/chrome/browser/extensions/webstore_startup_installer_browsertest.cc
@@ -247,10 +247,9 @@
       switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
 
   // Make the profile managed such that no extension installs are allowed.
-  browser()->profile()->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
   ManagedUserService* service =
       ManagedUserServiceFactory::GetForProfile(browser()->profile());
-  service->Init();
+  service->InitForTesting();
 
   ui_test_utils::NavigateToURL(
       browser(), GenerateTestServerUrl(kAppDomain, "install_prohibited.html"));
diff --git a/chrome/browser/extensions/window_controls_browsertest.cc b/chrome/browser/extensions/window_controls_browsertest.cc
deleted file mode 100644
index a8bc465..0000000
--- a/chrome/browser/extensions/window_controls_browsertest.cc
+++ /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.
-
-#include "chrome/browser/extensions/extension_process_manager.h"
-#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_switches.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/test/browser_test_utils.h"
-
-class WindowControlsTest : public extensions::PlatformAppBrowserTest {
- protected:
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    extensions::PlatformAppBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kEnableAppWindowControls);
-  }
-  content::WebContents* GetWebContentsForExtensionWindow(
-      const extensions::Extension* extension);
-};
-
-content::WebContents* WindowControlsTest::GetWebContentsForExtensionWindow(
-    const extensions::Extension* extension) {
-  ExtensionProcessManager* process_manager =
-      extensions::ExtensionSystem::Get(profile())->process_manager();
-
-  // Lookup render view host for background page.
-  const extensions::ExtensionHost* extension_host =
-      process_manager->GetBackgroundHostForExtension(extension->id());
-  content::RenderViewHost* background_view_host =
-      extension_host->render_view_host();
-
-  // Go through all active views, looking for the first window of the extension
-  const ExtensionProcessManager::ViewSet all_views =
-      process_manager->GetAllViews();
-  ExtensionProcessManager::ViewSet::const_iterator it = all_views.begin();
-  for (; it != all_views.end(); ++it) {
-    content::RenderViewHost* host = *it;
-
-    // Filter out views not part of this extension
-    if (process_manager->GetExtensionForRenderViewHost(host) == extension) {
-      // Filter out the background page view
-      if (host != background_view_host) {
-        content::WebContents* web_contents =
-            content::WebContents::FromRenderViewHost(host);
-        return web_contents;
-      }
-    }
-  }
-  return NULL;
-}
-
-IN_PROC_BROWSER_TEST_F(WindowControlsTest, CloseControlWorks) {
-  // Launch app and wait for window to show up
-  ExtensionTestMessageListener window_opened("window-opened", false);
-  const extensions::Extension* extension =
-      LoadAndLaunchPlatformApp("window_controls/buttons");
-  ASSERT_TRUE(window_opened.WaitUntilSatisfied());
-
-  // Find WebContents of window
-  content::WebContents* web_contents =
-      GetWebContentsForExtensionWindow(extension);
-  ASSERT_TRUE(web_contents != NULL);
-
-  // Send a left click on the "Close" button and wait for the close action
-  // to happen.
-  ExtensionTestMessageListener window_closed("window-closed", false);
-
-  // Send mouse click somewhere inside the [x] button
-  const int controlOffset = 25;
-  int x = web_contents->GetView()->GetContainerSize().width() - controlOffset;
-  int y = controlOffset;
-  content::SimulateMouseClickAt(web_contents,
-                                0,
-                                WebKit::WebMouseEvent::ButtonLeft,
-                                gfx::Point(x, y));
-
-  ASSERT_TRUE(window_closed.WaitUntilSatisfied());
-}
diff --git a/chrome/browser/feedback/feedback_data.cc b/chrome/browser/feedback/feedback_data.cc
index b0f3770..cdc2889 100644
--- a/chrome/browser/feedback/feedback_data.cc
+++ b/chrome/browser/feedback/feedback_data.cc
@@ -22,7 +22,6 @@
 
 using content::BrowserThread;
 
-#if defined(OS_CHROMEOS)
 namespace {
 
 const char kMultilineIndicatorString[] = "<multiline>\n";
@@ -31,9 +30,9 @@
 
 const char kTraceFilename[] = "tracing.log\n";
 
-std::string LogsToString(chromeos::SystemLogsResponse* sys_info) {
+std::string LogsToString(FeedbackData::SystemLogsMap* sys_info) {
   std::string syslogs_string;
-  for (chromeos::SystemLogsResponse::const_iterator it = sys_info->begin();
+  for (FeedbackData::SystemLogsMap::const_iterator it = sys_info->begin();
       it != sys_info->end(); ++it) {
     std::string key = it->first;
     std::string value = it->second;
@@ -54,104 +53,62 @@
   return syslogs_string;
 }
 
-void ZipLogs(chromeos::SystemLogsResponse* sys_info,
+void ZipLogs(FeedbackData::SystemLogsMap* sys_info,
              std::string* compressed_logs) {
   DCHECK(compressed_logs);
   std::string logs_string = LogsToString(sys_info);
-  if (!FeedbackUtil::ZipString(logs_string, compressed_logs)) {
+  if (!feedback_util::ZipString(logs_string, compressed_logs)) {
     compressed_logs->clear();
   }
 }
 
 }  // namespace
-#endif // OS_CHROMEOS
+
+// static
+const char FeedbackData::kScreensizeHeightKey[] = "ScreensizeHeight";
+// static
+const char FeedbackData::kScreensizeWidthKey[] = "ScreensizeWidth";
+
 
 FeedbackData::FeedbackData() : profile_(NULL),
-                               feedback_page_data_complete_(false) {
-#if defined(OS_CHROMEOS)
-  sys_info_.reset(NULL);
-  trace_id_ = 0;
-  attached_filedata_.reset(NULL);
-  send_sys_info_ = true;
-  read_attached_file_complete_ = false;
-  syslogs_collection_complete_ = false;
-#endif
+                               feedback_page_data_complete_(false),
+                               syslogs_compression_complete_(false),
+                               report_sent_(false) {
 }
 
 FeedbackData::~FeedbackData() {
 }
 
-bool FeedbackData::DataCollectionComplete() {
-#if defined(OS_CHROMEOS)
-  return (syslogs_collection_complete_ || !send_sys_info_) &&
-      read_attached_file_complete_ &&
+bool FeedbackData::IsDataComplete() {
+  return (syslogs_compression_complete_ || !sys_info_.get()) &&
       feedback_page_data_complete_;
-#else
-  return feedback_page_data_complete_;
-#endif
 }
 void FeedbackData::SendReport() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (DataCollectionComplete())
-    FeedbackUtil::SendReport(this);
+  if (IsDataComplete() && !report_sent_) {
+    report_sent_ = true;
+    feedback_util::SendReport(this);
+  }
 }
 
-void FeedbackData::FeedbackPageDataComplete() {
-#if defined(OS_CHROMEOS)
-  if (trace_id_ != 0) {
-    TracingManager* manager = TracingManager::Get();
-    // When there is a trace id attached to this report, fetch it and attach it
-    // as a file.  In this case, return early and retry this function later.
-    if (manager &&
-        manager->GetTraceData(
-            trace_id_,
-            base::Bind(&FeedbackData::OnGetTraceData, this))) {
-      return;
-    } else {
-      trace_id_ = 0;
-    }
-  }
-  if (attached_filename_.size() &&
-      base::FilePath::IsSeparator(attached_filename_[0]) &&
-      !attached_filedata_.get()) {
-    // Read the attached file and then send this report. The allocated string
-    // will be freed in FeedbackUtil::SendReport.
-    attached_filedata_.reset(new std::string);
-
-    base::FilePath root =
-        ash::Shell::GetInstance()->delegate()->
-            GetCurrentBrowserContext()->GetPath();
-    base::FilePath filepath = root.Append(attached_filename_.substr(1));
-    attached_filename_ = filepath.BaseName().value();
-
-    // Read the file into file_data, then call send report again with the
-    // stripped filename and file data (which will skip this code path).
-    content::BrowserThread::PostTaskAndReply(
-        content::BrowserThread::FILE, FROM_HERE,
-        base::Bind(&FeedbackData::ReadAttachedFile, this, filepath),
-        base::Bind(&FeedbackData::ReadFileComplete, this));
-  } else {
-    read_attached_file_complete_ = true;
-  }
-#endif
+void FeedbackData::OnFeedbackPageDataComplete() {
   feedback_page_data_complete_ = true;
   SendReport();
 }
 
-#if defined(OS_CHROMEOS)
 void FeedbackData::set_sys_info(
-    scoped_ptr<chromeos::SystemLogsResponse> sys_info) {
+    scoped_ptr<FeedbackData::SystemLogsMap> sys_info) {
   if (sys_info.get())
     CompressSyslogs(sys_info.Pass());
 }
 
 void FeedbackData::CompressSyslogs(
-    scoped_ptr<chromeos::SystemLogsResponse> sys_info) {
+    scoped_ptr<FeedbackData::SystemLogsMap> sys_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   // We get the pointer first since base::Passed will nullify the scoper, hence
   // it's not safe to use <scoper>.get() as a parameter to PostTaskAndReply.
-  chromeos::SystemLogsResponse* sys_info_ptr = sys_info.get();
+  FeedbackData::SystemLogsMap* sys_info_ptr = sys_info.get();
   std::string* compressed_logs_ptr = new std::string;
   scoped_ptr<std::string> compressed_logs(compressed_logs_ptr);
   BrowserThread::PostBlockingPoolTaskAndReply(
@@ -159,52 +116,20 @@
       base::Bind(&ZipLogs,
                  sys_info_ptr,
                  compressed_logs_ptr),
-      base::Bind(&FeedbackData::SyslogsComplete,
+      base::Bind(&FeedbackData::OnCompressLogsComplete,
                  this,
                  base::Passed(&sys_info),
                  base::Passed(&compressed_logs)));
 }
 
-void FeedbackData::SyslogsComplete(
-    scoped_ptr<chromeos::SystemLogsResponse> sys_info,
+void FeedbackData::OnCompressLogsComplete(
+    scoped_ptr<FeedbackData::SystemLogsMap> sys_info,
     scoped_ptr<std::string> compressed_logs) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  if (send_sys_info_) {
-    sys_info_ = sys_info.Pass();
-    compressed_logs_ = compressed_logs.Pass();
-    syslogs_collection_complete_ = true;
-    SendReport();
-  }
-}
+  sys_info_ = sys_info.Pass();
+  compressed_logs_ = compressed_logs.Pass();
+  syslogs_compression_complete_ = true;
 
-void FeedbackData::ReadFileComplete() {
-  read_attached_file_complete_ = true;
   SendReport();
 }
-
-void FeedbackData::StartSyslogsCollection() {
-  chromeos::ScrubbedSystemLogsFetcher* fetcher =
-      new chromeos::ScrubbedSystemLogsFetcher();
-  fetcher->Fetch(base::Bind(&FeedbackData::CompressSyslogs, this));
-}
-
-// private
-void FeedbackData::ReadAttachedFile(const base::FilePath& from) {
-  if (!file_util::ReadFileToString(from, attached_filedata_.get())) {
-    if (attached_filedata_.get())
-      attached_filedata_->clear();
-  }
-}
-
-void FeedbackData::OnGetTraceData(
-    scoped_refptr<base::RefCountedString> trace_data) {
-  scoped_ptr<std::string> data(new std::string(trace_data->data()));
-
-  set_attached_filename(kTraceFilename);
-  set_attached_filedata(data.Pass());
-  trace_id_ = 0;
-  FeedbackPageDataComplete();
-}
-
-#endif
diff --git a/chrome/browser/feedback/feedback_data.h b/chrome/browser/feedback/feedback_data.h
index 449035f..9193dac 100644
--- a/chrome/browser/feedback/feedback_data.h
+++ b/chrome/browser/feedback/feedback_data.h
@@ -5,52 +5,42 @@
 #ifndef CHROME_BROWSER_FEEDBACK_FEEDBACK_DATA_H_
 #define CHROME_BROWSER_FEEDBACK_FEEDBACK_DATA_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/ui/webui/screenshot_source.h"
+#include "base/memory/scoped_ptr.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/system_logs/scrubbed_system_logs_fetcher.h"
-#endif
-
-class Profile;
-#if defined(OS_CHROMEOS)
 namespace base {
-class RefCountedString;
+class FilePath;
 }
-#endif
+class Profile;
 
 class FeedbackData : public base::RefCountedThreadSafe<FeedbackData> {
  public:
+  typedef std::map<std::string, std::string> SystemLogsMap;
+
+  static const char kScreensizeHeightKey[];
+  static const char kScreensizeWidthKey[];
+
   FeedbackData();
 
   // Called once we've update all the data from the feedback page.
-  void FeedbackPageDataComplete();
+  void OnFeedbackPageDataComplete();
 
-#if defined(OS_CHROMEOS)
   // Called once we have read our system logs.
-  void CompressSyslogs(scoped_ptr<chromeos::SystemLogsResponse> sys_info);
+  void CompressSyslogs(scoped_ptr<SystemLogsMap> sys_info);
 
   // Called once we have read and compressed our system logs.
-  void SyslogsComplete(scoped_ptr<chromeos::SystemLogsResponse> sys_info,
-                       scoped_ptr<std::string> compressed_logs);
+  void OnCompressLogsComplete(scoped_ptr<SystemLogsMap> sys_info,
+                              scoped_ptr<std::string> compressed_logs);
 
-  // Called once we have read our attached file.
-  void ReadFileComplete();
-
-  // Starts the collection of our system logs. SyslogsComplete is called once
-  // the collection is done.
-  void StartSyslogsCollection();
-#endif
-
-  // Returns true if we've complete collection of data from all our
-  // data sources. At this time this involves the system logs, the attached
-  // file (if needed to be read of the disk) and the rest of the data from
-  // the feedback page.
-  bool DataCollectionComplete();
+  // 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.
+  bool IsDataComplete();
 
   // Sends the feedback report if we have all our data complete.
   void SendReport();
@@ -65,19 +55,13 @@
   const std::string& page_url() const { return page_url_; }
   const std::string& description() const { return description_; }
   const std::string& user_email() const { return user_email_; }
-  ScreenshotDataPtr image() const { return image_; }
+  std::string* image() const { return image_.get(); }
   const std::string attached_filename() const { return attached_filename_; }
   const GURL attached_file_url() const { return attached_file_url_; }
   std::string* attached_filedata() const { return attached_filedata_.get(); }
   const GURL screenshot_url() const { return screenshot_url_; }
-#if defined(OS_CHROMEOS)
-  chromeos::SystemLogsResponse* sys_info() const {
-    return send_sys_info_ ? sys_info_.get() : NULL;
-  }
-  const int trace_id() const { return trace_id_; }
-  const std::string timestamp() const { return timestamp_; }
+  SystemLogsMap* sys_info() const { return sys_info_.get(); }
   std::string* compressed_logs() const { return compressed_logs_.get(); }
-#endif
 
   // Setters
   void set_profile(Profile* profile) { profile_ = profile; }
@@ -91,7 +75,7 @@
   void set_user_email(const std::string& user_email) {
     user_email_ = user_email;
   }
-  void set_image(ScreenshotDataPtr image) { image_ = image; }
+  void set_image(scoped_ptr<std::string> image) { image_ = image.Pass(); }
   void set_attached_filename(const std::string& attached_filename) {
     attached_filename_ = attached_filename;
   }
@@ -100,58 +84,33 @@
   }
   void set_attached_file_url(const GURL& url) { attached_file_url_ = url; }
   void set_screenshot_url(const GURL& url) { screenshot_url_ = url; }
-#if defined(OS_CHROMEOS)
-  void set_sys_info(scoped_ptr<chromeos::SystemLogsResponse> sys_info);
-  void set_trace_id(int trace_id) { trace_id_ = trace_id; }
-  void set_send_sys_info(bool send_sys_info) { send_sys_info_ = send_sys_info; }
-  void set_timestamp(const std::string& timestamp) {
-    timestamp_ = timestamp;
-  }
-#endif
+  void set_sys_info(scoped_ptr<SystemLogsMap> sys_info);
 
  private:
   friend class base::RefCountedThreadSafe<FeedbackData>;
 
   virtual ~FeedbackData();
 
-#if defined(OS_CHROMEOS)
-  void ReadAttachedFile(const base::FilePath& from);
-  void OnGetTraceData(scoped_refptr<base::RefCountedString> trace_data);
-#endif
-
   Profile* profile_;
 
   std::string category_tag_;
   std::string page_url_;
   std::string description_;
   std::string user_email_;
-  ScreenshotDataPtr image_;
+  scoped_ptr<std::string> image_;
   std::string attached_filename_;
   scoped_ptr<std::string> attached_filedata_;
 
   GURL attached_file_url_;
   GURL screenshot_url_;
 
-#if defined(OS_CHROMEOS)
-  // Chromeos specific values for SendReport. Will be deleted in
-  // feedback_util::SendReport once consumed or in SyslogsComplete if
-  // we don't send the logs with the report.
-  scoped_ptr<chromeos::SystemLogsResponse> sys_info_;
-
-  int trace_id_;
-  std::string timestamp_;
+  scoped_ptr<SystemLogsMap> sys_info_;
   scoped_ptr<std::string> compressed_logs_;
 
-  // Flag to indicate whether or not we should send the system information
-  // gathered with the report or not.
-  bool send_sys_info_;
-
-  // Flags to indicate if various pieces of data needed for the report have
-  // been collected yet or are still pending collection.
-  bool read_attached_file_complete_;
-  bool syslogs_collection_complete_;
-#endif
   bool feedback_page_data_complete_;
+  bool syslogs_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 738bf9e..2c82b2c 100644
--- a/chrome/browser/feedback/feedback_util.cc
+++ b/chrome/browser/feedback/feedback_util.cc
@@ -14,14 +14,20 @@
 #include "base/file_version_info.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/windows_version.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h"
+#include "chrome/browser/feedback/feedback_data.h"
 #include "chrome/browser/metrics/variations/variations_http_header_provider.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/metrics/metrics_log_manager.h"
@@ -42,21 +48,65 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
-using content::WebContents;
+#if defined(OS_CHROMEOS)
+#include "ash/shell.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#endif
 
 namespace {
+
 const base::FilePath::CharType kLogsFilename[] =
     FILE_PATH_LITERAL("system_logs.txt");
+
+void DispatchFeedback(Profile* profile, std::string* post_body, int64 delay);
+
+// Check the key/value pair to see if it is one of the screensize, keys. If so,
+// populate the screensize structure with the key.
+bool IsScreensizeInfo(const std::string key,
+                      const std::string value,
+                      gfx::Rect* screen_size) {
+  if (key == FeedbackData::kScreensizeHeightKey) {
+    int height = 0;
+    base::StringToInt(value, &height);
+    screen_size->SetRect(0, 0, screen_size->width(), height);
+    return true;
+  } else if (key == FeedbackData::kScreensizeWidthKey) {
+    int width = 0;
+    base::StringToInt(value, &width);
+    screen_size->SetRect(0, 0, width, screen_size->height());
+    return true;
+  }
+  return false;
 }
 
-namespace chrome {
-const char kAppLauncherCategoryTag[] = "AppLauncher";
-}  // namespace chrome
+GURL GetTargetTabUrl(int session_id, int index) {
+  Browser* browser = chrome::FindBrowserWithID(session_id);
+  // Sanity checks.
+  if (!browser || index >= browser->tab_strip_model()->count())
+    return GURL();
 
-const int kFeedbackVersion = 1;
+  if (index >= 0) {
+    content::WebContents* target_tab =
+        browser->tab_strip_model()->GetWebContentsAt(index);
+    if (target_tab)
+      return target_tab->GetURL();
+  }
 
-const char kReportPhishingUrl[] =
-    "http://www.google.com/safebrowsing/report_phish/";
+  return GURL();
+}
+
+gfx::Rect GetScreenSize(Browser* browser) {
+#if defined(OS_CHROMEOS)
+  // For ChromeOS, don't use the browser window but the root window
+  // instead to grab the screenshot. We want everything on the screen, not
+  // just the current browser.
+  gfx::NativeWindow native_window = ash::Shell::GetPrimaryRootWindow();
+  return gfx::Rect(native_window->bounds());
+#else
+  return gfx::Rect(browser->window()->GetBounds().size());
+#endif
+}
 
 // URL to post bug reports to.
 const char kFeedbackPostUrl[] =
@@ -65,10 +115,6 @@
 const char kProtBufMimeType[] = "application/x-protobuf";
 const char kPngMimeType[] = "image/png";
 
-// Tags we use in product specific data
-const char kChromeVersionTag[] = "CHROME VERSION";
-const char kOsVersionTag[] = "OS VERSION";
-
 const int kHttpPostSuccessNoContent = 204;
 const int kHttpPostFailNoConnection = -1;
 const int kHttpPostFailClientError = 400;
@@ -78,22 +124,17 @@
 const int64 kRetryDelayIncreaseFactor = 2;
 const int64 kRetryDelayLimit = 14400000;  // 4 hours
 
-#if defined(OS_CHROMEOS)
 const size_t kFeedbackMaxLength = 4 * 1024;
 const size_t kFeedbackMaxLineCount = 40;
 
 const char kArbitraryMimeType[] = "application/octet-stream";
 const char kLogsAttachmentName[] = "system_logs.zip";
 
-const char kTimestampTag[] = "TIMESTAMP";
-
 const int kChromeOSProductId = 208;
-#endif
-
 const int kChromeBrowserProductId = 237;
 
 // Simple net::URLFetcherDelegate to clean up URLFetcher on completion.
-class FeedbackUtil::PostCleanup : public net::URLFetcherDelegate {
+class PostCleanup : public net::URLFetcherDelegate {
  public:
   PostCleanup(Profile* profile,
               std::string* post_body,
@@ -117,7 +158,7 @@
 // Don't use the data parameter, instead use the pointer we pass into every
 // post cleanup object - that pointer will be deleted and deleted only on a
 // successful post to the feedback server.
-void FeedbackUtil::PostCleanup::OnURLFetchComplete(
+void PostCleanup::OnURLFetchComplete(
     const net::URLFetcher* source) {
   std::stringstream error_stream;
   int response_code = source->GetResponseCode();
@@ -134,7 +175,7 @@
     } else {
       previous_delay_ = kInitialRetryDelay;
     }
-    FeedbackUtil::DispatchFeedback(profile_, post_body_, previous_delay_);
+    DispatchFeedback(profile_, post_body_, previous_delay_);
 
     // Process the error for debug output
     if (response_code == kHttpPostFailNoConnection) {
@@ -158,41 +199,9 @@
   delete this;
 }
 
-// static
-void FeedbackUtil::SetOSVersion(std::string* os_version) {
-#if defined(OS_WIN)
-  base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
-  base::win::OSInfo::VersionNumber version_number = os_info->version_number();
-  *os_version = base::StringPrintf("%d.%d.%d",
-                                   version_number.major,
-                                   version_number.minor,
-                                   version_number.build);
-  int service_pack = os_info->service_pack().major;
-  if (service_pack > 0)
-    os_version->append(base::StringPrintf("Service Pack %d", service_pack));
-#elif defined(OS_MACOSX)
-  *os_version = base::SysInfo::OperatingSystemVersion();
-#else
-  *os_version = "unknown";
-#endif
-}
-
-// static
-void FeedbackUtil::DispatchFeedback(Profile* profile,
-                                    std::string* post_body,
-                                    int64 delay) {
-  DCHECK(post_body);
-
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&FeedbackUtil::SendFeedback, profile, post_body, delay),
-      base::TimeDelta::FromMilliseconds(delay));
-}
-
-// static
-void FeedbackUtil::SendFeedback(Profile* profile,
-                                std::string* post_body,
-                                int64 previous_delay) {
+void SendFeedback(Profile* profile,
+                  std::string* post_body,
+                  int64 previous_delay) {
   DCHECK(post_body);
 
   GURL post_url;
@@ -205,7 +214,7 @@
 
   net::URLFetcher* fetcher = net::URLFetcher::Create(
       post_url, net::URLFetcher::POST,
-      new FeedbackUtil::PostCleanup(profile, post_body, previous_delay));
+      new PostCleanup(profile, post_body, previous_delay));
   fetcher->SetRequestContext(profile->GetRequestContext());
   fetcher->SetLoadFlags(
       net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
@@ -219,11 +228,18 @@
   fetcher->Start();
 }
 
+void DispatchFeedback(Profile* profile, std::string* post_body, int64 delay) {
+  DCHECK(post_body);
 
-// static
-void FeedbackUtil::AddFeedbackData(
-    userfeedback::ExtensionSubmit* feedback_data,
-    const std::string& key, const std::string& value) {
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&SendFeedback, profile, post_body, delay),
+      base::TimeDelta::FromMilliseconds(delay));
+}
+
+
+void AddFeedbackData(userfeedback::ExtensionSubmit* feedback_data,
+                     const std::string& key, const std::string& value) {
   // Don't bother with empty keys or values
   if (key == "" || value == "") return;
   // Create log_value object and add it to the web_data object
@@ -234,8 +250,7 @@
   *(web_data->add_product_specific_data()) = log_value;
 }
 
-#if defined(OS_CHROMEOS)
-bool FeedbackUtil::ValidFeedbackSize(const std::string& content) {
+bool ValidFeedbackSize(const std::string& content) {
   if (content.length() > kFeedbackMaxLength)
     return false;
   const size_t line_count = std::count(content.begin(), content.end(), '\n');
@@ -243,92 +258,70 @@
     return false;
   return true;
 }
-#endif
 
-// static
-void FeedbackUtil::SendReport(scoped_refptr<FeedbackData> data) {
+}  // namespace
+
+namespace chrome {
+
+const char kAppLauncherCategoryTag[] = "AppLauncher";
+
+void ShowFeedbackPage(Browser* browser,
+                    const std::string& description_template,
+                    const std::string& category_tag) {
+  DCHECK(browser);
+
+  // Get the current browser's screensize and send it with the feedback request
+  // event - this browser may have changed or even been closed by the time that
+  // feedback is sent.
+  gfx::Rect screen_size = GetScreenSize(browser);
+  GURL page_url = GetTargetTabUrl(
+      browser->session_id().id(), browser->tab_strip_model()->active_index());
+
+  extensions::FeedbackPrivateAPI* api =
+      extensions::FeedbackPrivateAPI::GetFactoryInstance()->GetForProfile(
+          browser->profile());
+
+  api->RequestFeedback(description_template,
+                       category_tag,
+                       page_url,
+                       screen_size);
+}
+
+}  // namespace chrome
+
+namespace feedback_util {
+
+void SendReport(scoped_refptr<FeedbackData> data) {
   if (!data.get()) {
-    LOG(ERROR) << "FeedbackUtil::SendReport called with NULL data!";
+    LOG(ERROR) << "SendReport called with NULL data!";
     NOTREACHED();
     return;
   }
 
-  // Create google feedback protocol buffer objects
   userfeedback::ExtensionSubmit feedback_data;
-  // type id set to 0, unused field but needs to be initialized to 0
+  // Unused field, needs to be 0 though.
   feedback_data.set_type_id(0);
 
   userfeedback::CommonData* common_data = feedback_data.mutable_common_data();
-  userfeedback::WebData* web_data = feedback_data.mutable_web_data();
-
-  // Set our user agent.
-  userfeedback::Navigator* navigator = web_data->mutable_navigator();
-  navigator->set_user_agent(content::GetUserAgent(GURL()));
-
-  // Set GAIA id to 0. We're not using gaia id's for recording
-  // use feedback - we're using the e-mail field, allows users to
-  // submit feedback from incognito mode and specify any mail id
-  // they wish
+  // We're not using gaia ids, we're using the e-mail field instead.
   common_data->set_gaia_id(0);
-
-  // Add the user e-mail to the feedback object
   common_data->set_user_email(data->user_email());
-
-  // Add the description to the feedback object
   common_data->set_description(data->description());
 
-  // Add the language
   std::string chrome_locale = g_browser_process->GetApplicationLocale();
   common_data->set_source_description_language(chrome_locale);
 
-  // Set the url
+  userfeedback::WebData* web_data = feedback_data.mutable_web_data();
   web_data->set_url(data->page_url());
+  web_data->mutable_navigator()->set_user_agent(content::GetUserAgent(GURL()));
 
-  // Add the Chrome version
-  chrome::VersionInfo version_info;
-  if (version_info.is_valid()) {
-    std::string chrome_version = version_info.Name() + " - " +
-        version_info.Version() +
-        " (" + version_info.LastChange() + ")";
-    AddFeedbackData(&feedback_data, std::string(kChromeVersionTag),
-                    chrome_version);
-  }
-
-  // We don't need the OS version for ChromeOS since we get it in
-  // CHROMEOS_RELEASE_VERSION from /etc/lsb-release
-#if !defined(OS_CHROMEOS)
-  // Add OS version (eg, for WinXP SP2: "5.1.2600 Service Pack 2").
-  std::string os_version;
-  SetOSVersion(&os_version);
-  AddFeedbackData(&feedback_data, std::string(kOsVersionTag), os_version);
-#endif
-
-  // Include the page image if we have one.
-  if (data->image().get() && data->image()->size()) {
-    userfeedback::PostedScreenshot screenshot;
-    screenshot.set_mime_type(kPngMimeType);
-    // Set the dimensions of the screenshot
-    userfeedback::Dimensions dimensions;
-    gfx::Rect& screen_size = GetScreenshotSize();
-    dimensions.set_width(static_cast<float>(screen_size.width()));
-    dimensions.set_height(static_cast<float>(screen_size.height()));
-    *(screenshot.mutable_dimensions()) = dimensions;
-
-    int image_data_size = data->image()->size();
-    char* image_data = reinterpret_cast<char*>(&(data->image()->front()));
-    screenshot.set_binary_content(std::string(image_data, image_data_size));
-
-    // Set the screenshot object in feedback
-    *(feedback_data.mutable_screenshot()) = screenshot;
-  }
-
-#if defined(OS_CHROMEOS)
+  gfx::Rect screen_size;
   if (data->sys_info()) {
-    // Add the product specific data
-    for (chromeos::SystemLogsResponse::const_iterator i =
+    for (FeedbackData::SystemLogsMap::const_iterator i =
         data->sys_info()->begin(); i != data->sys_info()->end(); ++i) {
-      if (ValidFeedbackSize(i->second)) {
-        AddFeedbackData(&feedback_data, i->first, i->second);
+      if (!IsScreensizeInfo(i->first, i->second, &screen_size)) {
+        if (ValidFeedbackSize(i->second))
+          AddFeedbackData(&feedback_data, i->first, i->second);
       }
     }
 
@@ -341,29 +334,44 @@
     }
   }
 
-  if (data->timestamp() != "")
-    AddFeedbackData(&feedback_data, std::string(kTimestampTag),
-                    data->timestamp());
-
-  if (data->attached_filename() != "" &&
+  if (!data->attached_filename().empty() &&
       data->attached_filedata() &&
-      data->attached_filedata()->size()) {
+      !data->attached_filedata()->empty()) {
     userfeedback::ProductSpecificBinaryData attached_file;
     attached_file.set_mime_type(kArbitraryMimeType);
-    attached_file.set_name(data->attached_filename());
+    // We need to use the UTF8Unsafe methods here to accomodate Windows, which
+    // uses wide strings to store filepaths.
+    std::string name = base::FilePath::FromUTF8Unsafe(
+        data->attached_filename()).BaseName().AsUTF8Unsafe();
+    attached_file.set_name(name);
     attached_file.set_data(*data->attached_filedata());
     *(feedback_data.add_product_specific_binary_data()) = attached_file;
   }
-#endif
 
-  // Set our category tag if we have one
+  // NOTE: Screenshot needs to be processed after system info since we'll get
+  // the screenshot dimensions from system info.
+  if (data->image() && data->image()->size()) {
+    userfeedback::PostedScreenshot screenshot;
+    screenshot.set_mime_type(kPngMimeType);
+
+    // Set the dimensions of the screenshot
+    userfeedback::Dimensions dimensions;
+    dimensions.set_width(static_cast<float>(screen_size.width()));
+    dimensions.set_height(static_cast<float>(screen_size.height()));
+
+    *(screenshot.mutable_dimensions()) = dimensions;
+    screenshot.set_binary_content(*data->image());
+
+    *(feedback_data.mutable_screenshot()) = screenshot;
+  }
+
   if (data->category_tag().size())
     feedback_data.set_bucket(data->category_tag());
 
-  // Set our Chrome specific data
+  // Set whether we're reporting from ChromeOS or Chrome on another platform.
   userfeedback::ChromeData chrome_data;
-  chrome_data.set_chrome_platform(
 #if defined(OS_CHROMEOS)
+  chrome_data.set_chrome_platform(
       userfeedback::ChromeData_ChromePlatform_CHROME_OS);
   userfeedback::ChromeOsData chrome_os_data;
   chrome_os_data.set_category(
@@ -371,6 +379,7 @@
   *(chrome_data.mutable_chrome_os_data()) = chrome_os_data;
   feedback_data.set_product_id(kChromeOSProductId);
 #else
+  chrome_data.set_chrome_platform(
       userfeedback::ChromeData_ChromePlatform_CHROME_BROWSER);
   userfeedback::ChromeBrowserData chrome_browser_data;
   chrome_browser_data.set_category(
@@ -381,60 +390,15 @@
 
   *(feedback_data.mutable_chrome_data()) = chrome_data;
 
-  // Serialize our report to a string pointer we can pass around
+  // This pointer will eventually get deleted by the PostCleanup class, after
+  // we've either managed to successfully upload the report or died trying.
   std::string* post_body = new std::string;
   feedback_data.SerializeToString(post_body);
 
-  // We have the body of our POST, so send it off to the server with 0 delay
   DispatchFeedback(data->profile(), post_body, 0);
 }
 
-#if defined(FULL_SAFE_BROWSING)
-// static
-void FeedbackUtil::ReportPhishing(WebContents* current_tab,
-                                  const std::string& phishing_url) {
-  current_tab->GetController().LoadURL(
-      safe_browsing_util::GeneratePhishingReportUrl(
-          kReportPhishingUrl, phishing_url,
-          false /* not client-side detection */),
-      content::Referrer(),
-      content::PAGE_TRANSITION_LINK,
-      std::string());
-}
-#endif
-
-static std::vector<unsigned char>* screenshot_png = NULL;
-static gfx::Rect* screenshot_size = NULL;
-
-// static
-std::vector<unsigned char>* FeedbackUtil::GetScreenshotPng() {
-  if (screenshot_png == NULL)
-    screenshot_png = new std::vector<unsigned char>;
-  return screenshot_png;
-}
-
-// static
-void FeedbackUtil::ClearScreenshotPng() {
-  if (screenshot_png)
-    screenshot_png->clear();
-}
-
-// static
-gfx::Rect& FeedbackUtil::GetScreenshotSize() {
-  if (screenshot_size == NULL)
-    screenshot_size = new gfx::Rect();
-  return *screenshot_size;
-}
-
-// static
-void FeedbackUtil::SetScreenshotSize(const gfx::Rect& rect) {
-  gfx::Rect& screen_size = GetScreenshotSize();
-  screen_size = rect;
-}
-
-// static
-bool FeedbackUtil::ZipString(const std::string& logs,
-                             std::string* compressed_logs) {
+bool ZipString(const std::string& logs, std::string* compressed_logs) {
   base::FilePath temp_path;
   base::FilePath zip_file;
 
@@ -456,3 +420,5 @@
 
   return true;
 }
+
+}  // namespace feedback_util
diff --git a/chrome/browser/feedback/feedback_util.h b/chrome/browser/feedback/feedback_util.h
index 7849186..a921e55 100644
--- a/chrome/browser/feedback/feedback_util.h
+++ b/chrome/browser/feedback/feedback_util.h
@@ -9,12 +9,11 @@
 
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
-#include "chrome/browser/feedback/feedback_data.h"
+#include "base/memory/ref_counted.h"
 #include "chrome/browser/feedback/proto/common.pb.h"
 #include "chrome/browser/feedback/proto/dom.pb.h"
 #include "chrome/browser/feedback/proto/extension.pb.h"
 #include "chrome/browser/feedback/proto/math.pb.h"
-#include "chrome/browser/ui/webui/screenshot_source.h"
 #include "ui/gfx/rect.h"
 
 #if defined(OS_MACOSX)
@@ -23,6 +22,7 @@
 #include "base/win/windows_version.h"
 #endif
 
+class FeedbackData;
 class Profile;
 
 namespace content {
@@ -33,69 +33,11 @@
 extern const char kAppLauncherCategoryTag[];
 }  // namespace chrome
 
-class FeedbackUtil {
- public:
+namespace feedback_util {
 
-#if defined(OS_MACOSX)
-  enum BugType {
-    PAGE_WONT_LOAD = 0,
-    PAGE_LOOKS_ODD,
-    PHISHING_PAGE,
-    CANT_SIGN_IN,
-    CHROME_MISBEHAVES,
-    SOMETHING_MISSING,
-    BROWSER_CRASH,
-    OTHER_PROBLEM
-  };
-#endif
+  void SendReport(scoped_refptr<FeedbackData> data);
+  bool ZipString(const std::string& logs, std::string* compressed_logs);
 
-
-  // SetOSVersion copies the maj.minor.build + servicePack_string
-  // into a string. We currently have:
-  //   base::win::GetVersion returns WinVersion, which is just
-  //     an enum of 2000, XP, 2003, or VISTA. Not enough detail for
-  //     bug reports.
-  //   base::SysInfo::OperatingSystemVersion returns an std::string
-  //     but doesn't include the build or service pack. That function
-  //     is probably the right one to extend, but will require changing
-  //     all the call sites or making it a wrapper around another util.
-  static void SetOSVersion(std::string *os_version);
-
-  // Send the feedback report after the specified delay
-  static void DispatchFeedback(Profile* profile,
-                               std::string* feedback_data,
-                               int64 delay);
-
-  // Generates bug report data.
-  static void SendReport(scoped_refptr<FeedbackData> data);
-  // Redirects the user to Google's phishing reporting page.
-  static void ReportPhishing(content::WebContents* current_tab,
-                             const std::string& phishing_url);
-  // Maintains a single vector of bytes to store the last screenshot taken.
-  static std::vector<unsigned char>* GetScreenshotPng();
-  static void ClearScreenshotPng();
-  static void SetScreenshotSize(const gfx::Rect& rect);
-  static gfx::Rect& GetScreenshotSize();
-  static bool ZipString(const std::string& logs, std::string* compressed_logs);
-
-  class PostCleanup;
-
- private:
-  // Add a key value pair to the feedback object
-  static void AddFeedbackData(
-      userfeedback::ExtensionSubmit* feedback_data,
-      const std::string& key, const std::string& value);
-
-  // Send the feedback report
-  static void SendFeedback(Profile* profile,
-                           std::string* feedback_data,
-                           int64 previous_delay);
-
-#if defined(OS_CHROMEOS)
-  static bool ValidFeedbackSize(const std::string& content);
-#endif
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(FeedbackUtil);
-};
+}  // namespace feedback_util
 
 #endif  // CHROME_BROWSER_FEEDBACK_FEEDBACK_UTIL_H_
diff --git a/chrome/browser/feedback/tracing_manager.cc b/chrome/browser/feedback/tracing_manager.cc
index 3a8a4cc..6bb4460 100644
--- a/chrome/browser/feedback/tracing_manager.cc
+++ b/chrome/browser/feedback/tracing_manager.cc
@@ -94,7 +94,7 @@
     return;
 
   std::string output_val;
-  FeedbackUtil::ZipString(data_, &output_val);
+  feedback_util::ZipString(data_, &output_val);
 
   scoped_refptr<base::RefCountedString> output(
       base::RefCountedString::TakeString(&output_val));
diff --git a/chrome/browser/first_run/try_chrome_dialog_view.cc b/chrome/browser/first_run/try_chrome_dialog_view.cc
index 0df3e46..c8ef28c 100644
--- a/chrome/browser/first_run/try_chrome_dialog_view.cc
+++ b/chrome/browser/first_run/try_chrome_dialog_view.cc
@@ -86,15 +86,11 @@
   icon->SetImage(rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_32).ToImageSkia());
   gfx::Size icon_size = icon->GetPreferredSize();
 
-  popup_ = new views::Widget;
-  if (!popup_) {
-    NOTREACHED();
-    return DIALOG_ERROR;
-  }
   // An approximate window size. After Layout() we'll get better bounds.
   views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
   params.can_activate = true;
   params.bounds = gfx::Rect(310, 200);
+  popup_ = new views::Widget;
   popup_->Init(params);
 
   views::View* root_view = popup_->GetRootView();
@@ -103,10 +99,6 @@
       views::Background::CreateSolidBackground(0xfc, 0xfc, 0xfc));
 
   views::GridLayout* layout = views::GridLayout::CreatePanel(root_view);
-  if (!layout) {
-    NOTREACHED();
-    return DIALOG_ERROR;
-  }
   root_view->SetLayoutManager(layout);
   views::ColumnSet* columns;
 
diff --git a/chrome/browser/fullscreen_win.cc b/chrome/browser/fullscreen_win.cc
index dd61b3e..23a2eab 100644
--- a/chrome/browser/fullscreen_win.cc
+++ b/chrome/browser/fullscreen_win.cc
@@ -8,6 +8,7 @@
 #include <shellapi.h>
 
 #include "base/logging.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 
 #if defined(USE_ASH)
@@ -61,7 +62,7 @@
   if (!monitor)
     return false;
   MONITORINFO monitor_info = { sizeof(monitor_info) };
-  if (!::GetMonitorInfo(monitor, &monitor_info))
+  if (!base::win::GetMonitorInfoWrapper(monitor, &monitor_info))
     return false;
 
   // It should be the main monitor.
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index 23dd587..a1bec46 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -198,7 +198,7 @@
     navigation_completed_ = true;
   }
 
-  // We're either waiting for just the inforbar, or for both a javascript
+  // We're either waiting for just the infobar, or for both a javascript
   // prompt and response.
   if ((wait_for_infobar_ && infobar_) ||
       (navigation_completed_ && !javascript_response_.empty()))
@@ -264,16 +264,37 @@
   double fake_latitude() const { return fake_latitude_; }
   double fake_longitude() const { return fake_longitude_; }
 
+  // Initializes the test server and navigates to the initial url.
   bool Initialize(InitializationOptions options) WARN_UNUSED_RESULT;
+
+  // Loads the specified number of iframes.
   void LoadIFrames(int number_iframes);
+
+  // Start watching for geolocation notifications. If |wait_for_infobar| is
+  // true, wait for the infobar to be displayed. Otherwise wait for a javascript
+  // response.
   void AddGeolocationWatch(bool wait_for_infobar);
+
+  // Checks that no errors have been received in javascript, and checks that the
+  // position most recently received in javascript matches |latitude| and
+  // |longitude|.
   void CheckGeoposition(double latitude, double longitude);
+
+  // For |requesting_url| if |allowed| is true accept the infobar. Otherwise
+  // cancel it.
   void SetInfoBarResponse(const GURL& requesting_url, bool allowed);
+
+  // Executes |function| in |web_contents| and checks that the return value
+  // matches |expected|.
   void CheckStringValueFromJavascriptForTab(const std::string& expected,
                                             const std::string& function,
                                             WebContents* web_contents);
+
+  // Executes |function| and checks that the return value matches |expected|.
   void CheckStringValueFromJavascript(const std::string& expected,
                                       const std::string& function);
+
+  // Sets a new position and sends a notification with the new position.
   void NotifyGeoposition(double latitude, double longitude);
 
  private:
@@ -456,13 +477,7 @@
   CheckStringValueFromJavascript("1", "geoGetLastError()");
 }
 
-// http://crbug.com/44589. Hangs on Mac, crashes on Windows
-#if defined(OS_MACOSX) || defined(OS_WIN)
-#define MAYBE_NoInfobarForSecondTab DISABLED_NoInfobarForSecondTab
-#else
-#define MAYBE_NoInfobarForSecondTab NoInfobarForSecondTab
-#endif
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForSecondTab) {
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForSecondTab) {
   ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
   AddGeolocationWatch(true);
   SetInfoBarResponse(current_url(), true);
@@ -475,13 +490,7 @@
   CheckGeoposition(fake_latitude(), fake_longitude());
 }
 
-// http://crbug.com/44589. Hangs on Mac, crashes on Windows
-#if defined(OS_MACOSX) || defined(OS_WIN)
-#define MAYBE_NoInfobarForDeniedOrigin DISABLED_NoInfobarForDeniedOrigin
-#else
-#define MAYBE_NoInfobarForDeniedOrigin NoInfobarForDeniedOrigin
-#endif
-IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, MAYBE_NoInfobarForDeniedOrigin) {
+IN_PROC_BROWSER_TEST_F(GeolocationBrowserTest, NoInfobarForDeniedOrigin) {
   ASSERT_TRUE(Initialize(INITIALIZATION_NONE));
   current_browser()->profile()->GetHostContentSettingsMap()->SetContentSetting(
       ContentSettingsPattern::FromURLNoWildcard(current_url()),
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate.cc b/chrome/browser/geolocation/geolocation_infobar_delegate.cc
index 4e9c37d..c14594f 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate.cc
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate.cc
@@ -69,6 +69,10 @@
                                update_content_setting, allowed);
 }
 
+void GeolocationInfoBarDelegate::InfoBarDismissed() {
+  SetPermission(false, false);
+}
+
 int GeolocationInfoBarDelegate::GetIconID() const {
   return IDR_GEOLOCATION_INFOBAR_ICON;
 }
diff --git a/chrome/browser/geolocation/geolocation_infobar_delegate.h b/chrome/browser/geolocation/geolocation_infobar_delegate.h
index 93a6ab7..6dc4b45 100644
--- a/chrome/browser/geolocation/geolocation_infobar_delegate.h
+++ b/chrome/browser/geolocation/geolocation_infobar_delegate.h
@@ -44,6 +44,7 @@
 
  private:
   // ConfirmInfoBarDelegate:
+  virtual void InfoBarDismissed() OVERRIDE;
   virtual int GetIconID() const OVERRIDE;
   virtual Type GetInfoBarType() const OVERRIDE;
   virtual bool ShouldExpireInternal(
diff --git a/chrome/browser/google/google_util.cc b/chrome/browser/google/google_util.cc
index d14ec5a..99e4b7a 100644
--- a/chrome/browser/google/google_util.cc
+++ b/chrome/browser/google/google_util.cc
@@ -186,7 +186,7 @@
 bool IsGoogleDomainUrl(const GURL& url,
                        SubdomainPermission subdomain_permission,
                        PortPermission port_permission) {
-  return url.is_valid() && (url.SchemeIs("http") || url.SchemeIs("https")) &&
+  return url.is_valid() && url.SchemeIsHTTPOrHTTPS() &&
       (url.port().empty() || (port_permission == ALLOW_NON_STANDARD_PORTS)) &&
       google_util::IsGoogleHostname(url.host(), subdomain_permission);
 }
diff --git a/chrome/browser/google_apis/auth_service.cc b/chrome/browser/google_apis/auth_service.cc
index 481fc8a..2534062 100644
--- a/chrome/browser/google_apis/auth_service.cc
+++ b/chrome/browser/google_apis/auth_service.cc
@@ -216,8 +216,7 @@
   OnHandleRefreshToken(true);
 }
 
-void AuthService::OnRefreshTokenRevoked(const std::string& account_id,
-                                        const GoogleServiceAuthError& error) {
+void AuthService::OnRefreshTokenRevoked(const std::string& account_id) {
   OnHandleRefreshToken(false);
 }
 
diff --git a/chrome/browser/google_apis/auth_service.h b/chrome/browser/google_apis/auth_service.h
index a93e017..ce22550 100644
--- a/chrome/browser/google_apis/auth_service.h
+++ b/chrome/browser/google_apis/auth_service.h
@@ -50,9 +50,7 @@
 
   // Overridden from OAuth2TokenService::Observer:
   virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
-  virtual void OnRefreshTokenRevoked(
-      const std::string& account_id,
-      const GoogleServiceAuthError& error) OVERRIDE;
+  virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE;
 
  private:
   // Called when the state of the refresh token changes.
diff --git a/chrome/browser/google_apis/drive_api_requests.cc b/chrome/browser/google_apis/drive_api_requests.cc
index 58ffbb0..7fb418c 100644
--- a/chrome/browser/google_apis/drive_api_requests.cc
+++ b/chrome/browser/google_apis/drive_api_requests.cc
@@ -238,51 +238,6 @@
   return true;
 }
 
-//=========================== RenameResourceRequest ==========================
-
-RenameResourceRequest::RenameResourceRequest(
-    RequestSender* sender,
-    const DriveApiUrlGenerator& url_generator,
-    const std::string& resource_id,
-    const std::string& new_title,
-    const EntryActionCallback& callback)
-    : EntryActionRequest(sender, callback),
-      url_generator_(url_generator),
-      resource_id_(resource_id),
-      new_title_(new_title) {
-  DCHECK(!callback.is_null());
-}
-
-RenameResourceRequest::~RenameResourceRequest() {}
-
-net::URLFetcher::RequestType RenameResourceRequest::GetRequestType() const {
-  return net::URLFetcher::PATCH;
-}
-
-std::vector<std::string>
-RenameResourceRequest::GetExtraRequestHeaders() const {
-  std::vector<std::string> headers;
-  headers.push_back(util::kIfMatchAllHeader);
-  return headers;
-}
-
-GURL RenameResourceRequest::GetURL() const {
-  return url_generator_.GetFileUrl(resource_id_);
-}
-
-bool RenameResourceRequest::GetContentData(std::string* upload_content_type,
-                                           std::string* upload_content) {
-  *upload_content_type = kContentTypeApplicationJson;
-
-  base::DictionaryValue root;
-  root.SetString("title", new_title_);
-  base::JSONWriter::Write(&root, upload_content);
-
-  DVLOG(1) << "RenameResource data: " << *upload_content_type << ", ["
-           << *upload_content << "]";
-  return true;
-}
-
 //=========================== TouchResourceRequest ===========================
 
 TouchResourceRequest::TouchResourceRequest(
@@ -387,6 +342,64 @@
   return true;
 }
 
+//=========================== MoveResourceRequest ============================
+
+MoveResourceRequest::MoveResourceRequest(
+    RequestSender* sender,
+    const DriveApiUrlGenerator& url_generator,
+    const std::string& resource_id,
+    const std::string& parent_resource_id,
+    const std::string& new_title,
+    const FileResourceCallback& callback)
+    : GetDataRequest(sender,
+                     base::Bind(&ParseJsonAndRun<FileResource>, callback)),
+      url_generator_(url_generator),
+      resource_id_(resource_id),
+      parent_resource_id_(parent_resource_id),
+      new_title_(new_title) {
+  DCHECK(!callback.is_null());
+}
+
+MoveResourceRequest::~MoveResourceRequest() {
+}
+
+net::URLFetcher::RequestType MoveResourceRequest::GetRequestType() const {
+  return net::URLFetcher::PATCH;
+}
+
+std::vector<std::string> MoveResourceRequest::GetExtraRequestHeaders() const {
+  std::vector<std::string> headers;
+  headers.push_back(util::kIfMatchAllHeader);
+  return headers;
+}
+
+GURL MoveResourceRequest::GetURL() const {
+  return url_generator_.GetFileUrl(resource_id_);
+}
+
+bool MoveResourceRequest::GetContentData(std::string* upload_content_type,
+                                         std::string* upload_content) {
+  *upload_content_type = kContentTypeApplicationJson;
+
+  base::DictionaryValue root;
+  root.SetString("title", new_title_);
+
+  if (!parent_resource_id_.empty()) {
+    // Set the parent resource (destination directory) of the new resource.
+    base::ListValue* parents = new base::ListValue;
+    root.Set("parents", parents);
+    base::DictionaryValue* parent_value = new base::DictionaryValue;
+    parents->Append(parent_value);
+    parent_value->SetString("id", parent_resource_id_);
+  }
+
+  base::JSONWriter::Write(&root, upload_content);
+
+  DVLOG(1) << "MoveResource data: " << *upload_content_type << ", ["
+           << *upload_content << "]";
+  return true;
+}
+
 //=========================== TrashResourceRequest ===========================
 
 TrashResourceRequest::TrashResourceRequest(
diff --git a/chrome/browser/google_apis/drive_api_requests.h b/chrome/browser/google_apis/drive_api_requests.h
index 9367b1f..e6128ea 100644
--- a/chrome/browser/google_apis/drive_api_requests.h
+++ b/chrome/browser/google_apis/drive_api_requests.h
@@ -199,36 +199,6 @@
   DISALLOW_COPY_AND_ASSIGN(CreateDirectoryRequest);
 };
 
-//=========================== RenameResourceRequest ==========================
-
-// This class performs the request for renaming a document/file/directory.
-class RenameResourceRequest : public EntryActionRequest {
- public:
-  // |callback| must not be null.
-  RenameResourceRequest(RequestSender* sender,
-                        const DriveApiUrlGenerator& url_generator,
-                        const std::string& resource_id,
-                        const std::string& new_title,
-                        const EntryActionCallback& callback);
-  virtual ~RenameResourceRequest();
-
- protected:
-  // UrlFetchRequestBase overrides.
-  virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE;
-  virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE;
-  virtual GURL GetURL() const OVERRIDE;
-  virtual bool GetContentData(std::string* upload_content_type,
-                              std::string* upload_content) OVERRIDE;
-
- private:
-  const DriveApiUrlGenerator url_generator_;
-
-  const std::string resource_id_;
-  const std::string new_title_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenameResourceRequest);
-};
-
 //=========================== TouchResourceRequest ===========================
 
 // This class performs the request to touch a document/file/directory.
@@ -301,6 +271,43 @@
   DISALLOW_COPY_AND_ASSIGN(CopyResourceRequest);
 };
 
+//=========================== MoveResourceRequest ============================
+
+// This class performs the request for moving a resource.
+//
+// Moves the resource with |resource_id| into a directory with
+// |parent_resource_id| and renames it as |new_title|.
+// |parent_resource_id| can be empty. In the case, the resource will still be
+// in the current directory.
+//
+// This request uses "Files: patch" request on Drive API v2. See also:
+// https://developers.google.com/drive/v2/reference/files/patch
+class MoveResourceRequest : public GetDataRequest {
+ public:
+  // Upon completion, |callback| will be called. |callback| must not be null.
+  MoveResourceRequest(RequestSender* sender,
+                      const DriveApiUrlGenerator& url_generator,
+                      const std::string& resource_id,
+                      const std::string& parent_resource_id,
+                      const std::string& new_title,
+                      const FileResourceCallback& callback);
+  virtual ~MoveResourceRequest();
+
+ protected:
+  virtual net::URLFetcher::RequestType GetRequestType() const OVERRIDE;
+  virtual std::vector<std::string> GetExtraRequestHeaders() const OVERRIDE;
+  virtual GURL GetURL() const OVERRIDE;
+  virtual bool GetContentData(std::string* upload_content_type,
+                              std::string* upload_content) OVERRIDE;
+ private:
+  const DriveApiUrlGenerator url_generator_;
+  const std::string resource_id_;
+  const std::string parent_resource_id_;
+  const std::string new_title_;
+
+  DISALLOW_COPY_AND_ASSIGN(MoveResourceRequest);
+};
+
 //=========================== TrashResourceRequest ===========================
 
 // This class performs the request for trashing a resource.
diff --git a/chrome/browser/google_apis/drive_api_requests_unittest.cc b/chrome/browser/google_apis/drive_api_requests_unittest.cc
index bdba3d8..ea71b78 100644
--- a/chrome/browser/google_apis/drive_api_requests_unittest.cc
+++ b/chrome/browser/google_apis/drive_api_requests_unittest.cc
@@ -562,39 +562,6 @@
   EXPECT_EQ(expected->parents().size(), file_resource->parents().size());
 }
 
-TEST_F(DriveApiRequestsTest, RenameResourceRequest) {
-  // Set an expected data file containing the directory's entry data.
-  // It'd be returned if we rename a directory.
-  expected_data_file_path_ =
-      test_util::GetTestFilePath("drive/directory_entry.json");
-
-  GDataErrorCode error = GDATA_OTHER_ERROR;
-
-  // Create "new directory" in the root directory.
-  {
-    base::RunLoop run_loop;
-    drive::RenameResourceRequest* request =
-        new drive::RenameResourceRequest(
-            request_sender_.get(),
-            *url_generator_,
-            "resource_id",
-            "new title",
-            test_util::CreateQuitCallback(
-                &run_loop,
-                test_util::CreateCopyResultCallback(&error)));
-    request_sender_->StartRequestWithRetry(request);
-    run_loop.Run();
-  }
-
-  EXPECT_EQ(HTTP_SUCCESS, error);
-  EXPECT_EQ(net::test_server::METHOD_PATCH, http_request_.method);
-  EXPECT_EQ("/drive/v2/files/resource_id", http_request_.relative_url);
-  EXPECT_EQ("application/json", http_request_.headers["Content-Type"]);
-
-  EXPECT_TRUE(http_request_.has_content);
-  EXPECT_EQ("{\"title\":\"new title\"}", http_request_.content);
-}
-
 TEST_F(DriveApiRequestsTest, TouchResourceRequest) {
   // Set an expected data file containing the directory's entry data.
   // It'd be returned if we rename a directory.
@@ -710,6 +677,81 @@
   EXPECT_TRUE(file_resource);
 }
 
+TEST_F(DriveApiRequestsTest, MoveResourceRequest) {
+  // Set an expected data file containing the dummy file entry data.
+  // It'd be returned if we move a file.
+  expected_data_file_path_ =
+      test_util::GetTestFilePath("drive/file_entry.json");
+
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<FileResource> file_resource;
+
+  // Move the file to the directory |parent_resource_id| with new name
+  // "new title".
+  {
+    base::RunLoop run_loop;
+    drive::MoveResourceRequest* request =
+        new drive::MoveResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "resource_id",
+            "parent_resource_id",
+            "new title",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &file_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  EXPECT_EQ(net::test_server::METHOD_PATCH, http_request_.method);
+  EXPECT_EQ("/drive/v2/files/resource_id", http_request_.relative_url);
+  EXPECT_EQ("application/json", http_request_.headers["Content-Type"]);
+
+  EXPECT_TRUE(http_request_.has_content);
+  EXPECT_EQ(
+      "{\"parents\":[{\"id\":\"parent_resource_id\"}],\"title\":\"new title\"}",
+      http_request_.content);
+  EXPECT_TRUE(file_resource);
+}
+
+TEST_F(DriveApiRequestsTest, MoveResourceRequest_EmptyParentResourceId) {
+  // Set an expected data file containing the directory's entry data.
+  // It'd be returned if we rename a directory.
+  expected_data_file_path_ =
+      test_util::GetTestFilePath("drive/file_entry.json");
+
+  GDataErrorCode error = GDATA_OTHER_ERROR;
+  scoped_ptr<FileResource> file_resource;
+
+  // Rename the file to "new title," but keep the parent directory as is.
+  {
+    base::RunLoop run_loop;
+    drive::MoveResourceRequest* request =
+        new drive::MoveResourceRequest(
+            request_sender_.get(),
+            *url_generator_,
+            "resource_id",
+            std::string(),
+            "new title",
+            test_util::CreateQuitCallback(
+                &run_loop,
+                test_util::CreateCopyResultCallback(&error, &file_resource)));
+    request_sender_->StartRequestWithRetry(request);
+    run_loop.Run();
+  }
+
+  EXPECT_EQ(HTTP_SUCCESS, error);
+  EXPECT_EQ(net::test_server::METHOD_PATCH, http_request_.method);
+  EXPECT_EQ("/drive/v2/files/resource_id", http_request_.relative_url);
+  EXPECT_EQ("application/json", http_request_.headers["Content-Type"]);
+
+  EXPECT_TRUE(http_request_.has_content);
+  EXPECT_EQ("{\"title\":\"new title\"}", http_request_.content);
+  EXPECT_TRUE(file_resource);
+}
+
 TEST_F(DriveApiRequestsTest, TrashResourceRequest) {
   // Set data for the expected result. Directory entry should be returned
   // if the trashing entry is a directory, so using it here should be fine.
diff --git a/chrome/browser/guestview/webview/webview_constants.cc b/chrome/browser/guestview/webview/webview_constants.cc
index c2f2f2b..1a98be9 100644
--- a/chrome/browser/guestview/webview/webview_constants.cc
+++ b/chrome/browser/guestview/webview/webview_constants.cc
@@ -20,13 +20,17 @@
 const char kEventNewWindow[] = "webview.onNewWindow";
 const char kEventPermissionRequest[] = "webview.onPermissionRequest";
 const char kEventResponsive[] = "webview.onResponsive";
+const char kEventSizeChanged[] = "webview.onSizeChanged";
 const char kEventUnresponsive[] = "webview.onUnresponsive";
 
 // Parameters/properties on events.
 const char kLevel[] = "level";
 const char kLine[] = "line";
 const char kMessage[] = "message";
+const char kNewHeight[] = "newHeight";
 const char kNewURL[] = "newUrl";
+const char kNewWidth[] = "newWidth";
+const char kOldHeight[] = "oldHeight";
 const char kOldURL[] = "oldUrl";
 const char kPermission[] = "permission";
 const char kPermissionTypeDialog[] = "dialog";
@@ -35,6 +39,7 @@
 const char kPermissionTypeMedia[] = "media";
 const char kPermissionTypeNewWindow[] = "newwindow";
 const char kPermissionTypePointerLock[] = "pointerLock";
+const char kOldWidth[] = "oldWidth";
 const char kProcessId[] = "processId";
 const char kReason[] = "reason";
 const char kRequestId[] = "requestId";
diff --git a/chrome/browser/guestview/webview/webview_constants.h b/chrome/browser/guestview/webview/webview_constants.h
index e479758..8af163e 100644
--- a/chrome/browser/guestview/webview/webview_constants.h
+++ b/chrome/browser/guestview/webview/webview_constants.h
@@ -23,13 +23,17 @@
 extern const char kEventNewWindow[];
 extern const char kEventPermissionRequest[];
 extern const char kEventResponsive[];
+extern const char kEventSizeChanged[];
 extern const char kEventUnresponsive[];
 
 // Parameters/properties on events.
 extern const char kLevel[];
 extern const char kLine[];
 extern const char kMessage[];
+extern const char kNewHeight[];
 extern const char kNewURL[];
+extern const char kNewWidth[];
+extern const char kOldHeight[];
 extern const char kOldURL[];
 extern const char kPermission[];
 extern const char kPermissionTypeDialog[];
@@ -38,6 +42,7 @@
 extern const char kPermissionTypeMedia[];
 extern const char kPermissionTypeNewWindow[];
 extern const char kPermissionTypePointerLock[];
+extern const char kOldWidth[];
 extern const char kProcessId[];
 extern const char kReason[];
 extern const char kRequestId[];
diff --git a/chrome/browser/guestview/webview/webview_guest.cc b/chrome/browser/guestview/webview/webview_guest.cc
index e989278..7900c66 100644
--- a/chrome/browser/guestview/webview/webview_guest.cc
+++ b/chrome/browser/guestview/webview/webview_guest.cc
@@ -16,6 +16,7 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/resource_request_details.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/result_codes.h"
@@ -182,6 +183,16 @@
   return false;
 }
 
+void WebViewGuest::LoadAbort(bool is_top_level,
+                             const GURL& url,
+                             const std::string& error_type) {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  args->SetBoolean(guestview::kIsTopLevel, is_top_level);
+  args->SetString(guestview::kUrl, url.spec());
+  args->SetString(guestview::kReason, error_type);
+  DispatchEvent(new GuestView::Event(webview::kEventLoadAbort, args.Pass()));
+}
+
 // TODO(fsamuel): Find a reliable way to test the 'responsive' and
 // 'unresponsive' events.
 void WebViewGuest::RendererResponsive() {
@@ -294,6 +305,26 @@
     base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false);
 }
 
+bool WebViewGuest::ClearData(const base::Time remove_since,
+                             uint32 removal_mask,
+                             const base::Closure& callback) {
+  content::StoragePartition* partition =
+      content::BrowserContext::GetStoragePartition(
+          web_contents()->GetBrowserContext(),
+          web_contents()->GetSiteInstance());
+
+  if (!partition)
+    return false;
+
+  partition->ClearDataForRange(
+      removal_mask,
+      content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
+      remove_since,
+      base::Time::Now(),
+      callback);
+  return true;
+}
+
 WebViewGuest::~WebViewGuest() {
 }
 
@@ -325,12 +356,7 @@
   // Translate the |error_code| into an error string.
   std::string error_type;
   RemoveChars(net::ErrorToString(error_code), "net::", &error_type);
-
-  scoped_ptr<DictionaryValue> args(new DictionaryValue());
-  args->SetBoolean(guestview::kIsTopLevel, is_main_frame);
-  args->SetString(guestview::kUrl, validated_url.spec());
-  args->SetString(guestview::kReason, error_type);
-  DispatchEvent(new GuestView::Event(webview::kEventLoadAbort, args.Pass()));
+  LoadAbort(is_main_frame, validated_url, error_type);
 }
 
 void WebViewGuest::DidStartProvisionalLoadForFrame(
@@ -406,3 +432,13 @@
           web_contents->GetRenderProcessHost()->GetID(),
           web_contents->GetRoutingID()));
 }
+
+void WebViewGuest::SizeChanged(const gfx::Size& old_size,
+                               const gfx::Size& new_size) {
+  scoped_ptr<DictionaryValue> args(new DictionaryValue());
+  args->SetInteger(webview::kOldHeight, old_size.height());
+  args->SetInteger(webview::kOldWidth, old_size.width());
+  args->SetInteger(webview::kNewHeight, new_size.height());
+  args->SetInteger(webview::kNewWidth, new_size.width());
+  DispatchEvent(new GuestView::Event(webview::kEventSizeChanged, args.Pass()));
+}
diff --git a/chrome/browser/guestview/webview/webview_guest.h b/chrome/browser/guestview/webview/webview_guest.h
index 94f85f9..c967ae0 100644
--- a/chrome/browser/guestview/webview/webview_guest.h
+++ b/chrome/browser/guestview/webview/webview_guest.h
@@ -47,12 +47,17 @@
   virtual void GuestProcessGone(base::TerminationStatus status) OVERRIDE;
   virtual bool HandleKeyboardEvent(
       const content::NativeWebKeyboardEvent& event) OVERRIDE;
+  virtual void LoadAbort(bool is_top_level,
+                         const GURL& url,
+                         const std::string& error_type) OVERRIDE;
   virtual void RendererResponsive() OVERRIDE;
   virtual void RendererUnresponsive() OVERRIDE;
   virtual bool RequestPermission(
       BrowserPluginPermissionType permission_type,
       const base::DictionaryValue& request_info,
       const PermissionResponseCallback& callback) OVERRIDE;
+  virtual void SizeChanged(const gfx::Size& old_size, const gfx::Size& new_size)
+      OVERRIDE;
 
   // NotificationObserver implementation.
   virtual void Observe(int type,
@@ -79,6 +84,14 @@
   // Kill the guest process.
   void Terminate();
 
+  // Clears data in the storage partition of this guest.
+  //
+  // Partition data that are newer than |removal_since| will be removed.
+  // |removal_mask| corresponds to bitmask in StoragePartition::RemoveDataMask.
+  bool ClearData(const base::Time remove_since,
+                 uint32 removal_mask,
+                 const base::Closure& callback);
+
   extensions::ScriptExecutor* script_executor() {
     return script_executor_.get();
   }
diff --git a/chrome/browser/history/android/android_provider_backend_unittest.cc b/chrome/browser/history/android/android_provider_backend_unittest.cc
index 830f74c..c828167 100644
--- a/chrome/browser/history/android/android_provider_backend_unittest.cc
+++ b/chrome/browser/history/android/android_provider_backend_unittest.cc
@@ -76,7 +76,6 @@
     }
   }
   virtual void DBLoaded(int backend_id) OVERRIDE {}
-  virtual void StartTopSitesMigration(int backend_id) OVERRIDE {}
   virtual void NotifyVisitDBObserversOnAddVisit(
       const history::BriefVisitInfo& info) OVERRIDE {}
 
diff --git a/chrome/browser/history/expire_history_backend.cc b/chrome/browser/history/expire_history_backend.cc
index 370a62b..aa7ede3 100644
--- a/chrome/browser/history/expire_history_backend.cc
+++ b/chrome/browser/history/expire_history_backend.cc
@@ -421,8 +421,6 @@
 
     // Delete stuff that references this URL.
     if (thumb_db_) {
-      thumb_db_->DeleteThumbnail(url_row.id());
-
       // Collect shared information.
       std::vector<IconMapping> icon_mappings;
       if (thumb_db_->GetIconMappingsForPageURL(url_row.url(), &icon_mappings)) {
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 4e69a4b..7cdecc5 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -564,7 +564,7 @@
 
   // Compute the file names.
   base::FilePath history_name = history_dir_.Append(chrome::kHistoryFilename);
-  base::FilePath thumbnail_name = GetThumbnailFileName();
+  base::FilePath thumbnail_name = GetFaviconsFileName();
   base::FilePath archived_name = GetArchivedFileName();
 
   // Delete the old index database files which are no longer used.
@@ -619,11 +619,11 @@
   }
 
   // Thumbnail database.
+  // TODO(shess): "thumbnail database" these days only stores
+  // favicons.  Thumbnails are stored in "top sites".  Consider
+  // renaming "thumbnail" references to "favicons" or something of the
+  // sort.
   thumbnail_db_.reset(new ThumbnailDatabase());
-  if (!db_->GetNeedsThumbnailMigration()) {
-    // No convertion needed - use new filename right away.
-    thumbnail_name = GetFaviconsFileName();
-  }
   if (thumbnail_db_->Init(thumbnail_name,
                           history_publisher_.get(),
                           db_.get()) != sql::INIT_OK) {
@@ -636,11 +636,6 @@
     thumbnail_db_.reset();
   }
 
-  if (db_->GetNeedsThumbnailMigration()) {
-    VLOG(1) << "Starting TopSites migration";
-    delegate_->StartTopSitesMigration(id_);
-  }
-
   // Archived database.
   if (db_->needs_version_17_migration()) {
     // See needs_version_17_migration() decl for more. In this case, we want
@@ -1651,89 +1646,6 @@
   provider->ExecuteWithDB(this, db_.get(), params);
 }
 
-void HistoryBackend::SetPageThumbnail(
-    const GURL& url,
-    const gfx::Image* thumbnail,
-    const ThumbnailScore& score) {
-  if (!db_ || !thumbnail_db_)
-    return;
-
-  URLRow url_row;
-  URLID url_id = db_->GetRowForURL(url, &url_row);
-  if (url_id) {
-    thumbnail_db_->SetPageThumbnail(url, url_id, thumbnail, score,
-                                    url_row.last_visit());
-  }
-
-  ScheduleCommit();
-}
-
-void HistoryBackend::GetPageThumbnail(
-    scoped_refptr<GetPageThumbnailRequest> request,
-    const GURL& page_url) {
-  if (request->canceled())
-    return;
-
-  scoped_refptr<base::RefCountedBytes> data;
-  GetPageThumbnailDirectly(page_url, &data);
-
-  request->ForwardResult(request->handle(), data);
-}
-
-void HistoryBackend::GetPageThumbnailDirectly(
-    const GURL& page_url,
-    scoped_refptr<base::RefCountedBytes>* data) {
-  if (thumbnail_db_) {
-    *data = new base::RefCountedBytes;
-
-    // Time the result.
-    TimeTicks beginning_time = TimeTicks::Now();
-
-    history::RedirectList redirects;
-    URLID url_id;
-    bool success = false;
-
-    // If there are some redirects, try to get a thumbnail from the last
-    // redirect destination.
-    if (GetMostRecentRedirectsFrom(page_url, &redirects) &&
-        !redirects.empty()) {
-      if ((url_id = db_->GetRowForURL(redirects.back(), NULL)))
-        success = thumbnail_db_->GetPageThumbnail(url_id, &(*data)->data());
-    }
-
-    // If we don't have a thumbnail from redirects, try the URL directly.
-    if (!success) {
-      if ((url_id = db_->GetRowForURL(page_url, NULL)))
-        success = thumbnail_db_->GetPageThumbnail(url_id, &(*data)->data());
-    }
-
-    // In this rare case, we start to mine the older redirect sessions
-    // from the visit table to try to find a thumbnail.
-    if (!success) {
-      success = GetThumbnailFromOlderRedirect(page_url, &(*data)->data());
-    }
-
-    if (!success)
-      *data = NULL;  // This will tell the callback there was an error.
-
-    UMA_HISTOGRAM_TIMES("History.GetPageThumbnail",
-                        TimeTicks::Now() - beginning_time);
-  }
-}
-
-void HistoryBackend::MigrateThumbnailsDatabase() {
-  // If there is no History DB, we can't record that the migration was done.
-  // It will be recorded on the next run.
-  if (db_) {
-    // If there is no thumbnail DB, we can still record a successful migration.
-    if (thumbnail_db_) {
-      thumbnail_db_->RenameAndDropThumbnails(GetThumbnailFileName(),
-                                             GetFaviconsFileName());
-    }
-    db_->ThumbnailMigrationDone();
-  }
-}
-
 void HistoryBackend::DeleteFTSIndexDatabases() {
   // Find files on disk matching the text databases file pattern so we can
   // quickly test for and delete them.
@@ -1751,37 +1663,6 @@
                        num_databases_deleted);
 }
 
-bool HistoryBackend::GetThumbnailFromOlderRedirect(
-    const GURL& page_url,
-    std::vector<unsigned char>* data) {
-  // Look at a few previous visit sessions.
-  VisitVector older_sessions;
-  URLID page_url_id = db_->GetRowForURL(page_url, NULL);
-  static const int kVisitsToSearchForThumbnail = 4;
-  db_->GetMostRecentVisitsForURL(
-      page_url_id, kVisitsToSearchForThumbnail, &older_sessions);
-
-  // Iterate across all those previous visits, and see if any of the
-  // final destinations of those redirect chains have a good thumbnail
-  // for us.
-  bool success = false;
-  for (VisitVector::const_iterator it = older_sessions.begin();
-       !success && it != older_sessions.end(); ++it) {
-    history::RedirectList redirects;
-    if (it->visit_id) {
-      GetRedirectsFromSpecificVisit(it->visit_id, &redirects);
-
-      if (!redirects.empty()) {
-        URLID url_id;
-        if ((url_id = db_->GetRowForURL(redirects.back(), NULL)))
-          success = thumbnail_db_->GetPageThumbnail(url_id, data);
-      }
-    }
-  }
-
-  return success;
-}
-
 void HistoryBackend::GetFavicons(
     const std::vector<GURL>& icon_urls,
     int icon_types,
@@ -2825,7 +2706,7 @@
 
   // Clear thumbnail and favicon history. The favicons for the given URLs will
   // be kept.
-  if (!ClearAllThumbnailHistory(&kept_urls)) {
+  if (!ClearAllThumbnailHistory(kept_urls)) {
     LOG(ERROR) << "Thumbnail history could not be cleared";
     // We continue in this error case. If the user wants to delete their
     // history, we should delete as much as we can.
@@ -2865,63 +2746,44 @@
   BroadcastNotifications(chrome::NOTIFICATION_HISTORY_URLS_DELETED, details);
 }
 
-bool HistoryBackend::ClearAllThumbnailHistory(URLRows* kept_urls) {
+bool HistoryBackend::ClearAllThumbnailHistory(const URLRows& kept_urls) {
   if (!thumbnail_db_) {
     // When we have no reference to the thumbnail database, maybe there was an
     // error opening it. In this case, we just try to blow it away to try to
     // fix the error if it exists. This may fail, in which case either the
     // file doesn't exist or there's no more we can do.
+    sql::Connection::Delete(GetFaviconsFileName());
+
+    // Older version of the database.
     sql::Connection::Delete(GetThumbnailFileName());
     return true;
   }
 
-  // Create duplicate icon_mapping, favicon, and favicon_bitmaps tables, this
-  // is where the favicons we want to keep will be stored.
-  if (!thumbnail_db_->InitTemporaryTables())
-    return false;
-
-  // This maps existing favicon IDs to the ones in the temporary table.
-  typedef std::map<chrome::FaviconID, chrome::FaviconID> FaviconMap;
-  FaviconMap copied_favicons;
-
-  // Copy all unique favicons to the temporary table, and update all the
-  // URLs to have the new IDs.
-  for (URLRows::iterator i = kept_urls->begin(); i != kept_urls->end(); ++i) {
-    std::vector<IconMapping> icon_mappings;
-    if (!thumbnail_db_->GetIconMappingsForPageURL(i->url(), &icon_mappings))
-      continue;
-
-    for (std::vector<IconMapping>::iterator m = icon_mappings.begin();
-         m != icon_mappings.end(); ++m) {
-      chrome::FaviconID old_id = m->icon_id;
-      chrome::FaviconID new_id;
-      FaviconMap::const_iterator found = copied_favicons.find(old_id);
-      if (found == copied_favicons.end()) {
-        new_id = thumbnail_db_->CopyFaviconAndFaviconBitmapsToTemporaryTables(
-            old_id);
-        copied_favicons[old_id] = new_id;
-      } else {
-        // We already encountered a URL that used this favicon, use the ID we
-        // previously got.
-        new_id = found->second;
-      }
-      // Add Icon mapping, and we don't care wheteher it suceeded or not.
-      thumbnail_db_->AddToTemporaryIconMappingTable(i->url(), new_id);
-    }
+  // Urls to retain mappings for.
+  std::vector<GURL> urls_to_keep;
+  for (URLRows::const_iterator i = kept_urls.begin();
+       i != kept_urls.end(); ++i) {
+    urls_to_keep.push_back(i->url());
   }
+
+  // Isolate from any long-running transaction.
+  thumbnail_db_->CommitTransaction();
+  thumbnail_db_->BeginTransaction();
+
+  // TODO(shess): If this fails, perhaps the database should be razed
+  // or deleted.
+  if (!thumbnail_db_->RetainDataForPageUrls(urls_to_keep)) {
+    thumbnail_db_->RollbackTransaction();
+    thumbnail_db_->BeginTransaction();
+    return false;
+  }
+
 #if defined(OS_ANDROID)
   // TODO (michaelbai): Add the unit test once AndroidProviderBackend is
   // avaliable in HistoryBackend.
   db_->ClearAndroidURLRows();
 #endif
 
-  // Drop original favicon_bitmaps, favicons, and icon mapping tables and
-  // replace them with the duplicate tables. Recreate the other tables. This
-  // will make the database consistent again.
-  thumbnail_db_->CommitTemporaryTables();
-
-  thumbnail_db_->RecreateThumbnailTable();
-
   // Vacuum to remove all the pages associated with the dropped tables. There
   // must be no transaction open on the table when we do this. We assume that
   // our long-running transaction is open, so we complete it and start it again.
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index fd92878..de64e5c 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -99,9 +99,6 @@
     // Invoked when the backend has finished loading the db.
     virtual void DBLoaded(int backend_id) = 0;
 
-    // Tell TopSites to start reading thumbnails from the ThumbnailsDB.
-    virtual void StartTopSitesMigration(int backend_id) = 0;
-
     virtual void NotifyVisitDBObserversOnAddVisit(
         const history::BriefVisitInfo& info) = 0;
   };
@@ -231,28 +228,6 @@
   bool GetMostRecentRedirectsTo(const GURL& url,
                                 history::RedirectList* redirects);
 
-  // Thumbnails ----------------------------------------------------------------
-
-  void SetPageThumbnail(const GURL& url,
-                        const gfx::Image* thumbnail,
-                        const ThumbnailScore& score);
-
-  // Retrieves a thumbnail, passing it across thread boundaries
-  // via. the included callback.
-  void GetPageThumbnail(scoped_refptr<GetPageThumbnailRequest> request,
-                        const GURL& page_url);
-
-  // Backend implementation of GetPageThumbnail. Unlike
-  // GetPageThumbnail(), this method has way to transport data across
-  // thread boundaries.
-  //
-  // Exposed for testing reasons.
-  void GetPageThumbnailDirectly(
-      const GURL& page_url,
-      scoped_refptr<base::RefCountedBytes>* data);
-
-  void MigrateThumbnailsDatabase();
-
   // Favicon -------------------------------------------------------------------
 
   void GetFavicons(const std::vector<GURL>& icon_urls,
@@ -563,13 +538,12 @@
   friend class ::TestingProfile;
 
   // Computes the name of the specified database on disk.
+  base::FilePath GetArchivedFileName() const;
   base::FilePath GetThumbnailFileName() const;
 
   // Returns the name of the Favicons database. This is the new name
   // of the Thumbnails database.
-  // See ThumbnailDatabase::RenameAndDropThumbnails.
   base::FilePath GetFaviconsFileName() const;
-  base::FilePath GetArchivedFileName() const;
 
 #if defined(OS_ANDROID)
   // Returns the name of android cache database.
@@ -629,16 +603,6 @@
   // Update the visit_duration information in visits table.
   void UpdateVisitDuration(VisitID visit_id, const base::Time end_ts);
 
-  // Thumbnail Helpers ---------------------------------------------------------
-
-  // When a simple GetMostRecentRedirectsFrom() fails, this method is
-  // called which searches the last N visit sessions instead of just
-  // the current one. Returns true and puts thumbnail data in |data|
-  // if a proper thumbnail was found. Returns false otherwise. Assumes
-  // that this HistoryBackend object has been Init()ed successfully.
-  bool GetThumbnailFromOlderRedirect(
-      const GURL& page_url, std::vector<unsigned char>* data);
-
   // Querying ------------------------------------------------------------------
 
   // Backends for QueryHistory. *Basic() handles queries that are not
@@ -824,9 +788,8 @@
 
   // Given a vector of all URLs that we will keep, removes all thumbnails
   // referenced by any URL, and also all favicons that aren't used by those
-  // URLs. The favicon IDs will change, so this will update the url rows in the
-  // vector to reference the new IDs.
-  bool ClearAllThumbnailHistory(URLRows* kept_urls);
+  // URLs.
+  bool ClearAllThumbnailHistory(const URLRows& kept_urls);
 
   // Deletes all information in the history database, except for the supplied
   // set of URLs in the URL table (these should correspond to the bookmarked
diff --git a/chrome/browser/history/history_backend_unittest.cc b/chrome/browser/history/history_backend_unittest.cc
index 8bb0111..c450a8a 100644
--- a/chrome/browser/history/history_backend_unittest.cc
+++ b/chrome/browser/history/history_backend_unittest.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 "chrome/browser/history/history_backend.h"
+
 #include <algorithm>
 #include <set>
 #include <vector>
@@ -9,21 +11,18 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
-#include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
-#include "base/platform_file.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "chrome/browser/history/history_backend.h"
 #include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -34,17 +33,12 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/importer/imported_favicon_usage.h"
-#include "chrome/common/thumbnail_score.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chrome/tools/profiles/thumbnail-inl.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/codec/jpeg_codec.h"
-#include "ui/gfx/image/image.h"
 #include "url/gurl.h"
 
 using base::Time;
@@ -57,10 +51,6 @@
 
 namespace {
 
-// data we'll put into the thumbnail database
-static const unsigned char blob1[] =
-    "12346102356120394751634516591348710478123649165419234519234512349134";
-
 static const gfx::Size kTinySize = gfx::Size(10, 10);
 static const gfx::Size kSmallSize = gfx::Size(16, 16);
 static const gfx::Size kLargeSize = gfx::Size(32, 32);
@@ -96,7 +86,6 @@
   virtual void BroadcastNotifications(int type,
                                       HistoryDetails* details) OVERRIDE;
   virtual void DBLoaded(int backend_id) OVERRIDE;
-  virtual void StartTopSitesMigration(int backend_id) OVERRIDE;
   virtual void NotifyVisitDBObserversOnAddVisit(
       const BriefVisitInfo& info) OVERRIDE {}
 
@@ -438,10 +427,6 @@
   test_->loaded_ = true;
 }
 
-void HistoryBackendTestDelegate::StartTopSitesMigration(int backend_id) {
-  test_->backend_->MigrateThumbnailsDatabase();
-}
-
 // http://crbug.com/114287
 #if defined(OS_WIN)
 #define MAYBE_Loaded DISABLED_Loaded
@@ -517,24 +502,6 @@
   URLRow outrow1;
   EXPECT_TRUE(mem_backend_->db_->GetRowForURL(row1.url(), NULL));
 
-  // Add thumbnails for each page. The |Images| take ownership of SkBitmap
-  // created from decoding the images.
-  ThumbnailScore score(0.25, true, true);
-  scoped_ptr<SkBitmap> google_bitmap(
-      gfx::JPEGCodec::Decode(kGoogleThumbnail, sizeof(kGoogleThumbnail)));
-
-  gfx::Image google_image = gfx::Image::CreateFrom1xBitmap(*google_bitmap);
-
-  Time time;
-  GURL gurl;
-  backend_->thumbnail_db_->SetPageThumbnail(gurl, row1_id, &google_image,
-                                            score, time);
-  scoped_ptr<SkBitmap> weewar_bitmap(
-     gfx::JPEGCodec::Decode(kWeewarThumbnail, sizeof(kWeewarThumbnail)));
-  gfx::Image weewar_image = gfx::Image::CreateFrom1xBitmap(*weewar_bitmap);
-  backend_->thumbnail_db_->SetPageThumbnail(gurl, row2_id, &weewar_image,
-                                            score, time);
-
   // Star row1.
   bookmark_model_.AddURL(
       bookmark_model_.bookmark_bar_node(), 0, string16(), row1.url());
@@ -558,12 +525,6 @@
   backend_->db_->GetAllVisitsInRange(Time(), Time(), 0, &all_visits);
   ASSERT_EQ(0U, all_visits.size());
 
-  // All thumbnails should be deleted.
-  std::vector<unsigned char> out_data;
-  EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(outrow1.id(),
-                                                         &out_data));
-  EXPECT_FALSE(backend_->thumbnail_db_->GetPageThumbnail(row2_id, &out_data));
-
   // We should have a favicon and favicon bitmaps for the first URL only. We
   // look them up by favicon URL since the IDs may have changed.
   chrome::FaviconID out_favicon1 = backend_->thumbnail_db_->
diff --git a/chrome/browser/history/history_database.cc b/chrome/browser/history/history_database.cc
index ca2d4ab..1f26b7e 100644
--- a/chrome/browser/history/history_database.cc
+++ b/chrome/browser/history/history_database.cc
@@ -31,10 +31,6 @@
 const int kCompatibleVersionNumber = 16;
 const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
 
-// Key in the meta table used to determine if we need to migrate thumbnails out
-// of history.
-const char kNeedsThumbnailMigrationKey[] = "needs_thumbnail_migration";
-
 }  // namespace
 
 HistoryDatabase::HistoryDatabase()
@@ -245,16 +241,6 @@
   return db_.Raze();
 }
 
-void HistoryDatabase::ThumbnailMigrationDone() {
-  meta_table_.SetValue(kNeedsThumbnailMigrationKey, 0);
-}
-
-bool HistoryDatabase::GetNeedsThumbnailMigration() {
-  int value = 0;
-  return (meta_table_.GetValue(kNeedsThumbnailMigrationKey, &value) &&
-          value != 0);
-}
-
 bool HistoryDatabase::SetSegmentID(VisitID visit_id, SegmentID segment_id) {
   sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE,
       "UPDATE visits SET segment_id = ? WHERE id = ?"));
@@ -365,9 +351,7 @@
   if (cur_version == 19) {
     cur_version++;
     meta_table_.SetVersionNumber(cur_version);
-    // Set a key indicating we need to migrate thumbnails. When successfull the
-    // key is removed (ThumbnailMigrationDone).
-    meta_table_.SetValue(kNeedsThumbnailMigrationKey, 1);
+    // This was the thumbnail migration.  Obsolete.
   }
 
   if (cur_version == 20) {
diff --git a/chrome/browser/history/history_database.h b/chrome/browser/history/history_database.h
index 5aac5ba..7c631cf 100644
--- a/chrome/browser/history/history_database.h
+++ b/chrome/browser/history/history_database.h
@@ -149,12 +149,6 @@
     return needs_version_17_migration_;
   }
 
-  // Marks the database as no longer needing migration.
-  void ThumbnailMigrationDone();
-
-  // Returns true if thumbnails needs to be migrated.
-  bool GetNeedsThumbnailMigration();
-
   // Visit table functions ----------------------------------------------------
 
   // Update the segment id of a visit. Return true on success.
diff --git a/chrome/browser/history/history_marshaling.h b/chrome/browser/history/history_marshaling.h
index 47703ee..a3204da 100644
--- a/chrome/browser/history/history_marshaling.h
+++ b/chrome/browser/history/history_marshaling.h
@@ -50,11 +50,6 @@
                            history::FilteredURLList>
     QueryFilteredURLsRequest;
 
-// Thumbnails -----------------------------------------------------------------
-
-typedef CancelableRequest<HistoryService::ThumbnailDataCallback>
-    GetPageThumbnailRequest;
-
 // Segment usage --------------------------------------------------------------
 
 typedef CancelableRequest1<HistoryService::SegmentQueryCallback,
diff --git a/chrome/browser/history/history_service.cc b/chrome/browser/history/history_service.cc
index 644dc85..0ad19e3 100644
--- a/chrome/browser/history/history_service.cc
+++ b/chrome/browser/history/history_service.cc
@@ -175,13 +175,6 @@
                    backend_id));
   }
 
-  virtual void StartTopSitesMigration(int backend_id) OVERRIDE {
-    service_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&HistoryService::StartTopSitesMigration,
-                   history_service_, backend_id));
-  }
-
   virtual void NotifyVisitDBObserversOnAddVisit(
       const history::BriefVisitInfo& info) OVERRIDE {
     service_task_runner_->PostTask(
@@ -206,8 +199,7 @@
       backend_loaded_(false),
       current_backend_id_(-1),
       bookmark_service_(NULL),
-      no_db_(false),
-      needs_top_sites_migration_(false) {
+      no_db_(false) {
 }
 
 HistoryService::HistoryService(Profile* profile)
@@ -219,8 +211,7 @@
       backend_loaded_(false),
       current_backend_id_(-1),
       bookmark_service_(NULL),
-      no_db_(false),
-      needs_top_sites_migration_(false) {
+      no_db_(false) {
   DCHECK(profile_);
   registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
                  content::Source<Profile>(profile_));
@@ -593,15 +584,6 @@
                     &HistoryBackend::AddPagesWithDetails, info, visit_source);
 }
 
-HistoryService::Handle HistoryService::GetPageThumbnail(
-    const GURL& page_url,
-    CancelableRequestConsumerBase* consumer,
-    const ThumbnailDataCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return Schedule(PRIORITY_NORMAL, &HistoryBackend::GetPageThumbnail, consumer,
-                  new history::GetPageThumbnailRequest(callback), page_url);
-}
-
 CancelableTaskTracker::TaskId HistoryService::GetFavicons(
     const std::vector<GURL>& icon_urls,
     int icon_types,
@@ -1002,7 +984,7 @@
   // TODO: We should allow kChromeUIScheme URLs if they have been explicitly
   // typed.  Right now, however, these are marked as typed even when triggered
   // by a shortcut or menu action.
-  if (url.SchemeIs(chrome::kJavaScriptScheme) ||
+  if (url.SchemeIs(content::kJavaScriptScheme) ||
       url.SchemeIs(chrome::kChromeDevToolsScheme) ||
       url.SchemeIs(chrome::kChromeUIScheme) ||
       url.SchemeIs(content::kViewSourceScheme) ||
@@ -1228,12 +1210,6 @@
       chrome::NOTIFICATION_HISTORY_LOADED,
       content::Source<Profile>(profile_),
       content::Details<HistoryService>(this));
-  if (thread_ && profile_) {
-    // We don't want to force creation of TopSites.
-    history::TopSites* ts = profile_->GetTopSitesWithoutCreating();
-    if (ts)
-      ts->HistoryLoaded();
-  }
 }
 
 bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) {
@@ -1242,27 +1218,6 @@
   return db && (db->GetRowForURL(url, url_row) != 0);
 }
 
-void HistoryService::StartTopSitesMigration(int backend_id) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!history_backend_.get() || current_backend_id_ != backend_id) {
-    DVLOG(1) << "Message from obsolete backend";
-    return;
-  }
-  needs_top_sites_migration_ = true;
-  if (thread_ && profile_) {
-    // We don't want to force creation of TopSites.
-    history::TopSites* ts = profile_->GetTopSitesWithoutCreating();
-    if (ts)
-      ts->MigrateFromHistory();
-  }
-}
-
-void HistoryService::OnTopSitesReady() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  ScheduleAndForget(PRIORITY_NORMAL,
-                    &HistoryBackend::MigrateThumbnailsDatabase);
-}
-
 void HistoryService::AddVisitDatabaseObserver(
     history::VisitDatabaseObserver* observer) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chrome/browser/history/history_service.h b/chrome/browser/history/history_service.h
index 1662571..f8d383b 100644
--- a/chrome/browser/history/history_service.h
+++ b/chrome/browser/history/history_service.h
@@ -367,22 +367,6 @@
       CancelableRequestConsumerBase* consumer,
       const QueryFilteredURLsCallback& callback);
 
-  // Thumbnails ----------------------------------------------------------------
-
-  // Implemented by consumers to get thumbnail data. Called when a request for
-  // the thumbnail data is complete. Once this callback is made, the request
-  // will be completed and no other calls will be made for that handle.
-  //
-  // This function will be called even on error conditions or if there is no
-  // thumbnail for that page. In these cases, the data pointer will be NULL.
-  typedef base::Callback<void(Handle, scoped_refptr<base::RefCountedBytes>)>
-      ThumbnailDataCallback;
-
-  // Requests a page thumbnail. See ThumbnailDataCallback definition above.
-  Handle GetPageThumbnail(const GURL& page_url,
-                          CancelableRequestConsumerBase* consumer,
-                          const ThumbnailDataCallback& callback);
-
   // Database management operations --------------------------------------------
 
   // Delete all the information related to a single url.
@@ -541,10 +525,6 @@
   virtual void ScheduleDBTask(history::HistoryDBTask* task,
                               CancelableRequestConsumerBase* consumer);
 
-  // Returns true if top sites needs to be migrated out of history into its own
-  // db.
-  bool needs_top_sites_migration() const { return needs_top_sites_migration_; }
-
   // Adds or removes observers for the VisitDatabase.
   void AddVisitDatabaseObserver(history::VisitDatabaseObserver* observer);
   void RemoveVisitDatabaseObserver(history::VisitDatabaseObserver* observer);
@@ -590,14 +570,6 @@
   void AddPagesWithDetails(const history::URLRows& info,
                            history::VisitSource visit_source);
 
-  // Starts the TopSites migration in the HistoryThread. Called by the
-  // BackendDelegate.
-  void StartTopSitesMigration(int backend_id);
-
-  // Called by TopSites after the thumbnails were read and it is safe
-  // to delete the thumbnails DB.
-  void OnTopSitesReady();
-
   // Returns true if this looks like the type of URL we want to add to the
   // history. We filter out some URLs such as JavaScript.
   static bool CanAddURL(const GURL& url);
@@ -1078,9 +1050,6 @@
   BookmarkService* bookmark_service_;
   bool no_db_;
 
-  // True if needs top site migration.
-  bool needs_top_sites_migration_;
-
   // The index used for quick history lookups.
   // TODO(mrossetti): Move in_memory_url_index out of history_service.
   // See http://crbug.com/138321
diff --git a/chrome/browser/history/history_unittest.cc b/chrome/browser/history/history_unittest.cc
index 28db9ba..53ffcf5 100644
--- a/chrome/browser/history/history_unittest.cc
+++ b/chrome/browser/history/history_unittest.cc
@@ -95,7 +95,6 @@
   virtual void BroadcastNotifications(int type,
                                       HistoryDetails* details) OVERRIDE;
   virtual void DBLoaded(int backend_id) OVERRIDE {}
-  virtual void StartTopSitesMigration(int backend_id) OVERRIDE {}
   virtual void NotifyVisitDBObserversOnAddVisit(
       const BriefVisitInfo& info) OVERRIDE {}
  private:
diff --git a/chrome/browser/history/thumbnail_database.cc b/chrome/browser/history/thumbnail_database.cc
index 51cbac1..59d60a1 100644
--- a/chrome/browser/history/thumbnail_database.cc
+++ b/chrome/browser/history/thumbnail_database.cc
@@ -7,29 +7,23 @@
 #include <algorithm>
 #include <string>
 
-#include "base/command_line.h"
+#include "base/bind.h"
 #include "base/debug/alias.h"
 #include "base/file_util.h"
 #include "base/format_macros.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/metrics/histogram.h"
 #include "base/rand_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/history/history_publisher.h"
-#include "chrome/browser/history/top_sites.h"
 #include "chrome/browser/history/url_database.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/dump_without_crashing.h"
-#include "chrome/common/thumbnail_score.h"
 #include "sql/statement.h"
 #include "sql/transaction.h"
 #include "third_party/sqlite/sqlite3.h"
-#include "ui/gfx/image/image_util.h"
 
 #if defined(OS_MACOSX)
 #include "base/mac/mac_util.h"
@@ -281,10 +275,6 @@
 static const int kCurrentVersionNumber = 7;
 static const int kCompatibleVersionNumber = 7;
 
-// Use 90 quality (out of 100) which is pretty high, because we're very
-// sensitive to artifacts for these small sized, highly detailed images.
-static const int kImageQuality = 90;
-
 ThumbnailDatabase::IconMappingEnumerator::IconMappingEnumerator() {
 }
 
@@ -300,8 +290,7 @@
 }
 
 ThumbnailDatabase::ThumbnailDatabase()
-    : history_publisher_(NULL),
-      use_top_sites_(false) {
+    : history_publisher_(NULL) {
 }
 
 sql::InitStatus ThumbnailDatabase::CantUpgradeToVersion(int cur_version) {
@@ -333,15 +322,18 @@
   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) ||
-      !InitThumbnailTable() ||
-      !InitFaviconBitmapsTable(&db_, false) ||
+      !InitFaviconBitmapsTable(&db_) ||
       !InitFaviconBitmapsIndex() ||
-      !InitFaviconsTable(&db_, false) ||
+      !InitFaviconsTable(&db_) ||
       !InitFaviconsIndex() ||
-      !InitIconMappingTable(&db_, false) ||
+      !InitIconMappingTable(&db_) ||
       !InitIconMappingIndex()) {
     db_.Close();
     return sql::INIT_FAILURE;
@@ -460,70 +452,24 @@
       favicon_count.Step() ? favicon_count.ColumnInt(0) : 0);
 }
 
-bool ThumbnailDatabase::InitThumbnailTable() {
-  if (!db_.DoesTableExist("thumbnails")) {
-    use_top_sites_ = true;
-  }
-  return true;
-}
-
 bool ThumbnailDatabase::UpgradeToVersion3() {
-  if (use_top_sites_) {
-    meta_table_.SetVersionNumber(3);
-    meta_table_.SetCompatibleVersionNumber(
-        std::min(3, kCompatibleVersionNumber));
-    return true;  // Not needed after migration to TopSites.
-  }
-
-  // sqlite doesn't like the "ALTER TABLE xxx ADD (column_one, two,
-  // three)" syntax, so list out the commands we need to execute:
-  const char* alterations[] = {
-    "ALTER TABLE thumbnails ADD boring_score DOUBLE DEFAULT 1.0",
-    "ALTER TABLE thumbnails ADD good_clipping INTEGER DEFAULT 0",
-    "ALTER TABLE thumbnails ADD at_top INTEGER DEFAULT 0",
-    "ALTER TABLE thumbnails ADD last_updated INTEGER DEFAULT 0",
-    NULL
-  };
-
-  for (int i = 0; alterations[i] != NULL; ++i) {
-    if (!db_.Execute(alterations[i])) {
-      return false;
-    }
-  }
-
+  // Version 3 migrated table thumbnails, which is obsolete.
   meta_table_.SetVersionNumber(3);
   meta_table_.SetCompatibleVersionNumber(std::min(3, kCompatibleVersionNumber));
   return true;
 }
 
-bool ThumbnailDatabase::RecreateThumbnailTable() {
-  if (use_top_sites_)
-    return true;  // Not needed after migration to TopSites.
-
-  if (!db_.Execute("DROP TABLE thumbnails"))
-    return false;
-  return InitThumbnailTable();
-}
-
-bool ThumbnailDatabase::InitFaviconsTable(sql::Connection* db,
-                                          bool is_temporary) {
-  // Note: if you update the schema, don't forget to update
-  // CopyFaviconAndFaviconBitmapsToTemporaryTables as well.
-  const char* name = is_temporary ? "temp_favicons" : "favicons";
-  if (!db->DoesTableExist(name)) {
-    std::string sql;
-    sql.append("CREATE TABLE ");
-    sql.append(name);
-    sql.append("("
-               "id INTEGER PRIMARY KEY,"
-               "url LONGVARCHAR NOT NULL,"
-               // Set the default icon_type as FAVICON to be consistent with
-               // table upgrade in UpgradeToVersion4().
-               "icon_type INTEGER DEFAULT 1)");
-    if (!db->Execute(sql.c_str()))
-      return false;
-  }
-  return true;
+bool ThumbnailDatabase::InitFaviconsTable(sql::Connection* db) {
+  const char kSql[] =
+      "CREATE TABLE IF NOT EXISTS favicons"
+      "("
+      "id INTEGER PRIMARY KEY,"
+      "url LONGVARCHAR NOT NULL,"
+      // Set the default icon_type as FAVICON to be consistent with
+      // table upgrade in UpgradeToVersion4().
+      "icon_type INTEGER DEFAULT 1"
+      ")";
+  return db->Execute(kSql);
 }
 
 bool ThumbnailDatabase::InitFaviconsIndex() {
@@ -532,26 +478,18 @@
       db_.Execute("CREATE INDEX IF NOT EXISTS favicons_url ON favicons(url)");
 }
 
-bool ThumbnailDatabase::InitFaviconBitmapsTable(sql::Connection* db,
-                                                bool is_temporary) {
-  // Note: if you update the schema, don't forget to update
-  // CopyFaviconAndFaviconBitmapsToTemporaryTables as well.
-  const char* name = is_temporary ? "temp_favicon_bitmaps" : "favicon_bitmaps";
-  if (!db->DoesTableExist(name)) {
-    std::string sql;
-    sql.append("CREATE TABLE ");
-    sql.append(name);
-    sql.append("("
-               "id INTEGER PRIMARY KEY,"
-               "icon_id INTEGER NOT NULL,"
-               "last_updated INTEGER DEFAULT 0,"
-               "image_data BLOB,"
-               "width INTEGER DEFAULT 0,"
-               "height INTEGER DEFAULT 0)");
-    if (!db->Execute(sql.c_str()))
-      return false;
-  }
-  return true;
+bool ThumbnailDatabase::InitFaviconBitmapsTable(sql::Connection* db) {
+  const char kSql[] =
+      "CREATE TABLE IF NOT EXISTS favicon_bitmaps"
+      "("
+      "id INTEGER PRIMARY KEY,"
+      "icon_id INTEGER NOT NULL,"
+      "last_updated INTEGER DEFAULT 0,"
+      "image_data BLOB,"
+      "width INTEGER DEFAULT 0,"
+      "height INTEGER DEFAULT 0"
+      ")";
+  return db->Execute(kSql);
 }
 
 bool ThumbnailDatabase::InitFaviconBitmapsIndex() {
@@ -586,115 +524,6 @@
   db_.TrimMemory(aggressively);
 }
 
-bool ThumbnailDatabase::SetPageThumbnail(
-    const GURL& url,
-    URLID id,
-    const gfx::Image* thumbnail,
-    const ThumbnailScore& score,
-    base::Time time) {
-  if (use_top_sites_) {
-    LOG(WARNING) << "Use TopSites instead.";
-    return false;  // Not possible after migration to TopSites.
-  }
-
-  if (!thumbnail)
-    return DeleteThumbnail(id);
-
-  bool add_thumbnail = true;
-  ThumbnailScore current_score;
-  if (ThumbnailScoreForId(id, &current_score)) {
-    add_thumbnail = ShouldReplaceThumbnailWith(current_score, score);
-  }
-
-  if (!add_thumbnail)
-    return true;
-
-  std::vector<unsigned char> jpeg_data;
-  bool encoded = gfx::JPEG1xEncodedDataFromImage(
-      *thumbnail, kImageQuality, &jpeg_data);
-  if (encoded) {
-    sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-        "INSERT OR REPLACE INTO thumbnails "
-        "(url_id, boring_score, good_clipping, at_top, last_updated, data) "
-        "VALUES (?,?,?,?,?,?)"));
-    statement.BindInt64(0, id);
-    statement.BindDouble(1, score.boring_score);
-    statement.BindBool(2, score.good_clipping);
-    statement.BindBool(3, score.at_top);
-    statement.BindInt64(4, score.time_at_snapshot.ToInternalValue());
-    statement.BindBlob(5, &jpeg_data[0],
-                       static_cast<int>(jpeg_data.size()));
-
-    if (!statement.Run())
-      return false;
-  }
-
-  // Publish the thumbnail to any indexers listening to us.
-  // The tests may send an invalid url. Hence avoid publishing those.
-  if (url.is_valid() && history_publisher_ != NULL)
-    history_publisher_->PublishPageThumbnail(jpeg_data, url, time);
-
-  return true;
-}
-
-bool ThumbnailDatabase::GetPageThumbnail(URLID id,
-                                         std::vector<unsigned char>* data) {
-  if (use_top_sites_) {
-    LOG(WARNING) << "Use TopSites instead.";
-    return false;  // Not possible after migration to TopSites.
-  }
-
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "SELECT data FROM thumbnails WHERE url_id=?"));
-  statement.BindInt64(0, id);
-
-  if (!statement.Step())
-    return false;  // don't have a thumbnail for this ID
-
-  statement.ColumnBlobAsVector(0, data);
-  return true;
-}
-
-bool ThumbnailDatabase::DeleteThumbnail(URLID id) {
-  if (use_top_sites_) {
-    return true;  // Not possible after migration to TopSites.
-  }
-
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "DELETE FROM thumbnails WHERE url_id = ?"));
-  statement.BindInt64(0, id);
-
-  return statement.Run();
-}
-
-bool ThumbnailDatabase::ThumbnailScoreForId(URLID id,
-                                            ThumbnailScore* score) {
-  DCHECK(score);
-  if (use_top_sites_) {
-    LOG(WARNING) << "Use TopSites instead.";
-    return false;  // Not possible after migration to TopSites.
-  }
-
-  // Fetch the current thumbnail's information to make sure we
-  // aren't replacing a good thumbnail with one that's worse.
-  sql::Statement select_statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "SELECT boring_score, good_clipping, at_top, last_updated "
-      "FROM thumbnails WHERE url_id=?"));
-  select_statement.BindInt64(0, id);
-
-  if (!select_statement.Step())
-    return false;
-
-  double current_boring_score = select_statement.ColumnDouble(0);
-  bool current_clipping = select_statement.ColumnBool(1);
-  bool current_at_top = select_statement.ColumnBool(2);
-  base::Time last_updated =
-      base::Time::FromInternalValue(select_statement.ColumnInt64(3));
-  *score = ThumbnailScore(current_boring_score, current_clipping,
-                          current_at_top, last_updated);
-  return true;
-}
-
 bool ThumbnailDatabase::GetFaviconBitmapIDSizes(
     chrome::FaviconID icon_id,
     std::vector<FaviconBitmapIDSize>* bitmap_id_sizes) {
@@ -835,14 +664,6 @@
   return statement.Run();
 }
 
-bool ThumbnailDatabase::DeleteFaviconBitmapsForFavicon(
-    chrome::FaviconID icon_id) {
-  sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
-      "DELETE FROM favicon_bitmaps WHERE icon_id=?"));
-  statement.BindInt64(0, icon_id);
-  return statement.Run();
-}
-
 bool ThumbnailDatabase::DeleteFaviconBitmap(FaviconBitmapID bitmap_id) {
   sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
       "DELETE FROM favicon_bitmaps WHERE id=?"));
@@ -991,11 +812,6 @@
   return result;
 }
 
-IconMappingID ThumbnailDatabase::AddIconMapping(const GURL& page_url,
-                                                chrome::FaviconID icon_id) {
-  return AddIconMapping(page_url, icon_id, false);
-}
-
 bool ThumbnailDatabase::UpdateIconMapping(IconMappingID mapping_id,
                                           chrome::FaviconID icon_id) {
   sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
@@ -1083,179 +899,119 @@
   return true;
 }
 
-bool ThumbnailDatabase::InitTemporaryTables() {
-  return InitIconMappingTable(&db_, true) &&
-         InitFaviconsTable(&db_, true) &&
-         InitFaviconBitmapsTable(&db_, true);
-}
-
-bool ThumbnailDatabase::CommitTemporaryTables() {
-  const char* main_tables[] = { "icon_mapping",
-                                "favicons",
-                                "favicon_bitmaps" };
-  const char* temporary_tables[] = { "temp_icon_mapping",
-                                     "temp_favicons",
-                                     "temp_favicon_bitmaps" };
-  DCHECK_EQ(arraysize(main_tables), arraysize(temporary_tables));
-
-  for (size_t i = 0; i < arraysize(main_tables); ++i) {
-    // Delete the main table.
-    std::string sql;
-    sql.append("DROP TABLE ");
-    sql.append(main_tables[i]);
-    if (!db_.Execute(sql.c_str()))
-      return false;
-
-    // Rename the temporary table.
-    sql.clear();
-    sql.append("ALTER TABLE ");
-    sql.append(temporary_tables[i]);
-    sql.append(" RENAME TO ");
-    sql.append(main_tables[i]);
-    if (!db_.Execute(sql.c_str()))
-      return false;
-  }
-
-  // The renamed tables needs indices (the temporary tables don't have any).
-  return InitIconMappingIndex() &&
-         InitFaviconsIndex() &&
-         InitFaviconBitmapsIndex();
-}
-
-IconMappingID ThumbnailDatabase::AddToTemporaryIconMappingTable(
-    const GURL& page_url,
-    const chrome::FaviconID icon_id) {
-  return AddIconMapping(page_url, icon_id, true);
-}
-
-chrome::FaviconID
-ThumbnailDatabase::CopyFaviconAndFaviconBitmapsToTemporaryTables(
-    chrome::FaviconID source) {
-  sql::Statement statement;
-  statement.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
-      "INSERT INTO temp_favicons (url, icon_type) "
-      "SELECT url, icon_type FROM favicons WHERE id = ?"));
-  statement.BindInt64(0, source);
-
-  if (!statement.Run())
-    return 0;
-
-  chrome::FaviconID new_favicon_id = db_.GetLastInsertRowId();
-
-  statement.Assign(db_.GetCachedStatement(SQL_FROM_HERE,
-      "INSERT INTO temp_favicon_bitmaps (icon_id, last_updated, image_data, "
-      "width, height) "
-      "SELECT ?, last_updated, image_data, width, height "
-      "FROM favicon_bitmaps WHERE icon_id = ?"));
-  statement.BindInt64(0, new_favicon_id);
-  statement.BindInt64(1, source);
-  if (!statement.Run())
-    return 0;
-
-  return new_favicon_id;
-}
-
-bool ThumbnailDatabase::NeedsMigrationToTopSites() {
-  return !use_top_sites_;
-}
-
-bool ThumbnailDatabase::RenameAndDropThumbnails(
-    const base::FilePath& old_db_file,
-    const base::FilePath& new_db_file) {
-  // Init favicons tables - same schema as the thumbnails.
-  sql::Connection favicons;
-  if (OpenDatabase(&favicons, new_db_file) != sql::INIT_OK)
+bool ThumbnailDatabase::RetainDataForPageUrls(
+    const std::vector<GURL>& urls_to_keep) {
+  sql::Transaction transaction(&db_);
+  if (!transaction.Begin())
     return false;
 
-  if (!InitFaviconBitmapsTable(&favicons, false) ||
-      !InitFaviconsTable(&favicons, false) ||
-      !InitIconMappingTable(&favicons, false)) {
-    favicons.Close();
-    return false;
-  }
-  favicons.Close();
-
-  // Can't attach within a transaction.
-  if (transaction_nesting())
-    CommitTransaction();
-
-  // Attach new DB.
+  // temp.icon_id_mapping generates new icon ids as consecutive
+  // integers starting from 1, and maps them to the old icon ids.
   {
-    // This block is needed because otherwise the attach statement is
-    // never cleared from cache and we can't close the DB :P
-    sql::Statement attach(db_.GetUniqueStatement("ATTACH ? AS new_favicons"));
-    if (!attach.is_valid()) {
-      // Keep the transaction open, even though we failed.
-      BeginTransaction();
+    const char kIconMappingCreate[] =
+        "CREATE TEMP TABLE icon_id_mapping "
+        "("
+        "new_icon_id INTEGER PRIMARY KEY,"
+        "old_icon_id INTEGER NOT NULL UNIQUE"
+        ")";
+    if (!db_.Execute(kIconMappingCreate))
       return false;
+
+    // Insert the icon ids for retained urls, skipping duplicates.
+    const char kIconMappingSql[] =
+        "INSERT OR IGNORE INTO temp.icon_id_mapping (old_icon_id) "
+        "SELECT icon_id FROM icon_mapping WHERE page_url = ?";
+    sql::Statement statement(db_.GetUniqueStatement(kIconMappingSql));
+    for (std::vector<GURL>::const_iterator
+             i = urls_to_keep.begin(); i != urls_to_keep.end(); ++i) {
+      statement.BindString(0, URLDatabase::GURLToDatabaseURL(*i));
+      if (!statement.Run())
+        return false;
     }
+  }
 
-#if defined(OS_POSIX)
-    attach.BindString(0, new_db_file.value());
-#else
-    attach.BindString(0, WideToUTF8(new_db_file.value()));
-#endif
-
-    if (!attach.Run()) {
-      BeginTransaction();
+  {
+    const char kRenameIconMappingTable[] =
+        "ALTER TABLE icon_mapping RENAME TO old_icon_mapping";
+    const char kCopyIconMapping[] =
+        "INSERT INTO icon_mapping (page_url, icon_id) "
+        "SELECT old.page_url, mapping.new_icon_id "
+        "FROM old_icon_mapping AS old "
+        "JOIN temp.icon_id_mapping AS mapping "
+        "ON (old.icon_id = mapping.old_icon_id)";
+    const char kDropOldIconMappingTable[] = "DROP TABLE old_icon_mapping";
+    if (!db_.Execute(kRenameIconMappingTable) ||
+        !InitIconMappingTable(&db_) ||
+        !db_.Execute(kCopyIconMapping) ||
+        !db_.Execute(kDropOldIconMappingTable)) {
       return false;
     }
   }
 
-  // Move favicons and favicon_bitmaps to new DB.
-  bool successfully_moved_data =
-     db_.Execute("INSERT OR REPLACE INTO new_favicons.favicon_bitmaps "
-                 "SELECT * FROM favicon_bitmaps") &&
-     db_.Execute("INSERT OR REPLACE INTO new_favicons.favicons "
-                 "SELECT * FROM favicons");
-  if (!successfully_moved_data) {
-    DLOG(FATAL) << "Unable to copy favicons and favicon_bitmaps.";
-    BeginTransaction();
+  {
+    const char kRenameFaviconsTable[] =
+        "ALTER TABLE favicons RENAME TO old_favicons";
+    const char kCopyFavicons[] =
+        "INSERT INTO favicons (id, url, icon_type) "
+        "SELECT mapping.new_icon_id, old.url, old.icon_type "
+        "FROM old_favicons AS old "
+        "JOIN temp.icon_id_mapping AS mapping "
+        "ON (old.id = mapping.old_icon_id)";
+    const char kDropOldFaviconsTable[] = "DROP TABLE old_favicons";
+    if (!db_.Execute(kRenameFaviconsTable) ||
+        !InitFaviconsTable(&db_) ||
+        !db_.Execute(kCopyFavicons) ||
+        !db_.Execute(kDropOldFaviconsTable)) {
+      return false;
+    }
+  }
+
+  {
+    const char kRenameFaviconBitmapsTable[] =
+        "ALTER TABLE favicon_bitmaps RENAME TO old_favicon_bitmaps";
+    const char kCopyFaviconBitmaps[] =
+        "INSERT INTO favicon_bitmaps "
+        "  (icon_id, last_updated, image_data, width, height) "
+        "SELECT mapping.new_icon_id, old.last_updated, "
+        "    old.image_data, old.width, old.height "
+        "FROM old_favicon_bitmaps AS old "
+        "JOIN temp.icon_id_mapping AS mapping "
+        "ON (old.icon_id = mapping.old_icon_id)";
+    const char kDropOldFaviconBitmapsTable[] =
+        "DROP TABLE old_favicon_bitmaps";
+    if (!db_.Execute(kRenameFaviconBitmapsTable) ||
+        !InitFaviconBitmapsTable(&db_) ||
+        !db_.Execute(kCopyFaviconBitmaps) ||
+        !db_.Execute(kDropOldFaviconBitmapsTable)) {
+      return false;
+    }
+  }
+
+  // Renaming the tables adjusts the indices to reference the new
+  // name, BUT DOES NOT RENAME THE INDICES.  The DROP will drop the
+  // indices, now re-create them against the new tables.
+  if (!InitIconMappingIndex() ||
+      !InitFaviconsIndex() ||
+      !InitFaviconBitmapsIndex()) {
     return false;
   }
 
-  if (!db_.Execute("DETACH new_favicons")) {
-    DLOG(FATAL) << "Unable to detach database.";
-    BeginTransaction();
-    return false;
-  }
-
-  db_.Close();
-
-  // Reset the DB to point to new file.
-  if (OpenDatabase(&db_, new_db_file) != sql::INIT_OK)
+  const char kIconMappingDrop[] = "DROP TABLE temp.icon_id_mapping";
+  if (!db_.Execute(kIconMappingDrop))
     return false;
 
-  sql::Connection::Delete(old_db_file);
-
-  meta_table_.Reset();
-  if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
-    return false;
-
-  if (!InitFaviconBitmapsIndex() || !InitFaviconsIndex())
-    return false;
-
-  // Reopen the transaction.
-  BeginTransaction();
-  use_top_sites_ = true;
-  return true;
+  return transaction.Commit();
 }
 
-bool ThumbnailDatabase::InitIconMappingTable(sql::Connection* db,
-                                             bool is_temporary) {
-  const char* name = is_temporary ? "temp_icon_mapping" : "icon_mapping";
-  if (!db->DoesTableExist(name)) {
-    std::string sql;
-    sql.append("CREATE TABLE ");
-    sql.append(name);
-    sql.append("("
-               "id INTEGER PRIMARY KEY,"
-               "page_url LONGVARCHAR NOT NULL,"
-               "icon_id INTEGER)");
-    if (!db->Execute(sql.c_str()))
-      return false;
-  }
-  return true;
+bool ThumbnailDatabase::InitIconMappingTable(sql::Connection* db) {
+  const char kSql[] =
+      "CREATE TABLE IF NOT EXISTS icon_mapping"
+      "("
+      "id INTEGER PRIMARY KEY,"
+      "page_url LONGVARCHAR NOT NULL,"
+      "icon_id INTEGER"
+      ")";
+  return db->Execute(kSql);
 }
 
 bool ThumbnailDatabase::InitIconMappingIndex() {
@@ -1268,19 +1024,10 @@
 }
 
 IconMappingID ThumbnailDatabase::AddIconMapping(const GURL& page_url,
-                                                chrome::FaviconID icon_id,
-                                                bool is_temporary) {
-  const char* name = is_temporary ? "temp_icon_mapping" : "icon_mapping";
-  const char* statement_name =
-      is_temporary ? "add_temp_icon_mapping" : "add_icon_mapping";
-
-  std::string sql;
-  sql.append("INSERT INTO ");
-  sql.append(name);
-  sql.append("(page_url, icon_id) VALUES (?, ?)");
-
-  sql::Statement statement(
-      db_.GetCachedStatement(sql::StatementID(statement_name), sql.c_str()));
+                                                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);
 
diff --git a/chrome/browser/history/thumbnail_database.h b/chrome/browser/history/thumbnail_database.h
index ae4006d..d407897 100644
--- a/chrome/browser/history/thumbnail_database.h
+++ b/chrome/browser/history/thumbnail_database.h
@@ -78,33 +78,6 @@
   // true try to trim all unused cache, otherwise trim by half.
   void TrimMemory(bool aggressively);
 
-  // Thumbnails ----------------------------------------------------------------
-
-  // Sets the given data to be the thumbnail for the given URL,
-  // overwriting any previous data. If the SkBitmap contains no pixel
-  // data, the thumbnail will be deleted.
-  bool SetPageThumbnail(const GURL& url,
-                        URLID id,
-                        const gfx::Image* thumbnail,
-                        const ThumbnailScore& score,
-                        base::Time time);
-
-  // Retrieves thumbnail data for the given URL, returning true on success,
-  // false if there is no such thumbnail or there was some other error.
-  bool GetPageThumbnail(URLID id, std::vector<unsigned char>* data);
-
-  // Delete the thumbnail with the provided id. Returns false on failure
-  bool DeleteThumbnail(URLID id);
-
-  // If there is a thumbnail score for the id provided, retrieves the
-  // current thumbnail score and places it in |score| and returns
-  // true. Returns false otherwise.
-  bool ThumbnailScoreForId(URLID id, ThumbnailScore* score);
-
-  // Called by the to delete all old thumbnails and make a clean table.
-  // Returns true on success.
-  bool RecreateThumbnailTable();
-
   // Favicon Bitmaps -----------------------------------------------------------
 
   // Returns true if there are favicon bitmaps for |icon_id|. If
@@ -155,10 +128,6 @@
   bool SetFaviconBitmapLastUpdateTime(FaviconBitmapID bitmap_id,
                                       base::Time time);
 
-  // Deletes the favicon bitmaps for the favicon with with |icon_id|.
-  // Returns true if successful.
-  bool DeleteFaviconBitmapsForFavicon(chrome::FaviconID icon_id);
-
   // Deletes the favicon bitmap with |bitmap_id|.
   // Returns true if successful.
   bool DeleteFaviconBitmap(FaviconBitmapID bitmap_id);
@@ -274,45 +243,10 @@
   bool InitIconMappingEnumerator(chrome::IconType type,
                                  IconMappingEnumerator* enumerator);
 
-  // Temporary Tables ---------------------------------------------------------
-  //
-  // Creates empty temporary tables for each of the tables in the thumbnail
-  // database. Favicon data which is not copied into the temporary tables will
-  // be deleted when CommitTemporaryTables() is called. This is used to delete
-  // most of the favicons when clearing history.
-  bool InitTemporaryTables();
-
-  // Replaces the main tables in the thumbnail database with the temporary
-  // tables created with InitTemporaryTables(). This means that any data not
-  // copied over will be deleted.
-  bool CommitTemporaryTables();
-
-  // Copies the given icon mapping from the "main" icon_mapping table to the
-  // temporary one. This is only valid in between calls to
-  // InitTemporaryTables() and CommitTemporaryTables().
-  //
-  // The ID of the favicon will change when this copy takes place. The new ID
-  // is returned, or 0 on failure.
-  IconMappingID AddToTemporaryIconMappingTable(const GURL& page_url,
-                                               const chrome::FaviconID icon_id);
-
-  // Copies the given favicon and associated favicon bitmaps from the "main"
-  // favicon and favicon_bitmaps tables to the temporary ones. This is only
-  // valid in between calls to InitTemporaryTables() and
-  // CommitTemporaryTables().
-  //
-  // The ID of the favicon will change when this copy takes place. The new ID
-  // is returned, or 0 on failure.
-  chrome::FaviconID CopyFaviconAndFaviconBitmapsToTemporaryTables(
-      chrome::FaviconID source);
-
-  // Returns true iff the thumbnails table exists.
-  // Migrating to TopSites is dropping the thumbnails table.
-  bool NeedsMigrationToTopSites();
-
-  // Renames the database file and drops the Thumbnails table.
-  bool RenameAndDropThumbnails(const base::FilePath& old_db_file,
-                               const base::FilePath& new_db_file);
+  // Remove all data except that associated with the passed page urls.
+  // Returns false in case of failure.  A nested transaction is used,
+  // so failure causes any outer transaction to be rolled back.
+  bool RetainDataForPageUrls(const std::vector<GURL>& urls_to_keep);
 
  private:
   friend class ExpireHistoryBackend;
@@ -322,6 +256,7 @@
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion5);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion6);
   FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, UpgradeToVersion7);
+  FRIEND_TEST_ALL_PREFIXES(ThumbnailDatabaseTest, RetainDataForPageUrls);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, MigrationIconMapping);
 
   // Creates the thumbnail table, returning true if the table already exists
@@ -351,13 +286,11 @@
   bool MigrateIconMappingData(URLDatabase* url_db);
 
   // Creates the favicon table, returning true if the table already exists,
-  // or was successfully created. |is_temporary| will be false when generating
-  // the "regular" favicons table. The expirer sets this to true to generate the
-  // temporary table, which will have a different name but the same schema.
+  // or was successfully created.
   // |db| is the connection to use for initializing the table.
   // A different connection is used in RenameAndDropThumbnails, when we
   // need to copy the favicons between two database files.
-  bool InitFaviconsTable(sql::Connection* db, bool is_temporary);
+  bool InitFaviconsTable(sql::Connection* db);
 
   // Creates the index over the favicon table. This will be called during
   // initialization after the table is created. This is a separate function
@@ -367,7 +300,7 @@
 
   // Creates the favicon_bitmaps table, return true if the table already exists
   // or was successfully created.
-  bool InitFaviconBitmapsTable(sql::Connection* db, bool is_temporary);
+  bool InitFaviconBitmapsTable(sql::Connection* db);
 
   // Creates the index over the favicon_bitmaps table. This will be called
   // during initialization after the table is created. This is a separate
@@ -378,7 +311,7 @@
 
   // Creates the icon_map table, return true if the table already exists or was
   // successfully created.
-  bool InitIconMappingTable(sql::Connection* db, bool is_temporary);
+  bool InitIconMappingTable(sql::Connection* db);
 
   // Creates the index over the icon_mapping table, This will be called during
   // initialization after the table is created. This is a separate function
@@ -390,13 +323,6 @@
   // Returns true if the |favicons| database is missing a column.
   bool IsFaviconDBStructureIncorrect();
 
-  // Adds a mapping between the given page_url and icon_id; The mapping will be
-  // added to temp_icon_mapping table if is_temporary is true.
-  // Returns the new mapping id if the adding succeeds, otherwise 0 is returned.
-  IconMappingID AddIconMapping(const GURL& page_url,
-                               chrome::FaviconID icon_id,
-                               bool is_temporary);
-
   // Returns True if the current database is latest.
   bool IsLatestVersion();
 
@@ -408,10 +334,6 @@
   // This can be NULL if there are no indexers registered to receive indexing
   // data from us.
   const HistoryPublisher* history_publisher_;
-
-  // True if migration to TopSites has been done and the thumbnails
-  // table should not be used.
-  bool use_top_sites_;
 };
 
 }  // namespace history
diff --git a/chrome/browser/history/thumbnail_database_unittest.cc b/chrome/browser/history/thumbnail_database_unittest.cc
index 6446fd1..75758e7 100644
--- a/chrome/browser/history/thumbnail_database_unittest.cc
+++ b/chrome/browser/history/thumbnail_database_unittest.cc
@@ -93,12 +93,11 @@
     data_path = data_path.AppendASCII("History");
 
     history_db_name_ = profile_->GetPath().Append(chrome::kHistoryFilename);
-    // Set up history and thumbnails as they would be before migration.
     ASSERT_NO_FATAL_FAILURE(
         ExecuteSQLScript(data_path.AppendASCII("history.20.sql"),
                          history_db_name_));
     thumbnail_db_name_ =
-        profile_->GetPath().Append(chrome::kThumbnailsFilename);
+        profile_->GetPath().Append(chrome::kFaviconsFilename);
     ASSERT_NO_FATAL_FAILURE(
         ExecuteSQLScript(data_path.AppendASCII("thumbnails.3.sql"),
                          thumbnail_db_name_));
@@ -112,66 +111,6 @@
   scoped_ptr<TestingProfile> profile_;
 };
 
-TEST_F(ThumbnailDatabaseTest, GetFaviconAfterMigrationToTopSites) {
-  ThumbnailDatabase db;
-  ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
-  db.BeginTransaction();
-
-  std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
-  scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
-
-  GURL url("http://google.com");
-  chrome::FaviconID icon_id = db.AddFavicon(url, chrome::FAVICON);
-  base::Time time = base::Time::Now();
-  FaviconBitmapID bitmap1_id = db.AddFaviconBitmap(icon_id, favicon, time,
-                                                   kSmallSize);
-  FaviconBitmapID bitmap2_id = db.AddFaviconBitmap(icon_id, favicon, time,
-                                                   kLargeSize);
-  EXPECT_TRUE(db.RenameAndDropThumbnails(file_name_, new_file_name_));
-  EXPECT_TRUE(db.IsLatestVersion());
-
-  GURL url_out;
-  chrome::IconType icon_type_out;
-  EXPECT_TRUE(db.GetFaviconHeader(icon_id, &url_out, &icon_type_out));
-
-  EXPECT_EQ(url, url_out);
-  EXPECT_EQ(chrome::FAVICON, icon_type_out);
-
-  std::vector<FaviconBitmap> favicon_bitmaps_out;
-  EXPECT_TRUE(db.GetFaviconBitmaps(icon_id, &favicon_bitmaps_out));
-  EXPECT_EQ(2u, favicon_bitmaps_out.size());
-
-  FaviconBitmap favicon_bitmap1 = favicon_bitmaps_out[0];
-  FaviconBitmap favicon_bitmap2 = favicon_bitmaps_out[1];
-
-  // Favicon bitmaps do not need to be in particular order.
-  if (favicon_bitmap1.bitmap_id == bitmap2_id) {
-    FaviconBitmap tmp_favicon_bitmap = favicon_bitmap1;
-    favicon_bitmap1 = favicon_bitmap2;
-    favicon_bitmap2 = tmp_favicon_bitmap;
-  }
-
-  EXPECT_EQ(bitmap1_id, favicon_bitmap1.bitmap_id);
-  EXPECT_EQ(icon_id, favicon_bitmap1.icon_id);
-  EXPECT_EQ(time.ToInternalValue(),
-            favicon_bitmap1.last_updated.ToInternalValue());
-  EXPECT_EQ(data.size(), favicon_bitmap1.bitmap_data->size());
-  EXPECT_TRUE(std::equal(data.begin(),
-                         data.end(),
-                         favicon_bitmap1.bitmap_data->front()));
-  EXPECT_EQ(kSmallSize, favicon_bitmap1.pixel_size);
-
-  EXPECT_EQ(bitmap2_id, favicon_bitmap2.bitmap_id);
-  EXPECT_EQ(icon_id, favicon_bitmap2.icon_id);
-  EXPECT_EQ(time.ToInternalValue(),
-            favicon_bitmap2.last_updated.ToInternalValue());
-  EXPECT_EQ(data.size(), favicon_bitmap2.bitmap_data->size());
-  EXPECT_TRUE(std::equal(data.begin(),
-                         data.end(),
-                         favicon_bitmap2.bitmap_data->front()));
-  EXPECT_EQ(kLargeSize, favicon_bitmap2.pixel_size);
-}
-
 TEST_F(ThumbnailDatabaseTest, AddIconMapping) {
   ThumbnailDatabase db;
   ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
@@ -470,17 +409,13 @@
   EXPECT_EQ(chrome::TOUCH_ICON, statement.ColumnInt(2));
 }
 
-// Test that only data moved to a temporary table is left in the main table
-// once the temporary table is committed.
-TEST_F(ThumbnailDatabaseTest, TemporaryTables) {
+TEST_F(ThumbnailDatabaseTest, RetainDataForPageUrls) {
   ThumbnailDatabase db;
 
   ASSERT_EQ(sql::INIT_OK, db.Init(file_name_, NULL, NULL));
 
   db.BeginTransaction();
 
-  EXPECT_TRUE(db.InitTemporaryTables());
-
   std::vector<unsigned char> data(blob1, blob1 + sizeof(blob1));
   scoped_refptr<base::RefCountedBytes> favicon(new base::RefCountedBytes(data));
 
@@ -492,24 +427,25 @@
   chrome::FaviconID kept_id = db.AddFavicon(kept_url, chrome::FAVICON);
   db.AddFaviconBitmap(kept_id, favicon, base::Time::Now(), kLargeSize);
 
-  GURL page_url("http://google.com");
-  db.AddIconMapping(page_url, unkept_id);
-  db.AddIconMapping(page_url, kept_id);
+  GURL unkept_page_url("http://chromium.org");
+  db.AddIconMapping(unkept_page_url, unkept_id);
+  db.AddIconMapping(unkept_page_url, kept_id);
 
-  chrome::FaviconID new_favicon_id =
-      db.CopyFaviconAndFaviconBitmapsToTemporaryTables(kept_id);
-  EXPECT_NE(0, new_favicon_id);
-  EXPECT_TRUE(db.AddToTemporaryIconMappingTable(page_url, new_favicon_id));
+  GURL kept_page_url("http://google.com");
+  db.AddIconMapping(kept_page_url, kept_id);
 
-  EXPECT_TRUE(db.CommitTemporaryTables());
+  // 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)));
 
   // Only copied data should be left.
   std::vector<IconMapping> icon_mappings;
-  EXPECT_TRUE(
-      db.GetIconMappingsForPageURL(page_url, chrome::FAVICON, &icon_mappings));
+  EXPECT_TRUE(db.GetIconMappingsForPageURL(
+                  kept_page_url, chrome::FAVICON, &icon_mappings));
   EXPECT_EQ(1u, icon_mappings.size());
-  EXPECT_EQ(new_favicon_id, icon_mappings[0].icon_id);
-  EXPECT_EQ(page_url, icon_mappings[0].page_url);
+  EXPECT_EQ(kept_page_url, icon_mappings[0].page_url);
 
   std::vector<FaviconBitmap> favicon_bitmaps;
   EXPECT_TRUE(db.GetFaviconBitmaps(icon_mappings[0].icon_id, &favicon_bitmaps));
@@ -517,6 +453,9 @@
   EXPECT_EQ(kLargeSize, favicon_bitmaps[0].pixel_size);
 
   EXPECT_FALSE(db.GetFaviconIDForFaviconURL(unkept_url, false, NULL));
+
+  // Schema should be the same.
+  EXPECT_EQ(original_schema, db.db_.GetSchema());
 }
 
 // Tests that deleting a favicon deletes the favicon row and favicon bitmap
diff --git a/chrome/browser/history/top_sites.cc b/chrome/browser/history/top_sites.cc
index b1f947d..816f09c 100644
--- a/chrome/browser/history/top_sites.cc
+++ b/chrome/browser/history/top_sites.cc
@@ -4,10 +4,8 @@
 
 #include "chrome/browser/history/top_sites.h"
 
-#include "base/metrics/field_trial.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/history/top_sites_impl.h"
-#include "chrome/browser/history/top_sites_likely_impl.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/locale_settings.h"
@@ -34,12 +32,6 @@
 
 // static
 TopSites* TopSites::Create(Profile* profile, const base::FilePath& db_name) {
-  if (base::FieldTrialList::FindFullName("MostLikely") == "Likely_Client") {
-    // Experimental group. Enabled through a command-line flag.
-    TopSitesLikelyImpl* top_sites_likely_impl = new TopSitesLikelyImpl(profile);
-    top_sites_likely_impl->Init(db_name);
-    return top_sites_likely_impl;
-  }
   TopSitesImpl* top_sites_impl = new TopSitesImpl(profile);
   top_sites_impl->Init(db_name);
   return top_sites_impl;
diff --git a/chrome/browser/history/top_sites.h b/chrome/browser/history/top_sites.h
index 5cfe8ba..6d57d12 100644
--- a/chrome/browser/history/top_sites.h
+++ b/chrome/browser/history/top_sites.h
@@ -90,19 +90,6 @@
   virtual bool GetTemporaryPageThumbnailScore(const GURL& url,
                                               ThumbnailScore* score) = 0;
 
-  // Invoked from History if migration is needed. If this is invoked it will
-  // be before HistoryLoaded is invoked. Should be called from the UI thread.
-  virtual void MigrateFromHistory() = 0;
-
-  // Invoked with data from migrating thumbnails out of history. Should be
-  // called from the UI thread.
-  virtual void FinishHistoryMigration(const ThumbnailMigration& data) = 0;
-
-  // Invoked from history when it finishes loading. If MigrateFromHistory was
-  // not invoked at this point then we load from the top sites service. Should
-  // be called from the UI thread.
-  virtual void HistoryLoaded() = 0;
-
   // Asks TopSites to refresh what it thinks the top sites are. This may do
   // nothing. Should be called from the UI thread.
   virtual void SyncWithHistory() = 0;
diff --git a/chrome/browser/history/top_sites_backend.cc b/chrome/browser/history/top_sites_backend.cc
index 58bf38d..a186675 100644
--- a/chrome/browser/history/top_sites_backend.cc
+++ b/chrome/browser/history/top_sites_backend.cc
@@ -37,16 +37,14 @@
       const GetMostVisitedThumbnailsCallback& callback,
       CancelableTaskTracker* tracker) {
   scoped_refptr<MostVisitedThumbnails> thumbnails = new MostVisitedThumbnails();
-  bool* need_history_migration = new bool(false);
 
   tracker->PostTaskAndReply(
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB).get(),
       FROM_HERE,
       base::Bind(&TopSitesBackend::GetMostVisitedThumbnailsOnDBThread,
                  this,
-                 thumbnails,
-                 need_history_migration),
-      base::Bind(callback, thumbnails, base::Owned(need_history_migration)));
+                 thumbnails),
+      base::Bind(callback, thumbnails));
 }
 
 void TopSitesBackend::UpdateTopSites(const TopSitesDelta& delta) {
@@ -98,15 +96,12 @@
 }
 
 void TopSitesBackend::GetMostVisitedThumbnailsOnDBThread(
-    scoped_refptr<MostVisitedThumbnails> thumbnails,
-    bool* need_history_migration) {
+    scoped_refptr<MostVisitedThumbnails> thumbnails) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
 
-  *need_history_migration = false;
   if (db_) {
     db_->GetPageThumbnails(&(thumbnails->most_visited),
                            &(thumbnails->url_to_images_map));
-    *need_history_migration = db_->may_need_history_migration();
   }
 }
 
diff --git a/chrome/browser/history/top_sites_backend.h b/chrome/browser/history/top_sites_backend.h
index e77705f..cad49e1 100644
--- a/chrome/browser/history/top_sites_backend.h
+++ b/chrome/browser/history/top_sites_backend.h
@@ -28,8 +28,7 @@
  public:
   // The boolean parameter indicates if the DB existed on disk or needs to be
   // migrated.
-  typedef base::Callback<void(const scoped_refptr<MostVisitedThumbnails>&,
-                              const bool*)>
+  typedef base::Callback<void(const scoped_refptr<MostVisitedThumbnails>&)>
       GetMostVisitedThumbnailsCallback;
 
   TopSitesBackend();
@@ -74,8 +73,7 @@
 
   // Does the work of getting the most visted thumbnails.
   void GetMostVisitedThumbnailsOnDBThread(
-      scoped_refptr<MostVisitedThumbnails> thumbnails,
-      bool* need_history_migration);
+      scoped_refptr<MostVisitedThumbnails> thumbnails);
 
   // Updates top sites.
   void UpdateTopSitesOnDBThread(const TopSitesDelta& delta);
diff --git a/chrome/browser/history/top_sites_database.cc b/chrome/browser/history/top_sites_database.cc
index 6192a87..c87c108 100644
--- a/chrome/browser/history/top_sites_database.cc
+++ b/chrome/browser/history/top_sites_database.cc
@@ -18,7 +18,7 @@
 // should be able to read version 2 files just fine.
 static const int kVersionNumber = 2;
 
-TopSitesDatabase::TopSitesDatabase() : may_need_history_migration_(false) {
+TopSitesDatabase::TopSitesDatabase() {
 }
 
 TopSitesDatabase::~TopSitesDatabase() {
@@ -27,17 +27,12 @@
 bool TopSitesDatabase::Init(const base::FilePath& db_name) {
   bool file_existed = base::PathExists(db_name);
 
-  if (!file_existed)
-    may_need_history_migration_ = true;
-
   db_.reset(CreateDB(db_name));
   if (!db_)
     return false;
 
   bool does_meta_exist = sql::MetaTable::DoesTableExist(db_.get());
   if (!does_meta_exist && file_existed) {
-    may_need_history_migration_ = true;
-
     // If the meta file doesn't exist, this version is old. We could remove all
     // the entries as they are no longer applicable, but it's safest to just
     // remove the file and start over.
@@ -255,6 +250,7 @@
 // Caller should have a transaction open.
 void TopSitesDatabase::UpdatePageRankNoTransaction(
     const MostVisitedURL& url, int new_rank) {
+  DCHECK_GT(db_->transaction_nesting(), 0);
   int prev_rank = GetURLRank(url);
   if (prev_rank == -1) {
     LOG(WARNING) << "Updating rank of an unknown URL: " << url.url.spec();
@@ -296,7 +292,7 @@
 }
 
 bool TopSitesDatabase::GetPageThumbnail(const GURL& url,
-                                            Images* thumbnail) {
+                                        Images* thumbnail) {
   sql::Statement statement(db_->GetCachedStatement(
       SQL_FROM_HERE,
       "SELECT thumbnail, boring_score, good_clipping, at_top, last_updated "
diff --git a/chrome/browser/history/top_sites_database.h b/chrome/browser/history/top_sites_database.h
index 42e04ed..5823938 100644
--- a/chrome/browser/history/top_sites_database.h
+++ b/chrome/browser/history/top_sites_database.h
@@ -32,13 +32,6 @@
   // Returns true on success. If false, no other functions should be called.
   bool Init(const base::FilePath& db_name);
 
-  // Returns true if migration of top sites from history may be needed. A value
-  // of true means either migration is definitely needed (the top sites file is
-  // old) or doesn't exist (as would happen for a new user).
-  bool may_need_history_migration() const {
-    return may_need_history_migration_;
-  }
-
   // Thumbnails ----------------------------------------------------------------
 
   // Returns a list of all URLs currently in the table.
@@ -105,9 +98,6 @@
   scoped_ptr<sql::Connection> db_;
   sql::MetaTable meta_table_;
 
-  // See description above class.
-  bool may_need_history_migration_;
-
   DISALLOW_COPY_AND_ASSIGN(TopSitesDatabase);
 };
 
diff --git a/chrome/browser/history/top_sites_impl.cc b/chrome/browser/history/top_sites_impl.cc
index c8f0466..3a1077a 100644
--- a/chrome/browser/history/top_sites_impl.cc
+++ b/chrome/browser/history/top_sites_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/metrics/histogram.h"
 #include "base/logging.h"
 #include "base/md5.h"
 #include "base/memory/ref_counted_memory.h"
@@ -81,80 +82,12 @@
 // artifacts for these small sized, highly detailed images.
 static const int kTopSitesImageQuality = 100;
 
-namespace {
-
-// HistoryDBTask used during migration of thumbnails from history to top sites.
-// When run on the history thread it collects the top sites and the
-// corresponding thumbnails. When run back on the ui thread it calls into
-// TopSitesImpl::FinishHistoryMigration.
-class LoadThumbnailsFromHistoryTask : public HistoryDBTask {
- public:
-  LoadThumbnailsFromHistoryTask(TopSites* top_sites,
-                                int result_count)
-      : top_sites_(top_sites),
-        result_count_(result_count) {
-    // l10n_util isn't thread safe, so cache for use on the db thread.
-    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL));
-    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_WEBSTORE_URL));
-#if defined(OS_ANDROID)
-    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_MOBILE_WELCOME_URL));
-#endif
-  }
-
-  virtual bool RunOnDBThread(history::HistoryBackend* backend,
-                             history::HistoryDatabase* db) OVERRIDE {
-    // Get the most visited urls.
-    backend->QueryMostVisitedURLsImpl(result_count_,
-                                      kDaysOfHistory,
-                                      &data_.most_visited);
-
-    // And fetch the thumbnails.
-    for (size_t i = 0; i < data_.most_visited.size(); ++i) {
-      const GURL& url = data_.most_visited[i].url;
-      if (ShouldFetchThumbnailFor(url)) {
-        scoped_refptr<base::RefCountedBytes> data;
-        backend->GetPageThumbnailDirectly(url, &data);
-        data_.url_to_thumbnail_map[url] = data;
-      }
-    }
-    return true;
-  }
-
-  virtual void DoneRunOnMainThread() OVERRIDE {
-    top_sites_->FinishHistoryMigration(data_);
-  }
-
- private:
-  virtual ~LoadThumbnailsFromHistoryTask() {}
-
-  bool ShouldFetchThumbnailFor(const GURL& url) {
-    return ignore_urls_.find(url.spec()) == ignore_urls_.end();
-  }
-
-  // Set of URLs we don't load thumbnails for. This is created on the UI thread
-  // and used on the history thread.
-  std::set<std::string> ignore_urls_;
-
-  scoped_refptr<TopSites> top_sites_;
-
-  // Number of results to request from history.
-  const int result_count_;
-
-  ThumbnailMigration data_;
-
-  DISALLOW_COPY_AND_ASSIGN(LoadThumbnailsFromHistoryTask);
-};
-
-}  // namespace
-
 TopSitesImpl::TopSitesImpl(Profile* profile)
     : backend_(NULL),
       cache_(new TopSitesCache()),
       thread_safe_cache_(new TopSitesCache()),
       profile_(profile),
       last_num_urls_changed_(0),
-      history_state_(HISTORY_LOADING),
-      top_sites_state_(TOP_SITES_LOADING),
       loaded_(false) {
   if (!profile_)
     return;
@@ -183,16 +116,6 @@
       base::Bind(&TopSitesImpl::OnGotMostVisitedThumbnails,
                  base::Unretained(this)),
       &cancelable_task_tracker_);
-
-  // History may have already finished loading by the time we're created.
-  HistoryService* history =
-      HistoryServiceFactory::GetForProfileWithoutCreating(profile_);
-  if (history && history->backend_loaded()) {
-    if (history->needs_top_sites_migration())
-      MigrateFromHistory();
-    else
-      history_state_ = HISTORY_LOADED;
-  }
 }
 
 bool TopSitesImpl::SetPageThumbnail(const GURL& url,
@@ -340,71 +263,6 @@
   return -1;
 }
 
-void TopSitesImpl::MigrateFromHistory() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (history_state_ != HISTORY_LOADING) {
-    // This can happen if history was unloaded then loaded again.
-    return;
-  }
-
-  history_state_ = HISTORY_MIGRATING;
-  HistoryServiceFactory::GetForProfile(
-      profile_, Profile::EXPLICIT_ACCESS)->ScheduleDBTask(
-          new LoadThumbnailsFromHistoryTask(
-              this,
-              num_results_to_request_from_history()),
-          &history_consumer_);
-}
-
-void TopSitesImpl::FinishHistoryMigration(const ThumbnailMigration& data) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_EQ(history_state_, HISTORY_MIGRATING);
-
-  history_state_ = HISTORY_LOADED;
-
-  SetTopSites(data.most_visited);
-
-  for (size_t i = 0; i < data.most_visited.size(); ++i) {
-    URLToThumbnailMap::const_iterator image_i =
-        data.url_to_thumbnail_map.find(data.most_visited[i].url);
-    if (image_i != data.url_to_thumbnail_map.end()) {
-      SetPageThumbnailEncoded(
-          data.most_visited[i].url, image_i->second.get(), ThumbnailScore());
-    }
-  }
-
-  MoveStateToLoaded();
-
-  ResetThreadSafeImageCache();
-
-  // We've scheduled all the thumbnails and top sites to be written to the top
-  // sites db, but it hasn't happened yet. Schedule a request on the db thread
-  // that notifies us when done. When done we'll know everything was written and
-  // we can tell history to finish its part of migration.
-  backend_->DoEmptyRequest(
-      base::Bind(&TopSitesImpl::OnHistoryMigrationWrittenToDisk,
-                 base::Unretained(this)),
-      &cancelable_task_tracker_);
-}
-
-void TopSitesImpl::HistoryLoaded() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (history_state_ != HISTORY_MIGRATING) {
-    // No migration from history is needed.
-    history_state_ = HISTORY_LOADED;
-    if (top_sites_state_ == TOP_SITES_LOADED_WAITING_FOR_HISTORY) {
-      // TopSites thought it needed migration, but it really didn't. This
-      // typically happens the first time a profile is run with Top Sites
-      // enabled
-      SetTopSites(MostVisitedURLList());
-      MoveStateToLoaded();
-    }
-  }
-  // else case can happen if history is unloaded, then loaded again.
-}
-
 void TopSitesImpl::SyncWithHistory() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   if (loaded_ && temp_images_.size()) {
@@ -691,6 +549,13 @@
 
 void TopSitesImpl::ApplyBlacklist(const MostVisitedURLList& urls,
                                   MostVisitedURLList* out) {
+  // Log the number of times ApplyBlacklist is called so we can compute the
+  // average number of blacklisted items per user.
+  const DictionaryValue* blacklist =
+      profile_->GetPrefs()->GetDictionary(prefs::kNtpMostVisitedURLsBlacklist);
+  UMA_HISTOGRAM_BOOLEAN("TopSites.NumberOfApplyBlacklist", true);
+  UMA_HISTOGRAM_COUNTS_100("TopSites.NumberOfBlacklistedItems",
+      (blacklist ? blacklist->size() : 0));
   for (size_t i = 0; i < urls.size() && i < kTopSitesNumber; ++i) {
     if (!IsBlacklisted(urls[i].url))
       out->push_back(urls[i]);
@@ -880,54 +745,23 @@
   timer_.Start(FROM_HERE, delta, this, &TopSitesImpl::TimerFired);
 }
 
-void TopSitesImpl::OnHistoryMigrationWrittenToDisk() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (!profile_)
-    return;
-
-  HistoryService* history = HistoryServiceFactory::GetForProfile(
-      profile_, Profile::EXPLICIT_ACCESS);
-  if (history)
-    history->OnTopSitesReady();
-}
-
 void TopSitesImpl::OnGotMostVisitedThumbnails(
-    const scoped_refptr<MostVisitedThumbnails>& thumbnails,
-    const bool* need_history_migration) {
+    const scoped_refptr<MostVisitedThumbnails>& thumbnails) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_EQ(top_sites_state_, TOP_SITES_LOADING);
 
-  if (!*need_history_migration) {
-    top_sites_state_ = TOP_SITES_LOADED;
+  // Set the top sites directly in the cache so that SetTopSites diffs
+  // correctly.
+  cache_->SetTopSites(thumbnails->most_visited);
+  SetTopSites(thumbnails->most_visited);
+  cache_->SetThumbnails(thumbnails->url_to_images_map);
 
-    // Set the top sites directly in the cache so that SetTopSites diffs
-    // correctly.
-    cache_->SetTopSites(thumbnails->most_visited);
-    SetTopSites(thumbnails->most_visited);
-    cache_->SetThumbnails(thumbnails->url_to_images_map);
+  ResetThreadSafeImageCache();
 
-    ResetThreadSafeImageCache();
+  MoveStateToLoaded();
 
-    MoveStateToLoaded();
-
-    // Start a timer that refreshes top sites from history.
-    RestartQueryForTopSitesTimer(
-        base::TimeDelta::FromSeconds(kUpdateIntervalSecs));
-  } else {
-    // The top sites file didn't exist or is the wrong version. We need to wait
-    // for history to finish loading to know if we really needed to migrate.
-    if (history_state_ == HISTORY_LOADED) {
-      top_sites_state_ = TOP_SITES_LOADED;
-      SetTopSites(MostVisitedURLList());
-      MoveStateToLoaded();
-    } else {
-      top_sites_state_ = TOP_SITES_LOADED_WAITING_FOR_HISTORY;
-      // Ask for history just in case it hasn't been loaded yet. When history
-      // finishes loading we'll do migration and/or move to loaded.
-      HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
-    }
-  }
+  // Start a timer that refreshes top sites from history.
+  RestartQueryForTopSitesTimer(
+      base::TimeDelta::FromSeconds(kUpdateIntervalSecs));
 }
 
 void TopSitesImpl::OnTopSitesAvailableFromHistory(
diff --git a/chrome/browser/history/top_sites_impl.h b/chrome/browser/history/top_sites_impl.h
index 025ac4d..678bf63 100644
--- a/chrome/browser/history/top_sites_impl.h
+++ b/chrome/browser/history/top_sites_impl.h
@@ -70,9 +70,6 @@
                                      ThumbnailScore* score) OVERRIDE;
   virtual bool GetTemporaryPageThumbnailScore(const GURL& url,
                                               ThumbnailScore* score) OVERRIDE;
-  virtual void MigrateFromHistory() OVERRIDE;
-  virtual void FinishHistoryMigration(const ThumbnailMigration& data) OVERRIDE;
-  virtual void HistoryLoaded() OVERRIDE;
   virtual void SyncWithHistory() OVERRIDE;
   virtual bool HasBlacklistedItems() const OVERRIDE;
   virtual void AddBlacklistedURL(const GURL& url) OVERRIDE;
@@ -110,34 +107,6 @@
                               const MostVisitedURLList& new_list,
                               TopSitesDelta* delta);
 
-  // Enumeration of the possible states history can be in. These values do not
-  // necessarily reflect the loaded state of history. In particular if the
-  // history backend is unloaded |history_state_| may be HISTORY_LOADED.
-  enum HistoryLoadState {
-    // We're waiting for history to finish loading.
-    HISTORY_LOADING,
-
-    // History finished loading and we need to migrate top sites out of history.
-    HISTORY_MIGRATING,
-
-    // History is loaded.
-    HISTORY_LOADED
-  };
-
-  // Enumeration of possible states the top sites backend can be in.
-  enum TopSitesLoadState {
-    // We're waiting for the backend to finish loading.
-    TOP_SITES_LOADING,
-
-    // The backend finished loading, but we may need to migrate. This is true if
-    // the top sites db didn't exist, or if the db existed but is from an old
-    // version.
-    TOP_SITES_LOADED_WAITING_FOR_HISTORY,
-
-    // Top sites is loaded.
-    TOP_SITES_LOADED
-  };
-
   // Sets the thumbnail without writing to the database. Useful when
   // reading last known top sites from the DB.
   // Returns true if the thumbnail was set, false if the existing one is better.
@@ -215,16 +184,10 @@
   // Stops and starts timer with a delay of |delta|.
   void RestartQueryForTopSitesTimer(base::TimeDelta delta);
 
-  // Callback after TopSitesBackend has finished migration. This tells history
-  // to finish it's side of migration (nuking thumbnails on disk). Should be
-  // called from the UI thread.
-  void OnHistoryMigrationWrittenToDisk();
-
   // Callback from TopSites with the top sites/thumbnails. Should be called
   // from the UI thread.
   void OnGotMostVisitedThumbnails(
-      const scoped_refptr<MostVisitedThumbnails>& thumbnails,
-      const bool* need_history_migration);
+      const scoped_refptr<MostVisitedThumbnails>& thumbnails);
 
   // Called when history service returns a list of top URLs.
   void OnTopSitesAvailableFromHistory(CancelableRequestProvider::Handle handle,
@@ -273,12 +236,6 @@
   // SetTopSites call.
   TempImages temp_images_;
 
-  // See description above HistoryLoadState.
-  HistoryLoadState history_state_;
-
-  // See description above TopSitesLoadState.
-  TopSitesLoadState top_sites_state_;
-
   // URL List of prepopulated page.
   std::vector<GURL> prepopulated_page_urls_;
 
diff --git a/chrome/browser/history/top_sites_impl_unittest.cc b/chrome/browser/history/top_sites_impl_unittest.cc
index a0b9f22..734132f 100644
--- a/chrome/browser/history/top_sites_impl_unittest.cc
+++ b/chrome/browser/history/top_sites_impl_unittest.cc
@@ -3,42 +3,23 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/format_macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
-#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/history/history_backend.h"
-#include "chrome/browser/history/history_database.h"
 #include "chrome/browser/history/history_db_task.h"
-#include "chrome/browser/history/history_marshaling.h"
-#include "chrome/browser/history/history_notifications.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/history/history_types.h"
 #include "chrome/browser/history/history_unittest_base.h"
-#include "chrome/browser/history/top_sites_backend.h"
 #include "chrome/browser/history/top_sites_cache.h"
-#include "chrome/browser/history/top_sites_database.h"
 #include "chrome/browser/history/top_sites_impl.h"
-#include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
 #include "chrome/common/cancelable_task_tracker.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_profile.h"
-#include "chrome/tools/profiles/thumbnail-inl.h"
 #include "content/public/test/test_browser_thread.h"
-#include "content/public/test/test_utils.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "url/gurl.h"
 
@@ -341,64 +322,6 @@
   DISALLOW_COPY_AND_ASSIGN(TopSitesImplTest);
 };  // Class TopSitesImplTest
 
-class TopSitesMigrationTest : public TopSitesImplTest {
- public:
-  TopSitesMigrationTest() {}
-
-  virtual void SetUp() {
-    TopSitesImplTest::SetUp();
-
-    base::FilePath data_path;
-    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
-    data_path = data_path.AppendASCII("top_sites");
-
-    // Set up history and thumbnails as they would be before migration.
-    ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-        data_path.AppendASCII("history.19.sql"),
-        profile()->GetPath().Append(chrome::kHistoryFilename)));
-    ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-        data_path.AppendASCII("thumbnails.3.sql"),
-        profile()->GetPath().Append(chrome::kThumbnailsFilename)));
-
-    ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-    profile()->CreateTopSites();
-    profile()->BlockUntilTopSitesLoaded();
-  }
-
-  // Returns true if history and top sites should be created in SetUp.
-  virtual bool CreateHistoryAndTopSites() OVERRIDE {
-    return false;
-  }
-
- protected:
-  // Assertions for the migration test. This is extracted into a standalone
-  // method so that it can be invoked twice.
-  void MigrationAssertions() {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    // We shouldn't have gotten a callback.
-    EXPECT_EQ(1, querier.number_of_callbacks());
-
-    // The data we loaded should contain google and yahoo.
-    ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(GURL("http://google.com/"), querier.urls()[0].url);
-    EXPECT_EQ(GURL("http://yahoo.com/"), querier.urls()[1].url);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
-
-    SkBitmap goog_thumbnail = GetThumbnail(GURL("http://google.com/"));
-    EXPECT_EQ(1, goog_thumbnail.width());
-
-    SkBitmap yahoo_thumbnail = GetThumbnail(GURL("http://yahoo.com/"));
-    EXPECT_EQ(2, yahoo_thumbnail.width());
-
-    // Favicon assertions are handled in ThumbnailDatabase.
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TopSitesMigrationTest);
-};
-
 // Helper function for appending a URL to a vector of "most visited" URLs,
 // using the default values for everything but the URL.
 static void AppendMostVisitedURL(std::vector<MostVisitedURL>* list,
@@ -899,27 +822,6 @@
   EXPECT_EQ(1, GetUpdateDelay().InMinutes());
 }
 
-TEST_F(TopSitesMigrationTest, Migrate) {
-  EXPECT_TRUE(IsTopSitesLoaded());
-
-  // Make sure the data was migrated to top sites.
-  ASSERT_NO_FATAL_FAILURE(MigrationAssertions());
-
-  // We need to wait for top sites and history to finish processing requests.
-  WaitForTopSites();
-  WaitForHistory();
-
-  // Make sure there is no longer a Thumbnails file on disk.
-  ASSERT_FALSE(base::PathExists(
-                   profile()->GetPath().Append(chrome::kThumbnailsFilename)));
-
-  // Recreate top sites and make sure everything is still there.
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  RecreateTopSitesAndBlock();
-
-  ASSERT_NO_FATAL_FAILURE(MigrationAssertions());
-}
-
 // Verifies that callbacks are notified correctly if requested before top sites
 // has loaded.
 TEST_F(TopSitesImplTest, NotifyCallbacksWhenLoaded) {
@@ -1191,77 +1093,4 @@
   ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
 }
 
-// Makes sure creating top sites before history is created works.
-TEST_F(TopSitesImplTest, CreateTopSitesThenHistory) {
-  profile()->DestroyTopSites();
-  profile()->DestroyHistoryService();
-
-  // Remove the TopSites file. This forces TopSites to wait until history loads
-  // before TopSites is considered loaded.
-  sql::Connection::Delete(
-      profile()->GetPath().Append(chrome::kTopSitesFilename));
-
-  // Create TopSites, but not History.
-  profile()->CreateTopSites();
-  WaitForTopSites();
-  EXPECT_FALSE(IsTopSitesLoaded());
-
-  // Load history, which should make TopSites finish loading too.
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  profile()->BlockUntilTopSitesLoaded();
-  EXPECT_TRUE(IsTopSitesLoaded());
-}
-
-class TopSitesUnloadTest : public TopSitesImplTest {
- public:
-  TopSitesUnloadTest() {}
-
-  virtual bool CreateHistoryAndTopSites() OVERRIDE {
-    return false;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TopSitesUnloadTest);
-};
-
-// Makes sure if history is unloaded after topsites is loaded we don't hit any
-// assertions.
-TEST_F(TopSitesUnloadTest, UnloadHistoryTest) {
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  profile()->CreateTopSites();
-  profile()->BlockUntilTopSitesLoaded();
-  HistoryServiceFactory::GetForProfile(
-      profile(), Profile::EXPLICIT_ACCESS)->UnloadBackend();
-  profile()->BlockUntilHistoryProcessesPendingRequests();
-}
-
-// Makes sure if history (with migration code) is unloaded after topsites is
-// loaded we don't hit any assertions.
-TEST_F(TopSitesUnloadTest, UnloadWithMigration) {
-  // Set up history and thumbnails as they would be before migration.
-  base::FilePath data_path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
-  data_path = data_path.AppendASCII("top_sites");
-  ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-      data_path.AppendASCII("history.19.sql"),
-      profile()->GetPath().Append(chrome::kHistoryFilename)));
-  ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-      data_path.AppendASCII("thumbnails.3.sql"),
-      profile()->GetPath().Append(chrome::kThumbnailsFilename)));
-
-  // Create history and block until it's loaded.
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  profile()->BlockUntilHistoryProcessesPendingRequests();
-
-  // Create top sites and unload history.
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_TOP_SITES_LOADED,
-      content::Source<Profile>(profile()));
-  profile()->CreateTopSites();
-  HistoryServiceFactory::GetForProfile(
-      profile(), Profile::EXPLICIT_ACCESS)->UnloadBackend();
-  profile()->BlockUntilHistoryProcessesPendingRequests();
-  observer.Wait();
-}
-
 }  // namespace history
diff --git a/chrome/browser/history/top_sites_likely_impl.cc b/chrome/browser/history/top_sites_likely_impl.cc
deleted file mode 100644
index 1b7e277..0000000
--- a/chrome/browser/history/top_sites_likely_impl.cc
+++ /dev/null
@@ -1,949 +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/browser/history/top_sites_likely_impl.h"
-
-#include <algorithm>
-#include <set>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/logging.h"
-#include "base/md5.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task_runner.h"
-#include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/history/history_backend.h"
-#include "chrome/browser/history/history_db_task.h"
-#include "chrome/browser/history/history_notifications.h"
-#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/profiles/profile.h"
-#include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
-#include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/thumbnail_score.h"
-#include "content/public/browser/browser_thread.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/notification_service.h"
-#include "content/public/browser/web_contents.h"
-#include "grit/locale_settings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/layout.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image_util.h"
-
-using base::DictionaryValue;
-using content::BrowserThread;
-using content::NavigationController;
-
-namespace history {
-
-namespace {
-
-void RunOrPostGetMostVisitedURLsCallback(
-    base::TaskRunner* task_runner,
-    const TopSitesLikelyImpl::GetMostVisitedURLsCallback& callback,
-    const MostVisitedURLList& urls) {
-  if (task_runner->RunsTasksOnCurrentThread())
-    callback.Run(urls);
-  else
-    task_runner->PostTask(FROM_HERE, base::Bind(callback, urls));
-}
-
-}  // namespace
-
-// How many top sites to store in the cache.
-static const size_t kTopSitesNumber = 20;
-
-// Max number of temporary images we'll cache. See comment above
-// temp_images_ for details.
-static const size_t kMaxTempTopImages = 8;
-
-static const int kDaysOfHistory = 90;
-// Time from startup to first HistoryService query.
-static const int64 kUpdateIntervalSecs = 15;
-// Intervals between requests to HistoryService.
-static const int64 kMinUpdateIntervalMinutes = 1;
-static const int64 kMaxUpdateIntervalMinutes = 60;
-
-// Use 100 quality (highest quality) because we're very sensitive to
-// artifacts for these small sized, highly detailed images.
-static const int kTopSitesImageQuality = 100;
-
-namespace {
-
-// HistoryDBTask used during migration of thumbnails from history to top sites.
-// When run on the history thread it collects the top sites and the
-// corresponding thumbnails. When run back on the ui thread it calls into
-// TopSitesLikelyImpl::FinishHistoryMigration.
-class LoadThumbnailsFromHistoryTask : public HistoryDBTask {
- public:
-  LoadThumbnailsFromHistoryTask(TopSites* top_sites,
-                                int result_count)
-      : top_sites_(top_sites),
-        result_count_(result_count) {
-    // l10n_util isn't thread safe, so cache for use on the db thread.
-    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_CHROME_WELCOME_URL));
-    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_WEBSTORE_URL));
-#if defined(OS_ANDROID)
-    ignore_urls_.insert(l10n_util::GetStringUTF8(IDS_MOBILE_WELCOME_URL));
-#endif
-  }
-
-  virtual bool RunOnDBThread(history::HistoryBackend* backend,
-                             history::HistoryDatabase* db) OVERRIDE {
-    // Get the most visited urls.
-    backend->QueryMostVisitedURLsImpl(result_count_,
-                                      kDaysOfHistory,
-                                      &data_.most_visited);
-
-    // And fetch the thumbnails.
-    for (size_t i = 0; i < data_.most_visited.size(); ++i) {
-      const GURL& url = data_.most_visited[i].url;
-      if (ShouldFetchThumbnailFor(url)) {
-        scoped_refptr<base::RefCountedBytes> data;
-        backend->GetPageThumbnailDirectly(url, &data);
-        data_.url_to_thumbnail_map[url] = data;
-      }
-    }
-    return true;
-  }
-
-  virtual void DoneRunOnMainThread() OVERRIDE {
-    top_sites_->FinishHistoryMigration(data_);
-  }
-
- private:
-  virtual ~LoadThumbnailsFromHistoryTask() {}
-
-  bool ShouldFetchThumbnailFor(const GURL& url) {
-    return ignore_urls_.find(url.spec()) == ignore_urls_.end();
-  }
-
-  // Set of URLs we don't load thumbnails for. This is created on the UI thread
-  // and used on the history thread.
-  std::set<std::string> ignore_urls_;
-
-  scoped_refptr<TopSites> top_sites_;
-
-  // Number of results to request from history.
-  const int result_count_;
-
-  ThumbnailMigration data_;
-
-  DISALLOW_COPY_AND_ASSIGN(LoadThumbnailsFromHistoryTask);
-};
-
-}  // namespace
-
-TopSitesLikelyImpl::TopSitesLikelyImpl(Profile* profile)
-    : backend_(NULL),
-      cache_(new TopSitesCache()),
-      thread_safe_cache_(new TopSitesCache()),
-      profile_(profile),
-      last_num_urls_changed_(0),
-      history_state_(HISTORY_LOADING),
-      top_sites_state_(TOP_SITES_LOADING),
-      loaded_(false) {
-  if (!profile_)
-    return;
-
-  if (content::NotificationService::current()) {
-    registrar_.Add(this, chrome::NOTIFICATION_HISTORY_URLS_DELETED,
-                   content::Source<Profile>(profile_));
-    // Listen for any nav commits. We'll ignore those not related to this
-    // profile when we get the notification.
-    registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
-                   content::NotificationService::AllSources());
-  }
-  for (size_t i = 0; i < arraysize(kPrepopulatedPages); i++) {
-    int url_id = kPrepopulatedPages[i].url_id;
-    prepopulated_page_urls_.push_back(
-        GURL(l10n_util::GetStringUTF8(url_id)));
-  }
-}
-
-void TopSitesLikelyImpl::Init(const base::FilePath& db_name) {
-  // Create the backend here, rather than in the constructor, so that
-  // unit tests that do not need the backend can run without a problem.
-  backend_ = new TopSitesBackend;
-  backend_->Init(db_name);
-  backend_->GetMostVisitedThumbnails(
-      base::Bind(&TopSitesLikelyImpl::OnGotMostVisitedThumbnails,
-                 base::Unretained(this)),
-      &cancelable_task_tracker_);
-
-  // History may have already finished loading by the time we're created.
-  HistoryService* history =
-      HistoryServiceFactory::GetForProfileWithoutCreating(profile_);
-  if (history && history->backend_loaded()) {
-    if (history->needs_top_sites_migration())
-      MigrateFromHistory();
-    else
-      history_state_ = HISTORY_LOADED;
-  }
-}
-
-bool TopSitesLikelyImpl::SetPageThumbnail(const GURL& url,
-                                    const gfx::Image& thumbnail,
-                                    const ThumbnailScore& score) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (!loaded_) {
-    // TODO(sky): I need to cache these and apply them after the load
-    // completes.
-    return false;
-  }
-
-  bool add_temp_thumbnail = false;
-  if (!IsKnownURL(url)) {
-    if (!IsFull()) {
-      add_temp_thumbnail = true;
-    } else {
-      return false;  // This URL is not known to us.
-    }
-  }
-
-  if (!HistoryService::CanAddURL(url))
-    return false;  // It's not a real webpage.
-
-  scoped_refptr<base::RefCountedBytes> thumbnail_data;
-  if (!EncodeBitmap(thumbnail, &thumbnail_data))
-    return false;
-
-  if (add_temp_thumbnail) {
-    // Always remove the existing entry and then add it back. That way if we end
-    // up with too many temp thumbnails we'll prune the oldest first.
-    RemoveTemporaryThumbnailByURL(url);
-    AddTemporaryThumbnail(url, thumbnail_data.get(), score);
-    return true;
-  }
-
-  return SetPageThumbnailEncoded(url, thumbnail_data.get(), score);
-}
-
-bool TopSitesLikelyImpl::SetPageThumbnailToJPEGBytes(
-    const GURL& url,
-    const base::RefCountedMemory* memory,
-    const ThumbnailScore& score) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (!loaded_) {
-    // TODO(sky): I need to cache these and apply them after the load
-    // completes.
-    return false;
-  }
-
-  bool add_temp_thumbnail = false;
-  if (!IsKnownURL(url)) {
-    if (!IsFull()) {
-      add_temp_thumbnail = true;
-    } else {
-      return false;  // This URL is not known to us.
-    }
-  }
-
-  if (!HistoryService::CanAddURL(url))
-    return false;  // It's not a real webpage.
-
-  if (add_temp_thumbnail) {
-    // Always remove the existing entry and then add it back. That way if we end
-    // up with too many temp thumbnails we'll prune the oldest first.
-    RemoveTemporaryThumbnailByURL(url);
-    AddTemporaryThumbnail(url, memory, score);
-    return true;
-  }
-
-  return SetPageThumbnailEncoded(url, memory, score);
-}
-
-// WARNING: this function may be invoked on any thread.
-void TopSitesLikelyImpl::GetMostVisitedURLs(
-    const GetMostVisitedURLsCallback& callback) {
-  MostVisitedURLList filtered_urls;
-  {
-    base::AutoLock lock(lock_);
-    if (!loaded_) {
-      // A request came in before we finished loading. Store the callback and
-      // we'll run it on current thread when we finish loading.
-      pending_callbacks_.push_back(
-          base::Bind(&RunOrPostGetMostVisitedURLsCallback,
-                     base::MessageLoopProxy::current(),
-                     callback));
-      return;
-    }
-    filtered_urls = thread_safe_cache_->top_sites();
-  }
-  callback.Run(filtered_urls);
-}
-
-bool TopSitesLikelyImpl::GetPageThumbnail(
-    const GURL& url, scoped_refptr<base::RefCountedMemory>* bytes) {
-  // WARNING: this may be invoked on any thread.
-  {
-    base::AutoLock lock(lock_);
-    if (thread_safe_cache_->GetPageThumbnail(url, bytes))
-      return true;
-  }
-
-  // Resource bundle is thread safe.
-  for (size_t i = 0; i < arraysize(kPrepopulatedPages); i++) {
-    if (url == prepopulated_page_urls_[i]) {
-      *bytes = ResourceBundle::GetSharedInstance().
-          LoadDataResourceBytesForScale(
-              kPrepopulatedPages[i].thumbnail_id,
-              ui::SCALE_FACTOR_100P);
-      return true;
-    }
-  }
-
-  return false;
-}
-
-bool TopSitesLikelyImpl::GetPageThumbnailScore(const GURL& url,
-                                         ThumbnailScore* score) {
-  // WARNING: this may be invoked on any thread.
-  base::AutoLock lock(lock_);
-  return thread_safe_cache_->GetPageThumbnailScore(url, score);
-}
-
-bool TopSitesLikelyImpl::GetTemporaryPageThumbnailScore(const GURL& url,
-                                                  ThumbnailScore* score) {
-  for (TempImages::iterator i = temp_images_.begin(); i != temp_images_.end();
-       ++i) {
-    if (i->first == url) {
-      *score = i->second.thumbnail_score;
-      return true;
-    }
-  }
-  return false;
-}
-
-
-// Returns the index of |url| in |urls|, or -1 if not found.
-static int IndexOf(const MostVisitedURLList& urls, const GURL& url) {
-  for (size_t i = 0; i < urls.size(); i++) {
-    if (urls[i].url == url)
-      return i;
-  }
-  return -1;
-}
-
-void TopSitesLikelyImpl::MigrateFromHistory() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (history_state_ != HISTORY_LOADING) {
-    // This can happen if history was unloaded then loaded again.
-    return;
-  }
-
-  history_state_ = HISTORY_MIGRATING;
-  HistoryServiceFactory::GetForProfile(
-      profile_, Profile::EXPLICIT_ACCESS)->ScheduleDBTask(
-          new LoadThumbnailsFromHistoryTask(
-              this,
-              num_results_to_request_from_history()),
-          &history_consumer_);
-}
-
-void TopSitesLikelyImpl::FinishHistoryMigration(
-    const ThumbnailMigration& data) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_EQ(history_state_, HISTORY_MIGRATING);
-
-  history_state_ = HISTORY_LOADED;
-
-  SetTopSites(data.most_visited);
-
-  for (size_t i = 0; i < data.most_visited.size(); ++i) {
-    URLToThumbnailMap::const_iterator image_i =
-        data.url_to_thumbnail_map.find(data.most_visited[i].url);
-    if (image_i != data.url_to_thumbnail_map.end()) {
-      SetPageThumbnailEncoded(
-          data.most_visited[i].url, image_i->second.get(), ThumbnailScore());
-    }
-  }
-
-  MoveStateToLoaded();
-
-  ResetThreadSafeImageCache();
-
-  // We've scheduled all the thumbnails and top sites to be written to the top
-  // sites db, but it hasn't happened yet. Schedule a request on the db thread
-  // that notifies us when done. When done we'll know everything was written and
-  // we can tell history to finish its part of migration.
-  backend_->DoEmptyRequest(
-      base::Bind(&TopSitesLikelyImpl::OnHistoryMigrationWrittenToDisk,
-                 base::Unretained(this)),
-      &cancelable_task_tracker_);
-}
-
-void TopSitesLikelyImpl::HistoryLoaded() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (history_state_ != HISTORY_MIGRATING) {
-    // No migration from history is needed.
-    history_state_ = HISTORY_LOADED;
-    if (top_sites_state_ == TOP_SITES_LOADED_WAITING_FOR_HISTORY) {
-      // TopSites thought it needed migration, but it really didn't. This
-      // typically happens the first time a profile is run with Top Sites
-      // enabled
-      SetTopSites(MostVisitedURLList());
-      MoveStateToLoaded();
-    }
-  }
-  // else case can happen if history is unloaded, then loaded again.
-}
-
-void TopSitesLikelyImpl::SyncWithHistory() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (loaded_ && temp_images_.size()) {
-    // If we have temporary thumbnails it means there isn't much data, and most
-    // likely the user is first running Chrome. During this time we throttle
-    // updating from history by 30 seconds. If the user creates a new tab page
-    // during this window of time we force updating from history so that the new
-    // tab page isn't so far out of date.
-    timer_.Stop();
-    StartQueryForMostVisited();
-  }
-}
-
-bool TopSitesLikelyImpl::HasBlacklistedItems() const {
-  const DictionaryValue* blacklist =
-      profile_->GetPrefs()->GetDictionary(prefs::kNtpMostVisitedURLsBlacklist);
-  return blacklist && !blacklist->empty();
-}
-
-void TopSitesLikelyImpl::AddBlacklistedURL(const GURL& url) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  Value* dummy = Value::CreateNullValue();
-  {
-    DictionaryPrefUpdate update(profile_->GetPrefs(),
-                                prefs::kNtpMostVisitedURLsBlacklist);
-    DictionaryValue* blacklist = update.Get();
-    blacklist->SetWithoutPathExpansion(GetURLHash(url), dummy);
-  }
-
-  ResetThreadSafeCache();
-  NotifyTopSitesChanged();
-}
-
-void TopSitesLikelyImpl::RemoveBlacklistedURL(const GURL& url) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  {
-    DictionaryPrefUpdate update(profile_->GetPrefs(),
-                                prefs::kNtpMostVisitedURLsBlacklist);
-    DictionaryValue* blacklist = update.Get();
-    blacklist->RemoveWithoutPathExpansion(GetURLHash(url), NULL);
-  }
-  ResetThreadSafeCache();
-  NotifyTopSitesChanged();
-}
-
-bool TopSitesLikelyImpl::IsBlacklisted(const GURL& url) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  const DictionaryValue* blacklist =
-      profile_->GetPrefs()->GetDictionary(prefs::kNtpMostVisitedURLsBlacklist);
-  return blacklist && blacklist->HasKey(GetURLHash(url));
-}
-
-void TopSitesLikelyImpl::ClearBlacklistedURLs() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  {
-    DictionaryPrefUpdate update(profile_->GetPrefs(),
-                                prefs::kNtpMostVisitedURLsBlacklist);
-    DictionaryValue* blacklist = update.Get();
-    blacklist->Clear();
-  }
-  ResetThreadSafeCache();
-  NotifyTopSitesChanged();
-}
-
-void TopSitesLikelyImpl::Shutdown() {
-  profile_ = NULL;
-  // Cancel all requests so that the service doesn't callback to us after we've
-  // invoked Shutdown (this could happen if we have a pending request and
-  // Shutdown is invoked).
-  history_consumer_.CancelAllRequests();
-  backend_->Shutdown();
-}
-
-// static
-void TopSitesLikelyImpl::DiffMostVisited(const MostVisitedURLList& old_list,
-                                   const MostVisitedURLList& new_list,
-                                   TopSitesDelta* delta) {
-  // Add all the old URLs for quick lookup. This maps URLs to the corresponding
-  // index in the input.
-  std::map<GURL, size_t> all_old_urls;
-  for (size_t i = 0; i < old_list.size(); i++)
-    all_old_urls[old_list[i].url] = i;
-
-  // Check all the URLs in the new set to see which ones are new or just moved.
-  // When we find a match in the old set, we'll reset its index to our special
-  // marker. This allows us to quickly identify the deleted ones in a later
-  // pass.
-  const size_t kAlreadyFoundMarker = static_cast<size_t>(-1);
-  for (size_t i = 0; i < new_list.size(); i++) {
-    std::map<GURL, size_t>::iterator found = all_old_urls.find(new_list[i].url);
-    if (found == all_old_urls.end()) {
-      MostVisitedURLWithRank added;
-      added.url = new_list[i];
-      added.rank = i;
-      delta->added.push_back(added);
-    } else {
-      if (found->second != i) {
-        MostVisitedURLWithRank moved;
-        moved.url = new_list[i];
-        moved.rank = i;
-        delta->moved.push_back(moved);
-      }
-      found->second = kAlreadyFoundMarker;
-    }
-  }
-
-  // Any member without the special marker in the all_old_urls list means that
-  // there wasn't a "new" URL that mapped to it, so it was deleted.
-  for (std::map<GURL, size_t>::const_iterator i = all_old_urls.begin();
-       i != all_old_urls.end(); ++i) {
-    if (i->second != kAlreadyFoundMarker)
-      delta->deleted.push_back(old_list[i->second]);
-  }
-}
-
-CancelableRequestProvider::Handle
-    TopSitesLikelyImpl::StartQueryForMostVisited() {
-  DCHECK(loaded_);
-  if (!profile_)
-    return 0;
-
-  HistoryService* hs = HistoryServiceFactory::GetForProfile(
-      profile_, Profile::EXPLICIT_ACCESS);
-  // |hs| may be null during unit tests.
-  if (hs) {
-    return hs->QueryMostVisitedURLs(
-        num_results_to_request_from_history(),
-        kDaysOfHistory,
-        &history_consumer_,
-        base::Bind(&TopSitesLikelyImpl::OnTopSitesAvailableFromHistory,
-                   base::Unretained(this)));
-  }
-  return 0;
-}
-
-bool TopSitesLikelyImpl::IsKnownURL(const GURL& url) {
-  return loaded_ && cache_->IsKnownURL(url);
-}
-
-const std::string& TopSitesLikelyImpl::GetCanonicalURLString(
-    const GURL& url) const {
-  return cache_->GetCanonicalURL(url).spec();
-}
-
-bool TopSitesLikelyImpl::IsFull() {
-  return loaded_ && cache_->top_sites().size() >= kTopSitesNumber;
-}
-
-TopSitesLikelyImpl::~TopSitesLikelyImpl() {
-}
-
-bool TopSitesLikelyImpl::SetPageThumbnailNoDB(
-    const GURL& url,
-    const base::RefCountedMemory* thumbnail_data,
-    const ThumbnailScore& score) {
-  // This should only be invoked when we know about the url.
-  DCHECK(cache_->IsKnownURL(url));
-
-  const MostVisitedURL& most_visited =
-      cache_->top_sites()[cache_->GetURLIndex(url)];
-  Images* image = cache_->GetImage(url);
-
-  // When comparing the thumbnail scores, we need to take into account the
-  // redirect hops, which are not generated when the thumbnail is because the
-  // redirects weren't known. We fill that in here since we know the redirects.
-  ThumbnailScore new_score_with_redirects(score);
-  new_score_with_redirects.redirect_hops_from_dest =
-      GetRedirectDistanceForURL(most_visited, url);
-
-  if (!ShouldReplaceThumbnailWith(image->thumbnail_score,
-                                  new_score_with_redirects) &&
-      image->thumbnail.get())
-    return false;  // The one we already have is better.
-
-  image->thumbnail = const_cast<base::RefCountedMemory*>(thumbnail_data);
-  image->thumbnail_score = new_score_with_redirects;
-
-  ResetThreadSafeImageCache();
-  return true;
-}
-
-bool TopSitesLikelyImpl::SetPageThumbnailEncoded(
-    const GURL& url,
-    const base::RefCountedMemory* thumbnail,
-    const ThumbnailScore& score) {
-  if (!SetPageThumbnailNoDB(url, thumbnail, score))
-    return false;
-
-  // Update the database.
-  if (!cache_->IsKnownURL(url))
-    return false;
-
-  size_t index = cache_->GetURLIndex(url);
-  const MostVisitedURL& most_visited = cache_->top_sites()[index];
-  backend_->SetPageThumbnail(most_visited,
-                             index,
-                             *(cache_->GetImage(most_visited.url)));
-  return true;
-}
-
-// static
-bool TopSitesLikelyImpl::EncodeBitmap(const gfx::Image& bitmap,
-                                scoped_refptr<base::RefCountedBytes>* bytes) {
-  if (bitmap.IsEmpty())
-    return false;
-  *bytes = new base::RefCountedBytes();
-  std::vector<unsigned char> data;
-  if (!gfx::JPEG1xEncodedDataFromImage(bitmap, kTopSitesImageQuality, &data))
-    return false;
-
-  // As we're going to cache this data, make sure the vector is only as big as
-  // it needs to be, as JPEGCodec::Encode() over-allocates data.capacity().
-  // (In a C++0x future, we can just call shrink_to_fit() in Encode())
-  (*bytes)->data() = data;
-  return true;
-}
-
-void TopSitesLikelyImpl::RemoveTemporaryThumbnailByURL(const GURL& url) {
-  for (TempImages::iterator i = temp_images_.begin(); i != temp_images_.end();
-       ++i) {
-    if (i->first == url) {
-      temp_images_.erase(i);
-      return;
-    }
-  }
-}
-
-void TopSitesLikelyImpl::AddTemporaryThumbnail(
-    const GURL& url,
-    const base::RefCountedMemory* thumbnail,
-    const ThumbnailScore& score) {
-  if (temp_images_.size() == kMaxTempTopImages)
-    temp_images_.erase(temp_images_.begin());
-
-  TempImage image;
-  image.first = url;
-  image.second.thumbnail = const_cast<base::RefCountedMemory*>(thumbnail);
-  image.second.thumbnail_score = score;
-  temp_images_.push_back(image);
-}
-
-void TopSitesLikelyImpl::TimerFired() {
-  StartQueryForMostVisited();
-}
-
-// static
-int TopSitesLikelyImpl::GetRedirectDistanceForURL(
-    const MostVisitedURL& most_visited,
-    const GURL& url) {
-  for (size_t i = 0; i < most_visited.redirects.size(); i++) {
-    if (most_visited.redirects[i] == url)
-      return static_cast<int>(most_visited.redirects.size() - i - 1);
-  }
-  NOTREACHED() << "URL should always be found.";
-  return 0;
-}
-
-MostVisitedURLList TopSitesLikelyImpl::GetPrepopulatePages() {
-  MostVisitedURLList urls;
-  urls.resize(arraysize(kPrepopulatedPages));
-  for (size_t i = 0; i < urls.size(); ++i) {
-    MostVisitedURL& url = urls[i];
-    url.url = GURL(prepopulated_page_urls_[i]);
-    url.redirects.push_back(url.url);
-    url.title = l10n_util::GetStringUTF16(kPrepopulatedPages[i].title_id);
-  }
-  return urls;
-}
-
-bool TopSitesLikelyImpl::loaded() const {
-  return loaded_;
-}
-
-bool TopSitesLikelyImpl::AddPrepopulatedPages(MostVisitedURLList* urls) {
-  bool added = false;
-  MostVisitedURLList prepopulate_urls = GetPrepopulatePages();
-  for (size_t i = 0; i < prepopulate_urls.size(); ++i) {
-    if (urls->size() < kTopSitesNumber &&
-        IndexOf(*urls, prepopulate_urls[i].url) == -1) {
-      urls->push_back(prepopulate_urls[i]);
-      added = true;
-    }
-  }
-  return added;
-}
-
-void TopSitesLikelyImpl::ApplyBlacklist(const MostVisitedURLList& urls,
-                                  MostVisitedURLList* out) {
-  for (size_t i = 0; i < urls.size() && i < kTopSitesNumber; ++i) {
-    if (!IsBlacklisted(urls[i].url))
-      out->push_back(urls[i]);
-  }
-}
-
-std::string TopSitesLikelyImpl::GetURLHash(const GURL& url) {
-  // We don't use canonical URLs here to be able to blacklist only one of
-  // the two 'duplicate' sites, e.g. 'gmail.com' and 'mail.google.com'.
-  return base::MD5String(url.spec());
-}
-
-base::TimeDelta TopSitesLikelyImpl::GetUpdateDelay() {
-  if (cache_->top_sites().size() <= arraysize(kPrepopulatedPages))
-    return base::TimeDelta::FromSeconds(30);
-
-  int64 range = kMaxUpdateIntervalMinutes - kMinUpdateIntervalMinutes;
-  int64 minutes = kMaxUpdateIntervalMinutes -
-      last_num_urls_changed_ * range / cache_->top_sites().size();
-  return base::TimeDelta::FromMinutes(minutes);
-}
-
-void TopSitesLikelyImpl::Observe(int type,
-                           const content::NotificationSource& source,
-                           const content::NotificationDetails& details) {
-  if (!loaded_)
-    return;
-
-  if (type == chrome::NOTIFICATION_HISTORY_URLS_DELETED) {
-    content::Details<history::URLsDeletedDetails> deleted_details(details);
-    if (deleted_details->all_history) {
-      SetTopSites(MostVisitedURLList());
-      backend_->ResetDatabase();
-    } else {
-      std::set<size_t> indices_to_delete;  // Indices into top_sites_.
-      for (URLRows::const_iterator i = deleted_details->rows.begin();
-           i != deleted_details->rows.end(); ++i) {
-        if (cache_->IsKnownURL(i->url()))
-          indices_to_delete.insert(cache_->GetURLIndex(i->url()));
-      }
-
-      if (indices_to_delete.empty())
-        return;
-
-      MostVisitedURLList new_top_sites(cache_->top_sites());
-      for (std::set<size_t>::reverse_iterator i = indices_to_delete.rbegin();
-           i != indices_to_delete.rend(); i++) {
-        new_top_sites.erase(new_top_sites.begin() + *i);
-      }
-      SetTopSites(new_top_sites);
-    }
-    StartQueryForMostVisited();
-  } else if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) {
-    NavigationController* controller =
-        content::Source<NavigationController>(source).ptr();
-    Profile* profile = Profile::FromBrowserContext(
-        controller->GetWebContents()->GetBrowserContext());
-    if (profile == profile_ && !IsFull()) {
-      content::LoadCommittedDetails* load_details =
-          content::Details<content::LoadCommittedDetails>(details).ptr();
-      if (!load_details)
-        return;
-      const GURL& url = load_details->entry->GetURL();
-      if (!cache_->IsKnownURL(url) && HistoryService::CanAddURL(url)) {
-        // To avoid slamming history we throttle requests when the url updates.
-        // To do otherwise negatively impacts perf tests.
-        RestartQueryForTopSitesTimer(GetUpdateDelay());
-      }
-    }
-  }
-}
-
-void TopSitesLikelyImpl::SetTopSites(const MostVisitedURLList& new_top_sites) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  MostVisitedURLList top_sites(new_top_sites);
-  AddPrepopulatedPages(&top_sites);
-
-  TopSitesDelta delta;
-  DiffMostVisited(cache_->top_sites(), top_sites, &delta);
-  if (!delta.deleted.empty() || !delta.added.empty() || !delta.moved.empty()) {
-    backend_->UpdateTopSites(delta);
-  }
-
-  last_num_urls_changed_ = delta.added.size() + delta.moved.size();
-
-  // We always do the following steps (setting top sites in cache, and resetting
-  // thread safe cache ...) as this method is invoked during startup at which
-  // point the caches haven't been updated yet.
-  cache_->SetTopSites(top_sites);
-
-  // See if we have any tmp thumbnails for the new sites.
-  if (!temp_images_.empty()) {
-    for (size_t i = 0; i < top_sites.size(); ++i) {
-      const MostVisitedURL& mv = top_sites[i];
-      GURL canonical_url = cache_->GetCanonicalURL(mv.url);
-      // At the time we get the thumbnail redirects aren't known, so we have to
-      // iterate through all the images.
-      for (TempImages::iterator it = temp_images_.begin();
-           it != temp_images_.end(); ++it) {
-        if (canonical_url == cache_->GetCanonicalURL(it->first)) {
-          SetPageThumbnailEncoded(
-              mv.url, it->second.thumbnail.get(), it->second.thumbnail_score);
-          temp_images_.erase(it);
-          break;
-        }
-      }
-    }
-  }
-
-  if (top_sites.size() >= kTopSitesNumber)
-    temp_images_.clear();
-
-  ResetThreadSafeCache();
-  ResetThreadSafeImageCache();
-  NotifyTopSitesChanged();
-
-  // Restart the timer that queries history for top sites. This is done to
-  // ensure we stay in sync with history.
-  RestartQueryForTopSitesTimer(GetUpdateDelay());
-}
-
-int TopSitesLikelyImpl::num_results_to_request_from_history() const {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  const DictionaryValue* blacklist =
-      profile_->GetPrefs()->GetDictionary(prefs::kNtpMostVisitedURLsBlacklist);
-  return kTopSitesNumber + (blacklist ? blacklist->size() : 0);
-}
-
-void TopSitesLikelyImpl::MoveStateToLoaded() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  MostVisitedURLList filtered_urls;
-  PendingCallbacks pending_callbacks;
-  {
-    base::AutoLock lock(lock_);
-
-    if (loaded_)
-      return;  // Don't do anything if we're already loaded.
-    loaded_ = true;
-
-    // Now that we're loaded we can service the queued up callbacks. Copy them
-    // here and service them outside the lock.
-    if (!pending_callbacks_.empty()) {
-      filtered_urls = thread_safe_cache_->top_sites();
-      pending_callbacks.swap(pending_callbacks_);
-    }
-  }
-
-  for (size_t i = 0; i < pending_callbacks.size(); i++)
-    pending_callbacks[i].Run(filtered_urls);
-
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_TOP_SITES_LOADED,
-      content::Source<Profile>(profile_),
-      content::Details<TopSites>(this));
-}
-
-void TopSitesLikelyImpl::ResetThreadSafeCache() {
-  base::AutoLock lock(lock_);
-  MostVisitedURLList cached;
-  ApplyBlacklist(cache_->top_sites(), &cached);
-  thread_safe_cache_->SetTopSites(cached);
-}
-
-void TopSitesLikelyImpl::ResetThreadSafeImageCache() {
-  base::AutoLock lock(lock_);
-  thread_safe_cache_->SetThumbnails(cache_->images());
-}
-
-void TopSitesLikelyImpl::NotifyTopSitesChanged() {
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_TOP_SITES_CHANGED,
-      content::Source<TopSites>(this),
-      content::NotificationService::NoDetails());
-}
-
-void TopSitesLikelyImpl::RestartQueryForTopSitesTimer(base::TimeDelta delta) {
-  if (timer_.IsRunning() && ((timer_start_time_ + timer_.GetCurrentDelay()) <
-                             (base::TimeTicks::Now() + delta))) {
-    return;
-  }
-
-  timer_start_time_ = base::TimeTicks::Now();
-  timer_.Stop();
-  timer_.Start(FROM_HERE, delta, this, &TopSitesLikelyImpl::TimerFired);
-}
-
-void TopSitesLikelyImpl::OnHistoryMigrationWrittenToDisk() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  if (!profile_)
-    return;
-
-  HistoryService* history = HistoryServiceFactory::GetForProfile(
-      profile_, Profile::EXPLICIT_ACCESS);
-  if (history)
-    history->OnTopSitesReady();
-}
-
-void TopSitesLikelyImpl::OnGotMostVisitedThumbnails(
-    const scoped_refptr<MostVisitedThumbnails>& thumbnails,
-    const bool* need_history_migration) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DCHECK_EQ(top_sites_state_, TOP_SITES_LOADING);
-
-  if (!*need_history_migration) {
-    top_sites_state_ = TOP_SITES_LOADED;
-
-    // Set the top sites directly in the cache so that SetTopSites diffs
-    // correctly.
-    cache_->SetTopSites(thumbnails->most_visited);
-    SetTopSites(thumbnails->most_visited);
-    cache_->SetThumbnails(thumbnails->url_to_images_map);
-
-    ResetThreadSafeImageCache();
-
-    MoveStateToLoaded();
-
-    // Start a timer that refreshes top sites from history.
-    RestartQueryForTopSitesTimer(
-        base::TimeDelta::FromSeconds(kUpdateIntervalSecs));
-  } else {
-    // The top sites file didn't exist or is the wrong version. We need to wait
-    // for history to finish loading to know if we really needed to migrate.
-    if (history_state_ == HISTORY_LOADED) {
-      top_sites_state_ = TOP_SITES_LOADED;
-      SetTopSites(MostVisitedURLList());
-      MoveStateToLoaded();
-    } else {
-      top_sites_state_ = TOP_SITES_LOADED_WAITING_FOR_HISTORY;
-      // Ask for history just in case it hasn't been loaded yet. When history
-      // finishes loading we'll do migration and/or move to loaded.
-      HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
-    }
-  }
-}
-
-void TopSitesLikelyImpl::OnTopSitesAvailableFromHistory(
-    CancelableRequestProvider::Handle handle,
-    MostVisitedURLList pages) {
-  SetTopSites(pages);
-
-  // Used only in testing.
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_TOP_SITES_UPDATED,
-      content::Source<TopSitesLikelyImpl>(this),
-      content::Details<CancelableRequestProvider::Handle>(&handle));
-}
-
-}  // namespace history
diff --git a/chrome/browser/history/top_sites_likely_impl.h b/chrome/browser/history/top_sites_likely_impl.h
deleted file mode 100644
index 89122d4..0000000
--- a/chrome/browser/history/top_sites_likely_impl.h
+++ /dev/null
@@ -1,293 +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 CHROME_BROWSER_HISTORY_TOP_SITES_LIKELY_IMPL_H_
-#define CHROME_BROWSER_HISTORY_TOP_SITES_LIKELY_IMPL_H_
-
-#include <list>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "chrome/browser/common/cancelable_request.h"
-#include "chrome/browser/history/history_service.h"
-#include "chrome/browser/history/history_types.h"
-#include "chrome/browser/history/page_usage_data.h"
-#include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/history/top_sites_backend.h"
-#include "chrome/common/cancelable_task_tracker.h"
-#include "chrome/common/thumbnail_score.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/image/image.h"
-#include "url/gurl.h"
-
-class Profile;
-
-namespace base {
-class FilePath;
-class RefCountedBytes;
-class RefCountedMemory;
-}
-
-namespace history {
-
-class TopSitesCache;
-class TopSitesLikelyImplTest;
-
-
-// This class allows requests for most visited urls and thumbnails on any
-// thread. All other methods must be invoked on the UI thread. All mutations
-// to internal state happen on the UI thread and are scheduled to update the
-// db using TopSitesBackend.
-class TopSitesLikelyImpl : public TopSites {
- public:
-  explicit TopSitesLikelyImpl(Profile* profile);
-
-  // Initializes TopSitesLikelyImpl.
-  void Init(const base::FilePath& db_name);
-
-  virtual bool SetPageThumbnail(const GURL& url,
-                        const gfx::Image& thumbnail,
-                        const ThumbnailScore& score) OVERRIDE;
-  virtual bool SetPageThumbnailToJPEGBytes(
-      const GURL& url,
-      const base::RefCountedMemory* memory,
-      const ThumbnailScore& score) OVERRIDE;
-  virtual void GetMostVisitedURLs(
-      const GetMostVisitedURLsCallback& callback) OVERRIDE;
-  virtual bool GetPageThumbnail(
-      const GURL& url, scoped_refptr<base::RefCountedMemory>* bytes) OVERRIDE;
-  virtual bool GetPageThumbnailScore(const GURL& url,
-                                     ThumbnailScore* score) OVERRIDE;
-  virtual bool GetTemporaryPageThumbnailScore(const GURL& url,
-                                              ThumbnailScore* score) OVERRIDE;
-  virtual void MigrateFromHistory() OVERRIDE;
-  virtual void FinishHistoryMigration(const ThumbnailMigration& data) OVERRIDE;
-  virtual void HistoryLoaded() OVERRIDE;
-  virtual void SyncWithHistory() OVERRIDE;
-  virtual bool HasBlacklistedItems() const OVERRIDE;
-  virtual void AddBlacklistedURL(const GURL& url) OVERRIDE;
-  virtual void RemoveBlacklistedURL(const GURL& url) OVERRIDE;
-  virtual bool IsBlacklisted(const GURL& url) OVERRIDE;
-  virtual void ClearBlacklistedURLs() OVERRIDE;
-  virtual void Shutdown() OVERRIDE;
-  virtual CancelableRequestProvider::Handle StartQueryForMostVisited() OVERRIDE;
-  virtual bool IsKnownURL(const GURL& url) OVERRIDE;
-  virtual const std::string& GetCanonicalURLString(
-      const GURL& url) const OVERRIDE;
-  virtual bool IsFull() OVERRIDE;
-  virtual MostVisitedURLList GetPrepopulatePages() OVERRIDE;
-  virtual bool loaded() const OVERRIDE;
-
- protected:
-  virtual ~TopSitesLikelyImpl();
-
- private:
-  friend class TopSitesLikelyImplTest;
-  FRIEND_TEST_ALL_PREFIXES(TopSitesLikelyImplTest, DiffMostVisited);
-
-  typedef std::pair<GURL, Images> TempImage;
-  typedef std::list<TempImage> TempImages;
-
-  // Generates the diff of things that happened between "old" and "new."
-  //
-  // The URLs that are in "new" but not "old" will be have their index into
-  // "new" put in |added_urls|. The URLs that are in "old" but not "new" will
-  // have their index into "old" put into |deleted_urls|.
-  //
-  // URLs appearing in both old and new lists but having different indices will
-  // have their index into "new" be put into |moved_urls|.
-  static void DiffMostVisited(const MostVisitedURLList& old_list,
-                              const MostVisitedURLList& new_list,
-                              TopSitesDelta* delta);
-
-  // Enumeration of the possible states history can be in. These values do not
-  // necessarily reflect the loaded state of history. In particular if the
-  // history backend is unloaded |history_state_| may be HISTORY_LOADED.
-  enum HistoryLoadState {
-    // We're waiting for history to finish loading.
-    HISTORY_LOADING,
-
-    // History finished loading and we need to migrate top sites out of history.
-    HISTORY_MIGRATING,
-
-    // History is loaded.
-    HISTORY_LOADED
-  };
-
-  // Enumeration of possible states the top sites backend can be in.
-  enum TopSitesLoadState {
-    // We're waiting for the backend to finish loading.
-    TOP_SITES_LOADING,
-
-    // The backend finished loading, but we may need to migrate. This is true if
-    // the top sites db didn't exist, or if the db existed but is from an old
-    // version.
-    TOP_SITES_LOADED_WAITING_FOR_HISTORY,
-
-    // Top sites is loaded.
-    TOP_SITES_LOADED
-  };
-
-  // Sets the thumbnail without writing to the database. Useful when
-  // reading last known top sites from the DB.
-  // Returns true if the thumbnail was set, false if the existing one is better.
-  bool SetPageThumbnailNoDB(const GURL& url,
-                            const base::RefCountedMemory* thumbnail_data,
-                            const ThumbnailScore& score);
-
-  // A version of SetPageThumbnail that takes RefCountedBytes as
-  // returned by HistoryService.
-  bool SetPageThumbnailEncoded(const GURL& url,
-                               const base::RefCountedMemory* thumbnail,
-                               const ThumbnailScore& score);
-
-  // Encodes the bitmap to bytes for storage to the db. Returns true if the
-  // bitmap was successfully encoded.
-  static bool EncodeBitmap(const gfx::Image& bitmap,
-                           scoped_refptr<base::RefCountedBytes>* bytes);
-
-  // Removes the cached thumbnail for url. Does nothing if |url| if not cached
-  // in |temp_images_|.
-  void RemoveTemporaryThumbnailByURL(const GURL& url);
-
-  // Add a thumbnail for an unknown url. See temp_thumbnails_map_.
-  void AddTemporaryThumbnail(const GURL& url,
-                             const base::RefCountedMemory* thumbnail,
-                             const ThumbnailScore& score);
-
-  // Called by our timer. Starts the query for the most visited sites.
-  void TimerFired();
-
-  // Finds the given URL in the redirect chain for the given TopSite, and
-  // returns the distance from the destination in hops that the given URL is.
-  // The URL is assumed to be in the list. The destination is 0.
-  static int GetRedirectDistanceForURL(const MostVisitedURL& most_visited,
-                                       const GURL& url);
-
-  // Add prepopulated pages: 'welcome to Chrome' and themes gallery to |urls|.
-  // Returns true if any pages were added.
-  bool AddPrepopulatedPages(MostVisitedURLList* urls);
-
-  // Takes |urls|, produces it's copy in |out| after removing blacklisted URLs.
-  void ApplyBlacklist(const MostVisitedURLList& urls, MostVisitedURLList* out);
-
-  // Returns an MD5 hash of the URL. Hashing is required for blacklisted URLs.
-  std::string GetURLHash(const GURL& url);
-
-  // Returns the delay until the next update of history is needed.
-  // Uses num_urls_changed
-  base::TimeDelta GetUpdateDelay();
-
-  // Implementation of content::NotificationObserver.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // Resets top_sites_ and updates the db (in the background). All mutations to
-  // top_sites_ *must* go through this. Should be called from the UI thread.
-  void SetTopSites(const MostVisitedURLList& new_top_sites);
-
-  // Returns the number of most visted results to request from history. This
-  // changes depending upon how many urls have been blacklisted. Should be
-  // called from the UI thread.
-  int num_results_to_request_from_history() const;
-
-  // Invoked when transitioning to LOADED. Notifies any queued up callbacks.
-  // Should be called from the UI thread.
-  void MoveStateToLoaded();
-
-  void ResetThreadSafeCache();
-
-  void ResetThreadSafeImageCache();
-
-  void NotifyTopSitesChanged();
-
-  // Stops and starts timer with a delay of |delta|.
-  void RestartQueryForTopSitesTimer(base::TimeDelta delta);
-
-  // Callback after TopSitesBackend has finished migration. This tells history
-  // to finish it's side of migration (nuking thumbnails on disk). Should be
-  // called from the UI thread.
-  void OnHistoryMigrationWrittenToDisk();
-
-  // Callback from TopSites with the top sites/thumbnails. Should be called
-  // from the UI thread.
-  void OnGotMostVisitedThumbnails(
-      const scoped_refptr<MostVisitedThumbnails>& thumbnails,
-      const bool* need_history_migration);
-
-  // Called when history service returns a list of top URLs.
-  void OnTopSitesAvailableFromHistory(CancelableRequestProvider::Handle handle,
-                                      MostVisitedURLList data);
-
-  scoped_refptr<TopSitesBackend> backend_;
-
-  // The top sites data.
-  scoped_ptr<TopSitesCache> cache_;
-
-  // Copy of the top sites data that may be accessed on any thread (assuming
-  // you hold |lock_|). The data in |thread_safe_cache_| has blacklisted and
-  // pinned urls applied (|cache_| does not).
-  scoped_ptr<TopSitesCache> thread_safe_cache_;
-
-  Profile* profile_;
-
-  // Lock used to access |thread_safe_cache_|.
-  mutable base::Lock lock_;
-
-  // Need a separate consumer for each CancelableRequestProvider we interact
-  // with (HistoryService and TopSitesBackend).
-  CancelableRequestConsumer history_consumer_;
-  CancelableTaskTracker cancelable_task_tracker_;
-
-  // Timer that asks history for the top sites. This is used to make sure our
-  // data stays in sync with history.
-  base::OneShotTimer<TopSitesLikelyImpl> timer_;
-
-  // The time we started |timer_| at. Only valid if |timer_| is running.
-  base::TimeTicks timer_start_time_;
-
-  content::NotificationRegistrar registrar_;
-
-  // The number of URLs changed on the last update.
-  size_t last_num_urls_changed_;
-
-  // The pending requests for the top sites list. Can only be non-empty at
-  // startup. After we read the top sites from the DB, we'll always have a
-  // cached list and be able to run callbacks immediately.
-  PendingCallbacks pending_callbacks_;
-
-  // Stores thumbnails for unknown pages. When SetPageThumbnail is
-  // called, if we don't know about that URL yet and we don't have
-  // enough Top Sites (new profile), we store it until the next
-  // SetTopSites call.
-  TempImages temp_images_;
-
-  // See description above HistoryLoadState.
-  HistoryLoadState history_state_;
-
-  // See description above TopSitesLoadState.
-  TopSitesLoadState top_sites_state_;
-
-  // URL List of prepopulated page.
-  std::vector<GURL> prepopulated_page_urls_;
-
-  // Are we loaded?
-  bool loaded_;
-
-  DISALLOW_COPY_AND_ASSIGN(TopSitesLikelyImpl);
-};
-
-}  // namespace history
-
-#endif  // CHROME_BROWSER_HISTORY_TOP_SITES_LIKELY_IMPL_H_
diff --git a/chrome/browser/history/top_sites_likely_impl_unittest.cc b/chrome/browser/history/top_sites_likely_impl_unittest.cc
deleted file mode 100644
index 01a9504..0000000
--- a/chrome/browser/history/top_sites_likely_impl_unittest.cc
+++ /dev/null
@@ -1,1268 +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/bind.h"
-#include "base/bind_helpers.h"
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/format_macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/path_service.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/history/history_backend.h"
-#include "chrome/browser/history/history_database.h"
-#include "chrome/browser/history/history_db_task.h"
-#include "chrome/browser/history/history_marshaling.h"
-#include "chrome/browser/history/history_notifications.h"
-#include "chrome/browser/history/history_service_factory.h"
-#include "chrome/browser/history/history_unittest_base.h"
-#include "chrome/browser/history/top_sites_backend.h"
-#include "chrome/browser/history/top_sites_cache.h"
-#include "chrome/browser/history/top_sites_database.h"
-#include "chrome/browser/history/top_sites_likely_impl.h"
-#include "chrome/browser/ui/webui/ntp/most_visited_handler.h"
-#include "chrome/common/cancelable_task_tracker.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/test/base/testing_profile.h"
-#include "chrome/tools/profiles/thumbnail-inl.h"
-#include "content/public/test/test_browser_thread.h"
-#include "content/public/test/test_utils.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/locale_settings.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/codec/jpeg_codec.h"
-#include "url/gurl.h"
-
-using content::BrowserThread;
-
-namespace history {
-
-namespace {
-
-// Used by WaitForHistory, see it for details.
-class WaitForHistoryTask : public HistoryDBTask {
- public:
-  WaitForHistoryTask() {}
-
-  virtual bool RunOnDBThread(HistoryBackend* backend,
-                             HistoryDatabase* db) OVERRIDE {
-    return true;
-  }
-
-  virtual void DoneRunOnMainThread() OVERRIDE {
-    base::MessageLoop::current()->Quit();
-  }
-
- private:
-  virtual ~WaitForHistoryTask() {}
-
-  DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask);
-};
-
-// Used for querying top sites. Either runs sequentially, or runs a nested
-// nested message loop until the response is complete. The later is used when
-// TopSites is queried before it finishes loading.
-class TopSitesQuerier {
- public:
-  TopSitesQuerier()
-      : weak_ptr_factory_(this),
-        number_of_callbacks_(0),
-        waiting_(false) {}
-
-  // Queries top sites. If |wait| is true a nested message loop is run until the
-  // callback is notified.
-  void QueryTopSites(TopSitesLikelyImpl* top_sites, bool wait) {
-    int start_number_of_callbacks = number_of_callbacks_;
-    top_sites->GetMostVisitedURLs(
-        base::Bind(&TopSitesQuerier::OnTopSitesAvailable,
-                   weak_ptr_factory_.GetWeakPtr()));
-    if (wait && start_number_of_callbacks == number_of_callbacks_) {
-      waiting_ = true;
-      base::MessageLoop::current()->Run();
-    }
-  }
-
-  void CancelRequest() {
-    weak_ptr_factory_.InvalidateWeakPtrs();
-  }
-
-  void set_urls(const MostVisitedURLList& urls) { urls_ = urls; }
-  const MostVisitedURLList& urls() const { return urls_; }
-
-  int number_of_callbacks() const { return number_of_callbacks_; }
-
- private:
-  // Callback for TopSitesLikelyImpl::GetMostVisitedURLs.
-  void OnTopSitesAvailable(const history::MostVisitedURLList& data) {
-    urls_ = data;
-    number_of_callbacks_++;
-    if (waiting_) {
-      base::MessageLoop::current()->Quit();
-      waiting_ = false;
-    }
-  }
-
-  base::WeakPtrFactory<TopSitesQuerier> weak_ptr_factory_;
-  MostVisitedURLList urls_;
-  int number_of_callbacks_;
-  bool waiting_;
-
-  DISALLOW_COPY_AND_ASSIGN(TopSitesQuerier);
-};
-
-// Extracts the data from |t1| into a SkBitmap. This is intended for usage of
-// thumbnail data, which is stored as jpgs.
-SkBitmap ExtractThumbnail(const base::RefCountedMemory& t1) {
-  scoped_ptr<SkBitmap> image(gfx::JPEGCodec::Decode(t1.front(),
-                                                    t1.size()));
-  return image.get() ? *image : SkBitmap();
-}
-
-// Returns true if t1 and t2 contain the same data.
-bool ThumbnailsAreEqual(base::RefCountedMemory* t1,
-                        base::RefCountedMemory* t2) {
-  if (!t1 || !t2)
-    return false;
-  if (t1->size() != t2->size())
-    return false;
-  return !memcmp(t1->front(), t2->front(), t1->size());
-}
-
-}  // namespace
-
-class TopSitesLikelyImplTest : public HistoryUnitTestBase {
- public:
-  TopSitesLikelyImplTest()
-      : ui_thread_(BrowserThread::UI, &message_loop_),
-        db_thread_(BrowserThread::DB, &message_loop_) {
-  }
-
-  virtual void SetUp() {
-    profile_.reset(new TestingProfile);
-    if (CreateHistoryAndTopSites()) {
-      ASSERT_TRUE(profile_->CreateHistoryService(false, false));
-      profile_->CreateTopSites();
-      profile_->BlockUntilTopSitesLoaded();
-    }
-  }
-
-  virtual void TearDown() {
-    profile_.reset();
-  }
-
-  // Returns true if history and top sites should be created in SetUp.
-  virtual bool CreateHistoryAndTopSites() {
-    return true;
-  }
-
-  // Gets the thumbnail for |url| from TopSites.
-  SkBitmap GetThumbnail(const GURL& url) {
-    scoped_refptr<base::RefCountedMemory> data;
-    return top_sites()->GetPageThumbnail(url, &data) ?
-        ExtractThumbnail(*data.get()) : SkBitmap();
-  }
-
-  // Creates a bitmap of the specified color. Caller takes ownership.
-  gfx::Image CreateBitmap(SkColor color) {
-    SkBitmap thumbnail;
-    thumbnail.setConfig(SkBitmap::kARGB_8888_Config, 4, 4);
-    thumbnail.allocPixels();
-    thumbnail.eraseColor(color);
-    return gfx::Image::CreateFrom1xBitmap(thumbnail);  // adds ref.
-  }
-
-  // Forces top sites to load top sites from history, then recreates top sites.
-  // Recreating top sites makes sure the changes from history are saved and
-  // loaded from the db.
-  void RefreshTopSitesAndRecreate() {
-    StartQueryForMostVisited();
-    WaitForHistory();
-    RecreateTopSitesAndBlock();
-  }
-
-  // Blocks the caller until history processes a task. This is useful if you
-  // need to wait until you know history has processed a task.
-  void WaitForHistory() {
-    history_service()->ScheduleDBTask(new WaitForHistoryTask(), &consumer_);
-    base::MessageLoop::current()->Run();
-  }
-
-  // Waits for top sites to finish processing a task. This is useful if you need
-  // to wait until top sites finishes processing a task.
-  void WaitForTopSites() {
-    top_sites()->backend_->DoEmptyRequest(
-        base::Bind(&TopSitesLikelyImplTest::QuitCallback,
-                   base::Unretained(this)),
-        &cancelable_task_tracker_);
-    base::MessageLoop::current()->Run();
-  }
-
-  TopSitesLikelyImpl* top_sites() {
-    return static_cast<TopSitesLikelyImpl*>(profile_->GetTopSites());
-  }
-  CancelableRequestConsumer* consumer() { return &consumer_; }
-  TestingProfile* profile() {return profile_.get();}
-  HistoryService* history_service() {
-    return HistoryServiceFactory::GetForProfile(profile_.get(),
-                                                Profile::EXPLICIT_ACCESS);
-  }
-
-  MostVisitedURLList GetPrepopulatePages() {
-    return top_sites()->GetPrepopulatePages();
-  }
-
-  // Returns true if the TopSitesQuerier contains the prepopulate data starting
-  // at |start_index|.
-  void ContainsPrepopulatePages(const TopSitesQuerier& querier,
-                                size_t start_index) {
-    MostVisitedURLList prepopulate_urls = GetPrepopulatePages();
-    ASSERT_LE(start_index + prepopulate_urls.size(), querier.urls().size());
-    for (size_t i = 0; i < prepopulate_urls.size(); ++i) {
-      EXPECT_EQ(prepopulate_urls[i].url.spec(),
-                querier.urls()[start_index + i].url.spec()) << " @ index " <<
-          i;
-    }
-  }
-
-  // Used for callbacks from history.
-  void EmptyCallback() {
-  }
-
-  // Quit the current message loop when invoked. Useful when running a nested
-  // message loop.
-  void QuitCallback() {
-    base::MessageLoop::current()->Quit();
-  }
-
-  // Adds a page to history.
-  void AddPageToHistory(const GURL& url) {
-    RedirectList redirects;
-    redirects.push_back(url);
-    history_service()->AddPage(
-        url, base::Time::Now(), static_cast<void*>(this), 0, GURL(),
-        redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
-        false);
-  }
-
-  // Adds a page to history.
-  void AddPageToHistory(const GURL& url, const string16& title) {
-    RedirectList redirects;
-    redirects.push_back(url);
-    history_service()->AddPage(
-        url, base::Time::Now(), static_cast<void*>(this), 0, GURL(),
-        redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
-        false);
-    history_service()->SetPageTitle(url, title);
-  }
-
-  // Adds a page to history.
-  void AddPageToHistory(const GURL& url,
-                        const string16& title,
-                        const history::RedirectList& redirects,
-                        base::Time time) {
-    history_service()->AddPage(
-        url, time, static_cast<void*>(this), 0, GURL(),
-        redirects, content::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED,
-        false);
-    history_service()->SetPageTitle(url, title);
-  }
-
-  // Delets a url.
-  void DeleteURL(const GURL& url) {
-    history_service()->DeleteURL(url);
-  }
-
-  // Returns true if the thumbnail equals the specified bytes.
-  bool ThumbnailEqualsBytes(const gfx::Image& image,
-                            base::RefCountedMemory* bytes) {
-    scoped_refptr<base::RefCountedBytes> encoded_image;
-    TopSitesLikelyImpl::EncodeBitmap(image, &encoded_image);
-    return ThumbnailsAreEqual(encoded_image.get(), bytes);
-  }
-
-  // Recreates top sites. This forces top sites to reread from the db.
-  void RecreateTopSitesAndBlock() {
-    // Recreate TopSites and wait for it to load.
-    profile()->CreateTopSites();
-    // As history already loaded we have to fake this call.
-    profile()->BlockUntilTopSitesLoaded();
-  }
-
-  // Wrappers that allow private TopSites functions to be called from the
-  // individual tests without making them all be friends.
-  GURL GetCanonicalURL(const GURL& url) {
-    return top_sites()->cache_->GetCanonicalURL(url);
-  }
-
-  void SetTopSites(const MostVisitedURLList& new_top_sites) {
-    top_sites()->SetTopSites(new_top_sites);
-  }
-
-  void StartQueryForMostVisited() {
-    top_sites()->StartQueryForMostVisited();
-  }
-
-  void SetLastNumUrlsChanged(size_t value) {
-    top_sites()->last_num_urls_changed_ = value;
-  }
-
-  size_t last_num_urls_changed() { return top_sites()->last_num_urls_changed_; }
-
-  base::TimeDelta GetUpdateDelay() {
-    return top_sites()->GetUpdateDelay();
-  }
-
-  bool IsTopSitesLoaded() { return top_sites()->loaded_; }
-
-  bool AddPrepopulatedPages(MostVisitedURLList* urls) {
-    return top_sites()->AddPrepopulatedPages(urls);
-  }
-
- private:
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread db_thread_;
-  scoped_ptr<TestingProfile> profile_;
-
-  // To cancel HistoryService tasks.
-  CancelableRequestConsumer consumer_;
-
-  // To cancel TopSitesBackend tasks.
-  CancelableTaskTracker cancelable_task_tracker_;
-
-  DISALLOW_COPY_AND_ASSIGN(TopSitesLikelyImplTest);
-};  // Class TopSitesLikelyImplTest
-
-class TopSitesLikelyMigrationTest : public TopSitesLikelyImplTest {
- public:
-  TopSitesLikelyMigrationTest() {}
-
-  virtual void SetUp() {
-    TopSitesLikelyImplTest::SetUp();
-
-    base::FilePath data_path;
-    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
-    data_path = data_path.AppendASCII("top_sites");
-
-    // Set up history and thumbnails as they would be before migration.
-    ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-        data_path.AppendASCII("history.19.sql"),
-        profile()->GetPath().Append(chrome::kHistoryFilename)));
-    ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-        data_path.AppendASCII("thumbnails.3.sql"),
-        profile()->GetPath().Append(chrome::kThumbnailsFilename)));
-
-    ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-    profile()->CreateTopSites();
-    profile()->BlockUntilTopSitesLoaded();
-  }
-
-  // Returns true if history and top sites should be created in SetUp.
-  virtual bool CreateHistoryAndTopSites() OVERRIDE {
-    return false;
-  }
-
- protected:
-  // Assertions for the migration test. This is extracted into a standalone
-  // method so that it can be invoked twice.
-  void MigrationAssertions() {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    // We shouldn't have gotten a callback.
-    EXPECT_EQ(1, querier.number_of_callbacks());
-
-    // The data we loaded should contain google and yahoo.
-    ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(GURL("http://google.com/"), querier.urls()[0].url);
-    EXPECT_EQ(GURL("http://yahoo.com/"), querier.urls()[1].url);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
-
-    SkBitmap goog_thumbnail = GetThumbnail(GURL("http://google.com/"));
-    EXPECT_EQ(1, goog_thumbnail.width());
-
-    SkBitmap yahoo_thumbnail = GetThumbnail(GURL("http://yahoo.com/"));
-    EXPECT_EQ(2, yahoo_thumbnail.width());
-
-    // Favicon assertions are handled in ThumbnailDatabase.
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TopSitesLikelyMigrationTest);
-};
-
-// Helper function for appending a URL to a vector of "most visited" URLs,
-// using the default values for everything but the URL.
-static void AppendMostVisitedURL(std::vector<MostVisitedURL>* list,
-                                 const GURL& url) {
-  MostVisitedURL mv;
-  mv.url = url;
-  mv.redirects.push_back(url);
-  list->push_back(mv);
-}
-
-// Same as AppendMostVisitedURL except that it adds a redirect from the first
-// URL to the second.
-static void AppendMostVisitedURLWithRedirect(
-    std::vector<MostVisitedURL>* list,
-    const GURL& redirect_source, const GURL& redirect_dest) {
-  MostVisitedURL mv;
-  mv.url = redirect_dest;
-  mv.redirects.push_back(redirect_source);
-  mv.redirects.push_back(redirect_dest);
-  list->push_back(mv);
-}
-
-// Tests GetCanonicalURL.
-TEST_F(TopSitesLikelyImplTest, GetCanonicalURL) {
-  // Have two chains:
-  //   google.com -> www.google.com
-  //   news.google.com (no redirects)
-  GURL news("http://news.google.com/");
-  GURL source("http://google.com/");
-  GURL dest("http://www.google.com/");
-
-  std::vector<MostVisitedURL> most_visited;
-  AppendMostVisitedURLWithRedirect(&most_visited, source, dest);
-  AppendMostVisitedURL(&most_visited, news);
-  SetTopSites(most_visited);
-
-  // Random URLs not in the database are returned unchanged.
-  GURL result = GetCanonicalURL(GURL("http://fark.com/"));
-  EXPECT_EQ(GURL("http://fark.com/"), result);
-
-  // Easy case, there are no redirects and the exact URL is stored.
-  result = GetCanonicalURL(news);
-  EXPECT_EQ(news, result);
-
-  // The URL in question is the source URL in a redirect list.
-  result = GetCanonicalURL(source);
-  EXPECT_EQ(dest, result);
-
-  // The URL in question is the destination of a redirect.
-  result = GetCanonicalURL(dest);
-  EXPECT_EQ(dest, result);
-}
-
-// Tests DiffMostVisited.
-TEST_F(TopSitesLikelyImplTest, DiffMostVisited) {
-  GURL stays_the_same("http://staysthesame/");
-  GURL gets_added_1("http://getsadded1/");
-  GURL gets_added_2("http://getsadded2/");
-  GURL gets_deleted_1("http://getsdeleted2/");
-  GURL gets_moved_1("http://getsmoved1/");
-
-  std::vector<MostVisitedURL> old_list;
-  AppendMostVisitedURL(&old_list, stays_the_same);  // 0  (unchanged)
-  AppendMostVisitedURL(&old_list, gets_deleted_1);  // 1  (deleted)
-  AppendMostVisitedURL(&old_list, gets_moved_1);    // 2  (moved to 3)
-
-  std::vector<MostVisitedURL> new_list;
-  AppendMostVisitedURL(&new_list, stays_the_same);  // 0  (unchanged)
-  AppendMostVisitedURL(&new_list, gets_added_1);    // 1  (added)
-  AppendMostVisitedURL(&new_list, gets_added_2);    // 2  (added)
-  AppendMostVisitedURL(&new_list, gets_moved_1);    // 3  (moved from 2)
-
-  history::TopSitesDelta delta;
-  history::TopSitesLikelyImpl::DiffMostVisited(old_list, new_list, &delta);
-
-  ASSERT_EQ(2u, delta.added.size());
-  ASSERT_TRUE(gets_added_1 == delta.added[0].url.url);
-  ASSERT_EQ(1, delta.added[0].rank);
-  ASSERT_TRUE(gets_added_2 == delta.added[1].url.url);
-  ASSERT_EQ(2, delta.added[1].rank);
-
-  ASSERT_EQ(1u, delta.deleted.size());
-  ASSERT_TRUE(gets_deleted_1 == delta.deleted[0].url);
-
-  ASSERT_EQ(1u, delta.moved.size());
-  ASSERT_TRUE(gets_moved_1 == delta.moved[0].url.url);
-  ASSERT_EQ(3, delta.moved[0].rank);
-}
-
-// Tests SetPageThumbnail.
-TEST_F(TopSitesLikelyImplTest, SetPageThumbnail) {
-  GURL url1a("http://google.com/");
-  GURL url1b("http://www.google.com/");
-  GURL url2("http://images.google.com/");
-  GURL invalid_url("chrome://favicon/http://google.com/");
-
-  std::vector<MostVisitedURL> list;
-  AppendMostVisitedURL(&list, url2);
-
-  MostVisitedURL mv;
-  mv.url = url1b;
-  mv.redirects.push_back(url1a);
-  mv.redirects.push_back(url1b);
-  list.push_back(mv);
-
-  // Save our most visited data containing that one site.
-  SetTopSites(list);
-
-  // Create a dummy thumbnail.
-  gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
-
-  base::Time now = base::Time::Now();
-  ThumbnailScore low_score(1.0, true, true, now);
-  ThumbnailScore medium_score(0.5, true, true, now);
-  ThumbnailScore high_score(0.0, true, true, now);
-
-  // Setting the thumbnail for invalid pages should fail.
-  EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
-                                             thumbnail, medium_score));
-
-  // Setting the thumbnail for url2 should succeed, lower scores shouldn't
-  // replace it, higher scores should.
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(url2, thumbnail, medium_score));
-  EXPECT_FALSE(top_sites()->SetPageThumbnail(url2, thumbnail, low_score));
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(url2, thumbnail, high_score));
-
-  // Set on the redirect source should succeed. It should be replacable by
-  // the same score on the redirect destination, which in turn should not
-  // be replaced by the source again.
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(url1a, thumbnail, medium_score));
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(url1b, thumbnail, medium_score));
-  EXPECT_FALSE(top_sites()->SetPageThumbnail(url1a, thumbnail, medium_score));
-}
-
-// Makes sure a thumbnail is correctly removed when the page is removed.
-TEST_F(TopSitesLikelyImplTest, ThumbnailRemoved) {
-  GURL url("http://google.com/");
-
-  // Configure top sites with 'google.com'.
-  std::vector<MostVisitedURL> list;
-  AppendMostVisitedURL(&list, url);
-  SetTopSites(list);
-
-  // Create a dummy thumbnail.
-  gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
-
-  base::Time now = base::Time::Now();
-  ThumbnailScore low_score(1.0, true, true, now);
-  ThumbnailScore medium_score(0.5, true, true, now);
-  ThumbnailScore high_score(0.0, true, true, now);
-
-  // Set the thumbnail.
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(url, thumbnail, medium_score));
-
-  // Make sure the thumbnail was actually set.
-  scoped_refptr<base::RefCountedMemory> result;
-  EXPECT_TRUE(top_sites()->GetPageThumbnail(url, &result));
-  EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
-
-  // Reset the thumbnails and make sure we don't get it back.
-  SetTopSites(MostVisitedURLList());
-  RefreshTopSitesAndRecreate();
-  EXPECT_FALSE(top_sites()->GetPageThumbnail(url, &result));
-}
-
-// Tests GetPageThumbnail.
-TEST_F(TopSitesLikelyImplTest, GetPageThumbnail) {
-  MostVisitedURLList url_list;
-  MostVisitedURL url1;
-  url1.url = GURL("http://asdf.com");
-  url1.redirects.push_back(url1.url);
-  url_list.push_back(url1);
-
-  MostVisitedURL url2;
-  url2.url = GURL("http://gmail.com");
-  url2.redirects.push_back(url2.url);
-  url2.redirects.push_back(GURL("http://mail.google.com"));
-  url_list.push_back(url2);
-
-  SetTopSites(url_list);
-
-  // Create a dummy thumbnail.
-  gfx::Image thumbnail(CreateBitmap(SK_ColorWHITE));
-  ThumbnailScore score(0.5, true, true, base::Time::Now());
-
-  scoped_refptr<base::RefCountedMemory> result;
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(url1.url, thumbnail, score));
-  EXPECT_TRUE(top_sites()->GetPageThumbnail(url1.url, &result));
-
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://gmail.com"),
-                                           thumbnail, score));
-  EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://gmail.com"),
-                                            &result));
-  // Get a thumbnail via a redirect.
-  EXPECT_TRUE(top_sites()->GetPageThumbnail(GURL("http://mail.google.com"),
-                                            &result));
-
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(GURL("http://mail.google.com"),
-                                           thumbnail, score));
-  EXPECT_TRUE(top_sites()->GetPageThumbnail(url2.url, &result));
-
-  EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, result.get()));
-}
-
-// Tests GetMostVisitedURLs.
-TEST_F(TopSitesLikelyImplTest, GetMostVisited) {
-  GURL news("http://news.google.com/");
-  GURL google("http://google.com/");
-
-  AddPageToHistory(news);
-  AddPageToHistory(google);
-
-  StartQueryForMostVisited();
-  WaitForHistory();
-
-  TopSitesQuerier querier;
-  querier.QueryTopSites(top_sites(), false);
-
-  ASSERT_EQ(1, querier.number_of_callbacks());
-
-  // 2 extra prepopulated URLs.
-  ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
-  EXPECT_EQ(news, querier.urls()[0].url);
-  EXPECT_EQ(google, querier.urls()[1].url);
-  ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
-}
-
-// Makes sure changes done to top sites get mirrored to the db.
-TEST_F(TopSitesLikelyImplTest, SaveToDB) {
-  MostVisitedURL url;
-  GURL asdf_url("http://asdf.com");
-  string16 asdf_title(ASCIIToUTF16("ASDF"));
-  GURL google_url("http://google.com");
-  string16 google_title(ASCIIToUTF16("Google"));
-  GURL news_url("http://news.google.com");
-  string16 news_title(ASCIIToUTF16("Google News"));
-
-  // Add asdf_url to history.
-  AddPageToHistory(asdf_url, asdf_title);
-
-  // Make TopSites reread from the db.
-  StartQueryForMostVisited();
-  WaitForHistory();
-
-  // Add a thumbnail.
-  gfx::Image tmp_bitmap(CreateBitmap(SK_ColorBLUE));
-  ASSERT_TRUE(top_sites()->SetPageThumbnail(asdf_url, tmp_bitmap,
-                                            ThumbnailScore()));
-
-  RecreateTopSitesAndBlock();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-    ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(asdf_url, querier.urls()[0].url);
-    EXPECT_EQ(asdf_title, querier.urls()[0].title);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
-
-    scoped_refptr<base::RefCountedMemory> read_data;
-    EXPECT_TRUE(top_sites()->GetPageThumbnail(asdf_url, &read_data));
-    EXPECT_TRUE(ThumbnailEqualsBytes(tmp_bitmap, read_data.get()));
-  }
-
-  MostVisitedURL url2;
-  url2.url = google_url;
-  url2.title = google_title;
-  url2.redirects.push_back(url2.url);
-
-  AddPageToHistory(url2.url, url2.title);
-
-  // Add new thumbnail at rank 0 and shift the other result to 1.
-  ASSERT_TRUE(top_sites()->SetPageThumbnail(google_url,
-                                            tmp_bitmap,
-                                            ThumbnailScore()));
-
-  // Make TopSites reread from the db.
-  RefreshTopSitesAndRecreate();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-    ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(asdf_url, querier.urls()[0].url);
-    EXPECT_EQ(asdf_title, querier.urls()[0].title);
-    EXPECT_EQ(google_url, querier.urls()[1].url);
-    EXPECT_EQ(google_title, querier.urls()[1].title);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
-  }
-}
-
-// More permutations of saving to db.
-TEST_F(TopSitesLikelyImplTest, RealDatabase) {
-  MostVisitedURL url;
-  GURL asdf_url("http://asdf.com");
-  string16 asdf_title(ASCIIToUTF16("ASDF"));
-  GURL google1_url("http://google.com");
-  GURL google2_url("http://google.com/redirect");
-  GURL google3_url("http://www.google.com");
-  string16 google_title(ASCIIToUTF16("Google"));
-  GURL news_url("http://news.google.com");
-  string16 news_title(ASCIIToUTF16("Google News"));
-
-  url.url = asdf_url;
-  url.title = asdf_title;
-  url.redirects.push_back(url.url);
-  gfx::Image asdf_thumbnail(CreateBitmap(SK_ColorRED));
-  ASSERT_TRUE(top_sites()->SetPageThumbnail(
-                  asdf_url, asdf_thumbnail, ThumbnailScore()));
-
-  base::Time add_time(base::Time::Now());
-  AddPageToHistory(url.url, url.title, url.redirects, add_time);
-
-  RefreshTopSitesAndRecreate();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(asdf_url, querier.urls()[0].url);
-    EXPECT_EQ(asdf_title, querier.urls()[0].title);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
-
-    scoped_refptr<base::RefCountedMemory> read_data;
-    EXPECT_TRUE(top_sites()->GetPageThumbnail(asdf_url, &read_data));
-    EXPECT_TRUE(ThumbnailEqualsBytes(asdf_thumbnail, read_data.get()));
-  }
-
-  MostVisitedURL url2;
-  url2.url = google3_url;
-  url2.title = google_title;
-  url2.redirects.push_back(google1_url);
-  url2.redirects.push_back(google2_url);
-  url2.redirects.push_back(google3_url);
-
-  AddPageToHistory(google3_url, url2.title, url2.redirects,
-                   add_time - base::TimeDelta::FromMinutes(1));
-  // Add google twice so that it becomes the first visited site.
-  AddPageToHistory(google3_url, url2.title, url2.redirects,
-                   add_time - base::TimeDelta::FromMinutes(2));
-
-  gfx::Image google_thumbnail(CreateBitmap(SK_ColorBLUE));
-  ASSERT_TRUE(top_sites()->SetPageThumbnail(
-                  url2.url, google_thumbnail, ThumbnailScore()));
-
-  RefreshTopSitesAndRecreate();
-
-  {
-    scoped_refptr<base::RefCountedMemory> read_data;
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    ASSERT_EQ(2u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(google1_url, querier.urls()[0].url);
-    EXPECT_EQ(google_title, querier.urls()[0].title);
-    ASSERT_EQ(3u, querier.urls()[0].redirects.size());
-    EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, &read_data));
-    EXPECT_TRUE(ThumbnailEqualsBytes(google_thumbnail, read_data.get()));
-
-    EXPECT_EQ(asdf_url, querier.urls()[1].url);
-    EXPECT_EQ(asdf_title, querier.urls()[1].title);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 2));
-  }
-
-  gfx::Image weewar_bitmap(CreateBitmap(SK_ColorYELLOW));
-
-  base::Time thumbnail_time(base::Time::Now());
-  ThumbnailScore low_score(1.0, true, true, thumbnail_time);
-  ThumbnailScore medium_score(0.5, true, true, thumbnail_time);
-  ThumbnailScore high_score(0.0, true, true, thumbnail_time);
-
-  // 1. Set to weewar. (Writes the thumbnail to the DB.)
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(google3_url,
-                                            weewar_bitmap,
-                                            medium_score));
-  RefreshTopSitesAndRecreate();
-  {
-    scoped_refptr<base::RefCountedMemory> read_data;
-    EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, &read_data));
-    EXPECT_TRUE(ThumbnailEqualsBytes(weewar_bitmap, read_data.get()));
-  }
-
-  gfx::Image green_bitmap(CreateBitmap(SK_ColorGREEN));
-
-  // 2. Set to google - low score.
-  EXPECT_FALSE(top_sites()->SetPageThumbnail(google3_url,
-                                             green_bitmap,
-                                             low_score));
-
-  // 3. Set to google - high score.
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(google1_url,
-                                            green_bitmap,
-                                            high_score));
-
-  // Check that the thumbnail was updated.
-  RefreshTopSitesAndRecreate();
-  {
-    scoped_refptr<base::RefCountedMemory> read_data;
-    EXPECT_TRUE(top_sites()->GetPageThumbnail(google3_url, &read_data));
-    EXPECT_FALSE(ThumbnailEqualsBytes(weewar_bitmap, read_data.get()));
-    EXPECT_TRUE(ThumbnailEqualsBytes(green_bitmap, read_data.get()));
-  }
-}
-
-TEST_F(TopSitesLikelyImplTest, DeleteNotifications) {
-  GURL google1_url("http://google.com");
-  GURL google2_url("http://google.com/redirect");
-  GURL google3_url("http://www.google.com");
-  string16 google_title(ASCIIToUTF16("Google"));
-  GURL news_url("http://news.google.com");
-  string16 news_title(ASCIIToUTF16("Google News"));
-
-  AddPageToHistory(google1_url, google_title);
-  AddPageToHistory(news_url, news_title);
-
-  RefreshTopSitesAndRecreate();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    ASSERT_EQ(GetPrepopulatePages().size() + 2, querier.urls().size());
-  }
-
-  DeleteURL(news_url);
-
-  // Wait for history to process the deletion.
-  WaitForHistory();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(google_title, querier.urls()[0].title);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
-  }
-
-  // Now reload. This verifies topsites actually wrote the deletion to disk.
-  RefreshTopSitesAndRecreate();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    ASSERT_EQ(1u + GetPrepopulatePages().size(), querier.urls().size());
-    EXPECT_EQ(google_title, querier.urls()[0].title);
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 1));
-  }
-
-  DeleteURL(google1_url);
-
-  // Wait for history to process the deletion.
-  WaitForHistory();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    ASSERT_EQ(GetPrepopulatePages().size(), querier.urls().size());
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
-  }
-
-  // Now reload. This verifies topsites actually wrote the deletion to disk.
-  RefreshTopSitesAndRecreate();
-
-  {
-    TopSitesQuerier querier;
-    querier.QueryTopSites(top_sites(), false);
-
-    ASSERT_EQ(GetPrepopulatePages().size(), querier.urls().size());
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier, 0));
-  }
-}
-
-// Makes sure GetUpdateDelay is updated appropriately.
-TEST_F(TopSitesLikelyImplTest, GetUpdateDelay) {
-  SetLastNumUrlsChanged(0);
-  EXPECT_EQ(30, GetUpdateDelay().InSeconds());
-
-  MostVisitedURLList url_list;
-  url_list.resize(20);
-  GURL tmp_url(GURL("http://x"));
-  for (size_t i = 0; i < url_list.size(); ++i) {
-    url_list[i].url = tmp_url;
-    url_list[i].redirects.push_back(tmp_url);
-  }
-  SetTopSites(url_list);
-  EXPECT_EQ(20u, last_num_urls_changed());
-  SetLastNumUrlsChanged(0);
-  EXPECT_EQ(60, GetUpdateDelay().InMinutes());
-
-  SetLastNumUrlsChanged(3);
-  EXPECT_EQ(52, GetUpdateDelay().InMinutes());
-
-  SetLastNumUrlsChanged(20);
-  EXPECT_EQ(1, GetUpdateDelay().InMinutes());
-}
-
-TEST_F(TopSitesLikelyMigrationTest, Migrate) {
-  EXPECT_TRUE(IsTopSitesLoaded());
-
-  // Make sure the data was migrated to top sites.
-  ASSERT_NO_FATAL_FAILURE(MigrationAssertions());
-
-  // We need to wait for top sites and history to finish processing requests.
-  WaitForTopSites();
-  WaitForHistory();
-
-  // Make sure there is no longer a Thumbnails file on disk.
-  ASSERT_FALSE(base::PathExists(
-                   profile()->GetPath().Append(chrome::kThumbnailsFilename)));
-
-  // Recreate top sites and make sure everything is still there.
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  RecreateTopSitesAndBlock();
-
-  ASSERT_NO_FATAL_FAILURE(MigrationAssertions());
-}
-
-// Verifies that callbacks are notified correctly if requested before top sites
-// has loaded.
-TEST_F(TopSitesLikelyImplTest, NotifyCallbacksWhenLoaded) {
-  // Recreate top sites. It won't be loaded now.
-  profile()->CreateTopSites();
-
-  EXPECT_FALSE(IsTopSitesLoaded());
-
-  TopSitesQuerier querier1;
-  TopSitesQuerier querier2;
-  TopSitesQuerier querier3;
-
-  // Starts the queries.
-  querier1.QueryTopSites(top_sites(), false);
-  querier2.QueryTopSites(top_sites(), false);
-  querier3.QueryTopSites(top_sites(), false);
-
-  // We shouldn't have gotten a callback.
-  EXPECT_EQ(0, querier1.number_of_callbacks());
-  EXPECT_EQ(0, querier2.number_of_callbacks());
-  EXPECT_EQ(0, querier3.number_of_callbacks());
-
-  // Wait for loading to complete.
-  profile()->BlockUntilTopSitesLoaded();
-
-  // Now we should have gotten the callbacks.
-  EXPECT_EQ(1, querier1.number_of_callbacks());
-  EXPECT_EQ(GetPrepopulatePages().size(), querier1.urls().size());
-  EXPECT_EQ(1, querier2.number_of_callbacks());
-  EXPECT_EQ(GetPrepopulatePages().size(), querier2.urls().size());
-  EXPECT_EQ(1, querier3.number_of_callbacks());
-  EXPECT_EQ(GetPrepopulatePages().size(), querier3.urls().size());
-
-  // Reset the top sites.
-  MostVisitedURLList pages;
-  MostVisitedURL url;
-  url.url = GURL("http://1.com/");
-  url.redirects.push_back(url.url);
-  pages.push_back(url);
-  url.url = GURL("http://2.com/");
-  url.redirects.push_back(url.url);
-  pages.push_back(url);
-  SetTopSites(pages);
-
-  // Recreate top sites. It won't be loaded now.
-  profile()->CreateTopSites();
-
-  EXPECT_FALSE(IsTopSitesLoaded());
-
-  TopSitesQuerier querier4;
-
-  // Query again.
-  querier4.QueryTopSites(top_sites(), false);
-
-  // We shouldn't have gotten a callback.
-  EXPECT_EQ(0, querier4.number_of_callbacks());
-
-  // Wait for loading to complete.
-  profile()->BlockUntilTopSitesLoaded();
-
-  // Now we should have gotten the callbacks.
-  EXPECT_EQ(1, querier4.number_of_callbacks());
-  ASSERT_EQ(2u + GetPrepopulatePages().size(), querier4.urls().size());
-
-  EXPECT_EQ("http://1.com/", querier4.urls()[0].url.spec());
-  EXPECT_EQ("http://2.com/", querier4.urls()[1].url.spec());
-  ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier4, 2));
-
-  // Reset the top sites again, this time don't reload.
-  url.url = GURL("http://3.com/");
-  url.redirects.push_back(url.url);
-  pages.push_back(url);
-  SetTopSites(pages);
-
-  // Query again.
-  TopSitesQuerier querier5;
-  querier5.QueryTopSites(top_sites(), true);
-
-  EXPECT_EQ(1, querier5.number_of_callbacks());
-
-  ASSERT_EQ(3u + GetPrepopulatePages().size(), querier5.urls().size());
-  EXPECT_EQ("http://1.com/", querier5.urls()[0].url.spec());
-  EXPECT_EQ("http://2.com/", querier5.urls()[1].url.spec());
-  EXPECT_EQ("http://3.com/", querier5.urls()[2].url.spec());
-  ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(querier5, 3));
-}
-
-// Makes sure canceled requests are not notified.
-TEST_F(TopSitesLikelyImplTest, CancelingRequestsForTopSites) {
-  // Recreate top sites. It won't be loaded now.
-  profile()->CreateTopSites();
-
-  EXPECT_FALSE(IsTopSitesLoaded());
-
-  TopSitesQuerier querier1;
-  TopSitesQuerier querier2;
-
-  // Starts the queries.
-  querier1.QueryTopSites(top_sites(), false);
-  querier2.QueryTopSites(top_sites(), false);
-
-  // We shouldn't have gotten a callback.
-  EXPECT_EQ(0, querier1.number_of_callbacks());
-  EXPECT_EQ(0, querier2.number_of_callbacks());
-
-  querier2.CancelRequest();
-
-  // Wait for loading to complete.
-  profile()->BlockUntilTopSitesLoaded();
-
-  // The first callback should succeed.
-  EXPECT_EQ(1, querier1.number_of_callbacks());
-  EXPECT_EQ(GetPrepopulatePages().size(), querier1.urls().size());
-
-  // And the canceled callback should not be notified.
-  EXPECT_EQ(0, querier2.number_of_callbacks());
-}
-
-// Makes sure temporary thumbnails are copied over correctly.
-TEST_F(TopSitesLikelyImplTest, AddTemporaryThumbnail) {
-  GURL unknown_url("http://news.google.com/");
-  GURL invalid_url("chrome://thumb/http://google.com/");
-  GURL url1a("http://google.com/");
-  GURL url1b("http://www.google.com/");
-
-  // Create a dummy thumbnail.
-  gfx::Image thumbnail(CreateBitmap(SK_ColorRED));
-
-  ThumbnailScore medium_score(0.5, true, true, base::Time::Now());
-
-  // Don't store thumbnails for Javascript URLs.
-  EXPECT_FALSE(top_sites()->SetPageThumbnail(invalid_url,
-                                             thumbnail,
-                                             medium_score));
-  // Store thumbnails for unknown (but valid) URLs temporarily - calls
-  // AddTemporaryThumbnail.
-  EXPECT_TRUE(top_sites()->SetPageThumbnail(unknown_url,
-                                            thumbnail,
-                                            medium_score));
-
-  // We shouldn't get the thumnail back though (the url isn't in to sites yet).
-  scoped_refptr<base::RefCountedMemory> out;
-  EXPECT_FALSE(top_sites()->GetPageThumbnail(unknown_url, &out));
-  // But we should be able to get the temporary page thumbnail score.
-  ThumbnailScore out_score;
-  EXPECT_TRUE(top_sites()->GetTemporaryPageThumbnailScore(unknown_url,
-                                                          &out_score));
-  EXPECT_TRUE(medium_score.Equals(out_score));
-
-  std::vector<MostVisitedURL> list;
-
-  MostVisitedURL mv;
-  mv.url = unknown_url;
-  mv.redirects.push_back(mv.url);
-  mv.redirects.push_back(url1a);
-  mv.redirects.push_back(url1b);
-  list.push_back(mv);
-
-  // Update URLs. This should result in using thumbnail.
-  SetTopSites(list);
-
-  ASSERT_TRUE(top_sites()->GetPageThumbnail(unknown_url, &out));
-  EXPECT_TRUE(ThumbnailEqualsBytes(thumbnail, out.get()));
-}
-
-// Tests variations of blacklisting.
-TEST_F(TopSitesLikelyImplTest, Blacklisting) {
-  MostVisitedURLList pages;
-  MostVisitedURL url, url1;
-  url.url = GURL("http://bbc.com/");
-  url.redirects.push_back(url.url);
-  pages.push_back(url);
-  url1.url = GURL("http://google.com/");
-  url1.redirects.push_back(url1.url);
-  pages.push_back(url1);
-
-  SetTopSites(pages);
-  EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
-
-  // Blacklist google.com.
-  top_sites()->AddBlacklistedURL(GURL("http://google.com/"));
-
-  GURL prepopulate_url = GetPrepopulatePages()[0].url;
-
-  EXPECT_TRUE(top_sites()->HasBlacklistedItems());
-  EXPECT_TRUE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
-  EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://bbc.com/")));
-  EXPECT_FALSE(top_sites()->IsBlacklisted(prepopulate_url));
-
-  // Make sure the blacklisted site isn't returned in the results.
-  {
-    TopSitesQuerier q;
-    q.QueryTopSites(top_sites(), true);
-    ASSERT_EQ(1u + GetPrepopulatePages().size(), q.urls().size());
-    EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
-  }
-
-  // Recreate top sites and make sure blacklisted url was correctly read.
-  RecreateTopSitesAndBlock();
-  {
-    TopSitesQuerier q;
-    q.QueryTopSites(top_sites(), true);
-    ASSERT_EQ(1u + GetPrepopulatePages().size(), q.urls().size());
-    EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 1));
-  }
-
-  // Blacklist one of the prepopulate urls.
-  top_sites()->AddBlacklistedURL(prepopulate_url);
-  EXPECT_TRUE(top_sites()->HasBlacklistedItems());
-
-  // Make sure the blacklisted prepopulate url isn't returned.
-  {
-    TopSitesQuerier q;
-    q.QueryTopSites(top_sites(), true);
-    ASSERT_EQ(1u + GetPrepopulatePages().size() - 1, q.urls().size());
-    EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
-    for (size_t i = 1; i < q.urls().size(); ++i)
-      EXPECT_NE(prepopulate_url.spec(), q.urls()[i].url.spec());
-  }
-
-  // Mark google as no longer blacklisted.
-  top_sites()->RemoveBlacklistedURL(GURL("http://google.com/"));
-  EXPECT_TRUE(top_sites()->HasBlacklistedItems());
-  EXPECT_FALSE(top_sites()->IsBlacklisted(GURL("http://google.com/")));
-
-  // Make sure google is returned now.
-  {
-    TopSitesQuerier q;
-    q.QueryTopSites(top_sites(), true);
-    ASSERT_EQ(2u + GetPrepopulatePages().size() - 1, q.urls().size());
-    EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
-    EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
-    // Android has only one prepopulated page which has been blacklisted, so
-    // only 2 urls are returned.
-    if (q.urls().size() > 2)
-      EXPECT_NE(prepopulate_url.spec(), q.urls()[2].url.spec());
-    else
-      EXPECT_EQ(1u, GetPrepopulatePages().size());
-  }
-
-  // Remove all blacklisted sites.
-  top_sites()->ClearBlacklistedURLs();
-  EXPECT_FALSE(top_sites()->HasBlacklistedItems());
-
-  {
-    TopSitesQuerier q;
-    q.QueryTopSites(top_sites(), true);
-    ASSERT_EQ(2u + GetPrepopulatePages().size(), q.urls().size());
-    EXPECT_EQ("http://bbc.com/", q.urls()[0].url.spec());
-    EXPECT_EQ("http://google.com/", q.urls()[1].url.spec());
-    ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 2));
-  }
-}
-
-// Makes sure prepopulated pages exist.
-TEST_F(TopSitesLikelyImplTest, AddPrepopulatedPages) {
-  TopSitesQuerier q;
-  q.QueryTopSites(top_sites(), true);
-  EXPECT_EQ(GetPrepopulatePages().size(), q.urls().size());
-  ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
-
-  MostVisitedURLList pages = q.urls();
-  EXPECT_FALSE(AddPrepopulatedPages(&pages));
-
-  EXPECT_EQ(GetPrepopulatePages().size(), pages.size());
-  q.set_urls(pages);
-  ASSERT_NO_FATAL_FAILURE(ContainsPrepopulatePages(q, 0));
-}
-
-// Makes sure creating top sites before history is created works.
-TEST_F(TopSitesLikelyImplTest, CreateTopSitesThenHistory) {
-  profile()->DestroyTopSites();
-  profile()->DestroyHistoryService();
-
-  // Remove the TopSites file. This forces TopSites to wait until history loads
-  // before TopSites is considered loaded.
-  sql::Connection::Delete(
-      profile()->GetPath().Append(chrome::kTopSitesFilename));
-
-  // Create TopSites, but not History.
-  profile()->CreateTopSites();
-  WaitForTopSites();
-  EXPECT_FALSE(IsTopSitesLoaded());
-
-  // Load history, which should make TopSites finish loading too.
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  profile()->BlockUntilTopSitesLoaded();
-  EXPECT_TRUE(IsTopSitesLoaded());
-}
-
-class TopSitesLikelyUnloadTest : public TopSitesLikelyImplTest {
- public:
-  TopSitesLikelyUnloadTest() {}
-
-  virtual bool CreateHistoryAndTopSites() OVERRIDE {
-    return false;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TopSitesLikelyUnloadTest);
-};
-
-// Makes sure if history is unloaded after topsites is loaded we don't hit any
-// assertions.
-TEST_F(TopSitesLikelyUnloadTest, UnloadHistoryTest) {
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  profile()->CreateTopSites();
-  profile()->BlockUntilTopSitesLoaded();
-  HistoryServiceFactory::GetForProfile(
-      profile(), Profile::EXPLICIT_ACCESS)->UnloadBackend();
-  profile()->BlockUntilHistoryProcessesPendingRequests();
-}
-
-// Makes sure if history (with migration code) is unloaded after topsites is
-// loaded we don't hit any assertions.
-TEST_F(TopSitesLikelyUnloadTest, UnloadWithMigration) {
-  // Set up history and thumbnails as they would be before migration.
-  base::FilePath data_path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_path));
-  data_path = data_path.AppendASCII("top_sites");
-  ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-      data_path.AppendASCII("history.19.sql"),
-      profile()->GetPath().Append(chrome::kHistoryFilename)));
-  ASSERT_NO_FATAL_FAILURE(ExecuteSQLScript(
-      data_path.AppendASCII("thumbnails.3.sql"),
-      profile()->GetPath().Append(chrome::kThumbnailsFilename)));
-
-  // Create history and block until it's loaded.
-  ASSERT_TRUE(profile()->CreateHistoryService(false, false));
-  profile()->BlockUntilHistoryProcessesPendingRequests();
-
-  // Create top sites and unload history.
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_TOP_SITES_LOADED,
-      content::Source<Profile>(profile()));
-  profile()->CreateTopSites();
-  HistoryServiceFactory::GetForProfile(
-      profile(), Profile::EXPLICIT_ACCESS)->UnloadBackend();
-  profile()->BlockUntilHistoryProcessesPendingRequests();
-  observer.Wait();
-}
-
-}  // namespace history
diff --git a/chrome/browser/history/url_index_private_data.cc b/chrome/browser/history/url_index_private_data.cc
index d4548cb..0d94e14 100644
--- a/chrome/browser/history/url_index_private_data.cc
+++ b/chrome/browser/history/url_index_private_data.cc
@@ -595,10 +595,8 @@
 
     // Filter for each remaining, unique character in the term.
     Char16Set leftover_chars = Char16SetFromString16(leftovers);
-    Char16Set unique_chars;
-    std::set_difference(leftover_chars.begin(), leftover_chars.end(),
-                        prefix_chars.begin(), prefix_chars.end(),
-                        std::inserter(unique_chars, unique_chars.begin()));
+    Char16Set unique_chars =
+        base::STLSetDifference<Char16Set>(leftover_chars, prefix_chars);
 
     // Reduce the word set with any leftover, unprocessed characters.
     if (!unique_chars.empty()) {
diff --git a/chrome/browser/icon_loader_chromeos.cc b/chrome/browser/icon_loader_chromeos.cc
index 1329845..c55d7c8 100644
--- a/chrome/browser/icon_loader_chromeos.cc
+++ b/chrome/browser/icon_loader_chromeos.cc
@@ -91,7 +91,7 @@
   // 'video': /\.(mov|mp4|m4v|mpe?g4?|ogm|ogv|ogx|webm)$/i
 
   const ExtensionIconMap::value_type kExtensionIdrBySizeData[] = {
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
     std::make_pair(".m4a", kAudioIdrs),
     std::make_pair(".mp3", kAudioIdrs),
     std::make_pair(".pdf", kPdfIdrs),
diff --git a/chrome/browser/invalidation/ticl_invalidation_service.cc b/chrome/browser/invalidation/ticl_invalidation_service.cc
index 140c990..2d11a0d 100644
--- a/chrome/browser/invalidation/ticl_invalidation_service.cc
+++ b/chrome/browser/invalidation/ticl_invalidation_service.cc
@@ -5,9 +5,12 @@
 #include "chrome/browser/invalidation/ticl_invalidation_service.h"
 
 #include "base/command_line.h"
+#include "base/metrics/histogram.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/invalidation/invalidation_service_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/about_signin_internals.h"
+#include "chrome/browser/signin/about_signin_internals_factory.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"
@@ -245,6 +248,23 @@
     }
     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
       // This is a real auth error.
+      // Report time since token was issued for invalid credentials error.
+      base::Time auth_token_time =
+          AboutSigninInternalsFactory::GetForProfile(profile_)->
+              GetTokenTime(GaiaConstants::kGaiaOAuth2LoginRefreshToken);
+      if (!auth_token_time.is_null()) {
+        base::TimeDelta age = base::Time::Now() - auth_token_time;
+        if (age < base::TimeDelta::FromHours(1)) {
+          UMA_HISTOGRAM_CUSTOM_TIMES(
+              "Sync.AuthInvalidationRejectedTokenAgeShort",
+              age,
+              base::TimeDelta::FromSeconds(1),
+              base::TimeDelta::FromHours(1),
+              50);
+        }
+        UMA_HISTOGRAM_COUNTS("Sync.AuthInvalidationRejectedTokenAgeLong",
+                             age.InDays());
+      }
       invalidator_registrar_->UpdateInvalidatorState(
           syncer::INVALIDATION_CREDENTIALS_REJECTED);
       break;
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index d096e43..d2745b3 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread.h"
 #include "base/threading/worker_pool.h"
 #include "base/time/default_tick_clock.h"
@@ -594,8 +595,12 @@
       new net::URLRequestJobFactoryImpl());
   job_factory->SetProtocolHandler(chrome::kDataScheme,
                                   new net::DataProtocolHandler());
-  job_factory->SetProtocolHandler(chrome::kFileScheme,
-                                  new net::FileProtocolHandler());
+  job_factory->SetProtocolHandler(
+      chrome::kFileScheme,
+      new net::FileProtocolHandler(
+          content::BrowserThread::GetBlockingPool()->
+              GetTaskRunnerWithShutdownBehavior(
+                  base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
 #if !defined(DISABLE_FTP_SUPPORT)
   globals_->proxy_script_fetcher_ftp_transaction_factory.reset(
       new net::FtpNetworkLayer(globals_->host_resolver.get()));
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc
index 0b67716..503a074 100644
--- a/chrome/browser/lifetime/application_lifetime.cc
+++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 
 #include "ash/shell.h"
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -16,6 +17,7 @@
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/download_service.h"
+#include "chrome/browser/lifetime/browser_close_manager.h"
 #include "chrome/browser/metrics/thread_watcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -41,6 +43,10 @@
 #include "chromeos/dbus/update_engine_client.h"
 #endif
 
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
 namespace chrome {
 namespace {
 
@@ -89,21 +95,20 @@
 }
 
 void CloseAllBrowsers() {
-  bool session_ending =
-      browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
-  // 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 there are no browsers, 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) {
+    // Tell everyone that we are shutting down.
+    browser_shutdown::SetTryingToQuit(true);
+
+#if defined(ENABLE_SESSION_SERVICE)
+    // If ShuttingDownWithoutClosingBrowsers() returns true, the session
+    // services may not get a chance to shut down normally, so explicitly shut
+    // them down here to ensure they have a chance to persist their data.
+    ProfileManager::ShutdownSessionServices();
+#endif
+
     chrome::NotifyAndTerminate(true);
     chrome::OnAppExiting();
     return;
@@ -113,33 +118,9 @@
   chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker(
       "StartedClosingWindows", false);
 #endif
-  for (scoped_ptr<chrome::BrowserIterator> it_ptr(
-           new chrome::BrowserIterator());
-       !it_ptr->done();) {
-    Browser* browser = **it_ptr;
-    browser->window()->Close();
-    if (!session_ending) {
-      it_ptr->Next();
-    } else {
-      // This path is hit during logoff/power-down. In this case we won't get
-      // a final message and so we force the browser to be deleted.
-      // Close doesn't immediately destroy the browser
-      // (Browser::TabStripEmpty() uses invoke later) but when we're ending the
-      // session we need to make sure the browser is destroyed now. So, invoke
-      // DestroyBrowser to make sure the browser is deleted and cleanup can
-      // happen.
-      while (browser->tab_strip_model()->count())
-        delete browser->tab_strip_model()->GetWebContentsAt(0);
-      browser->window()->DestroyBrowser();
-      it_ptr.reset(new chrome::BrowserIterator());
-      if (!it_ptr->done() && browser == **it_ptr) {
-        // Destroying the browser should have removed it from the browser list.
-        // We should never get here.
-        NOTREACHED();
-        return;
-      }
-    }
-  }
+  scoped_refptr<BrowserCloseManager> browser_close_manager =
+      new BrowserCloseManager;
+  browser_close_manager->StartClosingBrowsers();
 }
 
 void AttemptUserExit() {
@@ -273,6 +254,9 @@
       content::NotificationService::AllSources(),
       content::NotificationService::NoDetails());
 
+#if defined(OS_WIN)
+  base::win::SetShouldCrashOnProcessDetach(false);
+#endif
   // This will end by terminating the process.
   content::ImmediateShutdownAndExitProcess();
 }
diff --git a/chrome/browser/lifetime/browser_close_manager.cc b/chrome/browser/lifetime/browser_close_manager.cc
new file mode 100644
index 0000000..aa6f0fd
--- /dev/null
+++ b/chrome/browser/lifetime/browser_close_manager.cc
@@ -0,0 +1,164 @@
+// Copyright 2013 The Chromium Authors. 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/lifetime/browser_close_manager.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_shutdown.h"
+#include "chrome/browser/download/download_service.h"
+#include "chrome/browser/download/download_service_factory.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_iterator.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/chrome_pages.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/web_contents.h"
+
+BrowserCloseManager::BrowserCloseManager() : current_browser_(NULL) {}
+
+BrowserCloseManager::~BrowserCloseManager() {}
+
+void BrowserCloseManager::StartClosingBrowsers() {
+  // If the session is ending or batch browser shutdown is disabled, skip
+  // straight to closing the browsers. In the former case, there's no time to
+  // wait for beforeunload dialogs; in the latter, the windows will manage
+  // showing their own dialogs.
+  if (browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION ||
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBatchedShutdown)) {
+    CloseBrowsers();
+    return;
+  }
+  TryToCloseBrowsers();
+}
+
+void BrowserCloseManager::CancelBrowserClose() {
+  browser_shutdown::SetTryingToQuit(false);
+  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
+    it->ResetBeforeUnloadHandlers();
+  }
+}
+
+void BrowserCloseManager::TryToCloseBrowsers() {
+  // If all browser windows can immediately be closed, fall out of this loop and
+  // close the browsers. If any browser window cannot be closed, temporarily
+  // stop closing. CallBeforeUnloadHandlers prompts the user and calls
+  // OnBrowserReportCloseable with the result. If the user confirms the close,
+  // this will trigger TryToCloseBrowsers to try again.
+  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
+    if (it->CallBeforeUnloadHandlers(
+            base::Bind(&BrowserCloseManager::OnBrowserReportCloseable, this))) {
+      current_browser_ = *it;
+      return;
+    }
+  }
+  CheckForDownloadsInProgress();
+}
+
+void BrowserCloseManager::OnBrowserReportCloseable(bool proceed) {
+  if (!current_browser_)
+    return;
+
+  current_browser_ = NULL;
+
+  if (proceed)
+    TryToCloseBrowsers();
+  else
+    CancelBrowserClose();
+}
+
+void BrowserCloseManager::CheckForDownloadsInProgress() {
+  int download_count = DownloadService::DownloadCountAllProfiles();
+  if (download_count == 0) {
+    CloseBrowsers();
+    return;
+  }
+  ConfirmCloseWithPendingDownloads(
+      download_count,
+      base::Bind(&BrowserCloseManager::OnReportDownloadsCancellable, this));
+}
+
+void BrowserCloseManager::ConfirmCloseWithPendingDownloads(
+    int download_count,
+    const base::Callback<void(bool)>& callback) {
+  Browser* browser =
+      BrowserList::GetInstance(chrome::GetActiveDesktop())->GetLastActive();
+  DCHECK(browser);
+  browser->window()->ConfirmBrowserCloseWithPendingDownloads(
+      download_count,
+      Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN,
+      true,
+      callback);
+}
+
+void BrowserCloseManager::OnReportDownloadsCancellable(bool proceed) {
+  if (proceed) {
+    CloseBrowsers();
+    return;
+  }
+
+  CancelBrowserClose();
+
+  // Open the downloads page for each profile with downloads in progress.
+  std::vector<Profile*> profiles(
+      g_browser_process->profile_manager()->GetLoadedProfiles());
+  for (std::vector<Profile*>::iterator it = profiles.begin();
+       it != profiles.end();
+       ++it) {
+    DownloadService* download_service =
+        DownloadServiceFactory::GetForBrowserContext(*it);
+    if (download_service->DownloadCount() > 0) {
+      Browser* browser =
+          chrome::FindOrCreateTabbedBrowser(*it, chrome::GetActiveDesktop());
+      DCHECK(browser);
+      chrome::ShowDownloads(browser);
+    }
+  }
+}
+
+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
+
+  bool session_ending =
+      browser_shutdown::GetShutdownType() == browser_shutdown::END_SESSION;
+  for (scoped_ptr<chrome::BrowserIterator> it_ptr(
+           new chrome::BrowserIterator());
+       !it_ptr->done();) {
+    Browser* browser = **it_ptr;
+    browser->window()->Close();
+    if (!session_ending) {
+      it_ptr->Next();
+    } else {
+      // This path is hit during logoff/power-down. In this case we won't get
+      // a final message and so we force the browser to be deleted.
+      // Close doesn't immediately destroy the browser
+      // (Browser::TabStripEmpty() uses invoke later) but when we're ending the
+      // session we need to make sure the browser is destroyed now. So, invoke
+      // DestroyBrowser to make sure the browser is deleted and cleanup can
+      // happen.
+      while (browser->tab_strip_model()->count())
+        delete browser->tab_strip_model()->GetWebContentsAt(0);
+      browser->window()->DestroyBrowser();
+      it_ptr.reset(new chrome::BrowserIterator());
+      if (!it_ptr->done() && browser == **it_ptr) {
+        // Destroying the browser should have removed it from the browser list.
+        // We should never get here.
+        NOTREACHED();
+        return;
+      }
+    }
+  }
+}
diff --git a/chrome/browser/lifetime/browser_close_manager.h b/chrome/browser/lifetime/browser_close_manager.h
new file mode 100644
index 0000000..0e2c4a7
--- /dev/null
+++ b/chrome/browser/lifetime/browser_close_manager.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 CHROME_BROWSER_LIFETIME_BROWSER_CLOSE_MANAGER_H_
+#define CHROME_BROWSER_LIFETIME_BROWSER_CLOSE_MANAGER_H_
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+
+class Browser;
+
+// Manages confirming that browser windows are closeable and closing them at
+// shutdown.
+class BrowserCloseManager : public base::RefCounted<BrowserCloseManager> {
+ public:
+  BrowserCloseManager();
+
+  // Starts closing all browser windows.
+  void StartClosingBrowsers();
+
+ protected:
+  friend class base::RefCounted<BrowserCloseManager>;
+
+  virtual ~BrowserCloseManager();
+
+  virtual void ConfirmCloseWithPendingDownloads(
+      int download_count,
+      const base::Callback<void(bool)>& callback);
+
+ private:
+  // Notifies all browser windows that the close is cancelled.
+  void CancelBrowserClose();
+
+  // Checks whether all browser windows are ready to close and closes them if
+  // they are.
+  void TryToCloseBrowsers();
+
+  // Called to report whether a beforeunload dialog was accepted.
+  void OnBrowserReportCloseable(bool proceed);
+
+  // Closes all browser windows.
+  void CloseBrowsers();
+
+  // Checks whether there are any downloads in-progress and prompts the user to
+  // cancel them. If there are no downloads or the user accepts the cancel
+  // downloads dialog, CloseBrowsers is called to continue with the shutdown.
+  // Otherwise, if the user declines to cancel downloads, the shutdown is
+  // aborted and the downloads page is shown for each profile with in-progress
+  // downloads.
+  void CheckForDownloadsInProgress();
+
+  // Called to report whether downloads may be cancelled during shutdown.
+  void OnReportDownloadsCancellable(bool proceed);
+
+  // The browser for which we are waiting for a callback to
+  // OnBrowserReportCloseable.
+  Browser* current_browser_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserCloseManager);
+};
+
+#endif  // CHROME_BROWSER_LIFETIME_BROWSER_CLOSE_MANAGER_H_
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
new file mode 100644
index 0000000..0aaa132
--- /dev/null
+++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -0,0 +1,713 @@
+// Copyright 2013 The Chromium Authors. 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 "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_shutdown.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/lifetime/browser_close_manager.h"
+#include "chrome/browser/net/url_request_mock_util.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#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_iterator.h"
+#include "chrome/browser/ui/browser_window.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/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/download_item.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/download_test_observer.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/test/net/url_request_slow_download_job.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace {
+
+class AppModalDialogObserver {
+ public:
+  AppModalDialogObserver() {}
+
+  void Start() {
+    observer_.reset(new content::WindowedNotificationObserver(
+        chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
+        content::NotificationService::AllSources()));
+  }
+
+  void AcceptClose() {
+    NativeAppModalDialog* dialog = GetNextDialog();
+    ASSERT_TRUE(dialog);
+    dialog->AcceptAppModalDialog();
+  }
+
+  void CancelClose() {
+    NativeAppModalDialog* dialog = GetNextDialog();
+    ASSERT_TRUE(dialog);
+    dialog->CancelAppModalDialog();
+  }
+
+ private:
+  NativeAppModalDialog* GetNextDialog() {
+    DCHECK(observer_);
+    observer_->Wait();
+    if (observer_->source() == content::NotificationService::AllSources())
+      return NULL;
+
+    AppModalDialog* dialog =
+        content::Source<AppModalDialog>(observer_->source()).ptr();
+    EXPECT_TRUE(dialog->IsJavaScriptModalDialog());
+    JavaScriptAppModalDialog* js_dialog =
+        static_cast<JavaScriptAppModalDialog*>(dialog);
+    observer_.reset(new content::WindowedNotificationObserver(
+        chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
+        content::NotificationService::AllSources()));
+    return js_dialog->native_dialog();
+  }
+
+  scoped_ptr<content::WindowedNotificationObserver> observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppModalDialogObserver);
+};
+
+class RepeatedNotificationObserver : public content::NotificationObserver {
+ public:
+  explicit RepeatedNotificationObserver(int type, int count)
+      : num_outstanding_(count), running_(false) {
+    registrar_.Add(this, type, content::NotificationService::AllSources());
+  }
+
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE {
+    ASSERT_GT(num_outstanding_, 0);
+    if (!--num_outstanding_ && running_) {
+      content::BrowserThread::PostTask(
+          content::BrowserThread::UI, FROM_HERE, run_loop_.QuitClosure());
+    }
+  }
+
+  void Wait() {
+    if (num_outstanding_ <= 0)
+      return;
+
+    running_ = true;
+    run_loop_.Run();
+    running_ = false;
+  }
+
+ private:
+  int num_outstanding_;
+  content::NotificationRegistrar registrar_;
+  bool running_;
+  base::RunLoop run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(RepeatedNotificationObserver);
+};
+
+class TestBrowserCloseManager : public BrowserCloseManager {
+ public:
+  enum UserChoice {
+    USER_CHOICE_USER_CANCELS_CLOSE,
+    USER_CHOICE_USER_ALLOWS_CLOSE,
+  };
+
+  static void AttemptClose(UserChoice user_choice) {
+    scoped_refptr<BrowserCloseManager> browser_close_manager =
+        new TestBrowserCloseManager(user_choice);
+    browser_close_manager->StartClosingBrowsers();
+  }
+
+ protected:
+  virtual ~TestBrowserCloseManager() {}
+
+  virtual void ConfirmCloseWithPendingDownloads(
+      int download_count,
+      const base::Callback<void(bool)>& callback) OVERRIDE {
+    switch (user_choice_) {
+      case USER_CHOICE_USER_CANCELS_CLOSE: {
+        callback.Run(false);
+        break;
+      }
+      case USER_CHOICE_USER_ALLOWS_CLOSE: {
+        callback.Run(true);
+        break;
+      }
+    }
+  }
+
+ private:
+  explicit TestBrowserCloseManager(UserChoice user_choice)
+      : user_choice_(user_choice) {}
+
+  UserChoice user_choice_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestBrowserCloseManager);
+};
+
+}  // namespace
+
+class BrowserCloseManagerBrowserTest
+    : public InProcessBrowserTest,
+      public testing::WithParamInterface<bool> {
+ protected:
+  virtual void SetUpOnMainThread() OVERRIDE {
+    InProcessBrowserTest::SetUpOnMainThread();
+    SessionStartupPref::SetStartupPref(
+        browser()->profile(), SessionStartupPref(SessionStartupPref::LAST));
+    browsers_.push_back(browser());
+    dialogs_.Start();
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO,
+        FROM_HERE,
+        base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
+  }
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    command_line->AppendSwitch(switches::kEnableBatchedShutdown);
+    if (GetParam())
+      command_line->AppendSwitch(switches::kEnableFastUnload);
+  }
+
+  void CreateStalledDownload(Browser* browser) {
+    content::DownloadTestObserverInProgress observer(
+        content::BrowserContext::GetDownloadManager(browser->profile()), 1);
+    ui_test_utils::NavigateToURLWithDisposition(
+        browser,
+        GURL(content::URLRequestSlowDownloadJob::kKnownSizeUrl),
+        NEW_BACKGROUND_TAB,
+        ui_test_utils::BROWSER_TEST_NONE);
+    observer.WaitForFinished();
+    EXPECT_EQ(
+        1UL,
+        observer.NumDownloadsSeenInState(content::DownloadItem::IN_PROGRESS));
+  }
+
+  std::vector<Browser*> browsers_;
+  AppModalDialogObserver dialogs_;
+};
+
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, TestSingleTabShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/beforeunload.html")));
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browser()->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestShutdownMoreThanOnce) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/beforeunload.html")));
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
+  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browser()->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+  chrome::CloseAllBrowsers();
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, PRE_TestSessionRestore) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/beforeunload.html")));
+  AddBlankTabAndShow(browser());
+  ASSERT_NO_FATAL_FAILURE(
+      ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIAboutURL)));
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+
+  browser()->tab_strip_model()
+      ->CloseWebContentsAt(1, TabStripModel::CLOSE_USER_GESTURE);
+  content::TestNavigationObserver navigation_observer(
+      browser()->tab_strip_model()->GetActiveWebContents(), 1);
+  ASSERT_NO_FATAL_FAILURE(
+      NavigateToURLWithDisposition(browser(),
+                                   GURL(chrome::kChromeUIVersionURL),
+                                   CURRENT_TAB,
+                                   ui_test_utils::BROWSER_TEST_NONE));
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  navigation_observer.Wait();
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+  chrome::CloseAllBrowsers();
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test that the tab closed after the aborted shutdown attempt is not re-opened
+// when restoring the session.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, TestSessionRestore) {
+  // The testing framework launches Chrome with about:blank as args.
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+  EXPECT_EQ(GURL(chrome::kChromeUIVersionURL),
+            browser()->tab_strip_model()->GetWebContentsAt(0)->GetURL());
+  EXPECT_EQ(GURL("about:blank"),
+            browser()->tab_strip_model()->GetWebContentsAt(1)->GetURL());
+}
+
+// Test that browser windows are only closed if all browsers are ready to close
+// and that all beforeunload dialogs are shown again after a cancel.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, TestMultipleWindows) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+
+  // Cancel shutdown on the first beforeunload event.
+  {
+    RepeatedNotificationObserver cancel_observer(
+        chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
+    chrome::CloseAllBrowsers();
+    ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+    cancel_observer.Wait();
+  }
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count());
+
+  // Cancel shutdown on the second beforeunload event.
+  {
+    RepeatedNotificationObserver cancel_observer(
+        chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
+    chrome::CloseAllBrowsers();
+    ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+    ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+    cancel_observer.Wait();
+  }
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count());
+
+  // Allow shutdown for both beforeunload events.
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test that tabs in the same window with a beforeunload event that hangs are
+// treated the same as the user accepting the close, but do not close the tab
+// early.
+// Test is flaky on windows, disabled. See http://crbug.com/276366
+#if defined(OS_WIN)
+#define MAYBE_TestHangInBeforeUnloadMultipleTabs \
+    DISABLED_TestHangInBeforeUnloadMultipleTabs
+#else
+#define MAYBE_TestHangInBeforeUnloadMultipleTabs \
+    TestHangInBeforeUnloadMultipleTabs
+#endif
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       MAYBE_TestHangInBeforeUnloadMultipleTabs) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload_hang.html")));
+  AddBlankTabAndShow(browsers_[0]);
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  AddBlankTabAndShow(browsers_[0]);
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload_hang.html")));
+
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  // All tabs should still be open.
+  EXPECT_EQ(3, browsers_[0]->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test that tabs in different windows with a beforeunload event that hangs are
+// treated the same as the user accepting the close, but do not close the tab
+// early.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestHangInBeforeUnloadMultipleWindows) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload_hang.html")));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[2], embedded_test_server()->GetURL("/beforeunload_hang.html")));
+
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  // All windows should still be open.
+  EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[2]->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 3);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test that a window created during shutdown is closed.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestAddWindowDuringShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test that a window created during shutdown with a beforeunload handler can
+// cancel the shutdown.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestAddWindowWithBeforeUnloadDuringShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
+  chrome::CloseAllBrowsers();
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count());
+
+  // Allow shutdown for both beforeunload dialogs.
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test that tabs added during shutdown are closed.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestAddTabDuringShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  AddBlankTabAndShow(browsers_[0]);
+  AddBlankTabAndShow(browsers_[1]);
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test that tabs created during shutdown with beforeunload handlers can cancel
+// the shutdown.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestAddTabWithBeforeUnloadDuringShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  AddBlankTabAndShow(browsers_[0]);
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  AddBlankTabAndShow(browsers_[1]);
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(2, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(2, browsers_[1]->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestCloseTabDuringShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
+  chrome::CloseAllBrowsers();
+
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+  browsers_[1]->tab_strip_model()->CloseAllTabs();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  browsers_[1]->tab_strip_model()->CloseAllTabs();
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestOpenAndCloseWindowDuringShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 2);
+  chrome::CloseAllBrowsers();
+
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+  ASSERT_FALSE(browsers_[1]->ShouldCloseWindow());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_FALSE(browsers_[1]->ShouldCloseWindow());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestCloseWindowDuringShutdown) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[0], embedded_test_server()->GetURL("/beforeunload.html")));
+  browsers_.push_back(CreateBrowser(browser()->profile()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browsers_[1], embedded_test_server()->GetURL("/beforeunload.html")));
+  RepeatedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED, 1);
+  chrome::CloseAllBrowsers();
+
+  ASSERT_FALSE(browsers_[0]->ShouldCloseWindow());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.CancelClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  EXPECT_EQ(1, browsers_[0]->tab_strip_model()->count());
+  EXPECT_EQ(1, browsers_[1]->tab_strip_model()->count());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  chrome::CloseAllBrowsers();
+  ASSERT_FALSE(browsers_[0]->ShouldCloseWindow());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test shutdown with a download in progress.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest, TestWithDownloads) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(CreateStalledDownload(browser()));
+  content::TestNavigationObserver navigation_observer(
+      browser()->tab_strip_model()->GetActiveWebContents(), 1);
+  TestBrowserCloseManager::AttemptClose(
+      TestBrowserCloseManager::USER_CHOICE_USER_CANCELS_CLOSE);
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  navigation_observer.Wait();
+  EXPECT_EQ(GURL(chrome::kChromeUIDownloadsURL),
+            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+
+  TestBrowserCloseManager::AttemptClose(
+      TestBrowserCloseManager::USER_CHOICE_USER_ALLOWS_CLOSE);
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test shutdown with a download in progress from one profile, where the only
+// open windows are for another profile.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestWithDownloadsFromDifferentProfiles) {
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  base::FilePath path =
+      profile_manager->user_data_dir().AppendASCII("test_profile");
+  if (!base::PathExists(path))
+    ASSERT_TRUE(file_util::CreateDirectory(path));
+  Profile* other_profile =
+      Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
+  profile_manager->RegisterTestingProfile(other_profile, true, false);
+  Browser* other_profile_browser = CreateBrowser(other_profile);
+
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(CreateStalledDownload(browser()));
+  {
+    RepeatedNotificationObserver close_observer(
+        chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+    browser()->window()->Close();
+    close_observer.Wait();
+  }
+
+  // When the shutdown is cancelled, the downloads page should be opened in a
+  // browser for that profile. Because there are no browsers for that profile, a
+  // new browser should be opened.
+  ui_test_utils::BrowserAddedObserver new_browser_observer;
+  TestBrowserCloseManager::AttemptClose(
+      TestBrowserCloseManager::USER_CHOICE_USER_CANCELS_CLOSE);
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+  Browser* opened_browser = new_browser_observer.WaitForSingleNewBrowser();
+  EXPECT_EQ(
+      GURL(chrome::kChromeUIDownloadsURL),
+      opened_browser->tab_strip_model()->GetActiveWebContents()->GetURL());
+  EXPECT_EQ(GURL("about:blank"),
+            other_profile_browser->tab_strip_model()->GetActiveWebContents()
+                ->GetURL());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 2);
+  TestBrowserCloseManager::AttemptClose(
+      TestBrowserCloseManager::USER_CHOICE_USER_ALLOWS_CLOSE);
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+// Test shutdown with downloads in progress and beforeunload handlers.
+IN_PROC_BROWSER_TEST_P(BrowserCloseManagerBrowserTest,
+                       TestBeforeUnloadAndDownloads) {
+  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  ASSERT_NO_FATAL_FAILURE(CreateStalledDownload(browser()));
+  ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/beforeunload.html")));
+
+  content::WindowedNotificationObserver cancel_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
+      content::NotificationService::AllSources());
+  TestBrowserCloseManager::AttemptClose(
+      TestBrowserCloseManager::USER_CHOICE_USER_CANCELS_CLOSE);
+  ASSERT_NO_FATAL_FAILURE(dialogs_.AcceptClose());
+  cancel_observer.Wait();
+  EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
+
+  RepeatedNotificationObserver close_observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED, 1);
+  TestBrowserCloseManager::AttemptClose(
+      TestBrowserCloseManager::USER_CHOICE_USER_ALLOWS_CLOSE);
+  close_observer.Wait();
+  EXPECT_TRUE(browser_shutdown::IsTryingToQuit());
+  EXPECT_TRUE(chrome::BrowserIterator().done());
+}
+
+INSTANTIATE_TEST_CASE_P(BrowserCloseManagerBrowserTest,
+                        BrowserCloseManagerBrowserTest,
+                        testing::Bool());
diff --git a/chrome/browser/local_discovery/privet_http.h b/chrome/browser/local_discovery/privet_http.h
index d600f47..6b1069c 100644
--- a/chrome/browser/local_discovery/privet_http.h
+++ b/chrome/browser/local_discovery/privet_http.h
@@ -13,7 +13,7 @@
 
 namespace local_discovery {
 
-class PrivetHTTPImpl;
+class PrivetHTTPClient;
 
 // Represents a request to /privet/info. Will store a cached response and token
 // in the PrivetHTTPClient that created.
@@ -24,13 +24,17 @@
     virtual ~Delegate() {}
 
     // In case of non-HTTP errors, |http_code| will be -1.
-    virtual void OnPrivetInfoDone(int http_code,
-                                  const base::DictionaryValue* json_value) = 0;
+    virtual void OnPrivetInfoDone(
+        PrivetInfoOperation* operation,
+        int http_code,
+        const base::DictionaryValue* json_value) = 0;
   };
 
   virtual ~PrivetInfoOperation() {}
 
   virtual void Start() = 0;
+
+  virtual PrivetHTTPClient* GetHTTPClient() = 0;
 };
 
 // Represents a full registration flow (/privet/register), normally consisting
@@ -51,21 +55,25 @@
     ~Delegate() {}
 
     // Called when a user needs to claim the printer by visiting the given URL.
-    virtual void OnPrivetRegisterClaimToken(const std::string& token,
-                                            const GURL& url) = 0;
+    virtual void OnPrivetRegisterClaimToken(
+        PrivetRegisterOperation* operation,
+        const std::string& token,
+        const GURL& url) = 0;
 
     // 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
     // printer. If it is -1, an internal error occurred while trying to complete
     // the request. |json| may be null if printer_http_code signifies an error.
-    virtual void OnPrivetRegisterError(const std::string& action,
+    virtual void OnPrivetRegisterError(PrivetRegisterOperation* operation,
+                                       const std::string& action,
                                        FailureReason reason,
                                        int printer_http_code,
                                        const DictionaryValue* json) = 0;
 
     // Called when the registration is done.
-    virtual void OnPrivetRegisterDone(const std::string& device_id) = 0;
+    virtual void OnPrivetRegisterDone(PrivetRegisterOperation* operation,
+                                      const std::string& device_id) = 0;
   };
 
   virtual ~PrivetRegisterOperation() {}
@@ -74,6 +82,8 @@
   // Owner SHOULD call explicitly before destroying operation.
   virtual void Cancel() = 0;
   virtual void CompleteRegistration() = 0;
+
+  virtual PrivetHTTPClient* GetHTTPClient() = 0;
 };
 
 // Privet HTTP client. Must not outlive the operations it creates.
@@ -87,6 +97,9 @@
       PrivetRegisterOperation::Delegate* delegate) = 0;
   virtual scoped_ptr<PrivetInfoOperation> CreateInfoOperation(
       PrivetInfoOperation::Delegate* delegate) = 0;
+
+  // A name for the HTTP client, e.g. the device name for the privet device.
+  virtual const std::string& GetName() = 0;
 };
 
 }  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory.cc b/chrome/browser/local_discovery/privet_http_asynchronous_factory.cc
new file mode 100644
index 0000000..16c9e93
--- /dev/null
+++ b/chrome/browser/local_discovery/privet_http_asynchronous_factory.cc
@@ -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.
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
+#include "chrome/browser/local_discovery/privet_http_impl.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace local_discovery {
+
+namespace {
+
+std::string IPAddressToHostString(const net::IPAddressNumber& address) {
+  std::string address_str = net::IPAddressToString(address);
+
+  // IPv6 addresses need to be surrounded by brackets.
+  if (address.size() == net::kIPv6AddressSize) {
+    address_str = base::StringPrintf("[%s]", address_str.c_str());
+  }
+
+  return address_str;
+}
+
+}  // namespace
+
+PrivetHTTPAsynchronousFactoryImpl::PrivetHTTPAsynchronousFactoryImpl(
+    ServiceDiscoveryClient* service_discovery_client,
+    net::URLRequestContextGetter* request_context)
+    : service_discovery_client_(service_discovery_client),
+      request_context_(request_context) {
+}
+
+PrivetHTTPAsynchronousFactoryImpl::~PrivetHTTPAsynchronousFactoryImpl() {
+}
+
+scoped_ptr<PrivetHTTPAsynchronousFactory::Resolution>
+PrivetHTTPAsynchronousFactoryImpl::CreatePrivetHTTP(
+    const std::string& name,
+    const net::HostPortPair& address,
+    const ResultCallback& callback) {
+  return scoped_ptr<Resolution>(new ResolutionImpl(name, address, callback,
+                                                   service_discovery_client_,
+                                                   request_context_.get()));
+}
+
+PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::ResolutionImpl(
+    const std::string& name,
+    const net::HostPortPair& address,
+    const ResultCallback& callback,
+    ServiceDiscoveryClient* service_discovery_client,
+    net::URLRequestContextGetter* request_context)
+    : name_(name), hostport_(address), callback_(callback),
+      request_context_(request_context) {
+  net::AddressFamily address_family = net::ADDRESS_FAMILY_UNSPECIFIED;
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kPrivetIPv6Only)) {
+    address_family = net::ADDRESS_FAMILY_IPV6;
+  }
+
+  resolver_ = service_discovery_client->CreateLocalDomainResolver(
+      address.host(), address_family,
+      base::Bind(&ResolutionImpl::ResolveComplete, base::Unretained(this)));
+}
+
+PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::~ResolutionImpl() {
+}
+
+void PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::Start() {
+  resolver_->Start();
+}
+
+void PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::ResolveComplete(
+    bool success, const net::IPAddressNumber& address) {
+  if (!success) {
+    callback_.Run(scoped_ptr<PrivetHTTPClient>());
+    return;
+  }
+
+  net::HostPortPair new_address = net::HostPortPair(
+      IPAddressToHostString(address), hostport_.port());
+  callback_.Run(scoped_ptr<PrivetHTTPClient>(
+      new PrivetHTTPClientImpl(name_, new_address, request_context_.get())));
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory.h b/chrome/browser/local_discovery/privet_http_asynchronous_factory.h
new file mode 100644
index 0000000..ac2552b
--- /dev/null
+++ b/chrome/browser/local_discovery/privet_http_asynchronous_factory.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 CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_
+
+#include <string>
+
+#include "chrome/browser/local_discovery/privet_http.h"
+#include "chrome/browser/local_discovery/privet_http_impl.h"
+#include "chrome/common/local_discovery/service_discovery_client.h"
+
+namespace local_discovery {
+
+class PrivetHTTPAsynchronousFactory {
+ public:
+  typedef base::Callback<void(scoped_ptr<PrivetHTTPClient>)> ResultCallback;
+
+  class Resolution {
+   public:
+    virtual ~Resolution() {}
+    virtual void Start() = 0;
+  };
+
+  virtual ~PrivetHTTPAsynchronousFactory() {}
+
+  virtual scoped_ptr<Resolution> CreatePrivetHTTP(
+      const std::string& name,
+      const net::HostPortPair& address,
+      const ResultCallback& callback) = 0;
+};
+
+class PrivetHTTPAsynchronousFactoryImpl : public PrivetHTTPAsynchronousFactory {
+ public:
+  PrivetHTTPAsynchronousFactoryImpl(
+      ServiceDiscoveryClient* service_discovery_client,
+      net::URLRequestContextGetter* request_context);
+  virtual ~PrivetHTTPAsynchronousFactoryImpl();
+
+  virtual scoped_ptr<Resolution> CreatePrivetHTTP(
+      const std::string& name,
+      const net::HostPortPair& address,
+      const ResultCallback& callback) OVERRIDE;
+
+ private:
+  class ResolutionImpl : public Resolution {
+   public:
+    ResolutionImpl(const std::string& name,
+                   const net::HostPortPair& address,
+                   const ResultCallback& callback,
+                   ServiceDiscoveryClient* service_discovery_client,
+                   net::URLRequestContextGetter* request_context);
+    virtual ~ResolutionImpl();
+
+    virtual void Start() OVERRIDE;
+   private:
+    void ResolveComplete(bool success, const net::IPAddressNumber& address);
+
+    std::string name_;
+    scoped_ptr<LocalDomainResolver> resolver_;
+    net::HostPortPair hostport_;
+    ResultCallback callback_;
+    scoped_refptr<net::URLRequestContextGetter> request_context_;
+  };
+
+  ServiceDiscoveryClient* service_discovery_client_;
+  scoped_refptr<net::URLRequestContextGetter> request_context_;
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_H_
diff --git a/chrome/browser/local_discovery/privet_http_impl.cc b/chrome/browser/local_discovery/privet_http_impl.cc
index 38eacd7..c76b106 100644
--- a/chrome/browser/local_discovery/privet_http_impl.cc
+++ b/chrome/browser/local_discovery/privet_http_impl.cc
@@ -45,12 +45,16 @@
   url_fetcher_->Start();
 }
 
+PrivetHTTPClient* PrivetInfoOperationImpl::GetHTTPClient() {
+  return privet_client_;
+}
+
 void PrivetInfoOperationImpl::OnError(PrivetURLFetcher* fetcher,
                                       PrivetURLFetcher::ErrorType error) {
   if (error == PrivetURLFetcher::RESPONSE_CODE_ERROR) {
-    delegate_->OnPrivetInfoDone(fetcher->response_code(), NULL);
+    delegate_->OnPrivetInfoDone(this, fetcher->response_code(), NULL);
   } else {
-    delegate_->OnPrivetInfoDone(kPrivetHTTPCodeInternalFailure, NULL);
+    delegate_->OnPrivetInfoDone(this, kPrivetHTTPCodeInternalFailure, NULL);
   }
 }
 
@@ -59,7 +63,7 @@
                                            bool has_error) {
   if (!has_error)
     privet_client_->CacheInfo(value);
-  delegate_->OnPrivetInfoDone(fetcher->response_code(), value);
+  delegate_->OnPrivetInfoDone(this, fetcher->response_code(), value);
 }
 
 PrivetRegisterOperationImpl::PrivetRegisterOperationImpl(
@@ -98,6 +102,10 @@
   SendRequest(kPrivetActionComplete);
 }
 
+PrivetHTTPClient* PrivetRegisterOperationImpl::GetHTTPClient() {
+  return privet_client_;
+}
+
 void PrivetRegisterOperationImpl::OnError(PrivetURLFetcher* fetcher,
                                           PrivetURLFetcher::ErrorType error) {
   ongoing_ = false;
@@ -111,7 +119,8 @@
     reason = FAILURE_MALFORMED_RESPONSE;
   }
 
-  delegate_->OnPrivetRegisterError(current_action_,
+  delegate_->OnPrivetRegisterError(this,
+                                   current_action_,
                                    reason,
                                    visible_http_code,
                                    NULL);
@@ -150,7 +159,8 @@
                      base::TimeDelta::FromSeconds(timeout_seconds_randomized));
     } else  {
       ongoing_ = false;
-      delegate_->OnPrivetRegisterError(current_action_,
+      delegate_->OnPrivetRegisterError(this,
+                                       current_action_,
                                        FAILURE_JSON_ERROR,
                                        fetcher->response_code(),
                                        value);
@@ -195,9 +205,10 @@
   bool got_url = value.GetString(kPrivetKeyClaimURL, &claimUrl);
   bool got_token = value.GetString(kPrivetKeyClaimToken, &claimToken);
   if (got_url || got_token) {
-    delegate_->OnPrivetRegisterClaimToken(claimToken, GURL(claimUrl));
+    delegate_->OnPrivetRegisterClaimToken(this, claimToken, GURL(claimUrl));
   } else {
-    delegate_->OnPrivetRegisterError(current_action_,
+    delegate_->OnPrivetRegisterError(this,
+                                     current_action_,
                                      FAILURE_MALFORMED_RESPONSE,
                                      -1,
                                      NULL);
@@ -209,16 +220,18 @@
   std::string id;
   value.GetString(kPrivetKeyDeviceID, &id);
   ongoing_ = false;
-  delegate_->OnPrivetRegisterDone(id);
+  delegate_->OnPrivetRegisterDone(this, id);
 }
 
 void PrivetRegisterOperationImpl::OnPrivetInfoDone(
+    PrivetInfoOperation* operation,
     int http_code,
     const base::DictionaryValue* value) {
   // TODO(noamsml): Distinguish between network errors and unparsable JSON in
   // this case.
   if (!value) {
-    delegate_->OnPrivetRegisterError(kPrivetActionNameInfo,
+    delegate_->OnPrivetRegisterError(this,
+                                     kPrivetActionNameInfo,
                                      FAILURE_NETWORK,
                                      -1,
                                      NULL);
@@ -229,12 +242,14 @@
   // has stored it in the client.
   if (!value->HasKey(kPrivetInfoKeyToken)) {
     if (value->HasKey(kPrivetKeyError)) {
-      delegate_->OnPrivetRegisterError(kPrivetActionNameInfo,
+      delegate_->OnPrivetRegisterError(this,
+                                       kPrivetActionNameInfo,
                                        FAILURE_JSON_ERROR,
                                        http_code,
                                        value);
     } else {
-      delegate_->OnPrivetRegisterError(kPrivetActionNameInfo,
+      delegate_->OnPrivetRegisterError(this,
+                                       kPrivetActionNameInfo,
                                        FAILURE_MALFORMED_RESPONSE,
                                        -1,
                                        NULL);
@@ -262,9 +277,11 @@
 }
 
 PrivetHTTPClientImpl::PrivetHTTPClientImpl(
+    const std::string& name,
     const net::HostPortPair& host_port,
     net::URLRequestContextGetter* request_context)
-    : fetcher_factory_(request_context),
+    : name_(name),
+      fetcher_factory_(request_context),
       host_port_(host_port) {
 }
 
@@ -289,6 +306,10 @@
       new PrivetInfoOperationImpl(this, delegate));
 }
 
+const std::string& PrivetHTTPClientImpl::GetName() {
+  return name_;
+}
+
 void PrivetHTTPClientImpl::CacheInfo(const base::DictionaryValue* cached_info) {
   cached_info_.reset(cached_info->DeepCopy());
   std::string token;
diff --git a/chrome/browser/local_discovery/privet_http_impl.h b/chrome/browser/local_discovery/privet_http_impl.h
index 08c11a1..8de3312 100644
--- a/chrome/browser/local_discovery/privet_http_impl.h
+++ b/chrome/browser/local_discovery/privet_http_impl.h
@@ -24,6 +24,8 @@
 
   virtual void Start() OVERRIDE;
 
+  virtual PrivetHTTPClient* GetHTTPClient() OVERRIDE;
+
   virtual void OnError(PrivetURLFetcher* fetcher,
                        PrivetURLFetcher::ErrorType error) OVERRIDE;
   virtual void OnParsedJson(PrivetURLFetcher* fetcher,
@@ -58,8 +60,11 @@
                             const base::DictionaryValue* value,
                             bool has_error) OVERRIDE;
 
-  virtual void OnPrivetInfoDone(int http_code,
+  virtual void OnPrivetInfoDone(PrivetInfoOperation* operation,
+                                int http_code,
                                 const base::DictionaryValue* value) OVERRIDE;
+
+  virtual PrivetHTTPClient* GetHTTPClient() OVERRIDE;
  private:
   // Arguments is JSON value from request.
   typedef base::Callback<void(const base::DictionaryValue&)>
@@ -89,8 +94,10 @@
 
 class PrivetHTTPClientImpl : public PrivetHTTPClient {
  public:
-  PrivetHTTPClientImpl(const net::HostPortPair& host_port,
-                       net::URLRequestContextGetter* request_context);
+  PrivetHTTPClientImpl(
+      const std::string& name,
+      const net::HostPortPair& host_port,
+      net::URLRequestContextGetter* request_context);
   virtual ~PrivetHTTPClientImpl();
 
   virtual const base::DictionaryValue* GetCachedInfo() const OVERRIDE;
@@ -102,6 +109,8 @@
   virtual scoped_ptr<PrivetInfoOperation> CreateInfoOperation(
       PrivetInfoOperation::Delegate* delegate) OVERRIDE;
 
+  virtual const std::string& GetName() OVERRIDE;
+
   const PrivetURLFetcherFactory& fetcher_factory() const {
     return fetcher_factory_;
   }
@@ -110,6 +119,7 @@
   void CacheInfo(const base::DictionaryValue* cached_info);
 
  private:
+  std::string name_;
   PrivetURLFetcherFactory fetcher_factory_;
   net::HostPortPair host_port_;
   scoped_ptr<base::DictionaryValue> cached_info_;
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/local_discovery/privet_http_unittest.cc
index 05cf2c5..5d007f3 100644
--- a/chrome/browser/local_discovery/privet_http_unittest.cc
+++ b/chrome/browser/local_discovery/privet_http_unittest.cc
@@ -95,6 +95,7 @@
     request_context_= new net::TestURLRequestContextGetter(
         base::MessageLoopProxy::current());
     privet_client_.reset(new PrivetHTTPClientImpl(
+        "sampleDevice._privet._tcp.local",
         net::HostPortPair("10.0.0.8", 6006),
         request_context_.get()));
     fetcher_factory_.SetDelegateForTests(&fetcher_delegate_);
@@ -115,7 +116,8 @@
   MockInfoDelegate() {}
   ~MockInfoDelegate() {}
 
-  virtual void OnPrivetInfoDone(int response_code,
+  virtual void OnPrivetInfoDone(PrivetInfoOperation* operation,
+                                int response_code,
                                 const base::DictionaryValue* value) OVERRIDE {
     if (!value) {
       value_.reset();
@@ -140,10 +142,19 @@
   ~MockRegisterDelegate() {
   }
 
-  MOCK_METHOD2(OnPrivetRegisterClaimToken, void(const std::string& token,
-                                                const GURL& url));
+  virtual void OnPrivetRegisterClaimToken(
+      PrivetRegisterOperation* operation,
+      const std::string& token,
+      const GURL& url) OVERRIDE {
+    OnPrivetRegisterClaimTokenInternal(token, url);
+  }
+
+  MOCK_METHOD2(OnPrivetRegisterClaimTokenInternal, void(
+      const std::string& token,
+      const GURL& url));
 
   virtual void OnPrivetRegisterError(
+      PrivetRegisterOperation* operation,
       const std::string& action,
       PrivetRegisterOperation::FailureReason reason,
       int printer_http_code,
@@ -157,7 +168,14 @@
                     PrivetRegisterOperation::FailureReason reason,
                     int printer_http_code));
 
-  MOCK_METHOD1(OnPrivetRegisterDone, void(const std::string& device_id));
+  virtual void OnPrivetRegisterDone(
+      PrivetRegisterOperation* operation,
+      const std::string& device_id) OVERRIDE {
+    OnPrivetRegisterDoneInternal(device_id);
+  }
+
+  MOCK_METHOD1(OnPrivetRegisterDoneInternal,
+               void(const std::string& device_id));
 };
 
 class PrivetInfoTest : public PrivetHTTPTest {
@@ -266,7 +284,7 @@
 
  protected:
   bool SuccessfulResponseToURL(const GURL& url,
-                                         const std::string& response) {
+                               const std::string& response) {
     net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
     if (!fetcher || url != fetcher->GetOriginalURL())
       return false;
@@ -314,7 +332,7 @@
            "action=start&user=example@google.com"),
       kSampleRegisterStartResponse));
 
-  EXPECT_CALL(register_delegate_, OnPrivetRegisterClaimToken(
+  EXPECT_CALL(register_delegate_, OnPrivetRegisterClaimTokenInternal(
       "MySampleToken",
       GURL("https://domain.com/SoMeUrL")));
 
@@ -325,7 +343,7 @@
 
   register_operation_->CompleteRegistration();
 
-  EXPECT_CALL(register_delegate_, OnPrivetRegisterDone(
+  EXPECT_CALL(register_delegate_, OnPrivetRegisterDoneInternal(
       "MyDeviceID"));
 
   EXPECT_TRUE(SuccessfulResponseToURL(
@@ -368,7 +386,7 @@
       GURL("http://10.0.0.8:6006/privet/info"),
       kSampleInfoResponse));
 
-  EXPECT_CALL(register_delegate_, OnPrivetRegisterClaimToken(
+  EXPECT_CALL(register_delegate_, OnPrivetRegisterClaimTokenInternal(
       "MySampleToken", GURL("https://domain.com/SoMeUrL")));
 
   EXPECT_TRUE(SuccessfulResponseToURL(
@@ -434,7 +452,6 @@
                   PrivetRegisterOperation::FAILURE_NETWORK,
                   -1));
 
-
   EXPECT_TRUE(SuccessfulResponseToURL(
       GURL("http://10.0.0.8:6006/privet/info"),
       kSampleInfoResponseBadJson));
diff --git a/chrome/browser/local_discovery/privet_notifications.cc b/chrome/browser/local_discovery/privet_notifications.cc
new file mode 100644
index 0000000..3b40669
--- /dev/null
+++ b/chrome/browser/local_discovery/privet_notifications.cc
@@ -0,0 +1,217 @@
+// Copyright 2013 The Chromium Authors. 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/local_discovery/privet_notifications.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/local_discovery/privet_device_lister_impl.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_context.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace local_discovery {
+
+namespace {
+const int kTenMinutesInSeconds = 600;
+const char kPrivetInfoKeyUptime[] = "uptime";
+const char kPrivetNotificationIDPrefix[] = "privet_notification:";
+const char kPrivetNotificationOriginUrl[] = "chrome://devices";
+}
+
+PrivetNotificationsListener::PrivetNotificationsListener(
+    scoped_ptr<PrivetHTTPAsynchronousFactory> privet_http_factory,
+    Delegate* delegate) : delegate_(delegate) {
+  privet_http_factory_.swap(privet_http_factory);
+}
+
+PrivetNotificationsListener::~PrivetNotificationsListener() {
+}
+
+void PrivetNotificationsListener::DeviceChanged(
+    bool added,
+    const std::string& name,
+    const DeviceDescription& description) {
+  DeviceContextMap::iterator found = devices_seen_.find(name);
+  if (found != devices_seen_.end()) {
+    if (!description.id.empty() &&  // Device is registered
+        found->second->notification_may_be_active) {
+      found->second->notification_may_be_active = false;
+      delegate_->PrivetRemoveNotification(name);
+    }
+    return;  // Already saw this device.
+  }
+
+  linked_ptr<DeviceContext> device_context(new DeviceContext);
+
+  device_context->notification_may_be_active = false;
+  device_context->registered = !description.id.empty();
+  device_context->human_readable_name = description.name;
+  device_context->description = description.description;
+
+  devices_seen_.insert(make_pair(name, device_context));
+
+  if (!device_context->registered) {
+    device_context->privet_http_resolution =
+        privet_http_factory_->CreatePrivetHTTP(
+            name,
+            description.address,
+            base::Bind(&PrivetNotificationsListener::CreateInfoOperation,
+                       base::Unretained(this)));
+
+    device_context->privet_http_resolution->Start();
+  }
+}
+
+void PrivetNotificationsListener::CreateInfoOperation(
+    scoped_ptr<PrivetHTTPClient> http_client) {
+  std::string name = http_client->GetName();
+  DeviceContextMap::iterator device_iter = devices_seen_.find(name);
+  DCHECK(device_iter != devices_seen_.end());
+  DeviceContext* device = device_iter->second.get();
+  device->privet_http.swap(http_client);
+  device->info_operation =
+       device->privet_http->CreateInfoOperation(this);
+  device->info_operation->Start();
+}
+
+void PrivetNotificationsListener::OnPrivetInfoDone(
+      PrivetInfoOperation* operation,
+      int http_code,
+      const base::DictionaryValue* json_value) {
+  std::string name = operation->GetHTTPClient()->GetName();
+  DeviceContextMap::iterator device_iter = devices_seen_.find(name);
+  DCHECK(device_iter != devices_seen_.end());
+  DeviceContext* device = device_iter->second.get();
+
+  int uptime;
+
+  if (!json_value ||
+      !json_value->GetInteger(kPrivetInfoKeyUptime, &uptime) ||
+      uptime > kTenMinutesInSeconds) {
+    return;
+  }
+
+  DCHECK(!device->notification_may_be_active);
+  device->notification_may_be_active = true;
+  delegate_->PrivetNotify(name, device->human_readable_name,
+                          device->description);
+}
+
+void PrivetNotificationsListener::DeviceRemoved(const std::string& name) {
+  DCHECK_EQ(1u, devices_seen_.count(name));
+  DeviceContextMap::iterator device_iter = devices_seen_.find(name);
+  DCHECK(device_iter != devices_seen_.end());
+  DeviceContext* device = device_iter->second.get();
+
+  device->info_operation.reset();
+  device->privet_http_resolution.reset();
+  device->notification_may_be_active = false;
+  delegate_->PrivetRemoveNotification(name);
+}
+
+PrivetNotificationsListener::DeviceContext::DeviceContext() {
+}
+
+PrivetNotificationsListener::DeviceContext::~DeviceContext() {
+}
+
+PrivetNotificationService::PrivetNotificationService(
+    content::BrowserContext* profile,
+    NotificationUIManager* notification_manager)
+    : profile_(profile),
+      notification_manager_(notification_manager) {
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&PrivetNotificationService::Start, AsWeakPtr()));
+}
+
+PrivetNotificationService::~PrivetNotificationService() {
+  ServiceDiscoveryHostClientFactory::ReleaseClient();
+}
+
+void PrivetNotificationService::DeviceChanged(
+    bool added,
+    const std::string& name,
+    const DeviceDescription& description) {
+  privet_notifications_listener_->DeviceChanged(added, name, description);
+}
+
+void PrivetNotificationService::DeviceRemoved(const std::string& name) {
+  privet_notifications_listener_->DeviceRemoved(name);
+}
+
+void PrivetNotificationService::PrivetNotify(
+    const std::string& device_name,
+    const std::string& human_readable_name,
+    const std::string& description) {
+  Profile* profile_object = Profile::FromBrowserContext(profile_);
+  Notification notification(
+      GURL(kPrivetNotificationOriginUrl),
+      GURL(),
+      l10n_util::GetStringUTF16(IDS_LOCAL_DISOCVERY_NOTIFICATION_TITLE_PRINTER),
+      l10n_util::GetStringFUTF16(
+          IDS_LOCAL_DISOCVERY_NOTIFICATION_CONTENTS_PRINTER,
+          UTF8ToUTF16(human_readable_name)),
+      WebKit::WebTextDirectionDefault,
+      l10n_util::GetStringUTF16(
+          IDS_LOCAL_DISOCVERY_NOTIFICATION_DISPLAY_SOURCE_PRINTER),
+      UTF8ToUTF16(kPrivetNotificationIDPrefix +
+                  device_name),
+      new PrivetNotificationDelegate(device_name));
+
+  notification_manager_->Add(notification, profile_object);
+}
+
+void PrivetNotificationService::PrivetRemoveNotification(
+    const std::string& device_name) {
+  notification_manager_->CancelById(kPrivetNotificationIDPrefix + device_name);
+}
+
+void PrivetNotificationService::Start() {
+  service_discovery_client_ = ServiceDiscoveryHostClientFactory::GetClient();
+  device_lister_.reset(new PrivetDeviceListerImpl(service_discovery_client_,
+                                                  this));
+  device_lister_->Start();
+
+  scoped_ptr<PrivetHTTPAsynchronousFactory> http_factory(
+      new PrivetHTTPAsynchronousFactoryImpl(service_discovery_client_.get(),
+                                            profile_->GetRequestContext()));
+
+  privet_notifications_listener_.reset(new PrivetNotificationsListener(
+      http_factory.Pass(), this));
+}
+
+PrivetNotificationDelegate::PrivetNotificationDelegate(
+    const std::string& device_id) : device_id_(device_id) {
+}
+
+PrivetNotificationDelegate::~PrivetNotificationDelegate() {
+}
+
+std::string PrivetNotificationDelegate::id() const {
+  return kPrivetNotificationIDPrefix + device_id_;
+}
+
+content::RenderViewHost* PrivetNotificationDelegate::GetRenderViewHost() const {
+  return NULL;
+}
+
+void PrivetNotificationDelegate::Display() {
+}
+
+void PrivetNotificationDelegate::Error() {
+  LOG(ERROR) << "Error displaying privet notification " << device_id_;
+}
+
+void PrivetNotificationDelegate::Close(bool by_user) {
+}
+
+void PrivetNotificationDelegate::Click() {
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_notifications.h b/chrome/browser/local_discovery/privet_notifications.h
new file mode 100644
index 0000000..d0c87de
--- /dev/null
+++ b/chrome/browser/local_discovery/privet_notifications.h
@@ -0,0 +1,140 @@
+// Copyright 2013 The Chromium Authors. 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_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_H_
+
+#include <map>
+#include <string>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/local_discovery/privet_device_lister.h"
+#include "chrome/browser/local_discovery/privet_device_lister_impl.h"
+#include "chrome/browser/local_discovery/privet_http.h"
+#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
+#include "chrome/browser/local_discovery/service_discovery_host_client.h"
+#include "chrome/browser/notifications/notification_delegate.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "ui/message_center/notification_delegate.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace local_discovery {
+
+// Contains logic related to notifications not tied actually displaying them.
+class PrivetNotificationsListener : public PrivetInfoOperation::Delegate {
+ public:
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Notify user of the existence of device |device_name|.
+    virtual void PrivetNotify(const std::string& device_name,
+                              const std::string& human_readable_name,
+                              const std::string& description) = 0;
+
+    // Remove the noitification for |device_name| if it still exists.
+    virtual void PrivetRemoveNotification(const std::string& device_name) = 0;
+  };
+
+  PrivetNotificationsListener(
+      scoped_ptr<PrivetHTTPAsynchronousFactory> privet_http_factory,
+      Delegate* delegate);
+  virtual ~PrivetNotificationsListener();
+
+  // These two methods are akin to those of PrivetDeviceLister::Delegate. The
+  // user of PrivetNotificationListener should create a PrivetDeviceLister and
+  // forward device notifications to the PrivetNotificationLister.
+  void DeviceChanged(bool added,
+                     const std::string& name,
+                     const DeviceDescription& description);
+  void DeviceRemoved(const std::string& name);
+
+  // PrivetInfoOperation::Delegate implementation.
+  virtual void OnPrivetInfoDone(
+      PrivetInfoOperation* operation,
+      int http_code,
+      const base::DictionaryValue* json_value) OVERRIDE;
+
+ private:
+  struct DeviceContext {
+    DeviceContext();
+    ~DeviceContext();
+
+    bool notification_may_be_active;
+    bool registered;
+    std::string human_readable_name;
+    std::string description;
+    scoped_ptr<PrivetInfoOperation> info_operation;
+    scoped_ptr<PrivetHTTPAsynchronousFactory::Resolution>
+        privet_http_resolution;
+    scoped_ptr<PrivetHTTPClient> privet_http;
+  };
+
+  typedef std::map<std::string, linked_ptr<DeviceContext> > DeviceContextMap;
+
+  void CreateInfoOperation(scoped_ptr<PrivetHTTPClient> http_client);
+
+  Delegate* delegate_;
+  scoped_ptr<PrivetDeviceLister> device_lister_;
+  scoped_ptr<PrivetHTTPAsynchronousFactory> privet_http_factory_;
+  DeviceContextMap devices_seen_;
+};
+
+class PrivetNotificationService
+    : public BrowserContextKeyedService,
+      public PrivetDeviceLister::Delegate,
+      public PrivetNotificationsListener::Delegate,
+      public base::SupportsWeakPtr<PrivetNotificationService> {
+ public:
+  PrivetNotificationService(content::BrowserContext* profile,
+                            NotificationUIManager* notification_manager);
+  virtual ~PrivetNotificationService();
+
+  // PrivetDeviceLister::Delegate implementation:
+  virtual void DeviceChanged(bool added, const std::string& name,
+                             const DeviceDescription& description) OVERRIDE;
+  virtual void DeviceRemoved(const std::string& name) OVERRIDE;
+
+  // PrivetNotificationListener::Delegate implementation:
+  virtual void PrivetNotify(const std::string& device_name,
+                            const std::string& human_readable_name,
+                            const std::string& description) OVERRIDE;
+
+  virtual void PrivetRemoveNotification(
+      const std::string& device_name) OVERRIDE;
+ private:
+  void Start();
+
+  content::BrowserContext* profile_;
+  NotificationUIManager* notification_manager_;
+  scoped_ptr<PrivetDeviceLister> device_lister_;
+  scoped_refptr<ServiceDiscoveryHostClient> service_discovery_client_;
+  scoped_ptr<PrivetNotificationsListener> privet_notifications_listener_;
+};
+
+class PrivetNotificationDelegate : public NotificationDelegate {
+ public:
+  explicit PrivetNotificationDelegate(const std::string& device_id);
+
+  // NotificationDelegate implementation.
+  virtual std::string id() const OVERRIDE;
+  virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE;
+  virtual void Display() OVERRIDE;
+  virtual void Error() OVERRIDE;
+  virtual void Close(bool by_user) OVERRIDE;
+  virtual void Click() OVERRIDE;
+ private:
+  virtual ~PrivetNotificationDelegate();
+
+  std::string device_id_;
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_H_
diff --git a/chrome/browser/local_discovery/privet_notifications_factory.cc b/chrome/browser/local_discovery/privet_notifications_factory.cc
new file mode 100644
index 0000000..16f7ab6
--- /dev/null
+++ b/chrome/browser/local_discovery/privet_notifications_factory.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 "chrome/browser/local_discovery/privet_notifications_factory.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/local_discovery/privet_notifications.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+
+namespace local_discovery {
+
+PrivetNotificationServiceFactory*
+PrivetNotificationServiceFactory::GetInstance() {
+  return Singleton<PrivetNotificationServiceFactory>::get();
+}
+
+PrivetNotificationServiceFactory::PrivetNotificationServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+        "PrivetNotificationService",
+        BrowserContextDependencyManager::GetInstance()) {
+}
+
+PrivetNotificationServiceFactory::~PrivetNotificationServiceFactory() {
+}
+
+BrowserContextKeyedService*
+PrivetNotificationServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* profile) const {
+  return new PrivetNotificationService(
+      profile, g_browser_process->notification_ui_manager());
+}
+
+bool
+PrivetNotificationServiceFactory::ServiceIsCreatedWithBrowserContext() const {
+  return CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableDeviceDiscovery);
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_notifications_factory.h b/chrome/browser/local_discovery/privet_notifications_factory.h
new file mode 100644
index 0000000..cdff6d2
--- /dev/null
+++ b/chrome/browser/local_discovery/privet_notifications_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_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_FACTORY_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+
+namespace local_discovery {
+
+class PrivetNotificationServiceFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns singleton instance of PrivetNotificationServiceFactory.
+  static PrivetNotificationServiceFactory* GetInstance();
+
+ private:
+  friend struct DefaultSingletonTraits<PrivetNotificationServiceFactory>;
+
+  PrivetNotificationServiceFactory();
+  virtual ~PrivetNotificationServiceFactory();
+
+  // BrowserContextKeyedServiceFactory:
+  virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* profile) const OVERRIDE;
+  virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE;
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_NOTIFICATIONS_FACTORY_H_
diff --git a/chrome/browser/local_discovery/privet_notifications_unittest.cc b/chrome/browser/local_discovery/privet_notifications_unittest.cc
new file mode 100644
index 0000000..e0d6a52
--- /dev/null
+++ b/chrome/browser/local_discovery/privet_notifications_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright 2013 The Chromium Authors. 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/local_discovery/privet_notifications.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::StrictMock;
+
+using ::testing::_;
+using ::testing::SaveArg;
+
+namespace local_discovery {
+
+namespace {
+
+const char kExampleDeviceName[] = "test._privet._tcp.local";
+const char kExampleDeviceHumanName[] = "Test device";
+const char kExampleDeviceDescription[] = "Testing testing";
+const char kExampleDeviceID[] = "__test__id";
+
+class MockPrivetNotificationsListenerDeleagate
+    : public PrivetNotificationsListener::Delegate {
+ public:
+  MOCK_METHOD3(PrivetNotify, void(const std::string& device_name,
+                                  const std::string& human_readable_name,
+                                  const std::string& description));
+  MOCK_METHOD1(PrivetRemoveNotification, void(const std::string& device_name));
+};
+
+class MockPrivetInfoOperation : public PrivetInfoOperation {
+ public:
+  class DelegateForTests {
+   public:
+    virtual ~DelegateForTests() {}
+    virtual void InfoOperationStarted(MockPrivetInfoOperation* operation) = 0;
+  };
+
+  MockPrivetInfoOperation(PrivetHTTPClient* client,
+                          DelegateForTests* delegate_for_tests,
+                          Delegate* delegate)
+      : client_(client),
+        delegate_for_tests_(delegate_for_tests),
+        delegate_(delegate) {
+  }
+
+  virtual ~MockPrivetInfoOperation() {
+  }
+
+  virtual void Start() OVERRIDE {
+    delegate_for_tests_->InfoOperationStarted(this);
+  }
+
+  virtual PrivetHTTPClient* GetHTTPClient() OVERRIDE {
+    return client_;
+  }
+
+  Delegate* delegate() { return delegate_; }
+
+ private:
+  PrivetHTTPClient* client_;
+  DelegateForTests* delegate_for_tests_;
+  Delegate* delegate_;
+};
+
+class MockPrivetHTTPClient : public PrivetHTTPClient {
+ public:
+  MockPrivetHTTPClient(
+      MockPrivetInfoOperation::DelegateForTests* delegate_for_tests,
+      const std::string& name) : delegate_for_tests_(delegate_for_tests),
+                                 name_(name) {
+  }
+
+  virtual scoped_ptr<PrivetRegisterOperation> CreateRegisterOperation(
+      const std::string& user,
+      PrivetRegisterOperation::Delegate* delegate) OVERRIDE {
+    return scoped_ptr<PrivetRegisterOperation>();
+  }
+
+  virtual scoped_ptr<PrivetInfoOperation> CreateInfoOperation(
+      PrivetInfoOperation::Delegate* delegate) OVERRIDE {
+    return scoped_ptr<PrivetInfoOperation>(new MockPrivetInfoOperation(
+        this, delegate_for_tests_, delegate));
+  }
+
+  virtual const std::string& GetName() OVERRIDE { return name_; }
+
+  virtual const base::DictionaryValue* GetCachedInfo() const OVERRIDE {
+    NOTIMPLEMENTED();
+    return NULL;
+  }
+
+ private:
+  MockPrivetInfoOperation::DelegateForTests* delegate_for_tests_;
+  std::string name_;
+};
+
+class MockPrivetHttpFactory : public PrivetHTTPAsynchronousFactory {
+ public:
+  class MockResolution : public Resolution {
+   public:
+    MockResolution(
+        const std::string& name,
+        MockPrivetInfoOperation::DelegateForTests* delegate_for_tests,
+        const ResultCallback& callback)
+        : name_(name), delegate_for_tests_(delegate_for_tests),
+          callback_(callback) {
+    }
+
+    virtual ~MockResolution() {
+    }
+
+    virtual void Start() OVERRIDE {
+      callback_.Run(scoped_ptr<PrivetHTTPClient>(
+          new MockPrivetHTTPClient(delegate_for_tests_, name_)));
+    }
+
+   private:
+    std::string name_;
+    MockPrivetInfoOperation::DelegateForTests* delegate_for_tests_;
+    ResultCallback callback_;
+  };
+
+  MockPrivetHttpFactory(
+      MockPrivetInfoOperation::DelegateForTests* delegate_for_tests)
+      : delegate_for_tests_(delegate_for_tests) {
+  }
+
+  virtual scoped_ptr<Resolution> CreatePrivetHTTP(
+      const std::string& name,
+      const net::HostPortPair& address,
+      const ResultCallback& callback) OVERRIDE {
+    return scoped_ptr<Resolution>(
+        new MockResolution(name, delegate_for_tests_, callback));
+  }
+
+ private:
+  MockPrivetInfoOperation::DelegateForTests* delegate_for_tests_;
+};
+
+class MockDelegateForTests : public MockPrivetInfoOperation::DelegateForTests {
+ public:
+  MOCK_METHOD1(InfoOperationStarted, void(MockPrivetInfoOperation* operation));
+};
+
+class PrivetNotificationsListenerTest : public ::testing::Test {
+ public:
+  PrivetNotificationsListenerTest() {
+    notification_listener_.reset(new PrivetNotificationsListener(
+        scoped_ptr<PrivetHTTPAsynchronousFactory>(
+            new MockPrivetHttpFactory(&mock_delegate_for_tests_)),
+        &mock_delegate_));
+
+    description_.name = kExampleDeviceHumanName;
+    description_.description = kExampleDeviceDescription;
+  }
+
+  virtual ~PrivetNotificationsListenerTest() {
+  }
+
+  virtual void ExpectInfoOperation() {
+    EXPECT_CALL(mock_delegate_for_tests_, InfoOperationStarted(_))
+        .WillOnce(SaveArg<0>(&info_operation_));
+  }
+
+ protected:
+  StrictMock<MockPrivetNotificationsListenerDeleagate> mock_delegate_;
+  StrictMock<MockDelegateForTests> mock_delegate_for_tests_;
+  scoped_ptr<PrivetNotificationsListener> notification_listener_;
+  MockPrivetInfoOperation* info_operation_;
+  DeviceDescription description_;
+};
+
+TEST_F(PrivetNotificationsListenerTest, DisappearReappearTest) {
+  ExpectInfoOperation();
+
+  EXPECT_CALL(mock_delegate_, PrivetNotify(
+      kExampleDeviceName,
+      kExampleDeviceHumanName,
+      kExampleDeviceDescription));
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+
+  base::DictionaryValue value;
+
+  value.SetInteger("uptime", 20);
+
+  info_operation_->delegate()->OnPrivetInfoDone(info_operation_,
+                                                200, &value);
+
+  EXPECT_CALL(mock_delegate_, PrivetRemoveNotification(
+      kExampleDeviceName));
+
+  notification_listener_->DeviceRemoved(
+      kExampleDeviceName);
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+
+  description_.id = kExampleDeviceID;
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+}
+
+TEST_F(PrivetNotificationsListenerTest, RegisterTest) {
+  ExpectInfoOperation();
+
+  EXPECT_CALL(mock_delegate_, PrivetNotify(
+      kExampleDeviceName,
+      kExampleDeviceHumanName,
+      kExampleDeviceDescription));
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+
+  base::DictionaryValue value;
+
+  value.SetInteger("uptime", 20);
+
+  info_operation_->delegate()->OnPrivetInfoDone(info_operation_,
+                                                200, &value);
+
+  EXPECT_CALL(mock_delegate_, PrivetRemoveNotification(
+      kExampleDeviceName));
+
+  description_.id = kExampleDeviceID;
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+}
+
+TEST_F(PrivetNotificationsListenerTest, HighUptimeTest) {
+  ExpectInfoOperation();
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+
+  base::DictionaryValue value;
+
+  value.SetInteger("uptime", 3600);
+
+  info_operation_->delegate()->OnPrivetInfoDone(info_operation_,
+                                                200, &value);
+
+  description_.id = kExampleDeviceID;
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+}
+
+TEST_F(PrivetNotificationsListenerTest, HTTPErrorTest) {
+  ExpectInfoOperation();
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+
+  info_operation_->delegate()->OnPrivetInfoDone(info_operation_,
+                                                404, NULL);
+}
+
+TEST_F(PrivetNotificationsListenerTest, DictionaryErrorTest) {
+  ExpectInfoOperation();
+
+  notification_listener_->DeviceChanged(
+      true,
+      kExampleDeviceName,
+      description_);
+
+  base::DictionaryValue value;
+  value.SetString("error", "internal_error");
+
+  info_operation_->delegate()->OnPrivetInfoDone(info_operation_,
+                                                200, &value);
+}
+
+}  // namespace
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_host_client.cc b/chrome/browser/local_discovery/service_discovery_host_client.cc
index 74aeb81..71ab0ce 100644
--- a/chrome/browser/local_discovery/service_discovery_host_client.cc
+++ b/chrome/browser/local_discovery/service_discovery_host_client.cc
@@ -127,9 +127,12 @@
 }
 
 ServiceDiscoveryHostClient::~ServiceDiscoveryHostClient() {
-  DCHECK(CalledOnValidThread());
+  // The ServiceDiscoveryHostClient may be destroyed from the IO thread or the
+  // owning thread.
+  DetachFromThread();
   DCHECK(service_watcher_callbacks_.empty());
   DCHECK(service_resolver_callbacks_.empty());
+  DCHECK(domain_resolver_callbacks_.empty());
 }
 
 scoped_ptr<ServiceWatcher> ServiceDiscoveryHostClient::CreateServiceWatcher(
@@ -230,8 +233,10 @@
 
 void ServiceDiscoveryHostClient::ShutdownOnIOThread() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  if (utility_host_)
+  if (utility_host_) {
+    utility_host_->Send(new LocalDiscoveryMsg_ShutdownLocalDiscovery);
     utility_host_->EndBatchMode();
+  }
 }
 
 void ServiceDiscoveryHostClient::Send(IPC::Message* msg) {
@@ -326,4 +331,48 @@
     it->second.Run(success, ip_address);
 }
 
+ServiceDiscoveryHostClientFactory::ServiceDiscoveryHostClientFactory()
+    : instance_(NULL), references_(0) {
+}
+
+ServiceDiscoveryHostClientFactory::~ServiceDiscoveryHostClientFactory() {
+}
+
+// static
+ServiceDiscoveryHostClient* ServiceDiscoveryHostClientFactory::GetClient() {
+  return GetInstance()->GetClientInternal();
+}
+
+// static
+void ServiceDiscoveryHostClientFactory::ReleaseClient() {
+  GetInstance()->ReleaseClientInternal();
+}
+
+// static
+ServiceDiscoveryHostClientFactory*
+ServiceDiscoveryHostClientFactory::GetInstance() {
+  return Singleton<ServiceDiscoveryHostClientFactory>::get();
+}
+
+ServiceDiscoveryHostClient*
+ServiceDiscoveryHostClientFactory::GetClientInternal() {
+  DCHECK(CalledOnValidThread());
+  if (references_ == 0) {
+    instance_ = new ServiceDiscoveryHostClient;
+    instance_->Start();
+  }
+
+  references_++;
+  return instance_.get();
+}
+
+void ServiceDiscoveryHostClientFactory::ReleaseClientInternal() {
+  DCHECK(CalledOnValidThread());
+  references_--;
+  if (references_ == 0) {
+    instance_->Shutdown();
+    instance_ = NULL;
+  }
+}
+
 }  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/service_discovery_host_client.h b/chrome/browser/local_discovery/service_discovery_host_client.h
index 302b660..1a3278d 100644
--- a/chrome/browser/local_discovery/service_discovery_host_client.h
+++ b/chrome/browser/local_discovery/service_discovery_host_client.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <string>
 
+#include "base/memory/singleton.h"
 #include "base/threading/non_thread_safe.h"
 #include "chrome/common/local_discovery/service_discovery_client.h"
 #include "content/public/browser/utility_process_host_client.h"
@@ -120,6 +121,26 @@
   DISALLOW_COPY_AND_ASSIGN(ServiceDiscoveryHostClient);
 };
 
+class ServiceDiscoveryHostClientFactory : public base::NonThreadSafe {
+ public:
+  ServiceDiscoveryHostClientFactory();
+  ~ServiceDiscoveryHostClientFactory();
+
+  static ServiceDiscoveryHostClient* GetClient();
+  static void ReleaseClient();
+
+ private:
+  friend class Singleton<ServiceDiscoveryHostClientFactory>;
+
+  static ServiceDiscoveryHostClientFactory* GetInstance();
+
+  ServiceDiscoveryHostClient* GetClientInternal();
+  void ReleaseClientInternal();
+
+  scoped_refptr<ServiceDiscoveryHostClient> instance_;
+  int references_;
+};
+
 }  // namespace local_discovery
 
 #endif  // CHROME_BROWSER_LOCAL_DISCOVERY_SERVICE_DISCOVERY_HOST_CLIENT_H_
diff --git a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc
index 75608a6..fb79edc 100644
--- a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
+#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
 #include "chrome/browser/signin/oauth2_token_service.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -28,6 +29,7 @@
 const char kAccessToken[] = "accesstoken";
 const char kAuthorizationCode[] = "authorizationcode";
 const char kManagedUserToken[] = "managedusertoken";
+const char kOAuth2RefreshToken[] = "refreshtoken";
 
 const char kIssueTokenResponseFormat[] =
     "{"
@@ -41,100 +43,6 @@
     "  \"refresh_token\": \"%s\""
     "}";
 
-// MockOAuth2TokenService ---------------------------------------------
-
-class MockOAuth2TokenService : public OAuth2TokenService {
- public:
-  class Request : public OAuth2TokenService::Request {
-   public:
-    Request(const OAuth2TokenService::ScopeSet& scopes,
-            OAuth2TokenService::Consumer* consumer,
-            MockOAuth2TokenService* owner);
-    virtual ~Request();
-
-    void Succeed();
-    void Fail(GoogleServiceAuthError::State error);
-
-    const OAuth2TokenService::ScopeSet& scopes() const { return scopes_; }
-
-   private:
-    OAuth2TokenService::ScopeSet scopes_;
-
-    OAuth2TokenService::Consumer* consumer_;
-
-    MockOAuth2TokenService* owner_;
-  };
-
-  MockOAuth2TokenService();
-  virtual ~MockOAuth2TokenService();
-
-  Request* request() const { return request_; }
-
-  void ClearRequest(Request* request);
-
- private:
-  // OAuth2TokenService overrides:
-  virtual scoped_ptr<OAuth2TokenService::Request> StartRequest(
-     const OAuth2TokenService::ScopeSet& scopes,
-      OAuth2TokenService::Consumer* consumer) OVERRIDE;
-  virtual std::string GetRefreshToken() OVERRIDE;
-  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE {
-    return NULL;
-  }
-
-  Request* request_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockOAuth2TokenService);
-};
-
-MockOAuth2TokenService::Request::Request(
-    const OAuth2TokenService::ScopeSet& scopes,
-    OAuth2TokenService::Consumer* consumer,
-    MockOAuth2TokenService* owner)
-    : scopes_(scopes),
-      consumer_(consumer),
-      owner_(owner) {}
-
-MockOAuth2TokenService::Request::~Request() {
-  owner_->ClearRequest(this);
-}
-
-void MockOAuth2TokenService::Request::Succeed() {
-  base::Time expiration_date = base::Time::Now() +
-                               base::TimeDelta::FromHours(1);
-  consumer_->OnGetTokenSuccess(this, kAccessToken, expiration_date);
-}
-
-void MockOAuth2TokenService::Request::Fail(
-    GoogleServiceAuthError::State error) {
-  consumer_->OnGetTokenFailure(this, GoogleServiceAuthError(error));
-}
-
-MockOAuth2TokenService::MockOAuth2TokenService() : request_(NULL) {}
-
-MockOAuth2TokenService::~MockOAuth2TokenService() {
-  EXPECT_FALSE(request_);
-}
-
-void MockOAuth2TokenService::ClearRequest(
-    MockOAuth2TokenService::Request* request) {
-  if (request_ == request)
-    request_ = NULL;
-}
-
-scoped_ptr<OAuth2TokenService::Request> MockOAuth2TokenService::StartRequest(
-    const OAuth2TokenService::ScopeSet& scopes,
-    OAuth2TokenService::Consumer* consumer) {
-  scoped_ptr<Request> request(new Request(scopes, consumer, this));
-  request_ = request.get();
-  return request.PassAs<OAuth2TokenService::Request>();
-}
-
-std::string MockOAuth2TokenService::GetRefreshToken() {
-  NOTREACHED();
-  return std::string();
-}
-
 // Utility methods --------------------------------------------------
 
 // Slightly hacky way to extract a value from a URL-encoded POST request body.
@@ -166,6 +74,14 @@
   url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
 }
 
+void VerifyTokenRequest(
+    std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests) {
+  ASSERT_EQ(1u, requests.size());
+  EXPECT_EQ(1u, requests[0].scopes.size());
+  EXPECT_EQ(1u, requests[0].scopes.count(
+      GaiaUrls::GetInstance()->oauth1_login_scope()));
+}
+
 }  // namespace
 
 class ManagedUserRefreshTokenFetcherTest : public testing::Test {
@@ -176,10 +92,11 @@
  protected:
   void StartFetching();
 
-  MockOAuth2TokenService::Request* GetOAuth2TokenServiceRequest();
   net::TestURLFetcher* GetIssueTokenRequest();
   net::TestURLFetcher* GetRefreshTokenRequest();
 
+  void MakeOAuth2TokenServiceRequestSucceed();
+  void MakeOAuth2TokenServiceRequestFail(GoogleServiceAuthError::State error);
   void MakeIssueTokenRequestSucceed();
   void MakeRefreshTokenFetchSucceed();
 
@@ -194,7 +111,7 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
   TestingProfile profile_;
-  MockOAuth2TokenService oauth2_token_service_;
+  FakeProfileOAuth2TokenService oauth2_token_service_;
   net::TestURLFetcherFactory url_fetcher_factory_;
   scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher_;
 
@@ -211,22 +128,13 @@
       weak_ptr_factory_(this) {}
 
 void ManagedUserRefreshTokenFetcherTest::StartFetching() {
+  oauth2_token_service_.IssueRefreshToken(kOAuth2RefreshToken);
   token_fetcher_->Start(kManagedUserId, kDeviceName,
                         base::Bind(
                             &ManagedUserRefreshTokenFetcherTest::OnTokenFetched,
                             weak_ptr_factory_.GetWeakPtr()));
 }
 
-MockOAuth2TokenService::Request*
-ManagedUserRefreshTokenFetcherTest::GetOAuth2TokenServiceRequest() {
-  MockOAuth2TokenService::Request* request = oauth2_token_service_.request();
-
-  OAuth2TokenService::ScopeSet scopes = request->scopes();
-  EXPECT_EQ(1u, scopes.size());
-  EXPECT_EQ(1u, scopes.count(GaiaUrls::GetInstance()->oauth1_login_scope()));
-  return request;
-}
-
 net::TestURLFetcher*
 ManagedUserRefreshTokenFetcherTest::GetIssueTokenRequest() {
   net::TestURLFetcher* url_fetcher = url_fetcher_factory_.GetFetcherByID(1);
@@ -265,6 +173,28 @@
   return url_fetcher;
 }
 
+void
+ManagedUserRefreshTokenFetcherTest::MakeOAuth2TokenServiceRequestSucceed() {
+  std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
+      oauth2_token_service_.GetPendingRequests();
+  VerifyTokenRequest(requests);
+  base::Time expiration_date = base::Time::Now() +
+                               base::TimeDelta::FromHours(1);
+  oauth2_token_service_.IssueTokenForScope(requests[0].scopes,
+                                           kAccessToken,
+                                           expiration_date);
+}
+
+void
+ManagedUserRefreshTokenFetcherTest::MakeOAuth2TokenServiceRequestFail(
+    GoogleServiceAuthError::State error) {
+  std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
+      oauth2_token_service_.GetPendingRequests();
+  VerifyTokenRequest(requests);
+  oauth2_token_service_.IssueErrorForScope(requests[0].scopes,
+                                           GoogleServiceAuthError(error));
+}
+
 void ManagedUserRefreshTokenFetcherTest::MakeIssueTokenRequestSucceed() {
   SendResponse(GetIssueTokenRequest(),
                base::StringPrintf(kIssueTokenResponseFormat,
@@ -292,7 +222,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, Success) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   MakeIssueTokenRequestSucceed();
   MakeRefreshTokenFetchSucceed();
 
@@ -302,9 +232,9 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, ExpiredAccessToken) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   MakeIssueTokenRequestSucceed();
   MakeRefreshTokenFetchSucceed();
 
@@ -316,9 +246,9 @@
   // If we get a 401 error for the second time, we should give up instead of
   // retrying again.
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   SetHttpError(GetIssueTokenRequest(), net::HTTP_UNAUTHORIZED);
 
   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
@@ -328,7 +258,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, MalformedIssueTokenResponse) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   SendResponse(GetIssueTokenRequest(), "choke");
 
   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
@@ -338,7 +268,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, FetchAccessTokenFailure) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Fail(
+  MakeOAuth2TokenServiceRequestFail(
       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
 
   EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, error().state());
@@ -347,7 +277,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, IssueTokenNetworkError) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   SetNetworkError(GetIssueTokenRequest(), net::ERR_SSL_PROTOCOL_ERROR);
 
   EXPECT_EQ(GoogleServiceAuthError::CONNECTION_FAILED, error().state());
@@ -357,7 +287,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenNetworkError) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   MakeIssueTokenRequestSucceed();
   SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
@@ -371,7 +301,7 @@
 TEST_F(ManagedUserRefreshTokenFetcherTest,
        FetchRefreshTokenTransientNetworkError) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   MakeIssueTokenRequestSucceed();
   SetNetworkError(GetRefreshTokenRequest(), net::ERR_CONNECTION_REFUSED);
 
@@ -384,7 +314,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, FetchRefreshTokenBadRequest) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   MakeIssueTokenRequestSucceed();
   SetHttpError(GetRefreshTokenRequest(), net::HTTP_BAD_REQUEST);
 
@@ -403,7 +333,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileCallingIssueToken) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   Reset();
 
   EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
@@ -412,7 +342,7 @@
 
 TEST_F(ManagedUserRefreshTokenFetcherTest, CancelWhileFetchingRefreshToken) {
   StartFetching();
-  GetOAuth2TokenServiceRequest()->Succeed();
+  MakeOAuth2TokenServiceRequestSucceed();
   MakeIssueTokenRequestSucceed();
   Reset();
 
diff --git a/chrome/browser/managed_mode/managed_user_registration_utility.cc b/chrome/browser/managed_mode/managed_user_registration_utility.cc
index 6a46a33..e1f8691 100644
--- a/chrome/browser/managed_mode/managed_user_registration_utility.cc
+++ b/chrome/browser/managed_mode/managed_user_registration_utility.cc
@@ -6,6 +6,7 @@
 
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/rand_util.h"
@@ -19,6 +20,7 @@
 #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"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
@@ -113,7 +115,7 @@
 
 void ManagedUserRegistrationUtility::OnManagedUsersSyncingStopped() {
   AbortPendingRegistration(
-      true,   // Run the callback.
+      true,  // Run the callback.
       GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
 }
 
@@ -139,10 +141,12 @@
 }
 
 void ManagedUserRegistrationUtility::CompleteRegistrationIfReady() {
-  if (!pending_managed_user_acknowledged_ ||
-      pending_managed_user_token_.empty()) {
+  bool require_acknowledgment =
+      !pending_managed_user_acknowledged_ &&
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kNoManagedUserAcknowledgmentCheck);
+  if (require_acknowledgment || pending_managed_user_token_.empty())
     return;
-  }
 
   GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
   CompleteRegistration(true, error);
diff --git a/chrome/browser/managed_mode/managed_user_service.cc b/chrome/browser/managed_mode/managed_user_service.cc
index f42f768..0c0da8c 100644
--- a/chrome/browser/managed_mode/managed_user_service.cc
+++ b/chrome/browser/managed_mode/managed_user_service.cc
@@ -213,6 +213,24 @@
              switches::kEnableManagedUsers);
 }
 
+// static
+void ManagedUserService::MigrateUserPrefs(PrefService* prefs) {
+  if (!prefs->HasPrefPath(prefs::kProfileIsManaged))
+    return;
+
+  bool is_managed = prefs->GetBoolean(prefs::kProfileIsManaged);
+  prefs->ClearPref(prefs::kProfileIsManaged);
+
+  if (!is_managed)
+    return;
+
+  std::string managed_user_id = prefs->GetString(prefs::kManagedUserId);
+  if (!managed_user_id.empty())
+    return;
+
+  prefs->SetString(prefs::kManagedUserId, "Dummy ID");
+}
+
 scoped_refptr<const ManagedModeURLFilter>
 ManagedUserService::GetURLFilterForIOThread() {
   return url_filter_context_.io_url_filter();
@@ -298,17 +316,18 @@
   if (ExtensionManagementPolicyImpl(extension, &tmp_error))
     return true;
 
-  // If the extension is already loaded, we allow it, otherwise we'd unload
-  // all existing extensions.
-  ExtensionService* extension_service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-
-  // |extension_service| can be NULL in a unit test.
-  if (extension_service &&
-      extension_service->GetInstalledExtension(extension->id()))
-    return true;
-
+  // |extension| can be NULL in a unit test.
   if (extension) {
+    // If the extension is already loaded, we allow it, otherwise we'd unload
+    // all existing extensions.
+    ExtensionService* extension_service =
+        extensions::ExtensionSystem::Get(profile_)->extension_service();
+
+    // |extension_service| can be NULL in a unit test.
+    if (extension_service &&
+        extension_service->GetInstalledExtension(extension->id()))
+      return true;
+
     bool was_installed_by_default = extension->was_installed_by_default();
 #if defined(OS_CHROMEOS)
     // On Chrome OS all external sources are controlled by us so it means that
@@ -517,8 +536,8 @@
 }
 
 void ManagedUserService::InitForTesting() {
-  DCHECK(!profile_->GetPrefs()->GetBoolean(prefs::kProfileIsManaged));
-  profile_->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
+  DCHECK(!profile_->IsManaged());
+  profile_->GetPrefs()->SetString(prefs::kManagedUserId, "Test ID");
   Init();
 }
 
@@ -615,7 +634,7 @@
     ManagedUserRegistrationUtility* registration_utility,
     Profile* custodian_profile,
     const std::string& managed_user_id,
-    const ProfileManager::CreateCallback& callback) {
+    const AuthErrorCallback& callback) {
   DCHECK(ProfileIsManaged());
   DCHECK(!custodian_profile->IsManaged());
 
@@ -646,23 +665,21 @@
 }
 
 void ManagedUserService::OnManagedUserRegistered(
-    const ProfileManager::CreateCallback& callback,
+    const AuthErrorCallback& callback,
     Profile* custodian_profile,
     const GoogleServiceAuthError& auth_error,
     const std::string& token) {
-  if (auth_error.state() != GoogleServiceAuthError::NONE) {
-    LOG(ERROR) << "Managed user OAuth error: " << auth_error.ToString();
+  if (auth_error.state() == GoogleServiceAuthError::NONE) {
+    InitSync(token);
+    SigninManagerBase* signin =
+        SigninManagerFactory::GetForProfile(custodian_profile);
+    profile_->GetPrefs()->SetString(prefs::kManagedUserCustodianEmail,
+                                    signin->GetAuthenticatedUsername());
+  } else {
     DCHECK_EQ(std::string(), token);
-    callback.Run(profile_, Profile::CREATE_STATUS_REMOTE_FAIL);
-    return;
   }
 
-  InitSync(token);
-  SigninManagerBase* signin =
-      SigninManagerFactory::GetForProfile(custodian_profile);
-  profile_->GetPrefs()->SetString(prefs::kManagedUserCustodianEmail,
-                                  signin->GetAuthenticatedUsername());
-  callback.Run(profile_, Profile::CREATE_STATUS_INITIALIZED);
+  callback.Run(auth_error);
 }
 
 void ManagedUserService::UpdateManualHosts() {
diff --git a/chrome/browser/managed_mode/managed_user_service.h b/chrome/browser/managed_mode/managed_user_service.h
index 6dc4b56..de1b604 100644
--- a/chrome/browser/managed_mode/managed_user_service.h
+++ b/chrome/browser/managed_mode/managed_user_service.h
@@ -15,8 +15,8 @@
 #include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/managed_mode/managed_mode_url_filter.h"
 #include "chrome/browser/managed_mode/managed_users.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/profile_sync_service_observer.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"
@@ -48,6 +48,7 @@
  public:
   typedef std::vector<string16> CategoryList;
   typedef base::Callback<void(content::WebContents*)> NavigationBlockedCallback;
+  typedef base::Callback<void(const GoogleServiceAuthError&)> AuthErrorCallback;
 
   enum ManualBehavior {
     MANUAL_NONE = 0,
@@ -67,6 +68,8 @@
   // TODO(pamg, sergiu): Remove this once the feature is fully launched.
   static bool AreManagedUsersEnabled();
 
+  static void MigrateUserPrefs(PrefService* prefs);
+
   // Returns the URL filter for the IO thread, for filtering network requests
   // (in ManagedModeResourceThrottle).
   scoped_refptr<const ManagedModeURLFilter> GetURLFilterForIOThread();
@@ -131,7 +134,7 @@
   void RegisterAndInitSync(ManagedUserRegistrationUtility* registration_utility,
                            Profile* custodian_profile,
                            const std::string& managed_user_id,
-                           const ProfileManager::CreateCallback& callback);
+                           const AuthErrorCallback& callback);
 
   // Returns a pseudo-email address for systems that expect well-formed email
   // addresses (like Sync), even though we're not signed in.
@@ -208,7 +211,7 @@
 
   void OnCustodianProfileDownloaded(const string16& full_name);
 
-  void OnManagedUserRegistered(const ProfileManager::CreateCallback& callback,
+  void OnManagedUserRegistered(const AuthErrorCallback& callback,
                                Profile* custodian_profile,
                                const GoogleServiceAuthError& auth_error,
                                const std::string& token);
diff --git a/chrome/browser/managed_mode/managed_user_sync_service.cc b/chrome/browser/managed_mode/managed_user_sync_service.cc
index ca5002c..3728e85 100644
--- a/chrome/browser/managed_mode/managed_user_sync_service.cc
+++ b/chrome/browser/managed_mode/managed_user_sync_service.cc
@@ -150,7 +150,6 @@
         it->GetSpecifics().managed_user();
     DictionaryValue* value = new DictionaryValue();
     value->SetString(kName, managed_user.name());
-    DCHECK(managed_user.acknowledged());
     value->SetBoolean(kAcknowledged, managed_user.acknowledged());
     value->SetString(kMasterKey, managed_user.master_key());
     if (dict->HasKey(managed_user.id()))
diff --git a/chrome/browser/managed_mode/managed_user_theme.cc b/chrome/browser/managed_mode/managed_user_theme.cc
index 5d80e25..d6bd760 100644
--- a/chrome/browser/managed_mode/managed_user_theme.cc
+++ b/chrome/browser/managed_mode/managed_user_theme.cc
@@ -10,11 +10,30 @@
 #include "ui/gfx/image/image.h"
 
 namespace {
+
 const SkColor kDefaultColorFrameManagedUser = SkColorSetRGB(165, 197, 225);
 const SkColor kDefaultColorFrameManagedUserInactive =
     SkColorSetRGB(180, 225, 247);
 const SkColor kDefaultColorManagedUserLabelBackground =
     SkColorSetRGB(108, 167, 210);
+
+// Map resource ids to the managed user resource ids.
+int MapToManagedUserResourceIds(int id) {
+  switch (id) {
+    case IDR_THEME_FRAME:
+    case IDR_THEME_FRAME_WIN:
+      return IDR_MANAGED_USER_THEME_FRAME;
+    case IDR_THEME_FRAME_INACTIVE:
+    case IDR_THEME_FRAME_INACTIVE_WIN:
+      return IDR_MANAGED_USER_THEME_FRAME_INACTIVE;
+    case IDR_THEME_TAB_BACKGROUND:
+    case IDR_THEME_TAB_BACKGROUND_V:
+    case IDR_THEME_TAB_BACKGROUND_WIN:
+      return IDR_MANAGED_USER_THEME_TAB_BACKGROUND;
+  }
+  return id;
+}
+
 }  // namespace
 
 ManagedUserTheme::ManagedUserTheme()
@@ -44,18 +63,10 @@
   if (!HasCustomImage(id))
     return gfx::Image();
 
-  if (id == IDR_THEME_FRAME)
-    id = IDR_MANAGED_USER_THEME_FRAME;
-  else if (id == IDR_THEME_FRAME_INACTIVE)
-    id = IDR_MANAGED_USER_THEME_FRAME_INACTIVE;
-  else if (id == IDR_THEME_TAB_BACKGROUND || id == IDR_THEME_TAB_BACKGROUND_V)
-    id = IDR_MANAGED_USER_THEME_TAB_BACKGROUND;
+  id = MapToManagedUserResourceIds(id);
   return ResourceBundle::GetSharedInstance().GetNativeImageNamed(id);
 }
 
 bool ManagedUserTheme::HasCustomImage(int id) const {
-  return (id == IDR_THEME_FRAME ||
-          id == IDR_THEME_FRAME_INACTIVE ||
-          id == IDR_THEME_TAB_BACKGROUND ||
-          id == IDR_THEME_TAB_BACKGROUND_V);
+  return id != MapToManagedUserResourceIds(id);
 }
diff --git a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
index c630ebc..11bec08 100644
--- a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
+++ b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
@@ -60,7 +60,12 @@
 
 // Actual tests ---------------------------------------------------------------
 
-IN_PROC_BROWSER_TEST_F(MediaStreamInfoBarTest, TestAllowingUserMedia) {
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_TestAllowingUserMedia DISABLED_TestAllowingUserMedia
+#else
+#define MAYBE_TestAllowingUserMedia TestAllowingUserMedia
+#endif
+IN_PROC_BROWSER_TEST_F(MediaStreamInfoBarTest, MAYBE_TestAllowingUserMedia) {
   content::WebContents* tab_contents = LoadTestPageInTab();
   GetUserMediaAndAccept(tab_contents);
 }
@@ -75,8 +80,17 @@
   GetUserMediaAndDismiss(tab_contents);
 }
 
+// Failing on ChromiumOS Debug and Win Aura, so disabling on Aura.
+// See http://crbug.com/263333.
+#if defined(USE_AURA)
+#define MAYBE_TestAcceptThenDenyWhichShouldBeSticky \
+  DISABLED_TestAcceptThenDenyWhichShouldBeSticky
+#else
+#define MAYBE_TestAcceptThenDenyWhichShouldBeSticky \
+  TestAcceptThenDenyWhichShouldBeSticky
+#endif
 IN_PROC_BROWSER_TEST_F(MediaStreamInfoBarTest,
-                       TestAcceptThenDenyWhichShouldBeSticky) {
+                       MAYBE_TestAcceptThenDenyWhichShouldBeSticky) {
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
@@ -144,8 +158,15 @@
                                                kVideoOnlyCallConstraints);
 }
 
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_DenyingCameraDoesNotCauseStickyDenyForMics \
+  DISABLED_DenyingCameraDoesNotCauseStickyDenyForMics
+#else
+#define MAYBE_DenyingCameraDoesNotCauseStickyDenyForMics \
+  DenyingCameraDoesNotCauseStickyDenyForMics
+#endif
 IN_PROC_BROWSER_TEST_F(MediaStreamInfoBarTest,
-                       DenyingCameraDoesNotCauseStickyDenyForMics) {
+                       MAYBE_DenyingCameraDoesNotCauseStickyDenyForMics) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   // If camera blocking also blocked mics, the second call here would hang.
diff --git a/chrome/browser/media/chrome_webrtc_browsertest.cc b/chrome/browser/media/chrome_webrtc_browsertest.cc
index 8dfc0fa..de56fc1 100644
--- a/chrome/browser/media/chrome_webrtc_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/file_util.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
+#include "base/process/process_metrics.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
@@ -26,12 +27,14 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/perf/perf_test.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"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/python_utils.h"
 
 static const char kMainWebrtcTestHtmlPage[] =
     "/webrtc/webrtc_jsep01_test.html";
@@ -69,14 +72,6 @@
     base::Closure on_channel_closing_;
   };
 
-  virtual void SetUp() OVERRIDE {
-    // TODO(phoglund): Remove this when the bots enable real GPU with the
-    // command line. crbug.com/271504
-    UseRealGLBindings();
-
-    WebRtcTestBase::SetUp();
-  }
-
   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
     PeerConnectionServerRunner::KillAllPeerConnectionServersOnCurrentSystem();
     peerconnection_server_.Start();
@@ -96,6 +91,9 @@
         switches::kUseFakeDeviceForMediaStream));
     EXPECT_FALSE(command_line->HasSwitch(
         switches::kUseFakeUIForMediaStream));
+
+    // The video playback will not work without a GPU, so force its use here.
+    command_line->AppendSwitch(switches::kUseGpuInTests);
   }
 
   // Convenience method which executes the provided javascript in the context
@@ -188,6 +186,28 @@
         "'video');", tab_contents);
   }
 
+  void PrintProcessMetrics(base::ProcessMetrics* process_metrics,
+                           const std::string& suffix) {
+    perf_test::PrintResult("cpu", "", "cpu" + suffix,
+                           process_metrics->GetCPUUsage(),
+                           "%", true);
+    perf_test::PrintResult("memory", "", "ws_final" + suffix,
+                           process_metrics->GetWorkingSetSize(),
+                           "bytes", true);
+    perf_test::PrintResult("memory", "", "ws_peak" + suffix,
+                           process_metrics->GetPeakWorkingSetSize(),
+                           "bytes", true);
+
+    size_t private_mem;
+    size_t shared_mem;
+    if (process_metrics->GetMemoryBytes(&private_mem, &shared_mem)) {
+      perf_test::PrintResult("memory", "", "private_mem_final" + suffix,
+                             private_mem, "bytes", true);
+      perf_test::PrintResult("memory", "", "shared_mem_final" + suffix,
+                             shared_mem, "bytes", true);
+    }
+  }
+
  private:
   PeerConnectionServerRunner peerconnection_server_;
 };
@@ -231,6 +251,64 @@
   AssertNoAsynchronousErrors(right_tab);
 }
 
+// TODO(phoglund): figure out how to do mach port brokering on Mac.
+#if !defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
+                       MANUAL_RendererCpuUsage20Seconds) {
+  EXPECT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+
+  base::FilePath results_file;
+  EXPECT_TRUE(file_util::CreateTemporaryFile(&results_file));
+
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
+  content::WebContents* left_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  base::ProcessHandle renderer_pid =
+      left_tab->GetRenderProcessHost()->GetHandle();
+
+  scoped_ptr<base::ProcessMetrics> renderer_process_metrics(
+      base::ProcessMetrics::CreateProcessMetrics(renderer_pid));
+  scoped_ptr<base::ProcessMetrics> browser_process_metrics(
+      base::ProcessMetrics::CreateProcessMetrics(
+          base::Process::Current().handle()));
+
+  // Start measuring CPU.
+  renderer_process_metrics->GetCPUUsage();
+  browser_process_metrics->GetCPUUsage();
+
+  GetUserMediaAndAccept(left_tab);
+
+  chrome::AddBlankTabAt(browser(), -1, true);
+  content::WebContents* right_tab =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ui_test_utils::NavigateToURL(
+        browser(), embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
+  GetUserMediaAndAccept(right_tab);
+
+  ConnectToPeerConnectionServer("peer 1", left_tab);
+  ConnectToPeerConnectionServer("peer 2", right_tab);
+
+  EstablishCall(left_tab, right_tab);
+
+  AssertNoAsynchronousErrors(left_tab);
+  AssertNoAsynchronousErrors(right_tab);
+
+  SleepInJavascript(left_tab, 15000);
+
+  HangUp(left_tab);
+  WaitUntilHangupVerified(left_tab);
+  WaitUntilHangupVerified(right_tab);
+
+  PrintProcessMetrics(renderer_process_metrics.get(), "_r");
+  PrintProcessMetrics(browser_process_metrics.get(), "_b");
+
+  AssertNoAsynchronousErrors(left_tab);
+  AssertNoAsynchronousErrors(right_tab);
+}
+#endif
+
 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest,
                        MANUAL_TestMediaStreamTrackEnableDisable) {
   EXPECT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
diff --git a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
index 318a3ce..c1e0056 100644
--- a/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
+++ b/chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc
@@ -126,6 +126,9 @@
     EXPECT_FALSE(
         command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream))
         << "You cannot run this test with fake devices.";
+
+    // The video playback will not work without a GPU, so force its use here.
+    command_line->AppendSwitch(switches::kUseGpuInTests);
   }
 
   void StartPyWebSocketServer() {
@@ -142,9 +145,13 @@
         << "Fatal: missing data handler for pywebsocket server.";
 
     AppendToPythonPath(path_pywebsocket_dir);
-    CommandLine pywebsocket_command = MakePythonCommand(pywebsocket_server);
 
-    // Construct the command line manually, the server doesn't support -arg=val.
+    // Note: don't append switches to this command since it will mess up the
+    // -u in the python invocation!
+    CommandLine pywebsocket_command(CommandLine::NO_PROGRAM);
+    EXPECT_TRUE(GetPythonCommand(&pywebsocket_command));
+
+    pywebsocket_command.AppendArgPath(pywebsocket_server);
     pywebsocket_command.AppendArg("-p");
     pywebsocket_command.AppendArg(kPyWebSocketPortNumber);
     pywebsocket_command.AppendArg("-d");
@@ -267,15 +274,24 @@
         << "Missing video compare script: should be in "
         << path_to_compare_script.value();
 
-    CommandLine compare_command = MakePythonCommand(path_to_compare_script);
-    compare_command.AppendSwitchPath("--ref_video", reference_video_filename);
-    compare_command.AppendSwitchPath("--test_video", captured_video_filename);
-    compare_command.AppendSwitchPath("--frame_analyzer", path_to_analyzer);
-    compare_command.AppendSwitchASCII("--yuv_frame_width",
-                                      base::StringPrintf("%d", width));
-    compare_command.AppendSwitchASCII("--yuv_frame_height",
-                                      base::StringPrintf("%d", height));
-    compare_command.AppendSwitchPath("--stats_file", stats_file);
+    // Note: don't append switches to this command since it will mess up the
+    // -u in the python invocation!
+    CommandLine compare_command(CommandLine::NO_PROGRAM);
+    EXPECT_TRUE(GetPythonCommand(&compare_command));
+
+    compare_command.AppendArgPath(path_to_compare_script);
+    compare_command.AppendArg("--ref_video");
+    compare_command.AppendArgPath(reference_video_filename);
+    compare_command.AppendArg("--test_video");
+    compare_command.AppendArgPath(captured_video_filename);
+    compare_command.AppendArg("--frame_analyzer");
+    compare_command.AppendArgPath(path_to_analyzer);
+    compare_command.AppendArg("--yuv_frame_width");
+    compare_command.AppendArg(base::StringPrintf("%d", width));
+    compare_command.AppendArg("--yuv_frame_height");
+    compare_command.AppendArg(base::StringPrintf("%d", height));
+    compare_command.AppendArg("--stats_file");
+    compare_command.AppendArgPath(stats_file);
 
     LOG(INFO) << "Running " << compare_command.GetCommandLineString();
     std::string result;
@@ -380,28 +396,13 @@
     return browser_dir;
   }
 
-  CommandLine MakePythonCommand(base::FilePath python_script) {
-    CommandLine python_command(CommandLine::NO_PROGRAM);
-    EXPECT_TRUE(GetPythonCommand(&python_command));
-    CommandLine complete_command(python_script);
-    complete_command.PrependWrapper(python_command.GetCommandLineString());
-    return complete_command;
-  }
-
   PeerConnectionServerRunner peerconnection_server_;
   base::ProcessHandle pywebsocket_server_;
   scoped_ptr<base::Environment> environment_;
 };
 
-#if defined(OS_WIN)
-// Broken on Win: failing to start pywebsocket_server. http://crbug.com/255499.
-#define MAYBE_MANUAL_TestVGAVideoQuality DISABLED_MANUAL_TestVGAVideoQuality
-#else
-#define MAYBE_MANUAL_TestVGAVideoQuality MANUAL_TestVGAVideoQuality
-#endif
-
 IN_PROC_BROWSER_TEST_F(WebrtcVideoQualityBrowserTest,
-                       MAYBE_MANUAL_TestVGAVideoQuality) {
+                       MANUAL_TestVGAVideoQuality) {
   StartPyWebSocketServer();
 
   EXPECT_TRUE(test_server()->Start());
diff --git a/chrome/browser/media/desktop_media_picker_model.cc b/chrome/browser/media/desktop_media_picker_model.cc
index 878d04f..741fb1c 100644
--- a/chrome/browser/media/desktop_media_picker_model.cc
+++ b/chrome/browser/media/desktop_media_picker_model.cc
@@ -219,8 +219,12 @@
   current_frame_.reset(frame);
 }
 
-DesktopMediaPickerModel::DesktopMediaPickerModel()
-    : update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
+DesktopMediaPickerModel::DesktopMediaPickerModel(
+    scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
+    scoped_ptr<webrtc::WindowCapturer> window_capturer)
+    : screen_capturer_(screen_capturer.Pass()),
+      window_capturer_(window_capturer.Pass()),
+      update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
       thumbnail_size_(100, 100),
       observer_(NULL),
       weak_factory_(this) {
@@ -233,14 +237,6 @@
   capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release());
 }
 
-void DesktopMediaPickerModel::SetCapturers(
-    scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
-    scoped_ptr<webrtc::WindowCapturer> window_capturer) {
-  DCHECK(!observer_);
-  screen_capturer_ = screen_capturer.Pass();
-  window_capturer_ = window_capturer.Pass();
-}
-
 void DesktopMediaPickerModel::SetUpdatePeriod(base::TimeDelta period) {
   DCHECK(!observer_);
   update_period_ = period;
diff --git a/chrome/browser/media/desktop_media_picker_model.h b/chrome/browser/media/desktop_media_picker_model.h
index 494a325..7773c3d 100644
--- a/chrome/browser/media/desktop_media_picker_model.h
+++ b/chrome/browser/media/desktop_media_picker_model.h
@@ -49,17 +49,13 @@
     gfx::ImageSkia thumbnail;
   };
 
-  DesktopMediaPickerModel();
+  // Caller may pass NULL for either of the arguments in case when only some
+  // types of sources the model should be populated with (e.g. it will only
+  // contain windows, if |screen_capturer| is NULL).
+  DesktopMediaPickerModel(scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
+                          scoped_ptr<webrtc::WindowCapturer> window_capturer);
   virtual ~DesktopMediaPickerModel();
 
-  // Sets screen/window capturer implementations to use (e.g. for tests). Caller
-  // may pass NULL for either of the arguments in case when only some types of
-  // sources the model should be populated with (e.g. it will only contain
-  // windows, if |screen_capturer| is NULL). Must be called before
-  // StartUpdating().
-  void SetCapturers(scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
-                    scoped_ptr<webrtc::WindowCapturer> window_capturer);
-
   // Sets time interval between updates. By default list of sources and their
   // thumbnail are updated once per second. If called after StartUpdating() then
   // it will take effect only after the next update.
@@ -107,9 +103,6 @@
   void OnSourceThumbnail(int index, const gfx::ImageSkia& thumbnail);
   void OnRefreshFinished();
 
-  // Flags passed to the constructor.
-  int flags_;
-
   // Capturers specified in SetCapturers() and passed to the |worker_| later.
   scoped_ptr<webrtc::ScreenCapturer> screen_capturer_;
   scoped_ptr<webrtc::WindowCapturer> window_capturer_;
diff --git a/chrome/browser/media/desktop_media_picker_model_unittest.cc b/chrome/browser/media/desktop_media_picker_model_unittest.cc
index 3d2112c..d8f5825 100644
--- a/chrome/browser/media/desktop_media_picker_model_unittest.cc
+++ b/chrome/browser/media/desktop_media_picker_model_unittest.cc
@@ -74,7 +74,8 @@
 
   void SetNextFrame(WindowId window_id,
                     scoped_ptr<webrtc::DesktopFrame> frame) {
-      frames_[window_id] = frame.release();
+    base::AutoLock lock(frames_lock_);
+    frames_[window_id] = frame.release();
   }
 
   // webrtc::WindowCapturer implementation.
@@ -85,6 +86,8 @@
   virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
     DCHECK(callback_);
 
+    base::AutoLock lock(frames_lock_);
+
     webrtc::DesktopFrame* frame;
     std::map<WindowId, webrtc::DesktopFrame*>::iterator it =
         frames_.find(selected_window_id_);
@@ -118,6 +121,7 @@
 
   // Frames to be captured per window.
   std::map<WindowId, webrtc::DesktopFrame*> frames_;
+  base::Lock frames_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeWindowCapturer);
 };
@@ -128,15 +132,16 @@
       : window_capturer_(NULL),
         ui_thread_(content::BrowserThread::UI,
                    &message_loop_) {
-    // Set update period to reduce the time it takes to run tests.
-    model_.SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
   }
 
-  void SetDefaultCapturers() {
+  void CreateWithDefaultCapturers() {
     window_capturer_ = new FakeWindowCapturer();
-    model_.SetCapturers(
+    model_.reset(new DesktopMediaPickerModel(
         scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer()),
-        scoped_ptr<webrtc::WindowCapturer>(window_capturer_));
+        scoped_ptr<webrtc::WindowCapturer>(window_capturer_)));
+
+    // Set update period to reduce the time it takes to run tests.
+    model_->SetUpdatePeriod(base::TimeDelta::FromMilliseconds(0));
   }
 
  protected:
@@ -146,7 +151,7 @@
   // Owned by |model_|;
   FakeWindowCapturer* window_capturer_;
 
-  DesktopMediaPickerModel model_;
+  scoped_ptr<DesktopMediaPickerModel> model_;
 
   base::MessageLoop message_loop_;
   content::TestBrowserThread ui_thread_;
@@ -163,7 +168,7 @@
 }
 
 TEST_F(DesktopMediaPickerModelTest, InitialSourceList) {
-  SetDefaultCapturers();
+  CreateWithDefaultCapturers();
 
   webrtc::WindowCapturer::WindowList list;
   webrtc::WindowCapturer::Window window;
@@ -175,29 +180,29 @@
   {
     testing::InSequence dummy;
     EXPECT_CALL(observer_, OnSourceAdded(0))
-      .WillOnce(CheckListSize(&model_, 1));
+      .WillOnce(CheckListSize(model_.get(), 1));
     EXPECT_CALL(observer_, OnSourceAdded(1))
-      .WillOnce(CheckListSize(&model_, 2));
+      .WillOnce(CheckListSize(model_.get(), 2));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
       .WillOnce(QuitMessageLoop(&message_loop_));
   }
-  model_.StartUpdating(&observer_);
+  model_->StartUpdating(&observer_);
 
   message_loop_.Run();
 
-  EXPECT_EQ(model_.source(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
-  EXPECT_EQ(model_.source(0).id.id, 0);
-  EXPECT_EQ(model_.source(1).id.type, content::DesktopMediaID::TYPE_WINDOW);
-  EXPECT_EQ(model_.source(1).id.id, 0);
-  EXPECT_EQ(model_.source(1).name, UTF8ToUTF16(window.title));
+  EXPECT_EQ(model_->source(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
+  EXPECT_EQ(model_->source(0).id.id, 0);
+  EXPECT_EQ(model_->source(1).id.type, content::DesktopMediaID::TYPE_WINDOW);
+  EXPECT_EQ(model_->source(1).id.id, 0);
+  EXPECT_EQ(model_->source(1).name, UTF8ToUTF16(window.title));
 }
 
 TEST_F(DesktopMediaPickerModelTest, WindowsOnly) {
   window_capturer_ = new FakeWindowCapturer();
-  model_.SetCapturers(
+  model_.reset(new DesktopMediaPickerModel(
       scoped_ptr<webrtc::ScreenCapturer>(),
-      scoped_ptr<webrtc::WindowCapturer>(window_capturer_));
+      scoped_ptr<webrtc::WindowCapturer>(window_capturer_)));
 
   webrtc::WindowCapturer::WindowList list;
   webrtc::WindowCapturer::Window window;
@@ -209,38 +214,38 @@
   {
     testing::InSequence dummy;
     EXPECT_CALL(observer_, OnSourceAdded(0))
-      .WillOnce(CheckListSize(&model_, 1));
+      .WillOnce(CheckListSize(model_.get(), 1));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
       .WillOnce(QuitMessageLoop(&message_loop_));
   }
-  model_.StartUpdating(&observer_);
+  model_->StartUpdating(&observer_);
 
   message_loop_.Run();
 
-  EXPECT_EQ(model_.source(0).id.type, content::DesktopMediaID::TYPE_WINDOW);
+  EXPECT_EQ(model_->source(0).id.type, content::DesktopMediaID::TYPE_WINDOW);
 }
 
 TEST_F(DesktopMediaPickerModelTest, ScreenOnly) {
-  model_.SetCapturers(
+  model_.reset(new DesktopMediaPickerModel(
       scoped_ptr<webrtc::ScreenCapturer>(new FakeScreenCapturer),
-      scoped_ptr<webrtc::WindowCapturer>());
+      scoped_ptr<webrtc::WindowCapturer>()));
 
   {
     testing::InSequence dummy;
     EXPECT_CALL(observer_, OnSourceAdded(0))
-      .WillOnce(CheckListSize(&model_, 1));
+      .WillOnce(CheckListSize(model_.get(), 1));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0))
       .WillOnce(QuitMessageLoop(&message_loop_));
   }
-  model_.StartUpdating(&observer_);
+  model_->StartUpdating(&observer_);
 
   message_loop_.Run();
 
-  EXPECT_EQ(model_.source(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
+  EXPECT_EQ(model_->source(0).id.type, content::DesktopMediaID::TYPE_SCREEN);
 }
 
 TEST_F(DesktopMediaPickerModelTest, AddWindow) {
-  SetDefaultCapturers();
+  CreateWithDefaultCapturers();
 
   webrtc::WindowCapturer::WindowList list;
   webrtc::WindowCapturer::Window window;
@@ -252,21 +257,21 @@
   {
     testing::InSequence dummy;
     EXPECT_CALL(observer_, OnSourceAdded(0))
-      .WillOnce(CheckListSize(&model_, 1));
+      .WillOnce(CheckListSize(model_.get(), 1));
     EXPECT_CALL(observer_, OnSourceAdded(1))
-      .WillOnce(CheckListSize(&model_, 2));
+      .WillOnce(CheckListSize(model_.get(), 2));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
       .WillOnce(QuitMessageLoop(&message_loop_));
   }
-  model_.StartUpdating(&observer_);
+  model_->StartUpdating(&observer_);
 
   message_loop_.Run();
 
   testing::Mock::VerifyAndClearExpectations(&observer_);
 
   EXPECT_CALL(observer_, OnSourceAdded(1))
-    .WillOnce(DoAll(CheckListSize(&model_, 3),
+    .WillOnce(DoAll(CheckListSize(model_.get(), 3),
                     QuitMessageLoop(&message_loop_)));
 
   window.id = 0;
@@ -276,12 +281,12 @@
 
   message_loop_.Run();
 
-  EXPECT_EQ(model_.source(1).id.type, content::DesktopMediaID::TYPE_WINDOW);
-  EXPECT_EQ(model_.source(1).id.id, 0);
+  EXPECT_EQ(model_->source(1).id.type, content::DesktopMediaID::TYPE_WINDOW);
+  EXPECT_EQ(model_->source(1).id.id, 0);
 }
 
 TEST_F(DesktopMediaPickerModelTest, RemoveWindow) {
-  SetDefaultCapturers();
+  CreateWithDefaultCapturers();
 
   webrtc::WindowCapturer::WindowList list;
   webrtc::WindowCapturer::Window window;
@@ -296,24 +301,24 @@
   {
     testing::InSequence dummy;
     EXPECT_CALL(observer_, OnSourceAdded(0))
-      .WillOnce(CheckListSize(&model_, 1));
+      .WillOnce(CheckListSize(model_.get(), 1));
     EXPECT_CALL(observer_, OnSourceAdded(1))
-      .WillOnce(CheckListSize(&model_, 2));
+      .WillOnce(CheckListSize(model_.get(), 2));
     EXPECT_CALL(observer_, OnSourceAdded(2))
-      .WillOnce(CheckListSize(&model_, 3));
+      .WillOnce(CheckListSize(model_.get(), 3));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
       .WillOnce(QuitMessageLoop(&message_loop_));
   }
-  model_.StartUpdating(&observer_);
+  model_->StartUpdating(&observer_);
 
   message_loop_.Run();
 
   testing::Mock::VerifyAndClearExpectations(&observer_);
 
   EXPECT_CALL(observer_, OnSourceRemoved(1))
-    .WillOnce(DoAll(CheckListSize(&model_, 2),
+    .WillOnce(DoAll(CheckListSize(model_.get(), 2),
                     QuitMessageLoop(&message_loop_)));
 
   list.erase(list.begin());
@@ -323,7 +328,7 @@
 }
 
 TEST_F(DesktopMediaPickerModelTest, UpdateTitle) {
-  SetDefaultCapturers();
+  CreateWithDefaultCapturers();
 
   webrtc::WindowCapturer::WindowList list;
   webrtc::WindowCapturer::Window window;
@@ -335,14 +340,14 @@
   {
     testing::InSequence dummy;
     EXPECT_CALL(observer_, OnSourceAdded(0))
-      .WillOnce(CheckListSize(&model_, 1));
+      .WillOnce(CheckListSize(model_.get(), 1));
     EXPECT_CALL(observer_, OnSourceAdded(1))
-      .WillOnce(CheckListSize(&model_, 2));
+      .WillOnce(CheckListSize(model_.get(), 2));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1))
       .WillOnce(QuitMessageLoop(&message_loop_));
   }
-  model_.StartUpdating(&observer_);
+  model_->StartUpdating(&observer_);
 
   message_loop_.Run();
 
@@ -358,11 +363,12 @@
 
   message_loop_.Run();
 
-  EXPECT_EQ(model_.source(1).name, base::UTF8ToUTF16(kTestTitle));
+  EXPECT_EQ(model_->source(1).name, base::UTF8ToUTF16(kTestTitle));
 }
 
-TEST_F(DesktopMediaPickerModelTest, UpdateThumbnail) {
-  SetDefaultCapturers();
+// Disabled due to flakiness on all platforms, see http://crbug.com/275260.
+TEST_F(DesktopMediaPickerModelTest, DISABLED_UpdateThumbnail) {
+  CreateWithDefaultCapturers();
 
   webrtc::WindowCapturer::WindowList list;
   webrtc::WindowCapturer::Window window;
@@ -377,17 +383,17 @@
   {
     testing::InSequence dummy;
     EXPECT_CALL(observer_, OnSourceAdded(0))
-      .WillOnce(CheckListSize(&model_, 1));
+      .WillOnce(CheckListSize(model_.get(), 1));
     EXPECT_CALL(observer_, OnSourceAdded(1))
-      .WillOnce(CheckListSize(&model_, 2));
+      .WillOnce(CheckListSize(model_.get(), 2));
     EXPECT_CALL(observer_, OnSourceAdded(2))
-      .WillOnce(CheckListSize(&model_, 3));
+      .WillOnce(CheckListSize(model_.get(), 3));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(0));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(1));
     EXPECT_CALL(observer_, OnSourceThumbnailChanged(2))
       .WillOnce(QuitMessageLoop(&message_loop_));
   }
-  model_.StartUpdating(&observer_);
+  model_->StartUpdating(&observer_);
 
   message_loop_.Run();
 
diff --git a/chrome/browser/media/desktop_streams_registry.cc b/chrome/browser/media/desktop_streams_registry.cc
new file mode 100644
index 0000000..0c87357
--- /dev/null
+++ b/chrome/browser/media/desktop_streams_registry.cc
@@ -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.
+
+#include "chrome/browser/media/desktop_streams_registry.h"
+
+#include "base/base64.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/random.h"
+
+namespace {
+
+const int kStreamIdLengthBytes = 16;
+
+const int kApprovedStreamTimeToLiveSeconds = 10;
+
+std::string GenerateRandomStreamId() {
+  char buffer[kStreamIdLengthBytes];
+  crypto::RandBytes(buffer, arraysize(buffer));
+  std::string result;
+  if (!base::Base64Encode(base::StringPiece(buffer, arraysize(buffer)),
+                          &result)) {
+    LOG(FATAL) << "Base64Encode failed.";
+  }
+  return result;
+}
+
+}  // namespace
+
+DesktopStreamsRegistry::DesktopStreamsRegistry() {}
+DesktopStreamsRegistry::~DesktopStreamsRegistry() {}
+
+std::string DesktopStreamsRegistry::RegisterStream(
+    const GURL& origin,
+    const content::DesktopMediaID& source) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  std::string id = GenerateRandomStreamId();
+  ApprovedDesktopMediaStream& stream = approved_streams_[id];
+  stream.origin = origin;
+  stream.source = source;
+
+  content::BrowserThread::PostDelayedTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&DesktopStreamsRegistry::CleanupStream,
+                 base::Unretained(this), id),
+      base::TimeDelta::FromSeconds(kApprovedStreamTimeToLiveSeconds));
+
+  return id;
+}
+
+content::DesktopMediaID DesktopStreamsRegistry::RequestMediaForStreamId(
+    const std::string& id,
+    const GURL& origin) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  StreamsMap::iterator it = approved_streams_.find(id);
+  if (it == approved_streams_.end() || origin != it->second.origin)
+    return content::DesktopMediaID();
+  content::DesktopMediaID result = it->second.source;
+  approved_streams_.erase(it);
+  return result;
+}
+
+void DesktopStreamsRegistry::CleanupStream(const std::string& id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  approved_streams_.erase(id);
+}
diff --git a/chrome/browser/media/desktop_streams_registry.h b/chrome/browser/media/desktop_streams_registry.h
new file mode 100644
index 0000000..348708c
--- /dev/null
+++ b/chrome/browser/media/desktop_streams_registry.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 CHROME_BROWSER_MEDIA_DESKTOP_STREAMS_REGISTRY_H_
+#define CHROME_BROWSER_MEDIA_DESKTOP_STREAMS_REGISTRY_H_
+
+#include <map>
+#include <string>
+
+#include "chrome/browser/media/desktop_media_picker_model.h"
+#include "url/gurl.h"
+
+// DesktopStreamsRegistry is used to store accepted desktop media streams for
+// Desktop Capture API. Single instance of this class is created per browser in
+// MediaCaptureDevicesDispatcher.
+class DesktopStreamsRegistry {
+ public:
+  DesktopStreamsRegistry();
+  ~DesktopStreamsRegistry();
+
+  // Adds new stream to the registry. Called by the implementation of
+  // desktopCapture.chooseDesktopMedia() API after user has approved access to
+  // |source| for the |origin|. Returns identifier of the new stream.
+  std::string RegisterStream(const GURL& origin,
+                             const content::DesktopMediaID& source);
+
+  // Validates stream identifier specified in getUserMedia(). Returns null
+  // DesktopMediaID if the specified |id| is invalid, i.e. wasn't generated
+  // using RegisterStream() or if it was generated for a different origin.
+  // Otherwise returns ID of the source and removes it from the registry.
+  content::DesktopMediaID RequestMediaForStreamId(const std::string& id,
+                                                  const GURL& origin);
+
+ private:
+  // Type used to store list of accepted desktop media streams.
+  struct ApprovedDesktopMediaStream {
+    GURL origin;
+    content::DesktopMediaID source;
+  };
+  typedef std::map<std::string, ApprovedDesktopMediaStream> StreamsMap;
+
+  // Helper function that removes an expired stream from the registry.
+  void CleanupStream(const std::string& id);
+
+  StreamsMap approved_streams_;
+
+  DISALLOW_COPY_AND_ASSIGN(DesktopStreamsRegistry);
+};
+
+#endif  // CHROME_BROWSER_MEDIA_DESKTOP_STREAMS_REGISTRY_H_
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index 936257e..1ef3a23 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry.h"
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry_factory.h"
 #include "chrome/browser/media/audio_stream_indicator.h"
+#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"
@@ -86,6 +87,20 @@
 #endif
 }
 
+// Helper to get title of the calling application shown in the screen capture
+// notification.
+string16 GetApplicationTitle(content::WebContents* web_contents,
+                             const extensions::Extension* extension) {
+  // Use extension name as title for extensions and origin for drive-by web.
+  std::string title;
+  if (extension) {
+    title = extension->name();
+  } else {
+    title = web_contents->GetURL().GetOrigin().spec();
+  }
+  return UTF8ToUTF16(title);
+}
+
 }  // namespace
 
 MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest(
@@ -182,7 +197,7 @@
 
   if (request.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE ||
       request.audio_type == content::MEDIA_SYSTEM_AUDIO_CAPTURE) {
-    ProcessScreenCaptureAccessRequest(
+    ProcessDesktopCaptureAccessRequest(
         web_contents, request, callback, extension);
   } else if (extension) {
     // For extensions access is approved based on extension permissions.
@@ -193,7 +208,7 @@
   }
 }
 
-void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest(
+void MediaCaptureDevicesDispatcher::ProcessDesktopCaptureAccessRequest(
     content::WebContents* web_contents,
     const content::MediaStreamRequest& request,
     const content::MediaResponseCallback& callback,
@@ -206,6 +221,50 @@
     return;
   }
 
+  // First check if Desktop Capture API (i.e.
+  // chrome.desktopCapture.chooseDesktopMedia()) was used to generate device Id.
+  content::DesktopMediaID media_id =
+      GetDesktopStreamsRegistry()->RequestMediaForStreamId(
+          request.requested_video_device_id, request.security_origin);
+
+  // If the id wasn't generated using Desktop Capture API then process it as a
+  // screen capture request.
+  if (media_id.type == content::DesktopMediaID::TYPE_NONE) {
+    ProcessScreenCaptureAccessRequest(
+        web_contents, request, callback, extension);
+    return;
+  }
+
+  // Add selected desktop source to the list.
+  devices.push_back(content::MediaStreamDevice(
+      content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(),
+      std::string()));
+
+  // Audio is only supported for screen capture streams.
+  if (media_id.type == content::DesktopMediaID::TYPE_SCREEN &&
+      request.audio_type == content::MEDIA_SYSTEM_AUDIO_CAPTURE) {
+    devices.push_back(content::MediaStreamDevice(
+        content::MEDIA_SYSTEM_AUDIO_CAPTURE, media_id.ToString(),
+        "System Audio"));
+  }
+
+  ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
+      IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT,
+      GetApplicationTitle(web_contents, extension)));
+
+  callback.Run(devices, ui.Pass());
+}
+
+void MediaCaptureDevicesDispatcher::ProcessScreenCaptureAccessRequest(
+    content::WebContents* web_contents,
+    const content::MediaStreamRequest& request,
+    const content::MediaResponseCallback& callback,
+    const extensions::Extension* extension) {
+  content::MediaStreamDevices devices;
+  scoped_ptr<content::MediaStreamUI> ui;
+
+  DCHECK_EQ(request.video_type, content::MEDIA_DESKTOP_VIDEO_CAPTURE);
+
   content::DesktopMediaID media_id =
       content::DesktopMediaID::Parse(request.requested_video_device_id);
   if (media_id.is_null()) {
@@ -215,6 +274,14 @@
     return;
   }
 
+  // Only screen capture can be requested without using desktop media picker.
+  if (media_id.type != content::DesktopMediaID::TYPE_SCREEN) {
+    LOG(ERROR) << "Unsupported desktop media ID: "
+               << request.requested_video_device_id;
+    callback.Run(devices, ui.Pass());
+    return;
+  }
+
   const bool system_audio_capture_requested =
       request.audio_type == content::MEDIA_SYSTEM_AUDIO_CAPTURE;
 
@@ -286,16 +353,9 @@
   // Unless we're being invoked from a component extension, register to display
   // the notification for stream capture.
   if (!devices.empty() && !component_extension) {
-    // Use extension name as title for extensions and origin for drive-by web.
-    std::string title;
-    if (extension) {
-      title = extension->name();
-    } else {
-      title = web_contents->GetURL().GetOrigin().spec();
-    }
-
     ui = ScreenCaptureNotificationUI::Create(l10n_util::GetStringFUTF16(
-        IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT, UTF8ToUTF16(title)));
+        IDS_MEDIA_SCREEN_CAPTURE_NOTIFICATION_TEXT,
+        GetApplicationTitle(web_contents, extension)));
   }
 
   callback.Run(devices, ui.Pass());
@@ -491,7 +551,7 @@
 }
 
 scoped_refptr<MediaStreamCaptureIndicator>
-    MediaCaptureDevicesDispatcher::GetMediaStreamCaptureIndicator() {
+MediaCaptureDevicesDispatcher::GetMediaStreamCaptureIndicator() {
   return media_stream_capture_indicator_;
 }
 
@@ -500,6 +560,13 @@
   return audio_stream_indicator_;
 }
 
+DesktopStreamsRegistry*
+MediaCaptureDevicesDispatcher::GetDesktopStreamsRegistry() {
+  if (!desktop_streams_registry_)
+    desktop_streams_registry_.reset(new DesktopStreamsRegistry());
+  return desktop_streams_registry_.get();
+}
+
 void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged(
     const content::MediaStreamDevices& devices) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.h b/chrome/browser/media/media_capture_devices_dispatcher.h
index f82a28b..b36889f 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.h
+++ b/chrome/browser/media/media_capture_devices_dispatcher.h
@@ -19,6 +19,7 @@
 #include "content/public/common/media_stream_request.h"
 
 class AudioStreamIndicator;
+class DesktopStreamsRegistry;
 class MediaStreamCaptureIndicator;
 class Profile;
 
@@ -135,6 +136,8 @@
 
   scoped_refptr<AudioStreamIndicator> GetAudioStreamIndicator();
 
+  DesktopStreamsRegistry* GetDesktopStreamsRegistry();
+
  private:
   friend struct DefaultSingletonTraits<MediaCaptureDevicesDispatcher>;
 
@@ -158,6 +161,11 @@
                        const content::NotificationDetails& details) OVERRIDE;
 
   // Helpers for ProcessMediaAccessRequest().
+  void ProcessDesktopCaptureAccessRequest(
+      content::WebContents* web_contents,
+      const content::MediaStreamRequest& request,
+      const content::MediaResponseCallback& callback,
+      const extensions::Extension* extension);
   void ProcessScreenCaptureAccessRequest(
       content::WebContents* web_contents,
       const content::MediaStreamRequest& request,
@@ -211,6 +219,8 @@
 
   scoped_refptr<AudioStreamIndicator> audio_stream_indicator_;
 
+  scoped_ptr<DesktopStreamsRegistry> desktop_streams_registry_;
+
   content::NotificationRegistrar notifications_registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaCaptureDevicesDispatcher);
diff --git a/chrome/browser/media/media_stream_devices_controller.cc b/chrome/browser/media/media_stream_devices_controller.cc
index 04c5cf6..08fde6c 100644
--- a/chrome/browser/media/media_stream_devices_controller.cc
+++ b/chrome/browser/media/media_stream_devices_controller.cc
@@ -60,30 +60,37 @@
     const content::MediaResponseCallback& callback)
     : web_contents_(web_contents),
       request_(request),
-      callback_(callback),
-      // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
-      // and microphone to avoid popping two infobars.
-      microphone_requested_(
-          request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
-          request.request_type == content::MEDIA_OPEN_DEVICE),
-      webcam_requested_(
-          request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
-          request.request_type == content::MEDIA_OPEN_DEVICE) {
+      callback_(callback) {
   profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
   content_settings_ = TabSpecificContentSettings::FromWebContents(web_contents);
 
-  // Don't call GetDevicePolicy from the initializer list since the
-  // implementation depends on member variables.
-  if (microphone_requested_ &&
-      GetDevicePolicy(prefs::kAudioCaptureAllowed,
-                      prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) {
-    microphone_requested_ = false;
+  // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam
+  // and microphone to avoid popping two infobars.
+  // We start with setting the requested media type to allowed or blocked
+  // depending on the policy. If not blocked by policy it may be blocked later
+  // in the two remaining filtering steps (by user setting or by user when
+  // clicking the infobar).
+  // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE
+  // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed.
+  if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
+      request.request_type == content::MEDIA_OPEN_DEVICE) {
+    if (GetDevicePolicy(prefs::kAudioCaptureAllowed,
+                        prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) {
+      request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+          MEDIA_BLOCKED_BY_POLICY;
+    } else {
+      request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE] = MEDIA_ALLOWED;
+    }
   }
-
-  if (webcam_requested_ &&
-      GetDevicePolicy(prefs::kVideoCaptureAllowed,
-                      prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) {
-    webcam_requested_ = false;
+  if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE ||
+      request.request_type == content::MEDIA_OPEN_DEVICE) {
+    if (GetDevicePolicy(prefs::kVideoCaptureAllowed,
+                        prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) {
+      request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+          MEDIA_BLOCKED_BY_POLICY;
+    } else {
+      request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE] = MEDIA_ALLOWED;
+    }
   }
 }
 
@@ -155,6 +162,14 @@
   return false;
 }
 
+bool MediaStreamDevicesController::HasAudio() const {
+  return IsDeviceAudioCaptureRequestedAndAllowed();
+}
+
+bool MediaStreamDevicesController::HasVideo() const {
+  return IsDeviceVideoCaptureRequestedAndAllowed();
+}
+
 const std::string& MediaStreamDevicesController::GetSecurityOriginSpec() const {
   return request_.security_origin.spec();
 }
@@ -164,7 +179,9 @@
 
   // Get the default devices for the request.
   content::MediaStreamDevices devices;
-  if (microphone_requested_ || webcam_requested_) {
+  bool audio_allowed = IsDeviceAudioCaptureRequestedAndAllowed();
+  bool video_allowed = IsDeviceVideoCaptureRequestedAndAllowed();
+  if (audio_allowed || video_allowed) {
     switch (request_.request_type) {
       case content::MEDIA_OPEN_DEVICE: {
         const content::MediaStreamDevice* device = NULL;
@@ -192,8 +209,8 @@
           devices.push_back(*device);
         break;
       } case content::MEDIA_GENERATE_STREAM: {
-        bool needs_audio_device = microphone_requested_;
-        bool needs_video_device = webcam_requested_;
+        bool needs_audio_device = audio_allowed;
+        bool needs_video_device = video_allowed;
 
         // Get the exact audio or video device if an id is specified.
         if (!request_.requested_audio_device_id.empty()) {
@@ -229,8 +246,8 @@
         // Get the default devices for the request.
         MediaCaptureDevicesDispatcher::GetInstance()->
             GetDefaultDevicesForProfile(profile_,
-                                        microphone_requested_,
-                                        webcam_requested_,
+                                        audio_allowed,
+                                        video_allowed,
                                         &devices);
         break;
       case content::MEDIA_ENUMERATE_DEVICES:
@@ -325,9 +342,9 @@
     const char* list_policy_name;
     ContentSettingsType settings_type;
   } device_checks[] = {
-    { microphone_requested_, prefs::kAudioCaptureAllowed,
+    { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed,
       prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC },
-    { webcam_requested_, prefs::kVideoCaptureAllowed,
+    { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed,
       prefs::kVideoCaptureAllowedUrls,
       CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA },
   };
@@ -364,25 +381,32 @@
 }
 
 int MediaStreamDevicesController::FilterBlockedByDefaultDevices() {
-  int requested_devices = microphone_requested_ + webcam_requested_;
-  if (microphone_requested_ &&
-      profile_->GetHostContentSettingsMap()->GetContentSetting(
-          request_.security_origin,
-          request_.security_origin,
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
-          NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
-    requested_devices--;
-    microphone_requested_ = false;
+  int requested_devices = 0;
+
+  if (IsDeviceAudioCaptureRequestedAndAllowed()) {
+    if (profile_->GetHostContentSettingsMap()->GetContentSetting(
+        request_.security_origin,
+        request_.security_origin,
+        CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
+        NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
+      request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+          MEDIA_BLOCKED_BY_USER_SETTING;
+    } else {
+      ++requested_devices;
+    }
   }
 
-  if (webcam_requested_ &&
-      profile_->GetHostContentSettingsMap()->GetContentSetting(
-          request_.security_origin,
-          request_.security_origin,
-          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
-          NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
-    requested_devices--;
-    webcam_requested_ = false;
+  if (IsDeviceVideoCaptureRequestedAndAllowed()) {
+    if (profile_->GetHostContentSettingsMap()->GetContentSetting(
+        request_.security_origin,
+        request_.security_origin,
+        CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
+        NO_RESOURCE_IDENTIFIER) == CONTENT_SETTING_BLOCK) {
+      request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+          MEDIA_BLOCKED_BY_USER_SETTING;
+    } else {
+      ++requested_devices;
+    }
   }
 
   return requested_devices;
@@ -427,7 +451,8 @@
 
   ContentSetting content_setting = allowed ?
       CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
-  if (microphone_requested_) {
+  if (request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE) !=
+      request_permissions_.end()) {
       profile_->GetHostContentSettingsMap()->SetContentSetting(
         primary_pattern,
         ContentSettingsPattern::Wildcard(),
@@ -435,7 +460,8 @@
         std::string(),
         content_setting);
   }
-  if (webcam_requested_) {
+  if (request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE) !=
+      request_permissions_.end()) {
     profile_->GetHostContentSettingsMap()->SetContentSetting(
         primary_pattern,
         ContentSettingsPattern::Wildcard(),
@@ -449,42 +475,37 @@
   if (!content_settings_)
     return;
 
-  // We need to figure out which part of the request is accepted or denied here.
-  // For example, when the request contains both audio and video, but audio is
-  // blocked by the policy, then we will prompt the infobar to ask for video
-  // permission. In case the users approve the permission,
-  // we need to show an allowed icon for video but blocked icon for audio.
-  if (request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
-    // The request might contain audio while |webcam_requested_| is false,
-    // this happens when the policy is blocking the audio.
-    if (microphone_requested_)
-      content_settings_->OnMicrophoneAccessed();
-    else
-      content_settings_->OnMicrophoneAccessBlocked();
-  }
-
-  if (request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
-    // The request might contain video while |webcam_requested_| is false,
-    // this happens when the policy is blocking the video.
-    if (webcam_requested_)
-      content_settings_->OnCameraAccessed();
-    else
-      content_settings_->OnCameraAccessBlocked();
-  }
+  content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
+                                                request_permissions_);
 }
 
-void MediaStreamDevicesController::NotifyUIRequestDenied() const {
+void MediaStreamDevicesController::NotifyUIRequestDenied() {
   if (!content_settings_)
     return;
 
-  // Do not show the block icons for tab capture.
-  if (request_.audio_type == content::MEDIA_TAB_AUDIO_CAPTURE ||
-      request_.video_type == content::MEDIA_TAB_VIDEO_CAPTURE) {
-      return;
+  if (IsDeviceAudioCaptureRequestedAndAllowed()) {
+    request_permissions_[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+        MEDIA_BLOCKED_BY_USER;
+  }
+  if (IsDeviceVideoCaptureRequestedAndAllowed()) {
+    request_permissions_[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+        MEDIA_BLOCKED_BY_USER;
   }
 
-  if (request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE)
-    content_settings_->OnMicrophoneAccessBlocked();
-  if (request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE)
-    content_settings_->OnCameraAccessBlocked();
+  content_settings_->OnMediaStreamPermissionSet(request_.security_origin,
+                                                request_permissions_);
+}
+
+bool MediaStreamDevicesController::IsDeviceAudioCaptureRequestedAndAllowed()
+    const {
+  MediaStreamTypePermissionMap::const_iterator it =
+      request_permissions_.find(content::MEDIA_DEVICE_AUDIO_CAPTURE);
+  return it != request_permissions_.end() && it->second == MEDIA_ALLOWED;
+}
+
+bool MediaStreamDevicesController::IsDeviceVideoCaptureRequestedAndAllowed()
+    const {
+  MediaStreamTypePermissionMap::const_iterator it =
+      request_permissions_.find(content::MEDIA_DEVICE_VIDEO_CAPTURE);
+  return it != request_permissions_.end() && it->second == MEDIA_ALLOWED;
 }
diff --git a/chrome/browser/media/media_stream_devices_controller.h b/chrome/browser/media/media_stream_devices_controller.h
index 6291385..3f37048 100644
--- a/chrome/browser/media/media_stream_devices_controller.h
+++ b/chrome/browser/media/media_stream_devices_controller.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_
 #define CHROME_BROWSER_MEDIA_MEDIA_STREAM_DEVICES_CONTROLLER_H_
 
+#include <map>
 #include <string>
 
 #include "content/public/browser/web_contents_delegate.h"
@@ -22,6 +23,17 @@
 
 class MediaStreamDevicesController {
  public:
+  // Permissions for media stream types.
+  enum MediaStreamTypePermission {
+    MEDIA_ALLOWED,
+    MEDIA_BLOCKED_BY_POLICY,
+    MEDIA_BLOCKED_BY_USER_SETTING,
+    MEDIA_BLOCKED_BY_USER,
+  };
+
+  typedef std::map<content::MediaStreamType, MediaStreamTypePermission>
+      MediaStreamTypePermissionMap;
+
   MediaStreamDevicesController(content::WebContents* web_contents,
                                const content::MediaStreamRequest& request,
                                const content::MediaResponseCallback& callback);
@@ -41,8 +53,8 @@
   bool DismissInfoBarAndTakeActionOnSettings();
 
   // Public methods to be called by MediaStreamInfoBarDelegate;
-  bool has_audio() const { return microphone_requested_; }
-  bool has_video() const { return webcam_requested_; }
+  bool HasAudio() const;
+  bool HasVideo() const;
   const std::string& GetSecurityOriginSpec() const;
   void Accept(bool update_content_setting);
   void Deny(bool update_content_setting);
@@ -91,7 +103,16 @@
 
   // Notifies the content setting UI that the media stream access request or
   // part of the request is denied.
-  void NotifyUIRequestDenied() const;
+  void NotifyUIRequestDenied();
+
+  // Return true if the type has been requested and permission is currently set
+  // to allowed. Note that it does not reflect the final permission decision.
+  // This function is called during the filtering steps to check if the type has
+  // been blocked yet or not and the permission may be changed to blocked during
+  // these filterings. See also the initialization in the constructor and
+  // comments on that.
+  bool IsDeviceAudioCaptureRequestedAndAllowed() const;
+  bool IsDeviceVideoCaptureRequestedAndAllowed() const;
 
   content::WebContents* web_contents_;
 
@@ -112,8 +133,12 @@
   // audio/video devices was granted or not.
   content::MediaResponseCallback callback_;
 
-  bool microphone_requested_;
-  bool webcam_requested_;
+  // Holds the requested media types and the permission for each type. It is
+  // passed to the tab specific content settings when the permissions have been
+  // resolved. Currently only used by MEDIA_DEVICE_AUDIO_CAPTURE and
+  // MEDIA_DEVICE_VIDEO_CAPTURE since those are the only types that require
+  // updates in the settings.
+  MediaStreamTypePermissionMap request_permissions_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamDevicesController);
 };
diff --git a/chrome/browser/media/media_stream_infobar_delegate.cc b/chrome/browser/media/media_stream_infobar_delegate.cc
index 5e2aa87..ae5edbf 100644
--- a/chrome/browser/media/media_stream_infobar_delegate.cc
+++ b/chrome/browser/media/media_stream_infobar_delegate.cc
@@ -63,7 +63,7 @@
     : ConfirmInfoBarDelegate(infobar_service),
       controller_(controller.Pass()) {
   DCHECK(controller_.get());
-  DCHECK(controller_->has_audio() || controller_->has_video());
+  DCHECK(controller_->HasAudio() || controller_->HasVideo());
 }
 
 void MediaStreamInfoBarDelegate::InfoBarDismissed() {
@@ -75,7 +75,7 @@
 }
 
 int MediaStreamInfoBarDelegate::GetIconID() const {
-  return controller_->has_video() ?
+  return controller_->HasVideo() ?
       IDR_INFOBAR_MEDIA_STREAM_CAMERA : IDR_INFOBAR_MEDIA_STREAM_MIC;
 }
 
@@ -90,9 +90,9 @@
 
 string16 MediaStreamInfoBarDelegate::GetMessageText() const {
   int message_id = IDS_MEDIA_CAPTURE_AUDIO_AND_VIDEO;
-  if (!controller_->has_audio())
+  if (!controller_->HasAudio())
     message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY;
-  else if (!controller_->has_video())
+  else if (!controller_->HasVideo())
     message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY;
   return l10n_util::GetStringFUTF16(
       message_id, UTF8ToUTF16(controller_->GetSecurityOriginSpec()));
diff --git a/chrome/browser/media/midi_permission_infobar_delegate.cc b/chrome/browser/media/midi_permission_infobar_delegate.cc
index 3a982e5..b6f10cd 100644
--- a/chrome/browser/media/midi_permission_infobar_delegate.cc
+++ b/chrome/browser/media/midi_permission_infobar_delegate.cc
@@ -47,6 +47,10 @@
   contents_unique_id_ = committed_entry ? committed_entry->GetUniqueID() : 0;
 }
 
+void MIDIPermissionInfoBarDelegate::InfoBarDismissed() {
+  SetPermission(false, false);
+}
+
 int MIDIPermissionInfoBarDelegate::GetIconID() const {
   return IDR_INFOBAR_MIDI_SYSEX;
 }
@@ -67,7 +71,8 @@
 }
 
 string16 MIDIPermissionInfoBarDelegate::GetMessageText() const {
-  return l10n_util::GetStringFUTF16(IDS_MIDI_SYSEX_INFOBAR_QUESTION,
+  return l10n_util::GetStringFUTF16(
+      IDS_MIDI_SYSEX_INFOBAR_QUESTION,
       net::FormatUrl(requesting_frame_.GetOrigin(), display_languages_));
 }
 
diff --git a/chrome/browser/media/midi_permission_infobar_delegate.h b/chrome/browser/media/midi_permission_infobar_delegate.h
index 1ec1d29..0b00422 100644
--- a/chrome/browser/media/midi_permission_infobar_delegate.h
+++ b/chrome/browser/media/midi_permission_infobar_delegate.h
@@ -22,8 +22,8 @@
 // permission infobars to the user.
 class MIDIPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  // Creates a infobar delegate and adds it to |infobar_service|.
-  // Returns the delegate if it was successfully added.
+  // Creates a MIDI permission infobar delegate and adds it to
+  // |infobar_service|. Returns the delegate if it was successfully added.
   static InfoBarDelegate* Create(InfoBarService* infobar_service,
                                  PermissionQueueController* controller,
                                  const PermissionRequestID& id,
@@ -39,6 +39,7 @@
 
  private:
   // ConfirmInfoBarDelegate:
+  virtual void InfoBarDismissed() OVERRIDE;
   virtual int GetIconID() const OVERRIDE;
   virtual Type GetInfoBarType() const OVERRIDE;
   virtual bool ShouldExpireInternal(
diff --git a/chrome/browser/media/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc_browsertest_base.cc
index 7fc0723..69fc7e7 100644
--- a/chrome/browser/media/webrtc_browsertest_base.cc
+++ b/chrome/browser/media/webrtc_browsertest_base.cc
@@ -81,7 +81,7 @@
   // Request user media: this will launch the media stream info bar.
   std::string result;
   EXPECT_TRUE(content::ExecuteScriptAndExtractString(
-      tab_contents, "getUserMedia(" + constraints + ");", &result));
+      tab_contents, "doGetUserMedia(" + constraints + ");", &result));
   EXPECT_EQ("ok-requested", result);
 }
 
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
index f51a69b..2a26198 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
 
+#include <map>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/format_macros.h"
@@ -17,6 +19,8 @@
 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
 #include "chrome/common/media_galleries/itunes_library.h"
 #include "content/public/browser/browser_thread.h"
+#include "third_party/icu/source/common/unicode/locid.h"
+#include "webkit/browser/fileapi/native_file_util.h"
 
 using chrome::MediaFileSystemBackend;
 
@@ -83,6 +87,8 @@
     const FileWatchStartedCallback& watch_started_callback,
     const base::FilePathWatcher::Callback& library_changed_callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
+  // The watcher is created on the FILE thread because it is very difficult
+  // to safely pass an already-created member to a different thread.
   scoped_ptr<base::FilePathWatcher> watcher(new base::FilePathWatcher);
   bool success = watcher->Watch(
       library_path, false /*recursive*/,
@@ -94,12 +100,111 @@
       base::Bind(watch_started_callback, base::Passed(&watcher)));
 }
 
+// |result_path| is set if |locale_string| maps to a localized directory name
+// and it exists in the filesystem.
+bool CheckLocaleStringAutoAddPath(
+    const base::FilePath& media_path,
+    const std::map<std::string, std::string>& localized_dir_names,
+    const std::string& locale_string,
+    base::FilePath* result_path) {
+  DCHECK(!media_path.empty());
+  DCHECK(!localized_dir_names.empty());
+  DCHECK(!locale_string.empty());
+  DCHECK(result_path);
+
+  std::map<std::string, std::string>::const_iterator it =
+      localized_dir_names.find(locale_string);
+  if (it == localized_dir_names.end())
+    return false;
+
+  base::FilePath localized_auto_add_path =
+      media_path.Append(base::FilePath::FromUTF8Unsafe(it->second));
+  if (!fileapi::NativeFileUtil::DirectoryExists(localized_auto_add_path))
+    return false;
+
+  *result_path = localized_auto_add_path;
+  return true;
+}
+
+// This method is complex because Apple localizes the directory name in versions
+// of iTunes before 10.6.
+base::FilePath GetAutoAddPath(const base::FilePath& library_path) {
+  const char kiTunesMediaDir[] = "iTunes Media";
+  base::FilePath media_path =
+      library_path.DirName().AppendASCII(kiTunesMediaDir);
+
+  // Test 'universal' path first.
+  base::FilePath universal_auto_add_path =
+      media_path.AppendASCII("Automatically Add to iTunes.localized");
+  if (fileapi::NativeFileUtil::DirectoryExists(universal_auto_add_path))
+    return universal_auto_add_path;
+
+  // Test user locale. Localized directory names encoded in UTF-8.
+  std::map<std::string, std::string> localized_dir_names;
+  localized_dir_names["nl"] = "Voeg automatisch toe aan iTunes";
+  localized_dir_names["en"] = "Automatically Add to iTunes";
+  localized_dir_names["fr"] = "Ajouter automatiquement \xC3\xA0 iTunes";
+  localized_dir_names["de"] = "Automatisch zu iTunes hinzuf\xC3\xBCgen";
+  localized_dir_names["it"] = "Aggiungi automaticamente a iTunes";
+  localized_dir_names["ja"] = "iTunes \xE3\x81\xAB\xE8\x87\xAA\xE5\x8B\x95\xE7"
+                              "\x9A\x84\xE3\x81\xAB\xE8\xBF\xBD\xE5\x8A\xA0";
+  localized_dir_names["es"] = "A\xC3\xB1""adir autom\xC3\xA1ticamente a iTunes";
+  localized_dir_names["da"] = "F\xC3\xB8j automatisk til iTunes";
+  localized_dir_names["en-GB"] = "Automatically Add to iTunes";
+  localized_dir_names["fi"] = "Lis\xC3\xA4\xC3\xA4 automaattisesti iTunesiin";
+  localized_dir_names["ko"] = "iTunes\xEC\x97\x90 \xEC\x9E\x90\xEB\x8F\x99\xEC"
+                              "\x9C\xBC\xEB\xA1\x9C \xEC\xB6\x94\xEA\xB0\x80";
+  localized_dir_names["no"] = "Legg til automatisk i iTunes";
+  localized_dir_names["pl"] = "Automatycznie dodaj do iTunes";
+  localized_dir_names["pt"] = "Adicionar Automaticamente ao iTunes";
+  localized_dir_names["pt-PT"] = "Adicionar ao iTunes automaticamente";
+  localized_dir_names["ru"] = "\xD0\x90\xD0\xB2\xD1\x82\xD0\xBE\xD0\xBC\xD0\xB0"
+                              "\xD1\x82\xD0\xB8\xD1\x87\xD0\xB5\xD1\x81\xD0\xBA"
+                              "\xD0\xB8 \xD0\xB4\xD0\xBE\xD0\xB1\xD0\xB0\xD0"
+                              "\xB2\xD0\xBB\xD1\x8F\xD1\x82\xD1\x8C \xD0\xB2"
+                              "iTunes";
+  localized_dir_names["sv"] = "L\xC3\xA4gg automatiskt till i iTunes";
+  localized_dir_names["zh-CN"] = "\xE8\x87\xAA\xE5\x8A\xA8\xE6\xB7\xBB\xE5\x8A"
+                                 "\xA0\xE5\x88\xB0 iTunes";
+  localized_dir_names["zh-TW"] = "\xE8\x87\xAA\xE5\x8B\x95\xE5\x8A\xA0\xE5\x85"
+                                 "\xA5 iTunes";
+
+  const icu::Locale locale = icu::Locale::getDefault();
+  const char* language = locale.getLanguage();
+  const char* country = locale.getCountry();
+
+  base::FilePath result_path;
+  if (language != NULL && *language != '\0') {
+    if (country != NULL && *country != '\0' &&
+        CheckLocaleStringAutoAddPath(media_path, localized_dir_names,
+                                     std::string(language) + "-" + country,
+                                     &result_path)) {
+      return result_path;
+    }
+
+    if (CheckLocaleStringAutoAddPath(media_path, localized_dir_names,
+                                     language, &result_path)) {
+      return result_path;
+    }
+  }
+
+  // Fallback to trying English.
+  if (CheckLocaleStringAutoAddPath(media_path, localized_dir_names,
+                                   "en", &result_path)) {
+    return result_path;
+  }
+
+  return base::FilePath();
+}
+
 }  // namespace
 
 ITunesDataProvider::ITunesDataProvider(const base::FilePath& library_path)
     : library_path_(library_path),
+      auto_add_path_(GetAutoAddPath(library_path)),
       needs_refresh_(true),
-      is_valid_(false) {
+      is_valid_(false),
+      weak_factory_(this) {
   DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
   DCHECK(!library_path_.empty());
 
@@ -108,8 +213,10 @@
       FROM_HERE,
       base::Bind(StartLibraryWatchOnFileThread,
                  library_path_,
-                 base::Bind(&ITunesDataProvider::OnLibraryWatchStartedCallback),
-                 base::Bind(&ITunesDataProvider::OnLibraryChangedCallback)));
+                 base::Bind(&ITunesDataProvider::OnLibraryWatchStarted,
+                            weak_factory_.GetWeakPtr()),
+                 base::Bind(&ITunesDataProvider::OnLibraryChanged,
+                            weak_factory_.GetWeakPtr())));
 }
 
 ITunesDataProvider::~ITunesDataProvider() {}
@@ -126,7 +233,9 @@
   needs_refresh_ = false;
   xml_parser_ = new SafeITunesLibraryParser(
       library_path_,
-      base::Bind(&ITunesDataProvider::OnLibraryParsedCallback, ready_callback));
+      base::Bind(&ITunesDataProvider::OnLibraryParsed,
+                 weak_factory_.GetWeakPtr(),
+                 ready_callback));
   xml_parser_->Start();
 }
 
@@ -134,6 +243,10 @@
   return library_path_;
 }
 
+const base::FilePath& ITunesDataProvider::auto_add_path() const {
+  return auto_add_path_;
+}
+
 bool ITunesDataProvider::KnownArtist(const ArtistName& artist) const {
   DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
   DCHECK(is_valid_);
@@ -212,41 +325,6 @@
   return result;
 }
 
-// static
-void ITunesDataProvider::OnLibraryWatchStartedCallback(
-    scoped_ptr<base::FilePathWatcher> library_watcher) {
-  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
-  ITunesDataProvider* provider =
-      chrome::ImportedMediaGalleryRegistry::ITunesDataProvider();
-  if (provider)
-    provider->OnLibraryWatchStarted(library_watcher.Pass());
-}
-
-// static
-void ITunesDataProvider::OnLibraryChangedCallback(const base::FilePath& path,
-                                                  bool error) {
-  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
-  ITunesDataProvider* provider =
-      chrome::ImportedMediaGalleryRegistry::ITunesDataProvider();
-  if (provider)
-    provider->OnLibraryChanged(path, error);
-}
-
-// static
-void ITunesDataProvider::OnLibraryParsedCallback(
-    const ReadyCallback& ready_callback,
-    bool result,
-    const parser::Library& library) {
-  DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
-  ITunesDataProvider* provider =
-      chrome::ImportedMediaGalleryRegistry::ITunesDataProvider();
-  if (!provider) {
-    ready_callback.Run(false);
-    return;
-  }
-  provider->OnLibraryParsed(ready_callback, result, library);
-}
-
 void ITunesDataProvider::OnLibraryWatchStarted(
     scoped_ptr<base::FilePathWatcher> library_watcher) {
   DCHECK(MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread());
diff --git a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
index c53f552..8c4b73e 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_data_provider.h
@@ -36,11 +36,14 @@
 
   // Ask the data provider to refresh the data if necessary. |ready_callback|
   // will be called with the result; false if unable to parse the XML file.
-  void RefreshData(const ReadyCallback& ready_callback);
+  virtual void RefreshData(const ReadyCallback& ready_callback);
 
   // Get the platform path for the library XML file.
   const base::FilePath& library_path() const;
 
+  // Get the platform path for the auto-add directory.
+  virtual const base::FilePath& auto_add_path() const;
+
   // Returns true if |artist| exists in the library.
   bool KnownArtist(const ArtistName& artist) const;
 
@@ -68,17 +71,6 @@
   typedef std::map<AlbumName, Album> Artist;
   typedef std::map<ArtistName, Artist> Library;
 
-  // These are hacks to work around http://crbug.com/165590. Otherwise a
-  // WeakPtrFactory would be the obvious answer here.
-  // static so they can call their real counterparts.
-  // TODO(vandebo) Remove these when the bug is fixed.
-  static void OnLibraryWatchStartedCallback(
-      scoped_ptr<base::FilePathWatcher> library_watcher);
-  static void OnLibraryChangedCallback(const base::FilePath& path, bool error);
-  static void OnLibraryParsedCallback(const ReadyCallback& ready_callback,
-                                      bool result,
-                                      const parser::Library& library);
-
   // Called when the FilePathWatcher for |library_path_| has tried to add an
   // watch.
   void OnLibraryWatchStarted(scoped_ptr<base::FilePathWatcher> library_watcher);
@@ -94,6 +86,9 @@
   // Path to the library XML file.
   const base::FilePath library_path_;
 
+  // Path to the auto-add directory.
+  const base::FilePath auto_add_path_;
+
   // The parsed and uniquified data.
   Library library_;
 
@@ -109,6 +104,8 @@
 
   scoped_refptr<SafeITunesLibraryParser> xml_parser_;
 
+  base::WeakPtrFactory<ITunesDataProvider> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(ITunesDataProvider);
 };
 
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
index 641b382..75cc8d7 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
@@ -28,9 +28,6 @@
 
 namespace {
 
-const char kiTunesLibraryXML[] = "iTunes Music Library.xml";
-const char kiTunesMediaDir[] = "iTunes Media";
-
 base::PlatformFileError MakeDirectoryFileInfo(
     base::PlatformFileInfo* file_info) {
   base::PlatformFileInfo result;
@@ -41,51 +38,57 @@
 
 }  // namespace
 
-ItunesFileUtil::ItunesFileUtil(chrome::MediaPathFilter* media_path_filter)
+const char kITunesLibraryXML[] = "iTunes Music Library.xml";
+const char kITunesMediaDir[] = "iTunes Media";
+const char kITunesMusicDir[] = "Music";
+const char kITunesAutoAddDir[] = "Automatically Add to iTunes";
+
+ITunesFileUtil::ITunesFileUtil(chrome::MediaPathFilter* media_path_filter)
     : chrome::NativeMediaFileUtil(media_path_filter),
       weak_factory_(this),
       imported_registry_(NULL) {
 }
 
-ItunesFileUtil::~ItunesFileUtil() {
+ITunesFileUtil::~ITunesFileUtil() {
 }
 
-void ItunesFileUtil::GetFileInfoOnTaskRunnerThread(
+void ITunesFileUtil::GetFileInfoOnTaskRunnerThread(
     scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback) {
   GetDataProvider()->RefreshData(
-      base::Bind(&ItunesFileUtil::GetFileInfoWithFreshDataProvider,
+      base::Bind(&ITunesFileUtil::GetFileInfoWithFreshDataProvider,
                  weak_factory_.GetWeakPtr(), base::Passed(&context), url,
                  callback));
 }
 
-void ItunesFileUtil::ReadDirectoryOnTaskRunnerThread(
+void ITunesFileUtil::ReadDirectoryOnTaskRunnerThread(
     scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback) {
   GetDataProvider()->RefreshData(
-      base::Bind(&ItunesFileUtil::ReadDirectoryWithFreshDataProvider,
+      base::Bind(&ITunesFileUtil::ReadDirectoryWithFreshDataProvider,
                  weak_factory_.GetWeakPtr(), base::Passed(&context), url,
                  callback));
 }
 
-void ItunesFileUtil::CreateSnapshotFileOnTaskRunnerThread(
+void ITunesFileUtil::CreateSnapshotFileOnTaskRunnerThread(
     scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const CreateSnapshotFileCallback& callback) {
   GetDataProvider()->RefreshData(
-      base::Bind(&ItunesFileUtil::CreateSnapshotFileWithFreshDataProvider,
+      base::Bind(&ITunesFileUtil::CreateSnapshotFileWithFreshDataProvider,
                  weak_factory_.GetWeakPtr(), base::Passed(&context), url,
                  callback));
 }
 
 // Contents of the iTunes media gallery:
-//   /                                          - root directory
-//   /iTunes Music Library.xml                  - library xml file
-//   /iTunes Media/<Artist>/<Album>/<Track>     - tracks
+//   /                                                - root directory
+//   /iTunes Music Library.xml                        - library xml file
+//   /iTunes Media/Automatically Add to iTunes        - auto-import directory
+//   /iTunes Media/Music/<Artist>/<Album>/<Track>     - tracks
 //
-base::PlatformFileError ItunesFileUtil::GetFileInfoSync(
+base::PlatformFileError ITunesFileUtil::GetFileInfoSync(
     fileapi::FileSystemOperationContext* context,
     const fileapi::FileSystemURL& url,
     base::PlatformFileInfo* file_info,
@@ -96,7 +99,7 @@
   if (components.size() == 0)
     return MakeDirectoryFileInfo(file_info);
 
-  if (components.size() == 1 && components[0] == kiTunesLibraryXML) {
+  if (components.size() == 1 && components[0] == kITunesLibraryXML) {
     // We can't just call NativeMediaFileUtil::GetFileInfoSync() here because it
     // uses the MediaPathFilter. At this point, |library_path_| is known good
     // because GetFileInfoWithFreshDataProvider() gates access to this method.
@@ -106,42 +109,48 @@
     return fileapi::NativeFileUtil::GetFileInfo(file_path, file_info);
   }
 
-  if (components[0] != kiTunesMediaDir || components.size() > 4)
+  if (components[0] != kITunesMediaDir)
     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
 
-  switch (components.size()) {
-    case 1:
-      return MakeDirectoryFileInfo(file_info);
+  if (components[1] == kITunesAutoAddDir) {
+    if (GetDataProvider()->auto_add_path().empty())
+      return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+    return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
+                                                platform_path);
+  }
 
-    case 2:
-      if (GetDataProvider()->KnownArtist(components[1]))
+  if (components[1] == kITunesMusicDir) {
+    switch (components.size()) {
+      case 2:
         return MakeDirectoryFileInfo(file_info);
-      break;
 
-    case 3:
-      if (GetDataProvider()->KnownAlbum(components[1], components[2]))
-        return MakeDirectoryFileInfo(file_info);
-      break;
+      case 3:
+        if (GetDataProvider()->KnownArtist(components[2]))
+          return MakeDirectoryFileInfo(file_info);
+        break;
 
-    case 4: {
-      base::FilePath location =
-          GetDataProvider()->GetTrackLocation(components[1], components[2],
-                                              components[3]);
-      if (!location.empty()) {
-        return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
-                                                    platform_path);
+      case 4:
+        if (GetDataProvider()->KnownAlbum(components[2], components[3]))
+          return MakeDirectoryFileInfo(file_info);
+        break;
+
+      case 5: {
+        base::FilePath location =
+            GetDataProvider()->GetTrackLocation(components[2], components[3],
+                                                components[4]);
+         if (!location.empty()) {
+          return NativeMediaFileUtil::GetFileInfoSync(context, url, file_info,
+                                                      platform_path);
+        }
+        break;
       }
-      break;
     }
-
-    default:
-      NOTREACHED();
   }
 
   return base::PLATFORM_FILE_ERROR_NOT_FOUND;
 }
 
-base::PlatformFileError ItunesFileUtil::ReadDirectorySync(
+base::PlatformFileError ITunesFileUtil::ReadDirectorySync(
     fileapi::FileSystemOperationContext* context,
     const fileapi::FileSystemURL& url,
     EntryList* file_list) {
@@ -153,22 +162,42 @@
     base::PlatformFileInfo xml_info;
     if (!file_util::GetFileInfo(GetDataProvider()->library_path(), &xml_info))
       return base::PLATFORM_FILE_ERROR_IO;
-    file_list->push_back(DirectoryEntry(kiTunesLibraryXML,
+    file_list->push_back(DirectoryEntry(kITunesLibraryXML,
                                         DirectoryEntry::FILE,
                                         xml_info.size, xml_info.last_modified));
-    file_list->push_back(DirectoryEntry(kiTunesMediaDir,
+    file_list->push_back(DirectoryEntry(kITunesMediaDir,
                                         DirectoryEntry::DIRECTORY,
                                         0, base::Time()));
     return base::PLATFORM_FILE_OK;
   }
 
-  if (components.size() == 1 && components[0] == kiTunesLibraryXML)
+  if (components.size() == 1 && components[0] == kITunesLibraryXML)
     return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
 
-  if (components[0] != kiTunesMediaDir || components.size() > 4)
+  if (components[0] != kITunesMediaDir || components.size() > 5)
     return base::PLATFORM_FILE_ERROR_NOT_FOUND;
 
   if (components.size() == 1) {
+    if (!GetDataProvider()->auto_add_path().empty()) {
+      file_list->push_back(DirectoryEntry(kITunesAutoAddDir,
+                                          DirectoryEntry::DIRECTORY,
+                                          0, base::Time()));
+    }
+    file_list->push_back(DirectoryEntry(kITunesMusicDir,
+                                        DirectoryEntry::DIRECTORY,
+                                        0, base::Time()));
+    return base::PLATFORM_FILE_OK;
+  }
+
+  if (components[1] == kITunesAutoAddDir &&
+      !GetDataProvider()->auto_add_path().empty()) {
+    return NativeMediaFileUtil::ReadDirectorySync(context, url, file_list);
+  }
+
+  if (components[1] != kITunesMusicDir)
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+
+  if (components.size() == 2) {
     std::set<ITunesDataProvider::ArtistName> artists =
         GetDataProvider()->GetArtistNames();
     std::set<ITunesDataProvider::ArtistName>::const_iterator it;
@@ -178,9 +207,9 @@
     return base::PLATFORM_FILE_OK;
   }
 
-  if (components.size() == 2) {
+  if (components.size() == 3) {
     std::set<ITunesDataProvider::AlbumName> albums =
-        GetDataProvider()->GetAlbumNames(components[1]);
+        GetDataProvider()->GetAlbumNames(components[2]);
     if (albums.size() == 0)
       return base::PLATFORM_FILE_ERROR_NOT_FOUND;
     std::set<ITunesDataProvider::AlbumName>::const_iterator it;
@@ -190,9 +219,9 @@
     return base::PLATFORM_FILE_OK;
   }
 
-  if (components.size() == 3) {
+  if (components.size() == 4) {
     ITunesDataProvider::Album album =
-        GetDataProvider()->GetAlbum(components[1], components[2]);
+        GetDataProvider()->GetAlbum(components[2], components[3]);
     if (album.size() == 0)
       return base::PLATFORM_FILE_ERROR_NOT_FOUND;
     ITunesDataProvider::Album::const_iterator it;
@@ -219,14 +248,14 @@
   return base::PLATFORM_FILE_ERROR_NOT_FOUND;
 }
 
-base::PlatformFileError ItunesFileUtil::CreateSnapshotFileSync(
+base::PlatformFileError ITunesFileUtil::CreateSnapshotFileSync(
     fileapi::FileSystemOperationContext* context,
     const fileapi::FileSystemURL& url,
     base::PlatformFileInfo* file_info,
     base::FilePath* platform_path,
     scoped_refptr<webkit_blob::ShareableFileReference>* file_ref) {
   DCHECK(!url.path().IsAbsolute());
-  if (url.path() != base::FilePath().AppendASCII(kiTunesLibraryXML)) {
+  if (url.path() != base::FilePath().AppendASCII(kITunesLibraryXML)) {
     return NativeMediaFileUtil::CreateSnapshotFileSync(context, url, file_info,
                                                        platform_path, file_ref);
   }
@@ -241,32 +270,47 @@
   return GetFileInfoSync(context, url, file_info, platform_path);
 }
 
-base::PlatformFileError ItunesFileUtil::GetLocalFilePath(
+base::PlatformFileError ITunesFileUtil::GetLocalFilePath(
     fileapi::FileSystemOperationContext* context,
     const fileapi::FileSystemURL& url,
     base::FilePath* local_file_path) {
-  // Should only get here for files, i.e. the xml file and tracks.
   std::vector<std::string> components;
   fileapi::VirtualPath::GetComponentsUTF8Unsafe(url.path(), &components);
 
-  if (components.size() == 1 && components[0] == kiTunesLibraryXML) {
+  if (components.size() == 1 && components[0] == kITunesLibraryXML) {
     *local_file_path = GetDataProvider()->library_path();
     return base::PLATFORM_FILE_OK;
   }
 
-  if (components[0] != kiTunesMediaDir || components.size() != 4)
-    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+  if (components.size() >= 2 && components[0] == kITunesMediaDir &&
+      components[1] == kITunesAutoAddDir) {
+    *local_file_path = GetDataProvider()->auto_add_path();
+    if (local_file_path->empty())
+      return base::PLATFORM_FILE_ERROR_NOT_FOUND;
 
-  *local_file_path = GetDataProvider()->GetTrackLocation(components[1],
-                                                         components[2],
-                                                         components[3]);
+    for (size_t i = 2; i < components.size(); ++i) {
+      *local_file_path = local_file_path->Append(
+          base::FilePath::FromUTF8Unsafe(components[i]));
+    }
+    return base::PLATFORM_FILE_OK;
+  }
+
+  // Should only get here for files, i.e. the xml file and tracks.
+  if (components[0] != kITunesMediaDir || components[1] != kITunesMusicDir||
+      components.size() != 5) {
+    return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+  }
+
+  *local_file_path = GetDataProvider()->GetTrackLocation(components[2],
+                                                         components[3],
+                                                         components[4]);
   if (!local_file_path->empty())
     return base::PLATFORM_FILE_OK;
 
   return base::PLATFORM_FILE_ERROR_NOT_FOUND;
 }
 
-void ItunesFileUtil::GetFileInfoWithFreshDataProvider(
+void ITunesFileUtil::GetFileInfoWithFreshDataProvider(
     scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const GetFileInfoCallback& callback,
@@ -285,7 +329,7 @@
                                                      callback);
 }
 
-void ItunesFileUtil::ReadDirectoryWithFreshDataProvider(
+void ITunesFileUtil::ReadDirectoryWithFreshDataProvider(
     scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const ReadDirectoryCallback& callback,
@@ -304,7 +348,7 @@
                                                        callback);
 }
 
-void ItunesFileUtil::CreateSnapshotFileWithFreshDataProvider(
+void ITunesFileUtil::CreateSnapshotFileWithFreshDataProvider(
     scoped_ptr<fileapi::FileSystemOperationContext> context,
     const fileapi::FileSystemURL& url,
     const CreateSnapshotFileCallback& callback,
@@ -326,7 +370,7 @@
                                                             callback);
 }
 
-ITunesDataProvider* ItunesFileUtil::GetDataProvider() {
+ITunesDataProvider* ITunesFileUtil::GetDataProvider() {
   if (!imported_registry_)
     imported_registry_ = chrome::ImportedMediaGalleryRegistry::GetInstance();
   return imported_registry_->ITunesDataProvider();
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.h b/chrome/browser/media_galleries/fileapi/itunes_file_util.h
index 3aa75f1..5315af6 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.h
@@ -17,10 +17,15 @@
 
 class ITunesDataProvider;
 
-class ItunesFileUtil : public chrome::NativeMediaFileUtil {
+extern const char kITunesLibraryXML[];
+extern const char kITunesMediaDir[];
+extern const char kITunesMusicDir[];
+extern const char kITunesAutoAddDir[];
+
+class ITunesFileUtil : public chrome::NativeMediaFileUtil {
  public:
-  explicit ItunesFileUtil(chrome::MediaPathFilter* media_path_filter);
-  virtual ~ItunesFileUtil();
+  explicit ITunesFileUtil(chrome::MediaPathFilter* media_path_filter);
+  virtual ~ITunesFileUtil();
 
  protected:
   // NativeMediaFileUtil overrides.
@@ -73,13 +78,13 @@
       const CreateSnapshotFileCallback& callback,
       bool valid_parse);
 
-  ITunesDataProvider* GetDataProvider();
+  virtual ITunesDataProvider* GetDataProvider();
 
-  base::WeakPtrFactory<ItunesFileUtil> weak_factory_;
+  base::WeakPtrFactory<ITunesFileUtil> weak_factory_;
 
   chrome::ImportedMediaGalleryRegistry* imported_registry_;
 
-  DISALLOW_COPY_AND_ASSIGN(ItunesFileUtil);
+  DISALLOW_COPY_AND_ASSIGN(ITunesFileUtil);
 };
 
 }  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
new file mode 100644
index 0000000..c6a63c5
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util_unittest.cc
@@ -0,0 +1,346 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
+#include "chrome/browser/media_galleries/fileapi/itunes_file_util.h"
+#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
+#include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_util_adapter.h"
+#include "webkit/browser/fileapi/external_mount_points.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_operation_runner.h"
+#include "webkit/browser/fileapi/mock_file_system_options.h"
+#include "webkit/browser/quota/mock_special_storage_policy.h"
+
+using fileapi::FileSystemFileUtil;
+using fileapi::FileSystemOperationContext;
+using fileapi::FileSystemOperation;
+using fileapi::FileSystemURL;
+
+namespace itunes {
+
+namespace {
+
+void ReadDirectoryTestHelperCallback(
+    base::RunLoop* run_loop,
+    FileSystemOperation::FileEntryList* contents,
+    bool* completed, base::PlatformFileError error,
+    const FileSystemOperation::FileEntryList& file_list,
+    bool has_more) {
+  DCHECK(!*completed);
+  *completed = !has_more && error == base::PLATFORM_FILE_OK;
+  *contents = file_list;
+  run_loop->Quit();
+}
+
+void ReadDirectoryTestHelper(fileapi::FileSystemOperationRunner* runner,
+                             const FileSystemURL& url,
+                             FileSystemOperation::FileEntryList* contents,
+                             bool* completed) {
+  DCHECK(contents);
+  DCHECK(completed);
+  base::RunLoop run_loop;
+  runner->ReadDirectory(
+      url, base::Bind(&ReadDirectoryTestHelperCallback, &run_loop, contents,
+                      completed));
+  run_loop.Run();
+}
+
+}  // namespace
+
+class TestITunesDataProvider : public ITunesDataProvider {
+ public:
+  explicit TestITunesDataProvider(const base::FilePath& fake_library_path)
+     : ITunesDataProvider(fake_library_path) {
+    EXPECT_TRUE(fake_auto_add_dir_.CreateUniqueTempDir());
+  }
+
+  virtual ~TestITunesDataProvider() {}
+
+  virtual void RefreshData(const ReadyCallback& ready_callback) OVERRIDE {
+    ready_callback.Run(true /* success */);
+  }
+
+  virtual const base::FilePath& auto_add_path() const OVERRIDE {
+    return fake_auto_add_dir_.path();
+  }
+
+  void SetProvideAutoAddDir(bool provide_auto_add_dir) {
+    if (provide_auto_add_dir) {
+      if (!fake_auto_add_dir_.IsValid())
+        ASSERT_TRUE(fake_auto_add_dir_.CreateUniqueTempDir());
+    } else {
+      ASSERT_TRUE(fake_auto_add_dir_.Delete());
+    }
+  }
+
+ private:
+  base::ScopedTempDir fake_auto_add_dir_;
+};
+
+class TestITunesFileUtil : public ITunesFileUtil {
+ public:
+  explicit TestITunesFileUtil(chrome::MediaPathFilter* media_path_filter,
+                              ITunesDataProvider* data_provider)
+      : ITunesFileUtil(media_path_filter),
+        data_provider_(data_provider) {
+  }
+  virtual ~TestITunesFileUtil() {}
+
+ private:
+  virtual ITunesDataProvider* GetDataProvider() OVERRIDE {
+    return data_provider_;
+  }
+
+  ITunesDataProvider* data_provider_;
+};
+
+class TestMediaFileSystemBackend
+    : public chrome::MediaFileSystemBackend {
+ public:
+  TestMediaFileSystemBackend(const base::FilePath& profile_path,
+                             ITunesFileUtil* itunes_file_util)
+      : chrome::MediaFileSystemBackend(
+            profile_path,
+            chrome::MediaFileSystemBackend::MediaTaskRunner().get()),
+        test_file_util_(itunes_file_util) {}
+
+  virtual fileapi::AsyncFileUtil*
+  GetAsyncFileUtil(fileapi::FileSystemType type) OVERRIDE {
+    if (type != fileapi::kFileSystemTypeItunes)
+      return NULL;
+
+    return test_file_util_.get();
+  }
+
+ private:
+  scoped_ptr<fileapi::AsyncFileUtil> test_file_util_;
+};
+
+class ItunesFileUtilTest : public testing::Test {
+ public:
+  ItunesFileUtilTest()
+      : io_thread_(content::BrowserThread::IO, &message_loop_) {
+  }
+  virtual ~ItunesFileUtilTest() {}
+
+  void SetUpDataProvider() {
+    ASSERT_TRUE(fake_library_dir_.CreateUniqueTempDir());
+    ASSERT_EQ(
+        0,
+        file_util::WriteFile(
+            fake_library_dir_.path().AppendASCII(kITunesLibraryXML),
+            NULL,
+            0));
+
+    itunes_data_provider_.reset(
+        new TestITunesDataProvider(fake_library_dir_.path()));
+  }
+
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
+
+    scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
+        new quota::MockSpecialStoragePolicy();
+
+    // Initialize fake ItunesDataProvider on media task runner thread.
+    chrome::MediaFileSystemBackend::MediaTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&ItunesFileUtilTest::SetUpDataProvider,
+                   base::Unretained(this)));
+    base::WaitableEvent event(true, false /* initially_signalled */);
+    chrome::MediaFileSystemBackend::MediaTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
+    event.Wait();
+
+    media_path_filter_.reset(new chrome::MediaPathFilter());
+    ScopedVector<fileapi::FileSystemBackend> additional_providers;
+    additional_providers.push_back(new TestMediaFileSystemBackend(
+        profile_dir_.path(),
+        new TestITunesFileUtil(media_path_filter_.get(),
+                               itunes_data_provider_.get())));
+
+    file_system_context_ = new fileapi::FileSystemContext(
+        base::MessageLoopProxy::current().get(),
+        base::MessageLoopProxy::current().get(),
+        fileapi::ExternalMountPoints::CreateRefCounted().get(),
+        storage_policy.get(),
+        NULL,
+        additional_providers.Pass(),
+        profile_dir_.path(),
+        fileapi::CreateAllowFileAccessOptions());
+  }
+
+ protected:
+  void TestNonexistentFolder(const std::string& path_append) {
+    FileSystemOperation::FileEntryList contents;
+    FileSystemURL url = CreateURL(path_append);
+    bool completed = false;
+    ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+
+    ASSERT_FALSE(completed);
+  }
+
+  FileSystemURL CreateURL(const std::string& virtual_path) const {
+    return file_system_context_->CreateCrackedFileSystemURL(
+        GURL("http://www.example.com"), fileapi::kFileSystemTypeItunes,
+        base::FilePath::FromUTF8Unsafe(virtual_path));
+  }
+
+  fileapi::FileSystemOperationRunner* operation_runner() const {
+    return file_system_context_->operation_runner();
+  }
+
+  scoped_refptr<fileapi::FileSystemContext> file_system_context() const {
+    return file_system_context_;
+  }
+
+  TestITunesDataProvider* data_provider() const {
+    return itunes_data_provider_.get();
+  }
+
+ private:
+  base::MessageLoop message_loop_;
+  content::TestBrowserThread io_thread_;
+
+  base::ScopedTempDir profile_dir_;
+  base::ScopedTempDir fake_library_dir_;
+
+  scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+  scoped_ptr<chrome::MediaPathFilter> media_path_filter_;
+  scoped_ptr<TestITunesDataProvider> itunes_data_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(ItunesFileUtilTest);
+};
+
+TEST_F(ItunesFileUtilTest, RootContents) {
+  FileSystemOperation::FileEntryList contents;
+  FileSystemURL url = CreateURL("");
+  bool completed = false;
+  ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+
+  ASSERT_TRUE(completed);
+  ASSERT_EQ(2u, contents.size());
+
+  EXPECT_FALSE(contents.front().is_directory);
+  EXPECT_TRUE(contents.back().is_directory);
+
+  EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesLibraryXML).value(),
+            contents.front().name);
+  EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMediaDir).value(),
+            contents.back().name);
+}
+
+TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsNoAutoAdd) {
+  data_provider()->SetProvideAutoAddDir(false);
+
+  FileSystemOperation::FileEntryList contents;
+  FileSystemURL url = CreateURL(kITunesMediaDir);
+  bool completed = false;
+  ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+
+  ASSERT_TRUE(completed);
+  ASSERT_EQ(1u, contents.size());
+
+  EXPECT_TRUE(contents.front().is_directory);
+  EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(),
+            contents.back().name);
+}
+
+TEST_F(ItunesFileUtilTest, ItunesMediaDirectoryContentsAutoAdd) {
+  data_provider()->SetProvideAutoAddDir(true);
+
+  FileSystemOperation::FileEntryList contents;
+  FileSystemURL url = CreateURL(kITunesMediaDir);
+  bool completed = false;
+  ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+
+  ASSERT_TRUE(completed);
+  ASSERT_EQ(2u, contents.size());
+
+  EXPECT_TRUE(contents.front().is_directory);
+  EXPECT_TRUE(contents.back().is_directory);
+
+  EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesAutoAddDir).value(),
+            contents.front().name);
+  EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kITunesMusicDir).value(),
+            contents.back().name);
+}
+
+TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerate) {
+  data_provider()->SetProvideAutoAddDir(true);
+  ASSERT_EQ(0, file_util::WriteFile(
+      data_provider()->auto_add_path().AppendASCII("baz.ogg"), NULL, 0));
+
+  FileSystemOperation::FileEntryList contents;
+  FileSystemURL url = CreateURL(
+      std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir);
+  bool completed = false;
+
+  ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+  ASSERT_TRUE(completed);
+  ASSERT_EQ(1u, contents.size());
+  EXPECT_FALSE(contents.front().is_directory);
+  EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(),
+            contents.front().name);
+}
+
+TEST_F(ItunesFileUtilTest, ItunesAutoAddDirEnumerateNested) {
+  data_provider()->SetProvideAutoAddDir(true);
+  base::FilePath nested_dir =
+      data_provider()->auto_add_path().AppendASCII("foo").AppendASCII("bar");
+  ASSERT_TRUE(file_util::CreateDirectory(nested_dir));
+  ASSERT_EQ(0,
+            file_util::WriteFile(nested_dir.AppendASCII("baz.ogg"), NULL, 0));
+
+  FileSystemOperation::FileEntryList contents;
+  FileSystemURL url = CreateURL(
+      std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir);
+  bool completed = false;
+
+  ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+  ASSERT_TRUE(completed);
+  ASSERT_EQ(1u, contents.size());
+  EXPECT_TRUE(contents.front().is_directory);
+  EXPECT_EQ(base::FilePath().AppendASCII("foo").value(), contents.front().name);
+
+  contents.clear();
+  url = CreateURL(
+      std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo");
+  completed = false;
+  ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+  ASSERT_TRUE(completed);
+  ASSERT_EQ(1u, contents.size());
+  EXPECT_TRUE(contents.front().is_directory);
+  EXPECT_EQ(base::FilePath().AppendASCII("bar").value(), contents.front().name);
+
+  contents.clear();
+  url = CreateURL(
+      std::string(kITunesMediaDir) + "/" + kITunesAutoAddDir + "/foo/bar");
+  completed = false;
+  ReadDirectoryTestHelper(operation_runner(), url, &contents, &completed);
+  ASSERT_TRUE(completed);
+  ASSERT_EQ(1u, contents.size());
+  EXPECT_FALSE(contents.front().is_directory);
+  EXPECT_EQ(base::FilePath().AppendASCII("baz.ogg").value(),
+            contents.front().name);
+}
+
+}  // namespace itunes
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
index cf0bc26..102179d 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "webkit/browser/blob/local_file_stream_reader.h"
-#include "webkit/browser/fileapi/async_file_util_adapter.h"
 #include "webkit/browser/fileapi/copy_or_move_file_validator.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_file_stream_reader.h"
@@ -59,7 +58,7 @@
 #if defined(OS_WIN) || defined(OS_MACOSX)
       ,
       picasa_file_util_(new picasa::PicasaFileUtil(media_path_filter_.get())),
-      itunes_file_util_(new itunes::ItunesFileUtil(media_path_filter_.get()))
+      itunes_file_util_(new itunes::ITunesFileUtil(media_path_filter_.get()))
 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
 {
 }
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.h b/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
index c3b989b..c14695e 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
@@ -13,10 +13,6 @@
 class SequencedTaskRunner;
 }
 
-namespace fileapi {
-class AsyncFileUtilAdapter;
-}
-
 namespace chrome {
 
 class MediaPathFilter;
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 18b974f..129a3c1 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_map_service.h
@@ -16,15 +16,11 @@
 class MTPDeviceAsyncDelegate;
 
 // This class provides media transfer protocol (MTP) device delegate to
-// complete media file system operations. ScopedMTPDeviceMapEntry class
-// manages the device map entries.
+// complete media file system operations.
 class MTPDeviceMapService {
  public:
   static MTPDeviceMapService* GetInstance();
 
-  /////////////////////////////////////////////////////////////////////////////
-  //   Following methods are used to manage MTPDeviceAsyncDelegate objects.  //
-  /////////////////////////////////////////////////////////////////////////////
   // Adds the MTP device delegate to the map service. |device_location|
   // specifies the mount location of the MTP device.
   // Called on the IO thread.
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
index 3543759..5704be1 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
@@ -195,6 +195,17 @@
     delegate_ = new chrome::MTPDeviceDelegateImplMac(kDeviceId, kDevicePath);
   }
 
+  virtual void TearDown() OVERRIDE {
+    id<ICDeviceBrowserDelegate> delegate = manager_.device_browser();
+    [delegate deviceBrowser:nil didRemoveDevice:camera_ moreGoing:NO];
+
+    delegate_->CancelPendingTasksAndDeleteDelegate();
+
+    chrome::test::TestStorageMonitor::RemoveSingleton();
+
+    io_thread_->Stop();
+  }
+
   void OnError(base::WaitableEvent* event, base::PlatformFileError error) {
     error_ = error;
     event->Signal();
@@ -290,15 +301,6 @@
     return error_;
   }
 
-  virtual void TearDown() OVERRIDE {
-    id<ICDeviceBrowserDelegate> delegate = manager_.device_browser();
-    [delegate deviceBrowser:nil didRemoveDevice:camera_ moreGoing:NO];
-
-    delegate_->CancelPendingTasksAndDeleteDelegate();
-
-    io_thread_->Stop();
-  }
-
  protected:
   base::MessageLoopForUI message_loop_;
   // Note: threads must be made in this order: UI > FILE > IO
diff --git a/chrome/browser/media_galleries/media_file_system_registry.cc b/chrome/browser/media_galleries/media_file_system_registry.cc
index 232f89b..9f57566 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
 #include "chrome/browser/media_galleries/media_file_system_context.h"
 #include "chrome/browser/media_galleries/media_galleries_dialog_controller.h"
@@ -31,6 +32,7 @@
 #include "chrome/common/extensions/extension_set.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_details.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -57,6 +59,24 @@
   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)));
+}
+
 }  // namespace
 
 MediaFileSystemInfo::MediaFileSystemInfo(const string16& fs_name,
@@ -150,6 +170,10 @@
         break;
       }
       case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
+        content::LoadCommittedDetails* load_details =
+            content::Details<content::LoadCommittedDetails>(details).ptr();
+        if (load_details->is_in_page)
+          break;
         NavigationController* controller =
             content::Source<NavigationController>(source).ptr();
         WebContents* contents = controller->GetWebContents();
@@ -243,11 +267,9 @@
          ++it) {
       old_galleries.insert(it->first);
     }
-    MediaGalleryPrefIdSet invalid_galleries;
-    std::set_difference(old_galleries.begin(), old_galleries.end(),
-                        new_galleries.begin(), new_galleries.end(),
-                        std::inserter(invalid_galleries,
-                                      invalid_galleries.begin()));
+    MediaGalleryPrefIdSet invalid_galleries =
+        base::STLSetDifference<MediaGalleryPrefIdSet>(old_galleries,
+                                                      new_galleries);
     for (MediaGalleryPrefIdSet::const_iterator it = invalid_galleries.begin();
          it != invalid_galleries.end();
          ++it) {
@@ -678,13 +700,20 @@
           base::Bind(&MediaFileSystemRegistry::RemoveScopedMTPDeviceMapEntry,
                      base::Unretained(this),
                      device_location));
-  mtp_device_host->Init();
+  InitMTPDeviceAsyncDelegate(device_location);
   mtp_device_delegate_map_[device_location] = mtp_device_host.get();
   return mtp_device_host;
 }
 
 void MediaFileSystemRegistry::RemoveScopedMTPDeviceMapEntry(
     const base::FilePath::StringType& device_location) {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&MTPDeviceMapService::RemoveAsyncDelegate,
+                 base::Unretained(MTPDeviceMapService::GetInstance()),
+                 device_location));
+
   MTPDeviceDelegateMap::iterator delegate_it =
       mtp_device_delegate_map_.find(device_location);
   DCHECK(delegate_it != mtp_device_delegate_map_.end());
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 d1d96c7..ce95d3e 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -770,6 +770,7 @@
   MediaFileSystemRegistry* registry =
       g_browser_process->media_file_system_registry();
   EXPECT_EQ(0U, GetExtensionGalleriesHostCount(registry));
+  test::TestStorageMonitor::RemoveSingleton();
 #if defined(OS_CHROMEOS)
   test_user_manager_.reset();
 #endif
diff --git a/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc b/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc
index a5ae6ba..71f54ed 100644
--- a/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_dialog_controller_unittest.cc
@@ -61,6 +61,7 @@
 
   gallery.path = base::FilePath(FILE_PATH_LITERAL("sub/path"));
   EXPECT_EQ("path - 977 KB vendor, model", GalleryName(gallery));
+  test::TestStorageMonitor::RemoveSingleton();
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/media_galleries/media_galleries_permissions_unittest.cc b/chrome/browser/media_galleries/media_galleries_permissions_unittest.cc
index 4b9079c..0721556 100644
--- a/chrome/browser/media_galleries/media_galleries_permissions_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_permissions_unittest.cc
@@ -48,6 +48,8 @@
     prefs_.pref_service()->CommitPendingWrite();
     message_loop_.RunUntilIdle();
 
+    test::TestStorageMonitor::RemoveSingleton();
+
     testing::Test::TearDown();
   }
 
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.cc b/chrome/browser/media_galleries/media_galleries_preferences.cc
index cf64556..016d85c 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences.cc
@@ -14,7 +14,6 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_api.h"
-#include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/media_galleries/fileapi/itunes_finder.h"
@@ -924,7 +923,7 @@
     MediaGalleryPrefId gallery_id) {
   ExtensionPrefs* prefs = GetExtensionPrefs();
   const DictionaryValue* extensions =
-      prefs->pref_service()->GetDictionary(ExtensionPrefs::kExtensionsPref);
+      prefs->pref_service()->GetDictionary(prefs::kExtensionsPref);
   if (!extensions)
     return;
 
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
index e36df44..68edbd9 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -119,6 +119,7 @@
 
   virtual void TearDown() OVERRIDE {
     Verify();
+    test::TestStorageMonitor::RemoveSingleton();
   }
 
   void Verify() {
@@ -844,6 +845,8 @@
       StorageInfo::FIXED_MASS_STORAGE, "unique");
   EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("unique")).AsUTF8Unsafe(),
             UTF16ToUTF8(info.GetGalleryTooltip()));
+
+  test::TestStorageMonitor::RemoveSingleton();
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index 0f01e1e..c2a510d 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chrome {
@@ -25,12 +25,12 @@
     const std::vector<std::string>& media_galleries_permissions,
     Profile* profile) {
   scoped_ptr<DictionaryValue> manifest(new DictionaryValue);
-  manifest->SetString(extension_manifest_keys::kName, name);
-  manifest->SetString(extension_manifest_keys::kVersion, "0.1");
-  manifest->SetInteger(extension_manifest_keys::kManifestVersion, 2);
+  manifest->SetString(extensions::manifest_keys::kName, name);
+  manifest->SetString(extensions::manifest_keys::kVersion, "0.1");
+  manifest->SetInteger(extensions::manifest_keys::kManifestVersion, 2);
   ListValue* background_script_list = new ListValue;
   background_script_list->Append(Value::CreateStringValue("background.js"));
-  manifest->Set(extension_manifest_keys::kPlatformAppBackgroundScripts,
+  manifest->Set(extensions::manifest_keys::kPlatformAppBackgroundScripts,
                 background_script_list);
 
   ListValue* permission_detail_list = new ListValue;
@@ -41,7 +41,7 @@
   media_galleries_permission->Set("mediaGalleries", permission_detail_list);
   ListValue* permission_list = new ListValue;
   permission_list->Append(media_galleries_permission);
-  manifest->Set(extension_manifest_keys::kPermissions, permission_list);
+  manifest->Set(extensions::manifest_keys::kPermissions, permission_list);
 
   extensions::ExtensionPrefs* extension_prefs =
       extensions::ExtensionPrefs::Get(profile);
diff --git a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
index c29d4ae..822fb03 100644
--- a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
+++ b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.cc
@@ -4,33 +4,8 @@
 
 #include "chrome/browser/media_galleries/scoped_mtp_device_map_entry.h"
 
-#include "base/bind.h"
-#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
-#include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
-#include "chrome/browser/media_galleries/mtp_device_delegate_impl.h"
-#include "content/public/browser/browser_thread.h"
-
 namespace chrome {
 
-namespace {
-
-void OnDeviceAsyncDelegateDestroyed(
-    const base::FilePath::StringType& device_location) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  MTPDeviceMapService::GetInstance()->RemoveAsyncDelegate(
-      device_location);
-}
-
-void RemoveDeviceDelegate(const base::FilePath::StringType& device_location) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&OnDeviceAsyncDelegateDestroyed, device_location));
-}
-
-}  // namespace
-
 ScopedMTPDeviceMapEntry::ScopedMTPDeviceMapEntry(
     const base::FilePath::StringType& device_location,
     const base::Closure& on_destruction_callback)
@@ -38,28 +13,8 @@
       on_destruction_callback_(on_destruction_callback) {
 }
 
-void ScopedMTPDeviceMapEntry::Init() {
-  CreateMTPDeviceAsyncDelegateCallback callback =
-      base::Bind(&ScopedMTPDeviceMapEntry::OnMTPDeviceAsyncDelegateCreated,
-                 this);
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(&CreateMTPDeviceAsyncDelegate,
-                 device_location_,
-                 callback));
-}
-
 ScopedMTPDeviceMapEntry::~ScopedMTPDeviceMapEntry() {
-  RemoveDeviceDelegate(device_location_);
   on_destruction_callback_.Run();
 }
 
-void ScopedMTPDeviceMapEntry::OnMTPDeviceAsyncDelegateCreated(
-    MTPDeviceAsyncDelegate* delegate) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  MTPDeviceMapService::GetInstance()->AddAsyncDelegate(
-      device_location_, delegate);
-}
-
 }  // namespace chrome
diff --git a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
index abcf042..ffb6f55 100644
--- a/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
+++ b/chrome/browser/media_galleries/scoped_mtp_device_map_entry.h
@@ -2,10 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// ScopedMTPDeviceMapEntry manages the lifetime of a MTPDeviceAsyncDelegate.
-// Each extension that uses a device holds a reference to the device's
-// ScopedMTPDeviceMapEntry.
-
 #ifndef CHROME_BROWSER_MEDIA_GALLERIES_SCOPED_MTP_DEVICE_MAP_ENTRY_H_
 #define CHROME_BROWSER_MEDIA_GALLERIES_SCOPED_MTP_DEVICE_MAP_ENTRY_H_
 
@@ -19,6 +15,13 @@
 
 class MTPDeviceAsyncDelegate;
 
+// ScopedMTPDeviceMapEntry manages the reference count on a particular
+// MTP device location. These objects are held reference counted in
+// the ExtensionGalleriesHost objects. When a particular location is
+// destroyed, the constructor-time callback tells the MediaFileSystemRegistry
+// to erase it from the system-wide map, and it is also removed from
+// the MTPServiceMap at that point.
+// TODO(gbillock): Move this to media_file_system_registry.
 class ScopedMTPDeviceMapEntry
     : public base::RefCountedThreadSafe<
           ScopedMTPDeviceMapEntry, content::BrowserThread::DeleteOnUIThread> {
@@ -29,9 +32,6 @@
   ScopedMTPDeviceMapEntry(const base::FilePath::StringType& device_location,
                           const base::Closure& on_destruction_callback);
 
-  // Most be called after creating the ScopedMTPDeviceMapEntry.
-  void Init();
-
  private:
   // Friend declarations for ref counted implementation.
   friend struct content::BrowserThread::DeleteOnThread<
@@ -46,10 +46,6 @@
   // Destroyed on the UI thread.
   ~ScopedMTPDeviceMapEntry();
 
-  // Callback to add the managed MTPDeviceAsyncDelegate to the
-  // MTPDeviceMapService on the IO thread.
-  void OnMTPDeviceAsyncDelegateCreated(MTPDeviceAsyncDelegate* delegate);
-
   // The MTP or PTP device location.
   const base::FilePath::StringType device_location_;
 
diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc
index 5c6a8e2..dfbcbdf 100644
--- a/chrome/browser/metrics/metrics_service.cc
+++ b/chrome/browser/metrics/metrics_service.cc
@@ -192,6 +192,7 @@
 #include "chrome/browser/ui/browser_otr_state.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/common/child_process_logging.h"
+#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_result_codes.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/metrics/caching_permuted_entropy_provider.h"
@@ -225,6 +226,7 @@
 
 #if defined(OS_WIN)
 #include <windows.h>  // Needed for STATUS_* codes
+#include "base/win/registry.h"
 #endif
 
 using base::Time;
@@ -793,6 +795,34 @@
     IncrementPrefValue(prefs::kStabilityDebuggerPresent);
 }
 
+#if defined(OS_WIN)
+void MetricsService::CountBrowserCrashDumpAttempts() {
+  base::string16 key_str(chrome::kBrowserCrashDumpAttemptsRegistryPath);
+  key_str += L"\\";
+  key_str += UTF8ToWide(chrome::kChromeVersion);
+
+  base::win::RegKey regkey;
+  if (regkey.Open(HKEY_CURRENT_USER,
+                  key_str.c_str(),
+                  KEY_ALL_ACCESS) != ERROR_SUCCESS) {
+    return;
+  }
+
+  base::string16 temp_name;
+  DWORD temp_value = 0;
+  int crash_dump_attempts = 0;
+  for (int i = regkey.GetValueCount() - 1; i >= 0; --i) {
+    if (regkey.GetValueNameAt(i, &temp_name) == ERROR_SUCCESS &&
+        regkey.ReadValueDW(temp_name.c_str(), &temp_value) == ERROR_SUCCESS) {
+      regkey.DeleteValue(temp_name.c_str());
+      if (temp_value != 0)
+        ++crash_dump_attempts;
+    }
+  }
+  UMA_HISTOGRAM_COUNTS("Chrome.BrowserCrashDumpAttempts", crash_dump_attempts);
+}
+#endif  // defined(OS_WIN)
+
 //------------------------------------------------------------------------------
 // private methods
 //------------------------------------------------------------------------------
@@ -842,6 +872,10 @@
     pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
   }
 
+#if defined(OS_WIN)
+  CountBrowserCrashDumpAttempts();
+#endif  // defined(OS_WIN)
+
   if (!pref->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
     IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
     // This is marked false when we get a WM_ENDSESSION.
diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h
index 27437ec..a35da3d 100644
--- a/chrome/browser/metrics/metrics_service.h
+++ b/chrome/browser/metrics/metrics_service.h
@@ -171,6 +171,12 @@
   // This count is eventually send via UMA logs.
   void RecordBreakpadHasDebugger(bool has_debugger);
 
+#if defined(OS_WIN)
+  // Counts (and removes) the browser crash dump attempt signals left behind by
+  // any previous browser processes which generated a crash dump.
+  void CountBrowserCrashDumpAttempts();
+#endif  // OS_WIN
+
   // Save any unsent logs into a persistent store in a pref.  We always do this
   // at shutdown, but we can do it as we reduce the list as well.
   void StoreUnsentLogs();
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 4a14015..9e26a11 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -901,10 +901,8 @@
 void StartupTimeBomb::Arm(const base::TimeDelta& duration) {
   DCHECK_EQ(thread_id_, base::PlatformThread::CurrentId());
   DCHECK(!startup_watchdog_);
-  // TODO(rtenneti): http://crbug.com/112970. Don't arm the startup timebomb
-  // until we fix breakpad code not to crash in logging::DumpWithoutCrashing().
-  // startup_watchdog_ = new StartupWatchDogThread(duration);
-  // startup_watchdog_->Arm();
+  startup_watchdog_ = new StartupWatchDogThread(duration);
+  startup_watchdog_->Arm();
   return;
 }
 
diff --git a/chrome/browser/metrics/variations/variations_http_header_provider.cc b/chrome/browser/metrics/variations/variations_http_header_provider.cc
index f4ed100..7be3775 100644
--- a/chrome/browser/metrics/variations/variations_http_header_provider.cc
+++ b/chrome/browser/metrics/variations/variations_http_header_provider.cc
@@ -156,7 +156,7 @@
   }
 
   // The below mirrors logic in IsGoogleDomainUrl(), but for youtube.<TLD>.
-  if (!url.is_valid() || !(url.SchemeIs("http") || url.SchemeIs("https")))
+  if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS())
     return false;
 
   const std::string host = url.host();
diff --git a/chrome/browser/metrics/variations/variations_http_header_provider.h b/chrome/browser/metrics/variations/variations_http_header_provider.h
index 2454149..06b8c69 100644
--- a/chrome/browser/metrics/variations/variations_http_header_provider.h
+++ b/chrome/browser/metrics/variations/variations_http_header_provider.h
@@ -12,7 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/synchronization/lock.h"
-#include "chrome/common/metrics/variations/variation_ids.h"
+#include "chrome/common/metrics/variations/variations_associated_data.h"
 
 namespace content {
 class ResourceContext;
diff --git a/chrome/browser/nacl_host/nacl_browser.cc b/chrome/browser/nacl_host/nacl_browser.cc
index 8460124..0f461b8 100644
--- a/chrome/browser/nacl_host/nacl_browser.cc
+++ b/chrome/browser/nacl_host/nacl_browser.cc
@@ -12,6 +12,7 @@
 #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"
@@ -112,6 +113,10 @@
   UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX);
 }
 
+// Crash throttling parameters.
+const size_t kMaxCrashesPerInterval = 3;
+const int64 kCrashesIntervalInSeconds = 120;
+
 }  // namespace
 
 namespace nacl {
@@ -576,3 +581,21 @@
   }
   validation_cache_is_modified_ = false;
 }
+
+void NaClBrowser::OnProcessCrashed() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+  if (crash_times_.size() == kMaxCrashesPerInterval) {
+    crash_times_.pop_front();
+  }
+  base::Time time = base::Time::Now();
+  crash_times_.push_back(time);
+}
+
+bool NaClBrowser::IsThrottled() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+  if (crash_times_.size() != kMaxCrashesPerInterval) {
+    return false;
+  }
+  base::TimeDelta delta = base::Time::Now() - crash_times_.front();
+  return delta.InSeconds() <= kCrashesIntervalInSeconds;
+}
diff --git a/chrome/browser/nacl_host/nacl_browser.h b/chrome/browser/nacl_host/nacl_browser.h
index f9c6d9c..14263b7 100644
--- a/chrome/browser/nacl_host/nacl_browser.h
+++ b/chrome/browser/nacl_host/nacl_browser.h
@@ -5,12 +5,15 @@
 #ifndef CHROME_BROWSER_NACL_HOST_NACL_BROWSER_H_
 #define CHROME_BROWSER_NACL_HOST_NACL_BROWSER_H_
 
+#include <deque>
+
 #include "base/bind.h"
 #include "base/containers/mru_cache.h"
 #include "base/files/file_util_proxy.h"
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
 #include "base/platform_file.h"
+#include "base/time/time.h"
 #include "chrome/browser/nacl_host/nacl_validation_cache.h"
 #include "components/nacl/common/nacl_browser_delegate.h"
 
@@ -119,6 +122,14 @@
   void EarlyStartup();
   static void SetDelegate(NaClBrowserDelegate* delegate);
   static NaClBrowserDelegate* GetDelegate();
+
+  // Support for NaCl crash throttling.
+  // Each time a NaCl module crashes, the browser is notified.
+  void OnProcessCrashed();
+  // If "too many" crashes occur within a given time period, NaCl is throttled
+  // until the rate again drops below the threshold.
+  bool IsThrottled();
+
  private:
   friend struct DefaultSingletonTraits<NaClBrowser>;
 
@@ -177,6 +188,9 @@
   std::vector<base::Closure> waiting_;
 
   scoped_ptr<NaClBrowserDelegate> browser_delegate_;
+
+  std::deque<base::Time> crash_times_;
+
   DISALLOW_COPY_AND_ASSIGN(NaClBrowser);
 };
 
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.cc b/chrome/browser/nacl_host/nacl_host_message_filter.cc
index 784f9f9..c90ccbb 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.cc
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.cc
@@ -92,6 +92,7 @@
       launch_params.uses_irt,
       launch_params.enable_dyncode_syscalls,
       launch_params.enable_exception_handling,
+      launch_params.enable_crash_throttling,
       off_the_record_,
       profile_directory_);
   base::FilePath manifest_url =
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index c915a5f..1b4243d 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
 #include "base/process/process_iterator.h"
+#include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -25,6 +26,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/nacl_host/nacl_browser.h"
 #include "chrome/browser/nacl_host/nacl_host_message_filter.h"
+#include "chrome/common/chrome_switches.h"
 #include "components/nacl/common/nacl_browser_delegate.h"
 #include "components/nacl/common/nacl_cmd_line.h"
 #include "components/nacl/common/nacl_host_messages.h"
@@ -67,6 +69,56 @@
 using content::ChildProcessHost;
 using ppapi::proxy::SerializedHandle;
 
+#if defined(OS_WIN)
+
+namespace {
+
+// Looks for the largest contiguous unallocated region of address
+// space and returns it via |*out_addr| and |*out_size|.
+void FindAddressSpace(base::ProcessHandle process,
+                      char** out_addr, size_t* out_size) {
+  *out_addr = NULL;
+  *out_size = 0;
+  char* addr = 0;
+  while (true) {
+    MEMORY_BASIC_INFORMATION info;
+    size_t result = VirtualQueryEx(process, static_cast<void*>(addr),
+                                   &info, sizeof(info));
+    if (result < sizeof(info))
+      break;
+    if (info.State == MEM_FREE && info.RegionSize > *out_size) {
+      *out_addr = addr;
+      *out_size = info.RegionSize;
+    }
+    addr += info.RegionSize;
+  }
+}
+
+}  // namespace
+
+namespace nacl {
+
+// Allocates |size| bytes of address space in the given process at a
+// randomised address.
+void* AllocateAddressSpaceASLR(base::ProcessHandle process, size_t size) {
+  char* addr;
+  size_t avail_size;
+  FindAddressSpace(process, &addr, &avail_size);
+  if (avail_size < size)
+    return NULL;
+  size_t offset = base::RandGenerator(avail_size - size);
+  const int kPageSize = 0x10000;
+  void* request_addr =
+      reinterpret_cast<void*>(reinterpret_cast<uint64>(addr + offset)
+                              & ~(kPageSize - 1));
+  return VirtualAllocEx(process, request_addr, size,
+                        MEM_RESERVE, PAGE_NOACCESS);
+}
+
+}  // namespace nacl
+
+#endif  // defined(OS_WIN)
+
 namespace {
 
 #if defined(OS_WIN)
@@ -83,23 +135,16 @@
   virtual ~NaClSandboxedProcessLauncherDelegate() {}
 
   virtual void PostSpawnTarget(base::ProcessHandle process) {
-#if !defined(NACL_WIN64)
     // For Native Client sel_ldr processes on 32-bit Windows, reserve 1 GB of
     // address space to prevent later failure due to address space fragmentation
     // from .dll loading. The NaCl process will attempt to locate this space by
     // scanning the address space using VirtualQuery.
     // TODO(bbudge) Handle the --no-sandbox case.
     // http://code.google.com/p/nativeclient/issues/detail?id=2131
-    const SIZE_T kOneGigabyte = 1 << 30;
-    void* nacl_mem = VirtualAllocEx(process,
-                                    NULL,
-                                    kOneGigabyte,
-                                    MEM_RESERVE,
-                                    PAGE_NOACCESS);
-    if (!nacl_mem) {
+    const SIZE_T kNaClSandboxSize = 1 << 30;
+    if (!nacl::AllocateAddressSpaceASLR(process, kNaClSandboxSize)) {
       DLOG(WARNING) << "Failed to reserve address space for Native Client";
     }
-#endif  // !defined(NACL_WIN64)
   }
 };
 
@@ -181,6 +226,7 @@
                                  bool uses_irt,
                                  bool enable_dyncode_syscalls,
                                  bool enable_exception_handling,
+                                 bool enable_crash_throttling,
                                  bool off_the_record,
                                  const base::FilePath& profile_directory)
     : manifest_url_(manifest_url),
@@ -198,6 +244,7 @@
       enable_debug_stub_(false),
       enable_dyncode_syscalls_(enable_dyncode_syscalls),
       enable_exception_handling_(enable_exception_handling),
+      enable_crash_throttling_(enable_crash_throttling),
       off_the_record_(off_the_record),
       profile_directory_(profile_directory),
       ipc_plugin_listener_(this),
@@ -252,6 +299,14 @@
 #endif
 }
 
+void NaClProcessHost::OnProcessCrashed(int exit_status) {
+  if (enable_crash_throttling_ &&
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisablePnaclCrashThrottling)) {
+    NaClBrowser::GetInstance()->OnProcessCrashed();
+  }
+}
+
 // This is called at browser startup.
 // static
 void NaClProcessHost::EarlyStartup(NaClBrowserDelegate* delegate) {
@@ -284,6 +339,18 @@
   reply_msg_ = reply_msg;
   manifest_path_ = manifest_path;
 
+  // Do not launch the requested NaCl module if NaCl is marked "unstable" due
+  // to too many crashes within a given time period.
+  if (enable_crash_throttling_ &&
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisablePnaclCrashThrottling) &&
+      NaClBrowser::GetInstance()->IsThrottled()) {
+    SendErrorToRenderer("Process creation was throttled due to excessive"
+                        " crashes");
+    delete this;
+    return;
+  }
+
   const CommandLine* cmd = CommandLine::ForCurrentProcess();
 #if defined(OS_WIN)
   if (cmd->HasSwitch(switches::kEnableNaClDebug) &&
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
index f2133a1..e802680 100644
--- a/chrome/browser/nacl_host/nacl_process_host.h
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -35,6 +35,10 @@
 class ChannelProxy;
 }
 
+namespace nacl {
+void* AllocateAddressSpaceASLR(base::ProcessHandle process, size_t size);
+}
+
 // Represents the browser side of the browser <--> NaCl communication
 // channel. There will be one NaClProcessHost per NaCl process
 // The browser is responsible for starting the NaCl process
@@ -47,6 +51,15 @@
   // executed.
   // render_view_id: RenderView routing id, to control access to private APIs.
   // permission_bits: controls which interfaces the NaCl plugin can use.
+  // uses_irt: whether the launched process should use the IRT.
+  // enable_dyncode_syscalls: whether the launched process should allow dyncode
+  //                          and mmap with PROT_EXEC.
+  // enable_exception_handling: whether the launched process should allow
+  //                            hardware exception handling.
+  // enable_crash_throttling: whether a crash of this process contributes
+  //                          to the crash throttling statistics, and also
+  //                          whether this process should not start when too
+  //                          many crashes have been observed.
   // off_the_record: was the process launched from an incognito renderer?
   // profile_directory: is the path of current profile directory.
   NaClProcessHost(const GURL& manifest_url,
@@ -55,10 +68,13 @@
                   bool uses_irt,
                   bool enable_dyncode_syscalls,
                   bool enable_exception_handling,
+                  bool enable_crash_throttling,
                   bool off_the_record,
                   const base::FilePath& profile_directory);
   virtual ~NaClProcessHost();
 
+  virtual void OnProcessCrashed(int exit_status) OVERRIDE;
+
   // Do any minimal work that must be done at browser startup.
   static void EarlyStartup(NaClBrowserDelegate* delegate);
 
@@ -204,6 +220,7 @@
   bool enable_debug_stub_;
   bool enable_dyncode_syscalls_;
   bool enable_exception_handling_;
+  bool enable_crash_throttling_;
 
   bool off_the_record_;
 
diff --git a/chrome/browser/nacl_host/nacl_process_host_unittest.cc b/chrome/browser/nacl_host/nacl_process_host_unittest.cc
new file mode 100644
index 0000000..aaff322
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_process_host_unittest.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 "chrome/browser/nacl_host/nacl_process_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+TEST(NaClProcessHostTest, AddressSpaceAllocation) {
+  size_t size = 1 << 20;  // 1 MB
+  void* addr = nacl::AllocateAddressSpaceASLR(GetCurrentProcess(), size);
+  bool success = VirtualFree(addr, 0, MEM_RELEASE);
+  ASSERT_TRUE(success);
+}
+#endif
diff --git a/chrome/browser/nacl_host/pnacl_host.cc b/chrome/browser/nacl_host/pnacl_host.cc
index 2468f9d..86546bd 100644
--- a/chrome/browser/nacl_host/pnacl_host.cc
+++ b/chrome/browser/nacl_host/pnacl_host.cc
@@ -120,9 +120,8 @@
   bool rv = temp_dir.empty()
                 ? file_util::CreateTemporaryFile(&file_path)
                 : file_util::CreateTemporaryFileInDir(temp_dir, &file_path);
-
   if (!rv) {
-    LOG(ERROR) << "PnaclHost:: Temp file creation failed.";
+    PLOG(ERROR) << "Temp file creation failed.";
     return base::kInvalidPlatformFileValue;
   }
   base::PlatformFileError error;
@@ -135,7 +134,7 @@
       &error));
 
   if (error != base::PLATFORM_FILE_OK) {
-    LOG(ERROR) << "PnaclHost: Temp file open failed: " << error;
+    PLOG(ERROR) << "Temp file open failed: " << error;
     return base::kInvalidPlatformFileValue;
   }
 
@@ -187,13 +186,13 @@
   PendingTranslationMap::iterator entry = pending_translations_.find(id);
   if (entry != pending_translations_.end()) {
     // Existing translation must have been abandonded. Clean it up.
-    LOG(ERROR) << "PnaclHost::GetNexeFd for already-pending translation";
+    LOG(ERROR) << "GetNexeFd for already-pending translation";
     pending_translations_.erase(entry);
   }
 
   std::string cache_key(disk_cache_->GetKey(cache_info));
   if (cache_key.empty()) {
-    LOG(ERROR) << "PnaclHost::GetNexeFd: Invalid cache info";
+    LOG(ERROR) << "GetNexeFd: Invalid cache info";
     cb.Run(base::kInvalidPlatformFileValue, false);
     return;
   }
@@ -235,7 +234,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   PendingTranslationMap::iterator entry(pending_translations_.find(id));
   if (entry == pending_translations_.end()) {
-    LOG(ERROR) << "PnaclHost::OnCacheQueryReturn: id not found";
+    LOG(ERROR) << "OnCacheQueryReturn: id not found";
     return;
   }
   PendingTranslation* pt = &entry->second;
@@ -258,7 +257,7 @@
   if (entry == pending_translations_.end()) {
     // The renderer may have signaled an error or closed while the temp
     // file was being created.
-    LOG(ERROR) << "PnaclHost::OnTempFileReturn: id not found";
+    LOG(ERROR) << "OnTempFileReturn: id not found";
     BrowserThread::PostBlockingPoolTask(
         FROM_HERE, base::Bind(base::IgnoreResult(base::ClosePlatformFile), fd));
     return;
@@ -266,7 +265,7 @@
   if (fd == base::kInvalidPlatformFileValue) {
     // This translation will fail, but we need to retry any translation
     // waiting for its result.
-    LOG(ERROR) << "PnaclHost::OnTempFileReturn: temp file creation failed";
+    LOG(ERROR) << "OnTempFileReturn: temp file creation failed";
     std::string key(entry->second.cache_key);
     bool is_incognito = entry->second.is_incognito;
     entry->second.callback.Run(fd, false);
@@ -345,14 +344,14 @@
   bool error = false;
   if (!base::GetPlatformFileInfo(fd, &info) ||
       info.size >= std::numeric_limits<int>::max()) {
-    LOG(ERROR) << "PnaclHost: GetPlatformFileInfo failed";
+    PLOG(ERROR) << "GetPlatformFileInfo failed";
     error = true;
   } else {
     buffer = new net::DrainableIOBuffer(
         new net::IOBuffer(static_cast<int>(info.size)), info.size);
     if (base::ReadPlatformFile(fd, 0, buffer->data(), buffer->size()) !=
         info.size) {
-      LOG(ERROR) << "PnaclHost: CopyFileToBuffer write failed";
+      PLOG(ERROR) << "CopyFileToBuffer file read failed";
       error = true;
     }
   }
@@ -477,7 +476,10 @@
 // static
 int PnaclHost::CopyBufferToFile(base::PlatformFile fd,
                                 scoped_refptr<net::DrainableIOBuffer> buffer) {
-  return base::WritePlatformFile(fd, 0, buffer->data(), buffer->size());
+  int rv = base::WritePlatformFile(fd, 0, buffer->data(), buffer->size());
+  if (rv == -1)
+    PLOG(ERROR) << "CopyBufferToFile write error";
+  return rv;
 }
 
 void PnaclHost::OnBufferCopiedToTempFile(const TranslationID& id,
@@ -489,7 +491,6 @@
   }
   if (file_error == -1) {
     // Write error on the temp file. Request a new file and start over.
-    LOG(ERROR) << "PnaclHost::OnBufferCopiedToTempFile write error";
     BrowserThread::PostBlockingPoolTask(
         FROM_HERE,
         base::Bind(base::IgnoreResult(base::ClosePlatformFile),
diff --git a/chrome/browser/nacl_host/pnacl_host_unittest.cc b/chrome/browser/nacl_host/pnacl_host_unittest.cc
index 0ad9cd5..e2d529d 100644
--- a/chrome/browser/nacl_host/pnacl_host_unittest.cc
+++ b/chrome/browser/nacl_host/pnacl_host_unittest.cc
@@ -195,7 +195,8 @@
   EXPECT_EQ(0U, host_->pending_translations());
 }
 
-TEST_F(PnaclHostTest, OverlappedMissesAfterTempReturn) {
+// crbug.com/272492; flaky on all platforms.
+TEST_F(PnaclHostTest, DISABLED_OverlappedMissesAfterTempReturn) {
   nacl::PnaclCacheInfo info = GetTestCacheInfo();
   GET_NEXE_FD(0, 0, false, info, false);
   FlushQueues();
@@ -215,7 +216,8 @@
   EXPECT_EQ(0U, host_->pending_translations());
 }
 
-TEST_F(PnaclHostTest, OverlappedMissesBeforeTempReturn) {
+// crbug.com/272492; flaky on all platforms.
+TEST_F(PnaclHostTest, DISABLED_OverlappedMissesBeforeTempReturn) {
   nacl::PnaclCacheInfo info = GetTestCacheInfo();
   GET_NEXE_FD(0, 0, false, info, false);
   // Send the 2nd fd request before the first one returns a temp file.
@@ -266,7 +268,8 @@
   EXPECT_EQ(0U, host_->pending_translations());
 }
 
-TEST_F(PnaclHostTest, OverlappedMissesRendererClosing) {
+// crbug.com/272492; flaky on all platforms.
+TEST_F(PnaclHostTest, DISABLED_OverlappedMissesRendererClosing) {
   nacl::PnaclCacheInfo info = GetTestCacheInfo();
   GET_NEXE_FD(0, 0, false, info, false);
   // Send the 2nd fd request from a different renderer.
@@ -304,7 +307,8 @@
   EXPECT_EQ(3, temp_callback_count_);
 }
 
-TEST_F(PnaclHostTest, IncognitoOverlappedMiss) {
+// crbug.com/272492; flaky on all platforms.
+TEST_F(PnaclHostTest, DISABLED_IncognitoOverlappedMiss) {
   nacl::PnaclCacheInfo info = GetTestCacheInfo();
   GET_NEXE_FD(0, 0, true, info, false);
   GET_NEXE_FD(0, 1, false, info, false);
@@ -328,7 +332,8 @@
   host_->RendererClosing(0);
 }
 
-TEST_F(PnaclHostTest, IncognitoSecondOverlappedMiss) {
+// crbug.com/272492; flaky on all platforms.
+TEST_F(PnaclHostTest, DISABLED_IncognitoSecondOverlappedMiss) {
   // If the non-incognito request comes first, it should
   // behave exactly like OverlappedMissBeforeTempReturn
   nacl::PnaclCacheInfo info = GetTestCacheInfo();
diff --git a/chrome/browser/nacl_host/pnacl_translation_cache.cc b/chrome/browser/nacl_host/pnacl_translation_cache.cc
index 508c665..c3e325a 100644
--- a/chrome/browser/nacl_host/pnacl_translation_cache.cc
+++ b/chrome/browser/nacl_host/pnacl_translation_cache.cc
@@ -199,8 +199,7 @@
 void PnaclTranslationCacheEntry::CloseEntry(int rv) {
   DCHECK(entry_);
   if (rv < 0) {
-    LOG(ERROR) << "PnaclTranslationCache: failed to close entry: "
-               << net::ErrorToString(rv);
+    LOG(ERROR) << "Failed to close entry: " << net::ErrorToString(rv);
     entry_->Doom();
   }
   BrowserThread::PostTask(
@@ -230,7 +229,7 @@
 
   switch (step_) {
     case UNINITIALIZED:
-      LOG(ERROR) << "PnaclTranslationCache: DispatchNext called uninitialized";
+      LOG(ERROR) << "DispatchNext called uninitialized";
       break;
 
     case OPEN_ENTRY:
@@ -247,8 +246,7 @@
       } else {
         if (rv != net::ERR_FAILED) {
           // ERROR_FAILED is what we expect if the entry doesn't exist.
-          LOG(ERROR) << "PnaclTranslationCache: OpenEntry failed: "
-                     << net::ErrorToString(rv);
+          LOG(ERROR) << "OpenEntry failed: " << net::ErrorToString(rv);
         }
         if (is_read_) {
           // Just a cache miss, not necessarily an error.
@@ -266,8 +264,7 @@
         step_ = TRANSFER_ENTRY;
         WriteEntry(io_buf_->BytesConsumed(), io_buf_->BytesRemaining());
       } else {
-        LOG(ERROR) << "PnaclTranslationCache: Failed to Create Entry: "
-                   << net::ErrorToString(rv);
+        LOG(ERROR) << "Failed to Create Entry: " << net::ErrorToString(rv);
         Finish(rv);
       }
       break;
@@ -277,8 +274,7 @@
         // We do not call DispatchNext directly if WriteEntry/ReadEntry returns
         // ERR_IO_PENDING, and the callback should not return that value either.
         LOG(ERROR)
-            << "PnaclTranslationCache: Failed to complete write to entry: "
-            << net::ErrorToString(rv);
+            << "Failed to complete write to entry: " << net::ErrorToString(rv);
         step_ = CLOSE_ENTRY;
         CloseEntry(rv);
         break;
@@ -352,8 +348,7 @@
 
 void PnaclTranslationCache::OnCreateBackendComplete(int rv) {
   if (rv < 0) {
-    LOG(ERROR) << "PnaclTranslationCache: backend init failed:"
-               << net::ErrorToString(rv);
+    LOG(ERROR) << "Backend init failed:" << net::ErrorToString(rv);
   }
   // Invoke our client's callback function.
   if (!init_callback_.is_null()) {
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 76c09db..e02dca6 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/base_paths.h"
+#include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/path_service.h"
@@ -241,6 +242,18 @@
   return value;
 }
 
+// Ensure list has exactly n elements.
+void MaintainContentLengthPrefsWindow(base::ListValue* list, size_t n) {
+  // Remove data for old days from the front.
+  while (list->GetSize() > n)
+    list->Remove(0, NULL);
+  // Newly added lists are empty. Add entries to back to fill the window,
+  // each initialized to zero.
+  while (list->GetSize() < n)
+    list->AppendString(base::Int64ToString(0));
+  DCHECK_EQ(n, list->GetSize());
+}
+
 void RecordDailyContentLengthHistograms(
     int64 original_length,
     int64 received_length,
@@ -326,6 +339,15 @@
   ListPrefUpdate via_data_reduction_update(
       prefs, prefs::kDailyHttpReceivedContentLengthViaDataReductionProxy);
 
+  // New empty lists may have been created. Maintain the invariant that
+  // there should be exactly |kNumDaysInHistory| days in the histories.
+  MaintainContentLengthPrefsWindow(original_update.Get(), kNumDaysInHistory);
+  MaintainContentLengthPrefsWindow(received_update.Get(), kNumDaysInHistory);
+  MaintainContentLengthPrefsWindow(
+      data_reduction_enabled_update.Get(), kNumDaysInHistory);
+  MaintainContentLengthPrefsWindow(
+      via_data_reduction_update.Get(), kNumDaysInHistory);
+
   // Determine how many days it has been since the last update.
   int64 then_internal = prefs->GetInt64(
       prefs::kDailyHttpContentLengthLastUpdateDate);
@@ -376,8 +398,9 @@
           ListPrefInt64Value(*via_data_reduction_update,
                              via_data_reduction_update->GetSize() - 1));
     }
-
-    // Add entries for days since last update.
+    // Add entries for days since last update event. This will make the
+    // lists longer than kNumDaysInHistory. The additional items will be cut off
+    // from the head of the lists by MaintainContentLengthPrefsWindow, below.
     for (int i = 0;
          i < days_since_last_update && i < static_cast<int>(kNumDaysInHistory);
          ++i) {
@@ -387,23 +410,16 @@
       via_data_reduction_update->AppendString(base::Int64ToString(0));
     }
 
-    // Maintain the invariant that there should never be more than
-    // |kNumDaysInHistory| days in the histories.
-    while (original_update->GetSize() > kNumDaysInHistory)
-      original_update->Remove(0, NULL);
-    while (received_update->GetSize() > kNumDaysInHistory)
-      received_update->Remove(0, NULL);
-    while (data_reduction_enabled_update->GetSize() > kNumDaysInHistory)
-      data_reduction_enabled_update->Remove(0, NULL);
-    while (via_data_reduction_update->GetSize() > kNumDaysInHistory)
-      via_data_reduction_update->Remove(0, NULL);
+    // Entries for new days may have been appended. Maintain the invariant that
+    // there should be exactly |kNumDaysInHistory| days in the histories.
+    MaintainContentLengthPrefsWindow(original_update.Get(), kNumDaysInHistory);
+    MaintainContentLengthPrefsWindow(received_update.Get(), kNumDaysInHistory);
+    MaintainContentLengthPrefsWindow(
+        data_reduction_enabled_update.Get(), kNumDaysInHistory);
+    MaintainContentLengthPrefsWindow(
+        via_data_reduction_update.Get(), kNumDaysInHistory);
   }
 
-  DCHECK_EQ(kNumDaysInHistory, original_update->GetSize());
-  DCHECK_EQ(kNumDaysInHistory, received_update->GetSize());
-  DCHECK_EQ(kNumDaysInHistory, data_reduction_enabled_update->GetSize());
-  DCHECK_EQ(kNumDaysInHistory, via_data_reduction_update->GetSize());
-
   // Update the counts for the current day.
   AddInt64ToListPref(kNumDaysInHistory - 1,
                      original_content_length, original_update.Get());
@@ -626,6 +642,7 @@
     net::URLRequest* request,
     const net::CompletionCallback& callback,
     net::HttpRequestHeaders* headers) {
+  TRACE_EVENT_ASYNC_STEP0("net", "URLRequest", request, "SendRequest");
   return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
       profile_, extension_info_map_.get(), request, callback, headers);
 }
@@ -655,6 +672,7 @@
 
 
 void ChromeNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
+  TRACE_EVENT_ASYNC_STEP0("net", "URLRequest", request, "ResponseStarted");
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
       profile_, extension_info_map_.get(), request);
   ForwardProxyErrors(request, event_router_.get(), profile_);
@@ -662,6 +680,8 @@
 
 void ChromeNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
                                            int bytes_read) {
+  TRACE_EVENT_ASYNC_STEP1("net", "URLRequest", &request, "DidRead",
+                          "bytes_read", bytes_read);
   performance_monitor::PerformanceMonitor::GetInstance()->BytesReadOnIOThread(
       request, bytes_read);
 
@@ -672,6 +692,7 @@
 
 void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request,
                                         bool started) {
+  TRACE_EVENT_ASYNC_END0("net", "URLRequest", request);
   if (request->status().status() == net::URLRequestStatus::SUCCESS) {
     // For better accuracy, we use the actual bytes read instead of the length
     // specified with the Content-Length header, which may be inaccurate,
diff --git a/chrome/browser/net/load_timing_browsertest.cc b/chrome/browser/net/load_timing_browsertest.cc
index 75da353..51963fe 100644
--- a/chrome/browser/net/load_timing_browsertest.cc
+++ b/chrome/browser/net/load_timing_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
@@ -119,10 +120,13 @@
                               net::NetworkDelegate* network_delegate,
                               const base::FilePath& path,
                               const TimingDeltas& load_timing_deltas)
-      : net::URLRequestFileJob(request, network_delegate, path),
+      : net::URLRequestFileJob(
+            request, network_delegate, path,
+            content::BrowserThread::GetBlockingPool()->
+                GetTaskRunnerWithShutdownBehavior(
+                    base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
         load_timing_deltas_(load_timing_deltas),
-        weak_factory_(this) {
-  }
+        weak_factory_(this) {}
 
   // net::URLRequestFileJob implementation:
   virtual void Start() OVERRIDE {
diff --git a/chrome/browser/net/network_stats.cc b/chrome/browser/net/network_stats.cc
index 23a8a6a..cbb0389 100644
--- a/chrome/browser/net/network_stats.cc
+++ b/chrome/browser/net/network_stats.cc
@@ -150,6 +150,7 @@
   net::HostResolver::RequestInfo request(server_host_port_pair);
   int rv =
       resolver->Resolve(request,
+                        net::DEFAULT_PRIORITY,
                         &addresses_,
                         base::Bind(base::IgnoreResult(&NetworkStats::DoConnect),
                                    base::Unretained(this)),
@@ -189,28 +190,25 @@
     return false;
   }
 
-  net::DatagramClientSocket* udp_socket =
+  scoped_ptr<net::DatagramClientSocket> udp_socket =
       socket_factory_->CreateDatagramClientSocket(
           net::DatagramSocket::DEFAULT_BIND,
           net::RandIntCallback(),
           NULL,
           net::NetLog::Source());
-  if (!udp_socket) {
-    TestPhaseComplete(SOCKET_CREATE_FAILED, net::ERR_INVALID_ARGUMENT);
-    return false;
-  }
-  DCHECK(!socket_.get());
-  socket_.reset(udp_socket);
+  DCHECK(udp_socket);
+  DCHECK(!socket_);
+  socket_ = udp_socket.Pass();
 
   const net::IPEndPoint& endpoint = addresses_.front();
-  int rv = udp_socket->Connect(endpoint);
+  int rv = socket_->Connect(endpoint);
   if (rv < 0) {
     TestPhaseComplete(CONNECT_FAILED, rv);
     return false;
   }
 
-  udp_socket->SetSendBufferSize(kMaxUdpSendBufferSize);
-  udp_socket->SetReceiveBufferSize(kMaxUdpReceiveBufferSize);
+  socket_->SetSendBufferSize(kMaxUdpSendBufferSize);
+  socket_->SetReceiveBufferSize(kMaxUdpReceiveBufferSize);
   return ConnectComplete(rv);
 }
 
@@ -239,7 +237,9 @@
   probe_packet.set_group_id(current_test_index_);
   std::string output = probe_message_.MakeEncodedPacket(probe_packet);
 
-  SendData(output);
+  int result = SendData(output);
+  if (result < 0 && result != net::ERR_IO_PENDING)
+    TestPhaseComplete(WRITE_FAILED, result);
 }
 
 void NetworkStats::SendProbeRequest() {
@@ -286,7 +286,9 @@
 
   StartReadDataTimer(timeout_seconds, current_test_index_);
   probe_request_time_ = base::TimeTicks::Now();
-  SendData(output);
+  int result = SendData(output);
+  if (result < 0 && result != net::ERR_IO_PENDING)
+    TestPhaseComplete(WRITE_FAILED, result);
 }
 
 void NetworkStats::ReadData() {
@@ -409,8 +411,9 @@
   return true;
 }
 
-void NetworkStats::SendData(const std::string& output) {
-  DCHECK(!write_buffer_.get());
+int NetworkStats::SendData(const std::string& output) {
+  if (write_buffer_.get() || !socket_.get())
+    return net::ERR_UNEXPECTED;
   scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer(output));
   write_buffer_ = new net::DrainableIOBuffer(buffer.get(), buffer->size());
 
@@ -418,13 +421,10 @@
       write_buffer_.get(),
       write_buffer_->BytesRemaining(),
       base::Bind(&NetworkStats::OnWriteComplete, base::Unretained(this)));
-  if (bytes_written < 0) {
-    if (bytes_written != net::ERR_IO_PENDING)
-      // There is some unexpected error.
-      TestPhaseComplete(WRITE_FAILED, bytes_written);
-  } else {
-    UpdateSendBuffer(bytes_written);
-  }
+  if (bytes_written < 0)
+    return bytes_written;
+  UpdateSendBuffer(bytes_written);
+  return net::OK;
 }
 
 void NetworkStats::OnWriteComplete(int result) {
diff --git a/chrome/browser/net/network_stats.h b/chrome/browser/net/network_stats.h
index 7f80a03..59bf0b0 100644
--- a/chrome/browser/net/network_stats.h
+++ b/chrome/browser/net/network_stats.h
@@ -146,7 +146,9 @@
   void ReadData();
 
   // Send data contained in |str| to server.
-  void SendData(const std::string& str);
+  // Return a negative value if IO blocking occurs or there is an error.
+  // Otherwise return net::OK.
+  int SendData(const std::string& str);
 
   // Update the send buffer (telling it that |bytes_sent| has been sent).
   // And reset |write_buffer_|.
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
index 6e8e2fe..e55b3dd 100644
--- a/chrome/browser/net/predictor.cc
+++ b/chrome/browser/net/predictor.cc
@@ -108,7 +108,9 @@
     // lets the HostResolver know it can de-prioritize it.
     resolve_info.set_is_speculative(true);
     return resolver_.Resolve(
-        resolve_info, &addresses_,
+        resolve_info,
+        net::DEFAULT_PRIORITY,
+        &addresses_,
         base::Bind(&LookupRequest::OnLookupFinished, base::Unretained(this)),
         net::BoundNetLog());
   }
@@ -221,11 +223,8 @@
 
   GURL canonical_url(Predictor::CanonicalizeUrl(url_chain.back()));
 
-  // Record the preconnect trigger for the url as used if exist
   MRUPreconnects::iterator itPreconnect = mru_preconnects_.Peek(canonical_url);
   bool was_preconnected = (itPreconnect != mru_preconnects_.end());
-  if (was_preconnected)
-    itPreconnect->second.set_was_used();
 
   // This is an UMA which was named incorrectly. This actually measures the
   // ratio of URLRequests which have used a preconnected session.
@@ -251,8 +250,10 @@
     MRUPreconnects::iterator itPreconnect =
         mru_preconnects_.Peek(canonical_url);
     bool was_preconnected = (itPreconnect != mru_preconnects_.end());
-    if (was_preconnected)
+    if (was_preconnected) {
+      itPreconnect->second.set_was_used();
       did_use_preconnect = true;
+    }
   }
 
   UMA_HISTOGRAM_BOOLEAN("Net.PreconnectedLinkNavigations", did_use_preconnect);
@@ -466,7 +467,7 @@
       GURL gurl = tab_start_pref.urls[i];
       if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty())
         continue;
-      if (gurl.SchemeIs("http") || gurl.SchemeIs("https"))
+      if (gurl.SchemeIsHTTPOrHTTPS())
         urls.push_back(gurl.GetWithEmptyPath());
     }
   }
@@ -1300,7 +1301,7 @@
   if (kStartupResolutionCount <= first_navigations_.size())
     return;
 
-  DCHECK(url.SchemeIs("http") || url.SchemeIs("https"));
+  DCHECK(url.SchemeIsHTTPOrHTTPS());
   DCHECK_EQ(url, Predictor::CanonicalizeUrl(url));
   if (first_navigations_.find(url) == first_navigations_.end())
     first_navigations_[url] = base::TimeTicks::Now();
diff --git a/chrome/browser/net/predictor_tab_helper.cc b/chrome/browser/net/predictor_tab_helper.cc
index 752bb7a..0b8be8f 100644
--- a/chrome/browser/net/predictor_tab_helper.cc
+++ b/chrome/browser/net/predictor_tab_helper.cc
@@ -42,7 +42,7 @@
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
   if (!IsUserLinkNavigationRequest(params.transition) ||
-      !(params.url.SchemeIs("http") || params.url.SchemeIs("https")))
+      !(params.url.SchemeIsHTTPOrHTTPS()))
     return;
 
   Profile* profile = Profile::FromBrowserContext(
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index ab66107..66180e6 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -22,8 +22,13 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/proxy_config_service_impl.h"
+#include "chromeos/network/dhcp_proxy_script_fetcher_chromeos.h"
 #endif  // defined(OS_CHROMEOS)
 
+#if defined(OS_WIN)
+#include "win8/util/win8_util.h"
+#endif
+
 using content::BrowserThread;
 
 // static
@@ -100,6 +105,12 @@
   }
 #endif  // defined(OS_IOS)
 
+#if defined(OS_WIN)
+  // Crashes. http://crbug.com/266838
+  if (use_v8 && win8::IsSingleWindowMetroMode())
+    use_v8 = false;
+#endif
+
   size_t num_pac_threads = 0u;  // Use default number of threads.
 
   // Check the command line for an override on the number of proxy resolver
@@ -121,15 +132,21 @@
 #if defined(OS_IOS)
     NOTREACHED();
 #else
+    net::DhcpProxyScriptFetcher* dhcp_proxy_script_fetcher;
+#if defined(OS_CHROMEOS)
+    dhcp_proxy_script_fetcher =
+        new chromeos::DhcpProxyScriptFetcherChromeos(context);
+#else
     net::DhcpProxyScriptFetcherFactory dhcp_factory;
-    if (command_line.HasSwitch(switches::kDisableDhcpWpad)) {
+    if (command_line.HasSwitch(switches::kDisableDhcpWpad))
       dhcp_factory.set_enabled(false);
-    }
+    dhcp_proxy_script_fetcher = dhcp_factory.Create(context);
+#endif
 
     proxy_service = net::CreateProxyServiceUsingV8ProxyResolver(
         proxy_config_service,
         new net::ProxyScriptFetcherImpl(context),
-        dhcp_factory.Create(context),
+        dhcp_proxy_script_fetcher,
         context->host_resolver(),
         net_log,
         network_delegate);
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
index 49f594b..96f74c9 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
@@ -35,6 +35,7 @@
 
   GURL destination = notification->GetDefaultDestinationUrl();
   NavigateToUrl(destination);
+  chrome_notifier_->MarkNotificationAsRead(notification_id_);
 }
 
 // TODO(petewil) Add the ability to do URL actions also.
@@ -44,6 +45,7 @@
   if (notification) {
     GURL destination = notification->GetButtonUrl(button_index);
     NavigateToUrl(destination);
+    chrome_notifier_->MarkNotificationAsRead(notification_id_);
   }
 }
 
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 7532501..922cf0a 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate_browsertest.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate_browsertest.cc
@@ -144,6 +144,9 @@
   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/sync_notifier/chrome_notifier_service.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
index 6341a3f..ae1347e 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
@@ -439,14 +439,41 @@
   // Add the notifier_id if it is enabled and not already there.
   if (iter == enabled_sending_services_.end() && enabled) {
     enabled_sending_services_.push_back(notifier_id);
-    // TODO(petewil) Check now for any outstanding notifications.
+    // Check now for any outstanding notifications.
+    DisplayUnreadNotificationsFromSource(notifier_id);
   // Remove the notifier_id if it is disabled and present.
   } else if (iter != enabled_sending_services_.end() && !enabled) {
     enabled_sending_services_.erase(iter);
+    RemoveUnreadNotificationsFromSource(notifier_id);
   }
 
   // Otherwise, nothing to do, we can exit.
   return;
 }
 
+void ChromeNotifierService::DisplayUnreadNotificationsFromSource(
+    std::string notifier_id) {
+  for (std::vector<SyncedNotification*>::const_iterator iter =
+          notification_data_.begin();
+       iter != notification_data_.end();
+       ++iter) {
+    if ((*iter)->GetSendingServiceId() == notifier_id &&
+        (*iter)->GetReadState() == SyncedNotification::kUnread)
+      Display(*iter);
+  }
+}
+
+void ChromeNotifierService::RemoveUnreadNotificationsFromSource(
+    std::string notifier_id) {
+  for (std::vector<SyncedNotification*>::const_iterator iter =
+          notification_data_.begin();
+       iter != notification_data_.end();
+       ++iter) {
+    if ((*iter)->GetSendingServiceId() == notifier_id &&
+        (*iter)->GetReadState() == SyncedNotification::kUnread)
+      notification_manager_->CancelById((*iter)->GetKey());
+  }
+}
+
+
 }  // namespace notifier
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
index 61ff02b..8feed24 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
@@ -100,6 +100,14 @@
   // Remove a notification from our store.
   void FreeNotificationById(const std::string& notification_id);
 
+  // When a service it turned on, scan our cache for any notifications
+  // for that service, and display them if they are unread.
+  void DisplayUnreadNotificationsFromSource(std::string notifier_id);
+
+  // When a service it turned off, scan our cache for any notifications
+  // for that service, and remove them from the message center.
+  void RemoveUnreadNotificationsFromSource(std::string notifier_id);
+
   // Back pointer to the owning profile.
   Profile* const profile_;
   NotificationUIManager* const notification_manager_;
@@ -112,6 +120,7 @@
   ScopedVector<notifier::SyncedNotification> notification_data_;
 
   friend class ChromeNotifierServiceTest;
+  FRIEND_TEST_ALL_PREFIXES(ChromeNotifierServiceTest, ServiceEnabledTest);
 
   DISALLOW_COPY_AND_ASSIGN(ChromeNotifierService);
 };
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc
index 5f5ced5..67d7055 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <map>
 
+#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -36,6 +37,9 @@
 
 const int kNotificationPriority = static_cast<int>(
     message_center::LOW_PRIORITY);
+// The test notification provider name shold match the name of the first
+// synced notification service.
+const char kTestNotificationProvider[] = "Google+";
 
 // Extract notification id from syncer::SyncData.
 std::string GetNotificationId(const SyncData& sync_data) {
@@ -45,6 +49,10 @@
   return specifics.coalesced_notification().key();
 }
 
+}  // namespace
+
+namespace notifier {
+
 // Stub out the NotificationUIManager for unit testing.
 class StubNotificationUIManager : public NotificationUIManager {
  public:
@@ -186,8 +194,6 @@
   DISALLOW_COPY_AND_ASSIGN(SyncChangeProcessorDelegate);
 };
 
-}  // namespace
-
 class ChromeNotifierServiceTest : public testing::Test {
  public:
   ChromeNotifierServiceTest()
@@ -595,6 +601,34 @@
   EXPECT_FALSE(processor()->ContainsId(kKey1));
 }
 
-// TODO(petewil): There are more tests to add, such as when we add an API
-// to allow data entry from the client, we might have a more up to date
-// item on the client than the server, or we might have a merge conflict.
+TEST_F(ChromeNotifierServiceTest, ServiceEnabledTest) {
+  StubNotificationUIManager notification_manager;
+  ChromeNotifierService notifier(NULL, &notification_manager);
+  std::vector<std::string>::iterator iter;
+
+  // Create some local fake data.
+  scoped_ptr<SyncedNotification> n1(CreateNotification(
+      kTitle1, kText1, kIconUrl1, kImageUrl1, kAppId1, kKey1, kUnread));
+  notifier.AddForTest(n1.Pass());
+
+  // Enable the service and ensure the service is in the list.
+  // Initially the service starts in the disabled state.
+  notifier.OnSyncedNotificationServiceEnabled(kTestNotificationProvider, true);
+  iter = find(notifier.enabled_sending_services_.begin(),
+              notifier.enabled_sending_services_.end(),
+              kTestNotificationProvider);
+  EXPECT_NE(notifier.enabled_sending_services_.end(), iter);
+  // TODO(petewil): Verify Display gets called too.
+
+  // Disable the service and ensure it is gone from the list and the
+  // notification_manager.
+  notifier.OnSyncedNotificationServiceEnabled(kTestNotificationProvider, false);
+  iter = find(notifier.enabled_sending_services_.begin(),
+              notifier.enabled_sending_services_.end(),
+              kTestNotificationProvider);
+  EXPECT_EQ(notifier.enabled_sending_services_.end(), iter);
+  EXPECT_EQ(notification_manager.dismissed_id(), std::string(kKey1));
+
+}
+
+}  // namespace notifier
diff --git a/chrome/browser/password_manager/password_form_manager_unittest.cc b/chrome/browser/password_manager/password_form_manager_unittest.cc
index f9771a2..33339e1 100644
--- a/chrome/browser/password_manager/password_form_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_form_manager_unittest.cc
@@ -24,6 +24,8 @@
 
 using ::testing::Eq;
 
+namespace {
+
 class TestPasswordManagerDelegate : public PasswordManagerDelegate {
  public:
   explicit TestPasswordManagerDelegate(Profile* profile) : profile_(profile) {}
@@ -51,6 +53,8 @@
       bool wait_for_username) const OVERRIDE {}
 };
 
+}  // namespace
+
 class TestPasswordFormManager : public PasswordFormManager {
  public:
   TestPasswordFormManager(Profile* profile,
diff --git a/chrome/browser/password_manager/password_generation_manager_unittest.cc b/chrome/browser/password_manager/password_generation_manager_unittest.cc
index 22f2050..ad11d79 100644
--- a/chrome/browser/password_manager/password_generation_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_generation_manager_unittest.cc
@@ -68,8 +68,8 @@
   virtual content::BrowserContext* CreateBrowserContext() OVERRIDE {
     // Create an incognito profile.
     TestingProfile::Builder builder;
+    builder.SetIncognito();
     scoped_ptr<TestingProfile> profile = builder.Build();
-    profile->set_incognito(true);
     return profile.release();
   }
 };
diff --git a/chrome/browser/password_manager/password_manager.cc b/chrome/browser/password_manager/password_manager.cc
index dbeec6b..39629e9 100644
--- a/chrome/browser/password_manager/password_manager.cc
+++ b/chrome/browser/password_manager/password_manager.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/platform_thread.h"
+#include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/password_manager/password_form_manager.h"
 #include "chrome/browser/password_manager/password_manager_delegate.h"
 #include "chrome/browser/profiles/profile.h"
@@ -137,12 +138,16 @@
 }
 
 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) {
-  if (!IsSavingEnabled())
+  if (!IsSavingEnabled()) {
+    RecordFailure(SAVING_DISABLED);
     return;
+  }
 
   // No password to save? Then don't.
-  if (form.password_value.empty())
+  if (form.password_value.empty()) {
+    RecordFailure(EMPTY_PASSWORD);
     return;
+  }
 
   scoped_ptr<PasswordFormManager> manager;
   ScopedVector<PasswordFormManager>::iterator matched_manager_it =
@@ -173,6 +178,7 @@
     manager.reset(*matched_manager_it);
     pending_login_managers_.weak_erase(matched_manager_it);
   } else {
+    RecordFailure(NO_MATCHING_FORM);
     return;
   }
 
@@ -180,23 +186,31 @@
   // tried to submit credentials before we had time to even find matching
   // results for the given form and autofill. If this is the case, we just
   // give up.
-  if (!manager->HasCompletedMatching())
+  if (!manager->HasCompletedMatching()) {
+    RecordFailure(MATCHING_NOT_COMPLETE);
     return;
+  }
 
   // Also get out of here if the user told us to 'never remember' passwords for
   // this form.
-  if (manager->IsBlacklisted())
+  if (manager->IsBlacklisted()) {
+    RecordFailure(FORM_BLACKLISTED);
     return;
+  }
 
   // Bail if we're missing any of the necessary form components.
-  if (!manager->HasValidPasswordForm())
+  if (!manager->HasValidPasswordForm()) {
+    RecordFailure(INVALID_FORM);
     return;
+  }
 
   // Always save generated passwords, as the user expresses explicit intent for
   // Chrome to manage such passwords. For other passwords, respect the
   // autocomplete attribute.
-  if (!manager->HasGeneratedPassword() && !form.password_autocomplete_set)
+  if (!manager->HasGeneratedPassword() && !form.password_autocomplete_set) {
+    RecordFailure(AUTOCOMPLETE_OFF);
     return;
+  }
 
   PasswordForm provisionally_saved_form(form);
   provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() &&
@@ -210,6 +224,16 @@
   provisional_save_manager_.swap(manager);
 }
 
+void PasswordManager::RecordFailure(ProvisionalSaveFailure failure) {
+  UMA_HISTOGRAM_ENUMERATION("PasswordManager.ProvisionalSaveFailure",
+                            failure, MAX_FAILURE_VALUE);
+}
+
+void PasswordManager::AddSubmissionCallback(
+    const PasswordSubmittedCallback& callback) {
+  submission_callbacks_.push_back(callback);
+}
+
 void PasswordManager::AddObserver(LoginModelObserver* observer) {
   observers_.AddObserver(observer);
 }
@@ -218,20 +242,13 @@
   observers_.RemoveObserver(observer);
 }
 
-void PasswordManager::DidNavigateAnyFrame(
+void PasswordManager::DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) {
-  bool password_form_submitted = params.password_form.origin.is_valid();
-
-  // Try to save the password if one was submitted.
-  if (password_form_submitted)
-    ProvisionallySavePassword(params.password_form);
-
-  // Clear data after submission or main frame navigation. We don't want
-  // to clear data after subframe navigation as there might be password
-  // forms on other frames that could be submitted.
-  if (password_form_submitted || details.is_main_frame)
-    pending_login_managers_.clear();
+  // Clear data after main frame navigation. We don't want to clear data after
+  // subframe navigation as there might be password forms on other frames that
+  // could be submitted.
+  pending_login_managers_.clear();
 }
 
 bool PasswordManager::OnMessageReceived(const IPC::Message& message) {
@@ -241,11 +258,23 @@
                         OnPasswordFormsParsed)
     IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsRendered,
                         OnPasswordFormsRendered)
+    IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormSubmitted,
+                        OnPasswordFormSubmitted)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
 }
 
+void PasswordManager::OnPasswordFormSubmitted(
+    const PasswordForm& password_form) {
+  ProvisionallySavePassword(password_form);
+  for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
+    submission_callbacks_[i].Run(password_form);
+  }
+
+  pending_login_managers_.clear();
+}
+
 void PasswordManager::OnPasswordFormsParsed(
     const std::vector<PasswordForm>& forms) {
   // Ask the SSLManager for current security.
@@ -311,15 +340,20 @@
   if (provisional_save_manager_->HasGeneratedPassword())
     UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1);
 
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+  if (ShouldShowSavePasswordInfoBar()) {
+    if (CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableSavePasswordBubble)) {
-    if (ShouldShowSavePasswordInfoBar()) {
-      delegate_->AddSavePasswordInfoBarIfPermitted(
+      TabSpecificContentSettings* content_settings =
+          TabSpecificContentSettings::FromWebContents(web_contents());
+      content_settings->OnPasswordSubmitted(
           provisional_save_manager_.release());
     } else {
-      provisional_save_manager_->Save();
-      provisional_save_manager_.reset();
+      delegate_->AddSavePasswordInfoBarIfPermitted(
+          provisional_save_manager_.release());
     }
+  } else {
+    provisional_save_manager_->Save();
+    provisional_save_manager_.reset();
   }
 }
 
@@ -373,7 +407,7 @@
   PossiblyInitializeUsernamesExperiment(best_matches);
   switch (form_for_autofill.scheme) {
     case PasswordForm::SCHEME_HTML: {
-      // Note the check above is required because the observer_ for a non-HTML
+      // Note the check above is required because the observers_ for a non-HTML
       // schemed password form may have been freed, so we need to distinguish.
       autofill::PasswordFormFillData fill_data;
       InitPasswordFormFillData(form_for_autofill,
diff --git a/chrome/browser/password_manager/password_manager.h b/chrome/browser/password_manager/password_manager.h
index d65d1c7..351f6e5 100644
--- a/chrome/browser/password_manager/password_manager.h
+++ b/chrome/browser/password_manager/password_manager.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
@@ -42,6 +43,14 @@
       PasswordManagerDelegate* delegate);
   virtual ~PasswordManager();
 
+  typedef base::Callback<void(const content::PasswordForm&)>
+      PasswordSubmittedCallback;
+
+  // There is no corresponding remove function as currently all of the
+  // owners of these callbacks have sufficient lifetimes so that the callbacks
+  // should always be valid when called.
+  void AddSubmissionCallback(const PasswordSubmittedCallback& callback);
+
   // Is saving new data for password autofill enabled for the current profile?
   // For example, saving new data is disabled in Incognito mode, whereas filling
   // data is not.
@@ -69,7 +78,7 @@
   void ProvisionallySavePassword(const content::PasswordForm& form);
 
   // content::WebContentsObserver overrides.
-  virtual void DidNavigateAnyFrame(
+  virtual void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) OVERRIDE;
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
@@ -86,9 +95,27 @@
   PasswordManager(content::WebContents* web_contents,
                   PasswordManagerDelegate* delegate);
 
+  // Handle notification that a password form was submitted.
+  virtual void OnPasswordFormSubmitted(
+      const content::PasswordForm& password_form);
+
  private:
   friend class content::WebContentsUserData<PasswordManager>;
 
+  enum ProvisionalSaveFailure {
+    SAVING_DISABLED,
+    EMPTY_PASSWORD,
+    NO_MATCHING_FORM,
+    MATCHING_NOT_COMPLETE,
+    FORM_BLACKLISTED,
+    INVALID_FORM,
+    AUTOCOMPLETE_OFF,
+    MAX_FAILURE_VALUE
+  };
+
+  // Log failure for UMA
+  void RecordFailure(ProvisionalSaveFailure failure);
+
   // Possibly set up FieldTrial for testing other possible usernames. This only
   // happens if there are other_possible_usernames to be shown and the
   // experiment hasn't already been initialized. We setup the experiment at
@@ -142,6 +169,9 @@
   // notification in const member functions.
   mutable ObserverList<LoginModelObserver> observers_;
 
+  // Callbacks to be notified when a password form has been submitted.
+  std::vector<PasswordSubmittedCallback> submission_callbacks_;
+
   DISALLOW_COPY_AND_ASSIGN(PasswordManager);
 };
 
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 02d2cea..61bc94e 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -112,10 +112,117 @@
   DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
 };
 
-
 // Actual tests ---------------------------------------------------------------
+// This test was a bit flaky <http://crbug.com/276597>.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+                       DISABLED_PromptForNormalSubmit) {
+  ASSERT_TRUE(test_server()->Start());
 
-IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForXHRSubmit) {
+  GURL url = test_server()->GetURL("files/password/password_form.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Fill a form and submit through a <input type="submit"> button. Nothing
+  // special.
+  NavigationObserver observer(WebContents());
+  std::string fill_and_submit =
+      "document.getElementById('username_field').value = 'temp';"
+      "document.getElementById('password_field').value = 'random';"
+      "document.getElementById('input_submit_button').click()";
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+  observer.Wait();
+  EXPECT_TRUE(observer.infobar_shown());
+}
+
+// This test was a bit flaky <http://crbug.com/276597>.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+                       DISABLED_PromptForSubmitUsingJavaScript) {
+  ASSERT_TRUE(test_server()->Start());
+
+  GURL url = test_server()->GetURL("files/password/password_form.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Fill a form and submit using <button> that calls submit() on the form.
+  // This should work regardless of the type of element, as long as submit() is
+  // called.
+  NavigationObserver observer(WebContents());
+  std::string fill_and_submit =
+      "document.getElementById('username_field').value = 'temp';"
+      "document.getElementById('password_field').value = 'random';"
+      "document.getElementById('submit_button').click()";
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+  observer.Wait();
+  EXPECT_TRUE(observer.infobar_shown());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
+  ASSERT_TRUE(test_server()->Start());
+
+  GURL url = test_server()->GetURL("files/password/password_form.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Don't fill the password form, just navigate away. Shouldn't prompt.
+  NavigationObserver observer(WebContents());
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
+                                     "window.location.href = 'done.html';"));
+  observer.Wait();
+  EXPECT_FALSE(observer.infobar_shown());
+}
+
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+                       NoPromptForSubFrameNavigation) {
+  ASSERT_TRUE(test_server()->Start());
+
+  GURL url = test_server()->GetURL("files/password/multi_frames.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // If you are filling out a password form in one frame and a different frame
+  // navigates, this should not trigger the infobar.
+  NavigationObserver observer(WebContents());
+  std::string fill =
+      "var first_frame = document.getElementById('first_frame');"
+      "var frame_doc = first_frame.contentDocument;"
+      "frame_doc.getElementById('username_field').value = 'temp';"
+      "frame_doc.getElementById('password_field').value = 'random';";
+  std::string navigate_frame =
+      "var second_iframe = document.getElementById('second_frame');"
+      "second_iframe.contentWindow.location.href = 'done.html';";
+
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
+  observer.Wait();
+  EXPECT_FALSE(observer.infobar_shown());
+}
+
+// This test was a bit flaky <http://crbug.com/276597>.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+                       DISABLED_PromptAfterSubmitWithSubFrameNavigation) {
+  ASSERT_TRUE(test_server()->Start());
+
+  GURL url = test_server()->GetURL("files/password/multi_frames.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Make sure that we prompt to save password even if a sub-frame navigation
+  // happens first.
+  NavigationObserver observer(WebContents());
+  std::string navigate_frame =
+      "var second_iframe = document.getElementById('second_frame');"
+      "second_iframe.contentWindow.location.href = 'done.html';";
+  std::string fill_and_submit =
+      "var first_frame = document.getElementById('first_frame');"
+      "var frame_doc = first_frame.contentDocument;"
+      "frame_doc.getElementById('username_field').value = 'temp';"
+      "frame_doc.getElementById('password_field').value = 'random';"
+      "frame_doc.getElementById('input_submit_button').click();";
+
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
+  observer.Wait();
+  EXPECT_TRUE(observer.infobar_shown());
+}
+
+// This test was a bit flaky <http://crbug.com/276597>.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+                       DISABLED_PromptForXHRSubmit) {
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
diff --git a/chrome/browser/password_manager/password_manager_unittest.cc b/chrome/browser/password_manager/password_manager_unittest.cc
index 45ab851..cecba4f 100644
--- a/chrome/browser/password_manager/password_manager_unittest.cc
+++ b/chrome/browser/password_manager/password_manager_unittest.cc
@@ -30,6 +30,8 @@
 using testing::Return;
 using testing::WithArg;
 
+namespace {
+
 class MockPasswordManagerDelegate : public PasswordManagerDelegate {
  public:
   MOCK_METHOD1(FillPasswordForm, void(const autofill::PasswordFormFillData&));
@@ -46,6 +48,31 @@
   scoped->reset(arg0);
 }
 
+class TestPasswordManager : public PasswordManager {
+ public:
+  TestPasswordManager(content::WebContents* contents,
+                      PasswordManagerDelegate* delegate)
+      : PasswordManager(contents, delegate) {}
+  virtual ~TestPasswordManager() {}
+
+  virtual void OnPasswordFormSubmitted(const PasswordForm& form) OVERRIDE {
+    PasswordManager::OnPasswordFormSubmitted(form);
+  }
+
+  static TestPasswordManager* CreateForWebContentsAndDelegate(
+      content::WebContents* contents,
+      PasswordManagerDelegate* delegate) {
+    TestPasswordManager* tpm = new TestPasswordManager(contents, delegate);
+    contents->SetUserData(UserDataKey(), tpm);
+    return tpm;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestPasswordManager);
+};
+
+}  // namespace
+
 class PasswordManagerTest : public ChromeRenderViewHostTestHarness {
  protected:
   virtual void SetUp() {
@@ -55,7 +82,7 @@
             profile(), MockPasswordStore::Build).get());
 
     EXPECT_CALL(delegate_, GetProfile()).WillRepeatedly(Return(profile()));
-    PasswordManager::CreateForWebContentsAndDelegate(
+    manager_ = TestPasswordManager::CreateForWebContentsAndDelegate(
         web_contents(), &delegate_);
     EXPECT_CALL(delegate_, DidLastPageLoadEncounterSSLErrors())
         .WillRepeatedly(Return(false));
@@ -81,12 +108,50 @@
     return form;
   }
 
-  PasswordManager* manager() {
-    return PasswordManager::FromWebContents(web_contents());
+  bool FormsAreEqual(const content::PasswordForm& lhs,
+                     const content::PasswordForm& rhs) {
+    if (lhs.origin != rhs.origin)
+      return false;
+    if (lhs.action != rhs.action)
+      return false;
+    if (lhs.username_element != rhs.username_element)
+      return false;
+    if (lhs.password_element != rhs.password_element)
+      return false;
+    if (lhs.username_value != rhs.username_value)
+      return false;
+    if (lhs.password_value != rhs.password_value)
+      return false;
+    if (lhs.password_autocomplete_set != rhs.password_autocomplete_set)
+      return false;
+    if (lhs.submit_element != rhs.submit_element)
+      return false;
+    if (lhs.signon_realm != rhs.signon_realm)
+      return false;
+    return true;
+  }
+
+  TestPasswordManager* manager() {
+    return manager_;
+  }
+
+  void OnPasswordFormSubmitted(const content::PasswordForm& form) {
+    manager()->OnPasswordFormSubmitted(form);
+  }
+
+  PasswordManager::PasswordSubmittedCallback SubmissionCallback() {
+    return base::Bind(&PasswordManagerTest::FormSubmitted,
+                      base::Unretained(this));
+  }
+
+  void FormSubmitted(const content::PasswordForm& form) {
+    submitted_form_ = form;
   }
 
   scoped_refptr<MockPasswordStore> store_;
+  TestPasswordManager* manager_;
   MockPasswordManagerDelegate delegate_;  // Owned by manager_.
+  PasswordForm submitted_form_;
 };
 
 MATCHER_P(FormMatches, form, "") {
@@ -208,15 +273,8 @@
   manager()->OnPasswordFormsParsed(observed);  // The initial load.
   manager()->OnPasswordFormsRendered(observed);  // The initial layout.
 
-  PasswordForm empty_form(form);
-  empty_form.username_value = string16();
-  empty_form.password_value = string16();
-  content::LoadCommittedDetails details;
-  content::FrameNavigateParams params;
-  params.password_form = empty_form;
-  manager()->DidNavigateAnyFrame(details, params);
-
-  // No expected calls.
+  // No message from the renderer that a password was submitted. No
+  // expected calls.
   EXPECT_CALL(delegate_, AddSavePasswordInfoBarIfPermitted(_)).Times(0);
   observed.clear();
   manager()->OnPasswordFormsParsed(observed);  // The post-navigation load.
@@ -238,14 +296,11 @@
 
   // Simulate navigating a sub-frame.
   content::LoadCommittedDetails details;
-  details.is_main_frame = false;
   content::FrameNavigateParams params;
   manager()->DidNavigateAnyFrame(details, params);
 
-  // Simulate navigating the real page.
-  details.is_main_frame = true;
-  params.password_form = form;
-  manager()->DidNavigateAnyFrame(details, params);
+  // Simulate submitting the password.
+  OnPasswordFormSubmitted(form);
 
   // Now the password manager waits for the navigation to complete.
   scoped_ptr<PasswordFormManager> form_to_save;
@@ -289,7 +344,7 @@
   content::LoadCommittedDetails details;
   details.is_main_frame = true;
   content::FrameNavigateParams params;
-  manager()->DidNavigateAnyFrame(details, params);
+  manager()->DidNavigateMainFrame(details, params);
 
   // This page contains a form with the same markup, but on a different
   // URL.
@@ -298,8 +353,7 @@
   manager()->OnPasswordFormsRendered(observed);
 
   // Now submit this form
-  params.password_form = second_form;
-  manager()->DidNavigateAnyFrame(details, params);
+  OnPasswordFormSubmitted(second_form);
 
   // Navigation after form submit.
   scoped_ptr<PasswordFormManager> form_to_save;
@@ -475,3 +529,10 @@
   manager()->OnPasswordFormsParsed(observed);  // The post-navigation load.
   manager()->OnPasswordFormsRendered(observed);  // The post-navigation layout.
 }
+
+TEST_F(PasswordManagerTest, SubmissionCallbackTest) {
+  manager()->AddSubmissionCallback(SubmissionCallback());
+  PasswordForm form = MakeSimpleForm();
+  OnPasswordFormSubmitted(form);
+  EXPECT_TRUE(FormsAreEqual(form, submitted_form_));
+}
diff --git a/chrome/browser/performance_monitor/database_unittest.cc b/chrome/browser/performance_monitor/database_unittest.cc
index bde1fe3..950c183 100644
--- a/chrome/browser/performance_monitor/database_unittest.cc
+++ b/chrome/browser/performance_monitor/database_unittest.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/performance_monitor/metric.h"
 #include "chrome/browser/performance_monitor/performance_monitor_util.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
diff --git a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
index bb5a877..a343e04 100644
--- a/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
+++ b/chrome/browser/performance_monitor/performance_monitor_browsertest.cc
@@ -118,7 +118,7 @@
 
 // Verify that we received the proper number of events, checking the type of
 // each one.
-void CheckEventTypes(const std::vector<int> expected_event_types,
+void CheckEventTypes(const std::vector<int>& expected_event_types,
                      const Database::EventVector& events) {
   ASSERT_EQ(expected_event_types.size(), events.size());
 
diff --git a/chrome/browser/platform_util_chromeos.cc b/chrome/browser/platform_util_chromeos.cc
index 49df102..e803c69 100644
--- a/chrome/browser/platform_util_chromeos.cc
+++ b/chrome/browser/platform_util_chromeos.cc
@@ -39,12 +39,12 @@
 
 void ShowItemInFolder(const base::FilePath& full_path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  file_manager::util::ShowFileInFolder(full_path);
+  file_manager::util::ShowItemInFolder(full_path);
 }
 
 void OpenItem(const base::FilePath& full_path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  file_manager::util::ViewItem(full_path);
+  file_manager::util::OpenItem(full_path);
 }
 
 void OpenExternal(const GURL& url) {
diff --git a/chrome/browser/policy/DEPS b/chrome/browser/policy/DEPS
index de734d3..90f0e23 100644
--- a/chrome/browser/policy/DEPS
+++ b/chrome/browser/policy/DEPS
@@ -31,19 +31,6 @@
   ],
 
   # TODO(joaodasilva): remove these exceptions.
-  r"async_policy_loader\.cc": [
-    "+content/public/browser/browser_thread.h",
-  ],
-
-  r"async_policy_provider\.cc": [
-    "+content/public/browser/browser_thread.h",
-  ],
-
-  r"async_policy_provider_unittest\.cc": [
-    "+content/public/browser/browser_thread.h",
-    "+content/public/test/test_browser_thread.h",
-  ],
-
   r"configuration_policy_handler_android\.cc": [
     "+chrome/common/net/url_fixer_upper.h",
     "+chrome/common/pref_names.h",
@@ -51,7 +38,7 @@
 
   r"configuration_policy_handler\.cc": [
     "+chrome/browser/chrome_notification_types.h",
-    "+chrome/browser/download/download_util.h",
+    "+chrome/browser/download/download_prefs.h",
     "+chrome/browser/extensions/external_policy_loader.h",
     "+chrome/browser/prefs/proxy_config_dictionary.h",
     "+chrome/browser/prefs/proxy_prefs.h",
@@ -87,42 +74,10 @@
     "+chrome/common/pref_names.h",
   ],
 
-  r"configuration_policy_provider_test\.h": [
-    "+content/public/test/test_browser_thread.h",
-  ],
-
-  r"policy_domain_descriptor\.cc": [
-    "+chrome/common/policy/policy_schema.h",
-  ],
-
-  r"policy_domain_descriptor_unittest\.cc": [
-    "+chrome/common/policy/policy_schema.h",
-  ],
-
-  r"policy_loader_mac\.cc": [
-    "+chrome/common/chrome_paths.h",
-    "+chrome/common/policy/policy_schema.h",
-  ],
-
-  r"policy_loader_win\.cc": [
-    "+chrome/common/json_schema/json_schema_constants.h",
-  ],
-
-  r"policy_loader_win_unittest\.cc": [
-    "+chrome/common/chrome_paths.h",
-    "+chrome/common/json_schema/json_schema_constants.h",
-  ],
-
   r"policy_path_parser_win\.cc": [
     "+chrome/common/chrome_switches.h",
   ],
 
-  r"policy_service_impl_unittest\.cc": [
-    "+chrome/common/policy/policy_schema.h",
-    "+content/public/browser/browser_thread.h",
-    "+content/public/test/test_browser_thread_bundle.h",
-  ],
-
   r"policy_statistics_collector\.cc": [
     "+chrome/common/pref_names.h",
   ],
@@ -131,20 +86,4 @@
     "+chrome/browser/prefs/browser_prefs.h",
     "+chrome/common/pref_names.h",
   ],
-
-  r"preg_parser_win_unittest\.cc": [
-    "+chrome/common/chrome_paths.h",
-  ],
-
-  r"registry_dict_win\.cc": [
-    "+chrome/common/json_schema/json_schema_constants.h",
-  ],
-
-  r"registry_dict_win_unittest\.cc": [
-    "+chrome/common/json_schema/json_schema_constants.h",
-  ],
-
-  r"test/local_policy_test_server\.cc": [
-    "+chrome/common/chrome_paths.h",
-  ],
 }
diff --git a/chrome/browser/policy/async_policy_loader.cc b/chrome/browser/policy/async_policy_loader.cc
index 7919e3c..05c1bb0 100644
--- a/chrome/browser/policy/async_policy_loader.cc
+++ b/chrome/browser/policy/async_policy_loader.cc
@@ -5,13 +5,13 @@
 #include "chrome/browser/policy/async_policy_loader.h"
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
 #include "chrome/browser/policy/policy_bundle.h"
 #include "chrome/browser/policy/policy_domain_descriptor.h"
-#include "content/public/browser/browser_thread.h"
 
 using base::Time;
 using base::TimeDelta;
-using content::BrowserThread;
 
 namespace policy {
 
@@ -28,8 +28,10 @@
 
 }  // namespace
 
-AsyncPolicyLoader::AsyncPolicyLoader()
-    : weak_factory_(this) {}
+AsyncPolicyLoader::AsyncPolicyLoader(
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : task_runner_(task_runner),
+      weak_factory_(this) {}
 
 AsyncPolicyLoader::~AsyncPolicyLoader() {}
 
@@ -38,7 +40,7 @@
 }
 
 void AsyncPolicyLoader::Reload(bool force) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
 
   TimeDelta delay;
   Time now = Time::Now();
@@ -83,12 +85,12 @@
 }
 
 void AsyncPolicyLoader::Init(const UpdateCallback& update_callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
   DCHECK(update_callback_.is_null());
   DCHECK(!update_callback.is_null());
   update_callback_ = update_callback;
 
-  InitOnFile();
+  InitOnBackgroundThread();
 
   // There might have been changes to the underlying files since the initial
   // load and before the watchers have been created.
@@ -100,14 +102,13 @@
 }
 
 void AsyncPolicyLoader::ScheduleNextReload(TimeDelta delay) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
   weak_factory_.InvalidateWeakPtrs();
-  BrowserThread::PostDelayedTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&AsyncPolicyLoader::Reload,
-                 weak_factory_.GetWeakPtr(),
-                 false  /* force */),
-      delay);
+  task_runner_->PostDelayedTask(FROM_HERE,
+                                base::Bind(&AsyncPolicyLoader::Reload,
+                                           weak_factory_.GetWeakPtr(),
+                                           false /* force */),
+                                delay);
 }
 
 bool AsyncPolicyLoader::IsSafeToReload(const Time& now, TimeDelta* delay) {
diff --git a/chrome/browser/policy/async_policy_loader.h b/chrome/browser/policy/async_policy_loader.h
index ce7b05b..2da0a33 100644
--- a/chrome/browser/policy/async_policy_loader.h
+++ b/chrome/browser/policy/async_policy_loader.h
@@ -14,6 +14,10 @@
 #include "base/time/time.h"
 #include "chrome/browser/policy/policy_service.h"
 
+namespace base {
+class SequencedTaskRunner;
+}
+
 namespace policy {
 
 class PolicyBundle;
@@ -24,31 +28,36 @@
 // periodic reloads, watching file changes, refreshing policies and object
 // lifetime.
 //
-// All methods are invoked on the FILE thread, including the destructor.
-// The only exceptions are the constructor (which may be called on any thread),
-// and the initial Load() which is called on the thread that owns the provider.
+// All methods are invoked on the background |task_runner_|, including the
+// destructor. The only exceptions are the constructor (which may be called on
+// any thread), and the initial Load() which is called on the thread that owns
+// the provider.
 // LastModificationTime() is also invoked once on that thread at startup.
 class AsyncPolicyLoader {
  public:
-  AsyncPolicyLoader();
+  explicit AsyncPolicyLoader(
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
   virtual ~AsyncPolicyLoader();
 
+  // Gets a SequencedTaskRunner backed by the background thread.
+  base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); }
+
   // Returns the currently configured policies. Load() is always invoked on
-  // the FILE thread, except for the initial Load() at startup which is invoked
-  // from the thread that owns the provider.
+  // the background thread, except for the initial Load() at startup which is
+  // invoked from the thread that owns the provider.
   virtual scoped_ptr<PolicyBundle> Load() = 0;
 
-  // Allows implementations to finalize their initialization on the FILE
+  // Allows implementations to finalize their initialization on the background
   // thread (e.g. setup file watchers).
-  virtual void InitOnFile() = 0;
+  virtual void InitOnBackgroundThread() = 0;
 
   // Implementations should return the time of the last modification detected,
   // or base::Time() if it doesn't apply, which is the default.
   virtual base::Time LastModificationTime();
 
   // Implementations should invoke Reload() when a change is detected. This
-  // must be invoked from the FILE thread and will trigger a Load(), and pass
-  // the returned bundle to the provider.
+  // must be invoked from the background thread and will trigger a Load(),
+  // and pass the returned bundle to the provider.
   // The load is immediate when |force| is true. Otherwise, the loader
   // reschedules the reload until the LastModificationTime() is a couple of
   // seconds in the past. This mitigates the problem of reading files that are
@@ -82,7 +91,7 @@
   scoped_ptr<PolicyBundle> InitialLoad();
 
   // Used by the AsyncPolicyProvider to install the |update_callback_|.
-  // Invoked on the FILE thread.
+  // Invoked on the background thread.
   void Init(const UpdateCallback& update_callback);
 
   // Cancels any pending periodic reload and posts one |delay| time units from
@@ -94,6 +103,9 @@
   // before retrying when this returns false.
   bool IsSafeToReload(const base::Time& now, base::TimeDelta* delay);
 
+  // Task runner to run background threads.
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
   // Callback for updates, passed in Init().
   UpdateCallback update_callback_;
 
diff --git a/chrome/browser/policy/async_policy_provider.cc b/chrome/browser/policy/async_policy_provider.cc
index 7f821d8..f564482 100644
--- a/chrome/browser/policy/async_policy_provider.cc
+++ b/chrome/browser/policy/async_policy_provider.cc
@@ -6,14 +6,13 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_loop_proxy.h"
+#include "base/sequenced_task_runner.h"
 #include "chrome/browser/policy/async_policy_loader.h"
 #include "chrome/browser/policy/policy_bundle.h"
 #include "chrome/browser/policy/policy_domain_descriptor.h"
-#include "content/public/browser/browser_thread.h"
-
-using content::BrowserThread;
 
 namespace policy {
 
@@ -41,8 +40,8 @@
       base::Bind(&AsyncPolicyProvider::LoaderUpdateCallback,
                  base::MessageLoopProxy::current(),
                  weak_factory_.GetWeakPtr());
-  bool post = BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
+  bool post = loader_->task_runner()->PostTask(
+      FROM_HERE,
       base::Bind(&AsyncPolicyLoader::Init,
                  base::Unretained(loader_),
                  callback));
@@ -52,13 +51,14 @@
 void AsyncPolicyProvider::Shutdown() {
   DCHECK(CalledOnValidThread());
   // Note on the lifetime of |loader_|:
-  // The |loader_| lives on the FILE thread, and is deleted from here. This
-  // means that posting tasks on the |loader_| to FILE from the
-  // AsyncPolicyProvider is always safe, since a potential DeleteSoon() is only
-  // posted from here. The |loader_| posts back to the AsyncPolicyProvider
-  // through the |update_callback_|, which has a WeakPtr to |this|.
-  if (!BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, loader_)) {
-    // The FILE thread doesn't exist; this only happens on unit tests.
+  // The |loader_| lives on the background thread, and is deleted from here.
+  // This means that posting tasks on the |loader_| to the background thread
+  // from the AsyncPolicyProvider is always safe, since a potential DeleteSoon()
+  // is only posted from here. The |loader_| posts back to the
+  // AsyncPolicyProvider through the |update_callback_|, which has a WeakPtr to
+  // |this|.
+  if (!loader_->task_runner()->DeleteSoon(FROM_HERE, loader_)) {
+    // The background thread doesn't exist; this only happens on unit tests.
     delete loader_;
   }
   loader_ = NULL;
@@ -75,14 +75,16 @@
   // should already be provided.
   // However, it's also possible that an asynchronous Reload() is in progress
   // and just posted OnLoaderReloaded(). Therefore a task is posted to the
-  // FILE thread before posting the next Reload, to prevent a potential
+  // background thread before posting the next Reload, to prevent a potential
   // concurrent Reload() from triggering a notification too early. If another
   // refresh task has been posted, it is invalidated now.
+  if (!loader_)
+    return;
   refresh_callback_.Reset(
       base::Bind(&AsyncPolicyProvider::ReloadAfterRefreshSync,
                  weak_factory_.GetWeakPtr()));
-  BrowserThread::PostTaskAndReply(
-      BrowserThread::FILE, FROM_HERE,
+  loader_->task_runner()->PostTaskAndReply(
+      FROM_HERE,
       base::Bind(base::DoNothing),
       refresh_callback_.callback());
 }
@@ -90,11 +92,11 @@
 void AsyncPolicyProvider::RegisterPolicyDomain(
     scoped_refptr<const PolicyDomainDescriptor> descriptor) {
   if (loader_) {
-    BrowserThread::PostTask(BrowserThread::FILE,
-                            FROM_HERE,
-                            base::Bind(&AsyncPolicyLoader::RegisterPolicyDomain,
-                                       base::Unretained(loader_),
-                                       descriptor));
+    loader_->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&AsyncPolicyLoader::RegisterPolicyDomain,
+                   base::Unretained(loader_),
+                   descriptor));
   }
 }
 
@@ -112,11 +114,10 @@
   if (!loader_)
     return;
 
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&AsyncPolicyLoader::Reload,
-                 base::Unretained(loader_),
-                 true  /* force */));
+  loader_->task_runner()->PostTask(FROM_HERE,
+                                   base::Bind(&AsyncPolicyLoader::Reload,
+                                              base::Unretained(loader_),
+                                              true /* force */));
 }
 
 void AsyncPolicyProvider::OnLoaderReloaded(scoped_ptr<PolicyBundle> bundle) {
@@ -132,7 +133,6 @@
     scoped_refptr<base::MessageLoopProxy> loop,
     base::WeakPtr<AsyncPolicyProvider> weak_this,
     scoped_ptr<PolicyBundle> bundle) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   loop->PostTask(FROM_HERE,
                  base::Bind(&AsyncPolicyProvider::OnLoaderReloaded,
                             weak_this,
diff --git a/chrome/browser/policy/async_policy_provider.h b/chrome/browser/policy/async_policy_provider.h
index 7352f13..3302b96 100644
--- a/chrome/browser/policy/async_policy_provider.h
+++ b/chrome/browser/policy/async_policy_provider.h
@@ -21,9 +21,9 @@
 class AsyncPolicyLoader;
 class PolicyBundle;
 
-// A policy provider that loads its policies asynchronously on the FILE thread.
-// Platform-specific providers are created by passing an implementation of
-// AsyncPolicyLoader to a new AsyncPolicyProvider.
+// A policy provider that loads its policies asynchronously on a background
+// thread. Platform-specific providers are created by passing an implementation
+// of AsyncPolicyLoader to a new AsyncPolicyProvider.
 class AsyncPolicyProvider : public ConfigurationPolicyProvider,
                             public base::NonThreadSafe {
  public:
@@ -45,23 +45,23 @@
   void OnLoaderReloaded(scoped_ptr<PolicyBundle> bundle);
 
   // Callback passed to the loader that it uses to pass back the current policy
-  // bundle to the provider. This is invoked on the FILE thread and forwards
-  // to OnLoaderReloaded() on the loop that owns the provider, if |weak_this| is
-  // still valid.
+  // bundle to the provider. This is invoked on the background thread and
+  // forwards to OnLoaderReloaded() on the loop that owns the provider,
+  // if |weak_this| is still valid.
   static void LoaderUpdateCallback(scoped_refptr<base::MessageLoopProxy> loop,
                                    base::WeakPtr<AsyncPolicyProvider> weak_this,
                                    scoped_ptr<PolicyBundle> bundle);
 
   // The |loader_| that does the platform-specific policy loading. It lives
-  // on the FILE thread but is owned by |this|.
+  // on the background thread but is owned by |this|.
   AsyncPolicyLoader* loader_;
 
   // Used to get a WeakPtr to |this| for the update callback given to the
   // loader.
   base::WeakPtrFactory<AsyncPolicyProvider> weak_factory_;
 
-  // Callback used to synchronize RefreshPolicies() calls with the FILE thread.
-  // See the implementation for the details.
+  // Callback used to synchronize RefreshPolicies() calls with the background
+  // thread. See the implementation for the details.
   base::CancelableClosure refresh_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(AsyncPolicyProvider);
diff --git a/chrome/browser/policy/async_policy_provider_unittest.cc b/chrome/browser/policy/async_policy_provider_unittest.cc
index 89015fc..677dba8 100644
--- a/chrome/browser/policy/async_policy_provider_unittest.cc
+++ b/chrome/browser/policy/async_policy_provider_unittest.cc
@@ -5,13 +5,14 @@
 #include "chrome/browser/policy/async_policy_provider.h"
 
 #include "base/callback.h"
+#include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/sequenced_task_runner.h"
 #include "base/values.h"
 #include "chrome/browser/policy/async_policy_loader.h"
 #include "chrome/browser/policy/external_data_fetcher.h"
 #include "chrome/browser/policy/mock_configuration_policy_provider.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread.h"
 #include "policy/policy_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,7 +39,8 @@
 
 class MockPolicyLoader : public AsyncPolicyLoader {
  public:
-  MockPolicyLoader();
+  explicit MockPolicyLoader(
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
   virtual ~MockPolicyLoader();
 
   // Load() returns a scoped_ptr<PolicyBundle> but it can't be mocked because
@@ -48,14 +50,16 @@
   virtual scoped_ptr<PolicyBundle> Load() OVERRIDE;
 
   MOCK_METHOD0(MockLoad, const PolicyBundle*());
-  MOCK_METHOD0(InitOnFile, void());
+  MOCK_METHOD0(InitOnBackgroundThread, void());
   MOCK_METHOD0(LastModificationTime, base::Time());
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockPolicyLoader);
 };
 
-MockPolicyLoader::MockPolicyLoader() {}
+MockPolicyLoader::MockPolicyLoader(
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : AsyncPolicyLoader(task_runner) {}
 
 MockPolicyLoader::~MockPolicyLoader() {}
 
@@ -79,31 +83,25 @@
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
+  base::MessageLoop loop_;
   PolicyBundle initial_bundle_;
   MockPolicyLoader* loader_;
   scoped_ptr<AsyncPolicyProvider> provider_;
 
-  base::MessageLoop loop_;
-
  private:
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-
   DISALLOW_COPY_AND_ASSIGN(AsyncPolicyProviderTest);
 };
 
-AsyncPolicyProviderTest::AsyncPolicyProviderTest()
-    : ui_thread_(content::BrowserThread::UI, &loop_),
-      file_thread_(content::BrowserThread::FILE, &loop_) {}
+AsyncPolicyProviderTest::AsyncPolicyProviderTest() {}
 
 AsyncPolicyProviderTest::~AsyncPolicyProviderTest() {}
 
 void AsyncPolicyProviderTest::SetUp() {
   SetPolicy(&initial_bundle_, "policy", "initial");
-  loader_ = new MockPolicyLoader();
+  loader_ = new MockPolicyLoader(loop_.message_loop_proxy());
   EXPECT_CALL(*loader_, LastModificationTime())
       .WillRepeatedly(Return(base::Time()));
-  EXPECT_CALL(*loader_, InitOnFile()).Times(1);
+  EXPECT_CALL(*loader_, InitOnBackgroundThread()).Times(1);
   EXPECT_CALL(*loader_, MockLoad()).WillOnce(Return(&initial_bundle_));
 
   provider_.reset(
@@ -151,7 +149,7 @@
   provider_->AddObserver(&observer);
   EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
   provider_->RefreshPolicies();
-  // Doesn't refresh before going through the FILE thread.
+  // Doesn't refresh before going through the background thread.
   Mock::VerifyAndClearExpectations(&observer);
 
   // Doesn't refresh if another RefreshPolicies request is made.
@@ -190,7 +188,7 @@
   loader_->Reload(true);
   Mock::VerifyAndClearExpectations(&observer);
 
-  // Doesn't refresh before going through the FILE thread.
+  // Doesn't refresh before going through the background thread.
   EXPECT_CALL(observer, OnUpdatePolicy(provider_.get())).Times(0);
   provider_->RefreshPolicies();
   Mock::VerifyAndClearExpectations(&observer);
diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc
index 022c2e2..f8e8805 100644
--- a/chrome/browser/policy/browser_policy_connector.cc
+++ b/chrome/browser/policy/browser_policy_connector.cc
@@ -13,10 +13,12 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/async_policy_provider.h"
@@ -42,7 +44,8 @@
 
 #if defined(OS_WIN)
 #include "chrome/browser/policy/policy_loader_win.h"
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#include <CoreFoundation/CoreFoundation.h>
 #include "chrome/browser/policy/policy_loader_mac.h"
 #include "chrome/browser/policy/preferences_mac.h"
 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
@@ -50,7 +53,6 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/policy/app_pack_updater.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
@@ -61,7 +63,6 @@
 #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
 #include "chrome/browser/chromeos/policy/network_configuration_updater.h"
 #include "chrome/browser/chromeos/policy/network_configuration_updater_impl.h"
-#include "chrome/browser/chromeos/policy/network_configuration_updater_impl_cros.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/cros_settings_provider.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -72,7 +73,7 @@
 #include "chromeos/cryptohome/cryptohome_library.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/network/managed_network_configuration_handler.h"
+#include "chromeos/network/network_handler.h"
 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
 #endif
 
@@ -94,6 +95,30 @@
 // Used in BrowserPolicyConnector::SetPolicyProviderForTesting.
 ConfigurationPolicyProvider* g_testing_provider = NULL;
 
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+base::FilePath GetManagedPolicyPath() {
+  // This constructs the path to the plist file in which Mac OS X stores the
+  // managed preference for the application. This is undocumented and therefore
+  // fragile, but if it doesn't work out, AsyncPolicyLoader has a task that
+  // polls periodically in order to reload managed preferences later even if we
+  // missed the change.
+  base::FilePath path;
+  if (!PathService::Get(chrome::DIR_MANAGED_PREFS, &path))
+    return base::FilePath();
+
+  CFBundleRef bundle(CFBundleGetMainBundle());
+  if (!bundle)
+    return base::FilePath();
+
+  CFStringRef bundle_id = CFBundleGetIdentifier(bundle);
+  if (!bundle_id)
+    return base::FilePath();
+
+  return path.Append(base::SysCFStringRefToUTF8(bundle_id) + ".plist");
+}
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
 }  // namespace
 
 BrowserPolicyConnector::BrowserPolicyConnector()
@@ -206,9 +231,9 @@
   policy_statistics_collector_->Initialize();
 
 #if defined(OS_CHROMEOS)
-
   network_configuration_updater_.reset(new NetworkConfigurationUpdaterImpl(
       GetPolicyService(),
+      chromeos::NetworkHandler::Get()->managed_network_configuration_handler(),
       scoped_ptr<chromeos::onc::CertificateImporter>(
           new chromeos::onc::CertificateImporterImpl)));
 #endif
@@ -349,11 +374,6 @@
 }
 #endif
 
-void BrowserPolicyConnector::SetDeviceManagementServiceForTesting(
-    scoped_ptr<DeviceManagementService> service) {
-  device_management_service_ = service.Pass();
-}
-
 // static
 void BrowserPolicyConnector::SetPolicyProviderForTesting(
     ConfigurationPolicyProvider* provider) {
@@ -460,18 +480,25 @@
 ConfigurationPolicyProvider* BrowserPolicyConnector::CreatePlatformProvider() {
 #if defined(OS_WIN)
   const PolicyDefinitionList* policy_list = GetChromePolicyDefinitionList();
-  scoped_ptr<AsyncPolicyLoader> loader(PolicyLoaderWin::Create(policy_list));
+  scoped_ptr<AsyncPolicyLoader> loader(PolicyLoaderWin::Create(
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
+      policy_list));
   return new AsyncPolicyProvider(loader.Pass());
-#elif defined(OS_MACOSX)
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
   const PolicyDefinitionList* policy_list = GetChromePolicyDefinitionList();
-  scoped_ptr<AsyncPolicyLoader> loader(
-      new PolicyLoaderMac(policy_list, new MacPreferences()));
+  scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderMac(
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
+      policy_list,
+      GetManagedPolicyPath(),
+      new MacPreferences()));
   return new AsyncPolicyProvider(loader.Pass());
 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
   base::FilePath config_dir_path;
   if (PathService::Get(chrome::DIR_POLICY_FILES, &config_dir_path)) {
-    scoped_ptr<AsyncPolicyLoader> loader(
-        new ConfigDirPolicyLoader(config_dir_path, POLICY_SCOPE_MACHINE));
+    scoped_ptr<AsyncPolicyLoader> loader(new ConfigDirPolicyLoader(
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
+        config_dir_path,
+        POLICY_SCOPE_MACHINE));
     return new AsyncPolicyProvider(loader.Pass());
   } else {
     return NULL;
diff --git a/chrome/browser/policy/browser_policy_connector.h b/chrome/browser/policy/browser_policy_connector.h
index 1c067b4..9f37bdb 100644
--- a/chrome/browser/policy/browser_policy_connector.h
+++ b/chrome/browser/policy/browser_policy_connector.h
@@ -139,11 +139,6 @@
   void SetUserPolicyDelegate(ConfigurationPolicyProvider* user_policy_provider);
 #endif
 
-  // Allows setting a DeviceManagementService (for injecting mocks in
-  // unit tests).
-  void SetDeviceManagementServiceForTesting(
-      scoped_ptr<DeviceManagementService> service);
-
   // Sets a |provider| that will be included in PolicyServices returned by
   // CreatePolicyService. This is a static method because local state is
   // created immediately after the connector, and tests don't have a chance to
diff --git a/chrome/browser/policy/cloud/DEPS b/chrome/browser/policy/cloud/DEPS
index 0f3934a..fdfd970 100644
--- a/chrome/browser/policy/cloud/DEPS
+++ b/chrome/browser/policy/cloud/DEPS
@@ -91,7 +91,6 @@
   ],
 
   r"component_cloud_policy_service_unittest\.cc": [
-    "+chrome/common/policy/policy_schema.h",
     "+content/public/browser/browser_thread.h",
     "+content/public/test/test_browser_thread.h",
   ],
diff --git a/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.cc b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.cc
index 224977f..0f0e7be 100644
--- a/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.cc
@@ -11,13 +11,13 @@
 #include "base/logging.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "chrome/browser/signin/oauth2_token_service.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/signin/android_profile_oauth2_token_service.h"
-#include "chrome/browser/signin/oauth2_token_service.h"
 #else
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
@@ -25,8 +25,6 @@
 
 namespace policy {
 
-namespace {
-
 // OAuth2 scope for the userinfo service.
 const char kServiceScopeGetUserInfo[] =
     "https://www.googleapis.com/auth/userinfo.email";
@@ -37,22 +35,25 @@
 
 typedef base::Callback<void(const std::string&)> StringCallback;
 
-}  // namespace
-
-#if defined(OS_ANDROID)
-
 // This class fetches an OAuth2 token scoped for the userinfo and DM services.
-// The AccountManager is used to mint the token on the Java side, given the
-// username of an account that is known to exist on the device.
-// This allows fetching the token before the sign-in process is finished.
-class CloudPolicyClientRegistrationHelper::TokenHelperAndroid
+// On Android, we use a special API to allow us to fetch a token for an account
+// that is not yet logged in to allow fetching the token before the sign-in
+// process is finished.
+class CloudPolicyClientRegistrationHelper::TokenServiceHelper
     : public OAuth2TokenService::Consumer {
  public:
-  TokenHelperAndroid();
+  TokenServiceHelper();
 
-  void FetchAccessToken(AndroidProfileOAuth2TokenService* token_service,
-                        const std::string& username,
-                        const StringCallback& callback);
+  void FetchAccessToken(
+#if defined(OS_ANDROID)
+      // TODO(atwilson): Remove this when StartRequestForUsername() is merged
+      // into the base OAuth2TokenService class.
+      AndroidProfileOAuth2TokenService* token_service,
+#else
+      OAuth2TokenService* token_service,
+#endif
+      const std::string& username,
+      const StringCallback& callback);
 
  private:
   // OAuth2TokenService::Consumer implementation:
@@ -66,23 +67,35 @@
   scoped_ptr<OAuth2TokenService::Request> token_request_;
 };
 
-CloudPolicyClientRegistrationHelper::TokenHelperAndroid::TokenHelperAndroid() {}
+CloudPolicyClientRegistrationHelper::TokenServiceHelper::TokenServiceHelper() {}
 
-void CloudPolicyClientRegistrationHelper::TokenHelperAndroid::FetchAccessToken(
+void CloudPolicyClientRegistrationHelper::TokenServiceHelper::FetchAccessToken(
+#if defined(OS_ANDROID)
     AndroidProfileOAuth2TokenService* token_service,
+#else
+    OAuth2TokenService* token_service,
+#endif
     const std::string& username,
     const StringCallback& callback) {
+  DCHECK(!token_request_);
+  // Either the caller must supply a username, or the user must be signed in
+  // already.
+  DCHECK(!username.empty() || token_service->RefreshTokenIsAvailable());
   callback_ = callback;
 
   OAuth2TokenService::ScopeSet scopes;
   scopes.insert(GaiaConstants::kDeviceManagementServiceOAuth);
   scopes.insert(kServiceScopeGetUserInfo);
 
+#if defined(OS_ANDROID)
   token_request_ =
       token_service->StartRequestForUsername(username, scopes, this);
+#else
+  token_request_ = token_service->StartRequest(scopes, this);
+#endif
 }
 
-void CloudPolicyClientRegistrationHelper::TokenHelperAndroid::OnGetTokenSuccess(
+void CloudPolicyClientRegistrationHelper::TokenServiceHelper::OnGetTokenSuccess(
     const OAuth2TokenService::Request* request,
     const std::string& access_token,
     const base::Time& expiration_time) {
@@ -90,22 +103,23 @@
   callback_.Run(access_token);
 }
 
-void CloudPolicyClientRegistrationHelper::TokenHelperAndroid::OnGetTokenFailure(
+void CloudPolicyClientRegistrationHelper::TokenServiceHelper::OnGetTokenFailure(
     const OAuth2TokenService::Request* request,
     const GoogleServiceAuthError& error) {
   DCHECK_EQ(token_request_.get(), request);
   callback_.Run("");
 }
 
-#else
-
+#if !defined(OS_ANDROID)
 // This class fetches the OAuth2 token scoped for the userinfo and DM services.
 // It uses an OAuth2AccessTokenFetcher to fetch it, given a login refresh token
-// that can be used to authorize that request.
-class CloudPolicyClientRegistrationHelper::TokenHelper
+// that can be used to authorize that request. This class is not needed on
+// Android because we can use OAuth2TokenService to fetch tokens for accounts
+// even before they are signed in.
+class CloudPolicyClientRegistrationHelper::LoginTokenHelper
     : public OAuth2AccessTokenConsumer {
  public:
-  TokenHelper();
+  LoginTokenHelper();
 
   void FetchAccessToken(const std::string& login_refresh_token,
                         net::URLRequestContextGetter* context,
@@ -122,12 +136,13 @@
   scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
 };
 
-CloudPolicyClientRegistrationHelper::TokenHelper::TokenHelper() {}
+CloudPolicyClientRegistrationHelper::LoginTokenHelper::LoginTokenHelper() {}
 
-void CloudPolicyClientRegistrationHelper::TokenHelper::FetchAccessToken(
+void CloudPolicyClientRegistrationHelper::LoginTokenHelper::FetchAccessToken(
     const std::string& login_refresh_token,
     net::URLRequestContextGetter* context,
     const StringCallback& callback) {
+  DCHECK(!oauth2_access_token_fetcher_);
   callback_ = callback;
 
   // Start fetching an OAuth2 access token for the device management and
@@ -145,13 +160,13 @@
       scopes);
 }
 
-void CloudPolicyClientRegistrationHelper::TokenHelper::OnGetTokenSuccess(
+void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenSuccess(
     const std::string& access_token,
     const base::Time& expiration_time) {
   callback_.Run(access_token);
 }
 
-void CloudPolicyClientRegistrationHelper::TokenHelper::OnGetTokenFailure(
+void CloudPolicyClientRegistrationHelper::LoginTokenHelper::OnGetTokenFailure(
     const GoogleServiceAuthError& error) {
   callback_.Run("");
 }
@@ -178,10 +193,13 @@
     client_->RemoveObserver(this);
 }
 
-#if defined(OS_ANDROID)
 
 void CloudPolicyClientRegistrationHelper::StartRegistration(
+#if defined(OS_ANDROID)
     AndroidProfileOAuth2TokenService* token_service,
+#else
+    OAuth2TokenService* token_service,
+#endif
     const std::string& username,
     const base::Closure& callback) {
   DVLOG(1) << "Starting registration process with username";
@@ -189,16 +207,15 @@
   callback_ = callback;
   client_->AddObserver(this);
 
-  token_helper_.reset(new TokenHelperAndroid());
-  token_helper_->FetchAccessToken(
+  token_service_helper_.reset(new TokenServiceHelper());
+  token_service_helper_->FetchAccessToken(
       token_service,
       username,
       base::Bind(&CloudPolicyClientRegistrationHelper::OnTokenFetched,
                  base::Unretained(this)));
 }
 
-#else
-
+#if !defined(OS_ANDROID)
 void CloudPolicyClientRegistrationHelper::StartRegistrationWithLoginToken(
     const std::string& login_refresh_token,
     const base::Closure& callback) {
@@ -207,19 +224,22 @@
   callback_ = callback;
   client_->AddObserver(this);
 
-  token_helper_.reset(new TokenHelper());
-  token_helper_->FetchAccessToken(
+  login_token_helper_.reset(
+      new CloudPolicyClientRegistrationHelper::LoginTokenHelper());
+  login_token_helper_->FetchAccessToken(
       login_refresh_token,
       context_,
       base::Bind(&CloudPolicyClientRegistrationHelper::OnTokenFetched,
                  base::Unretained(this)));
 }
-
 #endif
 
 void CloudPolicyClientRegistrationHelper::OnTokenFetched(
     const std::string& access_token) {
-  token_helper_.reset();
+#if !defined(OS_ANDROID)
+  login_token_helper_.reset();
+#endif
+  token_service_helper_.reset();
 
   if (access_token.empty()) {
     DLOG(WARNING) << "Could not fetch access token for "
diff --git a/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h
index 330cfbd..cb26ed5 100644
--- a/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h
+++ b/chrome/browser/policy/cloud/cloud_policy_client_registration_helper.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 
 class AndroidProfileOAuth2TokenService;
+class OAuth2TokenService;
 
 namespace net {
 class URLRequestContextGetter;
@@ -40,15 +41,23 @@
       enterprise_management::DeviceRegisterRequest::Type registration_type);
   virtual ~CloudPolicyClientRegistrationHelper();
 
-#if defined(OS_ANDROID)
   // Starts the client registration process. This version uses the
-  // AndroidProfileOAuth2TokenService to mint the new token for the userinfo
+  // supplied OAuth2TokenService to mint the new token for the userinfo
   // and DM services, using the |username| account.
   // |callback| is invoked when the registration is complete.
-  void StartRegistration(AndroidProfileOAuth2TokenService* token_service,
-                         const std::string& username,
-                         const base::Closure& callback);
+  void StartRegistration(
+#if defined(OS_ANDROID)
+      // TODO(atwilson): Remove this when the Android StartRequestForUsername()
+      // API is folded into the base OAuth2TokenService class (when that class
+      // is made multi-account aware).
+      AndroidProfileOAuth2TokenService* token_service,
 #else
+      OAuth2TokenService* token_service,
+#endif
+      const std::string& username,
+      const base::Closure& callback);
+
+#if !defined(OS_ANDROID)
   // Starts the client registration process. The |login_refresh_token| is used
   // to mint a new token for the userinfo and DM services.
   // |callback| is invoked when the registration is complete.
@@ -57,10 +66,9 @@
 #endif
 
  private:
-#if defined(OS_ANDROID)
-  class TokenHelperAndroid;
-#else
-  class TokenHelper;
+  class TokenServiceHelper;
+#if !defined(OS_ANDROID)
+  class LoginTokenHelper;
 #endif
 
   void OnTokenFetched(const std::string& oauth_access_token);
@@ -79,13 +87,17 @@
   // Invoked when the registration request has been completed.
   void RequestCompleted();
 
-  // Internal helper used to fetch the access token. There is an OS_ANDROID
-  // implementation which uses the AccountManager and a known account name,
-  // and a desktop implementation which uses an OAuth2AccessTokenFetcher.
-#if defined(OS_ANDROID)
-  scoped_ptr<TokenHelperAndroid> token_helper_;
-#else
-  scoped_ptr<TokenHelper> token_helper_;
+  // Internal helper class that uses OAuth2TokenService to fetch an OAuth
+  // access token. On desktop, this is only used after the user has signed in -
+  // desktop platforms use LoginTokenHelper for policy fetches performed before
+  // signin is complete.
+  scoped_ptr<TokenServiceHelper> token_service_helper_;
+
+#if !defined(OS_ANDROID)
+  // Special desktop-only helper to fetch an OAuth access token prior to
+  // the completion of signin. Not used on Android since all token fetching
+  // is done via OAuth2TokenService.
+  scoped_ptr<LoginTokenHelper> login_token_helper_;
 #endif
 
   // Helper class for fetching information from GAIA about the currently
diff --git a/chrome/browser/policy/cloud/cloud_policy_manager_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_manager_unittest.cc
index ee3422d..04bfdaf 100644
--- a/chrome/browser/policy/cloud/cloud_policy_manager_unittest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_manager_unittest.cc
@@ -40,6 +40,7 @@
   virtual void SetUp() OVERRIDE;
 
   virtual ConfigurationPolicyProvider* CreateProvider(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_definition_list) OVERRIDE;
 
   virtual void InstallEmptyPolicy() OVERRIDE;
@@ -74,6 +75,7 @@
 void TestHarness::SetUp() {}
 
 ConfigurationPolicyProvider* TestHarness::CreateProvider(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
     const PolicyDefinitionList* policy_definition_list) {
   // Create and initialize the store.
   store_.NotifyStoreLoaded();
diff --git a/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc b/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
index 5fb06e3..0d95a7c 100644
--- a/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
+++ b/chrome/browser/policy/cloud/component_cloud_policy_service_unittest.cc
@@ -24,7 +24,7 @@
 #include "chrome/browser/policy/policy_types.h"
 #include "chrome/browser/policy/proto/cloud/chrome_extension_policy.pb.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
-#include "chrome/common/policy/policy_schema.h"
+#include "components/policy/core/common/policy_schema.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread.h"
 #include "net/url_request/test_url_fetcher_factory.h"
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc b/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc
index 42ec772..2e6e767 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.cc
@@ -43,8 +43,8 @@
 BrowserContextKeyedService*
     UserCloudPolicyInvalidatorFactory::BuildServiceInstanceFor(
         content::BrowserContext* context) const {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableCloudPolicyPush)) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kDisableCloudPolicyPush)) {
     return NULL;
   }
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.cc b/chrome/browser/policy/cloud/user_policy_signin_service.cc
index eafb1d3..baef750 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.cc
@@ -14,10 +14,9 @@
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.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 "chrome/browser/signin/token_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
@@ -26,32 +25,43 @@
 namespace policy {
 
 UserPolicySigninService::UserPolicySigninService(
-    Profile* profile) : UserPolicySigninServiceBase(profile) {
+    Profile* profile,
+    PrefService* local_state,
+    DeviceManagementService* device_management_service,
+    ProfileOAuth2TokenService* token_service)
+    : UserPolicySigninServiceBase(profile,
+                                  local_state,
+                                  device_management_service),
+      oauth2_token_service_(token_service) {
   if (profile->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
     return;
 
+  // ProfileOAuth2TokenService should not yet have loaded its tokens since this
+  // happens in the background after PKS initialization - so this service
+  // should always be created before the oauth token is available.
+  DCHECK(!oauth2_token_service_->RefreshTokenIsAvailable());
+
   // Listen for an OAuth token to become available so we can register a client
   // if for some reason the client is not already registered (for example, if
   // the policy load failed during initial signin).
-  registrar()->Add(this,
-                   chrome::NOTIFICATION_TOKEN_AVAILABLE,
-                   content::Source<TokenService>(
-                       TokenServiceFactory::GetForProfile(profile)));
-
-  // TokenService should not yet have loaded its tokens since this happens in
-  // the background after PKS initialization - so this service should always be
-  // created before the oauth token is available.
-  DCHECK(!TokenServiceFactory::GetForProfile(profile)->HasOAuthLoginToken());
+  oauth2_token_service_->AddObserver(this);
 }
 
-UserPolicySigninService::~UserPolicySigninService() {}
+UserPolicySigninService::~UserPolicySigninService() {
+}
 
-void UserPolicySigninService::Shutdown() {
+void UserPolicySigninService::PrepareForUserCloudPolicyManagerShutdown() {
   // Stop any pending registration helper activity. We do this here instead of
   // in the destructor because we want to shutdown the registration helper
   // before UserCloudPolicyManager shuts down the CloudPolicyClient.
   registration_helper_.reset();
+
+  UserPolicySigninServiceBase::PrepareForUserCloudPolicyManagerShutdown();
+}
+
+void UserPolicySigninService::Shutdown() {
   UserPolicySigninServiceBase::Shutdown();
+  oauth2_token_service_->RemoveObserver(this);
 }
 
 void UserPolicySigninService::RegisterPolicyClient(
@@ -93,44 +103,21 @@
   callback.Run(client.Pass());
 }
 
-void UserPolicySigninService::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-
-  if (profile()->IsManaged()) {
-    registrar()->RemoveAll();
-    return;
-  }
-
-  // If using a TestingProfile with no SigninManager or UserCloudPolicyManager,
-  // skip initialization.
-  if (!GetManager() || !SigninManagerFactory::GetForProfile(profile())) {
+void UserPolicySigninService::OnRefreshTokenAvailable(
+    const std::string& account_id) {
+  // If using a TestingProfile with no UserCloudPolicyManager, skip
+  // initialization.
+  if (!GetManager()) {
     DVLOG(1) << "Skipping initialization for tests due to missing components.";
     return;
   }
 
-  switch (type) {
-    case chrome::NOTIFICATION_TOKEN_AVAILABLE: {
-      const TokenService::TokenAvailableDetails& token_details =
-          *(content::Details<const TokenService::TokenAvailableDetails>(
-              details).ptr());
-      if (token_details.service() ==
-              GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
-        SigninManager* signin_manager =
-            SigninManagerFactory::GetForProfile(profile());
-        std::string username = signin_manager->GetAuthenticatedUsername();
-        // Should not have GAIA tokens if the user isn't signed in.
-        DCHECK(!username.empty());
-        // TokenService now has a refresh token (implying that the user is
-        // signed in) so initialize the UserCloudPolicyManager.
-        InitializeForSignedInUser(username);
-      }
-      break;
-    }
-    default:
-      UserPolicySigninServiceBase::Observe(type, source, details);
-  }
+  std::string username = GetSigninManager()->GetAuthenticatedUsername();
+  // Should not have OAuth tokens if the user isn't signed in.
+  DCHECK(!username.empty());
+  // ProfileOAuth2TokenService now has a refresh token so initialize the
+  // UserCloudPolicyManager.
+  InitializeForSignedInUser(username);
 }
 
 void UserPolicySigninService::InitializeUserCloudPolicyManager(
@@ -141,10 +128,9 @@
 
 void UserPolicySigninService::ShutdownUserCloudPolicyManager() {
   UserCloudPolicyManager* manager = GetManager();
-  if (manager) {
-    // Allow the user to signout again.
-    SigninManagerFactory::GetForProfile(profile())->ProhibitSignout(false);
-  }
+  // Allow the user to signout again.
+  if (manager)
+    GetSigninManager()->ProhibitSignout(false);
   UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager();
 }
 
@@ -159,22 +145,19 @@
   DVLOG_IF(1, manager->IsClientRegistered())
       << "Client already registered - not fetching DMToken";
   if (!manager->IsClientRegistered()) {
-    std::string token = TokenServiceFactory::GetForProfile(profile())->
-        GetOAuth2LoginRefreshToken();
-    if (token.empty()) {
-      // No token yet - this class listens for NOTIFICATION_TOKEN_AVAILABLE
+    if (!oauth2_token_service_->RefreshTokenIsAvailable()) {
+      // No token yet - this class listens for OnRefreshTokenAvailable()
       // and will re-attempt registration once the token is available.
       DLOG(WARNING) << "No OAuth Refresh Token - delaying policy download";
       return;
     }
-    RegisterCloudPolicyService(token);
+    RegisterCloudPolicyService();
   }
   // If client is registered now, prohibit signout.
   ProhibitSignoutIfNeeded();
 }
 
-void UserPolicySigninService::RegisterCloudPolicyService(
-    const std::string& login_token) {
+void UserPolicySigninService::RegisterCloudPolicyService() {
   DCHECK(!GetManager()->IsClientRegistered());
   DVLOG(1) << "Fetching new DM Token";
   // Do nothing if already starting the registration process.
@@ -188,8 +171,9 @@
       GetManager()->core()->client(),
       ShouldForceLoadPolicy(),
       enterprise_management::DeviceRegisterRequest::BROWSER));
-  registration_helper_->StartRegistrationWithLoginToken(
-      login_token,
+  registration_helper_->StartRegistration(
+      oauth2_token_service_,
+      GetSigninManager()->GetAuthenticatedUsername(),
       base::Bind(&UserPolicySigninService::OnRegistrationComplete,
                  base::Unretained(this)));
 }
@@ -202,9 +186,7 @@
 void UserPolicySigninService::ProhibitSignoutIfNeeded() {
   if (GetManager()->IsClientRegistered()) {
     DVLOG(1) << "User is registered for policy - prohibiting signout";
-    SigninManager* signin_manager =
-        SigninManagerFactory::GetForProfile(profile());
-    signin_manager->ProhibitSignout(true);
+    GetSigninManager()->ProhibitSignout(true);
   }
 }
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service.h b/chrome/browser/policy/cloud/user_policy_signin_service.h
index 221c226..fccb980 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service.h
@@ -11,6 +11,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_base.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
 
 class Profile;
 
@@ -20,24 +21,27 @@
 
 // A specialization of the UserPolicySigninServiceBase for the desktop
 // platforms (Windows, Mac and Linux).
-class UserPolicySigninService : public UserPolicySigninServiceBase {
+class UserPolicySigninService : public UserPolicySigninServiceBase,
+                                public OAuth2TokenService::Observer {
  public:
   // Creates a UserPolicySigninService associated with the passed |profile|.
-  explicit UserPolicySigninService(Profile* profile);
+  UserPolicySigninService(Profile* profile,
+                          PrefService* local_state,
+                          DeviceManagementService* device_management_service,
+                          ProfileOAuth2TokenService* oauth2_token_service);
   virtual ~UserPolicySigninService();
 
   // Registers a CloudPolicyClient for fetching policy for a user. The
   // |oauth2_login_token| and |username| are explicitly passed because
-  // the user is not signed in yet (TokenService does not have any tokens yet
-  // to prevent services from using it until after we've fetched policy).
+  // the user is not signed in yet (ProfileOAuth2TokenService does not have
+  // any tokens yet to prevent services from using it until after we've fetched
+  // policy).
   void RegisterPolicyClient(const std::string& username,
                             const std::string& oauth2_login_token,
                             const PolicyRegistrationCallback& callback);
 
-  // content::NotificationObserver implementation:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
+  // OAuth2TokenService::Observer implementation:
+  virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
 
   // CloudPolicyService::Observer implementation:
   virtual void OnInitializationCompleted(CloudPolicyService* service) OVERRIDE;
@@ -45,9 +49,12 @@
   // BrowserContextKeyedService implementation:
   virtual void Shutdown() OVERRIDE;
 
+ protected:
   // UserPolicySigninServiceBase implementation:
   virtual void InitializeUserCloudPolicyManager(
       scoped_ptr<CloudPolicyClient> client) OVERRIDE;
+
+  virtual void PrepareForUserCloudPolicyManagerShutdown() OVERRIDE;
   virtual void ShutdownUserCloudPolicyManager() OVERRIDE;
 
  private:
@@ -55,7 +62,7 @@
   // the cloud policy server. |oauth_login_token| should contain an OAuth login
   // refresh token that can be downscoped to get an access token for the
   // device_management service.
-  void RegisterCloudPolicyService(const std::string& oauth_login_token);
+  void RegisterCloudPolicyService();
 
   // Callback invoked when policy registration has finished.
   void OnRegistrationComplete();
@@ -70,6 +77,10 @@
 
   scoped_ptr<CloudPolicyClientRegistrationHelper> registration_helper_;
 
+  // Weak pointer to the token service we use to authenticate during
+  // CloudPolicyClient registration.
+  ProfileOAuth2TokenService* oauth2_token_service_;
+
   DISALLOW_COPY_AND_ASSIGN(UserPolicySigninService);
 };
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_android.cc b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
index f165796..c630659 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_android.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/profiles/profile.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 "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "net/base/network_change_notifier.h"
@@ -36,9 +35,16 @@
 
 }  // namespace
 
-UserPolicySigninService::UserPolicySigninService(Profile* profile)
-    : UserPolicySigninServiceBase(profile),
-      weak_factory_(this) {}
+UserPolicySigninService::UserPolicySigninService(
+    Profile* profile,
+    PrefService* local_state,
+    DeviceManagementService* device_management_service,
+    AndroidProfileOAuth2TokenService* token_service)
+    : UserPolicySigninServiceBase(profile,
+                                  local_state,
+                                  device_management_service),
+      weak_factory_(this),
+      oauth2_token_service_(token_service) {}
 
 UserPolicySigninService::~UserPolicySigninService() {}
 
@@ -63,7 +69,7 @@
       force_load_policy,
       GetRegistrationType()));
   registration_helper_->StartRegistration(
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
+      oauth2_token_service_,
       username,
       base::Bind(&UserPolicySigninService::CallPolicyRegistrationCallback,
                  base::Unretained(this),
@@ -132,9 +138,7 @@
   // If the user signed-out while this task was waiting then Shutdown() would
   // have been called, which would have invalidated this task. Since we're here
   // then the user must still be signed-in.
-  SigninManager* signin_manager =
-      SigninManagerFactory::GetForProfile(profile());
-  const std::string& username = signin_manager->GetAuthenticatedUsername();
+  const std::string& username = GetSigninManager()->GetAuthenticatedUsername();
   DCHECK(!username.empty());
   DCHECK(!GetManager()->IsClientRegistered());
   DCHECK(GetManager()->core()->client());
@@ -150,7 +154,7 @@
       force_load_policy,
       GetRegistrationType()));
   registration_helper_->StartRegistration(
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
+      oauth2_token_service_,
       username,
       base::Bind(&UserPolicySigninService::OnRegistrationDone,
                  base::Unretained(this)));
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_android.h b/chrome/browser/policy/cloud/user_policy_signin_service_android.h
index d6c1349..e990580 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_android.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_android.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_base.h"
 
+class AndroidProfileOAuth2TokenService;
 class Profile;
 
 namespace policy {
@@ -23,7 +24,10 @@
 class UserPolicySigninService : public UserPolicySigninServiceBase {
  public:
   // Creates a UserPolicySigninService associated with the passed |profile|.
-  explicit UserPolicySigninService(Profile* profile);
+  UserPolicySigninService(Profile* profile,
+                          PrefService* local_state,
+                          DeviceManagementService* device_management_service,
+                          AndroidProfileOAuth2TokenService* token_service);
   virtual ~UserPolicySigninService();
 
   // Registers a CloudPolicyClient for fetching policy for |username|.
@@ -55,6 +59,10 @@
   scoped_ptr<CloudPolicyClientRegistrationHelper> registration_helper_;
   base::WeakPtrFactory<UserPolicySigninService> weak_factory_;
 
+  // Weak pointer to the token service used to authenticate the
+  // CloudPolicyClient during registration.
+  AndroidProfileOAuth2TokenService* oauth2_token_service_;
+
   DISALLOW_COPY_AND_ASSIGN(UserPolicySigninService);
 };
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
index 2b78d89..1baf659 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -8,9 +8,9 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
+#include "chrome/browser/policy/cloud/device_management_service.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -23,8 +23,12 @@
 namespace policy {
 
 UserPolicySigninServiceBase::UserPolicySigninServiceBase(
-    Profile* profile)
+    Profile* profile,
+    PrefService* local_state,
+    DeviceManagementService* device_management_service)
     : profile_(profile),
+      local_state_(local_state),
+      device_management_service_(device_management_service),
       weak_factory_(this) {
   if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin))
     return;
@@ -68,7 +72,7 @@
     const content::NotificationDetails& details) {
   // If using a TestingProfile with no SigninManager or UserCloudPolicyManager,
   // skip initialization.
-  if (!GetManager() || !SigninManagerFactory::GetForProfile(profile_)) {
+  if (!GetManager() || !GetSigninManager()) {
     DVLOG(1) << "Skipping initialization for tests due to missing components.";
     return;
   }
@@ -129,6 +133,10 @@
 }
 
 void UserPolicySigninServiceBase::Shutdown() {
+  PrepareForUserCloudPolicyManagerShutdown();
+}
+
+void UserPolicySigninServiceBase::PrepareForUserCloudPolicyManagerShutdown() {
   UserCloudPolicyManager* manager = GetManager();
   if (manager && manager->core()->client())
     manager->core()->client()->RemoveObserver(this);
@@ -155,13 +163,11 @@
   }
 
   // If the DeviceManagementService is not yet initialized, start it up now.
-  BrowserPolicyConnector* connector =
-      g_browser_process->browser_policy_connector();
-  connector->ScheduleServiceInitialization(0);
+  device_management_service_->ScheduleInitialization(0);
 
   // Create a new CloudPolicyClient for fetching the DMToken.
   return UserCloudPolicyManager::CreateCloudPolicyClient(
-      connector->device_management_service());
+      device_management_service_);
 }
 
 bool UserPolicySigninServiceBase::ShouldLoadPolicyForUser(
@@ -179,9 +185,7 @@
 }
 
 void UserPolicySigninServiceBase::InitializeOnProfileReady() {
-  SigninManager* signin_manager =
-      SigninManagerFactory::GetForProfile(profile_);
-  std::string username = signin_manager->GetAuthenticatedUsername();
+  std::string username = GetSigninManager()->GetAuthenticatedUsername();
   if (username.empty())
     ShutdownUserCloudPolicyManager();
   else
@@ -202,11 +206,9 @@
     // If there is no cached DMToken then we can detect this when the
     // OnInitializationCompleted() callback is invoked and this will
     // initiate a policy fetch.
-    BrowserPolicyConnector* connector =
-        g_browser_process->browser_policy_connector();
     InitializeUserCloudPolicyManager(
         UserCloudPolicyManager::CreateCloudPolicyClient(
-            connector->device_management_service()).Pass());
+            device_management_service_).Pass());
   }
 
   // If the CloudPolicyService is initialized, kick off registration.
@@ -220,7 +222,7 @@
     scoped_ptr<CloudPolicyClient> client) {
   UserCloudPolicyManager* manager = GetManager();
   DCHECK(!manager->core()->client());
-  manager->Connect(g_browser_process->local_state(), client.Pass());
+  manager->Connect(local_state_, client.Pass());
   DCHECK(manager->core()->service());
 
   // Observe the client to detect errors fetching policy.
@@ -230,7 +232,7 @@
 }
 
 void UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager() {
-  Shutdown();
+  PrepareForUserCloudPolicyManagerShutdown();
   UserCloudPolicyManager* manager = GetManager();
   if (manager)
     manager->DisconnectAndRemovePolicy();
@@ -240,4 +242,8 @@
   return UserCloudPolicyManagerFactory::GetForProfile(profile_);
 }
 
+SigninManager* UserPolicySigninServiceBase::GetSigninManager() {
+  return SigninManagerFactory::GetForProfile(profile_);
+}
+
 }  // namespace policy
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.h b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
index 2f68e62..a551c35 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.h
@@ -18,10 +18,13 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
+class PrefService;
 class Profile;
+class SigninManager;
 
 namespace policy {
 
+class DeviceManagementService;
 class UserCloudPolicyManager;
 
 // The UserPolicySigninService is responsible for interacting with the policy
@@ -51,7 +54,10 @@
   typedef base::Callback<void(bool)> PolicyFetchCallback;
 
   // Creates a UserPolicySigninServiceBase associated with the passed |profile|.
-  explicit UserPolicySigninServiceBase(Profile* profile);
+  UserPolicySigninServiceBase(
+      Profile* profile,
+      PrefService* local_state,
+      DeviceManagementService* device_management_service);
   virtual ~UserPolicySigninServiceBase();
 
   // Initiates a policy fetch as part of user signin, using a CloudPolicyClient
@@ -111,6 +117,10 @@
   virtual void InitializeUserCloudPolicyManager(
       scoped_ptr<CloudPolicyClient> client);
 
+  // Prepares for the UserCloudPolicyManager to be shutdown due to
+  // user signout or profile destruction.
+  virtual void PrepareForUserCloudPolicyManagerShutdown();
+
   // Shuts down the UserCloudPolicyManager (for example, after the user signs
   // out) and deletes any cached policy.
   virtual void ShutdownUserCloudPolicyManager();
@@ -120,6 +130,7 @@
 
   Profile* profile() { return profile_; }
   content::NotificationRegistrar* registrar() { return &registrar_; }
+  SigninManager* GetSigninManager();
 
  private:
   // Weak pointer to the profile this service is associated with.
@@ -127,6 +138,9 @@
 
   content::NotificationRegistrar registrar_;
 
+  PrefService* local_state_;
+  DeviceManagementService* device_management_service_;
+
   base::WeakPtrFactory<UserPolicySigninServiceBase> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(UserPolicySigninServiceBase);
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
index 7804541..fbeafd1 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
@@ -5,8 +5,11 @@
 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
 
 #include "base/prefs/pref_service.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/pref_names.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
@@ -14,23 +17,24 @@
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/policy/cloud/user_policy_signin_service_android.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #else
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
 #endif
 
 namespace policy {
 
+namespace {
+
+// Used only for testing.
+DeviceManagementService* g_device_management_service = NULL;
+
+}  // namespace
+
 UserPolicySigninServiceFactory::UserPolicySigninServiceFactory()
     : BrowserContextKeyedServiceFactory(
         "UserPolicySigninService",
         BrowserContextDependencyManager::GetInstance()) {
-#if defined(OS_ANDROID)
   DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
-#else
-  DependsOn(TokenServiceFactory::GetInstance());
-#endif
   DependsOn(SigninManagerFactory::GetInstance());
   DependsOn(UserCloudPolicyManagerFactory::GetInstance());
 }
@@ -49,10 +53,28 @@
   return Singleton<UserPolicySigninServiceFactory>::get();
 }
 
+// static
+void UserPolicySigninServiceFactory::SetDeviceManagementServiceForTesting(
+    DeviceManagementService* device_management_service) {
+  g_device_management_service = device_management_service;
+}
+
 BrowserContextKeyedService*
 UserPolicySigninServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* profile) const {
-  return new UserPolicySigninService(static_cast<Profile*>(profile));
+    content::BrowserContext* context) const {
+  Profile* profile = static_cast<Profile*>(context);
+  BrowserPolicyConnector* connector =
+      g_browser_process->browser_policy_connector();
+  DeviceManagementService* device_management_service =
+      g_device_management_service ? g_device_management_service
+                                  : connector->device_management_service();
+  // TODO(atwilson): Inject SigninManager here or remove the dependency
+  // entirely. http://crbug.com/276270.
+  return new UserPolicySigninService(
+      profile,
+      g_browser_process->local_state(),
+      device_management_service,
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile));
 }
 
 bool
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_factory.h b/chrome/browser/policy/cloud/user_policy_signin_service_factory.h
index 8ced58c..3bde9d0 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_factory.h
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_factory.h
@@ -16,6 +16,7 @@
 
 namespace policy {
 
+class DeviceManagementService;
 class UserPolicySigninService;
 
 // Singleton that owns all UserPolicySigninServices and creates/deletes them as
@@ -30,6 +31,12 @@
   // Used primarily for testing.
   static UserPolicySigninService* GetForProfile(Profile* profile);
 
+  // Allows setting a mock DeviceManagementService for tests. Does not take
+  // ownership, and should be reset to NULL at the end of the test.
+  // Set this before an instance is built for a Profile.
+  static void SetDeviceManagementServiceForTesting(
+      DeviceManagementService* device_management_service);
+
  protected:
   // BrowserContextKeyedServiceFactory implementation.
   virtual BrowserContextKeyedService* BuildServiceInstanceFor(
@@ -48,6 +55,8 @@
   UserPolicySigninServiceFactory();
   virtual ~UserPolicySigninServiceFactory();
 
+  DeviceManagementService* device_management_service_;
+
   DISALLOW_COPY_AND_ASSIGN(UserPolicySigninServiceFactory);
 };
 
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
index 70b0c46..8da3550 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/fake_signin_manager.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 "chrome/test/base/testing_browser_process.h"
@@ -41,11 +42,9 @@
 #if defined(OS_ANDROID)
 #include "chrome/browser/policy/cloud/user_policy_signin_service_android.h"
 #include "chrome/browser/signin/android_profile_oauth2_token_service.h"
-#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #else
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
-#include "chrome/browser/signin/token_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
+#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
 #endif
 
 namespace em = enterprise_management;
@@ -72,10 +71,6 @@
     "  \"hd\": \"test.com\""
     "}";
 
-const char kCombinedScopes[] =
-    "https://www.googleapis.com/auth/chromeosdevicemanagement "
-    "https://www.googleapis.com/auth/userinfo.email";
-
 class SigninManagerFake : public FakeSigninManager {
  public:
   explicit SigninManagerFake(Profile* profile)
@@ -95,26 +90,32 @@
 };
 
 #if defined(OS_ANDROID)
-
-class FakeProfileOAuth2TokenService : public AndroidProfileOAuth2TokenService {
+// TODO(atwilson): Remove this when ProfileOAuth2TokenService supports
+// usernames.
+class FakeAndroidProfileOAuth2TokenService
+    : public AndroidProfileOAuth2TokenService {
  public:
-  explicit FakeProfileOAuth2TokenService(Profile* profile) {
+  explicit FakeAndroidProfileOAuth2TokenService(Profile* profile) {
     Initialize(profile);
   }
 
   static BrowserContextKeyedService* Build(content::BrowserContext* profile) {
-    return new FakeProfileOAuth2TokenService(static_cast<Profile*>(profile));
+    return new FakeAndroidProfileOAuth2TokenService(
+        static_cast<Profile*>(profile));
   }
 
   // AndroidProfileOAuth2TokenService overrides:
-  virtual void FetchOAuth2Token(
+  virtual void FetchOAuth2TokenWithUsername(
+      RequestImpl* request,
       const std::string& username,
-      const std::string& scope,
-      const FetchOAuth2TokenCallback& callback) OVERRIDE {
+      const OAuth2TokenService::ScopeSet& scope) OVERRIDE {
     ASSERT_TRUE(!HasPendingRequest());
     ASSERT_EQ(kTestUser, username);
-    ASSERT_EQ(kCombinedScopes, scope);
-    pending_callback_ = callback;
+    ASSERT_EQ(2U, scope.size());
+    EXPECT_EQ(1U, scope.count(GaiaConstants::kDeviceManagementServiceOAuth));
+    EXPECT_EQ(1U, scope.count(
+        "https://www.googleapis.com/auth/userinfo.email"));
+    pending_request_ = request->AsWeakPtr();
   }
 
   void IssueToken(const std::string& token) {
@@ -122,17 +123,21 @@
     GoogleServiceAuthError error = GoogleServiceAuthError::AuthErrorNone();
     if (token.empty())
       error = GoogleServiceAuthError::FromServiceError("fail");
-    pending_callback_.Run(
-        error, token, base::Time::Now() + base::TimeDelta::FromDays(1));
-    pending_callback_.Reset();
+    if (pending_request_) {
+      pending_request_->InformConsumer(
+          error,
+          token,
+          base::Time::Now() + base::TimeDelta::FromDays(1));
+    }
+    pending_request_.reset();
   }
 
   bool HasPendingRequest() const {
-    return !pending_callback_.is_null();
+    return pending_request_;
   }
 
  private:
-  FetchOAuth2TokenCallback pending_callback_;
+  base::WeakPtr<RequestImpl> pending_request_;
 };
 
 #endif
@@ -162,10 +167,8 @@
   }
 
   virtual void SetUp() OVERRIDE {
-    device_management_service_ = new MockDeviceManagementService();
-    g_browser_process->browser_policy_connector()->
-        SetDeviceManagementServiceForTesting(
-            scoped_ptr<DeviceManagementService>(device_management_service_));
+    UserPolicySigninServiceFactory::SetDeviceManagementServiceForTesting(
+        &device_management_service_);
 
     local_state_.reset(new TestingPrefServiceSimple);
     chrome::RegisterLocalState(local_state_->registry());
@@ -182,31 +185,31 @@
     chrome::RegisterUserProfilePrefs(prefs->registry());
     TestingProfile::Builder builder;
     builder.SetPrefService(scoped_ptr<PrefServiceSyncable>(prefs.Pass()));
+    builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
+                              SigninManagerFake::Build);
+#if defined(OS_ANDROID)
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeAndroidProfileOAuth2TokenService::Build);
+#else
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeProfileOAuth2TokenService::Build);
+#endif
+
     profile_ = builder.Build().Pass();
+    signin_manager_ = static_cast<SigninManagerFake*>(
+        SigninManagerFactory::GetForProfile(profile_.get()));
 
     mock_store_ = new MockUserCloudPolicyStore();
     EXPECT_CALL(*mock_store_, Load()).Times(AnyNumber());
     manager_.reset(new UserCloudPolicyManager(
         profile_.get(), scoped_ptr<UserCloudPolicyStore>(mock_store_)));
-    signin_manager_ = static_cast<SigninManagerFake*>(
-        SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
-            profile_.get(), SigninManagerFake::Build));
 
-#if defined(OS_ANDROID)
-    ProfileOAuth2TokenServiceFactory* factory =
-        ProfileOAuth2TokenServiceFactory::GetInstance();
-    token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
-        factory->SetTestingFactoryAndUse(profile_.get(),
-                                         FakeProfileOAuth2TokenService::Build));
-#endif
-
-    // Make sure the UserPolicySigninService is created.
-    UserPolicySigninServiceFactory::GetForProfile(profile_.get());
     Mock::VerifyAndClearExpectations(mock_store_);
     url_factory_.set_remove_fetcher_on_delete(true);
   }
 
   virtual void TearDown() OVERRIDE {
+    UserPolicySigninServiceFactory::SetDeviceManagementServiceForTesting(NULL);
     // Free the profile before we clear out the browser prefs.
     profile_.reset();
     TestingBrowserProcess* testing_browser_process =
@@ -218,9 +221,26 @@
     run_loop.RunUntilIdle();
   }
 
+#if defined(OS_ANDROID)
+  FakeAndroidProfileOAuth2TokenService* GetTokenService() {
+    ProfileOAuth2TokenService* service =
+        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
+    return static_cast<FakeAndroidProfileOAuth2TokenService*>(service);
+  }
+#else
+  FakeProfileOAuth2TokenService* GetTokenService() {
+    ProfileOAuth2TokenService* service =
+        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
+    return static_cast<FakeProfileOAuth2TokenService*>(service);
+  }
+#endif
+
   bool IsRequestActive() {
 #if defined(OS_ANDROID)
-    if (token_service_->HasPendingRequest())
+    if (GetTokenService()->HasPendingRequest())
+      return true;
+#else
+    if (!GetTokenService()->GetPendingRequests().empty())
       return true;
 #endif
     return url_factory_.GetFetcherByID(0);
@@ -228,8 +248,8 @@
 
   void MakeOAuthTokenFetchSucceed() {
 #if defined(OS_ANDROID)
-    ASSERT_TRUE(token_service_->HasPendingRequest());
-    token_service_->IssueToken("fake_token");
+    ASSERT_TRUE(GetTokenService()->HasPendingRequest());
+    GetTokenService()->IssueToken("fake_token");
 #else
     ASSERT_TRUE(IsRequestActive());
     net::TestURLFetcher* fetcher = url_factory_.GetFetcherByID(0);
@@ -259,11 +279,11 @@
     // When the user is from a hosted domain, this should kick off client
     // registration.
     MockDeviceManagementJob* register_request = NULL;
-    EXPECT_CALL(*device_management_service_,
+    EXPECT_CALL(device_management_service_,
                 CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION))
-        .WillOnce(device_management_service_->CreateAsyncJob(
+        .WillOnce(device_management_service_.CreateAsyncJob(
             &register_request));
-    EXPECT_CALL(*device_management_service_, StartJob(_, _, _, _, _, _, _))
+    EXPECT_CALL(device_management_service_, StartJob(_, _, _, _, _, _, _))
         .Times(1);
 
     // Now mimic the user being a hosted domain - this should cause a Register()
@@ -291,10 +311,10 @@
 
     // Now call to fetch policy - this should fire off a fetch request.
     MockDeviceManagementJob* fetch_request = NULL;
-    EXPECT_CALL(*device_management_service_,
+    EXPECT_CALL(device_management_service_,
                 CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH))
-        .WillOnce(device_management_service_->CreateAsyncJob(&fetch_request));
-    EXPECT_CALL(*device_management_service_, StartJob(_, _, _, _, _, _, _))
+        .WillOnce(device_management_service_.CreateAsyncJob(&fetch_request));
+    EXPECT_CALL(device_management_service_, StartJob(_, _, _, _, _, _, _))
         .Times(1);
     signin_service->FetchPolicyForSignedInUser(
         created_client_.Pass(),
@@ -341,9 +361,6 @@
   net::TestURLFetcherFactory url_factory_;
 
   SigninManagerFake* signin_manager_;
-#if defined(OS_ANDROID)
-  FakeProfileOAuth2TokenService* token_service_;  // Not owned.
-#endif
 
   // Used in conjunction with OnRegisterCompleted() to test client registration
   // callbacks.
@@ -354,7 +371,7 @@
 
   // Weak ptr to the MockDeviceManagementService (object is owned by the
   // BrowserPolicyConnector).
-  MockDeviceManagementService* device_management_service_;
+  MockDeviceManagementService device_management_service_;
 
   scoped_ptr<TestingPrefServiceSimple> local_state_;
 };
@@ -401,13 +418,45 @@
   ASSERT_FALSE(IsRequestActive());
 
   // Make oauth token available.
-  TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
-      GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth_login_refresh_token");
+  GetTokenService()->IssueRefreshToken("oauth_login_refresh_token");
 
   // Client registration should be in progress since we now have an oauth token.
   ASSERT_TRUE(IsRequestActive());
 }
 
+TEST_F(UserPolicySigninServiceTest, InitWhileSignedInOAuthError) {
+  // Set the user as signed in.
+  SigninManagerFactory::GetForProfile(profile_.get())->SetAuthenticatedUsername(
+      kTestUser);
+
+  // Let the SigninService know that the profile has been created.
+  content::NotificationService::current()->Notify(
+      chrome::NOTIFICATION_PROFILE_ADDED,
+      content::Source<Profile>(profile_.get()),
+      content::NotificationService::NoDetails());
+
+  // UserCloudPolicyManager should be initialized.
+  ASSERT_TRUE(manager_->core()->service());
+
+  // Complete initialization of the store.
+  mock_store_->NotifyStoreLoaded();
+
+  // No oauth access token yet, so client registration should be deferred.
+  ASSERT_FALSE(IsRequestActive());
+
+  // Make oauth token available.
+  GetTokenService()->IssueRefreshToken("oauth_login_refresh_token");
+
+  // Client registration should be in progress since we now have an oauth token.
+  ASSERT_TRUE(IsRequestActive());
+
+  // Now fail the access token fetch.
+  GoogleServiceAuthError error(
+      GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+  GetTokenService()->IssueErrorForAllPendingRequests(error);
+  ASSERT_FALSE(IsRequestActive());
+}
+
 TEST_F(UserPolicySigninServiceTest, SignInAfterInit) {
   EXPECT_CALL(*mock_store_, Clear());
   // Let the SigninService know that the profile has been created.
@@ -428,8 +477,7 @@
   mock_store_->NotifyStoreLoaded();
 
   // Make oauth token available.
-  TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
-      GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth_login_refresh_token");
+  GetTokenService()->IssueRefreshToken("oauth_login_refresh_token");
 
   // UserCloudPolicyManager should be initialized.
   ASSERT_TRUE(manager_->core()->service());
@@ -458,8 +506,7 @@
   mock_store_->NotifyStoreLoaded();
 
   // Make oauth token available.
-  TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
-      GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth_login_refresh_token");
+  GetTokenService()->IssueRefreshToken("oauth_login_refresh_token");
 
   // UserCloudPolicyManager should not be initialized and there should be no
   // DMToken request active.
@@ -484,8 +531,7 @@
       kTestUser);
 
   // Make oauth token available.
-  TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
-      GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth_login_refresh_token");
+  GetTokenService()->IssueRefreshToken("oauth_login_refresh_token");
 
   // UserCloudPolicyManager should be initialized.
   ASSERT_TRUE(manager_->core()->service());
@@ -518,8 +564,7 @@
       kTestUser);
 
   // Make oauth token available.
-  TokenServiceFactory::GetForProfile(profile_.get())->IssueAuthTokenForTest(
-      GaiaConstants::kGaiaOAuth2LoginRefreshToken, "oauth_login_refresh_token");
+  GetTokenService()->IssueRefreshToken("oauth_login_refresh_token");
 
   // UserCloudPolicyManager should be initialized.
   ASSERT_TRUE(manager_->core()->service());
@@ -579,8 +624,8 @@
 
   // Cause the access token fetch to fail - callback should be invoked.
 #if defined(OS_ANDROID)
-  ASSERT_TRUE(token_service_->HasPendingRequest());
-  token_service_->IssueToken("");
+  ASSERT_TRUE(GetTokenService()->HasPendingRequest());
+  GetTokenService()->IssueToken("");
 #else
   net::TestURLFetcher* fetcher = url_factory_.GetFetcherByID(0);
   fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, -1));
@@ -637,10 +682,10 @@
   // When the user is from a hosted domain, this should kick off client
   // registration.
   MockDeviceManagementJob* register_request = NULL;
-  EXPECT_CALL(*device_management_service_,
+  EXPECT_CALL(device_management_service_,
               CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION))
-      .WillOnce(device_management_service_->CreateAsyncJob(&register_request));
-  EXPECT_CALL(*device_management_service_, StartJob(_, _, _, _, _, _, _))
+      .WillOnce(device_management_service_.CreateAsyncJob(&register_request));
+  EXPECT_CALL(device_management_service_, StartJob(_, _, _, _, _, _, _))
         .Times(1);
 
   // Now mimic the user being a hosted domain - this should cause a Register()
@@ -671,10 +716,10 @@
   // When the user is from a hosted domain, this should kick off client
   // registration.
   MockDeviceManagementJob* register_request = NULL;
-  EXPECT_CALL(*device_management_service_,
+  EXPECT_CALL(device_management_service_,
               CreateJob(DeviceManagementRequestJob::TYPE_REGISTRATION))
-      .WillOnce(device_management_service_->CreateAsyncJob(&register_request));
-  EXPECT_CALL(*device_management_service_, StartJob(_, _, _, _, _, _, _))
+      .WillOnce(device_management_service_.CreateAsyncJob(&register_request));
+  EXPECT_CALL(device_management_service_, StartJob(_, _, _, _, _, _, _))
       .Times(1);
 
   // Now mimic the user being a hosted domain - this should cause a Register()
@@ -703,15 +748,15 @@
 TEST_F(UserPolicySigninServiceTest, FetchPolicyFailed) {
   scoped_ptr<CloudPolicyClient> client =
       UserCloudPolicyManager::CreateCloudPolicyClient(
-          device_management_service_);
+          &device_management_service_);
   client->SetupRegistration("mock_dm_token", "mock_client_id");
 
   // Initiate a policy fetch request.
   MockDeviceManagementJob* fetch_request = NULL;
-  EXPECT_CALL(*device_management_service_,
+  EXPECT_CALL(device_management_service_,
               CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH))
-      .WillOnce(device_management_service_->CreateAsyncJob(&fetch_request));
-  EXPECT_CALL(*device_management_service_, StartJob(_, _, _, _, _, _, _))
+      .WillOnce(device_management_service_.CreateAsyncJob(&fetch_request));
+  EXPECT_CALL(device_management_service_, StartJob(_, _, _, _, _, _, _))
       .Times(1);
   UserPolicySigninService* signin_service =
       UserPolicySigninServiceFactory::GetForProfile(profile_.get());
@@ -751,10 +796,10 @@
 
   // Kick off another policy fetch.
   MockDeviceManagementJob* fetch_request = NULL;
-  EXPECT_CALL(*device_management_service_,
+  EXPECT_CALL(device_management_service_,
               CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH))
-      .WillOnce(device_management_service_->CreateAsyncJob(&fetch_request));
-  EXPECT_CALL(*device_management_service_, StartJob(_, _, _, _, _, _, _))
+      .WillOnce(device_management_service_.CreateAsyncJob(&fetch_request));
+  EXPECT_CALL(device_management_service_, StartJob(_, _, _, _, _, _, _))
       .Times(1);
   manager_->RefreshPolicies();
   Mock::VerifyAndClearExpectations(this);
@@ -777,10 +822,10 @@
 
   // Kick off another policy fetch.
   MockDeviceManagementJob* fetch_request = NULL;
-  EXPECT_CALL(*device_management_service_,
+  EXPECT_CALL(device_management_service_,
               CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH))
-      .WillOnce(device_management_service_->CreateAsyncJob(&fetch_request));
-  EXPECT_CALL(*device_management_service_, StartJob(_, _, _, _, _, _, _))
+      .WillOnce(device_management_service_.CreateAsyncJob(&fetch_request));
+  EXPECT_CALL(device_management_service_, StartJob(_, _, _, _, _, _, _))
       .Times(1);
   manager_->RefreshPolicies();
   Mock::VerifyAndClearExpectations(this);
diff --git a/chrome/browser/policy/config_dir_policy_loader.cc b/chrome/browser/policy/config_dir_policy_loader.cc
index 7ba2b32..708c774 100644
--- a/chrome/browser/policy/config_dir_policy_loader.cc
+++ b/chrome/browser/policy/config_dir_policy_loader.cc
@@ -57,14 +57,15 @@
 
 }  // namespace
 
-ConfigDirPolicyLoader::ConfigDirPolicyLoader(const base::FilePath& config_dir,
-                                             PolicyScope scope)
-    : config_dir_(config_dir),
-      scope_(scope) {}
+ConfigDirPolicyLoader::ConfigDirPolicyLoader(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    const base::FilePath& config_dir,
+    PolicyScope scope)
+    : AsyncPolicyLoader(task_runner), config_dir_(config_dir), scope_(scope) {}
 
 ConfigDirPolicyLoader::~ConfigDirPolicyLoader() {}
 
-void ConfigDirPolicyLoader::InitOnFile() {
+void ConfigDirPolicyLoader::InitOnBackgroundThread() {
   base::FilePathWatcher::Callback callback =
       base::Bind(&ConfigDirPolicyLoader::OnFileUpdated, base::Unretained(this));
   mandatory_watcher_.Watch(config_dir_.Append(kMandatoryConfigDir), false,
diff --git a/chrome/browser/policy/config_dir_policy_loader.h b/chrome/browser/policy/config_dir_policy_loader.h
index afdc8e6..719e8ac 100644
--- a/chrome/browser/policy/config_dir_policy_loader.h
+++ b/chrome/browser/policy/config_dir_policy_loader.h
@@ -23,11 +23,13 @@
 // last value read takes precedence in case of policy key collisions.
 class ConfigDirPolicyLoader : public AsyncPolicyLoader {
  public:
-  ConfigDirPolicyLoader(const base::FilePath& config_dir, PolicyScope scope);
+  ConfigDirPolicyLoader(scoped_refptr<base::SequencedTaskRunner> task_runner,
+                        const base::FilePath& config_dir,
+                        PolicyScope scope);
   virtual ~ConfigDirPolicyLoader();
 
   // AsyncPolicyLoader implementation.
-  virtual void InitOnFile() OVERRIDE;
+  virtual void InitOnBackgroundThread() OVERRIDE;
   virtual scoped_ptr<PolicyBundle> Load() OVERRIDE;
   virtual base::Time LastModificationTime() OVERRIDE;
 
diff --git a/chrome/browser/policy/config_dir_policy_loader_unittest.cc b/chrome/browser/policy/config_dir_policy_loader_unittest.cc
index d3fec2b..5ac6d65 100644
--- a/chrome/browser/policy/config_dir_policy_loader_unittest.cc
+++ b/chrome/browser/policy/config_dir_policy_loader_unittest.cc
@@ -6,7 +6,10 @@
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/json/json_string_value_serializer.h"
+#include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/policy/async_policy_provider.h"
@@ -30,6 +33,7 @@
   virtual void SetUp() OVERRIDE;
 
   virtual ConfigurationPolicyProvider* CreateProvider(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_definition_list) OVERRIDE;
 
   virtual void InstallEmptyPolicy() OVERRIDE;
@@ -78,9 +82,10 @@
 }
 
 ConfigurationPolicyProvider* TestHarness::CreateProvider(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
     const PolicyDefinitionList* policy_definition_list) {
-  scoped_ptr<AsyncPolicyLoader> loader(
-      new ConfigDirPolicyLoader(test_dir(), POLICY_SCOPE_MACHINE));
+  scoped_ptr<AsyncPolicyLoader> loader(new ConfigDirPolicyLoader(
+      task_runner, test_dir(), POLICY_SCOPE_MACHINE));
   return new AsyncPolicyProvider(loader.Pass());
 }
 
@@ -181,7 +186,8 @@
 // The preferences dictionary is expected to be empty when there are no files to
 // load.
 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsEmpty) {
-  ConfigDirPolicyLoader loader(harness_.test_dir(), POLICY_SCOPE_MACHINE);
+  ConfigDirPolicyLoader loader(
+      loop_.message_loop_proxy(), harness_.test_dir(), POLICY_SCOPE_MACHINE);
   scoped_ptr<PolicyBundle> bundle(loader.Load());
   ASSERT_TRUE(bundle.get());
   const PolicyBundle kEmptyBundle;
@@ -193,7 +199,8 @@
 TEST_F(ConfigDirPolicyLoaderTest, ReadPrefsNonExistentDirectory) {
   base::FilePath non_existent_dir(
       harness_.test_dir().Append(FILE_PATH_LITERAL("not_there")));
-  ConfigDirPolicyLoader loader(non_existent_dir, POLICY_SCOPE_MACHINE);
+  ConfigDirPolicyLoader loader(
+      loop_.message_loop_proxy(), non_existent_dir, POLICY_SCOPE_MACHINE);
   scoped_ptr<PolicyBundle> bundle(loader.Load());
   ASSERT_TRUE(bundle.get());
   const PolicyBundle kEmptyBundle;
@@ -216,7 +223,8 @@
   for (unsigned int i = 5; i <= 8; ++i)
     harness_.WriteConfigFile(test_dict_bar, base::IntToString(i));
 
-  ConfigDirPolicyLoader loader(harness_.test_dir(), POLICY_SCOPE_USER);
+  ConfigDirPolicyLoader loader(
+      loop_.message_loop_proxy(), harness_.test_dir(), POLICY_SCOPE_USER);
   scoped_ptr<PolicyBundle> bundle(loader.Load());
   ASSERT_TRUE(bundle.get());
   PolicyBundle expected_bundle;
diff --git a/chrome/browser/policy/configuration_policy_handler.cc b/chrome/browser/policy/configuration_policy_handler.cc
index b31f689..30bcc9c 100644
--- a/chrome/browser/policy/configuration_policy_handler.cc
+++ b/chrome/browser/policy/configuration_policy_handler.cc
@@ -16,7 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/extensions/external_policy_loader.h"
 #include "chrome/browser/policy/configuration_policy_pref_store.h"
 #include "chrome/browser/policy/external_data_fetcher.h"
@@ -103,6 +103,9 @@
   { key::kDefaultSearchProviderImageURL,
     prefs::kDefaultSearchProviderImageURL,
     Value::TYPE_STRING },
+  { key::kDefaultSearchProviderNewTabURL,
+    prefs::kDefaultSearchProviderNewTabURL,
+    Value::TYPE_STRING },
   { key::kDefaultSearchProviderSearchURLPostParams,
     prefs::kDefaultSearchProviderSearchURLPostParams,
     Value::TYPE_STRING },
@@ -739,7 +742,7 @@
   // This is checked after path expansion because a non-empty policy value can
   // lead to an empty path value after expansion (e.g. "\"\"").
   if (expanded_value.empty())
-    expanded_value = download_util::GetDefaultDownloadDirectory().value();
+    expanded_value = DownloadPrefs::GetDefaultDownloadDirectory().value();
   prefs->SetValue(prefs::kDownloadDefaultDirectory,
                   Value::CreateStringValue(expanded_value));
   prefs->SetValue(prefs::kPromptForDownload,
@@ -967,6 +970,7 @@
     prefs->SetString(prefs::kDefaultSearchProviderEncodings, std::string());
     prefs->SetString(prefs::kDefaultSearchProviderKeyword, std::string());
     prefs->SetString(prefs::kDefaultSearchProviderInstantURL, std::string());
+    prefs->SetString(prefs::kDefaultSearchProviderNewTabURL, std::string());
     prefs->SetValue(prefs::kDefaultSearchProviderAlternateURLs,
                     new ListValue());
     prefs->SetString(prefs::kDefaultSearchProviderSearchTermsReplacementKey,
@@ -996,6 +1000,7 @@
       EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderEncodings);
       EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderKeyword);
       EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderInstantURL);
+      EnsureStringPrefExists(prefs, prefs::kDefaultSearchProviderNewTabURL);
       EnsureListPrefExists(prefs, prefs::kDefaultSearchProviderAlternateURLs);
       EnsureStringPrefExists(prefs,
           prefs::kDefaultSearchProviderSearchTermsReplacementKey);
diff --git a/chrome/browser/policy/configuration_policy_handler_list.cc b/chrome/browser/policy/configuration_policy_handler_list.cc
index 03c0711..39eec6d 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list.cc
@@ -12,8 +12,8 @@
 #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/common/extensions/manifest.h"
 #include "chrome/common/pref_names.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "policy/policy_constants.h"
 
diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
index 400d53b..6df3ae9 100644
--- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
@@ -641,6 +641,7 @@
   static const char* const kReplacementKey;
   static const char* const kImageURL;
   static const char* const kImageParams;
+  static const char* const kNewTabURL;
 
   // Build a default search policy by setting search-related keys in |policy| to
   // reasonable values. You can update any of the keys after calling this
@@ -666,6 +667,8 @@
     "http://test.com/searchbyimage/upload";
 const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kImageParams =
     "image_content=content,image_url=http://test.com/test.png";
+const char* const ConfigurationPolicyPrefStoreDefaultSearchTest::kNewTabURL =
+    "http://test.com/newtab";
 
 void ConfigurationPolicyPrefStoreDefaultSearchTest::
     BuildDefaultSearchPolicy(PolicyMap* policy) {
@@ -701,6 +704,9 @@
   policy->Set(key::kDefaultSearchProviderImageURLPostParams,
               POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
               base::Value::CreateStringValue(kImageParams), NULL);
+  policy->Set(key::kDefaultSearchProviderNewTabURL,
+              POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+              base::Value::CreateStringValue(kNewTabURL), NULL);
 }
 
 // Checks that if the policy for default search is valid, i.e. there's a
@@ -765,6 +771,10 @@
   EXPECT_TRUE(store_->GetValue(
       prefs::kDefaultSearchProviderImageURLPostParams, &value));
   EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
+
+  EXPECT_TRUE(store_->GetValue(
+      prefs::kDefaultSearchProviderNewTabURL, &value));
+  EXPECT_TRUE(base::StringValue(std::string()).Equals(value));
 }
 
 // Checks that for a fully defined search policy, all elements have been
@@ -844,6 +854,8 @@
   EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, NULL));
   EXPECT_FALSE(store_->GetValue(
       prefs::kDefaultSearchProviderImageURLPostParams, NULL));
+  EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL, NULL));
+  EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderNewTabURL, NULL));
 }
 
 // Checks that if the default search policy is invalid, that no elements of the
@@ -870,6 +882,8 @@
   EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderImageURL, NULL));
   EXPECT_FALSE(store_->GetValue(
       prefs::kDefaultSearchProviderImageURLPostParams, NULL));
+  EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderInstantURL, NULL));
+  EXPECT_FALSE(store_->GetValue(prefs::kDefaultSearchProviderNewTabURL, NULL));
 }
 
 // Checks that if the default search policy is invalid, that no elements of the
diff --git a/chrome/browser/policy/configuration_policy_provider_test.cc b/chrome/browser/policy/configuration_policy_provider_test.cc
index c0af27f..55ef224 100644
--- a/chrome/browser/policy/configuration_policy_provider_test.cc
+++ b/chrome/browser/policy/configuration_policy_provider_test.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/values.h"
 #include "chrome/browser/policy/configuration_policy_provider.h"
 #include "chrome/browser/policy/external_data_fetcher.h"
@@ -16,7 +16,6 @@
 #include "policy/policy_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-using content::BrowserThread;
 using ::testing::Mock;
 using ::testing::_;
 
@@ -44,9 +43,7 @@
 
 }  // namespace test_policy_definitions
 
-PolicyTestBase::PolicyTestBase()
-    : ui_thread_(BrowserThread::UI, &loop_),
-      file_thread_(BrowserThread::FILE, &loop_) {}
+PolicyTestBase::PolicyTestBase() {}
 
 PolicyTestBase::~PolicyTestBase() {}
 
@@ -83,8 +80,8 @@
   test_harness_.reset((*GetParam())());
   test_harness_->SetUp();
 
-  provider_.reset(
-      test_harness_->CreateProvider(&test_policy_definitions::kList));
+  provider_.reset(test_harness_->CreateProvider(
+      loop_.message_loop_proxy(), &test_policy_definitions::kList));
   provider_->Init();
   // Some providers do a reload on init. Make sure any notifications generated
   // are fired now.
diff --git a/chrome/browser/policy/configuration_policy_provider_test.h b/chrome/browser/policy/configuration_policy_provider_test.h
index 4d2b0ef..8b1cd66 100644
--- a/chrome/browser/policy/configuration_policy_provider_test.h
+++ b/chrome/browser/policy/configuration_policy_provider_test.h
@@ -9,15 +9,16 @@
 
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "chrome/browser/policy/policy_types.h"
-#include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
 class DictionaryValue;
 class ListValue;
+class SequencedTaskRunner;
 class Value;
 }
 
@@ -55,9 +56,6 @@
   base::MessageLoopForIO loop_;
 
  private:
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-
   DISALLOW_COPY_AND_ASSIGN(PolicyTestBase);
 };
 
@@ -76,6 +74,7 @@
 
   // Create a new policy provider.
   virtual ConfigurationPolicyProvider* CreateProvider(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_definition_list) = 0;
 
   // Returns the policy level and scope set by the policy provider.
diff --git a/chrome/browser/policy/managed_mode_policy_provider_unittest.cc b/chrome/browser/policy/managed_mode_policy_provider_unittest.cc
index b4ba945..6a90a68 100644
--- a/chrome/browser/policy/managed_mode_policy_provider_unittest.cc
+++ b/chrome/browser/policy/managed_mode_policy_provider_unittest.cc
@@ -86,6 +86,7 @@
   virtual void SetUp() OVERRIDE;
 
   virtual ConfigurationPolicyProvider* CreateProvider(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_definition_list) OVERRIDE;
 
   virtual void InstallEmptyPolicy() OVERRIDE;
@@ -130,6 +131,7 @@
 void TestHarness::SetUp() {}
 
 ConfigurationPolicyProvider* TestHarness::CreateProvider(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
     const PolicyDefinitionList* policy_definition_list) {
   provider_ = new ManagedModePolicyProvider(pref_store_.get());
   syncer::SyncDataList initial_sync_data;
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 65bb42f..cefed43 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -490,53 +490,6 @@
     UpdateProviderPolicy(policies);
   }
 
-  void TestScreenshotFeedback(bool enabled) {
-    SetScreenshotPolicy(enabled);
-
-    // Wait for feedback page to load.
-    content::WindowedNotificationObserver observer(
-        content::NOTIFICATION_LOAD_STOP,
-        content::NotificationService::AllSources());
-    EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_FEEDBACK));
-    observer.Wait();
-    content::WebContents* web_contents =
-        static_cast<content::Source<content::NavigationController> >(
-            observer.source())->GetWebContents();
-
-    // Wait for feedback page to fully initialize.
-    // setupCurrentScreenshot is called when feedback page loads and (among
-    // other things) adds current-screenshots-thumbnailDiv-0-image element.
-    // The code below executes either before setupCurrentScreenshot was called
-    // (setupCurrentScreenshot is replaced with our hook) or after it has
-    // completed (in that case send result immediately).
-    bool result = false;
-    EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
-        web_contents,
-        "function btest_initCompleted(url) {"
-        "  var img = new Image();"
-        "  img.src = url;"
-        "  img.onload = function() {"
-        "    domAutomationController.send(img.width * img.height > 0);"
-        "  };"
-        "  img.onerror = function() {"
-        "    domAutomationController.send(false);"
-        "  };"
-        "}"
-        "function setupCurrentScreenshot(url) {"
-        "  btest_initCompleted(url);"
-        "}"
-        "var img = document.getElementById("
-        "    'current-screenshots-thumbnailDiv-0-image');"
-        "if (img)"
-        "  btest_initCompleted(img.src);",
-        &result));
-    EXPECT_EQ(enabled, result);
-
-    // Feedback page is a singleton page, so close so future calls to this
-    // function work as expected.
-    web_contents->Close();
-  }
-
 #if defined(OS_CHROMEOS)
   void TestScreenshotFile(bool enabled) {
     SetScreenshotPolicy(enabled);
@@ -754,6 +707,7 @@
   const std::string kImageURL("http://test.com/searchbyimage/upload");
   const std::string kImageURLPostParams(
       "image_content=content,image_url=http://test.com/test.png");
+  const std::string kNewTabURL("http://search.example/newtab");
 
   TemplateURLService* service = TemplateURLServiceFactory::GetForProfile(
       browser()->profile());
@@ -769,7 +723,8 @@
     default_search->search_terms_replacement_key() ==
         kSearchTermsReplacementKey &&
     default_search->image_url() == kImageURL &&
-    default_search->image_url_post_params() == kImageURLPostParams);
+    default_search->image_url_post_params() == kImageURLPostParams &&
+    default_search->new_tab_url() == kNewTabURL);
 
   // Override the default search provider using policies.
   PolicyMap policies;
@@ -798,6 +753,10 @@
                POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
                base::Value::CreateStringValue(kImageURLPostParams),
                NULL);
+  policies.Set(key::kDefaultSearchProviderNewTabURL,
+               POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+               base::Value::CreateStringValue(kNewTabURL),
+               NULL);
   UpdateProviderPolicy(policies);
   default_search = service->GetDefaultSearchProvider();
   ASSERT_TRUE(default_search);
@@ -810,6 +769,7 @@
             default_search->search_terms_replacement_key());
   EXPECT_EQ(kImageURL, default_search->image_url());
   EXPECT_EQ(kImageURLPostParams, default_search->image_url_post_params());
+  EXPECT_EQ(kNewTabURL, default_search->new_tab_url());
 
   // Verify that searching from the omnibox uses kSearchURL.
   chrome::FocusLocationBar(browser());
@@ -1834,27 +1794,6 @@
   CheckURLIsBlocked(browser(), file_path2.c_str());
 }
 
-// Flaky on Linux. http://crbug.com/155459
-#if defined(OS_LINUX)
-#define MAYBE_DisableScreenshotsFeedback DISABLED_DisableScreenshotsFeedback
-#else
-#define MAYBE_DisableScreenshotsFeedback DisableScreenshotsFeedback
-#endif
-IN_PROC_BROWSER_TEST_F(PolicyTest, MAYBE_DisableScreenshotsFeedback) {
-#if defined(OS_WIN) && defined(USE_ASH)
-  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
-    return;
-#endif
-
-  // Make sure current screenshot can be taken and displayed on feedback page.
-  TestScreenshotFeedback(true);
-
-  // Check if banning screenshots disabled feedback page's ability to grab a
-  // screenshot.
-  TestScreenshotFeedback(false);
-}
-
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(PolicyTest, DisableScreenshotsFile) {
   int screenshot_count = CountScreenshots();
diff --git a/chrome/browser/policy/policy_domain_descriptor.cc b/chrome/browser/policy/policy_domain_descriptor.cc
index 0999062..c841a55 100644
--- a/chrome/browser/policy/policy_domain_descriptor.cc
+++ b/chrome/browser/policy/policy_domain_descriptor.cc
@@ -9,7 +9,7 @@
 #include "base/values.h"
 #include "chrome/browser/policy/policy_bundle.h"
 #include "chrome/browser/policy/policy_map.h"
-#include "chrome/common/policy/policy_schema.h"
+#include "components/policy/core/common/policy_schema.h"
 
 namespace policy {
 
diff --git a/chrome/browser/policy/policy_domain_descriptor_unittest.cc b/chrome/browser/policy/policy_domain_descriptor_unittest.cc
index 06e103d..9a03f8e 100644
--- a/chrome/browser/policy/policy_domain_descriptor_unittest.cc
+++ b/chrome/browser/policy/policy_domain_descriptor_unittest.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/policy/external_data_manager.h"
 #include "chrome/browser/policy/policy_bundle.h"
 #include "chrome/browser/policy/policy_map.h"
-#include "chrome/common/policy/policy_schema.h"
+#include "components/policy/core/common/policy_schema.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace policy {
diff --git a/chrome/browser/policy/policy_loader_mac.cc b/chrome/browser/policy/policy_loader_mac.cc
index 4a94bbb..29774f0 100644
--- a/chrome/browser/policy/policy_loader_mac.cc
+++ b/chrome/browser/policy/policy_loader_mac.cc
@@ -12,6 +12,7 @@
 #include "base/mac/scoped_cftyperef.h"
 #include "base/path_service.h"
 #include "base/platform_file.h"
+#include "base/sequenced_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/policy/external_data_fetcher.h"
@@ -20,8 +21,7 @@
 #include "chrome/browser/policy/policy_load_status.h"
 #include "chrome/browser/policy/policy_map.h"
 #include "chrome/browser/policy/preferences_mac.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/policy/policy_schema.h"
+#include "components/policy/core/common/policy_schema.h"
 #include "policy/policy_constants.h"
 
 using base::mac::CFCast;
@@ -31,27 +31,6 @@
 
 namespace {
 
-base::FilePath GetManagedPolicyPath() {
-  // This constructs the path to the plist file in which Mac OS X stores the
-  // managed preference for the application. This is undocumented and therefore
-  // fragile, but if it doesn't work out, AsyncPolicyLoader has a task that
-  // polls periodically in order to reload managed preferences later even if we
-  // missed the change.
-  base::FilePath path;
-  if (!PathService::Get(chrome::DIR_MANAGED_PREFS, &path))
-    return base::FilePath();
-
-  CFBundleRef bundle(CFBundleGetMainBundle());
-  if (!bundle)
-    return base::FilePath();
-
-  CFStringRef bundle_id = CFBundleGetIdentifier(bundle);
-  if (!bundle_id)
-    return base::FilePath();
-
-  return path.Append(base::SysCFStringRefToUTF8(bundle_id) + ".plist");
-}
-
 // Callback function for CFDictionaryApplyFunction. |key| and |value| are an
 // entry of the CFDictionary that should be converted into an equivalent entry
 // in the DictionaryValue in |context|.
@@ -80,15 +59,19 @@
 
 }  // namespace
 
-PolicyLoaderMac::PolicyLoaderMac(const PolicyDefinitionList* policy_list,
-                                 MacPreferences* preferences)
-    : policy_list_(policy_list),
+PolicyLoaderMac::PolicyLoaderMac(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    const PolicyDefinitionList* policy_list,
+    const base::FilePath& managed_policy_path,
+    MacPreferences* preferences)
+    : AsyncPolicyLoader(task_runner),
+      policy_list_(policy_list),
       preferences_(preferences),
-      managed_policy_path_(GetManagedPolicyPath()) {}
+      managed_policy_path_(managed_policy_path) {}
 
 PolicyLoaderMac::~PolicyLoaderMac() {}
 
-void PolicyLoaderMac::InitOnFile() {
+void PolicyLoaderMac::InitOnBackgroundThread() {
   if (!managed_policy_path_.empty()) {
     watcher_.Watch(
         managed_policy_path_, false,
diff --git a/chrome/browser/policy/policy_loader_mac.h b/chrome/browser/policy/policy_loader_mac.h
index 1d6d5fa..104ec90 100644
--- a/chrome/browser/policy/policy_loader_mac.h
+++ b/chrome/browser/policy/policy_loader_mac.h
@@ -17,6 +17,7 @@
 class MacPreferences;
 
 namespace base {
+class SequencedTaskRunner;
 class Value;
 }  // namespace base
 
@@ -31,12 +32,14 @@
 // watches the managed preferences files for updates.
 class PolicyLoaderMac : public AsyncPolicyLoader {
  public:
-  PolicyLoaderMac(const PolicyDefinitionList* policy_list,
+  PolicyLoaderMac(scoped_refptr<base::SequencedTaskRunner> task_runner,
+                  const PolicyDefinitionList* policy_list,
+                  const base::FilePath& managed_policy_path,
                   MacPreferences* preferences);
   virtual ~PolicyLoaderMac();
 
   // AsyncPolicyLoader implementation.
-  virtual void InitOnFile() OVERRIDE;
+  virtual void InitOnBackgroundThread() OVERRIDE;
   virtual scoped_ptr<PolicyBundle> Load() OVERRIDE;
   virtual base::Time LastModificationTime() OVERRIDE;
 
diff --git a/chrome/browser/policy/policy_loader_mac_unittest.cc b/chrome/browser/policy/policy_loader_mac_unittest.cc
index 8d725a2..76c2bc1 100644
--- a/chrome/browser/policy/policy_loader_mac_unittest.cc
+++ b/chrome/browser/policy/policy_loader_mac_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback.h"
+#include "base/files/file_path.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
@@ -126,6 +127,7 @@
   virtual void SetUp() OVERRIDE;
 
   virtual ConfigurationPolicyProvider* CreateProvider(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_definition_list) OVERRIDE;
 
   virtual void InstallEmptyPolicy() OVERRIDE;
@@ -158,10 +160,11 @@
 void TestHarness::SetUp() {}
 
 ConfigurationPolicyProvider* TestHarness::CreateProvider(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
     const PolicyDefinitionList* policy_definition_list) {
   prefs_ = new MockPreferences();
-  scoped_ptr<AsyncPolicyLoader> loader(
-      new PolicyLoaderMac(policy_definition_list, prefs_));
+  scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderMac(
+      task_runner, policy_definition_list, base::FilePath(), prefs_));
   return new AsyncPolicyProvider(loader.Pass());
 }
 
@@ -230,7 +233,10 @@
  protected:
   PolicyLoaderMacTest()
       : prefs_(new MockPreferences()),
-        loader_(new PolicyLoaderMac(&test_policy_definitions::kList, prefs_)),
+        loader_(new PolicyLoaderMac(loop_.message_loop_proxy(),
+                                    &test_policy_definitions::kList,
+                                    base::FilePath(),
+                                    prefs_)),
         provider_(scoped_ptr<AsyncPolicyLoader>(loader_)) {}
   virtual ~PolicyLoaderMacTest() {}
 
diff --git a/chrome/browser/policy/policy_loader_win.cc b/chrome/browser/policy/policy_loader_win.cc
index 3f59663..451ac08 100644
--- a/chrome/browser/policy/policy_loader_win.cc
+++ b/chrome/browser/policy/policy_loader_win.cc
@@ -23,6 +23,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/scoped_native_library.h"
+#include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
@@ -31,7 +32,7 @@
 #include "chrome/browser/policy/policy_map.h"
 #include "chrome/browser/policy/preg_parser_win.h"
 #include "chrome/browser/policy/registry_dict_win.h"
-#include "chrome/common/json_schema/json_schema_constants.h"
+#include "components/json_schema/json_schema_constants.h"
 #include "policy/policy_constants.h"
 
 namespace schema = json_schema_constants;
@@ -207,10 +208,13 @@
 const base::FilePath::CharType PolicyLoaderWin::kPRegFileName[] =
     FILE_PATH_LITERAL("Registry.pol");
 
-PolicyLoaderWin::PolicyLoaderWin(const PolicyDefinitionList* policy_list,
-                                 const string16& chrome_policy_key,
-                                 AppliedGPOListProvider* gpo_provider)
-    : is_initialized_(false),
+PolicyLoaderWin::PolicyLoaderWin(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    const PolicyDefinitionList* policy_list,
+    const string16& chrome_policy_key,
+    AppliedGPOListProvider* gpo_provider)
+    : AsyncPolicyLoader(task_runner),
+      is_initialized_(false),
       policy_list_(policy_list),
       chrome_policy_key_(chrome_policy_key),
       gpo_provider_(gpo_provider),
@@ -235,13 +239,14 @@
 
 // static
 scoped_ptr<PolicyLoaderWin> PolicyLoaderWin::Create(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
     const PolicyDefinitionList* policy_list) {
   return make_scoped_ptr(
-      new PolicyLoaderWin(policy_list, kRegistryChromePolicyKey,
+      new PolicyLoaderWin(task_runner, policy_list, kRegistryChromePolicyKey,
                           g_win_gpo_list_provider.Pointer()));
 }
 
-void PolicyLoaderWin::InitOnFile() {
+void PolicyLoaderWin::InitOnBackgroundThread() {
   is_initialized_ = true;
   SetupWatches();
 }
diff --git a/chrome/browser/policy/policy_loader_win.h b/chrome/browser/policy/policy_loader_win.h
index baf25ef..3b6f13a 100644
--- a/chrome/browser/policy/policy_loader_win.h
+++ b/chrome/browser/policy/policy_loader_win.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/values.h"
@@ -17,6 +18,10 @@
 #include "chrome/browser/policy/async_policy_loader.h"
 #include "chrome/browser/policy/policy_types.h"
 
+namespace base {
+class SequencedTaskRunner;
+}
+
 namespace policy {
 
 class AppliedGPOListProvider;
@@ -45,17 +50,19 @@
   // The PReg file name used by GPO.
   static const base::FilePath::CharType kPRegFileName[];
 
-  explicit PolicyLoaderWin(const PolicyDefinitionList* policy_list,
-                           const string16& chrome_policy_key,
-                           AppliedGPOListProvider* gpo_provider);
+  PolicyLoaderWin(scoped_refptr<base::SequencedTaskRunner> task_runner,
+                  const PolicyDefinitionList* policy_list,
+                  const string16& chrome_policy_key,
+                  AppliedGPOListProvider* gpo_provider);
   virtual ~PolicyLoaderWin();
 
   // Creates a policy loader that uses the Win API to access GPO.
   static scoped_ptr<PolicyLoaderWin> Create(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_list);
 
   // AsyncPolicyLoader implementation.
-  virtual void InitOnFile() OVERRIDE;
+  virtual void InitOnBackgroundThread() OVERRIDE;
   virtual scoped_ptr<PolicyBundle> Load() OVERRIDE;
 
  private:
diff --git a/chrome/browser/policy/policy_loader_win_unittest.cc b/chrome/browser/policy/policy_loader_win_unittest.cc
index 696f0c1..de822a1 100644
--- a/chrome/browser/policy/policy_loader_win_unittest.cc
+++ b/chrome/browser/policy/policy_loader_win_unittest.cc
@@ -13,6 +13,7 @@
 #include <iterator>
 #include <vector>
 
+#include "base/base_paths.h"
 #include "base/callback.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
@@ -33,8 +34,7 @@
 #include "chrome/browser/policy/policy_bundle.h"
 #include "chrome/browser/policy/policy_map.h"
 #include "chrome/browser/policy/preg_parser_win.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/json_schema/json_schema_constants.h"
+#include "components/json_schema/json_schema_constants.h"
 #include "policy/policy_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -252,6 +252,7 @@
   virtual void SetUp() OVERRIDE;
 
   virtual ConfigurationPolicyProvider* CreateProvider(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_list) OVERRIDE;
 
   virtual void InstallEmptyPolicy() OVERRIDE;
@@ -302,6 +303,7 @@
   virtual void SetUp() OVERRIDE;
 
   virtual ConfigurationPolicyProvider* CreateProvider(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
       const PolicyDefinitionList* policy_list) OVERRIDE;
 
   virtual void InstallEmptyPolicy() OVERRIDE;
@@ -418,9 +420,10 @@
 void RegistryTestHarness::SetUp() {}
 
 ConfigurationPolicyProvider* RegistryTestHarness::CreateProvider(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
     const PolicyDefinitionList* policy_list) {
-  scoped_ptr<AsyncPolicyLoader> loader(
-      new PolicyLoaderWin(policy_list, kRegistryChromePolicyKey, this));
+  scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(
+      task_runner, policy_list, kRegistryChromePolicyKey, this));
   return new AsyncPolicyProvider(loader.Pass());
 }
 
@@ -549,9 +552,10 @@
 }
 
 ConfigurationPolicyProvider* PRegTestHarness::CreateProvider(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
     const PolicyDefinitionList* policy_list) {
-  scoped_ptr<AsyncPolicyLoader> loader(
-      new PolicyLoaderWin(policy_list, kRegistryChromePolicyKey, this));
+  scoped_ptr<AsyncPolicyLoader> loader(new PolicyLoaderWin(
+      task_runner, policy_list, kRegistryChromePolicyKey, this));
   return new AsyncPolicyProvider(loader.Pass());
 }
 
@@ -785,8 +789,12 @@
   virtual ~PolicyLoaderWinTest() {}
 
   virtual void SetUp() OVERRIDE {
-    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_));
-    test_data_dir_ = test_data_dir_.AppendASCII("policy").AppendASCII("gpo");
+    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir_));
+    test_data_dir_ = test_data_dir_.AppendASCII("chrome")
+                                   .AppendASCII("test")
+                                   .AppendASCII("data")
+                                   .AppendASCII("policy")
+                                   .AppendASCII("gpo");
   }
 
   // AppliedGPOListProvider:
@@ -815,7 +823,8 @@
   }
 
   bool Matches(const PolicyBundle& expected) {
-    PolicyLoaderWin loader(&test_policy_definitions::kList, kTestPolicyKey,
+    PolicyLoaderWin loader(loop_.message_loop_proxy(),
+                           &test_policy_definitions::kList, kTestPolicyKey,
                            this);
     scoped_ptr<PolicyBundle> loaded(loader.Load());
     return loaded->Equals(expected);
diff --git a/chrome/browser/policy/policy_service_impl_unittest.cc b/chrome/browser/policy/policy_service_impl_unittest.cc
index 364e3c4..c34cb2b 100644
--- a/chrome/browser/policy/policy_service_impl_unittest.cc
+++ b/chrome/browser/policy/policy_service_impl_unittest.cc
@@ -15,9 +15,7 @@
 #include "chrome/browser/policy/mock_configuration_policy_provider.h"
 #include "chrome/browser/policy/mock_policy_service.h"
 #include "chrome/browser/policy/policy_domain_descriptor.h"
-#include "chrome/common/policy/policy_schema.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "components/policy/core/common/policy_schema.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -142,6 +140,7 @@
   }
 
  protected:
+  base::MessageLoop loop_;
   MockConfigurationPolicyProvider provider0_;
   MockConfigurationPolicyProvider provider1_;
   MockConfigurationPolicyProvider provider2_;
@@ -149,7 +148,6 @@
   PolicyMap policy1_;
   PolicyMap policy2_;
   scoped_ptr<PolicyServiceImpl> policy_service_;
-  content::TestBrowserThreadBundle thread_bundle_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PolicyServiceTest);
diff --git a/chrome/browser/policy/preg_parser_win_unittest.cc b/chrome/browser/policy/preg_parser_win_unittest.cc
index 0c39e06..31ba4f0 100644
--- a/chrome/browser/policy/preg_parser_win_unittest.cc
+++ b/chrome/browser/policy/preg_parser_win_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/policy/preg_parser_win.h"
 
+#include "base/base_paths.h"
 #include "base/files/file_path.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
@@ -11,7 +12,6 @@
 #include "base/values.h"
 #include "chrome/browser/policy/policy_load_status.h"
 #include "chrome/browser/policy/registry_dict_win.h"
-#include "chrome/common/chrome_paths.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace policy {
@@ -69,7 +69,7 @@
 
 TEST(PRegParserWinTest, TestParseFile) {
   base::FilePath test_data_dir;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+  ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
 
   // Prepare the test dictionary with some data so the test can check that the
   // PReg action triggers work, i.e. remove these items.
@@ -88,7 +88,8 @@
   dict.SetKey("DelValsTest", subdict.Pass());
 
   // Run the parser.
-  base::FilePath test_file(test_data_dir.AppendASCII("policy/registry.pol"));
+  base::FilePath test_file(
+      test_data_dir.AppendASCII("chrome/test/data/policy/registry.pol"));
   PolicyLoadStatusSample status;
   ASSERT_TRUE(preg_parser::ReadFile(
       test_file, L"SOFTWARE\\Policies\\Chromium", &dict, &status));
diff --git a/chrome/browser/policy/profile_policy_connector.cc b/chrome/browser/policy/profile_policy_connector.cc
index 65b95e5..9ea5c81 100644
--- a/chrome/browser/policy/profile_policy_connector.cc
+++ b/chrome/browser/policy/profile_policy_connector.cc
@@ -29,8 +29,6 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/policy/policy_service.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/dbus/cryptohome_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #else
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
@@ -63,7 +61,7 @@
     providers.push_back(cloud_policy_manager);
 
   bool allow_trusted_certs_from_policy = false;
-  std::string username;
+  chromeos::User* user = NULL;
   if (chromeos::ProfileHelper::IsSigninProfile(profile_)) {
     special_user_policy_provider_.reset(new LoginProfilePolicyProvider(
         connector->GetPolicyService()));
@@ -73,9 +71,9 @@
     // TODO(joaodasilva): get the |user| that corresponds to the |profile_|
     // from the ProfileHelper, once that's ready.
     chromeos::UserManager* user_manager = chromeos::UserManager::Get();
-    chromeos::User* user = user_manager->GetActiveUser();
+    user = user_manager->GetActiveUser();
     CHECK(user);
-    username = user->email();
+    std::string username = user->email();
     is_primary_user_ =
         chromeos::UserManager::Get()->GetLoggedInUsers().size() == 1;
     if (user->GetType() == chromeos::User::USER_TYPE_PUBLIC_ACCOUNT)
@@ -112,14 +110,10 @@
     else if (special_user_policy_provider_)
       connector->SetUserPolicyDelegate(special_user_policy_provider_.get());
 
-    chromeos::CryptohomeClient* cryptohome_client =
-        chromeos::DBusThreadManager::Get()->GetCryptohomeClient();
-    cryptohome_client->GetSanitizedUsername(
-        username,
-        base::Bind(
-            &ProfilePolicyConnector::InitializeNetworkConfigurationUpdater,
-            weak_ptr_factory_.GetWeakPtr(),
-            allow_trusted_certs_from_policy));
+    // A reference to |user| is stored by the NetworkConfigurationUpdater until
+    // UnsetUserPolicyService during Shutdown is called.
+    connector->network_configuration_updater()->SetUserPolicyService(
+        allow_trusted_certs_from_policy, user, policy_service());
   }
 #endif
 }
@@ -167,18 +161,6 @@
       username, device_local_account_policy_service));
   special_user_policy_provider_->Init();
 }
-
-void ProfilePolicyConnector::InitializeNetworkConfigurationUpdater(
-    bool allow_trusted_certs_from_policy,
-    chromeos::DBusMethodCallStatus status,
-    const std::string& hashed_username) {
-  // TODO(joaodasilva): create the NetworkConfigurationUpdater for user ONC
-  // here, after splitting that class into an instance for device policy and
-  // another per profile for user policy.
-  g_browser_process->browser_policy_connector()->
-      network_configuration_updater()->SetUserPolicyService(
-          allow_trusted_certs_from_policy, hashed_username, policy_service());
-}
 #endif
 
 }  // namespace policy
diff --git a/chrome/browser/policy/profile_policy_connector.h b/chrome/browser/policy/profile_policy_connector.h
index a7d726d..1fc3531 100644
--- a/chrome/browser/policy/profile_policy_connector.h
+++ b/chrome/browser/policy/profile_policy_connector.h
@@ -63,13 +63,6 @@
 
 #if defined(OS_CHROMEOS)
   void InitializeDeviceLocalAccountPolicyProvider(const std::string& username);
-
-  // Callback for CryptohomeClient::GetSanitizedUsername() that initializes the
-  // NetworkConfigurationUpdater after receiving the hashed username.
-  void InitializeNetworkConfigurationUpdater(
-      bool is_managed,
-      chromeos::DBusMethodCallStatus status,
-      const std::string& hashed_username);
 #endif
 
   Profile* profile_;
diff --git a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
index a88f58f..9e78633 100644
--- a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
+++ b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
@@ -238,7 +238,11 @@
 
 message SystemUse24HourClockProto {
   // Specifies an owner-determined clock format that applies to the login
-  // screen and all users.
+  // screen and is used as a default for all user sessions. Users can still
+  // override the format to use for their account.
+  //
+  // True and false select a 24 and 12 hour clock format, respectively. The
+  // default format for the case the setting is not present is 24 hour clock.
   optional bool use_24hour_clock = 1;
 }
 
@@ -346,12 +350,19 @@
 message AttestationSettingsProto {
   // Attestation involves proving that a cryptographic key is protected by a
   // legitimate Chrome OS TPM and reporting the operating mode of the platform.
-  // This setting enables attestation features at a device level.  If this is
-  // enabled a machine key will be generated and certified by the Chrome OS
-  // CA.  If this setting is disabled, the device will not communicate with the
-  // Chrome OS CA under any circumstances.  Even users with attestation settings
+  // This setting enables enterprise attestation features at a device level.  If
+  // this is enabled a machine key will be generated and certified by the Chrome
+  // OS CA.  If this setting is disabled, even users with attestation settings
   // enabled will not be able to use those features on the device.
   optional bool attestation_enabled = 1;
+
+  // Chrome OS devices can use remote attestation (Verified Access) to get a
+  // certificate issued by the Chrome OS CA that asserts the device is eligible
+  // to play protected content.  This process involves sending hardware
+  // endorsement information to the Chrome OS CA which uniquely identifies the
+  // device.  This setting allows this feature to be disabled for the device
+  // regardless of any user-specific settings.
+  optional bool content_protection_enabled = 2;
 }
 
 message AccessibilitySettingsProto {
diff --git a/chrome/browser/policy/registry_dict_win.cc b/chrome/browser/policy/registry_dict_win.cc
index b99cca3..00a5193 100644
--- a/chrome/browser/policy/registry_dict_win.cc
+++ b/chrome/browser/policy/registry_dict_win.cc
@@ -12,7 +12,7 @@
 #include "base/sys_byteorder.h"
 #include "base/values.h"
 #include "base/win/registry.h"
-#include "chrome/common/json_schema/json_schema_constants.h"
+#include "components/json_schema/json_schema_constants.h"
 
 namespace schema = json_schema_constants;
 
diff --git a/chrome/browser/policy/registry_dict_win_unittest.cc b/chrome/browser/policy/registry_dict_win_unittest.cc
index 59aa69f..6f31397 100644
--- a/chrome/browser/policy/registry_dict_win_unittest.cc
+++ b/chrome/browser/policy/registry_dict_win_unittest.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/policy/registry_dict_win.h"
 
 #include "base/values.h"
-#include "chrome/common/json_schema/json_schema_constants.h"
+#include "components/json_schema/json_schema_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace schema = json_schema_constants;
diff --git a/chrome/browser/policy/test/DEPS b/chrome/browser/policy/test/DEPS
deleted file mode 100644
index eec0a93..0000000
--- a/chrome/browser/policy/test/DEPS
+++ /dev/null
@@ -1,18 +0,0 @@
-# The //chrome/browser/policy code is being converted into a component at
-# //components/policy. This DEPS file is temporarily restricting the include
-# rules for this code; once all the exceptions are fixed then the code will
-# be moved, and this file will be removed.
-# http://crbug.com/271392
-
-include_rules = [
-  "-chrome",
-  "-chromeos",
-  "-content",
-  "+chrome/browser/policy",
-]
-
-specific_include_rules = {
-  r"local_policy_test_server\.cc": [
-    "+chrome/common/chrome_paths.h",
-  ],
-}
diff --git a/chrome/browser/policy/test/local_policy_test_server.cc b/chrome/browser/policy/test/local_policy_test_server.cc
index 5041d8d..0cc1156 100644
--- a/chrome/browser/policy/test/local_policy_test_server.cc
+++ b/chrome/browser/policy/test/local_policy_test_server.cc
@@ -9,13 +9,13 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/base_paths.h"
 #include "base/file_util.h"
 #include "base/json/json_writer.h"
 #include "base/path_service.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
-#include "chrome/common/chrome_paths.h"
 #include "crypto/rsa_private_key.h"
 #include "net/test/python_utils.h"
 #include "net/test/spawned_test_server/base_test_server.h"
@@ -72,8 +72,11 @@
                            base::FilePath()) {
   // Read configuration from a file in chrome/test/data/policy.
   base::FilePath source_root;
-  CHECK(PathService::Get(chrome::DIR_TEST_DATA, &source_root));
+  CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &source_root));
   config_file_ = source_root
+      .AppendASCII("chrome")
+      .AppendASCII("test")
+      .AppendASCII("data")
       .AppendASCII("policy")
       .AppendASCII(base::StringPrintf("policy_%s.json", test_name.c_str()));
 }
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 8e3fcb3..9284479 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/api/commands/command_service.h"
 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
 #include "chrome/browser/extensions/extension_prefs.h"
@@ -131,6 +132,7 @@
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/login/user_image_manager.h"
+#include "chrome/browser/chromeos/login/user_image_sync_observer.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
 #include "chrome/browser/chromeos/net/proxy_config_handler.h"
@@ -325,6 +327,7 @@
   SessionStartupPref::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
   TranslatePrefs::RegisterProfilePrefs(registry);
+  extensions::ActivityLog::RegisterProfilePrefs(registry);
 
 #if defined(ENABLE_AUTOFILL_DIALOG)
   autofill::AutofillDialogController::RegisterProfilePrefs(registry);
@@ -387,6 +390,7 @@
   extensions::EnterprisePlatformKeysPrivateChallengeUserKeyFunction::
       RegisterProfilePrefs(registry);
   FlagsUI::RegisterProfilePrefs(registry);
+  chromeos::UserImageSyncObserver::RegisterProfilePrefs(registry);
 #endif
 
 #if defined(OS_WIN)
@@ -448,6 +452,10 @@
   PrefsTabHelper::MigrateUserPrefs(prefs);
   PromoResourceService::MigrateUserPrefs(prefs);
   TranslatePrefs::MigrateUserPrefs(prefs);
+
+#if defined(ENABLE_MANAGED_USERS)
+  ManagedUserService::MigrateUserPrefs(prefs);
+#endif
 }
 
 void MigrateBrowserPrefs(Profile* profile, PrefService* local_state) {
diff --git a/chrome/browser/prefs/pref_metrics_service.cc b/chrome/browser/prefs/pref_metrics_service.cc
index a437c8c..3814032 100644
--- a/chrome/browser/prefs/pref_metrics_service.cc
+++ b/chrome/browser/prefs/pref_metrics_service.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/prefs/synced_pref_change_registrar.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
 #include "chrome/common/pref_names.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -49,16 +50,45 @@
   UMA_HISTOGRAM_BOOLEAN("Settings.ShowHomeButton", show_home_button);
   if (show_home_button) {
     UMA_HISTOGRAM_BOOLEAN("Settings.GivenShowHomeButton_HomePageIsNewTabPage",
-        home_page_is_ntp);
+                          home_page_is_ntp);
   }
+
+  // For non-NTP homepages, see if the URL comes from the same TLD+1 as a known
+  // search engine.  Note that this is only an approximation of search engine
+  // use, due to both false negatives (pages that come from unknown TLD+1 X but
+  // consist of a search box that sends to known TLD+1 Y) and false positives
+  // (pages that share a TLD+1 with a known engine but aren't actually search
+  // pages, e.g. plus.google.com).
+  if (!home_page_is_ntp) {
+    GURL homepage_url(prefs->GetString(prefs::kHomePage));
+    if (homepage_url.is_valid()) {
+      UMA_HISTOGRAM_ENUMERATION(
+          "Settings.HomePageEngineType",
+          TemplateURLPrepopulateData::GetEngineType(homepage_url),
+          SEARCH_ENGINE_MAX);
+    }
+  }
+
   int restore_on_startup = prefs->GetInteger(prefs::kRestoreOnStartup);
   UMA_HISTOGRAM_ENUMERATION("Settings.StartupPageLoadSettings",
-      restore_on_startup, kSessionStartupPrefValueMax);
+                            restore_on_startup, kSessionStartupPrefValueMax);
   if (restore_on_startup == SessionStartupPref::kPrefValueURLs) {
-    const int url_list_size = prefs->GetList(
-        prefs::kURLsToRestoreOnStartup)->GetSize();
-    UMA_HISTOGRAM_CUSTOM_COUNTS(
-        "Settings.StartupPageLoadURLs", url_list_size, 1, 50, 20);
+    const ListValue* url_list = prefs->GetList(prefs::kURLsToRestoreOnStartup);
+    UMA_HISTOGRAM_CUSTOM_COUNTS("Settings.StartupPageLoadURLs",
+                                url_list->GetSize(), 1, 50, 20);
+    // Similarly, check startup pages for known search engine TLD+1s.
+    std::string url_text;
+    for (size_t i = 0; i < url_list->GetSize(); i++) {
+      if (url_list->GetString(i, &url_text)) {
+        GURL start_url(url_text);
+        if (start_url.is_valid()) {
+          UMA_HISTOGRAM_ENUMERATION(
+              "Settings.StartupPageEngineTypes",
+              TemplateURLPrepopulateData::GetEngineType(start_url),
+              SEARCH_ENGINE_MAX);
+        }
+      }
+    }
   }
 }
 
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 12ba041..e049827 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -89,24 +89,6 @@
     callback.Run(false);
   }
 
-  virtual bool ShouldCreateWebContents(
-      WebContents* web_contents,
-      int route_id,
-      WindowContainerType window_container_type,
-      const string16& frame_name,
-      const GURL& target_url,
-      const content::Referrer& referrer,
-      WindowOpenDisposition disposition,
-      const WebKit::WebWindowFeatures& features,
-      bool user_gesture,
-      bool opener_suppressed) OVERRIDE {
-    // Since we don't want to permit child windows that would have a
-    // window.opener property, terminate prerendering.
-    prerender_contents_->Destroy(FINAL_STATUS_CREATE_NEW_WINDOW);
-    // Cancel the popup.
-    return false;
-  }
-
   virtual bool OnGoToEntryOffset(int offset) OVERRIDE {
     // This isn't allowed because the history merge operation
     // does not work if there are renderer issued challenges.
diff --git a/chrome/browser/prerender/prerender_histograms.cc b/chrome/browser/prerender/prerender_histograms.cc
index fba4c52..7e7fd42 100644
--- a/chrome/browser/prerender/prerender_histograms.cc
+++ b/chrome/browser/prerender/prerender_histograms.cc
@@ -250,7 +250,7 @@
     base::TimeDelta perceived_page_load_time,
     bool was_prerender,
     bool was_complete_prerender, const GURL& url) {
-  if (!IsWebURL(url))
+  if (!url.SchemeIsHTTPOrHTTPS())
     return;
   bool within_window = WithinWindow();
   bool is_google_url = IsGoogleDomain(url);
@@ -303,7 +303,7 @@
     const GURL& url) const {
   // If the URL to be prerendered is not a http[s] URL, or is a Google URL,
   // do not record.
-  if (!IsWebURL(url) || IsGoogleDomain(url))
+  if (!url.SchemeIsHTTPOrHTTPS() || IsGoogleDomain(url))
     return;
   RECORD_PLT("PrerenderNotSwappedInPLT", page_load_time);
 }
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 14aaa3b..f704d40 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -900,7 +900,7 @@
 
 // static
 bool PrerenderManager::DoesURLHaveValidScheme(const GURL& url) {
-  return (IsWebURL(url) ||
+  return (url.SchemeIsHTTPOrHTTPS() ||
           url.SchemeIs(extensions::kExtensionScheme) ||
           url.SchemeIs("data"));
 }
@@ -1471,7 +1471,7 @@
 
 void PrerenderManager::RecordLikelyLoginOnURL(const GURL& url) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (!IsWebURL(url))
+  if (!url.SchemeIsHTTPOrHTTPS())
     return;
   if (logged_in_predictor_table_.get()) {
     BrowserThread::PostTask(
diff --git a/chrome/browser/prerender/prerender_tab_helper.cc b/chrome/browser/prerender/prerender_tab_helper.cc
index cd67ad2..17ff619 100644
--- a/chrome/browser/prerender/prerender_tab_helper.cc
+++ b/chrome/browser/prerender/prerender_tab_helper.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/prerender/prerender_tab_helper.h"
 
+#include "base/bind.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
+#include "chrome/browser/password_manager/password_manager.h"
 #include "chrome/browser/predictors/logged_in_predictor_table.h"
 #include "chrome/browser/prerender/prerender_histograms.h"
 #include "chrome/browser/prerender/prerender_local_predictor.h"
@@ -150,9 +152,24 @@
   PrerenderTabHelper* tab_helper_;
 };
 
-PrerenderTabHelper::PrerenderTabHelper(content::WebContents* web_contents)
+// static
+void PrerenderTabHelper::CreateForWebContentsWithPasswordManager(
+    content::WebContents* web_contents,
+    PasswordManager* password_manager) {
+  if (!FromWebContents(web_contents)) {
+    web_contents->SetUserData(UserDataKey(),
+                              new PrerenderTabHelper(web_contents,
+                                                     password_manager));
+  }
+}
+
+PrerenderTabHelper::PrerenderTabHelper(content::WebContents* web_contents,
+                                       PasswordManager* password_manager)
     : content::WebContentsObserver(web_contents),
       weak_factory_(this) {
+  password_manager->AddSubmissionCallback(
+      base::Bind(&PrerenderTabHelper::PasswordSubmitted,
+                 weak_factory_.GetWeakPtr()));
 }
 
 PrerenderTabHelper::~PrerenderTabHelper() {
@@ -243,22 +260,13 @@
   }
 }
 
-void PrerenderTabHelper::DidNavigateAnyFrame(
-      const content::LoadCommittedDetails& details,
-      const content::FrameNavigateParams& params) {
+void PrerenderTabHelper::PasswordSubmitted(const content::PasswordForm& form) {
   PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
-  if (params.password_form.origin.is_valid() && prerender_manager) {
-    prerender_manager->RecordLikelyLoginOnURL(params.url);
+  if (prerender_manager) {
+    prerender_manager->RecordLikelyLoginOnURL(form.origin);
     RecordEvent(EVENT_LOGIN_ACTION_ADDED);
-    if (details.is_main_frame) {
-      RecordEvent(EVENT_LOGIN_ACTION_ADDED_MAINFRAME);
-      if (params.password_form.password_value.empty())
-        RecordEvent(EVENT_LOGIN_ACTION_ADDED_MAINFRAME_PW_EMPTY);
-    } else {
-      RecordEvent(EVENT_LOGIN_ACTION_ADDED_SUBFRAME);
-      if (params.password_form.password_value.empty())
-        RecordEvent(EVENT_LOGIN_ACTION_ADDED_SUBFRAME_PW_EMPTY);
-    }
+    if (form.password_value.empty())
+      RecordEvent(EVENT_LOGIN_ACTION_ADDED_PW_EMPTY);
   }
 }
 
diff --git a/chrome/browser/prerender/prerender_tab_helper.h b/chrome/browser/prerender/prerender_tab_helper.h
index c48290e..4bfdd19 100644
--- a/chrome/browser/prerender/prerender_tab_helper.h
+++ b/chrome/browser/prerender/prerender_tab_helper.h
@@ -12,6 +12,12 @@
 #include "content/public/browser/web_contents_user_data.h"
 #include "url/gurl.h"
 
+class PasswordManager;
+
+namespace content {
+struct PasswordForm;
+}
+
 namespace predictors {
 class LoggedInPredictorTable;
 }
@@ -34,13 +40,14 @@
     EVENT_MAINFRAME_COMMIT = 4,
     EVENT_MAINFRAME_COMMIT_DOMAIN_LOGGED_IN = 5,
     EVENT_LOGIN_ACTION_ADDED = 6,
-    EVENT_LOGIN_ACTION_ADDED_MAINFRAME = 7,
-    EVENT_LOGIN_ACTION_ADDED_MAINFRAME_PW_EMPTY = 8,
-    EVENT_LOGIN_ACTION_ADDED_SUBFRAME = 9,
-    EVENT_LOGIN_ACTION_ADDED_SUBFRAME_PW_EMPTY = 10,
+    EVENT_LOGIN_ACTION_ADDED_PW_EMPTY = 7,
     EVENT_MAX_VALUE
   };
 
+  static void CreateForWebContentsWithPasswordManager(
+      content::WebContents* web_contents,
+      PasswordManager* password_manager);
+
   virtual ~PrerenderTabHelper();
 
   // content::WebContentsObserver implementation.
@@ -63,15 +70,16 @@
       const GURL& validated_url,
       content::PageTransition transition_type,
       content::RenderViewHost* render_view_host) OVERRIDE;
-  virtual void DidNavigateAnyFrame(
-      const content::LoadCommittedDetails& details,
-      const content::FrameNavigateParams& params) OVERRIDE;
+
+  // Called when a password form has been submitted.
+  void PasswordSubmitted(const content::PasswordForm& form);
 
   // Called when this prerendered WebContents has just been swapped in.
   void PrerenderSwappedIn();
 
  private:
-  explicit PrerenderTabHelper(content::WebContents* web_contents);
+  PrerenderTabHelper(content::WebContents* web_contents,
+                     PasswordManager* password_manager);
   friend class content::WebContentsUserData<PrerenderTabHelper>;
 
   void RecordEvent(Event event) const;
diff --git a/chrome/browser/prerender/prerender_util.cc b/chrome/browser/prerender/prerender_util.cc
index ca25418..1c4ab6f 100644
--- a/chrome/browser/prerender/prerender_util.cc
+++ b/chrome/browser/prerender/prerender_util.cc
@@ -79,10 +79,6 @@
           StartsWithASCII(url.path(), std::string("/webhp"), true));
 }
 
-bool IsWebURL(const GURL& url) {
-  return url.SchemeIs("http") || url.SchemeIs("https");
-}
-
 bool IsNoSwapInExperiment(uint8 experiment_id) {
   // Currently, experiments 5 and 6 fall in this category.
   return experiment_id == 5 || experiment_id == 6;
@@ -100,7 +96,7 @@
       content::ResourceRequestInfo::ForRequest(request);
   // Gather histogram information about the X-Mod-Pagespeed header.
   if (info->GetResourceType() == ResourceType::MAIN_FRAME &&
-      IsWebURL(request->url())) {
+      request->url().SchemeIsHTTPOrHTTPS()) {
     UMA_HISTOGRAM_SPARSE_SLOWLY(kModPagespeedHistogram, 0);
     if (request->response_headers() &&
         request->response_headers()->HasHeader(kModPagespeedHeader)) {
diff --git a/chrome/browser/prerender/prerender_util.h b/chrome/browser/prerender/prerender_util.h
index 1c0626e..fd93887 100644
--- a/chrome/browser/prerender/prerender_util.h
+++ b/chrome/browser/prerender/prerender_util.h
@@ -34,10 +34,6 @@
 // Indicates whether the URL provided could be a Google search result page.
 bool IsGoogleSearchResultURL(const GURL& url);
 
-// Returns true iff the URL provided is Web URL, using the scheme http
-// or https.
-bool IsWebURL(const GURL& url);
-
 // The prerender contents of some experiments should never be swapped in
 // by pretending to never match on the URL.  This function will return true
 // iff this is the case for the experiment_id specified.
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index 9c00e65..542d2d2 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/auto_reset.h"
-#include "base/command_line.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -27,7 +26,6 @@
 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_details.h"
@@ -396,17 +394,6 @@
   base::AutoReset<bool> auto_reset(&is_creating_print_preview_dialog_, true);
   Profile* profile =
       Profile::FromBrowserContext(initiator->GetBrowserContext());
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kChromeFrame)) {
-    // Chrome Frame only ever runs on the native desktop, so it is safe to
-    // create the popup on the native desktop.
-    Browser* current_browser = new Browser(
-        Browser::CreateParams(Browser::TYPE_POPUP, profile,
-                              chrome::GetActiveDesktop()));
-    if (!current_browser) {
-      NOTREACHED() << "Failed to create popup browser window";
-      return NULL;
-    }
-  }
 
   // |web_dialog_ui_delegate| deletes itself in
   // PrintPreviewDialogDelegate::OnDialogClosed().
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index 89c7bd7..5479409 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.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.
 
@@ -88,7 +88,7 @@
        !printing_enabled_.GetValue() || tab_content_blocked_));
 }
 
-void PrintViewManagerBase::StopNavigation() {
+void PrintViewManagerBase::NavigationStopped() {
   // Cancel the current job, wait for the worker to finish.
   TerminatePrintJob(true);
 }
diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h
index 03a90c6..88abb84 100644
--- a/chrome/browser/printing/print_view_manager_base.h
+++ b/chrome/browser/printing/print_view_manager_base.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.
 
@@ -56,6 +56,9 @@
   // content::WebContentsObserver implementation.
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
 
+  // IPC Message handlers.
+  virtual void OnPrintingFailed(int cookie);
+
  private:
   // content::NotificationObserver implementation.
   virtual void Observe(int type,
@@ -67,13 +70,12 @@
       content::RenderViewHost* render_view_host) OVERRIDE;
 
   // Cancels the print job.
-  virtual void StopNavigation() OVERRIDE;
+  virtual void NavigationStopped() OVERRIDE;
 
   // IPC Message handlers.
   void OnDidGetPrintedPagesCount(int cookie, int number_pages);
   void OnDidGetDocumentCookie(int cookie);
   void OnDidPrintPage(const PrintHostMsg_DidPrintPage_Params& params);
-  void OnPrintingFailed(int cookie);
 
   // Processes a NOTIFY_PRINT_JOB_EVENT notification.
   void OnNotifyPrintJobEvent(const JobEventDetails& event_details);
diff --git a/chrome/browser/printing/print_view_manager_basic.cc b/chrome/browser/printing/print_view_manager_basic.cc
index 6f524d1..d978999 100644
--- a/chrome/browser/printing/print_view_manager_basic.cc
+++ b/chrome/browser/printing/print_view_manager_basic.cc
@@ -1,9 +1,15 @@
-// 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.
 
 #include "chrome/browser/printing/print_view_manager_basic.h"
 
+#if defined(OS_ANDROID)
+#include "base/file_descriptor_posix.h"
+#include "chrome/common/print_messages.h"
+#include "printing/printing_context_android.h"
+#endif
+
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManagerBasic);
 
 namespace printing {
@@ -15,4 +21,28 @@
 PrintViewManagerBasic::~PrintViewManagerBasic() {
 }
 
+#if defined(OS_ANDROID)
+void PrintViewManagerBasic::RenderProcessGone(base::TerminationStatus status) {
+  PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false);
+  file_descriptor_ = base::FileDescriptor(-1, false);
+  PrintViewManagerBase::RenderProcessGone(status);
+}
+
+void PrintViewManagerBasic::OnPrintingFailed(int cookie) {
+  PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false);
+  file_descriptor_ = base::FileDescriptor(-1, false);
+  PrintViewManagerBase::OnPrintingFailed(cookie);
+}
+
+bool PrintViewManagerBasic::OnMessageReceived(const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBasic, message)
+    IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+
+  return handled ? true : PrintViewManagerBase::OnMessageReceived(message);
+}
+#endif
+
 }  // namespace printing
diff --git a/chrome/browser/printing/print_view_manager_basic.h b/chrome/browser/printing/print_view_manager_basic.h
index be1bc66..0e40384 100644
--- a/chrome/browser/printing/print_view_manager_basic.h
+++ b/chrome/browser/printing/print_view_manager_basic.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,6 +8,10 @@
 #include "chrome/browser/printing/print_view_manager_base.h"
 #include "content/public/browser/web_contents_user_data.h"
 
+#if defined(OS_ANDROID)
+#include "base/file_descriptor_posix.h"
+#endif
+
 namespace printing {
 
 // Manages the print commands for a WebContents - basic version.
@@ -17,10 +21,34 @@
  public:
   virtual ~PrintViewManagerBasic();
 
+#if defined(OS_ANDROID)
+  // Sets the file descriptor into which the PDF will be written.
+  void set_file_descriptor(const base::FileDescriptor& file_descriptor) {
+    file_descriptor_ = file_descriptor;
+  }
+
+  // Gets the file descriptor into which the PDF will be written.
+  base::FileDescriptor file_descriptor() const { return file_descriptor_; }
+
+  // content::WebContentsObserver implementation.
+  // Terminates or cancels the print job if one was pending.
+  virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
+
+  // content::WebContentsObserver implementation.
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+#endif
+
  private:
   explicit PrintViewManagerBasic(content::WebContents* web_contents);
   friend class content::WebContentsUserData<PrintViewManagerBasic>;
 
+#if defined(OS_ANDROID)
+  virtual void OnPrintingFailed(int cookie) OVERRIDE;
+
+  // The file descriptor into which the PDF of the page will be written.
+  base::FileDescriptor file_descriptor_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBasic);
 };
 
diff --git a/chrome/browser/printing/printing_message_filter.cc b/chrome/browser/printing/printing_message_filter.cc
index 35b4074..7c66ae8 100644
--- a/chrome/browser/printing/printing_message_filter.cc
+++ b/chrome/browser/printing/printing_message_filter.cc
@@ -32,6 +32,12 @@
 #include "chrome/browser/printing/print_dialog_cloud.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/printing/print_view_manager_basic.h"
+#include "printing/printing_context_android.h"
+#endif
+
 using content::BrowserThread;
 
 namespace {
@@ -100,6 +106,11 @@
       message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
     *thread = BrowserThread::FILE;
   }
+#elif defined(OS_ANDROID)
+  if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
+      message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
+    *thread = BrowserThread::UI;
+  }
 #endif
 }
 
@@ -110,7 +121,7 @@
 #if defined(OS_WIN)
     IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection)
 #endif
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting,
                         OnAllocateTempFileForPrinting)
     IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten,
@@ -141,9 +152,13 @@
 }
 #endif
 
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 void PrintingMessageFilter::OnAllocateTempFileForPrinting(
-    base::FileDescriptor* temp_file_fd, int* sequence_number) {
+    int render_view_id,
+    base::FileDescriptor* temp_file_fd,
+    int* sequence_number) {
+#if defined(OS_CHROMEOS)
+  // TODO(thestig): Use |render_view_id| for Chrome OS.
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   temp_file_fd->fd = *sequence_number = -1;
   temp_file_fd->auto_close = false;
@@ -166,10 +181,23 @@
       }
     }
   }
+#elif defined(OS_ANDROID)
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
+  printing::PrintViewManagerBasic* print_view_manager =
+      printing::PrintViewManagerBasic::FromWebContents(wc);
+  // The file descriptor is originally created in & passed from the Android
+  // side, and it will handle the closing.
+  const base::FileDescriptor& file_descriptor =
+      print_view_manager->file_descriptor();
+  temp_file_fd->fd = file_descriptor.fd;
+  temp_file_fd->auto_close = false;
+#endif
 }
 
 void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id,
                                                          int sequence_number) {
+#if defined(OS_CHROMEOS)
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
   SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
   SequenceToPathMap::iterator it = map->find(sequence_number);
@@ -185,8 +213,21 @@
 
   // Erase the entry in the map.
   map->erase(it);
+#elif defined(OS_ANDROID)
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
+  printing::PrintViewManagerBasic* print_view_manager =
+      printing::PrintViewManagerBasic::FromWebContents(wc);
+  const base::FileDescriptor& file_descriptor =
+      print_view_manager->file_descriptor();
+  printing::PrintingContextAndroid::PdfWritingDone(file_descriptor.fd, true);
+  // Invalidate the file descriptor so it doesn't accidentally get reused.
+  print_view_manager->set_file_descriptor(base::FileDescriptor(-1, false));
+#endif
 }
+#endif  // defined(OS_CHROMEOS) || defined(OS_ANDROID)
 
+#if defined(OS_CHROMEOS)
 void PrintingMessageFilter::CreatePrintDialogForFile(
     int render_view_id,
     const base::FilePath& path) {
@@ -320,6 +361,11 @@
     scoped_refptr<printing::PrinterQuery> printer_query,
     IPC::Message* reply_msg) {
   PrintMsg_PrintPages_Params params;
+#if defined(OS_ANDROID)
+  // We need to save the routing ID here because Send method below deletes the
+  // |reply_msg| before we can get the routing ID for the Android code.
+  int routing_id = reply_msg->routing_id();
+#endif
   if (printer_query->last_status() != printing::PrintingContext::OK ||
       !printer_query->settings().dpi()) {
     params.Reset();
@@ -332,12 +378,32 @@
   PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
   Send(reply_msg);
   if (params.params.dpi && params.params.document_cookie) {
+#if defined(OS_ANDROID)
+    int file_descriptor;
+    const string16& device_name = printer_query->settings().device_name();
+    if (base::StringToInt(device_name, &file_descriptor)) {
+      BrowserThread::PostTask(
+          BrowserThread::UI, FROM_HERE,
+          base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this,
+                     routing_id, file_descriptor));
+    }
+#endif
     print_job_manager_->QueuePrinterQuery(printer_query.get());
   } else {
     printer_query->StopWorker();
   }
 }
 
+#if defined(OS_ANDROID)
+void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
+  printing::PrintViewManagerBasic* print_view_manager =
+      printing::PrintViewManagerBasic::FromWebContents(wc);
+  print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false));
+}
+#endif
+
 void PrintingMessageFilter::OnUpdatePrintSettings(
     int document_cookie, const DictionaryValue& job_settings,
     IPC::Message* reply_msg) {
diff --git a/chrome/browser/printing/printing_message_filter.h b/chrome/browser/printing/printing_message_filter.h
index 1e51258..38bad94 100644
--- a/chrome/browser/printing/printing_message_filter.h
+++ b/chrome/browser/printing/printing_message_filter.h
@@ -54,15 +54,25 @@
                           base::SharedMemoryHandle* browser_handle);
 #endif
 
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
   // Used to ask the browser allocate a temporary file for the renderer
   // to fill in resulting PDF in renderer.
-  void OnAllocateTempFileForPrinting(base::FileDescriptor* temp_file_fd,
+  void OnAllocateTempFileForPrinting(int render_view_id,
+                                     base::FileDescriptor* temp_file_fd,
                                      int* sequence_number);
   void OnTempFileForPrintingWritten(int render_view_id, int sequence_number);
+#endif
+
+#if defined(OS_CHROMEOS)
   void CreatePrintDialogForFile(int render_view_id, const base::FilePath& path);
 #endif
 
+#if defined(OS_ANDROID)
+  // Updates the file descriptor for the PrintViewManagerBasic of a given
+  // render_view_id.
+  void UpdateFileDescriptor(int render_view_id, int fd);
+#endif
+
   // Given a render_view_id get the corresponding WebContents.
   // Must be called on the UI thread.
   content::WebContents* GetWebContentsForRenderView(int render_view_id);
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index 62cd06b..34b6110 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -22,11 +22,11 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest_constants.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 
@@ -232,16 +232,16 @@
                                          extensions::Manifest::Type type,
                                          bool installed_by_default) {
   DictionaryValue manifest;
-  manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
-  manifest.SetString(extension_manifest_keys::kName, name);
+  manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
+  manifest.SetString(extensions::manifest_keys::kName, name);
   switch (type) {
     case extensions::Manifest::TYPE_THEME:
-      manifest.Set(extension_manifest_keys::kTheme, new DictionaryValue);
+      manifest.Set(extensions::manifest_keys::kTheme, new DictionaryValue);
       break;
     case extensions::Manifest::TYPE_HOSTED_APP:
-      manifest.SetString(extension_manifest_keys::kLaunchWebURL,
+      manifest.SetString(extensions::manifest_keys::kLaunchWebURL,
                          "http://www.google.com");
-      manifest.SetString(extension_manifest_keys::kUpdateURL,
+      manifest.SetString(extensions::manifest_keys::kUpdateURL,
                          "http://clients2.google.com/service/update2/crx");
       break;
     case extensions::Manifest::TYPE_EXTENSION:
@@ -250,7 +250,7 @@
     default:
       NOTREACHED();
   }
-  manifest.SetString(extension_manifest_keys::kOmniboxKeyword, name);
+  manifest.SetString(extensions::manifest_keys::kOmniboxKeyword, name);
   std::string error;
   scoped_refptr<Extension> extension = Extension::Create(
       path,
@@ -446,6 +446,8 @@
 }
 
 TEST_F(ProfileResetterTest, ResetExtensionsByDisabling) {
+  service_->Init();
+
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
index 0542727..d108b00 100644
--- a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
+++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
@@ -154,11 +154,11 @@
   feedback_data->set_category_tag(kProfileResetFeedbackBucket);
   feedback_data->set_description(report);
 
-  feedback_data->set_image(ScreenshotDataPtr());
+  feedback_data->set_image(scoped_ptr<std::string>(new std::string));
   feedback_data->set_profile(profile);
 
   feedback_data->set_page_url("");
   feedback_data->set_user_email("");
 
-  FeedbackUtil::SendReport(feedback_data);
+  feedback_util::SendReport(feedback_data);
 }
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 af227d1..b72421d 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -44,8 +44,10 @@
 #include "chrome/browser/extensions/api/processes/processes_api.h"
 #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/session_restore/session_restore_api.h"
+#include "chrome/browser/extensions/api/sessions/sessions_api.h"
 #include "chrome/browser/extensions/api/socket/socket.h"
+#include "chrome/browser/extensions/api/socket/udp_socket.h"
+#include "chrome/browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h"
 #include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
 #include "chrome/browser/extensions/api/system_info/system_info_api.h"
 #include "chrome/browser/extensions/api/tab_capture/tab_capture_registry_factory.h"
@@ -140,6 +142,10 @@
 #include "chrome/browser/spellchecker/spellcheck_factory.h"
 #endif
 
+#if defined(ENABLE_MDNS)
+#include "chrome/browser/local_discovery/privet_notifications_factory.h"
+#endif
+
 namespace chrome {
 
 void AddProfilesExtraParts(ChromeBrowserMainParts* main_parts) {
@@ -197,11 +203,14 @@
   extensions::ActivityLogFactory::GetInstance();
   extensions::ActivityLogAPI::GetFactoryInstance();
   extensions::AlarmManager::GetFactoryInstance();
+  extensions::ApiResourceManager<extensions::ResumableUDPSocket>::
+      GetFactoryInstance();
   extensions::ApiResourceManager<extensions::SerialConnection>::
       GetFactoryInstance();
   extensions::ApiResourceManager<extensions::Socket>::GetFactoryInstance();
   extensions::ApiResourceManager<extensions::UsbDeviceResource>::
       GetFactoryInstance();
+  extensions::api::UDPSocketEventDispatcher::GetFactoryInstance();
   extensions::AudioAPI::GetFactoryInstance();
   extensions::BookmarksAPI::GetFactoryInstance();
   extensions::BluetoothAPIFactory::GetInstance();
@@ -240,7 +249,7 @@
   extensions::PreferenceAPI::GetFactoryInstance();
   extensions::ProcessesAPI::GetFactoryInstance();
   extensions::PushMessagingAPI::GetFactoryInstance();
-  extensions::SessionRestoreAPI::GetFactoryInstance();
+  extensions::SessionsAPI::GetFactoryInstance();
 #if defined(ENABLE_SPELLCHECK)
   extensions::SpellcheckAPI::GetFactoryInstance();
 #endif
@@ -266,6 +275,9 @@
   HistoryServiceFactory::GetInstance();
   invalidation::InvalidationServiceFactory::GetInstance();
   InstantServiceFactory::GetInstance();
+#if defined(ENABLE_MDNS)
+  local_discovery::PrivetNotificationServiceFactory::GetInstance();
+#endif
 #if defined(ENABLE_MANAGED_USERS)
   ManagedUserServiceFactory::GetInstance();
   ManagedUserSyncServiceFactory::GetInstance();
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 7f42c5d..4aacf82 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -99,7 +99,7 @@
 
 void OffTheRecordProfileImpl::Init() {
   BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
-      this, false);
+      this);
 
   DCHECK_NE(IncognitoModePrefs::DISABLED,
             IncognitoModePrefs::GetAvailability(profile_->GetPrefs()));
@@ -496,4 +496,3 @@
   return ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
       GetPrefs(), g_browser_process->local_state());
 }
-
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 630fc6e..09b6015 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl_unittest.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl_unittest.cc
@@ -151,9 +151,8 @@
       new OffTheRecordProfileImpl(parent_profile.get()));
   child_profile->InitHostZoomMap();
 
-  BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
-      child_profile.get(),
-      true); // For testing.
+  BrowserContextDependencyManager::GetInstance()->
+      CreateBrowserContextServicesForTest(child_profile.get(), false);
 
   // Prepare child host zoom map.
   HostZoomMap* child_zoom_map =
diff --git a/chrome/browser/profiles/profile_destroyer_unittest.cc b/chrome/browser/profiles/profile_destroyer_unittest.cc
index 3c04289..4976584 100644
--- a/chrome/browser/profiles/profile_destroyer_unittest.cc
+++ b/chrome/browser/profiles/profile_destroyer_unittest.cc
@@ -11,7 +11,14 @@
 
 class TestingOffTheRecordDestructionProfile : public TestingProfile {
  public:
-  TestingOffTheRecordDestructionProfile() : destroyed_otr_profile_(false) {
+  TestingOffTheRecordDestructionProfile()
+      : TestingProfile(base::FilePath(),
+                       NULL,
+                       scoped_refptr<ExtensionSpecialStoragePolicy>()
+                       scoped_ptr<PrefServiceSyncable>(),
+                       true,
+                       TestingFactories()),
+        destroyed_otr_profile_(false) {
     set_incognito(true);
   }
   virtual void DestroyOffTheRecordProfile() OVERRIDE {
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index c3650e8..1ad2bcf 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -705,9 +705,7 @@
 }
 
 bool ProfileImpl::IsManaged() {
-  // TODO(ibraaaa): migrate away from |prefs::kProfileIsManaged|.
-  return GetPrefs()->GetBoolean(prefs::kProfileIsManaged) ||
-      !GetPrefs()->GetString(prefs::kManagedUserId).empty();
+  return !GetPrefs()->GetString(prefs::kManagedUserId).empty();
 }
 
 ExtensionService* ProfileImpl::GetExtensionService() {
@@ -757,7 +755,7 @@
   prefs_->SetBoolean(prefs::kSessionExitedCleanly, true);
 
   BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
-      this, false);
+      this);
 
   DCHECK(!net_pref_observer_);
   {
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index bbe1142..4026f4b 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -605,15 +605,17 @@
 ProfileImplIOData::InitializeMediaRequestContext(
     ChromeURLRequestContext* original_context,
     const StoragePartitionDescriptor& partition_descriptor) const {
-  // If this is for a in_memory partition, we can simply use the original
-  // context (like off-the-record mode).
-  if (partition_descriptor.in_memory)
-    return original_context;
-
   // Copy most state from the original context.
   MediaRequestContext* context = new MediaRequestContext(load_time_stats());
   context->CopyFrom(original_context);
 
+  // For in-memory context, return immediately after creating the new
+  // context before attaching a separate cache. It is important to return
+  // a new context rather than just reusing |original_context| because
+  // the caller expects to take ownership of the pointer.
+  if (partition_descriptor.in_memory)
+    return context;
+
   using content::StoragePartition;
   base::FilePath cache_path;
   int cache_max_size = app_media_cache_max_size_;
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index c662a0c..75b6ab2 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -184,13 +184,12 @@
     string16 name;
     info->GetString(kNameKey, &name);
     sorted_keys_.insert(FindPositionForProfile(it.key(), name), it.key());
-    // TODO(ibraaaa): delete this when we fully migrate to
-    // |prefs::kManagedUserId|.
+    // TODO(ibraaaa): delete this when 97% of our users are using M31.
+    // http://crbug.com/276163
     bool is_managed = false;
-    info->GetBoolean(kIsManagedKey, &is_managed);
-    if (is_managed) {
-      info->SetString(kManagedUserId, "DUMMY_ID");
+    if (info->GetBoolean(kIsManagedKey, &is_managed)) {
       info->Remove(kIsManagedKey, NULL);
+      info->SetString(kManagedUserId, is_managed ? "DUMMY_ID" : std::string());
     }
   }
 }
@@ -441,11 +440,10 @@
   std::string icon_url;
   GetInfoForProfileAtIndex(index)->GetString(kAvatarIconKey, &icon_url);
   size_t icon_index = 0;
-  if (IsDefaultAvatarIconUrl(icon_url, &icon_index))
-    return icon_index;
+  if (!IsDefaultAvatarIconUrl(icon_url, &icon_index))
+    DLOG(WARNING) << "Unknown avatar icon: " << icon_url;
 
-  DLOG(WARNING) << "Unknown avatar icon: " << icon_url;
-  return GetDefaultAvatarIconResourceIDAtIndex(0);
+  return icon_index;
 }
 
 void ProfileInfoCache::SetNameOfProfileAtIndex(size_t index,
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 0776e53..660a0b3 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.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/threading/sequenced_worker_pool.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/content_settings_provider.h"
@@ -209,7 +210,11 @@
       net::NetworkDelegate* network_delegate) const OVERRIDE {
     base::FilePath path;
     if (IsSupportedDevToolsURL(request->url(), &path))
-      return new net::URLRequestFileJob(request, network_delegate, path);
+      return new net::URLRequestFileJob(
+          request, network_delegate, path,
+          content::BrowserThread::GetBlockingPool()->
+              GetTaskRunnerWithShutdownBehavior(
+                  base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
 
     return NULL;
   }
@@ -835,7 +840,11 @@
   // NOTE(willchan): Keep these protocol handlers in sync with
   // ProfileIOData::IsHandledProtocol().
   bool set_protocol = job_factory->SetProtocolHandler(
-      chrome::kFileScheme, new net::FileProtocolHandler());
+      chrome::kFileScheme,
+      new net::FileProtocolHandler(
+          content::BrowserThread::GetBlockingPool()->
+              GetTaskRunnerWithShutdownBehavior(
+                  base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
   DCHECK(set_protocol);
 
   DCHECK(extension_info_map_.get());
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 05aca49..ec088d2 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -934,7 +934,6 @@
   if (profile->GetPath().DirName() != cache.GetUserDataDir())
     return;
 
-  bool is_managed = false;
   size_t avatar_index;
   std::string profile_name;
   std::string managed_user_id;
@@ -950,7 +949,6 @@
           cache.GetAvatarIconIndexOfProfileAtIndex(profile_cache_index);
       profile_name =
           UTF16ToUTF8(cache.GetNameOfProfileAtIndex(profile_cache_index));
-      is_managed = cache.ProfileIsManagedAtIndex(profile_cache_index);
       managed_user_id =
           cache.GetManagedUserIdOfProfileAtIndex(profile_cache_index);
     } else if (profile->GetPath() ==
@@ -969,9 +967,6 @@
   if (!profile->GetPrefs()->HasPrefPath(prefs::kProfileName))
     profile->GetPrefs()->SetString(prefs::kProfileName, profile_name);
 
-  if (!profile->GetPrefs()->HasPrefPath(prefs::kProfileIsManaged))
-    profile->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, is_managed);
-
   if (!profile->GetPrefs()->HasPrefPath(prefs::kManagedUserId))
     profile->GetPrefs()->SetString(prefs::kManagedUserId, managed_user_id);
 }
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index dd2417b..1181443 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -54,13 +54,9 @@
 // observers is the same.
 Profile* g_created_profile;
 
-}  // namespace
-
-namespace testing {
-
-class ProfileManager : public ::ProfileManagerWithoutInit {
+class UnittestProfileManager : public ::ProfileManagerWithoutInit {
  public:
-  explicit ProfileManager(const base::FilePath& user_data_dir)
+  explicit UnittestProfileManager(const base::FilePath& user_data_dir)
       : ::ProfileManagerWithoutInit(user_data_dir) {}
 
  protected:
@@ -84,7 +80,7 @@
   }
 };
 
-}  // namespace testing
+}  // namespace
 
 class ProfileManagerTest : public testing::Test {
  protected:
@@ -102,7 +98,7 @@
     // Create a new temporary directory, and store the path
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     TestingBrowserProcess::GetGlobal()->SetProfileManager(
-        new testing::ProfileManager(temp_dir_.path()));
+        new UnittestProfileManager(temp_dir_.path()));
 
 #if defined(OS_CHROMEOS)
   CommandLine* cl = CommandLine::ForCurrentProcess();
@@ -417,11 +413,12 @@
 
   // Attach an incognito Profile to the TestingProfile.
   ASSERT_FALSE(profile->GetOffTheRecordProfile());
-  TestingProfile* incognito_profile = new TestingProfile();
-  incognito_profile->set_incognito(true);
+  TestingProfile::Builder builder;
+  builder.SetIncognito();
+  scoped_ptr<TestingProfile> incognito_profile = builder.Build();
   EXPECT_TRUE(incognito_profile->IsOffTheRecord());
   TestingProfile* testing_profile = static_cast<TestingProfile*>(profile);
-  testing_profile->SetOffTheRecordProfile(incognito_profile);
+  testing_profile->SetOffTheRecordProfile(incognito_profile.PassAs<Profile>());
   ASSERT_TRUE(profile->GetOffTheRecordProfile());
 
   IncognitoModePrefs::SetAvailability(prefs, IncognitoModePrefs::DISABLED);
@@ -569,10 +566,10 @@
 
   // incognito profiles should not be managed by the profile manager but by the
   // original profile.
-  TestingProfile* profile2 = new TestingProfile();
-  ASSERT_TRUE(profile2);
-  profile2->set_incognito(true);
-  profile1->SetOffTheRecordProfile(profile2);
+  TestingProfile::Builder builder;
+  builder.SetIncognito();
+  scoped_ptr<TestingProfile> profile2 = builder.Build();
+  profile1->SetOffTheRecordProfile(profile2.PassAs<Profile>());
 
   std::vector<Profile*> last_opened_profiles =
       profile_manager->GetLastOpenedProfiles();
@@ -588,7 +585,8 @@
   EXPECT_EQ(profile1, last_opened_profiles[0]);
 
   // And for profile2.
-  Browser::CreateParams profile2_params(profile2, chrome::GetActiveDesktop());
+  Browser::CreateParams profile2_params(profile1->GetOffTheRecordProfile(),
+                                        chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser2a(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
diff --git a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
index 7dea610..13e837d 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
@@ -223,7 +223,9 @@
         ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS)) << location.ToString();
     const base::FilePath system_level_shortcut_path =
         GetSystemShortcutsDirectory().Append(
-            distribution->GetAppShortCutName() + installer::kLnkExt);
+            distribution->
+                GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+                installer::kLnkExt);
     EXPECT_TRUE(base::PathExists(system_level_shortcut_path))
         << location.ToString();
     return system_level_shortcut_path;
@@ -311,7 +313,8 @@
   const string16 kSanitizedProfileName = L"Harry";
   BrowserDistribution* distribution = GetDistribution();
   const string16 expected_name = kSanitizedProfileName + L" - " +
-      distribution->GetAppShortCutName() + installer::kLnkExt;
+      distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+          installer::kLnkExt;
   EXPECT_EQ(expected_name,
             profiles::internal::GetShortcutFilenameForProfile(kProfileName,
                                                               distribution));
@@ -319,9 +322,11 @@
 
 TEST_F(ProfileShortcutManagerTest, UnbadgedShortcutFilename) {
   BrowserDistribution* distribution = GetDistribution();
-  EXPECT_EQ(distribution->GetAppShortCutName() + installer::kLnkExt,
-            profiles::internal::GetShortcutFilenameForProfile(string16(),
-                                                              distribution));
+  EXPECT_EQ(
+      distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+          installer::kLnkExt,
+      profiles::internal::GetShortcutFilenameForProfile(string16(),
+                                                        distribution));
 }
 
 TEST_F(ProfileShortcutManagerTest, ShortcutFlags) {
@@ -579,7 +584,8 @@
                                 false));
   const base::FilePath regular_shortcut_path =
       CreateRegularShortcutWithName(FROM_HERE,
-                                    GetDistribution()->GetAppShortCutName());
+                                    GetDistribution()->GetShortcutName(
+                                        BrowserDistribution::SHORTCUT_CHROME));
 
   // Add another profile and check that the shortcut was replaced with
   // a badged shortcut with the right command line for the profile
@@ -597,7 +603,8 @@
                                 false));
   const base::FilePath regular_shortcut_path =
       CreateRegularShortcutWithName(FROM_HERE,
-                                    GetDistribution()->GetAppShortCutName());
+                                    GetDistribution()->GetShortcutName(
+                                        BrowserDistribution::SHORTCUT_CHROME));
   const base::FilePath customized_regular_shortcut_path =
       CreateRegularShortcutWithName(FROM_HERE, L"MyChrome");
 
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
index 48e862b..4b65d8c 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -629,7 +629,8 @@
     shortcut_name.append(L" - ");
     shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
   } else {
-    shortcut_name.append(distribution->GetAppShortCutName());
+    shortcut_name.append(
+        distribution->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME));
   }
   return shortcut_name + installer::kLnkExt;
 }
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index 426907b..d33d618 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -41,7 +41,6 @@
 
 using content::BrowserThread;
 using extensions::APIPermission;
-using extensions::api::activity_log_private::BlockedChromeActivityDetail;
 using WebKit::WebCache;
 
 namespace {
@@ -132,8 +131,6 @@
                         OnAddAPIActionToExtensionActivityLog);
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddDOMActionToActivityLog,
                         OnAddDOMActionToExtensionActivityLog);
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddBlockedCallToActivityLog,
-                        OnAddBlockedCallToExtensionActivityLog);
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddEventToActivityLog,
                         OnAddEventToExtensionActivityLog);
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowDatabase, OnAllowDatabase)
@@ -547,19 +544,6 @@
   AddActionToExtensionActivityLog(profile_, action);
 }
 
-void ChromeRenderMessageFilter::OnAddBlockedCallToExtensionActivityLog(
-    const std::string& extension_id,
-    const std::string& function_name) {
-  scoped_refptr<extensions::Action> action = new extensions::Action(
-      extension_id, base::Time::Now(), extensions::Action::ACTION_API_BLOCKED,
-      function_name);
-  action->mutable_other()->SetString(
-      activity_log_constants::kActionBlockedReason,
-      BlockedChromeActivityDetail::ToString(
-          BlockedChromeActivityDetail::REASON_ACCESS_DENIED));
-  AddActionToExtensionActivityLog(profile_, action);
-}
-
 void ChromeRenderMessageFilter::OnAllowDatabase(int render_view_id,
                                                 const GURL& origin_url,
                                                 const GURL& top_origin_url,
diff --git a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
index d1f29e4..e5e96e5 100644
--- a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
+++ b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
@@ -9,7 +9,6 @@
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.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/net/predictor.h"
@@ -21,11 +20,9 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/notification_service.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -33,6 +30,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/page_transition_types.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/manifest.h"
 #include "net/http/http_request_headers.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/window_open_disposition.h"
@@ -187,19 +185,13 @@
 }
 
 void ChromeRenderViewHostObserver::OnFocusedNodeTouched(bool editable) {
+#if defined(OS_WIN) && defined(USE_AURA)
   if (editable) {
-#if defined(OS_WIN) && defined(USE_AURA)
     base::win::DisplayVirtualKeyboard();
-#endif
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_FOCUSED_NODE_TOUCHED,
-        content::Source<RenderViewHost>(render_view_host()),
-        content::Details<bool>(&editable));
   } else {
-#if defined(OS_WIN) && defined(USE_AURA)
     base::win::DismissVirtualKeyboard();
-#endif
   }
+#endif  // OS_WIN && USE_AURA
 }
 
 // Handles the image thumbnail for the context node, composes a image search
diff --git a/chrome/browser/renderer_host/pepper/OWNERS b/chrome/browser/renderer_host/pepper/OWNERS
index dc19a03..33d4c55 100644
--- a/chrome/browser/renderer_host/pepper/OWNERS
+++ b/chrome/browser/renderer_host/pepper/OWNERS
@@ -1,3 +1,4 @@
+bbudge@chromium.org
 dmichael@chromium.org
 raymes@chromium.org
 yzshen@chromium.org
diff --git a/chrome/browser/resources/apps_debugger/css/items.css b/chrome/browser/resources/apps_debugger/css/items.css
index 7e76b43..4f7f6d1 100644
--- a/chrome/browser/resources/apps_debugger/css/items.css
+++ b/chrome/browser/resources/apps_debugger/css/items.css
@@ -5,22 +5,12 @@
 body,
 html {
   color: rgb(48, 57, 66);
-  font-family: Ubuntu, Arial, sans-serif;
+  font-family: 'Helvetica Neue', Ubuntu, Arial, sans-serif;
   height: 100%;
   overflow: hidden;
   width: 100%;
 }
 
-body {
-  font-size: 75%;
-}
-
-#container {
-  height: 100%;
-  overflow-y: scroll;
-  width: 100%;
-}
-
 hr {
   color: rgb(115, 111, 110);
   margin: 15px 0;
@@ -29,68 +19,68 @@
 /* Override the visual style of tabs. */
 
 #tabs-header-container {
-  border-bottom: 1px solid #e0e0e0;
-  height: calc(100% - 53px);
-  margin-top: 10px;
-}
-
-#tabs {
-  border-bottom: none;
-  left: -5px;
-  margin: 5px auto 0;
-  padding: 0 5px;
+  margin: 0 auto;
   position: relative;
   width: 720px;
 }
 
+#tabs {
+  border-bottom: none;
+  padding: 0;
+  position: relative;
+}
+
 tabs tab {
-  border-color: #e0e0e0;
+  -webkit-margin-end: 20px;
+  background: white;
+  border: none;
+  color: #7f7f7f;
+  font-size: 13px;
+  font-weight: bold;
+  height: 14px;
+  margin: 0;
   min-width: 100px;
-  padding: 7px 20px;
+  padding: 20px 0;
 }
 
 tabs > [selected] {
   background: white;
-  border-color: #e0e0e0;
+  border-bottom: 4px solid #7f7f7f;
+  color: #333;
 }
 
-html.focus-outline-visible tabs:focus > [selected] {
+html.focus-outline-visible :focus > tab[selected] {
   background: white;
   border-color: rgb(160, 160, 255);
   outline: none;
 }
 
 tabs > :not([selected]) {
-  background: rgba(0, 0, 0, 0.02);
-  border-color: #e0e0e0;
+  background: white;
 }
 
 tabs > :not([selected]):hover {
-  background: rgba(255, 255, 255, 0.9);
+  background: white;
+  border-bottom: 4px solid #eee;
 }
 
 tabpanels {
-  height: calc(100% - 20px);
+  height: calc(100% - 60px);
   padding: 0;
   width: 100%;
 }
 
 tabpanel {
-  margin: 0 auto;
-  padding-top: 24px;
-  width: 710px;
+  width: 100%;
 }
 
 /* Header */
 
 #header {
-  background-image: -webkit-linear-gradient(white,
-                                            white 40%,
-                                            rgba(255, 255, 255, 0.92));
-  position: fixed;
-  top: 0;
+  border-bottom: 1px solid #d1d1d1;
+  border-top: 1px solid #d1d1d1;
+  height: 58px;
   width: 100%;
-  z-index: 1;
 }
 
 #developer-controls {
@@ -108,35 +98,64 @@
   top: 3px;
 }
 
-#header-bottom-gradient {
-  background: linear-gradient(to bottom, white, rgba(255, 255, 255, 0));
-  height: 20px;
-  position: fixed;
-  top: 42px;
-  width: 100%;
-}
-
 #search {
-  padding: 4px;
+  -webkit-padding-end: 5px;
+  -webkit-padding-start: 34px;
+  background-image: -webkit-image-set(
+      url(../images/search.png) 1x,
+      url(../images/2x/search.png) 2x);
+  background-position: 0 8px;
+  background-repeat: no-repeat;
+  border: none;
+  font-size: 13px;
+  height: 18px;
   position: absolute;
-  right: 15px;
-  text-align: left;
-  width: 200px;
+  right: 16px;
+  top: 15px;
+  width: 220px;
 }
 
 html[dir='rtl'] #search {
-  left: 15px;
+  background-position-x: calc(100% - 16px);
+  left: 16px;
   right: auto;
 }
 
+#search::-webkit-search-cancel-button {
+  -webkit-appearance: none;
+  background-image: -webkit-image-set(
+      url(../images/search_clear.png) 1x,
+      url(../images/2x/search_clear.png) 2x);
+  background-repeat: no-repeat;
+  height: 16px;
+  width: 16px;
+}
+
+#search::-webkit-search-cancel-button:hover {
+  background-image: -webkit-image-set(
+      url(../images/search_clear_hover.png) 1x,
+      url(../images/2x/search_clear_hover.png) 2x);
+}
+
+#search::-webkit-search-cancel-button:active {
+  background-image: -webkit-image-set(
+      url(../images/search_clear_active.png) 1x,
+      url(../images/2x/search_clear_active.png) 2x);
+}
+
 /* Contents */
 
 #extension-settings {
+  height: 100%;
   margin: 0;
   max-width: 100%;
   padding: 0 0 10px;
 }
 
+#tab-box {
+  height: 100%;
+}
+
 #no-extensions-message,
 #no-apps-message {
   font-weight: bold;
@@ -162,6 +181,14 @@
   display: inline;
 }
 
+#no-packed-extensions,
+#no-unpacked-extensions,
+#no-packed-apps,
+#no-unpacked-apps {
+  color: #aaa;
+  margin-top: 10px;
+}
+
 .packed-list:not(.empty-item-list) #no-packed-extensions,
 .unpacked-list:not(.empty-item-list) #no-unpacked-extensions,
 .packed-list:not(.empty-item-list) #no-packed-apps,
@@ -174,7 +201,7 @@
 }
 
 .empty-item-list {
-  height: 6em;
+  height: 8em;
 }
 
 #no-extensions,
@@ -182,9 +209,17 @@
   margin: 10px;
 }
 
+#apps-tab,
+#extensions-tab {
+  height: 100%;
+  overflow-y: scroll;
+  width: 720px;
+}
+
 .packed-list,
 .unpacked-list {
-  margin-top: 30px;
+  margin: 0 auto;
+  width: 720px;
 }
 
 .loading #no-extensions,
@@ -195,19 +230,24 @@
 }
 
 .list-header {
-  border-bottom: 1px solid #e0e0e0;
+  border-bottom: 1px solid #d1d1d1;
+  font-size: 13px;
   font-weight: bold;
-  margin-bottom: 15px;
   padding-bottom: 15px;
+  padding-top: 20px;
 }
 
 .list-header .title {
   display: inline-block;
-  margin-top: 5px;
+  margin-top: 6px;
+}
+
+.items {
+  margin-top: 15px;
 }
 
 .extension-list-item-wrapper {
-  padding: 0 0 25px;
+  margin: 0 0 25px;
 }
 
 .extension-list-item-wrapper.highlighted {
@@ -217,22 +257,21 @@
 
 .extension-list-item {
   /* Set in ItemsList.createNode_(). */
+  background-position: 26px 0;
   background-repeat: no-repeat;
   display: -webkit-box;
   min-height: 48px;
 }
 
 html[dir='rtl'] .extension-list-item {
-  background-position: right;
+  background-position: calc(100% - 26px) 0;
 }
 
 .extension-title {
-  -webkit-padding-end: 20px;
   -webkit-user-select: text;
   color: rgb(48, 57, 66);
-  font-size: 14px;
+  font-size: 13px;
   font-weight: 500;
-  margin-bottom: 5px;
   text-decoration: none;
 }
 
@@ -251,22 +290,26 @@
 .extension-version {
   -webkit-padding-end: 7px;
   -webkit-user-select: text;
-  font-size: 13px;
+  font-size: 12px;
   font-weight: 400;
 }
 
+.extension-disabled {
+  font-size: 12px;
+}
+
 .extension-description {
   -webkit-padding-end: 5px;
   -webkit-user-select: text;
   font-size: 13px;
-  margin: 5px 0;
+  margin: 1px 0;
   white-space: normal;
 }
 
 .extension-details {
   -webkit-box-flex: 1;
-  -webkit-margin-start: 8px;
-  -webkit-padding-start: 55px;
+  -webkit-padding-start: 100px;
+  font-size: 12px;
   margin-top: 15px;
   max-width: 600px;
 }
@@ -299,23 +342,26 @@
   display: inline-block;
 }
 
-.file-access-control,
-.incognito-control,
-.checkbox label {
-  margin: 5px 0;
-  padding: 0;
-}
-
-.enabled-text {
-  font-weight: bold;
-}
-
 .extension-list-item-wrapper.inactive-extension .enabled-text,
 .extension-list-item-wrapper:not(.inactive-extension) .enable-text,
 .extension-list-item-wrapper.inactive-extension .optional-controls {
   display: none;
 }
 
+.controls-container {
+  margin: 10px 0;
+}
+
+.controls,
+.optional-controls {
+  display: inline-block;
+}
+
+.active-views {
+  margin-bottom: 14px;
+  margin-top: 10px;
+}
+
 .load-path > span {
   word-wrap: break-word;
 }
@@ -350,7 +396,11 @@
   margin-bottom: 10px;
 }
 
-.extension-details-all div {
+.extension-details-all {
+  margin-top: 6px;
+}
+
+.extension-details-all div.item {
   margin: 5px 0;
 }
 
@@ -385,20 +435,6 @@
   display: none;
 }
 
-/* Trash */
-
-.enable-controls > .trash > .lid,
-.enable-controls > .trash > .can {
-  background: url(../../../../../ui/webui/resources/images/trash.png)
-      0 0 no-repeat;
-}
-
-.enable-controls > .trash > .can {
-  height: 15px;
-  top: 0;
-  width: 13px;
-}
-
 .extension-id {
   -webkit-user-select: text;
 }
@@ -431,10 +467,59 @@
 }
 
 a {
+  color: rgb(60, 128, 246);
+  text-decoration: none;
+}
+
+a:active {
   color: rgb(17, 85, 204);
   text-decoration: underline;
 }
 
-a:active {
-  color: rgb(5, 37, 119);
+a:hover {
+  text-decoration: underline;
+}
+
+.optional-controls .terminated-reload-link,
+.controls .enable-checkbox,
+.optional-controls .incognito-control,
+.optional-controls .file-access-control {
+  -webkit-margin-end: 20px;
+}
+
+button {
+  background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  border-radius: 2px;
+  color: #444;
+  font-family: 'Helvetica Neue', Ubuntu, Arial, sans-serif;
+  font-size: 12px;
+  font-weight: bold;
+  height: 29px;
+  padding: 0 15px;
+  transition: border 250ms;
+}
+
+button:hover {
+  background-image: -webkit-linear-gradient(top, #f8f8f8, #f1f1f1);
+  border-color: #dcdcdc;
+  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+}
+
+button:active {
+  background-image: -webkit-linear-gradient(top, #f6f6f6, #f1f1f1);
+  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+}
+
+button:focus {
+  outline: none;
+}
+
+button[disabled],
+button[disabled]:hover,
+button[disabled]:active {
+  background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
+  border-color: rgba(0, 0, 0, 0.1);
+  box-shadow: none;
+  color: #888;
 }
diff --git a/chrome/browser/resources/apps_debugger/images/2x/search.png b/chrome/browser/resources/apps_debugger/images/2x/search.png
new file mode 100644
index 0000000..bf26fe1
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/2x/search.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/2x/search_clear.png b/chrome/browser/resources/apps_debugger/images/2x/search_clear.png
new file mode 100644
index 0000000..28f8e0d
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/2x/search_clear.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/2x/search_clear_active.png b/chrome/browser/resources/apps_debugger/images/2x/search_clear_active.png
new file mode 100644
index 0000000..9952208
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/2x/search_clear_active.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/2x/search_clear_hover.png b/chrome/browser/resources/apps_debugger/images/2x/search_clear_hover.png
new file mode 100644
index 0000000..77ac1c0
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/2x/search_clear_hover.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/restart.png b/chrome/browser/resources/apps_debugger/images/restart.png
deleted file mode 100644
index a37c2e6..0000000
--- a/chrome/browser/resources/apps_debugger/images/restart.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/run.png b/chrome/browser/resources/apps_debugger/images/run.png
deleted file mode 100644
index 811bc92..0000000
--- a/chrome/browser/resources/apps_debugger/images/run.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/search.png b/chrome/browser/resources/apps_debugger/images/search.png
new file mode 100644
index 0000000..51cbca0
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/search.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/search_clear.png b/chrome/browser/resources/apps_debugger/images/search_clear.png
new file mode 100644
index 0000000..b22b66b
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/search_clear.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/search_clear_active.png b/chrome/browser/resources/apps_debugger/images/search_clear_active.png
new file mode 100644
index 0000000..77ffb94
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/search_clear_active.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/images/search_clear_hover.png b/chrome/browser/resources/apps_debugger/images/search_clear_hover.png
new file mode 100644
index 0000000..872ea1b
--- /dev/null
+++ b/chrome/browser/resources/apps_debugger/images/search_clear_hover.png
Binary files differ
diff --git a/chrome/browser/resources/apps_debugger/js/items.js b/chrome/browser/resources/apps_debugger/js/items.js
index aaa1ea7..8d09464 100644
--- a/chrome/browser/resources/apps_debugger/js/items.js
+++ b/chrome/browser/resources/apps_debugger/js/items.js
@@ -43,7 +43,7 @@
      * @param {!Event} e Click event.
      * @private
      */
-   handleLoadUnpackedItem_: function(e) {
+    handleLoadUnpackedItem_: function(e) {
       chrome.developerPrivate.loadUnpacked();
     },
 
diff --git a/chrome/browser/resources/apps_debugger/js/items_list.js b/chrome/browser/resources/apps_debugger/js/items_list.js
index 489fa9d..2f60b18 100644
--- a/chrome/browser/resources/apps_debugger/js/items_list.js
+++ b/chrome/browser/resources/apps_debugger/js/items_list.js
@@ -287,7 +287,7 @@
         var list = panel.querySelector('ul');
         item.install_warnings.forEach(function(warning) {
           var li = document.createElement('li');
-          li[warning.isHTML ? 'innerHTML' : 'textContent'] = warning.message;
+          li.textContent = warning.message;
           list.appendChild(li);
         });
       }
@@ -366,6 +366,17 @@
     setPackButton_: function(item, el) {
       var packButton = el.querySelector('.pack-link');
       packButton.addEventListener('click', function(e) {
+        if (item.isApp) {
+          $('pack-heading').textContent =
+              loadTimeData.getString('packAppHeading');
+          $('pack-title').textContent =
+              loadTimeData.getString('packAppOverlay');
+        } else {
+          $('pack-heading').textContent =
+              loadTimeData.getString('packExtensionHeading');
+          $('pack-title').textContent =
+              loadTimeData.getString('packExtensionOverlay');
+        }
         $('item-root-dir').value = item.path;
         AppsDevTool.showOverlay($('packItemOverlay'));
       });
@@ -489,8 +500,10 @@
       var link = activeViews.querySelector('a');
 
       item.views.forEach(function(view, i) {
-        var label = view.path +
-            (view.incognito ? ' ' + str('viewIncognito') : '') +
+        var displayName = view.generatedBackgroundPage ?
+            str('backgroundPage') : view.path;
+        var label =
+            displayName + (view.incognito ? ' ' + str('viewIncognito') : '') +
             (view.render_process_id == -1 ? ' ' + str('viewInactive') : '');
         link.textContent = label;
         link.addEventListener('click', function(e) {
diff --git a/chrome/browser/resources/apps_debugger/main.html b/chrome/browser/resources/apps_debugger/main.html
index 257375e..defc2ec 100644
--- a/chrome/browser/resources/apps_debugger/main.html
+++ b/chrome/browser/resources/apps_debugger/main.html
@@ -20,197 +20,185 @@
     <script src="js/main_scripts.js"></script>
   </head>
   <body>
-    <div id="container">
-      <div id="overlay" class="overlay" hidden>
-        <include src="pack_item_overlay.html">
-        <include src="../../../../ui/webui/resources/html/alert_overlay.html">
-      </div>
-      <div class="page" id="extension-settings">
-        <tabbox id="tab-box">
-          <div id="header">
-            <div id="tabs-header-container">
-              <tabs id="tabs" tabindex="0">
-                <tab i18n-content="appsDevtoolApps"></tab>
-                <tab i18n-content="appsDevtoolExtensions"></tab>
-                <input id="search" type="text"
-                    i18n-values=".placeholder:appsDevtoolSearch"
-                    spellcheck="false">
-              </tabs>
-            </div>
-            <div id="header-bottom-gradient"></div>
-          </div>
-          <tabpanels id="tab-panels">
-            <!-- Apps Tab -->
-            <tabpanel id="apps-tab">
-              <div class="unpacked-list">
-                <div class="list-header">
-                  <span class="title" i18n-content="appsDevtoolUnpacked"></span>
-                  <button class="load-unpacked"
-                      i18n-content="appsDevtoolLoadUnpackedButton"></button>
-                </div>
-                <div class="items"></div>
-                <div id="no-unpacked-apps">
-                  <span id="no-unpacked-apps-message"
-                      i18n-content="appsDevtoolNoUnpackedApps"></span>
-                </div>
-              </div>
-              <div class="packed-list">
-                <div class="list-header">
-                  <span class="title" i18n-content="appsDevtoolInstalled">
-                  </span>
-                  <div class="update-items-container">
-                    <button class="update-items-progress"
-                        i18n-content="appsDevtoolUpdating" disabled></span>
-                    <button class="update-items-now"
-                        i18n-content="appsDevtoolUpdateButton"></button>
-                  </div>
-                </div>
-                <div class="items"></div>
-                <div id="no-packed-apps">
-                  <span id="no-packed-apps-message"
-                      i18n-content="appsDevtoolNoPackedApps"></span>
-                </div>
-              </div>
-            </tabpanel>
-            <!-- Extensions Tab -->
-            <tabpanel id="extensions-tab">
-              <div class="unpacked-list">
-                <div class="list-header">
-                  <span class="title" i18n-content="appsDevtoolUnpacked"></span>
-                  <button class="load-unpacked"
-                      i18n-content="appsDevtoolLoadUnpackedButton"></button>
-                </div>
-                <div class="items"></div>
-                <div id="no-unpacked-extensions">
-                  <span id="no-unpacked-extensions-message"
-                      i18n-content="appsDevtoolNoUnpackedExtensions"></span>
-                </div>
-              </div>
-              <div class="packed-list">
-                <div class="list-header">
-                  <span class="title" i18n-content="appsDevtoolInstalled">
-                  </span>
-                  <div class="update-items-container">
-                    <button class="update-items-progress"
-                        i18n-content="appsDevtoolUpdating" disabled></span>
-                    <button class="update-items-now"
-                        i18n-content="appsDevtoolUpdateButton"></button>
-                  </div>
-                </div>
-                <div class="items"></div>
-                <div id="no-packed-extensions">
-                  <span id="no-packed-extensions-message"
-                      i18n-content="appsDevtoolNoPackedExtensions"></span>
-                </div>
-              </div>
-            </tabpanel>
-          </tabpanels>
-        </tabbox>
-      </div>
+    <div id="overlay" class="overlay" hidden>
+      <include src="pack_item_overlay.html">
+      <include src="../../../../ui/webui/resources/html/alert_overlay.html">
     </div>
-    <div id="template-collection" hidden>
-      <div class="extension-list-item-wrapper">
-        <div class="extension-list-item">
-          <div class="extension-details">
-            <div class="extension-details-summary">
-              <div>
-                <a class="extension-title" href="#"></a>
-                <span class="extension-disabled"
-                    i18n-content="extensionDisabled"></span>
+    <div class="page" id="extension-settings">
+      <tabbox id="tab-box">
+        <div id="header">
+          <div id="tabs-header-container">
+            <tabs id="tabs" tabindex="0">
+              <tab i18n-content="appsDevtoolApps"></tab>
+              <tab i18n-content="appsDevtoolExtensions"></tab>
+            </tabs>
+            <input id="search" type="search"
+                i18n-values=".placeholder:appsDevtoolSearch"
+                spellcheck="false">
+          </div>
+        </div>
+        <tabpanels id="tab-panels">
+          <!-- Apps Tab -->
+          <tabpanel id="apps-tab">
+            <div class="unpacked-list">
+              <div class="list-header">
+                <span class="title"
+                    i18n-content="appsDevtoolUnpacked"></span>
+                <button class="load-unpacked custom-appearance"
+                    i18n-content="appsDevtoolLoadUnpackedButton"></button>
               </div>
-              <p class="extension-description"><span></span></p>
+              <div class="items"></div>
+              <div id="no-unpacked-apps">
+                <span id="no-unpacked-apps-message"
+                    i18n-content="appsDevtoolNoUnpackedApps"></span>
+              </div>
             </div>
-            <div class="extension-details-all">
-              <div>
-                <div>
-                  <span i18n-content="extensionSettingsVersion"></span>
-                  <span class="extension-version"></span>
-                </div>
-                <div class="item-id">
-                  <span i18n-content="extensionSettingsExtensionId"></span>
-                  <span class="extension-id"></span>
-                </div>
-                <div class="load-path" hidden>
-                  <span i18n-content="extensionSettingsExtensionPath"></span>
-                  <span></span>
+            <div class="packed-list">
+              <div class="list-header">
+                <span class="title" i18n-content="appsDevtoolInstalled">
+                </span>
+                <div class="update-items-container">
+                  <button class="update-items-progress custom-appearance"
+                      i18n-content="appsDevtoolUpdating" disabled></span>
+                  <button class="update-items-now custom-appearance"
+                      i18n-content="appsDevtoolUpdateButton"></button>
                 </div>
               </div>
-              <div>
-                <span class="extension-disable-reason"></span>
+              <div class="items"></div>
+              <div id="no-packed-apps">
+                <span id="no-packed-apps-message"
+                    i18n-content="appsDevtoolNoPackedApps"></span>
               </div>
-              <div class="managed-message"
-                  i18n-content="extensionSettingsPolicyControlled" hidden>
+            </div>
+          </tabpanel>
+          <!-- Extensions Tab -->
+          <tabpanel id="extensions-tab">
+            <div class="unpacked-list">
+              <div class="list-header">
+                <span class="title" i18n-content="appsDevtoolUnpacked"></span>
+                <button class="load-unpacked custom-appearance"
+                    i18n-content="appsDevtoolLoadUnpackedButton"></button>
               </div>
-              <div class="extension-warnings" hidden>
-                <span i18n-content="extensionSettingsWarningsTitle"></span>
+              <div class="items"></div>
+              <div id="no-unpacked-extensions">
+                <span id="no-unpacked-extensions-message"
+                    i18n-content="appsDevtoolNoUnpackedExtensions"></span>
               </div>
-              <div class="install-warnings" hidden>
-                <span i18n-content="extensionSettingsInstallWarnings"></span>
-                <ul></ul>
-              </div>
-              <div>
-                <div class="optional-controls">
-                  <button class="show-button"
-                      i18n-content="extensionSettingsShowButton" hidden>
-                  </button>
-                  <span class="optional-control-disableable">
-                    <label class="incognito-control" hidden>
-                      <input type="checkbox">
-                      <span i18n-content="extensionSettingsEnableIncognito">
-                      </span>
-                    </label>
-                    <label class="file-access-control" hidden>
-                      <input type="checkbox">
-                      <span i18n-content="extensionSettingsAllowFileAccess">
-                      </span>
-                    </label>
-                  </span>
-                </div>
-                <div class="enable-controls">
-                  <a class="terminated-reload-link" href="#"
-                      i18n-content="extensionSettingsReloadTerminated" hidden>
-                  </a>
-                  <div class="checkbox enable-checkbox" hidden>
-                    <label>
-                      <input type="checkbox">
-                      <span class="enable-checkbox-text">
-                        <span class="enabled-text"
-                            i18n-content="extensionSettingsEnabled"></span>
-                        <span class="enable-text"
-                            i18n-content="extensionSettingsEnable"></span>
-                      </span>
-                    </label>
-                    <span class="location-text"></span>
-                  </div>
+            </div>
+            <div class="packed-list">
+              <div class="list-header">
+                <span class="title" i18n-content="appsDevtoolInstalled">
+                </span>
+                <div class="update-items-container">
+                  <button class="update-items-progress custom-appearance"
+                      i18n-content="appsDevtoolUpdating" disabled></span>
+                  <button class="update-items-now custom-appearance"
+                      i18n-content="appsDevtoolUpdateButton"></button>
                 </div>
               </div>
-              <div>
-                <div class="active-views" hidden>
-                  <span i18n-content="extensionSettingsInspectViews"></span>
-                  <a href="#"></a>
-                </div>
+              <div class="items"></div>
+              <div id="no-packed-extensions">
+                <span id="no-packed-extensions-message"
+                    i18n-content="appsDevtoolNoPackedExtensions"></span>
               </div>
-              <div>
-                <a class="reload-link" href="#"
-                    i18n-content="extensionSettingsReloadUnpacked" hidden>
+            </div>
+          </tabpanel>
+        </tabpanels>
+      </tabbox>
+    </div>
+  </div>
+  <div id="template-collection" hidden>
+    <div class="extension-list-item-wrapper">
+      <div class="extension-list-item">
+        <div class="extension-details">
+          <div class="extension-details-summary">
+            <div class="extension-title-container">
+              <a class="extension-title" href="#"></a>
+              <span class="extension-version"></span>
+              <span class="extension-disabled"
+                  i18n-content="extensionDisabled"></span>
+            </div>
+            <div class="extension-description"><span></span></div>
+          </div>
+          <div class="extension-details-all">
+            <div>
+              <div class="item-id item">
+                <span i18n-content="extensionSettingsExtensionId"></span>
+                <span class="extension-id"></span>
+              </div>
+              <div class="load-path item" hidden>
+                <span i18n-content="extensionSettingsExtensionPath"></span>
+                <span></span>
+              </div>
+            </div>
+            <div class="item">
+              <span class="extension-disable-reason"></span>
+            </div>
+            <div class="managed-message item"
+                i18n-content="extensionSettingsPolicyControlled" hidden>
+            </div>
+            <div class="extension-warnings item" hidden>
+              <span i18n-content="extensionSettingsWarningsTitle"></span>
+            </div>
+            <div class="install-warnings item" hidden>
+              <span i18n-content="extensionSettingsInstallWarnings"></span>
+              <ul></ul>
+            </div>
+            <div class="controls-container">
+              <div class="controls">
+                <a class="terminated-reload-link" href="#"
+                    i18n-content="extensionSettingsReloadTerminated" hidden>
                 </a>
-                <a class="launch-link" i18n-content="extensionSettingsLaunch"
-                    href="#" hidden></a>
-                <a class="restart-link" i18n-content="extensionSettingsRestart"
-                    href="#" hidden></a>
+                <div class="checkbox enable-checkbox" hidden>
+                  <label>
+                    <input type="checkbox">
+                    <span class="enable-checkbox-text">
+                      <span class="enabled-text"
+                          i18n-content="extensionSettingsEnabled"></span>
+                      <span class="enable-text"
+                          i18n-content="extensionSettingsEnable"></span>
+                    </span>
+                  </label>
+                  <span class="location-text"></span>
+                </div>
               </div>
-              <div>
-                <a class="permissions-link"
-                    i18n-content="extensionSettingsPermissions" href="#"></a>
-                <a class="site-link" target="_blank" hidden></a>
-                <a class="options-link" i18n-content="extensionSettingsOptions"
-                    href="#" target="_blank" hidden></a>
-                <a class="pack-link" i18n-content="extensionSettingsPack"
-                    href="#" hidden></a>
-                <a class="delete-link" i18n-content="extensionSettingsDelete"
-                    href="#"></a>
+              <div class="optional-controls">
+                <label class="incognito-control" hidden>
+                  <input type="checkbox">
+                  <span i18n-content="extensionSettingsEnableIncognito">
+                  </span>
+                </label>
+                <label class="file-access-control" hidden>
+                  <input type="checkbox">
+                  <span i18n-content="extensionSettingsAllowFileAccess">
+                  </span>
+                </label>
               </div>
             </div>
+            <div>
+              <div class="active-views" hidden>
+                <span i18n-content="extensionSettingsInspectViews"></span>
+                <a href="#"></a>
+              </div>
+            </div>
+            <div class="buttons-container">
+              <a class="reload-link" href="#"
+                  i18n-content="extensionSettingsReloadUnpacked" hidden>
+              </a>
+              <a class="launch-link" i18n-content="extensionSettingsLaunch"
+                  href="#" hidden></a>
+              <a class="restart-link" i18n-content="extensionSettingsRestart"
+                  href="#" hidden></a>
+              <a class="permissions-link"
+                  i18n-content="extensionSettingsPermissions" href="#"></a>
+              <a class="site-link" target="_blank" hidden></a>
+              <a class="options-link" i18n-content="extensionSettingsOptions"
+                  href="#" target="_blank" hidden></a>
+              <a class="pack-link" i18n-content="extensionSettingsPack"
+                  href="#" hidden></a>
+              <a class="delete-link" i18n-content="extensionSettingsDelete"
+                  href="#"></a>
+            </div>
           </div>
         </div>
       </div>
diff --git a/chrome/browser/resources/apps_debugger/pack_item_overlay.html b/chrome/browser/resources/apps_debugger/pack_item_overlay.html
index 1af90e0..fd9bb8a 100644
--- a/chrome/browser/resources/apps_debugger/pack_item_overlay.html
+++ b/chrome/browser/resources/apps_debugger/pack_item_overlay.html
@@ -1,8 +1,7 @@
 <div id="packItemOverlay" class="page">
-  <h1 i18n-content="packExtensionOverlay"></h1>
+  <h1 id="pack-title"></h1>
   <div id="cbd-content-area" class="content-area">
-    <div class="pack-item-heading" i18n-content="packExtensionHeading">
-    </div>
+    <div class="pack-item-heading" id="pack-heading"></div>
     <input class="pack-item-text-area" id="item-root-dir" type="hidden">
     <div class="pack-item-text-boxes">
       <label i18n-content="packExtensionPrivateKey"></label>
@@ -15,8 +14,7 @@
     <div class="action-area-right">
       <div class="button-strip">
         <button id="pack-item-dismiss" i18n-content="cancel"></button>
-        <button id="pack-item-commit"
-                i18n-content="packExtensionCommit"></button>
+        <button id="pack-item-commit" i18n-content="packButton"></button>
       </div>
     </div>
   </div>
diff --git a/chrome/browser/resources/chromeos/about_os_credits.html b/chrome/browser/resources/chromeos/about_os_credits.html
index e4c10db..2cdde1a 100644
--- a/chrome/browser/resources/chromeos/about_os_credits.html
+++ b/chrome/browser/resources/chromeos/about_os_credits.html
@@ -1,7 +1,7 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>Credits</title>
 <style>
 body {
@@ -66,10 +66,10 @@
 
   if (licence.style && licence.style.display == 'block') {
     licence.style.display = 'none';
-    o.innerHTML = 'show license(s)';
+    o.innerHTML = 'show license text';
   } else {
     licence.style.display = 'block';
-    o.innerHTML = 'hide license(s)';
+    o.innerHTML = 'hide license text';
   }
   return false;
 }
@@ -81,7 +81,7 @@
 <div style="clear:both; overflow:auto;"><!-- Chromium <3s the following projects -->
 <div class="product">
 <span class="title">Linux-2.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.kernel.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -94,7 +94,7 @@
 
 <div class="product">
 <span class="title">X.Org-1.9.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.x.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -107,7 +107,7 @@
 
 <div class="product">
 <span class="title">acl-2.2.51</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://savannah.nongnu.org/projects/acl">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -120,7 +120,7 @@
 
 <div class="product">
 <span class="title">adhd-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.chromium.org">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -133,7 +133,7 @@
 
 <div class="product">
 <span class="title">alsa-headers-1.0.25</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.alsa-project.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -146,7 +146,7 @@
 
 <div class="product">
 <span class="title">alsa-lib-1.0.25</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.alsa-project.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -159,7 +159,7 @@
 
 <div class="product">
 <span class="title">alsa-plugins-1.0.25</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.alsa-project.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -173,7 +173,7 @@
 
 <div class="product">
 <span class="title">alsa-utils-1.0.25</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.alsa-project.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -186,7 +186,7 @@
 
 <div class="product">
 <span class="title">argparse-1.2.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/argparse/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license argparse-1.2.1/LICENSE.txt:
@@ -223,7 +223,7 @@
 
 <div class="product">
 <span class="title">ath3k-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.atheros.com/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -236,7 +236,7 @@
 
 <div class="product">
 <span class="title">ath6k-34</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.atheros.com/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -249,7 +249,7 @@
 
 <div class="product">
 <span class="title">atk-1.32.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://projects.gnome.org/accessibility/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -262,7 +262,7 @@
 
 <div class="product">
 <span class="title">attr-2.4.46</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://savannah.nongnu.org/projects/attr">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -275,7 +275,7 @@
 
 <div class="product">
 <span class="title">autoconf-2.13</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/autoconf/autoconf.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -288,7 +288,7 @@
 
 <div class="product">
 <span class="title">autoconf-2.68</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/autoconf/autoconf.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -301,7 +301,7 @@
 
 <div class="product">
 <span class="title">autoconf-wrapper-10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -314,7 +314,7 @@
 
 <div class="product">
 <span class="title">automake-1.11.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sources.redhat.com/automake/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -327,7 +327,7 @@
 
 <div class="product">
 <span class="title">automake-wrapper-5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -340,7 +340,7 @@
 
 <div class="product">
 <span class="title">avfs-1.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sourceforge.net/projects/avf">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -353,7 +353,7 @@
 
 <div class="product">
 <span class="title">baselayout-2.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://src.chromium.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -366,7 +366,7 @@
 
 <div class="product">
 <span class="title">bash-4.2_p20</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://tiswww.case.edu/php/chet/bash/bashtop.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -379,7 +379,7 @@
 
 <div class="product">
 <span class="title">binutils-2.22</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sources.redhat.com/binutils/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -393,7 +393,7 @@
 
 <div class="product">
 <span class="title">binutils-config-3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -406,7 +406,7 @@
 
 <div class="product">
 <span class="title">bluez-5.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.bluez.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -420,7 +420,7 @@
 
 <div class="product">
 <span class="title">bsdiff-4.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.daemonology.net/bsdiff/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -433,7 +433,7 @@
 
 <div class="product">
 <span class="title">busybox-1.21.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.busybox.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -446,7 +446,7 @@
 
 <div class="product">
 <span class="title">bzip2-1.0.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.bzip.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license bzip2-1.0.6/LICENSE:
@@ -505,7 +505,7 @@
 
 <div class="product">
 <span class="title">c-ares-1.7.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://c-ares.haxx.se/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -518,7 +518,7 @@
 
 <div class="product">
 <span class="title">cairo-1.12.12</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://cairographics.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -532,7 +532,7 @@
 
 <div class="product">
 <span class="title">chinese-input-1.0.0.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.google.com/inputtools/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -545,7 +545,7 @@
 
 <div class="product">
 <span class="title">chromeos-hangul-1.0.0.12</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://code.google.com/p/google-input-tools/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -558,7 +558,7 @@
 
 <div class="product">
 <span class="title">chromeos-keyboards-1.1.3.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://code.google.com/p/google-input-tools">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -571,7 +571,7 @@
 
 <div class="product">
 <span class="title">chvt-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -584,7 +584,7 @@
 
 <div class="product">
 <span class="title">coreutils-8.20</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/coreutils/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -597,7 +597,7 @@
 
 <div class="product">
 <span class="title">crda-1.1.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://wireless.kernel.org/en/developers/Regulatory">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license crda-1.1.1/LICENSE:
@@ -656,7 +656,7 @@
 
 <div class="product">
 <span class="title">croscorefonts-1.23.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -669,7 +669,7 @@
 
 <div class="product">
 <span class="title">crosextrafonts-20130214</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -682,7 +682,7 @@
 
 <div class="product">
 <span class="title">ctemplate-1.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/google-ctemplate/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license ctemplate-1.0/COPYING:
@@ -767,7 +767,7 @@
 
 <div class="product">
 <span class="title">curl-7.23.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://curl.haxx.se/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license curl-7.23.1/COPYING:
@@ -805,7 +805,7 @@
 
 <div class="product">
 <span class="title">dash-0.5.5.1.7</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://gondor.apana.org.au/~herbert/dash/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license dash-0.5.5.1/COPYING:
@@ -878,7 +878,7 @@
 
 <div class="product">
 <span class="title">dbus-1.6.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://dbus.freedesktop.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -892,7 +892,7 @@
 
 <div class="product">
 <span class="title">dbus-c++-0.0.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.freedesktop.org/wiki/Software/dbus-c%2B%2B">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -905,7 +905,7 @@
 
 <div class="product">
 <span class="title">dbus-glib-0.100</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://dbus.freedesktop.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -919,7 +919,7 @@
 
 <div class="product">
 <span class="title">ddccontrol-0.4.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://ddccontrol.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -932,7 +932,7 @@
 
 <div class="product">
 <span class="title">ddccontrol-db-20061014</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://ddccontrol.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -945,7 +945,7 @@
 
 <div class="product">
 <span class="title">dejavu-2.33</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://dejavu.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -958,7 +958,7 @@
 
 <div class="product">
 <span class="title">dhcpcd-5.1.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://roy.marples.name/projects/dhcpcd/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -971,7 +971,7 @@
 
 <div class="product">
 <span class="title">diffutils-3.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/diffutils/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -984,7 +984,7 @@
 
 <div class="product">
 <span class="title">dmidecode-2.10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.nongnu.org/dmidecode/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -997,7 +997,7 @@
 
 <div class="product">
 <span class="title">docbook-xml-dtd-4.1.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.docbook.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -1010,7 +1010,7 @@
 
 <div class="product">
 <span class="title">dosfstools-3.0.9</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.daniel-baumann.ch/software/dosfstools/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -1023,7 +1023,7 @@
 
 <div class="product">
 <span class="title">droidfonts-cros-20121206</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -1036,7 +1036,7 @@
 
 <div class="product">
 <span class="title">dtc-1.3.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.t2-project.org/packages/dtc.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -1049,7 +1049,7 @@
 
 <div class="product">
 <span class="title">e2fsprogs-1.42</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://e2fsprogs.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license e2fsprogs-1.42/COPYING:
@@ -2399,7 +2399,7 @@
 
 <div class="product">
 <span class="title">e2fsprogs-libs-1.42</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://e2fsprogs.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2412,7 +2412,7 @@
 
 <div class="product">
 <span class="title">ecryptfs-utils-101</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://launchpad.net/ecryptfs">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2425,7 +2425,7 @@
 
 <div class="product">
 <span class="title">eject-2.1.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://eject.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2438,7 +2438,7 @@
 
 <div class="product">
 <span class="title">elfutils-0.154</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://fedorahosted.org/elfutils/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2451,7 +2451,7 @@
 
 <div class="product">
 <span class="title">engine_pkcs11-0.1.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.opensc-project.org/engine_pkcs11">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2464,7 +2464,7 @@
 
 <div class="product">
 <span class="title">eselect-opengl-1.2.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2477,7 +2477,7 @@
 
 <div class="product">
 <span class="title">eselect-python-20100321</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2490,7 +2490,7 @@
 
 <div class="product">
 <span class="title">ethtool-6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sourceforge.net/projects/gkernel/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2503,7 +2503,7 @@
 
 <div class="product">
 <span class="title">exfat-utils-0.9.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/exfat/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2516,7 +2516,7 @@
 
 <div class="product">
 <span class="title">expat-2.1.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://expat.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license expat-2.1.0/COPYING:
@@ -2555,7 +2555,7 @@
 
 <div class="product">
 <span class="title">findutils-4.4.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/findutils/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2568,7 +2568,7 @@
 
 <div class="product">
 <span class="title">flashmap-0.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://flashmap.googlecode.com">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license flashmap-0.3/COPYING:
@@ -2618,7 +2618,7 @@
 
 <div class="product">
 <span class="title">flashrom-0.9.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://flashrom.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2631,7 +2631,7 @@
 
 <div class="product">
 <span class="title">flex-2.5.35_p10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://flex.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2644,7 +2644,7 @@
 
 <div class="product">
 <span class="title">font-util-1.2.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://xorg.freedesktop.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license font-util-1.2.0/COPYING:
@@ -2781,7 +2781,7 @@
 
 <div class="product">
 <span class="title">fontconfig-2.7.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://fontconfig.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2794,7 +2794,7 @@
 
 <div class="product">
 <span class="title">freetype-2.4.12</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.freetype.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2808,7 +2808,7 @@
 
 <div class="product">
 <span class="title">fuse-2.8.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://fuse.sourceforge.net">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2821,7 +2821,7 @@
 
 <div class="product">
 <span class="title">fuse-exfat-0.9.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/exfat/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2834,7 +2834,7 @@
 
 <div class="product">
 <span class="title">gdbm-1.9.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/gdbm/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -2847,7 +2847,7 @@
 
 <div class="product">
 <span class="title">gflags-1.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/google-gflags/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license gflags-1.2/COPYING:
@@ -2932,7 +2932,7 @@
 
 <div class="product">
 <span class="title">glew-1.5.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://glew.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license glew-1.5.6/LICENSE.txt:
@@ -3022,7 +3022,7 @@
 
 <div class="product">
 <span class="title">glib-2.34.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gtk.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3036,7 +3036,7 @@
 
 <div class="product">
 <span class="title">glog-0.3.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/google-glog/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license glog-0.3.2/COPYING:
@@ -3158,7 +3158,7 @@
 
 <div class="product">
 <span class="title">glproto-1.4.14</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.x.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3171,7 +3171,7 @@
 
 <div class="product">
 <span class="title">glu-9.0.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://cgit.freedesktop.org/mesa/glu/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3184,7 +3184,7 @@
 
 <div class="product">
 <span class="title">gmock-1.6.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/googlemock/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license gmock-1.6.0/COPYING:
@@ -3470,7 +3470,7 @@
 
 <div class="product">
 <span class="title">gmp-5.0.2_p1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://gmplib.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3483,7 +3483,7 @@
 
 <div class="product">
 <span class="title">grep-2.14</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/grep/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3496,7 +3496,7 @@
 
 <div class="product">
 <span class="title">gtest-1.6.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/googletest/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license gtest-1.6.0/COPYING:
@@ -3541,7 +3541,7 @@
 
 <div class="product">
 <span class="title">gtk+-2.20.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gtk.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3554,7 +3554,7 @@
 
 <div class="product">
 <span class="title">gtk-doc-am-1.18</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gtk.org/gtk-doc/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3568,7 +3568,7 @@
 
 <div class="product">
 <span class="title">gzip-1.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/gzip/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3581,7 +3581,7 @@
 
 <div class="product">
 <span class="title">harfbuzz-0.9.18</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.freedesktop.org/wiki/Software/HarfBuzz">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license harfbuzz-0.9.18/COPYING:
@@ -3689,7 +3689,7 @@
 
 <div class="product">
 <span class="title">hdparm-9.20</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sourceforge.net/projects/hdparm/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license hdparm-9.20/LICENSE.TXT:
@@ -3737,7 +3737,7 @@
 
 <div class="product">
 <span class="title">htpdate-1.0.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.clevervest.com/htp/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3750,7 +3750,7 @@
 
 <div class="product">
 <span class="title">hwids-20120922</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://github.com/gentoo/hwids">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3763,7 +3763,7 @@
 
 <div class="product">
 <span class="title">ibus-1.4.99.20120314</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/ibus/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3776,7 +3776,7 @@
 
 <div class="product">
 <span class="title">ibus-english-m-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://github.com/yusukes/ibus-zinnia">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3789,7 +3789,7 @@
 
 <div class="product">
 <span class="title">ibus-m17n-1.3.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/ibus/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3802,7 +3802,7 @@
 
 <div class="product">
 <span class="title">iniparser-3.0b</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://ndevilla.free.fr/iniparser/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license iniparser3.0b/LICENSE:
@@ -3840,7 +3840,7 @@
 
 <div class="product">
 <span class="title">input-tools-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.google.com/inputtools">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3853,7 +3853,7 @@
 
 <div class="product">
 <span class="title">intltool-0.41.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://edge.launchpad.net/intltool/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3866,7 +3866,7 @@
 
 <div class="product">
 <span class="title">iotools-1.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/iotools/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3879,7 +3879,7 @@
 
 <div class="product">
 <span class="title">iptables-1.4.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.iptables.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3892,7 +3892,7 @@
 
 <div class="product">
 <span class="title">iputils-20100418</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.linux-foundation.org/en/Net:Iputils">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3905,7 +3905,7 @@
 
 <div class="product">
 <span class="title">iw-3.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://wireless.kernel.org/en/users/Documentation/iw">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license iw-3.6/COPYING:
@@ -3938,7 +3938,7 @@
 
 <div class="product">
 <span class="title">jsonrpclib-0_pre20110820</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://github.com/joshmarshall/jsonrpclib">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3951,7 +3951,7 @@
 
 <div class="product">
 <span class="title">kbd-1.15.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://freshmeat.net/projects/kbd/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3964,7 +3964,7 @@
 
 <div class="product">
 <span class="title">keyutils-1.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.kernel.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -3978,7 +3978,7 @@
 
 <div class="product">
 <span class="title">ko-nanumfonts-3.10.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://hangeul.naver.com/index.nhn">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license ko-nanumfonts-3.10.0/LICENSE:
@@ -4097,7 +4097,7 @@
 
 <div class="product">
 <span class="title">ladspa-sdk-1.13</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.ladspa.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -4110,7 +4110,7 @@
 
 <div class="product">
 <span class="title">laptop-mode-tools-1.59</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.samwel.tk/laptop_mode/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -4123,7 +4123,7 @@
 
 <div class="product">
 <span class="title">leveldb-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/leveldb/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license leveldb-0.0.1/LICENSE:
@@ -4167,7 +4167,7 @@
 
 <div class="product">
 <span class="title">libaio-0.3.109</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.kernel.org/pub/linux/kernel/people/andrea/libaio/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -4180,7 +4180,7 @@
 
 <div class="product">
 <span class="title">libatomic_ops-7.2d</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.hpl.hp.com/research/linux/atomic_ops/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license gc-7.2/libatomic_ops/COPYING:
@@ -4953,7 +4953,7 @@
 
 <div class="product">
 <span class="title">libcap-2.17</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.friedhoff.org/posixfilecaps.html">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libcap-2.17/License:
@@ -5057,7 +5057,7 @@
 
 <div class="product">
 <span class="title">libchewing-0.3.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://chewing.csie.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5070,7 +5070,7 @@
 
 <div class="product">
 <span class="title">libdivsufsort-2.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/libdivsufsort/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libdivsufsort-2.0.1/COPYING:
@@ -5114,7 +5114,7 @@
 
 <div class="product">
 <span class="title">libevent-1.4.13</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://monkey.org/~provos/libevent/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5127,7 +5127,7 @@
 
 <div class="product">
 <span class="title">libffi-3.0.9</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sourceware.org/libffi/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libffi-3.0.9/LICENSE:
@@ -5165,7 +5165,7 @@
 
 <div class="product">
 <span class="title">libgcrypt-1.4.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnupg.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5178,7 +5178,7 @@
 
 <div class="product">
 <span class="title">libgpg-error-1.10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnupg.org/related_software/libgpg-error">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5192,7 +5192,7 @@
 
 <div class="product">
 <span class="title">libhangul-0.0.10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://kldp.net/projects/hangul/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5205,7 +5205,7 @@
 
 <div class="product">
 <span class="title">libmnl-1.0.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://netfilter.org/projects/libmnl">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5218,7 +5218,7 @@
 
 <div class="product">
 <span class="title">libmtp-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://libmtp.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5231,7 +5231,7 @@
 
 <div class="product">
 <span class="title">libnetfilter_queue-1.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.netfilter.org/projects/libnetfilter_queue/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5244,7 +5244,7 @@
 
 <div class="product">
 <span class="title">libnfnetlink-1.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.netfilter.org/projects/libnfnetlink/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5257,7 +5257,7 @@
 
 <div class="product">
 <span class="title">libnih-1.0.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://launchpad.net/libnih">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5270,7 +5270,7 @@
 
 <div class="product">
 <span class="title">libnl-1.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://people.suug.ch/~tgr/libnl/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5283,7 +5283,7 @@
 
 <div class="product">
 <span class="title">libnl-3.2.14</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.infradead.org/~tgr/libnl/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5296,7 +5296,7 @@
 
 <div class="product">
 <span class="title">libp11-0.2.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.opensc-project.org/libp11/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -5309,7 +5309,7 @@
 
 <div class="product">
 <span class="title">libpcap-1.1.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.tcpdump.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libpcap-1.1.1/LICENSE:
@@ -5345,7 +5345,7 @@
 
 <div class="product">
 <span class="title">libpcre-8.30</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.pcre.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license pcre-8.30/COPYING:
@@ -5464,7 +5464,7 @@
 
 <div class="product">
 <span class="title">libpng-1.2.49</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.libpng.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libpng-1.2.49/LICENSE:
@@ -5992,7 +5992,7 @@
 
 <div class="product">
 <span class="title">libpthread-stubs-0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://xorg.freedesktop.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libpthread-stubs-0.1/COPYING:
@@ -6030,7 +6030,7 @@
 
 <div class="product">
 <span class="title">libtool-2.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/libtool/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6043,7 +6043,7 @@
 
 <div class="product">
 <span class="title">libusb-0.1.12</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://libusb.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6056,7 +6056,7 @@
 
 <div class="product">
 <span class="title">libusb-1.0.9</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://libusb.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6069,7 +6069,7 @@
 
 <div class="product">
 <span class="title">libva-1.1.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.freedesktop.org/wiki/Software/vaapi">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libva-1.1.1/COPYING:
@@ -6154,7 +6154,7 @@
 
 <div class="product">
 <span class="title">libva-intel-driver-1.0.20</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.freedesktop.org/wiki/Software/vaapi">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libva-intel-driver-1.0.20/COPYING:
@@ -6220,7 +6220,7 @@
 
 <div class="product">
 <span class="title">libxcb-1.9.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://xcb.freedesktop.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libxcb-1.9.1/COPYING:
@@ -6267,7 +6267,7 @@
 
 <div class="product">
 <span class="title">libxml2-2.7.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.xmlsoft.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license libxml2-2.7.8/COPYING:
@@ -6343,7 +6343,7 @@
 
 <div class="product">
 <span class="title">linux-headers-3.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.kernel.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6356,7 +6356,7 @@
 
 <div class="product">
 <span class="title">llvm-3.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://llvm.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license llvm-3.2.src/LICENSE.TXT:
@@ -6569,7 +6569,7 @@
 
 <div class="product">
 <span class="title">lohitfonts-cros-2.5.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://fedorahosted.org/lohit">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license lohitfonts-cros-2.5.0/LICENSE:
@@ -6681,7 +6681,7 @@
 
 <div class="product">
 <span class="title">lsof-4.81</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6694,7 +6694,7 @@
 
 <div class="product">
 <span class="title">lvm2-2.02.88</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sources.redhat.com/lvm2/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6707,7 +6707,7 @@
 
 <div class="product">
 <span class="title">lzo-2.06</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.oberhumer.com/opensource/lzo/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6720,7 +6720,7 @@
 
 <div class="product">
 <span class="title">m17n-contrib-1.1.10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.m17n.org/m17n-lib/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6733,7 +6733,7 @@
 
 <div class="product">
 <span class="title">m17n-db-1.6.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.m17n.org/m17n-lib/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6746,7 +6746,7 @@
 
 <div class="product">
 <span class="title">m17n-lib-1.6.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.m17n.org/m17n-lib/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6759,7 +6759,7 @@
 
 <div class="product">
 <span class="title">m2crypto-0.21.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://chandlerproject.org/bin/view/Projects/MeTooCrypto">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license M2Crypto-0.21.1/LICENCE:
@@ -6802,7 +6802,7 @@
 
 <div class="product">
 <span class="title">make-3.82</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/make/make.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6815,7 +6815,7 @@
 
 <div class="product">
 <span class="title">marvell_sd8787-14.64.2.47</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.marvell.com/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6828,7 +6828,7 @@
 
 <div class="product">
 <span class="title">mawk-1.3.4_p20100625</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://invisible-island.net/mawk/mawk.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6841,7 +6841,7 @@
 
 <div class="product">
 <span class="title">memtester-4.2.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://pyropus.ca/software/memtester/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6854,7 +6854,7 @@
 
 <div class="product">
 <span class="title">mesa-9.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://mesa3d.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6869,7 +6869,7 @@
 
 <div class="product">
 <span class="title">mime-types-8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -6882,7 +6882,7 @@
 
 <div class="product">
 <span class="title">ml-anjalioldlipi-0.740</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://sites.google.com/site/cibu/anjalioldlipi-font">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license ml-anjalioldlipi-0.740/LICENSE:
@@ -6993,7 +6993,7 @@
 
 <div class="product">
 <span class="title">modemmanager-classic-interfaces-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.chromium.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7006,7 +7006,7 @@
 
 <div class="product">
 <span class="title">modemmanager-next-0.5.999</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://mail.gnome.org/archives/networkmanager-list/2008-July/msg00274.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7019,7 +7019,7 @@
 
 <div class="product">
 <span class="title">module-init-tools-3.16</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://modules.wiki.kernel.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7032,7 +7032,7 @@
 
 <div class="product">
 <span class="title">mtdev-1.1.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://bitmath.org/code/mtdev/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license mtdev-1.1.2/COPYING:
@@ -7072,7 +7072,7 @@
 
 <div class="product">
 <span class="title">mtools-4.0.15</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://mtools.linux.lu/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7085,7 +7085,7 @@
 
 <div class="product">
 <span class="title">my-padauk-2.50</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=padauk">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7098,7 +7098,7 @@
 
 <div class="product">
 <span class="title">nacl-mozc-1.10.1389.104</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/mozc">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7111,7 +7111,7 @@
 
 <div class="product">
 <span class="title">ncurses-5.9</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/ncurses/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7124,7 +7124,7 @@
 
 <div class="product">
 <span class="title">net-tools-1.60_p20110409135728</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://net-tools.berlios.de/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7137,7 +7137,7 @@
 
 <div class="product">
 <span class="title">netifaces-0.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://alastairs-place.net/netifaces/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7150,7 +7150,7 @@
 
 <div class="product">
 <span class="title">notofonts-20130514</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7163,7 +7163,7 @@
 
 <div class="product">
 <span class="title">nspr-4.9.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.mozilla.org/projects/nspr/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7178,7 +7178,7 @@
 
 <div class="product">
 <span class="title">nss-3.14.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.mozilla.org/projects/security/pki/nss/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7193,7 +7193,7 @@
 
 <div class="product">
 <span class="title">ntfs3g-2012.1.15</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.tuxera.com/community/ntfs-3g-download/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7206,7 +7206,7 @@
 
 <div class="product">
 <span class="title">o3d-203170</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/o3d/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7219,7 +7219,7 @@
 
 <div class="product">
 <span class="title">openssh-5.2_p1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.openssh.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license openssh-5.2p1/LICENCE:
@@ -7574,7 +7574,7 @@
 
 <div class="product">
 <span class="title">openssl-1.0.1c</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.openssl.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7587,7 +7587,7 @@
 
 <div class="product">
 <span class="title">openvpn-2.1.12</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://openvpn.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7600,7 +7600,7 @@
 
 <div class="product">
 <span class="title">pam-1.1.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://fedorahosted.org/linux-pam/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7613,7 +7613,7 @@
 
 <div class="product">
 <span class="title">pam_pwdfile-0.99</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://cpbotha.net/pam_pwdfile.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7626,7 +7626,7 @@
 
 <div class="product">
 <span class="title">pambase-20101024</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/proj/en/base/pam/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7639,7 +7639,7 @@
 
 <div class="product">
 <span class="title">pango-1.32.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.pango.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7654,7 +7654,7 @@
 
 <div class="product">
 <span class="title">parted-3.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/parted">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7667,7 +7667,7 @@
 
 <div class="product">
 <span class="title">patch-2.6.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/patch/patch.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7680,7 +7680,7 @@
 
 <div class="product">
 <span class="title">pax-utils-0.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://hardened.gentoo.org/pax-utils.xml">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7693,7 +7693,7 @@
 
 <div class="product">
 <span class="title">pciutils-3.1.10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://mj.ucw.cz/sw/pciutils/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7706,7 +7706,7 @@
 
 <div class="product">
 <span class="title">perf-3.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://perf.wiki.kernel.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7719,7 +7719,7 @@
 
 <div class="product">
 <span class="title">pkcs11-helper-1.07</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.opensc-project.org/pkcs11-helper">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7732,7 +7732,7 @@
 
 <div class="product">
 <span class="title">ply-image-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.chromium.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7745,7 +7745,7 @@
 
 <div class="product">
 <span class="title">popt-1.16</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://rpm5.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license popt-1.16/COPYING:
@@ -7784,7 +7784,7 @@
 
 <div class="product">
 <span class="title">portage-2.1.11.50</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/proj/en/portage/index.xml">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7797,7 +7797,7 @@
 
 <div class="product">
 <span class="title">ppp-2.4.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.samba.org/ppp">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7810,7 +7810,7 @@
 
 <div class="product">
 <span class="title">procps-3.3.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://procps.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7823,7 +7823,7 @@
 
 <div class="product">
 <span class="title">protobuf-2.3.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/protobuf/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7836,7 +7836,7 @@
 
 <div class="product">
 <span class="title">pv-1.3.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.ivarch.com/programs/pv.shtml">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -7849,7 +7849,7 @@
 
 <div class="product">
 <span class="title">python-2.7.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.python.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license Python-2.7.3/LICENSE:
@@ -8313,7 +8313,7 @@
 
 <div class="product">
 <span class="title">python-evdev-0.3.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://gvalkov.github.com/python-evdev/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license python-evdev-0.3.1/LICENSE:
@@ -8358,7 +8358,7 @@
 
 <div class="product">
 <span class="title">python-updater-0.10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/proj/en/Python/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8371,7 +8371,7 @@
 
 <div class="product">
 <span class="title">pyyaml-3.09</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://pyyaml.org/wiki/PyYAML">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license PyYAML-3.09/LICENSE:
@@ -8407,7 +8407,7 @@
 
 <div class="product">
 <span class="title">ragel-6.7</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.complang.org/ragel/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8420,7 +8420,7 @@
 
 <div class="product">
 <span class="title">readline-6.2_p1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8433,7 +8433,7 @@
 
 <div class="product">
 <span class="title">realtek-rt2800-firmware-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://git.kernel.org/?p=linux/kernel/git/firmware/linux-firmware.git">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8446,7 +8446,7 @@
 
 <div class="product">
 <span class="title">rootdev-0.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.chromium.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license rootdev-0.0.1/LICENSE:
@@ -8490,7 +8490,7 @@
 
 <div class="product">
 <span class="title">rsync-3.0.8</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://rsync.samba.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8503,7 +8503,7 @@
 
 <div class="product">
 <span class="title">rsyslog-5.8.11</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.rsyslog.com/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8518,7 +8518,7 @@
 
 <div class="product">
 <span class="title">sandbox-2.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gentoo.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8531,7 +8531,7 @@
 
 <div class="product">
 <span class="title">sbc-1.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://git.kernel.org/?p=bluetooth/sbc.git">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8545,7 +8545,7 @@
 
 <div class="product">
 <span class="title">scons-2.0.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.scons.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license scons-2.0.1/LICENSE.txt:
@@ -8582,7 +8582,7 @@
 
 <div class="product">
 <span class="title">sed-4.2.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://sed.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8595,7 +8595,7 @@
 
 <div class="product">
 <span class="title">setproctitle-1.1.6</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/py-setproctitle/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license setproctitle-1.1.6/COPYRIGHT:
@@ -8637,7 +8637,7 @@
 
 <div class="product">
 <span class="title">setuptools-0.6.14</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://pypi.python.org/pypi/distribute">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8650,7 +8650,7 @@
 
 <div class="product">
 <span class="title">sgml-common-0.6.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.iso.ch/cate/3524030.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8663,7 +8663,7 @@
 
 <div class="product">
 <span class="title">shadow-4.1.2.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://shadow.pld.org.pl/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license shadow-4.1.2.2/COPYING:
@@ -8798,7 +8798,7 @@
 
 <div class="product">
 <span class="title">shared-mime-info-0.90</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://freedesktop.org/wiki/Software/shared-mime-info">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8811,7 +8811,7 @@
 
 <div class="product">
 <span class="title">sharutils-4.7</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/sharutils/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8824,7 +8824,7 @@
 
 <div class="product">
 <span class="title">shflags-1.0.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/shflags/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8837,7 +8837,7 @@
 
 <div class="product">
 <span class="title">sil-abyssinica-1.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://scripts.sil.org/AbyssinicaSIL">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8850,7 +8850,7 @@
 
 <div class="product">
 <span class="title">simplejson-2.5.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://undefined.org/python/#simplejson">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license simplejson-2.5.0/LICENSE.txt:
@@ -8886,7 +8886,7 @@
 
 <div class="product">
 <span class="title">smartmontools-5.42</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://smartmontools.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8899,7 +8899,7 @@
 
 <div class="product">
 <span class="title">speex-1.2_rc1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.speex.org">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license speex-1.2rc1/COPYING:
@@ -8951,7 +8951,7 @@
 
 <div class="product">
 <span class="title">sqlite-3.6.22</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.sqlite.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8964,7 +8964,7 @@
 
 <div class="product">
 <span class="title">stressapptest-1.0.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://code.google.com/p/stressapptest/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8977,7 +8977,7 @@
 
 <div class="product">
 <span class="title">strongswan-5.0.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.strongswan.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -8992,7 +8992,7 @@
 
 <div class="product">
 <span class="title">sudo-1.8.6_p7</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.sudo.ws/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license sudo-1.8.6p7/doc/LICENSE:
@@ -9130,7 +9130,7 @@
 
 <div class="product">
 <span class="title">swig-2.0.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.swig.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license swig-2.0.4/CCache/COPYING:
@@ -9656,7 +9656,7 @@
 
 <div class="product">
 <span class="title">syslinux-3.83</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://syslinux.zytor.com/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9669,7 +9669,7 @@
 
 <div class="product">
 <span class="title">tar-1.26</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/tar/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9682,7 +9682,7 @@
 
 <div class="product">
 <span class="title">tibt-jomolhari-0.0.3c</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://sites.google.com/site/chrisfynn2/home/fonts/jomolhari">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9695,7 +9695,7 @@
 
 <div class="product">
 <span class="title">timezone-data-2012j</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.iana.org/time-zones">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9708,7 +9708,7 @@
 
 <div class="product">
 <span class="title">tlsdate-0.0.5</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://github.com/ioerror/tlsdate">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license tlsdate-0.0.5/LICENSE:
@@ -9776,7 +9776,7 @@
 
 <div class="product">
 <span class="title">trousers-0.3.3</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://trousers.sf.net">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9789,7 +9789,7 @@
 
 <div class="product">
 <span class="title">udev-171</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9802,7 +9802,7 @@
 
 <div class="product">
 <span class="title">unittest2-0.5.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://pypi.python.org/pypi/unittest2">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9815,7 +9815,7 @@
 
 <div class="product">
 <span class="title">unrar-4.2.4</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.rarlab.com/rar_add.htm">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9828,7 +9828,7 @@
 
 <div class="product">
 <span class="title">upstart-1.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://upstart.ubuntu.com/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9841,7 +9841,7 @@
 
 <div class="product">
 <span class="title">ureadahead-0.100.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="https://launchpad.net/ureadahead">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9854,7 +9854,7 @@
 
 <div class="product">
 <span class="title">usbutils-006</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://linux-usb.sourceforge.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -9867,7 +9867,7 @@
 
 <div class="product">
 <span class="title">util-linux-2.21.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.kernel.org/pub/linux/utils/util-linux/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license util-linux-2.21.2/COPYING:
@@ -10273,7 +10273,7 @@
 
 <div class="product">
 <span class="title">vim-7.3.409</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.vim.org/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -10286,7 +10286,7 @@
 
 <div class="product">
 <span class="title">wget-1.12</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.gnu.org/software/wget/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -10299,7 +10299,7 @@
 
 <div class="product">
 <span class="title">which-2.20</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.xs4all.nl/~carlo17/which/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -10312,7 +10312,7 @@
 
 <div class="product">
 <span class="title">wireless-regdb-20101124</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://wireless.kernel.org/en/developers/Regulatory">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license wireless-regdb-2010.11.24/LICENSE:
@@ -10371,7 +10371,7 @@
 
 <div class="product">
 <span class="title">wpa_supplicant-0.7.2</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://hostap.epitest.fi/wpa_supplicant/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -10384,7 +10384,7 @@
 
 <div class="product">
 <span class="title">xcb-proto-1.7.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://xcb.freedesktop.org/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license xcb-proto-1.7.1/COPYING:
@@ -10431,7 +10431,7 @@
 
 <div class="product">
 <span class="title">xkeyboard-config-2.4.1</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.freedesktop.org/wiki/Software/XKeyboardConfig">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license xkeyboard-config-2.4.1/COPYING:
@@ -10638,7 +10638,7 @@
 
 <div class="product">
 <span class="title">xl2tpd-1.3.0</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.xelerance.com/services/software/xl2tpd/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -10651,7 +10651,7 @@
 
 <div class="product">
 <span class="title">xxd-1.10</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://ftp.uni-erlangen.de/pub/utilities/etc/?order=s">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -10664,7 +10664,7 @@
 
 <div class="product">
 <span class="title">xz-utils-4.999.9_beta</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://tukaani.org/xz/">homepage</a></span>
 <div class="licence">
 <pre>Scanned Source license xz-4.999.9beta/COPYING:
@@ -10749,7 +10749,7 @@
 
 <div class="product">
 <span class="title">zlib-1.2.7</span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <span class="homepage"><a href="http://www.zlib.net/">homepage</a></span>
 <div class="licence">
 <pre></pre>
@@ -10767,7 +10767,7 @@
 <span class="title">
 <a name="AFL-2.1">Gentoo Package Provided Stock License AFL-2.1</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 The Academic Free License
@@ -10833,7 +10833,7 @@
 <span class="title">
 <a name="Apache-2.0">Gentoo Package Provided Stock License Apache-2.0</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
                                  Apache License
@@ -11526,7 +11526,7 @@
 <span class="title">
 <a name="Artistic-2">Gentoo Package Provided Stock License Artistic-2</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 		       The Artistic License 2.0
@@ -11742,7 +11742,7 @@
 <span class="title">
 <a name="Atheros">Gentoo Package Provided Stock License Atheros</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 2010, Atheros Communications, Inc.
@@ -11776,7 +11776,7 @@
 <span class="title">
 <a name="BSD-Google">Gentoo Package Provided Stock License BSD-Google</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright 2010, Google Inc.
@@ -11819,7 +11819,7 @@
 <span class="title">
 <a name="BSD-bsdiff">Gentoo Package Provided Stock License BSD-bsdiff</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright 2003-2005 Colin Percival
@@ -11857,7 +11857,7 @@
 <span class="title">
 <a name="BSD-dhcpcd">Gentoo Package Provided Stock License BSD-dhcpcd</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
@@ -11895,7 +11895,7 @@
 <span class="title">
 <a name="BSD-iputils">Gentoo Package Provided Stock License BSD-iputils</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 1989 The Regents of the University of California.
@@ -11943,7 +11943,7 @@
 <span class="title">
 <a name="BSD-libevent">Gentoo Package Provided Stock License BSD-libevent</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
@@ -11982,7 +11982,7 @@
 <span class="title">
 <a name="BZIP2">Gentoo Package Provided Stock License BZIP2</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 <copyright notice>
@@ -12030,7 +12030,7 @@
 <span class="title">
 <a name="BitstreamVera">Gentoo Package Provided Stock License BitstreamVera</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Bitstream Vera Fonts Copyright
@@ -12169,7 +12169,7 @@
 <span class="title">
 <a name="CPL-1.0">Gentoo Package Provided Stock License CPL-1.0</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Common Public License Version 1.0
@@ -12270,7 +12270,7 @@
 <span class="title">
 <a name="DES">Gentoo Package Provided Stock License DES</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
@@ -12336,7 +12336,7 @@
 <span class="title">
 <a name="FDL-1.1">Gentoo Package Provided Stock License FDL-1.1</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 		GNU Free Documentation License
@@ -12706,7 +12706,7 @@
 <span class="title">
 <a name="FLEX">Gentoo Package Provided Stock License FLEX</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Flex carries the copyright used for BSD software, slightly modified
@@ -12759,7 +12759,7 @@
 <span class="title">
 <a name="FTL">Gentoo Package Provided Stock License FTL</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
                     The FreeType Project LICENSE
@@ -12932,7 +12932,7 @@
 <span class="title">
 <a name="GPL-2">Gentoo Package Provided Stock License GPL-2</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 		    GNU GENERAL PUBLIC LICENSE
@@ -13287,7 +13287,7 @@
 <span class="title">
 <a name="GPL-2+">Gentoo Package Provided Stock License GPL-2+</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 GNU General Public License, version 2 or any later version.
@@ -13304,7 +13304,7 @@
 <span class="title">
 <a name="GPL-2-with-exceptions">Gentoo Package Provided Stock License GPL-2-with-exceptions</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 NOTE: This is the GPL with specific exceptions added by packages to extend your rights under the GPL. The specific exception(s) for the package can be found in the source tarball.
@@ -13672,7 +13672,7 @@
 <span class="title">
 <a name="GPL-3">Gentoo Package Provided Stock License GPL-3</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
                     GNU GENERAL PUBLIC LICENSE
@@ -14361,7 +14361,7 @@
 <span class="title">
 <a name="ISC">Gentoo Package Provided Stock License ISC</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 4-digit year, Company or Person's Name
@@ -14389,7 +14389,7 @@
 <span class="title">
 <a name="LGPL-2">Gentoo Package Provided Stock License LGPL-2</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 		  GNU LIBRARY GENERAL PUBLIC LICENSE
@@ -14886,7 +14886,7 @@
 <span class="title">
 <a name="LGPL-2+">Gentoo Package Provided Stock License LGPL-2+</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 GNU Library General Public License, version 2 or any later version.
@@ -14903,7 +14903,7 @@
 <span class="title">
 <a name="LGPL-2.1">Gentoo Package Provided Stock License LGPL-2.1</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 		  GNU LESSER GENERAL PUBLIC LICENSE
@@ -15422,7 +15422,7 @@
 <span class="title">
 <a name="LGPL-3">Gentoo Package Provided Stock License LGPL-3</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 		   GNU LESSER GENERAL PUBLIC LICENSE
@@ -15602,7 +15602,7 @@
 <span class="title">
 <a name="MIT-MIT">Gentoo Package Provided Stock License MIT-MIT</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright 1998 by the Massachusetts Institute of Technology.
@@ -15630,7 +15630,7 @@
 <span class="title">
 <a name="MIT-Mesa">Gentoo Package Provided Stock License MIT-Mesa</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 The Mesa 3D Graphics Library
@@ -15715,7 +15715,7 @@
 <span class="title">
 <a name="MPL-1.1">Gentoo Package Provided Stock License MPL-1.1</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
                           MOZILLA PUBLIC LICENSE
@@ -16297,7 +16297,7 @@
 <span class="title">
 <a name="MPL-2.0">Gentoo Package Provided Stock License MPL-2.0</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Mozilla Public License Version 2.0
@@ -16686,7 +16686,7 @@
 <span class="title">
 <a name="Marvell">Gentoo Package Provided Stock License Marvell</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (C) 2010, Marvell International Ltd.
@@ -16709,7 +16709,7 @@
 <span class="title">
 <a name="OFL">Gentoo Package Provided Stock License OFL</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 This Font Software is Copyright (c) 2003-2005, SIL International (http://scripts.sil.org/).
@@ -16823,7 +16823,7 @@
 <span class="title">
 <a name="OFL-1.1">Gentoo Package Provided Stock License OFL-1.1</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
@@ -16929,7 +16929,7 @@
 <span class="title">
 <a name="PSF-2">Gentoo Package Provided Stock License PSF-2</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
@@ -16990,7 +16990,7 @@
 <span class="title">
 <a name="RSA">Gentoo Package Provided Stock License RSA</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 [<copyright notice>]
@@ -17023,7 +17023,7 @@
 <span class="title">
 <a name="SGI-B-2.0">Gentoo Package Provided Stock License SGI-B-2.0</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
@@ -17065,7 +17065,7 @@
 <span class="title">
 <a name="UoI-NCSA">Gentoo Package Provided Stock License UoI-NCSA</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) <YEAR> <OWNER ORGANIZATION NAME>.  All rights reserved.
@@ -17109,7 +17109,7 @@
 <span class="title">
 <a name="ZLIB">Gentoo Package Provided Stock License ZLIB</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (C) <year> <copyright holders>
@@ -17141,7 +17141,7 @@
 <span class="title">
 <a name="as-is">Gentoo Package Provided Stock License as-is</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Note: This license label is deprecated, so don't use it for new packages.
@@ -17189,7 +17189,7 @@
 <span class="title">
 <a name="boehm-gc">Gentoo Package Provided Stock License boehm-gc</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 <copyright notice>
@@ -17214,7 +17214,7 @@
 <span class="title">
 <a name="fontconfig">Gentoo Package Provided Stock License fontconfig</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 fontconfig/COPYING
@@ -17251,7 +17251,7 @@
 <span class="title">
 <a name="icu">Gentoo Package Provided Stock License icu</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 ICU License - ICU 1.8.1 and later
@@ -17300,7 +17300,7 @@
 <span class="title">
 <a name="lsof">Gentoo Package Provided Stock License lsof</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ#1.9
@@ -17343,7 +17343,7 @@
 <span class="title">
 <a name="ncurses">Gentoo Package Provided Stock License ncurses</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 1998-2000,2005 Free Software Foundation, Inc.
@@ -17383,7 +17383,7 @@
 <span class="title">
 <a name="netiface">Gentoo Package Provided Stock License netiface</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 2007, 2008 Alastair Houghton
@@ -17417,7 +17417,7 @@
 <span class="title">
 <a name="openssl">Gentoo Package Provided Stock License openssl</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 
@@ -17559,7 +17559,7 @@
 <span class="title">
 <a name="ppp-2.4.4">Gentoo Package Provided Stock License ppp-2.4.4</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 /*
@@ -20385,7 +20385,7 @@
 <span class="title">
 <a name="public-domain">Gentoo Package Provided Stock License public-domain</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Software is in the public domain.
@@ -20401,7 +20401,7 @@
 <span class="title">
 <a name="ralink-firmware">Gentoo Package Provided Stock License ralink-firmware</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 Copyright (c) 2007, Ralink Technology Corporation
@@ -20455,7 +20455,7 @@
 <span class="title">
 <a name="unRAR">Gentoo Package Provided Stock License unRAR</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
  ******    *****   ******   UnRAR - free utility for RAR archives
@@ -20512,7 +20512,7 @@
 <span class="title">
 <a name="vim">Gentoo Package Provided Stock License vim</a>
 </span>
-<a class="show" href="#" onclick="return toggle(this);">show license(s)</a>
+<a class="show" href="#" onclick="return toggle(this);">show license text</a>
 <div class="licence">
 <pre>
 License details for VIM Editor:
diff --git a/chrome/browser/resources/chromeos/app_launch/app_launch.css b/chrome/browser/resources/chromeos/app_launch/app_launch.css
deleted file mode 100644
index 92a6b0d..0000000
--- a/chrome/browser/resources/chromeos/app_launch/app_launch.css
+++ /dev/null
@@ -1,66 +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.
- */
-
-html,
-body {
-  height: 100%;
-  margin: 0;
-  overflow: hidden;
-  padding: 0;
-  width: 100%;
-}
-
-#page {
-  -webkit-box-align: center;
-  -webkit-box-pack: center;
-  /* Delay the login screen for 2 seconds then fade it in. */
-  -webkit-transition: opacity 1s;
-  background: white;
-  display: -webkit-box;
-  height: 100%;
-  opacity: 0;
-  position: absolute;
-  width: 100%;
-}
-
-#content {
-  -webkit-box-align: center;
-  -webkit-box-orient: vertical;
-  -webkit-box-pack: center;
-  display: -webkit-box;
-  position: relative;
-}
-
-#header {
-  -webkit-padding-start: 108px;
-  background: left center no-repeat;
-  background-size: 96px;
-  color: #666;
-  display: -webkit-box;
-  font-size: 48px;
-  height: 96px;
-  line-height: 96px;
-}
-
-#launch-text {
-  color: #666;
-  font-size: 18px;
-  padding-bottom: 50px;
-  padding-top: 50px;
-}
-
-#spinner {
-  height: 32px;
-  width: 32px;
-}
-
-#shortcut-info {
-  bottom: 50px;
-  color: gray;
-  left: 0;
-  position: absolute;
-  right: 0;
-  text-align: center;
-}
diff --git a/chrome/browser/resources/chromeos/app_launch/app_launch.html b/chrome/browser/resources/chromeos/app_launch/app_launch.html
deleted file mode 100644
index d2c37f8..0000000
--- a/chrome/browser/resources/chromeos/app_launch/app_launch.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE HTML>
-<html i18n-values="dir:textdirection">
-<head>
-<link rel="stylesheet" href="chrome://resources/css/spinner.css">
-<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
-<link rel="stylesheet" href="app_launch.css">
-<script src="chrome://resources/js/util.js"></script>
-<script src="chrome://resources/js/load_time_data.js"></script>
-<script src="chrome://app-launch/app_launch.js"></script>
-<script src="chrome://app-launch/strings.js"></script>
-</head>
-<body i18n-values=".style.fontFamily:fontfamily;">
-  <div id="page">
-    <div id="content">
-      <div id="header" i18n-content="productName"></div>
-      <div id="launch-text" i18n-content="appStartMessage"></div>
-      <div id="spinner" class="spinner"></div>
-    </div>
-    <p id="shortcut-info" i18n-content="shortcutInfo"></p>
-  </div>
-  <script src="chrome://resources/js/i18n_template2.js"></script>
-</body>
-</html>
diff --git a/chrome/browser/resources/chromeos/app_launch/app_launch.js b/chrome/browser/resources/chromeos/app_launch/app_launch.js
deleted file mode 100644
index a2a3fe2..0000000
--- a/chrome/browser/resources/chromeos/app_launch/app_launch.js
+++ /dev/null
@@ -1,33 +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.
-
-/**
- * @fileoverview App install/launch splash screen.
- */
-
-/**
- * Initializes the click handler.
- */
-initialize = function() {
-  var params = parseQueryParams(window.location);
-  var appId = params['app'] || '';
-
-  chrome.send('initialize', [appId]);
-
-  $('shortcut-info').hidden = !loadTimeData.getBoolean('shortcutEnabled');
-  $('page').style.opacity = 1;
-  window.webkitRequestAnimationFrame(function() {});
-};
-
-updateApp = function(app) {
-  $('header').textContent = app.name;
-  $('header').style.backgroundImage = 'url(' + app.iconURL + ')';
-};
-
-updateMessage = function(message) {
-  $('launch-text').textContent = message;
-};
-
-disableTextSelectAndDrag();
-document.addEventListener('DOMContentLoaded', initialize);
diff --git a/chrome/browser/resources/chromeos/connectivity_diagnostics/manifest.json b/chrome/browser/resources/chromeos/connectivity_diagnostics/manifest.json
index 38a5d74..2a73fec 100644
--- a/chrome/browser/resources/chromeos/connectivity_diagnostics/manifest.json
+++ b/chrome/browser/resources/chromeos/connectivity_diagnostics/manifest.json
@@ -21,6 +21,7 @@
    ]},
    "clipboardWrite",
    "experimental",
+   "metricsPrivate",
    "networkingPrivate",
    "http://*.google.com/*",
    "https://*.google.com/*"
diff --git a/chrome/browser/resources/chromeos/guest_session_tab.html b/chrome/browser/resources/chromeos/guest_session_tab.html
index 6f73e72..7e51927 100644
--- a/chrome/browser/resources/chromeos/guest_session_tab.html
+++ b/chrome/browser/resources/chromeos/guest_session_tab.html
@@ -2,7 +2,7 @@
 <html i18n-values="dir:textdirection;">
 <head>
 <title i18n-content="title"></title>
-<link rel="stylesheet" href="../incognito_tab.css">
+<link rel="stylesheet" href="../ntp4/incognito_tab.css">
 <link rel="stylesheet" href="login/enterprise_info.css">
 <script>
 // Until themes can clear the cache, force-reload the theme stylesheet.
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay.js b/chrome/browser/resources/chromeos/keyboard_overlay.js
index d28515f..06d07d2 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay.js
@@ -128,10 +128,6 @@
 
   shortcutDataCache = keyboardOverlayData['shortcut'];
 
-  if (!isDisplayRotationEnabled()) {
-    // Rotate screen
-    delete shortcutDataCache['reload<>CTRL<>SHIFT'];
-  }
   if (!isDisplayUIScalingEnabled()) {
     // Zoom screen in
     delete shortcutDataCache['+<>CTRL<>SHIFT'];
@@ -575,14 +571,6 @@
 }
 
 /**
- * Returns true if display rotation feature is enabled.
- * @return {boolean} True if display rotation feature is enabled.
- */
-function isDisplayRotationEnabled() {
-  return loadTimeData.getBoolean('keyboardOverlayIsDisplayRotationEnabled');
-}
-
-/**
  * Returns true if display scaling feature is enabled.
  * @return {boolean} True if display scaling feature is enabled.
  */
diff --git a/chrome/browser/resources/chromeos/login/OWNERS b/chrome/browser/resources/chromeos/login/OWNERS
index 7e8a0a7..7cbbc2d 100644
--- a/chrome/browser/resources/chromeos/login/OWNERS
+++ b/chrome/browser/resources/chromeos/login/OWNERS
@@ -1,5 +1,5 @@
 nkostylev@chromium.org
-ivankr@chromium.org
 dpolukhin@chromium.org
 ygorshenin@chromium.org
 antrim@chromium.org
+dzhioev@chromium.org
diff --git a/chrome/browser/resources/chromeos/login/display_manager.js b/chrome/browser/resources/chromeos/login/display_manager.js
index 85c97b1..d650aa3 100644
--- a/chrome/browser/resources/chromeos/login/display_manager.js
+++ b/chrome/browser/resources/chromeos/login/display_manager.js
@@ -20,6 +20,7 @@
 /** @const */ var SCREEN_PASSWORD_CHANGED = 'password-changed';
 /** @const */ var SCREEN_CREATE_MANAGED_USER_FLOW =
     'managed-user-creation';
+/** @const */ var SCREEN_APP_LAUNCH_SPLASH = 'app-launch-splash';
 
 /* Accelerator identifiers. Must be kept in sync with webui_login_view.cc. */
 /** @const */ var ACCELERATOR_CANCEL = 'cancel';
@@ -32,6 +33,7 @@
 /** @const */ var ACCELERATOR_DEVICE_REQUISITION = 'device_requisition';
 /** @const */ var ACCELERATOR_DEVICE_REQUISITION_REMORA =
     'device_requisition_remora';
+/** @const */ var ACCELERATOR_APP_LAUNCH_BAILOUT = 'app_launch_bailout';
 
 /* Help topic identifiers. */
 /** @const */ var HELP_TOPIC_ENTERPRISE_REPORTING = 2535613;
@@ -53,6 +55,16 @@
   MANAGED_USER_CREATION_FLOW: 'ui-state-locally-managed'
 };
 
+/* Possible types of UI. */
+/** @const */ var DISPLAY_TYPE = {
+  UNKNOWN: 'unknown',
+  OOBE: 'oobe',
+  LOGIN: 'login',
+  LOCK: 'lock',
+  USER_ADDING: 'user-adding',
+  APP_LAUNCH_SPLASH: 'app-launch-splash'
+};
+
 cr.define('cr.ui.login', function() {
   var Bubble = cr.ui.Bubble;
 
@@ -130,6 +142,20 @@
     forceKeyboardFlow_: false,
 
     /**
+     * Type of UI.
+     * @type {string}
+     */
+    displayType_: DISPLAY_TYPE.UNKNOWN,
+
+    get displayType() {
+      return this.displayType_;
+    },
+
+    set displayType(displayType) {
+      this.displayType_ = displayType;
+    },
+
+    /**
      * Gets current screen element.
      * @type {HTMLElement}
      */
@@ -212,6 +238,10 @@
           this.deviceRequisition_ = 'remora';
           this.showDeviceRequisitionPrompt_();
         }
+      } else if (name == ACCELERATOR_APP_LAUNCH_BAILOUT) {
+        var currentStepId = this.screens_[this.currentStep_];
+        if (currentStepId == SCREEN_APP_LAUNCH_SPLASH)
+          chrome.send('cancelAppLaunch');
       }
 
       if (!this.forceKeyboardFlow_)
@@ -348,8 +378,7 @@
         }
       } else {
         // First screen on OOBE launch.
-        if (document.body.classList.contains('oobe-display') &&
-            innerContainer.classList.contains('down')) {
+        if (this.isOobeUI() && innerContainer.classList.contains('down')) {
           innerContainer.classList.remove('down');
           innerContainer.addEventListener(
               'webkitTransitionEnd', function f(e) {
@@ -366,8 +395,8 @@
         } else {
           if (defaultControl)
             defaultControl.focus();
+          chrome.send('loginVisible', ['oobe']);
         }
-        newHeader.classList.remove('right');  // Old OOBE.
       }
       this.currentStep_ = nextStepIndex;
       $('oobe').className = nextStepId;
@@ -465,9 +494,14 @@
       // Have to reset any previously predefined screen size first
       // so that screen contents would define it instead (offsetHeight/width).
       // http://crbug.com/146539
+      $('inner-container').style.height = '';
+      $('inner-container').style.width = '';
       screen.style.width = '';
       screen.style.height = '';
 
+     $('outer-container').classList.toggle(
+        'fullscreen', screen.classList.contains('fullscreen'));
+
       var height = screen.offsetHeight;
       var width = screen.offsetWidth;
       for (var i = 0, screenGroup; screenGroup = SCREEN_GROUPS[i]; i++) {
@@ -564,23 +598,7 @@
      * Returns true if Oobe UI is shown.
      */
     isOobeUI: function() {
-      return !document.body.classList.contains('login-display');
-    },
-
-    /**
-     * Returns true if the current UI type is the "Sign-in to add user"
-     * (another user session is already active).
-     */
-    isSignInToAddScreen: function() {
-      return document.documentElement.getAttribute('screen') ==
-          'user-adding';
-    },
-
-    /**
-     * Returns true if the current UI type is the lock screen.
-     */
-    isLockScreen: function() {
-      return document.documentElement.getAttribute('screen') == 'lock';
+      return document.body.classList.contains('oobe-display');
     },
 
     /**
@@ -595,16 +613,20 @@
    * Initializes display manager.
    */
   DisplayManager.initialize = function() {
-    // Extracting screen type from URL.
-    var hash = window.location.hash;
-    var screenType;
-    if (!hash) {
-      console.error('Screen type not found. Setting default value "login".');
-      screenType = 'login';
-    } else {
-      screenType = hash.substring(1);
+    // Extracting display type from URL.
+    var path = window.location.pathname.substr(1);
+    var displayType = DISPLAY_TYPE.UNKNOWN;
+    Object.getOwnPropertyNames(DISPLAY_TYPE).forEach(function(type) {
+      if (DISPLAY_TYPE[type] == path) {
+        displayType = path;
+      }
+    });
+    if (displayType == DISPLAY_TYPE.UNKNOWN) {
+      console.error("Unknown display type '" + path + "'. Setting default.");
+      displayType = DISPLAY_TYPE.LOGIN;
     }
-    document.documentElement.setAttribute('screen', screenType);
+    Oobe.getInstance().displayType = displayType;
+    document.documentElement.setAttribute('screen', displayType);
 
     var link = $('enterprise-info-hint-link');
     link.addEventListener(
diff --git a/chrome/browser/resources/chromeos/login/header_bar.js b/chrome/browser/resources/chromeos/login/header_bar.js
index fb8854e..82a04c4 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.js
+++ b/chrome/browser/resources/chromeos/login/header_bar.js
@@ -44,7 +44,8 @@
           this.handleSignoutClick_);
       $('cancel-multiple-sign-in-button').addEventListener('click',
           this.handleCancelMultipleSignInClick_);
-      if (document.documentElement.getAttribute('screen') == 'login')
+      if (Oobe.getInstance().displayType == DISPLAY_TYPE.LOGIN ||
+          Oobe.getInstance().displayType == DISPLAY_TYPE.OOBE)
         login.AppsMenuButton.decorate($('show-apps-button'));
     },
 
@@ -187,7 +188,8 @@
           (this.signinUIState_ == SIGNIN_UI_STATE.MANAGED_USER_CREATION_FLOW);
       var wrongHWIDWarningIsActive =
           (this.signinUIState_ == SIGNIN_UI_STATE.WRONG_HWID_WARNING);
-      var isMultiProfilesUI = Oobe.getInstance().isSignInToAddScreen();
+      var isMultiProfilesUI =
+          (Oobe.getInstance().displayType == DISPLAY_TYPE.USER_ADDING);
 
       $('add-user-button').hidden = !accountPickerIsActive || isMultiProfilesUI;
       $('cancel-add-user-button').hidden = accountPickerIsActive ||
diff --git a/chrome/browser/resources/chromeos/login/login.html b/chrome/browser/resources/chromeos/login/login.html
index c5bc486..6d30288 100644
--- a/chrome/browser/resources/chromeos/login/login.html
+++ b/chrome/browser/resources/chromeos/login/login.html
@@ -5,7 +5,7 @@
 <include src="login_resources.html">
 <script src="chrome://oobe/login.js"></script>
 </head>
-<body class="login-display" i18n-values=".style.fontFamily:fontfamily;">
+<body i18n-values=".style.fontFamily:fontfamily;">
   <include src="screen_container.html">
   <script src="chrome://resources/js/i18n_template2.js"></script>
 </body>
diff --git a/chrome/browser/resources/chromeos/login/login.js b/chrome/browser/resources/chromeos/login/login.js
index 65c7fe5..36a2fba 100644
--- a/chrome/browser/resources/chromeos/login/login.js
+++ b/chrome/browser/resources/chromeos/login/login.js
@@ -28,6 +28,7 @@
       login.PasswordChangedScreen.register();
       login.LocallyManagedUserCreationScreen.register();
       login.TermsOfServiceScreen.register();
+      login.AppLaunchSplashScreen.register();
 
       cr.ui.Bubble.decorate($('bubble'));
       login.HeaderBar.decorate($('login-header-bar'));
diff --git a/chrome/browser/resources/chromeos/login/login_common.js b/chrome/browser/resources/chromeos/login/login_common.js
index 4d490e1..273902c 100644
--- a/chrome/browser/resources/chromeos/login/login_common.js
+++ b/chrome/browser/resources/chromeos/login/login_common.js
@@ -19,6 +19,7 @@
 <include src="oobe_screen_terms_of_service.js"></include>
 <include src="oobe_screen_user_image.js"></include>
 <include src="screen_account_picker.js"></include>
+<include src="screen_app_launch_splash.js"></include>
 <include src="screen_error_message.js"></include>
 <include src="screen_gaia_signin.js"></include>
 <include src="screen_locally_managed_user_creation.js"></include>
@@ -77,9 +78,9 @@
    */
   Oobe.showOobeUI = function(showOobe) {
     if (showOobe) {
-      document.body.classList.remove('login-display');
+      document.body.classList.add('oobe-display');
     } else {
-      document.body.classList.add('login-display');
+      document.body.classList.remove('oobe-display');
       Oobe.getInstance().prepareForLoginDisplay_();
     }
 
@@ -224,32 +225,6 @@
   };
 
   /**
-   * Sets the domain name whose Terms of Service are being shown on the Terms of
-   * Service screen.
-   * @param {string} domain The domain name.
-   */
-  Oobe.setTermsOfServiceDomain = function(domain) {
-    login.TermsOfServiceScreen.setDomain(domain);
-  };
-
-  /**
-   * Displays an error message on the Terms of Service screen. Called when the
-   * download of the Terms of Service has failed.
-   */
-  Oobe.setTermsOfServiceLoadError = function() {
-    $('terms-of-service').classList.remove('tos-loading');
-    $('terms-of-service').classList.add('error');
-  };
-
-  /**
-   * Displays the given |termsOfService| on the Terms of Service screen.
-   * @param {string} termsOfService The terms of service, as plain text.
-   */
-  Oobe.setTermsOfService = function(termsOfService) {
-    login.TermsOfServiceScreen.setTermsOfService(termsOfService);
-  };
-
-  /**
    * Clears password field in user-pod.
    */
   Oobe.clearUserPodPassword = function() {
@@ -263,6 +238,17 @@
     DisplayManager.refocusCurrentPod();
   };
 
+  /**
+   * Login for autotests.
+   * @param {string} username Login username.
+   * @param {string} password Login password.
+   */
+  Oobe.loginForTesting = function(username, password) {
+    chrome.send('skipToLoginForTesting');
+    Oobe.showSigninUI(username);
+    chrome.send('completeLogin', [username, password]);
+  };
+
   // Export
   return {
     Oobe: Oobe
diff --git a/chrome/browser/resources/chromeos/login/login_resources.html b/chrome/browser/resources/chromeos/login/login_resources.html
index bbff064..6f4395b 100644
--- a/chrome/browser/resources/chromeos/login/login_resources.html
+++ b/chrome/browser/resources/chromeos/login/login_resources.html
@@ -20,6 +20,7 @@
 <link rel="stylesheet" href="oobe_screen_terms_of_service.css">
 <link rel="stylesheet" href="oobe_screen_update.css">
 <link rel="stylesheet" href="oobe_screen_user_image.css">
+<link rel="stylesheet" href="screen_app_launch_splash.css">
 <link rel="stylesheet" href="screen_container.css">
 <link rel="stylesheet" href="screen_account_picker.css">
 <link rel="stylesheet" href="screen_gaia_signin.css">
diff --git a/chrome/browser/resources/chromeos/login/login_screens.html b/chrome/browser/resources/chromeos/login/login_screens.html
index 481b039..6e13b61 100644
--- a/chrome/browser/resources/chromeos/login/login_screens.html
+++ b/chrome/browser/resources/chromeos/login/login_screens.html
@@ -10,3 +10,4 @@
 <include src="screen_password_changed.html">
 <include src="screen_tpm_error.html">
 <include src="screen_wrong_hwid.html">
+<include src="screen_app_launch_splash.html">
diff --git a/chrome/browser/resources/chromeos/login/oobe.css b/chrome/browser/resources/chromeos/login/oobe.css
index a898675..fea15a8 100644
--- a/chrome/browser/resources/chromeos/login/oobe.css
+++ b/chrome/browser/resources/chromeos/login/oobe.css
@@ -59,7 +59,7 @@
   box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15), inset 0 1px 2px
               rgba(255, 255, 255, 0.4);
   color: #fff;
-  font-size: 12px;
+  font-size: 14px;
   margin: 0 1px 0 0;
   min-height: 2em;
   min-width: 4em;
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js
index 7ad87e6..8af44f0 100644
--- a/chrome/browser/resources/chromeos/login/oobe.js
+++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -68,6 +68,7 @@
       login.PasswordChangedScreen.register();
       login.LocallyManagedUserCreationScreen.register();
       login.TermsOfServiceScreen.register();
+      login.AppLaunchSplashScreen.register();
 
       cr.ui.Bubble.decorate($('bubble'));
       login.HeaderBar.decorate($('login-header-bar'));
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen.css b/chrome/browser/resources/chromeos/login/oobe_screen.css
index 0872b5c..a06f8de 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen.css
+++ b/chrome/browser/resources/chromeos/login/oobe_screen.css
@@ -34,6 +34,14 @@
   -webkit-transform: translateX(-50px)
 }
 
+.step.fullscreen {
+  height: 100%;
+  left: 0;
+  right: 0;
+  top: 0;
+  width: 100%;
+}
+
 .step-controls {
   -webkit-box-pack: end;
   -webkit-padding-end: 34px;  /* Double the padding of .step */
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js b/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js
index 7fc313d..840a49b 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_terms_of_service.js
@@ -10,6 +10,7 @@
   function() { return {
     EXTERNAL_API: [
       'setDomain',
+      'setTermsOfServiceLoadError',
       'setTermsOfService'
     ],
 
@@ -28,6 +29,15 @@
     },
 
     /**
+     * Displays an error message on the Terms of Service screen. Called when the
+     * download of the Terms of Service has failed.
+     */
+    setTermsOfServiceLoadError: function() {
+      this.classList.remove('tos-loading');
+      this.classList.add('error');
+    },
+
+    /**
      * Displays the given |termsOfService|, enables the accept button and moves
      * the focus to it.
      * @param {string} termsOfService The terms of service, as plain text.
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css
index 94578bd..9c69a8f 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css
@@ -9,6 +9,11 @@
   width: 702px;
 }
 
+#user-image.loading {
+  min-height: 609px; /* Should be the same as #gaia-signin height. */
+  width: 722px; /* Should be the same as #gaia-signin width. */
+}
+
 #user-image-screen-curtain {
   -webkit-margin-start: 8px;
 }
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js
index 2785605..be2f1a8 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.js
@@ -199,7 +199,8 @@
       } else {
         $('ok-button').disabled = false;
         chrome.send('selectImage',
-                    [imageGrid.selectedItemUrl, imageGrid.selectionType]);
+                    [imageGrid.selectedItemUrl, imageGrid.selectionType,
+                     !imageGrid.inProgramSelection]);
       }
       // Start/stop camera on (de)selection.
       if (!imageGrid.inProgramSelection &&
@@ -384,7 +385,7 @@
         item.author = data.author || '';
         item.website = data.website || '';
       }
-      this.classList.remove('loading');
+      chrome.send('screenReady');
     },
 
     /**
@@ -399,6 +400,15 @@
     },
 
     /**
+     * Hides curtain with spinner.
+     * @private
+     */
+    hideCurtain_: function() {
+      this.classList.remove('loading');
+      Oobe.getInstance().updateScreenSize(this);
+    },
+
+    /**
      * Updates the image preview caption.
      * @private
      */
@@ -432,6 +442,7 @@
     'setProfilePictureEnabled',
     'setProfileImage',
     'setSelectedImage',
+    'hideCurtain'
   ].forEach(function(name) {
     UserImageScreen[name] = function(value) {
       $('user-image')[name + '_'](value);
diff --git a/chrome/browser/resources/chromeos/login/oobe_screens.html b/chrome/browser/resources/chromeos/login/oobe_screens.html
index 51845fa..f189bf6 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screens.html
+++ b/chrome/browser/resources/chromeos/login/oobe_screens.html
@@ -13,3 +13,4 @@
 <include src="screen_password_changed.html">
 <include src="screen_tpm_error.html">
 <include src="screen_wrong_hwid.html">
+<include src="screen_app_launch_splash.html">
diff --git a/chrome/browser/resources/chromeos/login/screen_app_launch_splash.css b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.css
new file mode 100644
index 0000000..535dc08
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.css
@@ -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.
+ */
+
+#app-launch-splash {
+  -webkit-box-align: center;
+  -webkit-box-pack: center;
+  background: white;
+  display: -webkit-box;
+}
+
+#splash-content {
+  -webkit-box-align: center;
+  -webkit-box-orient: vertical;
+  -webkit-box-pack: center;
+  display: -webkit-box;
+  position: relative;
+}
+
+#splash-header {
+  -webkit-padding-start: 108px;
+  background: left center no-repeat;
+  background-size: 96px;
+  color: #666;
+  display: -webkit-box;
+  font-size: 48px;
+  height: 96px;
+  line-height: 96px;
+}
+
+#splash-launch-text {
+  color: #666;
+  font-size: 18px;
+  padding-bottom: 50px;
+  padding-top: 50px;
+}
+
+#splash-spinner {
+  height: 32px;
+  width: 32px;
+}
+
+#splash-shortcut-info {
+  bottom: 50px;
+  color: gray;
+  left: 0;
+  position: absolute;
+  right: 0;
+  text-align: center;
+}
diff --git a/chrome/browser/resources/chromeos/login/screen_app_launch_splash.html b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.html
new file mode 100644
index 0000000..634301d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.html
@@ -0,0 +1,8 @@
+<div id="app-launch-splash" class="step hidden step-no-logo fullscreen">
+  <div id="splash-content">
+    <div id="splash-header" i18n-content="productName"></div>
+    <div id="splash-launch-text" i18n-content="appStartMessage"></div>
+    <div id="splash-spinner" class="spinner"></div>
+  </div>
+  <p id="splash-shortcut-info" i18n-content="shortcutInfo"></p>
+</div>
diff --git a/chrome/browser/resources/chromeos/login/screen_app_launch_splash.js b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.js
new file mode 100644
index 0000000..dfe4c2e
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screen_app_launch_splash.js
@@ -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.
+
+/**
+ * @fileoverview App install/launch splash screen implementation.
+ */
+
+login.createScreen('AppLaunchSplashScreen', 'app-launch-splash', function() {
+  return {
+    EXTERNAL_API: [
+      'toggleNetworkConfig',
+      'updateApp',
+      'updateMessage',
+    ],
+
+    /**
+     * Event handler that is invoked just before the frame is shown.
+     * @param {string} data Screen init payload.
+     */
+    onBeforeShow: function(data) {
+      this.updateApp(data['appInfo']);
+
+      $('splash-shortcut-info').hidden = !data['shortcutEnabled'];
+
+      Oobe.getInstance().headerHidden = true;
+    },
+
+    /**
+     * Event handler that is invoked just before the frame is hidden.
+     */
+    onBeforeHide: function() {
+    },
+
+    /**
+     * Toggles visibility of the network configuration option.
+     * @param {boolean} visible Whether to show the option.
+     */
+    toggleNetworkConfig: function(visible) {
+      // TODO(tengs): Implement network configuration in app launch.
+    },
+
+    /**
+     * Updates the app name and icon.
+     * @param {Object} app Details of app being launched.
+     */
+    updateApp: function(app) {
+      $('splash-header').textContent = app.name;
+      $('splash-header').style.backgroundImage = 'url(' + app.iconURL + ')';
+    },
+
+    /**
+     * Updates the message for the current launch state.
+     * @param {string} message Description for current launch state.
+     */
+    updateMessage: function(message) {
+      $('splash-launch-text').textContent = message;
+    }
+  };
+});
diff --git a/chrome/browser/resources/chromeos/login/screen_container.css b/chrome/browser/resources/chromeos/login/screen_container.css
index 9778b31..5461961 100644
--- a/chrome/browser/resources/chromeos/login/screen_container.css
+++ b/chrome/browser/resources/chromeos/login/screen_container.css
@@ -124,16 +124,23 @@
   opacity: 1;
 }
 
-body.login-display #inner-container {
+body:not(.oobe-display) #inner-container {
   height: 262px;
   padding: 0;
   width: 1100px;
 }
 
-body.login-display #progress-dots {
+body:not(.oobe-display) #progress-dots {
   display: none;
 }
 
+#outer-container.fullscreen,
+#outer-container.fullscreen #oobe,
+#outer-container.fullscreen #oobe #inner-container {
+  height: 100%;
+  width: 100%;
+}
+
 html[build=chrome] #header-sections {
   -webkit-margin-start: -48px;
 }
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.css b/chrome/browser/resources/chromeos/login/screen_gaia_signin.css
index af26cc3..08490bf 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.css
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.css
@@ -4,9 +4,9 @@
  */
 
 #gaia-signin {
-  height: 609px;
+  height: 609px; /* Should be the same as #user-image.loading min-heigth. */
   padding: 70px 17px 69px;    /* Screen has no controls. */
-  width: 722px;
+  width: 722px; /* Should be the same as #user-image.loading width. */
 }
 
 #gaia-signin.no-right-panel {
@@ -115,7 +115,12 @@
   margin-top: 16px;
 }
 
+#createManagedUserLogo img {
+  vertical-align: text-bottom;
+}
+
 #createManagedUserLinkPlaceholder,
 #createManagedUserNoManagerText {
   margin-top: 10px;
-}
\ No newline at end of file
+}
+
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 2d5bcde..021480e 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
@@ -32,6 +32,20 @@
 #managed-user-creation .below-marketing {
   font-size: 12px;
   line-height: 18px;
+  max-height: 184px;
+  overflow-x: auto;
+}
+
+.below-marketing::-webkit-scrollbar {
+  width: 8px;
+}
+
+.below-marketing::-webkit-scrollbar-track-piece {
+  background: #888
+}
+
+.below-marketing::-webkit-scrollbar-thumb {
+  background: #eee
 }
 
 #managed-user-creation .page-no-marketing {
@@ -45,9 +59,9 @@
   line-height: 24px;
 }
 
-#managed-user-creation-created-1 strong {
+.below-marketing strong {
   color: #000;
-  font-weight: normal;
+  font-weight: bold;
 }
 
 #managed-user-creation .page-title-explanation {
@@ -98,10 +112,20 @@
 }
 
 #managed-user-creation-created-1 .below-marketing {
-  margin: 55px 100px 0;
+  margin: 20px 40px 0;
 }
 
-#managed-user-creation-created-1-text-2,
+#managed-user-creation-created-1-text-1 {
+  max-width: 600px;
+  word-wrap: break-word;
+}
+
+#managed-user-creation-created-1-text-2 {
+  margin-top: 20px;
+  max-width: 600px;
+  word-wrap: break-word;
+}
+
 #managed-user-creation-created-1-text-3 {
   margin-top: 20px;
 }
@@ -116,6 +140,8 @@
   margin-top: 10px;
 }
 
+input.managed-user-creation-manager-password,
+#managed-user-creation-name,
 #managed-user-creation-password {
   padding: 4px 6px;
 }
@@ -203,11 +229,13 @@
 .manager-pod .managed-user-creation-manager-email {
   color: #666;
   font-size: small;
+  max-height: 16px;
 }
 
 .manager-pod .managed-user-creation-manager-name {
   color: #000;
   font-size: small;
+  max-height: 16px;
 }
 
 #managed-user-creation-status {
@@ -218,8 +246,17 @@
   color: rgb(207, 93, 70);
 }
 
+#managed-user-creation-status .spinner-wrapper {
+  -webkit-margin-start: 3px;
+  display: -webkit-inline-box;
+  margin-top: 3px;
+  vertical-align: top;
+}
+
 #managed-user-creation-status .id-text {
-  margin-top: 2px;
+  display: -webkit-inline-box;
+  margin-top: 1px;
+  vertical-align: baseline;
 }
 
 .manager-pod.focused {
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 41f5537..0d48b55 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
@@ -89,11 +89,9 @@
       <div class="below-marketing">
         <div>
           <div id="managed-user-creation-created-1-text-1"
-              class="page-title centred"></div>
-          <div id="managed-user-creation-created-1-text-2"
-              class="page-title centred"></div>
-          <div id="managed-user-creation-created-1-text-3"
-              class="page-title-explanation centred"></div>
+              class="page-title"></div>
+          <div id="managed-user-creation-created-1-text-2"></div>
+          <div id="managed-user-creation-created-1-text-3"></div>
         </div>
       </div>
     </div>
@@ -113,7 +111,9 @@
   </div>
   <div class="template-status-container status-container" hidden>
     <span class="id-text"></span>
-    <div class="id-spinner inline-spinner"></div>
+    <div class="spinner-wrapper">
+      <div class="id-spinner inline-spinner"></div>
+    </div>
   </div>
   <div id="managed-user-creation-manager-template" hidden
       class="manager-pod">
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 dfe83fc..e27102a 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
@@ -8,6 +8,7 @@
 
 login.createScreen('LocallyManagedUserCreationScreen',
                    'managed-user-creation', function() {
+  var MAX_NAME_LENGTH = 50;
   var UserImagesGrid = options.UserImagesGrid;
 
   var ManagerPod = cr.ui.define(function() {
@@ -866,10 +867,13 @@
       this.updateElementText_('created-1-text-1',
                               'createManagedUserCreated1Text1',
                               this.context_.managedName);
+      // TODO(antrim): Move wrapping with strong in grd file, and eliminate this
+      //call.
       this.updateElementText_('created-1-text-2',
                               'createManagedUserCreated1Text2',
-                              loadTimeData.getString('managementURL'),
-                              this.context_.managedName);
+                              this.wrapStrong(
+                                  loadTimeData.getString('managementURL')),
+                                  this.context_.managedName);
       this.updateElementText_('created-1-text-3',
                               'createManagedUserCreated1Text3',
                               managerDisplayId);
@@ -878,6 +882,12 @@
                               managerDisplayId);
     },
 
+    wrapStrong: function(original) {
+      if (original == undefined)
+        return original;
+      return '<strong>' + original + '</strong>';
+    },
+
     updateElementText_: function(localId, templateName) {
       var args = Array.prototype.slice.call(arguments);
       args.shift();
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.css b/chrome/browser/resources/chromeos/login/user_pod_row.css
index 04c6eda..1bf3e5e 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.css
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.css
@@ -14,8 +14,6 @@
   display: -webkit-box;
   max-height: 650px;
   overflow: visible;
-  position: relative;
-  z-index: 0;
 }
 
 podrow[ncolumns='4'] {
@@ -48,10 +46,8 @@
   display: inline-block;
   margin: 0 20px;
   padding: 10px 10px 3px;
-  position: relative;
   vertical-align: middle;
   width: 160px;
-  z-index: 0;
 }
 
 .pod .main-pane {
@@ -69,7 +65,6 @@
   /* Focused pod has the same size no matter how many pods. */
   -webkit-transform: scale(1.0) !important;
   cursor: default;
-  z-index: 1;
 }
 
 .pod .user-image {
@@ -282,7 +277,11 @@
 
 .action-box-menu-title-name {
   display: -webkit-box;
-  min-height: 23px;
+  height: 23px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  width: 180px;
 }
 
 .action-box-menu-title-email {
@@ -323,6 +322,13 @@
   width: 100%;
 }
 
+html[oobe=old] .pod.focused .action-box-area {
+  /* Track shifting of .user-image on pod focus. */
+  -webkit-transform: translateY(-1px);
+  -webkit-transition: -webkit-transform 140ms ease;
+  opacity: 1;
+}
+
 .signed-in-indicator {
   -webkit-transition: all 140ms ease;
   background: rgba(0, 0, 0, 0.5);
diff --git a/chrome/browser/resources/chromeos/login/user_pod_row.js b/chrome/browser/resources/chromeos/login/user_pod_row.js
index 85502c1..f9ac4dc 100644
--- a/chrome/browser/resources/chromeos/login/user_pod_row.js
+++ b/chrome/browser/resources/chromeos/login/user_pod_row.js
@@ -336,7 +336,7 @@
       this.nameElement.textContent = this.user_.displayName;
       this.signedInIndicatorElement.hidden = !this.user_.signedIn;
 
-      var needSignin = this.needGaiaSignin;
+      var needSignin = this.needSignin;
       this.passwordElement.hidden = needSignin;
       this.signinButtonElement.hidden = !needSignin;
 
@@ -381,15 +381,14 @@
     },
 
     /**
-     * Whether Gaia signin is required for this user.
+     * Whether signin is required for this user.
      */
-    get needGaiaSignin() {
-      // Gaia signin is performed if the user has an invalid oauth token and is
+    get needSignin() {
+      // Signin is performed if the user has an invalid oauth token and is
       // not currently signed in (i.e. not the lock screen).
-      // Locally managed users never require GAIA signin.
       return this.user.oauthTokenStatus != OAuthTokenStatus.VALID_OLD &&
           this.user.oauthTokenStatus != OAuthTokenStatus.VALID_NEW &&
-          !this.user.signedIn && !this.user.locallyManagedUser;
+          !this.user.signedIn;
     },
 
     /**
@@ -460,7 +459,7 @@
      * Focuses on input element.
      */
     focusInput: function() {
-      var needSignin = this.needGaiaSignin;
+      var needSignin = this.needSignin;
       this.signinButtonElement.hidden = !needSignin;
       this.passwordElement.hidden = needSignin;
 
@@ -476,7 +475,6 @@
      */
     activate: function() {
       if (!this.signinButtonElement.hidden) {
-        // Switch to Gaia signin.
         this.showSigninUI();
       } else if (!this.passwordElement.value) {
         return false;
@@ -489,11 +487,35 @@
       return true;
     },
 
+    showSupervisedUserSigninWarning: function() {
+      // Locally managed user token has been invalidated.
+      // Make sure that pod is focused i.e. "Sign in" button is seen.
+      this.parentNode.focusPod(this);
+
+      var error = document.createElement('div');
+      var messageDiv = document.createElement('div');
+      messageDiv.className = 'error-message-bubble';
+      messageDiv.textContent =
+          loadTimeData.getString('supervisedUserExpiredTokenWarning');
+      error.appendChild(messageDiv);
+
+      $('bubble').showContentForElement(
+          this.signinButtonElement,
+          cr.ui.Bubble.Attachment.TOP,
+          error,
+          this.signinButtonElement.offsetWidth / 2,
+          4);
+    },
+
     /**
      * Shows signin UI for this user.
      */
     showSigninUI: function() {
-      this.parentNode.showSigninUI(this.user.emailAddress);
+      if (this.user.locallyManagedUser) {
+        this.showSupervisedUserSigninWarning();
+      } else {
+        this.parentNode.showSigninUI(this.user.emailAddress);
+      }
     },
 
     /**
@@ -697,7 +719,7 @@
     },
 
     /** @override */
-    get needGaiaSignin() {
+    get needSignin() {
       return false;
     },
 
@@ -936,8 +958,8 @@
       // Event listeners that are installed for the time period during which
       // the element is visible.
       this.listeners_ = {
-        focus: [this.handleFocus_.bind(this), true],
-        click: [this.handleClick_.bind(this), false],
+        focus: [this.handleFocus_.bind(this), true /* useCapture */],
+        click: [this.handleClick_.bind(this), true],
         mousemove: [this.handleMouseMove_.bind(this), false],
         keydown: [this.handleKeyDown.bind(this), false]
       };
@@ -1201,6 +1223,7 @@
         podToFocus.classList.remove('faded');
         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(
@@ -1364,6 +1387,10 @@
         if (!pod)
           this.focusedPod_.isActionBoxMenuHovered = false;
       }
+
+      // Also stop event propagation.
+      if (pod && e.target == pod.imageElement)
+        e.stopPropagation();
     },
 
     /**
diff --git a/chrome/browser/resources/chromeos/network.css b/chrome/browser/resources/chromeos/network.css
new file mode 100644
index 0000000..0d68184
--- /dev/null
+++ b/chrome/browser/resources/chromeos/network.css
@@ -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.
+ */
+
+#log-level-container {
+  margin: 5px;
+}
+
+#log-level-container label {
+  vertical-align: middle;
+}
+
+#log-level-container input {
+  margin-bottom: 1px;
+  vertical-align: middle;
+}
+
+#network-log-container {
+  border: 1px solid rgb(220, 220, 220);
+  font-size: 12px;
+  height: 350px;
+  overflow: scroll;
+  padding: 10px;
+  width: 100%;
+}
+
+#network-log-container p {
+  font-family: monospace;
+  line-height: 20px;
+  margin: 2px;
+}
+
+#network-status-table {
+  border-collapse: collapse;
+}
+
+#network-status-table tr td {
+  border: 1px solid rgb(220, 220, 220);
+  font-size: 13px;
+}
+
+.network-status-table-header {
+  font-weight: bold;
+}
+
+.network-level-tag {
+  -webkit-margin-end: 5px;
+  border: 1px solid;
+  border-radius: 2px;
+  padding: 0 4px;
+}
+
+.network-log-level-event {
+  color: orange;
+}
+
+.network-log-level-error {
+  color: red;
+}
+
+.network-log-level-debug {
+  color: blue;
+}
diff --git a/chrome/browser/resources/chromeos/network.html b/chrome/browser/resources/chromeos/network.html
new file mode 100644
index 0000000..b991ce0
--- /dev/null
+++ b/chrome/browser/resources/chromeos/network.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection;">
+<head>
+  <meta charset="utf-8">
+  <title id="network" i18n-content="titleText"></title>
+  <link rel="stylesheet" href="chrome://network/network.css">
+  <script src="chrome://resources/js/load_time_data.js"></script>
+  <script src="chrome://resources/js/util.js"></script>
+  <script src="chrome://network/strings.js"></script>
+  <script src="chrome://network/network.js"></script>
+</head>
+<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+  <p i18n-content="autoRefreshText"></p>
+  <h3>Event Log (Newest first):</h3>
+  <div id="log-level-container">
+    <button id="log-refresh" i18n-content="logRefreshText"></button>
+    <label i18n-content="logLevelShowText"></label>
+    <input id="log-error" type="checkbox">
+    <label for="log-error" i18n-content="logLevelErrorText"></label>
+    <input id="log-user" type="checkbox">
+    <label for="log-user" i18n-content="logLevelUserText"></label>
+    <input id="log-event" type="checkbox">
+    <label for="log-event" i18n-content="logLevelEventText"></label>
+    <input id="log-debug" type="checkbox">
+    <label for="log-debug" i18n-content="logLevelDebugText"></label>
+  </div>
+  <div id="network-log-container">
+  </div>
+  <h3>Networks: </h3>
+  <table id="network-status-table">
+    <tr class="network-status-table-header">
+      <td>Name</td>
+      <td>Type</td>
+      <td>Status</td>
+      <td>Profile</td>
+      <td>Connect</td>
+      <td>Error</td>
+      <td>IP Addr</td>
+      <td>Security</td>
+      <td>Technology</td>
+      <td>Activation</td>
+      <td>Roaming</td>
+      <td>OOC</td>
+      <td>Strength</td>
+      <td>Auto</td>
+      <td>Fav</td>
+      <td>Pri</td>
+      <td>Path</td>
+    </tr>
+  </table>
+  <script src="chrome://resources/js/i18n_template2.js"></script>
+</body>
+</html>
diff --git a/chrome/browser/resources/chromeos/network.js b/chrome/browser/resources/chromeos/network.js
new file mode 100644
index 0000000..593c6eb
--- /dev/null
+++ b/chrome/browser/resources/chromeos/network.js
@@ -0,0 +1,172 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var NetworkUI = function() {
+  // Properties to display in the network state table
+  var NETWORK_STATE_FIELDS = ['Name', 'Type', 'State', 'Profile', 'Connectable',
+   'Error', 'ADdress', 'Security', 'Cellular.NetworkTechnology',
+   'Cellular.ActivationState', 'Cellular.RoamingState',
+   'Cellular.OutOfCredits', 'signalStrength', 'AutoConnect',
+   'Favorite', 'Priority'];
+
+  var LOG_LEVEL_CLASSNAME = {
+    'Error': 'network-log-level-error',
+    'User': 'network-log-level-user',
+    'Event': 'network-log-level-event',
+    'Debug': 'network-log-level-debug'
+  };
+
+  var LOG_LEVEL_CHECKBOX = {
+    'Error': 'log-error',
+    'User': 'log-user',
+    'Event': 'log-event',
+    'Debug': 'log-debug'
+  };
+
+  /**
+   * Create a tag of log level.
+   *
+   * @param {string} level A string that represents log level.
+   * @return {DOMElement} The created span element.
+   */
+  var createLevelTag = function(level) {
+    var tag = document.createElement('span');
+    tag.className = 'network-level-tag';
+    tag.textContent = level;
+    tag.classList.add(LOG_LEVEL_CLASSNAME[level]);
+    return tag;
+  };
+
+  /**
+   * Creates an element that contains the time, the event, the level and
+   * the description of the given log entry.
+   *
+   * @param {Object} logEntry An object that represents a single line of log.
+   * @return {DOMElement}  The created p element that represents the log entry.
+   */
+  var createLogEntryText = function(logEntry) {
+    var level = logEntry['level'];
+    if (!$(LOG_LEVEL_CHECKBOX[level]).checked)
+      return null;
+    var res = document.createElement('p');
+    var textWrapper = document.createElement('span');
+    textWrapper.textContent = loadTimeData.getStringF(
+      'logEntryFormat',
+      logEntry['timestamp'],
+      logEntry['event'],
+      logEntry['description']);
+    res.appendChild(createLevelTag(level));
+    res.appendChild(textWrapper);
+    return res;
+  };
+
+  /**
+   * Create event log entries.
+   *
+   * @param {Array.<string>} logEntries A array of strings that each string
+   *     represents a log event in JSON format.
+   */
+  var createEventLog = function(logEntries) {
+    var container = $('network-log-container');
+    container.textContent = '';
+    for (var i = 0; i < logEntries.length; ++i) {
+      var entry = createLogEntryText(JSON.parse(logEntries[i]));
+      if (entry)
+        container.appendChild(entry);
+    }
+  };
+
+  /**
+   * Create a cell in network state table.
+   *
+   * @param {string} value Content in the cell.
+   * @return {DOMElement} The created td element that displays the given value.
+   */
+  var createStatusTableCell = function(value) {
+    var col = document.createElement('td');
+    col.textContent = value || '';
+    return col;
+  };
+
+  /**
+   * Create a row in the network state table.
+   *
+   * @param {string} path The network path.
+   * @param {dictionary} status Properties of the network.
+   * @return {DOMElement} The created tr element that contains the network
+   *     state information.
+   */
+  var createStatusTableRow = function(path, status) {
+    var row = document.createElement('tr');
+    row.className = 'network-status-table-row';
+    for (var i = 0; i < NETWORK_STATE_FIELDS.length; ++i) {
+      row.appendChild(createStatusTableCell(status[NETWORK_STATE_FIELDS[i]]));
+    }
+    row.appendChild(createStatusTableCell(path));
+    return row;
+  };
+
+  /**
+   * Create network state table.
+   *
+   * @param {Array.<Object>} networkStatuses An array of network states.
+   */
+  var createNetworkTable = function(networkStatuses) {
+    var table = $('network-status-table');
+    var oldRows = table.querySelectorAll('.network-status-table-row');
+    for (var i = 0; i < oldRows.length; ++i)
+      table.removeChild(oldRows[i]);
+    for (var path in networkStatuses)
+      table.appendChild(
+          createStatusTableRow(path, networkStatuses[path]));
+  };
+
+  /**
+   * This callback function is triggered when the data is received.
+   *
+   * @param {dictionary} data A dictionary that contains network state
+   *     information.
+   */
+  var onNetworkInfoReceived = function(data) {
+    createEventLog(JSON.parse(data.networkEventLog));
+    createNetworkTable(data.networkState);
+  };
+
+  /**
+   * Sends a refresh request.
+   */
+  var sendRefresh = function() {
+    chrome.send('requestNetworkInfo');
+  }
+
+  /**
+   * Sets refresh rate if the interval is found in the url.
+   */
+  var setRefresh = function() {
+    var interval = parseQueryParams(window.location)['refresh'];
+    if (interval && interval != '')
+      setInterval(sendRefresh, parseInt(interval) * 1000);
+  };
+
+  /**
+   * Get network information from WebUI.
+   */
+  document.addEventListener('DOMContentLoaded', function() {
+    $('log-refresh').onclick = sendRefresh;
+    $('log-error').checked = true;
+    $('log-error').onclick = sendRefresh;
+    $('log-user').checked = true;
+    $('log-user').onclick = sendRefresh;
+    $('log-event').checked = true;
+    $('log-event').onclick = sendRefresh;
+    $('log-debug').checked = false;
+    $('log-debug').onclick = sendRefresh;
+    setRefresh();
+    sendRefresh();
+  });
+
+  return {
+    onNetworkInfoReceived: onNetworkInfoReceived
+  };
+}();
diff --git a/chrome/browser/resources/chromeos/sim_unlock.css b/chrome/browser/resources/chromeos/sim_unlock.css
index 8cd3220..d552feb 100644
--- a/chrome/browser/resources/chromeos/sim_unlock.css
+++ b/chrome/browser/resources/chromeos/sim_unlock.css
@@ -45,6 +45,10 @@
   margin-bottom: 0;
 }
 
+#puk-content-area {
+  max-height: 163px;
+}
+
 .code-input {
   -webkit-border-radius: 2px;
   border: 1px solid #aaa;
diff --git a/chrome/browser/resources/chromeos/sim_unlock.html b/chrome/browser/resources/chromeos/sim_unlock.html
index aa53ce6..9cd54d6 100644
--- a/chrome/browser/resources/chromeos/sim_unlock.html
+++ b/chrome/browser/resources/chromeos/sim_unlock.html
@@ -63,7 +63,7 @@
         </div>
         <div id="puk-enter-msg" i18n-content="enterPukMessage"></div>
         <div id="puk-input-area" class="input-area">
-          <input id="puk-input" class="code-input" type="text"
+          <input id="puk-input" class="code-input" type="password"
               maxlength="8" size="14">
         </div>
       </div>
diff --git a/chrome/browser/resources/chromeos/sim_unlock.js b/chrome/browser/resources/chromeos/sim_unlock.js
index 92033c8..c77ccbd 100644
--- a/chrome/browser/resources/chromeos/sim_unlock.js
+++ b/chrome/browser/resources/chromeos/sim_unlock.js
@@ -41,6 +41,10 @@
     initialized_: false,
     mode_: SimUnlock.SIM_DIALOG_UNLOCK,
     pukValue_: '',
+    defaultDialogSize_: {
+      'width': window.innerWidth,
+      'height': window.innerHeight
+    },
     state_: SimUnlock.SIM_UNLOCK_LOADING,
 
     changeState_: function(simInfo) {
@@ -117,6 +121,9 @@
           $('enter-puk-confirm').disabled = true;
           $('locked-puk-overlay').hidden = false;
           $('puk-input').focus();
+
+          // Resize the dialog to accomodate the PUK contents.
+          this.updateDialogSize_(0, 45);
           break;
         case SimUnlock.SIM_LOCKED_NO_PUK_TRIES_LEFT:
           $('locked-puk-no-tries-overlay').hidden = false;
@@ -136,6 +143,11 @@
       return this.state_;
     },
 
+    updateDialogSize_: function(deltaX, deltaY) {
+      window.resizeTo(this.defaultDialogSize_.width + deltaX,
+                      this.defaultDialogSize_.height + deltaY);
+    },
+
     hideAll_: function() {
       $('locked-pin-overlay').hidden = true;
       $('locked-pin-no-tries-overlay').hidden = true;
@@ -186,6 +198,7 @@
       $('retype-new-pin-input').value = '';
       $('choose-pin-overlay').hidden = false;
       $('new-pin-input').focus();
+      this.updateDialogSize_(0, 18);
     },
 
     updateSimStatus_: function(simInfo) {
diff --git a/chrome/browser/resources/chromeos/speech_synthesis/manifest.json b/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
index a756710..26cce46 100644
--- a/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
+++ b/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
@@ -11,6 +11,7 @@
       "voice_data_hmm_es-ES.js",
       "voice_data_hmm_fr-FR.js",
       "voice_data_hmm_it-IT.js",
+      "tts_controller.js",
       "tts_main.js"
     ]
   },
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 659f13e..cba4ccc 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -43,6 +43,12 @@
         <include name="IDR_BACKLOADER_BACKGROUND_JS" file="backloader/scripts/background.js" type="BINDATA" />
         <include name="IDR_BACKLOADER_PAGES_JS" file="backloader/scripts/pages.js" type="BINDATA" />
       </if>
+      <include name="IDR_FEEDBACK_DEFAULT_HTML" file="feedback/html/default.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
+      <include name="IDR_FEEDBACK_EVENT_HANDLER_JS" file="feedback/js/event_handler.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_FEEDBACK_FEEDBACK_JS" file="feedback/js/feedback.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_FEEDBACK_TAKE_SCREENSHOT_JS" file="feedback/js/take_screenshot.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_FEEDBACK_TOPBAR_HANDLER_JS" file="feedback/js/topbar_handlers.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_FEEDBACK_FEEDBACK_CSS" file="feedback/css/feedback.css" type="BINDATA" />
       <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" />
@@ -90,6 +96,7 @@
         <include name="IDR_FILE_MANAGER_ICON_96" file="file_manager/images/icon96.png" type="BINDATA" />
         <include name="IDR_FILE_MANAGER_ICON_128" file="file_manager/images/icon128.png" type="BINDATA" />
         <include name="IDR_FILE_MANAGER_ICON_256" file="file_manager/images/icon256.png" type="BINDATA" />
+        <include name="IDR_FILE_MANAGER_AUDIO_PLAYER_ICON_2X" file="file_manager/images/media/2x/audio_player.png" type="BINDATA" />
 
         <!-- Resources used for non-flattened HTML files. -->
         <include name="IDR_FILE_MANAGER_DRIVE_WELCOME_STYLE" file="file_manager/css/drive_welcome.css" type="BINDATA" />
diff --git a/chrome/browser/resources/components.css b/chrome/browser/resources/components.css
new file mode 100644
index 0000000..d7b475a
--- /dev/null
+++ b/chrome/browser/resources/components.css
@@ -0,0 +1,264 @@
+/* Copyright 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+body {
+  margin: 10px;
+  min-width: 47em;
+}
+
+a {
+  color: blue;
+  font-size: 103%;
+}
+
+#header {
+  -webkit-padding-start: 0;
+  box-sizing: border-box;
+  margin-bottom: 1.05em;
+  /* 67px is the height of the header's background image. */
+  min-height: 67px;
+  overflow: hidden;
+  padding-bottom: 20px;
+  padding-top: 20px;
+  position: relative;
+}
+
+#header > h1 {
+  background: -webkit-image-set(
+      url('../../app/theme/default_100_percent/extensions_section.png') 1x,
+      url('../../app/theme/default_200_percent/extensions_section.png') 2x)
+      0 20px no-repeat;
+  display: inline;
+  margin: 0;
+  padding-bottom: 40px;
+  padding-left: 75px;
+  padding-top: 40px;
+}
+
+html[dir=rtl] #header > h1 {
+  background: -webkit-image-set(
+      url('../../app/theme/default_100_percent/extensions_section.png') 1x,
+      url('../../app/theme/default_200_percent/extensions_section.png') 2x)
+      right no-repeat;
+  padding-left: 0;
+  padding-right: 95px;
+}
+
+h1 {
+  font-size: 156%;
+  font-weight: bold;
+  margin: 0;
+  padding: 0;
+}
+
+#disabled-container {
+  font-size: 120%;
+  padding-bottom: 1.5em;
+}
+
+#disabled-header {
+  color: red;
+  font-weight: bold;
+}
+
+.content {
+  font-size: 88%;
+  margin-top: 5px;
+}
+
+.section-header {
+  -webkit-padding-start: 5px;
+  background: rgb(235, 239, 249);
+  border-top: 1px solid rgb(181, 199, 222);
+  font-size: 99%;
+  padding-bottom: 2px;
+  padding-top: 3px;
+  width: 100%;
+}
+
+.section-header > table tr td:first-child {
+  width: 100%;
+}
+
+.section-header > table tr {
+  vertical-align: center;
+}
+
+.section-header > table {
+  width: 100%;
+  border-collapse:collapse
+}
+
+.section-header-title {
+  font-weight: bold;
+}
+
+.vbox-container {
+  -webkit-box-orient: vertical;
+  display: -webkit-box;
+}
+
+.wbox {
+  -webkit-box-align: stretch;
+  -webkit-box-flex: 1;
+  display: -webkit-box;
+}
+
+#top {
+  -webkit-padding-end: 5px;
+}
+
+.show-in-tmi-mode {
+  overflow: hidden;
+}
+
+body.hide-tmi-mode-initial .show-in-tmi-mode {
+  height: 0 !important;
+  opacity: 0;
+}
+
+body.hide-tmi-mode .show-in-tmi-mode {
+  -webkit-transition: all 100ms ease-out;
+  height: 0 !important;
+  opacity: 0;
+}
+
+body.show-tmi-mode-initial .show-in-tmi-mode {
+  opacity: 1;
+}
+
+body.show-tmi-mode .show-in-tmi-mode {
+  -webkit-transition: all 100ms ease-in;
+  opacity: 1;
+}
+
+.wbox-tmi-mode {
+  -webkit-box-align: stretch;
+  -webkit-box-flex: 1;
+}
+
+.tmi-mode-image {
+  margin-top: 2px;
+  padding-left: 5px;
+  padding-right: 5px;
+}
+
+.tmi-mode-link {
+  margin-right: 3px;
+  white-space: nowrap;
+}
+
+.tmi-mode-link a {
+  font-size: 97%;
+}
+
+.tmi-mode {
+  -webkit-padding-start: 10px;
+  background: rgb(244, 246, 252);
+  border-bottom: 1px solid rgb(237, 239, 245);
+  font-size: 89%;
+  padding-bottom: 0.8em;
+  padding-top: 0.8em;
+  width: 100%;
+}
+
+.component-disabled {
+  background-color: #f0f0f0;
+  color: #a0a0a0;
+}
+
+.component > tr > td {
+  padding-bottom: 4px;
+  padding-top: 5px;
+  vertical-align: top;
+}
+
+.component > table {
+  width: 100%;
+  border-collapse:collapse
+}
+
+.plugin-file {
+  padding-bottom: 5px;
+  padding-top: 5px;
+}
+
+.component {
+  border-bottom: 1px solid #cdcdcd;
+}
+
+.critical {
+  color: red;
+}
+
+/* Indent the text related to each plug-in. */
+.component-text {
+  -webkit-padding-start: 5px;
+}
+
+.component-name {
+  font-weight: bold;
+}
+
+.no-components {
+  font-size: 1.2em;
+  margin: 6em 0 0;
+  text-align: center;
+}
+
+/* Use tables for layout, so eliminate extra spacing. */
+.plugin-details table {
+  -webkit-border-horizontal-spacing: 0;
+  -webkit-border-vertical-spacing: 0;
+}
+
+.plugin-details {
+  -webkit-padding-start: 1em;
+}
+
+/* Separate the inital line, Description, Location, and MIME Types lines. */
+.plugin-details > div {
+  padding-top: 0.1em
+}
+
+/* Align rows of tables along the top. */
+.plugin-details tr {
+  vertical-align: top;
+}
+
+/* Separate columns by 1em for the most part. */
+.plugin-details td+td {
+  -webkit-padding-start: 1em;
+}
+
+/* Make the MIME Types tables smaller. */
+.plugin-details .mime-types {
+  font-size: 95%;
+}
+
+/* Separate the header from the contents in each MIME Types table. */
+.plugin-details .mime-types .header td {
+  border-bottom: 1px solid black;
+  padding-bottom: 0.1em;
+}
+
+/* Separate the columns for tables used for horizontal listings only a bit. */
+.hlisting td+td {
+  -webkit-padding-start: 0.4em;
+}
+
+/* Match the indentation of .plugin-text. */
+.component-actions {
+  -webkit-padding-start: 5px;
+  margin-bottom: 0.2em;
+  margin-top: 0.2em;
+}
+
+.always-allow {
+  -webkit-margin-start: 30px;
+}
+
+button {
+  font-size: 104%;
+}
diff --git a/chrome/browser/resources/components.html b/chrome/browser/resources/components.html
new file mode 100644
index 0000000..9d79099
--- /dev/null
+++ b/chrome/browser/resources/components.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection;">
+<head>
+<meta charset="utf-8">
+<title i18n-content="componentsTitle"></title>
+<link rel="stylesheet" href="components.css">
+<if expr="pp_ifdef('chromeos')">
+  <link rel="stylesheet"
+      href="chrome://resources/css/chromeos/ui_account_tweaks.css">
+</if>
+</head>
+<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+<div id="body-container" style="visibility:hidden">
+
+  <div id="header"><h1 i18n-content="componentsTitle">TITLE</h1></div>
+
+  <div id="componentTemplate">
+
+    <div id="container" class="vbox-container">
+    <div id="top" class="wbox">
+
+      <div class="section-header">
+        <table><tr>
+          <td>
+            <span class="section-header-title" i18n-content="componentsTitle"
+              >TITLE</span>
+            <span class="section-header-title"
+                  jsdisplay="components.length > 0">(<span
+                  jscontent="components.length"></span>)</span>
+          </td>
+        </tr></table>
+      </div>
+
+    </div>
+    </div>
+
+    <div class="content">
+      <div class="component-name no-components" jsdisplay="components.length === 0">
+        <div i18n-content="noComponents">NO_COMPONENTS_ARE_INSTALLED</div>
+      </div>
+
+      <div jsdisplay="components.length > 0">
+        <div class="component"
+             jsselect="components">
+          <table>
+          <tr class='component-enabled'>
+          <td>
+            <div class="component-text">
+              <div>
+                <span class="component-name" dir="ltr"
+                      jscontent="name">NAME</span>
+                <span>
+                  - <span i18n-content="componentVersion">VERSION</span>
+                    <span dir="ltr" jscontent="version">x.x.x.x</span>
+                </span>
+              </div>
+              <div class="component-actions" guest-visibility="disabled">
+                <button class="button-check-update" jsvalues=".id:id"
+                        i18n-content="checkUpdate">
+                   CHECK_UPDATE
+                </button>
+              </div>
+            </div>
+          </td>
+          </tr>
+          </table>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<script src="chrome://resources/js/util.js"></script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://components/components.js"></script>
+<if expr="pp_ifdef('chromeos')">
+  <script src="chrome://resources/js/chromeos/ui_account_tweaks.js"></script>
+</if>
+
+<script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/jstemplate_compiled.js"></script>
+<script src="chrome://components/strings.js"></script>
+<script src="chrome://resources/js/i18n_template2.js"></script>
+</body>
+</html>
diff --git a/chrome/browser/resources/components.js b/chrome/browser/resources/components.js
new file mode 100644
index 0000000..8753e31
--- /dev/null
+++ b/chrome/browser/resources/components.js
@@ -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.
+
+'use strict';
+
+/**
+ * Takes the |componentsData| input argument which represents data about the
+ * currently installed components and populates the html jstemplate with
+ * that data. It expects an object structure like the above.
+ * @param {Object} componentsData Detailed info about installed components.
+ *      Same expected format as returnComponentsData().
+ */
+function renderTemplate(componentsData) {
+  // This is the javascript code that processes the template:
+  var input = new JsEvalContext(componentsData);
+  var output = $('componentTemplate');
+  jstProcess(input, output);
+}
+
+/**
+ * Asks the C++ ComponentsDOMHandler to get details about the installed
+ * components.
+ * The ComponentsDOMHandler should reply to returnComponentsData() (below).
+ */
+function requestComponentsData() {
+  chrome.send('requestComponentsData');
+}
+
+/**
+ * Called by the WebUI to re-populate the page with data representing the
+ * current state of installed components.
+ * @param {Object} componentsData Detailed info about installed components. The
+ *     template expects each component's format to match the following
+ *     structure to correctly populate the page:
+ *   {
+ *     components: [
+ *       {
+ *          name: 'Component1',
+ *          version: '1.2.3',
+ *       },
+ *       {
+ *          name: 'Component2',
+ *          version: '4.5.6',
+ *       },
+ *     ]
+ *   }
+ */
+function returnComponentsData(componentsData) {
+  var bodyContainer = $('body-container');
+  var body = document.body;
+
+  bodyContainer.style.visibility = 'hidden';
+  body.className = '';
+
+  renderTemplate(componentsData);
+
+  // Add handlers to dynamically created HTML elements.
+  var links = document.getElementsByClassName('button-check-update');
+  for (var i = 0; i < links.length; i++) {
+    links[i].onclick = function(e) {
+      handleCheckUpdate(this);
+      e.preventDefault();
+    };
+  }
+
+  // Disable some controls for Guest in ChromeOS.
+  if (cr.isChromeOS)
+    uiAccountTweaks.UIAccountTweaks.applyGuestModeVisibility(document);
+
+  bodyContainer.style.visibility = 'visible';
+  body.className = 'show-tmi-mode-initial';
+}
+
+/**
+ * Handles an 'enable' or 'disable' button getting clicked.
+ * @param {HTMLElement} node The HTML element representing the component
+ *     being checked for update.
+ */
+function handleCheckUpdate(node) {
+  node.disabled = true;
+  // Tell the C++ ComponentssDOMHandler to check for update.
+  chrome.send('checkUpdate', [String(node.id)]);
+}
+
+// Get data and have it displayed upon loading.
+document.addEventListener('DOMContentLoaded', requestComponentsData);
+
+// Add handlers to static HTML elements.
+$('button-check-update').onclick = handleCheckUpdate;
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.js b/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.js
index 71f6b5b..89c628b 100644
--- a/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.js
+++ b/chrome/browser/resources/extensions/chromeos/kiosk_app_disable_bailout_confirm.js
@@ -26,7 +26,7 @@
       el.addEventListener('change', this.handleDisableBailoutShortcutChange_);
 
       $('kiosk-disable-bailout-confirm-button').onclick = function(e) {
-        ExtensionSettings.showOverlay($('kiosk-apps-page'));
+        extensions.ExtensionSettings.showOverlay($('kiosk-apps-page'));
         chrome.send('setDisableBailoutShortcut', [true]);
       };
       $('kiosk-disable-bailout-cancel-button').onclick = this.handleCancel;
@@ -34,7 +34,7 @@
 
     /** Handles overlay being canceled. */
     handleCancel: function() {
-      ExtensionSettings.showOverlay($('kiosk-apps-page'));
+      extensions.ExtensionSettings.showOverlay($('kiosk-apps-page'));
       $('kiosk-disable-bailout-shortcut').checked = false;
     },
 
@@ -52,7 +52,8 @@
       }
 
       // Otherwise, show the confirmation overlay.
-      ExtensionSettings.showOverlay($('kiosk-disable-bailout-confirm-overlay'));
+      extensions.ExtensionSettings.showOverlay($(
+          'kiosk-disable-bailout-confirm-overlay'));
       return true;
     }
   };
diff --git a/chrome/browser/resources/extensions/chromeos/kiosk_apps.js b/chrome/browser/resources/extensions/chromeos/kiosk_apps.js
index 14fdc0c..0a7f0f6 100644
--- a/chrome/browser/resources/extensions/chromeos/kiosk_apps.js
+++ b/chrome/browser/resources/extensions/chromeos/kiosk_apps.js
@@ -81,7 +81,7 @@
      * @private
      */
     handleDismiss_: function() {
-      ExtensionSettings.showOverlay(null);
+      extensions.ExtensionSettings.showOverlay(null);
     }
   };
 
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.html b/chrome/browser/resources/extensions/extension_commands_overlay.html
index ee2c9e6..8bd0af6 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.html
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.html
@@ -3,7 +3,7 @@
  * Use of this source code is governed by a BSD-style license that can be found
  * in the LICENSE file.
 -->
-<div id="extensionCommandsOverlay" class="page">
+<div id="extension-commands-overlay" class="page">
   <div class="close-button"></div>
   <h1 i18n-content="extensionCommandsOverlay"></h1>
   <div class="content-area">
@@ -17,7 +17,7 @@
   <div class="action-area">
     <div class="action-area-right">
       <div class="button-strip">
-        <button id="extensionCommandsDismiss" i18n-content="ok"></button>
+        <button id="extension-commands-dismiss" i18n-content="ok"></button>
       </div>
     </div>
   </div>
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.js b/chrome/browser/resources/extensions/extension_commands_overlay.js
index d984be5..db02bff 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.js
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.js
@@ -31,7 +31,7 @@
       cr.ui.overlay.globalInitialization();
       overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
 
-      $('extensionCommandsDismiss').addEventListener('click',
+      $('extension-commands-dismiss').addEventListener('click',
           this.handleDismiss_.bind(this));
 
       // This will request the data to show on the page and will get a response
@@ -44,7 +44,7 @@
      * @param {Event} e The click event.
      */
     handleDismiss_: function(e) {
-      ExtensionSettings.showOverlay(null);
+      extensions.ExtensionSettings.showOverlay(null);
     },
   };
 
@@ -75,6 +75,3 @@
     ExtensionCommandsOverlay: ExtensionCommandsOverlay
   };
 });
-
-// Update the C++ call so this isn't necessary.
-var ExtensionCommandsOverlay = extensions.ExtensionCommandsOverlay;
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
index 0e0f694..59f5d00 100644
--- a/chrome/browser/resources/extensions/extension_list.js
+++ b/chrome/browser/resources/extensions/extension_list.js
@@ -287,7 +287,9 @@
         var link = activeViews.querySelector('a');
 
         extension.views.forEach(function(view, i) {
-          var label = view.path +
+          var displayName = view.generatedBackgroundPage ?
+              loadTimeData.getString('backgroundPage') : view.path;
+          var label = displayName +
               (view.incognito ?
                   ' ' + loadTimeData.getString('viewIncognito') : '') +
               (view.renderProcessId == -1 ?
@@ -327,7 +329,7 @@
         var list = panel.querySelector('ul');
         extension.installWarnings.forEach(function(warning) {
           var li = document.createElement('li');
-          li[warning.isHTML ? 'innerHTML' : 'innerText'] = warning.message;
+          li.innerText = warning.message;
           list.appendChild(li);
         });
       }
diff --git a/chrome/browser/resources/extensions/extensions.css b/chrome/browser/resources/extensions/extensions.css
index 579fdaa..98bbdfe 100644
--- a/chrome/browser/resources/extensions/extensions.css
+++ b/chrome/browser/resources/extensions/extensions.css
@@ -2,6 +2,18 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+html,
+body {
+  height: 100%;
+  overflow: hidden;
+}
+
+@media print {
+  body {
+    height: auto;
+  }
+}
+
 html.loading * {
   -webkit-transition-duration: 0 !important;
 }
@@ -90,6 +102,11 @@
 
 /* Contents */
 
+#page-container {
+  height: 100%;
+  overflow-y: auto;
+}
+
 #extension-settings {
   max-width: 738px;
 }
@@ -267,13 +284,13 @@
   display: none;
 }
 
-#dropTargetOverlay {
+#drop-target-overlay {
   color: rgb(48, 57, 66);
   font-size: 18px;
   text-align: center;
 }
 
-#dropTargetOverlay div {
+#drop-target-overlay div {
   margin: 1em;
 }
 
diff --git a/chrome/browser/resources/extensions/extensions.html b/chrome/browser/resources/extensions/extensions.html
index b6ff0f0..a381365 100644
--- a/chrome/browser/resources/extensions/extensions.html
+++ b/chrome/browser/resources/extensions/extensions.html
@@ -49,65 +49,67 @@
     <include src="chromeos/kiosk_apps.html">
     <include src="chromeos/kiosk_app_disable_bailout_confirm.html">
 </if>
-  <div id="dropTargetOverlay" class="page">
+  <div id="drop-target-overlay" class="page">
     <div i18n-content="extensionSettingsInstallDropTarget"></div>
   </div>
 </div>
 
-<div class="page" id="extension-settings">
-  <header id="page-header"><h1 i18n-content="extensionSettings"></h1>
-    <div id="header-controls" class="header-extras">
-      <div id="dev-toggle" class="checkbox">
-        <label>
-          <input id="toggle-dev-on" type="checkbox">
-          <span i18n-content="extensionSettingsDeveloperMode">
-        </label>
+<div id="page-container">
+  <div class="page" id="extension-settings">
+    <header id="page-header"><h1 i18n-content="extensionSettings"></h1>
+      <div id="header-controls" class="header-extras">
+        <div id="dev-toggle" class="checkbox">
+          <label>
+            <input id="toggle-dev-on" type="checkbox">
+            <span i18n-content="extensionSettingsDeveloperMode"></span>
+          </label>
+        </div>
       </div>
-    </div>
-    <div class="page-banner profile-is-managed-banner">
-      <div class="page-banner-gradient">
-        <span class="page-banner-text"
-            i18n-content="extensionSettingsManagedMode"></span>
+      <div class="page-banner profile-is-managed-banner">
+        <div class="page-banner-gradient">
+          <span class="page-banner-text"
+              i18n-content="extensionSettingsManagedMode"></span>
+        </div>
       </div>
-    </div>
-  </header>
-  <div id="dev-controls" hidden>
-    <div id="apps-dev-tool-banner">
-      <div class="apps-dev-tool-banner-text"
-          i18n-content="extensionSettingsUseAppsDevTools"></div>
-      <button id="open-apps-dev-tools"
-          i18n-content="extensionSettingsOpenAppsDevTools"></button>
-    </div>
-    <div class="buttons-container">
-      <button id="load-unpacked"
-          i18n-content="extensionSettingsLoadUnpackedButton"></button>
-      <button id="pack-extension"
-          i18n-content="extensionSettingsPackButton"></button>
+    </header>
+    <div id="dev-controls" hidden>
+      <div id="apps-dev-tool-banner">
+        <div class="apps-dev-tool-banner-text"
+            i18n-content="extensionSettingsUseAppsDevTools"></div>
+        <button id="open-apps-dev-tools"
+            i18n-content="extensionSettingsOpenAppsDevTools"></button>
+      </div>
+      <div class="buttons-container">
+        <button id="load-unpacked"
+            i18n-content="extensionSettingsLoadUnpackedButton"></button>
+        <button id="pack-extension"
+            i18n-content="extensionSettingsPackButton"></button>
 <if expr="pp_ifdef('chromeos')">
-      <button id="add-kiosk-app"
-          i18n-content="addKioskAppButton" hidden></button>
+        <button id="add-kiosk-app"
+            i18n-content="addKioskAppButton" hidden></button>
 </if>
-      <div id="dev-controls-spacer"></div>
-      <button id="update-extensions-now"
-          i18n-content="extensionSettingsUpdateButton"></button>
+        <div id="dev-controls-spacer"></div>
+        <button id="update-extensions-now"
+            i18n-content="extensionSettingsUpdateButton"></button>
+      </div>
     </div>
-  </div>
-  <div id="extension-settings-list" class="empty-extension-list"></div>
-  <div id="no-extensions">
-    <span id="no-extensions-message"
-        i18n-content="extensionSettingsNoExtensions"></span>
-    <span id="suggest-gallery" class="more-extensions-link"
-        i18n-values=".innerHTML:extensionSettingsSuggestGallery">
-    </span>
-  </div>
-  <div id="footer-section">
-    <a target="_blank" class="more-extensions-link"
-        i18n-values="href:extensionSettingsGetMoreExtensionsUrl"
-        i18n-content="extensionSettingsGetMoreExtensions"></a>
-    <a target="_blank" hidden
-        class="extension-commands-config"
-        i18n-content="extensionSettingsCommandsLink"
-        href="#"></a>
+    <div id="extension-settings-list" class="empty-extension-list"></div>
+    <div id="no-extensions">
+      <span id="no-extensions-message"
+          i18n-content="extensionSettingsNoExtensions"></span>
+      <span id="suggest-gallery" class="more-extensions-link"
+          i18n-values=".innerHTML:extensionSettingsSuggestGallery">
+      </span>
+    </div>
+    <div id="footer-section">
+      <a target="_blank" class="more-extensions-link"
+          i18n-values="href:extensionSettingsGetMoreExtensionsUrl"
+          i18n-content="extensionSettingsGetMoreExtensions"></a>
+      <a target="_blank" hidden
+          class="extension-commands-config"
+          i18n-content="extensionSettingsCommandsLink"
+          href="#"></a>
+    </div>
   </div>
 </div>
 
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js
index f07af56..b1d5a57 100644
--- a/chrome/browser/resources/extensions/extensions.js
+++ b/chrome/browser/resources/extensions/extensions.js
@@ -34,7 +34,7 @@
     doDragEnter: function() {
       chrome.send('startDrag');
       ExtensionSettings.showOverlay(null);
-      ExtensionSettings.showOverlay($('dropTargetOverlay'));
+      ExtensionSettings.showOverlay($('drop-target-overlay'));
     },
     /** @override */
     doDragLeave: function() {
@@ -146,7 +146,7 @@
         extensions.KioskDisableBailoutConfirm.getInstance().initialize();
       }
 
-      cr.ui.overlay.setupOverlay($('dropTargetOverlay'));
+      cr.ui.overlay.setupOverlay($('drop-target-overlay'));
       cr.ui.overlay.globalInitialization();
 
       extensions.ExtensionFocusManager.getInstance().initialize();
@@ -177,7 +177,7 @@
      * @private
      */
     handlePackExtension_: function(e) {
-      ExtensionSettings.showOverlay($('packExtensionOverlay'));
+      ExtensionSettings.showOverlay($('pack-extension-overlay'));
       chrome.send('metricsHandler:recordAction', ['Options_PackExtension']);
     },
 
@@ -187,7 +187,7 @@
      * @private
      */
     showExtensionCommandsConfigUi_: function(e) {
-      ExtensionSettings.showOverlay($('extensionCommandsOverlay'));
+      ExtensionSettings.showOverlay($('extension-commands-overlay'));
       chrome.send('metricsHandler:recordAction',
                   ['Options_ExtensionCommands']);
     },
@@ -409,8 +409,6 @@
   };
 });
 
-var ExtensionSettings = extensions.ExtensionSettings;
-
 window.addEventListener('load', function(e) {
-  ExtensionSettings.getInstance().initialize();
+  extensions.ExtensionSettings.getInstance().initialize();
 });
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.html b/chrome/browser/resources/extensions/pack_extension_overlay.html
index e83d4a5..a7794bd 100644
--- a/chrome/browser/resources/extensions/pack_extension_overlay.html
+++ b/chrome/browser/resources/extensions/pack_extension_overlay.html
@@ -1,28 +1,30 @@
-<div id="packExtensionOverlay" class="page">
+<div id="pack-extension-overlay" class="page">
   <h1 i18n-content="packExtensionOverlay"></h1>
   <div id="cbd-content-area" class="content-area">
     <div class="pack-extension-heading" i18n-content="packExtensionHeading">
     </div>
     <div class="pack-extension-text-boxes">
-      <label i18n-content="packExtensionRootDir" for="extensionRootDir"></label>
-      <input class="pack-extension-text-area" id="extensionRootDir" type="text">
-      <button id="browseExtensionDir"
+      <label i18n-content="packExtensionRootDir"
+             for="extension-root-dir"></label>
+      <input class="pack-extension-text-area"
+             id="extension-root-dir" type="text">
+      <button id="browse-extension-dir"
               i18n-content="packExtensionBrowseButton"></button>
     </div>
     <div class="pack-extension-text-boxes">
-      <label i18n-content="packExtensionPrivateKey" for="extensionPrivateKey">
+      <label i18n-content="packExtensionPrivateKey" for="extension-private-key">
       </label>
       <input class="pack-extension-text-area"
-             id="extensionPrivateKey" type="text">
-      <button id="browsePrivateKey"
+             id="extension-private-key" type="text">
+      <button id="browse-private-key"
               i18n-content="packExtensionBrowseButton"></button>
     </div>
   </div>
   <div class="action-area">
     <div class="action-area-right">
       <div class="button-strip">
-        <button id="packExtensionDismiss" i18n-content="cancel"></button>
-        <button id="packExtensionCommit"
+        <button id="pack-extension-dismiss" i18n-content="cancel"></button>
+        <button id="pack-extension-commit"
                 i18n-content="packExtensionCommit"></button>
       </div>
     </div>
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.js b/chrome/browser/resources/extensions/pack_extension_overlay.js
index e4b9f0d..22a3165 100644
--- a/chrome/browser/resources/extensions/pack_extension_overlay.js
+++ b/chrome/browser/resources/extensions/pack_extension_overlay.js
@@ -23,13 +23,13 @@
       cr.ui.overlay.globalInitialization();
       overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
 
-      $('packExtensionDismiss').addEventListener('click',
+      $('pack-extension-dismiss').addEventListener('click',
           this.handleDismiss_.bind(this));
-      $('packExtensionCommit').addEventListener('click',
+      $('pack-extension-commit').addEventListener('click',
           this.handleCommit_.bind(this));
-      $('browseExtensionDir').addEventListener('click',
+      $('browse-extension-dir').addEventListener('click',
           this.handleBrowseExtensionDir_.bind(this));
-      $('browsePrivateKey').addEventListener('click',
+      $('browse-private-key').addEventListener('click',
           this.handleBrowsePrivateKey_.bind(this));
     },
 
@@ -38,7 +38,7 @@
      * @param {Event} e The click event.
      */
     handleDismiss_: function(e) {
-      ExtensionSettings.showOverlay(null);
+      extensions.ExtensionSettings.showOverlay(null);
     },
 
     /**
@@ -46,8 +46,8 @@
      * @param {Event} e The click event.
      */
     handleCommit_: function(e) {
-      var extensionPath = $('extensionRootDir').value;
-      var privateKeyPath = $('extensionPrivateKey').value;
+      var extensionPath = $('extension-root-dir').value;
+      var privateKeyPath = $('extension-private-key').value;
       chrome.send('pack', [extensionPath, privateKeyPath, 0]);
     },
 
@@ -75,7 +75,7 @@
      */
     handleBrowseExtensionDir_: function(e) {
       this.showFileDialog_('folder', 'load', function(filePath) {
-        $('extensionRootDir').value = filePath;
+        $('extension-root-dir').value = filePath;
       });
     },
 
@@ -86,7 +86,7 @@
      */
     handleBrowsePrivateKey_: function(e) {
       this.showFileDialog_('file', 'pem', function(filePath) {
-        $('extensionPrivateKey').value = filePath;
+        $('extension-private-key').value = filePath;
       });
     },
   };
@@ -103,10 +103,10 @@
         loadTimeData.getString('ok'),
         '',
         function() {
-          ExtensionSettings.showOverlay(null);
+          extensions.ExtensionSettings.showOverlay(null);
         },
         null);
-    ExtensionSettings.showOverlay($('alertOverlay'));
+    extensions.ExtensionSettings.showOverlay($('alertOverlay'));
   };
 
   /**
@@ -120,10 +120,10 @@
         loadTimeData.getString('ok'),
         '',
         function() {
-          ExtensionSettings.showOverlay($('packExtensionOverlay'));
+          extensions.ExtensionSettings.showOverlay($('pack-extension-overlay'));
         },
         null);
-    ExtensionSettings.showOverlay($('alertOverlay'));
+    extensions.ExtensionSettings.showOverlay($('alertOverlay'));
   };
 
   // Export
@@ -131,6 +131,3 @@
     PackExtensionOverlay: PackExtensionOverlay
   };
 });
-
-// Update the C++ call so this isn't necessary.
-var PackExtensionOverlay = extensions.PackExtensionOverlay;
diff --git a/chrome/browser/resources/feedback.css b/chrome/browser/resources/feedback.css
deleted file mode 100644
index 74ce670..0000000
--- a/chrome/browser/resources/feedback.css
+++ /dev/null
@@ -1,130 +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. */
-
-#feedback-page {
-  -webkit-margin-start: 80px;
-  color: rgb(48, 57, 66);
-}
-
-#feedback-page > h1 {
-  border-bottom: 1px solid #eee;
-  padding-bottom: 6px;
-  width: 718px;
-}
-
-#content {
-  width: 600px;
-}
-
-#description {
-  display: block;
-  font-weight: 300;
-  text-align: start;
-  vertical-align: text-top;
-}
-
-#description-text {
-  box-sizing: border-box;
-  margin-top: 1em;
-  width: 100%;
-}
-
-.input-text-container {
-  -webkit-box-align: baseline;
-  display: -webkit-box;
-}
-
-.input-text-container > label {
-  -webkit-margin-end: 1em;
-  width: 150px;
-}
-
-.input-text-container > input {
-  -webkit-box-flex: 1;
-  display: block;
-  /* Don't push checkboxes out of alignment with bulky input. */
-  margin-bottom: -0.25em;
-}
-
-html:not(.focus-outline-visible)
-:enabled:focus:-webkit-any(input[type='checkbox'], input[type='radio'],
-    input[type='submit']) {
-  /* Cancel border-color for :focus specified in widgets.css. */
-  border-color: rgba(0, 0, 0, 0.25);
-}
-
-.thumbnail-list {
-  margin-bottom: 1em;
-  margin-top: 1em;
-  min-height: 151px;
-}
-
-.image-thumbnail-container {
-  border: 2px solid #ccc;
-  border-radius: 3px;
-  display: inline-block;
-}
-
-.image-thumbnail-container-selected:not(:only-of-type) {
-  border-color: green;
-}
-
-.image-thumbnail-container:not(:only-of-type):not(
-    .image-thumbnail-container-selected):hover {
-  border-color: rgb(184, 218, 176);
-}
-
-.image-thumbnail {
-  border: 2px solid white;
-}
-
-.image-thumbnail img {
-  display: block;
-  height: 140px;
-}
-
-#privacy-note {
-  margin-bottom: 0.8em;
-  width: 44em;
-}
-
-#buttons-pane {
-  /* Linux and Mac OS X display OK/Cancel dialogs in the reverse direction. */
-<if expr="not pp_ifdef('toolkit_views')">
-  -webkit-box-direction: reverse;
-</if>
-  display: -webkit-box;
-  padding: 0 0 12px;
-}
-
-#buttons-pane > input {
-  -webkit-margin-end: 0.8em;
-  display: block;
-}
-
-#attach-file-note {
-  -webkit-margin-start: 150px;
-  -webkit-padding-start: 1em;
-  padding-bottom: 20px
-  padding-top: 10px;
-}
-
-#attach-file {
-  margin: 0;
-}
-
-.attach-file-notification {
-  color: rgb(204, 0, 0);
-  font-weight: bold;
-  padding-left: 20px;
-}
-
-.launcher-layout #page-url,
-.launcher-layout #screenshot-row,
-.launcher-layout #title,
-.launcher-layout #description,
-html:not(.launcher-layout) #launcher-title,
-html:not(.launcher-layout) #launcher-description {
-  display: none;
-}
diff --git a/chrome/browser/resources/feedback/css/feedback.css b/chrome/browser/resources/feedback/css/feedback.css
new file mode 100644
index 0000000..0eb9a4a
--- /dev/null
+++ b/chrome/browser/resources/feedback/css/feedback.css
@@ -0,0 +1,137 @@
+/* Copyright 2013 The Chromium 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 {
+  height: 100%;
+}
+
+body {
+  height: 100%;
+  margin: 0;
+  padding: 0;
+  width: 100%;
+}
+
+.title-bar {
+  -webkit-align-items: center;
+  background-color: #fff;
+  box-shadow: 0 1px #d0d0d0;
+  color: rgb(80, 80, 82);
+  display: -webkit-flex;
+  font-size: 15px;
+  height: 48px;
+}
+
+.title-bar #page-title {
+  -webkit-app-region: drag;
+  -webkit-flex: 1 1 auto;
+  -webkit-margin-start: 20px;
+}
+
+.title-bar .button-bar {
+  -webkit-flex: 0 1 auto;
+}
+
+.content {
+  background-color: #fbfbfb;
+  color: #646464;
+  font-size: 12px;
+  margin: 20px;
+}
+
+.content #description-text {
+  border-color: #c8c8c8;
+  box-sizing: border-box;
+  height: 120px;
+  line-height: 18px;
+  padding: 10px;
+  resize: none;
+  width: 100%;
+}
+
+.content .text-field-container {
+  -webkit-align-items: center;
+  -webkit-padding-start: 10px;
+  display: -webkit-flex;
+  height: 29px;
+  margin-top: 10px;
+}
+
+.content .text-field-container > label {
+  -webkit-flex: 0 1 auto;
+  width: 100px;
+}
+
+.content .text-field-container > input[type=text] {
+  -webkit-flex: 1 1 auto;
+  -webkit-padding-start: 5px;
+  border: 1px solid;
+  border-color: #c8c8c8;
+  color: #585858;
+  height: 100%;
+}
+
+.content .text-field-container > input[type=checkbox] {
+  margin-right: 9px;
+}
+
+.content .checkbox-field-container {
+  -webkit-align-items: center;
+  display: -webkit-flex;
+  height: 29px;
+}
+
+#screenshot-container {
+  margin-top: 30px;
+}
+
+.content #screenshot-image {
+  -webkit-margin-start: 30px;
+  display: block;
+  height: 60px;
+  margin-top: 40px;
+  transition: all 250ms ease;
+}
+
+.content #screenshot-image:hover {
+  height: 170px;
+  margin-top: 80px;
+  z-index: 1;
+}
+
+.content #privacy-note {
+  color: #969696;
+  font-size: 10px;
+  line-height: 15px;
+  margin-bottom: 20px;
+  margin-top: 40px;
+}
+
+.content .buttons-pane {
+  display: -webkit-flex;
+  justify-content: flex-end
+}
+
+.content #attach-file-note {
+  -webkit-margin-start: 112px;
+  margin-bottom: 10px;
+  margin-top: 10px;
+}
+
+.content .attach-file-notification {
+  -webkit-padding-start: 20px;
+  color: rgb(204, 0, 0);
+  font-weight: bold;
+}
+
+button.white-button {
+  -webkit-margin-end: 10px;
+  color: #000;
+}
+
+button.blue-button {
+  color: #fff;
+  text-shadow: 1px sharp drop shadow rgb(45, 106, 218);
+}
diff --git a/chrome/browser/resources/feedback/html/default.html b/chrome/browser/resources/feedback/html/default.html
new file mode 100644
index 0000000..3455d04
--- /dev/null
+++ b/chrome/browser/resources/feedback/html/default.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection;">
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="chrome://resources/css/apps/common.css"></link>
+<link rel="stylesheet" href="chrome://resources/css/apps/topbutton_bar.css"></link>
+<link rel="stylesheet" href="../css/feedback.css">
+
+<script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/i18n_template_no_process.js"></script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="../js/take_screenshot.js"></script>
+<script src="../js/topbar_handlers.js"></script>
+<script src="../js/feedback.js"></script>
+</head>
+<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+  <div class="title-bar">
+    <span id="page-title" i18n-content="page-title"></span>
+    <span class="topbutton-bar">
+      <button class="minimize-button" id="minimize-button" tabindex="-1">
+      </button>
+      <button class="close-button" id="close-button" tabindex="-1">
+      </button>
+    </span>
+  </div>
+  <div class="content">
+    <textarea id="description-text"></textarea>
+    <div id="page-url" class="text-field-container">
+      <label id="page-url-label" i18n-content="page-url"></label>
+      <input id="page-url-text" type="text">
+    </div>
+    <!-- User e-mail -->
+    <div id="user-email" class="text-field-container">
+      <label id="user-email-label" i18n-content="user-email"></label>
+      <input id="user-email-text" type="text">
+    </div>
+    <!-- Attach a file -->
+    <div id="attach-file-container" class="text-field-container">
+      <label i18n-content="attach-file-label"></label>
+      <input id="attach-file" type="file">
+      <div id="attach-error" class="attach-file-notification"
+          i18n-content="attach-file-to-big" hidden></div>
+    </div>
+    <div id="attach-file-note" i18n-content="attach-file-note"></div>
+    <!-- Screenshot -->
+    <div id="screenshot-container" class="checkbox-field-container">
+      <input id="screenshot-checkbox" type="checkbox" checked>
+      <label id="screenshot-label" i18n-content="screenshot"></label>
+      <img id="screenshot-image">
+    </div>
+<if expr="pp_ifdef('chromeos')">
+    <!-- System Information -->
+    <div class="checkbox-field-container">
+      <input id="sys-info-checkbox" type="checkbox" checked>
+      <span id="sysinfo-label">
+        <a id="sysinfo-url" href="#" i18n-content="sysinfo"></a>
+      </span>
+    </div>
+</if>
+    <!-- Privacy node -->
+    <div id="privacy-note" i18n-values=".innerHTML:privacy-note"></div>
+    <!-- Buttons -->
+    <div class="buttons-pane">
+      <button id="cancel-button" type="submit"
+          class="white-button" i18n-content="cancel">
+      </button>
+      <button id="send-report-button" type="submit"
+          class="blue-button" i18n-content="send-report">
+      </button>
+    </div>
+  </div>
+</body>
+</html>
diff --git a/chrome/browser/resources/feedback/js/event_handler.js b/chrome/browser/resources/feedback/js/event_handler.js
new file mode 100644
index 0000000..309ecc3
--- /dev/null
+++ b/chrome/browser/resources/feedback/js/event_handler.js
@@ -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.
+
+/**
+ * @type {number}
+ * @const
+ */
+var FEEDBACK_WIDTH = 500;
+/**
+ * @type {number}
+ * @const
+ */
+var FEEDBACK_HEIGHT = 610;
+
+var initialFeedbackInfo = null;
+
+/**
+ * Callback which gets notified once our feedback UI has loaded and is ready to
+ * receive its initial feedback info object.
+ * @param {Object} request The message request object.
+ * @param {Object} sender The sender of the message.
+ * @param {function(Object)} sendResponse Callback for sending a response.
+ */
+function feedbackReady(request, sender, sendResponse) {
+  if (request.ready) {
+    chrome.runtime.sendMessage(
+        {sentFromEventPage: true, data: initialFeedbackInfo});
+  }
+}
+
+/**
+ * Callback which starts up the feedback UI.
+ * @param {Object} feedbackInfo Object containing any initial feedback info.
+ */
+function startFeedbackUI(feedbackInfo) {
+  initialFeedbackInfo = feedbackInfo;
+  chrome.app.window.create('html/default.html', {
+      frame: 'none',
+      id: 'default_window',
+      width: FEEDBACK_WIDTH,
+      height: FEEDBACK_HEIGHT,
+      hidden: true,
+      singleton: true },
+      function(appWindow) {});
+}
+
+chrome.runtime.onMessage.addListener(feedbackReady);
+chrome.feedbackPrivate.onFeedbackRequested.addListener(startFeedbackUI);
diff --git a/chrome/browser/resources/feedback/js/feedback.js b/chrome/browser/resources/feedback/js/feedback.js
new file mode 100644
index 0000000..a3379e0
--- /dev/null
+++ b/chrome/browser/resources/feedback/js/feedback.js
@@ -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.
+
+/** @type {string}
+ * @const
+ */
+var FEEDBACK_LANDING_PAGE =
+    'https://www.google.com/support/chrome/go/feedback_confirmation';
+/** @type {number}
+ * @const
+ */
+var MAX_ATTACH_FILE_SIZE = 3 * 1024 * 1024;
+
+var attachedFileBlob = null;
+var lastReader = null;
+
+var feedbackInfo = null;
+var systemInfo = null;
+
+/**
+ * Reads the selected file when the user selects a file.
+ * @param {Event} fileSelectedEvent The onChanged event for the file input box.
+ */
+function onFileSelected(fileSelectedEvent) {
+  $('attach-error').hidden = true;
+  var file = fileSelectedEvent.target.files[0];
+  if (!file) {
+    // User canceled file selection.
+    attachedFileBlob = null;
+    return;
+  }
+
+  if (file.size > MAX_ATTACH_FILE_SIZE) {
+    $('attach-error').hidden = false;
+
+    // Clear our selected file.
+    $('attach-file').value = '';
+    attachedFileBlob = null;
+    return;
+  }
+
+  attachedFileBlob = file.slice();
+}
+
+/**
+ * Opens a new tab with chrome://system, showing the current system info.
+ */
+function openSystemTab() {
+  window.open('chrome://system', '_blank');
+}
+
+/**
+ * Sends the report; after the report is sent, we need to be redirected to
+ * the landing page, but we shouldn't be able to navigate back, hence
+ * we open the landing page in a new tab and sendReport closes this tab.
+ * @return {boolean} True if the report was sent.
+ */
+function sendReport() {
+  if ($('description-text').value.length == 0) {
+    var description = $('description-text');
+    description.placeholder = loadTimeData.getString('no-description');
+    description.focus();
+    return false;
+  }
+
+  console.log('Feedback: Sending report');
+  if (attachedFileBlob) {
+    feedbackInfo.attachedFile = { name: $('attach-file').value,
+                                  data: attachedFileBlob };
+  }
+
+  feedbackInfo.description = $('description-text').value;
+  feedbackInfo.pageUrl = $('page-url-text').value;
+  feedbackInfo.email = $('user-email-text').value;
+
+  if ($('sys-info-checkbox') != null &&
+      $('sys-info-checkbox').checked &&
+      systemInfo != null) {
+    if (feedbackInfo.systemInformation != null) {
+      // Concatenate sysinfo if we had any initial system information
+      // sent with the feedback request event.
+      feedbackInfo.systemInformation =
+          feedbackInfo.systemInformation.concat(systemInfo);
+    } else {
+      feedbackInfo.systemInformation = systemInfo;
+    }
+  }
+
+  chrome.feedbackPrivate.sendFeedback(feedbackInfo, function(result) {
+    window.open(FEEDBACK_LANDING_PAGE, '_blank');
+    window.close();
+  });
+
+  return true;
+}
+
+/**
+ * Click listener for the cancel button.
+ * @param {Event} e The click event being handled.
+ */
+function cancel(e) {
+  e.preventDefault();
+  window.close();
+}
+
+/**
+ * Converts a blob data URL to a blob object.
+ * @param {string} url The data URL to convert.
+ * @return {Blob} Blob object containing the data.
+ */
+function dataUrlToBlob(url) {
+  var mimeString = url.split(',')[0].split(':')[1].split(';')[0];
+  var data = atob(url.split(',')[1]);
+  var dataArray = [];
+  for (var i = 0; i < data.length; ++i)
+    dataArray.push(data.charCodeAt(i));
+
+  return new Blob([new Uint8Array(dataArray)], {type: mimeString});
+}
+
+/**
+ * Initializes our page.
+ * Flow:
+ * .) DOMContent Loaded        -> . Request feedbackInfo object
+ *                                . Setup page event handlers
+ * .) Feedback Object Received -> . take screenshot
+ *                                . request email
+ *                                . request System info
+ *                                . request i18n strings
+ * .) Screenshot taken         -> . Show Feedback window.
+ */
+function initialize() {
+  // Add listener to receive the feedback info object.
+  chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
+    if (request.sentFromEventPage) {
+      feedbackInfo = request.data;
+      $('description-text').textContent = feedbackInfo.description;
+      $('page-url-text').value = feedbackInfo.pageUrl;
+
+      takeScreenshot(function(screenshotDataUrl) {
+        $('screenshot-image').src = screenshotDataUrl;
+        feedbackInfo.screenshot = dataUrlToBlob(screenshotDataUrl);
+        chrome.app.window.current().show();
+      });
+
+      chrome.feedbackPrivate.getUserEmail(function(email) {
+        $('user-email-text').value = email;
+      });
+
+      chrome.feedbackPrivate.getSystemInformation(function(sysInfo) {
+        systemInfo = sysInfo;
+      });
+
+      chrome.feedbackPrivate.getStrings(function(strings) {
+        loadTimeData.data = strings;
+        i18nTemplate.process(document, loadTimeData);
+      });
+    }
+  });
+
+  window.addEventListener('DOMContentLoaded', function() {
+    // Ready to receive the feedback object.
+    chrome.runtime.sendMessage({ready: true});
+
+    // Setup our event handlers.
+    $('attach-file').addEventListener('change', onFileSelected);
+    $('send-report-button').onclick = sendReport;
+    $('cancel-button').onclick = cancel;
+    if ($('sysinfo-url')) {
+      $('sysinfo-url').onclick = openSystemTab;
+    }
+  });
+}
+
+initialize();
diff --git a/chrome/browser/resources/feedback/js/take_screenshot.js b/chrome/browser/resources/feedback/js/take_screenshot.js
new file mode 100644
index 0000000..99b58b5
--- /dev/null
+++ b/chrome/browser/resources/feedback/js/take_screenshot.js
@@ -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.
+
+/**
+ * Function to take the screenshot of the current screen.
+ * @param {function(string)} callback Callback for returning the data URL to the
+ *                           screenshot.
+ */
+function takeScreenshot(callback) {
+  var streaming = false;
+  var video = document.createElement('video');
+
+  video.addEventListener('canplay', function(e) {
+    if (!streaming) {
+      streaming = true;
+
+      var canvas = document.createElement('canvas');
+      canvas.setAttribute('width', video.videoWidth);
+      canvas.setAttribute('height', video.videoHeight);
+      canvas.getContext('2d').drawImage(
+          video, 0, 0, video.videoWidth, video.videoHeight);
+
+      video.pause();
+      video.src = '';
+
+      callback(canvas.toDataURL('image/png'));
+    }
+  }, false);
+
+  navigator.webkitGetUserMedia(
+    {
+      video: {mandatory: {chromeMediaSource: 'screen'}}
+    },
+    function(stream) {
+      video.src = window.webkitURL.createObjectURL(stream);
+      video.play();
+    },
+    function(err) {
+      console.error('takeScreenshot failed: ' +
+          err.name + '; ' + err.message + '; ' + err.constraintName);
+    }
+  );
+}
diff --git a/chrome/browser/resources/feedback/js/topbar_handlers.js b/chrome/browser/resources/feedback/js/topbar_handlers.js
new file mode 100644
index 0000000..793e0e5
--- /dev/null
+++ b/chrome/browser/resources/feedback/js/topbar_handlers.js
@@ -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.
+
+/**
+ * Setup handlers for the minimize and close topbar buttons.
+ */
+function initializeHandlers() {
+  $('minimize-button').addEventListener('click', function(e) {
+    e.preventDefault();
+    chrome.app.window.current().minimize();
+  });
+
+  $('minimize-button').addEventListener('mousedown', function(e) {
+    e.preventDefault();
+  });
+
+  $('close-button').addEventListener('click', function() {
+    window.close();
+  });
+
+  $('close-button').addEventListener('mousedown', function(e) {
+    e.preventDefault();
+  });
+}
+
+window.addEventListener('DOMContentLoaded', initializeHandlers);
diff --git a/chrome/browser/resources/feedback/manifest.json b/chrome/browser/resources/feedback/manifest.json
new file mode 100644
index 0000000..2ac2d42
--- /dev/null
+++ b/chrome/browser/resources/feedback/manifest.json
@@ -0,0 +1,20 @@
+{
+  // chrome-extension://gfdkimpbcpahaombhbimeihdjnejgicl/
+  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMZElzFX2J1g1nRQ/8S3rg/1CjFyDltWOxQg+9M8aVgNVxbutEWFQz+oQzIP9BB67mJifULgiv12ToFKsae4NpEUR8sPZjiKDIHumc6pUdixOm8SJ5Rs16SMR6+VYxFUjlVW+5CA3IILptmNBxgpfyqoK0qRpBDIhGk1KDEZ4zqQIDAQAB",
+  "name": "Feedback",
+  "version": "1.0",
+  "manifest_version": 2,
+  "description": "User feedback extension",
+  "permissions": [
+      "feedbackPrivate",
+      "chrome://resources/"
+  ],
+  "app": {
+    "background": {
+      "scripts": ["js/event_handler.js"]
+    },
+    "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources; style-src 'unsafe-inline' *; img-src *; media-src 'self'"
+  },
+  "display_in_launcher": false,
+  "display_in_new_tab_page": false
+}
diff --git a/chrome/browser/resources/feedback_invalid.html b/chrome/browser/resources/feedback_invalid.html
deleted file mode 100644
index 330de1d..0000000
--- a/chrome/browser/resources/feedback_invalid.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<meta charset="utf-8">
-</head>
-<title i18n-content="title"></title>
-<body style="-webkit-user-select: none">
-Invalid Feedback options - please check.
-</body>
-</html>
diff --git a/chrome/browser/resources/file_manager/action_choice.html b/chrome/browser/resources/file_manager/action_choice.html
index 4df5eb6..f47c73d 100644
--- a/chrome/browser/resources/file_manager/action_choice.html
+++ b/chrome/browser/resources/file_manager/action_choice.html
@@ -38,6 +38,7 @@
     <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>
diff --git a/chrome/browser/resources/file_manager/css/audio_player.css b/chrome/browser/resources/file_manager/css/audio_player.css
index 7ded6a8..1f6b7bb 100644
--- a/chrome/browser/resources/file_manager/css/audio_player.css
+++ b/chrome/browser/resources/file_manager/css/audio_player.css
@@ -92,10 +92,10 @@
   -webkit-box-align: center;
   -webkit-box-orient: vertical;
   -webkit-box-pack: start;
-  border-top: 1px solid rgba(255, 255, 255, 0.1);
   display: -webkit-box;
   overflow-x: hidden;
   overflow-y: auto;
+  top: 0;
 }
 
 /* A single track container.
diff --git a/chrome/browser/resources/file_manager/css/common.css b/chrome/browser/resources/file_manager/css/common.css
index 2c6e080..5cff23a 100644
--- a/chrome/browser/resources/file_manager/css/common.css
+++ b/chrome/browser/resources/file_manager/css/common.css
@@ -263,8 +263,9 @@
   background-repeat: no-repeat;
   border: 5px solid transparent;
   border-image: -webkit-image-set(
-    url('../images/common/button.png') 1x,
-    url('../images/common/2x/button.png') 2x) 5 / 5px / 2px repeat;
+    url('chrome://resources/images/apps/button.png') 1x,
+    url('chrome://resources/images/2x/apps/button.png')
+        2x) 5 / 5px / 2px repeat;
   box-sizing: content-box;
   color: rgb(34, 34, 34);
   cursor: default;
@@ -288,8 +289,9 @@
 input[type='submit']:hover,
 select:hover {
   border-image: -webkit-image-set(
-    url('../images/common/button_hover.png') 1x,
-    url('../images/common/2x/button_hover.png') 2x) 5 / 5px / 2px repeat;
+    url('chrome://resources/images/apps/button_hover.png') 1x,
+    url('chrome://resources/images/2x/apps/button_hover.png')
+        2x) 5 / 5px / 2px repeat;
   color: #222;
 }
 
@@ -297,8 +299,9 @@
 input[type='button']:active,
 input[type='submit']:active {
   border-image: -webkit-image-set(
-    url('../images/common/button_pressed.png') 1x,
-    url('../images/common/2x/button_pressed.png') 2x) 5 / 5px / 2px repeat;
+    url('chrome://resources/images/apps/button_pressed.png') 1x,
+    url('chrome://resources/images/2x/apps/button_pressed.png')
+        2x) 5 / 5px / 2px repeat;
   color: #333;
 }
 
@@ -311,8 +314,9 @@
   background-color: rgb(250, 250, 250);
   background-image: none;
   border-image: -webkit-image-set(
-    url('../images/common/button.png') 1x,
-    url('../images/common/2x/button.png') 2x) 5 / 5px / 2px repeat;
+    url('chrome://resources/images/apps/button.png') 1x,
+    url('chrome://resources/images/2x/apps/button.png')
+        2x) 5 / 5px / 2px repeat;
   color: rgb(150, 150, 150);
 }
 
diff --git a/chrome/browser/resources/file_manager/css/file_manager.css b/chrome/browser/resources/file_manager/css/file_manager.css
index 28e9ef4..8597e93 100644
--- a/chrome/browser/resources/file_manager/css/file_manager.css
+++ b/chrome/browser/resources/file_manager/css/file_manager.css
@@ -248,13 +248,18 @@
 }
 
 #volume-list li.root-item {
-  -webkit-animation: fadeIn 150ms ease-in-out;
   -webkit-box-align: center;
   display: -webkit-box;
   line-height: 22px;  /* To accomodate for icons. */
   padding-left: 11px;
 }
 
+/* TODO(yoshiki): Animation is temporary disabled for volumes. Add animation
+   back. crbug.com/276132. */
+#volume-list li[item-type=shortcut].root-item {
+  -webkit-animation: fadeIn 150ms ease-in-out;
+}
+
 /* This selector is used by JavaScript. "fadeout" class will be dinamically
    added to elements.
    Must keep the class name 'fadeout' and the animation name 'fadeOut' in sync
@@ -432,29 +437,10 @@
 .dialog-header #search-box,
 .dialog-header #autocomplete-list,
 .dialog-header #search-icon,
-.dialog-header #search-clear-button,
-.dialog-header .buttonbar button {
+.dialog-header #search-clear-button {
   -webkit-app-region: no-drag;
 }
 
-.dialog-header #gear-button {
-  background-image: -webkit-image-set(
-    url('../images/files/ui/topbar_button_settings.png') 1x,
-    url('../images/files/ui/2x/topbar_button_settings.png') 2x);
-}
-
-.dialog-header #maximize-button {
-  background-image: -webkit-image-set(
-    url('../images/files/ui/topbar_button_maximize.png') 1x,
-    url('../images/files/ui/2x/topbar_button_maximize.png') 2x);
-}
-
-.dialog-header #close-button {
-  background-image: -webkit-image-set(
-    url('../images/files/ui/topbar_button_close.png') 1x,
-    url('../images/files/ui/2x/topbar_button_close.png') 2x);
-}
-
 /* Container for the detail and thumbnail list views. */
 .dialog-body {
   -webkit-box-flex: 1;
@@ -486,6 +472,7 @@
   -webkit-box-orient: horizontal;
   border-top: 1px solid rgb(225, 225, 225);
   display: -webkit-box;
+  outline: none;
   padding: 10px;
 }
 
@@ -559,9 +546,6 @@
   width: 26px;
 }
 
-#search-breadcrumbs {
-}
-
 .breadcrumbs > [collapsed]::before {
   content: '...';
 }
@@ -598,40 +582,6 @@
   width: 25px;
 }
 
-.dialog-header .buttonbar {
-  -webkit-box-align: center;
-  height: 100%;
-}
-
-.dialog-header .buttonbar button {
-  -webkit-box-shadow: none;
-  -webkit-margin-end: 10px;
-  -webkit-margin-start: 0;
-  background-color: transparent;
-  background-image: none;
-  background-position: center;
-  background-repeat: no-repeat;
-  border: 0 none transparent;
-  display: block;
-  height: 32px;
-  min-width: 0;
-  outline: none;
-  padding: 0;
-  width: 32px;
-}
-
-.dialog-header .buttonbar button:active {
-  -webkit-box-shadow:
-    0 1px 0 0 #c2c2c2 inset,
-    0 0 0 1px #dedede inset;
-}
-
-.dialog-header button:hover,
-.dialog-header button:focus,
-.dialog-header button:active {
-  background-color: #ededed;
-}
-
 #search-box,
 #filename-input-box input {
   border: 1px solid #c8c8c8;
@@ -672,9 +622,6 @@
 
 #search-box::-webkit-search-cancel-button {
   -webkit-appearance: none;
-}
-
-#search-box::-webkit-search-cancel-button {
   right: 2px;
 }
 
@@ -1021,8 +968,6 @@
   0% {
     background-color: transparent;
   }
-  50% {
-  }
 }
 
 .table-row-cell .selection-label {
@@ -1665,7 +1610,8 @@
   position: relative;
 }
 
-.buttonbar .tooltip {
+.buttonbar .tooltip,
+.topbutton-bar .tooltip {
   right: -12px;
   top: 35px;
 }
diff --git a/chrome/browser/resources/file_manager/css/gallery.css b/chrome/browser/resources/file_manager/css/gallery.css
index 1966f07..30aac69 100644
--- a/chrome/browser/resources/file_manager/css/gallery.css
+++ b/chrome/browser/resources/file_manager/css/gallery.css
@@ -1369,12 +1369,12 @@
 
 .gallery > .header > .maximize-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/topbar_button_maximize.png') 1x,
-    url('../images/files/ui/2x/topbar_button_maximize.png') 2x);
+    url('chrome://resources/images/apps/topbar_button_maximize.png') 1x,
+    url('chrome://resources/images/2x/apps/topbar_button_maximize.png') 2x);
 }
 
 .gallery > .header > .close-button {
   background-image: -webkit-image-set(
-    url('../images/files/ui/topbar_button_close.png') 1x,
-    url('../images/files/ui/2x/topbar_button_close.png') 2x);
+    url('chrome://resources/images/apps/topbar_button_close.png') 1x,
+    url('chrome://resources/images/2x/apps/topbar_button_close.png') 2x);
 }
diff --git a/chrome/browser/resources/file_manager/gallery.html b/chrome/browser/resources/file_manager/gallery.html
index 9488fb6..fc7e486 100644
--- a/chrome/browser/resources/file_manager/gallery.html
+++ b/chrome/browser/resources/file_manager/gallery.html
@@ -42,6 +42,7 @@
     <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/volume_manager.js"></script>
 
@@ -68,8 +69,6 @@
     <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="js/photo/gallery_testapi.js"></script>
   </if>
 </head>
 <body>
diff --git a/chrome/browser/resources/file_manager/images/common/2x/button.png b/chrome/browser/resources/file_manager/images/common/2x/button.png
deleted file mode 100644
index 9fdd912..0000000
--- a/chrome/browser/resources/file_manager/images/common/2x/button.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/button_hover.png b/chrome/browser/resources/file_manager/images/common/2x/button_hover.png
deleted file mode 100644
index 79f492e..0000000
--- a/chrome/browser/resources/file_manager/images/common/2x/button_hover.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/2x/button_pressed.png b/chrome/browser/resources/file_manager/images/common/2x/button_pressed.png
deleted file mode 100644
index 00cbed6..0000000
--- a/chrome/browser/resources/file_manager/images/common/2x/button_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/button.png b/chrome/browser/resources/file_manager/images/common/button.png
deleted file mode 100644
index 76bc97e..0000000
--- a/chrome/browser/resources/file_manager/images/common/button.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/button_hover.png b/chrome/browser/resources/file_manager/images/common/button_hover.png
deleted file mode 100644
index 34965e0..0000000
--- a/chrome/browser/resources/file_manager/images/common/button_hover.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/common/button_pressed.png b/chrome/browser/resources/file_manager/images/common/button_pressed.png
deleted file mode 100644
index 3c81b8b..0000000
--- a/chrome/browser/resources/file_manager/images/common/button_pressed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_close.png b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_close.png
deleted file mode 100644
index 7a28084..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_maximize.png b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_maximize.png
deleted file mode 100644
index 59377a4..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_maximize.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_settings.png b/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_settings.png
deleted file mode 100644
index b474c4c..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/2x/topbar_button_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_close.png b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_close.png
deleted file mode 100644
index b902560..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_close.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_maximize.png b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_maximize.png
deleted file mode 100644
index 3bd557f..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_maximize.png
+++ /dev/null
Binary files differ
diff --git a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_settings.png b/chrome/browser/resources/file_manager/images/files/ui/topbar_button_settings.png
deleted file mode 100644
index ef0724a..0000000
--- a/chrome/browser/resources/file_manager/images/files/ui/topbar_button_settings.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
index c247ee2..fe4e6bf 100644
--- a/chrome/browser/resources/file_manager/js/action_choice.js
+++ b/chrome/browser/resources/file_manager/js/action_choice.js
@@ -13,16 +13,17 @@
  *
  * @param {HTMLElement} dom Container.
  * @param {FileSystem} filesystem Local file system.
+ * @param {VolumeManager} volumeManager VolueManager of the app.
  * @param {Object} params Parameters.
  * @constructor
  */
-function ActionChoice(dom, filesystem, params) {
+function ActionChoice(dom, filesystem, volumeManager, params) {
   this.dom_ = dom;
   this.filesystem_ = filesystem;
   this.params_ = params;
   this.document_ = this.dom_.ownerDocument;
   this.metadataCache_ = this.params_.metadataCache;
-  this.volumeManager_ = VolumeManager.getInstance();
+  this.volumeManager_ = volumeManager;
   this.volumeManager_.addEventListener('externally-unmounted',
      this.onDeviceUnmounted_.bind(this));
   this.initDom_();
@@ -102,7 +103,10 @@
 
   var onFilesystem = function(filesystem) {
     var dom = document.querySelector('.action-choice');
-    ActionChoice.instance = new ActionChoice(dom, filesystem, params);
+    VolumeManager.getInstance(function(volumeManager) {
+      ActionChoice.instance = new ActionChoice(
+          dom, filesystem, volumeManager, params);
+    });
   };
 
   chrome.fileBrowserPrivate.getStrings(function(strings) {
@@ -315,7 +319,8 @@
     this.sourceEntry_ = entry;
     this.document_.querySelector('title').textContent = entry.name;
 
-    var deviceType = this.volumeManager_.getDeviceType(entry.fullPath);
+    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);
@@ -323,11 +328,26 @@
         loadTimeData.getString('ACTION_CHOICE_LOADING_' +
                                deviceType.toUpperCase());
 
-    util.traverseTree(entry, onTraversed, 0 /* infinite depth */,
-        FileType.isVisible);
+    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);
 
   var onReady = function() {
+    // TODO(hidehiko): Replace filesystem by volumeManager.
     util.resolvePath(this.filesystem_.root, source, onEntry, function() {
       this.recordAction_('error');
       this.close_();
@@ -438,8 +458,8 @@
   }
 
   if (action == this.watchSingleVideoAction_) {
-    chrome.fileBrowserPrivate.viewFiles([this.singleVideo_.toURL()],
-        function(success) {});
+    util.viewFilesInBrowser([this.singleVideo_.toURL()],
+                            function(success) {});
     this.recordAction_('watch-single-video');
     this.close_();
     return;
diff --git a/chrome/browser/resources/file_manager/js/action_choice_scripts.js b/chrome/browser/resources/file_manager/js/action_choice_scripts.js
index 2cf5cd8..a14794d 100644
--- a/chrome/browser/resources/file_manager/js/action_choice_scripts.js
+++ b/chrome/browser/resources/file_manager/js/action_choice_scripts.js
@@ -29,6 +29,7 @@
 (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"/>
diff --git a/chrome/browser/resources/file_manager/js/async_util.js b/chrome/browser/resources/file_manager/js/async_util.js
index 59199eb..9b7639b 100644
--- a/chrome/browser/resources/file_manager/js/async_util.js
+++ b/chrome/browser/resources/file_manager/js/async_util.js
@@ -10,6 +10,38 @@
 var AsyncUtil = {};
 
 /**
+ * Asynchronous version of Array.forEach.
+ * This executes a provided function callback once per array element, then
+ * run completionCallback to notify the completion.
+ * The callback can be an asynchronous function, but the execution is
+ * sequentially done.
+ *
+ * @param {Array.<T>} array The array to be iterated.
+ * @param {function(function(), T, number, Array.<T>} callback The iteration
+ *     callback. The first argument is a callback to notify the completion of
+ *     the iteration.
+ * @param {function()} completionCallback Called when all iterations are
+ *     completed.
+ * @param {Object=} opt_thisObject Bound to callback if given.
+ * @template T
+ */
+AsyncUtil.forEach = function(
+    array, callback, completionCallback, opt_thisObject) {
+  if (opt_thisObject)
+    callback = callback.bind(opt_thisObject);
+
+  var queue = new AsyncUtil.Queue();
+  for (var i = 0; i < array.length; i++) {
+    queue.run(function(element, index, iterationCompletionCallback) {
+      callback(iterationCompletionCallback, element, index, array);
+    }.bind(null, array[i], i));
+  }
+  queue.run(function(iterationCompletionCallback) {
+    completionCallback();  // Don't pass iteration completion callback.
+  });
+};
+
+/**
  * Creates a class for executing several asynchronous closures in a fifo queue.
  * Added tasks will be executed sequentially in order they were added.
  *
diff --git a/chrome/browser/resources/file_manager/js/background.js b/chrome/browser/resources/file_manager/js/background.js
index 693cd9d..2f7b877 100644
--- a/chrome/browser/resources/file_manager/js/background.js
+++ b/chrome/browser/resources/file_manager/js/background.js
@@ -110,7 +110,6 @@
     options = options();
   options.id = this.url_;  // This is to make Chrome reuse window geometries.
   options.singleton = false;
-  options.hidden = true;
 
   // Get similar windows, it means with the same initial url, eg. different
   // main windows of Files.app.
@@ -130,11 +129,6 @@
                          bounds.top + AppWindowWrapper.SHIFT_DISTANCE);
       }
 
-      // Show after changing bounds is done. For the new UI, Files.app shows
-      // it's window as soon as the UI is pre-initialized.
-      if (!this.id_.match(FILES_ID_PATTERN))
-        appWindow.show();
-
       appWindows[this.id_] = appWindow;
       var contentWindow = appWindow.contentWindow;
       contentWindow.appID = this.id_;
@@ -276,6 +270,7 @@
     minWidth: 320,
     minHeight: 240,
     frame: 'none',
+    hidden: true,
     transparentBackground: true
   };
 }
@@ -431,19 +426,13 @@
  */
 function createAudioPlayerOptions() {
   var WIDTH = 280;
-  var MIN_HEIGHT = 35 + 58;
-  var MAX_HEIGHT = 35 + 58 * 3;
-  var BOTTOM = 80;
-  var RIGHT = 20;
-
+  var HEIGHT = 35 + 58;
   return {
-    defaultLeft: (window.screen.availWidth - WIDTH - RIGHT),
-    defaultTop: (window.screen.availHeight - MIN_HEIGHT - BOTTOM),
-    minHeight: MIN_HEIGHT,
-    maxHeight: MAX_HEIGHT,
-    height: MIN_HEIGHT,
+    type: 'panel',
+    hidden: true,
+    minHeight: HEIGHT,
     minWidth: WIDTH,
-    maxWidth: WIDTH,
+    height: HEIGHT,
     width: WIDTH
   };
 }
diff --git a/chrome/browser/resources/file_manager/js/directory_model.js b/chrome/browser/resources/file_manager/js/directory_model.js
index f1c5f97..ebae107 100644
--- a/chrome/browser/resources/file_manager/js/directory_model.js
+++ b/chrome/browser/resources/file_manager/js/directory_model.js
@@ -16,49 +16,71 @@
  * Returns root entries asynchronously.
  * @param {DirectoryEntry} root The root entry of the whole file system.
  * @param {boolean} isDriveEnabled True if the drive is enabled.
- * @param {function(Array.<Entry>)} callback Called when roots are resolved.
+ * @param {function(Array.<Entry>)} completionCallback Called when roots are
+ *     resolved.
  */
-DirectoryModelUtil.resolveRoots = function(root, isDriveEnabled, callback) {
-  var groups = {
-    drive: null,
-    downloads: null,
-    archives: null,
-    removables: null,
+DirectoryModelUtil.resolveRoots = function(
+    root, isDriveEnabled, completionCallback) {
+  var rootEntryGroup = {
+    drive: [],
+    downloads: [],
+    archives: [],
+    removables: [],
   };
 
-  // Use a fake instead, to return a list as fast as possible.
-  groups.drive = (isDriveEnabled ? [DirectoryModel.fakeDriveEntry_] : []);
+  // Add the entry at path as a root.
+  var addRootEntry = function(absolutePath, key, callback) {
+    root.getDirectory(
+        absolutePath.substring(1),  // Remove the leading '/'.
+        {create: false},
+        function(entry) {
+          rootEntryGroup[key] = [entry];
+          callback();
+        },
+        function(error) {
+          console.error('Error resolving ' + key + ' root dir: ' + error);
+          callback();
+        });
+  };
 
-  var addRootEntryList = function(key, rootEntryList) {
-    groups[key] = rootEntryList;
+  // Read the directory at path, and add all contained entries as roots.
+  var addRootEntryList = function(absolutePath, key, callback) {
+    util.readDirectory(
+        root,
+        absolutePath.substring(1),  // Remove the leading '/'.
+        function(entryList) {
+          rootEntryGroup[key] = entryList;
+          callback();
+        });
+  };
 
-    for (var key in groups) {
-      if (!groups[key]) {
-        // There is a pending task.
-        return;
-      }
+  var group = new AsyncUtil.Group();
+
+  // Resolve the Drive root if enabled.
+  if (isDriveEnabled) {
+    group.add(addRootEntry.bind(
+        null, RootDirectory.DRIVE + '/' + DriveSubRootDirectory.ROOT, 'drive'));
+  }
+
+  // Resolve Download, Archives and Removables directories.
+  group.add(addRootEntry.bind(null, RootDirectory.DOWNLOADS, 'downloads'));
+  group.add(addRootEntryList.bind(null, RootDirectory.ARCHIVE, 'archives'));
+  group.add(addRootEntryList.bind(
+      null, RootDirectory.REMOVABLE, 'removables'));
+
+  group.run(function() {
+    if (!rootEntryGroup.drive && isDriveEnabled) {
+      // Drive is enabled, but not available. Use the fake entry here.
+      rootEntryGroup.drive = [DirectoryModel.fakeDriveEntry_];
     }
 
     // Concat the result in the order.
-    callback([].concat(
-        groups.drive, groups.downloads, groups.archives, groups.removables));
-  };
-
-  // Resolve download root directory.
-  root.getDirectory(
-      RootDirectory.DOWNLOADS.substring(1),  // Remove the leading '/'.
-      { create: false },
-      function(entry) { addRootEntryList('downloads', [entry]); },
-      function(err) {
-        console.error('Error resolving downloads root dir: ' + error);
-        addRootEntryList('downloads', []);
-      });
-
-  // Reads 'archives' and 'removables' roots.
-  util.readDirectory(root, RootDirectory.ARCHIVE.substring(1),
-                     addRootEntryList.bind(null, 'archives'));
-  util.readDirectory(root, RootDirectory.REMOVABLE.substring(1),
-                     addRootEntryList.bind(null, 'removables'));
+    completionCallback([].concat(
+        rootEntryGroup.drive,
+        rootEntryGroup.downloads,
+        rootEntryGroup.archives,
+        rootEntryGroup.removables));
+  });
 };
 
 /**
@@ -71,13 +93,12 @@
  * @param {FileWatcher} fileWatcher Instance of FileWatcher.
  * @param {MetadataCache} metadataCache The metadata cache service.
  * @param {VolumeManager} volumeManager The volume manager.
- * @param {boolean} isDriveEnabled True if DRIVE enabled (initial value).
  * @param {boolean} showSpecialSearchRoots True if special-search roots are
  *     available. They should be hidden for the dialogs to save files.
  * @constructor
  */
 function DirectoryModel(root, singleSelection, fileFilter, fileWatcher,
-                        metadataCache, volumeManager, isDriveEnabled,
+                        metadataCache, volumeManager,
                         showSpecialSearchRoots) {
   this.root_ = root;
   this.fileListSelection_ = singleSelection ?
@@ -87,7 +108,6 @@
   this.pendingScan_ = null;
   this.rescanTime_ = null;
   this.scanFailures_ = 0;
-  this.driveEnabled_ = isDriveEnabled;
   this.showSpecialSearchRoots_ = showSpecialSearchRoots;
 
   this.fileFilter_ = fileFilter;
@@ -193,6 +213,9 @@
       'drive-status-changed',
       this.taskQueue_.run.bind(
           this.taskQueue_, this.onDriveStatusChanged_.bind(this)));
+  this.volumeManager_.addEventListener(
+      'drive-enabled-status-changed',
+      this.onDriveEnabledStatusChanged_.bind(this));
   this.taskQueue_.run(this.updateRoots_.bind(this));
 };
 
@@ -211,22 +234,24 @@
 };
 
 /**
- * Sets whether DRIVE appears in the roots list and
- * if it could be used as current directory.
- * @param {boolead} enabled True if DRIVE enabled.
+ * Called when the drive enable status is changed.
+ * @param {cr.Event} event Event object for the status change.
+ * @private
  */
-DirectoryModel.prototype.setDriveEnabled = function(enabled) {
-  if (this.driveEnabled_ == enabled)
-    return;
-  // Mount Drive if it was previously disabled and is now enabled.
-  if (enabled)
-    this.volumeManager_.mountDrive(function() {}, function() {});
+DirectoryModel.prototype.onDriveEnabledStatusChanged_ = function(event) {
+  this.taskQueue_.run(function(callback) {
+    // TODO(hidehiko): This should be moved to VolumeManager, when rootsList
+    // is moved to there.
+    this.taskQueue_.run(this.updateRoots_.bind(this));
 
-  this.driveEnabled_ = enabled;
-  this.taskQueue_.run(this.updateRoots_.bind(this));
-  if (!enabled && (this.getCurrentRootType() == RootType.DRIVE ||
-                   this.getCurrentRootType() == RootType.DRIVE_OFFLINE))
-    this.changeDirectory(PathUtil.DEFAULT_DIRECTORY);
+    if (!event.enabled &&
+        PathUtil.isDriveBasedPath(this.getCurrentDirEntry().fullPath)) {
+      // Currently, this is on Drive's directory, but Drive file system is
+      // disabled. So, move back to the default directory.
+      this.changeDirectory(PathUtil.DEFAULT_DIRECTORY);
+    }
+    callback();
+  }.bind(this));
 };
 
 /**
@@ -320,10 +345,16 @@
  * @return {boolean} True if the |path| is read only.
  */
 DirectoryModel.prototype.isPathReadOnly = function(path) {
+  // TODO(hidehiko): Migrate this into VolumeInfo.
   switch (PathUtil.getRootType(path)) {
     case RootType.REMOVABLE:
-      return !!this.volumeManager_.isReadOnly(PathUtil.getRootPath(path)) ||
-             !!this.volumeManager_.getMountError(PathUtil.getRootPath(path));
+      var volumeInfo = this.volumeManager_.getVolumeInfo(
+          PathUtil.getRootPath(path));
+      // Returns true if the volume is actually read only, or if an error
+      // is found during the mounting.
+      // TODO(hidehiko): Remove "error" check here, by removing error'ed volume
+      // info from VolumeManager.
+      return volumeInfo && (volumeInfo.isReadOnly || !!volumeInfo.error);
     case RootType.ARCHIVE:
       return true;
     case RootType.DOWNLOADS:
@@ -711,10 +742,10 @@
 
 /**
  * Callback when an entry is changed.
- * @param {util.EntryChangedType} type How the entry is changed.
+ * @param {util.EntryChangedKind} kind How the entry is changed.
  * @param {Entry} entry The changed entry.
  */
-DirectoryModel.prototype.onEntryChanged = function(type, entry) {
+DirectoryModel.prototype.onEntryChanged = function(kind, entry) {
   // TODO(hidehiko): We should update directory model even the search result
   // is shown.
   var rootType = this.getCurrentRootType();
@@ -725,7 +756,7 @@
       this.isSearching())
     return;
 
-  if (type == util.EntryChangedType.CREATED) {
+  if (kind == util.EntryChangedKind.CREATED) {
     entry.getParent(function(parentEntry) {
       if (this.getCurrentDirEntry().fullPath != parentEntry.fullPath) {
         // Do nothing if current directory changed during async operations.
@@ -739,9 +770,9 @@
 
         var index = this.findIndexByEntry_(entry);
         if (index >= 0)
-          fileList.splice(index, 1, entry);
+          this.getFileList().splice(index, 1, entry);
         else
-          fileList.push(entry);
+          this.getFileList().push(entry);
       }.bind(this));
     }.bind(this));
   } else {
@@ -753,99 +784,61 @@
 };
 
 /**
- * TODO(hidehiko): Migrate this method into findIndexByEntry_ defined below.
- * @param {string} name Filename.
- * @return {number} The index in the fileList.
- * @private
- */
-DirectoryModel.prototype.findIndexByName_ = function(name) {
-  var fileList = this.getFileList();
-  for (var i = 0; i < fileList.length; i++)
-    if (fileList.item(i).name == name)
-      return i;
-  return -1;
-};
-
-/**
  * @param {Entry} entry The entry to be searched.
  * @return {number} The index in the fileList, or -1 if not found.
  * @private
  */
 DirectoryModel.prototype.findIndexByEntry_ = function(entry) {
   var fileList = this.getFileList();
-  for (var i = 0; i < fileList.length; i++)
-    if (fileList.item(i).fullPath == entry.fullPath)
+  for (var i = 0; i < fileList.length; i++) {
+    if (util.isSameEntry(fileList.item(i), entry))
       return i;
+  }
   return -1;
 };
 
 /**
- * Rename the entry in the filesystem and update the file list.
- * @param {Entry} entry Entry to rename.
- * @param {string} newName New name.
- * @param {function(FileError)} errorCallback Called on error.
- * @param {function()=} opt_successCallback Called on success.
+ * Called when rename is done successfully.
+ * Note: conceptually, DirectoryModel should work without this, because entries
+ * can be renamed by other systems anytime and Files.app should reflect it
+ * correctly.
+ * TODO(hidehiko): investigate more background, and remove this if possible.
+ *
+ * @param {Entry} oldEntry The old entry.
+ * @param {Entry} newEntry The new entry.
+ * @param {function()} opt_callback Called on completion.
  */
-DirectoryModel.prototype.renameEntry = function(entry, newName,
-                                                errorCallback,
-                                                opt_successCallback) {
-  var currentDirPath = this.getCurrentDirPath();
-  var onSuccess = function(newEntry) {
-    this.currentDirContents_.prefetchMetadata([newEntry], function() {
-      // If the current directory is the old entry, then quietly change to the
-      // new one.
-      if (entry.fullPath == this.getCurrentDirPath())
-        this.changeDirectory(newEntry.fullPath);
+DirectoryModel.prototype.onRenameEntry = function(
+    oldEntry, newEntry, opt_callback) {
+  this.currentDirContents_.prefetchMetadata([newEntry], function() {
+    // If the current directory is the old entry, then quietly change to the
+    // new one.
+    if (util.isSameEntry(oldEntry, this.getCurrentDirEntry()))
+      this.changeDirectory(newEntry.fullPath);
 
-      // Update selection and call the success callback if still in the same
-      // directory as while started renaming.
-      if (currentDirPath != this.getCurrentDirPath())
-        return;
-
-      var index = this.findIndexByName_(entry.name);
-
-      if (index >= 0) {
-        var wasSelected = this.fileListSelection_.getIndexSelected(index);
-
-        this.getFileList().splice(index, 1, newEntry);
-
-        if (wasSelected)
-          this.fileListSelection_.setIndexSelected(
-              this.findIndexByName_(newName), true);
+    // Look for the old entry.
+    // If the entry doesn't exist in the list, it has been updated from
+    // outside (probably by directory rescan).
+    var index = this.findIndexByEntry_(oldEntry);
+    if (index >= 0) {
+      // Update the content list and selection status.
+      var wasSelected = this.fileListSelection_.getIndexSelected(index);
+      this.fileListSelection_.beginChange();
+      this.fileListSelection_.setIndexSelected(index, false);
+      this.getFileList().splice(index, 1, newEntry);
+      if (wasSelected) {
+        // We re-search the index, because splice may trigger sorting so that
+        // index may be stale.
+        this.fileListSelection_.setIndexSelected(
+            this.findIndexByEntry_(newEntry), true);
       }
+      this.fileListSelection_.endChange();
+    }
 
-      // If the entry doesn't exist in the list it mean that it updated from
-      // outside (probably by directory rescan).
-      if (opt_successCallback)
-         opt_successCallback();
-    }.bind(this));
-  }.bind(this);
-
-  var onParentFound = function(parentEntry) {
-    entry.moveTo(parentEntry, newName, onSuccess, errorCallback);
-  };
-
-  entry.getParent(onParentFound, errorCallback);
-};
-
-/**
- * Checks if current directory contains a file or directory with this name.
- * @param {string} entry Entry to which newName will be given.
- * @param {string} name Name to check.
- * @param {function(boolean, boolean?)} callback Called when the result's
- *     available. First parameter is true if the entry exists and second
- *     is true if it's a file.
- */
-DirectoryModel.prototype.doesExist = function(entry, name, callback) {
-  var onParentFound = function(parentEntry) {
-    util.resolvePath(parentEntry, name,
-        function(foundEntry) {
-          callback(true, foundEntry.isFile);
-        },
-        callback.bind(window, false));
-  };
-
-  entry.getParent(onParentFound, callback.bind(window, false));
+    // Run callback, finally.
+    if (opt_callback)
+      opt_callback();
+  }.bind(this));
 };
 
 /**
@@ -1177,7 +1170,7 @@
 DirectoryModel.prototype.updateRoots_ = function(opt_callback) {
   metrics.startInterval('Load.Roots');
   DirectoryModelUtil.resolveRoots(
-      this.root_, this.driveEnabled_,
+      this.root_, this.volumeManager_.driveEnabled,
       function(rootEntries) {
         metrics.recordInterval('Load.Roots');
 
@@ -1223,55 +1216,40 @@
  * @private
  */
 DirectoryModel.prototype.onDriveStatusChanged_ = function(callback) {
-  var mounted = this.isDriveMounted();
-  if (mounted) {
-    // Change fake entry to real one and rescan.
-    var onGotDirectory = function(entry) {
-      this.updateRootEntry_(entry);
-      var currentDirEntry = this.getCurrentDirEntry();
+  this.updateRoots_(function() {
+    var currentDirEntry = this.getCurrentDirEntry();
+    if (this.isDriveMounted()) {
       if (currentDirEntry == DirectoryModel.fakeDriveEntry_) {
-        this.changeDirectoryEntrySilent_(entry);
+        // Replace the fake entry by real DirectoryEntry silently.
+        for (var i = 0; i < this.rootsList_.length; i++) {
+          if (this.rootsList_.item(i).fullPath ==
+              DirectoryModel.fakeDriveEntry_.fullPath) {
+            this.changeDirectoryEntrySilent_(this.rootsList_.item(i));
+            break;
+          }
+        }
       } else if (PathUtil.isSpecialSearchRoot(currentDirEntry.fullPath)) {
         this.rescan();
       }
-      callback();
-    };
-    this.root_.getDirectory(
-        DirectoryModel.fakeDriveEntry_.fullPath, {},
-        onGotDirectory.bind(this));
-  } else {
-    var rootType = this.getCurrentRootType();
-    if (rootType != RootType.DRIVE && rootType != RootType.DRIVE_OFFLINE) {
-      callback();
-      return;
-    }
-
-    // Current entry unmounted. Replace with fake drive one.
-    this.updateRootEntry_(DirectoryModel.fakeDriveEntry_);
-    if (this.getCurrentDirPath() == DirectoryModel.fakeDriveEntry_.fullPath) {
-      // Replace silently and rescan.
-      this.changeDirectoryEntrySilent_(DirectoryModel.fakeDriveEntry_);
     } else {
-      this.changeDirectoryEntry_(false, DirectoryModel.fakeDriveEntry_);
+      // TODO(hidehiko): Conceptually, fakeDriveEntry should be a trick to
+      // initialize Drive file system mounting state lazily. So, moving back
+      // to the fakeDriveEntry sounds weird state. Disabling the Drive File
+      // System should be handled as same as other file systems (such as
+      // unmounting zip-archive, disconnecting USB flush storage, etc.).
+      // The handling code is here due to historical reason. Clean this up.
+      if (currentDirEntry.fullPath == DirectoryModel.fakeDriveEntry_.fullPath) {
+        // Replace silently and rescan.
+        this.changeDirectoryEntrySilent_(DirectoryModel.fakeDriveEntry_);
+      } else if (PathUtil.isDriveBasedPath(currentDirEntry.fullPath)) {
+        // Now, Drive file system is unmounted. Go back to the fake Drive
+        // entry.
+        this.changeDirectoryEntry_(false, DirectoryModel.fakeDriveEntry_);
+      }
     }
-    callback();
-  }
-};
 
-/**
- * Update the entry in the roots list model.
- *
- * @param {DirectoryEntry} entry New entry.
- * @private
- */
-DirectoryModel.prototype.updateRootEntry_ = function(entry) {
-  for (var i = 0; i != this.rootsList_.length; i++) {
-    if (this.rootsList_.item(i).fullPath == entry.fullPath) {
-      this.rootsList_.splice(i, 1, entry);
-      return;
-    }
-  }
-  console.error('Cannot find root: ' + entry.fullPath);
+    callback();
+  }.bind(this));
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/js/directory_tree.js b/chrome/browser/resources/file_manager/js/directory_tree.js
index 981089e..2d14314 100644
--- a/chrome/browser/resources/file_manager/js/directory_tree.js
+++ b/chrome/browser/resources/file_manager/js/directory_tree.js
@@ -130,31 +130,14 @@
  * Retrieves the file list with the latest information.
  *
  * @param {DirectoryTree|DirectoryItem} item Parent to be reloaded.
- * @param {DirectoryModel} dm The directory model.
  * @param {function(Array.<Entry>)} successCallback Callback on success.
  * @param {function()=} opt_errorCallback Callback on failure.
  */
 DirectoryTreeUtil.updateSubDirectories = function(
-    item, dm, successCallback, opt_errorCallback) {
-  // Tries to retrieve new entry if the cached entry is dummy.
+    item, successCallback, opt_errorCallback) {
   if (util.isFakeDirectoryEntry(item.entry)) {
-    // Fake Drive root.
-    dm.resolveDirectory(
-        item.fullPath,
-        function(entry) {
-          item.dirEntry_ = entry;
-
-          // If the retrieved entry is dummy again, returns with an error.
-          if (util.isFakeDirectoryEntry(entry)) {
-            if (opt_errorCallback)
-              opt_errorCallback();
-            return;
-          }
-
-          DirectoryTreeUtil.updateSubDirectories(
-              item, dm, successCallback, opt_errorCallback);
-        },
-        opt_errorCallback || function() {});
+    if (opt_errorCallback)
+      opt_errorCallback();
     return;
   }
 
@@ -292,7 +275,6 @@
   this.hasChildren = false;
 
   this.addEventListener('expand', this.onExpand_.bind(this), false);
-  var volumeManager = VolumeManager.getInstance();
   var icon = this.querySelector('.icon');
   icon.classList.add('volume-icon');
   var iconType = PathUtil.getRootType(path);
@@ -309,7 +291,7 @@
         if (!PathUtil.isUnmountableByUser(path))
           return;
 
-        volumeManager.unmount(path, function() {}, function() {});
+        tree.volumeManager.unmount(path, function() {}, function() {});
       }.bind(this));
 
   if (this.parentTree_.contextMenuForSubitems)
@@ -373,7 +355,6 @@
     recursive, opt_successCallback, opt_errorCallback) {
   DirectoryTreeUtil.updateSubDirectories(
       this,
-      this.directoryModel_,
       function(entries) {
         this.entries_ = entries;
         this.redrawSubDirectoryList_(recursive);
@@ -455,10 +436,11 @@
  * Decorates an element.
  * @param {HTMLElement} el Element to be DirectoryTree.
  * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ * @param {VolumeManager} volumeManager VolumeManager of the system.
  */
-DirectoryTree.decorate = function(el, directoryModel) {
+DirectoryTree.decorate = function(el, directoryModel, volumeManager) {
   el.__proto__ = DirectoryTree.prototype;
-  (/** @type {DirectoryTree} */ el).decorate(directoryModel);
+  (/** @type {DirectoryTree} */ el).decorate(directoryModel, volumeManager);
 };
 
 DirectoryTree.prototype = {
@@ -471,9 +453,31 @@
    */
   set expanded(value) {},
 
+  /**
+   * The DirectoryEntry corresponding to this DirectoryItem. This may be
+   * a dummy DirectoryEntry.
+   * @type {DirectoryEntry|Object}
+   * @override
+   **/
+  get entry() {
+    return this.dirEntry_;
+  },
+
+  /**
+   * The DirectoryModel this tree corresponds to.
+   * @type {DirectoryModel}
+   */
   get directoryModel() {
     return this.directoryModel_;
-  }
+  },
+
+  /**
+   * The VolumeManager instance of the system.
+   * @type {VolumeManager}
+   */
+  get volumeManager() {
+    return this.volumeManager_;
+  },
 };
 
 cr.defineProperty(DirectoryTree, 'contextMenuForSubitems', cr.PropertyKind.JS);
@@ -481,11 +485,13 @@
 /**
  * Decorates an element.
  * @param {DirectoryModel} directoryModel Current DirectoryModel.
+ * @param {VolumeManager} volumeManager VolumeManager of the system.
  */
-DirectoryTree.prototype.decorate = function(directoryModel) {
+DirectoryTree.prototype.decorate = function(directoryModel, volumeManager) {
   cr.ui.Tree.prototype.decorate.call(this);
 
   this.directoryModel_ = directoryModel;
+  this.volumeManager_ = volumeManager;
   this.entries_ = DirectoryTreeUtil.generateTopLevelEntries();
 
   this.fileFilter_ = this.directoryModel_.getFileFilter();
@@ -514,7 +520,13 @@
   this.scrollBar_ = MainPanelScrollBar();
   this.scrollBar_.initialize(this.parentNode, this);
 
+  // Once, draws the list with the fake '/drive/' entry.
   this.redraw(false /* recursive */);
+  // Resoves 'My Drive' entry and replaces the fake with the true one.
+  this.maybeResolveMyDriveRoot_(function() {
+    // After the true entry is resolved, draws the list again.
+    this.redraw(true /* recursive */);
+  }.bind(this));
 };
 
 /**
@@ -527,20 +539,53 @@
   if (!DirectoryTreeUtil.isEligiblePathForDirectoryTree(entry.fullPath))
     return;
 
-  if (this.selectedItem && util.isSameEntry(entry, this.selectedItem.entry))
-    return;
+  this.maybeResolveMyDriveRoot_(function() {
+    if (this.selectedItem && util.isSameEntry(entry, this.selectedItem.entry))
+      return;
 
-  if (DirectoryTreeUtil.searchAndSelectByEntry(this.items, entry))
-    return;
+    if (DirectoryTreeUtil.searchAndSelectByEntry(this.items, entry))
+      return;
 
-  this.selectedItem = null;
-  this.updateSubDirectories(
-      false /* recursive */,
-      // Success callback, failure is not handled.
-      function() {
-        if (!DirectoryTreeUtil.searchAndSelectByEntry(this.items, entry))
-          this.selectedItem = null;
-      }.bind(this));
+    this.selectedItem = null;
+    this.updateSubDirectories(
+        false /* recursive */,
+        // Success callback, failure is not handled.
+        function() {
+          if (!DirectoryTreeUtil.searchAndSelectByEntry(this.items, entry))
+            this.selectedItem = null;
+        }.bind(this));
+  }.bind(this));
+};
+
+/**
+ * Resolves the My Drive root's entry, if it is a fake. If the entry is already
+ * resolved to a DirectoryEntry, completionCallback() will be called
+ * immediately.
+ * @param {function()} completionCallback Called when the resolving is
+ *     done (or the entry is already resolved), regardless if it is
+ *     successfully done or not.
+ * @private
+ */
+DirectoryTree.prototype.maybeResolveMyDriveRoot_ = function(
+    completionCallback) {
+  var myDriveItem = this.items[0];
+  if (!util.isFakeDirectoryEntry(myDriveItem.entry)) {
+    // The entry is already resolved. Don't need to try again.
+    completionCallback();
+    return;
+  }
+
+  // The entry is a fake.
+  this.directoryModel_.resolveDirectory(
+      myDriveItem.fullPath,
+      function(entry) {
+        if (!util.isFakeDirectoryEntry(entry)) {
+          myDriveItem.dirEntry_ = entry;
+        }
+
+        completionCallback();
+      },
+      completionCallback);
 };
 
 /**
@@ -554,7 +599,6 @@
   var myDriveItem = this.items[0];
   DirectoryTreeUtil.updateSubDirectories(
       myDriveItem,
-      this.directoryModel_,
       function(entries) {
         this.entries_ = entries;
         this.redraw(recursive);
diff --git a/chrome/browser/resources/file_manager/js/drive_banners.js b/chrome/browser/resources/file_manager/js/drive_banners.js
index d439497..7bd1bcf 100644
--- a/chrome/browser/resources/file_manager/js/drive_banners.js
+++ b/chrome/browser/resources/file_manager/js/drive_banners.js
@@ -254,8 +254,8 @@
 
   if (this.warningDismissedCounter_) {
     if (this.warningDismissedCounter_ ==
-            sizeStats.totalSizeKB && // Quota had not changed
-        sizeStats.remainingSizeKB / sizeStats.totalSizeKB < 0.15) {
+            sizeStats.totalSize && // Quota had not changed
+        sizeStats.remainingSize / sizeStats.totalSize < 0.15) {
       // Since the last dismissal decision the quota has not changed AND
       // the user did not free up significant space. Obey the dismissal.
       show = false;
@@ -274,7 +274,7 @@
     var text = this.document_.createElement('div');
     text.className = 'drive-text';
     text.textContent = strf('DRIVE_SPACE_AVAILABLE_LONG',
-        util.bytesToString(sizeStats.remainingSizeKB * 1024));
+        util.bytesToString(sizeStats.remainingSize));
     box.appendChild(text);
 
     var link = this.document_.createElement('a');
@@ -291,7 +291,7 @@
       window.localStorage[WARNING_DISMISSED_KEY] = total;
       box.hidden = true;
       this.requestRelayout_(100);
-    }.bind(this, sizeStats.totalSizeKB));
+    }.bind(this, sizeStats.totalSize));
   }
 
   if (box.hidden != !show) {
@@ -348,12 +348,10 @@
     chrome.fileBrowserPrivate.getSizeStats(
         util.makeFilesystemUrl(self.directoryModel_.getCurrentRootPath()),
         function(result) {
-          var offerSpaceKb = util.boardIs('link') ?
-              1024 * 1024 * 1024 :  // 1TB.
-              100 * 1024 * 1024;  // 100GB.
-          if (result && result.totalSizeKB >= offerSpaceKb) {
+          var offerSpaceGB =
+              util.boardIs('link') ? 1024 /* 1TB */ : 100 /* 100GB */;
+          if (result && result.totalSize >= offerSpaceGB * 1024 * 1024 * 1024)
             self.useNewWelcomeBanner_ = false;
-          }
           self.maybeShowWelcomeBanner_();
         });
   } else {
@@ -508,10 +506,11 @@
           // the file system size. Just ignore it.
           return;
         }
-
         // sizeStats is undefined, if some error occurs.
-        var remainingRatio = (sizeStats && sizeStats.totalSizeKB > 0) ?
-            (sizeStats.remainingSizeKB / sizeStats.totalSizeKB) : 1;
+        if (!sizeStats || sizeStats.totalSize == 0)
+          return;
+
+        var remainingRatio = sizeStats.remainingSize / sizeStats.totalSize;
         var isLowDiskSpace = remainingRatio < threshold;
         if (root == RootDirectory.DOWNLOADS)
           self.showLowDownloadsSpaceWarning_(isLowDiskSpace);
diff --git a/chrome/browser/resources/file_manager/js/file_copy_manager.js b/chrome/browser/resources/file_manager/js/file_copy_manager.js
index f374a3d..908804a 100644
--- a/chrome/browser/resources/file_manager/js/file_copy_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_copy_manager.js
@@ -56,6 +56,93 @@
 };
 
 /**
+ * Copies source to parent with the name newName recursively.
+ *
+ * @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(util.EntryChangedKind, Entry)} entryChangedCallback
+ *     Callback invoked when an entry is changed.
+ * @param {function(Entry, number)} progressCallback Callback invoked
+ *     periodically during the copying. It takes source and the number of
+ *     copied bytes since the last invocation.
+ * @param {function(Entry)} successCallback Callback invoked when the copy
+ *     is successfully done with the entry 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.copyRecursively = function(
+    source, parent, newName, entryChangedCallback, progressCallback,
+    successCallback, errorCallback) {
+  // Notify that the copy begins for each entry.
+  progressCallback(source, 0);
+
+  // If the entry is a file, redirect it to copyFile_().
+  if (source.isFile) {
+    return fileOperationUtil.copyFile_(
+        source, parent, newName, progressCallback,
+        function(entry) {
+          entryChangedCallback(util.EntryChangedKind.CREATED, entry);
+          successCallback(entry);
+        },
+        errorCallback);
+  }
+
+  // Hereafter, the source is directory.
+  var cancelRequested = false;
+  var cancelCallback = null;
+
+  // First, we create the directory copy.
+  parent.getDirectory(
+      newName, {create: true, exclusive: true},
+      function(dirEntry) {
+        entryChangedCallback(util.EntryChangedKind.CREATED, dirEntry);
+        if (cancelRequested) {
+          errorCallback(util.createFileError(FileError.ABORT_ERR));
+          return;
+        }
+
+        // Iterate on children, and copy them recursively.
+        util.forEachDirEntry(
+            source,
+            function(child, callback) {
+              if (cancelRequested) {
+                errorCallback(util.createFileError(FileError.ABORT_ERR));
+                return;
+              }
+
+              cancelCallback = fileOperationUtil.copyRecursively(
+                  child, dirEntry, child.name, entryChangedCallback,
+                  progressCallback,
+                  function() {
+                    cancelCallback = null;
+                    callback();
+                  },
+                  function(error) {
+                    cancelCallback = null;
+                    errorCallback(error);
+                  });
+            },
+            function() {
+              successCallback(dirEntry);
+            },
+            errorCallback);
+      },
+      errorCallback);
+
+  return function() {
+    cancelRequested = true;
+    if (cancelCallback) {
+      cancelCallback();
+      cancelCallback = null;
+    }
+  };
+};
+
+/**
  * Copies a file from source to the parent directory with newName.
  * See also copyFileByStream_ and copyFileOnDrive_ for the implementation
  * details.
@@ -72,11 +159,12 @@
  *     is successfully done with the entry of the created file.
  * @param {function(FileError)} errorCallback Callback invoked when an error
  *     is found.
- * @return {function()} Callback to cancle the current file copy operation.
+ * @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
  */
-fileOperationUtil.copyFile = function(
+fileOperationUtil.copyFile_ = function(
     source, parent, newName, progressCallback, successCallback, errorCallback) {
   if (!PathUtil.isDriveBasedPath(source.fullPath) &&
       !PathUtil.isDriveBasedPath(parent.fullPath)) {
@@ -422,14 +510,14 @@
 
 /**
  * Dispatches an event to notify that an entry is changed (created or deleted).
- * @param {util.EntryChangedType} type The enum to represent if the entry
- *     is created or deleted.
+ * @param {util.EntryChangedKind} kind The enum to represent if the entry is
+ *     created or deleted.
  * @param {Entry} entry The changed entry.
  */
 FileCopyManager.EventRouter.prototype.sendEntryChangedEvent = function(
-    type, entry) {
+    kind, entry) {
   var event = new cr.Event('entry-changed');
-  event.type = type;
+  event.kind = kind;
   event.entry = entry;
   this.dispatchEvent(event);
 };
@@ -457,33 +545,48 @@
  * Tasks may be added while the queue is being serviced.  Though a
  * cancel operation cancels everything in the queue.
  *
+ * @param {Array.<Entry>} sourceEntries Array of source entries.
  * @param {DirectoryEntry} targetDirEntry Target directory.
- * @param {DirectoryEntry=} opt_zipBaseDirEntry Base directory dealt as a root
- *     in ZIP archive.
  * @constructor
  */
-FileCopyManager.Task = function(targetDirEntry, opt_zipBaseDirEntry) {
+FileCopyManager.Task = function(sourceEntries, targetDirEntry) {
+  this.sourceEntries = sourceEntries;
   this.targetDirEntry = targetDirEntry;
-  this.zipBaseDirEntry = opt_zipBaseDirEntry;
-  this.originalEntries = null;
 
   // TODO(hidehiko): When we support recursive copy, we should be able to
   // rely on originalEntries. Then remove this.
   this.entries = [];
 
   /**
-   * The index of entries being processed. The entries should be processed
-   * from 0, so this is also the number of completed entries.
+   * The number of entries, whose processing is completed.
    * @type {number}
    */
-  this.entryIndex = 0;
+  this.numCompletedEntries = 0;
   this.totalBytes = 0;
   this.completedBytes = 0;
 
+  /**
+   * The entry currently being processed.
+   * @type {Entry}
+   */
+  this.processingEntry = null;
+
   this.deleteAfterCopy = false;
   this.move = false;
   this.zip = 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
@@ -494,36 +597,35 @@
 };
 
 /**
- * @param {Array.<Entry>} entries Entries.
  * @param {function()} callback When entries resolved.
  */
-FileCopyManager.Task.prototype.setEntries = function(entries, callback) {
-  this.originalEntries = entries;
-
+FileCopyManager.Task.prototype.initialize = function(callback) {
   // When moving directories, FileEntry.moveTo() is used if both source
   // and target are on Drive. There is no need to recurse into directories.
-  util.recurseAndResolveEntries(entries, !this.move, function(result) {
-    if (this.move) {
-      // 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.entries = result.dirEntries.concat(result.fileEntries).sort(
-          function(entry1, entry2) {
-            return entry2.fullPath.length - entry1.fullPath.length;
-          });
-    } else {
-      // Copying tasks are recursively processed. So, directories must be
-      // processed earlier than their child files. Since
-      // util.recurseAndResolveEntries is already listing entries in the
-      // recursive traversal order, we just keep the ordering.
-      this.entries = result.dirEntries.concat(result.fileEntries);
-    }
+  util.recurseAndResolveEntries(
+      this.sourceEntries, !this.move,
+      function(result) {
+        if (this.move) {
+          // 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.entries = result.dirEntries.concat(result.fileEntries).sort(
+              function(entry1, entry2) {
+                return entry2.fullPath.length - entry1.fullPath.length;
+              });
+        } else {
+          // Copying tasks are recursively processed. So, directories must be
+          // processed earlier than their child files. Since
+          // util.recurseAndResolveEntries is already listing entries in the
+          // recursive traversal order, we just keep the ordering.
+          this.entries = result.dirEntries.concat(result.fileEntries);
+        }
 
-    this.totalBytes = result.fileBytes;
-    callback();
-  }.bind(this));
+        this.totalBytes = result.fileBytes;
+        callback();
+      }.bind(this));
 };
 
 /**
@@ -564,6 +666,357 @@
 };
 
 /**
+ * Requests cancellation of this task.
+ * When the cancellation is done, it is notified via callbacks of run().
+ */
+FileCopyManager.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(FileCopyManager.Error)} errorCallback Callback run on error.
+ */
+FileCopyManager.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 {FileCopyManager.Task}
+ */
+FileCopyManager.CopyTask = function(sourceEntries, targetDirEntry) {
+  FileCopyManager.Task.call(this, sourceEntries, targetDirEntry);
+};
+
+/**
+ * Extends FileCopyManager.Task.
+ */
+FileCopyManager.CopyTask.prototype.__proto__ = FileCopyManager.Task.prototype;
+
+/**
+ * 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(FileCopyManager.Error)} errorCallback On error.
+ * @override
+ */
+FileCopyManager.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.entries.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 FileCopyManager.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 FileCopyManager.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR,
+              util.createFileError(FileError.ABORT_ERR)));
+          return;
+        }
+        progressCallback();
+        this.cancelCallback_ = FileCopyManager.CopyTask.processEntry_(
+            entry, this.targetDirEntry,
+            function(type, entry) {
+              this.numCompletedEntries++;
+              entryChangedCallback(type, entry);
+            }.bind(this),
+            function(entry, size) {
+              this.processingEntry = entry;
+              this.updateFileCopyProgress(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(util.EntryChangedKind, Entry)} entryChangedCallback
+ *     Callback invoked when an entry is changed.
+ * @param {function(Entry, number)} progressCallback Callback invoked
+ *     periodically during the copying.
+ * @param {function()} successCallback On success.
+ * @param {function(FileCopyManager.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
+ */
+FileCopyManager.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 FileCopyManager.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR,
+              util.createFileError(FileError.ABORT_ERR)));
+          return;
+        }
+
+        cancelCallback = fileOperationUtil.copyRecursively(
+            sourceEntry, destinationEntry, destinationName,
+            entryChangedCallback, progressCallback,
+            function(entry) {
+              cancelCallback = null;
+              successCallback();
+            },
+            function(error) {
+              cancelCallback = null;
+              errorCallback(new FileCopyManager.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 {FileCopyManager.Task}
+ */
+FileCopyManager.MoveTask = function(sourceEntries, targetDirEntry) {
+  FileCopyManager.Task.call(this, sourceEntries, targetDirEntry);
+  // TODO(hidehiko): We should handle dispatching copy/move/zip more nicely.
+  this.move = true;
+};
+
+/**
+ * Extends FileCopyManager.Task.
+ */
+FileCopyManager.MoveTask.prototype.__proto__ = FileCopyManager.Task.prototype;
+
+/**
+ * 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(FileCopyManager.Error)} errorCallback On error.
+ * @override
+ */
+FileCopyManager.MoveTask.prototype.run = function(
+    entryChangedCallback, progressCallback, successCallback, errorCallback) {
+  if (this.entries.length == 0) {
+    successCallback();
+    return;
+  }
+
+  AsyncUtil.forEach(
+      this.entries,
+      function(callback, entry, index) {
+        if (this.cancelRequested_) {
+          errorCallback(new FileCopyManager.Error(
+              util.FileOperationErrorType.FILESYSTEM_ERROR,
+              util.createFileError(FileError.ABORT_ERR)));
+          return;
+        }
+        this.processingEntry = entry;
+        progressCallback();
+        FileCopyManager.MoveTask.processEntry_(
+            entry, this.targetDirEntry, entryChangedCallback,
+            function() {
+              this.numCompletedEntries++;
+              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(FileCopyManager.Error)} errorCallback On error.
+ * @private
+ */
+FileCopyManager.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 FileCopyManager.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 {FileCopyManager.Task}
+ */
+FileCopyManager.ZipTask = function(
+    sourceEntries, targetDirEntry, zipBaseDirEntry) {
+  FileCopyManager.Task.call(this, sourceEntries, targetDirEntry);
+  this.zipBaseDirEntry = zipBaseDirEntry;
+  this.zip = true;
+};
+
+/**
+ * Extends FileCopyManager.Task.
+ */
+FileCopyManager.ZipTask.prototype.__proto__ = FileCopyManager.Task.prototype;
+
+/**
+ * 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(FileCopyManager.Error)} errorCallback On error.
+ * @override
+ */
+FileCopyManager.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.completedBytes = this.totalBytes;
+        progressCallback();
+
+        fileOperationUtil.zipSelection(
+            this.entries,
+            this.zipBaseDirEntry,
+            destPath,
+            function(entry) {
+              entryChangedCallback(util.EntryChangedKind.CREATE, entry);
+              successCallback();
+            },
+            function(error) {
+              errorCallback(new FileCopyManager.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.
@@ -581,22 +1034,6 @@
 // FileCopyManager methods.
 
 /**
- * Initializes the filesystem if it is not done yet.
- * @param {function()} callback Completion callback.
- */
-FileCopyManager.prototype.initialize = function(callback) {
-  // Already initialized.
-  if (this.root_) {
-    callback();
-    return;
-  }
-  chrome.fileBrowserPrivate.requestFileSystem(function(filesystem) {
-    this.root_ = filesystem.root;
-    callback();
-  }.bind(this));
-};
-
-/**
  * Called before a new method is run in the manager. Prepares the manager's
  * state for running a new method.
  */
@@ -632,12 +1069,12 @@
   for (var i = 0; i < this.copyTasks_.length; i++) {
     var task = this.copyTasks_[i];
     rv.totalItems += task.entries.length;
-    rv.completedItems += task.entryIndex;
+    rv.completedItems += task.numCompletedEntries;
 
     rv.totalBytes += task.totalBytes;
     rv.completedBytes += task.completedBytes;
 
-    var numPendingEntries = task.entries.length - task.entryIndex;
+    var numPendingEntries = task.entries.length - task.numCompletedEntries;
     if (task.zip) {
       rv.pendingZips += numPendingEntries;
     } else if (task.move || task.deleteAfterCopy) {
@@ -646,8 +1083,8 @@
       rv.pendingCopies += numPendingEntries;
     }
 
-    if (numPendingEntries == 1)
-      pendingEntry = task.entries[task.entries.length - 1];
+    if (task.processingEntry)
+      pendingEntry = task.processingEntry;
   }
 
   if (rv.totalItems - rv.completedItems == 1 && pendingEntry)
@@ -733,6 +1170,8 @@
   // Otherwise call it right now.
   if (this.copyTasks_.length == 0)
     this.doCancel_();
+  else
+    this.copyTasks_[0].requestCancel();
 };
 
 /**
@@ -764,75 +1203,71 @@
 /**
  * Kick off pasting.
  *
- * @param {Array.<string>} files Pathes of source files.
- * @param {Array.<string>} directories Pathes of source directories.
- * @param {boolean} isCut If the source items are removed from original
- *     location.
- * @param {string} targetPath Target path.
+ * @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.
  */
-FileCopyManager.prototype.paste = function(
-    files, directories, isCut, targetPath) {
-  var self = this;
+FileCopyManager.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(),
+        new FileCopyManager.Error(
+            util.FileOperationErrorType.FILESYSTEM_ERROR, error));
+  }.bind(this);
+
+  var targetEntry = null;
   var entries = [];
-  var added = 0;
-  var total;
 
-  var steps = {
-    start: function() {
-      // Filter entries.
-      var entryFilterFunc = function(entry) {
-        if (entry == '')
-          return false;
-        if (isCut && entry.replace(/\/[^\/]+$/, '') == targetPath)
-          // Moving to the same directory is a redundant operation.
-          return false;
-        return true;
-      };
-      directories = directories ? directories.filter(entryFilterFunc) : [];
-      files = files ? files.filter(entryFilterFunc) : [];
+  // 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;
+          }
 
-      // Check the number of filtered entries.
-      total = directories.length + files.length;
-      if (total == 0)
+          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;
-
-      // Retrieve entries.
-      util.getDirectories(self.root_, {create: false}, directories,
-                          steps.onEntryFound, steps.onPathError);
-      util.getFiles(self.root_, {create: false}, files,
-                    steps.onEntryFound, steps.onPathError);
-    },
-
-    onEntryFound: function(entry) {
-      // When getDirectories/getFiles finish, they call addEntry with null.
-      // We don't want to add null to our entries.
-      if (entry == null)
-        return;
-      entries.push(entry);
-      added++;
-      if (added == total)
-        steps.onSourceEntriesFound();
-    },
-
-    onSourceEntriesFound: function() {
-      self.root_.getDirectory(targetPath, {},
-                              steps.onTargetEntryFound, steps.onPathError);
-    },
-
-    onTargetEntryFound: function(targetEntry) {
-      self.queueCopy_(targetEntry, entries, isCut);
-    },
-
-    onPathError: function(err) {
-      self.eventRouter_.sendProgressEvent(
-          'ERROR',
-          self.getStatus(),
-          new FileCopyManager.Error(
-              util.FileOperationErrorType.FILESYSTEM_ERROR, err));
     }
-  };
 
-  steps.start();
+    this.queueCopy_(targetEntry, entries, isMove);
+  }.bind(this));
 };
 
 /**
@@ -855,37 +1290,40 @@
  *
  * @param {DirectoryEntry} targetDirEntry Target directory.
  * @param {Array.<Entry>} entries Entries to copy.
- * @param {boolean} deleteAfterCopy In case of move.
+ * @param {boolean} isMove In case of move.
  * @return {FileCopyManager.Task} Copy task.
  * @private
  */
 FileCopyManager.prototype.queueCopy_ = function(
-    targetDirEntry, entries, deleteAfterCopy) {
-  var self = this;
+    targetDirEntry, entries, isMove) {
   // When copying files, null can be specified as source directory.
-  var copyTask = new FileCopyManager.Task(targetDirEntry);
-  if (deleteAfterCopy) {
+  var task;
+  if (isMove) {
     if (this.isMovable(entries[0], targetDirEntry)) {
-      copyTask.move = true;
+      task = new FileCopyManager.MoveTask(entries, targetDirEntry);
     } else {
-      copyTask.deleteAfterCopy = true;
+      task = new FileCopyManager.CopyTask(entries, targetDirEntry);
+      task.deleteAfterCopy = true;
     }
+  } else {
+    task = new FileCopyManager.CopyTask(entries, targetDirEntry);
   }
-  copyTask.setEntries(entries, function() {
-    self.copyTasks_.push(copyTask);
-    self.maybeScheduleCloseBackgroundPage_();
-    if (self.copyTasks_.length == 1) {
-      // Assume self.cancelRequested_ == false.
+
+  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!
-      self.serviceAllTasks_();
+      this.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());
+      this.eventRouter_.sendProgressEvent('PROGRESS', this.getStatus());
     }
-  });
+  }.bind(this));
 
-  return copyTask;
+  return task;
 };
 
 /**
@@ -901,8 +1339,8 @@
     self.eventRouter_.sendProgressEvent('PROGRESS', self.getStatus());
   };
 
-  var onEntryChanged = function(type, entry) {
-    self.eventRouter_.sendEntryChangedEvent(type, entry);
+  var onEntryChanged = function(kind, entry) {
+    self.eventRouter_.sendEntryChangedEvent(kind, entry);
   };
 
   var onTaskError = function(err) {
@@ -932,362 +1370,15 @@
     // big task logically, so there is only one BEGIN/SUCCESS event pair for
     // these continuous tasks.
     self.eventRouter_.sendProgressEvent('PROGRESS', self.getStatus());
-
-    self.serviceTask_(self.copyTasks_[0], onEntryChanged, onTaskProgress,
-                      onTaskSuccess, onTaskError);
+    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());
-  this.serviceTask_(this.copyTasks_[0], onEntryChanged, onTaskProgress,
-                    onTaskSuccess, onTaskError);
-};
-
-/**
- * Runs a given task.
- * Note that the responsibility of this method is just dispatching to the
- * appropriate serviceXxxTask_() method.
- * TODO(hidehiko): Remove this method by introducing FileCopyManager.Task.run()
- *     (crbug.com/246976).
- *
- * @param {FileCopyManager.Task} task A task to be run.
- * @param {function(util.EntryChangedType, 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(FileCopyManager.Error)} errorCallback Callback run on error.
- * @private
- */
-FileCopyManager.prototype.serviceTask_ = function(
-    task, entryChangedCallback, progressCallback,
-    successCallback, errorCallback) {
-  if (task.zip)
-    this.serviceZipTask_(task, entryChangedCallback, progressCallback,
-                         successCallback, errorCallback);
-  else if (task.move)
-    this.serviceMoveTask_(task, entryChangedCallback, progressCallback,
-                          successCallback, errorCallback);
-  else
-    this.serviceCopyTask_(task, entryChangedCallback, progressCallback,
-                          successCallback, errorCallback);
-};
-
-/**
- * Service all entries in the copy (and move) task.
- * Note: this method contains also the operation of "Move" due to historical
- * reason.
- *
- * @param {FileCopyManager.Task} task A copy task to be run.
- * @param {function(util.EntryChangedType, 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(FileCopyManager.Error)} errorCallback On error.
- * @private
- */
-FileCopyManager.prototype.serviceCopyTask_ = function(
-    task, entryChangedCallback, progressCallback, successCallback,
-    errorCallback) {
-  // TODO(hidehiko): We should be able to share the code to iterate on entries
-  // with serviceMoveTask_().
-  if (task.entries.length == 0) {
-    successCallback();
-    return;
-  }
-
-  var self = this;
-
-  var deleteOriginals = function() {
-    var count = task.originalEntries.length;
-
-    var onEntryDeleted = function(entry) {
-      entryChangedCallback(util.EntryChangedType.DELETED, entry);
-      count--;
-      if (!count)
-        successCallback();
-    };
-
-    var onFilesystemError = function(err) {
-      errorCallback(new FileCopyManager.Error(
-          util.FileOperationErrorType.FILESYSTEM_ERROR, err));
-    };
-
-    for (var i = 0; i < task.originalEntries.length; i++) {
-      var entry = task.originalEntries[i];
-      util.removeFileOrDirectory(
-          entry, onEntryDeleted.bind(self, entry), onFilesystemError);
-    }
-  };
-
-  var onEntryServiced = function() {
-    task.entryIndex++;
-
-    // We should not dispatch a PROGRESS event when there is no pending items
-    // in the task.
-    if (task.entryIndex >= task.entries.length) {
-      if (task.deleteAfterCopy) {
-        deleteOriginals();
-      } else {
-        successCallback();
-      }
-      return;
-    }
-
-    progressCallback();
-    self.processCopyEntry_(
-        task, task.entries[task.entryIndex], entryChangedCallback,
-        progressCallback, onEntryServiced, errorCallback);
-  };
-
-  this.processCopyEntry_(
-      task, task.entries[task.entryIndex], entryChangedCallback,
-      progressCallback, onEntryServiced, errorCallback);
-};
-
-/**
- * Copies the next entry in a given task.
- * TODO(olege): Refactor this method into a separate class.
- *
- * @param {FileManager.Task} task A task.
- * @param {Entry} sourceEntry An entry to be copied.
- * @param {function(util.EntryChangedType, 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(FileCopyManager.Error)} errorCallback On error.
- * @private
- */
-FileCopyManager.prototype.processCopyEntry_ = function(
-    task, sourceEntry, entryChangedCallback, progressCallback, successCallback,
-    errorCallback) {
-  if (this.maybeCancel_())
-    return;
-
-  var self = this;
-
-  // |sourceEntry.originalSourcePath| is set in util.recurseAndResolveEntries.
-  var sourcePath = sourceEntry.originalSourcePath;
-  if (sourceEntry.fullPath.substr(0, sourcePath.length) != sourcePath) {
-    // We found an entry in the list that is not relative to the base source
-    // path, something is wrong.
-    errorCallback(new FileCopyManager.Error(
-        util.FileOperationErrorType.UNEXPECTED_SOURCE_FILE,
-        sourceEntry.fullPath));
-    return;
-  }
-
-  var targetDirEntry = task.targetDirEntry;
-  var originalPath = sourceEntry.fullPath.substr(sourcePath.length + 1);
-  originalPath = task.applyRenames(originalPath);
-
-  var onDeduplicated = function(targetRelativePath) {
-    var onCopyComplete = function(entry) {
-      entryChangedCallback(util.EntryChangedType.CREATED, entry);
-      successCallback();
-    };
-
-    var onFilesystemError = function(err) {
-      errorCallback(new FileCopyManager.Error(
-          util.FileOperationErrorType.FILESYSTEM_ERROR, err));
-    };
-
-    if (sourceEntry.isDirectory) {
-      // Copying the directory means just creating a new directory.
-      targetDirEntry.getDirectory(
-          targetRelativePath,
-          {create: true, exclusive: true},
-          function(targetEntry) {
-            if (targetRelativePath != originalPath) {
-              task.registerRename(originalPath, targetRelativePath);
-            }
-            onCopyComplete(targetEntry);
-          },
-          util.flog('Error getting dir: ' + targetRelativePath,
-                    onFilesystemError));
-    } else {
-      // Copy a file.
-      targetDirEntry.getDirectory(
-          PathUtil.dirname(targetRelativePath), {create: false},
-          function(dirEntry) {
-            self.cancelCallback_ = fileOperationUtil.copyFile(
-                sourceEntry, dirEntry, PathUtil.basename(targetRelativePath),
-                function(entry, size) {
-                  task.updateFileCopyProgress(size);
-                  progressCallback();
-                },
-                function(entry) {
-                  self.cancelCallback_ = null;
-                  onCopyComplete(entry);
-                },
-                function(error) {
-                  self.cancelCallback_ = null;
-                  onFilesystemError(error);
-                });
-          },
-          onFilesystemError);
-    }
-  };
-
-  fileOperationUtil.deduplicatePath(
-      targetDirEntry, originalPath, onDeduplicated, errorCallback);
-};
-
-/**
- * Moves all entries in the task.
- *
- * @param {FileCopyManager.Task} task A move task to be run.
- * @param {function(util.EntryChangedType, 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(FileCopyManager.Error)} errorCallback On error.
- * @private
- */
-FileCopyManager.prototype.serviceMoveTask_ = function(
-    task, entryChangedCallback, progressCallback, successCallback,
-    errorCallback) {
-  if (task.entries.length == 0) {
-    successCallback();
-    return;
-  }
-
-  this.processMoveEntry_(
-      task, task.entries[task.entryIndex], entryChangedCallback,
-      (function onCompleted() {
-        task.entryIndex++;
-
-        // We should not dispatch a PROGRESS event when there is no pending
-        // items in the task.
-        if (task.entryIndex >= task.entries.length) {
-          successCallback();
-          return;
-        }
-
-        // Move the next entry.
-        progressCallback();
-        this.processMoveEntry_(
-            task, task.entries[task.entryIndex], entryChangedCallback,
-            onCompleted.bind(this), errorCallback);
-      }).bind(this),
-      errorCallback);
-};
-
-/**
- * Moves the next entry in a given task.
- *
- * Implementation note: This method can be simplified more. For example, in
- * Task.setEntries(), the flag to recurse is set to false for move task,
- * so that all the entries' originalSourcePath should be
- * dirname(sourceEntry.fullPath).
- * Thus, targetRelativePath should contain exact one component. Also we can
- * skip applyRenames, because the destination directory always should be
- * task.targetDirEntry.
- * The unnecessary complexity is due to historical reason.
- * TODO(hidehiko): Refactor this method.
- *
- * @param {FileManager.Task} task A move task.
- * @param {Entry} sourceEntry An entry to be moved.
- * @param {function(util.EntryChangedType, Entry)} entryChangedCallback Callback
- *     invoked when an entry is changed.
- * @param {function()} successCallback On success.
- * @param {function(FileCopyManager.Error)} errorCallback On error.
- * @private
- */
-FileCopyManager.prototype.processMoveEntry_ = function(
-    task, sourceEntry, entryChangedCallback, successCallback, errorCallback) {
-  if (this.maybeCancel_())
-    return;
-
-  // |sourceEntry.originalSourcePath| is set in util.recurseAndResolveEntries.
-  var sourcePath = sourceEntry.originalSourcePath;
-  if (sourceEntry.fullPath.substr(0, sourcePath.length) != sourcePath) {
-    // We found an entry in the list that is not relative to the base source
-    // path, something is wrong.
-    errorCallback(new FileCopyManager.Error(
-        util.FileOperationErrorType.UNEXPECTED_SOURCE_FILE,
-        sourceEntry.fullPath));
-    return;
-  }
-
-  fileOperationUtil.deduplicatePath(
-      task.targetDirEntry,
-      task.applyRenames(sourceEntry.fullPath.substr(sourcePath.length + 1)),
-      function(targetRelativePath) {
-        var onFilesystemError = function(err) {
-          errorCallback(new FileCopyManager.Error(
-              util.FileOperationErrorType.FILESYSTEM_ERROR,
-              err));
-        };
-
-        task.targetDirEntry.getDirectory(
-            PathUtil.dirname(targetRelativePath), {create: false},
-            function(dirEntry) {
-              sourceEntry.moveTo(
-                  dirEntry, PathUtil.basename(targetRelativePath),
-                  function(targetEntry) {
-                    entryChangedCallback(
-                        util.EntryChangedType.CREATED, targetEntry);
-                    entryChangedCallback(
-                        util.EntryChangedType.DELETED, sourceEntry);
-                    successCallback();
-                  },
-                  onFilesystemError);
-            },
-            onFilesystemError);
-      },
-      errorCallback);
-};
-
-/**
- * Service a zip file creation task.
- *
- * @param {FileCopyManager.Task} task A zip task to be run.
- * @param {function(util.EntryChangedType, 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(FileCopyManager.Error)} errorCallback On error.
- * @private
- */
-FileCopyManager.prototype.serviceZipTask_ = function(
-    task, entryChangedCallback, progressCallback, successCallback,
-    errorCallback) {
-  // TODO(hidehiko): we should localize the name.
-  var destName = 'Archive';
-  if (task.originalEntries.length == 1) {
-    var entryPath = task.originalEntries[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(
-      task.targetDirEntry, destName + '.zip',
-      function(destPath) {
-        progressCallback();
-
-        fileOperationUtil.zipSelection(
-            task.entries,
-            task.zipBaseDirEntry,
-            destPath,
-            function(entry) {
-              entryChangedCallback(util.EntryChangedType.CREATE, entry);
-              successCallback();
-            },
-            function(error) {
-              errorCallback(new FileCopyManager.Error(
-                  util.FileOperationErrorType.FILESYSTEM_ERROR, error));
-            });
-      },
-      errorCallback);
+  this.copyTasks_[0].run(
+      onEntryChanged, onTaskProgress, onTaskSuccess, onTaskError);
 };
 
 /**
@@ -1399,7 +1490,7 @@
         entry,
         function(currentEntry) {
           this.eventRouter_.sendEntryChangedEvent(
-              util.EntryChangedType.DELETED, currentEntry);
+              util.EntryChangedKind.DELETED, currentEntry);
           onComplete();
         }.bind(this, entry),
         function(error) {
@@ -1418,13 +1509,10 @@
  */
 FileCopyManager.prototype.zipSelection = function(dirEntry, selectionEntries) {
   var self = this;
-  var zipTask = new FileCopyManager.Task(dirEntry, dirEntry);
+  var zipTask = new FileCopyManager.ZipTask(
+      selectionEntries, dirEntry, dirEntry);
   zipTask.zip = true;
-  zipTask.setEntries(selectionEntries, function() {
-    // 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.
-    zipTask.completedBytes = zipTask.totalBytes;
+  zipTask.initialize(function() {
     self.copyTasks_.push(zipTask);
     if (self.copyTasks_.length == 1) {
       // Assume self.cancelRequested_ == false.
diff --git a/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js b/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js
index 6642e7e..767aaad 100644
--- a/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js
+++ b/chrome/browser/resources/file_manager/js/file_copy_manager_wrapper.js
@@ -24,16 +24,13 @@
   this.pendingTasks_ = [];
 
   chrome.runtime.getBackgroundPage(function(backgroundPage) {
-    var fileCopyManager = backgroundPage.FileCopyManager.getInstance();
-    fileCopyManager.initialize(function() {
-      // Here the fileCopyManager is initialized. Keep the instance, and run
-      // pending tasks.
-      this.fileCopyManager_ = fileCopyManager;
-      for (var i = 0; i < this.pendingTasks_.length; i++) {
-        this.pendingTasks_[i](fileCopyManager);
-      }
-      this.pendingTasks_ = [];
-    }.bind(this));
+    this.fileCopyManager_ = backgroundPage.FileCopyManager.getInstance();
+
+    // Run pending tasks.
+    for (var i = 0; i < this.pendingTasks_.length; i++) {
+      this.pendingTasks_[i](this.fileCopyManager_);
+    }
+    this.pendingTasks_ = [];
   }.bind(this));
 }
 
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
index 9ef23dc..7297b23 100644
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_manager.js
@@ -246,10 +246,6 @@
       }.bind(this));
     }.bind(this));
 
-    // Removes the user data which is no longer used.
-    // TODO(yoshiki): Remove this in M31 http://crbug.com/268784/
-    chrome.storage.local.remove('folder-shortcuts-list');
-
     group.run(callback);
   };
 
@@ -271,10 +267,6 @@
       this.filesystem_ = filesystem;
       callback();
     }.bind(this));
-
-    // Mount Drive if enabled.
-    if (this.isDriveEnabled())
-      this.volumeManager_.mountDrive(function() {}, function() {});
   };
 
   /**
@@ -288,7 +280,7 @@
     this.grid_.startBatchUpdates();
 
     this.initFileList_();
-    this.setupCurrentDirectory_(true /* page loading */);
+    this.setupCurrentDirectory_();
 
     // PyAuto tests monitor this state by polling this variable
     this.__defineGetter__('workerInitialized_', function() {
@@ -389,12 +381,16 @@
         driveConnectionChangedHandler);
     driveConnectionChangedHandler();
 
-    // Set the initial focus and set it as a fallback.
-    this.document_.addEventListener('focusout', function(e) {
-      if (!e.relatedTarget)
-        setTimeout(this.refocus.bind(this), 0);
-    }.bind(this));
+    // 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_();
 
@@ -563,6 +559,11 @@
     CommandUtil.registerCommand(this.dialogContainer_, 'newfolder',
         Commands.newFolderCommand, this, this.directoryModel_);
 
+    // Required to handle the command outside of the container, on the footer.
+    // TODO(mtomasz): Remove after fixing crbug.com/275235.
+    CommandUtil.registerCommand(this.dialogDom_.querySelector('.dialog-footer'),
+        'newfolder', Commands.newFolderCommand, this, this.directoryModel_);
+
     CommandUtil.registerCommand(this.dialogContainer_, 'newwindow',
         Commands.newWindowCommand, this, this.directoryModel_);
 
@@ -683,8 +684,12 @@
     this.initializeQueue_.add(
         this.initPreferences_.bind(this), [], 'initPreferences');
     this.initializeQueue_.add(
+        this.initVolumeManager_.bind(this),
+        ['initPreferences'], 'initVolumeManager');
+    this.initializeQueue_.add(
         this.initFileSystem_.bind(this),
-        ['initGeneral', 'initPreferences'], 'initFileSystem');
+        ['initGeneral', 'initPreferences', 'initVolumeManager'],
+        'initFileSystem');
 
     this.initializeQueue_.run();
   };
@@ -716,7 +721,6 @@
    * @private
    */
   FileManager.prototype.initGeneral_ = function(callback) {
-    this.volumeManager_ = VolumeManager.getInstance();
     if (window.appState) {
       this.params_ = window.appState.params || {};
       this.defaultPath = window.appState.defaultPath;
@@ -752,6 +756,23 @@
   };
 
   /**
+   * Initializes the VolumeManager instance.
+   * @param {function()} callback Completion callback.
+   * @private
+   */
+  FileManager.prototype.initVolumeManager_ = function(callback) {
+    VolumeManager.getInstance(function(volumeManager) {
+      this.volumeManager_ = volumeManager;
+
+      // Mount Drive if enabled.
+      // TODO(hidehiko): Mounting state of Drive file system should be
+      // handled by C++ backend side.
+      volumeManager.setDriveEnabled(this.isDriveEnabled());
+      callback();
+    }.bind(this));
+  };
+
+  /**
    * 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
@@ -1090,9 +1111,7 @@
         this.fileWatcher_,
         this.metadataCache_,
         this.volumeManager_,
-        this.isDriveEnabled(),
         showSpecialSearchRoots);
-
     this.directoryModel_.start();
 
     this.folderShortcutsModel_ = new FolderShortcutsDataModel();
@@ -1183,10 +1202,13 @@
     DirectoryTree.decorate(this.directoryTree_, this.directoryModel_);
 
     this.navigationList_ = this.dialogDom_.querySelector('#volume-list');
-    NavigationList.decorate(this.navigationList_, this.directoryModel_);
+    NavigationList.decorate(this.navigationList_,
+                            this.volumeManager_,
+                            this.directoryModel_);
     this.navigationList_.fileManager = this;
     this.navigationList_.dataModel =
-        new NavigationListModel(this.directoryModel_.getRootsList(),
+        new NavigationListModel(this.filesystem_,
+                                this.directoryModel_.getRootsList(),
                                 this.folderShortcutsModel_);
 
     this.navigationList_.addEventListener(
@@ -1209,7 +1231,10 @@
    */
   FileManager.prototype.updateMiddleBarVisibility_ = function() {
     var currentPath = this.directoryModel_.getCurrentDirPath();
-    var visible = DirectoryTreeUtil.isEligiblePathForDirectoryTree(currentPath);
+    var driveStatus = this.volumeManager_.getDriveStatus();
+    var visible =
+        DirectoryTreeUtil.isEligiblePathForDirectoryTree(currentPath) &&
+        driveStatus == VolumeManager.DriveStatus.MOUNTED;
     this.dialogDom_.
         querySelector('.dialog-middlebar-contents').hidden = !visible;
     this.dialogDom_.querySelector('#middlebar-splitter').hidden = !visible;
@@ -1397,11 +1422,11 @@
    * @private
    */
   FileManager.prototype.onCopyManagerEntryChanged_ = function(event) {
-    var type = event.type;
+    var kind = event.kind;
     var entry = event.entry;
-    this.directoryModel_.onEntryChanged(type, entry);
+    this.directoryModel_.onEntryChanged(kind, entry);
 
-    if (type == util.EntryChangedType.CREATE && FileType.isImage(entry)) {
+    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();
@@ -1578,18 +1603,13 @@
    * Default path may also contain a file name. Freshly opened file manager
    * window has neither.
    *
-   * @param {boolean} pageLoading True if the page is loading,
-   *                              false if popping state.
    * @private
    */
-  FileManager.prototype.setupCurrentDirectory_ = function(pageLoading) {
+  FileManager.prototype.setupCurrentDirectory_ = function() {
     var path = location.hash ?  // Location hash has the highest priority.
         decodeURIComponent(location.hash.substr(1)) :
         this.defaultPath;
 
-    if (!pageLoading && path == this.directoryModel_.getCurrentDirPath())
-      return;
-
     if (!path) {
       path = PathUtil.DEFAULT_DIRECTORY;
     } else if (path.indexOf('/') == -1) {
@@ -1597,21 +1617,15 @@
       path = PathUtil.DEFAULT_DIRECTORY + '/' + path;
     }
 
-    // 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.
-    var invokeHandlers = pageLoading && (this.params_.action != 'select') &&
-        this.dialogType == DialogType.FULL_PAGE;
-
     if (PathUtil.getRootType(path) === RootType.DRIVE) {
       if (!this.isDriveEnabled()) {
         var leafName = path.substr(path.indexOf('/') + 1);
-        path = this.directoryModel_.getDefaultDirectory() + '/' + leafName;
-        this.finishSetupCurrentDirectory_(path, invokeHandlers);
+        path = PathUtil.DEFAULT_DIRECTORY + '/' + leafName;
+        this.finishSetupCurrentDirectory_(path);
         return;
       }
       if (this.volumeManager_.isMounted(RootDirectory.DRIVE)) {
-        this.finishSetupCurrentDirectory_(path, invokeHandlers);
+        this.finishSetupCurrentDirectory_(path);
         return;
       }
 
@@ -1623,36 +1637,37 @@
       this.volumeManager_.mountDrive(function() {
         tracker.stop();
         if (!tracker.hasChanged)
-          this.finishSetupCurrentDirectory_(path, invokeHandlers);
+          this.finishSetupCurrentDirectory_(path);
       }.bind(this), function(error) {
         tracker.stop();
       });
     } else {
-      this.finishSetupCurrentDirectory_(path, invokeHandlers);
+      this.finishSetupCurrentDirectory_(path);
     }
   };
 
   /**
    * @param {string} path Path to setup.
-   * @param {boolean} invokeHandlers If thrue and |path| points to a file
-   *     then default handler is triggered.
-   *
    * @private
    */
-  FileManager.prototype.finishSetupCurrentDirectory_ = function(
-      path, invokeHandlers) {
-    if (invokeHandlers) {
-      var onResolve = function(baseName, leafName, exists) {
-        var urls = null;
-        var action = null;
+  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.
-            urls = [];
-            action = 'gallery';
+            task = function() {
+              new FileTasks(this, this.params_).openGallery([]);
+            }.bind(this);
           }
         } else {
           // There are 3 ways we can get here:
@@ -1662,44 +1677,38 @@
           // 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.
-          if (FileType.isImageOrVideo(path)) {
-            urls = [util.makeFilesystemUrl(path)];
-            action = 'gallery';
-          }
-          if (FileType.getMediaType(path) == 'archive') {
-            urls = [util.makeFilesystemUrl(path)];
-            action = 'archives';
+          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 (urls) {
+        // 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);
-            var tasks = new FileTasks(this, this.params_);
-            if (action == 'gallery') {
-              tasks.openGallery(urls);
-            } else if (action == 'archives') {
-              tasks.mountArchives(urls);
-            }
+            task();
           }.bind(this);
           this.directoryModel_.addEventListener('scan-completed', listener);
         }
-      }.bind(this);
+        return;
+      }
 
-      this.directoryModel_.setupPath(path, onResolve);
-      return;
-    }
-
-    if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
-      this.directoryModel_.setupPath(path, function(basePath, leafName) {
+      if (this.dialogType == DialogType.SELECT_SAVEAS_FILE) {
         this.filenameInput_.value = leafName;
         this.selectDefaultPathInFilenameInput_();
-      }.bind(this));
-      return;
-    }
-
-    this.directoryModel_.setupPath(path);
+        return;
+      }
+    }.bind(this));
   };
 
   /**
@@ -1959,7 +1968,7 @@
       self.initDateTimeFormatters_();
       self.refreshCurrentDirectoryMetadata_();
 
-      self.directoryModel_.setDriveEnabled(self.isDriveEnabled());
+      self.volumeManager_.setDriveEnabled(self.isDriveEnabled());
 
       if (prefs.cellularDisabled)
         self.syncButton.setAttribute('checked', '');
@@ -2310,16 +2319,6 @@
    *                               changed.
    */
   FileManager.prototype.onDirectoryAction = function(entry) {
-    var mountError = this.volumeManager_.getMountError(
-        PathUtil.getRootPath(entry.fullPath));
-    if (mountError == VolumeManager.Error.UNKNOWN_FILESYSTEM) {
-      return this.butterBar_.show(ButterBar.Mode.ERROR,
-                                  str('UNKNOWN_FILESYSTEM_WARNING'));
-    } else if (mountError == VolumeManager.Error.UNSUPPORTED_FILESYSTEM) {
-      return this.butterBar_.show(ButterBar.Mode.ERROR,
-                                  str('UNSUPPORTED_FILESYSTEM_WARNING'));
-    }
-
     return this.directoryModel_.changeDirectory(entry.fullPath);
   };
 
@@ -2439,10 +2438,10 @@
   // TODO(haruki): Rename this method. "Drive" here does not refer
   // "Google Drive".
   FileManager.prototype.updateUnformattedDriveStatus_ = function() {
-    var volumeInfo = this.volumeManager_.getVolumeInfo_(
+    var volumeInfo = this.volumeManager_.getVolumeInfo(
         PathUtil.getRootPath(this.directoryModel_.getCurrentRootPath()));
 
-    if (volumeInfo.error) {
+    if (volumeInfo && volumeInfo.error) {
       this.dialogDom_.setAttribute('unformatted', '');
 
       var errorNode = this.dialogDom_.querySelector('#format-panel > .error');
@@ -2589,20 +2588,39 @@
       // case of success.
       nameNode.textContent = newName;
 
-      this.directoryModel_.doesExist(entry, newName, function(exists, isFile) {
-        if (!exists) {
-          var onError = function(err) {
-            this.alert.show(strf('ERROR_RENAMING', entry.name,
-                                 util.getFileErrorString(err.code)));
-          }.bind(this);
-          this.directoryModel_.renameEntry(entry, newName, onError.bind(this));
-        } else {
-          nameNode.textContent = entry.name;
-          var message = isFile ? 'FILE_ALREADY_EXISTS' :
-                                 'DIRECTORY_ALREADY_EXISTS';
-          this.alert.show(strf(message, newName));
-        }
-      }.bind(this));
+      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
diff --git a/chrome/browser/resources/file_manager/js/file_manager_commands.js b/chrome/browser/resources/file_manager/js/file_manager_commands.js
index 914c7c5..db2d454 100644
--- a/chrome/browser/resources/file_manager/js/file_manager_commands.js
+++ b/chrome/browser/resources/file_manager/js/file_manager_commands.js
@@ -7,36 +7,40 @@
 var CommandUtil = {};
 
 /**
- * Extracts path on which command event was dispatched.
+ * Extracts entry on which command event was dispatched.
  *
  * @param {DirectoryTree|DirectoryItem|NavigationList|HTMLLIElement|cr.ui.List}
  *     element Directory to extract a path from.
- * @return {?string} Path of the found node.
+ * @return {Entry} Entry of the found node.
  */
-CommandUtil.getCommandPath = function(element) {
+CommandUtil.getCommandEntry = function(element) {
   if (element instanceof NavigationList) {
     // element is a NavigationList.
-    return element.selectedItem;
+
+    /** @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);
-    return (index != -1) ? navigationList.dataModel.item(index) : null;
+    /** @type {NavigationModelItem} */
+    var item = (index != -1) ? navigationList.dataModel.item(index) : null;
+    return item && item.getCachedEntry();
   } else if (element instanceof DirectoryTree) {
     // element is a DirectoryTree.
-    var item = element.selectedItem;
-    return item && item.fullPath;
+    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 && element.entry.fullPath ||
-           element.fullPath;
+    return element.entry;
   } else if (cr.ui.List) {
     // element is a normal List (eg. the file list on the right panel).
     var entry = element.selectedItem;
-    return entry && entry.fullPath;
+    return entry;
   } else {
     console.warn('Unsupported element');
     return null;
@@ -48,8 +52,10 @@
  * @return {?RootType} Type of the found root.
  */
 CommandUtil.getCommandRootType = function(navigationList) {
-  var root = CommandUtil.getCommandPath(navigationList);
-  return root && PathUtil.isRootPath(root) && PathUtil.getRootType(root);
+  var root = CommandUtil.getCommandEntry(navigationList);
+  return root &&
+         PathUtil.isRootPath(root.fullPath) &&
+         PathUtil.getRootType(root.fullPath);
 };
 
 /**
@@ -174,9 +180,9 @@
    * @param {FileManager} fileManager The file manager instance.
    */
   execute: function(event, fileManager) {
-    var root = CommandUtil.getCommandPath(event.target);
+    var root = CommandUtil.getCommandEntry(event.target);
     if (root)
-      fileManager.unmountVolume(PathUtil.getRootPath(root));
+      fileManager.unmountVolume(PathUtil.getRootPath(root.fullPath));
   },
   /**
    * @param {Event} event Command event.
@@ -202,10 +208,10 @@
    * @param {FileManager} fileManager The file manager instance.
    */
   execute: function(event, fileManager) {
-    var root = CommandUtil.getCommandPath(event.target);
+    var root = CommandUtil.getCommandEntry(event.target);
 
     if (root) {
-      var url = util.makeFilesystemUrl(PathUtil.getRootPath(root));
+      var url = util.makeFilesystemUrl(PathUtil.getRootPath(root.fullPath));
       fileManager.confirm.show(
           loadTimeData.getString('FORMATTING_WARNING'),
           chrome.fileBrowserPrivate.formatDevice.bind(null, url));
@@ -217,10 +223,10 @@
    * @param {DirectoryModel} directoryModel The directory model instance.
    */
   canExecute: function(event, fileManager, directoryModel) {
-    var root = CommandUtil.getCommandPath(event.target);
+    var root = CommandUtil.getCommandEntry(event.target);
     var removable = root &&
-                    PathUtil.getRootType(root) == RootType.REMOVABLE;
-    var isReadOnly = root && directoryModel.isPathReadOnly(root);
+                    PathUtil.getRootType(root.fullPath) == RootType.REMOVABLE;
+    var isReadOnly = root && directoryModel.isPathReadOnly(root.fullPath);
     event.canExecute = removable && !isReadOnly;
     event.command.setHidden(!removable);
   }
@@ -235,7 +241,7 @@
    * @param {NavigationList} navigationList Target navigation list.
    */
   execute: function(event, navigationList) {
-    var root = CommandUtil.getCommandPath(navigationList);
+    var root = CommandUtil.getCommandEntry(navigationList);
     if (!root)
       return;
 
@@ -563,9 +569,9 @@
    * @param {FileManager} fileManager The file manager instance.
    */
   execute: function(event, fileManager) {
-    var path = CommandUtil.getCommandPath(event.target);
-    if (path)
-      fileManager.createFolderShortcut(path);
+    var entry = CommandUtil.getCommandEntry(event.target);
+    if (entry)
+      fileManager.createFolderShortcut(entry.fullPath);
   },
 
   /**
@@ -582,18 +588,21 @@
       return;
     }
 
-    var path = CommandUtil.getCommandPath(event.target);
-    var folderShortcutExists = path && fileManager.folderShortcutExists(path);
+    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) {
+    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 = path && PathUtil.isEligibleForFolderShortcut(path);
+    var eligible = entry &&
+                   PathUtil.isEligibleForFolderShortcut(entry.fullPath);
     event.canExecute =
         eligible && onlyOneFolderSelected && !folderShortcutExists;
     event.command.setHidden(!eligible || !onlyOneFolderSelected);
@@ -609,9 +618,9 @@
    * @param {FileManager} fileManager The file manager instance.
    */
   execute: function(event, fileManager) {
-    var path = CommandUtil.getCommandPath(event.target);
-    if (path)
-      fileManager.removeFolderShortcut(path);
+    var entry = CommandUtil.getCommandEntry(event.target);
+    if (entry)
+      fileManager.removeFolderShortcut(entry.fullPath);
   },
 
   /**
@@ -628,9 +637,10 @@
       return;
     }
 
-    var path = CommandUtil.getCommandPath(target);
-    var eligible = path && PathUtil.isEligibleForFolderShortcut(path);
-    var isShortcut = path && fileManager.folderShortcutExists(path);
+    var entry = CommandUtil.getCommandEntry(target);
+    var eligible = entry &&
+                   PathUtil.isEligibleForFolderShortcut(entry.fullPath);
+    var isShortcut = entry && fileManager.folderShortcutExists(entry.fullPath);
     event.canExecute = isShortcut && eligible;
     event.command.setHidden(!event.canExecute);
   }
diff --git a/chrome/browser/resources/file_manager/js/file_manager_pyauto.js b/chrome/browser/resources/file_manager/js/file_manager_pyauto.js
index 8d9d528..147d004 100644
--- a/chrome/browser/resources/file_manager/js/file_manager_pyauto.js
+++ b/chrome/browser/resources/file_manager/js/file_manager_pyauto.js
@@ -141,8 +141,13 @@
    */
   renameItem: function(name) {
     var entry = fileManager.getSelection().entries[0];
-    fileManager.directoryModel_.renameEntry(entry, name, pyautoAPI.sendDone_,
-        pyautoAPI.sendDone_);
+    util.rename(entry, name,
+                function(newEntry) {
+                  // Update directory model on success.
+                  fileManager.directoryModel_.onRenameEntry(
+                      entry, newEntry, pyautoAPI.sendDone_);
+                },
+                pyautoAPI.sendDone_);
   },
 
   /**
diff --git a/chrome/browser/resources/file_manager/js/file_tasks.js b/chrome/browser/resources/file_manager/js/file_tasks.js
index fd72362..8e908e6 100644
--- a/chrome/browser/resources/file_manager/js/file_tasks.js
+++ b/chrome/browser/resources/file_manager/js/file_tasks.js
@@ -136,6 +136,28 @@
 };
 
 /**
+ * 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.
@@ -286,7 +308,7 @@
     }.bind(this);
 
     this.checkAvailability_(function() {
-      chrome.fileBrowserPrivate.viewFiles(urls, callback);
+      util.viewFilesInBrowser(urls, callback);
     }.bind(this));
   }
 
@@ -315,11 +337,8 @@
  */
 FileTasks.prototype.executeInternal_ = function(taskId, urls) {
   this.checkAvailability_(function() {
-    var taskParts = taskId.split('|');
-    if (taskParts[0] == chrome.runtime.id && taskParts[1] == 'file') {
-      // For internal tasks we do not listen to the event to avoid
-      // handling the same task instance from multiple tabs.
-      // So, we manually execute the task.
+    if (FileTasks.isInternalTask_(taskId)) {
+      var taskParts = taskId.split('|');
       this.executeInternalTask_(taskParts[2], urls);
     } else {
       chrome.fileBrowserPrivate.executeTask(taskId, urls);
@@ -446,13 +465,7 @@
     return;
   }
 
-  if (id == 'view-pdf' || id == 'view-swf' || id == 'view-in-browser' ||
-      id == 'install-crx' || id.match(/^open-hosted-/) || id == 'watch') {
-    chrome.fileBrowserPrivate.viewFiles(urls, function(success) {
-      if (!success)
-        console.error('chrome.fileBrowserPrivate.viewFiles failed', urls);
-    });
-  }
+  console.error('Unexpected action ID: ' + id);
 };
 
 /**
@@ -551,7 +564,6 @@
 
   galleryFrame.onload = function() {
     galleryFrame.contentWindow.ImageUtil.metrics = metrics;
-    window.galleryTestAPI = galleryFrame.contentWindow.galleryTestAPI;
 
     // TODO(haruki): isOnReadonlyDirectory() only checks the permission for the
     // root. We should check more granular permission to know whether the file
@@ -580,7 +592,8 @@
       onMaximize: onMaximize,
       displayStringFunction: strf
     };
-    galleryFrame.contentWindow.Gallery.open(context, allUrls, urls);
+    galleryFrame.contentWindow.Gallery.open(
+        context, fm.volumeManager_, allUrls, urls);
   }.bind(this);
 
   galleryFrame.src = 'gallery.html';
diff --git a/chrome/browser/resources/file_manager/js/file_transfer_controller.js b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
index 95f0d6f..46a1b9d 100644
--- a/chrome/browser/resources/file_manager/js/file_transfer_controller.js
+++ b/chrome/browser/resources/file_manager/js/file_transfer_controller.js
@@ -141,19 +141,13 @@
    *     |dataTransfer.effectAllowed| property ('move', 'copy', 'copyMove').
    */
   cutOrCopy_: function(dataTransfer, effectAllowed) {
-    var directories = [];
-    var files = [];
-    var entries = this.selectedEntries_;
-    for (var i = 0; i < entries.length; i++) {
-      (entries[i].isDirectory ? directories : files).push(entries[i].fullPath);
-    }
-
     // Tag to check it's filemanager data.
     dataTransfer.setData('fs/tag', 'filemanager-data');
     dataTransfer.setData('fs/sourceRoot',
                          this.directoryModel_.getCurrentRootPath());
-    dataTransfer.setData('fs/directories', directories.join('\n'));
-    dataTransfer.setData('fs/files', files.join('\n'));
+    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);
 
@@ -201,21 +195,18 @@
    * @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/pase handlers stay uninitialized. DnD handlers
     // work fine.
-    var files = (dataTransfer.getData('fs/files') || '').split('\n');
-    var directories =
-        (dataTransfer.getData('fs/directories') || '').split('\n');
     var effectAllowed = dataTransfer.effectAllowed != 'uninitialized' ?
         dataTransfer.effectAllowed : dataTransfer.getData('fs/effectallowed');
     var toMove = effectAllowed == 'move' ||
         (effectAllowed == 'copyMove' && opt_effect == 'move');
-    this.copyManager_.paste(files,
-                            directories,
-                            toMove,
-                            destinationPath);
+
+    // Start the pasting operation.
+    this.copyManager_.paste(sourcePaths, destinationPath, toMove);
     return toMove ? 'move' : 'copy';
   },
 
@@ -420,7 +411,7 @@
     if (item == this.dropTarget_)
       return;
 
-    var path = item && list.dataModel.item(item.listIndex);
+    var path = item && list.dataModel.item(item.listIndex).path;
     if (path)
       this.setDropTarget_(item, true /* directory */, event.dataTransfer, path);
     else
diff --git a/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js b/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js
index 25895f9..c170fdb 100644
--- a/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js
+++ b/chrome/browser/resources/file_manager/js/folder_shortcuts_data_model.js
@@ -35,7 +35,10 @@
     if (list instanceof Array) {
       list = filter(list);
 
-      var permutation = this.calculatePermitation_(this.array_, list);
+      // Record metrics.
+      metrics.recordSmallCount('FolderShortcut.Count', list.length);
+
+      var permutation = this.calculatePermutation_(this.array_, list);
       this.array_ = list;
       this.firePermutedEvent_(permutation);
     }
@@ -66,7 +69,7 @@
           return;
       }
 
-      var permutation = this.calculatePermitation_(this.array_, list);
+      var permutation = this.calculatePermutation_(this.array_, list);
       this.array_ = list;
       this.firePermutedEvent_(permutation);
     }
@@ -91,6 +94,18 @@
   },
 
   /**
+   * Returns the paths in the given range as a new array instance. The
+   * arguments and return value are compatible with Array.slice().
+   *
+   * @param {number} start Where to start the selection.
+   * @param {number=} opt_end Where to end the selection.
+   * @return {Array.<string>} Paths in the selected range.
+   */
+  slice: function(begin, opt_end) {
+    return this.array_.slice(begin, opt_end);
+  },
+
+  /**
    * @param {number} index Index of the element to be retrieved.
    * @return {string} The value of the |index|-th element.
    */
@@ -158,8 +173,9 @@
     }
 
     this.firePermutedEvent_(
-        this.calculatePermitation_(oldArray, this.array_));
+        this.calculatePermutation_(oldArray, this.array_));
     this.save_();
+    metrics.recordUserAction('FolderShortcut.Add');
     return addedIndex;
   },
 
@@ -182,8 +198,9 @@
 
     if (removedIndex != -1) {
       this.firePermutedEvent_(
-          this.calculatePermitation_(oldArray, this.array_));
+          this.calculatePermutation_(oldArray, this.array_));
       this.save_();
+      metrics.recordUserAction('FolderShortcut.Remove');
       return removedIndex;
     }
 
@@ -220,7 +237,7 @@
    * @return {Array.<number>} Created permutation array.
    * @private
    */
-  calculatePermitation_: function(oldArray, newArray) {
+  calculatePermutation_: function(oldArray, newArray) {
     var oldIndex = 0;  // Index of oldArray.
     var newIndex = 0;  // Index of newArray.
 
diff --git a/chrome/browser/resources/file_manager/js/media/audio_player.js b/chrome/browser/resources/file_manager/js/media/audio_player.js
index a6abf9d..185c31c 100644
--- a/chrome/browser/resources/file_manager/js/media/audio_player.js
+++ b/chrome/browser/resources/file_manager/js/media/audio_player.js
@@ -5,15 +5,18 @@
 'use strict';
 
 /**
+ * TODO(mtomasz): Rewrite the entire audio player.
+ *
  * @param {HTMLElement} container Container element.
+ * @param {VolumeManager} volumeManager VolumeManager of the system.
  * @constructor
  */
-function AudioPlayer(container) {
+function AudioPlayer(container, volumeManager) {
   this.container_ = container;
   this.metadataCache_ = MetadataCache.createFull();
   this.currentTrack_ = -1;
   this.playlistGeneration_ = 0;
-  this.volumeManager_ = VolumeManager.getInstance();
+  this.volumeManager_ = volumeManager;
 
   this.container_.classList.add('collapsed');
 
@@ -49,30 +52,27 @@
 
   this.volumeManager_.addEventListener('externally-unmounted',
       this.onExternallyUnmounted_.bind(this));
+
+  window.addEventListener('resize', this.onResize_.bind(this));
+
+  // Show the window after DOM is processed.
+  var currentWindow = chrome.app.window.current();
+  setTimeout(currentWindow.show.bind(currentWindow), 0);
 }
 
 /**
- * Key in the local storage for the list of track urls.
- */
-AudioPlayer.PLAYLIST_KEY = 'audioPlaylist';
-
-/**
- * Key in the local storage for the number of the current track.
- */
-AudioPlayer.TRACK_KEY = 'audioTrack';
-
-/**
  * Initial load method (static).
  */
 AudioPlayer.load = function() {
   document.ondragstart = function(e) { e.preventDefault() };
 
-  // If the audio player is starting before the first instance of the File
-  // Manager then it does not have access to filesystem URLs. Request it now.
-  chrome.fileBrowserPrivate.requestFileSystem(function() {
+  // TODO(mtomasz): Consider providing an exact size icon, instead of relying
+  // on downsampling by ash.
+  chrome.app.window.current().setIcon('images/media/2x/audio_player.png');
+
+  VolumeManager.getInstance(function(volumeManager) {
     AudioPlayer.instance =
-        new AudioPlayer(document.querySelector('.audio-player'));
-    chrome.mediaPlayerPrivate.onPlaylistChanged.addListener(getPlaylist);
+        new AudioPlayer(document.querySelector('.audio-player'), volumeManager);
     reload();
   });
 };
@@ -91,27 +91,10 @@
  */
 function reload() {
   if (window.appState) {
-    // Launching/reloading a v2 app.
     util.saveAppState();
     AudioPlayer.instance.load(window.appState);
     return;
   }
-
-  // Lauching/reloading a v1 app.
-  if (document.location.hash) {
-    // The window is reloading, restore the state.
-    AudioPlayer.instance.load(null);
-  } else {
-    getPlaylist();
-  }
-}
-
-/**
- * Get the playlist from Chrome.
- */
-function getPlaylist() {
-  chrome.mediaPlayerPrivate.getPlaylist(
-      AudioPlayer.instance.load.bind(AudioPlayer.instance));
 }
 
 /**
@@ -119,39 +102,9 @@
  * @param {Playlist} playlist Playlist object passed via mediaPlayerPrivate.
  */
 AudioPlayer.prototype.load = function(playlist) {
-  if (!playlist || !playlist.items.length) {
-    // playlist is null if the window is being reloaded.
-    // playlist is empty if ChromeOS has restarted with the Audio Player open.
-    // Restore the playlist from the local storage.
-    util.platform.getPreferences(function(prefs) {
-      try {
-        var restoredPlaylist = {
-          items: JSON.parse(prefs[AudioPlayer.PLAYLIST_KEY]),
-          position: Number(prefs[AudioPlayer.TRACK_KEY]),
-          time: true // Force restoring time from document.location.
-        };
-        if (restoredPlaylist.items.length)
-          this.load(restoredPlaylist);
-      } catch (ignore) {}
-    }.bind(this));
-    return;
-  }
-
-  if (!window.appState) {
-    // Remember the playlist for the restart.
-    // App v2 handles that in the background page.
-    util.platform.setPreference(
-        AudioPlayer.PLAYLIST_KEY, JSON.stringify(playlist.items));
-    util.platform.setPreference(
-        AudioPlayer.TRACK_KEY, playlist.position);
-  }
-
   this.playlistGeneration_++;
-
   this.audioControls_.pause();
-
   this.currentTrack_ = -1;
-
   this.urls_ = playlist.items;
 
   this.invalidTracks_ = {};
@@ -412,58 +365,115 @@
 };
 
 /**
- * Expand/collapse button click handler.
+ * Expand/collapse button click handler. Toggles the mode and updates the
+ * height of the window.
+ *
  * @private
  */
 AudioPlayer.prototype.onExpandCollapse_ = function() {
-  this.container_.classList.toggle('collapsed');
+  if (!this.isCompact_()) {
+    this.setExpanded_(false);
+    this.lastExpandedHeight_ = window.innerHeight;
+  } else {
+    this.setExpanded_(true);
+  }
   this.syncHeight_();
-  if (!this.isCompact_())
+};
+
+/**
+ * Toggles the current expand mode.
+ *
+ * @param {boolean} on True if on, false otherwise.
+ * @private
+ */
+AudioPlayer.prototype.setExpanded_ = function(on) {
+  if (on) {
+    this.container_.classList.remove('collapsed');
     this.scrollToCurrent_(true);
+  } else {
+    this.container_.classList.add('collapsed');
+  }
+};
+
+/**
+ * Toggles the expanded mode when resizing.
+ *
+ * @param {Event} event Resize event.
+ * @private
+ */
+AudioPlayer.prototype.onResize_ = function(event) {
+  if (this.isCompact_() &&
+      window.innerHeight >= AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
+    this.setExpanded_(true);
+  } else if (!this.isCompact_() &&
+             window.innerHeight < AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
+    this.setExpanded_(false);
+  }
 };
 
 /* Keep the below constants in sync with the CSS. */
 
 /**
- * Player header height.
- * TODO(kaznacheev): Set to 30 when the audio player is title-less.
+ * Window header size in pixels.
+ * @type {number}
+ * @const
  */
-AudioPlayer.HEADER_HEIGHT = 0;
+AudioPlayer.HEADER_HEIGHT = 28;
 
 /**
- * Track height.
+ * Track height in pixels.
+ * @type {number}
+ * @const
  */
 AudioPlayer.TRACK_HEIGHT = 58;
 
 /**
- * Controls bar height.
+ * Controls bar height in pixels.
+ * @type {number}
+ * @const
  */
 AudioPlayer.CONTROLS_HEIGHT = 35;
 
 /**
+ * Default number of items in the expanded mode.
+ * @type {number}
+ * @const
+ */
+AudioPlayer.DEFAULT_EXPANDED_ITEMS = 5;
+
+/**
+ * Minimum size of the window in the expanded mode in pixels.
+ * @type {number}
+ * @const
+ */
+AudioPlayer.EXPANDED_MODE_MIN_HEIGHT = AudioPlayer.CONTROLS_HEIGHT +
+                                       AudioPlayer.TRACK_HEIGHT * 2;
+
+/**
  * Set the correct player window height.
  * @private
  */
 AudioPlayer.prototype.syncHeight_ = function() {
-  var expandedListHeight =
-      Math.min(this.urls_.length, 3) * AudioPlayer.TRACK_HEIGHT;
-  this.trackList_.style.height = expandedListHeight + 'px';
+  var targetHeight;
 
-  var targetClientHeight = AudioPlayer.CONTROLS_HEIGHT +
-      (this.isCompact_() ?
-      AudioPlayer.TRACK_HEIGHT :
-      AudioPlayer.HEADER_HEIGHT + expandedListHeight);
+  if (!this.isCompact_()) {
+    // Expanded.
+    if (this.lastExpandedHeight_) {
+      targetHeight = this.lastExpandedHeight_;
+    } else {
+      var expandedListHeight =
+        Math.min(this.urls_.length, AudioPlayer.DEFAULT_EXPANDED_ITEMS) *
+                                    AudioPlayer.TRACK_HEIGHT;
+      targetHeight = AudioPlayer.CONTROLS_HEIGHT + expandedListHeight;
+    }
+  } else {
+    // Not expaned.
+    targetHeight = AudioPlayer.CONTROLS_HEIGHT + AudioPlayer.TRACK_HEIGHT;
+  }
 
-  var appWindow = chrome.app.window.current();
-  var oldHeight = appWindow.contentWindow.outerHeight;
-  var bottom = appWindow.contentWindow.screenY + oldHeight;
-  var newTop = Math.max(0, bottom - targetClientHeight);
-  appWindow.moveTo(appWindow.contentWindow.screenX, newTop);
-  appWindow.resizeTo(appWindow.contentWindow.outerWidth,
-      oldHeight + targetClientHeight - this.container_.clientHeight);
+  window.resizeTo(window.innerWidth, targetHeight + AudioPlayer.HEADER_HEIGHT);
 };
 
-
 /**
  * Create a TrackInfo object encapsulating the information about one track.
  *
diff --git a/chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js b/chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js
index f48c057..6aae530 100644
--- a/chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js
+++ b/chrome/browser/resources/file_manager/js/media/mediaplayer_scripts.js
@@ -15,6 +15,7 @@
 (function() {
 // 'strict mode' is invoked for this scope.
 
+//<include src="../async_util.js"/>
 //<include src="../util.js"/>
 //<include src="../file_type.js"/>
 //<include src="../volume_manager.js">
diff --git a/chrome/browser/resources/file_manager/js/media/video_player.js b/chrome/browser/resources/file_manager/js/media/video_player.js
index 2a0ca66..8e70ccf 100644
--- a/chrome/browser/resources/file_manager/js/media/video_player.js
+++ b/chrome/browser/resources/file_manager/js/media/video_player.js
@@ -134,33 +134,33 @@
   document.ondragstart = function(e) { e.preventDefault() };
 
   chrome.fileBrowserPrivate.getStrings(function(strings) {
-    loadTimeData.data = strings;
+    VolumeManager.getInstance(function(inVolumeManager) {
+      loadTimeData.data = strings;
 
-    controls = new FullWindowVideoControls(
-       document.querySelector('#video-player'),
-       document.querySelector('#video-container'),
-       document.querySelector('#controls'));
+      controls = new FullWindowVideoControls(
+          document.querySelector('#video-player'),
+          document.querySelector('#video-container'),
+          document.querySelector('#controls'));
 
-    metadataCache = MetadataCache.createFull();
-    volumeManager = VolumeManager.getInstance();
+      metadataCache = MetadataCache.createFull();
+      volumeManager = inVolumeManager;
+      volumeManager.addEventListener('externally-unmounted',
+                                     onExternallyUnmounted);
 
-    // If the video player is starting before the first instance of the File
-    // Manager then it does not have access to filesystem URLs. Request it now.
-    chrome.fileBrowserPrivate.requestFileSystem(reload);
+      // If the video player is starting before the first instance of the File
+      // Manager then it does not have access to filesystem URLs.
+      // Request it now.
+      chrome.fileBrowserPrivate.requestFileSystem(reload);
+      var reloadVideo = function(e) {
+        if (decodeErrorOccured) {
+          reload();
+          e.preventDefault();
+        }
+      };
 
-    volumeManager.addEventListener('externally-unmounted',
-                                   onExternallyUnmounted);
-
-    var reloadVideo = function(e) {
-      if (decodeErrorOccured) {
-        reload();
-        e.preventDefault();
-      }
-    };
-
-    document.addEventListener('keydown', reloadVideo, true);
-    document.addEventListener('click', reloadVideo, true);
-
+      document.addEventListener('keydown', reloadVideo, true);
+      document.addEventListener('click', reloadVideo, true);
+    });
   });
 }
 
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
index cc0c239..2166b77 100644
--- a/chrome/browser/resources/file_manager/js/media/video_player_scripts.js
+++ b/chrome/browser/resources/file_manager/js/media/video_player_scripts.js
@@ -15,6 +15,7 @@
 (function() {
 // 'strict mode' is invoked for this scope.
 
+//<include src="../async_util.js"/>
 //<include src="../util.js"/>
 //<include src="../file_type.js"/>
 //<include src="../volume_manager.js">
diff --git a/chrome/browser/resources/file_manager/js/navigation_list.js b/chrome/browser/resources/file_manager/js/navigation_list.js
index 7d6e628..fbd42c5 100644
--- a/chrome/browser/resources/file_manager/js/navigation_list.js
+++ b/chrome/browser/resources/file_manager/js/navigation_list.js
@@ -5,18 +5,146 @@
 'use strict';
 
 /**
+ * Entry of NavigationListModel. This construtor should be called only from
+ * the helper methods (NavigationModelItem.createWithPath/createWithEntry).
+ *
+ * @param {FileSystem} filesystem Fielsystem.
+ * @param {?string} path Path.
+ * @param {DirectoryEntry} entry Entry. Can be a fake.
+ * @extends {cr.EventTarget}
+ * @constructor
+ */
+function NavigationModelItem(filesystem, path, entry) {
+  this.filesystem_ = filesystem;
+  this.path_ = path;
+  this.entry_ = entry;
+
+  this.resolvingQueue_ = new AsyncUtil.Queue();
+}
+
+NavigationModelItem.prototype = {
+  __proto__: cr.EventTarget.prototype,
+  get path() { return this.path_; }
+};
+
+/**
+ * Returns the cached entry of the item. This may returns 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 {FileSystem} filesystem FileSystem.
+ * @param {string} path Path.
+ * @return {NavigationModelItem} Created NavigationModelItem.
+ */
+NavigationModelItem.createWithPath = function(filesystem, path) {
+  var modelItem = new NavigationModelItem(
+      filesystem,
+      path,
+      null);
+  modelItem.resolveDirectoryEntry_();
+  return modelItem;
+};
+
+/**
+ * @param {DirectoryEntry} entry Entry. Can be a fake.
+ * @return {NavigationModelItem} Created NavigationModelItem.
+ */
+NavigationModelItem.createWithEntry = function(entry) {
+  if (entry) {
+    return new NavigationModelItem(
+        entry.filesystem,
+        entry.fullPath,
+        entry);
+  } else {
+    return null;
+  }
+};
+
+/**
+ * Retrieves the entry. If the entry is being retrived, wait until it ends. If
+ * it is nessesary to resolve entry from the path, resolveDirectoryEntry must be
+ * called before using this method.
+ *
+ * @param {function(Entry)} callback Called with the resolved entry. The entry
+ *     may be NULL if resolving is failed.
+ */
+NavigationModelItem.prototype.getEntryAsync = function(callback) {
+  // If resolveDirectoryEntry_() is running, waits until it finishes.
+  this.resolvingQueue_.run(function(continueCallback) {
+    callback(this.entry_);
+    continueCallback();
+  }.bind(this));
+};
+
+/**
+ * Resolves an directory entry.
+ * @private
+ */
+NavigationModelItem.prototype.resolveDirectoryEntry_ = function() {
+  this.resolvingQueue_.run(function(continueCallback) {
+    this.filesystem_.root.getDirectory(
+        this.path_,
+        {create: false},
+        function(directoryEntry) {
+          this.entry_ = directoryEntry;
+          continueCallback();
+        }.bind(this),
+        function(error) {
+          this.entry_ = null;
+          console.error('Error on resolving path: ' + this.path_);
+          continueCallback();
+        }.bind(this));
+  }.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 {FileSystem} filesystem FileSystem.
  * @param {cr.ui.ArrayDataModel} volumesList The first list of the model.
  * @param {cr.ui.ArrayDataModel} pinnedList The second list of the model.
  * @constructor
  * @extends {cr.EventTarget}
  */
-function NavigationListModel(volumesList, pinnedList) {
-  this.volumesList_ = volumesList;
-  this.pinnedList_ = pinnedList;
+function NavigationListModel(filesystem, volumesList, pinnedList) {
+  this.volumesListModel_ = volumesList;
+  this.pinnedListModel_ = pinnedList;
+
+  /**
+   * (Re)generates this.volumesList_ and this.pinnedList_ from the models.
+   * This should be called whenever the models are updated.
+   */
+  var generateLists = function() {
+    this.volumesList_ =
+        this.volumesListModel_.slice(0).map(function(entry) {
+          return NavigationModelItem.createWithEntry(entry);
+        });
+    this.pinnedList_ =
+        this.pinnedListModel_.slice(0).map(function(path) {
+            return NavigationModelItem.createWithPath(filesystem, path);
+        });
+  }.bind(this);
+
+  generateLists();
 
   // Generates a combined 'permuted' event from an event of either list.
   var permutedHandler = function(listNum, e) {
+    generateLists();
+
     var permutedEvent = new Event('permuted');
     var newPermutation = [];
     var newLength;
@@ -44,18 +172,24 @@
     permutedEvent.permutation = newPermutation;
     this.dispatchEvent(permutedEvent);
   };
-  this.volumesList_.addEventListener('permuted', permutedHandler.bind(this, 1));
-  this.pinnedList_.addEventListener('permuted', permutedHandler.bind(this, 2));
+  this.volumesListModel_.addEventListener(
+      'permuted', permutedHandler.bind(this, 1));
+  this.pinnedListModel_.addEventListener(
+      'permuted', permutedHandler.bind(this, 2));
 
   // Generates a combined 'change' event from an event of either list.
   var changeHandler = function(listNum, e) {
+    generateLists();
+
     var changeEvent = new Event('change');
     changeEvent.index =
         (listNum == 1) ? e.index : (e.index + this.volumesList_.length);
     this.dispatchEvent(changeEvent);
   };
-  this.volumesList_.addEventListener('change', changeHandler.bind(this, 1));
-  this.pinnedList_.addEventListener('change', changeHandler.bind(this, 2));
+  this.volumesListModel_.addEventListener(
+      'change', changeHandler.bind(this, 1));
+  this.pinnedListModel_.addEventListener(
+      'change', changeHandler.bind(this, 2));
 
   // 'splice' and 'sorted' events are not implemented, since they are not used
   // in list.js.
@@ -77,12 +211,10 @@
  */
 NavigationListModel.prototype.item = function(index) {
   var offset = this.volumesList_.length;
-  if (index < offset) {
-    var entry = this.volumesList_.item(index);
-    return entry ? entry.fullPath : undefined;
-  } else {
-    return this.pinnedList_.item(index - offset);
-  }
+  if (index < offset)
+    return this.volumesList_[index];
+  else
+    return this.pinnedList_[index - offset];
 };
 
 /**
@@ -96,14 +228,14 @@
 
 /**
  * Returns the first matching item.
- * @param {Entry} item The entry to find.
+ * @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(item, opt_fromIndex) {
+NavigationListModel.prototype.indexOf = function(modelItem, opt_fromIndex) {
   for (var i = opt_fromIndex || 0; i < this.length; i++) {
-    if (item === this.item(i))
+    if (modelItem === this.item(i))
       return i;
   }
   return -1;
@@ -118,6 +250,7 @@
 
 NavigationListItem.prototype = {
   __proto__: HTMLLIElement.prototype,
+  get modelItem() { return this.modelItem_; },
 };
 
 /**
@@ -146,23 +279,27 @@
 
 /**
  * Associate a path with this item.
- * @param {string} path Path of 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.setPath = function(path) {
-  if (this.path_)
-    console.warn('NavigationListItem.setPath should be called only once.');
+NavigationListItem.prototype.setModelItem =
+    function(modelItem, opt_deviceType) {
+  if (this.modelItem_)
+    console.warn('NavigationListItem.setModelItem should be called only once.');
 
-  this.path_ = path;
+  this.modelItem_ = modelItem;
 
-  var rootType = PathUtil.getRootType(path);
+  this.setAttribute('item-type',
+                    modelItem.isShortcut() ? 'shortcut' : 'volume');
 
+  var rootType = PathUtil.getRootType(modelItem.path);
   this.iconDiv_.setAttribute('volume-type-icon', rootType);
-  if (rootType === RootType.REMOVABLE) {
-    this.iconDiv_.setAttribute('volume-subtype',
-        VolumeManager.getInstance().getDeviceType(path));
+  if (opt_deviceType) {
+    this.iconDiv_.setAttribute('volume-subtype', opt_deviceType);
   }
 
-  this.label_.textContent = PathUtil.getFolderLabel(path);
+  this.label_.textContent = PathUtil.getFolderLabel(modelItem.path);
 
   if (rootType === RootType.ARCHIVE || rootType === RootType.REMOVABLE) {
     this.eject_ = cr.doc.createElement('div');
@@ -187,14 +324,14 @@
  * @param {cr.ui.Menu} menu Menu this item.
  */
 NavigationListItem.prototype.maybeSetContextMenu = function(menu) {
-  if (!this.path_) {
+  if (!this.modelItem_.path) {
     console.error('NavigationListItem.maybeSetContextMenu must be called ' +
-                  'after setPath().');
+                  'after setModelItem().');
     return;
   }
 
-  var isRoot = PathUtil.isRootPath(this.path_);
-  var rootType = PathUtil.getRootType(this.path_);
+  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
@@ -242,24 +379,26 @@
 
 /**
  * @param {HTMLElement} el Element to be DirectoryItem.
+ * @param {VolumeManager} volumeManager The VolumeManager of the system.
  * @param {DirectoryModel} directoryModel Current DirectoryModel.
  *     folders.
  */
-NavigationList.decorate = function(el, directoryModel) {
+NavigationList.decorate = function(el, volumeManager, directoryModel) {
   el.__proto__ = NavigationList.prototype;
-  el.decorate(directoryModel);
+  el.decorate(volumeManager, directoryModel);
 };
 
 /**
+ * @param {VolumeManager} volumeManager The VolumeManager of the system.
  * @param {DirectoryModel} directoryModel Current DirectoryModel.
  */
-NavigationList.prototype.decorate = function(directoryModel) {
+NavigationList.prototype.decorate = function(volumeManager, directoryModel) {
   cr.ui.List.decorate(this);
   this.__proto__ = NavigationList.prototype;
 
   this.fileManager_ = null;
   this.directoryModel_ = directoryModel;
-  this.volumeManager_ = VolumeManager.getInstance();
+  this.volumeManager_ = volumeManager;
   this.selectionModel = new cr.ui.ListSingleSelectionModel();
 
   this.directoryModel_.addEventListener('directory-changed',
@@ -277,8 +416,8 @@
   this.setAttribute('role', 'listbox');
 
   var self = this;
-  this.itemConstructor = function(path) {
-    return self.renderRoot_(path);
+  this.itemConstructor = function(modelItem) {
+    return self.renderRoot_(modelItem);
   };
 };
 
@@ -291,6 +430,13 @@
  * @override
  */
 NavigationList.prototype.removeChild = function(item) {
+  // TODO(yoshiki): Animation is temporary disabled for volumes. Add animation
+  // back. crbug.com/276132.
+  if (!item.modelItem.isShortcut()) {
+    Node.prototype.removeChild.call(this, item);
+    return;
+  }
+
   var removeElement = function(e) {
     // Must keep the animation name 'fadeOut' in sync with the css.
     if (e.animationName == 'fadeOut')
@@ -307,17 +453,24 @@
 /**
  * Creates an element of a navigation list. This method is called from
  * cr.ui.List internally.
- * @param {string} path Path of the directory to be rendered.
+ *
+ * @param {NavigationModelItem} modelItem NavigationModelItem to be rendered.
  * @return {NavigationListItem} Rendered element.
  * @private
  */
-NavigationList.prototype.renderRoot_ = function(path) {
+NavigationList.prototype.renderRoot_ = function(modelItem) {
   var item = new NavigationListItem();
-  item.setPath(path);
+  var volumeInfo =
+      PathUtil.isRootPath(modelItem.path) &&
+      this.volumeManager_.getVolumeInfo(modelItem.path);
+  item.setModelItem(modelItem, volumeInfo && volumeInfo.deviceType);
 
   var handleClick = function() {
-    if (item.selected && path !== this.directoryModel_.getCurrentDirPath())
-      this.changeDirectory_(path);
+    if (item.selected &&
+        modelItem.path !== this.directoryModel_.getCurrentDirPath()) {
+      metrics.recordUserAction('FolderShortcut.Navigate');
+      this.changeDirectory_(modelItem.path);
+    }
   }.bind(this);
   item.addEventListener('click', handleClick);
 
@@ -371,6 +524,7 @@
 
 /**
  * Selects the n-th item from the list.
+ *
  * @param {number} index Item index.
  * @return {boolean} True for success, otherwise false.
  */
@@ -378,14 +532,17 @@
   if (index < 0 || index > this.dataModel.length - 1)
     return false;
 
-  var newPath = this.dataModel.item(index);
+  var newPath = this.dataModel.item(index).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.
   if (this.directoryModel_.getCurrentDirEntry().fullPath == newPath)
     return false;
 
+  metrics.recordUserAction('FolderShortcut.Navigate');
   this.changeDirectory_(newPath);
   return true;
 };
@@ -447,7 +604,7 @@
   var bestMatchIndex = -1;
   var bestMatchSubStringLen = 0;
   for (var i = 0; i < this.dataModel.length; i++) {
-    var itemPath = this.dataModel.item(i);
+    var itemPath = this.dataModel.item(i).path;
     if (path.indexOf(itemPath) == 0) {
       if (bestMatchSubStringLen < itemPath.length) {
         bestMatchIndex = i;
@@ -466,7 +623,7 @@
   // (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);
+    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;
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery.js b/chrome/browser/resources/file_manager/js/photo/gallery.js
index c942d75..9bcbfb6 100644
--- a/chrome/browser/resources/file_manager/js/photo/gallery.js
+++ b/chrome/browser/resources/file_manager/js/photo/gallery.js
@@ -4,19 +4,6 @@
 
 'use strict';
 
-util.addPageLoadHandler(function() {
-  if (!location.hash)
-    return;
-
-  var pageState;
-  if (location.search) {
-    try {
-      pageState = JSON.parse(decodeURIComponent(location.search.substr(1)));
-    } catch (ignore) {}
-  }
-  Gallery.openStandalone(decodeURI(location.hash.substr(1)), pageState);
-});
-
 /**
  * Called from the main frame when unloading.
  * @return {string?} User-visible message on null if it is OK to close.
@@ -44,15 +31,17 @@
  *     {string} readonlyDirName Directory name for readonly warning or null.
  *     {DirEntry} saveDirEntry Directory to save to.
  *     {function(string)} displayStringFunction.
+ * @param {VolumeManager} volumeManager The VolumeManager instance of the
+ *      system.
  * @class
  * @constructor
  */
-function Gallery(context) {
+function Gallery(context, volumeManager) {
   this.container_ = document.querySelector('.gallery');
   this.document_ = document;
   this.context_ = context;
   this.metadataCache_ = context.metadataCache;
-  this.volumeManager_ = VolumeManager.getInstance();
+  this.volumeManager_ = volumeManager;
 
   this.dataModel_ = new cr.ui.ArrayDataModel([]);
   this.selectionModel_ = new cr.ui.ListSelectionModel();
@@ -71,98 +60,16 @@
  * Create and initialize a Gallery object based on a context.
  *
  * @param {Object} context Gallery context.
+ * @param {VolumeManager} volumeManager VolumeManager of the system.
  * @param {Array.<string>} urls Array of urls.
  * @param {Array.<string>} selectedUrls Array of selected urls.
  */
-Gallery.open = function(context, urls, selectedUrls) {
-  Gallery.instance = new Gallery(context);
+Gallery.open = function(context, volumeManager, urls, selectedUrls) {
+  Gallery.instance = new Gallery(context, volumeManager);
   Gallery.instance.load(urls, selectedUrls);
 };
 
 /**
- * Create a Gallery object in a tab.
- * TODO(mtomasz): Remove it after dropping support for Files.app V1.
- *
- * @param {string} path File system path to a selected file.
- * @param {Object} pageState Page state object.
- * @param {function=} opt_callback Called when gallery object is constructed.
- */
-Gallery.openStandalone = function(path, pageState, opt_callback) {
-  ImageUtil.metrics = metrics;
-
-  var currentDir;
-  var urls = [];
-  var selectedUrls = [];
-  var appWindow = chrome.app.window.current();
-
-  Gallery.getFileBrowserPrivate().requestFileSystem(function(filesystem) {
-    // If the path points to the directory scan it.
-    filesystem.root.getDirectory(path, {create: false}, scanDirectory,
-        function() {
-          // Try to scan the parent directory.
-          var pathParts = path.split('/');
-          pathParts.pop();
-          var parentPath = pathParts.join('/');
-          filesystem.root.getDirectory(parentPath, {create: false},
-              scanDirectory, open /* no data, just display an error */);
-        });
-  });
-
-  var scanDirectory = function(dirEntry) {
-    currentDir = dirEntry;
-    util.forEachDirEntry(currentDir, function(entry) {
-      if (entry == null) {
-        open();
-      } else if (FileType.isImageOrVideo(entry)) {
-        var url = entry.toURL();
-        urls.push(url);
-        if (entry.fullPath == path)
-          selectedUrls = [url];
-      }
-    });
-  };
-
-  var onBack = function() {
-    // Exiting to the Files app seems arbitrary. Consider closing the tab.
-    document.location = 'main.html?' +
-        JSON.stringify({defaultPath: document.location.hash.substr(1)});
-  };
-
-  var onClose = function() {
-    window.close();
-  };
-
-  var onMaximize = function() {
-    var appWindow = chrome.app.window.current();
-    if (appWindow.isMaximized())
-      appWindow.restore();
-    else
-      appWindow.maximize();
-  };
-
-  function open() {
-    urls.sort();
-    Gallery.getFileBrowserPrivate().getStrings(function(strings) {
-      loadTimeData.data = strings;
-      var context = {
-        readonlyDirName: null,
-        curDirEntry: currentDir,
-        saveDirEntry: null,
-        metadataCache: MetadataCache.createFull(),
-        pageState: pageState,
-        appWindow: appWindow,
-        onBack: onBack,
-        onClose: onClose,
-        onMaximize: onMaximize,
-        displayStringFunction: strf
-      };
-      Gallery.open(context, urls, selectedUrls);
-      if (opt_callback) opt_callback();
-    });
-  }
-};
-
-/**
  * Tools fade-out timeout im milliseconds.
  * @const
  * @type {number}
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js b/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
index 6548dd0..57cbdd8 100644
--- a/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
+++ b/chrome/browser/resources/file_manager/js/photo/gallery_scripts.js
@@ -32,6 +32,7 @@
 // 'strict mode' is invoked for this scope.
 
 //<include src="../file_type.js">
+//<include src="../async_util.js">
 //<include src="../util.js">
 //<include src="../volume_manager.js">
 
@@ -59,8 +60,6 @@
 //<include src="slide_mode.js">
 //<include src="ribbon.js">
 
-//<include src="gallery_testapi.js">
-
 // Exports
 window.ImageUtil = ImageUtil;
 window.Gallery = Gallery;
diff --git a/chrome/browser/resources/file_manager/js/photo/gallery_testapi.js b/chrome/browser/resources/file_manager/js/photo/gallery_testapi.js
deleted file mode 100644
index 9e740d0..0000000
--- a/chrome/browser/resources/file_manager/js/photo/gallery_testapi.js
+++ /dev/null
@@ -1,246 +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';
-
-/**
- * Test API for Chrome OS Image Editor.
- *
- * There are two ways to load Image Editor before testing:
- *   - open File Manager, and then click on an image file to open Image Editor;
- *   or
- *   - open tab with URL:
- *     chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/gallery.html
- *     and then call |galleryTestAPI.load('/Downloads/path/to/file.jpg')|.
- *
- *  After Image Editor is loaded, you can call methods from |galleryTestAPI| to
- *  emulate user actions and get feedback.
- */
-var galleryTestAPI = {
-  /**
-   * Open the Photo Editor.
-   * @param {string} path Path to the directory or an image file.
-   */
-  load: function(path) {
-    Gallery.openStandalone(path, null, function() {
-      galleryTestAPI.waitFor_('loaded');
-    });
-  },
-
-  /**
-   * Responds with the selected file name.
-   */
-  getSelectedFileName: function() {
-    galleryTestAPI.respond_(document.querySelector('.namebox').value);
-  },
-
-  /**
-   * Toggles edit mode.
-   */
-  clickEditToggle: function() {
-    galleryTestAPI.click('.edit');
-    setTimeout(galleryTestAPI.respond_.bind(null, true), 0);
-  },
-
-  /**
-   * Clicks arrow to select next image.
-   */
-  clickNextImageArrow: function() {
-    galleryTestAPI.click('.arrow.right');
-    galleryTestAPI.waitFor_('image-displayed');
-  },
-
-  /**
-   * Clicks arrow to select previous image.
-   */
-  clickPreviousImageArrow: function() {
-    galleryTestAPI.click('.arrow.left');
-    galleryTestAPI.waitFor_('image-displayed');
-  },
-
-  /**
-   * Clicks last thumbnail in ribbon to select an image.
-   */
-  clickLastRibbonThumbnail: function() {
-    galleryTestAPI.clickRibbonThumbnail(true);
-  },
-
-  /**
-   * Clicks first thumbnail in ribbon to select an image.
-   */
-  clickFirstRibbonThumbnail: function() {
-    galleryTestAPI.clickRibbonThumbnail(false);
-  },
-
-  /**
-   * Clicks thumbnail in ribbon.
-   * @param {boolean} last Whether to click on last vs first.
-   */
-  clickRibbonThumbnail: function(last) {
-    // TODO(dgozman): investigate why this timeout is required sometimes.
-    setTimeout(function() {
-      var nodes = document.querySelectorAll('.ribbon > :not([vanishing])');
-      if (nodes.length == 0) {
-        galleryTestAPI.respond_(false);
-        return;
-      }
-      nodes[last ? nodes.length - 1 : 0].click();
-      galleryTestAPI.waitFor_('image-displayed');
-    }, 0);
-  },
-
-  /**
-   * Clicks 'rotate left' tool.
-   */
-  clickRotateLeft: function() {
-    galleryTestAPI.editAndRespond_(
-        galleryTestAPI.click.bind(null, '.rotate_left'));
-  },
-
-  /**
-   * Clicks 'rotate right' tool.
-   */
-  clickRotateRight: function() {
-    galleryTestAPI.editAndRespond_(
-        galleryTestAPI.click.bind(null, '.rotate_right'));
-  },
-
-  /**
-   * Clicks 'undo' tool.
-   */
-  clickUndo: function() {
-    galleryTestAPI.editAndRespond_(galleryTestAPI.click.bind(null, '.undo'));
-  },
-
-  /**
-   * Clicks 'redo' tool.
-   */
-  clickRedo: function() {
-    galleryTestAPI.editAndRespond_(galleryTestAPI.click.bind(null, '.redo'));
-  },
-
-  /**
-   * Clicks 'autofix' tool.
-   */
-  clickAutofix: function() {
-    galleryTestAPI.editAndRespond_(galleryTestAPI.click.bind(null, '.autofix'));
-  },
-
-  /**
-   * Responds whether autofix tool is available.
-   */
-  isAutofixAvailable: function() {
-    galleryTestAPI.respond_(
-        !document.querySelector('.autofix').hasAttribute('disabled'));
-  },
-
-  /**
-   * Performs a click on the element with specififc selector.
-   * @param {string} selector CSS selector.
-   */
-  click: function(selector) {
-    document.querySelector(selector).click();
-  },
-
-  /**
-   * Waits until editor is ready, performs action and then responds.
-   * @param {function} action The action to perform.
-   * @private
-   */
-  editAndRespond_: function(action) {
-    // TODO(dgozman): investigate why this is required sometimes.
-    setTimeout(function() {
-      action();
-      galleryTestAPI.waitFor_('image-saved');
-    }, 0);
-  },
-
-  /**
-   * Waits for event fired and then calls a function.
-   * @param {string} event Event name.
-   * @param {function=} opt_callback Callback. If not passed,
-   *     |galleryTestAPI.respond_(true)| is called.
-   * @private
-   */
-  waitFor_: function(event, opt_callback) {
-    var callback = opt_callback || galleryTestAPI.respond_.bind(null, true);
-    var listener = function() {
-      Gallery.instance.removeEventListener(event, listener);
-      callback();
-    };
-    Gallery.instance.addEventListener(event, listener);
-  },
-
-  /**
-   * @param {string|boolean|number} value Value to send back.
-   * @private
-   */
-  respond_: function(value) {
-    if (window.domAutomationController) {
-      window.domAutomationController.send(value);
-    } else if (galleryTestAPI.respondCallback) {
-      galleryTestAPI.respondCallback(value);
-    } else {
-      console.log('playerTestAPI response: ' + value);
-    }
-  }
-};
-
-/**
- * Test example.
- */
-galleryTestAPI.testExample = function() {
-  var api = galleryTestAPI;
-  var PATH = '/Downloads/file.jpg';
-
-  var steps = [
-    function load() {
-      if (!Gallery.instance) {
-        api.load(PATH);
-      } else {
-        nextStep();
-      }
-    },
-
-    function getName() { api.getSelectedFileName(); },
-
-    function lastRibbon(filename) {
-      console.log(filename);
-      api.clickLastRibbonThumbnail();
-    },
-
-    function toggleEdit() { api.clickEditToggle(); },
-
-    function rightArrow() { api.clickNextImageArrow(); },
-
-    function rotateLeft() { api.clickRotateLeft(); },
-
-    function rotateRight() { api.clickRotateRight(); },
-
-    function undo() { api.clickUndo(); },
-
-    function queryAutofix() { api.isAutofixAvailable(); },
-
-    function autofix(available) {
-      if (available) {
-        api.clickAutofix();
-      } else {
-        nextStep();
-      }
-    },
-
-    function done() { console.log('done'); }
-  ];
-
-  var step = 0;
-
-  function nextStep() {
-    ++step;
-    console.log('nextStep calls: ' + steps[step - 1].name);
-    steps[step - 1].apply(null, arguments);
-  }
-
-  api.respondCallback = nextStep;
-  nextStep();
-};
diff --git a/chrome/browser/resources/file_manager/js/photo/importing_dialog.js b/chrome/browser/resources/file_manager/js/photo/importing_dialog.js
index dde1695..88d1232 100644
--- a/chrome/browser/resources/file_manager/js/photo/importing_dialog.js
+++ b/chrome/browser/resources/file_manager/js/photo/importing_dialog.js
@@ -91,11 +91,10 @@
  */
 ImportingDialog.prototype.start = function(destination) {
   this.destination_ = destination;
-  var files = this.entries_.map(function(e) { return e.fullPath });
-  var isOnDrive =
-      PathUtil.getRootType(files[0].fullPath) == RootType.DRIVE;
-  this.copyManager_.paste(files, [], this.move_, isOnDrive,
-                          this.destination_.fullPath, true);
+  this.copyManager_.paste(
+      this.entries_.map(function(e) { return e.fullPath }),
+      this.destination_.fullPath,
+      this.move_);
 };
 
 /**
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
index c9db07d..e0bf1dc 100644
--- a/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
+++ b/chrome/browser/resources/file_manager/js/photo/photo_import_scripts.js
@@ -31,6 +31,7 @@
 (function() {
 // 'strict mode' is invoked for this scope.
 
+//<include src="../async_util.js"/>
 //<include src="../util.js"/>
 //<include src="../file_type.js"/>
 //<include src="../directory_contents.js"/>
diff --git a/chrome/browser/resources/file_manager/js/share_dialog.js b/chrome/browser/resources/file_manager/js/share_dialog.js
index a06a50e..42c0000 100644
--- a/chrome/browser/resources/file_manager/js/share_dialog.js
+++ b/chrome/browser/resources/file_manager/js/share_dialog.js
@@ -56,7 +56,7 @@
 
   var registerInjectionHooks = function() {
     this.webView_.removeEventListener('loadstop', registerInjectionHooks);
-    this.webView_.onBeforeSendHeaders.addListener(
+    this.webView_.request.onBeforeSendHeaders.addListener(
       this.authorizeRequest_.bind(this),
       {urls: [this.urlPattern_]},
       ['blocking', 'requestHeaders']);
diff --git a/chrome/browser/resources/file_manager/js/util.js b/chrome/browser/resources/file_manager/js/util.js
index 966c8e6..843584c 100644
--- a/chrome/browser/resources/file_manager/js/util.js
+++ b/chrome/browser/resources/file_manager/js/util.js
@@ -148,15 +148,19 @@
         if (!recurse)
           return;
         pendingSubdirectories++;
-        util.forEachDirEntry(entry, function(inEntry) {
-          if (inEntry == null) {
-            // Null entry indicates we're done scanning this directory.
-            pendingSubdirectories--;
-            steps.areWeThereYet();
-            return;
-          }
-          steps.tallyEntry(inEntry, originalSourcePath);
-        });
+        util.forEachDirEntry(
+            entry,
+            function(inEntry, callback) {
+              steps.tallyEntry(inEntry, originalSourcePath);
+              callback();
+            },
+            function() {
+              pendingSubdirectories--;
+              steps.areWeThereYet();
+            },
+            function(err) {
+              console.error('Failed to read dir entries at ' + entry.fullPath);
+            });
       } else {
         fileEntries.push(entry);
         pendingFiles++;
@@ -193,33 +197,35 @@
 };
 
 /**
- * Utility function to invoke callback once for each entry in dirEntry.
- * callback is called with 'null' after all entries are visited to indicate
- * the end of the directory scan.
+ * Iterates the entries contained by dirEntry, and invokes callback once for
+ * each entry. On completion, successCallback will be invoked.
  *
- * @param {DirectoryEntry} dirEntry The directory entry to enumerate.
- * @param {function(Entry)} callback The function to invoke for each entry in
- *     dirEntry.
+ * @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) {
-  var reader;
+util.forEachDirEntry = function(
+    dirEntry, callback, successCallback, errorCallback) {
+  var reader = dirEntry.createReader();
+  var iterate = function() {
+    reader.readEntries(function(entries) {
+      if (entries.length == 0) {
+        successCallback();
+        return;
+      }
 
-  var onError = function(err) {
-    console.error('Failed to read  dir entries at ' + dirEntry.fullPath);
+      AsyncUtil.forEach(
+          entries,
+          function(forEachCallback, entry) {
+            // Do not pass index nor entries.
+            callback(entry, forEachCallback);
+          },
+          iterate);
+    }, errorCallback);
   };
-
-  var onReadSome = function(results) {
-    if (results.length == 0)
-      return callback(null);
-
-    for (var i = 0; i < results.length; i++)
-      callback(results[i]);
-
-    reader.readEntries(onReadSome, onError);
-  };
-
-  reader = dirEntry.createReader();
-  reader.readEntries(onReadSome, onError);
+  iterate();
 };
 
 /**
@@ -444,6 +450,42 @@
 };
 
 /**
+ * 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.
@@ -670,83 +712,30 @@
 };
 
 /**
- * Traverses a tree up to a certain depth.
- * @param {FileEntry} root Root entry.
- * @param {function(Array.<Entry>)} callback The callback is called at the very
- *     end with a list of entries found.
- * @param {number?} max_depth Maximum depth. Pass zero to traverse everything.
- * @param {function(entry):boolean=} opt_filter Optional filter to skip some
- *     files/directories.
+ * 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(root, callback, max_depth, opt_filter) {
-  var list = [];
-  util.forEachEntryInTree(root, function(entry) {
-    if (entry) {
-      list.push(entry);
-    } else {
-      callback(list);
-    }
-    return true;
-  }, max_depth, opt_filter);
-};
-
-/**
- * Traverses a tree up to a certain depth, and calls a callback for each entry.
- * callback is called with 'null' after all entries are visited to indicate
- * the end of the traversal.
- * @param {FileEntry} root Root entry.
- * @param {function(Entry):boolean} callback The callback is called for each
- *     entry, and then once with null passed. If callback returns false once,
- *     the whole traversal is stopped.
- * @param {number?} max_depth Maximum depth. Pass zero to traverse everything.
- * @param {function(entry):boolean=} opt_filter Optional filter to skip some
- *     files/directories.
- */
-util.forEachEntryInTree = function(root, callback, max_depth, opt_filter) {
-  if (root.isFile) {
-    if (opt_filter && !opt_filter(root)) {
-      callback(null);
-      return;
-    }
-    if (callback(root))
-      callback(null);
+util.traverseTree = function(entry, callback, successCallback, errorCallback) {
+  if (!callback(entry)) {
+    successCallback();
     return;
   }
 
-  var pending = 0;
-  var cancelled = false;
-
-  var maybeDone = function() {
-    if (pending == 0 && !cancelled)
-      callback(null);
-  };
-
-  var readEntry = function(entry, depth) {
-    if (cancelled) return;
-    if (opt_filter && !opt_filter(entry)) return;
-
-    if (!callback(entry)) {
-      cancelled = true;
-      return;
-    }
-
-    // Do not recurse too deep and into files.
-    if (entry.isFile || (max_depth != 0 && depth >= max_depth))
-      return;
-
-    pending++;
-    util.forEachDirEntry(entry, function(childEntry) {
-      if (childEntry == null) {
-        // Null entry indicates we're done scanning this directory.
-        pending--;
-        maybeDone();
-      } else {
-        readEntry(childEntry, depth + 1);
-      }
-    });
-  };
-
-  readEntry(root, 0);
+  util.forEachDirEntry(
+      entry,
+      function(child, iterationCallback) {
+        util.traverseTree(child, callback, iterationCallback, errorCallback);
+      },
+      successCallback,
+      errorCallback);
 };
 
 /**
@@ -1147,10 +1136,10 @@
 };
 
 /**
- * The type of an entry changed event.
+ * The kind of an entry changed event.
  * @enum {number}
  */
-util.EntryChangedType = {
+util.EntryChangedKind = {
   CREATED: 0,
   DELETED: 1,
 };
@@ -1199,3 +1188,14 @@
   // 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);
+};
diff --git a/chrome/browser/resources/file_manager/js/volume_manager.js b/chrome/browser/resources/file_manager/js/volume_manager.js
index 379b2dc..b00eb36 100644
--- a/chrome/browser/resources/file_manager/js/volume_manager.js
+++ b/chrome/browser/resources/file_manager/js/volume_manager.js
@@ -5,12 +5,117 @@
 'use strict';
 
 /**
+ * Represents each volume, such as "drive", "download directory", each "USB
+ * flush storage", or "mounted zip archive" etc.
+ *
+ * @param {string} mountPath Where the volume is mounted.
+ * @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(mountPath, error, deviceType, isReadOnly) {
+  // TODO(hidehiko): This should include FileSystem instance.
+  this.mountPath_ = mountPath;
+  this.error_ = error;
+  this.deviceType_ = deviceType;
+  this.isReadOnly_ = !!isReadOnly;
+}
+
+VolumeInfo.prototype = {
+  get mountPath() { return this.mountPath_; },
+  get error() { return this.error_; },
+  get deviceType() { return this.deviceType_; },
+  get isReadOnly() { return this.isReadOnly_; },
+};
+
+/**
+ * Utilities for volume manager implementation.
+ */
+var volumeManagerUtil = {};
+
+/**
+ * Throws an Error when the given error is not in VolumeManager.Error.
+ * @param {VolumeManager.Error} error Status string usually received from APIs.
+ */
+volumeManagerUtil.validateError = function(error) {
+  for (var key in VolumeManager.Error) {
+    if (error == VolumeManager.Error[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. '/arhive/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);
+};
+
+/**
+ * Builds the VolumeInfo data for mountPath.
+ * @param {string} mountPath Path to the volume.
+ * @param {VolumeManager.Error} error The error string if available.
+ * @param {function(Object)} callback Called on completion.
+ *     TODO(hidehiko): Replace the type from Object to its original type.
+ */
+volumeManagerUtil.createVolumeInfo = function(mountPath, error, callback) {
+  // Validation of the input.
+  volumeManagerUtil.validateMountPath(mountPath);
+  if (error)
+    volumeManagerUtil.validateError(error);
+
+  // TODO(hidehiko): Do we really need to create a volume info for error
+  // case?
+  chrome.fileBrowserPrivate.getVolumeMetadata(
+      util.makeFilesystemUrl(mountPath),
+      function(metadata) {
+        if (chrome.runtime.lastError && !error)
+          error = VolumeManager.Error.UNKNOWN;
+        callback(new VolumeInfo(
+            mountPath, error,
+            metadata && metadata.deviceType,
+            !!metadata && metadata.isReadOnly));
+      });
+};
+
+/**
  * VolumeManager is responsible for tracking list of mounted volumes.
  *
+ * @param {Entry} root The root of file system.
  * @constructor
  * @extends {cr.EventTarget}
  */
-function VolumeManager() {
+function VolumeManager(root) {
+  /**
+   * Root enty of the whole file system.
+   * TODO(hidehiko): Remove this when multi-file system is supported.
+   * @type {Entry}
+   * @private
+   */
+  this.root_ = root;
+
   /**
    * The list of archives requested to mount. We will show contents once
    * archive is mounted, but only for mounts from within this filebrowser tab.
@@ -20,7 +125,8 @@
   this.requests_ = {};
 
   /**
-   * @type {Object.<string, Object>}
+   * TODO(hidehiko): Replace Object with cr.ui.ArrayDataModel.
+   * @type {Object.<string, VolumeInfo>}
    * @private
    */
   this.mountedVolumes_ = {};
@@ -32,6 +138,15 @@
    */
   this.ready_ = false;
 
+  /**
+   * True if Drive file system is enabled.
+   * TODO(hidehiko): This should be migrated into the multi-file system
+   * support. If drive file system is disabled, Files.app should receive
+   * unmounted event and UI should hide Drive.
+   * @type {boolean}
+   */
+  this.driveEnabled = false;
+
   this.initMountPoints_();
   this.driveStatus_ = VolumeManager.DriveStatus.UNMOUNTED;
 
@@ -43,7 +158,6 @@
   chrome.fileBrowserPrivate.onDriveConnectionStatusChanged.addListener(
       this.onDriveConnectionStatusChanged_.bind(this));
   this.onDriveConnectionStatusChanged_();
-
 }
 
 /**
@@ -139,11 +253,60 @@
 VolumeManager.MOUNTING_DELAY = 500;
 
 /**
- * @return {VolumeManager} Singleton instance.
+ * The singleton instance of VolumeManager. Initialized by the first invocation
+ * of getInstance().
+ * @type {VolumeManager}
+ * @private
  */
-VolumeManager.getInstance = function() {
-  return VolumeManager.instance_ = VolumeManager.instance_ ||
-                                   new VolumeManager();
+VolumeManager.instance_ = null;
+
+/**
+ * The queue of pending getInstance invocations.
+ * @type {AsyncUtil.Queue}
+ * @private
+ */
+VolumeManager.getInstanceQueue_ = new AsyncUtil.Queue();
+
+/**
+ * @param {function(VolumeManager)} callback Callback to obtain VolumeManager
+ *     instance.
+ */
+VolumeManager.getInstance = function(callback) {
+  VolumeManager.getInstanceQueue_.run(function(completionCallback) {
+    if (VolumeManager.instance_) {
+      callback(VolumeManager.instance_);
+      completionCallback();
+      return;
+    }
+
+    chrome.fileBrowserPrivate.requestFileSystem(function(filesystem) {
+      VolumeManager.instance_ = new VolumeManager(filesystem.root);
+      callback(VolumeManager.instance_);
+      completionCallback();
+    });
+  });
+};
+
+
+/**
+ * Enables/disables Drive file system. Dispatches
+ * 'drive-enabled-status-changed' event, when the enabled state is actually
+ * changed.
+ * @param {boolean} enabled True if Drive file system is enabled.
+ */
+VolumeManager.prototype.setDriveEnabled = function(enabled) {
+  console.error('VolumeManager: setDriveEnabled: ' + enabled);
+  if (this.driveEnabled == enabled)
+    return;
+  this.driveEnabled = enabled;
+
+  // When drive is enabled, start to mount.
+  if (enabled)
+    this.mountDrive(function() {}, function() {});
+
+  var e = new cr.Event('drive-enabled-status-changed');
+  e.enabled = enabled;
+  this.dispatchEvent(e);
 };
 
 /**
@@ -169,7 +332,7 @@
  * @return {boolean} True if mounted.
  */
 VolumeManager.prototype.isMounted = function(mountPath) {
-  this.validateMountPath_(mountPath);
+  volumeManagerUtil.validateMountPath(mountPath);
   return mountPath in this.mountedVolumes_;
 };
 
@@ -185,46 +348,57 @@
  * @private
  */
 VolumeManager.prototype.initMountPoints_ = function() {
-  var mountedVolumes = [];
-  var self = this;
-  var index = 0;
   this.deferredQueue_ = [];
-  var step = function(mountPoints) {
-    if (index < mountPoints.length) {
-      var info = mountPoints[index];
-      if (info.mountType == 'drive')
-        console.error('Drive is not expected initially mounted');
-      var error = info.mountCondition ? 'error_' + info.mountCondition : '';
-      var onVolumeInfo = function(volume) {
-        mountedVolumes.push(volume);
-        index++;
-        step(mountPoints);
-      };
-      self.makeVolumeInfo_('/' + info.mountPath, error, onVolumeInfo);
-    } else {
-      for (var i = 0; i < mountedVolumes.length; i++) {
-        var volume = mountedVolumes[i];
-        self.mountedVolumes_[volume.mountPath] = volume;
-      }
+  chrome.fileBrowserPrivate.getMountPoints(function(mountPointList) {
+    // According to the C++ implementation, getMountPoints only looks at
+    // the connected devices (such as USB memory), and doesn't return anything
+    // about Drive, Downloads nor archives.
+    // TODO(hidehiko): Figure out the historical intention of the method,
+    // and clean them up.
 
+    // Create VolumeInfo for each mount point.
+    var group = new AsyncUtil.Group();
+    for (var i = 0; i < mountPointList.length; i++) {
+      var mountPoint = mountPointList[i];
+
+      // TODO(hidehiko): It should be ok that the drive is mounted already.
+      if (mountPoint.mountType == 'drive')
+        console.error('Drive is not expected initially mounted');
+
+      var error = mountPoint.mountCondition ?
+          'error_' + mountPoint.mountCondition : '';
+      group.add(function(mountPoint, error, callback) {
+        volumeManagerUtil.createVolumeInfo(
+            '/' + mountPoint.mountPath, error,
+            function(volumeInfo) {
+              this.mountedVolumes_[volumeInfo.mountPath] = volumeInfo;
+              callback();
+            }.bind(this));
+      }.bind(this, mountPoint, error));
+    }
+
+    // Then, finalize the initialization.
+    group.run(function() {
       // Subscribe to the mount completed event when mount points initialized.
       chrome.fileBrowserPrivate.onMountCompleted.addListener(
-          self.onMountCompleted_.bind(self));
+          this.onMountCompleted_.bind(this));
 
-      var deferredQueue = self.deferredQueue_;
-      self.deferredQueue_ = null;
+      // Run pending tasks.
+      var deferredQueue = this.deferredQueue_;
+      this.deferredQueue_ = null;
       for (var i = 0; i < deferredQueue.length; i++) {
         deferredQueue[i]();
       }
 
-      cr.dispatchSimpleEvent(self, 'ready');
-      self.ready_ = true;
-      if (mountedVolumes.length > 0)
-        cr.dispatchSimpleEvent(self, 'change');
-    }
-  };
+      // Now, the initialization is completed. Set the state to the ready.
+      this.ready_ = true;
 
-  chrome.fileBrowserPrivate.getMountPoints(step);
+      // Notify event listeners that the initialization is done.
+      cr.dispatchSimpleEvent(this, 'ready');
+      if (mountPointList.length > 0)
+        cr.dispatchSimpleEvent(self, 'change');
+    }.bind(this));
+  }.bind(this));
 };
 
 /**
@@ -238,18 +412,19 @@
       var requestKey = this.makeRequestKey_(
           'mount', event.mountType, event.sourcePath);
       var error = event.status == 'success' ? '' : event.status;
-      this.makeVolumeInfo_(event.mountPath, error, function(volume) {
-        this.mountedVolumes_[volume.mountPath] = volume;
-        this.finishRequest_(requestKey, event.status, event.mountPath);
-        cr.dispatchSimpleEvent(this, 'change');
-      }.bind(this));
+      volumeManagerUtil.createVolumeInfo(
+          event.mountPath, error, function(volume) {
+            this.mountedVolumes_[volume.mountPath] = volume;
+            this.finishRequest_(requestKey, event.status, event.mountPath);
+            cr.dispatchSimpleEvent(this, 'change');
+          }.bind(this));
     } else {
       console.warn('No mount path.');
       this.finishRequest_(requestKey, event.status);
     }
   } else if (event.eventType == 'unmount') {
     var mountPath = event.mountPath;
-    this.validateMountPath_(mountPath);
+    volumeManagerUtil.validateMountPath(mountPath);
     var status = event.status;
     if (status == VolumeManager.Error.PATH_UNMOUNTED) {
       console.warn('Volume already unmounted: ', mountPath);
@@ -310,45 +485,21 @@
  * @private
  */
 VolumeManager.prototype.waitDriveLoaded_ = function(mountPath, callback) {
-  chrome.fileBrowserPrivate.requestFileSystem(function(filesystem) {
-    filesystem.root.getDirectory(mountPath, {},
-        function(entry) {
-          // After file system is mounted, we need to "read" drive grand root
-          // entry at first. It loads mydrive root entry as a part of
-          // 'fast-fetch' quickly, and starts full feed fetch in parallel.
-          // Without this read, accessing mydrive root will be 'full-fetch'
-          // rather than 'fast-fetch' on the current architecture.
-          // Just "getting" the grand root entry doesn't trigger it. Rather,
-          // it starts when the entry is "read".
-          entry.createReader().readEntries(
-              callback.bind(null, true),
-              callback.bind(null, false));
-        },
-        callback.bind(null, false));
-  });
-};
-
-/**
- * @param {string} mountPath Path to the volume.
- * @param {VolumeManager?} error Mounting error if any.
- * @param {function(Object)} callback Result acceptor.
- * @private
- */
-VolumeManager.prototype.makeVolumeInfo_ = function(
-    mountPath, error, callback) {
-  if (error)
-    this.validateError_(error);
-  this.validateMountPath_(mountPath);
-  var onVolumeMetadata = function(metadata) {
-   callback({
-     mountPath: mountPath,
-     error: error,
-     deviceType: metadata && metadata.deviceType,
-     readonly: !!metadata && metadata.isReadOnly
-   });
-  };
-  chrome.fileBrowserPrivate.getVolumeMetadata(
-      util.makeFilesystemUrl(mountPath), onVolumeMetadata);
+  this.root_.getDirectory(
+      mountPath, {},
+      function(entry) {
+        // After file system is mounted, we need to "read" drive grand root
+        // entry at first. It loads mydrive root entry as a part of
+        // 'fast-fetch' quickly, and starts full feed fetch in parallel.
+        // Without this read, accessing mydrive root will be 'full-fetch'
+        // rather than 'fast-fetch' on the current architecture.
+        // Just "getting" the grand root entry doesn't trigger it. Rather,
+        // it starts when the entry is "read".
+        entry.createReader().readEntries(
+            callback.bind(null, true),
+            callback.bind(null, false));
+      },
+      callback.bind(null, false));
 };
 
 /**
@@ -411,7 +562,7 @@
 VolumeManager.prototype.unmount = function(mountPath,
                                            successCallback,
                                            errorCallback) {
-  this.validateMountPath_(mountPath);
+  volumeManagerUtil.validateMountPath(mountPath);
   if (this.deferredQueue_) {
     this.deferredQueue_.push(this.unmount.bind(this,
         mountPath, successCallback, errorCallback));
@@ -431,49 +582,11 @@
 
 /**
  * @param {string} mountPath Volume mounted path.
- * @return {VolumeManager.Error?} Returns mount error code
- *                                or undefined if no error.
+ * @return {VolumeInfo} The data about the volume.
  */
-VolumeManager.prototype.getMountError = function(mountPath) {
-  return this.getVolumeInfo_(mountPath).error;
-};
-
-/**
- * @param {string} mountPath Volume mounted path.
- * @return {boolean} True if volume at |mountedPath| is mounted but not usable.
- */
-VolumeManager.prototype.isUnreadable = function(mountPath) {
-  var error = this.getMountError(mountPath);
-  return error == VolumeManager.Error.UNKNOWN_FILESYSTEM ||
-         error == VolumeManager.Error.UNSUPPORTED_FILESYSTEM;
-};
-
-/**
- * @param {string} mountPath Volume mounted path.
- * @return {string} Device type ('usb'|'sd'|'optical'|'mobile'|'unknown')
- *   (as defined in chromeos/disks/disk_mount_manager.cc).
- */
-VolumeManager.prototype.getDeviceType = function(mountPath) {
-  return this.getVolumeInfo_(mountPath).deviceType;
-};
-
-/**
- * @param {string} mountPath Volume mounted path.
- * @return {boolean} True if volume at |mountedPath| is read only.
- */
-VolumeManager.prototype.isReadOnly = function(mountPath) {
-  return !!this.getVolumeInfo_(mountPath).readonly;
-};
-
-/**
- * Helper method.
- * @param {string} mountPath Volume mounted path.
- * @return {Object} Structure created in |startRequest_|.
- * @private
- */
-VolumeManager.prototype.getVolumeInfo_ = function(mountPath) {
-  this.validateMountPath_(mountPath);
-  return this.mountedVolumes_[mountPath] || {};
+VolumeManager.prototype.getVolumeInfo = function(mountPath) {
+  volumeManagerUtil.validateMountPath(mountPath);
+  return this.mountedVolumes_[mountPath];
 };
 
 /**
@@ -570,30 +683,7 @@
   if (status == 'success') {
     callEach(request.successCallbacks, this, [opt_mountPath]);
   } else {
-    this.validateError_(status);
+    volumeManagerUtil.validateError(status);
     callEach(request.errorCallbacks, this, [status]);
   }
 };
-
-/**
- * @param {VolumeManager.Error} error Status string iusually received from API.
- * @private
- */
-VolumeManager.prototype.validateError_ = function(error) {
-  for (var i in VolumeManager.Error) {
-    if (error == VolumeManager.Error[i])
-      return;
-  }
-  throw new Error('Invalid mount error: ', error);
-};
-
-/**
- * @param {string} mountPath Mount path.
- * @private
- */
-VolumeManager.prototype.validateMountPath_ = function(mountPath) {
-  if (!/^\/(drive|drive_shared_with_me|drive_offline|drive_recent|Downloads)$/
-       .test(mountPath) &&
-      !/^\/((archive|removable|drive)\/[^\/]+)$/.test(mountPath))
-    throw new Error('Invalid mount path: ', mountPath);
-};
diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html
index d2b05db..7fc55c0 100644
--- a/chrome/browser/resources/file_manager/main.html
+++ b/chrome/browser/resources/file_manager/main.html
@@ -14,6 +14,8 @@
 
     <meta name="google" value="notranslate">
 
+    <link rel="stylesheet" href="chrome://resources/css/apps/topbutton_bar.css"></link>
+
     <link rel="stylesheet" href="css/list.css"></link>
     <link rel="stylesheet" href="css/table.css"></link>
     <link rel="stylesheet" href="css/tree.css"></link>
@@ -297,15 +299,17 @@
             <div id="search-icon"></div>
           </div>
           <div id="search-clear-button"></div>
-          <div class="buttonbar">
-            <button class="menubutton" id="gear-button" tabindex="10"
+          <div class="topbutton-bar">
+            <button class="menubutton gear-button" id="gear-button" tabindex="10"
                     menu="#gear-menu"
                     i18n-values="aria-label:GEAR_BUTTON_TOOLTIP"
                     aria-activedescendant="gear-menu">
             </button>
-            <button id="maximize-button" visibleif="full-page" tabindex="-1">
+            <button class="maximize-button" id="maximize-button"
+                    visibleif="full-page" tabindex="-1">
             </button>
-            <button id="close-button" visibleif="full-page" tabindex="-1">
+            <button class="close-button" id="close-button"
+                    visibleif="full-page" tabindex="-1">
             </button>
           </div>
         </div>
@@ -363,7 +367,8 @@
             <div class=progress-bar>
               <div class=progress-track></div>
             </div>
-            <div class="right buttonbar" id="open-panel" visibleif="open-file open-multi-file">
+            <div class="right buttonbar" id="open-panel"
+                 visibleif="open-file open-multi-file">
               <select class="file-type"></select>
               <button class=ok disabled tabindex="7"></button>
               <button class=cancel i18n-content=CANCEL_LABEL tabindex="8"></button>
@@ -377,7 +382,8 @@
         </div>
       </div>
     </div>
-    <div class="dialog-footer progressable" visibleif="saveas-file folder">
+    <div class="dialog-footer progressable" tabindex="-1"
+         visibleif="saveas-file folder">
       <div class="left">
         <button id="new-folder" i18n-content=NEW_FOLDER_BUTTON_LABEL
                 visibleif="saveas-file folder" command="#newfolder"
diff --git a/chrome/browser/resources/file_manager/mediaplayer.html b/chrome/browser/resources/file_manager/mediaplayer.html
index c24daec..5c60121 100644
--- a/chrome/browser/resources/file_manager/mediaplayer.html
+++ b/chrome/browser/resources/file_manager/mediaplayer.html
@@ -26,6 +26,7 @@
     <!-- Keep the list in sync with mediaplayer_scripts.js. -->
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://resources/js/cr/event_target.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/volume_manager.js"></script>
diff --git a/chrome/browser/resources/file_manager/photo_import.html b/chrome/browser/resources/file_manager/photo_import.html
index 31e1b35..054cf34 100644
--- a/chrome/browser/resources/file_manager/photo_import.html
+++ b/chrome/browser/resources/file_manager/photo_import.html
@@ -47,6 +47,7 @@
     <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/file_type.js"></script>
     <script src="js/directory_contents.js"></script>
diff --git a/chrome/browser/resources/file_manager/video_player.html b/chrome/browser/resources/file_manager/video_player.html
index 458b177..41ded04 100644
--- a/chrome/browser/resources/file_manager/video_player.html
+++ b/chrome/browser/resources/file_manager/video_player.html
@@ -25,6 +25,7 @@
     <!-- Keep the list in sync with video_player_scripts.js. -->
     <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/file_type.js"></script>
     <script src="js/volume_manager.js"></script>
diff --git a/chrome/browser/resources/google_now/background.js b/chrome/browser/resources/google_now/background.js
index 893bfef..399ed96 100644
--- a/chrome/browser/resources/google_now/background.js
+++ b/chrome/browser/resources/google_now/background.js
@@ -23,8 +23,7 @@
 // TODO(vadimt): Honor the flag the enables Google Now integration.
 // TODO(vadimt): Figure out the final values of the constants.
 // TODO(vadimt): Remove 'console' calls.
-// TODO(vadimt): Consider sending JS stacks for chrome.* API errors and
-// malformed server responses.
+// TODO(vadimt): Consider sending JS stacks for malformed server responses.
 
 /**
  * Standard response code for successful HTTP requests. This is the only success
@@ -133,6 +132,9 @@
 tasks.instrumentChromeApiFunction(
     'preferencesPrivate.googleGeolocationAccessEnabled.onChange.addListener',
     0);
+tasks.instrumentChromeApiFunction('permissions.contains', 1);
+tasks.instrumentChromeApiFunction('permissions.remove', 1);
+tasks.instrumentChromeApiFunction('permissions.request', 1);
 tasks.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0);
 tasks.instrumentChromeApiFunction('runtime.onStartup.addListener', 0);
 tasks.instrumentChromeApiFunction('tabs.create', 1);
@@ -343,6 +345,7 @@
   // notifications center and bug 260376 is fixed, the below clearing
   // code is no longer necessary.
   instrumented.notifications.getAll(function(notifications) {
+    notifications = notifications || {};
     for (var notificationId in notifications) {
       chrome.notifications.clear(notificationId, function() {});
     }
@@ -402,7 +405,7 @@
   console.log('requestLocation');
   recordEvent(GoogleNowEvent.LOCATION_REQUEST);
   // TODO(vadimt): Figure out location request options.
-  chrome.metricsPrivate.getVariationParams('GoogleNow', function(params) {
+  instrumented.metricsPrivate.getVariationParams('GoogleNow', function(params) {
     var minDistanceInMeters =
         parseInt(params && params.minDistanceInMeters, 10) ||
         100;
@@ -579,15 +582,12 @@
  */
 function onNotificationClicked(notificationId, selector) {
   instrumented.storage.local.get('notificationsData', function(items) {
-    items.notificationsData = items.notificationsData || {};
+    var notificationData = items &&
+        items.notificationsData &&
+        items.notificationsData[notificationId];
 
-    var notificationData = items.notificationsData[notificationId];
-
-    if (!notificationData) {
-      // 'notificationsData' in storage may not match the actual list of
-      // notifications.
+    if (!notificationData)
       return;
-    }
 
     var actionUrls = notificationData.actionUrls;
     if (typeof actionUrls != 'object') {
@@ -595,13 +595,14 @@
     }
 
     var url = selector(actionUrls);
-
-    if (typeof url != 'string')
+    if (!url)
       return;
 
     instrumented.tabs.create({url: url}, function(tab) {
-      if (!tab)
-        chrome.windows.create({url: url});
+      if (tab)
+        chrome.windows.update(tab.windowId, {focused: true});
+      else
+        chrome.windows.create({url: url, focused: true});
     });
   });
 }
@@ -762,6 +763,36 @@
 }
 
 /**
+ * Enables or disables the Google Now background permission.
+ * @param {boolean} backgroundEnable true to run in the background.
+ *     false to not run in the background.
+ * @param {function} callback Called on completion.
+ */
+function setBackgroundEnable(backgroundEnable, callback) {
+  instrumented.permissions.contains({permissions: ['background']},
+      function(hasPermission) {
+        if (backgroundEnable != hasPermission) {
+          console.log('Action Taken setBackgroundEnable=' + backgroundEnable);
+          if (backgroundEnable)
+            instrumented.permissions.request(
+                {permissions: ['background']},
+                function() {
+                  callback();
+                });
+          else
+            instrumented.permissions.remove(
+                {permissions: ['background']},
+                function() {
+                  callback();
+                });
+        } else {
+          console.log('Action Ignored setBackgroundEnable=' + backgroundEnable);
+          callback();
+        }
+      });
+}
+
+/**
  * Does the actual work of deciding what Google Now should do
  * based off of the current state of Chrome.
  * @param {boolean} signedIn true if the user is signed in.
@@ -769,12 +800,15 @@
  *     the geolocation option is enabled.
  * @param {boolean} userRespondedToToast true if
  *     the user has responded to the toast.
+ * @param {boolean} enableBackground true if
+ *     the background permission should be requested.
  * @param {function()} callback Call this function on completion.
  */
 function updateRunningState(
     signedIn,
     geolocationEnabled,
     userRespondedToToast,
+    enableBackground,
     callback) {
 
   console.log(
@@ -784,6 +818,7 @@
 
   var shouldSetToastVisible = false;
   var shouldPollCards = false;
+  var shouldSetBackground = false;
 
   if (signedIn) {
     if (geolocationEnabled) {
@@ -794,6 +829,9 @@
         chrome.storage.local.set({userRespondedToToast: true});
       }
 
+      if (enableBackground)
+        shouldSetBackground = true;
+
       shouldPollCards = true;
     } else {
       if (userRespondedToToast) {
@@ -807,11 +845,14 @@
   }
 
   console.log(
-      'Requested Actions setToastVisible=' + shouldSetToastVisible + ' ' +
+      'Requested Actions shouldSetBackground=' + shouldSetBackground + ' ' +
+      'setToastVisible=' + shouldSetToastVisible + ' ' +
       'setShouldPollCards=' + shouldPollCards);
 
-  setToastVisible(shouldSetToastVisible, function() {
-    setShouldPollCards(shouldPollCards, callback);
+  setBackgroundEnable(shouldSetBackground, function() {
+    setToastVisible(shouldSetToastVisible, function() {
+      setShouldPollCards(shouldPollCards, callback);
+    });
   });
 }
 
@@ -824,24 +865,32 @@
     tasks.debugSetStepName('onStateChange-isSignedIn');
     authenticationManager.isSignedIn(function(token) {
       var signedIn = !!token && !!NOTIFICATION_CARDS_URL;
-      tasks.debugSetStepName(
-          'onStateChange-get-googleGeolocationAccessEnabledPref');
-      instrumented.
-          preferencesPrivate.
-          googleGeolocationAccessEnabled.
-          get({}, function(prefValue) {
-            var geolocationEnabled = !!prefValue.value;
+      instrumented.metricsPrivate.getVariationParams(
+          'GoogleNow',
+          function(response) {
+            var enableBackground =
+                (!response || (response.enableBackground != 'false'));
             tasks.debugSetStepName(
-              'onStateChange-get-userRespondedToToast');
-            instrumented.storage.local.get(
-                'userRespondedToToast',
-                function(items) {
-                  var userRespondedToToast = !!items.userRespondedToToast;
-                  updateRunningState(
-                      signedIn,
-                      geolocationEnabled,
-                      userRespondedToToast,
-                      callback);
+                'onStateChange-get-googleGeolocationAccessEnabledPref');
+            instrumented.
+                preferencesPrivate.
+                googleGeolocationAccessEnabled.
+                get({}, function(prefValue) {
+                  var geolocationEnabled = !!prefValue.value;
+                  tasks.debugSetStepName(
+                    'onStateChange-get-userRespondedToToast');
+                  instrumented.storage.local.get(
+                      'userRespondedToToast',
+                      function(items) {
+                        var userRespondedToToast =
+                            !items || !!items.userRespondedToToast;
+                        updateRunningState(
+                            signedIn,
+                            geolocationEnabled,
+                            userRespondedToToast,
+                            enableBackground,
+                            callback);
+                      });
                 });
           });
     });
@@ -922,10 +971,9 @@
         chrome.metricsPrivate.recordUserAction(
             'GoogleNow.ButtonClicked' + buttonIndex);
         onNotificationClicked(notificationId, function(actionUrls) {
-          if (!Array.isArray(actionUrls.buttonUrls))
-            return undefined;
-
-          return actionUrls.buttonUrls[buttonIndex];
+          var url = actionUrls.buttonUrls[buttonIndex];
+          verify(url, 'onButtonClicked: no url for a button');
+          return url;
         });
       }
     });
diff --git a/chrome/browser/resources/google_now/background_unittest.gtestjs b/chrome/browser/resources/google_now/background_unittest.gtestjs
index a99ff5f..f298348 100644
--- a/chrome/browser/resources/google_now/background_unittest.gtestjs
+++ b/chrome/browser/resources/google_now/background_unittest.gtestjs
@@ -55,6 +55,7 @@
 function mockInitializeDependencies(fixture) {
   fixture.makeAndRegisterMockGlobals([
     'recordEvent',
+    'setBackgroundEnable',
     'showWelcomeToast',
     'startPollingCards'
   ]);
@@ -62,6 +63,7 @@
     'authenticationManager.isSignedIn',
     'chrome.location.clearWatch',
     'chrome.storage.local.set',
+    'instrumented.metricsPrivate.getVariationParams',
     'instrumented.notifications.getAll',
     'instrumented.preferencesPrivate.googleGeolocationAccessEnabled.get',
     'instrumented.storage.local.get',
@@ -77,19 +79,22 @@
  * Note that this CAN NOT be used if any of the methods below are called
  * outside of this context with the same argument matchers.
  * expects() calls cannot be chained with the same argument matchers.
- * @param {object} mockApisObj Mock APIs Object.
+ * @param {object} fixture Test fixture.
  * @param {string} testIdentityToken getAuthToken callback token.
  * @param {boolean} testGeolocationPref Geolocation Preference callback value.
  * @param {boolean} testUserRespondedToToast User Response to toast
- &     callback value.
+ *     callback value.
+ * @param {object} testExperimentVariationParams Response of
+ *     metricsPrivate.getVariationParams
  */
 function expectStateMachineCalls(
-    mockApisObj,
+    fixture,
     testIdentityToken,
     testGeolocationPref,
-    testUserRespondedToToast) {
+    testUserRespondedToToast,
+    testExperimentVariationParams) {
   var authenticationManagerIsSignedInSavedArgs = new SaveMockArguments();
-  mockApisObj.expects(once()).
+  fixture.mockApis.expects(once()).
       authenticationManager_isSignedIn(
           authenticationManagerIsSignedInSavedArgs.match(ANYTHING)).
       will(invokeCallback(
@@ -97,8 +102,16 @@
           0,
           testIdentityToken));
 
+  var getVariationParamsSavedArgs = new SaveMockArguments();
+  fixture.mockApis.expects(once()).
+      instrumented_metricsPrivate_getVariationParams(
+          getVariationParamsSavedArgs.match(ANYTHING),
+          getVariationParamsSavedArgs.match(ANYTHING)).
+      will(invokeCallback(
+          getVariationParamsSavedArgs, 1, testExperimentVariationParams));
+
   var googleGeolocationPrefGetSavedArgs = new SaveMockArguments();
-  mockApisObj.expects(once()).
+  fixture.mockApis.expects(once()).
       instrumented_preferencesPrivate_googleGeolocationAccessEnabled_get(
           googleGeolocationPrefGetSavedArgs.match(eqJSON({})),
           googleGeolocationPrefGetSavedArgs.match(ANYTHING)).
@@ -106,11 +119,19 @@
           googleGeolocationPrefGetSavedArgs, 1, {value: testGeolocationPref}));
 
   var storageGetSavedArgs = new SaveMockArguments();
-  mockApisObj.expects(once()).
+  fixture.mockApis.expects(once()).
       instrumented_storage_local_get(
           storageGetSavedArgs.match(eq('userRespondedToToast')),
           storageGetSavedArgs.match(ANYTHING)).
       will(invokeCallback(storageGetSavedArgs, 1, testUserRespondedToToast));
+
+  var setBackgroundEnableSavedArgs = new SaveMockArguments();
+  fixture.mockGlobals.expects(once()).
+      setBackgroundEnable(
+          setBackgroundEnableSavedArgs.match(ANYTHING),
+          setBackgroundEnableSavedArgs.match(ANYTHING)).
+      will(invokeCallback(
+          setBackgroundEnableSavedArgs, 1, {}));
 }
 
 /**
@@ -155,6 +176,7 @@
       var testIdentityToken = undefined;
       var testGeolocationPref = false;
       var testUserRespondedToToast = {};
+      var testExperimentVariationParams = {};
 
       mockInitializeDependencies(this);
 
@@ -167,10 +189,11 @@
       expectInitialization(this.mockApis);
 
       expectStateMachineCalls(
-          this.mockApis,
+          this,
           testIdentityToken,
           testGeolocationPref,
-          testUserRespondedToToast);
+          testUserRespondedToToast,
+          testExperimentVariationParams);
 
       var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
       this.mockApis.expects(exactly(2)).
@@ -199,6 +222,7 @@
       var testIdentityToken = undefined;
       var testGeolocationPref = false;
       var testUserRespondedToToast = {};
+      var testExperimentVariationParams = {};
 
       mockInitializeDependencies(this);
 
@@ -211,10 +235,11 @@
       expectInitialization(this.mockApis);
 
       expectStateMachineCalls(
-          this.mockApis,
+          this,
           testIdentityToken,
           testGeolocationPref,
-          testUserRespondedToToast);
+          testUserRespondedToToast,
+          testExperimentVariationParams);
 
       var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
       this.mockApis.expects(exactly(2)).
@@ -241,6 +266,7 @@
       var testIdentityToken = 'some identity token';
       var testGeolocationPref = false;
       var testUserRespondedToToast = {};
+      var testExperimentVariationParams = {};
 
       mockInitializeDependencies(this);
 
@@ -250,10 +276,11 @@
       expectInitialization(this.mockApis);
 
       expectStateMachineCalls(
-          this.mockApis,
+          this,
           testIdentityToken,
           testGeolocationPref,
-          testUserRespondedToToast);
+          testUserRespondedToToast,
+          testExperimentVariationParams);
 
       var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
       this.mockApis.expects(exactly(2)).
@@ -278,6 +305,7 @@
   var testIdentityToken = 'some identity token';
   var testGeolocationPref = true;
   var testUserRespondedToToast = {userRespondedToToast: true};
+  var testExperimentVariationParams = {};
 
   mockInitializeDependencies(this);
 
@@ -287,10 +315,11 @@
   expectInitialization(this.mockApis);
 
   expectStateMachineCalls(
-      this.mockApis,
+      this,
       testIdentityToken,
       testGeolocationPref,
-      testUserRespondedToToast);
+      testUserRespondedToToast,
+      testExperimentVariationParams);
 
   var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
   this.mockApis.expects(exactly(2)).
@@ -315,6 +344,7 @@
   var testIdentityToken = 'some identity token';
   var testGeolocationPref = false;
   var testUserRespondedToToast = {userRespondedToToast: true};
+  var testExperimentVariationParams = {};
 
   mockInitializeDependencies(this);
 
@@ -327,10 +357,11 @@
   expectInitialization(this.mockApis);
 
   expectStateMachineCalls(
-      this.mockApis,
+      this,
       testIdentityToken,
       testGeolocationPref,
-      testUserRespondedToToast);
+      testUserRespondedToToast,
+      testExperimentVariationParams);
 
   var chromeNotificationGetAllSavedArgs = new SaveMockArguments();
   this.mockApis.expects(exactly(2)).
@@ -351,6 +382,7 @@
 function mockOnNotificationClickedDependencies(fixture) {
   fixture.makeAndRegisterMockApis([
       'chrome.windows.create',
+      'chrome.windows.update',
       'instrumented.storage.local.get',
       'instrumented.tabs.create']);
 }
@@ -413,39 +445,6 @@
 
 TEST_F(
     'GoogleNowBackgroundUnitTest',
-    'OnNotificationClicked_UrlNotString',
-    function() {
-      // Tests the case when selector returns a non-string, probably because of
-      // a malformed server response.
-      // In this case, the function should do nothing.
-
-      // Setup and expectations.
-      var testActionUrls = {testField: 'TEST VALUE'};
-      var testNotificationId = 'TEST_ID';
-      var testNotificationData = {
-          notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
-      };
-      var testActionUrl = {};
-
-      mockOnNotificationClickedDependencies(this);
-      this.makeMockLocalFunctions(['selector']);
-
-      var storageGetSavedArgs = new SaveMockArguments();
-      this.mockApis.expects(once()).
-          instrumented_storage_local_get(
-              storageGetSavedArgs.match(eq('notificationsData')),
-              storageGetSavedArgs.match(ANYTHING)).
-          will(invokeCallback(storageGetSavedArgs, 1, testNotificationData));
-      this.mockLocalFunctions.expects(once()).selector(testActionUrls).will(
-          returnValue(testActionUrl));
-
-      // Invoking the tested function.
-      onNotificationClicked(
-          testNotificationId, this.mockLocalFunctions.functions().selector);
-    });
-
-TEST_F(
-    'GoogleNowBackgroundUnitTest',
     'OnNotificationClicked_TabCreateSuccess',
     function() {
       // Tests the selected URL is OK and crome.tabs.create suceeds.
@@ -457,7 +456,7 @@
           notificationsData: {'TEST_ID': {actionUrls: testActionUrls}}
       };
       var testActionUrl = 'http://testurl.com';
-      var testCreatedTab = {};
+      var testCreatedTab = {windowId: 239};
 
       mockOnNotificationClickedDependencies(this);
       this.makeMockLocalFunctions(['selector']);
@@ -476,6 +475,9 @@
               chromeTabsCreateSavedArgs.match(eqJSON({url: testActionUrl})),
               chromeTabsCreateSavedArgs.match(ANYTHING)).
           will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
+      this.mockApis.expects(once()).chrome_windows_update(
+          testCreatedTab.windowId, 
+          eqJSON({focused: true}));
 
       // Invoking the tested function.
       onNotificationClicked(
@@ -517,7 +519,7 @@
               chromeTabsCreateSavedArgs.match(ANYTHING)).
           will(invokeCallback(chromeTabsCreateSavedArgs, 1, testCreatedTab));
       this.mockApis.expects(once()).chrome_windows_create(
-          eqJSON({url: testActionUrl}));
+          eqJSON({url: testActionUrl, focused: true}));
 
       // Invoking the tested function.
       onNotificationClicked(
diff --git a/chrome/browser/resources/google_now/cards.js b/chrome/browser/resources/google_now/cards.js
index 5e24819..ea12319 100644
--- a/chrome/browser/resources/google_now/cards.js
+++ b/chrome/browser/resources/google_now/cards.js
@@ -40,46 +40,38 @@
                 JSON.stringify(cardCreateInfo));
 
     if (cardCreateInfo.previousVersion !== cardCreateInfo.version) {
-      try {
-        // Delete a notification with the specified id if it already exists, and
-        // then create a notification.
-        instrumented.notifications.create(
-            cardId,
-            cardCreateInfo.notification,
-            function(newNotificationId) {
-              if (!newNotificationId || chrome.runtime.lastError) {
-                var errorMessage = chrome.runtime.lastError &&
-                                   chrome.runtime.lastError.message;
-                console.error('notifications.create: ID=' + newNotificationId +
-                              ', ERROR=' + errorMessage);
-                return;
-              }
+      // Delete a notification with the specified id if it already exists, and
+      // then create a notification.
+      instrumented.notifications.create(
+          cardId,
+          cardCreateInfo.notification,
+          function(newNotificationId) {
+            if (!newNotificationId || chrome.runtime.lastError) {
+              var errorMessage = chrome.runtime.lastError &&
+                                  chrome.runtime.lastError.message;
+              console.error('notifications.create: ID=' + newNotificationId +
+                            ', ERROR=' + errorMessage);
+              return;
+            }
 
-              scheduleHiding(cardId, cardCreateInfo.timeHide);
-            });
-      } catch (error) {
-        console.error('Error in notifications.create: ' + error);
-      }
+            scheduleHiding(cardId, cardCreateInfo.timeHide);
+          });
     } else {
-      try {
-        // Update existing notification.
-        instrumented.notifications.update(
-            cardId,
-            cardCreateInfo.notification,
-            function(wasUpdated) {
-              if (!wasUpdated || chrome.runtime.lastError) {
-                var errorMessage = chrome.runtime.lastError &&
-                                   chrome.runtime.lastError.message;
-                console.error('notifications.update: UPDATED=' + wasUpdated +
-                              ', ERROR=' + errorMessage);
-                return;
-              }
+      // Update existing notification.
+      instrumented.notifications.update(
+          cardId,
+          cardCreateInfo.notification,
+          function(wasUpdated) {
+            if (!wasUpdated || chrome.runtime.lastError) {
+              var errorMessage = chrome.runtime.lastError &&
+                                  chrome.runtime.lastError.message;
+              console.error('notifications.update: UPDATED=' + wasUpdated +
+                            ', ERROR=' + errorMessage);
+              return;
+            }
 
-              scheduleHiding(cardId, cardCreateInfo.timeHide);
-            });
-      } catch (error) {
-        console.error('Error in notifications.update: ' + error);
-      }
+            scheduleHiding(cardId, cardCreateInfo.timeHide);
+          });
     }
   }
 
@@ -154,8 +146,9 @@
       // Alarm to show the card.
       var cardId = alarm.name.substring(cardShowPrefix.length);
       instrumented.storage.local.get('notificationsData', function(items) {
-        items.notificationsData = items.notificationsData || {};
         console.log('cardManager.onAlarm.get ' + JSON.stringify(items));
+        if (!items || !items.notificationsData)
+          return;
         var notificationData = items.notificationsData[cardId];
         if (!notificationData)
           return;
diff --git a/chrome/browser/resources/google_now/manifest.json b/chrome/browser/resources/google_now/manifest.json
index 8aaf352..3bbf433 100644
--- a/chrome/browser/resources/google_now/manifest.json
+++ b/chrome/browser/resources/google_now/manifest.json
@@ -17,6 +17,7 @@
     "<all_urls>",
     "identity"
   ],
+  "optional_permissions": ["background"],
   "manifest_version": 2,
   "background": {
     "scripts": ["utility.js", "cards.js", "background.js"],
diff --git a/chrome/browser/resources/google_now/utility.js b/chrome/browser/resources/google_now/utility.js
index 12e9f93..7878ac4 100644
--- a/chrome/browser/resources/google_now/utility.js
+++ b/chrome/browser/resources/google_now/utility.js
@@ -20,12 +20,15 @@
 var DEBUG_MODE = localStorage['debug_mode'];
 
 /**
- * Shows a message popup in debug mode.
- * @param {string} message Diagnostic message.
+ * Builds an error object with a message that may be sent to the server.
+ * @param {string} message Error message. This message may be sent to the
+ *     server.
+ * @return {Error} Error object.
  */
-function debugAlert(message) {
-  if (DEBUG_MODE)
-    alert(message);
+function buildErrorWithMessageForServer(message) {
+  var error = new Error(message);
+  error.canSendMessageToServer = true;
+  return error;
 }
 
 /**
@@ -36,7 +39,7 @@
  */
 function verify(condition, message) {
   if (!condition)
-    throw new Error('\nASSERT: ' + message);
+    throw buildErrorWithMessageForServer('ASSERT: ' + message);
 }
 
 /**
@@ -105,12 +108,8 @@
    */
   function checkInInstrumentedCallback() {
     if (!isInInstrumentedCallback) {
-      // Cannot use verify() since no one will catch the exception.
-      // This check will detect bugs at the development stage, and is very
-      // unlikely to be seen by users.
-      var error = 'Not in instrumented callback: ' + new Error().stack;
-      console.error(error);
-      debugAlert(error);
+      reportError(buildErrorWithMessageForServer(
+          'Not in instrumented callback'));
     }
   }
 
@@ -196,29 +195,45 @@
 
   /**
    * Sends an error report to the server.
-   * @param {Error} error Error to report.
+   * @param {Error} error Error to send.
    */
   function sendErrorReport(error) {
-    var filteredStack = error.stack.replace(/.*\n/, '\n');
+    var filteredStack = error.canSendMessageToServer ?
+        error.stack : error.stack.replace(/.*\n/, '(message removed)\n');
     var file;
     var line;
-    var topFrameMatches = filteredStack.match(/\(.*\)/);
-    // topFrameMatches's example:
-    // (chrome-extension://pmofbkohncoogjjhahejjfbppikbjigm/utility.js:308:19)
-    var crashLocation = topFrameMatches && topFrameMatches[0];
-    if (crashLocation) {
-      var topFrameElements =
-          crashLocation.substring(1, crashLocation.length - 1).split(':');
-      // topFrameElements for the above example will look like:
-      // [0] chrome-extension
-      // [1] //pmofbkohncoogjjhahejjfbppikbjigm/utility.js
-      // [2] 308
-      // [3] 19
+    var topFrameLineMatch = filteredStack.match(/\n    at .*\n/);
+    var topFrame = topFrameLineMatch && topFrameLineMatch[0];
+    if (topFrame) {
+      // Examples of a frame:
+      // 1. '\n    at someFunction (chrome-extension://
+      //     pmofbkohncoogjjhahejjfbppikbjigm/background.js:915:15)\n'
+      // 2. '\n    at chrome-extension://pmofbkohncoogjjhahejjfbppikbjigm/
+      //     utility.js:269:18\n'
+      // 3. '\n    at Function.target.(anonymous function) (extensions::
+      //     SafeBuiltins:19:14)\n'
+      // 4. '\n    at Event.dispatchToListener (event_bindings:382:22)\n'
+      var errorLocation;
+      // Find the the parentheses at the end of the line, if any.
+      var parenthesesMatch = topFrame.match(/\(.*\)\n/);
+      if (parenthesesMatch && parenthesesMatch[0]) {
+        errorLocation =
+            parenthesesMatch[0].substring(1, parenthesesMatch[0].length - 2);
+      } else {
+        errorLocation = topFrame;
+      }
+
+      var topFrameElements = errorLocation.split(':');
+      // topFrameElements is an array that ends like:
+      // [N-3] //pmofbkohncoogjjhahejjfbppikbjigm/utility.js
+      // [N-2] 308
+      // [N-1] 19
       if (topFrameElements.length >= 3) {
-        file = topFrameElements[0] + ':' + topFrameElements[1];
-        line = topFrameElements[2];
+        file = topFrameElements[topFrameElements.length - 3];
+        line = topFrameElements[topFrameElements.length - 2];
       }
     }
+
     var requestParameters =
         'error=' + encodeURIComponent(error.name) +
         '&script=' + encodeURIComponent(file) +
@@ -233,6 +248,24 @@
   }
 
   /**
+   * Reports an error to the server and the user, as appropriate.
+   * @param {Error} error Error to report.
+   */
+  function reportError(error) {
+    var message = 'Critical error:\n' + error.stack;
+    console.error(message);
+    if (!errorReported) {
+      errorReported = true;
+      chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) {
+        if (isEnabled)
+          sendErrorReport(error);
+        if (DEBUG_MODE)
+          alert(message);
+      });
+    }
+  }
+
+  /**
    * Unique ID of the next callback.
    * @type {number}
    */
@@ -284,16 +317,7 @@
                'Instrumented callback is not instrumented upon exit');
         isInInstrumentedCallback = false;
       } catch (error) {
-        var message = 'Uncaught exception:\n' + error.stack;
-        console.error(message);
-        if (!errorReported) {
-          errorReported = true;
-          chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) {
-            if (isEnabled)
-              sendErrorReport(error);
-          });
-          debugAlert(message);
-        }
+        reportError(error);
       }
     };
   }
@@ -315,9 +339,10 @@
       // the original function.
       var callback = arguments[callbackParameter];
       if (typeof callback != 'function') {
-        debugAlert('Argument ' + callbackParameter + ' of ' +
-                   functionIdentifierParts.join('.') + '.' + functionName +
-                   ' is not a function');
+        reportError(buildErrorWithMessageForServer(
+            'Argument ' + callbackParameter + ' of ' +
+            functionIdentifierParts.join('.') + '.' + functionName +
+            ' is not a function'));
       }
       arguments[callbackParameter] = wrapCallback(
           callback, functionName == 'addListener');
@@ -346,6 +371,11 @@
     var instrumentedContainer = instrumented;
     functionIdentifierParts.map(function(fragment) {
       chromeContainer = chromeContainer[fragment];
+      if (!chromeContainer) {
+        reportError(buildErrorWithMessageForServer(
+            'Cannot instrument ' + functionIdentifier));
+      }
+
       if (!(fragment in instrumentedContainer))
         instrumentedContainer[fragment] = {};
 
@@ -353,9 +383,10 @@
     });
 
     var targetFunction = chromeContainer[functionName];
-
-    if (!targetFunction)
-      debugAlert('Cannot instrument ' + functionName);
+    if (!targetFunction) {
+      reportError(buildErrorWithMessageForServer(
+          'Cannot instrument ' + functionIdentifier));
+    }
 
     instrumentedContainer[functionName] = createInstrumentedFunction(
         functionIdentifierParts,
@@ -473,6 +504,10 @@
    */
   function planForNext(callback) {
     instrumented.storage.local.get(currentDelayStorageKey, function(items) {
+      if (!items) {
+        items = {};
+        items[currentDelayStorageKey] = maximumDelaySeconds;
+      }
       console.log('planForNext-get-storage ' + JSON.stringify(items));
       scheduleNextAttempt(items[currentDelayStorageKey]);
       callback();
@@ -523,15 +558,15 @@
   /**
    * Removes the specified cached token.
    * @param {string} token Authentication Token to remove from the cache.
-   * @param {function} onSuccess Called on completion.
+   * @param {function} callback Called on completion.
    */
-  function removeToken(token, onSuccess) {
+  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() {});
-      onSuccess();
+      callback();
     });
   }
 
diff --git a/chrome/browser/resources/help_app/OWNERS b/chrome/browser/resources/help_app/OWNERS
new file mode 100644
index 0000000..c78d452
--- /dev/null
+++ b/chrome/browser/resources/help_app/OWNERS
@@ -0,0 +1,2 @@
+dpolukhin@chromium.org
+nkostylev@chromium.org
diff --git a/chrome/browser/resources/help_app/manifest.json b/chrome/browser/resources/help_app/manifest.json
index b82aed5..9c984cb 100644
--- a/chrome/browser/resources/help_app/manifest.json
+++ b/chrome/browser/resources/help_app/manifest.json
@@ -8,12 +8,18 @@
   "permissions": [
     "tabs",
     "https://support.google.com/chromeos/*/*",
+    "https://support.google.com/chromebook/*/*",
     "https://gweb-gettingstartedguide.appspot.com/*",
     "chromeosInfoPrivate"
   ],
   "content_scripts": [
     {
-      "matches": ["http://support.google.com/chromeos/*", "https://support.google.com/chromeos/*"],
+      "matches": [
+        "http://support.google.com/chromeos/*",
+        "https://support.google.com/chromeos/*",
+        "http://support.google.com/chromebook/*",
+        "https://support.google.com/chromebook/*"
+      ],
       "js": ["javascript/contentscript.js"],
       "run_at": "document_end",
       "all_frames": true
diff --git a/chrome/browser/resources/history/history.css b/chrome/browser/resources/history/history.css
index 61bddb3..6d41422 100644
--- a/chrome/browser/resources/history/history.css
+++ b/chrome/browser/resources/history/history.css
@@ -572,10 +572,6 @@
   outline: none;
 }
 
-body:not(.has-results) #results-pagination {
-  display: none;
-}
-
 #older-button {
   float: right;
 }
diff --git a/chrome/browser/resources/history/history.html b/chrome/browser/resources/history/history.html
index 6c82921..a58e433 100644
--- a/chrome/browser/resources/history/history.html
+++ b/chrome/browser/resources/history/history.html
@@ -2,7 +2,7 @@
 <html i18n-values="dir:textdirection;">
 <head>
 <meta charset="utf-8">
-<if expr="is_android or pp_ifdef('ios')">
+<if expr="is_android or is_ios">
 <meta name="viewport" content="width=device-width, initial-scale=1.0,
                                maximum-scale=1.0, user-scalable=no">
 </if>
@@ -11,19 +11,19 @@
 <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
 <link rel="stylesheet" href="chrome://resources/css/menu.css">
 <link rel="stylesheet" href="chrome://resources/css/menu_button.css">
-<if expr="not is_android and not pp_ifdef('ios')">
+<if expr="not is_android and not is_ios">
 <link rel="stylesheet" href="alert_overlay.css">
 <link rel="stylesheet" href="chrome://resources/css/overlay.css">
 </if>
 <link rel="stylesheet" href="chrome://resources/css/spinner.css">
-<if expr="not is_android and not pp_ifdef('ios')">
+<if expr="not is_android and not is_ios">
 <link rel="stylesheet" href="../uber/uber_shared.css">
 </if>
 <link rel="stylesheet" href="history.css">
-<if expr="is_android or pp_ifdef('ios')">
+<if expr="is_android or is_ios">
 <link rel="stylesheet" href="history_mobile.css">
 </if>
-<if expr="not is_android and not pp_ifdef('ios')">
+<if expr="not is_android and not is_ios">
 <link rel="stylesheet" href="other_devices.css">
 </if>
 
@@ -34,7 +34,7 @@
 <script src="chrome://resources/js/cr/ui/focus_manager.js"></script>
 <script src="chrome://resources/js/cr/ui/menu_item.js"></script>
 <script src="chrome://resources/js/cr/ui/menu.js"></script>
-<if expr="not is_android and not pp_ifdef('ios')">
+<if expr="not is_android and not is_ios">
 <script src="chrome://resources/js/cr/ui/alert_overlay.js"></script>
 <script src="chrome://resources/js/cr/ui/overlay.js"></script>
 </if>
@@ -54,15 +54,15 @@
 
 </head>
 
-<if expr="not is_android">
+<if expr="not is_android and not is_ios">
 <body class="uber-frame"
     i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
 </if>
-<if expr="is_android or pp_ifdef('ios')">
+<if expr="is_android or is_ios">
 <body i18n-values=".style.fontFamily:fontfamily">
 </if>
 
-<if expr="not is_android and not pp_ifdef('ios')">
+<if expr="not is_android and not is_ios">
 <div id="overlay" class="overlay" hidden>
   <include src="alert_overlay.html">
 </div>
@@ -138,7 +138,7 @@
   </div>
 </div>
 
-<menu id="action-menu">
+<menu id="action-menu" hidden>
   <button id="more-from-site" i18n-content="moreFromSite"></button>
   <button id="remove-visit" i18n-content="removeFromHistory"></button>
 </menu>
diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js
index 1227c99..9d8ceba 100644
--- a/chrome/browser/resources/history/history.js
+++ b/chrome/browser/resources/history/history.js
@@ -929,15 +929,14 @@
  */
 HistoryView.prototype.onModelReady = function(doneLoading) {
   this.displayResults_(doneLoading);
-
-  // Allow custom styling based on whether there are any results on the page.
-  // To make this easier, add a class to the body if there are any results.
-  if (this.model_.visits_.length)
-    document.body.classList.add('has-results');
-  else
-    document.body.classList.remove('has-results');
-
   this.updateNavBar_();
+
+  if (isMobileVersion()) {
+    // Hide the search field if it is empty and there are no results.
+    var hasResults = this.model_.visits_.length > 0;
+    var isSearch = this.model_.getSearchText().length > 0;
+    $('search-field').hidden = !(hasResults || isSearch);
+  }
 };
 
 /**
@@ -1298,7 +1297,6 @@
           createElementWithClassName('div', 'no-results-message'));
       noResults.textContent = loadTimeData.getString('noResults');
       this.resultDiv_.appendChild(resultsFragment);
-      this.updateNavBar_();
       return;
     }
 
@@ -1326,7 +1324,6 @@
     // Add all the days and their visits to the page.
     this.resultDiv_.appendChild(resultsFragment);
   }
-  this.updateNavBar_();
 };
 
 /**
@@ -1335,9 +1332,10 @@
  */
 HistoryView.prototype.updateNavBar_ = function() {
   this.updateRangeButtons_();
+
+  // Managed users have the control bar on top, don't show it on the bottom
+  // as well.
   if (!loadTimeData.getBoolean('isManagedProfile')) {
-    // Managed users have the control bar on top, don't show it on the bottom
-    // as well.
     $('newest-button').hidden = this.pageIndex_ == 0;
     $('newer-button').hidden = this.pageIndex_ == 0;
     $('older-button').hidden =
diff --git a/chrome/browser/resources/history/history_mobile.css b/chrome/browser/resources/history/history_mobile.css
index 41268f5..bb5b82e 100644
--- a/chrome/browser/resources/history/history_mobile.css
+++ b/chrome/browser/resources/history/history_mobile.css
@@ -66,11 +66,6 @@
   background-position: right 16px center;
 }
 
-/* Hide the search field if it is empty (!valid) and there are no results. */
-body:not(.has-results) #search-field:not(:valid) {
-  display: none;
-}
-
 .no-results-message {
   margin-bottom: 1em;
   padding-left: 16px;
@@ -170,7 +165,7 @@
   margin: 0;
 }
 
-<if expr="pp_ifdef('ios')">
+<if expr="is_ios">
 /* Add extra spacing caused by the missing search bar on iOS. */
 h3:first-of-type {
   margin-top: 16px;
@@ -221,7 +216,7 @@
   margin-top: 16px;
 }
 
-<if expr="pp_ifdef('ios')">
+<if expr="is_ios">
 /* iOS does not support the latest flexbox syntax, only the 2009 working draft
    syntax (http://www.w3.org/TR/2009/WD-css3-flexbox-20090723/). */
 .entry-box,
diff --git a/chrome/browser/resources/incognito_tab.css b/chrome/browser/resources/incognito_tab.css
deleted file mode 100644
index 1b8c8df..0000000
--- a/chrome/browser/resources/incognito_tab.css
+++ /dev/null
@@ -1,51 +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. */
-
-body {
-  margin: 10px 8px;
-}
-
-.icon {
-  -webkit-margin-end: 3px;
-  -webkit-margin-start: 6px;
-}
-
-html[dir='ltr'] .icon {
-  -webkit-transform: scaleX(-1);
-  float: right;
-}
-
-html[dir='rtl'] .icon {
-  float: left;
-}
-
-.content {
-  background-color: #eee;
-  border-radius: 5px;
-  color: black;
-  margin-left: auto;
-  margin-right: auto;
-  margin-top: 66px;
-  max-width: 600px;
-  padding: 10px;
-}
-
-.extensions-message {
-  -webkit-padding-start: 39px;
-  margin-top: 15px;
-  position: relative;
-}
-
-.extension-icon {
-  content: -webkit-image-set(
-      url('../../app/theme/default_100_percent/extensions_section.png') 1x,
-      url('../../app/theme/default_200_percent/extensions_section.png') 2x);
-  display: inline-block;
-  left: 0;
-  margin-top: -15px;
-  position: absolute;
-  right: 0;
-  top: 50%;
-  width: 30px;
-}
diff --git a/chrome/browser/resources/incognito_tab.html b/chrome/browser/resources/incognito_tab.html
deleted file mode 100644
index ffc19d6..0000000
--- a/chrome/browser/resources/incognito_tab.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!DOCTYPE html>
-<html i18n-values="dir:textdirection;bookmarkbarattached:bookmarkbarattached">
-<head>
-<title i18n-content="title"></title>
-<link rel="stylesheet" href="incognito_tab.css">
-<script>
-// Until themes can clear the cache, force-reload the theme stylesheet.
-document.write('<link id="incognitothemecss" rel="stylesheet" ' +
-               'href="chrome://theme/css/incognito_new_tab_theme.css?' +
-               Date.now() + '">');
-</script>
-</head>
-<body>
-<div class="content"
-    i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
-  <img src="../../../ui/webui/resources/images/otr_icon_standalone.png" class="icon">
-  <span i18n-values=".innerHTML:content"></span>
-  <div class="extensions-message">
-    <div class="extension-icon"></div>
-    <span i18n-values=".innerHTML:extensionsmessage"></span>
-  </div>
-</div>
-</body>
-<script src="chrome://resources/js/cr.js"></script>
-<script>
-cr.define('ntp', function() {
-  'use strict';
-  /**
-   * Set whether the bookmarks bar is attached or not.
-   * @param {boolean} attached Whether the bar is attached or not.
-   */
-  function setBookmarkBarAttached(attached) {
-    document.documentElement.setAttribute('bookmarkbarattached', !!attached);
-  }
-
-  function themeChanged() {
-    document.getElementById('incognitothemecss').href =
-        'chrome://theme/css/incognito_new_tab_theme.css?' + Date.now();
-  }
-
-  return {
-    setBookmarkBarAttached: setBookmarkBarAttached,
-    themeChanged: themeChanged,
-  };
-});
-</script>
-</html>
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index 8cc00a9..e2d3ab2 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -136,6 +136,14 @@
   padding: 5px 0;
 }
 
+.subrow {
+  padding: 5px 24px;
+}
+
+.invisible-view {
+  color: rgb(151, 156, 160);
+}
+
 .url {
   color: #A0A0A0;
 }
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index 9070fa6..a066005 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -212,7 +212,10 @@
 
         var browserHeader = document.createElement('div');
         browserHeader.className = 'browser-header';
-        browserHeader.textContent = browser.adbBrowserProduct;
+        if (browser.adbBrowserPackage && !isChrome)
+          browserHeader.textContent = browser.adbBrowserPackage;
+        else
+          browserHeader.textContent = browser.adbBrowserProduct;
         var majorChromeVersion = 0;
         if (browser.adbBrowserVersion) {
           browserHeader.textContent += ' (' + browser.adbBrowserVersion + ')';
@@ -262,7 +265,7 @@
       for (var p = 0; p < browser.pages.length; p++) {
         var page = browser.pages[p];
         var row = addTargetToList(
-            page, pageList, ['faviconUrl', 'name', 'url']);
+            page, pageList, ['faviconUrl', 'name', 'url', 'description']);
         if (isChrome) {
           row.appendChild(createActionLink(
               'reload', reload.bind(null, page), page.attached));
@@ -323,14 +326,50 @@
   return span;
 }
 
+function addWebViewDescription(webview, list) {
+  var viewStatus = { visibility: 'empty', position: '', size: '' };
+  if (!webview.empty) {
+    if (webview.attached)
+      viewStatus.visibility = webview.visible ? 'visible' : 'hidden';
+    else
+      viewStatus.visibility = 'detached';
+    viewStatus.size = 'size ' + webview.width + ' \u00d7 ' + webview.height;
+  }
+  if (webview.attached) {
+      viewStatus.position =
+        'at (' + webview.screenX + ', ' + webview.screenY + ')';
+  }
+
+  var row = document.createElement('div');
+  row.className = 'subrow';
+  if (webview.empty || !webview.attached || !webview.visible)
+    row.className += ' invisible-view';
+  row.appendChild(formatValue(viewStatus, 'visibility'));
+  row.appendChild(formatValue(viewStatus, 'position'));
+  row.appendChild(formatValue(viewStatus, 'size'));
+  list.appendChild(row);
+  return row;
+}
+
 function addTargetToList(data, list, properties) {
   var row = document.createElement('div');
   row.className = 'row';
-  for (var j = 0; j < properties.length; j++)
-    row.appendChild(formatValue(data, properties[j]));
+  var description = null;
+  for (var j = 0; j < properties.length; j++) {
+    if (properties[j] != 'description')
+      row.appendChild(formatValue(data, properties[j]));
+    else if (data['description']) {
+      try {
+        description = JSON.parse(data['description']);
+      } catch (e) {}
+    }
+  }
 
   row.appendChild(createActionLink('inspect', inspect.bind(null, data)));
 
+  if (description)
+    addWebViewDescription(description, row);
+
   row.processId = data.processId;
   row.routeId = data.routeId;
 
diff --git a/chrome/browser/resources/local_discovery/local_discovery.css b/chrome/browser/resources/local_discovery/local_discovery.css
index 535df79..2433e43 100644
--- a/chrome/browser/resources/local_discovery/local_discovery.css
+++ b/chrome/browser/resources/local_discovery/local_discovery.css
@@ -13,3 +13,19 @@
 td {
   background-color: #f0f0f0;
 }
+
+#info-console {
+  background-color: #f0f0f0;
+  height: 100px;
+  overflow: auto;
+}
+
+.info-item {
+  border-bottom: 2px #f0f0f0 solid;
+  margin-bottom: 5px;
+}
+
+.info-item .info-item-name {
+  font-weight: bold;
+  padding-right: 20px;
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/local_discovery/local_discovery.html b/chrome/browser/resources/local_discovery/local_discovery.html
index dc1e8df..007524f 100644
--- a/chrome/browser/resources/local_discovery/local_discovery.html
+++ b/chrome/browser/resources/local_discovery/local_discovery.html
@@ -6,24 +6,30 @@
   <link rel="stylesheet" href="local_discovery.css">
   <script src="chrome://resources/js/cr.js"></script>
   <script src="chrome://resources/js/util.js"></script>
+  <script src="chrome://resources/js/load_time_data.js"></script>
   <script src="local_discovery.js"></script>
+  <script src="strings.js"></script>
 </head>
 <body>
-  <p>
-    Searching for discoverable devices...
-  </p>
   <div>
+    <div id="info-console"></div>
     <table id="devices-table" width="100%">
       <thead>
-        <th>Name</th>
-        <th>Domain</th>
-        <th>Port</th>
-        <th>IP</th>
-        <th>Metadata</th>
-        <th>Last seen</th>
-        <th>Registered</th>
+        <th i18n-content="serviceName"></th>
+        <th i18n-content="serviceDomain"></th>
+        <th i18n-content="servicePort"></th>
+        <th i18n-content="serviceIp"></th>
+        <th i18n-content="serviceLastseen"></th>
+        <th i18n-content="serviceRegister"></th>
+        <th i18n-content="serviceInfo"></th>
       </thead>
     </table>
   </div>
+
+  <div id="info-pane">
+  </div>
+
+  <script src="chrome://resources/js/i18n_template2.js"></script>
+  <script src="chrome://resources/js/jstemplate_compiled.js"></script>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/chrome/browser/resources/local_discovery/local_discovery.js b/chrome/browser/resources/local_discovery/local_discovery.js
index 1ef4eb1..a926a5a 100644
--- a/chrome/browser/resources/local_discovery/local_discovery.js
+++ b/chrome/browser/resources/local_discovery/local_discovery.js
@@ -10,55 +10,270 @@
  * callbacks from the C++ code saying that a new device is available.
  */
 
-/**
- * Appends a row to the output table listing the new device.
- * @param {string} name of the device service.
- * @param {string} info - additional info of the device,
- *                        if empty device need to be deleted
- */
-function onServiceUpdate(name, info) {
-  var table = $('devices-table');
+cr.define('local_discovery', function() {
+  'use strict';
 
-  var params = [];
-  if (info) {
-    params[0] = info.domain;
-    params[1] = info.port;
-    params[2] = info.ip;
-    params[3] = info.metadata;
-    params[4] = info.lastSeen;
-    params[5] = info.registered;
+  /**
+   * Add a text TD to a TR.
+   * @param {HTMLTableRowElement} row Row in table to be filled.
+   * @param {string} text Text of TD.
+   */
+  function textTD(row, text) {
+    var td = document.createElement('td');
+    td.textContent = text;
+    row.appendChild(td);
   }
 
-  for (var i = 0, row; row = table.rows[i]; i++) {
-    if (row.cells[0].textContent == name) {
-      if (!info) {
-        // Delete service from the row.
-        table.removeChild(row);
-      } else {
-        // Replace existing service.
-        for (var j = 0; j < params.length; j++) {
-          row.cells[j + 1].textContent = params[j];
+  /**
+   * Add a button TD to a TR.
+   * @param {HTMLTableRowElement} row Row in table to be filled.
+   * @param {string} text Text of button.
+   * @param {function()} action Action to be taken when button is pressed.
+   */
+  function buttonTD(row, text, action) {
+    var td = document.createElement('td');
+    var button = document.createElement('button');
+    button.textContent = text;
+    button.addEventListener('click', action);
+    td.appendChild(button);
+    row.appendChild(td);
+  }
+
+  /**
+   * Fill a table row from the provided information.
+   * @param {HTMLTableRowElement} row Row in table to be filled.
+   * @param {string} name Name of the device.
+   * @param {Object} info Information about the device.
+   */
+  function fillRow(row, name, info) {
+    textTD(row, name);
+    textTD(row, info.domain);
+    textTD(row, info.port);
+    textTD(row, info.ip);
+    textTD(row, info.lastSeen);
+
+    if (!info.registered) {
+      buttonTD(row, loadTimeData.getString('serviceRegister'),
+               sendRegisterDevice.bind(null, name));
+    } else {
+      textTD(row, loadTimeData.getString('registered'));
+    }
+
+    buttonTD(row, loadTimeData.getString('serviceInfo'),
+             sendInfoRequest.bind(null, name));
+  }
+
+  /**
+   * Appends a row to the output table listing the new device.
+   * @param {string} name Name of the device.
+   * @param {string} info Additional info of the device, if empty device need to
+   *                      be deleted.
+   */
+  function onServiceUpdate(name, info) {
+    name = name.replace(/[\r\n]/g, '');
+    var table = $('devices-table');
+
+    for (var i = 0, row; row = table.rows[i]; i++) {
+      if (row.cells[0].textContent == name) {
+        if (!info) {
+          // Delete service from the row.
+          table.removeChild(row);
+        } else {
+          // Replace existing service.
+          while (row.firstChild) {
+            row.removeChild(row.firstChild);
+          }
+
+          fillRow(row, name, info);
+          return;
         }
       }
+    }
+
+    if (!info) {
+      // Service could not be found in the table.
       return;
     }
+
+    // Row does not exist. Create it.
+    var tr = document.createElement('tr');
+
+    fillRow(tr, name, info);
+    table.appendChild(tr);
+  }
+
+  /**
+   * Adds a row to the logging console.
+   * @param {string} msg The message to log.
+   */
+  function logToInfoConsole(msg) {
+    var div = document.createElement('div');
+    div.textContent = msg;
+    $('info-console').appendChild(div);
+  }
+
+  /**
+   * Register a device.
+   * @param {string} device The device to register.
+   */
+  function sendRegisterDevice(device) {
+    chrome.send('registerDevice', [device]);
+    logToInfoConsole(loadTimeData.getStringF('registeringService', device));
+  }
+
+  /**
+   * Announce that a registration failed.
+   * @param {string} reason The error message.
+   */
+  function registrationFailed(reason) {
+    logToInfoConsole(loadTimeData.getStringF('registrationFailed', reason));
+  }
+
+  /**
+   * Request the contents of a device's /info page.
+   * @param {string} device The device to query.
+   */
+  function sendInfoRequest(device) {
+    chrome.send('info', [device]);
+    logToInfoConsole(loadTimeData.getStringF('infoStarted', device));
+  }
+
+  /**
+   * Announce that a registration succeeeded.
+   * @param {string} id The id of the newly registered device.
+   */
+  function registrationSuccess(id) {
+    logToInfoConsole(loadTimeData.getStringF('registrationSucceeded', id));
+  }
+
+  /**
+   * Render an info item onto the info pane.
+   * @param {string} name Name of the item.
+   * @param {?} value Value of the item.
+   * @param {function(?):string} render_type Render function for value
+   *     datatype.
+   * @return {HTMLElement} Rendered info item.
+   */
+  function renderInfoItem(name, value, render_type) {
+    var container = document.createElement('div');
+    container.classList.add('info-item');
+    var nameElem = document.createElement('span');
+    nameElem.classList.add('info-item-name');
+    nameElem.textContent = name;
+    container.appendChild(nameElem);
+    var valueElem = document.createElement('span');
+    valueElem.textContent = render_type(value);
+    container.appendChild(valueElem);
+    return container;
+  }
+
+  /**
+   * Render and append an info item to the info pane, if it exists.
+   * @param {Object} info Info response.
+   * @param {string} name Name of property.
+   * @param {function(?):string} render_type Render function for value.
+   */
+  function infoItem(info, name, render_type) {
+    if (name in info) {
+      $('info-pane').appendChild(renderInfoItem(name, info[name], render_type));
+    }
   }
 
-  if (!info) {
-    // Service could not be found in the table.
-    return;
+  /**
+   * Render a string to an info-pane-displayable string.
+   * @param {?} value Value; not guaranteed to be a string.
+   * @return {string} Rendered value.
+   */
+  function renderTypeString(value) {
+    if (typeof value != 'string') {
+      return 'INVALID';
+    }
+    return value;
   }
 
-  var tr = document.createElement('tr');
-  var td = document.createElement('td');
-  td.textContent = name;
-  tr.appendChild(td);
+  /**
+   * Render a integer to an info-pane-displayable string.
+   * @param {?} value Value; not guaranteed to be an integer.
+   * @return {string} Rendered value.
+   */
+  function renderTypeInt(value) {
+    if (typeof value != 'number') {
+      return 'INVALID';
+    }
 
-  for (var j = 0; j < params.length; j++) {
-    td = document.createElement('td');
-    td.textContent = params[j];
-    tr.appendChild(td);
+    return value.toString();
   }
 
-  table.appendChild(tr);
-}
+  /**
+   * Render an array to an info-pane-displayable string.
+   * @param {?} value Value; not guaranteed to be an array.
+   * @return {string} Rendered value.
+   */
+  function renderTypeStringList(value) {
+    if (!Array.isArray(value)) {
+      return 'INVALID';
+    }
+
+    var returnValue = '';
+    var valueLength = value.length;
+    for (var i = 0; i < valueLength - 1; i++) {
+      returnValue += value[i];
+      returnValue += ', ';
+    }
+
+    if (value.length != 0) {
+      returnValue += value[value.length - 1];
+    }
+
+    return returnValue;
+  }
+
+  /**
+   * Render info response from JSON.
+   * @param {Object} info Info response.
+   */
+  function renderInfo(info) {
+    // Clear info
+    while ($('info-pane').firstChild) {
+      $('info-pane').removeChild($('info-pane').firstChild);
+    }
+
+    infoItem(info, 'x-privet-token', renderTypeString);
+    infoItem(info, 'id', renderTypeString);
+    infoItem(info, 'name', renderTypeString);
+    infoItem(info, 'description', renderTypeString);
+    infoItem(info, 'type', renderTypeStringList);
+    infoItem(info, 'api', renderTypeStringList);
+    infoItem(info, 'connection_state', renderTypeString);
+    infoItem(info, 'device_state', renderTypeString);
+    infoItem(info, 'manufacturer', renderTypeString);
+    infoItem(info, 'url', renderTypeString);
+    infoItem(info, 'model', renderTypeString);
+    infoItem(info, 'serial_number', renderTypeString);
+    infoItem(info, 'firmware', renderTypeString);
+    infoItem(info, 'uptime', renderTypeInt);
+    infoItem(info, 'setup_url', renderTypeString);
+    infoItem(info, 'support_url', renderTypeString);
+    infoItem(info, 'update_url', renderTypeString);
+  }
+
+  /**
+   * Announce that an info request failed.
+   * @param {string} reason The error message.
+   */
+  function infoFailed(reason) {
+    logToInfoConsole(loadTimeData.getStringF('infoFailed', reason));
+  }
+
+  document.addEventListener('DOMContentLoaded', function() {
+    chrome.send('start');
+  });
+
+  return {
+    registrationSuccess: registrationSuccess,
+    registrationFailed: registrationFailed,
+    onServiceUpdate: onServiceUpdate,
+    infoFailed: infoFailed,
+    renderInfo: renderInfo
+  };
+});
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index b387819..e6a7755 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -1052,6 +1052,9 @@
         setFakeboxDragFocus(false);
       };
     }
+
+    // Update the fakebox style to match the current key capturing state.
+    setFakeboxFocus(searchboxApiHandle.isKeyCaptureEnabled);
   }
 
   if (searchboxApiHandle.rtl) {
diff --git a/chrome/browser/resources/local_ntp/most_visited_thumbnail.js b/chrome/browser/resources/local_ntp/most_visited_thumbnail.js
index 7417b04..8952d70 100644
--- a/chrome/browser/resources/local_ntp/most_visited_thumbnail.js
+++ b/chrome/browser/resources/local_ntp/most_visited_thumbnail.js
@@ -11,14 +11,18 @@
   'use strict';
 
   fillMostVisited(document.location, function(params, data) {
+    function logEvent(eventName) {
+      chrome.embeddedSearch.newTabPage.logEvent(eventName);
+    }
     function showDomainElement() {
+      logEvent(NTP_LOGGING_EVENT_TYPE.NTP_THUMBNAIL_ERROR);
       var link = createMostVisitedLink(params, data.url, data.title);
       var domain = document.createElement('div');
       domain.textContent = data.domain;
       link.appendChild(domain);
       document.body.appendChild(link);
     };
-    if (data.thumbnailUrl) {
+    function createAndAppendThumbnail(isVisible) {
       var image = new Image();
       image.onload = function() {
         var shadow = document.createElement('span');
@@ -28,9 +32,33 @@
         link.appendChild(image);
         document.body.appendChild(link);
       };
+      if (!isVisible) {
+        image.style.visibility = 'hidden';
+      }
+      return image;
+    }
 
-      image.onerror = showDomainElement;
+    if (data.thumbnailUrl) {
+      var image = createAndAppendThumbnail(true);
+      // If a backup thumbnail URL was provided, preload it in case the first
+      // thumbnail errors. The backup thumbnail is always preloaded so that the
+      // server can't gain knowledge on the local thumbnail DB by specifying a
+      // second URL that is only sometimes fetched.
+      if (data.thumbnailUrl2) {
+        var image2 = createAndAppendThumbnail(false);
+        image2.onerror = showDomainElement;
+        image2.src = data.thumbnailUrl2;
+        // The first thumbnail's onerror function will swap the visibility of
+        // the two thumbnails.
+        image.onerror = function() {
+          image.style.visibility = 'hidden';
+          image2.style.visibility = 'visible';
+        };
+      } else {
+        image.onerror = showDomainElement;
+      }
       image.src = data.thumbnailUrl;
+      logEvent(NTP_LOGGING_EVENT_TYPE.NTP_THUMBNAIL_ATTEMPT);
     } else {
       showDomainElement();
     }
diff --git a/chrome/browser/resources/local_ntp/most_visited_util.js b/chrome/browser/resources/local_ntp/most_visited_util.js
index 5352128..446b7ca 100644
--- a/chrome/browser/resources/local_ntp/most_visited_util.js
+++ b/chrome/browser/resources/local_ntp/most_visited_util.js
@@ -9,6 +9,19 @@
 
 <include src="instant_iframe_validation.js">
 
+/**
+ * Enum for the different types of events that are logged from the NTP.
+ * @enum {number}
+ * @const
+ */
+var NTP_LOGGING_EVENT_TYPE = {
+  // The user moused over an NTP tile or title.
+  NTP_MOUSEOVER: 0,
+  // The page attempted to load a thumbnail image.
+  NTP_THUMBNAIL_ATTEMPT: 1,
+  // There was an error in loading a thumbnail image.
+  NTP_THUMBNAIL_ERROR: 2
+};
 
 /**
  * Parses query parameters from Location.
@@ -62,7 +75,7 @@
     link.textContent = text;
   link.addEventListener('mouseover', function() {
     var ntpApiHandle = chrome.embeddedSearch.newTabPage;
-    ntpApiHandle.logEvent('NewTabPage.NumberOfMouseOvers');
+    ntpApiHandle.logEvent(NTP_LOGGING_EVENT_TYPE.NTP_MOUSEOVER);
   });
   return link;
 }
@@ -114,8 +127,10 @@
     // Means that we get suggestion data from the server. Create data object.
     data.url = params.url;
     data.thumbnailUrl = params.tu || '';
+    data.thumbnailUrl2 = params.tu2 || '';
     data.title = params.ti || '';
     data.direction = params.di || '';
+    data.domain = params.dom || '';
   } else {
     var apiHandle = chrome.embeddedSearch.searchBox;
     data = apiHandle.getMostVisitedItemData(params.rid);
@@ -123,7 +138,8 @@
       return;
   }
   if (/^javascript:/i.test(data.url) ||
-      /^javascript:/i.test(data.thumbnailUrl))
+      /^javascript:/i.test(data.thumbnailUrl) ||
+      /^javascript:/i.test(data.thumbnailUrl2))
     return;
   if (data.direction)
     document.body.dir = data.direction;
diff --git a/chrome/browser/resources/net_internals/cros_log_analyzer_view.css b/chrome/browser/resources/net_internals/cros_log_analyzer_view.css
deleted file mode 100644
index 098190c..0000000
--- a/chrome/browser/resources/net_internals/cros_log_analyzer_view.css
+++ /dev/null
@@ -1,234 +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.
-  */
-
- #cros-log-analyzer-header {
-  margin-bottom: 20px;
- }
-
-.cros-log-analyzer-container {
-  background-color: rgb(242, 242, 242);
-  border: 1px solid rgb(220, 220, 220);
-}
-
-#cros-log-analyzer-log-content {
-  border: 1px solid rgb(220, 220, 220);
-  font-size: 11px;
-  height: 300px;
-  line-height: 18px;
-  margin-bottom: -1px;
-  overflow: scroll;
-  padding: 10px;
-  width: 1000px;
- }
-
-#cros-log-analyzer-filter-container {
-  font-size: 12px;
-  margin-bottom: 5px;
-  padding: 5px 10px;
-  width: 1000px;
-}
-
-#cros-log-analyzer-filter-container p {
-  margin: 10px 0;
-}
-
-#cros-log-analyzer-log-table {
-  table-layout: fixed;
-  width: 950px;
-}
-
-#cros-log-analyzer-log-table td {
-  overflow: hidden;
-  table-layout: fixed;
-  word-wrap: break-word;
-}
-
-.cros-log-analyzer-td-time {
-  width: 100px;
-}
-
-#cros-log-analyzer-log-header-table {
-  font-size: 12px;
-  font-weight: bold;
-  margin-bottom: -1px;
-  text-align: center;
-  width: 1000px;
-}
-
-.cros-log-analyzer-td-pname {
-  text-align: center;
-  width: 120px;
-}
-
-.cros-log-analyzer-td-level {
-  width: 70px;
-}
-
-.cros-log-analyzer-td-level p {
-  border: 1px solid;
-  border-radius: 5px;
-  margin: 0 3px;
-  text-align: center;
-  width: 58px;
-}
-
-.cros-log-analyzer-td-level-error {
-  background-color: rgb(255, 153, 163);
-  color: red;
-}
-
-.cros-log-analyzer-td-level-info {
-  background-color: rgb(195, 227, 250);
-  color: rgb(10, 147, 245);
-  width: 120px;
-}
-
-.cros-log-analyzer-td-level-warning {
-  background-color: rgb(250, 229, 195);
-  color: darkorange;
-}
-
-.cros-log-analyzer-td-level-unknown {
-  color: gray;
-}
-
-.cros-log-analyzer-td-pid {
-  width: 60px;
-}
-
-#cros-log-analyzer-filter-pname {
-  border-bottom: 1px solid rgb(209, 209, 209);
-  padding: 5px 0 10px 0;
-}
-
-#cros-log-analyzer-filter-level {
-  padding: 5px 0 10px 0;
-}
-
-#cros-log-analyzer-search-container {
-  -webkit-margin-start: 760px;
-  border-radius: 5px;
-  font-size: 12px;
-  margin-bottom: 5px;
-  margin-left: 720px;
-  margin-top: -40px;
-  padding: 5px;
-  width: 280px;
-}
-
-#cros-log-analyzer-search-container input {
-  border: 1px solid rgb(220, 220, 220);
-}
-
-#cros-log-analyzer-visualizer-container {
-  border: 1px solid rgb(211, 211, 211);
-  height: 100px;
-  position: relative;
-  width: 1002px;
-}
-
-#cros-log-analyzer-visualizer-timeline {
-  background: gray;
-  opacity: 0.5;
-  position: absolute;
-  top: 0;
-  width: 2px;
-}
-
-.cros-log-analyzer-visualizer-time-display {
-  font-size: 10px;
-  position: absolute;
-  width: 50px;
-}
-
-#cros-log-analyzer-visualizer-reset-btn {
-  border: 1px solid rgb(211, 211, 211);
-  border-radius: 2px;
-  position: absolute;
-  right: 5px;
-  top: 5px;
-}
-
-#cros-log-analyzer-visualizer-tracking-layer {
-  background: none;
-  height: 100%;
-  left: 0;
-  position: absolute;
-  top: 0;
-  width: 100%;
-}
-
-.cros-log-analyzer-visualizer-canvas {
-  left: 0;
-  position: absolute;
-  top: 0;
-}
-
-.cros-log-analyzer-flash {
-  -webkit-animation: fade 1s linear 1;
-}
-
-#cros-log-analyzer-marker-container {
-  background-color: rgb(242, 242, 242);
-  border: 1px solid rgb(211, 211, 211);
-  left: 1030px;
-  min-height: 320px;
-  padding: 10px;
-  position: absolute;
-  top: 63px;
-  width: 200px;
-}
-
-.cros-log-analyzer-marker-history-entry {
-  display: -webkit-flex;
-  height: 20px;
-}
-
-
-.cros-log-analyzer-marker-history-entry * {
-  display: block;
-}
-
-.cros-log-analyzer-marker-history-entry p {
-  font-size: 13px;
-  height: 15px;
-  margin: 0;
-  width: 98px;
-}
-
-.cros-log-analyzer-marker-history-entry a {
-  color: grey;
-  font-size: 11px;
-}
-
-.cros-log-analyzer-marker-history-color-tag {
-  border-radius: 10px;
-  height: 10px;
-  margin: 4px;
-  width: 10px;
-}
-
-.cros-log-analyzer-marker-highlight {
-  font-weight: bold;
-}
-
-#cros-log-analyzer-save-btn {
-  background-color: rgb(211, 211, 211);
-}
-
-@-webkit-keyframes fade {
-  0%
-  {
-    opacity: 1;
-  }
-  50%
-  {
-    opacity: 0;
-  }
-  100%
-  {
-    opacity: 1;
-  }
-}
diff --git a/chrome/browser/resources/net_internals/cros_log_analyzer_view.html b/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
index a23543c..4c18f5c 100644
--- a/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
+++ b/chrome/browser/resources/net_internals/cros_log_analyzer_view.html
@@ -5,8 +5,10 @@
   </div>
   <div id='cros-log-analyzer-search-container'
       class='cros-log-analyzer-container'>
-    Search:
-    <input type='text' id='cros-log-analyzer-search-input'>
+    <label>
+      Search:
+      <input type='text' id='cros-log-analyzer-search-input'>
+    </label>
     <span id='cros-log-analyzer-save-btn'>Save</span>
   </div>
   <table id="cros-log-analyzer-log-header-table"
diff --git a/chrome/browser/resources/net_internals/cros_log_analyzer_view.js b/chrome/browser/resources/net_internals/cros_log_analyzer_view.js
deleted file mode 100644
index fa6927a..0000000
--- a/chrome/browser/resources/net_internals/cros_log_analyzer_view.js
+++ /dev/null
@@ -1,371 +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 view displays the log messages from various resources in an
- * interactive log analyzer
- *
- *   - Filter checkboxes
- *   - Filter text inputs
- *   - Display the log by different sections: time|level|process|description
- *
- */
-var CrosLogAnalyzerView = (function() {
-  'use strict';
-
-  // Inherits from DivView.
-  var superClass = DivView;
-
-  // Special classes (defined in log_analyzer_view.css)
-  var LOG_CONTAINER_CLASSNAME = 'cros-log-analyzer-container';
-  var LOG_FILTER_PNAME_BLOCK_CLASSNAME = 'cros-log-analyzer-filter-pname-block';
-  var LOG_CELL_HEADER_CLASSNAME = 'cros-log-analyzer-td-head';
-  var LOG_CELL_TIME_CLASSNAME = 'cros-log-analyzer-td-time';
-  var LOG_CELL_PNAME_CLASSNAME = 'cros-log-analyzer-td-pname';
-  var LOG_CELL_PID_CLASSNAME = 'cros-log-analyzer-td-pid';
-  var LOG_CELL_DESCRIPTION_CLASSNAME = 'cros-log-analyzer-td-description';
-  var LOG_CELL_LEVEL_CLASSNAME = 'cros-log-analyzer-td-level';
-  var LOG_CELL_LEVEL_CLASSNAME_LIST = {
-    'Error': 'cros-log-analyzer-td-level-error',
-    'Warning': 'cros-log-analyzer-td-level-warning',
-    'Info': 'cros-log-analyzer-td-level-info',
-    'Unknown': 'cros-log-analyzer-td-level-unknown'
-  };
-
-  /**
-   * @constructor
-   */
-  function CrosLogAnalyzerView() {
-    assertFirstConstructorCall(CrosLogAnalyzerView);
-
-    // Call superclass's constructor.
-    superClass.call(this, CrosLogAnalyzerView.MAIN_BOX_ID);
-
-    // Stores log entry objects
-    this.logEntries = [];
-    // Stores current search query
-    this.currentQuery = '';
-    // Stores raw text data of log
-    this.logData = '';
-    // Stores all the unique process names
-    this.pNames = [];
-    // References to special HTML elements in log_analyzer_view.html
-    this.pNameCheckboxes = {};
-    this.levelCheckboxes = {};
-    this.tableEntries = [];
-
-    this.initialize();
-  }
-
-  CrosLogAnalyzerView.TAB_ID = 'tab-handle-cros-log-analyzer';
-  CrosLogAnalyzerView.TAB_NAME = 'Log Analyzer';
-  CrosLogAnalyzerView.TAB_HASH = '#analyzer';
-
-  // IDs for special HTML elements in log_analyzer_view.html
-  CrosLogAnalyzerView.MAIN_BOX_ID = 'cros-log-analyzer-tab-content';
-  CrosLogAnalyzerView.LOG_TABLE_ID = 'cros-log-analyzer-log-table';
-  CrosLogAnalyzerView.LOG_FILTER_PNAME_ID = 'cros-log-analyzer-filter-pname';
-  CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID = 'cros-log-analyzer-search-input';
-  CrosLogAnalyzerView.LOG_SEARCH_SAVE_BTN_ID = 'cros-log-analyzer-save-btn';
-  CrosLogAnalyzerView.LOG_VISUALIZER_CONTAINER_ID =
-      'cros-log-analyzer-visualizer-container';
-
-  cr.addSingletonGetter(CrosLogAnalyzerView);
-
-  /**
-   * Contains types of logs we are interested in
-   */
-  var LOGS_LIST = {
-    'NETWORK_LOG': 1,
-    'SYSTEM_LOG': 2
-  };
-
-  /**
-   * Contains headers of the log table
-   */
-  var TABLE_HEADERS_LIST = ['Level', 'Time', 'Process', 'PID', 'Description'];
-
-  CrosLogAnalyzerView.prototype = {
-    // Inherit the superclass's methods.
-    __proto__: superClass.prototype,
-
-    /**
-     * Called during the initialization of the View. Adds the system log
-     * listener into Browser_Bridge so that the system log can be retrieved.
-     */
-    initialize: function() {
-      g_browser.addSystemLogObserver(this);
-      $(CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID).addEventListener('keyup',
-          this.onSearchQueryChange_.bind(this));
-      $(CrosLogAnalyzerView.LOG_SEARCH_SAVE_BTN_ID).addEventListener(
-          'click', this.onSaveBtnClicked_.bind(this));
-    },
-
-    /**
-     * Called when the save button is clicked. Saves the current filter query
-     * to the mark history. And highlights the matched text with colors.
-     */
-    onSaveBtnClicked_: function() {
-      this.marker.addMarkHistory(this.currentQuery);
-      // Clears the filter query
-      $(CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID).value = '';
-      this.currentQuery = '';
-      // Refresh the table
-      this.populateTable();
-      this.filterLog();
-    },
-
-    onSearchQueryChange_: function() {
-      var inputField = $(CrosLogAnalyzerView.LOG_SEARCH_INPUT_ID);
-      this.currentQuery = inputField.value;
-      this.filterLog();
-    },
-
-    /**
-     * Creates the log table where each row represents a entry of log.
-     * This function is called if and only if the log is received from system
-     * level.
-     */
-    populateTable: function() {
-      var logTable = $(CrosLogAnalyzerView.LOG_TABLE_ID);
-      logTable.innerHTML = '';
-      this.tableEntries.length = 0;
-      // Create entries
-      for (var i = 0; i < this.logEntries.length; i++) {
-        this.logEntries[i].rowNum = i;
-        var row = this.createTableRow(this.logEntries[i]);
-        logTable.appendChild(row);
-      }
-    },
-
-    /**
-     * Creates the single row of the table where each row is a representation
-     * of the logEntry object.
-     */
-    createTableRow: function(entry) {
-      var row = document.createElement('tr');
-      for (var i = 0; i < 5; i++) {
-        // Creates rows
-        addNode(row, 'td');
-      }
-      var cells = row.childNodes;
-      // Level cell
-      cells[0].className = LOG_CELL_LEVEL_CLASSNAME;
-      var levelTag = addNodeWithText(cells[0], 'p', entry.level);
-      levelTag.className = LOG_CELL_LEVEL_CLASSNAME_LIST[entry.level];
-
-      // Time cell
-      cells[1].className = LOG_CELL_TIME_CLASSNAME;
-      cells[1].textContent = entry.getTime();
-
-      // Process name cell
-      cells[2].className = LOG_CELL_PNAME_CLASSNAME;
-      this.marker.getHighlightedEntry(entry, 'processName', cells[2]);
-
-      // Process ID cell
-      cells[3].className = LOG_CELL_PID_CLASSNAME;
-      this.marker.getHighlightedEntry(entry, 'processID', cells[3]);
-
-      // Description cell
-      cells[4].className = LOG_CELL_DESCRIPTION_CLASSNAME;
-      this.marker.getHighlightedEntry(entry, 'description', cells[4]);
-
-      // Add the row into this.tableEntries for future reference
-      this.tableEntries.push(row);
-      return row;
-    },
-
-    /**
-     * Regenerates the table and filter.
-     */
-    refresh: function() {
-      this.createFilter();
-      this.createLogMaker();
-      this.populateTable();
-      this.createVisualizer();
-    },
-
-    /**
-     * Uses the search query to match the pattern in different fields of entry.
-     */
-    patternMatch: function(entry, pattern) {
-      return entry.processID.match(pattern) ||
-             entry.processName.match(pattern) ||
-             entry.level.match(pattern) ||
-             entry.description.match(pattern);
-    },
-
-    /**
-     * Filters the log to show/hide the rows in the table.
-     * Each logEntry instance has a visibility property. This function
-     * shows or hides the row only based on this property.
-     */
-    filterLog: function() {
-      // Supports regular expression
-      var pattern = new RegExp(this.currentQuery, 'i');
-      for (var i = 0; i < this.logEntries.length; i++) {
-        var entry = this.logEntries[i];
-        // Filters the result by pname and level
-        var pNameCheckbox = this.pNameCheckboxes[entry.processName];
-        var levelCheckbox = this.levelCheckboxes[entry.level];
-        entry.visibility = pNameCheckbox.checked && levelCheckbox.checked &&
-            !this.visualizer.isOutOfBound(entry);
-        if (this.currentQuery) {
-          // If the search query is not empty, filter the result by query
-          entry.visibility = entry.visibility &&
-              this.patternMatch(entry, pattern);
-        }
-        // Changes style of HTML row based on the visibility of logEntry
-        if (entry.visibility) {
-          this.tableEntries[i].style.display = 'table-row';
-        } else {
-          this.tableEntries[i].style.display = 'none';
-        }
-      }
-      this.filterVisualizer();
-    },
-
-    /**
-     * Initializes filter tags and checkboxes. There are two types of filters:
-     * Level and Process. Level filters are static that we have only 4 levels
-     * in total but process filters are dynamically changing based on the log.
-     * The filter layout looks like:
-     *  |-----------------------------------------------------------------|
-     *  |                                                                 |
-     *  |                     Section of process filter                   |
-     *  |                                                                 |
-     *  |-----------------------------------------------------------------|
-     *  |                                                                 |
-     *  |                      Section of level filter                    |
-     *  |                                                                 |
-     *  |-----------------------------------------------------------------|
-     */
-    createFilter: function() {
-      this.createFilterByPName();
-      this.levelCheckboxes = {
-        'Error': $('checkbox-error'),
-        'Warning': $('checkbox-warning'),
-        'Info': $('checkbox-info'),
-        'Unknown': $('checkbox-unknown')
-      };
-
-      for (var level in this.levelCheckboxes) {
-        this.levelCheckboxes[level].addEventListener(
-            'change', this.onFilterChange_.bind(this));
-      }
-    },
-
-    /**
-     * Helper function of createFilter(). Create filter section of
-     * process filters.
-     */
-    createFilterByPName: function() {
-      var filterContainerDiv = $(CrosLogAnalyzerView.LOG_FILTER_PNAME_ID);
-      filterContainerDiv.innerHTML = 'Process: ';
-      for (var i = 0; i < this.pNames.length; i++) {
-        var pNameBlock = this.createPNameBlock(this.pNames[i]);
-        filterContainerDiv.appendChild(pNameBlock);
-      }
-    },
-
-    /**
-     * Helper function of createFilterByPName(). Create a single filter block in
-     * the section of process filters.
-     */
-    createPNameBlock: function(pName) {
-      var block = document.createElement('span');
-      block.className = LOG_FILTER_PNAME_BLOCK_CLASSNAME;
-
-      var tag = document.createElement('label');
-      var span = document.createElement('span');
-      span.textContent = pName;
-
-      var checkbox = document.createElement('input');
-      checkbox.type = 'checkbox';
-      checkbox.name = pName;
-      checkbox.value = pName;
-      checkbox.checked = true;
-      checkbox.addEventListener('change', this.onFilterChange_.bind(this));
-      this.pNameCheckboxes[pName] = checkbox;
-
-      tag.appendChild(checkbox);
-      tag.appendChild(span);
-      block.appendChild(tag);
-
-      return block;
-    },
-
-    /**
-     * Click handler for filter checkboxes. Everytime a checkbox is clicked,
-     * the visibility of related logEntries are changed.
-     */
-    onFilterChange_: function() {
-      this.filterLog();
-    },
-
-    /**
-     * Creates a visualizer that visualizes the logs as a timeline graph
-     * during the initialization of the View.
-     */
-    createVisualizer: function() {
-      this.visualizer = new CrosLogVisualizer(this,
-          CrosLogAnalyzerView.LOG_VISUALIZER_CONTAINER_ID);
-      this.visualizer.updateEvents(this.logEntries);
-    },
-
-    /**
-     * Sync the visibility of log entries with the visualizer.
-     */
-    filterVisualizer: function() {
-      this.visualizer.updateEvents(this.logEntries);
-    },
-
-    /**
-     * Called during the initialization. It creates the log marker that
-     * highlights log text.
-     */
-    createLogMaker: function() {
-      this.marker = new CrosLogMarker(this);
-    },
-
-    /**
-     * Given a row text line of log, a logEntry instance is initialized and used
-     * for parsing. After the text is parsed, we put the instance into
-     * logEntries which is an array for storing. This function is called when
-     * the data is received from Browser Bridge.
-     */
-    addLogEntry: function(logType, textEntry) {
-      var newEntry = new CrosLogEntry();
-      if (logType == LOGS_LIST.NETWORK_LOG) {
-        newEntry.tokenizeNetworkLog(textEntry);
-      } else {
-        //TODO(shinfan): Add more if cases here
-      }
-      this.logEntries.push(newEntry);
-
-      // Record pname
-      var pName = newEntry.processName;
-      if (this.pNames.indexOf(pName) == -1) {
-        this.pNames.push(pName);
-      }
-    },
-
-    /*
-     * Asynchronous call back function from Browser Bridge.
-     */
-    onSystemLogChanged: function(callback) {
-      if (callback.log == this.logData) return;
-      this.logData = callback.log;
-      // Clear the old array by setting length to zero
-      this.logEntries.length = 0;
-      var entries = callback.log.split('\n');
-      for (var i = 1; i < entries.length; i++) {
-        this.addLogEntry(LOGS_LIST.NETWORK_LOG, entries[i]);
-      }
-      this.refresh();
-    }
-  };
-
-  return CrosLogAnalyzerView;
-})();
diff --git a/chrome/browser/resources/net_internals/cros_log_marker.js b/chrome/browser/resources/net_internals/cros_log_marker.js
index 71201e3..d67a00c 100644
--- a/chrome/browser/resources/net_internals/cros_log_marker.js
+++ b/chrome/browser/resources/net_internals/cros_log_marker.js
@@ -14,12 +14,13 @@
 var CrosLogMarker = (function() {
   'use strict';
 
-  // Special classes (defined in log_analyzer_view.css)
-  var LOG_MARKER_HIGHLIGHT_CLASS = 'cros-log-analyzer-marker-highlight';
-  var LOG_MARKER_CONTAINER_ID = 'cros-log-analyzer-marker-container';
-  var LOG_MARKER_HISTORY_ENTRY_CLASS = 'cros-log-analyzer-marker-history-entry';
+  // Special classes (defined in log_visualizer_view.css)
+  var LOG_MARKER_HIGHLIGHT_CLASS = 'cros-log-visualizer-marker-highlight';
+  var LOG_MARKER_CONTAINER_ID = 'cros-log-visualizer-marker-container';
+  var LOG_MARKER_HISTORY_ENTRY_CLASS =
+      'cros-log-visualizer-marker-history-entry';
   var LOG_MARKER_HISTORY_COLOR_TAG_CLASS =
-          'cros-log-analyzer-marker-history-color-tag';
+          'cros-log-visualizer-marker-history-color-tag';
 
   /**
    * Colors used for highlighting. (Current we support 6 colors)
@@ -56,18 +57,18 @@
 
   /**
    * @constructor
-   * @param {CrosLogAnalyzerView} logAnalyzerView A reference to
-   *     CrosLogAnalyzerView.
+   * @param {CrosLogVisualizerView} logVisualizerView A reference to
+   *     CrosLogVisualizerView.
    */
-  function CrosLogMarker(logAnalyzerView) {
+  function CrosLogMarker(logVisualizerView) {
     this.container = $(LOG_MARKER_CONTAINER_ID);
     // Stores highlight objects for each entry.
     this.entryHighlights = [];
     // Stores all the filter queries.
     this.markHistory = {};
-    // Object references from CrosLogAnalyzerView.
-    this.logEntries = logAnalyzerView.logEntries;
-    this.logAnalyzerView = logAnalyzerView;
+    // Object references from CrosLogVisualizerView.
+    this.logEntries = logVisualizerView.logEntries;
+    this.logVisualizerView = logVisualizerView;
     // Counts how many highlights are created.
     this.markCount = 0;
     for (var i = 0; i < this.logEntries.length; i++) {
@@ -324,11 +325,11 @@
     },
 
     /**
-     * Refresh the log table in the CrosLogAnalyzerView.
+     * Refresh the log table in the CrosLogVisualizerView.
      */
     refreshLogTable: function() {
-      this.logAnalyzerView.populateTable();
-      this.logAnalyzerView.filterLog();
+      this.logVisualizerView.populateTable();
+      this.logVisualizerView.filterLog();
     },
 
     /**
diff --git a/chrome/browser/resources/net_internals/cros_log_visualizer.js b/chrome/browser/resources/net_internals/cros_log_visualizer.js
index 40b5475..73db4c3 100644
--- a/chrome/browser/resources/net_internals/cros_log_visualizer.js
+++ b/chrome/browser/resources/net_internals/cros_log_visualizer.js
@@ -14,18 +14,18 @@
   'use strict';
 
   // HTML attributes of canvas
-  var LOG_VISUALIZER_CANVAS_CLASS = 'cros-log-analyzer-visualizer-canvas';
+  var LOG_VISUALIZER_CANVAS_CLASS = 'cros-log-visualizer-visualizer-canvas';
   var LOG_VISUALIZER_CANVAS_WIDTH = 980;
   var LOG_VISUALIZER_CANVAS_HEIGHT = 100;
 
   // Special HTML classes
-  var LOG_VISUALIZER_TIMELINE_ID = 'cros-log-analyzer-visualizer-timeline';
+  var LOG_VISUALIZER_TIMELINE_ID = 'cros-log-visualizer-visualizer-timeline';
   var LOG_VISUALIZER_TIME_DISPLAY_CLASS =
-      'cros-log-analyzer-visualizer-time-display';
+      'cros-log-visualizer-visualizer-time-display';
   var LOG_VISUALIZER_RESET_BTN_ID =
-      'cros-log-analyzer-visualizer-reset-btn';
+      'cros-log-visualizer-visualizer-reset-btn';
   var LOG_VISUALIZER_TRACKING_LAYER_ID =
-      'cros-log-analyzer-visualizer-tracking-layer';
+      'cros-log-visualizer-visualizer-tracking-layer';
 
   /**
    * Event level list
@@ -51,12 +51,12 @@
   /**
    * @constructor
    */
-  function CrosLogVisualizer(logAnalyzer, containerID) {
+  function CrosLogVisualizer(logVisualizer, containerID) {
     /**
-     * Pass the LogAnalyzer in as a reference so the visualizer can
+     * Pass the LogVisualizer in as a reference so the visualizer can
      * synchrous with the log filter.
      */
-    this.logAnalyzer = logAnalyzer;
+    this.logVisualizer = logVisualizer;
 
     // If the data is initialized
     this.dataIntialized = false;
@@ -84,7 +84,7 @@
     this.container.appendChild(this.btnReset);
 
     this.container.addEventListener('webkitAnimationEnd', function() {
-      this.container.classList.remove('cros-log-analyzer-flash');
+      this.container.classList.remove('cros-log-visualizer-flash');
     }.bind(this), false);
   }
 
@@ -193,7 +193,7 @@
      * CSS3 fadeIn/fadeOut effects
      */
     flashEffect: function() {
-      this.container.classList.add('cros-log-analyzer-flash');
+      this.container.classList.add('cros-log-visualizer-flash');
     },
 
     /**
@@ -205,7 +205,7 @@
       // Reset all the parameters as initial
       this.initialize();
       // Reset the visibility of the entries in the log table
-      this.logAnalyzer.filterLog();
+      this.logVisualizer.filterLog();
       this.flashEffect();
      },
 
@@ -368,7 +368,7 @@
       // Recalculate the pamameter based on the range user select
       this.reCalculate();
       // Filter the log table and hide the entries that are not in the range
-      this.logAnalyzer.filterLog();
+      this.logVisualizer.filterLog();
     },
   };
 
diff --git a/chrome/browser/resources/net_internals/cros_log_visualizer_view.css b/chrome/browser/resources/net_internals/cros_log_visualizer_view.css
new file mode 100644
index 0000000..8f49da3
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_visualizer_view.css
@@ -0,0 +1,234 @@
+ /* Copyright 2013 The Chromium Authors. All rights reserved.
+  * Use of this source code is governed by a BSD-style license that can be
+  * found in the LICENSE file.
+  */
+
+ #cros-log-visualizer-header {
+  margin-bottom: 20px;
+ }
+
+.cros-log-visualizer-container {
+  background-color: rgb(242, 242, 242);
+  border: 1px solid rgb(220, 220, 220);
+}
+
+#cros-log-visualizer-log-content {
+  border: 1px solid rgb(220, 220, 220);
+  font-size: 11px;
+  height: 300px;
+  line-height: 18px;
+  margin-bottom: -1px;
+  overflow: scroll;
+  padding: 10px;
+  width: 1000px;
+ }
+
+#cros-log-visualizer-filter-container {
+  font-size: 12px;
+  margin-bottom: 5px;
+  padding: 5px 10px;
+  width: 1000px;
+}
+
+#cros-log-visualizer-filter-container p {
+  margin: 10px 0;
+}
+
+#cros-log-visualizer-log-table {
+  table-layout: fixed;
+  width: 950px;
+}
+
+#cros-log-visualizer-log-table td {
+  overflow: hidden;
+  table-layout: fixed;
+  word-wrap: break-word;
+}
+
+.cros-log-visualizer-td-time {
+  width: 100px;
+}
+
+#cros-log-visualizer-log-header-table {
+  font-size: 12px;
+  font-weight: bold;
+  margin-bottom: -1px;
+  text-align: center;
+  width: 1000px;
+}
+
+.cros-log-visualizer-td-pname {
+  text-align: center;
+  width: 120px;
+}
+
+.cros-log-visualizer-td-level {
+  width: 70px;
+}
+
+.cros-log-visualizer-td-level p {
+  border: 1px solid;
+  border-radius: 5px;
+  margin: 0 3px;
+  text-align: center;
+  width: 58px;
+}
+
+.cros-log-visualizer-td-level-error {
+  background-color: rgb(255, 153, 163);
+  color: rgb(238, 0, 0);
+}
+
+.cros-log-visualizer-td-level-info {
+  background-color: rgb(195, 227, 250);
+  color: rgb(10, 147, 245);
+  width: 120px;
+}
+
+.cros-log-visualizer-td-level-warning {
+  background-color: rgb(250, 229, 195);
+  color: darkorange;
+}
+
+.cros-log-visualizer-td-level-unknown {
+  color: gray;
+}
+
+.cros-log-visualizer-td-pid {
+  width: 60px;
+}
+
+#cros-log-visualizer-filter-pname {
+  border-bottom: 1px solid rgb(209, 209, 209);
+  padding: 5px 0 10px 0;
+}
+
+#cros-log-visualizer-filter-level {
+  padding: 5px 0 10px 0;
+}
+
+#cros-log-visualizer-search-container {
+  -webkit-margin-start: 760px;
+  border-radius: 5px;
+  font-size: 12px;
+  margin-bottom: 5px;
+  margin-left: 720px;
+  margin-top: -40px;
+  padding: 5px;
+  width: 280px;
+}
+
+#cros-log-visualizer-search-container input {
+  border: 1px solid rgb(220, 220, 220);
+}
+
+#cros-log-visualizer-visualizer-container {
+  border: 1px solid rgb(211, 211, 211);
+  height: 100px;
+  position: relative;
+  width: 1002px;
+}
+
+#cros-log-visualizer-visualizer-timeline {
+  background: gray;
+  opacity: 0.5;
+  position: absolute;
+  top: 0;
+  width: 2px;
+}
+
+.cros-log-visualizer-visualizer-time-display {
+  font-size: 10px;
+  position: absolute;
+  width: 50px;
+}
+
+#cros-log-visualizer-visualizer-reset-btn {
+  border: 1px solid rgb(211, 211, 211);
+  border-radius: 2px;
+  position: absolute;
+  right: 5px;
+  top: 5px;
+}
+
+#cros-log-visualizer-visualizer-tracking-layer {
+  background: none;
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+
+.cros-log-visualizer-visualizer-canvas {
+  left: 0;
+  position: absolute;
+  top: 0;
+}
+
+.cros-log-visualizer-flash {
+  -webkit-animation: fade 1s linear 1;
+}
+
+#cros-log-visualizer-marker-container {
+  background-color: rgb(242, 242, 242);
+  border: 1px solid rgb(211, 211, 211);
+  left: 1030px;
+  min-height: 320px;
+  padding: 10px;
+  position: absolute;
+  top: 63px;
+  width: 200px;
+}
+
+.cros-log-visualizer-marker-history-entry {
+  display: -webkit-flex;
+  height: 20px;
+}
+
+
+.cros-log-visualizer-marker-history-entry * {
+  display: block;
+}
+
+.cros-log-visualizer-marker-history-entry p {
+  font-size: 13px;
+  height: 15px;
+  margin: 0;
+  width: 98px;
+}
+
+.cros-log-visualizer-marker-history-entry a {
+  color: grey;
+  font-size: 11px;
+}
+
+.cros-log-visualizer-marker-history-color-tag {
+  border-radius: 10px;
+  height: 10px;
+  margin: 4px;
+  width: 10px;
+}
+
+.cros-log-visualizer-marker-highlight {
+  font-weight: bold;
+}
+
+#cros-log-visualizer-save-btn {
+  background-color: rgb(211, 211, 211);
+}
+
+@-webkit-keyframes fade {
+  0%
+  {
+    opacity: 1;
+  }
+  50%
+  {
+    opacity: 0;
+  }
+  100%
+  {
+    opacity: 1;
+  }
+}
diff --git a/chrome/browser/resources/net_internals/cros_log_visualizer_view.html b/chrome/browser/resources/net_internals/cros_log_visualizer_view.html
new file mode 100644
index 0000000..0803884
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_visualizer_view.html
@@ -0,0 +1,56 @@
+<!-- Log Visualizer -->
+<div id="cros-log-visualizer-tab-content" class="content-box">
+  <div id="cros-log-visualizer-header">
+    Network Log
+  </div>
+  <div id='cros-log-visualizer-search-container'
+      class='cros-log-visualizer-container'>
+    Search:
+    <input type='text' placeholder="Enter your keyword"
+        id='cros-log-visualizer-search-input'>
+    <span id='cros-log-visualizer-save-btn'>Save</span>
+  </div>
+  <table id="cros-log-visualizer-log-header-table"
+      class="cros-log-visualizer-container">
+    <tr>
+      <td class="cros-log-visualizer-td-level">Level</td>
+      <td class="cros-log-visualizer-td-time">Time</td>
+      <td class="cros-log-visualizer-td-pname">Process</td>
+      <td class="cros-log-visualizer-td-pid">PID</td>
+      <td class="cros-log-visualizer-td-description">Description</td>
+    </tr>
+  </table>
+  <div id="cros-log-visualizer-log-content">
+    <table id="cros-log-visualizer-log-table">
+    </table>
+  </div>
+  <div id='cros-log-visualizer-marker-container'>
+  </div>
+  <div id='cros-log-visualizer-filter-container'
+      class='cros-log-visualizer-container'>
+    <div id='cros-log-visualizer-filter-pname'>
+    </div>
+    <div id='cros-log-visualizer-filter-level'>
+      Level:
+      <span class="cros-log-visualizer-filter-level-block">
+        <input type='checkbox' id='checkbox-error' checked=true>
+        <label for="checkbox-error">Error</label>
+      </span>
+      <span class="cros-log-visualizer-filter-level-block">
+        <input type='checkbox' id='checkbox-warning' checked=true>
+        <label for="checkbox-warning">Warning</label>
+      </span>
+      <span class="cros-log-visualizer-filter-level-block">
+        <input type='checkbox' id='checkbox-info' checked=true>
+        <label for="checkbox-info">Info</label>
+      </span>
+      <span class="cros-log-visualizer-filter-level-block">
+        <input type='checkbox' id='checkbox-unknown'checked=true>
+        <label for="checkbox-unknown">Unknown</label>
+      </span>
+    </div>
+  </div>
+  <div id="cros-log-visualizer-visualizer-container">
+    <div id="cros-log-visualizer-visualizer-tracking-layer"></div>
+  </div>
+</div>
diff --git a/chrome/browser/resources/net_internals/cros_log_visualizer_view.js b/chrome/browser/resources/net_internals/cros_log_visualizer_view.js
new file mode 100644
index 0000000..6a0bf48
--- /dev/null
+++ b/chrome/browser/resources/net_internals/cros_log_visualizer_view.js
@@ -0,0 +1,374 @@
+// Copyright 2013 The Chromium 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 view displays the log messages from various resources in an
+ * interactive log visualizer
+ *
+ *   - Filter checkboxes
+ *   - Filter text inputs
+ *   - Display the log by different sections: time|level|process|description
+ *
+ */
+var CrosLogVisualizerView = (function() {
+  'use strict';
+
+  // Inherits from DivView.
+  var superClass = DivView;
+
+  // Special classes (defined in log_visualizer_view.css)
+  var LOG_CONTAINER_CLASSNAME = 'cros-log-visualizer-container';
+  var LOG_FILTER_PNAME_BLOCK_CLASSNAME =
+      'cros-log-visualizer-filter-pname-block';
+  var LOG_CELL_HEADER_CLASSNAME = 'cros-log-visualizer-td-head';
+  var LOG_CELL_TIME_CLASSNAME = 'cros-log-visualizer-td-time';
+  var LOG_CELL_PNAME_CLASSNAME = 'cros-log-visualizer-td-pname';
+  var LOG_CELL_PID_CLASSNAME = 'cros-log-visualizer-td-pid';
+  var LOG_CELL_DESCRIPTION_CLASSNAME = 'cros-log-visualizer-td-description';
+  var LOG_CELL_LEVEL_CLASSNAME = 'cros-log-visualizer-td-level';
+  var LOG_CELL_LEVEL_CLASSNAME_LIST = {
+    'Error': 'cros-log-visualizer-td-level-error',
+    'Warning': 'cros-log-visualizer-td-level-warning',
+    'Info': 'cros-log-visualizer-td-level-info',
+    'Unknown': 'cros-log-visualizer-td-level-unknown'
+  };
+
+  /**
+   * @constructor
+   */
+  function CrosLogVisualizerView() {
+    assertFirstConstructorCall(CrosLogVisualizerView);
+
+    // Call superclass's constructor.
+    superClass.call(this, CrosLogVisualizerView.MAIN_BOX_ID);
+
+    // Stores log entry objects
+    this.logEntries = [];
+    // Stores current search query
+    this.currentQuery = '';
+    // Stores raw text data of log
+    this.logData = '';
+    // Stores all the unique process names
+    this.pNames = [];
+    // References to special HTML elements in log_visualizer_view.html
+    this.pNameCheckboxes = {};
+    this.levelCheckboxes = {};
+    this.tableEntries = [];
+
+    this.initialize();
+  }
+
+  CrosLogVisualizerView.TAB_ID = 'tab-handle-cros-log-visualizer';
+  CrosLogVisualizerView.TAB_NAME = 'Log Visualizer';
+  CrosLogVisualizerView.TAB_HASH = '#visualizer';
+
+  // IDs for special HTML elements in log_visualizer_view.html
+  CrosLogVisualizerView.MAIN_BOX_ID = 'cros-log-visualizer-tab-content';
+  CrosLogVisualizerView.LOG_TABLE_ID = 'cros-log-visualizer-log-table';
+  CrosLogVisualizerView.LOG_FILTER_PNAME_ID =
+      'cros-log-visualizer-filter-pname';
+  CrosLogVisualizerView.LOG_SEARCH_INPUT_ID =
+      'cros-log-visualizer-search-input';
+  CrosLogVisualizerView.LOG_SEARCH_SAVE_BTN_ID = 'cros-log-visualizer-save-btn';
+  CrosLogVisualizerView.LOG_VISUALIZER_CONTAINER_ID =
+      'cros-log-visualizer-visualizer-container';
+
+  cr.addSingletonGetter(CrosLogVisualizerView);
+
+  /**
+   * Contains types of logs we are interested in
+   */
+  var LOGS_LIST = {
+    'NETWORK_LOG': 1,
+    'SYSTEM_LOG': 2
+  };
+
+  /**
+   * Contains headers of the log table
+   */
+  var TABLE_HEADERS_LIST = ['Level', 'Time', 'Process', 'PID', 'Description'];
+
+  CrosLogVisualizerView.prototype = {
+    // Inherit the superclass's methods.
+    __proto__: superClass.prototype,
+
+    /**
+     * Called during the initialization of the View. Adds the system log
+     * listener into Browser_Bridge so that the system log can be retrieved.
+     */
+    initialize: function() {
+      g_browser.addSystemLogObserver(this);
+      $(CrosLogVisualizerView.LOG_SEARCH_INPUT_ID).addEventListener('keyup',
+          this.onSearchQueryChange_.bind(this));
+      $(CrosLogVisualizerView.LOG_SEARCH_SAVE_BTN_ID).addEventListener(
+          'click', this.onSaveBtnClicked_.bind(this));
+    },
+
+    /**
+     * Called when the save button is clicked. Saves the current filter query
+     * to the mark history. And highlights the matched text with colors.
+     */
+    onSaveBtnClicked_: function() {
+      this.marker.addMarkHistory(this.currentQuery);
+      // Clears the filter query
+      $(CrosLogVisualizerView.LOG_SEARCH_INPUT_ID).value = '';
+      this.currentQuery = '';
+      // Refresh the table
+      this.populateTable();
+      this.filterLog();
+    },
+
+    onSearchQueryChange_: function() {
+      var inputField = $(CrosLogVisualizerView.LOG_SEARCH_INPUT_ID);
+      this.currentQuery = inputField.value;
+      this.filterLog();
+    },
+
+    /**
+     * Creates the log table where each row represents a entry of log.
+     * This function is called if and only if the log is received from system
+     * level.
+     */
+    populateTable: function() {
+      var logTable = $(CrosLogVisualizerView.LOG_TABLE_ID);
+      logTable.innerHTML = '';
+      this.tableEntries.length = 0;
+      // Create entries
+      for (var i = 0; i < this.logEntries.length; i++) {
+        this.logEntries[i].rowNum = i;
+        var row = this.createTableRow(this.logEntries[i]);
+        logTable.appendChild(row);
+      }
+    },
+
+    /**
+     * Creates the single row of the table where each row is a representation
+     * of the logEntry object.
+     */
+    createTableRow: function(entry) {
+      var row = document.createElement('tr');
+      for (var i = 0; i < 5; i++) {
+        // Creates rows
+        addNode(row, 'td');
+      }
+      var cells = row.childNodes;
+      // Level cell
+      cells[0].className = LOG_CELL_LEVEL_CLASSNAME;
+      var levelTag = addNodeWithText(cells[0], 'p', entry.level);
+      levelTag.className = LOG_CELL_LEVEL_CLASSNAME_LIST[entry.level];
+
+      // Time cell
+      cells[1].className = LOG_CELL_TIME_CLASSNAME;
+      cells[1].textContent = entry.getTime();
+
+      // Process name cell
+      cells[2].className = LOG_CELL_PNAME_CLASSNAME;
+      this.marker.getHighlightedEntry(entry, 'processName', cells[2]);
+
+      // Process ID cell
+      cells[3].className = LOG_CELL_PID_CLASSNAME;
+      this.marker.getHighlightedEntry(entry, 'processID', cells[3]);
+
+      // Description cell
+      cells[4].className = LOG_CELL_DESCRIPTION_CLASSNAME;
+      this.marker.getHighlightedEntry(entry, 'description', cells[4]);
+
+      // Add the row into this.tableEntries for future reference
+      this.tableEntries.push(row);
+      return row;
+    },
+
+    /**
+     * Regenerates the table and filter.
+     */
+    refresh: function() {
+      this.createFilter();
+      this.createLogMaker();
+      this.populateTable();
+      this.createVisualizer();
+    },
+
+    /**
+     * Uses the search query to match the pattern in different fields of entry.
+     */
+    patternMatch: function(entry, pattern) {
+      return entry.processID.match(pattern) ||
+             entry.processName.match(pattern) ||
+             entry.level.match(pattern) ||
+             entry.description.match(pattern);
+    },
+
+    /**
+     * Filters the log to show/hide the rows in the table.
+     * Each logEntry instance has a visibility property. This function
+     * shows or hides the row only based on this property.
+     */
+    filterLog: function() {
+      // Supports regular expression
+      var pattern = new RegExp(this.currentQuery, 'i');
+      for (var i = 0; i < this.logEntries.length; i++) {
+        var entry = this.logEntries[i];
+        // Filters the result by pname and level
+        var pNameCheckbox = this.pNameCheckboxes[entry.processName];
+        var levelCheckbox = this.levelCheckboxes[entry.level];
+        entry.visibility = pNameCheckbox.checked && levelCheckbox.checked &&
+            !this.visualizer.isOutOfBound(entry);
+        if (this.currentQuery) {
+          // If the search query is not empty, filter the result by query
+          entry.visibility = entry.visibility &&
+              this.patternMatch(entry, pattern);
+        }
+        // Changes style of HTML row based on the visibility of logEntry
+        if (entry.visibility) {
+          this.tableEntries[i].style.display = 'table-row';
+        } else {
+          this.tableEntries[i].style.display = 'none';
+        }
+      }
+      this.filterVisualizer();
+    },
+
+    /**
+     * Initializes filter tags and checkboxes. There are two types of filters:
+     * Level and Process. Level filters are static that we have only 4 levels
+     * in total but process filters are dynamically changing based on the log.
+     * The filter layout looks like:
+     *  |-----------------------------------------------------------------|
+     *  |                                                                 |
+     *  |                     Section of process filter                   |
+     *  |                                                                 |
+     *  |-----------------------------------------------------------------|
+     *  |                                                                 |
+     *  |                      Section of level filter                    |
+     *  |                                                                 |
+     *  |-----------------------------------------------------------------|
+     */
+    createFilter: function() {
+      this.createFilterByPName();
+      this.levelCheckboxes = {
+        'Error': $('checkbox-error'),
+        'Warning': $('checkbox-warning'),
+        'Info': $('checkbox-info'),
+        'Unknown': $('checkbox-unknown')
+      };
+
+      for (var level in this.levelCheckboxes) {
+        this.levelCheckboxes[level].addEventListener(
+            'change', this.onFilterChange_.bind(this));
+      }
+    },
+
+    /**
+     * Helper function of createFilter(). Create filter section of
+     * process filters.
+     */
+    createFilterByPName: function() {
+      var filterContainerDiv = $(CrosLogVisualizerView.LOG_FILTER_PNAME_ID);
+      filterContainerDiv.innerHTML = 'Process: ';
+      for (var i = 0; i < this.pNames.length; i++) {
+        var pNameBlock = this.createPNameBlock(this.pNames[i]);
+        filterContainerDiv.appendChild(pNameBlock);
+      }
+    },
+
+    /**
+     * Helper function of createFilterByPName(). Create a single filter block in
+     * the section of process filters.
+     */
+    createPNameBlock: function(pName) {
+      var block = document.createElement('span');
+      block.className = LOG_FILTER_PNAME_BLOCK_CLASSNAME;
+
+      var tag = document.createElement('label');
+      var span = document.createElement('span');
+      span.textContent = pName;
+
+      var checkbox = document.createElement('input');
+      checkbox.type = 'checkbox';
+      checkbox.name = pName;
+      checkbox.value = pName;
+      checkbox.checked = true;
+      checkbox.addEventListener('change', this.onFilterChange_.bind(this));
+      this.pNameCheckboxes[pName] = checkbox;
+
+      tag.appendChild(checkbox);
+      tag.appendChild(span);
+      block.appendChild(tag);
+
+      return block;
+    },
+
+    /**
+     * Click handler for filter checkboxes. Everytime a checkbox is clicked,
+     * the visibility of related logEntries are changed.
+     */
+    onFilterChange_: function() {
+      this.filterLog();
+    },
+
+    /**
+     * Creates a visualizer that visualizes the logs as a timeline graph
+     * during the initialization of the View.
+     */
+    createVisualizer: function() {
+      this.visualizer = new CrosLogVisualizer(this,
+          CrosLogVisualizerView.LOG_VISUALIZER_CONTAINER_ID);
+      this.visualizer.updateEvents(this.logEntries);
+    },
+
+    /**
+     * Sync the visibility of log entries with the visualizer.
+     */
+    filterVisualizer: function() {
+      this.visualizer.updateEvents(this.logEntries);
+    },
+
+    /**
+     * Called during the initialization. It creates the log marker that
+     * highlights log text.
+     */
+    createLogMaker: function() {
+      this.marker = new CrosLogMarker(this);
+    },
+
+    /**
+     * Given a row text line of log, a logEntry instance is initialized and used
+     * for parsing. After the text is parsed, we put the instance into
+     * logEntries which is an array for storing. This function is called when
+     * the data is received from Browser Bridge.
+     */
+    addLogEntry: function(logType, textEntry) {
+      var newEntry = new CrosLogEntry();
+      if (logType == LOGS_LIST.NETWORK_LOG) {
+        newEntry.tokenizeNetworkLog(textEntry);
+      } else {
+        //TODO(shinfan): Add more if cases here
+      }
+      this.logEntries.push(newEntry);
+
+      // Record pname
+      var pName = newEntry.processName;
+      if (this.pNames.indexOf(pName) == -1) {
+        this.pNames.push(pName);
+      }
+    },
+
+    /*
+     * Asynchronous call back function from Browser Bridge.
+     */
+    onSystemLogChanged: function(callback) {
+      if (callback.log == this.logData) return;
+      this.logData = callback.log;
+      // Clear the old array by setting length to zero
+      this.logEntries.length = 0;
+      var entries = callback.log.split('\n');
+      for (var i = 1; i < entries.length; i++) {
+        this.addLogEntry(LOGS_LIST.NETWORK_LOG, entries[i]);
+      }
+      this.refresh();
+    }
+  };
+
+  return CrosLogVisualizerView;
+})();
diff --git a/chrome/browser/resources/net_internals/events_view.css b/chrome/browser/resources/net_internals/events_view.css
index 443b1d7..58a327a 100644
--- a/chrome/browser/resources/net_internals/events_view.css
+++ b/chrome/browser/resources/net_internals/events_view.css
@@ -99,9 +99,9 @@
 }
 
 #events-view-source-list-tbody .source-ipv6-probe-job {
-  color: red;
+  color: rgb(235, 0, 0);
 }
 
 #events-view-source-list-tbody .source-none {
-  color: red;
+  color: rgb(235, 0, 0);
 }
diff --git a/chrome/browser/resources/net_internals/events_view.html b/chrome/browser/resources/net_internals/events_view.html
index 5f2b454..ddf0387 100644
--- a/chrome/browser/resources/net_internals/events_view.html
+++ b/chrome/browser/resources/net_internals/events_view.html
@@ -7,7 +7,7 @@
       <td width=1%>
         <span id=events-view-filter-help-hover class=mouse-over-help-hover>(?)</span>
       </td>
-      <td width=98%><input type="search" incremental id=events-view-filter-input></td>
+      <td width=98%><input type="search" incremental id=events-view-filter-input title="Sort and filter"></td>
       <td width=1% id=events-view-filter-count>(1 of 34)</td>
     </tr>
   </table>
@@ -37,7 +37,7 @@
   <table id=events-view-source-list-table cellspacing=0 cellpadding=0 width=100%>
     <thead>
       <tr>
-        <td style='border-left:0'><input type=checkbox id=events-view-select-all></td>
+        <td style='border-left:0'><input type=checkbox id=events-view-select-all title="Select all"></td>
         <td id=events-view-sort-by-id>ID</td>
         <td id=events-view-sort-by-source>Source Type</td>
         <td id=events-view-sort-by-description width=99%>Description</td>
diff --git a/chrome/browser/resources/net_internals/export_view.html b/chrome/browser/resources/net_internals/export_view.html
index 1a3b8dc..0bc8be3 100644
--- a/chrome/browser/resources/net_internals/export_view.html
+++ b/chrome/browser/resources/net_internals/export_view.html
@@ -1,13 +1,13 @@
 <style>
 
 .export-view-explanation-warning {
-  border: 2px solid red;
+  border: 2px solid #e00;
 }
 
 #export-view-privacy-warning {
   padding: 5px;
-  color: red;
-  border: 1px solid red;
+  color: #e00;
+  border: 1px solid #e00;
 }
 
 #export-view-save-log-file {
diff --git a/chrome/browser/resources/net_internals/hsts_view.html b/chrome/browser/resources/net_internals/hsts_view.html
index d0b0b50..7a64ad1 100644
--- a/chrome/browser/resources/net_internals/hsts_view.html
+++ b/chrome/browser/resources/net_internals/hsts_view.html
@@ -22,8 +22,8 @@
              placeholder="example.com"><br>
     <label>Include subdomains for STS: <input type="checkbox" id=hsts-view-check-sts-input></label><br>
     <label>Include subdomains for PKP: <input type="checkbox" id=hsts-view-check-pkp-input></label><br>
-    Public key fingerprints: <input type=text id=hsts-view-add-pins style="width: 25em; max-width: 100%;"><br>
-    <p style="font-size: small; color: gray; font-style: italic; margin-left: 2em; max-width: 40em; max-width: 100%;">(public key fingerprints are comma separated and consist of the hash function followed by a foreslash and the base64 encoded fingerprint, for example <tt>sha1/Guzek9lMwR3KeIS8wwS9gBvVtIg=</tt>)</p>
+    <label>Public key fingerprints: <input type=text id=hsts-view-add-pins style="width: 25em; max-width: 100%;"></label><br>
+    <p style="font-size: small; color: #767676; font-style: italic; margin-left: 2em; max-width: 40em; max-width: 100%;">(public key fingerprints are comma separated and consist of the hash function followed by a foreslash and the base64 encoded fingerprint, for example <tt>sha1/Guzek9lMwR3KeIS8wwS9gBvVtIg=</tt>)</p>
     <input type=submit value="Add" id=hsts-view-add-submit>
   </form>
 
diff --git a/chrome/browser/resources/net_internals/hsts_view.js b/chrome/browser/resources/net_internals/hsts_view.js
index 69a342a..663248d 100644
--- a/chrome/browser/resources/net_internals/hsts_view.js
+++ b/chrome/browser/resources/net_internals/hsts_view.js
@@ -102,7 +102,7 @@
         this.queryOutputDiv_.innerHTML = '';
         var s = addNode(this.queryOutputDiv_, 'span');
         s.textContent = result.error;
-        s.style.color = 'red';
+        s.style.color = '#e00';
         yellowFade(this.queryOutputDiv_);
         return;
       }
diff --git a/chrome/browser/resources/net_internals/import_view.html b/chrome/browser/resources/net_internals/import_view.html
index 7ff31d9..91ab9fe 100644
--- a/chrome/browser/resources/net_internals/import_view.html
+++ b/chrome/browser/resources/net_internals/import_view.html
@@ -21,13 +21,13 @@
 }
 
 .import-view-error-log {
-  color: red;
+  color: #e00;
   padding: 5px;
-  border: 1px solid red;
+  border: 1px solid #e00;
 }
 
 .import-view-warning-log {
-  color: red;
+  color: #e00;
 }
 
 </style>
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html
index a62ff75..02eeb7a 100644
--- a/chrome/browser/resources/net_internals/index.html
+++ b/chrome/browser/resources/net_internals/index.html
@@ -16,7 +16,7 @@
     <link rel="stylesheet" href="timeline_view.css">
     <link rel="stylesheet" href="logs_view.css">
     <link rel="stylesheet" href="chromeos_view.css">
-    <link rel="stylesheet" href="cros_log_analyzer_view.css">
+    <link rel="stylesheet" href="cros_log_visualizer_view.css">
     <script src="chrome://resources/js/util.js"></script>
     <script src="chrome://resources/js/cr.js"></script>
     <script src="chrome://net-internals/index.js"></script>
@@ -46,7 +46,7 @@
       <include src="timeline_view.html"/>
       <include src="logs_view.html"/>
       <include src="chromeos_view.html"/>
-      <include src="cros_log_analyzer_view.html"/>
+      <include src="cros_log_visualizer_view.html"/>
     </div>
 
     <script src="chrome://resources/js/i18n_template.js"></script>
diff --git a/chrome/browser/resources/net_internals/index.js b/chrome/browser/resources/net_internals/index.js
index 49b1c8a..59b892f 100644
--- a/chrome/browser/resources/net_internals/index.js
+++ b/chrome/browser/resources/net_internals/index.js
@@ -50,7 +50,7 @@
 <include src="chromeos_view.js"/>
 <include src="http_pipeline_view.js"/>
 <include src="bandwidth_view.js"/>
-<include src="cros_log_analyzer_view.js"/>
+<include src="cros_log_visualizer_view.js"/>
 <include src="cros_log_entry.js"/>
 <include src="cros_log_visualizer.js" />
 <include src="cros_log_marker.js" />
diff --git a/chrome/browser/resources/net_internals/log_view_painter.js b/chrome/browser/resources/net_internals/log_view_painter.js
index eec71b5..9e2dd06 100644
--- a/chrome/browser/resources/net_internals/log_view_painter.js
+++ b/chrome/browser/resources/net_internals/log_view_painter.js
@@ -335,6 +335,12 @@
     return;
   }
 
+  if (key == 'quic_crypto_handshake_message' && typeof value == 'string') {
+    var lines = value.split('\n');
+    out.writeArrowIndentedLines(lines);
+    return;
+  }
+
   if (key == 'quic_rst_stream_error' && typeof value == 'number') {
     var valueStr = value + ' (' + quicRstStreamErrorToString(value) + ')';
     out.writeArrowKeyValue(key, valueStr);
diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css
index 305226a..822e40f 100644
--- a/chrome/browser/resources/net_internals/main.css
+++ b/chrome/browser/resources/net_internals/main.css
@@ -103,7 +103,7 @@
  * Styling for text indicating a potential problem or error state.
  */
 .warning-text {
-  color: red;
+  color: rgb(238, 0, 0);
 }
 
 /**
diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js
index 50927d1..9f97e1b 100644
--- a/chrome/browser/resources/net_internals/main.js
+++ b/chrome/browser/resources/net_internals/main.js
@@ -195,7 +195,7 @@
       addTab(HttpCacheView);
       addTab(ModulesView);
       addTab(TestView);
-      addTab(CrosLogAnalyzerView);
+      addTab(CrosLogVisualizerView);
       addTab(HSTSView);
       addTab(LogsView);
       addTab(BandwidthView);
@@ -204,7 +204,8 @@
 
       this.tabSwitcher_.showMenuItem(LogsView.TAB_ID, cr.isChromeOS);
       this.tabSwitcher_.showMenuItem(CrosView.TAB_ID, cr.isChromeOS);
-      this.tabSwitcher_.showMenuItem(CrosLogAnalyzerView.TAB_ID, cr.isChromeOS);
+      this.tabSwitcher_.showMenuItem(CrosLogVisualizerView.TAB_ID,
+                                     cr.isChromeOS);
     },
 
     /**
diff --git a/chrome/browser/resources/net_internals/source_row.js b/chrome/browser/resources/net_internals/source_row.js
index f3e89da..137d70a 100644
--- a/chrome/browser/resources/net_internals/source_row.js
+++ b/chrome/browser/resources/net_internals/source_row.js
@@ -42,6 +42,7 @@
 
       var selectionCol = addNode(tr, 'td');
       var checkbox = addNode(selectionCol, 'input');
+      checkbox.title = this.getSourceId();
       selectionCol.style.borderLeft = '0';
       checkbox.type = 'checkbox';
 
diff --git a/chrome/browser/resources/net_internals/status_view.css b/chrome/browser/resources/net_internals/status_view.css
index d03f1b1..8e7e76a 100644
--- a/chrome/browser/resources/net_internals/status_view.css
+++ b/chrome/browser/resources/net_internals/status_view.css
@@ -4,15 +4,15 @@
  */
 
 .capture-status-view {
-  background: rgb(255, 0, 0);
+  background: rgb(238, 0, 0);
 }
 
 .halted-status-view {
-  background: rgb(0, 170, 0);
+  background: rgb(0, 138, 0);
 }
 
 .loaded-status-view {
-  background: rgb(136, 136, 204);
+  background: rgb(113, 113, 171);
 }
 
 #capture-status-view {
diff --git a/chrome/browser/resources/net_internals/status_view.html b/chrome/browser/resources/net_internals/status_view.html
index 2c89282..54e550f 100644
--- a/chrome/browser/resources/net_internals/status_view.html
+++ b/chrome/browser/resources/net_internals/status_view.html
@@ -13,7 +13,7 @@
            title='Number of events captured to this window'></span>)</a>
   </span>
   <span class=capture-status-view-arrow>
-    <select id=capture-status-view-actions>
+    <select id=capture-status-view-actions aria-label="Capture Actions">
       <optgroup label="Capture">
         <option value=stop>Stop</option>
         <option value=reset>Reset</option>
diff --git a/chrome/browser/resources/net_internals/test_view.html b/chrome/browser/resources/net_internals/test_view.html
index 9fd833f..9f1839c 100644
--- a/chrome/browser/resources/net_internals/test_view.html
+++ b/chrome/browser/resources/net_internals/test_view.html
@@ -5,7 +5,7 @@
     tests for why it failed.
   </div>
   <form id="test-view-connection-tests-form">
-    URL: <input id="test-view-url-input" type="text">
+    <label>URL: <input id="test-view-url-input" type="text"></label>
     <input id="test-view-connection-tests-submit" type="submit"
         value="Start tests">
   </form>
diff --git a/chrome/browser/resources/net_internals/test_view.js b/chrome/browser/resources/net_internals/test_view.js
index 00eeaac..a902bd0 100644
--- a/chrome/browser/resources/net_internals/test_view.js
+++ b/chrome/browser/resources/net_internals/test_view.js
@@ -143,7 +143,7 @@
       } else {
         addTextNode(r.resultCell,
                     netErrorToString(result) + ' (' + result + ')');
-        r.passFailCell.style.color = 'red';
+        r.passFailCell.style.color = '#e00';
         addTextNode(r.passFailCell, 'FAIL');
       }
 
diff --git a/chrome/browser/resources/net_internals/timeline_view.css b/chrome/browser/resources/net_internals/timeline_view.css
index 336317d..565117a 100644
--- a/chrome/browser/resources/net_internals/timeline_view.css
+++ b/chrome/browser/resources/net_internals/timeline_view.css
@@ -9,7 +9,12 @@
 }
 
 #timeline-view-selection-toggle {
-  cursor: pointer;
+  background-color: #fff;
+  background-image: url(chrome://resources/images/select.png);
+  border: none;
+  height: 8px;
+  padding: none;
+  width: 19px;
 }
 
 .timeline-view-rotateleft {
diff --git a/chrome/browser/resources/net_internals/timeline_view.html b/chrome/browser/resources/net_internals/timeline_view.html
index 57501eb..10ada22 100644
--- a/chrome/browser/resources/net_internals/timeline_view.html
+++ b/chrome/browser/resources/net_internals/timeline_view.html
@@ -1,8 +1,8 @@
 <div id=timeline-view-selection-div>
   <div style="text-align: right">
-    <img id=timeline-view-selection-toggle
-         class=timeline-view-rotateleft
-         src='chrome://resources/images/select.png'>
+    <button id=timeline-view-selection-toggle
+            title="Toggle visibility of selection view"
+            class=timeline-view-rotateleft></button>
   </div>
 <ul id=timeline-view-selection-ul>
   <li id=timeline-view-open-sockets><label><input type=checkbox checked>
diff --git a/chrome/browser/resources/net_internals/top_bar_view.html b/chrome/browser/resources/net_internals/top_bar_view.html
index 0499fa3..b36721f 100644
--- a/chrome/browser/resources/net_internals/top_bar_view.html
+++ b/chrome/browser/resources/net_internals/top_bar_view.html
@@ -48,7 +48,7 @@
 #top-bar-view {
   -webkit-align-items: center;
   border-bottom: 1px solid gray;
-  color: #eee;
+  color: #fff;
   display: -webkit-flex;
   padding: 2px 2px 4px 7px;
 }
@@ -56,7 +56,7 @@
 
 <div id=top-bar-view>
   <span class=top-bar-view-arrow>
-    <select id=top-bar-view-tab-selecter></select>
+    <select aria-label="Tab selector" id=top-bar-view-tab-selecter></select>
   </span>
   <div style="-webkit-flex-grow: 1">
     <include src="status_view.html"/>
diff --git a/chrome/browser/resources/net_internals/waterfall_row.js b/chrome/browser/resources/net_internals/waterfall_row.js
index d17ebc3..06a5bdb 100644
--- a/chrome/browser/resources/net_internals/waterfall_row.js
+++ b/chrome/browser/resources/net_internals/waterfall_row.js
@@ -15,16 +15,18 @@
   // TODO(viona):
   // -Support nested events.
   // -Handle updating length when an event is stalled.
-  function WaterfallRow(parentView, sourceEntry, eventList) {
+  function WaterfallRow(parentView, sourceEntry) {
     this.parentView_ = parentView;
     this.sourceEntry_ = sourceEntry;
 
-    this.eventTypes_ = eventList;
     this.description_ = sourceEntry.getDescription();
 
     this.createRow_();
   }
 
+  // Offset of popup from mouse location.
+  var POPUP_OFFSET_FROM_CURSOR = 25;
+
   WaterfallRow.prototype = {
     onSourceUpdated: function() {
       this.updateRow();
@@ -36,20 +38,22 @@
       // URL Request to start the job has not been received. In that case, the
       // description obtained is incorrect. The following fixes that.
       if (this.description_ == '') {
-        this.urlCell_.innerHTML = '';
+        this.sourceCell_.innerHTML = '';
         this.description_ = this.sourceEntry_.getDescription();
-        addTextNode(this.urlCell_, this.description_);
+        addTextNode(this.sourceCell_, this.description_);
       }
 
       this.rowCell_.innerHTML = '';
 
-      var matchingEventPairs = this.findLogEntryPairs_(this.eventTypes_);
+      var matchingEventPairs =
+          WaterfallRow.findUrlRequestEvents(this.sourceEntry_);
 
       // Creates the spacing in the beginning to show start time.
       var startTime = this.parentView_.getStartTime();
-      var sourceEntryStartTime = this.sourceEntry_.getStartTime();
+      var sourceEntryStartTime = this.getStartTime();
       var delay = sourceEntryStartTime - startTime;
       var frontNode = addNode(this.rowCell_, 'div');
+      frontNode.classList.add('waterfall-view-padding');
       setNodeWidth(frontNode, delay * scale);
 
       var barCell = addNode(this.rowCell_, 'div');
@@ -60,6 +64,7 @@
       }
 
       var currentEnd = sourceEntryStartTime;
+
       for (var i = 0; i < matchingEventPairs.length; ++i) {
         var event = matchingEventPairs[i];
         var startTicks = event.startEntry.time;
@@ -73,13 +78,13 @@
         if (currentEnd < event.startTime) {
           var eventDuration = event.startTime - currentEnd;
           var padNode = this.createNode_(
-              barCell, eventDuration, this.type_, 'source');
+              barCell, eventDuration, this.sourceTypeString_, 'source');
         }
 
         // Creates event bars.
-        var eventType = eventTypeToCssClass_(EventTypeNames[event.eventType]);
         var eventNode = this.createNode_(
-            barCell, event.eventDuration, eventType, event);
+            barCell, event.eventDuration, EventTypeNames[event.eventType],
+            event);
         currentEnd = event.startTime + event.eventDuration;
       }
 
@@ -87,7 +92,7 @@
       if (this.getEndTime() > currentEnd) {
         var endDuration = (this.getEndTime() - currentEnd);
         var endNode = this.createNode_(
-            barCell, endDuration, this.type_, 'source');
+            barCell, endDuration, this.sourceTypeString_, 'source');
       }
     },
 
@@ -103,7 +108,6 @@
       parentNode.innerHTML = '';
     },
 
-    // TODO(viona): Create popup at mouse location.
     createPopup_: function(parentNode, event, eventType, duration, mouse) {
       var tableStart = this.parentView_.getStartTime();
 
@@ -113,18 +117,26 @@
       var popupList = addNode(newPopup, 'ul');
       popupList.classList.add('waterfall-view-popup-list');
 
+      popupList.style.maxWidth =
+          $(WaterfallView.MAIN_BOX_ID).offsetWidth * 0.5 + 'px';
+
+      this.createPopupItem_(
+          popupList, 'Has Error', this.sourceEntry_.isError());
+
       this.createPopupItem_(
           popupList, 'Event Type', eventType);
-      this.createPopupItem_(
-          popupList, 'Event Duration', duration.toFixed(0) + 'ms');
 
       if (event != 'source') {
         this.createPopupItem_(
+          popupList, 'Event Duration', duration.toFixed(0) + 'ms');
+        this.createPopupItem_(
             popupList, 'Event Start Time', event.startTime - tableStart + 'ms');
         this.createPopupItem_(
             popupList, 'Event End Time', event.endTime - tableStart + 'ms');
       }
-
+      this.createPopupItem_(
+            popupList, 'Source Duration',
+            this.getEndTime() - this.getStartTime() + 'ms');
       this.createPopupItem_(
           popupList, 'Source Start Time',
           this.getStartTime() - tableStart + 'ms');
@@ -133,37 +145,27 @@
       this.createPopupItem_(
           popupList, 'Source ID', this.sourceEntry_.getSourceId());
       var urlListItem = this.createPopupItem_(
-          popupList, 'Source Description: ', this.description_);
+          popupList, 'Source Description', this.description_);
 
-      var viewWidth = $(WaterfallView.MAIN_BOX_ID).offsetWidth;
-      // Controls the overflow of extremely long URLs by cropping to window.
-      if (urlListItem.offsetWidth > viewWidth) {
-        urlListItem.style.width = viewWidth + 'px';
-      }
       urlListItem.classList.add('waterfall-view-popup-list-url-item');
 
-      this.createPopupItem_(
-          popupList, 'Has Error', this.sourceEntry_.isError());
-
       // Fixes cases where the popup appears 'off-screen'.
-      var popupLeft = mouse.pageX + $(WaterfallView.MAIN_BOX_ID).scrollLeft;
-      var popupRight = popupLeft + newPopup.offsetWidth;
-      var viewRight = viewWidth + $(WaterfallView.MAIN_BOX_ID).scrollLeft;
-
-      if (viewRight - popupRight < 0) {
-        popupLeft = viewRight - newPopup.offsetWidth;
+      var popupLeft = mouse.pageX - newPopup.offsetWidth;
+      if (popupLeft < 0) {
+        popupLeft = mouse.pageX;
       }
-      newPopup.style.left = popupLeft + 'px';
+      newPopup.style.left = popupLeft +
+          $(WaterfallView.MAIN_BOX_ID).scrollLeft -
+          $(WaterfallView.BAR_TABLE_ID).offsetLeft + 'px';
 
-      var popupTop = mouse.pageY + $(WaterfallView.MAIN_BOX_ID).scrollTop;
-      var popupBottom = popupTop + newPopup.offsetHeight;
-      var viewBottom = $(WaterfallView.MAIN_BOX_ID).offsetHeight +
-          $(WaterfallView.MAIN_BOX_ID).scrollTop;
-
-      if (viewBottom - popupBottom < 0) {
-        popupTop = viewBottom - newPopup.offsetHeight;
+      var popupTop = mouse.pageY - newPopup.offsetHeight -
+          POPUP_OFFSET_FROM_CURSOR;
+      if (popupTop < 0) {
+        popupTop = mouse.pageY;
       }
-      newPopup.style.top = popupTop + 'px';
+      newPopup.style.top = popupTop +
+          $(WaterfallView.MAIN_BOX_ID).scrollTop -
+          $(WaterfallView.BAR_TABLE_ID).offsetTop + 'px';
     },
 
     createPopupItem_: function(parentPopup, key, popupInformation) {
@@ -174,17 +176,8 @@
 
     createRow_: function() {
       // Create a row.
-      var tr = addNode($(WaterfallView.TBODY_ID), 'tr');
-      tr._id = this.sourceEntry_.getSourceId();
-      this.tableRow = tr;
-
-      var idCell = addNode(tr, 'td');
-      addTextNode(idCell, this.sourceEntry_.getSourceId());
-
-      var urlCell = addNode(tr, 'td');
-      urlCell.classList.add('waterfall-view-url-cell');
-      addTextNode(urlCell, this.description_);
-      this.urlCell_ = urlCell;
+      var tr = addNode($(WaterfallView.BAR_TBODY_ID), 'tr');
+      tr.classList.add('waterfall-view-table-row');
 
       // Creates the color bar.
 
@@ -192,62 +185,212 @@
       rowCell.classList.add('waterfall-view-row');
       this.rowCell_ = rowCell;
 
-      var sourceTypeString = this.sourceEntry_.getSourceTypeString();
-      this.type_ = eventTypeToCssClass_(sourceTypeString);
+      this.sourceTypeString_ = this.sourceEntry_.getSourceTypeString();
+
+      var infoTr = addNode($(WaterfallView.INFO_TBODY_ID), 'tr');
+      infoTr.classList.add('waterfall-view-information-row');
+
+      var idCell = addNode(infoTr, 'td');
+      idCell.classList.add('waterfall-view-id-cell');
+      var idValue = this.sourceEntry_.getSourceId();
+      var idLink = addNodeWithText(idCell, 'a', idValue);
+      idLink.href = '#events&s=' + idValue;
+
+      var sourceCell = addNode(infoTr, 'td');
+      sourceCell.classList.add('waterfall-view-url-cell');
+      addTextNode(sourceCell, this.description_);
+      this.sourceCell_ = sourceCell;
 
       this.updateRow();
     },
 
     // Generates nodes.
-    createNode_: function(parentNode, duration, eventType, event) {
+    createNode_: function(parentNode, duration, eventTypeString, event) {
+      var linkNode = addNode(parentNode, 'a');
+      linkNode.href = '#events&s=' + this.sourceEntry_.getSourceId();
+
       var scale = this.parentView_.getScaleFactor();
-      var newNode = addNode(parentNode, 'div');
+      var newNode = addNode(linkNode, 'div');
       setNodeWidth(newNode, duration * scale);
-      newNode.classList.add(eventType);
+      newNode.classList.add(eventTypeToCssClass_(eventTypeString));
+      newNode.classList.add('waterfall-view-bar-component');
       newNode.addEventListener(
           'mouseover',
-          this.createPopup_.bind(this, newNode, event, eventType, duration),
+          this.createPopup_.bind(this, newNode, event, eventTypeString,
+              duration),
           true);
       newNode.addEventListener(
           'mouseout', this.clearPopup_.bind(this, newNode), true);
       return newNode;
     },
-
-    /**
-     * Finds pairs of starting and ending events of all types that are in
-     * typeList. Currently does not handle nested events. Can consider adding
-     * starting events to a stack and popping off as their close events are
-     * found. Returns an array of objects containing start/end entry pairs,
-     * in the format {startEntry, endEntry}.
-     */
-    findLogEntryPairs_: function() {
-      var typeList = this.eventTypes_;
-      var matchingEventPairs = [];
-      var startEntries = {};
-      var entries = this.sourceEntry_.getLogEntries();
-      for (var i = 0; i < entries.length; ++i) {
-        var currentEntry = entries[i];
-        var type = currentEntry.type;
-        if (typeList.indexOf(type) < 0) {
-          continue;
-        }
-        if (currentEntry.phase == EventPhase.PHASE_BEGIN) {
-          startEntries[type] = currentEntry;
-        }
-        if (startEntries[type] && currentEntry.phase == EventPhase.PHASE_END) {
-          var event = {
-            startEntry: startEntries[type],
-            endEntry: currentEntry,
-          };
-          matchingEventPairs.push(event);
-        }
-      }
-      return matchingEventPairs;
-    },
   };
 
-  function eventTypeToCssClass_(rawEventType) {
-    return rawEventType.toLowerCase().replace(/_/g, '-');
+  /**
+   * Identifies source dependencies and extracts events of interest for use in
+   * inlining in URL Request bars.
+   * Created as static function for testing purposes.
+   */
+  WaterfallRow.findUrlRequestEvents = function(sourceEntry) {
+    var eventPairs = [];
+    if (!sourceEntry) {
+      return eventPairs;
+    }
+
+    // One level down from URL Requests.
+
+    var httpStreamJobSources = findDependenciesOfType_(
+        sourceEntry, EventType.HTTP_STREAM_REQUEST_BOUND_TO_JOB);
+
+    var httpTransactionReadHeadersPairs = findEntryPairsFromSourceEntries_(
+        [sourceEntry], EventType.HTTP_TRANSACTION_READ_HEADERS);
+    eventPairs = eventPairs.concat(httpTransactionReadHeadersPairs);
+
+    var proxyServicePairs = findEntryPairsFromSourceEntries_(
+        httpStreamJobSources, EventType.PROXY_SERVICE);
+    eventPairs = eventPairs.concat(proxyServicePairs);
+
+    if (httpStreamJobSources.length > 0) {
+      for (var i = 0; i < httpStreamJobSources.length; ++i) {
+        // Two levels down from URL Requests.
+
+        var hostResolverImplSources = findDependenciesOfType_(
+            httpStreamJobSources[i], EventType.HOST_RESOLVER_IMPL);
+
+        var socketSources = findDependenciesOfType_(
+            httpStreamJobSources[i], EventType.SOCKET_POOL_BOUND_TO_SOCKET);
+
+        // Three levels down from URL Requests.
+
+        var hostResolverImplRequestPairs = findEntryPairsFromSourceEntries_(
+            hostResolverImplSources, EventType.HOST_RESOLVER_IMPL_REQUEST);
+        eventPairs = eventPairs.concat(hostResolverImplRequestPairs);
+
+        var tcpConnectPairs = findEntryPairsFromSourceEntries_(
+            socketSources, EventType.TCP_CONNECT);
+
+        var sslConnectPairs = findEntryPairsFromSourceEntries_(
+            socketSources, EventType.SSL_CONNECT);
+
+        var connectionPairs = tcpConnectPairs.concat(sslConnectPairs);
+
+        // Truncates times of connection events such that they are shown after a
+        // proxy service event.
+        for (var k = 0; k < connectionPairs.length; ++k) {
+          var eventPair = shallowCloneObject(connectionPairs[k]);
+          var eventInRange = false;
+          // Should only have one proxy service event for the streamJob.
+          var proxyEvent = proxyServicePairs[0];
+          if (eventPair.startEntry.time >= proxyEvent.endEntry.time) {
+            eventInRange = true;
+          } else if (eventPair.endEntry.time > proxyEvent.endEntry.time) {
+            eventInRange = true;
+            eventPair.startEntry.time = proxyEvent.endEntry.time;
+          }
+          if (eventInRange) {
+            eventPairs.push(eventPair);
+          }
+        }
+      }
+    }
+    eventPairs.sort(function(a, b) {
+      return a.startEntry.time - b.startEntry.time;
+    });
+    return eventPairs;
+  }
+
+  function eventTypeToCssClass_(eventType) {
+    return eventType.toLowerCase().replace(/_/g, '-');
+  }
+
+  /**
+   * Finds all events of input type from the input list of Source Entries.
+   * Returns an ordered list of start and end log entries.
+   */
+  function findEntryPairsFromSourceEntries_(sourceEntryList, eventType) {
+    var eventPairs = [];
+    for (var i = 0; i < sourceEntryList.length; ++i) {
+      var sourceEntry = sourceEntryList[i];
+      if (sourceEntry) {
+        var entries = sourceEntry.getLogEntries();
+        var matchingEventPairs = findEntryPairsByType_(entries, eventType);
+        eventPairs = eventPairs.concat(matchingEventPairs);
+      }
+    }
+    return eventPairs;
+  }
+
+  /**
+   * Finds all events of input type from the input list of log entries.
+   * Returns an ordered list of start and end log entries.
+   */
+  function findEntryPairsByType_(entries, eventType) {
+    var matchingEventPairs = [];
+    var startEntry = null;
+    for (var i = 0; i < entries.length; ++i) {
+      var currentEntry = entries[i];
+      if (eventType != currentEntry.type) {
+        continue;
+      }
+      if (currentEntry.phase == EventPhase.PHASE_BEGIN) {
+        startEntry = currentEntry;
+      }
+      if (startEntry && currentEntry.phase == EventPhase.PHASE_END) {
+        var event = {
+          startEntry: startEntry,
+          endEntry: currentEntry,
+        };
+        matchingEventPairs.push(event);
+        startEntry = null;
+      }
+    }
+    return matchingEventPairs;
+  }
+
+  /**
+   * Returns an ordered list of SourceEntries that are dependencies for
+   * events of the given type.
+   */
+  function findDependenciesOfType_(sourceEntry, eventType) {
+    var sourceEntryList = [];
+    if (sourceEntry) {
+      var eventList = findEventsInSourceEntry_(sourceEntry, eventType);
+      for (var i = 0; i < eventList.length; ++i) {
+        var foundSourceEntry = findSourceEntryFromEvent_(eventList[i]);
+        if (foundSourceEntry) {
+          sourceEntryList.push(foundSourceEntry);
+        }
+      }
+    }
+    return sourceEntryList;
+  }
+
+  /**
+   * Returns an ordered list of events from the given sourceEntry with the
+   * given type.
+   */
+  function findEventsInSourceEntry_(sourceEntry, eventType) {
+    var entries = sourceEntry.getLogEntries();
+    var events = [];
+    for (var i = 0; i < entries.length; ++i) {
+      var currentEntry = entries[i];
+      if (currentEntry.type == eventType) {
+        events.push(currentEntry);
+      }
+    }
+    return events;
+  }
+
+  /**
+   * Follows the event to obtain the sourceEntry that is the source
+   * dependency.
+   */
+  function findSourceEntryFromEvent_(event) {
+    if (!('params' in event) || !('source_dependency' in event.params)) {
+      return undefined;
+    } else {
+      var id = event.params.source_dependency.id;
+      return SourceTracker.getInstance().getSourceEntry(id);
+    }
   }
 
   return WaterfallRow;
diff --git a/chrome/browser/resources/net_internals/waterfall_view.css b/chrome/browser/resources/net_internals/waterfall_view.css
index 14a0f60c..d30721b 100644
--- a/chrome/browser/resources/net_internals/waterfall_view.css
+++ b/chrome/browser/resources/net_internals/waterfall_view.css
@@ -11,29 +11,85 @@
   padding-left: 5px;
   position: fixed;
   top: 40px;
+  /* Displays above time bar and information tables. */
+  z-index: 3;
+}
+
+#waterfall-view-time-bar-table {
+  border-collapse: collapse;
+  border-spacing: 0;
+  position: absolute;
+  /* Displays above main tab and under information table. */
+  z-index: 1;
+}
+
+#waterfall-view-information-table {
+  background-color: #FFF;
+  border-collapse: collapse;
+  border-spacing: 0;
+  left: 0;
+  overflow: hidden;
+  position: fixed;
+  /* Displays above time bar table. */
+  z-index: 2;
+}
+
+.waterfall-view-information-row {
+  height: 25px;
+  margin: 0;
+  padding: 0;
+  white-space: nowrap;
 }
 
 .waterfall-view-url-cell {
   display: inline-block;
+  font-size: 15px;
+  height: 25px;
   overflow: hidden;
+  padding-bottom: 0;
+  padding-top: 0;
   text-overflow: ellipsis;
   white-space: nowrap;
   width: 250px;
 }
 
-.waterfall-view-row {
+.waterfall-view-id-cell {
+  display: inline-block;
+  font-size: 15px;
+  height: 25px;
+  min-width: 30px;
+  overflow: hidden;
+  padding-bottom: 0;
+  padding-left: 5px;
+  padding-right: 2px;
+  padding-top: 0;
+}
+
+.waterfall-view-table-row {
   white-space: nowrap;
 }
 
+.waterfall-view-row {
+  height: 25px;
+  padding: 0;
+}
+
 .waterfall-view-row * {
   display: inline-block;
   padding-top: 0;
 }
 
-.waterfall-view-bar > * {
+.waterfall-view-bar-component {
   height: 15px;
 }
 
+.waterfall-view-popup {
+  display: inline-block;
+  position: absolute;
+  /* Displays above info table and controls */
+  z-index: 4;
+}
+
 .waterfall-view-popup-list {
   background-color: rgba(255, 255, 255, 0.8);
   border-color: #000;
@@ -41,13 +97,13 @@
   border-width: 2px;
   color: #000;
   padding-right: 1em;
-  z-index: -1;
 }
 
 .waterfall-view-popup-list > li {
   display: list-item;
 }
 .waterfall-view-popup-list-url-item {
+  overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
@@ -87,7 +143,7 @@
   background: -webkit-linear-gradient(top, #EEE, rgba(0, 122, 122, 0.5));
 }
 
-.waterfall-view-row .host-resolver-impl {
+.waterfall-view-row .host-resolver-impl-request {
   background: -webkit-linear-gradient(top, #EEE, rgba(122, 0, 122, 0.5));
 }
 
@@ -103,11 +159,6 @@
   background: -webkit-linear-gradient(top, #EEE, rgba(55, 122, 178, 0.5));
 }
 
-.waterfall-view-popup {
-  display: inline-block;
-  position: absolute;
-}
-
 .waterfall-view-time-scale-row {
   white-space: nowrap;
 }
diff --git a/chrome/browser/resources/net_internals/waterfall_view.html b/chrome/browser/resources/net_internals/waterfall_view.html
index ac88a7a..fbbca32 100644
--- a/chrome/browser/resources/net_internals/waterfall_view.html
+++ b/chrome/browser/resources/net_internals/waterfall_view.html
@@ -7,16 +7,25 @@
       <input id=waterfall-view-adjust-to-window type=button value="Fit Range in Window">
     </div>
     <p>
-    <table id=waterfall-view-source-list-table>
+    <!-- Table that displays time bars -->
+    <table id=waterfall-view-time-bar-table>
       <thead>
-      <tr>
-        <td id=waterfall-view-source-id>ID</td>
-        <td id=waterfall-view-source-header>Source</td>
+      <tr id=waterfall-view-table-header>
         <td id=waterfall-view-time-scale-labels></td>
       </tr>
       </thead>
       <!-- Events Waterfall table body: This is where request rows go into -->
-      <tbody id=waterfall-view-source-list-tbody></tbody>
+      <tbody id=waterfall-view-time-bar-tbody></tbody>
+    </table>
+    <!-- Fixed table that contains the id and url information. -->
+    <table id=waterfall-view-information-table>
+      <thead id=waterfall-view-information-thead>
+        <tr>
+          <td class=waterfall-view-id-cell id=waterfall-view-id-header>ID</td>
+          <td class=waterfall-view-url-cell id=waterfall-view-url-header>URL</td>
+        </tr>
+      </thead>
+      <tbody id=waterfall-view-information-tbody></tbody>
     </table>
   </div>
 </div>
diff --git a/chrome/browser/resources/net_internals/waterfall_view.js b/chrome/browser/resources/net_internals/waterfall_view.js
index aac15b6..5c78ea5 100644
--- a/chrome/browser/resources/net_internals/waterfall_view.js
+++ b/chrome/browser/resources/net_internals/waterfall_view.js
@@ -29,7 +29,12 @@
     $(WaterfallView.MAIN_BOX_ID).addEventListener(
         'mousewheel', this.scrollToZoom_.bind(this), true);
 
+    $(WaterfallView.MAIN_BOX_ID).addEventListener(
+        'scroll', this.scrollInfoTable_.bind(this), true);
+
     this.initializeSourceList_();
+
+    window.onload = this.scrollInfoTable_();
   }
 
   WaterfallView.TAB_ID = 'tab-handle-waterfall';
@@ -38,14 +43,18 @@
 
   // IDs for special HTML elements in events_waterfall_view.html.
   WaterfallView.MAIN_BOX_ID = 'waterfall-view-tab-content';
-  WaterfallView.TBODY_ID = 'waterfall-view-source-list-tbody';
+  WaterfallView.BAR_TABLE_ID = 'waterfall-view-time-bar-table';
+  WaterfallView.BAR_TBODY_ID = 'waterfall-view-time-bar-tbody';
   WaterfallView.SCALE_ID = 'waterfall-view-adjust-to-window';
-  WaterfallView.ID_HEADER_ID = 'waterfall-view-source-id';
-  WaterfallView.SOURCE_HEADER_ID = 'waterfall-view-source-header';
   WaterfallView.TIME_SCALE_HEADER_ID = 'waterfall-view-time-scale-labels';
   WaterfallView.TIME_RANGE_ID = 'waterfall-view-time-range-submit';
   WaterfallView.START_TIME_ID = 'waterfall-view-start-input';
   WaterfallView.END_TIME_ID = 'waterfall-view-end-input';
+  WaterfallView.INFO_TABLE_ID = 'waterfall-view-information-table';
+  WaterfallView.INFO_TBODY_ID = 'waterfall-view-information-tbody';
+  WaterfallView.CONTROLS_ID = 'waterfall-view-controls';
+  WaterfallView.ID_HEADER_ID = 'waterfall-view-id-header';
+  WaterfallView.URL_HEADER_ID = 'waterfall-view-url-header';
 
   // The number of units mouse wheel deltas increase for each tick of the
   // wheel.
@@ -73,28 +82,22 @@
         this.startTime_ = timeutil.convertTimeTicksToTime(logEntries[0].time);
         // Initial scale factor.
         this.scaleFactor_ = 0.1;
-        this.eventsList_ = this.createEventsList_();
       }
       for (var i = 0; i < sourceEntries.length; ++i) {
         var sourceEntry = sourceEntries[i];
         var id = sourceEntry.getSourceId();
-        for (var j = 0; j < this.eventsList_.length; ++j) {
-          var eventObject = this.eventsList_[j];
-          if (sourceEntry.getSourceType() == eventObject.mainEvent) {
-            var row = this.sourceIdToRowMap_[id];
-            if (!row) {
-              var newRow = new WaterfallRow(
-                  this, sourceEntry, eventObject.importantEventTypes);
-              if (newRow == undefined) {
-                console.log(sourceEntry);
-              }
-              this.sourceIdToRowMap_[id] = newRow;
-            } else {
-              row.onSourceUpdated();
-            }
+        if (sourceEntry.getSourceType() == EventSourceType.URL_REQUEST) {
+          var row = this.sourceIdToRowMap_[id];
+          if (!row) {
+            var newRow = new WaterfallRow(this, sourceEntry);
+            this.sourceIdToRowMap_[id] = newRow;
+          } else {
+            row.onSourceUpdated();
           }
         }
       }
+      this.scrollInfoTable_();
+      this.positionBarTable_();
       this.updateTimeScale_(this.scaleFactor_);
     },
 
@@ -114,13 +117,26 @@
       return this.startTime_;
     },
 
+    setGeometry: function(left, top, width, height) {
+      superClass.prototype.setGeometry.call(this, left, top, width, height);
+      this.scrollInfoTable_();
+    },
+
+    show: function(isVisible) {
+      superClass.prototype.show.call(this, isVisible);
+      if (isVisible) {
+        this.scrollInfoTable_();
+      }
+    },
+
     /**
      * Initializes the list of source entries.  If source entries are already
      * being displayed, removes them all in the process.
      */
     initializeSourceList_: function() {
       this.sourceIdToRowMap_ = {};
-      $(WaterfallView.TBODY_ID).innerHTML = '';
+      $(WaterfallView.BAR_TBODY_ID).innerHTML = '';
+      $(WaterfallView.INFO_TBODY_ID).innerHTML = '';
       this.startTime_ = null;
       this.scaleFactor_ = null;
     },
@@ -128,11 +144,12 @@
     /**
      * Changes scroll position of the window such that horizontally, everything
      * within the specified range fits into the user's viewport.
-     * TODO(viona): Find a way to get rid of the magic number.
      */
     adjustToWindow_: function(windowStart, windowEnd) {
-      var maxWidth = $(WaterfallView.MAIN_BOX_ID).offsetWidth - 50;
-      $(WaterfallView.TBODY_ID).width = maxWidth + 'px';
+      var waterfallLeft = $(WaterfallView.INFO_TABLE_ID).offsetWidth +
+          $(WaterfallView.INFO_TABLE_ID).offsetLeft +
+          $(WaterfallView.ID_HEADER_ID).offsetWidth;
+      var maxWidth = $(WaterfallView.MAIN_BOX_ID).offsetWidth - waterfallLeft;
       var totalDuration = 0;
       if (windowEnd != -1) {
         totalDuration = windowEnd - windowStart;
@@ -149,12 +166,11 @@
         return;
       }
       this.scaleAll_(maxWidth / totalDuration);
-      var waterfallLeft = $(WaterfallView.TIME_SCALE_HEADER_ID).offsetLeft;
       $(WaterfallView.MAIN_BOX_ID).scrollLeft =
-          windowStart * this.scaleFactor_ + waterfallLeft;
+          windowStart * this.scaleFactor_;
     },
 
-    // Updates the time tick indicators.
+    /** Updates the time tick indicators. */
     updateTimeScale_: function(scaleFactor) {
       var timePerTick = 1;
       var minTickDistance = 20;
@@ -165,7 +181,7 @@
       var timeTickRow = addNode($(WaterfallView.TIME_SCALE_HEADER_ID), 'div');
       timeTickRow.classList.add('waterfall-view-time-scale-row');
 
-      var availableWidth = $(WaterfallView.TBODY_ID).clientWidth;
+      var availableWidth = $(WaterfallView.BAR_TBODY_ID).clientWidth;
       var tickDistance = scaleFactor * timePerTick;
 
       while (tickDistance < minTickDistance) {
@@ -202,10 +218,12 @@
     scrollToZoom_: function(event) {
       // To use scrolling to control zoom, hold down the alt key and scroll.
       if ('wheelDelta' in event && event.altKey) {
+        event.preventDefault();
         var zoomFactor = Math.pow(MOUSE_WHEEL_ZOOM_RATE,
              event.wheelDeltaY / MOUSE_WHEEL_UNITS_PER_CLICK);
 
-        var waterfallLeft = $(WaterfallView.TIME_SCALE_HEADER_ID).offsetLeft;
+        var waterfallLeft = $(WaterfallView.ID_HEADER_ID).offsetWidth +
+            $(WaterfallView.URL_HEADER_ID).offsetWidth;
         var oldCursorPosition = event.pageX +
             $(WaterfallView.MAIN_BOX_ID).scrollLeft;
         var oldCursorPositionInTable = oldCursorPosition - waterfallLeft;
@@ -221,7 +239,42 @@
       }
     },
 
-    // Parses user input, then calls adjustToWindow to shift that into view.
+    /**
+     * Positions the bar table such that it is in line with the right edge of
+     * the info table.
+     */
+    positionBarTable_: function() {
+      var offsetLeft = $(WaterfallView.INFO_TABLE_ID).offsetWidth +
+          $(WaterfallView.INFO_TABLE_ID).offsetLeft;
+      $(WaterfallView.BAR_TABLE_ID).style.left = offsetLeft + 'px';
+    },
+
+    /**
+     * Moves the info table when the page is scrolled vertically, ensuring that
+     * the correct information is displayed on the page, and that no elements
+     * are blocked unnecessarily.
+     */
+    scrollInfoTable_: function(event) {
+      $(WaterfallView.INFO_TABLE_ID).style.top =
+          $(WaterfallView.MAIN_BOX_ID).offsetTop +
+          $(WaterfallView.BAR_TABLE_ID).offsetTop -
+          $(WaterfallView.MAIN_BOX_ID).scrollTop + 'px';
+
+      if ($(WaterfallView.INFO_TABLE_ID).offsetHeight >
+          $(WaterfallView.MAIN_BOX_ID).clientHeight) {
+        var scroll = $(WaterfallView.MAIN_BOX_ID).scrollTop;
+        var bottomClip =
+            $(WaterfallView.MAIN_BOX_ID).clientHeight -
+            $(WaterfallView.BAR_TABLE_ID).offsetTop +
+            $(WaterfallView.MAIN_BOX_ID).scrollTop;
+        // Clips the information table such that it does not cover the scroll
+        // bars or the controls bar.
+        $(WaterfallView.INFO_TABLE_ID).style.clip = 'rect(' + scroll +
+            'px auto ' + bottomClip + 'px auto)';
+      }
+    },
+
+    /** Parses user input, then calls adjustToWindow to shift that into view. */
     setStartEndTimes_: function() {
       var windowStart = parseInt($(WaterfallView.START_TIME_ID).value);
       var windowEnd = parseInt($(WaterfallView.END_TIME_ID).value);
@@ -234,39 +287,7 @@
       this.adjustToWindow_(windowStart, windowEnd);
     },
 
-    // Provides a structure that can be used to define source entry types and
-    // the log entries that are of interest.
-    createEventsList_: function() {
-      var eventsList = [];
-      // Creating list of events.
-      // TODO(viona): This is hard-coded. Consider user-input.
-      //              Also, work on getting socket information inlined in the
-      //              relevant URL_REQUEST events.
-      var urlRequestEvents = [
-        EventType.HTTP_STREAM_REQUEST,
-        EventType.HTTP_STREAM_REQUEST_BOUND_TO_JOB,
-        EventType.HTTP_TRANSACTION_READ_HEADERS
-      ];
 
-      eventsList.push(this.createEventTypeObjects_(
-          EventSourceType.URL_REQUEST, urlRequestEvents));
-
-      var httpStreamJobEvents = [EventType.PROXY_SERVICE];
-      eventsList.push(this.createEventTypeObjects_(
-          EventSourceType.HTTP_STREAM_JOB, httpStreamJobEvents));
-
-      return eventsList;
-    },
-
-    // Creates objects that can be used to define source entry types and
-    // the log entries that are of interest.
-    createEventTypeObjects_: function(mainEventType, eventTypesList) {
-      var eventTypeObject = {
-        mainEvent: mainEventType,
-        importantEventTypes: eventTypesList
-      };
-      return eventTypeObject;
-    },
   };
 
   return WaterfallView;
diff --git a/chrome/browser/resources/new_incognito_tab_theme.css b/chrome/browser/resources/new_incognito_tab_theme.css
deleted file mode 100644
index f962888..0000000
--- a/chrome/browser/resources/new_incognito_tab_theme.css
+++ /dev/null
@@ -1,22 +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.
- */
-
-html {
-  background-attachment: fixed;
-  background-color: $2;
-  background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$1);
-  background-position: $3;
-  background-repeat: $5;
-  height: 100%;
-  overflow: auto;
-}
-
-#attribution-img {
-  content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?$1);
-}
-
-html[bookmarkbarattached='true'] {
-  background-position: $4;
-}
diff --git a/chrome/browser/resources/ntp4/guest_tab.css b/chrome/browser/resources/ntp4/guest_tab.css
new file mode 100644
index 0000000..ae24211
--- /dev/null
+++ b/chrome/browser/resources/ntp4/guest_tab.css
@@ -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. */
+
+body {
+  margin: 10px 8px;
+}
+
+.icon {
+  -webkit-margin-end: 3px;
+  -webkit-margin-start: 6px;
+}
+
+html[dir='ltr'] .icon {
+  float: right;
+}
+
+html[dir='rtl'] .icon {
+  float: left;
+}
+
+.content {
+  background-color: #eee;
+  border-radius: 5px;
+  color: black;
+  margin-left: auto;
+  margin-right: auto;
+  margin-top: 66px;
+  max-width: 600px;
+  padding: 10px;
+}
diff --git a/chrome/browser/resources/ntp4/guest_tab.html b/chrome/browser/resources/ntp4/guest_tab.html
new file mode 100644
index 0000000..da293b4
--- /dev/null
+++ b/chrome/browser/resources/ntp4/guest_tab.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html i18n-values="dir:textdirection;bookmarkbarattached:bookmarkbarattached">
+<head>
+<title i18n-content="title"></title>
+<link rel="stylesheet" href="guest_tab.css">
+<script>
+// Until themes can clear the cache, force-reload the theme stylesheet.
+document.write('<link id="guestthemecss" rel="stylesheet" ' +
+               'href="chrome://theme/css/guest_new_tab_theme.css?' +
+               Date.now() + '">');
+</script>
+</head>
+<body>
+<div class="content"
+    i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+  <img src="../../../../ui/webui/resources/images/guest_icon_standalone.png"
+      class="icon">
+  <span i18n-values=".innerHTML:content"></span>
+</div>
+</body>
+<script src="chrome://resources/js/cr.js"></script>
+<script>
+cr.define('ntp', function() {
+  'use strict';
+
+  function themeChanged() {
+    document.getElementById('guestthemecss').href =
+        'chrome://theme/css/guest_new_tab_theme.css?' + Date.now();
+  }
+
+  return {
+    themeChanged: themeChanged,
+  };
+});
+</script>
+</html>
diff --git a/chrome/browser/resources/ntp4/incognito_tab.css b/chrome/browser/resources/ntp4/incognito_tab.css
new file mode 100644
index 0000000..5acb539
--- /dev/null
+++ b/chrome/browser/resources/ntp4/incognito_tab.css
@@ -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. */
+
+body {
+  margin: 10px 8px;
+}
+
+.icon {
+  -webkit-margin-end: 3px;
+  -webkit-margin-start: 6px;
+}
+
+html[dir='ltr'] .icon {
+  -webkit-transform: scaleX(-1);
+  float: right;
+}
+
+html[dir='rtl'] .icon {
+  float: left;
+}
+
+.content {
+  background-color: #eee;
+  border-radius: 5px;
+  color: black;
+  margin-left: auto;
+  margin-right: auto;
+  margin-top: 66px;
+  max-width: 600px;
+  padding: 10px;
+}
+
+.extensions-message {
+  -webkit-padding-start: 39px;
+  margin-top: 15px;
+  position: relative;
+}
+
+.extension-icon {
+  content: -webkit-image-set(
+      url('../../../app/theme/default_100_percent/extensions_section.png') 1x,
+      url('../../../app/theme/default_200_percent/extensions_section.png') 2x);
+  display: inline-block;
+  left: 0;
+  margin-top: -15px;
+  position: absolute;
+  right: 0;
+  top: 50%;
+  width: 30px;
+}
diff --git a/chrome/browser/resources/ntp4/incognito_tab.html b/chrome/browser/resources/ntp4/incognito_tab.html
new file mode 100644
index 0000000..53f9b79
--- /dev/null
+++ b/chrome/browser/resources/ntp4/incognito_tab.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html i18n-values="dir:textdirection;bookmarkbarattached:bookmarkbarattached">
+<head>
+<title i18n-content="title"></title>
+<link rel="stylesheet" href="incognito_tab.css">
+<script>
+// Until themes can clear the cache, force-reload the theme stylesheet.
+document.write('<link id="incognitothemecss" rel="stylesheet" ' +
+               'href="chrome://theme/css/incognito_new_tab_theme.css?' +
+               Date.now() + '">');
+</script>
+</head>
+<body>
+<div class="content"
+    i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+  <img src="../../../../ui/webui/resources/images/otr_icon_standalone.png" class="icon">
+  <span i18n-values=".innerHTML:content"></span>
+  <div class="extensions-message">
+    <div class="extension-icon"></div>
+    <span i18n-values=".innerHTML:extensionsmessage"></span>
+  </div>
+</div>
+</body>
+<script src="chrome://resources/js/cr.js"></script>
+<script>
+cr.define('ntp', function() {
+  'use strict';
+  /**
+   * Set whether the bookmarks bar is attached or not.
+   * @param {boolean} attached Whether the bar is attached or not.
+   */
+  function setBookmarkBarAttached(attached) {
+    document.documentElement.setAttribute('bookmarkbarattached', !!attached);
+  }
+
+  function themeChanged() {
+    document.getElementById('incognitothemecss').href =
+        'chrome://theme/css/incognito_new_tab_theme.css?' + Date.now();
+  }
+
+  return {
+    setBookmarkBarAttached: setBookmarkBarAttached,
+    themeChanged: themeChanged,
+  };
+});
+</script>
+</html>
diff --git a/chrome/browser/resources/ntp4/new_guest_tab_theme.css b/chrome/browser/resources/ntp4/new_guest_tab_theme.css
new file mode 100644
index 0000000..b4d1df1
--- /dev/null
+++ b/chrome/browser/resources/ntp4/new_guest_tab_theme.css
@@ -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.
+ */
+
+html {
+  background-attachment: fixed;
+  background-color: $2;
+  background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$1);
+  background-position: $3;
+  background-repeat: $5;
+  height: 100%;
+  overflow: auto;
+}
+
+#attribution-img {
+  content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?$1);
+}
+
+html[bookmarkbarattached='true'] {
+  background-position: $4;
+}
diff --git a/chrome/browser/resources/ntp4/new_incognito_tab_theme.css b/chrome/browser/resources/ntp4/new_incognito_tab_theme.css
new file mode 100644
index 0000000..b4d1df1
--- /dev/null
+++ b/chrome/browser/resources/ntp4/new_incognito_tab_theme.css
@@ -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.
+ */
+
+html {
+  background-attachment: fixed;
+  background-color: $2;
+  background-image: url(chrome://theme/IDR_THEME_NTP_BACKGROUND?$1);
+  background-position: $3;
+  background-repeat: $5;
+  height: 100%;
+  overflow: auto;
+}
+
+#attribution-img {
+  content: url(chrome://theme/IDR_THEME_NTP_ATTRIBUTION?$1);
+}
+
+html[bookmarkbarattached='true'] {
+  background-position: $4;
+}
diff --git a/chrome/browser/resources/options/autofill_options.css b/chrome/browser/resources/options/autofill_options.css
index 488197c..e777c94 100644
--- a/chrome/browser/resources/options/autofill_options.css
+++ b/chrome/browser/resources/options/autofill_options.css
@@ -3,7 +3,7 @@
  * found in the LICENSE file. */
 
 #autofill-options {
-  min-width: 550px;
+  width: 550px;
 }
 
 #autofill-help {
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index e2e80fd..b84defe 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -293,12 +293,6 @@
           OptionsPage.closeOverlay();
         };
 
-        $('bluetooth-reconnect-device').onmousedown = function(event) {
-          // Prevent 'blur' event, which would reset the list selection,
-          // thereby disabling the apply button.
-          event.preventDefault();
-        };
-
         $('bluetooth-paired-devices-list').addEventListener('change',
             function() {
           var item = $('bluetooth-paired-devices-list').selectedItem;
@@ -631,19 +625,20 @@
       }
 
       var pageContainer = $('page-container');
-      var pageTop = parseFloat(pageContainer.style.top);
-      var topSection = document.querySelector('#page-container section');
-      var pageHeight = document.body.scrollHeight - topSection.offsetTop;
+      // pageContainer.offsetTop is relative to the screen.
+      var pageTop = pageContainer.offsetTop;
+      var sectionBottom = section.offsetTop + section.offsetHeight;
+      // section.offsetTop is relative to the 'page-container'.
       var sectionTop = section.offsetTop;
-      var sectionHeight = section.offsetHeight;
-      var marginBottom = window.getComputedStyle(section).marginBottom;
-      if (marginBottom)
-        sectionHeight += parseFloat(marginBottom);
-      if (pageHeight - pageTop < sectionTop + sectionHeight) {
-        pageContainer.oldScrollTop = sectionTop + sectionHeight - pageHeight;
-        var verticalPosition = pageContainer.getBoundingClientRect().top -
-            pageContainer.oldScrollTop;
-        pageContainer.style.top = verticalPosition + 'px';
+      if (pageTop + sectionBottom > document.body.scrollHeight ||
+          pageTop + sectionTop < 0) {
+        pageContainer.oldScrollTop = -pageTop;
+        // Currently not all layout updates are guaranteed to precede the
+        // initializationComplete event (for example 'set-as-default-browser'
+        // button) leaving some uncertainty in the optimal scroll position.
+        // The section is placed approximately in the middle of the screen.
+        pageContainer.style.top = document.body.scrollHeight / 2 -
+            sectionBottom + 'px';
       }
     },
 
@@ -1067,21 +1062,12 @@
     },
 
     /**
-     * Reports a local error (e.g., disk full) to the "create" overlay during
-     * profile creation.
+     * Reports an error to the "create" overlay during profile creation.
+     * @param {string} error The error message to display.
      * @private
      */
-    showCreateProfileLocalError_: function() {
-      CreateProfileOverlay.onLocalError();
-    },
-
-    /**
-    * Reports a remote error (e.g., a network error during managed-user
-    * registration) to the "create" overlay during profile creation.
-    * @private
-    */
-    showCreateProfileRemoteError_: function() {
-      CreateProfileOverlay.onRemoteError();
+    showCreateProfileError_: function(error) {
+      CreateProfileOverlay.onError(error);
     },
 
     /**
@@ -1479,8 +1465,7 @@
     'setupPageZoomSelector',
     'setupProxySettingsSection',
     'showBluetoothSettings',
-    'showCreateProfileLocalError',
-    'showCreateProfileRemoteError',
+    'showCreateProfileError',
     'showCreateProfileSuccess',
     'showMouseControls',
     'showTouchpadControls',
diff --git a/chrome/browser/resources/options/chromeos/OWNERS b/chrome/browser/resources/options/chromeos/OWNERS
index cb08621..0722704 100644
--- a/chrome/browser/resources/options/chromeos/OWNERS
+++ b/chrome/browser/resources/options/chromeos/OWNERS
@@ -1,14 +1,10 @@
 achuith@chromium.org
 dpolukhin@chromium.org
-glotov@chromium.org
 nkostylev@chromium.org
 stevenjb@chromium.org
 xiyuan@chromium.org
 zelidrag@chromium.org
 
-# Change Picture and Accounts pages.
-ivankr@chromium.org
-
 # Display options.
 mukai@chromium.org
 
diff --git a/chrome/browser/resources/options/chromeos/bluetooth_device_list.js b/chrome/browser/resources/options/chromeos/bluetooth_device_list.js
index 5777571..ede390f 100644
--- a/chrome/browser/resources/options/chromeos/bluetooth_device_list.js
+++ b/chrome/browser/resources/options/chromeos/bluetooth_device_list.js
@@ -6,6 +6,7 @@
   /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
   /** @const */ var DeletableItem = options.DeletableItem;
   /** @const */ var DeletableItemList = options.DeletableItemList;
+  /** @const */ var ListSingleSelectionModel = cr.ui.ListSingleSelectionModel;
 
   /**
    * Bluetooth settings constants.
@@ -127,6 +128,7 @@
       this.autoExpands = true;
       this.fixedHeight = true;
       this.clear();
+      this.selectionModel = new ListSingleSelectionModel();
     },
 
     /**
@@ -284,25 +286,21 @@
       if (!target.classList.contains('row-delete-button'))
         return;
 
-      var listItem = this.getListItemAncestor(target);
-      var selected = this.selectionModel.selectedIndexes;
-      var index = this.getIndexOfListItem(listItem);
-      if (selected.indexOf(index) == -1)
-        selected = [index];
-      for (var j = selected.length - 1; j >= 0; j--) {
-        var index = selected[j];
-        var item = this.getListItemByIndex(index);
-        if (item && item.deletable) {
-          // Device is busy until we hear back from the Bluetooth adapter.
-          // Prevent double removal request.
-          item.deletable = false;
-          // TODO(kevers): Provide visual feedback that the device is busy.
+      var item = this.getListItemAncestor(target);
+      var selected = this.selectionModel.selectedIndex;
+      var index = this.getIndexOfListItem(item);
+      if (item && item.deletable) {
+        if (selected != index)
+          this.setSelectedDevice_(item.data.address);
+        // Device is busy until we hear back from the Bluetooth adapter.
+        // Prevent double removal request.
+        item.deletable = false;
+        // TODO(kevers): Provide visual feedback that the device is busy.
 
-          // Inform the bluetooth adapter that we are disconnecting or
-          // forgetting the device.
-          chrome.send('updateBluetoothDevice',
-            [item.data.address, item.connected ? 'disconnect' : 'forget']);
-        }
+        // Inform the bluetooth adapter that we are disconnecting or
+        // forgetting the device.
+        chrome.send('updateBluetoothDevice',
+          [item.data.address, item.connected ? 'disconnect' : 'forget']);
       }
     },
 
diff --git a/chrome/browser/resources/options/chromeos/internet_detail.html b/chrome/browser/resources/options/chromeos/internet_detail.html
index 0f0011a..556c70a 100644
--- a/chrome/browser/resources/options/chromeos/internet_detail.html
+++ b/chrome/browser/resources/options/chromeos/internet_detail.html
@@ -282,11 +282,11 @@
             <td class="option-name" i18n-content="restrictedPool"></td>
             <td id="restricted-pool" class="option-value"></td>
           </tr>
-          <tr class="gsm-only">
+          <tr>
             <td class="option-name" i18n-content="operatorName"></td>
             <td id="operator-name" class="option-value"></td>
           </tr>
-          <tr class="gsm-only">
+          <tr>
             <td class="option-name" i18n-content="operatorCode"></td>
             <td id="operator-code" class="option-value"></td>
           </tr>
@@ -374,7 +374,7 @@
             <td class="option-name" i18n-content="hardwareRevision"></td>
             <td id="hardware-revision" class="option-value"></td>
           </tr>
-          <tr>
+          <tr class="cdma-only">
             <td class="option-name" i18n-content="prlVersion"></td>
             <td id="prl-version" class="option-value"></td>
           </tr>
@@ -382,7 +382,7 @@
             <td class="option-name">MEID:</td>
             <td id="meid" class="option-value"></td>
           </tr>
-          <tr>
+          <tr class="gsm-only">
             <td class="option-name">ICCID:</td>
             <td id="iccid" class="option-value"></td>
           </tr>
@@ -680,6 +680,10 @@
             </div>
           </div>
         </div>
+        <div class="proxy-subsection" id="web-proxy-auto-discovery">
+          <span i18n-content="webProxyAutoDiscoveryUrl"></span>
+          <input id="web-proxy-auto-discovery-url" type="url" disabled>
+        </div>
       </section>
     </div>
   </div>
diff --git a/chrome/browser/resources/options/chromeos/internet_detail.js b/chrome/browser/resources/options/chromeos/internet_detail.js
index c3a8f36..a36df41 100644
--- a/chrome/browser/resources/options/chromeos/internet_detail.js
+++ b/chrome/browser/resources/options/chromeos/internet_detail.js
@@ -389,6 +389,8 @@
       updateHidden('#details-internet-page .wimax-details', !this.wimax);
       updateHidden('#details-internet-page .vpn-details', !this.vpn);
       updateHidden('#details-internet-page .proxy-details', !this.showProxy);
+      updateHidden('#details-internet-page .gsm-only', !this.gsm);
+      updateHidden('#details-internet-page .cdma-only', this.gsm);
       /* Network information merged into the Wifi tab for wireless networks
          unless the option is set for enabling a static IP configuration. */
       updateHidden('#details-internet-page .network-details',
@@ -589,6 +591,7 @@
     $('buyplan-details').hidden = true;
     $('activate-details').hidden = true;
     $('view-account-details').hidden = true;
+    $('web-proxy-auto-discovery').hidden = true;
     detailsPage.cellular = false;
     detailsPage.wireless = false;
     detailsPage.vpn = false;
@@ -820,13 +823,13 @@
     if (data.type != Constants.TYPE_ETHERNET)
       $('details-internet-disconnect').hidden = !data.connected;
 
-    if (data.type == Constants.TYPE_WIMAX ||
-        data.type == Constants.TYPE_WIFI ||
-        data.type == Constants.TYPE_VPN)
+    if ((data.type == Constants.TYPE_WIFI && data.encryption) ||
+        data.type == Constants.TYPE_WIMAX ||
+        data.type == Constants.TYPE_VPN) {
       $('details-internet-configure').hidden = false;
-    else
+    } else {
       $('details-internet-configure').hidden = true;
-
+    }
     $('connection-state').data = data;
   }
 
@@ -881,12 +884,14 @@
       $('details-internet-disconnect').hidden = true;
     else
       $('details-internet-disconnect').hidden = !data.connected;
-    if (data.type == Constants.TYPE_WIMAX ||
-        data.type == Constants.TYPE_WIFI ||
-        data.type == Constants.TYPE_VPN)
+    if ((data.type == Constants.TYPE_WIFI && data.encryption) ||
+        data.type == Constants.TYPE_WIMAX ||
+        data.type == Constants.TYPE_VPN) {
       $('details-internet-configure').hidden = false;
-    else
+    } else {
       $('details-internet-configure').hidden = true;
+    }
+    $('web-proxy-auto-discovery').hidden = true;
 
     detailsPage.deviceConnected = data.deviceConnected;
     detailsPage.connecting = data.connecting;
@@ -911,6 +916,11 @@
       inetNetmask.value = data.ipconfig.value.netmask;
       inetGateway.automatic = data.ipconfig.value.gateway;
       inetGateway.value = data.ipconfig.value.gateway;
+      if (data.ipconfig.value.webProxyAutoDiscoveryUrl) {
+        $('web-proxy-auto-discovery').hidden = false;
+        $('web-proxy-auto-discovery-url').value =
+            data.ipconfig.value.webProxyAutoDiscoveryUrl;
+      }
     }
 
     // Override the "automatic" values with the real saved DHCP values,
@@ -1088,18 +1098,29 @@
       $('model-id').textContent = data.modelId;
       $('firmware-revision').textContent = data.firmwareRevision;
       $('hardware-revision').textContent = data.hardwareRevision;
-      $('prl-version').textContent = data.prlVersion;
-      $('meid').textContent = data.meid;
-      $('iccid').textContent = data.iccid;
-      $('imei').textContent = data.imei;
       $('mdn').textContent = data.mdn;
-      $('esn').textContent = data.esn;
       $('min').textContent = data.min;
+      $('operator-name').textContent = data.operatorName;
+      $('operator-code').textContent = data.operatorCode;
+
+      // Show IMEI/ESN/MEID only if they are available.
+      (function() {
+        var setContentOrHide = function(property) {
+          var value = data[property];
+          if (value)
+            $(property).textContent = value;
+          else
+            $(property).parentElement.hidden = true;
+        };
+        setContentOrHide('esn');
+        setContentOrHide('imei');
+        setContentOrHide('meid');
+        setContentOrHide('prl-version');
+      })();
       detailsPage.gsm = data.gsm;
       if (data.gsm) {
-        $('operator-name').textContent = data.operatorName;
-        $('operator-code').textContent = data.operatorCode;
-        $('imsi').textContent = data.imsi;
+        $('iccid').textContent = data.iccid ? data.iccid : '';
+        $('imsi').textContent = data.imsi ? data.imsi : '';
 
         var apnSelector = $('select-apn');
         // Clear APN lists, keep only last element that "other".
diff --git a/chrome/browser/resources/options/import_data_overlay.js b/chrome/browser/resources/options/import_data_overlay.js
index 36bc866..8088c53 100644
--- a/chrome/browser/resources/options/import_data_overlay.js
+++ b/chrome/browser/resources/options/import_data_overlay.js
@@ -102,21 +102,18 @@
     },
 
     /**
-     * Sets the enabled and checked states of a checkbox element.
+     * Sets the enabled state of a checkbox element.
      * @param {Object} checkbox A checkbox element.
      * @param {boolean} enabled The enabled state of the checkbox. If false,
-     * the checkbox is disabled and unchecked. If true, the checkbox is enabled
-     * and checked.
-     * @param {boolean} visible The visible state of the checkbox.
+     *     the checkbox is disabled. If true, the checkbox is enabled.
      * @private
      */
     setUpCheckboxState_: function(checkbox, enabled) {
       checkbox.setDisabled('noProfileData', !enabled);
-      checkbox.checked = enabled;
     },
 
     /**
-     * Update the enabled and checked states of all checkboxes.
+     * Update the enabled and visible states of all the checkboxes.
      * @private
      */
     updateCheckboxes_: function() {
@@ -132,7 +129,6 @@
       for (var i = 0; i < importOptions.length; i++) {
         var checkbox = $('import-' + importOptions[i]);
         var enable = browserProfile && browserProfile[importOptions[i]];
-        checkbox.checked = enable;
         this.setUpCheckboxState_(checkbox, enable);
         var checkboxWithLabel = $('import-' + importOptions[i] + '-with-label');
         checkboxWithLabel.style.display = enable ? '' : 'none';
diff --git a/chrome/browser/resources/options/manage_profile_overlay.css b/chrome/browser/resources/options/manage_profile_overlay.css
index 29ca51a..743eab5 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.css
+++ b/chrome/browser/resources/options/manage_profile_overlay.css
@@ -81,6 +81,10 @@
   margin-bottom: 5px;
 }
 
+#create-profile-content {
+  padding-bottom: 0;
+}
+
 .action-area-shortcut-container {
   -webkit-box-flex: 1;
 }
@@ -114,3 +118,7 @@
   white-space: pre-wrap;
   word-wrap: break-word;
 }
+
+#create-profile-managed-content-area {
+  padding-top: 0;
+}
diff --git a/chrome/browser/resources/options/manage_profile_overlay.html b/chrome/browser/resources/options/manage_profile_overlay.html
index c81d543..fa0d0a7 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.html
+++ b/chrome/browser/resources/options/manage_profile_overlay.html
@@ -65,7 +65,7 @@
       </div>
       <div id="create-profile-error-bubble" hidden></div>
     </div>
-    <div class="content-area">
+    <div id="create-profile-managed-content-area" class="content-area">
       <div id="create-shortcut-container" class="checkbox" hidden>
         <label>
           <input id="create-shortcut" type="checkbox">
diff --git a/chrome/browser/resources/options/manage_profile_overlay.js b/chrome/browser/resources/options/manage_profile_overlay.js
index 40ede52..5e6d2af 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.js
+++ b/chrome/browser/resources/options/manage_profile_overlay.js
@@ -260,7 +260,7 @@
 
     /**
      * Display the error bubble, with |errorText| in the bubble.
-     * @param {string} errorText The localized string id to display as an error.
+     * @param {string} errorText The string to display as an error.
      * @param {string} mode A label that specifies the type of dialog
      *     box which is currently being viewed (i.e. 'create' or
      *     'manage').
@@ -272,7 +272,7 @@
     showErrorBubble_: function(errorText, mode, disableOKButton) {
       var nameErrorEl = $(mode + '-profile-error-bubble');
       nameErrorEl.hidden = false;
-      nameErrorEl.textContent = loadTimeData.getString(errorText);
+      nameErrorEl.textContent = errorText;
 
       if (disableOKButton)
         $(mode + '-profile-ok').disabled = true;
@@ -305,7 +305,9 @@
       if (newName == oldName) {
         this.hideErrorBubble_(mode);
       } else if (this.profileNames_[newName] != undefined) {
-        this.showErrorBubble_('manageProfilesDuplicateNameError', mode, true);
+        var errorText =
+            loadTimeData.getString('manageProfilesDuplicateNameError');
+        this.showErrorBubble_(errorText, mode, true);
       } else {
         this.hideErrorBubble_(mode);
 
@@ -558,25 +560,14 @@
     },
 
     /**
-     * Shows an error message describing a local error (most likely a disk
-     * error) when creating a new profile. Called by BrowserOptions via the
-     * BrowserOptionsHandler.
+     * Shows an error message describing an error when creating a new profile.
+     * Called by BrowserOptions via the BrowserOptionsHandler.
+     * @param {string} error The error message to display.
      * @private
      */
-    onLocalError_: function() {
+    onError_: function(error) {
       this.updateCreateInProgress_(false);
-      this.showErrorBubble_('createProfileLocalError');
-    },
-
-    /**
-     * Shows an error message describing a remote error (most likely a network
-     * error) when creating a new profile. Called by BrowserOptions via the
-     * BrowserOptionsHandler.
-     * @private
-     */
-    onRemoteError_: function() {
-      this.updateCreateInProgress_(false);
-      this.showErrorBubble_('createProfileRemoteError');
+      this.showErrorBubble_(error);
     },
 
     /**
@@ -706,8 +697,7 @@
   // Forward public APIs to private implementations.
   [
     'cancelCreateProfile',
-    'onLocalError',
-    'onRemoteError',
+    'onError',
     'onSuccess',
     'receiveExistingManagedUsers',
     'updateCreateInProgress',
diff --git a/chrome/browser/resources/options/managed_user_create_confirm.css b/chrome/browser/resources/options/managed_user_create_confirm.css
index 37b3770..a1e8af8 100644
--- a/chrome/browser/resources/options/managed_user_create_confirm.css
+++ b/chrome/browser/resources/options/managed_user_create_confirm.css
@@ -7,18 +7,31 @@
 }
 
 #managed-user-created-title {
+  padding: 20px;
   word-wrap: break-word;
 }
 
+@media only screen and (max-height:400px) {
+
+/* Omit the image on very small screens. */
 #managed-user-created-image {
+  display: none;
+}
+
+} /* @media only screen and (max-height:400px) */
+
+#managed-user-created-image {
+  -webkit-border-radius: 3px 3px 0 0;
+  -webkit-box-flex: 5;
   background-image: -webkit-image-set(
       url('../../../../ui/resources/default_100_percent/supervised_illustration_done.png') 1x,
       url('../../../../ui/resources/default_200_percent/supervised_illustration_done.png') 2x);
+  background-position: center;
   height: 344px;
 }
 
 #managed-user-created-text {
-  margin-top: 10px;
+  padding: 0 20px 0 20px;
   white-space: pre-wrap;
   word-wrap: break-word;
 }
@@ -27,3 +40,7 @@
   max-width: 600px;
   word-wrap: break-word;
 }
+
+#managed-user-created-action-area {
+  padding: 20px;
+}
diff --git a/chrome/browser/resources/options/managed_user_create_confirm.html b/chrome/browser/resources/options/managed_user_create_confirm.html
index c7c9b90..346b9f0 100644
--- a/chrome/browser/resources/options/managed_user_create_confirm.html
+++ b/chrome/browser/resources/options/managed_user_create_confirm.html
@@ -1,12 +1,10 @@
 <div id="managed-user-created" class="page" hidden>
   <div class="close-button"></div>
   <!-- Overlay for the confirmation after creating a supervised user. -->
+  <div id="managed-user-created-image"></div>
   <h1 id="managed-user-created-title"></h1>
-  <div class="content-area">
-    <div id="managed-user-created-image"></div>
-    <div id="managed-user-created-text"></div>
-  </div>
-  <div class="action-area button-strip">
+  <div id="managed-user-created-text" class="content-area"></div>
+  <div id="managed-user-created-action-area" class="action-area button-strip">
     <button id="managed-user-created-done"
         i18n-content="managedUserCreatedDone">
     </button>
diff --git a/chrome/browser/resources/options/managed_user_learn_more.css b/chrome/browser/resources/options/managed_user_learn_more.css
index 79878ee..d22a9a7 100644
--- a/chrome/browser/resources/options/managed_user_learn_more.css
+++ b/chrome/browser/resources/options/managed_user_learn_more.css
@@ -6,15 +6,35 @@
   width: 722px;
 }
 
+#managed-user-learn-more-title {
+  padding: 20px;
+}
+
 #managed-user-learn-more-text {
-  margin-top: 10px;
+  padding: 0 20px 0 20px;
   white-space: pre-wrap;
   word-wrap: break-word;
 }
 
+@media only screen and (max-height:500px) {
+
+/* Omit the image on very small screens. */
 #managed-user-learn-more-image {
+  display: none;
+}
+
+} /* @media only screen and (max-height:500px) */
+
+#managed-user-learn-more-image {
+  -webkit-border-radius: 3px 3px 0 0;
+  -webkit-box-flex: 1;
   background-image: -webkit-image-set(
       url('../../../../ui/resources/default_100_percent/supervised_illustration_start.png') 1x,
       url('../../../../ui/resources/default_200_percent/supervised_illustration_start.png') 2x);
+  background-position: center;
   height: 344px;
 }
+
+#managed-user-learn-more-action-area {
+  padding: 20px;
+}
diff --git a/chrome/browser/resources/options/managed_user_learn_more.html b/chrome/browser/resources/options/managed_user_learn_more.html
index e0b2c62..0698546 100644
--- a/chrome/browser/resources/options/managed_user_learn_more.html
+++ b/chrome/browser/resources/options/managed_user_learn_more.html
@@ -1,14 +1,15 @@
 <div id="managed-user-learn-more" class="page" hidden>
   <div class="close-button"></div>
   <!-- Overlay for the 'Learn more' link when creating a supervised user. -->
-  <h1 i18n-content="managedUserLearnMoreTitle"></h1>
-  <div class="content-area">
-    <div id="managed-user-learn-more-image"></div>
-    <div id="managed-user-learn-more-text"
-        i18n-content="managedUserLearnMoreText">
-    </div>
+  <div id="managed-user-learn-more-image"></div>
+  <h1 id="managed-user-learn-more-title"
+      i18n-content="managedUserLearnMoreTitle">
+  </h1>
+  <div id="managed-user-learn-more-text" class="content-area"
+      i18n-content="managedUserLearnMoreText">
   </div>
-  <div class="action-area button-strip">
+  <div id="managed-user-learn-more-action-area"
+      class="action-area button-strip">
     <button id="managed-user-learn-more-done"
         i18n-content="managedUserLearnMoreDone">
     </button>
diff --git a/chrome/browser/resources/options/options_page.js b/chrome/browser/resources/options/options_page.js
index a9b7c84..0e827fd 100644
--- a/chrome/browser/resources/options/options_page.js
+++ b/chrome/browser/resources/options/options_page.js
@@ -283,7 +283,7 @@
     if (document.activeElement != document.body) {
       if (FocusOutlineManager.forDocument(document).visible) {
         overlay.focus();
-      } else {
+      } else if (!overlay.pageDiv.contains(document.activeElement)) {
         document.activeElement.blur();
       }
     }
diff --git a/chrome/browser/resources/options/reset_profile_settings_overlay.html b/chrome/browser/resources/options/reset_profile_settings_overlay.html
index 5c96eaa..873a6fc 100644
--- a/chrome/browser/resources/options/reset_profile_settings_overlay.html
+++ b/chrome/browser/resources/options/reset_profile_settings_overlay.html
@@ -22,8 +22,12 @@
     </div>
   </div>
   <div class="gray-bottom-bar checkbox">
-    <input id="send-settings" type="checkbox" checked=true>
-    <label for="send-settings" i18n-content="resetProfileSettingsFeedback">
-    </label>
+    <span class="controlled-setting-with-label">
+      <input id="send-settings" type="checkbox" checked>
+      <span>
+        <label for="send-settings" i18n-content="resetProfileSettingsFeedback">
+        </label>
+      </span>
+    </span>
   </div>
 </div>
diff --git a/chrome/browser/resources/quick_office/manifest_editor.json b/chrome/browser/resources/quick_office/manifest_editor.json
index ae3ef79..39fd847 100644
--- a/chrome/browser/resources/quick_office/manifest_editor.json
+++ b/chrome/browser/resources/quick_office/manifest_editor.json
@@ -79,7 +79,7 @@
       "sub_package_path": "_platform_specific/arm/"
     }
   ],
-  "version": "3.0.4.2",
+  "version": "3.0.5.2",
   "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 02be439..204e174 100644
--- a/chrome/browser/resources/quick_office/manifest_viewing.json
+++ b/chrome/browser/resources/quick_office/manifest_viewing.json
@@ -78,7 +78,7 @@
       "sub_package_path": "_platform_specific/arm/"
     }
   ],
-  "version": "3.0.3.1063",
+  "version": "3.0.5.2",
   "web_accessible_resources": [
     "views/qowt.html"
   ]
diff --git a/chrome/browser/resources/sync_setup_overlay.js b/chrome/browser/resources/sync_setup_overlay.js
index bc21ae6..770eecf 100644
--- a/chrome/browser/resources/sync_setup_overlay.js
+++ b/chrome/browser/resources/sync_setup_overlay.js
@@ -452,7 +452,8 @@
         this.useEncryptEverything_ = args.encryptAllData;
 
         // Determine whether to display the 'OK, sync everything' confirmation
-        // dialog or the advanced sync settings dialog.
+        // dialog or the advanced sync settings dialog, and assign focus to the
+        // OK button, or to the passphrase field if a passphrase is required.
         this.usePassphrase_ = args.usePassphrase;
         if (args.showSyncEverythingPage == false || this.usePassphrase_ ||
             args.syncAllDataTypes == false || args.showPassphrase) {
@@ -460,8 +461,13 @@
                           DataTypeSelection.SYNC_EVERYTHING :
                           DataTypeSelection.CHOOSE_WHAT_TO_SYNC;
           this.showCustomizePage_(args, index);
+          if (args.showPassphrase)
+            $('passphrase').focus();
+          else
+            $('choose-datatypes-ok').focus();
         } else {
           this.showSyncEverythingPage_();
+          $('confirm-everything-ok').focus();
         }
       }
     },
@@ -491,8 +497,6 @@
 
       if (!this.useEncryptEverything_ && !this.usePassphrase_)
         $('basic-encryption-option').checked = true;
-
-      $('confirm-everything-ok').focus();
     },
 
     /**
@@ -558,7 +562,6 @@
           !(args.usePassphrase && args.passphraseFailed);
 
       $('sync-passphrase-warning').hidden = false;
-      $('passphrase').focus();
     },
 
     /**
@@ -572,7 +575,6 @@
       $('customize-sync-preferences').hidden = false;
 
       $('sync-custom-passphrase-container').hidden = false;
-      $('sync-custom-passphrase').hidden = true;
       $('sync-new-encryption-section-container').hidden = false;
       $('customize-sync-encryption-new').hidden = false;
 
@@ -582,10 +584,6 @@
       this.setDataTypeCheckboxesEnabled_(
           index == DataTypeSelection.CHOOSE_WHAT_TO_SYNC);
 
-      // The passphrase input may need to take over focus from the OK button, so
-      // set focus before that logic.
-      $('choose-datatypes-ok').focus();
-
       if (args && args.showPassphrase) {
         this.showPassphraseContainer_(args);
       } else {
diff --git a/chrome/browser/resources/translate.js b/chrome/browser/resources/translate.js
index 773189e..90e5a54 100644
--- a/chrome/browser/resources/translate.js
+++ b/chrome/browser/resources/translate.js
@@ -9,7 +9,11 @@
 
 var cr = {};
 
-cr.googleTranslate = (function(key) {
+/**
+ * An object to provide functions to interact with the Translate library.
+ * @type {object}
+ */
+cr.googleTranslate = (function() {
   /**
    * The Translate Element library's instance.
    * @type {object}
@@ -74,55 +78,6 @@
    */
   var endTime = 0.0;
 
-  // Create another call point for appendChild.
-  var head = document.head;
-  head._appendChild = head.appendChild;
-
-  // TODO(toyoshim): This is temporary solution and will be removed once server
-  // side fixed to use https always. See also, http://crbug.com/164584 .
-  function forceToHttps(url) {
-    if (url.indexOf('http:') == 0)
-      return url.replace('http', 'https');
-
-    return url;
-  }
-
-  /**
-   * Inserts CSS element into the main world.
-   * @param {Object} child Link element for CSS.
-   */
-  function insertCSS(child) {
-    child.href = forceToHttps(child.href);
-    head._appendChild(child);
-  }
-
-  /**
-   * Inserts JavaScript into the isolated world.
-   * @param {string} src JavaScript URL.
-   */
-  function insertJS(src) {
-    var xhr = new XMLHttpRequest();
-    xhr.open('GET', forceToHttps(src), true);
-    xhr.onreadystatechange = function() {
-      if (this.readyState != this.DONE || this.status != 200)
-        return;
-      eval(this.responseText);
-    }
-    xhr.send();
-  }
-
-  /**
-   * Alternate implementation of appendChild. In the isolated world, appendChild
-   * for the first head element is replaced with this function in order to make
-   * CSS link tag and script tag injection work fine like the main world.
-   */
-  head.appendChild = function(child) {
-    if (child.type == 'text/css')
-      insertCSS(child);
-    else
-      insertJS(child.src);
-  };
-
   function checkLibReady() {
     if (lib.isAvailable()) {
       readyTime = performance.now();
@@ -239,7 +194,14 @@
       if (!libReady)
         return false;
       startTime = performance.now();
-      lib.translatePage(originalLang, targetLang, onTranslateProgress);
+      try {
+        lib.translatePage(originalLang, targetLang, onTranslateProgress);
+      } catch (err) {
+        console.error('Translate: ' + err);
+        // TODO(toyoshim): Check if it shows an error notification.
+        error = true;
+        return false;
+      }
       return true;
     },
 
@@ -259,16 +221,56 @@
       loadedTime = performance.now();
       try {
         lib = google.translate.TranslateService({
-          'key': key,
+          // translateApiKey is predefined by translate_script.cc.
+          'key': translateApiKey,
           'useSecureConnection': true
         });
+        translateApiKey = undefined;
       } catch (err) {
         error = true;
+        translateApiKey = undefined;
         return;
       }
       // The TranslateService is not available immediately as it needs to start
       // Flash.  Let's wait until it is ready.
       checkLibReady();
+    },
+
+    /**
+     * Entry point called by the Translate Element when it want to load an
+     * external CSS resource into the page.
+     * @param {string} url URL of an external CSS resource to load.
+     */
+    onLoadCSS: function(url) {
+      var element = document.createElement('link');
+      element.type = 'text/css';
+      element.rel = 'stylesheet';
+      element.charset = 'UTF-8';
+      element.href = url;
+      document.head.appendChild(element);
+    },
+
+    /**
+     * Entry point called by the Translate Element when it want to load and run
+     * an external JavaScript on the page.
+     * @param {string} url URL of an external JavaScript to load.
+     */
+    onLoadJavascript: function(url) {
+      // securityOrigin is predefined by translate_script.cc.
+      if (url.indexOf(securityOrigin) != 0) {
+        // TODO(toyoshim): Handle this error to show an error notification.
+        console.error('Translate: ' + url + ' is not allowed to load.');
+        error = true;
+        return;
+      }
+      var xhr = new XMLHttpRequest();
+      xhr.open('GET', url, true);
+      xhr.onreadystatechange = function() {
+        if (this.readyState != this.DONE || this.status != 200)
+          return;
+        eval(this.responseText);
+      }
+      xhr.send();
     }
   };
-})/* Calling code '(|key|);' will be appended by TranslateHelper in C++ here. */
+})();
diff --git a/chrome/browser/resources/translate_internals/prefs.html b/chrome/browser/resources/translate_internals/prefs.html
index f39b242..5cd07b8 100644
--- a/chrome/browser/resources/translate_internals/prefs.html
+++ b/chrome/browser/resources/translate_internals/prefs.html
@@ -25,7 +25,7 @@
     <p id="prefs-supported-languages-last-updated">Last updated: <span></span></p>
     <ul id="prefs-supported-languages-languages"></ul>
   </section>
-<if expr="not pp_ifdef('ios')">
+<if expr="not is_ios">
   <section id="prefs-cld-version">
     <h2>CLD Version</h2>
     <p i18n-content="cld-version"></p>
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 7ad5e86..c93be27 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -1036,10 +1036,6 @@
 
 void SafeBrowsingBlockingPageV2::PopulateMalwareStringDictionary(
     DictionaryValue* strings) {
-  std::string diagnostic_link = base::StringPrintf(kSbDiagnosticHtml,
-      l10n_util::GetStringUTF8(
-        IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE).c_str());
-
   // Check to see if we're blocking the main page, or a sub-resource on the
   // main page.
   string16 headline, description1, description2, description3;
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index efb1153..b336ea9 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -154,7 +154,9 @@
 
 class FakeSafeBrowsingService : public SafeBrowsingService {
  public:
-  FakeSafeBrowsingService() { }
+  FakeSafeBrowsingService()
+      : fake_database_manager_(),
+        fake_ui_manager_() { }
 
   // Returned pointer has the same lifespan as the database_manager_ refcounted
   // object.
@@ -261,7 +263,7 @@
 
 class TestMalwareDetailsFactory : public MalwareDetailsFactory {
  public:
-  TestMalwareDetailsFactory() { }
+  TestMalwareDetailsFactory() : details_() { }
   virtual ~TestMalwareDetailsFactory() { }
 
   virtual MalwareDetails* CreateMalwareDetails(
@@ -477,7 +479,7 @@
     EXPECT_TRUE(report.complete());
   }
 
-  void MalwareRedirectCancelAndProceed(const std::string open_function) {
+  void MalwareRedirectCancelAndProceed(const std::string& open_function) {
     GURL load_url = test_server()->GetURL(
         "files/safe_browsing/interstitial_cancel.html");
     GURL malware_url("http://localhost/files/safe_browsing/malware.html");
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 66fef8a..0ec9c9a 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -69,7 +69,7 @@
   const TemplateURL* default_provider =
       template_url_service->GetDefaultSearchProvider();
   return default_provider &&
-      (TemplateURLPrepopulateData::GetEngineType(default_provider->url()) ==
+      (TemplateURLPrepopulateData::GetEngineType(*default_provider) ==
        SEARCH_ENGINE_GOOGLE);
 }
 
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc
index 1328ffe..f42fafb 100644
--- a/chrome/browser/search/search.cc
+++ b/chrome/browser/search/search.cc
@@ -62,6 +62,7 @@
 const char kUseRemoteNTPOnStartupFlagName[] = "use_remote_ntp_on_startup";
 const char kShowNtpFlagName[] = "show_ntp";
 const char kRecentTabsOnNTPFlagName[] = "show_recent_tabs";
+const char kUseCacheableNTP[] = "use_cacheable_ntp";
 
 // Constants for the field trial name and group prefix.
 const char kInstantExtendedFieldTrialName[] = "InstantExtended";
@@ -120,6 +121,21 @@
   return GURL(ref.ReplaceSearchTerms(search_terms_args));
 }
 
+GURL GetNewTabPageURL(Profile* profile) {
+  if (!ShouldUseCacheableNTP())
+    return GURL();
+
+  if (!profile)
+    return GURL();
+
+  TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
+  if (!template_url)
+    return GURL();
+
+  return TemplateURLRefToGURL(template_url->new_tab_url_ref(),
+                              kDisableStartMargin, false);
+}
+
 bool MatchesOrigin(const GURL& my_url, const GURL& other_url) {
   return my_url.host() == other_url.host() &&
          my_url.port() == other_url.port() &&
@@ -191,13 +207,6 @@
        google_util::StartsWithCommandLineGoogleBaseURL(url));
 }
 
-// Returns true if |url| matches --instant-new-tab-url.
-bool IsCommandLineInstantNTPURL(const GURL& url) {
-  const GURL ntp_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-      switches::kInstantNewTabURL));
-  return ntp_url.is_valid() && MatchesOriginAndPath(ntp_url, url);
-}
-
 // Returns true if |url| can be used as an Instant URL for |profile|.
 bool IsInstantURL(const GURL& url, Profile* profile) {
   if (!IsInstantExtendedAPIEnabled())
@@ -206,7 +215,8 @@
   if (!url.is_valid())
     return false;
 
-  if (IsCommandLineInstantNTPURL(url))
+  const GURL new_tab_url(GetNewTabPageURL(profile));
+  if (new_tab_url.is_valid() && MatchesOriginAndPath(url, new_tab_url))
     return true;
 
   TemplateURL* template_url = GetDefaultSearchProviderTemplateURL(profile);
@@ -388,8 +398,10 @@
       entry->GetVirtualURL() == GetLocalInstantURL(profile))
     return GetSearchTermsImpl(contents, entry).empty();
 
+  GURL new_tab_url(GetNewTabPageURL(profile));
   return entry->GetVirtualURL() == GURL(chrome::kChromeUINewTabURL) &&
-      IsCommandLineInstantNTPURL(entry->GetURL());
+      new_tab_url.is_valid() &&
+      MatchesOriginAndPath(entry->GetURL(), new_tab_url);
 }
 
 bool IsSuggestPrefEnabled(Profile* profile) {
@@ -458,11 +470,20 @@
   return false;
 }
 
+bool ShouldUseCacheableNTP() {
+  FieldTrialFlags flags;
+  if (GetFieldTrialInfo(
+          base::FieldTrialList::FindFullName(kInstantExtendedFieldTrialName),
+          &flags, NULL)) {
+    return GetBoolValueForFlagWithDefault(kUseCacheableNTP, false, flags);
+  }
+  return false;
+}
+
 bool ShouldShowInstantNTP() {
-  // If the instant-new-tab-url flag is set, we'll always just load the NTP
-  // directly instead of preloading contents using InstantNTP.
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kInstantNewTabURL))
+  // If using the cacheable NTP, load the NTP directly instead of preloading its
+  // contents using InstantNTP.
+  if (ShouldUseCacheableNTP())
     return false;
 
   FieldTrialFlags flags;
@@ -570,12 +591,12 @@
       url->host() != chrome::kChromeUINewTabHost)
     return false;
 
-  const GURL ntp_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-      switches::kInstantNewTabURL));
-  if (!ntp_url.is_valid())
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  GURL new_tab_url(GetNewTabPageURL(profile));
+  if (!new_tab_url.is_valid())
     return false;
 
-  *url = ntp_url;
+  *url = new_tab_url;
   return true;
 }
 
@@ -584,9 +605,9 @@
   if (!IsInstantExtendedAPIEnabled())
     return false;
 
-  const GURL ntp_url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-      switches::kInstantNewTabURL));
-  if (!MatchesOriginAndPath(ntp_url, *url))
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  GURL new_tab_url(GetNewTabPageURL(profile));
+  if (!new_tab_url.is_valid() || !MatchesOriginAndPath(new_tab_url, *url))
     return false;
 
   *url = GURL(chrome::kChromeUINewTabURL);
diff --git a/chrome/browser/search/search.h b/chrome/browser/search/search.h
index 094f660..5888529 100644
--- a/chrome/browser/search/search.h
+++ b/chrome/browser/search/search.h
@@ -126,6 +126,10 @@
 // to always show the remote NTP on browser startup.
 bool ShouldPreferRemoteNTPOnStartup();
 
+// Returns true if the cacheable NTP should be shown and false if not.
+// Exposed for testing.
+bool ShouldUseCacheableNTP();
+
 // Returns true if the Instant NTP should be shown and false if not.
 bool ShouldShowInstantNTP();
 
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index b2ba58f..35de837 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -245,6 +245,7 @@
     data.SetURL("http://foo.com/url?bar={searchTerms}");
     data.instant_url = "http://foo.com/instant?"
         "{google:omniboxStartMarginParameter}foo=foo#foo=foo&strk";
+    data.new_tab_url = "http://foo.com/newtab?strk";
     data.alternate_urls.push_back("http://foo.com/alt#quux={searchTerms}");
     data.search_terms_replacement_key = "strk";
 
@@ -666,17 +667,29 @@
 TEST_F(SearchTest, ShouldShowInstantNTP_DisabledViaFinch) {
   EnableInstantExtendedAPIForTesting();
   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
-                                                     "Group1 show_ntp:0"));
+      "Group1 show_ntp:0"));
   EXPECT_FALSE(ShouldShowInstantNTP());
 }
 
-TEST_F(SearchTest, ShouldShowInstantNTP_DisabledByInstantNewTabURLSwitch) {
+TEST_F(SearchTest, ShouldShowInstantNTP_DisabledByUseCacheableNTPFinchFlag) {
   EnableInstantExtendedAPIForTesting();
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kInstantNewTabURL, "http://example.com/newtab");
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+      "Group1 use_cacheable_ntp:1"));
   EXPECT_FALSE(ShouldShowInstantNTP());
 }
 
+TEST_F(SearchTest, ShouldUseCacheableNTP_Default) {
+  EnableInstantExtendedAPIForTesting();
+  EXPECT_FALSE(ShouldUseCacheableNTP());
+}
+
+TEST_F(SearchTest, ShouldUseCacheableNTP_EnabledViaFinch) {
+  EnableInstantExtendedAPIForTesting();
+  ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial("InstantExtended",
+      "Group1 use_cacheable_ntp:1"));
+  EXPECT_TRUE(ShouldUseCacheableNTP());
+}
+
 TEST_F(SearchTest, IsNTPURL) {
   GURL invalid_url;
   GURL ntp_url(chrome::kChromeUINewTabURL);
diff --git a/chrome/browser/search_engines/prepopulated_engines.json b/chrome/browser/search_engines/prepopulated_engines.json
index a3d199a..e0a8daa 100644
--- a/chrome/browser/search_engines/prepopulated_engines.json
+++ b/chrome/browser/search_engines/prepopulated_engines.json
@@ -26,7 +26,7 @@
 
     // Increment this if you change the data in ways that mean users with
     // existing data should get a new version.
-    "kCurrentDataVersion": 61
+    "kCurrentDataVersion": 62
   },
 
   // The following engines are included in country lists and are added to the
@@ -490,6 +490,7 @@
       "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}",
       "image_url": "{google:baseURL}searchbyimage/upload",
+      "new_tab_url": "{google:baseURL}newtab?{google:RLZ}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}ie={inputEncoding}",
       "image_url_post_params": "encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource}",
       "alternate_urls": [
         "{google:baseURL}#q={searchTerms}",
diff --git a/chrome/browser/search_engines/prepopulated_engines_schema.json b/chrome/browser/search_engines/prepopulated_engines_schema.json
index 893e565..eeee30d 100644
--- a/chrome/browser/search_engines/prepopulated_engines_schema.json
+++ b/chrome/browser/search_engines/prepopulated_engines_schema.json
@@ -28,6 +28,8 @@
     { "field": "instant_url", "type": "string", "optional": true },
     // If omitted, this engine does not support image search.
     { "field": "image_url", "type": "string", "optional": true },
+    // If omitted, this engine does not support rendering a new tab page.
+    { "field": "new_tab_url", "type": "string", "optional": true },
     // The followings are post parameters for the corresponding search URL.
     // If omitted, a GET request will be sent when using the corresponding
     // search URL. Otherwise, a POST request will be sent.
diff --git a/chrome/browser/search_engines/template_url.cc b/chrome/browser/search_engines/template_url.cc
index 3d0bea9..a0a7c63 100644
--- a/chrome/browser/search_engines/template_url.cc
+++ b/chrome/browser/search_engines/template_url.cc
@@ -238,6 +238,7 @@
     case SUGGEST: return owner_->suggestions_url();
     case INSTANT: return owner_->instant_url();
     case IMAGE:   return owner_->image_url();
+    case NEW_TAB: return owner_->new_tab_url();
     case INDEXED: return owner_->GetURL(index_in_owner_);
     default:      NOTREACHED(); return std::string();  // NOLINT
   }
@@ -249,6 +250,7 @@
     case SEARCH:  return owner_->search_url_post_params();
     case SUGGEST: return owner_->suggestions_url_post_params();
     case INSTANT: return owner_->instant_url_post_params();
+    case NEW_TAB: return std::string();
     case IMAGE:   return owner_->image_url_post_params();
     default:      NOTREACHED(); return std::string();  // NOLINT
   }
@@ -1009,7 +1011,8 @@
                            TemplateURLRef::SUGGEST),
       instant_url_ref_(this,
                        TemplateURLRef::INSTANT),
-      image_url_ref_(this, TemplateURLRef::IMAGE) {
+      image_url_ref_(this, TemplateURLRef::IMAGE),
+      new_tab_url_ref_(this, TemplateURLRef::NEW_TAB) {
   SetPrepopulateId(data_.prepopulate_id);
 
   if (data_.search_terms_replacement_key ==
diff --git a/chrome/browser/search_engines/template_url.h b/chrome/browser/search_engines/template_url.h
index 1d874bb..0a06d03 100644
--- a/chrome/browser/search_engines/template_url.h
+++ b/chrome/browser/search_engines/template_url.h
@@ -50,6 +50,7 @@
     SUGGEST,
     INSTANT,
     IMAGE,
+    NEW_TAB,
     INDEXED
   };
 
@@ -408,6 +409,7 @@
   std::string suggestions_url;
   std::string instant_url;
   std::string image_url;
+  std::string new_tab_url;
 
   // The following post_params are comma-separated lists used to specify the
   // post parameters for the corresponding URL.
@@ -525,6 +527,7 @@
   const std::string& suggestions_url() const { return data_.suggestions_url; }
   const std::string& instant_url() const { return data_.instant_url; }
   const std::string& image_url() const { return data_.image_url; }
+  const std::string& new_tab_url() const { return data_.new_tab_url; }
   const std::string& search_url_post_params() const {
     return data_.search_url_post_params;
   }
@@ -579,6 +582,7 @@
   }
   const TemplateURLRef& instant_url_ref() const { return instant_url_ref_; }
   const TemplateURLRef& image_url_ref() const { return image_url_ref_; }
+  const TemplateURLRef& new_tab_url_ref() const { return new_tab_url_ref_; }
 
   // Returns true if |url| supports replacement.
   bool SupportsReplacement() const;
@@ -700,6 +704,7 @@
   TemplateURLRef suggestions_url_ref_;
   TemplateURLRef instant_url_ref_;
   TemplateURLRef image_url_ref_;
+  TemplateURLRef new_tab_url_ref_;
 
   // TODO(sky): Add date last parsed OSD file.
 
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.cc b/chrome/browser/search_engines/template_url_prepopulate_data.cc
index 064b65e..652ecf5 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data.cc
@@ -1077,6 +1077,7 @@
     const base::StringPiece& suggest_url,
     const base::StringPiece& instant_url,
     const base::StringPiece& image_url,
+    const base::StringPiece& new_tab_url,
     const base::StringPiece& search_url_post_params,
     const base::StringPiece& suggest_url_post_params,
     const base::StringPiece& instant_url_post_params,
@@ -1095,6 +1096,7 @@
   data.suggestions_url = suggest_url.as_string();
   data.instant_url = instant_url.as_string();
   data.image_url = image_url.as_string();
+  data.new_tab_url = new_tab_url.as_string();
   data.search_url_post_params = search_url_post_params.as_string();
   data.suggestions_url_post_params = suggest_url_post_params.as_string();
   data.instant_url_post_params = instant_url_post_params.as_string();
@@ -1148,6 +1150,7 @@
       std::string suggest_url;
       std::string instant_url;
       std::string image_url;
+      std::string new_tab_url;
       std::string search_url_post_params;
       std::string suggest_url_post_params;
       std::string instant_url_post_params;
@@ -1158,6 +1161,7 @@
       engine->GetString("suggest_url", &suggest_url);
       engine->GetString("instant_url", &instant_url);
       engine->GetString("image_url", &image_url);
+      engine->GetString("new_tab_url", &new_tab_url);
       engine->GetString("search_url_post_params", &search_url_post_params);
       engine->GetString("suggest_url_post_params", &suggest_url_post_params);
       engine->GetString("instant_url_post_params", &instant_url_post_params);
@@ -1166,7 +1170,7 @@
       engine->GetString("search_terms_replacement_key",
           &search_terms_replacement_key);
       t_urls->push_back(MakePrepopulatedTemplateURL(profile, name, keyword,
-          search_url, suggest_url, instant_url, image_url,
+          search_url, suggest_url, instant_url, image_url, new_tab_url,
           search_url_post_params, suggest_url_post_params,
           instant_url_post_params, image_url_post_params,
           favicon_url, encoding, *alternate_urls, search_terms_replacement_key,
@@ -1188,10 +1192,11 @@
 
   return MakePrepopulatedTemplateURL(profile, WideToUTF16(engine.name),
       WideToUTF16(engine.keyword), engine.search_url, engine.suggest_url,
-      engine.instant_url, engine.image_url, engine.search_url_post_params,
-      engine.suggest_url_post_params, engine.instant_url_post_params,
-      engine.image_url_post_params, engine.favicon_url, engine.encoding,
-      alternate_urls, engine.search_terms_replacement_key, engine.id);
+      engine.instant_url, engine.image_url, engine.new_tab_url,
+      engine.search_url_post_params, engine.suggest_url_post_params,
+      engine.instant_url_post_params, engine.image_url_post_params,
+      engine.favicon_url, engine.encoding, alternate_urls,
+      engine.search_terms_replacement_key, engine.id);
 }
 
 bool SameDomain(const GURL& given_url, const GURL& prepopulated_url) {
@@ -1287,24 +1292,22 @@
   return default_search_provider;
 }
 
-SearchEngineType GetEngineType(const std::string& url) {
+SearchEngineType GetEngineType(const TemplateURL& url) {
   // Restricted to UI thread because ReplaceSearchTerms() is so restricted.
   using content::BrowserThread;
   DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
          BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  // We may get a valid URL, or we may get the Google prepopulate URL which
-  // can't be converted directly to a GURL.  To handle the latter, we first
-  // construct a TemplateURL from the provided |url|, then call
-  // ReplaceSearchTerms().  This should return a valid URL even when the input
-  // has Google base URLs.
-  TemplateURLData data;
-  data.SetURL(url);
-  TemplateURL turl(NULL, data);
-  GURL as_gurl(turl.url_ref().ReplaceSearchTerms(
-      TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("x"))));
-  if (!as_gurl.is_valid())
-    return SEARCH_ENGINE_OTHER;
+  // By calling ReplaceSearchTerms, we ensure that even TemplateURLs whose URLs
+  // can't be directly inspected (e.g. due to containing {google:baseURL}) can
+  // be converted to GURLs we can look at.
+  GURL gurl(url.url_ref().ReplaceSearchTerms(TemplateURLRef::SearchTermsArgs(
+      ASCIIToUTF16("x"))));
+  return gurl.is_valid() ? GetEngineType(gurl) : SEARCH_ENGINE_OTHER;
+}
+
+SearchEngineType GetEngineType(const GURL& url) {
+  DCHECK(url.is_valid());
 
   // Check using TLD+1s, in order to more aggressively match search engine types
   // for data imported from other browsers.
@@ -1312,19 +1315,19 @@
   // First special-case Google, because the prepopulate URL for it will not
   // convert to a GURL and thus won't have an origin.  Instead see if the
   // incoming URL's host is "[*.]google.<TLD>".
-  if (google_util::IsGoogleHostname(as_gurl.host(),
+  if (google_util::IsGoogleHostname(url.host(),
                                     google_util::DISALLOW_SUBDOMAIN))
     return google.type;
 
   // Now check the rest of the prepopulate data.
   for (size_t i = 0; i < arraysize(kAllEngines); ++i) {
     // First check the main search URL.
-    if (SameDomain(as_gurl, GURL(kAllEngines[i]->search_url)))
+    if (SameDomain(url, GURL(kAllEngines[i]->search_url)))
       return kAllEngines[i]->type;
 
     // Then check the alternate URLs.
     for (size_t j = 0; j < kAllEngines[i]->alternate_urls_size; ++j) {
-      if (SameDomain(as_gurl, GURL(kAllEngines[i]->alternate_urls[j])))
+      if (SameDomain(url, GURL(kAllEngines[i]->alternate_urls[j])))
         return kAllEngines[i]->type;
     }
   }
@@ -1333,12 +1336,10 @@
 }
 
 GURL GetLogoURL(const TemplateURL& template_url, LogoSize size) {
-  if (GetEngineType(template_url.url()) == SEARCH_ENGINE_GOOGLE) {
-    return GURL((size == LOGO_200_PERCENT) ?
-                google_logos.logo_200_percent_url :
-                google_logos.logo_100_percent_url);
-  }
-  return GURL();
+  if (GetEngineType(template_url) != SEARCH_ENGINE_GOOGLE)
+    return GURL();
+  return GURL((size == LOGO_200_PERCENT) ?
+      google_logos.logo_200_percent_url : google_logos.logo_100_percent_url);
 }
 
 }  // namespace TemplateURLPrepopulateData
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data.h b/chrome/browser/search_engines/template_url_prepopulate_data.h
index ef07dd0..40f6cd7 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data.h
+++ b/chrome/browser/search_engines/template_url_prepopulate_data.h
@@ -61,12 +61,17 @@
 // not used.
 TemplateURL* GetPrepopulatedDefaultSearch(Profile* profile);
 
-// Returns the type of the matching engine, or SEARCH_ENGINE_OTHER if no engines
-// match.  This uses same-origin checks unless the |url| is a Google seach URL,
-// in which case we'll identify any valid Google hostname as "Google".
+// Returns the type of the provided engine, or SEARCH_ENGINE_OTHER if no engines
+// match.  This checks the TLD+1 for the most part, but will report the type as
+// SEARCH_ENGINE_GOOGLE for any hostname that causes
+// google_util::IsGoogleHostname() to return true.
 //
 // NOTE: Must be called on the UI thread.
-SearchEngineType GetEngineType(const std::string& url);
+SearchEngineType GetEngineType(const TemplateURL& template_url);
+
+// Like the above, but takes a GURL which is expected to represent a search URL.
+// This may be called on any thread.
+SearchEngineType GetEngineType(const GURL& url);
 
 // Returns the logo at the specified |size| for |template_url|.  If no logo is
 // known, this will return an empty GURL.
diff --git a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
index d1f69fd..d2e4db4 100644
--- a/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
+++ b/chrome/browser/search_engines/template_url_prepopulate_data_unittest.cc
@@ -19,62 +19,70 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
-typedef testing::Test TemplateURLPrepopulateDataTest;
+namespace {
+SearchEngineType GetEngineType(const std::string& url) {
+  TemplateURLData data;
+  data.SetURL(url);
+  return TemplateURLPrepopulateData::GetEngineType(TemplateURL(NULL, data));
+}
+}  // namespace
 
-const int kCountryIds[] = {
-    'A'<<8|'D', 'A'<<8|'E', 'A'<<8|'F', 'A'<<8|'G', 'A'<<8|'I',
-    'A'<<8|'L', 'A'<<8|'M', 'A'<<8|'N', 'A'<<8|'O', 'A'<<8|'Q',
-    'A'<<8|'R', 'A'<<8|'S', 'A'<<8|'T', 'A'<<8|'U', 'A'<<8|'W',
-    'A'<<8|'X', 'A'<<8|'Z', 'B'<<8|'A', 'B'<<8|'B', 'B'<<8|'D',
-    'B'<<8|'E', 'B'<<8|'F', 'B'<<8|'G', 'B'<<8|'H', 'B'<<8|'I',
-    'B'<<8|'J', 'B'<<8|'M', 'B'<<8|'N', 'B'<<8|'O', 'B'<<8|'R',
-    'B'<<8|'S', 'B'<<8|'T', 'B'<<8|'V', 'B'<<8|'W', 'B'<<8|'Y',
-    'B'<<8|'Z', 'C'<<8|'A', 'C'<<8|'C', 'C'<<8|'D', 'C'<<8|'F',
-    'C'<<8|'G', 'C'<<8|'H', 'C'<<8|'I', 'C'<<8|'K', 'C'<<8|'L',
-    'C'<<8|'M', 'C'<<8|'N', 'C'<<8|'O', 'C'<<8|'R', 'C'<<8|'U',
-    'C'<<8|'V', 'C'<<8|'X', 'C'<<8|'Y', 'C'<<8|'Z', 'D'<<8|'E',
-    'D'<<8|'J', 'D'<<8|'K', 'D'<<8|'M', 'D'<<8|'O', 'D'<<8|'Z',
-    'E'<<8|'C', 'E'<<8|'E', 'E'<<8|'G', 'E'<<8|'R', 'E'<<8|'S',
-    'E'<<8|'T', 'F'<<8|'I', 'F'<<8|'J', 'F'<<8|'K', 'F'<<8|'M',
-    'F'<<8|'O', 'F'<<8|'R', 'G'<<8|'A', 'G'<<8|'B', 'G'<<8|'D',
-    'G'<<8|'E', 'G'<<8|'F', 'G'<<8|'G', 'G'<<8|'H', 'G'<<8|'I',
-    'G'<<8|'L', 'G'<<8|'M', 'G'<<8|'N', 'G'<<8|'P', 'G'<<8|'Q',
-    'G'<<8|'R', 'G'<<8|'S', 'G'<<8|'T', 'G'<<8|'U', 'G'<<8|'W',
-    'G'<<8|'Y', 'H'<<8|'K', 'H'<<8|'M', 'H'<<8|'N', 'H'<<8|'R',
-    'H'<<8|'T', 'H'<<8|'U', 'I'<<8|'D', 'I'<<8|'E', 'I'<<8|'L',
-    'I'<<8|'M', 'I'<<8|'N', 'I'<<8|'O', 'I'<<8|'P', 'I'<<8|'Q',
-    'I'<<8|'R', 'I'<<8|'S', 'I'<<8|'T', 'J'<<8|'E', 'J'<<8|'M',
-    'J'<<8|'O', 'J'<<8|'P', 'K'<<8|'E', 'K'<<8|'G', 'K'<<8|'H',
-    'K'<<8|'I', 'K'<<8|'M', 'K'<<8|'N', 'K'<<8|'P', 'K'<<8|'R',
-    'K'<<8|'W', 'K'<<8|'Y', 'K'<<8|'Z', 'L'<<8|'A', 'L'<<8|'B',
-    'L'<<8|'C', 'L'<<8|'I', 'L'<<8|'K', 'L'<<8|'R', 'L'<<8|'S',
-    'L'<<8|'T', 'L'<<8|'U', 'L'<<8|'V', 'L'<<8|'Y', 'M'<<8|'A',
-    'M'<<8|'C', 'M'<<8|'D', 'M'<<8|'E', 'M'<<8|'G', 'M'<<8|'H',
-    'M'<<8|'K', 'M'<<8|'L', 'M'<<8|'M', 'M'<<8|'N', 'M'<<8|'O',
-    'M'<<8|'P', 'M'<<8|'Q', 'M'<<8|'R', 'M'<<8|'S', 'M'<<8|'T',
-    'M'<<8|'U', 'M'<<8|'V', 'M'<<8|'W', 'M'<<8|'X', 'M'<<8|'Y',
-    'M'<<8|'Z', 'N'<<8|'A', 'N'<<8|'C', 'N'<<8|'E', 'N'<<8|'F',
-    'N'<<8|'G', 'N'<<8|'I', 'N'<<8|'L', 'N'<<8|'O', 'N'<<8|'P',
-    'N'<<8|'R', 'N'<<8|'U', 'N'<<8|'Z', 'O'<<8|'M', 'P'<<8|'A',
-    'P'<<8|'E', 'P'<<8|'F', 'P'<<8|'G', 'P'<<8|'H', 'P'<<8|'K',
-    'P'<<8|'L', 'P'<<8|'M', 'P'<<8|'N', 'P'<<8|'R', 'P'<<8|'S',
-    'P'<<8|'T', 'P'<<8|'W', 'P'<<8|'Y', 'Q'<<8|'A', 'R'<<8|'E',
-    'R'<<8|'O', 'R'<<8|'S', 'R'<<8|'U', 'R'<<8|'W', 'S'<<8|'A',
-    'S'<<8|'B', 'S'<<8|'C', 'S'<<8|'D', 'S'<<8|'E', 'S'<<8|'G',
-    'S'<<8|'H', 'S'<<8|'I', 'S'<<8|'J', 'S'<<8|'K', 'S'<<8|'L',
-    'S'<<8|'M', 'S'<<8|'N', 'S'<<8|'O', 'S'<<8|'R', 'S'<<8|'T',
-    'S'<<8|'V', 'S'<<8|'Y', 'S'<<8|'Z', 'T'<<8|'C', 'T'<<8|'D',
-    'T'<<8|'F', 'T'<<8|'G', 'T'<<8|'H', 'T'<<8|'J', 'T'<<8|'K',
-    'T'<<8|'L', 'T'<<8|'M', 'T'<<8|'N', 'T'<<8|'O', 'T'<<8|'R',
-    'T'<<8|'T', 'T'<<8|'V', 'T'<<8|'W', 'T'<<8|'Z', 'U'<<8|'A',
-    'U'<<8|'G', 'U'<<8|'M', 'U'<<8|'S', 'U'<<8|'Y', 'U'<<8|'Z',
-    'V'<<8|'A', 'V'<<8|'C', 'V'<<8|'E', 'V'<<8|'G', 'V'<<8|'I',
-    'V'<<8|'N', 'V'<<8|'U', 'W'<<8|'F', 'W'<<8|'S', 'Y'<<8|'E',
-    'Y'<<8|'T', 'Z'<<8|'A', 'Z'<<8|'M', 'Z'<<8|'W', -1 };
+typedef testing::Test TemplateURLPrepopulateDataTest;
 
 // Verifies the set of prepopulate data doesn't contain entries with duplicate
 // ids.
 TEST(TemplateURLPrepopulateDataTest, UniqueIDs) {
+  const int kCountryIds[] = {
+      'A'<<8|'D', 'A'<<8|'E', 'A'<<8|'F', 'A'<<8|'G', 'A'<<8|'I',
+      'A'<<8|'L', 'A'<<8|'M', 'A'<<8|'N', 'A'<<8|'O', 'A'<<8|'Q',
+      'A'<<8|'R', 'A'<<8|'S', 'A'<<8|'T', 'A'<<8|'U', 'A'<<8|'W',
+      'A'<<8|'X', 'A'<<8|'Z', 'B'<<8|'A', 'B'<<8|'B', 'B'<<8|'D',
+      'B'<<8|'E', 'B'<<8|'F', 'B'<<8|'G', 'B'<<8|'H', 'B'<<8|'I',
+      'B'<<8|'J', 'B'<<8|'M', 'B'<<8|'N', 'B'<<8|'O', 'B'<<8|'R',
+      'B'<<8|'S', 'B'<<8|'T', 'B'<<8|'V', 'B'<<8|'W', 'B'<<8|'Y',
+      'B'<<8|'Z', 'C'<<8|'A', 'C'<<8|'C', 'C'<<8|'D', 'C'<<8|'F',
+      'C'<<8|'G', 'C'<<8|'H', 'C'<<8|'I', 'C'<<8|'K', 'C'<<8|'L',
+      'C'<<8|'M', 'C'<<8|'N', 'C'<<8|'O', 'C'<<8|'R', 'C'<<8|'U',
+      'C'<<8|'V', 'C'<<8|'X', 'C'<<8|'Y', 'C'<<8|'Z', 'D'<<8|'E',
+      'D'<<8|'J', 'D'<<8|'K', 'D'<<8|'M', 'D'<<8|'O', 'D'<<8|'Z',
+      'E'<<8|'C', 'E'<<8|'E', 'E'<<8|'G', 'E'<<8|'R', 'E'<<8|'S',
+      'E'<<8|'T', 'F'<<8|'I', 'F'<<8|'J', 'F'<<8|'K', 'F'<<8|'M',
+      'F'<<8|'O', 'F'<<8|'R', 'G'<<8|'A', 'G'<<8|'B', 'G'<<8|'D',
+      'G'<<8|'E', 'G'<<8|'F', 'G'<<8|'G', 'G'<<8|'H', 'G'<<8|'I',
+      'G'<<8|'L', 'G'<<8|'M', 'G'<<8|'N', 'G'<<8|'P', 'G'<<8|'Q',
+      'G'<<8|'R', 'G'<<8|'S', 'G'<<8|'T', 'G'<<8|'U', 'G'<<8|'W',
+      'G'<<8|'Y', 'H'<<8|'K', 'H'<<8|'M', 'H'<<8|'N', 'H'<<8|'R',
+      'H'<<8|'T', 'H'<<8|'U', 'I'<<8|'D', 'I'<<8|'E', 'I'<<8|'L',
+      'I'<<8|'M', 'I'<<8|'N', 'I'<<8|'O', 'I'<<8|'P', 'I'<<8|'Q',
+      'I'<<8|'R', 'I'<<8|'S', 'I'<<8|'T', 'J'<<8|'E', 'J'<<8|'M',
+      'J'<<8|'O', 'J'<<8|'P', 'K'<<8|'E', 'K'<<8|'G', 'K'<<8|'H',
+      'K'<<8|'I', 'K'<<8|'M', 'K'<<8|'N', 'K'<<8|'P', 'K'<<8|'R',
+      'K'<<8|'W', 'K'<<8|'Y', 'K'<<8|'Z', 'L'<<8|'A', 'L'<<8|'B',
+      'L'<<8|'C', 'L'<<8|'I', 'L'<<8|'K', 'L'<<8|'R', 'L'<<8|'S',
+      'L'<<8|'T', 'L'<<8|'U', 'L'<<8|'V', 'L'<<8|'Y', 'M'<<8|'A',
+      'M'<<8|'C', 'M'<<8|'D', 'M'<<8|'E', 'M'<<8|'G', 'M'<<8|'H',
+      'M'<<8|'K', 'M'<<8|'L', 'M'<<8|'M', 'M'<<8|'N', 'M'<<8|'O',
+      'M'<<8|'P', 'M'<<8|'Q', 'M'<<8|'R', 'M'<<8|'S', 'M'<<8|'T',
+      'M'<<8|'U', 'M'<<8|'V', 'M'<<8|'W', 'M'<<8|'X', 'M'<<8|'Y',
+      'M'<<8|'Z', 'N'<<8|'A', 'N'<<8|'C', 'N'<<8|'E', 'N'<<8|'F',
+      'N'<<8|'G', 'N'<<8|'I', 'N'<<8|'L', 'N'<<8|'O', 'N'<<8|'P',
+      'N'<<8|'R', 'N'<<8|'U', 'N'<<8|'Z', 'O'<<8|'M', 'P'<<8|'A',
+      'P'<<8|'E', 'P'<<8|'F', 'P'<<8|'G', 'P'<<8|'H', 'P'<<8|'K',
+      'P'<<8|'L', 'P'<<8|'M', 'P'<<8|'N', 'P'<<8|'R', 'P'<<8|'S',
+      'P'<<8|'T', 'P'<<8|'W', 'P'<<8|'Y', 'Q'<<8|'A', 'R'<<8|'E',
+      'R'<<8|'O', 'R'<<8|'S', 'R'<<8|'U', 'R'<<8|'W', 'S'<<8|'A',
+      'S'<<8|'B', 'S'<<8|'C', 'S'<<8|'D', 'S'<<8|'E', 'S'<<8|'G',
+      'S'<<8|'H', 'S'<<8|'I', 'S'<<8|'J', 'S'<<8|'K', 'S'<<8|'L',
+      'S'<<8|'M', 'S'<<8|'N', 'S'<<8|'O', 'S'<<8|'R', 'S'<<8|'T',
+      'S'<<8|'V', 'S'<<8|'Y', 'S'<<8|'Z', 'T'<<8|'C', 'T'<<8|'D',
+      'T'<<8|'F', 'T'<<8|'G', 'T'<<8|'H', 'T'<<8|'J', 'T'<<8|'K',
+      'T'<<8|'L', 'T'<<8|'M', 'T'<<8|'N', 'T'<<8|'O', 'T'<<8|'R',
+      'T'<<8|'T', 'T'<<8|'V', 'T'<<8|'W', 'T'<<8|'Z', 'U'<<8|'A',
+      'U'<<8|'G', 'U'<<8|'M', 'U'<<8|'S', 'U'<<8|'Y', 'U'<<8|'Z',
+      'V'<<8|'A', 'V'<<8|'C', 'V'<<8|'E', 'V'<<8|'G', 'V'<<8|'I',
+      'V'<<8|'N', 'V'<<8|'U', 'W'<<8|'F', 'W'<<8|'S', 'Y'<<8|'E',
+      'Y'<<8|'T', 'Z'<<8|'A', 'Z'<<8|'M', 'Z'<<8|'W', -1 };
+
   TestingProfile profile;
   for (size_t i = 0; i < arraysize(kCountryIds); ++i) {
     profile.GetPrefs()->SetInteger(prefs::kCountryIDAtInstall, kCountryIds[i]);
@@ -225,10 +233,10 @@
   EXPECT_FALSE(t_urls[default_index]->suggestions_url().empty());
   EXPECT_FALSE(t_urls[default_index]->instant_url().empty());
   EXPECT_FALSE(t_urls[default_index]->image_url().empty());
+  EXPECT_FALSE(t_urls[default_index]->new_tab_url().empty());
   EXPECT_FALSE(t_urls[default_index]->image_url_post_params().empty());
-  EXPECT_EQ(
-      SEARCH_ENGINE_GOOGLE,
-      TemplateURLPrepopulateData::GetEngineType(t_urls[default_index]->url()));
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
+            TemplateURLPrepopulateData::GetEngineType(*t_urls[default_index]));
 }
 
 // Verifies that built-in search providers are processed correctly.
@@ -258,30 +266,26 @@
   EXPECT_FALSE(t_urls[default_index]->suggestions_url().empty());
   EXPECT_FALSE(t_urls[default_index]->instant_url().empty());
   EXPECT_FALSE(t_urls[default_index]->image_url().empty());
+  EXPECT_FALSE(t_urls[default_index]->new_tab_url().empty());
   EXPECT_FALSE(t_urls[default_index]->image_url_post_params().empty());
   // Expect at least 2 alternate_urls.
   // This caught a bug with static initialization of arrays, so leave this in.
   EXPECT_GT(t_urls[default_index]->alternate_urls().size(), 1u);
   for (size_t i = 0; i < t_urls[default_index]->alternate_urls().size(); ++i)
     EXPECT_FALSE(t_urls[default_index]->alternate_urls()[i].empty());
-  EXPECT_EQ(
-      SEARCH_ENGINE_GOOGLE,
-      TemplateURLPrepopulateData::GetEngineType(t_urls[default_index]->url()));
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
+            TemplateURLPrepopulateData::GetEngineType(*t_urls[default_index]));
   EXPECT_FALSE(t_urls[default_index]->search_terms_replacement_key().empty());
 }
 
 TEST(TemplateURLPrepopulateDataTest, GetEngineTypeBasic) {
-  EXPECT_EQ(SEARCH_ENGINE_OTHER,
-            TemplateURLPrepopulateData::GetEngineType("http://example.com/"));
-  EXPECT_EQ(SEARCH_ENGINE_ASK,
-            TemplateURLPrepopulateData::GetEngineType("http://www.ask.com/"));
-  EXPECT_EQ(SEARCH_ENGINE_OTHER,
-       TemplateURLPrepopulateData::GetEngineType("http://search.atlas.cz/"));
-  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
-       TemplateURLPrepopulateData::GetEngineType("http://www.google.com/"));
+  EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType("http://example.com/"));
+  EXPECT_EQ(SEARCH_ENGINE_ASK, GetEngineType("http://www.ask.com/"));
+  EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType("http://search.atlas.cz/"));
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE, GetEngineType("http://www.google.com/"));
 }
 
-TEST_F(TemplateURLPrepopulateDataTest, GetEngineTypeAdvanced) {
+TEST(TemplateURLPrepopulateDataTest, GetEngineTypeAdvanced) {
   // Google URLs in different forms.
   const char* kGoogleURLs[] = {
     // Original with google:baseURL:
@@ -296,8 +300,7 @@
     "http://www.google.ru/search?q={searchTerms}"
   };
   for (size_t i = 0; i < arraysize(kGoogleURLs); ++i) {
-    EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
-              TemplateURLPrepopulateData::GetEngineType(kGoogleURLs[i]));
+    EXPECT_EQ(SEARCH_ENGINE_GOOGLE, GetEngineType(kGoogleURLs[i]));
   }
 
   // Non-Google URLs.
@@ -309,35 +312,28 @@
       "http://someothersite.yahoo.com/",
   };
   for (size_t i = 0; i < arraysize(kYahooURLs); ++i) {
-    EXPECT_EQ(SEARCH_ENGINE_YAHOO,
-              TemplateURLPrepopulateData::GetEngineType(kYahooURLs[i]));
+    EXPECT_EQ(SEARCH_ENGINE_YAHOO, GetEngineType(kYahooURLs[i]));
   }
 
   // URLs for engines not present in country-specific lists.
   EXPECT_EQ(SEARCH_ENGINE_NIGMA,
-            TemplateURLPrepopulateData::GetEngineType(
-                "http://nigma.ru/?s={searchTerms}&arg1=value1"));
+            GetEngineType("http://nigma.ru/?s={searchTerms}&arg1=value1"));
   // Also test matching against alternate URLs (and TLD+1 matching).
   EXPECT_EQ(SEARCH_ENGINE_SOFTONIC,
-            TemplateURLPrepopulateData::GetEngineType(
-                "http://test.softonic.com.br/?{searchTerms}"));
+            GetEngineType("http://test.softonic.com.br/?{searchTerms}"));
 
   // Search URL for which no prepopulated search provider exists.
   EXPECT_EQ(SEARCH_ENGINE_OTHER,
-            TemplateURLPrepopulateData::GetEngineType(
-                "http://example.net/search?q={searchTerms}"));
-  EXPECT_EQ(SEARCH_ENGINE_OTHER,
-            TemplateURLPrepopulateData::GetEngineType("invalid:search:url"));
+            GetEngineType("http://example.net/search?q={searchTerms}"));
+  EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType("invalid:search:url"));
 
   // URL that doesn't look Google-related, but matches a Google base URL
   // specified on the command line.
   const std::string foo_url("http://www.foo.com/search?q={searchTerms}");
-  EXPECT_EQ(SEARCH_ENGINE_OTHER,
-            TemplateURLPrepopulateData::GetEngineType(foo_url));
+  EXPECT_EQ(SEARCH_ENGINE_OTHER, GetEngineType(foo_url));
   CommandLine::ForCurrentProcess()->AppendSwitchASCII(switches::kGoogleBaseURL,
                                                       "http://www.foo.com/");
-  EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
-            TemplateURLPrepopulateData::GetEngineType(foo_url));
+  EXPECT_EQ(SEARCH_ENGINE_GOOGLE, GetEngineType(foo_url));
 }
 
 TEST(TemplateURLPrepopulateDataTest, GetLogoURLGoogle) {
diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc
index 34a3b8e..55df617 100644
--- a/chrome/browser/search_engines/template_url_service.cc
+++ b/chrome/browser/search_engines/template_url_service.cc
@@ -57,29 +57,6 @@
 
 namespace {
 
-// String in the URL that is replaced by the search term.
-const char kSearchTermParameter[] = "{searchTerms}";
-
-// String in Initializer that is replaced with kSearchTermParameter.
-const char kTemplateParameter[] = "%s";
-
-// Term used when generating a search url. Use something obscure so that on
-// the rare case the term replaces the URL it's unlikely another keyword would
-// have the same url.
-const char kReplacementTerm[] = "blah.blah.blah.blah.blah";
-
-// The name of the histogram used to track default search changes. See the
-// comment for DefaultSearchChangeOrigin.
-const char kDSPChangeHistogramName[] = "Search.DefaultSearchChangeOrigin";
-
-// The name of the histogram used to track whether or not the user has a default
-// search provider.
-const char kHasDSPHistogramName[] = "Search.HasDefaultSearchProvider";
-
-// The name of the histogram used to store the id of the default search
-// provider.
-const char kDSPHistogramName[] = "Search.DefaultSearchProvider";
-
 bool TemplateURLsHaveSamePrefs(const TemplateURL* url1,
                                const TemplateURL* url2) {
   if (url1 == url2)
@@ -91,12 +68,12 @@
       (url1->suggestions_url() == url2->suggestions_url()) &&
       (url1->instant_url() == url2->instant_url()) &&
       (url1->image_url() == url2->image_url()) &&
+      (url1->new_tab_url() == url2->new_tab_url()) &&
       (url1->search_url_post_params() == url2->search_url_post_params()) &&
       (url1->suggestions_url_post_params() ==
           url2->suggestions_url_post_params()) &&
       (url1->instant_url_post_params() == url2->instant_url_post_params()) &&
       (url1->image_url_post_params() == url2->image_url_post_params()) &&
-      (url1->image_url() == url2->image_url()) &&
       (url1->favicon_url() == url2->favicon_url()) &&
       (url1->safe_for_autoreplace() == url2->safe_for_autoreplace()) &&
       (url1->show_in_default_list() == url2->show_in_default_list()) &&
@@ -436,12 +413,14 @@
   if (!search_ref.SupportsReplacementUsingTermsData(search_terms_data))
     return GURL(t_url->url());
 
-  // TODO(jnd): Adds additional parameters to get post data when the search URL
+  // Use something obscure for the search terms argument so that in the rare
+  // case the term replaces the URL it's unlikely another keyword would have the
+  // same url.
+  // TODO(jnd): Add additional parameters to get post data when the search URL
   // has post parameters.
   return GURL(search_ref.ReplaceSearchTermsUsingTermsData(
-      TemplateURLRef::SearchTermsArgs(ASCIIToUTF16(kReplacementTerm)),
-      search_terms_data,
-      NULL));
+      TemplateURLRef::SearchTermsArgs(ASCIIToUTF16("blah.blah.blah.blah.blah")),
+      search_terms_data, NULL));
 }
 
 bool TemplateURLService::CanReplaceKeyword(
@@ -1274,6 +1253,7 @@
   se_specifics->set_instant_url(turl.instant_url());
   if (!turl.image_url().empty())
     se_specifics->set_image_url(turl.image_url());
+  se_specifics->set_new_tab_url(turl.new_tab_url());
   if (!turl.search_url_post_params().empty())
     se_specifics->set_search_url_post_params(turl.search_url_post_params());
   if (!turl.suggestions_url_post_params().empty()) {
@@ -1338,6 +1318,7 @@
   data.suggestions_url = specifics.suggestions_url();
   data.instant_url = specifics.instant_url();
   data.image_url = specifics.image_url();
+  data.new_tab_url = specifics.new_tab_url();
   data.search_url_post_params = specifics.search_url_post_params();
   data.suggestions_url_post_params = specifics.suggestions_url_post_params();
   data.instant_url_post_params = specifics.instant_url_post_params();
@@ -1448,19 +1429,12 @@
       DCHECK(initializers[i].url);
       DCHECK(initializers[i].content);
 
-      size_t template_position =
-          std::string(initializers[i].url).find(kTemplateParameter);
-      DCHECK(template_position != std::string::npos);
-      std::string osd_url(initializers[i].url);
-      osd_url.replace(template_position, arraysize(kTemplateParameter) - 1,
-                      kSearchTermParameter);
-
       // TemplateURLService ends up owning the TemplateURL, don't try and free
       // it.
       TemplateURLData data;
       data.short_name = UTF8ToUTF16(initializers[i].content);
       data.SetKeyword(UTF8ToUTF16(initializers[i].keyword));
-      data.SetURL(osd_url);
+      data.SetURL(initializers[i].url);
       TemplateURL* template_url = new TemplateURL(profile_, data);
       AddNoNotify(template_url, true);
 
@@ -1608,6 +1582,7 @@
   std::string suggest_url;
   std::string instant_url;
   std::string image_url;
+  std::string new_tab_url;
   std::string search_url_post_params;
   std::string suggest_url_post_params;
   std::string instant_url_post_params;
@@ -1627,6 +1602,7 @@
     suggest_url = t_url->suggestions_url();
     instant_url = t_url->instant_url();
     image_url = t_url->image_url();
+    new_tab_url = t_url->new_tab_url();
     search_url_post_params = t_url->search_url_post_params();
     suggest_url_post_params = t_url->suggestions_url_post_params();
     instant_url_post_params = t_url->instant_url_post_params();
@@ -1648,6 +1624,7 @@
   prefs->SetString(prefs::kDefaultSearchProviderSuggestURL, suggest_url);
   prefs->SetString(prefs::kDefaultSearchProviderInstantURL, instant_url);
   prefs->SetString(prefs::kDefaultSearchProviderImageURL, image_url);
+  prefs->SetString(prefs::kDefaultSearchProviderNewTabURL, new_tab_url);
   prefs->SetString(prefs::kDefaultSearchProviderSearchURLPostParams,
                    search_url_post_params);
   prefs->SetString(prefs::kDefaultSearchProviderSuggestURLPostParams,
@@ -1708,6 +1685,8 @@
       prefs->GetString(prefs::kDefaultSearchProviderInstantURL);
   std::string image_url =
       prefs->GetString(prefs::kDefaultSearchProviderImageURL);
+  std::string new_tab_url =
+      prefs->GetString(prefs::kDefaultSearchProviderNewTabURL);
   std::string search_url_post_params =
       prefs->GetString(prefs::kDefaultSearchProviderSearchURLPostParams);
   std::string suggest_url_post_params =
@@ -1735,6 +1714,7 @@
   data.suggestions_url = suggest_url;
   data.instant_url = instant_url;
   data.image_url = image_url;
+  data.new_tab_url = new_tab_url;
   data.search_url_post_params = search_url_post_params;
   data.suggestions_url_post_params = suggest_url_post_params;
   data.instant_url_post_params = instant_url_post_params;
@@ -1917,9 +1897,6 @@
   if (!urls_for_host)
     return;
 
-  QueryTerms query_terms;
-  const std::string path = row.url().path();
-
   for (TemplateURLSet::const_iterator i = urls_for_host->begin();
        i != urls_for_host->end(); ++i) {
     string16 search_terms;
@@ -2122,8 +2099,8 @@
   // changed, and needs to be persisted below (for example, when this is called
   // from UpdateNoNotify).
   if (default_search_provider_ != url) {
-    UMA_HISTOGRAM_ENUMERATION(kDSPChangeHistogramName, dsp_change_origin_,
-                              DSP_CHANGE_MAX);
+    UMA_HISTOGRAM_ENUMERATION("Search.DefaultSearchChangeOrigin",
+                              dsp_change_origin_, DSP_CHANGE_MAX);
     default_search_provider_ = url;
   }
 
@@ -2480,7 +2457,6 @@
   }
 
   if (should_add_sync_turl) {
-    const std::string guid = sync_turl->sync_guid();
     // Force the local ID to kInvalidTemplateURLID so we can add it.
     TemplateURLData data(sync_turl->data());
     data.id = kInvalidTemplateURLID;
@@ -2623,7 +2599,7 @@
   if (!is_default_search_managed_) {
     bool has_default_search_provider = default_search_provider_ &&
         default_search_provider_->SupportsReplacement();
-    UMA_HISTOGRAM_BOOLEAN(kHasDSPHistogramName,
+    UMA_HISTOGRAM_BOOLEAN("Search.HasDefaultSearchProvider",
                           has_default_search_provider);
     // Ensure that default search provider exists. See http://crbug.com/116952.
     if (!has_default_search_provider) {
@@ -2631,11 +2607,15 @@
           SetDefaultSearchProviderNoNotify(FindNewDefaultSearchProvider());
       DCHECK(success);
     }
-    // Don't log anything if the user has a NULL default search provider. A
-    // logged value of 0 indicates a custom default search provider.
+    // Don't log anything if the user has a NULL default search provider.
     if (default_search_provider_) {
+      // TODO(pkasting): This histogram obsoletes the next one.  Remove the next
+      // one in Chrome 32 or later.
+      UMA_HISTOGRAM_ENUMERATION("Search.DefaultSearchProviderType",
+          TemplateURLPrepopulateData::GetEngineType(*default_search_provider_),
+          SEARCH_ENGINE_MAX);
       UMA_HISTOGRAM_ENUMERATION(
-          kDSPHistogramName,
+          "Search.DefaultSearchProvider",
           default_search_provider_->prepopulate_id(),
           TemplateURLPrepopulateData::kMaxPrepopulatedEngineID);
     }
diff --git a/chrome/browser/search_engines/template_url_service_factory.cc b/chrome/browser/search_engines/template_url_service_factory.cc
index 1beedcd..4b769c6 100644
--- a/chrome/browser/search_engines/template_url_service_factory.cc
+++ b/chrome/browser/search_engines/template_url_service_factory.cc
@@ -87,6 +87,10 @@
       std::string(),
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterStringPref(
+      prefs::kDefaultSearchProviderNewTabURL,
+      std::string(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterStringPref(
       prefs::kDefaultSearchProviderSearchURLPostParams,
       std::string(),
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
diff --git a/chrome/browser/search_engines/template_url_service_unittest.cc b/chrome/browser/search_engines/template_url_service_unittest.cc
index 42cd071..41c117e 100644
--- a/chrome/browser/search_engines/template_url_service_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_unittest.cc
@@ -26,12 +26,12 @@
 #include "chrome/browser/search_engines/template_url_service_test_util.h"
 #include "chrome/browser/webdata/web_data_service_factory.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/webdata/common/web_database.h"
 #include "content/public/test/test_browser_thread.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::Time;
@@ -950,13 +950,13 @@
       std::string(), std::string(), false, "UTF-8", Time(), Time());
   TemplateURL* default_provider = model()->GetDefaultSearchProvider();
   EXPECT_NE(SEARCH_ENGINE_GOOGLE,
-      TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
+            TemplateURLPrepopulateData::GetEngineType(*default_provider));
 
   DictionaryValue manifest;
-  manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
-  manifest.SetString(extension_manifest_keys::kName, "ext1");
+  manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
+  manifest.SetString(extensions::manifest_keys::kName, "ext1");
   manifest.SetString("app.launch.web_url", "http://www.google.com");
-  manifest.SetString(extension_manifest_keys::kOmniboxKeyword, "ext_keyword");
+  manifest.SetString(extensions::manifest_keys::kOmniboxKeyword, "ext_keyword");
   std::string error;
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(
@@ -976,7 +976,7 @@
   default_provider = model()->GetDefaultSearchProvider();
   ASSERT_TRUE(default_provider);
   EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
-      TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
+            TemplateURLPrepopulateData::GetEngineType(*default_provider));
   CheckExtensionKeyword(ASCIIToUTF16("ext_keyword"), ASCIIToUTF16("ext1"));
   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword2")));
   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
@@ -987,7 +987,7 @@
   default_provider = model()->GetDefaultSearchProvider();
   ASSERT_TRUE(default_provider);
   EXPECT_EQ(SEARCH_ENGINE_GOOGLE,
-      TemplateURLPrepopulateData::GetEngineType(default_provider->url()));
+            TemplateURLPrepopulateData::GetEngineType(*default_provider));
   CheckExtensionKeyword(ASCIIToUTF16("ext_keyword"), ASCIIToUTF16("ext1"));
   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("ext_keyword2")));
   EXPECT_FALSE(model()->GetTemplateURLForKeyword(ASCIIToUTF16("keyword")));
diff --git a/chrome/browser/search_engines/template_url_unittest.cc b/chrome/browser/search_engines/template_url_unittest.cc
index 708da7e..7dbff02 100644
--- a/chrome/browser/search_engines/template_url_unittest.cc
+++ b/chrome/browser/search_engines/template_url_unittest.cc
@@ -38,7 +38,7 @@
 };
 
 TestSearchTermsData::TestSearchTermsData(const std::string& google_base_url)
-    : google_base_url_(google_base_url)  {
+    : google_base_url_(google_base_url) {
 }
 
 std::string TestSearchTermsData::GoogleBaseURLValue() const {
@@ -1197,6 +1197,7 @@
   TemplateURLData data;
   data.SetURL("http://bar/search?q={searchTerms}");
   data.instant_url = "http://bar/instant#q={searchTerms}";
+  data.new_tab_url = "http://bar/newtab";
   data.alternate_urls.push_back("http://bar/?q={searchTerms}");
   data.alternate_urls.push_back("http://bar/#q={searchTerms}");
   data.alternate_urls.push_back("http://bar/search#q{searchTerms}");
@@ -1216,6 +1217,7 @@
     { "http://bar/url?url=http://www.foo.com/&q=foo#ref=bar", false, },
     { "http://bar/", false, },
     { "http://foo/", false, },
+    { "http://bar/newtab", false, },
   };
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(url_data); ++i) {
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h
index 9abd195..f855984 100644
--- a/chrome/browser/shell_integration.h
+++ b/chrome/browser/shell_integration.h
@@ -166,11 +166,6 @@
   static string16 GetAppListAppModelIdForProfile(
       const base::FilePath& profile_path);
 
-  // Returns the location (path and index) of the Chromium icon, (e.g.,
-  // "C:\path\to\chrome.exe,0"). This is used to specify the icon to use
-  // for the taskbar group on Win 7.
-  static string16 GetChromiumIconLocation();
-
   // Migrates existing chrome shortcuts by tagging them with correct app id.
   // see http://crbug.com/28104
   static void MigrateChromiumShortcuts();
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index cece2f1..d6de8c5 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -361,20 +361,6 @@
       GetAppListAppName(), profile_path);
 }
 
-string16 ShellIntegration::GetChromiumIconLocation() {
-  // Determine the path to chrome.exe. If we can't determine what that is,
-  // we have bigger fish to fry...
-  base::FilePath chrome_exe;
-  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
-    NOTREACHED();
-    return string16();
-  }
-
-  return ShellUtil::FormatIconLocation(
-      chrome_exe.value(),
-      BrowserDistribution::GetDistribution()->GetIconIndex());
-}
-
 void ShellIntegration::MigrateChromiumShortcuts() {
   if (base::win::GetVersion() < base::win::VERSION_WIN7)
     return;
@@ -515,7 +501,8 @@
     base::DIR_START_MENU,
   };
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  string16 shortcut_name(dist->GetAppShortCutName());
+  string16 shortcut_name(
+      dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME));
   base::FilePath shortcut;
 
   // Check both the common and the per-user Start Menu folders for system-level
diff --git a/chrome/browser/signin/about_signin_internals.cc b/chrome/browser/signin/about_signin_internals.cc
index 50bca57..c90e49b 100644
--- a/chrome/browser/signin/about_signin_internals.cc
+++ b/chrome/browser/signin/about_signin_internals.cc
@@ -92,6 +92,10 @@
     const std::string pref_path =
         SigninStatusFieldToString(static_cast<UntimedSigninStatusField>(i));
 
+    // Erase SID and LSID, since those are written as service tokens below.
+    if (i == signin_internals_util::SID || i == signin_internals_util::LSID)
+      pref_service->SetString(pref_path.c_str(), std::string());
+
     signin_status_.untimed_signin_fields[i - UNTIMED_FIELDS_BEGIN] =
         pref_service->GetString(pref_path.c_str());
   }
@@ -114,7 +118,17 @@
     const std::string time = pref + ".time";
     const std::string time_internal = pref + ".time_internal";
 
-    TokenInfo token_info(pref_service->GetString(value.c_str()),
+    // If the length is too long, assume its a full token and truncate it.
+    // We don't want to continue to persist full tokens in the preferences.
+    std::string truncated_value = pref_service->GetString(value.c_str());
+    if (truncated_value.length() >
+        signin_internals_util::kTruncateTokenStringLength) {
+      truncated_value =
+          GetTruncatedHash(pref_service->GetString(value.c_str()));
+      profile_->GetPrefs()->SetString(value.c_str(), truncated_value);
+    }
+
+    TokenInfo token_info(truncated_value,
                          pref_service->GetString(status.c_str()),
                          pref_service->GetString(time.c_str()),
                          pref_service->GetInt64(time_internal.c_str()),
@@ -133,8 +147,10 @@
   // This should have been initialized already.
   DCHECK(signin_status_.token_info_map.count(token_name));
 
+  std::string truncated_token = GetTruncatedHash(token);
+
   const std::string status_success = "Successful";
-  signin_status_.token_info_map[token_name].token = token;
+  signin_status_.token_info_map[token_name].truncated_token = truncated_token;
   signin_status_.token_info_map[token_name].status = status_success;
 
   // Also update preferences.
@@ -143,7 +159,7 @@
   const std::string time_internal_pref =
       TokenPrefPath(token_name) + ".time_internal";
   const std::string status_pref = TokenPrefPath(token_name) + ".status";
-  profile_->GetPrefs()->SetString(value_pref.c_str(), token);
+  profile_->GetPrefs()->SetString(value_pref.c_str(), truncated_token);
   profile_->GetPrefs()->SetString(status_pref.c_str(), "Successful");
 
   // Update timestamp if needed.
@@ -173,7 +189,7 @@
   // This should have been initialized already.
   DCHECK(signin_status_.token_info_map.count(token_name));
 
-  signin_status_.token_info_map[token_name].token.clear();
+  signin_status_.token_info_map[token_name].truncated_token.clear();
   signin_status_.token_info_map[token_name].status = error;
   signin_status_.token_info_map[token_name].time = time_as_str;
   signin_status_.token_info_map[token_name].time_internal = time_as_int;
@@ -198,7 +214,7 @@
   // This should have been initialized already.
   DCHECK(signin_status_.token_info_map.count(token_name));
 
-  signin_status_.token_info_map[token_name].token.clear();
+  signin_status_.token_info_map[token_name].truncated_token.clear();
 
   const std::string value_pref = TokenPrefPath(token_name) + ".value";
   profile_->GetPrefs()->SetString(value_pref.c_str(), std::string());
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.cc b/chrome/browser/signin/android_profile_oauth2_token_service.cc
index f79eb63..42a6516 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.cc
@@ -36,6 +36,16 @@
   return scope;
 }
 
+// Callback from FetchOAuth2TokenWithUsername().
+// Arguments:
+// - the error, or NONE if the token fetch was successful.
+// - the OAuth2 access token.
+// - the expiry time of the token (may be null, indicating that the expiry
+//   time is unknown.
+typedef base::Callback<void(
+    const GoogleServiceAuthError&, const std::string&, const base::Time&)>
+        FetchOAuth2TokenCallback;
+
 }  // namespace
 
 AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() {
@@ -45,18 +55,6 @@
 }
 
 scoped_ptr<OAuth2TokenService::Request>
-    AndroidProfileOAuth2TokenService::StartRequest(
-        const OAuth2TokenService::ScopeSet& scopes,
-        OAuth2TokenService::Consumer* consumer) {
-  const std::string& sync_username =
-      SigninManagerFactory::GetForProfile(profile())->
-          GetAuthenticatedUsername();
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  DCHECK(!sync_username.empty());
-  return StartRequestForUsername(sync_username, scopes, consumer);
-}
-
-scoped_ptr<OAuth2TokenService::Request>
     AndroidProfileOAuth2TokenService::StartRequestForUsername(
         const std::string& username,
         const OAuth2TokenService::ScopeSet& scopes,
@@ -64,10 +62,7 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
   scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
-  FetchOAuth2Token(
-      username,
-      CombineScopes(scopes),
-      base::Bind(&RequestImpl::InformConsumer, request->AsWeakPtr()));
+  FetchOAuth2TokenWithUsername(request.get(), username, scopes);
   return request.PassAs<Request>();
 }
 
@@ -91,20 +86,36 @@
 }
 
 void AndroidProfileOAuth2TokenService::FetchOAuth2Token(
+    RequestImpl* request,
+    net::URLRequestContextGetter* getter,
+    const std::string& client_id,
+    const std::string& client_secret,
+    const OAuth2TokenService::ScopeSet& scopes) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  std::string username = SigninManagerFactory::GetForProfile(profile())->
+      GetAuthenticatedUsername();
+  DCHECK(!username.empty());
+  // Just ignore client_id, getter, etc since we don't use them on Android.
+  FetchOAuth2TokenWithUsername(request, username, scopes);
+}
+
+void AndroidProfileOAuth2TokenService::FetchOAuth2TokenWithUsername(
+    RequestImpl* request,
     const std::string& username,
-    const std::string& scope,
-    const FetchOAuth2TokenCallback& callback) {
+    const OAuth2TokenService::ScopeSet& scopes) {
   JNIEnv* env = AttachCurrentThread();
+  std::string scope = CombineScopes(scopes);
   ScopedJavaLocalRef<jstring> j_username =
       ConvertUTF8ToJavaString(env, username);
   ScopedJavaLocalRef<jstring> j_scope =
       ConvertUTF8ToJavaString(env, scope);
 
-  // Allocate a copy of the callback on the heap, because the callback
+  // Allocate a copy of the request WeakPtr on the heap, because the object
   // needs to be passed through JNI as an int.
   // It will be passed back to OAuth2TokenFetched(), where it will be freed.
   scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
-      new FetchOAuth2TokenCallback(callback));
+      new FetchOAuth2TokenCallback(base::Bind(&RequestImpl::InformConsumer,
+                                              request->AsWeakPtr())));
 
   // Call into Java to get a new token.
   Java_AndroidProfileOAuth2TokenServiceHelper_getOAuth2AuthToken(
@@ -121,11 +132,8 @@
     jboolean result,
     jint nativeCallback) {
   std::string token = ConvertJavaStringToUTF8(env, authToken);
-  scoped_ptr<AndroidProfileOAuth2TokenService::FetchOAuth2TokenCallback>
-      heap_callback(
-          reinterpret_cast<
-              AndroidProfileOAuth2TokenService::FetchOAuth2TokenCallback*>(
-                  nativeCallback));
+  scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
+      reinterpret_cast<FetchOAuth2TokenCallback*>(nativeCallback));
   GoogleServiceAuthError err(result ?
                              GoogleServiceAuthError::NONE :
                              GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.h b/chrome/browser/signin/android_profile_oauth2_token_service.h
index 39680fe..0057540 100644
--- a/chrome/browser/signin/android_profile_oauth2_token_service.h
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.h
@@ -28,23 +28,6 @@
 // request from other thread, please use ProfileOAuth2TokenServiceRequest.
 class AndroidProfileOAuth2TokenService : public ProfileOAuth2TokenService {
  public:
-
-  // Callback from FetchOAuth2Token.
-  // Arguments:
-  // - the error, or NONE if the token fetch was successful.
-  // - the OAuth2 access token.
-  // - the expiry time of the token (may be null, indicating that the expiry
-  //   time is unknown.
-  typedef base::Callback<void(
-      const GoogleServiceAuthError&, const std::string&, const base::Time&)>
-          FetchOAuth2TokenCallback;
-
-  // Start the OAuth2 access token for the given scopes using
-  // ProfileSyncServiceAndroid.
-  virtual scoped_ptr<OAuth2TokenService::Request> StartRequest(
-      const OAuth2TokenService::ScopeSet& scopes,
-      OAuth2TokenService::Consumer* consumer) OVERRIDE;
-
   // StartRequest() fetches a token for the currently signed-in account; this
   // version uses the account corresponding to |username|. This allows fetching
   // tokens before a user is signed-in (e.g. during the sign-in flow).
@@ -66,10 +49,20 @@
   AndroidProfileOAuth2TokenService();
   virtual ~AndroidProfileOAuth2TokenService();
 
-  // virtual for testing.
-  virtual void FetchOAuth2Token(const std::string& username,
-                                const std::string& scope,
-                                const FetchOAuth2TokenCallback& callback);
+  // Overridden from OAuth2TokenService to intercept token fetch requests and
+  // redirect them to the Account Manager.
+  virtual void FetchOAuth2Token(RequestImpl* request,
+                                net::URLRequestContextGetter* getter,
+                                const std::string& client_id,
+                                const std::string& client_secret,
+                                const ScopeSet& scopes) OVERRIDE;
+
+  // Low-level helper function used by both FetchOAuth2Token and
+  // StartRequestForUsername to fetch tokens. virtual to enable mocks.
+  virtual void FetchOAuth2TokenWithUsername(
+      RequestImpl* request,
+      const std::string& username,
+      const ScopeSet& scope);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AndroidProfileOAuth2TokenService);
diff --git a/chrome/browser/signin/fake_profile_oauth2_token_service.cc b/chrome/browser/signin/fake_profile_oauth2_token_service.cc
new file mode 100644
index 0000000..04d4fb9
--- /dev/null
+++ b/chrome/browser/signin/fake_profile_oauth2_token_service.cc
@@ -0,0 +1,120 @@
+// Copyright 2013 The Chromium Authors. 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/fake_profile_oauth2_token_service.h"
+
+FakeProfileOAuth2TokenService::PendingRequest::PendingRequest() {
+}
+
+FakeProfileOAuth2TokenService::PendingRequest::~PendingRequest() {
+}
+
+// static
+BrowserContextKeyedService* FakeProfileOAuth2TokenService::Build(
+    content::BrowserContext* profile) {
+  return new FakeProfileOAuth2TokenService();
+}
+
+FakeProfileOAuth2TokenService::FakeProfileOAuth2TokenService() {
+}
+
+FakeProfileOAuth2TokenService::~FakeProfileOAuth2TokenService() {
+}
+
+void FakeProfileOAuth2TokenService::Shutdown() {
+  // Do not call the base class handler because it assumes that Initialize()
+  // is always called before Shutdown() and that's not the case for this mock.
+}
+
+void FakeProfileOAuth2TokenService::IssueRefreshToken(
+    const std::string& token) {
+  refresh_token_ = token;
+  if (refresh_token_.empty())
+    FireRefreshTokenRevoked("account_id");
+  else
+    FireRefreshTokenAvailable("account_id");
+  // TODO(atwilson): Maybe we should also call FireRefreshTokensLoaded() here?
+}
+
+void FakeProfileOAuth2TokenService::IssueTokenForScope(
+    const ScopeSet& scope,
+    const std::string& access_token,
+    const base::Time& expiration) {
+  CompleteRequests(false,
+                   scope,
+                   GoogleServiceAuthError::AuthErrorNone(),
+                   access_token,
+                   expiration);
+}
+
+void FakeProfileOAuth2TokenService::IssueErrorForScope(
+    const ScopeSet& scope,
+    const GoogleServiceAuthError& error) {
+  CompleteRequests(false, scope, error, std::string(), base::Time());
+}
+
+void FakeProfileOAuth2TokenService::IssueErrorForAllPendingRequests(
+    const GoogleServiceAuthError& error) {
+  CompleteRequests(true, ScopeSet(), error, std::string(), base::Time());
+}
+
+void FakeProfileOAuth2TokenService::IssueTokenForAllPendingRequests(
+    const std::string& access_token,
+    const base::Time& expiration) {
+  CompleteRequests(true,
+                   ScopeSet(),
+                   GoogleServiceAuthError::AuthErrorNone(),
+                   access_token,
+                   expiration);
+}
+
+void FakeProfileOAuth2TokenService::CompleteRequests(
+    bool all_scopes,
+    const ScopeSet& scope,
+    const GoogleServiceAuthError& error,
+    const std::string& access_token,
+    const base::Time& expiration) {
+  std::vector<FakeProfileOAuth2TokenService::PendingRequest> requests =
+      GetPendingRequests();
+  // Walk the requests and notify the callbacks.
+  for (std::vector<PendingRequest>::iterator it = pending_requests_.begin();
+       it != pending_requests_.end(); ++it) {
+    if (it->request && (all_scopes || it->scopes == scope))
+      it->request->InformConsumer(error, access_token, expiration);
+  }
+}
+
+std::string FakeProfileOAuth2TokenService::GetRefreshToken() {
+  return refresh_token_;
+}
+
+net::URLRequestContextGetter*
+FakeProfileOAuth2TokenService::GetRequestContext() {
+  return NULL;
+}
+
+std::vector<FakeProfileOAuth2TokenService::PendingRequest>
+FakeProfileOAuth2TokenService::GetPendingRequests() {
+  std::vector<PendingRequest> valid_requests;
+  for (std::vector<PendingRequest>::iterator it = pending_requests_.begin();
+       it != pending_requests_.end(); ++it) {
+    if (it->request)
+      valid_requests.push_back(*it);
+  }
+  return valid_requests;
+}
+
+void FakeProfileOAuth2TokenService::FetchOAuth2Token(
+    RequestImpl* request,
+    net::URLRequestContextGetter* getter,
+    const std::string& client_id,
+    const std::string& client_secret,
+    const ScopeSet& scopes) {
+  PendingRequest pending_request;
+  pending_request.client_id = client_id;
+  pending_request.client_secret = client_secret;
+  pending_request.scopes = scopes;
+  pending_request.request = request->AsWeakPtr();
+  pending_requests_.push_back(pending_request);
+}
diff --git a/chrome/browser/signin/fake_profile_oauth2_token_service.h b/chrome/browser/signin/fake_profile_oauth2_token_service.h
new file mode 100644
index 0000000..cd5bc8b
--- /dev/null
+++ b/chrome/browser/signin/fake_profile_oauth2_token_service.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 CHROME_BROWSER_SIGNIN_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_H_
+#define CHROME_BROWSER_SIGNIN_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_H_
+
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+
+namespace content {
+class BrowserContext;
+}
+
+// Helper class to simplify writing unittests that depend on an instance of
+// ProfileOAuth2TokenService.
+//
+// Tests would typically do something like the following:
+//
+// FakeProfileOAuth2TokenService service;
+// ...
+// service.IssueRefreshToken("token");  // Issue refresh token/notify observers
+// ...
+// // Confirm that there is at least one active request.
+// EXPECT_GT(0U, service.GetPendingRequests().size());
+// ...
+// // Make any pending token fetches for a given scope succeed.
+// ScopeSet scopes;
+// scopes.insert(GaiaConstants::kYourServiceScope);
+// IssueTokenForScope(scopes, "access_token", base::Time()::Max());
+// ...
+// // ...or make them fail...
+// IssueErrorForScope(scopes, GoogleServiceAuthError(INVALID_GAIA_CREDENTIALS));
+//
+class FakeProfileOAuth2TokenService : public ProfileOAuth2TokenService {
+ public:
+  struct PendingRequest {
+    PendingRequest();
+    ~PendingRequest();
+
+    std::string client_id;
+    std::string client_secret;
+    ScopeSet scopes;
+    base::WeakPtr<RequestImpl> request;
+  };
+
+  FakeProfileOAuth2TokenService();
+  virtual ~FakeProfileOAuth2TokenService();
+
+  // Sets the current refresh token. If |token| is non-empty, this will invoke
+  // OnRefreshTokenAvailable() on all Observers, otherwise this will invoke
+  // OnRefreshTokenRevoked().
+  void IssueRefreshToken(const std::string& token);
+
+  // Gets a list of active requests (can be used by tests to validate that the
+  // correct request has been issued).
+  std::vector<PendingRequest> GetPendingRequests();
+
+  // Helper routines to issue tokens for pending requests.
+  void IssueTokenForScope(const ScopeSet& scopes,
+                          const std::string& access_token,
+                          const base::Time& expiration);
+
+  void IssueErrorForScope(const ScopeSet& scopes,
+                          const GoogleServiceAuthError& error);
+
+  void IssueTokenForAllPendingRequests(const std::string& access_token,
+                                       const base::Time& expiration);
+
+  void IssueErrorForAllPendingRequests(const GoogleServiceAuthError& error);
+
+  virtual void Shutdown() OVERRIDE;
+
+  // Helper function to be used with
+  // BrowserContextKeyedService::SetTestingFactory().
+  static BrowserContextKeyedService* Build(content::BrowserContext* profile);
+
+ protected:
+  // OAuth2TokenService overrides.
+  virtual void FetchOAuth2Token(RequestImpl* request,
+                                net::URLRequestContextGetter* getter,
+                                const std::string& client_id,
+                                const std::string& client_secret,
+                                const ScopeSet& scopes) OVERRIDE;
+
+  virtual std::string GetRefreshToken() OVERRIDE;
+
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+
+ private:
+  // Helper function to complete pending requests - if |all_scopes| is true,
+  // then all pending requests are completed, otherwise, only those requests
+  // matching |scopes| are completed.
+  void CompleteRequests(bool all_scopes,
+                        const ScopeSet& scopes,
+                        const GoogleServiceAuthError& error,
+                        const std::string& access_token,
+                        const base::Time& expiration);
+
+  std::vector<PendingRequest> pending_requests_;
+  std::string refresh_token_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeProfileOAuth2TokenService);
+};
+
+#endif  // CHROME_BROWSER_SIGNIN_FAKE_PROFILE_OAUTH2_TOKEN_SERVICE_H_
diff --git a/chrome/browser/signin/oauth2_token_service.cc b/chrome/browser/signin/oauth2_token_service.cc
index 0b6bd5d..1773871 100644
--- a/chrome/browser/signin/oauth2_token_service.cc
+++ b/chrome/browser/signin/oauth2_token_service.cc
@@ -315,7 +315,6 @@
 }
 
 OAuth2TokenService::~OAuth2TokenService() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   // Release all the pending fetchers.
   STLDeleteContainerPairSecondPointers(
       pending_fetchers_.begin(), pending_fetchers_.end());
@@ -330,7 +329,6 @@
 }
 
 bool OAuth2TokenService::RefreshTokenIsAvailable() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   return !GetRefreshToken().empty();
 }
 
@@ -383,20 +381,34 @@
 
   scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
 
-  std::string refresh_token = GetRefreshToken();
-  if (refresh_token.empty()) {
+  if (!RefreshTokenIsAvailable()) {
     base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
         &RequestImpl::InformConsumer,
         request->AsWeakPtr(),
-        GoogleServiceAuthError(
-            GoogleServiceAuthError::USER_NOT_SIGNED_UP),
+        GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP),
         std::string(),
         base::Time()));
     return request.PassAs<Request>();
   }
 
-  if (HasCacheEntry(scopes))
-    return StartCacheLookupRequest(scopes, consumer);
+  if (HasCacheEntry(scopes)) {
+    StartCacheLookupRequest(request.get(), scopes, consumer);
+  } else {
+    FetchOAuth2Token(request.get(),
+                     getter,
+                     client_id,
+                     client_secret,
+                     scopes);
+  }
+  return request.PassAs<Request>();
+}
+
+void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
+                                          net::URLRequestContextGetter* getter,
+                                          const std::string& client_id,
+                                          const std::string& client_secret,
+                                          const ScopeSet& scopes) {
+  std::string refresh_token = GetRefreshToken();
 
   // If there is already a pending fetcher for |scopes| and |refresh_token|,
   // simply register this |request| for those results rather than starting
@@ -406,7 +418,7 @@
       pending_fetchers_.find(fetch_parameters);
   if (iter != pending_fetchers_.end()) {
     iter->second->AddWaitingRequest(request->AsWeakPtr());
-    return request.PassAs<Request>();
+    return;
   }
 
   pending_fetchers_[fetch_parameters] =
@@ -417,23 +429,20 @@
                               refresh_token,
                               scopes,
                               request->AsWeakPtr());
-  return request.PassAs<Request>();
 }
 
-scoped_ptr<OAuth2TokenService::Request>
-    OAuth2TokenService::StartCacheLookupRequest(
-        const OAuth2TokenService::ScopeSet& scopes,
-        OAuth2TokenService::Consumer* consumer) {
+void OAuth2TokenService::StartCacheLookupRequest(
+    RequestImpl* request,
+    const OAuth2TokenService::ScopeSet& scopes,
+    OAuth2TokenService::Consumer* consumer) {
   CHECK(HasCacheEntry(scopes));
   const CacheEntry* cache_entry = GetCacheEntry(scopes);
-  scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
   base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
       &RequestImpl::InformConsumer,
       request->AsWeakPtr(),
       GoogleServiceAuthError(GoogleServiceAuthError::NONE),
       cache_entry->access_token,
       cache_entry->expiration_date));
-  return request.PassAs<Request>();
 }
 
 void OAuth2TokenService::InvalidateToken(const ScopeSet& scopes,
@@ -577,10 +586,9 @@
 }
 
 void OAuth2TokenService::FireRefreshTokenRevoked(
-    const std::string& account_id,
-    const GoogleServiceAuthError& error) {
+    const std::string& account_id) {
   FOR_EACH_OBSERVER(Observer, observer_list_,
-                    OnRefreshTokenRevoked(account_id, error));
+                    OnRefreshTokenRevoked(account_id));
 }
 
 void OAuth2TokenService::FireRefreshTokensLoaded() {
diff --git a/chrome/browser/signin/oauth2_token_service.h b/chrome/browser/signin/oauth2_token_service.h
index d63fbdf..ac993de 100644
--- a/chrome/browser/signin/oauth2_token_service.h
+++ b/chrome/browser/signin/oauth2_token_service.h
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/threading/non_thread_safe.h"
 #include "base/time/time.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
@@ -49,7 +50,7 @@
 //
 // The caller of StartRequest() owns the returned request and is responsible to
 // delete the request even once the callback has been invoked.
-class OAuth2TokenService {
+class OAuth2TokenService : public base::NonThreadSafe {
  public:
   // Class representing a request that fetches an OAuth2 access token.
   class Request {
@@ -87,8 +88,7 @@
     virtual void OnRefreshTokenAvailable(const std::string& account_id) {}
     // Called whenever the login-scoped refresh token becomes unavailable for
     // account |account_id|.
-    virtual void OnRefreshTokenRevoked(const std::string& account_id,
-                                       const GoogleServiceAuthError& error) {}
+    virtual void OnRefreshTokenRevoked(const std::string& account_id) {}
     // Called after all refresh tokens are loaded during OAuth2TokenService
     // startup.
     virtual void OnRefreshTokensLoaded() {}
@@ -114,13 +114,15 @@
   // |scopes| is the set of scopes to get an access token for, |consumer| is
   // the object that will be called back with results if the returned request
   // is not deleted.
+  // TODO(atwilson): Make this non-virtual when we change
+  // ProfileOAuth2TokenServiceRequestTest to use FakeProfileOAuth2TokenService.
   virtual scoped_ptr<Request> StartRequest(const ScopeSet& scopes,
                                            Consumer* consumer);
 
   // This method does the same as |StartRequest| except it uses |client_id| and
   // |client_secret| to identify OAuth client app instead of using
   // Chrome's default values.
-  virtual scoped_ptr<Request> StartRequestForClient(
+  scoped_ptr<Request> StartRequestForClient(
       const std::string& client_id,
       const std::string& client_secret,
       const ScopeSet& scopes,
@@ -129,7 +131,7 @@
   // This method does the same as |StartRequest| except it uses the request
   // context given by |getter| instead of using the one returned by
   // |GetRequestContext| implemented by derived classes.
-  virtual scoped_ptr<Request> StartRequestWithContext(
+  scoped_ptr<Request> StartRequestWithContext(
       net::URLRequestContextGetter* getter,
       const ScopeSet& scopes,
       Consumer* consumer);
@@ -191,8 +193,9 @@
 
   // Posts a task to fire the Consumer callback with the cached token.  Must
   // Must only be called if HasCacheEntry() returns true.
-  scoped_ptr<Request> StartCacheLookupRequest(const ScopeSet& scopes,
-                                              Consumer* consumer);
+  void StartCacheLookupRequest(RequestImpl* request,
+                               const ScopeSet& scopes,
+                               Consumer* consumer);
 
   // Clears the internal token cache.
   void ClearCache();
@@ -205,16 +208,23 @@
 
   // Called by subclasses to notify observers.
   void FireRefreshTokenAvailable(const std::string& account_id);
-  void FireRefreshTokenRevoked(const std::string& account_id,
-                               const GoogleServiceAuthError& error);
+  void FireRefreshTokenRevoked(const std::string& account_id);
   void FireRefreshTokensLoaded();
   void FireRefreshTokensCleared();
 
- private:
   // Derived classes must provide a request context used for fetching access
   // tokens with the |StartRequest| method.
   virtual net::URLRequestContextGetter* GetRequestContext() = 0;
 
+  // Fetches an OAuth token for the specified client/scopes. Virtual so it can
+  // be overridden for tests and for platform-specific behavior on Android.
+  virtual void FetchOAuth2Token(RequestImpl* request,
+                                net::URLRequestContextGetter* getter,
+                                const std::string& client_id,
+                                const std::string& client_secret,
+                                const ScopeSet& scopes);
+
+ private:
   // Class that fetches an OAuth2 access token for a given set of scopes and
   // OAuth2 refresh token.
   class Fetcher;
diff --git a/chrome/browser/signin/profile_oauth2_token_service.cc b/chrome/browser/signin/profile_oauth2_token_service.cc
index 439e5ec..1687b33 100644
--- a/chrome/browser/signin/profile_oauth2_token_service.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service.cc
@@ -68,8 +68,6 @@
 }
 
 void ProfileOAuth2TokenService::Initialize(Profile* profile) {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
   DCHECK(profile);
   DCHECK(!profile_);
   profile_ = profile;
@@ -88,14 +86,12 @@
                  chrome::NOTIFICATION_TOKEN_AVAILABLE,
                  token_service_source);
   registrar_.Add(this,
-                 chrome::NOTIFICATION_TOKEN_REQUEST_FAILED,
-                 token_service_source);
-  registrar_.Add(this,
                  chrome::NOTIFICATION_TOKEN_LOADING_FINISHED,
                  token_service_source);
 }
 
 void ProfileOAuth2TokenService::Shutdown() {
+  DCHECK(profile_) << "Shutdown() called without matching call to Initialize()";
   CancelAllRequests();
   signin_global_error_->RemoveProvider(this);
   GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(
@@ -111,6 +107,10 @@
   return token_service->GetOAuth2LoginRefreshToken();
 }
 
+net::URLRequestContextGetter* ProfileOAuth2TokenService::GetRequestContext() {
+  return profile_->GetRequestContext();
+}
+
 void ProfileOAuth2TokenService::UpdateAuthError(
     const GoogleServiceAuthError& error) {
   // Do not report connection errors as these are not actually auth errors.
@@ -147,25 +147,6 @@
       }
       break;
     }
-    case chrome::NOTIFICATION_TOKEN_REQUEST_FAILED: {
-      TokenService::TokenRequestFailedDetails* tok_details =
-          content::Details<TokenService::TokenRequestFailedDetails>(details)
-              .ptr();
-      if (tok_details->service() == GaiaConstants::kLSOService ||
-          tok_details->service() ==
-              GaiaConstants::kGaiaOAuth2LoginRefreshToken) {
-        // TODO(fgorski): Canceling all requests will not be correct in a
-        // multi-login environment. We should cacnel only the requests related
-        // to the failed refresh token.
-        // Failed refresh token is not available at this point, but since
-        // there are no other refresh tokens, we cancel all active requests.
-        CancelAllRequests();
-        ClearCache();
-        UpdateAuthError(tok_details->error());
-        FireRefreshTokenRevoked(GetAccountId(profile_), tok_details->error());
-      }
-      break;
-    }
     case chrome::NOTIFICATION_TOKENS_CLEARED: {
       CancelAllRequests();
       ClearCache();
@@ -174,6 +155,15 @@
       break;
     }
     case chrome::NOTIFICATION_TOKEN_LOADING_FINISHED:
+      // During startup, if the user is signed in and the OAuth2 refresh token
+      // is empty, flag it as an error by badging the menu. Otherwise, if the
+      // user goes on to set up sync, they will have to make two attempts:
+      // One to surface the OAuth2 error, and a second one after signing in.
+      // See crbug.com/276650.
+      if (!GetAccountId(profile_).empty() && GetRefreshToken().empty()) {
+        UpdateAuthError(GoogleServiceAuthError(
+            GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+      }
       FireRefreshTokensLoaded();
       break;
     default:
@@ -186,10 +176,6 @@
   return last_auth_error_;
 }
 
-net::URLRequestContextGetter* ProfileOAuth2TokenService::GetRequestContext() {
-  return profile_->GetRequestContext();
-}
-
 void ProfileOAuth2TokenService::RegisterCacheEntry(
     const std::string& refresh_token,
     const ScopeSet& scopes,
@@ -254,8 +240,7 @@
         TokenWebData::FromBrowserContext(profile_);
     if (token_web_data.get())
       token_web_data->RemoveTokenForService(ApplyAccountIdPrefix(account_id));
-    FireRefreshTokenRevoked(account_id,
-        GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+    FireRefreshTokenRevoked(account_id);
 
     // TODO(fgorski): Notify diagnostic observers.
   }
@@ -265,12 +250,11 @@
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
   CancelAllRequests();
-  GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
   for (std::map<std::string, std::string>::const_iterator iter =
            refresh_tokens_.begin();
        iter != refresh_tokens_.end();
        ++iter) {
-    FireRefreshTokenRevoked(iter->first, error);
+    FireRefreshTokenRevoked(iter->first);
   }
   refresh_tokens_.clear();
 
diff --git a/chrome/browser/signin/profile_oauth2_token_service.h b/chrome/browser/signin/profile_oauth2_token_service.h
index 013cc06..a920e5e 100644
--- a/chrome/browser/signin/profile_oauth2_token_service.h
+++ b/chrome/browser/signin/profile_oauth2_token_service.h
@@ -58,9 +58,6 @@
   // SigninGlobalError::AuthStatusProvider implementation.
   virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
 
-  // OAuth2TokenService implementation.
-  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
-
   // Takes injected TokenService for testing.
   bool ShouldCacheForRefreshToken(TokenService *token_service,
                                   const std::string& refresh_token);
@@ -94,6 +91,9 @@
   // OAuth2TokenService overrides.
   virtual std::string GetRefreshToken() OVERRIDE;
 
+  // OAuth2TokenService implementation.
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+
   // Updates the internal cache of the result from the most-recently-completed
   // auth request (used for reporting errors to the user).
   virtual void UpdateAuthError(const GoogleServiceAuthError& error) OVERRIDE;
diff --git a/chrome/browser/signin/profile_oauth2_token_service_factory.cc b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
index e40433b..23dbcae 100644
--- a/chrome/browser/signin/profile_oauth2_token_service_factory.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/token_service_factory.h"
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
@@ -15,6 +16,7 @@
         "ProfileOAuth2TokenService",
         BrowserContextDependencyManager::GetInstance()) {
   DependsOn(GlobalErrorServiceFactory::GetInstance());
+  DependsOn(SigninManagerFactory::GetInstance());
   DependsOn(TokenServiceFactory::GetInstance());
 }
 
diff --git a/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc b/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
index ef1c18b..6fb6e5b 100644
--- a/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
@@ -181,9 +181,11 @@
 void ProfileOAuth2TokenServiceRequestTest::SetUp() {
   ui_thread_.reset(new content::TestBrowserThread(content::BrowserThread::UI,
                                                   &ui_loop_));
-  profile_.reset(new TestingProfile());
-  ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-      profile_.get(), &CreateOAuth2TokenService);
+  TestingProfile::Builder builder;
+  builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                            &CreateOAuth2TokenService);
+  profile_ = builder.Build();
+
   oauth2_service_ = (MockProfileOAuth2TokenService*)
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
 }
diff --git a/chrome/browser/signin/profile_oauth2_token_service_unittest.cc b/chrome/browser/signin/profile_oauth2_token_service_unittest.cc
index 78dece9..2092755 100644
--- a/chrome/browser/signin/profile_oauth2_token_service_unittest.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_unittest.cc
@@ -16,6 +16,10 @@
 
 using content::BrowserThread;
 
+// Defining constant here to handle backward compatiblity tests, but this
+// constant is no longer used in current versions of chrome.
+static const char kLSOService[] = "lso";
+
 class ProfileOAuth2TokenServiceTest : public TokenServiceTestHarness,
                                       public OAuth2TokenService::Observer {
  public:
@@ -44,9 +48,7 @@
   virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE {
     ++token_available_count_;
   }
-  virtual void OnRefreshTokenRevoked(
-      const std::string& account_id,
-      const GoogleServiceAuthError& error) OVERRIDE {
+  virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE {
     ++token_revoked_count_;
   }
   virtual void OnRefreshTokensLoaded() OVERRIDE {
@@ -132,8 +134,7 @@
   // Populate DB with legacy tokens.
   service()->OnIssueAuthTokenSuccess(GaiaConstants::kSyncService,
                                      "syncServiceToken");
-  service()->OnIssueAuthTokenSuccess(GaiaConstants::kLSOService,
-                                     "lsoToken");
+  service()->OnIssueAuthTokenSuccess(kLSOService, "lsoToken");
   service()->OnIssueAuthTokenSuccess(
       GaiaConstants::kGaiaOAuth2LoginRefreshToken,
       main_refresh_token);
@@ -158,8 +159,7 @@
       GaiaConstants::kGaiaOAuth2LoginRefreshToken,
       "secondOldRefreshToken");
   // Add some other legacy token. (Expected to get discarded).
-  service()->OnIssueAuthTokenSuccess(GaiaConstants::kLSOService,
-                                     "lsoToken");
+  service()->OnIssueAuthTokenSuccess(kLSOService, "lsoToken");
   // Also add a token using PO2TS.UpdateCredentials and make sure upgrade does
   // not wipe it.
   std::string other_account_id("other_account_id");
@@ -275,22 +275,6 @@
   ResetObserverCounts();
 }
 
-// Until the TokenService class is removed, problems fetching the LSO token
-// should translate to problems fetching the oauth2 refresh token.
-TEST_F(ProfileOAuth2TokenServiceTest, LsoNotification) {
-  EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
-
-  // Get a valid token.
-  service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
-                                   "refreshToken");
-  ExpectOneTokenAvailableNotification();
-
-  service()->OnIssueAuthTokenFailure(
-      GaiaConstants::kLSOService,
-      GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
-  ExpectOneTokenRevokedNotification();
-}
-
 // Until the TokenService class is removed, finish token loading in TokenService
 // should translate to finish token loading in ProfileOAuth2TokenService.
 TEST_F(ProfileOAuth2TokenServiceTest, TokensLoaded) {
diff --git a/chrome/browser/signin/signin_internals_util.cc b/chrome/browser/signin/signin_internals_util.cc
index 9895302..94e1f10 100644
--- a/chrome/browser/signin/signin_internals_util.cc
+++ b/chrome/browser/signin/signin_internals_util.cc
@@ -28,10 +28,15 @@
 // about:signin-internals.
 const char kObfuscatedGaiaIdFetcherToken[] = "ObfuscatedGaiaIdFetcher";
 const char kOAuth2MintTokenFlowToken[] = "OAuth2MintTokenFlow";
+
+const char kSIDToken[] = "SID";
+const char kLSIDToken[] = "LSID";
+
 const char* kTokenPrefsArray[] = {
   GaiaConstants::kSyncService,
-  GaiaConstants::kLSOService,
   GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+  kSIDToken,
+  kLSIDToken,
   kOperationsBaseToken,
   kUserPolicySigninServiceToken,
   kProfileDownloaderToken,
@@ -41,37 +46,18 @@
 
 const size_t kNumTokenPrefs = arraysize(kTokenPrefsArray);
 
-
-namespace {
-
-// Gets the first 6 hex characters of the SHA256 hash of the passed in string.
-// These are enough to perform equality checks across a single users tokens,
-// while preventing outsiders from reverse-engineering the actual token from
-// the displayed value.
-// Note that for readability (in about:signin-internals), an empty string
-// is not hashed, but simply returned as an empty string.
-const size_t kTruncateSize = 3;
-std::string GetTruncatedHash(const std::string& str) {
-  if (str.empty())
-    return str;
-
-  char hash_val[kTruncateSize];
-  crypto::SHA256HashString(str, &hash_val[0], kTruncateSize);
-  return StringToLowerASCII(base::HexEncode(&hash_val[0], kTruncateSize));
-}
-
-} // namespace
-
-TokenInfo::TokenInfo(const std::string& token,
+TokenInfo::TokenInfo(const std::string& truncated_token,
                      const std::string& status,
                      const std::string& time,
                      const int64& time_internal,
                      const std::string& service)
-    : token(token),
+    : truncated_token(truncated_token),
       status(status),
       time(time),
       time_internal(time_internal),
       service(service) {
+  // This should be a truncated and hashed token.
+  DCHECK_LE(truncated_token.length(), kTruncateTokenStringLength);
 }
 
 TokenInfo::TokenInfo() {
@@ -83,7 +69,7 @@
 DictionaryValue* TokenInfo::ToValue() {
   scoped_ptr<DictionaryValue> token_info(new DictionaryValue());
   token_info->SetString("service", service);
-  token_info->SetString("token", GetTruncatedHash(token));
+  token_info->SetString("token", truncated_token);
   token_info->SetString("status", status);
   token_info->SetString("time", time);
 
@@ -246,26 +232,18 @@
       "Not Signed In" : "Signed In";
   AddSectionEntry(basic_info, "Chrome Version", GetVersionString());
   AddSectionEntry(basic_info, "Signin Status", signin_status_string);
-  int i;
-  for (i = UNTIMED_FIELDS_BEGIN; i < UNTIMED_FIELDS_END; ++i) {
-    const std::string field =
-        SigninStatusFieldToLabel(static_cast<UntimedSigninStatusField>(i));
-    if (i == SID || i == LSID) {
-      AddSectionEntry(
-          basic_info,
-          field,
-          GetTruncatedHash(untimed_signin_fields[i - UNTIMED_FIELDS_BEGIN]));
-    } else {
-      AddSectionEntry(
-          basic_info,
-          field,
-          untimed_signin_fields[i - UNTIMED_FIELDS_BEGIN]);
-    }
-  }
+
+  // Only add username.  SID and LSID have moved to tokens section.
+  const std::string field =
+      SigninStatusFieldToLabel(static_cast<UntimedSigninStatusField>(USERNAME));
+  AddSectionEntry(
+      basic_info,
+      field,
+      untimed_signin_fields[USERNAME - UNTIMED_FIELDS_BEGIN]);
 
   // Time and status information of the possible sign in types.
   ListValue* detailed_info = AddSection(signin_info, "Last Signin Details");
-  for (; i < TIMED_FIELDS_END; ++i) {
+  for (int i = TIMED_FIELDS_BEGIN; i < TIMED_FIELDS_END; ++i) {
     const std::string value_field =
         SigninStatusFieldToLabel(static_cast<TimedSigninStatusField>(i)).first;
     const std::string time_field =
@@ -290,4 +268,23 @@
   return signin_status.Pass();
 }
 
+// Gets the first few hex characters of the SHA256 hash of the passed in string.
+// These are enough to perform equality checks across a single users tokens,
+// while preventing outsiders from reverse-engineering the actual token from
+// the displayed value.
+// Note that for readability (in about:signin-internals), an empty string
+// is not hashed, but simply returned as an empty string.
+std::string GetTruncatedHash(const std::string& str) {
+  if (str.empty())
+    return str;
+
+  // Since each character in the hash string generates two hex charaters
+  // we only need half as many charaters in |hash_val| as hex characters
+  // returned.
+  const int kTruncateSize = kTruncateTokenStringLength / 2;
+  char hash_val[kTruncateSize];
+  crypto::SHA256HashString(str, &hash_val[0], kTruncateSize);
+  return StringToLowerASCII(base::HexEncode(&hash_val[0], kTruncateSize));
+}
+
 } //  namespace signin_internals_util
diff --git a/chrome/browser/signin/signin_internals_util.h b/chrome/browser/signin/signin_internals_util.h
index 214159f..c662eca 100644
--- a/chrome/browser/signin/signin_internals_util.h
+++ b/chrome/browser/signin/signin_internals_util.h
@@ -23,9 +23,14 @@
 extern const char kProfileDownloaderToken[];
 extern const char kObfuscatedGaiaIdFetcherToken[];
 extern const char kOAuth2MintTokenFlowToken[];
+extern const char kSIDToken[];
+extern const char kLSIDToken[];
 extern const char* kTokenPrefsArray[];
 extern const size_t kNumTokenPrefs;
 
+// The length of strings returned by GetTruncatedHash() below.
+const size_t kTruncateTokenStringLength = 6;
+
 // Helper enums to access fields from SigninStatus (declared below).
 enum {
   SIGNIN_FIELDS_BEGIN = 0,
@@ -63,13 +68,13 @@
 // values, we replicate the service name within this struct for a cleaner
 // serialization (with ToValue()).
 struct TokenInfo {
-  std::string token;    // The actual token.
-  std::string status;   // Status of the last token fetch.
-  std::string time;     // Timestamp of the last token fetch
+  std::string truncated_token;  // The hashed and truncated token.
+  std::string status;  // Status of the last token fetch.
+  std::string time;  // Timestamp of the last token fetch
   int64 time_internal;  // Same as |time|, but in base::Time internal format.
   std::string service;  // The service that this token is for.
 
-  TokenInfo(const std::string& token,
+  TokenInfo(const std::string& truncated_token,
             const std::string& status,
             const std::string& time,
             const int64& time_internal,
@@ -141,6 +146,14 @@
 
 };
 
+// Gets the first 6 hex characters of the SHA256 hash of the passed in string.
+// These are enough to perform equality checks across a single users tokens,
+// while preventing outsiders from reverse-engineering the actual token from
+// the displayed value.
+// Note that for readability (in about:signin-internals), an empty string
+// is not hashed, but simply returned as an empty string.
+std::string GetTruncatedHash(const std::string& str);
+
 } // namespace signin_internals_util
 
 #endif  // CHROME_BROWSER_SIGNIN_SIGNIN_INTERNALS_UTIL_H_
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index 09a4862..119e680 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -350,9 +350,6 @@
 
   // Erase (now) stale information from AboutSigninInternals.
   NotifyDiagnosticsObservers(USERNAME, "");
-  NotifyDiagnosticsObservers(LSID, "");
-  NotifyDiagnosticsObservers(
-      signin_internals_util::SID, "");
 
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
@@ -500,9 +497,6 @@
   last_result_ = result;
   // Update signin_internals_
   NotifyDiagnosticsObservers(CLIENT_LOGIN_STATUS, "Successful");
-  NotifyDiagnosticsObservers(LSID, result.lsid);
-  NotifyDiagnosticsObservers(
-      signin_internals_util::SID, result.sid);
   // Make a request for the canonical email address and services.
   client_login_->StartGetUserInfo(result.lsid);
 }
diff --git a/chrome/browser/signin/token_service.cc b/chrome/browser/signin/token_service.cc
index 6de5e32..2367348 100644
--- a/chrome/browser/signin/token_service.cc
+++ b/chrome/browser/signin/token_service.cc
@@ -33,8 +33,7 @@
 
 // List of services that are capable of ClientLogin-based authentication.
 const char* kServices[] = {
-  GaiaConstants::kSyncService,
-  GaiaConstants::kLSOService
+  GaiaConstants::kSyncService
 };
 
 #define FOR_DIAGNOSTICS_OBSERVERS(func)                               \
@@ -110,23 +109,6 @@
   token_map_[service] = auth_token;
   FireTokenAvailableNotification(service, auth_token);
   SaveAuthTokenToDB(service, auth_token);
-
-// We don't ever want to fetch OAuth2 tokens from LSO service token in case
-// when ChromeOS is in forced OAuth2 use mode. OAuth2 token should only
-// arrive into token service exclusively through UpdateCredentialsWithOAuth2.
-#if !defined(OS_CHROMEOS)
-  // If we got ClientLogin token for "lso" service, and we don't already have
-  // OAuth2 tokens, start fetching OAuth2 login scoped token pair.
-  if (service == GaiaConstants::kLSOService && !HasOAuthLoginToken()) {
-    int index = GetServiceIndex(service);
-    CHECK_GE(index, 0);
-    // iOS fetches the service tokens outside of the TokenService.
-    if (!fetchers_[index].get()) {
-      fetchers_[index].reset(new GaiaAuthFetcher(this, source_, getter_.get()));
-    }
-    fetchers_[index]->StartLsoForOAuthLoginTokenExchange(auth_token);
-  }
-#endif
 }
 
 
@@ -163,9 +145,12 @@
   }
 
   // Notify AboutSigninInternals that a new lsid and sid are available.
-  FOR_DIAGNOSTICS_OBSERVERS(NotifySigninValueChanged(
-      signin_internals_util::SID, credentials.sid));
-  FOR_DIAGNOSTICS_OBSERVERS(NotifySigninValueChanged(LSID, credentials.lsid));
+  FOR_DIAGNOSTICS_OBSERVERS(
+      NotifyTokenReceivedSuccess(signin_internals_util::kSIDToken,
+                                 credentials.sid, true));
+  FOR_DIAGNOSTICS_OBSERVERS(
+      NotifyTokenReceivedSuccess(signin_internals_util::kLSIDToken,
+                                 credentials.lsid, true));
 }
 
 void TokenService::UpdateCredentialsWithOAuth2(
@@ -414,10 +399,12 @@
       sid = db_tokens.find(GaiaConstants::kGaiaSid)->second;
 
     if (!lsid.empty() && !sid.empty()) {
-      FOR_DIAGNOSTICS_OBSERVERS(NotifySigninValueChanged(
-          signin_internals_util::SID, sid));
-      FOR_DIAGNOSTICS_OBSERVERS(NotifySigninValueChanged(LSID, lsid));
-
+      FOR_DIAGNOSTICS_OBSERVERS(
+          NotifyTokenReceivedSuccess(signin_internals_util::kSIDToken, sid,
+                                     false));
+      FOR_DIAGNOSTICS_OBSERVERS(
+          NotifyTokenReceivedSuccess(signin_internals_util::kLSIDToken, lsid,
+                                     false));
       credentials_ = GaiaAuthConsumer::ClientLoginResult(sid,
                                                          lsid,
                                                          std::string(),
diff --git a/chrome/browser/signin/token_service.h b/chrome/browser/signin/token_service.h
index 5ab612c..d064796 100644
--- a/chrome/browser/signin/token_service.h
+++ b/chrome/browser/signin/token_service.h
@@ -247,7 +247,7 @@
   // number of entries in this array must match the number of entries in the
   // kServices array declared in the cc file.  If not, a compile time error
   // will occur.
-  scoped_ptr<GaiaAuthFetcher> fetchers_[2];
+  scoped_ptr<GaiaAuthFetcher> fetchers_[1];
 
   // Map from service to token.
   std::map<std::string, std::string> token_map_;
diff --git a/chrome/browser/signin/token_service_unittest.cc b/chrome/browser/signin/token_service_unittest.cc
index 0617ae5..f934764 100644
--- a/chrome/browser/signin/token_service_unittest.cc
+++ b/chrome/browser/signin/token_service_unittest.cc
@@ -64,7 +64,8 @@
   oauth_token_ = "oauth";
   oauth_secret_ = "secret";
 
-  profile_.reset(new TestingProfile());
+  profile_ = CreateProfile().Pass();
+
   profile_->CreateWebDataService();
 
   // Force the loading of the WebDataService.
@@ -81,6 +82,10 @@
   service()->Initialize("test", profile_.get());
 }
 
+scoped_ptr<TestingProfile> TokenServiceTestHarness::CreateProfile() {
+  return make_scoped_ptr(new TestingProfile());
+}
+
 void TokenServiceTestHarness::TearDown() {
   // You have to destroy the profile before the threads are shut down.
   profile_.reset();
diff --git a/chrome/browser/signin/token_service_unittest.h b/chrome/browser/signin/token_service_unittest.h
index 34aa043..3039be3 100644
--- a/chrome/browser/signin/token_service_unittest.h
+++ b/chrome/browser/signin/token_service_unittest.h
@@ -63,6 +63,7 @@
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
+  virtual scoped_ptr<TestingProfile> CreateProfile();
   void UpdateCredentialsOnService();
   TestingProfile* profile() const { return profile_.get(); }
   TokenService* service() const { return service_; }
diff --git a/chrome/browser/signin/ubertoken_fetcher_unittest.cc b/chrome/browser/signin/ubertoken_fetcher_unittest.cc
index 569025a..1592d4d 100644
--- a/chrome/browser/signin/ubertoken_fetcher_unittest.cc
+++ b/chrome/browser/signin/ubertoken_fetcher_unittest.cc
@@ -64,13 +64,17 @@
  public:
   virtual void SetUp() OVERRIDE {
     TokenServiceTestHarness::SetUp();
-
-    ProfileOAuth2TokenServiceFactory::GetInstance()->
-        SetTestingFactoryAndUse(profile(), Build);
     UpdateCredentialsOnService();
     fetcher_.reset(new UbertokenFetcher(profile(), &consumer_));
   }
 
+  virtual scoped_ptr<TestingProfile> CreateProfile() OVERRIDE {
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              Build);
+    return builder.Build().Pass();
+  }
+
   virtual void TearDown() OVERRIDE {
     fetcher_.reset();
     TokenServiceTestHarness::TearDown();
diff --git a/chrome/browser/speech/tts_message_filter.cc b/chrome/browser/speech/tts_message_filter.cc
index 6b94b8c..714c51f 100644
--- a/chrome/browser/speech/tts_message_filter.cc
+++ b/chrome/browser/speech/tts_message_filter.cc
@@ -17,6 +17,7 @@
 TtsMessageFilter::TtsMessageFilter(int render_process_id, Profile* profile)
     : render_process_id_(render_process_id),
       profile_(profile) {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   TtsController::GetInstance()->AddVoicesChangedDelegate(this);
 }
 
@@ -48,10 +49,13 @@
 }
 
 void TtsMessageFilter::OnChannelClosing() {
-  TtsController::GetInstance()->RemoveVoicesChangedDelegate(this);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&TtsMessageFilter::OnChannelClosingInUIThread, this));
 }
 
 void TtsMessageFilter::OnInitializeVoiceList() {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   TtsController* tts_controller = TtsController::GetInstance();
   std::vector<VoiceData> voices;
   tts_controller->GetVoices(profile_, &voices);
@@ -70,6 +74,7 @@
 }
 
 void TtsMessageFilter::OnSpeak(const TtsUtteranceRequest& request) {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   scoped_ptr<Utterance> utterance(new Utterance(profile_));
   utterance->set_src_id(request.id);
   utterance->set_text(request.text);
@@ -89,14 +94,17 @@
 }
 
 void TtsMessageFilter::OnPause() {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   TtsController::GetInstance()->Pause();
 }
 
 void TtsMessageFilter::OnResume() {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   TtsController::GetInstance()->Resume();
 }
 
 void TtsMessageFilter::OnCancel() {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   TtsController::GetInstance()->Stop();
 }
 
@@ -104,6 +112,7 @@
                                   TtsEventType event_type,
                                   int char_index,
                                   const std::string& error_message) {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   switch (event_type) {
     case TTS_EVENT_START:
       Send(new TtsMsg_DidStartSpeaking(utterance->src_id()));
@@ -140,8 +149,14 @@
 }
 
 void TtsMessageFilter::OnVoicesChanged() {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   OnInitializeVoiceList();
 }
 
+void TtsMessageFilter::OnChannelClosingInUIThread() {
+  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  TtsController::GetInstance()->RemoveVoicesChangedDelegate(this);
+}
+
 TtsMessageFilter::~TtsMessageFilter() {
 }
diff --git a/chrome/browser/speech/tts_message_filter.h b/chrome/browser/speech/tts_message_filter.h
index 767a9c0..97fb329 100644
--- a/chrome/browser/speech/tts_message_filter.h
+++ b/chrome/browser/speech/tts_message_filter.h
@@ -44,6 +44,8 @@
   void OnResume();
   void OnCancel();
 
+  void OnChannelClosingInUIThread();
+
   int render_process_id_;
   Profile* profile_;
 
diff --git a/chrome/browser/spellchecker/feedback.cc b/chrome/browser/spellchecker/feedback.cc
index 42bebbc..b571a53 100644
--- a/chrome/browser/spellchecker/feedback.cc
+++ b/chrome/browser/spellchecker/feedback.cc
@@ -19,6 +19,8 @@
 #include <algorithm>
 #include <iterator>
 
+#include "base/stl_util.h"
+
 namespace spellcheck {
 
 Feedback::Feedback() {
@@ -44,12 +46,9 @@
   HashCollection& renderer_hashes = renderer_it->second;
   HashCollection remaining_hashes(remaining_markers.begin(),
                                   remaining_markers.end());
-  std::vector<uint32> removed_hashes;
-  std::set_difference(renderer_hashes.begin(),
-                      renderer_hashes.end(),
-                      remaining_hashes.begin(),
-                      remaining_hashes.end(),
-                      std::back_inserter(removed_hashes));
+  std::vector<uint32> removed_hashes =
+      base::STLSetDifference<std::vector<uint32> >(renderer_hashes,
+                                                   remaining_hashes);
   for (std::vector<uint32>::const_iterator hash_it = removed_hashes.begin();
        hash_it != removed_hashes.end();
        ++hash_it) {
diff --git a/chrome/browser/spellchecker/feedback_sender.cc b/chrome/browser/spellchecker/feedback_sender.cc
index f8d4957..8943667 100644
--- a/chrome/browser/spellchecker/feedback_sender.cc
+++ b/chrome/browser/spellchecker/feedback_sender.cc
@@ -345,12 +345,9 @@
   // longer alive.
   std::vector<int> known_renderers = feedback_.GetRendersWithMisspellings();
   std::sort(known_renderers.begin(), known_renderers.end());
-  std::vector<int> dead_renderers;
-  std::set_difference(known_renderers.begin(),
-                      known_renderers.end(),
-                      alive_renderers.begin(),
-                      alive_renderers.end(),
-                      std::back_inserter(dead_renderers));
+  std::vector<int> dead_renderers =
+      base::STLSetDifference<std::vector<int> >(known_renderers,
+                                                alive_renderers);
   for (std::vector<int>::const_iterator it = dead_renderers.begin();
        it != dead_renderers.end();
        ++it) {
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
index c5c8163..4872b4e 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
@@ -129,12 +129,7 @@
 int SanitizeWordsToAdd(const WordSet& existing, WordList& to_add) {
   // Do not add duplicate words.
   std::sort(to_add.begin(), to_add.end());
-  WordList new_words;
-  std::set_difference(to_add.begin(),
-                      to_add.end(),
-                      existing.begin(),
-                      existing.end(),
-                      std::back_inserter(new_words));
+  WordList new_words = base::STLSetDifference<WordList>(to_add, existing);
   new_words.erase(std::unique(new_words.begin(), new_words.end()),
                   new_words.end());
   int result = VALID_CHANGE;
@@ -328,12 +323,8 @@
 
   // Add as many as possible local words remotely.
   std::sort(to_add_locally.begin(), to_add_locally.end());
-  WordList to_add_remotely;
-  std::set_difference(words_.begin(),
-                      words_.end(),
-                      to_add_locally.begin(),
-                      to_add_locally.end(),
-                      std::back_inserter(to_add_remotely));
+  WordList to_add_remotely = base::STLSetDifference<WordList>(words_,
+                                                              to_add_locally);
 
   // Send local changes to the sync server.
   Change to_change_remotely(to_add_remotely);
@@ -431,12 +422,9 @@
 
   // Remove words.
   std::sort(custom_words.begin(), custom_words.end());
-  WordList remaining;
-  std::set_difference(custom_words.begin(),
-                      custom_words.end(),
-                      dictionary_change.to_remove().begin(),
-                      dictionary_change.to_remove().end(),
-                      std::back_inserter(remaining));
+  WordList remaining =
+      base::STLSetDifference<WordList>(custom_words,
+                                       dictionary_change.to_remove());
   std::swap(custom_words, remaining);
 
   SaveDictionaryFileReliably(custom_words, path);
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
index e20932d..72c73d6 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
@@ -25,6 +25,11 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_WIN)
+// For version specific disabled tests below (http://crbug.com/230534).
+#include "base/win/windows_version.h"
+#endif
+
 using base::HistogramBase;
 using base::HistogramSamples;
 using base::StatisticsRecorder;
@@ -1069,9 +1074,18 @@
 }
 
 TEST_F(SpellcheckCustomDictionaryTest, RecordSizeStatsCorrectly) {
+#if defined(OS_WIN)
+// Failing consistently on Win7. See crbug.com/230534.
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+    return;
+#endif
   // Record a baseline.
   SpellCheckHostMetrics::RecordCustomWordCountStats(123);
 
+  // Determine if test failures are due the statistics recorder not being
+  // available or because the histogram just isn't there: crbug.com/230534.
+  EXPECT_TRUE(StatisticsRecorder::IsActive());
+
   HistogramBase* histogram =
       StatisticsRecorder::FindHistogram("SpellCheck.CustomWords");
   ASSERT_TRUE(histogram != NULL);
diff --git a/chrome/browser/spellchecker/spellcheck_host_metrics_unittest.cc b/chrome/browser/spellchecker/spellcheck_host_metrics_unittest.cc
index 3812d4b..37df690 100644
--- a/chrome/browser/spellchecker/spellcheck_host_metrics_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_host_metrics_unittest.cc
@@ -13,6 +13,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_WIN)
+// For version specific disabled tests below (http://crbug.com/230534).
+#include "base/win/windows_version.h"
+#endif
+
 using base::HistogramBase;
 using base::HistogramSamples;
 using base::StatisticsRecorder;
@@ -67,8 +72,17 @@
 }
 
 TEST_F(SpellcheckHostMetricsTest, CustomWordStats) {
+#if defined(OS_WIN)
+// Failing consistently on Win7. See crbug.com/230534.
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+    return;
+#endif
   SpellCheckHostMetrics::RecordCustomWordCountStats(123);
 
+  // Determine if test failures are due the statistics recorder not being
+  // available or because the histogram just isn't there: crbug.com/230534.
+  EXPECT_TRUE(StatisticsRecorder::IsActive());
+
   HistogramBase* histogram =
       StatisticsRecorder::FindHistogram("SpellCheck.CustomWords");
   ASSERT_TRUE(histogram != NULL);
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc b/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc
index 812c5ce..c0e469b 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc
+++ b/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc
@@ -79,6 +79,7 @@
                                  int render_process_id)
     : local_pending_(true),
       remote_pending_(true),
+      remote_success_(false),
       client_(client),
       destination_(destination),
       render_process_id_(render_process_id),
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 a259ef1..1918368 100644
--- a/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
+++ b/chrome/browser/storage_monitor/image_capture_device_manager_unittest.mm
@@ -262,6 +262,10 @@
     monitor_ = chrome::test::TestStorageMonitor::CreateAndInstall();
   }
 
+  virtual void TearDown() OVERRIDE {
+    chrome::test::TestStorageMonitor::RemoveSingleton();
+  }
+
   MockICCameraDevice* AttachDevice(
       chrome::ImageCaptureDeviceManager* manager) {
     // Ownership will be passed to the device browser delegate.
diff --git a/chrome/browser/storage_monitor/media_storage_util_unittest.cc b/chrome/browser/storage_monitor/media_storage_util_unittest.cc
index 4ed217e..a07260b 100644
--- a/chrome/browser/storage_monitor/media_storage_util_unittest.cc
+++ b/chrome/browser/storage_monitor/media_storage_util_unittest.cc
@@ -70,6 +70,7 @@
 
   virtual void TearDown() OVERRIDE {
     WaitForFileThread();
+    chrome::test::TestStorageMonitor::RemoveSingleton();
   }
 
   static void PostQuitToUIThread() {
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 e3ace3f..78471c6 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
@@ -110,6 +110,7 @@
     StorageMonitor* monitor = g_browser_process->storage_monitor();
     monitor->RemoveObserver(mock_storage_observer_.get());
     mtp_device_observer_.reset();
+    chrome::test::TestStorageMonitor::RemoveSingleton();
   }
 
   // Returns the device changed observer object.
diff --git a/chrome/browser/storage_monitor/storage_monitor.h b/chrome/browser/storage_monitor/storage_monitor.h
index f008dca..a11596b 100644
--- a/chrome/browser/storage_monitor/storage_monitor.h
+++ b/chrome/browser/storage_monitor/storage_monitor.h
@@ -21,7 +21,6 @@
 class ChromeBrowserMainPartsMac;
 class MediaGalleriesPlatformAppBrowserTest;
 class MediaGalleriesPrivateApiTest;
-class MediaGalleriesPrivateEjectApiTest;
 class SystemStorageApiTest;
 class SystemStorageEjectApiTest;
 
@@ -137,7 +136,6 @@
  protected:
   friend class ::MediaGalleriesPlatformAppBrowserTest;
   friend class ::MediaGalleriesPrivateApiTest;
-  friend class ::MediaGalleriesPrivateEjectApiTest;
   friend class MediaFileSystemRegistryTest;
   friend class ::SystemStorageApiTest;
   friend class ::SystemStorageEjectApiTest;
diff --git a/chrome/browser/storage_monitor/test_storage_monitor.cc b/chrome/browser/storage_monitor/test_storage_monitor.cc
index b4a04a6..5967f9a 100644
--- a/chrome/browser/storage_monitor/test_storage_monitor.cc
+++ b/chrome/browser/storage_monitor/test_storage_monitor.cc
@@ -32,13 +32,13 @@
 
 // static
 TestStorageMonitor* TestStorageMonitor::CreateAndInstall() {
-  RemoveSingleton();
   TestStorageMonitor* monitor = new TestStorageMonitor();
   scoped_ptr<StorageMonitor> pass_monitor(monitor);
   monitor->Init();
   monitor->MarkInitialized();
   TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal();
   if (browser_process) {
+    DCHECK(browser_process->storage_monitor() == NULL);
     browser_process->SetStorageMonitor(pass_monitor.Pass());
     return monitor;
   }
diff --git a/chrome/browser/sync/glue/device_info.cc b/chrome/browser/sync/glue/device_info.cc
index 486c8bb..dc21190 100644
--- a/chrome/browser/sync/glue/device_info.cc
+++ b/chrome/browser/sync/glue/device_info.cc
@@ -44,22 +44,36 @@
 std::string DeviceTypeToString(sync_pb::SyncEnums::DeviceType device_type) {
   switch (device_type) {
     case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
-      return "WIN";
     case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
-      return "MAC";
     case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
-      return "LINUX";
     case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
-      return "CHROME OS";
-    case sync_pb::SyncEnums_DeviceType_TYPE_OTHER:
-      return "OTHER";
+      return "desktop_or_laptop";
     case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
-      return "PHONE";
+      return "phone";
     case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
-      return "TABLET";
+      return "tablet";
     default:
-      NOTREACHED();
-      return "UNKNOWN";
+      return "unknown";
+  }
+}
+
+std::string GetOS(sync_pb::SyncEnums::DeviceType device_type) {
+  switch (device_type) {
+    case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
+      return "win";
+    case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
+      return "mac";
+    case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
+      return "linux";
+    case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
+      return "chrome_os";
+    case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
+    case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
+      // TODO(lipalani): crbug.com/170375. Add support for ios
+      // phones and tablets.
+      return "android";
+    default:
+      return "unknown";
   }
 }
 
@@ -172,10 +186,10 @@
 
 base::DictionaryValue* DeviceInfo::ToValue() {
   base::DictionaryValue* value = new base::DictionaryValue();
-  value->SetString("Id", public_id_);
-  value->SetString("Client Name", client_name_);
-  value->SetString("Chrome Version", chrome_version_);
-  value->SetString("Sync User Agent", sync_user_agent_);
+  value->SetString("id", public_id_);
+  value->SetString("name", client_name_);
+  value->SetString("chromeVersion", chrome_version_);
+  value->SetString("os", GetOS(device_type_));
   value->SetString("Device Type", DeviceTypeToString(device_type_));
   return value;
 }
diff --git a/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc b/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
index bfeeb21..3f17c4b 100644
--- a/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
+++ b/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
@@ -12,9 +12,9 @@
 #include "chrome/browser/extensions/api/bookmarks/bookmarks_api.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest_constants.h"
 #include "sync/util/extensions_activity.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -25,7 +25,7 @@
 namespace {
 
 using content::BrowserThread;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 // Create and return an extension with the given path.
 scoped_refptr<Extension> MakeExtension(const std::string& name) {
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 40d198a..4c0426b 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -409,7 +409,7 @@
 }
 
 ScopedVector<browser_sync::DeviceInfo>
-    ProfileSyncService::GetAllSignedInDevices() const {
+    ProfileSyncService::GetAllSignedinDevices() const {
   ScopedVector<browser_sync::DeviceInfo> devices;
   if (backend_) {
     browser_sync::SyncedDeviceTracker* device_tracker =
@@ -537,11 +537,6 @@
 
   DCHECK(IsSyncEnabledAndLoggedIn());
 
-  if (use_oauth2_token_ && access_token_.empty()) {
-    RequestAccessToken();
-    return;
-  }
-
   if (start_up_time_.is_null()) {
     start_up_time_ = base::Time::Now();
     last_synced_time_ = sync_prefs_.GetLastSyncedTime();
@@ -670,8 +665,6 @@
     }
     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
       // Report time since token was issued for invalid credentials error.
-      // TODO(pavely): crbug.com/246817 Collect UMA histogram for auth token
-      // rejections from invalidation service.
       base::Time auth_token_time =
           AboutSigninInternalsFactory::GetForProfile(profile_)->
               GetTokenTime(GaiaConstants::kGaiaOAuth2LoginRefreshToken);
@@ -702,8 +695,7 @@
 }
 
 void ProfileSyncService::OnRefreshTokenRevoked(
-    const std::string& account_id,
-    const GoogleServiceAuthError& error) {
+    const std::string& account_id) {
   if (!IsOAuthRefreshTokenAvailable()) {
     // The additional check around IsOAuthRefreshTokenAvailable() above
     // prevents us sounding the alarm if we actually have a valid token but
@@ -711,7 +703,8 @@
     // (e.g. flaky network). It's possible the token we do have is also
     // invalid, but in that case we should already have (or can expect) an
     // auth error sent from the sync backend.
-    UpdateAuthErrorState(error);
+    UpdateAuthErrorState(
+        GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
   }
 }
 
@@ -1419,6 +1412,14 @@
 }
 
 GoogleServiceAuthError ProfileSyncService::GetAuthStatus() const {
+  // If waiting_for_auth() returns true, it means that ProfileSyncService has
+  // detected that the user has just successfully completed gaia signin, but the
+  // backend is yet to update its connection state. In such a case, we do not
+  // want to continue surfacing an auth error to the UI via SigninGlobalError.
+  // Otherwise, it will make for a confusing UX, since the user just re-entered
+  // their credentials. See http://crbug.com/261317.
+  if (waiting_for_auth())
+    return AuthError::AuthErrorNone();
   return GetAuthError();
 }
 
@@ -1970,6 +1971,14 @@
           GetAuthError().state() != AuthError::NONE) {
         // Track the fact that we're still waiting for auth to complete.
         is_auth_in_progress_ = true;
+
+        // The user has just successfully completed re-auth, so immediately
+        // clear any auth error that was showing in the UI. If the backend is
+        // yet to update its connection state, GetAuthStatus() will return
+        // AuthError::NONE while |is_auth_in_progress_| is set to true.
+        // See http://crbug.com/261317.
+        if (profile_)
+          SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
       }
       break;
     }
diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h
index ff1721b..f0bf397 100644
--- a/chrome/browser/sync/profile_sync_service.h
+++ b/chrome/browser/sync/profile_sync_service.h
@@ -269,7 +269,7 @@
   // null.
   // TODO(zea): Figure out a better way to expose this to the UI elements that
   // need it.
-  browser_sync::SessionModelAssociator* GetSessionModelAssociator();
+  virtual browser_sync::SessionModelAssociator* GetSessionModelAssociator();
 
   // Returns sync's representation of the local device info.
   // Return value is an empty scoped_ptr if the device info is unavailable.
@@ -283,7 +283,7 @@
 
   // Gets the device info for all devices signed into the account associated
   // with this profile.
-  virtual ScopedVector<browser_sync::DeviceInfo> GetAllSignedInDevices() const;
+  virtual ScopedVector<browser_sync::DeviceInfo> GetAllSignedinDevices() const;
 
   // Fills state_map with a map of current data types that are possible to
   // sync, as well as their states.
@@ -610,9 +610,7 @@
 
   // OAuth2TokenService::Observer implementation.
   virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
-  virtual void OnRefreshTokenRevoked(
-      const std::string& account_id,
-      const GoogleServiceAuthError& error) OVERRIDE;
+  virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE;
   virtual void OnRefreshTokensLoaded() OVERRIDE;
   virtual void OnRefreshTokensCleared() OVERRIDE;
 
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index 1af7644..4f03967 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -377,7 +377,7 @@
  public:
   virtual DataTypeController* CreateDataTypeController(
       ProfileSyncComponentsFactory* factory,
-      ProfileMock* profile,
+      TestingProfile* profile,
       ProfileSyncService* service) = 0;
   virtual void SetExpectation(ProfileSyncComponentsFactoryMock* factory,
                               ProfileSyncService* service,
@@ -390,7 +390,7 @@
  public:
   virtual browser_sync::DataTypeController* CreateDataTypeController(
       ProfileSyncComponentsFactory* factory,
-      ProfileMock* profile,
+      TestingProfile* profile,
       ProfileSyncService* service) OVERRIDE {
     return new AutofillDataTypeController(factory, profile, service);
   }
@@ -412,7 +412,7 @@
  public:
   virtual browser_sync::DataTypeController* CreateDataTypeController(
       ProfileSyncComponentsFactory* factory,
-      ProfileMock* profile,
+      TestingProfile* profile,
       ProfileSyncService* service) OVERRIDE {
     return new AutofillProfileDataTypeController(factory, profile, service);
   }
@@ -503,7 +503,10 @@
 
   virtual void SetUp() OVERRIDE {
     AbstractProfileSyncServiceTest::SetUp();
-    profile_.reset(new ProfileMock());
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeOAuth2TokenService::BuildTokenService);
+    profile_ = builder.Build().Pass();
     web_database_.reset(new WebDatabaseFake(&autofill_table_));
     MockWebDataServiceWrapper* wrapper =
         static_cast<MockWebDataServiceWrapper*>(
@@ -524,8 +527,6 @@
     token_service_ = static_cast<TokenService*>(
         TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
             profile_.get(), BuildTokenService));
-    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), FakeOAuth2TokenService::BuildTokenService);
     EXPECT_CALL(*personal_data_manager_, LoadProfiles()).Times(1);
     EXPECT_CALL(*personal_data_manager_, LoadCreditCards()).Times(1);
 
@@ -757,7 +758,7 @@
   friend class AddAutofillHelper<AutofillProfile>;
   friend class FakeServerUpdater;
 
-  scoped_ptr<ProfileMock> profile_;
+  scoped_ptr<TestingProfile> profile_;
   AutofillTableMock autofill_table_;
   scoped_ptr<WebDatabaseFake> web_database_;
   scoped_refptr<WebDataServiceFake> web_data_service_;
diff --git a/chrome/browser/sync/profile_sync_service_mock.cc b/chrome/browser/sync/profile_sync_service_mock.cc
index 150273b..6985cce 100644
--- a/chrome/browser/sync/profile_sync_service_mock.cc
+++ b/chrome/browser/sync/profile_sync_service_mock.cc
@@ -41,11 +41,11 @@
 }
 
 ScopedVector<browser_sync::DeviceInfo>
-      ProfileSyncServiceMock::GetAllSignedInDevices() const {
-    ScopedVector<browser_sync::DeviceInfo> devices;
-    std::vector<browser_sync::DeviceInfo*>* device_vector =
-        GetAllSignedInDevicesMock();
-    devices.get() = *device_vector;
-    return devices.Pass();
+    ProfileSyncServiceMock::GetAllSignedinDevices() const {
+  ScopedVector<browser_sync::DeviceInfo> devices;
+  std::vector<browser_sync::DeviceInfo*>* device_vector =
+      GetAllSignedinDevicesMock();
+  devices.get() = *device_vector;
+  return devices.Pass();
 }
 
diff --git a/chrome/browser/sync/profile_sync_service_mock.h b/chrome/browser/sync/profile_sync_service_mock.h
index 116185a..9cb444f 100644
--- a/chrome/browser/sync/profile_sync_service_mock.h
+++ b/chrome/browser/sync/profile_sync_service_mock.h
@@ -20,6 +20,8 @@
 #include "sync/protocol/sync_protocol_error.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
+using ::testing::Invoke;
+
 class ProfileSyncServiceMock : public ProfileSyncService {
  public:
   // no-arg constructor provided so TestingProfile can use NiceMock.
@@ -96,11 +98,13 @@
       const syncer::SyncProtocolError&));
   MOCK_METHOD1(SetSetupInProgress, void(bool));
 
-  MOCK_CONST_METHOD0(GetAllSignedInDevicesMock,
+  MOCK_METHOD0(GetSessionModelAssociator,
+               browser_sync::SessionModelAssociator*());
+  MOCK_CONST_METHOD0(GetAllSignedinDevicesMock,
                      std::vector<browser_sync::DeviceInfo*>* ());
   // This is to get around the fact that GMOCK does not handle Scoped*.
   virtual ScopedVector<browser_sync::DeviceInfo>
-      GetAllSignedInDevices() const OVERRIDE;
+      GetAllSignedinDevices() const OVERRIDE;
 
   // DataTypeManagerObserver mocks.
   MOCK_METHOD0(OnConfigureBlocked, void());
diff --git a/chrome/browser/sync/profile_sync_service_password_unittest.cc b/chrome/browser/sync/profile_sync_service_password_unittest.cc
index 17b9523..3dbdb19 100644
--- a/chrome/browser/sync/profile_sync_service_password_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_password_unittest.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/sync/test_profile_sync_service.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/test/base/profile_mock.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/common/password_form.h"
 #include "content/public/test/mock_notification_observer.h"
@@ -154,7 +153,10 @@
 
   virtual void SetUp() {
     AbstractProfileSyncServiceTest::SetUp();
-    profile_.reset(new ProfileMock());
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeOAuth2TokenService::BuildTokenService);
+    profile_ = builder.Build().Pass();
     invalidation::InvalidationServiceFactory::GetInstance()->
         SetBuildOnlyFakeInvalidatorsForTest(true);
     password_store_ = static_cast<MockPasswordStore*>(
@@ -192,8 +194,6 @@
       token_service_ = static_cast<TokenService*>(
           TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
               profile_.get(), BuildTokenService));
-      ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-          profile_.get(), FakeOAuth2TokenService::BuildTokenService);
 
       PasswordTestProfileSyncService* sync =
           static_cast<PasswordTestProfileSyncService*>(
@@ -256,8 +256,6 @@
       return true;
     if (pf1.username_value < pf2.username_value)
       return true;
-    if (pf1.username_value < pf2.username_value)
-      return true;
     if (pf1.password_element < pf2.password_element)
       return true;
     if (pf1.password_value < pf2.password_value)
@@ -314,7 +312,7 @@
   }
 
   content::MockNotificationObserver observer_;
-  scoped_ptr<ProfileMock> profile_;
+  scoped_ptr<TestingProfile> profile_;
   scoped_refptr<MockPasswordStore> password_store_;
   content::NotificationRegistrar registrar_;
 };
diff --git a/chrome/browser/sync/profile_sync_service_preference_unittest.cc b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
index 4d57c21..03b3e5d 100644
--- a/chrome/browser/sync/profile_sync_service_preference_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_preference_unittest.cc
@@ -123,7 +123,10 @@
 
   virtual void SetUp() {
     AbstractProfileSyncServiceTest::SetUp();
-    profile_.reset(new TestingProfile());
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeOAuth2TokenService::BuildTokenService);
+    profile_ = builder.Build().Pass();
     invalidation::InvalidationServiceFactory::GetInstance()->
         SetBuildOnlyFakeInvalidatorsForTest(true);
     prefs_ = profile_->GetTestingPrefService();
@@ -156,8 +159,6 @@
     SigninManagerBase* signin =
          SigninManagerFactory::GetForProfile(profile_.get());
     signin->SetAuthenticatedUsername("test");
-    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), FakeOAuth2TokenService::BuildTokenService);
     sync_service_ = static_cast<TestProfileSyncService*>(
         ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
             profile_.get(), &TestProfileSyncService::BuildAutoStartAsyncInit));
diff --git a/chrome/browser/sync/profile_sync_service_session_unittest.cc b/chrome/browser/sync/profile_sync_service_session_unittest.cc
index 592a826..1b4e173 100644
--- a/chrome/browser/sync/profile_sync_service_session_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_session_unittest.cc
@@ -212,13 +212,15 @@
 
  protected:
   virtual TestingProfile* CreateProfile() OVERRIDE {
-    TestingProfile* profile = new TestingProfile();
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeOAuth2TokenService::BuildTokenService);
     // Don't want the profile to create a real ProfileSyncService.
-    ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(profile,
-                                                                NULL);
+    builder.AddTestingFactory(ProfileSyncServiceFactory::GetInstance(), NULL);
+    scoped_ptr<TestingProfile> profile(builder.Build());
     invalidation::InvalidationServiceFactory::GetInstance()->
         SetBuildOnlyFakeInvalidatorsForTest(true);
-    return profile;
+    return profile.release();
   }
 
   virtual void SetUp() {
@@ -271,8 +273,6 @@
     SigninManagerBase* signin =
         SigninManagerFactory::GetForProfile(profile());
     signin->SetAuthenticatedUsername("test_user");
-    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-        profile(), FakeOAuth2TokenService::BuildTokenService);
     ProfileSyncComponentsFactoryMock* factory =
         new ProfileSyncComponentsFactoryMock();
     sync_service_.reset(new FakeProfileSyncService(
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index f1bfd96..a1bdf31 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -68,6 +68,11 @@
         content::Source<TokenService>(this),
         content::NotificationService::NoDetails());
   }
+
+  static BrowserContextKeyedService* BuildFakeTokenService(
+      content::BrowserContext* profile) {
+    return new FakeTokenService();
+  }
 };
 
 class ProfileSyncServiceStartupTest : public testing::Test {
@@ -76,28 +81,35 @@
       : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
                        content::TestBrowserThreadBundle::REAL_FILE_THREAD |
                        content::TestBrowserThreadBundle::REAL_IO_THREAD),
-        profile_(new TestingProfile),
         sync_(NULL) {}
 
   virtual ~ProfileSyncServiceStartupTest() {
   }
 
   virtual void SetUp() {
+    profile_ = CreateProfile();
+  }
+
+  virtual scoped_ptr<TestingProfile> CreateProfile() {
+    TestingProfile::Builder builder;
 #if defined(OS_CHROMEOS)
-    SigninManagerFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), FakeSigninManagerBase::Build);
+    builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
+                              FakeSigninManagerBase::Build);
 #else
-    SigninManagerFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), FakeSigninManager::Build);
+    builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
+                              FakeSigninManager::Build);
 #endif
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeOAuth2TokenService::BuildTokenService);
+    builder.AddTestingFactory(ProfileSyncServiceFactory::GetInstance(),
+                              BuildService);
+    builder.AddTestingFactory(TokenServiceFactory::GetInstance(),
+                              FakeTokenService::BuildFakeTokenService);
+    return builder.Build();
   }
 
   virtual void TearDown() {
     sync_->RemoveObserver(&observer_);
-    ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), NULL);
-    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), NULL);
     profile_.reset();
 
     // Pump messages posted by the sync core thread (which may end up
@@ -118,11 +130,8 @@
   }
 
   void CreateSyncService() {
-    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), FakeOAuth2TokenService::BuildTokenService);
     sync_ = static_cast<TestProfileSyncService*>(
-        ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-            profile_.get(), BuildService));
+        ProfileSyncServiceFactory::GetForProfile(profile_.get()));
     sync_->AddObserver(&observer_);
     sync_->set_synchronous_sync_configuration();
   }
@@ -146,8 +155,6 @@
  public:
   virtual void SetUp() {
     ProfileSyncServiceStartupTest::SetUp();
-    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-        profile_.get(), FakeOAuth2TokenService::BuildTokenService);
     sync_ = static_cast<TestProfileSyncService*>(
         ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
             profile_.get(), BuildCrosService));
@@ -173,11 +180,6 @@
   }
 };
 
-BrowserContextKeyedService* BuildFakeTokenService(
-    content::BrowserContext* profile) {
-  return new FakeTokenService();
-}
-
 TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) {
   // We've never completed startup.
   profile_->GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
@@ -235,8 +237,7 @@
   SigninManagerFactory::GetForProfile(
       profile_.get())->Initialize(profile_.get(), NULL);
   TokenService* token_service = static_cast<TokenService*>(
-      TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          profile_.get(), BuildFakeTokenService));
+      TokenServiceFactory::GetForProfile(profile_.get()));
   CreateSyncService();
 
   // Should not actually start, rather just clean things up and wait
@@ -327,8 +328,7 @@
   profile_->GetPrefs()->ClearPref(prefs::kSyncHasSetupCompleted);
   EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
   TokenService* token_service = static_cast<TokenService*>(
-      TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          profile_.get(), BuildFakeTokenService));
+      TokenServiceFactory::GetForProfile(profile_.get()));
 
   sync_->Initialize();
   // Sync should not start because there are no tokens yet.
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 23c6edd..c1f2fd9 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -38,7 +38,6 @@
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/browser/sync/test_profile_sync_service.h"
-#include "chrome/test/base/profile_mock.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/browser_context_keyed_service/refcounted_browser_context_keyed_service.h"
 #include "content/public/browser/notification_service.h"
@@ -184,7 +183,10 @@
 
   virtual void SetUp() {
     AbstractProfileSyncServiceTest::SetUp();
-    profile_.reset(new ProfileMock());
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeOAuth2TokenService::BuildTokenService);
+    profile_ = builder.Build().Pass();
     invalidation::InvalidationServiceFactory::GetInstance()->
         SetBuildOnlyFakeInvalidatorsForTest(true);
     history_backend_ = new HistoryBackendMock();
@@ -214,8 +216,6 @@
       token_service_ = static_cast<TokenService*>(
           TokenServiceFactory::GetInstance()->SetTestingFactoryAndUse(
               profile_.get(), BuildTokenService));
-      ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-          profile_.get(), FakeOAuth2TokenService::BuildTokenService);
       sync_service_ = static_cast<TestProfileSyncService*>(
           ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
               profile_.get(),
@@ -322,7 +322,7 @@
 
   scoped_ptr<Thread> history_thread_;
 
-  scoped_ptr<ProfileMock> profile_;
+  scoped_ptr<TestingProfile> profile_;
   scoped_refptr<HistoryBackendMock> history_backend_;
   HistoryServiceMock* history_service_;
   browser_sync::DataTypeErrorHandlerMock error_handler_;
diff --git a/chrome/browser/sync/profile_sync_service_unittest.cc b/chrome/browser/sync/profile_sync_service_unittest.cc
index ff213c2..b2d1a53 100644
--- a/chrome/browser/sync/profile_sync_service_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_unittest.cc
@@ -59,11 +59,12 @@
    }
 
   void SetUp() {
-    profile.reset(new TestingProfile());
+    TestingProfile::Builder builder;
+    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
+                              FakeOAuth2TokenService::BuildTokenService);
+    profile = builder.Build().Pass();
     invalidation::InvalidationServiceFactory::GetInstance()->
         SetBuildOnlyFakeInvalidatorsForTest(true);
-    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
-        profile.get(), FakeOAuth2TokenService::BuildTokenService);
   }
 
   void TearDown() {
diff --git a/chrome/browser/sync/sessions2/tab_node_pool2.cc b/chrome/browser/sync/sessions2/tab_node_pool2.cc
new file mode 100644
index 0000000..459186b
--- /dev/null
+++ b/chrome/browser/sync/sessions2/tab_node_pool2.cc
@@ -0,0 +1,194 @@
+// Copyright 2013 The Chromium Authors. 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/sessions2/tab_node_pool2.h"
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/sync_data.h"
+#include "sync/internal_api/public/base/model_type.h"
+#include "sync/protocol/session_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
+
+namespace browser_sync {
+
+static const char kNoSessionsFolderError[] =
+    "Server did not create the top-level sessions node. We "
+    "might be running against an out-of-date server.";
+
+const size_t TabNodePool2::kFreeNodesLowWatermark = 25;
+const size_t TabNodePool2::kFreeNodesHighWatermark = 100;
+
+TabNodePool2::TabNodePool2()
+    : max_used_tab_node_id_(kInvalidTabNodeID) {}
+
+// static
+// We start vending tab node IDs at 0.
+const int TabNodePool2::kInvalidTabNodeID = -1;
+
+TabNodePool2::~TabNodePool2() {}
+
+// Static
+std::string TabNodePool2::TabIdToTag(
+    const std::string machine_tag, int tab_node_id) {
+  return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id);
+}
+
+void TabNodePool2::AddTabNode(int tab_node_id,
+                              const SessionID& tab_id) {
+  DCHECK_GT(tab_node_id, kInvalidTabNodeID);
+  DCHECK_GT(tab_id.id(), kInvalidTabID);
+  DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end());
+  unassociated_nodes_.insert(tab_node_id);
+  if (max_used_tab_node_id_ < tab_node_id)
+    max_used_tab_node_id_ = tab_node_id;
+}
+
+void TabNodePool2::AssociateTabNode(int tab_node_id,
+                                    SessionID::id_type tab_id) {
+  DCHECK_GT(tab_node_id, kInvalidTabNodeID);
+  // Remove sync node if it is in unassociated nodes pool.
+  std::set<int>::iterator u_it = unassociated_nodes_.find(tab_node_id);
+  if (u_it != unassociated_nodes_.end()) {
+    unassociated_nodes_.erase(u_it);
+  } else {
+    // This is a new node association, the sync node should be free.
+    // Remove node from free node pool and then associate it with the tab.
+    std::set<int>::iterator it = free_nodes_pool_.find(tab_node_id);
+    DCHECK(it != free_nodes_pool_.end());
+    free_nodes_pool_.erase(it);
+  }
+  DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end());
+  nodeid_tabid_map_[tab_node_id] = tab_id;
+}
+
+int TabNodePool2::GetFreeTabNode(syncer::SyncChangeList* append_changes) {
+  DCHECK_GT(machine_tag_.length(), 0U);
+  DCHECK(append_changes);
+  if (free_nodes_pool_.empty()) {
+    // Tab pool has no free nodes, allocate new one.
+    int tab_node_id = ++max_used_tab_node_id_;
+    std::string tab_node_tag = TabIdToTag(machine_tag_, tab_node_id);
+
+    // We fill the new node with just enough data so that in case of a crash/bug
+    // we can identify the node as our own on re-association and reuse it.
+    sync_pb::EntitySpecifics entity;
+    sync_pb::SessionSpecifics* specifics = entity.mutable_session();
+    specifics->set_session_tag(machine_tag_);
+    specifics->set_tab_node_id(tab_node_id);
+    append_changes->push_back(syncer::SyncChange(
+        FROM_HERE,
+        syncer::SyncChange::ACTION_ADD,
+        syncer::SyncData::CreateLocalData(tab_node_tag,
+                                          tab_node_tag,
+                                          entity)));
+
+    // Grow the pool by 1 since we created a new node.
+    DVLOG(1) << "Adding sync node " << tab_node_id
+             << " to tab node id pool";
+    free_nodes_pool_.insert(tab_node_id);
+    return tab_node_id;
+  } else {
+    // Return the next free node.
+    return *free_nodes_pool_.begin();
+  }
+}
+
+void TabNodePool2::FreeTabNode(int tab_node_id,
+                               syncer::SyncChangeList* append_changes) {
+  DCHECK(append_changes);
+  TabNodeIDToTabIDMap::iterator it = nodeid_tabid_map_.find(tab_node_id);
+  DCHECK(it != nodeid_tabid_map_.end());
+  nodeid_tabid_map_.erase(it);
+  FreeTabNodeInternal(tab_node_id, append_changes);
+}
+
+void TabNodePool2::FreeTabNodeInternal(
+    int tab_node_id,
+    syncer::SyncChangeList* append_changes) {
+  DCHECK(free_nodes_pool_.find(tab_node_id) == free_nodes_pool_.end());
+  DCHECK(append_changes);
+  free_nodes_pool_.insert(tab_node_id);
+
+  // If number of free nodes exceed kFreeNodesHighWatermark,
+  // delete sync nodes till number reaches kFreeNodesLowWatermark.
+  // Note: This logic is to mitigate temporary disassociation issues with old
+  // clients: http://crbug.com/259918. Newer versions do not need this.
+  if (free_nodes_pool_.size() > kFreeNodesHighWatermark) {
+    for (std::set<int>::iterator free_it = free_nodes_pool_.begin();
+         free_it != free_nodes_pool_.end();) {
+      const std::string tab_node_tag = TabIdToTag(machine_tag_, *free_it);
+      append_changes->push_back(syncer::SyncChange(
+          FROM_HERE,
+          syncer::SyncChange::ACTION_DELETE,
+          syncer::SyncData::CreateLocalDelete(tab_node_tag,
+                                              syncer::SESSIONS)));
+      free_nodes_pool_.erase(free_it++);
+      if (free_nodes_pool_.size() <= kFreeNodesLowWatermark) {
+        return;
+      }
+    }
+  }
+}
+
+bool TabNodePool2::IsUnassociatedTabNode(int tab_node_id) {
+  return unassociated_nodes_.find(tab_node_id) != unassociated_nodes_.end();
+}
+
+void TabNodePool2::ReassociateTabNode(int tab_node_id,
+                                      SessionID::id_type tab_id) {
+  // Remove from list of unassociated sync_nodes if present.
+  std::set<int>::iterator it = unassociated_nodes_.find(tab_node_id);
+  if (it != unassociated_nodes_.end()) {
+    unassociated_nodes_.erase(it);
+  } else {
+    // tab_node_id must be an already associated node.
+    DCHECK(nodeid_tabid_map_.find(tab_node_id) != nodeid_tabid_map_.end());
+  }
+  nodeid_tabid_map_[tab_node_id] = tab_id;
+}
+
+SessionID::id_type TabNodePool2::GetTabIdFromTabNodeId(
+    int tab_node_id) const {
+  TabNodeIDToTabIDMap::const_iterator it = nodeid_tabid_map_.find(tab_node_id);
+  if (it != nodeid_tabid_map_.end()) {
+    return it->second;
+  }
+  return kInvalidTabID;
+}
+
+void TabNodePool2::FreeUnassociatedTabNodes(
+    syncer::SyncChangeList* append_changes) {
+  for (std::set<int>::iterator it = unassociated_nodes_.begin();
+       it != unassociated_nodes_.end();) {
+    FreeTabNodeInternal(*it, append_changes);
+    unassociated_nodes_.erase(it++);
+  }
+  DCHECK(unassociated_nodes_.empty());
+}
+
+// Clear tab pool.
+void TabNodePool2::Clear() {
+  unassociated_nodes_.clear();
+  free_nodes_pool_.clear();
+  nodeid_tabid_map_.clear();
+  max_used_tab_node_id_ = kInvalidTabNodeID;
+}
+
+size_t TabNodePool2::Capacity() const {
+  return nodeid_tabid_map_.size() + unassociated_nodes_.size() +
+         free_nodes_pool_.size();
+}
+
+bool TabNodePool2::Empty() const { return free_nodes_pool_.empty(); }
+
+bool TabNodePool2::Full() { return nodeid_tabid_map_.empty(); }
+
+void TabNodePool2::SetMachineTag(const std::string& machine_tag) {
+  machine_tag_ = machine_tag;
+}
+
+}  // namespace browser_sync
diff --git a/chrome/browser/sync/sessions2/tab_node_pool2.h b/chrome/browser/sync/sessions2/tab_node_pool2.h
new file mode 100644
index 0000000..db3c8b5
--- /dev/null
+++ b/chrome/browser/sync/sessions2/tab_node_pool2.h
@@ -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.
+
+#ifndef CHROME_BROWSER_SYNC_SESSIONS2_TAB_NODE_POOL2_H_
+#define CHROME_BROWSER_SYNC_SESSIONS2_TAB_NODE_POOL2_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "chrome/browser/sessions/session_id.h"
+#include "sync/api/sync_change_processor.h"
+
+namespace syncer {
+class SyncChangeProcessor;
+}
+
+namespace browser_sync {
+
+// A pool for managing free/used tab sync nodes for the *local* session.
+// Performs lazy creation of sync nodes when necessary.
+// Note: We make use of the following "id's"
+// - a tab_id: created by session service, unique to this client
+// - a tab_node_id: the id for a particular sync tab node. This is used
+//   to generate the sync tab node tag through:
+//       tab_tag = StringPrintf("%s_%ui", local_session_tag, tab_node_id);
+//
+// A sync node can be in one of the three states:
+// 1. Associated   : Sync node is used and associated with a tab.
+// 2. Unassociated : Sync node is used but currently unassociated with any tab.
+//                   This is true for old nodes that remain from a session
+//                   restart. Nodes are only unassociated temporarily while the
+//                   model associator figures out which tabs belong to which
+//                   nodes. Eventually any remaining unassociated nodes are
+//                   freed.
+// 3. Free         : Sync node is unused.
+
+class TabNodePool2 {
+ public:
+   TabNodePool2();
+  ~TabNodePool2();
+  enum InvalidTab {
+    kInvalidTabID = -1
+  };
+
+  // If free nodes > kFreeNodesHighWatermark, delete all free nodes until
+  // free nodes <= kFreeNodesLowWatermark.
+  static const size_t kFreeNodesLowWatermark;
+
+  // Maximum limit of FreeNodes allowed on the client.
+  static const size_t kFreeNodesHighWatermark;
+
+  static const int kInvalidTabNodeID;
+
+  // Build a sync tag from tab_node_id.
+  static std::string TabIdToTag(const std::string machine_tag,
+                                int tab_node_id);
+
+  // Returns the tab_node_id for the next free tab node. If none are available,
+  // creates a new tab node and adds it to free nodes pool. The free node can
+  // then be used to associate with a tab by calling AssociateTabNode.
+  // Note: The node is considered free until it has been associated. Repeated
+  // calls to GetFreeTabNode will return the same id until node has been
+  // associated.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller context. If the need
+  // to create nodes arises in the implementation, associated SyncChanges will
+  // be appended to this list for later application by the caller via the
+  // SyncChangeProcessor.
+  int GetFreeTabNode(syncer::SyncChangeList* change_output);
+
+  // Removes association for |tab_node_id| and returns it to the free node pool.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller's context. If the need
+  // to delete sync nodes arises in the implementation, associated SyncChanges
+  // will be appended to this list for later application by the caller via the
+  // SyncChangeProcessor.
+  void FreeTabNode(int tab_node_id, syncer::SyncChangeList* change_output);
+
+  // Associates |tab_node_id| with |tab_id|. |tab_node_id| should either be
+  // unassociated or free. If |tab_node_id| is free, |tab_node_id| is removed
+  // from the free node pool In order to associate a non free sync node,
+  // use ReassociateTabNode.
+  void AssociateTabNode(int tab_node_id, SessionID::id_type tab_id);
+
+  // Adds |tab_node_id| as an unassociated sync node.
+  // Note: this should only be called when we discover tab sync nodes from
+  // previous sessions, not for freeing tab nodes we created through
+  // GetFreeTabNode (use FreeTabNode below for that).
+  void AddTabNode(int tab_node_id, const SessionID& tab_id);
+
+  // Returns the tab_id for |tab_node_id| if it is associated else returns
+  // kInvalidTabID.
+  SessionID::id_type GetTabIdFromTabNodeId(int tab_node_id) const;
+
+  // Reassociates |tab_node_id| with |tab_id|. |tab_node_id| must be either
+  // associated with a tab or in the set of unassociated nodes.
+  void ReassociateTabNode(int tab_node_id, SessionID::id_type tab_id);
+
+  // Returns true if |tab_node_id| is an unassociated tab node.
+  bool IsUnassociatedTabNode(int tab_node_id);
+
+  // Returns any unassociated nodes to the free node pool.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller's context.
+  // See FreeTabNode for more detail.
+  void FreeUnassociatedTabNodes(syncer::SyncChangeList* change_output);
+
+  // Clear tab pool.
+  void Clear();
+
+  // Return the number of tab nodes this client currently has allocated
+  // (including both free, unassociated and associated nodes)
+  size_t Capacity() const;
+
+  // Return empty status (all tab nodes are in use).
+  bool Empty() const;
+
+  // Return full status (no tab nodes are in use).
+  bool Full();
+
+  void SetMachineTag(const std::string& machine_tag);
+
+ private:
+  friend class SyncTabNodePool2Test;
+  typedef std::map<int, SessionID::id_type> TabNodeIDToTabIDMap;
+
+  // Adds |tab_node_id| to free node pool.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller's context.
+  // See FreeTabNode for more detail.
+  void FreeTabNodeInternal(int tab_node_id,
+                           syncer::SyncChangeList* change_output);
+
+  // Stores mapping of node ids associated with tab_ids, these are the used
+  // nodes of tab node pool.
+  // The nodes in the map can be returned to free tab node pool by calling
+  // FreeTabNode(tab_node_id).
+  TabNodeIDToTabIDMap nodeid_tabid_map_;
+
+  // The node ids for the set of free sync nodes.
+  std::set<int> free_nodes_pool_;
+
+  // The node ids that are added to pool using AddTabNode and are currently
+  // not associated with any tab. They can be reassociated using
+  // ReassociateTabNode.
+  std::set<int> unassociated_nodes_;
+
+  // The maximum used tab_node id for a sync node. A new sync node will always
+  // be created with max_used_tab_node_id_ + 1.
+  int max_used_tab_node_id_;
+
+  // The machine tag associated with this tab pool. Used in the title of new
+  // sync nodes.
+  std::string machine_tag_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabNodePool2);
+};
+
+}  // namespace browser_sync
+
+#endif  // CHROME_BROWSER_SYNC_SESSIONS2_TAB_NODE_POOL2_H_
diff --git a/chrome/browser/sync/sessions2/tab_node_pool2_unittest.cc b/chrome/browser/sync/sessions2/tab_node_pool2_unittest.cc
new file mode 100644
index 0000000..14942e2
--- /dev/null
+++ b/chrome/browser/sync/sessions2/tab_node_pool2_unittest.cc
@@ -0,0 +1,228 @@
+// Copyright 2013 The Chromium Authors. 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/sessions2/tab_node_pool2.h"
+
+#include "sync/api/sync_change.h"
+#include "sync/protocol/session_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_sync {
+
+class SyncTabNodePool2Test : public testing::Test {
+ protected:
+  SyncTabNodePool2Test() { pool_.SetMachineTag("tag"); }
+
+  int GetMaxUsedTabNodeId() const { return pool_.max_used_tab_node_id_; }
+
+  TabNodePool2 pool_;
+};
+
+namespace {
+
+TEST_F(SyncTabNodePool2Test, TabNodeIdIncreases) {
+  syncer::SyncChangeList changes;
+  // max_used_tab_node_ always increases.
+  SessionID session_id;
+  session_id.set_id(1);
+  pool_.AddTabNode(10, session_id);
+  EXPECT_EQ(10, GetMaxUsedTabNodeId());
+  session_id.set_id(2);
+  pool_.AddTabNode(1, session_id);
+  EXPECT_EQ(10, GetMaxUsedTabNodeId());
+  session_id.set_id(3);
+  pool_.AddTabNode(1000, session_id);
+  EXPECT_EQ(1000, GetMaxUsedTabNodeId());
+  pool_.ReassociateTabNode(1000, 500);
+
+  // Freeing a tab node does not change max_used_tab_node_id_.
+  pool_.FreeTabNode(1000, &changes);
+  EXPECT_TRUE(changes.empty());
+  pool_.FreeUnassociatedTabNodes(&changes);
+  EXPECT_TRUE(changes.empty());
+  EXPECT_EQ(1000, GetMaxUsedTabNodeId());
+  for (int i = 0; i < 3; ++i) {
+    pool_.AssociateTabNode(pool_.GetFreeTabNode(&changes), i + 1);
+    EXPECT_EQ(1000, GetMaxUsedTabNodeId());
+  }
+  // We Free() nodes above, so GetFreeTabNode should not need to create.
+  EXPECT_TRUE(changes.empty());
+
+  EXPECT_EQ(1000, GetMaxUsedTabNodeId());
+}
+
+TEST_F(SyncTabNodePool2Test, OldTabNodesAddAndRemove) {
+  syncer::SyncChangeList changes;
+  // VerifyOldTabNodes are added.
+  // tab_node_id = 1, tab_id = 1
+  SessionID session_id;
+  session_id.set_id(1);
+  pool_.AddTabNode(1, session_id);
+  // tab_node_id = 2, tab_id = 2
+  session_id.set_id(2);
+  pool_.AddTabNode(2, session_id);
+  EXPECT_EQ(2u, pool_.Capacity());
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.IsUnassociatedTabNode(1));
+  pool_.ReassociateTabNode(1, 2);
+  EXPECT_TRUE(pool_.Empty());
+  // Check FreeUnassociatedTabNodes returns the node to free node pool_.
+  pool_.FreeUnassociatedTabNodes(&changes);
+  EXPECT_TRUE(changes.empty());
+  // 2 should be returned to free node pool_.
+  EXPECT_EQ(2u, pool_.Capacity());
+  // Should be able to free 1.
+  pool_.FreeTabNode(1, &changes);
+  EXPECT_TRUE(changes.empty());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(1, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  pool_.AssociateTabNode(1, 1);
+  EXPECT_EQ(2, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  pool_.AssociateTabNode(2, 1);
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_FALSE(pool_.Full());
+}
+
+TEST_F(SyncTabNodePool2Test, OldTabNodesReassociation) {
+  // VerifyOldTabNodes are reassociated correctly.
+  SessionID session_id;
+  session_id.set_id(1);
+  pool_.AddTabNode(4, session_id);
+  session_id.set_id(2);
+  pool_.AddTabNode(5, session_id);
+  session_id.set_id(3);
+  pool_.AddTabNode(6, session_id);
+  EXPECT_EQ(3u, pool_.Capacity());
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.IsUnassociatedTabNode(4));
+  pool_.ReassociateTabNode(4, 5);
+  // Free 5 and 6.
+  syncer::SyncChangeList changes;
+  pool_.FreeUnassociatedTabNodes(&changes);
+  EXPECT_TRUE(changes.empty());
+  // 5 and 6 nodes should not be unassociated.
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(5));
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(6));
+  // Free node pool should have 5 and 6.
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_EQ(3u, pool_.Capacity());
+
+  // Free all nodes
+  pool_.FreeTabNode(4, &changes);
+  EXPECT_TRUE(changes.empty());
+  EXPECT_TRUE(pool_.Full());
+  std::set<int> free_sync_ids;
+  for (int i = 0; i < 3; ++i) {
+    free_sync_ids.insert(pool_.GetFreeTabNode(&changes));
+    // GetFreeTabNode will return the same value till the node is
+    // reassociated.
+    pool_.AssociateTabNode(pool_.GetFreeTabNode(&changes), i + 1);
+  }
+
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_EQ(3u, free_sync_ids.size());
+  EXPECT_EQ(1u, free_sync_ids.count(4));
+  EXPECT_EQ(1u, free_sync_ids.count(5));
+  EXPECT_EQ(1u, free_sync_ids.count(6));
+}
+
+TEST_F(SyncTabNodePool2Test, Init) {
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+}
+
+TEST_F(SyncTabNodePool2Test, AddGet) {
+  syncer::SyncChangeList changes;
+  SessionID session_id;
+  session_id.set_id(1);
+  pool_.AddTabNode(5, session_id);
+  session_id.set_id(2);
+  pool_.AddTabNode(10, session_id);
+  pool_.FreeUnassociatedTabNodes(&changes);
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+
+  EXPECT_EQ(2U, pool_.Capacity());
+  EXPECT_EQ(5, pool_.GetFreeTabNode(&changes));
+  pool_.AssociateTabNode(5, 1);
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_FALSE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  // 5 is now used, should return 10.
+  EXPECT_EQ(10, pool_.GetFreeTabNode(&changes));
+}
+
+TEST_F(SyncTabNodePool2Test, All) {
+  syncer::SyncChangeList changes;
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(0U, pool_.Capacity());
+
+  // GetFreeTabNode returns the lowest numbered free node.
+  EXPECT_EQ(0, pool_.GetFreeTabNode(&changes));
+  EXPECT_EQ(1U, changes.size());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(1U, pool_.Capacity());
+
+  // Associate 5, next free node should be 10.
+  pool_.AssociateTabNode(0, 1);
+  EXPECT_EQ(1, pool_.GetFreeTabNode(&changes));
+  EXPECT_EQ(2U, changes.size());
+  changes.clear();
+  pool_.AssociateTabNode(1, 2);
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_FALSE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  // Release them in reverse order.
+  pool_.FreeTabNode(1, &changes);
+  pool_.FreeTabNode(0, &changes);
+  EXPECT_EQ(2U, pool_.Capacity());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(0, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  pool_.AssociateTabNode(0, 1);
+  EXPECT_EQ(2U, pool_.Capacity());
+  EXPECT_EQ(1, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  pool_.AssociateTabNode(1, 2);
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_FALSE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  // Release them again.
+  pool_.FreeTabNode(1, &changes);
+  pool_.FreeTabNode(0, &changes);
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  pool_.Clear();
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(0U, pool_.Capacity());
+}
+
+TEST_F(SyncTabNodePool2Test, GetFreeTabNodeCreate) {
+  syncer::SyncChangeList changes;
+  EXPECT_EQ(0, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes[0].IsValid());
+  EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
+  EXPECT_TRUE(changes[0].sync_data().IsValid());
+  sync_pb::EntitySpecifics entity = changes[0].sync_data().GetSpecifics();
+  sync_pb::SessionSpecifics specifics(entity.session());
+  EXPECT_EQ(0, specifics.tab_node_id());
+}
+
+}  // namespace
+
+}  // namespace browser_sync
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc
index e07ffcc..d51ba27 100644
--- a/chrome/browser/sync/test/integration/apps_helper.cc
+++ b/chrome/browser/sync/test/integration/apps_helper.cc
@@ -10,7 +10,7 @@
 #include "chrome/browser/sync/test/integration/sync_app_helper.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_extension_helper.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 using sync_datatype_helper::test;
 
diff --git a/chrome/browser/sync/test/integration/extensions_helper.cc b/chrome/browser/sync/test/integration/extensions_helper.cc
index 5f53855..1727fbb 100644
--- a/chrome/browser/sync/test/integration/extensions_helper.cc
+++ b/chrome/browser/sync/test/integration/extensions_helper.cc
@@ -12,7 +12,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_extension_helper.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 using sync_datatype_helper::test;
 
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc
index fba06cd..393f943 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc
@@ -16,8 +16,8 @@
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "extensions/common/id_util.h"
+#include "extensions/common/manifest_constants.h"
 #include "sync/api/string_ordinal.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -273,30 +273,30 @@
                                          const std::string& name,
                                          Manifest::Type type) {
   DictionaryValue source;
-  source.SetString(extension_manifest_keys::kName, name);
+  source.SetString(extensions::manifest_keys::kName, name);
   const std::string& public_key = NameToPublicKey(name);
-  source.SetString(extension_manifest_keys::kPublicKey, public_key);
-  source.SetString(extension_manifest_keys::kVersion, "0.0.0.0");
+  source.SetString(extensions::manifest_keys::kPublicKey, public_key);
+  source.SetString(extensions::manifest_keys::kVersion, "0.0.0.0");
   switch (type) {
     case Manifest::TYPE_EXTENSION:
       // Do nothing.
       break;
     case Manifest::TYPE_THEME:
-      source.Set(extension_manifest_keys::kTheme, new DictionaryValue());
+      source.Set(extensions::manifest_keys::kTheme, new DictionaryValue());
       break;
     case Manifest::TYPE_HOSTED_APP:
     case Manifest::TYPE_LEGACY_PACKAGED_APP:
-      source.Set(extension_manifest_keys::kApp, new DictionaryValue());
-      source.SetString(extension_manifest_keys::kLaunchWebURL,
+      source.Set(extensions::manifest_keys::kApp, new DictionaryValue());
+      source.SetString(extensions::manifest_keys::kLaunchWebURL,
                        "http://www.example.com");
       break;
     case Manifest::TYPE_PLATFORM_APP: {
-      source.Set(extension_manifest_keys::kApp, new DictionaryValue());
-      source.Set(extension_manifest_keys::kPlatformAppBackground,
+      source.Set(extensions::manifest_keys::kApp, new DictionaryValue());
+      source.Set(extensions::manifest_keys::kPlatformAppBackground,
                  new DictionaryValue());
       ListValue* scripts = new ListValue();
       scripts->AppendString("main.js");
-      source.Set(extension_manifest_keys::kPlatformAppBackgroundScripts,
+      source.Set(extensions::manifest_keys::kPlatformAppBackgroundScripts,
                  scripts);
       break;
     }
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.h b/chrome/browser/sync/test/integration/sync_extension_helper.h
index 2efd610..0ed3824 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.h
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.h
@@ -13,7 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class Profile;
 class SyncTest;
diff --git a/chrome/browser/sync/test/integration/themes_helper.cc b/chrome/browser/sync/test/integration/themes_helper.cc
index dbfc0b1..887b31c 100644
--- a/chrome/browser/sync/test/integration/themes_helper.cc
+++ b/chrome/browser/sync/test/integration/themes_helper.cc
@@ -11,8 +11,8 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "extensions/common/id_util.h"
+#include "extensions/common/manifest.h"
 
 using sync_datatype_helper::test;
 
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.cc b/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.cc
index 6789c19..d2bdf15 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.cc
@@ -60,6 +60,24 @@
 
 void EmptyStatusCallback(SyncStatusCode status) {}
 
+void RemoteVersionsCallbackAdapter(
+    const DriveFileSyncService::RemoteVersionsCallback& versions_callback,
+    const SyncStatusCallback& completion_callback,
+    SyncStatusCode status,
+    const std::vector<DriveFileSyncService::Version>& versions) {
+  completion_callback.Run(status);
+  versions_callback.Run(status, versions);
+}
+
+void DownloadVersionCallbackAdapter(
+    const DriveFileSyncService::DownloadVersionCallback& download_callback,
+    const SyncStatusCallback& completion_callback,
+    SyncStatusCode status,
+    scoped_ptr<webkit_blob::ScopedFile> downloaded) {
+  completion_callback.Run(status);
+  download_callback.Run(status, downloaded.Pass());
+}
+
 }  // namespace
 
 ConflictResolutionPolicy DriveFileSyncService::kDefaultPolicy =
@@ -251,6 +269,25 @@
   return conflict_resolution_resolver_.policy();
 }
 
+void DriveFileSyncService::GetRemoteVersions(
+    const fileapi::FileSystemURL& url,
+    const RemoteVersionsCallback& callback) {
+  task_manager_->ScheduleTask(
+      base::Bind(&DriveFileSyncService::DoGetRemoteVersions, AsWeakPtr(),
+                 url, callback),
+      base::Bind(&EmptyStatusCallback));
+}
+
+void DriveFileSyncService::DownloadRemoteVersion(
+    const fileapi::FileSystemURL& url,
+    const std::string& version_id,
+    const DownloadVersionCallback& callback) {
+  task_manager_->ScheduleTask(
+      base::Bind(&DriveFileSyncService::DoDownloadRemoteVersion, AsWeakPtr(),
+                 url, version_id, callback),
+      base::Bind(&EmptyStatusCallback));
+}
+
 void DriveFileSyncService::ApplyLocalChange(
     const FileChange& local_file_change,
     const base::FilePath& local_file_path,
@@ -595,6 +632,90 @@
       &DriveFileSyncService::DidApplyLocalChange, AsWeakPtr(), callback));
 }
 
+void DriveFileSyncService::DoGetRemoteVersions(
+    const fileapi::FileSystemURL& url,
+    const RemoteVersionsCallback& versions_callback,
+    const SyncStatusCallback& completion_callback) {
+  RemoteVersionsCallback callback =
+      base::Bind(&RemoteVersionsCallbackAdapter,
+                 versions_callback, completion_callback);
+
+  DriveMetadata drive_metadata;
+  SyncStatusCode status = metadata_store_->ReadEntry(url, &drive_metadata);
+  if (drive_metadata.resource_id().empty())
+    status = SYNC_DATABASE_ERROR_NOT_FOUND;
+  if (status != SYNC_STATUS_OK) {
+    callback.Run(status, std::vector<Version>());
+    return;
+  }
+
+  api_util_->GetResourceEntry(
+      drive_metadata.resource_id(),
+      base::Bind(
+          &DriveFileSyncService::DidGetEntryForRemoteVersions,
+          AsWeakPtr(), callback));
+}
+
+void DriveFileSyncService::DidGetEntryForRemoteVersions(
+    const RemoteVersionsCallback& callback,
+    google_apis::GDataErrorCode error,
+    scoped_ptr<google_apis::ResourceEntry> entry) {
+  if (error != google_apis::HTTP_SUCCESS) {
+    callback.Run(GDataErrorCodeToSyncStatusCodeWrapper(error),
+                 std::vector<Version>());
+    return;
+  }
+  DCHECK(entry);
+
+  SyncFileType file_type =
+      entry->is_file() ? SYNC_FILE_TYPE_FILE :
+      entry->is_folder() ? SYNC_FILE_TYPE_DIRECTORY :
+      SYNC_FILE_TYPE_UNKNOWN;
+
+  Version version;
+  version.id = "dummy";  // Not used in the current version.
+  version.metadata = SyncFileMetadata(file_type,
+                                      entry->file_size(),
+                                      entry->updated_time());
+  std::vector<Version> versions;
+  versions.push_back(version);
+  callback.Run(SYNC_STATUS_OK, versions);
+}
+
+void DriveFileSyncService::DoDownloadRemoteVersion(
+    const fileapi::FileSystemURL& url,
+    const std::string& /* version_id */,
+    const DownloadVersionCallback& download_callback,
+    const SyncStatusCallback& completion_callback) {
+  DownloadVersionCallback callback =
+      base::Bind(&DownloadVersionCallbackAdapter,
+                 download_callback, completion_callback);
+
+  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>());
+    return;
+  }
+
+  api_util_->DownloadFile(
+      metadata.resource_id(), std::string(),
+      base::Bind(&DriveFileSyncService::DidDownloadVersion, AsWeakPtr(),
+                 callback));
+}
+
+void DriveFileSyncService::DidDownloadVersion(
+    const DownloadVersionCallback& download_callback,
+    google_apis::GDataErrorCode error,
+    const std::string& file_md5,
+    int64 file_size,
+    const base::Time& last_updated,
+    scoped_ptr<webkit_blob::ScopedFile> downloaded) {
+  SyncStatusCode status = GDataErrorCodeToSyncStatusCodeWrapper(error);
+  download_callback.Run(status, downloaded.Pass());
+}
+
 void DriveFileSyncService::UpdateRegisteredOrigins() {
   ExtensionService* extension_service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h b/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h
index b42b811..71802d1 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h
+++ b/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service.h
@@ -114,6 +114,13 @@
   virtual SyncStatusCode SetConflictResolutionPolicy(
       ConflictResolutionPolicy policy) OVERRIDE;
   virtual ConflictResolutionPolicy GetConflictResolutionPolicy() const OVERRIDE;
+  virtual void GetRemoteVersions(
+      const fileapi::FileSystemURL& url,
+      const RemoteVersionsCallback& callback) OVERRIDE;
+  virtual void DownloadRemoteVersion(
+      const fileapi::FileSystemURL& url,
+      const std::string& version_id,
+      const DownloadVersionCallback& callback) OVERRIDE;
 
   // LocalChangeProcessor overrides.
   virtual void ApplyLocalChange(
@@ -209,6 +216,28 @@
       const fileapi::FileSystemURL& url,
       const SyncStatusCallback& callback);
 
+  void DoGetRemoteVersions(
+      const fileapi::FileSystemURL& url,
+      const RemoteVersionsCallback& callback,
+      const SyncStatusCallback& completion_callback);
+  void DidGetEntryForRemoteVersions(
+      const RemoteVersionsCallback& callback,
+      google_apis::GDataErrorCode error,
+      scoped_ptr<google_apis::ResourceEntry> entry);
+
+  void DoDownloadRemoteVersion(
+      const fileapi::FileSystemURL& url,
+      const std::string& version_id,
+      const DownloadVersionCallback& callback,
+      const SyncStatusCallback& completion_callback);
+  void DidDownloadVersion(
+      const DownloadVersionCallback& download_callback,
+      google_apis::GDataErrorCode error,
+      const std::string& file_md5,
+      int64 file_size,
+      const base::Time& last_updated,
+      scoped_ptr<webkit_blob::ScopedFile> downloaded);
+
   void UpdateRegisteredOrigins();
 
   void StartBatchSync(const SyncStatusCallback& callback);
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service_fake_unittest.cc b/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service_fake_unittest.cc
index 244d272..b31f9dd 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service_fake_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_file_sync_service_fake_unittest.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/file_util.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "chrome/browser/drive/drive_uploader.h"
@@ -85,6 +86,24 @@
   *url_out = url;
 }
 
+void DidGetRemoteVersions(
+    SyncStatusCode* status_out,
+    std::vector<RemoteFileSyncService::Version>* versions_out,
+    SyncStatusCode status,
+    const std::vector<RemoteFileSyncService::Version>& versions) {
+  *status_out = status;
+  *versions_out = versions;
+}
+
+void DidDownloadRemoteVersion(
+    SyncStatusCode* status_out,
+    webkit_blob::ScopedFile* downloaded_out,
+    SyncStatusCode status,
+    scoped_ptr<webkit_blob::ScopedFile> downloaded) {
+  *status_out = status;
+  *downloaded_out = downloaded->Pass();
+}
+
 void ExpectEqStatus(bool* done,
                     SyncStatusCode expected,
                     SyncStatusCode actual) {
@@ -394,6 +413,34 @@
     return origin_root_resource_id;
   }
 
+  void AddNewFile(const GURL& origin,
+                  const std::string& parent_resource_id,
+                  const std::string& title,
+                  const std::string& content,
+                  scoped_ptr<google_apis::ResourceEntry>* entry) {
+    std::string file_id;
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->AddFile(
+                  parent_resource_id, title, content, &file_id));
+    ASSERT_EQ(google_apis::HTTP_SUCCESS,
+              fake_drive_helper_->GetResourceEntry(
+                  file_id, entry));
+
+    DriveMetadata metadata;
+    metadata.set_resource_id(file_id);
+    metadata.set_md5_checksum((*entry)->file_md5());
+    metadata.set_conflicted(false);
+    metadata.set_to_be_fetched(false);
+    metadata.set_type(DriveMetadata::RESOURCE_TYPE_FILE);
+
+    bool done = false;
+    metadata_store()->UpdateEntry(
+        CreateURL(origin, title), metadata,
+        base::Bind(&ExpectEqStatus, &done, SYNC_STATUS_OK));
+    base::RunLoop().RunUntilIdle();
+    ASSERT_TRUE(done);
+  }
+
   void TestRegisterNewOrigin();
   void TestRegisterExistingOrigin();
   void TestRegisterOriginWithSyncDisabled();
@@ -405,6 +452,7 @@
   void TestRemoteChange_UpdateFile();
   void TestRemoteChange_Override();
   void TestRemoteChange_Folder();
+  void TestGetRemoteVersions();
 
  private:
   content::TestBrowserThreadBundle thread_bundle_;
@@ -729,6 +777,47 @@
       resource_id, ExtensionNameToGURL(kExtensionName1)));
 }
 
+void DriveFileSyncServiceFakeTest::TestGetRemoteVersions() {
+  SetUpDriveSyncService(true);
+  const std::string origin_resource_id =
+      SetUpOriginRootDirectory(kExtensionName1);
+
+  const GURL origin(ExtensionNameToGURL(kExtensionName1));
+  const std::string title("file");
+  const std::string content("data1");
+  const fileapi::FileSystemURL& url(CreateURL(origin, title));
+
+  scoped_ptr<google_apis::ResourceEntry> entry;
+  AddNewFile(origin, origin_resource_id, title, content, &entry);
+
+  SyncStatusCode status = SYNC_STATUS_FAILED;
+  std::vector<RemoteFileSyncService::Version> versions;
+  sync_service_->GetRemoteVersions(
+      url, base::Bind(&DidGetRemoteVersions, &status, &versions));
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_EQ(SYNC_STATUS_OK, status);
+  ASSERT_FALSE(versions.empty());
+  EXPECT_EQ(1u, versions.size());
+  EXPECT_EQ(static_cast<int64>(content.length()), versions[0].metadata.size);
+  EXPECT_EQ(entry->file_size(), versions[0].metadata.size);
+  EXPECT_EQ(entry->updated_time(), versions[0].metadata.last_modified);
+
+  status = SYNC_STATUS_FAILED;
+  webkit_blob::ScopedFile downloaded;
+  sync_service_->DownloadRemoteVersion(
+      url, versions[0].id,
+      base::Bind(&DidDownloadRemoteVersion, &status, &downloaded));
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_EQ(SYNC_STATUS_OK, status);
+
+  std::string downloaded_content;
+  EXPECT_TRUE(file_util::ReadFileToString(downloaded.path(),
+                                          &downloaded_content));
+  EXPECT_EQ(content, downloaded_content);
+}
+
 TEST_F(DriveFileSyncServiceFakeTest, RegisterNewOrigin) {
   ASSERT_FALSE(IsDriveAPIDisabled());
   TestRegisterNewOrigin();
@@ -839,6 +928,16 @@
   TestRemoteChange_Folder();
 }
 
+TEST_F(DriveFileSyncServiceFakeTest, GetRemoteVersions) {
+  ASSERT_FALSE(IsDriveAPIDisabled());
+  TestGetRemoteVersions();
+}
+
+TEST_F(DriveFileSyncServiceFakeTest, GetRemoteVersions_WAPI) {
+  ScopedDisableDriveAPI disable_drive_api;
+  TestGetRemoteVersions();
+}
+
 #endif  // !defined(OS_ANDROID)
 
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/drive_metadata_store.cc b/chrome/browser/sync_file_system/drive_backend/drive_metadata_store.cc
index 9fb3fb9..739197c 100644
--- a/chrome/browser/sync_file_system/drive_backend/drive_metadata_store.cc
+++ b/chrome/browser/sync_file_system/drive_backend/drive_metadata_store.cc
@@ -582,7 +582,6 @@
     // |origin| has not been registered yet.
     return;
   }
-  std::string resource_id = found->second;
   disabled_origins_.erase(found);
 
   // |origin| goes back to DriveFileSyncService::pending_batch_sync_origins_
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 5219758..98df266 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -50,6 +50,11 @@
 typedef MetadataDatabase::TrackersByParentAndTitle TrackersByParentAndTitle;
 typedef MetadataDatabase::TrackersByTitle TrackersByTitle;
 
+bool IsAppRoot(const FileTracker& tracker) {
+  return tracker.tracker_kind() == TRACKER_KIND_APP_ROOT ||
+      tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT;
+}
+
 std::string RemovePrefix(const std::string& str, const std::string& prefix) {
   if (StartsWithASCII(str, prefix, true))
     return str.substr(prefix.size());
@@ -155,23 +160,26 @@
   batch->Delete(kFileTrackerKeyPrefix + base::Int64ToString(tracker_id));
 }
 
-void PushChildTrackersToStack(
+template <typename OutputIterator>
+OutputIterator PushChildTrackersToContainer(
     const TrackersByParentAndTitle& trackers_by_parent,
     int64 parent_tracker_id,
-    std::stack<int64>* stack) {
+    OutputIterator target_itr) {
   TrackersByParentAndTitle::const_iterator found =
       trackers_by_parent.find(parent_tracker_id);
   if (found == trackers_by_parent.end())
-    return;
+    return target_itr;
 
   for (TrackersByTitle::const_iterator title_itr = found->second.begin();
        title_itr != found->second.end(); ++title_itr) {
     const TrackerSet& trackers = title_itr->second;
     for (TrackerSet::const_iterator tracker_itr = trackers.begin();
          tracker_itr != trackers.end(); ++tracker_itr) {
-      stack->push((*tracker_itr)->tracker_id());
+      *target_itr = (*tracker_itr)->tracker_id();
+      ++target_itr;
     }
   }
+  return target_itr;
 }
 
 std::string GetTrackerTitle(const FileTracker& tracker) {
@@ -325,7 +333,6 @@
 
 SyncStatusCode InitializeServiceMetadata(DatabaseContents* contents,
                                          leveldb::WriteBatch* batch) {
-
   if (!contents->service_metadata) {
     contents->service_metadata.reset(new ServiceMetadata);
     contents->service_metadata->set_next_tracker_id(1);
@@ -374,7 +381,7 @@
       unvisited_trackers.erase(found);
       reachable_trackers.push_back(tracker);
 
-      if (!tracker->active() && !tracker->is_app_root())
+      if (!tracker->active())
         continue;
     }
 
@@ -503,24 +510,44 @@
                                    const std::string& folder_id,
                                    const SyncStatusCallback& callback) {
   if (FindAppRootTracker(app_id, NULL)) {
+    // The app-root is already registered.
     RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
     return;
   }
 
   TrackerSet trackers;
-  if (!FindTrackersByFileID(folder_id, &trackers) ||
-      trackers.has_active() ||
-      trackers.tracker_set().size() != 1) {
+  if (!FindTrackersByFileID(folder_id, &trackers) || trackers.has_active()) {
+    // The folder is tracked by another tracker.
     util::Log(logging::LOG_WARNING, FROM_HERE,
               "Failed to register App for %s", app_id.c_str());
     RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_HAS_CONFLICT));
     return;
   }
 
-  FileTracker* tracker = *trackers.tracker_set().begin();
+  int64 sync_root_tracker_id = service_metadata_->sync_root_tracker_id();
+  if (!sync_root_tracker_id) {
+    util::Log(logging::LOG_WARNING, FROM_HERE,
+              "Sync-root needs to be set up before registering app-root");
+    RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
+    return;
+  }
+
+  // Make this tracker an app-root tracker.
+  FileTracker* app_root_tracker = NULL;
+  for (TrackerSet::iterator itr = trackers.begin();
+       itr != trackers.end(); ++itr) {
+    FileTracker* tracker = *itr;
+    if (tracker->parent_tracker_id() == sync_root_tracker_id)
+      app_root_tracker = tracker;
+  }
+
+  if (!app_root_tracker) {
+    RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
+    return;
+  }
 
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
-  RegisterTrackerAsAppRoot(app_id, tracker->tracker_id(), batch.get());
+  RegisterTrackerAsAppRoot(app_id, app_root_tracker->tracker_id(), batch.get());
   WriteToDatabase(batch.Pass(), callback);
 }
 
@@ -532,38 +559,40 @@
     return;
   }
 
-  if (!tracker.active()) {
+  if (tracker.tracker_kind() == TRACKER_KIND_DISABLED_APP_ROOT) {
     RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
     return;
   }
 
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
-  MakeTrackerInactive(tracker.tracker_id(), batch.get());
+  MakeAppRootDisabled(tracker.tracker_id(), batch.get());
   WriteToDatabase(batch.Pass(), callback);
 }
 
 void MetadataDatabase::EnableApp(const std::string& app_id,
                                  const SyncStatusCallback& callback) {
   FileTracker tracker;
-  if (!FindAppRootTracker(app_id, &tracker)) {
+  if (!FindAppRootTracker(app_id, &tracker) ||
+      tracker.tracker_kind() == TRACKER_KIND_REGULAR) {
     RunSoon(FROM_HERE, base::Bind(callback, SYNC_DATABASE_ERROR_NOT_FOUND));
     return;
   }
 
-  if (tracker.active()) {
+  if (tracker.tracker_kind() == TRACKER_KIND_APP_ROOT) {
     RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
     return;
   }
 
   scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
-  MakeTrackerActive(tracker.tracker_id(), batch.get());
+  MakeAppRootEnabled(tracker.tracker_id(), batch.get());
   WriteToDatabase(batch.Pass(), callback);
 }
 
 void MetadataDatabase::UnregisterApp(const std::string& app_id,
                                      const SyncStatusCallback& callback) {
   FileTracker tracker;
-  if (!FindAppRootTracker(app_id, &tracker)) {
+  if (!FindAppRootTracker(app_id, &tracker) ||
+      tracker.tracker_kind() == TRACKER_KIND_REGULAR) {
     RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
     return;
   }
@@ -605,7 +634,7 @@
     return false;
 
   std::vector<base::FilePath> components;
-  while (!current.is_app_root()) {
+  while (!IsAppRoot(current)) {
     std::string title = GetTrackerTitle(current);
     if (title.empty())
       return false;
@@ -651,6 +680,45 @@
   WriteToDatabase(batch.Pass(), callback);
 }
 
+void MetadataDatabase::PopulateFolder(const std::string& folder_id,
+                                      const FileIDList& child_file_ids,
+                                      const SyncStatusCallback& callback) {
+  TrackerSet trackers;
+  if (!FindTrackersByFileID(folder_id, &trackers) ||
+      !trackers.has_active()) {
+    // It's OK that there is no folder to populate its children.
+    // Inactive folders should ignore their contents updates.
+    RunSoon(FROM_HERE, base::Bind(callback, SYNC_STATUS_OK));
+    return;
+  }
+
+  FileTracker* folder_tracker =
+      tracker_by_id_[trackers.active_tracker()->tracker_id()];
+  DCHECK(folder_tracker);
+  std::set<std::string> children(child_file_ids.begin(), child_file_ids.end());
+
+  std::vector<int64> known_children;
+  PushChildTrackersToContainer(trackers_by_parent_and_title_,
+                               folder_tracker->tracker_id(),
+                               std::back_inserter(known_children));
+  for (std::vector<int64>::iterator itr = known_children.begin();
+       itr != known_children.end(); ++itr)
+    children.erase(tracker_by_id_[*itr]->file_id());
+
+  scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch);
+  for (FileIDList::const_iterator itr = child_file_ids.begin();
+       itr != child_file_ids.end(); ++itr)
+    CreateTrackerForParentAndFileID(*folder_tracker, *itr, batch.get());
+  folder_tracker->set_needs_folder_listing(false);
+  if (!ShouldKeepDirty(*folder_tracker)) {
+    folder_tracker->set_dirty(false);
+    dirty_trackers_.erase(folder_tracker);
+  }
+  PutTrackerToBatch(*folder_tracker, batch.get());
+
+  WriteToDatabase(batch.Pass(), callback);
+}
+
 MetadataDatabase::MetadataDatabase(base::SequencedTaskRunner* task_runner)
     : task_runner_(task_runner), weak_ptr_factory_(this) {
   DCHECK(task_runner);
@@ -753,7 +821,7 @@
     tracker_by_id_[tracker->tracker_id()] = tracker;
     trackers_by_file_id_[tracker->file_id()].Insert(tracker);
 
-    if (tracker->is_app_root())
+    if (IsAppRoot(*tracker))
       app_root_by_app_id_[tracker->app_id()] = tracker;
 
     if (tracker->parent_tracker_id()) {
@@ -776,7 +844,7 @@
   FileTracker* tracker = tracker_by_id_[tracker_id];
   DCHECK(tracker);
   tracker->set_app_id(app_id);
-  tracker->set_is_app_root(true);
+  tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT);
   app_root_by_app_id_[app_id] = tracker;
 
   MakeTrackerActive(tracker->tracker_id(), batch);
@@ -787,16 +855,20 @@
     leveldb::WriteBatch* batch) {
   FileTracker* tracker = FindAndEraseItem(&app_root_by_app_id_, app_id);
   tracker->set_app_id(std::string());
-  tracker->set_is_app_root(false);
+  tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
 
   // Inactivate the tracker to drop all descendant.
-  // (Note that we set is_app_root to false before calling this.)
+  // (Note that we set tracker_kind to TRACKER_KIND_REGULAR before calling
+  // this.)
   MakeTrackerInactive(tracker->tracker_id(), batch);
 }
 
 void MetadataDatabase::MakeTrackerActive(int64 tracker_id,
                                          leveldb::WriteBatch* batch) {
   FileTracker* tracker = tracker_by_id_[tracker_id];
+  DCHECK(tracker);
+  DCHECK(!tracker->active());
+
   int64 parent_tracker_id = tracker->parent_tracker_id();
   DCHECK(tracker->has_synced_details());
   trackers_by_file_id_[tracker->file_id()].Activate(tracker);
@@ -816,6 +888,9 @@
 void MetadataDatabase::MakeTrackerInactive(int64 tracker_id,
                                            leveldb::WriteBatch* batch) {
   FileTracker* tracker = tracker_by_id_[tracker_id];
+  DCHECK(tracker);
+  DCHECK(tracker->active());
+  DCHECK_EQ(TRACKER_KIND_REGULAR, tracker->tracker_kind());
   trackers_by_file_id_[tracker->file_id()].Inactivate(tracker);
 
   std::string title = GetTrackerTitle(*tracker);
@@ -824,16 +899,39 @@
     trackers_by_parent_and_title_[parent_tracker_id][title].Inactivate(tracker);
   tracker->set_active(false);
 
-  // Keep the folder tree under an app-root, since we keep the local files of
-  // SyncFileSystem.
-  if (!tracker->is_app_root())
-    RemoveAllDescendantTrackers(tracker_id, batch);
+  RemoveAllDescendantTrackers(tracker_id, batch);
   MarkTrackersDirtyByFileID(tracker->file_id(), batch);
   if (parent_tracker_id)
     MarkTrackersDirtyByPath(parent_tracker_id, title, batch);
   PutTrackerToBatch(*tracker, batch);
 }
 
+void MetadataDatabase::MakeAppRootDisabled(int64 tracker_id,
+                                           leveldb::WriteBatch* batch) {
+  FileTracker* tracker = tracker_by_id_[tracker_id];
+  DCHECK(tracker);
+  DCHECK_EQ(TRACKER_KIND_APP_ROOT, tracker->tracker_kind());
+  DCHECK(tracker->active());
+
+  // Keep the app-root tracker active (but change the tracker_kind) so that
+  // other conflicting trackers won't become active.
+  tracker->set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT);
+  PutTrackerToBatch(*tracker, batch);
+}
+
+void MetadataDatabase::MakeAppRootEnabled(int64 tracker_id,
+                                          leveldb::WriteBatch* batch) {
+  FileTracker* tracker = tracker_by_id_[tracker_id];
+  DCHECK(tracker);
+  DCHECK_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker->tracker_kind());
+  DCHECK(tracker->active());
+
+  tracker->set_tracker_kind(TRACKER_KIND_APP_ROOT);
+  // Mark descendant trackers as dirty to handle changes in disable period.
+  RecursiveMarkTrackerAsDirty(tracker_id, batch);
+  PutTrackerToBatch(*tracker, batch);
+}
+
 void MetadataDatabase::CreateTrackerForParentAndFileID(
     const FileTracker& parent_tracker,
     const std::string& file_id,
@@ -844,7 +942,7 @@
   tracker->set_parent_tracker_id(parent_tracker.tracker_id());
   tracker->set_file_id(file_id);
   tracker->set_app_id(parent_tracker.app_id());
-  tracker->set_is_app_root(false);
+  tracker->set_tracker_kind(TRACKER_KIND_REGULAR);
   tracker->set_dirty(true);
   tracker->set_active(false);
   tracker->set_needs_folder_listing(false);
@@ -858,25 +956,26 @@
   trackers_by_parent_and_title_[parent_tracker.tracker_id()][std::string()]
       .Insert(tracker.get());
   dirty_trackers_.insert(tracker.get());
+  DCHECK(!ContainsKey(tracker_by_id_, tracker_id));
   tracker_by_id_[tracker_id] = tracker.release();
 }
 
 void MetadataDatabase::RemoveTrackerIgnoringSiblings(
     int64 tracker_id,
     leveldb::WriteBatch* batch) {
-  FileTracker* tracker = FindAndEraseItem(&tracker_by_id_, tracker_id);
+  scoped_ptr<FileTracker> tracker(
+      FindAndEraseItem(&tracker_by_id_, tracker_id));
   if (!tracker)
     return;
 
-  EraseTrackerFromFileIDIndex(tracker, batch);
-  if (tracker->is_app_root())
+  EraseTrackerFromFileIDIndex(tracker.get(), batch);
+  if (IsAppRoot(*tracker))
     app_root_by_app_id_.erase(tracker->app_id());
-  EraseTrackerFromPathIndex(tracker);
+  EraseTrackerFromPathIndex(tracker.get());
 
   MarkTrackersDirtyByFileID(tracker->file_id(), batch);
   // Do not mark the same path trackers as dirty, since the caller is deleting
   // all its siblings.
-  delete tracker;
   PutTrackerDeletionToBatch(tracker_id, batch);
 }
 
@@ -905,7 +1004,7 @@
          itr != found->second.end(); ++itr) {
       FileTracker* parent_tracker = *itr;
       int64 parent_tracker_id = parent_tracker->tracker_id();
-      if (!parent_tracker->active() && !parent_tracker->is_app_root())
+      if (!parent_tracker->active())
         continue;
 
       if (ContainsKey(known_parents, parent_tracker_id))
@@ -918,15 +1017,17 @@
 
 void MetadataDatabase::RemoveAllDescendantTrackers(int64 root_tracker_id,
                                                    leveldb::WriteBatch* batch) {
-  std::stack<int64> pending_trackers;
-  PushChildTrackersToStack(trackers_by_parent_and_title_,
-                           root_tracker_id, &pending_trackers);
+  std::vector<int64> pending_trackers;
+  PushChildTrackersToContainer(trackers_by_parent_and_title_,
+                               root_tracker_id,
+                               std::back_inserter(pending_trackers));
 
   while (!pending_trackers.empty()) {
-    int64 tracker_id = pending_trackers.top();
-    pending_trackers.pop();
-    PushChildTrackersToStack(trackers_by_parent_and_title_,
-                             tracker_id, &pending_trackers);
+    int64 tracker_id = pending_trackers.back();
+    pending_trackers.pop_back();
+    PushChildTrackersToContainer(trackers_by_parent_and_title_,
+                                 tracker_id,
+                                 std::back_inserter(pending_trackers));
     RemoveTrackerIgnoringSiblings(tracker_id, batch);
   }
 }
@@ -948,11 +1049,9 @@
 
 void MetadataDatabase::EraseFileFromDatabase(const std::string& file_id,
                                              leveldb::WriteBatch* batch) {
-  FileMetadata* file = FindAndEraseItem(&file_by_id_, file_id);
-  if (!file)
-    return;
-  delete file;
-  PutFileDeletionToBatch(file_id, batch);
+  scoped_ptr<FileMetadata> file(FindAndEraseItem(&file_by_id_, file_id));
+  if (file)
+    PutFileDeletionToBatch(file_id, batch);
 }
 
 void MetadataDatabase::EraseTrackerFromPathIndex(FileTracker* tracker) {
@@ -1020,6 +1119,53 @@
   return tracker_id;
 }
 
+void MetadataDatabase::RecursiveMarkTrackerAsDirty(int64 root_tracker_id,
+                                                   leveldb::WriteBatch* batch) {
+  std::vector<int64> stack;
+  stack.push_back(root_tracker_id);
+  while (!stack.empty()) {
+    int64 tracker_id = stack.back();
+    stack.pop_back();
+    PushChildTrackersToContainer(
+        trackers_by_parent_and_title_, tracker_id, std::back_inserter(stack));
+
+    FileTracker* tracker = tracker_by_id_[tracker_id];
+    if (!tracker->dirty()) {
+      tracker->set_dirty(true);
+      PutTrackerToBatch(*tracker, batch);
+      dirty_trackers_.insert(tracker);
+    }
+  }
+}
+
+bool MetadataDatabase::ShouldKeepDirty(const FileTracker& tracker) const {
+  DCHECK(tracker.dirty());
+  if (!tracker.has_synced_details())
+    return true;
+
+  FileByID::const_iterator found = file_by_id_.find(tracker.file_id());
+  if (found == file_by_id_.end())
+    return true;
+  const FileMetadata& file = *found->second;
+
+  if (tracker.active()) {
+    if (tracker.needs_folder_listing())
+      return true;
+    if (tracker.synced_details().md5() != file.details().md5())
+      return true;
+  }
+
+  const FileDetails& local_details = tracker.synced_details();
+  const FileDetails& remote_details = file.details();
+
+  if (local_details.title() != remote_details.title())
+    return true;
+  if (local_details.deleted() != remote_details.deleted())
+    return true;
+
+  return false;
+}
+
 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch,
                                        const SyncStatusCallback& callback) {
   base::PostTaskAndReplyWithResult(
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 1be2d1c..8b02892 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.h
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
@@ -37,6 +37,7 @@
 namespace sync_file_system {
 namespace drive_backend {
 
+class FileDetails;
 class FileMetadata;
 class FileTracker;
 class ServiceMetadata;
@@ -108,11 +109,13 @@
   typedef std::map<std::string, TrackerSet> TrackersByTitle;
   typedef std::map<int64, TrackersByTitle> TrackersByParentAndTitle;
   typedef std::map<std::string, FileTracker*> TrackerByAppID;
+  typedef std::vector<std::string> FileIDList;
 
   typedef base::Callback<
       void(SyncStatusCode status, scoped_ptr<MetadataDatabase> instance)>
       CreateCallback;
 
+  // The entry point of the MetadataDatabase for production code.
   static void Create(base::SequencedTaskRunner* task_runner,
                      const base::FilePath& database_path,
                      const CreateCallback& callback);
@@ -184,6 +187,13 @@
   void UpdateByChangeList(ScopedVector<google_apis::ChangeResource> changes,
                           const SyncStatusCallback& callback);
 
+  // Adds |child_file_ids| to |folder_id| as its children.
+  // This method affects the active tracker only.
+  // If the tracker has no further change to sync, unmarks its dirty flag.
+  void PopulateFolder(const std::string& folder_id,
+                      const FileIDList& child_file_ids,
+                      const SyncStatusCallback& callback);
+
  private:
   struct DirtyTrackerComparator {
     bool operator()(const FileTracker* left,
@@ -211,6 +221,8 @@
                                 leveldb::WriteBatch* batch);
   void MakeTrackerActive(int64 tracker_id, leveldb::WriteBatch* batch);
   void MakeTrackerInactive(int64 tracker_id, leveldb::WriteBatch* batch);
+  void MakeAppRootDisabled(int64 tracker_id, leveldb::WriteBatch* batch);
+  void MakeAppRootEnabled(int64 tracker_id, leveldb::WriteBatch* batch);
 
   void UnregisterTrackerAsAppRoot(const std::string& app_id,
                                   leveldb::WriteBatch* batch);
@@ -241,6 +253,10 @@
 
   int64 GetNextTrackerID(leveldb::WriteBatch* batch);
 
+  void RecursiveMarkTrackerAsDirty(int64 root_tracker_id,
+                                   leveldb::WriteBatch* batch);
+  bool ShouldKeepDirty(const FileTracker& tracker) const;
+
   void WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch,
                        const SyncStatusCallback& callback);
 
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.proto b/chrome/browser/sync_file_system/drive_backend/metadata_database.proto
index 736f357..7ef465b 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.proto
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.proto
@@ -16,6 +16,12 @@
   FILE_KIND_FOLDER = 2;
 }
 
+enum TrackerKind {
+  TRACKER_KIND_REGULAR = 0;
+  TRACKER_KIND_APP_ROOT = 1;
+  TRACKER_KIND_DISABLED_APP_ROOT = 2;
+}
+
 message ServiceMetadata {
   optional int64 largest_change_id = 1;
   optional int64 sync_root_tracker_id = 2;
@@ -61,7 +67,7 @@
   required string file_id = 3;
 
   optional string app_id = 4;
-  optional bool is_app_root = 5;
+  optional TrackerKind tracker_kind = 5;
 
   optional FileDetails synced_details = 6;
 
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 c748860..0c19711 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
@@ -22,10 +22,26 @@
 
 namespace {
 
+typedef MetadataDatabase::FileIDList FileIDList;
+
 const int64 kInitialChangeID = 1234;
 const int64 kSyncRootTrackerID = 100;
 const char kSyncRootFolderID[] = "sync_root_folder_id";
 
+struct TrackedFile {
+  FileMetadata metadata;
+  FileTracker tracker;
+
+  // Implies the file should not in the database.
+  bool should_be_absent;
+
+  // Implies the file should have a tracker in the database but should have no
+  // metadata.
+  bool tracker_only;
+
+  TrackedFile() : should_be_absent(false), tracker_only(false) {}
+};
+
 void ExpectEquivalent(const ServiceMetadata* left,
                       const ServiceMetadata* right) {
   if (!left) {
@@ -86,7 +102,7 @@
   EXPECT_EQ(left->parent_tracker_id(), right->parent_tracker_id());
   EXPECT_EQ(left->file_id(), right->file_id());
   EXPECT_EQ(left->app_id(), right->app_id());
-  EXPECT_EQ(left->is_app_root(), right->is_app_root());
+  EXPECT_EQ(left->tracker_kind(), right->tracker_kind());
   ExpectEquivalent(&left->synced_details(), &right->synced_details());
   EXPECT_EQ(left->dirty(), right->dirty());
   EXPECT_EQ(left->active(), right->active());
@@ -209,6 +225,44 @@
     message_loop_.RunUntilIdle();
   }
 
+  void SetUpDatabaseByTrackedFiles(const TrackedFile** tracked_files,
+                                   int size) {
+    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
+    ASSERT_TRUE(db);
+
+    for (int i = 0; i < size; ++i) {
+      const TrackedFile* file = tracked_files[i];
+      if (file->should_be_absent)
+        continue;
+      if (!file->tracker_only)
+        EXPECT_TRUE(PutFileToDB(db.get(), file->metadata).ok());
+      EXPECT_TRUE(PutTrackerToDB(db.get(), file->tracker).ok());
+    }
+  }
+
+  void VerifyTrackedFile(const TrackedFile& file) {
+    if (!file.should_be_absent) {
+      if (file.tracker_only) {
+        EXPECT_FALSE(metadata_database()->FindFileByFileID(
+            file.metadata.file_id(), NULL));
+      } else {
+        VerifyFile(file.metadata);
+      }
+      VerifyTracker(file.tracker);
+      return;
+    }
+
+    EXPECT_FALSE(metadata_database()->FindFileByFileID(
+        file.metadata.file_id(), NULL));
+    EXPECT_FALSE(metadata_database()->FindTrackerByTrackerID(
+        file.tracker.tracker_id(), NULL));
+  }
+
+  void VerifyTrackedFiles(const TrackedFile** tracked_files, int size) {
+    for (int i = 0; i < size; ++i)
+      VerifyTrackedFile(*tracked_files[i]);
+  }
+
   MetadataDatabase* metadata_database() { return metadata_database_.get(); }
 
   leveldb::DB* db() {
@@ -294,7 +348,7 @@
     tracker.set_parent_tracker_id(parent_tracker.tracker_id());
     tracker.set_file_id(file.file_id());
     tracker.set_app_id(parent_tracker.app_id());
-    tracker.set_is_app_root(false);
+    tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
     tracker.set_dirty(false);
     tracker.set_active(true);
     tracker.set_needs_folder_listing(false);
@@ -302,6 +356,37 @@
     return tracker;
   }
 
+  TrackedFile CreateTrackedSyncRoot() {
+    TrackedFile sync_root;
+    sync_root.metadata = CreateSyncRootMetadata();
+    sync_root.tracker = CreateSyncRootTracker(sync_root.metadata);
+    return sync_root;
+  }
+
+  TrackedFile CreateTrackedAppRoot(const TrackedFile& sync_root,
+                                   const std::string& app_id) {
+    TrackedFile app_root(CreateTrackedFolder(sync_root, app_id));
+    app_root.tracker.set_app_id(app_id);
+    app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
+    return app_root;
+  }
+
+  TrackedFile CreateTrackedFile(const TrackedFile& parent,
+                                const std::string& title) {
+    TrackedFile file;
+    file.metadata = CreateFileMetadata(parent.metadata, title);
+    file.tracker = CreateTracker(parent.tracker, file.metadata);
+    return file;
+  }
+
+  TrackedFile CreateTrackedFolder(const TrackedFile& parent,
+                                  const std::string& title) {
+    TrackedFile folder;
+    folder.metadata = CreateFolderMetadata(parent.metadata, title);
+    folder.tracker = CreateTracker(parent.tracker, folder.metadata);
+    return folder;
+  }
+
   scoped_ptr<google_apis::ChangeResource> CreateChangeResourceFromMetadata(
       const FileMetadata& file) {
     scoped_ptr<google_apis::ChangeResource> change(
@@ -497,6 +582,16 @@
     return status;
   }
 
+  SyncStatusCode PopulateFolder(const std::string& folder_id,
+                                const FileIDList& listed_children) {
+    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
+    metadata_database_->PopulateFolder(
+        folder_id, listed_children,
+        base::Bind(&SyncStatusResultCallback, &status));
+    message_loop_.RunUntilIdle();
+    return status;
+  }
+
  private:
   base::ScopedTempDir database_dir_;
   base::MessageLoop message_loop_;
@@ -518,153 +613,81 @@
 }
 
 TEST_F(MetadataDatabaseTest, InitializationTest_SimpleTree) {
-  FileMetadata sync_root(CreateSyncRootMetadata());
-  FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root));
+  TrackedFile sync_root(CreateTrackedSyncRoot());
+  TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
+  app_root.tracker.set_app_id(app_root.metadata.details().title());
+  app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
 
-  FileMetadata app_root(
-      CreateFolderMetadata(sync_root, "app_id" /* title */));
-  FileTracker app_root_tracker(
-      CreateTracker(sync_root_tracker, app_root));
-  app_root_tracker.set_app_id(app_root.details().title());
-  app_root_tracker.set_is_app_root(true);
+  TrackedFile file(CreateTrackedFile(app_root, "file"));
+  TrackedFile folder(CreateTrackedFolder(app_root, "folder"));
+  TrackedFile file_in_folder(CreateTrackedFile(folder, "file_in_folder"));
+  TrackedFile orphaned_file(CreateTrackedFile(sync_root, "orphaned_file"));
+  orphaned_file.metadata.mutable_details()->clear_parent_folder_ids();
+  orphaned_file.tracker.set_parent_tracker_id(0);
 
-  FileMetadata file(CreateFileMetadata(app_root, "file"));
-  FileTracker file_tracker(CreateTracker(app_root_tracker, file));
+  const TrackedFile* tracked_files[] = {
+    &sync_root, &app_root, &file, &folder, &file_in_folder, &orphaned_file
+  };
 
-  FileMetadata folder(CreateFolderMetadata(app_root, "folder"));
-  FileTracker folder_tracker(CreateTracker(app_root_tracker, folder));
-
-  FileMetadata file_in_folder(
-      CreateFileMetadata(folder, "file_in_folder"));
-  FileTracker file_in_folder_tracker(
-      CreateTracker(folder_tracker, file_in_folder));
-
-  FileMetadata orphaned_file(
-      CreateFileMetadata(sync_root, "orphaned_file"));
-  orphaned_file.mutable_details()->clear_parent_folder_ids();
-  FileTracker orphaned_file_tracker(
-      CreateTracker(sync_root_tracker, orphaned_file));
-  orphaned_file_tracker.set_parent_tracker_id(0);
-
-  {
-    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
-    ASSERT_TRUE(db);
-
-    EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), file_in_folder).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), file_in_folder_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), orphaned_file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), orphaned_file_tracker).ok());
-  }
-
+  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
   EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
 
-  VerifyFile(sync_root);
-  VerifyTracker(sync_root_tracker);
-  VerifyFile(app_root);
-  VerifyTracker(app_root_tracker);
-  VerifyFile(file);
-  VerifyTracker(file_tracker);
-  VerifyFile(folder);
-  VerifyTracker(folder_tracker);
-  VerifyFile(file_in_folder);
-  VerifyTracker(file_in_folder_tracker);
-
-  EXPECT_FALSE(metadata_database()->FindFileByFileID(
-      orphaned_file.file_id(), NULL));
-  EXPECT_FALSE(metadata_database()->FindTrackerByTrackerID(
-      orphaned_file_tracker.tracker_id(), NULL));
+  orphaned_file.should_be_absent = true;
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
 }
 
 TEST_F(MetadataDatabaseTest, AppManagementTest) {
-  FileMetadata sync_root(CreateSyncRootMetadata());
-  FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root));
+  TrackedFile sync_root(CreateTrackedSyncRoot());
+  TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
+  app_root.tracker.set_app_id(app_root.metadata.details().title());
+  app_root.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
 
-  FileMetadata app_root(CreateFolderMetadata(sync_root, "app_id"));
-  FileTracker app_root_tracker(
-      CreateTracker(sync_root_tracker, app_root));
-  app_root_tracker.set_app_id(app_root.details().title());
-  app_root_tracker.set_is_app_root(true);
+  TrackedFile file(CreateTrackedFile(app_root, "file"));
+  TrackedFile folder(CreateTrackedFolder(sync_root, "folder"));
+  folder.tracker.set_active(false);
 
-  FileMetadata file(CreateFileMetadata(app_root, "file"));
-  FileTracker file_tracker(CreateTracker(app_root_tracker, file));
-
-  FileMetadata folder(CreateFolderMetadata(sync_root, "folder"));
-  FileTracker folder_tracker(CreateTracker(sync_root_tracker, folder));
-  folder_tracker.set_active(false);
-
-  {
-    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
-    ASSERT_TRUE(db);
-
-    EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker).ok());
-  }
-
+  const TrackedFile* tracked_files[] = {
+    &sync_root, &app_root, &file, &folder,
+  };
+  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
   EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
-  VerifyFile(sync_root);
-  VerifyTracker(sync_root_tracker);
-  VerifyFile(app_root);
-  VerifyTracker(app_root_tracker);
-  VerifyFile(file);
-  VerifyTracker(file_tracker);
-  VerifyFile(folder);
-  VerifyTracker(folder_tracker);
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
 
-  folder_tracker.set_app_id("foo");
-  folder_tracker.set_is_app_root(true);
-  folder_tracker.set_active(true);
-  folder_tracker.set_dirty(true);
-  folder_tracker.set_needs_folder_listing(true);
+  folder.tracker.set_app_id("foo");
   EXPECT_EQ(SYNC_STATUS_OK, RegisterApp(
-      folder_tracker.app_id(), folder.file_id()));
-  VerifyFile(folder);
-  VerifyTracker(folder_tracker);
+      folder.tracker.app_id(), folder.metadata.file_id()));
+  folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
+  folder.tracker.set_active(true);
+  folder.tracker.set_dirty(true);
+  folder.tracker.set_needs_folder_listing(true);
+  VerifyTrackedFile(folder);
   VerifyReloadConsistency();
 
-  EXPECT_EQ(SYNC_STATUS_OK, DisableApp(folder_tracker.app_id()));
-  folder_tracker.set_active(false);
-  VerifyFile(folder);
-  VerifyTracker(folder_tracker);
+  EXPECT_EQ(SYNC_STATUS_OK, DisableApp(folder.tracker.app_id()));
+  folder.tracker.set_tracker_kind(TRACKER_KIND_DISABLED_APP_ROOT);
+  VerifyTrackedFile(folder);
   VerifyReloadConsistency();
 
-  EXPECT_EQ(SYNC_STATUS_OK, EnableApp(folder_tracker.app_id()));
-  folder_tracker.set_active(true);
-  VerifyFile(folder);
-  VerifyTracker(folder_tracker);
+  EXPECT_EQ(SYNC_STATUS_OK, EnableApp(folder.tracker.app_id()));
+  folder.tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
+  VerifyTrackedFile(folder);
   VerifyReloadConsistency();
 
-  EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(folder_tracker.app_id()));
-  folder_tracker.set_app_id(std::string());
-  folder_tracker.set_is_app_root(false);
-  folder_tracker.set_active(false);
-  VerifyFile(folder);
-  VerifyTracker(folder_tracker);
+  EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(folder.tracker.app_id()));
+  folder.tracker.set_app_id(std::string());
+  folder.tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
+  folder.tracker.set_active(false);
+  VerifyTrackedFile(folder);
   VerifyReloadConsistency();
 
-  EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(app_root_tracker.app_id()));
-  app_root_tracker.set_app_id(std::string());
-  app_root_tracker.set_is_app_root(false);
-  app_root_tracker.set_active(false);
-  app_root_tracker.set_dirty(true);
-  VerifyFile(app_root);
-  VerifyTracker(app_root_tracker);
-  EXPECT_FALSE(metadata_database()->FindFileByFileID(file.file_id(), NULL));
-  EXPECT_FALSE(metadata_database()->FindTrackerByTrackerID(
-      file_tracker.tracker_id(), NULL));
+  EXPECT_EQ(SYNC_STATUS_OK, UnregisterApp(app_root.tracker.app_id()));
+  app_root.tracker.set_app_id(std::string());
+  app_root.tracker.set_tracker_kind(TRACKER_KIND_REGULAR);
+  app_root.tracker.set_active(false);
+  app_root.tracker.set_dirty(true);
+  file.should_be_absent = true;
+  VerifyTrackedFile(app_root);
+  VerifyTrackedFile(file);
   VerifyReloadConsistency();
 }
 
@@ -676,7 +699,7 @@
   FileTracker app_root_tracker(
       CreateTracker(sync_root_tracker, app_root));
   app_root_tracker.set_app_id(app_root.details().title());
-  app_root_tracker.set_is_app_root(true);
+  app_root_tracker.set_tracker_kind(TRACKER_KIND_APP_ROOT);
 
   FileMetadata folder(CreateFolderMetadata(app_root, "folder"));
   FileTracker folder_tracker(CreateTracker(app_root_tracker, folder));
@@ -718,116 +741,170 @@
 }
 
 TEST_F(MetadataDatabaseTest, UpdateByChangeListTest) {
-  FileMetadata sync_root(CreateSyncRootMetadata());
-  FileTracker sync_root_tracker(CreateSyncRootTracker(sync_root));
+  TrackedFile sync_root(CreateTrackedSyncRoot());
+  TrackedFile app_root(CreateTrackedFolder(sync_root, "app_id"));
+  TrackedFile disabled_app_root(CreateTrackedFolder(sync_root, "disabled_app"));
+  TrackedFile file(CreateTrackedFile(app_root, "file"));
+  TrackedFile renamed_file(CreateTrackedFile(app_root, "to be renamed"));
+  TrackedFile folder(CreateTrackedFolder(app_root, "folder"));
+  TrackedFile reorganized_file(
+      CreateTrackedFile(app_root, "to be reorganized"));
+  TrackedFile updated_file(
+      CreateTrackedFile(app_root, "to be updated"));
+  TrackedFile noop_file(CreateTrackedFile(app_root, "has noop change"));
+  TrackedFile new_file(CreateTrackedFile(app_root, "to be added later"));
+  new_file.should_be_absent = true;
 
-  FileMetadata app_root(CreateFolderMetadata(sync_root, "app_id"));
-  FileTracker app_root_tracker(
-      CreateTracker(sync_root_tracker, app_root));
+  const TrackedFile* tracked_files[] = {
+    &sync_root, &app_root, &disabled_app_root,
+    &file, &renamed_file, &folder, &reorganized_file, &updated_file, &noop_file,
+    &new_file,
+  };
 
-  FileMetadata disabled_app_root(
-      CreateFolderMetadata(sync_root, "disabled_app"));
-  FileTracker disabled_app_root_tracker(
-      CreateTracker(sync_root_tracker, disabled_app_root));
-
-  FileMetadata file(CreateFileMetadata(app_root, "file"));
-  FileTracker file_tracker(CreateTracker(app_root_tracker, file));
-
-  FileMetadata renamed_file(CreateFileMetadata(app_root, "to be renamed"));
-  FileTracker renamed_file_tracker(
-      CreateTracker(app_root_tracker, renamed_file));
-
-  FileMetadata folder(CreateFolderMetadata(app_root, "folder"));
-  FileTracker folder_tracker(CreateTracker(app_root_tracker, folder));
-
-  FileMetadata reorganized_file(
-      CreateFileMetadata(app_root, "to be reorganized"));
-  FileTracker reorganized_file_tracker(
-      CreateTracker(app_root_tracker, reorganized_file));
-
-  FileMetadata updated_file(CreateFileMetadata(app_root, "to be updated"));
-  FileTracker updated_file_tracker(
-      CreateTracker(app_root_tracker, updated_file));
-
-  FileMetadata noop_file(CreateFileMetadata(app_root, "have noop change"));
-  FileTracker noop_file_tracker(
-      CreateTracker(app_root_tracker, noop_file));
-
-  FileMetadata new_file(CreateFileMetadata(app_root, "to be added later"));
-
-  {
-    scoped_ptr<leveldb::DB> db = InitializeLevelDB();
-    ASSERT_TRUE(db);
-
-    EXPECT_TRUE(PutFileToDB(db.get(), sync_root).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), sync_root_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), app_root).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), app_root_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), disabled_app_root).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), disabled_app_root_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), file_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), renamed_file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), renamed_file_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), folder).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), folder_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), reorganized_file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), reorganized_file_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), updated_file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), updated_file_tracker).ok());
-    EXPECT_TRUE(PutFileToDB(db.get(), noop_file).ok());
-    EXPECT_TRUE(PutTrackerToDB(db.get(), noop_file_tracker).ok());
-  }
-
+  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
   EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
 
-  ApplyRenameChangeToMetadata("renamed", &renamed_file);
-  ApplyReorganizeChangeToMetadata(folder.file_id(), &reorganized_file);
-  ApplyContentChangeToMetadata(&updated_file);
+  ApplyRenameChangeToMetadata("renamed", &renamed_file.metadata);
+  ApplyReorganizeChangeToMetadata(folder.metadata.file_id(),
+                                  &reorganized_file.metadata);
+  ApplyContentChangeToMetadata(&updated_file.metadata);
 
   ScopedVector<google_apis::ChangeResource> changes;
-  PushToChangeList(CreateChangeResourceFromMetadata(renamed_file), &changes);
-  PushToChangeList(CreateChangeResourceFromMetadata(
-      reorganized_file), &changes);
-  PushToChangeList(CreateChangeResourceFromMetadata(updated_file), &changes);
-  PushToChangeList(CreateChangeResourceFromMetadata(noop_file), &changes);
-  PushToChangeList(CreateChangeResourceFromMetadata(new_file), &changes);
-
-  renamed_file_tracker.set_dirty(true);
-  reorganized_file_tracker.set_dirty(true);
-  updated_file_tracker.set_dirty(true);
-  noop_file_tracker.set_dirty(true);
-
+  PushToChangeList(
+      CreateChangeResourceFromMetadata(renamed_file.metadata), &changes);
+  PushToChangeList(
+      CreateChangeResourceFromMetadata(reorganized_file.metadata), &changes);
+  PushToChangeList(
+      CreateChangeResourceFromMetadata(updated_file.metadata), &changes);
+  PushToChangeList(
+      CreateChangeResourceFromMetadata(noop_file.metadata), &changes);
+  PushToChangeList(
+      CreateChangeResourceFromMetadata(new_file.metadata), &changes);
   EXPECT_EQ(SYNC_STATUS_OK, UpdateByChangeList(changes.Pass()));
 
-  FileTracker new_file_tracker(CreateTracker(app_root_tracker, new_file));
-  new_file_tracker.set_tracker_id(GetTrackerIDByFileID(new_file.file_id()));
-  new_file_tracker.clear_synced_details();
-  new_file_tracker.set_active(false);
-  new_file_tracker.set_dirty(true);
-  EXPECT_NE(0, new_file_tracker.tracker_id());
+  renamed_file.tracker.set_dirty(true);
+  reorganized_file.tracker.set_dirty(true);
+  updated_file.tracker.set_dirty(true);
+  noop_file.tracker.set_dirty(true);
+  new_file.tracker.clear_synced_details();
+  new_file.tracker.set_active(false);
+  new_file.tracker.set_dirty(true);
+  new_file.tracker.set_tracker_id(
+      GetTrackerIDByFileID(new_file.metadata.file_id()));
+  EXPECT_NE(0, new_file.tracker.tracker_id());
 
-  VerifyFile(sync_root);
-  VerifyTracker(sync_root_tracker);
-  VerifyFile(app_root);
-  VerifyTracker(app_root_tracker);
-  VerifyFile(disabled_app_root);
-  VerifyTracker(disabled_app_root_tracker);
-  VerifyFile(file);
-  VerifyTracker(file_tracker);
-  VerifyFile(renamed_file);
-  VerifyTracker(renamed_file_tracker);
-  VerifyFile(folder);
-  VerifyTracker(folder_tracker);
-  VerifyFile(reorganized_file);
-  VerifyTracker(reorganized_file_tracker);
-  VerifyFile(updated_file);
-  VerifyTracker(updated_file_tracker);
-  VerifyFile(noop_file);
-  VerifyTracker(noop_file_tracker);
-  VerifyFile(new_file);
-  VerifyTracker(new_file_tracker);
+  new_file.should_be_absent = false;
 
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
+  VerifyReloadConsistency();
+}
+
+TEST_F(MetadataDatabaseTest, PopulateFolderTest_RegularFolder) {
+  TrackedFile sync_root(CreateTrackedSyncRoot());
+  TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id"));
+  app_root.tracker.set_app_id(app_root.metadata.details().title());
+
+  TrackedFile folder_to_populate(
+      CreateTrackedFolder(app_root, "folder_to_populate"));
+  folder_to_populate.tracker.set_needs_folder_listing(true);
+  folder_to_populate.tracker.set_dirty(true);
+
+  TrackedFile known_file(CreateTrackedFile(folder_to_populate, "known_file"));
+  TrackedFile new_file(CreateTrackedFile(folder_to_populate, "new_file"));
+  new_file.should_be_absent = true;
+
+  const TrackedFile* tracked_files[] = {
+    &sync_root, &app_root, &folder_to_populate, &known_file, &new_file
+  };
+
+  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
+
+  FileIDList listed_children;
+  listed_children.push_back(known_file.metadata.file_id());
+  listed_children.push_back(new_file.metadata.file_id());
+
+  EXPECT_EQ(SYNC_STATUS_OK,
+            PopulateFolder(folder_to_populate.metadata.file_id(),
+                           listed_children));
+
+  folder_to_populate.tracker.set_dirty(false);
+  folder_to_populate.tracker.set_needs_folder_listing(false);
+  new_file.tracker.set_tracker_id(
+      GetTrackerIDByFileID(new_file.metadata.file_id()));
+  new_file.tracker.set_dirty(true);
+  new_file.tracker.set_active(false);
+  new_file.tracker.clear_synced_details();
+  new_file.should_be_absent = false;
+  new_file.tracker_only = true;
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
+  VerifyReloadConsistency();
+}
+
+TEST_F(MetadataDatabaseTest, PopulateFolderTest_InactiveFolder) {
+  TrackedFile sync_root(CreateTrackedSyncRoot());
+  TrackedFile app_root(CreateTrackedAppRoot(sync_root, "app_id"));
+
+  TrackedFile inactive_folder(CreateTrackedFolder(app_root, "inactive_folder"));
+  inactive_folder.tracker.set_active(false);
+  inactive_folder.tracker.set_dirty(true);
+
+  TrackedFile new_file(
+      CreateTrackedFile(inactive_folder, "file_in_inactive_folder"));
+  new_file.should_be_absent = true;
+
+  const TrackedFile* tracked_files[] = {
+    &sync_root, &app_root, &inactive_folder, &new_file,
+  };
+
+  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
+
+  FileIDList listed_children;
+  listed_children.push_back(new_file.metadata.file_id());
+
+  EXPECT_EQ(SYNC_STATUS_OK,
+            PopulateFolder(inactive_folder.metadata.file_id(),
+                           listed_children));
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
+  VerifyReloadConsistency();
+}
+
+TEST_F(MetadataDatabaseTest, PopulateFolderTest_DisabledAppRoot) {
+  TrackedFile sync_root(CreateTrackedSyncRoot());
+  TrackedFile disabled_app_root(
+      CreateTrackedAppRoot(sync_root, "disabled_app"));
+  disabled_app_root.tracker.set_dirty(true);
+  disabled_app_root.tracker.set_needs_folder_listing(true);
+
+  TrackedFile known_file(CreateTrackedFile(disabled_app_root, "known_file"));
+  TrackedFile file(CreateTrackedFile(disabled_app_root, "file"));
+  file.should_be_absent = true;
+
+  const TrackedFile* tracked_files[] = {
+    &sync_root, &disabled_app_root, &disabled_app_root, &known_file, &file,
+  };
+
+  SetUpDatabaseByTrackedFiles(tracked_files, arraysize(tracked_files));
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
+
+  FileIDList disabled_app_children;
+  disabled_app_children.push_back(file.metadata.file_id());
+  EXPECT_EQ(SYNC_STATUS_OK, PopulateFolder(
+      disabled_app_root.metadata.file_id(), disabled_app_children));
+  file.tracker.set_tracker_id(GetTrackerIDByFileID(file.metadata.file_id()));
+  file.tracker.clear_synced_details();
+  file.tracker.set_dirty(true);
+  file.tracker.set_active(false);
+  file.should_be_absent = false;
+  file.tracker_only = true;
+
+  disabled_app_root.tracker.set_dirty(false);
+  disabled_app_root.tracker.set_needs_folder_listing(false);
+  VerifyTrackedFiles(tracked_files, arraysize(tracked_files));
   VerifyReloadConsistency();
 }
 
diff --git a/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.cc b/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.cc
index 0fd06b7..0149ec6 100644
--- a/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.cc
+++ b/chrome/browser/sync_file_system/drive_backend/remote_sync_delegate.cc
@@ -232,10 +232,10 @@
     const SyncStatusCallback& callback,
     SyncFileType remote_file_type) {
   ConflictResolution resolution = conflict_resolution_resolver()->Resolve(
-      remote_file_type,
-      remote_change_.updated_time,
       local_metadata_.file_type,
-      local_metadata_.last_modified);
+      local_metadata_.last_modified,
+      remote_file_type,
+      remote_change_.updated_time);
 
   switch (resolution) {
     case CONFLICT_RESOLUTION_LOCAL_WIN:
diff --git a/chrome/browser/sync_file_system/local/sync_file_system_backend.cc b/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
index 5cb2cd2..ac426c9 100644
--- a/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
+++ b/chrome/browser/sync_file_system/local/sync_file_system_backend.cc
@@ -9,11 +9,9 @@
 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
 #include "chrome/browser/sync_file_system/local/syncable_file_system_operation.h"
 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
-#include "webkit/browser/fileapi/async_file_util_adapter.h"
 #include "webkit/browser/fileapi/file_system_context.h"
 #include "webkit/browser/fileapi/file_system_file_stream_reader.h"
 #include "webkit/browser/fileapi/file_system_operation_impl.h"
-#include "webkit/browser/fileapi/obfuscated_file_util.h"
 #include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
 #include "webkit/browser/fileapi/sandbox_quota_observer.h"
 #include "webkit/common/fileapi/file_system_util.h"
@@ -21,12 +19,12 @@
 namespace sync_file_system {
 
 SyncFileSystemBackend::SyncFileSystemBackend()
-    : sandbox_context_(NULL) {
+    : delegate_(NULL) {
 }
 
 SyncFileSystemBackend::~SyncFileSystemBackend() {
   if (change_tracker_) {
-    sandbox_context_->file_task_runner()->DeleteSoon(
+    delegate_->file_task_runner()->DeleteSoon(
         FROM_HERE, change_tracker_.release());
   }
 }
@@ -39,14 +37,17 @@
 
 void SyncFileSystemBackend::Initialize(fileapi::FileSystemContext* context) {
   DCHECK(context);
-  DCHECK(!sandbox_context_);
-  sandbox_context_ = context->sandbox_context();
-  update_observers_ = update_observers_.AddObserver(
-      sandbox_context_->quota_observer(),
-      sandbox_context_->file_task_runner());
-  syncable_update_observers_ = syncable_update_observers_.AddObserver(
-      sandbox_context_->quota_observer(),
-      sandbox_context_->file_task_runner());
+  DCHECK(!delegate_);
+  delegate_ = context->sandbox_delegate();
+
+  delegate_->AddFileUpdateObserver(
+      fileapi::kFileSystemTypeSyncable,
+      delegate_->quota_observer(),
+      delegate_->file_task_runner());
+  delegate_->AddFileUpdateObserver(
+      fileapi::kFileSystemTypeSyncableForInternalSync,
+      delegate_->quota_observer(),
+      delegate_->file_task_runner());
 }
 
 void SyncFileSystemBackend::OpenFileSystem(
@@ -55,22 +56,21 @@
     fileapi::OpenFileSystemMode mode,
     const OpenFileSystemCallback& callback) {
   DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->OpenFileSystem(
-      origin_url, type, mode, callback,
-      GetSyncableFileSystemRootURI(origin_url));
+  DCHECK(delegate_);
+  delegate_->OpenFileSystem(origin_url, type, mode, callback,
+                            GetSyncableFileSystemRootURI(origin_url));
 }
 
 fileapi::FileSystemFileUtil* SyncFileSystemBackend::GetFileUtil(
     fileapi::FileSystemType type) {
-  DCHECK(sandbox_context_);
-  return sandbox_context_->sync_file_util();
+  DCHECK(delegate_);
+  return delegate_->sync_file_util();
 }
 
 fileapi::AsyncFileUtil* SyncFileSystemBackend::GetAsyncFileUtil(
     fileapi::FileSystemType type) {
-  DCHECK(sandbox_context_);
-  return sandbox_context_->file_util();
+  DCHECK(delegate_);
+  return delegate_->file_util();
 }
 
 fileapi::CopyOrMoveFileValidatorFactory*
@@ -90,23 +90,18 @@
   DCHECK(CanHandleType(url.type()));
   DCHECK(context);
   DCHECK(error_code);
-  if (!sandbox_context_->IsAccessValid(url)) {
-    *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
-    return NULL;
-  }
 
-  scoped_ptr<fileapi::FileSystemOperationContext> operation_context(
-      new fileapi::FileSystemOperationContext(context));
+  DCHECK(delegate_);
+  scoped_ptr<fileapi::FileSystemOperationContext> operation_context =
+      delegate_->CreateFileSystemOperationContext(url, context, error_code);
+  if (!operation_context)
+    return NULL;
 
   if (url.type() == fileapi::kFileSystemTypeSyncableForInternalSync) {
-    operation_context->set_update_observers(update_observers_);
-    operation_context->set_change_observers(change_observers_);
     return new fileapi::FileSystemOperationImpl(
         url, context, operation_context.Pass());
   }
 
-  operation_context->set_update_observers(syncable_update_observers_);
-  operation_context->set_change_observers(syncable_change_observers_);
   return new SyncableFileSystemOperation(
       url, context, operation_context.Pass());
 }
@@ -118,11 +113,9 @@
     const base::Time& expected_modification_time,
     fileapi::FileSystemContext* context) const {
   DCHECK(CanHandleType(url.type()));
-  if (!sandbox_context_->IsAccessValid(url))
-    return scoped_ptr<webkit_blob::FileStreamReader>();
-  return scoped_ptr<webkit_blob::FileStreamReader>(
-      new fileapi::FileSystemFileStreamReader(
-          context, url, offset, expected_modification_time));
+  DCHECK(delegate_);
+  return delegate_->CreateFileStreamReader(
+      url, offset, expected_modification_time, context);
 }
 
 scoped_ptr<fileapi::FileStreamWriter>
@@ -131,116 +124,13 @@
     int64 offset,
     fileapi::FileSystemContext* context) const {
   DCHECK(CanHandleType(url.type()));
-  if (!sandbox_context_->IsAccessValid(url))
-    return scoped_ptr<fileapi::FileStreamWriter>();
-  return scoped_ptr<fileapi::FileStreamWriter>(
-      new fileapi::SandboxFileStreamWriter(
-          context, url, offset, update_observers_));
+  DCHECK(delegate_);
+  return delegate_->CreateFileStreamWriter(
+      url, offset, context, fileapi::kFileSystemTypeSyncableForInternalSync);
 }
 
 fileapi::FileSystemQuotaUtil* SyncFileSystemBackend::GetQuotaUtil() {
-  return this;
-}
-
-base::PlatformFileError SyncFileSystemBackend::DeleteOriginDataOnFileThread(
-    fileapi::FileSystemContext* context,
-    quota::QuotaManagerProxy* proxy,
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  return sandbox_context_->DeleteOriginDataOnFileThread(
-      context, proxy, origin_url, type);
-}
-
-void SyncFileSystemBackend::GetOriginsForTypeOnFileThread(
-    fileapi::FileSystemType type,
-    std::set<GURL>* origins) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->GetOriginsForTypeOnFileThread(type, origins);
-}
-
-void SyncFileSystemBackend::GetOriginsForHostOnFileThread(
-    fileapi::FileSystemType type,
-    const std::string& host,
-    std::set<GURL>* origins) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->GetOriginsForHostOnFileThread(type, host, origins);
-}
-
-int64 SyncFileSystemBackend::GetOriginUsageOnFileThread(
-    fileapi::FileSystemContext* context,
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  return sandbox_context_->GetOriginUsageOnFileThread(
-      context, origin_url, type);
-}
-
-void SyncFileSystemBackend::InvalidateUsageCache(
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->InvalidateUsageCache(origin_url, type);
-}
-
-void SyncFileSystemBackend::StickyInvalidateUsageCache(
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->StickyInvalidateUsageCache(origin_url, type);
-}
-
-void SyncFileSystemBackend::AddFileUpdateObserver(
-    fileapi::FileSystemType type,
-    fileapi::FileUpdateObserver* observer,
-    base::SequencedTaskRunner* task_runner) {
-  DCHECK_EQ(fileapi::kFileSystemTypeSyncable, type);
-  fileapi::UpdateObserverList* list = &syncable_update_observers_;
-  *list = list->AddObserver(observer, task_runner);
-}
-
-void SyncFileSystemBackend::AddFileChangeObserver(
-    fileapi::FileSystemType type,
-    fileapi::FileChangeObserver* observer,
-    base::SequencedTaskRunner* task_runner) {
-  DCHECK_EQ(fileapi::kFileSystemTypeSyncable, type);
-  fileapi::ChangeObserverList* list = &syncable_change_observers_;
-  *list = list->AddObserver(observer, task_runner);
-}
-
-void SyncFileSystemBackend::AddFileAccessObserver(
-    fileapi::FileSystemType type,
-    fileapi::FileAccessObserver* observer,
-    base::SequencedTaskRunner* task_runner) {
-  NOTREACHED() << "SyncFileSystemBackend does not support access observers.";
-}
-
-const fileapi::UpdateObserverList* SyncFileSystemBackend::GetUpdateObservers(
-    fileapi::FileSystemType type) const {
-  DCHECK(CanHandleType(type));
-  if (type != fileapi::kFileSystemTypeSyncable)
-    return NULL;
-  return &syncable_update_observers_;
-}
-
-const fileapi::ChangeObserverList* SyncFileSystemBackend::GetChangeObservers(
-    fileapi::FileSystemType type) const {
-  DCHECK(CanHandleType(type));
-  DCHECK_EQ(fileapi::kFileSystemTypeSyncable, type);
-  if (type != fileapi::kFileSystemTypeSyncable)
-    return NULL;
-  return &syncable_change_observers_;
-}
-
-const fileapi::AccessObserverList* SyncFileSystemBackend::GetAccessObservers(
-    fileapi::FileSystemType type) const {
-  return NULL;
+  return delegate_;
 }
 
 // static
@@ -258,15 +148,15 @@
   DCHECK(tracker);
   change_tracker_ = tracker.Pass();
 
-  DCHECK(sandbox_context_);
-  AddFileUpdateObserver(
+  DCHECK(delegate_);
+  delegate_->AddFileUpdateObserver(
       fileapi::kFileSystemTypeSyncable,
       change_tracker_.get(),
-      sandbox_context_->file_task_runner());
-  AddFileChangeObserver(
+      delegate_->file_task_runner());
+  delegate_->AddFileChangeObserver(
       fileapi::kFileSystemTypeSyncable,
       change_tracker_.get(),
-      sandbox_context_->file_task_runner());
+      delegate_->file_task_runner());
 }
 
 void SyncFileSystemBackend::set_sync_context(
diff --git a/chrome/browser/sync_file_system/local/sync_file_system_backend.h b/chrome/browser/sync_file_system/local/sync_file_system_backend.h
index c203693..fdba979 100644
--- a/chrome/browser/sync_file_system/local/sync_file_system_backend.h
+++ b/chrome/browser/sync_file_system/local/sync_file_system_backend.h
@@ -7,7 +7,7 @@
 
 #include "webkit/browser/fileapi/file_system_backend.h"
 #include "webkit/browser/fileapi/file_system_quota_util.h"
-#include "webkit/browser/fileapi/sandbox_context.h"
+#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
 
 namespace sync_file_system {
 
@@ -15,8 +15,7 @@
 class LocalFileSyncContext;
 
 class SyncFileSystemBackend
-    : public fileapi::FileSystemBackend,
-      public fileapi::FileSystemQuotaUtil {
+    : public fileapi::FileSystemBackend {
  public:
   SyncFileSystemBackend();
   virtual ~SyncFileSystemBackend();
@@ -52,48 +51,6 @@
       fileapi::FileSystemContext* context) const OVERRIDE;
   virtual fileapi::FileSystemQuotaUtil* GetQuotaUtil() OVERRIDE;
 
-  // FileSystemQuotaUtil overrides.
-  virtual base::PlatformFileError DeleteOriginDataOnFileThread(
-      fileapi::FileSystemContext* context,
-      quota::QuotaManagerProxy* proxy,
-      const GURL& origin_url,
-      fileapi::FileSystemType type) OVERRIDE;
-  virtual void GetOriginsForTypeOnFileThread(
-      fileapi::FileSystemType type,
-      std::set<GURL>* origins) OVERRIDE;
-  virtual void GetOriginsForHostOnFileThread(
-      fileapi::FileSystemType type,
-      const std::string& host,
-      std::set<GURL>* origins) OVERRIDE;
-  virtual int64 GetOriginUsageOnFileThread(
-      fileapi::FileSystemContext* context,
-      const GURL& origin_url,
-      fileapi::FileSystemType type) OVERRIDE;
-  virtual void InvalidateUsageCache(
-      const GURL& origin_url,
-      fileapi::FileSystemType type) OVERRIDE;
-  virtual void StickyInvalidateUsageCache(
-      const GURL& origin_url,
-      fileapi::FileSystemType type) OVERRIDE;
-  virtual void AddFileUpdateObserver(
-      fileapi::FileSystemType type,
-      fileapi::FileUpdateObserver* observer,
-      base::SequencedTaskRunner* task_runner) OVERRIDE;
-  virtual void AddFileChangeObserver(
-      fileapi::FileSystemType type,
-      fileapi::FileChangeObserver* observer,
-      base::SequencedTaskRunner* task_runner) OVERRIDE;
-  virtual void AddFileAccessObserver(
-      fileapi::FileSystemType type,
-      fileapi::FileAccessObserver* observer,
-      base::SequencedTaskRunner* task_runner) OVERRIDE;
-  virtual const fileapi::UpdateObserverList* GetUpdateObservers(
-      fileapi::FileSystemType type) const OVERRIDE;
-  virtual const fileapi::ChangeObserverList* GetChangeObservers(
-      fileapi::FileSystemType type) const OVERRIDE;
-  virtual const fileapi::AccessObserverList* GetAccessObservers(
-      fileapi::FileSystemType type) const OVERRIDE;
-
   static SyncFileSystemBackend* GetBackend(
       const fileapi::FileSystemContext* context);
 
@@ -109,15 +66,8 @@
   void set_sync_context(sync_file_system::LocalFileSyncContext* sync_context);
 
  private:
-  // Observers for internal sync.
-  fileapi::UpdateObserverList update_observers_;
-  fileapi::ChangeObserverList change_observers_;
-
-  fileapi::UpdateObserverList syncable_update_observers_;
-  fileapi::ChangeObserverList syncable_change_observers_;
-
   // Owned by FileSystemContext.
-  fileapi::SandboxContext* sandbox_context_;
+  fileapi::SandboxFileSystemBackendDelegate* delegate_;
 
   scoped_ptr<sync_file_system::LocalFileChangeTracker> change_tracker_;
   scoped_refptr<sync_file_system::LocalFileSyncContext> sync_context_;
diff --git a/chrome/browser/sync_file_system/mock_remote_file_sync_service.h b/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
index de49827..3f24cd0 100644
--- a/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
+++ b/chrome/browser/sync_file_system/mock_remote_file_sync_service.h
@@ -57,6 +57,13 @@
                SyncStatusCode(ConflictResolutionPolicy));
   MOCK_CONST_METHOD0(GetConflictResolutionPolicy,
                      ConflictResolutionPolicy());
+  MOCK_METHOD2(GetRemoteVersions,
+               void(const fileapi::FileSystemURL&,
+                    const RemoteVersionsCallback&));
+  MOCK_METHOD3(DownloadRemoteVersion,
+               void(const fileapi::FileSystemURL&,
+                    const std::string&,
+                    const DownloadVersionCallback&));
 
   virtual scoped_ptr<base::ListValue> DumpFiles(const GURL& origin) OVERRIDE;
 
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 39c4cae..3d6e4bd 100644
--- a/chrome/browser/sync_file_system/remote_file_sync_service.h
+++ b/chrome/browser/sync_file_system/remote_file_sync_service.h
@@ -7,10 +7,12 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "chrome/browser/sync_file_system/conflict_resolution_policy.h"
 #include "chrome/browser/sync_file_system/sync_callbacks.h"
+#include "chrome/browser/sync_file_system/sync_file_metadata.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 
 class GURL;
@@ -19,6 +21,10 @@
 class ListValue;
 }
 
+namespace webkit_blob {
+class ScopedFile;
+}
+
 namespace sync_file_system {
 
 class FileStatusObserver;
@@ -80,6 +86,22 @@
     DISALLOW_COPY_AND_ASSIGN(Observer);
   };
 
+  struct Version {
+    std::string id;
+    SyncFileMetadata metadata;
+  };
+
+  // For GetOriginStatusMap.
+  typedef std::map<GURL, std::string> OriginStatusMap;
+
+  // For GetRemoteVersions.
+  typedef base::Callback<void(SyncStatusCode status,
+                              const std::vector<Version>& versions)>
+      RemoteVersionsCallback;
+  typedef base::Callback<void(SyncStatusCode status,
+                              scoped_ptr<webkit_blob::ScopedFile> downloaded)>
+      DownloadVersionCallback;
+
   RemoteFileSyncService() {}
   virtual ~RemoteFileSyncService() {}
 
@@ -145,7 +167,6 @@
 
   // Returns all origins along with an arbitrary string description of their
   // corresponding sync statuses.
-  typedef std::map<GURL, std::string> OriginStatusMap;
   virtual void GetOriginStatusMap(OriginStatusMap* status_map) = 0;
 
   // Returns file metadata for |origin|.
@@ -168,6 +189,19 @@
   // Gets the conflict resolution policy.
   virtual ConflictResolutionPolicy GetConflictResolutionPolicy() const = 0;
 
+  // Returns a list of remote versions with their metadata.
+  // This method is typically called for a file which is in conflicting state.
+  virtual void GetRemoteVersions(
+      const fileapi::FileSystemURL& url,
+      const RemoteVersionsCallback& callback) = 0;
+
+  // Downloads the remote image.  The |id| should be the ID string for a
+  // version returned by GetRemoteVersions.
+  virtual void DownloadRemoteVersion(
+      const fileapi::FileSystemURL& url,
+      const std::string& id,
+      const DownloadVersionCallback& callback) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(RemoteFileSyncService);
 };
diff --git a/chrome/browser/sync_file_system/sync_status_code.cc b/chrome/browser/sync_file_system/sync_status_code.cc
index c2603cc..366980c 100644
--- a/chrome/browser/sync_file_system/sync_status_code.cc
+++ b/chrome/browser/sync_file_system/sync_status_code.cc
@@ -50,6 +50,8 @@
       return "File not empty.";
     case SYNC_FILE_ERROR_INVALID_URL:
       return "Invalid URL.";
+    case SYNC_FILE_ERROR_IO:
+      return "OS or hardware error.";
 
     // Database related errors.
     case SYNC_DATABASE_ERROR_NOT_FOUND:
@@ -139,6 +141,8 @@
       return SYNC_FILE_ERROR_NOT_EMPTY;
     case base::PLATFORM_FILE_ERROR_INVALID_URL:
       return SYNC_FILE_ERROR_INVALID_URL;
+    case base::PLATFORM_FILE_ERROR_IO:
+      return SYNC_FILE_ERROR_IO;
     default:
       return SYNC_FILE_ERROR_FAILED;
   }
diff --git a/chrome/browser/sync_file_system/sync_status_code.h b/chrome/browser/sync_file_system/sync_status_code.h
index e3ec68e..d12787c 100644
--- a/chrome/browser/sync_file_system/sync_status_code.h
+++ b/chrome/browser/sync_file_system/sync_status_code.h
@@ -39,12 +39,13 @@
   SYNC_FILE_ERROR_NOT_A_FILE = -13,
   SYNC_FILE_ERROR_NOT_EMPTY = -14,
   SYNC_FILE_ERROR_INVALID_URL = -15,
+  SYNC_FILE_ERROR_IO = -16,
 
   // Database related errors.
-  SYNC_DATABASE_ERROR_NOT_FOUND = -16,
-  SYNC_DATABASE_ERROR_CORRUPTION = -17,
-  SYNC_DATABASE_ERROR_IO_ERROR = -18,
-  SYNC_DATABASE_ERROR_FAILED = -19,
+  SYNC_DATABASE_ERROR_NOT_FOUND = -50,
+  SYNC_DATABASE_ERROR_CORRUPTION = -51,
+  SYNC_DATABASE_ERROR_IO_ERROR = -52,
+  SYNC_DATABASE_ERROR_FAILED = -53,
 
   // Sync specific status code.
   SYNC_STATUS_FILE_BUSY = -100,
diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc
index a569d4e..8d3dcec 100644
--- a/chrome/browser/tab_contents/background_contents.cc
+++ b/chrome/browser/tab_contents/background_contents.cc
@@ -13,6 +13,7 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/session_storage_namespace.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/view_type_utils.h"
@@ -21,17 +22,27 @@
 using content::SiteInstance;
 using content::WebContents;
 
-BackgroundContents::BackgroundContents(SiteInstance* site_instance,
-                                       int routing_id,
-                                       Delegate* delegate)
+BackgroundContents::BackgroundContents(
+    SiteInstance* site_instance,
+    int routing_id,
+    Delegate* delegate,
+    const std::string& partition_id,
+    content::SessionStorageNamespace* session_storage_namespace)
     : delegate_(delegate) {
   profile_ = Profile::FromBrowserContext(
       site_instance->GetBrowserContext());
 
-  // TODO(rafaelw): Implement correct session storage.
   WebContents::CreateParams create_params(profile_, site_instance);
   create_params.routing_id = routing_id;
-  web_contents_.reset(WebContents::Create(create_params));
+  if (session_storage_namespace) {
+    content::SessionStorageNamespaceMap session_storage_namespace_map;
+    session_storage_namespace_map.insert(
+        std::make_pair(partition_id, session_storage_namespace));
+    web_contents_.reset(WebContents::CreateWithSessionStorage(
+        create_params, session_storage_namespace_map));
+  } else {
+    web_contents_.reset(WebContents::Create(create_params));
+  }
   extensions::SetViewType(
       web_contents_.get(), extensions::VIEW_TYPE_BACKGROUND_CONTENTS);
   web_contents_->SetDelegate(this);
diff --git a/chrome/browser/tab_contents/background_contents.h b/chrome/browser/tab_contents/background_contents.h
index e6b817c..90d80a5 100644
--- a/chrome/browser/tab_contents/background_contents.h
+++ b/chrome/browser/tab_contents/background_contents.h
@@ -17,6 +17,7 @@
 class Profile;
 
 namespace content {
+class SessionStorageNamespace;
 class SiteInstance;
 };
 
@@ -42,9 +43,12 @@
     virtual ~Delegate() {}
   };
 
-  BackgroundContents(content::SiteInstance* site_instance,
-                     int routing_id,
-                     Delegate* delegate);
+  BackgroundContents(
+      content::SiteInstance* site_instance,
+      int routing_id,
+      Delegate* delegate,
+      const std::string& partition_id,
+      content::SessionStorageNamespace* session_storage_namespace);
   virtual ~BackgroundContents();
 
   content::WebContents* web_contents() const { return web_contents_.get(); }
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index c7a2795..46118e2 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -1363,6 +1363,7 @@
       // the page) from the NavigationEntry because its reflects their origin
       // rather than the display one (returned by GetURL) which may be
       // different (like having "view-source:" on the front).
+      // TODO(nasko): Audit all GetActiveEntry calls in this file.
       NavigationEntry* active_entry =
           source_web_contents_->GetController().GetActiveEntry();
       return content::IsSavableURL(
@@ -1796,7 +1797,9 @@
 
     case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
       NavigationController* controller = &source_web_contents_->GetController();
-      NavigationEntry* nav_entry = controller->GetActiveEntry();
+      // Important to use GetVisibleEntry to match what's showing in the
+      // omnibox.
+      NavigationEntry* nav_entry = controller->GetVisibleEntry();
       Browser* browser =
           chrome::FindBrowserWithWebContents(source_web_contents_);
       chrome::ShowWebsiteSettings(browser, source_web_contents_,
diff --git a/chrome/browser/tab_contents/spelling_menu_observer_browsertest.cc b/chrome/browser/tab_contents/spelling_menu_observer_browsertest.cc
index ae5c0a0..ad3e7fa 100644
--- a/chrome/browser/tab_contents/spelling_menu_observer_browsertest.cc
+++ b/chrome/browser/tab_contents/spelling_menu_observer_browsertest.cc
@@ -44,7 +44,7 @@
     string16 title;
   };
 
-  MockRenderViewContextMenu();
+  explicit MockRenderViewContextMenu(bool incognito);
   virtual ~MockRenderViewContextMenu();
 
   // RenderViewContextMenuProxy implementation.
@@ -89,9 +89,12 @@
   DISALLOW_COPY_AND_ASSIGN(MockRenderViewContextMenu);
 };
 
-MockRenderViewContextMenu::MockRenderViewContextMenu()
-  : observer_(NULL),
-    profile_(new TestingProfile) {
+MockRenderViewContextMenu::MockRenderViewContextMenu(bool incognito)
+    : observer_(NULL) {
+  TestingProfile::Builder builder;
+  if (incognito)
+    builder.SetIncognito();
+  profile_ = builder.Build();
 }
 
 MockRenderViewContextMenu::~MockRenderViewContextMenu() {
@@ -202,7 +205,7 @@
   SpellingMenuObserverTest();
 
   virtual void SetUpOnMainThread() OVERRIDE {
-    Reset();
+    Reset(false);
   }
 
   virtual void CleanUpOnMainThread() OVERRIDE {
@@ -210,9 +213,9 @@
     menu_.reset();
   }
 
-  void Reset() {
+  void Reset(bool incognito) {
     observer_.reset();
-    menu_.reset(new MockRenderViewContextMenu);
+    menu_.reset(new MockRenderViewContextMenu(incognito));
     observer_.reset(new SpellingMenuObserver(menu_.get()));
     menu_->SetObserver(observer_.get());
   }
@@ -395,7 +398,8 @@
 // is functional.
 IN_PROC_BROWSER_TEST_F(SpellingMenuObserverTest,
                        NoSpellingServiceWhenOffTheRecord) {
-  menu()->GetProfile()->AsTestingProfile()->set_incognito(true);
+  // Create a menu in an incognito profile.
+  Reset(true);
 
   // This means spellchecking is allowed. Default is that the service is
   // contacted but this test makes sure that if profile is incognito, that
@@ -433,9 +437,6 @@
   EXPECT_EQ(IDC_CONTENT_CONTEXT_SPELLING_TOGGLE, item.command_id);
   EXPECT_FALSE(item.enabled);
   EXPECT_FALSE(item.hidden);
-
-  // Set incognito back to false to allow appropriate test cleanup.
-  menu()->GetProfile()->AsTestingProfile()->set_incognito(false);
 }
 
 // Test that the menu is preceeded by a separator if there are any suggestions,
@@ -452,7 +453,7 @@
   EXPECT_NE(-1, item.command_id);
 
   // Case #2. Misspelled word, suggestions, no spellcheck service.
-  Reset();
+  Reset(false);
   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, false);
   InitMenu("asdfkj", "asdf");
 
@@ -463,7 +464,7 @@
   EXPECT_EQ(-1, item.command_id);
 
   // Case #3. Misspelled word, suggestion service is on.
-  Reset();
+  Reset(false);
   menu()->GetPrefs()->SetBoolean(prefs::kSpellCheckUseSpellingService, true);
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   command_line->AppendSwitch(switches::kUseSpellingSuggestions);
diff --git a/chrome/browser/task_manager/child_process_resource_provider.cc b/chrome/browser/task_manager/child_process_resource_provider.cc
index 0c48d6c..c195800 100644
--- a/chrome/browser/task_manager/child_process_resource_provider.cc
+++ b/chrome/browser/task_manager/child_process_resource_provider.cc
@@ -8,14 +8,12 @@
 
 #include "base/i18n/rtl.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/task_manager/resource_provider.h"
 #include "chrome/browser/task_manager/task_manager.h"
 #include "components/nacl/common/nacl_process_type.h"
 #include "content/public/browser/browser_child_process_host_iterator.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_data.h"
-#include "content/public/browser/notification_service.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -343,10 +341,7 @@
   for (size_t i = 0; i < child_processes.size(); ++i)
     AddToTaskManager(child_processes[i]);
 
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY,
-      content::Source<ChildProcessResourceProvider>(this),
-      content::NotificationService::NoDetails());
+  task_manager_->model()->NotifyDataReady();
 }
 
 }  // namespace task_manager
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc
index 1a9154a..fcd4f30 100644
--- a/chrome/browser/task_manager/task_manager.cc
+++ b/chrome/browser/task_manager/task_manager.cc
@@ -1238,7 +1238,24 @@
                      routing_id, byte_count));
 }
 
+// This is called on the UI thread.
+void TaskManagerModel::NotifyDataReady() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  for (size_t i = 0; i < on_data_ready_callbacks_.size(); ++i) {
+    if (!on_data_ready_callbacks_[i].is_null())
+        on_data_ready_callbacks_[i].Run();
+  }
+
+  on_data_ready_callbacks_.clear();
+}
+
+void TaskManagerModel::RegisterOnDataReadyCallback(
+    const base::Closure& callback) {
+  on_data_ready_callbacks_.push_back(callback);
+}
+
 TaskManagerModel::~TaskManagerModel() {
+  on_data_ready_callbacks_.clear();
 }
 
 void TaskManagerModel::RefreshCallback() {
diff --git a/chrome/browser/task_manager/task_manager.h b/chrome/browser/task_manager/task_manager.h
index 80573e1..eb62db1 100644
--- a/chrome/browser/task_manager/task_manager.h
+++ b/chrome/browser/task_manager/task_manager.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
@@ -322,6 +323,10 @@
 
   void NotifyBytesRead(const net::URLRequest& request, int bytes_read);
 
+  void RegisterOnDataReadyCallback(const base::Closure& callback);
+
+  void NotifyDataReady();
+
  private:
   friend class base::RefCountedThreadSafe<TaskManagerModel>;
   friend class TaskManagerBrowserTest;
@@ -554,6 +559,8 @@
   // each NotifyBytesRead() call.
   std::vector<BytesReadParam> bytes_read_buffer_;
 
+  std::vector<base::Closure> on_data_ready_callbacks_;
+
   // All per-Resource values are stored here.
   mutable PerResourceCache per_resource_cache_;
 
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index e24346d..056b9dc 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_util.h"
@@ -55,6 +56,12 @@
 // unpacked on the filesystem.)
 const char* kDefaultThemeGalleryID = "hkacjpbfdknhflllbcmjibkdeoafencn";
 
+// Wait this many seconds after startup to garbage collect unused themes.
+// Removing unused themes is done after a delay because there is no
+// reason to do it at startup.
+// ExtensionService::GarbageCollectExtensions() does something similar.
+const int kRemoveUnusedThemesStartupDelay = 30;
+
 SkColor TintForUnderline(SkColor input) {
   return SkColorSetA(input, SkColorGetA(input) / 3);
 }
@@ -79,6 +86,7 @@
     : ready_(false),
       rb_(ResourceBundle::GetSharedInstance()),
       profile_(NULL),
+      installed_pending_load_id_(kDefaultThemeID),
       number_of_infobars_(0),
       weak_ptr_factory_(this) {
 }
@@ -96,11 +104,9 @@
 
   LoadThemePrefs();
 
-  if (!ready_) {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_EXTENSIONS_READY,
-                   content::Source<Profile>(profile_));
-  }
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSIONS_READY,
+                 content::Source<Profile>(profile_));
 
   theme_syncable_service_.reset(new ThemeSyncableService(profile_, this));
 }
@@ -211,36 +217,83 @@
 void ThemeService::Observe(int type,
                            const content::NotificationSource& source,
                            const content::NotificationDetails& details) {
-  DCHECK(type == chrome::NOTIFICATION_EXTENSIONS_READY);
-  registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
-      content::Source<Profile>(profile_));
-
-  MigrateTheme();
-  set_ready();
-
-  // Send notification in case anyone requested data and cached it when the
-  // theme service was not ready yet.
-  NotifyThemeChanged();
+  using content::Details;
+  switch (type) {
+    case chrome::NOTIFICATION_EXTENSIONS_READY:
+      registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
+          content::Source<Profile>(profile_));
+      OnExtensionServiceReady();
+      break;
+    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
+    {
+      // The theme may be initially disabled. Wait till it is loaded (if ever).
+      Details<const extensions::InstalledExtensionInfo> installed_details(
+          details);
+      if (installed_details->extension->is_theme())
+        installed_pending_load_id_ = installed_details->extension->id();
+      break;
+    }
+    case chrome::NOTIFICATION_EXTENSION_LOADED:
+    {
+      const Extension* extension = Details<const Extension>(details).ptr();
+      if (extension->is_theme() &&
+          installed_pending_load_id_ != kDefaultThemeID &&
+          installed_pending_load_id_ == extension->id()) {
+        SetTheme(extension);
+      }
+      installed_pending_load_id_ = kDefaultThemeID;
+      break;
+    }
+    case chrome::NOTIFICATION_EXTENSION_ENABLED:
+    {
+      const Extension* extension = Details<const Extension>(details).ptr();
+      if (extension->is_theme())
+        SetTheme(extension);
+      break;
+    }
+    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
+    {
+      Details<const extensions::UnloadedExtensionInfo> unloaded_details(
+          details);
+      if (unloaded_details->reason != extension_misc::UNLOAD_REASON_UPDATE &&
+          unloaded_details->extension->is_theme() &&
+          unloaded_details->extension->id() == GetThemeID()) {
+        UseDefaultTheme();
+      }
+      break;
+    }
+  }
 }
 
 void ThemeService::SetTheme(const Extension* extension) {
+  DCHECK(extension->is_theme());
+  ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile_)->extension_service();
+  if (!service->IsExtensionEnabled(extension->id())) {
+    // |extension| is disabled when reverting to the previous theme via an
+    // infobar.
+    service->EnableExtension(extension->id());
+    // Enabling the extension will call back to SetTheme().
+    return;
+  }
+
+  std::string previous_theme_id = GetThemeID();
+
   // Clear our image cache.
   FreePlatformCaches();
 
-  DCHECK(extension);
-  DCHECK(extension->is_theme());
-  if (DCHECK_IS_ON()) {
-    ExtensionService* service =
-        extensions::ExtensionSystem::Get(profile_)->extension_service();
-    DCHECK(service);
-    DCHECK(service->GetExtensionById(extension->id(), false));
-  }
-
   BuildFromExtension(extension);
   SaveThemeID(extension->id());
 
   NotifyThemeChanged();
   content::RecordAction(UserMetricsAction("Themes_Installed"));
+
+  if (previous_theme_id != kDefaultThemeID &&
+      previous_theme_id != extension->id()) {
+    // Disable the old theme.
+    service->DisableExtension(previous_theme_id,
+                              extensions::Extension::DISABLE_USER_ACTION);
+  }
 }
 
 void ThemeService::SetCustomDefaultTheme(
@@ -254,25 +307,41 @@
   return false;
 }
 
-void ThemeService::RemoveUnusedThemes() {
+void ThemeService::RemoveUnusedThemes(bool ignore_infobars) {
   // We do not want to garbage collect themes on startup (|ready_| is false).
-  // Themes will get garbage collected once
-  // ExtensionService::GarbageCollectExtensions() runs.
+  // Themes will get garbage collected after |kRemoveUnusedThemesStartupDelay|.
   if (!profile_ || !ready_)
     return;
+  if (!ignore_infobars && number_of_infobars_ != 0)
+    return;
 
   ExtensionService* service = profile_->GetExtensionService();
   if (!service)
     return;
   std::string current_theme = GetThemeID();
   std::vector<std::string> remove_list;
-  const ExtensionSet* extensions = service->extensions();
+  scoped_ptr<const ExtensionSet> extensions(
+      service->GenerateInstalledExtensionsSet());
+  extensions::ExtensionPrefs* prefs = service->extension_prefs();
   for (ExtensionSet::const_iterator it = extensions->begin();
        it != extensions->end(); ++it) {
-    if ((*it)->is_theme() && (*it)->id() != current_theme) {
-      remove_list.push_back((*it)->id());
+    const extensions::Extension* extension = *it;
+    if (extension->is_theme() &&
+        extension->id() != current_theme) {
+      // Only uninstall themes which are not disabled or are disabled with
+      // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled
+      // themes because externally installed themes are initially disabled.
+      int disable_reason = prefs->GetDisableReasons(extension->id());
+      if (!prefs->IsExtensionDisabled(extension->id()) ||
+          disable_reason == Extension::DISABLE_USER_ACTION) {
+        remove_list.push_back((*it)->id());
+      }
     }
   }
+  // TODO: Garbage collect all unused themes. This method misses themes which
+  // are installed but not loaded because they are blacklisted by a management
+  // policy provider.
+
   for (size_t i = 0; i < remove_list.size(); ++i)
     service->UninstallExtension(remove_list[i], false, NULL);
 }
@@ -328,7 +397,14 @@
   profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename);
   SaveThemeID(kDefaultThemeID);
 
-  RemoveUnusedThemes();
+  // There should be no more infobars. This may not be the case because of
+  // http://crbug.com/62154
+  // RemoveUnusedThemes is called on a task because ClearAllThemeData() may
+  // be called as a result of NOTIFICATION_EXTENSION_UNLOADED.
+  base::MessageLoop::current()->PostTask(FROM_HERE,
+      base::Bind(&ThemeService::RemoveUnusedThemes,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 true));
 }
 
 void ThemeService::LoadThemePrefs() {
@@ -359,16 +435,9 @@
   if (loaded_pack) {
     content::RecordAction(UserMetricsAction("Themes.Loaded"));
     set_ready();
-  } else {
-    // TODO(erg): We need to pop up a dialog informing the user that their
-    // theme is being migrated.
-    ExtensionService* service =
-        extensions::ExtensionSystem::Get(profile_)->extension_service();
-    if (service && service->is_ready()) {
-      MigrateTheme();
-      set_ready();
-    }
   }
+  // Else: wait for the extension service to be ready so that the theme pack
+  // can be recreated from the extension.
 }
 
 void ThemeService::NotifyThemeChanged() {
@@ -398,16 +467,41 @@
 }
 #endif
 
-void ThemeService::SwapThemeSupplier(
-    scoped_refptr<CustomThemeSupplier> theme_supplier) {
-  if (theme_supplier_.get())
-    theme_supplier_->StopUsingTheme();
-  theme_supplier_ = theme_supplier;
-  if (theme_supplier_.get())
-    theme_supplier_->StartUsingTheme();
+void ThemeService::OnExtensionServiceReady() {
+  if (!ready_) {
+    // If the ThemeService is not ready yet, the custom theme data pack needs to
+    // be recreated from the extension.
+    MigrateTheme();
+    set_ready();
+
+    // Send notification in case anyone requested data and cached it when the
+    // theme service was not ready yet.
+    NotifyThemeChanged();
+  }
+
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSION_INSTALLED,
+                 content::Source<Profile>(profile_));
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSION_LOADED,
+                 content::Source<Profile>(profile_));
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSION_ENABLED,
+                 content::Source<Profile>(profile_));
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_EXTENSION_UNLOADED,
+                 content::Source<Profile>(profile_));
+
+  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      base::Bind(&ThemeService::RemoveUnusedThemes,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 false),
+      base::TimeDelta::FromSeconds(kRemoveUnusedThemesStartupDelay));
 }
 
 void ThemeService::MigrateTheme() {
+  // TODO(erg): We need to pop up a dialog informing the user that their
+  // theme is being migrated.
   ExtensionService* service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
   const Extension* extension = service ?
@@ -423,6 +517,15 @@
   }
 }
 
+void ThemeService::SwapThemeSupplier(
+    scoped_refptr<CustomThemeSupplier> theme_supplier) {
+  if (theme_supplier_.get())
+    theme_supplier_->StopUsingTheme();
+  theme_supplier_ = theme_supplier;
+  if (theme_supplier_.get())
+    theme_supplier_->StartUsingTheme();
+}
+
 void ThemeService::SavePackName(const base::FilePath& pack_path) {
   profile_->GetPrefs()->SetFilePath(
       prefs::kCurrentThemePackFilename, pack_path);
@@ -493,7 +596,7 @@
   number_of_infobars_--;
 
   if (number_of_infobars_ == 0)
-    RemoveUnusedThemes();
+    RemoveUnusedThemes(false);
 }
 
 ThemeSyncableService* ThemeService::GetThemeSyncableService() const {
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h
index 117844f..22abfde 100644
--- a/chrome/browser/themes/theme_service.h
+++ b/chrome/browser/themes/theme_service.h
@@ -135,8 +135,10 @@
   // destroyed, uninstalls all themes that aren't the currently selected.
   void OnInfobarDestroyed();
 
-  // Remove preference values for themes that are no longer in use.
-  void RemoveUnusedThemes();
+  // Uninstall theme extensions which are no longer in use. |ignore_infobars| is
+  // whether unused themes should be removed despite a theme infobar being
+  // visible.
+  void RemoveUnusedThemes(bool ignore_infobars);
 
   // Returns the syncable service for syncing theme. The returned service is
   // owned by |this| object.
@@ -190,14 +192,17 @@
  private:
   friend class theme_service_internal::ThemeServiceTest;
 
-  // Replaces the current theme supplier with a new one and calls
-  // StopUsingTheme() or StartUsingTheme() as appropriate.
-  void SwapThemeSupplier(scoped_refptr<CustomThemeSupplier> theme_supplier);
+  // Called when the extension service is ready.
+  void OnExtensionServiceReady();
 
   // Migrate the theme to the new theme pack schema by recreating the data pack
   // from the extension.
   void MigrateTheme();
 
+  // Replaces the current theme supplier with a new one and calls
+  // StopUsingTheme() or StartUsingTheme() as appropriate.
+  void SwapThemeSupplier(scoped_refptr<CustomThemeSupplier> theme_supplier);
+
   // Saves the filename of the cached theme pack.
   void SavePackName(const base::FilePath& pack_path);
 
@@ -244,6 +249,13 @@
 
   scoped_refptr<CustomThemeSupplier> theme_supplier_;
 
+  // The id of the theme extension which has just been installed but has not
+  // been loaded yet. The theme extension with |installed_pending_load_id_| may
+  // never be loaded if the install is due to updating a disabled theme.
+  // |pending_install_id_| should be set to |kDefaultThemeID| if there are no
+  // recently installed theme extensions
+  std::string installed_pending_load_id_;
+
   // The number of infobars currently displayed.
   int number_of_infobars_;
 
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc
index 6288935..4b03205 100644
--- a/chrome/browser/themes/theme_service_unittest.cc
+++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -4,18 +4,22 @@
 
 #include "chrome/browser/themes/theme_service.h"
 
-#include "base/json/json_reader.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service_unittest.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/managed_mode/managed_user_service.h"
 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
 #include "chrome/browser/themes/custom_theme_supplier.h"
 #include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace theme_service_internal {
@@ -28,25 +32,57 @@
   }
   virtual ~ThemeServiceTest() {}
 
-  scoped_refptr<extensions::Extension> MakeThemeExtension(base::FilePath path) {
-    DictionaryValue source;
-    source.SetString(extension_manifest_keys::kName, "theme");
-    source.Set(extension_manifest_keys::kTheme, new DictionaryValue());
-    source.SetString(extension_manifest_keys::kUpdateURL, "http://foo.com");
-    source.SetString(extension_manifest_keys::kVersion, "0.0.0.0");
-    std::string error;
-    scoped_refptr<extensions::Extension> extension =
-        extensions::Extension::Create(
-            path, extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
-            source, extensions::Extension::NO_FLAGS, &error);
-    EXPECT_TRUE(extension.get());
-    EXPECT_EQ("", error);
-    return extension;
+  // Moves a minimal theme to |temp_dir_path| and unpacks it from that
+  // directory.
+  std::string LoadUnpackedThemeAt(const base::FilePath& temp_dir) {
+    base::FilePath dst_manifest_path = temp_dir.AppendASCII("manifest.json");
+    base::FilePath test_data_dir;
+    EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+    base::FilePath src_manifest_path =
+        test_data_dir.AppendASCII("extensions/theme_minimal/manifest.json");
+    EXPECT_TRUE(base::CopyFile(src_manifest_path, dst_manifest_path));
+
+    scoped_refptr<extensions::UnpackedInstaller> installer(
+        extensions::UnpackedInstaller::Create(service_));
+    content::WindowedNotificationObserver observer(
+        chrome::NOTIFICATION_EXTENSION_LOADED,
+        content::Source<Profile>(profile_.get()));
+    installer->Load(temp_dir);
+    observer.Wait();
+
+    std::string extension_id =
+        content::Details<extensions::Extension>(observer.details())->id();
+
+    // Let the ThemeService finish creating the theme pack.
+    base::MessageLoop::current()->RunUntilIdle();
+
+    return extension_id;
+  }
+
+  // Update the theme with |extension_id|.
+  void UpdateUnpackedTheme(const std::string& extension_id) {
+    int updated_notification = service_->IsExtensionEnabled(extension_id) ?
+        chrome::NOTIFICATION_EXTENSION_LOADED :
+        chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED;
+
+    const base::FilePath& path =
+        service_->GetInstalledExtension(extension_id)->path();
+
+    scoped_refptr<extensions::UnpackedInstaller> installer(
+        extensions::UnpackedInstaller::Create(service_));
+    content::WindowedNotificationObserver observer(updated_notification,
+        content::Source<Profile>(profile_.get()));
+    installer->Load(path);
+    observer.Wait();
+
+    // Let the ThemeService finish creating the theme pack.
+    base::MessageLoop::current()->RunUntilIdle();
   }
 
   virtual void SetUp() {
     ExtensionServiceTestBase::SetUp();
     InitializeEmptyExtensionService();
+    service_->Init();
     bool success = manager_->SetUp();
     ASSERT_TRUE(success);
   }
@@ -66,50 +102,133 @@
 // Installs then uninstalls a theme and makes sure that the ThemeService
 // reverts to the default theme after the uninstall.
 TEST_F(ThemeServiceTest, ThemeInstallUninstall) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   ThemeService* theme_service =
       ThemeServiceFactory::GetForProfile(profile_.get());
   theme_service->UseDefaultTheme();
-  scoped_refptr<extensions::Extension> extension =
-      MakeThemeExtension(temp_dir.path());
-  service_->FinishInstallationForTest(extension.get());
-  // Let ThemeService finish creating the theme pack.
+  // Let the ThemeService uninstall unused themes.
   base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_FALSE(theme_service->UsingDefaultTheme());
-  EXPECT_EQ(extension->id(), theme_service->GetThemeID());
 
-  // Now unload the extension, should revert to the default theme.
-  service_->UnloadExtension(extension->id(),
-                            extension_misc::UNLOAD_REASON_UNINSTALL);
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const std::string& extension_id = LoadUnpackedThemeAt(temp_dir.path());
+  EXPECT_FALSE(theme_service->UsingDefaultTheme());
+  EXPECT_EQ(extension_id, theme_service->GetThemeID());
+
+  // Now uninstall the extension, should revert to the default theme.
+  service_->UninstallExtension(extension_id, false, NULL);
   EXPECT_TRUE(theme_service->UsingDefaultTheme());
 }
 
-// Upgrades a theme and ensures that the ThemeService does not revert to the
-// default theme.
-TEST_F(ThemeServiceTest, ThemeUpgrade) {
-  base::ScopedTempDir temp_dir;
-  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+// Test that a theme extension is disabled when not in use. A theme may be
+// installed but not in use if it there is an infobar to revert to the previous
+// theme.
+TEST_F(ThemeServiceTest, DisableUnusedTheme) {
   ThemeService* theme_service =
       ThemeServiceFactory::GetForProfile(profile_.get());
   theme_service->UseDefaultTheme();
-  scoped_refptr<extensions::Extension> extension =
-      MakeThemeExtension(temp_dir.path());
-  service_->FinishInstallationForTest(extension.get());
-  // Let ThemeService finish creating the theme pack.
+  // Let the ThemeService uninstall unused themes.
   base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_FALSE(theme_service->UsingDefaultTheme());
-  EXPECT_EQ(extension->id(), theme_service->GetThemeID());
 
-  // Now unload the extension, should revert to the default theme.
-  service_->UnloadExtension(extension->id(),
-                            extension_misc::UNLOAD_REASON_UPDATE);
+  base::ScopedTempDir temp_dir1;
+  ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
+  base::ScopedTempDir temp_dir2;
+  ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
+
+  // 1) Installing a theme should disable the previously active theme.
+  const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path());
   EXPECT_FALSE(theme_service->UsingDefaultTheme());
+  EXPECT_EQ(extension1_id, theme_service->GetThemeID());
+  EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id));
+
+  // Show an infobar to prevent the current theme from being uninstalled.
+  theme_service->OnInfobarDisplayed();
+
+  const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path());
+  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
+  EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id));
+  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
+      ExtensionService::INCLUDE_DISABLED));
+
+  // 2) Enabling a disabled theme extension should swap the current theme.
+  service_->EnableExtension(extension1_id);
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(extension1_id, theme_service->GetThemeID());
+  EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id));
+  EXPECT_TRUE(service_->GetExtensionById(extension2_id,
+      ExtensionService::INCLUDE_DISABLED));
+
+  // 3) Using SetTheme() with a disabled theme should enable and set the
+  // theme. This is the case when the user reverts to the previous theme
+  // via an infobar.
+  const extensions::Extension* extension2 =
+      service_->GetInstalledExtension(extension2_id);
+  theme_service->SetTheme(extension2);
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
+  EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id));
+  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
+      ExtensionService::INCLUDE_DISABLED));
+
+  // 4) Disabling the current theme extension should revert to the default theme
+  // and uninstall any installed theme extensions.
+  theme_service->OnInfobarDestroyed();
+  EXPECT_FALSE(theme_service->UsingDefaultTheme());
+  service_->DisableExtension(extension2_id,
+      extensions::Extension::DISABLE_USER_ACTION);
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(theme_service->UsingDefaultTheme());
+  EXPECT_FALSE(service_->GetInstalledExtension(extension1_id));
+  EXPECT_FALSE(service_->GetInstalledExtension(extension2_id));
+}
+
+// Test the ThemeService's behavior when a theme is upgraded.
+TEST_F(ThemeServiceTest, ThemeUpgrade) {
+  // Setup.
+  ThemeService* theme_service =
+      ThemeServiceFactory::GetForProfile(profile_.get());
+  theme_service->UseDefaultTheme();
+  // Let the ThemeService uninstall unused themes.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  theme_service->OnInfobarDisplayed();
+
+  base::ScopedTempDir temp_dir1;
+  ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
+  base::ScopedTempDir temp_dir2;
+  ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
+
+  const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path());
+  const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path());
+
+  // Test the initial state.
+  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
+      ExtensionService::INCLUDE_DISABLED));
+  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
+
+  // 1) Upgrading the current theme should not revert to the default theme.
+  content::WindowedNotificationObserver theme_change_observer(
+      chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+      content::Source<ThemeService>(theme_service));
+  UpdateUnpackedTheme(extension2_id);
+
+  // The ThemeService should have sent an theme change notification even though
+  // the id of the current theme did not change.
+  theme_change_observer.Wait();
+
+  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
+  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
+      ExtensionService::INCLUDE_DISABLED));
+
+  // 2) Upgrading a disabled theme should not change the current theme.
+  UpdateUnpackedTheme(extension1_id);
+  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
+  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
+      ExtensionService::INCLUDE_DISABLED));
 }
 
 // Checks that managed users have their own default theme.
 TEST_F(ThemeServiceTest, ManagedUserThemeReplacesDefaultTheme) {
-  profile_->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
+  ManagedUserServiceFactory::GetForProfile(profile_.get())->InitForTesting();
   ThemeService* theme_service =
       ThemeServiceFactory::GetForProfile(profile_.get());
   theme_service->UseDefaultTheme();
@@ -135,7 +254,7 @@
 // Checks that managed users don't use the system theme even if it is the
 // default. The system theme is only available on Linux.
 TEST_F(ThemeServiceTest, ManagedUserThemeReplacesNativeTheme) {
-  profile_->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
+  ManagedUserServiceFactory::GetForProfile(profile_.get())->InitForTesting();
   profile_->GetPrefs()->SetBoolean(prefs::kUsesSystemTheme, true);
   ThemeService* theme_service =
       ThemeServiceFactory::GetForProfile(profile_.get());
diff --git a/chrome/browser/themes/theme_syncable_service.cc b/chrome/browser/themes/theme_syncable_service.cc
index 3389443..55d3f74 100644
--- a/chrome/browser/themes/theme_syncable_service.cc
+++ b/chrome/browser/themes/theme_syncable_service.cc
@@ -208,7 +208,7 @@
     string id(theme_specifics.custom_theme_id());
     GURL update_url(theme_specifics.custom_theme_update_url());
     DVLOG(1) << "Applying theme " << id << " with update_url " << update_url;
-    ExtensionServiceInterface* extensions_service =
+    ExtensionService* extensions_service =
         extensions::ExtensionSystem::Get(profile_)->extension_service();
     CHECK(extensions_service);
     const extensions::Extension* extension =
@@ -218,8 +218,12 @@
         DVLOG(1) << "Extension " << id << " is not a theme; aborting";
         return;
       }
-      if (!extensions_service->IsExtensionEnabled(id)) {
-        DVLOG(1) << "Theme " << id << " is not enabled; aborting";
+      int disabled_reasons =
+          extensions_service->extension_prefs()->GetDisableReasons(id);
+      if (!extensions_service->IsExtensionEnabled(id) &&
+          disabled_reasons != extensions::Extension::DISABLE_USER_ACTION) {
+        DVLOG(1) << "Theme " << id << " is disabled with reason "
+                 << disabled_reasons << "; aborting";
         return;
       }
       // An enabled theme extension with the given id was found, so
diff --git a/chrome/browser/themes/theme_syncable_service_unittest.cc b/chrome/browser/themes/theme_syncable_service_unittest.cc
index bf91861..e5f9eb0 100644
--- a/chrome/browser/themes/theme_syncable_service_unittest.cc
+++ b/chrome/browser/themes/theme_syncable_service_unittest.cc
@@ -15,13 +15,13 @@
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "chrome/common/extensions/permissions/api_permission_set.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 "sync/api/sync_error.h"
 #include "sync/api/sync_error_factory_mock.h"
 #include "sync/protocol/sync.pb.h"
@@ -144,10 +144,10 @@
     extensions::Manifest::Location location,
     const string& update_url) {
   DictionaryValue source;
-  source.SetString(extension_manifest_keys::kName, name);
-  source.Set(extension_manifest_keys::kTheme, new DictionaryValue());
-  source.SetString(extension_manifest_keys::kUpdateURL, update_url);
-  source.SetString(extension_manifest_keys::kVersion, "0.0.0.0");
+  source.SetString(extensions::manifest_keys::kName, name);
+  source.Set(extensions::manifest_keys::kTheme, new DictionaryValue());
+  source.SetString(extensions::manifest_keys::kUpdateURL, update_url);
+  source.SetString(extensions::manifest_keys::kVersion, "0.0.0.0");
   string error;
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
index 4910100..2e3d47a 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.cc
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
@@ -181,7 +181,7 @@
   load_interrupted_ = false;
 }
 
-void ThumbnailTabHelper::StopNavigation() {
+void ThumbnailTabHelper::NavigationStopped() {
   // This function gets called when the page loading is interrupted by the
   // stop button.
   load_interrupted_ = true;
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.h b/chrome/browser/thumbnails/thumbnail_tab_helper.h
index 3d1434f..5fa7b0a 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.h
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.h
@@ -43,7 +43,7 @@
       content::RenderViewHost* render_view_host) OVERRIDE;
   virtual void DidStartLoading(
       content::RenderViewHost* render_view_host) OVERRIDE;
-  virtual void StopNavigation() OVERRIDE;
+  virtual void NavigationStopped() OVERRIDE;
 
   // Update the thumbnail of the given tab contents if necessary.
   void UpdateThumbnailIfNecessary(content::WebContents* web_contents);
diff --git a/chrome/browser/translate/translate_browsertest.cc b/chrome/browser/translate/translate_browsertest.cc
index 35581cd..61b13e6 100644
--- a/chrome/browser/translate/translate_browsertest.cc
+++ b/chrome/browser/translate/translate_browsertest.cc
@@ -162,9 +162,7 @@
   element_js +=
     "google = { 'translate' : { 'TranslateService' : function() { return {\n"
     "  isAvailable: function() {\n"
-    "    var script = document.createElement('script');\n"
-    "    script.src = main_script_url;\n"
-    "    document.getElementsByTagName('head')[0].appendChild(script);\n"
+    "    cr.googleTranslate.onLoadJavascript(main_script_url);\n"
     "    return true;\n"
     "  },\n"
     "  translatePage: function(sl, tl, cb) {\n"
diff --git a/chrome/browser/translate/translate_language_list.cc b/chrome/browser/translate/translate_language_list.cc
index 5a58151..2184cf2 100644
--- a/chrome/browser/translate/translate_language_list.cc
+++ b/chrome/browser/translate/translate_language_list.cc
@@ -242,7 +242,7 @@
 
   // Update language lists if they are not updated after Chrome was launched
   // for later requests.
-  if (language_list_fetcher_.get())
+  if (!update_is_disabled && language_list_fetcher_.get())
     RequestLanguageList();
 }
 
diff --git a/chrome/browser/translate/translate_manager.cc b/chrome/browser/translate/translate_manager.cc
index a7df993..9188acf 100644
--- a/chrome/browser/translate/translate_manager.cc
+++ b/chrome/browser/translate/translate_manager.cc
@@ -53,7 +53,7 @@
 #include "net/http/http_status_code.h"
 
 #ifdef FILE_MANAGER_EXTENSION
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #include "extensions/common/constants.h"
 #endif
 
@@ -106,7 +106,7 @@
          !url.SchemeIs(chrome::kChromeDevToolsScheme) &&
 #ifdef FILE_MANAGER_EXTENSION
          !(url.SchemeIs(extensions::kExtensionScheme) &&
-           url.DomainIs(kFileBrowserDomain)) &&
+           url.DomainIs(file_manager::kFileManagerAppId)) &&
 #endif
          !url.SchemeIs(chrome::kFtpScheme);
 }
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc
index 4bfe4e0..f10bb02 100644
--- a/chrome/browser/translate/translate_manager_browsertest.cc
+++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -1146,12 +1146,12 @@
   // case either.
   TestingProfile* test_profile =
       static_cast<TestingProfile*>(web_contents()->GetBrowserContext());
-  test_profile->set_incognito(true);
+  test_profile->ForceIncognito(true);
   SimulateNavigation(GURL("http://www.youtube.fr"), "fr", true);
   EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
   EXPECT_TRUE(GetTranslateInfoBar() != NULL);
   EXPECT_TRUE(CloseTranslateInfoBar());
-  test_profile->set_incognito(false);  // Get back to non incognito.
+  test_profile->ForceIncognito(false);  // Get back to non incognito.
 
   // Now revert the always translate pref and make sure we go back to expected
   // behavior, which is show a "before translate" infobar.
@@ -1291,7 +1291,7 @@
   static_cast<extensions::TestExtensionSystem*>(
       extensions::ExtensionSystem::Get(test_profile))->
       CreateExtensionProcessManager();
-  test_profile->set_incognito(true);
+  test_profile->ForceIncognito(true);
   for (int i = 0; i < 8; ++i) {
     SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
         " incognito mode=" << test_profile->IsOffTheRecord());
@@ -1308,7 +1308,7 @@
       EXPECT_TRUE(infobar->ShouldShowAlwaysTranslateShortcut());
     }
     if (i == 3)
-      test_profile->set_incognito(false);
+      test_profile->ForceIncognito(false);
   }
   // Simulate the user pressing "Always translate French".
   infobar->AlwaysTranslatePageLanguage();
@@ -1324,7 +1324,7 @@
 
   // Now test that declining the translation causes a "never translate" button
   // to be shown (in non incognito mode only).
-  test_profile->set_incognito(true);
+  test_profile->ForceIncognito(true);
   for (int i = 0; i < 8; ++i) {
     SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
         " incognito mode=" << test_profile->IsOffTheRecord());
@@ -1340,7 +1340,7 @@
       EXPECT_TRUE(infobar->ShouldShowNeverTranslateShortcut());
     }
     if (i == 3)
-      test_profile->set_incognito(false);
+      test_profile->ForceIncognito(false);
   }
   // Simulate the user pressing "Never translate French".
   infobar->NeverTranslatePageLanguage();
diff --git a/chrome/browser/translate/translate_manager_unittest.cc b/chrome/browser/translate/translate_manager_unittest.cc
index 9073b3a..f297710 100644
--- a/chrome/browser/translate/translate_manager_unittest.cc
+++ b/chrome/browser/translate/translate_manager_unittest.cc
@@ -9,7 +9,7 @@
 #include "url/gurl.h"
 
 #ifdef FILE_MANAGER_EXTENSION
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #include "extensions/common/constants.h"
 #endif
 
@@ -31,7 +31,7 @@
   std::string filemanager =
       std::string(extensions::kExtensionScheme) +
       std::string("://") +
-      std::string(kFileBrowserDomain);
+      std::string(file_manager::kFileManagerAppId);
   GURL filemanager_url = GURL(filemanager);
   EXPECT_FALSE(TranslateManager::IsTranslatableURL(filemanager_url));
 #endif
diff --git a/chrome/browser/translate/translate_prefs.cc b/chrome/browser/translate/translate_prefs.cc
index 303fb21..25541c7 100644
--- a/chrome/browser/translate/translate_prefs.cc
+++ b/chrome/browser/translate/translate_prefs.cc
@@ -8,6 +8,7 @@
 #include "base/prefs/pref_service.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"
@@ -420,10 +421,21 @@
     result.insert(*it);
   }
 
+  const std::string& app_locale = g_browser_process->GetApplicationLocale();
+  std::string ui_lang = TranslateManager::GetLanguageCode(app_locale);
+  bool is_ui_english = ui_lang == "en" ||
+      StartsWithASCII(ui_lang, "en-", false);
+
   for (std::vector<std::string>::const_iterator it = accept_languages.begin();
        it != accept_languages.end(); ++it) {
     std::string lang = *it;
     TranslateUtil::ToTranslateLanguageSynonym(&lang);
+
+    // Regarding http://crbug.com/36182, even though English exists in Accept
+    // language list, English could be translated on non-English locale.
+    if (lang == "en" && !is_ui_english)
+      continue;
+
     result.insert(lang);
   }
 
diff --git a/chrome/browser/translate/translate_prefs.h b/chrome/browser/translate/translate_prefs.h
index 2d77124..f78aa28 100644
--- a/chrome/browser/translate/translate_prefs.h
+++ b/chrome/browser/translate/translate_prefs.h
@@ -89,6 +89,8 @@
  private:
   friend class TranslatePrefsTest;
   FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest, CreateBlockedLanguages);
+  FRIEND_TEST_ALL_PREFIXES(TranslatePrefsTest,
+                           CreateBlockedLanguagesNonEnglishUI);
 
   // Merges two language sets to migrate to the language setting UI.
   static void CreateBlockedLanguages(
@@ -115,6 +117,8 @@
   base::DictionaryValue* GetTranslationAcceptedCountDictionary() const;
 
   PrefService* prefs_;  // Weak.
+
+  DISALLOW_COPY_AND_ASSIGN(TranslatePrefs);
 };
 
 #endif  // CHROME_BROWSER_TRANSLATE_TRANSLATE_PREFS_H_
diff --git a/chrome/browser/translate/translate_prefs_unittest.cc b/chrome/browser/translate/translate_prefs_unittest.cc
index a09aa61..7c3cf11 100644
--- a/chrome/browser/translate/translate_prefs_unittest.cc
+++ b/chrome/browser/translate/translate_prefs_unittest.cc
@@ -8,15 +8,10 @@
 #include <string>
 #include <vector>
 
+#include "chrome/test/base/scoped_browser_locale.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-class TranslatePrefsTest : public testing::Test {
- public:
-  TranslatePrefsTest() {}
-  virtual ~TranslatePrefsTest() {}
-};
-
-TEST_F(TranslatePrefsTest, CreateBlockedLanguages) {
+TEST(TranslatePrefsTest, CreateBlockedLanguages) {
   std::vector<std::string> blacklisted_languages;
   blacklisted_languages.push_back("en");
   blacklisted_languages.push_back("fr");
@@ -59,3 +54,60 @@
                         *it));
   }
 }
+
+TEST(TranslatePrefsTest, CreateBlockedLanguagesNonEnglishUI) {
+  std::vector<std::string> blacklisted_languages;
+  blacklisted_languages.push_back("fr");
+
+  std::vector<std::string> accept_languages;
+  accept_languages.push_back("en");
+  accept_languages.push_back("ja");
+  accept_languages.push_back("zh");
+
+  // Run in an English locale.
+  {
+    ScopedBrowserLocale scoped_browser_locale("en");
+    std::vector<std::string> blocked_languages;
+    TranslatePrefs::CreateBlockedLanguages(&blocked_languages,
+                                           blacklisted_languages,
+                                           accept_languages);
+    std::vector<std::string> expected;
+    expected.push_back("en");
+    expected.push_back("fr");
+    expected.push_back("ja");
+    expected.push_back("zh");
+
+    EXPECT_EQ(expected.size(), blocked_languages.size());
+    for (std::vector<std::string>::const_iterator it = expected.begin();
+         it != expected.end(); ++it) {
+      EXPECT_NE(blocked_languages.end(),
+                std::find(blocked_languages.begin(),
+                          blocked_languages.end(),
+                          *it));
+    }
+  }
+
+  // Run in a Japanese locale.
+  // English should not be included in the result even though Accept Languages
+  // has English because the UI is not English.
+  {
+    ScopedBrowserLocale scoped_browser_locale("ja");
+    std::vector<std::string> blocked_languages;
+    TranslatePrefs::CreateBlockedLanguages(&blocked_languages,
+                                           blacklisted_languages,
+                                           accept_languages);
+    std::vector<std::string> expected;
+    expected.push_back("fr");
+    expected.push_back("ja");
+    expected.push_back("zh");
+
+    EXPECT_EQ(expected.size(), blocked_languages.size());
+    for (std::vector<std::string>::const_iterator it = expected.begin();
+         it != expected.end(); ++it) {
+      EXPECT_NE(blocked_languages.end(),
+                std::find(blocked_languages.begin(),
+                          blocked_languages.end(),
+                          *it));
+    }
+  }
+}
diff --git a/chrome/browser/translate/translate_script.cc b/chrome/browser/translate/translate_script.cc
index 48184aa..2f1d681 100644
--- a/chrome/browser/translate/translate_script.cc
+++ b/chrome/browser/translate/translate_script.cc
@@ -8,10 +8,13 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "chrome/browser/translate/translate_url_fetcher.h"
 #include "chrome/browser/translate/translate_url_util.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/translate/translate_util.h"
 #include "google_apis/google_api_keys.h"
 #include "grit/browser_resources.h"
 #include "net/base/escape.h"
@@ -22,17 +25,24 @@
 
 const int kExpirationDelayDays = 1;
 
-const char kScriptURL[] =
-    "https://translate.google.com/translate_a/element.js";
-const char kRequestHeader[] = "Google-Translate-Element-Mode: library";
-
-// Used in kTranslateScriptURL to specify a callback function name.
-const char kCallbackQueryName[] = "cb";
-const char kCallbackQueryValue[] =
-    "cr.googleTranslate.onTranslateElementLoad";
-
 }  // namespace
 
+const char TranslateScript::kScriptURL[] =
+    "https://translate.google.com/translate_a/element.js";
+const char TranslateScript::kRequestHeader[] =
+    "Google-Translate-Element-Mode: library";
+const char TranslateScript::kAlwaysUseSslQueryName[] = "aus";
+const char TranslateScript::kAlwaysUseSslQueryValue[] = "true";
+const char TranslateScript::kCallbackQueryName[] = "cb";
+const char TranslateScript::kCallbackQueryValue[] =
+    "cr.googleTranslate.onTranslateElementLoad";
+const char TranslateScript::kCssLoaderCallbackQueryName[] = "clc";
+const char TranslateScript::kCssLoaderCallbackQueryValue[] =
+    "cr.googleTranslate.onLoadCSS";
+const char TranslateScript::kJavascriptLoaderCallbackQueryName[] = "jlc";
+const char TranslateScript::kJavascriptLoaderCallbackQueryValue[] =
+    "cr.googleTranslate.onLoadJavascript";
+
 TranslateScript::TranslateScript()
     : weak_method_factory_(this),
       expiration_delay_(base::TimeDelta::FromDays(kExpirationDelayDays)) {
@@ -74,6 +84,18 @@
       translate_script_url,
       kCallbackQueryName,
       kCallbackQueryValue);
+  translate_script_url = net::AppendQueryParameter(
+      translate_script_url,
+      kAlwaysUseSslQueryName,
+      kAlwaysUseSslQueryValue);
+  translate_script_url = net::AppendQueryParameter(
+      translate_script_url,
+      kCssLoaderCallbackQueryName,
+      kCssLoaderCallbackQueryValue);
+  translate_script_url = net::AppendQueryParameter(
+      translate_script_url,
+      kJavascriptLoaderCallbackQueryName,
+      kJavascriptLoaderCallbackQueryValue);
 
   translate_script_url =
       TranslateURLUtil::AddHostLocaleToUrl(translate_script_url);
@@ -96,15 +118,20 @@
   scoped_ptr<const TranslateURLFetcher> delete_ptr(fetcher_.release());
 
   if (success) {
+    DCHECK(data_.empty());
+    // Insert variable definitions on API Key and security origin.
+    data_ = base::StringPrintf("var translateApiKey = '%s';\n",
+                               google_apis::GetAPIKey().c_str());
+
+    GURL security_origin = TranslateUtil::GetTranslateSecurityOrigin();
+    base::StringAppendF(
+        &data_, "var securityOrigin = '%s';", security_origin.spec().c_str());
+
+    // Append embedded translate.js and a remote element library.
     base::StringPiece str = ResourceBundle::GetSharedInstance().
         GetRawDataResource(IDR_TRANSLATE_JS);
-    DCHECK(data_.empty());
-    str.CopyToString(&data_);
-    std::string argument = "('";
-    std::string api_key = google_apis::GetAPIKey();
-    argument += net::EscapeQueryParamValue(api_key, true);
-    argument += "');\n";
-    data_ += argument + data;
+    str.AppendToString(&data_);
+    data_ += data;
 
     // We'll expire the cached script after some time, to make sure long
     // running browsers still get fixes that might get pushed with newer
diff --git a/chrome/browser/translate/translate_script.h b/chrome/browser/translate/translate_script.h
index e303243..ebc07d5 100644
--- a/chrome/browser/translate/translate_script.h
+++ b/chrome/browser/translate/translate_script.h
@@ -8,10 +8,12 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 
+class TranslateScriptTest;
 class TranslateURLFetcher;
 
 class TranslateScript {
@@ -44,6 +46,30 @@
   bool HasPendingRequest() const { return fetcher_.get() != NULL; }
 
  private:
+  friend class TranslateScriptTest;
+  FRIEND_TEST_ALL_PREFIXES(TranslateScriptTest, CheckScriptParameters);
+  FRIEND_TEST_ALL_PREFIXES(TranslateScriptTest, CheckScriptURL);
+
+  static const char kScriptURL[];
+  static const char kRequestHeader[];
+
+  // Used in kTranslateScriptURL to specify using always ssl to load resources.
+  static const char kAlwaysUseSslQueryName[];
+  static const char kAlwaysUseSslQueryValue[];
+
+  // Used in kTranslateScriptURL to specify a callback function name.
+  static const char kCallbackQueryName[];
+  static const char kCallbackQueryValue[];
+
+  // Used in kTranslateScriptURL to specify a CSS loader callback function name.
+  static const char kCssLoaderCallbackQueryName[];
+  static const char kCssLoaderCallbackQueryValue[];
+
+  // Used in kTranslateScriptURL to specify a JavaScript loader callback
+  // function name.
+  static const char kJavascriptLoaderCallbackQueryName[];
+  static const char kJavascriptLoaderCallbackQueryValue[];
+
   // The callback when the script is fetched or a server error occured.
   void OnScriptFetchComplete(int id, bool success, const std::string& data);
 
diff --git a/chrome/browser/translate/translate_script_unittest.cc b/chrome/browser/translate/translate_script_unittest.cc
new file mode 100644
index 0000000..991f9de
--- /dev/null
+++ b/chrome/browser/translate/translate_script_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright 2013 The Chromium Authors. 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/translate/translate_script.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/chrome_switches.h"
+#include "net/base/load_flags.h"
+#include "net/base/url_util.h"
+#include "net/http/http_request_headers.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+class TranslateScriptTest : public testing::Test {
+ public:
+  TranslateScriptTest() : testing::Test() {}
+
+ protected:
+  virtual void SetUp() {
+    script_.reset(new TranslateScript);
+    DCHECK(script_.get());
+  }
+
+  virtual void TearDown() {
+    script_.reset();
+  }
+
+  void Request() {
+    script_->Request(
+        base::Bind(&TranslateScriptTest::OnComplete, base::Unretained(this)));
+  }
+
+  net::TestURLFetcher* GetTestURLFetcher() {
+    return url_fetcher_factory_.GetFetcherByID(TranslateScript::kFetcherId);
+  }
+
+ private:
+  void OnComplete(bool success, const std::string& script) {
+  }
+
+  scoped_ptr<TranslateScript> script_;
+  net::TestURLFetcherFactory url_fetcher_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TranslateScriptTest);
+};
+
+TEST_F(TranslateScriptTest, CheckScriptParameters) {
+  Request();
+  net::TestURLFetcher* fetcher = GetTestURLFetcher();
+  ASSERT_TRUE(fetcher);
+
+  GURL expected_url(TranslateScript::kScriptURL);
+  GURL url = fetcher->GetOriginalURL();
+  EXPECT_TRUE(url.is_valid());
+  EXPECT_EQ(expected_url.GetOrigin().spec(), url.GetOrigin().spec());
+  EXPECT_EQ(expected_url.path(), url.path());
+
+  int load_flags = fetcher->GetLoadFlags();
+  EXPECT_EQ(net::LOAD_DO_NOT_SEND_COOKIES,
+            load_flags & net::LOAD_DO_NOT_SEND_COOKIES);
+  EXPECT_EQ(net::LOAD_DO_NOT_SAVE_COOKIES,
+            load_flags & net::LOAD_DO_NOT_SAVE_COOKIES);
+
+  std::string expected_extra_headers =
+      base::StringPrintf("%s\r\n\r\n", TranslateScript::kRequestHeader);
+  net::HttpRequestHeaders extra_headers;
+  fetcher->GetExtraRequestHeaders(&extra_headers);
+  EXPECT_EQ(expected_extra_headers, extra_headers.ToString());
+
+  std::string always_use_ssl;
+  net::GetValueForKeyInQuery(
+      url, TranslateScript::kAlwaysUseSslQueryName, &always_use_ssl);
+  EXPECT_EQ(std::string(TranslateScript::kAlwaysUseSslQueryValue),
+            always_use_ssl);
+
+  std::string callback;
+  net::GetValueForKeyInQuery(
+      url, TranslateScript::kCallbackQueryName, &callback);
+  EXPECT_EQ(std::string(TranslateScript::kCallbackQueryValue), callback);
+
+  std::string css_loader_callback;
+  net::GetValueForKeyInQuery(
+      url, TranslateScript::kCssLoaderCallbackQueryName, &css_loader_callback);
+  EXPECT_EQ(std::string(TranslateScript::kCssLoaderCallbackQueryValue),
+            css_loader_callback);
+
+  std::string javascript_loader_callback;
+  net::GetValueForKeyInQuery(
+      url,
+      TranslateScript::kJavascriptLoaderCallbackQueryName,
+      &javascript_loader_callback);
+  EXPECT_EQ(std::string(TranslateScript::kJavascriptLoaderCallbackQueryValue),
+            javascript_loader_callback);
+}
+
+TEST_F(TranslateScriptTest, CheckScriptURL) {
+  const std::string script_url("http://www.tamurayukari.com/mero-n.js");
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendSwitchASCII(switches::kTranslateScriptURL,
+                                  script_url);
+
+  Request();
+  net::TestURLFetcher* fetcher = GetTestURLFetcher();
+  ASSERT_TRUE(fetcher);
+
+  GURL expected_url(script_url);
+  GURL url = fetcher->GetOriginalURL();
+  EXPECT_TRUE(url.is_valid());
+  EXPECT_EQ(expected_url.GetOrigin().spec(), url.GetOrigin().spec());
+  EXPECT_EQ(expected_url.path(), url.path());
+}
diff --git a/chrome/browser/ui/android/certificate_viewer_android.cc b/chrome/browser/ui/android/certificate_viewer_android.cc
index 41b3831..7a76139e5 100644
--- a/chrome/browser/ui/android/certificate_viewer_android.cc
+++ b/chrome/browser/ui/android/certificate_viewer_android.cc
@@ -17,8 +17,8 @@
 void ShowCertificateViewer(content::WebContents* web_contents,
                            gfx::NativeWindow parent,
                            net::X509Certificate* cert) {
-  // TODO(yfriedman, bulach): Hook this up to Java ui code: crbug.com/114822
-  NOTIMPLEMENTED();
+  // For Android, showing the certificate is always handled in Java.
+  NOTREACHED();
 }
 
 static jstring GetCertIssuedToText(JNIEnv* env, jclass) {
diff --git a/chrome/browser/ui/android/extensions/extension_install_ui_android.cc b/chrome/browser/ui/android/extensions/extension_install_ui_android.cc
index c916cf0..25e6b4d 100644
--- a/chrome/browser/ui/android/extensions/extension_install_ui_android.cc
+++ b/chrome/browser/ui/android/extensions/extension_install_ui_android.cc
@@ -5,12 +5,10 @@
 #include "chrome/browser/ui/android/extensions/extension_install_ui_android.h"
 
 #include "base/logging.h"
-#include "chrome/browser/extensions/extension_install_prompt.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/web_contents.h"
 
 void ExtensionInstallUIAndroid::OnInstallSuccess(
-    const extensions::Extension* extension, SkBitmap* icon) {
+    const extensions::Extension* extension,
+    SkBitmap* icon) {
   NOTIMPLEMENTED();
 }
 
@@ -30,8 +28,8 @@
 }
 
 // static
-void ExtensionInstallUI::OpenAppInstalledUI(
-    Profile* profile, const std::string& app_id) {
+void ExtensionInstallUI::OpenAppInstalledUI(Profile* profile,
+                                            const std::string& app_id) {
   NOTIMPLEMENTED();
 }
 
diff --git a/chrome/browser/ui/android/extensions/extension_install_ui_android.h b/chrome/browser/ui/android/extensions/extension_install_ui_android.h
index 96d79dd..7fc5d1e 100644
--- a/chrome/browser/ui/android/extensions/extension_install_ui_android.h
+++ b/chrome/browser/ui/android/extensions/extension_install_ui_android.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_ANDROID_EXTENSIONS_EXTENSION_INSTALL_UI_ANDROID_H_
 #define CHROME_BROWSER_UI_ANDROID_EXTENSIONS_EXTENSION_INSTALL_UI_ANDROID_H_
 
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/extension_install_ui.h"
 
 class ExtensionInstallUIAndroid : public ExtensionInstallUI {
@@ -12,7 +14,7 @@
   ExtensionInstallUIAndroid();
   virtual ~ExtensionInstallUIAndroid();
 
-  // ExtensionInstallUI implementation:
+  // ExtensionInstallUI:
   virtual void OnInstallSuccess(const extensions::Extension* extension,
                                 SkBitmap* icon) OVERRIDE;
   virtual void OnInstallFailure(
diff --git a/chrome/browser/ui/android/website_settings_popup_android.cc b/chrome/browser/ui/android/website_settings_popup_android.cc
index 4ae86b3..4d196b3 100644
--- a/chrome/browser/ui/android/website_settings_popup_android.cc
+++ b/chrome/browser/ui/android/website_settings_popup_android.cc
@@ -36,7 +36,7 @@
   content::WebContents* contents =
       content::ContentViewCore::GetNativeContentViewCore(env, view)->
           GetWebContents();
-  int cert_id = contents->GetController().GetActiveEntry()->GetSSL().cert_id;
+  int cert_id = contents->GetController().GetVisibleEntry()->GetSSL().cert_id;
   scoped_refptr<net::X509Certificate> cert;
   bool ok = CertStore::GetInstance()->RetrieveCert(cert_id, &cert);
   CHECK(ok);
@@ -77,7 +77,10 @@
     jobject context,
     jobject java_content_view,
     WebContents* web_contents) {
-  if (web_contents->GetController().GetActiveEntry() == NULL)
+  // Important to use GetVisibleEntry to match what's showing in the omnibox.
+  content::NavigationEntry* nav_entry =
+      web_contents->GetController().GetVisibleEntry();
+  if (nav_entry == NULL)
     return;
 
   popup_jobject_.Reset(
@@ -89,8 +92,8 @@
       Profile::FromBrowserContext(web_contents->GetBrowserContext()),
       TabSpecificContentSettings::FromWebContents(web_contents),
       InfoBarService::FromWebContents(web_contents),
-      web_contents->GetURL(),
-      web_contents->GetController().GetActiveEntry()->GetSSL(),
+      nav_entry->GetURL(),
+      nav_entry->GetSSL(),
       content::CertStore::GetInstance()));
 }
 
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 23bff8d..abb59af 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
@@ -13,8 +13,6 @@
 
 void AppListControllerDelegate::ViewClosing() {}
 
-void AppListControllerDelegate::ViewActivationChanged(bool active) {}
-
 gfx::ImageSkia AppListControllerDelegate::GetWindowIcon() {
   return gfx::ImageSkia();
 }
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 150d7c0..b0859f4 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.h
@@ -32,9 +32,6 @@
   // Handle the view being closed.
   virtual void ViewClosing();
 
-  // Handle the view being activated or deactivated.
-  virtual void ViewActivationChanged(bool active);
-
   // Get app list window.
   virtual gfx::NativeWindow GetAppListWindow() = 0;
 
diff --git a/chrome/browser/ui/app_list/app_list_service.cc b/chrome/browser/ui/app_list/app_list_service.cc
index 5a5f933..2ad2888 100644
--- a/chrome/browser/ui/app_list/app_list_service.cc
+++ b/chrome/browser/ui/app_list/app_list_service.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/app_list/app_list_service.h"
 
+#include "base/bind.h"
+#include "base/callback.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_registry_simple.h"
@@ -15,13 +17,54 @@
 
 namespace {
 
-base::TimeDelta GetTimeFromOriginalProcessStart(
-    const CommandLine& command_line) {
-  std::string start_time_string =
-      command_line.GetSwitchValueASCII(switches::kOriginalProcessStartTime);
-  int64 remote_start_time;
-  base::StringToInt64(start_time_string, &remote_start_time);
-  return base::Time::Now() - base::Time::FromInternalValue(remote_start_time);
+enum StartupType {
+  COLD_START,
+  WARM_START,
+  WARM_START_FAST,
+};
+
+base::Time GetOriginalProcessStartTime(const CommandLine& command_line) {
+  if (command_line.HasSwitch(switches::kOriginalProcessStartTime)) {
+    std::string start_time_string =
+        command_line.GetSwitchValueASCII(switches::kOriginalProcessStartTime);
+    int64 remote_start_time;
+    base::StringToInt64(start_time_string, &remote_start_time);
+    return base::Time::FromInternalValue(remote_start_time);
+  }
+
+// base::CurrentProcessInfo::CreationTime() is only defined on some
+// platforms.
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
+  return base::CurrentProcessInfo::CreationTime();
+#endif
+  return base::Time();
+}
+
+StartupType GetStartupType(const CommandLine& command_line) {
+  // The presence of kOriginalProcessStartTime implies that another process
+  // has sent us its command line to handle, ie: we are already running.
+  if (command_line.HasSwitch(switches::kOriginalProcessStartTime)) {
+    return command_line.HasSwitch(switches::kFastStart) ?
+        WARM_START_FAST : WARM_START;
+  }
+  return COLD_START;
+}
+
+void RecordFirstPaintTiming(StartupType startup_type,
+                            const base::Time& start_time) {
+  base::TimeDelta elapsed = base::Time::Now() - start_time;
+  switch (startup_type) {
+    case COLD_START:
+      UMA_HISTOGRAM_LONG_TIMES("Startup.AppListFirstPaintColdStart", elapsed);
+      break;
+    case WARM_START:
+      UMA_HISTOGRAM_LONG_TIMES("Startup.AppListFirstPaintWarmStart", elapsed);
+      break;
+    case WARM_START_FAST:
+      UMA_HISTOGRAM_LONG_TIMES("Startup.AppListFirstPaintWarmStartFast",
+                               elapsed);
+      break;
+  }
 }
 
 }  // namespace
@@ -38,21 +81,24 @@
 
 // static
 void AppListService::RecordShowTimings(const CommandLine& command_line) {
-  // The presence of kOriginalProcessStartTime implies that another process
-  // has sent us its command line to handle, ie: we are already running.
-  if (command_line.HasSwitch(switches::kOriginalProcessStartTime)) {
-    base::TimeDelta elapsed = GetTimeFromOriginalProcessStart(command_line);
-    if (command_line.HasSwitch(switches::kFastStart))
-      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStartFast", elapsed);
-    else
+  base::Time start_time = GetOriginalProcessStartTime(command_line);
+  if (start_time.is_null())
+    return;
+
+  base::TimeDelta elapsed = base::Time::Now() - start_time;
+  StartupType startup = GetStartupType(command_line);
+  switch (startup) {
+    case COLD_START:
+      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListColdStart", elapsed);
+      break;
+    case WARM_START:
       UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStart", elapsed);
-  } else {
-    // base::CurrentProcessInfo::CreationTime() is only defined on some
-    // platforms.
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-    UMA_HISTOGRAM_LONG_TIMES(
-        "Startup.ShowAppListColdStart",
-        base::Time::Now() - base::CurrentProcessInfo::CreationTime());
-#endif
+      break;
+    case WARM_START_FAST:
+      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStartFast", elapsed);
+      break;
   }
+
+  AppListService::Get()->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 441fdc1..60144f0 100644
--- a/chrome/browser/ui/app_list/app_list_service.h
+++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -36,6 +37,10 @@
 
   static void RecordShowTimings(const CommandLine& command_line);
 
+  // Indicates that |callback| should be called next time the app list is
+  // painted.
+  virtual void SetAppListNextPaintCallback(const base::Closure& callback) = 0;
+
   // Perform Chrome first run logic. This is executed before Chrome's threads
   // have been created.
   virtual void HandleFirstRun() = 0;
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 b3c879d..23671d2 100644
--- a/chrome/browser/ui/app_list/app_list_service_disabled.cc
+++ b/chrome/browser/ui/app_list/app_list_service_disabled.cc
@@ -21,6 +21,8 @@
   AppListServiceDisabled() {}
 
   // AppListService overrides:
+  virtual void SetAppListNextPaintCallback(
+      const base::Closure& callback) OVERRIDE {}
   virtual void HandleFirstRun() OVERRIDE {}
   virtual void Init(Profile* initial_profile) OVERRIDE {}
 
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 102809c..8b8b90b 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_service_impl.cc
@@ -10,14 +10,11 @@
 #include "base/prefs/pref_service.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
 
 namespace {
 
@@ -120,6 +117,9 @@
 
 AppListServiceImpl::~AppListServiceImpl() {}
 
+void AppListServiceImpl::SetAppListNextPaintCallback(
+    const base::Closure& callback) {}
+
 void AppListServiceImpl::HandleFirstRun() {}
 
 void AppListServiceImpl::Init(Profile* initial_profile) {}
@@ -158,7 +158,6 @@
 }
 
 void AppListServiceImpl::CreateShortcut() {}
-void AppListServiceImpl::OnSigninStatusChanged() {}
 
 // We need to watch for profile removal to keep kAppListProfile updated.
 void AppListServiceImpl::OnProfileWillBeRemoved(
@@ -174,13 +173,6 @@
   }
 }
 
-void AppListServiceImpl::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  OnSigninStatusChanged();
-}
-
 void AppListServiceImpl::Show() {
   profile_loader_.LoadProfileInvalidatingOtherLoads(
       GetProfilePath(g_browser_process->profile_manager()->user_data_dir()),
@@ -202,17 +194,7 @@
 }
 
 void AppListServiceImpl::SetProfile(Profile* new_profile) {
-  registrar_.RemoveAll();
   profile_ = new_profile;
-  if (!profile_)
-    return;
-
-  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
-                 content::Source<Profile>(profile_));
-  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
-                 content::Source<Profile>(profile_));
-  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
-                 content::Source<Profile>(profile_));
 }
 
 void AppListServiceImpl::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 5f7d70f..86ed93d 100644
--- a/chrome/browser/ui/app_list/app_list_service_impl.h
+++ b/chrome/browser/ui/app_list/app_list_service_impl.h
@@ -15,22 +15,14 @@
 #include "chrome/browser/profiles/profile_info_cache_observer.h"
 #include "chrome/browser/profiles/profile_loader.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 
 namespace base {
 class FilePath;
 }
 
-namespace content {
-class NotificationSource;
-class NotificationDetails;
-}
-
 // Parts of the AppListService implementation shared between platforms.
 class AppListServiceImpl : public AppListService,
-                           public ProfileInfoCacheObserver,
-                           public content::NotificationObserver {
+                           public ProfileInfoCacheObserver {
  public:
   static void RecordAppListLaunch();
   static void RecordAppListAppLaunch();
@@ -53,10 +45,9 @@
   // Create a platform-specific shortcut for the app list.
   virtual void CreateShortcut();
 
-  // Called in response to observed successful and unsuccessful signin changes.
-  virtual void OnSigninStatusChanged();
-
   // AppListService overrides:
+  virtual void SetAppListNextPaintCallback(
+      const base::Closure& callback) OVERRIDE;
   virtual void HandleFirstRun() OVERRIDE;
   virtual void Init(Profile* initial_profile) OVERRIDE;
 
@@ -83,11 +74,6 @@
   virtual void OnProfileWillBeRemoved(
       const base::FilePath& profile_path) OVERRIDE;
 
-  // content::NotificationObserver
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
   // The profile the AppList is currently displaying.
   Profile* profile_;
 
@@ -98,7 +84,6 @@
   int pending_profile_loads_;
 
   base::WeakPtrFactory<AppListServiceImpl> weak_factory_;
-  content::NotificationRegistrar registrar_;
 
   ProfileLoader profile_loader_;
 
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 bc34424..592f71d 100644
--- a/chrome/browser/ui/app_list/app_list_service_mac.mm
+++ b/chrome/browser/ui/app_list/app_list_service_mac.mm
@@ -8,6 +8,7 @@
 #include "apps/app_launcher.h"
 #include "apps/app_shim/app_shim_handler_mac.h"
 #include "apps/app_shim/app_shim_mac.h"
+#include "apps/pref_names.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
@@ -15,7 +16,6 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_loop.h"
-#include "base/observer_list.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -24,6 +24,7 @@
 #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_view_delegate.h"
+#include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/web_applications/web_app_ui.h"
 #include "chrome/browser/web_applications/web_app.h"
@@ -47,6 +48,9 @@
 
 namespace {
 
+// Version of the app list shortcut version installed.
+const int kShortcutVersion = 1;
+
 // AppListServiceMac manages global resources needed for the app list to
 // operate, and controls when the app list is opened and closed.
 class AppListServiceMac : public AppListServiceImpl,
@@ -71,7 +75,6 @@
 
   // AppListServiceImpl overrides:
   virtual void CreateShortcut() OVERRIDE;
-  virtual void OnSigninStatusChanged() OVERRIDE;
 
   // AppShimHandler overrides:
   virtual void OnShimLaunch(apps::AppShimHandler::Host* host,
@@ -91,11 +94,6 @@
   base::scoped_nsobject<AppListWindowController> window_controller_;
   base::scoped_nsobject<NSRunningApplication> previously_active_application_;
 
-  // App shim hosts observing when the app list is dismissed. In normal user
-  // usage there should only be one. However, it can't be guaranteed, so use
-  // an ObserverList rather than handling corner cases.
-  ObserverList<apps::AppShimHandler::Host> observers_;
-
   DISALLOW_COPY_AND_ASSIGN(AppListServiceMac);
 };
 
@@ -110,6 +108,7 @@
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
   virtual bool CanPin() OVERRIDE;
   virtual bool CanDoCreateShortcutsFlow(bool is_platform_app) OVERRIDE;
+  virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE;
   virtual void DoCreateShortcutsFlow(Profile* profile,
                                      const std::string& extension_id) OVERRIDE;
   virtual void ActivateApp(Profile* profile,
@@ -172,10 +171,24 @@
         *resource_bundle.GetImageSkiaNamed(IDR_APP_LIST_256));
   }
 
-  // TODO(tapted): Create a dock icon using chrome/browser/mac/dock.h .
+  ShellIntegration::ShortcutLocations shortcut_locations;
+  PrefService* local_state = g_browser_process->local_state();
+  int installed_version =
+      local_state->GetInteger(apps::prefs::kAppLauncherShortcutVersion);
+
+  // If this is a first-time install, add a dock icon. Otherwise just update
+  // the target, and wait for OSX to refresh its icon caches. This might not
+  // occur until a reboot, but OSX does not offer a nicer way. Deleting cache
+  // files on disk and killing processes can easily result in icon corruption.
+  if (installed_version == 0)
+    shortcut_locations.in_quick_launch_bar = true;
+
   web_app::CreateShortcuts(shortcut_info,
-                           ShellIntegration::ShortcutLocations(),
+                           shortcut_locations,
                            web_app::SHORTCUT_CREATION_AUTOMATED);
+
+  local_state->SetInteger(apps::prefs::kAppLauncherShortcutVersion,
+                          kShortcutVersion);
 }
 
 // Check that there is an app list shim. If enabling and there is not, make one.
@@ -257,6 +270,13 @@
       *extension, profile, base::Bind(&CreateShortcutsInDefaultLocation));
 }
 
+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, int event_flags) {
   LaunchApp(profile, extension, event_flags);
@@ -277,12 +297,21 @@
   if (initial_profile && !init_called_with_profile) {
     init_called_with_profile = true;
     HandleCommandLineFlags(initial_profile);
+    PrefService* local_state = g_browser_process->local_state();
     if (!apps::IsAppLauncherEnabled()) {
+      local_state->SetInteger(apps::prefs::kAppLauncherShortcutVersion, 0);
+
       // Not yet enabled via the Web Store. Check for the chrome://flag.
       content::BrowserThread::PostTask(
           content::BrowserThread::FILE, FROM_HERE,
           base::Bind(&CheckAppListShimOnFileThread,
                      initial_profile->GetPath()));
+    } else {
+      int installed_shortcut_version =
+          local_state->GetInteger(apps::prefs::kAppLauncherShortcutVersion);
+
+      if (kShortcutVersion > installed_shortcut_version)
+        CreateShortcut();
     }
   }
 
@@ -312,6 +341,9 @@
 }
 
 void AppListServiceMac::ShowForProfile(Profile* requested_profile) {
+  if (requested_profile->IsManaged())
+    return;
+
   InvalidatePendingProfileLoads();
 
   if (IsAppListVisible() && (requested_profile == profile())) {
@@ -347,10 +379,6 @@
     return;
 
   [[window_controller_ window] close];
-
-  FOR_EACH_OBSERVER(apps::AppShimHandler::Host,
-                    observers_,
-                    OnAppClosed());
 }
 
 bool AppListServiceMac::IsAppListVisible() const {
@@ -366,33 +394,26 @@
   return [window_controller_ window];
 }
 
-void AppListServiceMac::OnSigninStatusChanged() {
-  [[window_controller_ appListViewController] onSigninStatusChanged];
-}
-
 void AppListServiceMac::OnShimLaunch(apps::AppShimHandler::Host* host,
                                      apps::AppShimLaunchType launch_type) {
-  Show();
-  observers_.AddObserver(host);
-  host->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_SUCCESS);
+  if (IsAppListVisible())
+    DismissAppList();
+  else
+    Show();
+
+  // Always close the shim process immediately.
+  host->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_DUPLICATE_HOST);
 }
 
-void AppListServiceMac::OnShimClose(apps::AppShimHandler::Host* host) {
-  observers_.RemoveObserver(host);
-  DismissAppList();
-}
+void AppListServiceMac::OnShimClose(apps::AppShimHandler::Host* host) {}
 
 void AppListServiceMac::OnShimFocus(apps::AppShimHandler::Host* host,
-                                    apps::AppShimFocusType focus_type) {
-  DismissAppList();
-}
+                                    apps::AppShimFocusType focus_type) {}
 
 void AppListServiceMac::OnShimSetHidden(apps::AppShimHandler::Host* host,
                                         bool hidden) {}
 
-void AppListServiceMac::OnShimQuit(apps::AppShimHandler::Host* host) {
-  DismissAppList();
-}
+void AppListServiceMac::OnShimQuit(apps::AppShimHandler::Host* host) {}
 
 enum DockLocation {
   DockLocationOtherDisplay,
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 15a5ae9..a5089b1 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
@@ -18,38 +18,24 @@
 class AppListServiceMacBrowserTest : public InProcessBrowserTest,
                                      public AppShimHandler::Host {
  public:
-  AppListServiceMacBrowserTest() : launch_count_(0),
-                                   close_count_(0),
-                                   running_(false) {}
+  AppListServiceMacBrowserTest() : launch_count_(0) {}
 
  protected:
   void LaunchShim() {
-    DCHECK(!running_);
-    // AppList shims should always succced showing the app list.
+    // AppList shims always launch normally (never relaunched via dock icon).
     AppShimHandler::GetForAppMode(app_mode::kAppListModeId)->
         OnShimLaunch(this, apps::APP_SHIM_LAUNCH_NORMAL);
-    running_ = true;
-  }
-
-  void FocusShim() {
-    DCHECK(running_);
-    AppShimHandler::GetForAppMode(app_mode::kAppListModeId)->
-        OnShimFocus(this, apps::APP_SHIM_FOCUS_REOPEN);
-  }
-
-  void QuitShim() {
-    DCHECK(running_);
-    running_ = false;
-    AppShimHandler::GetForAppMode(app_mode::kAppListModeId)->OnShimClose(this);
   }
 
   // AppShimHandler::Host overrides:
-  virtual void OnAppLaunchComplete(apps::AppShimLaunchResult) OVERRIDE {
+  virtual void OnAppLaunchComplete(apps::AppShimLaunchResult result) OVERRIDE {
+    // AppList shims are always given APP_SHIM_LAUNCH_DUPLICATE_HOST, indicating
+    // that the shim process should immediately close.
+    EXPECT_EQ(apps::APP_SHIM_LAUNCH_DUPLICATE_HOST, result);
     ++launch_count_;
   }
   virtual void OnAppClosed() OVERRIDE {
-    ++close_count_;
-    QuitShim();
+    NOTREACHED();
   }
   virtual base::FilePath GetProfilePath() const OVERRIDE {
     NOTREACHED();  // Currently unused in this test.
@@ -60,8 +46,6 @@
   }
 
   int launch_count_;
-  int close_count_;
-  bool running_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AppListServiceMacBrowserTest);
@@ -75,38 +59,25 @@
 
   AppListService* service = AppListService::Get();
   EXPECT_FALSE(service->IsAppListVisible());
-  EXPECT_EQ(0, close_count_);
 
   // With no saved profile, the default profile should be chosen and saved.
   service->Show();
   EXPECT_EQ(browser()->profile(), service->GetCurrentAppListProfile());
   EXPECT_TRUE(service->IsAppListVisible());
   EXPECT_EQ(0, launch_count_);
-  EXPECT_EQ(0, close_count_);
   service->DismissAppList();
   EXPECT_FALSE(service->IsAppListVisible());
 
-  // There is no shim yet, so the close count should not change.
-  EXPECT_EQ(0, close_count_);
-
-  // Test showing the app list via the shim, then quit the shim directly. The
-  // close count does not change since the shim host is triggering the close,
-  // not the app list.
+  // Test showing the app list via the shim. The shim should immediately close
+  // leaving the app list visible.
   LaunchShim();
   EXPECT_TRUE(service->IsAppListVisible());
   EXPECT_EQ(1, launch_count_);
-  QuitShim();
-  EXPECT_FALSE(service->IsAppListVisible());
-  EXPECT_EQ(0, close_count_);
 
-  // Test showing the app list via the shim, then simulate clicking the dock
-  // icon again, which should close it.
+  // Launching again should toggle the app list.
   LaunchShim();
-  EXPECT_TRUE(service->IsAppListVisible());
-  EXPECT_EQ(2, launch_count_);
-  FocusShim();
   EXPECT_FALSE(service->IsAppListVisible());
-  EXPECT_EQ(1, close_count_);
+  EXPECT_EQ(2, launch_count_);
 
   // Test showing the app list via the shim, then dismissing the app list.
   LaunchShim();
@@ -114,14 +85,4 @@
   EXPECT_EQ(3, launch_count_);
   service->DismissAppList();
   EXPECT_FALSE(service->IsAppListVisible());
-  EXPECT_EQ(2, close_count_);
-
-  // Verify that observers are correctly removed by ensuring that |close_count_|
-  // is unchanged when the app list is dismissed again.
-  service->ShowForProfile(browser()->profile());
-  EXPECT_TRUE(service->IsAppListVisible());
-  EXPECT_EQ(3, launch_count_);
-  service->DismissAppList();
-  EXPECT_FALSE(service->IsAppListVisible());
-  EXPECT_EQ(2, close_count_);
 }
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 ee4769f..e53fa9b 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -7,6 +7,7 @@
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/feedback/feedback_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -23,6 +24,7 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_source.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/user_metrics.h"
 
@@ -54,12 +56,41 @@
 AppListViewDelegate::AppListViewDelegate(AppListControllerDelegate* controller,
                                          Profile* profile)
     : controller_(controller),
-      profile_(profile) {}
+      profile_(profile),
+      model_(NULL) {
+  DCHECK(profile_);
+  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
+                 content::Source<Profile>(profile_));
+  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
+                 content::Source<Profile>(profile_));
+  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
+                 content::Source<Profile>(profile_));
+  g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
+}
 
-AppListViewDelegate::~AppListViewDelegate() {}
+AppListViewDelegate::~AppListViewDelegate() {
+  g_browser_process->
+      profile_manager()->GetProfileInfoCache().RemoveObserver(this);
+}
+
+void AppListViewDelegate::OnProfileChanged() {
+  model_->SetSignedIn(!signin_delegate_->NeedSignin());
+  ProfileInfoCache& cache =
+      g_browser_process->profile_manager()->GetProfileInfoCache();
+  // Populate the current user details.
+  size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
+  // The profile won't exist in the cache if the current app list profile is
+  // being deleted.
+  if (profile_index == std::string::npos)
+    return;
+
+  model_->SetCurrentUser(cache.GetNameOfProfileAtIndex(profile_index),
+                         cache.GetUserNameOfProfileAtIndex(profile_index));
+}
 
 void AppListViewDelegate::SetModel(app_list::AppListModel* model) {
   if (model) {
+    model_ = model;
     apps_builder_.reset(new AppsModelBuilder(profile_,
                                              model->apps(),
                                              controller_.get()));
@@ -74,9 +105,12 @@
     app_sync_ui_state_watcher_.reset(new AppSyncUIStateWatcher(profile_,
                                                                model));
 #endif
+    OnProfileChanged();
   } else {
+    model_ = NULL;
     apps_builder_.reset();
     search_controller_.reset();
+    signin_delegate_.reset();
 #if defined(USE_ASH)
     app_sync_ui_state_watcher_.reset();
 #endif
@@ -122,12 +156,12 @@
 }
 
 void AppListViewDelegate::StartSearch() {
-  if (search_controller_.get())
+  if (search_controller_)
     search_controller_->Start();
 }
 
 void AppListViewDelegate::StopSearch() {
-  if (search_controller_.get())
+  if (search_controller_)
     search_controller_->Stop();
 }
 
@@ -152,34 +186,10 @@
   controller_->ViewClosing();
 }
 
-void AppListViewDelegate::ViewActivationChanged(bool active) {
-  controller_->ViewActivationChanged(active);
-}
-
 gfx::ImageSkia AppListViewDelegate::GetWindowIcon() {
   return controller_->GetWindowIcon();
 }
 
-string16 AppListViewDelegate::GetCurrentUserName() {
-  ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
-  if (profile_index != std::string::npos)
-    return cache.GetNameOfProfileAtIndex(profile_index);
-
-  return string16();
-}
-
-string16 AppListViewDelegate::GetCurrentUserEmail()  {
-  ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
-  if (profile_index != std::string::npos)
-    return cache.GetUserNameOfProfileAtIndex(profile_index);
-
-  return string16();
-}
-
 void AppListViewDelegate::OpenSettings() {
   ExtensionService* service = profile_->GetExtensionService();
   DCHECK(service);
@@ -209,3 +219,19 @@
   chrome::ShowFeedbackPage(browser, std::string(),
                            chrome::kAppLauncherCategoryTag);
 }
+
+void AppListViewDelegate::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  OnProfileChanged();
+}
+
+void AppListViewDelegate::OnProfileNameChanged(
+    const base::FilePath& profile_path,
+    const base::string16& old_profile_name) {
+  if (profile_->GetPath() != profile_path)
+    return;
+
+  OnProfileChanged();
+}
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
index 0b5d121..c2576aa 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -11,6 +11,9 @@
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
+#include "chrome/browser/profiles/profile_info_cache_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "ui/app_list/app_list_view_delegate.h"
 
 class AppListControllerDelegate;
@@ -25,6 +28,11 @@
 class FilePath;
 }
 
+namespace content {
+class NotificationDetails;
+class NotificationSource;
+}
+
 namespace gfx {
 class ImageSkia;
 }
@@ -33,13 +41,17 @@
 class AppSyncUIStateWatcher;
 #endif
 
-class AppListViewDelegate : public app_list::AppListViewDelegate {
+class AppListViewDelegate : public app_list::AppListViewDelegate,
+                            public content::NotificationObserver,
+                            public ProfileInfoCacheObserver {
  public:
   // The delegate will take ownership of the controller.
   AppListViewDelegate(AppListControllerDelegate* controller, Profile* profile);
   virtual ~AppListViewDelegate();
 
  private:
+  void OnProfileChanged();
+
   // Overridden from app_list::AppListViewDelegate:
   virtual void SetModel(app_list::AppListModel* model) OVERRIDE;
   virtual app_list::SigninDelegate* GetSigninDelegate() OVERRIDE;
@@ -57,20 +69,29 @@
                                         int event_flags) OVERRIDE;
   virtual void Dismiss() OVERRIDE;
   virtual void ViewClosing() OVERRIDE;
-  virtual void ViewActivationChanged(bool active) OVERRIDE;
   virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
-  virtual string16 GetCurrentUserName() OVERRIDE;
-  virtual string16 GetCurrentUserEmail() OVERRIDE;
   virtual void OpenSettings() OVERRIDE;
   virtual void OpenHelp() OVERRIDE;
   virtual void OpenFeedback() OVERRIDE;
 
+  // Overridden from content::NotificationObserver:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // Overridden from ProfileInfoCacheObserver:
+  virtual void OnProfileNameChanged(
+      const base::FilePath& profile_path,
+      const base::string16& old_profile_name) OVERRIDE;
+
   scoped_ptr<app_list::SigninDelegate> signin_delegate_;
   scoped_ptr<AppsModelBuilder> apps_builder_;
   scoped_ptr<app_list::SearchController> search_controller_;
   scoped_ptr<AppListControllerDelegate> controller_;
   Profile* profile_;
+  app_list::AppListModel* model_;  // Weak. Owned by AppListView.
 
+  content::NotificationRegistrar registrar_;
 #if defined(USE_ASH)
   scoped_ptr<AppSyncUIStateWatcher> app_sync_ui_state_watcher_;
 #endif
diff --git a/chrome/browser/ui/app_list/apps_model_builder_unittest.cc b/chrome/browser/ui/app_list/apps_model_builder_unittest.cc
index 4dca6ee..c1554e5 100644
--- a/chrome/browser/ui/app_list/apps_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/apps_model_builder_unittest.cc
@@ -15,9 +15,9 @@
 #include "chrome/browser/extensions/extension_service_unittest.h"
 #include "chrome/browser/extensions/extension_sorting.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
+#include "extensions/common/manifest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/app_list/app_list_item_model.h"
 
diff --git a/chrome/browser/ui/app_list/chrome_signin_delegate.cc b/chrome/browser/ui/app_list/chrome_signin_delegate.cc
index e74ca6f..e7d0aa4 100644
--- a/chrome/browser/ui/app_list/chrome_signin_delegate.cc
+++ b/chrome/browser/ui/app_list/chrome_signin_delegate.cc
@@ -18,7 +18,6 @@
 #include "content/public/common/page_transition_types.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
-#include "ui/app_list/signin_delegate_observer.h"
 #include "ui/base/resource/resource_bundle.h"
 
 namespace {
@@ -49,8 +48,6 @@
 void ChromeSigninDelegate::ShowSignin() {
   DCHECK(profile_);
 
-  signin_tracker_.reset(new SigninTracker(profile_, this));
-
   Browser* browser = FindOrCreateTabbedBrowser(profile_,
                                                chrome::GetActiveDesktop());
   chrome::ShowBrowserSignin(browser, signin::SOURCE_APP_LAUNCHER);
@@ -101,9 +98,3 @@
 }
 
 ChromeSigninDelegate::~ChromeSigninDelegate() {}
-
-void ChromeSigninDelegate::SigninFailed(const GoogleServiceAuthError& error) {}
-
-void ChromeSigninDelegate::SigninSuccess() {
-  NotifySigninSuccess();
-}
diff --git a/chrome/browser/ui/app_list/chrome_signin_delegate.h b/chrome/browser/ui/app_list/chrome_signin_delegate.h
index 059cbdc..17e9b5a 100644
--- a/chrome/browser/ui/app_list/chrome_signin_delegate.h
+++ b/chrome/browser/ui/app_list/chrome_signin_delegate.h
@@ -7,13 +7,11 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/signin/signin_tracker.h"
 #include "ui/app_list/signin_delegate.h"
 
 class Profile;
 
-class ChromeSigninDelegate : public app_list::SigninDelegate,
-                             public SigninTracker::Observer {
+class ChromeSigninDelegate : public app_list::SigninDelegate {
  public:
   explicit ChromeSigninDelegate(Profile* profile);
 
@@ -34,14 +32,8 @@
   virtual string16 GetLearnMoreLinkText() OVERRIDE;
   virtual string16 GetSettingsLinkText() OVERRIDE;
 
-  // Overridden from SigninTracker::Observer:
-  virtual void SigninFailed(const GoogleServiceAuthError& error) OVERRIDE;
-  virtual void SigninSuccess() OVERRIDE;
-
   Profile* profile_;
 
-  scoped_ptr<SigninTracker> signin_tracker_;
-
   DISALLOW_COPY_AND_ASSIGN(ChromeSigninDelegate);
 };
 
diff --git a/chrome/browser/ui/app_list/search/app_result.cc b/chrome/browser/ui/app_list/search/app_result.cc
index 4cd6328..1c49dd3 100644
--- a/chrome/browser/ui/app_list/search/app_result.cc
+++ b/chrome/browser/ui/app_list/search/app_result.cc
@@ -13,11 +13,14 @@
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/search/tokenized_string.h"
 #include "chrome/browser/ui/app_list/search/tokenized_string_match.h"
+#include "chrome/browser/ui/extensions/extension_enable_flow.h"
 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "content/public/browser/user_metrics.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/image/image_skia_operations.h"
 
 namespace app_list {
 
@@ -44,7 +47,7 @@
       extension_misc::EXTENSION_ICON_SMALL,
       extensions::IconsInfo::GetDefaultAppIcon(),
       this));
-  SetIcon(icon_->image_skia());
+  UpdateIcon();
   StartObservingInstall();
 }
 
@@ -73,6 +76,10 @@
   if (!extension)
     return;
 
+  // Check if enable flow is already running or should be started
+  if (RunExtensionEnableFlow())
+    return;
+
   CoreAppLauncherHandler::RecordAppListSearchLaunch(extension);
   content::RecordAction(
       content::UserMetricsAction("AppList_ClickOnAppFromSearch"));
@@ -118,15 +125,59 @@
   install_tracker_ = NULL;
 }
 
+bool AppResult::RunExtensionEnableFlow() {
+  const ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile_)->extension_service();
+  if (service->IsExtensionEnabledForLauncher(app_id_))
+    return false;
+
+  if (!extension_enable_flow_) {
+    controller_->OnShowExtensionPrompt();
+
+    extension_enable_flow_.reset(new ExtensionEnableFlow(
+        profile_, app_id_, this));
+    extension_enable_flow_->StartForNativeWindow(
+        controller_->GetAppListWindow());
+  }
+  return true;
+}
+
+void AppResult::UpdateIcon() {
+  gfx::ImageSkia icon = icon_->image_skia();
+
+  const ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile_)->extension_service();
+  const bool enabled = service->IsExtensionEnabledForLauncher(app_id_);
+  if (!enabled) {
+    const color_utils::HSL shift = {-1, 0, 0.6};
+    icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
+  }
+
+  SetIcon(icon);
+}
+
 void AppResult::OnExtensionIconImageChanged(extensions::IconImage* image) {
   DCHECK_EQ(icon_.get(), image);
-  SetIcon(icon_->image_skia());
+  UpdateIcon();
 }
 
 void AppResult::ExecuteLaunchCommand(int event_flags) {
   Open(event_flags);
 }
 
+void AppResult::ExtensionEnableFlowFinished() {
+  extension_enable_flow_.reset();
+  controller_->OnCloseExtensionPrompt();
+
+  // Automatically open app after enabling.
+  Open(ui::EF_NONE);
+}
+
+void AppResult::ExtensionEnableFlowAborted(bool user_initiated) {
+  extension_enable_flow_.reset();
+  controller_->OnCloseExtensionPrompt();
+}
+
 void AppResult::OnBeginExtensionInstall(const std::string& extension_id,
                                         const std::string& extension_name,
                                         const gfx::ImageSkia& installing_icon,
@@ -140,7 +191,9 @@
 
 void AppResult::OnExtensionInstalled(const extensions::Extension* extension) {}
 
-void AppResult::OnExtensionLoaded(const extensions::Extension* extension) {}
+void AppResult::OnExtensionLoaded(const extensions::Extension* extension) {
+  UpdateIcon();
+}
 
 void AppResult::OnExtensionUnloaded(const extensions::Extension* extension) {}
 
diff --git a/chrome/browser/ui/app_list/search/app_result.h b/chrome/browser/ui/app_list/search/app_result.h
index bb46181..4474d94 100644
--- a/chrome/browser/ui/app_list/search/app_result.h
+++ b/chrome/browser/ui/app_list/search/app_result.h
@@ -12,8 +12,10 @@
 #include "chrome/browser/extensions/install_observer.h"
 #include "chrome/browser/ui/app_list/app_context_menu_delegate.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
 
 class AppListControllerDelegate;
+class ExtensionEnableFlow;
 class Profile;
 
 namespace extensions {
@@ -29,6 +31,7 @@
 class AppResult : public ChromeSearchResult,
                   public extensions::IconImage::Observer,
                   public AppContextMenuDelegate,
+                  public ExtensionEnableFlowDelegate,
                   public extensions::InstallObserver {
  public:
   AppResult(Profile* profile,
@@ -50,6 +53,14 @@
   void StartObservingInstall();
   void StopObservingInstall();
 
+  // Checks if extension is disabled and if enable flow should be started.
+  // Returns true if extension enable flow is started or there is already one
+  // running.
+  bool RunExtensionEnableFlow();
+
+  // Updates the app item's icon, if necessary making it gray.
+  void UpdateIcon();
+
   // extensions::IconImage::Observer overrides:
   virtual void OnExtensionIconImageChanged(
       extensions::IconImage* image) OVERRIDE;
@@ -57,6 +68,10 @@
   // AppContextMenuDelegate overrides:
   virtual void ExecuteLaunchCommand(int event_flags) OVERRIDE;
 
+  // ExtensionEnableFlowDelegate overrides:
+  virtual void ExtensionEnableFlowFinished() OVERRIDE;
+  virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
+
   // extensions::InstallObserver overrides:
   virtual void OnBeginExtensionInstall(const std::string& extension_id,
                                        const std::string& extension_name,
@@ -86,6 +101,7 @@
   bool is_platform_app_;
   scoped_ptr<extensions::IconImage> icon_;
   scoped_ptr<AppContextMenu> context_menu_;
+  scoped_ptr<ExtensionEnableFlow> extension_enable_flow_;
 
   extensions::InstallTracker* install_tracker_;  // Not owned.
 
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index 992d250..a848cbc 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -72,6 +72,22 @@
 
 void AppSearchProvider::Stop() {}
 
+void AppSearchProvider::AddApps(const ExtensionSet* extensions,
+                                ExtensionService* service) {
+  for (ExtensionSet::const_iterator iter = extensions->begin();
+       iter != extensions->end(); ++iter) {
+    const extensions::Extension* app = iter->get();
+
+    if (!app->ShouldDisplayInAppLauncher())
+      continue;
+
+    if (profile_->IsOffTheRecord() &&
+        !service->CanLoadInIncognito(app))
+      continue;
+    apps_.push_back(new App(app));
+  }
+}
+
 void AppSearchProvider::RefreshApps() {
   ExtensionService* extension_service =
       extensions::ExtensionSystemFactory::GetForProfile(profile_)->
@@ -79,19 +95,11 @@
   if (!extension_service)
     return;  // During testing, there is no extension service.
 
-  const ExtensionSet* extensions = extension_service->extensions();
   apps_.clear();
-  for (ExtensionSet::const_iterator iter = extensions->begin();
-       iter != extensions->end(); ++iter) {
-    const extensions::Extension* app = iter->get();
-    if (!app->ShouldDisplayInAppLauncher())
-      continue;
 
-    if (profile_->IsOffTheRecord() &&
-        !extension_service->CanLoadInIncognito(app))
-      continue;
-    apps_.push_back(new App(app));
-  }
+  AddApps(extension_service->extensions(), extension_service);
+  AddApps(extension_service->disabled_extensions(), extension_service);
+  AddApps(extension_service->terminated_extensions(), extension_service);
 }
 
 void AppSearchProvider::Observe(int type,
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.h b/chrome/browser/ui/app_list/search/app_search_provider.h
index b5e6ed8..530a782 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.h
+++ b/chrome/browser/ui/app_list/search/app_search_provider.h
@@ -12,6 +12,8 @@
 #include "content/public/browser/notification_registrar.h"
 
 class AppListControllerDelegate;
+class ExtensionService;
+class ExtensionSet;
 class Profile;
 
 namespace app_list {
@@ -31,6 +33,8 @@
   class App;
   typedef ScopedVector<App> Apps;
 
+  // Adds extensions to apps container if they should be displayed.
+  void AddApps(const ExtensionSet* extensions, ExtensionService* service);
   void RefreshApps();
 
   // content::NotificationObserver overrides:
diff --git a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
index f487c67..fe8f22c 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
@@ -93,7 +93,7 @@
 
   service_->DisableExtension(kHostedAppId,
                              extensions::Extension::DISABLE_NONE);
-  EXPECT_EQ("", RunQuery("host"));
+  EXPECT_EQ("Hosted App", RunQuery("host"));
 
   service_->EnableExtension(kHostedAppId);
   EXPECT_EQ("Hosted App", RunQuery("host"));
diff --git a/chrome/browser/ui/app_list/search/webstore_cache.cc b/chrome/browser/ui/app_list/search/webstore_cache.cc
new file mode 100644
index 0000000..be130e4
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/webstore_cache.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 "chrome/browser/ui/app_list/search/webstore_cache.h"
+
+#include "base/values.h"
+
+namespace app_list {
+namespace {
+
+const int kWebstoreCacheMaxSize = 100;
+const int kWebstoreCacheTimeLimitInMinutes = 1;
+
+}  // namespace
+
+void WebstoreCache::CacheDeletor::operator()(WebstoreCache::Payload& payload) {
+  delete payload.second;
+}
+
+WebstoreCache::WebstoreCache()
+    : cache_(kWebstoreCacheMaxSize) {
+}
+
+WebstoreCache::~WebstoreCache() {
+}
+
+const base::DictionaryValue* WebstoreCache::Get(const std::string& query) {
+  Cache::iterator iter = cache_.Get(query);
+  if (iter != cache_.end()) {
+    if (base::Time::Now() - iter->second.first <=
+        base::TimeDelta::FromMinutes(kWebstoreCacheTimeLimitInMinutes)) {
+      return iter->second.second;
+    } else {
+      cache_.Erase(iter);
+    }
+  }
+  return NULL;
+}
+
+void WebstoreCache::Put(const std::string& query,
+                        scoped_ptr<base::DictionaryValue> result) {
+  if (result)
+    cache_.Put(query, std::make_pair(base::Time::Now(), result.release()));
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/webstore_cache.h b/chrome/browser/ui/app_list/search/webstore_cache.h
new file mode 100644
index 0000000..4890c33
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/webstore_cache.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 CHROME_BROWSER_UI_APP_LIST_SEARCH_WEBSTORE_CACHE_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_WEBSTORE_CACHE_H_
+
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/mru_cache.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace app_list {
+
+// WebstoreCache manages the cache of webstore search results which should
+// be valid during an input session. This will reduce unnecessary queries
+// for typing backspace or so on.
+class WebstoreCache {
+ public:
+  WebstoreCache();
+  ~WebstoreCache();
+
+  // 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);
+
+  // Puts the new result to the query.
+  void Put(const std::string& query, scoped_ptr<base::DictionaryValue> result);
+
+ private:
+  typedef std::pair<base::Time, base::DictionaryValue*> Payload;
+  class CacheDeletor {
+   public:
+    void operator()(Payload& payload);
+  };
+  typedef base::MRUCacheBase<std::string, Payload, CacheDeletor> Cache;
+
+  Cache cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebstoreCache);
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_WEBSTORE_CACHE_H_
diff --git a/chrome/browser/ui/app_list/search/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore_provider.cc
index 32d4f5d..ec8cdd4 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider.cc
+++ b/chrome/browser/ui/app_list/search/webstore_provider.cc
@@ -29,6 +29,8 @@
 const char kKeyId[] = "id";
 const char kKeyLocalizedName[] = "localized_name";
 const char kKeyIconUrl[] = "icon_url";
+const size_t kMinimumQueryLength = 3u;
+const int kWebstoreQueryThrottleIntrevalInMs = 100;
 
 // Returns true if the launcher should send queries to the web store server.
 bool UseWebstoreSearch() {
@@ -85,7 +87,8 @@
 WebstoreProvider::WebstoreProvider(Profile* profile,
                                    AppListControllerDelegate* controller)
   : profile_(profile),
-    controller_(controller) {}
+    controller_(controller),
+    use_throttling_(true) {}
 
 WebstoreProvider::~WebstoreProvider() {}
 
@@ -94,11 +97,27 @@
 
   // If |query| contains sensitive data, bail out and do not create the place
   // holder "search-web-store" result.
-  if (IsSensitiveInput(query))
+  if (IsSensitiveInput(query)) {
+    query_.clear();
     return;
+  }
 
   const std::string query_utf8 = UTF16ToUTF8(query);
 
+  if (query_utf8.size() < kMinimumQueryLength) {
+    query_.clear();
+    return;
+  }
+
+  query_ = query_utf8;
+  const base::DictionaryValue* cached_result = cache_.Get(query_);
+  if (cached_result) {
+    ProcessWebstoreSearchResults(cached_result);
+    if (!webstore_search_fetched_callback_.is_null())
+      webstore_search_fetched_callback_.Run();
+    return;
+  }
+
   if (UseWebstoreSearch() && chrome::IsSuggestPrefEnabled(profile_)) {
     if (!webstore_search_) {
       webstore_search_.reset(new WebstoreSearchFetcher(
@@ -106,8 +125,19 @@
                      base::Unretained(this)),
           profile_->GetRequestContext()));
     }
-    webstore_search_->Start(query_utf8,
-                            g_browser_process->GetApplicationLocale());
+
+    base::TimeDelta interval =
+        base::TimeDelta::FromMilliseconds(kWebstoreQueryThrottleIntrevalInMs);
+    if (!use_throttling_ || base::Time::Now() - last_keytyped_ > interval) {
+      query_throttler_.Stop();
+      StartQuery();
+    } else {
+      query_throttler_.Start(
+          FROM_HERE,
+          interval,
+          base::Bind(&WebstoreProvider::StartQuery, base::Unretained(this)));
+    }
+    last_keytyped_ = base::Time::Now();
   }
 
   // Add a placeholder result which when clicked will run the user's query in a
@@ -121,17 +151,26 @@
     webstore_search_->Stop();
 }
 
+void WebstoreProvider::StartQuery() {
+  // |query_| can be NULL when the query is scheduled but then canceled.
+  if (!webstore_search_ || query_.empty())
+    return;
+
+  webstore_search_->Start(query_, g_browser_process->GetApplicationLocale());
+}
+
 void WebstoreProvider::OnWebstoreSearchFetched(
     scoped_ptr<base::DictionaryValue> json) {
   ProcessWebstoreSearchResults(json.get());
+  cache_.Put(query_, json.Pass());
 
   if (!webstore_search_fetched_callback_.is_null())
     webstore_search_fetched_callback_.Run();
 }
 
 void WebstoreProvider::ProcessWebstoreSearchResults(
-    base::DictionaryValue* json) {
-  base::ListValue* result_list = NULL;
+    const base::DictionaryValue* json) {
+  const base::ListValue* result_list = NULL;
   if (!json ||
       !json->GetList(kKeyResults, &result_list) ||
       !result_list ||
@@ -143,7 +182,7 @@
   for (ListValue::const_iterator it = result_list->begin();
        it != result_list->end();
        ++it) {
-    base::DictionaryValue* dict;
+    const base::DictionaryValue* dict;
     if (!(*it)->GetAsDictionary(&dict))
       continue;
 
diff --git a/chrome/browser/ui/app_list/search/webstore_provider.h b/chrome/browser/ui/app_list/search/webstore_provider.h
index 253111d..aa6e8d4 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider.h
+++ b/chrome/browser/ui/app_list/search/webstore_provider.h
@@ -8,7 +8,10 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
+#include "chrome/browser/ui/app_list/search/webstore_cache.h"
 
 class AppListControllerDelegate;
 class Profile;
@@ -41,8 +44,11 @@
  private:
   friend class app_list::test::WebstoreProviderTest;
 
+  // Start the search request with |query_|.
+  void StartQuery();
+
   void OnWebstoreSearchFetched(scoped_ptr<base::DictionaryValue> json);
-  void ProcessWebstoreSearchResults(base::DictionaryValue* json);
+  void ProcessWebstoreSearchResults(const base::DictionaryValue* json);
   scoped_ptr<ChromeSearchResult> CreateResult(
       const base::DictionaryValue& dict);
 
@@ -50,11 +56,29 @@
     webstore_search_fetched_callback_ = callback;
   }
 
+  void set_use_throttling(bool use) { use_throttling_ = use; }
+
   Profile* profile_;
   AppListControllerDelegate* controller_;
   scoped_ptr<WebstoreSearchFetcher> webstore_search_;
   base::Closure webstore_search_fetched_callback_;
 
+  // The cache of the search result which will be valid only in a single
+  // input session.
+  WebstoreCache cache_;
+
+  // The timestamp when the last key event happened.
+  base::Time last_keytyped_;
+
+  // The timer to throttle QPS to the webstore search .
+  base::OneShotTimer<WebstoreProvider> query_throttler_;
+
+  // The current query.
+  std::string query_;
+
+  // The flag for tests. It prevents the throttling If set to false.
+  bool use_throttling_;
+
   DISALLOW_COPY_AND_ASSIGN(WebstoreProvider);
 };
 
diff --git a/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc b/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
index ced21f4..5b83a34 100644
--- a/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/webstore_provider_browsertest.cc
@@ -28,6 +28,40 @@
 
 namespace app_list {
 namespace test {
+namespace {
+
+// Mock results.
+const char kOneResult[] = "{"
+    "\"search_url\": \"http://host/search\","
+    "\"results\":["
+      "{"
+        "\"id\": \"app1_id\","
+        "\"localized_name\": \"app1 name\","
+        "\"icon_url\": \"http://host/icon\""
+      "}"
+    "]}";
+
+const char kThreeResults[] = "{"
+    "\"search_url\": \"http://host/search\","
+    "\"results\":["
+      "{"
+        "\"id\": \"app1_id\","
+        "\"localized_name\": \"one\","
+        "\"icon_url\": \"http://host/icon\""
+      "},"
+      "{"
+        "\"id\": \"app2_id\","
+        "\"localized_name\": \"two\","
+        "\"icon_url\": \"http://host/icon\""
+      "},"
+      "{"
+        "\"id\": \"app3_id\","
+        "\"localized_name\": \"three\","
+        "\"icon_url\": \"http://host/icon\""
+      "}"
+    "]}";
+
+}  // namespace
 
 class WebstoreProviderTest : public InProcessBrowserTest {
  public:
@@ -56,6 +90,8 @@
     webstore_provider_->set_webstore_search_fetched_callback(
         base::Bind(&WebstoreProviderTest::OnSearchResultsFetched,
                    base::Unretained(this)));
+    // TODO(mukai): add test cases for throttling.
+    webstore_provider_->set_use_throttling(false);
   }
 
   virtual void CleanUpOnMainThread() OVERRIDE {
@@ -67,7 +103,7 @@
                        const std::string& mock_server_response) {
     webstore_provider_->Start(UTF8ToUTF16(query));
 
-    if (!mock_server_response.empty()) {
+    if (webstore_provider_->webstore_search_ && !mock_server_response.empty()) {
       mock_server_response_ = mock_server_response;
 
       DCHECK(!run_loop_);
@@ -137,34 +173,6 @@
 #define MAYBE_Basic Basic
 #endif
 IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, MAYBE_Basic) {
-  const char kOneResult[] = "{"
-      "\"search_url\": \"http://host/search\","
-      "\"results\":["
-        "{"
-          "\"id\": \"app1_id\","
-          "\"localized_name\": \"app1 name\","
-          "\"icon_url\": \"http://host/icon\""
-        "}"
-      "]}";
-  const char kThreeResults[] = "{"
-      "\"search_url\": \"http://host/search\","
-      "\"results\":["
-        "{"
-          "\"id\": \"app1_id\","
-          "\"localized_name\": \"one\","
-          "\"icon_url\": \"http://host/icon\""
-        "},"
-        "{"
-          "\"id\": \"app2_id\","
-          "\"localized_name\": \"two\","
-          "\"icon_url\": \"http://host/icon\""
-        "},"
-        "{"
-          "\"id\": \"app3_id\","
-          "\"localized_name\": \"three\","
-          "\"icon_url\": \"http://host/icon\""
-        "}"
-      "]}";
   struct {
     const char* query;
     const char* mock_server_response;
@@ -207,7 +215,20 @@
   };
 
   for (size_t i = 0; i < arraysize(inputs); ++i)
-    EXPECT_EQ("", RunQuery(inputs[i], ""));
+    EXPECT_EQ("", RunQuery(inputs[i], kOneResult));
+}
+
+IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, NoSearchForShortQueries) {
+  EXPECT_EQ("", RunQuery("a", kOneResult));
+  EXPECT_EQ("", RunQuery("ab", kOneResult));
+  EXPECT_EQ("app1 name", RunQuery("abc", kOneResult));
+}
+
+IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, SearchCache) {
+  EXPECT_EQ("app1 name", RunQuery("foo", kOneResult));
+
+  // No result is provided but the provider gets the result from the cache.
+  EXPECT_EQ("app1 name", RunQuery("foo", ""));
 }
 
 }  // namespace test
diff --git a/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.cc b/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.cc
index 9ab735e..89fe155 100644
--- a/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.cc
+++ b/chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.cc
@@ -4,8 +4,10 @@
 
 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
 
+#include "base/command_line.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
+#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 #include "ui/base/text/text_elider.h"
@@ -114,8 +116,12 @@
 void JavaScriptAppModalDialog::OnCancel(bool suppress_js_messages) {
   // If we are shutting down and this is an onbeforeunload dialog, cancel the
   // shutdown.
-  if (is_before_unload_dialog_)
+  // TODO(sammc): Remove this when kEnableBatchedShutdown becomes mandatory.
+  if (is_before_unload_dialog_ &&
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableBatchedShutdown)) {
     browser_shutdown::SetTryingToQuit(false);
+  }
 
   // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame
   // will receive its activation messages before this dialog receives
diff --git a/chrome/browser/ui/apps/app_metro_infobar_delegate_win.cc b/chrome/browser/ui/apps/app_metro_infobar_delegate_win.cc
new file mode 100644
index 0000000..c0af2f9
--- /dev/null
+++ b/chrome/browser/ui/apps/app_metro_infobar_delegate_win.cc
@@ -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.
+
+#include "chrome/browser/ui/apps/app_metro_infobar_delegate_win.h"
+
+#include "apps/app_launch_for_metro_restart_win.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/metro_utils/metro_chrome_win.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_service_win.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/host_desktop.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/url_constants.h"
+#include "grit/generated_resources.h"
+#include "grit/google_chrome_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "win8/util/win8_util.h"
+
+// static
+void AppMetroInfoBarDelegateWin::Create(
+    Profile* profile,
+    Mode mode,
+    const std::string& extension_id) {
+  DCHECK(win8::IsSingleWindowMetroMode());
+  DCHECK_EQ(mode == SHOW_APP_LIST, extension_id.empty());
+
+  // Chrome should never get here via the Ash desktop, so only look for browsers
+  // on the native desktop.
+  Browser* browser = FindOrCreateTabbedBrowser(
+      profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
+
+  // Create a new tab at about:blank, and add the infobar.
+  content::WebContents* web_contents = browser->OpenURL(content::OpenURLParams(
+      GURL(content::kAboutBlankURL), content::Referrer(), NEW_FOREGROUND_TAB,
+      content::PAGE_TRANSITION_LINK, false));
+  InfoBarService* info_bar_service =
+      InfoBarService::FromWebContents(web_contents);
+  info_bar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
+      new AppMetroInfoBarDelegateWin(info_bar_service, mode, extension_id)));
+
+  // Use PostTask because we can get here in a COM SendMessage, and
+  // ActivateApplication can not be sent nested (returns error
+  // RPC_E_CANTCALLOUT_ININPUTSYNCCALL).
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(base::IgnoreResult(chrome::ActivateMetroChrome)));
+}
+
+AppMetroInfoBarDelegateWin::AppMetroInfoBarDelegateWin(
+    InfoBarService* info_bar_service,
+    Mode mode,
+    const std::string& extension_id)
+    : ConfirmInfoBarDelegate(info_bar_service),
+      mode_(mode),
+      extension_id_(extension_id) {
+  DCHECK_EQ(mode_ == SHOW_APP_LIST, extension_id_.empty());
+}
+
+AppMetroInfoBarDelegateWin::~AppMetroInfoBarDelegateWin() {}
+
+int AppMetroInfoBarDelegateWin::GetIconID() const {
+  return chrome::GetAppListIconResourceId();
+}
+
+string16 AppMetroInfoBarDelegateWin::GetMessageText() const {
+  return l10n_util::GetStringUTF16(mode_ == SHOW_APP_LIST ?
+      IDS_WIN8_INFOBAR_DESKTOP_RESTART_FOR_APP_LIST :
+      IDS_WIN8_INFOBAR_DESKTOP_RESTART_FOR_PACKAGED_APP);
+}
+
+string16 AppMetroInfoBarDelegateWin::GetButtonLabel(
+    InfoBarButton button) const {
+  return l10n_util::GetStringUTF16(button == BUTTON_CANCEL ?
+      IDS_WIN8_INFOBAR_DESKTOP_RESTART_TO_LAUNCH_APPS_NO_BUTTON :
+      IDS_WIN8_INFOBAR_DESKTOP_RESTART_TO_LAUNCH_APPS_YES_BUTTON);
+}
+
+bool AppMetroInfoBarDelegateWin::Accept() {
+  PrefService* prefs = g_browser_process->local_state();
+  if (mode_ == SHOW_APP_LIST) {
+    prefs->SetBoolean(prefs::kRestartWithAppList, true);
+  } else {
+    apps::SetAppLaunchForMetroRestart(
+        Profile::FromBrowserContext(web_contents()->GetBrowserContext()),
+        extension_id_);
+  }
+
+  web_contents()->Close();  // Note: deletes |this|.
+  chrome::AttemptRestartWithModeSwitch();
+  return false;
+}
+
+bool AppMetroInfoBarDelegateWin::Cancel() {
+  web_contents()->Close();
+  return false;
+}
+
+string16 AppMetroInfoBarDelegateWin::GetLinkText() const {
+  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
+}
+
+bool AppMetroInfoBarDelegateWin::LinkClicked(
+    WindowOpenDisposition disposition) {
+  web_contents()->OpenURL(content::OpenURLParams(
+      GURL("https://support.google.com/chrome/?p=ib_redirect_to_desktop"),
+      content::Referrer(),
+      (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
+      content::PAGE_TRANSITION_LINK, false));
+  return false;
+}
diff --git a/chrome/browser/ui/apps/app_metro_infobar_delegate_win.h b/chrome/browser/ui/apps/app_metro_infobar_delegate_win.h
new file mode 100644
index 0000000..920654e
--- /dev/null
+++ b/chrome/browser/ui/apps/app_metro_infobar_delegate_win.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 CHROME_BROWSER_UI_APPS_APP_METRO_INFOBAR_DELEGATE_WIN_H_
+#define CHROME_BROWSER_UI_APPS_APP_METRO_INFOBAR_DELEGATE_WIN_H_
+
+#include <string>
+
+#include "chrome/browser/infobars/confirm_infobar_delegate.h"
+
+class InfoBarService;
+class Profile;
+
+// This infobar operates by opening a new tab on about:blank, showing an
+// infobar offering to relaunch the browser in metro mode, and then relaunching
+// in Desktop mode if confirmed.
+class AppMetroInfoBarDelegateWin : public ConfirmInfoBarDelegate {
+ public:
+  enum Mode {
+    SHOW_APP_LIST,
+    LAUNCH_PACKAGED_APP
+  };
+
+  // Creates an app metro infobar delegate, adds it to a new browser tab, then
+  // activates Metro mode.
+  static void Create(Profile* profile,
+                     Mode mode,
+                     const std::string& extension_id);
+
+ private:
+  AppMetroInfoBarDelegateWin(InfoBarService* infobar_service,
+                             Mode mode,
+                             const std::string& extension_id);
+  virtual ~AppMetroInfoBarDelegateWin();
+
+  // ConfirmInfoBarDelegate overrides:
+  virtual int GetIconID() const OVERRIDE;
+  virtual string16 GetMessageText() const OVERRIDE;
+  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
+  virtual bool Accept() OVERRIDE;
+  virtual bool Cancel() OVERRIDE;
+  virtual string16 GetLinkText() const OVERRIDE;
+  virtual bool LinkClicked(WindowOpenDisposition disposition) OVERRIDE;
+
+  Mode mode_;
+  std::string extension_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppMetroInfoBarDelegateWin);
+};
+
+#endif  // CHROME_BROWSER_UI_APPS_APP_METRO_INFOBAR_DELEGATE_WIN_H_
diff --git a/chrome/browser/ui/apps/apps_metro_handler_win.cc b/chrome/browser/ui/apps/apps_metro_handler_win.cc
new file mode 100644
index 0000000..d10bf2b
--- /dev/null
+++ b/chrome/browser/ui/apps/apps_metro_handler_win.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 "chrome/browser/ui/apps/apps_metro_handler_win.h"
+
+#include "apps/shell_window.h"
+#include "apps/shell_window_registry.h"
+#include "chrome/browser/ui/simple_message_box.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+bool VerifySwitchToMetroForApps(gfx::NativeWindow parent_window) {
+  if (!apps::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
+          apps::ShellWindow::WINDOW_TYPE_DEFAULT)) {
+    return true;
+  }
+
+  chrome::MessageBoxResult result = chrome::ShowMessageBox(
+      parent_window,
+      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+      l10n_util::GetStringUTF16(IDS_WIN8_PROMPT_TO_CLOSE_APPS_FOR_METRO),
+      chrome::MESSAGE_BOX_TYPE_OK_CANCEL);
+
+  return result == chrome::MESSAGE_BOX_RESULT_YES;
+}
diff --git a/chrome/browser/ui/apps/apps_metro_handler_win.h b/chrome/browser/ui/apps/apps_metro_handler_win.h
new file mode 100644
index 0000000..3d42725
--- /dev/null
+++ b/chrome/browser/ui/apps/apps_metro_handler_win.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 CHROME_BROWSER_UI_APPS_APPS_METRO_HANDLER_WIN_H_
+#define CHROME_BROWSER_UI_APPS_APPS_METRO_HANDLER_WIN_H_
+
+#include "ui/gfx/native_widget_types.h"
+
+// Check if there are apps running and if not, return true. Otherwise, Show a
+// modal dialog on |parent| asking whether the user is OK with their packaged
+// apps closing, in order to relaunch to metro mode. Returns true if the user
+// clicks OK.
+bool VerifySwitchToMetroForApps(gfx::NativeWindow parent);
+
+#endif  // CHROME_BROWSER_UI_APPS_APPS_METRO_HANDLER_WIN_H_
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc b/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
index c03aae9..c7dee54 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_browsertest.cc
@@ -12,7 +12,7 @@
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.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"
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
index e8194fa..57e7eba 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate_chromeos.cc
@@ -7,6 +7,7 @@
 #include "apps/native_app_window.h"
 #include "apps/shell_window_registry.h"
 #include "ash/keyboard_overlay/keyboard_overlay_view.h"
+#include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
@@ -15,7 +16,7 @@
 #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
 #include "chrome/browser/chromeos/background/ash_user_wallpaper_delegate.h"
 #include "chrome/browser/chromeos/display/display_preferences.h"
-#include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #include "chrome/browser/chromeos/extensions/media_player_api.h"
 #include "chrome/browser/chromeos/extensions/media_player_event_router.h"
 #include "chrome/browser/chromeos/system/ash_system_tray_delegate.h"
@@ -43,6 +44,21 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_view.h"
 
+namespace {
+
+// This function is used for restoring focus after the user session is started.
+// It's needed because some windows can be opened in background while login UI
+// is still active because we currently restore browser windows before login UI
+// is deleted.
+void RestoreFocus() {
+  ash::MruWindowTracker::WindowList mru_list =
+      ash::Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
+  if (!mru_list.empty())
+    mru_list.front()->Focus();
+}
+
+}  // anonymous namespace
+
 bool ChromeShellDelegate::IsFirstRunAfterBoot() const {
   return CommandLine::ForCurrentProcess()->HasSwitch(
       chromeos::switches::kFirstExecAfterBoot);
@@ -69,19 +85,20 @@
       return;
     }
   } else {
+    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(kFileBrowserDomain);
+        registry->GetShellWindowsForApp(kFileManagerAppId);
     if (list.empty()) {
       // Open the new window.
       const ExtensionService* const service = profile->GetExtensionService();
       if (service == NULL ||
-          !service->IsExtensionEnabledForLauncher(kFileBrowserDomain))
+          !service->IsExtensionEnabledForLauncher(kFileManagerAppId))
         return;
       const extensions::Extension* const extension =
-          service->GetInstalledExtension(kFileBrowserDomain);
+          service->GetInstalledExtension(kFileManagerAppId);
       // event_flags = 0 means this invokes the same behavior as the launcher
       // item is clicked without any keyboard modifiers.
       chrome::OpenApplication(
@@ -242,6 +259,7 @@
       ash::Shell::GetInstance()->CreateLauncher();
       break;
     case chrome::NOTIFICATION_SESSION_STARTED:
+      RestoreFocus();
       ash::Shell::GetInstance()->ShowLauncher();
       break;
     default:
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 f32790d..bdb625f 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
@@ -12,7 +12,6 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -40,9 +39,9 @@
 // item with the appropriate LauncherItemController type).
 AppShortcutLauncherItemController::AppShortcutLauncherItemController(
     const std::string& app_id,
-    ChromeLauncherControllerPerApp* controller)
+    ChromeLauncherController* controller)
     : LauncherItemController(TYPE_SHORTCUT, app_id, controller),
-      app_controller_(controller) {
+      chrome_launcher_controller_(controller) {
   // To detect V1 applications we use their domain and match them against the
   // used URL. This will also work with applications like Google Drive.
   const Extension* extension =
@@ -61,25 +60,30 @@
   return GetAppTitle();
 }
 
-bool AppShortcutLauncherItemController::HasWindow(aura::Window* window) const {
+bool AppShortcutLauncherItemController::IsCurrentlyShownInWindow(
+    aura::Window* window) const {
+  Browser* browser = chrome::FindBrowserWithWindow(window);
+  content::WebContents* active_content_of_window =
+      browser ? browser->tab_strip_model()->GetActiveWebContents() : NULL;
+
   std::vector<content::WebContents*> content =
-      app_controller_->GetV1ApplicationsFromAppId(app_id());
-  for (size_t i = 0; i < content.size(); i++) {
-    Browser* browser = chrome::FindBrowserWithWebContents(content[i]);
-    if (browser && browser->window()->GetNativeWindow() == window)
-      return true;
-  }
-  return false;
+      chrome_launcher_controller_->GetV1ApplicationsFromAppId(app_id());
+
+  std::vector<content::WebContents*>::const_iterator iter =
+      std::find(content.begin(), content.end(), active_content_of_window);
+
+  return iter != content.end() ? true : false;
 }
 
 bool AppShortcutLauncherItemController::IsOpen() const {
-  return !app_controller_->GetV1ApplicationsFromAppId(app_id()).empty();
+  return !chrome_launcher_controller_->
+      GetV1ApplicationsFromAppId(app_id()).empty();
 }
 
 bool AppShortcutLauncherItemController::IsVisible() const {
   // Return true if any browser window associated with the app is visible.
   std::vector<content::WebContents*> content =
-      app_controller_->GetV1ApplicationsFromAppId(app_id());
+      chrome_launcher_controller_->GetV1ApplicationsFromAppId(app_id());
   for (size_t i = 0; i < content.size(); i++) {
     Browser* browser = chrome::FindBrowserWithWebContents(content[i]);
     if (browser && browser->window()->GetNativeWindow()->IsVisible())
@@ -89,7 +93,7 @@
 }
 
 void AppShortcutLauncherItemController::Launch(int event_flags) {
-  app_controller_->LaunchApp(app_id(), event_flags);
+  launcher_controller()->LaunchApp(app_id(), event_flags);
 }
 
 void AppShortcutLauncherItemController::Activate() {
@@ -114,7 +118,7 @@
 void AppShortcutLauncherItemController::Close() {
   // Close all running 'programs' of this type.
   std::vector<content::WebContents*> content =
-      app_controller_->GetV1ApplicationsFromAppId(app_id());
+      launcher_controller()->GetV1ApplicationsFromAppId(app_id());
   for (size_t i = 0; i < content.size(); i++) {
     Browser* browser = chrome::FindBrowserWithWebContents(content[i]);
     if (!browser)
@@ -157,8 +161,8 @@
   for (size_t i = 0; i < content_list.size(); i++) {
     content::WebContents* web_contents = content_list[i];
     // Get the icon.
-    gfx::Image app_icon = app_controller_->GetAppListIcon(web_contents);
-    string16 title = app_controller_->GetAppListTitle(web_contents);
+    gfx::Image app_icon = launcher_controller()->GetAppListIcon(web_contents);
+    string16 title = launcher_controller()->GetAppListTitle(web_contents);
     items.push_back(new ChromeLauncherAppMenuItemTab(
         title, &app_icon, web_contents, i == 0));
   }
@@ -261,8 +265,8 @@
            refocus_pattern.MatchesURL(tab_url)) ||
           (extension->OverlapsWithOrigin(tab_url) &&
            extension->web_extent().MatchesURL(tab_url)) ||
-          launcher_controller()->GetPerAppInterface()->
-             IsWebContentHandledByApplication(web_contents, app_id()));
+          launcher_controller()->IsWebContentHandledByApplication(web_contents,
+                                                                  app_id()));
 }
 
 void AppShortcutLauncherItemController::ActivateContent(
@@ -275,7 +279,8 @@
   int old_index = tab_strip->active_index();
   if (index != old_index)
     tab_strip->ActivateTabAt(index, false);
-  app_controller_->ActivateWindowOrMinimizeIfActive(browser->window(),
+  launcher_controller()->ActivateWindowOrMinimizeIfActive(
+      browser->window(),
       index == old_index && GetRunningApplications().size() == 1);
 }
 
@@ -308,7 +313,8 @@
 }
 
 bool AppShortcutLauncherItemController::IsV2App() {
-  const Extension* extension = app_controller_->GetExtensionForAppID(app_id());
+  const Extension* extension =
+      launcher_controller()->GetExtensionForAppID(app_id());
   return extension && extension->is_platform_app();
 }
 
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 49a2e7b..bf8ab68 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
@@ -8,8 +8,10 @@
 #include <string>
 
 #include "base/time/time.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+#include "url/gurl.h"
+
+class URLPattern;
 
 namespace aura {
 class Window;
@@ -27,13 +29,13 @@
 class AppShortcutLauncherItemController : public LauncherItemController {
  public:
   AppShortcutLauncherItemController(const std::string& app_id,
-                                    ChromeLauncherControllerPerApp* controller);
+                                    ChromeLauncherController* controller);
 
   virtual ~AppShortcutLauncherItemController();
 
   // LauncherItemController overrides:
   virtual string16 GetTitle() OVERRIDE;
-  virtual bool HasWindow(aura::Window* window) const OVERRIDE;
+  virtual bool IsCurrentlyShownInWindow(aura::Window* window) const OVERRIDE;
   virtual bool IsOpen() const OVERRIDE;
   virtual bool IsVisible() const OVERRIDE;
   virtual void Launch(int event_flags) OVERRIDE;
@@ -79,12 +81,13 @@
   bool AllowNextLaunchAttempt();
 
   GURL refocus_url_;
-  ChromeLauncherControllerPerApp* app_controller_;
 
   // Since V2 applications can be undetectable after launching, this timer is
   // keeping track of the last launch attempt.
   base::Time last_launch_attempt_;
 
+  ChromeLauncherController* chrome_launcher_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(AppShortcutLauncherItemController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc
index 349bcf4..04668bb 100644
--- a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.cc
@@ -63,17 +63,11 @@
   ash::LauncherItemStatus app_status =
       ash::wm::IsActiveWindow(window_) ?
       ash::STATUS_ACTIVE : ash::STATUS_RUNNING;
-  if (type() != TYPE_TABBED && type() != TYPE_WINDOWED_APP) {
+  if (type() != TYPE_TABBED && type() != TYPE_WINDOWED_APP)
     launcher_controller()->CreateAppLauncherItem(this, app_id(), app_status);
-  } else {
-    launcher_controller()->CreateTabbedLauncherItem(
-        this,
-        is_incognito_ ? ChromeLauncherController::STATE_INCOGNITO :
-                        ChromeLauncherController::STATE_NOT_INCOGNITO,
-        app_status);
-    if (type() == TYPE_WINDOWED_APP)
-      launcher_controller()->LockV1AppWithID(LauncherItemController::app_id());
-  }
+  else if (type() == TYPE_WINDOWED_APP)
+    launcher_controller()->LockV1AppWithID(LauncherItemController::app_id());
+
   // In testing scenarios we can get tab strips with no active contents.
   if (tab_model_->active_index() != TabStripModel::kNoTab)
     UpdateLauncher(tab_model_->GetActiveWebContents());
@@ -92,8 +86,7 @@
     type = TYPE_TABBED;
     if (!browser->is_type_tabbed() &&
         browser->is_type_popup() &&
-        browser->is_app() &&
-        ChromeLauncherController::instance()->GetPerAppInterface()) {
+        browser->is_app()) {
       app_id = web_app::GetExtensionIdFromApplicationName(
                     browser->app_name());
       // Only allow this for known applications. Some unit tests for example
@@ -135,7 +128,8 @@
   return GetAppTitle();
 }
 
-bool BrowserLauncherItemController::HasWindow(aura::Window* window) const {
+bool BrowserLauncherItemController::IsCurrentlyShownInWindow(
+    aura::Window* window) const {
   return window_ == window;
 }
 
@@ -179,11 +173,6 @@
 void BrowserLauncherItemController::LauncherItemChanged(
     int index,
     const ash::LauncherItem& old_item) {
-  if (!launcher_controller()->GetPerAppInterface() &&
-      launcher_model()->items()[index].status == ash::STATUS_ACTIVE &&
-      old_item.status == ash::STATUS_RUNNING) {
-    Activate();
-  }
 }
 
 ChromeLauncherAppMenuItems
@@ -200,9 +189,8 @@
     int reason) {
   // Update immediately on a tab change.
   if (old_contents &&
-      (!launcher_controller()->GetPerAppInterface() ||
-       TabStripModel::kNoTab !=
-           tab_model_->GetIndexOfWebContents(old_contents)))
+      TabStripModel::kNoTab !=
+          tab_model_->GetIndexOfWebContents(old_contents))
     UpdateAppState(old_contents);
   UpdateAppState(new_contents);
   UpdateLauncher(new_contents);
@@ -256,60 +244,15 @@
 }
 
 void BrowserLauncherItemController::UpdateItemStatus() {
-  if (launcher_controller()->GetPerAppInterface())
-    return;
-
-  ash::LauncherItemStatus status;
-  if (ash::wm::IsActiveWindow(window_)) {
-    // Clear attention state if active.
-    if (window_->GetProperty(aura::client::kDrawAttentionKey))
-      window_->SetProperty(aura::client::kDrawAttentionKey, false);
-    status = ash::STATUS_ACTIVE;
-  } else if (window_->GetProperty(aura::client::kDrawAttentionKey)) {
-    status = ash::STATUS_ATTENTION;
-  } else {
-    status = ash::STATUS_RUNNING;
-  }
-  launcher_controller()->SetItemStatus(launcher_id(), status);
 }
 
 void BrowserLauncherItemController::UpdateLauncher(content::WebContents* tab) {
-  if (launcher_controller()->GetPerAppInterface())
-    return;
-
-  if (type() == TYPE_APP_PANEL)
-    return;  // Maintained entirely by ChromeLauncherController.
-
-  if (!tab)
-    return;  // Assume the window is going to be closed if there are no tabs.
-
-  int item_index = launcher_model()->ItemIndexByID(launcher_id());
-  if (item_index == -1)
-    return;
-
-  ash::LauncherItem item = launcher_model()->items()[item_index];
-  DCHECK_EQ(TYPE_TABBED, type());
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  FaviconTabHelper* favicon_tab_helper =
-      FaviconTabHelper::FromWebContents(tab);
-  if (favicon_tab_helper->ShouldDisplayFavicon()) {
-    item.image = favicon_tab_helper->GetFavicon().AsImageSkia();
-    if (item.image.isNull()) {
-      item.image = *rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
-    }
-  } else {
-    item.image = *rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
-  }
-  launcher_model()->Set(item_index, item);
 }
 
 void BrowserLauncherItemController::UpdateAppState(content::WebContents* tab) {
   ChromeLauncherController::AppState app_state;
 
-  if (!launcher_controller()->GetPerAppInterface() &&
-      tab_model_->GetIndexOfWebContents(tab) == TabStripModel::kNoTab) {
-    app_state = ChromeLauncherController::APP_STATE_REMOVED;
-  } else if (tab_model_->GetActiveWebContents() == tab) {
+  if (tab_model_->GetActiveWebContents() == tab) {
     if (ash::wm::IsActiveWindow(window_))
       app_state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
     else
diff --git a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h
index 512408b..51fbc33 100644
--- a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller.h
@@ -68,7 +68,7 @@
 
   // LauncherItemController overrides:
   virtual string16 GetTitle() OVERRIDE;
-  virtual bool HasWindow(aura::Window* window) const OVERRIDE;
+  virtual bool IsCurrentlyShownInWindow(aura::Window* window) const OVERRIDE;
   virtual bool IsOpen() const OVERRIDE;
   virtual bool IsVisible() const OVERRIDE;
   virtual void Launch(int event_flags) OVERRIDE;
diff --git a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller_unittest.cc b/chrome/browser/ui/ash/launcher/browser_launcher_item_controller_unittest.cc
deleted file mode 100644
index 0f20bc2..0000000
--- a/chrome/browser/ui/ash/launcher/browser_launcher_item_controller_unittest.cc
+++ /dev/null
@@ -1,543 +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/launcher/browser_launcher_item_controller.h"
-
-#include <map>
-#include <string>
-
-#include "ash/ash_switches.h"
-#include "ash/launcher/launcher_model.h"
-#include "base/command_line.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/favicon/favicon_tab_helper.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/web_contents.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/aura/client/activation_change_observer.h"
-#include "ui/aura/client/activation_delegate.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/test_activation_client.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_delegate.h"
-#include "ui/base/events/event.h"
-
-// TODO(skuhne): Remove this module together with the
-// browser_launcher_item_controller.* when the old launcher goes away.
-
-namespace {
-
-// Test implementation of AppTabHelper.
-class AppTabHelperImpl : public ChromeLauncherController::AppTabHelper {
- public:
-  AppTabHelperImpl() {}
-  virtual ~AppTabHelperImpl() {}
-
-  // Sets the id for the specified tab. The id is removed if Remove() is
-  // invoked.
-  void SetAppID(content::WebContents* tab, const std::string& id) {
-    tab_id_map_[tab] = id;
-  }
-
-  // Returns true if there is an id registered for |tab|.
-  bool HasAppID(content::WebContents* tab) const {
-    return tab_id_map_.find(tab) != tab_id_map_.end();
-  }
-
-  // AppTabHelper implementation:
-  virtual std::string GetAppID(content::WebContents* tab) OVERRIDE {
-    return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] :
-        std::string();
-  }
-
-  virtual bool IsValidID(const std::string& id) OVERRIDE {
-    for (TabToStringMap::const_iterator i = tab_id_map_.begin();
-         i != tab_id_map_.end(); ++i) {
-      if (i->second == id)
-        return true;
-    }
-    return false;
-  }
-
- private:
-  typedef std::map<content::WebContents*, std::string> TabToStringMap;
-
-  TabToStringMap tab_id_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppTabHelperImpl);
-};
-
-// Test implementation of AppIconLoader.
-class AppIconLoaderImpl : public extensions::AppIconLoader {
- public:
-  AppIconLoaderImpl() : fetch_count_(0) {}
-  virtual ~AppIconLoaderImpl() {}
-
-  // Returns the number of times FetchImage() has been invoked and resets the
-  // count to 0.
-  int GetAndClearFetchCount() {
-    int value = fetch_count_;
-    fetch_count_ = 0;
-    return value;
-  }
-
-  // AppIconLoader implementation:
-  virtual void FetchImage(const std::string& id) OVERRIDE {
-    fetch_count_++;
-  }
-  virtual void ClearImage(const std::string& id) OVERRIDE {
-  }
-  virtual void UpdateImage(const std::string& id) OVERRIDE {
-  }
-
- private:
-  int fetch_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppIconLoaderImpl);
-};
-
-// Test implementation of TabStripModelDelegate.
-class TabHelperTabStripModelDelegate : public TestTabStripModelDelegate {
- public:
-  TabHelperTabStripModelDelegate() {}
-  virtual ~TabHelperTabStripModelDelegate() {}
-
-  virtual void WillAddWebContents(content::WebContents* contents) OVERRIDE {
-    // BrowserLauncherItemController assumes that all WebContents passed to it
-    // have attached an extensions::TabHelper and a FaviconTabHelper. The
-    // TestTabStripModelDelegate adds an extensions::TabHelper.
-    TestTabStripModelDelegate::WillAddWebContents(contents);
-    FaviconTabHelper::CreateForWebContents(contents);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TabHelperTabStripModelDelegate);
-};
-
-}  // namespace
-
-// TODO(skuhne): Several of these unit tests need to be moved into a new home
-// when the old launcher & the browser launcher item controller are removed
-// (several of these tests are not testing the BrowserLauncherItemController -
-// but the LauncherController framework).
-class LauncherItemControllerPerAppTest
-    : public ChromeRenderViewHostTestHarness {
- public:
-  virtual void SetUp() OVERRIDE {
-    ChromeRenderViewHostTestHarness::SetUp();
-
-    activation_client_.reset(
-        new aura::test::TestActivationClient(root_window()));
-    launcher_model_.reset(new ash::LauncherModel);
-    launcher_delegate_.reset(
-        ChromeLauncherController::CreateInstance(profile(),
-                                                 launcher_model_.get()));
-    app_tab_helper_ = new AppTabHelperImpl;
-    app_icon_loader_ = new AppIconLoaderImpl;
-    launcher_delegate_->SetAppTabHelperForTest(app_tab_helper_);
-    launcher_delegate_->SetAppIconLoaderForTest(app_icon_loader_);
-    launcher_delegate_->Init();
-  }
-
-  virtual void TearDown() OVERRIDE {
-    launcher_delegate_.reset();
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
- protected:
-  // Contains all the objects needed to create a BrowserLauncherItemController.
-  struct State : public aura::client::ActivationDelegate,
-                 public aura::client::ActivationChangeObserver {
-   public:
-    State(LauncherItemControllerPerAppTest* test,
-          const std::string& app_id,
-          BrowserLauncherItemController::Type launcher_type)
-        : launcher_test(test),
-          window(NULL),
-          tab_strip(&tab_strip_delegate, test->profile()),
-          updater(launcher_type,
-                  &window,
-                  &tab_strip,
-                  test->launcher_delegate_.get(),
-                  app_id) {
-      window.Init(ui::LAYER_NOT_DRAWN);
-      launcher_test->root_window()->AddChild(&window);
-      launcher_test->activation_client_->ActivateWindow(&window);
-      aura::client::SetActivationDelegate(&window, this);
-      aura::client::SetActivationChangeObserver(&window, this);
-      updater.Init();
-    }
-
-    ash::LauncherItem GetUpdaterItem() {
-      ash::LauncherID launcher_id =
-          BrowserLauncherItemController::TestApi(&updater).item_id();
-      int index = launcher_test->launcher_model_->ItemIndexByID(launcher_id);
-      return launcher_test->launcher_model_->items()[index];
-    }
-
-    // aura::client::ActivationDelegate overrides.
-    virtual bool ShouldActivate() const OVERRIDE {
-      return true;
-    }
-
-    // aura::client::ActivationChangeObserver overrides:
-    virtual void OnWindowActivated(aura::Window* gained_active,
-                                   aura::Window* lost_active) OVERRIDE {
-      DCHECK(&window == gained_active || &window == lost_active);
-      updater.BrowserActivationStateChanged();
-    }
-
-    LauncherItemControllerPerAppTest* launcher_test;
-    aura::Window window;
-    TabHelperTabStripModelDelegate tab_strip_delegate;
-    TabStripModel tab_strip;
-    BrowserLauncherItemController updater;
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(State);
-  };
-
-  const std::string& GetAppID(ash::LauncherID id) const {
-    return launcher_delegate_->GetAppIdFromLauncherIdForTest(id);
-  }
-
-  void ResetAppTabHelper() {
-    launcher_delegate_->SetAppTabHelperForTest(app_tab_helper_);
-  }
-
-  void ResetAppIconLoader() {
-    launcher_delegate_->SetAppIconLoaderForTest(app_icon_loader_);
-  }
-
-  void UnpinAppsWithID(const std::string& app_id) {
-    launcher_delegate_->UnpinAppsWithID(app_id);
-  }
-
-  const ash::LauncherItem& GetItem(BrowserLauncherItemController* updater) {
-    int index = launcher_model_->ItemIndexByID(
-        BrowserLauncherItemController::TestApi(updater).item_id());
-    return launcher_model_->items()[index];
-  }
-
-  scoped_ptr<ash::LauncherModel> launcher_model_;
-  scoped_ptr<ChromeLauncherController> launcher_delegate_;
-
-  // Owned by BrowserLauncherItemController.
-  AppTabHelperImpl* app_tab_helper_;
-  AppIconLoaderImpl* app_icon_loader_;
-
-  scoped_ptr<aura::test::TestActivationClient> activation_client_;
-};
-
-// Verify that the launcher item positions are persisted and restored.
-TEST_F(LauncherItemControllerPerAppTest, PersistLauncherItemPositions) {
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
-            launcher_model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_APP_LIST,
-            launcher_model_->items()[1].type);
-  scoped_ptr<content::WebContents> tab1(CreateTestWebContents());
-  scoped_ptr<content::WebContents> tab2(CreateTestWebContents());
-  app_tab_helper_->SetAppID(tab1.get(), "1");
-  app_tab_helper_->SetAppID(tab1.get(), "2");
-
-  EXPECT_FALSE(launcher_delegate_->IsAppPinned("1"));
-  launcher_delegate_->PinAppWithID("1");
-  EXPECT_TRUE(launcher_delegate_->IsAppPinned("1"));
-  launcher_delegate_->PinAppWithID("2");
-
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
-            launcher_model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[2].type);
-  EXPECT_EQ(ash::TYPE_APP_LIST,
-            launcher_model_->items()[3].type);
-
-  launcher_model_->Move(0, 2);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
-            launcher_model_->items()[2].type);
-  EXPECT_EQ(ash::TYPE_APP_LIST,
-            launcher_model_->items()[3].type);
-
-  launcher_delegate_.reset();
-  launcher_model_.reset(new ash::LauncherModel);
-  launcher_delegate_.reset(
-      ChromeLauncherController::CreateInstance(profile(),
-                                               launcher_model_.get()));
-  app_tab_helper_ = new AppTabHelperImpl;
-  app_tab_helper_->SetAppID(tab1.get(), "1");
-  app_tab_helper_->SetAppID(tab2.get(), "2");
-  ResetAppTabHelper();
-
-  launcher_delegate_->Init();
-
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[0].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
-            launcher_model_->items()[2].type);
-  EXPECT_EQ(ash::TYPE_APP_LIST,
-            launcher_model_->items()[3].type);
-}
-
-class BrowserLauncherItemControllerTest
-    : public LauncherItemControllerPerAppTest {
- public:
-  BrowserLauncherItemControllerTest() {}
-
-  virtual void SetUp() OVERRIDE {
-    CommandLine::ForCurrentProcess()->AppendSwitch(
-        ash::switches::kAshDisablePerAppLauncher);
-
-    LauncherItemControllerPerAppTest::SetUp();
-  }
-
-  virtual void TearDown() OVERRIDE {
-    LauncherItemControllerPerAppTest::TearDown();
-  }
-};
-
-// Verifies a new launcher item is added for TYPE_TABBED.
-TEST_F(BrowserLauncherItemControllerTest, TabbedSetup) {
-  size_t initial_size = launcher_model_->items().size();
-  {
-    scoped_ptr<content::WebContents> web_contents(CreateTestWebContents());
-    State state(this, std::string(),
-                BrowserLauncherItemController::TYPE_TABBED);
-
-    // There should be one more item.
-    ASSERT_EQ(initial_size + 1, launcher_model_->items().size());
-    // New item should be added at the end.
-    EXPECT_EQ(ash::TYPE_TABBED, state.GetUpdaterItem().type);
-  }
-
-  // Deleting the BrowserLauncherItemController should have removed the item.
-  ASSERT_EQ(initial_size, launcher_model_->items().size());
-
-  // Do the same, but this time add the tab first.
-  {
-    scoped_ptr<content::WebContents> web_contents(CreateTestWebContents());
-
-    TabHelperTabStripModelDelegate tab_strip_delegate;
-    TabStripModel tab_strip(&tab_strip_delegate, profile());
-    tab_strip.InsertWebContentsAt(0,
-                                  web_contents.get(),
-                                  TabStripModel::ADD_ACTIVE);
-    aura::Window window(NULL);
-    window.Init(ui::LAYER_NOT_DRAWN);
-    root_window()->AddChild(&window);
-    BrowserLauncherItemController updater(
-        LauncherItemController::TYPE_TABBED,
-        &window, &tab_strip, launcher_delegate_.get(),
-        std::string());
-    updater.Init();
-
-    // There should be one more item.
-    ASSERT_EQ(initial_size + 1, launcher_model_->items().size());
-    // New item should be added at the end.
-    EXPECT_EQ(ash::TYPE_TABBED, GetItem(&updater).type);
-  }
-}
-
-// Verifies pinned apps are persisted and restored.
-TEST_F(BrowserLauncherItemControllerTest, PersistPinned) {
-  size_t initial_size = launcher_model_->items().size();
-  scoped_ptr<content::WebContents> tab1(CreateTestWebContents());
-
-  app_tab_helper_->SetAppID(tab1.get(), "1");
-
-  app_icon_loader_->GetAndClearFetchCount();
-  launcher_delegate_->PinAppWithID("1");
-  ash::LauncherID id = launcher_delegate_->GetLauncherIDForAppID("1");
-  int app_index = launcher_model_->ItemIndexByID(id);
-  EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[app_index].type);
-  EXPECT_TRUE(launcher_delegate_->IsAppPinned("1"));
-  EXPECT_FALSE(launcher_delegate_->IsAppPinned("0"));
-  EXPECT_EQ(initial_size + 1, launcher_model_->items().size());
-
-  launcher_delegate_.reset();
-  launcher_model_.reset(new ash::LauncherModel);
-  launcher_delegate_.reset(
-      ChromeLauncherController::CreateInstance(profile(),
-                                               launcher_model_.get()));
-  app_tab_helper_ = new AppTabHelperImpl;
-  app_tab_helper_->SetAppID(tab1.get(), "1");
-  ResetAppTabHelper();
-  app_icon_loader_ = new AppIconLoaderImpl;
-  ResetAppIconLoader();
-  launcher_delegate_->Init();
-  EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0);
-  ASSERT_EQ(initial_size + 1, launcher_model_->items().size());
-  EXPECT_TRUE(launcher_delegate_->IsAppPinned("1"));
-  EXPECT_FALSE(launcher_delegate_->IsAppPinned("0"));
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[app_index].type);
-
-  UnpinAppsWithID("1");
-  ASSERT_EQ(initial_size, launcher_model_->items().size());
-}
-
-// Verify that launcher item positions are persisted and restored.
-TEST_F(BrowserLauncherItemControllerTest,
-    PersistLauncherItemPositionsPerBrowser) {
-  int browser_shortcut_index = 0;
-  int app_list_index = 1;
-
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
-            launcher_model_->items()[browser_shortcut_index].type);
-  EXPECT_EQ(ash::TYPE_APP_LIST,
-            launcher_model_->items()[app_list_index].type);
-
-  scoped_ptr<content::WebContents> tab1(CreateTestWebContents());
-  scoped_ptr<content::WebContents> tab2(CreateTestWebContents());
-
-  app_tab_helper_->SetAppID(tab1.get(), "1");
-  app_tab_helper_->SetAppID(tab2.get(), "2");
-
-  app_icon_loader_->GetAndClearFetchCount();
-  launcher_delegate_->PinAppWithID("1");
-  ash::LauncherID id = launcher_delegate_->GetLauncherIDForAppID("1");
-  int app1_index = launcher_model_->ItemIndexByID(id);
-
-  launcher_delegate_->PinAppWithID("2");
-  id = launcher_delegate_->GetLauncherIDForAppID("2");
-  int app2_index = launcher_model_->ItemIndexByID(id);
-
-  launcher_model_->Move(browser_shortcut_index, app1_index);
-
-  browser_shortcut_index = 1;
-  app1_index = 0;
-
-  EXPECT_GT(app_icon_loader_->GetAndClearFetchCount(), 0);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[app1_index].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
-            launcher_model_->items()[browser_shortcut_index].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[app2_index].type);
-
-  launcher_delegate_.reset();
-  launcher_model_.reset(new ash::LauncherModel);
-  launcher_delegate_.reset(
-      ChromeLauncherController::CreateInstance(profile(),
-                                               launcher_model_.get()));
-
-  app_tab_helper_ = new AppTabHelperImpl;
-  app_tab_helper_->SetAppID(tab1.get(), "1");
-  app_tab_helper_->SetAppID(tab2.get(), "2");
-  ResetAppTabHelper();
-  app_icon_loader_ = new AppIconLoaderImpl;
-  ResetAppIconLoader();
-  launcher_delegate_->Init();
-
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[app1_index].type);
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT,
-            launcher_model_->items()[browser_shortcut_index].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT,
-            launcher_model_->items()[app2_index].type);
-}
-
-// Confirm that tabbed browsers handle activation correctly.
-TEST_F(BrowserLauncherItemControllerTest, ActivateBrowsers) {
-  State state1(this, std::string(), BrowserLauncherItemController::TYPE_TABBED);
-
-  // First browser is active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status);
-
-  {
-    // Both running.
-    State state2(this, std::string(),
-                 BrowserLauncherItemController::TYPE_TABBED);
-    EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status);
-    EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status);
-
-    // Make first browser active again.
-    activation_client_->ActivateWindow(&state1.window);
-    EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status);
-    EXPECT_EQ(ash::STATUS_RUNNING, state2.GetUpdaterItem().status);
-
-    // And back to second.
-    activation_client_->ActivateWindow(&state2.window);
-    EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status);
-    EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status);
-  }
-
-  // First browser should be active again after second is closed.
-  EXPECT_EQ(ash::STATUS_ACTIVE, state1.GetUpdaterItem().status);
-}
-
-// Confirm that window activation works through the model.
-TEST_F(BrowserLauncherItemControllerTest, SwitchDirectlyToApp) {
-  State state1(this, std::string(),
-               BrowserLauncherItemController::TYPE_TABBED);
-  int index1 = launcher_model_->ItemIndexByID(state1.GetUpdaterItem().id);
-
-  // Second app is active and first is inactive.
-  State state2(this, std::string(),
-               BrowserLauncherItemController::TYPE_TABBED);
-  int index2 = launcher_model_->ItemIndexByID(state2.GetUpdaterItem().id);
-
-  EXPECT_EQ(ash::STATUS_RUNNING, state1.GetUpdaterItem().status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, state2.GetUpdaterItem().status);
-  EXPECT_EQ(&state2.window, activation_client_->GetActiveWindow());
-
-  // Test that we can properly switch to the first item.
-  ash::LauncherItem new_item1(launcher_model_->items()[index1]);
-  new_item1.status = ash::STATUS_ACTIVE;
-  launcher_model_->Set(index1, new_item1);
-  EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model_->items()[index1].status);
-  EXPECT_EQ(ash::STATUS_RUNNING, launcher_model_->items()[index2].status);
-  EXPECT_EQ(&state1.window, activation_client_->GetActiveWindow());
-
-  // And to the second item active.
-  ash::LauncherItem new_item2(launcher_model_->items()[index2]);
-  new_item2.status = ash::STATUS_ACTIVE;
-  launcher_model_->Set(index2, new_item2);
-  EXPECT_EQ(ash::STATUS_RUNNING, launcher_model_->items()[index1].status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model_->items()[index2].status);
-  EXPECT_EQ(&state2.window, activation_client_->GetActiveWindow());
-}
-
-// Test attention states of windows.
-TEST_F(BrowserLauncherItemControllerTest, FlashWindow) {
-  // App panel first
-  State app_state(this, "1", BrowserLauncherItemController::TYPE_APP_PANEL);
-  EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status);
-
-  // Active windows don't show attention.
-  app_state.window.SetProperty(aura::client::kDrawAttentionKey, true);
-  EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status);
-
-  // Then browser window
-  State browser_state(
-      this, std::string(), BrowserLauncherItemController::TYPE_TABBED);
-  // First browser is active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, browser_state.GetUpdaterItem().status);
-  EXPECT_EQ(ash::STATUS_RUNNING, app_state.GetUpdaterItem().status);
-
-  // App window should go to attention state.
-  app_state.window.SetProperty(aura::client::kDrawAttentionKey, true);
-  EXPECT_EQ(ash::STATUS_ATTENTION, app_state.GetUpdaterItem().status);
-
-  // Activating app window should clear attention state.
-  activation_client_->ActivateWindow(&app_state.window);
-  EXPECT_EQ(ash::STATUS_ACTIVE, app_state.GetUpdaterItem().status);
-}
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 61a3e59..2f00201 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
@@ -13,7 +13,7 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -36,12 +36,11 @@
 #endif
 
 BrowserShortcutLauncherItemController::BrowserShortcutLauncherItemController(
-    ChromeLauncherControllerPerApp* launcher_controller,
+    ChromeLauncherController* launcher_controller,
     Profile* profile)
     : LauncherItemController(TYPE_SHORTCUT,
                              extension_misc::kChromeAppId,
                              launcher_controller),
-      app_controller_(launcher_controller),
       profile_(profile) {
 }
 
@@ -53,7 +52,7 @@
   return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
 }
 
-bool BrowserShortcutLauncherItemController::HasWindow(
+bool BrowserShortcutLauncherItemController::IsCurrentlyShownInWindow(
     aura::Window* window) const {
   const BrowserList* ash_browser_list =
       BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
@@ -158,7 +157,7 @@
       continue;
     if (browser->is_type_tabbed())
       found_tabbed_browser = true;
-    else if (!app_controller_->IsBrowserRepresentedInBrowserList(browser))
+    else if (!launcher_controller()->IsBrowserRepresentedInBrowserList(browser))
       continue;
     TabStripModel* tab_strip = browser->tab_strip_model();
     if (tab_strip->active_index() == -1)
@@ -174,8 +173,9 @@
       for (int index = 0; index  < tab_strip->count(); ++index) {
         content::WebContents* web_contents =
             tab_strip->GetWebContentsAt(index);
-        gfx::Image app_icon = app_controller_->GetAppListIcon(web_contents);
-        string16 title = app_controller_->GetAppListTitle(web_contents);
+        gfx::Image app_icon =
+            launcher_controller()->GetAppListIcon(web_contents);
+        string16 title = launcher_controller()->GetAppListTitle(web_contents);
         // Check if we need to insert a separator in front.
         bool leading_separator = !index;
         items.push_back(new ChromeLauncherAppMenuItemTab(
@@ -223,7 +223,7 @@
   for (BrowserList::const_iterator it =
            ash_browser_list->begin();
        it != ash_browser_list->end(); ++it) {
-    if (app_controller_->IsBrowserRepresentedInBrowserList(*it))
+    if (launcher_controller()->IsBrowserRepresentedInBrowserList(*it))
       items.push_back(*it);
   }
   // If there are no suitable browsers we create a new one.
@@ -254,7 +254,7 @@
                                           true,
                                           chrome::HOST_DESKTOP_TYPE_ASH);
       if (!browser ||
-          !app_controller_->IsBrowserRepresentedInBrowserList(browser))
+          !launcher_controller()->IsBrowserRepresentedInBrowserList(browser))
         browser = items[0];
     }
   }
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 4454b71..c7583f8 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
@@ -16,21 +16,20 @@
 }
 
 class Browser;
-class ChromeLauncherControllerPerApp;
+class ChromeLauncherController;
 class Profile;
 
 // Item controller for an browser shortcut.
 class BrowserShortcutLauncherItemController : public LauncherItemController {
  public:
-  BrowserShortcutLauncherItemController(
-      ChromeLauncherControllerPerApp* controller,
-      Profile* profile);
+  BrowserShortcutLauncherItemController(ChromeLauncherController* controller,
+                                        Profile* profile);
 
   virtual ~BrowserShortcutLauncherItemController();
 
   // LauncherItemController overrides:
   virtual string16 GetTitle() OVERRIDE;
-  virtual bool HasWindow(aura::Window* window) const OVERRIDE;
+  virtual bool IsCurrentlyShownInWindow(aura::Window* window) const OVERRIDE;
   virtual bool IsOpen() const OVERRIDE;
   virtual bool IsVisible() const OVERRIDE;
   virtual void Launch(int event_flags) OVERRIDE;
@@ -59,8 +58,6 @@
   // Activate a browser - or advance to the next one on the list.
   void ActivateOrAdvanceToNextBrowser();
 
-  ChromeLauncherControllerPerApp* app_controller_;
-
   Profile* profile_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserShortcutLauncherItemController);
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
index a2c4907..9ca859d 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.cc
@@ -6,12 +6,12 @@
 
 #include "ash/wm/window_util.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.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/tabs/tab_strip_model.h"
 #include "content/public/browser/notification_service.h"
+#include "ui/base/events/event_constants.h"
 
 ChromeLauncherAppMenuItemBrowser::ChromeLauncherAppMenuItemBrowser(
     const string16 title,
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
index 1aaf17d..294c2f1 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.cc
@@ -5,11 +5,11 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
 
 #include "ash/wm/window_util.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.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/tabs/tab_strip_model.h"
+#include "ui/base/events/event_constants.h"
 
 ChromeLauncherAppMenuItemTab::ChromeLauncherAppMenuItemTab(
     const string16 title,
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
index d85c90b..fe6546c 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.cc
@@ -4,13 +4,13 @@
 
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
 
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 
 ChromeLauncherAppMenuItemV2App::ChromeLauncherAppMenuItemV2App(
     const string16 title,
     const gfx::Image* icon,
     const std::string& app_id,
-    ChromeLauncherControllerPerApp* launcher_controller,
+    ChromeLauncherController* launcher_controller,
     int app_index,
     bool has_leading_separator)
     : ChromeLauncherAppMenuItem(title, icon, has_leading_separator),
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
index 391ae26..c195b0e 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h
@@ -13,7 +13,7 @@
 class image;
 }
 
-class ChromeLauncherControllerPerApp;
+class ChromeLauncherController;
 
 // A menu item controller for a running V2 application. It gets created when an
 // application list gets created. It's main purpose is to add the activation
@@ -24,7 +24,7 @@
       const string16 title,
       const gfx::Image* icon,
       const std::string& app_id,
-      ChromeLauncherControllerPerApp* launcher_controller,
+      ChromeLauncherController* launcher_controller,
       int app_index,
       bool has_leading_separator);
   virtual bool IsEnabled() const OVERRIDE;
@@ -32,7 +32,7 @@
 
  private:
   // The owning class which can be used to validate the controller.
-  ChromeLauncherControllerPerApp* launcher_controller_;
+  ChromeLauncherController* launcher_controller_;
 
   // The application ID.
   const std::string app_id_;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 442f2e8..9f1759e 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -1,17 +1,289 @@
-// Copyright (c) 2012 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.
 
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 
-#include "ash/ash_switches.h"
-#include "base/command_line.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h"
+#include <vector>
 
-// statics
+#include "ash/ash_switches.h"
+#include "ash/launcher/launcher.h"
+#include "ash/launcher/launcher_model.h"
+#include "ash/launcher/launcher_util.h"
+#include "ash/root_window_controller.h"
+#include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shelf/shelf_widget.h"
+#include "ash/shell.h"
+#include "ash/wm/window_util.h"
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/app_mode/app_mode_utils.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/extensions/app_icon_loader_impl.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#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"
+#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
+#include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
+#include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
+#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
+#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
+#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
+#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.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_list.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/application_launch.h"
+#include "chrome/browser/ui/extensions/extension_enable_flow.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/web_applications/web_app.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/extension_resource.h"
+#include "extensions/common/url_pattern.h"
+#include "grit/ash_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "grit/ui_resources.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/views/corewm/window_animations.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h"
+#endif
+
+using extensions::Extension;
+using extension_misc::kGmailAppId;
+using content::WebContents;
+
+// static
 ChromeLauncherController* ChromeLauncherController::instance_ = NULL;
 
+namespace {
+
+std::string GetPrefKeyForRootWindow(aura::RootWindow* root_window) {
+  gfx::Display display = gfx::Screen::GetScreenFor(
+      root_window)->GetDisplayNearestWindow(root_window);
+  DCHECK(display.is_valid());
+
+  return base::Int64ToString(display.id());
+}
+
+void UpdatePerDisplayPref(PrefService* pref_service,
+                          aura::RootWindow* root_window,
+                          const char* pref_key,
+                          const std::string& value) {
+  std::string key = GetPrefKeyForRootWindow(root_window);
+  if (key.empty())
+    return;
+
+  DictionaryPrefUpdate update(pref_service, prefs::kShelfPreferences);
+  base::DictionaryValue* shelf_prefs = update.Get();
+  base::DictionaryValue* prefs = NULL;
+  if (!shelf_prefs->GetDictionary(key, &prefs)) {
+    prefs = new base::DictionaryValue();
+    shelf_prefs->Set(key, prefs);
+  }
+  prefs->SetStringWithoutPathExpansion(pref_key, value);
+}
+
+// Returns a pref value in |pref_service| for the display of |root_window|. The
+// pref value is stored in |local_path| and |path|, but |pref_service| may have
+// per-display preferences and the value can be specified by policy. Here is
+// the priority:
+//  * A value managed by policy. This is a single value that applies to all
+//    displays.
+//  * A user-set value for the specified display.
+//  * A user-set value in |local_path| or |path|, if no per-display settings are
+//    ever specified (see http://crbug.com/173719 for why). |local_path| is
+//    preferred. See comment in |kShelfAlignment| as to why we consider two
+//    prefs and why |local_path| is preferred.
+//  * A value recommended by policy. This is a single value that applies to all
+//    root windows.
+//  * The default value for |local_path| if the value is not recommended by
+//    policy.
+std::string GetPrefForRootWindow(PrefService* pref_service,
+                                 aura::RootWindow* root_window,
+                                 const char* local_path,
+                                 const char* path) {
+  const PrefService::Preference* local_pref =
+      pref_service->FindPreference(local_path);
+  const std::string value(pref_service->GetString(local_path));
+  if (local_pref->IsManaged())
+    return value;
+
+  std::string pref_key = GetPrefKeyForRootWindow(root_window);
+  bool has_per_display_prefs = false;
+  if (!pref_key.empty()) {
+    const base::DictionaryValue* shelf_prefs = pref_service->GetDictionary(
+        prefs::kShelfPreferences);
+    const base::DictionaryValue* display_pref = NULL;
+    std::string per_display_value;
+    if (shelf_prefs->GetDictionary(pref_key, &display_pref) &&
+        display_pref->GetString(path, &per_display_value))
+      return per_display_value;
+
+    // If the pref for the specified display is not found, scan the whole prefs
+    // and check if the prefs for other display is already specified.
+    std::string unused_value;
+    for (base::DictionaryValue::Iterator iter(*shelf_prefs);
+         !iter.IsAtEnd(); iter.Advance()) {
+      const base::DictionaryValue* display_pref = NULL;
+      if (iter.value().GetAsDictionary(&display_pref) &&
+          display_pref->GetString(path, &unused_value)) {
+        has_per_display_prefs = true;
+        break;
+      }
+    }
+  }
+
+  if (local_pref->IsRecommended() || !has_per_display_prefs)
+    return value;
+
+  const base::Value* default_value =
+      pref_service->GetDefaultPrefValue(local_path);
+  std::string default_string;
+  default_value->GetAsString(&default_string);
+  return default_string;
+}
+
+// If prefs have synced and no user-set value exists at |local_path|, the value
+// from |synced_path| is copied to |local_path|.
+void MaybePropagatePrefToLocal(PrefServiceSyncable* pref_service,
+                               const char* local_path,
+                               const char* synced_path) {
+  if (!pref_service->FindPreference(local_path)->HasUserSetting() &&
+      pref_service->IsSyncing()) {
+    // First time the user is using this machine, propagate from remote to
+    // local.
+    pref_service->SetString(local_path, pref_service->GetString(synced_path));
+  }
+}
+
+}  // namespace
+
+ChromeLauncherController::ChromeLauncherController(
+    Profile* profile,
+    ash::LauncherModel* model)
+    : model_(model),
+      profile_(profile),
+      app_sync_ui_state_(NULL),
+      ignore_persist_pinned_state_change_(false) {
+  if (!profile_) {
+    // Use the original profile as on chromeos we may get a temporary off the
+    // record profile.
+    profile_ = ProfileManager::GetDefaultProfile()->GetOriginalProfile();
+
+    app_sync_ui_state_ = AppSyncUIState::Get(profile_);
+    if (app_sync_ui_state_)
+      app_sync_ui_state_->AddObserver(this);
+  }
+
+  model_->AddObserver(this);
+  BrowserList::AddObserver(this);
+  // Right now ash::Shell isn't created for tests.
+  // TODO(mukai): Allows it to observe display change and write tests.
+  if (ash::Shell::HasInstance())
+    ash::Shell::GetInstance()->display_controller()->AddObserver(this);
+  // TODO(stevenjb): Find a better owner for shell_window_controller_?
+  shell_window_controller_.reset(new ShellWindowLauncherController(this));
+  app_tab_helper_.reset(new LauncherAppTabHelper(profile_));
+  app_icon_loader_.reset(new extensions::AppIconLoaderImpl(
+      profile_, extension_misc::EXTENSION_ICON_SMALL, this));
+
+  notification_registrar_.Add(this,
+                              chrome::NOTIFICATION_EXTENSION_LOADED,
+                              content::Source<Profile>(profile_));
+  notification_registrar_.Add(this,
+                              chrome::NOTIFICATION_EXTENSION_UNLOADED,
+                              content::Source<Profile>(profile_));
+  pref_change_registrar_.Init(profile_->GetPrefs());
+  pref_change_registrar_.Add(
+      prefs::kPinnedLauncherApps,
+      base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
+                 base::Unretained(this)));
+  pref_change_registrar_.Add(
+      prefs::kShelfAlignmentLocal,
+      base::Bind(&ChromeLauncherController::SetShelfAlignmentFromPrefs,
+                 base::Unretained(this)));
+  pref_change_registrar_.Add(
+      prefs::kShelfAutoHideBehaviorLocal,
+      base::Bind(&ChromeLauncherController::
+                     SetShelfAutoHideBehaviorFromPrefs,
+                 base::Unretained(this)));
+  pref_change_registrar_.Add(
+      prefs::kShelfPreferences,
+      base::Bind(&ChromeLauncherController::SetShelfBehaviorsFromPrefs,
+                 base::Unretained(this)));
+}
+
+ChromeLauncherController::~ChromeLauncherController() {
+  // Reset the shell window controller here since it has a weak pointer to this.
+  shell_window_controller_.reset();
+
+  for (std::set<ash::Launcher*>::iterator iter = launchers_.begin();
+       iter != launchers_.end();
+       ++iter)
+    (*iter)->shelf_widget()->shelf_layout_manager()->RemoveObserver(this);
+
+  model_->RemoveObserver(this);
+  BrowserList::RemoveObserver(this);
+  if (ash::Shell::HasInstance())
+    ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
+  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
+       i != id_to_item_controller_map_.end(); ++i) {
+    i->second->OnRemoved();
+    // TODO(skuhne): After getting rid of the old launcher, get also rid of the
+    // BrowserLauncherItemController (since it is only used for activation
+    // tracking at that point.
+    int index = model_->ItemIndexByID(i->first);
+    // A "browser proxy" is not known to the model and this removal does
+    // therefore not need to be propagated to the model.
+    if (index != -1 &&
+        model_->items()[index].type != ash::TYPE_BROWSER_SHORTCUT)
+      model_->RemoveItemAt(index);
+  }
+
+  if (ash::Shell::HasInstance())
+    ash::Shell::GetInstance()->RemoveShellObserver(this);
+
+  if (app_sync_ui_state_)
+    app_sync_ui_state_->RemoveObserver(this);
+
+  PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
+
+  if (instance_ == this)
+    instance_ = NULL;
+}
+
 // static
 ChromeLauncherController* ChromeLauncherController::CreateInstance(
     Profile* profile,
@@ -19,21 +291,1368 @@
   // We do not check here for re-creation of the ChromeLauncherController since
   // it appears that it might be intentional that the ChromeLauncherController
   // can be re-created.
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          ash::switches::kAshDisablePerAppLauncher))
-    instance_ = new ChromeLauncherControllerPerApp(profile, model);
-  else
-    instance_ = new ChromeLauncherControllerPerBrowser(profile, model);
+  instance_ = new ChromeLauncherController(profile, model);
   return instance_;
 }
 
-ChromeLauncherController::~ChromeLauncherController() {
-  if (instance_ == this)
-    instance_ = NULL;
+void ChromeLauncherController::Init() {
+  UpdateAppLaunchersFromPref();
+  CreateBrowserShortcutLauncherItem();
+
+  // TODO(sky): update unit test so that this test isn't necessary.
+  if (ash::Shell::HasInstance()) {
+    SetShelfAutoHideBehaviorFromPrefs();
+    SetShelfAlignmentFromPrefs();
+    PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
+    if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() ||
+        !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)->
+            HasUserSetting()) {
+      // This causes OnIsSyncingChanged to be called when the value of
+      // PrefService::IsSyncing() changes.
+      prefs->AddObserver(this);
+    }
+    ash::Shell::GetInstance()->AddShellObserver(this);
+  }
 }
 
-bool ChromeLauncherController::IsPerAppLauncher() {
-  if (!instance_)
+ash::LauncherID ChromeLauncherController::CreateAppLauncherItem(
+    LauncherItemController* controller,
+    const std::string& app_id,
+    ash::LauncherItemStatus status) {
+  CHECK(controller);
+  int index = 0;
+  // Panels are inserted on the left so as not to push all existing panels over.
+  if (controller->GetLauncherItemType() != ash::TYPE_APP_PANEL) {
+    index = model_->item_count();
+    // For the alternate shelf layout increment the index (after the app icon)
+    if (ash::switches::UseAlternateShelfLayout())
+      ++index;
+  }
+  return InsertAppLauncherItem(controller,
+                               app_id,
+                               status,
+                               index,
+                               controller->GetLauncherItemType());
+}
+
+void ChromeLauncherController::SetItemStatus(
+    ash::LauncherID id,
+    ash::LauncherItemStatus status) {
+  int index = model_->ItemIndexByID(id);
+  // Since ordinary browser windows are not registered, we might get a negative
+  // index here.
+  if (index >= 0) {
+    ash::LauncherItem item = model_->items()[index];
+    item.status = status;
+    model_->Set(index, item);
+
+    if (model_->items()[index].type == ash::TYPE_BROWSER_SHORTCUT)
+      return;
+  }
+  UpdateBrowserItemStatus();
+}
+
+void ChromeLauncherController::SetItemController(
+    ash::LauncherID id,
+    LauncherItemController* controller) {
+  CHECK(controller);
+  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
+  CHECK(iter != id_to_item_controller_map_.end());
+  iter->second->OnRemoved();
+  iter->second = controller;
+  controller->set_launcher_id(id);
+}
+
+void ChromeLauncherController::CloseLauncherItem(ash::LauncherID id) {
+  CHECK(id);
+  if (IsPinned(id)) {
+    // Create a new shortcut controller.
+    IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
+    CHECK(iter != id_to_item_controller_map_.end());
+    SetItemStatus(id, ash::STATUS_CLOSED);
+    std::string app_id = iter->second->app_id();
+    iter->second->OnRemoved();
+    iter->second = new AppShortcutLauncherItemController(app_id, this);
+    iter->second->set_launcher_id(id);
+  } else {
+    LauncherItemClosed(id);
+  }
+}
+
+void ChromeLauncherController::Pin(ash::LauncherID id) {
+  DCHECK(HasItemController(id));
+
+  int index = model_->ItemIndexByID(id);
+  DCHECK_GE(index, 0);
+
+  ash::LauncherItem item = model_->items()[index];
+
+  if (item.type == ash::TYPE_PLATFORM_APP ||
+      item.type == ash::TYPE_WINDOWED_APP) {
+    item.type = ash::TYPE_APP_SHORTCUT;
+    model_->Set(index, item);
+  } else if (item.type != ash::TYPE_APP_SHORTCUT) {
+    return;
+  }
+
+  if (CanPin())
+    PersistPinnedState();
+}
+
+void ChromeLauncherController::Unpin(ash::LauncherID id) {
+  DCHECK(HasItemController(id));
+
+  LauncherItemController* controller = id_to_item_controller_map_[id];
+  if (controller->type() == LauncherItemController::TYPE_APP) {
+    int index = model_->ItemIndexByID(id);
+    DCHECK_GE(index, 0);
+    ash::LauncherItem item = model_->items()[index];
+    item.type = ash::TYPE_PLATFORM_APP;
+    model_->Set(index, item);
+  } else {
+    // Prevent the removal of items upon unpin if it is locked by a running
+    // windowed V1 app.
+    if (!controller->locked()) {
+      LauncherItemClosed(id);
+    } else {
+      int index = model_->ItemIndexByID(id);
+      DCHECK_GE(index, 0);
+      ash::LauncherItem item = model_->items()[index];
+      item.type = ash::TYPE_WINDOWED_APP;
+      model_->Set(index, item);
+    }
+  }
+  if (CanPin())
+    PersistPinnedState();
+}
+
+bool ChromeLauncherController::IsPinned(ash::LauncherID id) {
+  int index = model_->ItemIndexByID(id);
+  if (index < 0)
     return false;
-  return instance_->GetPerAppInterface() != NULL;
+  ash::LauncherItemType type = model_->items()[index].type;
+  return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT);
+}
+
+void ChromeLauncherController::TogglePinned(ash::LauncherID id) {
+  if (!HasItemController(id))
+    return;  // May happen if item closed with menu open.
+
+  if (IsPinned(id))
+    Unpin(id);
+  else
+    Pin(id);
+}
+
+bool ChromeLauncherController::IsPinnable(ash::LauncherID id) const {
+  int index = model_->ItemIndexByID(id);
+  if (index == -1)
+    return false;
+
+  ash::LauncherItemType type = model_->items()[index].type;
+  return ((type == ash::TYPE_APP_SHORTCUT ||
+           type == ash::TYPE_PLATFORM_APP ||
+           type == ash::TYPE_WINDOWED_APP) &&
+          CanPin());
+}
+
+void ChromeLauncherController::LockV1AppWithID(
+    const std::string& app_id) {
+  ash::LauncherID id = GetLauncherIDForAppID(app_id);
+  if (!IsPinned(id) && !IsWindowedAppInLauncher(app_id)) {
+    CreateAppShortcutLauncherItemWithType(app_id,
+                                          model_->item_count(),
+                                          ash::TYPE_WINDOWED_APP);
+    id = GetLauncherIDForAppID(app_id);
+  }
+  CHECK(id);
+  id_to_item_controller_map_[id]->lock();
+}
+
+void ChromeLauncherController::UnlockV1AppWithID(
+    const std::string& app_id) {
+  ash::LauncherID id = GetLauncherIDForAppID(app_id);
+  CHECK(IsPinned(id) || IsWindowedAppInLauncher(app_id));
+  CHECK(id);
+  LauncherItemController* controller = id_to_item_controller_map_[id];
+  controller->unlock();
+  if (!controller->locked() && !IsPinned(id))
+    CloseLauncherItem(id);
+}
+
+void ChromeLauncherController::Launch(ash::LauncherID id,
+                                            int event_flags) {
+  if (!HasItemController(id))
+    return;  // In case invoked from menu and item closed while menu up.
+  id_to_item_controller_map_[id]->Launch(event_flags);
+}
+
+void ChromeLauncherController::Close(ash::LauncherID id) {
+  if (!HasItemController(id))
+    return;  // May happen if menu closed.
+  id_to_item_controller_map_[id]->Close();
+}
+
+bool ChromeLauncherController::IsOpen(ash::LauncherID id) {
+  if (!HasItemController(id))
+    return false;
+  return id_to_item_controller_map_[id]->IsOpen();
+}
+
+bool ChromeLauncherController::IsPlatformApp(ash::LauncherID id) {
+  if (!HasItemController(id))
+    return false;
+
+  std::string app_id = GetAppIDForLauncherID(id);
+  const Extension* extension = GetExtensionForAppID(app_id);
+  // An extension can be synced / updated at any time and therefore not be
+  // available.
+  return extension ? extension->is_platform_app() : false;
+}
+
+void ChromeLauncherController::LaunchApp(const std::string& app_id,
+                                               int event_flags) {
+  // |extension| could be NULL when it is being unloaded for updating.
+  const Extension* extension = GetExtensionForAppID(app_id);
+  if (!extension)
+    return;
+
+  const ExtensionService* service =
+      extensions::ExtensionSystem::Get(profile_)->extension_service();
+  if (!service->IsExtensionEnabledForLauncher(app_id)) {
+    // Do nothing if there is already a running enable flow.
+    if (extension_enable_flow_)
+      return;
+
+    extension_enable_flow_.reset(
+        new ExtensionEnableFlow(profile_, app_id, this));
+    extension_enable_flow_->StartForNativeWindow(NULL);
+    return;
+  }
+
+  chrome::OpenApplication(chrome::AppLaunchParams(GetProfileForNewWindows(),
+                                                  extension,
+                                                  event_flags));
+}
+
+void ChromeLauncherController::ActivateApp(const std::string& app_id,
+                                                 int event_flags) {
+  // If there is an existing non-shortcut controller for this app, open it.
+  ash::LauncherID id = GetLauncherIDForAppID(app_id);
+  if (id) {
+    LauncherItemController* controller = id_to_item_controller_map_[id];
+    controller->Activate();
+    return;
+  }
+
+  // Create a temporary application launcher item and use it to see if there are
+  // running instances.
+  scoped_ptr<AppShortcutLauncherItemController> app_controller(
+      new AppShortcutLauncherItemController(app_id, this));
+  if (!app_controller->GetRunningApplications().empty())
+    app_controller->Activate();
+  else
+    LaunchApp(app_id, event_flags);
+}
+
+extensions::ExtensionPrefs::LaunchType
+    ChromeLauncherController::GetLaunchType(ash::LauncherID id) {
+  DCHECK(HasItemController(id));
+
+  const Extension* extension = GetExtensionForAppID(
+      id_to_item_controller_map_[id]->app_id());
+
+  // An extension can be unloaded/updated/unavailable at any time.
+  if (!extension)
+    return extensions::ExtensionPrefs::LAUNCH_DEFAULT;
+
+  return profile_->GetExtensionService()->extension_prefs()->GetLaunchType(
+      extension,
+      extensions::ExtensionPrefs::LAUNCH_DEFAULT);
+}
+
+std::string ChromeLauncherController::GetAppID(content::WebContents* tab) {
+  return app_tab_helper_->GetAppID(tab);
+}
+
+ash::LauncherID ChromeLauncherController::GetLauncherIDForAppID(
+    const std::string& app_id) {
+  for (IDToItemControllerMap::const_iterator i =
+           id_to_item_controller_map_.begin();
+       i != id_to_item_controller_map_.end(); ++i) {
+    if (i->second->type() == LauncherItemController::TYPE_APP_PANEL)
+      continue;  // Don't include panels
+    if (i->second->app_id() == app_id)
+      return i->first;
+  }
+  return 0;
+}
+
+std::string ChromeLauncherController::GetAppIDForLauncherID(
+    ash::LauncherID id) {
+  CHECK(HasItemController(id));
+  return id_to_item_controller_map_[id]->app_id();
+}
+
+void ChromeLauncherController::SetAppImage(const std::string& id,
+                                           const gfx::ImageSkia& image) {
+  // TODO: need to get this working for shortcuts.
+
+  for (IDToItemControllerMap::const_iterator i =
+           id_to_item_controller_map_.begin();
+       i != id_to_item_controller_map_.end(); ++i) {
+    LauncherItemController* controller = i->second;
+    if (controller->app_id() != id)
+      continue;
+    if (controller->image_set_by_controller())
+      continue;
+    int index = model_->ItemIndexByID(i->first);
+    if (index == -1)
+      continue;
+    ash::LauncherItem item = model_->items()[index];
+    item.image = image;
+    model_->Set(index, item);
+    // It's possible we're waiting on more than one item, so don't break.
+  }
+}
+
+void ChromeLauncherController::OnAutoHideBehaviorChanged(
+    aura::RootWindow* root_window,
+    ash::ShelfAutoHideBehavior new_behavior) {
+  SetShelfAutoHideBehaviorPrefs(new_behavior, root_window);
+}
+
+void ChromeLauncherController::SetLauncherItemImage(
+    ash::LauncherID launcher_id,
+    const gfx::ImageSkia& image) {
+  int index = model_->ItemIndexByID(launcher_id);
+  if (index == -1)
+    return;
+  ash::LauncherItem item = model_->items()[index];
+  item.image = image;
+  model_->Set(index, item);
+}
+
+bool ChromeLauncherController::IsAppPinned(const std::string& app_id) {
+  for (IDToItemControllerMap::const_iterator i =
+           id_to_item_controller_map_.begin();
+       i != id_to_item_controller_map_.end(); ++i) {
+    if (IsPinned(i->first) && i->second->app_id() == app_id)
+      return true;
+  }
+  return false;
+}
+
+bool ChromeLauncherController::IsWindowedAppInLauncher(
+    const std::string& app_id) {
+  int index = model_->ItemIndexByID(GetLauncherIDForAppID(app_id));
+  if (index < 0)
+    return false;
+
+  ash::LauncherItemType type = model_->items()[index].type;
+  return type == ash::TYPE_WINDOWED_APP;
+}
+
+void ChromeLauncherController::PinAppWithID(const std::string& app_id) {
+  if (CanPin())
+    DoPinAppWithID(app_id);
+  else
+    NOTREACHED();
+}
+
+void ChromeLauncherController::SetLaunchType(
+    ash::LauncherID id,
+    extensions::ExtensionPrefs::LaunchType launch_type) {
+  if (!HasItemController(id))
+    return;
+
+  profile_->GetExtensionService()->extension_prefs()->SetLaunchType(
+      id_to_item_controller_map_[id]->app_id(), launch_type);
+}
+
+void ChromeLauncherController::UnpinAppsWithID(const std::string& app_id) {
+  if (CanPin())
+    DoUnpinAppsWithID(app_id);
+  else
+    NOTREACHED();
+}
+
+bool ChromeLauncherController::IsLoggedInAsGuest() {
+  return ProfileManager::GetDefaultProfileOrOffTheRecord()->IsOffTheRecord();
+}
+
+void ChromeLauncherController::CreateNewWindow() {
+  chrome::NewEmptyWindow(
+      GetProfileForNewWindows(), chrome::HOST_DESKTOP_TYPE_ASH);
+}
+
+void ChromeLauncherController::CreateNewIncognitoWindow() {
+  chrome::NewEmptyWindow(GetProfileForNewWindows()->GetOffTheRecordProfile(),
+                         chrome::HOST_DESKTOP_TYPE_ASH);
+}
+
+bool ChromeLauncherController::CanPin() const {
+  const PrefService::Preference* pref =
+      profile_->GetPrefs()->FindPreference(prefs::kPinnedLauncherApps);
+  return pref && pref->IsUserModifiable();
+}
+
+void ChromeLauncherController::PersistPinnedState() {
+  if (ignore_persist_pinned_state_change_)
+    return;
+  // It is a coding error to call PersistPinnedState() if the pinned apps are
+  // not user-editable. The code should check earlier and not perform any
+  // modification actions that trigger persisting the state.
+  if (!CanPin()) {
+    NOTREACHED() << "Can't pin but pinned state being updated";
+    return;
+  }
+
+  // Mutating kPinnedLauncherApps is going to notify us and trigger us to
+  // process the change. We don't want that to happen so remove ourselves as a
+  // listener.
+  pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
+  {
+    ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
+    updater->Clear();
+    for (size_t i = 0; i < model_->items().size(); ++i) {
+      if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
+        ash::LauncherID id = model_->items()[i].id;
+        if (HasItemController(id) && IsPinned(id)) {
+          base::DictionaryValue* app_value = ash::CreateAppDict(
+              id_to_item_controller_map_[id]->app_id());
+          if (app_value)
+            updater->Append(app_value);
+        }
+      } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) {
+        PersistChromeItemIndex(i);
+      }
+    }
+  }
+  pref_change_registrar_.Add(
+      prefs::kPinnedLauncherApps,
+      base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
+                 base::Unretained(this)));
+}
+
+ash::LauncherModel* ChromeLauncherController::model() {
+  return model_;
+}
+
+Profile* ChromeLauncherController::profile() {
+  return profile_;
+}
+
+ash::ShelfAutoHideBehavior ChromeLauncherController::GetShelfAutoHideBehavior(
+    aura::RootWindow* root_window) const {
+  // Don't show the shelf in app mode.
+  if (chrome::IsRunningInAppMode())
+    return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
+
+  // See comment in |kShelfAlignment| as to why we consider two prefs.
+  const std::string behavior_value(
+      GetPrefForRootWindow(profile_->GetPrefs(),
+                           root_window,
+                           prefs::kShelfAutoHideBehaviorLocal,
+                           prefs::kShelfAutoHideBehavior));
+
+  // Note: To maintain sync compatibility with old images of chrome/chromeos
+  // the set of values that may be encountered includes the now-extinct
+  // "Default" as well as "Never" and "Always", "Default" should now
+  // be treated as "Never" (http://crbug.com/146773).
+  if (behavior_value == ash::kShelfAutoHideBehaviorAlways)
+    return ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
+  return ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER;
+}
+
+bool ChromeLauncherController::CanUserModifyShelfAutoHideBehavior(
+    aura::RootWindow* root_window) const {
+  return profile_->GetPrefs()->
+      FindPreference(prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
+}
+
+void ChromeLauncherController::ToggleShelfAutoHideBehavior(
+    aura::RootWindow* root_window) {
+  ash::ShelfAutoHideBehavior behavior = GetShelfAutoHideBehavior(root_window) ==
+      ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS ?
+          ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER :
+          ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
+  SetShelfAutoHideBehaviorPrefs(behavior, root_window);
+  return;
+}
+
+void ChromeLauncherController::RemoveTabFromRunningApp(
+    WebContents* tab,
+    const std::string& app_id) {
+  web_contents_to_app_id_.erase(tab);
+  AppIDToWebContentsListMap::iterator i_app_id =
+      app_id_to_web_contents_list_.find(app_id);
+  if (i_app_id != app_id_to_web_contents_list_.end()) {
+    WebContentsList* tab_list = &i_app_id->second;
+    tab_list->remove(tab);
+    if (tab_list->empty()) {
+      app_id_to_web_contents_list_.erase(i_app_id);
+      i_app_id = app_id_to_web_contents_list_.end();
+      ash::LauncherID id = GetLauncherIDForAppID(app_id);
+      if (id)
+        SetItemStatus(id, ash::STATUS_CLOSED);
+    }
+  }
+}
+
+void ChromeLauncherController::UpdateAppState(content::WebContents* contents,
+                                              AppState app_state) {
+  std::string app_id = GetAppID(contents);
+
+  // Check if the gMail app is loaded and it matches the given content.
+  // This special treatment is needed to address crbug.com/234268.
+  if (app_id.empty() && ContentCanBeHandledByGmailApp(contents))
+    app_id = kGmailAppId;
+
+  // Check the old |app_id| for a tab. If the contents has changed we need to
+  // remove it from the previous app.
+  if (web_contents_to_app_id_.find(contents) != web_contents_to_app_id_.end()) {
+    std::string last_app_id = web_contents_to_app_id_[contents];
+    if (last_app_id != app_id)
+      RemoveTabFromRunningApp(contents, last_app_id);
+  }
+
+  if (app_id.empty()) {
+    // Even if there is no application running, we should update the activation
+    // state of the associated browser.
+    UpdateBrowserItemStatus();
+    return;
+  }
+
+  web_contents_to_app_id_[contents] = app_id;
+
+  if (app_state == APP_STATE_REMOVED) {
+    // The tab has gone away.
+    RemoveTabFromRunningApp(contents, app_id);
+  } else {
+    WebContentsList& tab_list(app_id_to_web_contents_list_[app_id]);
+
+    if (app_state == APP_STATE_INACTIVE) {
+      WebContentsList::const_iterator i_tab =
+          std::find(tab_list.begin(), tab_list.end(), contents);
+      if (i_tab == tab_list.end())
+        tab_list.push_back(contents);
+      if (i_tab != tab_list.begin()) {
+        // Going inactive, but wasn't the front tab, indicating that a new
+        // tab has already become active.
+        return;
+      }
+    } else {
+      tab_list.remove(contents);
+      tab_list.push_front(contents);
+    }
+    ash::LauncherID id = GetLauncherIDForAppID(app_id);
+    if (id) {
+      // If the window is active, mark the app as active.
+      SetItemStatus(id, app_state == APP_STATE_WINDOW_ACTIVE ?
+          ash::STATUS_ACTIVE : ash::STATUS_RUNNING);
+    }
+  }
+  UpdateBrowserItemStatus();
+}
+
+void ChromeLauncherController::SetRefocusURLPatternForTest(ash::LauncherID id,
+                                                           const GURL& url) {
+  DCHECK(HasItemController(id));
+  LauncherItemController* controller = id_to_item_controller_map_[id];
+
+  int index = model_->ItemIndexByID(id);
+  if (index == -1) {
+    NOTREACHED() << "Invalid launcher id";
+    return;
+  }
+
+  ash::LauncherItemType type = model_->items()[index].type;
+  if (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_WINDOWED_APP) {
+    AppShortcutLauncherItemController* app_controller =
+        static_cast<AppShortcutLauncherItemController*>(controller);
+    app_controller->set_refocus_url(url);
+  } else {
+    NOTREACHED() << "Invalid launcher type";
+  }
+}
+
+const Extension* ChromeLauncherController::GetExtensionForAppID(
+    const std::string& app_id) const {
+  // Some unit tests do not have a real extension.
+  return (profile_->GetExtensionService()) ?
+      profile_->GetExtensionService()->GetInstalledExtension(app_id) : NULL;
+}
+
+void ChromeLauncherController::ActivateWindowOrMinimizeIfActive(
+    ui::BaseWindow* window,
+    bool allow_minimize) {
+  if (window->IsActive() && allow_minimize) {
+    if (CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kDisableMinimizeOnSecondLauncherItemClick)) {
+      AnimateWindow(window->GetNativeWindow(),
+                    views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
+    } else {
+      window->Minimize();
+    }
+  } else {
+    window->Show();
+    window->Activate();
+  }
+}
+
+void ChromeLauncherController::ItemSelected(const ash::LauncherItem& item,
+                                            const ui::Event& event) {
+  DCHECK(HasItemController(item.id));
+  LauncherItemController* item_controller = id_to_item_controller_map_[item.id];
+#if defined(OS_CHROMEOS)
+  if (!item_controller->app_id().empty()) {
+    chromeos::default_pinned_apps_field_trial::RecordShelfAppClick(
+        item_controller->app_id());
+  }
+#endif
+  item_controller->Clicked(event);
+}
+
+string16 ChromeLauncherController::GetTitle(const ash::LauncherItem& item) {
+  DCHECK(HasItemController(item.id));
+  return id_to_item_controller_map_[item.id]->GetTitle();
+}
+
+ui::MenuModel* ChromeLauncherController::CreateContextMenu(
+    const ash::LauncherItem& item,
+    aura::RootWindow* root_window) {
+  return new LauncherContextMenu(this, &item, root_window);
+}
+
+ash::LauncherMenuModel* ChromeLauncherController::CreateApplicationMenu(
+    const ash::LauncherItem& item,
+    int event_flags) {
+  return new LauncherApplicationMenuItemModel(GetApplicationList(item,
+                                                                 event_flags));
+}
+
+ash::LauncherID ChromeLauncherController::GetIDByWindow(aura::Window* window) {
+  int browser_index = ash::launcher::GetBrowserItemIndex(*model_);
+  DCHECK_GE(browser_index, 0);
+  ash::LauncherID browser_id = model_->items()[browser_index].id;
+
+  IDToItemControllerMap::const_iterator i = id_to_item_controller_map_.begin();
+  for (; i != id_to_item_controller_map_.end(); ++i) {
+    // Since a |window| can be used by multiple applications, an explicit
+    // application always gets chosen over the generic browser.
+    if (i->first != browser_id && i->second->IsCurrentlyShownInWindow(window))
+      return i->first;
+  }
+
+  if (i == id_to_item_controller_map_.end() &&
+      GetBrowserShortcutLauncherItemController()->
+          IsCurrentlyShownInWindow(window))
+    return browser_id;
+
+  return 0;
+}
+
+bool ChromeLauncherController::IsDraggable(const ash::LauncherItem& item) {
+  return (item.type == ash::TYPE_APP_SHORTCUT ||
+          item.type == ash::TYPE_WINDOWED_APP) ? CanPin() : true;
+}
+
+bool ChromeLauncherController::ShouldShowTooltip(
+    const ash::LauncherItem& item) {
+  if (item.type == ash::TYPE_APP_PANEL &&
+      id_to_item_controller_map_[item.id]->IsVisible())
+    return false;
+  return true;
+}
+
+void ChromeLauncherController::OnLauncherCreated(ash::Launcher* launcher) {
+  launchers_.insert(launcher);
+  launcher->shelf_widget()->shelf_layout_manager()->AddObserver(this);
+}
+
+void ChromeLauncherController::OnLauncherDestroyed(ash::Launcher* launcher) {
+  launchers_.erase(launcher);
+  // RemoveObserver is not called here, since by the time this method is called
+  // Launcher is already in its destructor.
+}
+
+void ChromeLauncherController::LauncherItemAdded(int index) {
+}
+
+void ChromeLauncherController::LauncherItemRemoved(int index,
+                                                   ash::LauncherID id) {
+}
+
+void ChromeLauncherController::LauncherItemMoved(int start_index,
+                                                 int target_index) {
+  ash::LauncherID id = model_->items()[target_index].id;
+  if (HasItemController(id) && IsPinned(id))
+    PersistPinnedState();
+}
+
+void ChromeLauncherController::LauncherItemChanged(
+    int index,
+    const ash::LauncherItem& old_item) {
+  ash::LauncherID id = model_->items()[index].id;
+  DCHECK(HasItemController(id));
+  id_to_item_controller_map_[id]->LauncherItemChanged(index, old_item);
+}
+
+void ChromeLauncherController::LauncherStatusChanged() {
+}
+
+void ChromeLauncherController::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();
+      if (IsAppPinned(extension->id())) {
+        // Clear and re-fetch to ensure icon is up-to-date.
+        app_icon_loader_->ClearImage(extension->id());
+        app_icon_loader_->FetchImage(extension->id());
+      }
+
+      UpdateAppLaunchersFromPref();
+      break;
+    }
+    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
+      const content::Details<extensions::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) {
+        CloseWindowedAppsFromRemovedExtension(id);
+      }
+
+      if (IsAppPinned(id)) {
+        if (unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
+          DoUnpinAppsWithID(id);
+          app_icon_loader_->ClearImage(id);
+        } else {
+          app_icon_loader_->UpdateImage(id);
+        }
+      }
+      break;
+    }
+    default:
+      NOTREACHED() << "Unexpected notification type=" << type;
+  }
+}
+
+void ChromeLauncherController::OnShelfAlignmentChanged(
+    aura::RootWindow* root_window) {
+  const char* pref_value = NULL;
+  switch (ash::Shell::GetInstance()->GetShelfAlignment(root_window)) {
+    case ash::SHELF_ALIGNMENT_BOTTOM:
+      pref_value = ash::kShelfAlignmentBottom;
+      break;
+    case ash::SHELF_ALIGNMENT_LEFT:
+      pref_value = ash::kShelfAlignmentLeft;
+      break;
+    case ash::SHELF_ALIGNMENT_RIGHT:
+      pref_value = ash::kShelfAlignmentRight;
+      break;
+    case ash::SHELF_ALIGNMENT_TOP:
+      pref_value = ash::kShelfAlignmentTop;
+  }
+
+  UpdatePerDisplayPref(
+      profile_->GetPrefs(), root_window, prefs::kShelfAlignment, pref_value);
+
+  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
+    // See comment in |kShelfAlignment| about why we have two prefs here.
+    profile_->GetPrefs()->SetString(prefs::kShelfAlignmentLocal, pref_value);
+    profile_->GetPrefs()->SetString(prefs::kShelfAlignment, pref_value);
+  }
+}
+
+void ChromeLauncherController::OnDisplayConfigurationChanging() {
+}
+
+void ChromeLauncherController::OnDisplayConfigurationChanged() {
+  SetShelfBehaviorsFromPrefs();
+}
+
+void ChromeLauncherController::OnIsSyncingChanged() {
+  PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
+  MaybePropagatePrefToLocal(prefs,
+                            prefs::kShelfAlignmentLocal,
+                            prefs::kShelfAlignment);
+  MaybePropagatePrefToLocal(prefs,
+                            prefs::kShelfAutoHideBehaviorLocal,
+                            prefs::kShelfAutoHideBehavior);
+}
+
+void ChromeLauncherController::OnAppSyncUIStatusChanged() {
+  if (app_sync_ui_state_->status() == AppSyncUIState::STATUS_SYNCING)
+    model_->SetStatus(ash::LauncherModel::STATUS_LOADING);
+  else
+    model_->SetStatus(ash::LauncherModel::STATUS_NORMAL);
+}
+
+void ChromeLauncherController::ExtensionEnableFlowFinished() {
+  LaunchApp(extension_enable_flow_->extension_id(), ui::EF_NONE);
+  extension_enable_flow_.reset();
+}
+
+void ChromeLauncherController::ExtensionEnableFlowAborted(bool user_initiated) {
+  extension_enable_flow_.reset();
+}
+
+ChromeLauncherAppMenuItems ChromeLauncherController::GetApplicationList(
+    const ash::LauncherItem& item,
+    int event_flags) {
+  // Make sure that there is a controller associated with the id and that the
+  // extension itself is a valid application and not a panel.
+  if (!HasItemController(item.id) ||
+      !GetLauncherIDForAppID(id_to_item_controller_map_[item.id]->app_id()))
+    return ChromeLauncherAppMenuItems().Pass();
+
+  return id_to_item_controller_map_[item.id]->GetApplicationList(event_flags);
+}
+
+std::vector<content::WebContents*>
+ChromeLauncherController::GetV1ApplicationsFromAppId(std::string app_id) {
+  ash::LauncherID id = GetLauncherIDForAppID(app_id);
+
+  // If there is no such an item pinned to the launcher, no menu gets created.
+  if (id) {
+    LauncherItemController* controller = id_to_item_controller_map_[id];
+    DCHECK(controller);
+    if (controller->type() == LauncherItemController::TYPE_SHORTCUT)
+      return GetV1ApplicationsFromController(controller);
+  }
+  return std::vector<content::WebContents*>();
+}
+
+void ChromeLauncherController::ActivateShellApp(const std::string& app_id,
+                                                int index) {
+  ash::LauncherID id = GetLauncherIDForAppID(app_id);
+  if (id) {
+    LauncherItemController* controller = id_to_item_controller_map_[id];
+    if (controller->type() == LauncherItemController::TYPE_APP) {
+      ShellWindowLauncherItemController* shell_window_controller =
+          static_cast<ShellWindowLauncherItemController*>(controller);
+      shell_window_controller->ActivateIndexedApp(index);
+    }
+  }
+}
+
+bool ChromeLauncherController::IsWebContentHandledByApplication(
+    content::WebContents* web_contents,
+    const std::string& app_id) {
+  if ((web_contents_to_app_id_.find(web_contents) !=
+       web_contents_to_app_id_.end()) &&
+      (web_contents_to_app_id_[web_contents] == app_id))
+    return true;
+  return (app_id == kGmailAppId && ContentCanBeHandledByGmailApp(web_contents));
+}
+
+bool ChromeLauncherController::ContentCanBeHandledByGmailApp(
+    content::WebContents* web_contents) {
+  ash::LauncherID id = GetLauncherIDForAppID(kGmailAppId);
+  if (id) {
+    const GURL url = web_contents->GetURL();
+    // We need to extend the application matching for the gMail app beyond the
+    // manifest file's specification. This is required because of the namespace
+    // overlap with the offline app ("/mail/mu/").
+    if (!MatchPattern(url.path(), "/mail/mu/*") &&
+        MatchPattern(url.path(), "/mail/*") &&
+        GetExtensionForAppID(kGmailAppId) &&
+        GetExtensionForAppID(kGmailAppId)->OverlapsWithOrigin(url))
+      return true;
+  }
+  return false;
+}
+
+gfx::Image ChromeLauncherController::GetAppListIcon(
+    content::WebContents* web_contents) const {
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  if (IsIncognito(web_contents))
+    return rb.GetImageNamed(IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER);
+  FaviconTabHelper* favicon_tab_helper =
+      FaviconTabHelper::FromWebContents(web_contents);
+  gfx::Image result = favicon_tab_helper->GetFavicon();
+  if (result.IsEmpty())
+    return rb.GetImageNamed(IDR_DEFAULT_FAVICON);
+  return result;
+}
+
+string16 ChromeLauncherController::GetAppListTitle(
+    content::WebContents* web_contents) const {
+  string16 title = web_contents->GetTitle();
+  if (!title.empty())
+    return title;
+  WebContentsToAppIDMap::const_iterator iter =
+      web_contents_to_app_id_.find(web_contents);
+  if (iter != web_contents_to_app_id_.end()) {
+    std::string app_id = iter->second;
+    const extensions::Extension* extension = GetExtensionForAppID(app_id);
+    if (extension)
+      return UTF8ToUTF16(extension->name());
+  }
+  return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
+}
+
+void ChromeLauncherController::OnBrowserRemoved(Browser* browser) {
+  // When called by a unit test it is possible that there is no shell.
+  // In that case, the following function should not get called.
+  if (ash::Shell::HasInstance())
+    UpdateBrowserItemStatus();
+}
+
+ash::LauncherID ChromeLauncherController::CreateAppShortcutLauncherItem(
+    const std::string& app_id,
+    int index) {
+  return CreateAppShortcutLauncherItemWithType(app_id,
+                                               index,
+                                               ash::TYPE_APP_SHORTCUT);
+}
+
+void ChromeLauncherController::SetAppTabHelperForTest(AppTabHelper* helper) {
+  app_tab_helper_.reset(helper);
+}
+
+void ChromeLauncherController::SetAppIconLoaderForTest(
+    extensions::AppIconLoader* loader) {
+  app_icon_loader_.reset(loader);
+}
+
+const std::string& ChromeLauncherController::GetAppIdFromLauncherIdForTest(
+    ash::LauncherID id) {
+  return id_to_item_controller_map_[id]->app_id();
+}
+
+ash::LauncherID ChromeLauncherController::CreateAppShortcutLauncherItemWithType(
+    const std::string& app_id,
+    int index,
+    ash::LauncherItemType launcher_item_type) {
+  AppShortcutLauncherItemController* controller =
+      new AppShortcutLauncherItemController(app_id, this);
+  ash::LauncherID launcher_id = InsertAppLauncherItem(
+      controller, app_id, ash::STATUS_CLOSED, index, launcher_item_type);
+  return launcher_id;
+}
+
+void ChromeLauncherController::UpdateBrowserItemStatus() {
+  // Determine the new browser's active state and change if necessary.
+  size_t browser_index = ash::launcher::GetBrowserItemIndex(*model_);
+  DCHECK_GE(browser_index, 0u);
+  ash::LauncherItem browser_item = model_->items()[browser_index];
+  ash::LauncherItemStatus browser_status = ash::STATUS_CLOSED;
+
+  aura::Window* window = ash::wm::GetActiveWindow();
+  if (window) {
+    // Check if the active browser / tab is a browser which is not an app,
+    // a windowed app, a popup or any other item which is not a browser of
+    // interest.
+    Browser* browser = chrome::FindBrowserWithWindow(window);
+    if (IsBrowserRepresentedInBrowserList(browser)) {
+      browser_status = ash::STATUS_ACTIVE;
+      const ash::LauncherItems& items = model_->items();
+      // If another launcher item has claimed to be active, we don't.
+      for (size_t i = 0;
+           i < items.size() && browser_status == ash::STATUS_ACTIVE; ++i) {
+        if (i != browser_index && items[i].status == ash::STATUS_ACTIVE)
+          browser_status = ash::STATUS_RUNNING;
+      }
+    }
+  }
+
+  if (browser_status == ash::STATUS_CLOSED) {
+    const BrowserList* ash_browser_list =
+        BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
+    for (BrowserList::const_reverse_iterator it =
+             ash_browser_list->begin_last_active();
+         it != ash_browser_list->end_last_active() &&
+         browser_status == ash::STATUS_CLOSED; ++it) {
+      if (IsBrowserRepresentedInBrowserList(*it))
+        browser_status = ash::STATUS_RUNNING;
+    }
+  }
+
+  if (browser_status != browser_item.status) {
+    browser_item.status = browser_status;
+    model_->Set(browser_index, browser_item);
+  }
+}
+
+Profile* ChromeLauncherController::GetProfileForNewWindows() {
+  return ProfileManager::GetDefaultProfileOrOffTheRecord();
+}
+
+void ChromeLauncherController::LauncherItemClosed(ash::LauncherID id) {
+  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
+  CHECK(iter != id_to_item_controller_map_.end());
+  CHECK(iter->second);
+  app_icon_loader_->ClearImage(iter->second->app_id());
+  iter->second->OnRemoved();
+  id_to_item_controller_map_.erase(iter);
+  int index = model_->ItemIndexByID(id);
+  // A "browser proxy" is not known to the model and this removal does
+  // therefore not need to be propagated to the model.
+  if (index != -1)
+    model_->RemoveItemAt(index);
+}
+
+void ChromeLauncherController::DoPinAppWithID(const std::string& app_id) {
+  // If there is an item, do nothing and return.
+  if (IsAppPinned(app_id))
+    return;
+
+  ash::LauncherID launcher_id = GetLauncherIDForAppID(app_id);
+  if (launcher_id) {
+    // App item exists, pin it
+    Pin(launcher_id);
+  } else {
+    // Otherwise, create a shortcut item for it.
+    CreateAppShortcutLauncherItem(app_id, model_->item_count());
+    if (CanPin())
+      PersistPinnedState();
+  }
+}
+
+void ChromeLauncherController::DoUnpinAppsWithID(const std::string& app_id) {
+  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
+       i != id_to_item_controller_map_.end(); ) {
+    IDToItemControllerMap::iterator current(i);
+    ++i;
+    if (current->second->app_id() == app_id && IsPinned(current->first))
+      Unpin(current->first);
+  }
+}
+
+void ChromeLauncherController::UpdateAppLaunchersFromPref() {
+  // Construct a vector representation of to-be-pinned apps from the pref.
+  std::vector<std::string> pinned_apps;
+  int chrome_icon_index = GetChromeIconIndexFromPref();
+  int index = 0;
+  int max_index = model_->item_count();
+  // Using the alternate shelf layout the App Icon should be the first item in
+  // the list thus start adding items at slot 1 (instead of slot 0).
+  if (ash::switches::UseAlternateShelfLayout()) {
+    ++index;
+    ++max_index;
+    // The alternate shelf layout's icon position will always include the
+    // AppLauncher which needs to be subtracted here.
+    if (chrome_icon_index > 0)
+      --chrome_icon_index;
+  }
+  const base::ListValue* pinned_apps_pref =
+      profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
+  for (base::ListValue::const_iterator it(pinned_apps_pref->begin());
+       it != pinned_apps_pref->end(); ++it) {
+    // To preserve the Chrome icon position, we insert a dummy slot for it - if
+    // the model has a Chrome item. While initializing we can come here with no
+    // item in which case the count would be 1 or below.
+    if (it - pinned_apps_pref->begin() == chrome_icon_index &&
+        model_->item_count() > 1) {
+      pinned_apps.push_back(extension_misc::kChromeAppId);
+    }
+
+    DictionaryValue* app = NULL;
+    std::string app_id;
+    if ((*it)->GetAsDictionary(&app) &&
+        app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) &&
+        std::find(pinned_apps.begin(), pinned_apps.end(), app_id) ==
+            pinned_apps.end() &&
+        app_tab_helper_->IsValidID(app_id)) {
+      pinned_apps.push_back(app_id);
+    }
+  }
+
+  // Walk the model and |pinned_apps| from the pref lockstep, adding and
+  // removing items as necessary. NB: This code uses plain old indexing instead
+  // of iterators because of model mutations as part of the loop.
+  std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
+  for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
+    // If the next app launcher according to the pref is present in the model,
+    // delete all app launcher entries in between.
+    if (*pref_app_id == extension_misc::kChromeAppId ||
+        IsAppPinned(*pref_app_id)) {
+      for (; index < max_index; ++index) {
+        const ash::LauncherItem& item(model_->items()[index]);
+        if (item.type != ash::TYPE_APP_SHORTCUT &&
+            item.type != ash::TYPE_BROWSER_SHORTCUT)
+          continue;
+
+        IDToItemControllerMap::const_iterator entry =
+            id_to_item_controller_map_.find(item.id);
+        if ((extension_misc::kChromeAppId == *pref_app_id &&
+             item.type == ash::TYPE_BROWSER_SHORTCUT) ||
+            (entry != id_to_item_controller_map_.end() &&
+             entry->second->app_id() == *pref_app_id)) {
+          ++pref_app_id;
+          break;
+        } else {
+          if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
+            // We cannot delete the browser shortcut. As such we move it up by
+            // one. To avoid any side effects from our pinned state observer, we
+            // do not call the model directly.
+            MoveItemWithoutPinnedStateChangeNotification(index, index + 1);
+          } else {
+            LauncherItemClosed(item.id);
+            --max_index;
+          }
+          --index;
+        }
+      }
+      // If the item wasn't found, that means id_to_item_controller_map_
+      // is out of sync.
+      DCHECK(index < max_index);
+    } else {
+      // This app wasn't pinned before, insert a new entry.
+      ash::LauncherID id = CreateAppShortcutLauncherItem(*pref_app_id, index);
+      index = model_->ItemIndexByID(id);
+      ++pref_app_id;
+    }
+  }
+
+  // Remove any trailing existing items.
+  while (index < model_->item_count()) {
+    const ash::LauncherItem& item(model_->items()[index]);
+    if (item.type == ash::TYPE_APP_SHORTCUT)
+      LauncherItemClosed(item.id);
+    else
+      ++index;
+  }
+
+  // Append unprocessed items from the pref to the end of the model.
+  for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
+    // Ignore the chrome icon.
+    if (*pref_app_id != extension_misc::kChromeAppId)
+      DoPinAppWithID(*pref_app_id);
+  }
+
+}
+
+void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs(
+    ash::ShelfAutoHideBehavior behavior,
+    aura::RootWindow* root_window) {
+  const char* value = NULL;
+  switch (behavior) {
+    case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
+      value = ash::kShelfAutoHideBehaviorAlways;
+      break;
+    case ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
+      value = ash::kShelfAutoHideBehaviorNever;
+      break;
+    case ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
+      // This one should not be a valid preference option for now. We only want
+      // to completely hide it when we run app mode.
+      NOTREACHED();
+      return;
+  }
+
+  UpdatePerDisplayPref(
+      profile_->GetPrefs(), root_window, prefs::kShelfAutoHideBehavior, value);
+
+  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
+    // See comment in |kShelfAlignment| about why we have two prefs here.
+    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehaviorLocal, value);
+    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehavior, value);
+  }
+}
+
+void ChromeLauncherController::SetShelfAutoHideBehaviorFromPrefs() {
+  ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
+
+  for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
+       iter != root_windows.end(); ++iter) {
+    ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
+        GetShelfAutoHideBehavior(*iter), *iter);
+  }
+}
+
+void ChromeLauncherController::SetShelfAlignmentFromPrefs() {
+  if (!ash::ShelfWidget::ShelfAlignmentAllowed())
+    return;
+
+  ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
+
+  for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
+       iter != root_windows.end(); ++iter) {
+    // See comment in |kShelfAlignment| as to why we consider two prefs.
+    const std::string alignment_value(
+        GetPrefForRootWindow(profile_->GetPrefs(),
+                             *iter,
+                             prefs::kShelfAlignmentLocal,
+                             prefs::kShelfAlignment));
+    ash::ShelfAlignment alignment = ash::SHELF_ALIGNMENT_BOTTOM;
+    if (alignment_value == ash::kShelfAlignmentLeft)
+      alignment = ash::SHELF_ALIGNMENT_LEFT;
+    else if (alignment_value == ash::kShelfAlignmentRight)
+      alignment = ash::SHELF_ALIGNMENT_RIGHT;
+    else if (alignment_value == ash::kShelfAlignmentTop)
+      alignment = ash::SHELF_ALIGNMENT_TOP;
+    ash::Shell::GetInstance()->SetShelfAlignment(alignment, *iter);
+  }
+}
+
+void ChromeLauncherController::SetShelfBehaviorsFromPrefs() {
+  SetShelfAutoHideBehaviorFromPrefs();
+  SetShelfAlignmentFromPrefs();
+}
+
+WebContents* ChromeLauncherController::GetLastActiveWebContents(
+    const std::string& app_id) {
+  AppIDToWebContentsListMap::const_iterator i =
+      app_id_to_web_contents_list_.find(app_id);
+  if (i == app_id_to_web_contents_list_.end())
+    return NULL;
+  DCHECK_GT(i->second.size(), 0u);
+  return *i->second.begin();
+}
+
+ash::LauncherID ChromeLauncherController::InsertAppLauncherItem(
+    LauncherItemController* controller,
+    const std::string& app_id,
+    ash::LauncherItemStatus status,
+    int index,
+    ash::LauncherItemType launcher_item_type) {
+  ash::LauncherID id = model_->next_id();
+  CHECK(!HasItemController(id));
+  CHECK(controller);
+  id_to_item_controller_map_[id] = controller;
+  controller->set_launcher_id(id);
+
+  ash::LauncherItem item;
+  item.type = launcher_item_type;
+  item.is_incognito = false;
+  item.image = extensions::IconsInfo::GetDefaultAppIcon();
+
+  WebContents* active_tab = GetLastActiveWebContents(app_id);
+  if (active_tab) {
+    Browser* browser = chrome::FindBrowserWithWebContents(active_tab);
+    DCHECK(browser);
+    if (browser->window()->IsActive())
+      status = ash::STATUS_ACTIVE;
+    else
+      status = ash::STATUS_RUNNING;
+  }
+  item.status = status;
+
+  model_->AddAt(index, item);
+
+  app_icon_loader_->FetchImage(app_id);
+
+  return id;
+}
+
+bool ChromeLauncherController::HasItemController(ash::LauncherID id) const {
+  return id_to_item_controller_map_.find(id) !=
+         id_to_item_controller_map_.end();
+}
+
+std::vector<content::WebContents*>
+ChromeLauncherController::GetV1ApplicationsFromController(
+    LauncherItemController* controller) {
+  DCHECK(controller->type() == LauncherItemController::TYPE_SHORTCUT);
+  AppShortcutLauncherItemController* app_controller =
+      static_cast<AppShortcutLauncherItemController*>(controller);
+  return app_controller->GetRunningApplications();
+}
+
+bool ChromeLauncherController::IsBrowserRepresentedInBrowserList(
+    Browser* browser) {
+  return (browser &&
+          (browser->is_type_tabbed() ||
+           !browser->is_app() ||
+           !browser->is_type_popup() ||
+           GetLauncherIDForAppID(web_app::GetExtensionIdFromApplicationName(
+               browser->app_name())) <= 0));
+}
+
+LauncherItemController*
+ChromeLauncherController::GetBrowserShortcutLauncherItemController() {
+  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
+      i != id_to_item_controller_map_.end(); ++i) {
+    int index = model_->ItemIndexByID(i->first);
+    const ash::LauncherItem& item = model_->items()[index];
+    if (item.type == ash::TYPE_BROWSER_SHORTCUT)
+      return i->second;
+  }
+  // LauncerItemController For Browser Shortcut must be existed. If it does not
+  // existe create it.
+  ash::LauncherID id = CreateBrowserShortcutLauncherItem();
+  DCHECK(id_to_item_controller_map_[id]);
+  return id_to_item_controller_map_[id];
+}
+
+ash::LauncherID ChromeLauncherController::CreateBrowserShortcutLauncherItem() {
+  ash::LauncherItem browser_shortcut;
+  browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT;
+  browser_shortcut.is_incognito = false;
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
+  ash::LauncherID id = model_->next_id();
+  size_t index = GetChromeIconIndexFromPref();
+  model_->AddAt(index, browser_shortcut);
+  browser_item_controller_.reset(
+      new BrowserShortcutLauncherItemController(this, profile_));
+  id_to_item_controller_map_[id] = browser_item_controller_.get();
+  id_to_item_controller_map_[id]->set_launcher_id(id);
+  return id;
+}
+
+void ChromeLauncherController::PersistChromeItemIndex(int index) {
+  profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index);
+}
+
+int ChromeLauncherController::GetChromeIconIndexFromPref() const {
+  size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
+  const base::ListValue* pinned_apps_pref =
+      profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
+  if (ash::switches::UseAlternateShelfLayout())
+    return std::max(static_cast<size_t>(1),
+                    std::min(pinned_apps_pref->GetSize() + 1, index));
+  return std::max(static_cast<size_t>(0),
+                  std::min(pinned_apps_pref->GetSize(), index));
+}
+
+bool ChromeLauncherController::IsIncognito(
+    content::WebContents* web_contents) const {
+  const Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  return profile->IsOffTheRecord() && !profile->IsGuestSession();
+}
+
+void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension(
+    const std::string& app_id) {
+  // This function cannot rely on the controller's enumeration functionality
+  // since the extension has already be unloaded.
+  const BrowserList* ash_browser_list =
+      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
+  std::vector<Browser*> browser_to_close;
+  for (BrowserList::const_reverse_iterator
+           it = ash_browser_list->begin_last_active();
+       it != ash_browser_list->end_last_active(); ++it) {
+    Browser* browser = *it;
+    if (!browser->is_type_tabbed() &&
+        browser->is_type_popup() &&
+        browser->is_app() &&
+        app_id == web_app::GetExtensionIdFromApplicationName(
+            browser->app_name())) {
+      browser_to_close.push_back(browser);
+    }
+  }
+  while (!browser_to_close.empty()) {
+    TabStripModel* tab_strip = browser_to_close.back()->tab_strip_model();
+    tab_strip->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
+    browser_to_close.pop_back();
+  }
+}
+
+void
+ChromeLauncherController::MoveItemWithoutPinnedStateChangeNotification(
+    int source_index, int target_index) {
+  base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true);
+  model_->Move(source_index, target_index);
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index dafc18d..cdf7105 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -1,24 +1,47 @@
-// Copyright (c) 2012 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.
 
 #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_H_
 #define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_H_
 
+#include <list>
+#include <map>
+#include <set>
 #include <string>
+#include <vector>
 
+#include "ash/display/display_controller.h"
 #include "ash/launcher/launcher_delegate.h"
+#include "ash/launcher/launcher_model_observer.h"
 #include "ash/launcher/launcher_types.h"
+#include "ash/shelf/shelf_layout_manager_observer.h"
 #include "ash/shelf/shelf_types.h"
+#include "ash/shell_observer.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
+#include "base/prefs/pref_change_registrar.h"
 #include "chrome/browser/extensions/app_icon_loader.h"
 #include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/prefs/pref_service_syncable_observer.h"
+#include "chrome/browser/ui/ash/app_sync_ui_state_observer.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
+#include "chrome/browser/ui/browser_list_observer.h"
+#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
+#include "content/public/browser/notification_observer.h"
+#include "ui/aura/window_observer.h"
 
-class LauncherItemControllerPerAppTest;
+class AppSyncUIState;
+class Browser;
+class BrowserShortcutLauncherItemController;
+class ExtensionEnableFlow;
+class GURL;
 class LauncherItemController;
 class Profile;
-class ChromeLauncherAppMenuItem;
-class ChromeLauncherControllerPerApp;
+class ShellWindowLauncherController;
+class TabContents;
 
 namespace ash {
 class LauncherModel;
@@ -26,10 +49,10 @@
 
 namespace aura {
 class Window;
-class RootWindow;
 }
 
 namespace content {
+class NotificationRegistrar;
 class WebContents;
 }
 
@@ -42,17 +65,23 @@
 
 // ChromeLauncherController manages the launcher items needed for content
 // windows. Launcher items have a type, an optional app id, and a controller.
-// ChromeLauncherController will furthermore create the particular
-// implementation of interest - either sorting by application (new) or sorting
-// by browser (old).
-// * Tabbed browsers and browser app windows have BrowserLauncherItemController,
-//   owned by the BrowserView instance.
+// This incarnation groups running tabs/windows in application specific lists.
+// * Browser app windows have BrowserLauncherItemController, owned by the
+//   BrowserView instance.
 // * App shell windows have ShellWindowLauncherItemController, owned by
 //   ShellWindowLauncherController.
 // * Shortcuts have no LauncherItemController.
-class ChromeLauncherController
-    : public ash::LauncherDelegate,
-      public extensions::AppIconLoader::Delegate {
+class ChromeLauncherController : public ash::LauncherDelegate,
+                                 public ash::LauncherModelObserver,
+                                 public ash::ShellObserver,
+                                 public ash::DisplayController::Observer,
+                                 public content::NotificationObserver,
+                                 public extensions::AppIconLoader::Delegate,
+                                 public PrefServiceSyncableObserver,
+                                 public AppSyncUIStateObserver,
+                                 public ExtensionEnableFlowDelegate,
+                                 public chrome::BrowserListObserver,
+                                 public ash::ShelfLayoutManagerObserver {
  public:
   // Indicates if a launcher item is incognito or not.
   enum IncognitoState {
@@ -82,16 +111,11 @@
     virtual bool IsValidID(const std::string& id) = 0;
   };
 
-  ChromeLauncherController() {}
+  ChromeLauncherController(Profile* profile, ash::LauncherModel* model);
   virtual ~ChromeLauncherController();
 
   // Initializes this ChromeLauncherController.
-  virtual void Init() = 0;
-
-  // Returns the new per application interface of the given launcher. If it is
-  // a per browser (old) controller, it will return NULL;
-  // TODO(skuhne): Remove when we rip out the old launcher.
-  virtual ChromeLauncherControllerPerApp* GetPerAppInterface() = 0;
+  void Init();
 
   // Creates an instance.
   static ChromeLauncherController* CreateInstance(Profile* profile,
@@ -100,211 +124,391 @@
   // Returns the single ChromeLauncherController instance.
   static ChromeLauncherController* instance() { return instance_; }
 
-  // Creates a new tabbed item on the launcher for |controller|.
-  virtual ash::LauncherID CreateTabbedLauncherItem(
-      LauncherItemController* controller,
-      IncognitoState is_incognito,
-      ash::LauncherItemStatus status) = 0;
-
   // Creates a new app item on the launcher for |controller|.
-  virtual ash::LauncherID CreateAppLauncherItem(
-      LauncherItemController* controller,
-      const std::string& app_id,
-      ash::LauncherItemStatus status) = 0;
+  ash::LauncherID CreateAppLauncherItem(LauncherItemController* controller,
+                                        const std::string& app_id,
+                                        ash::LauncherItemStatus status);
 
-  // Updates the running status of an item.
-  virtual void SetItemStatus(ash::LauncherID id,
-                             ash::LauncherItemStatus status) = 0;
+  // Updates the running status of an item. It will also update the status of
+  // browsers launcher item if needed.
+  void SetItemStatus(ash::LauncherID id, ash::LauncherItemStatus status);
 
   // Updates the controller associated with id (which should be a shortcut).
   // |controller| remains owned by caller.
-  virtual void SetItemController(ash::LauncherID id,
-                                 LauncherItemController* controller) = 0;
+  void SetItemController(ash::LauncherID id,
+                         LauncherItemController* controller);
 
   // Closes or unpins the launcher item.
-  virtual void CloseLauncherItem(ash::LauncherID id) = 0;
+  void CloseLauncherItem(ash::LauncherID id);
 
   // Pins the specified id. Currently only supports platform apps.
-  virtual void Pin(ash::LauncherID id) = 0;
+  void Pin(ash::LauncherID id);
 
   // Unpins the specified id, closing if not running.
-  virtual void Unpin(ash::LauncherID id) = 0;
+  void Unpin(ash::LauncherID id);
 
   // Returns true if the item identified by |id| is pinned.
-  virtual bool IsPinned(ash::LauncherID id) = 0;
+  bool IsPinned(ash::LauncherID id);
 
   // Pins/unpins the specified id.
-  virtual void TogglePinned(ash::LauncherID id) = 0;
+  void TogglePinned(ash::LauncherID id);
 
   // Returns true if the specified item can be pinned or unpinned. Only apps can
   // be pinned.
-  virtual bool IsPinnable(ash::LauncherID id) const = 0;
+  bool IsPinnable(ash::LauncherID id) const;
 
   // If there is no launcher item in the launcher for application |app_id|, one
   // gets created. The (existing or created) launcher items get then locked
   // against a users un-pinning removal.
-  virtual void LockV1AppWithID(const std::string& app_id) = 0;
+  void LockV1AppWithID(const std::string& app_id);
 
   // A previously locked launcher item of type |app_id| gets unlocked. If the
   // lock count reaches 0 and the item is not pinned it will go away.
-  virtual void UnlockV1AppWithID(const std::string& app_id) = 0;
+  void UnlockV1AppWithID(const std::string& app_id);
 
   // Requests that the launcher item controller specified by |id| open a new
   // instance of the app.  |event_flags| holds the flags of the event which
   // triggered this command.
-  virtual void Launch(ash::LauncherID id, int event_flags) = 0;
+  void Launch(ash::LauncherID id, int event_flags);
 
   // Closes the specified item.
-  virtual void Close(ash::LauncherID id) = 0;
+  void Close(ash::LauncherID id);
 
   // Returns true if the specified item is open.
-  virtual bool IsOpen(ash::LauncherID id) = 0;
+  bool IsOpen(ash::LauncherID id);
 
   // Returns true if the specified item is for a platform app.
-  virtual bool IsPlatformApp(ash::LauncherID id) = 0;
+  bool IsPlatformApp(ash::LauncherID id);
 
   // Opens a new instance of the application identified by |app_id|.
   // Used by the app-list, and by pinned-app launcher items.
-  virtual void LaunchApp(const std::string& app_id, int event_flags) = 0;
+  void LaunchApp(const std::string& app_id, int event_flags);
 
   // If |app_id| is running, reactivates the app's most recently active window,
   // otherwise launches and activates the app.
   // Used by the app-list, and by pinned-app launcher items.
-  virtual void ActivateApp(const std::string& app_id, int event_flags) = 0;
+  void ActivateApp(const std::string& app_id, int event_flags);
 
   // Returns the launch type of app for the specified id.
-  virtual extensions::ExtensionPrefs::LaunchType GetLaunchType(
-      ash::LauncherID id) = 0;
+  extensions::ExtensionPrefs::LaunchType GetLaunchType(ash::LauncherID id);
 
   // Returns the id of the app for the specified tab.
-  virtual std::string GetAppID(content::WebContents* tab) = 0;
+  std::string GetAppID(content::WebContents* tab);
 
-  // Returns the launcherID of the first non-panel item whose app_id
-  // matches |app_id| or 0 if none match.
-  virtual ash::LauncherID GetLauncherIDForAppID(const std::string& app_id) = 0;
-
-  // Returns the id of the app for the specified id (which must exist).
-  virtual std::string GetAppIDForLauncherID(ash::LauncherID id) = 0;
+  std::string GetAppIDForLauncherID(ash::LauncherID id);
 
   // Set the image for a specific launcher item (e.g. when set by the app).
-  virtual void SetLauncherItemImage(ash::LauncherID launcher_id,
-                                    const gfx::ImageSkia& image) = 0;
+  void SetLauncherItemImage(ash::LauncherID launcher_id,
+                            const gfx::ImageSkia& image);
 
-  // Returns true if a pinned launcher item with given |app_id| could be found.
-  virtual bool IsAppPinned(const std::string& app_id) = 0;
-
-  // Pins an app with |app_id| to launcher. If there is a running instance in
-  // launcher, the running instance is pinned. If there is no running instance,
-  // a new launcher item is created and pinned.
-  virtual void PinAppWithID(const std::string& app_id) = 0;
+  // Find out if the given application |id| is a windowed app item and not a
+  // pinned item in the launcher.
+  bool IsWindowedAppInLauncher(const std::string& app_id);
 
   // Updates the launche type of the app for the specified id to |launch_type|.
-  virtual void SetLaunchType(
-      ash::LauncherID id,
-      extensions::ExtensionPrefs::LaunchType launch_type) = 0;
-
-  // Unpins any app items whose id is |app_id|.
-  virtual void UnpinAppsWithID(const std::string& app_id) = 0;
+  void SetLaunchType(ash::LauncherID id,
+                     extensions::ExtensionPrefs::LaunchType launch_type);
 
   // Returns true if the user is currently logged in as a guest.
-  virtual bool IsLoggedInAsGuest() = 0;
+  // Makes virtual for unittest in LauncherContextMenuTest.
+  virtual bool IsLoggedInAsGuest();
 
   // Invoked when user clicks on button in the launcher and there is no last
   // used window (or CTRL is held with the click).
-  virtual void CreateNewWindow() = 0;
+  void CreateNewWindow();
 
   // Invoked when the user clicks on button in the launcher to create a new
   // incognito window.
-  virtual void CreateNewIncognitoWindow() = 0;
+  void CreateNewIncognitoWindow();
 
   // Checks whether the user is allowed to pin apps. Pinning may be disallowed
   // by policy in case there is a pre-defined set of pinned apps.
-  virtual bool CanPin() const = 0;
+  bool CanPin() const;
 
   // Updates the pinned pref state. The pinned state consists of a list pref.
   // Each item of the list is a dictionary. The key |kAppIDPath| gives the
   // id of the app.
-  virtual void PersistPinnedState() = 0;
+  void PersistPinnedState();
 
-  virtual ash::LauncherModel* model() = 0;
+  ash::LauncherModel* model();
 
-  virtual Profile* profile() = 0;
+  Profile* profile();
 
   // Gets the shelf auto-hide behavior on |root_window|.
-  virtual ash::ShelfAutoHideBehavior GetShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const = 0;
+  ash::ShelfAutoHideBehavior GetShelfAutoHideBehavior(
+      aura::RootWindow* root_window) const;
 
   // Returns |true| if the user is allowed to modify the shelf auto-hide
   // behavior on |root_window|.
-  virtual bool CanUserModifyShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const = 0;
+  bool CanUserModifyShelfAutoHideBehavior(aura::RootWindow* 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.
-  virtual void ToggleShelfAutoHideBehavior(aura::RootWindow* root_window) = 0;
+  void ToggleShelfAutoHideBehavior(aura::RootWindow* root_window);
 
   // The tab no longer represents its previously identified application.
-  virtual void RemoveTabFromRunningApp(content::WebContents* tab,
-                                       const std::string& app_id) = 0;
+  void RemoveTabFromRunningApp(content::WebContents* tab,
+                               const std::string& app_id);
 
   // Notify the controller that the state of an non platform app's tabs
   // have changed,
-  virtual void UpdateAppState(content::WebContents* contents,
-                              AppState app_state) = 0;
+  void UpdateAppState(content::WebContents* contents, AppState app_state);
 
   // Limits application refocusing to urls that match |url| for |id|.
-  virtual void SetRefocusURLPatternForTest(ash::LauncherID id,
-                                           const GURL& url) = 0;
+  void SetRefocusURLPatternForTest(ash::LauncherID id, const GURL& url);
 
   // Returns the extension identified by |app_id|.
-  virtual const extensions::Extension* GetExtensionForAppID(
-      const std::string& app_id) const = 0;
+  const extensions::Extension* GetExtensionForAppID(
+      const std::string& app_id) const;
 
   // Activates a |window|. If |allow_minimize| is true and the system allows
   // it, the the window will get minimized instead.
-  virtual void ActivateWindowOrMinimizeIfActive(ui::BaseWindow* window,
-                                                bool allow_minimize) = 0;
+  void ActivateWindowOrMinimizeIfActive(ui::BaseWindow* window,
+                                        bool allow_minimize);
+
   // ash::LauncherDelegate overrides:
   virtual void ItemSelected(const ash::LauncherItem& item,
-                           const ui::Event& event) OVERRIDE = 0;
-  virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE = 0;
+                           const ui::Event& event) OVERRIDE;
+  virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
-      const ash::LauncherItem& item, aura::RootWindow* root) OVERRIDE = 0;
+      const ash::LauncherItem& item, aura::RootWindow* root) OVERRIDE;
   virtual ash::LauncherMenuModel* CreateApplicationMenu(
       const ash::LauncherItem& item,
-      int event_flags) OVERRIDE = 0;
-  virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE = 0;
-  virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE = 0;
-  virtual bool ShouldShowTooltip(const ash::LauncherItem& item) OVERRIDE = 0;
-  virtual bool IsPerAppLauncher() OVERRIDE;
+      int event_flags) OVERRIDE;
+  virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE;
+  virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE;
+  virtual bool ShouldShowTooltip(const ash::LauncherItem& item) OVERRIDE;
+  virtual void OnLauncherCreated(ash::Launcher* launcher) OVERRIDE;
+  virtual void OnLauncherDestroyed(ash::Launcher* launcher) OVERRIDE;
+  virtual ash::LauncherID GetLauncherIDForAppID(
+      const std::string& app_id) OVERRIDE;
+  virtual void PinAppWithID(const std::string& app_id) OVERRIDE;
+  virtual bool IsAppPinned(const std::string& app_id) OVERRIDE;
+  virtual void UnpinAppsWithID(const std::string& app_id) OVERRIDE;
+
+  // ash::LauncherModelObserver overrides:
+  virtual void LauncherItemAdded(int index) OVERRIDE;
+  virtual void LauncherItemRemoved(int index, ash::LauncherID id) OVERRIDE;
+  virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE;
+  virtual void LauncherItemChanged(int index,
+                                   const ash::LauncherItem& old_item) OVERRIDE;
+  virtual void LauncherStatusChanged() OVERRIDE;
+
+  // content::NotificationObserver overrides:
+  virtual void Observe(int type,
+                       const content::NotificationSource& source,
+                       const content::NotificationDetails& details) OVERRIDE;
+
+  // ash::ShellObserver overrides:
+  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) OVERRIDE;
+
+  // ash::DisplayController::Observer overrides:
+  virtual void OnDisplayConfigurationChanging() OVERRIDE;
+  virtual void OnDisplayConfigurationChanged() OVERRIDE;
+
+  // PrefServiceSyncableObserver overrides:
+  virtual void OnIsSyncingChanged() OVERRIDE;
+
+  // AppSyncUIStateObserver overrides:
+  virtual void OnAppSyncUIStatusChanged() OVERRIDE;
+
+  // ExtensionEnableFlowDelegate overrides:
+  virtual void ExtensionEnableFlowFinished() OVERRIDE;
+  virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
 
   // extensions::AppIconLoader overrides:
   virtual void SetAppImage(const std::string& app_id,
-                           const gfx::ImageSkia& image) OVERRIDE = 0;
+                           const gfx::ImageSkia& image) OVERRIDE;
+
+  // ash::ShelfLayoutManagerObserver overrides:
+  virtual void OnAutoHideBehaviorChanged(
+      aura::RootWindow* root_window,
+      ash::ShelfAutoHideBehavior new_behavior) OVERRIDE;
+
+  // 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.
+  ChromeLauncherAppMenuItems GetApplicationList(const ash::LauncherItem& item,
+                                                int event_flags);
+
+  // Get the list of all tabs which belong to a certain application type.
+  std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
+      std::string app_id);
+
+  // Activates a specified shell application.
+  void ActivateShellApp(const std::string& app_id, int index);
+
+  // Checks if a given |web_contents| is known to be associated with an
+  // application of type |app_id|.
+  bool IsWebContentHandledByApplication(content::WebContents* web_contents,
+                                        const std::string& app_id);
+
+  // Check if the gMail app is loaded and it can handle the given web content.
+  // This special treatment is required to address crbug.com/234268.
+  bool ContentCanBeHandledByGmailApp(content::WebContents* web_contents);
+
+  // Get the favicon for the application list entry for |web_contents|.
+  // Note that for incognito windows the incognito icon will be returned.
+  // If |web_contents| has not loaded, returns the default favicon.
+  gfx::Image GetAppListIcon(content::WebContents* web_contents) const;
+
+  // Get the title for the applicatoin list entry for |web_contents|.
+  // If |web_contents| has not loaded, returns "Net Tab".
+  string16 GetAppListTitle(content::WebContents* web_contents) const;
+
+  // Overridden from chrome::BrowserListObserver.
+  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
+
+  // Returns true when the given |browser| is listed in the browser application
+  // list.
+  bool IsBrowserRepresentedInBrowserList(Browser* browser);
+
+  // Returns the LauncherItemController of BrowserShortcut.
+  LauncherItemController* GetBrowserShortcutLauncherItemController();
 
  protected:
-  friend class LauncherItemControllerPerAppTest;
-  friend class LauncherPlatformAppBrowserTest;
-  friend class LauncherAppBrowserTest;
-  // TODO(skuhne): Remove these when the old launcher get removed.
-  friend class LauncherPlatformPerAppAppBrowserTest;
-  friend class LauncherPerAppAppBrowserTest;
-
   // Creates a new app shortcut item and controller on the launcher at |index|.
   // Use kInsertItemAtEnd to add a shortcut as the last item.
-  virtual ash::LauncherID CreateAppShortcutLauncherItem(
-      const std::string& app_id,
-      int index) = 0;
+  ash::LauncherID CreateAppShortcutLauncherItem(const std::string& app_id,
+                                                int index);
 
   // Sets the AppTabHelper/AppIconLoader, taking ownership of the helper class.
   // These are intended for testing.
-  virtual void SetAppTabHelperForTest(AppTabHelper* helper) = 0;
-  virtual void SetAppIconLoaderForTest(extensions::AppIconLoader* loader) = 0;
-  virtual const std::string& GetAppIdFromLauncherIdForTest(
-      ash::LauncherID id) = 0;
+  void SetAppTabHelperForTest(AppTabHelper* helper);
+  void SetAppIconLoaderForTest(extensions::AppIconLoader* loader);
+  const std::string& GetAppIdFromLauncherIdForTest(ash::LauncherID id);
 
  private:
+  friend class ChromeLauncherControllerTest;
+  friend class LauncherAppBrowserTest;
+  friend class LauncherPlatformAppBrowserTest;
+
+  typedef std::map<ash::LauncherID, LauncherItemController*>
+          IDToItemControllerMap;
+  typedef std::list<content::WebContents*> WebContentsList;
+  typedef std::map<std::string, WebContentsList> AppIDToWebContentsListMap;
+  typedef std::map<content::WebContents*, std::string> WebContentsToAppIDMap;
+
+  // Creates a new app shortcut item and controller on the launcher at |index|.
+  // Use kInsertItemAtEnd to add a shortcut as the last item.
+  ash::LauncherID CreateAppShortcutLauncherItemWithType(
+      const std::string& app_id,
+      int index,
+      ash::LauncherItemType launcher_item_type);
+
+  // Updates the activation state of the Broswer item.
+  void UpdateBrowserItemStatus();
+
+  // Returns the profile used for new windows.
+  Profile* GetProfileForNewWindows();
+
+  // Invoked when the associated browser or app is closed.
+  void LauncherItemClosed(ash::LauncherID id);
+
+  // Internal helpers for pinning and unpinning that handle both
+  // client-triggered and internal pinning operations.
+  void DoPinAppWithID(const std::string& app_id);
+  void DoUnpinAppsWithID(const std::string& app_id);
+
+  // Re-syncs launcher model with prefs::kPinnedLauncherApps.
+  void UpdateAppLaunchersFromPref();
+
+  // Persists the shelf auto-hide behavior to prefs.
+  void SetShelfAutoHideBehaviorPrefs(ash::ShelfAutoHideBehavior behavior,
+                                     aura::RootWindow* root_window);
+
+  // Sets the shelf auto-hide behavior from prefs.
+  void SetShelfAutoHideBehaviorFromPrefs();
+
+  // Sets the shelf alignment from prefs.
+  void SetShelfAlignmentFromPrefs();
+
+  // Sets both of auto-hide behavior and alignment from prefs.
+  void SetShelfBehaviorsFromPrefs();
+
+  // Returns the most recently active web contents for an app.
+  content::WebContents* GetLastActiveWebContents(const std::string& app_id);
+
+  // Creates an app launcher to insert at |index|. Note that |index| may be
+  // adjusted by the model to meet ordering constraints.
+  // The |launcher_item_type| will be set into the LauncherModel.
+  ash::LauncherID InsertAppLauncherItem(
+      LauncherItemController* controller,
+      const std::string& app_id,
+      ash::LauncherItemStatus status,
+      int index,
+      ash::LauncherItemType launcher_item_type);
+
+  bool HasItemController(ash::LauncherID id) const;
+
+  // Enumerate all Web contents which match a given shortcut |controller|.
+  std::vector<content::WebContents*> GetV1ApplicationsFromController(
+      LauncherItemController* controller);
+
+  // Create LauncherItem for Browser Shortcut.
+  ash::LauncherID CreateBrowserShortcutLauncherItem();
+
+  // Check if the given |web_contents| is in incognito mode.
+  bool IsIncognito(content::WebContents* web_contents) const;
+
+  // Update browser shortcut's index.
+  void PersistChromeItemIndex(int index);
+
+  // Get browser shortcut's index from pref.
+  int GetChromeIconIndexFromPref() const;
+
+  // Close all windowed V1 applications of a certain extension which was already
+  // deleted.
+  void CloseWindowedAppsFromRemovedExtension(const std::string& app_id);
+
+  // Move a launcher item ignoring the pinned state changes from |index| to
+  // |target_index|.
+  void MoveItemWithoutPinnedStateChangeNotification(int source_index,
+                                                    int target_index);
+
   static ChromeLauncherController* instance_;
+
+  ash::LauncherModel* model_;
+
+  // Profile used for prefs and loading extensions. This is NOT necessarily the
+  // profile new windows are created with.
+  Profile* profile_;
+
+  IDToItemControllerMap id_to_item_controller_map_;
+
+  // Maintains activation order of web contents for each app.
+  AppIDToWebContentsListMap app_id_to_web_contents_list_;
+
+  // Direct access to app_id for a web contents.
+  WebContentsToAppIDMap web_contents_to_app_id_;
+
+  // Used to track shell windows.
+  scoped_ptr<ShellWindowLauncherController> shell_window_controller_;
+
+  // Used to get app info for tabs.
+  scoped_ptr<AppTabHelper> app_tab_helper_;
+
+  // Used to load the image for an app item.
+  scoped_ptr<extensions::AppIconLoader> app_icon_loader_;
+
+  content::NotificationRegistrar notification_registrar_;
+
+  PrefChangeRegistrar pref_change_registrar_;
+
+  AppSyncUIState* app_sync_ui_state_;
+
+  scoped_ptr<ExtensionEnableFlow> extension_enable_flow_;
+
+  // Launchers that are currently being observed.
+  std::set<ash::Launcher*> launchers_;
+
+  // The owned browser shortcut item.
+  scoped_ptr<BrowserShortcutLauncherItemController> browser_item_controller_;
+
+  // If true, incoming pinned state changes should be ignored.
+  bool ignore_persist_pinned_state_change_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherController);
 };
 
 #endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_H_
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 801538a..3b448be 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 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,15 +8,18 @@
 #include "apps/shell_window.h"
 #include "apps/shell_window_registry.h"
 #include "ash/ash_switches.h"
+#include "ash/display/display_controller.h"
 #include "ash/launcher/launcher.h"
 #include "ash/launcher/launcher_model.h"
+#include "ash/launcher/launcher_util.h"
+#include "ash/launcher/launcher_view.h"
 #include "ash/shell.h"
 #include "ash/test/launcher_view_test_api.h"
 #include "ash/test/shell_test_api.h"
 #include "ash/wm/window_util.h"
-#include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/automation/automation_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_apitest.h"
@@ -25,10 +28,14 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/launcher_item_controller.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_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/host_desktop.h"
@@ -39,37 +46,81 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/common/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/app_list/views/apps_grid_view.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/test/event_generator.h"
 #include "ui/aura/window.h"
+#include "ui/base/events/event.h"
 
 using apps::ShellWindow;
 using extensions::Extension;
 using content::WebContents;
 
+namespace {
+
+class TestEvent : public ui::Event {
+ public:
+  explicit TestEvent(ui::EventType type)
+      : ui::Event(type, base::TimeDelta(), 0) {
+  }
+  virtual ~TestEvent() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestEvent);
+};
+
+class TestShellWindowRegistryObserver
+    : public apps::ShellWindowRegistry::Observer {
+ public:
+  explicit TestShellWindowRegistryObserver(Profile* profile)
+      : profile_(profile),
+        icon_updates_(0) {
+    apps::ShellWindowRegistry::Get(profile_)->AddObserver(this);
+  }
+
+  virtual ~TestShellWindowRegistryObserver() {
+    apps::ShellWindowRegistry::Get(profile_)->RemoveObserver(this);
+  }
+
+  // Overridden from ShellWindowRegistry::Observer:
+  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE {}
+
+  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {
+    ++icon_updates_;
+  }
+
+  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE {}
+
+  int icon_updates() { return icon_updates_; }
+
+ private:
+  Profile* profile_;
+  int icon_updates_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestShellWindowRegistryObserver);
+};
+
+}  // namespace
+
 class LauncherPlatformAppBrowserTest
     : public extensions::PlatformAppBrowserTest {
  protected:
-  LauncherPlatformAppBrowserTest()
-      : launcher_(NULL),
-        controller_(NULL) {
+  LauncherPlatformAppBrowserTest() : launcher_(NULL), controller_(NULL) {
   }
 
   virtual ~LauncherPlatformAppBrowserTest() {}
 
-  ash::LauncherModel* launcher_model() {
-    return ash::test::ShellTestApi(ash::Shell::GetInstance()).launcher_model();
-  }
-
   virtual void RunTestOnMainThreadLoop() OVERRIDE {
     launcher_ = ash::Launcher::ForPrimaryDisplay();
-    controller_ = static_cast<ChromeLauncherController*>(launcher_->delegate());
+    controller_ = ChromeLauncherController::instance();
     return extensions::PlatformAppBrowserTest::RunTestOnMainThreadLoop();
   }
 
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    PlatformAppBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(ash::switches::kAshDisablePerAppLauncher);
+  ash::LauncherModel* launcher_model() {
+    return ash::test::ShellTestApi(ash::Shell::GetInstance()).launcher_model();
   }
 
   ash::LauncherID CreateAppShortcutLauncherItem(const std::string& name) {
@@ -79,7 +130,7 @@
 
   const ash::LauncherItem& GetLastLauncherItem() {
     // Unless there are any panels, the item at index [count - 1] will be
-    // the app list, and the item at [count - 2] will be the desited item.
+    // the app list, and the item at [count - 2] will be the desired item.
     return launcher_model()->items()[launcher_model()->item_count() - 2];
   }
 
@@ -89,15 +140,39 @@
     return launcher_model()->items()[launcher_model()->item_count() - 1];
   }
 
+  LauncherItemController* GetItemController(ash::LauncherID id) {
+    return controller_->id_to_item_controller_map_[id];
+  }
+
+  // Returns the number of menu items, ignoring separators.
+  int GetNumApplicationMenuItems(const ash::LauncherItem& item) {
+    const int event_flags = 0;
+    scoped_ptr<ash::LauncherMenuModel> menu(
+        controller_->CreateApplicationMenu(item, event_flags));
+    int num_items = 0;
+    for (int i = 0; i < menu->GetItemCount(); ++i) {
+      if (menu->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR)
+        ++num_items;
+    }
+    return num_items;
+  }
+
+  // Activate the launcher item with the given |id|.
+  void ActivateLauncherItem(int id) {
+    launcher_->ActivateLauncherItem(id);
+  }
+
   ash::Launcher* launcher_;
   ChromeLauncherController* controller_;
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(LauncherPlatformAppBrowserTest);
 };
 
 class LauncherAppBrowserTest : public ExtensionBrowserTest {
  protected:
-  LauncherAppBrowserTest()
-      : launcher_(NULL),
-        model_(NULL) {
+  LauncherAppBrowserTest() : launcher_(NULL), model_(NULL), controller_(NULL) {
   }
 
   virtual ~LauncherAppBrowserTest() {}
@@ -106,12 +181,17 @@
     launcher_ = ash::Launcher::ForPrimaryDisplay();
     model_ =
         ash::test::ShellTestApi(ash::Shell::GetInstance()).launcher_model();
+    controller_ = ChromeLauncherController::instance();
     return ExtensionBrowserTest::RunTestOnMainThreadLoop();
   }
 
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    ExtensionBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(ash::switches::kAshDisablePerAppLauncher);
+  size_t NumberOfDetectedLauncherBrowsers(bool show_all_tabs) {
+    LauncherItemController* item_controller =
+      controller_->GetBrowserShortcutLauncherItemController();
+    int items = item_controller->GetApplicationList(
+        show_all_tabs ? ui::EF_SHIFT_DOWN : 0).size();
+    // If we have at least one item, we have also a title which we remove here.
+    return items ? (items - 1) : 0;
   }
 
   const Extension* LoadAndLaunchExtension(
@@ -121,19 +201,21 @@
     EXPECT_TRUE(LoadExtension(test_data_dir_.AppendASCII(name)));
 
     ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
+        profile())->extension_service();
     const Extension* extension =
         service->GetExtensionById(last_loaded_extension_id_, false);
     EXPECT_TRUE(extension);
 
-    chrome::OpenApplication(chrome::AppLaunchParams(
-        browser()->profile(), extension, container, disposition));
+    chrome::OpenApplication(chrome::AppLaunchParams(profile(),
+                                                    extension,
+                                                    container,
+                                                    disposition));
     return extension;
   }
 
   ash::LauncherID CreateShortcut(const char* name) {
     ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
+        profile())->extension_service();
     LoadExtension(test_data_dir_.AppendASCII(name));
 
     // First get app_id.
@@ -142,29 +224,72 @@
     const std::string app_id = extension->id();
 
     // Then create a shortcut.
-    ChromeLauncherController* controller =
-        static_cast<ChromeLauncherController*>(launcher_->delegate());
     int item_count = model_->item_count();
-    ash::LauncherID shortcut_id = controller->CreateAppShortcutLauncherItem(
-        app_id, item_count);
-    controller->PersistPinnedState();
+    ash::LauncherID shortcut_id = controller_->CreateAppShortcutLauncherItem(
+        app_id,
+        item_count);
+    controller_->PersistPinnedState();
     EXPECT_EQ(++item_count, model_->item_count());
-    ash::LauncherItem item = *model_->ItemByID(shortcut_id);
+    const ash::LauncherItem& item = *model_->ItemByID(shortcut_id);
     EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
     return item.id;
   }
 
+  // Activate the launcher item with the given |id|.
+  void ActivateLauncherItem(int id) {
+    launcher_->ActivateLauncherItem(id);
+  }
+
   ash::LauncherID PinFakeApp(const std::string& name) {
-    ChromeLauncherController* controller =
-        static_cast<ChromeLauncherController*>(launcher_->delegate());
-    return controller->CreateAppShortcutLauncherItem(
+    return controller_->CreateAppShortcutLauncherItem(
         name, model_->item_count());
   }
 
   ash::Launcher* launcher_;
   ash::LauncherModel* model_;
+  ChromeLauncherController* controller_;
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(LauncherAppBrowserTest);
 };
 
+class LauncherAppBrowserTestNoDefaultBrowser : public LauncherAppBrowserTest {
+ protected:
+  LauncherAppBrowserTestNoDefaultBrowser() {}
+  virtual ~LauncherAppBrowserTestNoDefaultBrowser() {}
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    LauncherAppBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kNoStartupWindow);
+  }
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(LauncherAppBrowserTestNoDefaultBrowser);
+};
+
+// Since the default for minimizing on click might change, I added both classes
+// to either get the minimize on click or not.
+class LauncherAppBrowserNoMinimizeOnClick
+    : public LauncherPlatformAppBrowserTest {
+ protected:
+  LauncherAppBrowserNoMinimizeOnClick() {}
+  virtual ~LauncherAppBrowserNoMinimizeOnClick() {}
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    LauncherPlatformAppBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(
+        switches::kDisableMinimizeOnSecondLauncherItemClick);
+  }
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(LauncherAppBrowserNoMinimizeOnClick);
+};
+
+typedef LauncherPlatformAppBrowserTest LauncherAppBrowserMinimizeOnClick;
+
 // Test that we can launch a platform app and get a running item.
 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchUnpinned) {
   int item_count = launcher_model()->item_count();
@@ -310,6 +435,7 @@
   ash::LauncherID item_id = item1.id;
   EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
   EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  EXPECT_EQ(2, GetNumApplicationMenuItems(item1));  // Title + 1 window
 
   // Add second window.
   ShellWindow* window2 = CreateShellWindow(extension);
@@ -317,6 +443,7 @@
   ASSERT_EQ(item_count, launcher_model()->item_count());
   const ash::LauncherItem& item2 = *launcher_model()->ItemByID(item_id);
   EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
+  EXPECT_EQ(3, GetNumApplicationMenuItems(item2));  // Title + 2 windows
 
   // Close second window.
   CloseShellWindow(window2);
@@ -324,6 +451,7 @@
   ASSERT_EQ(item_count, launcher_model()->item_count());
   const ash::LauncherItem& item3 = *launcher_model()->ItemByID(item_id);
   EXPECT_EQ(ash::STATUS_ACTIVE, item3.status);
+  EXPECT_EQ(2, GetNumApplicationMenuItems(item3));  // Title + 1 window
 
   // Close first window.
   CloseShellWindow(window1);
@@ -373,33 +501,9 @@
   ASSERT_EQ(item_count, launcher_model()->item_count());
 }
 
-// Test that we can launch a platform app panel and get a running item.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, LaunchPanelWindow) {
-  int item_count = launcher_model()->item_count();
-  const Extension* extension = LoadAndLaunchPlatformApp("launch");
-  ShellWindow::CreateParams params;
-  params.window_type = ShellWindow::WINDOW_TYPE_PANEL;
-  params.focused = false;
-  ShellWindow* window = CreateShellWindowFromParams(extension, params);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item = GetLastLauncherPanelItem();
-  EXPECT_EQ(ash::TYPE_APP_PANEL, item.type);
-  // Opening a panel does not activate it.
-  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
-  CloseShellWindow(window);
-  --item_count;
-  EXPECT_EQ(item_count, launcher_model()->item_count());
-}
-
-#if defined(OS_CHROMEOS)
-#define MAYBE_WindowActivation DISABLED_WindowActivation
-#else
-#define MAYBE_WindowActivation WindowActivation
-#endif
 // Confirm that app windows can be reactivated by clicking their icons and that
 // the correct activation order is maintained.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, MAYBE_WindowActivation) {
+IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, WindowActivation) {
   int item_count = launcher_model()->item_count();
 
   // First run app.
@@ -427,7 +531,7 @@
             launcher_model()->ItemByID(item_id1)->status);
 
   // Activate first one.
-  launcher_->ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
+  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
   EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model()->ItemByID(item_id1)->status);
   EXPECT_EQ(ash::STATUS_RUNNING,
             launcher_model()->ItemByID(item_id2)->status);
@@ -435,7 +539,7 @@
   EXPECT_FALSE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
 
   // Activate second one.
-  launcher_->ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id2));
+  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id2));
   EXPECT_EQ(ash::STATUS_RUNNING,
             launcher_model()->ItemByID(item_id1)->status);
   EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model()->ItemByID(item_id2)->status);
@@ -450,23 +554,23 @@
   EXPECT_TRUE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
 
   // Activate launcher item for app1, this will activate the first app window.
-  launcher_->ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
+  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
   EXPECT_TRUE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
   EXPECT_FALSE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
-  launcher_->ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
+  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
+  EXPECT_TRUE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
 
   // Activate the second app again
-  launcher_->ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id2));
+  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id2));
   EXPECT_FALSE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
   EXPECT_TRUE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
   EXPECT_FALSE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
 
   // Activate the first app again
-  launcher_->ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
+  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
+  EXPECT_TRUE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
   EXPECT_FALSE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
+  EXPECT_FALSE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
 
   // Close second app.
   CloseShellWindow(window2);
@@ -482,6 +586,138 @@
   EXPECT_EQ(item_count, launcher_model()->item_count());
 }
 
+// Confirm that Click behavior for app windows is correnct.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserNoMinimizeOnClick,
+                       AppClickBehavior) {
+  // Launch a platform app and create a window for it.
+  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
+  ShellWindow* window1 = CreateShellWindow(extension1);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  // Confirm that a controller item was created and is the correct state.
+  const ash::LauncherItem& item1 = GetLastLauncherItem();
+  LauncherItemController* item1_controller = GetItemController(item1.id);
+  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
+  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  EXPECT_EQ(LauncherItemController::TYPE_APP, item1_controller->type());
+  // Clicking the item should have no effect.
+  TestEvent click_event(ui::ET_MOUSE_PRESSED);
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  // Minimize the window and confirm that the controller item is updated.
+  window1->GetBaseWindow()->Minimize();
+  EXPECT_FALSE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
+  // Clicking the item should activate the window.
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  // Maximizing a window should preserve state after minimize + click.
+  window1->GetBaseWindow()->Maximize();
+  window1->GetBaseWindow()->Minimize();
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsMaximized());
+}
+
+// Confirm the minimizing click behavior for apps.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserMinimizeOnClick,
+                       PackagedAppClickBehaviorInMinimizeMode) {
+  // Launch one platform app and create a window for it.
+  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
+  ShellWindow* window1 = CreateShellWindow(extension1);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+
+  // Confirm that a controller item was created and is the correct state.
+  const ash::LauncherItem& item1 = GetLastLauncherItem();
+  LauncherItemController* item1_controller = GetItemController(item1.id);
+  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
+  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  EXPECT_EQ(LauncherItemController::TYPE_APP, item1_controller->type());
+  // Since it is already active, clicking it should minimize.
+  TestEvent click_event(ui::ET_MOUSE_PRESSED);
+  item1_controller->Clicked(click_event);
+  EXPECT_FALSE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsMinimized());
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
+  // Clicking the item again should activate the window again.
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  // Maximizing a window should preserve state after minimize + click.
+  window1->GetBaseWindow()->Maximize();
+  window1->GetBaseWindow()->Minimize();
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsMaximized());
+  window1->GetBaseWindow()->Restore();
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  EXPECT_FALSE(window1->GetBaseWindow()->IsMaximized());
+
+  // Creating a second window of the same type should change the behavior so
+  // that a click does not change the activation state.
+  ShellWindow* window1a = CreateShellWindow(extension1);
+  EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1a->GetBaseWindow()->IsActive());
+  // The first click does nothing.
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  EXPECT_FALSE(window1a->GetBaseWindow()->IsActive());
+  // The second neither.
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
+  EXPECT_FALSE(window1a->GetBaseWindow()->IsActive());
+}
+
+// Confirm that click behavior for app panels is correct.
+IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, AppPanelClickBehavior) {
+  // Enable experimental APIs to allow panel creation.
+  CommandLine::ForCurrentProcess()->AppendSwitch(
+      extensions::switches::kEnableExperimentalExtensionApis);
+  // Launch a platform app and create a panel window for it.
+  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
+  ShellWindow::CreateParams params;
+  params.window_type = ShellWindow::WINDOW_TYPE_PANEL;
+  params.focused = false;
+  ShellWindow* panel = CreateShellWindowFromParams(extension1, params);
+  EXPECT_TRUE(panel->GetNativeWindow()->IsVisible());
+  // Panels should not be active by default.
+  EXPECT_FALSE(panel->GetBaseWindow()->IsActive());
+  // Confirm that a controller item was created and is the correct state.
+  const ash::LauncherItem& item1 = GetLastLauncherPanelItem();
+  LauncherItemController* item1_controller = GetItemController(item1.id);
+  EXPECT_EQ(ash::TYPE_APP_PANEL, item1.type);
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
+  EXPECT_EQ(LauncherItemController::TYPE_APP_PANEL, item1_controller->type());
+  // Click the item and confirm that the panel is activated.
+  TestEvent click_event(ui::ET_MOUSE_PRESSED);
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
+  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+  // Click the item again and confirm that the panel is minimized.
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(panel->GetBaseWindow()->IsMinimized());
+  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
+  // Click the item again and confirm that the panel is activated.
+  item1_controller->Clicked(click_event);
+  EXPECT_TRUE(panel->GetNativeWindow()->IsVisible());
+  EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
+  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+}
+
 IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, BrowserActivation) {
   int item_count = launcher_model()->item_count();
 
@@ -500,24 +736,49 @@
             launcher_model()->ItemByID(item_id1)->status);
 }
 
-// Test that draw attention sets the launcher item status.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, DrawAttention) {
-  const Extension* extension = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* shell_window = CreateShellWindow(extension);
-  const ash::LauncherItem& item = GetLastLauncherItem();
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
-  // Set Minimize window to deactivate the launcher item.
-  shell_window->GetBaseWindow()->Minimize();
-  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
-  // Set DrawAttention property.
-  shell_window->GetNativeWindow()->SetProperty(
-      aura::client::kDrawAttentionKey, true);
-  EXPECT_EQ(ash::STATUS_ATTENTION, item.status);
-  // Activate window, should clear DrawAttention.
-  shell_window->GetBaseWindow()->Activate();
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
-  EXPECT_FALSE(shell_window->GetNativeWindow()->GetProperty(
-      aura::client::kDrawAttentionKey));
+// Test that opening an app sets the correct icon
+IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, SetIcon) {
+  TestShellWindowRegistryObserver test_observer(browser()->profile());
+
+  // Enable experimental APIs to allow panel creation.
+  CommandLine::ForCurrentProcess()->AppendSwitch(
+      extensions::switches::kEnableExperimentalExtensionApis);
+
+  int base_launcher_item_count = launcher_model()->item_count();
+  ExtensionTestMessageListener launched_listener("Launched", false);
+  ExtensionTestMessageListener completed_listener("Completed", false);
+  LoadAndLaunchPlatformApp("app_icon");
+  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+  ASSERT_TRUE(completed_listener.WaitUntilSatisfied());
+
+  // Now wait until the WebContent has decoded the icons and chrome has
+  // processed it. This needs to be in a loop since the renderer runs in a
+  // different process.
+  while (test_observer.icon_updates() < 3) {
+    base::RunLoop run_loop;
+    run_loop.RunUntilIdle();
+  }
+
+  // This test creates one shell window and one panel window.
+  int launcher_item_count = launcher_model()->item_count();
+  ASSERT_EQ(base_launcher_item_count + 2, launcher_item_count);
+  // The Panel will be the last item, the app list second-to-last, the app
+  // third from last.
+  const ash::LauncherItem& app_item =
+      launcher_model()->items()[launcher_item_count - 3];
+  const ash::LauncherItem& panel_item =
+      launcher_model()->items()[launcher_item_count - 1];
+  const LauncherItemController* app_item_controller =
+      GetItemController(app_item.id);
+  const LauncherItemController* panel_item_controller =
+      GetItemController(panel_item.id);
+  // Icons for Apps are set by the ShellWindowLauncherController, so
+  // image_set_by_controller() should be set.
+  EXPECT_TRUE(app_item_controller->image_set_by_controller());
+  EXPECT_TRUE(panel_item_controller->image_set_by_controller());
+  // Ensure icon heights are correct (see test.js in app_icon/ test directory)
+  EXPECT_EQ(48, app_item.image.height());
+  EXPECT_EQ(64, panel_item.image.height());
 }
 
 // Test that we can launch an app with a shortcut.
@@ -526,7 +787,7 @@
   int tab_count = tab_strip->count();
   ash::LauncherID shortcut_id = CreateShortcut("app1");
   EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(++tab_count, tab_strip->count());
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
   WebContents* tab = tab_strip->GetActiveWebContents();
@@ -586,7 +847,7 @@
   ash::wm::MaximizeWindow(window2);
 
   ash::LauncherID shortcut_id = CreateShortcut("app1");
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(++tab_count, tab_strip->count());
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
 
@@ -594,7 +855,7 @@
   ash::wm::ActivateWindow(window1);
   EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut_id)).status);
 
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
 }
 
@@ -635,13 +896,13 @@
   EXPECT_EQ(++item_count, model_->item_count());
 
   // Launch first app.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
   EXPECT_EQ(++tab_count, tab_strip->count());
   WebContents* tab1 = tab_strip->GetActiveWebContents();
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status);
 
   // Launch second app.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut2));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut2));
   EXPECT_EQ(++tab_count, tab_strip->count());
   WebContents* tab2 = tab_strip->GetActiveWebContents();
   ASSERT_NE(tab1, tab2);
@@ -649,7 +910,7 @@
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status);
 
   // Reactivate first app.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
   EXPECT_EQ(tab_count, tab_strip->count());
   EXPECT_EQ(tab_strip->GetActiveWebContents(), tab1);
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status);
@@ -662,21 +923,20 @@
       NEW_FOREGROUND_TAB,
       0);
   EXPECT_EQ(++tab_count, tab_strip->count());
-  WebContents* tab3 = tab_strip->GetActiveWebContents();
   EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status);
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status);
 
   // Reactivate first app.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
   EXPECT_EQ(tab_count, tab_strip->count());
   EXPECT_EQ(tab_strip->GetActiveWebContents(), tab1);
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status);
   EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut2)).status);
 
   // And second again. This time the second tab should become active.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut2));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut2));
   EXPECT_EQ(tab_count, tab_strip->count());
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab3);
+  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab2);
   EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status);
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status);
 }
@@ -686,7 +946,7 @@
 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, Navigation) {
   ash::LauncherID shortcut_id = CreateShortcut("app1");
   EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
 
   // Navigate away.
@@ -704,9 +964,10 @@
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
   ash::LauncherID shortcut_id = CreateShortcut("app1");
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(++tab_count, tab_strip->count());
   EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
+  WebContents* first_tab = tab_strip->GetActiveWebContents();
 
   // Create new tab owned by app.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -717,7 +978,6 @@
   EXPECT_EQ(++tab_count, tab_strip->count());
   // Confirm app is still active.
   EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  WebContents* second_tab = tab_strip->GetActiveWebContents();
 
   // Create new tab not owned by app.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -729,24 +989,22 @@
   // No longer active.
   EXPECT_EQ(ash::STATUS_RUNNING, model_->ItemByID(shortcut_id)->status);
 
-  // Activating app makes second tab active again.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  // Activating app makes first tab active again.
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), second_tab);
+  EXPECT_EQ(tab_strip->GetActiveWebContents(), first_tab);
 }
 
 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, RefocusFilter) {
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
   ash::LauncherID shortcut_id = CreateShortcut("app1");
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(++tab_count, tab_strip->count());
   EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
   WebContents* first_tab = tab_strip->GetActiveWebContents();
 
-  controller->SetRefocusURLPatternForTest(
+  controller_->SetRefocusURLPatternForTest(
       shortcut_id, GURL("http://www.example.com/path1/*"));
   // Create new tab owned by app.
   ui_test_utils::NavigateToURLWithDisposition(
@@ -770,34 +1028,32 @@
 
   // Activating app makes first tab active again, because second tab isn't
   // in its refocus url path.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
   EXPECT_EQ(tab_strip->GetActiveWebContents(), first_tab);
 }
 
 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, RefocusFilterLaunch) {
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
   ash::LauncherID shortcut_id = CreateShortcut("app1");
-  controller->SetRefocusURLPatternForTest(
+  controller_->SetRefocusURLPatternForTest(
       shortcut_id, GURL("http://www.example.com/path1/*"));
 
-  // Create new tab owned by app.
+  // Create new tab.
   ui_test_utils::NavigateToURLWithDisposition(
       browser(),
-      GURL("http://www.example.com/path2/bar.html"),
+      GURL("http://www.example2.com/path2/bar.html"),
       NEW_FOREGROUND_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
   EXPECT_EQ(++tab_count, tab_strip->count());
   WebContents* first_tab = tab_strip->GetActiveWebContents();
-  // Confirm app is active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
+  // Confirm app is not active.
+  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
 
   // Activating app should launch new tab, because second tab isn't
   // in its refocus url path.
-  launcher_->ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
+  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
   EXPECT_EQ(++tab_count, tab_strip->count());
   WebContents* second_tab = tab_strip->GetActiveWebContents();
   EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
@@ -805,6 +1061,580 @@
   EXPECT_EQ(tab_strip->GetActiveWebContents(), second_tab);
 }
 
+// Check the launcher activation state for applications and browser.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ActivationStateCheck) {
+  TabStripModel* tab_strip = browser()->tab_strip_model();
+  // Get the browser item index
+  int browser_index = ash::launcher::GetBrowserItemIndex(*controller_->model());
+  EXPECT_TRUE(browser_index >= 0);
+
+  // Even though we are just comming up, the browser should be active.
+  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
+
+  ash::LauncherID shortcut_id = CreateShortcut("app1");
+  controller_->SetRefocusURLPatternForTest(
+      shortcut_id, GURL("http://www.example.com/path1/*"));
+
+  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
+
+  // Create new tab which would be the running app.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL("http://www.example.com/path1/bar.html"),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  // There should never be two items active at the same time.
+  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[browser_index].status);
+
+  tab_strip->ActivateTabAt(0, false);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
+
+  tab_strip->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
+  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
+
+  ash::wm::DeactivateWindow(browser()->window()->GetNativeWindow());
+  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
+  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[browser_index].status);
+}
+
+// Check that the launcher activation state for a V1 application stays closed
+// even after an asynchronous browser event comes in after the tab got
+// destroyed.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, AsyncActivationStateCheck) {
+  TabStripModel* tab_strip = browser()->tab_strip_model();
+
+  ash::LauncherID shortcut_id = CreateShortcut("app1");
+  controller_->SetRefocusURLPatternForTest(
+      shortcut_id, GURL("http://www.example.com/path1/*"));
+
+  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
+
+  // Create new tab which would be the running app.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL("http://www.example.com/path1/bar.html"),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
+  // To address the issue of crbug.com/174050, the tab we are about to close
+  // has to be active.
+  tab_strip->ActivateTabAt(1, false);
+  EXPECT_EQ(1, tab_strip->active_index());
+
+  // Close the web contents.
+  tab_strip->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
+  // The status should now be set to closed.
+  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
+}
+
+// Checks that a windowed application does not add an item to the browser list.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTestNoDefaultBrowser,
+    WindowedAppDoesNotAddToBrowser) {
+  // Get the number of items in the browser menu.
+  size_t items = NumberOfDetectedLauncherBrowsers(false);
+  size_t running_browser = chrome::GetTotalBrowserCount();
+  EXPECT_EQ(0u, items);
+  EXPECT_EQ(0u, running_browser);
+
+  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_WINDOW, NEW_WINDOW);
+
+  // No new browser should get detected, even though one more is running.
+  EXPECT_EQ(0u, NumberOfDetectedLauncherBrowsers(false));
+  EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
+
+  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
+
+  // A new browser should get detected and one more should be running.
+  EXPECT_EQ(NumberOfDetectedLauncherBrowsers(false), 1u);
+  EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
+}
+
+// Checks the functionality to enumerate all browsers vs. all tabs.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTestNoDefaultBrowser,
+    EnumerateALlBrowsersAndTabs) {
+  // Create at least one browser.
+  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
+  size_t browsers = NumberOfDetectedLauncherBrowsers(false);
+  size_t tabs = NumberOfDetectedLauncherBrowsers(true);
+
+  // Create a second browser.
+  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
+
+  EXPECT_EQ(++browsers, NumberOfDetectedLauncherBrowsers(false));
+  EXPECT_EQ(++tabs, NumberOfDetectedLauncherBrowsers(true));
+
+  // Create only a tab.
+  LoadAndLaunchExtension("app1",
+                         extension_misc::LAUNCH_TAB,
+                         NEW_FOREGROUND_TAB);
+
+  EXPECT_EQ(browsers, NumberOfDetectedLauncherBrowsers(false));
+  EXPECT_EQ(++tabs, NumberOfDetectedLauncherBrowsers(true));
+}
+
+// Check that the keyboard activation of a launcher item tabs properly through
+// the items at hand.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, AltNumberTabsTabbing) {
+  TabStripModel* tab_strip = browser()->tab_strip_model();
+
+  ash::LauncherID shortcut_id = CreateShortcut("app");
+  controller_->SetRefocusURLPatternForTest(
+      shortcut_id, GURL("http://www.example.com/path/*"));
+  std::string url = "http://www.example.com/path/bla";
+
+  int shortcut_index = model_->ItemIndexByID(shortcut_id);
+
+  // Create an application handled browser tab.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(url),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  content::WebContents* content1 = tab_strip->GetActiveWebContents();
+
+  // Create some other browser tab.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL("http://www.test.com"),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+  content::WebContents* content1a = tab_strip->GetActiveWebContents();
+
+  // Make sure that the active tab is now our handled tab.
+  EXPECT_NE(content1a, content1);
+
+  // The active tab should still be the unnamed tab. Then we switch and reach
+  // the first app and stay there.
+  EXPECT_EQ(content1a, tab_strip->GetActiveWebContents());
+  ActivateLauncherItem(shortcut_index);
+  EXPECT_EQ(content1, tab_strip->GetActiveWebContents());
+  ActivateLauncherItem(shortcut_index);
+  EXPECT_EQ(content1, tab_strip->GetActiveWebContents());
+
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(),
+      GURL(url),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+  content::WebContents* content2 = tab_strip->GetActiveWebContents();
+
+  EXPECT_EQ(content2, browser()->tab_strip_model()->GetActiveWebContents());
+  ActivateLauncherItem(shortcut_index);
+  EXPECT_EQ(content1, browser()->tab_strip_model()->GetActiveWebContents());
+  ActivateLauncherItem(shortcut_index);
+  EXPECT_EQ(content2, browser()->tab_strip_model()->GetActiveWebContents());
+}
+
+// Check that the keyboard activation of a launcher item tabs properly through
+// the items at hand.
+IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,
+                       AltNumberAppsTabbing) {
+  // First run app.
+  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
+  ui::BaseWindow* window1 = CreateShellWindow(extension1)->GetBaseWindow();
+  const ash::LauncherItem& item1 = GetLastLauncherItem();
+  ash::LauncherID app_id = item1.id;
+  int app_index = launcher_model()->ItemIndexByID(app_id);
+
+  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
+  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
+
+  const Extension* extension2 = LoadAndLaunchPlatformApp("launch_2");
+  ui::BaseWindow* window2 = CreateShellWindow(extension2)->GetBaseWindow();
+
+  // By now the browser should be active. Issue Alt keystrokes several times to
+  // see that we stay on that application.
+  EXPECT_TRUE(window2->IsActive());
+  ActivateLauncherItem(app_index);
+  EXPECT_TRUE(window1->IsActive());
+  ActivateLauncherItem(app_index);
+  EXPECT_TRUE(window1->IsActive());
+
+  ui::BaseWindow* window1a = CreateShellWindow(extension1)->GetBaseWindow();
+
+  EXPECT_TRUE(window1a->IsActive());
+  EXPECT_FALSE(window1->IsActive());
+  ActivateLauncherItem(app_index);
+  EXPECT_TRUE(window1->IsActive());
+  ActivateLauncherItem(app_index);
+  EXPECT_TRUE(window1a->IsActive());
+}
+
+// Test that we can launch a platform app panel and get a running item.
+IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest,
+    LaunchPanelWindow) {
+  int item_count = launcher_model()->item_count();
+  const Extension* extension = LoadAndLaunchPlatformApp("launch");
+  ShellWindow::CreateParams params;
+  params.window_type = ShellWindow::WINDOW_TYPE_PANEL;
+  params.focused = false;
+  ShellWindow* window = CreateShellWindowFromParams(extension, params);
+  ++item_count;
+  ASSERT_EQ(item_count, launcher_model()->item_count());
+  const ash::LauncherItem& item = GetLastLauncherPanelItem();
+  EXPECT_EQ(ash::TYPE_APP_PANEL, item.type);
+  // Opening a panel does not activate it.
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
+  CloseShellWindow(window);
+  --item_count;
+  EXPECT_EQ(item_count, launcher_model()->item_count());
+}
+
+// Test attention states of windows.
+IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, WindowAttentionStatus) {
+  const Extension* extension = LoadAndLaunchPlatformApp("launch");
+  ShellWindow::CreateParams params;
+  params.window_type = ShellWindow::WINDOW_TYPE_PANEL;
+  params.focused = false;
+  ShellWindow* panel = CreateShellWindowFromParams(extension, params);
+  EXPECT_TRUE(panel->GetNativeWindow()->IsVisible());
+  // Panels should not be active by default.
+  EXPECT_FALSE(panel->GetBaseWindow()->IsActive());
+  // Confirm that a controller item was created and is the correct state.
+  const ash::LauncherItem& item = GetLastLauncherPanelItem();
+  LauncherItemController* item_controller = GetItemController(item.id);
+  EXPECT_EQ(ash::TYPE_APP_PANEL, item.type);
+  EXPECT_EQ(ash::STATUS_RUNNING, item.status);
+  EXPECT_EQ(LauncherItemController::TYPE_APP_PANEL, item_controller->type());
+
+  // App windows should go to attention state.
+  panel->GetNativeWindow()->SetProperty(aura::client::kDrawAttentionKey, true);
+  EXPECT_EQ(ash::STATUS_ATTENTION, item.status);
+
+  // Click the item and confirm that the panel is activated.
+  TestEvent click_event(ui::ET_MOUSE_PRESSED);
+  item_controller->Clicked(click_event);
+  EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
+  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+
+  // Active windows don't show attention.
+  panel->GetNativeWindow()->SetProperty(aura::client::kDrawAttentionKey, true);
+  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
+}
+
+// Checks that the browser Alt "tabbing" is properly done.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTestNoDefaultBrowser,
+    AltNumberBrowserTabbing) {
+  // Get the number of items in the browser menu.
+  EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
+  // The first activation should create a browser.
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
+  // A second activation should not create a new instance.
+  launcher_->ActivateLauncherItem(0);
+  Browser* browser1 = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
+  EXPECT_TRUE(browser1);
+  aura::Window* window1 = browser1->window()->GetNativeWindow();
+  Browser* browser2 = CreateBrowser(profile());
+  aura::Window* window2 = browser2->window()->GetNativeWindow();
+
+  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
+  EXPECT_NE(window1, window2);
+  EXPECT_EQ(window2, ash::wm::GetActiveWindow());
+
+  // Activate multiple times the switcher to see that the windows get activated.
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(window2, ash::wm::GetActiveWindow());
+
+  // Create a third browser - make sure that we do not toggle simply between
+  // two windows.
+  Browser* browser3 = CreateBrowser(profile());
+  aura::Window* window3 = browser3->window()->GetNativeWindow();
+
+  EXPECT_EQ(3u, chrome::GetTotalBrowserCount());
+  EXPECT_NE(window1, window3);
+  EXPECT_NE(window2, window3);
+  EXPECT_EQ(window3, ash::wm::GetActiveWindow());
+
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(window2, ash::wm::GetActiveWindow());
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(window3, ash::wm::GetActiveWindow());
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
+
+  // Create anther app and make sure that none of our browsers is active.
+  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
+  EXPECT_NE(window1, ash::wm::GetActiveWindow());
+  EXPECT_NE(window2, ash::wm::GetActiveWindow());
+
+  // After activation our browser should be active again.
+  launcher_->ActivateLauncherItem(0);
+  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
+}
+
+// Checks that after a session restore, we do not start applications on an
+// activation.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ActivateAfterSessionRestore) {
+  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
+
+  // Create a known application.
+  ash::LauncherID shortcut_id = CreateShortcut("app1");
+
+  // Create a new browser - without activating it - and load an "app" into it.
+  Browser::CreateParams params =
+      Browser::CreateParams(profile(), chrome::GetActiveDesktop());
+  params.initial_show_state = ui::SHOW_STATE_INACTIVE;
+  Browser* browser2 = new Browser(params);
+  controller_->SetRefocusURLPatternForTest(
+      shortcut_id, GURL("http://www.example.com/path/*"));
+  std::string url = "http://www.example.com/path/bla";
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser2,
+      GURL(url),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  // Remember the number of tabs for each browser.
+  TabStripModel* tab_strip = browser()->tab_strip_model();
+  int tab_count1 = tab_strip->count();
+  TabStripModel* tab_strip2 = browser2->tab_strip_model();
+  int tab_count2 = tab_strip2->count();
+
+  // Check that we have two browsers and the inactive browser remained inactive.
+  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
+  EXPECT_EQ(chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()),
+            browser());
+  // Check that the LRU browser list does only contain the original browser.
+  BrowserList* ash_browser_list =
+      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
+  BrowserList::const_reverse_iterator it =
+      ash_browser_list->begin_last_active();
+  EXPECT_EQ(*it, browser());
+  ++it;
+  EXPECT_EQ(it, ash_browser_list->end_last_active());
+
+  // Now request to either activate an existing app or create a new one.
+  controller_->ItemSelected(*model_->ItemByID(shortcut_id),
+                           ui::KeyEvent(ui::ET_KEY_RELEASED,
+                                        ui::VKEY_RETURN,
+                                        0,
+                                        false));
+
+  // Check that we have set focus on the existing application and nothing new
+  // was created.
+  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
+  EXPECT_EQ(tab_count1, tab_strip->count());
+  EXPECT_EQ(tab_count2, tab_strip2->count());
+  EXPECT_EQ(chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()),
+            browser2);
+}
+
+// Do various drag and drop interaction tests between the application list and
+// the launcher.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, DragAndDrop) {
+  // Get a number of interfaces we need.
+  aura::test::EventGenerator generator(
+      ash::Shell::GetPrimaryRootWindow(), gfx::Point());
+  ash::test::LauncherViewTestAPI test(launcher_->GetLauncherViewForTest());
+  AppListService* service = AppListService::Get();
+
+  // There should be two items in our launcher by this time.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(service->IsAppListVisible());
+
+  // Open the app list menu and check that the drag and drop host was set.
+  gfx::Rect app_list_bounds =
+      test.launcher_view()->GetAppListButtonView()->GetBoundsInScreen();
+  generator.MoveMouseTo(app_list_bounds.CenterPoint().x(),
+                        app_list_bounds.CenterPoint().y());
+  base::MessageLoop::current()->RunUntilIdle();
+  generator.ClickLeftButton();
+
+  EXPECT_TRUE(service->IsAppListVisible());
+  app_list::AppsGridView* grid_view =
+      app_list::AppsGridView::GetLastGridViewForTest();
+  ASSERT_TRUE(grid_view);
+  ASSERT_TRUE(grid_view->has_drag_and_drop_host_for_test());
+
+  // There should be 2 items in our application list.
+  const views::ViewModel* vm_grid = grid_view->view_model_for_test();
+  EXPECT_EQ(2, vm_grid->view_size());
+
+  // Test #1: Drag an app list which does not exist yet item into the
+  // launcher. Keeping it dragged, see that a new item gets created. Continuing
+  // to drag it out should remove it again.
+
+  // Get over item #1 of the application list and press the mouse button.
+  views::View* item1 = vm_grid->view_at(1);
+  gfx::Rect bounds_grid_1 = item1->GetBoundsInScreen();
+  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
+                        bounds_grid_1.CenterPoint().y());
+  base::MessageLoop::current()->RunUntilIdle();
+  generator.PressLeftButton();
+
+  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
+
+  // Drag the item into the launcher and check that a new item gets created.
+  const views::ViewModel* vm_launcher =
+      test.launcher_view()->view_model_for_test();
+  views::View* launcher1 = vm_launcher->view_at(1);
+  gfx::Rect bounds_launcher_1 = launcher1->GetBoundsInScreen();
+  generator.MoveMouseTo(bounds_launcher_1.CenterPoint().x(),
+                        bounds_launcher_1.CenterPoint().y());
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Check that a new item got created.
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_TRUE(grid_view->forward_events_to_drag_and_drop_host_for_test());
+
+  // Move it where the item originally was and check that it disappears again.
+  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
+                        bounds_grid_1.CenterPoint().y());
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
+
+  // Dropping it should keep the launcher as it originally was.
+  generator.ReleaseLeftButton();
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(2, model_->item_count());
+  // There are a few animations which need finishing before we can continue.
+  test.RunMessageLoopUntilAnimationsDone();
+  // Move the mouse outside of the launcher.
+  generator.MoveMouseTo(0, 0);
+
+  // Test #2: Check that the unknown item dropped into the launcher will
+  // create a new item.
+  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
+                        bounds_grid_1.CenterPoint().y());
+  generator.PressLeftButton();
+  generator.MoveMouseTo(bounds_launcher_1.CenterPoint().x(),
+                        bounds_launcher_1.CenterPoint().y());
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_TRUE(grid_view->forward_events_to_drag_and_drop_host_for_test());
+  generator.ReleaseLeftButton();
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
+  EXPECT_EQ(3, model_->item_count());  // It should be still there.
+  test.RunMessageLoopUntilAnimationsDone();
+
+  // Test #3: Check that the now known item dropped into the launcher will
+  // not create a new item.
+  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
+                        bounds_grid_1.CenterPoint().y());
+  generator.PressLeftButton();
+  generator.MoveMouseTo(bounds_launcher_1.CenterPoint().x(),
+                        bounds_launcher_1.CenterPoint().y());
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(3, model_->item_count());  // No new item got added.
+  EXPECT_TRUE(grid_view->forward_events_to_drag_and_drop_host_for_test());
+  generator.ReleaseLeftButton();
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
+  EXPECT_EQ(3, model_->item_count());  // And it remains that way.
+}
+
+// Check that clicking on an app launcher item launches a new browser.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, ClickItem) {
+  // Get a number of interfaces we need.
+  aura::test::EventGenerator generator(
+      ash::Shell::GetPrimaryRootWindow(), gfx::Point());
+  ash::test::LauncherViewTestAPI test(launcher_->GetLauncherViewForTest());
+  AppListService* service = AppListService::Get();
+  // There should be two items in our launcher by this time.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(service->IsAppListVisible());
+
+  // Open the app list menu and check that the drag and drop host was set.
+  gfx::Rect app_list_bounds =
+      test.launcher_view()->GetAppListButtonView()->GetBoundsInScreen();
+  generator.MoveMouseTo(app_list_bounds.CenterPoint().x(),
+                        app_list_bounds.CenterPoint().y());
+  generator.ClickLeftButton();
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(service->IsAppListVisible());
+  app_list::AppsGridView* grid_view =
+      app_list::AppsGridView::GetLastGridViewForTest();
+  ASSERT_TRUE(grid_view);
+  const views::ViewModel* vm_grid = grid_view->view_model_for_test();
+  EXPECT_EQ(2, vm_grid->view_size());
+  gfx::Rect bounds_grid_1 = vm_grid->view_at(1)->GetBoundsInScreen();
+  // Test now that a click does create a new application tab.
+  TabStripModel* tab_strip = browser()->tab_strip_model();
+  int tab_count = tab_strip->count();
+  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
+                        bounds_grid_1.CenterPoint().y());
+  generator.ClickLeftButton();
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(tab_count + 1, tab_strip->count());
+}
+
+// Check LauncherItemController of Browser Shortcut functionality.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTestNoDefaultBrowser,
+    BrowserShortcutLauncherItemController) {
+  LauncherItemController* item_controller =
+      controller_->GetBrowserShortcutLauncherItemController();
+
+  // Get the number of browsers.
+  size_t running_browser = chrome::GetTotalBrowserCount();
+  EXPECT_EQ(0u, running_browser);
+  EXPECT_FALSE(item_controller->IsOpen());
+
+  // Activate. This creates new browser
+  item_controller->Activate();
+  // New Window is created.
+  running_browser = chrome::GetTotalBrowserCount();
+  EXPECT_EQ(1u, running_browser);
+  EXPECT_TRUE(item_controller->IsOpen());
+
+  // Minimize Window.
+  aura::Window* window = ash::wm::GetActiveWindow();
+  ash::wm::MinimizeWindow(window);
+  EXPECT_TRUE(ash::wm::IsWindowMinimized(window));
+
+  // Activate again. This doesn't create new browser.
+  // It activates window.
+  item_controller->Activate();
+  running_browser = chrome::GetTotalBrowserCount();
+  EXPECT_EQ(1u, running_browser);
+  EXPECT_TRUE(item_controller->IsOpen());
+  EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
+}
+
+// Check that GetIDByWindow() returns |LauncherID| of the active tab.
+IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, MatchingLauncherIDandActiveTab) {
+  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
+  EXPECT_EQ(1, browser()->tab_strip_model()->count());
+  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
+  EXPECT_EQ(2, model_->item_count());
+
+  aura::Window* window = browser()->window()->GetNativeWindow();
+
+  int browser_index = ash::launcher::GetBrowserItemIndex(*model_);
+  ash::LauncherID browser_id = model_->items()[browser_index].id;
+  EXPECT_EQ(browser_id, controller_->GetIDByWindow(window));
+
+  ash::LauncherID app_id = CreateShortcut("app1");
+  EXPECT_EQ(3, model_->item_count());
+
+  // Creates a new tab for "app1" and checks that GetIDByWindow() returns
+  // |LauncherID| of "app1".
+  ActivateLauncherItem(model_->ItemIndexByID(app_id));
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
+  EXPECT_EQ(app_id, controller_->GetIDByWindow(window));
+
+  // Makes tab at index 0(NTP) as an active tab and checks that GetIDByWindow()
+  // returns |LauncherID| of browser shortcut.
+  browser()->tab_strip_model()->ActivateTabAt(0, false);
+  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
+  EXPECT_EQ(browser_id, controller_->GetIDByWindow(window));
+}
+
 IN_PROC_BROWSER_TEST_F(LauncherAppBrowserTest, OverflowBubble) {
   // Make sure to have a browser window
   chrome::NewTab(browser());
@@ -828,9 +1658,7 @@
   EXPECT_TRUE(launcher_->IsShowingOverflowBubble());
 
   // Unpin first pinned app and there should be no crash.
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
-  controller->UnpinAppsWithID(std::string("fake_app_0"));
+  controller_->UnpinAppsWithID(std::string("fake_app_0"));
 
   test.RunMessageLoopUntilAnimationsDone();
   EXPECT_FALSE(launcher_->IsShowingOverflowBubble());
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
deleted file mode 100644
index 71b0881..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc
+++ /dev/null
@@ -1,1689 +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/launcher/chrome_launcher_controller_per_app.h"
-
-#include <vector>
-
-#include "ash/ash_switches.h"
-#include "ash/launcher/launcher.h"
-#include "ash/launcher/launcher_model.h"
-#include "ash/launcher/launcher_util.h"
-#include "ash/root_window_controller.h"
-#include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_widget.h"
-#include "ash/shell.h"
-#include "ash/wm/window_util.h"
-#include "base/command_line.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/app_mode/app_mode_utils.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/app_icon_loader_impl.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#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"
-#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
-#include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
-#include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
-#include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
-#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
-#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.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_list.h"
-#include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/extensions/extension_enable_flow.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/web_applications/web_app.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/common/extension_resource.h"
-#include "extensions/common/url_pattern.h"
-#include "grit/ash_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "grit/theme_resources.h"
-#include "grit/ui_resources.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/views/corewm/window_animations.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h"
-#endif
-
-using extensions::Extension;
-using extension_misc::kGmailAppId;
-using content::WebContents;
-
-namespace {
-
-std::string GetPrefKeyForRootWindow(aura::RootWindow* root_window) {
-  gfx::Display display = gfx::Screen::GetScreenFor(
-      root_window)->GetDisplayNearestWindow(root_window);
-  DCHECK(display.is_valid());
-
-  return base::Int64ToString(display.id());
-}
-
-void UpdatePerDisplayPref(PrefService* pref_service,
-                          aura::RootWindow* root_window,
-                          const char* pref_key,
-                          const std::string& value) {
-  std::string key = GetPrefKeyForRootWindow(root_window);
-  if (key.empty())
-    return;
-
-  DictionaryPrefUpdate update(pref_service, prefs::kShelfPreferences);
-  base::DictionaryValue* shelf_prefs = update.Get();
-  base::DictionaryValue* prefs = NULL;
-  if (!shelf_prefs->GetDictionary(key, &prefs)) {
-    prefs = new base::DictionaryValue();
-    shelf_prefs->Set(key, prefs);
-  }
-  prefs->SetStringWithoutPathExpansion(pref_key, value);
-}
-
-// Returns a pref value in |pref_service| for the display of |root_window|. The
-// pref value is stored in |local_path| and |path|, but |pref_service| may have
-// per-display preferences and the value can be specified by policy. Here is
-// the priority:
-//  * A value managed by policy. This is a single value that applies to all
-//    displays.
-//  * A user-set value for the specified display.
-//  * A user-set value in |local_path| or |path|, if no per-display settings are
-//    ever specified (see http://crbug.com/173719 for why). |local_path| is
-//    preferred. See comment in |kShelfAlignment| as to why we consider two
-//    prefs and why |local_path| is preferred.
-//  * A value recommended by policy. This is a single value that applies to all
-//    root windows.
-//  * The default value for |local_path| if the value is not recommended by
-//    policy.
-std::string GetPrefForRootWindow(PrefService* pref_service,
-                                 aura::RootWindow* root_window,
-                                 const char* local_path,
-                                 const char* path) {
-  const PrefService::Preference* local_pref =
-      pref_service->FindPreference(local_path);
-  const std::string value(pref_service->GetString(local_path));
-  if (local_pref->IsManaged())
-    return value;
-
-  std::string pref_key = GetPrefKeyForRootWindow(root_window);
-  bool has_per_display_prefs = false;
-  if (!pref_key.empty()) {
-    const base::DictionaryValue* shelf_prefs = pref_service->GetDictionary(
-        prefs::kShelfPreferences);
-    const base::DictionaryValue* display_pref = NULL;
-    std::string per_display_value;
-    if (shelf_prefs->GetDictionary(pref_key, &display_pref) &&
-        display_pref->GetString(path, &per_display_value))
-      return per_display_value;
-
-    // If the pref for the specified display is not found, scan the whole prefs
-    // and check if the prefs for other display is already specified.
-    std::string unused_value;
-    for (base::DictionaryValue::Iterator iter(*shelf_prefs);
-         !iter.IsAtEnd(); iter.Advance()) {
-      const base::DictionaryValue* display_pref = NULL;
-      if (iter.value().GetAsDictionary(&display_pref) &&
-          display_pref->GetString(path, &unused_value)) {
-        has_per_display_prefs = true;
-        break;
-      }
-    }
-  }
-
-  if (local_pref->IsRecommended() || !has_per_display_prefs)
-    return value;
-
-  const base::Value* default_value =
-      pref_service->GetDefaultPrefValue(local_path);
-  std::string default_string;
-  default_value->GetAsString(&default_string);
-  return default_string;
-}
-
-// If prefs have synced and no user-set value exists at |local_path|, the value
-// from |synced_path| is copied to |local_path|.
-void MaybePropagatePrefToLocal(PrefServiceSyncable* pref_service,
-                               const char* local_path,
-                               const char* synced_path) {
-  if (!pref_service->FindPreference(local_path)->HasUserSetting() &&
-      pref_service->IsSyncing()) {
-    // First time the user is using this machine, propagate from remote to
-    // local.
-    pref_service->SetString(local_path, pref_service->GetString(synced_path));
-  }
-}
-
-}  // namespace
-
-ChromeLauncherControllerPerApp::ChromeLauncherControllerPerApp(
-    Profile* profile,
-    ash::LauncherModel* model)
-    : model_(model),
-      profile_(profile),
-      app_sync_ui_state_(NULL),
-      ignore_persist_pinned_state_change_(false) {
-  if (!profile_) {
-    // Use the original profile as on chromeos we may get a temporary off the
-    // record profile.
-    profile_ = ProfileManager::GetDefaultProfile()->GetOriginalProfile();
-
-    app_sync_ui_state_ = AppSyncUIState::Get(profile_);
-    if (app_sync_ui_state_)
-      app_sync_ui_state_->AddObserver(this);
-  }
-
-  model_->AddObserver(this);
-  BrowserList::AddObserver(this);
-  // Right now ash::Shell isn't created for tests.
-  // TODO(mukai): Allows it to observe display change and write tests.
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetInstance()->display_controller()->AddObserver(this);
-  // TODO(stevenjb): Find a better owner for shell_window_controller_?
-  shell_window_controller_.reset(new ShellWindowLauncherController(this));
-  app_tab_helper_.reset(new LauncherAppTabHelper(profile_));
-  app_icon_loader_.reset(new extensions::AppIconLoaderImpl(
-      profile_, extension_misc::EXTENSION_ICON_SMALL, this));
-
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_EXTENSION_LOADED,
-                              content::Source<Profile>(profile_));
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_EXTENSION_UNLOADED,
-                              content::Source<Profile>(profile_));
-  pref_change_registrar_.Init(profile_->GetPrefs());
-  pref_change_registrar_.Add(
-      prefs::kPinnedLauncherApps,
-      base::Bind(&ChromeLauncherControllerPerApp::UpdateAppLaunchersFromPref,
-                 base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kShelfAlignmentLocal,
-      base::Bind(&ChromeLauncherControllerPerApp::SetShelfAlignmentFromPrefs,
-                 base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kShelfAutoHideBehaviorLocal,
-      base::Bind(&ChromeLauncherControllerPerApp::
-                     SetShelfAutoHideBehaviorFromPrefs,
-                 base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kShelfPreferences,
-      base::Bind(&ChromeLauncherControllerPerApp::SetShelfBehaviorsFromPrefs,
-                 base::Unretained(this)));
-}
-
-ChromeLauncherControllerPerApp::~ChromeLauncherControllerPerApp() {
-  // Reset the shell window controller here since it has a weak pointer to this.
-  shell_window_controller_.reset();
-
-  for (std::set<ash::Launcher*>::iterator iter = launchers_.begin();
-       iter != launchers_.end();
-       ++iter)
-    (*iter)->shelf_widget()->shelf_layout_manager()->RemoveObserver(this);
-
-  model_->RemoveObserver(this);
-  BrowserList::RemoveObserver(this);
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
-  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    i->second->OnRemoved();
-    // TODO(skuhne): After getting rid of the old launcher, get also rid of the
-    // BrowserLauncherItemController (since it is only used for activation
-    // tracking at that point.
-    int index = model_->ItemIndexByID(i->first);
-    // A "browser proxy" is not known to the model and this removal does
-    // therefore not need to be propagated to the model.
-    if (index != -1 &&
-        model_->items()[index].type != ash::TYPE_BROWSER_SHORTCUT)
-      model_->RemoveItemAt(index);
-  }
-
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetInstance()->RemoveShellObserver(this);
-
-  if (app_sync_ui_state_)
-    app_sync_ui_state_->RemoveObserver(this);
-
-  PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
-}
-
-void ChromeLauncherControllerPerApp::Init() {
-  UpdateAppLaunchersFromPref();
-  CreateBrowserShortcutLauncherItem();
-
-  // TODO(sky): update unit test so that this test isn't necessary.
-  if (ash::Shell::HasInstance()) {
-    SetShelfAutoHideBehaviorFromPrefs();
-    SetShelfAlignmentFromPrefs();
-    PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
-    if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() ||
-        !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)->
-            HasUserSetting()) {
-      // This causes OnIsSyncingChanged to be called when the value of
-      // PrefService::IsSyncing() changes.
-      prefs->AddObserver(this);
-    }
-    ash::Shell::GetInstance()->AddShellObserver(this);
-  }
-}
-
-ChromeLauncherControllerPerApp*
-ChromeLauncherControllerPerApp::GetPerAppInterface() {
-  return this;
-}
-
-ash::LauncherID ChromeLauncherControllerPerApp::CreateTabbedLauncherItem(
-    LauncherItemController* controller,
-    IncognitoState is_incognito,
-    ash::LauncherItemStatus status) {
-  // We are using the launcher id only for addressing purposes to make the
-  // old launcher model happy. The |model_| does neither know anything about
-  // the browser proxy nor ever use it. As such the controller will only be
-  // used for event tracking.
-  ash::LauncherID id = model_->reserve_external_id();
-  CHECK(!HasItemController(id));
-  // TODO(skuhne): We should get rid of this entire controller and make sure
-  // that we add only some general observers to make sure that we get the
-  // state changes.
-  CHECK(controller);
-  id_to_item_controller_map_[id] = controller;
-  controller->set_launcher_id(id);
-  return id;
-}
-
-ash::LauncherID ChromeLauncherControllerPerApp::CreateAppLauncherItem(
-    LauncherItemController* controller,
-    const std::string& app_id,
-    ash::LauncherItemStatus status) {
-  CHECK(controller);
-  int index = 0;
-  // Panels are inserted on the left so as not to push all existing panels over.
-  if (controller->GetLauncherItemType() != ash::TYPE_APP_PANEL) {
-    index = model_->item_count();
-    // For the alternate shelf layout increment the index (after the app icon)
-    if (ash::switches::UseAlternateShelfLayout())
-      ++index;
-  }
-  return InsertAppLauncherItem(controller,
-                               app_id,
-                               status,
-                               index,
-                               controller->GetLauncherItemType());
-}
-
-void ChromeLauncherControllerPerApp::SetItemStatus(
-    ash::LauncherID id,
-    ash::LauncherItemStatus status) {
-  int index = model_->ItemIndexByID(id);
-  // Since ordinary browser windows are not registered, we might get a negative
-  // index here.
-  if (index >= 0) {
-    ash::LauncherItem item = model_->items()[index];
-    item.status = status;
-    model_->Set(index, item);
-
-    if (model_->items()[index].type == ash::TYPE_BROWSER_SHORTCUT)
-      return;
-  }
-  UpdateBrowserItemStatus();
-}
-
-void ChromeLauncherControllerPerApp::SetItemController(
-    ash::LauncherID id,
-    LauncherItemController* controller) {
-  CHECK(controller);
-  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
-  CHECK(iter != id_to_item_controller_map_.end());
-  iter->second->OnRemoved();
-  iter->second = controller;
-  controller->set_launcher_id(id);
-}
-
-void ChromeLauncherControllerPerApp::CloseLauncherItem(ash::LauncherID id) {
-  CHECK(id);
-  if (IsPinned(id)) {
-    // Create a new shortcut controller.
-    IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
-    CHECK(iter != id_to_item_controller_map_.end());
-    SetItemStatus(id, ash::STATUS_CLOSED);
-    std::string app_id = iter->second->app_id();
-    iter->second->OnRemoved();
-    iter->second = new AppShortcutLauncherItemController(app_id, this);
-    iter->second->set_launcher_id(id);
-  } else {
-    LauncherItemClosed(id);
-  }
-}
-
-void ChromeLauncherControllerPerApp::Pin(ash::LauncherID id) {
-  DCHECK(HasItemController(id));
-
-  int index = model_->ItemIndexByID(id);
-  DCHECK_GE(index, 0);
-
-  ash::LauncherItem item = model_->items()[index];
-
-  if (item.type == ash::TYPE_PLATFORM_APP ||
-      item.type == ash::TYPE_WINDOWED_APP) {
-    item.type = ash::TYPE_APP_SHORTCUT;
-    model_->Set(index, item);
-  } else if (item.type != ash::TYPE_APP_SHORTCUT) {
-    return;
-  }
-
-  if (CanPin())
-    PersistPinnedState();
-}
-
-void ChromeLauncherControllerPerApp::Unpin(ash::LauncherID id) {
-  DCHECK(HasItemController(id));
-
-  LauncherItemController* controller = id_to_item_controller_map_[id];
-  if (controller->type() == LauncherItemController::TYPE_APP) {
-    int index = model_->ItemIndexByID(id);
-    DCHECK_GE(index, 0);
-    ash::LauncherItem item = model_->items()[index];
-    item.type = ash::TYPE_PLATFORM_APP;
-    model_->Set(index, item);
-  } else {
-    // Prevent the removal of items upon unpin if it is locked by a running
-    // windowed V1 app.
-    if (!controller->locked()) {
-      LauncherItemClosed(id);
-    } else {
-      int index = model_->ItemIndexByID(id);
-      DCHECK_GE(index, 0);
-      ash::LauncherItem item = model_->items()[index];
-      item.type = ash::TYPE_WINDOWED_APP;
-      model_->Set(index, item);
-    }
-  }
-  if (CanPin())
-    PersistPinnedState();
-}
-
-bool ChromeLauncherControllerPerApp::IsPinned(ash::LauncherID id) {
-  int index = model_->ItemIndexByID(id);
-  if (index < 0)
-    return false;
-  ash::LauncherItemType type = model_->items()[index].type;
-  return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT);
-}
-
-void ChromeLauncherControllerPerApp::TogglePinned(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return;  // May happen if item closed with menu open.
-
-  if (IsPinned(id))
-    Unpin(id);
-  else
-    Pin(id);
-}
-
-bool ChromeLauncherControllerPerApp::IsPinnable(ash::LauncherID id) const {
-  int index = model_->ItemIndexByID(id);
-  if (index == -1)
-    return false;
-
-  ash::LauncherItemType type = model_->items()[index].type;
-  return ((type == ash::TYPE_APP_SHORTCUT ||
-           type == ash::TYPE_PLATFORM_APP ||
-           type == ash::TYPE_WINDOWED_APP) &&
-          CanPin());
-}
-
-void ChromeLauncherControllerPerApp::LockV1AppWithID(
-    const std::string& app_id) {
-  ash::LauncherID id = GetLauncherIDForAppID(app_id);
-  if (!IsPinned(id) && !IsWindowedAppInLauncher(app_id)) {
-    CreateAppShortcutLauncherItemWithType(app_id,
-                                          model_->item_count(),
-                                          ash::TYPE_WINDOWED_APP);
-    id = GetLauncherIDForAppID(app_id);
-  }
-  CHECK(id);
-  id_to_item_controller_map_[id]->lock();
-}
-
-void ChromeLauncherControllerPerApp::UnlockV1AppWithID(
-    const std::string& app_id) {
-  ash::LauncherID id = GetLauncherIDForAppID(app_id);
-  CHECK(IsPinned(id) || IsWindowedAppInLauncher(app_id));
-  CHECK(id);
-  LauncherItemController* controller = id_to_item_controller_map_[id];
-  controller->unlock();
-  if (!controller->locked() && !IsPinned(id))
-    CloseLauncherItem(id);
-}
-
-void ChromeLauncherControllerPerApp::Launch(ash::LauncherID id,
-                                            int event_flags) {
-  if (!HasItemController(id))
-    return;  // In case invoked from menu and item closed while menu up.
-  id_to_item_controller_map_[id]->Launch(event_flags);
-}
-
-void ChromeLauncherControllerPerApp::Close(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return;  // May happen if menu closed.
-  id_to_item_controller_map_[id]->Close();
-}
-
-bool ChromeLauncherControllerPerApp::IsOpen(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return false;
-  return id_to_item_controller_map_[id]->IsOpen();
-}
-
-bool ChromeLauncherControllerPerApp::IsPlatformApp(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return false;
-
-  std::string app_id = GetAppIDForLauncherID(id);
-  const Extension* extension = GetExtensionForAppID(app_id);
-  // An extension can be synced / updated at any time and therefore not be
-  // available.
-  return extension ? extension->is_platform_app() : false;
-}
-
-void ChromeLauncherControllerPerApp::LaunchApp(const std::string& app_id,
-                                               int event_flags) {
-  // |extension| could be NULL when it is being unloaded for updating.
-  const Extension* extension = GetExtensionForAppID(app_id);
-  if (!extension)
-    return;
-
-  const ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  if (!service->IsExtensionEnabledForLauncher(app_id)) {
-    // Do nothing if there is already a running enable flow.
-    if (extension_enable_flow_)
-      return;
-
-    extension_enable_flow_.reset(
-        new ExtensionEnableFlow(profile_, app_id, this));
-    extension_enable_flow_->StartForNativeWindow(NULL);
-    return;
-  }
-
-  chrome::OpenApplication(chrome::AppLaunchParams(GetProfileForNewWindows(),
-                                                  extension,
-                                                  event_flags));
-}
-
-void ChromeLauncherControllerPerApp::ActivateApp(const std::string& app_id,
-                                                 int event_flags) {
-  // If there is an existing non-shortcut controller for this app, open it.
-  ash::LauncherID id = GetLauncherIDForAppID(app_id);
-  if (id) {
-    LauncherItemController* controller = id_to_item_controller_map_[id];
-    controller->Activate();
-    return;
-  }
-
-  // Create a temporary application launcher item and use it to see if there are
-  // running instances.
-  scoped_ptr<AppShortcutLauncherItemController> app_controller(
-      new AppShortcutLauncherItemController(app_id, this));
-  if (!app_controller->GetRunningApplications().empty())
-    app_controller->Activate();
-  else
-    LaunchApp(app_id, event_flags);
-}
-
-extensions::ExtensionPrefs::LaunchType
-    ChromeLauncherControllerPerApp::GetLaunchType(ash::LauncherID id) {
-  DCHECK(HasItemController(id));
-
-  const Extension* extension = GetExtensionForAppID(
-      id_to_item_controller_map_[id]->app_id());
-
-  // An extension can be unloaded/updated/unavailable at any time.
-  if (!extension)
-    return extensions::ExtensionPrefs::LAUNCH_DEFAULT;
-
-  return profile_->GetExtensionService()->extension_prefs()->GetLaunchType(
-      extension,
-      extensions::ExtensionPrefs::LAUNCH_DEFAULT);
-}
-
-std::string ChromeLauncherControllerPerApp::GetAppID(
-    content::WebContents* tab) {
-  return app_tab_helper_->GetAppID(tab);
-}
-
-ash::LauncherID ChromeLauncherControllerPerApp::GetLauncherIDForAppID(
-    const std::string& app_id) {
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    if (i->second->type() == LauncherItemController::TYPE_APP_PANEL)
-      continue;  // Don't include panels
-    if (i->second->app_id() == app_id)
-      return i->first;
-  }
-  return 0;
-}
-
-std::string ChromeLauncherControllerPerApp::GetAppIDForLauncherID(
-    ash::LauncherID id) {
-  CHECK(HasItemController(id));
-  return id_to_item_controller_map_[id]->app_id();
-}
-
-void ChromeLauncherControllerPerApp::SetAppImage(
-    const std::string& id,
-    const gfx::ImageSkia& image) {
-  // TODO: need to get this working for shortcuts.
-
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    LauncherItemController* controller = i->second;
-    if (controller->app_id() != id)
-      continue;
-    if (controller->image_set_by_controller())
-      continue;
-    int index = model_->ItemIndexByID(i->first);
-    if (index == -1)
-      continue;
-    ash::LauncherItem item = model_->items()[index];
-    item.image = image;
-    model_->Set(index, item);
-    // It's possible we're waiting on more than one item, so don't break.
-  }
-}
-
-void ChromeLauncherControllerPerApp::OnAutoHideBehaviorChanged(
-    aura::RootWindow* root_window,
-    ash::ShelfAutoHideBehavior new_behavior) {
-  SetShelfAutoHideBehaviorPrefs(new_behavior, root_window);
-}
-
-void ChromeLauncherControllerPerApp::SetLauncherItemImage(
-    ash::LauncherID launcher_id,
-    const gfx::ImageSkia& image) {
-  int index = model_->ItemIndexByID(launcher_id);
-  if (index == -1)
-    return;
-  ash::LauncherItem item = model_->items()[index];
-  item.image = image;
-  model_->Set(index, item);
-}
-
-bool ChromeLauncherControllerPerApp::IsAppPinned(const std::string& app_id) {
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    if (IsPinned(i->first) && i->second->app_id() == app_id)
-      return true;
-  }
-  return false;
-}
-
-bool ChromeLauncherControllerPerApp::IsWindowedAppInLauncher(
-    const std::string& app_id) {
-  int index = model_->ItemIndexByID(GetLauncherIDForAppID(app_id));
-  if (index < 0)
-    return false;
-
-  ash::LauncherItemType type = model_->items()[index].type;
-  return type == ash::TYPE_WINDOWED_APP;
-}
-
-void ChromeLauncherControllerPerApp::PinAppWithID(const std::string& app_id) {
-  if (CanPin())
-    DoPinAppWithID(app_id);
-  else
-    NOTREACHED();
-}
-
-void ChromeLauncherControllerPerApp::SetLaunchType(
-    ash::LauncherID id,
-    extensions::ExtensionPrefs::LaunchType launch_type) {
-  if (!HasItemController(id))
-    return;
-
-  profile_->GetExtensionService()->extension_prefs()->SetLaunchType(
-      id_to_item_controller_map_[id]->app_id(), launch_type);
-}
-
-void ChromeLauncherControllerPerApp::UnpinAppsWithID(
-    const std::string& app_id) {
-  if (CanPin())
-    DoUnpinAppsWithID(app_id);
-  else
-    NOTREACHED();
-}
-
-bool ChromeLauncherControllerPerApp::IsLoggedInAsGuest() {
-  return ProfileManager::GetDefaultProfileOrOffTheRecord()->IsOffTheRecord();
-}
-
-void ChromeLauncherControllerPerApp::CreateNewWindow() {
-  chrome::NewEmptyWindow(
-      GetProfileForNewWindows(), chrome::HOST_DESKTOP_TYPE_ASH);
-}
-
-void ChromeLauncherControllerPerApp::CreateNewIncognitoWindow() {
-  chrome::NewEmptyWindow(GetProfileForNewWindows()->GetOffTheRecordProfile(),
-                         chrome::HOST_DESKTOP_TYPE_ASH);
-}
-
-bool ChromeLauncherControllerPerApp::CanPin() const {
-  const PrefService::Preference* pref =
-      profile_->GetPrefs()->FindPreference(prefs::kPinnedLauncherApps);
-  return pref && pref->IsUserModifiable();
-}
-
-void ChromeLauncherControllerPerApp::PersistPinnedState() {
-  if (ignore_persist_pinned_state_change_)
-    return;
-  // It is a coding error to call PersistPinnedState() if the pinned apps are
-  // not user-editable. The code should check earlier and not perform any
-  // modification actions that trigger persisting the state.
-  if (!CanPin()) {
-    NOTREACHED() << "Can't pin but pinned state being updated";
-    return;
-  }
-
-  // Mutating kPinnedLauncherApps is going to notify us and trigger us to
-  // process the change. We don't want that to happen so remove ourselves as a
-  // listener.
-  pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
-  {
-    ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
-    updater->Clear();
-    for (size_t i = 0; i < model_->items().size(); ++i) {
-      if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
-        ash::LauncherID id = model_->items()[i].id;
-        if (HasItemController(id) && IsPinned(id)) {
-          base::DictionaryValue* app_value = ash::CreateAppDict(
-              id_to_item_controller_map_[id]->app_id());
-          if (app_value)
-            updater->Append(app_value);
-        }
-      } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) {
-        PersistChromeItemIndex(i);
-      }
-    }
-  }
-  pref_change_registrar_.Add(
-      prefs::kPinnedLauncherApps,
-      base::Bind(&ChromeLauncherControllerPerApp::UpdateAppLaunchersFromPref,
-                 base::Unretained(this)));
-}
-
-ash::LauncherModel* ChromeLauncherControllerPerApp::model() {
-  return model_;
-}
-
-Profile* ChromeLauncherControllerPerApp::profile() {
-  return profile_;
-}
-
-ash::ShelfAutoHideBehavior
-    ChromeLauncherControllerPerApp::GetShelfAutoHideBehavior(
-        aura::RootWindow* root_window) const {
-  // Don't show the shelf in app mode.
-  if (chrome::IsRunningInAppMode())
-    return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
-
-  // See comment in |kShelfAlignment| as to why we consider two prefs.
-  const std::string behavior_value(
-      GetPrefForRootWindow(profile_->GetPrefs(),
-                           root_window,
-                           prefs::kShelfAutoHideBehaviorLocal,
-                           prefs::kShelfAutoHideBehavior));
-
-  // Note: To maintain sync compatibility with old images of chrome/chromeos
-  // the set of values that may be encountered includes the now-extinct
-  // "Default" as well as "Never" and "Always", "Default" should now
-  // be treated as "Never" (http://crbug.com/146773).
-  if (behavior_value == ash::kShelfAutoHideBehaviorAlways)
-    return ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
-  return ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER;
-}
-
-bool ChromeLauncherControllerPerApp::CanUserModifyShelfAutoHideBehavior(
-    aura::RootWindow* root_window) const {
-  return profile_->GetPrefs()->
-      FindPreference(prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
-}
-
-void ChromeLauncherControllerPerApp::ToggleShelfAutoHideBehavior(
-    aura::RootWindow* root_window) {
-  ash::ShelfAutoHideBehavior behavior = GetShelfAutoHideBehavior(root_window) ==
-      ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS ?
-          ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER :
-          ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
-  SetShelfAutoHideBehaviorPrefs(behavior, root_window);
-  return;
-}
-
-void ChromeLauncherControllerPerApp::RemoveTabFromRunningApp(
-    WebContents* tab,
-    const std::string& app_id) {
-  web_contents_to_app_id_.erase(tab);
-  AppIDToWebContentsListMap::iterator i_app_id =
-      app_id_to_web_contents_list_.find(app_id);
-  if (i_app_id != app_id_to_web_contents_list_.end()) {
-    WebContentsList* tab_list = &i_app_id->second;
-    tab_list->remove(tab);
-    if (tab_list->empty()) {
-      app_id_to_web_contents_list_.erase(i_app_id);
-      i_app_id = app_id_to_web_contents_list_.end();
-      ash::LauncherID id = GetLauncherIDForAppID(app_id);
-      if (id)
-        SetItemStatus(id, ash::STATUS_CLOSED);
-    }
-  }
-}
-
-void ChromeLauncherControllerPerApp::UpdateAppState(
-    content::WebContents* contents,
-    AppState app_state) {
-  std::string app_id = GetAppID(contents);
-
-  // Check if the gMail app is loaded and it matches the given content.
-  // This special treatment is needed to address crbug.com/234268.
-  if (app_id.empty() && ContentCanBeHandledByGmailApp(contents))
-    app_id = kGmailAppId;
-
-  // Check the old |app_id| for a tab. If the contents has changed we need to
-  // remove it from the previous app.
-  if (web_contents_to_app_id_.find(contents) != web_contents_to_app_id_.end()) {
-    std::string last_app_id = web_contents_to_app_id_[contents];
-    if (last_app_id != app_id)
-      RemoveTabFromRunningApp(contents, last_app_id);
-  }
-
-  if (app_id.empty()) {
-    // Even if there is no application running, we should update the activation
-    // state of the associated browser.
-    UpdateBrowserItemStatus();
-    return;
-  }
-
-  web_contents_to_app_id_[contents] = app_id;
-
-  if (app_state == APP_STATE_REMOVED) {
-    // The tab has gone away.
-    RemoveTabFromRunningApp(contents, app_id);
-  } else {
-    WebContentsList& tab_list(app_id_to_web_contents_list_[app_id]);
-
-    if (app_state == APP_STATE_INACTIVE) {
-      WebContentsList::const_iterator i_tab =
-          std::find(tab_list.begin(), tab_list.end(), contents);
-      if (i_tab == tab_list.end())
-        tab_list.push_back(contents);
-      if (i_tab != tab_list.begin()) {
-        // Going inactive, but wasn't the front tab, indicating that a new
-        // tab has already become active.
-        return;
-      }
-    } else {
-      tab_list.remove(contents);
-      tab_list.push_front(contents);
-    }
-    ash::LauncherID id = GetLauncherIDForAppID(app_id);
-    if (id) {
-      // If the window is active, mark the app as active.
-      SetItemStatus(id, app_state == APP_STATE_WINDOW_ACTIVE ?
-          ash::STATUS_ACTIVE : ash::STATUS_RUNNING);
-    }
-  }
-  UpdateBrowserItemStatus();
-}
-
-void ChromeLauncherControllerPerApp::SetRefocusURLPatternForTest(
-    ash::LauncherID id,
-    const GURL& url) {
-  DCHECK(HasItemController(id));
-  LauncherItemController* controller = id_to_item_controller_map_[id];
-
-  int index = model_->ItemIndexByID(id);
-  if (index == -1) {
-    NOTREACHED() << "Invalid launcher id";
-    return;
-  }
-
-  ash::LauncherItemType type = model_->items()[index].type;
-  if (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_WINDOWED_APP) {
-    AppShortcutLauncherItemController* app_controller =
-        static_cast<AppShortcutLauncherItemController*>(controller);
-    app_controller->set_refocus_url(url);
-  } else {
-    NOTREACHED() << "Invalid launcher type";
-  }
-}
-
-const Extension* ChromeLauncherControllerPerApp::GetExtensionForAppID(
-    const std::string& app_id) const {
-  // Some unit tests do not have a real extension.
-  return (profile_->GetExtensionService()) ?
-      profile_->GetExtensionService()->GetInstalledExtension(app_id) : NULL;
-}
-
-void ChromeLauncherControllerPerApp::ActivateWindowOrMinimizeIfActive(
-    ui::BaseWindow* window,
-    bool allow_minimize) {
-  if (window->IsActive() && allow_minimize) {
-    if (CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableMinimizeOnSecondLauncherItemClick)) {
-      AnimateWindow(window->GetNativeWindow(),
-                    views::corewm::WINDOW_ANIMATION_TYPE_BOUNCE);
-    } else {
-      window->Minimize();
-    }
-  } else {
-    window->Show();
-    window->Activate();
-  }
-}
-
-void ChromeLauncherControllerPerApp::ItemSelected(const ash::LauncherItem& item,
-                                                 const ui::Event& event) {
-  DCHECK(HasItemController(item.id));
-  LauncherItemController* item_controller = id_to_item_controller_map_[item.id];
-#if defined(OS_CHROMEOS)
-  if (!item_controller->app_id().empty()) {
-    chromeos::default_pinned_apps_field_trial::RecordShelfAppClick(
-        item_controller->app_id());
-  }
-#endif
-  item_controller->Clicked(event);
-}
-
-string16 ChromeLauncherControllerPerApp::GetTitle(
-    const ash::LauncherItem& item) {
-  DCHECK(HasItemController(item.id));
-  return id_to_item_controller_map_[item.id]->GetTitle();
-}
-
-ui::MenuModel* ChromeLauncherControllerPerApp::CreateContextMenu(
-    const ash::LauncherItem& item,
-    aura::RootWindow* root_window) {
-  return new LauncherContextMenu(this, &item, root_window);
-}
-
-ash::LauncherMenuModel* ChromeLauncherControllerPerApp::CreateApplicationMenu(
-    const ash::LauncherItem& item,
-    int event_flags) {
-  return new LauncherApplicationMenuItemModel(GetApplicationList(item,
-                                                                 event_flags));
-}
-
-ash::LauncherID ChromeLauncherControllerPerApp::GetIDByWindow(
-    aura::Window* window) {
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    if (i->second->HasWindow(window)) {
-      // Since this might be a reserved index, there might be no item in the
-      // launcher for it.
-      if (model_->ItemIndexByID(i->first) < 0)
-        break;
-      return i->first;
-    }
-  }
-  if (window->type() == aura::client::WINDOW_TYPE_NORMAL) {
-    // Coming here we are looking for the associated browser item as the
-    // default.
-    // TODO(flackr): This shouldn't return a default icon if no window is found.
-    //    The browser launcher item controller should know which windows it is
-    //    managing so that it is identified as the ID in the above loop.
-    int browser_index = ash::launcher::GetBrowserItemIndex(*model_);
-    // Note that there should always be a browser item in the launcher.
-    DCHECK_GE(browser_index, 0);
-    return model_->items()[browser_index].id;
-  }
-  return 0;
-}
-
-bool ChromeLauncherControllerPerApp::IsDraggable(
-    const ash::LauncherItem& item) {
-  return (item.type == ash::TYPE_APP_SHORTCUT ||
-          item.type == ash::TYPE_WINDOWED_APP) ? CanPin() : true;
-}
-
-bool ChromeLauncherControllerPerApp::ShouldShowTooltip(
-    const ash::LauncherItem& item) {
-  if (item.type == ash::TYPE_APP_PANEL &&
-      id_to_item_controller_map_[item.id]->IsVisible())
-    return false;
-  return true;
-}
-
-void ChromeLauncherControllerPerApp::OnLauncherCreated(
-    ash::Launcher* launcher) {
-  launchers_.insert(launcher);
-  launcher->shelf_widget()->shelf_layout_manager()->AddObserver(this);
-}
-
-void ChromeLauncherControllerPerApp::OnLauncherDestroyed(
-    ash::Launcher* launcher) {
-  launchers_.erase(launcher);
-  // RemoveObserver is not called here, since by the time this method is called
-  // Launcher is already in its destructor.
-}
-
-void ChromeLauncherControllerPerApp::LauncherItemAdded(int index) {
-}
-
-void ChromeLauncherControllerPerApp::LauncherItemRemoved(
-    int index,
-    ash::LauncherID id) {
-}
-
-void ChromeLauncherControllerPerApp::LauncherItemMoved(
-    int start_index,
-    int target_index) {
-  ash::LauncherID id = model_->items()[target_index].id;
-  if (HasItemController(id) && IsPinned(id))
-    PersistPinnedState();
-}
-
-void ChromeLauncherControllerPerApp::LauncherItemChanged(
-    int index,
-    const ash::LauncherItem& old_item) {
-  ash::LauncherID id = model_->items()[index].id;
-  DCHECK(HasItemController(id));
-  id_to_item_controller_map_[id]->LauncherItemChanged(index, old_item);
-}
-
-void ChromeLauncherControllerPerApp::LauncherStatusChanged() {
-}
-
-void ChromeLauncherControllerPerApp::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();
-      if (IsAppPinned(extension->id())) {
-        // Clear and re-fetch to ensure icon is up-to-date.
-        app_icon_loader_->ClearImage(extension->id());
-        app_icon_loader_->FetchImage(extension->id());
-      }
-
-      UpdateAppLaunchersFromPref();
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      const content::Details<extensions::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) {
-        CloseWindowedAppsFromRemovedExtension(id);
-      }
-
-      if (IsAppPinned(id)) {
-        if (unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
-          DoUnpinAppsWithID(id);
-          app_icon_loader_->ClearImage(id);
-        } else {
-          app_icon_loader_->UpdateImage(id);
-        }
-      }
-      break;
-    }
-    default:
-      NOTREACHED() << "Unexpected notification type=" << type;
-  }
-}
-
-void ChromeLauncherControllerPerApp::OnShelfAlignmentChanged(
-    aura::RootWindow* root_window) {
-  const char* pref_value = NULL;
-  switch (ash::Shell::GetInstance()->GetShelfAlignment(root_window)) {
-    case ash::SHELF_ALIGNMENT_BOTTOM:
-      pref_value = ash::kShelfAlignmentBottom;
-      break;
-    case ash::SHELF_ALIGNMENT_LEFT:
-      pref_value = ash::kShelfAlignmentLeft;
-      break;
-    case ash::SHELF_ALIGNMENT_RIGHT:
-      pref_value = ash::kShelfAlignmentRight;
-      break;
-    case ash::SHELF_ALIGNMENT_TOP:
-      pref_value = ash::kShelfAlignmentTop;
-  }
-
-  UpdatePerDisplayPref(
-      profile_->GetPrefs(), root_window, prefs::kShelfAlignment, pref_value);
-
-  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
-    // See comment in |kShelfAlignment| about why we have two prefs here.
-    profile_->GetPrefs()->SetString(prefs::kShelfAlignmentLocal, pref_value);
-    profile_->GetPrefs()->SetString(prefs::kShelfAlignment, pref_value);
-  }
-}
-
-void ChromeLauncherControllerPerApp::OnDisplayConfigurationChanging() {
-}
-
-void ChromeLauncherControllerPerApp::OnDisplayConfigurationChanged() {
-  SetShelfBehaviorsFromPrefs();
-}
-
-void ChromeLauncherControllerPerApp::OnIsSyncingChanged() {
-  PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
-  MaybePropagatePrefToLocal(prefs,
-                            prefs::kShelfAlignmentLocal,
-                            prefs::kShelfAlignment);
-  MaybePropagatePrefToLocal(prefs,
-                            prefs::kShelfAutoHideBehaviorLocal,
-                            prefs::kShelfAutoHideBehavior);
-}
-
-void ChromeLauncherControllerPerApp::OnAppSyncUIStatusChanged() {
-  if (app_sync_ui_state_->status() == AppSyncUIState::STATUS_SYNCING)
-    model_->SetStatus(ash::LauncherModel::STATUS_LOADING);
-  else
-    model_->SetStatus(ash::LauncherModel::STATUS_NORMAL);
-}
-
-void ChromeLauncherControllerPerApp::ExtensionEnableFlowFinished() {
-  LaunchApp(extension_enable_flow_->extension_id(), ui::EF_NONE);
-  extension_enable_flow_.reset();
-}
-
-void ChromeLauncherControllerPerApp::ExtensionEnableFlowAborted(
-    bool user_initiated) {
-  extension_enable_flow_.reset();
-}
-
-ChromeLauncherAppMenuItems ChromeLauncherControllerPerApp::GetApplicationList(
-    const ash::LauncherItem& item,
-    int event_flags) {
-  // Make sure that there is a controller associated with the id and that the
-  // extension itself is a valid application and not a panel.
-  if (!HasItemController(item.id) ||
-      !GetLauncherIDForAppID(id_to_item_controller_map_[item.id]->app_id()))
-    return ChromeLauncherAppMenuItems().Pass();
-
-  return id_to_item_controller_map_[item.id]->GetApplicationList(event_flags);
-}
-
-std::vector<content::WebContents*>
-ChromeLauncherControllerPerApp::GetV1ApplicationsFromAppId(
-    std::string app_id) {
-  ash::LauncherID id = GetLauncherIDForAppID(app_id);
-
-  // If there is no such an item pinned to the launcher, no menu gets created.
-  if (id) {
-    LauncherItemController* controller = id_to_item_controller_map_[id];
-    DCHECK(controller);
-    if (controller->type() == LauncherItemController::TYPE_SHORTCUT)
-      return GetV1ApplicationsFromController(controller);
-  }
-  return std::vector<content::WebContents*>();
-}
-
-void ChromeLauncherControllerPerApp::ActivateShellApp(
-    const std::string& app_id,
-    int index) {
-  ash::LauncherID id = GetLauncherIDForAppID(app_id);
-  if (id) {
-    LauncherItemController* controller = id_to_item_controller_map_[id];
-    if (controller->type() == LauncherItemController::TYPE_APP) {
-      ShellWindowLauncherItemController* shell_window_controller =
-          static_cast<ShellWindowLauncherItemController*>(controller);
-      shell_window_controller->ActivateIndexedApp(index);
-    }
-  }
-}
-
-bool ChromeLauncherControllerPerApp::IsWebContentHandledByApplication(
-    content::WebContents* web_contents,
-    const std::string& app_id) {
-  if ((web_contents_to_app_id_.find(web_contents) !=
-       web_contents_to_app_id_.end()) &&
-      (web_contents_to_app_id_[web_contents] == app_id))
-    return true;
-  return (app_id == kGmailAppId && ContentCanBeHandledByGmailApp(web_contents));
-}
-
-bool ChromeLauncherControllerPerApp::ContentCanBeHandledByGmailApp(
-    content::WebContents* web_contents) {
-  ash::LauncherID id = GetLauncherIDForAppID(kGmailAppId);
-  if (id) {
-    const GURL url = web_contents->GetURL();
-    // We need to extend the application matching for the gMail app beyond the
-    // manifest file's specification. This is required because of the namespace
-    // overlap with the offline app ("/mail/mu/").
-    if (!MatchPattern(url.path(), "/mail/mu/*") &&
-        MatchPattern(url.path(), "/mail/*") &&
-        GetExtensionForAppID(kGmailAppId) &&
-        GetExtensionForAppID(kGmailAppId)->OverlapsWithOrigin(url))
-      return true;
-  }
-  return false;
-}
-
-gfx::Image ChromeLauncherControllerPerApp::GetAppListIcon(
-    content::WebContents* web_contents) const {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  if (IsIncognito(web_contents))
-    return rb.GetImageNamed(IDR_AURA_LAUNCHER_LIST_INCOGNITO_BROWSER);
-  FaviconTabHelper* favicon_tab_helper =
-      FaviconTabHelper::FromWebContents(web_contents);
-  gfx::Image result = favicon_tab_helper->GetFavicon();
-  if (result.IsEmpty())
-    return rb.GetImageNamed(IDR_DEFAULT_FAVICON);
-  return result;
-}
-
-string16 ChromeLauncherControllerPerApp::GetAppListTitle(
-    content::WebContents* web_contents) const {
-  string16 title = web_contents->GetTitle();
-  if (!title.empty())
-    return title;
-  WebContentsToAppIDMap::const_iterator iter =
-      web_contents_to_app_id_.find(web_contents);
-  if (iter != web_contents_to_app_id_.end()) {
-    std::string app_id = iter->second;
-    const extensions::Extension* extension = GetExtensionForAppID(app_id);
-    if (extension)
-      return UTF8ToUTF16(extension->name());
-  }
-  return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
-}
-
-void ChromeLauncherControllerPerApp::OnBrowserRemoved(Browser* browser) {
-  // When called by a unit test it is possible that there is no shell.
-  // In that case, the following function should not get called.
-  if (ash::Shell::HasInstance())
-    UpdateBrowserItemStatus();
-}
-
-ash::LauncherID ChromeLauncherControllerPerApp::CreateAppShortcutLauncherItem(
-    const std::string& app_id,
-    int index) {
-  return CreateAppShortcutLauncherItemWithType(app_id,
-                                               index,
-                                               ash::TYPE_APP_SHORTCUT);
-}
-
-void ChromeLauncherControllerPerApp::SetAppTabHelperForTest(
-    AppTabHelper* helper) {
-  app_tab_helper_.reset(helper);
-}
-
-void ChromeLauncherControllerPerApp::SetAppIconLoaderForTest(
-    extensions::AppIconLoader* loader) {
-  app_icon_loader_.reset(loader);
-}
-
-const std::string&
-ChromeLauncherControllerPerApp::GetAppIdFromLauncherIdForTest(
-    ash::LauncherID id) {
-  return id_to_item_controller_map_[id]->app_id();
-}
-
-ash::LauncherID
-ChromeLauncherControllerPerApp::CreateAppShortcutLauncherItemWithType(
-    const std::string& app_id,
-    int index,
-    ash::LauncherItemType launcher_item_type) {
-  AppShortcutLauncherItemController* controller =
-      new AppShortcutLauncherItemController(app_id, this);
-  ash::LauncherID launcher_id = InsertAppLauncherItem(
-      controller, app_id, ash::STATUS_CLOSED, index, launcher_item_type);
-  return launcher_id;
-}
-
-void ChromeLauncherControllerPerApp::UpdateBrowserItemStatus() {
-  // Determine the new browser's active state and change if necessary.
-  size_t browser_index = ash::launcher::GetBrowserItemIndex(*model_);
-  DCHECK_GE(browser_index, 0u);
-  ash::LauncherItem browser_item = model_->items()[browser_index];
-  ash::LauncherItemStatus browser_status = ash::STATUS_CLOSED;
-
-  aura::Window* window = ash::wm::GetActiveWindow();
-  if (window) {
-    // Check if the active browser / tab is a browser which is not an app,
-    // a windowed app, a popup or any other item which is not a browser of
-    // interest.
-    Browser* browser = chrome::FindBrowserWithWindow(window);
-    if (IsBrowserRepresentedInBrowserList(browser)) {
-      browser_status = ash::STATUS_ACTIVE;
-      const ash::LauncherItems& items = model_->items();
-      // If another launcher item has claimed to be active, we don't.
-      for (size_t i = 0;
-           i < items.size() && browser_status == ash::STATUS_ACTIVE; ++i) {
-        if (i != browser_index && items[i].status == ash::STATUS_ACTIVE)
-          browser_status = ash::STATUS_RUNNING;
-      }
-    }
-  }
-
-  if (browser_status == ash::STATUS_CLOSED) {
-    const BrowserList* ash_browser_list =
-        BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
-    for (BrowserList::const_reverse_iterator it =
-             ash_browser_list->begin_last_active();
-         it != ash_browser_list->end_last_active() &&
-         browser_status == ash::STATUS_CLOSED; ++it) {
-      if (IsBrowserRepresentedInBrowserList(*it))
-        browser_status = ash::STATUS_RUNNING;
-    }
-  }
-
-  if (browser_status != browser_item.status) {
-    browser_item.status = browser_status;
-    model_->Set(browser_index, browser_item);
-  }
-}
-
-Profile* ChromeLauncherControllerPerApp::GetProfileForNewWindows() {
-  return ProfileManager::GetDefaultProfileOrOffTheRecord();
-}
-
-void ChromeLauncherControllerPerApp::LauncherItemClosed(ash::LauncherID id) {
-  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
-  CHECK(iter != id_to_item_controller_map_.end());
-  CHECK(iter->second);
-  app_icon_loader_->ClearImage(iter->second->app_id());
-  iter->second->OnRemoved();
-  id_to_item_controller_map_.erase(iter);
-  int index = model_->ItemIndexByID(id);
-  // A "browser proxy" is not known to the model and this removal does
-  // therefore not need to be propagated to the model.
-  if (index != -1)
-    model_->RemoveItemAt(index);
-}
-
-void ChromeLauncherControllerPerApp::DoPinAppWithID(
-    const std::string& app_id) {
-  // If there is an item, do nothing and return.
-  if (IsAppPinned(app_id))
-    return;
-
-  ash::LauncherID launcher_id = GetLauncherIDForAppID(app_id);
-  if (launcher_id) {
-    // App item exists, pin it
-    Pin(launcher_id);
-  } else {
-    // Otherwise, create a shortcut item for it.
-    CreateAppShortcutLauncherItem(app_id, model_->item_count());
-    if (CanPin())
-      PersistPinnedState();
-  }
-}
-
-void ChromeLauncherControllerPerApp::DoUnpinAppsWithID(
-    const std::string& app_id) {
-  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ) {
-    IDToItemControllerMap::iterator current(i);
-    ++i;
-    if (current->second->app_id() == app_id && IsPinned(current->first))
-      Unpin(current->first);
-  }
-}
-
-void ChromeLauncherControllerPerApp::UpdateAppLaunchersFromPref() {
-  // Construct a vector representation of to-be-pinned apps from the pref.
-  std::vector<std::string> pinned_apps;
-  int chrome_icon_index = GetChromeIconIndexFromPref();
-  const base::ListValue* pinned_apps_pref =
-      profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
-  for (base::ListValue::const_iterator it(pinned_apps_pref->begin());
-       it != pinned_apps_pref->end(); ++it) {
-    // To preserve the Chrome icon position, we insert a dummy slot for it - if
-    // the model has a Chrome item. While initializing we can come here with no
-    // item in which case the count would be 1 or below.
-    if (it - pinned_apps_pref->begin() == chrome_icon_index &&
-        model_->item_count() > 1) {
-      pinned_apps.push_back(extension_misc::kChromeAppId);
-    }
-
-    DictionaryValue* app = NULL;
-    std::string app_id;
-    if ((*it)->GetAsDictionary(&app) &&
-        app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) &&
-        std::find(pinned_apps.begin(), pinned_apps.end(), app_id) ==
-            pinned_apps.end() &&
-        app_tab_helper_->IsValidID(app_id)) {
-      pinned_apps.push_back(app_id);
-    }
-  }
-
-  // Walk the model and |pinned_apps| from the pref lockstep, adding and
-  // removing items as necessary. NB: This code uses plain old indexing instead
-  // of iterators because of model mutations as part of the loop.
-  std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
-  int index = 0;
-  int max_index = model_->item_count();
-  // Using the alternate shelf layout the App Icon should be the first item in
-  // the list thus start adding items at slot 1 (instead of slot 0).
-  if (ash::switches::UseAlternateShelfLayout()) {
-    ++index;
-    ++max_index;
-  }
-  for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
-    // If the next app launcher according to the pref is present in the model,
-    // delete all app launcher entries in between.
-    if (*pref_app_id == extension_misc::kChromeAppId ||
-        IsAppPinned(*pref_app_id)) {
-      for (; index < max_index; ++index) {
-        const ash::LauncherItem& item(model_->items()[index]);
-        if (item.type != ash::TYPE_APP_SHORTCUT &&
-            item.type != ash::TYPE_BROWSER_SHORTCUT)
-          continue;
-
-        IDToItemControllerMap::const_iterator entry =
-            id_to_item_controller_map_.find(item.id);
-        if ((extension_misc::kChromeAppId == *pref_app_id &&
-             item.type == ash::TYPE_BROWSER_SHORTCUT) ||
-            (entry != id_to_item_controller_map_.end() &&
-             entry->second->app_id() == *pref_app_id)) {
-          ++pref_app_id;
-          break;
-        } else {
-          if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
-            // We cannot delete the browser shortcut. As such we move it up by
-            // one. To avoid any side effects from our pinned state observer, we
-            // do not call the model directly.
-            MoveItemWithoutPinnedStateChangeNotification(index, index + 1);
-          } else {
-            LauncherItemClosed(item.id);
-            --max_index;
-          }
-          --index;
-        }
-      }
-      // If the item wasn't found, that means id_to_item_controller_map_
-      // is out of sync.
-      DCHECK(index < max_index);
-    } else {
-      // This app wasn't pinned before, insert a new entry.
-      ash::LauncherID id = CreateAppShortcutLauncherItem(*pref_app_id, index);
-      index = model_->ItemIndexByID(id);
-      ++pref_app_id;
-    }
-  }
-
-  // Remove any trailing existing items.
-  while (index < model_->item_count()) {
-    const ash::LauncherItem& item(model_->items()[index]);
-    if (item.type == ash::TYPE_APP_SHORTCUT)
-      LauncherItemClosed(item.id);
-    else
-      ++index;
-  }
-
-  // Append unprocessed items from the pref to the end of the model.
-  for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
-    // Ignore the chrome icon.
-    if (*pref_app_id != extension_misc::kChromeAppId)
-      DoPinAppWithID(*pref_app_id);
-  }
-
-}
-
-void ChromeLauncherControllerPerApp::SetShelfAutoHideBehaviorPrefs(
-    ash::ShelfAutoHideBehavior behavior,
-    aura::RootWindow* root_window) {
-  const char* value = NULL;
-  switch (behavior) {
-    case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
-      value = ash::kShelfAutoHideBehaviorAlways;
-      break;
-    case ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
-      value = ash::kShelfAutoHideBehaviorNever;
-      break;
-    case ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
-      // This one should not be a valid preference option for now. We only want
-      // to completely hide it when we run app mode.
-      NOTREACHED();
-      return;
-  }
-
-  UpdatePerDisplayPref(
-      profile_->GetPrefs(), root_window, prefs::kShelfAutoHideBehavior, value);
-
-  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
-    // See comment in |kShelfAlignment| about why we have two prefs here.
-    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehaviorLocal, value);
-    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehavior, value);
-  }
-}
-
-void ChromeLauncherControllerPerApp::SetShelfAutoHideBehaviorFromPrefs() {
-  ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
-
-  for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
-        GetShelfAutoHideBehavior(*iter), *iter);
-  }
-}
-
-void ChromeLauncherControllerPerApp::SetShelfAlignmentFromPrefs() {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kShowShelfAlignmentMenu))
-    return;
-
-  ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
-
-  for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    // See comment in |kShelfAlignment| as to why we consider two prefs.
-    const std::string alignment_value(
-        GetPrefForRootWindow(profile_->GetPrefs(),
-                             *iter,
-                             prefs::kShelfAlignmentLocal,
-                             prefs::kShelfAlignment));
-    ash::ShelfAlignment alignment = ash::SHELF_ALIGNMENT_BOTTOM;
-    if (alignment_value == ash::kShelfAlignmentLeft)
-      alignment = ash::SHELF_ALIGNMENT_LEFT;
-    else if (alignment_value == ash::kShelfAlignmentRight)
-      alignment = ash::SHELF_ALIGNMENT_RIGHT;
-    else if (alignment_value == ash::kShelfAlignmentTop)
-      alignment = ash::SHELF_ALIGNMENT_TOP;
-    ash::Shell::GetInstance()->SetShelfAlignment(alignment, *iter);
-  }
-}
-
-void ChromeLauncherControllerPerApp::SetShelfBehaviorsFromPrefs() {
-  SetShelfAutoHideBehaviorFromPrefs();
-  SetShelfAlignmentFromPrefs();
-}
-
-WebContents* ChromeLauncherControllerPerApp::GetLastActiveWebContents(
-    const std::string& app_id) {
-  AppIDToWebContentsListMap::const_iterator i =
-      app_id_to_web_contents_list_.find(app_id);
-  if (i == app_id_to_web_contents_list_.end())
-    return NULL;
-  DCHECK_GT(i->second.size(), 0u);
-  return *i->second.begin();
-}
-
-ash::LauncherID ChromeLauncherControllerPerApp::InsertAppLauncherItem(
-    LauncherItemController* controller,
-    const std::string& app_id,
-    ash::LauncherItemStatus status,
-    int index,
-    ash::LauncherItemType launcher_item_type) {
-  ash::LauncherID id = model_->next_id();
-  CHECK(!HasItemController(id));
-  CHECK(controller);
-  id_to_item_controller_map_[id] = controller;
-  controller->set_launcher_id(id);
-
-  ash::LauncherItem item;
-  item.type = launcher_item_type;
-  item.is_incognito = false;
-  item.image = extensions::IconsInfo::GetDefaultAppIcon();
-
-  WebContents* active_tab = GetLastActiveWebContents(app_id);
-  if (active_tab) {
-    Browser* browser = chrome::FindBrowserWithWebContents(active_tab);
-    DCHECK(browser);
-    if (browser->window()->IsActive())
-      status = ash::STATUS_ACTIVE;
-    else
-      status = ash::STATUS_RUNNING;
-  }
-  item.status = status;
-
-  model_->AddAt(index, item);
-
-  app_icon_loader_->FetchImage(app_id);
-
-  return id;
-}
-
-bool ChromeLauncherControllerPerApp::HasItemController(
-    ash::LauncherID id) const {
-  return id_to_item_controller_map_.find(id) !=
-         id_to_item_controller_map_.end();
-}
-
-std::vector<content::WebContents*>
-ChromeLauncherControllerPerApp::GetV1ApplicationsFromController(
-    LauncherItemController* controller) {
-  DCHECK(controller->type() == LauncherItemController::TYPE_SHORTCUT);
-  AppShortcutLauncherItemController* app_controller =
-      static_cast<AppShortcutLauncherItemController*>(controller);
-  return app_controller->GetRunningApplications();
-}
-
-bool ChromeLauncherControllerPerApp::IsBrowserRepresentedInBrowserList(
-    Browser* browser) {
-  return (browser &&
-          (browser->is_type_tabbed() ||
-           !browser->is_app() ||
-           !browser->is_type_popup() ||
-           GetLauncherIDForAppID(web_app::GetExtensionIdFromApplicationName(
-               browser->app_name())) <= 0));
-}
-
-LauncherItemController*
-ChromeLauncherControllerPerApp::GetBrowserShortcutLauncherItemController() {
-  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
-      i != id_to_item_controller_map_.end(); ++i) {
-    int index = model_->ItemIndexByID(i->first);
-    const ash::LauncherItem& item = model_->items()[index];
-    if (item.type == ash::TYPE_BROWSER_SHORTCUT)
-      return i->second;
-  }
-  // LauncerItemController For Browser Shortcut must be existed. If it does not
-  // existe create it.
-  ash::LauncherID id = CreateBrowserShortcutLauncherItem();
-  DCHECK(id_to_item_controller_map_[id]);
-  return id_to_item_controller_map_[id];
-}
-
-ash::LauncherID
-ChromeLauncherControllerPerApp::CreateBrowserShortcutLauncherItem() {
-  ash::LauncherItem browser_shortcut;
-  browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT;
-  browser_shortcut.is_incognito = false;
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
-  ash::LauncherID id = model_->next_id();
-  size_t index = GetChromeIconIndexFromPref();
-  model_->AddAt(index, browser_shortcut);
-  browser_item_controller_.reset(
-      new BrowserShortcutLauncherItemController(this, profile_));
-  id_to_item_controller_map_[id] = browser_item_controller_.get();
-  id_to_item_controller_map_[id]->set_launcher_id(id);
-  return id;
-}
-
-void ChromeLauncherControllerPerApp::PersistChromeItemIndex(int index) {
-  profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index);
-}
-
-int ChromeLauncherControllerPerApp::GetChromeIconIndexFromPref() const {
-  size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
-  const base::ListValue* pinned_apps_pref =
-      profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
-  if (ash::switches::UseAlternateShelfLayout())
-    return std::max(static_cast<size_t>(1),
-                    std::min(pinned_apps_pref->GetSize(), index));
-  return std::max(static_cast<size_t>(0),
-                  std::min(pinned_apps_pref->GetSize(), index));
-}
-
-bool ChromeLauncherControllerPerApp::IsIncognito(
-    content::WebContents* web_contents) const {
-  const Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext());
-  return profile->IsOffTheRecord() && !profile->IsGuestSession();
-}
-
-void ChromeLauncherControllerPerApp::CloseWindowedAppsFromRemovedExtension(
-    const std::string& app_id) {
-  // This function cannot rely on the controller's enumeration functionality
-  // since the extension has already be unloaded.
-  const BrowserList* ash_browser_list =
-      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
-  std::vector<Browser*> browser_to_close;
-  for (BrowserList::const_reverse_iterator
-           it = ash_browser_list->begin_last_active();
-       it != ash_browser_list->end_last_active(); ++it) {
-    Browser* browser = *it;
-    if (!browser->is_type_tabbed() &&
-        browser->is_type_popup() &&
-        browser->is_app() &&
-        app_id == web_app::GetExtensionIdFromApplicationName(
-            browser->app_name())) {
-      browser_to_close.push_back(browser);
-    }
-  }
-  while (!browser_to_close.empty()) {
-    TabStripModel* tab_strip = browser_to_close.back()->tab_strip_model();
-    tab_strip->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
-    browser_to_close.pop_back();
-  }
-}
-
-void
-ChromeLauncherControllerPerApp::MoveItemWithoutPinnedStateChangeNotification(
-    int source_index, int target_index) {
-  base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true);
-  model_->Move(source_index, target_index);
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h
deleted file mode 100644
index 951589c..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h
+++ /dev/null
@@ -1,508 +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_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_PER_APP_H_
-#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_PER_APP_H_
-
-#include <list>
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "ash/display/display_controller.h"
-#include "ash/launcher/launcher_model_observer.h"
-#include "ash/launcher/launcher_types.h"
-#include "ash/shelf/shelf_layout_manager_observer.h"
-#include "ash/shelf/shelf_types.h"
-#include "ash/shell_observer.h"
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
-#include "base/prefs/pref_change_registrar.h"
-#include "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/prefs/pref_service_syncable_observer.h"
-#include "chrome/browser/ui/ash/app_sync_ui_state_observer.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.h"
-#include "chrome/browser/ui/browser_list_observer.h"
-#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "ui/aura/window_observer.h"
-
-class AppSyncUIState;
-class Browser;
-class BrowserLauncherItemControllerTest;
-class BrowserShortcutLauncherItemController;
-class ExtensionEnableFlow;
-class LauncherItemController;
-class Profile;
-class TabContents;
-
-namespace ash {
-class LauncherModel;
-}
-
-namespace aura {
-class Window;
-}
-
-namespace content {
-class WebContents;
-}
-
-namespace ui {
-class BaseWindow;
-}
-
-// ChromeLauncherControllerPerApp manages the launcher items needed for content
-// content windows. Launcher items have a type, an optional app id, and a
-// controller. This incarnation groups running tabs/windows in application
-// specific lists.
-// * Tabbed browsers and browser app windows have BrowserLauncherItemController,
-//   owned by the BrowserView instance.
-// * App shell windows have ShellWindowLauncherItemController, owned by
-//   ShellWindowLauncherController.
-// * Shortcuts have no LauncherItemController.
-class ChromeLauncherControllerPerApp
-    : public ash::LauncherModelObserver,
-      public ash::ShellObserver,
-      public ash::DisplayController::Observer,
-      public ChromeLauncherController,
-      public content::NotificationObserver,
-      public PrefServiceSyncableObserver,
-      public AppSyncUIStateObserver,
-      public ExtensionEnableFlowDelegate,
-      public chrome::BrowserListObserver,
-      public ash::ShelfLayoutManagerObserver {
- public:
-  ChromeLauncherControllerPerApp(Profile* profile, ash::LauncherModel* model);
-  virtual ~ChromeLauncherControllerPerApp();
-
-  // ChromeLauncherController overrides:
-
-  // Initializes this ChromeLauncherControllerPerApp.
-  virtual void Init() OVERRIDE;
-
-  // Returns the new per application interface of the given launcher. If it is
-  // a per browser (old) controller, it will return NULL;
-  // TODO(skuhne): Remove when we rip out the old launcher.
-  virtual ChromeLauncherControllerPerApp* GetPerAppInterface() OVERRIDE;
-
-  // Creates a new tabbed item on the launcher for |controller|.
-  virtual ash::LauncherID CreateTabbedLauncherItem(
-      LauncherItemController* controller,
-      IncognitoState is_incognito,
-      ash::LauncherItemStatus status) OVERRIDE;
-
-  // Creates a new app item on the launcher for |controller|.
-  virtual ash::LauncherID CreateAppLauncherItem(
-      LauncherItemController* controller,
-      const std::string& app_id,
-      ash::LauncherItemStatus status) OVERRIDE;
-
-  // Updates the running status of an item. It will also update the status of
-  // browsers launcher item if needed.
-  virtual void SetItemStatus(ash::LauncherID id,
-                             ash::LauncherItemStatus status) OVERRIDE;
-
-  // Updates the controller associated with id (which should be a shortcut).
-  // |controller| remains owned by caller.
-  virtual void SetItemController(ash::LauncherID id,
-                                 LauncherItemController* controller) OVERRIDE;
-
-  // Closes or unpins the launcher item.
-  virtual void CloseLauncherItem(ash::LauncherID id) OVERRIDE;
-
-  // Pins the specified id. Currently only supports platform apps.
-  virtual void Pin(ash::LauncherID id) OVERRIDE;
-
-  // Unpins the specified id, closing if not running.
-  virtual void Unpin(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the item identified by |id| is pinned.
-  virtual bool IsPinned(ash::LauncherID id) OVERRIDE;
-
-  // Pins/unpins the specified id.
-  virtual void TogglePinned(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the specified item can be pinned or unpinned. Only apps can
-  // be pinned.
-  virtual bool IsPinnable(ash::LauncherID id) const OVERRIDE;
-
-  // If there is no launcher item in the launcher for application |app_id|, one
-  // gets created. The (existing or created) launcher items get then locked
-  // against a users un-pinning removal.
-  virtual void LockV1AppWithID(const std::string& app_id) OVERRIDE;
-
-  // A previously locked launcher item of type |app_id| gets unlocked. If the
-  // lock count reaches 0 and the item is not pinned it will go away.
-  virtual void UnlockV1AppWithID(const std::string& app_id) OVERRIDE;
-
-  // Requests that the launcher item controller specified by |id| open a new
-  // instance of the app.  |event_flags| holds the flags of the event which
-  // triggered this command.
-  virtual void Launch(ash::LauncherID id, int event_flags) OVERRIDE;
-
-  // Closes the specified item.
-  virtual void Close(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the specified item is open.
-  virtual bool IsOpen(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the specified item is for a platform app.
-  virtual bool IsPlatformApp(ash::LauncherID id) OVERRIDE;
-
-  // Opens a new instance of the application identified by |app_id|.
-  // Used by the app-list, and by pinned-app launcher items.
-  virtual void LaunchApp(const std::string& app_id, int event_flags) OVERRIDE;
-
-  // If |app_id| is running, reactivates the app's most recently active window,
-  // otherwise launches and activates the app.
-  // Used by the app-list, and by pinned-app launcher items.
-  virtual void ActivateApp(const std::string& app_id, int event_flags) OVERRIDE;
-
-  // Returns the launch type of app for the specified id.
-  virtual extensions::ExtensionPrefs::LaunchType GetLaunchType(
-      ash::LauncherID id) OVERRIDE;
-
-  // Returns the id of the app for the specified tab.
-  virtual std::string GetAppID(content::WebContents* tab) OVERRIDE;
-
-  // Returns the |LauncherModel|'s ID or 0 if the AppId was not found.
-  virtual ash::LauncherID GetLauncherIDForAppID(
-      const std::string& app_id) OVERRIDE;
-  virtual std::string GetAppIDForLauncherID(ash::LauncherID id) OVERRIDE;
-
-  // Set the image for a specific launcher item (e.g. when set by the app).
-  virtual void SetLauncherItemImage(ash::LauncherID launcher_id,
-                                    const gfx::ImageSkia& image) OVERRIDE;
-
-  // Returns true if a pinned launcher item with given |app_id| could be found.
-  virtual bool IsAppPinned(const std::string& app_id) OVERRIDE;
-
-  // Find out if the given application |id| is a windowed app item and not a
-  // pinned item in the launcher.
-  bool IsWindowedAppInLauncher(const std::string& app_id);
-
-  // Pins an app with |app_id| to launcher. If there is a running instance in
-  // launcher, the running instance is pinned. If there is no running instance,
-  // a new launcher item is created and pinned.
-  virtual void PinAppWithID(const std::string& app_id) OVERRIDE;
-
-  // Updates the launche type of the app for the specified id to |launch_type|.
-  virtual void SetLaunchType(
-      ash::LauncherID id,
-      extensions::ExtensionPrefs::LaunchType launch_type) OVERRIDE;
-
-  // Unpins any app items whose id is |app_id|.
-  virtual void UnpinAppsWithID(const std::string& app_id) OVERRIDE;
-
-  // Returns true if the user is currently logged in as a guest.
-  virtual bool IsLoggedInAsGuest() OVERRIDE;
-
-  // Invoked when user clicks on button in the launcher and there is no last
-  // used window (or CTRL is held with the click).
-  virtual void CreateNewWindow() OVERRIDE;
-
-  // Invoked when the user clicks on button in the launcher to create a new
-  // incognito window.
-  virtual void CreateNewIncognitoWindow() OVERRIDE;
-
-  // Checks whether the user is allowed to pin apps. Pinning may be disallowed
-  // by policy in case there is a pre-defined set of pinned apps.
-  virtual bool CanPin() const OVERRIDE;
-
-  // Updates the pinned pref state. The pinned state consists of a list pref.
-  // Each item of the list is a dictionary. The key |kAppIDPath| gives the
-  // id of the app.
-  virtual void PersistPinnedState() OVERRIDE;
-
-  virtual ash::LauncherModel* model() OVERRIDE;
-
-  virtual Profile* profile() OVERRIDE;
-
-  // Gets the shelf auto-hide behavior on |root_window|.
-  virtual ash::ShelfAutoHideBehavior GetShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const OVERRIDE;
-
-  // Returns |true| if the user is allowed to modify the shelf auto-hide
-  // behavior on |root_window|.
-  virtual bool CanUserModifyShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const OVERRIDE;
-
-  // Toggles the shelf auto-hide behavior on |root_window|. Does nothing if the
-  // user is not allowed to modify the auto-hide behavior.
-  virtual void ToggleShelfAutoHideBehavior(
-      aura::RootWindow* root_window) OVERRIDE;
-
-  // The tab no longer represents its previously identified application.
-  virtual void RemoveTabFromRunningApp(content::WebContents* tab,
-                                       const std::string& app_id) OVERRIDE;
-
-  // Notify the controller that the state of an non platform app's tabs
-  // have changed,
-  virtual void UpdateAppState(content::WebContents* contents,
-                              AppState app_state) OVERRIDE;
-
-  // Limits application refocusing to urls that match |url| for |id|.
-  virtual void SetRefocusURLPatternForTest(ash::LauncherID id,
-                                           const GURL& url) OVERRIDE;
-
-  // Returns the extension identified by |app_id|.
-  virtual const extensions::Extension* GetExtensionForAppID(
-      const std::string& app_id) const OVERRIDE;
-
-  // Activates a |window|. If |allow_minimize| is true and the system allows
-  // it, the the window will get minimized instead.
-  virtual void ActivateWindowOrMinimizeIfActive(ui::BaseWindow* window,
-                                                bool allow_minimize) OVERRIDE;
-
-  // ash::LauncherDelegate overrides:
-  virtual void ItemSelected(const ash::LauncherItem& item,
-                           const ui::Event& event) OVERRIDE;
-  virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE;
-  virtual ui::MenuModel* CreateContextMenu(
-      const ash::LauncherItem& item, aura::RootWindow* root) OVERRIDE;
-  virtual ash::LauncherMenuModel* CreateApplicationMenu(
-      const ash::LauncherItem& item,
-      int event_flags) OVERRIDE;
-  virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE;
-  virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE;
-  virtual bool ShouldShowTooltip(const ash::LauncherItem& item) OVERRIDE;
-  virtual void OnLauncherCreated(ash::Launcher* launcher) OVERRIDE;
-  virtual void OnLauncherDestroyed(ash::Launcher* launcher) OVERRIDE;
-
-  // ash::LauncherModelObserver overrides:
-  virtual void LauncherItemAdded(int index) OVERRIDE;
-  virtual void LauncherItemRemoved(int index, ash::LauncherID id) OVERRIDE;
-  virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE;
-  virtual void LauncherItemChanged(int index,
-                                   const ash::LauncherItem& old_item) OVERRIDE;
-  virtual void LauncherStatusChanged() OVERRIDE;
-
-  // content::NotificationObserver overrides:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // ash::ShellObserver overrides:
-  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) OVERRIDE;
-
-  // ash::DisplayController::Observer overrides:
-  virtual void OnDisplayConfigurationChanging() OVERRIDE;
-  virtual void OnDisplayConfigurationChanged() OVERRIDE;
-
-  // PrefServiceSyncableObserver overrides:
-  virtual void OnIsSyncingChanged() OVERRIDE;
-
-  // AppSyncUIStateObserver overrides:
-  virtual void OnAppSyncUIStatusChanged() OVERRIDE;
-
-  // ExtensionEnableFlowDelegate overrides:
-  virtual void ExtensionEnableFlowFinished() OVERRIDE;
-  virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
-
-  // extensions::AppIconLoader overrides:
-  virtual void SetAppImage(const std::string& app_id,
-                           const gfx::ImageSkia& image) OVERRIDE;
-
-  // ash::ShelfLayoutManagerObserver overrides:
-  virtual void OnAutoHideBehaviorChanged(
-      aura::RootWindow* root_window,
-      ash::ShelfAutoHideBehavior new_behavior) OVERRIDE;
-
-  // 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.
-  ChromeLauncherAppMenuItems GetApplicationList(const ash::LauncherItem& item,
-                                                int event_flags);
-
-  // Get the list of all tabs which belong to a certain application type.
-  std::vector<content::WebContents*> GetV1ApplicationsFromAppId(
-      std::string app_id);
-
-  // Activates a specified shell application.
-  void ActivateShellApp(const std::string& app_id, int index);
-
-  // Checks if a given |web_contents| is known to be associated with an
-  // application of type |app_id|.
-  bool IsWebContentHandledByApplication(content::WebContents* web_contents,
-                                        const std::string& app_id);
-
-  // Check if the gMail app is loaded and it can handle the given web content.
-  // This special treatment is required to address crbug.com/234268.
-  bool ContentCanBeHandledByGmailApp(content::WebContents* web_contents);
-
-  // Get the favicon for the application list entry for |web_contents|.
-  // Note that for incognito windows the incognito icon will be returned.
-  // If |web_contents| has not loaded, returns the default favicon.
-  gfx::Image GetAppListIcon(content::WebContents* web_contents) const;
-
-  // Get the title for the applicatoin list entry for |web_contents|.
-  // If |web_contents| has not loaded, returns "Net Tab".
-  string16 GetAppListTitle(content::WebContents* web_contents) const;
-
-  // Overridden from chrome::BrowserListObserver.
-  virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
-
-  // Returns true when the given |browser| is listed in the browser application
-  // list.
-  bool IsBrowserRepresentedInBrowserList(Browser* browser);
-
-  // Returns the LauncherItemController of BrowserShortcut.
-  LauncherItemController* GetBrowserShortcutLauncherItemController();
-
- protected:
-  // ChromeLauncherController overrides:
-
-  // Creates a new app shortcut item and controller on the launcher at |index|.
-  // Use kInsertItemAtEnd to add a shortcut as the last item.
-  virtual ash::LauncherID CreateAppShortcutLauncherItem(
-      const std::string& app_id,
-      int index) OVERRIDE;
-
-  // Sets the AppTabHelper/AppIconLoader, taking ownership of the helper class.
-  // These are intended for testing.
-  virtual void SetAppTabHelperForTest(AppTabHelper* helper) OVERRIDE;
-  virtual void SetAppIconLoaderForTest(
-      extensions::AppIconLoader* loader) OVERRIDE;
-  virtual const std::string& GetAppIdFromLauncherIdForTest(
-      ash::LauncherID id) OVERRIDE;
-
- private:
-  friend class ChromeLauncherControllerPerAppTest;
-  friend class LauncherPerAppAppBrowserTest;
-  friend class LauncherPlatformPerAppAppBrowserTest;
-
-  // Creates a new app shortcut item and controller on the launcher at |index|.
-   // Use kInsertItemAtEnd to add a shortcut as the last item.
-   virtual ash::LauncherID CreateAppShortcutLauncherItemWithType(
-       const std::string& app_id,
-       int index,
-       ash::LauncherItemType launcher_item_type);
-
-  // Updates the activation state of the Broswer item.
-  void UpdateBrowserItemStatus();
-
-  typedef std::map<ash::LauncherID, LauncherItemController*>
-          IDToItemControllerMap;
-  typedef std::list<content::WebContents*> WebContentsList;
-  typedef std::map<std::string, WebContentsList> AppIDToWebContentsListMap;
-  typedef std::map<content::WebContents*, std::string> WebContentsToAppIDMap;
-
-  // Returns the profile used for new windows.
-  Profile* GetProfileForNewWindows();
-
-  // Invoked when the associated browser or app is closed.
-  void LauncherItemClosed(ash::LauncherID id);
-
-  // Internal helpers for pinning and unpinning that handle both
-  // client-triggered and internal pinning operations.
-  void DoPinAppWithID(const std::string& app_id);
-  void DoUnpinAppsWithID(const std::string& app_id);
-
-  // Re-syncs launcher model with prefs::kPinnedLauncherApps.
-  void UpdateAppLaunchersFromPref();
-
-  // Persists the shelf auto-hide behavior to prefs.
-  void SetShelfAutoHideBehaviorPrefs(ash::ShelfAutoHideBehavior behavior,
-                                     aura::RootWindow* root_window);
-
-  // Sets the shelf auto-hide behavior from prefs.
-  void SetShelfAutoHideBehaviorFromPrefs();
-
-  // Sets the shelf alignment from prefs.
-  void SetShelfAlignmentFromPrefs();
-
-  // Sets both of auto-hide behavior and alignment from prefs.
-  void SetShelfBehaviorsFromPrefs();
-
-  // Returns the most recently active web contents for an app.
-  content::WebContents* GetLastActiveWebContents(const std::string& app_id);
-
-  // Creates an app launcher to insert at |index|. Note that |index| may be
-  // adjusted by the model to meet ordering constraints.
-  // The |launcher_item_type| will be set into the LauncherModel.
-  ash::LauncherID InsertAppLauncherItem(
-      LauncherItemController* controller,
-      const std::string& app_id,
-      ash::LauncherItemStatus status,
-      int index,
-      ash::LauncherItemType launcher_item_type);
-
-  bool HasItemController(ash::LauncherID id) const;
-
-  // Enumerate all Web contents which match a given shortcut |controller|.
-  std::vector<content::WebContents*> GetV1ApplicationsFromController(
-      LauncherItemController* controller);
-
-  // Create LauncherItem for Browser Shortcut.
-  ash::LauncherID CreateBrowserShortcutLauncherItem();
-
-  // Check if the given |web_contents| is in incognito mode.
-  bool IsIncognito(content::WebContents* web_contents) const;
-
-  // Update browser shortcut's index.
-  void PersistChromeItemIndex(int index);
-
-  // Get browser shortcut's index from pref.
-  int GetChromeIconIndexFromPref() const;
-
-  // Close all windowed V1 applications of a certain extension which was already
-  // deleted.
-  void CloseWindowedAppsFromRemovedExtension(const std::string& app_id);
-
-  // Move a launcher item ignoring the pinned state changes from |index| to
-  // |target_index|.
-  void MoveItemWithoutPinnedStateChangeNotification(int source_index,
-                                                    int target_index);
-
-  ash::LauncherModel* model_;
-
-  // Profile used for prefs and loading extensions. This is NOT necessarily the
-  // profile new windows are created with.
-  Profile* profile_;
-
-  IDToItemControllerMap id_to_item_controller_map_;
-
-  // Maintains activation order of web contents for each app.
-  AppIDToWebContentsListMap app_id_to_web_contents_list_;
-
-  // Direct access to app_id for a web contents.
-  WebContentsToAppIDMap web_contents_to_app_id_;
-
-  // Used to track shell windows.
-  scoped_ptr<ShellWindowLauncherController> shell_window_controller_;
-
-  // Used to get app info for tabs.
-  scoped_ptr<AppTabHelper> app_tab_helper_;
-
-  // Used to load the image for an app item.
-  scoped_ptr<extensions::AppIconLoader> app_icon_loader_;
-
-  content::NotificationRegistrar notification_registrar_;
-
-  PrefChangeRegistrar pref_change_registrar_;
-
-  AppSyncUIState* app_sync_ui_state_;
-
-  scoped_ptr<ExtensionEnableFlow> extension_enable_flow_;
-
-  // Launchers that are currently being observed.
-  std::set<ash::Launcher*> launchers_;
-
-  // The owned browser shortcut item.
-  scoped_ptr<BrowserShortcutLauncherItemController> browser_item_controller_;
-
-  // If true, incoming pinned state changes should be ignored.
-  bool ignore_persist_pinned_state_change_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerPerApp);
-};
-
-#endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_PER_APP_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_browsertest.cc
deleted file mode 100644
index 248b19a..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_browsertest.cc
+++ /dev/null
@@ -1,1582 +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/launcher/chrome_launcher_controller.h"
-
-#include "apps/native_app_window.h"
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
-#include "ash/ash_switches.h"
-#include "ash/display/display_controller.h"
-#include "ash/launcher/launcher.h"
-#include "ash/launcher/launcher_model.h"
-#include "ash/launcher/launcher_util.h"
-#include "ash/launcher/launcher_view.h"
-#include "ash/shell.h"
-#include "ash/test/launcher_view_test_api.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/wm/window_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/automation/automation_util.h"
-#include "chrome/browser/chrome_notification_types.h"
-#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/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_browsertest_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/app_list/app_list_service.h"
-#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
-#include "chrome/browser/ui/ash/launcher/launcher_item_controller.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_list.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/common/switches.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/app_list/views/apps_grid_view.h"
-#include "ui/aura/test/event_generator.h"
-#include "ui/aura/window.h"
-#include "ui/base/events/event.h"
-
-using apps::ShellWindow;
-using extensions::Extension;
-using content::WebContents;
-
-namespace {
-
-class TestEvent : public ui::Event {
- public:
-  explicit TestEvent(ui::EventType type)
-      : ui::Event(type, base::TimeDelta(), 0) {
-  }
-  virtual ~TestEvent() {
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestEvent);
-};
-
-class TestShellWindowRegistryObserver
-    : public apps::ShellWindowRegistry::Observer {
- public:
-  explicit TestShellWindowRegistryObserver(Profile* profile)
-      : profile_(profile),
-        icon_updates_(0) {
-    apps::ShellWindowRegistry::Get(profile_)->AddObserver(this);
-  }
-
-  virtual ~TestShellWindowRegistryObserver() {
-    apps::ShellWindowRegistry::Get(profile_)->RemoveObserver(this);
-  }
-
-  // Overridden from ShellWindowRegistry::Observer:
-  virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE {}
-
-  virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {
-    ++icon_updates_;
-  }
-
-  virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE {}
-
-  int icon_updates() { return icon_updates_; }
-
- private:
-  Profile* profile_;
-  int icon_updates_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestShellWindowRegistryObserver);
-};
-
-}  // namespace
-
-// TODO(skuhne): Change name back to LauncherPlatformAppBrowserTest when the
-// old launcher gets ripped out.
-class LauncherPlatformPerAppAppBrowserTest
-    : public extensions::PlatformAppBrowserTest {
- protected:
-  LauncherPlatformPerAppAppBrowserTest()
-      : launcher_(NULL),
-        controller_(NULL) {
-  }
-
-  virtual ~LauncherPlatformPerAppAppBrowserTest() {}
-
-  virtual void RunTestOnMainThreadLoop() OVERRIDE {
-    launcher_ = ash::Launcher::ForPrimaryDisplay();
-    controller_ =
-        static_cast<ChromeLauncherControllerPerApp*>(launcher_->delegate());
-    return extensions::PlatformAppBrowserTest::RunTestOnMainThreadLoop();
-  }
-
-  ash::LauncherModel* launcher_model() {
-    return ash::test::ShellTestApi(ash::Shell::GetInstance()).launcher_model();
-  }
-
-  ash::LauncherID CreateAppShortcutLauncherItem(const std::string& name) {
-    return controller_->CreateAppShortcutLauncherItem(
-        name, controller_->model()->item_count());
-  }
-
-  const ash::LauncherItem& GetLastLauncherItem() {
-    // Unless there are any panels, the item at index [count - 1] will be
-    // the app list, and the item at [count - 2] will be the desired item.
-    return launcher_model()->items()[launcher_model()->item_count() - 2];
-  }
-
-  const ash::LauncherItem& GetLastLauncherPanelItem() {
-    // Panels show up on the right side of the launcher, so the desired item
-    // will be the last one.
-    return launcher_model()->items()[launcher_model()->item_count() - 1];
-  }
-
-  LauncherItemController* GetItemController(ash::LauncherID id) {
-    return controller_->id_to_item_controller_map_[id];
-  }
-
-  // Returns the number of menu items, ignoring separators.
-  int GetNumApplicationMenuItems(const ash::LauncherItem& item) {
-    const int event_flags = 0;
-    scoped_ptr<ash::LauncherMenuModel> menu(
-        controller_->CreateApplicationMenu(item, event_flags));
-    int num_items = 0;
-    for (int i = 0; i < menu->GetItemCount(); ++i) {
-      if (menu->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR)
-        ++num_items;
-    }
-    return num_items;
-  }
-
-  // Activate the launcher item with the given |id|.
-  void ActivateLauncherItem(int id) {
-    launcher_->ActivateLauncherItem(id);
-  }
-
-  ash::Launcher* launcher_;
-  ChromeLauncherControllerPerApp* controller_;
-
- private:
-
-  DISALLOW_COPY_AND_ASSIGN(LauncherPlatformPerAppAppBrowserTest);
-};
-
-// TODO(skuhne): Change name back to LauncherAppBrowserTest when the
-// old launcher gets ripped out.
-class LauncherPerAppAppBrowserTest : public ExtensionBrowserTest {
- protected:
-  LauncherPerAppAppBrowserTest()
-      : launcher_(NULL),
-        model_(NULL) {
-  }
-
-  virtual ~LauncherPerAppAppBrowserTest() {}
-
-  virtual void RunTestOnMainThreadLoop() OVERRIDE {
-    launcher_ = ash::Launcher::ForPrimaryDisplay();
-    model_ =
-        ash::test::ShellTestApi(ash::Shell::GetInstance()).launcher_model();
-    return ExtensionBrowserTest::RunTestOnMainThreadLoop();
-  }
-
-  size_t NumberOfDetectedLauncherBrowsers(bool show_all_tabs) {
-    ChromeLauncherControllerPerApp* controller =
-        static_cast<ChromeLauncherControllerPerApp*>(launcher_->delegate());
-    LauncherItemController* item_controller =
-      controller->GetBrowserShortcutLauncherItemController();
-    int items = item_controller->GetApplicationList(
-        show_all_tabs ? ui::EF_SHIFT_DOWN : 0).size();
-    // If we have at least one item, we have also a title which we remove here.
-    return items ? (items - 1) : 0;
-  }
-
-  const Extension* LoadAndLaunchExtension(
-      const char* name,
-      extension_misc::LaunchContainer container,
-      WindowOpenDisposition disposition) {
-    EXPECT_TRUE(LoadExtension(test_data_dir_.AppendASCII(name)));
-
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        profile())->extension_service();
-    const Extension* extension =
-        service->GetExtensionById(last_loaded_extension_id_, false);
-    EXPECT_TRUE(extension);
-
-    chrome::OpenApplication(chrome::AppLaunchParams(profile(),
-                                                    extension,
-                                                    container,
-                                                    disposition));
-    return extension;
-  }
-
-  ash::LauncherID CreateShortcut(const char* name) {
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        profile())->extension_service();
-    LoadExtension(test_data_dir_.AppendASCII(name));
-
-    // First get app_id.
-    const Extension* extension =
-        service->GetExtensionById(last_loaded_extension_id_, false);
-    const std::string app_id = extension->id();
-
-    // Then create a shortcut.
-    ChromeLauncherController* controller =
-        static_cast<ChromeLauncherController*>(launcher_->delegate());
-    int item_count = model_->item_count();
-    ash::LauncherID shortcut_id = controller->CreateAppShortcutLauncherItem(
-        app_id,
-        item_count);
-    controller->PersistPinnedState();
-    EXPECT_EQ(++item_count, model_->item_count());
-    const ash::LauncherItem& item = *model_->ItemByID(shortcut_id);
-    EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
-    return item.id;
-  }
-
-  // Activate the launcher item with the given |id|.
-  void ActivateLauncherItem(int id) {
-    launcher_->ActivateLauncherItem(id);
-  }
-
-  ash::Launcher* launcher_;
-  ash::LauncherModel* model_;
-
- private:
-
-  DISALLOW_COPY_AND_ASSIGN(LauncherPerAppAppBrowserTest);
-};
-
-// TODO(skuhne): Change name to LauncherAppBrowserTestNoBrowser when the
-// old launcher gets ripped out.
-class LauncherPerAppAppBrowserTestNoDefaultBrowser
-    : public LauncherPerAppAppBrowserTest {
- protected:
-  LauncherPerAppAppBrowserTestNoDefaultBrowser() {}
-  virtual ~LauncherPerAppAppBrowserTestNoDefaultBrowser() {}
-
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    LauncherPerAppAppBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kNoStartupWindow);
-  }
-
- private:
-
-  DISALLOW_COPY_AND_ASSIGN(LauncherPerAppAppBrowserTestNoDefaultBrowser);
-};
-
-// Since the default for minimizing on click might change, I added both classes
-// to either get the minimize on click or not.
-class LauncherPerAppAppBrowserNoMinimizeOnClick
-    : public LauncherPlatformPerAppAppBrowserTest {
- protected:
-  LauncherPerAppAppBrowserNoMinimizeOnClick() {}
-  virtual ~LauncherPerAppAppBrowserNoMinimizeOnClick() {}
-
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    LauncherPlatformPerAppAppBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(
-        switches::kDisableMinimizeOnSecondLauncherItemClick);
-  }
-
- private:
-
-  DISALLOW_COPY_AND_ASSIGN(LauncherPerAppAppBrowserNoMinimizeOnClick);
-};
-
-typedef LauncherPlatformPerAppAppBrowserTest
-    LauncherPerAppAppBrowserMinimizeOnClick;
-
-// Test that we can launch a platform app and get a running item.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, LaunchUnpinned) {
-  int item_count = launcher_model()->item_count();
-  const Extension* extension = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* window = CreateShellWindow(extension);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item = GetLastLauncherItem();
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
-  CloseShellWindow(window);
-  --item_count;
-  EXPECT_EQ(item_count, launcher_model()->item_count());
-}
-
-// Test that we can launch a platform app that already has a shortcut.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, LaunchPinned) {
-  int item_count = launcher_model()->item_count();
-
-  // First get app_id.
-  const Extension* extension = LoadAndLaunchPlatformApp("launch");
-  const std::string app_id = extension->id();
-
-  // Then create a shortcut.
-  ash::LauncherID shortcut_id = CreateAppShortcutLauncherItem(app_id);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  ash::LauncherItem item = *launcher_model()->ItemByID(shortcut_id);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
-  EXPECT_EQ(ash::STATUS_CLOSED, item.status);
-
-  // Open a window. Confirm the item is now running.
-  ShellWindow* window = CreateShellWindow(extension);
-  ash::wm::ActivateWindow(window->GetNativeWindow());
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  item = *launcher_model()->ItemByID(shortcut_id);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
-
-  // Then close it, make sure there's still an item.
-  CloseShellWindow(window);
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  item = *launcher_model()->ItemByID(shortcut_id);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
-  EXPECT_EQ(ash::STATUS_CLOSED, item.status);
-}
-
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, PinRunning) {
-  // Run.
-  int item_count = launcher_model()->item_count();
-  const Extension* extension = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* window = CreateShellWindow(extension);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item1 = GetLastLauncherItem();
-  ash::LauncherID id = item1.id;
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-
-  // Create a shortcut. The app item should be after it.
-  ash::LauncherID foo_id = CreateAppShortcutLauncherItem("foo");
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  EXPECT_LT(launcher_model()->ItemIndexByID(foo_id),
-            launcher_model()->ItemIndexByID(id));
-
-  // Pin the app. The item should remain.
-  controller_->Pin(id);
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item2 = *launcher_model()->ItemByID(id);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item2.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
-
-  // New shortcuts should come after the item.
-  ash::LauncherID bar_id = CreateAppShortcutLauncherItem("bar");
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  EXPECT_LT(launcher_model()->ItemIndexByID(id),
-            launcher_model()->ItemIndexByID(bar_id));
-
-  // Then close it, make sure the item remains.
-  CloseShellWindow(window);
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-}
-
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, UnpinRunning) {
-  int item_count = launcher_model()->item_count();
-
-  // First get app_id.
-  const Extension* extension = LoadAndLaunchPlatformApp("launch");
-  const std::string app_id = extension->id();
-
-  // Then create a shortcut.
-  ash::LauncherID shortcut_id = CreateAppShortcutLauncherItem(app_id);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  ash::LauncherItem item = *launcher_model()->ItemByID(shortcut_id);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
-  EXPECT_EQ(ash::STATUS_CLOSED, item.status);
-
-  // Create a second shortcut. This will be needed to force the first one to
-  // move once it gets unpinned.
-  ash::LauncherID foo_id = CreateAppShortcutLauncherItem("foo");
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  EXPECT_LT(launcher_model()->ItemIndexByID(shortcut_id),
-            launcher_model()->ItemIndexByID(foo_id));
-
-  // Open a window. Confirm the item is now running.
-  ShellWindow* window = CreateShellWindow(extension);
-  ash::wm::ActivateWindow(window->GetNativeWindow());
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  item = *launcher_model()->ItemByID(shortcut_id);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
-
-  // Unpin the app. The item should remain.
-  controller_->Unpin(shortcut_id);
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  item = *launcher_model()->ItemByID(shortcut_id);
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
-  // The item should have moved after the other shortcuts.
-  EXPECT_GT(launcher_model()->ItemIndexByID(shortcut_id),
-            launcher_model()->ItemIndexByID(foo_id));
-
-  // Then close it, make sure the item's gone.
-  CloseShellWindow(window);
-  --item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-}
-
-// Test that we can launch a platform app with more than one window.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, MultipleWindows) {
-  int item_count = launcher_model()->item_count();
-
-  // First run app.
-  const Extension* extension = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* window1 = CreateShellWindow(extension);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item = GetLastLauncherItem();
-  ash::LauncherID item_id = item.id;
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item.status);
-  EXPECT_EQ(2, GetNumApplicationMenuItems(item));  // Title + 1 window
-
-  // Add second window.
-  ShellWindow* window2 = CreateShellWindow(extension);
-  // Confirm item stays.
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item2 = *launcher_model()->ItemByID(item_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
-  EXPECT_EQ(3, GetNumApplicationMenuItems(item2));  // Title + 2 windows
-
-  // Close second window.
-  CloseShellWindow(window2);
-  // Confirm item stays.
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item3 = *launcher_model()->ItemByID(item_id);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item3.status);
-  EXPECT_EQ(2, GetNumApplicationMenuItems(item3));  // Title + 1 window
-
-  // Close first window.
-  CloseShellWindow(window1);
-  // Confirm item is removed.
-  --item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-}
-
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, MultipleApps) {
-  int item_count = launcher_model()->item_count();
-
-  // First run app.
-  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* window1 = CreateShellWindow(extension1);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item1 = GetLastLauncherItem();
-  ash::LauncherID item_id1 = item1.id;
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-
-  // Then run second app.
-  const Extension* extension2 = LoadAndLaunchPlatformApp("launch_2");
-  ShellWindow* window2 = CreateShellWindow(extension2);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item2 = GetLastLauncherItem();
-  ash::LauncherID item_id2 = item2.id;
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item2.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
-
-  EXPECT_NE(item_id1, item_id2);
-  EXPECT_EQ(ash::STATUS_RUNNING,
-            launcher_model()->ItemByID(item_id1)->status);
-
-  // Close second app.
-  CloseShellWindow(window2);
-  --item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  // First app should be active again.
-  EXPECT_EQ(ash::STATUS_ACTIVE,
-            launcher_model()->ItemByID(item_id1)->status);
-
-  // Close first app.
-  CloseShellWindow(window1);
-  --item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-
-}
-
-// Confirm that app windows can be reactivated by clicking their icons and that
-// the correct activation order is maintained.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, WindowActivation) {
-  int item_count = launcher_model()->item_count();
-
-  // First run app.
-  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* window1 = CreateShellWindow(extension1);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item1 = GetLastLauncherItem();
-  ash::LauncherID item_id1 = item1.id;
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-
-  // Then run second app.
-  const Extension* extension2 = LoadAndLaunchPlatformApp("launch_2");
-  ShellWindow* window2 = CreateShellWindow(extension2);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item2 = GetLastLauncherItem();
-  ash::LauncherID item_id2 = item2.id;
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item2.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item2.status);
-
-  EXPECT_NE(item_id1, item_id2);
-  EXPECT_EQ(ash::STATUS_RUNNING,
-            launcher_model()->ItemByID(item_id1)->status);
-
-  // Activate first one.
-  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
-  EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model()->ItemByID(item_id1)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING,
-            launcher_model()->ItemByID(item_id2)->status);
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
-
-  // Activate second one.
-  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id2));
-  EXPECT_EQ(ash::STATUS_RUNNING,
-            launcher_model()->ItemByID(item_id1)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model()->ItemByID(item_id2)->status);
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
-
-  // Add window for app1. This will activate it.
-  ShellWindow* window1b = CreateShellWindow(extension1);
-  ash::wm::ActivateWindow(window1b->GetNativeWindow());
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
-
-  // Activate launcher item for app1, this will activate the first app window.
-  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
-  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
-
-  // Activate the second app again
-  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id2));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
-
-  // Activate the first app again
-  ActivateLauncherItem(launcher_model()->ItemIndexByID(item_id1));
-  EXPECT_TRUE(ash::wm::IsActiveWindow(window1b->GetNativeWindow()));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window2->GetNativeWindow()));
-  EXPECT_FALSE(ash::wm::IsActiveWindow(window1->GetNativeWindow()));
-
-  // Close second app.
-  CloseShellWindow(window2);
-  --item_count;
-  EXPECT_EQ(item_count, launcher_model()->item_count());
-  // First app should be active again.
-  EXPECT_EQ(ash::STATUS_ACTIVE, launcher_model()->ItemByID(item_id1)->status);
-
-  // Close first app.
-  CloseShellWindow(window1b);
-  CloseShellWindow(window1);
-  --item_count;
-  EXPECT_EQ(item_count, launcher_model()->item_count());
-}
-
-// Confirm that Click behavior for app windows is correnct.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserNoMinimizeOnClick,
-                       AppClickBehavior) {
-  // Launch a platform app and create a window for it.
-  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* window1 = CreateShellWindow(extension1);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  // Confirm that a controller item was created and is the correct state.
-  const ash::LauncherItem& item1 = GetLastLauncherItem();
-  LauncherItemController* item1_controller = GetItemController(item1.id);
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-  EXPECT_EQ(LauncherItemController::TYPE_APP, item1_controller->type());
-  // Clicking the item should have no effect.
-  TestEvent click_event(ui::ET_MOUSE_PRESSED);
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  // Minimize the window and confirm that the controller item is updated.
-  window1->GetBaseWindow()->Minimize();
-  EXPECT_FALSE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
-  // Clicking the item should activate the window.
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-  // Maximizing a window should preserve state after minimize + click.
-  window1->GetBaseWindow()->Maximize();
-  window1->GetBaseWindow()->Minimize();
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsMaximized());
-}
-
-// Confirm the minimizing click behavior for apps.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserMinimizeOnClick,
-                       PackagedAppClickBehaviorInMinimizeMode) {
-  // Launch one platform app and create a window for it.
-  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
-  ShellWindow* window1 = CreateShellWindow(extension1);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-
-  // Confirm that a controller item was created and is the correct state.
-  const ash::LauncherItem& item1 = GetLastLauncherItem();
-  LauncherItemController* item1_controller = GetItemController(item1.id);
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-  EXPECT_EQ(LauncherItemController::TYPE_APP, item1_controller->type());
-  // Since it is already active, clicking it should minimize.
-  TestEvent click_event(ui::ET_MOUSE_PRESSED);
-  item1_controller->Clicked(click_event);
-  EXPECT_FALSE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_FALSE(window1->GetBaseWindow()->IsActive());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsMinimized());
-  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
-  // Clicking the item again should activate the window again.
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-  // Maximizing a window should preserve state after minimize + click.
-  window1->GetBaseWindow()->Maximize();
-  window1->GetBaseWindow()->Minimize();
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsMaximized());
-  window1->GetBaseWindow()->Restore();
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_FALSE(window1->GetBaseWindow()->IsMaximized());
-
-  // Creating a second window of the same type should change the behavior so
-  // that a click does not change the activation state.
-  ShellWindow* window1a = CreateShellWindow(extension1);
-  EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1a->GetBaseWindow()->IsActive());
-  // The first click does nothing.
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_FALSE(window1a->GetBaseWindow()->IsActive());
-  // The second neither.
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(window1->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1a->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(window1->GetBaseWindow()->IsActive());
-  EXPECT_FALSE(window1a->GetBaseWindow()->IsActive());
-}
-
-// Confirm that click behavior for app panels is correct.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest,
-                       AppPanelClickBehavior) {
-  // Enable experimental APIs to allow panel creation.
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      extensions::switches::kEnableExperimentalExtensionApis);
-  // Launch a platform app and create a panel window for it.
-  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
-  ShellWindow::CreateParams params;
-  params.window_type = ShellWindow::WINDOW_TYPE_PANEL;
-  params.focused = false;
-  ShellWindow* panel = CreateShellWindowFromParams(extension1, params);
-  EXPECT_TRUE(panel->GetNativeWindow()->IsVisible());
-  // Panels should not be active by default.
-  EXPECT_FALSE(panel->GetBaseWindow()->IsActive());
-  // Confirm that a controller item was created and is the correct state.
-  const ash::LauncherItem& item1 = GetLastLauncherPanelItem();
-  LauncherItemController* item1_controller = GetItemController(item1.id);
-  EXPECT_EQ(ash::TYPE_APP_PANEL, item1.type);
-  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
-  EXPECT_EQ(LauncherItemController::TYPE_APP_PANEL, item1_controller->type());
-  // Click the item and confirm that the panel is activated.
-  TestEvent click_event(ui::ET_MOUSE_PRESSED);
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-  // Click the item again and confirm that the panel is minimized.
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(panel->GetBaseWindow()->IsMinimized());
-  EXPECT_EQ(ash::STATUS_RUNNING, item1.status);
-  // Click the item again and confirm that the panel is activated.
-  item1_controller->Clicked(click_event);
-  EXPECT_TRUE(panel->GetNativeWindow()->IsVisible());
-  EXPECT_TRUE(panel->GetBaseWindow()->IsActive());
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-}
-
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest,
-    BrowserActivation) {
-  int item_count = launcher_model()->item_count();
-
-  // First run app.
-  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
-  CreateShellWindow(extension1);
-  ++item_count;
-  ASSERT_EQ(item_count, launcher_model()->item_count());
-  const ash::LauncherItem& item1 = GetLastLauncherItem();
-  ash::LauncherID item_id1 = item1.id;
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-
-  ash::wm::ActivateWindow(browser()->window()->GetNativeWindow());
-  EXPECT_EQ(ash::STATUS_RUNNING,
-            launcher_model()->ItemByID(item_id1)->status);
-}
-
-// Test that opening an app sets the correct icon
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest, SetIcon) {
-  TestShellWindowRegistryObserver test_observer(browser()->profile());
-
-  // Enable experimental APIs to allow panel creation.
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      extensions::switches::kEnableExperimentalExtensionApis);
-
-  int base_launcher_item_count = launcher_model()->item_count();
-  ExtensionTestMessageListener launched_listener("Launched", false);
-  ExtensionTestMessageListener completed_listener("Completed", false);
-  LoadAndLaunchPlatformApp("app_icon");
-  ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
-  ASSERT_TRUE(completed_listener.WaitUntilSatisfied());
-
-  // Now wait until the WebContent has decoded the icons and chrome has
-  // processed it. This needs to be in a loop since the renderer runs in a
-  // different process.
-  while (test_observer.icon_updates() < 3) {
-    base::RunLoop run_loop;
-    run_loop.RunUntilIdle();
-  }
-
-  // This test creates one shell window and one panel window.
-  int launcher_item_count = launcher_model()->item_count();
-  ASSERT_EQ(base_launcher_item_count + 2, launcher_item_count);
-  // The Panel will be the last item, the app list second-to-last, the app
-  // third from last.
-  const ash::LauncherItem& app_item =
-      launcher_model()->items()[launcher_item_count - 3];
-  const ash::LauncherItem& panel_item =
-      launcher_model()->items()[launcher_item_count - 1];
-  const LauncherItemController* app_item_controller =
-      GetItemController(app_item.id);
-  const LauncherItemController* panel_item_controller =
-      GetItemController(panel_item.id);
-  // Icons for Apps are set by the ShellWindowLauncherController, so
-  // image_set_by_controller() should be set.
-  EXPECT_TRUE(app_item_controller->image_set_by_controller());
-  EXPECT_TRUE(panel_item_controller->image_set_by_controller());
-  // Ensure icon heights are correct (see test.js in app_icon/ test directory)
-  EXPECT_EQ(48, app_item.image.height());
-  EXPECT_EQ(64, panel_item.image.height());
-}
-
-// Test that we can launch an app with a shortcut.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, LaunchPinned) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
-  WebContents* tab = tab_strip->GetActiveWebContents();
-  content::WindowedNotificationObserver close_observer(
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<WebContents>(tab));
-  browser()->tab_strip_model()->CloseSelectedTabs();
-  close_observer.Wait();
-  EXPECT_EQ(--tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
-}
-
-// Launch the app first and then create the shortcut.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, LaunchUnpinned) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB,
-                         NEW_FOREGROUND_TAB);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
-  WebContents* tab = tab_strip->GetActiveWebContents();
-  content::WindowedNotificationObserver close_observer(
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-      content::Source<WebContents>(tab));
-  browser()->tab_strip_model()->CloseSelectedTabs();
-  close_observer.Wait();
-  EXPECT_EQ(--tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
-}
-
-// Launches an app in the background and then tries to open it. This is test for
-// a crash we had.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, LaunchInBackground) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB,
-                         NEW_BACKGROUND_TAB);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  ChromeLauncherController::instance()->LaunchApp(last_loaded_extension_id_, 0);
-}
-
-// Confirm that clicking a icon for an app running in one of 2 maxmized windows
-// activates the right window.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, LaunchMaximized) {
-  aura::Window* window1 = browser()->window()->GetNativeWindow();
-  ash::wm::MaximizeWindow(window1);
-  content::WindowedNotificationObserver open_observer(
-      chrome::NOTIFICATION_BROWSER_WINDOW_READY,
-      content::NotificationService::AllSources());
-  chrome::NewEmptyWindow(browser()->profile(), chrome::HOST_DESKTOP_TYPE_ASH);
-  open_observer.Wait();
-  Browser* browser2 = content::Source<Browser>(open_observer.source()).ptr();
-  aura::Window* window2 = browser2->window()->GetNativeWindow();
-  TabStripModel* tab_strip = browser2->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::wm::MaximizeWindow(window2);
-
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
-
-  window1->Show();
-  ash::wm::ActivateWindow(window1);
-  EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut_id)).status);
-
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
-}
-
-// Activating the same app multiple times should launch only a single copy.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, ActivateApp) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  const Extension* extension =
-      LoadExtension(test_data_dir_.AppendASCII("app1"));
-
-  ChromeLauncherController::instance()->ActivateApp(extension->id(), 0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  ChromeLauncherController::instance()->ActivateApp(extension->id(), 0);
-  EXPECT_EQ(tab_count, tab_strip->count());
-}
-
-// Launching the same app multiple times should launch a copy for each call.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, LaunchApp) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  const Extension* extension =
-      LoadExtension(test_data_dir_.AppendASCII("app1"));
-
-  ChromeLauncherController::instance()->LaunchApp(extension->id(), 0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  ChromeLauncherController::instance()->LaunchApp(extension->id(), 0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-}
-
-// Launch 2 apps and toggle which is active.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, MultipleApps) {
-  int item_count = model_->item_count();
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::LauncherID shortcut1 = CreateShortcut("app1");
-  EXPECT_EQ(++item_count, model_->item_count());
-  ash::LauncherID shortcut2 = CreateShortcut("app2");
-  EXPECT_EQ(++item_count, model_->item_count());
-
-  // Launch first app.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  WebContents* tab1 = tab_strip->GetActiveWebContents();
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status);
-
-  // Launch second app.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut2));
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  WebContents* tab2 = tab_strip->GetActiveWebContents();
-  ASSERT_NE(tab1, tab2);
-  EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status);
-
-  // Reactivate first app.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
-  EXPECT_EQ(tab_count, tab_strip->count());
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab1);
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status);
-  EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut2)).status);
-
-  // Open second tab for second app. This should activate it.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example.com/path3/foo.html"),
-      NEW_FOREGROUND_TAB,
-      0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status);
-
-  // Reactivate first app.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut1));
-  EXPECT_EQ(tab_count, tab_strip->count());
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab1);
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut1)).status);
-  EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut2)).status);
-
-  // And second again. This time the second tab should become active.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut2));
-  EXPECT_EQ(tab_count, tab_strip->count());
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), tab2);
-  EXPECT_EQ(ash::STATUS_RUNNING, (*model_->ItemByID(shortcut1)).status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut2)).status);
-}
-
-// Confirm that a page can be navigated from and to while maintaining the
-// correct running state.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, Navigation) {
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
-
-  // Navigate away.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL("http://www.example.com/path0/bar.html"));
-  EXPECT_EQ(ash::STATUS_CLOSED, (*model_->ItemByID(shortcut_id)).status);
-
-  // Navigate back.
-  ui_test_utils::NavigateToURL(
-      browser(), GURL("http://www.example.com/path1/foo.html"));
-  EXPECT_EQ(ash::STATUS_ACTIVE, (*model_->ItemByID(shortcut_id)).status);
-}
-
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, MultipleOwnedTabs) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  WebContents* first_tab = tab_strip->GetActiveWebContents();
-
-  // Create new tab owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example.com/path2/bar.html"),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // Confirm app is still active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-
-  // Create new tab not owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example.com/path3/foo.html"),
-      NEW_FOREGROUND_TAB,
-      0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // No longer active.
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->ItemByID(shortcut_id)->status);
-
-  // Activating app makes first tab active again.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), first_tab);
-}
-
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, RefocusFilter) {
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  WebContents* first_tab = tab_strip->GetActiveWebContents();
-
-  controller->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path1/*"));
-  // Create new tab owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example.com/path2/bar.html"),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // Confirm app is still active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-
-  // Create new tab not owned by app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example.com/path3/foo.html"),
-      NEW_FOREGROUND_TAB,
-      0);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  // No longer active.
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->ItemByID(shortcut_id)->status);
-
-  // Activating app makes first tab active again, because second tab isn't
-  // in its refocus url path.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), first_tab);
-}
-
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, RefocusFilterLaunch) {
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  controller->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path1/*"));
-
-  // Create new tab.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example2.com/path2/bar.html"),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  WebContents* first_tab = tab_strip->GetActiveWebContents();
-  // Confirm app is not active.
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
-
-  // Activating app should launch new tab, because second tab isn't
-  // in its refocus url path.
-  ActivateLauncherItem(model_->ItemIndexByID(shortcut_id));
-  EXPECT_EQ(++tab_count, tab_strip->count());
-  WebContents* second_tab = tab_strip->GetActiveWebContents();
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  EXPECT_NE(first_tab, second_tab);
-  EXPECT_EQ(tab_strip->GetActiveWebContents(), second_tab);
-}
-
-// Check the launcher activation state for applications and browser.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, ActivationStateCheck) {
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  // Get the browser item index
-  int browser_index = ash::launcher::GetBrowserItemIndex(*controller->model());
-  EXPECT_TRUE(browser_index >= 0);
-
-  // Even though we are just comming up, the browser should be active.
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
-
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  controller->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path1/*"));
-
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
-
-  // Create new tab which would be the running app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example.com/path1/bar.html"),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
-  // There should never be two items active at the same time.
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[browser_index].status);
-
-  tab_strip->ActivateTabAt(0, false);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
-
-  tab_strip->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->items()[browser_index].status);
-
-  ash::wm::DeactivateWindow(browser()->window()->GetNativeWindow());
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
-  EXPECT_EQ(ash::STATUS_RUNNING, model_->items()[browser_index].status);
-}
-
-// Check that the launcher activation state for a V1 application stays closed
-// even after an asynchronous browser event comes in after the tab got
-// destroyed.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest,
-                       AsyncActivationStateCheck) {
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-  controller->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path1/*"));
-
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
-
-  // Create new tab which would be the running app.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.example.com/path1/bar.html"),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
-  EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(shortcut_id)->status);
-  // To address the issue of crbug.com/174050, the tab we are about to close
-  // has to be active.
-  tab_strip->ActivateTabAt(1, false);
-  EXPECT_EQ(1, tab_strip->active_index());
-
-  // Close the web contents.
-  tab_strip->CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
-  // The status should now be set to closed.
-  EXPECT_EQ(ash::STATUS_CLOSED, model_->ItemByID(shortcut_id)->status);
-}
-
-// Checks that a windowed application does not add an item to the browser list.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTestNoDefaultBrowser,
-    WindowedAppDoesNotAddToBrowser) {
-  // Get the number of items in the browser menu.
-  size_t items = NumberOfDetectedLauncherBrowsers(false);
-  size_t running_browser = chrome::GetTotalBrowserCount();
-  EXPECT_EQ(0u, items);
-  EXPECT_EQ(0u, running_browser);
-
-  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_WINDOW, NEW_WINDOW);
-
-  // No new browser should get detected, even though one more is running.
-  EXPECT_EQ(0u, NumberOfDetectedLauncherBrowsers(false));
-  EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
-
-  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
-
-  // A new browser should get detected and one more should be running.
-  EXPECT_EQ(NumberOfDetectedLauncherBrowsers(false), 1u);
-  EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
-}
-
-// Checks the functionality to enumerate all browsers vs. all tabs.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTestNoDefaultBrowser,
-    EnumerateALlBrowsersAndTabs) {
-  // Create at least one browser.
-  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
-  size_t browsers = NumberOfDetectedLauncherBrowsers(false);
-  size_t tabs = NumberOfDetectedLauncherBrowsers(true);
-
-  // Create a second browser.
-  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
-
-  EXPECT_EQ(++browsers, NumberOfDetectedLauncherBrowsers(false));
-  EXPECT_EQ(++tabs, NumberOfDetectedLauncherBrowsers(true));
-
-  // Create only a tab.
-  LoadAndLaunchExtension("app1",
-                         extension_misc::LAUNCH_TAB,
-                         NEW_FOREGROUND_TAB);
-
-  EXPECT_EQ(browsers, NumberOfDetectedLauncherBrowsers(false));
-  EXPECT_EQ(++tabs, NumberOfDetectedLauncherBrowsers(true));
-}
-
-// Check that the keyboard activation of a launcher item tabs properly through
-// the items at hand.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, AltNumberTabsTabbing) {
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
-
-  ash::LauncherID shortcut_id = CreateShortcut("app");
-  controller->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path/*"));
-  std::string url = "http://www.example.com/path/bla";
-
-  int shortcut_index = model_->ItemIndexByID(shortcut_id);
-
-  // Create an application handled browser tab.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL(url),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
-  content::WebContents* content1 = tab_strip->GetActiveWebContents();
-
-  // Create some other browser tab.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL("http://www.test.com"),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  content::WebContents* content1a = tab_strip->GetActiveWebContents();
-
-  // Make sure that the active tab is now our handled tab.
-  EXPECT_NE(content1a, content1);
-
-  // The active tab should still be the unnamed tab. Then we switch and reach
-  // the first app and stay there.
-  EXPECT_EQ(content1a, tab_strip->GetActiveWebContents());
-  ActivateLauncherItem(shortcut_index);
-  EXPECT_EQ(content1, tab_strip->GetActiveWebContents());
-  ActivateLauncherItem(shortcut_index);
-  EXPECT_EQ(content1, tab_strip->GetActiveWebContents());
-
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(),
-      GURL(url),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  content::WebContents* content2 = tab_strip->GetActiveWebContents();
-
-  EXPECT_EQ(content2, browser()->tab_strip_model()->GetActiveWebContents());
-  ActivateLauncherItem(shortcut_index);
-  EXPECT_EQ(content1, browser()->tab_strip_model()->GetActiveWebContents());
-  ActivateLauncherItem(shortcut_index);
-  EXPECT_EQ(content2, browser()->tab_strip_model()->GetActiveWebContents());
-}
-
-// Check that the keyboard activation of a launcher item tabs properly through
-// the items at hand.
-IN_PROC_BROWSER_TEST_F(LauncherPlatformPerAppAppBrowserTest,
-                       AltNumberAppsTabbing) {
-  // First run app.
-  const Extension* extension1 = LoadAndLaunchPlatformApp("launch");
-  ui::BaseWindow* window1 = CreateShellWindow(extension1)->GetBaseWindow();
-  const ash::LauncherItem& item1 = GetLastLauncherItem();
-  ash::LauncherID app_id = item1.id;
-  int app_index = launcher_model()->ItemIndexByID(app_id);
-
-  EXPECT_EQ(ash::TYPE_PLATFORM_APP, item1.type);
-  EXPECT_EQ(ash::STATUS_ACTIVE, item1.status);
-
-  const Extension* extension2 = LoadAndLaunchPlatformApp("launch_2");
-  ui::BaseWindow* window2 = CreateShellWindow(extension2)->GetBaseWindow();
-
-  // By now the browser should be active. Issue Alt keystrokes several times to
-  // see that we stay on that application.
-  EXPECT_TRUE(window2->IsActive());
-  ActivateLauncherItem(app_index);
-  EXPECT_TRUE(window1->IsActive());
-  ActivateLauncherItem(app_index);
-  EXPECT_TRUE(window1->IsActive());
-
-  ui::BaseWindow* window1a = CreateShellWindow(extension1)->GetBaseWindow();
-
-  EXPECT_TRUE(window1a->IsActive());
-  EXPECT_FALSE(window1->IsActive());
-  ActivateLauncherItem(app_index);
-  EXPECT_TRUE(window1->IsActive());
-  ActivateLauncherItem(app_index);
-  EXPECT_TRUE(window1a->IsActive());
-}
-
-// Checks that the browser Alt "tabbing" is properly done.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTestNoDefaultBrowser,
-    AltNumberBrowserTabbing) {
-  // Get the number of items in the browser menu.
-  EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
-  // The first activation should create a browser.
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
-  // A second activation should not create a new instance.
-  launcher_->ActivateLauncherItem(0);
-  Browser* browser1 = chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow());
-  EXPECT_TRUE(browser1);
-  aura::Window* window1 = browser1->window()->GetNativeWindow();
-  Browser* browser2 = CreateBrowser(profile());
-  aura::Window* window2 = browser2->window()->GetNativeWindow();
-
-  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
-  EXPECT_NE(window1, window2);
-  EXPECT_EQ(window2, ash::wm::GetActiveWindow());
-
-  // Activate multiple times the switcher to see that the windows get activated.
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(window2, ash::wm::GetActiveWindow());
-
-  // Create a third browser - make sure that we do not toggle simply between
-  // two windows.
-  Browser* browser3 = CreateBrowser(profile());
-  aura::Window* window3 = browser3->window()->GetNativeWindow();
-
-  EXPECT_EQ(3u, chrome::GetTotalBrowserCount());
-  EXPECT_NE(window1, window3);
-  EXPECT_NE(window2, window3);
-  EXPECT_EQ(window3, ash::wm::GetActiveWindow());
-
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(window2, ash::wm::GetActiveWindow());
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(window3, ash::wm::GetActiveWindow());
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
-
-  // Create anther app and make sure that none of our browsers is active.
-  LoadAndLaunchExtension("app1", extension_misc::LAUNCH_TAB, NEW_WINDOW);
-  EXPECT_NE(window1, ash::wm::GetActiveWindow());
-  EXPECT_NE(window2, ash::wm::GetActiveWindow());
-
-  // After activation our browser should be active again.
-  launcher_->ActivateLauncherItem(0);
-  EXPECT_EQ(window1, ash::wm::GetActiveWindow());
-}
-
-// Checks that after a session restore, we do not start applications on an
-// activation.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest,
-    ActivateAfterSessionRestore) {
-  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
-
-  // Create a known application.
-  ChromeLauncherController* controller =
-      static_cast<ChromeLauncherController*>(launcher_->delegate());
-  ash::LauncherID shortcut_id = CreateShortcut("app1");
-
-  // Create a new browser - without activating it - and load an "app" into it.
-  Browser::CreateParams params =
-      Browser::CreateParams(profile(), chrome::GetActiveDesktop());
-  params.initial_show_state = ui::SHOW_STATE_INACTIVE;
-  Browser* browser2 = new Browser(params);
-  controller->SetRefocusURLPatternForTest(
-      shortcut_id, GURL("http://www.example.com/path/*"));
-  std::string url = "http://www.example.com/path/bla";
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser2,
-      GURL(url),
-      NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-
-  // Remember the number of tabs for each browser.
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count1 = tab_strip->count();
-  TabStripModel* tab_strip2 = browser2->tab_strip_model();
-  int tab_count2 = tab_strip2->count();
-
-  // Check that we have two browsers and the inactive browser remained inactive.
-  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
-  EXPECT_EQ(chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()),
-            browser());
-  // Check that the LRU browser list does only contain the original browser.
-  BrowserList* ash_browser_list =
-      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
-  BrowserList::const_reverse_iterator it =
-      ash_browser_list->begin_last_active();
-  EXPECT_EQ(*it, browser());
-  ++it;
-  EXPECT_EQ(it, ash_browser_list->end_last_active());
-
-  // Now request to either activate an existing app or create a new one.
-  controller->ItemSelected(*model_->ItemByID(shortcut_id),
-                           ui::KeyEvent(ui::ET_KEY_RELEASED,
-                                        ui::VKEY_RETURN,
-                                        0,
-                                        false));
-
-  // Check that we have set focus on the existing application and nothing new
-  // was created.
-  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
-  EXPECT_EQ(tab_count1, tab_strip->count());
-  EXPECT_EQ(tab_count2, tab_strip2->count());
-  EXPECT_EQ(chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()),
-            browser2);
-}
-
-// Do various drag and drop interaction tests between the application list and
-// the launcher.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, DragAndDrop) {
-  // Get a number of interfaces we need.
-  aura::test::EventGenerator generator(
-      ash::Shell::GetPrimaryRootWindow(), gfx::Point());
-  ash::test::LauncherViewTestAPI test(launcher_->GetLauncherViewForTest());
-  AppListService* service = AppListService::Get();
-
-  // There should be two items in our launcher by this time.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(service->IsAppListVisible());
-
-  // Open the app list menu and check that the drag and drop host was set.
-  gfx::Rect app_list_bounds =
-      test.launcher_view()->GetAppListButtonView()->GetBoundsInScreen();
-  generator.MoveMouseTo(app_list_bounds.CenterPoint().x(),
-                        app_list_bounds.CenterPoint().y());
-  base::MessageLoop::current()->RunUntilIdle();
-  generator.ClickLeftButton();
-
-  EXPECT_TRUE(service->IsAppListVisible());
-  app_list::AppsGridView* grid_view =
-      app_list::AppsGridView::GetLastGridViewForTest();
-  ASSERT_TRUE(grid_view);
-  ASSERT_TRUE(grid_view->has_drag_and_drop_host_for_test());
-
-  // There should be 2 items in our application list.
-  const views::ViewModel* vm_grid = grid_view->view_model_for_test();
-  EXPECT_EQ(2, vm_grid->view_size());
-
-  // Test #1: Drag an app list which does not exist yet item into the
-  // launcher. Keeping it dragged, see that a new item gets created. Continuing
-  // to drag it out should remove it again.
-
-  // Get over item #1 of the application list and press the mouse button.
-  views::View* item1 = vm_grid->view_at(1);
-  gfx::Rect bounds_grid_1 = item1->GetBoundsInScreen();
-  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
-                        bounds_grid_1.CenterPoint().y());
-  base::MessageLoop::current()->RunUntilIdle();
-  generator.PressLeftButton();
-
-  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
-
-  // Drag the item into the launcher and check that a new item gets created.
-  const views::ViewModel* vm_launcher =
-      test.launcher_view()->view_model_for_test();
-  views::View* launcher1 = vm_launcher->view_at(1);
-  gfx::Rect bounds_launcher_1 = launcher1->GetBoundsInScreen();
-  generator.MoveMouseTo(bounds_launcher_1.CenterPoint().x(),
-                        bounds_launcher_1.CenterPoint().y());
-  base::MessageLoop::current()->RunUntilIdle();
-
-  // Check that a new item got created.
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_TRUE(grid_view->forward_events_to_drag_and_drop_host_for_test());
-
-  // Move it where the item originally was and check that it disappears again.
-  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
-                        bounds_grid_1.CenterPoint().y());
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
-
-  // Dropping it should keep the launcher as it originally was.
-  generator.ReleaseLeftButton();
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(2, model_->item_count());
-  // There are a few animations which need finishing before we can continue.
-  test.RunMessageLoopUntilAnimationsDone();
-  // Move the mouse outside of the launcher.
-  generator.MoveMouseTo(0, 0);
-
-  // Test #2: Check that the unknown item dropped into the launcher will
-  // create a new item.
-  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
-                        bounds_grid_1.CenterPoint().y());
-  generator.PressLeftButton();
-  generator.MoveMouseTo(bounds_launcher_1.CenterPoint().x(),
-                        bounds_launcher_1.CenterPoint().y());
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_TRUE(grid_view->forward_events_to_drag_and_drop_host_for_test());
-  generator.ReleaseLeftButton();
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
-  EXPECT_EQ(3, model_->item_count());  // It should be still there.
-  test.RunMessageLoopUntilAnimationsDone();
-
-  // Test #3: Check that the now known item dropped into the launcher will
-  // not create a new item.
-  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
-                        bounds_grid_1.CenterPoint().y());
-  generator.PressLeftButton();
-  generator.MoveMouseTo(bounds_launcher_1.CenterPoint().x(),
-                        bounds_launcher_1.CenterPoint().y());
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(3, model_->item_count());  // No new item got added.
-  EXPECT_TRUE(grid_view->forward_events_to_drag_and_drop_host_for_test());
-  generator.ReleaseLeftButton();
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_FALSE(grid_view->forward_events_to_drag_and_drop_host_for_test());
-  EXPECT_EQ(3, model_->item_count());  // And it remains that way.
-}
-
-// Check that clicking on an app launcher item launches a new browser.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, ClickItem) {
-  // Get a number of interfaces we need.
-  aura::test::EventGenerator generator(
-      ash::Shell::GetPrimaryRootWindow(), gfx::Point());
-  ash::test::LauncherViewTestAPI test(launcher_->GetLauncherViewForTest());
-  AppListService* service = AppListService::Get();
-  // There should be two items in our launcher by this time.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(service->IsAppListVisible());
-
-  // Open the app list menu and check that the drag and drop host was set.
-  gfx::Rect app_list_bounds =
-      test.launcher_view()->GetAppListButtonView()->GetBoundsInScreen();
-  generator.MoveMouseTo(app_list_bounds.CenterPoint().x(),
-                        app_list_bounds.CenterPoint().y());
-  generator.ClickLeftButton();
-  base::MessageLoop::current()->RunUntilIdle();
-
-  EXPECT_TRUE(service->IsAppListVisible());
-  app_list::AppsGridView* grid_view =
-      app_list::AppsGridView::GetLastGridViewForTest();
-  ASSERT_TRUE(grid_view);
-  const views::ViewModel* vm_grid = grid_view->view_model_for_test();
-  EXPECT_EQ(2, vm_grid->view_size());
-  gfx::Rect bounds_grid_1 = vm_grid->view_at(1)->GetBoundsInScreen();
-  // Test now that a click does create a new application tab.
-  TabStripModel* tab_strip = browser()->tab_strip_model();
-  int tab_count = tab_strip->count();
-  generator.MoveMouseTo(bounds_grid_1.CenterPoint().x(),
-                        bounds_grid_1.CenterPoint().y());
-  generator.ClickLeftButton();
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(tab_count + 1, tab_strip->count());
-}
-
-// Check LauncherItemController of Browser Shortcut functionality.
-IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTestNoDefaultBrowser,
-    BrowserShortcutLauncherItemController) {
-  ChromeLauncherControllerPerApp* controller =
-      static_cast<ChromeLauncherControllerPerApp*>(launcher_->delegate());
-  LauncherItemController* item_controller =
-      controller->GetBrowserShortcutLauncherItemController();
-
-  // Get the number of browsers.
-  size_t running_browser = chrome::GetTotalBrowserCount();
-  EXPECT_EQ(0u, running_browser);
-  EXPECT_FALSE(item_controller->IsOpen());
-
-  // Activate. This creates new browser
-  item_controller->Activate();
-  // New Window is created.
-  running_browser = chrome::GetTotalBrowserCount();
-  EXPECT_EQ(1u, running_browser);
-  EXPECT_TRUE(item_controller->IsOpen());
-
-  // Minimize Window.
-  aura::Window* window = ash::wm::GetActiveWindow();
-  ash::wm::MinimizeWindow(window);
-  EXPECT_TRUE(ash::wm::IsWindowMinimized(window));
-
-  // Activate again. This doesn't create new browser.
-  // It activates window.
-  item_controller->Activate();
-  running_browser = chrome::GetTotalBrowserCount();
-  EXPECT_EQ(1u, running_browser);
-  EXPECT_TRUE(item_controller->IsOpen());
-  EXPECT_FALSE(ash::wm::IsWindowMinimized(window));
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
deleted file mode 100644
index 8643cc1..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc
+++ /dev/null
@@ -1,1156 +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/launcher/chrome_launcher_controller_per_app.h"
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "ash/launcher/launcher_model.h"
-#include "ash/launcher/launcher_model_observer.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
-#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.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_list.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/test/base/browser_with_test_window_test.h"
-#include "chrome/test/base/testing_pref_service_syncable.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/base/models/menu_model.h"
-
-using extensions::Extension;
-using extensions::Manifest;
-
-namespace {
-const char* offline_gmail_url = "https://mail.google.com/mail/mu/u";
-const char* gmail_url = "https://mail.google.com/mail/u";
-}
-
-namespace {
-
-// LauncherModelObserver implementation that tracks what messages are invoked.
-class TestLauncherModelObserver : public ash::LauncherModelObserver {
- public:
-  TestLauncherModelObserver()
-    : added_(0),
-      removed_(0),
-      changed_(0) {
-  }
-
-  virtual ~TestLauncherModelObserver() {
-  }
-
-  // LauncherModelObserver
-  virtual void LauncherItemAdded(int index) OVERRIDE {
-    ++added_;
-    last_index_ = index;
-  }
-
-  virtual void LauncherItemRemoved(int index, ash::LauncherID id) OVERRIDE {
-    ++removed_;
-    last_index_ = index;
-  }
-
-  virtual void LauncherItemChanged(int index,
-                                   const ash::LauncherItem& old_item) OVERRIDE {
-    ++changed_;
-    last_index_ = index;
-  }
-
-  virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE {
-    last_index_ = target_index;
-  }
-
-  virtual void LauncherStatusChanged() OVERRIDE {
-  }
-
-  void clear_counts() {
-    added_ = 0;
-    removed_ = 0;
-    changed_ = 0;
-    last_index_ = 0;
-  }
-
-  int added() const { return added_; }
-  int removed() const { return removed_; }
-  int changed() const { return changed_; }
-  int last_index() const { return last_index_; }
-
- private:
-  int added_;
-  int removed_;
-  int changed_;
-  int last_index_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestLauncherModelObserver);
-};
-
-// Test implementation of AppIconLoader.
-class TestAppIconLoaderImpl : public extensions::AppIconLoader {
- public:
-  TestAppIconLoaderImpl() : fetch_count_(0) {
-  }
-
-  virtual ~TestAppIconLoaderImpl() {
-  }
-
-  // AppIconLoader implementation:
-  virtual void FetchImage(const std::string& id) OVERRIDE {
-    ++fetch_count_;
-  }
-
-  virtual void ClearImage(const std::string& id) OVERRIDE {
-  }
-
-  virtual void UpdateImage(const std::string& id) OVERRIDE {
-  }
-
-  int fetch_count() const { return fetch_count_; }
-
- private:
-  int fetch_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestAppIconLoaderImpl);
-};
-
-}  // namespace
-
-class ChromeLauncherControllerPerAppTest : public BrowserWithTestWindowTest {
- protected:
-  ChromeLauncherControllerPerAppTest()
-      : extension_service_(NULL) {
-    SetHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH);
-  }
-
-  virtual ~ChromeLauncherControllerPerAppTest() {
-  }
-
-  virtual void SetUp() OVERRIDE {
-    BrowserWithTestWindowTest::SetUp();
-
-    model_.reset(new ash::LauncherModel);
-    model_observer_.reset(new TestLauncherModelObserver);
-    model_->AddObserver(model_observer_.get());
-
-    DictionaryValue manifest;
-    manifest.SetString(extension_manifest_keys::kName,
-                       "launcher controller test extension");
-    manifest.SetString(extension_manifest_keys::kVersion, "1");
-    manifest.SetString(extension_manifest_keys::kDescription,
-                       "for testing pinned apps");
-
-    extensions::TestExtensionSystem* extension_system(
-        static_cast<extensions::TestExtensionSystem*>(
-            extensions::ExtensionSystem::Get(profile())));
-    extension_service_ = extension_system->CreateExtensionService(
-        CommandLine::ForCurrentProcess(), base::FilePath(), false);
-
-    std::string error;
-    extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest,
-                                    Extension::NO_FLAGS,
-                                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-                                    &error);
-    extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest,
-                                    Extension::NO_FLAGS,
-                                    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
-                                    &error);
-    // Fake gmail extension.
-    DictionaryValue manifest_gmail;
-    manifest_gmail.SetString(extension_manifest_keys::kName,
-                             "Gmail launcher controller test extension");
-    manifest_gmail.SetString(extension_manifest_keys::kVersion, "1");
-    manifest_gmail.SetString(extension_manifest_keys::kDescription,
-                             "for testing pinned Gmail");
-    manifest_gmail.SetString(extension_manifest_keys::kLaunchWebURL,
-                             "https://mail.google.com/mail/ca");
-    ListValue* list = new ListValue();
-    list->Append(Value::CreateStringValue("*://mail.google.com/mail/ca"));
-    manifest_gmail.Set(extension_manifest_keys::kWebURLs, list);
-
-    extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest_gmail,
-                                    Extension::NO_FLAGS,
-                                    extension_misc::kGmailAppId,
-                                    &error);
-
-    // Fake search extension.
-    extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest,
-                                    Extension::NO_FLAGS,
-                                    extension_misc::kGoogleSearchAppId,
-                                    &error);
-  }
-
-  virtual void TearDown() OVERRIDE {
-    model_->RemoveObserver(model_observer_.get());
-    model_observer_.reset();
-    launcher_controller_.reset();
-    model_.reset();
-
-    BrowserWithTestWindowTest::TearDown();
-  }
-
-  void InitLauncherController() {
-    launcher_controller_.reset(
-        new ChromeLauncherControllerPerApp(profile(), model_.get()));
-    launcher_controller_->Init();
-  }
-
-  void InitLauncherControllerWithBrowser() {
-    chrome::NewTab(browser());
-    BrowserList::SetLastActive(browser());
-    InitLauncherController();
-  }
-
-  void SetAppIconLoader(extensions::AppIconLoader* loader) {
-    launcher_controller_->SetAppIconLoaderForTest(loader);
-  }
-
-  void InsertPrefValue(base::ListValue* pref_value,
-                       int index,
-                       const std::string& extension_id) {
-    base::DictionaryValue* entry = new DictionaryValue();
-    entry->SetString(ash::kPinnedAppsPrefAppIDPath, extension_id);
-    pref_value->Insert(index, entry);
-  }
-
-  // Gets the currently configured app launchers from the controller.
-  void GetAppLaunchers(ChromeLauncherControllerPerApp* controller,
-                       std::vector<std::string>* launchers) {
-    launchers->clear();
-    for (ash::LauncherItems::const_iterator iter(model_->items().begin());
-         iter != model_->items().end(); ++iter) {
-      ChromeLauncherControllerPerApp::IDToItemControllerMap::const_iterator
-          entry(controller->id_to_item_controller_map_.find(iter->id));
-      if (iter->type == ash::TYPE_APP_SHORTCUT &&
-          entry != controller->id_to_item_controller_map_.end()) {
-        launchers->push_back(entry->second->app_id());
-      }
-    }
-  }
-
-  std::string GetPinnedAppStatus() {
-    std::string result;
-    for (int i = 0; i < model_->item_count(); i++) {
-      switch (model_->items()[i].type) {
-        case ash::TYPE_APP_SHORTCUT: {
-          const std::string& app =
-              launcher_controller_->GetAppIDForLauncherID(
-                  model_->items()[i].id);
-          if (app == extension1_->id()) {
-            result += "App1, ";
-            EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-          } else if (app == extension2_->id()) {
-            result += "App2, ";
-            EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
-          } else if (app == extension3_->id()) {
-            result += "App3, ";
-            EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
-          } else {
-            result += "unknown";
-          }
-          break;
-          }
-        case ash::TYPE_BROWSER_SHORTCUT:
-          result += "Chrome, ";
-          break;
-        case ash::TYPE_APP_LIST:
-          result += "AppList";
-          break;
-        default:
-          result += "Unknown";
-          break;
-      }
-    }
-    return result;
-  }
-
-  // Needed for extension service & friends to work.
-  scoped_refptr<Extension> extension1_;
-  scoped_refptr<Extension> extension2_;
-  scoped_refptr<Extension> extension3_;
-  scoped_refptr<Extension> extension4_;
-  scoped_ptr<ChromeLauncherControllerPerApp> launcher_controller_;
-  scoped_ptr<TestLauncherModelObserver> model_observer_;
-  scoped_ptr<ash::LauncherModel> model_;
-
-  ExtensionService* extension_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerPerAppTest);
-};
-
-TEST_F(ChromeLauncherControllerPerAppTest, DefaultApps) {
-  InitLauncherController();
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon.
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_EQ("Chrome, App3, AppList", GetPinnedAppStatus());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-}
-
-// Check that the restauration of launcher items is happening in the same order
-// as the user has pinned them (on another system) when they are synced reverse
-// order.
-TEST_F(ChromeLauncherControllerPerAppTest, RestoreDefaultAppsReverseOrder) {
-  InitLauncherController();
-
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  InsertPrefValue(&policy_value, 2, extension3_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                  policy_value.DeepCopy());
-  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, AppList", GetPinnedAppStatus());
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon.
-  ash::LauncherItem item;
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_EQ("Chrome, App3, AppList", GetPinnedAppStatus());
-
-  // Installing |extension2_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_EQ("Chrome, App2, App3, AppList", GetPinnedAppStatus());
-
-  // Installing |extension1_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension1_.get());
-  EXPECT_EQ("Chrome, App1, App2, App3, AppList", GetPinnedAppStatus());
-}
-
-// Check that the restauration of launcher items is happening in the same order
-// as the user has pinned them (on another system) when they are synced random
-// order.
-TEST_F(ChromeLauncherControllerPerAppTest, RestoreDefaultAppsRandomOrder) {
-  InitLauncherController();
-
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  InsertPrefValue(&policy_value, 2, extension3_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                  policy_value.DeepCopy());
-  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, AppList", GetPinnedAppStatus());
-
-  // Installing |extension2_| should add it to the launcher - behind the
-  // chrome icon.
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, App2, AppList", GetPinnedAppStatus());
-
-  // Installing |extension1_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension1_.get());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, App1, App2, AppList", GetPinnedAppStatus());
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_EQ("Chrome, App1, App2, App3, AppList", GetPinnedAppStatus());
-}
-
-// Check that the restauration of launcher items is happening in the same order
-// as the user has pinned / moved them (on another system) when they are synced
-// random order - including the chrome icon.
-TEST_F(ChromeLauncherControllerPerAppTest,
-    RestoreDefaultAppsRandomOrderChromeMoved) {
-  InitLauncherController();
-
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  InsertPrefValue(&policy_value, 2, extension3_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                  policy_value.DeepCopy());
-  profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
-                                                 1);
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, AppList", GetPinnedAppStatus());
-
-  // Installing |extension2_| should add it to the launcher - behind the
-  // chrome icon.
-  ash::LauncherItem item;
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, App2, AppList", GetPinnedAppStatus());
-
-  // Installing |extension1_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension1_.get());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_EQ("App1, Chrome, App2, AppList", GetPinnedAppStatus());
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_EQ("App1, Chrome, App2, App3, AppList", GetPinnedAppStatus());
-}
-
-// Check that syncing to a different state does the correct thing.
-TEST_F(ChromeLauncherControllerPerAppTest, RestoreDefaultAppsResyncOrder) {
-  InitLauncherController();
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  InsertPrefValue(&policy_value, 2, extension3_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                  policy_value.DeepCopy());
-  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
-  extension_service_->AddExtension(extension2_.get());
-  extension_service_->AddExtension(extension1_.get());
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_EQ("Chrome, App1, App2, App3, AppList", GetPinnedAppStatus());
-
-  // Change the order with increasing chrome position and decreasing position.
-  base::ListValue policy_value1;
-  InsertPrefValue(&policy_value1, 0, extension3_->id());
-  InsertPrefValue(&policy_value1, 1, extension1_->id());
-  InsertPrefValue(&policy_value1, 2, extension2_->id());
-  profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
-                                                 2);
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                  policy_value1.DeepCopy());
-  EXPECT_EQ("App3, App1, Chrome, App2, AppList", GetPinnedAppStatus());
-  base::ListValue policy_value2;
-  InsertPrefValue(&policy_value2, 0, extension2_->id());
-  InsertPrefValue(&policy_value2, 1, extension3_->id());
-  InsertPrefValue(&policy_value2, 2, extension1_->id());
-  profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
-                                                 1);
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                  policy_value2.DeepCopy());
-  EXPECT_EQ("App2, Chrome, App3, App1, AppList", GetPinnedAppStatus());
-}
-
-// Check that simple locking of an application will 'create' a launcher item.
-TEST_F(ChromeLauncherControllerPerAppTest, CheckLockApps) {
-  InitLauncherController();
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
-
-  launcher_controller_->LockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
-
-  launcher_controller_->UnlockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
-}
-
-// Check that multiple locks of an application will be properly handled.
-TEST_F(ChromeLauncherControllerPerAppTest, CheckMukltiLockApps) {
-  InitLauncherController();
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  for (int i = 0; i < 2; i++) {
-    launcher_controller_->LockV1AppWithID(extension1_->id());
-
-    EXPECT_EQ(3, model_->item_count());
-    EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
-    EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-    EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(
-        extension1_->id()));
-  }
-
-  launcher_controller_->UnlockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->UnlockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-}
-
-// Check that already pinned items are not effected by locks.
-TEST_F(ChromeLauncherControllerPerAppTest, CheckAlreadyPinnedLockApps) {
-  InitLauncherController();
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  launcher_controller_->PinAppWithID(extension1_->id());
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->LockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->UnlockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->UnpinAppsWithID(extension1_->id());
-
-  EXPECT_EQ(2, model_->item_count());
-}
-
-// Check that already pinned items which get locked stay after unpinning.
-TEST_F(ChromeLauncherControllerPerAppTest, CheckPinnedAppsStayAfterUnlock) {
-  InitLauncherController();
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->PinAppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->LockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->UnpinAppsWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->UnlockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(2, model_->item_count());
-}
-
-// Check that lock -> pin -> unlock -> unpin does properly transition.
-TEST_F(ChromeLauncherControllerPerAppTest, CheckLockPinUnlockUnpin) {
-  InitLauncherController();
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->LockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->PinAppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->UnlockV1AppWithID(extension1_->id());
-
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(
-      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
-
-  launcher_controller_->UnpinAppsWithID(extension1_->id());
-
-  EXPECT_EQ(2, model_->item_count());
-}
-
-TEST_F(ChromeLauncherControllerPerAppTest, Policy) {
-  extension_service_->AddExtension(extension1_.get());
-  extension_service_->AddExtension(extension3_.get());
-
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
-                                                     policy_value.DeepCopy());
-
-  // Only |extension1_| should get pinned. |extension2_| is specified but not
-  // installed, and |extension3_| is part of the default set, but that shouldn't
-  // take effect when the policy override is in place.
-  InitLauncherController();
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-
-  // Installing |extension2_| should add it to the launcher.
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_EQ(4, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-
-  // Removing |extension1_| from the policy should be reflected in the launcher.
-  policy_value.Remove(0, NULL);
-  profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
-                                                     policy_value.DeepCopy());
-  EXPECT_EQ(3, model_->item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-}
-
-TEST_F(ChromeLauncherControllerPerAppTest, UnpinWithUninstall) {
-  extension_service_->AddExtension(extension3_.get());
-  extension_service_->AddExtension(extension4_.get());
-
-  InitLauncherController();
-
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
-
-  extension_service_->UnloadExtension(extension3_->id(),
-                                      extension_misc::UNLOAD_REASON_UNINSTALL);
-
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
-}
-
-TEST_F(ChromeLauncherControllerPerAppTest, PrefUpdates) {
-  extension_service_->AddExtension(extension2_.get());
-  extension_service_->AddExtension(extension3_.get());
-  extension_service_->AddExtension(extension4_.get());
-
-  InitLauncherController();
-
-  std::vector<std::string> expected_launchers;
-  std::vector<std::string> actual_launchers;
-  base::ListValue pref_value;
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Unavailable extensions don't create launcher items.
-  InsertPrefValue(&pref_value, 0, extension1_->id());
-  InsertPrefValue(&pref_value, 1, extension2_->id());
-  InsertPrefValue(&pref_value, 2, extension4_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  expected_launchers.push_back(extension2_->id());
-  expected_launchers.push_back(extension4_->id());
-  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Redundant pref entries show up only once.
-  InsertPrefValue(&pref_value, 2, extension3_->id());
-  InsertPrefValue(&pref_value, 2, extension3_->id());
-  InsertPrefValue(&pref_value, 5, extension3_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  expected_launchers.insert(expected_launchers.begin() + 1, extension3_->id());
-  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Order changes are reflected correctly.
-  pref_value.Clear();
-  InsertPrefValue(&pref_value, 0, extension4_->id());
-  InsertPrefValue(&pref_value, 1, extension3_->id());
-  InsertPrefValue(&pref_value, 2, extension2_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  std::reverse(expected_launchers.begin(), expected_launchers.end());
-  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Clearing works.
-  pref_value.Clear();
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  expected_launchers.clear();
-  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-}
-
-TEST_F(ChromeLauncherControllerPerAppTest, PendingInsertionOrder) {
-  extension_service_->AddExtension(extension1_.get());
-  extension_service_->AddExtension(extension3_.get());
-
-  InitLauncherController();
-
-  base::ListValue pref_value;
-  InsertPrefValue(&pref_value, 0, extension1_->id());
-  InsertPrefValue(&pref_value, 1, extension2_->id());
-  InsertPrefValue(&pref_value, 2, extension3_->id());
-  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-
-  std::vector<std::string> expected_launchers;
-  expected_launchers.push_back(extension1_->id());
-  expected_launchers.push_back(extension3_->id());
-  std::vector<std::string> actual_launchers;
-
-  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Install |extension2| and verify it shows up between the other two.
-  extension_service_->AddExtension(extension2_.get());
-  expected_launchers.insert(expected_launchers.begin() + 1, extension2_->id());
-  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-}
-
-// Checks the created menus and menu lists for correctness. It uses the given
-// |controller| to create the objects for the given |item| and checks the
-// found item count against the |expected_items|. The |title| list contains the
-// menu titles in the order of their appearance in the menu (not including the
-// application name).
-bool CheckMenuCreation(ChromeLauncherControllerPerApp* controller,
-                       const ash::LauncherItem& item,
-                       size_t expected_items,
-                       string16 title[],
-                       bool is_browser) {
-  ChromeLauncherAppMenuItems items = controller->GetApplicationList(item, 0);
-  // A new behavior has been added: Only show menus if there is at least one
-  // item available.
-  if (expected_items < 1 && is_browser) {
-    EXPECT_EQ(0u, items.size());
-    return items.size() == 0;
-  }
-  // There should be one item in there: The title.
-  EXPECT_EQ(expected_items + 1, items.size());
-  EXPECT_FALSE(items[0]->IsEnabled());
-  for (size_t i = 0; i < expected_items; i++) {
-    EXPECT_EQ(title[i], items[1 + i]->title());
-    // Check that the first real item has a leading separator.
-    if (i == 1)
-      EXPECT_TRUE(items[i]->HasLeadingSeparator());
-    else
-      EXPECT_FALSE(items[i]->HasLeadingSeparator());
-  }
-
-  scoped_ptr<ash::LauncherMenuModel> menu(
-      controller->CreateApplicationMenu(item, 0));
-  // The first element in the menu is a spacing separator. On some systems
-  // (e.g. Windows) such things do not exist. As such we check the existence
-  // and adjust dynamically.
-  int first_item = menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR ? 1 : 0;
-  int expected_menu_items = first_item +
-                            (expected_items ? (expected_items + 3) : 2);
-  EXPECT_EQ(expected_menu_items, menu->GetItemCount());
-  EXPECT_FALSE(menu->IsEnabledAt(first_item));
-  if (expected_items) {
-    EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR,
-              menu->GetTypeAt(first_item + 1));
-  }
-  return items.size() == expected_items + 1;
-}
-
-// Check that browsers get reflected correctly in the launcher menu.
-TEST_F(ChromeLauncherControllerPerAppTest, BrowserMenuGeneration) {
-  EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
-  chrome::NewTab(browser());
-
-  InitLauncherController();
-
-  // Check that the browser list is empty at this time.
-  ash::LauncherItem item_browser;
-  item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
-  item_browser.id =
-      launcher_controller_->GetLauncherIDForAppID(extension_misc::kChromeAppId);
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_browser, 0, NULL, true));
-
-  // Now make the created browser() visible by adding it to the active browser
-  // list.
-  BrowserList::SetLastActive(browser());
-  string16 title1 = ASCIIToUTF16("Test1");
-  NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
-  string16 one_menu_item[] = {title1};
-
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_browser, 1, one_menu_item, true));
-
-  // Create one more browser/window and check that one more was added.
-  Browser::CreateParams ash_params(profile(), chrome::HOST_DESKTOP_TYPE_ASH);
-  scoped_ptr<Browser> browser2(
-      chrome::CreateBrowserWithTestWindowForParams(&ash_params));
-  chrome::NewTab(browser2.get());
-  BrowserList::SetLastActive(browser2.get());
-  string16 title2 = ASCIIToUTF16("Test2");
-  NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"),
-                                      title2);
-
-  // Check that the list contains now two entries - make furthermore sure that
-  // the active item is the first entry.
-  string16 two_menu_items[] = {title1, title2};
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_browser, 2, two_menu_items, true));
-
-  // Apparently we have to close all tabs we have.
-  chrome::CloseTab(browser2.get());
-}
-
-// 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
-// and does not need a separate test here.
-TEST_F(ChromeLauncherControllerPerAppTest, V1AppMenuGeneration) {
-  EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
-  EXPECT_EQ(0, browser()->tab_strip_model()->count());
-
-  InitLauncherControllerWithBrowser();
-
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_->item_count());
-  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
-
-  // 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 one empty tab.
-  chrome::NewTab(browser());
-  string16 title2 = ASCIIToUTF16("Test2");
-  NavigateAndCommitActiveTabWithTitle(
-      browser(),
-      GURL("https://bla"),
-      title2);
-
-  // and another one with another gmail instance.
-  chrome::NewTab(browser());
-  string16 title3 = ASCIIToUTF16("Test3");
-  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3);
-  string16 two_menu_items[] = {title1, title3};
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
-
-  // Even though the item is in the V1 app list, it should also be in the
-  // browser list.
-  string16 browser_menu_item[] = {title3};
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_browser, 1, browser_menu_item, false));
-
-  // Test that closing of (all) the item(s) does work (and all menus get
-  // updated properly).
-  launcher_controller_->Close(item_gmail.id);
-
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_gmail, 0, NULL, false));
-  string16 browser_menu_item2[] = {title2};
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_browser, 1, browser_menu_item2, false));
-}
-
-// Checks that the generated menu list properly activates items.
-TEST_F(ChromeLauncherControllerPerAppTest, V1AppMenuExecution) {
-  InitLauncherControllerWithBrowser();
-
-  // Add |extension3_| to the launcher and add two items.
-  GURL gmail = GURL("https://mail.google.com/mail/u");
-  ash::LauncherID gmail_id = model_->next_id();
-  extension_service_->AddExtension(extension3_.get());
-  launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
-  string16 title1 = ASCIIToUTF16("Test1");
-  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
-  chrome::NewTab(browser());
-  string16 title2 = ASCIIToUTF16("Test2");
-  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
-
-  // Check that the menu is properly set.
-  ash::LauncherItem item_gmail;
-  item_gmail.type = ash::TYPE_APP_SHORTCUT;
-  item_gmail.id = gmail_id;
-  string16 two_menu_items[] = {title1, title2};
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
-  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
-  // Execute the second item in the list (which shouldn't do anything since that
-  // item is per definition already the active tab).
-  {
-    scoped_ptr<ash::LauncherMenuModel> menu(
-        launcher_controller_->CreateApplicationMenu(item_gmail, 0));
-    // The first element in the menu is a spacing separator. On some systems
-    // (e.g. Windows) such things do not exist. As such we check the existence
-    // and adjust dynamically.
-    int first_item =
-        (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
-    menu->ActivatedAt(first_item + 3);
-  }
-  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
-
-  // Execute the first item.
-  {
-    scoped_ptr<ash::LauncherMenuModel> menu(
-        launcher_controller_->CreateApplicationMenu(item_gmail, 0));
-    int first_item =
-        (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
-    menu->ActivatedAt(first_item + 2);
-  }
-  // Now the active tab should be the second item.
-  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
-}
-
-// Checks that the generated menu list properly deletes items.
-TEST_F(ChromeLauncherControllerPerAppTest, V1AppMenuDeletionExecution) {
-  InitLauncherControllerWithBrowser();
-
-  // Add |extension3_| to the launcher and add two items.
-  GURL gmail = GURL("https://mail.google.com/mail/u");
-  ash::LauncherID gmail_id = model_->next_id();
-  extension_service_->AddExtension(extension3_.get());
-  launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
-  string16 title1 = ASCIIToUTF16("Test1");
-  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
-  chrome::NewTab(browser());
-  string16 title2 = ASCIIToUTF16("Test2");
-  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
-
-  // Check that the menu is properly set.
-  ash::LauncherItem item_gmail;
-  item_gmail.type = ash::TYPE_APP_SHORTCUT;
-  item_gmail.id = gmail_id;
-  string16 two_menu_items[] = {title1, title2};
-  EXPECT_TRUE(CheckMenuCreation(
-      launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
-
-  int tabs = browser()->tab_strip_model()->count();
-  // Activate the proper tab through the menu item.
-  {
-    ChromeLauncherAppMenuItems items =
-        launcher_controller_->GetApplicationList(item_gmail, 0);
-    items[1]->Execute(0);
-    EXPECT_EQ(tabs, browser()->tab_strip_model()->count());
-  }
-
-  // Delete one tab through the menu item.
-  {
-    ChromeLauncherAppMenuItems items =
-        launcher_controller_->GetApplicationList(item_gmail, 0);
-    items[1]->Execute(ui::EF_SHIFT_DOWN);
-    EXPECT_EQ(--tabs, browser()->tab_strip_model()->count());
-  }
-}
-
-// Tests that panels create launcher items correctly
-TEST_F(ChromeLauncherControllerPerAppTest, AppPanels) {
-  InitLauncherControllerWithBrowser();
-  EXPECT_EQ(1, model_observer_->added());
-
-  TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl();
-  SetAppIconLoader(app_icon_loader);
-
-  // Test adding an app panel
-  std::string app_id = extension1_->id();
-  ShellWindowLauncherItemController app_panel_controller(
-      LauncherItemController::TYPE_APP_PANEL, "id", app_id,
-      launcher_controller_.get());
-  ash::LauncherID launcher_id1 = launcher_controller_->CreateAppLauncherItem(
-      &app_panel_controller, app_id, ash::STATUS_RUNNING);
-  int panel_index = model_observer_->last_index();
-  EXPECT_EQ(2, model_observer_->added());
-  EXPECT_EQ(0, model_observer_->changed());
-  EXPECT_EQ(1, app_icon_loader->fetch_count());
-  model_observer_->clear_counts();
-
-  // App panels should have a separate identifier than the app id
-  EXPECT_EQ(0, launcher_controller_->GetLauncherIDForAppID(app_id));
-
-  // Setting the app image image should not change the panel if it set its icon
-  app_panel_controller.set_image_set_by_controller(true);
-  gfx::ImageSkia image;
-  launcher_controller_->SetAppImage(app_id, image);
-  EXPECT_EQ(0, model_observer_->changed());
-  model_observer_->clear_counts();
-
-  // Add a second app panel and verify that it get the same index as the first
-  // one had, being added to the left of the existing panel.
-  ash::LauncherID launcher_id2 = launcher_controller_->CreateAppLauncherItem(
-      &app_panel_controller, app_id, ash::STATUS_RUNNING);
-  EXPECT_EQ(panel_index, model_observer_->last_index());
-  EXPECT_EQ(1, model_observer_->added());
-  model_observer_->clear_counts();
-
-  launcher_controller_->CloseLauncherItem(launcher_id2);
-  launcher_controller_->CloseLauncherItem(launcher_id1);
-  EXPECT_EQ(2, model_observer_->removed());
-}
-
-// Tests that the Gmail extension matches more then the app itself claims with
-// the manifest file.
-TEST_F(ChromeLauncherControllerPerAppTest, GmailMatching) {
-  InitLauncherControllerWithBrowser();
-
-  // Create a Gmail browser tab.
-  chrome::NewTab(browser());
-  string16 title = ASCIIToUTF16("Test");
-  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title);
-  content::WebContents* content =
-      browser()->tab_strip_model()->GetActiveWebContents();
-
-  // Check that the launcher controller does not recognize the running app.
-  EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
-
-  // 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()));
-
-  // Check that it is now handled.
-  EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
-
-  // Check also that the app has detected that properly.
-  ash::LauncherItem item_gmail;
-  item_gmail.type = ash::TYPE_APP_SHORTCUT;
-  item_gmail.id = gmail_id;
-  EXPECT_EQ(2U, launcher_controller_->GetApplicationList(item_gmail, 0).size());
-}
-
-// Tests that the Gmail extension does not match the offline verison.
-TEST_F(ChromeLauncherControllerPerAppTest, GmailOfflineMatching) {
-  InitLauncherControllerWithBrowser();
-
-  // Create a Gmail browser tab.
-  chrome::NewTab(browser());
-  string16 title = ASCIIToUTF16("Test");
-  NavigateAndCommitActiveTabWithTitle(browser(),
-                                      GURL(offline_gmail_url),
-                                      title);
-  content::WebContents* content =
-      browser()->tab_strip_model()->GetActiveWebContents();
-
-  // 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()));
-
-  // The content should not be able to be handled by the app.
-  EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
deleted file mode 100644
index 3c2360a..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc
+++ /dev/null
@@ -1,1477 +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/launcher/chrome_launcher_controller_per_browser.h"
-
-#include <vector>
-
-#include "ash/ash_switches.h"
-#include "ash/launcher/launcher_model.h"
-#include "ash/root_window_controller.h"
-#include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_widget.h"
-#include "ash/shell.h"
-#include "ash/wm/window_util.h"
-#include "base/command_line.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/values.h"
-#include "chrome/browser/app_mode/app_mode_utils.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/app_icon_loader_impl.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.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"
-#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
-#include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
-#include "chrome/browser/ui/ash/launcher/launcher_context_menu.h"
-#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
-#include "chrome/browser/ui/ash/launcher/shell_window_launcher_controller.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_tabstrip.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/extensions/extension_enable_flow.h"
-#include "chrome/browser/ui/host_desktop.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/web_applications/web_app.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/common/url_pattern.h"
-#include "grit/chromium_strings.h"
-#include "grit/theme_resources.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/base/l10n/l10n_util.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h"
-#endif
-
-using content::WebContents;
-using extensions::Extension;
-
-namespace {
-
-// Item controller for an app shortcut. Shortcuts track app and launcher ids,
-// but do not have any associated windows (opening a shortcut will replace the
-// item with the appropriate LauncherItemController type).
-class AppShortcutLauncherItemController : public LauncherItemController {
- public:
-  AppShortcutLauncherItemController(
-      const std::string& app_id,
-      ChromeLauncherControllerPerBrowser* controller)
-      : LauncherItemController(TYPE_SHORTCUT, app_id, controller) {
-    // Google Drive should just refocus to it's main app UI.
-    // TODO(davemoore): Generalize this for other applications.
-    if (app_id == "apdfllckaahabafndbhieahigkjlhalf") {
-      const Extension* extension =
-          launcher_controller()->GetExtensionForAppID(app_id);
-      refocus_url_ = GURL(
-          extensions::AppLaunchInfo::GetLaunchWebURL(extension).spec() + "*");
-    }
-  }
-
-  virtual ~AppShortcutLauncherItemController() {}
-
-  // LauncherItemController overrides:
-  virtual string16 GetTitle() OVERRIDE {
-    return GetAppTitle();
-  }
-
-  virtual bool HasWindow(aura::Window* window) const OVERRIDE {
-    return false;
-  }
-
-  virtual bool IsOpen() const OVERRIDE {
-    return false;
-  }
-
-  virtual bool IsVisible() const OVERRIDE {
-    return false;
-  }
-
-  virtual void Launch(int event_flags) OVERRIDE {
-    launcher_controller()->LaunchApp(app_id(), event_flags);
-  }
-
-  virtual void Activate() OVERRIDE {
-    launcher_controller()->ActivateApp(app_id(), ui::EF_NONE);
-  }
-
-  virtual void Close() OVERRIDE {
-    // TODO: maybe should treat as unpin?
-  }
-
-  virtual void Clicked(const ui::Event& event) OVERRIDE {
-    Activate();
-  }
-
-  virtual void OnRemoved() OVERRIDE {
-    // AppShortcutLauncherItemController is unowned; delete on removal.
-    delete this;
-  }
-
-  virtual void LauncherItemChanged(
-      int model_index,
-      const ash::LauncherItem& old_item) OVERRIDE {
-  }
-
-  virtual ChromeLauncherAppMenuItems GetApplicationList(
-      int event_flags) OVERRIDE {
-    ChromeLauncherAppMenuItems items;
-    return items.Pass();
-  }
-
-  // Stores the optional refocus url pattern for this item.
-  const GURL& refocus_url() const { return refocus_url_; }
-  void set_refocus_url(const GURL& refocus_url) { refocus_url_ = refocus_url; }
-
- private:
-  GURL refocus_url_;
-  DISALLOW_COPY_AND_ASSIGN(AppShortcutLauncherItemController);
-};
-
-std::string GetPrefKeyForRootWindow(aura::RootWindow* root_window) {
-  gfx::Display display = gfx::Screen::GetScreenFor(
-      root_window)->GetDisplayNearestWindow(root_window);
-  DCHECK(display.is_valid());
-
-  return base::Int64ToString(display.id());
-}
-
-void UpdatePerDisplayPref(PrefService* pref_service,
-                          aura::RootWindow* root_window,
-                          const char* pref_key,
-                          const std::string& value) {
-  std::string key = GetPrefKeyForRootWindow(root_window);
-  if (key.empty())
-    return;
-
-  DictionaryPrefUpdate update(pref_service, prefs::kShelfPreferences);
-  base::DictionaryValue* shelf_prefs = update.Get();
-  base::DictionaryValue* prefs = NULL;
-  if (!shelf_prefs->GetDictionary(key, &prefs)) {
-    prefs = new base::DictionaryValue();
-    shelf_prefs->Set(key, prefs);
-  }
-  prefs->SetStringWithoutPathExpansion(pref_key, value);
-}
-
-// Returns a pref value in |pref_service| for the display of |root_window|. The
-// pref value is stored in |local_path| and |path|, but |pref_service| may have
-// per-display preferences and the value can be specified by policy. Here is
-// the priority:
-//  * A value managed by policy. This is a single value that applies to all
-//    displays.
-//  * A user-set value for the specified display.
-//  * A user-set value in |local_path| or |path|, if no per-display settings are
-//    ever specified (see http://crbug.com/173719 for why). |local_path| is
-//    preferred. See comment in |kShelfAlignment| as to why we consider two
-//    prefs and why |local_path| is preferred.
-//  * A value recommended by policy. This is a single value that applies to all
-//    root windows.
-//  * The default value for |local_path| if the value is not recommended by
-//    policy.
-std::string GetPrefForRootWindow(PrefService* pref_service,
-                                 aura::RootWindow* root_window,
-                                 const char* local_path,
-                                 const char* path) {
-  const PrefService::Preference* local_pref =
-      pref_service->FindPreference(local_path);
-  const std::string value(pref_service->GetString(local_path));
-  if (local_pref->IsManaged())
-    return value;
-
-  std::string pref_key = GetPrefKeyForRootWindow(root_window);
-  bool has_per_display_prefs = false;
-  if (!pref_key.empty()) {
-    const base::DictionaryValue* shelf_prefs = pref_service->GetDictionary(
-        prefs::kShelfPreferences);
-    const base::DictionaryValue* display_pref = NULL;
-    std::string per_display_value;
-    if (shelf_prefs->GetDictionary(pref_key, &display_pref) &&
-        display_pref->GetString(path, &per_display_value))
-      return per_display_value;
-
-    // If the pref for the specified display is not found, scan the whole prefs
-    // and check if the prefs for other display is already specified.
-    std::string unused_value;
-    for (base::DictionaryValue::Iterator iter(*shelf_prefs);
-         !iter.IsAtEnd(); iter.Advance()) {
-      const base::DictionaryValue* display_pref = NULL;
-      if (iter.value().GetAsDictionary(&display_pref) &&
-          display_pref->GetString(path, &unused_value)) {
-        has_per_display_prefs = true;
-        break;
-      }
-    }
-  }
-
-  if (local_pref->IsRecommended() || !has_per_display_prefs)
-    return value;
-
-  const base::Value* default_value =
-      pref_service->GetDefaultPrefValue(local_path);
-  std::string default_string;
-  default_value->GetAsString(&default_string);
-  return default_string;
-}
-
-// If prefs have synced and no user-set value exists at |local_path|, the value
-// from |synced_path| is copied to |local_path|.
-void MaybePropagatePrefToLocal(PrefServiceSyncable* pref_service,
-                               const char* local_path,
-                               const char* synced_path) {
-  if (!pref_service->FindPreference(local_path)->HasUserSetting() &&
-      pref_service->IsSyncing()) {
-    // First time the user is using this machine, propagate from remote to
-    // local.
-    pref_service->SetString(local_path, pref_service->GetString(synced_path));
-  }
-}
-
-}  // namespace
-
-// ChromeLauncherControllerPerBrowser -----------------------------------------
-
-ChromeLauncherControllerPerBrowser::ChromeLauncherControllerPerBrowser(
-    Profile* profile,
-    ash::LauncherModel* model)
-    : model_(model),
-      profile_(profile),
-      app_sync_ui_state_(NULL),
-      ignore_persist_pinned_state_change_(false) {
-  if (!profile_) {
-    // Use the original profile as on chromeos we may get a temporary off the
-    // record profile.
-    profile_ = ProfileManager::GetDefaultProfile()->GetOriginalProfile();
-
-    app_sync_ui_state_ = AppSyncUIState::Get(profile_);
-    if (app_sync_ui_state_)
-      app_sync_ui_state_->AddObserver(this);
-  }
-
-  model_->AddObserver(this);
-  // Right now ash::Shell isn't created for tests.
-  // TODO(mukai): Allows it to observe display change and write tests.
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetInstance()->display_controller()->AddObserver(this);
-  // TODO(stevenjb): Find a better owner for shell_window_controller_?
-  shell_window_controller_.reset(new ShellWindowLauncherController(this));
-  app_tab_helper_.reset(new LauncherAppTabHelper(profile_));
-  app_icon_loader_.reset(new extensions::AppIconLoaderImpl(
-      profile_, extension_misc::EXTENSION_ICON_SMALL, this));
-
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_EXTENSION_LOADED,
-                              content::Source<Profile>(profile_));
-  notification_registrar_.Add(this,
-                              chrome::NOTIFICATION_EXTENSION_UNLOADED,
-                              content::Source<Profile>(profile_));
-  pref_change_registrar_.Init(profile_->GetPrefs());
-  pref_change_registrar_.Add(
-      prefs::kPinnedLauncherApps,
-      base::Bind(&ChromeLauncherControllerPerBrowser::
-                     UpdateAppLaunchersFromPref,
-                 base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kShelfAlignmentLocal,
-      base::Bind(&ChromeLauncherControllerPerBrowser::
-                     SetShelfAlignmentFromPrefs,
-                 base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kShelfAutoHideBehaviorLocal,
-      base::Bind(&ChromeLauncherControllerPerBrowser::
-                     SetShelfAutoHideBehaviorFromPrefs,
-                 base::Unretained(this)));
-  pref_change_registrar_.Add(
-      prefs::kShelfPreferences,
-      base::Bind(&ChromeLauncherControllerPerBrowser::
-                     SetShelfBehaviorsFromPrefs,
-                 base::Unretained(this)));
-}
-
-ChromeLauncherControllerPerBrowser::~ChromeLauncherControllerPerBrowser() {
-  // Reset the shell window controller here since it has a weak pointer to
-  // this.
-  shell_window_controller_.reset();
-
-  for (std::set<ash::Launcher*>::iterator iter = launchers_.begin();
-       iter != launchers_.end();
-       ++iter)
-    (*iter)->shelf_widget()->shelf_layout_manager()->RemoveObserver(this);
-
-  model_->RemoveObserver(this);
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
-  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    i->second->OnRemoved();
-    model_->RemoveItemAt(model_->ItemIndexByID(i->first));
-  }
-
-  if (ash::Shell::HasInstance())
-    ash::Shell::GetInstance()->RemoveShellObserver(this);
-
-  if (app_sync_ui_state_)
-    app_sync_ui_state_->RemoveObserver(this);
-
-  PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
-}
-
-void ChromeLauncherControllerPerBrowser::Init() {
-  UpdateAppLaunchersFromPref();
-  CreateBrowserShortcutLauncherItem();
-
-  // TODO(sky): update unit test so that this test isn't necessary.
-  if (ash::Shell::HasInstance()) {
-    SetShelfAutoHideBehaviorFromPrefs();
-    SetShelfAlignmentFromPrefs();
-    PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
-    if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() ||
-        !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)->
-            HasUserSetting()) {
-      // This causes OnIsSyncingChanged to be called when the value of
-      // PrefService::IsSyncing() changes.
-      prefs->AddObserver(this);
-    }
-    ash::Shell::GetInstance()->AddShellObserver(this);
-  }
-}
-
-ChromeLauncherControllerPerApp*
-ChromeLauncherControllerPerBrowser::GetPerAppInterface() {
-  return NULL;
-}
-
-ash::LauncherID ChromeLauncherControllerPerBrowser::CreateTabbedLauncherItem(
-    LauncherItemController* controller,
-    IncognitoState is_incognito,
-    ash::LauncherItemStatus status) {
-  ash::LauncherID id = model_->next_id();
-  DCHECK(!HasItemController(id));
-  DCHECK(controller);
-  id_to_item_controller_map_[id] = controller;
-  controller->set_launcher_id(id);
-
-  ash::LauncherItem item;
-  item.type = ash::TYPE_TABBED;
-  item.is_incognito = (is_incognito == STATE_INCOGNITO);
-  item.status = status;
-  model_->Add(item);
-  return id;
-}
-
-ash::LauncherID ChromeLauncherControllerPerBrowser::CreateAppLauncherItem(
-    LauncherItemController* controller,
-    const std::string& app_id,
-    ash::LauncherItemStatus status) {
-  DCHECK(controller);
-  int index = 0;
-  // Panels are inserted on the left so as not to push all existing panels over.
-  if (controller->GetLauncherItemType() != ash::TYPE_APP_PANEL) {
-    index = model_->item_count();
-    // For the alternate shelf layout increment index (insert after app icon).
-    if (ash::switches::UseAlternateShelfLayout())
-      ++index;
-  }
-  return InsertAppLauncherItem(controller, app_id, status, index);
-}
-
-void ChromeLauncherControllerPerBrowser::SetItemStatus(
-    ash::LauncherID id,
-    ash::LauncherItemStatus status) {
-  int index = model_->ItemIndexByID(id);
-  DCHECK_GE(index, 0);
-  ash::LauncherItem item = model_->items()[index];
-  item.status = status;
-  model_->Set(index, item);
-}
-
-void ChromeLauncherControllerPerBrowser::SetItemController(
-    ash::LauncherID id,
-    LauncherItemController* controller) {
-  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
-  DCHECK(iter != id_to_item_controller_map_.end());
-  iter->second->OnRemoved();
-  iter->second = controller;
-  controller->set_launcher_id(id);
-}
-
-void ChromeLauncherControllerPerBrowser::CloseLauncherItem(
-    ash::LauncherID id) {
-  if (IsPinned(id)) {
-    // Create a new shortcut controller.
-    IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
-    DCHECK(iter != id_to_item_controller_map_.end());
-    SetItemStatus(id, ash::STATUS_CLOSED);
-    std::string app_id = iter->second->app_id();
-    iter->second->OnRemoved();
-    iter->second = new AppShortcutLauncherItemController(app_id, this);
-    iter->second->set_launcher_id(id);
-  } else {
-    LauncherItemClosed(id);
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::Unpin(ash::LauncherID id) {
-  DCHECK(HasItemController(id));
-
-  LauncherItemController* controller = id_to_item_controller_map_[id];
-  if (controller->type() == LauncherItemController::TYPE_APP) {
-    int index = model_->ItemIndexByID(id);
-    ash::LauncherItem item = model_->items()[index];
-    item.type = ash::TYPE_PLATFORM_APP;
-    model_->Set(index, item);
-  } else {
-    LauncherItemClosed(id);
-  }
-  if (CanPin())
-    PersistPinnedState();
-}
-
-void ChromeLauncherControllerPerBrowser::Pin(ash::LauncherID id) {
-  DCHECK(HasItemController(id));
-
-  int index = model_->ItemIndexByID(id);
-  ash::LauncherItem item = model_->items()[index];
-
-  if (item.type != ash::TYPE_PLATFORM_APP)
-    return;
-
-  item.type = ash::TYPE_APP_SHORTCUT;
-  model_->Set(index, item);
-
-  if (CanPin())
-    PersistPinnedState();
-}
-
-bool ChromeLauncherControllerPerBrowser::IsPinned(ash::LauncherID id) {
-  int index = model_->ItemIndexByID(id);
-  ash::LauncherItemType type = model_->items()[index].type;
-  return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT);
-}
-
-void ChromeLauncherControllerPerBrowser::TogglePinned(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return;  // May happen if item closed with menu open.
-
-  if (IsPinned(id))
-    Unpin(id);
-  else
-    Pin(id);
-}
-
-bool ChromeLauncherControllerPerBrowser::IsPinnable(ash::LauncherID id) const {
-  int index = model_->ItemIndexByID(id);
-  if (index == -1)
-    return false;
-
-  ash::LauncherItemType type = model_->items()[index].type;
-  return ((type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_PLATFORM_APP) &&
-          CanPin());
-}
-
-void ChromeLauncherControllerPerBrowser::LockV1AppWithID(
-    const std::string& app_id) {
-}
-
-void ChromeLauncherControllerPerBrowser::UnlockV1AppWithID(
-    const std::string& app_id) {
-}
-
-void ChromeLauncherControllerPerBrowser::Launch(
-    ash::LauncherID id, int event_flags) {
-  if (!HasItemController(id))
-    return;  // In case invoked from menu and item closed while menu up.
-  id_to_item_controller_map_[id]->Launch(event_flags);
-}
-
-void ChromeLauncherControllerPerBrowser::Close(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return;  // May happen if menu closed.
-  id_to_item_controller_map_[id]->Close();
-}
-
-bool ChromeLauncherControllerPerBrowser::IsOpen(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return false;
-  return id_to_item_controller_map_[id]->IsOpen();
-}
-
-bool ChromeLauncherControllerPerBrowser::IsPlatformApp(ash::LauncherID id) {
-  if (!HasItemController(id))
-    return false;
-
-  std::string app_id = GetAppIDForLauncherID(id);
-  const Extension* extension = GetExtensionForAppID(app_id);
-  DCHECK(extension);
-  return extension->is_platform_app();
-}
-
-void ChromeLauncherControllerPerBrowser::LaunchApp(const std::string& app_id,
-                                                   int event_flags) {
-  // |extension| could be NULL when it is being unloaded for updating.
-  const Extension* extension = GetExtensionForAppID(app_id);
-  if (!extension)
-    return;
-
-  const ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  if (!service->IsExtensionEnabledForLauncher(app_id)) {
-    // Do nothing if there is already a running enable flow.
-    if (extension_enable_flow_)
-      return;
-
-    extension_enable_flow_.reset(
-        new ExtensionEnableFlow(profile_, app_id, this));
-    extension_enable_flow_->StartForNativeWindow(NULL);
-    return;
-  }
-
-  chrome::OpenApplication(chrome::AppLaunchParams(GetProfileForNewWindows(),
-                                                  extension,
-                                                  event_flags));
-}
-
-void ChromeLauncherControllerPerBrowser::ActivateApp(const std::string& app_id,
-                                                     int event_flags) {
-  if (app_id == extension_misc::kChromeAppId) {
-    BrowserShortcutClicked(event_flags);
-    return;
-  }
-
-  // If there is an existing non-shortcut controller for this app, open it.
-  ash::LauncherID id = GetLauncherIDForAppID(app_id);
-  URLPattern refocus_pattern(URLPattern::SCHEME_ALL);
-  refocus_pattern.SetMatchAllURLs(true);
-
-  if (id > 0) {
-    LauncherItemController* controller = id_to_item_controller_map_[id];
-    if (controller->type() != LauncherItemController::TYPE_SHORTCUT) {
-      controller->Activate();
-      return;
-    }
-
-    AppShortcutLauncherItemController* app_controller =
-        static_cast<AppShortcutLauncherItemController*>(controller);
-    const GURL refocus_url = app_controller->refocus_url();
-
-    if (!refocus_url.is_empty())
-      refocus_pattern.Parse(refocus_url.spec());
-  }
-
-  // Check if there are any open tabs for this app.
-  AppIDToWebContentsListMap::iterator app_i =
-      app_id_to_web_contents_list_.find(app_id);
-  if (app_i != app_id_to_web_contents_list_.end()) {
-    for (WebContentsList::iterator tab_i = app_i->second.begin();
-         tab_i != app_i->second.end();
-         ++tab_i) {
-      WebContents* tab = *tab_i;
-      const GURL tab_url = tab->GetURL();
-      if (refocus_pattern.MatchesURL(tab_url)) {
-        Browser* browser = chrome::FindBrowserWithWebContents(tab);
-        TabStripModel* tab_strip = browser->tab_strip_model();
-        int index = tab_strip->GetIndexOfWebContents(tab);
-        DCHECK_NE(TabStripModel::kNoTab, index);
-        tab_strip->ActivateTabAt(index, false);
-        browser->window()->Show();
-        ash::wm::ActivateWindow(browser->window()->GetNativeWindow());
-        return;
-      }
-    }
-  }
-
-  LaunchApp(app_id, event_flags);
-}
-
-extensions::ExtensionPrefs::LaunchType
-    ChromeLauncherControllerPerBrowser::GetLaunchType(ash::LauncherID id) {
-  DCHECK(HasItemController(id));
-
-  const Extension* extension = GetExtensionForAppID(
-      id_to_item_controller_map_[id]->app_id());
-  return profile_->GetExtensionService()->extension_prefs()->GetLaunchType(
-      extension,
-      extensions::ExtensionPrefs::LAUNCH_DEFAULT);
-}
-
-std::string ChromeLauncherControllerPerBrowser::GetAppID(
-    content::WebContents* tab) {
-  return app_tab_helper_->GetAppID(tab);
-}
-
-ash::LauncherID ChromeLauncherControllerPerBrowser::GetLauncherIDForAppID(
-    const std::string& app_id) {
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    if (i->second->type() == LauncherItemController::TYPE_APP_PANEL)
-      continue;  // Don't include panels
-    if (i->second->app_id() == app_id)
-      return i->first;
-  }
-  return 0;
-}
-
-std::string ChromeLauncherControllerPerBrowser::GetAppIDForLauncherID(
-    ash::LauncherID id) {
-  DCHECK(HasItemController(id));
-  return id_to_item_controller_map_[id]->app_id();
-}
-
-void ChromeLauncherControllerPerBrowser::SetAppImage(
-    const std::string& id,
-    const gfx::ImageSkia& image) {
-  // TODO: need to get this working for shortcuts.
-
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    if (i->second->app_id() != id)
-      continue;
-
-    int index = model_->ItemIndexByID(i->first);
-    ash::LauncherItem item = model_->items()[index];
-    item.image = image;
-    model_->Set(index, item);
-    // It's possible we're waiting on more than one item, so don't break.
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::OnAutoHideBehaviorChanged(
-    aura::RootWindow* root_window,
-    ash::ShelfAutoHideBehavior new_behavior) {
-  SetShelfAutoHideBehaviorPrefs(new_behavior, root_window);
-}
-
-void ChromeLauncherControllerPerBrowser::SetLauncherItemImage(
-    ash::LauncherID launcher_id,
-    const gfx::ImageSkia& image) {
-  int index = model_->ItemIndexByID(launcher_id);
-  if (index == -1)
-    return;
-  ash::LauncherItem item = model_->items()[index];
-  item.image = image;
-  model_->Set(index, item);
-}
-
-bool ChromeLauncherControllerPerBrowser::IsAppPinned(
-    const std::string& app_id) {
-  // Check the LauncherModel since there is no controller for the browser item.
-  if (app_id == extension_misc::kChromeAppId) {
-    for (size_t index = 0; index < model_->items().size(); index++) {
-      if (model_->items()[index].type == ash::TYPE_BROWSER_SHORTCUT)
-        return true;
-    }
-    return false;
-  }
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    if (IsPinned(i->first) && i->second->app_id() == app_id)
-      return true;
-  }
-  return false;
-}
-
-void ChromeLauncherControllerPerBrowser::PinAppWithID(
-    const std::string& app_id) {
-  if (CanPin())
-    DoPinAppWithID(app_id);
-  else
-    NOTREACHED();
-}
-
-void ChromeLauncherControllerPerBrowser::SetLaunchType(
-    ash::LauncherID id,
-    extensions::ExtensionPrefs::LaunchType launch_type) {
-  if (!HasItemController(id))
-    return;
-
-  return profile_->GetExtensionService()->extension_prefs()->SetLaunchType(
-      id_to_item_controller_map_[id]->app_id(), launch_type);
-}
-
-void ChromeLauncherControllerPerBrowser::UnpinAppsWithID(
-    const std::string& app_id) {
-  if (CanPin())
-    DoUnpinAppsWithID(app_id);
-  else
-    NOTREACHED();
-}
-
-bool ChromeLauncherControllerPerBrowser::IsLoggedInAsGuest() {
-  return ProfileManager::GetDefaultProfileOrOffTheRecord()->IsOffTheRecord();
-}
-
-void ChromeLauncherControllerPerBrowser::CreateNewWindow() {
-  chrome::NewEmptyWindow(
-      GetProfileForNewWindows(), chrome::HOST_DESKTOP_TYPE_ASH);
-}
-
-void ChromeLauncherControllerPerBrowser::CreateNewIncognitoWindow() {
-  chrome::NewEmptyWindow(GetProfileForNewWindows()->GetOffTheRecordProfile(),
-                         chrome::HOST_DESKTOP_TYPE_ASH);
-}
-
-bool ChromeLauncherControllerPerBrowser::CanPin() const {
-  const PrefService::Preference* pref =
-      profile_->GetPrefs()->FindPreference(prefs::kPinnedLauncherApps);
-  return pref && pref->IsUserModifiable();
-}
-
-ash::ShelfAutoHideBehavior
-    ChromeLauncherControllerPerBrowser::GetShelfAutoHideBehavior(
-        aura::RootWindow* root_window) const {
-  // Don't show the shelf in the app mode.
-  if (chrome::IsRunningInAppMode())
-    return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
-
-  // See comment in |kShelfAlignment| as to why we consider two prefs.
-  const std::string behavior_value(
-      GetPrefForRootWindow(profile_->GetPrefs(),
-                           root_window,
-                           prefs::kShelfAutoHideBehaviorLocal,
-                           prefs::kShelfAutoHideBehavior));
-
-  // Note: To maintain sync compatibility with old images of chrome/chromeos
-  // the set of values that may be encountered includes the now-extinct
-  // "Default" as well as "Never" and "Always", "Default" should now
-  // be treated as "Never" (http://crbug.com/146773).
-  if (behavior_value == ash::kShelfAutoHideBehaviorAlways)
-    return ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
-  return ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER;
-}
-
-bool ChromeLauncherControllerPerBrowser::CanUserModifyShelfAutoHideBehavior(
-    aura::RootWindow* root_window) const {
-  return profile_->GetPrefs()->
-      FindPreference(prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
-}
-
-void ChromeLauncherControllerPerBrowser::ToggleShelfAutoHideBehavior(
-    aura::RootWindow* root_window) {
-  ash::ShelfAutoHideBehavior behavior = GetShelfAutoHideBehavior(root_window) ==
-      ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS ?
-          ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER :
-          ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
-  SetShelfAutoHideBehaviorPrefs(behavior, root_window);
-  return;
-}
-
-void ChromeLauncherControllerPerBrowser::RemoveTabFromRunningApp(
-    WebContents* tab,
-    const std::string& app_id) {
-  web_contents_to_app_id_.erase(tab);
-  AppIDToWebContentsListMap::iterator i_app_id =
-      app_id_to_web_contents_list_.find(app_id);
-  if (i_app_id != app_id_to_web_contents_list_.end()) {
-    WebContentsList* tab_list = &i_app_id->second;
-    tab_list->remove(tab);
-    if (tab_list->empty()) {
-      app_id_to_web_contents_list_.erase(i_app_id);
-      i_app_id = app_id_to_web_contents_list_.end();
-      ash::LauncherID id = GetLauncherIDForAppID(app_id);
-      if (id > 0)
-        SetItemStatus(id, ash::STATUS_CLOSED);
-    }
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::UpdateAppState(
-    content::WebContents* contents,
-    AppState app_state) {
-  std::string app_id = GetAppID(contents);
-
-  // Check the old |app_id| for a tab. If the contents has changed we need to
-  // remove it from the previous app.
-  if (web_contents_to_app_id_.find(contents) != web_contents_to_app_id_.end()) {
-    std::string last_app_id = web_contents_to_app_id_[contents];
-    if (last_app_id != app_id)
-      RemoveTabFromRunningApp(contents, last_app_id);
-  }
-
-  if (app_id.empty())
-    return;
-
-  web_contents_to_app_id_[contents] = app_id;
-
-  if (app_state == APP_STATE_REMOVED) {
-    // The tab has gone away.
-    RemoveTabFromRunningApp(contents, app_id);
-  } else {
-    WebContentsList& tab_list(app_id_to_web_contents_list_[app_id]);
-
-    if (app_state == APP_STATE_INACTIVE) {
-      WebContentsList::const_iterator i_tab =
-          std::find(tab_list.begin(), tab_list.end(), contents);
-      if (i_tab == tab_list.end())
-        tab_list.push_back(contents);
-      if (i_tab != tab_list.begin()) {
-        // Going inactive, but wasn't the front tab, indicating that a new
-        // tab has already become active.
-        return;
-      }
-    } else {
-      tab_list.remove(contents);
-      tab_list.push_front(contents);
-    }
-    ash::LauncherID id = GetLauncherIDForAppID(app_id);
-    if (id > 0) {
-      // If the window is active, mark the app as active.
-      SetItemStatus(id, app_state == APP_STATE_WINDOW_ACTIVE ?
-          ash::STATUS_ACTIVE : ash::STATUS_RUNNING);
-    }
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::SetRefocusURLPatternForTest(
-    ash::LauncherID id,
-    const GURL& url) {
-  DCHECK(HasItemController(id));
-  LauncherItemController* controller = id_to_item_controller_map_[id];
-
-  int index = model_->ItemIndexByID(id);
-  if (index == -1) {
-    NOTREACHED() << "Invalid launcher id";
-    return;
-  }
-
-  ash::LauncherItemType type = model_->items()[index].type;
-  if (type == ash::TYPE_APP_SHORTCUT) {
-    AppShortcutLauncherItemController* app_controller =
-        static_cast<AppShortcutLauncherItemController*>(controller);
-    app_controller->set_refocus_url(url);
-  } else {
-    NOTREACHED() << "Invalid launcher type";
-  }
-}
-
-const Extension* ChromeLauncherControllerPerBrowser::GetExtensionForAppID(
-    const std::string& app_id) const {
-  return profile_->GetExtensionService()->GetInstalledExtension(app_id);
-}
-
-void ChromeLauncherControllerPerBrowser::ActivateWindowOrMinimizeIfActive(
-    ui::BaseWindow* window,
-    bool allow_minimize) {
-  window->Show();
-  window->Activate();
-}
-
-void ChromeLauncherControllerPerBrowser::BrowserShortcutClicked(
-    int event_flags) {
-#if defined(OS_CHROMEOS)
-  chromeos::default_pinned_apps_field_trial::RecordShelfClick(
-      chromeos::default_pinned_apps_field_trial::CHROME);
-#endif
-  if (event_flags & ui::EF_CONTROL_DOWN) {
-    CreateNewWindow();
-    return;
-  }
-
-  Browser* last_browser = chrome::FindTabbedBrowser(
-      GetProfileForNewWindows(), true, chrome::HOST_DESKTOP_TYPE_ASH);
-
-  if (!last_browser) {
-    CreateNewWindow();
-    return;
-  }
-
-  aura::Window* window = last_browser->window()->GetNativeWindow();
-  window->Show();
-  ash::wm::ActivateWindow(window);
-}
-
-void ChromeLauncherControllerPerBrowser::ItemSelected(
-    const ash::LauncherItem& item,
-    const ui::Event& event) {
-  if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
-    BrowserShortcutClicked(event.flags());
-    return;
-  }
-
-  DCHECK(HasItemController(item.id));
-  LauncherItemController* item_controller = id_to_item_controller_map_[item.id];
-#if defined(OS_CHROMEOS)
-  if (!item_controller->app_id().empty()) {
-    chromeos::default_pinned_apps_field_trial::RecordShelfAppClick(
-        item_controller->app_id());
-  }
-#endif
-  item_controller->Clicked(event);
-}
-
-string16 ChromeLauncherControllerPerBrowser::GetTitle(
-    const ash::LauncherItem& item) {
-  if (item.type == ash::TYPE_BROWSER_SHORTCUT)
-    return l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
-
-  DCHECK(HasItemController(item.id));
-  return id_to_item_controller_map_[item.id]->GetTitle();
-}
-
-ui::MenuModel* ChromeLauncherControllerPerBrowser::CreateContextMenu(
-    const ash::LauncherItem& item,
-    aura::RootWindow* root_window) {
-  return new LauncherContextMenu(this, &item, root_window);
-}
-
-ash::LauncherMenuModel*
-ChromeLauncherControllerPerBrowser::CreateApplicationMenu(
-    const ash::LauncherItem& item,
-    int event_flags) {
-  // Not used by this launcher type.
-  return NULL;
-}
-
-ash::LauncherID ChromeLauncherControllerPerBrowser::GetIDByWindow(
-    aura::Window* window) {
-  for (IDToItemControllerMap::const_iterator i =
-           id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ++i) {
-    if (i->second->HasWindow(window))
-      return i->first;
-  }
-  return 0;
-}
-
-bool ChromeLauncherControllerPerBrowser::IsDraggable(
-    const ash::LauncherItem& item) {
-  return item.type == ash::TYPE_APP_SHORTCUT ? CanPin() : true;
-}
-
-bool ChromeLauncherControllerPerBrowser::ShouldShowTooltip(
-    const ash::LauncherItem& item) {
-  if (item.type == ash::TYPE_APP_PANEL &&
-      id_to_item_controller_map_[item.id]->IsVisible())
-    return false;
-  return true;
-}
-
-void ChromeLauncherControllerPerBrowser::OnLauncherCreated(
-    ash::Launcher* launcher) {
-  launchers_.insert(launcher);
-  launcher->shelf_widget()->shelf_layout_manager()->AddObserver(this);
-}
-
-void ChromeLauncherControllerPerBrowser::OnLauncherDestroyed(
-    ash::Launcher* launcher) {
-  launchers_.erase(launcher);
-  // RemoveObserver is not called here, since by the time this method is called
-  // Launcher is already in its destructor.
-}
-
-void ChromeLauncherControllerPerBrowser::LauncherItemAdded(int index) {
-}
-
-void ChromeLauncherControllerPerBrowser::LauncherItemRemoved(
-    int index,
-    ash::LauncherID id) {
-}
-
-void ChromeLauncherControllerPerBrowser::LauncherItemMoved(
-    int start_index,
-    int target_index) {
-  ash::LauncherID id = model_->items()[target_index].id;
-  if (HasItemController(id) && IsPinned(id))
-    PersistPinnedState();
-  else if (!HasItemController(id) &&
-           model_->items()[target_index].type == ash::TYPE_BROWSER_SHORTCUT)
-    PersistPinnedState();
-}
-
-void ChromeLauncherControllerPerBrowser::LauncherItemChanged(
-    int index,
-    const ash::LauncherItem& old_item) {
-  ash::LauncherID id = model_->items()[index].id;
-  id_to_item_controller_map_[id]->LauncherItemChanged(index, old_item);
-}
-
-void ChromeLauncherControllerPerBrowser::LauncherStatusChanged() {
-}
-
-void ChromeLauncherControllerPerBrowser::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();
-      if (IsAppPinned(extension->id())) {
-        // Clear and re-fetch to ensure icon is up-to-date.
-        app_icon_loader_->ClearImage(extension->id());
-        app_icon_loader_->FetchImage(extension->id());
-      }
-
-      UpdateAppLaunchersFromPref();
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      const content::Details<extensions::UnloadedExtensionInfo>& unload_info(
-          details);
-      const Extension* extension = unload_info->extension;
-      if (IsAppPinned(extension->id())) {
-        if (unload_info->reason == extension_misc::UNLOAD_REASON_UNINSTALL) {
-          DoUnpinAppsWithID(extension->id());
-          app_icon_loader_->ClearImage(extension->id());
-        } else {
-          app_icon_loader_->UpdateImage(extension->id());
-        }
-      }
-      break;
-    }
-    default:
-      NOTREACHED() << "Unexpected notification type=" << type;
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::OnShelfAlignmentChanged(
-    aura::RootWindow* root_window) {
-  const char* pref_value = NULL;
-  switch (ash::Shell::GetInstance()->GetShelfAlignment(root_window)) {
-    case ash::SHELF_ALIGNMENT_BOTTOM:
-      pref_value = ash::kShelfAlignmentBottom;
-      break;
-    case ash::SHELF_ALIGNMENT_LEFT:
-      pref_value = ash::kShelfAlignmentLeft;
-      break;
-    case ash::SHELF_ALIGNMENT_RIGHT:
-      pref_value = ash::kShelfAlignmentRight;
-      break;
-    case ash::SHELF_ALIGNMENT_TOP:
-      pref_value = ash::kShelfAlignmentTop;
-      break;
-  }
-
-  UpdatePerDisplayPref(
-      profile_->GetPrefs(), root_window, prefs::kShelfAlignment, pref_value);
-
-  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
-    // See comment in |kShelfAlignment| about why we have two prefs here.
-    profile_->GetPrefs()->SetString(prefs::kShelfAlignmentLocal, pref_value);
-    profile_->GetPrefs()->SetString(prefs::kShelfAlignment, pref_value);
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::OnDisplayConfigurationChanging() {
-}
-
-void ChromeLauncherControllerPerBrowser::OnDisplayConfigurationChanged() {
-  SetShelfBehaviorsFromPrefs();
-}
-
-void ChromeLauncherControllerPerBrowser::OnIsSyncingChanged() {
-  PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
-  MaybePropagatePrefToLocal(prefs,
-                            prefs::kShelfAlignmentLocal,
-                            prefs::kShelfAlignment);
-  MaybePropagatePrefToLocal(prefs,
-                            prefs::kShelfAutoHideBehaviorLocal,
-                            prefs::kShelfAutoHideBehavior);
-}
-
-void ChromeLauncherControllerPerBrowser::OnAppSyncUIStatusChanged() {
-  if (app_sync_ui_state_->status() == AppSyncUIState::STATUS_SYNCING)
-    model_->SetStatus(ash::LauncherModel::STATUS_LOADING);
-  else
-    model_->SetStatus(ash::LauncherModel::STATUS_NORMAL);
-}
-
-void ChromeLauncherControllerPerBrowser::ExtensionEnableFlowFinished() {
-  LaunchApp(extension_enable_flow_->extension_id(), ui::EF_NONE);
-  extension_enable_flow_.reset();
-}
-
-void ChromeLauncherControllerPerBrowser::ExtensionEnableFlowAborted(
-    bool user_initiated) {
-  extension_enable_flow_.reset();
-}
-
-void ChromeLauncherControllerPerBrowser::PersistPinnedState() {
-  if (ignore_persist_pinned_state_change_)
-    return;
-  // It is a coding error to call PersistPinnedState() if the pinned apps are
-  // not user-editable. The code should check earlier and not perform any
-  // modification actions that trigger persisting the state.
-  if (!CanPin()) {
-    NOTREACHED() << "Can't pin but pinned state being updated";
-    return;
-  }
-
-  // Mutating kPinnedLauncherApps is going to notify us and trigger us to
-  // process the change. We don't want that to happen so remove ourselves as a
-  // listener.
-  pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
-  {
-    ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
-    updater->Clear();
-    for (size_t i = 0; i < model_->items().size(); ++i) {
-      if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
-        ash::LauncherID id = model_->items()[i].id;
-        if (HasItemController(id) && IsPinned(id)) {
-          base::DictionaryValue* app_value = ash::CreateAppDict(
-              id_to_item_controller_map_[id]->app_id());
-          if (app_value)
-            updater->Append(app_value);
-        }
-      } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) {
-          SetChromeIconIndexToPref(i);
-      }
-    }
-  }
-  pref_change_registrar_.Add(
-      prefs::kPinnedLauncherApps,
-      base::Bind(&ChromeLauncherControllerPerBrowser::
-                     UpdateAppLaunchersFromPref,
-                 base::Unretained(this)));
-}
-
-ash::LauncherModel* ChromeLauncherControllerPerBrowser::model() {
-  return model_;
-}
-
-Profile* ChromeLauncherControllerPerBrowser::profile() {
-  return profile_;
-}
-
-Profile* ChromeLauncherControllerPerBrowser::GetProfileForNewWindows() {
-  return ProfileManager::GetDefaultProfileOrOffTheRecord();
-}
-
-void ChromeLauncherControllerPerBrowser::LauncherItemClosed(
-    ash::LauncherID id) {
-  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
-  DCHECK(iter != id_to_item_controller_map_.end());
-  app_icon_loader_->ClearImage(iter->second->app_id());
-  iter->second->OnRemoved();
-  id_to_item_controller_map_.erase(iter);
-  model_->RemoveItemAt(model_->ItemIndexByID(id));
-}
-
-void ChromeLauncherControllerPerBrowser::DoPinAppWithID(
-    const std::string& app_id) {
-  // If there is an item, do nothing and return.
-  if (IsAppPinned(app_id))
-    return;
-
-  ash::LauncherID launcher_id = GetLauncherIDForAppID(app_id);
-  if (launcher_id) {
-    // App item exists, pin it
-    Pin(launcher_id);
-  } else {
-    // Otherwise, create a shortcut item for it.
-    CreateAppShortcutLauncherItem(app_id, model_->item_count());
-    if (CanPin())
-      PersistPinnedState();
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::DoUnpinAppsWithID(
-    const std::string& app_id) {
-  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
-       i != id_to_item_controller_map_.end(); ) {
-    IDToItemControllerMap::iterator current(i);
-    ++i;
-    if (current->second->app_id() == app_id && IsPinned(current->first))
-      Unpin(current->first);
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::UpdateAppLaunchersFromPref() {
-  // Construct a vector representation of to-be-pinned apps from the pref.
-  std::vector<std::string> pinned_apps;
-  int chrome_icon_index = GetChromeIconIndexFromPref();
-  const base::ListValue* pinned_apps_pref =
-      profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
-  for (base::ListValue::const_iterator it(pinned_apps_pref->begin());
-       it != pinned_apps_pref->end(); ++it) {
-    // To preserve the Chrome icon position, we insert a dummy slot for it - if
-    // the model has a Chrome item. While initializing we can come here with no
-    // item in which case the count would be 1 or below.
-    if (it - pinned_apps_pref->begin() == chrome_icon_index &&
-        model_->item_count() > 1) {
-      pinned_apps.push_back(extension_misc::kChromeAppId);
-    }
-    DictionaryValue* app = NULL;
-    std::string app_id;
-    if ((*it)->GetAsDictionary(&app) &&
-        app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) &&
-        std::find(pinned_apps.begin(), pinned_apps.end(), app_id) ==
-            pinned_apps.end() &&
-        app_tab_helper_->IsValidID(app_id)) {
-      pinned_apps.push_back(app_id);
-    }
-  }
-
-  // Walk the model and |pinned_apps| from the pref lockstep, adding and
-  // removing items as necessary. NB: This code uses plain old indexing instead
-  // of iterators because of model mutations as part of the loop.
-  std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
-  int index = 0;
-  int max_index = model_->item_count();
-  if (ash::switches::UseAlternateShelfLayout()) {
-    ++index;
-    ++max_index;
-  }
-  for (; index < model_->item_count() && pref_app_id != pinned_apps.end();
-       ++index) {
-    // If the next app launcher according to the pref is present in the model,
-    // delete all app launcher entries in between.
-    if (*pref_app_id == extension_misc::kChromeAppId ||
-        IsAppPinned(*pref_app_id)) {
-      for (; index < model_->item_count(); ++index) {
-        const ash::LauncherItem& item(model_->items()[index]);
-        if (item.type != ash::TYPE_APP_SHORTCUT &&
-            item.type != ash::TYPE_BROWSER_SHORTCUT)
-          continue;
-
-        IDToItemControllerMap::const_iterator entry =
-            id_to_item_controller_map_.find(item.id);
-        if ((extension_misc::kChromeAppId == *pref_app_id &&
-             item.type == ash::TYPE_BROWSER_SHORTCUT) ||
-            (entry != id_to_item_controller_map_.end() &&
-             entry->second->app_id() == *pref_app_id)) {
-          ++pref_app_id;
-          break;
-        } else {
-          if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
-            // We cannot delete the browser shortcut. As such we move it up by
-            // one. To avoid any side effects from our pinned state observer, we
-            // do not call the model directly.
-            MoveItemWithoutPinnedStateChangeNotification(index, index + 1);
-          } else {
-            LauncherItemClosed(item.id);
-            --max_index;
-          }
-          --index;
-        }
-      }
-      // If the item wasn't found, that means id_to_item_controller_map_
-      // is out of sync.
-      DCHECK(index < model_->item_count());
-    } else {
-      // This app wasn't pinned before, insert a new entry.
-      ash::LauncherID id = CreateAppShortcutLauncherItem(*pref_app_id, index);
-      index = model_->ItemIndexByID(id);
-      ++pref_app_id;
-    }
-  }
-
-  // Remove any trailing existing items.
-  while (index < model_->item_count()) {
-    const ash::LauncherItem& item(model_->items()[index]);
-    if (item.type == ash::TYPE_APP_SHORTCUT)
-      LauncherItemClosed(item.id);
-    else
-      ++index;
-  }
-
-  // Append unprocessed items from the pref to the end of the model.
-  for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
-    // Ignore the chrome icon.
-    if (*pref_app_id != extension_misc::kChromeAppId)
-      DoPinAppWithID(*pref_app_id);
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::SetShelfAutoHideBehaviorPrefs(
-    ash::ShelfAutoHideBehavior behavior,
-    aura::RootWindow* root_window) {
-  const char* value = NULL;
-  switch (behavior) {
-    case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
-      value = ash::kShelfAutoHideBehaviorAlways;
-      break;
-    case ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
-      value = ash::kShelfAutoHideBehaviorNever;
-      break;
-    case ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
-      // This one should not be a valid preference option for now. We only want
-      // to completely hide it when we run app mode.
-      NOTREACHED();
-      return;
-  }
-
-  UpdatePerDisplayPref(
-      profile_->GetPrefs(), root_window, prefs::kShelfAutoHideBehavior, value);
-
-  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
-    // See comment in |kShelfAlignment| about why we have two prefs here.
-    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehaviorLocal, value);
-    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehavior, value);
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::SetShelfAutoHideBehaviorFromPrefs() {
-  ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
-
-  for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
-        GetShelfAutoHideBehavior(*iter), *iter);
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::SetShelfAlignmentFromPrefs() {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kShowShelfAlignmentMenu))
-    return;
-
-  ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
-
-  for (ash::Shell::RootWindowList::const_iterator iter = root_windows.begin();
-       iter != root_windows.end(); ++iter) {
-    // See comment in |kShelfAlignment| as to why we consider two prefs.
-    const std::string alignment_value(
-        GetPrefForRootWindow(profile_->GetPrefs(),
-                             *iter,
-                             prefs::kShelfAlignmentLocal,
-                             prefs::kShelfAlignment));
-    ash::ShelfAlignment alignment = ash::SHELF_ALIGNMENT_BOTTOM;
-    if (alignment_value == ash::kShelfAlignmentLeft)
-      alignment = ash::SHELF_ALIGNMENT_LEFT;
-    else if (alignment_value == ash::kShelfAlignmentRight)
-      alignment = ash::SHELF_ALIGNMENT_RIGHT;
-    else if (alignment_value == ash::kShelfAlignmentTop)
-      alignment = ash::SHELF_ALIGNMENT_TOP;
-    ash::Shell::GetInstance()->SetShelfAlignment(alignment, *iter);
-  }
-}
-
-void ChromeLauncherControllerPerBrowser::SetShelfBehaviorsFromPrefs() {
-  SetShelfAutoHideBehaviorFromPrefs();
-  SetShelfAlignmentFromPrefs();
-}
-
-WebContents* ChromeLauncherControllerPerBrowser::GetLastActiveWebContents(
-    const std::string& app_id) {
-  AppIDToWebContentsListMap::const_iterator i =
-      app_id_to_web_contents_list_.find(app_id);
-  if (i == app_id_to_web_contents_list_.end())
-    return NULL;
-  DCHECK_GT(i->second.size(), 0u);
-  return *i->second.begin();
-}
-
-ash::LauncherID ChromeLauncherControllerPerBrowser::InsertAppLauncherItem(
-    LauncherItemController* controller,
-    const std::string& app_id,
-    ash::LauncherItemStatus status,
-    int index) {
-  ash::LauncherID id = model_->next_id();
-  DCHECK(!HasItemController(id));
-  DCHECK(controller);
-  id_to_item_controller_map_[id] = controller;
-  controller->set_launcher_id(id);
-
-  ash::LauncherItem item;
-  item.type = controller->GetLauncherItemType();
-  item.is_incognito = false;
-  item.image = extensions::IconsInfo::GetDefaultAppIcon();
-
-  WebContents* active_tab = GetLastActiveWebContents(app_id);
-  if (active_tab) {
-    Browser* browser = chrome::FindBrowserWithWebContents(active_tab);
-    DCHECK(browser);
-    if (browser->window()->IsActive())
-      status = ash::STATUS_ACTIVE;
-    else
-      status = ash::STATUS_RUNNING;
-  }
-  item.status = status;
-
-  model_->AddAt(index, item);
-
-  app_icon_loader_->FetchImage(app_id);
-
-  return id;
-}
-
-bool ChromeLauncherControllerPerBrowser::HasItemController(
-    ash::LauncherID id) const {
-  return id_to_item_controller_map_.find(id) !=
-         id_to_item_controller_map_.end();
-}
-
-ash::LauncherID
-ChromeLauncherControllerPerBrowser::CreateBrowserShortcutLauncherItem() {
-  ash::LauncherItem browser_shortcut;
-  browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT;
-  browser_shortcut.is_incognito = false;
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
-  ash::LauncherID id = model_->next_id();
-  size_t index = GetChromeIconIndexFromPref();
-  model_->AddAt(index, browser_shortcut);
-  return id;
-}
-
-void ChromeLauncherControllerPerBrowser::SetChromeIconIndexToPref(int index) {
-  profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index);
-}
-
-int ChromeLauncherControllerPerBrowser::GetChromeIconIndexFromPref() const {
-  size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
-  const base::ListValue* pinned_apps_pref =
-  profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
-  if (ash::switches::UseAlternateShelfLayout())
-    return std::max(static_cast<size_t>(1),
-                    std::min(pinned_apps_pref->GetSize(), index));
-  return std::max(static_cast<size_t>(0),
-                  std::min(pinned_apps_pref->GetSize(), index));
-}
-
-ash::LauncherID
-ChromeLauncherControllerPerBrowser::CreateAppShortcutLauncherItem(
-    const std::string& app_id,
-    int index) {
-  AppShortcutLauncherItemController* controller =
-      new AppShortcutLauncherItemController(app_id, this);
-  ash::LauncherID launcher_id = InsertAppLauncherItem(
-      controller, app_id, ash::STATUS_CLOSED, index);
-  return launcher_id;
-}
-
-void ChromeLauncherControllerPerBrowser::SetAppTabHelperForTest(
-    AppTabHelper* helper) {
-  app_tab_helper_.reset(helper);
-}
-
-void ChromeLauncherControllerPerBrowser::SetAppIconLoaderForTest(
-    extensions::AppIconLoader* loader) {
-  app_icon_loader_.reset(loader);
-}
-
-const std::string&
-ChromeLauncherControllerPerBrowser::GetAppIdFromLauncherIdForTest(
-    ash::LauncherID id) {
-  return id_to_item_controller_map_[id]->app_id();
-}
-
-void ChromeLauncherControllerPerBrowser::
-    MoveItemWithoutPinnedStateChangeNotification(int source_index,
-                                                 int target_index) {
-  base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true);
-  model_->Move(source_index, target_index);
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h
deleted file mode 100644
index 0204501..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h
+++ /dev/null
@@ -1,430 +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_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_PER_BROWSER_H_
-#define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_PER_BROWSER_H_
-
-#include <list>
-#include <map>
-#include <string>
-
-#include "ash/display/display_controller.h"
-#include "ash/launcher/launcher_delegate.h"
-#include "ash/launcher/launcher_model_observer.h"
-#include "ash/launcher/launcher_types.h"
-#include "ash/shelf/shelf_layout_manager_observer.h"
-#include "ash/shelf/shelf_types.h"
-#include "ash/shell_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 "chrome/browser/extensions/extension_prefs.h"
-#include "chrome/browser/prefs/pref_service_syncable_observer.h"
-#include "chrome/browser/ui/ash/app_sync_ui_state_observer.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "ui/aura/window_observer.h"
-
-class AppSyncUIState;
-class Browser;
-class BrowserLauncherItemControllerTest;
-class ExtensionEnableFlow;
-class LauncherItemController;
-class Profile;
-class ShellWindowLauncherController;
-
-namespace ash {
-class LauncherModel;
-}
-
-namespace aura {
-class Window;
-}
-
-namespace content {
-class WebContents;
-}
-
-namespace ui {
-class BaseWindow;
-}
-
-// ChromeLauncherControllerPerBrowser manages the launcher items needed for
-// content windows. Launcher items have a type, an optional app id, and a
-// controller. This incarnation manages the items on a per browser base using
-// browser proxies and application icons.
-// * Tabbed browsers and browser app windows have BrowserLauncherItemController,
-//   owned by the BrowserView instance.
-// * App shell windows have ShellWindowLauncherItemController, owned by
-//   ShellWindowLauncherController.
-// * Shortcuts have no LauncherItemController.
-class ChromeLauncherControllerPerBrowser
-    : public ash::LauncherModelObserver,
-      public ash::ShellObserver,
-      public ash::DisplayController::Observer,
-      public ChromeLauncherController,
-      public content::NotificationObserver,
-      public PrefServiceSyncableObserver,
-      public AppSyncUIStateObserver,
-      public ExtensionEnableFlowDelegate,
-      public ash::ShelfLayoutManagerObserver {
- public:
-  ChromeLauncherControllerPerBrowser(Profile* profile,
-                                     ash::LauncherModel* model);
-  virtual ~ChromeLauncherControllerPerBrowser();
-
-  // ChromeLauncherController overrides:
-
-  // Initializes this ChromeLauncherControllerPerBrowser.
-  virtual void Init() OVERRIDE;
-
-  // Returns the new per application interface of the given launcher. If it is
-  // a per browser (old) controller, it will return NULL;
-  // TODO(skuhne): Remove when we rip out the old launcher.
-  virtual ChromeLauncherControllerPerApp* GetPerAppInterface() OVERRIDE;
-
-  // Creates a new tabbed item on the launcher for |controller|.
-  virtual ash::LauncherID CreateTabbedLauncherItem(
-      LauncherItemController* controller,
-      IncognitoState is_incognito,
-      ash::LauncherItemStatus status) OVERRIDE;
-
-  // Creates a new app item on the launcher for |controller|.
-  virtual ash::LauncherID CreateAppLauncherItem(
-      LauncherItemController* controller,
-      const std::string& app_id,
-      ash::LauncherItemStatus status) OVERRIDE;
-
-  // Updates the running status of an item.
-  virtual void SetItemStatus(ash::LauncherID id,
-                             ash::LauncherItemStatus status) OVERRIDE;
-
-  // Updates the controller associated with id (which should be a shortcut).
-  // |controller| remains owned by caller.
-  virtual void SetItemController(ash::LauncherID id,
-                                 LauncherItemController* controller) OVERRIDE;
-
-  // Closes or unpins the launcher item.
-  virtual void CloseLauncherItem(ash::LauncherID id) OVERRIDE;
-
-  // Pins the specified id. Currently only supports platform apps.
-  virtual void Pin(ash::LauncherID id) OVERRIDE;
-
-  // Unpins the specified id, closing if not running.
-  virtual void Unpin(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the item identified by |id| is pinned.
-  virtual bool IsPinned(ash::LauncherID id) OVERRIDE;
-
-  // Pins/unpins the specified id.
-  virtual void TogglePinned(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the specified item can be pinned or unpinned. Only apps can
-  // be pinned.
-  virtual bool IsPinnable(ash::LauncherID id) const OVERRIDE;
-
-  // If there is no launcher item in the launcher for application |app_id|, one
-  // gets created. The (existing or created) launcher items get then locked
-  // against a users un-pinning removal.
-  virtual void LockV1AppWithID(const std::string& app_id) OVERRIDE;
-
-  // A previously locked launcher item of type |app_id| gets unlocked. If the
-  // lock count reaches 0 and the item is not pinned it will go away.
-  virtual void UnlockV1AppWithID(const std::string& app_id) OVERRIDE;
-
-  // Requests that the launcher item controller specified by |id| open a new
-  // instance of the app.  |event_flags| holds the flags of the event which
-  // triggered this command.
-  virtual void Launch(ash::LauncherID id, int event_flags) OVERRIDE;
-
-  // Closes the specified item.
-  virtual void Close(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the specified item is open.
-  virtual bool IsOpen(ash::LauncherID id) OVERRIDE;
-
-  // Returns true if the specified item is for a platform app.
-  virtual bool IsPlatformApp(ash::LauncherID id) OVERRIDE;
-
-  // Opens a new instance of the application identified by |app_id|.
-  // Used by the app-list, and by pinned-app launcher items.
-  virtual void LaunchApp(const std::string& app_id, int event_flags) OVERRIDE;
-
-  // If |app_id| is running, reactivates the app's most recently active window,
-  // otherwise launches and activates the app.
-  // Used by the app-list, and by pinned-app launcher items.
-  virtual void ActivateApp(const std::string& app_id, int event_flags) OVERRIDE;
-
-  // Returns the launch type of app for the specified id.
-  virtual extensions::ExtensionPrefs::LaunchType GetLaunchType(
-      ash::LauncherID id) OVERRIDE;
-
-  // Returns the id of the app for the specified tab.
-  virtual std::string GetAppID(content::WebContents* tab) OVERRIDE;
-
-  virtual ash::LauncherID GetLauncherIDForAppID(
-      const std::string& app_id) OVERRIDE;
-  virtual std::string GetAppIDForLauncherID(ash::LauncherID id) OVERRIDE;
-
-  // Set the image for a specific launcher item (e.g. when set by the app).
-  virtual void SetLauncherItemImage(ash::LauncherID launcher_id,
-                                    const gfx::ImageSkia& image) OVERRIDE;
-
-  // Returns true if a pinned launcher item with given |app_id| could be found.
-  virtual bool IsAppPinned(const std::string& app_id) OVERRIDE;
-
-  // Pins an app with |app_id| to launcher. If there is a running instance in
-  // launcher, the running instance is pinned. If there is no running instance,
-  // a new launcher item is created and pinned.
-  virtual void PinAppWithID(const std::string& app_id) OVERRIDE;
-
-  // Updates the launche type of the app for the specified id to |launch_type|.
-  virtual void SetLaunchType(
-      ash::LauncherID id,
-      extensions::ExtensionPrefs::LaunchType launch_type) OVERRIDE;
-
-  // Unpins any app items whose id is |app_id|.
-  virtual void UnpinAppsWithID(const std::string& app_id) OVERRIDE;
-
-  // Returns true if the user is currently logged in as a guest.
-  virtual bool IsLoggedInAsGuest() OVERRIDE;
-
-  // Invoked when user clicks on button in the launcher and there is no last
-  // used window (or CTRL is held with the click).
-  virtual void CreateNewWindow() OVERRIDE;
-
-  // Invoked when the user clicks on button in the launcher to create a new
-  // incognito window.
-  virtual void CreateNewIncognitoWindow() OVERRIDE;
-
-  // Checks whether the user is allowed to pin apps. Pinning may be disallowed
-  // by policy in case there is a pre-defined set of pinned apps.
-  virtual bool CanPin() const OVERRIDE;
-
-  // Updates the pinned pref state. The pinned state consists of a list pref.
-  // Each item of the list is a dictionary. The key |kAppIDPath| gives the
-  // id of the app.
-  virtual void PersistPinnedState() OVERRIDE;
-
-  virtual ash::LauncherModel* model() OVERRIDE;
-
-  virtual Profile* profile() OVERRIDE;
-
-  // Gets the shelf auto-hide behavior on |root_window|.
-  virtual ash::ShelfAutoHideBehavior GetShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const OVERRIDE;
-
-  // Returns |true| if the user is allowed to modify the shelf auto-hide
-  // behavior on |root_window|.
-  virtual bool CanUserModifyShelfAutoHideBehavior(
-      aura::RootWindow* root_window) const OVERRIDE;
-
-  // Toggles the shelf auto-hide behavior on |root_window|. Does nothing if the
-  // user is not allowed to modify the auto-hide behavior.
-  virtual void ToggleShelfAutoHideBehavior(
-      aura::RootWindow* root_window) OVERRIDE;
-
-  // The tab no longer represents its previously identified application.
-  virtual void RemoveTabFromRunningApp(content::WebContents* tab,
-                                       const std::string& app_id) OVERRIDE;
-
-  // Notify the controller that the state of an non platform app's tabs
-  // have changed,
-  virtual void UpdateAppState(content::WebContents* contents,
-                              AppState app_state) OVERRIDE;
-
-  // Limits application refocusing to urls that match |url| for |id|.
-  virtual void SetRefocusURLPatternForTest(ash::LauncherID id,
-                                           const GURL& url) OVERRIDE;
-
-  // Returns the extension identified by |app_id|.
-  virtual const extensions::Extension* GetExtensionForAppID(
-      const std::string& app_id) const OVERRIDE;
-
-  // Activates a |window|. If |allow_minimize| is true and the system allows
-  // it, the the window will get minimized instead.
-  virtual void ActivateWindowOrMinimizeIfActive(ui::BaseWindow* window,
-                                                bool allow_minimize) OVERRIDE;
-
-  // ash::LauncherDelegate overrides:
-  virtual void ItemSelected(const ash::LauncherItem& item,
-                           const ui::Event& event) OVERRIDE;
-  virtual string16 GetTitle(const ash::LauncherItem& item) OVERRIDE;
-  virtual ui::MenuModel* CreateContextMenu(
-      const ash::LauncherItem& item, aura::RootWindow* root) OVERRIDE;
-  virtual ash::LauncherMenuModel* CreateApplicationMenu(
-      const ash::LauncherItem& item,
-      int event_flags) OVERRIDE;
-  virtual ash::LauncherID GetIDByWindow(aura::Window* window) OVERRIDE;
-  virtual bool IsDraggable(const ash::LauncherItem& item) OVERRIDE;
-  virtual bool ShouldShowTooltip(const ash::LauncherItem& item) OVERRIDE;
-  virtual void OnLauncherCreated(ash::Launcher* launcher) OVERRIDE;
-  virtual void OnLauncherDestroyed(ash::Launcher* launcher) OVERRIDE;
-
-  // ash::LauncherModelObserver overrides:
-  virtual void LauncherItemAdded(int index) OVERRIDE;
-  virtual void LauncherItemRemoved(int index, ash::LauncherID id) OVERRIDE;
-  virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE;
-  virtual void LauncherItemChanged(int index,
-                                   const ash::LauncherItem& old_item) OVERRIDE;
-  virtual void LauncherStatusChanged() OVERRIDE;
-
-  // content::NotificationObserver overrides:
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE;
-
-  // ash::ShellObserver overrides:
-  virtual void OnShelfAlignmentChanged(aura::RootWindow* root_window) OVERRIDE;
-
-  // ash::DisplayController::Observer overrides:
-  virtual void OnDisplayConfigurationChanging() OVERRIDE;
-  virtual void OnDisplayConfigurationChanged() OVERRIDE;
-
-  // PrefServiceSyncableObserver overrides:
-  virtual void OnIsSyncingChanged() OVERRIDE;
-
-  // AppSyncUIStateObserver overrides:
-  virtual void OnAppSyncUIStatusChanged() OVERRIDE;
-
-  // ExtensionEnableFlowDelegate overrides:
-  virtual void ExtensionEnableFlowFinished() OVERRIDE;
-  virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE;
-
-  // extensions::AppIconLoader overrides:
-  virtual void SetAppImage(const std::string& app_id,
-                           const gfx::ImageSkia& image) OVERRIDE;
-
-  // ash::ShelfLayoutManagerObserver overrides:
-  virtual void OnAutoHideBehaviorChanged(
-      aura::RootWindow* root_window,
-      ash::ShelfAutoHideBehavior new_behavior) OVERRIDE;
-
- protected:
-  // ChromeLauncherController overrides:
-
-  // Creates a new app shortcut item and controller on the launcher at |index|.
-  // Use kInsertItemAtEnd to add a shortcut as the last item.
-  virtual ash::LauncherID CreateAppShortcutLauncherItem(
-      const std::string& app_id,
-      int index) OVERRIDE;
-
-  // Sets the AppTabHelper/AppIconLoader, taking ownership of the helper class.
-  // These are intended for testing.
-  virtual void SetAppTabHelperForTest(AppTabHelper* helper) OVERRIDE;
-  virtual void SetAppIconLoaderForTest(
-      extensions::AppIconLoader* loader) OVERRIDE;
-  virtual const std::string& GetAppIdFromLauncherIdForTest(
-      ash::LauncherID id) OVERRIDE;
-
- private:
-  friend class ChromeLauncherControllerPerBrowserTest;
-
-  typedef std::map<ash::LauncherID, LauncherItemController*>
-          IDToItemControllerMap;
-  typedef std::list<content::WebContents*> WebContentsList;
-  typedef std::map<std::string, WebContentsList> AppIDToWebContentsListMap;
-  typedef std::map<content::WebContents*, std::string> WebContentsToAppIDMap;
-
-  // Returns the profile used for new windows.
-  Profile* GetProfileForNewWindows();
-
-  // Invoked when the associated browser or app is closed.
-  void LauncherItemClosed(ash::LauncherID id);
-
-  // Internal helpers for pinning and unpinning that handle both
-  // client-triggered and internal pinning operations.
-  void DoPinAppWithID(const std::string& app_id);
-  void DoUnpinAppsWithID(const std::string& app_id);
-
-  // Re-syncs launcher model with prefs::kPinnedLauncherApps.
-  void UpdateAppLaunchersFromPref();
-
-  // Persists the shelf auto-hide behavior to prefs.
-  void SetShelfAutoHideBehaviorPrefs(ash::ShelfAutoHideBehavior behavior,
-                                     aura::RootWindow* root_window);
-
-  // Sets the shelf auto-hide behavior from prefs.
-  void SetShelfAutoHideBehaviorFromPrefs();
-
-  // Sets the shelf alignment from prefs.
-  void SetShelfAlignmentFromPrefs();
-
-  // Sets both of auto-hide behavior and alignment from prefs.
-  void SetShelfBehaviorsFromPrefs();
-
-  // Returns the most recently active WebContents for an app.
-  content::WebContents* GetLastActiveWebContents(const std::string& app_id);
-
-  // Creates an app launcher to insert at |index|. Note that |index| may be
-  // adjusted by the model to meet ordering constraints.
-  ash::LauncherID InsertAppLauncherItem(
-      LauncherItemController* controller,
-      const std::string& app_id,
-      ash::LauncherItemStatus status,
-      int index);
-
-  bool HasItemController(ash::LauncherID id) const;
-
-  // Create LauncherItem for Browser Shortcut.
-  ash::LauncherID CreateBrowserShortcutLauncherItem();
-
-  // Update browser shortcut's index.
-  void SetChromeIconIndexToPref(int index);
-
-  // Get browser shortcut's index from pref.
-  int GetChromeIconIndexFromPref() const;
-
-  // Invoked when browser shortcut is clicked.
-  void BrowserShortcutClicked(int event_flags);
-
-  // Move an item internally (ignoring pinned state changes) from |index| to
-  // |target_index|.
-  void MoveItemWithoutPinnedStateChangeNotification(int source_index,
-                                                    int target_index);
-
-  ash::LauncherModel* model_;
-
-  // Profile used for prefs and loading extensions. This is NOT necessarily the
-  // profile new windows are created with.
-  Profile* profile_;
-
-  IDToItemControllerMap id_to_item_controller_map_;
-
-  // Maintains activation order of web contents for each app.
-  AppIDToWebContentsListMap app_id_to_web_contents_list_;
-
-  // Direct access to app_id for a web contents.
-  WebContentsToAppIDMap web_contents_to_app_id_;
-
-  // Used to track shell windows.
-  scoped_ptr<ShellWindowLauncherController> shell_window_controller_;
-
-  // Used to get app info for tabs.
-  scoped_ptr<AppTabHelper> app_tab_helper_;
-
-  // Used to load the image for an app item.
-  scoped_ptr<extensions::AppIconLoader> app_icon_loader_;
-
-  content::NotificationRegistrar notification_registrar_;
-
-  PrefChangeRegistrar pref_change_registrar_;
-
-  AppSyncUIState* app_sync_ui_state_;
-
-  scoped_ptr<ExtensionEnableFlow> extension_enable_flow_;
-
-  // Launchers that are currently being observed.
-  std::set<ash::Launcher*> launchers_;
-
-  // If true, incoming pinned state changes should be ignored.
-  bool ignore_persist_pinned_state_change_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerPerBrowser);
-};
-
-#endif  // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_PER_BROWSER_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser_unittest.cc
deleted file mode 100644
index f91430b..0000000
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser_unittest.cc
+++ /dev/null
@@ -1,462 +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/launcher/chrome_launcher_controller_per_browser.h"
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "ash/launcher/launcher_model.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/run_loop.h"
-#include "base/values.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/test_extension_system.h"
-#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
-#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
-#include "chrome/common/extensions/extension.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/test/test_browser_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
-#include "chrome/browser/chromeos/settings/device_settings_service.h"
-#endif
-
-using extensions::Extension;
-using extensions::Manifest;
-
-class ChromeLauncherControllerPerBrowserTest : public testing::Test {
- protected:
-  ChromeLauncherControllerPerBrowserTest()
-      : profile_(new TestingProfile()),
-        extension_service_(NULL) {
-    DictionaryValue manifest;
-    manifest.SetString("name", "launcher controller test extension");
-    manifest.SetString("version", "1");
-    manifest.SetString("description", "for testing pinned apps");
-
-    extensions::TestExtensionSystem* extension_system(
-        static_cast<extensions::TestExtensionSystem*>(
-            extensions::ExtensionSystem::Get(profile_.get())));
-    extension_service_ = extension_system->CreateExtensionService(
-        CommandLine::ForCurrentProcess(), base::FilePath(), false);
-
-    std::string error;
-    extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest,
-                                    Extension::NO_FLAGS,
-                                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-                                    &error);
-    extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest,
-                                    Extension::NO_FLAGS,
-                                    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
-                                    &error);
-    // Fake gmail extension.
-    extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest,
-                                    Extension::NO_FLAGS,
-                                    extension_misc::kGmailAppId,
-                                    &error);
-    // Fake search extension.
-    extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest,
-                                    Extension::NO_FLAGS,
-                                    extension_misc::kGoogleSearchAppId,
-                                    &error);
-  }
-
-  virtual void TearDown() OVERRIDE {
-    profile_.reset();
-    // Execute any pending deletion tasks.
-    base::RunLoop().RunUntilIdle();
-  }
-
-  void InsertPrefValue(base::ListValue* pref_value,
-                       int index,
-                       const std::string& extension_id) {
-    base::DictionaryValue* entry = new DictionaryValue();
-    entry->SetString(ash::kPinnedAppsPrefAppIDPath, extension_id);
-    pref_value->Insert(index, entry);
-  }
-
-  // Gets the currently configured app launchers from the controller.
-  void GetAppLaunchers(ChromeLauncherControllerPerBrowser* controller,
-                       std::vector<std::string>* launchers) {
-    launchers->clear();
-    for (ash::LauncherItems::const_iterator iter(model_.items().begin());
-         iter != model_.items().end(); ++iter) {
-      ChromeLauncherControllerPerBrowser::IDToItemControllerMap::const_iterator
-          entry(controller->id_to_item_controller_map_.find(iter->id));
-      if (iter->type == ash::TYPE_APP_SHORTCUT &&
-          entry != controller->id_to_item_controller_map_.end()) {
-        launchers->push_back(entry->second->app_id());
-      }
-    }
-  }
-
-  std::string GetPinnedAppStatus(
-      ChromeLauncherController* launcher_controller) {
-    std::string result;
-    for (int i = 0; i < model_.item_count(); i++) {
-      switch (model_.items()[i].type) {
-        case ash::TYPE_APP_SHORTCUT: {
-          const std::string& app =
-              launcher_controller->GetAppIDForLauncherID(
-                  model_.items()[i].id);
-          if (app == extension1_->id()) {
-            result += "App1, ";
-            EXPECT_TRUE(launcher_controller->IsAppPinned(extension1_->id()));
-          } else if (app == extension2_->id()) {
-            result += "App2, ";
-            EXPECT_TRUE(launcher_controller->IsAppPinned(extension2_->id()));
-          } else if (app == extension3_->id()) {
-            result += "App3, ";
-            EXPECT_TRUE(launcher_controller->IsAppPinned(extension3_->id()));
-          } else {
-            result += "unknown";
-          }
-          break;
-          }
-        case ash::TYPE_BROWSER_SHORTCUT:
-          result += "Chrome, ";
-          break;
-        case ash::TYPE_APP_LIST:
-          result += "AppList";
-          break;
-        default:
-          result += "Unknown";
-          break;
-      }
-    }
-    return result;
-  }
-
-  // Needed for extension service & friends to work.
-  content::TestBrowserThreadBundle thread_bundle_;
-
-#if defined OS_CHROMEOS
-  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
-  chromeos::ScopedTestCrosSettings test_cros_settings_;
-  chromeos::ScopedTestUserManager test_user_manager_;
-#endif
-
-  scoped_refptr<Extension> extension1_;
-  scoped_refptr<Extension> extension2_;
-  scoped_refptr<Extension> extension3_;
-  scoped_refptr<Extension> extension4_;
-  scoped_ptr<TestingProfile> profile_;
-  ash::LauncherModel model_;
-
-  ExtensionService* extension_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerPerBrowserTest);
-};
-
-TEST_F(ChromeLauncherControllerPerBrowserTest, DefaultApps) {
-  ChromeLauncherControllerPerBrowser launcher_controller(profile_.get(),
-                                                         &model_);
-  launcher_controller.Init();
-
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_EQ(2, model_.item_count());
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon.
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_EQ("Chrome, App3, AppList", GetPinnedAppStatus(&launcher_controller));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension2_->id()));
-}
-
-// Check that the restauration of launcher items is happening in the same order
-// as the user has pinned them (on another system) when they are synced reverse
-// order.
-TEST_F(ChromeLauncherControllerPerBrowserTest, RestoreDefaultAppsReverseOrder) {
-  ChromeLauncherControllerPerBrowser launcher_controller(profile_.get(),
-                                                         &model_);
-  launcher_controller.Init();
-
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  InsertPrefValue(&policy_value, 2, extension3_->id());
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 policy_value.DeepCopy());
-  EXPECT_EQ(0, profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, AppList", GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon.
-  ash::LauncherItem item;
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_EQ("Chrome, App3, AppList", GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension2_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_EQ("Chrome, App2, App3, AppList",
-            GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension1_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension1_.get());
-  EXPECT_EQ("Chrome, App1, App2, App3, AppList",
-            GetPinnedAppStatus(&launcher_controller));
-}
-
-// Check that the restauration of launcher items is happening in the same order
-// as the user has pinned them (on another system) when they are synced random
-// order.
-TEST_F(ChromeLauncherControllerPerBrowserTest, RestoreDefaultAppsRandomOrder) {
-  ChromeLauncherControllerPerBrowser launcher_controller(profile_.get(),
-                                                         &model_);
-  launcher_controller.Init();
-
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  InsertPrefValue(&policy_value, 2, extension3_->id());
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 policy_value.DeepCopy());
-  EXPECT_EQ(0, profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, AppList", GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension2_| should add it to the launcher - behind the
-  // chrome icon.
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, App2, AppList", GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension1_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension1_.get());
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, App1, App2, AppList",
-            GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_EQ("Chrome, App1, App2, App3, AppList",
-            GetPinnedAppStatus(&launcher_controller));
-}
-
-// Check that the restauration of launcher items is happening in the same order
-// as the user has pinned / moved them (on another system) when they are synced
-// random order - including the chrome icon.
-TEST_F(ChromeLauncherControllerPerBrowserTest,
-    RestoreDefaultAppsRandomOrderChromeMoved) {
-  ChromeLauncherControllerPerBrowser launcher_controller(profile_.get(),
-                                                         &model_);
-  launcher_controller.Init();
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  InsertPrefValue(&policy_value, 2, extension3_->id());
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 policy_value.DeepCopy());
-  profile_->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
-                                                1);
-  // Model should only contain the browser shortcut and app list items.
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, AppList", GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension2_| should add it to the launcher - behind the
-  // chrome icon.
-  ash::LauncherItem item;
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_EQ("Chrome, App2, AppList", GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension1_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension1_.get());
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_EQ("App1, Chrome, App2, AppList",
-            GetPinnedAppStatus(&launcher_controller));
-
-  // Installing |extension3_| should add it to the launcher - behind the
-  // chrome icon, but in first location.
-  extension_service_->AddExtension(extension3_.get());
-  EXPECT_EQ("App1, Chrome, App2, App3, AppList",
-            GetPinnedAppStatus(&launcher_controller));
-}
-
-TEST_F(ChromeLauncherControllerPerBrowserTest, Policy) {
-  extension_service_->AddExtension(extension1_.get());
-  extension_service_->AddExtension(extension3_.get());
-
-  base::ListValue policy_value;
-  InsertPrefValue(&policy_value, 0, extension1_->id());
-  InsertPrefValue(&policy_value, 1, extension2_->id());
-  profile_->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
-                                                    policy_value.DeepCopy());
-
-  // Only |extension1_| should get pinned. |extension2_| is specified but not
-  // installed, and |extension3_| is part of the default set, but that shouldn't
-  // take effect when the policy override is in place.
-  ChromeLauncherControllerPerBrowser launcher_controller(profile_.get(),
-                                                         &model_);
-  launcher_controller.Init();
-  EXPECT_EQ(3, model_.item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[1].type);
-  EXPECT_TRUE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_.items()[0].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[1].type);
-  EXPECT_EQ(ash::TYPE_APP_LIST, model_.items()[2].type);
-
-  // Installing |extension2_| should add it to the launcher.
-  extension_service_->AddExtension(extension2_.get());
-  EXPECT_EQ(4, model_.item_count());
-  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_.items()[0].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[1].type);
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[2].type);
-  EXPECT_EQ(ash::TYPE_APP_LIST, model_.items()[3].type);
-  EXPECT_TRUE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-
-  // Removing |extension1_| from the policy should be reflected in the launcher.
-  policy_value.Remove(0, NULL);
-  profile_->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
-                                                    policy_value.DeepCopy());
-  EXPECT_EQ(3, model_.item_count());
-  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_.items()[1].type);
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension1_->id()));
-  EXPECT_TRUE(launcher_controller.IsAppPinned(extension2_->id()));
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-}
-
-TEST_F(ChromeLauncherControllerPerBrowserTest, UnpinWithUninstall) {
-  extension_service_->AddExtension(extension3_.get());
-  extension_service_->AddExtension(extension4_.get());
-
-  ChromeLauncherControllerPerBrowser launcher_controller(profile_.get(),
-                                                         &model_);
-  launcher_controller.Init();
-
-  EXPECT_TRUE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_TRUE(launcher_controller.IsAppPinned(extension4_->id()));
-
-  extension_service_->UnloadExtension(extension3_->id(),
-                                      extension_misc::UNLOAD_REASON_UNINSTALL);
-
-  EXPECT_FALSE(launcher_controller.IsAppPinned(extension3_->id()));
-  EXPECT_TRUE(launcher_controller.IsAppPinned(extension4_->id()));
-}
-
-TEST_F(ChromeLauncherControllerPerBrowserTest, PrefUpdates) {
-  extension_service_->AddExtension(extension2_.get());
-  extension_service_->AddExtension(extension3_.get());
-  extension_service_->AddExtension(extension4_.get());
-  ChromeLauncherControllerPerBrowser controller(profile_.get(), &model_);
-  controller.Init();
-
-  std::vector<std::string> expected_launchers;
-  std::vector<std::string> actual_launchers;
-  base::ListValue pref_value;
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  GetAppLaunchers(&controller, &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Unavailable extensions don't create launcher items.
-  InsertPrefValue(&pref_value, 0, extension1_->id());
-  InsertPrefValue(&pref_value, 1, extension2_->id());
-  InsertPrefValue(&pref_value, 2, extension4_->id());
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  expected_launchers.push_back(extension2_->id());
-  expected_launchers.push_back(extension4_->id());
-  GetAppLaunchers(&controller, &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Redundant pref entries show up only once.
-  InsertPrefValue(&pref_value, 2, extension3_->id());
-  InsertPrefValue(&pref_value, 2, extension3_->id());
-  InsertPrefValue(&pref_value, 5, extension3_->id());
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  expected_launchers.insert(expected_launchers.begin() + 1, extension3_->id());
-  GetAppLaunchers(&controller, &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Order changes are reflected correctly.
-  pref_value.Clear();
-  InsertPrefValue(&pref_value, 0, extension4_->id());
-  InsertPrefValue(&pref_value, 1, extension3_->id());
-  InsertPrefValue(&pref_value, 2, extension2_->id());
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  std::reverse(expected_launchers.begin(), expected_launchers.end());
-  GetAppLaunchers(&controller, &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Clearing works.
-  pref_value.Clear();
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-  expected_launchers.clear();
-  GetAppLaunchers(&controller, &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-}
-
-TEST_F(ChromeLauncherControllerPerBrowserTest, PendingInsertionOrder) {
-  extension_service_->AddExtension(extension1_.get());
-  extension_service_->AddExtension(extension3_.get());
-  ChromeLauncherControllerPerBrowser controller(profile_.get(), &model_);
-  controller.Init();
-
-  base::ListValue pref_value;
-  InsertPrefValue(&pref_value, 0, extension1_->id());
-  InsertPrefValue(&pref_value, 1, extension2_->id());
-  InsertPrefValue(&pref_value, 2, extension3_->id());
-  profile_->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
-                                                 pref_value.DeepCopy());
-
-  std::vector<std::string> expected_launchers;
-  expected_launchers.push_back(extension1_->id());
-  expected_launchers.push_back(extension3_->id());
-  std::vector<std::string> actual_launchers;
-
-  GetAppLaunchers(&controller, &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-
-  // Install |extension2| and verify it shows up between the other two.
-  extension_service_->AddExtension(extension2_.get());
-  expected_launchers.insert(expected_launchers.begin() + 1, extension2_->id());
-  GetAppLaunchers(&controller, &actual_launchers);
-  EXPECT_EQ(expected_launchers, actual_launchers);
-}
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
new file mode 100644
index 0000000..c08d2f6
--- /dev/null
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -0,0 +1,1530 @@
+// Copyright 2013 The Chromium Authors. 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/chrome_launcher_controller.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "ash/ash_switches.h"
+#include "ash/launcher/launcher_model.h"
+#include "ash/launcher/launcher_model_observer.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
+#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/shell_window_launcher_item_controller.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_list.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
+#include "chrome/test/base/testing_pref_service_syncable.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_browser_thread.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/models/menu_model.h"
+
+using extensions::Extension;
+using extensions::Manifest;
+
+namespace {
+const char* offline_gmail_url = "https://mail.google.com/mail/mu/u";
+const char* gmail_url = "https://mail.google.com/mail/u";
+}
+
+namespace {
+
+// LauncherModelObserver implementation that tracks what messages are invoked.
+class TestLauncherModelObserver : public ash::LauncherModelObserver {
+ public:
+  TestLauncherModelObserver()
+    : added_(0),
+      removed_(0),
+      changed_(0) {
+  }
+
+  virtual ~TestLauncherModelObserver() {
+  }
+
+  // LauncherModelObserver
+  virtual void LauncherItemAdded(int index) OVERRIDE {
+    ++added_;
+    last_index_ = index;
+  }
+
+  virtual void LauncherItemRemoved(int index, ash::LauncherID id) OVERRIDE {
+    ++removed_;
+    last_index_ = index;
+  }
+
+  virtual void LauncherItemChanged(int index,
+                                   const ash::LauncherItem& old_item) OVERRIDE {
+    ++changed_;
+    last_index_ = index;
+  }
+
+  virtual void LauncherItemMoved(int start_index, int target_index) OVERRIDE {
+    last_index_ = target_index;
+  }
+
+  virtual void LauncherStatusChanged() OVERRIDE {
+  }
+
+  void clear_counts() {
+    added_ = 0;
+    removed_ = 0;
+    changed_ = 0;
+    last_index_ = 0;
+  }
+
+  int added() const { return added_; }
+  int removed() const { return removed_; }
+  int changed() const { return changed_; }
+  int last_index() const { return last_index_; }
+
+ private:
+  int added_;
+  int removed_;
+  int changed_;
+  int last_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestLauncherModelObserver);
+};
+
+// Test implementation of AppIconLoader.
+class TestAppIconLoaderImpl : public extensions::AppIconLoader {
+ public:
+  TestAppIconLoaderImpl() : fetch_count_(0) {
+  }
+
+  virtual ~TestAppIconLoaderImpl() {
+  }
+
+  // AppIconLoader implementation:
+  virtual void FetchImage(const std::string& id) OVERRIDE {
+    ++fetch_count_;
+  }
+
+  virtual void ClearImage(const std::string& id) OVERRIDE {
+  }
+
+  virtual void UpdateImage(const std::string& id) OVERRIDE {
+  }
+
+  int fetch_count() const { return fetch_count_; }
+
+ private:
+  int fetch_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAppIconLoaderImpl);
+};
+
+// Test implementation of AppTabHelper.
+class TestAppTabHelperImpl : public ChromeLauncherController::AppTabHelper {
+ public:
+  TestAppTabHelperImpl() {}
+  virtual ~TestAppTabHelperImpl() {}
+
+  // Sets the id for the specified tab. The id is removed if Remove() is
+  // invoked.
+  void SetAppID(content::WebContents* tab, const std::string& id) {
+    tab_id_map_[tab] = id;
+  }
+
+  // Returns true if there is an id registered for |tab|.
+  bool HasAppID(content::WebContents* tab) const {
+    return tab_id_map_.find(tab) != tab_id_map_.end();
+  }
+
+  // AppTabHelper implementation:
+  virtual std::string GetAppID(content::WebContents* tab) OVERRIDE {
+    return tab_id_map_.find(tab) != tab_id_map_.end() ? tab_id_map_[tab] :
+        std::string();
+  }
+
+  virtual bool IsValidID(const std::string& id) OVERRIDE {
+    for (TabToStringMap::const_iterator i = tab_id_map_.begin();
+         i != tab_id_map_.end(); ++i) {
+      if (i->second == id)
+        return true;
+    }
+    return false;
+  }
+
+ private:
+  typedef std::map<content::WebContents*, std::string> TabToStringMap;
+
+  TabToStringMap tab_id_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAppTabHelperImpl);
+};
+
+}  // namespace
+
+class ChromeLauncherControllerTest : public BrowserWithTestWindowTest {
+ protected:
+  ChromeLauncherControllerTest() : extension_service_(NULL) {
+    SetHostDesktopType(chrome::HOST_DESKTOP_TYPE_ASH);
+  }
+
+  virtual ~ChromeLauncherControllerTest() {
+  }
+
+  virtual void SetUp() OVERRIDE {
+    BrowserWithTestWindowTest::SetUp();
+
+    model_.reset(new ash::LauncherModel);
+    model_observer_.reset(new TestLauncherModelObserver);
+    model_->AddObserver(model_observer_.get());
+
+    DictionaryValue manifest;
+    manifest.SetString(extensions::manifest_keys::kName,
+                       "launcher controller test extension");
+    manifest.SetString(extensions::manifest_keys::kVersion, "1");
+    manifest.SetString(extensions::manifest_keys::kDescription,
+                       "for testing pinned apps");
+
+    extensions::TestExtensionSystem* extension_system(
+        static_cast<extensions::TestExtensionSystem*>(
+            extensions::ExtensionSystem::Get(profile())));
+    extension_service_ = extension_system->CreateExtensionService(
+        CommandLine::ForCurrentProcess(), base::FilePath(), false);
+
+    std::string error;
+    extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
+                                    manifest,
+                                    Extension::NO_FLAGS,
+                                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+                                    &error);
+    extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
+                                    manifest,
+                                    Extension::NO_FLAGS,
+                                    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+                                    &error);
+    // Fake gmail extension.
+    DictionaryValue manifest_gmail;
+    manifest_gmail.SetString(extensions::manifest_keys::kName,
+                             "Gmail launcher controller test extension");
+    manifest_gmail.SetString(extensions::manifest_keys::kVersion, "1");
+    manifest_gmail.SetString(extensions::manifest_keys::kDescription,
+                             "for testing pinned Gmail");
+    manifest_gmail.SetString(extensions::manifest_keys::kLaunchWebURL,
+                             "https://mail.google.com/mail/ca");
+    ListValue* list = new ListValue();
+    list->Append(Value::CreateStringValue("*://mail.google.com/mail/ca"));
+    manifest_gmail.Set(extensions::manifest_keys::kWebURLs, list);
+
+    extension3_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
+                                    manifest_gmail,
+                                    Extension::NO_FLAGS,
+                                    extension_misc::kGmailAppId,
+                                    &error);
+
+    // Fake search extension.
+    extension4_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
+                                    manifest,
+                                    Extension::NO_FLAGS,
+                                    extension_misc::kGoogleSearchAppId,
+                                    &error);
+  }
+
+  virtual void TearDown() OVERRIDE {
+    model_->RemoveObserver(model_observer_.get());
+    model_observer_.reset();
+    launcher_controller_.reset();
+    model_.reset();
+
+    BrowserWithTestWindowTest::TearDown();
+  }
+
+  void InitLauncherController() {
+    launcher_controller_.reset(
+        new ChromeLauncherController(profile(), model_.get()));
+    launcher_controller_->Init();
+  }
+
+  void InitLauncherControllerWithBrowser() {
+    chrome::NewTab(browser());
+    BrowserList::SetLastActive(browser());
+    InitLauncherController();
+  }
+
+  void SetAppIconLoader(extensions::AppIconLoader* loader) {
+    launcher_controller_->SetAppIconLoaderForTest(loader);
+  }
+
+  void SetAppTabHelper(ChromeLauncherController::AppTabHelper* helper) {
+    launcher_controller_->SetAppTabHelperForTest(helper);
+  }
+
+  void InsertPrefValue(base::ListValue* pref_value,
+                       int index,
+                       const std::string& extension_id) {
+    base::DictionaryValue* entry = new DictionaryValue();
+    entry->SetString(ash::kPinnedAppsPrefAppIDPath, extension_id);
+    pref_value->Insert(index, entry);
+  }
+
+  // Gets the currently configured app launchers from the controller.
+  void GetAppLaunchers(ChromeLauncherController* controller,
+                       std::vector<std::string>* launchers) {
+    launchers->clear();
+    for (ash::LauncherItems::const_iterator iter(model_->items().begin());
+         iter != model_->items().end(); ++iter) {
+      ChromeLauncherController::IDToItemControllerMap::const_iterator
+          entry(controller->id_to_item_controller_map_.find(iter->id));
+      if (iter->type == ash::TYPE_APP_SHORTCUT &&
+          entry != controller->id_to_item_controller_map_.end()) {
+        launchers->push_back(entry->second->app_id());
+      }
+    }
+  }
+
+  std::string GetPinnedAppStatus() {
+    std::string result;
+    for (int i = 0; i < model_->item_count(); i++) {
+      switch (model_->items()[i].type) {
+        case ash::TYPE_APP_SHORTCUT: {
+            const std::string& app =
+                launcher_controller_->GetAppIDForLauncherID(
+                    model_->items()[i].id);
+            if (app == extension1_->id()) {
+              result += "App1, ";
+              EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+            } else if (app == extension2_->id()) {
+              result += "App2, ";
+              EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
+            } else if (app == extension3_->id()) {
+              result += "App3, ";
+              EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
+            } else if (app == extension4_->id()) {
+              result += "App4, ";
+              EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
+            } else {
+              result += "unknown, ";
+            }
+            break;
+          }
+        case ash::TYPE_BROWSER_SHORTCUT:
+          result += "Chrome, ";
+          break;
+        case ash::TYPE_APP_LIST:
+          result += "AppList, ";
+          break;
+        default:
+          result += "Unknown";
+          break;
+      }
+    }
+    return result;
+  }
+
+  // Needed for extension service & friends to work.
+  scoped_refptr<Extension> extension1_;
+  scoped_refptr<Extension> extension2_;
+  scoped_refptr<Extension> extension3_;
+  scoped_refptr<Extension> extension4_;
+  scoped_ptr<ChromeLauncherController> launcher_controller_;
+  scoped_ptr<TestLauncherModelObserver> model_observer_;
+  scoped_ptr<ash::LauncherModel> model_;
+
+  ExtensionService* extension_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerTest);
+};
+
+// The testing framework to test the alternate shelf layout.
+class AlternateLayoutChromeLauncherControllerTest
+    : public ChromeLauncherControllerTest {
+ protected:
+  AlternateLayoutChromeLauncherControllerTest() {
+  }
+
+  virtual ~AlternateLayoutChromeLauncherControllerTest() {
+  }
+
+  // Overwrite the Setup function to add the Alternate Shelf layout option.
+  virtual void SetUp() OVERRIDE {
+    CommandLine::ForCurrentProcess()->AppendSwitch(
+        ash::switches::kAshUseAlternateShelfLayout);
+    ChromeLauncherControllerTest::SetUp();
+  }
+
+  // Set the index at which the chrome icon should be.
+  void SetShelfChromeIconIndex(int index) {
+    profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
+                                                   index + 1);
+  }
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(AlternateLayoutChromeLauncherControllerTest);
+};
+
+
+TEST_F(ChromeLauncherControllerTest, DefaultApps) {
+  InitLauncherController();
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon.
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("Chrome, App3, AppList, ", GetPinnedAppStatus());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+}
+
+// Check that the restauration of launcher items is happening in the same order
+// as the user has pinned them (on another system) when they are synced reverse
+// order.
+TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsReverseOrder) {
+  InitLauncherController();
+
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("Chrome, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon.
+  ash::LauncherItem item;
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_EQ("Chrome, App3, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension2_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_EQ("Chrome, App2, App3, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension1_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension1_.get());
+  EXPECT_EQ("Chrome, App1, App2, App3, AppList, ", GetPinnedAppStatus());
+}
+
+// Check that the restauration of launcher items is happening in the same order
+// as the user has pinned them (on another system) when they are synced random
+// order.
+TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrder) {
+  InitLauncherController();
+
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("Chrome, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension2_| should add it to the launcher - behind the
+  // chrome icon.
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("Chrome, App2, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension1_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension1_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("Chrome, App1, App2, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("Chrome, App1, App2, App3, AppList, ", GetPinnedAppStatus());
+}
+
+// Check that the restauration of launcher items is happening in the same order
+// as the user has pinned / moved them (on another system) when they are synced
+// random order - including the chrome icon.
+TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsRandomOrderChromeMoved) {
+  InitLauncherController();
+
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
+                                                 1);
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("Chrome, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension2_| should add it to the launcher - behind the
+  // chrome icon.
+  ash::LauncherItem item;
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("Chrome, App2, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension1_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension1_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("App1, Chrome, App2, AppList, ", GetPinnedAppStatus());
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("App1, Chrome, App2, App3, AppList, ", GetPinnedAppStatus());
+}
+
+// Check that syncing to a different state does the correct thing.
+TEST_F(ChromeLauncherControllerTest, RestoreDefaultAppsResyncOrder) {
+  InitLauncherController();
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  EXPECT_EQ(0, profile()->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex));
+  extension_service_->AddExtension(extension2_.get());
+  extension_service_->AddExtension(extension1_.get());
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("Chrome, App1, App2, App3, AppList, ", GetPinnedAppStatus());
+
+  // Change the order with increasing chrome position and decreasing position.
+  base::ListValue policy_value1;
+  InsertPrefValue(&policy_value1, 0, extension3_->id());
+  InsertPrefValue(&policy_value1, 1, extension1_->id());
+  InsertPrefValue(&policy_value1, 2, extension2_->id());
+  profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
+                                                 2);
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value1.DeepCopy());
+  EXPECT_EQ("App3, App1, Chrome, App2, AppList, ", GetPinnedAppStatus());
+  base::ListValue policy_value2;
+  InsertPrefValue(&policy_value2, 0, extension2_->id());
+  InsertPrefValue(&policy_value2, 1, extension3_->id());
+  InsertPrefValue(&policy_value2, 2, extension1_->id());
+  profile()->GetTestingPrefService()->SetInteger(prefs::kShelfChromeIconIndex,
+                                                 1);
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value2.DeepCopy());
+  EXPECT_EQ("App2, Chrome, App3, App1, AppList, ", GetPinnedAppStatus());
+}
+
+TEST_F(AlternateLayoutChromeLauncherControllerTest, DefaultApps) {
+  InitLauncherController();
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon.
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("AppList, Chrome, App3, ", GetPinnedAppStatus());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+}
+
+// Check that the restauration of launcher items is happening in the same order
+// as the user has pinned them (on another system) when they are synced reverse
+// order.
+TEST_F(AlternateLayoutChromeLauncherControllerTest,
+    RestoreDefaultAppsReverseOrder) {
+  InitLauncherController();
+
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  SetShelfChromeIconIndex(0);
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("AppList, Chrome, ", GetPinnedAppStatus());
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon.
+  ash::LauncherItem item;
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_EQ("AppList, Chrome, App3, ", GetPinnedAppStatus());
+
+  // Installing |extension2_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_EQ("AppList, Chrome, App2, App3, ", GetPinnedAppStatus());
+
+  // Installing |extension1_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension1_.get());
+  EXPECT_EQ("AppList, Chrome, App1, App2, App3, ", GetPinnedAppStatus());
+}
+
+// Check that the restauration of launcher items is happening in the same order
+// as the user has pinned them (on another system) when they are synced random
+// order.
+TEST_F(AlternateLayoutChromeLauncherControllerTest,
+    RestoreDefaultAppsRandomOrder) {
+  InitLauncherController();
+
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  SetShelfChromeIconIndex(0);
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("AppList, Chrome, ", GetPinnedAppStatus());
+
+  // Installing |extension2_| should add it to the launcher - behind the
+  // chrome icon.
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("AppList, Chrome, App2, ", GetPinnedAppStatus());
+
+  // Installing |extension1_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension1_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("AppList, Chrome, App1, App2, ", GetPinnedAppStatus());
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("AppList, Chrome, App1, App2, App3, ", GetPinnedAppStatus());
+}
+
+// Check that the restauration of launcher items is happening in the same order
+// as the user has pinned / moved them (on another system) when they are synced
+// random order - including the chrome icon - using the alternate shelf layout.
+TEST_F(AlternateLayoutChromeLauncherControllerTest,
+    RestoreDefaultAppsRandomOrderChromeMoved) {
+  InitLauncherController();
+
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  SetShelfChromeIconIndex(1);
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("AppList, Chrome, ", GetPinnedAppStatus());
+
+  // Installing |extension2_| should add it to the launcher - behind the
+  // chrome icon.
+  ash::LauncherItem item;
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("AppList, Chrome, App2, ", GetPinnedAppStatus());
+
+  // Installing |extension1_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension1_.get());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_EQ("AppList, App1, Chrome, App2, ", GetPinnedAppStatus());
+
+  // Installing |extension3_| should add it to the launcher - behind the
+  // chrome icon, but in first location.
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("AppList, App1, Chrome, App2, App3, ", GetPinnedAppStatus());
+}
+
+// Check that syncing to a different state does the correct thing with the
+// alternate shelf layout.
+TEST_F(AlternateLayoutChromeLauncherControllerTest,
+    RestoreDefaultAppsResyncOrder) {
+  InitLauncherController();
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  InsertPrefValue(&policy_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value.DeepCopy());
+  // The alternate shelf layout has always one static item at the beginning.
+  SetShelfChromeIconIndex(0);
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_EQ("AppList, Chrome, App2, ", GetPinnedAppStatus());
+  extension_service_->AddExtension(extension1_.get());
+  EXPECT_EQ("AppList, Chrome, App1, App2, ", GetPinnedAppStatus());
+  extension_service_->AddExtension(extension3_.get());
+  EXPECT_EQ("AppList, Chrome, App1, App2, App3, ", GetPinnedAppStatus());
+
+  // Change the order with increasing chrome position and decreasing position.
+  base::ListValue policy_value1;
+  InsertPrefValue(&policy_value1, 0, extension3_->id());
+  InsertPrefValue(&policy_value1, 1, extension1_->id());
+  InsertPrefValue(&policy_value1, 2, extension2_->id());
+  SetShelfChromeIconIndex(3);
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value1.DeepCopy());
+  EXPECT_EQ("AppList, App3, App1, App2, Chrome, ", GetPinnedAppStatus());
+  base::ListValue policy_value2;
+  InsertPrefValue(&policy_value2, 0, extension2_->id());
+  InsertPrefValue(&policy_value2, 1, extension3_->id());
+  InsertPrefValue(&policy_value2, 2, extension1_->id());
+  SetShelfChromeIconIndex(2);
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value2.DeepCopy());
+  EXPECT_EQ("AppList, App2, App3, Chrome, App1, ", GetPinnedAppStatus());
+
+  // Check that the chrome icon can also be at the first possible location.
+  SetShelfChromeIconIndex(0);
+  base::ListValue policy_value3;
+  InsertPrefValue(&policy_value3, 0, extension3_->id());
+  InsertPrefValue(&policy_value3, 1, extension2_->id());
+  InsertPrefValue(&policy_value3, 2, extension1_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                  policy_value3.DeepCopy());
+  EXPECT_EQ("AppList, Chrome, App3, App2, App1, ", GetPinnedAppStatus());
+
+  // Check that unloading of extensions works as expected.
+  extension_service_->UnloadExtension(extension1_->id(),
+                                      extension_misc::UNLOAD_REASON_UNINSTALL);
+  EXPECT_EQ("AppList, Chrome, App3, App2, ", GetPinnedAppStatus());
+
+  extension_service_->UnloadExtension(extension2_->id(),
+                                      extension_misc::UNLOAD_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);
+  EXPECT_EQ("AppList, Chrome, App3, ", GetPinnedAppStatus());
+}
+
+// Check that simple locking of an application will 'create' a launcher item.
+TEST_F(ChromeLauncherControllerTest, CheckLockApps) {
+  InitLauncherController();
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
+
+  launcher_controller_->LockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
+
+  launcher_controller_->UnlockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension2_->id()));
+}
+
+// Check that multiple locks of an application will be properly handled.
+TEST_F(ChromeLauncherControllerTest, CheckMukltiLockApps) {
+  InitLauncherController();
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  for (int i = 0; i < 2; i++) {
+    launcher_controller_->LockV1AppWithID(extension1_->id());
+
+    EXPECT_EQ(3, model_->item_count());
+    EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
+    EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+    EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(
+        extension1_->id()));
+  }
+
+  launcher_controller_->UnlockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->UnlockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+}
+
+// Check that already pinned items are not effected by locks.
+TEST_F(ChromeLauncherControllerTest, CheckAlreadyPinnedLockApps) {
+  InitLauncherController();
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  launcher_controller_->PinAppWithID(extension1_->id());
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->LockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->UnlockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->UnpinAppsWithID(extension1_->id());
+
+  EXPECT_EQ(2, model_->item_count());
+}
+
+// Check that already pinned items which get locked stay after unpinning.
+TEST_F(ChromeLauncherControllerTest, CheckPinnedAppsStayAfterUnlock) {
+  InitLauncherController();
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->PinAppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->LockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->UnpinAppsWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->UnlockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(2, model_->item_count());
+}
+
+// Check that lock -> pin -> unlock -> unpin does properly transition.
+TEST_F(ChromeLauncherControllerTest, CheckLockPinUnlockUnpin) {
+  InitLauncherController();
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->LockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_WINDOWED_APP, model_->items()[1].type);
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_TRUE(launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->PinAppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->UnlockV1AppWithID(extension1_->id());
+
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(
+      launcher_controller_->IsWindowedAppInLauncher(extension1_->id()));
+
+  launcher_controller_->UnpinAppsWithID(extension1_->id());
+
+  EXPECT_EQ(2, model_->item_count());
+}
+
+TEST_F(ChromeLauncherControllerTest, Policy) {
+  extension_service_->AddExtension(extension1_.get());
+  extension_service_->AddExtension(extension3_.get());
+
+  base::ListValue policy_value;
+  InsertPrefValue(&policy_value, 0, extension1_->id());
+  InsertPrefValue(&policy_value, 1, extension2_->id());
+  profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
+                                                     policy_value.DeepCopy());
+
+  // Only |extension1_| should get pinned. |extension2_| is specified but not
+  // installed, and |extension3_| is part of the default set, but that shouldn't
+  // take effect when the policy override is in place.
+  InitLauncherController();
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+
+  // Installing |extension2_| should add it to the launcher.
+  extension_service_->AddExtension(extension2_.get());
+  EXPECT_EQ(4, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+
+  // Removing |extension1_| from the policy should be reflected in the launcher.
+  policy_value.Remove(0, NULL);
+  profile()->GetTestingPrefService()->SetManagedPref(prefs::kPinnedLauncherApps,
+                                                     policy_value.DeepCopy());
+  EXPECT_EQ(3, model_->item_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension1_->id()));
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension2_->id()));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+}
+
+TEST_F(ChromeLauncherControllerTest, UnpinWithUninstall) {
+  extension_service_->AddExtension(extension3_.get());
+  extension_service_->AddExtension(extension4_.get());
+
+  InitLauncherController();
+
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
+
+  extension_service_->UnloadExtension(extension3_->id(),
+                                      extension_misc::UNLOAD_REASON_UNINSTALL);
+
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+  EXPECT_TRUE(launcher_controller_->IsAppPinned(extension4_->id()));
+}
+
+TEST_F(ChromeLauncherControllerTest, PrefUpdates) {
+  extension_service_->AddExtension(extension2_.get());
+  extension_service_->AddExtension(extension3_.get());
+  extension_service_->AddExtension(extension4_.get());
+
+  InitLauncherController();
+
+  std::vector<std::string> expected_launchers;
+  std::vector<std::string> actual_launchers;
+  base::ListValue pref_value;
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                 pref_value.DeepCopy());
+  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
+  EXPECT_EQ(expected_launchers, actual_launchers);
+
+  // Unavailable extensions don't create launcher items.
+  InsertPrefValue(&pref_value, 0, extension1_->id());
+  InsertPrefValue(&pref_value, 1, extension2_->id());
+  InsertPrefValue(&pref_value, 2, extension4_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                 pref_value.DeepCopy());
+  expected_launchers.push_back(extension2_->id());
+  expected_launchers.push_back(extension4_->id());
+  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
+  EXPECT_EQ(expected_launchers, actual_launchers);
+
+  // Redundant pref entries show up only once.
+  InsertPrefValue(&pref_value, 2, extension3_->id());
+  InsertPrefValue(&pref_value, 2, extension3_->id());
+  InsertPrefValue(&pref_value, 5, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                 pref_value.DeepCopy());
+  expected_launchers.insert(expected_launchers.begin() + 1, extension3_->id());
+  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
+  EXPECT_EQ(expected_launchers, actual_launchers);
+
+  // Order changes are reflected correctly.
+  pref_value.Clear();
+  InsertPrefValue(&pref_value, 0, extension4_->id());
+  InsertPrefValue(&pref_value, 1, extension3_->id());
+  InsertPrefValue(&pref_value, 2, extension2_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                 pref_value.DeepCopy());
+  std::reverse(expected_launchers.begin(), expected_launchers.end());
+  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
+  EXPECT_EQ(expected_launchers, actual_launchers);
+
+  // Clearing works.
+  pref_value.Clear();
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                 pref_value.DeepCopy());
+  expected_launchers.clear();
+  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
+  EXPECT_EQ(expected_launchers, actual_launchers);
+}
+
+TEST_F(ChromeLauncherControllerTest, PendingInsertionOrder) {
+  extension_service_->AddExtension(extension1_.get());
+  extension_service_->AddExtension(extension3_.get());
+
+  InitLauncherController();
+
+  base::ListValue pref_value;
+  InsertPrefValue(&pref_value, 0, extension1_->id());
+  InsertPrefValue(&pref_value, 1, extension2_->id());
+  InsertPrefValue(&pref_value, 2, extension3_->id());
+  profile()->GetTestingPrefService()->SetUserPref(prefs::kPinnedLauncherApps,
+                                                 pref_value.DeepCopy());
+
+  std::vector<std::string> expected_launchers;
+  expected_launchers.push_back(extension1_->id());
+  expected_launchers.push_back(extension3_->id());
+  std::vector<std::string> actual_launchers;
+
+  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
+  EXPECT_EQ(expected_launchers, actual_launchers);
+
+  // Install |extension2| and verify it shows up between the other two.
+  extension_service_->AddExtension(extension2_.get());
+  expected_launchers.insert(expected_launchers.begin() + 1, extension2_->id());
+  GetAppLaunchers(launcher_controller_.get(), &actual_launchers);
+  EXPECT_EQ(expected_launchers, actual_launchers);
+}
+
+// Checks the created menus and menu lists for correctness. It uses the given
+// |controller| to create the objects for the given |item| and checks the
+// found item count against the |expected_items|. The |title| list contains the
+// menu titles in the order of their appearance in the menu (not including the
+// application name).
+bool CheckMenuCreation(ChromeLauncherController* controller,
+                       const ash::LauncherItem& item,
+                       size_t expected_items,
+                       string16 title[],
+                       bool is_browser) {
+  ChromeLauncherAppMenuItems items = controller->GetApplicationList(item, 0);
+  // A new behavior has been added: Only show menus if there is at least one
+  // item available.
+  if (expected_items < 1 && is_browser) {
+    EXPECT_EQ(0u, items.size());
+    return items.size() == 0;
+  }
+  // There should be one item in there: The title.
+  EXPECT_EQ(expected_items + 1, items.size());
+  EXPECT_FALSE(items[0]->IsEnabled());
+  for (size_t i = 0; i < expected_items; i++) {
+    EXPECT_EQ(title[i], items[1 + i]->title());
+    // Check that the first real item has a leading separator.
+    if (i == 1)
+      EXPECT_TRUE(items[i]->HasLeadingSeparator());
+    else
+      EXPECT_FALSE(items[i]->HasLeadingSeparator());
+  }
+
+  scoped_ptr<ash::LauncherMenuModel> menu(
+      controller->CreateApplicationMenu(item, 0));
+  // The first element in the menu is a spacing separator. On some systems
+  // (e.g. Windows) such things do not exist. As such we check the existence
+  // and adjust dynamically.
+  int first_item = menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR ? 1 : 0;
+  int expected_menu_items = first_item +
+                            (expected_items ? (expected_items + 3) : 2);
+  EXPECT_EQ(expected_menu_items, menu->GetItemCount());
+  EXPECT_FALSE(menu->IsEnabledAt(first_item));
+  if (expected_items) {
+    EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR,
+              menu->GetTypeAt(first_item + 1));
+  }
+  return items.size() == expected_items + 1;
+}
+
+// Check that browsers get reflected correctly in the launcher menu.
+TEST_F(ChromeLauncherControllerTest, BrowserMenuGeneration) {
+  EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
+  chrome::NewTab(browser());
+
+  InitLauncherController();
+
+  // Check that the browser list is empty at this time.
+  ash::LauncherItem item_browser;
+  item_browser.type = ash::TYPE_BROWSER_SHORTCUT;
+  item_browser.id =
+      launcher_controller_->GetLauncherIDForAppID(extension_misc::kChromeAppId);
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 0, NULL, true));
+
+  // Now make the created browser() visible by adding it to the active browser
+  // list.
+  BrowserList::SetLastActive(browser());
+  string16 title1 = ASCIIToUTF16("Test1");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL("http://test1"), title1);
+  string16 one_menu_item[] = {title1};
+
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 1, one_menu_item, true));
+
+  // Create one more browser/window and check that one more was added.
+  Browser::CreateParams ash_params(profile(), chrome::HOST_DESKTOP_TYPE_ASH);
+  scoped_ptr<Browser> browser2(
+      chrome::CreateBrowserWithTestWindowForParams(&ash_params));
+  chrome::NewTab(browser2.get());
+  BrowserList::SetLastActive(browser2.get());
+  string16 title2 = ASCIIToUTF16("Test2");
+  NavigateAndCommitActiveTabWithTitle(browser2.get(), GURL("http://test2"),
+                                      title2);
+
+  // Check that the list contains now two entries - make furthermore sure that
+  // the active item is the first entry.
+  string16 two_menu_items[] = {title1, title2};
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 2, two_menu_items, true));
+
+  // Apparently we have to close all tabs we have.
+  chrome::CloseTab(browser2.get());
+}
+
+// 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
+// and does not need a separate test here.
+TEST_F(ChromeLauncherControllerTest, V1AppMenuGeneration) {
+  EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
+  EXPECT_EQ(0, browser()->tab_strip_model()->count());
+
+  InitLauncherControllerWithBrowser();
+
+  // Model should only contain the browser shortcut and app list items.
+  EXPECT_EQ(2, model_->item_count());
+  EXPECT_FALSE(launcher_controller_->IsAppPinned(extension3_->id()));
+
+  // 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 one empty tab.
+  chrome::NewTab(browser());
+  string16 title2 = ASCIIToUTF16("Test2");
+  NavigateAndCommitActiveTabWithTitle(
+      browser(),
+      GURL("https://bla"),
+      title2);
+
+  // and another one with another gmail instance.
+  chrome::NewTab(browser());
+  string16 title3 = ASCIIToUTF16("Test3");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title3);
+  string16 two_menu_items[] = {title1, title3};
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
+
+  // Even though the item is in the V1 app list, it should also be in the
+  // browser list.
+  string16 browser_menu_item[] = {title3};
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 1, browser_menu_item, false));
+
+  // Test that closing of (all) the item(s) does work (and all menus get
+  // updated properly).
+  launcher_controller_->Close(item_gmail.id);
+
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 0, NULL, false));
+  string16 browser_menu_item2[] = {title2};
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_browser, 1, browser_menu_item2, false));
+}
+
+// Checks that the generated menu list properly activates items.
+TEST_F(ChromeLauncherControllerTest, V1AppMenuExecution) {
+  InitLauncherControllerWithBrowser();
+
+  // Add |extension3_| to the launcher and add two items.
+  GURL gmail = GURL("https://mail.google.com/mail/u");
+  ash::LauncherID gmail_id = model_->next_id();
+  extension_service_->AddExtension(extension3_.get());
+  launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
+  string16 title1 = ASCIIToUTF16("Test1");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
+  chrome::NewTab(browser());
+  string16 title2 = ASCIIToUTF16("Test2");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
+
+  // Check that the menu is properly set.
+  ash::LauncherItem item_gmail;
+  item_gmail.type = ash::TYPE_APP_SHORTCUT;
+  item_gmail.id = gmail_id;
+  string16 two_menu_items[] = {title1, title2};
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
+  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
+  // Execute the second item in the list (which shouldn't do anything since that
+  // item is per definition already the active tab).
+  {
+    scoped_ptr<ash::LauncherMenuModel> menu(
+        launcher_controller_->CreateApplicationMenu(item_gmail, 0));
+    // The first element in the menu is a spacing separator. On some systems
+    // (e.g. Windows) such things do not exist. As such we check the existence
+    // and adjust dynamically.
+    int first_item =
+        (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
+    menu->ActivatedAt(first_item + 3);
+  }
+  EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
+
+  // Execute the first item.
+  {
+    scoped_ptr<ash::LauncherMenuModel> menu(
+        launcher_controller_->CreateApplicationMenu(item_gmail, 0));
+    int first_item =
+        (menu->GetTypeAt(0) == ui::MenuModel::TYPE_SEPARATOR) ? 1 : 0;
+    menu->ActivatedAt(first_item + 2);
+  }
+  // Now the active tab should be the second item.
+  EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
+}
+
+// Checks that the generated menu list properly deletes items.
+TEST_F(ChromeLauncherControllerTest, V1AppMenuDeletionExecution) {
+  InitLauncherControllerWithBrowser();
+
+  // Add |extension3_| to the launcher and add two items.
+  GURL gmail = GURL("https://mail.google.com/mail/u");
+  ash::LauncherID gmail_id = model_->next_id();
+  extension_service_->AddExtension(extension3_.get());
+  launcher_controller_->SetRefocusURLPatternForTest(gmail_id, GURL(gmail_url));
+  string16 title1 = ASCIIToUTF16("Test1");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title1);
+  chrome::NewTab(browser());
+  string16 title2 = ASCIIToUTF16("Test2");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title2);
+
+  // Check that the menu is properly set.
+  ash::LauncherItem item_gmail;
+  item_gmail.type = ash::TYPE_APP_SHORTCUT;
+  item_gmail.id = gmail_id;
+  string16 two_menu_items[] = {title1, title2};
+  EXPECT_TRUE(CheckMenuCreation(
+      launcher_controller_.get(), item_gmail, 2, two_menu_items, false));
+
+  int tabs = browser()->tab_strip_model()->count();
+  // Activate the proper tab through the menu item.
+  {
+    ChromeLauncherAppMenuItems items =
+        launcher_controller_->GetApplicationList(item_gmail, 0);
+    items[1]->Execute(0);
+    EXPECT_EQ(tabs, browser()->tab_strip_model()->count());
+  }
+
+  // Delete one tab through the menu item.
+  {
+    ChromeLauncherAppMenuItems items =
+        launcher_controller_->GetApplicationList(item_gmail, 0);
+    items[1]->Execute(ui::EF_SHIFT_DOWN);
+    EXPECT_EQ(--tabs, browser()->tab_strip_model()->count());
+  }
+}
+
+// Tests that panels create launcher items correctly
+TEST_F(ChromeLauncherControllerTest, AppPanels) {
+  InitLauncherControllerWithBrowser();
+  // Browser shortcut LauncherItem is added.
+  EXPECT_EQ(1, model_observer_->added());
+
+  TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl();
+  SetAppIconLoader(app_icon_loader);
+
+  // Test adding an app panel
+  std::string app_id = extension1_->id();
+  ShellWindowLauncherItemController app_panel_controller(
+      LauncherItemController::TYPE_APP_PANEL, "id", app_id,
+      launcher_controller_.get());
+  ash::LauncherID launcher_id1 = launcher_controller_->CreateAppLauncherItem(
+      &app_panel_controller, app_id, ash::STATUS_RUNNING);
+  int panel_index = model_observer_->last_index();
+  EXPECT_EQ(2, model_observer_->added());
+  EXPECT_EQ(0, model_observer_->changed());
+  EXPECT_EQ(1, app_icon_loader->fetch_count());
+  model_observer_->clear_counts();
+
+  // App panels should have a separate identifier than the app id
+  EXPECT_EQ(0, launcher_controller_->GetLauncherIDForAppID(app_id));
+
+  // Setting the app image image should not change the panel if it set its icon
+  app_panel_controller.set_image_set_by_controller(true);
+  gfx::ImageSkia image;
+  launcher_controller_->SetAppImage(app_id, image);
+  EXPECT_EQ(0, model_observer_->changed());
+  model_observer_->clear_counts();
+
+  // Add a second app panel and verify that it get the same index as the first
+  // one had, being added to the left of the existing panel.
+  ash::LauncherID launcher_id2 = launcher_controller_->CreateAppLauncherItem(
+      &app_panel_controller, app_id, ash::STATUS_RUNNING);
+  EXPECT_EQ(panel_index, model_observer_->last_index());
+  EXPECT_EQ(1, model_observer_->added());
+  model_observer_->clear_counts();
+
+  launcher_controller_->CloseLauncherItem(launcher_id2);
+  launcher_controller_->CloseLauncherItem(launcher_id1);
+  EXPECT_EQ(2, model_observer_->removed());
+}
+
+// Tests that the Gmail extension matches more then the app itself claims with
+// the manifest file.
+TEST_F(ChromeLauncherControllerTest, GmailMatching) {
+  InitLauncherControllerWithBrowser();
+
+  // Create a Gmail browser tab.
+  chrome::NewTab(browser());
+  string16 title = ASCIIToUTF16("Test");
+  NavigateAndCommitActiveTabWithTitle(browser(), GURL(gmail_url), title);
+  content::WebContents* content =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // Check that the launcher controller does not recognize the running app.
+  EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
+
+  // 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()));
+
+  // Check that it is now handled.
+  EXPECT_TRUE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
+
+  // Check also that the app has detected that properly.
+  ash::LauncherItem item_gmail;
+  item_gmail.type = ash::TYPE_APP_SHORTCUT;
+  item_gmail.id = gmail_id;
+  EXPECT_EQ(2U, launcher_controller_->GetApplicationList(item_gmail, 0).size());
+}
+
+// Tests that the Gmail extension does not match the offline verison.
+TEST_F(ChromeLauncherControllerTest, GmailOfflineMatching) {
+  InitLauncherControllerWithBrowser();
+
+  // Create a Gmail browser tab.
+  chrome::NewTab(browser());
+  string16 title = ASCIIToUTF16("Test");
+  NavigateAndCommitActiveTabWithTitle(browser(),
+                                      GURL(offline_gmail_url),
+                                      title);
+  content::WebContents* content =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  // 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()));
+
+  // The content should not be able to be handled by the app.
+  EXPECT_FALSE(launcher_controller_->ContentCanBeHandledByGmailApp(content));
+}
+
+// Verify that the launcher item positions are persisted and restored.
+TEST_F(ChromeLauncherControllerTest, PersistLauncherItemPositions) {
+  InitLauncherController();
+
+  TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
+  SetAppTabHelper(app_tab_helper);
+
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[0].type);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[1].type);
+
+  TabStripModel* tab_strip_model = browser()->tab_strip_model();
+  EXPECT_EQ(0, tab_strip_model->count());
+  chrome::NewTab(browser());
+  chrome::NewTab(browser());
+  EXPECT_EQ(2, tab_strip_model->count());
+  app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
+  app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
+
+  EXPECT_FALSE(launcher_controller_->IsAppPinned("1"));
+  launcher_controller_->PinAppWithID("1");
+  EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
+  launcher_controller_->PinAppWithID("2");
+
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[0].type);
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[2].type);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[3].type);
+
+  // Move browser shortcut item from index 0 to index 2.
+  model_->Move(0, 2);
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[0].type);
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[2].type);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[3].type);
+
+  launcher_controller_.reset();
+  model_.reset(new ash::LauncherModel);
+  launcher_controller_.reset(
+      ChromeLauncherController::CreateInstance(profile(), model_.get()));
+  app_tab_helper = new TestAppTabHelperImpl;
+  app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
+  app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(1), "2");
+  SetAppTabHelper(app_tab_helper);
+
+  launcher_controller_->Init();
+
+  // Check LauncherItems are restored after resetting ChromeLauncherController.
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[0].type);
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[1].type);
+  EXPECT_EQ(ash::TYPE_BROWSER_SHORTCUT, model_->items()[2].type);
+  EXPECT_EQ(ash::TYPE_APP_LIST, model_->items()[3].type);
+}
+
+// Verifies pinned apps are persisted and restored.
+TEST_F(ChromeLauncherControllerTest, PersistPinned) {
+  InitLauncherControllerWithBrowser();
+  size_t initial_size = model_->items().size();
+
+  TabStripModel* tab_strip_model = browser()->tab_strip_model();
+  EXPECT_EQ(1, tab_strip_model->count());
+
+  TestAppTabHelperImpl* app_tab_helper = new TestAppTabHelperImpl;
+  app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
+  SetAppTabHelper(app_tab_helper);
+
+  TestAppIconLoaderImpl* app_icon_loader = new TestAppIconLoaderImpl;
+  SetAppIconLoader(app_icon_loader);
+  EXPECT_EQ(0, app_icon_loader->fetch_count());
+
+  launcher_controller_->PinAppWithID("1");
+  ash::LauncherID id = launcher_controller_->GetLauncherIDForAppID("1");
+  int app_index = model_->ItemIndexByID(id);
+  EXPECT_EQ(1, app_icon_loader->fetch_count());
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type);
+  EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
+  EXPECT_EQ(initial_size + 1, model_->items().size());
+
+  launcher_controller_.reset();
+  model_.reset(new ash::LauncherModel);
+  launcher_controller_.reset(
+      ChromeLauncherController::CreateInstance(profile(), model_.get()));
+  app_tab_helper = new TestAppTabHelperImpl;
+  app_tab_helper->SetAppID(tab_strip_model->GetWebContentsAt(0), "1");
+  SetAppTabHelper(app_tab_helper);
+  app_icon_loader = new TestAppIconLoaderImpl;
+  SetAppIconLoader(app_icon_loader);
+  launcher_controller_->Init();
+
+  EXPECT_EQ(1, app_icon_loader->fetch_count());
+  ASSERT_EQ(initial_size + 1, model_->items().size());
+  EXPECT_TRUE(launcher_controller_->IsAppPinned("1"));
+  EXPECT_FALSE(launcher_controller_->IsAppPinned("0"));
+  EXPECT_EQ(ash::TYPE_APP_SHORTCUT, model_->items()[app_index].type);
+
+  launcher_controller_->UnpinAppsWithID("1");
+  ASSERT_EQ(initial_size, model_->items().size());
+}
diff --git a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc
index 61c9881..b380e97 100644
--- a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h"
 
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
 
 LauncherApplicationMenuItemModel::LauncherApplicationMenuItemModel(
     ChromeLauncherAppMenuItems item_list)
diff --git a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h
index 48816f4..46a483f 100644
--- a/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h
+++ b/chrome/browser/ui/ash/launcher/launcher_application_menu_item_model.h
@@ -7,7 +7,12 @@
 
 #include "ash/launcher/launcher_delegate.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
+#include "base/memory/scoped_vector.h"
+
+class ChromeLauncherAppMenuItem;
+
+// A list of the elements which makes up a simple menu description.
+typedef ScopedVector<ChromeLauncherAppMenuItem> ChromeLauncherAppMenuItems;
 
 // A menu model that builds the contents of a menu for a launcher item
 // containing a list of running applications.
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
index 1d28300..14930dd 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -8,6 +8,7 @@
 
 #include "ash/desktop_background/user_wallpaper_delegate.h"
 #include "ash/root_window_controller.h"
+#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/wm/property_util.h"
@@ -144,8 +145,7 @@
     AddCheckItemWithStringId(MENU_AUTO_HIDE,
                              IDS_ASH_SHELF_CONTEXT_MENU_AUTO_HIDE);
   }
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kShowShelfAlignmentMenu)) {
+  if (ash::ShelfWidget::ShelfAlignmentAllowed()) {
     AddSubMenuWithStringId(MENU_ALIGNMENT_MENU,
                            IDS_ASH_SHELF_CONTEXT_MENU_POSITION,
                            &launcher_alignment_menu_);
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
index dbcf723..96bb851 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -13,21 +13,18 @@
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h"
 #include "chrome/test/base/testing_profile.h"
 #include "ui/aura/root_window.h"
 
-class TestChromeLauncherControllerPerBrowser :
-    public ChromeLauncherControllerPerBrowser {
+class TestChromeLauncherController : public ChromeLauncherController {
  public:
-  TestChromeLauncherControllerPerBrowser(
-      Profile* profile, ash::LauncherModel* model)
-      : ChromeLauncherControllerPerBrowser(profile, model) {}
+  TestChromeLauncherController(Profile* profile, ash::LauncherModel* model)
+      : ChromeLauncherController(profile, model) {}
   virtual bool IsLoggedInAsGuest() OVERRIDE {
     return false;
   }
  private:
-  DISALLOW_COPY_AND_ASSIGN(TestChromeLauncherControllerPerBrowser);
+  DISALLOW_COPY_AND_ASSIGN(TestChromeLauncherController);
 };
 
 class LauncherContextMenuTest : public ash::test::AshTestBase {
@@ -43,8 +40,7 @@
   virtual void SetUp() OVERRIDE {
     ash::test::AshTestBase::SetUp();
     controller_.reset(
-        new TestChromeLauncherControllerPerBrowser(profile(),
-                                                   &launcher_model_));
+        new TestChromeLauncherController(profile(), &launcher_model_));
   }
 
   virtual void TearDown() OVERRIDE {
diff --git a/chrome/browser/ui/ash/launcher/launcher_item_controller.h b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
index 70c6196..631a66f 100644
--- a/chrome/browser/ui/ash/launcher/launcher_item_controller.h
+++ b/chrome/browser/ui/ash/launcher/launcher_item_controller.h
@@ -66,7 +66,9 @@
   virtual string16 GetTitle() = 0;
 
   // Returns true if this item controls |window|.
-  virtual bool HasWindow(aura::Window* window) const = 0;
+  // When this |window| has multiple applications/tabs, it only returns true
+  // it controls the currently visible app/tab.
+  virtual bool IsCurrentlyShownInWindow(aura::Window* window) const = 0;
 
   // Returns true if this item is open.
   virtual bool IsOpen() const = 0;
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 ab155fd..0a52893 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
@@ -11,7 +11,6 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app.h"
 #include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/aura/client/aura_constants.h"
@@ -96,7 +95,7 @@
   return GetAppTitle();
 }
 
-bool ShellWindowLauncherItemController::HasWindow(
+bool ShellWindowLauncherItemController::IsCurrentlyShownInWindow(
     aura::Window* window) const {
   ShellWindowList::const_iterator iter =
       std::find_if(shell_windows_.begin(), shell_windows_.end(),
@@ -155,8 +154,7 @@
     } else {
       ShowAndActivateOrMinimize(panel);
     }
-  } else if (launcher_controller()->GetPerAppInterface() ||
-      shell_windows_.size() == 1) {
+  } else {
     ShellWindow* window_to_show = last_active_shell_window_ ?
         last_active_shell_window_ : shell_windows_.front();
     // If the event was triggered by a keystroke, we try to advance to the next
@@ -168,20 +166,6 @@
     } else {
       ShowAndActivateOrMinimize(window_to_show);
     }
-  } else {
-    // TODO(stevenjb): Deprecate
-    if (!last_active_shell_window_ ||
-        last_active_shell_window_->GetBaseWindow()->IsActive()) {
-      // Restore all windows since there is no other way to restore them.
-      for (ShellWindowList::iterator iter = shell_windows_.begin();
-           iter != shell_windows_.end(); ++iter) {
-        ShellWindow* shell_window = *iter;
-        if (shell_window->GetBaseWindow()->IsMinimized())
-          shell_window->GetBaseWindow()->Restore();
-      }
-    }
-    if (last_active_shell_window_)
-      ShowAndActivateOrMinimize(last_active_shell_window_);
   }
 }
 
@@ -206,7 +190,7 @@
         shell_window->GetTitle(),
         image.get(),  // Will be copied
         app_id(),
-        launcher_controller()->GetPerAppInterface(),
+        launcher_controller(),
         index,
         index == 0 /* has_leading_separator */));
     ++index;
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 acf4308..f55d6c3 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
@@ -56,7 +56,7 @@
 
   // LauncherItemController
   virtual string16 GetTitle() OVERRIDE;
-  virtual bool HasWindow(aura::Window* window) const OVERRIDE;
+  virtual bool IsCurrentlyShownInWindow(aura::Window* window) const OVERRIDE;
   virtual bool IsOpen() const OVERRIDE;
   virtual bool IsVisible() const OVERRIDE;
   virtual void Launch(int event_flags) OVERRIDE;
diff --git a/chrome/browser/ui/ash/screenshot_taker.cc b/chrome/browser/ui/ash/screenshot_taker.cc
index f1764fb..13cf3b9 100644
--- a/chrome/browser/ui/ash/screenshot_taker.cc
+++ b/chrome/browser/ui/ash/screenshot_taker.cc
@@ -10,8 +10,10 @@
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/file_util.h"
+#include "base/i18n/time_formatting.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/prefs/pref_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -21,8 +23,8 @@
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/screenshot_source.h"
 #include "chrome/browser/ui/window_snapshot/window_snapshot.h"
+#include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "grit/ash_strings.h"
 #include "grit/theme_resources.h"
@@ -33,6 +35,11 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 
+#if defined(USE_ASH)
+#include "ash/shell.h"
+#include "ash/shell_delegate.h"
+#endif
+
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
@@ -70,7 +77,7 @@
     if (!success_)
       return;
 #if defined(OS_CHROMEOS)
-    file_manager::util::ShowFileInFolder(screenshot_path_);
+    file_manager::util::ShowItemInFolder(screenshot_path_);
 #else
     // TODO(sschmitz): perhaps add similar action for Windows.
 #endif
@@ -222,6 +229,68 @@
   return chrome::GrabWindowSnapshotForUser(window, png_data, snapshot_bounds);
 }
 
+bool ShouldUse24HourClock() {
+#if defined(OS_CHROMEOS)
+  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
+  if (profile) {
+    return profile->GetPrefs()->GetBoolean(prefs::kUse24HourClock);
+  }
+#endif
+  return base::GetHourClockType() == base::k24HourClock;
+}
+
+std::string GetScreenshotBaseFilename() {
+  base::Time::Exploded now;
+  base::Time::Now().LocalExplode(&now);
+
+  // We don't use base/i18n/time_formatting.h here because it doesn't
+  // support our format.  Don't use ICU either to avoid i18n file names
+  // for non-English locales.
+  // TODO(mukai): integrate this logic somewhere time_formatting.h
+  std::string file_name = base::StringPrintf(
+      "Screenshot %d-%02d-%02d at ", now.year, now.month, now.day_of_month);
+
+  if (ShouldUse24HourClock()) {
+    file_name.append(base::StringPrintf(
+        "%02d.%02d.%02d", now.hour, now.minute, now.second));
+  } else {
+    int hour = now.hour;
+    if (hour > 12) {
+      hour -= 12;
+    } else if (hour == 0) {
+      hour = 12;
+    }
+    file_name.append(base::StringPrintf(
+        "%d.%02d.%02d ", hour, now.minute, now.second));
+    file_name.append((now.hour >= 12) ? "PM" : "AM");
+  }
+
+  return file_name;
+}
+
+bool GetScreenshotDirectory(base::FilePath* directory) {
+  if (g_browser_process->local_state()->GetBoolean(prefs::kDisableScreenshots))
+    return false;
+
+  bool is_logged_in = true;
+
+#if defined(OS_CHROMEOS)
+  is_logged_in = chromeos::LoginState::Get()->IsUserLoggedIn();
+#endif
+
+  if (is_logged_in) {
+    DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext(
+        ash::Shell::GetInstance()->delegate()->GetCurrentBrowserContext());
+    *directory = download_prefs->DownloadPath();
+  } else  {
+    if (!file_util::GetTempDir(directory)) {
+      LOG(ERROR) << "Failed to find temporary directory.";
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
 ScreenshotTaker::ScreenshotTaker()
@@ -236,14 +305,13 @@
   base::FilePath screenshot_directory;
   if (!screenshot_directory_for_test_.empty()) {
     screenshot_directory = screenshot_directory_for_test_;
-  } else if (!ScreenshotSource::GetScreenshotDirectory(&screenshot_directory)) {
+  } else if (!GetScreenshotDirectory(&screenshot_directory)) {
     ShowNotification(ScreenshotTakerObserver::SCREENSHOT_GET_DIR_FAILED,
                      base::FilePath());
     return;
   }
   std::string screenshot_basename = !screenshot_basename_for_test_.empty() ?
-      screenshot_basename_for_test_ :
-      ScreenshotSource::GetScreenshotBaseFilename();
+      screenshot_basename_for_test_ : GetScreenshotBaseFilename();
 
   ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
   // Reorder root_windows to take the primary root window's snapshot at first.
@@ -285,7 +353,7 @@
   base::FilePath screenshot_directory;
   if (!screenshot_directory_for_test_.empty()) {
     screenshot_directory = screenshot_directory_for_test_;
-  } else if (!ScreenshotSource::GetScreenshotDirectory(&screenshot_directory)) {
+  } else if (!GetScreenshotDirectory(&screenshot_directory)) {
     ShowNotification(ScreenshotTakerObserver::SCREENSHOT_GET_DIR_FAILED,
                      base::FilePath());
     return;
@@ -294,8 +362,7 @@
   scoped_refptr<base::RefCountedBytes> png_data(new base::RefCountedBytes);
 
   std::string screenshot_basename = !screenshot_basename_for_test_.empty() ?
-      screenshot_basename_for_test_ :
-      ScreenshotSource::GetScreenshotBaseFilename();
+      screenshot_basename_for_test_ : GetScreenshotBaseFilename();
   base::FilePath screenshot_path =
       screenshot_directory.AppendASCII(screenshot_basename + ".png");
   if (GrabWindowSnapshot(window, rect, &png_data->data())) {
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 832e8be..3fec283 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -107,6 +107,26 @@
 // Limit Wallet items refresh rate to at most once per minute.
 const int kWalletItemsRefreshRateSeconds = 60;
 
+// A helper class to make sure an AutofillDialogView knows when a series of
+// updates is incoming.
+class ScopedViewUpdates {
+ public:
+  explicit ScopedViewUpdates(AutofillDialogView* view) : view_(view) {
+    if (view_)
+      view_->UpdatesStarted();
+  }
+
+  ~ScopedViewUpdates() {
+    if (view_)
+      view_->UpdatesFinished();
+  }
+
+ private:
+  AutofillDialogView* view_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedViewUpdates);
+};
+
 // Returns true if |card_type| is supported by Wallet.
 bool IsWalletSupportedCard(const std::string& card_type) {
   return card_type == autofill::kVisaCard ||
@@ -626,6 +646,8 @@
 void AutofillDialogControllerImpl::UpdateAutocheckoutStep(
     AutocheckoutStepType step_type,
     AutocheckoutStepStatus step_status) {
+  ScopedViewUpdates updates(view_.get());
+
   int total_steps = 0;
   int completed_steps = 0;
   for (size_t i = 0; i < steps_.size(); ++i) {
@@ -852,6 +874,7 @@
 void AutofillDialogControllerImpl::GetWalletItems() {
   DCHECK(previously_selected_instrument_id_.empty());
   DCHECK(previously_selected_shipping_address_id_.empty());
+  ScopedViewUpdates updates(view_.get());
 
   if (wallet_items_) {
     if (ActiveInstrument())
@@ -872,6 +895,7 @@
 }
 
 void AutofillDialogControllerImpl::HideSignIn() {
+  ScopedViewUpdates updates(view_.get());
   signin_registrar_.RemoveAll();
   view_->HideSignIn();
   view_->UpdateAccountChooser();
@@ -912,6 +936,7 @@
 }
 
 void AutofillDialogControllerImpl::OnWalletOrSigninUpdate() {
+  ScopedViewUpdates updates(view_.get());
   SignedInStateUpdated();
   SuggestionsUpdated();
   UpdateAccountChooserView();
@@ -1421,6 +1446,7 @@
 
 void AutofillDialogControllerImpl::EditClickedForSection(
     DialogSection section) {
+  ScopedViewUpdates updates(view_.get());
   scoped_ptr<DataModelWrapper> model = CreateWrapper(section);
   SetEditingExistingData(section, true);
 
@@ -1436,12 +1462,6 @@
       GetDialogType(), common::DialogSectionToUiEditEvent(section));
 }
 
-void AutofillDialogControllerImpl::EditCancelledForSection(
-    DialogSection section) {
-  ResetSectionInput(section);
-  UpdateSection(section);
-}
-
 gfx::Image AutofillDialogControllerImpl::IconForField(
     ServerFieldType type, const string16& user_input) const {
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
@@ -1876,6 +1896,8 @@
 }
 
 void AutofillDialogControllerImpl::SignInLinkClicked() {
+  ScopedViewUpdates updates(view_.get());
+
   if (signin_registrar_.IsEmpty()) {
     // Start sign in.
     DCHECK(!IsPayingWithWallet());
@@ -2005,6 +2027,7 @@
 
 void AutofillDialogControllerImpl::DidAcceptSuggestion(const string16& value,
                                                        int identifier) {
+  ScopedViewUpdates updates(view_.get());
   const PersonalDataManager::GUIDPair& pair = popup_guids_[identifier];
 
   scoped_ptr<DataModelWrapper> wrapper;
@@ -2064,6 +2087,8 @@
 void AutofillDialogControllerImpl::SuggestionItemSelected(
     SuggestionsMenuModel* model,
     size_t index) {
+  ScopedViewUpdates updates(view_.get());
+
   if (model->GetItemKeyAt(index) == kManageItemsKey) {
     GURL url;
     if (!IsPayingWithWallet()) {
@@ -2137,6 +2162,7 @@
 void AutofillDialogControllerImpl::OnDidGetFullWallet(
     scoped_ptr<wallet::FullWallet> full_wallet) {
   DCHECK(is_submitting_ && IsPayingWithWallet());
+  ScopedViewUpdates updates(view_.get());
 
   full_wallet_ = full_wallet.Pass();
 
@@ -2177,6 +2203,7 @@
 
 void AutofillDialogControllerImpl::OnUserNameFetchSuccess(
     const std::string& username) {
+  ScopedViewUpdates updates(view_.get());
   const string16 username16 = UTF8ToUTF16(username);
   signin_helper_.reset();
   account_chooser_model_.SetActiveWalletAccountName(username16);
@@ -2252,6 +2279,8 @@
 // AccountChooserModelDelegate implementation.
 
 void AutofillDialogControllerImpl::AccountChoiceChanged() {
+  ScopedViewUpdates updates(view_.get());
+
   if (is_submitting_)
     GetWalletClient()->CancelRequests();
 
@@ -2263,6 +2292,7 @@
 
 void AutofillDialogControllerImpl::UpdateAccountChooserView() {
   if (view_) {
+    ScopedViewUpdates updates(view_.get());
     view_->UpdateAccountChooser();
     view_->UpdateNotificationArea();
   }
@@ -2447,6 +2477,8 @@
 }
 
 void AutofillDialogControllerImpl::SuggestionsUpdated() {
+  ScopedViewUpdates updates(view_.get());
+
   const DetailOutputMap snapshot = TakeUserInputSnapshot();
 
   suggested_email_.Reset();
@@ -2974,6 +3006,7 @@
     full_wallet_.reset();
 
   if (view_) {
+    ScopedViewUpdates updates(view_.get());
     view_->UpdateButtonStrip();
     view_->UpdateNotificationArea();
   }
@@ -3115,7 +3148,8 @@
       active_address_id_,
       source_url_,
       wallet_items_->google_transaction_id(),
-      capabilities));
+      capabilities,
+      wallet_items_->HasRequiredAction(wallet::SETUP_WALLET)));
 }
 
 void AutofillDialogControllerImpl::HandleSaveOrUpdateRequiredActions(
@@ -3143,6 +3177,7 @@
     if (GetDialogType() == DIALOG_TYPE_REQUEST_AUTOCOMPLETE) {
       // To get past this point, the view must call back OverlayButtonPressed.
 #if defined(TOOLKIT_VIEWS)
+      ScopedViewUpdates updates(view_.get());
       view_->UpdateButtonStrip();
 #else
       // TODO(estade): implement overlays on other platforms.
@@ -3365,6 +3400,7 @@
 
   autocheckout_state_ = autocheckout_state;
   if (view_) {
+    ScopedViewUpdates updates(view_.get());
     view_->UpdateDetailArea();
     view_->UpdateButtonStrip();
     view_->UpdateAutocheckoutStepsArea();
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
index 73a9687..bd3dcdb 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -138,7 +138,6 @@
   virtual SuggestionState SuggestionStateForSection(
       DialogSection section) OVERRIDE;
   virtual void EditClickedForSection(DialogSection section) OVERRIDE;
-  virtual void EditCancelledForSection(DialogSection section) OVERRIDE;
   virtual gfx::Image IconForField(ServerFieldType type,
                                   const string16& user_input) const OVERRIDE;
   virtual string16 InputValidityMessage(DialogSection section,
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index 69c8323..f7d8798 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -122,17 +122,45 @@
 
 class TestAutofillDialogView : public AutofillDialogView {
  public:
-  TestAutofillDialogView() {}
+  TestAutofillDialogView() : updates_started_(0) {}
   virtual ~TestAutofillDialogView() {}
 
   virtual void Show() OVERRIDE {}
   virtual void Hide() OVERRIDE {}
-  virtual void UpdateNotificationArea() OVERRIDE {}
-  virtual void UpdateAccountChooser() OVERRIDE {}
-  virtual void UpdateButtonStrip() OVERRIDE {}
-  virtual void UpdateDetailArea() OVERRIDE {}
-  virtual void UpdateAutocheckoutStepsArea() OVERRIDE {}
-  virtual void UpdateSection(DialogSection section) OVERRIDE {}
+
+  virtual void UpdatesStarted() OVERRIDE {
+    updates_started_++;
+  }
+
+  virtual void UpdatesFinished() OVERRIDE {
+    updates_started_--;
+    EXPECT_GE(updates_started_, 0);
+  }
+
+  virtual void UpdateNotificationArea() OVERRIDE {
+    EXPECT_GE(updates_started_, 1);
+  }
+
+  virtual void UpdateAccountChooser() OVERRIDE {
+    EXPECT_GE(updates_started_, 1);
+  }
+
+  virtual void UpdateButtonStrip() OVERRIDE {
+    EXPECT_GE(updates_started_, 1);
+  }
+
+  virtual void UpdateDetailArea() OVERRIDE {
+    EXPECT_GE(updates_started_, 1);
+  }
+
+  virtual void UpdateAutocheckoutStepsArea() OVERRIDE {
+    EXPECT_GE(updates_started_, 1);
+  }
+
+  virtual void UpdateSection(DialogSection section) OVERRIDE {
+    EXPECT_GE(updates_started_, 1);
+  }
+
   virtual void FillSection(DialogSection section,
                            const DetailInput& originating_input) OVERRIDE {};
   virtual void GetUserInput(DialogSection section, DetailOutputMap* output)
@@ -163,6 +191,8 @@
  private:
   std::map<DialogSection, DetailOutputMap> outputs_;
 
+  int updates_started_;
+
   DISALLOW_COPY_AND_ASSIGN(TestAutofillDialogView);
 };
 
@@ -1461,7 +1491,7 @@
   EXPECT_NE(wallet_manage_instruments_url, wallet_manage_addresses_url);
 }
 
-TEST_F(AutofillDialogControllerTest, EditClickedCancelled) {
+TEST_F(AutofillDialogControllerTest, EditClicked) {
   EXPECT_CALL(*controller()->GetView(), ModelChanged()).Times(1);
 
   AutofillProfile full_profile(test::GetVerifiedProfile());
@@ -1488,15 +1518,6 @@
       controller()->RequestedFieldsForSection(SECTION_EMAIL);
   EXPECT_EQ(kEmail, inputs1[0].initial_value);
   EXPECT_FALSE(controller()->SuggestionStateForSection(SECTION_EMAIL).visible);
-
-  // When edit is cancelled, the initial_value should be empty.
-  controller()->EditCancelledForSection(SECTION_EMAIL);
-  const DetailInputs& inputs2 =
-      controller()->RequestedFieldsForSection(SECTION_EMAIL);
-  EXPECT_EQ(kEmail,
-            controller()->SuggestionStateForSection(SECTION_EMAIL).
-                vertically_compact_text);
-  EXPECT_EQ(string16(), inputs2[0].initial_value);
 }
 
 // Tests that editing an autofill profile and then submitting works.
@@ -2112,13 +2133,13 @@
   controller()->EditClickedForSection(SECTION_EMAIL);
   EXPECT_TRUE(controller()->ShouldOfferToSaveInChrome());
 
-  controller()->EditCancelledForSection(SECTION_EMAIL);
+  controller()->MenuModelForSection(SECTION_EMAIL)->ActivatedAt(0);
   EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
 
   controller()->MenuModelForSection(SECTION_EMAIL)->ActivatedAt(1);
   EXPECT_TRUE(controller()->ShouldOfferToSaveInChrome());
 
-  profile()->set_incognito(true);
+  profile()->ForceIncognito(true);
   EXPECT_FALSE(controller()->ShouldOfferToSaveInChrome());
 }
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_view.h b/chrome/browser/ui/autofill/autofill_dialog_view.h
index e450e0c..9466c0b 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_view.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_view.h
@@ -32,6 +32,15 @@
   // Closes the dialog window. May self-delete.
   virtual void Hide() = 0;
 
+  // A hint that the view is going to receive a series of Update* calls soon,
+  // and may want to delay visible changes until after the updates are over.
+  // As multiple calls to UpdatesStarted may be stacked, and the view should
+  // expect an equal number of calls to UpdateFinished().
+  virtual void UpdatesStarted() = 0;
+
+  // The matching call to UpdatesStarted.
+  virtual void UpdatesFinished() = 0;
+
   // Called when a different notification is available.
   virtual void UpdateNotificationArea() = 0;
 
diff --git a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
index 5ecae0f..5eda546 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
@@ -121,9 +121,6 @@
   // Should be called when the user starts editing of the section.
   virtual void EditClickedForSection(DialogSection section) = 0;
 
-  // Should be called when the user cancels editing of the section.
-  virtual void EditCancelledForSection(DialogSection section) = 0;
-
   // Returns an icon to be displayed along with the input for the given type.
   // |user_input| is the current text in the textfield.
   virtual gfx::Image IconForField(ServerFieldType type,
diff --git a/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc
index 1c8a170..36d8ced 100644
--- a/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc
+++ b/chrome/browser/ui/autofill/generated_credit_card_bubble_controller.cc
@@ -223,6 +223,8 @@
 }
 
 void GeneratedCreditCardBubbleController::Show(bool was_anchor_click) {
+  Hide();
+
   if (!CanShow())
     return;
 
diff --git a/chrome/browser/ui/blocked_content/blocked_content_tab_helper.cc b/chrome/browser/ui/blocked_content/blocked_content_tab_helper.cc
index f10c5d5..bb45102 100644
--- a/chrome/browser/ui/blocked_content/blocked_content_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/blocked_content_tab_helper.cc
@@ -42,18 +42,8 @@
   // for this tab, unless this is an in-page navigation.
   if (!details.is_in_page) {
     // Close blocked popups.
-    if (blocked_contents_->GetBlockedContentsCount()) {
+    if (blocked_contents_->GetBlockedContentsCount())
       blocked_contents_->Clear();
-      PopupNotificationVisibilityChanged(false);
-    }
-  }
-}
-
-void BlockedContentTabHelper::PopupNotificationVisibilityChanged(
-    bool visible) {
-  if (!web_contents()->IsBeingDestroyed()) {
-    TabSpecificContentSettings::FromWebContents(web_contents())->
-        SetPopupsBlocked(visible);
   }
 }
 
@@ -84,69 +74,7 @@
                                              WindowOpenDisposition disposition,
                                              const gfx::Rect& initial_pos,
                                              bool user_gesture) {
-  if (!blocked_contents_->GetBlockedContentsCount())
-    PopupNotificationVisibilityChanged(true);
   SendNotification(new_contents, true);
   blocked_contents_->AddWebContents(
       new_contents, disposition, initial_pos, user_gesture);
 }
-
-void BlockedContentTabHelper::AddPopup(content::WebContents* new_contents,
-                                       WindowOpenDisposition disposition,
-                                       const gfx::Rect& initial_pos,
-                                       bool user_gesture) {
-  // A page can't spawn popups (or do anything else, either) until its load
-  // commits, so when we reach here, the popup was spawned by the
-  // NavigationController's last committed entry, not the active entry.  For
-  // example, if a page opens a popup in an onunload() handler, then the active
-  // entry is the page to be loaded as we navigate away from the unloading
-  // page.  For this reason, we can't use GetURL() to get the opener URL,
-  // because it returns the active entry.
-  NavigationEntry* entry =
-      web_contents()->GetController().GetLastCommittedEntry();
-  GURL creator = entry ? entry->GetVirtualURL() : GURL::EmptyGURL();
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-
-  if (creator.is_valid() &&
-      profile->GetHostContentSettingsMap()->GetContentSetting(
-          creator, creator, CONTENT_SETTINGS_TYPE_POPUPS, std::string()) ==
-          CONTENT_SETTING_ALLOW) {
-    content::WebContentsDelegate* delegate = web_contents()->GetDelegate();
-    if (delegate) {
-      delegate->AddNewContents(web_contents(),
-                               new_contents,
-                               disposition,
-                               initial_pos,
-                               true,  // user_gesture
-                               NULL);
-    }
-  } else {
-    // Call blocked_contents_->AddWebContents with user_gesture == true
-    // so that the contents will not get blocked again.
-    SendNotification(new_contents, true);
-    blocked_contents_->AddWebContents(new_contents,
-                                      disposition,
-                                      initial_pos,
-                                      true);  // user_gesture
-    TabSpecificContentSettings::FromWebContents(web_contents())->
-        OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS, std::string());
-  }
-}
-
-void BlockedContentTabHelper::LaunchForContents(
-    content::WebContents* web_contents) {
-  SendNotification(web_contents, false);
-  blocked_contents_->LaunchForContents(web_contents);
-  if (!blocked_contents_->GetBlockedContentsCount())
-    PopupNotificationVisibilityChanged(false);
-}
-
-size_t BlockedContentTabHelper::GetBlockedContentsCount() const {
-  return blocked_contents_->GetBlockedContentsCount();
-}
-
-void BlockedContentTabHelper::GetBlockedContents(
-    std::vector<content::WebContents*>* blocked_contents) const {
-  blocked_contents_->GetBlockedContents(blocked_contents);
-}
diff --git a/chrome/browser/ui/blocked_content/blocked_content_tab_helper.h b/chrome/browser/ui/blocked_content/blocked_content_tab_helper.h
index 9807347..f3f624d 100644
--- a/chrome/browser/ui/blocked_content/blocked_content_tab_helper.h
+++ b/chrome/browser/ui/blocked_content/blocked_content_tab_helper.h
@@ -15,7 +15,8 @@
 class BlockedContentContainer;
 class BlockedContentTabHelperDelegate;
 
-// Per-tab class to manage blocked popups.
+// Collects WebContents objects spawned from the observed WebContents and
+// optionally adds them to the tab strip later on.
 class BlockedContentTabHelper
     : public content::WebContentsObserver,
       public content::WebContentsUserData<BlockedContentTabHelper> {
@@ -39,22 +40,6 @@
                       const gfx::Rect& initial_pos,
                       bool user_gesture);
 
-  // Adds the incoming |new_contents| to the |blocked_contents_| container.
-  void AddPopup(content::WebContents* new_contents,
-                WindowOpenDisposition disposition,
-                const gfx::Rect& initial_pos,
-                bool user_gesture);
-
-  // Shows the blocked WebContents |web_contents|.
-  void LaunchForContents(content::WebContents* web_contents);
-
-  // Returns the number of blocked contents.
-  size_t GetBlockedContentsCount() const;
-
-  // Returns the blocked WebContentses.  |blocked_contents| must be non-NULL.
-  void GetBlockedContents(
-      std::vector<content::WebContents*>* blocked_contents) const;
-
   // content::WebContentsObserver overrides:
   virtual void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
@@ -64,9 +49,6 @@
   explicit BlockedContentTabHelper(content::WebContents* web_contents);
   friend class content::WebContentsUserData<BlockedContentTabHelper>;
 
-  // Called when the blocked popup notification is shown or hidden.
-  void PopupNotificationVisibilityChanged(bool visible);
-
   // Called to notify any observers that |contents| is entering or leaving
   // the blocked state.
   void SendNotification(content::WebContents* contents, bool blocked_state);
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index 91dc0ab..293cca3 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -74,51 +73,52 @@
 class PopupBlockerBrowserTest : public InProcessBrowserTest {
  public:
   PopupBlockerBrowserTest() {}
+  virtual ~PopupBlockerBrowserTest() {}
 
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    InProcessBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kDisableBetterPopupBlocking);
-  }
-
-  // Returns a url that shows one popup.
-  GURL GetTestURL() {
-    return ui_test_utils::GetTestUrl(
-      base::FilePath(kTestDir),
-      base::FilePath(FILE_PATH_LITERAL("popup-blocked-to-post-blank.html")));
-  }
-
-  std::vector<WebContents*> GetBlockedContents(Browser* browser) {
+  int GetBlockedContentsCount() {
     // Do a round trip to the renderer first to flush any in-flight IPCs to
     // create a to-be-blocked window.
-    WebContents* tab = browser->tab_strip_model()->GetActiveWebContents();
+    WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
     CHECK(content::ExecuteScript(tab, std::string()));
-    BlockedContentTabHelper* blocked_content_tab_helper =
-        BlockedContentTabHelper::FromWebContents(tab);
-    std::vector<WebContents*> blocked_contents;
-    blocked_content_tab_helper->GetBlockedContents(&blocked_contents);
-    return blocked_contents;
+    PopupBlockerTabHelper* popup_blocker_helper =
+        PopupBlockerTabHelper::FromWebContents(tab);
+    return popup_blocker_helper->GetBlockedPopupsCount();
   }
 
-  void NavigateAndCheckPopupShown(Browser* browser, const GURL& url) {
+  void NavigateAndCheckPopupShown(const GURL& url) {
     content::WindowedNotificationObserver observer(
         chrome::NOTIFICATION_TAB_ADDED,
         content::NotificationService::AllSources());
-    ui_test_utils::NavigateToURL(browser, url);
+    ui_test_utils::NavigateToURL(browser(), url);
     observer.Wait();
 
-    ASSERT_EQ(2u, chrome::GetBrowserCount(browser->profile(),
-                                          browser->host_desktop_type()));
+    ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile(),
+                                          browser()->host_desktop_type()));
 
-    std::vector<WebContents*> blocked_contents = GetBlockedContents(browser);
-    ASSERT_TRUE(blocked_contents.empty());
+    ASSERT_EQ(0, GetBlockedContentsCount());
   }
 
-  void BasicTest(Browser* browser, const GURL& url) {
+  // Navigates to the test indicated by |test_name| using |browser| which is
+  // expected to try to open a popup. Verifies that the popup was blocked and
+  // then opens the blocked popup. Once the popup stopped loading, verifies
+  // that the title of the page is "PASS" if |check_title| is true.
+  //
+  // If |expect_new_browser| is true, the popup is expected to open a new
+  // window, or a background tab if it is false.
+  //
+  // Returns the WebContents of the launched popup.
+  WebContents* RunCheckTest(Browser* browser,
+                            const base::FilePath& test_name,
+                            bool expect_new_browser,
+                            bool check_title) {
+    GURL url(ui_test_utils::GetTestUrl(base::FilePath(kTestDir), test_name));
+
+    CountRenderViewHosts counter;
+
     ui_test_utils::NavigateToURL(browser, url);
 
-    // If the popup blocker blocked the blank post, there should be only one
-    // tab in only one browser window and the URL of current tab must be equal
-    // to the original URL.
+    // Since the popup blocker blocked the window.open, there should be only one
+    // tab.
     EXPECT_EQ(1u, chrome::GetBrowserCount(browser->profile(),
                                           browser->host_desktop_type()));
     EXPECT_EQ(1, browser->tab_strip_model()->count());
@@ -126,50 +126,128 @@
         browser->tab_strip_model()->GetActiveWebContents();
     EXPECT_EQ(url, web_contents->GetURL());
 
-    std::vector<WebContents*> blocked_contents = GetBlockedContents(browser);
-    ASSERT_EQ(1u, blocked_contents.size());
+    // And no new RVH created.
+    EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
 
     content::WindowedNotificationObserver observer(
         chrome::NOTIFICATION_TAB_ADDED,
         content::NotificationService::AllSources());
+    ui_test_utils::BrowserAddedObserver browser_observer;
 
-    BlockedContentTabHelper* blocked_content_tab_helper =
-        BlockedContentTabHelper::FromWebContents(web_contents);
-    blocked_content_tab_helper->LaunchForContents(blocked_contents[0]);
+    // Launch the blocked popup.
+    PopupBlockerTabHelper* popup_blocker_helper =
+        PopupBlockerTabHelper::FromWebContents(web_contents);
+    if (!popup_blocker_helper->GetBlockedPopupsCount()) {
+      content::WindowedNotificationObserver observer(
+          chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
+          content::NotificationService::AllSources());
+      observer.Wait();
+    }
+    EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
+    std::map<int32, GURL> blocked_requests =
+        popup_blocker_helper->GetBlockedPopupRequests();
+    std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
+    popup_blocker_helper->ShowBlockedPopup(iter->first);
 
     observer.Wait();
+    Browser* new_browser;
+    if (expect_new_browser) {
+      new_browser = browser_observer.WaitForSingleNewBrowser();
+      web_contents = new_browser->tab_strip_model()->GetActiveWebContents();
+    } else {
+      new_browser = browser;
+      EXPECT_EQ(2, browser->tab_strip_model()->count());
+      web_contents = browser->tab_strip_model()->GetWebContentsAt(1);
+    }
+
+    if (check_title) {
+      // Check that the check passed.
+      base::string16 expected_title(base::ASCIIToUTF16("PASS"));
+      content::TitleWatcher title_watcher(web_contents, expected_title);
+      EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+    }
+
+    return web_contents;
   }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PopupBlockerBrowserTest);
 };
 
-IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, PopupBlockedPostBlank) {
-  BasicTest(browser(), GetTestURL());
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
+                       BlockWebContentsCreation) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
+    return;
+#endif
+
+  RunCheckTest(
+      browser(),
+      base::FilePath(FILE_PATH_LITERAL("popup-blocked-to-post-blank.html")),
+      true,
+      false);
 }
 
 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
-                       PopupBlockedPostBlankIncognito) {
-  BasicTest(CreateIncognitoBrowser(), GetTestURL());
+                       BlockWebContentsCreationIncognito) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
+    return;
+#endif
+
+  RunCheckTest(
+      CreateIncognitoBrowser(),
+      base::FilePath(FILE_PATH_LITERAL("popup-blocked-to-post-blank.html")),
+      true,
+      false);
 }
 
 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
                        PopupBlockedFakeClickOnAnchor) {
-  GURL url(ui_test_utils::GetTestUrl(
-      base::FilePath(kTestDir),
-      base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor.html"))));
-  BasicTest(browser(), url);
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
+    return;
+#endif
+
+  RunCheckTest(
+      browser(),
+      base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor.html")),
+      false,
+      false);
+}
+
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
+                       PopupBlockedFakeClickOnAnchorNoTarget) {
+#if defined(OS_WIN) && defined(USE_ASH)
+  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
+    return;
+#endif
+
+  RunCheckTest(
+      browser(),
+      base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor2.html")),
+      false,
+      false);
 }
 
 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, MultiplePopups) {
-  GURL url(ui_test_utils::GetTestUrl(base::FilePath(
-      kTestDir), base::FilePath(FILE_PATH_LITERAL("popup-many.html"))));
+  GURL url(ui_test_utils::GetTestUrl(
+      base::FilePath(kTestDir),
+      base::FilePath(FILE_PATH_LITERAL("popup-many.html"))));
   ui_test_utils::NavigateToURL(browser(), url);
-  std::vector<WebContents*> blocked_contents = GetBlockedContents(browser());
-  ASSERT_EQ(2u, blocked_contents.size());
+  ASSERT_EQ(2, GetBlockedContentsCount());
 }
 
 // Verify that popups are launched on browser back button.
 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
                        AllowPopupThroughContentSetting) {
-  GURL url(GetTestURL());
+  GURL url(ui_test_utils::GetTestUrl(
+      base::FilePath(kTestDir),
+      base::FilePath(FILE_PATH_LITERAL("popup-blocked-to-post-blank.html"))));
   browser()->profile()->GetHostContentSettingsMap()
       ->SetContentSetting(ContentSettingsPattern::FromURL(url),
                           ContentSettingsPattern::Wildcard(),
@@ -177,10 +255,11 @@
                           std::string(),
                           CONTENT_SETTING_ALLOW);
 
-  NavigateAndCheckPopupShown(browser(), url);
+  NavigateAndCheckPopupShown(url);
 }
 
-IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, PopupsLaunchWhenTabIsClosed) {
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
+                       PopupsLaunchWhenTabIsClosed) {
   CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kDisablePopupBlocking);
   GURL url = ui_test_utils::GetTestUrl(
@@ -188,7 +267,7 @@
       base::FilePath(FILE_PATH_LITERAL("popup-on-unload.html")));
   ui_test_utils::NavigateToURL(browser(), url);
 
-  NavigateAndCheckPopupShown(browser(), GURL(content::kAboutBlankURL));
+  NavigateAndCheckPopupShown(GURL(content::kAboutBlankURL));
 }
 
 // Verify that when you unblock popup, the popup shows in history and omnibox.
@@ -196,8 +275,10 @@
                        UnblockedPopupShowsInHistoryAndOmnibox) {
   CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kDisablePopupBlocking);
-  GURL url(GetTestURL());
-  NavigateAndCheckPopupShown(browser(), url);
+  GURL url(ui_test_utils::GetTestUrl(
+      base::FilePath(kTestDir),
+      base::FilePath(FILE_PATH_LITERAL("popup-blocked-to-post-blank.html"))));
+  NavigateAndCheckPopupShown(url);
 
   std::string search_string =
       "data:text/html,<title>Popup Success!</title>you should not see this "
@@ -219,239 +300,71 @@
   EXPECT_EQ(ASCIIToUTF16(search_string), model->CurrentMatch(NULL).contents);
 }
 
-class BetterPopupBlockerBrowserTest : public PopupBlockerBrowserTest {
- public:
-  BetterPopupBlockerBrowserTest() {}
-  virtual ~BetterPopupBlockerBrowserTest() {}
-
-  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
-    InProcessBrowserTest::SetUpCommandLine(command_line);
-  }
-
-  // Navigates to the test indicated by |test_name| which is expected to try to
-  // open a popup. Verifies that the popup was blocked and then opens the
-  // blocked popup. Once the popup stopped loading, verifies that the title of
-  // the page is "PASS".
-  //
-  // If |expect_new_browser| is true, the popup is expected to open a new
-  // window, or a background tab if it is false.
-  void RunCheckTest(const base::FilePath& test_name, bool expect_new_browser) {
-    GURL url(ui_test_utils::GetTestUrl(base::FilePath(kTestDir), test_name));
-
-    CountRenderViewHosts counter;
-
-    ui_test_utils::NavigateToURL(browser(), url);
-
-    // Since the popup blocker blocked the window.open, there should be only one
-    // tab.
-    EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
-                                          browser()->host_desktop_type()));
-    EXPECT_EQ(1, browser()->tab_strip_model()->count());
-    WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-    EXPECT_EQ(url, web_contents->GetURL());
-
-    // And no new RVH created.
-    EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
-
-    content::WindowedNotificationObserver observer(
-        chrome::NOTIFICATION_TAB_ADDED,
-        content::NotificationService::AllSources());
-    ui_test_utils::BrowserAddedObserver browser_observer;
-
-    // Launch the blocked popup.
-    PopupBlockerTabHelper* popup_blocker_helper =
-        PopupBlockerTabHelper::FromWebContents(web_contents);
-    EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
-    std::map<int32, GURL> blocked_requests =
-        popup_blocker_helper->GetBlockedPopupRequests();
-    std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
-    popup_blocker_helper->ShowBlockedPopup(iter->first);
-
-    observer.Wait();
-    Browser* new_browser;
-    if (expect_new_browser) {
-      new_browser  = browser_observer.WaitForSingleNewBrowser();
-      web_contents = new_browser->tab_strip_model()->GetActiveWebContents();
-    } else {
-      new_browser = browser();
-      EXPECT_EQ(2, browser()->tab_strip_model()->count());
-      web_contents = browser()->tab_strip_model()->GetWebContentsAt(1);
-    }
-
-    // Check that the check passed.
-    base::string16 expected_title(base::ASCIIToUTF16("PASS"));
-    content::TitleWatcher title_watcher(web_contents, expected_title);
-    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BetterPopupBlockerBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest,
-                       BlockWebContentsCreation) {
-#if defined(OS_WIN) && defined(USE_ASH)
-  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
-    return;
-#endif
-
-  CountRenderViewHosts counter;
-
-  ui_test_utils::NavigateToURL(browser(), GetTestURL());
-
-  // Wait until the request actually has hit the popup blocker. The
-  // NavigateToURL call above returns as soon as the main tab stopped loading
-  // which can happen before the popup request was processed.
-  WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  PopupBlockerTabHelper* popup_blocker_helper =
-      PopupBlockerTabHelper::FromWebContents(web_contents);
-  if (!popup_blocker_helper->GetBlockedPopupsCount()) {
-    content::WindowedNotificationObserver observer(
-        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
-        content::NotificationService::AllSources());
-    observer.Wait();
-  }
-
-  // If the popup blocker blocked the blank post, there should be only one tab.
-  EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
-                                        browser()->host_desktop_type()));
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_EQ(GetTestURL(), web_contents->GetURL());
-
-  // And no new RVH created.
-  EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
-
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_TAB_ADDED,
-      content::NotificationService::AllSources());
-
-  // Launch the blocked popup.
-  EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
-  std::map<int32, GURL> blocked_requests =
-      popup_blocker_helper->GetBlockedPopupRequests();
-  std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
-  popup_blocker_helper->ShowBlockedPopup(iter->first);
-
-  observer.Wait();
-}
-
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest,
-                       PopupBlockedFakeClickOnAnchorNoTarget) {
-#if defined(OS_WIN) && defined(USE_ASH)
-  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
-    return;
-#endif
-
-  GURL url(ui_test_utils::GetTestUrl(
-      base::FilePath(kTestDir),
-      base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor2.html"))));
-
-  CountRenderViewHosts counter;
-
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  // If the popup blocker blocked the blank post, there should be only one tab.
-  EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
-                                        browser()->host_desktop_type()));
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(url, web_contents->GetURL());
-
-  // And no new RVH created.
-  EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
-
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_TAB_ADDED,
-      content::NotificationService::AllSources());
-
-  // Launch the blocked popup.
-  PopupBlockerTabHelper* popup_blocker_helper =
-      PopupBlockerTabHelper::FromWebContents(web_contents);
-  EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
-  std::map<int32, GURL> blocked_requests =
-      popup_blocker_helper->GetBlockedPopupRequests();
-  std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
-  popup_blocker_helper->ShowBlockedPopup(iter->first);
-
-  observer.Wait();
-}
-
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, WindowFeatures) {
-  GURL url(ui_test_utils::GetTestUrl(
-      base::FilePath(kTestDir),
-      base::FilePath(FILE_PATH_LITERAL("popup-window-open.html"))));
-
-  CountRenderViewHosts counter;
-
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  // If the popup blocker blocked the blank post, there should be only one tab.
-  EXPECT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
-                                        browser()->host_desktop_type()));
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  EXPECT_EQ(url, web_contents->GetURL());
-
-  // And no new RVH created.
-  EXPECT_EQ(0, counter.GetRenderViewHostCreatedCount());
-
-  content::WindowedNotificationObserver observer(
-      chrome::NOTIFICATION_TAB_ADDED,
-      content::NotificationService::AllSources());
-  ui_test_utils::BrowserAddedObserver browser_observer;
-
-  // Launch the blocked popup.
-  PopupBlockerTabHelper* popup_blocker_helper =
-      PopupBlockerTabHelper::FromWebContents(web_contents);
-  EXPECT_EQ(1u, popup_blocker_helper->GetBlockedPopupsCount());
-  std::map<int32, GURL> blocked_requests =
-      popup_blocker_helper->GetBlockedPopupRequests();
-  std::map<int32, GURL>::const_iterator iter = blocked_requests.begin();
-  popup_blocker_helper->ShowBlockedPopup(iter->first);
-
-  observer.Wait();
-  Browser* new_browser = browser_observer.WaitForSingleNewBrowser();
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, WindowFeatures) {
+  WebContents* popup =
+      RunCheckTest(browser(),
+                   base::FilePath(FILE_PATH_LITERAL("popup-window-open.html")),
+                   true,
+                   false);
 
   // Check that the new popup has (roughly) the requested size.
-  web_contents = new_browser->tab_strip_model()->GetActiveWebContents();
-  gfx::Size window_size = web_contents->GetView()->GetContainerSize();
+  gfx::Size window_size = popup->GetView()->GetContainerSize();
   EXPECT_TRUE(349 <= window_size.width() && window_size.width() <= 351);
   EXPECT_TRUE(249 <= window_size.height() && window_size.height() <= 251);
 }
 
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, CorrectReferrer) {
-  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-referrer.html")), true);
-}
-
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, WindowFeaturesBarProps) {
-  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-windowfeatures.html")),
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, CorrectReferrer) {
+  RunCheckTest(browser(),
+               base::FilePath(FILE_PATH_LITERAL("popup-referrer.html")),
+               true,
                true);
 }
 
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, SessionStorage) {
-  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-sessionstorage.html")),
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, WindowFeaturesBarProps) {
+  RunCheckTest(browser(),
+               base::FilePath(FILE_PATH_LITERAL("popup-windowfeatures.html")),
+               true,
                true);
 }
 
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, Opener) {
-  RunCheckTest(base::FilePath(FILE_PATH_LITERAL("popup-opener.html")), true);
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, SessionStorage) {
+  RunCheckTest(browser(),
+               base::FilePath(FILE_PATH_LITERAL("popup-sessionstorage.html")),
+               true,
+               true);
 }
 
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, OpenerSuppressed) {
-  RunCheckTest(
-      base::FilePath(FILE_PATH_LITERAL("popup-openersuppressed.html")), false);
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, Opener) {
+  RunCheckTest(browser(),
+               base::FilePath(FILE_PATH_LITERAL("popup-opener.html")),
+               true,
+               true);
 }
 
-IN_PROC_BROWSER_TEST_F(BetterPopupBlockerBrowserTest, ShiftClick) {
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, OpenerSuppressed) {
+  RunCheckTest(browser(),
+               base::FilePath(FILE_PATH_LITERAL("popup-openersuppressed.html")),
+               false,
+               true);
+}
+
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, ShiftClick) {
   RunCheckTest(
+      browser(),
       base::FilePath(FILE_PATH_LITERAL("popup-fake-click-on-anchor3.html")),
+      true,
       true);
 }
 
+IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, WebUI) {
+  WebContents* popup =
+      RunCheckTest(browser(),
+                   base::FilePath(FILE_PATH_LITERAL("popup-webui.html")),
+                   true,
+                   false);
+
+  // Check that the new popup displays about:blank.
+  EXPECT_EQ(GURL(content::kAboutBlankURL), popup->GetURL());
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index 7212bae..0d27929 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -14,6 +14,7 @@
 #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/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_view.h"
@@ -99,9 +100,12 @@
     const WebWindowFeatures& features,
     bool user_gesture,
     bool opener_suppressed) {
+  GURL popup_url(target_url);
+  content::RenderViewHost::FilterURL(
+      web_contents()->GetRenderProcessHost(), false, &popup_url);
   chrome::NavigateParams nav_params(
       Profile::FromBrowserContext(web_contents()->GetBrowserContext()),
-      target_url,
+      popup_url,
       content::PAGE_TRANSITION_LINK);
   nav_params.referrer = referrer;
   nav_params.source_contents = web_contents();
diff --git a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc
index ef95d4b..4d19024 100644
--- a/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_context_menu_controller_unittest.cc
@@ -46,7 +46,13 @@
   }
 
   virtual void SetUp() OVERRIDE {
-    profile_.reset(new TestingProfile());
+    Reset(false);
+  }
+  void Reset(bool incognito) {
+    TestingProfile::Builder builder;
+    if (incognito)
+      builder.SetIncognito();
+    profile_ = builder.Build();
     profile_->CreateBookmarkModel(true);
 
     model_ = BookmarkModelFactory::GetForProfile(profile_.get());
@@ -237,11 +243,12 @@
 
 // Tests the enabled state of open incognito.
 TEST_F(BookmarkContextMenuControllerTest, DisableIncognito) {
+  // Create a new incognito profile.
+  Reset(true);
   std::vector<const BookmarkNode*> nodes;
   nodes.push_back(model_->bookmark_bar_node()->GetChild(0));
   BookmarkContextMenuController controller(
       NULL, NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes);
-  profile_->set_incognito(true);
   EXPECT_FALSE(controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
   EXPECT_FALSE(
       controller.IsCommandIdEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
diff --git a/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc b/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc
index ad72b6a..426050b 100644
--- a/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_drag_drop.cc
@@ -31,7 +31,8 @@
     return ui::DragDropTypes::DRAG_NONE;
   }
   // Dropping a folder from different profile. Always accept.
-  bookmark_utils::CloneBookmarkNode(model, data.elements, parent_node, index);
+  bookmark_utils::CloneBookmarkNode(model, data.elements, parent_node,
+                                    index, true);
   return ui::DragDropTypes::DRAG_COPY;
 }
 
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 1424f7e..cbf706b 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -368,8 +368,7 @@
 
   toolbar_model_.reset(new ToolbarModelImpl(toolbar_model_delegate_.get()));
   search_model_.reset(new SearchModel());
-  search_delegate_.reset(
-      new SearchDelegate(search_model_.get(), toolbar_model_.get()));
+  search_delegate_.reset(new SearchDelegate(search_model_.get()));
 
   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
                  content::Source<Profile>(profile_->GetOriginalProfile()));
@@ -602,6 +601,24 @@
   return unload_controller_->ShouldCloseWindow();
 }
 
+bool Browser::CallBeforeUnloadHandlers(
+    const base::Callback<void(bool)>& on_close_confirmed) {
+  cancel_download_confirmation_state_ = RESPONSE_RECEIVED;
+  if (IsFastTabUnloadEnabled()) {
+    return fast_unload_controller_->CallBeforeUnloadHandlers(
+        on_close_confirmed);
+  }
+  return unload_controller_->CallBeforeUnloadHandlers(on_close_confirmed);
+}
+
+void Browser::ResetBeforeUnloadHandlers() {
+  cancel_download_confirmation_state_ = NOT_PROMPTED;
+  if (IsFastTabUnloadEnabled())
+    fast_unload_controller_->ResetBeforeUnloadHandlers();
+  else
+    unload_controller_->ResetBeforeUnloadHandlers();
+}
+
 bool Browser::HasCompletedUnloadProcessing() const {
   DCHECK(IsFastTabUnloadEnabled());
   return fast_unload_controller_->HasCompletedUnloadProcessing();
@@ -1290,10 +1307,7 @@
   if (source)
     popup_blocker_helper = PopupBlockerTabHelper::FromWebContents(source);
 
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableBetterPopupBlocking) &&
-      popup_blocker_helper) {
-
+  if (popup_blocker_helper) {
     if ((params.disposition == NEW_POPUP ||
          params.disposition == NEW_FOREGROUND_TAB ||
          params.disposition == NEW_BACKGROUND_TAB ||
@@ -1500,15 +1514,16 @@
     WindowContainerType window_container_type,
     const string16& frame_name,
     const GURL& target_url,
-    const content::Referrer& referrer,
-    WindowOpenDisposition disposition,
-    const WebWindowFeatures& features,
-    bool user_gesture,
-    bool opener_suppressed) {
+    const std::string& partition_id,
+    content::SessionStorageNamespace* session_storage_namespace) {
   if (window_container_type == WINDOW_CONTAINER_TYPE_BACKGROUND) {
     // If a BackgroundContents is created, suppress the normal WebContents.
-    return !MaybeCreateBackgroundContents(
-        route_id, web_contents, frame_name, target_url);
+    return !MaybeCreateBackgroundContents(route_id,
+                                          web_contents,
+                                          frame_name,
+                                          target_url,
+                                          partition_id,
+                                          session_storage_namespace);
   }
 
   return true;
@@ -1858,8 +1873,8 @@
 // Browser, UI update coalescing and handling (private):
 
 void Browser::UpdateToolbar(bool should_restore_state) {
-  window_->UpdateToolbar(tab_strip_model_->GetActiveWebContents(),
-                         should_restore_state);
+  window_->UpdateToolbar(should_restore_state ?
+      tab_strip_model_->GetActiveWebContents() : NULL);
 }
 
 void Browser::UpdateSearchState(WebContents* contents) {
@@ -2038,14 +2053,20 @@
     return cancel_download_confirmation_state_ != WAITING_FOR_RESPONSE;
 
   int num_downloads_blocking;
-  if (DOWNLOAD_CLOSE_OK ==
-      OkToCloseWithInProgressDownloads(&num_downloads_blocking))
+  Browser::DownloadClosePreventionType dialog_type =
+      OkToCloseWithInProgressDownloads(&num_downloads_blocking);
+  if (dialog_type == DOWNLOAD_CLOSE_OK)
     return true;
 
   // Closing this window will kill some downloads; prompt to make sure
   // that's ok.
   cancel_download_confirmation_state_ = WAITING_FOR_RESPONSE;
-  window_->ConfirmBrowserCloseWithPendingDownloads();
+  window_->ConfirmBrowserCloseWithPendingDownloads(
+      num_downloads_blocking,
+      dialog_type,
+      false,
+      base::Bind(&Browser::InProgressDownloadResponse,
+                 weak_factory_.GetWeakPtr()));
 
   // Return false so the browser does not close.  We'll close if the user
   // confirms in the dialog.
@@ -2064,7 +2085,7 @@
       set_delegate(delegate);
   BookmarkTabHelper::FromWebContents(web_contents)->set_delegate(delegate);
   WebContentsModalDialogManager::FromWebContents(web_contents)->
-      set_delegate(delegate);
+      SetDelegate(delegate);
   CoreTabHelper::FromWebContents(web_contents)->set_delegate(delegate);
   SearchEngineTabHelper::FromWebContents(web_contents)->set_delegate(delegate);
   ZoomController::FromWebContents(web_contents)->set_observer(delegate);
@@ -2181,10 +2202,13 @@
   return window_ && window_->ShouldHideUIForFullscreen();
 }
 
-bool Browser::MaybeCreateBackgroundContents(int route_id,
-                                            WebContents* opener_web_contents,
-                                            const string16& frame_name,
-                                            const GURL& target_url) {
+bool Browser::MaybeCreateBackgroundContents(
+    int route_id,
+    WebContents* opener_web_contents,
+    const string16& frame_name,
+    const GURL& target_url,
+    const std::string& partition_id,
+    content::SessionStorageNamespace* session_storage_namespace) {
   GURL opener_url = opener_web_contents->GetURL();
   ExtensionService* extensions_service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
@@ -2247,7 +2271,9 @@
                                         route_id,
                                         profile_,
                                         frame_name,
-                                        ASCIIToUTF16(extension->id()));
+                                        ASCIIToUTF16(extension->id()),
+                                        partition_id,
+                                        session_storage_namespace);
 
   // When a separate process is used, the original renderer cannot access the
   // new window later, thus we need to navigate the window now.
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 22e7fb0..7710549 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -239,6 +239,11 @@
   BrowserWindow* window() const { return window_; }
   ToolbarModel* toolbar_model() { return toolbar_model_.get(); }
   const ToolbarModel* toolbar_model() const { return toolbar_model_.get(); }
+#if defined(UNIT_TEST)
+  void swap_toolbar_models(scoped_ptr<ToolbarModel>* toolbar_model) {
+    toolbar_model->swap(toolbar_model_);
+  }
+#endif
   TabStripModel* tab_strip_model() const { return tab_strip_model_.get(); }
   chrome::BrowserCommandController* command_controller() {
     return command_controller_.get();
@@ -288,9 +293,28 @@
 
   // OnBeforeUnload handling //////////////////////////////////////////////////
 
-  // Gives beforeunload handlers the chance to cancel the close.
+  // Gives beforeunload handlers the chance to cancel the close. Returns whether
+  // to proceed with the close. If called while the process begun by
+  // CallBeforeUnloadHandlers is in progress, returns false without taking
+  // action.
   bool ShouldCloseWindow();
 
+  // Begins the process of confirming whether the associated browser can be
+  // closed. If there are no tabs with beforeunload handlers it will immediately
+  // return false. Otherwise, it starts prompting the user, returns true and
+  // will call |on_close_confirmed| with the result of the user's decision.
+  // After calling this function, if the window will not be closed, call
+  // ResetBeforeUnloadHandlers() to reset all beforeunload handlers; calling
+  // this function multiple times without an intervening call to
+  // ResetBeforeUnloadHandlers() will run only the beforeunload handlers
+  // registered since the previous call.
+  bool CallBeforeUnloadHandlers(
+      const base::Callback<void(bool)>& on_close_confirmed);
+
+  // Clears the results of any beforeunload confirmation dialogs triggered by a
+  // CallBeforeUnloadHandlers call.
+  void ResetBeforeUnloadHandlers();
+
   // Figure out if there are tabs that have beforeunload handlers.
   // It starts beforeunload/unload processing as a side-effect.
   bool TabsNeedBeforeUnloadFired();
@@ -572,11 +596,8 @@
       WindowContainerType window_container_type,
       const string16& frame_name,
       const GURL& target_url,
-      const content::Referrer& referrer,
-      WindowOpenDisposition disposition,
-      const WebKit::WebWindowFeatures& features,
-      bool user_action,
-      bool opener_suppressed) OVERRIDE;
+      const std::string& partition_id,
+      content::SessionStorageNamespace* session_storage_namespace) OVERRIDE;
   virtual void WebContentsCreated(content::WebContents* source_contents,
                                   int64 source_frame_id,
                                   const string16& frame_name,
@@ -780,10 +801,13 @@
 
   // Creates a BackgroundContents if appropriate; return true if one was
   // created.
-  bool MaybeCreateBackgroundContents(int route_id,
-                                     content::WebContents* opener_web_contents,
-                                     const string16& frame_name,
-                                     const GURL& target_url);
+  bool MaybeCreateBackgroundContents(
+      int route_id,
+      content::WebContents* opener_web_contents,
+      const string16& frame_name,
+      const GURL& target_url,
+      const std::string& partition_id,
+      content::SessionStorageNamespace* session_storage_namespace);
 
   // Data members /////////////////////////////////////////////////////////////
 
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 0d58d60..e176b52 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 7429d58..16d4f41 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/avatar_menu_model.h"
 #include "chrome/browser/profiles/profile.h"
@@ -46,7 +47,7 @@
 #if defined(OS_WIN)
 #include "base/win/metro.h"
 #include "base/win/windows_version.h"
-#include "chrome/browser/ui/extensions/apps_metro_handler_win.h"
+#include "chrome/browser/ui/apps/apps_metro_handler_win.h"
 #endif
 
 #if defined(USE_ASH)
@@ -234,14 +235,15 @@
     return false;
 
 #if defined(OS_CHROMEOS)
-  // On Chrome OS, the top row of keys are mapped to F1-F10.  We don't want web
-  // pages to be able to change the behavior of these keys.  Ash handles F4 and
-  // up; this leaves us needing to reserve F1-F3 here.
+  // On Chrome OS, the top row of keys are mapped to browser actions like
+  // back/forward or refresh. We don't want web pages to be able to change the
+  // behavior of these keys.  Ash handles F4 and up; this leaves us needing to
+  // reserve browser back/forward and refresh here.
   ui::KeyboardCode key_code =
     static_cast<ui::KeyboardCode>(event.windowsKeyCode);
-  if ((key_code == ui::VKEY_F1 && command_id == IDC_BACK) ||
-      (key_code == ui::VKEY_F2 && command_id == IDC_FORWARD) ||
-      (key_code == ui::VKEY_F3 && command_id == IDC_RELOAD)) {
+  if ((key_code == ui::VKEY_BROWSER_BACK && command_id == IDC_BACK) ||
+      (key_code == ui::VKEY_BROWSER_FORWARD && command_id == IDC_FORWARD) ||
+      (key_code == ui::VKEY_BROWSER_REFRESH && command_id == IDC_RELOAD)) {
     return true;
   }
 #endif
@@ -448,7 +450,7 @@
       content::RecordAction(content::UserMetricsAction("Win8DesktopRestart"));
       break;
     case IDC_WIN8_METRO_RESTART:
-      if (!chrome::VerifySwitchToMetroForApps(window()->GetNativeWindow()))
+      if (!VerifySwitchToMetroForApps(window()->GetNativeWindow()))
         break;
 
       // SwitchToMetroUIHandler deletes itself.
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc
index b9e5516..ccd98cf 100644
--- a/chrome/browser/ui/browser_command_controller_unittest.cc
+++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -27,14 +27,14 @@
 #if defined(OS_CHROMEOS)
   // F1-3 keys are reserved Chrome accelerators on Chrome OS.
   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
-      IDC_BACK, content::NativeWebKeyboardEvent(ui::ET_KEY_PRESSED, false,
-                                                ui::VKEY_F1, 0, 0)));
+      IDC_BACK, content::NativeWebKeyboardEvent(
+          ui::ET_KEY_PRESSED, false, ui::VKEY_BROWSER_BACK, 0, 0)));
   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
-      IDC_FORWARD, content::NativeWebKeyboardEvent(ui::ET_KEY_PRESSED, false,
-                                                   ui::VKEY_F2, 0, 0)));
+      IDC_FORWARD, content::NativeWebKeyboardEvent(
+          ui::ET_KEY_PRESSED, false, ui::VKEY_BROWSER_FORWARD, 0, 0)));
   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
-      IDC_RELOAD, content::NativeWebKeyboardEvent(ui::ET_KEY_PRESSED, false,
-                                                  ui::VKEY_F3, 0, 0)));
+      IDC_RELOAD, content::NativeWebKeyboardEvent(
+          ui::ET_KEY_PRESSED, false, ui::VKEY_BROWSER_REFRESH, 0, 0)));
 
   // When there are modifier keys pressed, don't reserve.
   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
@@ -293,16 +293,17 @@
 
   // Set up a profile with an off the record profile.
   TestingProfile::Builder builder;
-  TestingProfile* profile2 = builder.Build().release();
-  profile2->set_incognito(true);
+  builder.SetIncognito();
+  scoped_ptr<TestingProfile> profile2(builder.Build());
   TestingProfile::Builder builder2;
   TestingProfile* profile1 = builder2.Build().release();
   profile2->SetOriginalProfile(profile1);
   EXPECT_EQ(profile2->GetOriginalProfile(), profile1);
-  profile1->SetOffTheRecordProfile(profile2);
+  profile1->SetOffTheRecordProfile(profile2.PassAs<Profile>());
 
   // Create a new browser based on the off the record profile.
-  Browser::CreateParams profile_params(profile2, chrome::GetActiveDesktop());
+  Browser::CreateParams profile_params(profile1->GetOffTheRecordProfile(),
+                                       chrome::GetActiveDesktop());
   scoped_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile_params));
 
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 990693e..02a5e8f 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -332,6 +332,9 @@
     if (params.should_set_opener)
       create_params.opener = params.source_contents;
   }
+  if (params.disposition == NEW_BACKGROUND_TAB)
+    create_params.initially_hidden = true;
+
 #if defined(USE_AURA)
   if (params.browser->window() &&
       params.browser->window()->GetNativeWindow()) {
@@ -348,14 +351,6 @@
   BrowserNavigatorWebContentsAdoption::AttachTabHelpers(target_contents);
   extensions::TabHelper::FromWebContents(target_contents)->
       SetExtensionAppById(params.extension_app_id);
-  // TODO(sky): Figure out why this is needed. Without it we seem to get
-  // failures in startup tests.
-  // By default, content believes it is not hidden.  When adding contents
-  // in the background, tell it that it's hidden.
-  if ((params.tabstrip_add_types & TabStripModel::ADD_ACTIVE) == 0) {
-    // TabStripModel::AddWebContents invokes WasHidden if not foreground.
-    target_contents->WasHidden();
-  }
   return target_contents;
 }
 
diff --git a/chrome/browser/ui/browser_tab_contents.cc b/chrome/browser/ui/browser_tab_contents.cc
index 032f107..56b4433 100644
--- a/chrome/browser/ui/browser_tab_contents.cc
+++ b/chrome/browser/ui/browser_tab_contents.cc
@@ -139,12 +139,10 @@
       web_contents, PasswordManagerDelegateImpl::FromWebContents(web_contents));
   PDFTabHelper::CreateForWebContents(web_contents);
   PluginObserver::CreateForWebContents(web_contents);
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableBetterPopupBlocking)) {
-    PopupBlockerTabHelper::CreateForWebContents(web_contents);
-  }
+  PopupBlockerTabHelper::CreateForWebContents(web_contents);
   PrefsTabHelper::CreateForWebContents(web_contents);
-  prerender::PrerenderTabHelper::CreateForWebContents(web_contents);
+  prerender::PrerenderTabHelper::CreateForWebContentsWithPasswordManager(
+      web_contents, PasswordManager::FromWebContents(web_contents));
   SadTabHelper::CreateForWebContents(web_contents);
   safe_browsing::SafeBrowsingTabObserver::CreateForWebContents(web_contents);
   SearchEngineTabHelper::CreateForWebContents(web_contents);
@@ -183,7 +181,8 @@
                                      OneClickSigninHelper::CAN_OFFER_FOR_ALL,
                                      std::string(),
                                      NULL)) {
-    OneClickSigninHelper::CreateForWebContents(web_contents);
+    OneClickSigninHelper::CreateForWebContentsWithPasswordManager(
+        web_contents, PasswordManager::FromWebContents(web_contents));
   }
 #endif
 
diff --git a/chrome/browser/ui/browser_tabstrip.cc b/chrome/browser/ui/browser_tabstrip.cc
index e5572b5..52da4ad 100644
--- a/chrome/browser/ui/browser_tabstrip.cc
+++ b/chrome/browser/ui/browser_tabstrip.cc
@@ -72,22 +72,6 @@
       return;
     }
 
-    // Handle blocking of popups.
-    if ((disposition == NEW_POPUP || disposition == NEW_FOREGROUND_TAB ||
-         disposition == NEW_BACKGROUND_TAB) && !user_gesture &&
-        !CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisablePopupBlocking) &&
-        CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableBetterPopupBlocking)) {
-      // Unrequested popups from normal pages are constrained unless they're in
-      // the white list.  The popup owner will handle checking this.
-      source_blocked_content->AddPopup(
-          new_contents, disposition, initial_pos, user_gesture);
-      if (was_blocked)
-        *was_blocked = true;
-      return;
-    }
-
     new_contents->GetRenderViewHost()->DisassociateFromPopupCount();
   }
 
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index ac21b8f..ad1259d 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -6,8 +6,9 @@
 #define CHROME_BROWSER_UI_BROWSER_WINDOW_H_
 
 #include "base/callback_forward.h"
-#include "chrome/browser/lifetime/application_lifetime.h"
+#include "chrome/browser/lifetime/browser_close_manager.h"
 #include "chrome/browser/ui/bookmarks/bookmark_bar.h"
+#include "chrome/browser/ui/browser.h"
 #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"
@@ -151,8 +152,7 @@
   virtual void UpdateReloadStopState(bool is_loading, bool force) = 0;
 
   // Updates the toolbar with the state for the specified |contents|.
-  virtual void UpdateToolbar(content::WebContents* contents,
-                             bool should_restore_state) = 0;
+  virtual void UpdateToolbar(content::WebContents* contents) = 0;
 
   // Focuses the toolbar (for accessibility).
   virtual void FocusToolbar() = 0;
@@ -244,9 +244,12 @@
 
   // Shows the confirmation dialog box warning that the browser is closing with
   // in-progress downloads.
-  // This method should call Browser::InProgressDownloadResponse once the user
-  // has confirmed.
-  virtual void ConfirmBrowserCloseWithPendingDownloads() = 0;
+  // This method should call |callback| with the user's response.
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) = 0;
 
   // ThemeService calls this when a user has changed his or her theme,
   // indicating that it's time to redraw everything.
@@ -360,7 +363,7 @@
   virtual void OverscrollUpdate(int delta_y) {}
 
  protected:
-  friend void chrome::CloseAllBrowsers();
+  friend class BrowserCloseManager;
   friend class BrowserView;
   virtual void DestroyBrowser() = 0;
 };
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
index 02a18ef..89182fa 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
@@ -111,6 +111,7 @@
   virtual bool IsDetached() const OVERRIDE;
   virtual void UpdateWindowIcon() OVERRIDE;
   virtual void UpdateWindowTitle() OVERRIDE;
+  virtual void UpdateInputRegion(scoped_ptr<SkRegion> region) OVERRIDE;
   virtual void UpdateDraggableRegions(
       const std::vector<extensions::DraggableRegion>& regions) OVERRIDE;
   virtual void HandleKeyboardEvent(
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
index 4a05067..4904243 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
@@ -530,6 +530,10 @@
   [window() setTitle:base::SysUTF16ToNSString(title)];
 }
 
+void NativeAppWindowCocoa::UpdateInputRegion(scoped_ptr<SkRegion> region) {
+  NOTIMPLEMENTED();
+}
+
 void NativeAppWindowCocoa::UpdateDraggableRegions(
     const std::vector<extensions::DraggableRegion>& regions) {
   // Draggable region is not supported for non-frameless window.
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
index cff4275..1e8c4c5 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.h
@@ -40,6 +40,8 @@
   // AutofillDialogView implementation:
   virtual void Show() OVERRIDE;
   virtual void Hide() OVERRIDE;
+  virtual void UpdatesStarted() OVERRIDE;
+  virtual void UpdatesFinished() OVERRIDE;
   virtual void UpdateAccountChooser() OVERRIDE;
   virtual void UpdateButtonStrip() OVERRIDE;
   virtual void UpdateDetailArea() OVERRIDE;
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
index 292af78..306ba33 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
@@ -80,6 +80,14 @@
   constrained_window_->CloseWebContentsModalDialog();
 }
 
+void AutofillDialogCocoa::UpdatesStarted() {
+  // TODO(estade): implement if it makes sense to.
+}
+
+void AutofillDialogCocoa::UpdatesFinished() {
+  // TODO(estade): implement if it makes sense to.
+}
+
 void AutofillDialogCocoa::UpdateAccountChooser() {
   [sheet_delegate_ updateAccountChooser];
 }
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm
index 8d27f8b..b3bda61 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_suggestion_container.mm
@@ -140,7 +140,9 @@
   lineFrame.size = [self preferredSizeForFirstLine];
   lineFrame.origin.x = NSMinX(bounds);
   lineFrame.origin.y = preferredContainerSize.height - NSHeight(lineFrame);
-  DCHECK_LE(NSWidth(lineFrame), NSWidth(bounds));
+
+  // Ensure text does not exceed the view width.
+  lineFrame.size.width = std::min(NSWidth(lineFrame), NSWidth(bounds));
 
   // Layout the controls - two lines on two rows, left-aligned. The optional
   // textfield is on the first line, right-aligned. The icon is also on the
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
index 3a7cef4..c530a23 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_toolbar_view.mm
@@ -46,9 +46,10 @@
       [controller_ isAnimatingFromState:BookmarkBar::DETACHED]) {
     [self drawAsDetachedBubble];
   } else {
-    NSPoint phase = [[self window]
-        themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
-    [[NSGraphicsContext currentContext] cr_setPatternPhase:phase forView:self];
+    NSPoint position = [[self window]
+        themeImagePositionForAlignment:THEME_IMAGE_ALIGN_WITH_TAB_STRIP];
+    [[NSGraphicsContext currentContext] cr_setPatternPhase:position
+                                                   forView:self];
     [self drawBackgroundWithOpaque:YES];
   }
 }
@@ -77,9 +78,9 @@
     CGContextRef cgContext = static_cast<CGContextRef>([context graphicsPort]);
     CGContextSetAlpha(cgContext, 1 - morph);
     CGContextBeginTransparencyLayer(cgContext, NULL);
-    NSPoint phase = [[self window]
-        themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
-    [context cr_setPatternPhase:phase forView:self];
+    NSPoint position = [[self window]
+        themeImagePositionForAlignment:THEME_IMAGE_ALIGN_WITH_TAB_STRIP];
+    [context cr_setPatternPhase:position forView:self];
     [self drawBackgroundWithOpaque:YES];
     CGContextEndTransparencyLayer(cgContext);
   }
diff --git a/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
index 43b7c3b..f7c9dda 100644
--- a/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser/avatar_button_controller_unittest.mm
@@ -5,6 +5,8 @@
 #import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
 
 #include "base/mac/scoped_nsobject.h"
+#include "chrome/browser/managed_mode/managed_user_service.h"
+#include "chrome/browser/managed_mode/managed_user_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser/avatar_menu_bubble_controller.h"
@@ -85,7 +87,7 @@
   EXPECT_FALSE([controller() labelButtonView]);
 
   // Transform the first profile to a managed user profile.
-  profile()->GetPrefs()->SetBoolean(prefs::kProfileIsManaged, true);
+  ManagedUserServiceFactory::GetForProfile(profile())->InitForTesting();
 
   // Build a new controller to check if it is initialized correctly for a
   // managed user profile.
diff --git a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
index d1378da..3880b11 100644
--- a/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/browser/zoom_bubble_controller.mm
@@ -82,6 +82,7 @@
   if ((self = [super initWithWindow:window
                        parentWindow:parentWindow
                          anchoredAt:NSZeroPoint])) {
+    [window setCanBecomeKeyWindow:NO];
     closeObserver_.reset(Block_copy(closeObserver));
 
     ui::NativeTheme* nativeTheme = ui::NativeTheme::instance();
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index d060c02..334d273 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -79,8 +79,7 @@
   virtual LocationBar* GetLocationBar() const OVERRIDE;
   virtual void SetFocusToLocationBar(bool select_all) OVERRIDE;
   virtual void UpdateReloadStopState(bool is_loading, bool force) OVERRIDE;
-  virtual void UpdateToolbar(content::WebContents* contents,
-                             bool should_restore_state) OVERRIDE;
+  virtual void UpdateToolbar(content::WebContents* contents) OVERRIDE;
   virtual void FocusToolbar() OVERRIDE;
   virtual void FocusAppMenu() OVERRIDE;
   virtual void FocusBookmarksToolbar() OVERRIDE;
@@ -106,7 +105,11 @@
 #endif
   virtual bool IsDownloadShelfVisible() const OVERRIDE;
   virtual DownloadShelf* GetDownloadShelf() OVERRIDE;
-  virtual void ConfirmBrowserCloseWithPendingDownloads() OVERRIDE;
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) OVERRIDE;
   virtual void UserChangedTheme() OVERRIDE;
   virtual int GetExtraRenderViewHeight() const OVERRIDE;
   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
@@ -165,7 +168,6 @@
 
   Browser* browser_;  // weak, owned by controller
   BrowserWindowController* controller_;  // weak, owns us
-  base::WeakPtrFactory<Browser> confirm_close_factory_;
   base::scoped_nsobject<NSString> pending_window_title_;
   ui::WindowShowState initial_show_state_;
   NSInteger attention_request_id_;  // identifier from requestUserAttention
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 56e8bc8..6b7e00b 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -118,7 +118,6 @@
                                        BrowserWindowController* controller)
   : browser_(browser),
     controller_(controller),
-    confirm_close_factory_(browser),
     initial_show_state_(ui::SHOW_STATE_DEFAULT),
     attention_request_id_(0) {
 
@@ -424,10 +423,8 @@
   [controller_ setIsLoading:is_loading force:force];
 }
 
-void BrowserWindowCocoa::UpdateToolbar(content::WebContents* contents,
-                                       bool should_restore_state) {
-  [controller_ updateToolbarWithContents:contents
-                      shouldRestoreState:should_restore_state ? YES : NO];
+void BrowserWindowCocoa::UpdateToolbar(content::WebContents* contents) {
+  [controller_ updateToolbarWithContents:contents];
 }
 
 void BrowserWindowCocoa::FocusToolbar() {
@@ -532,12 +529,12 @@
 
 // We allow closing the window here since the real quit decision on Mac is made
 // in [AppController quit:].
-void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads() {
-  // Call InProgressDownloadResponse asynchronously to avoid a crash when the
-  // browser window is closed here (http://crbug.com/44454).
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-      base::Bind(&Browser::InProgressDownloadResponse,
-                 confirm_close_factory_.GetWeakPtr(), true));
+void BrowserWindowCocoa::ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) {
+  callback.Run(true);
 }
 
 void BrowserWindowCocoa::UserChangedTheme() {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index abebc77..e117b06 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -33,6 +33,7 @@
 @class DownloadShelfController;
 class ExtensionKeybindingRegistryCocoa;
 @class FindBarCocoaController;
+@class FullscreenModeController;
 @class FullscreenWindow;
 @class InfoBarContainerController;
 class LocationBarViewMac;
@@ -71,6 +72,7 @@
   base::scoped_nsobject<OverlayableContentsController>
       overlayableContentsController_;
   base::scoped_nsobject<PresentationModeController> presentationModeController_;
+  base::scoped_nsobject<FullscreenModeController> fullscreenModeController_;
   base::scoped_nsobject<FullscreenExitBubbleController>
       fullscreenExitBubbleController_;
 
@@ -222,12 +224,10 @@
 // Access the avatar button controller.
 - (AvatarButtonController*)avatarButtonController;
 
-// Updates the toolbar (and transitively the location bar) with the states of
-// the specified |tab|.  If |shouldRestore| is true, we're switching
-// (back?) to this tab and should restore any previous location bar state
-// (such as user editing) as well.
-- (void)updateToolbarWithContents:(content::WebContents*)tab
-               shouldRestoreState:(BOOL)shouldRestore;
+// Forces the toolbar (and transitively the location bar) to update its current
+// state.  If |tab| is non-NULL, we're switching (back?) to this tab and should
+// restore any previous location bar state (such as user editing) as well.
+- (void)updateToolbarWithContents:(content::WebContents*)tab;
 
 // Sets whether or not the current page in the frontmost tab is bookmarked.
 - (void)setStarredState:(BOOL)isStarred;
@@ -311,9 +311,13 @@
 // Gets the window style.
 - (ThemedWindowStyle)themedWindowStyle;
 
-// Returns the pattern phase for |alignment|. If the window does not have a tab
-// strip, the phase for THEME_PATTERN_ALIGN_WITH_FRAME is always returned.
-- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment;
+// Returns the position in the coordinates of the root view
+// ([[self contentView] superview]) that the top left of a theme image with
+// |alignment| should be painted at. If the window does not have a tab strip,
+// the offset for THEME_IMAGE_ALIGN_WITH_FRAME is always returned. The result of
+// this method can be used in conjunction with
+// [NSGraphicsContext cr_setPatternPhase:] to set the offset of pattern colors.
+- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment;
 
 // Return the point to which a bubble window's arrow should point, in window
 // coordinates.
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 75a97b8..7717c7e 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -361,11 +361,10 @@
     // registering for the appropriate command state changes from the back-end.
     // Adds the toolbar to the content area.
     toolbarController_.reset([[ToolbarController alloc]
-              initWithModel:browser->toolbar_model()
-                   commands:browser->command_controller()->command_updater()
-                    profile:browser->profile()
-                    browser:browser
-             resizeDelegate:self]);
+              initWithCommands:browser->command_controller()->command_updater()
+                       profile:browser->profile()
+                       browser:browser
+                resizeDelegate:self]);
     [toolbarController_ setHasToolbar:[self hasToolbar]
                        hasLocationBar:[self hasLocationBar]];
 
@@ -1249,10 +1248,8 @@
   return [view convertRect:[view bounds] toView:nil];
 }
 
-- (void)updateToolbarWithContents:(WebContents*)tab
-               shouldRestoreState:(BOOL)shouldRestore {
-  [toolbarController_ updateToolbarWithContents:tab
-                             shouldRestoreState:shouldRestore];
+- (void)updateToolbarWithContents:(WebContents*)tab {
+  [toolbarController_ updateToolbarWithContents:tab];
 }
 
 - (void)setStarredState:(BOOL)isStarred {
@@ -1658,13 +1655,14 @@
   return style;
 }
 
-- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
+- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
   NSView* windowChromeView = [[[self window] contentView] superview];
   NSView* tabStripView = nil;
-  if (alignment == THEME_PATTERN_ALIGN_WITH_TAB_STRIP && [self hasTabStrip])
+  if ([self hasTabStrip])
     tabStripView = [self tabStripView];
-  return [BrowserWindowUtils themePatternPhaseFor:windowChromeView
-                                     withTabStrip:tabStripView];
+  return [BrowserWindowUtils themeImagePositionFor:windowChromeView
+                                      withTabStrip:tabStripView
+                                         alignment:alignment];
 }
 
 - (NSPoint)bookmarkBubblePoint {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
index ca1940b..3e9a785 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_tabstrip.cc"
 #include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/browser/avatar_button_controller.h"
 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 55cb3f7..f2238d3 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -23,6 +23,7 @@
 #import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h"
 #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
+#import "chrome/browser/ui/cocoa/fullscreen_mode_controller.h"
 #import "chrome/browser/ui/cocoa/fullscreen_window.h"
 #import "chrome/browser/ui/cocoa/infobars/infobar_container_controller.h"
 #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
@@ -181,6 +182,9 @@
   CGFloat minY = NSMinY(contentBounds);
   CGFloat width = NSWidth(contentBounds);
 
+  BOOL useSimplifiedFullscreen = CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableSimplifiedFullscreen);
+
   // Suppress title drawing if necessary.
   if ([window respondsToSelector:@selector(setShouldHideTitle:)])
     [(id)window setShouldHideTitle:![self hasTitleBar]];
@@ -192,7 +196,7 @@
   CGFloat floatingBarHeight = [self floatingBarHeight];
   // In presentation mode, |yOffset| accounts for the sliding position of the
   // floating bar and the extra offset needed to dodge the menu bar.
-  CGFloat yOffset = inPresentationMode ?
+  CGFloat yOffset = inPresentationMode && !useSimplifiedFullscreen ?
       (std::floor((1 - floatingBarShownFraction_) * floatingBarHeight) -
           [presentationModeController_ floatingBarVerticalOffset]) : 0;
   CGFloat maxY = NSMaxY(contentBounds) + yOffset;
@@ -202,6 +206,17 @@
     // value, and then lay out the tab strip.
     NSRect windowFrame = [contentView convertRect:[window frame] fromView:nil];
     maxY = NSHeight(windowFrame) + yOffset;
+    if (useSimplifiedFullscreen && [self isFullscreen]) {
+      CGFloat tabStripHeight = NSHeight([[self tabStripView] frame]);
+      CGFloat revealAmount = (1 - floatingBarShownFraction_) * tabStripHeight;
+      // In simplified fullscreen, only the toolbar is visible by default, and
+      // the tabstrip and menu bar come down (each separately) when the user
+      // mouses near the top of the window. Push the maxY of the toolbar up by
+      // the amount of the tabstrip that is revealed, while removing the amount
+      // of space needed by the menu bar.
+      maxY += std::floor(
+          revealAmount - [fullscreenModeController_ menuBarHeight]);
+    }
     maxY = [self layoutTabStripAtMaxY:maxY
                                 width:width
                            fullscreen:[self isFullscreen]];
@@ -234,8 +249,6 @@
 
   // If in presentation mode, reset |maxY| to top of screen, so that the
   // floating bar slides over the things which appear to be in the content area.
-  BOOL useSimplifiedFullscreen = CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableSimplifiedFullscreen);
   if (inPresentationMode ||
       (useSimplifiedFullscreen && !fullscreenUrl_.is_empty())) {
     maxY = NSMaxY(contentBounds);
@@ -805,6 +818,14 @@
     [self deregisterForContentViewResizeNotifications];
   enteringFullscreen_ = NO;
   enteringPresentationMode_ = NO;
+
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableSimplifiedFullscreen) &&
+      fullscreenUrl_.is_empty()) {
+    fullscreenModeController_.reset([[FullscreenModeController alloc]
+        initWithBrowserWindowController:self]);
+  }
+
   [self showFullscreenExitBubbleIfNecessary];
   browser_->WindowFullscreenStateChanged();
 }
@@ -812,6 +833,7 @@
 - (void)windowWillExitFullScreen:(NSNotification*)notification {
   if (chrome::mac::SupportsSystemFullscreen())
     [self registerForContentViewResizeNotifications];
+  fullscreenModeController_.reset();
   [self destroyFullscreenExitBubbleIfNecessary];
   [self setPresentationModeInternal:NO forceDropdown:NO];
 }
diff --git a/chrome/browser/ui/cocoa/browser_window_utils.h b/chrome/browser/ui/cocoa/browser_window_utils.h
index b28d50d..0a13738 100644
--- a/chrome/browser/ui/cocoa/browser_window_utils.h
+++ b/chrome/browser/ui/cocoa/browser_window_utils.h
@@ -7,6 +7,8 @@
 
 #import <Cocoa/Cocoa.h>
 
+#include "chrome/browser/ui/cocoa/themed_window.h"
+
 class Browser;
 
 namespace content {
@@ -37,8 +39,19 @@
                         withNewTitle:(NSString*)newTitle
                            forWindow:(NSWindow*)window;
 
-+ (NSPoint)themePatternPhaseFor:(NSView*)windowView
-                   withTabStrip:(NSView*)tabStripView;
+// Returns the position in the coordinates of |windowView| that the top left of
+// a theme image should be painted at. See
+// [BrowserWindowController themeImagePositionForAlignment:] for more details.
++ (NSPoint)themeImagePositionFor:(NSView*)windowView
+                    withTabStrip:(NSView*)tabStripView
+                       alignment:(ThemeImageAlignment)alignment;
+
+// Returns the position in the coordinates of |tabStripView| that the top left
+// of a theme image should be painted at. This method exists so that the
+// position can be queried by the new tab button before the tab strip is layed
+// out.
++ (NSPoint)themeImagePositionInTabStripCoords:(NSView*)tabStripView
+                                    alignment:(ThemeImageAlignment)alignment;
 
 + (void)activateWindowForController:(NSWindowController*)controller;
 @end
diff --git a/chrome/browser/ui/cocoa/browser_window_utils.mm b/chrome/browser/ui/cocoa/browser_window_utils.mm
index de2e3d6..83c73b5 100644
--- a/chrome/browser/ui/cocoa/browser_window_utils.mm
+++ b/chrome/browser/ui/cocoa/browser_window_utils.mm
@@ -145,39 +145,57 @@
   return [newTitle copy];
 }
 
-// Our patterns want to be drawn from the upper left hand corner of the view.
-// Cocoa wants to do it from the lower left of the window.
+// The titlebar/tabstrip header on the mac is slightly smaller than on Windows.
+// There is also no window frame to the left and right of the web contents on
+// mac.
+// To keep:
+// - the window background pattern (IDR_THEME_FRAME.*) lined up vertically with
+// the tab and toolbar patterns
+// - the toolbar pattern lined up horizontally with the NTP background.
+// we have to shift the pattern slightly, rather than drawing from the top left
+// corner of the frame / tabstrip. The offsets below were empirically determined
+// in order to line these patterns up.
 //
-// Rephase our pattern to fit this view. Some other views (Tabs, Toolbar etc.)
-// will phase their patterns relative to this so all the views look right.
-//
-// To line up the background pattern with the pattern in the browser window
-// the background pattern for the tabs needs to be moved left by 5 pixels.
+// This will make the themes look slightly different than in Windows/Linux
+// because of the differing heights between window top and tab top, but this has
+// been approved by UI.
 const CGFloat kPatternHorizontalOffset = -5;
-// To match Windows and CrOS, have to offset vertically by 2 pixels.
 // Without tab strip, offset an extra pixel (determined by experimentation).
 const CGFloat kPatternVerticalOffset = 2;
 const CGFloat kPatternVerticalOffsetNoTabStrip = 3;
 
-
-+ (NSPoint)themePatternPhaseFor:(NSView*)windowView
-                   withTabStrip:(NSView*)tabStripView {
-  // When we have a tab strip, line up with the top of the tab, otherwise,
-  // line up with the top of the window.
-  if (!tabStripView)
++ (NSPoint)themeImagePositionFor:(NSView*)windowView
+                    withTabStrip:(NSView*)tabStripView
+                       alignment:(ThemeImageAlignment)alignment {
+  if (!tabStripView) {
     return NSMakePoint(kPatternHorizontalOffset,
-                       NSHeight([windowView bounds])
-                       + kPatternVerticalOffsetNoTabStrip);
+                       NSHeight([windowView bounds]) +
+                           kPatternVerticalOffsetNoTabStrip);
+  }
 
-  NSRect tabStripViewWindowBounds = [tabStripView bounds];
-  tabStripViewWindowBounds =
-      [tabStripView convertRect:tabStripViewWindowBounds
-                         toView:windowView];
-  return NSMakePoint(NSMinX(tabStripViewWindowBounds)
-                         + kPatternHorizontalOffset,
-                     NSMinY(tabStripViewWindowBounds)
-                         + [TabStripController defaultTabHeight]
-                         + kPatternVerticalOffset);
+  NSPoint position =
+      [BrowserWindowUtils themeImagePositionInTabStripCoords:tabStripView
+                                                   alignment:alignment];
+  return [tabStripView convertPoint:position toView:windowView];
+}
+
++ (NSPoint)themeImagePositionInTabStripCoords:(NSView*)tabStripView
+                                    alignment:(ThemeImageAlignment)alignment {
+  DCHECK(tabStripView);
+
+  if (alignment == THEME_IMAGE_ALIGN_WITH_TAB_STRIP) {
+    // The theme image is lined up with the top of the tab which is below the
+    // top of the tab strip.
+    return NSMakePoint(kPatternHorizontalOffset,
+                       [TabStripController defaultTabHeight] +
+                           kPatternVerticalOffset);
+  }
+  // The theme image is lined up with the top of the tab strip (as opposed to
+  // the top of the tab above). This is the same as lining up with the top of
+  // the window's root view when not in presentation mode.
+  return NSMakePoint(kPatternHorizontalOffset,
+                     NSHeight([tabStripView bounds]) +
+                         kPatternVerticalOffsetNoTabStrip);
 }
 
 + (void)activateWindowForController:(NSWindowController*)controller {
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.mm b/chrome/browser/ui/cocoa/chrome_browser_window.mm
index 9855072..8aa3743 100644
--- a/chrome/browser/ui/cocoa/chrome_browser_window.mm
+++ b/chrome/browser/ui/cocoa/chrome_browser_window.mm
@@ -24,11 +24,11 @@
   return [delegate themedWindowStyle];
 }
 
-- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
+- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
   id delegate = [self delegate];
-  if (![delegate respondsToSelector:@selector(themePatternPhaseForAlignment:)])
+  if (![delegate respondsToSelector:@selector(themeImagePositionForAlignment:)])
     return NSZeroPoint;
-  return [delegate themePatternPhaseForAlignment:alignment];
+  return [delegate themeImagePositionForAlignment:alignment];
 }
 
 @end
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
index 7900efe..5a53816 100644
--- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
@@ -238,6 +238,7 @@
     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
       nibPath = @"ContentBlockedMIDISysEx"; break;
     // These content types have no bubble:
+    case CONTENT_SETTINGS_TYPE_SAVE_PASSWORD:
     case CONTENT_SETTINGS_TYPE_DEFAULT:
     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
     case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm
index 966acce..749a57a 100644
--- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm
+++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm
@@ -88,6 +88,7 @@
         i == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
         i == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA ||
         i == CONTENT_SETTINGS_TYPE_PPAPI_BROKER ||
+        i == CONTENT_SETTINGS_TYPE_SAVE_PASSWORD ||
         i == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
       // These types have no bubble.
       continue;
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.mm b/chrome/browser/ui/cocoa/download/download_item_cell.mm
index 96c30a0..20ec1a9 100644
--- a/chrome/browser/ui/cocoa/download/download_item_cell.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_cell.mm
@@ -19,6 +19,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/text/text_elider.h"
 #include "ui/gfx/canvas_skia_paint.h"
+#include "ui/gfx/font.h"
 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
 
 // Distance from top border to icon.
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm
index 7aee38c..29ccb02 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_context_menu_browsertest.mm
@@ -55,7 +55,7 @@
         [window->cocoa_controller() toolbarController];
     LocationBarViewMac* locationBarView =
         [toolbarController locationBarBridge];
-    locationBarView->Update(contents, false);
+    locationBarView->Update(NULL);
   }
 
   const Extension* extension_;
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
index 4016bbd..8b87ef3 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm
@@ -19,7 +19,7 @@
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "extensions/common/manifest_constants.h"
 #include "third_party/ocmock/gtest_support.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -44,7 +44,7 @@
 
 @end
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 class ExtensionInstalledBubbleControllerTest : public CocoaProfileTest {
 
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm
index 2668046..4ba2b99 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_view.mm
@@ -70,10 +70,10 @@
     [path addClip];
 
     // Set the pattern phase
-    NSPoint phase = [[self window]
-        themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
+    NSPoint position = [[self window]
+        themeImagePositionForAlignment:THEME_IMAGE_ALIGN_WITH_TAB_STRIP];
+    [context cr_setPatternPhase:position forView:self];
 
-    [context cr_setPatternPhase:phase forView:self];
     [super drawBackgroundWithOpaque:YES];
   }
 
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
index fef660b..7f626f4 100644
--- a/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
+++ b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
@@ -19,11 +19,9 @@
     [[NSColor windowBackgroundColor] set];
   NSRectFill(rect);
 
-  // TODO(rohitrao): Don't assume -22 here.
   [FramedBrowserWindow drawWindowThemeInDirtyRect:rect
                                           forView:self
                                            bounds:[self bounds]
-                                           offset:NSMakePoint(0, -22)
                              forceBlackBackground:YES];
 
 }
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.h b/chrome/browser/ui/cocoa/framed_browser_window.h
index a5750bf..3c9a6ba 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window.h
+++ b/chrome/browser/ui/cocoa/framed_browser_window.h
@@ -57,7 +57,6 @@
 + (BOOL)drawWindowThemeInDirtyRect:(NSRect)dirtyRect
                            forView:(NSView*)view
                             bounds:(NSRect)bounds
-                            offset:(NSPoint)offset
               forceBlackBackground:(BOOL)forceBlackBackground;
 
 // Gets the color to draw title text.
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm
index acf4ca4..6c143c5 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window.mm
+++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
@@ -8,6 +8,7 @@
 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
 #include "chrome/browser/profiles/profile_info_util.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_utils.h"
 #import "chrome/browser/ui/cocoa/custom_frame_view.h"
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
@@ -15,6 +16,7 @@
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "grit/theme_resources.h"
+#include "ui/base/cocoa/nsgraphics_context_additions.h"
 
 // Replicate specific 10.7 SDK declarations for building with prior SDKs.
 #if !defined(MAC_OS_X_VERSION_10_7) || \
@@ -42,7 +44,6 @@
 namespace {
 
 const CGFloat kBrowserFrameViewPaintHeight = 60.0;
-const NSPoint kBrowserFrameViewPatternPhaseOffset = { -5, 3 };
 
 // Size of the gradient. Empirically determined so that the gradient looks
 // like what the heuristic does when there are just a few tabs.
@@ -361,7 +362,6 @@
       drawWindowThemeInDirtyRect:rect
                          forView:view
                           bounds:windowRect
-                          offset:NSZeroPoint
             forceBlackBackground:NO];
 
   // If the window needs a title and we painted over the title as drawn by the
@@ -394,7 +394,6 @@
 + (BOOL)drawWindowThemeInDirtyRect:(NSRect)dirtyRect
                            forView:(NSView*)view
                             bounds:(NSRect)bounds
-                            offset:(NSPoint)offset
               forceBlackBackground:(BOOL)forceBlackBackground {
   ui::ThemeProvider* themeProvider = [[view window] themeProvider];
   if (!themeProvider)
@@ -435,31 +434,6 @@
 
   BOOL themed = NO;
   if (themeImageColor) {
-    // The titlebar/tabstrip header on the mac is slightly smaller than on
-    // Windows.  To keep the window background lined up with the tab and toolbar
-    // patterns, we have to shift the pattern slightly, rather than simply
-    // drawing it from the top left corner.  The offset below was empirically
-    // determined in order to line these patterns up.
-    //
-    // This will make the themes look slightly different than in Windows/Linux
-    // because of the differing heights between window top and tab top, but this
-    // has been approved by UI.
-    NSView* frameView = [[[view window] contentView] superview];
-    NSPoint topLeft = NSMakePoint(NSMinX(bounds), NSMaxY(bounds));
-    NSPoint topLeftInFrameCoordinates =
-        [view convertPoint:topLeft toView:frameView];
-
-    NSPoint phase = kBrowserFrameViewPatternPhaseOffset;
-    phase.x += (offset.x + topLeftInFrameCoordinates.x);
-    phase.y += (offset.y + topLeftInFrameCoordinates.y);
-
-    // Align the phase to physical pixels so resizing the window under HiDPI
-    // doesn't cause wiggling of the theme.
-    phase = [frameView convertPointToBase:phase];
-    phase.x = floor(phase.x);
-    phase.y = floor(phase.y);
-    phase = [frameView convertPointFromBase:phase];
-
     // Default to replacing any existing pixels with the theme image, but if
     // asked paint black first and blend the theme with black.
     NSCompositingOperation operation = NSCompositeCopy;
@@ -469,7 +443,19 @@
       operation = NSCompositeSourceOver;
     }
 
-    [[NSGraphicsContext currentContext] setPatternPhase:phase];
+    NSPoint position = [[view window] themeImagePositionForAlignment:
+        THEME_IMAGE_ALIGN_WITH_FRAME];
+
+    // Align the phase to physical pixels so resizing the window under HiDPI
+    // doesn't cause wiggling of the theme.
+    NSView* frameView = [[[view window] contentView] superview];
+    position = [frameView convertPointToBase:position];
+    position.x = floor(position.x);
+    position.y = floor(position.y);
+    position = [frameView convertPointFromBase:position];
+    [[NSGraphicsContext currentContext] cr_setPatternPhase:position
+                                                   forView:view];
+
     [themeImageColor set];
     NSRectFillUsingOperation(dirtyRect, operation);
     themed = YES;
@@ -492,11 +478,14 @@
 
   if (overlayImage) {
     // Anchor to top-left and don't scale.
+    NSView* frameView = [[[view window] contentView] superview];
+    NSPoint position = [[view window] themeImagePositionForAlignment:
+        THEME_IMAGE_ALIGN_WITH_FRAME];
+    position = [view convertPoint:position fromView:frameView];
     NSSize overlaySize = [overlayImage size];
     NSRect imageFrame = NSMakeRect(0, 0, overlaySize.width, overlaySize.height);
-    [overlayImage drawAtPoint:NSMakePoint(offset.x,
-                                          NSHeight(bounds) + offset.y -
-                                               overlaySize.height)
+    [overlayImage drawAtPoint:NSMakePoint(position.x,
+                                          position.y - overlaySize.height)
                      fromRect:imageFrame
                     operation:NSCompositeSourceOver
                      fraction:1.0];
diff --git a/chrome/browser/ui/cocoa/fullscreen_mode_controller.h b/chrome/browser/ui/cocoa/fullscreen_mode_controller.h
new file mode 100644
index 0000000..c91ae82
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_mode_controller.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 CHROME_BROWSER_UI_COCOA_FULLSCREEN_MODE_CONTROLLER_H_
+#define CHROME_BROWSER_UI_COCOA_FULLSCREEN_MODE_CONTROLLER_H_
+
+#include <Carbon/Carbon.h>
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
+#import "ui/base/cocoa/tracking_area.h"
+
+@class BrowserWindowController;
+
+// This class is responsible for managing the menu bar and tabstrip animation
+// when in --enable-simplified-fullscreen. By default, in fullscreen, only the
+// toolbar and not the tabstrip are visible. When the user mouses near the top
+// of the screen, then the full tabstrip becomes available. If the user mouses
+// to the very top of the screen, the menubar also becomes visible.
+//
+// There is one instance of this class per BrowserWindowController, and it is
+// created when fullscreen is being entered and is destroyed when fullscreen
+// is exited.
+@interface FullscreenModeController : NSObject<NSAnimationDelegate> {
+ @private
+  enum FullscreenToolbarState {
+    kFullscreenToolbarOnly,
+    kFullscreenToolbarAndTabstrip,
+  };
+
+  // The browser for which this is managing fullscreen. Weak, owns self.
+  BrowserWindowController* controller_;
+
+  // The tracking area used to observe the top region of the fullscren window,
+  // to initiate the animations to bring down the tabstrip.
+  ui::ScopedCrTrackingArea trackingArea_;
+
+  // The animation that is either showing or hiding the tabstrip. Nil when no
+  // animation is running.
+  base::scoped_nsobject<NSAnimation> animation_;
+
+  // The current and destination states of |animation_|. When no animation is
+  // running, these values are equal.
+  FullscreenToolbarState destinationState_;
+  FullscreenToolbarState currentState_;
+
+  // A Carbon event handler that tracks the revealed fraction of the menu bar.
+  EventHandlerRef menuBarTrackingHandler_;
+
+  // A fraction in the range [0.0, 1.0] that indicates how much of the
+  // menu bar is visible. Updated via |menuBarTrackingHandler_|.
+  CGFloat menuBarRevealFraction_;
+}
+
+// Designated initializer. Must be called after making the window fullscreen.
+- (id)initWithBrowserWindowController:(BrowserWindowController*)bwc;
+
+// Returns the pixel height of the menu bar, adjusted for fractional visibility.
+- (CGFloat)menuBarHeight;
+
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_FULLSCREEN_MODE_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/fullscreen_mode_controller.mm b/chrome/browser/ui/cocoa/fullscreen_mode_controller.mm
new file mode 100644
index 0000000..c404351
--- /dev/null
+++ b/chrome/browser/ui/cocoa/fullscreen_mode_controller.mm
@@ -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.
+
+#import "chrome/browser/ui/cocoa/fullscreen_mode_controller.h"
+
+#import "chrome/browser/ui/cocoa/browser_window_controller.h"
+#import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
+#import "chrome/browser/ui/cocoa/fast_resize_view.h"
+
+@interface FullscreenModeController (Private)
+- (void)startAnimationToState:(FullscreenToolbarState)state;
+- (void)setMenuBarRevealProgress:(CGFloat)progress;
+- (void)setRevealAnimationProgress:(NSAnimationProgress)progress;
+@end
+
+namespace {
+
+OSStatus MenuBarRevealHandler(EventHandlerCallRef handler,
+                              EventRef event,
+                              void* context) {
+  FullscreenModeController* self =
+      static_cast<FullscreenModeController*>(context);
+  CGFloat revealFraction = 0;
+  GetEventParameter(event, FOUR_CHAR_CODE('rvlf'), typeCGFloat, NULL,
+      sizeof(CGFloat), NULL, &revealFraction);
+  [self setMenuBarRevealProgress:revealFraction];
+  return CallNextEventHandler(handler, event);
+}
+
+// The duration of the animation to bring down the tabstrip.
+const NSTimeInterval kAnimationDuration = 0.35;
+
+// The height of the tracking area in which mouse entered/exit events will
+// reveal the tabstrip.
+const NSUInteger kTrackingAreaHeight = 100;
+
+// There is a tiny gap between the window's max Y and the top of the screen,
+// which will produce a mouse exit event when the menu bar should be revealed.
+// This factor is the size of that gap plus padding.
+const CGFloat kTrackingAreaMaxYEpsilon = 15;
+
+}  // namespace
+
+// Animation ///////////////////////////////////////////////////////////////////
+
+@interface FullscreenModeDropDownAnimation : NSAnimation {
+  FullscreenModeController* controller_;
+}
+@end
+
+@implementation FullscreenModeDropDownAnimation
+
+- (id)initWithFullscreenModeController:(FullscreenModeController*)controller {
+  if ((self = [super initWithDuration:kAnimationDuration
+                       animationCurve:NSAnimationEaseInOut])) {
+    controller_ = controller;
+    [self setAnimationBlockingMode:NSAnimationNonblocking];
+    [self setDelegate:controller_];
+  }
+  return self;
+}
+
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+  [controller_ setRevealAnimationProgress:progress];
+}
+
+@end
+
+// Implementation //////////////////////////////////////////////////////////////
+
+@implementation FullscreenModeController
+
+- (id)initWithBrowserWindowController:(BrowserWindowController*)bwc {
+  if ((self = [super init])) {
+    controller_ = bwc;
+
+    currentState_ = kFullscreenToolbarOnly;
+    destinationState_ = kFullscreenToolbarOnly;
+
+    // Create the tracking area at the top of the window.
+    NSRect windowFrame = [[bwc window] frame];
+    NSRect trackingRect = NSMakeRect(
+        0, NSHeight(windowFrame) - kTrackingAreaHeight,
+        NSWidth(windowFrame), kTrackingAreaHeight);
+    trackingArea_.reset(
+        [[CrTrackingArea alloc] initWithRect:trackingRect
+                                     options:NSTrackingMouseEnteredAndExited |
+                                             NSTrackingActiveAlways
+                                       owner:self
+                                    userInfo:nil]);
+    [[[bwc window] contentView] addTrackingArea:trackingArea_.get()];
+
+    // Install the Carbon event handler for the undocumented menu bar show/hide
+    // event.
+    EventTypeSpec eventSpec = { kEventClassMenu, 2004 };
+    InstallApplicationEventHandler(NewEventHandlerUPP(&MenuBarRevealHandler),
+                                   1, &eventSpec,
+                                   self, &menuBarTrackingHandler_);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  RemoveEventHandler(menuBarTrackingHandler_);
+  [[[controller_ window] contentView] removeTrackingArea:trackingArea_.get()];
+  [super dealloc];
+}
+
+- (CGFloat)menuBarHeight {
+  // -[NSMenu menuBarHeight] will return 0 when the menu bar is hidden, so
+  // use the status bar API instead, which always returns a constant value.
+  return [[NSStatusBar systemStatusBar] thickness] * menuBarRevealFraction_;
+}
+
+- (void)mouseEntered:(NSEvent*)event {
+  if (animation_ || currentState_ == kFullscreenToolbarAndTabstrip)
+    return;
+
+  [self startAnimationToState:kFullscreenToolbarAndTabstrip];
+}
+
+- (void)mouseExited:(NSEvent*)event {
+  if (animation_ || currentState_ == kFullscreenToolbarOnly)
+    return;
+
+  // Take allowance for the small gap between the window max Y and top edge of
+  // the screen.
+  NSPoint mousePoint = [NSEvent mouseLocation];
+  NSRect screenRect = [[[controller_ window] screen] frame];
+  if (mousePoint.y >= NSMaxY(screenRect) - kTrackingAreaMaxYEpsilon)
+    return;
+
+  [self startAnimationToState:kFullscreenToolbarOnly];
+}
+
+- (void)startAnimationToState:(FullscreenToolbarState)state {
+  DCHECK_NE(currentState_, state);
+
+  destinationState_ = state;
+
+  // Turn on fast resize mode to ensure a smooth web contents animation.
+  // TODO(rsesek): This makes the animation jump at the end.
+  [[controller_ tabContentArea] setFastResizeMode:YES];
+
+  animation_.reset([[FullscreenModeDropDownAnimation alloc]
+      initWithFullscreenModeController:self]);
+  [animation_ startAnimation];
+}
+
+- (void)setMenuBarRevealProgress:(CGFloat)progress {
+  menuBarRevealFraction_ = progress;
+
+  // If an animation is not running, then -layoutSubviews will not be called
+  // for each tick of the menu bar reveal. Do that manually.
+  // TODO(rsesek): This is kind of hacky and janky.
+  if (!animation_)
+    [controller_ layoutSubviews];
+}
+
+- (void)setRevealAnimationProgress:(NSAnimationProgress)progress {
+  // When hiding the tabstrip, invert the fraction.
+  if (destinationState_ == kFullscreenToolbarOnly)
+    progress = 1.0 - progress;
+  [controller_ setFloatingBarShownFraction:progress];
+}
+
+- (void)animationDidEnd:(NSAnimation*)animation {
+  DCHECK_EQ(animation_.get(), animation);
+
+  currentState_ = destinationState_;
+
+  [animation_ setDelegate:nil];
+  animation_.reset();
+
+  [[controller_ tabContentArea] setFastResizeMode:NO];
+}
+
+@end
diff --git a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
index 2c03aca..218e031 100644
--- a/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
+++ b/chrome/browser/ui/cocoa/infobars/translate_infobar_unittest.mm
@@ -61,7 +61,7 @@
  public:
   // Each test gets a single Mock translate delegate for the lifetime of
   // the test.
-  virtual void SetUp() {
+  virtual void SetUp() OVERRIDE {
     TranslateLanguageList::DisableUpdate();
     CocoaProfileTest::SetUp();
     web_contents_.reset(
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
index 44d3ac0..cc146d9 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
@@ -17,7 +17,7 @@
 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
 #include "chrome/browser/ui/omnibox/location_bar.h"
 #include "chrome/browser/ui/omnibox/omnibox_edit_controller.h"
-#include "chrome/browser/ui/toolbar/toolbar_model.h"
+#include "chrome/browser/ui/search/search_model_observer.h"
 #include "chrome/common/content_settings_types.h"
 
 @class AutocompleteTextField;
@@ -27,11 +27,11 @@
 class KeywordHintDecoration;
 class LocationBarDecoration;
 class LocationIconDecoration;
+class MicSearchDecoration;
 class PageActionDecoration;
 class Profile;
 class SelectedKeywordDecoration;
 class StarDecoration;
-class ToolbarModel;
 class ZoomDecoration;
 class ZoomDecorationTest;
 
@@ -42,11 +42,11 @@
 class LocationBarViewMac : public LocationBar,
                            public LocationBarTesting,
                            public OmniboxEditController,
-                           public content::NotificationObserver {
+                           public content::NotificationObserver,
+                           public SearchModelObserver {
  public:
   LocationBarViewMac(AutocompleteTextField* field,
                      CommandUpdater* command_updater,
-                     ToolbarModel* toolbar_model,
                      Profile* profile,
                      Browser* browser);
   virtual ~LocationBarViewMac();
@@ -104,10 +104,10 @@
   // redrawn and laid out if necessary.
   void OnDecorationsChanged();
 
-  // Updates the location bar.  Resets the bar's permanent text and
-  // security style, and if |should_restore_state| is true, restores
-  // saved state from the tab (for tab switching).
-  void Update(const content::WebContents* tab, bool should_restore_state);
+  // Updates the location bar.  Resets the bar's permanent text and security
+  // style, and if |tab| is non-NULL, restores saved state from the tab (for tab
+  // switching).
+  void Update(const content::WebContents* tab);
 
   // Layout the various decorations which live in the field.
   void Layout();
@@ -152,7 +152,9 @@
   virtual gfx::Image GetFavicon() const OVERRIDE;
   virtual string16 GetTitle() const OVERRIDE;
   virtual InstantController* GetInstant() OVERRIDE;
-  virtual content::WebContents* GetWebContents() const OVERRIDE;
+  virtual content::WebContents* GetWebContents() OVERRIDE;
+  virtual ToolbarModel* GetToolbarModel() OVERRIDE;
+  virtual const ToolbarModel* GetToolbarModel() const OVERRIDE;
 
   NSImage* GetKeywordImage(const string16& keyword);
 
@@ -164,8 +166,11 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  // SearchModelObserver:
+  virtual void ModelChanged(const SearchModel::State& old_state,
+                            const SearchModel::State& new_state) OVERRIDE;
+
   Browser* browser() const { return browser_; }
-  ToolbarModel* toolbar_model() const { return toolbar_model_; }
 
  private:
   friend ZoomDecorationTest;
@@ -200,6 +205,10 @@
   // Ensures the star decoration is visible or hidden, as required.
   void UpdateStarDecorationVisibility();
 
+  // Updates the voice search decoration. Returns true if the visible state was
+  // changed.
+  bool UpdateMicSearchDecorationVisibility();
+
   scoped_ptr<OmniboxViewMac> omnibox_view_;
 
   CommandUpdater* command_updater_;  // Weak, owned by Browser.
@@ -243,12 +252,13 @@
   // Keyword hint decoration displayed on the right-hand side.
   scoped_ptr<KeywordHintDecoration> keyword_hint_decoration_;
 
+  // The voice search icon.
+  scoped_ptr<MicSearchDecoration> mic_search_decoration_;
+
   Profile* profile_;
 
   Browser* browser_;
 
-  ToolbarModel* toolbar_model_;  // Weak, owned by Browser.
-
   // The transition type to use for the navigation.
   content::PageTransition transition_;
 
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 b28c4aa..f1bed4f 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
@@ -38,6 +38,7 @@
 #import "chrome/browser/ui/cocoa/location_bar/ev_bubble_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/keyword_hint_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_icon_decoration.h"
+#import "chrome/browser/ui/cocoa/location_bar/mic_search_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/page_action_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
@@ -81,11 +82,9 @@
 LocationBarViewMac::LocationBarViewMac(
     AutocompleteTextField* field,
     CommandUpdater* command_updater,
-    ToolbarModel* toolbar_model,
     Profile* profile,
     Browser* browser)
-    : omnibox_view_(new OmniboxViewMac(this, toolbar_model, profile,
-                                       command_updater, field)),
+    : omnibox_view_(new OmniboxViewMac(this, profile, command_updater, field)),
       command_updater_(command_updater),
       field_(field),
       disposition_(CURRENT_TAB),
@@ -96,9 +95,9 @@
       star_decoration_(new StarDecoration(command_updater)),
       zoom_decoration_(new ZoomDecoration(this)),
       keyword_hint_decoration_(new KeywordHintDecoration()),
+      mic_search_decoration_(new MicSearchDecoration(command_updater)),
       profile_(profile),
       browser_(browser),
-      toolbar_model_(toolbar_model),
       transition_(content::PageTransitionFromInt(
           content::PAGE_TRANSITION_TYPED |
           content::PAGE_TRANSITION_FROM_ADDRESS_BAR)),
@@ -123,11 +122,15 @@
       profile_->GetPrefs(),
       base::Bind(&LocationBarViewMac::OnEditBookmarksEnabledChanged,
                  base::Unretained(this)));
+
+  browser_->search_model()->AddObserver(this);
 }
 
 LocationBarViewMac::~LocationBarViewMac() {
   // Disconnect from cell in case it outlives us.
   [[field_ cell] clearDecorations];
+
+  browser_->search_model()->RemoveObserver(this);
 }
 
 void LocationBarViewMac::ShowFirstRunBubble() {
@@ -184,10 +187,8 @@
 }
 
 void LocationBarViewMac::UpdateContentSettingsIcons() {
-  if (RefreshContentSettingsDecorations()) {
-    [field_ updateMouseTracking];
-    [field_ setNeedsDisplay:YES];
-  }
+  if (RefreshContentSettingsDecorations())
+    OnDecorationsChanged();
 }
 
 void LocationBarViewMac::UpdatePageActions() {
@@ -228,8 +229,7 @@
   omnibox_view_->SaveStateToTab(contents);
 }
 
-void LocationBarViewMac::Update(const WebContents* contents,
-                                bool should_restore_state) {
+void LocationBarViewMac::Update(const WebContents* contents) {
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, IsStarEnabled());
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
                                          IsStarEnabled());
@@ -237,8 +237,8 @@
   UpdateZoomDecoration();
   RefreshPageActionDecorations();
   RefreshContentSettingsDecorations();
-  // OmniboxView restores state if the tab is non-NULL.
-  omnibox_view_->Update(should_restore_state ? contents : NULL);
+  UpdateMicSearchDecorationVisibility();
+  omnibox_view_->Update(contents);
   OnChanged();
 }
 
@@ -297,8 +297,8 @@
 }
 
 void LocationBarViewMac::OnInputInProgress(bool in_progress) {
-  toolbar_model_->SetInputInProgress(in_progress);
-  Update(NULL, false);
+  GetToolbarModel()->set_input_in_progress(in_progress);
+  Update(NULL);
 }
 
 void LocationBarViewMac::OnSetFocus() {
@@ -353,10 +353,18 @@
   return result;
 }
 
-WebContents* LocationBarViewMac::GetWebContents() const {
+WebContents* LocationBarViewMac::GetWebContents() {
   return browser_->tab_strip_model()->GetActiveWebContents();
 }
 
+ToolbarModel* LocationBarViewMac::GetToolbarModel() {
+  return browser_->toolbar_model();
+}
+
+const ToolbarModel* LocationBarViewMac::GetToolbarModel() const {
+  return browser_->toolbar_model();
+}
+
 PageActionDecoration* LocationBarViewMac::GetPageActionDecoration(
     ExtensionAction* page_action) {
   DCHECK(page_action);
@@ -385,7 +393,7 @@
     return;
 
   decoration->set_preview_enabled(preview_enabled);
-  decoration->UpdateVisibility(contents, toolbar_model_->GetURL());
+  decoration->UpdateVisibility(contents, GetToolbarModel()->GetURL());
 }
 
 NSRect LocationBarViewMac::GetPageActionFrame(ExtensionAction* page_action) {
@@ -494,7 +502,7 @@
   OnDecorationsChanged();
 
   if (can_show_bubble && zoom_decoration_->IsVisible())
-    zoom_decoration_->ToggleBubble(YES);
+    zoom_decoration_->ShowBubble(YES);
 }
 
 NSPoint LocationBarViewMac::GetBookmarkBubblePoint() const {
@@ -561,6 +569,12 @@
   }
 }
 
+void LocationBarViewMac::ModelChanged(const SearchModel::State& old_state,
+                                      const SearchModel::State& new_state) {
+  if (UpdateMicSearchDecorationVisibility())
+    Layout();
+}
+
 void LocationBarViewMac::OnEditBookmarksEnabledChanged() {
   UpdateStarDecorationVisibility();
   OnChanged();
@@ -572,7 +586,7 @@
 }
 
 bool LocationBarViewMac::RefreshContentSettingsDecorations() {
-  const bool input_in_progress = toolbar_model_->GetInputInProgress();
+  const bool input_in_progress = GetToolbarModel()->input_in_progress();
   WebContents* web_contents = input_in_progress ?
       NULL : browser_->tab_strip_model()->GetActiveWebContents();
   bool icons_updated = false;
@@ -617,11 +631,10 @@
     }
   }
 
-  GURL url = toolbar_model_->GetURL();
+  GURL url = GetToolbarModel()->GetURL();
   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
     page_action_decorations_[i]->UpdateVisibility(
-        toolbar_model_->GetInputInProgress() ? NULL : web_contents,
-        url);
+        GetToolbarModel()->input_in_progress() ? NULL : web_contents, url);
   }
 }
 
@@ -650,6 +663,7 @@
   }
 
   [cell addRightDecoration:keyword_hint_decoration_.get()];
+  [cell addRightDecoration:mic_search_decoration_.get()];
 
   // By default only the location icon is visible.
   location_icon_decoration_->SetVisible(true);
@@ -673,13 +687,13 @@
     selected_keyword_decoration_->SetVisible(true);
     selected_keyword_decoration_->SetKeyword(short_name, is_extension_keyword);
     selected_keyword_decoration_->SetImage(GetKeywordImage(keyword));
-  } else if (toolbar_model_->GetSecurityLevel(false) ==
+  } else if (GetToolbarModel()->GetSecurityLevel(false) ==
              ToolbarModel::EV_SECURE) {
     // Switch from location icon to show the EV bubble instead.
     location_icon_decoration_->SetVisible(false);
     ev_bubble_decoration_->SetVisible(true);
 
-    string16 label(toolbar_model_->GetEVCertName());
+    string16 label(GetToolbarModel()->GetEVCertName());
     ev_bubble_decoration_->SetFullLabel(base::SysUTF16ToNSString(label));
   } else if (!keyword.empty() && is_keyword_hint) {
     keyword_hint_decoration_->SetKeyword(short_name,
@@ -705,7 +719,7 @@
 bool LocationBarViewMac::IsStarEnabled() {
   return [field_ isEditable] &&
          browser_defaults::bookmarks_enabled &&
-         !toolbar_model_->GetInputInProgress() &&
+         !GetToolbarModel()->input_in_progress() &&
          edit_bookmarks_enabled_.GetValue();
 }
 
@@ -720,3 +734,12 @@
 void LocationBarViewMac::UpdateStarDecorationVisibility() {
   star_decoration_->SetVisible(IsStarEnabled());
 }
+
+bool LocationBarViewMac::UpdateMicSearchDecorationVisibility() {
+  bool is_visible = !GetToolbarModel()->input_in_progress() &&
+                    browser_->search_model()->voice_search_supported();
+  if (mic_search_decoration_->IsVisible() == is_visible)
+    return false;
+  mic_search_decoration_->SetVisible(is_visible);
+  return true;
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm
index 1e96e67..619f4d8 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_icon_decoration.mm
@@ -98,7 +98,8 @@
 
   WebContents* tab = owner_->GetWebContents();
   const NavigationController& controller = tab->GetController();
-  NavigationEntry* nav_entry = controller.GetActiveEntry();
+  // Important to use GetVisibleEntry to match what's showing in the omnibox.
+  NavigationEntry* nav_entry = controller.GetVisibleEntry();
   if (!nav_entry) {
     NOTREACHED();
     return true;
diff --git a/chrome/browser/ui/cocoa/location_bar/mic_search_decoration.h b/chrome/browser/ui/cocoa/location_bar/mic_search_decoration.h
new file mode 100644
index 0000000..e8c9534
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/mic_search_decoration.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_UI_COCOA_LOCATION_BAR_MIC_SEARCH_DECORATION_H_
+#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_MIC_SEARCH_DECORATION_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "chrome/browser/ui/cocoa/location_bar/image_decoration.h"
+
+class CommandUpdater;
+
+// Draws a microphone icon on the right side of the omnibox. This is used for
+// voice search.
+class MicSearchDecoration : public ImageDecoration {
+ public:
+  explicit MicSearchDecoration(CommandUpdater* command_updater);
+  virtual ~MicSearchDecoration();
+
+  // Implement |LocationBarDecoration|.
+  virtual bool AcceptsMousePress() OVERRIDE;
+  virtual bool OnMousePressed(NSRect frame) OVERRIDE;
+  virtual NSString* GetToolTip() OVERRIDE;
+
+ private:
+  CommandUpdater* command_updater_;  // Weak, owned by Browser.
+
+  DISALLOW_COPY_AND_ASSIGN(MicSearchDecoration);
+};
+
+#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_MIC_SEARCH_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/mic_search_decoration.mm b/chrome/browser/ui/cocoa/location_bar/mic_search_decoration.mm
new file mode 100644
index 0000000..cb92a7d
--- /dev/null
+++ b/chrome/browser/ui/cocoa/location_bar/mic_search_decoration.mm
@@ -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.
+
+#import "chrome/browser/ui/cocoa/location_bar/mic_search_decoration.h"
+
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/command_updater.h"
+#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+MicSearchDecoration::MicSearchDecoration(CommandUpdater* command_updater)
+    : command_updater_(command_updater) {
+  SetImage(OmniboxViewMac::ImageForResource(IDR_OMNIBOX_MIC_SEARCH));
+}
+
+MicSearchDecoration::~MicSearchDecoration() {
+}
+
+bool MicSearchDecoration::AcceptsMousePress() {
+  return true;
+}
+
+bool MicSearchDecoration::OnMousePressed(NSRect frame) {
+  command_updater_->ExecuteCommand(IDC_TOGGLE_SPEECH_INPUT);
+  return true;
+}
+
+NSString* MicSearchDecoration::GetToolTip() {
+  return l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_MIC_SEARCH);
+}
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
index ffc1994..6bbbe6d 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.h
@@ -27,9 +27,11 @@
   void Update(ZoomController* zoom_controller);
 
   // Shows the zoom bubble for this decoration. If |auto_close| is YES, then
-  // the bubble will automatically close after a fixed period of time. Closes
-  // the bubble if it was already visible.
-  void ToggleBubble(BOOL auto_close);
+  // the bubble will automatically close after a fixed period of time.
+  void ShowBubble(BOOL auto_close);
+
+  // Closes the zoom bubble.
+  void CloseBubble();
 
  private:
   friend ZoomDecorationTest;
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
index e36170f..0d60f5b 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration.mm
@@ -45,11 +45,9 @@
   [bubble_ onZoomChanged];
 }
 
-void ZoomDecoration::ToggleBubble(BOOL auto_close) {
-  if (bubble_) {
-    [bubble_ close];
+void ZoomDecoration::ShowBubble(BOOL auto_close) {
+  if (bubble_)
     return;
-  }
 
   content::WebContents* web_contents = owner_->GetWebContents();
   if (!web_contents)
@@ -85,6 +83,10 @@
                     autoClose:auto_close];
 }
 
+void ZoomDecoration::CloseBubble() {
+  [bubble_ close];
+}
+
 NSPoint ZoomDecoration::GetBubblePointInFrame(NSRect frame) {
   return NSMakePoint(NSMaxX(frame), NSMaxY(frame));
 }
@@ -99,7 +101,7 @@
 }
 
 bool ZoomDecoration::ShouldShowDecoration() const {
-  if (owner_->toolbar_model()->GetInputInProgress())
+  if (owner_->GetToolbarModel()->input_in_progress())
     return false;
   if (bubble_)
     return true;
@@ -111,7 +113,10 @@
 }
 
 bool ZoomDecoration::OnMousePressed(NSRect frame) {
-  ToggleBubble(NO);
+  if (bubble_)
+    CloseBubble();
+  else
+    ShowBubble(NO);
   return true;
 }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm b/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm
index 76f89e6..b4aeda6 100644
--- a/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/zoom_decoration_browsertest.mm
@@ -21,7 +21,6 @@
  protected:
   ZoomDecorationTest()
       : InProcessBrowserTest(),
-        old_toolbar_model_(NULL),
         should_quit_on_zoom_(false),
         zoom_callback_(base::Bind(&ZoomDecorationTest::OnZoomChanged,
                                   base::Unretained(this))) {
@@ -30,15 +29,11 @@
   virtual void SetUpOnMainThread() OVERRIDE {
     content::HostZoomMap::GetForBrowserContext(
         browser()->profile())->AddZoomLevelChangedCallback(zoom_callback_);
-
-    old_toolbar_model_ = GetLocationBar()->toolbar_model_;
-    GetLocationBar()->toolbar_model_ = &test_toolbar_model_;
   }
 
   virtual void CleanUpOnMainThread() OVERRIDE {
     content::HostZoomMap::GetForBrowserContext(
         browser()->profile())->RemoveZoomLevelChangedCallback(zoom_callback_);
-    GetLocationBar()->toolbar_model_ = old_toolbar_model_;
   }
 
   LocationBarViewMac* GetLocationBar() const {
@@ -59,10 +54,6 @@
     return [controller locationBarBridge]->zoom_decoration_.get();
   }
 
-  ZoomBubbleController* GetBubble() const {
-    return GetZoomDecoration()->bubble_;
-  }
-
   void Zoom(content::PageZoom zoom) {
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
@@ -80,10 +71,7 @@
     }
   }
 
-  TestToolbarModel test_toolbar_model_;
-
  private:
-  ToolbarModel* old_toolbar_model_;
   bool should_quit_on_zoom_;
   content::HostZoomMap::ZoomLevelChangedCallback zoom_callback_;
 
@@ -103,12 +91,12 @@
   // Zoom in and show bubble then reset.
   Zoom(content::PAGE_ZOOM_IN);
   EXPECT_TRUE(zoom_decoration->IsVisible());
-  zoom_decoration->ToggleBubble(false);
+  zoom_decoration->ShowBubble(false);
   Zoom(content::PAGE_ZOOM_RESET);
   EXPECT_TRUE(zoom_decoration->IsVisible());
 
   // Hide bubble and verify the decoration is hidden.
-  [GetBubble() close];
+  zoom_decoration->CloseBubble();
   EXPECT_FALSE(zoom_decoration->IsVisible());
 }
 
@@ -119,7 +107,9 @@
   Zoom(content::PAGE_ZOOM_IN);
   EXPECT_TRUE(zoom_decoration->IsVisible());
 
-  test_toolbar_model_.SetInputInProgress(true);
+  scoped_ptr<ToolbarModel> toolbar_model(new TestToolbarModel);
+  toolbar_model->set_input_in_progress(true);
+  browser()->swap_toolbar_models(&toolbar_model);
   GetLocationBar()->ZoomChangedForActiveTab(false);
   EXPECT_FALSE(zoom_decoration->IsVisible());
 }
@@ -130,7 +120,7 @@
   // Create a new browser so that it can be closed properly.
   Browser* browser2 = CreateBrowser(browser()->profile());
   ZoomDecoration* zoom_decoration = GetZoomDecorationForBrowser(browser2);
-  zoom_decoration->ToggleBubble(true);
+  zoom_decoration->ShowBubble(true);
 
   // Test shouldn't crash.
   browser2->window()->Close();
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
index ec6142f..96fd417 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -75,10 +75,17 @@
 }
 
 - (void)setContentText:(NSAttributedString*)contentText {
+  [[self controlView] setNeedsDisplay:YES];
   contentText_.reset([contentText retain]);
 }
 
 - (void)setDescriptionText:(NSAttributedString*)descriptionText {
+  [[self controlView] setNeedsDisplay:YES];
+  if (![descriptionText length]) {
+    descriptionText_.reset();
+    return;
+  }
+
   base::scoped_nsobject<NSMutableAttributedString> dashDescriptionText(
       [[NSMutableAttributedString alloc]
           initWithAttributedString:descriptionText]);
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
index 6bddf63..9000941 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
@@ -133,7 +133,12 @@
     [self selectCell:selectedCell];
   } else {
     const NSInteger selectedRow = [self selectedRow];
-    DCHECK_GE(selectedRow, 0);
+
+    // No row could be selected if the model failed to update.
+    if (selectedRow == -1) {
+      NOTREACHED();
+      return;
+    }
 
     DCHECK(delegate_);
     delegate_->OnMatrixRowClicked(self, selectedRow);
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
index 1b69f6f..35f2e34 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
@@ -175,7 +175,8 @@
 
 void OmniboxPopupViewMac::OnMatrixRowSelected(OmniboxPopupMatrix* matrix,
                                               size_t row) {
-  model_->SetSelectedLine(row, false, false);
+  size_t start_match = model_->result().ShouldHideTopMatch() ? 1 : 0;
+  model_->SetSelectedLine(row + start_match, false, false);
 }
 
 void OmniboxPopupViewMac::OnMatrixRowClicked(OmniboxPopupMatrix* matrix,
@@ -403,7 +404,9 @@
 
 void OmniboxPopupViewMac::OpenURLForRow(size_t row,
                                         WindowOpenDisposition disposition) {
-  DCHECK_GE(row, 0u);
+  size_t start_match = model_->result().ShouldHideTopMatch() ? 1 : 0;
+  row += start_match;
+  DCHECK_LT(row, GetResult().size());
 
   // OpenMatch() may close the popup, which will clear the result set and, by
   // extension, |match| and its contents.  So copy the relevant match out to
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
index 2d2d0d3..82e0d18 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
@@ -332,7 +332,7 @@
       [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)]);
   [[test_window() contentView] addSubview:field];
 
-  OmniboxViewMac view(NULL, NULL, profile(), NULL, NULL);
+  OmniboxViewMac view(NULL, profile(), NULL, NULL);
   MockOmniboxPopupViewMac popup_view(&view, view.model(), field);
 
   popup_view.UpdatePopupAppearance();
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
index b52da56..5cb76b6 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
@@ -23,7 +23,6 @@
                        public AutocompleteTextFieldObserver {
  public:
   OmniboxViewMac(OmniboxEditController* controller,
-                 ToolbarModel* toolbar_model,
                  Profile* profile,
                  CommandUpdater* command_updater,
                  AutocompleteTextField* field);
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index de73f1e..5edacd7 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -133,11 +133,10 @@
 }
 
 OmniboxViewMac::OmniboxViewMac(OmniboxEditController* controller,
-                               ToolbarModel* toolbar_model,
                                Profile* profile,
                                CommandUpdater* command_updater,
                                AutocompleteTextField* field)
-    : OmniboxView(profile, controller, toolbar_model, command_updater),
+    : OmniboxView(profile, controller, command_updater),
       popup_view_(new OmniboxPopupViewMac(this, model(), field)),
       field_(field),
       saved_temporary_selection_(NSMakeRange(0, 0)),
@@ -190,8 +189,8 @@
   // that the field isn't always updated correctly.  Figure out why
   // this is.  Maybe this method should be refactored into more
   // specific cases.
-  bool user_visible =
-      model()->UpdatePermanentText(toolbar_model()->GetText(true));
+  bool user_visible = model()->UpdatePermanentText(
+      controller()->GetToolbarModel()->GetText(true));
 
   if (tab_for_state_restoring) {
     RevertAll();
@@ -225,7 +224,7 @@
     // TODO(shess): This corresponds to _win and _gtk, except those
     // guard it with a test for whether the security level changed.
     // But AFAICT, that can only change if the text changed, and that
-    // code compares the toolbar_model() security level with the local
+    // code compares the toolbar model security level with the local
     // security level.  Dig in and figure out why this isn't a no-op
     // that should go away.
     EmphasizeURLComponents();
@@ -465,7 +464,7 @@
   // [Could it be to not change if no change?  If so, I'm guessing
   // AppKit may already handle that.]
   const ToolbarModel::SecurityLevel security_level =
-      toolbar_model()->GetSecurityLevel(false);
+      controller()->GetToolbarModel()->GetSecurityLevel(false);
 
   // Emphasize the scheme for security UI display purposes (if necessary).
   if (!model()->user_input_in_progress() && model()->CurrentTextIsURL() &&
@@ -818,8 +817,8 @@
   DCHECK(CanCopy());
   DCHECK(ShouldEnableCopyURL());
 
-  string16 text = toolbar_model()->GetText(false);
-  GURL url = toolbar_model()->GetURL();
+  string16 text = controller()->GetToolbarModel()->GetText(false);
+  GURL url = controller()->GetToolbarModel()->GetURL();
 
   NSString* nstext = base::SysUTF16ToNSString(text);
   [pb declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
@@ -866,8 +865,8 @@
 // platforms. Some refactor might be necessary to simplify this. Or at least
 // this method could call the OmniboxView version.
 bool OmniboxViewMac::ShouldEnableCopyURL() {
-  return !model()->user_input_in_progress() &&
-      toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false);
+  return controller()->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+      false);
 }
 
 bool OmniboxViewMac::CanPasteAndGo() {
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
index 0749f66..a59a450 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
@@ -78,7 +78,8 @@
 
 class TestingOmniboxEditController : public OmniboxEditController {
  public:
-  TestingOmniboxEditController() {}
+  explicit TestingOmniboxEditController(ToolbarModel* toolbar_model)
+      : toolbar_model_(toolbar_model) {}
   virtual ~TestingOmniboxEditController() {}
 
   // Overridden from OmniboxEditController:
@@ -94,11 +95,15 @@
   virtual gfx::Image GetFavicon() const OVERRIDE { return gfx::Image(); }
   virtual string16 GetTitle() const OVERRIDE { return string16(); }
   virtual InstantController* GetInstant() OVERRIDE { return NULL; }
-  virtual content::WebContents* GetWebContents() const OVERRIDE {
-    return NULL;
+  virtual content::WebContents* GetWebContents() OVERRIDE { return NULL; }
+  virtual ToolbarModel* GetToolbarModel() OVERRIDE { return toolbar_model_; }
+  virtual const ToolbarModel* GetToolbarModel() const OVERRIDE {
+    return toolbar_model_;
   }
 
  private:
+  ToolbarModel* toolbar_model_;
+
   DISALLOW_COPY_AND_ASSIGN(TestingOmniboxEditController);
 };
 
@@ -117,7 +122,7 @@
 
 TEST_F(OmniboxViewMacTest, TabToAutocomplete) {
   chrome::EnableInstantExtendedAPIForTesting();
-  OmniboxViewMac view(NULL, NULL, profile(), NULL, NULL);
+  OmniboxViewMac view(NULL, profile(), NULL, NULL);
 
   // This is deleted by the omnibox view.
   MockOmniboxEditModel* model =
@@ -149,9 +154,9 @@
 
   TestingToolbarModelDelegate delegate;
   ToolbarModelImpl toolbar_model(&delegate);
-  OmniboxViewMac view(NULL, &toolbar_model, profile(), NULL, field.get());
+  TestingOmniboxEditController controller(&toolbar_model);
+  OmniboxViewMac view(&controller, profile(), NULL, field.get());
 
-  TestingOmniboxEditController controller;
   // This is deleted by the omnibox view.
   MockOmniboxEditModel* model =
       new MockOmniboxEditModel(&view, &controller, profile());
@@ -172,7 +177,7 @@
 }
 
 TEST_F(OmniboxViewMacTest, UpDownArrow) {
-  OmniboxViewMac view(NULL, NULL, profile(), NULL, NULL);
+  OmniboxViewMac view(NULL, profile(), NULL, NULL);
 
   // This is deleted by the omnibox view.
   MockOmniboxEditModel* model =
diff --git a/chrome/browser/ui/cocoa/one_click_signin_view_controller.mm b/chrome/browser/ui/cocoa/one_click_signin_view_controller.mm
index b663214..07029d1 100644
--- a/chrome/browser/ui/cocoa/one_click_signin_view_controller.mm
+++ b/chrome/browser/ui/cocoa/one_click_signin_view_controller.mm
@@ -167,8 +167,8 @@
   NSSize delta = NSMakeSize(0.0, totalYOffset);
 
   if (isSyncDialog_) {
-    [messageTextField_ setStringValue:l10n_util::GetNSStringFWithFixup(
-        IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW, email_)];
+    [messageTextField_ setStringValue:l10n_util::GetNSStringWithFixup(
+        IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW)];
   } else if ([errorMessage_ length] != 0) {
     [messageTextField_ setStringValue:errorMessage_];
   }
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm
index bfc103e..0545797 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.mm
@@ -20,6 +20,7 @@
 #import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
 #include "ui/base/cocoa/window_size_constants.h"
 #include "ui/base/text/text_elider.h"
+#include "ui/gfx/font.h"
 #include "ui/gfx/point.h"
 
 namespace {
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
index 1ac010a..068a56b 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
@@ -56,9 +56,9 @@
   if (NSMinY(dirtyRect) < backgroundHeight) {
     gfx::ScopedNSGraphicsContextSaveGState scopedGState;
     NSGraphicsContext *context = [NSGraphicsContext currentContext];
-    NSPoint phase = [[self window] themePatternPhaseForAlignment:
-        THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
-    [context cr_setPatternPhase:phase forView:self];
+    NSPoint position = [[self window] themeImagePositionForAlignment:
+        THEME_IMAGE_ALIGN_WITH_TAB_STRIP];
+    [context cr_setPatternPhase:position forView:self];
 
     // Themes don't have an inactive image so only look for one if there's no
     // theme.
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index 57c46a5..e4271e2 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -323,9 +323,9 @@
 
   ThemeService* themeProvider =
       static_cast<ThemeService*>([[self window] themeProvider]);
-  NSPoint phase = [[self window]
-      themePatternPhaseForAlignment: THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
-  [context cr_setPatternPhase:phase forView:self];
+  NSPoint position = [[self window]
+      themeImagePositionForAlignment: THEME_IMAGE_ALIGN_WITH_TAB_STRIP];
+  [context cr_setPatternPhase:position forView:self];
 
   CGImageRef mask([self tabClippingMask]);
   CGRect maskBounds = CGRectMake(0, 0, maskCacheWidth_, kMaskHeight);
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index 7978772..c3cc590 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -33,10 +33,10 @@
   return NO;
 }
 
-- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
+- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
   if ([self parentWindow]) {
     return [[[self parentWindow] windowController]
-        themePatternPhaseForAlignment:alignment];
+        themeImagePositionForAlignment:alignment];
   }
   return NSZeroPoint;
 }
diff --git a/chrome/browser/ui/cocoa/themed_window.h b/chrome/browser/ui/cocoa/themed_window.h
index f553795..592e567 100644
--- a/chrome/browser/ui/cocoa/themed_window.h
+++ b/chrome/browser/ui/cocoa/themed_window.h
@@ -22,13 +22,13 @@
 typedef NSUInteger ThemedWindowStyle;
 
 // Indicates how the theme image should be aligned.
-enum ThemePatternAlignment {
+enum ThemeImageAlignment {
   // Aligns the top of the theme image with the top of the frame. Use this
   // for IDR_THEME_THEME_FRAME.*
-  THEME_PATTERN_ALIGN_WITH_FRAME,
-  // Aligns the top of the theme image with the top of the tab
-  // strip. Use this for IDR_THEME_TAB_BACKGROUND and IDR_THEME_TOOLBAR.
-  THEME_PATTERN_ALIGN_WITH_TAB_STRIP
+  THEME_IMAGE_ALIGN_WITH_FRAME,
+  // Aligns the top of the theme image with the top of the tabs.
+  // Use this for IDR_THEME_TAB_BACKGROUND and IDR_THEME_TOOLBAR.
+  THEME_IMAGE_ALIGN_WITH_TAB_STRIP
 };
 
 // Implemented by windows that support theming.
@@ -36,7 +36,13 @@
 @interface NSWindow (ThemeProvider)
 - (ThemeProvider*)themeProvider;
 - (ThemedWindowStyle)themedWindowStyle;
-- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment;
+
+// Returns the position in the coordinates of the root view
+// ([[self contentView] superview]) that the top left of a theme image with
+// |alignment| should be painted at. The result of this method can be used in
+// conjunction with [NSGraphicsContext cr_setPatternPhase:] to set the offset of
+// pattern colors.
+- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment;
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_THEMED_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/themed_window.mm b/chrome/browser/ui/cocoa/themed_window.mm
index 6696464..4e5a2c3 100644
--- a/chrome/browser/ui/cocoa/themed_window.mm
+++ b/chrome/browser/ui/cocoa/themed_window.mm
@@ -16,7 +16,7 @@
   return THEMED_NORMAL;
 }
 
-- (NSPoint)themePatternPhaseForAlignment:(ThemePatternAlignment)alignment {
+- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
   return NSZeroPoint;
 }
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
index 07a0bf5..b023897 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
@@ -27,7 +27,6 @@
 class Profile;
 @class ReloadButton;
 @class ToolbarButton;
-class ToolbarModel;
 @class WrenchMenuController;
 
 namespace content {
@@ -58,7 +57,6 @@
   IBOutlet BrowserActionsContainerView* browserActionsContainerView_;
 
  @private
-  ToolbarModel* toolbarModel_;  // weak, one per window
   CommandUpdater* commands_;  // weak, one per window
   Profile* profile_;  // weak, one per window
   Browser* browser_;  // weak, one per window
@@ -98,12 +96,11 @@
 
 // Initialize the toolbar and register for command updates. The profile is
 // needed for initializing the location bar. The browser is needed for
-// initializing the back/forward menus.
-- (id)initWithModel:(ToolbarModel*)model
-           commands:(CommandUpdater*)commands
-            profile:(Profile*)profile
-            browser:(Browser*)browser
-     resizeDelegate:(id<ViewResizer>)resizeDelegate;
+// the toolbar model and back/forward menus.
+- (id)initWithCommands:(CommandUpdater*)commands
+               profile:(Profile*)profile
+               browser:(Browser*)browser
+        resizeDelegate:(id<ViewResizer>)resizeDelegate;
 
 // Get the C++ bridge object representing the location bar for this tab.
 - (LocationBarViewMac*)locationBarBridge;
@@ -117,12 +114,10 @@
 // Make the location bar the first responder, if possible.
 - (void)focusLocationBar:(BOOL)selectAll;
 
-// Updates the toolbar (and transitively the location bar) with the states of
-// the specified |tab|.  If |shouldRestore| is true, we're switching
-// (back?) to this tab and should restore any previous location bar state
-// (such as user editing) as well.
-- (void)updateToolbarWithContents:(content::WebContents*)tabForRestoring
-               shouldRestoreState:(BOOL)shouldRestore;
+// Forces the toolbar (and transitively the location bar) to update its current
+// state.  If |tab| is non-NULL, we're switching (back?) to this tab and should
+// restore any previous location bar state (such as user editing) as well.
+- (void)updateToolbarWithContents:(content::WebContents*)tab;
 
 // Sets whether or not the current page in the frontmost tab is bookmarked.
 - (void)setStarredState:(BOOL)isStarred;
@@ -170,12 +165,11 @@
 @interface ToolbarController(ProtectedMethods)
 // Designated initializer which takes a nib name in order to allow subclasses
 // to load a different nib file.
-- (id)initWithModel:(ToolbarModel*)model
-           commands:(CommandUpdater*)commands
-            profile:(Profile*)profile
-            browser:(Browser*)browser
-     resizeDelegate:(id<ViewResizer>)resizeDelegate
-       nibFileNamed:(NSString*)nibName;
+- (id)initWithCommands:(CommandUpdater*)commands
+               profile:(Profile*)profile
+               browser:(Browser*)browser
+        resizeDelegate:(id<ViewResizer>)resizeDelegate
+          nibFileNamed:(NSString*)nibName;
 @end
 
 // A set of private methods used by tests, in the absence of "friends" in ObjC.
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index 7f3e9f0..d675586 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -46,7 +46,6 @@
 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/toolbar/toolbar_model.h"
 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/common/net/url_fixer_upper.h"
@@ -148,16 +147,14 @@
 
 @synthesize browser = browser_;
 
-- (id)initWithModel:(ToolbarModel*)model
-           commands:(CommandUpdater*)commands
-            profile:(Profile*)profile
-            browser:(Browser*)browser
-     resizeDelegate:(id<ViewResizer>)resizeDelegate
-       nibFileNamed:(NSString*)nibName {
-  DCHECK(model && commands && profile && [nibName length]);
+- (id)initWithCommands:(CommandUpdater*)commands
+               profile:(Profile*)profile
+               browser:(Browser*)browser
+        resizeDelegate:(id<ViewResizer>)resizeDelegate
+          nibFileNamed:(NSString*)nibName {
+  DCHECK(commands && profile && [nibName length]);
   if ((self = [super initWithNibName:nibName
                               bundle:base::mac::FrameworkBundle()])) {
-    toolbarModel_ = model;
     commands_ = commands;
     profile_ = profile;
     browser_ = browser;
@@ -176,17 +173,15 @@
   return self;
 }
 
-- (id)initWithModel:(ToolbarModel*)model
-           commands:(CommandUpdater*)commands
-            profile:(Profile*)profile
-            browser:(Browser*)browser
-     resizeDelegate:(id<ViewResizer>)resizeDelegate {
-  if ((self = [self initWithModel:model
-                         commands:commands
-                          profile:profile
-                          browser:browser
-                   resizeDelegate:resizeDelegate
-                     nibFileNamed:@"Toolbar"])) {
+- (id)initWithCommands:(CommandUpdater*)commands
+               profile:(Profile*)profile
+               browser:(Browser*)browser
+        resizeDelegate:(id<ViewResizer>)resizeDelegate {
+  if ((self = [self initWithCommands:commands
+                             profile:profile
+                             browser:browser
+                      resizeDelegate:resizeDelegate
+                        nibFileNamed:@"Toolbar"])) {
   }
   return self;
 }
@@ -270,8 +265,7 @@
 
   [self initCommandStatus:commands_];
 
-  locationBarView_.reset(new LocationBarViewMac(locationBar_,
-                                                commands_, toolbarModel_,
+  locationBarView_.reset(new LocationBarViewMac(locationBar_, commands_,
                                                 profile_, browser_));
   [locationBar_ setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
   // Register pref observers for the optional home and page/options buttons
@@ -435,9 +429,8 @@
   [homeButton_ setEnabled:commands->IsCommandEnabled(IDC_HOME) ? YES : NO];
 }
 
-- (void)updateToolbarWithContents:(WebContents*)tab
-               shouldRestoreState:(BOOL)shouldRestore {
-  locationBarView_->Update(tab, shouldRestore ? true : false);
+- (void)updateToolbarWithContents:(WebContents*)tab {
+  locationBarView_->Update(tab);
 
   [locationBar_ updateMouseTracking];
 
@@ -781,7 +774,7 @@
   GURL url(URLFixerUpper::FixupURL(
       base::SysNSStringToUTF8([urls objectAtIndex:0]), std::string()));
 
-  if (url.SchemeIs(chrome::kJavaScriptScheme)) {
+  if (url.SchemeIs(content::kJavaScriptScheme)) {
     browser_->window()->GetLocationBar()->GetLocationEntry()->SetUserText(
           OmniboxView::StripJavascriptSchemas(UTF8ToUTF16(url.spec())));
   }
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
index 8fb005e..dd160b4 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller_unittest.mm
@@ -61,11 +61,11 @@
     updater->UpdateCommandEnabled(IDC_FORWARD, false);
     resizeDelegate_.reset([[ViewResizerPong alloc] init]);
     bar_.reset(
-        [[ToolbarController alloc] initWithModel:browser()->toolbar_model()
-                                        commands:browser()->command_controller()->command_updater()
-                                         profile:profile()
-                                         browser:browser()
-                                  resizeDelegate:resizeDelegate_.get()]);
+        [[ToolbarController alloc]
+            initWithCommands:browser()->command_controller()->command_updater()
+                     profile:profile()
+                     browser:browser()
+              resizeDelegate:resizeDelegate_.get()]);
     EXPECT_TRUE([bar_ view]);
     NSView* parent = [test_window() contentView];
     [parent addSubview:[bar_ view]];
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm
index a4ec3fd..18bf58b 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_view.mm
@@ -18,9 +18,9 @@
 }
 
 - (void)drawRect:(NSRect)rect {
-  NSPoint phase = [[self window]
-      themePatternPhaseForAlignment:THEME_PATTERN_ALIGN_WITH_TAB_STRIP];
-  [[NSGraphicsContext currentContext] cr_setPatternPhase:phase forView:self];
+  NSPoint position = [[self window]
+      themeImagePositionForAlignment:THEME_IMAGE_ALIGN_WITH_TAB_STRIP];
+  [[NSGraphicsContext currentContext] cr_setPatternPhase:position forView:self];
   [self drawBackgroundWithOpaque:YES];
 }
 
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm
index ef73a61..5d19bc6 100644
--- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm
+++ b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm
@@ -43,6 +43,10 @@
     GetConstrainedWindowMac(dialog)->PulseWebContentsModalDialog();
   }
 
+  virtual void HostChanged(
+      web_modal::WebContentsModalDialogHost* new_host) OVERRIDE {
+  }
+
  private:
   static ConstrainedWindowMac* GetConstrainedWindowMac(
       NativeWebContentsModalDialog dialog) {
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 98d0091..04a3ef0 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -546,56 +546,70 @@
 
 
 void ContentSettingPopupBubbleModel::SetPopups() {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableBetterPopupBlocking)) {
-    std::map<int32, GURL> blocked_popups =
-        PopupBlockerTabHelper::FromWebContents(web_contents())
-            ->GetBlockedPopupRequests();
-    for (std::map<int32, GURL>::const_iterator iter = blocked_popups.begin();
-         iter != blocked_popups.end();
-         ++iter) {
-      std::string title(iter->second.spec());
-      // The popup may not have a valid URL.
-      if (title.empty())
-        title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
-      PopupItem popup_item(
-          ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-              IDR_DEFAULT_FAVICON),
-          title,
-          iter->first);
-      add_popup(popup_item);
-    }
-    return;
-  }
-  std::vector<WebContents*> blocked_contents;
-  BlockedContentTabHelper::FromWebContents(web_contents())->
-      GetBlockedContents(&blocked_contents);
-  for (std::vector<WebContents*>::const_iterator
-       i = blocked_contents.begin(); i != blocked_contents.end(); ++i) {
-    std::string title(UTF16ToUTF8((*i)->GetTitle()));
-    // The popup may not have committed a load yet, in which case it won't
-    // have a URL or title.
+  std::map<int32, GURL> blocked_popups =
+      PopupBlockerTabHelper::FromWebContents(web_contents())
+          ->GetBlockedPopupRequests();
+  for (std::map<int32, GURL>::const_iterator iter = blocked_popups.begin();
+       iter != blocked_popups.end();
+       ++iter) {
+    std::string title(iter->second.spec());
+    // The popup may not have a valid URL.
     if (title.empty())
       title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE);
     PopupItem popup_item(
-        FaviconTabHelper::FromWebContents(*i)->GetFavicon(), title, *i);
+        ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+            IDR_DEFAULT_FAVICON),
+        title,
+        iter->first);
     add_popup(popup_item);
   }
 }
 
 void ContentSettingPopupBubbleModel::OnPopupClicked(int index) {
   if (web_contents()) {
-    if (!CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kDisableBetterPopupBlocking)) {
-      PopupBlockerTabHelper::FromWebContents(web_contents())->
-          ShowBlockedPopup(bubble_content().popup_items[index].popup_id);
-    } else {
-      BlockedContentTabHelper::FromWebContents(web_contents())->
-          LaunchForContents(bubble_content().popup_items[index].web_contents);
-    }
+    PopupBlockerTabHelper::FromWebContents(web_contents())->
+        ShowBlockedPopup(bubble_content().popup_items[index].popup_id);
   }
 }
 
+// The model for the save password bubble.
+class SavePasswordBubbleModel : public ContentSettingBubbleModel {
+ public:
+  SavePasswordBubbleModel(WebContents* web_contents, Profile* profile);
+  virtual ~SavePasswordBubbleModel() {}
+
+ private:
+  // Sets the title of the bubble.
+  void SetTitle();
+
+  TabSpecificContentSettings::PasswordSavingState state_;
+
+  DISALLOW_COPY_AND_ASSIGN(SavePasswordBubbleModel);
+};
+
+SavePasswordBubbleModel::SavePasswordBubbleModel(WebContents* web_contents,
+                                                 Profile* profile)
+    : ContentSettingBubbleModel(web_contents, profile,
+                                CONTENT_SETTINGS_TYPE_SAVE_PASSWORD),
+      state_(TabSpecificContentSettings::NO_PASSWORD_TO_BE_SAVED) {
+  DCHECK(profile);
+  TabSpecificContentSettings* content_settings =
+      TabSpecificContentSettings::FromWebContents(web_contents);
+  state_ = content_settings->GetPasswordSavingState();
+
+  SetTitle();
+}
+
+void SavePasswordBubbleModel::SetTitle() {
+  int title_id = 0;
+  // If the save password icon was accessed, the icon is displayed and the
+  // bubble is instantiated
+  if (state_ == TabSpecificContentSettings::PASSWORD_TO_BE_SAVED)
+    title_id = IDS_SAVE_PASSWORD;
+
+  set_title(l10n_util::GetStringUTF8(title_id));
+}
+
 // The model of the content settings bubble for media settings.
 class ContentSettingMediaStreamBubbleModel
     : public ContentSettingTitleAndLinkModel {
@@ -717,7 +731,9 @@
 }
 
 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() {
-  GURL url = web_contents()->GetURL();
+  TabSpecificContentSettings* content_settings =
+      TabSpecificContentSettings::FromWebContents(web_contents());
+  GURL url = content_settings->media_stream_access_origin();
   RadioGroup radio_group;
   radio_group.url = url;
 
@@ -804,12 +820,15 @@
   if (profile()) {
     HostContentSettingsMap* content_settings =
         profile()->GetHostContentSettingsMap();
+    TabSpecificContentSettings* tab_content_settings =
+        TabSpecificContentSettings::FromWebContents(web_contents());
     // The same patterns must be used as in other places (e.g. the infobar) in
     // order to override the existing rule. Otherwise a new rule is created.
     // TODO(markusheintz): Extract to a helper so that there is only a single
     // place to touch.
     ContentSettingsPattern primary_pattern =
-        ContentSettingsPattern::FromURLNoWildcard(web_contents()->GetURL());
+        ContentSettingsPattern::FromURLNoWildcard(
+            tab_content_settings->media_stream_access_origin());
     ContentSettingsPattern secondary_pattern =
         ContentSettingsPattern::Wildcard();
     if (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED ||
@@ -1257,6 +1276,9 @@
         WebContents* web_contents,
         Profile* profile,
         ContentSettingsType content_type) {
+  if (content_type == CONTENT_SETTINGS_TYPE_SAVE_PASSWORD) {
+    return new SavePasswordBubbleModel(web_contents, profile);
+  }
   if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) {
     return new ContentSettingCookiesBubbleModel(delegate, web_contents, profile,
                                                 content_type);
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.h b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
index 89c7bef..bc88e96 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.h
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
@@ -34,19 +34,11 @@
   typedef ContentSettingBubbleModelDelegate Delegate;
 
   struct PopupItem {
-    PopupItem(const gfx::Image& image,
-              const std::string& title,
-              content::WebContents* web_contents)
-        : image(image),
-          title(title),
-          web_contents(web_contents),
-          popup_id(-1) {}
     PopupItem(const gfx::Image& image, const std::string& title, int32 popup_id)
-        : image(image), title(title), web_contents(NULL), popup_id(popup_id) {}
+        : image(image), title(title), popup_id(popup_id) {}
 
     gfx::Image image;
     std::string title;
-    content::WebContents* web_contents;
     int32 popup_id;
   };
   typedef std::vector<PopupItem> PopupItems;
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
index 9702064..9bd24ab 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
@@ -118,8 +118,16 @@
 
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
-  content_settings->OnMicrophoneAccessed();
-  content_settings->OnCameraAccessed();
+  std::string request_host = "google.com";
+  GURL security_origin("http://" + request_host);
+  MediaStreamDevicesController::MediaStreamTypePermissionMap
+      request_permissions;
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
 
   scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -133,7 +141,7 @@
   EXPECT_EQ(bubble_content.radio_group.radio_items[0],
             l10n_util::GetStringFUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION,
-                UTF8ToUTF16(web_contents()->GetURL().spec())));
+                UTF8ToUTF16(request_host)));
   EXPECT_EQ(bubble_content.radio_group.radio_items[1],
             l10n_util::GetStringUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK));
@@ -173,8 +181,13 @@
 
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
-  content_settings->OnMicrophoneAccessBlocked();
-  content_settings->OnCameraAccessBlocked();
+  MediaStreamDevicesController::MediaStreamTypePermissionMap
+      request_permissions;
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  content_settings->OnMediaStreamPermissionSet(url, request_permissions);
   {
     scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
         ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -239,7 +252,14 @@
 
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
-  content_settings->OnMicrophoneAccessed();
+  std::string request_host = "google.com";
+  GURL security_origin("http://" + request_host);
+  MediaStreamDevicesController::MediaStreamTypePermissionMap
+      request_permissions;
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
 
   scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -253,7 +273,7 @@
   EXPECT_EQ(bubble_content.radio_group.radio_items[0],
             l10n_util::GetStringFUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION,
-                UTF8ToUTF16(web_contents()->GetURL().spec())));
+                UTF8ToUTF16(request_host)));
   EXPECT_EQ(bubble_content.radio_group.radio_items[1],
             l10n_util::GetStringUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK));
@@ -266,7 +286,10 @@
             bubble_content.media_menus.begin()->first);
 
   // Change the microphone access.
-  content_settings->OnMicrophoneAccessBlocked();
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
   content_setting_bubble_model.reset(
       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
           NULL, web_contents(), profile(),
@@ -279,7 +302,7 @@
   EXPECT_EQ(new_bubble_content.radio_group.radio_items[0],
             l10n_util::GetStringFUTF8(
                 IDS_BLOCKED_MEDIASTREAM_MIC_ASK,
-                UTF8ToUTF16(web_contents()->GetURL().spec())));
+                UTF8ToUTF16(request_host)));
   EXPECT_EQ(new_bubble_content.radio_group.radio_items[1],
             l10n_util::GetStringUTF8(
                 IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION));
@@ -299,7 +322,14 @@
 
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
-  content_settings->OnCameraAccessed();
+  std::string request_host = "google.com";
+  GURL security_origin("http://" + request_host);
+  MediaStreamDevicesController::MediaStreamTypePermissionMap
+      request_permissions;
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
 
   scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -313,7 +343,7 @@
   EXPECT_EQ(bubble_content.radio_group.radio_items[0],
             l10n_util::GetStringFUTF8(
                 IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION,
-                UTF8ToUTF16(web_contents()->GetURL().spec())));
+                UTF8ToUTF16(request_host)));
   EXPECT_EQ(bubble_content.radio_group.radio_items[1],
             l10n_util::GetStringUTF8(
                 IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK));
@@ -326,7 +356,10 @@
             bubble_content.media_menus.begin()->first);
 
   // Change the camera access.
-  content_settings->OnCameraAccessBlocked();
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
   content_setting_bubble_model.reset(
       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
           NULL, web_contents(), profile(),
@@ -339,7 +372,7 @@
   EXPECT_EQ(new_bubble_content.radio_group.radio_items[0],
             l10n_util::GetStringFUTF8(
                 IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK,
-                UTF8ToUTF16(web_contents()->GetURL().spec())));
+                UTF8ToUTF16(request_host)));
   EXPECT_EQ(new_bubble_content.radio_group.radio_items[1],
             l10n_util::GetStringUTF8(
                 IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION));
@@ -359,9 +392,16 @@
 
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
+  std::string request_host = "google.com";
+  GURL security_origin("http://" + request_host);
 
   // Firstly, add microphone access.
-  content_settings->OnMicrophoneAccessed();
+  MediaStreamDevicesController::MediaStreamTypePermissionMap
+      request_permissions;
+  request_permissions[content::MEDIA_DEVICE_AUDIO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
 
   scoped_ptr<ContentSettingBubbleModel> content_setting_bubble_model(
       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -375,7 +415,7 @@
   EXPECT_EQ(bubble_content.radio_group.radio_items[0],
             l10n_util::GetStringFUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION,
-                UTF8ToUTF16(web_contents()->GetURL().spec())));
+                UTF8ToUTF16(request_host)));
   EXPECT_EQ(bubble_content.radio_group.radio_items[1],
             l10n_util::GetStringUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK));
@@ -385,7 +425,10 @@
             bubble_content.media_menus.begin()->first);
 
   // Then add camera access.
-  content_settings->OnCameraAccessed();
+  request_permissions[content::MEDIA_DEVICE_VIDEO_CAPTURE] =
+      MediaStreamDevicesController::MEDIA_ALLOWED;
+  content_settings->OnMediaStreamPermissionSet(security_origin,
+                                               request_permissions);
 
   content_setting_bubble_model.reset(
       ContentSettingBubbleModel::CreateContentSettingBubbleModel(
@@ -399,7 +442,7 @@
   EXPECT_EQ(new_bubble_content.radio_group.radio_items[0],
             l10n_util::GetStringFUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION,
-                UTF8ToUTF16(web_contents()->GetURL().spec())));
+                UTF8ToUTF16(request_host)));
   EXPECT_EQ(new_bubble_content.radio_group.radio_items[1],
             l10n_util::GetStringUTF8(
                 IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK));
diff --git a/chrome/browser/ui/content_settings/content_setting_image_model.cc b/chrome/browser/ui/content_settings/content_setting_image_model.cc
index 9e564a2..764e1c9 100644
--- a/chrome/browser/ui/content_settings/content_setting_image_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_image_model.cc
@@ -59,6 +59,13 @@
   virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
 };
 
+class ContentSettingSavePasswordImageModel : public ContentSettingImageModel {
+ public:
+  ContentSettingSavePasswordImageModel();
+
+  virtual void UpdateFromWebContents(WebContents* web_contents) OVERRIDE;
+};
+
 namespace {
 
 struct ContentSettingsTypeIdEntry {
@@ -198,6 +205,34 @@
       IDS_GEOLOCATION_ALLOWED_TOOLTIP : IDS_GEOLOCATION_BLOCKED_TOOLTIP));
 }
 
+ContentSettingSavePasswordImageModel::ContentSettingSavePasswordImageModel()
+    : ContentSettingImageModel(CONTENT_SETTINGS_TYPE_SAVE_PASSWORD) {
+}
+
+void ContentSettingSavePasswordImageModel::UpdateFromWebContents(
+    WebContents* web_contents) {
+  set_visible(false);
+  if (!web_contents)
+    return;
+  TabSpecificContentSettings* content_settings =
+      TabSpecificContentSettings::FromWebContents(web_contents);
+  if (!content_settings)
+    return;
+
+  TabSpecificContentSettings::PasswordSavingState state =
+      content_settings->GetPasswordSavingState();
+  switch (state) {
+    case TabSpecificContentSettings::PASSWORD_TO_BE_SAVED:
+      set_icon(IDR_SAVE_PASSWORD);
+      set_visible(true);
+      break;
+    case TabSpecificContentSettings::NO_PASSWORD_TO_BE_SAVED:
+      set_icon(IDR_SAVE_PASSWORD);
+      set_visible(false);
+      break;
+  }
+}
+
 ContentSettingMediaImageModel::ContentSettingMediaImageModel(
     ContentSettingsType type)
     : ContentSettingImageModel(type) {
@@ -359,6 +394,8 @@
       return new ContentSettingMediaImageModel(content_settings_type);
     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
       return new ContentSettingMIDISysExImageModel();
+    case CONTENT_SETTINGS_TYPE_SAVE_PASSWORD:
+      return new ContentSettingSavePasswordImageModel();
     default:
       return new ContentSettingBlockedImageModel(content_settings_type);
   }
diff --git a/chrome/browser/ui/extensions/app_metro_infobar_delegate_win.cc b/chrome/browser/ui/extensions/app_metro_infobar_delegate_win.cc
deleted file mode 100644
index a08aa86..0000000
--- a/chrome/browser/ui/extensions/app_metro_infobar_delegate_win.cc
+++ /dev/null
@@ -1,117 +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/extensions/app_metro_infobar_delegate_win.h"
-
-#include "apps/app_launch_for_metro_restart_win.h"
-#include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
-#include "base/prefs/pref_service.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/metro_utils/metro_chrome_win.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/app_list/app_list_service_win.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/host_desktop.h"
-#include "chrome/common/pref_names.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/url_constants.h"
-#include "grit/generated_resources.h"
-#include "grit/google_chrome_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "win8/util/win8_util.h"
-
-// static
-void AppMetroInfoBarDelegateWin::Create(
-    Profile* profile,
-    Mode mode,
-    const std::string& extension_id) {
-  DCHECK(win8::IsSingleWindowMetroMode());
-  DCHECK_EQ(mode == SHOW_APP_LIST, extension_id.empty());
-
-  // Chrome should never get here via the Ash desktop, so only look for browsers
-  // on the native desktop.
-  Browser* browser = FindOrCreateTabbedBrowser(
-      profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
-
-  // Create a new tab at about:blank, and add the infobar.
-  content::WebContents* web_contents = browser->OpenURL(content::OpenURLParams(
-      GURL(content::kAboutBlankURL), content::Referrer(), NEW_FOREGROUND_TAB,
-      content::PAGE_TRANSITION_LINK, false));
-  InfoBarService* info_bar_service =
-      InfoBarService::FromWebContents(web_contents);
-  info_bar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
-      new AppMetroInfoBarDelegateWin(info_bar_service, mode, extension_id)));
-
-  // Use PostTask because we can get here in a COM SendMessage, and
-  // ActivateApplication can not be sent nested (returns error
-  // RPC_E_CANTCALLOUT_ININPUTSYNCCALL).
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(base::IgnoreResult(chrome::ActivateMetroChrome)));
-}
-
-AppMetroInfoBarDelegateWin::AppMetroInfoBarDelegateWin(
-    InfoBarService* info_bar_service,
-    Mode mode,
-    const std::string& extension_id)
-    : ConfirmInfoBarDelegate(info_bar_service),
-      mode_(mode),
-      extension_id_(extension_id) {
-  DCHECK_EQ(mode_ == SHOW_APP_LIST, extension_id_.empty());
-}
-
-AppMetroInfoBarDelegateWin::~AppMetroInfoBarDelegateWin() {}
-
-int AppMetroInfoBarDelegateWin::GetIconID() const {
-  return chrome::GetAppListIconResourceId();
-}
-
-string16 AppMetroInfoBarDelegateWin::GetMessageText() const {
-  return l10n_util::GetStringUTF16(mode_ == SHOW_APP_LIST ?
-      IDS_WIN8_INFOBAR_DESKTOP_RESTART_FOR_APP_LIST :
-      IDS_WIN8_INFOBAR_DESKTOP_RESTART_FOR_PACKAGED_APP);
-}
-
-string16 AppMetroInfoBarDelegateWin::GetButtonLabel(
-    InfoBarButton button) const {
-  return l10n_util::GetStringUTF16(button == BUTTON_CANCEL ?
-      IDS_WIN8_INFOBAR_DESKTOP_RESTART_TO_LAUNCH_APPS_NO_BUTTON :
-      IDS_WIN8_INFOBAR_DESKTOP_RESTART_TO_LAUNCH_APPS_YES_BUTTON);
-}
-
-bool AppMetroInfoBarDelegateWin::Accept() {
-  PrefService* prefs = g_browser_process->local_state();
-  if (mode_ == SHOW_APP_LIST) {
-    prefs->SetBoolean(prefs::kRestartWithAppList, true);
-  } else {
-    apps::SetAppLaunchForMetroRestart(
-        Profile::FromBrowserContext(web_contents()->GetBrowserContext()),
-        extension_id_);
-  }
-
-  web_contents()->Close();  // Note: deletes |this|.
-  chrome::AttemptRestartWithModeSwitch();
-  return false;
-}
-
-bool AppMetroInfoBarDelegateWin::Cancel() {
-  web_contents()->Close();
-  return false;
-}
-
-string16 AppMetroInfoBarDelegateWin::GetLinkText() const {
-  return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
-}
-
-bool AppMetroInfoBarDelegateWin::LinkClicked(
-    WindowOpenDisposition disposition) {
-  web_contents()->OpenURL(content::OpenURLParams(
-      GURL("https://support.google.com/chrome/?p=ib_redirect_to_desktop"),
-      content::Referrer(),
-      (disposition == CURRENT_TAB) ? NEW_FOREGROUND_TAB : disposition,
-      content::PAGE_TRANSITION_LINK, false));
-  return false;
-}
diff --git a/chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h b/chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h
deleted file mode 100644
index 1f625f7..0000000
--- a/chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h
+++ /dev/null
@@ -1,52 +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_EXTENSIONS_APP_METRO_INFOBAR_DELEGATE_WIN_H_
-#define CHROME_BROWSER_UI_EXTENSIONS_APP_METRO_INFOBAR_DELEGATE_WIN_H_
-
-#include <string>
-
-#include "chrome/browser/infobars/confirm_infobar_delegate.h"
-
-class InfoBarService;
-class Profile;
-
-// This infobar operates by opening a new tab on about:blank, showing an
-// infobar offering to relaunch the browser in metro mode, and then relaunching
-// in Desktop mode if confirmed.
-class AppMetroInfoBarDelegateWin : public ConfirmInfoBarDelegate {
- public:
-  enum Mode {
-    SHOW_APP_LIST,
-    LAUNCH_PACKAGED_APP
-  };
-
-  // Creates an app metro infobar delegate, adds it to a new browser tab, then
-  // activates Metro mode.
-  static void Create(Profile* profile,
-                     Mode mode,
-                     const std::string& extension_id);
-
- private:
-  AppMetroInfoBarDelegateWin(InfoBarService* infobar_service,
-                             Mode mode,
-                             const std::string& extension_id);
-  virtual ~AppMetroInfoBarDelegateWin();
-
-  // ConfirmInfoBarDelegate overrides:
-  virtual int GetIconID() const OVERRIDE;
-  virtual string16 GetMessageText() const OVERRIDE;
-  virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
-  virtual bool Accept() OVERRIDE;
-  virtual bool Cancel() OVERRIDE;
-  virtual string16 GetLinkText() const OVERRIDE;
-  virtual bool LinkClicked(WindowOpenDisposition disposition) OVERRIDE;
-
-  Mode mode_;
-  std::string extension_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppMetroInfoBarDelegateWin);
-};
-
-#endif  // CHROME_BROWSER_UI_EXTENSIONS_APP_METRO_INFOBAR_DELEGATE_WIN_H_
diff --git a/chrome/browser/ui/extensions/apps_metro_handler_win.cc b/chrome/browser/ui/extensions/apps_metro_handler_win.cc
deleted file mode 100644
index f59f675..0000000
--- a/chrome/browser/ui/extensions/apps_metro_handler_win.cc
+++ /dev/null
@@ -1,31 +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/extensions/apps_metro_handler_win.h"
-
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
-#include "chrome/browser/ui/simple_message_box.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace chrome {
-
-bool VerifySwitchToMetroForApps(gfx::NativeWindow parent_window) {
-  if (!apps::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
-          apps::ShellWindow::WINDOW_TYPE_DEFAULT)) {
-    return true;
-  }
-
-  MessageBoxResult result = ShowMessageBox(
-      parent_window,
-      l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
-      l10n_util::GetStringUTF16(IDS_WIN8_PROMPT_TO_CLOSE_APPS_FOR_METRO),
-      MESSAGE_BOX_TYPE_OK_CANCEL);
-
-  return result == MESSAGE_BOX_RESULT_YES;
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/extensions/apps_metro_handler_win.h b/chrome/browser/ui/extensions/apps_metro_handler_win.h
deleted file mode 100644
index f1a79de..0000000
--- a/chrome/browser/ui/extensions/apps_metro_handler_win.h
+++ /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.
-
-#ifndef CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
-#define CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
-
-#include "ui/gfx/native_widget_types.h"
-
-namespace chrome {
-
-// Check if there are apps running and if not, return true. Otherwise, Show a
-// modal dialog on |parent| asking whether the user is OK with their packaged
-// apps closing, in order to relaunch to metro mode. Returns true if the user
-// clicks OK.
-bool VerifySwitchToMetroForApps(gfx::NativeWindow parent);
-
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.cc b/chrome/browser/ui/extensions/extension_install_ui_default.cc
index abc00b6..36bc8bc 100644
--- a/chrome/browser/ui/extensions/extension_install_ui_default.cc
+++ b/chrome/browser/ui/extensions/extension_install_ui_default.cc
@@ -204,13 +204,12 @@
 // ExtensionInstallUIDefault --------------------------------------------------
 
 ExtensionInstallUIDefault::ExtensionInstallUIDefault(Profile* profile)
-    : skip_post_install_ui_(false),
+    : ExtensionInstallUI(profile),
+      skip_post_install_ui_(false),
       previous_using_native_theme_(false),
       use_app_installed_bubble_(false) {
-  profile_ = profile;
-
-  // |profile_| can be NULL during tests.
-  if (profile_) {
+  // |profile| can be NULL during tests.
+  if (profile) {
     // Remember the current theme in case the user presses undo.
     const Extension* previous_theme =
         ThemeServiceFactory::GetThemeForProfile(profile);
@@ -221,15 +220,14 @@
   }
 }
 
-ExtensionInstallUIDefault::~ExtensionInstallUIDefault() {
-}
+ExtensionInstallUIDefault::~ExtensionInstallUIDefault() {}
 
 void ExtensionInstallUIDefault::OnInstallSuccess(const Extension* extension,
                                                  SkBitmap* icon) {
   if (skip_post_install_ui_)
     return;
 
-  if (!profile_) {
+  if (!profile()) {
     // TODO(zelidrag): Figure out what exact conditions cause crash
     // http://crbug.com/159437 and write browser test to cover it.
     NOTREACHED();
@@ -238,13 +236,13 @@
 
   if (extension->is_theme()) {
     ThemeInstalledInfoBarDelegate::Create(
-        extension, profile_, previous_theme_id_, previous_using_native_theme_);
+        extension, profile(), previous_theme_id_, previous_using_native_theme_);
     return;
   }
 
   // Extensions aren't enabled by default in incognito so we confirm
   // the install in a normal window.
-  Profile* current_profile = profile_->GetOriginalProfile();
+  Profile* current_profile = profile()->GetOriginalProfile();
   if (extension->is_app()) {
     bool use_bubble = false;
 
@@ -282,8 +280,8 @@
   if (disable_failure_ui_for_tests || skip_post_install_ui_)
     return;
 
-  Browser* browser = chrome::FindLastActiveWithProfile(profile_,
-      chrome::GetActiveDesktop());
+  Browser* browser =
+      chrome::FindLastActiveWithProfile(profile(), chrome::GetActiveDesktop());
   if (!browser)  // Can be NULL in unittests.
     return;
   WebContents* web_contents =
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.h b/chrome/browser/ui/extensions/extension_install_ui_default.h
index a465d5d..52ce0f7 100644
--- a/chrome/browser/ui/extensions/extension_install_ui_default.h
+++ b/chrome/browser/ui/extensions/extension_install_ui_default.h
@@ -5,21 +5,18 @@
 #ifndef CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_INSTALL_UI_DEFAULT_H_
 #define CHROME_BROWSER_UI_EXTENSIONS_EXTENSION_INSTALL_UI_DEFAULT_H_
 
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
 #include "chrome/browser/extensions/extension_install_ui.h"
 
-class InfoBarDelegate;
 class Profile;
 
-namespace content {
-class WebContents;
-}
-
 class ExtensionInstallUIDefault : public ExtensionInstallUI {
  public:
   explicit ExtensionInstallUIDefault(Profile* profile);
   virtual ~ExtensionInstallUIDefault();
 
-  // ExtensionInstallUI implementation:
+  // ExtensionInstallUI:
   virtual void OnInstallSuccess(const extensions::Extension* extension,
                                 SkBitmap* icon) OVERRIDE;
   virtual void OnInstallFailure(
diff --git a/chrome/browser/ui/fast_unload_controller.cc b/chrome/browser/ui/fast_unload_controller.cc
index f118a38..af90382 100644
--- a/chrome/browser/ui/fast_unload_controller.cc
+++ b/chrome/browser/ui/fast_unload_controller.cc
@@ -65,7 +65,8 @@
 bool FastUnloadController::CanCloseContents(content::WebContents* contents) {
   // Don't try to close the tab when the whole browser is being closed, since
   // that avoids the fast shutdown path where we just kill all the renderers.
-  return !is_attempting_to_close_browser_;
+  return !is_attempting_to_close_browser_ ||
+      is_calling_before_unload_handlers();
 }
 
 bool FastUnloadController::BeforeUnloadFired(content::WebContents* contents,
@@ -106,27 +107,63 @@
   if (HasCompletedUnloadProcessing())
     return true;
 
+  // The behavior followed here varies based on the current phase of the
+  // operation and whether a batched shutdown is in progress.
+  //
+  // If there are tabs with outstanding beforeunload handlers:
+  // 1. If a batched shutdown is in progress: return false.
+  //    This is to prevent interference with batched shutdown already in
+  //    progress.
+  // 2. Otherwise: start sending beforeunload events and return false.
+  //
+  // Otherwise, If there are no tabs with outstanding beforeunload handlers:
+  // 3. If a batched shutdown is in progress: start sending unload events and
+  //    return false.
+  // 4. Otherwise: return true.
   is_attempting_to_close_browser_ = true;
+  // Cases 1 and 4.
+  bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
+  if (need_beforeunload_fired == is_calling_before_unload_handlers())
+    return !need_beforeunload_fired;
 
-  if (!TabsNeedBeforeUnloadFired())
-    return true;
-
+  // Cases 2 and 3.
+  on_close_confirmed_.Reset();
   ProcessPendingTabs();
   return false;
 }
 
+bool FastUnloadController::CallBeforeUnloadHandlers(
+    const base::Callback<void(bool)>& on_close_confirmed) {
+  if (!TabsNeedBeforeUnloadFired())
+    return false;
+
+  on_close_confirmed_ = on_close_confirmed;
+  is_attempting_to_close_browser_ = true;
+  ProcessPendingTabs();
+  return true;
+}
+
+void FastUnloadController::ResetBeforeUnloadHandlers() {
+  if (!is_calling_before_unload_handlers())
+    return;
+  CancelWindowClose();
+}
+
 bool FastUnloadController::TabsNeedBeforeUnloadFired() {
   if (!tabs_needing_before_unload_.empty() ||
       tab_needing_before_unload_ack_ != NULL)
     return true;
 
-  if (!tabs_needing_unload_.empty())
+  if (!is_calling_before_unload_handlers() && !tabs_needing_unload_.empty())
     return false;
 
   for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
     content::WebContents* contents =
         browser_->tab_strip_model()->GetWebContentsAt(i);
-    if (contents->NeedToFireBeforeUnload())
+    if (!ContainsKey(tabs_needing_unload_, contents) &&
+        !ContainsKey(tabs_needing_unload_ack_, contents) &&
+        tab_needing_before_unload_ack_ != contents &&
+        contents->NeedToFireBeforeUnload())
       tabs_needing_before_unload_.insert(contents);
   }
   return !tabs_needing_before_unload_.empty();
@@ -265,6 +302,11 @@
     return;
   }
 
+  if (is_calling_before_unload_handlers()) {
+    on_close_confirmed_.Run(true);
+    return;
+  }
+
   // Process all the unload handlers. (The beforeunload handlers have finished.)
   if (!tabs_needing_unload_.empty()) {
     browser_->OnWindowClosing();
@@ -339,6 +381,12 @@
 
   // No need to clear tabs_needing_unload_ack_. Those tabs are already detached.
 
+  if (is_calling_before_unload_handlers()) {
+    base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_;
+    on_close_confirmed_.Reset();
+    on_close_confirmed.Run(false);
+  }
+
   is_attempting_to_close_browser_ = false;
 
   content::NotificationService::current()->Notify(
diff --git a/chrome/browser/ui/fast_unload_controller.h b/chrome/browser/ui/fast_unload_controller.h
index 945197d..ef45a21 100644
--- a/chrome/browser/ui/fast_unload_controller.h
+++ b/chrome/browser/ui/fast_unload_controller.h
@@ -7,6 +7,7 @@
 
 #include <set>
 
+#include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_piece.h"
@@ -80,6 +81,15 @@
   // when there are no remaining beforeunload handlers to be run.
   bool ShouldCloseWindow();
 
+  // Begins the process of confirming whether the associated browser can be
+  // closed.
+  bool CallBeforeUnloadHandlers(
+      const base::Callback<void(bool)>& on_close_confirmed);
+
+  // Clears the results of any beforeunload confirmation dialogs triggered by a
+  // CallBeforeUnloadHandlers call.
+  void ResetBeforeUnloadHandlers();
+
   // Returns true if |browser_| has any tabs that have BeforeUnload handlers
   // that have not been fired. This method is non-const because it builds a list
   // of tabs that need their BeforeUnloadHandlers fired.
@@ -138,6 +148,10 @@
   void LogUnloadStep(const base::StringPiece& step_name,
                      content::WebContents* contents) const;
 
+  bool is_calling_before_unload_handlers() {
+    return !on_close_confirmed_.is_null();
+  }
+
   Browser* browser_;
 
   content::NotificationRegistrar registrar_;
@@ -166,6 +180,11 @@
   // a Browser window isn't just immediately closed.
   bool is_attempting_to_close_browser_;
 
+  // A callback to call to report whether the user chose to close all tabs of
+  // |browser_| that have beforeunload event handlers. This is set only if we
+  // are currently confirming that the browser is closable.
+  base::Callback<void(bool)> on_close_confirmed_;
+
   // Manage tabs with beforeunload/unload handlers that close detached.
   class DetachedWebContentsDelegate;
   scoped_ptr<DetachedWebContentsDelegate> detached_delegate_;
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 510014b..43d9490 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.cc
@@ -612,6 +612,10 @@
   // No-op.
 }
 
+void NativeAppWindowGtk::UpdateInputRegion(scoped_ptr<SkRegion> region) {
+  NOTIMPLEMENTED();
+}
+
 void NativeAppWindowGtk::UpdateDraggableRegions(
     const std::vector<extensions::DraggableRegion>& regions) {
   // Draggable region is not supported for non-frameless window.
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 67d1a0b..b43c8fa 100644
--- a/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
+++ b/chrome/browser/ui/gtk/apps/native_app_window_gtk.h
@@ -66,6 +66,7 @@
   virtual void UpdateWindowTitle() OVERRIDE;
   virtual void HandleKeyboardEvent(
       const content::NativeWebKeyboardEvent& event) OVERRIDE;
+  virtual void UpdateInputRegion(scoped_ptr<SkRegion> region) OVERRIDE;
   virtual void UpdateDraggableRegions(
       const std::vector<extensions::DraggableRegion>& regions) OVERRIDE;
   virtual void RenderViewHostChanged() OVERRIDE;
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk.cc
index c82e655..1291386 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk.cc
@@ -219,8 +219,7 @@
   gtk_container_add(GTK_CONTAINER(paint_box_), bookmark_hbox_);
 
   apps_shortcut_button_ = theme_service_->BuildChromeButton();
-  bookmark_utils::ConfigureAppsShortcutButton(apps_shortcut_button_,
-                                              theme_service_);
+  ConfigureAppsShortcutButton(apps_shortcut_button_, theme_service_);
   g_signal_connect(apps_shortcut_button_, "clicked",
                    G_CALLBACK(OnAppsButtonClickedThunk), this);
   // Accept middle mouse clicking.
@@ -574,8 +573,8 @@
       menu_bar_helper_.Add(gtk_bin_get_child(GTK_BIN(item)));
   }
 
-  bookmark_utils::ConfigureButtonForNode(model_->other_node(),
-      model_, other_bookmarks_button_, theme_service_);
+  ConfigureButtonForNode(
+      model_->other_node(), model_, other_bookmarks_button_, theme_service_);
 
   SetInstructionState();
   SetChevronState();
@@ -977,7 +976,7 @@
   GtkToolItem* item = gtk_toolbar_get_nth_item(
       GTK_TOOLBAR(bookmark_toolbar_.get()), index);
   GtkWidget* button = gtk_bin_get_child(GTK_BIN(item));
-  bookmark_utils::ConfigureButtonForNode(node, model, button, theme_service_);
+  ConfigureButtonForNode(node, model, button, theme_service_);
   SetChevronState();
 }
 
@@ -1027,12 +1026,12 @@
 
 GtkWidget* BookmarkBarGtk::CreateBookmarkButton(const BookmarkNode* node) {
   GtkWidget* button = theme_service_->BuildChromeButton();
-  bookmark_utils::ConfigureButtonForNode(node, model_, button, theme_service_);
+  ConfigureButtonForNode(node, model_, button, theme_service_);
 
   // The tool item is also a source for dragging
   gtk_drag_source_set(button, GDK_BUTTON1_MASK, NULL, 0,
       static_cast<GdkDragAction>(GDK_ACTION_MOVE | GDK_ACTION_COPY));
-  int target_mask = bookmark_utils::GetCodeMask(node->is_folder());
+  int target_mask = GetCodeMask(node->is_folder());
   ui::SetSourceTargetListFromCodeMask(button, target_mask);
   g_signal_connect(button, "drag-begin",
                    G_CALLBACK(&OnButtonDragBeginThunk), this);
@@ -1205,8 +1204,7 @@
   dragged_node_ = node;
   DCHECK(dragged_node_);
 
-  drag_icon_ = bookmark_utils::GetDragRepresentationForNode(
-      node, model_, theme_service_);
+  drag_icon_ = GetDragRepresentationForNode(node, model_, theme_service_);
 
   // We have to jump through some hoops to get the drag icon to line up because
   // it is a different size than the button.
@@ -1254,9 +1252,9 @@
                                      GtkSelectionData* selection_data,
                                      guint target_type,
                                      guint time) {
-  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget);
-  bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type,
-                                           browser_->profile());
+  const BookmarkNode* node = BookmarkNodeForWidget(widget);
+  WriteBookmarkToSelection(
+      node, selection_data, target_type, browser_->profile());
 }
 
 void BookmarkBarGtk::OnAppsButtonClicked(GtkWidget* sender) {
@@ -1356,19 +1354,19 @@
     }
 
     case ui::CHROME_NAMED_URL: {
-      dnd_success = bookmark_utils::CreateNewBookmarkFromNamedUrl(
+      dnd_success = CreateNewBookmarkFromNamedUrl(
           selection_data, model_, dest_node, index);
       break;
     }
 
     case ui::TEXT_URI_LIST: {
-      dnd_success = bookmark_utils::CreateNewBookmarksFromURIList(
+      dnd_success = CreateNewBookmarksFromURIList(
           selection_data, model_, dest_node, index);
       break;
     }
 
     case ui::NETSCAPE_URL: {
-      dnd_success = bookmark_utils::CreateNewBookmarkFromNetscapeURL(
+      dnd_success = CreateNewBookmarkFromNetscapeURL(
           selection_data, model_, dest_node, index);
       break;
     }
@@ -1383,7 +1381,7 @@
       // so that it doesn't look like we can drag onto the bookmark bar.
       if (!url.is_valid())
         break;
-      string16 title = bookmark_utils::GetNameForURL(url);
+      string16 title = GetNameForURL(url);
       model_->AddURL(dest_node, index, title, url);
       dnd_success = TRUE;
       break;
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc
index ba5e752..99ed9ed 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk.cc
@@ -63,7 +63,7 @@
                      GtkTreeIter* iter,
                      gpointer pointer_data) {
   ExpandNodesData* data = reinterpret_cast<ExpandNodesData*>(pointer_data);
-  int64 node_id = bookmark_utils::GetIdFromTreeIter(model, iter);
+  int64 node_id = GetIdFromTreeIter(model, iter);
   if (data->ids->find(node_id) != data->ids->end())
     gtk_tree_view_expand_to_path(GTK_TREE_VIEW(data->tree_view), path);
   return FALSE;  // Indicates we want to continue iterating.
@@ -87,8 +87,7 @@
   GtkTreeIter iter;
   gtk_tree_model_get_iter(gtk_tree_view_get_model(tree_view), &iter, path);
   const BookmarkNode* node = data->bookmark_model->GetNodeByID(
-      bookmark_utils::GetIdFromTreeIter(gtk_tree_view_get_model(tree_view),
-                                        &iter));
+      GetIdFromTreeIter(gtk_tree_view_get_model(tree_view), &iter));
   if (node)
     data->nodes.insert(node);
 }
@@ -213,7 +212,7 @@
   }
 
   const BookmarkNode* GetNodeAt(GtkTreeModel* model, GtkTreeIter* iter) const {
-    int64 id = bookmark_utils::GetIdFromTreeIter(model, iter);
+    int64 id = GetIdFromTreeIter(model, iter);
     return (id > 0) ? editor_->bb_model_->GetNodeByID(id) : NULL;
   }
 
@@ -392,10 +391,9 @@
       selected_id = details_.existing_node->parent()->id();
     else if (parent_)
       selected_id = parent_->id();
-    tree_store_ = bookmark_utils::MakeFolderTreeStore();
-    bookmark_utils::AddToTreeStore(bb_model_, selected_id, tree_store_,
-                                   &selected_iter);
-    tree_view_ = bookmark_utils::MakeTreeViewForStore(tree_store_);
+    tree_store_ = MakeFolderTreeStore();
+    AddToTreeStore(bb_model_, selected_id, tree_store_, &selected_iter);
+    tree_view_ = MakeTreeViewForStore(tree_store_);
     gtk_widget_set_size_request(tree_view_, kTreeWidth, kTreeHeight);
     tree_selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view_));
     g_signal_connect(tree_view_, "button-press-event",
@@ -555,8 +553,7 @@
   }
 
   // Create the new folders and update the titles.
-  const BookmarkNode* new_parent =
-      bookmark_utils::CommitTreeStoreDifferencesBetween(
+  const BookmarkNode* new_parent = CommitTreeStoreDifferencesBetween(
       bb_model_, tree_store_, selected_parent);
 
   SaveExpandedNodesData data;
@@ -583,13 +580,13 @@
 void BookmarkEditorGtk::AddNewFolder(GtkTreeIter* parent, GtkTreeIter* child) {
   gtk_tree_store_append(tree_store_, child, parent);
   gtk_tree_store_set(
-      tree_store_, child,
-      bookmark_utils::FOLDER_ICON,
-      GtkThemeService::GetFolderIcon(true).ToGdkPixbuf(),
-      bookmark_utils::FOLDER_NAME,
+      tree_store_,
+      child,
+      FOLDER_ICON, GtkThemeService::GetFolderIcon(true).ToGdkPixbuf(),
+      FOLDER_NAME,
           l10n_util::GetStringUTF8(IDS_BOOKMARK_EDITOR_NEW_FOLDER_NAME).c_str(),
-      bookmark_utils::ITEM_ID, static_cast<int64>(0),
-      bookmark_utils::IS_EDITABLE, TRUE,
+      ITEM_ID, static_cast<int64>(0),
+      IS_EDITABLE, TRUE,
       -1);
 }
 
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk_unittest.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk_unittest.cc
index 8d994d7..df25882 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_editor_gtk_unittest.cc
@@ -21,7 +21,6 @@
 
 using base::Time;
 using base::TimeDelta;
-using bookmark_utils::GetTitleFromTreeIter;
 using content::BrowserThread;
 
 // Base class for bookmark editor tests. This class is a copy from
@@ -254,12 +253,10 @@
   // Create two nodes: "F21" as a child of "F2" and "F211" as a child of "F21".
   GtkTreeIter f21_iter;
   editor.AddNewFolder(&f2_iter, &f21_iter);
-  gtk_tree_store_set(editor.tree_store_, &f21_iter,
-                     bookmark_utils::FOLDER_NAME, "F21", -1);
+  gtk_tree_store_set(editor.tree_store_, &f21_iter, FOLDER_NAME, "F21", -1);
   GtkTreeIter f211_iter;
   editor.AddNewFolder(&f21_iter, &f211_iter);
-  gtk_tree_store_set(editor.tree_store_, &f211_iter,
-                     bookmark_utils::FOLDER_NAME, "F211", -1);
+  gtk_tree_store_set(editor.tree_store_, &f211_iter, FOLDER_NAME, "F211", -1);
 
   ASSERT_EQ(1, gtk_tree_model_iter_n_children(store, &f2_iter));
 
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_menu_controller_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_menu_controller_gtk.cc
index f24f9b8..de4d854 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_menu_controller_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_menu_controller_gtk.cc
@@ -37,7 +37,7 @@
 void SetImageMenuItem(GtkWidget* menu_item,
                       const BookmarkNode* node,
                       BookmarkModel* model) {
-  GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(node, model, true);
+  GdkPixbuf* pixbuf = GetPixbufForNode(node, model, true);
   gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
                                 gtk_image_new_from_pixbuf(pixbuf));
   g_object_unref(pixbuf);
@@ -156,8 +156,8 @@
   for (int i = start_child_index; i < parent->child_count(); ++i) {
     const BookmarkNode* node = parent->GetChild(i);
 
-    GtkWidget* menu_item = gtk_image_menu_item_new_with_label(
-        bookmark_utils::BuildMenuLabelFor(node).c_str());
+    GtkWidget* menu_item =
+        gtk_image_menu_item_new_with_label(BuildMenuLabelFor(node).c_str());
     g_object_set_data(G_OBJECT(menu_item), "bookmark-node", AsVoid(node));
     SetImageMenuItem(menu_item, node, model_);
     gtk_util::SetAlwaysShowImage(menu_item);
@@ -345,8 +345,8 @@
   // pressing.
   ignore_button_release_ = true;
 
-  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(menu_item);
-  drag_icon_ = bookmark_utils::GetDragRepresentationForNode(
+  const BookmarkNode* node = BookmarkNodeForWidget(menu_item);
+  drag_icon_ = GetDragRepresentationForNode(
       node, model_, GtkThemeService::GetFrom(browser_->profile()));
   gint x, y;
   gtk_widget_get_pointer(menu_item, &x, &y);
@@ -365,11 +365,12 @@
   drag_icon_ = NULL;
 }
 
-void BookmarkMenuController::OnMenuItemDragGet(
-    GtkWidget* widget, GdkDragContext* context,
-    GtkSelectionData* selection_data,
-    guint target_type, guint time) {
-  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget);
-  bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type,
-                                           browser_->profile());
+void BookmarkMenuController::OnMenuItemDragGet(GtkWidget* widget,
+                                               GdkDragContext* context,
+                                               GtkSelectionData* selection_data,
+                                               guint target_type,
+                                               guint time) {
+  const BookmarkNode* node = BookmarkNodeForWidget(widget);
+  WriteBookmarkToSelection(
+      node, selection_data, target_type, browser_->profile());
 }
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_sub_menu_model_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_sub_menu_model_gtk.cc
index e1de7ed..cdc7662 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_sub_menu_model_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_sub_menu_model_gtk.cc
@@ -81,11 +81,13 @@
       // Ironically the label will end up getting converted back to UTF8 later.
       // We need to escape any Windows-style "&" characters since they will be
       // converted in MenuGtk outside of our control here.
-      const string16 label = UTF8ToUTF16(ui::EscapeWindowsStyleAccelerators(
-          bookmark_utils::BuildMenuLabelFor(child)));
+      const string16 label = UTF8ToUTF16(
+          ui::EscapeWindowsStyleAccelerators(BuildMenuLabelFor(child)));
       // No command id. We override ActivatedAt below to handle activations.
       AddItem(kBookmarkItemCommandId, label);
-      GdkPixbuf* node_icon = bookmark_utils::GetPixbufForNode(child, model_,
+      GdkPixbuf* node_icon = GetPixbufForNode(
+          child,
+          model_,
           GtkThemeService::GetFrom(profile_)->UsingNativeTheme());
       SetIcon(GetItemCount() - 1, gfx::Image(node_icon));
       // TODO(mdm): set up an observer to watch for icon load events and set
@@ -99,8 +101,8 @@
   // Ironically the label will end up getting converted back to UTF8 later.
   // We need to escape any Windows-style "&" characters since they will be
   // converted in MenuGtk outside of our control here.
-  const string16 label = UTF8ToUTF16(ui::EscapeWindowsStyleAccelerators(
-      bookmark_utils::BuildMenuLabelFor(node)));
+  const string16 label =
+      UTF8ToUTF16(ui::EscapeWindowsStyleAccelerators(BuildMenuLabelFor(node)));
   // Don't pass in the delegate, if any. Bookmark submenus don't need one.
   BookmarkNodeMenuModel* submenu =
       new BookmarkNodeMenuModel(NULL, model_, node, page_navigator_, profile_);
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.cc
index 52944a1..7624b75 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.cc
@@ -25,16 +25,20 @@
   // pixbuf-expander-open. Unfortunately there is no GTK_STOCK_OPEN_DIRECTORY
   // (and indeed, Nautilus does not render an expanded directory any
   // differently).
-  gtk_tree_store_set(store, iter,
-      bookmark_utils::FOLDER_ICON,
-      GtkThemeService::GetFolderIcon(true).ToGdkPixbuf(),
-      bookmark_utils::FOLDER_NAME,
-      UTF16ToUTF8(node->GetTitle()).c_str(),
-      bookmark_utils::ITEM_ID, node->id(),
-      // We don't want to use node->is_folder() because that would let the
-      // user edit "Bookmarks Bar" and "Other Bookmarks".
-      bookmark_utils::IS_EDITABLE, node->type() == BookmarkNode::FOLDER,
-      -1);
+  gtk_tree_store_set(store,
+                     iter,
+                     FOLDER_ICON,
+                     GtkThemeService::GetFolderIcon(true).ToGdkPixbuf(),
+                     FOLDER_NAME,
+                     UTF16ToUTF8(node->GetTitle()).c_str(),
+                     ITEM_ID,
+                     node->id(),
+                     // We don't want to use node->is_folder() because that
+                     // would let the
+                     // user edit "Bookmarks Bar" and "Other Bookmarks".
+                     IS_EDITABLE,
+                     node->type() == BookmarkNode::FOLDER,
+                     -1);
 }
 
 // Helper function for CommitTreeStoreDifferencesBetween() which recursively
@@ -56,11 +60,9 @@
   if (gtk_tree_model_iter_children(GTK_TREE_MODEL(tree_store), &child_iter,
                                    parent_iter)) {
     do {
-      int64 id = bookmark_utils::GetIdFromTreeIter(GTK_TREE_MODEL(tree_store),
-                                                   &child_iter);
+      int64 id = GetIdFromTreeIter(GTK_TREE_MODEL(tree_store), &child_iter);
       string16 title =
-          bookmark_utils::GetTitleFromTreeIter(GTK_TREE_MODEL(tree_store),
-                                               &child_iter);
+          GetTitleFromTreeIter(GTK_TREE_MODEL(tree_store), &child_iter);
       const BookmarkNode* child_bb_node = NULL;
       if (id == 0) {
         child_bb_node = bb_model->AddFolder(
@@ -71,8 +73,7 @@
         GValue value  = { 0 };
         g_value_init(&value, G_TYPE_INT64);
         g_value_set_int64(&value, child_bb_node->id());
-        gtk_tree_store_set_value(tree_store, &child_iter,
-                                 bookmark_utils::ITEM_ID, &value);
+        gtk_tree_store_set_value(tree_store, &child_iter, ITEM_ID, &value);
       } else {
         // Existing node, reset the title (BookmarkModel ignores changes if the
         // title is the same).
@@ -100,16 +101,13 @@
   gboolean rv = gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store),
                                         &folder_iter, tree_path);
   DCHECK(rv);
-  gtk_tree_store_set(tree_store, &folder_iter,
-                     bookmark_utils::FOLDER_NAME, new_folder_name,
-                     -1);
+  gtk_tree_store_set(
+      tree_store, &folder_iter, FOLDER_NAME, new_folder_name, -1);
   gtk_tree_path_free(tree_path);
 }
 
 }  // namespace
 
-namespace bookmark_utils {
-
 GtkTreeStore* MakeFolderTreeStore() {
   return gtk_tree_store_new(FOLDER_STORE_NUM_COLUMNS, GDK_TYPE_PIXBUF,
                             G_TYPE_STRING, G_TYPE_INT64, G_TYPE_BOOLEAN);
@@ -243,5 +241,3 @@
 
   return ret_val;
 }
-
-}  // namespace bookmark_utils
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.h b/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.h
index e0d9f9a..9137e45 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.h
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_tree_model.h
@@ -19,8 +19,6 @@
 typedef struct _GdkPixbuf GdkPixbuf;
 typedef struct _GtkWidget GtkWidget;
 
-namespace bookmark_utils {
-
 enum FolderTreeStoreColumns {
   FOLDER_ICON,
   FOLDER_NAME,
@@ -71,6 +69,4 @@
 // Returns the title field in utf8 of the row pointed to by |iter|.
 string16 GetTitleFromTreeIter(GtkTreeModel* model, GtkTreeIter* iter);
 
-}  // namespace bookmark_utils
-
 #endif  // CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_TREE_MODEL_H_
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.cc
index 367092c..8b9ab4a 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.cc
@@ -57,8 +57,11 @@
 }
 
 // Creates the widget hierarchy for a bookmark button.
-void PackButton(GdkPixbuf* pixbuf, const string16& title, bool ellipsize,
-                GtkThemeService* provider, GtkWidget* button) {
+void PackButton(GdkPixbuf* pixbuf,
+                const string16& title,
+                bool ellipsize,
+                GtkThemeService* provider,
+                GtkWidget* button) {
   GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(button));
   if (former_child)
     gtk_container_remove(GTK_CONTAINER(button), former_child);
@@ -84,7 +87,7 @@
     }
 
     gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
-    bookmark_utils::SetButtonTextColors(label, provider);
+    SetButtonTextColors(label, provider);
   }
 
   GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
@@ -157,19 +160,17 @@
   return TRUE;
 }
 
-void OnDragIconDestroy(GtkWidget* drag_icon,
-                       DragRepresentationData* data) {
+void OnDragIconDestroy(GtkWidget* drag_icon, DragRepresentationData* data) {
   g_object_unref(drag_icon);
   delete data;
 }
 
 }  // namespace
 
-namespace bookmark_utils {
-
 const char kBookmarkNode[] = "bookmark-node";
 
-GdkPixbuf* GetPixbufForNode(const BookmarkNode* node, BookmarkModel* model,
+GdkPixbuf* GetPixbufForNode(const BookmarkNode* node,
+                            BookmarkModel* model,
                             bool native) {
   GdkPixbuf* pixbuf;
 
@@ -239,10 +240,12 @@
   return widget;
 }
 
-void ConfigureButtonForNode(const BookmarkNode* node, BookmarkModel* model,
-                            GtkWidget* button, GtkThemeService* provider) {
-  GdkPixbuf* pixbuf = bookmark_utils::GetPixbufForNode(
-      node, model, provider->UsingNativeTheme());
+void ConfigureButtonForNode(const BookmarkNode* node,
+                            BookmarkModel* model,
+                            GtkWidget* button,
+                            GtkThemeService* provider) {
+  GdkPixbuf* pixbuf =
+      GetPixbufForNode(node, model, provider->UsingNativeTheme());
   PackButton(pixbuf, node->GetTitle(), node != model->other_node(), provider,
              button);
   g_object_unref(pixbuf);
@@ -251,8 +254,7 @@
   if (!tooltip.empty())
     gtk_widget_set_tooltip_markup(button, tooltip.c_str());
 
-  g_object_set_data(G_OBJECT(button), bookmark_utils::kBookmarkNode,
-                    AsVoid(node));
+  g_object_set_data(G_OBJECT(button), kBookmarkNode, AsVoid(node));
 }
 
 void ConfigureAppsShortcutButton(GtkWidget* button, GtkThemeService* provider) {
@@ -288,7 +290,7 @@
 
 const BookmarkNode* BookmarkNodeForWidget(GtkWidget* widget) {
   return reinterpret_cast<const BookmarkNode*>(
-      g_object_get_data(G_OBJECT(widget), bookmark_utils::kBookmarkNode));
+      g_object_get_data(G_OBJECT(widget), kBookmarkNode));
 }
 
 void SetButtonTextColors(GtkWidget* label, GtkThemeService* provider) {
@@ -439,7 +441,9 @@
 }
 
 bool CreateNewBookmarkFromNamedUrl(GtkSelectionData* selection_data,
-    BookmarkModel* model, const BookmarkNode* parent, int idx) {
+                                   BookmarkModel* model,
+                                   const BookmarkNode* parent,
+                                   int idx) {
   GURL url;
   string16 title;
   if (!ui::ExtractNamedURL(selection_data, &url, &title))
@@ -450,7 +454,9 @@
 }
 
 bool CreateNewBookmarksFromURIList(GtkSelectionData* selection_data,
-    BookmarkModel* model, const BookmarkNode* parent, int idx) {
+                                   BookmarkModel* model,
+                                   const BookmarkNode* parent,
+                                   int idx) {
   std::vector<GURL> urls;
   ui::ExtractURIList(selection_data, &urls);
   for (size_t i = 0; i < urls.size(); ++i) {
@@ -461,7 +467,9 @@
 }
 
 bool CreateNewBookmarkFromNetscapeURL(GtkSelectionData* selection_data,
-    BookmarkModel* model, const BookmarkNode* parent, int idx) {
+                                      BookmarkModel* model,
+                                      const BookmarkNode* parent,
+                                      int idx) {
   GURL url;
   string16 title;
   if (!ui::ExtractNetscapeURL(selection_data, &url, &title))
@@ -483,5 +491,3 @@
     return l10n_util::GetStringUTF16(IDS_APP_UNTITLED_SHORTCUT_FILE_NAME);
   }
 }
-
-}  // namespace bookmark_utils
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h b/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h
index a3a8224..edaedc2 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h
@@ -22,13 +22,12 @@
 typedef struct _GtkSelectionData GtkSelectionData;
 typedef struct _GtkWidget GtkWidget;
 
-namespace bookmark_utils {
-
 extern const char kBookmarkNode[];
 
 // Get the image that is used to represent the node. This function adds a ref
 // to the returned pixbuf, so it requires a matching call to g_object_unref().
-GdkPixbuf* GetPixbufForNode(const BookmarkNode* node, BookmarkModel* model,
+GdkPixbuf* GetPixbufForNode(const BookmarkNode* node,
+                            BookmarkModel* model,
                             bool native);
 
 // Returns a GtkWindow with a visual hierarchy for passing to
@@ -42,8 +41,10 @@
 
 // Helper function that sets visual properties of GtkButton |button| to the
 // contents of |node|.
-void ConfigureButtonForNode(const BookmarkNode* node, BookmarkModel* model,
-                            GtkWidget* button, GtkThemeService* provider);
+void ConfigureButtonForNode(const BookmarkNode* node,
+                            BookmarkModel* model,
+                            GtkWidget* button,
+                            GtkThemeService* provider);
 
 // Helper function to set the visual properties for the apps page shortcut
 // |button|.
@@ -91,31 +92,26 @@
 
 // Unpickle a new bookmark of the CHROME_NAMED_URL drag type, and put it in
 // the appropriate location in the model.
-bool CreateNewBookmarkFromNamedUrl(
-    GtkSelectionData* selection_data,
-    BookmarkModel* model,
-    const BookmarkNode* parent,
-    int idx);
+bool CreateNewBookmarkFromNamedUrl(GtkSelectionData* selection_data,
+                                   BookmarkModel* model,
+                                   const BookmarkNode* parent,
+                                   int idx);
 
 // Add the URIs in |selection_data| into the model at the given position. They
 // will be added whether or not the URL is valid.
-bool CreateNewBookmarksFromURIList(
-    GtkSelectionData* selection_data,
-    BookmarkModel* model,
-    const BookmarkNode* parent,
-    int idx);
+bool CreateNewBookmarksFromURIList(GtkSelectionData* selection_data,
+                                   BookmarkModel* model,
+                                   const BookmarkNode* parent,
+                                   int idx);
 
 // Add the "url\ntitle" combination into the model at the given position.
-bool CreateNewBookmarkFromNetscapeURL(
-    GtkSelectionData* selection_data,
-    BookmarkModel* model,
-    const BookmarkNode* parent,
-    int idx);
+bool CreateNewBookmarkFromNetscapeURL(GtkSelectionData* selection_data,
+                                      BookmarkModel* model,
+                                      const BookmarkNode* parent,
+                                      int idx);
 
 // Returns a name for the given URL. Used for drags into bookmark areas when
 // the source doesn't specify a title.
 string16 GetNameForURL(const GURL& url);
 
-}  // namespace bookmark_utils
-
 #endif  // CHROME_BROWSER_UI_GTK_BOOKMARKS_BOOKMARK_UTILS_GTK_H_
diff --git a/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk_unittest.cc b/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk_unittest.cc
index 1b88bbd..1b4df24 100644
--- a/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk_unittest.cc
@@ -2,42 +2,42 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
+
 #include <string>
+
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/dragdrop/gtk_dnd_util.h"
 #include "url/gurl.h"
 
 TEST(BookmarkUtilsGtkTest, GetNodesFromSelectionInvalid) {
   std::vector<const BookmarkNode*> nodes;
-  nodes = bookmark_utils::GetNodesFromSelection(NULL, NULL, 0, NULL, NULL,
-                                                NULL);
+  nodes = GetNodesFromSelection(NULL, NULL, 0, NULL, NULL, NULL);
   EXPECT_EQ(0u, nodes.size());
 
   GtkSelectionData data;
   data.data = NULL;
   data.length = 0;
-  nodes = bookmark_utils::GetNodesFromSelection(NULL, &data, 0, NULL, NULL,
-                                                NULL);
+  nodes = GetNodesFromSelection(NULL, &data, 0, NULL, NULL, NULL);
   EXPECT_EQ(0u, nodes.size());
 
-  nodes = bookmark_utils::GetNodesFromSelection(NULL, NULL,
-      ui::CHROME_BOOKMARK_ITEM, NULL, NULL, NULL);
+  nodes = GetNodesFromSelection(
+      NULL, NULL, ui::CHROME_BOOKMARK_ITEM, NULL, NULL, NULL);
   EXPECT_EQ(0u, nodes.size());
 
   data.data = NULL;
   data.length = 0;
-  nodes = bookmark_utils::GetNodesFromSelection(NULL, &data,
-      ui::CHROME_BOOKMARK_ITEM, NULL, NULL, NULL);
+  nodes = GetNodesFromSelection(
+      NULL, &data, ui::CHROME_BOOKMARK_ITEM, NULL, NULL, NULL);
   EXPECT_EQ(0u, nodes.size());
 
   guchar test_data[] = "";
   data.data = test_data;
   data.length = 0;
-  nodes = bookmark_utils::GetNodesFromSelection(NULL, &data,
-      ui::CHROME_BOOKMARK_ITEM, NULL, NULL, NULL);
+  nodes = GetNodesFromSelection(
+      NULL, &data, ui::CHROME_BOOKMARK_ITEM, NULL, NULL, NULL);
   EXPECT_EQ(0u, nodes.size());
 }
 
@@ -47,7 +47,7 @@
   GtkSelectionData data;
   data.data = NULL;
   data.length = 0;
-  bookmark_utils::WriteBookmarkToSelection(&x, &data, ui::TEXT_HTML, NULL);
+  WriteBookmarkToSelection(&x, &data, ui::TEXT_HTML, NULL);
   std::string selection(reinterpret_cast<char*>(data.data), data.length);
   EXPECT_EQ("<a href=\"http://www.google.com/\">Google</a>", selection);
 
diff --git a/chrome/browser/ui/gtk/browser_toolbar_gtk.cc b/chrome/browser/ui/gtk/browser_toolbar_gtk.cc
index 0575a3e..ed004be 100644
--- a/chrome/browser/ui/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_toolbar_gtk.cc
@@ -98,7 +98,6 @@
 BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser, BrowserWindowGtk* window)
     : toolbar_(NULL),
       location_bar_(new LocationBarViewGtk(browser)),
-      model_(browser->toolbar_model()),
       is_wrench_menu_model_valid_(true),
       browser_(browser),
       window_(window),
@@ -428,9 +427,8 @@
 
 // BrowserToolbarGtk, public ---------------------------------------------------
 
-void BrowserToolbarGtk::UpdateWebContents(WebContents* contents,
-                                          bool should_restore_state) {
-  location_bar_->Update(should_restore_state ? contents : NULL);
+void BrowserToolbarGtk::UpdateWebContents(WebContents* contents) {
+  location_bar_->Update(contents);
 
   if (actions_toolbar_.get())
     actions_toolbar_->Update();
diff --git a/chrome/browser/ui/gtk/browser_toolbar_gtk.h b/chrome/browser/ui/gtk/browser_toolbar_gtk.h
index 9c21f56..bc3bc1f 100644
--- a/chrome/browser/ui/gtk/browser_toolbar_gtk.h
+++ b/chrome/browser/ui/gtk/browser_toolbar_gtk.h
@@ -33,7 +33,6 @@
 class LocationBar;
 class LocationBarViewGtk;
 class ReloadButtonGtk;
-class ToolbarModel;
 
 namespace content {
 class WebContents;
@@ -109,8 +108,7 @@
   bool IsWrenchMenuShowing() const;
 
   // Message that we should react to a state change.
-  void UpdateWebContents(content::WebContents* contents,
-                         bool should_restore_state);
+  void UpdateWebContents(content::WebContents* contents);
 
  private:
   void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& host);
@@ -192,9 +190,6 @@
   // The image shown in GTK+ mode in the wrench button.
   GtkWidget* wrench_menu_image_;
 
-  // The model that contains the security level, text, icon to display...
-  ToolbarModel* model_;
-
   GtkThemeService* theme_service_;
 
   scoped_ptr<MenuGtk> wrench_menu_;
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc
index 93a08dc..47fa0e7 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.cc
+++ b/chrome/browser/ui/gtk/browser_window_gtk.cc
@@ -908,10 +908,9 @@
       force);
 }
 
-void BrowserWindowGtk::UpdateToolbar(content::WebContents* contents,
-                                     bool should_restore_state) {
+void BrowserWindowGtk::UpdateToolbar(content::WebContents* contents) {
   TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::UpdateToolbar");
-  toolbar_->UpdateWebContents(contents, should_restore_state);
+  toolbar_->UpdateWebContents(contents);
 }
 
 void BrowserWindowGtk::FocusToolbar() {
@@ -1073,12 +1072,15 @@
     // 1. The logic is a little complicated.
     // 2. We should be careful not to introduce any accelerators that trigger
     //    customized code instead of browser commands.
+    bool original_block_command_state =
+        browser_->command_controller()->block_command_execution();
     browser_->command_controller()->SetBlockCommandExecution(true);
     gtk_window_activate_key(window_, os_event);
     // We don't need to care about the WindowOpenDisposition value,
     // because all commands executed in this path use the default value.
     id = browser_->command_controller()->GetLastBlockedCommand(NULL);
-    browser_->command_controller()->SetBlockCommandExecution(false);
+    browser_->command_controller()->SetBlockCommandExecution(
+        original_block_command_state);
   }
 
   if (id == -1)
@@ -1154,8 +1156,8 @@
 void BrowserWindowGtk::ShowAvatarBubble(WebContents* web_contents,
                                         const gfx::Rect& rect) {
   GtkWidget* widget = web_contents->GetView()->GetContentNativeView();
-  new AvatarMenuBubbleGtk(browser_.get(), widget,
-      BubbleGtk::ANCHOR_TOP_LEFT, &rect);
+  new AvatarMenuBubbleGtk(browser_.get(), widget, BubbleGtk::ANCHOR_TOP_RIGHT,
+                          &rect);
 }
 
 void BrowserWindowGtk::ShowAvatarBubbleFromAvatarButton() {
@@ -1176,8 +1178,13 @@
   new PasswordGenerationBubbleGtk(rect, form, web_contents, password_generator);
 }
 
-void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads() {
-  DownloadInProgressDialogGtk::Show(browser(), GetNativeWindow());
+void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads(
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  DownloadInProgressDialogGtk::Show(
+      GetNativeWindow(), download_count, dialog_type, app_modal, callback);
 }
 
 void BrowserWindowGtk::Observe(int type,
@@ -1521,7 +1528,7 @@
 }
 
 WebContents* BrowserWindowGtk::GetDisplayedTab() {
-  return contents_container_->GetVisibleTab();
+  return contents_container_->tab();
 }
 
 void BrowserWindowGtk::QueueToolbarRedraw() {
@@ -1927,9 +1934,6 @@
     bookmark_bar_->SetPageNavigator(browser_.get());
 
   BookmarkBar::State state = browser_->bookmark_bar_state();
-  if (contents_container_->HasOverlay() && state == BookmarkBar::DETACHED)
-    state = BookmarkBar::HIDDEN;
-
   toolbar_->UpdateForBookmarkBarVisibility(state == BookmarkBar::DETACHED);
   PlaceBookmarkBar(state == BookmarkBar::DETACHED);
   bookmark_bar_->SetBookmarkBarState(
diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h
index 7b44b8c..dadf6ca 100644
--- a/chrome/browser/ui/gtk/browser_window_gtk.h
+++ b/chrome/browser/ui/gtk/browser_window_gtk.h
@@ -114,8 +114,7 @@
   virtual LocationBar* GetLocationBar() const OVERRIDE;
   virtual void SetFocusToLocationBar(bool select_all) OVERRIDE;
   virtual void UpdateReloadStopState(bool is_loading, bool force) OVERRIDE;
-  virtual void UpdateToolbar(content::WebContents* contents,
-                             bool should_restore_state) OVERRIDE;
+  virtual void UpdateToolbar(content::WebContents* contents) OVERRIDE;
   virtual void FocusToolbar() OVERRIDE;
   virtual void FocusAppMenu() OVERRIDE;
   virtual void FocusBookmarksToolbar() OVERRIDE;
@@ -141,7 +140,11 @@
 #endif
   virtual bool IsDownloadShelfVisible() const OVERRIDE;
   virtual DownloadShelf* GetDownloadShelf() OVERRIDE;
-  virtual void ConfirmBrowserCloseWithPendingDownloads() OVERRIDE;
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) OVERRIDE;
   virtual void UserChangedTheme() OVERRIDE;
   virtual int GetExtraRenderViewHeight() const OVERRIDE;
   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
diff --git a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc
index 74d9781..aa9e25e 100644
--- a/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/content_setting_bubble_gtk.cc
@@ -32,6 +32,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/text/text_elider.h"
+#include "ui/gfx/font.h"
 #include "ui/gfx/gtk_util.h"
 
 using content::PluginService;
diff --git a/chrome/browser/ui/gtk/custom_drag.cc b/chrome/browser/ui/gtk/custom_drag.cc
index 2a690f6..027fcd7 100644
--- a/chrome/browser/ui/gtk/custom_drag.cc
+++ b/chrome/browser/ui/gtk/custom_drag.cc
@@ -167,21 +167,19 @@
 
 BookmarkDrag::BookmarkDrag(Profile* profile,
                            const std::vector<const BookmarkNode*>& nodes)
-    : CustomDrag(NULL,
-                 bookmark_utils::GetCodeMask(false),
-                 kBookmarkDragAction),
+    : CustomDrag(NULL, GetCodeMask(false), kBookmarkDragAction),
       profile_(profile),
-      nodes_(nodes) {
-}
+      nodes_(nodes) {}
 
 BookmarkDrag::~BookmarkDrag() {
 }
 
-void BookmarkDrag::OnDragDataGet(GtkWidget* widget, GdkDragContext* context,
+void BookmarkDrag::OnDragDataGet(GtkWidget* widget,
+                                 GdkDragContext* context,
                                  GtkSelectionData* selection_data,
-                                 guint target_type, guint time) {
-  bookmark_utils::WriteBookmarksToSelection(nodes_, selection_data,
-                                            target_type, profile_);
+                                 guint target_type,
+                                 guint time) {
+  WriteBookmarksToSelection(nodes_, selection_data, target_type, profile_);
 }
 
 // static
diff --git a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc
index e188a58..b047ea1 100644
--- a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.cc
@@ -6,28 +6,33 @@
 
 #include <gtk/gtk.h>
 
+#include "base/callback.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
 // static
-void DownloadInProgressDialogGtk::Show(Browser* browser,
-                                       gfx::NativeWindow parent_window) {
-  new DownloadInProgressDialogGtk(browser, parent_window);
+void DownloadInProgressDialogGtk::Show(
+    gfx::NativeWindow parent_window,
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  new DownloadInProgressDialogGtk(parent_window, download_count, dialog_type,
+                                  app_modal, callback);
 }
 
 DownloadInProgressDialogGtk::DownloadInProgressDialogGtk(
-    Browser* browser,
-    gfx::NativeWindow parent_window)
-    : browser_(browser) {
-  int download_count;
-  Browser::DownloadClosePreventionType dialog_type =
-      browser_->OkToCloseWithInProgressDownloads(&download_count);
-
+    gfx::NativeWindow parent_window,
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback)
+    : app_modal_(app_modal),
+      callback_(callback) {
   std::string title_text;
   std::string explanation_text;
   std::string ok_button_text;
@@ -71,6 +76,8 @@
   std::string cancel_button_text = l10n_util::GetStringUTF8(
       IDS_DOWNLOAD_REMOVE_CONFIRM_CANCEL_BUTTON_LABEL);
 
+  if (app_modal_)
+    gtk_util::MakeAppModalWindowGroup();
   GtkWidget* dialog = gtk_message_dialog_new(
       parent_window,
       static_cast<GtkDialogFlags>(GTK_DIALOG_MODAL),
@@ -98,6 +105,8 @@
 void DownloadInProgressDialogGtk::OnResponse(GtkWidget* dialog,
                                              int response_id) {
   gtk_widget_destroy(dialog);
-  browser_->InProgressDownloadResponse(response_id == GTK_RESPONSE_ACCEPT);
+  if (app_modal_)
+    gtk_util::AppModalDismissedUngroupWindows();
+  callback_.Run(response_id == GTK_RESPONSE_ACCEPT);
   delete this;
 }
diff --git a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h
index 6eb439e..b45ab48 100644
--- a/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h
+++ b/chrome/browser/ui/gtk/download/download_in_progress_dialog_gtk.h
@@ -6,23 +6,30 @@
 #define CHROME_BROWSER_UI_GTK_DOWNLOAD_DOWNLOAD_IN_PROGRESS_DIALOG_GTK_H_
 
 #include "base/basictypes.h"
+#include "chrome/browser/ui/browser.h"
 #include "ui/base/gtk/gtk_signal.h"
 #include "ui/gfx/native_widget_types.h"
 
-class Browser;
-
 class DownloadInProgressDialogGtk {
  public:
-  static void Show(Browser* browser, gfx::NativeWindow parent_window);
+  static void Show(gfx::NativeWindow parent_window,
+                   int download_count,
+                   Browser::DownloadClosePreventionType dialog_type,
+                   bool app_modal,
+                   const base::Callback<void(bool)>& callback);
 
  private:
-  explicit DownloadInProgressDialogGtk(Browser* browser,
-                                       gfx::NativeWindow parent_window);
+  DownloadInProgressDialogGtk(gfx::NativeWindow parent_window,
+                              int download_count,
+                              Browser::DownloadClosePreventionType dialog_type,
+                              bool app_modal,
+                              const base::Callback<void(bool)>& callback);
   ~DownloadInProgressDialogGtk();
 
   CHROMEGTK_CALLBACK_1(DownloadInProgressDialogGtk, void, OnResponse, int);
 
-  Browser* browser_;
+  const bool app_modal_;
+  const base::Callback<void(bool)> callback_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadInProgressDialogGtk);
 };
diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.cc b/chrome/browser/ui/gtk/location_bar_view_gtk.cc
index 95693c2..fe478aa 100644
--- a/chrome/browser/ui/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/ui/gtk/location_bar_view_gtk.cc
@@ -21,6 +21,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/accessibility/accessibility_events.h"
+#include "chrome/browser/accessibility/accessibility_extension_api.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
@@ -82,6 +83,7 @@
 #include "grit/theme_resources.h"
 #include "net/base/net_util.h"
 #include "ui/base/accelerators/platform_accelerator_gtk.h"
+#include "ui/base/accessibility/accessibility_types.h"
 #include "ui/base/dragdrop/gtk_dnd_util.h"
 #include "ui/base/gtk/gtk_hig_constants.h"
 #include "ui/base/gtk/gtk_signal_registrar.h"
@@ -174,7 +176,7 @@
                                    public BubbleDelegateGtk {
  public:
   ContentSettingImageViewGtk(ContentSettingsType content_type,
-                             const LocationBarViewGtk* parent);
+                             LocationBarViewGtk* parent);
   virtual ~ContentSettingImageViewGtk();
 
   // PageToolViewGtk
@@ -194,6 +196,9 @@
   virtual void BubbleClosing(BubbleGtk* bubble,
                              bool closed_by_escape) OVERRIDE;
 
+  // The owning LocationBarViewGtk.
+  LocationBarViewGtk* parent_;
+
   scoped_ptr<ContentSettingImageModel> content_setting_image_model_;
 
   // The currently shown bubble if any.
@@ -204,8 +209,9 @@
 
 ContentSettingImageViewGtk::ContentSettingImageViewGtk(
     ContentSettingsType content_type,
-    const LocationBarViewGtk* parent)
-    : PageToolViewGtk(parent),
+    LocationBarViewGtk* parent)
+    : PageToolViewGtk(),
+      parent_(parent),
       content_setting_image_model_(
           ContentSettingImageModel::CreateContentSettingImageModel(
               content_type)),
@@ -349,7 +355,6 @@
       tab_to_search_hint_icon_(NULL),
       tab_to_search_hint_trailing_label_(NULL),
       command_updater_(browser->command_controller()->command_updater()),
-      toolbar_model_(browser->toolbar_model()),
       browser_(browser),
       disposition_(CURRENT_TAB),
       transition_(content::PageTransitionFromInt(
@@ -390,8 +395,9 @@
   gtk_widget_set_redraw_on_allocate(hbox_.get(), TRUE);
 
   // Now initialize the OmniboxViewGtk.
-  location_entry_.reset(new OmniboxViewGtk(this, toolbar_model_, browser_,
-      browser_->profile(), command_updater_, popup_window_mode_, hbox_.get()));
+  location_entry_.reset(new OmniboxViewGtk(this, browser_, browser_->profile(),
+                                           command_updater_, popup_window_mode_,
+                                           hbox_.get()));
   location_entry_->Init();
 
   g_signal_connect(hbox_.get(), "expose-event",
@@ -613,10 +619,18 @@
                                       ui::CHROME_NAMED_URL);
 }
 
-WebContents* LocationBarViewGtk::GetWebContents() const {
+WebContents* LocationBarViewGtk::GetWebContents() {
   return browser_->tab_strip_model()->GetActiveWebContents();
 }
 
+ToolbarModel* LocationBarViewGtk::GetToolbarModel() {
+  return browser_->toolbar_model();
+}
+
+const ToolbarModel* LocationBarViewGtk::GetToolbarModel() const {
+  return browser_->toolbar_model();
+}
+
 void LocationBarViewGtk::SetPreviewEnabledPageAction(
     ExtensionAction* page_action,
     bool preview_enabled) {
@@ -791,9 +805,9 @@
   // This is identical to the Windows code, except that we don't proxy the call
   // back through the Toolbar, and just access the model here.
   // The edit should make sure we're only notified when something changes.
-  DCHECK(toolbar_model_->GetInputInProgress() != in_progress);
+  DCHECK_NE(GetToolbarModel()->input_in_progress(), in_progress);
 
-  toolbar_model_->SetInputInProgress(in_progress);
+  GetToolbarModel()->set_input_in_progress(in_progress);
   Update(NULL);
 }
 
@@ -807,21 +821,21 @@
       l10n_util::GetStringUTF8(IDS_ACCNAME_LOCATION),
       std::string(),
       false);
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED,
-      content::Source<Profile>(profile),
-      content::Details<AccessibilityTextBoxInfo>(&info));
+  ExtensionAccessibilityEventRouter::GetInstance()->HandleControlEvent(
+      ui::AccessibilityTypes::EVENT_FOCUS,
+      &info);
 
   // Update the keyword and search hint states.
   OnChanged();
 }
 
 gfx::Image LocationBarViewGtk::GetFavicon() const {
-  return FaviconTabHelper::FromWebContents(GetWebContents())->GetFavicon();
+  return FaviconTabHelper::FromWebContents(
+      browser_->tab_strip_model()->GetActiveWebContents())->GetFavicon();
 }
 
 string16 LocationBarViewGtk::GetTitle() const {
-  return GetWebContents()->GetTitle();
+  return browser_->tab_strip_model()->GetActiveWebContents()->GetTitle();
 }
 
 InstantController* LocationBarViewGtk::GetInstant() {
@@ -870,8 +884,8 @@
   for (ScopedVector<PageToolViewGtk>::iterator i(
            content_setting_views_.begin());
        i != content_setting_views_.end(); ++i) {
-    (*i)->Update(
-        toolbar_model_->GetInputInProgress() ? NULL : GetWebContents());
+    (*i)->Update(GetToolbarModel()->input_in_progress() ?
+        NULL : GetWebContents());
     any_visible = (*i)->IsVisible() || any_visible;
   }
 
@@ -916,7 +930,7 @@
 
     for (size_t i = 0; i < page_action_views_.size(); i++) {
       page_action_views_[i]->UpdateVisibility(
-          toolbar_model_->GetInputInProgress() ? NULL : contents, url);
+          GetToolbarModel()->input_in_progress() ? NULL : contents, url);
     }
     gtk_widget_queue_draw(hbox_.get());
   }
@@ -1190,7 +1204,7 @@
       GTK_IMAGE(location_icon_image_),
       theme_service_->GetImageNamed(resource_id).ToGdkPixbuf());
 
-  if (toolbar_model_->GetSecurityLevel(false) == ToolbarModel::EV_SECURE) {
+  if (GetToolbarModel()->GetSecurityLevel(false) == ToolbarModel::EV_SECURE) {
     if (!gtk_util::IsActingAsRoundedWindow(site_type_event_box_)) {
       // Fun fact: If wee try to make |site_type_event_box_| act as a
       // rounded window while it doesn't have a visible window, GTK interprets
@@ -1206,7 +1220,7 @@
                                    gtk_util::BORDER_ALL);
     }
 
-    string16 info_text = toolbar_model_->GetEVCertName();
+    string16 info_text = GetToolbarModel()->GetEVCertName();
     gtk_label_set_text(GTK_LABEL(security_info_label_),
                        UTF16ToUTF8(info_text).c_str());
 
@@ -1371,7 +1385,8 @@
     if (event->x == 0 && event->y == 0)
       return FALSE;
 
-    NavigationEntry* nav_entry = tab->GetController().GetActiveEntry();
+    // Important to use GetVisibleEntry to match what's showing in the omnibox.
+    NavigationEntry* nav_entry = tab->GetController().GetVisibleEntry();
     if (!nav_entry) {
       NOTREACHED();
       return FALSE;
@@ -1413,8 +1428,8 @@
   gfx::Image favicon = GetFavicon();
   if (favicon.IsEmpty())
     return;
-  drag_icon_ = bookmark_utils::GetDragRepresentation(favicon.ToGdkPixbuf(),
-      GetTitle(), theme_service_);
+  drag_icon_ =
+      GetDragRepresentation(favicon.ToGdkPixbuf(), GetTitle(), theme_service_);
   gtk_drag_set_icon_widget(context, drag_icon_, 0, 0);
 
   WebContents* tab = GetWebContents();
@@ -1507,7 +1522,7 @@
 }
 
 void LocationBarViewGtk::ShowZoomBubble() {
-  if (toolbar_model_->GetInputInProgress() || !GetWebContents())
+  if (GetToolbarModel()->input_in_progress() || !GetWebContents())
     return;
 
   ZoomBubbleGtk::ShowBubble(GetWebContents(), true);
@@ -1551,7 +1566,7 @@
   ZoomController* zoom_controller =
       ZoomController::FromWebContents(web_contents);
   if (!zoom_controller || zoom_controller->IsAtDefaultZoom() ||
-      toolbar_model_->GetInputInProgress()) {
+      GetToolbarModel()->input_in_progress()) {
     gtk_widget_hide(zoom_.get());
     ZoomBubbleGtk::CloseBubble();
     return;
@@ -1591,8 +1606,8 @@
   // Indicate the star icon is not correctly sized. It will be marked as sized
   // when the next size-allocate signal is received by the star widget.
   star_sized_ = false;
-  bool star_enabled = !toolbar_model_->GetInputInProgress() &&
-                      edit_bookmarks_enabled_.GetValue();
+  bool star_enabled = !GetToolbarModel()->input_in_progress() &&
+      edit_bookmarks_enabled_.GetValue();
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
                                          star_enabled);
@@ -1677,14 +1692,12 @@
 ////////////////////////////////////////////////////////////////////////////////
 // LocationBarViewGtk::PageToolViewGtk
 
-LocationBarViewGtk::PageToolViewGtk::PageToolViewGtk(
-    const LocationBarViewGtk* parent)
+LocationBarViewGtk::PageToolViewGtk::PageToolViewGtk()
     : alignment_(gtk_alignment_new(0, 0, 1, 1)),
       event_box_(gtk_event_box_new()),
       hbox_(gtk_hbox_new(FALSE, InnerPadding())),
       image_(gtk_image_new()),
       label_(gtk_label_new(NULL)),
-      parent_(parent),
       animation_(this),
       weak_factory_(this) {
   gtk_alignment_set_padding(GTK_ALIGNMENT(alignment_.get()), 1, 1, 0, 0);
diff --git a/chrome/browser/ui/gtk/location_bar_view_gtk.h b/chrome/browser/ui/gtk/location_bar_view_gtk.h
index b8dc178..f728a89 100644
--- a/chrome/browser/ui/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/ui/gtk/location_bar_view_gtk.h
@@ -43,7 +43,6 @@
 class ExtensionAction;
 class GtkThemeService;
 class OmniboxViewGtk;
-class ToolbarModel;
 
 namespace content {
 class WebContents;
@@ -121,7 +120,9 @@
   virtual gfx::Image GetFavicon() const OVERRIDE;
   virtual string16 GetTitle() const OVERRIDE;
   virtual InstantController* GetInstant() OVERRIDE;
-  virtual content::WebContents* GetWebContents() const OVERRIDE;
+  virtual content::WebContents* GetWebContents() OVERRIDE;
+  virtual ToolbarModel* GetToolbarModel() OVERRIDE;
+  virtual const ToolbarModel* GetToolbarModel() const OVERRIDE;
 
   // LocationBar:
   virtual void ShowFirstRunBubble() OVERRIDE;
@@ -162,7 +163,7 @@
   // location bar.
   class PageToolViewGtk : public ui::AnimationDelegate {
    public:
-    explicit PageToolViewGtk(const LocationBarViewGtk* parent);
+    PageToolViewGtk();
     virtual ~PageToolViewGtk();
 
     GtkWidget* widget();
@@ -202,9 +203,6 @@
     // Explanatory text (e.g. "popup blocked").
     ui::OwnedWidgetGtk label_;
 
-    // The owning LocationBarViewGtk.
-    const LocationBarViewGtk* parent_;
-
     // When we show explanatory text, we slide it in/out.
     ui::SlideAnimation animation_;
 
@@ -482,7 +480,6 @@
   GtkWidget* location_entry_alignment_;
 
   CommandUpdater* command_updater_;
-  ToolbarModel* toolbar_model_;
   Browser* browser_;
 
   // When we get an OnAutocompleteAccept notification from the autocomplete
diff --git a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
index 15fa357..28e0462 100644
--- a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
+++ b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.cc
@@ -176,13 +176,12 @@
 }  // namespace
 
 OmniboxViewGtk::OmniboxViewGtk(OmniboxEditController* controller,
-                               ToolbarModel* toolbar_model,
                                Browser* browser,
                                Profile* profile,
                                CommandUpdater* command_updater,
                                bool popup_window_mode,
                                GtkWidget* location_bar)
-    : OmniboxView(profile, controller, toolbar_model, command_updater),
+    : OmniboxView(profile, controller, command_updater),
       browser_(browser),
       text_view_(NULL),
       tag_table_(NULL),
@@ -453,11 +452,11 @@
 
 void OmniboxViewGtk::Update(const WebContents* contents) {
   // NOTE: We're getting the URL text here from the ToolbarModel.
-  bool visibly_changed_permanent_text =
-      model()->UpdatePermanentText(toolbar_model()->GetText(true));
+  bool visibly_changed_permanent_text = model()->UpdatePermanentText(
+      controller()->GetToolbarModel()->GetText(true));
 
   ToolbarModel::SecurityLevel security_level =
-        toolbar_model()->GetSecurityLevel(false);
+        controller()->GetToolbarModel()->GetSecurityLevel(false);
   bool changed_security_level = (security_level != security_level_);
   security_level_ = security_level;
 
@@ -1261,8 +1260,8 @@
                      G_CALLBACK(HandleCopyURLClipboardThunk), this);
     gtk_widget_set_sensitive(
         copy_url_menuitem,
-        toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false) &&
-            !model()->user_input_in_progress());
+        controller()->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+            false));
     gtk_widget_show(copy_url_menuitem);
   }
 
@@ -1565,8 +1564,8 @@
 }
 
 void OmniboxViewGtk::HandleCopyURLClipboard(GtkWidget* sender) {
-  DoWriteToClipboard(toolbar_model()->GetURL(),
-                     toolbar_model()->GetText(false));
+  DoWriteToClipboard(controller()->GetToolbarModel()->GetURL(),
+                     controller()->GetToolbarModel()->GetText(false));
 }
 
 void OmniboxViewGtk::HandleCutClipboard(GtkWidget* sender) {
diff --git a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.h b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.h
index 8ec060f..eff5b7d 100644
--- a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.h
+++ b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk.h
@@ -57,7 +57,6 @@
   // In other use case, you should pass browser->profile() object as
   // profile parameter.
   OmniboxViewGtk(OmniboxEditController* controller,
-                 ToolbarModel* toolbar_model,
                  Browser* browser,
                  Profile* profile,
                  CommandUpdater* command_updater,
diff --git a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk_unittest.cc b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk_unittest.cc
index a77871a..c7f7859 100644
--- a/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk_unittest.cc
+++ b/chrome/browser/ui/gtk/omnibox/omnibox_view_gtk_unittest.cc
@@ -32,7 +32,9 @@
   MOCK_CONST_METHOD0(GetFavicon, gfx::Image());
   MOCK_CONST_METHOD0(GetTitle, string16());
   MOCK_METHOD0(GetInstant, InstantController*());
-  MOCK_CONST_METHOD0(GetWebContents, content::WebContents*());
+  MOCK_METHOD0(GetWebContents, content::WebContents*());
+  MOCK_METHOD0(GetToolbarModel, ToolbarModel*());
+  MOCK_CONST_METHOD0(GetToolbarModel, ToolbarModel*());
 
   virtual ~OmniboxEditControllerMock() {}
 };
@@ -47,9 +49,7 @@
     profile_.reset(new TestingProfile);
     window_ = gtk_window_new(GTK_WINDOW_POPUP);
     controller_.reset(new OmniboxEditControllerMock);
-    view_.reset(new OmniboxViewGtk(controller_.get(), NULL,
-                                   NULL,
-                                   profile_.get(),
+    view_.reset(new OmniboxViewGtk(controller_.get(), NULL, profile_.get(),
                                    NULL, false, window_));
     view_->Init();
     text_buffer_ = view_->text_buffer_;
diff --git a/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc b/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc
index 0cdf87a..629b9c7 100644
--- a/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/one_click_signin_bubble_gtk.cc
@@ -52,9 +52,11 @@
 
 void OneClickSigninBubbleGtk::BubbleClosing(
     BubbleGtk* bubble, bool closed_by_escape) {
+  // If we get here and |start_sync_callback_| is not null, act like this is
+  // an undo.  All actions that start sign in are explicitly handled below.
   if (is_sync_dialog_ && !start_sync_callback_.is_null()) {
     base::ResetAndReturn(&start_sync_callback_).Run(
-        OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
+        OneClickSigninSyncStarter::UNDO_SYNC);
   }
 
   // The bubble needs to close and remove the widgets from the window before
@@ -75,7 +77,7 @@
           one_click_signin::HISTOGRAM_CONFIRM_ADVANCED);
 
     base::ResetAndReturn(&start_sync_callback_).Run(
-      OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
+        OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
   } else {
     Browser* browser = chrome::FindBrowserWithWindow(
       gtk_window_get_transient_for(bubble_->GetNativeWindow()));
@@ -96,7 +98,7 @@
           one_click_signin::HISTOGRAM_CONFIRM_OK);
 
     base::ResetAndReturn(&start_sync_callback_).Run(
-      OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
+        OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
   }
   bubble_->Close();
 }
@@ -135,11 +137,13 @@
 }
 
 void OneClickSigninBubbleGtk::OnClickCloseButton(GtkWidget* button) {
+  DCHECK(is_sync_dialog_);
   OneClickSigninHelper::LogConfirmHistogramValue(
       clicked_learn_more_ ?
           one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_CLOSE :
           one_click_signin::HISTOGRAM_CONFIRM_CLOSE);
-  start_sync_callback_.Reset();
+  base::ResetAndReturn(&start_sync_callback_).Run(
+      OneClickSigninSyncStarter::UNDO_SYNC);
   bubble_->Close();
 }
 
@@ -207,7 +211,7 @@
 
   // The email is always set for the sync dialog.
   header_label_ = theme_provider->BuildLabel(
-      l10n_util::GetStringFUTF8(IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW, email_),
+      l10n_util::GetStringUTF8(IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW),
       ui::kGdkBlack);
 
   PangoAttrList* attributes = pango_attr_list_new();
diff --git a/chrome/browser/ui/gtk/one_click_signin_bubble_gtk_browsertest.cc b/chrome/browser/ui/gtk/one_click_signin_bubble_gtk_browsertest.cc
index 370f3b6..0f495d7 100644
--- a/chrome/browser/ui/gtk/one_click_signin_bubble_gtk_browsertest.cc
+++ b/chrome/browser/ui/gtk/one_click_signin_bubble_gtk_browsertest.cc
@@ -79,7 +79,7 @@
 // Callback should be called to setup sync with default settings.
 IN_PROC_BROWSER_TEST_F(OneClickSigninBubbleGtkTest, DialogShowAndClose) {
   EXPECT_CALL(*this, OnStartSync(
-      OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS)).Times(1);
+      OneClickSigninSyncStarter::UNDO_SYNC)).Times(1);
 
   MakeBubble(
     BrowserWindow::ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG)->bubble_->Close();
diff --git a/chrome/browser/ui/gtk/status_bubble_gtk.cc b/chrome/browser/ui/gtk/status_bubble_gtk.cc
index f514047..3d4fc79 100644
--- a/chrome/browser/ui/gtk/status_bubble_gtk.cc
+++ b/chrome/browser/ui/gtk/status_bubble_gtk.cc
@@ -21,6 +21,7 @@
 #include "ui/base/gtk/gtk_compat.h"
 #include "ui/base/gtk/gtk_hig_constants.h"
 #include "ui/base/text/text_elider.h"
+#include "ui/gfx/font.h"
 
 namespace {
 
diff --git a/chrome/browser/ui/gtk/tab_contents/web_drag_bookmark_handler_gtk.cc b/chrome/browser/ui/gtk/tab_contents/web_drag_bookmark_handler_gtk.cc
index f0b34ec..a7c6c92 100644
--- a/chrome/browser/ui/gtk/tab_contents/web_drag_bookmark_handler_gtk.cc
+++ b/chrome/browser/ui/gtk/tab_contents/web_drag_bookmark_handler_gtk.cc
@@ -36,19 +36,15 @@
 
 GdkAtom WebDragBookmarkHandlerGtk::GetBookmarkTargetAtom() const {
   // For GTK, bookmark drag data is encoded as pickle and associated with
-  // ui::CHROME_BOOKMARK_ITEM. See bookmark_utils::WriteBookmarksToSelection()
-  // for details.
+  // ui::CHROME_BOOKMARK_ITEM. See WriteBookmarksToSelection() for details.
   return ui::GetAtomForTarget(ui::CHROME_BOOKMARK_ITEM);
 }
 
 void WebDragBookmarkHandlerGtk::OnReceiveDataFromGtk(GtkSelectionData* data) {
   Profile* profile =
       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
-  bookmark_drag_data_.ReadFromVector(
-      bookmark_utils::GetNodesFromSelection(
-          NULL, data,
-          ui::CHROME_BOOKMARK_ITEM,
-          profile, NULL, NULL));
+  bookmark_drag_data_.ReadFromVector(GetNodesFromSelection(
+      NULL, data, ui::CHROME_BOOKMARK_ITEM, profile, NULL, NULL));
   bookmark_drag_data_.SetOriginatingProfile(profile);
 }
 
diff --git a/chrome/browser/ui/gtk/tab_contents_container_gtk.cc b/chrome/browser/ui/gtk/tab_contents_container_gtk.cc
index cda69a8..cdec01f 100644
--- a/chrome/browser/ui/gtk/tab_contents_container_gtk.cc
+++ b/chrome/browser/ui/gtk/tab_contents_container_gtk.cc
@@ -19,7 +19,6 @@
 
 TabContentsContainerGtk::TabContentsContainerGtk(StatusBubbleGtk* status_bubble)
     : tab_(NULL),
-      overlay_(NULL),
       status_bubble_(status_bubble) {
   Init();
 }
@@ -44,7 +43,6 @@
 
   floating_.Own(gtk_floating_container_new());
   gtk_widget_set_name(floating_.get(), "chrome-tab-contents-container");
-  g_signal_connect(floating_.get(), "focus", G_CALLBACK(OnFocusThunk), this);
 
   expanded_ = gtk_expanded_container_new();
   gtk_container_add(GTK_CONTAINER(floating_.get()), expanded_);
@@ -72,12 +70,8 @@
   tab_ = tab;
 
   if (tab_) {
-    // If the overlay is becoming the new permanent tab, we just reassign some
-    // pointers. Otherwise, we have to actually add it to the widget hierarchy.
-    if (tab_ == overlay_)
-      overlay_ = NULL;
-    else
-      PackTab(tab_);
+    // We have to actually add it to the widget hierarchy.
+    PackTab(tab_);
 
     // Make sure that the tab is below the find bar. Sometimes the content
     // native view will be null.
@@ -90,23 +84,6 @@
   }
 }
 
-void TabContentsContainerGtk::SetOverlay(content::WebContents* overlay) {
-  if (overlay_ == overlay)
-    return;
-
-  if (overlay_) {
-    HideTab(overlay_);
-    GtkWidget* overlay_widget = overlay_->GetView()->GetNativeView();
-    if (overlay_widget)
-      gtk_container_remove(GTK_CONTAINER(expanded_), overlay_widget);
-  }
-
-  overlay_ = overlay;
-
-  if (overlay_)
-    PackTab(overlay_);
-}
-
 void TabContentsContainerGtk::PackTab(content::WebContents* tab) {
   gfx::NativeView widget = tab->GetView()->GetNativeView();
   if (widget) {
@@ -156,28 +133,12 @@
     content::WebContents* contents) {
   // Sometimes, a WebContents is destroyed before we know about it. This allows
   // us to clean up our state in case this happens.
-  if (contents == overlay_)
-    SetOverlay(NULL);
-  else if (contents == tab_)
+  if (contents == tab_)
     SetTab(NULL);
   else
     NOTREACHED();
 }
 
-// Prevent |overlay_| from getting focus via the tab key. If |tab_| exists, try
-// to focus that. Otherwise, do nothing, but stop event propagation. See bug
-// http://crbug.com/63365
-gboolean TabContentsContainerGtk::OnFocus(GtkWidget* widget,
-                                          GtkDirectionType focus) {
-  if (overlay_) {
-    gtk_widget_child_focus(tab_->GetView()->GetContentNativeView(), focus);
-    return TRUE;
-  }
-
-  // No overlay contents; let the default handler run.
-  return FALSE;
-}
-
 // -----------------------------------------------------------------------------
 // ViewIDUtil::Delegate implementation
 
diff --git a/chrome/browser/ui/gtk/tab_contents_container_gtk.h b/chrome/browser/ui/gtk/tab_contents_container_gtk.h
index 13d647d..8feaf33 100644
--- a/chrome/browser/ui/gtk/tab_contents_container_gtk.h
+++ b/chrome/browser/ui/gtk/tab_contents_container_gtk.h
@@ -12,7 +12,6 @@
 #include "chrome/browser/ui/gtk/view_id_util.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
-#include "ui/base/gtk/gtk_signal.h"
 #include "ui/base/gtk/owned_widget_gtk.h"
 
 class StatusBubbleGtk;
@@ -35,14 +34,6 @@
   void SetTab(content::WebContents* tab);
   content::WebContents* tab() const { return tab_; }
 
-  void SetOverlay(content::WebContents* overlay);
-  bool HasOverlay() const { return overlay_ != NULL; }
-
-  // Returns the WebContents currently displayed.
-  content::WebContents* GetVisibleTab() const {
-    return overlay_ ? overlay_ : tab_;
-  }
-
   // Remove the tab from the hierarchy.
   void DetachTab(content::WebContents* tab);
 
@@ -74,21 +65,11 @@
   // Stops showing |tab|.
   void HideTab(content::WebContents* tab);
 
-  // Handle focus traversal on the tab contents container. Focus should not
-  // traverse to the overlay contents.
-  CHROMEGTK_CALLBACK_1(TabContentsContainerGtk, gboolean, OnFocus,
-                       GtkDirectionType);
-
   content::NotificationRegistrar registrar_;
 
-  // The WebContents for the currently selected tab. This will be showing
-  // unless there is an overlay contents.
+  // The WebContents for the currently selected tab.
   content::WebContents* tab_;
 
-  // The current overlay contents (for Instant). If non-NULL, it will be
-  // visible.
-  content::WebContents* overlay_;
-
   // The status bubble manager.  Always non-NULL.
   StatusBubbleGtk* status_bubble_;
 
diff --git a/chrome/browser/ui/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/ui/gtk/tabs/tab_strip_gtk.cc
index 10bd53c..a099c47 100644
--- a/chrome/browser/ui/gtk/tabs/tab_strip_gtk.cc
+++ b/chrome/browser/ui/gtk/tabs/tab_strip_gtk.cc
@@ -1092,14 +1092,10 @@
       GetTabAtAdjustForAnimation(*it)->SchedulePaint();
   }
 
-  ui::ListSelectionModel::SelectedIndices no_longer_selected;
-  std::insert_iterator<std::vector<int> > it2(no_longer_selected,
-                                              no_longer_selected.begin());
-  std::set_difference(old_model.selected_indices().begin(),
-                      old_model.selected_indices().end(),
-                      model_->selection_model().selected_indices().begin(),
-                      model_->selection_model().selected_indices().end(),
-                      it2);
+  ui::ListSelectionModel::SelectedIndices no_longer_selected =
+      base::STLSetDifference<ui::ListSelectionModel::SelectedIndices>(
+          old_model.selected_indices(),
+          model_->selection_model().selected_indices());
   for (std::vector<int>::iterator it = no_longer_selected.begin();
        it != no_longer_selected.end(); ++it) {
     GetTabAtAdjustForAnimation(*it)->StopMiniTabTitleAnimation();
diff --git a/chrome/browser/ui/gtk/web_contents_modal_dialog_manager_gtk.cc b/chrome/browser/ui/gtk/web_contents_modal_dialog_manager_gtk.cc
index a89bef2..5eba5a9 100644
--- a/chrome/browser/ui/gtk/web_contents_modal_dialog_manager_gtk.cc
+++ b/chrome/browser/ui/gtk/web_contents_modal_dialog_manager_gtk.cc
@@ -86,6 +86,10 @@
   virtual void PulseDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
   }
 
+  virtual void HostChanged(
+      web_modal::WebContentsModalDialogHost* new_host) OVERRIDE {
+  }
+
  private:
   typedef ChromeWebContentsViewDelegateGtk TabContentsViewType;
 
diff --git a/chrome/browser/ui/login/login_prompt_browsertest.cc b/chrome/browser/ui/login/login_prompt_browsertest.cc
index 362ffde..f7252ab 100644
--- a/chrome/browser/ui/login/login_prompt_browsertest.cc
+++ b/chrome/browser/ui/login/login_prompt_browsertest.cc
@@ -48,8 +48,8 @@
 
     AuthInfo() {}
 
-    AuthInfo(const std::string username,
-             const std::string password)
+    AuthInfo(const std::string& username,
+             const std::string& password)
         : username_(username), password_(password) {}
   };
 
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_controller.h b/chrome/browser/ui/omnibox/omnibox_edit_controller.h
index b651739..da17eb2 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_controller.h
+++ b/chrome/browser/ui/omnibox/omnibox_edit_controller.h
@@ -11,6 +11,7 @@
 
 class GURL;
 class InstantController;
+class ToolbarModel;
 
 namespace content {
 class WebContents;
@@ -67,7 +68,10 @@
   virtual InstantController* GetInstant() = 0;
 
   // Returns the WebContents of the currently active tab.
-  virtual content::WebContents* GetWebContents() const = 0;
+  virtual content::WebContents* GetWebContents() = 0;
+
+  virtual ToolbarModel* GetToolbarModel() = 0;
+  virtual const ToolbarModel* GetToolbarModel() const = 0;
 
  protected:
   virtual ~OmniboxEditController() {}
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_model.cc b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
index e983bbc..d8d89b8 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_model.cc
+++ b/chrome/browser/ui/omnibox/omnibox_edit_model.cc
@@ -49,6 +49,7 @@
 #include "chrome/browser/ui/omnibox/omnibox_view.h"
 #include "chrome/browser/ui/search/instant_controller.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/net/url_fixer_upper.h"
 #include "chrome/common/pref_names.h"
@@ -357,7 +358,8 @@
 }
 
 bool OmniboxEditModel::CurrentTextIsURL() const {
-  if (view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false))
+  if (controller_->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+      false))
     return false;
 
   // If current text is not composed of replaced search terms and
@@ -385,7 +387,8 @@
   // Do not adjust if selection did not start at the beginning of the field, or
   // if the URL was replaced by search terms.
   if ((sel_min != 0) ||
-      view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false))
+      controller_->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+          false))
     return;
 
   if (!user_input_in_progress_ && is_all_selected) {
@@ -695,6 +698,11 @@
       // in template_url.h.
     }
 
+    // TODO(pkasting): This histogram obsoletes the next one.  Remove the next
+    // one in Chrome 32 or later.
+    UMA_HISTOGRAM_ENUMERATION("Omnibox.SearchEngineType",
+        TemplateURLPrepopulateData::GetEngineType(*template_url),
+        SEARCH_ENGINE_MAX);
     // NOTE: Non-prepopulated engines will all have ID 0, which is fine as
     // the prepopulate IDs start at 1.  Distribution-specific engines will
     // all have IDs above the maximum, and will be automatically lumped
@@ -722,7 +730,8 @@
 
     RecordPercentageMatchHistogram(
         permanent_text_, current_text,
-        view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false),
+        controller_->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+            false),
         match.transition);
 
     // Track whether the destination URL sends us to a search results page
@@ -812,7 +821,14 @@
   SetFocusState(OMNIBOX_FOCUS_VISIBLE, OMNIBOX_FOCUS_CHANGE_EXPLICIT);
   control_key_state_ = control_down ? DOWN_WITHOUT_CHANGE : UP;
 
-  if (delegate_->CurrentPageExists()) {
+  // Try to get ZeroSuggest suggestions if a page is loaded and the user has
+  // not been typing in the omnibox.  The |user_input_in_progress_| check is
+  // used to detect the case where this function is called after right-clicking
+  // in the omnibox and selecting paste in Linux (in which case we actually get
+  // the OnSetFocus() call after the process of handling the paste has kicked
+  // off).
+  // TODO(hfung): Remove this when crbug/271590 is fixed.
+  if (delegate_->CurrentPageExists() && !user_input_in_progress_) {
     // TODO(jered): We may want to merge this into Start() and just call that
     // here rather than having a special entry point for zero-suggest.  Note
     // that we avoid PermanentURL() here because it's not guaranteed to give us
@@ -1175,8 +1191,8 @@
                                              GURL* alternate_nav_url) const {
   DCHECK(match != NULL);
 
-  if (!user_input_in_progress_ &&
-      view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false)) {
+  if (controller_->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+      false)) {
     // Any time the user hits enter on the unchanged omnibox, we should reload.
     // When we're not extracting search terms, AcceptInput() will take care of
     // this (see code referring to PAGE_TRANSITION_RELOAD there), but when we're
@@ -1298,7 +1314,8 @@
     return AutocompleteInput::BLANK;
   if (url == profile()->GetPrefs()->GetString(prefs::kHomePage))
     return AutocompleteInput::HOMEPAGE;
-  if (view_->toolbar_model()->WouldReplaceSearchURLWithSearchTerms(true)) {
+  if (controller_->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+      true)) {
     return AutocompleteInput::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT;
   }
   if (delegate_->IsSearchResultsPage()) {
diff --git a/chrome/browser/ui/omnibox/omnibox_edit_unittest.cc b/chrome/browser/ui/omnibox/omnibox_edit_unittest.cc
index 1424011..2b4be29 100644
--- a/chrome/browser/ui/omnibox/omnibox_edit_unittest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_edit_unittest.cc
@@ -21,8 +21,8 @@
 
 class TestingOmniboxView : public OmniboxView {
  public:
-  explicit TestingOmniboxView(ToolbarModel* model)
-      : OmniboxView(NULL, NULL, model, NULL) {}
+  explicit TestingOmniboxView(OmniboxEditController* controller)
+      : OmniboxView(NULL, controller, NULL) {}
 
   virtual void SaveStateToTab(WebContents* tab) OVERRIDE {}
   virtual void Update(const WebContents* tab_for_state_restoring) OVERRIDE {}
@@ -88,7 +88,8 @@
 
 class TestingOmniboxEditController : public OmniboxEditController {
  public:
-  TestingOmniboxEditController() {}
+  explicit TestingOmniboxEditController(ToolbarModel* toolbar_model)
+      : toolbar_model_(toolbar_model) {}
   virtual void OnAutocompleteAccept(const GURL& url,
                                     WindowOpenDisposition disposition,
                                     content::PageTransition transition,
@@ -101,11 +102,15 @@
   virtual gfx::Image GetFavicon() const OVERRIDE { return gfx::Image(); }
   virtual string16 GetTitle() const OVERRIDE { return string16(); }
   virtual InstantController* GetInstant() OVERRIDE { return NULL; }
-  virtual WebContents* GetWebContents() const OVERRIDE {
-    return NULL;
+  virtual WebContents* GetWebContents() OVERRIDE { return NULL; }
+  virtual ToolbarModel* GetToolbarModel() OVERRIDE { return toolbar_model_; }
+  virtual const ToolbarModel* GetToolbarModel() const OVERRIDE {
+    return toolbar_model_;
   }
 
  private:
+  ToolbarModel* toolbar_model_;
+
   DISALLOW_COPY_AND_ASSIGN(TestingOmniboxEditController);
 };
 
@@ -173,8 +178,8 @@
     { "www.google.com/webhp?", 0, true, "hello world", "hello world", false,
       "", true },
   };
-  TestingOmniboxView view(toolbar_model());
-  TestingOmniboxEditController controller;
+  TestingOmniboxEditController controller(toolbar_model());
+  TestingOmniboxView view(&controller);
   TestingProfile profile;
   // NOTE: The TemplateURLService must be created before the
   // AutocompleteClassifier so that the SearchProvider gets a non-NULL
diff --git a/chrome/browser/ui/omnibox/omnibox_view.cc b/chrome/browser/ui/omnibox/omnibox_view.cc
index 9d8f50f..883ec68 100644
--- a/chrome/browser/ui/omnibox/omnibox_view.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view.cc
@@ -11,11 +11,13 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
+#include "chrome/browser/ui/omnibox/omnibox_edit_controller.h"
+#include "chrome/browser/ui/toolbar/toolbar_model.h"
 #include "ui/base/clipboard/clipboard.h"
 
 // static
 string16 OmniboxView::StripJavascriptSchemas(const string16& text) {
-  const string16 kJsPrefix(ASCIIToUTF16(chrome::kJavaScriptScheme) +
+  const string16 kJsPrefix(ASCIIToUTF16(content::kJavaScriptScheme) +
                            ASCIIToUTF16(":"));
   string16 out(text);
   while (StartsWith(out, kJsPrefix, false))
@@ -99,7 +101,7 @@
           model_->CurrentTextType() :
               AutocompleteMatchType::URL_WHAT_YOU_TYPED);
   } else {
-    return toolbar_model_->GetIcon();
+    return controller_->GetToolbarModel()->GetIcon();
   }
 }
 
@@ -143,10 +145,8 @@
 
 OmniboxView::OmniboxView(Profile* profile,
                          OmniboxEditController* controller,
-                         ToolbarModel* toolbar_model,
                          CommandUpdater* command_updater)
     : controller_(controller),
-      toolbar_model_(toolbar_model),
       command_updater_(command_updater) {
   // |profile| can be NULL in tests.
   if (profile)
diff --git a/chrome/browser/ui/omnibox/omnibox_view.h b/chrome/browser/ui/omnibox/omnibox_view.h
index a138de5..62c4c63 100644
--- a/chrome/browser/ui/omnibox/omnibox_view.h
+++ b/chrome/browser/ui/omnibox/omnibox_view.h
@@ -18,7 +18,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/autocomplete/autocomplete_match.h"
 #include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
-#include "chrome/browser/ui/toolbar/toolbar_model.h"
 #include "content/public/common/url_constants.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/native_widget_types.h"
@@ -60,9 +59,6 @@
   CommandUpdater* command_updater() { return command_updater_; }
   const CommandUpdater* command_updater() const { return command_updater_; }
 
-  ToolbarModel* toolbar_model() { return toolbar_model_; }
-  const ToolbarModel* toolbar_model() const { return toolbar_model_; }
-
   // For use when switching tabs, this saves the current state onto the tab so
   // that it can be restored during a later call to Update().
   virtual void SaveStateToTab(content::WebContents* tab) = 0;
@@ -251,7 +247,6 @@
  protected:
   OmniboxView(Profile* profile,
               OmniboxEditController* controller,
-              ToolbarModel* toolbar_model,
               CommandUpdater* command_updater);
 
   // Internally invoked whenever the text changes in some way.
@@ -266,6 +261,7 @@
   virtual void EmphasizeURLComponents() = 0;
 
   OmniboxEditController* controller() { return controller_; }
+  const OmniboxEditController* controller() const { return controller_; }
 
  private:
   friend class OmniboxViewMacTest;
@@ -273,7 +269,6 @@
   // |model_| can be NULL in tests.
   scoped_ptr<OmniboxEditModel> model_;
   OmniboxEditController* controller_;
-  ToolbarModel* toolbar_model_;
 
   // The object that handles additional command functionality exposed on the
   // edit, such as invoking the keyword editor.
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index a4f0093..353f5ae 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -1016,12 +1016,8 @@
     omnibox_view->SelectAll(true);
     ASSERT_TRUE(omnibox_view->IsSelectAll());
 
-    // The first item should be the default match.
-    size_t default_line = popup_model->selected_line();
-    std::string default_url =
-        popup_model->result().match_at(default_line).destination_url.spec();
-
     // Move down.
+    size_t default_line = popup_model->selected_line();
     omnibox_view->model()->OnUpOrDownKeyPressed(1);
     ASSERT_EQ(default_line + 1, popup_model->selected_line());
     string16 selected_text =
@@ -1464,20 +1460,19 @@
   EXPECT_EQ(UTF8ToUTF16(content::kAboutBlankURL), old_text);
   EXPECT_TRUE(omnibox_view->IsSelectAll());
 
-  // Undo should clear the omnibox.
-  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
+  // Delete the text, then undo.
+  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_BACK, 0));
   EXPECT_TRUE(omnibox_view->GetText().empty());
-
-  // Nothing should happen if undo again.
   ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
-  EXPECT_TRUE(omnibox_view->GetText().empty());
-
-  // Redo should restore the original text.
-  ASSERT_NO_FATAL_FAILURE(
-      SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN));
   EXPECT_EQ(old_text, omnibox_view->GetText());
 
+  // Redo should delete the text again.
+  ASSERT_NO_FATAL_FAILURE(
+      SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN));
+  EXPECT_TRUE(omnibox_view->GetText().empty());
+
   // Looks like the undo manager doesn't support restoring selection.
+  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
   EXPECT_FALSE(omnibox_view->IsSelectAll());
 
   // The cursor should be at the end.
@@ -1512,10 +1507,6 @@
   // Undo delete two characters.
   ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
   EXPECT_EQ(old_text, omnibox_view->GetText());
-
-  // Undo again.
-  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_Z, ui::EF_CONTROL_DOWN));
-  EXPECT_TRUE(omnibox_view->GetText().empty());
 }
 
 // See http://crosbug.com/10306
diff --git a/chrome/browser/ui/panels/base_panel_browser_test.cc b/chrome/browser/ui/panels/base_panel_browser_test.cc
index 69eb6ef..c14adb1 100644
--- a/chrome/browser/ui/panels/base_panel_browser_test.cc
+++ b/chrome/browser/ui/panels/base_panel_browser_test.cc
@@ -25,12 +25,12 @@
 #include "chrome/browser/ui/panels/test_panel_mouse_watcher.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/web_contents_tester.h"
+#include "extensions/common/manifest_constants.h"
 #include "sync/api/string_ordinal.h"
 
 #if defined(OS_LINUX)
@@ -547,8 +547,8 @@
   base::FilePath full_path = extension_prefs->install_directory().Append(path);
 
   scoped_ptr<DictionaryValue> input_value(extra_value.DeepCopy());
-  input_value->SetString(extension_manifest_keys::kVersion, "1.0.0.0");
-  input_value->SetString(extension_manifest_keys::kName, "Sample Extension");
+  input_value->SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
+  input_value->SetString(extensions::manifest_keys::kName, "Sample Extension");
 
   std::string error;
   scoped_refptr<Extension> extension = Extension::Create(
diff --git a/chrome/browser/ui/panels/base_panel_browser_test.h b/chrome/browser/ui/panels/base_panel_browser_test.h
index cb225c9..abda71c 100644
--- a/chrome/browser/ui/panels/base_panel_browser_test.h
+++ b/chrome/browser/ui/panels/base_panel_browser_test.h
@@ -5,14 +5,14 @@
 #ifndef CHROME_BROWSER_UI_PANELS_BASE_PANEL_BROWSER_TEST_H_
 #define CHROME_BROWSER_UI_PANELS_BASE_PANEL_BROWSER_TEST_H_
 
-#include "base/values.h"
 #include "base/memory/ref_counted.h"
+#include "base/values.h"
 #include "chrome/browser/ui/panels/display_settings_provider.h"
 #include "chrome/browser/ui/panels/panel.h"
 #include "chrome/browser/ui/panels/panel_manager.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "extensions/common/manifest.h"
 #include "ui/gfx/rect.h"
 
 class NativePanelTesting;
diff --git a/chrome/browser/ui/panels/stacked_panel_browsertest.cc b/chrome/browser/ui/panels/stacked_panel_browsertest.cc
index 48fbea4..a590088 100644
--- a/chrome/browser/ui/panels/stacked_panel_browsertest.cc
+++ b/chrome/browser/ui/panels/stacked_panel_browsertest.cc
@@ -1265,7 +1265,7 @@
 
   // Create 3 stacked panels.
   StackedPanelCollection* stack = panel_manager->CreateStack();
-  Panel* panel1 = CreateStackedPanel("1", gfx::Rect(100, 250, 200, 200), stack);
+  Panel* panel1 = CreateStackedPanel("1", gfx::Rect(100, 50, 200, 200), stack);
   Panel* panel2 = CreateStackedPanel("2", gfx::Rect(0, 0, 150, 100), stack);
   Panel* panel3 = CreateStackedPanel("3", gfx::Rect(0, 0, 150, 120), stack);
   ASSERT_EQ(3, stack->num_panels());
@@ -1285,6 +1285,41 @@
   panel_manager->CloseAll();
 }
 
+// Skip the test since active state might not be fully supported for some window
+// managers.
+#if defined(TOOLKIT_GTK) || defined(OS_MACOSX)
+#define MAYBE_FocusNextUnminimizedPanelOnPanelClose \
+    DISABLED_FocusNextUnminimizedPanelOnPanelClose
+#else
+#define MAYBE_FocusNextUnminimizedPanelOnPanelClose \
+    FocusNextUnminimizedPanelOnPanelClose
+#endif
+IN_PROC_BROWSER_TEST_F(StackedPanelBrowserTest,
+                       MAYBE_FocusNextUnminimizedPanelOnPanelClose) {
+  PanelManager* panel_manager = PanelManager::GetInstance();
+
+  // Create 3 stacked panels.
+  StackedPanelCollection* stack = panel_manager->CreateStack();
+  Panel* panel1 = CreateStackedPanel("1", gfx::Rect(100, 50, 200, 200), stack);
+  Panel* panel2 = CreateStackedPanel("2", gfx::Rect(0, 0, 150, 100), stack);
+  Panel* panel3 = CreateStackedPanel("3", gfx::Rect(0, 0, 150, 120), stack);
+  ASSERT_EQ(3, stack->num_panels());
+  ASSERT_FALSE(panel1->IsActive());
+  ASSERT_FALSE(panel2->IsActive());
+  ASSERT_TRUE(panel3->IsActive());
+
+  // Minimize P2.
+  panel2->Minimize();
+  WaitForBoundsAnimationFinished(panel2);
+
+  // Close P3. Expect P1, not P2, should become active.
+  CloseWindowAndWait(panel3);
+  EXPECT_TRUE(panel1->IsActive());
+  EXPECT_FALSE(panel2->IsActive());
+
+  panel_manager->CloseAll();
+}
+
 IN_PROC_BROWSER_TEST_F(StackedPanelBrowserTest,
                        ExpandCollapsedTopPanelOnBottomPanelClose) {
   PanelManager* panel_manager = PanelManager::GetInstance();
@@ -1300,6 +1335,7 @@
   ASSERT_EQ(2, stack->num_panels());
 
   // Collapse top panel.
+  int original_panel1_height = panel1->GetBounds().height();
   panel1->Minimize();
   WaitForBoundsAnimationFinished(panel2);
   EXPECT_TRUE(panel1->IsMinimized());
@@ -1314,6 +1350,7 @@
   EXPECT_EQ(PanelCollection::DETACHED, panel1->collection()->type());
   EXPECT_FALSE(panel1->IsMinimized());
   EXPECT_EQ(Panel::EXPANDED, panel1->expansion_state());
+  EXPECT_EQ(original_panel1_height, panel1->GetBounds().height());
 
   panel_manager->CloseAll();
 }
diff --git a/chrome/browser/ui/panels/stacked_panel_collection.cc b/chrome/browser/ui/panels/stacked_panel_collection.cc
index 40e938d..396f501 100644
--- a/chrome/browser/ui/panels/stacked_panel_collection.cc
+++ b/chrome/browser/ui/panels/stacked_panel_collection.cc
@@ -280,11 +280,18 @@
   }
 
   // If an active panel is being closed, try to focus the next recently active
-  // panel in the stack.
+  // panel in the stack that is not minimized.
   if (reason == PanelCollection::PANEL_CLOSED &&
       panel->IsActive() &&
       !most_recently_active_panels_.empty()) {
-    most_recently_active_panels_.front()->Activate();
+    for (Panels::const_iterator iter = most_recently_active_panels_.begin();
+       iter != most_recently_active_panels_.end(); ++iter) {
+      Panel* other_panel = *iter;
+      if (!IsPanelMinimized(other_panel)) {
+        other_panel->Activate();
+        break;
+      }
+    }
   }
 
   // If the top panel is closed, move up all other panels to stay at the same
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.cc b/chrome/browser/ui/prefs/prefs_tab_helper.cc
index 3e3f718..0591876 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.cc
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.cc
@@ -15,6 +15,8 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_preferences_util.h"
+#include "chrome/browser/user_style_sheet_watcher.h"
+#include "chrome/browser/user_style_sheet_watcher_factory.h"
 #include "chrome/common/pref_font_webkit_names.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/pref_names_util.h"
@@ -410,7 +412,8 @@
 }  // namespace
 
 PrefsTabHelper::PrefsTabHelper(WebContents* contents)
-    : web_contents_(contents) {
+    : web_contents_(contents),
+      weak_ptr_factory_(this) {
   PrefService* prefs = GetProfile()->GetPrefs();
   pref_change_registrar_.Init(prefs);
   if (prefs) {
@@ -459,8 +462,13 @@
       web_contents_->GetMutableRendererPrefs(), GetProfile());
 
 #if !defined(OS_ANDROID)
-  registrar_.Add(this, chrome::NOTIFICATION_USER_STYLE_SHEET_UPDATED,
-                 content::NotificationService::AllSources());
+  UserStyleSheetWatcher* uss =
+      UserStyleSheetWatcherFactory::GetForProfile(GetProfile());
+  if (uss) {
+    uss->RegisterOnStyleSheetUpdatedCallback(
+        base::Bind(&PrefsTabHelper::UpdateWebPreferences,
+                   weak_ptr_factory_.GetWeakPtr()));
+  }
 #endif
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(ENABLE_THEMES)
   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
@@ -649,27 +657,21 @@
 void PrefsTabHelper::Observe(int type,
                              const content::NotificationSource& source,
                              const content::NotificationDetails& details) {
-  switch (type) {
-#if !defined(OS_ANDROID)
-    case chrome::NOTIFICATION_USER_STYLE_SHEET_UPDATED:
-      UpdateWebPreferences();
-      break;
-#endif // !defined(OS_ANDROID)
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(ENABLE_THEMES)
-    case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: {
-      UpdateRendererPreferences();
-      break;
-    }
-#endif
-#if defined(USE_AURA)
-    case chrome::NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED: {
-      UpdateRendererPreferences();
-      break;
-    }
-#endif  // defined(USE_AURA)
-    default:
-      NOTREACHED();
+  if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) {
+    UpdateRendererPreferences();
+    return;
   }
+#endif
+
+#if defined(USE_AURA)
+  if (type == chrome::NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED) {
+    UpdateRendererPreferences();
+    return;
+  }
+#endif  // defined(USE_AURA)
+
+  NOTREACHED();
 }
 
 void PrefsTabHelper::UpdateWebPreferences() {
diff --git a/chrome/browser/ui/prefs/prefs_tab_helper.h b/chrome/browser/ui/prefs/prefs_tab_helper.h
index 09086b5..6d613d4 100644
--- a/chrome/browser/ui/prefs/prefs_tab_helper.h
+++ b/chrome/browser/ui/prefs/prefs_tab_helper.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_PREFS_PREFS_TAB_HELPER_H_
 
 #include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
 #include "base/prefs/pref_change_registrar.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -55,6 +56,7 @@
   content::WebContents* web_contents_;
   content::NotificationRegistrar registrar_;
   PrefChangeRegistrar pref_change_registrar_;
+  base::WeakPtrFactory<PrefsTabHelper> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PrefsTabHelper);
 };
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index 9518620..dd6544b 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -312,14 +312,21 @@
 
   void InstallThemeAndVerify(const std::string& theme_dir,
                              const std::string& theme_name) {
-    const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_dir);
-    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(
-        theme_path, 1, ExtensionBrowserTest::browser()));
     const extensions::Extension* theme =
         ThemeServiceFactory::GetThemeForProfile(
             ExtensionBrowserTest::browser()->profile());
-    ASSERT_NE(static_cast<extensions::Extension*>(NULL), theme);
-    ASSERT_EQ(theme->name(), theme_name);
+    // If there is already a theme installed, the current theme should be
+    // disabled and the new one installed + enabled.
+    int expected_change = theme ? 0 : 1;
+
+    const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_dir);
+    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(
+        theme_path, expected_change, ExtensionBrowserTest::browser()));
+    const extensions::Extension* new_theme =
+        ThemeServiceFactory::GetThemeForProfile(
+            ExtensionBrowserTest::browser()->profile());
+    ASSERT_NE(static_cast<extensions::Extension*>(NULL), new_theme);
+    ASSERT_EQ(new_theme->name(), theme_name);
   }
 
  private:
@@ -1372,16 +1379,11 @@
   EXPECT_EQ(ASCIIToUTF16("flowers"), omnibox()->GetText());
 }
 
-// Flaky on Mac and Linux Tests bots.
-#if defined(OS_MACOSX) || defined(OS_LINUX)
-#define MAYBE_UpdateSearchQueryOnForwardNavigation DISABLED_UpdateSearchQueryOnForwardNavigation
-#else
-#define MAYBE_UpdateSearchQueryOnForwardNavigation UpdateSearchQueryOnForwardNavigation
-#endif
+// Flaky: crbug.com/253092.
 // Test to verify that the omnibox search query is updated on browser
 // forward button press events.
 IN_PROC_BROWSER_TEST_F(InstantExtendedTest,
-                       MAYBE_UpdateSearchQueryOnForwardNavigation) {
+                       DISABLED_UpdateSearchQueryOnForwardNavigation) {
   ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
 
   // Focus omnibox and confirm overlay isn't shown.
diff --git a/chrome/browser/ui/search/instant_loader.cc b/chrome/browser/ui/search/instant_loader.cc
index 949cf60..fbdba21 100644
--- a/chrome/browser/ui/search/instant_loader.cc
+++ b/chrome/browser/ui/search/instant_loader.cc
@@ -94,8 +94,6 @@
   BlockedContentTabHelper::FromWebContents(contents())->
       SetAllContentsBlocked(true);
   TabSpecificContentSettings::CreateForWebContents(contents());
-  TabSpecificContentSettings::FromWebContents(contents())->
-      SetPopupsBlocked(true);
 
   // Bookmarks (Users can bookmark the Instant NTP. This ensures the bookmarked
   // state is correctly set when the contents are swapped into a tab.)
@@ -132,16 +130,6 @@
 
   BlockedContentTabHelper::FromWebContents(contents())->
       SetAllContentsBlocked(false);
-  TabSpecificContentSettings::FromWebContents(contents())->
-      SetPopupsBlocked(false);
-#if !defined(OS_ANDROID)
-  PopupBlockerTabHelper* popup_helper =
-      PopupBlockerTabHelper::FromWebContents(contents());
-  if (popup_helper) {
-    TabSpecificContentSettings::FromWebContents(contents())
-        ->SetPopupsBlocked(!!popup_helper->GetBlockedPopupsCount());
-  }
-#endif
 
   CoreTabHelper::FromWebContents(contents())->set_delegate(NULL);
 
diff --git a/chrome/browser/ui/search/instant_page.cc b/chrome/browser/ui/search/instant_page.cc
index 9149ea7..60d31cf 100644
--- a/chrome/browser/ui/search/instant_page.cc
+++ b/chrome/browser/ui/search/instant_page.cc
@@ -149,7 +149,7 @@
                         OnSearchBoxNavigate);
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_PasteAndOpenDropdown,
                         OnSearchBoxPaste);
-    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CountMouseover, OnCountMouseover);
+    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_LogEvent, OnLogEvent);
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem,
                         OnDeleteMostVisitedItem);
     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion,
@@ -261,11 +261,11 @@
   delegate_->PasteIntoOmnibox(contents(), text);
 }
 
-void InstantPage::OnCountMouseover(int page_id) {
+void InstantPage::OnLogEvent(int page_id, NTPLoggingEventType event) {
   if (!contents()->IsActiveEntry(page_id))
     return;
 
-  InstantTab::CountMouseover(contents());
+  InstantTab::LogEvent(contents(), event);
 }
 
 void InstantPage::OnDeleteMostVisitedItem(int page_id, const GURL& url) {
diff --git a/chrome/browser/ui/search/instant_page.h b/chrome/browser/ui/search/instant_page.h
index 1cb5dfe..e8356c3 100644
--- a/chrome/browser/ui/search/instant_page.h
+++ b/chrome/browser/ui/search/instant_page.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/search/instant_ipc_sender.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
 #include "chrome/common/instant_types.h"
+#include "chrome/common/ntp_logging_events.h"
 #include "chrome/common/omnibox_focus_state.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/page_transition_types.h"
@@ -195,7 +196,7 @@
                            WindowOpenDisposition disposition,
                            bool is_search_type);
   void OnSearchBoxPaste(int page_id, const string16& text);
-  void OnCountMouseover(int page_id);
+  void OnLogEvent(int page_id, NTPLoggingEventType event);
   void OnDeleteMostVisitedItem(int page_id, const GURL& url);
   void OnUndoMostVisitedDeletion(int page_id, const GURL& url);
   void OnUndoAllMostVisitedDeletions(int page_id);
diff --git a/chrome/browser/ui/search/instant_tab.cc b/chrome/browser/ui/search/instant_tab.cc
index 3112930..53601ec 100644
--- a/chrome/browser/ui/search/instant_tab.cc
+++ b/chrome/browser/ui/search/instant_tab.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
+#include "chrome/common/ntp_logging_events.h"
 #include "content/public/browser/web_contents.h"
 
 InstantTab::InstantTab(InstantPage::Delegate* delegate,
@@ -21,10 +22,11 @@
 }
 
 // static
-void InstantTab::CountMouseover(content::WebContents* contents) {
+void InstantTab::LogEvent(content::WebContents* contents,
+                          NTPLoggingEventType event) {
   NTPUserDataLogger* data = NTPUserDataLogger::FromWebContents(contents);
   if (data)
-    data->increment_number_of_mouseovers();
+    data->LogEvent(event);
 }
 
 // static
diff --git a/chrome/browser/ui/search/instant_tab.h b/chrome/browser/ui/search/instant_tab.h
index b608490..a74b8e3 100644
--- a/chrome/browser/ui/search/instant_tab.h
+++ b/chrome/browser/ui/search/instant_tab.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "chrome/browser/ui/search/instant_page.h"
+#include "chrome/common/ntp_logging_events.h"
 
 class Profile;
 
@@ -22,8 +23,9 @@
   // the page supports the Instant API.
   void Init(content::WebContents* contents);
 
-  // Used to log each time the user mouses over NTP tiles or titles.
-  static void CountMouseover(content::WebContents* contents);
+  // Used to signal that an event has occurred on the New Tab Page.
+  static void LogEvent(content::WebContents* contents,
+                       NTPLoggingEventType event);
 
   // Used to log in UMA the total number of mouseovers over NTP tiles/titles.
   static void EmitMouseoverCount(content::WebContents* contents);
diff --git a/chrome/browser/ui/search/search_delegate.cc b/chrome/browser/ui/search/search_delegate.cc
index 2af2654..31e763d 100644
--- a/chrome/browser/ui/search/search_delegate.cc
+++ b/chrome/browser/ui/search/search_delegate.cc
@@ -7,8 +7,7 @@
 #include "chrome/browser/ui/search/search_model.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 
-SearchDelegate::SearchDelegate(SearchModel* browser_search_model,
-                               ToolbarModel* toolbar_model)
+SearchDelegate::SearchDelegate(SearchModel* browser_search_model)
     : browser_model_(browser_search_model),
       tab_model_() {
 }
diff --git a/chrome/browser/ui/search/search_delegate.h b/chrome/browser/ui/search/search_delegate.h
index da8c8c4..c424453 100644
--- a/chrome/browser/ui/search/search_delegate.h
+++ b/chrome/browser/ui/search/search_delegate.h
@@ -9,8 +9,6 @@
 #include "base/compiler_specific.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
 
-class ToolbarModel;
-
 namespace content {
 class WebContents;
 }
@@ -25,8 +23,7 @@
 // Browser-level model.
 class SearchDelegate : public SearchModelObserver {
  public:
-  SearchDelegate(SearchModel* browser_search_model,
-                 ToolbarModel* toolbar_model);
+  explicit SearchDelegate(SearchModel* browser_search_model);
   virtual ~SearchDelegate();
 
   // Overrides for SearchModelObserver:
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 513d982..a5226e7 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -65,7 +65,7 @@
 #include "ui/base/resource/resource_bundle.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
+#include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -595,10 +595,9 @@
 
   if (chrome::IsRunningInAppMode() &&
       command_line.HasSwitch(switches::kAppId)) {
-    // StartupAppLauncher deletes itself when done.
-    (new chromeos::StartupAppLauncher(
+    chromeos::LaunchAppOrDie(
         last_used_profile,
-        command_line.GetSwitchValueASCII(switches::kAppId)))->Start();
+        command_line.GetSwitchValueASCII(switches::kAppId));
 
     // Skip browser launch since app mode launches its app window.
     silent_launch = true;
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index cea4329..3a7b5c3 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -869,13 +869,11 @@
     if (!command_line_.HasSwitch(switches::kTestType)) {
       GoogleApiKeysInfoBarDelegate::Create(InfoBarService::FromWebContents(
           browser->tab_strip_model()->GetActiveWebContents()));
-
-      // TODO(phajdan.jr): Always enable after migrating bots:
-      // http://crbug.com/170262 .
-      ObsoleteOSInfoBarDelegate::Create(InfoBarService::FromWebContents(
-          browser->tab_strip_model()->GetActiveWebContents()));
     }
 
+    ObsoleteOSInfoBarDelegate::Create(InfoBarService::FromWebContents(
+        browser->tab_strip_model()->GetActiveWebContents()));
+
     if (browser_defaults::kOSSupportsOtherBrowsers &&
         !command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) {
       // Generally, the default browser prompt should not be shown on first
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc
index 46f030d..2cea5e4 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -26,6 +26,9 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/google/google_util.h"
+#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"
@@ -54,7 +57,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/net/url_util.h"
-#include "chrome/common/one_click_signin_messages.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
@@ -519,13 +521,17 @@
     return;
 
   content::NavigationController* nc = &web_contents()->GetController();
+  HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext()),
+      Profile::IMPLICIT_ACCESS);
 
   // Have to wait until something else gets added to history before removal.
   if (history_index_to_remove_ < nc->GetLastCommittedEntryIndex()) {
     content::NavigationEntry* entry =
         nc->GetEntryAtIndex(history_index_to_remove_);
-    if (signin::IsContinueUrlForWebBasedSigninFlow(entry->GetURL()) &&
-        nc->RemoveEntryAtIndex(history_index_to_remove_)) {
+    if (signin::IsContinueUrlForWebBasedSigninFlow(entry->GetURL())) {
+      hs->DeleteURL(entry->GetURL());
+      nc->RemoveEntryAtIndex(history_index_to_remove_);
       delete this;  // Success.
     }
   }
@@ -560,7 +566,8 @@
 // static
 const int OneClickSigninHelper::kMaxNavigationsSince = 10;
 
-OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents)
+OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents,
+                                           PasswordManager* password_manager)
     : content::WebContentsObserver(web_contents),
       showing_signin_(false),
       auto_accept_(AUTO_ACCEPT_NONE),
@@ -570,6 +577,12 @@
       untrusted_confirmation_required_(false),
       do_not_clear_pending_email_(false),
       weak_pointer_factory_(this) {
+  // May be NULL during testing.
+  if (password_manager) {
+    password_manager->AddSubmissionCallback(
+        base::Bind(&OneClickSigninHelper::PasswordSubmitted,
+                   weak_pointer_factory_.GetWeakPtr()));
+  }
 }
 
 OneClickSigninHelper::~OneClickSigninHelper() {
@@ -585,6 +598,16 @@
 }
 
 // static
+void OneClickSigninHelper::CreateForWebContentsWithPasswordManager(
+    content::WebContents* contents,
+    PasswordManager* password_manager) {
+  if (!FromWebContents(contents)) {
+    contents->SetUserData(UserDataKey(),
+                          new OneClickSigninHelper(contents, password_manager));
+  }
+}
+
+// static
 bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents,
                                     CanOfferFor can_offer_for,
                                     const std::string& email,
@@ -886,6 +909,15 @@
     helper->source_ = source;
   }
 
+  // Save the email in the one-click signin manager.  The manager may
+  // not exist if the contents is incognito or if the profile is already
+  // connected to a Google account.
+  if (!session_index.empty())
+    helper->session_index_ = session_index;
+
+  if (!email.empty())
+    helper->email_ = email;
+
   CanOfferFor can_offer_for =
       (auto_accept != AUTO_ACCEPT_EXPLICIT &&
           helper->auto_accept_ != AUTO_ACCEPT_EXPLICIT) ?
@@ -915,15 +947,6 @@
   helper->untrusted_confirmation_required_ |=
       (manager && !manager->IsSigninProcess(child_id));
 
-  // Save the email in the one-click signin manager.  The manager may
-  // not exist if the contents is incognito or if the profile is already
-  // connected to a Google account.
-  if (!session_index.empty())
-    helper->session_index_ = session_index;
-
-  if (!email.empty())
-    helper->email_ = email;
-
   if (continue_url.is_valid()) {
     // Set |original_continue_url_| if it is currently empty. |continue_url|
     // could be modified by gaia pages, thus we need to record the original
@@ -999,29 +1022,13 @@
   }
 }
 
-bool OneClickSigninHelper::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(OneClickSigninHelper, message)
-    IPC_MESSAGE_HANDLER(OneClickSigninHostMsg_FormSubmitted, OnFormSubmitted)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-bool OneClickSigninHelper::OnFormSubmitted(const content::PasswordForm& form) {
-  // |password_| used to be set in DidNavigateAnyFrame, this is too late because
-  // it is not executed until the end of redirect chains and password may
-  // get lost if one of the redirects requires context swap.
-
+void OneClickSigninHelper::PasswordSubmitted(
+    const content::PasswordForm& form) {
   // We only need to scrape the password for Gaia logins.
-  if (form.origin.is_valid() &&
-      gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) {
+  if (gaia::IsGaiaSignonRealm(GURL(form.signon_realm))) {
     VLOG(1) << "OneClickSigninHelper::DidNavigateAnyFrame: got password";
     password_ = UTF16ToUTF8(form.password_value);
   }
-
-  return true;
 }
 
 void OneClickSigninHelper::SetDoNotClearPendingEmailForTesting() {
@@ -1148,17 +1155,6 @@
     return;
   }
 
-  // When the user uses the first-run, ntp, or hotdog menu to sign in, then have
-  // the option of checking the the box "Let me choose what to sync".  When the
-  // sign in process started, the source parameter in the continue URL may have
-  // indicated one of the three options above.  However, once this box is
-  // checked, the source parameter will indicate settings.  This will only be
-  // communicated back to chrome when Gaia redirects to the continue URL, and
-  // this is considered here a last minute change to the source.  See a little
-  // further below for when this variable is set to a web contents that must be
-  // used to show the sync setup page.
-  content::WebContents* sync_setup_contents = NULL;
-
   if (!continue_url_match && IsValidGaiaSigninRedirectOrResponseURL(url))
     return;
 
@@ -1193,10 +1189,7 @@
     signin::Source source = signin::GetSourceForPromoURL(url);
     if (source != source_) {
       source_ = source;
-      if (source == signin::SOURCE_SETTINGS) {
-        sync_setup_contents = web_contents();
-        switched_to_advanced_ = true;
-      }
+      switched_to_advanced_ = source == signin::SOURCE_SETTINGS;
     }
   }
 
@@ -1256,11 +1249,14 @@
       //   default settings.
       // - If sign in was initiated from the settings page for first time sync
       //   set up, show the advanced sync settings dialog.
-      // - If sign in was initiated from the settings page due to a re-auth,
-      //   simply navigate back to the settings page.
+      // - If sign in was initiated from the settings page due to a re-auth when
+      //   sync was already setup, simply navigate back to the settings page.
+      ProfileSyncService* sync_service =
+          ProfileSyncServiceFactory::GetForProfile(profile);
       OneClickSigninSyncStarter::StartSyncMode start_mode =
           source_ == signin::SOURCE_SETTINGS ?
-              SigninGlobalError::GetForProfile(profile)->HasMenuItem() ?
+              (SigninGlobalError::GetForProfile(profile)->HasMenuItem() &&
+               sync_service && sync_service->HasSyncSetupCompleted()) ?
                   OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
                   OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
               OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
@@ -1274,7 +1270,7 @@
 
         // No need to display a second confirmation so pass false below.
         // TODO(atwilson): Move this into OneClickSigninSyncStarter.
-        // If |sync_setup_contents| is deleted before the callback execution,
+        // If |contents| is deleted before the callback execution,
         // the tab modal dialog is closed and the callback is never executed.
         ConfirmEmailDialogDelegate::AskForConfirmation(
             contents,
@@ -1283,16 +1279,15 @@
             base::Bind(
                 &StartExplicitSync,
                 StartSyncArgs(profile, browser, auto_accept_,
-                              session_index_, email_, password_,
-                              sync_setup_contents,
+                              session_index_, email_, password_, contents,
                               false /* confirmation_required */, source_,
                               CreateSyncStarterCallback()),
                 contents,
                 start_mode));
       } else {
         StartSync(
-            StartSyncArgs(profile, browser, auto_accept_, session_index_,
-                          email_, password_, sync_setup_contents,
+            StartSyncArgs(profile, browser, auto_accept_,
+                          session_index_, email_, password_, contents,
                           untrusted_confirmation_required_, source_,
                           CreateSyncStarterCallback()),
             start_mode);
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.h b/chrome/browser/ui/sync/one_click_signin_helper.h
index 46f7765..da9a138 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper.h
+++ b/chrome/browser/ui/sync/one_click_signin_helper.h
@@ -19,6 +19,7 @@
 
 class Browser;
 class GURL;
+class PasswordManager;
 class ProfileIOData;
 
 namespace content {
@@ -78,6 +79,10 @@
     CAN_OFFER_FOR_INTERSTITAL_ONLY
   };
 
+  static void CreateForWebContentsWithPasswordManager(
+      content::WebContents* contents,
+      PasswordManager* password_manager);
+
   virtual ~OneClickSigninHelper();
 
   // Returns true if the one-click signin feature can be offered at this time.
@@ -125,7 +130,7 @@
  private:
   friend class content::WebContentsUserData<OneClickSigninHelper>;
   friend class OneClickSigninHelperTest;
-  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
+  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIncognitoTest,
                            ShowInfoBarUIThreadIncognito);
   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
                            SigninFromWebstoreWithConfigSyncfirst);
@@ -166,7 +171,8 @@
   // SAML-based accounts, but causes bug crbug.com/181163.
   static const int kMaxNavigationsSince;
 
-  explicit OneClickSigninHelper(content::WebContents* web_contents);
+  OneClickSigninHelper(content::WebContents* web_contents,
+                       PasswordManager* password_manager);
 
   // Returns true if the one-click signin feature can be offered at this time.
   // It can be offered if the io_data is not in an incognito window and if the
@@ -208,11 +214,10 @@
   // TestingProfile provides.
   void SetDoNotClearPendingEmailForTesting();
 
-  // Grab Gaia password if available.
-  bool OnFormSubmitted(const content::PasswordForm& form);
+  // Called when password has been submitted.
+  void PasswordSubmitted(const content::PasswordForm& form);
 
   // content::WebContentsObserver overrides.
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
   virtual void NavigateToPendingEntry(
       const GURL& url,
       content::NavigationController::ReloadType reload_type) OVERRIDE;
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 1406217..d8ceb51 100644
--- a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
+++ b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
@@ -205,11 +205,10 @@
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
-  // Creates the sign-in manager for tests.  If |use_incognito| is true then
-  // a WebContents for an incognito profile is created.  If |username| is
+  // Creates the sign-in manager for tests.  If |username| is
   // is not empty, the profile of the mock WebContents will be connected to
   // the given account.
-  void CreateSigninManager(bool use_incognito, const std::string& username);
+  void CreateSigninManager(const std::string& username);
 
   // Set the ID of the signin process that the test will assume to be the
   // only process allowed to sign the user in to Chrome.
@@ -258,9 +257,7 @@
 }
 
 void OneClickSigninHelperTest::CreateSigninManager(
-    bool use_incognito,
     const std::string& username) {
-  profile()->set_incognito(use_incognito);
   signin_manager_ = static_cast<SigninManagerMock*>(
       SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
           profile(), BuildSigninManagerMock));
@@ -325,7 +322,7 @@
   password_form.origin = GURL("https://accounts.google.com");
   password_form.signon_realm = "https://accounts.google.com";
   password_form.password_value = UTF8ToUTF16("password");
-  helper->OnFormSubmitted(password_form);
+  helper->PasswordSubmitted(password_form);
 }
 
 class OneClickSigninHelperIOTest : public OneClickSigninHelperTest {
@@ -368,6 +365,20 @@
   return io_data;
 }
 
+class OneClickSigninHelperIncognitoTest : public OneClickSigninHelperTest {
+ protected:
+  // content::RenderViewHostTestHarness.
+  virtual content::BrowserContext* CreateBrowserContext() OVERRIDE;
+};
+
+content::BrowserContext*
+OneClickSigninHelperIncognitoTest::CreateBrowserContext() {
+  // Builds an incognito profile to run this test.
+  TestingProfile::Builder builder;
+  builder.SetIncognito();
+  return builder.Build().release();
+}
+
 TEST_F(OneClickSigninHelperTest, CanOfferNoContents) {
   std::string error_message;
   EXPECT_FALSE(OneClickSigninHelper::CanOffer(
@@ -387,7 +398,7 @@
 }
 
 TEST_F(OneClickSigninHelperTest, CanOffer) {
-  CreateSigninManager(false, std::string());
+  CreateSigninManager(std::string());
 
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
         WillRepeatedly(Return(true));
@@ -425,7 +436,7 @@
 }
 
 TEST_F(OneClickSigninHelperTest, CanOfferFirstSetup) {
-  CreateSigninManager(false, std::string());
+  CreateSigninManager(std::string());
 
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
         WillRepeatedly(Return(true));
@@ -455,7 +466,7 @@
 }
 
 TEST_F(OneClickSigninHelperTest, CanOfferProfileConnected) {
-  CreateSigninManager(false, "foo@gmail.com");
+  CreateSigninManager("foo@gmail.com");
 
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
       WillRepeatedly(Return(true));
@@ -495,7 +506,7 @@
 }
 
 TEST_F(OneClickSigninHelperTest, CanOfferUsernameNotAllowed) {
-  CreateSigninManager(false, std::string());
+  CreateSigninManager(std::string());
 
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
       WillRepeatedly(Return(false));
@@ -519,7 +530,7 @@
 }
 
 TEST_F(OneClickSigninHelperTest, CanOfferWithRejectedEmail) {
-  CreateSigninManager(false, std::string());
+  CreateSigninManager(std::string());
 
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
         WillRepeatedly(Return(true));
@@ -547,8 +558,8 @@
       "john@gmail.com", &error_message));
 }
 
-TEST_F(OneClickSigninHelperTest, CanOfferIncognito) {
-  CreateSigninManager(true, std::string());
+TEST_F(OneClickSigninHelperIncognitoTest, CanOfferIncognito) {
+  CreateSigninManager(std::string());
 
   std::string error_message;
   EXPECT_FALSE(OneClickSigninHelper::CanOffer(
@@ -568,7 +579,7 @@
 }
 
 TEST_F(OneClickSigninHelperTest, CanOfferNoSigninCookies) {
-  CreateSigninManager(false, std::string());
+  CreateSigninManager(std::string());
   AllowSigninCookies(false);
 
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
@@ -592,7 +603,7 @@
 }
 
 TEST_F(OneClickSigninHelperTest, CanOfferDisabledByPolicy) {
-  CreateSigninManager(false, std::string());
+  CreateSigninManager(std::string());
 
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_)).
         WillRepeatedly(Return(true));
@@ -626,8 +637,8 @@
 
 // Should not crash if a helper instance is not associated with an incognito
 // web contents.
-TEST_F(OneClickSigninHelperTest, ShowInfoBarUIThreadIncognito) {
-  CreateSigninManager(true, std::string());
+TEST_F(OneClickSigninHelperIncognitoTest, ShowInfoBarUIThreadIncognito) {
+  CreateSigninManager(std::string());
   OneClickSigninHelper* helper =
       OneClickSigninHelper::FromWebContents(web_contents());
   EXPECT_EQ(NULL, helper);
@@ -642,7 +653,7 @@
 // config sync, then Chrome should redirect immediately to sync settings page,
 // and upon successful setup, redirect back to webstore.
 TEST_F(OneClickSigninHelperTest, SigninFromWebstoreWithConfigSyncfirst) {
-  CreateSigninManager(false, std::string());
+  CreateSigninManager(std::string());
   EXPECT_CALL(*signin_manager_, IsAllowedUsername(_))
       .WillRepeatedly(Return(true));
 
@@ -650,7 +661,7 @@
 
   content::WebContents* contents = web_contents();
 
-  OneClickSigninHelper::CreateForWebContents(contents);
+  OneClickSigninHelper::CreateForWebContentsWithPasswordManager(contents, NULL);
   OneClickSigninHelper* helper =
       OneClickSigninHelper::FromWebContents(contents);
   helper->SetDoNotClearPendingEmailForTesting();
@@ -678,7 +689,7 @@
 TEST_F(OneClickSigninHelperTest, CleanTransientStateOnNavigate) {
   content::WebContents* contents = web_contents();
 
-  OneClickSigninHelper::CreateForWebContents(contents);
+  OneClickSigninHelper::CreateForWebContentsWithPasswordManager(contents, NULL);
   OneClickSigninHelper* helper =
       OneClickSigninHelper::FromWebContents(contents);
   helper->SetDoNotClearPendingEmailForTesting();
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 884c09d..441ebc5 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -374,10 +374,10 @@
       break;
     }
     case CONFIGURE_SYNC_FIRST:
-      ShowSettingsPageInNewTab(true);  // Show sync config UI.
+      ShowSettingsPage(true);  // Show sync config UI.
       break;
     case SHOW_SETTINGS_WITHOUT_CONFIGURE:
-      ShowSettingsPageInNewTab(false);  // Don't show sync config UI.
+      ShowSettingsPage(false);  // Don't show sync config UI.
       break;
     default:
       NOTREACHED();
@@ -411,7 +411,7 @@
   }
 }
 
-void OneClickSigninSyncStarter::ShowSettingsPageInNewTab(bool configure_sync) {
+void OneClickSigninSyncStarter::ShowSettingsPage(bool configure_sync) {
   // Give the user a chance to configure things. We don't clear the
   // ProfileSyncService::setup_in_progress flag because we don't want sync
   // to start up until after the configure UI is displayed (the configure UI
@@ -422,10 +422,20 @@
     login_ui->current_login_ui()->FocusUI();
   } else {
     EnsureBrowser();
+
+    // If the sign in tab is showing a blank page and is not about to be
+    // closed, use it to show the settings UI.
+    bool use_same_tab = false;
+    if (web_contents()) {
+      GURL current_url = web_contents()->GetLastCommittedURL();
+      use_same_tab = signin::IsContinueUrlForWebBasedSigninFlow(current_url) &&
+          !signin::IsAutoCloseEnabledInURL(current_url);
+    }
     if (profile_sync_service) {
       // Need to navigate to the settings page and display the sync UI.
-      if (web_contents()) {
-        ShowSyncSettingsPageInWebContents(web_contents());
+      if (use_same_tab) {
+        ShowSettingsPageInWebContents(web_contents(),
+                                      chrome::kSyncSetupSubPage);
       } else {
         // If the user is setting up sync for the first time, let them configure
         // advanced sync settings. However, in the case of re-authentication,
@@ -440,7 +450,10 @@
     } else {
       // Sync is disabled - just display the settings page.
       FinishProfileSyncServiceSetup();
-      chrome::ShowSettings(browser_);
+      if (use_same_tab)
+        ShowSettingsPageInWebContents(web_contents(), std::string());
+      else
+        chrome::ShowSettings(browser_);
     }
   }
 }
@@ -459,10 +472,10 @@
     service->SetSetupInProgress(false);
 }
 
-void OneClickSigninSyncStarter::ShowSyncSettingsPageInWebContents(
-    content::WebContents* contents) {
-  std::string url = std::string(chrome::kChromeUISettingsURL) +
-      chrome::kSyncSetupSubPage;
+void OneClickSigninSyncStarter::ShowSettingsPageInWebContents(
+    content::WebContents* contents,
+    const std::string& sub_page) {
+  std::string url = std::string(chrome::kChromeUISettingsURL) + sub_page;
   content::OpenURLParams params(GURL(url),
                                 content::Referrer(),
                                 CURRENT_TAB,
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.h b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
index 11c3ce5..cc8903f 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.h
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
@@ -81,9 +81,8 @@
   // OneClickSigninSyncStarter from a browser, provide both.
   // If |display_confirmation| is true, the user will be prompted to confirm the
   // signin before signin completes.
-  // |web_contents| is used to show the sync setup page, if necessary. If NULL,
-  // the sync setup page will be loaded in either a new tab or a tab that is
-  // already showing it.
+  // |web_contents| is used to show the sync UI if it's showing a blank page
+  // and not about to be closed. It can be NULL.
   // |callback| is always executed before OneClickSigninSyncStarter is deleted.
   // It can be empty.
   OneClickSigninSyncStarter(Profile* profile,
@@ -183,12 +182,16 @@
 
   void FinishProfileSyncServiceSetup();
 
-  // Displays the settings UI in a new tab. Brings up the advanced sync settings
-  // dialog if |configure_sync| is true.
-  void ShowSettingsPageInNewTab(bool configure_sync);
+  // Displays the settings UI and brings up the advanced sync settings
+  // dialog if |configure_sync| is true. The web contents provided to the
+  // constructor is used if it's showing a blank page and not about to be
+  // closed. Otherwise, a new tab or an existing settings tab is used.
+  void ShowSettingsPage(bool configure_sync);
 
-  // Displays the sync configuration UI in the provided web contents.
-  void ShowSyncSettingsPageInWebContents(content::WebContents* contents);
+  // Displays a settings page in the provided web contents. |sub_page| can be
+  // empty to show the main settings page.
+  void ShowSettingsPageInWebContents(content::WebContents* contents,
+                                     const std::string& sub_page);
 
   // Shows the post-signin confirmation bubble. If |custom_message| is empty,
   // the default "You are signed in" message is displayed.
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 0fc79ad..fdaa0a2 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
@@ -28,7 +28,6 @@
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_manifest_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"
@@ -36,6 +35,7 @@
 #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 "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -97,8 +97,8 @@
     const std::string& name,
     const std::string& id) {
   DictionaryValue manifest;
-  manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
-  manifest.SetString(extension_manifest_keys::kName, name);
+  manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
+  manifest.SetString(extensions::manifest_keys::kName, name);
   std::string error;
   scoped_refptr<extensions::Extension> extension =
     extensions::Extension::Create(
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 8b3675f..746861f 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
+++ b/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/prefs/testing_pref_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_shutdown.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index a550ca0..7b117fa 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -704,10 +704,6 @@
     if ((add_types & ADD_ACTIVE) == 0) {
       contents->GetView()->SizeContents(
           old_contents->GetView()->GetContainerSize());
-      // We need to hide the contents or else we get and execute paints for
-      // background tabs. With enough background tabs they will steal the
-      // backing store of the visible tab causing flashing. See bug 20831.
-      contents->WasHidden();
     }
   }
 }
diff --git a/chrome/browser/ui/toolbar/test_toolbar_model.cc b/chrome/browser/ui/toolbar/test_toolbar_model.cc
index 95411b3..9e14e24 100644
--- a/chrome/browser/ui/toolbar/test_toolbar_model.cc
+++ b/chrome/browser/ui/toolbar/test_toolbar_model.cc
@@ -11,8 +11,7 @@
       should_replace_url_(false),
       security_level_(NONE),
       icon_(IDR_LOCATION_BAR_HTTP),
-      should_display_url_(true),
-      input_in_progress_(false) {}
+      should_display_url_(true) {}
 
 TestToolbarModel::~TestToolbarModel() {}
 
@@ -50,11 +49,3 @@
 bool TestToolbarModel::ShouldDisplayURL() const {
   return should_display_url_;
 }
-
-void TestToolbarModel::SetInputInProgress(bool value) {
-  input_in_progress_ = value;
-}
-
-bool TestToolbarModel::GetInputInProgress() const {
-  return input_in_progress_;
-}
diff --git a/chrome/browser/ui/toolbar/test_toolbar_model.h b/chrome/browser/ui/toolbar/test_toolbar_model.h
index 80b9f19..6ba3655 100644
--- a/chrome/browser/ui/toolbar/test_toolbar_model.h
+++ b/chrome/browser/ui/toolbar/test_toolbar_model.h
@@ -26,8 +26,6 @@
   virtual int GetIcon() const OVERRIDE;
   virtual string16 GetEVCertName() const OVERRIDE;
   virtual bool ShouldDisplayURL() const OVERRIDE;
-  virtual void SetInputInProgress(bool value) OVERRIDE;
-  virtual bool GetInputInProgress() const OVERRIDE;
 
   void set_text(const string16& text) { text_ = text; }
   void set_url(const GURL& url) { url_ = url;}
@@ -53,7 +51,6 @@
   int icon_;
   string16 ev_cert_name_;
   bool should_display_url_;
-  bool input_in_progress_;
 
   DISALLOW_COPY_AND_ASSIGN(TestToolbarModel);
 };
diff --git a/chrome/browser/ui/toolbar/toolbar_model.h b/chrome/browser/ui/toolbar/toolbar_model.h
index 8238cb6..7111327 100644
--- a/chrome/browser/ui/toolbar/toolbar_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_model.h
@@ -76,13 +76,19 @@
   // in the location bar.
   virtual bool ShouldDisplayURL() const = 0;
 
-  // Getter/setter of whether the text in location bar is currently being
-  // edited.
-  virtual void SetInputInProgress(bool value) = 0;
-  virtual bool GetInputInProgress() const = 0;
+  // Whether the text in the omnibox is currently being edited.
+  void set_input_in_progress(bool input_in_progress) {
+    input_in_progress_ = input_in_progress;
+  }
+  bool input_in_progress() const { return input_in_progress_; }
 
  protected:
-   ToolbarModel() {}
+  ToolbarModel() : input_in_progress_(false) {}
+
+ private:
+  bool input_in_progress_;
+
+  DISALLOW_COPY_AND_ASSIGN(ToolbarModel);
 };
 
 #endif  // CHROME_BROWSER_UI_TOOLBAR_TOOLBAR_MODEL_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_model_impl.cc b/chrome/browser/ui/toolbar/toolbar_model_impl.cc
index 4e6f66b..39d85bd 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_impl.cc
+++ b/chrome/browser/ui/toolbar/toolbar_model_impl.cc
@@ -42,8 +42,7 @@
 using content::WebContents;
 
 ToolbarModelImpl::ToolbarModelImpl(ToolbarModelDelegate* delegate)
-    : delegate_(delegate),
-      input_in_progress_(false) {
+    : delegate_(delegate) {
 }
 
 ToolbarModelImpl::~ToolbarModelImpl() {
@@ -182,13 +181,11 @@
   return true;
 }
 
-ToolbarModel::SecurityLevel
-    ToolbarModelImpl::GetSecurityLevel(bool ignore_editing) const {
-  if (!ignore_editing && input_in_progress_) {
-    // When editing, assume no security style.
-    return NONE;
-  }
-  return GetSecurityLevelForWebContents(delegate_->GetActiveWebContents());
+ToolbarModel::SecurityLevel ToolbarModelImpl::GetSecurityLevel(
+    bool ignore_editing) const {
+  // When editing, assume no security style.
+  return (input_in_progress() && !ignore_editing) ?
+      NONE : GetSecurityLevelForWebContents(delegate_->GetActiveWebContents());
 }
 
 int ToolbarModelImpl::GetIcon() const {
@@ -208,7 +205,7 @@
 }
 
 string16 ToolbarModelImpl::GetEVCertName() const {
-  DCHECK_EQ(GetSecurityLevel(false), EV_SECURE);
+  DCHECK_EQ(EV_SECURE, GetSecurityLevel(false));
   scoped_refptr<net::X509Certificate> cert;
   // Note: Navigation controller and active entry are guaranteed non-NULL or
   // the security level would be NONE.
@@ -232,14 +229,6 @@
       UTF8ToUTF16(cert.subject().country_name));
 }
 
-void ToolbarModelImpl::SetInputInProgress(bool value) {
-  input_in_progress_ = value;
-}
-
-bool ToolbarModelImpl::GetInputInProgress() const {
-  return input_in_progress_;
-}
-
 NavigationController* ToolbarModelImpl::GetNavigationController() const {
   // This |current_tab| can be NULL during the initialization of the
   // toolbar during window creation (i.e. before any tabs have been added
@@ -256,6 +245,9 @@
 }
 
 string16 ToolbarModelImpl::GetSearchTerms(bool ignore_editing) const {
+  if (input_in_progress() && !ignore_editing)
+    return string16();
+
   const WebContents* web_contents = delegate_->GetActiveWebContents();
   string16 search_terms(chrome::GetSearchTerms(web_contents));
   if (search_terms.empty())
@@ -274,9 +266,8 @@
     return search_terms;
 
   // If the URL is using a Google base URL specified via the command line, we
-  // allow search term replacement any time the user isn't editing, bypassing
-  // the security check below.
-  if ((ignore_editing || !input_in_progress_) && entry &&
+  // bypass the security check below.
+  if (entry &&
       google_util::StartsWithCommandLineGoogleBaseURL(entry->GetVirtualURL()))
     return search_terms;
 
diff --git a/chrome/browser/ui/toolbar/toolbar_model_impl.h b/chrome/browser/ui/toolbar/toolbar_model_impl.h
index 651e809..e86f3fe 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_impl.h
+++ b/chrome/browser/ui/toolbar/toolbar_model_impl.h
@@ -47,8 +47,6 @@
   virtual int GetIcon() const OVERRIDE;
   virtual string16 GetEVCertName() const OVERRIDE;
   virtual bool ShouldDisplayURL() const OVERRIDE;
-  virtual void SetInputInProgress(bool value) OVERRIDE;
-  virtual bool GetInputInProgress() const OVERRIDE;
 
   // Returns "<organization_name> [<country>]".
   static string16 GetEVCertName(const net::X509Certificate& cert);
@@ -70,9 +68,6 @@
 
   ToolbarModelDelegate* delegate_;
 
-  // Whether the text in the location bar is currently being edited.
-  bool input_in_progress_;
-
   DISALLOW_IMPLICIT_CONSTRUCTORS(ToolbarModelImpl);
 };
 
diff --git a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
index 20595cb..3408299 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
@@ -251,14 +251,14 @@
             toolbar_model->WouldReplaceSearchURLWithSearchTerms(false));
 
   // Now pretend the user started modifying the omnibox.
-  toolbar_model->SetInputInProgress(true);
+  toolbar_model->set_input_in_progress(true);
   EXPECT_FALSE(toolbar_model->WouldReplaceSearchURLWithSearchTerms(false));
   EXPECT_EQ(would_replace,
             toolbar_model->WouldReplaceSearchURLWithSearchTerms(true));
 
   // Tell the ToolbarModel that the user has stopped editing.  This prevents
   // this function from having side effects.
-  toolbar_model->SetInputInProgress(false);
+  toolbar_model->set_input_in_progress(false);
 }
 
 
diff --git a/chrome/browser/ui/unload_controller.cc b/chrome/browser/ui/unload_controller.cc
index e6d66fd..3759839 100644
--- a/chrome/browser/ui/unload_controller.cc
+++ b/chrome/browser/ui/unload_controller.cc
@@ -36,7 +36,8 @@
   // that avoids the fast shutdown path where we just kill all the renderers.
   if (is_attempting_to_close_browser_)
     ClearUnloadState(contents, true);
-  return !is_attempting_to_close_browser_;
+  return !is_attempting_to_close_browser_ ||
+      is_calling_before_unload_handlers();
 }
 
 bool UnloadController::BeforeUnloadFired(content::WebContents* contents,
@@ -71,22 +72,58 @@
   if (HasCompletedUnloadProcessing())
     return true;
 
+  // The behavior followed here varies based on the current phase of the
+  // operation and whether a batched shutdown is in progress.
+  //
+  // If there are tabs with outstanding beforeunload handlers:
+  // 1. If a batched shutdown is in progress: return false.
+  //    This is to prevent interference with batched shutdown already in
+  //    progress.
+  // 2. Otherwise: start sending beforeunload events and return false.
+  //
+  // Otherwise, If there are no tabs with outstanding beforeunload handlers:
+  // 3. If a batched shutdown is in progress: start sending unload events and
+  //    return false.
+  // 4. Otherwise: return true.
   is_attempting_to_close_browser_ = true;
+  // Cases 1 and 4.
+  bool need_beforeunload_fired = TabsNeedBeforeUnloadFired();
+  if (need_beforeunload_fired == is_calling_before_unload_handlers())
+    return !need_beforeunload_fired;
 
-  if (!TabsNeedBeforeUnloadFired())
-    return true;
-
+  // Cases 2 and 3.
+  on_close_confirmed_.Reset();
   ProcessPendingTabs();
   return false;
 }
 
+bool UnloadController::CallBeforeUnloadHandlers(
+    const base::Callback<void(bool)>& on_close_confirmed) {
+  if (HasCompletedUnloadProcessing() || !TabsNeedBeforeUnloadFired())
+    return false;
+
+  is_attempting_to_close_browser_ = true;
+  on_close_confirmed_ = on_close_confirmed;
+
+  ProcessPendingTabs();
+  return true;
+}
+
+void UnloadController::ResetBeforeUnloadHandlers() {
+  if (!is_calling_before_unload_handlers())
+    return;
+  CancelWindowClose();
+}
+
 bool UnloadController::TabsNeedBeforeUnloadFired() {
   if (tabs_needing_before_unload_fired_.empty()) {
     for (int i = 0; i < browser_->tab_strip_model()->count(); ++i) {
       content::WebContents* contents =
           browser_->tab_strip_model()->GetWebContentsAt(i);
-      if (contents->NeedToFireBeforeUnload())
+      if (!ContainsKey(tabs_needing_unload_fired_, contents) &&
+          contents->NeedToFireBeforeUnload()) {
         tabs_needing_before_unload_fired_.insert(contents);
+      }
     }
   }
   return !tabs_needing_before_unload_fired_.empty();
@@ -185,6 +222,8 @@
     } else {
       ClearUnloadState(web_contents, true);
     }
+  } else if (is_calling_before_unload_handlers()) {
+    on_close_confirmed_.Run(true);
   } else if (!tabs_needing_unload_fired_.empty()) {
     // We've finished firing all beforeunload events and can proceed with unload
     // events.
@@ -218,6 +257,11 @@
   DCHECK(is_attempting_to_close_browser_);
   tabs_needing_before_unload_fired_.clear();
   tabs_needing_unload_fired_.clear();
+  if (is_calling_before_unload_handlers()) {
+    base::Callback<void(bool)> on_close_confirmed = on_close_confirmed_;
+    on_close_confirmed_.Reset();
+    on_close_confirmed.Run(false);
+  }
   is_attempting_to_close_browser_ = false;
 
   content::NotificationService::current()->Notify(
diff --git a/chrome/browser/ui/unload_controller.h b/chrome/browser/ui/unload_controller.h
index 4c13c67..b4c0a68 100644
--- a/chrome/browser/ui/unload_controller.h
+++ b/chrome/browser/ui/unload_controller.h
@@ -7,6 +7,7 @@
 
 #include <set>
 
+#include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "content/public/browser/notification_observer.h"
@@ -49,9 +50,18 @@
   }
 
   // Called in response to a request to close |browser_|'s window. Returns true
-  // when there are no remaining unload handlers to be run.
+  // when there are no remaining beforeunload handlers to be run.
   bool ShouldCloseWindow();
 
+  // Begins the process of confirming whether the associated browser can be
+  // closed.
+  bool CallBeforeUnloadHandlers(
+      const base::Callback<void(bool)>& on_close_confirmed);
+
+  // Clears the results of any beforeunload confirmation dialogs triggered by a
+  // CallBeforeUnloadHandlers call.
+  void ResetBeforeUnloadHandlers();
+
   // Returns true if |browser_| has any tabs that have BeforeUnload handlers
   // that have not been fired. This method is non-const because it builds a list
   // of tabs that need their BeforeUnloadHandlers fired.
@@ -110,6 +120,10 @@
   // the state of the stack), pass in false.
   void ClearUnloadState(content::WebContents* web_contents, bool process_now);
 
+  bool is_calling_before_unload_handlers() {
+    return !on_close_confirmed_.is_null();
+  }
+
   Browser* browser_;
 
   content::NotificationRegistrar registrar_;
@@ -128,6 +142,11 @@
   // Browser window isn't just immediately closed.
   bool is_attempting_to_close_browser_;
 
+  // A callback to call to report whether the user chose to close all tabs of
+  // |browser_| that have beforeunload event handlers. This is set only if we
+  // are currently confirming that the browser is closable.
+  base::Callback<void(bool)> on_close_confirmed_;
+
   base::WeakPtrFactory<UnloadController> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(UnloadController);
diff --git a/chrome/browser/ui/views/accessibility/accessibility_event_router_views.cc b/chrome/browser/ui/views/accessibility/accessibility_event_router_views.cc
index dffdb6e..db193be 100644
--- a/chrome/browser/ui/views/accessibility/accessibility_event_router_views.cc
+++ b/chrome/browser/ui/views/accessibility/accessibility_event_router_views.cc
@@ -15,7 +15,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
 #include "ui/base/accessibility/accessible_view_state.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/submenu_view.h"
@@ -48,44 +47,19 @@
     return;
   }
 
-  chrome::NotificationType notification_type;
-  switch (event_type) {
-    case ui::AccessibilityTypes::EVENT_FOCUS:
-      notification_type = chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED;
-      break;
-    case ui::AccessibilityTypes::EVENT_MENUSTART:
-    case ui::AccessibilityTypes::EVENT_MENUPOPUPSTART:
-      notification_type = chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED;
-      break;
-    case ui::AccessibilityTypes::EVENT_MENUEND:
-    case ui::AccessibilityTypes::EVENT_MENUPOPUPEND:
-      notification_type = chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED;
-      break;
-    case ui::AccessibilityTypes::EVENT_TEXT_CHANGED:
-    case ui::AccessibilityTypes::EVENT_SELECTION_CHANGED:
-      // These two events should only be sent for views that have focus. This
-      // enforces the invariant that we fire events triggered by user action and
-      // not by programmatic logic. For example, the location bar can be updated
-      // by javascript while the user focus is within some other part of the
-      // user interface. In contrast, the other supported events here do not
-      // depend on focus. For example, a menu within a menubar can open or close
-      // while focus is within the location bar or anywhere else as a result of
-      // user action. Note that the below logic can at some point be removed if
-      // we pass more information along to the listener such as focused state.
-      if (!view->GetFocusManager() ||
-          view->GetFocusManager()->GetFocusedView() != view)
-        return;
-      notification_type = chrome::NOTIFICATION_ACCESSIBILITY_TEXT_CHANGED;
-      break;
-    case ui::AccessibilityTypes::EVENT_VALUE_CHANGED:
-      notification_type = chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_ACTION;
-      break;
-    case ui::AccessibilityTypes::EVENT_ALERT:
-      notification_type = chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_OPENED;
-      break;
-    case ui::AccessibilityTypes::EVENT_NAME_CHANGED:
-    default:
-      NOTIMPLEMENTED();
+  if (event_type == ui::AccessibilityTypes::EVENT_TEXT_CHANGED ||
+      event_type == ui::AccessibilityTypes::EVENT_SELECTION_CHANGED) {
+    // These two events should only be sent for views that have focus. This
+    // enforces the invariant that we fire events triggered by user action and
+    // not by programmatic logic. For example, the location bar can be updated
+    // by javascript while the user focus is within some other part of the
+    // user interface. In contrast, the other supported events here do not
+    // depend on focus. For example, a menu within a menubar can open or close
+    // while focus is within the location bar or anywhere else as a result of
+    // user action. Note that the below logic can at some point be removed if
+    // we pass more information along to the listener such as focused state.
+    if (!view->GetFocusManager() ||
+        view->GetFocusManager()->GetFocusedView() != view)
       return;
   }
 
@@ -99,9 +73,9 @@
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
       base::Bind(
-          &AccessibilityEventRouterViews::DispatchNotificationOnViewStorageId,
+          &AccessibilityEventRouterViews::DispatchEventOnViewStorageId,
           view_storage_id,
-          notification_type));
+          event_type));
 }
 
 void AccessibilityEventRouterViews::HandleMenuItemFocused(
@@ -124,8 +98,8 @@
                                  has_submenu,
                                  item_index,
                                  item_count);
-  SendAccessibilityNotification(
-      chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED, &info);
+  SendControlAccessibilityNotification(
+      ui::AccessibilityTypes::EVENT_FOCUS, &info);
 }
 
 void AccessibilityEventRouterViews::Observe(
@@ -142,9 +116,9 @@
 // Private methods
 //
 
-void AccessibilityEventRouterViews::DispatchNotificationOnViewStorageId(
+void AccessibilityEventRouterViews::DispatchEventOnViewStorageId(
     int view_storage_id,
-    chrome::NotificationType type) {
+    ui::AccessibilityTypes::Event type) {
   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
   views::View* view = view_storage->RetrieveView(view_storage_id);
   view_storage->RemoveView(view_storage_id);
@@ -153,11 +127,11 @@
 
   AccessibilityEventRouterViews* instance =
       AccessibilityEventRouterViews::GetInstance();
-  instance->DispatchAccessibilityNotification(view, type);
+  instance->DispatchAccessibilityEvent(view, type);
 }
 
-void AccessibilityEventRouterViews::DispatchAccessibilityNotification(
-    views::View* view, chrome::NotificationType type) {
+void AccessibilityEventRouterViews::DispatchAccessibilityEvent(
+    views::View* view, ui::AccessibilityTypes::Event type) {
   // Get the profile associated with this view. If it's not found, use
   // the most recent profile where accessibility events were sent, or
   // the default profile.
@@ -180,8 +154,10 @@
 
   most_recent_profile_ = profile;
 
-  if (type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED ||
-      type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED) {
+  if (type == ui::AccessibilityTypes::EVENT_MENUSTART ||
+      type == ui::AccessibilityTypes::EVENT_MENUPOPUPSTART ||
+      type == ui::AccessibilityTypes::EVENT_MENUEND ||
+      type == ui::AccessibilityTypes::EVENT_MENUPOPUPEND) {
     SendMenuNotification(view, type, profile);
     return;
   }
@@ -234,35 +210,35 @@
 // static
 void AccessibilityEventRouterViews::SendButtonNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   AccessibilityButtonInfo info(
       profile, GetViewName(view), GetViewContext(view));
-  SendAccessibilityNotification(type, &info);
+  SendControlAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendLinkNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   AccessibilityLinkInfo info(profile, GetViewName(view), GetViewContext(view));
-  SendAccessibilityNotification(type, &info);
+  SendControlAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendMenuNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   AccessibilityMenuInfo info(profile, GetViewName(view));
-  SendAccessibilityNotification(type, &info);
+  SendMenuAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendMenuItemNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   std::string name = GetViewName(view);
   std::string context = GetViewContext(view);
@@ -286,13 +262,13 @@
 
   AccessibilityMenuItemInfo info(
       profile, name, context, has_submenu, index, count);
-  SendAccessibilityNotification(type, &info);
+  SendControlAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendTextfieldNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   ui::AccessibleViewState state;
   view->GetAccessibleState(&state);
@@ -303,13 +279,13 @@
   AccessibilityTextBoxInfo info(profile, name, context, password);
   std::string value = UTF16ToUTF8(state.value);
   info.SetValue(value, state.selection_start, state.selection_end);
-  SendAccessibilityNotification(type, &info);
+  SendControlAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendComboboxNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   ui::AccessibleViewState state;
   view->GetAccessibleState(&state);
@@ -318,13 +294,13 @@
   std::string context = GetViewContext(view);
   AccessibilityComboBoxInfo info(
       profile, name, context, value, state.index, state.count);
-  SendAccessibilityNotification(type, &info);
+  SendControlAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendCheckboxNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   ui::AccessibleViewState state;
   view->GetAccessibleState(&state);
@@ -336,13 +312,13 @@
       name,
       context,
       state.state == ui::AccessibilityTypes::STATE_CHECKED);
-  SendAccessibilityNotification(type, &info);
+  SendControlAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendWindowNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   ui::AccessibleViewState state;
   view->GetAccessibleState(&state);
@@ -358,13 +334,13 @@
     window_text = UTF16ToUTF8(state.name);
 
   AccessibilityWindowInfo info(profile, window_text);
-  SendAccessibilityNotification(type, &info);
+  SendWindowAccessibilityNotification(event, &info);
 }
 
 // static
 void AccessibilityEventRouterViews::SendSliderNotification(
     views::View* view,
-    int type,
+    ui::AccessibilityTypes::Event event,
     Profile* profile) {
   ui::AccessibleViewState state;
   view->GetAccessibleState(&state);
@@ -377,7 +353,7 @@
       name,
       context,
       value);
-  SendAccessibilityNotification(type, &info);
+  SendControlAccessibilityNotification(event, &info);
 }
 
 // static
@@ -444,28 +420,6 @@
 }
 
 // static
-bool AccessibilityEventRouterViews::IsMenuEvent(
-    views::View* view,
-    int type) {
-  if (type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED ||
-      type == chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED)
-    return true;
-
-  while (view) {
-    ui::AccessibleViewState state;
-    view->GetAccessibleState(&state);
-    ui::AccessibilityTypes::Role role = state.role;
-    if (role == ui::AccessibilityTypes::ROLE_MENUITEM ||
-        role == ui::AccessibilityTypes::ROLE_MENUPOPUP) {
-      return true;
-    }
-    view = view->parent();
-  }
-
-  return false;
-}
-
-// static
 void AccessibilityEventRouterViews::RecursiveGetMenuItemIndexAndCount(
     views::View* menu,
     views::View* item,
diff --git a/chrome/browser/ui/views/accessibility/accessibility_event_router_views.h b/chrome/browser/ui/views/accessibility/accessibility_event_router_views.h
index 9bb3a25..f5738b6 100644
--- a/chrome/browser/ui/views/accessibility/accessibility_event_router_views.h
+++ b/chrome/browser/ui/views/accessibility/accessibility_event_router_views.h
@@ -11,7 +11,6 @@
 #include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/accessibility/accessibility_events.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "ui/base/accessibility/accessibility_types.h"
@@ -70,54 +69,54 @@
   AccessibilityEventRouterViews();
   virtual ~AccessibilityEventRouterViews();
 
-  // Call DispatchAccessibilityNotification using a view storage id.
-  static void DispatchNotificationOnViewStorageId(
+  // Call DispatchAccessibilityEvent using a view storage id.
+  static void DispatchEventOnViewStorageId(
       int view_storage_id,
-      chrome::NotificationType type);
+      ui::AccessibilityTypes::Event event);
 
   // Checks the type of the view and calls one of the more specific
   // Send*Notification methods, below.
-  void DispatchAccessibilityNotification(
+  void DispatchAccessibilityEvent(
       views::View* view,
-      chrome::NotificationType type);
+      ui::AccessibilityTypes::Event event);
 
   // Each of these methods constructs an AccessibilityControlInfo object
   // and sends a notification of a specific accessibility event.
   static void SendButtonNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendLinkNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendMenuNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendMenuItemNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendTextfieldNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendComboboxNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendCheckboxNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendWindowNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
   static void SendSliderNotification(
       views::View* view,
-      int type,
+      ui::AccessibilityTypes::Event event,
       Profile* profile);
 
   // Return the name of a view.
@@ -131,10 +130,6 @@
       views::View* view,
       ui::AccessibilityTypes::Role role);
 
-  // Return true if it's an event on a menu.
-  static bool IsMenuEvent(views::View* view,
-                          int type);
-
   // Recursively explore all menu items of |menu| and return in |count|
   // the total number of items, and in |index| the 0-based index of
   // |item|, if found. Initialize |count| to zero before calling this
diff --git a/chrome/browser/ui/views/accessibility/accessibility_event_router_views_unittest.cc b/chrome/browser/ui/views/accessibility/accessibility_event_router_views_unittest.cc
index 710eb9e..1559a29 100644
--- a/chrome/browser/ui/views/accessibility/accessibility_event_router_views_unittest.cc
+++ b/chrome/browser/ui/views/accessibility/accessibility_event_router_views_unittest.cc
@@ -8,11 +8,8 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/accessibility/accessibility_extension_api.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/views/accessibility/accessibility_event_router_views.h"
 #include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/accessibility/accessible_view_state.h"
 #include "ui/views/controls/button/label_button.h"
@@ -104,10 +101,9 @@
 };
 
 class AccessibilityEventRouterViewsTest
-    : public testing::Test,
-      public content::NotificationObserver {
+    : public testing::Test {
  public:
-  AccessibilityEventRouterViewsTest() {
+  AccessibilityEventRouterViewsTest() : focus_event_count_(0) {
   }
 
   virtual void SetUp() {
@@ -119,9 +115,11 @@
     aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
     aura_test_helper_->SetUp();
 #endif  // USE_AURA
+    EnableAccessibilityAndListenToFocusNotifications();
   }
 
   virtual void TearDown() {
+    ClearCallback();
 #if defined(USE_AURA)
     aura_test_helper_->TearDown();
 #endif
@@ -155,25 +153,25 @@
   }
 
   void EnableAccessibilityAndListenToFocusNotifications() {
-    registrar_.Add(this,
-                   chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED,
-                   content::NotificationService::AllSources());
-
     // Switch on accessibility event notifications.
     ExtensionAccessibilityEventRouter* accessibility_event_router =
         ExtensionAccessibilityEventRouter::GetInstance();
     accessibility_event_router->SetAccessibilityEnabled(true);
+    accessibility_event_router->SetControlEventCallbackForTesting(base::Bind(
+        &AccessibilityEventRouterViewsTest::OnFocusEvent,
+        base::Unretained(this)));
+  }
+
+  void ClearCallback() {
+    ExtensionAccessibilityEventRouter* accessibility_event_router =
+        ExtensionAccessibilityEventRouter::GetInstance();
+    accessibility_event_router->ClearControlEventCallback();
   }
 
  protected:
-  // Implement NotificationObserver::Observe and store information about a
-  // ACCESSIBILITY_CONTROL_FOCUSED event.
-  virtual void Observe(int type,
-                       const content::NotificationSource& source,
-                       const content::NotificationDetails& details) OVERRIDE {
-    ASSERT_EQ(type, chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED);
-    const AccessibilityControlInfo* info =
-        content::Details<const AccessibilityControlInfo>(details).ptr();
+  // Handle Focus event.
+  virtual void OnFocusEvent(ui::AccessibilityTypes::Event event,
+                            const AccessibilityControlInfo* info) {
     focus_event_count_++;
     last_control_name_ = info->name();
     last_control_context_ = info->context();
@@ -183,7 +181,6 @@
   int focus_event_count_;
   std::string last_control_name_;
   std::string last_control_context_;
-  content::NotificationRegistrar registrar_;
   TestingProfile profile_;
 #if defined(OS_WIN)
   scoped_ptr<ui::ScopedOleInitializer> ole_initializer_;
@@ -219,10 +216,10 @@
   window->Show();
   window->Activate();
 
-  // Set focus to the first button initially.
+  // Set focus to the first button initially and run message loop to execute
+  // callback.
   button1->RequestFocus();
-
-  EnableAccessibilityAndListenToFocusNotifications();
+  base::MessageLoop::current()->RunUntilIdle();
 
   // Change the accessible name of button3.
   button3->SetAccessibleName(ASCIIToUTF16(kButton3NewASCII));
@@ -267,8 +264,6 @@
   // Put the view in a window.
   views::Widget* window = CreateWindowWithContents(contents);
 
-  EnableAccessibilityAndListenToFocusNotifications();
-
   // Set focus to the button.
   focus_event_count_ = 0;
   button->RequestFocus();
@@ -301,8 +296,6 @@
   // Put the view in a window.
   views::Widget* window = CreateWindowWithContents(contents);
 
-  EnableAccessibilityAndListenToFocusNotifications();
-
   // Set focus to the button.
   focus_event_count_ = 0;
   button->RequestFocus();
@@ -335,8 +328,6 @@
   // Put the view in a window.
   views::Widget* window = CreateWindowWithContents(contents);
 
-  EnableAccessibilityAndListenToFocusNotifications();
-
   // Set focus to the child view.
   focus_event_count_ = 0;
   child->RequestFocus();
@@ -373,8 +364,6 @@
   // Put the view in a window.
   views::Widget* window = CreateWindowWithContents(contents);
 
-  EnableAccessibilityAndListenToFocusNotifications();
-
   // Set focus to the child view.
   focus_event_count_ = 0;
   child->RequestFocus();
diff --git a/chrome/browser/ui/views/app_list/app_list_controller_win.cc b/chrome/browser/ui/views/app_list/app_list_controller_win.cc
index 46bdc93..2574a61 100644
--- a/chrome/browser/ui/views/app_list/app_list_controller_win.cc
+++ b/chrome/browser/ui/views/app_list/app_list_controller_win.cc
@@ -32,8 +32,8 @@
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/app_list/app_list_service_win.h"
 #include "chrome/browser/ui/app_list/app_list_view_delegate.h"
+#include "chrome/browser/ui/apps/app_metro_infobar_delegate_win.h"
 #include "chrome/browser/ui/browser_commands.h"
-#include "chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/views/browser_dialogs.h"
 #include "chrome/browser/web_applications/web_app.h"
@@ -111,6 +111,111 @@
 #endif
 }
 
+string16 GetAppListIconPath() {
+  base::FilePath icon_path;
+  if (!PathService::Get(base::FILE_EXE, &icon_path)) {
+    NOTREACHED();
+    return string16();
+  }
+
+  std::stringstream ss;
+  ss << "," << GetAppListIconIndex();
+  string16 result = icon_path.value();
+  result.append(UTF8ToUTF16(ss.str()));
+  return result;
+}
+
+// Utility methods for showing the app list.
+// Attempts to find the bounds of the Windows taskbar. Returns true on success.
+// |rect| is in screen coordinates. If the taskbar is in autohide mode and is
+// not visible, |rect| will be outside the current monitor's bounds, except for
+// one pixel of overlap where the edge of the taskbar is shown.
+bool GetTaskbarRect(gfx::Rect* rect) {
+  HWND taskbar_hwnd = FindWindow(kTrayClassName, NULL);
+  if (!taskbar_hwnd)
+    return false;
+
+  RECT win_rect;
+  if (!GetWindowRect(taskbar_hwnd, &win_rect))
+    return false;
+
+  *rect = gfx::Rect(win_rect);
+  return true;
+}
+
+gfx::Point FindReferencePoint(const gfx::Display& display,
+                              const gfx::Point& cursor) {
+  const int kSnapDistance = 50;
+
+  // If we can't find the taskbar, snap to the bottom left.
+  // If the display size is the same as the work area, and does not contain the
+  // taskbar, either the taskbar is hidden or on another monitor, so just snap
+  // to the bottom left.
+  gfx::Rect taskbar_rect;
+  if (!GetTaskbarRect(&taskbar_rect) ||
+      (display.work_area() == display.bounds() &&
+          !display.work_area().Contains(taskbar_rect))) {
+    return display.work_area().bottom_left();
+  }
+
+  // Snap to the taskbar edge. If the cursor is greater than kSnapDistance away,
+  // also move to the left (for horizontal taskbars) or top (for vertical).
+  const gfx::Rect& screen_rect = display.bounds();
+  // First handle taskbar on bottom.
+  // Note on Windows 8 the work area won't include split windows on the left or
+  // right, and neither will |taskbar_rect|.
+  if (taskbar_rect.width() == display.work_area().width()) {
+    if (taskbar_rect.bottom() == screen_rect.bottom()) {
+      if (taskbar_rect.y() - cursor.y() > kSnapDistance)
+        return gfx::Point(screen_rect.x(), taskbar_rect.y());
+
+      return gfx::Point(cursor.x(), taskbar_rect.y());
+    }
+
+    // Now try on the top.
+    if (cursor.y() - taskbar_rect.bottom() > kSnapDistance)
+      return gfx::Point(screen_rect.x(), taskbar_rect.bottom());
+
+    return gfx::Point(cursor.x(), taskbar_rect.bottom());
+  }
+
+  // Now try the left.
+  if (taskbar_rect.x() == screen_rect.x()) {
+    if (cursor.x() - taskbar_rect.right() > kSnapDistance)
+      return gfx::Point(taskbar_rect.right(), screen_rect.y());
+
+    return gfx::Point(taskbar_rect.right(), cursor.y());
+  }
+
+  // Finally, try the right.
+  if (taskbar_rect.x() - cursor.x() > kSnapDistance)
+    return gfx::Point(taskbar_rect.x(), screen_rect.y());
+
+  return gfx::Point(taskbar_rect.x(), cursor.y());
+}
+
+gfx::Point FindAnchorPoint(
+    const gfx::Size view_size,
+    const gfx::Display& display,
+    const gfx::Point& cursor) {
+  const int kSnapOffset = 3;
+
+  gfx::Rect bounds_rect(display.work_area());
+  // Always subtract the taskbar area since work_area() will not subtract it
+  // if the taskbar is set to auto-hide, and the app list should never overlap
+  // the taskbar.
+  gfx::Rect taskbar_rect;
+  if (GetTaskbarRect(&taskbar_rect))
+    bounds_rect.Subtract(taskbar_rect);
+
+  bounds_rect.Inset(view_size.width() / 2 + kSnapOffset,
+                    view_size.height() / 2 + kSnapOffset);
+
+  gfx::Point anchor = FindReferencePoint(display, cursor);
+  anchor.SetToMax(bounds_rect.origin());
+  anchor.SetToMin(bounds_rect.bottom_right());
+  return anchor;
+}
 string16 GetAppListShortcutName() {
   chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
   if (channel == chrome::VersionInfo::CHANNEL_CANARY)
@@ -252,7 +357,6 @@
   // AppListController overrides:
   virtual void DismissView() OVERRIDE;
   virtual void ViewClosing() OVERRIDE;
-  virtual void ViewActivationChanged(bool active) OVERRIDE;
   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE;
   virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
   virtual bool CanPin() OVERRIDE;
@@ -272,6 +376,39 @@
   DISALLOW_COPY_AND_ASSIGN(AppListControllerDelegateWin);
 };
 
+// Customizes the app list |hwnd| for Windows (eg: disable aero peek, set up
+// restart params).
+void SetWindowAttributes(HWND hwnd) {
+  // Vista and lower do not offer pinning to the taskbar, which makes any
+  // presence on the taskbar useless. So, hide the window on the taskbar
+  // for these versions of Windows.
+  if (base::win::GetVersion() <= base::win::VERSION_VISTA) {
+    LONG_PTR ex_styles = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+    ex_styles |= WS_EX_TOOLWINDOW;
+    SetWindowLongPtr(hwnd, GWL_EXSTYLE, ex_styles);
+  }
+
+  if (base::win::GetVersion() > base::win::VERSION_VISTA) {
+    // Disable aero peek. Without this, hovering over the taskbar popup puts
+    // Windows into a mode for switching between windows in the same
+    // application. The app list has just one window, so it is just distracting.
+    BOOL disable_value = TRUE;
+    ::DwmSetWindowAttribute(hwnd,
+                            DWMWA_DISALLOW_PEEK,
+                            &disable_value,
+                            sizeof(disable_value));
+  }
+
+  ui::win::SetAppIdForWindow(GetAppModelId(), hwnd);
+  CommandLine relaunch = GetAppListCommandLine();
+  string16 app_name(GetAppListShortcutName());
+  ui::win::SetRelaunchDetailsForWindow(
+      relaunch.GetCommandLineString(), app_name, hwnd);
+  ::SetWindowText(hwnd, app_name.c_str());
+  string16 icon_path = GetAppListIconPath();
+  ui::win::SetAppIconForWindow(icon_path, hwnd);
+}
+
 class ScopedKeepAlive {
  public:
   ScopedKeepAlive() { chrome::StartKeepAlive(); }
@@ -281,21 +418,27 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedKeepAlive);
 };
 
-class ActivationTracker {
+class ActivationTracker : public app_list::AppListView::Observer {
  public:
   ActivationTracker(app_list::AppListView* view,
-                    const base::Closure& on_active_lost)
+                    const base::Closure& on_should_dismiss)
       : view_(view),
-        on_active_lost_(on_active_lost),
+        on_should_dismiss_(on_should_dismiss),
         regain_next_lost_focus_(false),
         preserving_focus_for_taskbar_menu_(false) {
+    view_->AddObserver(this);
+  }
+
+  ~ActivationTracker() {
+    view_->RemoveObserver(this);
   }
 
   void RegainNextLostFocus() {
     regain_next_lost_focus_ = true;
   }
 
-  void OnActivationChanged(bool active) {
+  virtual void OnActivationChanged(
+      views::Widget* widget, bool active) OVERRIDE {
     const int kFocusCheckIntervalMS = 250;
     if (active) {
       timer_.Stop();
@@ -344,7 +487,7 @@
 
       // If the focused window is NULL, and the mouse button is not being
       // pressed, then the launcher no longer has focus.
-      on_active_lost_.Run();
+      on_should_dismiss_.Run();
       return;
     }
 
@@ -384,7 +527,7 @@
 
     // If we get here, the focused window is not the taskbar, it's context menu,
     // or the app list.
-    on_active_lost_.Run();
+    on_should_dismiss_.Run();
   }
 
  private:
@@ -392,7 +535,7 @@
   app_list::AppListView* view_;
 
   // Called to request |view_| be closed.
-  base::Closure on_active_lost_;
+  base::Closure on_should_dismiss_;
 
   // True if we are anticipating that the app list will lose focus, and we want
   // to take it back. This is used when switching out of Metro mode, and the
@@ -413,6 +556,224 @@
   base::RepeatingTimer<ActivationTracker> timer_;
 };
 
+// Responsible for positioning, hiding and showing an AppListView on Windows.
+// This includes watching window activation/deactivation messages to determine
+// if the user has clicked away from it.
+class AppListViewWin {
+ public:
+  AppListViewWin(app_list::AppListView* view,
+                 const base::Closure& on_should_dismiss)
+    : view_(view),
+      activation_tracker_(view, on_should_dismiss),
+      window_icon_updated_(false) {
+  }
+
+  void Show() {
+    view_->GetWidget()->Show();
+    if (!window_icon_updated_) {
+      view_->GetWidget()->GetTopLevelWidget()->UpdateWindowIcon();
+      window_icon_updated_ = true;
+    }
+    view_->GetWidget()->Activate();
+  }
+
+  void ShowNearCursor(const gfx::Point& cursor) {
+    UpdateArrowPositionAndAnchorPoint(cursor);
+    Show();
+  }
+
+  void Hide() {
+    view_->GetWidget()->Hide();
+    activation_tracker_.OnViewHidden();
+  }
+
+  bool IsVisible() {
+    return view_->GetWidget()->IsVisible();
+  }
+
+  void Prerender() {
+    view_->Prerender();
+  }
+
+  void RegainNextLostFocus() {
+    activation_tracker_.RegainNextLostFocus();
+  }
+
+  gfx::NativeWindow GetWindow() {
+    return view_->GetWidget()->GetNativeWindow();
+  }
+
+  void OnSigninStatusChanged() {
+    view_->OnSigninStatusChanged();
+  }
+
+ private:
+  void UpdateArrowPositionAndAnchorPoint(const gfx::Point& cursor) {
+    gfx::Screen* screen =
+        gfx::Screen::GetScreenFor(view_->GetWidget()->GetNativeView());
+    gfx::Display display = screen->GetDisplayNearestPoint(cursor);
+
+    view_->SetBubbleArrow(views::BubbleBorder::FLOAT);
+    view_->SetAnchorPoint(FindAnchorPoint(
+        view_->GetPreferredSize(), display, cursor));
+  }
+
+
+  // Weak pointer. The view manages its own lifetime.
+  app_list::AppListView* view_;
+  ActivationTracker activation_tracker_;
+  bool window_icon_updated_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListViewWin);
+};
+
+// Factory for AppListViews. Used to allow us to create fake views in tests.
+class AppListViewFactory {
+ public:
+  AppListViewFactory() {}
+  virtual ~AppListViewFactory() {}
+
+  AppListViewWin* CreateAppListView(
+      Profile* profile,
+      app_list::PaginationModel* pagination_model,
+      const base::Closure& on_should_dismiss) {
+    // The controller will be owned by the view delegate, and the delegate is
+    // owned by the app list view. The app list view manages it's own lifetime.
+    // TODO(koz): Make AppListViewDelegate take a scoped_ptr.
+    AppListViewDelegate* view_delegate = new AppListViewDelegate(
+        new AppListControllerDelegateWin, profile);
+    app_list::AppListView* view = new app_list::AppListView(view_delegate);
+    gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
+    view->InitAsBubble(NULL,
+                       pagination_model,
+                       NULL,
+                       cursor,
+                       views::BubbleBorder::FLOAT,
+                       false /* border_accepts_events */);
+    SetWindowAttributes(view->GetHWND());
+    return new AppListViewWin(view, on_should_dismiss);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AppListViewFactory);
+};
+
+// Creates and shows AppListViews as needed.
+class AppListShower {
+ public:
+  explicit AppListShower(scoped_ptr<AppListViewFactory> factory)
+      : factory_(factory.Pass()),
+        profile_(NULL),
+        can_close_app_list_(true) {
+  }
+
+  void set_can_close(bool can_close) {
+    can_close_app_list_ = can_close;
+  }
+
+  void ShowAndReacquireFocus(Profile* requested_profile) {
+    ShowForProfile(requested_profile);
+    view_->RegainNextLostFocus();
+  }
+
+  void ShowForProfile(Profile* requested_profile) {
+    // If the app list is already displaying |profile| just activate it (in case
+    // we have lost focus).
+    if (IsAppListVisible() && (requested_profile == profile_)) {
+      view_->Show();
+      return;
+    }
+
+    DismissAppList();
+    CreateViewForProfile(requested_profile);
+
+    DCHECK(view_);
+    EnsureHaveKeepAliveForView();
+    gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
+    view_->ShowNearCursor(cursor);
+  }
+
+  gfx::NativeWindow GetWindow() {
+    if (!view_)
+      return NULL;
+    return view_->GetWindow();
+  }
+
+  void OnSigninStatusChanged() {
+    if (view_)
+      view_->OnSigninStatusChanged();
+  }
+
+  // Create or recreate, and initialize |view_| from |requested_profile|.
+  void CreateViewForProfile(Profile* requested_profile) {
+    // Aura has problems with layered windows and bubble delegates. The app
+    // launcher has a trick where it only hides the window when it is dismissed,
+    // reshowing it again later. This does not work with win aura for some
+    // reason. This change temporarily makes it always get recreated, only on
+    // win aura. See http://crbug.com/176186.
+#if !defined(USE_AURA)
+    if (requested_profile == profile_)
+      return;
+#endif
+
+    profile_ = requested_profile;
+    view_.reset(factory_->CreateAppListView(
+        profile_, &pagination_model_,
+        base::Bind(&AppListShower::DismissAppList, base::Unretained(this))));
+  }
+
+  void DismissAppList() {
+    if (view_ && can_close_app_list_) {
+      view_->Hide();
+      FreeAnyKeepAliveForView();
+    }
+  }
+
+  void CloseAppList() {
+    view_.reset();
+    profile_ = NULL;
+    FreeAnyKeepAliveForView();
+  }
+
+  bool IsAppListVisible() const {
+    return view_ && view_->IsVisible();
+  }
+
+  void WarmupForProfile(Profile* profile) {
+    DCHECK(!profile_);
+    CreateViewForProfile(profile);
+    view_->Prerender();
+  }
+
+  bool HasView() const {
+    return !!view_;
+  }
+
+ private:
+  void EnsureHaveKeepAliveForView() {
+    if (!keep_alive_)
+      keep_alive_.reset(new ScopedKeepAlive());
+  }
+
+  void FreeAnyKeepAliveForView() {
+    if (keep_alive_)
+      keep_alive_.reset(NULL);
+  }
+
+  scoped_ptr<AppListViewFactory> factory_;
+  scoped_ptr<AppListViewWin> view_;
+  Profile* profile_;
+  bool can_close_app_list_;
+
+  // PaginationModel that is shared across all views.
+  app_list::PaginationModel pagination_model_;
+
+  // Used to keep the browser process alive while the app list is visible.
+  scoped_ptr<ScopedKeepAlive> keep_alive_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListShower);
+};
+
 // The AppListController class manages global resources needed for the app
 // list to operate, and controls when the app list is opened and closed.
 // TODO(tapted): Rename this class to AppListServiceWin and move entire file to
@@ -427,16 +788,15 @@
                      LeakySingletonTraits<AppListController> >::get();
   }
 
-  void set_can_close(bool can_close) { can_close_app_list_ = can_close; }
-  bool can_close() { return can_close_app_list_; }
+  void set_can_close(bool can_close) {
+    shower_->set_can_close(can_close);
+  }
 
-  void AppListClosing();
-  void AppListActivationChanged(bool active);
-  void ShowAppListDuringModeSwitch(Profile* requested_profile);
-
-  app_list::AppListView* GetView() { return current_view_; }
+  void OnAppListClosing();
 
   // AppListService overrides:
+  virtual void SetAppListNextPaintCallback(
+      const base::Closure& callback) OVERRIDE;
   virtual void HandleFirstRun() OVERRIDE;
   virtual void Init(Profile* initial_profile) OVERRIDE;
   virtual void CreateForProfile(Profile* requested_profile) OVERRIDE;
@@ -448,7 +808,6 @@
 
   // AppListServiceImpl overrides:
   virtual void CreateShortcut() OVERRIDE;
-  virtual void OnSigninStatusChanged() OVERRIDE;
 
  private:
   friend struct DefaultSingletonTraits<AppListController>;
@@ -465,42 +824,8 @@
   void LoadProfileForWarmup();
   void OnLoadProfileForWarmup(Profile* initial_profile);
 
-  // Creates an AppListView.
-  app_list::AppListView* CreateAppListView();
-
-  // Customizes the app list |hwnd| for Windows (eg: disable aero peek, set up
-  // restart params).
-  void SetWindowAttributes(HWND hwnd);
-
-  // Utility methods for showing the app list.
-  gfx::Point FindAnchorPoint(const gfx::Display& display,
-                             const gfx::Point& cursor);
-  void UpdateArrowPositionAndAnchorPoint(const gfx::Point& cursor);
-  string16 GetAppListIconPath();
-
-  // Check if the app list or the taskbar has focus. The app list is kept
-  // visible whenever either of these have focus, which allows it to be
-  // pinned but will hide it if it otherwise loses focus. This is checked
-  // periodically whenever the app list does not have focus.
-  void CheckTaskbarOrViewHasFocus();
-
-  // Utilities to manage browser process keep alive for the view itself. Note
-  // keep alives are also used when asynchronously loading profiles.
-  void EnsureHaveKeepAliveForView();
-  void FreeAnyKeepAliveForView();
-
-  // Weak pointer. The view manages its own lifetime.
-  app_list::AppListView* current_view_;
-
-  scoped_ptr<ActivationTracker> activation_tracker_;
-
-  app_list::PaginationModel pagination_model_;
-
-  // True if the controller can close the app list.
-  bool can_close_app_list_;
-
-  // Used to keep the browser process alive while the app list is visible.
-  scoped_ptr<ScopedKeepAlive> keep_alive_;
+  // Responsible for putting views on the screen.
+  scoped_ptr<AppListShower> shower_;
 
   bool enable_app_list_on_next_init_;
 
@@ -517,12 +842,8 @@
   AppListController::GetInstance()->DismissAppList();
 }
 
-void AppListControllerDelegateWin::ViewActivationChanged(bool active) {
-  AppListController::GetInstance()->AppListActivationChanged(active);
-}
-
 void AppListControllerDelegateWin::ViewClosing() {
-  AppListController::GetInstance()->AppListClosing();
+  AppListController::GetInstance()->OnAppListClosing();
 }
 
 gfx::NativeWindow AppListControllerDelegateWin::GetAppListWindow() {
@@ -562,12 +883,9 @@
       extension_id);
   DCHECK(extension);
 
-  app_list::AppListView* view = AppListController::GetInstance()->GetView();
-  if (!view)
+  gfx::NativeWindow parent_hwnd = GetAppListWindow();
+  if (!parent_hwnd)
     return;
-
-  gfx::NativeWindow parent_hwnd =
-      view->GetWidget()->GetTopLevelWidget()->GetNativeWindow();
   OnShowExtensionPrompt();
   chrome::ShowCreateChromeAppShortcutsDialog(
       parent_hwnd, profile, extension,
@@ -595,31 +913,26 @@
 }
 
 AppListController::AppListController()
-    : current_view_(NULL),
-      can_close_app_list_(true),
-      enable_app_list_on_next_init_(false),
+    : enable_app_list_on_next_init_(false),
+      shower_(new AppListShower(make_scoped_ptr(new AppListViewFactory))),
       weak_factory_(this) {}
 
 AppListController::~AppListController() {
 }
 
 gfx::NativeWindow AppListController::GetAppListWindow() {
-  if (!IsAppListVisible())
-    return NULL;
-  return current_view_ ? current_view_->GetWidget()->GetNativeWindow() : NULL;
+  return shower_->GetWindow();
 }
 
 AppListControllerDelegate* AppListController::CreateControllerDelegate() {
   return new AppListControllerDelegateWin();
 }
 
-void AppListController::OnSigninStatusChanged() {
-  if (current_view_)
-    current_view_->OnSigninStatusChanged();
-}
-
 void AppListController::ShowForProfile(Profile* requested_profile) {
   DCHECK(requested_profile);
+  if (requested_profile->IsManaged())
+    return;
+
   ScopedKeepAlive show_app_list_keepalive;
 
   content::BrowserThread::PostBlockingPoolTask(
@@ -635,249 +948,33 @@
   }
 
   InvalidatePendingProfileLoads();
-
-  // If the app list is already displaying |profile| just activate it (in case
-  // we have lost focus).
-  if (IsAppListVisible() && (requested_profile == profile())) {
-    current_view_->GetWidget()->Show();
-    current_view_->GetWidget()->Activate();
-    return;
-  }
-
+  // TODO(koz): Investigate making SetProfile() call SetProfilePath() itself.
   SetProfilePath(requested_profile->GetPath());
-
-  DismissAppList();
-  CreateForProfile(requested_profile);
-
-  DCHECK(current_view_);
-  EnsureHaveKeepAliveForView();
-  gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
-  UpdateArrowPositionAndAnchorPoint(cursor);
-  current_view_->GetWidget()->Show();
-  current_view_->GetWidget()->GetTopLevelWidget()->UpdateWindowIcon();
-  current_view_->GetWidget()->Activate();
+  SetProfile(requested_profile);
+  shower_->ShowForProfile(requested_profile);
   RecordAppListLaunch();
 }
 
-void AppListController::ShowAppListDuringModeSwitch(
-    Profile* requested_profile) {
-  ShowForProfile(requested_profile);
-  activation_tracker_->RegainNextLostFocus();
-}
-
-void AppListController::CreateForProfile(Profile* requested_profile) {
-  // Aura has problems with layered windows and bubble delegates. The app
-  // launcher has a trick where it only hides the window when it is dismissed,
-  // reshowing it again later. This does not work with win aura for some
-  // reason. This change temporarily makes it always get recreated, only on win
-  // aura. See http://crbug.com/176186.
-#if !defined(USE_AURA)
-  if (requested_profile == profile())
-    return;
-#endif
-
-  SetProfile(requested_profile);
-  current_view_ = CreateAppListView();
-  activation_tracker_.reset(new ActivationTracker(current_view_,
-      base::Bind(&AppListController::DismissAppList, base::Unretained(this))));
-}
-
-app_list::AppListView* AppListController::CreateAppListView() {
-  // The controller will be owned by the view delegate, and the delegate is
-  // owned by the app list view. The app list view manages it's own lifetime.
-  AppListViewDelegate* view_delegate =
-      new AppListViewDelegate(CreateControllerDelegate(), profile());
-  app_list::AppListView* view = new app_list::AppListView(view_delegate);
-  gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint();
-  view->InitAsBubble(NULL,
-                     &pagination_model_,
-                     NULL,
-                     cursor,
-                     views::BubbleBorder::FLOAT,
-                     false /* border_accepts_events */);
-  SetWindowAttributes(view->GetHWND());
-  return view;
-}
-
-void AppListController::SetWindowAttributes(HWND hwnd) {
-  // Vista and lower do not offer pinning to the taskbar, which makes any
-  // presence on the taskbar useless. So, hide the window on the taskbar
-  // for these versions of Windows.
-  if (base::win::GetVersion() <= base::win::VERSION_VISTA) {
-    LONG_PTR ex_styles = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
-    ex_styles |= WS_EX_TOOLWINDOW;
-    SetWindowLongPtr(hwnd, GWL_EXSTYLE, ex_styles);
-  }
-
-  if (base::win::GetVersion() > base::win::VERSION_VISTA) {
-    // Disable aero peek. Without this, hovering over the taskbar popup puts
-    // Windows into a mode for switching between windows in the same
-    // application. The app list has just one window, so it is just distracting.
-    BOOL disable_value = TRUE;
-    ::DwmSetWindowAttribute(hwnd,
-                            DWMWA_DISALLOW_PEEK,
-                            &disable_value,
-                            sizeof(disable_value));
-  }
-
-  ui::win::SetAppIdForWindow(GetAppModelId(), hwnd);
-  CommandLine relaunch = GetAppListCommandLine();
-  string16 app_name(GetAppListShortcutName());
-  ui::win::SetRelaunchDetailsForWindow(
-      relaunch.GetCommandLineString(), app_name, hwnd);
-  ::SetWindowText(hwnd, app_name.c_str());
-  string16 icon_path = GetAppListIconPath();
-  ui::win::SetAppIconForWindow(icon_path, hwnd);
-}
 
 void AppListController::DismissAppList() {
-  if (IsAppListVisible() && can_close_app_list_) {
-    current_view_->GetWidget()->Hide();
-    activation_tracker_->OnViewHidden();
-    FreeAnyKeepAliveForView();
-  }
+  shower_->DismissAppList();
 }
 
-void AppListController::AppListClosing() {
-  FreeAnyKeepAliveForView();
-  current_view_ = NULL;
-  activation_tracker_.reset();
+void AppListController::OnAppListClosing() {
+  shower_->CloseAppList();
   SetProfile(NULL);
 }
 
-void AppListController::AppListActivationChanged(bool active) {
-  activation_tracker_->OnActivationChanged(active);
-}
-
-// Attempts to find the bounds of the Windows taskbar. Returns true on success.
-// |rect| is in screen coordinates. If the taskbar is in autohide mode and is
-// not visible, |rect| will be outside the current monitor's bounds, except for
-// one pixel of overlap where the edge of the taskbar is shown.
-bool GetTaskbarRect(gfx::Rect* rect) {
-  HWND taskbar_hwnd = FindWindow(kTrayClassName, NULL);
-  if (!taskbar_hwnd)
-    return false;
-
-  RECT win_rect;
-  if (!GetWindowRect(taskbar_hwnd, &win_rect))
-    return false;
-
-  *rect = gfx::Rect(win_rect);
-  return true;
-}
-
-gfx::Point FindReferencePoint(const gfx::Display& display,
-                              const gfx::Point& cursor) {
-  const int kSnapDistance = 50;
-
-  // If we can't find the taskbar, snap to the bottom left.
-  // If the display size is the same as the work area, and does not contain the
-  // taskbar, either the taskbar is hidden or on another monitor, so just snap
-  // to the bottom left.
-  gfx::Rect taskbar_rect;
-  if (!GetTaskbarRect(&taskbar_rect) ||
-      (display.work_area() == display.bounds() &&
-          !display.work_area().Contains(taskbar_rect))) {
-    return display.work_area().bottom_left();
-  }
-
-  // Snap to the taskbar edge. If the cursor is greater than kSnapDistance away,
-  // also move to the left (for horizontal taskbars) or top (for vertical).
-  const gfx::Rect& screen_rect = display.bounds();
-  // First handle taskbar on bottom.
-  if (taskbar_rect.width() == screen_rect.width()) {
-    if (taskbar_rect.bottom() == screen_rect.bottom()) {
-      if (taskbar_rect.y() - cursor.y() > kSnapDistance)
-        return gfx::Point(screen_rect.x(), taskbar_rect.y());
-
-      return gfx::Point(cursor.x(), taskbar_rect.y());
-    }
-
-    // Now try on the top.
-    if (cursor.y() - taskbar_rect.bottom() > kSnapDistance)
-      return gfx::Point(screen_rect.x(), taskbar_rect.bottom());
-
-    return gfx::Point(cursor.x(), taskbar_rect.bottom());
-  }
-
-  // Now try the left.
-  if (taskbar_rect.x() == screen_rect.x()) {
-    if (cursor.x() - taskbar_rect.right() > kSnapDistance)
-      return gfx::Point(taskbar_rect.right(), screen_rect.y());
-
-    return gfx::Point(taskbar_rect.right(), cursor.y());
-  }
-
-  // Finally, try the right.
-  if (taskbar_rect.x() - cursor.x() > kSnapDistance)
-    return gfx::Point(taskbar_rect.x(), screen_rect.y());
-
-  return gfx::Point(taskbar_rect.x(), cursor.y());
-}
-
-gfx::Point AppListController::FindAnchorPoint(
-    const gfx::Display& display,
-    const gfx::Point& cursor) {
-  const int kSnapOffset = 3;
-
-  gfx::Rect bounds_rect(display.work_area());
-  // Always subtract the taskbar area since work_area() will not subtract it if
-  // the taskbar is set to auto-hide, and the app list should never overlap the
-  // taskbar.
-  gfx::Rect taskbar_rect;
-  if (GetTaskbarRect(&taskbar_rect))
-    bounds_rect.Subtract(taskbar_rect);
-
-  gfx::Size view_size(current_view_->GetPreferredSize());
-  bounds_rect.Inset(view_size.width() / 2 + kSnapOffset,
-                    view_size.height() / 2 + kSnapOffset);
-
-  gfx::Point anchor = FindReferencePoint(display, cursor);
-  anchor.SetToMax(bounds_rect.origin());
-  anchor.SetToMin(bounds_rect.bottom_right());
-  return anchor;
-}
-
-void AppListController::UpdateArrowPositionAndAnchorPoint(
-    const gfx::Point& cursor) {
-  gfx::Screen* screen =
-      gfx::Screen::GetScreenFor(current_view_->GetWidget()->GetNativeView());
-  gfx::Display display = screen->GetDisplayNearestPoint(cursor);
-
-  current_view_->SetBubbleArrow(views::BubbleBorder::FLOAT);
-  current_view_->SetAnchorPoint(FindAnchorPoint(display, cursor));
-}
-
-string16 AppListController::GetAppListIconPath() {
-  base::FilePath icon_path;
-  if (!PathService::Get(base::FILE_EXE, &icon_path)) {
-    NOTREACHED();
-    return string16();
-  }
-
-  std::stringstream ss;
-  ss << "," << GetAppListIconIndex();
-  string16 result = icon_path.value();
-  result.append(UTF8ToUTF16(ss.str()));
-  return result;
-}
-
-void AppListController::EnsureHaveKeepAliveForView() {
-  if (!keep_alive_)
-    keep_alive_.reset(new ScopedKeepAlive());
-}
-
-void AppListController::FreeAnyKeepAliveForView() {
-  if (keep_alive_)
-    keep_alive_.reset(NULL);
-}
-
 void AppListController::OnLoadProfileForWarmup(Profile* initial_profile) {
   if (!IsWarmupNeeded())
     return;
 
-  CreateForProfile(initial_profile);
-  current_view_->Prerender();
+  shower_->WarmupForProfile(initial_profile);
+}
+
+void AppListController::SetAppListNextPaintCallback(
+    const base::Closure& callback) {
+  app_list::AppListView::SetNextPaintCallback(callback);
 }
 
 void AppListController::HandleFirstRun() {
@@ -907,8 +1004,9 @@
   if (prefs->HasPrefPath(prefs::kRestartWithAppList) &&
       prefs->GetBoolean(prefs::kRestartWithAppList)) {
     prefs->SetBoolean(prefs::kRestartWithAppList, false);
-    AppListController::GetInstance()->
-        ShowAppListDuringModeSwitch(initial_profile);
+    // If we are restarting in Metro mode we will lose focus straight away. We
+    // need to reacquire focus when that happens.
+    shower_->ShowAndReacquireFocus(initial_profile);
   }
 
   // Migrate from legacy app launcher if we are on a non-canary and non-chromium
@@ -943,8 +1041,12 @@
   HandleCommandLineFlags(initial_profile);
 }
 
+void AppListController::CreateForProfile(Profile* profile) {
+  shower_->CreateViewForProfile(profile);
+}
+
 bool AppListController::IsAppListVisible() const {
-  return current_view_ && current_view_->GetWidget()->IsVisible();
+  return shower_->IsAppListVisible();
 }
 
 void AppListController::CreateShortcut() {
@@ -957,7 +1059,9 @@
   shortcut_locations.in_quick_launch_bar = true;
   shortcut_locations.in_applications_menu = true;
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  shortcut_locations.applications_menu_subdir = dist->GetAppShortCutName();
+  shortcut_locations.applications_menu_subdir =
+      dist->GetStartMenuShortcutSubfolder(
+          BrowserDistribution::SUBFOLDER_CHROME);
   base::FilePath user_data_dir(
       g_browser_process->profile_manager()->user_data_dir());
 
@@ -965,7 +1069,7 @@
       content::BrowserThread::FILE,
       FROM_HERE,
       base::Bind(&CreateAppListShortcuts,
-                  user_data_dir, GetAppModelId(), shortcut_locations));
+                 user_data_dir, GetAppModelId(), shortcut_locations));
 }
 
 void AppListController::ScheduleWarmup() {
@@ -992,7 +1096,7 @@
 
   // We only need to initialize the view if there's no view already created and
   // there's no profile loading to be shown.
-  return !current_view_ && !profile_loader().IsAnyProfileLoading();
+  return !shower_->HasView() && !profile_loader().IsAnyProfileLoading();
 }
 
 void AppListController::LoadProfileForWarmup() {
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 3ceb272..b278b0d 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/native_app_window_views.cc
@@ -524,7 +524,8 @@
 }
 
 bool NativeAppWindowViews::CanMaximize() const {
-  return resizable_ && maximum_size_.IsEmpty();
+  return resizable_ && maximum_size_.IsEmpty() &&
+      !shell_window_->window_type_is_panel();
 }
 
 string16 NativeAppWindowViews::GetWindowTitle() const {
@@ -602,6 +603,14 @@
   return views::WidgetDelegateView::CreateNonClientFrameView(widget);
 }
 
+bool NativeAppWindowViews::WidgetHasHitTestMask() const {
+  return input_region_ != NULL;
+}
+
+void NativeAppWindowViews::GetWidgetHitTestMask(gfx::Path* mask) const {
+  input_region_->getBoundaryPath(mask);
+}
+
 bool NativeAppWindowViews::ShouldDescendIntoChildForEventHandling(
     gfx::NativeView child,
     const gfx::Point& location) {
@@ -741,6 +750,10 @@
   window_->UpdateWindowTitle();
 }
 
+void NativeAppWindowViews::UpdateInputRegion(scoped_ptr<SkRegion> region) {
+  input_region_ = region.Pass();
+}
+
 void NativeAppWindowViews::UpdateDraggableRegions(
     const std::vector<extensions::DraggableRegion>& regions) {
   // Draggable region is not supported for non-frameless window.
diff --git a/chrome/browser/ui/views/apps/native_app_window_views.h b/chrome/browser/ui/views/apps/native_app_window_views.h
index 7cc7d53..5456bb2 100644
--- a/chrome/browser/ui/views/apps/native_app_window_views.h
+++ b/chrome/browser/ui/views/apps/native_app_window_views.h
@@ -103,6 +103,8 @@
   virtual views::View* GetContentsView() OVERRIDE;
   virtual views::NonClientFrameView* CreateNonClientFrameView(
       views::Widget* widget) OVERRIDE;
+  virtual bool WidgetHasHitTestMask() const OVERRIDE;
+  virtual void GetWidgetHitTestMask(gfx::Path* mask) const OVERRIDE;
   virtual bool ShouldDescendIntoChildForEventHandling(
       gfx::NativeView child,
       const gfx::Point& location) OVERRIDE;
@@ -133,6 +135,7 @@
   virtual bool IsDetached() const OVERRIDE;
   virtual void UpdateWindowIcon() OVERRIDE;
   virtual void UpdateWindowTitle() OVERRIDE;
+  virtual void UpdateInputRegion(scoped_ptr<SkRegion> region) OVERRIDE;
   virtual void UpdateDraggableRegions(
       const std::vector<extensions::DraggableRegion>& regions) OVERRIDE;
   virtual void HandleKeyboardEvent(
@@ -161,6 +164,10 @@
   views::Widget* window_;
   bool is_fullscreen_;
 
+  // The region of the window that accepts input events.
+  // If this is not set, then the entire window accepts input events.
+  scoped_ptr<SkRegion> input_region_;
+
   scoped_ptr<SkRegion> draggable_region_;
 
   const bool frameless_;
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
index f7aa279..0d45f12 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
@@ -15,6 +15,7 @@
 #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"
+#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/native_web_keyboard_event.h"
@@ -59,6 +60,7 @@
 #include "ui/views/window/dialog_client_view.h"
 
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 namespace autofill {
 
@@ -862,7 +864,13 @@
 
 void AutofillDialogViews::OnWidgetBoundsChanged(views::Widget* widget,
                                                 const gfx::Rect& new_bounds) {
-  ContentsPreferredSizeChanged();
+  // Wait until at least 100ms pass without any bounds change event before
+  // reacting. This way drags don't cause an excessive number of layouts.
+  browser_resize_timer_.Start(
+      FROM_HERE,
+      base::TimeDelta::FromMilliseconds(100),
+      base::Bind(&AutofillDialogViews::ContentsPreferredSizeChanged,
+                 base::Unretained(this)));
 }
 
 void AutofillDialogViews::NotificationArea::ButtonPressed(
@@ -1178,7 +1186,10 @@
 
 AutofillDialogViews::AutofillDialogViews(AutofillDialogViewDelegate* delegate)
     : delegate_(delegate),
+      updates_scope_(0),
+      needs_update_(false),
       window_(NULL),
+      browser_resize_timer_(false, false),
       notification_area_(NULL),
       account_chooser_(NULL),
       sign_in_webview_(NULL),
@@ -1225,11 +1236,14 @@
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(
           delegate_->GetWebContents());
-  window_ = CreateWebContentsModalDialogViews(
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  DCHECK(modal_delegate);
+
+  window_ = views::Widget::CreateWindowAsFramelessChild(
       this,
       delegate_->GetWebContents()->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
   focus_manager_ = window_->GetFocusManager();
   focus_manager_->AddFocusChangeListener(this);
@@ -1254,6 +1268,19 @@
     window_->Close();
 }
 
+void AutofillDialogViews::UpdatesStarted() {
+  updates_scope_++;
+}
+
+void AutofillDialogViews::UpdatesFinished() {
+  updates_scope_--;
+  DCHECK_GE(updates_scope_, 0);
+  if (updates_scope_ == 0 && needs_update_) {
+    needs_update_ = false;
+    ContentsPreferredSizeChanged();
+  }
+}
+
 void AutofillDialogViews::UpdateAccountChooser() {
   account_chooser_->Update();
   // TODO(estade): replace this with a better loading image/animation.
@@ -1475,58 +1502,10 @@
 }
 
 gfx::Size AutofillDialogViews::GetPreferredSize() {
-  gfx::Insets insets = GetInsets();
-  gfx::Size scroll_size = scrollable_area_->contents()->GetPreferredSize();
-  int width = scroll_size.width() + insets.width();
+  if (preferred_size_.IsEmpty())
+    preferred_size_ = CalculatePreferredSize();
 
-  if (sign_in_webview_->visible()) {
-    gfx::Size size = static_cast<views::View*>(sign_in_webview_)->
-        GetPreferredSize();
-    return gfx::Size(width, size.height() + insets.height());
-  }
-
-  int base_height = insets.height();
-  int notification_height = notification_area_->
-      GetHeightForWidth(scroll_size.width());
-  if (notification_height > 0)
-    base_height += notification_height + views::kRelatedControlVerticalSpacing;
-
-  int steps_height = autocheckout_steps_area_->
-      GetHeightForWidth(scroll_size.width());
-  if (steps_height > 0)
-    base_height += steps_height + views::kRelatedControlVerticalSpacing;
-
-  gfx::Size preferred_size;
-  // When the scroll area isn't visible, it still sets the width but doesn't
-  // factor into height.
-  if (!scrollable_area_->visible()) {
-    preferred_size.SetSize(width, base_height);
-  } else {
-    // Show as much of the scroll view as is possible without going past the
-    // bottom of the browser window.
-    views::Widget* widget =
-        views::Widget::GetTopLevelWidgetForNativeView(
-            delegate_->GetWebContents()->GetView()->GetNativeView());
-    int browser_window_height =
-        widget ? widget->GetContentsView()->bounds().height() : INT_MAX;
-    const int kWindowDecorationHeight = 200;
-    int height = base_height + std::min(
-        scroll_size.height(),
-        std::max(kMinimumContentsHeight,
-                 browser_window_height - base_height -
-                     kWindowDecorationHeight));
-    preferred_size.SetSize(width, height);
-  }
-
-  if (!overlay_view_->visible())
-    return preferred_size;
-
-  int height_of_overlay =
-      overlay_view_->GetHeightForContentsForWidth(preferred_size.width());
-  if (height_of_overlay > 0)
-    preferred_size.set_height(height_of_overlay);
-
-  return preferred_size;
+  return preferred_size_;
 }
 
 void AutofillDialogViews::Layout() {
@@ -1768,6 +1747,54 @@
   delegate_->LegalDocumentLinkClicked(range);
 }
 
+gfx::Size AutofillDialogViews::CalculatePreferredSize() {
+  gfx::Insets insets = GetInsets();
+  gfx::Size scroll_size = scrollable_area_->contents()->GetPreferredSize();
+  // Width is always set by the scroll area.
+  const int width = scroll_size.width();
+
+  if (sign_in_webview_->visible()) {
+    gfx::Size size = static_cast<views::View*>(sign_in_webview_)->
+        GetPreferredSize();
+    return gfx::Size(width + insets.width(), size.height() + insets.height());
+  }
+
+  if (overlay_view_->visible()) {
+    int height = overlay_view_->GetHeightForContentsForWidth(width);
+    if (height != 0)
+      return gfx::Size(width + insets.width(), height + insets.height());
+  }
+
+  int height = 0;
+  int notification_height = notification_area_->GetHeightForWidth(width);
+  if (notification_height > 0)
+    height += notification_height + views::kRelatedControlVerticalSpacing;
+
+  int steps_height = autocheckout_steps_area_->GetHeightForWidth(width);
+  if (steps_height > 0)
+    height += steps_height + views::kRelatedControlVerticalSpacing;
+
+  if (scrollable_area_->visible()) {
+    // Show as much of the scroll view as is possible without going past the
+    // bottom of the browser window.
+    views::Widget* widget =
+        views::Widget::GetTopLevelWidgetForNativeView(
+            delegate_->GetWebContents()->GetView()->GetNativeView());
+    int browser_window_height =
+        widget ? widget->GetContentsView()->bounds().height() : INT_MAX;
+    const int kWindowDecorationHeight = 200;
+    int browser_constrained_height =
+        browser_window_height - height - kWindowDecorationHeight;
+    int scroll_height = std::min(
+        scroll_size.height(),
+        std::max(kMinimumContentsHeight, browser_constrained_height));
+
+    height += scroll_height;
+  }
+
+  return gfx::Size(width + insets.width(), height + insets.height());
+}
+
 void AutofillDialogViews::InitChildViews() {
   button_strip_extra_view_ = new LayoutPropagationView();
   button_strip_extra_view_->SetLayoutManager(
@@ -2272,6 +2299,13 @@
 }
 
 void AutofillDialogViews::ContentsPreferredSizeChanged() {
+  if (updates_scope_ != 0) {
+    needs_update_ = true;
+    return;
+  }
+
+  preferred_size_ = gfx::Size();
+
   if (GetWidget()) {
     GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
     // If the above line does not cause the dialog's size to change, |contents_|
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
index 8cf5079..71cdb94 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
@@ -10,6 +10,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_types.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_view.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_view_delegate.h"
@@ -80,6 +81,8 @@
   // AutofillDialogView implementation:
   virtual void Show() OVERRIDE;
   virtual void Hide() OVERRIDE;
+  virtual void UpdatesStarted() OVERRIDE;
+  virtual void UpdatesFinished() OVERRIDE;
   virtual void UpdateAccountChooser() OVERRIDE;
   virtual void UpdateAutocheckoutStepsArea() OVERRIDE;
   virtual void UpdateButtonStrip() OVERRIDE;
@@ -483,6 +486,8 @@
 
   typedef std::map<DialogSection, DetailsGroup> DetailGroupMap;
 
+  gfx::Size CalculatePreferredSize();
+
   void InitChildViews();
 
   // Creates and returns a view that holds all detail sections.
@@ -560,6 +565,7 @@
 
   // Call this when the size of anything in |contents_| might've changed.
   void ContentsPreferredSizeChanged();
+  void DoContentsPreferredSizeChanged();
 
   // Gets the textfield view that is shown for the given DetailInput model, or
   // NULL.
@@ -575,10 +581,23 @@
   // The delegate that drives this view. Weak pointer, always non-NULL.
   AutofillDialogViewDelegate* const delegate_;
 
+  // The preferred size of the view, cached to avoid needless recomputation.
+  gfx::Size preferred_size_;
+
+  // The current number of unmatched calls to UpdatesStarted.
+  int updates_scope_;
+
+  // True when there's been a call to ContentsPreferredSizeChanged() suppressed
+  // due to an unmatched UpdatesStarted.
+  bool needs_update_;
+
   // The window that displays |contents_|. Weak pointer; may be NULL when the
   // dialog is closing.
   views::Widget* window_;
 
+  // A timer used to coalesce re-layouts due to browser window resizes.
+  base::Timer browser_resize_timer_;
+
   // A DialogSection-keyed map of the DetailGroup structs.
   DetailGroupMap detail_groups_;
 
diff --git a/chrome/browser/ui/views/avatar_menu_button.cc b/chrome/browser/ui/views/avatar_menu_button.cc
index f1b749d..5cdb78f 100644
--- a/chrome/browser/ui/views/avatar_menu_button.cc
+++ b/chrome/browser/ui/views/avatar_menu_button.cc
@@ -25,10 +25,10 @@
   return static_cast<int>(x + 0.5);
 }
 
-AvatarMenuButton::AvatarMenuButton(Browser* browser, bool incognito)
+AvatarMenuButton::AvatarMenuButton(Browser* browser, bool disabled)
     : MenuButton(NULL, string16(), this, false),
       browser_(browser),
-      incognito_(incognito),
+      disabled_(disabled),
       is_gaia_picture_(false),
       old_height_(0) {
   // In RTL mode, the avatar icon should be looking the opposite direction.
@@ -70,7 +70,7 @@
 }
 
 bool AvatarMenuButton::HitTestRect(const gfx::Rect& rect) const {
-  if (incognito_)
+  if (disabled_)
     return false;
   return views::MenuButton::HitTestRect(rect);
 }
@@ -86,7 +86,7 @@
 // views::MenuButtonListener implementation
 void AvatarMenuButton::OnMenuButtonClicked(views::View* source,
                                            const gfx::Point& point) {
-  if (incognito_)
+  if (disabled_)
     return;
 
   ShowAvatarBubble();
diff --git a/chrome/browser/ui/views/avatar_menu_button.h b/chrome/browser/ui/views/avatar_menu_button.h
index c83c7a6..2555c5a 100644
--- a/chrome/browser/ui/views/avatar_menu_button.h
+++ b/chrome/browser/ui/views/avatar_menu_button.h
@@ -26,9 +26,9 @@
 class AvatarMenuButton : public views::MenuButton,
                          public views::MenuButtonListener {
  public:
-  // Creates a new button. If |incognito| is true and we're not in managed mode,
+  // Creates a new button. If |disabled| is true and we're not in managed mode,
   // clicking on the button will cause the profile menu to be displayed.
-  AvatarMenuButton(Browser* browser, bool incognito);
+  AvatarMenuButton(Browser* browser, bool disabled);
 
   virtual ~AvatarMenuButton();
 
@@ -46,7 +46,7 @@
                                    const gfx::Point& point) OVERRIDE;
 
   Browser* browser_;
-  bool incognito_;
+  bool disabled_;
   scoped_ptr<ui::MenuModel> menu_model_;
 
   // Use a scoped ptr because gfx::Image doesn't have a default constructor.
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_context_menu_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_context_menu_test.cc
index 2b83def..70b00e1 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_context_menu_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_context_menu_test.cc
@@ -260,9 +260,12 @@
 TEST_F(BookmarkContextMenuTest, DisableIncognito) {
   std::vector<const BookmarkNode*> nodes;
   nodes.push_back(model_->bookmark_bar_node()->GetChild(0));
+  TestingProfile::Builder builder;
+  builder.SetIncognito();
+  scoped_ptr<TestingProfile> incognito_ = builder.Build().Pass();
+  incognito_->SetOriginalProfile(profile_.get());
   BookmarkContextMenu controller(
-      NULL, NULL, profile_.get(), NULL, nodes[0]->parent(), nodes, false);
-  profile_->set_incognito(true);
+      NULL, NULL, incognito_.get(), NULL, nodes[0]->parent(), nodes, false);
   EXPECT_FALSE(controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_INCOGNITO));
   EXPECT_FALSE(
       controller.IsCommandEnabled(IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO));
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
index 5c2a41c..ffbeb43 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.cc
@@ -8,10 +8,7 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/bookmarks/bookmark_model.h"
-#include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/bookmarks/bookmark_node_data.h"
 #include "chrome/browser/bookmarks/bookmark_utils.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h"
 #include "chrome/common/pref_names.h"
@@ -60,8 +57,7 @@
   gfx::Rect bounds(screen_loc.x(), screen_loc.y(), menu_button->width(),
                    menu_button->height() - 1);
   for_drop_ = for_drop;
-  BookmarkModelFactory::GetForProfile(
-      menu_delegate_->profile())->AddObserver(this);
+  menu_delegate_->GetBookmarkModel()->AddObserver(this);
   // We only delete ourself after the menu completes, so we can safely ignore
   // the return value.
   ignore_result(menu_runner_->RunMenuAt(menu_delegate_->parent(), menu_button,
@@ -195,8 +191,7 @@
 }
 
 BookmarkMenuController::~BookmarkMenuController() {
-  BookmarkModelFactory::GetForProfile(
-      menu_delegate_->profile())->RemoveObserver(this);
+  menu_delegate_->GetBookmarkModel()->RemoveObserver(this);
   if (observer_)
     observer_->BookmarkMenuDeleted(this);
 }
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
index 5965de1..0830e25 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.cc
@@ -57,7 +57,7 @@
 }
 
 BookmarkMenuDelegate::~BookmarkMenuDelegate() {
-  BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this);
+  GetBookmarkModel()->RemoveObserver(this);
 }
 
 void BookmarkMenuDelegate::Init(
@@ -67,7 +67,7 @@
     int start_child_index,
     ShowOptions show_options,
     bookmark_utils::BookmarkLaunchLocation location) {
-  BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this);
+  GetBookmarkModel()->AddObserver(this);
   real_delegate_ = real_delegate;
   if (parent) {
     parent_menu_item_ = parent;
@@ -93,6 +93,10 @@
     context_menu_->SetPageNavigator(navigator);
 }
 
+BookmarkModel* BookmarkMenuDelegate::GetBookmarkModel() {
+  return BookmarkModelFactory::GetForProfile(profile_);
+}
+
 void BookmarkMenuDelegate::SetActiveMenu(const BookmarkNode* node,
                                          int start_index) {
   DCHECK(!parent_menu_item_);
@@ -202,12 +206,10 @@
   const BookmarkNode* node = menu_id_to_node_map_[item->GetCommand()];
   const BookmarkNode* drop_parent = node->parent();
   int index_to_drop_at = drop_parent->GetIndexOf(node);
+  BookmarkModel* model = GetBookmarkModel();
   switch (*position) {
     case views::MenuDelegate::DROP_AFTER:
-      if (node == BookmarkModelFactory::GetForProfile(
-              profile_)->other_node() ||
-          node == BookmarkModelFactory::GetForProfile(
-              profile_)->mobile_node()) {
+      if (node == model->other_node() || node == model->mobile_node()) {
         // Dropping after these nodes makes no sense.
         *position = views::MenuDelegate::DROP_NONE;
       }
@@ -215,8 +217,7 @@
       break;
 
     case views::MenuDelegate::DROP_BEFORE:
-      if (node == BookmarkModelFactory::GetForProfile(
-              profile_)->mobile_node()) {
+      if (node == model->mobile_node()) {
         // Dropping before this node makes no sense.
         *position = views::MenuDelegate::DROP_NONE;
       }
@@ -241,7 +242,7 @@
     const ui::DropTargetEvent& event) {
   const BookmarkNode* drop_node = menu_id_to_node_map_[menu->GetCommand()];
   DCHECK(drop_node);
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile_);
+  BookmarkModel* model = GetBookmarkModel();
   DCHECK(model);
   const BookmarkNode* drop_parent = drop_node->parent();
   DCHECK(drop_parent);
@@ -282,8 +283,7 @@
   std::vector<const BookmarkNode*> nodes;
   nodes.push_back(menu_id_to_node_map_[id]);
   bool close_on_delete = !parent_menu_item_ &&
-      (nodes[0]->parent() == BookmarkModelFactory::GetForProfile(
-          profile())->other_node() &&
+      (nodes[0]->parent() == GetBookmarkModel()->other_node() &&
        nodes[0]->parent()->child_count() == 1);
   context_menu_.reset(
       new BookmarkContextMenu(
@@ -303,8 +303,7 @@
 bool BookmarkMenuDelegate::CanDrag(MenuItemView* menu) {
   const BookmarkNode* node = menu_id_to_node_map_[menu->GetCommand()];
   // Don't let users drag the other folder.
-  return node->parent() != BookmarkModelFactory::GetForProfile(
-      profile_)->root_node();
+  return node->parent() != GetBookmarkModel()->root_node();
 }
 
 void BookmarkMenuDelegate::WriteDragData(MenuItemView* sender,
@@ -346,7 +345,7 @@
 
   // Remove the observer so that when the remove happens we don't prematurely
   // cancel the menu. The observer is added back in DidRemoveBookmarks().
-  BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this);
+  GetBookmarkModel()->RemoveObserver(this);
 
   // Remove the menu items.
   std::set<MenuItemView*> changed_parent_menus;
@@ -399,7 +398,7 @@
 
 void BookmarkMenuDelegate::DidRemoveBookmarks() {
   // Balances remove in WillRemoveBookmarksImpl.
-  BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this);
+  GetBookmarkModel()->AddObserver(this);
   DCHECK(is_mutating_model_);
   is_mutating_model_ = false;
 }
@@ -420,7 +419,7 @@
 void BookmarkMenuDelegate::BuildMenusForPermanentNodes(
     views::MenuItemView* menu,
     int* next_menu_id) {
-  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile_);
+  BookmarkModel* model = GetBookmarkModel();
   bool added_separator = false;
   BuildMenuForPermanentNode(model->other_node(), menu, next_menu_id,
                             &added_separator);
@@ -464,8 +463,7 @@
 
     menu_id_to_node_map_[id] = node;
     if (node->is_url()) {
-      const gfx::Image& image = BookmarkModelFactory::GetForProfile(
-          profile_)->GetFavicon(node);
+      const gfx::Image& image = GetBookmarkModel()->GetFavicon(node);
       const gfx::ImageSkia* icon = image.IsEmpty() ?
           rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON) : image.ToImageSkia();
       node_to_menu_map_[node] =
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
index 7a8a2cb..6bed146 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
+++ b/chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h
@@ -74,20 +74,19 @@
   // the first child of |node| to show in the menu.
   void SetActiveMenu(const BookmarkNode* node, int start_index);
 
+  BookmarkModel* GetBookmarkModel();
+
   // Returns the menu.
-  views::MenuItemView* menu() const { return menu_; }
+  views::MenuItemView* menu() { return menu_; }
 
   // Returns the context menu, or NULL if the context menu isn't showing.
-  views::MenuItemView* context_menu() const {
+  views::MenuItemView* context_menu() {
     return context_menu_.get() ? context_menu_->menu() : NULL;
   }
 
-  Profile* profile() { return profile_; }
-
   views::Widget* parent() { return parent_; }
   const views::Widget* parent() const { return parent_; }
 
-
   // Returns true if we're in the process of mutating the model. This happens
   // when the user deletes menu items using the context menu.
   bool is_mutating_model() const { return is_mutating_model_; }
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc
index 26b4445..fd1ca0e 100644
--- a/chrome/browser/ui/views/collected_cookies_views.cc
+++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "chrome/browser/ui/views/cookie_info_view.h"
 #include "chrome/common/pref_names.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/notification_details.h"
@@ -50,6 +51,7 @@
 #include "ui/views/window/dialog_delegate.h"
 
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 namespace chrome {
 
@@ -209,11 +211,13 @@
                  content::Source<TabSpecificContentSettings>(content_settings));
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents);
-  window_ = CreateWebContentsModalDialogViews(
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  DCHECK(modal_delegate);
+  window_ = views::Widget::CreateWindowAsFramelessChild(
       this,
       web_contents->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
 }
 
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 da98e43..423ebf8 100644
--- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
+++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.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/native_web_keyboard_event.h"
@@ -26,6 +27,7 @@
 using ui::WebDialogWebContentsDelegate;
 using web_modal::NativeWebContentsModalDialog;
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 namespace {
 
@@ -225,11 +227,13 @@
           browser_context, delegate, tab_delegate);
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents);
-  views::Widget* window = CreateWebContentsModalDialogViews(
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  DCHECK(modal_delegate);
+  views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
       constrained_delegate,
       web_contents->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window->GetNativeView());
   constrained_delegate->SetWindow(window);
   return constrained_delegate;
diff --git a/chrome/browser/ui/views/constrained_window_views.cc b/chrome/browser/ui/views/constrained_window_views.cc
index bc7bb68..07ba004 100644
--- a/chrome/browser/ui/views/constrained_window_views.cc
+++ b/chrome/browser/ui/views/constrained_window_views.cc
@@ -6,48 +6,23 @@
 
 #include <algorithm>
 
-#include "base/command_line.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/toolbar/toolbar_model.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/theme_image_mapper.h"
-#include "chrome/common/chrome_constants.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/browser/navigation_controller.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 "grit/theme_resources.h"
 #include "grit/ui_resources.h"
-#include "net/base/net_util.h"
-#include "ui/aura/client/aura_constants.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_base_switches.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/font.h"
-#include "ui/gfx/path.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/screen.h"
 #include "ui/views/border.h"
 #include "ui/views/color_constants.h"
 #include "ui/views/controls/button/image_button.h"
-#include "ui/views/focus/focus_manager.h"
-#include "ui/views/views_delegate.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
-#include "ui/views/window/client_view.h"
-#include "ui/views/window/dialog_client_view.h"
 #include "ui/views/window/dialog_delegate.h"
 #include "ui/views/window/frame_background.h"
-#include "ui/views/window/non_client_view.h"
 #include "ui/views/window/window_resources.h"
 #include "ui/views/window/window_shape.h"
 
@@ -58,26 +33,15 @@
 
 #if defined(USE_AURA)
 #include "ui/aura/window.h"
-#include "ui/views/corewm/shadow_types.h"
-#include "ui/views/corewm/visibility_controller.h"
-#include "ui/views/corewm/window_animations.h"
-#include "ui/views/corewm/window_modality_controller.h"
 #endif
 
 #if defined(USE_ASH)
-#include "ash/ash_constants.h"
-#include "ash/shell.h"
 #include "ash/wm/custom_frame_view_ash.h"
 #endif
 
-using base::TimeDelta;
 using web_modal::WebContentsModalDialogHost;
 using web_modal::WebContentsModalDialogHostObserver;
 
-namespace views {
-class ClientView;
-}
-
 namespace {
 // The name of a key to store on the window handle to associate
 // WebContentsModalDialogHostObserverViews with the Widget.
@@ -104,7 +68,8 @@
   }
 
   virtual ~WebContentsModalDialogHostObserverViews() {
-    host_->RemoveObserver(this);
+    if (host_)
+      host_->RemoveObserver(this);
     target_widget_->RemoveObserver(this);
     target_widget_->SetNativeWindowProperty(native_window_property_,
                                             NULL);
@@ -117,22 +82,12 @@
 
   // WebContentsModalDialogHostObserver overrides
   virtual void OnPositionRequiresUpdate() OVERRIDE {
-    gfx::Size size = target_widget_->GetWindowBoundsInScreen().size();
-    gfx::Point position = host_->GetDialogPosition(size);
-    views::Border* border =
-        target_widget_->non_client_view()->frame_view()->border();
-    // Border may be null during widget initialization.
-    if (border) {
-      // Align the first row of pixels inside the border. This is the apparent
-      // top of the dialog.
-      position.set_y(position.y() - border->GetInsets().top());
-    }
+    UpdateWebContentsModalDialogPosition(target_widget_, host_);
+  }
 
-    if (target_widget_->is_top_level())
-      position += views::Widget::GetWidgetForNativeView(host_->GetHostView())->
-          GetClientAreaBoundsInScreen().OffsetFromOrigin();
-
-    target_widget_->SetBounds(gfx::Rect(position, size));
+  virtual void OnHostDestroying() OVERRIDE {
+    host_->RemoveObserver(this);
+    host_ = NULL;
   }
 
  private:
@@ -612,78 +567,27 @@
   }
 }
 
-#if defined(USE_ASH)
-// Ash has its own window frames, but we need the special close semantics for
-// constrained windows.
-class ConstrainedWindowFrameViewAsh : public ash::CustomFrameViewAsh {
- public:
-  explicit ConstrainedWindowFrameViewAsh()
-      : ash::CustomFrameViewAsh(),
-        container_(NULL) {
+void UpdateWebContentsModalDialogPosition(
+    views::Widget* widget,
+    web_modal::WebContentsModalDialogHost* dialog_host) {
+  gfx::Size size = widget->GetWindowBoundsInScreen().size();
+  gfx::Point position = dialog_host->GetDialogPosition(size);
+  views::Border* border =
+      widget->non_client_view()->frame_view()->border();
+  // Border may be null during widget initialization.
+  if (border) {
+    // Align the first row of pixels inside the border. This is the apparent
+    // top of the dialog.
+    position.set_y(position.y() - border->GetInsets().top());
   }
 
-  void Init(views::Widget* container) {
-    container_ = container;
-    ash::CustomFrameViewAsh::Init(container);
-    // Always use "active" look.
-    SetInactiveRenderingDisabled(true);
+  if (widget->is_top_level()) {
+    position +=
+        views::Widget::GetWidgetForNativeView(dialog_host->GetHostView())->
+            GetClientAreaBoundsInScreen().OffsetFromOrigin();
   }
 
-  // views::ButtonListener overrides:
-  virtual void ButtonPressed(views::Button* sender,
-                             const ui::Event& event) OVERRIDE {
-    if (sender == close_button())
-      container_->Close();
-  }
-
- private:
-  views::Widget* container_;  // not owned
-  DISALLOW_COPY_AND_ASSIGN(ConstrainedWindowFrameViewAsh);
-};
-#endif  // defined(USE_ASH)
-
-views::Widget* CreateWebContentsModalDialogViews(
-    views::WidgetDelegate* widget_delegate,
-    gfx::NativeView parent,
-    WebContentsModalDialogHost* dialog_host) {
-  views::Widget* dialog = new views::Widget;
-
-  views::Widget::InitParams params;
-  params.delegate = widget_delegate;
-  params.child = true;
-  WebContentsModalDialogHostObserver* dialog_host_observer = NULL;
-  if (views::DialogDelegate::UseNewStyle()) {
-    params.parent = dialog_host->GetHostView();
-    params.remove_standard_frame = true;
-    dialog_host_observer =
-        new WebContentsModalDialogHostObserverViews(
-            dialog_host,
-            dialog,
-            kWebContentsModalDialogHostObserverViewsKey);
-#if defined(USE_AURA)
-    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
-#endif
-  } else {
-    params.parent = parent;
-  }
-
-  dialog->Init(params);
-
-#if defined(USE_AURA)
-  if (views::DialogDelegate::UseNewStyle()) {
-    // TODO(msw): Add a matching shadow type and remove the bubble frame border?
-    views::corewm::SetShadowType(dialog->GetNativeWindow(),
-                                 views::corewm::SHADOW_TYPE_NONE);
-  }
-#endif
-
-  if (dialog_host_observer) {
-    dialog_host_observer->OnPositionRequiresUpdate();
-    dialog->SetNativeWindowProperty(kWebContentsModalDialogHostObserverViewsKey,
-                                    dialog_host_observer);
-  }
-
-  return dialog;
+  widget->SetBounds(gfx::Rect(position, size));
 }
 
 views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog,
@@ -720,8 +624,10 @@
                                                           force_opaque_border);
   }
 #if defined(USE_ASH)
-  ConstrainedWindowFrameViewAsh* frame = new ConstrainedWindowFrameViewAsh;
+  ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh;
   frame->Init(widget);
+  // Always use "active" look.
+  frame->SetInactiveRenderingDisabled(true);
   return frame;
 #endif
   return new ConstrainedWindowFrameView(widget,
diff --git a/chrome/browser/ui/views/constrained_window_views.h b/chrome/browser/ui/views/constrained_window_views.h
index 968c4da..390a0e8 100644
--- a/chrome/browser/ui/views/constrained_window_views.h
+++ b/chrome/browser/ui/views/constrained_window_views.h
@@ -7,24 +7,25 @@
 
 #include "ui/gfx/native_widget_types.h"
 
+namespace content {
+class BrowserContext;
+}
+
+namespace views {
+class DialogDelegate;
+class NonClientFrameView;
+class Widget;
+class WidgetDelegate;
+}
+
 namespace web_modal {
 class WebContentsModalDialogHost;
 }
 
-namespace content {
-class WebContents;
-class BrowserContext;
-}
-namespace views {
-class DialogDelegate;
-class NonClientFrameView;
-class WidgetDelegate;
-class Widget;
-}
-
-views::Widget* CreateWebContentsModalDialogViews(
-    views::WidgetDelegate* widget_delegate,
-    gfx::NativeView parent,
+// Update the position of dialog |widget| against |dialog_host|. This is used to
+// reposition widgets e.g. when the host dimensions change.
+void UpdateWebContentsModalDialogPosition(
+    views::Widget* widget,
     web_modal::WebContentsModalDialogHost* dialog_host);
 
 // Create a widget for |dialog| that is modal to the browser window |parent|.
diff --git a/chrome/browser/ui/views/constrained_window_views_browsertest.cc b/chrome/browser/ui/views/constrained_window_views_browsertest.cc
index 3902b21..fd337fa 100644
--- a/chrome/browser/ui/views/constrained_window_views_browsertest.cc
+++ b/chrome/browser/ui/views/constrained_window_views_browsertest.cc
@@ -14,6 +14,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.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/native_web_keyboard_event.h"
@@ -36,6 +37,7 @@
 #endif
 
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 namespace {
 
@@ -140,14 +142,16 @@
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents);
   ASSERT_TRUE(web_contents_modal_dialog_manager != NULL);
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  ASSERT_TRUE(modal_delegate != NULL);
 
   // Create a constrained dialog.  It will attach itself to web_contents.
   scoped_ptr<TestConstrainedDialog> test_dialog1(new TestConstrainedDialog);
-  views::Widget* window1 = CreateWebContentsModalDialogViews(
+  views::Widget* window1 = views::Widget::CreateWindowAsFramelessChild(
       test_dialog1.get(),
       web_contents->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window1->GetNativeView());
 
   views::FocusManager* focus_manager = window1->GetFocusManager();
@@ -161,11 +165,10 @@
   // web_contents, but will remain hidden since the test_dialog1 is still
   // showing.
   scoped_ptr<TestConstrainedDialog> test_dialog2(new TestConstrainedDialog);
-  views::Widget* window2 = CreateWebContentsModalDialogViews(
+  views::Widget* window2 = views::Widget::CreateWindowAsFramelessChild(
       test_dialog2.get(),
       web_contents->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window2->GetNativeView());
   // Should be the same focus_manager.
   ASSERT_EQ(focus_manager, window2->GetFocusManager());
@@ -223,14 +226,16 @@
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents);
   ASSERT_TRUE(web_contents_modal_dialog_manager != NULL);
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  ASSERT_TRUE(modal_delegate != NULL);
 
   // Create a constrained dialog.  It will attach itself to web_contents.
   scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog);
-  views::Widget* window = CreateWebContentsModalDialogViews(
+  views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
       test_dialog.get(),
       web_contents->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window->GetNativeView());
 
   bool closed =
@@ -253,11 +258,13 @@
   scoped_ptr<TestConstrainedDialog> test_dialog(new TestConstrainedDialog);
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents);
-  views::Widget* window = CreateWebContentsModalDialogViews(
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  ASSERT_TRUE(modal_delegate != NULL);
+  views::Widget* window = views::Widget::CreateWindowAsFramelessChild(
       test_dialog.get(),
       web_contents->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window->GetNativeView());
   EXPECT_TRUE(window->IsVisible());
 
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.cc b/chrome/browser/ui/views/content_setting_bubble_contents.cc
index f6f30bb..87f56c8 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.cc
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.cc
@@ -403,11 +403,13 @@
   manage_link_ = new views::Link(UTF8ToUTF16(bubble_content.manage_link));
   manage_link_->set_listener(this);
   layout->AddView(manage_link_);
-
-  close_button_ = new views::LabelButton(
-      this, l10n_util::GetStringUTF16(IDS_DONE));
-  close_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
-  layout->AddView(close_button_);
+  if (content_setting_bubble_model_->content_type() !=
+      CONTENT_SETTINGS_TYPE_SAVE_PASSWORD) {
+    close_button_ =
+        new views::LabelButton(this, l10n_util::GetStringUTF16(IDS_DONE));
+    close_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+    layout->AddView(close_button_);
+  }
 }
 
 void ContentSettingBubbleContents::ButtonPressed(views::Button* sender,
diff --git a/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc b/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
index 15bc3c1..d234b2b 100644
--- a/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
+++ b/chrome/browser/ui/views/download/download_in_progress_dialog_view.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 
 #include "base/strings/string_number_conversions.h"
-#include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -21,20 +20,25 @@
 #include "ui/views/widget/widget.h"
 
 // static
-void DownloadInProgressDialogView::Show(Browser* browser,
-                                        gfx::NativeWindow parent) {
-  DownloadInProgressDialogView* window =
-      new DownloadInProgressDialogView(browser);
+void DownloadInProgressDialogView::Show(
+    gfx::NativeWindow parent,
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  DownloadInProgressDialogView* window = new DownloadInProgressDialogView(
+      download_count, dialog_type, app_modal, callback);
   CreateBrowserModalDialogViews(window, parent)->Show();
 }
 
-DownloadInProgressDialogView::DownloadInProgressDialogView(Browser* browser)
-    : browser_(browser),
+DownloadInProgressDialogView::DownloadInProgressDialogView(
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback)
+    : app_modal_(app_modal),
+      callback_(callback),
       message_box_view_(NULL) {
-  int download_count;
-  Browser::DownloadClosePreventionType dialog_type =
-      browser_->OkToCloseWithInProgressDownloads(&download_count);
-
   string16 explanation_text;
   switch (dialog_type) {
     case Browser::DOWNLOAD_CLOSE_BROWSER_SHUTDOWN:
@@ -93,17 +97,17 @@
 }
 
 bool DownloadInProgressDialogView::Cancel() {
-  browser_->InProgressDownloadResponse(false);
+  callback_.Run(false);
   return true;
 }
 
 bool DownloadInProgressDialogView::Accept() {
-  browser_->InProgressDownloadResponse(true);
+  callback_.Run(true);
   return true;
 }
 
 ui::ModalType DownloadInProgressDialogView::GetModalType() const {
-  return ui::MODAL_TYPE_WINDOW;
+  return app_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW;
 }
 
 string16 DownloadInProgressDialogView::GetWindowTitle() const {
diff --git a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
index cf53d3f..acce8e8 100644
--- a/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
+++ b/chrome/browser/ui/views/download/download_in_progress_dialog_view.h
@@ -7,20 +7,26 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "chrome/browser/ui/browser.h"
 #include "ui/views/window/dialog_delegate.h"
 
-class Browser;
-
 namespace views {
 class MessageBoxView;
 }
 
 class DownloadInProgressDialogView : public views::DialogDelegate {
  public:
-  static void Show(Browser* browser, gfx::NativeWindow parent);
+  static void Show(gfx::NativeWindow parent_window,
+                   int download_count,
+                   Browser::DownloadClosePreventionType dialog_type,
+                   bool app_modal,
+                   const base::Callback<void(bool)>& callback);
 
  private:
-  explicit DownloadInProgressDialogView(Browser* browser);
+  DownloadInProgressDialogView(int download_count,
+                               Browser::DownloadClosePreventionType dialog_type,
+                               bool app_modal,
+                               const base::Callback<void(bool)>& callback);
   virtual ~DownloadInProgressDialogView();
 
   // views::DialogDelegate:
@@ -37,7 +43,8 @@
   virtual const views::Widget* GetWidget() const OVERRIDE;
   virtual views::View* GetContentsView() OVERRIDE;
 
-  Browser* browser_;
+  const bool app_modal_;
+  const base::Callback<void(bool)> callback_;
   views::MessageBoxView* message_box_view_;
 
   string16 title_text_;
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 409b889..7921718 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/utf_string_conversions.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/web_contents.h"
@@ -29,6 +30,7 @@
 #include "ui/views/window/dialog_client_view.h"
 
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 namespace {
 
@@ -85,12 +87,13 @@
       WebContentsModalDialogManager::FromWebContents(
           controller->web_contents());
   DCHECK(web_contents_modal_dialog_manager);
-  DCHECK(web_contents_modal_dialog_manager->delegate());
-  window_ = CreateWebContentsModalDialogViews(
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  DCHECK(modal_delegate);
+  window_ = views::Widget::CreateWindowAsFramelessChild(
       this,
       controller->web_contents()->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
 }
 
@@ -128,7 +131,10 @@
   subtext->SetMultiLine(true);
   subtext->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   layout->StartRow(0, column_set_id);
-  layout->AddView(subtext);
+  layout->AddView(
+      subtext, 1, 1,
+      views::GridLayout::FILL, views::GridLayout::LEADING,
+      dialog_content_width, subtext->GetHeightForWidth(dialog_content_width));
   layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
   // Scrollable area for checkboxes.
diff --git a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc
index fbdb190..f4491b1 100644
--- a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.cc
@@ -4,174 +4,89 @@
 
 #include "chrome/browser/ui/views/frame/app_non_client_frame_view_ash.h"
 
-#include "ash/shell_delegate.h"
-#include "ash/wm/workspace/frame_maximize_button.h"
-#include "base/debug/stack_trace.h"
+#include "ash/wm/workspace/frame_caption_button_container_view.h"
 #include "base/i18n/rtl.h"
-#include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "grit/ash_resources.h"
-#include "grit/generated_resources.h"  // Accessibility names
-#include "grit/theme_resources.h"
 #include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/base/theme_provider.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/point.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
-#include "ui/views/controls/button/image_button.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/non_client_view.h"
 
 namespace {
-// The number of pixels within the shadow to draw the buttons.
-const int kShadowStart = 16;
-// The size and close buttons are designed to overlap.
-const int kButtonOverlap = 1;
 
-// TODO(pkotwicz): Remove these constants once the IDR_AURA_FULLSCREEN_SHADOW
-// resource is updated.
-const int kShadowHeightStretch = -1;
-}
+// The size of the shadow around the caption buttons.
+const int kShadowSizeX = 16;
+const int kShadowSizeBottom = 21;
 
-class AppNonClientFrameViewAsh::ControlView
-    : public views::View, public views::ButtonListener {
+// The border for |control_view_|.
+class ControlViewBorder : public views::Border {
  public:
-  // TODO(skuhne): If we keep the "always maximized" experiment we might want to
-  // make this function be able to work with a |restore_button_| which is NULL.
-  explicit ControlView(AppNonClientFrameViewAsh* owner) :
-      owner_(owner),
-      close_button_(new views::ImageButton(this)),
-      restore_button_(new ash::FrameMaximizeButton(this, owner_))
-  {
-    close_button_->SetAccessibleName(
-        l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE));
-    restore_button_->SetAccessibleName(
-        l10n_util::GetStringUTF16(IDS_ACCNAME_MAXIMIZE));
-
-    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-
-    int control_base_resource_id = owner->browser_view()->IsOffTheRecord() ?
-        IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE :
-        IDR_AURA_WINDOW_HEADER_BASE_ACTIVE;
-    control_base_ = rb.GetImageNamed(control_base_resource_id).ToImageSkia();
-    shadow_ = rb.GetImageNamed(
-        base::i18n::IsRTL() ? IDR_AURA_WINDOW_FULLSCREEN_SHADOW_RTL :
-                              IDR_AURA_WINDOW_FULLSCREEN_SHADOW).ToImageSkia();
-
-    AddChildView(close_button_);
-    AddChildView(restore_button_);
+  ControlViewBorder() {
+    int border_id = base::i18n::IsRTL() ?
+        IDR_AURA_WINDOW_FULLSCREEN_SHADOW_RTL :
+        IDR_AURA_WINDOW_FULLSCREEN_SHADOW;
+    border_ = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+        border_id).AsImageSkia();
   }
 
-  virtual ~ControlView() {}
-
-  virtual void Layout() OVERRIDE {
-    if (ash::Shell::IsForcedMaximizeMode()) {
-      // TODO(skuhne): If this experiment would get persued, it would be better
-      // to check here the |restore_button_|'s visibility. Furthermore we
-      // should change |shadow_| to a new bitmap which can host only a single
-      // button.
-      gfx::Size size = restore_button_->bounds().size();
-      if (size.width()) {
-        size.set_width(0);
-        restore_button_->SetSize(size);
-      }
-    }
-    restore_button_->SetPosition(gfx::Point(kShadowStart, 0));
-    close_button_->SetPosition(gfx::Point(kShadowStart +
-        restore_button_->width() - kButtonOverlap, 0));
-  }
-
-  virtual void ViewHierarchyChanged(
-      const ViewHierarchyChangedDetails& details) OVERRIDE {
-    if (details.is_add && details.child == this) {
-      SetButtonImages(restore_button_,
-                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE,
-                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE_H,
-                      IDR_AURA_WINDOW_FULLSCREEN_RESTORE_P);
-      restore_button_->SizeToPreferredSize();
-
-      SetButtonImages(close_button_,
-                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE,
-                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE_H,
-                      IDR_AURA_WINDOW_FULLSCREEN_CLOSE_P);
-      close_button_->SizeToPreferredSize();
-    }
-  }
-
-  virtual gfx::Size GetPreferredSize() OVERRIDE {
-    int maximize_button_deduction = ash::Shell::IsForcedMaximizeMode() ?
-        restore_button_->GetPreferredSize().width() : 0;
-
-    return gfx::Size(shadow_->width() - maximize_button_deduction,
-                     shadow_->height() + kShadowHeightStretch);
-  }
-
-  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
-    canvas->TileImageInt(*control_base_,
-        base::i18n::IsRTL() ? 0 : restore_button_->x(),
-        restore_button_->y(),
-        restore_button_->width() - kButtonOverlap + close_button_->width(),
-        restore_button_->height());
-
-    views::View::OnPaint(canvas);
-
-    canvas->DrawImageInt(*shadow_, 0, kShadowHeightStretch);
-  }
-
-  virtual void ButtonPressed(views::Button* sender,
-                             const ui::Event& event) OVERRIDE {
-    ash::UserMetricsAction action = ash::UMA_WINDOW_APP_CLOSE_BUTTON_CLICK;
-    if (sender == close_button_) {
-      owner_->frame()->Close();
-    } else if (sender == restore_button_) {
-      action = ash::UMA_WINDOW_MAXIMIZE_BUTTON_CLICK_RESTORE;
-      restore_button_->SetState(views::CustomButton::STATE_NORMAL);
-      owner_->frame()->Restore();
-    } else {
-      return;
-    }
-    ChromeShellDelegate::instance()->RecordUserMetricsAction(action);
-  }
-
-  // Returns the insets of the control which are only covered by the shadow.
-  gfx::Insets GetShadowInsets() {
-    bool rtl = base::i18n::IsRTL();
-    return gfx::Insets(
-        0,
-        rtl ? 0 : restore_button_->x(),
-        shadow_->height() - close_button_->height(),
-        rtl ? restore_button_->x() : 0);
+  virtual ~ControlViewBorder() {
   }
 
  private:
-  // Sets images whose ids are passed in for each of the respective states
-  // of |button|.
-  void SetButtonImages(views::ImageButton* button, int normal_image_id,
-                       int hot_image_id, int pushed_image_id) {
-    ui::ThemeProvider* theme_provider = GetThemeProvider();
-    button->SetImage(views::CustomButton::STATE_NORMAL,
-                     theme_provider->GetImageSkiaNamed(normal_image_id));
-    button->SetImage(views::CustomButton::STATE_HOVERED,
-                     theme_provider->GetImageSkiaNamed(hot_image_id));
-    button->SetImage(views::CustomButton::STATE_PRESSED,
-                     theme_provider->GetImageSkiaNamed(pushed_image_id));
+  // views::Border overrides:
+  virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE {
+    canvas->DrawImageInt(border_, 0, view.height() - border_.height());
   }
 
-  AppNonClientFrameViewAsh* owner_;
-  views::ImageButton* close_button_;
-  views::ImageButton* restore_button_;
-  const gfx::ImageSkia* control_base_;
-  const gfx::ImageSkia* shadow_;
+  virtual gfx::Insets GetInsets() const OVERRIDE {
+    return gfx::Insets(0, kShadowSizeX, kShadowSizeBottom, 0);
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(ControlView);
+  gfx::ImageSkia border_;
+
+  DISALLOW_COPY_AND_ASSIGN(ControlViewBorder);
 };
 
+// The background for |control_view_|.
+class ControlViewBackground : public views::Background {
+ public:
+  explicit ControlViewBackground(bool is_incognito) {
+    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+    int control_base_resource_id = is_incognito ?
+        IDR_AURA_WINDOW_HEADER_BASE_INCOGNITO_ACTIVE :
+        IDR_AURA_WINDOW_HEADER_BASE_ACTIVE;
+    background_ = rb.GetImageNamed(control_base_resource_id).AsImageSkia();
+  }
+
+  virtual ~ControlViewBackground() {
+  }
+
+ private:
+  // views::Background override:
+  virtual void Paint(gfx::Canvas* canvas, views::View* view) const OVERRIDE {
+    gfx::Rect paint_bounds(view->GetContentsBounds());
+    paint_bounds.set_x(view->GetMirroredXForRect(paint_bounds));
+    canvas->TileImageInt(background_, paint_bounds.x(), paint_bounds.y(),
+        paint_bounds.width(), paint_bounds.height());
+  }
+
+  gfx::ImageSkia background_;
+
+  DISALLOW_COPY_AND_ASSIGN(ControlViewBackground);
+};
+
+}  // namespace
+
 // Observer to detect when the browser frame widget closes so we can clean
 // up our ControlView. Because we can be closed via a keyboard shortcut we
 // are not guaranteed to run AppNonClientFrameView's Close() or Restore().
@@ -201,9 +116,13 @@
 AppNonClientFrameViewAsh::AppNonClientFrameViewAsh(
     BrowserFrame* frame, BrowserView* browser_view)
     : BrowserNonClientFrameView(frame, browser_view),
-      control_view_(new ControlView(this)),
+      control_view_(new ash::FrameCaptionButtonContainerView(this, frame)),
       control_widget_(NULL),
       frame_observer_(new FrameObserver(this)) {
+  control_view_->set_border(new ControlViewBorder());
+  control_view_->set_background(new ControlViewBackground(
+      browser_view->IsOffTheRecord()));
+
   // This FrameView is always maximized so we don't want the window to have
   // resize borders.
   frame->GetNativeView()->set_hit_test_bounds_override_inner(gfx::Insets());
@@ -219,9 +138,17 @@
   control_widget_->SetContentsView(control_view_);
   aura::Window* window = control_widget_->GetNativeView();
   window->SetName(kControlWindowName);
+
   // Need to exclude the shadow from the active control area.
-  window->SetHitTestBoundsOverrideOuter(control_view_->GetShadowInsets(),
-                                        control_view_->GetShadowInsets());
+  gfx::Insets hit_test_insets(control_view_->GetInsets());
+  if (base::i18n::IsRTL()) {
+    hit_test_insets = gfx::Insets(hit_test_insets.top(),
+                                  hit_test_insets.right(),
+                                  hit_test_insets.bottom(),
+                                  hit_test_insets.left());
+  }
+  window->SetHitTestBoundsOverrideOuter(hit_test_insets, hit_test_insets);
+
   gfx::Rect control_bounds = GetControlBounds();
   window->SetBounds(control_bounds);
   control_widget_->Show();
diff --git a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.h
index 2d8ac3e..2c0058f 100644
--- a/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.h
+++ b/chrome/browser/ui/views/frame/app_non_client_frame_view_ash.h
@@ -46,7 +46,6 @@
   virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
 
  private:
-  class ControlView;
   class FrameObserver;
 
   gfx::Rect GetControlBounds() const;
@@ -55,7 +54,7 @@
   void CloseControlWidget();
 
   // The View containing the restore and close buttons.
-  ControlView* control_view_;
+  views::View* control_view_;
   // The widget holding the control_view_.
   views::Widget* control_widget_;
   // Observer for browser frame close.
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 3e8e4d7..9a86155 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
@@ -6,6 +6,7 @@
 
 #include <dwmapi.h>
 
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
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 e580c1b..e5ae6d0 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
@@ -56,8 +56,9 @@
         avatar_label_ = new AvatarLabel(browser_view_);
         AddChildView(avatar_label_);
       }
-      avatar_button_ = new AvatarMenuButton(browser_view_->browser(),
-                                            browser_view_->IsOffTheRecord());
+      avatar_button_ = new AvatarMenuButton(
+          browser_view_->browser(),
+          browser_view_->IsOffTheRecord() && !browser_view_->IsGuestSession());
       AddChildView(avatar_button_);
       frame_->GetRootView()->Layout();
     }
@@ -78,7 +79,9 @@
   gfx::Image avatar;
   string16 text;
   bool is_gaia_picture = false;
-  if (browser_view_->IsOffTheRecord()) {
+  if (browser_view_->IsGuestSession()) {
+    avatar = rb.GetImageNamed(browser_view_->GetGuestIconResourceID());
+  } else if (browser_view_->IsOffTheRecord()) {
     avatar = rb.GetImageNamed(browser_view_->GetOTRIconResourceID());
   } else if (AvatarMenuModel::ShouldShowAvatarMenu()) {
     ProfileInfoCache& cache =
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index c2f4dc9..6ad8447 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -568,11 +568,20 @@
   return browser_->profile()->IsGuestSession();
 }
 
+int BrowserView::GetGuestIconResourceID() const {
+  return IDR_GUEST_ICON;
+}
+
 bool BrowserView::ShouldShowAvatar() const {
   if (!IsBrowserTypeNormal())
     return false;
+#if defined(OS_CHROMEOS)
   if (IsOffTheRecord() && !IsGuestSession())
     return true;
+#else
+  if (IsOffTheRecord())  // Desktop guest is incognito and needs avatar.
+    return true;
+#endif
   // Tests may not have a profile manager.
   if (!g_browser_process->profile_manager())
     return false;
@@ -964,9 +973,8 @@
       is_loading ? ReloadButton::MODE_STOP : ReloadButton::MODE_RELOAD, force);
 }
 
-void BrowserView::UpdateToolbar(content::WebContents* contents,
-                                bool should_restore_state) {
-  toolbar_->Update(contents, should_restore_state);
+void BrowserView::UpdateToolbar(content::WebContents* contents) {
+  toolbar_->Update(contents);
 }
 
 void BrowserView::FocusToolbar() {
@@ -1155,8 +1163,13 @@
   return download_shelf_.get();
 }
 
-void BrowserView::ConfirmBrowserCloseWithPendingDownloads() {
-  DownloadInProgressDialogView::Show(browser_.get(), GetNativeWindow());
+void BrowserView::ConfirmBrowserCloseWithPendingDownloads(
+    int download_count,
+    Browser::DownloadClosePreventionType dialog_type,
+    bool app_modal,
+    const base::Callback<void(bool)>& callback) {
+  DownloadInProgressDialogView::Show(
+      GetNativeWindow(), download_count, dialog_type, app_modal, callback);
 }
 
 void BrowserView::ShowCreateChromeAppShortcutsDialog(
@@ -1257,13 +1270,14 @@
   // the |browser_| object then send the keyboard event to the
   // |focus_manager| as if we are activating an accelerator key.
   // Then we can retrieve the command id from the |browser_| object.
+  bool original_block_command_state = controller->block_command_execution();
   controller->SetBlockCommandExecution(true);
   // If the |accelerator| is a non-browser shortcut (e.g. Ash shortcut), the
   // command execution cannot be blocked and true is returned. However, it is
   // okay as long as is_app() is false. See comments in this function.
   const bool processed = focus_manager->ProcessAccelerator(accelerator);
   const int id = controller->GetLastBlockedCommand(NULL);
-  controller->SetBlockCommandExecution(false);
+  controller->SetBlockCommandExecution(original_block_command_state);
 
   // Executing the command may cause |this| object to be destroyed.
   if (controller->IsReservedCommandOrKey(id, event)) {
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 00dd37b..f34f37f 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -204,6 +204,10 @@
   // a guest session.
   bool IsGuestSession() const;
 
+  // Returns the resource ID to use for the Guest icon, which may depend on
+  // which layout is being shown and whether we are full-screen.
+  int GetGuestIconResourceID() const;
+
   // Returns true if the non-client view should render an avatar icon.
   bool ShouldShowAvatar() const;
 
@@ -308,8 +312,7 @@
   virtual LocationBar* GetLocationBar() const OVERRIDE;
   virtual void SetFocusToLocationBar(bool select_all) OVERRIDE;
   virtual void UpdateReloadStopState(bool is_loading, bool force) OVERRIDE;
-  virtual void UpdateToolbar(content::WebContents* contents,
-                             bool should_restore_state) OVERRIDE;
+  virtual void UpdateToolbar(content::WebContents* contents) OVERRIDE;
   virtual void FocusToolbar() OVERRIDE;
   virtual void FocusAppMenu() OVERRIDE;
   virtual void FocusBookmarksToolbar() OVERRIDE;
@@ -340,7 +343,11 @@
   void SetDownloadShelfVisible(bool visible);
   virtual bool IsDownloadShelfVisible() const OVERRIDE;
   virtual DownloadShelf* GetDownloadShelf() OVERRIDE;
-  virtual void ConfirmBrowserCloseWithPendingDownloads() OVERRIDE;
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) OVERRIDE;
   virtual void UserChangedTheme() OVERRIDE;
   virtual int GetExtraRenderViewHeight() const OVERRIDE;
   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
diff --git a/chrome/browser/ui/views/frame/browser_view_layout.cc b/chrome/browser/ui/views/frame/browser_view_layout.cc
index 46b140a..571a098 100644
--- a/chrome/browser/ui/views/frame/browser_view_layout.cc
+++ b/chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -69,6 +69,12 @@
           : browser_view_layout_(browser_view_layout) {
   }
 
+  virtual ~WebContentsModalDialogHostViews() {
+    FOR_EACH_OBSERVER(web_modal::WebContentsModalDialogHostObserver,
+                      observer_list_,
+                      OnHostDestroying());
+  }
+
   void NotifyPositionRequiresUpdate() {
     FOR_EACH_OBSERVER(WebContentsModalDialogHostObserver,
                       observer_list_,
diff --git a/chrome/browser/ui/views/frame/browser_view_unittest.cc b/chrome/browser/ui/views/frame/browser_view_unittest.cc
index d3ad284..38e6ae2 100644
--- a/chrome/browser/ui/views/frame/browser_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_unittest.cc
@@ -324,9 +324,9 @@
     // visible.
     // This profile instance is owned by the TestingProfile instance within the
     // BrowserWithTestWindowTest class.
-    TestingProfile* incognito_profile = new TestingProfile();
-    incognito_profile->set_incognito(true);
-    GetProfile()->SetOffTheRecordProfile(incognito_profile);
+    TestingProfile::Builder builder;
+    builder.SetIncognito();
+    GetProfile()->SetOffTheRecordProfile(builder.Build());
 
     browser_view_ = new TestBrowserView();
     browser_view_->SetWindowSwitcherButton(
diff --git a/chrome/browser/ui/views/frame/contents_container.cc b/chrome/browser/ui/views/frame/contents_container.cc
index 13c076a..9461aa9 100644
--- a/chrome/browser/ui/views/frame/contents_container.cc
+++ b/chrome/browser/ui/views/frame/contents_container.cc
@@ -4,27 +4,15 @@
 
 #include "chrome/browser/ui/views/frame/contents_container.h"
 
-#include "content/public/browser/web_contents.h"
-#include "ui/views/controls/webview/webview.h"
-
-// static
-const char ContentsContainer::kViewClassName[] = "ContentsContainer";
-
 ContentsContainer::ContentsContainer(views::View* active_web_view)
-    : active_(active_web_view),
+    : active_web_view_(active_web_view),
       active_top_margin_(0) {
-  AddChildView(active_);
+  AddChildView(active_web_view_);
 }
 
 ContentsContainer::~ContentsContainer() {
 }
 
-void ContentsContainer::SetActive(views::WebView* overlay) {
-  DCHECK(overlay);
-  active_ = overlay;
-  Layout();
-}
-
 bool ContentsContainer::SetActiveTopMargin(int margin) {
   if (active_top_margin_ == margin)
     return false;
@@ -40,7 +28,7 @@
   int content_y = active_top_margin_;
   int content_height = std::max(0, height() - content_y);
 
-  active_->SetBounds(0, content_y, width(), content_height);
+  active_web_view_->SetBounds(0, content_y, width(), content_height);
 
   // Need to invoke views::View in case any views whose bounds didn't change
   // still need a layout.
@@ -48,5 +36,5 @@
 }
 
 const char* ContentsContainer::GetClassName() const {
-  return kViewClassName;
+  return "ContentsContainer";
 }
diff --git a/chrome/browser/ui/views/frame/contents_container.h b/chrome/browser/ui/views/frame/contents_container.h
index 00b9705..cfd6d9a 100644
--- a/chrome/browser/ui/views/frame/contents_container.h
+++ b/chrome/browser/ui/views/frame/contents_container.h
@@ -11,35 +11,13 @@
 #include "base/compiler_specific.h"
 #include "ui/views/view.h"
 
-namespace content {
-class WebContents;
-}
-
-namespace gfx {
-class Rect;
-}
-
-namespace views {
-class WebView;
-};
-
 // ContentsContainer is responsible for managing the active WebContents view.
 // ContentsContainer has one child: the currently active WebContents.
-// TODO(kuan): Remove ContentsContainer since it has only one child now -
-// http://crbug.com/236587.
 class ContentsContainer : public views::View {
  public:
-  // Internal class name
-  static const char kViewClassName[];
-
-  explicit ContentsContainer(views::View* active);
+  explicit ContentsContainer(views::View* active_web_view);
   virtual ~ContentsContainer();
 
-  // Makes the overlay view the active view and nulls out the old active view.
-  // The caller must delete or remove the old active view separately.
-  // Called after |overlay| has been reparented to |ContentsContainer|.
-  void SetActive(views::WebView* overlay);
-
   // Sets the active top margin; the active WebView's y origin would be
   // positioned at this |margin|, causing the active WebView to be pushed down
   // vertically by |margin| pixels in the |ContentsContainer|. Returns true
@@ -50,14 +28,11 @@
   virtual void Layout() OVERRIDE;
   virtual const char* GetClassName() const OVERRIDE;
 
-  // Testing interface:
-  views::View* GetActiveWebViewForTest() { return active_; }
-
  private:
-  views::View* active_;
+  views::View* active_web_view_;
 
   // The margin between the top and the active view. This is used to make the
-  // overlay overlap the bookmark bar on the new tab page.
+  // find bar overlap the detached bookmark bar on the new tab page.
   int active_top_margin_;
 
   DISALLOW_COPY_AND_ASSIGN(ContentsContainer);
diff --git a/chrome/browser/ui/views/location_bar/generated_credit_card_view.cc b/chrome/browser/ui/views/location_bar/generated_credit_card_view.cc
index ff914b6..38ce6ad 100644
--- a/chrome/browser/ui/views/location_bar/generated_credit_card_view.cc
+++ b/chrome/browser/ui/views/location_bar/generated_credit_card_view.cc
@@ -9,10 +9,8 @@
 #include "ui/gfx/image/image.h"
 
 GeneratedCreditCardView::GeneratedCreditCardView(
-    ToolbarModel* toolbar_model,
     LocationBarView::Delegate* delegate)
-    : toolbar_model_(toolbar_model),
-      delegate_(delegate) {
+    : delegate_(delegate) {
   Update();
 }
 
@@ -45,7 +43,7 @@
 autofill::GeneratedCreditCardBubbleController* GeneratedCreditCardView::
     GetController() const {
   content::WebContents* wc = delegate_->GetWebContents();
-  if (!wc || toolbar_model_->GetInputInProgress())
+  if (!wc || delegate_->GetToolbarModel()->input_in_progress())
     return NULL;
 
   return autofill::GeneratedCreditCardBubbleController::FromWebContents(wc);
diff --git a/chrome/browser/ui/views/location_bar/generated_credit_card_view.h b/chrome/browser/ui/views/location_bar/generated_credit_card_view.h
index c741985..5dda7f3 100644
--- a/chrome/browser/ui/views/location_bar/generated_credit_card_view.h
+++ b/chrome/browser/ui/views/location_bar/generated_credit_card_view.h
@@ -12,8 +12,6 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "ui/views/controls/image_view.h"
 
-class ToolbarModel;
-
 namespace autofill {
 class GeneratedCreditCardBubbleController;
 }
@@ -29,8 +27,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 class GeneratedCreditCardView : public LocationBarDecorationView {
  public:
-  GeneratedCreditCardView(ToolbarModel* toolbar_model,
-                         LocationBarView::Delegate* delegate);
+  explicit GeneratedCreditCardView(LocationBarView::Delegate* delegate);
   virtual ~GeneratedCreditCardView();
 
   void Update();
@@ -45,7 +42,6 @@
   // current web contents.
   autofill::GeneratedCreditCardBubbleController* GetController() const;
 
-  ToolbarModel* toolbar_model_;  // weak; outlives us.
   LocationBarView::Delegate* delegate_;  // weak; outlives us.
 
   DISALLOW_COPY_AND_ASSIGN(GeneratedCreditCardView);
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 64bdc85..5dc19f8 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -164,13 +164,11 @@
 LocationBarView::LocationBarView(Browser* browser,
                                  Profile* profile,
                                  CommandUpdater* command_updater,
-                                 ToolbarModel* model,
                                  Delegate* delegate,
                                  bool is_popup_mode)
     : browser_(browser),
       profile_(profile),
       command_updater_(command_updater),
-      model_(model),
       delegate_(delegate),
       disposition_(CURRENT_TAB),
       transition_(content::PageTransitionFromInt(
@@ -280,16 +278,30 @@
   AddChildView(ev_bubble_view_);
 
   // Initialize the Omnibox view.
-  location_entry_.reset(CreateOmniboxView(this, model_, profile_,
-      command_updater_, is_popup_mode_, this, font_list, font_y_offset));
+  location_entry_.reset(CreateOmniboxView(this, profile_, command_updater_,
+                                          is_popup_mode_, this, font_list,
+                                          font_y_offset));
   SetLocationEntryFocusable(true);
   location_entry_view_ = location_entry_->AddToView(this);
 
   // Initialize the inline autocomplete view which is visible only when IME is
   // turned on.  Use the same font with the omnibox and highlighted background.
   ime_inline_autocomplete_view_ = new views::Label(string16(), font);
-  ime_inline_autocomplete_view_->set_border(
-      views::Border::CreateEmptyBorder(font_y_offset, 0, 0, 0));
+  {
+    // views::Label (|ime_inline_autocomplete_view_|) supports only gfx::Font
+    // and ignores the rest of fonts but the first in |font_list| while
+    // views::Textfield (|location_entry_view_|) supports gfx::FontList and
+    // layouts text based on all fonts in the list.  Thus the font height and
+    // baseline can be different between them.  We add padding to align them
+    // on the same baseline.
+    // TODO(yukishiino): Remove this hack once views::Label supports
+    // gfx::FontList.
+    const int baseline_diff = location_entry_view_->GetBaseline() -
+        ime_inline_autocomplete_view_->GetBaseline();
+    ime_inline_autocomplete_view_->set_border(
+        views::Border::CreateEmptyBorder(
+            font_y_offset + baseline_diff, 0, 0, 0));
+  }
   ime_inline_autocomplete_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   ime_inline_autocomplete_view_->SetAutoColorReadabilityEnabled(false);
   ime_inline_autocomplete_view_->set_background(
@@ -348,10 +360,10 @@
     AddChildView(content_blocked_view);
   }
 
-  generated_credit_card_view_ = new GeneratedCreditCardView(model_, delegate_);
+  generated_credit_card_view_ = new GeneratedCreditCardView(delegate_);
   AddChildView(generated_credit_card_view_);
 
-  zoom_view_ = new ZoomView(model_, delegate_);
+  zoom_view_ = new ZoomView(delegate_);
   zoom_view_->set_id(VIEW_ID_ZOOM_BUTTON);
   AddChildView(zoom_view_);
 
@@ -484,7 +496,7 @@
 
 void LocationBarView::Update(const WebContents* tab_for_state_restoring) {
   mic_search_view_->SetVisible(
-      !model_->GetInputInProgress() && browser_ &&
+      !GetToolbarModel()->input_in_progress() && browser_ &&
       browser_->search_model()->voice_search_supported());
   RefreshContentSettingViews();
   generated_credit_card_view_->Update();
@@ -493,11 +505,11 @@
   RefreshPageActionViews();
   RefreshScriptBubble();
   open_pdf_in_reader_view_->Update(
-      model_->GetInputInProgress() ? NULL : GetWebContents());
+      GetToolbarModel()->input_in_progress() ? NULL : GetWebContents());
 
-  bool star_enabled =
-      browser_defaults::bookmarks_enabled && !is_popup_mode_ && star_view_ &&
-      !model_->GetInputInProgress() && edit_bookmarks_enabled_.GetValue();
+  bool star_enabled = browser_defaults::bookmarks_enabled && !is_popup_mode_ &&
+      star_view_ && !GetToolbarModel()->input_in_progress() &&
+      edit_bookmarks_enabled_.GetValue();
 
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE, star_enabled);
   command_updater_->UpdateCommandEnabled(IDC_BOOKMARK_PAGE_FROM_STAR,
@@ -545,7 +557,7 @@
 
 void LocationBarView::UpdateOpenPDFInReaderPrompt() {
   open_pdf_in_reader_view_->Update(
-      model_->GetInputInProgress() ? NULL : GetWebContents());
+      GetToolbarModel()->input_in_progress() ? NULL : GetWebContents());
   Layout();
   SchedulePaint();
 }
@@ -584,7 +596,7 @@
     return;
 
   page_action_view->image_view()->set_preview_enabled(preview_enabled);
-  page_action_view->UpdateVisibility(contents, model_->GetURL());
+  page_action_view->UpdateVisibility(contents, GetToolbarModel()->GetURL());
   Layout();
   SchedulePaint();
 }
@@ -726,8 +738,9 @@
         selected_keyword_view_->set_is_extension_icon(false);
       }
     }
-  } else if (model_->GetSecurityLevel(false) == ToolbarModel::EV_SECURE) {
-    ev_bubble_view_->SetLabel(model_->GetEVCertName());
+  } else if (GetToolbarModel()->GetSecurityLevel(false) ==
+      ToolbarModel::EV_SECURE) {
+    ev_bubble_view_->SetLabel(GetToolbarModel()->GetEVCertName());
     // The largest fraction of the omnibox that can be taken by the EV bubble.
     const double kMaxBubbleFraction = 0.5;
     leading_decorations.AddDecoration(bubble_location_y, bubble_height, false,
@@ -1094,10 +1107,18 @@
   return delegate_->GetInstant();
 }
 
-WebContents* LocationBarView::GetWebContents() const {
+WebContents* LocationBarView::GetWebContents() {
   return delegate_->GetWebContents();
 }
 
+ToolbarModel* LocationBarView::GetToolbarModel() {
+  return delegate_->GetToolbarModel();
+}
+
+const ToolbarModel* LocationBarView::GetToolbarModel() const {
+  return delegate_->GetToolbarModel();
+}
+
 // static
 int LocationBarView::GetBuiltInHorizontalPaddingForChildViews() {
   return (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) ?
@@ -1113,7 +1134,8 @@
 void LocationBarView::RefreshContentSettingViews() {
   for (ContentSettingViews::const_iterator i(content_setting_views_.begin());
        i != content_setting_views_.end(); ++i) {
-    (*i)->Update(model_->GetInputInProgress() ? NULL : GetWebContents());
+    (*i)->Update(GetToolbarModel()->input_in_progress() ?
+        NULL : GetWebContents());
   }
 }
 
@@ -1177,8 +1199,8 @@
 
     for (PageActionViews::const_iterator i(page_action_views_.begin());
          i != page_action_views_.end(); ++i) {
-      (*i)->UpdateVisibility(model_->GetInputInProgress() ? NULL : contents,
-                             url);
+      (*i)->UpdateVisibility(
+          GetToolbarModel()->input_in_progress() ? NULL : contents, url);
 
       // Check if the visibility of the action changed and notify if it did.
       ExtensionAction* action = (*i)->image_view()->page_action();
@@ -1250,7 +1272,7 @@
 
   const int32 tab_id = SessionID::IdForTab(web_contents);
   const ToolbarModel::SecurityLevel security_level =
-      model_->GetSecurityLevel(false);
+      GetToolbarModel()->GetSecurityLevel(false);
   const SkColor text_color = GetColor(security_level, TEXT);
   const SkColor background_color = GetColor(security_level, BACKGROUND);
 
@@ -1517,8 +1539,8 @@
 
 void LocationBarView::ModelChanged(const SearchModel::State& old_state,
                                    const SearchModel::State& new_state) {
-  const bool visible =
-      !model_->GetInputInProgress() && new_state.voice_search_supported;
+  const bool visible = !GetToolbarModel()->input_in_progress() &&
+      new_state.voice_search_supported;
   if (mic_search_view_->visible() != visible) {
     mic_search_view_->SetVisible(visible);
     Layout();
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 2c14ff7..a39c901 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -91,11 +91,14 @@
   class Delegate {
    public:
     // Should return the current web contents.
-    virtual content::WebContents* GetWebContents() const = 0;
+    virtual content::WebContents* GetWebContents() = 0;
 
     // Returns the InstantController, or NULL if there isn't one.
     virtual InstantController* GetInstant() = 0;
 
+    virtual ToolbarModel* GetToolbarModel() = 0;
+    virtual const ToolbarModel* GetToolbarModel() const = 0;
+
     // Creates Widget for the given delegate.
     virtual views::Widget* CreateViewsBubble(
         views::BubbleDelegateView* bubble_delegate) = 0;
@@ -134,7 +137,6 @@
   LocationBarView(Browser* browser,
                   Profile* profile,
                   CommandUpdater* command_updater,
-                  ToolbarModel* model,
                   Delegate* delegate,
                   bool is_popup_mode);
 
@@ -266,7 +268,9 @@
   virtual gfx::Image GetFavicon() const OVERRIDE;
   virtual string16 GetTitle() const OVERRIDE;
   virtual InstantController* GetInstant() OVERRIDE;
-  virtual content::WebContents* GetWebContents() const OVERRIDE;
+  virtual content::WebContents* GetWebContents() OVERRIDE;
+  virtual ToolbarModel* GetToolbarModel() OVERRIDE;
+  virtual const ToolbarModel* GetToolbarModel() const OVERRIDE;
 
   // views::View:
   virtual const char* GetClassName() const OVERRIDE;
@@ -432,9 +436,6 @@
   // Command updater which corresponds to this View.
   CommandUpdater* command_updater_;
 
-  // The model.
-  ToolbarModel* model_;
-
   // Our delegate.
   Delegate* delegate_;
 
diff --git a/chrome/browser/ui/views/location_bar/page_info_helper.cc b/chrome/browser/ui/views/location_bar/page_info_helper.cc
index 7f27d50..4839122 100644
--- a/chrome/browser/ui/views/location_bar/page_info_helper.cc
+++ b/chrome/browser/ui/views/location_bar/page_info_helper.cc
@@ -34,7 +34,8 @@
   if (!tab)
     return;
   const NavigationController& controller = tab->GetController();
-  NavigationEntry* nav_entry = controller.GetActiveEntry();
+  // Important to use GetVisibleEntry to match what's showing in the omnibox.
+  NavigationEntry* nav_entry = controller.GetVisibleEntry();
   if (!nav_entry) {
     NOTREACHED();
     return;
diff --git a/chrome/browser/ui/views/location_bar/zoom_view.cc b/chrome/browser/ui/views/location_bar/zoom_view.cc
index 34b432a..0ed27fb 100644
--- a/chrome/browser/ui/views/location_bar/zoom_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_view.cc
@@ -16,10 +16,8 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/size.h"
 
-ZoomView::ZoomView(ToolbarModel* toolbar_model,
-                   LocationBarView::Delegate* location_bar_delegate)
-    : toolbar_model_(toolbar_model),
-      location_bar_delegate_(location_bar_delegate) {
+ZoomView::ZoomView(LocationBarView::Delegate* location_bar_delegate)
+    : location_bar_delegate_(location_bar_delegate) {
   set_accessibility_focusable(true);
   Update(NULL);
   LocationBarView::InitTouchableLocationBarChildView(this);
@@ -30,7 +28,7 @@
 
 void ZoomView::Update(ZoomController* zoom_controller) {
   if (!zoom_controller || zoom_controller->IsAtDefaultZoom() ||
-      toolbar_model_->GetInputInProgress()) {
+      location_bar_delegate_->GetToolbarModel()->input_in_progress()) {
     SetVisible(false);
     ZoomBubbleView::CloseBubble();
     return;
diff --git a/chrome/browser/ui/views/location_bar/zoom_view.h b/chrome/browser/ui/views/location_bar/zoom_view.h
index bc3876d..0bac5d2 100644
--- a/chrome/browser/ui/views/location_bar/zoom_view.h
+++ b/chrome/browser/ui/views/location_bar/zoom_view.h
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "ui/views/controls/image_view.h"
 
-class ToolbarModel;
 class ZoomController;
 
 // View for the zoom icon in the Omnibox.
@@ -21,8 +20,7 @@
   // tabs, it cannot be provided in the constructor. Instead, a
   // LocationBarView::Delegate is passed here so that it can be queried for the
   // current WebContents as needed.
-  ZoomView(ToolbarModel* toolbar_model,
-           LocationBarView::Delegate* location_bar_delegate);
+  explicit ZoomView(LocationBarView::Delegate* location_bar_delegate);
   virtual ~ZoomView();
 
   // Updates the image and its tooltip appropriately, hiding or showing the icon
@@ -45,9 +43,6 @@
   // widget.
   void ActivateBubble();
 
-  // Toolbar model used to test whether location bar input is in progress.
-  ToolbarModel* toolbar_model_;
-
   // The delegate used to get the currently visible WebContents.
   LocationBarView::Delegate* location_bar_delegate_;
 
diff --git a/chrome/browser/ui/views/login_prompt_views.cc b/chrome/browser/ui/views/login_prompt_views.cc
index 7ce58c3..0979077 100644
--- a/chrome/browser/ui/views/login_prompt_views.cc
+++ b/chrome/browser/ui/views/login_prompt_views.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "chrome/browser/ui/views/login_view.h"
 #include "chrome/common/chrome_switches.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"
@@ -27,6 +28,7 @@
 using content::PasswordForm;
 using content::WebContents;
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 // ----------------------------------------------------------------------------
 // LoginHandlerViews
@@ -153,11 +155,13 @@
     WebContents* requesting_contents = GetWebContentsForLogin();
     WebContentsModalDialogManager* web_contents_modal_dialog_manager =
         WebContentsModalDialogManager::FromWebContents(requesting_contents);
-    dialog_ = CreateWebContentsModalDialogViews(
+    WebContentsModalDialogManagerDelegate* modal_delegate =
+        web_contents_modal_dialog_manager->delegate();
+    DCHECK(modal_delegate);
+    dialog_ = views::Widget::CreateWindowAsFramelessChild(
         this,
         requesting_contents->GetView()->GetNativeView(),
-        web_contents_modal_dialog_manager->delegate()->
-            GetWebContentsModalDialogHost());
+        modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
     web_contents_modal_dialog_manager->ShowDialog(dialog_->GetNativeView());
     NotifyAuthNeeded();
   }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 4073001..c58534a 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -99,14 +99,13 @@
 const char OmniboxViewViews::kViewClassName[] = "OmniboxViewViews";
 
 OmniboxViewViews::OmniboxViewViews(OmniboxEditController* controller,
-                                   ToolbarModel* toolbar_model,
                                    Profile* profile,
                                    CommandUpdater* command_updater,
                                    bool popup_window_mode,
                                    LocationBarView* location_bar,
                                    const gfx::FontList& font_list,
                                    int font_y_offset)
-    : OmniboxView(profile, controller, toolbar_model, command_updater),
+    : OmniboxView(profile, controller, command_updater),
       popup_window_mode_(popup_window_mode),
       security_level_(ToolbarModel::NONE),
       ime_composing_before_change_(false),
@@ -198,8 +197,13 @@
 
 void OmniboxViewViews::OnMouseReleased(const ui::MouseEvent& event) {
   views::Textfield::OnMouseReleased(event);
+  // When the user has clicked and released to give us focus, select all unless
+  // we're doing search term replacement (in which case refining the existing
+  // query is common enough that we do click-to-place-cursor).
   if ((event.IsOnlyLeftMouseButton() || event.IsOnlyRightMouseButton()) &&
-      select_all_on_mouse_release_) {
+      select_all_on_mouse_release_ &&
+      !controller()->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+          false)) {
     // Select all in the reverse direction so as not to scroll the caret
     // into view and shift the contents jarringly.
     SelectAll(true);
@@ -362,10 +366,10 @@
 
 void OmniboxViewViews::Update(const content::WebContents* contents) {
   // NOTE: We're getting the URL text here from the ToolbarModel.
-  bool visibly_changed_permanent_text =
-      model()->UpdatePermanentText(toolbar_model()->GetText(true));
+  bool visibly_changed_permanent_text = model()->UpdatePermanentText(
+      controller()->GetToolbarModel()->GetText(true));
   ToolbarModel::SecurityLevel security_level =
-        toolbar_model()->GetSecurityLevel(false);
+        controller()->GetToolbarModel()->GetSecurityLevel(false);
   bool changed_security_level = (security_level != security_level_);
   security_level_ = security_level;
 
@@ -774,11 +778,10 @@
 bool OmniboxViewViews::IsCommandIdEnabled(int command_id) const {
   if (command_id == IDS_PASTE_AND_GO)
     return model()->CanPasteAndGo(GetClipboardText());
-  if (command_id == IDC_COPY_URL) {
-    return toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false) &&
-      !model()->user_input_in_progress();
-  }
-  return command_updater()->IsCommandEnabled(command_id);
+  if (command_id != IDC_COPY_URL)
+    return command_updater()->IsCommandEnabled(command_id);
+  return controller()->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+      false);
 }
 
 bool OmniboxViewViews::IsItemForCommandIdDynamic(int command_id) const {
@@ -897,7 +900,8 @@
 }
 
 void OmniboxViewViews::CopyURL() {
-  DoCopyURL(toolbar_model()->GetURL(), toolbar_model()->GetText(false));
+  DoCopyURL(controller()->GetToolbarModel()->GetURL(),
+            controller()->GetToolbarModel()->GetText(false));
 }
 
 void OmniboxViewViews::OnPaste() {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index f853248..dff230c 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -42,7 +42,6 @@
   static const char kViewClassName[];
 
   OmniboxViewViews(OmniboxEditController* controller,
-                   ToolbarModel* toolbar_model,
                    Profile* profile,
                    CommandUpdater* command_updater,
                    bool popup_window_mode,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
index a3617ea..2ecd259 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_win.cc
@@ -460,14 +460,12 @@
 HMODULE OmniboxViewWin::loaded_library_module_ = NULL;
 
 OmniboxViewWin::OmniboxViewWin(OmniboxEditController* controller,
-                               ToolbarModel* toolbar_model,
                                LocationBarView* location_bar,
                                CommandUpdater* command_updater,
                                bool popup_window_mode,
                                const gfx::FontList& font_list,
                                int font_y_offset)
-    : OmniboxView(location_bar->profile(), controller, toolbar_model,
-                  command_updater),
+    : OmniboxView(location_bar->profile(), controller, command_updater),
       popup_view_(OmniboxPopupContentsView::Create(
           font_list, this, model(), location_bar)),
       location_bar_(location_bar),
@@ -599,11 +597,11 @@
 }
 
 void OmniboxViewWin::Update(const WebContents* tab_for_state_restoring) {
-  const bool visibly_changed_permanent_text =
-      model()->UpdatePermanentText(toolbar_model()->GetText(true));
+  const bool visibly_changed_permanent_text = model()->UpdatePermanentText(
+      controller()->GetToolbarModel()->GetText(true));
 
   const ToolbarModel::SecurityLevel security_level =
-      toolbar_model()->GetSecurityLevel(false);
+      controller()->GetToolbarModel()->GetSecurityLevel(false);
   const bool changed_security_level = (security_level != security_level_);
 
   // Bail early when no visible state will actually change (prevents an
@@ -1105,7 +1103,8 @@
 }
 
 void OmniboxViewWin::CopyURL() {
-  DoCopyURL(toolbar_model()->GetURL(), toolbar_model()->GetText(false));
+  DoCopyURL(controller()->GetToolbarModel()->GetURL(),
+            controller()->GetToolbarModel()->GetText(false));
 }
 
 bool OmniboxViewWin::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
@@ -1177,8 +1176,8 @@
       return !!CanCopy();
     case IDC_COPY_URL:
       return !!CanCopy() &&
-          !model()->user_input_in_progress() &&
-          toolbar_model()->WouldReplaceSearchURLWithSearchTerms(false);
+          controller()->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+              false);
     case IDC_PASTE:
       return !!CanPaste();
     case IDS_PASTE_AND_GO:
@@ -2797,9 +2796,13 @@
 
 void OmniboxViewWin::SelectAllIfNecessary(MouseButton button,
                                           const CPoint& point) {
-  // When the user has clicked and released to give us focus, select all.
+  // When the user has clicked and released to give us focus, select all unless
+  // we're doing search term replacement (in which case refining the existing
+  // query is common enough that we do click-to-place-cursor).
   if (tracking_click_[button] &&
-      !IsDrag(click_point_[button], point)) {
+      !IsDrag(click_point_[button], point) &&
+      !controller()->GetToolbarModel()->WouldReplaceSearchURLWithSearchTerms(
+          false)) {
     // Select all in the reverse direction so as not to scroll the caret
     // into view and shift the contents jarringly.
     SelectAll(true);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_win.h b/chrome/browser/ui/views/omnibox/omnibox_view_win.h
index 89a91b6..df1a239 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_win.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_win.h
@@ -59,7 +59,6 @@
   DECLARE_WND_SUPERCLASS(L"Chrome_OmniboxView", MSFTEDIT_CLASS);
 
   OmniboxViewWin(OmniboxEditController* controller,
-                 ToolbarModel* toolbar_model,
                  LocationBarView* parent_view,
                  CommandUpdater* command_updater,
                  bool popup_window_mode,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_views.cc b/chrome/browser/ui/views/omnibox/omnibox_views.cc
index 14bec61..fc9dc1f 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_views.cc
@@ -28,7 +28,6 @@
 }
 
 OmniboxView* CreateOmniboxView(OmniboxEditController* controller,
-                               ToolbarModel* toolbar_model,
                                Profile* profile,
                                CommandUpdater* command_updater,
                                bool popup_window_mode,
@@ -37,14 +36,13 @@
                                int font_y_offset) {
 #if defined(OS_WIN) && !defined(USE_AURA)
   if (!views::Textfield::IsViewsTextfieldEnabled()) {
-    return new OmniboxViewWin(
-        controller, toolbar_model, location_bar, command_updater,
-        popup_window_mode, font_list, font_y_offset);
+    return new OmniboxViewWin(controller, location_bar, command_updater,
+                              popup_window_mode, font_list, font_y_offset);
   }
 #endif
   OmniboxViewViews* omnibox = new OmniboxViewViews(
-      controller, toolbar_model, profile, command_updater, popup_window_mode,
-      location_bar, font_list, font_y_offset);
+      controller, profile, command_updater, popup_window_mode, location_bar,
+      font_list, font_y_offset);
   omnibox->Init();
   return omnibox;
 }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_views.h b/chrome/browser/ui/views/omnibox/omnibox_views.h
index 1cbc947..66c29f8 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_views.h
@@ -12,7 +12,6 @@
 class OmniboxViewViews;
 class OmniboxViewWin;
 class Profile;
-class ToolbarModel;
 
 namespace gfx {
 class FontList;
@@ -30,7 +29,6 @@
 
 // Creates an OmniboxView of the appropriate type; Views or Win.
 OmniboxView* CreateOmniboxView(OmniboxEditController* controller,
-                               ToolbarModel* toolbar_model,
                                Profile* profile,
                                CommandUpdater* command_updater,
                                bool popup_window_mode,
diff --git a/chrome/browser/ui/views/panels/panel_view.cc b/chrome/browser/ui/views/panels/panel_view.cc
index dfa8604..d122392 100644
--- a/chrome/browser/ui/views/panels/panel_view.cc
+++ b/chrome/browser/ui/views/panels/panel_view.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/panels/panel.h"
 #include "chrome/browser/ui/panels/panel_bounds_animation.h"
 #include "chrome/browser/ui/panels/panel_manager.h"
@@ -290,9 +291,8 @@
       ShellIntegration::GetAppModelIdForProfile(UTF8ToWide(panel->app_name()),
                                                 panel->profile()->GetPath()),
       views::HWNDForWidget(window_));
+  ui::win::PreventWindowFromPinning(views::HWNDForWidget(window_));
 #endif
-
-  views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
 }
 
 PanelView::~PanelView() {
@@ -436,8 +436,6 @@
     return;
   }
 
-  views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
-
   panel_->OnNativePanelClosed();
   if (window_)
     window_->Close();
@@ -947,10 +945,13 @@
   if (window_closed_)
     return;
 
-  // The panel window is in focus (actually accepting keystrokes) if it is
-  // active and belongs to a foreground application.
-  bool focused = active &&
-      views::HWNDForWidget(widget) == ::GetForegroundWindow();
+  bool focused = active;
+  if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_NATIVE) {
+    // The panel window is in focus (actually accepting keystrokes) if it is
+    // active and belongs to a foreground application.
+    focused = active &&
+        views::HWNDForWidget(widget) == ::GetForegroundWindow();
+  }
 #else
   NOTIMPLEMENTED();
   bool focused = active;
@@ -978,6 +979,13 @@
 #endif
 
   panel()->OnActiveStateChanged(focused);
+
+   // Give web contents view a chance to set focus to the appropriate element.
+  if (focused_) {
+    content::WebContents* web_contents = panel_->GetWebContents();
+    if (web_contents)
+      web_contents->GetView()->RestoreFocus();
+  }
 }
 
 void PanelView::OnWidgetBoundsChanged(views::Widget* widget,
@@ -986,17 +994,6 @@
     panel()->collection()->OnPanelResizedByMouse(panel(), new_bounds);
 }
 
-void PanelView::OnNativeFocusChange(gfx::NativeView focused_before,
-                                    gfx::NativeView focused_now) {
-  if (focused_now != window_->GetNativeView())
-    return;
-
-  // Give web contents view a chance to set focus to the appropriate element.
-  content::WebContents* web_contents = panel_->GetWebContents();
-  if (web_contents)
-    web_contents->GetView()->RestoreFocus();
-}
-
 bool PanelView::OnTitlebarMousePressed(const gfx::Point& mouse_location) {
   mouse_pressed_ = true;
   mouse_dragging_state_ = NO_DRAGGING;
diff --git a/chrome/browser/ui/views/panels/panel_view.h b/chrome/browser/ui/views/panels/panel_view.h
index 54c078c..93cc9fd 100644
--- a/chrome/browser/ui/views/panels/panel_view.h
+++ b/chrome/browser/ui/views/panels/panel_view.h
@@ -8,7 +8,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/panels/native_panel.h"
 #include "ui/base/animation/animation_delegate.h"
-#include "ui/views/focus/widget_focus_manager.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -28,7 +27,6 @@
 class PanelView : public NativePanel,
                   public views::WidgetObserver,
                   public views::WidgetDelegateView,
-                  public views::WidgetFocusChangeListener,
 #if defined(OS_WIN)
                   public ui::HWNDMessageFilter,
 #endif
@@ -151,10 +149,6 @@
   virtual void OnWidgetBoundsChanged(views::Widget* widget,
                                      const gfx::Rect& new_bounds) OVERRIDE;
 
-  // Overridden from views::WidgetFocusChangeListener:
-  virtual void OnNativeFocusChange(gfx::NativeView focused_before,
-                                   gfx::NativeView focused_now) OVERRIDE;
-
   // Overridden from ui::HWNDMessageFilter:
 #if defined(OS_WIN)
   virtual bool FilterMessage(HWND hwnd,
diff --git a/chrome/browser/ui/views/profile_chooser_view.cc b/chrome/browser/ui/views/profile_chooser_view.cc
index af7ee91..934e425 100644
--- a/chrome/browser/ui/views/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profile_chooser_view.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/common/url_constants.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/image/image.h"
@@ -156,7 +157,8 @@
       other_profiles.push_back(i);
     }
   }
-  DCHECK(current_profile_view_);
+  if (!current_profile_view_)  // Guest windows don't have an entry.
+    current_profile_view_ = CreateGuestProfileView();
 
   layout->StartRow(1, 0);
   layout->AddView(current_profile_view_);
@@ -198,12 +200,11 @@
   return view;
 }
 
-views::View* ProfileChooserView::CreateProfileCardView(size_t avatar_to_show) {
+views::View* ProfileChooserView::CreateProfileCardView(
+    const AvatarMenuModel::Item& avatar_item) {
   views::View* view = new views::View();
 
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  const AvatarMenuModel::Item& avatar_item =
-      avatar_menu_model_->GetItemAt(avatar_to_show);
 
   const int kLargeImageSide = 64;
   views::View* photo_image =
@@ -248,7 +249,8 @@
     size_t avatar_to_show) {
   views::View* view = new views::View();
 
-  views::View* card_view = CreateProfileCardView(avatar_to_show);
+  views::View* card_view = CreateProfileCardView(
+      avatar_menu_model_->GetItemAt(avatar_to_show));
 
   views::LabelButton* signout_button = new views::LabelButton(
       this,
@@ -275,6 +277,44 @@
   return view;
 }
 
+views::View* ProfileChooserView::CreateGuestProfileView() {
+  views::View* view = new views::View();
+
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+
+  gfx::Image guest_icon = rb.GetImageNamed(IDR_GUEST_ICON);
+  AvatarMenuModel::Item guest_avatar_item(0, guest_icon);
+  guest_avatar_item.active = true;
+  guest_avatar_item.name = l10n_util::GetStringUTF16(
+      IDS_PROFILES_PROFILE_GUEST_BUTTON);
+  guest_avatar_item.signed_in = false;
+
+  views::View* card_view = CreateProfileCardView(guest_avatar_item);
+  views::LabelButton* signout_button = new views::LabelButton(
+      this,
+      l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON));
+  signout_button->SetStyle(views::Button::STYLE_BUTTON);
+  DCHECK(!signout_current_profile_view_);
+  signout_current_profile_view_ = signout_button;
+
+  views::GridLayout* layout = new views::GridLayout(view);
+  view->SetLayoutManager(layout);
+
+  views::ColumnSet* columns = layout->AddColumnSet(0);
+  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
+                     views::GridLayout::USE_PREF, 0, 0);
+  columns->AddPaddingColumn(0, 30);
+  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 1,
+                     views::GridLayout::USE_PREF, 0, 0);
+  columns->AddPaddingColumn(0, 10);
+
+  layout->StartRow(1, 0);
+  layout->AddView(card_view, 1, 1);
+  layout->AddView(signout_button);
+
+  return view;
+}
+
 views::View* ProfileChooserView::CreateOtherProfilesView(
     const Indexes& avatars_to_show) {
   views::View* view = new views::View();
diff --git a/chrome/browser/ui/views/profile_chooser_view.h b/chrome/browser/ui/views/profile_chooser_view.h
index 25f15a0..38271d6 100644
--- a/chrome/browser/ui/views/profile_chooser_view.h
+++ b/chrome/browser/ui/views/profile_chooser_view.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <vector>
 
+#include "chrome/browser/profiles/avatar_menu_model.h"
 #include "chrome/browser/profiles/avatar_menu_model_observer.h"
 #include "ui/views/bubble/bubble_delegate.h"
 #include "ui/views/controls/button/button.h"
@@ -20,7 +21,6 @@
 class LabelButton;
 }
 
-class AvatarMenuModel;
 class Browser;
 class ProfileItemView;
 
@@ -82,8 +82,9 @@
   static bool close_on_deactivate_;
 
   views::View* CreateProfileImageView(const gfx::Image& icon, int side);
-  views::View* CreateProfileCardView(size_t avatar_to_show);
+  views::View* CreateProfileCardView(const AvatarMenuModel::Item& avatar_item);
   views::View* CreateCurrentProfileView(size_t avatars_to_show);
+  views::View* CreateGuestProfileView();
   views::View* CreateOtherProfilesView(const Indexes& avatars_to_show);
   views::View* CreateOptionsView();
 
diff --git a/chrome/browser/ui/views/select_file_dialog_extension.cc b/chrome/browser/ui/views/select_file_dialog_extension.cc
index e3324aa..362024a 100644
--- a/chrome/browser/ui/views/select_file_dialog_extension.cc
+++ b/chrome/browser/ui/views/select_file_dialog_extension.cc
@@ -13,8 +13,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_loop.h"
+#include "chrome/browser/chromeos/extensions/file_manager/app_id.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.h"
 #include "chrome/browser/chromeos/extensions/file_manager/file_manager_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/fileapi_util.h"
+#include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
@@ -332,11 +335,12 @@
   // an invalid temporal cache file path may passed as |default_dialog_path|
   // (crbug.com/178013 #9-#11). In such a case, we use the last selected
   // directory as a workaround. Real fix is tracked at crbug.com/110119.
+  using file_manager::kFileManagerAppId;
   if (default_dialog_path.IsAbsolute() &&
-      (file_manager::util::ConvertFileToRelativeFileSystemPath(
-           profile_, kFileBrowserDomain, default_dialog_path, &virtual_path) ||
-       file_manager::util::ConvertFileToRelativeFileSystemPath(
-           profile_, kFileBrowserDomain, fallback_path, &virtual_path))) {
+      (file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
+           profile_, kFileManagerAppId, default_dialog_path, &virtual_path) ||
+       file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
+           profile_, kFileManagerAppId, fallback_path, &virtual_path))) {
     virtual_path = base::FilePath("/").Append(virtual_path);
   } else {
     // If the path was relative, or failed to convert, just use the base name,
@@ -346,11 +350,12 @@
   has_multiple_file_type_choices_ =
       file_types ? file_types->extensions.size() > 1 : true;
 
-  GURL file_browser_url = file_manager::util::GetFileBrowserUrlWithParams(
-      type, title, virtual_path, file_types, file_type_index,
-      default_extension);
+  GURL file_manager_url =
+      file_manager::util::GetFileManagerMainPageUrlWithParams(
+          type, title, virtual_path, file_types, file_type_index,
+          default_extension);
 
-  ExtensionDialog* dialog = ExtensionDialog::Show(file_browser_url,
+  ExtensionDialog* dialog = ExtensionDialog::Show(file_manager_url,
       base_window, profile_, web_contents,
       kFileManagerWidth, kFileManagerHeight,
       kFileManagerWidth,
diff --git a/chrome/browser/ui/views/simple_message_box_views.cc b/chrome/browser/ui/views/simple_message_box_views.cc
index cc6211d..8d75c98 100644
--- a/chrome/browser/ui/views/simple_message_box_views.cc
+++ b/chrome/browser/ui/views/simple_message_box_views.cc
@@ -22,6 +22,9 @@
 #include "ui/aura/client/dispatcher_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
+#if defined(OS_WIN)
+#include "chrome/browser/ui/views/simple_message_box_win.h"
+#endif
 #endif
 
 namespace chrome {
@@ -174,6 +177,13 @@
                                 const string16& title,
                                 const string16& message,
                                 MessageBoxType type) {
+#if defined(USE_AURA) && defined(OS_WIN)
+  // If we're very early, we can't show a GPU-based dialog, so fallback to
+  // plain Windows MessageBox.
+  if (!ui::ContextFactory::GetInstance())
+    return NativeShowMessageBox(NULL, title, message, type);
+#endif
+
   scoped_refptr<SimpleMessageBoxViews> dialog(
       new SimpleMessageBoxViews(title, message, type));
   CreateBrowserModalDialogViews(dialog.get(), parent)->Show();
diff --git a/chrome/browser/ui/views/simple_message_box_win.cc b/chrome/browser/ui/views/simple_message_box_win.cc
index 167600c..70ab8a8 100644
--- a/chrome/browser/ui/views/simple_message_box_win.cc
+++ b/chrome/browser/ui/views/simple_message_box_win.cc
@@ -10,15 +10,10 @@
 
 namespace chrome {
 
-MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
-                                const string16& title,
-                                const string16& message,
-                                MessageBoxType type) {
-  startup_metric_utils::SetNonBrowserUIDisplayed();
-
-  if (!parent)
-    parent = ui::GetWindowToParentTo(true);
-
+MessageBoxResult NativeShowMessageBox(HWND parent,
+                                      const string16& title,
+                                      const string16& message,
+                                      MessageBoxType type) {
   UINT flags = MB_SETFOREGROUND;
   if (type == MESSAGE_BOX_TYPE_QUESTION) {
     flags |= MB_YESNO;
@@ -34,4 +29,18 @@
       MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO;
 }
 
+#if !defined(USE_AURA)
+MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
+                                const string16& title,
+                                const string16& message,
+                                MessageBoxType type) {
+  startup_metric_utils::SetNonBrowserUIDisplayed();
+
+  if (!parent)
+    parent = ui::GetWindowToParentTo(true);
+
+  return NativeShowMessageBox(parent, title, message, type);
+}
+#endif
+
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/simple_message_box_win.h b/chrome/browser/ui/views/simple_message_box_win.h
new file mode 100644
index 0000000..75dee4a
--- /dev/null
+++ b/chrome/browser/ui/views/simple_message_box_win.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 CHROME_BROWSER_UI_VIEWS_SIMPLE_MESSAGE_BOX_WIN_H_
+#define CHROME_BROWSER_UI_VIEWS_SIMPLE_MESSAGE_BOX_WIN_H_
+
+#include "chrome/browser/ui/simple_message_box.h"
+
+namespace chrome {
+
+MessageBoxResult NativeShowMessageBox(HWND parent,
+                                      const string16& title,
+                                      const string16& message,
+                                      MessageBoxType type);
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_UI_VIEWS_SIMPLE_MESSAGE_BOX_WIN_H_
diff --git a/chrome/browser/ui/views/ssl_client_certificate_selector.cc b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
index 4da3e79..d6805e5 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/certificate_viewer.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"
@@ -33,6 +34,7 @@
 using content::BrowserThread;
 using content::WebContents;
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 namespace {
 
@@ -144,11 +146,13 @@
 
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents_);
-  window_ = CreateWebContentsModalDialogViews(
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  DCHECK(modal_delegate);
+  window_ = views::Widget::CreateWindowAsFramelessChild(
       this,
       web_contents_->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
 
   // Select the first row automatically.  This must be done after the dialog has
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 7dd013e..7484f40 100644
--- a/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
+++ b/chrome/browser/ui/views/ssl_client_certificate_selector_browsertest.cc
@@ -35,7 +35,10 @@
 
 class SSLClientCertificateSelectorTest : public InProcessBrowserTest {
  public:
-  SSLClientCertificateSelectorTest() : io_loop_finished_event_(false, false) {
+  SSLClientCertificateSelectorTest()
+      : io_loop_finished_event_(false, false),
+        url_request_(NULL),
+        selector_(NULL) {
   }
 
   virtual void SetUpInProcessBrowserTestFixture() {
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win.cc b/chrome/browser/ui/views/status_icons/status_tray_win.cc
index 21a00d4..a1f5c66 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_win.cc
@@ -92,6 +92,12 @@
       }
     }
 
+    // It is possible for this procedure to be called with an obsolete icon
+    // id.  In that case we should just return early before handling any
+    // actions.
+    if (!win_icon)
+      return TRUE;
+
     switch (lparam) {
       case TB_INDETERMINATE:
         win_icon->HandleBalloonClickEvent();
diff --git a/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc b/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
index b021f8c..15ce2f8 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_win_unittest.cc
@@ -89,4 +89,18 @@
   EXPECT_TRUE(observer.balloon_clicked());
   icon->RemoveObserver(&observer);
 }
+
+TEST(StatusTrayWinTest, HandleOldIconId) {
+  StatusTrayWin tray;
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
+
+  StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon(
+      StatusTray::OTHER_ICON, *image, ASCIIToUTF16("tool tip")));
+  UINT message_id = icon->message_id();
+  UINT icon_id = icon->icon_id();
+
+  tray.RemoveStatusIcon(icon);
+  tray.WndProc(NULL, message_id, icon_id, WM_LBUTTONDOWN);
+}
 #endif  // !defined(USE_AURA)
diff --git a/chrome/browser/ui/views/sync/one_click_signin_bubble_view.cc b/chrome/browser/ui/views/sync/one_click_signin_bubble_view.cc
index 65cb45e..3e9efc6 100644
--- a/chrome/browser/ui/views/sync/one_click_signin_bubble_view.cc
+++ b/chrome/browser/ui/views/sync/one_click_signin_bubble_view.cc
@@ -208,8 +208,7 @@
     layout->StartRow(0, COLUMN_SET_TITLE_BAR);
 
     views::Label* label = new views::Label(
-        l10n_util::GetStringFUTF16(IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW,
-                                   email_));
+        l10n_util::GetStringUTF16(IDS_ONE_CLICK_SIGNIN_DIALOG_TITLE_NEW));
     label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     label->SetFont(label->font().DeriveFont(3, gfx::Font::BOLD));
     layout->AddView(label);
@@ -317,14 +316,15 @@
             one_click_signin::HISTOGRAM_CONFIRM_RETURN);
 
         base::ResetAndReturn(&start_sync_callback_).Run(
-          OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
+            OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS);
       } else if (accelerator.key_code() == ui::VKEY_ESCAPE) {
         OneClickSigninHelper::LogConfirmHistogramValue(
         clicked_learn_more_ ?
             one_click_signin::HISTOGRAM_CONFIRM_LEARN_MORE_ESCAPE :
             one_click_signin::HISTOGRAM_CONFIRM_ESCAPE);
 
-        start_sync_callback_.Reset();
+        base::ResetAndReturn(&start_sync_callback_).Run(
+            OneClickSigninSyncStarter::UNDO_SYNC);
       }
     }
 
@@ -355,7 +355,7 @@
             one_click_signin::HISTOGRAM_CONFIRM_ADVANCED);
 
       base::ResetAndReturn(&start_sync_callback_).Run(
-      OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
+          OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST);
     } else {
       delegate_->OnAdvancedLinkClicked();
     }
diff --git a/chrome/browser/ui/views/sync/one_click_signin_bubble_view_unittest.cc b/chrome/browser/ui/views/sync/one_click_signin_bubble_view_unittest.cc
index 24dddcd..ce46b65 100644
--- a/chrome/browser/ui/views/sync/one_click_signin_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/sync/one_click_signin_bubble_view_unittest.cc
@@ -323,5 +323,6 @@
   // fade animation of the bubble is done.
   content::RunAllPendingInMessageLoop();
   EXPECT_FALSE(OneClickSigninBubbleView::IsShowing());
-  EXPECT_FALSE(on_start_sync_called_);
+  EXPECT_TRUE(on_start_sync_called_);
+  EXPECT_EQ(OneClickSigninSyncStarter::UNDO_SYNC, mode_);
 }
diff --git a/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc b/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc
index 474235b..ab69052 100644
--- a/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc
+++ b/chrome/browser/ui/views/tab_contents/web_drag_bookmark_handler_win.cc
@@ -10,9 +10,9 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/url_constants.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/drop_data.h"
+#include "content/public/common/url_constants.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
 
@@ -94,7 +94,7 @@
 
 bool WebDragBookmarkHandlerWin::AddDragData(const content::DropData& drop_data,
                                             ui::OSExchangeData* data) {
-  if (!drop_data.url.SchemeIs(chrome::kJavaScriptScheme))
+  if (!drop_data.url.SchemeIs(content::kJavaScriptScheme))
     return false;
 
   // We don't want to allow javascript URLs to be dragged to the desktop,
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 56c0978..0c99fec 100644
--- a/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
+++ b/chrome/browser/ui/views/tab_modal_confirm_dialog_views.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "chrome/common/chrome_switches.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/web_contents.h"
@@ -24,6 +25,7 @@
 #include "ui/views/window/dialog_client_view.h"
 
 using web_modal::WebContentsModalDialogManager;
+using web_modal::WebContentsModalDialogManagerDelegate;
 
 // static
 TabModalConfirmDialog* TabModalConfirmDialog::Create(
@@ -53,11 +55,13 @@
 
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(web_contents);
-  dialog_ = CreateWebContentsModalDialogViews(
+  WebContentsModalDialogManagerDelegate* modal_delegate =
+      web_contents_modal_dialog_manager->delegate();
+  DCHECK(modal_delegate);
+  dialog_ = views::Widget::CreateWindowAsFramelessChild(
       this,
       web_contents->GetView()->GetNativeView(),
-      web_contents_modal_dialog_manager->delegate()->
-          GetWebContentsModalDialogHost());
+      modal_delegate->GetWebContentsModalDialogHost()->GetHostView());
   web_contents_modal_dialog_manager->ShowDialog(dialog_->GetNativeView());
   delegate_->set_close_delegate(this);
 }
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 9ba163c..ebb15ad 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -2006,15 +2006,46 @@
         point_in_screen,
         dock_windows_);
     dock_windows_.erase(dragged_native_view);
+    // Only bring browser windows to front - only windows with a TabStrip can
+    // be tab drag targets.
+    if (!GetTabStripForWindow(window))
+      return;
   }
   if (window) {
     views::Widget* widget_window = views::Widget::GetWidgetForNativeView(
         window);
-    if (widget_window)
-      widget_window->StackAtTop();
-    else
+    if (!widget_window)
       return;
 
+#if defined(USE_ASH)
+    // TODO(varkha): A better strategy would be for DragWindowController to
+    // be able to observe stacking changes to the phantom drag widget's
+    // siblings in order to keep it on top.
+    // One way is to implement a notification that is sent to a window parent's
+    // observers when a stacking order is changed among the children of that
+    // same parent. Note that OnWindowStackingChanged is sent only to the
+    // child that is the argument of one of the Window::StackChildX calls and
+    // not to all its siblings affected by the stacking change.
+    aura::Window* browser_window = widget_window->GetNativeView();
+    // Find a topmost non-popup window and stack the recipient browser window
+    // above it in order to avoid stacking the browser window on top of the
+    // phantom drag widget created by DragWindowController in a second display.
+    for (aura::Window::Windows::const_reverse_iterator it =
+         browser_window->parent()->children().rbegin();
+         it != browser_window->parent()->children().rend(); ++it) {
+      // If the iteration reached the recipient browser window then it is
+      // already topmost and it is safe to return early with no stacking change.
+      if (*it == browser_window)
+        return;
+      if ((*it)->type() != aura::client::WINDOW_TYPE_POPUP) {
+        widget_window->StackAbove(*it);
+        break;
+      }
+    }
+#else
+    widget_window->StackAtTop();
+#endif
+
     // The previous call made the window appear on top of the dragged window,
     // move the dragged window to the front.
     if (view_.get())
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index a99257d..321fe2c 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -843,14 +843,10 @@
     }
   }
 
-  ui::ListSelectionModel::SelectedIndices no_longer_selected;
-  std::insert_iterator<ui::ListSelectionModel::SelectedIndices>
-      it(no_longer_selected, no_longer_selected.begin());
-  std::set_difference(old_selection.selected_indices().begin(),
-                      old_selection.selected_indices().end(),
-                      new_selection.selected_indices().begin(),
-                      new_selection.selected_indices().end(),
-                      it);
+  ui::ListSelectionModel::SelectedIndices no_longer_selected =
+      base::STLSetDifference<ui::ListSelectionModel::SelectedIndices>(
+          old_selection.selected_indices(),
+          new_selection.selected_indices());
   for (size_t i = 0; i < no_longer_selected.size(); ++i)
     tab_at(no_longer_selected[i])->StopMiniTabTitleAnimation();
 }
diff --git a/chrome/browser/ui/views/toolbar_view.cc b/chrome/browser/ui/views/toolbar_view.cc
index 9fee7cf..3a3bb1b 100644
--- a/chrome/browser/ui/views/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar_view.cc
@@ -115,8 +115,7 @@
 // ToolbarView, public:
 
 ToolbarView::ToolbarView(Browser* browser)
-    : model_(browser->toolbar_model()),
-      back_(NULL),
+    : back_(NULL),
       forward_(NULL),
       reload_(NULL),
       home_(NULL),
@@ -187,7 +186,7 @@
   // Have to create this before |reload_| as |reload_|'s constructor needs it.
   location_bar_ = new LocationBarView(
       browser_, browser_->profile(),
-      browser_->command_controller()->command_updater(), model_, this,
+      browser_->command_controller()->command_updater(), this,
       display_mode_ == DISPLAYMODE_LOCATION);
 
   reload_ = new ReloadButton(location_bar_,
@@ -250,9 +249,9 @@
   }
 }
 
-void ToolbarView::Update(WebContents* tab, bool should_restore_state) {
+void ToolbarView::Update(WebContents* tab) {
   if (location_bar_)
-    location_bar_->Update(should_restore_state ? tab : NULL);
+    location_bar_->Update(tab);
 
   if (browser_actions_)
     browser_actions_->RefreshBrowserActionViews();
@@ -344,10 +343,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ToolbarView, LocationBarView::Delegate implementation:
 
-WebContents* ToolbarView::GetWebContents() const {
+WebContents* ToolbarView::GetWebContents() {
   return browser_->tab_strip_model()->GetActiveWebContents();
 }
 
+ToolbarModel* ToolbarView::GetToolbarModel() {
+  return browser_->toolbar_model();
+}
+
+const ToolbarModel* ToolbarView::GetToolbarModel() const {
+  return browser_->toolbar_model();
+}
+
 InstantController* ToolbarView::GetInstant() {
   return browser_->instant_controller() ?
       browser_->instant_controller()->instant() : NULL;
@@ -376,9 +383,9 @@
 
 void ToolbarView::OnInputInProgress(bool in_progress) {
   // The edit should make sure we're only notified when something changes.
-  DCHECK(model_->GetInputInProgress() != in_progress);
+  DCHECK_NE(GetToolbarModel()->input_in_progress(), in_progress);
 
-  model_->SetInputInProgress(in_progress);
+  GetToolbarModel()->set_input_in_progress(in_progress);
   location_bar_->Update(NULL);
 }
 
diff --git a/chrome/browser/ui/views/toolbar_view.h b/chrome/browser/ui/views/toolbar_view.h
index 7f72778..9bf3cc4 100644
--- a/chrome/browser/ui/views/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar_view.h
@@ -52,11 +52,11 @@
   // Create the contents of the Browser Toolbar.
   void Init();
 
-  // Updates the toolbar (and transitively the location bar) with the states of
-  // the specified |tab|.  If |should_restore_state| is true, we're switching
-  // (back?) to this tab and should restore any previous location bar state
-  // (such as user editing) as well.
-  void Update(content::WebContents* tab, bool should_restore_state);
+  // Forces the toolbar (and transitively the location bar) to update its
+  // current state.  If |tab| is non-NULL, we're switching (back?) to this tab
+  // and should restore any previous location bar state (such as user editing)
+  // as well.
+  void Update(content::WebContents* tab);
 
   // Set focus to the toolbar with complete keyboard access, with the
   // focus initially set to the app menu. Focus will be restored
@@ -93,7 +93,9 @@
                                    const gfx::Point& point) OVERRIDE;
 
   // Overridden from LocationBarView::Delegate:
-  virtual content::WebContents* GetWebContents() const OVERRIDE;
+  virtual content::WebContents* GetWebContents() OVERRIDE;
+  virtual ToolbarModel* GetToolbarModel() OVERRIDE;
+  virtual const ToolbarModel* GetToolbarModel() const OVERRIDE;
   virtual InstantController* GetInstant() OVERRIDE;
   virtual views::Widget* CreateViewsBubble(
       views::BubbleDelegateView* bubble_delegate) OVERRIDE;
@@ -195,9 +197,6 @@
 
   int content_shadow_height() const;
 
-  // The model that contains the security level, text, icon to display...
-  ToolbarModel* model_;
-
   // Controls
   views::ImageButton* back_;
   views::ImageButton* forward_;
diff --git a/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc b/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc
index 9b82e77..9798a64 100644
--- a/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc
+++ b/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc
@@ -8,12 +8,17 @@
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/views/constrained_window_views.h"
 #include "components/web_modal/native_web_contents_modal_dialog_manager.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/web_contents_view.h"
+#include "ui/gfx/point.h"
+#include "ui/gfx/size.h"
+#include "ui/views/border.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/widget/widget_observer.h"
 #include "ui/views/window/dialog_delegate.h"
+#include "ui/views/window/non_client_view.h"
 
 #if defined(USE_AURA)
 #include "ui/aura/client/aura_constants.h"
@@ -33,11 +38,14 @@
 using web_modal::NativeWebContentsModalDialog;
 using web_modal::NativeWebContentsModalDialogManager;
 using web_modal::NativeWebContentsModalDialogManagerDelegate;
+using web_modal::WebContentsModalDialogHost;
+using web_modal::WebContentsModalDialogHostObserver;
 
 namespace {
 
 class NativeWebContentsModalDialogManagerViews
     : public NativeWebContentsModalDialogManager,
+      public WebContentsModalDialogHostObserver,
       public views::WidgetObserver
 #if defined(USE_AURA)
       , public aura::WindowObserver
@@ -46,7 +54,8 @@
  public:
   NativeWebContentsModalDialogManagerViews(
       NativeWebContentsModalDialogManagerDelegate* native_delegate)
-      : native_delegate_(native_delegate) {
+      : native_delegate_(native_delegate),
+        host_(NULL) {
 #if defined(USE_AURA)
     native_delegate_->GetWebContents()->GetView()->GetNativeView()->
         AddObserver(this);
@@ -54,6 +63,9 @@
   }
 
   virtual ~NativeWebContentsModalDialogManagerViews() {
+    if (host_)
+      host_->RemoveObserver(this);
+
     for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
          it != observed_widgets_.end();
          ++it) {
@@ -107,15 +119,16 @@
           widget->GetNativeWindow()->parent()));
     }
 #endif
+    // Host may be NULL during tab drag on Views/Win32.
+    if (host_)
+      UpdateWebContentsModalDialogPosition(widget, host_);
     widget->Show();
     FocusDialog(dialog);
-#if defined(USE_AURA)
-    if (views::DialogDelegate::UseNewStyle()) {
-      widget->GetNativeWindow()->parent()->StackChildAbove(
-          widget->GetNativeWindow(),
-          native_delegate_->GetWebContents()->GetView()->GetNativeView());
-    }
 
+#if defined(USE_AURA)
+    // TODO(pkotwicz): Control the z-order of the constrained dialog via
+    // views::kHostViewKey. We will need to ensure that the parent window's
+    // shadows are below the constrained dialog in z-order when we do this.
     shown_widgets_.insert(widget);
 #endif
   }
@@ -151,6 +164,22 @@
   virtual void PulseDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
   }
 
+  // WebContentsModalDialogHostObserver overrides
+  virtual void OnPositionRequiresUpdate() OVERRIDE {
+    DCHECK(host_);
+
+    for (std::set<views::Widget*>::iterator it = observed_widgets_.begin();
+         it != observed_widgets_.end();
+         ++it) {
+      UpdateWebContentsModalDialogPosition(*it, host_);
+    }
+  }
+
+  virtual void OnHostDestroying() OVERRIDE {
+    host_->RemoveObserver(this);
+    host_ = NULL;
+  }
+
   // views::WidgetObserver overrides
 
   // NOTE(wittman): OnWidgetClosing is overriden to ensure that, when the widget
@@ -169,6 +198,18 @@
     WidgetClosing(widget);
   }
 
+  virtual void HostChanged(
+      web_modal::WebContentsModalDialogHost* new_host) OVERRIDE {
+    if (host_)
+      host_->RemoveObserver(this);
+
+    host_ = new_host;
+
+    if (host_) {
+      host_->AddObserver(this);
+    }
+  }
+
  private:
 #if defined(USE_AURA)
   // aura::WindowObserver overrides
@@ -190,6 +231,10 @@
           (*it)->GetFocusManager()->ViewRemoved((*it)->GetRootView());
         params.new_parent->AddChild((*it)->GetNativeWindow());
       }
+
+      // Host may be null when destroying the WebContents.
+      if (host_)
+        OnPositionRequiresUpdate();
     }
   }
 #endif
@@ -216,6 +261,7 @@
   }
 
   NativeWebContentsModalDialogManagerDelegate* native_delegate_;
+  WebContentsModalDialogHost* host_;
   std::set<views::Widget*> observed_widgets_;
   std::set<views::Widget*> shown_widgets_;
 
diff --git a/chrome/browser/ui/views/wrench_menu.cc b/chrome/browser/ui/views/wrench_menu.cc
index 53daa47..05f3811 100644
--- a/chrome/browser/ui/views/wrench_menu.cc
+++ b/chrome/browser/ui/views/wrench_menu.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_delegate.h"
+#include "chrome/browser/ui/views/wrench_menu_observer.h"
 #include "content/public/browser/host_zoom_map.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -320,11 +321,19 @@
 
 // WrenchMenuView is a view that can contain label buttons.
 class WrenchMenuView : public views::View,
-                       public views::ButtonListener {
+                       public views::ButtonListener,
+                       public WrenchMenuObserver {
  public:
   WrenchMenuView(WrenchMenu* menu, MenuModel* menu_model)
       : menu_(menu),
-        menu_model_(menu_model) {}
+        menu_model_(menu_model) {
+    menu_->AddObserver(this);
+  }
+
+  virtual ~WrenchMenuView() {
+    if (menu_)
+      menu_->RemoveObserver(this);
+  }
 
   // Overridden from views::View.
   virtual void SchedulePaintInRect(const gfx::Rect& r) OVERRIDE {
@@ -348,6 +357,8 @@
                                        int index,
                                        MenuButtonBackground** background,
                                        int acc_string_id) {
+    // Should only be invoked during construction when |menu_| is valid.
+    DCHECK(menu_);
     LabelButton* button = new LabelButton(this, gfx::RemoveAcceleratorChar(
         l10n_util::GetStringUTF16(string_id), '&', NULL, NULL));
     button->SetAccessibleName(
@@ -371,14 +382,26 @@
     return button;
   }
 
+  // Overridden from WrenchMenuObserver:
+  virtual void WrenchMenuDestroyed() OVERRIDE {
+    menu_->RemoveObserver(this);
+    menu_ = NULL;
+    menu_model_ = NULL;
+  }
+
  protected:
+  WrenchMenu* menu() { return menu_; }
+  MenuModel* menu_model() { return menu_model_; }
+
+ private:
   // Hosting WrenchMenu.
+  // WARNING: this may be NULL during shutdown.
   WrenchMenu* menu_;
 
   // The menu model containing the increment/decrement/reset items.
+  // WARNING: this may be NULL during shutdown.
   MenuModel* menu_model_;
 
- private:
   DISALLOW_COPY_AND_ASSIGN(WrenchMenuView);
 };
 
@@ -433,12 +456,12 @@
 
     LabelButton* paste = CreateAndConfigureButton(
         IDS_PASTE,
-        menu_->use_new_menu() && menu_->supports_new_separators_ ?
+        menu->use_new_menu() && menu->supports_new_separators_ ?
             MenuButtonBackground::CENTER_BUTTON :
             MenuButtonBackground::RIGHT_BUTTON,
         paste_index,
         NULL);
-    if (menu_->use_new_menu()) {
+    if (menu->use_new_menu()) {
       cut->SetTextColor(views::Button::STATE_NORMAL, kTouchButtonText);
       copy->SetTextColor(views::Button::STATE_NORMAL, kTouchButtonText);
       paste->SetTextColor(views::Button::STATE_NORMAL, kTouchButtonText);
@@ -469,7 +492,7 @@
   // Overridden from ButtonListener.
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE {
-    menu_->CancelAndEvaluate(menu_model_, sender->tag());
+    menu()->CancelAndEvaluate(menu_model(), sender->tag());
   }
 
  private:
@@ -511,8 +534,7 @@
         fullscreen_button_(NULL),
         zoom_label_width_(0) {
     HostZoomMap::GetForBrowserContext(
-        menu_->browser_->profile())->AddZoomLevelChangedCallback(
-            zoom_callback_);
+        menu->browser_->profile())->AddZoomLevelChangedCallback(zoom_callback_);
 
     decrement_button_ = CreateButtonWithAccName(
         IDS_ZOOM_MINUS2, MenuButtonBackground::LEFT_BUTTON, decrement_index,
@@ -524,10 +546,10 @@
     zoom_label_->SetHorizontalAlignment(gfx::ALIGN_RIGHT);
 
     MenuButtonBackground* center_bg = new MenuButtonBackground(
-        menu_->use_new_menu() && menu_->supports_new_separators_ ?
+        menu->use_new_menu() && menu->supports_new_separators_ ?
             MenuButtonBackground::RIGHT_BUTTON :
             MenuButtonBackground::CENTER_BUTTON,
-        menu_->use_new_menu());
+        menu->use_new_menu());
     zoom_label_->set_background(center_bg);
     const MenuConfig& menu_config(menu->GetMenuConfig());
     zoom_label_->set_border(
@@ -548,7 +570,7 @@
         ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
             IDR_FULLSCREEN_MENU_BUTTON);
     fullscreen_button_->SetImage(ImageButton::STATE_NORMAL, full_screen_image);
-    if (menu_->use_new_menu()) {
+    if (menu->use_new_menu()) {
       zoom_label_->SetEnabledColor(kTouchButtonText);
       decrement_button_->SetTextColor(views::Button::STATE_NORMAL,
                                       kTouchButtonText);
@@ -576,12 +598,12 @@
     fullscreen_button_->SetImageAlignment(
         ImageButton::ALIGN_CENTER, ImageButton::ALIGN_MIDDLE);
     int horizontal_padding =
-        menu_->use_new_menu() ? kHorizontalTouchPadding : kHorizontalPadding;
+        menu->use_new_menu() ? kHorizontalTouchPadding : kHorizontalPadding;
     fullscreen_button_->set_border(views::Border::CreateEmptyBorder(
         0, horizontal_padding, 0, horizontal_padding));
     fullscreen_button_->set_background(
         new MenuButtonBackground(MenuButtonBackground::SINGLE_BUTTON,
-                                 menu_->use_new_menu()));
+                                 menu->use_new_menu()));
     fullscreen_button_->SetAccessibleName(
         GetAccessibleNameForWrenchMenuItem(
             menu_model, fullscreen_index, IDS_ACCNAME_FULLSCREEN));
@@ -591,9 +613,7 @@
   }
 
   virtual ~ZoomView() {
-    HostZoomMap::GetForBrowserContext(
-        menu_->browser_->profile())->RemoveZoomLevelChangedCallback(
-            zoom_callback_);
+    Shutdown();
   }
 
   // Overridden from View.
@@ -601,7 +621,8 @@
     // The increment/decrement button are forced to the same width.
     int button_width = std::max(increment_button_->GetPreferredSize().width(),
                                 decrement_button_->GetPreferredSize().width());
-    int zoom_padding = menu_->use_new_menu() ? kTouchZoomPadding : kZoomPadding;
+    int zoom_padding = menu()->use_new_menu() ?
+        kTouchZoomPadding : kZoomPadding;
     int fullscreen_width = fullscreen_button_->GetPreferredSize().width() +
                            zoom_padding;
     // Returned height doesn't matter as MenuItemView forces everything to the
@@ -629,10 +650,10 @@
     bounds.set_width(button_width);
     increment_button_->SetBoundsRect(bounds);
 
-    x += bounds.width() + (menu_->use_new_menu() ? 0 : kZoomPadding);
+    x += bounds.width() + (menu()->use_new_menu() ? 0 : kZoomPadding);
     bounds.set_x(x);
     bounds.set_width(fullscreen_button_->GetPreferredSize().width() +
-                     (menu_->use_new_menu() ? kTouchZoomPadding : 0));
+                     (menu()->use_new_menu() ? kTouchZoomPadding : 0));
     fullscreen_button_->SetBoundsRect(bounds);
   }
 
@@ -640,14 +661,30 @@
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE {
     if (sender->tag() == fullscreen_index_) {
-      menu_->CancelAndEvaluate(menu_model_, sender->tag());
+      menu()->CancelAndEvaluate(menu_model(), sender->tag());
     } else {
       // Zoom buttons don't close the menu.
-      menu_model_->ActivatedAt(sender->tag());
+      menu_model()->ActivatedAt(sender->tag());
     }
   }
 
+  // Overridden from WrenchMenuObserver.
+  virtual void WrenchMenuDestroyed() OVERRIDE {
+    Shutdown();
+    WrenchMenuView::WrenchMenuDestroyed();
+  }
+
  private:
+  // Invoked from the destructor or when the WrenchMenu is destroyed.
+  void Shutdown() {
+    if (!menu())
+      return;
+
+    HostZoomMap::GetForBrowserContext(
+        menu()->browser_->profile())->RemoveZoomLevelChangedCallback(
+            zoom_callback_);
+  }
+
   void OnZoomLevelChanged(const HostZoomMap::ZoomLevelChange& change) {
     UpdateZoomControls();
   }
@@ -656,7 +693,7 @@
     bool enable_increment = false;
     bool enable_decrement = false;
     WebContents* selected_tab =
-        menu_->browser_->tab_strip_model()->GetActiveWebContents();
+        menu()->browser_->tab_strip_model()->GetActiveWebContents();
     int zoom = 100;
     if (selected_tab)
       zoom = selected_tab->GetZoomPercent(&enable_increment, &enable_decrement);
@@ -677,7 +714,7 @@
     int max_w = 0;
 
     WebContents* selected_tab =
-        menu_->browser_->tab_strip_model()->GetActiveWebContents();
+        menu()->browser_->tab_strip_model()->GetActiveWebContents();
     if (selected_tab) {
       int min_percent = selected_tab->GetMinimumZoomPercent();
       int max_percent = selected_tab->GetMaximumZoomPercent();
@@ -811,6 +848,7 @@
     if (model)
       model->RemoveObserver(this);
   }
+  FOR_EACH_OBSERVER(WrenchMenuObserver, observer_list_, WrenchMenuDestroyed());
 }
 
 void WrenchMenu::Init(ui::MenuModel* model) {
@@ -859,6 +897,14 @@
   return MenuConfig::instance(GetNativeTheme());
 }
 
+void WrenchMenu::AddObserver(WrenchMenuObserver* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void WrenchMenu::RemoveObserver(WrenchMenuObserver* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
 const gfx::Font* WrenchMenu::GetLabelFont(int index) const {
   if (is_recent_tabs_command(index)) {
     return recent_tabs_menu_model_delegate_->GetLabelFontAt(
diff --git a/chrome/browser/ui/views/wrench_menu.h b/chrome/browser/ui/views/wrench_menu.h
index dd857c1..44613be 100644
--- a/chrome/browser/ui/views/wrench_menu.h
+++ b/chrome/browser/ui/views/wrench_menu.h
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
 #include "chrome/browser/bookmarks/base_bookmark_model_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -17,6 +18,7 @@
 
 class BookmarkMenuDelegate;
 class Browser;
+class WrenchMenuObserver;
 
 namespace ui {
 class NativeTheme;
@@ -53,6 +55,9 @@
 
   bool use_new_menu() const { return use_new_menu_; }
 
+  void AddObserver(WrenchMenuObserver* observer);
+  void RemoveObserver(WrenchMenuObserver* observer);
+
   // MenuDelegate overrides:
   virtual const gfx::Font* GetLabelFont(int index) const OVERRIDE;
   virtual bool GetForegroundColor(int command_id,
@@ -190,6 +195,8 @@
 
   const bool supports_new_separators_;
 
+  ObserverList<WrenchMenuObserver> observer_list_;
+
   DISALLOW_COPY_AND_ASSIGN(WrenchMenu);
 };
 
diff --git a/chrome/browser/ui/views/wrench_menu_observer.h b/chrome/browser/ui/views/wrench_menu_observer.h
new file mode 100644
index 0000000..eccee38
--- /dev/null
+++ b/chrome/browser/ui/views/wrench_menu_observer.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_WRENCH_MENU_OBSERVER_H_
+#define CHROME_BROWSER_UI_VIEWS_WRENCH_MENU_OBSERVER_H_
+
+class WrenchMenuObserver {
+ public:
+  // Invoked when the WrenchMenu is about to be destroyed (from its destructor).
+  virtual void WrenchMenuDestroyed() = 0;
+
+ protected:
+  virtual ~WrenchMenuObserver() {}
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_WRENCH_MENU_OBSERVER_H_
diff --git a/chrome/browser/ui/views/wrench_toolbar_button.cc b/chrome/browser/ui/views/wrench_toolbar_button.cc
index 82aec7e..b143a9f 100644
--- a/chrome/browser/ui/views/wrench_toolbar_button.cc
+++ b/chrome/browser/ui/views/wrench_toolbar_button.cc
@@ -27,9 +27,9 @@
 
 void WrenchToolbarButton::OnPaint(gfx::Canvas* canvas) {
   // Badge non-ChromeOS ASH builds so that users know that they are using ASH.
-#if defined(USE_ASH) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
   wrench_icon_painter_->set_badge(
-      *GetThemeProvider()->GetImageSkiaNamed(IDR_TOOLS_BADGE_ASH));
+      *GetThemeProvider()->GetImageSkiaNamed(IDR_TOOLS_BADGE_AURA));
 #endif
 
   wrench_icon_painter_->Paint(
diff --git a/chrome/browser/ui/website_settings/website_settings_ui.cc b/chrome/browser/ui/website_settings/website_settings_ui.cc
index 9bb47a3..6c76411 100644
--- a/chrome/browser/ui/website_settings/website_settings_ui.cc
+++ b/chrome/browser/ui/website_settings/website_settings_ui.cc
@@ -230,6 +230,8 @@
       resource_id = use_blocked ? IDR_BLOCKED_MIDI_SYSEX
                                 : IDR_ALLOWED_MIDI_SYSEX;
       break;
+    case CONTENT_SETTINGS_TYPE_SAVE_PASSWORD:
+      resource_id = IDR_SAVE_PASSWORD;
     default:
       NOTREACHED();
       break;
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc
index 4d23d50..febc1f1 100644
--- a/chrome/browser/ui/webui/about_ui.cc
+++ b/chrome/browser/ui/webui/about_ui.cc
@@ -80,15 +80,9 @@
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chromeos/customization_document.h"
 #include "chrome/browser/chromeos/memory/oom_priority_manager.h"
-#include "chrome/browser/ui/webui/chromeos/about_network.h"
 #include "chromeos/chromeos_switches.h"
 #endif
 
-#if defined(USE_ASH)
-#include "ash/wm/frame_painter.h"
-#include "base/strings/string_split.h"
-#endif
-
 using base::Time;
 using base::TimeDelta;
 using content::BrowserThread;
@@ -521,102 +515,6 @@
 
 #endif  // OS_CHROMEOS
 
-#if defined(USE_ASH)
-
-// Adds an entry to the chrome://transparency page, with the format:
-// |label|:
-// -- - |value|% + ++
-// where --, -, +, and ++ are links to change the appropriate |key|.
-// TODO(jamescook): Remove this temporary tool when we decide what the window
-// header opacity should be for Ash.
-std::string TransparencyLink(const std::string& label,
-                             int value,
-                             const std::string& key) {
-  return base::StringPrintf("<p>%s</p>"
-      "<p>"
-      "<a href='%s%s=%d'>--</a> "
-      "<a href='%s%s=%d'>-</a> "
-      "%d%% "
-      "<a href='%s%s=%d'>+</a> "
-      "<a href='%s%s=%d'>++</a>"
-      "</p>",
-      label.c_str(),
-      chrome::kChromeUITransparencyURL, key.c_str(), value - 5,
-      chrome::kChromeUITransparencyURL, key.c_str(), value - 1,
-      value,
-      chrome::kChromeUITransparencyURL, key.c_str(), value + 1,
-      chrome::kChromeUITransparencyURL, key.c_str(), value + 5);
-}
-
-// Returns a transparency percent from an opacity value.
-int TransparencyFromOpacity(int opacity) {
-  return (255 - opacity) * 100 / 255;
-}
-
-// Displays a tweaking page for window header transparency, as we're iterating
-// rapidly on how transparent we want the headers to be.
-// TODO(jamescook): Remove this temporary tool when we decide what the window
-// header opacity should be for Ash.
-std::string AboutTransparency(const std::string& path) {
-  const char kActive[] = "active";
-  const char kInactive[] = "inactive";
-  const char kSolo[] = "solo";
-  // Apply transparency based on a path like "active=10&inactive=25".
-  std::vector<std::pair<std::string, std::string> > kv_pairs;
-  if (!path.empty() &&
-      base::SplitStringIntoKeyValuePairs(path, '=', '&', &kv_pairs)) {
-    for (std::vector<std::pair<std::string, std::string> >::const_iterator it =
-            kv_pairs.begin();
-         it != kv_pairs.end();
-         ++it) {
-      int* opacity = NULL;
-      if (it->first == kActive)
-        opacity = &ash::FramePainter::kActiveWindowOpacity;
-      else if (it->first == kInactive)
-        opacity = &ash::FramePainter::kInactiveWindowOpacity;
-      else if (it->first == kSolo)
-        opacity = &ash::FramePainter::kSoloWindowOpacity;
-      if (opacity) {
-        int transparent = 0;
-        base::StringToInt(it->second, &transparent);
-        transparent = std::max(0, std::min(100, transparent));
-        *opacity = (100 - transparent) * 255 / 100;
-      }
-    }
-  }
-
-  // Display current settings.  Do everything in transparency-percent instead of
-  // opacity-value.
-  std::string output;
-  AppendHeader(&output, 0, "About transparency");
-  AppendFooter(&output);
-  AppendBody(&output);
-  output.append("<h3>Window header transparency</h3>");
-  output.append(TransparencyLink("Active window:",
-      TransparencyFromOpacity(ash::FramePainter::kActiveWindowOpacity),
-      kActive));
-  output.append(TransparencyLink("Inactive window:",
-      TransparencyFromOpacity(ash::FramePainter::kInactiveWindowOpacity),
-      kInactive));
-  output.append(TransparencyLink("Solo window:",
-      TransparencyFromOpacity(ash::FramePainter::kSoloWindowOpacity),
-      kSolo));
-  output.append(base::StringPrintf(
-      "<p>Share: %s%s=%d&%s=%d&%s=%d</p>",
-      chrome::kChromeUITransparencyURL,
-      kActive,
-      TransparencyFromOpacity(ash::FramePainter::kActiveWindowOpacity),
-      kInactive,
-      TransparencyFromOpacity(ash::FramePainter::kInactiveWindowOpacity),
-      kSolo,
-      TransparencyFromOpacity(ash::FramePainter::kSoloWindowOpacity)));
-  output.append("<p>Reshape window to force a redraw.</p>");
-  AppendFooter(&output);
-  return output;
-}
-
-#endif  // USE_ASH
-
 // AboutDnsHandler bounces the request back to the IO thread to collect
 // the DNS information.
 class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> {
@@ -1111,10 +1009,6 @@
   } else if (source_name_ == chrome::kChromeUIDiscardsHost) {
     response = AboutDiscards(path);
 #endif
-#if defined(USE_ASH)
-  } else if (source_name_ == chrome::kChromeUITransparencyHost) {
-    response = AboutTransparency(path);
-#endif
   } else if (source_name_ == chrome::kChromeUIDNSHost) {
     AboutDnsHandler::Start(profile(), callback);
     return;
@@ -1128,8 +1022,6 @@
     FinishMemoryDataRequest(path, callback);
     return;
 #if defined(OS_CHROMEOS)
-  } else if (source_name_ == chrome::kChromeUINetworkHost) {
-    response = chromeos::about_ui::AboutNetwork(path);
   } else if (source_name_ == chrome::kChromeUIOSCreditsHost) {
     response = ResourceBundle::GetSharedInstance().GetRawDataResource(
         IDR_OS_CREDITS_HTML).as_string();
diff --git a/chrome/browser/ui/webui/app_launcher_page_ui.cc b/chrome/browser/ui/webui/app_launcher_page_ui.cc
index f029494..c1fb8ae 100644
--- a/chrome/browser/ui/webui/app_launcher_page_ui.cc
+++ b/chrome/browser/ui/webui/app_launcher_page_ui.cc
@@ -110,9 +110,10 @@
 
   content::RenderProcessHost* render_host =
       content::RenderProcessHost::FromID(render_process_id);
-  bool is_incognito = render_host->GetBrowserContext()->IsOffTheRecord();
+  NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType(
+      profile_, render_host);
   scoped_refptr<base::RefCountedMemory> html_bytes(
-      resource->GetNewTabHTML(is_incognito));
+      resource->GetNewTabHTML(win_type));
 
   callback.Run(html_bytes.get());
 }
diff --git a/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc b/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc
index 5c0ef3a..17055fb 100644
--- a/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc
+++ b/chrome/browser/ui/webui/bidi_checker_web_ui_test.cc
@@ -156,8 +156,8 @@
 //==============================
 
 static void SetupHistoryPageTest(Browser* browser,
-                                 const std::string page_url,
-                                 const std::string page_title) {
+                                 const std::string& page_url,
+                                 const std::string& page_title) {
   HistoryService* history_service = HistoryServiceFactory::GetForProfile(
       browser->profile(), Profile::IMPLICIT_ACCESS);
   const GURL history_url = GURL(page_url);
@@ -193,27 +193,6 @@
 }
 
 //==============================
-// chrome://bugreport
-//==============================
-
-IN_PROC_BROWSER_TEST_F(WebUIBidiCheckerBrowserTestLTR, TestFeedbackPage) {
-  // The bugreport page receives its contents as GET arguments. Here we provide
-  // a custom, Hebrew typed, description message.
-  RunBidiCheckerOnPage(
-      "chrome://feedback?session_id=1&tab_index=0&description=%D7%91%D7%93%D7%99%D7%A7%D7%94");
-}
-
-// Test disabled because it is flaky (http://crbug.com/134434)
-#if defined(OS_CHROMEOS)
-#define MAYBE_TestFeedbackPage DISABLED_TestFeedbackPage
-#else
-#define MAYBE_TestFeedbackPage TestFeedbackPage
-#endif
-IN_PROC_BROWSER_TEST_F(WebUIBidiCheckerBrowserTestRTL, MAYBE_TestFeedbackPage) {
-  RunBidiCheckerOnPage("chrome://feedback?session_id=1&tab_index=0&description=test");
-}
-
-//==============================
 // chrome://crashes
 //==============================
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index c9ea885..a80d332 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -18,13 +18,13 @@
 #include "chrome/browser/ui/webui/about_ui.h"
 #include "chrome/browser/ui/webui/app_launcher_page_ui.h"
 #include "chrome/browser/ui/webui/bookmarks_ui.h"
+#include "chrome/browser/ui/webui/components_ui.h"
 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
 #include "chrome/browser/ui/webui/crashes_ui.h"
 #include "chrome/browser/ui/webui/devtools_ui.h"
 #include "chrome/browser/ui/webui/downloads_ui.h"
 #include "chrome/browser/ui/webui/extensions/extension_info_ui.h"
 #include "chrome/browser/ui/webui/extensions/extensions_ui.h"
-#include "chrome/browser/ui/webui/feedback_ui.h"
 #include "chrome/browser/ui/webui/flags_ui.h"
 #include "chrome/browser/ui/webui/flash_ui.h"
 #include "chrome/browser/ui/webui/help/help_ui.h"
@@ -33,7 +33,6 @@
 #include "chrome/browser/ui/webui/inline_login_ui.h"
 #include "chrome/browser/ui/webui/inspect_ui.h"
 #include "chrome/browser/ui/webui/instant_ui.h"
-#include "chrome/browser/ui/webui/local_discovery/local_discovery_ui.h"
 #include "chrome/browser/ui/webui/memory_internals/memory_internals_ui.h"
 #include "chrome/browser/ui/webui/net_internals/net_internals_ui.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
@@ -94,7 +93,6 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/ui/webui/chromeos/app_launch_ui.h"
 #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_ui.h"
 #include "chrome/browser/ui/webui/chromeos/choose_mobile_network_ui.h"
 #include "chrome/browser/ui/webui/chromeos/cryptohome_ui.h"
@@ -104,6 +102,7 @@
 #include "chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/browser/ui/webui/chromeos/mobile_setup_ui.h"
+#include "chrome/browser/ui/webui/chromeos/network_ui.h"
 #include "chrome/browser/ui/webui/chromeos/proxy_settings_ui.h"
 #include "chrome/browser/ui/webui/chromeos/salsa_ui.h"
 #include "chrome/browser/ui/webui/chromeos/sim_unlock_ui.h"
@@ -130,6 +129,10 @@
 #include "chrome/browser/ui/webui/certificate_viewer_ui.h"
 #endif
 
+#if defined(ENABLE_MDNS)
+#include "chrome/browser/ui/webui/local_discovery/local_discovery_ui.h"
+#endif
+
 using content::WebUI;
 using content::WebUIController;
 using ui::ExternalWebDialogUI;
@@ -167,6 +170,13 @@
   return new AboutUI(web_ui, url.host());
 }
 
+#if defined(OS_CHROMEOS)
+template<>
+WebUIController* NewWebUI<chromeos::OobeUI>(WebUI* web_ui, const GURL& url) {
+  return new chromeos::OobeUI(web_ui, url);
+}
+#endif
+
 // Only create ExtensionWebUI for URLs that are allowed extension bindings,
 // hosted by actual tabs.
 bool NeedsExtensionWebUI(Profile* profile, const GURL& url) {
@@ -219,11 +229,13 @@
     return &NewWebUI<ConstrainedWebDialogUI>;
   if (url.host() == chrome::kChromeUICrashesHost)
     return &NewWebUI<CrashesUI>;
+#if defined(ENABLE_MDNS)
   if (url.host() == chrome::kChromeUIDevicesHost &&
       CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kEnableDeviceDiscovery)) {
     return &NewWebUI<LocalDiscoveryUI>;
   }
+#endif
   if (url.host() == chrome::kChromeUIFlagsHost)
     return &NewWebUI<FlagsUI>;
   if (url.host() == chrome::kChromeUIHistoryFrameHost)
@@ -291,9 +303,6 @@
   // Downloads list on Android uses the built-in download manager.
   if (url.host() == chrome::kChromeUIDownloadsHost)
     return &NewWebUI<DownloadsUI>;
-  // Feedback on Android uses the built-in feedback app.
-  if (url.host() == chrome::kChromeUIFeedbackHost)
-    return &NewWebUI<FeedbackUI>;
   // Flash is not available on android.
   if (url.host() == chrome::kChromeUIFlashHost)
     return &NewWebUI<FlashUI>;
@@ -314,6 +323,9 @@
   // Android does not support plugins for now.
   if (url.host() == chrome::kChromeUIPluginsHost)
     return &NewWebUI<PluginsUI>;
+  // Android does not support components for now.
+  if (url.host() == chrome::kChromeUIComponentsHost)
+    return &NewWebUI<ComponentsUI>;
   // Settings are implemented with native UI elements on Android.
   if (url.host() == chrome::kChromeUISettingsFrameHost)
     return &NewWebUI<options::OptionsUI>;
@@ -339,8 +351,6 @@
     return &NewWebUI<CertificateViewerUI>;
 #endif
 #if defined(OS_CHROMEOS)
-  if (url.host() == chrome::kChromeUIAppLaunchHost)
-    return &NewWebUI<chromeos::AppLaunchUI>;
   if (url.host() == chrome::kChromeUIBluetoothPairingHost)
     return &NewWebUI<chromeos::BluetoothPairingUI>;
   if (url.host() == chrome::kChromeUIChooseMobileNetworkHost)
@@ -369,6 +379,8 @@
     return &NewWebUI<chromeos::SlowUI>;
   if (url.host() == chrome::kChromeUISystemInfoHost)
     return &NewWebUI<chromeos::SystemInfoUI>;
+  if (url.host() == chrome::kChromeUINetworkHost)
+    return &NewWebUI<chromeos::NetworkUI>;
 #endif  // defined(OS_CHROMEOS)
 
   /****************************************************************************
@@ -418,9 +430,7 @@
 #endif
 #if defined(OS_CHROMEOS)
       || url.host() == chrome::kChromeUIDiscardsHost
-      || url.host() == chrome::kChromeUINetworkHost
       || url.host() == chrome::kChromeUIOSCreditsHost
-      || url.host() == chrome::kChromeUITransparencyHost
 #endif
 #if defined(WEBUI_TASK_MANAGER)
       || url.host() == chrome::kChromeUITaskManagerHost
@@ -608,6 +618,10 @@
   // Android doesn't use the plugins pages.
   if (page_url.host() == chrome::kChromeUIPluginsHost)
     return PluginsUI::GetFaviconResourceBytes(scale_factor);
+
+  // Android doesn't use the components pages.
+  if (page_url.host() == chrome::kChromeUIComponentsHost)
+    return ComponentsUI::GetFaviconResourceBytes(scale_factor);
 #endif
 
   return NULL;
diff --git a/chrome/browser/ui/webui/chromeos/OWNERS b/chrome/browser/ui/webui/chromeos/OWNERS
index 53311ba..0248897 100644
--- a/chrome/browser/ui/webui/chromeos/OWNERS
+++ b/chrome/browser/ui/webui/chromeos/OWNERS
@@ -4,5 +4,5 @@
 achuith@chromium.org
 satorux@chromium.org
 
-per-file about_network.*=stevenjb@chromium.org
+per-file network_ui.*=stevenjb@chromium.org
 per-file sim_unlock_ui.*=stevenjb@chromium.org
diff --git a/chrome/browser/ui/webui/chromeos/about_network.cc b/chrome/browser/ui/webui/chromeos/about_network.cc
deleted file mode 100644
index 96e6a36..0000000
--- a/chrome/browser/ui/webui/chromeos/about_network.cc
+++ /dev/null
@@ -1,206 +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/webui/chromeos/about_network.h"
-
-#include "ash/ash_switches.h"
-#include "base/command_line.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/webui/about_ui.h"
-#include "chromeos/network/favorite_state.h"
-#include "chromeos/network/network_event_log.h"
-#include "chromeos/network/network_state.h"
-#include "chromeos/network/network_state_handler.h"
-#include "grit/generated_resources.h"
-#include "net/base/escape.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace chromeos {
-
-namespace {
-
-// Html output helper functions
-
-std::string WrapWithH3(const std::string& text) {
-  return "<h3>" + net::EscapeForHTML(text) + "</h3>";
-}
-
-std::string WrapWithTH(const std::string& text) {
-  return "<th>" + net::EscapeForHTML(text) + "</th>";
-}
-
-std::string WrapWithTD(const std::string& text) {
-  return "<td>" + net::EscapeForHTML(text) + "</td>";
-}
-
-std::string WrapWithTR(const std::string& text) {
-  return "<tr>" + text + "</tr>";
-}
-
-void AppendRefresh(std::string *output, int refresh, const std::string& name) {
-  if (refresh > 0) {
-    output->append(l10n_util::GetStringFUTF8(
-        IDS_ABOUT_AUTO_REFRESH, base::IntToString16(refresh)));
-  } else {
-    output->append(l10n_util::GetStringFUTF8(
-        IDS_ABOUT_AUTO_REFRESH_INFO, UTF8ToUTF16(name)));
-  }
-}
-
-std::string GetHeaderHtmlInfo(int refresh) {
-  std::string output;
-  ::about_ui::AppendHeader(&output, refresh, "About Network");
-  ::about_ui::AppendBody(&output);
-  AppendRefresh(&output, refresh, "network");
-  return output;
-}
-
-std::string GetEventLogSection(bool debug) {
-  std::string output;
-  output.append(WrapWithH3(
-      l10n_util::GetStringUTF8(IDS_ABOUT_NETWORK_EVENT_LOG)));
-  output.append("<pre style=\""
-                "border-style:solid; border-width:1px; "
-                "overflow: auto; "
-                "height:200px;\">");
-  network_event_log::LogLevel log_level = debug
-      ? network_event_log::LOG_LEVEL_DEBUG
-      : network_event_log::LOG_LEVEL_EVENT;
-  std::string format = debug ? "file,time,desc,html" : "time,desc,html";
-  // network_event_log::GetAsString does HTML escaping.
-  output.append(
-      network_event_log::GetAsString(network_event_log::NEWEST_FIRST,
-                                     format, log_level, 0));
-  output.append("</pre>");
-  return output;
-}
-
-std::string NetworkStateToHtmlTableHeader() {
-  std::string str =
-      WrapWithTH("Name") +
-      WrapWithTH("Type") +
-      WrapWithTH("State") +
-      WrapWithTH("Path") +
-      WrapWithTH("Profile") +
-      WrapWithTH("Connect") +
-      WrapWithTH("Error") +
-      WrapWithTH("IP Addr") +
-      WrapWithTH("Security") +
-      WrapWithTH("Technology") +
-      WrapWithTH("Activation") +
-      WrapWithTH("Romaing") +
-      WrapWithTH("OOC") +
-      WrapWithTH("Strength") +
-      WrapWithTH("Auto") +
-      WrapWithTH("Fav") +
-      WrapWithTH("Pri");
-  return WrapWithTR(str);
-}
-
-std::string NetworkStateToHtmlTableRow(const NetworkState* network) {
-  std::string str =
-      WrapWithTD(network->name()) +
-      WrapWithTD(network->type()) +
-      WrapWithTD(network->connection_state()) +
-      WrapWithTD(network->path()) +
-      WrapWithTD(network->profile_path()) +
-      WrapWithTD(base::IntToString(network->connectable())) +
-      WrapWithTD(network->error()) +
-      WrapWithTD(network->ip_address()) +
-      WrapWithTD(network->security()) +
-      WrapWithTD(network->network_technology()) +
-      WrapWithTD(network->activation_state()) +
-      WrapWithTD(network->roaming()) +
-      WrapWithTD(base::IntToString(network->cellular_out_of_credits())) +
-      WrapWithTD(base::IntToString(network->signal_strength())) +
-      WrapWithTD(base::IntToString(network->auto_connect())) +
-      WrapWithTD(base::IntToString(network->favorite())) +
-      WrapWithTD(base::IntToString(network->priority()));
-  return WrapWithTR(str);
-}
-
-std::string FavoriteStateToHtmlTableHeader() {
-  std::string str =
-      WrapWithTH("Name") +
-      WrapWithTH("Type") +
-      WrapWithTH("Path") +
-      WrapWithTH("Profile");
-  return WrapWithTR(str);
-}
-
-std::string FavoriteStateToHtmlTableRow(const FavoriteState* favorite) {
-  std::string str =
-      WrapWithTD(favorite->name()) +
-      WrapWithTD(favorite->type()) +
-      WrapWithTD(favorite->path()) +
-      WrapWithTD(favorite->profile_path());
-  return WrapWithTR(str);
-}
-
-std::string GetNetworkStateHtmlInfo() {
-  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
-  NetworkStateHandler::NetworkStateList network_list;
-  handler->GetNetworkList(&network_list);
-
-  std::string output;
-  output.append(WrapWithH3(
-      l10n_util::GetStringUTF8(IDS_ABOUT_NETWORK_NETWORKS)));
-  output.append("<table border=1>");
-  output.append(NetworkStateToHtmlTableHeader());
-  for (NetworkStateHandler::NetworkStateList::iterator iter =
-           network_list.begin(); iter != network_list.end(); ++iter) {
-    const NetworkState* network = *iter;
-    output.append(NetworkStateToHtmlTableRow(network));
-  }
-  output.append("</table>");
-  return output;
-}
-
-std::string GetFavoriteStateHtmlInfo() {
-  NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
-  NetworkStateHandler::FavoriteStateList favorite_list;
-  handler->GetFavoriteList(&favorite_list);
-
-  std::string output;
-  output.append(WrapWithH3(
-      l10n_util::GetStringUTF8(IDS_ABOUT_NETWORK_FAVORITES)));
-  output.append("<table border=1>");
-  output.append(FavoriteStateToHtmlTableHeader());
-  for (NetworkStateHandler::FavoriteStateList::iterator iter =
-           favorite_list.begin(); iter != favorite_list.end(); ++iter) {
-    const FavoriteState* favorite = *iter;
-    output.append(FavoriteStateToHtmlTableRow(favorite));
-  }
-  output.append("</table>");
-  return output;
-}
-
-}  // namespace
-
-namespace about_ui {
-
-std::string AboutNetwork(const std::string& query) {
-  base::StringTokenizer tok(query, "/");
-  int refresh = 0;
-  bool debug = false;
-  while (tok.GetNext()) {
-    std::string token = tok.token();
-    if (token == "debug")
-      debug = true;
-    else
-      base::StringToInt(token, &refresh);
-  }
-  std::string output = GetHeaderHtmlInfo(refresh);
-  if (network_event_log::IsInitialized())
-    output += GetEventLogSection(debug);
-  output += GetNetworkStateHtmlInfo();
-  output += GetFavoriteStateHtmlInfo();
-  return output;
-}
-
-}  // namespace about_ui
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/about_network.h b/chrome/browser/ui/webui/chromeos/about_network.h
deleted file mode 100644
index 3bf96cc..0000000
--- a/chrome/browser/ui/webui/chromeos/about_network.h
+++ /dev/null
@@ -1,21 +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_BROWSER_UI_WEBUI_CHROMEOS_ABOUT_NETWORK_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_ABOUT_NETWORK_H_
-
-#include <string>
-
-namespace chromeos {
-namespace about_ui {
-
-// Returns the HTML for chrome://network for the chromeos networks.
-// |query| contains any text after 'chrome://network/', used to indicate the
-// refresh interval and whether to include debug log entries.
-std::string AboutNetwork(const std::string& query);
-
-}  // namespace about_ui
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_ABOUT_NETWORK_H_
diff --git a/chrome/browser/ui/webui/chromeos/app_launch_ui.cc b/chrome/browser/ui/webui/chromeos/app_launch_ui.cc
deleted file mode 100644
index 587ac63..0000000
--- a/chrome/browser/ui/webui/chromeos/app_launch_ui.cc
+++ /dev/null
@@ -1,129 +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/webui/chromeos/app_launch_ui.h"
-
-#include "base/values.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/theme_source.h"
-#include "chrome/common/url_constants.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "content/public/browser/web_ui_message_handler.h"
-#include "grit/browser_resources.h"
-#include "grit/chrome_unscaled_resources.h"
-#include "grit/chromium_strings.h"
-#include "grit/generated_resources.h"
-#include "net/base/network_change_notifier.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/webui/web_ui_util.h"
-
-namespace chromeos {
-
-namespace {
-
-content::WebUIDataSource* CreateWebUIDataSource() {
-  content::WebUIDataSource* source =
-        content::WebUIDataSource::Create(chrome::kChromeUIAppLaunchHost);
-  source->SetDefaultResource(IDR_APP_LAUNCH_SPLASH_HTML);
-  source->SetUseJsonJSFormatV2();
-  source->AddLocalizedString("appStartMessage",
-                             net::NetworkChangeNotifier::IsOffline() ?
-                                 IDS_APP_START_NETWORK_WAIT_MESSAGE :
-                                 IDS_APP_START_APP_WAIT_MESSAGE);
-  source->AddLocalizedString("productName", IDS_SHORT_PRODUCT_NAME);
-
-  const string16 product_os_name =
-      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
-  source->AddString(
-      "shortcutInfo",
-      l10n_util::GetStringFUTF16(IDS_APP_START_BAILOUT_SHORTCUT_FORMAT,
-                                 product_os_name));
-
-  source->AddBoolean("shortcutEnabled",
-                     !KioskAppManager::Get()->GetDisableBailoutShortcut());
-
-  source->SetJsonPath("strings.js");
-  source->AddResourcePath("app_launch.js", IDR_APP_LAUNCH_SPLASH_JS);
-  return source;
-}
-
-}  // namespace
-
-class AppLaunchUI::AppLaunchUIHandler : public content::WebUIMessageHandler {
- public:
-  AppLaunchUIHandler() : initialized_(false) {}
-  virtual ~AppLaunchUIHandler() {}
-
-  void SetLaunchText(const std::string& text) {
-    text_ = text;
-    if (initialized_)
-      SendLaunchText();
-  }
-
-  // content::WebUIMessageHandler overrides:
-  virtual void RegisterMessages() OVERRIDE {
-    web_ui()->RegisterMessageCallback("initialize",
-        base::Bind(&AppLaunchUIHandler::HandleInitialize,
-                   base::Unretained(this)));
-  }
-
- private:
-  void SendAppInfo(const std::string& app_id) {
-    KioskAppManager::App app;
-    KioskAppManager::Get()->GetApp(app_id, &app);
-
-    if (app.name.empty())
-      app.name = l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME);
-
-    if (app.icon.isNull()) {
-      app.icon = *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-          IDR_PRODUCT_LOGO_128);
-    }
-
-    base::DictionaryValue app_info;
-    app_info.SetString("name", app.name);
-    app_info.SetString("iconURL", webui::GetBitmapDataUrl(*app.icon.bitmap()));
-
-    web_ui()->CallJavascriptFunction("updateApp", app_info);
-  }
-
-  void SendLaunchText() {
-    web_ui()->CallJavascriptFunction("updateMessage", base::StringValue(text_));
-  }
-
-  // JS callbacks.
-  void HandleInitialize(const base::ListValue* args) {
-    initialized_ = true;
-
-    std::string app_id;
-    if (args->GetString(0, &app_id) && !app_id.empty())
-      SendAppInfo(app_id);
-
-    SendLaunchText();
-  }
-
-  bool initialized_;
-  std::string text_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppLaunchUIHandler);
-};
-
-AppLaunchUI::AppLaunchUI(content::WebUI* web_ui)
-    : WebUIController(web_ui),
-      handler_(NULL) {
-  Profile* profile = Profile::FromWebUI(web_ui);
-  content::WebUIDataSource::Add(profile, CreateWebUIDataSource());
-
-  handler_ = new AppLaunchUIHandler;
-  web_ui->AddMessageHandler(handler_);
-}
-
-void AppLaunchUI::SetLaunchText(const std::string& text) {
-  handler_->SetLaunchText(text);
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/app_launch_ui.h b/chrome/browser/ui/webui/chromeos/app_launch_ui.h
deleted file mode 100644
index e969c7a..0000000
--- a/chrome/browser/ui/webui/chromeos/app_launch_ui.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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_APP_LAUNCH_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_APP_LAUNCH_UI_H_
-
-#include <string>
-
-#include "content/public/browser/web_ui_controller.h"
-
-namespace chromeos {
-
-// A custom WebUI that shows app install/launch splash screen in ChromeOS
-// app mode (aka Kiosk).
-class AppLaunchUI : public content::WebUIController {
- public:
-  explicit AppLaunchUI(content::WebUI* web_ui);
-
-  void SetLaunchText(const std::string& text);
-
- private:
-  class AppLaunchUIHandler;
-
-  AppLaunchUIHandler* handler_;  // Owned by WebUI.
-
-  DISALLOW_COPY_AND_ASSIGN(AppLaunchUI);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_APP_LAUNCH_UI_H_
diff --git a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
index 6568946..d1323df 100644
--- a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
@@ -131,8 +131,8 @@
   StringAppendF(&out, "%s\n", path.AsUTF8Unsafe().c_str());
   StringAppendF(&out, "  title: %s\n", entry.title().c_str());
   StringAppendF(&out, "  resource_id: %s\n", entry.resource_id().c_str());
-  StringAppendF(&out, "  parent_resource_id: %s\n",
-                entry.parent_resource_id().c_str());
+  StringAppendF(&out, "  parent_local_id: %s\n",
+                entry.parent_local_id().c_str());
   StringAppendF(&out, "  shared_with_me: %s\n",
                 entry.shared_with_me() ? "true" : "false");
 
diff --git a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
index 3854377..96a7f41 100644
--- a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
@@ -259,8 +259,6 @@
                          chromeos::switches::kHasChromeOSDiamondKey));
   ash::Shell* shell = ash::Shell::GetInstance();
   ash::internal::DisplayManager* display_manager = shell->display_manager();
-  source->AddBoolean("keyboardOverlayIsDisplayRotationEnabled",
-                     display_manager->IsDisplayRotationEnabled());
   source->AddBoolean("keyboardOverlayIsDisplayUIScalingEnabled",
                      display_manager->IsDisplayUIScalingEnabled());
   source->SetJsonPath("strings.js");
diff --git a/chrome/browser/ui/webui/chromeos/login/OWNERS b/chrome/browser/ui/webui/chromeos/login/OWNERS
index 0ee9589..0cff262 100644
--- a/chrome/browser/ui/webui/chromeos/login/OWNERS
+++ b/chrome/browser/ui/webui/chromeos/login/OWNERS
@@ -1,4 +1,4 @@
-ivankr@chromium.org
 nkostylev@chromium.org
 ygorshenin@chromium.org
 antrim@chromium.org
+dzhioev@chromium.org
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
new file mode 100644
index 0000000..00646a8
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
@@ -0,0 +1,162 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
+
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "grit/browser_resources.h"
+#include "grit/chrome_unscaled_resources.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/webui/web_ui_util.h"
+
+namespace {
+
+const char kJsScreenPath[] = "login.AppLaunchSplashScreen";
+
+} // namespace
+
+namespace chromeos {
+
+AppLaunchSplashScreenHandler::AppLaunchSplashScreenHandler()
+    : BaseScreenHandler(kJsScreenPath),
+      delegate_(NULL),
+      show_on_init_(false),
+      state_(APP_LAUNCH_STATE_LOADING_AUTH_FILE) {
+}
+
+AppLaunchSplashScreenHandler::~AppLaunchSplashScreenHandler() {
+}
+
+void AppLaunchSplashScreenHandler::DeclareLocalizedValues(
+    LocalizedValuesBuilder* builder) {
+
+  builder->Add("appStartMessage", IDS_APP_START_NETWORK_WAIT_MESSAGE);
+
+  const string16 product_os_name =
+      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME);
+  builder->Add(
+      "shortcutInfo",
+      l10n_util::GetStringFUTF16(IDS_APP_START_BAILOUT_SHORTCUT_FORMAT,
+                                 product_os_name));
+
+  builder->Add(
+      "productName",
+      l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_OS_NAME));
+}
+
+void AppLaunchSplashScreenHandler::Initialize() {
+  if (show_on_init_) {
+    show_on_init_ = false;
+    Show(app_id_);
+  }
+}
+
+void AppLaunchSplashScreenHandler::Show(const std::string& app_id) {
+  app_id_ = app_id;
+  if (!page_is_ready()) {
+    show_on_init_ = true;
+    return;
+  }
+
+  base::DictionaryValue data;
+  data.SetBoolean("shortcutEnabled",
+                  !KioskAppManager::Get()->GetDisableBailoutShortcut());
+
+  // |data| will take ownership of |app_info|.
+  base::DictionaryValue *app_info = new base::DictionaryValue();
+  PopulateAppInfo(app_info);
+  data.Set("appInfo", app_info);
+
+  SetLaunchText(l10n_util::GetStringUTF8(GetProgressMessageFromState(state_)));
+  ShowScreen(OobeUI::kScreenAppLaunchSplash, &data);
+}
+
+void AppLaunchSplashScreenHandler::RegisterMessages() {
+  AddCallback("configureNetwork",
+              &AppLaunchSplashScreenHandler::HandleConfigureNetwork);
+  AddCallback("cancelAppLaunch",
+              &AppLaunchSplashScreenHandler::HandleCancelAppLaunch);
+}
+
+void AppLaunchSplashScreenHandler::PrepareToShow() {
+}
+
+void AppLaunchSplashScreenHandler::Hide() {
+}
+
+void AppLaunchSplashScreenHandler::ToggleNetworkConfig(bool visible) {
+  // TODO(tengs): Implement network configuration in app launch.
+}
+
+void AppLaunchSplashScreenHandler::UpdateAppLaunchState(AppLaunchState state) {
+  if (state == state_)
+    return;
+
+  state_ = state;
+  if (page_is_ready()) {
+    SetLaunchText(
+        l10n_util::GetStringUTF8(GetProgressMessageFromState(state_)));
+  }
+}
+
+void AppLaunchSplashScreenHandler::SetDelegate(
+    AppLaunchSplashScreenHandler::Delegate* delegate) {
+  delegate_ = delegate;
+}
+
+void AppLaunchSplashScreenHandler::PopulateAppInfo(
+    base::DictionaryValue* out_info) {
+  KioskAppManager::App app;
+  KioskAppManager::Get()->GetApp(app_id_, &app);
+
+  if (app.name.empty())
+    app.name = l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME);
+
+  if (app.icon.isNull()) {
+    app.icon = *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+        IDR_PRODUCT_LOGO_128);
+  }
+
+  out_info->SetString("name", app.name);
+  out_info->SetString("iconURL", webui::GetBitmapDataUrl(*app.icon.bitmap()));
+}
+
+void AppLaunchSplashScreenHandler::SetLaunchText(const std::string& text) {
+  CallJS("updateMessage", text);
+}
+
+int AppLaunchSplashScreenHandler::GetProgressMessageFromState(
+    AppLaunchState state) {
+  switch (state) {
+    case APP_LAUNCH_STATE_LOADING_AUTH_FILE:
+    case APP_LAUNCH_STATE_LOADING_TOKEN_SERVICE:
+      // TODO(zelidrag): Add better string for this one than "Please wait..."
+      return IDS_SYNC_SETUP_SPINNER_TITLE;
+    case APP_LAUNCH_STATE_PREPARING_NETWORK:
+      return IDS_APP_START_NETWORK_WAIT_MESSAGE;
+    case APP_LAUNCH_STATE_INSTALLING_APPLICATION:
+      return IDS_APP_START_APP_WAIT_MESSAGE;
+  }
+  return IDS_APP_START_NETWORK_WAIT_MESSAGE;
+}
+
+void AppLaunchSplashScreenHandler::HandleConfigureNetwork() {
+  if (delegate_)
+    delegate_->OnConfigureNetwork();
+  else
+    LOG(WARNING) << "No delegate set to handle network configuration.";
+}
+
+void AppLaunchSplashScreenHandler::HandleCancelAppLaunch() {
+  if (delegate_)
+    delegate_->OnCancelAppLaunch();
+  else
+    LOG(WARNING) << "No delegate set to handle cancel app launch";
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
new file mode 100644
index 0000000..72cc4b7
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.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_WEBUI_CHROMEOS_LOGIN_APP_LAUNCH_SPLASH_SCREEN_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_APP_LAUNCH_SPLASH_SCREEN_HANDLER_H_
+
+#include <set>
+#include <string>
+
+#include "chrome/browser/chromeos/login/screens/app_launch_splash_screen_actor.h"
+#include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
+
+namespace chromeos {
+
+// A class that handles the WebUI hooks for the app launch splash screen.
+class AppLaunchSplashScreenHandler : public BaseScreenHandler,
+                                     public AppLaunchSplashScreenActor {
+ public:
+  AppLaunchSplashScreenHandler();
+  virtual ~AppLaunchSplashScreenHandler();
+
+  // BaseScreenHandler implementation:
+  virtual void DeclareLocalizedValues(LocalizedValuesBuilder* builder) OVERRIDE;
+  virtual void Initialize() OVERRIDE;
+
+  // WebUIMessageHandler implementation:
+  virtual void RegisterMessages() OVERRIDE;
+
+  // AppLaunchSplashScreenActor implementation:
+  virtual void Show(const std::string& app_id) OVERRIDE;
+  virtual void PrepareToShow() OVERRIDE;
+  virtual void Hide() OVERRIDE;
+  virtual void ToggleNetworkConfig(bool visible) OVERRIDE;
+  virtual void UpdateAppLaunchState(AppLaunchState state) OVERRIDE;
+  virtual void SetDelegate(
+      AppLaunchSplashScreenHandler::Delegate* delegate) OVERRIDE;
+
+ private:
+  void PopulateAppInfo(base::DictionaryValue* out_info);
+  void SetLaunchText(const std::string& text);
+  int GetProgressMessageFromState(AppLaunchState state);
+  void HandleConfigureNetwork();
+  void HandleCancelAppLaunch();
+
+  AppLaunchSplashScreenHandler::Delegate* delegate_;
+  bool show_on_init_;
+  std::string app_id_;
+  AppLaunchState state_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppLaunchSplashScreenHandler);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_LOGIN_APP_LAUNCH_SPLASH_SCREEN_HANDLER_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
index 40d0b1d..c000029 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -9,6 +9,8 @@
 #include "base/time/time.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/captive_portal_window_proxy.h"
+#include "chrome/browser/chromeos/login/login_display_host_impl.h"
+#include "chrome/browser/chromeos/login/webui_login_view.h"
 #include "chrome/browser/chromeos/net/network_portal_detector.h"
 #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
@@ -74,9 +76,13 @@
 
 void ErrorScreenHandler::FixCaptivePortal() {
   if (!captive_portal_window_proxy_.get()) {
+    content::WebContents* web_contents =
+        LoginDisplayHostImpl::default_host()->GetWebUILoginView()->
+            GetWebContents();
     captive_portal_window_proxy_.reset(
         new CaptivePortalWindowProxy(network_state_informer_.get(),
-                                     GetNativeWindow()));
+                                     GetNativeWindow(),
+                                     web_contents));
   }
   captive_portal_window_proxy_->ShowIfRedirected();
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc
index 7cfea29..bded6ac 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_launcher.h"
 #include "chrome/browser/chromeos/login/existing_user_controller.h"
 #include "chrome/browser/policy/browser_policy_connector.h"
 #include "chromeos/chromeos_switches.h"
@@ -47,9 +46,6 @@
   web_ui()->RegisterMessageCallback("kioskAppsLoaded",
       base::Bind(&KioskAppMenuHandler::HandleKioskAppsLoaded,
                  base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("launchKioskApp",
-      base::Bind(&KioskAppMenuHandler::HandleLaunchKioskApps,
-                 base::Unretained(this)));
   web_ui()->RegisterMessageCallback("checkKioskAppLaunchError",
       base::Bind(&KioskAppMenuHandler::HandleCheckKioskAppLaunchError,
                  base::Unretained(this)));
@@ -111,19 +107,6 @@
       content::NotificationService::NoDetails());
 }
 
-void KioskAppMenuHandler::HandleLaunchKioskApps(const base::ListValue* args) {
-  std::string app_id;
-  CHECK(args->GetString(0, &app_id));
-
-  KioskAppManager::App app_data;
-  CHECK(KioskAppManager::Get()->GetApp(app_id, &app_data));
-
-  ExistingUserController::current_controller()->PrepareKioskAppLaunch();
-
-  // KioskAppLauncher deletes itself when done.
-  (new KioskAppLauncher(KioskAppManager::Get(), app_id))->Start();
-}
-
 void KioskAppMenuHandler::HandleCheckKioskAppLaunchError(
     const base::ListValue* args) {
   KioskAppLaunchError::Error error = KioskAppLaunchError::Get();
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h
index 9da4f99..3646058 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h
@@ -37,7 +37,6 @@
   // JS callbacks.
   void HandleInitializeKioskApps(const base::ListValue* args);
   void HandleKioskAppsLoaded(const base::ListValue* args);
-  void HandleLaunchKioskApps(const base::ListValue* args);
   void HandleCheckKioskAppLaunchError(const base::ListValue* args);
 
   // KioskAppManagerObserver overrides:
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 20a8b4c..57a46e7 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 
-#include <string>
-
 #include "ash/ash_switches.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -21,6 +19,7 @@
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/about_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
@@ -54,8 +53,21 @@
 
 namespace {
 
-// Path for a stripped down login page that does not have OOBE elements.
-const char kLoginPath[] = "login#login";
+// List of known types of OobeUI. Type added as path in chrome://oobe url, for
+// example chrome://oobe/user-adding.
+const char kOobeDisplay[] = "oobe";
+const char kLoginDisplay[] = "login";
+const char kLockDisplay[] = "lock";
+const char kUserAddingDisplay[] = "user-adding";
+const char kAppLaunchSplashDisplay[] = "app-launch-splash";
+
+const char* kKnownDisplayTypes[] = {
+  kOobeDisplay,
+  kLoginDisplay,
+  kLockDisplay,
+  kUserAddingDisplay,
+  kAppLaunchSplashDisplay
+};
 
 const char kStringsJSPath[] = "strings.js";
 const char kLoginJSPath[] = "login.js";
@@ -86,7 +98,8 @@
 
 // Creates a WebUIDataSource for chrome://oobe
 content::WebUIDataSource* CreateOobeUIDataSource(
-    const base::DictionaryValue& localized_strings) {
+    const base::DictionaryValue& localized_strings,
+    const std::string& display_type) {
   content::WebUIDataSource* source =
       content::WebUIDataSource::Create(chrome::kChromeUIOobeHost);
   source->SetUseJsonJSFormatV2();
@@ -95,35 +108,40 @@
 
   if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled()) {
     source->SetDefaultResource(IDR_DEMO_USER_LOGIN_HTML);
-    source->AddResourcePath(kDemoUserLoginJSPath,
-                            IDR_DEMO_USER_LOGIN_JS);
+    source->AddResourcePath(kDemoUserLoginJSPath, IDR_DEMO_USER_LOGIN_JS);
     return source;
   }
-
-  source->SetDefaultResource(IDR_OOBE_HTML);
-  source->AddResourcePath(kOobeJSPath,
-                          IDR_OOBE_JS);
-  source->AddResourcePath(kLoginPath,
-                          IDR_LOGIN_HTML);
-  source->AddResourcePath(kLoginJSPath,
-                          IDR_LOGIN_JS);
-  source->AddResourcePath(kKeyboardUtilsJSPath,
-                          IDR_KEYBOARD_UTILS_JS);
+  if (display_type == kOobeDisplay) {
+    source->SetDefaultResource(IDR_OOBE_HTML);
+    source->AddResourcePath(kOobeJSPath, IDR_OOBE_JS);
+  } else {
+    source->SetDefaultResource(IDR_LOGIN_HTML);
+    source->AddResourcePath(kLoginJSPath, IDR_LOGIN_JS);
+  }
+  source->AddResourcePath(kKeyboardUtilsJSPath, IDR_KEYBOARD_UTILS_JS);
   source->OverrideContentSecurityPolicyFrameSrc(
       "frame-src chrome://terms/ "
       "chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/;");
 
   // Serve deferred resources.
-  source->AddResourcePath(kEnrollmentHTMLPath,
-                          IDR_OOBE_ENROLLMENT_HTML);
-  source->AddResourcePath(kEnrollmentCSSPath,
-                          IDR_OOBE_ENROLLMENT_CSS);
-  source->AddResourcePath(kEnrollmentJSPath,
-                          IDR_OOBE_ENROLLMENT_JS);
+  source->AddResourcePath(kEnrollmentHTMLPath, IDR_OOBE_ENROLLMENT_HTML);
+  source->AddResourcePath(kEnrollmentCSSPath, IDR_OOBE_ENROLLMENT_CSS);
+  source->AddResourcePath(kEnrollmentJSPath, IDR_OOBE_ENROLLMENT_JS);
 
   return source;
 }
 
+std::string GetDisplayType(const GURL& url) {
+  std::string path = url.path().size() ? url.path().substr(1) : "";
+  if (std::find(kKnownDisplayTypes,
+                kKnownDisplayTypes + arraysize(kKnownDisplayTypes),
+                path) == kKnownDisplayTypes + arraysize(kKnownDisplayTypes)) {
+    LOG(ERROR) << "Unknown display type '" << path << "'. Setting default.";
+    return kLoginDisplay;
+  }
+  return path;
+}
+
 }  // namespace
 
 // static
@@ -143,8 +161,9 @@
                                             = "managed-user-creation";
 const char OobeUI::kScreenTermsOfService[]  = "terms-of-service";
 const char OobeUI::kScreenWrongHWID[]       = "wrong-hwid";
+const char OobeUI::kScreenAppLaunchSplash[] = "app-launch-splash";
 
-OobeUI::OobeUI(content::WebUI* web_ui)
+OobeUI::OobeUI(content::WebUI* web_ui, const GURL& url)
     : WebUIController(web_ui),
       core_handler_(NULL),
       network_dropdown_handler_(NULL),
@@ -163,6 +182,7 @@
       kiosk_app_menu_handler_(NULL),
       current_screen_(SCREEN_UNKNOWN),
       ready_(false) {
+  display_type_ = GetDisplayType(url);
   InitializeScreenMaps();
 
   network_state_informer_ = new NetworkStateInformer();
@@ -179,10 +199,12 @@
   AddScreenHandler(update_screen_handler_);
   network_dropdown_handler_->AddObserver(update_screen_handler_);
 
-  NetworkScreenHandler* network_screen_handler =
-      new NetworkScreenHandler(core_handler_);
-  network_screen_actor_ = network_screen_handler;
-  AddScreenHandler(network_screen_handler);
+  if (display_type_ == kOobeDisplay) {
+    NetworkScreenHandler* network_screen_handler =
+        new NetworkScreenHandler(core_handler_);
+    network_screen_actor_ = network_screen_handler;
+    AddScreenHandler(network_screen_handler);
+  }
 
   EulaScreenHandler* eula_screen_handler = new EulaScreenHandler(core_handler_);
   eula_screen_actor_ = eula_screen_handler;
@@ -237,6 +259,11 @@
                                                    core_handler_);
   AddScreenHandler(signin_screen_handler_);
 
+  AppLaunchSplashScreenHandler* app_launch_splash_screen_handler =
+      new AppLaunchSplashScreenHandler();
+  AddScreenHandler(app_launch_splash_screen_handler);
+  app_launch_splash_screen_actor_ = app_launch_splash_screen_handler;
+
   // Initialize KioskAppMenuHandler. Note that it is NOT a screen handler.
   kiosk_app_menu_handler_ = new KioskAppMenuHandler;
   web_ui->AddMessageHandler(kiosk_app_menu_handler_);
@@ -256,7 +283,8 @@
 
   // Set up the chrome://oobe/ source.
   content::WebUIDataSource::Add(profile,
-                                CreateOobeUIDataSource(localized_strings));
+                                CreateOobeUIDataSource(localized_strings,
+                                                       display_type_));
 
   // Set up the chrome://userimage/ source.
   options::UserImageSource* user_image_source =
@@ -326,6 +354,11 @@
   return locally_managed_user_creation_screen_actor_;
 }
 
+AppLaunchSplashScreenActor*
+      OobeUI::GetAppLaunchSplashScreenActor() {
+  return app_launch_splash_screen_actor_;
+}
+
 void OobeUI::GetLocalizedStrings(base::DictionaryValue* localized_strings) {
   // Note, handlers_[0] is a GenericHandler used by the WebUI.
   for (size_t i = 0; i < handlers_.size(); ++i)
@@ -378,6 +411,7 @@
       kScreenManagedUserCreationFlow;
   screen_names_[SCREEN_TERMS_OF_SERVICE] = kScreenTermsOfService;
   screen_names_[SCREEN_WRONG_HWID] = kScreenWrongHWID;
+  screen_names_[SCREEN_APP_LAUNCH_SPLASH] = kScreenAppLaunchSplash;
 
   screen_ids_.clear();
   for (size_t i = 0; i < screen_names_.size(); ++i)
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
index 6da71aa..6c92fda 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -17,9 +17,10 @@
 
 namespace base {
 class DictionaryValue;
-}
+}  // namespace base
 
 namespace chromeos {
+class AppLaunchSplashScreenActor;
 class BaseScreenHandler;
 class CoreOobeHandler;
 class ErrorScreenHandler;
@@ -56,8 +57,9 @@
   static const char kScreenManagedUserCreationFlow[];
   static const char kScreenTermsOfService[];
   static const char kScreenWrongHWID[];
+  static const char kScreenAppLaunchSplash[];
 
-  explicit OobeUI(content::WebUI* web_ui);
+  OobeUI(content::WebUI* web_ui, const GURL& url);
   virtual ~OobeUI();
 
   // OobeDisplay implementation:
@@ -77,6 +79,8 @@
   virtual WrongHWIDScreenActor* GetWrongHWIDScreenActor() OVERRIDE;
   virtual LocallyManagedUserCreationScreenHandler*
       GetLocallyManagedUserCreationScreenActor() OVERRIDE;
+  virtual AppLaunchSplashScreenActor*
+      GetAppLaunchSplashScreenActor() OVERRIDE;
   virtual bool IsJSReady(const base::Closure& display_is_ready_callback)
       OVERRIDE;
 
@@ -98,6 +102,9 @@
   void ShowSigninScreen(SigninScreenHandlerDelegate* delegate,
                         NativeWindowDelegate* native_window_delegate);
 
+  // Shows the kiosk splash screen.
+  void ShowAppLaunchSplashScreen();
+
   // Resets the delegate set in ShowSigninScreen.
   void ResetSigninScreenHandlerDelegate();
 
@@ -114,6 +121,9 @@
   // CoreOobeHandler::Delegate implementation:
   virtual void OnCurrentScreenChanged(const std::string& screen) OVERRIDE;
 
+  // Type of UI.
+  std::string display_type_;
+
   // Reference to NetworkStateInformer that handles changes in network
   // state.
   scoped_refptr<NetworkStateInformer> network_state_informer_;
@@ -136,6 +146,7 @@
   WrongHWIDScreenActor* wrong_hwid_screen_actor_;
   LocallyManagedUserCreationScreenHandler*
       locally_managed_user_creation_screen_actor_;
+  AppLaunchSplashScreenActor* app_launch_splash_screen_actor_;
 
   // Reference to ErrorScreenHandler that handles error screen
   // requests and forward calls from native code to JS side.
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 917aba6..b398ef1 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -468,6 +468,8 @@
       g_browser_process->browser_policy_connector()->IsEnterpriseManaged() ?
           IDS_DISABLED_ADD_USER_TOOLTIP_ENTERPRISE :
           IDS_DISABLED_ADD_USER_TOOLTIP);
+  builder->Add("supervisedUserExpiredTokenWarning",
+               IDS_SUPERVISED_USER_EXPIRED_TOKEN_WARNING);
 
   // Strings used by password changed dialog.
   builder->Add("passwordChangedTitle", IDS_LOGIN_PASSWORD_CHANGED_TITLE);
@@ -849,6 +851,11 @@
               &SigninScreenHandler::HandleShowLoadingTimeoutError);
   AddCallback("updateOfflineLogin",
               &SigninScreenHandler::HandleUpdateOfflineLogin);
+  AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod);
+
+  // This message is sent by the kiosk app menu, but is handled here
+  // so we can tell the delegate to launch the app.
+  AddCallback("launchKioskApp", &SigninScreenHandler::HandleLaunchKioskApp);
 }
 
 void SigninScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) {
@@ -1292,7 +1299,6 @@
         &SigninScreenHandler::ShowSigninScreenIfReady,
         weak_factory_.GetWeakPtr()));
   }
-  SetUserInputMethodHWDefault();
 }
 
 void SigninScreenHandler::HandleToggleEnrollmentScreen() {
@@ -1338,13 +1344,21 @@
       user->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT;
   bool is_locally_managed_user =
       user->GetType() == User::USER_TYPE_LOCALLY_MANAGED;
+  User::OAuthTokenStatus token_status = user->oauth_token_status();
+
+  // If supervised user has unknown token status consider that as valid token.
+  // It will be invalidated inside session in case it has been revoked.
+  if (is_locally_managed_user &&
+      token_status == User::OAUTH_TOKEN_STATUS_UNKNOWN) {
+    token_status = User::OAUTH2_TOKEN_STATUS_VALID;
+  }
 
   user_dict->SetString(kKeyUsername, email);
   user_dict->SetString(kKeyEmailAddress, user->display_email());
   user_dict->SetString(kKeyDisplayName, user->GetDisplayName());
   user_dict->SetBoolean(kKeyPublicAccount, is_public_account);
   user_dict->SetBoolean(kKeyLocallyManagedUser, is_locally_managed_user);
-  user_dict->SetInteger(kKeyOauthTokenStatus, user->oauth_token_status());
+  user_dict->SetInteger(kKeyOauthTokenStatus, token_status);
   user_dict->SetBoolean(kKeySignedIn, user->is_logged_in());
   user_dict->SetBoolean(kKeyIsOwner, is_owner);
 
@@ -1433,12 +1447,8 @@
   is_account_picker_showing_first_time_ = true;
   MaybePreloadAuthExtension();
 
-  if (ScreenLocker::default_screen_locker()) {
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_LOCK_WEBUI_READY,
-        content::NotificationService::AllSources(),
-        content::NotificationService::NoDetails());
-  }
+  if (ScreenLocker::default_screen_locker())
+    ScreenLocker::default_screen_locker()->delegate()->OnLockWebUIReady();
 
   if (delegate_)
     delegate_->OnSigninScreenReady();
@@ -1446,10 +1456,8 @@
 
 void SigninScreenHandler::HandleWallpaperReady() {
   if (ScreenLocker::default_screen_locker()) {
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_LOCK_BACKGROUND_DISPLAYED,
-        content::NotificationService::AllSources(),
-        content::NotificationService::NoDetails());
+    ScreenLocker::default_screen_locker()->delegate()->
+        OnLockBackgroundDisplayed();
   }
 }
 
@@ -1612,6 +1620,14 @@
   offline_login_active_ = offline_login_active;
 }
 
+void SigninScreenHandler::HandleFocusPod(const std::string& user_id) {
+  SetUserInputMethod(user_id);
+}
+
+void SigninScreenHandler::HandleLaunchKioskApp(const std::string& app_id) {
+  delegate_->LoginAsKioskApp(app_id);
+}
+
 void SigninScreenHandler::StartClearingDnsCache() {
   if (dns_clear_task_running_ || !g_browser_process->io_thread())
     return;
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 1d51afc..33d8915 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -157,6 +157,9 @@
   // Signs out if the screen is currently locked.
   virtual void Signout() = 0;
 
+  // Login to kiosk mode for app with |app_id|.
+  virtual void LoginAsKioskApp(const std::string& app_id) = 0;
+
  protected:
   virtual ~SigninScreenHandlerDelegate() {}
 };
@@ -326,6 +329,8 @@
   void HandleShowLoadingTimeoutError();
   void HandleUpdateOfflineLogin(bool offline_login_active);
   void HandleShowLocallyManagedUserCreationScreen();
+  void HandleFocusPod(const std::string& user_id);
+  void HandleLaunchKioskApp(const std::string& app_id);
 
   // Fills |user_dict| with information about |user|.
   static void FillUserDictionary(User* user,
diff --git a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
index 6af88b9..496f143 100644
--- a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
@@ -101,7 +101,7 @@
 
 void TermsOfServiceScreenHandler::UpdateDomainInUI() {
   if (page_is_ready())
-    CallJS("cr.ui.Oobe.setTermsOfServiceDomain", domain_);
+    CallJS("setDomain", domain_);
 }
 
 void TermsOfServiceScreenHandler::UpdateTermsOfServiceInUI() {
@@ -113,9 +113,9 @@
   // download is still in progress and the UI will be updated when the
   // OnLoadError() or the OnLoadSuccess() callback is called.
   if (load_error_)
-    CallJS("cr.ui.Oobe.setTermsOfServiceLoadError");
+    CallJS("setTermsOfServiceLoadError");
   else if (!terms_of_service_.empty())
-    CallJS("cr.ui.Oobe.setTermsOfService", terms_of_service_);
+    CallJS("setTermsOfService", terms_of_service_);
 }
 
 void TermsOfServiceScreenHandler::HandleBack() {
diff --git a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
index 44cb018..75b3152 100644
--- a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
@@ -30,7 +30,8 @@
 UserImageScreenHandler::UserImageScreenHandler()
     : BaseScreenHandler(kJsScreenPath),
       screen_(NULL),
-      show_on_init_(false) {
+      show_on_init_(false),
+      is_ready_(false) {
 }
 
 UserImageScreenHandler::~UserImageScreenHandler() {
@@ -62,6 +63,8 @@
   if (!screen_)
     return;
   screen_->CheckCameraPresence();
+  if (is_ready_)
+    screen_->OnScreenReady();
 }
 
 void UserImageScreenHandler::Hide() {
@@ -94,6 +97,7 @@
 
 void UserImageScreenHandler::RegisterMessages() {
   AddCallback("getImages", &UserImageScreenHandler::HandleGetImages);
+  AddCallback("screenReady", &UserImageScreenHandler::HandleScreenReady);
   AddCallback("photoTaken", &UserImageScreenHandler::HandlePhotoTaken);
   AddCallback("selectImage", &UserImageScreenHandler::HandleSelectImage);
   AddCallback("checkCameraPresence",
@@ -146,6 +150,12 @@
     OnProfileImageAbsent();
 }
 
+void UserImageScreenHandler::HandleScreenReady() {
+  is_ready_ = true;
+  if (screen_)
+    screen_->OnScreenReady();
+}
+
 void UserImageScreenHandler::HandlePhotoTaken(const std::string& image_url) {
   std::string mime_type, charset, raw_data;
   if (!net::DataURL::Parse(GURL(image_url), &mime_type, &charset, &raw_data))
@@ -163,9 +173,10 @@
 }
 
 void UserImageScreenHandler::HandleSelectImage(const std::string& image_url,
-                                               const std::string& image_type) {
+                                               const std::string& image_type,
+                                               bool is_user_selection) {
   if (screen_)
-    screen_->OnImageSelected(image_type, image_url);
+    screen_->OnImageSelected(image_type, image_url, is_user_selection);
 }
 
 void UserImageScreenHandler::HandleImageAccepted() {
@@ -185,6 +196,10 @@
   CallJS("setCameraPresent", present);
 }
 
+void UserImageScreenHandler::HideCurtain() {
+  CallJS("hideCurtain");
+}
+
 void UserImageScreenHandler::SetProfilePictureEnabled(bool enabled) {
   CallJS("setProfilePictureEnabled", enabled);
 }
diff --git a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h
index 9ac7c64..8a0959c 100644
--- a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h
@@ -47,11 +47,16 @@
 
   virtual void SetCameraPresent(bool enabled) OVERRIDE;
 
+  virtual void HideCurtain() OVERRIDE;
+
  private:
 
   // Sends image data to the page.
   void HandleGetImages();
 
+  // Screen ready to be shown.
+  void HandleScreenReady();
+
   // Handles photo taken with WebRTC UI.
   void HandlePhotoTaken(const std::string& image_url);
 
@@ -60,7 +65,8 @@
 
   // Handles clicking on default user image.
   void HandleSelectImage(const std::string& image_url,
-                         const std::string& image_type);
+                         const std::string& image_type,
+                         bool is_user_selection);
 
   // Called when user accept the image closing the screen.
   void HandleImageAccepted();
@@ -73,6 +79,9 @@
   // Keeps whether screen should be shown right after initialization.
   bool show_on_init_;
 
+  // Keeps whether screen has loaded all default images and redy to be shown.
+  bool is_ready_;
+
   base::Time screen_show_time_;
 
   DISALLOW_COPY_AND_ASSIGN(UserImageScreenHandler);
diff --git a/chrome/browser/ui/webui/chromeos/network_ui.cc b/chrome/browser/ui/webui/chromeos/network_ui.cc
new file mode 100644
index 0000000..523a351
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/network_ui.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/webui/chromeos/network_ui.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/url_constants.h"
+#include "chromeos/network/network_event_log.h"
+#include "chromeos/network/network_state.h"
+#include "chromeos/network/network_state_handler.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
+
+namespace chromeos {
+
+namespace {
+
+const char kStringsJsFile[] = "strings.js";
+const char kRequestNetworkInfoCallback[] = "requestNetworkInfo";
+const char kNetworkEventLogTag[] = "networkEventLog";
+const char kNetworkStateTag[] = "networkState";
+const char kOnNetworkInfoReceivedFunction[] = "NetworkUI.onNetworkInfoReceived";
+const char kLevelDebugTag[] = "Debug";
+
+class NetworkMessageHandler : public content::WebUIMessageHandler {
+ public:
+  NetworkMessageHandler();
+  virtual ~NetworkMessageHandler();
+
+  // WebUIMessageHandler implementation.
+  virtual void RegisterMessages() OVERRIDE;
+
+ private:
+  void CollectNetworkInfo(const base::ListValue* value) const;
+  std::string GetNetworkEventLog() const;
+  void GetNetworkState(base::DictionaryValue* output) const;
+  void RespondToPage(const base::DictionaryValue& value) const;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkMessageHandler);
+};
+
+NetworkMessageHandler::NetworkMessageHandler() {
+}
+
+NetworkMessageHandler::~NetworkMessageHandler() {
+}
+
+void NetworkMessageHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      kRequestNetworkInfoCallback,
+      base::Bind(&NetworkMessageHandler::CollectNetworkInfo,
+                 base::Unretained(this)));
+}
+
+void NetworkMessageHandler::CollectNetworkInfo(
+    const base::ListValue* value) const {
+  base::DictionaryValue data;
+  data.SetString(kNetworkEventLogTag, GetNetworkEventLog());
+  base::DictionaryValue* networkState = new base::DictionaryValue;
+  GetNetworkState(networkState);
+  data.Set(kNetworkStateTag, networkState);
+  RespondToPage(data);
+}
+
+void NetworkMessageHandler::RespondToPage(
+    const base::DictionaryValue& value) const {
+  web_ui()->CallJavascriptFunction(kOnNetworkInfoReceivedFunction, value);
+}
+
+std::string NetworkMessageHandler::GetNetworkEventLog() const {
+  std::string format = "time,desc,json";
+  return chromeos::network_event_log::GetAsString(
+      chromeos::network_event_log::NEWEST_FIRST,
+      format,
+      chromeos::network_event_log::LOG_LEVEL_DEBUG,
+      0);
+}
+
+void NetworkMessageHandler::GetNetworkState(
+    base::DictionaryValue* output) const {
+  chromeos::NetworkStateHandler* handler =
+      chromeos::NetworkHandler::Get()->network_state_handler();
+  chromeos::NetworkStateHandler::NetworkStateList network_list;
+  handler->GetNetworkList(&network_list);
+
+  for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it =
+           network_list.begin();
+       it != network_list.end();
+       ++it) {
+    base::DictionaryValue* properties = new base::DictionaryValue;
+    (*it)->GetProperties(properties);
+    output->Set((*it)->path(), properties);
+  }
+}
+
+}  // namespace
+
+NetworkUI::NetworkUI(content::WebUI* web_ui)
+    : content::WebUIController(web_ui) {
+  web_ui->AddMessageHandler(new NetworkMessageHandler());
+
+  content::WebUIDataSource* html =
+      content::WebUIDataSource::Create(chrome::kChromeUINetworkHost);
+  html->SetUseJsonJSFormatV2();
+
+  html->AddLocalizedString("titleText", IDS_NETWORK_TITLE);
+  html->AddLocalizedString("autoRefreshText", IDS_NETWORK_AUTO_REFRESH);
+  html->AddLocalizedString("logRefreshText", IDS_NETWORK_LOG_REFRESH);
+  html->AddLocalizedString("logLevelShowText", IDS_NETWORK_LOG_LEVEL_SHOW);
+  html->AddLocalizedString("logLevelErrorText", IDS_NETWORK_LOG_LEVEL_ERROR);
+  html->AddLocalizedString("logLevelUserText", IDS_NETWORK_LOG_LEVEL_USER);
+  html->AddLocalizedString("logLevelEventText", IDS_NETWORK_LOG_LEVEL_EVENT);
+  html->AddLocalizedString("logLevelDebugText", IDS_NETWORK_LOG_LEVEL_DEBUG);
+  html->AddLocalizedString("logEntryFormat", IDS_NETWORK_LOG_ENTRY);
+  html->SetJsonPath(kStringsJsFile);
+
+  html->AddResourcePath("network.css", IDR_NETWORK_CSS);
+  html->AddResourcePath("network.js", IDR_NETWORK_JS);
+  html->SetDefaultResource(IDR_NETWORK_HTML);
+
+  Profile* profile = Profile::FromWebUI(web_ui);
+  content::WebUIDataSource::Add(profile, html);
+}
+
+NetworkUI::~NetworkUI() {
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/network_ui.h b/chrome/browser/ui/webui/chromeos/network_ui.h
new file mode 100644
index 0000000..8fb0dca
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/network_ui.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 CHROME_BROWSER_UI_WEBUI_CHROMEOS_NETWORK_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_NETWORK_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+
+namespace chromeos {
+
+class NetworkUI : public content::WebUIController {
+ public:
+  explicit NetworkUI(content::WebUI* web_ui);
+  virtual ~NetworkUI();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NetworkUI);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_NETWORK_UI_H_
diff --git a/chrome/browser/ui/webui/components_ui.cc b/chrome/browser/ui/webui/components_ui.cc
new file mode 100644
index 0000000..c58b91c
--- /dev/null
+++ b/chrome/browser/ui/webui/components_ui.cc
@@ -0,0 +1,166 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/components_ui.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/component_updater/component_updater_service.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "grit/browser_resources.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"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
+#endif
+
+using content::WebUIMessageHandler;
+
+namespace {
+
+content::WebUIDataSource* CreateComponentsUIHTMLSource() {
+  content::WebUIDataSource* source =
+      content::WebUIDataSource::Create(chrome::kChromeUIComponentsHost);
+  source->SetUseJsonJSFormatV2();
+
+  source->AddLocalizedString("componentsTitle", IDS_COMPONENTS_TITLE);
+  source->AddLocalizedString("componentsNoneInstalled",
+                             IDS_COMPONENTS_NONE_INSTALLED);
+  source->AddLocalizedString("componentVersion", IDS_COMPONENTS_VERSION);
+  source->AddLocalizedString("checkUpdate", IDS_COMPONENTS_CHECK_FOR_UPDATE);
+  source->AddLocalizedString("noComponents", IDS_COMPONENTS_NO_COMPONENTS);
+
+  source->SetJsonPath("strings.js");
+  source->AddResourcePath("components.js", IDR_COMPONENTS_JS);
+  source->SetDefaultResource(IDR_COMPONENTS_HTML);
+#if defined(OS_CHROMEOS)
+  chromeos::AddAccountUITweaksLocalizedValues(source);
+#endif
+  return source;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ComponentsDOMHandler
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The handler for Javascript messages for the chrome://components/ page.
+class ComponentsDOMHandler : public WebUIMessageHandler {
+ public:
+  ComponentsDOMHandler();
+  virtual ~ComponentsDOMHandler() {}
+
+  // WebUIMessageHandler implementation.
+  virtual void RegisterMessages() OVERRIDE;
+
+  // Callback for the "requestComponentsData" message.
+  void HandleRequestComponentsData(const ListValue* args);
+
+  // Callback for the "checkUpdate" message.
+  void HandleCheckUpdate(const ListValue* args);
+
+ private:
+  void LoadComponents();
+
+  content::NotificationRegistrar registrar_;
+
+  DISALLOW_COPY_AND_ASSIGN(ComponentsDOMHandler);
+};
+
+ComponentsDOMHandler::ComponentsDOMHandler() {
+}
+
+void ComponentsDOMHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback("requestComponentsData",
+      base::Bind(&ComponentsDOMHandler::HandleRequestComponentsData,
+                 base::Unretained(this)));
+
+  web_ui()->RegisterMessageCallback("checkUpdate",
+      base::Bind(&ComponentsDOMHandler::HandleCheckUpdate,
+                 base::Unretained(this)));
+}
+
+void ComponentsDOMHandler::HandleRequestComponentsData(const ListValue* args) {
+  LoadComponents();
+}
+
+// This function is called when user presses button from html UI.
+// TODO(shrikant): We need to make this button available based on current
+// state e.g. If component state is currently updating then we need to disable
+// button. (https://code.google.com/p/chromium/issues/detail?id=272540)
+void ComponentsDOMHandler::HandleCheckUpdate(const ListValue* args) {
+  if (args->GetSize() != 1) {
+    NOTREACHED();
+    return;
+  }
+
+  std::string component_id;
+  if (!args->GetString(0, &component_id)) {
+    NOTREACHED();
+    return;
+  }
+
+  ComponentUpdateService* cus = g_browser_process->component_updater();
+  cus->CheckForUpdateSoon(component_id);
+}
+
+void ComponentsDOMHandler::LoadComponents() {
+  ComponentUpdateService* cus = g_browser_process->component_updater();
+  std::vector<CrxComponentInfo> components;
+  cus->GetComponents(&components);
+
+  // Construct DictionaryValues to return to UI.
+  ListValue* component_list = new ListValue();
+  for (size_t j = 0; j < components.size(); ++j) {
+    const CrxComponentInfo& component = components[j];
+
+    DictionaryValue* component_entry = new DictionaryValue();
+    component_entry->SetString("id", component.id);
+    component_entry->SetString("name", component.name);
+    component_entry->SetString("version", component.version);
+
+    component_list->Append(component_entry);
+  }
+
+  DictionaryValue results;
+  results.Set("components", component_list);
+  web_ui()->CallJavascriptFunction("returnComponentsData", results);
+}
+
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// ComponentsUI
+//
+///////////////////////////////////////////////////////////////////////////////
+
+ComponentsUI::ComponentsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
+  web_ui->AddMessageHandler(new ComponentsDOMHandler());
+
+  // Set up the chrome://components/ source.
+  Profile* profile = Profile::FromWebUI(web_ui);
+  content::WebUIDataSource::Add(profile, CreateComponentsUIHTMLSource());
+}
+
+// static
+base::RefCountedMemory* ComponentsUI::GetFaviconResourceBytes(
+      ui::ScaleFactor scale_factor) {
+  return ResourceBundle::GetSharedInstance().
+      LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor);
+}
diff --git a/chrome/browser/ui/webui/components_ui.h b/chrome/browser/ui/webui/components_ui.h
new file mode 100644
index 0000000..afe57cb
--- /dev/null
+++ b/chrome/browser/ui/webui/components_ui.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_UI_WEBUI_COMPONENTS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_COMPONENTS_UI_H_
+
+#include "content/public/browser/web_ui_controller.h"
+#include "ui/base/layout.h"
+
+namespace base {
+class RefCountedMemory;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+class ComponentsUI : public content::WebUIController {
+ public:
+  explicit ComponentsUI(content::WebUI* web_ui);
+
+  static base::RefCountedMemory* GetFaviconResourceBytes(
+      ui::ScaleFactor scale_factor);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ComponentsUI);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBUI_COMPONENTS_UI_H_
diff --git a/chrome/browser/ui/webui/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads_dom_handler.cc
index 6415b54..028dc58 100644
--- a/chrome/browser/ui/webui/downloads_dom_handler.cc
+++ b/chrome/browser/ui/webui/downloads_dom_handler.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/download/download_danger_prompt.h"
+#include "chrome/browser/download/download_field_trial.h"
 #include "chrome/browser/download/download_history.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/download/download_prefs.h"
@@ -182,7 +183,7 @@
                download_item->GetDangerType() ==
                    content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED);
         std::string trial_condition =
-            base::FieldTrialList::FindFullName(download_util::kFinchTrialName);
+            base::FieldTrialList::FindFullName(kMalwareWarningFinchTrialName);
         const char* danger_type_value =
             GetDangerTypeString(download_item->GetDangerType());
         file_value->SetString("danger_type", danger_type_value);
@@ -193,8 +194,8 @@
           if (danger_type == content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
               danger_type == content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
               danger_type == content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST) {
-            finch_string = download_util::AssembleMalwareFinchString(
-                trial_condition, file_name);
+            finch_string =
+                AssembleMalwareFinchString(trial_condition, file_name);
           }
           file_value->SetString("finch_string", finch_string);
         }
@@ -205,7 +206,7 @@
       }
 
       file_value->SetString("progress_status_text",
-          download_util::GetProgressStatusText(download_item));
+                            download_model.GetTabProgressStatusText());
 
       file_value->SetInteger("percent",
           static_cast<int>(download_item->PercentComplete()));
@@ -217,7 +218,7 @@
       file_value->SetString("state", "INTERRUPTED");
 
       file_value->SetString("progress_status_text",
-          download_util::GetProgressStatusText(download_item));
+                            download_model.GetTabProgressStatusText());
 
       file_value->SetInteger("percent",
           static_cast<int>(download_item->PercentComplete()));
diff --git a/chrome/browser/ui/webui/extensions/command_handler.cc b/chrome/browser/ui/webui/extensions/command_handler.cc
index d99e9f9..9b30ff6 100644
--- a/chrome/browser/ui/webui/extensions/command_handler.cc
+++ b/chrome/browser/ui/webui/extensions/command_handler.cc
@@ -71,7 +71,7 @@
   DictionaryValue results;
   GetAllCommands(&results);
   web_ui()->CallJavascriptFunction(
-      "ExtensionCommandsOverlay.returnExtensionsData", results);
+      "extensions.ExtensionCommandsOverlay.returnExtensionsData", results);
 }
 
 void CommandHandler::HandleRequestExtensionsData(const ListValue* args) {
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
index ed1f622..8b40319 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.js
@@ -26,11 +26,11 @@
   assertEquals(this.browsePreload, document.location.href);
 
   // This dialog should be hidden at first.
-  assertFalse($('packExtensionOverlay').classList.contains('showing'));
+  assertFalse($('pack-extension-overlay').classList.contains('showing'));
 
   // Show the dialog, which triggers a chrome.send() for metrics purposes.
   cr.dispatchSimpleEvent($('pack-extension'), 'click');
-  assertTrue($('packExtensionOverlay').classList.contains('showing'));
+  assertTrue($('pack-extension-overlay').classList.contains('showing'));
 });
 
 /**
@@ -55,5 +55,5 @@
     function() {
   // Just navigating to the page should trigger the chrome.send().
   assertEquals(this.browsePreload, document.location.href);
-  assertTrue($('extensionCommandsOverlay').classList.contains('showing'));
+  assertTrue($('extension-commands-overlay').classList.contains('showing'));
 });
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index ac1482c..37c8d21 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_disabled_ui.h"
@@ -88,11 +89,13 @@
 ExtensionPage::ExtensionPage(const GURL& url,
                              int render_process_id,
                              int render_view_id,
-                             bool incognito)
+                             bool incognito,
+                             bool generated_background_page)
     : url(url),
       render_process_id(render_process_id),
       render_view_id(render_view_id),
-      incognito(incognito) {
+      incognito(incognito),
+      generated_background_page(generated_background_page) {
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -141,11 +144,11 @@
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
-DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
+base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
     const Extension* extension,
     const std::vector<ExtensionPage>& pages,
     const ExtensionWarningService* warning_service) {
-  DictionaryValue* extension_data = new DictionaryValue();
+  base::DictionaryValue* extension_data = new base::DictionaryValue();
   bool enabled = extension_service_->IsExtensionEnabled(extension->id());
   GetExtensionBasicInfo(extension, enabled, extension_data);
 
@@ -207,10 +210,10 @@
   }
 
   // Add views
-  ListValue* views = new ListValue;
+  base::ListValue* views = new base::ListValue;
   for (std::vector<ExtensionPage>::const_iterator iter = pages.begin();
        iter != pages.end(); ++iter) {
-    DictionaryValue* view_value = new DictionaryValue;
+    base::DictionaryValue* view_value = new base::DictionaryValue;
     if (iter->url.scheme() == kExtensionScheme) {
       // No leading slash.
       view_value->SetString("path", iter->url.path().substr(1));
@@ -221,6 +224,8 @@
     view_value->SetInteger("renderViewId", iter->render_view_id);
     view_value->SetInteger("renderProcessId", iter->render_process_id);
     view_value->SetBoolean("incognito", iter->incognito);
+    view_value->SetBoolean("generatedBackgroundPage",
+                           iter->generated_background_page);
     views->Append(view_value);
   }
   extension_data->Set("views", views);
@@ -237,10 +242,10 @@
         warning_service->GetWarningMessagesForExtension(extension->id());
 
     if (!warnings.empty()) {
-      ListValue* warnings_list = new ListValue;
+      base::ListValue* warnings_list = new base::ListValue;
       for (std::vector<std::string>::const_iterator iter = warnings.begin();
            iter != warnings.end(); ++iter) {
-        warnings_list->Append(Value::CreateStringValue(*iter));
+        warnings_list->Append(base::Value::CreateStringValue(*iter));
       }
       extension_data->Set("warnings", warnings_list);
     }
@@ -251,11 +256,10 @@
     const std::vector<InstallWarning>& install_warnings =
         extension->install_warnings();
     if (!install_warnings.empty()) {
-      scoped_ptr<ListValue> list(new ListValue());
+      scoped_ptr<base::ListValue> list(new base::ListValue());
       for (std::vector<InstallWarning>::const_iterator it =
                install_warnings.begin(); it != install_warnings.end(); ++it) {
-        DictionaryValue* item = new DictionaryValue();
-        item->SetBoolean("isHTML", it->format == InstallWarning::FORMAT_HTML);
+        base::DictionaryValue* item = new base::DictionaryValue();
         item->SetString("message", it->message);
         list->Append(item);
       }
@@ -296,6 +300,8 @@
       l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO));
   source->AddString("viewInactive",
       l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE));
+  source->AddString("backgroundPage",
+      l10n_util::GetStringUTF16(IDS_EXTENSIONS_BACKGROUND_PAGE));
   source->AddString("extensionSettingsEnable",
       l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE));
   source->AddString("extensionSettingsEnabled",
@@ -567,13 +573,13 @@
 }
 
 void ExtensionSettingsHandler::HandleRequestExtensionsData(
-    const ListValue* args) {
-  DictionaryValue results;
+    const base::ListValue* args) {
+  base::DictionaryValue results;
 
   Profile* profile = Profile::FromWebUI(web_ui());
 
   // Add the extensions to the results structure.
-  ListValue* extensions_list = new ListValue();
+  base::ListValue* extensions_list = new base::ListValue();
 
   ExtensionWarningService* warnings =
       ExtensionSystem::Get(profile)->warning_service();
@@ -625,25 +631,44 @@
       extension_service_->extension_prefs()->ExtensionsBlacklistedByDefault();
   results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled);
 
-  web_ui()->CallJavascriptFunction("ExtensionSettings.returnExtensionsData",
-                                   results);
+  web_ui()->CallJavascriptFunction(
+      "extensions.ExtensionSettings.returnExtensionsData", results);
 
   MaybeRegisterForNotifications();
 }
 
 void ExtensionSettingsHandler::HandleToggleDeveloperMode(
-    const ListValue* args) {
+    const base::ListValue* args) {
   Profile* profile = Profile::FromWebUI(web_ui());
   if (profile->IsManaged())
     return;
 
   bool developer_mode =
-      profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
-  profile->GetPrefs()->SetBoolean(
-      prefs::kExtensionsUIDeveloperMode, !developer_mode);
+      !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode);
+  profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode,
+                                  developer_mode);
+
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kAppsDevtool))
+    return;
+
+  base::FilePath apps_debugger_path(FILE_PATH_LITERAL("apps_debugger"));
+  if (developer_mode) {
+    profile->GetExtensionService()->component_loader()->Add(
+        IDR_APPS_DEBUGGER_MANIFEST,
+        apps_debugger_path);
+  } else {
+    std::string extension_id =
+        profile->GetExtensionService()->component_loader()->GetExtensionID(
+            IDR_APPS_DEBUGGER_MANIFEST,
+            apps_debugger_path);
+    scoped_refptr<const Extension> extension(
+        profile->GetExtensionService()->GetInstalledExtension(extension_id));
+    profile->GetExtensionService()->component_loader()->Remove(extension_id);
+  }
 }
 
-void ExtensionSettingsHandler::HandleInspectMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleInspectMessage(
+    const base::ListValue* args) {
   std::string extension_id;
   std::string render_process_id_str;
   std::string render_view_id_str;
@@ -683,7 +708,8 @@
   DevToolsWindow::OpenDevToolsWindow(host);
 }
 
-void ExtensionSettingsHandler::HandleLaunchMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleLaunchMessage(
+    const base::ListValue* args) {
   CHECK_EQ(1U, args->GetSize());
   std::string extension_id;
   CHECK(args->GetString(0, &extension_id));
@@ -695,7 +721,8 @@
                                                   NEW_WINDOW));
 }
 
-void ExtensionSettingsHandler::HandleRestartMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleRestartMessage(
+    const base::ListValue* args) {
   CHECK_EQ(1U, args->GetSize());
   std::string extension_id;
   CHECK(args->GetString(0, &extension_id));
@@ -703,13 +730,15 @@
       extension_id);
 }
 
-void ExtensionSettingsHandler::HandleReloadMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleReloadMessage(
+    const base::ListValue* args) {
   std::string extension_id = UTF16ToUTF8(ExtractStringValue(args));
   CHECK(!extension_id.empty());
   extension_service_->ReloadExtension(extension_id);
 }
 
-void ExtensionSettingsHandler::HandleEnableMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleEnableMessage(
+    const base::ListValue* args) {
   CHECK_EQ(2U, args->GetSize());
   std::string extension_id, enable_str;
   CHECK(args->GetString(0, &extension_id));
@@ -755,7 +784,7 @@
 }
 
 void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
-    const ListValue* args) {
+    const base::ListValue* args) {
   CHECK_EQ(2U, args->GetSize());
   std::string extension_id, enable_str;
   CHECK(args->GetString(0, &extension_id));
@@ -783,7 +812,7 @@
 }
 
 void ExtensionSettingsHandler::HandleAllowFileAccessMessage(
-    const ListValue* args) {
+    const base::ListValue* args) {
   CHECK_EQ(2U, args->GetSize());
   std::string extension_id, allow_str;
   CHECK(args->GetString(0, &extension_id));
@@ -803,7 +832,8 @@
   extension_service_->SetAllowFileAccess(extension, allow_str == "true");
 }
 
-void ExtensionSettingsHandler::HandleUninstallMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleUninstallMessage(
+    const base::ListValue* args) {
   CHECK_EQ(1U, args->GetSize());
   std::string extension_id;
   CHECK(args->GetString(0, &extension_id));
@@ -826,7 +856,8 @@
   GetExtensionUninstallDialog()->ConfirmUninstall(extension);
 }
 
-void ExtensionSettingsHandler::HandleOptionsMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleOptionsMessage(
+    const base::ListValue* args) {
   const Extension* extension = GetActiveExtension(args);
   if (!extension || ManifestURL::GetOptionsPage(extension).is_empty())
     return;
@@ -834,7 +865,8 @@
       chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
 }
 
-void ExtensionSettingsHandler::HandlePermissionsMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandlePermissionsMessage(
+    const base::ListValue* args) {
   std::string extension_id(UTF16ToUTF8(ExtractStringValue(args)));
   CHECK(!extension_id.empty());
   const Extension* extension =
@@ -859,7 +891,8 @@
   prompt_->ReviewPermissions(this, extension, retained_file_paths);
 }
 
-void ExtensionSettingsHandler::HandleShowButtonMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleShowButtonMessage(
+    const base::ListValue* args) {
   const Extension* extension = GetActiveExtension(args);
   if (!extension)
     return;
@@ -867,7 +900,8 @@
       extension_service_->extension_prefs(), extension->id(), true);
 }
 
-void ExtensionSettingsHandler::HandleAutoUpdateMessage(const ListValue* args) {
+void ExtensionSettingsHandler::HandleAutoUpdateMessage(
+    const base::ListValue* args) {
   ExtensionUpdater* updater = extension_service_->updater();
   if (updater) {
     ExtensionUpdater::CheckParams params;
@@ -877,7 +911,7 @@
 }
 
 void ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage(
-    const ListValue* args) {
+    const base::ListValue* args) {
   DCHECK(args->empty());
 
   string16 select_title =
@@ -902,13 +936,13 @@
 }
 
 void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
-  ListValue arguments;
-  arguments.Append(Value::CreateStringValue(message));
+  base::ListValue arguments;
+  arguments.Append(base::Value::CreateStringValue(message));
   web_ui()->CallJavascriptFunction("alert", arguments);
 }
 
 const Extension* ExtensionSettingsHandler::GetActiveExtension(
-    const ListValue* args) {
+    const base::ListValue* args) {
   std::string extension_id = UTF16ToUTF8(ExtractStringValue(args));
   CHECK(!extension_id.empty());
   return extension_service_->GetExtensionById(extension_id, false);
@@ -987,7 +1021,11 @@
       extension_is_enabled &&
       !process_manager->GetBackgroundHostForExtension(extension->id())) {
     result.push_back(ExtensionPage(
-        BackgroundInfo::GetBackgroundURL(extension), -1, -1, false));
+        BackgroundInfo::GetBackgroundURL(extension),
+        -1,
+        -1,
+        false,
+        BackgroundInfo::HasGeneratedBackgroundPage(extension)));
   }
 
   // Repeat for the incognito process, if applicable. Don't try to get
@@ -1005,7 +1043,11 @@
         extension_is_enabled &&
         !process_manager->GetBackgroundHostForExtension(extension->id())) {
       result.push_back(ExtensionPage(
-          BackgroundInfo::GetBackgroundURL(extension), -1, -1, true));
+          BackgroundInfo::GetBackgroundURL(extension),
+          -1,
+          -1,
+          true,
+          BackgroundInfo::HasGeneratedBackgroundPage(extension)));
     }
   }
 
@@ -1029,7 +1071,7 @@
     content::RenderProcessHost* process = host->GetProcess();
     result->push_back(
         ExtensionPage(url, process->GetID(), host->GetRoutingID(),
-                      process->GetBrowserContext()->IsOffTheRecord()));
+                      process->GetBrowserContext()->IsOffTheRecord(), false));
   }
 }
 
@@ -1052,7 +1094,7 @@
     result->push_back(
         ExtensionPage(web_contents->GetURL(), process->GetID(),
                       host->GetRoutingID(),
-                      process->GetBrowserContext()->IsOffTheRecord()));
+                      process->GetBrowserContext()->IsOffTheRecord(), false));
   }
 }
 
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.h b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
index e3188e3..07d45ce 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
@@ -52,11 +52,13 @@
   ExtensionPage(const GURL& url,
                 int render_process_id,
                 int render_view_id,
-                bool incognito);
+                bool incognito,
+                bool generated_background_page);
   GURL url;
   int render_process_id;
   int render_view_id;
   bool incognito;
+  bool generated_background_page;
 };
 
 // Extension Settings UI handler.
diff --git a/chrome/browser/ui/webui/extensions/pack_extension_handler.cc b/chrome/browser/ui/webui/extensions/pack_extension_handler.cc
index 7653446..4bb3e4e 100644
--- a/chrome/browser/ui/webui/extensions/pack_extension_handler.cc
+++ b/chrome/browser/ui/webui/extensions/pack_extension_handler.cc
@@ -73,7 +73,7 @@
       UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(
           crx_file, pem_file))));
   web_ui()->CallJavascriptFunction(
-      "PackExtensionOverlay.showSuccessMessage", arguments);
+      "extensions.PackExtensionOverlay.showSuccessMessage", arguments);
 }
 
 void PackExtensionHandler::OnPackFailure(const std::string& error,
@@ -85,8 +85,8 @@
     base::FundamentalValue overwrite_flag(ExtensionCreator::kOverwriteCRX);
 
     web_ui()->CallJavascriptFunction(
-        "ExtensionSettings.askToOverrideWarning", error_str, extension_path_str,
-            key_path_str, overwrite_flag);
+        "extensions.ExtensionSettings.askToOverrideWarning",
+        error_str, extension_path_str, key_path_str, overwrite_flag);
   } else {
     ShowAlert(error);
   }
@@ -202,7 +202,8 @@
 void PackExtensionHandler::ShowAlert(const std::string& message) {
   ListValue arguments;
   arguments.Append(Value::CreateStringValue(message));
-  web_ui()->CallJavascriptFunction("PackExtensionOverlay.showError", arguments);
+  web_ui()->CallJavascriptFunction(
+      "extensions.PackExtensionOverlay.showError", arguments);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/ui/webui/feedback_ui.cc b/chrome/browser/ui/webui/feedback_ui.cc
index 72863a6..8579ea9 100644
--- a/chrome/browser/ui/webui/feedback_ui.cc
+++ b/chrome/browser/ui/webui/feedback_ui.cc
@@ -89,6 +89,8 @@
 const char kTimestampParameter[] = "timestamp=";
 const char kTraceIdParameter[] = "traceId=";
 
+const char kPerformanceCategoryTag[] = "Performance";
+
 const size_t kMaxSavedScreenshots = 2;
 size_t kMaxNumScanFiles = 1000;
 
@@ -623,6 +625,8 @@
   (*i++)->GetAsString(&trace_id_str);
   int trace_id = 0;
   base::StringToInt(trace_id_str, &trace_id);
+  if (trace_id)
+    category_tag = kPerformanceCategoryTag;
 
   std::string attached_filename;
   scoped_ptr<std::string> attached_filedata;
diff --git a/chrome/browser/ui/webui/feedback_ui.h b/chrome/browser/ui/webui/feedback_ui.h
deleted file mode 100644
index 4bef57d..0000000
--- a/chrome/browser/ui/webui/feedback_ui.h
+++ /dev/null
@@ -1,32 +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_UI_WEBUI_FEEDBACK_UI_H_
-#define CHROME_BROWSER_UI_WEBUI_FEEDBACK_UI_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "ui/web_dialogs/web_dialog_ui.h"
-
-namespace base {
-class FilePath;
-}
-
-class FeedbackUI : public ui::WebDialogUI {
- public:
-  explicit FeedbackUI(content::WebUI* web_ui);
-
-#if defined(OS_CHROMEOS)
-  static void GetMostRecentScreenshots(
-      const base::FilePath& filepath,
-      std::vector<std::string>* saved_screenshots,
-      size_t max_saved);
-#endif
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FeedbackUI);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_FEEDBACK_UI_H_
diff --git a/chrome/browser/ui/webui/feedback_ui_unittest.cc b/chrome/browser/ui/webui/feedback_ui_unittest.cc
deleted file mode 100644
index 6bcf7d3..0000000
--- a/chrome/browser/ui/webui/feedback_ui_unittest.cc
+++ /dev/null
@@ -1,89 +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 tests in this file are chromeos only.
-
-#include "chrome/browser/ui/webui/feedback_ui.h"
-
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// This macro helps avoid wrapped lines in the test structs.
-#define FPL(x) FILE_PATH_LITERAL(x)
-
-namespace {
-
-// Simple function to create a file with |filename|.
-void CreateFile(const base::FilePath& filename) {
-  FILE* fp = file_util::OpenFile(filename, "w");
-  ASSERT_TRUE(fp != NULL);
-  file_util::CloseFile(fp);
-}
-
-std::string GetScreenshotFilename(const std::string timestamp) {
-  return std::string("Screenshot ") + timestamp + std::string(".png");
-}
-
-std::string GetScreenshotUrl(const std::string timestamp) {
-  return std::string("chrome://screenshots/saved/") +
-      GetScreenshotFilename(timestamp);
-}
-
-class FeedbackUITest : public testing::Test {
- public:
-  FeedbackUITest() {}
-  virtual ~FeedbackUITest() {}
-  virtual void SetUp() OVERRIDE {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-  }
- protected:
-  void CreateScreenshotFile(const std::string& timestamp) {
-    base::FilePath filepath = temp_dir_.path().Append(
-        FILE_PATH_LITERAL(GetScreenshotFilename(timestamp)));
-    ASSERT_NO_FATAL_FAILURE(CreateFile(filepath));
-  }
-
-  base::ScopedTempDir temp_dir_;
-  std::vector<std::string> saved_screenshots_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FeedbackUITest);
-};
-
-TEST_F(FeedbackUITest, GetMostRecentScreenshotsNoScreenShot) {
-  // Create a random file.
-  base::FilePath filepath =
-      temp_dir_.path().Append(FILE_PATH_LITERAL("garbage.png"));
-  ASSERT_NO_FATAL_FAILURE(CreateFile(filepath));
-  // Expect getting no screenshot.
-  FeedbackUI::GetMostRecentScreenshots(
-      temp_dir_.path(), &saved_screenshots_, 2);
-  ASSERT_TRUE(saved_screenshots_.empty());
-}
-
-TEST_F(FeedbackUITest, GetMostRecentScreenshotsOneScreenShot) {
-  // Create 1 screenshot.
-  ASSERT_NO_FATAL_FAILURE(CreateScreenshotFile("20120416-152908"));
-  // Expect getting 1 screenshot.
-  FeedbackUI::GetMostRecentScreenshots(
-      temp_dir_.path(), &saved_screenshots_, 2);
-  ASSERT_EQ(1U, saved_screenshots_.size());
-  ASSERT_EQ(GetScreenshotUrl("20120416-152908"), saved_screenshots_[0]);
-}
-
-TEST_F(FeedbackUITest, GetMostRecentScreenshotsManyScreenShots) {
-  // Create 2 screenshots.
-  ASSERT_NO_FATAL_FAILURE(CreateScreenshotFile("20120416-152908"));
-  ASSERT_NO_FATAL_FAILURE(CreateScreenshotFile("20120416-162908"));
-  ASSERT_NO_FATAL_FAILURE(CreateScreenshotFile("20120413-152908"));
-  // Expect getting most recent 2 screenshots.
-  FeedbackUI::GetMostRecentScreenshots(
-      temp_dir_.path(), &saved_screenshots_, 2);
-  ASSERT_EQ(2U, saved_screenshots_.size());
-  ASSERT_EQ(GetScreenshotUrl("20120416-162908"), saved_screenshots_[0]);
-  ASSERT_EQ(GetScreenshotUrl("20120416-152908"), saved_screenshots_[1]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index a4eaa3d..d580104 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -89,10 +89,12 @@
 static const char kUrlField[]  = "url";
 static const char kNameField[]  = "name";
 static const char kFaviconUrlField[] = "faviconUrl";
+static const char kDescription[] = "description";
 static const char kPidField[]  = "pid";
 static const char kAdbSerialField[] = "adbSerial";
 static const char kAdbModelField[] = "adbModel";
 static const char kAdbBrowserProductField[] = "adbBrowserProduct";
+static const char kAdbBrowserPackageField[] = "adbBrowserPackage";
 static const char kAdbBrowserVersionField[] = "adbBrowserVersion";
 static const char kAdbGlobalIdField[] = "adbGlobalId";
 static const char kAdbBrowsersField[] = "browsers";
@@ -105,6 +107,7 @@
     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) {
@@ -117,6 +120,7 @@
   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);
 
   return target_data;
 }
@@ -167,6 +171,7 @@
                                url,
                                title,
                                favicon_url,
+                               "",
                                rvh->GetProcess()->GetID(),
                                rvh->GetRoutingID());
 }
@@ -405,6 +410,7 @@
           worker_info[i].url,
           UTF16ToUTF8(worker_info[i].name),
           GURL(),
+          "",
           worker_info[i].process_id,
           worker_info[i].route_id,
           worker_info[i].handle));
@@ -598,6 +604,7 @@
       DevToolsAdbBridge::RemoteBrowser* browser = bit->get();
       DictionaryValue* browser_data = new DictionaryValue();
       browser_data->SetString(kAdbBrowserProductField, browser->product());
+      browser_data->SetString(kAdbBrowserPackageField, browser->package());
       browser_data->SetString(kAdbBrowserVersionField, browser->version());
       std::string browser_id = base::StringPrintf(
           "browser:%s:%s:%s",
@@ -616,7 +623,7 @@
         DictionaryValue* page_data = BuildTargetDescriptor(
             kAdbTargetType, page->attached(),
             GURL(page->url()), page->title(), GURL(page->favicon_url()),
-            0, 0);
+            page->description(), 0, 0);
         std::string page_id = base::StringPrintf("page:%s:%s:%s",
             device->serial().c_str(),
             browser->socket().c_str(),
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc
index e7a81d4..8906099 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui.cc
@@ -10,6 +10,7 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "grit/browser_resources.h"
+#include "grit/generated_resources.h"
 
 namespace {
 
@@ -20,6 +21,35 @@
   source->SetDefaultResource(IDR_LOCAL_DISCOVERY_HTML);
   source->AddResourcePath("local_discovery.css", IDR_LOCAL_DISCOVERY_CSS);
   source->AddResourcePath("local_discovery.js", IDR_LOCAL_DISCOVERY_JS);
+
+  source->SetUseJsonJSFormatV2();
+  source->AddLocalizedString("serviceName",
+                             IDS_LOCAL_DISCOVERY_SERVICE_NAME);
+  source->AddLocalizedString("serviceDomain",
+                             IDS_LOCAL_DISCOVERY_SERVICE_DOMAIN);
+  source->AddLocalizedString("servicePort",
+                             IDS_LOCAL_DISCOVERY_SERVICE_PORT);
+  source->AddLocalizedString("serviceIp",
+                             IDS_LOCAL_DISCOVERY_SERVICE_IP);
+  source->AddLocalizedString("serviceLastseen",
+                             IDS_LOCAL_DISCOVERY_SERVICE_LASTSEEN);
+  source->AddLocalizedString("serviceRegister",
+                             IDS_LOCAL_DISCOVERY_SERVICE_REGISTER);
+  source->AddLocalizedString("registeringService",
+                             IDS_LOCAL_DISCOVERY_REGISTERING_SERVICE);
+  source->AddLocalizedString("registrationFailed",
+                             IDS_LOCAL_DISCOVERY_REGISTRATION_FAILED);
+  source->AddLocalizedString("registrationSucceeded",
+                             IDS_LOCAL_DISCOVERY_REGISTRATION_SUCCEEDED);
+  source->AddLocalizedString("registered",
+                             IDS_LOCAL_DISCOVERY_REGISTERED);
+  source->AddLocalizedString("infoStarted", IDS_LOCAL_DISCOVERY_INFO_STARTED);
+  source->AddLocalizedString("infoFailed", IDS_LOCAL_DISCOVERY_INFO_FAILED);
+  source->AddLocalizedString("serviceInfo",
+                             IDS_LOCAL_DISCOVERY_SERVICE_INFO);
+
+  source->SetJsonPath("strings.js");
+
   return source;
 }
 
@@ -33,5 +63,5 @@
 
   // TODO(gene): Use LocalDiscoveryUIHandler to send updated to the devices
   // page. For example
-  // web_ui->AddMessageHandler(new LocalDiscoveryUIHandler());
+  web_ui->AddMessageHandler(local_discovery::LocalDiscoveryUIHandler::Create());
 }
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
new file mode 100644
index 0000000..8282ece
--- /dev/null
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.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/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/ui_test_utils.cc"
+#include "chrome/test/base/web_ui_browsertest.h"
+
+namespace local_discovery {
+
+namespace {
+
+const char kChromeDevicesPage[] = "chrome://devices";
+const char kSampleServiceName[] = "myService._privet._tcp.local";
+const char kSampleDeviceID[] = "MyFakeID";
+const char kSampleDeviceHost[] = "myservice.local";
+
+class TestMessageLoopCondition {
+ public:
+  TestMessageLoopCondition() : signaled_(false),
+                               waiting_(false) {
+  }
+
+  ~TestMessageLoopCondition() {
+  }
+
+  // Signal a waiting method that it can continue executing.
+  void Signal() {
+    signaled_ = true;
+    if (waiting_)
+      base::MessageLoop::current()->Quit();
+  }
+
+  // Pause execution and recursively run the message loop until |Signal()| is
+  // called. Do not pause if |Signal()| has already been called.
+  void Wait() {
+    if (!signaled_) {
+      waiting_ = true;
+      base::MessageLoop::current()->Run();
+      waiting_ = false;
+    }
+  }
+
+ private:
+  bool signaled_;
+  bool waiting_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMessageLoopCondition);
+};
+
+class FakePrivetDeviceLister : public PrivetDeviceLister {
+ public:
+  explicit FakePrivetDeviceLister(const base::Closure& discover_devices_called)
+      : discover_devices_called_(discover_devices_called) {
+  }
+
+  virtual ~FakePrivetDeviceLister() {
+  }
+
+  // PrivetDeviceLister implementation.
+  virtual void Start() OVERRIDE {
+  }
+
+  virtual void DiscoverNewDevices(bool force_referesh) OVERRIDE {
+    discover_devices_called_.Run();
+  }
+
+  void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+  Delegate* delegate() { return delegate_; }
+
+ private:
+  Delegate* delegate_;
+  base::Closure discover_devices_called_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakePrivetDeviceLister);
+};
+
+class FakeLocalDiscoveryUIFactory : public LocalDiscoveryUIHandler::Factory {
+ public:
+  explicit FakeLocalDiscoveryUIFactory(
+      scoped_ptr<FakePrivetDeviceLister> privet_lister) {
+    owned_privet_lister_ = privet_lister.Pass();
+    privet_lister_ = owned_privet_lister_.get();
+    LocalDiscoveryUIHandler::SetFactory(this);
+  }
+
+  virtual ~FakeLocalDiscoveryUIFactory() {
+    LocalDiscoveryUIHandler::SetFactory(NULL);
+  }
+
+  // LocalDiscoveryUIHandler::Factory implementation.
+  virtual LocalDiscoveryUIHandler* CreateLocalDiscoveryUIHandler() OVERRIDE {
+    DCHECK(owned_privet_lister_);  // This factory is a one-use factory.
+    scoped_ptr<LocalDiscoveryUIHandler> handler(
+        new LocalDiscoveryUIHandler(
+            owned_privet_lister_.PassAs<PrivetDeviceLister>()));
+    privet_lister_->set_delegate(handler.get());
+    return handler.release();
+  }
+
+  FakePrivetDeviceLister* privet_lister() { return privet_lister_; }
+
+ private:
+  // FakePrivetDeviceLister is owned either by the factory or, once it creates a
+  // LocalDiscoveryUI, by the LocalDiscoveryUI.  |privet_lister_| points to the
+  // FakePrivetDeviceLister whereas |owned_privet_lister_| manages the ownership
+  // of the pointer when it is owned by the factory.
+  scoped_ptr<FakePrivetDeviceLister> owned_privet_lister_;
+  FakePrivetDeviceLister* privet_lister_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeLocalDiscoveryUIFactory);
+};
+
+class LocalDiscoveryUITest : public WebUIBrowserTest {
+ public:
+  LocalDiscoveryUITest() {
+  }
+  virtual ~LocalDiscoveryUITest() {
+  }
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    WebUIBrowserTest::SetUpOnMainThread();
+
+    scoped_ptr<FakePrivetDeviceLister> fake_lister;
+    fake_lister.reset(new FakePrivetDeviceLister(
+        base::Bind(&TestMessageLoopCondition::Signal,
+                   base::Unretained(&condition_devices_listed_))));
+
+    ui_factory_.reset(new FakeLocalDiscoveryUIFactory(
+        fake_lister.Pass()));
+
+    AddLibrary(base::FilePath(FILE_PATH_LITERAL("local_discovery_ui_test.js")));
+  }
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    WebUIBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kEnableDeviceDiscovery);
+  }
+
+  FakeLocalDiscoveryUIFactory* ui_factory() { return ui_factory_.get(); }
+  TestMessageLoopCondition& condition_devices_listed() {
+    return condition_devices_listed_;
+  }
+
+ private:
+  scoped_ptr<FakeLocalDiscoveryUIFactory> ui_factory_;
+  TestMessageLoopCondition condition_devices_listed_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalDiscoveryUITest);
+};
+
+IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, EmptyTest) {
+  ui_test_utils::NavigateToURL(browser(), GURL(kChromeDevicesPage));
+  condition_devices_listed().Wait();
+  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkTableHasNoRows"));
+}
+
+IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, AddRowTest) {
+  ui_test_utils::NavigateToURL(browser(), GURL(kChromeDevicesPage));
+  condition_devices_listed().Wait();
+  DeviceDescription description;
+
+  description.id = kSampleDeviceID;
+  description.address = net::HostPortPair(kSampleDeviceHost, 8888);
+  description.ip_address.push_back(1);
+  description.ip_address.push_back(2);
+  description.ip_address.push_back(3);
+  description.ip_address.push_back(4);
+
+  ui_factory()->privet_lister()->delegate()->DeviceChanged(
+      true, kSampleServiceName, description);
+
+  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkTableHasOneRow"));
+
+  ui_factory()->privet_lister()->delegate()->DeviceRemoved(
+      kSampleServiceName);
+
+  EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkTableHasNoRows"));
+}
+
+}  // namespace
+
+}  // namespace local_discovery
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 e1f458c..0d26427 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
@@ -5,42 +5,275 @@
 #include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h"
 
 #include "base/bind.h"
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "chrome/browser/local_discovery/privet_device_lister_impl.h"
+#include "chrome/browser/local_discovery/privet_http_impl.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_manager.h"
+#include "chrome/browser/signin/signin_manager_base.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "content/public/browser/web_ui.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/net_util.h"
+#include "net/http/http_status_code.h"
 
-LocalDiscoveryUIHandler::LocalDiscoveryUIHandler()
-    : action_callback_(base::Bind(&LocalDiscoveryUIHandler::OnNewDevice,
-                                  base::Unretained(this))) {
-  content::AddActionCallback(action_callback_);
+namespace local_discovery {
+
+namespace {
+// TODO(noamsml): This is a temporary shim until automated_url is in the
+// response.
+const char kPrivetAutomatedClaimURLFormat[] = "%s/confirm?token=%s";
+
+LocalDiscoveryUIHandler::Factory* g_factory = NULL;
+}  // namespace
+
+LocalDiscoveryUIHandler::LocalDiscoveryUIHandler() {
+}
+
+LocalDiscoveryUIHandler::LocalDiscoveryUIHandler(
+    scoped_ptr<PrivetDeviceLister> privet_lister) {
+  privet_lister.swap(privet_lister_);
 }
 
 LocalDiscoveryUIHandler::~LocalDiscoveryUIHandler() {
-  content::RemoveActionCallback(action_callback_);
+  if (service_discovery_client_.get()) {
+    service_discovery_client_ = NULL;
+    ServiceDiscoveryHostClientFactory::ReleaseClient();
+  }
 }
 
-void LocalDiscoveryUIHandler::RegisterMessages() {}
-
-void LocalDiscoveryUIHandler::OnNewDevice(const std::string& name) {
-  // TODO(gene): Once we receive information about new locally discovered
-  // device, we should add it to the page.
-  // Here is an example how to do it:
-  //
-  // base::StringValue service_name(name);
-  //
-  // base::DictionaryValue info;
-  // info.SetString("domain", "domain.local");
-  // info.SetString("port", "80");
-  // info.SetString("ip", "XXX.XXX.XXX.XXX");
-  // info.SetString("metadata", "metadata\nmetadata");
-  // info.SetString("lastSeen", "unknown");
-  // info.SetString("registered", "not registered");
-  //
-  // base::StringValue domain("domain.local");
-  // base::StringValue port("80");
-  // base::StringValue ip("XXX.XXX.XXX.XXX");
-  // base::StringValue metadata("metadata<br>metadata");
-  // base::StringValue lastSeen("unknown");
-  // base::StringValue registered("not registered");
-  //
-  // web_ui()->CallJavascriptFunction("onServiceUpdate", service_name, info);
+// static
+LocalDiscoveryUIHandler* LocalDiscoveryUIHandler::Create() {
+  if (g_factory) return g_factory->CreateLocalDiscoveryUIHandler();
+  return new LocalDiscoveryUIHandler();
 }
+
+// static
+void LocalDiscoveryUIHandler::SetFactory(Factory* factory) {
+  g_factory = factory;
+}
+
+void LocalDiscoveryUIHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback("start", base::Bind(
+      &LocalDiscoveryUIHandler::HandleStart,
+      base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("registerDevice", base::Bind(
+      &LocalDiscoveryUIHandler::HandleRegisterDevice,
+      base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("info", base::Bind(
+      &LocalDiscoveryUIHandler::HandleInfoRequested,
+      base::Unretained(this)));
+}
+
+void LocalDiscoveryUIHandler::HandleStart(const base::ListValue* args) {
+  // If privet_lister_ is already set, it is a mock used for tests or the result
+  // of a reload.
+  if (!privet_lister_) {
+    service_discovery_client_ = ServiceDiscoveryHostClientFactory::GetClient();
+    privet_lister_.reset(new PrivetDeviceListerImpl(
+        service_discovery_client_.get(), this));
+    privet_http_factory_.reset(new PrivetHTTPAsynchronousFactoryImpl(
+        service_discovery_client_.get(),
+        Profile::FromWebUI(web_ui())->GetRequestContext()));
+  }
+
+  privet_lister_->Start();
+  privet_lister_->DiscoverNewDevices(false);
+}
+
+void LocalDiscoveryUIHandler::HandleRegisterDevice(
+    const base::ListValue* args) {
+  std::string device_name;
+
+  bool rv = args->GetString(0, &device_name);
+  DCHECK(rv);
+
+  privet_resolution_ = privet_http_factory_->CreatePrivetHTTP(
+      device_name,
+      device_descriptions_[device_name].address,
+      base::Bind(&LocalDiscoveryUIHandler::StartRegisterHTTP,
+                 base::Unretained(this)));
+  privet_resolution_->Start();
+}
+
+void LocalDiscoveryUIHandler::HandleInfoRequested(const base::ListValue* args) {
+  std::string device_name;
+  args->GetString(0, &device_name);
+
+  privet_resolution_ = privet_http_factory_->CreatePrivetHTTP(
+      device_name,
+      device_descriptions_[device_name].address,
+      base::Bind(&LocalDiscoveryUIHandler::StartInfoHTTP,
+                 base::Unretained(this)));
+  privet_resolution_->Start();
+}
+
+void LocalDiscoveryUIHandler::StartRegisterHTTP(
+    scoped_ptr<PrivetHTTPClient> http_client) {
+  current_http_client_.swap(http_client);
+
+  if (!current_http_client_) {
+    LogRegisterErrorToWeb("Resolution failed");
+    return;
+  }
+
+  Profile* profile = Profile::FromWebUI(web_ui());
+  SigninManagerBase* signin_manager =
+      SigninManagerFactory::GetForProfileIfExists(profile);
+
+  if (!signin_manager) {
+    LogRegisterErrorToWeb("You must be signed in");
+    return;
+  }
+
+  std::string username = signin_manager->GetAuthenticatedUsername();
+
+  current_register_operation_ =
+      current_http_client_->CreateRegisterOperation(username, this);
+  current_register_operation_->Start();
+}
+
+void LocalDiscoveryUIHandler::StartInfoHTTP(
+    scoped_ptr<PrivetHTTPClient> http_client) {
+  current_http_client_.swap(http_client);
+  if (!current_http_client_) {
+    LogRegisterErrorToWeb("Resolution failed");
+    return;
+  }
+
+  current_info_operation_ = current_http_client_->CreateInfoOperation(this);
+  current_info_operation_->Start();
+}
+
+void LocalDiscoveryUIHandler::OnPrivetRegisterClaimToken(
+    PrivetRegisterOperation* operation,
+    const std::string& token,
+    const GURL& url) {
+  if (device_descriptions_.count(current_http_client_->GetName()) == 0) {
+    LogRegisterErrorToWeb("Device no longer exists");
+    return;
+  }
+
+  GURL automated_claim_url(base::StringPrintf(
+      kPrivetAutomatedClaimURLFormat,
+      device_descriptions_[current_http_client_->GetName()].url.c_str(),
+      token.c_str()));
+
+  Profile* profile = Profile::FromWebUI(web_ui());
+
+  OAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+
+  if (!token_service) {
+    LogRegisterErrorToWeb("Could not get token service");
+    return;
+  }
+
+  confirm_api_call_flow_.reset(new PrivetConfirmApiCallFlow(
+      profile->GetRequestContext(),
+      token_service,
+      automated_claim_url,
+      base::Bind(&LocalDiscoveryUIHandler::OnConfirmDone,
+                 base::Unretained(this))));
+
+  confirm_api_call_flow_->Start();
+}
+
+void LocalDiscoveryUIHandler::OnPrivetRegisterError(
+    PrivetRegisterOperation* operation,
+    const std::string& action,
+    PrivetRegisterOperation::FailureReason reason,
+    int printer_http_code,
+    const DictionaryValue* json) {
+  // TODO(noamsml): Add detailed error message.
+  LogRegisterErrorToWeb("Registration error");
+}
+
+void LocalDiscoveryUIHandler::OnPrivetRegisterDone(
+    PrivetRegisterOperation* operation,
+    const std::string& device_id) {
+  current_register_operation_.reset();
+  current_http_client_.reset();
+
+  LogRegisterDoneToWeb(device_id);
+}
+
+void LocalDiscoveryUIHandler::OnConfirmDone(
+    PrivetConfirmApiCallFlow::Status status) {
+  if (status == PrivetConfirmApiCallFlow::SUCCESS) {
+    DLOG(INFO) << "Confirm success.";
+    confirm_api_call_flow_.reset();
+    current_register_operation_->CompleteRegistration();
+  } else {
+    // TODO(noamsml): Add detailed error message.
+    LogRegisterErrorToWeb("Confirm error");
+  }
+}
+
+void LocalDiscoveryUIHandler::DeviceChanged(
+    bool added,
+    const std::string& name,
+    const DeviceDescription& description) {
+  device_descriptions_[name] = description;
+
+  base::StringValue service_name(name);
+  base::DictionaryValue info;
+  info.SetString("domain", description.address.host());
+  info.SetInteger("port", description.address.port());
+  std::string ip_addr_string;
+  if (!description.ip_address.empty())
+    ip_addr_string = net::IPAddressToString(description.ip_address);
+
+  info.SetString("ip", ip_addr_string);
+  info.SetString("lastSeen", "unknown");
+  info.SetBoolean("registered", !description.id.empty());
+
+  web_ui()->CallJavascriptFunction("local_discovery.onServiceUpdate",
+                                   service_name, info);
+}
+
+void LocalDiscoveryUIHandler::DeviceRemoved(const std::string& name) {
+  device_descriptions_.erase(name);
+  scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
+  base::StringValue name_value(name);
+
+  web_ui()->CallJavascriptFunction("local_discovery.onServiceUpdate",
+                                   name_value, *null_value);
+}
+
+void LocalDiscoveryUIHandler::LogRegisterErrorToWeb(const std::string& error) {
+  base::StringValue error_value(error);
+  web_ui()->CallJavascriptFunction("local_discovery.registrationFailed",
+                                   error_value);
+  DLOG(ERROR) << error;
+}
+
+void LocalDiscoveryUIHandler::LogRegisterDoneToWeb(const std::string& id) {
+  base::StringValue id_value(id);
+  web_ui()->CallJavascriptFunction("local_discovery.registrationSuccess",
+                                   id_value);
+  DLOG(INFO) << "Registered " << id;
+}
+
+void LocalDiscoveryUIHandler::LogInfoErrorToWeb(const std::string& error) {
+  base::StringValue error_value(error);
+  web_ui()->CallJavascriptFunction("local_discovery.infoFailed", error_value);
+  LOG(ERROR) << error;
+}
+
+void LocalDiscoveryUIHandler::OnPrivetInfoDone(
+    PrivetInfoOperation* operation,
+    int http_code,
+    const base::DictionaryValue* json_value) {
+  if (http_code != net::HTTP_OK || !json_value) {
+    LogInfoErrorToWeb(base::StringPrintf("HTTP error %d", http_code));
+    return;
+  }
+
+  web_ui()->CallJavascriptFunction("local_discovery.renderInfo", *json_value);
+}
+
+}  // namespace local_discovery
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 f2b7eec..42b594e 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
@@ -5,29 +5,134 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_LOCAL_DISCOVERY_LOCAL_DISCOVERY_UI_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_LOCAL_DISCOVERY_LOCAL_DISCOVERY_UI_HANDLER_H_
 
+#include <map>
+#include <string>
+
+#include "chrome/browser/local_discovery/privet_confirm_api_flow.h"
+#include "chrome/browser/local_discovery/privet_device_lister.h"
+#include "chrome/browser/local_discovery/privet_http.h"
+#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
+#include "chrome/browser/local_discovery/service_discovery_host_client.h"
+#include "chrome/common/local_discovery/service_discovery_client.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
+namespace local_discovery {
+
 // UI Handler for chrome://devices/
 // It listens to local discovery notifications and passes those notifications
 // into the Javascript to update the page.
-class LocalDiscoveryUIHandler : public content::WebUIMessageHandler {
+class LocalDiscoveryUIHandler : public content::WebUIMessageHandler,
+                                public PrivetRegisterOperation::Delegate,
+                                public PrivetDeviceLister::Delegate,
+                                public PrivetInfoOperation::Delegate {
  public:
+  class Factory {
+   public:
+    virtual ~Factory() {}
+    virtual LocalDiscoveryUIHandler* CreateLocalDiscoveryUIHandler() = 0;
+  };
+
   LocalDiscoveryUIHandler();
+  // This constructor should only used by tests.
+  explicit LocalDiscoveryUIHandler(
+      scoped_ptr<PrivetDeviceLister> privet_lister);
   virtual ~LocalDiscoveryUIHandler();
 
+  static LocalDiscoveryUIHandler* Create();
+  static void SetFactory(Factory* factory);
+
   // WebUIMessageHandler implementation.
-  // Does nothing for now.
   virtual void RegisterMessages() OVERRIDE;
 
- private:
-  // Callback for adding new device to the devices page.
-  // |name| contains a user friendly name of the device.
-  void OnNewDevice(const std::string& name);
+  // PrivetRegisterOperation::Delegate implementation.
+  virtual void OnPrivetRegisterClaimToken(
+      PrivetRegisterOperation* operation,
+      const std::string& token,
+      const GURL& url) OVERRIDE;
 
-  content::ActionCallback action_callback_;
+  virtual void OnPrivetRegisterError(
+      PrivetRegisterOperation* operation,
+      const std::string& action,
+      PrivetRegisterOperation::FailureReason reason,
+      int printer_http_code,
+      const DictionaryValue* json) OVERRIDE;
+
+  virtual void OnPrivetRegisterDone(
+      PrivetRegisterOperation* operation,
+      const std::string& device_id) OVERRIDE;
+
+  // PrivetDeviceLister::Delegate implementation.
+  virtual void DeviceChanged(
+      bool added,
+      const std::string& name,
+      const DeviceDescription& description) OVERRIDE;
+  virtual void DeviceRemoved(const std::string& name) OVERRIDE;
+
+  // PrivetInfoOperation::Delegate implementation:
+  virtual void OnPrivetInfoDone(
+      PrivetInfoOperation* operation,
+      int http_code,
+      const base::DictionaryValue* json_value) OVERRIDE;
+
+ private:
+  // Message handlers:
+  // For registering a device.
+  void HandleRegisterDevice(const base::ListValue* args);
+  // For when the page is ready to recieve device notifications.
+
+  void HandleStart(const base::ListValue* args);
+  // For when info for a device is requested.
+  void HandleInfoRequested(const base::ListValue* args);
+
+  // For when the IP address of the printer has been resolved for registration.
+  void StartRegisterHTTP(scoped_ptr<PrivetHTTPClient> http_client);
+
+  // For when the IP address of the printer has been resolved for registration.
+  void StartInfoHTTP(scoped_ptr<PrivetHTTPClient> http_client);
+
+  // For when the confirm operation on the cloudprint server has finished
+  // executing.
+  void OnConfirmDone(PrivetConfirmApiCallFlow::Status status);
+
+  // Log an error to the web interface.
+  void LogRegisterErrorToWeb(const std::string& error);
+
+  // Log a successful registration to the web inteface.
+  void LogRegisterDoneToWeb(const std::string& id);
+
+  // Log an error to the web interface.
+  void LogInfoErrorToWeb(const std::string& error);
+
+  // The current HTTP client (used for the current operation).
+  scoped_ptr<PrivetHTTPClient> current_http_client_;
+
+  // The current info operation (operations are currently exclusive).
+  scoped_ptr<PrivetInfoOperation> current_info_operation_;
+
+  // The current register operation. Only one allowed at any time.
+  scoped_ptr<PrivetRegisterOperation> current_register_operation_;
+
+  // The current confirm call used during the registration flow.
+  scoped_ptr<PrivetConfirmApiCallFlow> confirm_api_call_flow_;
+
+  // The device lister used to list devices on the local network.
+  scoped_ptr<PrivetDeviceLister> privet_lister_;
+
+  // The service discovery client used listen for devices on the local network.
+  scoped_refptr<ServiceDiscoveryHostClient> service_discovery_client_;
+
+  // A factory for creating the privet HTTP Client.
+  scoped_ptr<PrivetHTTPAsynchronousFactory> privet_http_factory_;
+
+  // An object representing the resolution process for the privet_http_factory.
+  scoped_ptr<PrivetHTTPAsynchronousFactory::Resolution> privet_resolution_;
+
+  // A map of current device descriptions provided by the PrivetDeviceLister.
+  std::map<std::string, DeviceDescription> device_descriptions_;
 
   DISALLOW_COPY_AND_ASSIGN(LocalDiscoveryUIHandler);
 };
 
+}  // namespace local_discovery
 #endif  // CHROME_BROWSER_UI_WEBUI_LOCAL_DISCOVERY_LOCAL_DISCOVERY_UI_HANDLER_H_
diff --git a/chrome/browser/ui/webui/metrics_handler.cc b/chrome/browser/ui/webui/metrics_handler.cc
index f230b71..c68c159 100644
--- a/chrome/browser/ui/webui/metrics_handler.cc
+++ b/chrome/browser/ui/webui/metrics_handler.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/metrics/metric_event_duration_details.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/ui/webui/ntp/ntp_user_data_logger.h"
+#include "chrome/common/ntp_logging_events.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
@@ -118,5 +119,5 @@
   NTPUserDataLogger* data = NTPUserDataLogger::FromWebContents(
       web_ui()->GetWebContents());
   if (data)
-    data->increment_number_of_mouseovers();
+    data->LogEvent(NTP_MOUSEOVER);
 }
diff --git a/chrome/browser/ui/webui/nacl_ui.cc b/chrome/browser/ui/webui/nacl_ui.cc
index 6111748..f38de6b 100644
--- a/chrome/browser/ui/webui/nacl_ui.cc
+++ b/chrome/browser/ui/webui/nacl_ui.cc
@@ -249,9 +249,9 @@
   string16 pnacl_enabled_string = ASCIIToUTF16("Enabled");
   if (!isPluginEnabled(0)) {
     pnacl_enabled_string = ASCIIToUTF16("Disabled in profile prefs");
-  } else if (!CommandLine::ForCurrentProcess()->HasSwitch(
-                 switches::kEnablePnacl)) {
-    pnacl_enabled_string = ASCIIToUTF16("Not enabled by flag '--enable-pnacl'");
+  } else if (CommandLine::ForCurrentProcess()->HasSwitch(
+                 switches::kDisablePnacl)) {
+    pnacl_enabled_string = ASCIIToUTF16("Disabled by flag '--disable-pnacl'");
   }
   AddPair(list,
           ASCIIToUTF16("Portable Native Client (PNaCl)"),
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index cecd557..62715e8 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -32,7 +32,7 @@
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_remover.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/download/download_util.h"
+#include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/io_thread.h"
@@ -78,7 +78,9 @@
 #include "ui/base/resource/resource_bundle.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/network_library.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/net/onc_utils.h"
 #include "chrome/browser/chromeos/system/syslogs_provider.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
@@ -378,7 +380,7 @@
 void StoreDebugLogs(const StoreDebugLogsCallback& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
-  const base::FilePath fileshelf = download_util::GetDefaultDownloadDirectory();
+  const base::FilePath fileshelf = DownloadPrefs::GetDefaultDownloadDirectory();
   DebugLogFileHelper* helper = new DebugLogFileHelper();
   bool posted = base::WorkerPool::PostTaskAndReply(FROM_HERE,
       base::Bind(&DebugLogFileHelper::DoWork,
@@ -1544,31 +1546,31 @@
     NOTREACHED();
   }
 
-  chromeos::onc::ONCSource onc_source = chromeos::onc::ONC_SOURCE_USER_IMPORT;
-
-  base::ListValue network_configs;
-  base::ListValue certificates;
   std::string error;
-  if (!chromeos::onc::ParseAndValidateOncForImport(
-          onc_blob, onc_source, passcode, &network_configs, &certificates)) {
-    error = "Errors occurred during the ONC parsing. ";
-    LOG(ERROR) << error;
+  const chromeos::User* user = chromeos::UserManager::Get()->GetActiveUser();
+  if (user) {
+    chromeos::onc::ONCSource onc_source = chromeos::onc::ONC_SOURCE_USER_IMPORT;
+
+    base::ListValue network_configs;
+    base::ListValue certificates;
+    if (!chromeos::onc::ParseAndValidateOncForImport(
+            onc_blob, onc_source, passcode, &network_configs, &certificates)) {
+      error = "Errors occurred during the ONC parsing. ";
+    }
+
+    chromeos::onc::CertificateImporterImpl cert_importer;
+    if (!cert_importer.ImportCertificates(certificates, onc_source, NULL))
+      error += "Some certificates couldn't be imported. ";
+
+    std::string network_error;
+    chromeos::onc::ImportNetworksForUser(user, network_configs, &network_error);
+    if (!network_error.empty())
+      error += network_error;
+  } else {
+    error = "No active user.";
   }
 
-  chromeos::onc::CertificateImporterImpl cert_importer;
-  if (!cert_importer.ImportCertificates(certificates, onc_source, NULL)) {
-    error += "Some certificates couldn't be imported. ";
-    LOG(ERROR) << error;
-  }
-
-  chromeos::NetworkLibrary* network_library =
-      chromeos::NetworkLibrary::Get();
-  network_library->LoadOncNetworks(network_configs, onc_source);
-
-  // Now that we've added the networks, we need to rescan them so they'll be
-  // available from the menu more immediately.
-  network_library->RequestNetworkScan();
-
+  LOG_IF(ERROR, !error.empty()) << error;
   SendJavascriptCommand("receivedONCFileParse",
                         Value::CreateStringValue(error));
 }
diff --git a/chrome/browser/ui/webui/ntp/android/ntp_resource_cache_android.cc b/chrome/browser/ui/webui/ntp/android/ntp_resource_cache_android.cc
index 7430d88..27f9974 100644
--- a/chrome/browser/ui/webui/ntp/android/ntp_resource_cache_android.cc
+++ b/chrome/browser/ui/webui/ntp/android/ntp_resource_cache_android.cc
@@ -15,6 +15,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_process_host.h"
 #include "grit/browser_resources.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -35,7 +36,20 @@
 
 NTPResourceCache::~NTPResourceCache() {}
 
-base::RefCountedMemory* NTPResourceCache::GetNewTabHTML(bool is_incognito) {
+NTPResourceCache::WindowType NTPResourceCache::GetWindowType(
+    Profile* profile, content::RenderProcessHost* render_host) {
+  if (render_host) {
+    // Sometimes the |profile| is the parent (non-incognito) version of the user
+    // so we check the |render_host| if it is provided.
+    if (render_host->GetBrowserContext()->IsOffTheRecord())
+      return NTPResourceCache::INCOGNITO;
+  } else if (profile->IsOffTheRecord()) {
+    return NTPResourceCache::INCOGNITO;
+  }
+  return NTPResourceCache::NORMAL;
+}
+
+base::RefCountedMemory* NTPResourceCache::GetNewTabHTML(WindowType win_type) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   // Android uses same html/css for incognito NTP and normal NTP
   if (!new_tab_html_.get())
@@ -43,7 +57,7 @@
   return new_tab_html_.get();
 }
 
-base::RefCountedMemory* NTPResourceCache::GetNewTabCSS(bool is_incognito) {
+base::RefCountedMemory* NTPResourceCache::GetNewTabCSS(WindowType win_type) {
   // This is used for themes, which are not currently supported on Android.
   NOTIMPLEMENTED();
   return NULL;
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 4de0128..3528093 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/crx_installer.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_system.h"
@@ -270,10 +269,23 @@
 
       break;
     }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
-      const Extension* extension =
-          content::Details<extensions::UnloadedExtensionInfo>(
-              details)->extension;
+    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
+    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
+      const Extension* extension = NULL;
+      bool uninstalled = false;
+      if (type == chrome::NOTIFICATION_EXTENSION_UNINSTALLED) {
+        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) {
+          // Uninstalls are tracked by NOTIFICATION_EXTENSION_UNINSTALLED.
+          return;
+        }
+        extension = content::Details<extensions::UnloadedExtensionInfo>(
+            details)->extension;
+        uninstalled = false;
+      }
       if (!extension->is_app())
         return;
 
@@ -282,13 +294,11 @@
         return;
 
       scoped_ptr<DictionaryValue> app_info(GetAppInfo(extension));
-      scoped_ptr<base::FundamentalValue> uninstall_value(
-          Value::CreateBooleanValue(
-              content::Details<extensions::UnloadedExtensionInfo>(
-                  details)->reason == extension_misc::UNLOAD_REASON_UNINSTALL));
       if (app_info.get()) {
         visible_apps_.erase(extension->id());
 
+        scoped_ptr<base::FundamentalValue> uninstall_value(
+            Value::CreateBooleanValue(uninstalled));
         scoped_ptr<base::FundamentalValue> from_page(
             Value::CreateBooleanValue(!extension_id_prompting_.empty()));
         web_ui()->CallJavascriptFunction(
@@ -437,14 +447,15 @@
         base::Unretained(this));
     extension_pref_change_registrar_.Init(
         extension_service_->extension_prefs()->pref_service());
-    extension_pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref,
-                                         callback);
+    extension_pref_change_registrar_.Add(prefs::kExtensionsPref, callback);
     extension_pref_change_registrar_.Add(prefs::kNtpAppPageNames, callback);
 
     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
         content::Source<Profile>(profile));
     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
         content::Source<Profile>(profile));
+    registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
+        content::Source<Profile>(profile));
     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED,
         content::Source<ExtensionSorting>(
             extension_service_->extension_prefs()->extension_sorting()));
diff --git a/chrome/browser/ui/webui/ntp/new_tab_ui.cc b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
index 4f9c51d..ca4baf1 100644
--- a/chrome/browser/ui/webui/ntp/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/ntp/new_tab_ui.cc
@@ -382,10 +382,11 @@
 
   content::RenderProcessHost* render_host =
       content::RenderProcessHost::FromID(render_process_id);
-  bool is_incognito = render_host->GetBrowserContext()->IsOffTheRecord();
+  NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType(
+      profile_, render_host);
   scoped_refptr<base::RefCountedMemory> html_bytes(
       NTPResourceCacheFactory::GetForProfile(profile_)->
-      GetNewTabHTML(is_incognito));
+      GetNewTabHTML(win_type));
 
   callback.Run(html_bytes.get());
 }
diff --git a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
index c890db3..db212ec 100644
--- a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
@@ -13,7 +13,6 @@
 #include "base/prefs/pref_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
@@ -26,7 +25,6 @@
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.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/chrome_pages.h"
@@ -149,8 +147,7 @@
       RecordInHistogram(NTP_SIGN_IN_PROMO_CLICKED);
     }
 #endif
-  } else if (args->GetSize() == 4 &&
-             chrome::IsCommandEnabled(browser, IDC_SHOW_AVATAR_MENU)) {
+  } else if (args->GetSize() == 4) {
     // The user is signed in, show the profiles menu.
     double x = 0;
     double y = 0;
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
index ef3e419..73ccf8d 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -43,6 +43,7 @@
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/render_process_host.h"
 #include "grit/browser_resources.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -222,33 +223,56 @@
   return false;
 }
 
-base::RefCountedMemory* NTPResourceCache::GetNewTabHTML(bool is_incognito) {
+NTPResourceCache::WindowType NTPResourceCache::GetWindowType(
+    Profile* profile, content::RenderProcessHost* render_host) {
+  if (profile->IsGuestSession()) {
+    return NTPResourceCache::GUEST;
+  } else if (render_host) {
+    // Sometimes the |profile| is the parent (non-incognito) version of the user
+    // so we check the |render_host| if it is provided.
+    if (render_host->GetBrowserContext()->IsOffTheRecord())
+      return NTPResourceCache::INCOGNITO;
+  } else if (profile->IsOffTheRecord()) {
+    return NTPResourceCache::INCOGNITO;
+  }
+  return NTPResourceCache::NORMAL;
+}
+
+base::RefCountedMemory* NTPResourceCache::GetNewTabHTML(WindowType win_type) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (is_incognito) {
+  if (win_type == GUEST) {
+    if (!new_tab_guest_html_.get())
+      CreateNewTabGuestHTML();
+    return new_tab_guest_html_.get();
+  } else if (win_type == INCOGNITO) {
     if (!new_tab_incognito_html_.get())
       CreateNewTabIncognitoHTML();
+    return new_tab_incognito_html_.get();
   } else {
     // Refresh the cached HTML if necessary.
     // NOTE: NewTabCacheNeedsRefresh() must be called every time the new tab
     // HTML is fetched, because it needs to initialize cached values.
     if (NewTabCacheNeedsRefresh() || !new_tab_html_.get())
       CreateNewTabHTML();
+    return new_tab_html_.get();
   }
-  return is_incognito ? new_tab_incognito_html_.get() :
-                        new_tab_html_.get();
 }
 
-base::RefCountedMemory* NTPResourceCache::GetNewTabCSS(bool is_incognito) {
+base::RefCountedMemory* NTPResourceCache::GetNewTabCSS(WindowType win_type) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (is_incognito) {
+  if (win_type == GUEST) {
+    if (!new_tab_guest_css_.get())
+      CreateNewTabGuestCSS();
+    return new_tab_guest_css_.get();
+  } else if (win_type == INCOGNITO) {
     if (!new_tab_incognito_css_.get())
       CreateNewTabIncognitoCSS();
+    return new_tab_incognito_css_.get();
   } else {
     if (!new_tab_css_.get())
       CreateNewTabCSS();
+    return new_tab_css_.get();
   }
-  return is_incognito ? new_tab_incognito_css_.get() :
-                        new_tab_css_.get();
 }
 
 void NTPResourceCache::Observe(int type,
@@ -331,6 +355,27 @@
   new_tab_incognito_html_ = base::RefCountedString::TakeString(&full_html);
 }
 
+void NTPResourceCache::CreateNewTabGuestHTML() {
+  DictionaryValue localized_strings;
+  localized_strings.SetString("title",
+      l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
+  const char* new_tab_link = kLearnMoreGuestSessionUrl;
+  localized_strings.SetString("content",
+      l10n_util::GetStringFUTF16(IDS_NEW_TAB_GUEST_SESSION_MESSAGE,
+                                 GetUrlWithLang(GURL(new_tab_link))));
+
+  webui::SetFontAndTextDirection(&localized_strings);
+
+  static const base::StringPiece guest_tab_html(
+      ResourceBundle::GetSharedInstance().GetRawDataResource(
+          IDR_GUEST_TAB_HTML));
+
+  std::string full_html = webui::GetI18nTemplateHtml(
+      guest_tab_html, &localized_strings);
+
+  new_tab_guest_html_ = base::RefCountedString::TakeString(&full_html);
+}
+
 void NTPResourceCache::CreateNewTabHTML() {
   // TODO(estade): these strings should be defined in their relevant handlers
   // (in GetLocalizedValues) and should have more legible names.
@@ -540,6 +585,39 @@
   new_tab_incognito_css_ = base::RefCountedString::TakeString(&full_css);
 }
 
+void NTPResourceCache::CreateNewTabGuestCSS() {
+  ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
+  DCHECK(tp);
+
+  // Get our theme colors
+  SkColor color_background =
+      GetThemeColor(tp, ThemeProperties::COLOR_NTP_BACKGROUND);
+
+  // Generate the replacements.
+  std::vector<std::string> subst;
+
+  // Cache-buster for background.
+  subst.push_back(
+      profile_->GetPrefs()->GetString(prefs::kCurrentThemeID));  // $1
+
+  // Colors.
+  subst.push_back(SkColorToRGBAString(color_background));  // $2
+  subst.push_back(GetNewTabBackgroundCSS(tp, false));  // $3
+  subst.push_back(GetNewTabBackgroundCSS(tp, true));  // $4
+  subst.push_back(GetNewTabBackgroundTilingCSS(tp));  // $5
+
+  // Get our template.
+  static const base::StringPiece new_tab_theme_css(
+      ResourceBundle::GetSharedInstance().GetRawDataResource(
+          IDR_NEW_GUEST_TAB_THEME_CSS));
+
+  // Create the string from our template and the replacements.
+  std::string full_css = ReplaceStringPlaceholders(
+      new_tab_theme_css, subst, NULL);
+
+  new_tab_guest_css_ = base::RefCountedString::TakeString(&full_css);
+}
+
 void NTPResourceCache::CreateNewTabCSS() {
   ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
   DCHECK(tp);
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
index ea5f49b..a5203e1 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.h
@@ -20,16 +20,26 @@
 class RefCountedMemory;
 }
 
+namespace content {
+class RenderProcessHost;
+}
+
 // This class keeps a cache of NTP resources (HTML and CSS) so we don't have to
 // regenerate them all the time.
 class NTPResourceCache : public content::NotificationObserver,
                          public BrowserContextKeyedService {
  public:
+  enum WindowType {
+    NORMAL,
+    INCOGNITO,
+    GUEST,
+  };
+
   explicit NTPResourceCache(Profile* profile);
   virtual ~NTPResourceCache();
 
-  base::RefCountedMemory* GetNewTabHTML(bool is_incognito);
-  base::RefCountedMemory* GetNewTabCSS(bool is_incognito);
+  base::RefCountedMemory* GetNewTabHTML(WindowType win_type);
+  base::RefCountedMemory* GetNewTabCSS(WindowType win_type);
 
   void set_should_show_apps_page(bool should_show_apps_page) {
     should_show_apps_page_ = should_show_apps_page;
@@ -49,6 +59,9 @@
                        const content::NotificationSource& source,
                        const content::NotificationDetails& details) OVERRIDE;
 
+  static WindowType GetWindowType(
+      Profile* profile, content::RenderProcessHost* render_host);
+
  private:
   void OnPreferenceChanged();
 
@@ -69,11 +82,15 @@
   string16 GetSyncTypeMessage();
 
   void CreateNewTabIncognitoHTML();
-
   void CreateNewTabIncognitoCSS();
 
+  void CreateNewTabGuestHTML();
+  void CreateNewTabGuestCSS();
+
   void CreateNewTabCSS();
 
+  scoped_refptr<base::RefCountedMemory> new_tab_guest_html_;
+  scoped_refptr<base::RefCountedMemory> new_tab_guest_css_;
   scoped_refptr<base::RefCountedMemory> new_tab_incognito_html_;
   scoped_refptr<base::RefCountedMemory> new_tab_incognito_css_;
   scoped_refptr<base::RefCountedMemory> new_tab_css_;
diff --git a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc
index 5309ce4..cd05553 100644
--- a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc
@@ -6,33 +6,61 @@
 
 #include "base/metrics/histogram.h"
 #include "chrome/browser/search/search.h"
+#include "chrome/common/url_constants.h"
 #include "content/public/browser/navigation_details.h"
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(NTPUserDataLogger);
 
 NTPUserDataLogger::NTPUserDataLogger(content::WebContents* contents)
     : content::WebContentsObserver(contents),
-      number_of_mouseovers_(0) {
+      number_of_mouseovers_(0),
+      number_of_thumbnail_attempts_(0),
+      number_of_thumbnail_errors_(0) {
 }
 
 NTPUserDataLogger::~NTPUserDataLogger() {}
 
-void NTPUserDataLogger::increment_number_of_mouseovers() {
-  number_of_mouseovers_++;
+void NTPUserDataLogger::EmitThumbnailErrorRate() {
+    DCHECK_LE(number_of_thumbnail_errors_, number_of_thumbnail_attempts_);
+    int error_rate =
+        (100 * number_of_thumbnail_errors_) / number_of_thumbnail_attempts_;
+    UMA_HISTOGRAM_PERCENTAGE("NewTabPage.ThumbnailErrorRate", error_rate);
+    number_of_thumbnail_attempts_ = 0;
+    number_of_thumbnail_errors_ = 0;
 }
 
 void NTPUserDataLogger::EmitMouseoverCount() {
-  UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfMouseOvers",
-                       number_of_mouseovers_);
+  UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfMouseOvers", number_of_mouseovers_);
   number_of_mouseovers_ = 0;
 }
 
+void NTPUserDataLogger::LogEvent(NTPLoggingEventType event) {
+  switch (event) {
+    case NTP_MOUSEOVER:
+      number_of_mouseovers_++;
+      break;
+    case NTP_THUMBNAIL_ATTEMPT:
+      number_of_thumbnail_attempts_++;
+      break;
+    case NTP_THUMBNAIL_ERROR:
+      number_of_thumbnail_errors_++;
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
 // content::WebContentsObserver override
 void NTPUserDataLogger::NavigationEntryCommitted(
     const content::LoadCommittedDetails& load_details) {
   if (!load_details.previous_url.is_valid())
     return;
 
-  if (chrome::MatchesOriginAndPath(ntp_url_, load_details.previous_url))
+  if (chrome::MatchesOriginAndPath(ntp_url_, load_details.previous_url)) {
     EmitMouseoverCount();
+    // Only log thumbnail error rates for Instant NTP pages, as we do not have
+    // this data for non-Instant NTPs.
+    if (ntp_url_ != GURL(chrome::kChromeUINewTabURL))
+      EmitThumbnailErrorRate();
+  }
 }
diff --git a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h
index 63fffa7..0103a58 100644
--- a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h
+++ b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_NTP_NTP_USER_DATA_LOGGER_H_
 #define CHROME_BROWSER_UI_WEBUI_NTP_NTP_USER_DATA_LOGGER_H_
 
+#include "chrome/common/ntp_logging_events.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
@@ -16,9 +17,6 @@
  public:
   virtual ~NTPUserDataLogger();
 
-  // Called each time the mouse hovers over a most visited tile or title.
-  void increment_number_of_mouseovers();
-
   // To be set after initialization of this class. Used to determine whether a
   // tab visibility change event or navigation event comes from the NTP.
   void set_ntp_url(const GURL& url) {
@@ -27,12 +25,20 @@
 
   const GURL& ntp_url() const { return ntp_url_; }
 
+  // Logs the error percentage rate when loading thumbnail images for this NTP
+  // session to UMA histogram. Called when the user navigates to a URL.
+  void EmitThumbnailErrorRate();
+
   // Logs total number of mouseovers per NTP session to UMA histogram. Called
   // when an NTP tab is about to be deactivated (be it by switching tabs, losing
   // focus or closing the tab/shutting down Chrome), or when the user navigates
   // to a URL.
   void EmitMouseoverCount();
 
+  // Called each time an event occurs on the NTP that requires a counter to be
+  // incremented.
+  void LogEvent(NTPLoggingEventType event);
+
   // content::WebContentsObserver override
   virtual void NavigationEntryCommitted(
       const content::LoadCommittedDetails& load_details) OVERRIDE;
@@ -44,6 +50,15 @@
   // Total number of mouseovers for this NTP session.
   int number_of_mouseovers_;
 
+  // Total number of attempts made to load thumbnail images for this NTP
+  // session.
+  int number_of_thumbnail_attempts_;
+
+  // Total number of errors that occurred when trying to load thumbnail images
+  // for this NTP session. When these errors occur a grey tile is shown instead
+  // of a thumbnail image.
+  int number_of_thumbnail_errors_;
+
   // The URL of this New Tab Page - varies based on NTP version.
   GURL ntp_url_;
 
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 32b0823..99ef39a 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -1134,11 +1134,6 @@
   if (create_shortcut)
     callbacks.push_back(base::Bind(&CreateDesktopShortcutForProfile));
 
-  ProfileManager::CreateCallback show_user_feedback =
-      base::Bind(&BrowserOptionsHandler::ShowProfileCreationFeedback,
-                 weak_ptr_factory_.GetWeakPtr(), GetDesktopType(),
-                 managed_user);
-
   if (managed_user && ManagedUserService::AreManagedUsersEnabled()) {
     if (!IsValidExistingManagedUserId(managed_user_id))
       return;
@@ -1150,10 +1145,13 @@
     callbacks.push_back(
         base::Bind(&BrowserOptionsHandler::RegisterManagedUser,
                    weak_ptr_factory_.GetWeakPtr(),
-                   show_user_feedback,
+                   GetDesktopType(),
                    managed_user_id));
   } else {
-    callbacks.push_back(show_user_feedback);
+    callbacks.push_back(
+        base::Bind(&BrowserOptionsHandler::ShowProfileCreationFeedback,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   GetDesktopType()));
   }
 
   ProfileMetrics::LogProfileAddNewUser(ProfileMetrics::ADD_NEW_USER_DIALOG);
@@ -1164,13 +1162,16 @@
 }
 
 void BrowserOptionsHandler::RegisterManagedUser(
-    const ProfileManager::CreateCallback& callback,
+    chrome::HostDesktopType desktop_type,
     const std::string& managed_user_id,
     Profile* new_profile,
     Profile::CreateStatus status) {
-  DCHECK(profile_path_being_created_ == new_profile->GetPath());
-  if (status != Profile::CREATE_STATUS_INITIALIZED)
+  DCHECK_EQ(profile_path_being_created_.value(),
+            new_profile->GetPath().value());
+  if (status != Profile::CREATE_STATUS_INITIALIZED) {
+    ShowProfileCreationFeedback(desktop_type, new_profile, status);
     return;
+  }
 
   ManagedUserService* managed_user_service =
       ManagedUserServiceFactory::GetForProfile(new_profile);
@@ -1182,7 +1183,10 @@
       managed_user_registration_utility_.get(),
       Profile::FromWebUI(web_ui()),
       managed_user_id,
-      callback);
+      base::Bind(&BrowserOptionsHandler::OnManagedUserRegistered,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 desktop_type,
+                 new_profile));
 }
 
 void BrowserOptionsHandler::RecordProfileCreationMetrics(
@@ -1195,28 +1199,40 @@
       base::TimeTicks::Now() - profile_creation_start_time_);
 }
 
+void BrowserOptionsHandler::OnManagedUserRegistered(
+    chrome::HostDesktopType desktop_type,
+    Profile* profile,
+    const GoogleServiceAuthError& error) {
+  GoogleServiceAuthError::State state = error.state();
+  if (state == GoogleServiceAuthError::NONE) {
+    ShowProfileCreationSuccess(profile, desktop_type, true);
+    return;
+  }
+
+  string16 error_msg;
+  if (state == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS ||
+      state == GoogleServiceAuthError::USER_NOT_SIGNED_UP ||
+      state == GoogleServiceAuthError::ACCOUNT_DELETED ||
+      state == GoogleServiceAuthError::ACCOUNT_DISABLED) {
+    error_msg = l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_SIGN_IN_ERROR);
+  } else {
+    error_msg = l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_REMOTE_ERROR);
+  }
+  ShowProfileCreationError(profile, error_msg);
+}
+
 void BrowserOptionsHandler::ShowProfileCreationFeedback(
     chrome::HostDesktopType desktop_type,
-    bool is_managed,
     Profile* profile,
     Profile::CreateStatus status) {
-  DCHECK(profile_path_being_created_ == profile->GetPath());
   if (status != Profile::CREATE_STATUS_CREATED)
     RecordProfileCreationMetrics(status);
 
   switch (status) {
     case Profile::CREATE_STATUS_LOCAL_FAIL: {
-      profile_path_being_created_.clear();
-      web_ui()->CallJavascriptFunction(
-          "BrowserOptions.showCreateProfileLocalError");
-      DeleteProfileAtPath(profile->GetPath());
-      break;
-    }
-    case Profile::CREATE_STATUS_REMOTE_FAIL: {
-      profile_path_being_created_.clear();
-      web_ui()->CallJavascriptFunction(
-          "BrowserOptions.showCreateProfileRemoteError");
-      DeleteProfileAtPath(profile->GetPath());
+      string16 error =
+          l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_LOCAL_ERROR);
+      ShowProfileCreationError(profile, error);
       break;
     }
     case Profile::CREATE_STATUS_CREATED: {
@@ -1224,30 +1240,17 @@
       break;
     }
     case Profile::CREATE_STATUS_INITIALIZED: {
-      profile_path_being_created_.clear();
-      DictionaryValue dict;
-      dict.SetString("name",
-                     profile->GetPrefs()->GetString(prefs::kProfileName));
-      dict.Set("filePath", base::CreateFilePathValue(profile->GetPath()));
-      dict.SetBoolean("isManaged", is_managed);
-      web_ui()->CallJavascriptFunction(
-          "BrowserOptions.showCreateProfileSuccess", dict);
-
-      // If the new profile is a managed user, instead of opening a new window
-      // right away, a confirmation overlay will be shown from the creation
-      // dialog.
-      if (!is_managed) {
-        // Opening the new window must be the last action, after all callbacks
-        // have been run, to give them a chance to initialize the profile.
-        OpenNewWindowForProfile(desktop_type,
-                                profile,
-                                Profile::CREATE_STATUS_INITIALIZED);
-      }
+      // Managed user registration success is handled in
+      // OnManagedUserRegistered().
+      ShowProfileCreationSuccess(profile, desktop_type, false);
       break;
     }
     // User-initiated cancellation is handled in CancelProfileRegistration and
     // does not call this callback.
     case Profile::CREATE_STATUS_CANCELED:
+    // Managed user registration errors are handled in
+    // OnManagedUserRegistered().
+    case Profile::CREATE_STATUS_REMOTE_FAIL:
     case Profile::MAX_CREATE_STATUS: {
       NOTREACHED();
       break;
@@ -1255,6 +1258,41 @@
   }
 }
 
+void BrowserOptionsHandler::ShowProfileCreationError(Profile* profile,
+                                                     const string16& error) {
+  profile_path_being_created_.clear();
+  web_ui()->CallJavascriptFunction("BrowserOptions.showCreateProfileError",
+                                   base::StringValue(error));
+  DeleteProfileAtPath(profile->GetPath());
+}
+
+void BrowserOptionsHandler::ShowProfileCreationSuccess(
+    Profile* profile,
+    chrome::HostDesktopType desktop_type,
+    bool is_managed) {
+  DCHECK_EQ(profile_path_being_created_.value(), profile->GetPath().value());
+  profile_path_being_created_.clear();
+  DictionaryValue dict;
+  dict.SetString("name",
+                 profile->GetPrefs()->GetString(prefs::kProfileName));
+  dict.Set("filePath", base::CreateFilePathValue(profile->GetPath()));
+  dict.SetBoolean("isManaged", is_managed);
+  web_ui()->CallJavascriptFunction(
+      "BrowserOptions.showCreateProfileSuccess", dict);
+
+  // If the new profile is a managed user, instead of opening a new window
+  // right away, a confirmation overlay will be shown from the creation
+  // dialog.
+  if (is_managed)
+    return;
+
+  // Opening the new window must be the last action, after all callbacks
+  // have been run, to give them a chance to initialize the profile.
+  OpenNewWindowForProfile(desktop_type,
+                          profile,
+                          Profile::CREATE_STATUS_INITIALIZED);
+}
+
 void BrowserOptionsHandler::DeleteProfile(const ListValue* args) {
   DCHECK(args);
   const Value* file_path_value;
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h
index 2c75f71..dfe4787 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.h
+++ b/chrome/browser/ui/webui/options/browser_options_handler.h
@@ -14,7 +14,6 @@
 #include "base/prefs/pref_member.h"
 #include "base/time/time.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/search_engines/template_url_service_observer.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/sync/profile_sync_service_observer.h"
@@ -30,6 +29,7 @@
 class AutocompleteController;
 class CloudPrintSetupHandler;
 class CustomHomePagesTableModel;
+class GoogleServiceAuthError;
 class ManagedUserRegistrationUtility;
 class TemplateURLService;
 
@@ -155,21 +155,33 @@
 
   // After a new managed-user profile has been created, registers the user with
   // the management server.
-  void RegisterManagedUser(const ProfileManager::CreateCallback& callback,
+  void RegisterManagedUser(chrome::HostDesktopType desktop_type,
                            const std::string& managed_user_id,
                            Profile* new_profile,
                            Profile::CreateStatus status);
 
+  // Called back with the result of the managed user registration.
+  void OnManagedUserRegistered(chrome::HostDesktopType desktop_type,
+                               Profile* profile,
+                               const GoogleServiceAuthError& error);
+
   // Records UMA histograms relevant to profile creation.
   void RecordProfileCreationMetrics(Profile::CreateStatus status);
 
   // Updates the UI as the final task after a new profile has been created.
   void ShowProfileCreationFeedback(
       chrome::HostDesktopType desktop_type,
-      bool is_managed,
       Profile* profile,
       Profile::CreateStatus status);
 
+  // Updates the UI to show an error when creating a profile.
+  void ShowProfileCreationError(Profile* profile, const string16& error);
+
+  // Updates the UI to indicate success when creating a profile.
+  void ShowProfileCreationSuccess(Profile* profile,
+                                  chrome::HostDesktopType desktop_type,
+                                  bool is_managed);
+
   // Deletes the given profile. Expects one argument:
   //   0: profile file path (string)
   void DeleteProfile(const base::ListValue* args);
diff --git a/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc b/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc
index 1517808..309313b 100644
--- a/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc
+++ b/chrome/browser/ui/webui/options/certificate_manager_browsertest.cc
@@ -55,7 +55,7 @@
     // Enable web trust certs from policy.
     g_browser_process->browser_policy_connector()->
         network_configuration_updater()->SetUserPolicyService(
-            true, "", connector->policy_service());
+            true, NULL /* no user */, connector->policy_service());
 #endif
     content::RunAllPendingInMessageLoop();
   }
diff --git a/chrome/browser/ui/webui/options/certificate_manager_handler.cc b/chrome/browser/ui/webui/options/certificate_manager_handler.cc
index 3ad62db..31393c6 100644
--- a/chrome/browser/ui/webui/options/certificate_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/certificate_manager_handler.cc
@@ -300,7 +300,7 @@
                                  int* saved_errno,
                                  int* bytes_written) {
   *bytes_written = file_util::WriteFile(path, data.data(), data.size());
-  *saved_errno = bytes_written >= 0 ? 0 : errno;
+  *saved_errno = *bytes_written >= 0 ? 0 : errno;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/webui/options/chromeos/OWNERS b/chrome/browser/ui/webui/options/chromeos/OWNERS
index d63bb1c..8ba3fab 100644
--- a/chrome/browser/ui/webui/options/chromeos/OWNERS
+++ b/chrome/browser/ui/webui/options/chromeos/OWNERS
@@ -1,10 +1,6 @@
 dpolukhin@chromium.org
-glotov@chromium.org
 nkostylev@chromium.org
 
-# Change Picture and Accounts pages:
-ivankr@chromium.org
-
 # Display options.
 mukai@chromium.org
 
diff --git a/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc
index e75e1e9..537feab 100644
--- a/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/change_picture_options_handler.cc
@@ -79,6 +79,8 @@
       content::NotificationService::AllSources());
   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
       content::NotificationService::AllSources());
+  registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
+      content::NotificationService::AllSources());
 }
 
 ChangePictureOptionsHandler::~ChangePictureOptionsHandler() {
@@ -411,6 +413,11 @@
     // User profile image has been updated.
     SendProfileImage(*content::Details<const gfx::ImageSkia>(details).ptr(),
                      false);
+  } else if (type == chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED) {
+    // Not initialized yet.
+    if (previous_image_index_ == User::kInvalidImageIndex)
+      return;
+    SendSelectedImage();
   }
 }
 
diff --git a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
index 25fecc1..e04df15 100644
--- a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc
@@ -165,13 +165,6 @@
     for (size_t i = 0; i < descriptor.language_codes().size(); ++i) {
       languages->SetBoolean(descriptor.language_codes().at(i), true);
     }
-    // Check extra languages to see if there are languages associated with
-    // this input method. If these are present, add these.
-    const std::vector<std::string> extra_language_codes =
-        manager->GetInputMethodUtil()->GetExtraLanguageCodesFromId(
-            descriptor.id());
-    for (size_t j = 0; j < extra_language_codes.size(); ++j)
-      languages->SetBoolean(extra_language_codes[j], true);
     dictionary->Set("languageCodeSet", languages);
 
     input_method_list->Append(dictionary);
@@ -195,12 +188,6 @@
     for (size_t i = 0; i < languages.size(); ++i)
       language_codes.insert(languages[i]);
   }
-  // Collect the language codes from extra languages.
-  const std::vector<std::string> extra_language_codes =
-      input_method::InputMethodManager::Get()->GetInputMethodUtil()
-          ->GetExtraLanguageCodeList();
-  for (size_t i = 0; i < extra_language_codes.size(); ++i)
-    language_codes.insert(extra_language_codes[i]);
 
   // Map of display name -> {language code, native_display_name}.
   // In theory, we should be able to create a map that is sorted by
diff --git a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler_unittest.cc b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler_unittest.cc
index b51e0f0..7ba873e 100644
--- a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler_unittest.cc
+++ b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler_unittest.cc
@@ -35,7 +35,6 @@
     descriptors.push_back(GetDesc("xkb:fr::fra", "fr", "fr"));
     descriptors.push_back(GetDesc("xkb:be::fra", "be", "fr"));
     descriptors.push_back(GetDesc("xkb:is::ice", "is", "is"));
-    descriptors.push_back(GetDesc("mozc", "us", "ja"));
     return descriptors;
   }
 
@@ -62,7 +61,7 @@
   scoped_ptr<ListValue> list(
       chromeos::options::CrosLanguageOptionsHandler::GetInputMethodList(
           descriptors));
-  ASSERT_EQ(5U, list->GetSize());
+  ASSERT_EQ(4U, list->GetSize());
 
   DictionaryValue* entry = NULL;
   DictionaryValue *language_code_set = NULL;
@@ -81,8 +80,6 @@
   // (i.e. makes the test fragile).
   // EXPECT_EQ("English (USA) keyboard layout", display_name);
   ASSERT_TRUE(language_code_set->HasKey("en-US"));
-  ASSERT_TRUE(language_code_set->HasKey("id"));  // From kExtraLanguages.
-  ASSERT_TRUE(language_code_set->HasKey("fil"));  // From kExtraLanguages.
 
   ASSERT_TRUE(list->GetDictionary(1, &entry));
   ASSERT_TRUE(entry->GetString("id", &input_method_id));
@@ -110,15 +107,6 @@
   // Commented out. See above.
   // EXPECT_EQ("Japanese input method (for US keyboard)", display_name);
   ASSERT_TRUE(language_code_set->HasKey("is"));
-
-  ASSERT_TRUE(list->GetDictionary(4, &entry));
-  ASSERT_TRUE(entry->GetString("id", &input_method_id));
-  ASSERT_TRUE(entry->GetString("displayName", &display_name));
-  ASSERT_TRUE(entry->GetDictionary("languageCodeSet", &language_code_set));
-  EXPECT_EQ("mozc", input_method_id);
-  // Commented out. See above.
-  // EXPECT_EQ("Japanese input method (for US keyboard)", display_name);
-  ASSERT_TRUE(language_code_set->HasKey("ja"));
 }
 
 TEST_F(CrosLanguageOptionsHandlerTest, GetUILanguageList) {
diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
index d02c3b3..504cf23 100644
--- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
@@ -167,8 +167,6 @@
 void DisplayOptionsHandler::SendDisplayInfo(
     const std::vector<gfx::Display>& displays) {
   DisplayManager* display_manager = GetDisplayManager();
-  ash::DisplayController* display_controller =
-      ash::Shell::GetInstance()->display_controller();
   base::FundamentalValue mirroring(display_manager->IsMirrored());
 
   int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
@@ -215,10 +213,11 @@
     std::sort(resolutions.begin(), resolutions.end(), CompareResolution);
 
     base::ListValue* js_resolutions = new base::ListValue();
-    gfx::Size current_size(bounds.width() * display.device_scale_factor(),
-                           bounds.height() * display.device_scale_factor());
+    gfx::Size current_size = display_info.bounds_in_pixel().size();
+    gfx::Insets current_overscan = display_info.GetOverscanInsetsInPixel();
     for (size_t i = 0; i < resolutions.size(); ++i) {
       base::DictionaryValue* resolution_info = new base::DictionaryValue();
+      gfx::Size resolution = resolutions[i].size;
       if (!ui_scales.empty()) {
         resolution_info->SetDouble("scale", ui_scales[i]);
         if (ui_scales[i] == 1.0f)
@@ -230,11 +229,12 @@
         // because |resolutions| is sorted by its area.
         if (i == resolutions.size() - 1)
           resolution_info->SetBoolean("isBest", true);
-        resolution_info->SetBoolean(
-            "selected", (resolutions[i].size == current_size));
+        resolution_info->SetBoolean("selected", (resolution == current_size));
+        resolution.Enlarge(
+            -current_overscan.width(), -current_overscan.height());
       }
-      resolution_info->SetInteger("width", resolutions[i].size.width());
-      resolution_info->SetInteger("height",resolutions[i].size.height());
+      resolution_info->SetInteger("width", resolution.width());
+      resolution_info->SetInteger("height", resolution.height());
       js_resolutions->Append(resolution_info);
     }
     js_display->Set("resolutions", js_resolutions);
@@ -245,7 +245,7 @@
   scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
   if (display_manager->GetNumDisplays() > 1) {
     const ash::DisplayLayout layout =
-        display_controller->GetCurrentDisplayLayout();
+        display_manager->GetCurrentDisplayLayout();
     layout_value.reset(new base::FundamentalValue(layout.position));
     offset_value.reset(new base::FundamentalValue(layout.offset));
   }
@@ -347,8 +347,10 @@
 
   const ash::internal::DisplayInfo& display_info =
       GetDisplayManager()->GetDisplayInfo(display_id);
+  gfx::Insets current_overscan = display_info.GetOverscanInsetsInPixel();
   gfx::Size new_resolution = gfx::ToFlooredSize(gfx::SizeF(width, height));
-  gfx::Size old_resolution = display_info.size_in_pixel();
+  new_resolution.Enlarge(current_overscan.width(), current_overscan.height());
+  gfx::Size old_resolution = display_info.bounds_in_pixel().size();
   bool has_new_resolution = false;
   bool has_old_resolution = false;
   for (size_t i = 0; i < display_info.resolutions().size(); ++i) {
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 6537a55..f0eb6ec 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -30,14 +30,13 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/choose_mobile_network_dialog.h"
-#include "chrome/browser/chromeos/cros/network_library.h"
 #include "chrome/browser/chromeos/cros/network_property_ui_data.h"
 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/mobile_config.h"
+#include "chrome/browser/chromeos/net/onc_utils.h"
 #include "chrome/browser/chromeos/options/network_config_view.h"
-#include "chrome/browser/chromeos/options/network_connect.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/sim_dialog_delegate.h"
 #include "chrome/browser/chromeos/ui_proxy_config_service.h"
@@ -110,6 +109,7 @@
 const char kIpConfigGateway[] = "gateway";
 const char kIpConfigNameServers[] = "nameServers";
 const char kIpConfigAutoConfig[] = "ipAutoConfig";
+const char kIpConfigWebProxyAutoDiscoveryUrl[] = "webProxyAutoDiscoveryUrl";
 
 // These are types of name server selections from the web ui.
 const char kNameServerTypeAutomatic[] = "automatic";
@@ -260,6 +260,11 @@
 void ShillError(const std::string& function,
                 const std::string& error_name,
                 scoped_ptr<base::DictionaryValue> error_data) {
+  // UpdateConnectionData may send requests for stale services; ignore
+  // these errors.
+  if (function == "UpdateConnectionData" &&
+      error_name == network_handler::kDBusFailedError)
+    return;
   NET_LOG_ERROR("Shill Error from InternetOptionsHandler: " + error_name,
                 function);
 }
@@ -648,7 +653,7 @@
 
   onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
   const base::DictionaryValue* onc =
-      network_connect::FindPolicyForActiveUser(vpn, &onc_source);
+      onc::FindPolicyForActiveUser(vpn->guid(), &onc_source);
 
   NetworkPropertyUIData hostname_ui_data;
   hostname_ui_data.ParseOncProperty(
@@ -712,14 +717,17 @@
 // TODO(stevenjb): Move implementation here.
 
 // Helper methods for SetIPConfigProperties
-void AppendPropertyKeyIfPresent(const std::string& key,
+bool AppendPropertyKeyIfPresent(const std::string& key,
                                 const base::DictionaryValue& old_properties,
                                 std::vector<std::string>* property_keys) {
-  if (old_properties.HasKey(key))
+  if (old_properties.HasKey(key)) {
     property_keys->push_back(key);
+    return true;
+  }
+  return false;
 }
 
-void AddStringPropertyIfChanged(const std::string& key,
+bool AddStringPropertyIfChanged(const std::string& key,
                                 const std::string& new_value,
                                 const base::DictionaryValue& old_properties,
                                 base::DictionaryValue* new_properties) {
@@ -727,10 +735,12 @@
   if (!old_properties.GetStringWithoutPathExpansion(key, &old_value) ||
       new_value != old_value) {
     new_properties->SetStringWithoutPathExpansion(key, new_value);
+    return true;
   }
+  return false;
 }
 
-void AddIntegerPropertyIfChanged(const std::string& key,
+bool AddIntegerPropertyIfChanged(const std::string& key,
                                  int new_value,
                                  const base::DictionaryValue& old_properties,
                                  base::DictionaryValue* new_properties) {
@@ -738,7 +748,18 @@
   if (!old_properties.GetIntegerWithoutPathExpansion(key, &old_value) ||
       new_value != old_value) {
     new_properties->SetIntegerWithoutPathExpansion(key, new_value);
+    return true;
   }
+  return false;
+}
+
+void RequestReconnect(const std::string& service_path,
+                      gfx::NativeWindow owning_window) {
+  NetworkHandler::Get()->network_connection_handler()->DisconnectNetwork(
+      service_path,
+      base::Bind(&ash::network_connect::ConnectToNetwork,
+                 service_path, owning_window),
+      base::Bind(&ShillError, "RequestReconnect"));
 }
 
 }  // namespace
@@ -833,7 +854,6 @@
     { "configureButton", IDS_OPTIONS_SETTINGS_CONFIGURE },
     { "disconnectButton", IDS_OPTIONS_SETTINGS_DISCONNECT },
     { "viewAccountButton", IDS_STATUSBAR_NETWORK_VIEW_ACCOUNT },
-
     { "wimaxConnTabLabel", IDS_OPTIONS_SETTINGS_INTERNET_TAB_WIMAX },
 
     // Wifi Tab.
@@ -913,6 +933,9 @@
     { "lockSimCard", IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_LOCK_SIM_CARD },
     { "changePinButton",
       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_BUTTON },
+
+    // Proxy Tab.
+    { "webProxyAutoDiscoveryUrl", IDS_PROXY_WEB_PROXY_AUTO_DISCOVERY },
   };
 
   RegisterStrings(localized_strings, resources, arraysize(resources));
@@ -1076,7 +1099,7 @@
     NOTREACHED();
     return;
   }
-  network_connect::ShowMobileSetup(service_path);
+  ash::network_connect::ShowMobileSetup(service_path);
 }
 
 void InternetOptionsHandler::BuyDataPlanCallback(const base::ListValue* args) {
@@ -1087,7 +1110,7 @@
     NOTREACHED();
     return;
   }
-  network_connect::ShowMobileSetup(service_path);
+  ash::network_connect::ShowMobileSetup(service_path);
 }
 
 void InternetOptionsHandler::SetApnCallback(const base::ListValue* args) {
@@ -1366,20 +1389,24 @@
     NOTREACHED();
     return;
   }
-  NET_LOG_EVENT("SetIPConfigProperties", service_path);
+  NET_LOG_USER("SetIPConfigProperties", service_path);
 
+  bool request_reconnect = false;
   std::vector<std::string> properties_to_clear;
   base::DictionaryValue properties_to_set;
 
   if (dhcp_for_ip) {
-    AppendPropertyKeyIfPresent(shill::kStaticIPAddressProperty,
-                               shill_properties, &properties_to_clear);
-    AppendPropertyKeyIfPresent(shill::kStaticIPPrefixlenProperty,
-                               shill_properties, &properties_to_clear);
-    AppendPropertyKeyIfPresent(shill::kStaticIPGatewayProperty,
-                               shill_properties, &properties_to_clear);
+    request_reconnect |= AppendPropertyKeyIfPresent(
+        shill::kStaticIPAddressProperty,
+        shill_properties, &properties_to_clear);
+    request_reconnect |= AppendPropertyKeyIfPresent(
+        shill::kStaticIPPrefixlenProperty,
+        shill_properties, &properties_to_clear);
+    request_reconnect |= AppendPropertyKeyIfPresent(
+        shill::kStaticIPGatewayProperty,
+        shill_properties, &properties_to_clear);
   } else {
-    AddStringPropertyIfChanged(
+    request_reconnect |= AddStringPropertyIfChanged(
         shill::kStaticIPAddressProperty,
         address, shill_properties, &properties_to_set);
     int prefixlen = network_util::NetmaskToPrefixLength(netmask);
@@ -1387,10 +1414,10 @@
       LOG(ERROR) << "Invalid prefix length for: " << service_path;
       prefixlen = 0;
     }
-    AddIntegerPropertyIfChanged(
+    request_reconnect |= AddIntegerPropertyIfChanged(
         shill::kStaticIPPrefixlenProperty,
         prefixlen, shill_properties, &properties_to_set);
-    AddStringPropertyIfChanged(
+    request_reconnect |= AddStringPropertyIfChanged(
         shill::kStaticIPGatewayProperty,
         gateway, shill_properties, &properties_to_set);
   }
@@ -1422,9 +1449,15 @@
   shill_properties.GetStringWithoutPathExpansion(
       flimflam::kDeviceProperty, &device_path);
   if (!device_path.empty()) {
-    // TODO(stevenjb): Enable this once 18873007 has landed.
-    // NetworkHandler::Get()->network_device_handler()->RequestRefreshIPConfigs(
-    //     device_path);
+    base::Closure callback = base::Bind(&base::DoNothing);
+    // If auto config or a static IP property changed, we need to reconnect
+    // to the network.
+    if (request_reconnect)
+      callback = base::Bind(&RequestReconnect, service_path, GetNativeWindow());
+    NetworkHandler::Get()->network_device_handler()->RequestRefreshIPConfigs(
+        device_path,
+        callback,
+        base::Bind(&ShillError, "RequestRefreshIPConfigs"));
   }
 }
 
@@ -1439,7 +1472,7 @@
 
   onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
   const base::DictionaryValue* onc =
-      network_connect::FindPolicyForActiveUser(network, &onc_source);
+      onc::FindPolicyForActiveUser(network->guid(), &onc_source);
   const NetworkPropertyUIData property_ui_data(onc_source);
 
   base::DictionaryValue dictionary;
@@ -1457,6 +1490,8 @@
   ipconfig_dhcp->SetString(kIpConfigGateway, network->gateway());
   std::string ipconfig_name_servers = network->GetDnsServersAsString();
   ipconfig_dhcp->SetString(kIpConfigNameServers, ipconfig_name_servers);
+  ipconfig_dhcp->SetString(kIpConfigWebProxyAutoDiscoveryUrl,
+                           network->web_proxy_auto_discovery_url().spec());
   SetValueDictionary(&dictionary,
                      kDictionaryIpConfig,
                      ipconfig_dhcp.release(),
@@ -1769,6 +1804,16 @@
       cellular->activation_state() == flimflam::kActivationStateActivating ||
       cellular->IsConnectingState());
 
+  // Don't show any account management related buttons if the activation
+  // state is unknown or no payment portal URL is available.
+  std::string support_url;
+  if (cellular->activation_state() == flimflam::kActivationStateUnknown ||
+      !dictionary->GetString(kTagSupportUrl, &support_url) ||
+      support_url.empty()) {
+    VLOG(2) << "No support URL is available. Don't display buttons.";
+    return;
+  }
+
   if (cellular->activation_state() != flimflam::kActivationStateActivating &&
       cellular->activation_state() != flimflam::kActivationStateActivated) {
     dictionary->SetBoolean(kTagShowActivateButton, true);
diff --git a/chrome/browser/ui/webui/options/content_settings_handler.cc b/chrome/browser/ui/webui/options/content_settings_handler.cc
index e978f79..3cfb99d 100644
--- a/chrome/browser/ui/webui/options/content_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/content_settings_handler.cc
@@ -102,6 +102,7 @@
   {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker"},
   {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "multiple-automatic-downloads"},
   {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex"},
+  {CONTENT_SETTINGS_TYPE_SAVE_PASSWORD, "save-password"},
 };
 
 ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
@@ -702,6 +703,9 @@
     case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
       // The RPH settings are retrieved separately.
       break;
+    case CONTENT_SETTINGS_TYPE_SAVE_PASSWORD:
+      // There is no user facing UI for this content type and we skip it here.
+      break;
     case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
       UpdateMIDISysExExceptionsView();
       break;
diff --git a/chrome/browser/ui/webui/options/geolocation_options_handler.cc b/chrome/browser/ui/webui/options/geolocation_options_handler.cc
index 47ec77c..deb83bc 100644
--- a/chrome/browser/ui/webui/options/geolocation_options_handler.cc
+++ b/chrome/browser/ui/webui/options/geolocation_options_handler.cc
@@ -22,7 +22,15 @@
 void GeolocationOptionsHandler::InitializePage() {
   DCHECK(web_ui());
 
-  if ((base::FieldTrialList::FindFullName("GoogleNow") == "Enable") ||
+  const char kEnablePrefix[] = "Enable";
+  const char kFieldTrialName[] = "GoogleNow";
+  std::string enable_prefix(kEnablePrefix);
+  std::string field_trial_result =
+      base::FieldTrialList::FindFullName(kFieldTrialName);
+  if ((field_trial_result.compare(
+          0,
+          enable_prefix.length(),
+          enable_prefix) == 0) ||
       CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableGoogleNowIntegration)) {
     web_ui()->CallJavascriptFunction(
diff --git a/chrome/browser/ui/webui/options/manage_profile_browsertest.js b/chrome/browser/ui/webui/options/manage_profile_browsertest.js
index 70c494a..e02a526 100644
--- a/chrome/browser/ui/webui/options/manage_profile_browsertest.js
+++ b/chrome/browser/ui/webui/options/manage_profile_browsertest.js
@@ -174,12 +174,7 @@
   var errorBubble = $('create-profile-error-bubble');
   assertTrue(errorBubble.hidden);
 
-  CreateProfileOverlay.onLocalError();
-  assertEquals('createProfile', OptionsPage.getTopmostVisiblePage().name);
-  assertFalse(errorBubble.hidden);
-
-  errorBubble.hidden = true;
-  CreateProfileOverlay.onRemoteError();
+  CreateProfileOverlay.onError('An Error Message!');
   assertEquals('createProfile', OptionsPage.getTopmostVisiblePage().name);
   assertFalse(errorBubble.hidden);
 });
diff --git a/chrome/browser/ui/webui/options/manage_profile_handler.cc b/chrome/browser/ui/webui/options/manage_profile_handler.cc
index 0d54e68..273ec26 100644
--- a/chrome/browser/ui/webui/options/manage_profile_handler.cc
+++ b/chrome/browser/ui/webui/options/manage_profile_handler.cc
@@ -117,8 +117,6 @@
     { "createProfileTitle", IDS_PROFILES_CREATE_TITLE },
     { "createProfileInstructions", IDS_PROFILES_CREATE_INSTRUCTIONS },
     { "createProfileConfirm", IDS_PROFILES_CREATE_CONFIRM },
-    { "createProfileLocalError", IDS_PROFILES_CREATE_LOCAL_ERROR },
-    { "createProfileRemoteError", IDS_PROFILES_CREATE_REMOTE_ERROR },
     { "createProfileShortcutCheckbox", IDS_PROFILES_CREATE_SHORTCUT_CHECKBOX },
     { "createProfileShortcutButton", IDS_PROFILES_CREATE_SHORTCUT_BUTTON },
     { "removeProfileShortcutButton", IDS_PROFILES_REMOVE_SHORTCUT_BUTTON },
diff --git a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
index a726a26..923db39 100644
--- a/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/reset_profile_settings_handler.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string16.h"
 #include "base/values.h"
@@ -40,6 +41,12 @@
   resetter_.reset(new ProfileResetter(profile));
 }
 
+void ResetProfileSettingsHandler::InitializePage() {
+  web_ui()->CallJavascriptFunction(
+      "ResetProfileSettingsOverlay.setResettingState",
+      base::FundamentalValue(resetter_->IsActive()));
+}
+
 void ResetProfileSettingsHandler::GetLocalizedValues(
     DictionaryValue* localized_strings) {
   DCHECK(localized_strings);
@@ -146,6 +153,7 @@
       base::Bind(&ResetProfileSettingsHandler::OnResetProfileSettingsDone,
                  AsWeakPtr()));
   content::RecordAction(content::UserMetricsAction("ResetProfile"));
+  UMA_HISTOGRAM_BOOLEAN("ProfileReset.SendFeedback", send_settings);
 }
 
 }  // namespace options
diff --git a/chrome/browser/ui/webui/options/reset_profile_settings_handler.h b/chrome/browser/ui/webui/options/reset_profile_settings_handler.h
index 586a773..c6f51ef 100644
--- a/chrome/browser/ui/webui/options/reset_profile_settings_handler.h
+++ b/chrome/browser/ui/webui/options/reset_profile_settings_handler.h
@@ -32,6 +32,7 @@
   virtual void GetLocalizedValues(
       base::DictionaryValue* localized_strings) OVERRIDE;
   virtual void InitializeHandler() OVERRIDE;
+  virtual void InitializePage() OVERRIDE;
 
   // WebUIMessageHandler implementation.
   virtual void RegisterMessages() OVERRIDE;
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index c514db3..fa9ed74 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -63,10 +63,10 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/policy/policy_domain_descriptor.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension_set.h"
-#include "chrome/common/extensions/manifest.h"
-#include "chrome/common/policy/policy_schema.h"
+#include "components/policy/core/common/policy_schema.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #endif
 
 namespace em = enterprise_management;
@@ -451,7 +451,8 @@
 #endif
 
 PolicyUIHandler::PolicyUIHandler()
-    : weak_factory_(this) {
+    : initialized_(false),
+      weak_factory_(this) {
 }
 
 PolicyUIHandler::~PolicyUIHandler() {
@@ -568,7 +569,7 @@
     const extensions::Extension* extension = it->get();
     // Skip this extension if it's not an enterprise extension.
     if (!extension->manifest()->HasPath(
-        extension_manifest_keys::kStorageManagedSchema))
+        extensions::manifest_keys::kStorageManagedSchema))
       continue;
     base::DictionaryValue* extension_value = new base::DictionaryValue;
     extension_value->SetString("name", extension->name());
@@ -581,7 +582,7 @@
       const policy::PolicySchemaMap* policies = schema->second->GetProperties();
       policy::PolicySchemaMap::const_iterator it_policies;
       for (it_policies = policies->begin(); it_policies != policies->end();
-           it_policies++) {
+           ++it_policies) {
         policy_names->SetBoolean(it_policies->first, true);
       }
     }
@@ -615,7 +616,7 @@
     const extensions::Extension* extension = it->get();
     // Skip this extension if it's not an enterprise extension.
     if (!extension->manifest()->HasPath(
-        extension_manifest_keys::kStorageManagedSchema))
+        extensions::manifest_keys::kStorageManagedSchema))
       continue;
     base::DictionaryValue* extension_policies = new base::DictionaryValue;
     policy::PolicyNamespace policy_namespace = policy::PolicyNamespace(
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy_ui_browsertest.cc
index 4db7a9f..feb7532 100644
--- a/chrome/browser/ui/webui/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_ui_browsertest.cc
@@ -90,7 +90,7 @@
 
   void UpdateProviderPolicy(const policy::PolicyMap& policy);
 
-  void VerifyPolicies(const std::vector<std::vector<std::string> > expected);
+  void VerifyPolicies(const std::vector<std::vector<std::string> >& expected);
 
  private:
   policy::MockConfigurationPolicyProvider provider_;
@@ -118,7 +118,7 @@
 }
 
 void PolicyUITest::VerifyPolicies(
-    const std::vector<std::vector<std::string> > expected_policies) {
+    const std::vector<std::vector<std::string> >& expected_policies) {
   ui_test_utils::NavigateToURL(browser(), GURL("chrome://policy"));
 
   // Retrieve the text contents of the policy table cells for all policies.
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 32e6012..d6dae2b 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -46,6 +46,7 @@
 #include "chrome/browser/ui/webui/print_preview/sticky_settings.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/print_messages.h"
 #include "content/public/browser/browser_context.h"
@@ -65,9 +66,6 @@
 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
 
 #if defined(OS_CHROMEOS)
-// TODO(kinaba): provide more non-intrusive way for handling local/remote
-// distinction and remove these ugly #ifdef's. http://crbug.com/140425
-#include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #endif
@@ -82,9 +80,6 @@
 
 namespace {
 
-// The cloud print OAuth2 scope.
-const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint";
-
 enum UserActionBuckets {
   PRINT_TO_PRINTER,
   PRINT_TO_PDF,
@@ -170,7 +165,6 @@
 // Name of a dictionary field holding the state of selection for document.
 const char kDocumentHasSelection[] = "documentHasSelection";
 
-
 // Get the print job settings dictionary from |args|. The caller takes
 // ownership of the returned DictionaryValue. Returns NULL on failure.
 DictionaryValue* GetSettingsDictionary(const ListValue* args) {
@@ -248,22 +242,6 @@
       base::Bind(&base::DeletePointer<Metafile>, metafile));
 }
 
-#if defined(OS_CHROMEOS)
-void PrintToPdfCallbackWithCheck(Metafile* metafile,
-                                 drive::FileError error,
-                                 const base::FilePath& path) {
-  if (error != drive::FILE_ERROR_OK) {
-    LOG(ERROR) << "Save to pdf failed to write: " << error;
-  } else {
-    metafile->SaveTo(path);
-  }
-  // |metafile| must be deleted on the UI thread.
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&base::DeletePointer<Metafile>, metafile));
-}
-#endif
-
 static base::LazyInstance<printing::StickySettings> sticky_settings =
     LAZY_INSTANCE_INITIALIZER;
 
@@ -293,7 +271,7 @@
 
     if (service) {
       OAuth2TokenService::ScopeSet oauth_scopes;
-      oauth_scopes.insert(kCloudPrintAuth);
+      oauth_scopes.insert(cloud_print::kCloudPrintAuth);
       scoped_ptr<OAuth2TokenService::Request> request(
           service->StartRequest(oauth_scopes, this));
       requests_[type].reset(request.release());
@@ -960,7 +938,6 @@
   ui::SelectFileDialog::FileTypeInfo file_type_info;
   file_type_info.extensions.resize(1);
   file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pdf"));
-  file_type_info.support_drive = true;
 
   // Initializing save_path_ if it is not already initialized.
   printing::StickySettings* sticky_settings = GetStickySettings();
@@ -1033,18 +1010,9 @@
   printing::PreviewMetafile* metafile = new printing::PreviewMetafile;
   metafile->InitFromData(static_cast<const void*>(data->front()), data->size());
   // PrintToPdfCallback takes ownership of |metafile|.
-#if defined(OS_CHROMEOS)
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  drive::util::PrepareWritableFileAndRun(
-      Profile::FromBrowserContext(preview_web_contents()->GetBrowserContext()),
-      *print_to_pdf_path_,
-      base::Bind(&PrintToPdfCallbackWithCheck, metafile));
-#else
   BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                           base::Bind(&PrintToPdfCallback, metafile,
                                      *print_to_pdf_path_));
-#endif
-
   print_to_pdf_path_.reset();
   ClosePreviewDialog();
 }
@@ -1088,4 +1056,3 @@
   *title = print_preview_ui->initiator_title();
   return true;
 }
-
diff --git a/chrome/browser/ui/webui/screenshot_source.cc b/chrome/browser/ui/webui/screenshot_source.cc
deleted file mode 100644
index 2c09777..0000000
--- a/chrome/browser/ui/webui/screenshot_source.cc
+++ /dev/null
@@ -1,270 +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/webui/screenshot_source.h"
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#include "base/i18n/time_formatting.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/download/download_prefs.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
-#include "url/url_canon.h"
-#include "url/url_util.h"
-
-#if defined(USE_ASH)
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
-#endif
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/drive/drive_integration_service.h"
-#include "chrome/browser/chromeos/drive/file_system_interface.h"
-#include "chrome/browser/chromeos/drive/file_system_util.h"
-#include "chromeos/login/login_state.h"
-#include "content/public/browser/browser_thread.h"
-#endif
-
-// static
-const char ScreenshotSource::kScreenshotUrlRoot[] = "chrome://screenshots/";
-// static
-const char ScreenshotSource::kScreenshotCurrent[] = "current";
-// static
-const char ScreenshotSource::kScreenshotSaved[] = "saved/";
-#if defined(OS_CHROMEOS)
-// static
-const char ScreenshotSource::kScreenshotPrefix[] = "Screenshot ";
-// static
-const char ScreenshotSource::kScreenshotSuffix[] = ".png";
-#endif
-
-bool ShouldUse24HourClock() {
-#if defined(OS_CHROMEOS)
-  Profile* profile = ProfileManager::GetDefaultProfileOrOffTheRecord();
-  if (profile) {
-    return profile->GetPrefs()->GetBoolean(prefs::kUse24HourClock);
-  }
-#endif
-  return base::GetHourClockType() == base::k24HourClock;
-}
-
-ScreenshotSource::ScreenshotSource(
-    std::vector<unsigned char>* current_screenshot,
-    Profile* profile)
-    : profile_(profile) {
-  // Setup the last screenshot taken.
-  if (current_screenshot)
-    current_screenshot_.reset(new ScreenshotData(*current_screenshot));
-  else
-    current_screenshot_.reset(new ScreenshotData());
-}
-
-ScreenshotSource::~ScreenshotSource() {}
-
-// static
-std::string ScreenshotSource::GetScreenshotBaseFilename() {
-  base::Time::Exploded now;
-  base::Time::Now().LocalExplode(&now);
-
-  // We don't use base/i18n/time_formatting.h here because it doesn't
-  // support our format.  Don't use ICU either to avoid i18n file names
-  // for non-English locales.
-  // TODO(mukai): integrate this logic somewhere time_formatting.h
-  std::string file_name = base::StringPrintf(
-      "Screenshot %d-%02d-%02d at ", now.year, now.month, now.day_of_month);
-
-  if (ShouldUse24HourClock()) {
-    file_name.append(base::StringPrintf(
-        "%02d.%02d.%02d", now.hour, now.minute, now.second));
-  } else {
-    int hour = now.hour;
-    if (hour > 12) {
-      hour -= 12;
-    } else if (hour == 0) {
-      hour = 12;
-    }
-    file_name.append(base::StringPrintf(
-        "%d.%02d.%02d ", hour, now.minute, now.second));
-    file_name.append((now.hour >= 12) ? "PM" : "AM");
-  }
-
-  return file_name;
-}
-
-#if defined(USE_ASH)
-
-// static
-bool ScreenshotSource::AreScreenshotsDisabled() {
-  return g_browser_process->local_state()->GetBoolean(
-      prefs::kDisableScreenshots);
-}
-
-// static
-bool ScreenshotSource::GetScreenshotDirectory(base::FilePath* directory) {
-  if (ScreenshotSource::AreScreenshotsDisabled())
-    return false;
-
-  bool is_logged_in = true;
-
-#if defined(OS_CHROMEOS)
-  is_logged_in = chromeos::LoginState::Get()->IsUserLoggedIn();
-#endif
-
-  if (is_logged_in) {
-    DownloadPrefs* download_prefs = DownloadPrefs::FromBrowserContext(
-        ash::Shell::GetInstance()->delegate()->GetCurrentBrowserContext());
-    *directory = download_prefs->DownloadPath();
-  } else  {
-    if (!file_util::GetTempDir(directory)) {
-      LOG(ERROR) << "Failed to find temporary directory.";
-      return false;
-    }
-  }
-  return true;
-}
-
-#endif
-
-std::string ScreenshotSource::GetSource() const {
-  return chrome::kChromeUIScreenshotPath;
-}
-
-void ScreenshotSource::StartDataRequest(
-  const std::string& path,
-  int render_process_id,
-  int render_view_id,
-  const content::URLDataSource::GotDataCallback& callback) {
-  SendScreenshot(path, callback);
-}
-
-std::string ScreenshotSource::GetMimeType(const std::string&) const {
-  // We need to explicitly return a mime type, otherwise if the user tries to
-  // drag the image they get no extension.
-  return "image/png";
-}
-
-ScreenshotDataPtr ScreenshotSource::GetCachedScreenshot(
-    const std::string& screenshot_path) {
-  std::map<std::string, ScreenshotDataPtr>::iterator pos;
-  std::string path = screenshot_path.substr(
-      0, screenshot_path.find_first_of("?"));
-  if ((pos = cached_screenshots_.find(path)) != cached_screenshots_.end()) {
-    return pos->second;
-  } else {
-    return ScreenshotDataPtr(new ScreenshotData);
-  }
-}
-
-void ScreenshotSource::SendScreenshot(
-    const std::string& screenshot_path,
-    const content::URLDataSource::GotDataCallback& callback) {
-  // Strip the query param value - we only use it as a hack to ensure our
-  // image gets reloaded instead of being pulled from the browser cache
-  std::string path = screenshot_path.substr(
-      0, screenshot_path.find_first_of("?"));
-  if (path == ScreenshotSource::kScreenshotCurrent) {
-    CacheAndSendScreenshot(path, callback, current_screenshot_);
-#if defined(OS_CHROMEOS)
-  } else if (path.compare(0, strlen(ScreenshotSource::kScreenshotSaved),
-             ScreenshotSource::kScreenshotSaved) == 0) {
-    using content::BrowserThread;
-
-    std::string filename =
-        path.substr(strlen(ScreenshotSource::kScreenshotSaved));
-
-    url_canon::RawCanonOutputT<char16> decoded;
-    url_util::DecodeURLEscapeSequences(
-        filename.data(), filename.size(), &decoded);
-    // Screenshot filenames don't use non-ascii characters.
-    std::string decoded_filename = UTF16ToASCII(string16(
-        decoded.data(), decoded.length()));
-
-    base::FilePath download_path;
-    GetScreenshotDirectory(&download_path);
-    if (drive::util::IsUnderDriveMountPoint(download_path)) {
-      drive::FileSystemInterface* file_system =
-          drive::DriveIntegrationServiceFactory::GetForProfile(
-              profile_)->file_system();
-      file_system->GetFileByPath(
-          drive::util::ExtractDrivePath(download_path).Append(decoded_filename),
-          base::Bind(&ScreenshotSource::GetSavedScreenshotCallback,
-                     base::Unretained(this), screenshot_path, callback));
-    } else {
-      BrowserThread::PostTask(
-          BrowserThread::FILE, FROM_HERE,
-          base::Bind(&ScreenshotSource::SendSavedScreenshot,
-                     base::Unretained(this),
-                     screenshot_path,
-                     callback, download_path.Append(decoded_filename)));
-    }
-#endif
-  } else {
-    CacheAndSendScreenshot(
-        path, callback, ScreenshotDataPtr(new ScreenshotData()));
-  }
-}
-
-#if defined(OS_CHROMEOS)
-void ScreenshotSource::SendSavedScreenshot(
-    const std::string& screenshot_path,
-    const content::URLDataSource::GotDataCallback& callback,
-    const base::FilePath& file) {
-  ScreenshotDataPtr read_bytes(new ScreenshotData);
-  int64 file_size = 0;
-
-  if (!file_util::GetFileSize(file, &file_size)) {
-    CacheAndSendScreenshot(screenshot_path, callback, read_bytes);
-    return;
-  }
-
-  read_bytes->resize(file_size);
-  if (!file_util::ReadFile(file, reinterpret_cast<char*>(&read_bytes->front()),
-                           static_cast<int>(file_size)))
-    read_bytes->clear();
-
-  CacheAndSendScreenshot(screenshot_path, callback, read_bytes);
-}
-
-void ScreenshotSource::GetSavedScreenshotCallback(
-    const std::string& screenshot_path,
-    const content::URLDataSource::GotDataCallback& callback,
-    drive::FileError error,
-    const base::FilePath& file,
-    scoped_ptr<drive::ResourceEntry> entry) {
-  if (error != drive::FILE_ERROR_OK) {
-    ScreenshotDataPtr read_bytes(new ScreenshotData);
-    CacheAndSendScreenshot(screenshot_path, callback, read_bytes);
-    return;
-  }
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::Bind(&ScreenshotSource::SendSavedScreenshot,
-                 base::Unretained(this), screenshot_path, callback, file));
-}
-#endif
-
-void ScreenshotSource::CacheAndSendScreenshot(
-    const std::string& screenshot_path,
-    const content::URLDataSource::GotDataCallback& callback,
-    ScreenshotDataPtr bytes) {
-  // Strip the query from the screenshot path.
-  std::string path = screenshot_path.substr(
-      0, screenshot_path.find_first_of("?"));
-  cached_screenshots_[path] = bytes;
-  callback.Run(new base::RefCountedBytes(*bytes));
-}
diff --git a/chrome/browser/ui/webui/screenshot_source.h b/chrome/browser/ui/webui/screenshot_source.h
deleted file mode 100644
index fdc76ae..0000000
--- a/chrome/browser/ui/webui/screenshot_source.h
+++ /dev/null
@@ -1,126 +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_BROWSER_UI_WEBUI_SCREENSHOT_SOURCE_H_
-#define CHROME_BROWSER_UI_WEBUI_SCREENSHOT_SOURCE_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/linked_ptr.h"
-#include "content/public/browser/url_data_source.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/drive/file_system_interface.h"
-#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/google_apis/gdata_errorcode.h"
-#endif
-
-typedef std::vector<unsigned char> ScreenshotData;
-typedef linked_ptr<ScreenshotData> ScreenshotDataPtr;
-
-class Profile;
-
-namespace base {
-class FilePath;
-}
-
-// ScreenshotSource is the data source that serves screenshots (saved
-// or current) to the bug report html ui.
-class ScreenshotSource : public content::URLDataSource {
- public:
-  explicit ScreenshotSource(
-      std::vector<unsigned char>* current_screenshot,
-      Profile* profile);
-
-#if defined(USE_ASH)
-  // Queries the browser process to determine if screenshots are disabled.
-  static bool AreScreenshotsDisabled();
-
-  // Common access for the screenshot directory, parameter is set to the
-  // requested directory and return value of true is given upon success.
-  static bool GetScreenshotDirectory(base::FilePath* directory);
-#endif
-
-  // Get the basefilename for screenshots
-  static std::string GetScreenshotBaseFilename();
-
-  // content::URLDataSource implementation.
-  virtual std::string GetSource() const OVERRIDE;
-  virtual void StartDataRequest(
-      const std::string& path,
-      int render_process_id,
-      int render_view_id,
-      const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
-  virtual std::string GetMimeType(const std::string&) const OVERRIDE;
-
-  // Get the screenshot specified by the given relative path that we've cached
-  // from a previous request to the screenshots source.
-  // Note: This method strips the query string from the given path.
-  ScreenshotDataPtr GetCachedScreenshot(const std::string& screenshot_path);
-
-  // Url that represents the base directory for screenshots.
-  static const char kScreenshotUrlRoot[];
-  // Identifier for the current screenshot
-  // (relative to screenshot base directory).
-  static const char kScreenshotCurrent[];
-  // Path for directory where screenshots are saved
-  // (relative to screenshot base directory).
-  static const char kScreenshotSaved[];
-#if defined(OS_CHROMEOS)
-  // Common prefix to screenshot filenames.
-  static const char kScreenshotPrefix[];
-  // Common suffix to screenshot filenames.
-  static const char kScreenshotSuffix[];
-#endif
-
- private:
-  virtual ~ScreenshotSource();
-
-  // Send the screenshot specified by the given relative path to the requestor.
-  // This is the ancestor for SendSavedScreenshot and CacheAndSendScreenshot.
-  // All calls to send a screenshot should only call this method.
-  // Note: This method strips the query string from the given path.
-  void SendScreenshot(const std::string& screenshot_path,
-                      const content::URLDataSource::GotDataCallback& callback);
-#if defined(OS_CHROMEOS)
-  // Send a saved screenshot image file specified by the given screenshot path
-  // to the requestor.
-  void SendSavedScreenshot(
-      const std::string& screenshot_path,
-      const content::URLDataSource::GotDataCallback& callback,
-      const base::FilePath& file);
-
-  // The callback for Drive's getting file method.
-  void GetSavedScreenshotCallback(
-      const std::string& screenshot_path,
-      const content::URLDataSource::GotDataCallback& callback,
-      drive::FileError error,
-      const base::FilePath& file,
-      scoped_ptr<drive::ResourceEntry> entry);
-
-#endif
-  // Sends the screenshot data to the requestor while caching it locally to the
-  // class instance, indexed by path.
-  void CacheAndSendScreenshot(
-      const std::string& screenshot_path,
-      const content::URLDataSource::GotDataCallback& callback,
-      ScreenshotDataPtr bytes);
-
-  // Pointer to the screenshot data for the current screenshot.
-  ScreenshotDataPtr current_screenshot_;
-
-  Profile* profile_;
-
-  // Key: Relative path to the screenshot (including filename)
-  // Value: Pointer to the screenshot data associated with the path.
-  std::map<std::string, ScreenshotDataPtr> cached_screenshots_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScreenshotSource);
-};
-
-#endif  // CHROME_BROWSER_UI_WEBUI_SCREENSHOT_SOURCE_H_
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
index 3405777..d5ea9fb 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -261,6 +261,8 @@
   web_ui()->RegisterMessageCallback("loadWallpaper", kDoNothingCallback);
   web_ui()->RegisterMessageCallback("updateCurrentScreen", kDoNothingCallback);
   web_ui()->RegisterMessageCallback("loginVisible", kDoNothingCallback);
+  // Unused callbacks from user_pod_row.js
+  web_ui()->RegisterMessageCallback("focusPod", kDoNothingCallback);
 }
 
 void UserManagerScreenHandler::GetLocalizedValues(
diff --git a/chrome/browser/ui/webui/signin/user_manager_ui_browsertest.cc b/chrome/browser/ui/webui/signin/user_manager_ui_browsertest.cc
new file mode 100644
index 0000000..d1cb865
--- /dev/null
+++ b/chrome/browser/ui/webui/signin/user_manager_ui_browsertest.cc
@@ -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.
+#include "base/command_line.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.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/in_process_browser_test.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+const GURL& url = GURL(chrome::kChromeUIUserManagerURL);
+}  // namespace
+
+class UserManagerUIBrowserTest : public InProcessBrowserTest,
+                                 public testing::WithParamInterface<bool> {
+ public:
+  UserManagerUIBrowserTest() {}
+
+ protected:
+   virtual void SetUp() OVERRIDE {
+    InProcessBrowserTest::SetUp();
+    DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+        switches::kNewProfileManagement));
+  }
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    command_line->AppendSwitch(switches::kNewProfileManagement);
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(UserManagerUIBrowserTest, PageLoads) {
+  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(), url, 1);
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  string16 title = web_contents->GetTitle();
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_USER_MANAGER_SCREEN_TITLE), title);
+
+  // If the page has loaded correctly, then there should be an account picker.
+  int num_account_pickers = -1;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+      web_contents,
+      "domAutomationController.send("
+      "document.getElementsByClassName('account-picker').length)",
+      &num_account_pickers));
+  EXPECT_EQ(1, num_account_pickers);
+
+  int num_pods = -1;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
+      web_contents,
+      "domAutomationController.send("
+      "parseInt(document.getElementById('pod-row').getAttribute('ncolumns')))",
+      &num_pods));
+
+  // There should be one user pod for each profile.
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  EXPECT_EQ(num_pods, static_cast<int>(profile_manager->GetNumberOfProfiles()));
+}
diff --git a/chrome/browser/ui/webui/theme_source.cc b/chrome/browser/ui/webui/theme_source.cc
index b3a5409..c58a586 100644
--- a/chrome/browser/ui/webui/theme_source.cc
+++ b/chrome/browser/ui/webui/theme_source.cc
@@ -43,8 +43,10 @@
 
 ThemeSource::ThemeSource(Profile* profile)
     : profile_(profile->GetOriginalProfile()) {
-  css_bytes_ = NTPResourceCacheFactory::GetForProfile(profile)->GetNewTabCSS(
-      profile->IsOffTheRecord());
+  NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType(
+      profile_, NULL);
+  css_bytes_ =
+      NTPResourceCacheFactory::GetForProfile(profile)->GetNewTabCSS(win_type);
 }
 
 ThemeSource::~ThemeSource() {
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc
index 1ed5cee..2eff4af 100644
--- a/chrome/browser/unload_browsertest.cc
+++ b/chrome/browser/unload_browsertest.cc
@@ -481,12 +481,15 @@
 
 // Test that fast-tab-close works when closing a tab with an unload handler
 // (http://crbug.com/142458).
-IN_PROC_BROWSER_TEST_F(FastUnloadTest, UnloadHidden) {
+// Flaky on Windows bots (http://crbug.com/267597).
 #if defined(OS_WIN)
-  // Flaky on Win7+ bots (http://crbug.com/267597).
-  if (base::win::GetVersion() >= base::win::VERSION_WIN7)
-    return;
+#define MAYBE_UnloadHidden \
+    DISABLED_UnloadHidden
+#else
+#define MAYBE_UnloadHidden \
+    UnloadHidden
 #endif
+IN_PROC_BROWSER_TEST_F(FastUnloadTest, MAYBE_UnloadHidden) {
   NavigateToPage("no_listeners");
   NavigateToPageInNewTab("unload_sets_cookie");
   EXPECT_EQ("", GetCookies("no_listeners"));
diff --git a/chrome/browser/user_style_sheet_watcher.cc b/chrome/browser/user_style_sheet_watcher.cc
index 2dd6414..a8774b5 100644
--- a/chrome/browser/user_style_sheet_watcher.cc
+++ b/chrome/browser/user_style_sheet_watcher.cc
@@ -8,7 +8,6 @@
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/chrome_notification_types.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
@@ -57,6 +56,9 @@
   // base64 URL.  Posts the base64 URL back to the UI thread.
   void LoadStyleSheet(const base::FilePath& style_sheet_file);
 
+  // Register a callback to be called whenever the stylesheet gets updated.
+  void RegisterOnStyleSheetUpdatedCallback(const base::Closure& callback);
+
   // Send out a notification if the stylesheet has already been loaded.
   void NotifyLoaded();
 
@@ -65,7 +67,7 @@
 
  private:
   friend class base::RefCountedThreadSafe<UserStyleSheetLoader>;
-  ~UserStyleSheetLoader() {}
+  ~UserStyleSheetLoader();
 
   // Called on the UI thread after the stylesheet has loaded.
   void SetStyleSheet(const GURL& url);
@@ -76,6 +78,8 @@
   // Whether the stylesheet has been loaded.
   bool has_loaded_;
 
+  std::vector<base::Closure> on_loaded_callbacks_;
+
   DISALLOW_COPY_AND_ASSIGN(UserStyleSheetLoader);
 };
 
@@ -83,12 +87,17 @@
     : has_loaded_(false) {
 }
 
+void UserStyleSheetLoader::RegisterOnStyleSheetUpdatedCallback(
+    const base::Closure& callback) {
+  on_loaded_callbacks_.push_back(callback);
+}
+
 void UserStyleSheetLoader::NotifyLoaded() {
   if (has_loaded_) {
-    content::NotificationService::current()->Notify(
-        chrome::NOTIFICATION_USER_STYLE_SHEET_UPDATED,
-        content::Source<UserStyleSheetLoader>(this),
-        content::NotificationService::NoDetails());
+    for (size_t i = 0; i < on_loaded_callbacks_.size(); ++i) {
+      if (!on_loaded_callbacks_[i].is_null())
+        on_loaded_callbacks_[i].Run();
+    }
   }
 }
 
@@ -129,6 +138,10 @@
                                      style_sheet_url));
 }
 
+UserStyleSheetLoader::~UserStyleSheetLoader() {
+  on_loaded_callbacks_.clear();
+}
+
 void UserStyleSheetLoader::SetStyleSheet(const GURL& url) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
@@ -181,6 +194,11 @@
   return loader_->user_style_sheet();
 }
 
+void UserStyleSheetWatcher::RegisterOnStyleSheetUpdatedCallback(
+    const base::Closure& callback) {
+  loader_->RegisterOnStyleSheetUpdatedCallback(callback);
+}
+
 void UserStyleSheetWatcher::Observe(int type,
     const content::NotificationSource& source,
     const content::NotificationDetails& details) {
diff --git a/chrome/browser/user_style_sheet_watcher.h b/chrome/browser/user_style_sheet_watcher.h
index 9ab8482..daa95ed 100644
--- a/chrome/browser/user_style_sheet_watcher.h
+++ b/chrome/browser/user_style_sheet_watcher.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_USER_STYLE_SHEET_WATCHER_H_
 #define CHROME_BROWSER_USER_STYLE_SHEET_WATCHER_H_
 
+#include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
 #include "base/memory/ref_counted.h"
@@ -30,6 +31,9 @@
 
   GURL user_style_sheet() const;
 
+  // Register a callback to be called whenever the stylesheet gets updated.
+  void RegisterOnStyleSheetUpdatedCallback(const base::Closure& callback);
+
   // content::NotificationObserver interface
   virtual void Observe(int type,
                        const content::NotificationSource& source,
diff --git a/chrome/browser/web_applications/web_app_linux.cc b/chrome/browser/web_applications/web_app_linux.cc
index 4371597..d616cf0 100644
--- a/chrome/browser/web_applications/web_app_linux.cc
+++ b/chrome/browser/web_applications/web_app_linux.cc
@@ -18,16 +18,22 @@
     const ShellIntegration::ShortcutInfo& shortcut_info,
     const ShellIntegration::ShortcutLocations& creation_locations,
     ShortcutCreationReason /*creation_reason*/) {
+#if !defined(OS_CHROMEOS)
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
   return ShellIntegrationLinux::CreateDesktopShortcut(
       shortcut_info, creation_locations);
+#else
+  return false;
+#endif
 }
 
 void DeletePlatformShortcuts(
     const base::FilePath& web_app_path,
     const ShellIntegration::ShortcutInfo& shortcut_info) {
+#if !defined(OS_CHROMEOS)
   ShellIntegrationLinux::DeleteDesktopShortcuts(shortcut_info.profile_path,
       shortcut_info.extension_id);
+#endif
 }
 
 void UpdatePlatformShortcuts(
@@ -56,7 +62,9 @@
 }
 
 void DeleteAllShortcutsForProfile(const base::FilePath& profile_path) {
+#if !defined(OS_CHROMEOS)
   ShellIntegrationLinux::DeleteAllDesktopShortcuts(profile_path);
+#endif
 }
 
 }  // namespace internals
diff --git a/chrome/browser/web_applications/web_app_mac.h b/chrome/browser/web_applications/web_app_mac.h
index e469aed..f47f64f 100644
--- a/chrome/browser/web_applications/web_app_mac.h
+++ b/chrome/browser/web_applications/web_app_mac.h
@@ -5,22 +5,15 @@
 #ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_MAC_H_
 #define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_MAC_H_
 
+#include <string>
 #include <vector>
 
+#include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
-#include "base/strings/string16.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/web_applications/web_app.h"
 
-#ifdef __OBJC__
-@class NSDictionary;
-@class NSString;
-#else  // __OBJC__
-class NSDictionary;
-class NSString;
-#endif  // __OBJC__
-
 namespace web_app {
 
 // Returns the full path of the .app shim that would be created by
@@ -36,46 +29,52 @@
 class WebAppShortcutCreator {
  public:
   // Creates a new shortcut based on information in |shortcut_info|.
-  // A copy of the shortcut is placed in |app_data_path|.
+  // A copy of the shortcut is placed in |app_data_dir|.
   // |chrome_bundle_id| is the CFBundleIdentifier of the Chrome browser bundle.
   WebAppShortcutCreator(
-      const base::FilePath& app_data_path,
-      const ShellIntegration::ShortcutInfo& shortcut_info,
-      const std::string& chrome_bundle_id);
+      const base::FilePath& app_data_dir,
+      const ShellIntegration::ShortcutInfo& shortcut_info);
 
   virtual ~WebAppShortcutCreator();
 
   // Returns the base name for the shortcut.
-  base::FilePath GetShortcutName() const;
+  base::FilePath GetShortcutBasename() const;
 
   // Returns a path to the Chrome Apps folder in the relevant applications
   // folder. E.g. ~/Applications or /Applications.
-  virtual base::FilePath GetDestinationPath() const;
+  virtual base::FilePath GetApplicationsDirname() const;
 
-  bool CreateShortcuts(ShortcutCreationReason creation_reason);
+  // The full path to the app bundle under the relevant Applications folder.
+  base::FilePath GetApplicationsShortcutPath() const;
+
+  // The full path to the app bundle under the profile folder.
+  base::FilePath GetInternalShortcutPath() const;
+
+  bool CreateShortcuts(ShortcutCreationReason creation_reason,
+                       ShellIntegration::ShortcutLocations creation_locations);
   void DeleteShortcuts();
   bool UpdateShortcuts();
 
  protected:
-  // Returns a path to the app loader.
-  base::FilePath GetAppLoaderPath() const;
-
-  // Updates the plist inside |app_path| with information about the app.
-  bool UpdatePlist(const base::FilePath& app_path) const;
-
-  // Updates the icon for the shortcut.
-  bool UpdateIcon(const base::FilePath& app_path) const;
-
   // Returns a path to an app bundle with the given id. Or an empty path if no
   // matching bundle was found.
   // Protected and virtual so it can be mocked out for testing.
   virtual base::FilePath GetAppBundleById(const std::string& bundle_id) const;
 
+  // Show the bundle we just generated in the Finder.
+  virtual void RevealAppShimInFinder() const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(WebAppShortcutCreatorTest, DeleteShortcuts);
   FRIEND_TEST_ALL_PREFIXES(WebAppShortcutCreatorTest, UpdateIcon);
   FRIEND_TEST_ALL_PREFIXES(WebAppShortcutCreatorTest, UpdateShortcuts);
 
+  // Returns the bundle identifier to use for this app bundle.
+  std::string GetBundleIdentifier() const;
+
+  // Returns the bundle identifier for the internal copy of the bundle.
+  std::string GetInternalBundleIdentifier() const;
+
   // Copies the app loader template into a temporary directory and fills in all
   // relevant information.
   bool BuildShortcut(const base::FilePath& staging_path) const;
@@ -91,24 +90,20 @@
   // Updates the bundle id of the internal copy of the app shim bundle.
   bool UpdateInternalBundleIdentifier() const;
 
-  // Returns the bundle identifier to use for this app bundle.
-  std::string GetBundleIdentifier() const;
+  // Updates the plist inside |app_path| with information about the app.
+  bool UpdatePlist(const base::FilePath& app_path) const;
 
-  // Returns the bundle identifier for the internal copy of the bundle.
-  std::string GetInternalBundleIdentifier() const;
-
-  // Show the bundle we just generated in the Finder.
-  virtual void RevealAppShimInFinder() const;
+  // Updates the icon for the shortcut.
+  bool UpdateIcon(const base::FilePath& app_path) const;
 
   // Path to the data directory for this app. For example:
   // ~/Library/Application Support/Chromium/Default/Web Applications/_crx_abc/
-  base::FilePath app_data_path_;
+  base::FilePath app_data_dir_;
 
   // Information about the app.
   ShellIntegration::ShortcutInfo info_;
 
-  // The CFBundleIdentifier of the Chrome browser bundle.
-  std::string chrome_bundle_id_;
+  DISALLOW_COPY_AND_ASSIGN(WebAppShortcutCreator);
 };
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_mac.mm b/chrome/browser/web_applications/web_app_mac.mm
index c22c8a4..3811329 100644
--- a/chrome/browser/web_applications/web_app_mac.mm
+++ b/chrome/browser/web_applications/web_app_mac.mm
@@ -12,33 +12,29 @@
 #include "base/file_util.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/mac/bundle_locations.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/launch_services_util.h"
-#include "base/mac/mac_logging.h"
 #include "base/mac/mac_util.h"
 #include "base/mac/scoped_cftyperef.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
+#include "base/strings/string16.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/mac/dock.h"
-#include "chrome/browser/ui/web_applications/web_app_ui.h"
-#include "chrome/browser/web_applications/web_app.h"
+#import "chrome/browser/mac/dock.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/mac/app_mode_common.h"
+#import "chrome/common/mac/app_mode_common.h"
 #include "content/public/browser/browser_thread.h"
 #include "grit/chromium_strings.h"
-#include "skia/ext/skia_utils_mac.h"
+#import "skia/ext/skia_utils_mac.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
+#import "ui/base/l10n/l10n_util_mac.h"
 #include "ui/gfx/image/image_family.h"
 
 namespace {
@@ -182,7 +178,7 @@
 // Takes the path to an app bundle and checks that the CrAppModeUserDataDir in
 // the Info.plist starts with the current user_data_dir. This uses starts with
 // instead of equals because the CrAppModeUserDataDir could be the user_data_dir
-// or the app_data_path.
+// or the |app_data_dir_|.
 bool HasSameUserDataDir(const base::FilePath& bundle_path) {
   NSDictionary* plist = ReadPlist(GetPlistPath(bundle_path));
   base::FilePath user_data_dir;
@@ -204,10 +200,10 @@
       !base::PathExists(shim_path) ||
       !HasSameUserDataDir(shim_path)) {
     // The user may have deleted the copy in the Applications folder, use the
-    // one in the web app's app_data_path.
-    base::FilePath app_data_path = web_app::GetWebAppDataDirectory(
+    // one in the web app's |app_data_dir_|.
+    base::FilePath app_data_dir = web_app::GetWebAppDataDirectory(
         shortcut_info.profile_path, shortcut_info.extension_id, GURL());
-    shim_path = app_data_path.Append(shim_path.BaseName());
+    shim_path = app_data_dir.Append(shim_path.BaseName());
   }
 
   if (!base::PathExists(shim_path))
@@ -220,21 +216,26 @@
       shim_path, command_line, kLSLaunchDefaults | kLSLaunchDontSwitch, NULL);
 }
 
+base::FilePath GetAppLoaderPath() {
+  return base::mac::PathForFrameworkBundleResource(
+      base::mac::NSToCFCast(@"app_mode_loader.app"));
+}
+
 base::FilePath GetLocalizableAppShortcutsSubdirName() {
-#if defined(GOOGLE_CHROME_BUILD)
+  static const char kChromiumAppDirName[] = "Chromium Apps.localized";
   static const char kChromeAppDirName[] = "Chrome Apps.localized";
   static const char kChromeCanaryAppDirName[] = "Chrome Canary Apps.localized";
 
-  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
-  if (channel == chrome::VersionInfo::CHANNEL_CANARY)
-    return base::FilePath(kChromeCanaryAppDirName);
+  switch (chrome::VersionInfo::GetChannel()) {
+    case chrome::VersionInfo::CHANNEL_UNKNOWN:
+      return base::FilePath(kChromiumAppDirName);
 
-  return base::FilePath(kChromeAppDirName);
-#else
-  static const char kChromiumAppDirName[] = "Chromium Apps.localized";
+    case chrome::VersionInfo::CHANNEL_CANARY:
+      return base::FilePath(kChromeCanaryAppDirName);
 
-  return base::FilePath(kChromiumAppDirName);
-#endif
+    default:
+      return base::FilePath(kChromeAppDirName);
+  }
 }
 
 // Adds a localized strings file for the Chrome Apps directory using the current
@@ -337,20 +338,25 @@
 
 namespace web_app {
 
-
 WebAppShortcutCreator::WebAppShortcutCreator(
-    const base::FilePath& app_data_path,
-    const ShellIntegration::ShortcutInfo& shortcut_info,
-    const std::string& chrome_bundle_id)
-    : app_data_path_(app_data_path),
-      info_(shortcut_info),
-      chrome_bundle_id_(chrome_bundle_id) {
+    const base::FilePath& app_data_dir,
+    const ShellIntegration::ShortcutInfo& shortcut_info)
+    : app_data_dir_(app_data_dir),
+      info_(shortcut_info) {}
+
+WebAppShortcutCreator::~WebAppShortcutCreator() {}
+
+base::FilePath WebAppShortcutCreator::GetApplicationsShortcutPath() const {
+  base::FilePath applications_dir = GetApplicationsDirname();
+  return applications_dir.empty() ?
+      base::FilePath() : applications_dir.Append(GetShortcutBasename());
 }
 
-WebAppShortcutCreator::~WebAppShortcutCreator() {
+base::FilePath WebAppShortcutCreator::GetInternalShortcutPath() const {
+  return app_data_dir_.Append(GetShortcutBasename());
 }
 
-base::FilePath WebAppShortcutCreator::GetShortcutName() const {
+base::FilePath WebAppShortcutCreator::GetShortcutBasename() const {
   std::string app_name;
   // Check if there should be a separate shortcut made for different profiles.
   // Such shortcuts will have a |profile_name| set on the ShortcutInfo,
@@ -373,16 +379,9 @@
     return false;
   }
 
-  if (!UpdatePlist(staging_path))
-    return false;
-
-  if (!UpdateDisplayName(staging_path))
-    return false;
-
-  if (!UpdateIcon(staging_path))
-    return false;
-
-  return true;
+  return UpdatePlist(staging_path) &&
+      UpdateDisplayName(staging_path) &&
+      UpdateIcon(staging_path);
 }
 
 size_t WebAppShortcutCreator::CreateShortcutsIn(
@@ -393,7 +392,7 @@
   if (!scoped_temp_dir.CreateUniqueTempDir())
     return 0;
 
-  base::FilePath app_name = GetShortcutName();
+  base::FilePath app_name = GetShortcutBasename();
   base::FilePath staging_path = scoped_temp_dir.path().Append(app_name);
   if (!BuildShortcut(staging_path))
     return 0;
@@ -420,15 +419,16 @@
 }
 
 bool WebAppShortcutCreator::CreateShortcuts(
-    ShortcutCreationReason creation_reason) {
-  const base::FilePath applications_path = GetDestinationPath();
-  if (applications_path.empty() ||
-      !base::DirectoryExists(applications_path.DirName())) {
+    ShortcutCreationReason creation_reason,
+    ShellIntegration::ShortcutLocations creation_locations) {
+  const base::FilePath applications_dir = GetApplicationsDirname();
+  if (applications_dir.empty() ||
+      !base::DirectoryExists(applications_dir.DirName())) {
     LOG(ERROR) << "Couldn't find an Applications directory to copy app to.";
     return false;
   }
 
-  UpdateAppShortcutsSubdirLocalizedName(applications_path);
+  UpdateAppShortcutsSubdirLocalizedName(applications_dir);
 
   // If non-nil, this path is added to the OSX Dock after creating shortcuts.
   NSString* path_to_add_to_dock = nil;
@@ -444,12 +444,12 @@
     base::FilePath user_data_dir;
     CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
     path_to_add_to_dock = base::SysUTF8ToNSString(
-        user_data_dir.Append(GetShortcutName()).AsUTF8Unsafe());
+        user_data_dir.Append(GetShortcutBasename()).AsUTF8Unsafe());
     paths.push_back(user_data_dir);
   } else {
-    paths.push_back(app_data_path_);
+    paths.push_back(app_data_dir_);
   }
-  paths.push_back(applications_path);
+  paths.push_back(applications_dir);
 
   size_t success_count = CreateShortcutsIn(paths);
   if (success_count == 0)
@@ -461,7 +461,7 @@
   if (success_count != paths.size())
     return false;
 
-  if (path_to_add_to_dock)
+  if (creation_locations.in_quick_launch_bar && path_to_add_to_dock)
     dock::AddIcon(path_to_add_to_dock, nil);
 
   if (creation_reason == SHORTCUT_CREATION_BY_USER)
@@ -471,12 +471,9 @@
 }
 
 void WebAppShortcutCreator::DeleteShortcuts() {
-  base::FilePath dst_path = GetDestinationPath();
-  if (!dst_path.empty()) {
-    base::FilePath bundle_path = dst_path.Append(GetShortcutName());
-    if (HasSameUserDataDir(bundle_path))
-      DeletePathAndParentIfEmpty(bundle_path);
-  }
+  base::FilePath app_path = GetApplicationsShortcutPath();
+  if (!app_path.empty() && HasSameUserDataDir(app_path))
+    DeletePathAndParentIfEmpty(app_path);
 
   // In case the user has moved/renamed/copied the app bundle.
   base::FilePath bundle_path = GetAppBundleById(GetBundleIdentifier());
@@ -484,20 +481,18 @@
     base::DeleteFile(bundle_path, true);
 
   // Delete the internal one.
-  DeletePathAndParentIfEmpty(app_data_path_.Append(GetShortcutName()));
+  DeletePathAndParentIfEmpty(GetInternalShortcutPath());
 }
 
 bool WebAppShortcutCreator::UpdateShortcuts() {
   std::vector<base::FilePath> paths;
-  base::DeleteFile(app_data_path_.Append(GetShortcutName()), true);
-  paths.push_back(app_data_path_);
+  base::DeleteFile(GetInternalShortcutPath(), true);
+  paths.push_back(app_data_dir_);
 
-  base::FilePath dst_path = GetDestinationPath();
-  base::FilePath app_path = dst_path.Append(GetShortcutName());
-
-  // If the path does not exist, check if a matching bundle can be found
-  // elsewhere.
-  if (dst_path.empty() || !base::PathExists(app_path))
+  // Try to update the copy under /Applications. If that does not exist, check
+  // if a matching bundle can be found elsewhere.
+  base::FilePath app_path = GetApplicationsShortcutPath();
+  if (app_path.empty() || !base::PathExists(app_path))
     app_path = GetAppBundleById(GetBundleIdentifier());
 
   if (!app_path.empty()) {
@@ -513,15 +508,11 @@
   return success_count == paths.size() && !app_path.empty();
 }
 
-base::FilePath WebAppShortcutCreator::GetAppLoaderPath() const {
-  return base::mac::PathForFrameworkBundleResource(
-      base::mac::NSToCFCast(@"app_mode_loader.app"));
-}
-
-base::FilePath WebAppShortcutCreator::GetDestinationPath() const {
+base::FilePath WebAppShortcutCreator::GetApplicationsDirname() const {
   base::FilePath path = GetWritableApplicationsDirectory();
   if (path.empty())
     return path;
+
   return path.Append(GetLocalizableAppShortcutsSubdirName());
 }
 
@@ -529,7 +520,8 @@
   NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id);
   NSString* extension_title = base::SysUTF16ToNSString(info_.title);
   NSString* extension_url = base::SysUTF8ToNSString(info_.url.spec());
-  NSString* chrome_bundle_id = base::SysUTF8ToNSString(chrome_bundle_id_);
+  NSString* chrome_bundle_id =
+      base::SysUTF8ToNSString(base::mac::BaseBundleID());
   NSDictionary* replacement_dict =
       [NSDictionary dictionaryWithObjectsAndKeys:
           extension_id, app_mode::kShortcutIdPlaceholder,
@@ -560,7 +552,7 @@
   // 2. Fill in other values.
   [plist setObject:base::SysUTF8ToNSString(GetBundleIdentifier())
             forKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)];
-  [plist setObject:base::mac::FilePathToNSString(app_data_path_)
+  [plist setObject:base::mac::FilePathToNSString(app_data_dir_)
             forKey:app_mode::kCrAppModeUserDataDirKey];
   [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName())
             forKey:app_mode::kCrAppModeProfileDirKey];
@@ -592,7 +584,7 @@
 
   NSString* bundle_name = base::SysUTF16ToNSString(info_.title);
   NSString* display_name = base::SysUTF16ToNSString(info_.title);
-  if (HasExistingExtensionShim(GetDestinationPath(),
+  if (HasExistingExtensionShim(GetApplicationsDirname(),
                                info_.extension_id,
                                app_path.BaseName())) {
     display_name = [bundle_name
@@ -641,7 +633,7 @@
 }
 
 bool WebAppShortcutCreator::UpdateInternalBundleIdentifier() const {
-  NSString* plist_path = GetPlistPath(app_data_path_.Append(GetShortcutName()));
+  NSString* plist_path = GetPlistPath(GetInternalShortcutPath());
   NSMutableDictionary* plist = ReadPlist(plist_path);
 
   [plist setObject:base::SysUTF8ToNSString(GetInternalBundleIdentifier())
@@ -673,7 +665,7 @@
 
   // This matches APP_MODE_APP_BUNDLE_ID in chrome/chrome.gyp.
   std::string bundle_id =
-      chrome_bundle_id_ + std::string(".app.") +
+      base::mac::BaseBundleID() + std::string(".app.") +
       normalized_profile_path + "-" + info_.extension_id;
 
   return bundle_id;
@@ -684,11 +676,10 @@
 }
 
 void WebAppShortcutCreator::RevealAppShimInFinder() const {
-  base::FilePath dst_path = GetDestinationPath();
-  if (dst_path.empty())
+  base::FilePath app_path = GetApplicationsShortcutPath();
+  if (app_path.empty())
     return;
 
-  base::FilePath app_path = dst_path.Append(GetShortcutName());
   [[NSWorkspace sharedWorkspace]
                     selectFile:base::mac::FilePathToNSString(app_path)
       inFileViewerRootedAtPath:nil];
@@ -696,12 +687,8 @@
 
 base::FilePath GetAppInstallPath(
     const ShellIntegration::ShortcutInfo& shortcut_info) {
-  WebAppShortcutCreator shortcut_creator(base::FilePath(),
-                                         shortcut_info,
-                                         std::string());
-  base::FilePath dst_path = shortcut_creator.GetDestinationPath();
-  return dst_path.empty() ?
-      base::FilePath() : dst_path.Append(shortcut_creator.GetShortcutName());
+  WebAppShortcutCreator shortcut_creator(base::FilePath(), shortcut_info);
+  return shortcut_creator.GetApplicationsShortcutPath();
 }
 
 void MaybeLaunchShortcut(const ShellIntegration::ShortcutInfo& shortcut_info) {
@@ -721,17 +708,15 @@
     const ShellIntegration::ShortcutLocations& creation_locations,
     ShortcutCreationReason creation_reason) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  WebAppShortcutCreator shortcut_creator(
-      app_data_path, shortcut_info, base::mac::BaseBundleID());
-  return shortcut_creator.CreateShortcuts(creation_reason);
+  WebAppShortcutCreator shortcut_creator(app_data_path, shortcut_info);
+  return shortcut_creator.CreateShortcuts(creation_reason, creation_locations);
 }
 
 void DeletePlatformShortcuts(
     const base::FilePath& app_data_path,
     const ShellIntegration::ShortcutInfo& shortcut_info) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  WebAppShortcutCreator shortcut_creator(
-      app_data_path, shortcut_info, base::mac::BaseBundleID());
+  WebAppShortcutCreator shortcut_creator(app_data_path, shortcut_info);
   shortcut_creator.DeleteShortcuts();
 }
 
@@ -740,8 +725,7 @@
     const string16& old_app_title,
     const ShellIntegration::ShortcutInfo& shortcut_info) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
-  WebAppShortcutCreator shortcut_creator(
-      app_data_path, shortcut_info, base::mac::BaseBundleID());
+  WebAppShortcutCreator shortcut_creator(app_data_path, shortcut_info);
   shortcut_creator.UpdateShortcuts();
 }
 
@@ -754,8 +738,7 @@
        it != bundles.end(); ++it) {
     ShellIntegration::ShortcutInfo shortcut_info =
         BuildShortcutInfoFromBundle(*it);
-    WebAppShortcutCreator shortcut_creator(
-        it->DirName(), shortcut_info, base::mac::BaseBundleID());
+    WebAppShortcutCreator shortcut_creator(it->DirName(), shortcut_info);
     shortcut_creator.DeleteShortcuts();
   }
 }
diff --git a/chrome/browser/web_applications/web_app_mac_unittest.mm b/chrome/browser/web_applications/web_app_mac_unittest.mm
index 817de70..4b2909a 100644
--- a/chrome/browser/web_applications/web_app_mac_unittest.mm
+++ b/chrome/browser/web_applications/web_app_mac_unittest.mm
@@ -5,7 +5,6 @@
 #import "chrome/browser/web_applications/web_app_mac.h"
 
 #import <Cocoa/Cocoa.h>
-
 #include <errno.h>
 #include <sys/xattr.h>
 
@@ -17,7 +16,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/mac/app_mode_common.h"
+#import "chrome/common/mac/app_mode_common.h"
 #include "grit/theme_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,17 +36,19 @@
 class WebAppShortcutCreatorMock : public web_app::WebAppShortcutCreator {
  public:
   explicit WebAppShortcutCreatorMock(
-      const base::FilePath& app_data_path,
+      const base::FilePath& app_data_dir,
       const ShellIntegration::ShortcutInfo& shortcut_info)
-      : WebAppShortcutCreator(app_data_path,
-                              shortcut_info,
-                              kFakeChromeBundleId) {
+      : WebAppShortcutCreator(app_data_dir,
+                              shortcut_info) {
   }
 
-  MOCK_CONST_METHOD0(GetDestinationPath, base::FilePath());
+  MOCK_CONST_METHOD0(GetApplicationsDirname, base::FilePath());
   MOCK_CONST_METHOD1(GetAppBundleById,
                      base::FilePath(const std::string& bundle_id));
   MOCK_CONST_METHOD0(RevealAppShimInFinder, void());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebAppShortcutCreatorMock);
 };
 
 ShellIntegration::ShortcutInfo GetShortcutInfo() {
@@ -66,28 +67,31 @@
   WebAppShortcutCreatorTest() {}
 
   virtual void SetUp() {
-    EXPECT_TRUE(app_data_path_temp_dir_.CreateUniqueTempDir());
-    EXPECT_TRUE(destination_path_temp_dir_.CreateUniqueTempDir());
-    app_data_path_ = app_data_path_temp_dir_.path();
-    destination_path_ = destination_path_temp_dir_.path();
+    base::mac::SetBaseBundleID(kFakeChromeBundleId);
+
+    EXPECT_TRUE(temp_app_data_dir_.CreateUniqueTempDir());
+    EXPECT_TRUE(temp_destination_dir_.CreateUniqueTempDir());
+    app_data_dir_ = temp_app_data_dir_.path();
+    destination_dir_ = temp_destination_dir_.path();
 
     info_ = GetShortcutInfo();
     shim_base_name_ = base::FilePath(
         info_.profile_path.BaseName().value() +
         " " + info_.extension_id + ".app");
-    internal_shim_path_ = app_data_path_.Append(shim_base_name_);
-    shim_path_ = destination_path_.Append(shim_base_name_);
+    internal_shim_path_ = app_data_dir_.Append(shim_base_name_);
+    shim_path_ = destination_dir_.Append(shim_base_name_);
   }
 
-  base::ScopedTempDir app_data_path_temp_dir_;
-  base::ScopedTempDir destination_path_temp_dir_;
-  base::FilePath app_data_path_;
-  base::FilePath destination_path_;
+  base::ScopedTempDir temp_app_data_dir_;
+  base::ScopedTempDir temp_destination_dir_;
+  base::FilePath app_data_dir_;
+  base::FilePath destination_dir_;
 
   ShellIntegration::ShortcutInfo info_;
   base::FilePath shim_base_name_;
   base::FilePath internal_shim_path_;
   base::FilePath shim_path_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(WebAppShortcutCreatorTest);
 };
@@ -98,14 +102,15 @@
 namespace web_app {
 
 TEST_F(WebAppShortcutCreatorTest, CreateShortcuts) {
-  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_path_, info_);
-  EXPECT_CALL(shortcut_creator, GetDestinationPath())
-      .WillRepeatedly(Return(destination_path_));
+  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
+  EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
+      .WillRepeatedly(Return(destination_dir_));
 
-  EXPECT_TRUE(shortcut_creator.CreateShortcuts(SHORTCUT_CREATION_AUTOMATED));
+  EXPECT_TRUE(shortcut_creator.CreateShortcuts(
+      SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
   EXPECT_TRUE(base::PathExists(shim_path_));
-  EXPECT_TRUE(base::PathExists(destination_path_));
-  EXPECT_EQ(shim_base_name_, shortcut_creator.GetShortcutName());
+  EXPECT_TRUE(base::PathExists(destination_dir_));
+  EXPECT_EQ(shim_base_name_, shortcut_creator.GetShortcutBasename());
 
   base::FilePath plist_path =
       shim_path_.Append("Contents").Append("Info.plist");
@@ -135,9 +140,9 @@
   base::FilePath other_folder = other_folder_temp_dir.path();
   base::FilePath other_shim_path = other_folder.Append(shim_base_name_);
 
-  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_path_, info_);
-  EXPECT_CALL(shortcut_creator, GetDestinationPath())
-      .WillRepeatedly(Return(destination_path_));
+  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
+  EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
+      .WillRepeatedly(Return(destination_dir_));
 
   std::string expected_bundle_id = kFakeChromeBundleId;
   expected_bundle_id += ".app.Profile-1-" + info_.extension_id;
@@ -169,23 +174,24 @@
   // When using PathService::Override, it calls base::MakeAbsoluteFilePath.
   // On Mac this prepends "/private" to the path, but points to the same
   // directory in the file system.
-  app_data_path_ = base::MakeAbsoluteFilePath(app_data_path_);
+  app_data_dir_ = base::MakeAbsoluteFilePath(app_data_dir_);
 
   base::ScopedTempDir other_folder_temp_dir;
   EXPECT_TRUE(other_folder_temp_dir.CreateUniqueTempDir());
   base::FilePath other_folder = other_folder_temp_dir.path();
   base::FilePath other_shim_path = other_folder.Append(shim_base_name_);
 
-  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_path_, info_);
-  EXPECT_CALL(shortcut_creator, GetDestinationPath())
-      .WillRepeatedly(Return(destination_path_));
+  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
+  EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
+      .WillRepeatedly(Return(destination_dir_));
 
   std::string expected_bundle_id = kFakeChromeBundleId;
   expected_bundle_id += ".app.Profile-1-" + info_.extension_id;
   EXPECT_CALL(shortcut_creator, GetAppBundleById(expected_bundle_id))
       .WillOnce(Return(other_shim_path));
 
-  EXPECT_TRUE(shortcut_creator.CreateShortcuts(SHORTCUT_CREATION_AUTOMATED));
+  EXPECT_TRUE(shortcut_creator.CreateShortcuts(
+      SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
   EXPECT_TRUE(base::PathExists(internal_shim_path_));
   EXPECT_TRUE(base::PathExists(shim_path_));
 
@@ -205,7 +211,7 @@
   [plist writeToFile:plist_path
           atomically:YES];
 
-  EXPECT_TRUE(PathService::Override(chrome::DIR_USER_DATA, app_data_path_));
+  EXPECT_TRUE(PathService::Override(chrome::DIR_USER_DATA, app_data_dir_));
   shortcut_creator.DeleteShortcuts();
   EXPECT_FALSE(base::PathExists(internal_shim_path_));
   EXPECT_TRUE(base::PathExists(shim_path_));
@@ -217,20 +223,21 @@
   // directory prepended to the extension id on the app bundle name.
   info_.profile_name.clear();
   base::FilePath dst_path =
-      destination_path_.Append(info_.extension_id + ".app");
+      destination_dir_.Append(info_.extension_id + ".app");
 
   NiceMock<WebAppShortcutCreatorMock> shortcut_creator(base::FilePath(), info_);
-  EXPECT_CALL(shortcut_creator, GetDestinationPath())
-      .WillRepeatedly(Return(destination_path_));
-  EXPECT_EQ(dst_path.BaseName(), shortcut_creator.GetShortcutName());
+  EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
+      .WillRepeatedly(Return(destination_dir_));
+  EXPECT_EQ(dst_path.BaseName(), shortcut_creator.GetShortcutBasename());
 }
 
 TEST_F(WebAppShortcutCreatorTest, RunShortcut) {
-  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_path_, info_);
-  EXPECT_CALL(shortcut_creator, GetDestinationPath())
-      .WillRepeatedly(Return(destination_path_));
+  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
+  EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
+      .WillRepeatedly(Return(destination_dir_));
 
-  EXPECT_TRUE(shortcut_creator.CreateShortcuts(SHORTCUT_CREATION_AUTOMATED));
+  EXPECT_TRUE(shortcut_creator.CreateShortcuts(
+      SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
   EXPECT_TRUE(base::PathExists(shim_path_));
 
   ssize_t status = getxattr(
@@ -241,12 +248,13 @@
 
 TEST_F(WebAppShortcutCreatorTest, CreateFailure) {
   base::FilePath non_existent_path =
-      destination_path_.Append("not-existent").Append("name.app");
+      destination_dir_.Append("not-existent").Append("name.app");
 
-  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_path_, info_);
-  EXPECT_CALL(shortcut_creator, GetDestinationPath())
+  NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_);
+  EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
       .WillRepeatedly(Return(non_existent_path));
-  EXPECT_FALSE(shortcut_creator.CreateShortcuts(SHORTCUT_CREATION_AUTOMATED));
+  EXPECT_FALSE(shortcut_creator.CreateShortcuts(
+      SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
 }
 
 TEST_F(WebAppShortcutCreatorTest, UpdateIcon) {
@@ -254,7 +262,7 @@
       ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
           IDR_PRODUCT_LOGO_32);
   info_.favicon.Add(product_logo);
-  WebAppShortcutCreatorMock shortcut_creator(app_data_path_, info_);
+  WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_);
 
   ASSERT_TRUE(shortcut_creator.UpdateIcon(shim_path_));
   base::FilePath icon_path =
@@ -268,16 +276,18 @@
 }
 
 TEST_F(WebAppShortcutCreatorTest, RevealAppShimInFinder) {
-  WebAppShortcutCreatorMock shortcut_creator(app_data_path_, info_);
-  EXPECT_CALL(shortcut_creator, GetDestinationPath())
-      .WillRepeatedly(Return(destination_path_));
+  WebAppShortcutCreatorMock shortcut_creator(app_data_dir_, info_);
+  EXPECT_CALL(shortcut_creator, GetApplicationsDirname())
+      .WillRepeatedly(Return(destination_dir_));
 
   EXPECT_CALL(shortcut_creator, RevealAppShimInFinder())
       .Times(0);
-  EXPECT_TRUE(shortcut_creator.CreateShortcuts(SHORTCUT_CREATION_AUTOMATED));
+  EXPECT_TRUE(shortcut_creator.CreateShortcuts(
+      SHORTCUT_CREATION_AUTOMATED, ShellIntegration::ShortcutLocations()));
 
   EXPECT_CALL(shortcut_creator, RevealAppShimInFinder());
-  EXPECT_TRUE(shortcut_creator.CreateShortcuts(SHORTCUT_CREATION_BY_USER));
+  EXPECT_TRUE(shortcut_creator.CreateShortcuts(
+      SHORTCUT_CREATION_BY_USER, ShellIntegration::ShortcutLocations()));
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/webdata/keyword_table.cc b/chrome/browser/webdata/keyword_table.cc
index b6816d1..ec02c29 100644
--- a/chrome/browser/webdata/keyword_table.cc
+++ b/chrome/browser/webdata/keyword_table.cc
@@ -76,6 +76,10 @@
     columns.push_back("instant_url_post_params");
     columns.push_back("image_url_post_params");
   }
+  if (version >= 53) {
+    // Column added in version 53.
+    columns.push_back("new_tab_url");
+  }
 
   return JoinString(columns, std::string(concatenated ? " || " : ", "));
 }
@@ -127,6 +131,7 @@
   s->BindString(starting_column + 20, data.suggestions_url_post_params);
   s->BindString(starting_column + 21, data.instant_url_post_params);
   s->BindString(starting_column + 22, data.image_url_post_params);
+  s->BindString(starting_column + 23, data.new_tab_url);
 }
 
 WebDatabaseTable::TypeKey GetKey() {
@@ -178,7 +183,8 @@
                    "search_url_post_params VARCHAR,"
                    "suggest_url_post_params VARCHAR,"
                    "instant_url_post_params VARCHAR,"
-                   "image_url_post_params VARCHAR)");
+                   "image_url_post_params VARCHAR,"
+                   "new_tab_url VARCHAR)");
 }
 
 bool KeywordTable::IsSyncable() {
@@ -228,6 +234,9 @@
     case 52:
       *update_compatible_version = true;
       return MigrateToVersion52AddImageSearchAndPOSTSupport();
+    case 53:
+      *update_compatible_version = true;
+      return MigrateToVersion53AddNewTabURLColumn();
   }
 
   return true;
@@ -236,7 +245,8 @@
 bool KeywordTable::AddKeyword(const TemplateURLData& data) {
   DCHECK(data.id);
   std::string query("INSERT INTO keywords (" + GetKeywordColumns() + ") "
-                    "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
+                    "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,"
+                    "        ?)");
   sql::Statement s(db_->GetUniqueStatement(query.c_str()));
   BindURLToStatement(data, &s, 0, 1);
 
@@ -281,8 +291,9 @@
       "created_by_policy=?, instant_url=?, last_modified=?, sync_guid=?, "
       "alternate_urls=?, search_terms_replacement_key=?, image_url=?,"
       "search_url_post_params=?, suggest_url_post_params=?, "
-      "instant_url_post_params=?, image_url_post_params=? WHERE id=?"));
-  BindURLToStatement(data, &s, 23, 0);  // "23" binds id() as the last item.
+      "instant_url_post_params=?, image_url_post_params=?, new_tab_url=? "
+      "WHERE id=?"));
+  BindURLToStatement(data, &s, 24, 0);  // "24" binds id() as the last item.
 
   return s.Run();
 }
@@ -473,15 +484,24 @@
   // Fill the |image_url| and other four post params columns with empty strings;
   return transaction.Begin() &&
       db_->Execute("ALTER TABLE keywords ADD COLUMN image_url "
-                    "VARCHAR DEFAULT ''") &&
+                   "VARCHAR DEFAULT ''") &&
       db_->Execute("ALTER TABLE keywords ADD COLUMN search_url_post_params "
-                    "VARCHAR DEFAULT ''") &&
+                   "VARCHAR DEFAULT ''") &&
       db_->Execute("ALTER TABLE keywords ADD COLUMN suggest_url_post_params "
-                    "VARCHAR DEFAULT ''") &&
+                   "VARCHAR DEFAULT ''") &&
       db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url_post_params "
-                    "VARCHAR DEFAULT ''") &&
+                   "VARCHAR DEFAULT ''") &&
       db_->Execute("ALTER TABLE keywords ADD COLUMN image_url_post_params "
-                    "VARCHAR DEFAULT ''") &&
+                   "VARCHAR DEFAULT ''") &&
+      transaction.Commit();
+}
+
+bool KeywordTable::MigrateToVersion53AddNewTabURLColumn() {
+  sql::Transaction transaction(db_);
+
+  return transaction.Begin() &&
+      db_->Execute("ALTER TABLE keywords ADD COLUMN new_tab_url "
+                   "VARCHAR DEFAULT ''") &&
       transaction.Commit();
 }
 
@@ -502,6 +522,7 @@
   data->suggestions_url = s.ColumnString(11);
   data->instant_url = s.ColumnString(14);
   data->image_url = s.ColumnString(19);
+  data->new_tab_url = s.ColumnString(24);
   data->search_url_post_params = s.ColumnString(20);
   data->suggestions_url_post_params = s.ColumnString(21);
   data->instant_url_post_params = s.ColumnString(22);
diff --git a/chrome/browser/webdata/keyword_table.h b/chrome/browser/webdata/keyword_table.h
index 7634846..477721b 100644
--- a/chrome/browser/webdata/keyword_table.h
+++ b/chrome/browser/webdata/keyword_table.h
@@ -67,7 +67,8 @@
 //                          was added in version 52.
 //   image_url_post_params  See TemplateURLData::image_url_post_params. This
 //                          was added in version 52.
-//
+//   new_tab_url            See TemplateURLData::new_tab_url. This was added in
+//                          version 53.
 //
 // This class also manages some fields in the |meta| table:
 //
@@ -137,6 +138,7 @@
   bool MigrateToVersion48RemoveKeywordsBackup();
   bool MigrateToVersion49AddSearchTermsReplacementKeyColumn();
   bool MigrateToVersion52AddImageSearchAndPOSTSupport();
+  bool MigrateToVersion53AddNewTabURLColumn();
 
  private:
   FRIEND_TEST_ALL_PREFIXES(KeywordTableTest, GetTableContents);
diff --git a/chrome/browser/webdata/keyword_table_unittest.cc b/chrome/browser/webdata/keyword_table_unittest.cc
index 760166e..d9b61a5 100644
--- a/chrome/browser/webdata/keyword_table_unittest.cc
+++ b/chrome/browser/webdata/keyword_table_unittest.cc
@@ -137,6 +137,7 @@
   keyword.SetURL("http://url/");
   keyword.suggestions_url = "url2";
   keyword.image_url = "http://image-search-url/";
+  keyword.new_tab_url = "http://new-tab-url/";
   keyword.favicon_url = GURL("http://favicon.url/");
   keyword.show_in_default_list = true;
   keyword.safe_for_autoreplace = true;
@@ -152,6 +153,7 @@
   keyword.SetKeyword(ASCIIToUTF16("url"));
   keyword.instant_url = "http://instant2/";
   keyword.image_url.clear();
+  keyword.new_tab_url.clear();
   keyword.originating_url = GURL("http://originating.url/");
   keyword.input_encodings.push_back("Shift_JIS");
   keyword.id = 2;
@@ -163,9 +165,9 @@
 
   const char kTestContents[] = "1short_namekeywordhttp://favicon.url/"
       "http://url/1001url20001234-5678-90AB-CDEF[\"a_url1\",\"a_url2\"]espv"
-      "http://image-search-url/2short_nameurlhttp://favicon.url/http://url/1"
-      "http://originating.url/00Shift_JIS1url250http://instant2/0"
-      "FEDC-BA09-8765-4321[]";
+      "http://image-search-url/http://new-tab-url/2short_nameurl"
+      "http://favicon.url/http://url/1http://originating.url/00Shift_JIS1url250"
+      "http://instant2/0FEDC-BA09-8765-4321[]";
 
   std::string contents;
   EXPECT_TRUE(table_->GetTableContents("keywords",
@@ -192,6 +194,7 @@
   keyword.image_url = "http://image-search-url/";
   keyword.search_url_post_params = "ie=utf-8,oe=utf-8";
   keyword.image_url_post_params = "name=1,value=2";
+  keyword.new_tab_url = "http://new-tab-url";
   EXPECT_TRUE(table_->AddKeyword(keyword));
 
   keyword.SetKeyword(ASCIIToUTF16("url"));
@@ -206,13 +209,15 @@
   keyword.image_url.clear();
   keyword.search_url_post_params.clear();
   keyword.image_url_post_params.clear();
+  keyword.new_tab_url.clear();
   EXPECT_TRUE(table_->AddKeyword(keyword));
 
-  const char kTestContents[] = "1short_nameurlhttp://favicon.url/http://url/1"
-      "http://originating.url/00Shift_JIS1url250http://instant2/0"
-      "FEDC-BA09-8765-4321[]2short_namekeywordhttp://favicon.url/"
-      "http://url/1001url20001234-5678-90AB-CDEF[\"a_url1\",\"a_url2\"]espv"
-      "http://image-search-url/ie=utf-8,oe=utf-8name=1,value=2";
+  const char kTestContents[] = "1short_nameurlhttp://favicon.url/"
+      "http://url/1http://originating.url/00Shift_JIS1url250http://instant2/"
+      "0FEDC-BA09-8765-4321[]2short_namekeywordhttp://favicon.url/http://url/"
+      "1001url20001234-5678-90AB-CDEF[\"a_url1\",\"a_url2\"]espv"
+      "http://image-search-url/ie=utf-8,oe=utf-8name=1,value=2"
+      "http://new-tab-url";
 
   std::string contents;
   EXPECT_TRUE(table_->GetTableContents("keywords",
diff --git a/chrome/browser/webdata/web_data_service.h b/chrome/browser/webdata/web_data_service.h
index 2904e2e..820f4b4 100644
--- a/chrome/browser/webdata/web_data_service.h
+++ b/chrome/browser/webdata/web_data_service.h
@@ -148,53 +148,6 @@
   // specified web app.
   Handle GetWebAppImages(const GURL& app_url, WebDataServiceConsumer* consumer);
 
-#if defined(ENABLE_WEB_INTENTS)
-  //////////////////////////////////////////////////////////////////////////////
-  //
-  // Web Intents
-  //
-  //////////////////////////////////////////////////////////////////////////////
-
-  // Adds a web intent service registration.
-  void AddWebIntentService(const webkit_glue::WebIntentServiceData& service);
-
-  // Removes a web intent service registration.
-  void RemoveWebIntentService(const webkit_glue::WebIntentServiceData& service);
-
-  // Get all web intent services registered for the specified |action|.
-  // |consumer| must not be NULL.
-  Handle GetWebIntentServicesForAction(const string16& action,
-                                       WebDataServiceConsumer* consumer);
-
-  // Get all web intent services registered using the specified |service_url|.
-  // |consumer| must not be NULL.
-  Handle GetWebIntentServicesForURL(const string16& service_url,
-                                    WebDataServiceConsumer* consumer);
-
-  // Get all web intent services registered. |consumer| must not be NULL.
-  Handle GetAllWebIntentServices(WebDataServiceConsumer* consumer);
-
-  // Adds a default web intent service entry.
-  void AddDefaultWebIntentService(const DefaultWebIntentService& service);
-
-  // Removes a default web intent service entry. Removes entries matching
-  // the |action|, |type|, and |url_pattern| of |service|.
-  void RemoveDefaultWebIntentService(const DefaultWebIntentService& service);
-
-  // Removes all default web intent service entries associated with
-  // |service_url|
-  void RemoveWebIntentServiceDefaults(const GURL& service_url);
-
-    // Get a list of all web intent service defaults for the given |action|.
-  // |consumer| must not be null.
-  Handle GetDefaultWebIntentServicesForAction(const string16& action,
-                                              WebDataServiceConsumer* consumer);
-
-  // Get a list of all registered web intent service defaults.
-  // |consumer| must not be null.
-  Handle GetAllDefaultWebIntentServices(WebDataServiceConsumer* consumer);
-#endif
-
 #if defined(OS_WIN)
   //////////////////////////////////////////////////////////////////////////////
   //
diff --git a/chrome/browser_tests.isolate b/chrome/browser_tests.isolate
index 79ffdc0..a43a861 100644
--- a/chrome/browser_tests.isolate
+++ b/chrome/browser_tests.isolate
@@ -14,7 +14,6 @@
         ],
         'isolate_dependency_tracked': [
           '../testing/xvfb.py',
-          '<(PRODUCT_DIR)/chrome.pak',
           '<(PRODUCT_DIR)/chrome<(EXECUTABLE_SUFFIX)',
           '<(PRODUCT_DIR)/libclearkeycdm.so',
           '<(PRODUCT_DIR)/libclearkeycdmadapter.so',
@@ -44,8 +43,6 @@
           '../media/test/data/sfx.ogg',
           '../ppapi/tests/test_case.html',
           '../ppapi/tests/test_page.css',
-          '../tools/swarm_client/run_isolated.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '../testing/test_env.py',
           '<(PRODUCT_DIR)/browser_tests<(EXECUTABLE_SUFFIX)',
           '<(PRODUCT_DIR)/ppapi_nacl_tests_glibc.nmf',
@@ -73,6 +70,7 @@
           '../third_party/safe_browsing/',
           '../third_party/simplejson/',
           '../third_party/tlslite/',
+          '../tools/swarm_client/',
           '<(PRODUCT_DIR)/nacl_test_data/',
           '<(PRODUCT_DIR)/pnacl/',
           '<(PRODUCT_DIR)/pseudo_locales/',
diff --git a/chrome/chrome.isolate b/chrome/chrome.isolate
index 86233c4..263a82c 100644
--- a/chrome/chrome.isolate
+++ b/chrome/chrome.isolate
@@ -6,7 +6,6 @@
     ['OS=="linux"', {
       'variables': {
         'isolate_dependency_tracked': [
-          '<(PRODUCT_DIR)/chrome.pak',
           '<(PRODUCT_DIR)/libclearkeycdm.so',
           '<(PRODUCT_DIR)/libclearkeycdmadapter.so',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
diff --git a/chrome/chrome_android.gypi b/chrome/chrome_android.gypi
index 8237fac..9b8cbb7 100644
--- a/chrome/chrome_android.gypi
+++ b/chrome/chrome_android.gypi
@@ -19,6 +19,7 @@
         'chrome_android_auxiliary',
         'chromium_testshell_jni_headers',
         'chrome.gyp:browser_ui',
+        '../content/content.gyp:content_app_browser',
       ],
       'sources': [
         # This file must always be included in the shared_library step to ensure
@@ -105,6 +106,7 @@
         'chrome.gyp:renderer',
         'chrome.gyp:utility',
         '../content/content.gyp:content',
+        '../content/content.gyp:content_app_browser',
       ],
       'include_dirs': [
         '..',
diff --git a/chrome/chrome_android_paks.gypi b/chrome/chrome_android_paks.gypi
index 6a95ee5..7937f2f 100644
--- a/chrome/chrome_android_paks.gypi
+++ b/chrome/chrome_android_paks.gypi
@@ -5,7 +5,6 @@
   'variables': {
     'chrome_android_pak_output_folder': '<@(PRODUCT_DIR)/../assets/<(package_name)',
     'chrome_android_pak_input_resources': [
-      '<(PRODUCT_DIR)/chrome.pak',
       '<(PRODUCT_DIR)/resources.pak',
       '<(PRODUCT_DIR)/chrome_100_percent.pak',
       '<(PRODUCT_DIR)/locales/am.pak',
@@ -54,7 +53,6 @@
       '<(PRODUCT_DIR)/locales/zh-TW.pak',
     ],
     'chrome_android_pak_output_resources': [
-      '<(chrome_android_pak_output_folder)/chrome.pak',
       '<(chrome_android_pak_output_folder)/resources.pak',
       '<(chrome_android_pak_output_folder)/chrome_100_percent.pak',
       '<(chrome_android_pak_output_folder)/am.pak',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 4a1deca..45ed2d1 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -51,8 +51,8 @@
         '../third_party/libjingle/libjingle.gyp:libjingle',
         '../third_party/libxml/libxml.gyp:libxml',
         '../third_party/widevine/cdm/widevine_cdm.gyp:widevine_cdm_version_h',
+        '../third_party/zlib/google/zip.gyp:zip',
         '../third_party/zlib/zlib.gyp:minizip',
-        '../third_party/zlib/zlib.gyp:zip',
         '../third_party/zlib/zlib.gyp:zlib',
         '../ui/base/strings/ui_strings.gyp:ui_strings',
         '../ui/message_center/message_center.gyp:message_center',
@@ -85,6 +85,8 @@
         'browser/accessibility/accessibility_events.h',
         'browser/accessibility/invert_bubble_prefs.cc',
         'browser/accessibility/invert_bubble_prefs.h',
+        'browser/android/bookmarks_bridge.cc',
+        'browser/android/bookmarks_bridge.h',
         'browser/android/chrome_jni_registrar.cc',
         'browser/android/chrome_jni_registrar.h',
         'browser/android/chrome_startup_flags.cc',
@@ -122,6 +124,10 @@
         'browser/android/resource_mapper.cc',
         'browser/android/resource_mapper.h',
         'browser/android/resource_id.h',
+        'browser/android/signin/google_auto_login_helper.cc',
+        'browser/android/signin/google_auto_login_helper.h',
+        'browser/android/shortcut_helper.cc',
+        'browser/android/shortcut_helper.h',
         'browser/android/signin/signin_manager_android.cc',
         'browser/android/signin/signin_manager_android.h',
         'browser/android/tab_android.cc',
@@ -491,6 +497,8 @@
         'browser/download/download_danger_prompt.h',
         'browser/download/download_extensions.cc',
         'browser/download/download_extensions.h',
+        'browser/download/download_field_trial.cc',
+        'browser/download/download_field_trial.h',
         'browser/download/download_file_picker.cc',
         'browser/download/download_file_picker.h',
         'browser/download/download_history.cc',
@@ -798,8 +806,6 @@
         'browser/history/top_sites_database.h',
         'browser/history/top_sites_impl.cc',
         'browser/history/top_sites_impl.h',
-        'browser/history/top_sites_likely_impl.cc',
-        'browser/history/top_sites_likely_impl.h',
         'browser/history/typed_url_syncable_service.cc',
         'browser/history/typed_url_syncable_service.h',
         'browser/history/url_database.cc',
@@ -909,6 +915,8 @@
         'browser/lifetime/application_lifetime_mac.mm',
         'browser/lifetime/application_lifetime_stub.cc',
         'browser/lifetime/application_lifetime_win.cc',
+        'browser/lifetime/browser_close_manager.cc',
+        'browser/lifetime/browser_close_manager.h',
         'browser/local_discovery/privet_confirm_api_flow.cc',
         'browser/local_discovery/privet_confirm_api_flow.h',
         'browser/local_discovery/privet_constants.h',
@@ -970,6 +978,8 @@
         'browser/media/chrome_midi_permission_context.h',
         'browser/media/chrome_midi_permission_context_factory.cc',
         'browser/media/chrome_midi_permission_context_factory.h',
+        'browser/media/desktop_streams_registry.cc',
+        'browser/media/desktop_streams_registry.h',
         'browser/media/desktop_media_picker.h',
         'browser/media/desktop_media_picker_model.cc',
         'browser/media/desktop_media_picker_model.h',
@@ -2167,6 +2177,8 @@
         'browser/sync/profile_sync_service_observer.h',
         'browser/sync/retry_verifier.cc',
         'browser/sync/retry_verifier.h',
+        'browser/sync/sessions2/tab_node_pool2.cc',
+        'browser/sync/sessions2/tab_node_pool2.h',
         'browser/sync/sync_startup_tracker.cc',
         'browser/sync/sync_startup_tracker.h',
         'browser/sync/sync_global_error.cc',
@@ -3262,6 +3274,12 @@
               'browser/local_discovery/privet_device_lister.cc',
               'browser/local_discovery/privet_device_lister_impl.h',
               'browser/local_discovery/privet_device_lister_impl.cc',
+              'browser/local_discovery/privet_http_asynchronous_factory.cc',
+              'browser/local_discovery/privet_http_asynchronous_factory.h',
+              'browser/local_discovery/privet_notifications.cc',
+              'browser/local_discovery/privet_notifications.h',
+              'browser/local_discovery/privet_notifications_factory.cc',
+              'browser/local_discovery/privet_notifications_factory.h',
               'browser/local_discovery/service_discovery_host_client.cc',
               'browser/local_discovery/service_discovery_host_client.h',
             ]
@@ -3412,6 +3430,7 @@
             'android/java/src/org/chromium/chrome/browser/autofill/AutofillDialogResult.java',
             'android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupGlue.java',
             'android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java',
+            'android/java/src/org/chromium/chrome/browser/BookmarksBridge.java',
             'android/java/src/org/chromium/chrome/browser/CertificateViewer.java',
             'android/java/src/org/chromium/chrome/browser/ChromeBrowserProvider.java',
             'android/java/src/org/chromium/chrome/browser/ChromeHttpAuthHandler.java',
@@ -3428,6 +3447,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/ShortcutHelper.java',
             'android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java',
             'android/java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java',
             'android/java/src/org/chromium/chrome/browser/signin/AndroidProfileOAuth2TokenServiceHelper.java',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 982b46c..71f3030 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -123,11 +123,11 @@
         'browser/chromeos/accessibility/magnification_manager.h',
         'browser/chromeos/app_mode/app_session_lifetime.cc',
         'browser/chromeos/app_mode/app_session_lifetime.h',
+        'browser/chromeos/app_mode/app_launch_utils.cc',
+        'browser/chromeos/app_mode/app_launch_utils.h',
         'browser/chromeos/app_mode/kiosk_app_data.cc',
         'browser/chromeos/app_mode/kiosk_app_data.h',
         'browser/chromeos/app_mode/kiosk_app_data_delegate.h',
-        'browser/chromeos/app_mode/kiosk_app_launcher.cc',
-        'browser/chromeos/app_mode/kiosk_app_launcher.h',
         'browser/chromeos/app_mode/kiosk_app_launch_error.cc',
         'browser/chromeos/app_mode/kiosk_app_launch_error.h',
         'browser/chromeos/app_mode/kiosk_app_manager.cc',
@@ -135,12 +135,16 @@
         'browser/chromeos/app_mode/kiosk_app_manager_observer.h',
         'browser/chromeos/app_mode/kiosk_app_update_service.cc',
         'browser/chromeos/app_mode/kiosk_app_update_service.h',
+        'browser/chromeos/app_mode/kiosk_profile_loader.cc',
+        'browser/chromeos/app_mode/kiosk_profile_loader.h',
         'browser/chromeos/app_mode/startup_app_launcher.cc',
         'browser/chromeos/app_mode/startup_app_launcher.h',
         'browser/chromeos/attestation/attestation_ca_client.cc',
         'browser/chromeos/attestation/attestation_ca_client.h',
         'browser/chromeos/attestation/attestation_policy_observer.cc',
         'browser/chromeos/attestation/attestation_policy_observer.h',
+        'browser/chromeos/attestation/platform_verification_flow.cc',
+        'browser/chromeos/attestation/platform_verification_flow.h',
         'browser/chromeos/audio/audio_devices_pref_handler_impl.cc',
         'browser/chromeos/audio/audio_devices_pref_handler_impl.h',
         'browser/chromeos/background/ash_user_wallpaper_delegate.cc',
@@ -232,8 +236,6 @@
         'browser/chromeos/drive/drive_url_request_job.h',
         'browser/chromeos/drive/file_cache.cc',
         'browser/chromeos/drive/file_cache.h',
-        'browser/chromeos/drive/file_cache_metadata.cc',
-        'browser/chromeos/drive/file_cache_metadata.h',
         'browser/chromeos/drive/file_change.cc',
         'browser/chromeos/drive/file_change.h',
         'browser/chromeos/drive/file_errors.cc',
@@ -275,8 +277,6 @@
         'browser/chromeos/drive/file_system_util.h',
         'browser/chromeos/drive/file_task_executor.cc',
         'browser/chromeos/drive/file_task_executor.h',
-        'browser/chromeos/drive/file_write_helper.cc',
-        'browser/chromeos/drive/file_write_helper.h',
         'browser/chromeos/drive/file_write_watcher.cc',
         'browser/chromeos/drive/file_write_watcher.h',
         'browser/chromeos/drive/fileapi_worker.cc',
@@ -307,6 +307,8 @@
         'browser/chromeos/drive/webkit_file_stream_reader_impl.h',
         'browser/chromeos/drive/webkit_file_stream_writer_impl.cc',
         'browser/chromeos/drive/webkit_file_stream_writer_impl.h',
+        'browser/chromeos/drive/write_on_cache_file.cc',
+        'browser/chromeos/drive/write_on_cache_file.h',
         'browser/chromeos/enrollment_dialog_view.cc',
         'browser/chromeos/enrollment_dialog_view.h',
         'browser/chromeos/enterprise_extension_observer.cc',
@@ -319,6 +321,9 @@
         'browser/chromeos/extensions/external_cache.h',
         'browser/chromeos/extensions/external_pref_cache_loader.cc',
         'browser/chromeos/extensions/external_pref_cache_loader.h',
+        'browser/chromeos/extensions/file_manager/action_choice_dialog.cc',
+        'browser/chromeos/extensions/file_manager/action_choice_dialog.h',
+        'browser/chromeos/extensions/file_manager/app_id.h',
         'browser/chromeos/extensions/file_manager/desktop_notifications.cc',
         'browser/chromeos/extensions/file_manager/desktop_notifications.h',
         'browser/chromeos/extensions/file_manager/event_router.cc',
@@ -335,6 +340,8 @@
         'browser/chromeos/extensions/file_manager/fileapi_util.h',
         'browser/chromeos/extensions/file_manager/mounted_disk_monitor.cc',
         'browser/chromeos/extensions/file_manager/mounted_disk_monitor.h',
+        'browser/chromeos/extensions/file_manager/url_util.cc',
+        'browser/chromeos/extensions/file_manager/url_util.h',
         'browser/chromeos/extensions/file_manager/zip_file_creator.cc',
         'browser/chromeos/extensions/file_manager/zip_file_creator.h',
         'browser/chromeos/extensions/info_private_api.cc',
@@ -414,6 +421,8 @@
         'browser/chromeos/language_preferences.h',
         'browser/chromeos/locale_change_guard.cc',
         'browser/chromeos/locale_change_guard.h',
+        'browser/chromeos/login/app_launch_controller.cc',
+        'browser/chromeos/login/app_launch_controller.h',
         'browser/chromeos/login/auth_attempt_state.cc',
         'browser/chromeos/login/auth_attempt_state.h',
         'browser/chromeos/login/auth_attempt_state_resolver.cc',
@@ -572,6 +581,8 @@
         'browser/chromeos/login/user_image_manager.cc',
         'browser/chromeos/login/user_image_manager_impl.cc',
         'browser/chromeos/login/user_image_manager_impl.h',
+        'browser/chromeos/login/user_image_sync_observer.cc',
+        'browser/chromeos/login/user_image_sync_observer.h',
         'browser/chromeos/login/user_flow.cc',
         'browser/chromeos/login/user_flow.h',
         'browser/chromeos/login/user_manager.cc',
@@ -590,8 +601,6 @@
         'browser/chromeos/login/webui_screen_locker.h',
         'browser/chromeos/login/wizard_controller.cc',
         'browser/chromeos/login/wizard_controller.h',
-        'browser/chromeos/media/media_player.cc',
-        'browser/chromeos/media/media_player.h',
         'browser/chromeos/memory/oom_priority_manager.cc',
         'browser/chromeos/memory/oom_priority_manager.h',
         'browser/chromeos/mobile/mobile_activator.cc',
@@ -614,8 +623,6 @@
         'browser/chromeos/offline/offline_load_page.h',
         'browser/chromeos/options/network_config_view.cc',
         'browser/chromeos/options/network_config_view.h',
-        'browser/chromeos/options/network_connect.cc',
-        'browser/chromeos/options/network_connect.h',
         'browser/chromeos/options/passphrase_textfield.cc',
         'browser/chromeos/options/passphrase_textfield.h',
         'browser/chromeos/options/vpn_config_view.cc',
@@ -662,8 +669,6 @@
         'browser/chromeos/policy/network_configuration_updater.h',
         'browser/chromeos/policy/network_configuration_updater_impl.cc',
         'browser/chromeos/policy/network_configuration_updater_impl.h',
-        'browser/chromeos/policy/network_configuration_updater_impl_cros.cc',
-        'browser/chromeos/policy/network_configuration_updater_impl_cros.h',
         'browser/chromeos/policy/policy_cert_verifier.cc',
         'browser/chromeos/policy/policy_cert_verifier.h',
         'browser/chromeos/policy/policy_oauth2_token_fetcher.cc',
@@ -756,8 +761,6 @@
         'browser/chromeos/settings/system_settings_provider.h',
         'browser/chromeos/sim_dialog_delegate.cc',
         'browser/chromeos/sim_dialog_delegate.h',
-        'browser/chromeos/sms_observer.cc',
-        'browser/chromeos/sms_observer.h',
         'browser/chromeos/status/data_promo_notification.cc',
         'browser/chromeos/status/data_promo_notification.h',
         'browser/chromeos/status/network_menu.cc',
@@ -805,8 +808,6 @@
         'browser/chromeos/system_logs/system_logs_fetcher_base.h',
         'browser/chromeos/system_logs/touch_log_source.cc',
         'browser/chromeos/system_logs/touch_log_source.h',
-        'browser/chromeos/ui/app_launch_view.cc',
-        'browser/chromeos/ui/app_launch_view.h',
         'browser/chromeos/ui/echo_dialog_listener.h',
         'browser/chromeos/ui/echo_dialog_view.cc',
         'browser/chromeos/ui/echo_dialog_view.h',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index e61183b..c9a4060 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -197,6 +197,8 @@
         'browser/extensions/api/declarative_webrequest/webrequest_constants.h',
         'browser/extensions/api/declarative_webrequest/webrequest_rules_registry.cc',
         'browser/extensions/api/declarative_webrequest/webrequest_rules_registry.h',
+        'browser/extensions/api/desktop_capture/desktop_capture_api.cc',
+        'browser/extensions/api/desktop_capture/desktop_capture_api.h',
         'browser/extensions/api/developer_private/developer_private_api.cc',
         'browser/extensions/api/developer_private/developer_private_api.h',
         'browser/extensions/api/developer_private/developer_private_api_factory.cc',
@@ -409,8 +411,10 @@
         'browser/extensions/api/serial/serial_port_enumerator.h',
         'browser/extensions/api/serial/serial_port_enumerator_posix.cc',
         'browser/extensions/api/serial/serial_port_enumerator_win.cc',
-        'browser/extensions/api/session_restore/session_restore_api.cc',
-        'browser/extensions/api/session_restore/session_restore_api.h',
+        'browser/extensions/api/sessions/sessions_api.cc',
+        'browser/extensions/api/sessions/sessions_api.h',
+        'browser/extensions/api/sessions/session_id.cc',
+        'browser/extensions/api/sessions/session_id.h',
         'browser/extensions/api/signedin_devices/id_mapping_helper.cc',
         'browser/extensions/api/signedin_devices/id_mapping_helper.h',
         'browser/extensions/api/signedin_devices/signedin_devices_api.cc',
@@ -423,6 +427,10 @@
         'browser/extensions/api/socket/tcp_socket.h',
         'browser/extensions/api/socket/udp_socket.cc',
         'browser/extensions/api/socket/udp_socket.h',
+        'browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.h',
+        'browser/extensions/api/sockets_udp/udp_socket_event_dispatcher.cc',
+        'browser/extensions/api/sockets_udp/sockets_udp_api.cc',
+        'browser/extensions/api/sockets_udp/sockets_udp_api.h',
         'browser/extensions/api/spellcheck/spellcheck_api.cc',
         'browser/extensions/api/spellcheck/spellcheck_api.h',
         'browser/extensions/api/storage/leveldb_settings_storage_factory.cc',
@@ -506,6 +514,8 @@
         'browser/extensions/api/tabs/tabs_constants.h',
         'browser/extensions/api/tabs/windows_event_router.cc',
         'browser/extensions/api/tabs/windows_event_router.h',
+        'browser/extensions/api/tabs/windows_util.cc',
+        'browser/extensions/api/tabs/windows_util.h',
         'browser/extensions/api/test/test_api.cc',
         'browser/extensions/api/test/test_api.h',
         'browser/extensions/api/top_sites/top_sites_api.cc',
@@ -846,6 +856,7 @@
             # less intertwined in the main codebase.
             ['exclude', '^browser/extensions/api/'],
             ['exclude', '^browser/extensions/.*_api\.cc$'],
+            ['exclude', '^browser/extensions/browser_event_router.cc'],
             ['include', '^browser/extensions/api/activity_log_private/activity_log_private_api.cc'],
             ['include', '^browser/extensions/api/activity_log_private/activity_log_private_api.h'],
             ['include', '^browser/extensions/api/alarms/alarm_manager.cc'],
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index a869a13..4ce2d2b 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -163,6 +163,8 @@
         'browser/ui/app_list/search/tokenized_string_char_iterator.h',
         'browser/ui/app_list/search/tokenized_string_match.cc',
         'browser/ui/app_list/search/tokenized_string_match.h',
+        'browser/ui/app_list/search/webstore_cache.cc',
+        'browser/ui/app_list/search/webstore_cache.h',
         'browser/ui/app_list/search/webstore_installer.cc',
         'browser/ui/app_list/search/webstore_installer.h',
         'browser/ui/app_list/search/webstore_provider.cc',
@@ -182,6 +184,10 @@
         'browser/ui/app_modal_dialogs/javascript_dialog_manager.cc',
         'browser/ui/app_modal_dialogs/javascript_dialog_manager.h',
         'browser/ui/app_modal_dialogs/native_app_modal_dialog.h',
+        'browser/ui/apps/app_metro_infobar_delegate_win.cc',
+        'browser/ui/apps/app_metro_infobar_delegate_win.h',
+        'browser/ui/apps/apps_metro_handler_win.cc',
+        'browser/ui/apps/apps_metro_handler_win.h',
         'browser/ui/apps/chrome_shell_window_delegate.cc',
         'browser/ui/apps/chrome_shell_window_delegate.h',
         'browser/ui/ash/ash_keyboard_controller_proxy.cc',
@@ -232,10 +238,6 @@
         'browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h',
         'browser/ui/ash/launcher/chrome_launcher_controller.cc',
         'browser/ui/ash/launcher/chrome_launcher_controller.h',
-        'browser/ui/ash/launcher/chrome_launcher_controller_per_app.cc',
-        'browser/ui/ash/launcher/chrome_launcher_controller_per_app.h',
-        'browser/ui/ash/launcher/chrome_launcher_controller_per_browser.cc',
-        'browser/ui/ash/launcher/chrome_launcher_controller_per_browser.h',
         'browser/ui/ash/launcher/launcher_app_tab_helper.cc',
         'browser/ui/ash/launcher/launcher_app_tab_helper.h',
         'browser/ui/ash/launcher/launcher_context_menu.cc',
@@ -692,6 +694,8 @@
         'browser/ui/cocoa/fullscreen_exit_bubble_controller.mm',
         'browser/ui/cocoa/fullscreen_exit_bubble_view.h',
         'browser/ui/cocoa/fullscreen_exit_bubble_view.mm',
+        'browser/ui/cocoa/fullscreen_mode_controller.h',
+        'browser/ui/cocoa/fullscreen_mode_controller.mm',
         'browser/ui/cocoa/fullscreen_window.h',
         'browser/ui/cocoa/fullscreen_window.mm',
         'browser/ui/cocoa/global_error_bubble_controller.h',
@@ -776,6 +780,8 @@
         'browser/ui/cocoa/location_bar/location_bar_view_mac.mm',
         'browser/ui/cocoa/location_bar/location_icon_decoration.h',
         'browser/ui/cocoa/location_bar/location_icon_decoration.mm',
+        'browser/ui/cocoa/location_bar/mic_search_decoration.h',
+        'browser/ui/cocoa/location_bar/mic_search_decoration.mm',
         'browser/ui/cocoa/location_bar/page_action_decoration.h',
         'browser/ui/cocoa/location_bar/page_action_decoration.mm',
         'browser/ui/cocoa/location_bar/selected_keyword_decoration.h',
@@ -978,12 +984,8 @@
         'browser/ui/crypto_module_password_dialog.h',
         'browser/ui/crypto_module_password_dialog_nss.cc',
         'browser/ui/crypto_module_password_dialog_openssl.cc',
-        'browser/ui/extensions/app_metro_infobar_delegate_win.cc',
-        'browser/ui/extensions/app_metro_infobar_delegate_win.h',
         'browser/ui/extensions/application_launch.cc',
         'browser/ui/extensions/application_launch.h',
-        'browser/ui/extensions/apps_metro_handler_win.cc',
-        'browser/ui/extensions/apps_metro_handler_win.h',
         'browser/ui/extensions/extension_install_ui_default.cc',
         'browser/ui/extensions/extension_install_ui_default.h',
         'browser/ui/extensions/extension_enable_flow.cc',
@@ -1881,6 +1883,7 @@
         'browser/ui/views/select_file_dialog_extension_factory.h',
         'browser/ui/views/simple_message_box_views.cc',
         'browser/ui/views/simple_message_box_win.cc',
+        'browser/ui/views/simple_message_box_win.h',
         'browser/ui/views/speech_recognition_bubble_views.cc',
         'browser/ui/views/ssl_client_certificate_selector.cc',
         'browser/ui/views/ssl_client_certificate_selector.h',
@@ -1957,6 +1960,7 @@
         'browser/ui/views/website_settings/website_settings_popup_view.h',
         'browser/ui/views/wrench_menu.cc',
         'browser/ui/views/wrench_menu.h',
+        'browser/ui/views/wrench_menu_observer.h',
         'browser/ui/views/wrench_toolbar_button.cc',
         'browser/ui/views/wrench_toolbar_button.h',
         'browser/ui/web_applications/web_app_ui.cc',
@@ -1985,10 +1989,6 @@
         'browser/ui/webui/chrome_web_contents_handler.h',
         'browser/ui/webui/chrome_web_ui_controller_factory.cc',
         'browser/ui/webui/chrome_web_ui_controller_factory.h',
-        'browser/ui/webui/chromeos/about_network.cc',
-        'browser/ui/webui/chromeos/about_network.h',
-        'browser/ui/webui/chromeos/app_launch_ui.cc',
-        'browser/ui/webui/chromeos/app_launch_ui.h',
         'browser/ui/webui/chromeos/bluetooth_pairing_ui.cc',
         'browser/ui/webui/chromeos/bluetooth_pairing_ui.h',
         'browser/ui/webui/chromeos/choose_mobile_network_ui.cc',
@@ -2005,6 +2005,8 @@
         'browser/ui/webui/chromeos/imageburner/imageburner_ui.h',
         'browser/ui/webui/chromeos/keyboard_overlay_ui.cc',
         'browser/ui/webui/chromeos/keyboard_overlay_ui.h',
+        'browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc',
+        'browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h',
         'browser/ui/webui/chromeos/login/base_screen_handler.cc',
         'browser/ui/webui/chromeos/login/base_screen_handler.h',
         'browser/ui/webui/chromeos/login/base_screen_handler_utils.h',
@@ -2052,6 +2054,8 @@
         'browser/ui/webui/chromeos/mobile_setup_dialog.h',
         'browser/ui/webui/chromeos/mobile_setup_ui.cc',
         'browser/ui/webui/chromeos/mobile_setup_ui.h',
+        'browser/ui/webui/chromeos/network_ui.cc',
+        'browser/ui/webui/chromeos/network_ui.h',
         'browser/ui/webui/chromeos/proxy_settings_ui.cc',
         'browser/ui/webui/chromeos/proxy_settings_ui.h',
         'browser/ui/webui/chromeos/sim_unlock_ui.cc',
@@ -2062,6 +2066,8 @@
         'browser/ui/webui/chromeos/system_info_ui.h',
         'browser/ui/webui/chromeos/ui_account_tweaks.cc',
         'browser/ui/webui/chromeos/ui_account_tweaks.h',
+        'browser/ui/webui/components_ui.cc',
+        'browser/ui/webui/components_ui.h',
         'browser/ui/webui/constrained_web_dialog_ui.cc',
         'browser/ui/webui/constrained_web_dialog_ui.h',
         'browser/ui/webui/constrained_web_dialog_delegate_base.cc',
@@ -2096,8 +2102,6 @@
         'browser/ui/webui/extensions/pack_extension_handler.h',
         'browser/ui/webui/favicon_source.cc',
         'browser/ui/webui/favicon_source.h',
-        'browser/ui/webui/feedback_ui.cc',
-        'browser/ui/webui/feedback_ui.h',
         'browser/ui/webui/fileicon_source.cc',
         'browser/ui/webui/fileicon_source.h',
         'browser/ui/webui/flags_ui.cc',
@@ -2132,10 +2136,6 @@
         'browser/ui/webui/inspect_ui.h',
         'browser/ui/webui/instant_ui.cc',
         'browser/ui/webui/instant_ui.h',
-        'browser/ui/webui/local_discovery/local_discovery_ui.cc',
-        'browser/ui/webui/local_discovery/local_discovery_ui.h',
-        'browser/ui/webui/local_discovery/local_discovery_ui_handler.cc',
-        'browser/ui/webui/local_discovery/local_discovery_ui_handler.h',
         'browser/ui/webui/media/webrtc_logs_ui.cc',
         'browser/ui/webui/media/webrtc_logs_ui.h',
         'browser/ui/webui/memory_internals/memory_internals_handler.cc',
@@ -2328,8 +2328,6 @@
         'browser/ui/webui/quota_internals/quota_internals_types.h',
         'browser/ui/webui/quota_internals/quota_internals_ui.cc',
         'browser/ui/webui/quota_internals/quota_internals_ui.h',
-        'browser/ui/webui/screenshot_source.cc',
-        'browser/ui/webui/screenshot_source.h',
         'browser/ui/webui/set_as_default_browser_ui.cc',
         'browser/ui/webui/set_as_default_browser_ui.h',
         'browser/ui/webui/signin/login_ui_service.cc',
@@ -2676,7 +2674,6 @@
             ['exclude', '^browser/ui/views/color_chooser_dialog.cc'],
             ['exclude', '^browser/ui/views/color_chooser_dialog.h'],
             ['exclude', '^browser/ui/views/color_chooser_win.cc'],
-            ['exclude', '^browser/ui/views/simple_message_box_win.cc'],
             ['exclude', '^browser/ui/views/tabs/native_view_photobooth.h'],
             ['exclude', '^browser/ui/views/tabs/native_view_photobooth_win.cc'],
             ['exclude', '^browser/ui/views/tabs/native_view_photobooth_win.h'],
@@ -3110,6 +3107,14 @@
             'browser/ui/webui/media/webrtc_logs_ui.h',
           ],
         }],
+        ['enable_mdns==1', {
+          'sources': [
+            'browser/ui/webui/local_discovery/local_discovery_ui.cc',
+            'browser/ui/webui/local_discovery/local_discovery_ui.h',
+            'browser/ui/webui/local_discovery/local_discovery_ui_handler.cc',
+            'browser/ui/webui/local_discovery/local_discovery_ui_handler.h',
+          ],
+        }],
       ],
     },
   ],
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index c29bd66..09c2912 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -37,6 +37,8 @@
         '<(DEPTH)/chrome/chrome_resources.gyp:chrome_strings',
         '<(DEPTH)/chrome/chrome_resources.gyp:theme_resources',
         '<(DEPTH)/chrome/common_constants.gyp:common_constants',
+        '<(DEPTH)/components/components.gyp:json_schema',
+        '<(DEPTH)/components/components.gyp:policy_component',
         '<(DEPTH)/components/components.gyp:visitedlink_common',
         '<(DEPTH)/content/content.gyp:content_common',
         '<(DEPTH)/net/net.gyp:net',
@@ -46,7 +48,7 @@
         '<(DEPTH)/third_party/libxml/libxml.gyp:libxml',
         '<(DEPTH)/third_party/mt19937ar/mt19937ar.gyp:mt19937ar',
         '<(DEPTH)/third_party/sqlite/sqlite.gyp:sqlite',
-        '<(DEPTH)/third_party/zlib/zlib.gyp:zip',
+        '<(DEPTH)/third_party/zlib/google/zip.gyp:zip',
         '<(DEPTH)/ui/ui.gyp:ui_resources',
         '<(DEPTH)/url/url.gyp:url_lib',
         '<(DEPTH)/webkit/common/user_agent/webkit_user_agent.gyp:user_agent',
@@ -72,12 +74,18 @@
         '../extensions/common/extension_resource.h',
         '../extensions/common/extensions_client.cc',
         '../extensions/common/extensions_client.h',
+        '../extensions/common/features/feature.cc',
+        '../extensions/common/features/feature.h',
         '../extensions/common/features/feature_provider.cc',
         '../extensions/common/features/feature_provider.h',
         '../extensions/common/id_util.cc',
         '../extensions/common/id_util.h',
         '../extensions/common/install_warning.cc',
         '../extensions/common/install_warning.h',
+        '../extensions/common/manifest.cc',
+        '../extensions/common/manifest.h',
+        '../extensions/common/manifest_constants.cc',
+        '../extensions/common/manifest_constants.h',
         '../extensions/common/matcher/regex_set_matcher.cc',
         '../extensions/common/matcher/regex_set_matcher.h',
         '../extensions/common/matcher/string_pattern.cc',
@@ -247,8 +255,6 @@
         'common/extensions/features/base_feature_provider.h',
         'common/extensions/features/complex_feature.cc',
         'common/extensions/features/complex_feature.h',
-        'common/extensions/features/feature.cc',
-        'common/extensions/features/feature.h',
         'common/extensions/features/feature_channel.cc',
         'common/extensions/features/feature_channel.h',
         'common/extensions/features/manifest_feature.cc',
@@ -259,8 +265,6 @@
         'common/extensions/features/simple_feature.h',
         'common/extensions/incognito_handler.cc',
         'common/extensions/incognito_handler.h',
-        'common/extensions/manifest.cc',
-        'common/extensions/manifest.h',
         'common/extensions/manifest_handler.cc',
         'common/extensions/manifest_handler.h',
         'common/extensions/manifest_handler_helpers.cc',
@@ -373,10 +377,6 @@
         'common/instant_restricted_id_cache.h',
         'common/instant_types.cc',
         'common/instant_types.h',
-        'common/json_schema/json_schema_constants.cc',
-        'common/json_schema/json_schema_constants.h',
-        'common/json_schema/json_schema_validator.cc',
-        'common/json_schema/json_schema_validator.h',
         'common/localized_error.cc',
         'common/localized_error.h',
         'common/logging_chrome.cc',
@@ -419,15 +419,12 @@
         'common/omaha_query_params/omaha_query_params.cc',
         'common/omaha_query_params/omaha_query_params.h',
         'common/omnibox_focus_state.h',
-        'common/one_click_signin_messages.h',
         'common/partial_circular_buffer.cc',
         'common/partial_circular_buffer.h',
         'common/pepper_flash.cc',
         'common/pepper_flash.h',
         'common/pepper_permission_util.cc',
         'common/pepper_permission_util.h',
-        'common/policy/policy_schema.cc',
-        'common/policy/policy_schema.h',
         'common/pref_names_util.cc',
         'common/pref_names_util.h',
         'common/print_messages.cc',
@@ -593,12 +590,9 @@
         }],
         ['OS=="win"', {
           'include_dirs': [
+            '<(DEPTH)/breakpad/src',
             '<(DEPTH)/third_party/wtl/include',
           ],
-          'sources!': [
-            'common/crash_keys.cc',
-            'common/crash_keys.h',
-          ],
         }],
         ['enable_mdns == 1', {
             'sources': [
diff --git a/chrome/chrome_dll_bundle.gypi b/chrome/chrome_dll_bundle.gypi
index 9b8d1af..57bd2b9 100644
--- a/chrome/chrome_dll_bundle.gypi
+++ b/chrome/chrome_dll_bundle.gypi
@@ -61,7 +61,6 @@
     'app/theme/menu_overflow_down.pdf',
     'app/theme/menu_overflow_up.pdf',
     'browser/mac/install.sh',
-    '<(SHARED_INTERMEDIATE_DIR)/repack/chrome.pak',
     '<(SHARED_INTERMEDIATE_DIR)/repack/chrome_100_percent.pak',
     '<(SHARED_INTERMEDIATE_DIR)/repack/resources.pak',
     '<!@pymod_do_main(repack_locales -o -p <(OS) -g <(grit_out_dir) -s <(SHARED_INTERMEDIATE_DIR) -x <(SHARED_INTERMEDIATE_DIR) <(locales))',
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 78047eb..67b0efa 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -436,6 +436,9 @@
             '../third_party/widevine/cdm/widevine_cdm.gyp:widevinecdmadapter',
           ],
         }],
+        ['chrome_multiple_dll', {
+          'defines': ['CHROME_MULTIPLE_DLL'],
+        }],
         ['OS=="mac" and asan==1', {
           'xcode_settings': {
             # Override the outer definition of CHROMIUM_STRIP_SAVE_FILE.
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index f4c5f5d..fd405ce 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -553,7 +553,6 @@
           # TODO(mmoss) Any convenient way to get all the relevant build
           # files? (e.g. all locales, resources, etc.)
           '<(PRODUCT_DIR)/chrome',
-          '<(PRODUCT_DIR)/chrome.pak',
           '<(PRODUCT_DIR)/chrome_sandbox',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libppGoogleNaClPluginChrome.so',
diff --git a/chrome/chrome_ios_bundle_resources.gypi b/chrome/chrome_ios_bundle_resources.gypi
index 988654b..efcb5f8 100644
--- a/chrome/chrome_ios_bundle_resources.gypi
+++ b/chrome/chrome_ios_bundle_resources.gypi
@@ -7,7 +7,6 @@
     '<(DEPTH)/chrome/chrome_resources.gyp:packed_extra_resources',
   ],
   'mac_bundle_resources': [
-    '<(SHARED_INTERMEDIATE_DIR)/repack/chrome.pak',
     '<(SHARED_INTERMEDIATE_DIR)/repack/chrome_100_percent.pak',
     '<(SHARED_INTERMEDIATE_DIR)/repack/chrome_200_percent.pak',
     '<(SHARED_INTERMEDIATE_DIR)/repack/resources.pak',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 5b0d88c..fde9706 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -79,6 +79,8 @@
         'renderer/extensions/context_menus_custom_bindings.h',
         'renderer/extensions/dispatcher.cc',
         'renderer/extensions/dispatcher.h',
+        'renderer/extensions/document_custom_bindings.cc',
+        'renderer/extensions/document_custom_bindings.h',
         'renderer/extensions/dom_activity_logger.cc',
         'renderer/extensions/dom_activity_logger.h',
         'renderer/extensions/event_bindings.cc',
@@ -171,8 +173,6 @@
         'renderer/net/renderer_net_predictor.h',
         'renderer/net_benchmarking_extension.cc',
         'renderer/net_benchmarking_extension.h',
-        'renderer/one_click_signin_agent.cc',
-        'renderer/one_click_signin_agent.h',
         'renderer/playback_extension.cc',
         'renderer/playback_extension.h',
         'renderer/resource_bundle_source_map.cc',
@@ -278,6 +278,7 @@
         'renderer/prerender/prerenderer_client.h',
         'renderer/printing/print_web_view_helper.cc',
         'renderer/printing/print_web_view_helper.h',
+        'renderer/printing/print_web_view_helper_android.cc',
         'renderer/printing/print_web_view_helper_linux.cc',
         'renderer/printing/print_web_view_helper_mac.mm',
         'renderer/printing/print_web_view_helper_win.cc',
diff --git a/chrome/chrome_repack_chrome.gypi b/chrome/chrome_repack_chrome.gypi
index a895435..f9f2f2d 100644
--- a/chrome/chrome_repack_chrome.gypi
+++ b/chrome/chrome_repack_chrome.gypi
@@ -5,25 +5,8 @@
   'action_name': 'repack_chrome',
   'variables': {
     'pak_inputs': [
-      '<(grit_out_dir)/browser_resources.pak',
-      '<(grit_out_dir)/common_resources.pak',
-      '<(SHARED_INTERMEDIATE_DIR)/chrome/chrome_unscaled_resources.pak',
       '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.pak',
     ],
-    'conditions': [
-      ['OS != "ios"', {
-        'pak_inputs': [
-          '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak',
-          '<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/tracing_resources.pak',
-          '<(SHARED_INTERMEDIATE_DIR)/webkit/blink_resources.pak',
-        ],
-      }],
-      ['enable_extensions==1', {
-        'pak_inputs': [
-          '<(grit_out_dir)/extensions_api_resources.pak',
-        ],
-      }],
-    ],
   },
   'inputs': [
     '<(repack_path)',
diff --git a/chrome/chrome_repack_resources.gypi b/chrome/chrome_repack_resources.gypi
index 8519aab..7480c2d 100644
--- a/chrome/chrome_repack_resources.gypi
+++ b/chrome/chrome_repack_resources.gypi
@@ -5,14 +5,26 @@
   'action_name': 'repack_resources',
   'variables': {
     'pak_inputs': [
+      '<(SHARED_INTERMEDIATE_DIR)/chrome/chrome_unscaled_resources.pak',
+      '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.pak',
+      '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/webui_resources.pak',
+      '<(grit_out_dir)/browser_resources.pak',
+      '<(grit_out_dir)/common_resources.pak',
       '<(grit_out_dir)/memory_internals_resources.pak',
       '<(grit_out_dir)/net_internals_resources.pak',
       '<(grit_out_dir)/signin_internals_resources.pak',
       '<(grit_out_dir)/sync_internals_resources.pak',
       '<(grit_out_dir)/translate_internals_resources.pak',
-      '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/webui_resources.pak',
     ],
     'conditions': [
+      ['OS != "ios"', {
+        'pak_inputs': [
+          '<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing/tracing_resources.pak',
+          '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak',
+          '<(SHARED_INTERMEDIATE_DIR)/webkit/blink_resources.pak',
+          '<(grit_out_dir)/devtools_discovery_page_resources.pak',
+        ],
+      }],
       ['OS != "ios" and OS != "android"', {
         # New paks should be added here by default.
         'pak_inputs': [
@@ -23,9 +35,9 @@
           '<(grit_out_dir)/sync_file_system_internals_resources.pak',
         ],
       }],
-      ['OS != "ios"', {
+      ['enable_extensions==1', {
         'pak_inputs': [
-          '<(grit_out_dir)/devtools_discovery_page_resources.pak',
+          '<(grit_out_dir)/extensions_api_resources.pak',
         ],
       }],
     ],
diff --git a/chrome/chrome_resources.gyp b/chrome/chrome_resources.gyp
index 3084064..ea6e283 100644
--- a/chrome/chrome_resources.gyp
+++ b/chrome/chrome_resources.gyp
@@ -278,6 +278,7 @@
       },
       'dependencies': [
         'chrome_extra_resources',
+        'packed_resources',
       ],
       'actions': [
         {
diff --git a/chrome/chrome_syzygy.gypi b/chrome/chrome_syzygy.gypi
index 0fbf6bc..6dbbd34 100644
--- a/chrome/chrome_syzygy.gypi
+++ b/chrome/chrome_syzygy.gypi
@@ -51,7 +51,6 @@
           'msvs_cygwin_shell': 0,
           'inputs': [
             '<(PRODUCT_DIR)/<(dll_name).dll',
-            '<(PRODUCT_DIR)/<(dll_name).dll.pdb',
             '<(DEPTH)/chrome/tools/build/win/win-syzyasan-filter.txt',
           ],
           'outputs': [
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index c3725e9..74c95df 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -206,6 +206,10 @@
       ],
       'sources': [
         '../apps/app_shim/app_shim_quit_interactive_uitest_mac.mm',
+        '../ui/views/corewm/desktop_capture_controller_unittest.cc',
+        'browser/apps/app_browsertest_util.cc',
+        'browser/apps/app_browsertest_util.h',
+        'browser/apps/web_view_interactive_browsertest.cc',
         'browser/autofill/autofill_interactive_uitest.cc',
         'browser/browser_keyevents_browsertest.cc',
         'browser/extensions/api/omnibox/omnibox_api_interactive_test.cc',
@@ -218,9 +222,6 @@
         'browser/extensions/extension_test_message_listener.cc',
         'browser/extensions/extension_test_message_listener.h',
         'browser/extensions/notifications_apitest.cc',
-        'browser/extensions/platform_app_browsertest_util.cc',
-        'browser/extensions/platform_app_browsertest_util.h',
-        'browser/extensions/web_view_interactive_browsertest.cc',
         'browser/extensions/window_open_interactive_apitest.cc',
         'browser/extensions/extension_fullscreen_apitest.cc',
         'browser/extensions/extension_pointer_lock_apitest.cc',
@@ -384,13 +385,16 @@
             'browser/ui/views/tabs/tab_drag_controller_interactive_uitest_win.cc',
           ],
         }],
+        ['use_aura==0 or chromeos==1', {
+          'sources!': [
+            '../ui/views/corewm/desktop_capture_controller_unittest.cc',
+          ],
+        }],
         ['chromeos==1', {
           'dependencies': [
             '../chromeos/chromeos.gyp:chromeos',
           ],
           'sources': [
-            'browser/chromeos/cros/cros_in_process_browser_test.cc',
-            'browser/chromeos/cros/cros_in_process_browser_test.h',
             'browser/chromeos/input_method/keyboard_browsertest.cc',
             'browser/chromeos/input_method/textinput_browsertest.cc',
             'browser/chromeos/input_method/textinput_surroundingtext_browsertest.cc',
@@ -1118,6 +1122,7 @@
         'common/extensions/api/api.gyp:api',
         'renderer',
         'test_support_common',
+        'test_support_unit',
         '../base/base.gyp:base',
         '../base/base.gyp:base_i18n',
         '../base/base.gyp:test_support_base',
@@ -1153,7 +1158,12 @@
       'sources': [
         '../apps/app_restore_service_browsertest.cc',
         '../apps/load_and_launch_browsertest.cc',
+        '../components/autofill/content/renderer/test_password_autofill_agent.h',
+        '../components/autofill/content/renderer/test_password_autofill_agent.cc',
+        '../remoting/test/auth_browsertest.cc',
+        '../remoting/test/launch_browsertest.cc',
         '../remoting/test/remote_desktop_browsertest.cc',
+        '../remoting/test/remote_desktop_browsertest.h',
         'app/breakpad_mac_stubs.mm',
         'app/chrome_command_ids.h',
         'app/chrome_dll.rc',
@@ -1162,6 +1172,12 @@
         'browser/accessibility/accessibility_extension_apitest.cc',
         'browser/accessibility/browser_accessibility_state_browsertest.cc',
         'browser/app_controller_mac_browsertest.mm',
+        'browser/apps/ad_view_browsertest.cc',
+        'browser/apps/app_browsertest.cc',
+        'browser/apps/app_browsertest_util.cc',
+        'browser/apps/app_browsertest_util.h',
+        'browser/apps/web_view_browsertest.cc',
+        'browser/apps/window_controls_browsertest.cc',
         'browser/autocomplete/autocomplete_browsertest.cc',
         'browser/autofill/autofill_browsertest.cc',
         'browser/autofill/autofill_driver_impl_browsertest.cc',
@@ -1183,8 +1199,6 @@
         '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/cros/cros_in_process_browser_test.cc',
-        'browser/chromeos/cros/cros_in_process_browser_test.h',
         'browser/chromeos/drive/drive_integration_service_browsertest.cc',
         'browser/chromeos/drive/test_util.cc',
         'browser/chromeos/drive/test_util.h',
@@ -1209,9 +1223,13 @@
         'browser/chromeos/login/enrollment/mock_enrollment_screen.h',
         'browser/chromeos/login/existing_user_controller_browsertest.cc',
         'browser/chromeos/login/kiosk_browsertest.cc',
+        'browser/chromeos/login/login_screen_policy_browsertest.cc',
         'browser/chromeos/login/login_utils_browsertest.cc',
+        'browser/chromeos/login/login_manager_test.cc',
+        'browser/chromeos/login/login_manager_test.h',
         'browser/chromeos/login/mock_authenticator.cc',
         'browser/chromeos/login/mock_authenticator.h',
+        'browser/chromeos/login/session_login_browsertest.cc',
         'browser/chromeos/login/screen_locker_tester.cc',
         'browser/chromeos/login/screen_locker_tester.h',
         'browser/chromeos/login/screens/mock_error_screen.cc',
@@ -1233,8 +1251,9 @@
         'browser/chromeos/login/wizard_controller_browsertest.cc',
         'browser/chromeos/login/wizard_in_process_browser_test.cc',
         'browser/chromeos/login/wizard_in_process_browser_test.h',
-        'browser/chromeos/media/media_player_browsertest.cc',
         'browser/chromeos/memory/oom_priority_manager_browsertest.cc',
+        'browser/chromeos/policy/cros_enterprise_test_utils.cc',
+        'browser/chromeos/policy/cros_enterprise_test_utils.h',
         'browser/chromeos/policy/device_local_account_browsertest.cc',
         'browser/chromeos/policy/device_policy_cros_browser_test.cc',
         'browser/chromeos/policy/device_policy_cros_browser_test.h',
@@ -1262,7 +1281,6 @@
         'browser/errorpage_browsertest.cc',
         'browser/extensions/active_tab_apitest.cc',
         'browser/extensions/activity_log/activity_log_browsertest.cc',
-        'browser/extensions/ad_view_browsertest.cc',
         'browser/extensions/alert_apitest.cc',
         'browser/extensions/all_urls_apitest.cc',
         'browser/extensions/api/activity_log_private/activity_log_private_apitest.cc',
@@ -1283,6 +1301,7 @@
         'browser/extensions/api/debugger/debugger_extension_apitest.cc',
         'browser/extensions/api/declarative/declarative_apitest.cc',
         'browser/extensions/api/declarative_content/declarative_content_apitest.cc',
+        'browser/extensions/api/desktop_capture/desktop_capture_apitest.cc',
         'browser/extensions/api/developer_private/developer_private_apitest.cc',
         'browser/extensions/api/dial/dial_apitest.cc',
         'browser/extensions/api/dns/dns_apitest.cc',
@@ -1306,7 +1325,6 @@
         'browser/extensions/api/management/management_apitest.cc',
         'browser/extensions/api/management/management_browsertest.cc',
         'browser/extensions/api/media_galleries/media_galleries_apitest.cc',
-        'browser/extensions/api/media_galleries_private/media_galleries_eject_apitest.cc',
         'browser/extensions/api/media_galleries_private/media_galleries_private_apitest.cc',
         'browser/extensions/api/media_galleries_private/media_galleries_watch_apitest.cc',
         'browser/extensions/api/messaging/native_messaging_apitest.cc',
@@ -1327,8 +1345,9 @@
         'browser/extensions/api/rtc_private/rtc_private_apitest.cc',
         'browser/extensions/api/runtime/runtime_apitest.cc',
         'browser/extensions/api/serial/serial_apitest.cc',
-        'browser/extensions/api/session_restore/session_restore_apitest.cc',
+        'browser/extensions/api/sessions/sessions_apitest.cc',
         'browser/extensions/api/socket/socket_apitest.cc',
+        'browser/extensions/api/sockets_udp/sockets_udp_apitest.cc',
         'browser/extensions/api/storage/settings_apitest.cc',
         'browser/extensions/api/streams_private/streams_private_apitest.cc',
         'browser/extensions/api/sync_file_system/sync_file_system_apitest.cc',
@@ -1404,9 +1423,6 @@
         'browser/extensions/mutation_observers_apitest.cc',
         'browser/extensions/options_page_apitest.cc',
         'browser/extensions/page_action_browsertest.cc',
-        'browser/extensions/platform_app_browsertest.cc',
-        'browser/extensions/platform_app_browsertest_util.cc',
-        'browser/extensions/platform_app_browsertest_util.h',
         'browser/extensions/plugin_apitest.cc',
         'browser/extensions/process_management_browsertest.cc',
         'browser/extensions/requirements_checker_browsertest.cc',
@@ -1417,9 +1433,7 @@
         'browser/extensions/subscribe_page_action_browsertest.cc',
         'browser/extensions/test_extension_dir.cc',
         'browser/extensions/test_extension_dir.h',
-        'browser/extensions/window_controls_browsertest.cc',
         'browser/extensions/web_contents_browsertest.cc',
-        'browser/extensions/web_view_browsertest.cc',
         'browser/extensions/webstore_startup_installer_browsertest.cc',
         'browser/extensions/window_open_apitest.cc',
         'browser/external_extension_browsertest.cc',
@@ -1438,6 +1452,7 @@
         'browser/importer/importer_unittest_utils.h',
         'browser/infobars/infobar_extension_apitest.cc',
         'browser/infobars/infobars_browsertest.cc',
+        'browser/lifetime/browser_close_manager_browsertest.cc',
         'browser/loadtimes_extension_bindings_browsertest.cc',
         'browser/locale_tests_browsertest.cc',
         'browser/logging_chrome_browsertest.cc',
@@ -1543,7 +1558,6 @@
         '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/chrome_launcher_controller_per_app_browsertest.cc',
         'browser/ui/ash/launcher/launcher_favicon_loader_browsertest.cc',
         'browser/ui/ash/shelf_browsertest.cc',
         'browser/ui/ash/volume_controller_browsertest_chromeos.cc',
@@ -1654,6 +1668,7 @@
         'browser/ui/webui/options/settings_format_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',
         'browser/ui/webui/sync_setup_browsertest.js',
         'browser/ui/webui/web_ui_test_handler.cc',
         'browser/ui/webui/web_ui_test_handler.h',
@@ -1712,6 +1727,7 @@
         'test/data/webui/net_internals/prerender_view.js',
         'test/data/webui/net_internals/test_view.js',
         'test/data/webui/net_internals/timeline_view.js',
+        'test/data/webui/net_internals/waterfall_view.js',
         'test/data/webui/ntp4.js',
         'test/data/webui/ntp4_browsertest.cc',
         'test/data/webui/ntp4_browsertest.h',
@@ -1846,6 +1862,8 @@
             'browser/signin/signin_browsertest.cc',
             # chromeos does not use cross-platform panels
             'browser/ui/panels/panel_extension_browsertest.cc',
+            # chromeos does not use the desktop user manager
+            'browser/ui/webui/signin/user_manager_ui_browsertest.cc',
           ],
           'dependencies': [
             '../dbus/dbus.gyp:dbus_test_support',
@@ -1953,7 +1971,6 @@
             'browser/chromeos/system/tray_accessibility_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_per_app_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',
@@ -2089,6 +2106,11 @@
             ['exclude', '^test/data/webui/print_preview.js'],
           ],
         }],
+        ['enable_mdns==1', {
+          'sources' : [
+            'browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc',
+          ]
+        }],
       ],  # conditions
     },  # target browser_tests
     {
@@ -2129,11 +2151,16 @@
         'HAS_OUT_OF_PROC_TEST_RUNNER',
       ],
       'sources': [
+        '../components/autofill/content/renderer/test_password_autofill_agent.cc',
+        '../components/autofill/content/renderer/test_password_autofill_agent.h',
         'app/breakpad_mac_stubs.mm',
         'app/chrome_command_ids.h',
         'app/chrome_dll.rc',
         'app/chrome_dll_resource.h',
         'app/chrome_version.rc.version',
+        'browser/extensions/api/tab_capture/tab_capture_performancetest.cc',
+        'browser/extensions/extension_apitest.cc',
+        'browser/extensions/extension_browsertest.cc',
         'test/base/chrome_render_view_test.cc',
         'test/base/chrome_render_view_test.h',
         'test/base/chrome_test_launcher.cc',
@@ -3271,7 +3298,6 @@
             '../base/base.gyp:base_java_test_support',
             '../content/content.gyp:content_java_test_support',
             '../sync/sync.gyp:sync_javatests',
-            '../tools/android/forwarder/forwarder.gyp:forwarder',
           ],
           'variables': {
             'apk_name': 'ChromiumTestShellTest',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 77fd367..72d7e96 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -163,6 +163,8 @@
         'browser/search_engines/template_url_service_test_util.h',
         'browser/sessions/session_service_test_helper.cc',
         'browser/sessions/session_service_test_helper.h',
+        'browser/signin/fake_profile_oauth2_token_service.cc',
+        'browser/signin/fake_profile_oauth2_token_service.h',
         'browser/signin/fake_signin_manager.cc',
         'browser/signin/fake_signin_manager.h',
         'browser/ssl/ssl_client_auth_requestor_mock.cc',
@@ -232,6 +234,8 @@
         'test/base/module_system_test.h',
         'test/base/profile_mock.cc',
         'test/base/profile_mock.h',
+        'test/base/scoped_browser_locale.cc',
+        'test/base/scoped_browser_locale.h',
         'test/base/scoped_testing_local_state.cc',
         'test/base/scoped_testing_local_state.h',
         'test/base/test_browser_window.cc',
@@ -506,6 +510,8 @@
         '../apps/saved_files_service_unittest.cc',
         '../apps/app_shim/extension_app_shim_handler_mac_unittest.cc',
         '../apps/shell_window_geometry_cache_unittest.cc',
+        '../components/autofill/content/renderer/test_password_autofill_agent.cc',
+        '../components/autofill/content/renderer/test_password_autofill_agent.h',
         '../extensions/browser/file_reader_unittest.cc',
         '../extensions/common/event_filter_unittest.cc',
         '../extensions/common/extension_resource_unittest.cc',
@@ -575,6 +581,7 @@
         'browser/chromeos/accessibility/magnification_manager_unittest.cc',
         'browser/chromeos/attestation/attestation_ca_client_unittest.cc',
         'browser/chromeos/attestation/attestation_policy_observer_unittest.cc',
+        'browser/chromeos/attestation/platform_verification_flow_unittest.cc',
         'browser/chromeos/contacts/contact_database_unittest.cc',
         'browser/chromeos/contacts/contact_manager_stub.cc',
         'browser/chromeos/contacts/contact_manager_stub.h',
@@ -617,7 +624,6 @@
         'browser/chromeos/drive/fake_file_system_unittest.cc',
         'browser/chromeos/drive/fake_free_disk_space_getter.cc',
         'browser/chromeos/drive/fake_free_disk_space_getter.h',
-        'browser/chromeos/drive/file_cache_metadata_unittest.cc',
         'browser/chromeos/drive/file_cache_unittest.cc',
         'browser/chromeos/drive/file_change_unittest.cc',
         'browser/chromeos/drive/file_system/copy_operation_unittest.cc',
@@ -636,7 +642,6 @@
         'browser/chromeos/drive/file_system/update_operation_unittest.cc',
         'browser/chromeos/drive/file_system_unittest.cc',
         'browser/chromeos/drive/file_system_util_unittest.cc',
-        'browser/chromeos/drive/file_write_helper_unittest.cc',
         'browser/chromeos/drive/file_write_watcher_unittest.cc',
         'browser/chromeos/drive/fileapi_worker_unittest.cc',
         'browser/chromeos/drive/job_queue_unittest.cc',
@@ -651,10 +656,13 @@
         'browser/chromeos/drive/test_util.cc',
         'browser/chromeos/drive/test_util.h',
         'browser/chromeos/drive/webkit_file_stream_reader_impl_unittest.cc',
+        'browser/chromeos/drive/write_on_cache_file_unittest.cc',
         'browser/chromeos/extensions/default_app_order_unittest.cc',
         'browser/chromeos/extensions/file_manager/desktop_notifications_unittest.cc',
+        'browser/chromeos/extensions/file_manager/file_manager_util_unittest.cc',
         'browser/chromeos/extensions/file_manager/file_tasks_unittest.cc',
         'browser/chromeos/extensions/file_manager/file_watcher_unittest.cc',
+        'browser/chromeos/extensions/file_manager/url_util_unittest.cc',
         'browser/chromeos/extensions/wallpaper_private_api_unittest.cc',
         'browser/chromeos/external_metrics_unittest.cc',
         'browser/chromeos/fileapi/file_access_permissions_unittest.cc',
@@ -699,7 +707,7 @@
         'browser/chromeos/policy/device_local_account_policy_service_unittest.cc',
         'browser/chromeos/policy/enterprise_install_attributes_unittest.cc',
         'browser/chromeos/policy/login_screen_power_management_policy_unittest.cc',
-        'browser/chromeos/policy/network_configuration_updater_impl_cros_unittest.cc',
+        'browser/chromeos/policy/network_configuration_updater_impl_unittest.cc',
         'browser/chromeos/policy/proxy_policy_provider_unittest.cc',
         'browser/chromeos/policy/recommendation_restorer_unittest.cc',
         'browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc',
@@ -746,19 +754,19 @@
         'browser/custom_handlers/protocol_handler_registry_unittest.cc',
         'browser/diagnostics/diagnostics_model_unittest.cc',
         'browser/diagnostics/diagnostics_controller_unittest.cc',
-        'browser/download/chrome_download_manager_delegate_unittest.cc',
-        'browser/download/download_item_model_unittest.cc',
         'browser/download/all_download_item_notifier_unittest.cc',
+        'browser/download/chrome_download_manager_delegate_unittest.cc',
+        'browser/download/download_field_trial_unittest.cc',
         'browser/download/download_history_unittest.cc',
+        'browser/download/download_item_model_unittest.cc',
+        'browser/download/download_path_reservation_tracker_unittest.cc',
         'browser/download/download_query_unittest.cc',
         'browser/download/download_request_infobar_delegate_unittest.cc',
         'browser/download/download_request_limiter_unittest.cc',
-        'browser/download/download_path_reservation_tracker_unittest.cc',
         'browser/download/download_shelf_unittest.cc',
         'browser/download/download_status_updater_unittest.cc',
         'browser/download/download_target_determiner_unittest.cc',
         'browser/download/download_ui_controller_unittest.cc',
-        'browser/download/download_util_unittest.cc',
         'browser/drive/drive_api_util_unittest.cc',
         'browser/drive/drive_uploader_unittest.cc',
         'browser/drive/event_logger_unittest.cc',
@@ -766,6 +774,7 @@
         'browser/enumerate_modules_model_unittest_win.cc',
         'browser/extensions/active_tab_unittest.cc',
         'browser/extensions/activity_log/activity_database_unittest.cc',
+        'browser/extensions/activity_log/activity_log_enabled_unittest.cc',
         'browser/extensions/activity_log/activity_log_unittest.cc',
         'browser/extensions/activity_log/activity_log_policy_unittest.cc',
         'browser/extensions/activity_log/counting_policy_unittest.cc',
@@ -820,6 +829,7 @@
         'browser/extensions/api/socket/socket_api_unittest.cc',
         'browser/extensions/api/socket/tcp_socket_unittest.cc',
         'browser/extensions/api/socket/udp_socket_unittest.cc',
+        'browser/extensions/api/sockets_udp/sockets_udp_api_unittest.cc',
         'browser/extensions/api/storage/policy_value_store_unittest.cc',
         'browser/extensions/api/storage/settings_frontend_unittest.cc',
         'browser/extensions/api/storage/settings_quota_unittest.cc',
@@ -935,7 +945,6 @@
         'browser/history/thumbnail_database_unittest.cc',
         'browser/history/top_sites_database_unittest.cc',
         'browser/history/top_sites_impl_unittest.cc',
-        'browser/history/top_sites_likely_impl_unittest.cc',
         'browser/history/typed_url_syncable_service_unittest.cc',
         'browser/history/url_database_unittest.cc',
         'browser/history/visit_database_unittest.cc',
@@ -983,6 +992,7 @@
         'browser/metrics/variations/variations_service_unittest.cc',
         'browser/metrics/variations/variations_request_scheduler_unittest.cc',
         'browser/nacl_host/nacl_file_host_unittest.cc',
+        'browser/nacl_host/nacl_process_host_unittest.cc',
         'browser/nacl_host/nacl_validation_cache_unittest.cc',
         'browser/nacl_host/pnacl_translation_cache_unittest.cc',
         'browser/nacl_host/pnacl_host_unittest.cc',
@@ -1281,6 +1291,7 @@
         'browser/sync/profile_sync_service_unittest.cc',
         'browser/sync/profile_sync_test_util.cc',
         'browser/sync/profile_sync_test_util.h',
+        'browser/sync/sessions2/tab_node_pool2_unittest.cc',
         'browser/sync/sync_global_error_unittest.cc',
         'browser/sync/sync_prefs_unittest.cc',
         'browser/sync/sync_startup_tracker_unittest.cc',
@@ -1345,12 +1356,11 @@
         'browser/translate/translate_browser_metrics_unittest.cc',
         'browser/translate/translate_manager_unittest.cc',
         'browser/translate/translate_prefs_unittest.cc',
+        'browser/translate/translate_script_unittest.cc',
         'browser/ui/android/tab_model/tab_model_unittest.cc',
         'browser/ui/ash/event_rewriter_unittest.cc',
         'browser/ui/ash/ime_controller_chromeos_unittest.cc',
-        'browser/ui/ash/launcher/browser_launcher_item_controller_unittest.cc',
-        'browser/ui/ash/launcher/chrome_launcher_controller_per_app_unittest.cc',
-        'browser/ui/ash/launcher/chrome_launcher_controller_per_browser_unittest.cc',
+        'browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc',
         'browser/ui/ash/launcher/launcher_context_menu_unittest.cc',
         'browser/ui/ash/screenshot_taker_unittest.cc',
         'browser/ui/ash/window_positioner_unittest.cc',
@@ -1680,7 +1690,6 @@
         'browser/webdata/token_service_table_unittest.cc',
         'browser/webdata/web_apps_table_unittest.cc',
         'common/cancelable_task_tracker_unittest.cc',
-        'common/child_process_logging_mac_unittest.mm',
         'common/chrome_paths_unittest.cc',
         'common/cloud_print/cloud_print_helpers_unittest.cc',
         'common/chrome_content_client_unittest.cc',
@@ -1755,9 +1764,6 @@
         'common/favicon/favicon_url_parser_unittest.cc',
         'common/importer/firefox_importer_utils_unittest.cc',
         'common/instant_restricted_id_cache_unittest.cc',
-        'common/json_schema/json_schema_validator_unittest.cc',
-        'common/json_schema/json_schema_validator_unittest_base.cc',
-        'common/json_schema/json_schema_validator_unittest_base.h',
         'common/mac/cfbundle_blocker_unittest.mm',
         'common/mac/mock_launchd.cc',
         'common/mac/mock_launchd.h',
@@ -1775,7 +1781,6 @@
         'common/net/url_fixer_upper_unittest.cc',
         'common/net/x509_certificate_model_unittest.cc',
         'common/partial_circular_buffer_unittest.cc',
-        'common/policy/policy_schema_unittest.cc',
         'common/pref_names_util_unittest.cc',
         'common/service_process_util_unittest.cc',
         'common/switch_utils_unittest.cc',
@@ -2130,6 +2135,7 @@
               'utility/local_discovery/local_domain_resolver_unittest.cc',
               'utility/local_discovery/service_discovery_client_unittest.cc',
               'browser/local_discovery/privet_device_lister_unittest.cc',
+              'browser/local_discovery/privet_notifications_unittest.cc'
             ]
         }],
         ['configuration_policy==0', {
@@ -2226,9 +2232,6 @@
             'browser/ui/sync/one_click_signin_helper_unittest.cc',
             'browser/ui/sync/one_click_signin_sync_starter_unittest.cc',
           ],
-          'sources': [
-            'browser/ui/webui/feedback_ui_unittest.cc',
-          ],
         }, { # else: chromeos == 0
           'sources/': [
             ['exclude', '^browser/chromeos/'],
@@ -2364,6 +2367,7 @@
         }],
         ['OS=="win" or OS=="mac"', {
           'sources': [
+            'browser/media_galleries/fileapi/itunes_file_util_unittest.cc',
             'browser/media_galleries/fileapi/picasa/picasa_file_util_unittest.cc',
             'utility/media_galleries/itunes_library_parser_unittest.cc',
             'utility/media_galleries/picasa_album_table_reader_unittest.cc',
@@ -2557,7 +2561,6 @@
             ['exclude', '^browser/ui/tabs/'],
             ['exclude', '^browser/ui/toolbar/'],
             ['exclude', '^browser/ui/webui/downloads_'],
-            ['exclude', '^browser/ui/webui/feedback_'],
             ['exclude', '^browser/ui/webui/flags_'],
             ['exclude', '^browser/ui/webui/help/'],
             ['exclude', '^browser/ui/webui/options/'],
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index 7101165..18b6bce 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -4,6 +4,7 @@
   "+chromeos",  # For chromeos_switches.h
   "+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
diff --git a/chrome/common/child_process_logging.h b/chrome/common/child_process_logging.h
index 2583b7d..21a12bb 100644
--- a/chrome/common/child_process_logging.h
+++ b/chrome/common/child_process_logging.h
@@ -12,7 +12,6 @@
 #include "base/basictypes.h"
 #include "base/debug/crash_logging.h"
 #include "base/strings/string16.h"
-#include "url/gurl.h"
 
 class CommandLine;
 
@@ -50,7 +49,6 @@
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 // These are declared here so the crash reporter can access them directly in
 // compromised context without going through the standard library.
-extern char g_active_url[];
 extern char g_channel[];
 extern char g_client_id[];
 extern char g_extension_ids[];
@@ -79,10 +77,6 @@
 static const size_t kPrinterInfoStrLen = 64;
 #endif
 
-// Sets the URL that is logged if the child process crashes. Use GURL() to clear
-// the URL.
-void SetActiveURL(const GURL& url);
-
 // Sets the Client ID that is used as GUID if a Chrome process crashes.
 void SetClientId(const std::string& client_id);
 
@@ -121,22 +115,6 @@
 void SetChannel(const std::string& channel);
 #endif
 
-// Simple wrapper class that sets the active URL in it's constructor and clears
-// the active URL in the destructor.
-class ScopedActiveURLSetter {
- public:
-  explicit ScopedActiveURLSetter(const GURL& url)  {
-    SetActiveURL(url);
-  }
-
-  ~ScopedActiveURLSetter()  {
-    SetActiveURL(GURL());
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedActiveURLSetter);
-};
-
 // Set/clear information about currently accessed printer.
 class ScopedPrinterInfoSetter {
  public:
@@ -154,20 +132,13 @@
 
 }  // namespace child_process_logging
 
-#if defined(OS_MACOSX)
-
+#if defined(OS_WIN)
 namespace child_process_logging {
 
-void SetActiveURLImpl(const GURL& url,
-                      base::debug::SetCrashKeyValueFuncT set_key_func,
-                      base::debug::ClearCrashKeyValueFuncT clear_key_func);
-
-extern const size_t kMaxNumCrashURLChunks;
-extern const size_t kMaxNumURLChunkValueLength;
-extern const char* kUrlChunkFormatStr;
+// Sets up the base/debug/crash_logging.h mechanism.
+void Init();
 
 }  // namespace child_process_logging
-
-#endif  // defined(OS_MACOSX)
+#endif  // defined(OS_WIN)
 
 #endif  // CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
diff --git a/chrome/common/child_process_logging_mac.mm b/chrome/common/child_process_logging_mac.mm
index 6877e0d..da7c7fe 100644
--- a/chrome/common/child_process_logging_mac.mm
+++ b/chrome/common/child_process_logging_mac.mm
@@ -16,7 +16,6 @@
 #include "chrome/common/metrics/variations/variations_util.h"
 #include "chrome/installer/util/google_update_settings.h"
 #include "gpu/config/gpu_info.h"
-#include "url/gurl.h"
 
 namespace child_process_logging {
 
@@ -25,9 +24,6 @@
 using base::debug::SetCrashKeyValue;
 using base::debug::ClearCrashKey;
 
-const size_t kMaxNumCrashURLChunks = 8;
-const size_t kMaxNumURLChunkValueLength = 255;
-const char* kUrlChunkFormatStr = "url-chunk-%d";
 const char* kGuidParamName = "guid";
 const char* kGPUVendorIdParamName = "gpu-venid";
 const char* kGPUDeviceIdParamName = "gpu-devid";
@@ -44,50 +40,11 @@
 static const size_t kClientIdSize = 32 + 1;
 static char g_client_id[kClientIdSize];
 
-void SetActiveURLImpl(const GURL& url,
-                      SetCrashKeyValueFuncT set_key_func,
-                      ClearCrashKeyValueFuncT clear_key_func) {
-  // First remove any old url chunks we might have lying around.
-  for (size_t i = 0; i < kMaxNumCrashURLChunks; i++) {
-    // On Windows the url-chunk items are 1-based, so match that.
-    clear_key_func(base::StringPrintf(kUrlChunkFormatStr, i + 1));
-  }
-
-  const std::string& raw_url = url.possibly_invalid_spec();
-  size_t raw_url_length = raw_url.length();
-
-  // Bail on zero-length URLs.
-  if (raw_url_length == 0) {
-    return;
-  }
-
-  // Parcel the URL up into up to 8, 255 byte segments.
-  size_t offset = 0;
-  for (size_t i = 0;
-       i < kMaxNumCrashURLChunks && offset < raw_url_length;
-       ++i) {
-
-    // On Windows the url-chunk items are 1-based, so match that.
-    std::string key = base::StringPrintf(kUrlChunkFormatStr, i + 1);
-    size_t length = std::min(kMaxNumURLChunkValueLength,
-                             raw_url_length - offset);
-    std::string value = raw_url.substr(offset, length);
-    set_key_func(key, value);
-
-    // Next chunk.
-    offset += kMaxNumURLChunkValueLength;
-  }
-}
-
 void SetClientIdImpl(const std::string& client_id,
                      SetCrashKeyValueFuncT set_key_func) {
   set_key_func(kGuidParamName, client_id);
 }
 
-void SetActiveURL(const GURL& url) {
-  SetActiveURLImpl(url, SetCrashKeyValue, ClearCrashKey);
-}
-
 void SetClientId(const std::string& client_id) {
   std::string str(client_id);
   ReplaceSubstringsAfterOffset(&str, 0, "-", "");
diff --git a/chrome/common/child_process_logging_mac_unittest.mm b/chrome/common/child_process_logging_mac_unittest.mm
deleted file mode 100644
index bdd93b9..0000000
--- a/chrome/common/child_process_logging_mac_unittest.mm
+++ /dev/null
@@ -1,144 +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/common/child_process_logging.h"
-
-#include <map>
-#include <string>
-
-#import <Foundation/Foundation.h>
-
-#include "base/debug/crash_logging.h"
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-typedef PlatformTest ChildProcessLoggingTest;
-
-namespace {
-
-// Class to mock breakpad's setkeyvalue/clearkeyvalue functions needed for
-// SetActiveRendererURLImpl.
-// The Keys are stored in a static dictionary and methods are provided to
-// verify correctness.
-class MockBreakpadKeyValueStore {
- public:
-  MockBreakpadKeyValueStore() {
-    // Only one of these objects can be active at once.
-    DCHECK(dict == NULL);
-    dict = new std::map<std::string, std::string>;
-  }
-
-  ~MockBreakpadKeyValueStore() {
-    // Only one of these objects can be active at once.
-    DCHECK(dict != NULL);
-    delete dict;
-    dict = NULL;
-  }
-
-  static void SetKeyValue(const base::StringPiece& key,
-                          const base::StringPiece& value) {
-    DCHECK(dict != NULL);
-    (*dict)[key.as_string()] = value.as_string();
-  }
-
-  static void ClearKeyValue(const base::StringPiece& key) {
-    DCHECK(dict != NULL);
-    dict->erase(key.as_string());
-  }
-
-  size_t CountDictionaryEntries() {
-    return dict->size();
-  }
-
-  bool VerifyDictionaryContents(const std::string& url) {
-    using child_process_logging::kMaxNumCrashURLChunks;
-    using child_process_logging::kMaxNumURLChunkValueLength;
-    using child_process_logging::kUrlChunkFormatStr;
-
-    size_t num_url_chunks = CountDictionaryEntries();
-    EXPECT_LE(num_url_chunks, kMaxNumCrashURLChunks);
-
-    std::string accumulated_url;
-    for (size_t i = 0; i < num_url_chunks; ++i) {
-      // URL chunk names are 1-based.
-      std::string key = base::StringPrintf(kUrlChunkFormatStr, i + 1);
-      std::string value = (*dict)[key];
-      EXPECT_GT(value.length(), 0u);
-      EXPECT_LE(value.length(),
-                static_cast<size_t>(kMaxNumURLChunkValueLength));
-      accumulated_url += value;
-    }
-
-    return url == accumulated_url;
-  }
-
- private:
-  static std::map<std::string, std::string>* dict;
-  DISALLOW_COPY_AND_ASSIGN(MockBreakpadKeyValueStore);
-};
-
-// static
-std::map<std::string, std::string>* MockBreakpadKeyValueStore::dict;
-
-}  // namespace
-
-// Call through to SetActiveURLImpl using the functions from
-// MockBreakpadKeyValueStore.
-void SetActiveURLWithMock(const GURL& url) {
-  using child_process_logging::SetActiveURLImpl;
-
-  base::debug::SetCrashKeyValueFuncT setFunc =
-      MockBreakpadKeyValueStore::SetKeyValue;
-  base::debug::ClearCrashKeyValueFuncT clearFunc =
-      MockBreakpadKeyValueStore::ClearKeyValue;
-
-  SetActiveURLImpl(url, setFunc, clearFunc);
-}
-
-TEST_F(ChildProcessLoggingTest, TestUrlSplitting) {
-  using child_process_logging::kMaxNumCrashURLChunks;
-  using child_process_logging::kMaxNumURLChunkValueLength;
-
-  const std::string short_url("http://abc/");
-  std::string long_url("http://");
-  std::string overflow_url("http://");
-
-  long_url += std::string(kMaxNumURLChunkValueLength * 2, 'a');
-  long_url += "/";
-
-  int max_num_chars_stored_in_dump = kMaxNumURLChunkValueLength *
-      kMaxNumCrashURLChunks;
-  overflow_url += std::string(max_num_chars_stored_in_dump + 1, 'a');
-  overflow_url += "/";
-
-  // Check that Clearing NULL URL works.
-  MockBreakpadKeyValueStore mock;
-  SetActiveURLWithMock(GURL());
-  EXPECT_EQ(0u, mock.CountDictionaryEntries());
-
-  // Check that we can set a URL.
-  SetActiveURLWithMock(GURL(short_url.c_str()));
-  EXPECT_TRUE(mock.VerifyDictionaryContents(short_url));
-  EXPECT_EQ(1u, mock.CountDictionaryEntries());
-  SetActiveURLWithMock(GURL());
-  EXPECT_EQ(0u, mock.CountDictionaryEntries());
-
-  // Check that we can replace a long url with a short url.
-  SetActiveURLWithMock(GURL(long_url.c_str()));
-  EXPECT_TRUE(mock.VerifyDictionaryContents(long_url));
-  SetActiveURLWithMock(GURL(short_url.c_str()));
-  EXPECT_TRUE(mock.VerifyDictionaryContents(short_url));
-  SetActiveURLWithMock(GURL());
-  EXPECT_EQ(0u, mock.CountDictionaryEntries());
-
-
-  // Check that overflow works correctly.
-  SetActiveURLWithMock(GURL(overflow_url.c_str()));
-  EXPECT_TRUE(mock.VerifyDictionaryContents(
-      overflow_url.substr(0, max_num_chars_stored_in_dump)));
-  SetActiveURLWithMock(GURL());
-  EXPECT_EQ(0u, mock.CountDictionaryEntries());
-}
diff --git a/chrome/common/child_process_logging_posix.cc b/chrome/common/child_process_logging_posix.cc
index a9dd3dc..fa1748b 100644
--- a/chrome/common/child_process_logging_posix.cc
+++ b/chrome/common/child_process_logging_posix.cc
@@ -18,14 +18,12 @@
 namespace child_process_logging {
 
 // Account for the terminating null character.
-static const size_t kMaxActiveURLSize = 1024 + 1;
 static const size_t kClientIdSize = 32 + 1;
 static const size_t kChannelSize = 32;
 
 // We use static strings to hold the most recent active url and the client
 // identifier. If we crash, the crash handler code will send the contents of
 // these strings to the browser.
-char g_active_url[kMaxActiveURLSize];
 char g_client_id[kClientIdSize];
 
 char g_channel[kChannelSize] = "";
@@ -59,11 +57,6 @@
     kMaxVariationChunkSize * kMaxReportedVariationChunks + 1;
 char g_variation_chunks[kMaxVariationChunksSize] = "";
 
-void SetActiveURL(const GURL& url) {
-  base::strlcpy(g_active_url, url.possibly_invalid_spec().c_str(),
-                arraysize(g_active_url));
-}
-
 void SetClientId(const std::string& client_id) {
   std::string str(client_id);
   ReplaceSubstringsAfterOffset(&str, 0, "-", std::string());
diff --git a/chrome/common/child_process_logging_win.cc b/chrome/common/child_process_logging_win.cc
index 672be22..8e6c9b5 100644
--- a/chrome/common/child_process_logging_win.cc
+++ b/chrome/common/child_process_logging_win.cc
@@ -12,18 +12,15 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/crash_keys.h"
 #include "chrome/common/metrics/variations/variations_util.h"
 #include "chrome/installer/util/google_update_settings.h"
 #include "gpu/config/gpu_info.h"
-#include "url/gurl.h"
 
 namespace child_process_logging {
 
 namespace {
 
-// exported in breakpad_win.cc: void __declspec(dllexport) __cdecl SetActiveURL.
-typedef void (__cdecl *MainSetActiveURL)(const wchar_t*);
-
 // exported in breakpad_win.cc: void __declspec(dllexport) __cdecl SetClientId.
 typedef void (__cdecl *MainSetClientId)(const wchar_t*);
 
@@ -56,6 +53,15 @@
 //   void __declspec(dllexport) __cdecl SetExperimentList3
 typedef void (__cdecl *MainSetExperimentList)(const wchar_t**, size_t, size_t);
 
+// exported in breakpad_win.cc:
+//    void __declspec(dllexport) __cdecl SetCrashKeyValueImpl.
+typedef void (__cdecl *SetCrashKeyValue)(const wchar_t*, const wchar_t*);
+
+// exported in breakpad_win.cc:
+//    void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl.
+typedef void (__cdecl *ClearCrashKeyValue)(const wchar_t*);
+
+
 // Copied from breakpad_win.cc.
 void StringVectorToCStringVector(const std::vector<std::wstring>& wstrings,
                                  std::vector<const wchar_t*>* cstrings) {
@@ -67,22 +73,6 @@
 
 }  // namespace
 
-void SetActiveURL(const GURL& url) {
-  static MainSetActiveURL set_active_url = NULL;
-  // note: benign race condition on set_active_url.
-  if (!set_active_url) {
-    HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
-    if (!exe_module)
-      return;
-    set_active_url = reinterpret_cast<MainSetActiveURL>(
-        GetProcAddress(exe_module, "SetActiveURL"));
-    if (!set_active_url)
-      return;
-  }
-
-  (set_active_url)(UTF8ToWide(url.possibly_invalid_spec()).c_str());
-}
-
 void SetClientId(const std::string& client_id) {
   std::string str(client_id);
   // Remove all instance of '-' char from the GUID. So BCD-WXY becomes BCDWXY.
@@ -256,4 +246,46 @@
   (set_number_of_views)(number_of_views);
 }
 
+namespace {
+
+void SetCrashKeyValueTrampoline(const base::StringPiece& key,
+                                const base::StringPiece& value) {
+  static SetCrashKeyValue set_crash_key = NULL;
+  if (!set_crash_key) {
+    HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
+    if (!exe_module)
+      return;
+    set_crash_key = reinterpret_cast<SetCrashKeyValue>(
+        GetProcAddress(exe_module, "SetCrashKeyValueImpl"));
+  }
+
+  if (set_crash_key)
+    (set_crash_key)(UTF8ToWide(key).data(), UTF8ToWide(value).data());
+}
+
+void ClearCrashKeyValueTrampoline(const base::StringPiece& key) {
+  static ClearCrashKeyValue clear_crash_key = NULL;
+  if (!clear_crash_key) {
+    HMODULE exe_module = GetModuleHandle(chrome::kBrowserProcessExecutableName);
+    if (!exe_module)
+      return;
+    clear_crash_key = reinterpret_cast<ClearCrashKeyValue>(
+        GetProcAddress(exe_module, "ClearCrashKeyValueImpl"));
+  }
+
+  if (clear_crash_key)
+    (clear_crash_key)(UTF8ToWide(key).data());
+}
+
+}  // namespace
+
+void Init() {
+  // Note: on other platforms, this is set up during Breakpad initialization,
+  // in ChromeBreakpadClient. But on Windows, that is before the DLL module is
+  // loaded, which is a prerequisite of the crash key system.
+  crash_keys::RegisterChromeCrashKeys();
+  base::debug::SetCrashKeyReportingFunctions(
+      &SetCrashKeyValueTrampoline, &ClearCrashKeyValueTrampoline);
+}
+
 }  // namespace child_process_logging
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 40621f8..3dd5bd3 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -247,6 +247,9 @@
 const wchar_t kMetroRegistryPath[] =
     L"Software\\" PRODUCT_STRING_PATH L"\\Metro";
 const wchar_t kLaunchModeValue[] = L"launch_mode";
+// This is used by breakpad and the metrics reporting.
+const wchar_t kBrowserCrashDumpAttemptsRegistryPath[] =
+    L"Software\\" PRODUCT_STRING_PATH L"\\BrowserCrashDumpAttempts";
 #endif
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index cd97f7c..1691e56 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -130,6 +130,11 @@
 // Used by Metro Chrome to store activation state.
 extern const wchar_t kMetroRegistryPath[];
 extern const wchar_t kLaunchModeValue[];
+// Used by the browser as a container in which to track unreported crash dump
+// attempts. The actual values (each representing one crash dump attempt) are
+// stored in a subkey named with the version number of the build. Each value
+// under the subkey represents an additional attempt.
+extern const wchar_t kBrowserCrashDumpAttemptsRegistryPath[];
 #endif
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 1eb9c10..cfaa40e 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/cpu.h"
+#include "base/debug/crash_logging.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
@@ -18,6 +19,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
+#include "chrome/common/crash_keys.h"
 #include "chrome/common/pepper_flash.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/url_constants.h"
@@ -170,7 +172,8 @@
                                                 kNaClPluginExtension,
                                                 kNaClPluginDescription);
       nacl.mime_types.push_back(nacl_mime_type);
-      if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePnacl)) {
+      if (!CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kDisablePnacl)) {
         content::WebPluginMimeType pnacl_mime_type(kPnaclPluginMimeType,
                                                    kPnaclPluginExtension,
                                                    kPnaclPluginDescription);
@@ -385,7 +388,8 @@
 namespace chrome {
 
 void ChromeContentClient::SetActiveURL(const GURL& url) {
-  child_process_logging::SetActiveURL(url);
+  base::debug::SetCrashKeyValue(crash_keys::kActiveURL,
+                                url.possibly_invalid_spec());
 }
 
 void ChromeContentClient::SetGpuInfo(const gpu::GPUInfo& gpu_info) {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index be999cf..b8d00b3 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -290,9 +290,6 @@
 // measurements.
 const char kDisableBackgroundNetworking[]   = "disable-background-networking";
 
-// Disables more strict popup blocking.
-const char kDisableBetterPopupBlocking[]    = "disable-better-popup-blocking";
-
 // Disables the bundled PPAPI version of Flash.
 const char kDisableBundledPpapiFlash[]      = "disable-bundled-ppapi-flash";
 
@@ -307,6 +304,9 @@
 const char kDisableClientSidePhishingDetection[] =
     "disable-client-side-phishing-detection";
 
+// Disables pushing cloud policy to Chrome using an invalidation service.
+const char kDisableCloudPolicyPush[]        = "disable-cloud-policy-push";
+
 const char kDisableComponentUpdate[]        = "disable-component-update";
 
 // Disables establishing certificate revocation information by downloading a
@@ -533,12 +533,13 @@
 // GAIA login page, an info bar can help the user login.
 const char kEnableAutologin[]               = "enable-autologin";
 
+// Enables running all beforeunload handlers before closing any browser windows
+// on shutdown.
+const char kEnableBatchedShutdown[]         = "enable-batched-shutdown";
+
 // Enables the benchmarking extensions.
 const char kEnableBenchmarking[]            = "enable-benchmarking";
 
-// Enables pushing cloud policy to Chrome using an invalidation service.
-const char kEnableCloudPolicyPush[]         = "enable-cloud-policy-push";
-
 // This applies only when the process type is "service". Enables the Cloud
 // Print Proxy component within the service process.
 const char kEnableCloudPrintProxy[]         = "enable-cloud-print-proxy";
@@ -654,8 +655,11 @@
 // account creation.
 const char kEnablePasswordGeneration[]      = "enable-password-generation";
 
-// Enables the usage of Portable Native Client.
-const char kEnablePnacl[]                   = "enable-pnacl";
+// Disables the usage of Portable Native Client.
+const char kDisablePnacl[]                  = "disable-pnacl";
+
+// Disables crash throttling for Portable Native Client.
+const char kDisablePnaclCrashThrottling[]   = "disable-pnacl-crash-throttling";
 
 // Disables the installation of Portable Native Client.
 const char kDisablePnaclInstall[]           = "disable-pnacl-install";
@@ -734,6 +738,9 @@
 // instant-extended-api, where thumbnails are generally smaller.
 const char kEnableThumbnailRetargeting[]   = "enable-thumbnail-retargeting";
 
+// Enables Translate experimental new UX which replaces the infobar.
+const char kEnableTranslateNewUX[]         = "enable-translate-new-ux";
+
 // Enables Translate settings in chrome://settings/languages.
 const char kEnableTranslateSettings[]      = "enable-translate-settings";
 
@@ -897,9 +904,6 @@
 // app/extension ID given, and then prompt the user to download and install it.
 const char kInstallFromWebstore[]           = "install-from-webstore";
 
-// Causes Chrome to load this URL instead of chrome://newtab for New Tab pages.
-const char kInstantNewTabURL[]              = "instant-new-tab-url";
-
 // Marks a renderer as an Instant process.
 const char kInstantProcess[]                = "instant-process";
 
@@ -1113,6 +1117,9 @@
 // Enable conversion from vector to raster for any page.
 const char kPrintRaster[]                   = "print-raster";
 
+// Use IPv6 only for privet HTTP.
+const char kPrivetIPv6Only[]                   = "privet-ipv6-only";
+
 // Outputs the product version information and quit. Used as an internal api to
 // detect the installed version of Chrome on Linux.
 const char kProductVersion[]                = "product-version";
@@ -1260,9 +1267,6 @@
 // See kHideIcons.
 const char kShowIcons[]                     = "show-icons";
 
-// If true the alignment of the shelf can be changed.
-const char kShowShelfAlignmentMenu[]        = "show-launcher-alignment-menu";
-
 // Marks a renderer as the signin process.
 const char kSigninProcess[]                 = "signin-process";
 
@@ -1483,6 +1487,10 @@
 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
 #if defined(OS_ANDROID)
+// Enable the accessibility tab switcher.
+const char kEnableAccessibilityTabSwitcher[] =
+    "enable-accessibility-tab-switcher";
+
 // Enables the new NTP.
 const char kEnableNewNTP[]                  = "enable-new-ntp";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 4f3cb57..32203e3 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -89,11 +89,11 @@
 extern const char kDisableAuthNegotiateCnameLookup[];
 extern const char kDisableBackgroundMode[];
 extern const char kDisableBackgroundNetworking[];
-extern const char kDisableBetterPopupBlocking[];
 extern const char kDisableBundledPpapiFlash[];
 extern const char kDisableBookmarkAutocompleteProvider[];
 extern const char kDisableClientSidePhishingDetection[];
 extern const char kDisableCloudPolicyOnSignin[];
+extern const char kDisableCloudPolicyPush[];
 extern const char kDisableComponentUpdate[];
 extern const char kDisableCRLSets[];
 extern const char kDisableCustomJumpList[];
@@ -113,6 +113,8 @@
 extern const char kDisableNTPOtherSessionsMenu[];
 extern const char kDisableOmniboxAutoCompletionForIme[];
 extern const char kDisablePasswordAutofillPublicSuffixDomainMatching[];
+extern const char kDisablePnacl[];
+extern const char kDisablePnaclCrashThrottling[];
 extern const char kDisablePnaclInstall[];
 extern const char kDisablePopupBlocking[];
 extern const char kDisablePreconnect[];
@@ -158,8 +160,8 @@
 extern const char kEnableAsyncDns[];
 extern const char kEnableAuthNegotiatePort[];
 extern const char kEnableAutologin[];
+extern const char kEnableBatchedShutdown[];
 extern const char kEnableBenchmarking[];
-extern const char kEnableCloudPolicyPush[];
 extern const char kEnableCloudPrintProxy[];
 extern const char kEnableComponentCloudPolicy[];
 extern const char kEnableContacts[];
@@ -189,7 +191,6 @@
 extern const char kEnablePanels[];
 extern const char kEnablePasswordAutofillPublicSuffixDomainMatching[];
 extern const char kEnablePasswordGeneration[];
-extern const char kEnablePnacl[];
 extern const char kEnableProfiling[];
 extern const char kEnableQuic[];
 extern const char kEnableQuicHttps[];
@@ -210,6 +211,7 @@
 extern const char kEnableSyncSyncedNotifications[];
 extern const char kEnableTabGroupsContextMenu[];
 extern const char kEnableThumbnailRetargeting[];
+extern const char kEnableTranslateNewUX[];
 extern const char kEnableTranslateSettings[];
 extern const char kEnableUnrestrictedSSL3Fallback[];
 extern const char kEnableUserAlternateProtocolPorts[];
@@ -248,7 +250,6 @@
 extern const char kIgnoreUrlFetcherCertRequests[];
 extern const char kIncognito[];
 extern const char kInstallFromWebstore[];
-extern const char kInstantNewTabURL[];
 extern const char kInstantProcess[];
 extern const char kKeepAliveForTest[];
 extern const char kKioskMode[];
@@ -303,6 +304,7 @@
 extern const char kPrerenderModeSwitchValueDisabled[];
 extern const char kPrerenderModeSwitchValueEnabled[];
 extern const char kPrerenderModeSwitchValuePrefetchOnly[];
+extern const char kPrivetIPv6Only[];
 extern const char kProductVersion[];
 extern const char kProfileDirectory[];
 extern const char kProfilingAtStart[];
@@ -339,7 +341,6 @@
 extern const char kSetToken[];
 extern const char kShowAppList[];
 extern const char kShowIcons[];
-extern const char kShowShelfAlignmentMenu[];
 extern const char kSigninProcess[];
 extern const char kSilentDumpOnDCHECK[];
 extern const char kSimulateUpgrade[];
@@ -405,6 +406,7 @@
 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
 #if defined(OS_ANDROID)
+extern const char kEnableAccessibilityTabSwitcher[];
 extern const char kEnableNewNTP[];
 extern const char kEnableTranslate[];
 extern const char kFakeCloudPolicyType[];
diff --git a/chrome/common/common_message_generator.h b/chrome/common/common_message_generator.h
index b1819fc..d355031 100644
--- a/chrome/common/common_message_generator.h
+++ b/chrome/common/common_message_generator.h
@@ -8,7 +8,6 @@
 #include "chrome/common/benchmarking_messages.h"
 #include "chrome/common/chrome_utility_messages.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/one_click_signin_messages.h"
 #include "chrome/common/prerender_messages.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
diff --git a/chrome/common/content_settings_types.h b/chrome/common/content_settings_types.h
index 081fde4..c1b03a5 100644
--- a/chrome/common/content_settings_types.h
+++ b/chrome/common/content_settings_types.h
@@ -29,6 +29,7 @@
   CONTENT_SETTINGS_TYPE_PPAPI_BROKER,
   CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
   CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
+  CONTENT_SETTINGS_TYPE_SAVE_PASSWORD,
 #if defined(OS_WIN)
   CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP,
 #endif
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 691e877..eae2403 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -45,8 +45,8 @@
 
 size_t RegisterChromeCrashKeys() {
   base::debug::CrashKey keys[] = {
-    // TODO(rsesek): Remove when done testing. Needed so arraysize > 0.
-    { "rsesek_key", kSmallSize },
+    { kActiveURL, kLargeSize },
+
     // content/:
     { "ppapi_path", kMediumSize },
     { "subresource_url", kLargeSize },
@@ -72,6 +72,8 @@
   return base::debug::InitCrashKeys(keys, arraysize(keys), kSingleChunkLength);
 }
 
+const char kActiveURL[] = "url-chunk";
+
 #if defined(OS_MACOSX)
 namespace mac {
 
diff --git a/chrome/common/crash_keys.h b/chrome/common/crash_keys.h
index 4111eb6..941a828 100644
--- a/chrome/common/crash_keys.h
+++ b/chrome/common/crash_keys.h
@@ -15,6 +15,9 @@
 
 // Crash Key Name Constants ////////////////////////////////////////////////////
 
+// The URL of the active tab.
+extern const char kActiveURL[];
+
 #if defined(OS_MACOSX)
 namespace mac {
 
diff --git a/chrome/common/descriptors_android.h b/chrome/common/descriptors_android.h
index 16886e9..f18a8c6 100644
--- a/chrome/common/descriptors_android.h
+++ b/chrome/common/descriptors_android.h
@@ -9,8 +9,7 @@
 
 enum {
 #if defined(OS_ANDROID)
-  kAndroidChromePakDescriptor = kContentIPCDescriptorMax + 1,
-  kAndroidLocalePakDescriptor,
+  kAndroidLocalePakDescriptor = kContentIPCDescriptorMax + 1,
   kAndroidChrome100PercentPakDescriptor,
   kAndroidUIResourcesPakDescriptor,
   kAndroidMinidumpDescriptor,
diff --git a/chrome/common/extensions/api/PRESUBMIT.py b/chrome/common/extensions/api/PRESUBMIT.py
new file mode 100644
index 0000000..20d61fa
--- /dev/null
+++ b/chrome/common/extensions/api/PRESUBMIT.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.
+
+def _GetJSONParseError(input_api, contents):
+  try:
+    json_comment_eater = input_api.os_path.join(
+        input_api.PresubmitLocalPath(),
+        '..', '..', '..', '..', 'tools',
+        'json_comment_eater', 'json_comment_eater.py')
+    process = input_api.subprocess.Popen(
+        [input_api.python_executable, json_comment_eater],
+        stdin=input_api.subprocess.PIPE,
+        stdout=input_api.subprocess.PIPE)
+    (nommed, _) = process.communicate(input=contents)
+    input_api.json.loads(nommed)
+  except ValueError as e:
+    return e
+  return None
+
+
+def _GetParseErrors(input_api, output_api):
+  # Run unit tests.
+  results = []
+  if input_api.AffectedFiles(
+      file_filter=lambda f: 'PRESUBMIT' in f.LocalPath()):
+    results = input_api.canned_checks.RunUnitTestsInDirectory(
+        input_api, output_api, '.', whitelist=[r'^PRESUBMIT_test\.py$'])
+
+  for affected_file in input_api.AffectedFiles(
+      file_filter=lambda f: f.LocalPath().endswith('.json'),
+      include_deletes=False):
+    filename = affected_file.AbsoluteLocalPath()
+    contents = input_api.ReadFile(filename)
+    parse_error = _GetJSONParseError(input_api, contents)
+    if parse_error:
+      results.append(output_api.PresubmitError(
+          'Features file %s could not be parsed: %s' %
+          (affected_file.LocalPath(), parse_error)))
+    # TODO(yoz): Also ensure IDL files are parseable.
+  return results
+
+
+def CheckChangeOnUpload(input_api, output_api):
+  return _GetParseErrors(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  return _GetParseErrors(input_api, output_api)
diff --git a/chrome/common/extensions/api/PRESUBMIT_test.py b/chrome/common/extensions/api/PRESUBMIT_test.py
new file mode 100755
index 0000000..f14ea7e
--- /dev/null
+++ b/chrome/common/extensions/api/PRESUBMIT_test.py
@@ -0,0 +1,62 @@
+#!/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 json
+import os
+import subprocess
+import sys
+import unittest
+
+import PRESUBMIT
+
+
+class MockInputApi(object):
+  def __init__(self):
+    self.json = json
+    self.os_path = os.path
+    self.subprocess = subprocess
+    self.python_executable = sys.executable
+
+  def PresubmitLocalPath(self):
+    return os.path.dirname(__file__)
+
+
+class JSONParsingTest(unittest.TestCase):
+  def testSuccess(self):
+    input_api = MockInputApi()
+    input_json = '''
+// This is a comment.
+{
+  "key1": ["value1", "value2"],
+  "key2": 3  // This is an inline comment.
+}
+'''
+    self.assertEqual(None,
+                     PRESUBMIT._GetJSONParseError(input_api, input_json))
+
+  def testFailure(self):
+    input_api = MockInputApi()
+    input_json = '{ x }'
+    self.assertEqual('Expecting property name: line 1 column 2 (char 2)',
+                     str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
+
+    input_json = '{ "hello": "world }'
+    self.assertEqual(
+        'Unterminated string starting at: line 1 column 11 (char 11)',
+        str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
+
+    input_json = '{ "a": "b", "c": "d", }'
+    self.assertEqual(
+        'Expecting property name: line 1 column 22 (char 22)',
+        str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
+
+    input_json = '{ "a": "b" "c": "d" }'
+    self.assertEqual(
+        'Expecting , delimiter: line 1 column 11 (char 11)',
+        str(PRESUBMIT._GetJSONParseError(input_api, input_json)))
+
+
+if __name__ == "__main__":
+  unittest.main()
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 3f1a46f..33e9c27 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -141,6 +141,10 @@
     "dependencies": ["permission:declarativeWebRequest"],
     "contexts": ["blessed_extension"]
   },
+  "desktopCapture": {
+    "dependencies": ["permission:desktopCapture"],
+    "contexts": ["blessed_extension"]
+  },
   "developerPrivate": {
     "dependencies": ["permission:developerPrivate"],
     "contexts": ["blessed_extension"]
@@ -209,10 +213,6 @@
     "dependencies": ["permission:experimental"],
     "contexts": ["blessed_extension"]
   },
-  "experimental.processes": {
-    "dependencies": ["permission:experimental"],
-    "contexts": ["blessed_extension"]
-  },
   "experimental.rlz": {
     "dependencies": ["permission:experimental"],
     "contexts": ["blessed_extension"]
@@ -327,6 +327,13 @@
     "channel": "stable",
     "extension_types": ["extension", "packaged_app", "platform_app"]
   },
+  // This is not a real API, only here for documentation purposes.
+  // See http://crbug.com/275944 for background.
+  "manifestTypes": {
+    "internal": true,
+    "channel": "stable",
+    "contexts": "all"
+  },
   "mediaGalleries": {
     "dependencies": ["permission:mediaGalleries"],
     "contexts": ["blessed_extension"]
@@ -391,6 +398,10 @@
     "dependencies": ["permission:privacy"],
     "contexts": ["blessed_extension"]
   },
+  "processes": {
+    "dependencies": ["permission:processes"],
+    "contexts": ["blessed_extension"]
+  },
   "proxy": {
     "dependencies": ["permission:proxy"],
     "contexts": ["blessed_extension"]
@@ -458,14 +469,19 @@
     "dependencies": ["permission:serial"],
     "contexts": ["blessed_extension"]
   },
-  "sessionRestore": {
-    "dependencies": ["permission:sessionRestore"],
+  "sessions": {
+    "dependencies": ["permission:sessions"],
     "contexts": ["blessed_extension"]
   },
   "socket": {
     "dependencies": ["permission:socket"],
     "contexts": ["blessed_extension"]
   },
+  "sockets.udp": {
+    "dependencies": ["permission:sockets.udp"],
+    "channel": "dev",
+    "contexts": ["blessed_extension"]
+  },
   "storage": {
     "dependencies": ["permission:storage"],
     "contexts": ["blessed_extension", "unblessed_extension", "content_script"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index fbaf434..a533a68 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -13,9 +13,9 @@
   },
   "activityLogPrivate": {
     "channel": "dev",
-    "extension_types": ["extension"],
+    "extension_types": ["extension", "platform_app"],
     "whitelist": [
-      "acldcpdepobcjbdanifkmfndkjoilgba",  // Activity Log
+      "acldcpdepobcjbdanifkmfndkjoilgba",  // Activity Log (Watchdog)
       "ajabfgledjhbabeoojlabelaifmakodf"   // For testing
     ]
   },
@@ -187,6 +187,17 @@
       "whitelist": ["heildphpnddilhkemkielfhnkaagiabh"]
     }
   ],
+  "desktopCapture": [
+    {
+      "channel": "dev",
+      "extension_types": ["extension", "platform_app"]
+    },
+    {
+      "channel": "stable",
+      "extension_types": ["extension", "platform_app"],
+      "whitelist": ["80B9DC58E5210749F052F5B4DB239C50CF72AEB6"]
+    }
+  ],
   "downloads": {
     "channel": "stable",
     "extension_types": ["extension"]
@@ -349,7 +360,8 @@
       "extension_types": ["platform_app"],
       "whitelist": [
           "gonnpeheodhmhdjiimoiheniambmdcco",  // Apps Editor old.
-          "cbelnpbjogfbjamhpbofhlnklecjpido"  // Apps Editor published.
+          "cbelnpbjogfbjamhpbofhlnklecjpido",  // Apps Editor published.
+          "acldcpdepobcjbdanifkmfndkjoilgba"   // Activity Log (Watchdog)
       ]
     }
   ],
@@ -377,7 +389,8 @@
       "dhgjflpimlbndbpamnkoepaacagejgda",
       "ebpbnabdhheoknfklmpddcdijjkmklkp",  // G+ Photos staging
       "efjnaogkjbogokcnohkmnjdojkikgobo",  // G+ Photos prod
-      "ejegoaikibpmikoejfephaneibodccma"   // G+ Photos dev
+      "ejegoaikibpmikoejfephaneibodccma",  // G+ Photos dev
+      "F7FA7ABC1ECB89BA8EE6656847EFABBF43BB9BCA"
     ]
   },
   "mediaPlayerPrivate": {
@@ -411,7 +424,8 @@
     "extension_types": ["platform_app"],
     "whitelist": [
       "4B1D0E19C6C43C008C44A8278C8B5BFE15ABEB3C", // Music Manager
-      "B8F61FD1B25DE03706DBB8906A73261E4DBB992A"  // Test
+      "B8F61FD1B25DE03706DBB8906A73261E4DBB992A", // Test
+      "F7FA7ABC1ECB89BA8EE6656847EFABBF43BB9BCA"
     ]
   },
   "nativeMessaging": {
@@ -480,6 +494,10 @@
     "channel": "stable",
     "extension_types": ["extension", "packaged_app"]
   },
+  "processes": {
+    "channel": "dev",
+    "extension_types": ["extension"]
+  },
   "proxy": {
     "channel": "stable",
     "extension_types": ["extension", "packaged_app"]
@@ -519,7 +537,7 @@
     "channel": "stable",
     "extension_types": ["platform_app"]
   },
-  "sessionRestore": {
+  "sessions": {
     "channel": "dev",
     "extension_types": ["extension", "packaged_app"]
   },
@@ -547,6 +565,10 @@
       "kodldpbjkkmmnilagfdheibampofhaom"
     ]
   }],
+  "sockets.udp": {
+    "channel": "dev",
+    "extension_types": ["platform_app"]
+  },
   "syncFileSystem": {
     "channel": "stable",
     "extension_types": ["platform_app"]
@@ -587,7 +609,7 @@
   },
   "tabCapture": [{
     "channel": "dev",
-    "extension_types": ["extension", "packaged_app", "platform_app"]
+    "extension_types": ["extension", "packaged_app"]
   }, {
     "channel": "stable",
     "extension_types": ["extension", "packaged_app"],
diff --git a/chrome/common/extensions/api/activity_log_private.json b/chrome/common/extensions/api/activity_log_private.json
index 72dbc46..3e915d8 100644
--- a/chrome/common/extensions/api/activity_log_private.json
+++ b/chrome/common/extensions/api/activity_log_private.json
@@ -8,75 +8,40 @@
     "description": "none",
     "types": [
       {
-        "id": "DomActivityDetail",
+        "id": "ExtensionActivity",
         "type": "object",
-        "description": "Stores the fields associated with an ActivityLog DomAction.",
+        "description": "This corresponds to a row from the ActivityLog database. Fields will be blank if they were specified precisely in a lookup filter.",
         "properties": {
-          "domActivityType": {"type": "string", "enum": ["getter", "setter", "method", "inserted", "xhr", "webrequest", "modified"], "optional": true},
-          "url": {"type": "string", "optional": true},
-          "urlTitle": {"type": "string", "optional": true},
+          "extensionId": {"type": "string", "optional": true},
+          "activityType": {"type": "string", "enum": ["api_call", "api_event", "content_script", "dom_access", "dom_event", "web_request"]},
+          "time": {"type": "number", "optional": true},
           "apiCall": {"type": "string", "optional": true},
           "args": {"type": "string", "optional": true},
-          "extra": {"type": "string", "optional": true}
-        }
-      },
-      {
-        "id": "ChromeActivityDetail",
-        "type": "object",
-        "description": "Stores the fields associated with an ActivityLog ApiAction.",
-        "properties": {
-          "apiActivityType": {"type": "string", "enum": ["call", "event_callback", "unknown_type"], "optional": true},
-          "apiCall": {"type": "string", "optional": true},
-          "args": {"type": "string", "optional": true},
-          "extra": {"type": "string", "optional": true}
-        }
-      },
-      {
-        "id": "BlockedChromeActivityDetail",
-        "type": "object",
-        "description": "Stores the fields associated with an ActivityLog BlockedAction.",
-        "properties": {
-          "apiCall": {"type": "string", "optional": true},
-          "args": {"type": "string", "optional": true},
-          "reason": {"type": "string", "enum": ["unknown_reason_type", "access_denied", "quota_exceeded"], "optional": true},
+          "count": {"type": "number", "optional": true},
+          "pageUrl": {"type": "string", "optional": true},
+          "pageTitle": {"type": "string", "optional": true},
+          "argUrl": {"type": "string", "optional": true},
           "extra": {"type": "string", "optional": true}
         }
       },
       {
         "id": "ActivityFilter",
         "type": "object",
-        "description": "The result set will be limited to rows that match the specification. All matches will be exact except for the URL field of domActivityDetail, which is considered a prefix.",
+        "description": "The result set will be limited to rows that match the specification. All matches will be exact except for URL fields, which are considered prefixes.",
         "properties": {
-          "extensionId": {"type": "string", "optional": true},
           "daysAgo": {"type": "string", "optional": true},
-          "activityType": {"type": "string", "enum": ["dom", "chrome", "blocked_chrome"], "optional": true},
-          "domActivityDetail": {"$ref": "DomActivityDetail", "optional": true},
-          "chromeActivityDetail": {"$ref": "ChromeActivityDetail", "optional": true},
-          "blockedChromeActivityDetail": {"$ref": "BlockedChromeActivityDetail", "optional": true}
-        }
-      },
-      {
-        "id": "ExtensionActivity",
-        "type": "object",
-        "description": "This corresponds to a row from the ActivityLog database. Fields will be blank if they were specified precisely in a lookup filter.",
-        "properties": {
-          "extensionId": {"type": "string", "optional": true},
-          "time": {"type": "number", "optional": true},
-          "count": {"type": "integer", "optional": true},
-          "activityType": {"type": "string", "enum": ["dom", "chrome", "blocked_chrome"], "optional": true},
-          "domActivityDetail": {"$ref": "DomActivityDetail", "optional": true},
-          "chromeActivityDetail": {"$ref": "ChromeActivityDetail", "optional": true},
-          "blockedChromeActivityDetail": {"$ref": "BlockedChromeActivityDetail", "optional": true}
+          "activityDetail": {"$ref": "ExtensionActivity", "optional": true}
         }
       },
       {
         "id": "ActivityResultSet",
         "type": "object",
-        "description": "This holds the results of a lookup, the filter of the lookup, and the page of the lookup if there is more than one page of results.",
+        "description": "This holds the results of a lookup, the filter of the lookup, the time of the lookup, and whether there are more results that match.",
         "properties": {
           "result": {"type": "array", "items": {"$ref": "ExtensionActivity"}},
           "filter": {"$ref": "ActivityFilter"},
-          "page": {"type": "integer", "optional": true}
+          "maxTime": {"type": "integer", "optional": true},
+          "moreResults": {"type": "boolean"}
         }
       }
     ],
@@ -91,10 +56,10 @@
             "$ref": "ActivityFilter"
           },
           {
-            "name": "page",
+            "name": "maxTime",
             "type": "integer",
             "optional": true,
-            "description": "Specify this if you want a specific page of results."
+            "description": "Specify this if you want results that weren't available in the first page."
           },
           {
             "name": "callback",
diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp
index 465021a..bb38061 100644
--- a/chrome/common/extensions/api/api.gyp
+++ b/chrome/common/extensions/api/api.gyp
@@ -39,6 +39,7 @@
           'cookies.json',
           'debugger.json',
           'developer_private.idl',
+          'desktop_capture.idl',
           'diagnostics.idl',
           'dial.idl',
           'downloads.idl',
@@ -86,8 +87,10 @@
           'rtc_private.idl',
           'runtime.json',
           'serial.idl',
-          'session_restore.json',
+          'sessions.json',
+          'signedin_devices.idl',
           'socket.idl',
+          'sockets_udp.idl',
           'storage.json',
           'sync_file_system.idl',
           'system_indicator.idl',
diff --git a/chrome/common/extensions/api/app_current_window_internal.idl b/chrome/common/extensions/api/app_current_window_internal.idl
index bf33d92..8ccc3b8 100644
--- a/chrome/common/extensions/api/app_current_window_internal.idl
+++ b/chrome/common/extensions/api/app_current_window_internal.idl
@@ -16,6 +16,16 @@
     long? height;
   };
 
+  dictionary RegionRect {
+    long left;
+    long top;
+    long width;
+    long height;
+  };
+
+  dictionary Region {
+    RegionRect[]? rects;
+  };
 
   interface Functions {
     static void focus();
@@ -29,6 +39,7 @@
     static void hide();
     static void setBounds(Bounds bounds);
     static void setIcon(DOMString icon_url);
+    static void setInputRegion(Region region);
   };
 
   interface Events {
diff --git a/chrome/common/extensions/api/audio.idl b/chrome/common/extensions/api/audio.idl
index ebf6585..0f08827 100644
--- a/chrome/common/extensions/api/audio.idl
+++ b/chrome/common/extensions/api/audio.idl
@@ -65,8 +65,6 @@
 
   interface Events {
     // Fired when anything changes to the audio device configuration.
-    // TODO(hshi): as suggested by mpcomplete this should pass down the same
-    // data as GetInfoCallback. Implement this once we have getInfo working.
     static void onDeviceChanged();
   };
 };
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index 45903d2..027268e 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -41,5 +41,8 @@
 
     // Get login status.
     static void loginStatus(LoginStatusCallback callback);
+
+    // Simulates a memory access bug for asan testing.
+    static void simulateAsanMemoryBug();
   };
 };
diff --git a/chrome/common/extensions/api/commands/commands_handler.cc b/chrome/common/extensions/api/commands/commands_handler.cc
index e36213c..51320e7 100644
--- a/chrome/common/extensions/api/commands/commands_handler.cc
+++ b/chrome/common/extensions/api/commands/commands_handler.cc
@@ -10,10 +10,10 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "extensions/common/error_utils.h"
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 namespace {
 // The maximum number of commands (including page action/browser actions) with a
 // keybinding an extension can have.
diff --git a/chrome/common/extensions/api/commands/commands_handler.h b/chrome/common/extensions/api/commands/commands_handler.h
index d38cc2b..54f2b7e 100644
--- a/chrome/common/extensions/api/commands/commands_handler.h
+++ b/chrome/common/extensions/api/commands/commands_handler.h
@@ -10,8 +10,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "chrome/common/extensions/command.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/api/desktop_capture.idl b/chrome/common/extensions/api/desktop_capture.idl
new file mode 100644
index 0000000..aa6f186
--- /dev/null
+++ b/chrome/common/extensions/api/desktop_capture.idl
@@ -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.
+
+// Desktop Capture API that can be used to capture content of screen or
+// individual windows or tabs.
+namespace desktopCapture {
+  // Enum used to define set of desktop media sources used in
+  // chooseDesktopMedia().
+  enum DesktopCaptureSourceType {
+    screen,
+    window,
+    tab
+  };
+
+  // |streamId|: An opaque string that can be passed to
+  // <code>getUserMedia()</code> API to generate media stream that corresponds
+  // to the source selected by the user. If user didn't select any source
+  // (i.e. canceled the prompt) then the callback is called with an empty
+  // <code>streamId</code>.
+  callback ChooseDesktopMediaCallback = void (DOMString streamId);
+
+  interface Functions {
+    // Shows desktop media picker UI with the specified set of sources.
+    //
+    // |sources|: Set of sources that should be shown to the user.
+    //
+    // |origin|: Optional origin of the page for which the stream is created. If
+    // not specified then the resulting stream can be used only the calling
+    // extension, otherwise the stream can be used only by a page with the
+    // specified origin.
+    static void chooseDesktopMedia(DesktopCaptureSourceType[] sources,
+                                   optional DOMString origin,
+                                   ChooseDesktopMediaCallback callback);
+  };
+};
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl
index cadfc0b..9329723 100644
--- a/chrome/common/extensions/api/developer_private.idl
+++ b/chrome/common/extensions/api/developer_private.idl
@@ -24,10 +24,10 @@
 
     long render_view_id;
     boolean incognito;
+    boolean generatedBackgroundPage;
   };
 
   dictionary InstallWarning {
-    boolean is_html;
     DOMString message;
   };
 
diff --git a/chrome/common/extensions/api/experimental_processes.json b/chrome/common/extensions/api/experimental_processes.json
deleted file mode 100644
index 9bb7633..0000000
--- a/chrome/common/extensions/api/experimental_processes.json
+++ /dev/null
@@ -1,263 +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.
-
-[
-  {
-    "namespace": "experimental.processes",
-    "description": "Use the <code>chrome.experimental.processes</code> API to interact with the browser's processes.",
-    "types": [
-      {
-        "id": "Process",
-        "type": "object",
-        "description": "An object containing information about one of the browser's processes.",
-        "properties": {
-          "id": {
-            "type": "integer",
-            "description": "Unique ID of the process provided by the browser."
-          },
-          "osProcessId": {
-            "type": "integer",
-            "description": "The ID of the process, as provided by the OS."
-          },
-          "type": {
-            "type": "string",
-            "enum": ["browser", "renderer", "extension", "notification", "plugin", "worker", "nacl", "utility", "gpu", "other"],
-            "description": "The type of process."
-          },
-          "profile": {
-            "type": "string",
-            "description": "The profile which the process is associated with."
-          },
-          "tabs": {
-            "type": "array",  "items": {"type": "integer", "minimum": 0},
-            "description": "Array of Tab IDs that have a page rendered by this process. The list will be non-empty for renderer processes only."
-          },
-          "cpu": {
-            "type": "number",
-            "optional": true,
-            "description": "The most recent measurement of the process CPU usage, between 0 and 100%. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "network": {
-            "type": "number",
-            "optional": true,
-            "description": "The most recent measurement of the process network usage, in bytes per second. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "privateMemory": {
-            "type": "number",
-            "optional": true,
-            "description": "The most recent measurement of the process private memory usage, in bytes. Only available when receiving the object as part of a callback from onUpdatedWithMemory or getProcessInfo with the includeMemory flag."
-          },
-          "jsMemoryAllocated": {
-            "type": "number",
-            "optional": true,
-            "description": "The most recent measurement of the process JavaScript allocated memory, in bytes. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "jsMemoryUsed": {
-            "type": "number",
-            "optional": true,
-            "description": "The most recent measurement of the process JavaScript memory used, in bytes. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "sqliteMemory": {
-            "type": "number",
-            "optional": true,
-            "description": "The most recent measurement of the process’s SQLite memory usage, in bytes. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "fps": {
-            "type": "number",
-            "optional": true,
-            "description": "The most recent measurement of the process frames per second. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "imageCache": {
-            "$ref": "Cache",
-            "optional": true,
-            "description": "The most recent information about the image cache for the process. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "scriptCache": {
-            "$ref": "Cache",
-            "optional": true,
-            "description": "The most recent information about the script cache for the process. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          },
-          "cssCache": {
-            "$ref": "Cache",
-            "optional": true,
-            "description": "The most recent information about the CSS cache for the process. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
-          }
-        }
-      },
-      {
-        "id": "Cache",
-        "type": "object",
-        "description": "The Cache object contains information about the size and utilization of a cache used by the browser.",
-        "properties": {
-          "size": {
-            "type": "number",
-            "description": "The size of the cache, in bytes."
-          },
-          "liveSize": {
-            "type": "number",
-            "description": "The part of the cache that is utilized, in bytes."
-          }
-        }
-      }
-    ],
-    "functions": [
-      {
-        "name": "terminate",
-        "type": "function",
-        "description": "Terminates the specified renderer process. Equivalent to visiting about:crash, but without changing the tab's URL.",
-        "parameters": [
-          {
-            "name": "processId",
-            "type": "integer",
-            "minimum": 0,
-            "description": "The ID of the process to be terminated."
-          },
-          {
-            "name": "callback",
-            "type": "function",
-            "optional": true,
-            "parameters": [
-              {
-                "name": "didTerminate",
-                "type": "boolean",
-                "description": "True if terminating the process was successful, otherwise false."
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "getProcessIdForTab",
-        "type": "function",
-        "description": "Returns the ID of the renderer process for the specified tab.",
-        "parameters": [
-          {
-            "name": "tabId",
-            "type": "integer",
-            "minimum": 0,
-            "description": "The ID of the tab for which the renderer process ID is to be returned."
-          },
-          {
-            "name": "callback",
-            "type": "function",
-            "parameters": [
-              {
-                "name": "processId",
-                "type": "integer",
-                "description": "Process ID of the tab's renderer process."
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "getProcessInfo",
-        "type": "function",
-        "description": "Retrieves the process information for each process ID specified.",
-        "parameters": [
-          {
-            "name": "processIds",
-            "choices": [
-              {"type": "integer", "minimum": 0},
-              {"type": "array", "items": {"type": "integer", "minimum": 0}}
-            ],
-            "description": "The list of process IDs or single process ID for which to return the process information. An empty list indicates all processes are requested."
-          },
-          {
-            "name": "includeMemory",
-            "type": "boolean",
-            "description": "True if detailed memory usage is required. Note, collecting memory usage information incurs extra CPU usage and should only be queried for when needed."
-          },
-          {
-            "name": "callback",
-            "type": "function",
-            "description": "Called when the processes information is collected.",
-            "parameters": [
-              {
-                "name": "processes",
-                "description": "A dictionary of Process objects for each requested process that is a live child process of the current browser process, indexed by process ID. Metrics requiring aggregation over time will not be populated in each Process object.",
-                "type": "object",
-                "additionalProperties": { "$ref": "Process" }
-              }
-            ]
-          }
-        ]
-      }
-    ],
-    "events": [
-      {
-        "name": "onUpdated",
-        "type": "function",
-        "description": "Fired each time the Task Manager updates its process statistics, providing the dictionary of updated Process objects, indexed by process ID.",
-        "parameters": [
-          {
-            "name": "processes",
-            "type": "object",
-            "description": "A dictionary of updated Process objects for each live process in the browser, indexed by process ID.  Metrics requiring aggregation over time will be populated in each Process object.",
-            "additionalProperties": { "$ref": "Process" }
-          }
-        ]
-      },
-      {
-        "name": "onUpdatedWithMemory",
-        "type": "function",
-        "description": "Fired each time the Task Manager updates its process statistics, providing the dictionary of updated Process objects, indexed by process ID. Identical to onUpdate, with the addition of memory usage details included in each Process object. Note, collecting memory usage information incurs extra CPU usage and should only be listened for when needed.",
-        "parameters": [
-          {
-            "name": "processes",
-            "type": "object",
-            "description": "A dictionary of updated Process objects for each live process in the browser, indexed by process ID.  Memory usage details will be included in each Process object.",
-            "additionalProperties": { "$ref": "Process" }
-          }
-        ]
-      },
-      {
-        "name": "onCreated",
-        "type": "function",
-        "description": "Fired each time a process is created, providing the corrseponding Process object.",
-        "parameters": [
-          {
-            "name": "process",
-            "description": "Details of the process that was created. Metrics requiring aggregation over time will not be populated in the object.",
-            "$ref": "Process"
-          }
-        ]
-      },
-      {
-        "name": "onUnresponsive",
-        "type": "function",
-        "description": "Fired each time a process becomes unresponsive, providing the corrseponding Process object.",
-        "parameters": [
-          {
-            "name": "process",
-            "description": "Details of the unresponsive process. Metrics requiring aggregation over time will not be populated in the object. Only available for renderer processes.",
-            "$ref": "Process"
-          }
-        ]
-      },
-      {
-        "name": "onExited",
-        "type": "function",
-        "description": "Fired each time a process is terminated, providing the type of exit.",
-        "parameters": [
-          {
-            "name": "processId",
-            "description": "The ID of the process that exited.",
-            "type": "integer"
-          },
-          {
-            "name": "exitType",
-            "description": "The type of exit that occurred for the process - normal, abnormal, killed, crashed. Only available for renderer processes.",
-            "type": "integer"
-          },
-          {
-            "name": "exitCode",
-            "description": "The exit code if the process exited abnormally. Only available for renderer processes.",
-            "type": "integer"
-          }
-        ]
-      }
-    ]
-  }
-]
diff --git a/chrome/common/extensions/api/extension_action/action_info.cc b/chrome/common/extensions/api/extension_action/action_info.cc
index 6d0ae6d..10e3385 100644
--- a/chrome/common/extensions/api/extension_action/action_info.cc
+++ b/chrome/common/extensions/api/extension_action/action_info.cc
@@ -13,7 +13,7 @@
 #include "extensions/common/error_utils.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/api/extension_action/browser_action_handler.cc b/chrome/common/extensions/api/extension_action/browser_action_handler.cc
index 0376745..41001cc 100644
--- a/chrome/common/extensions/api/extension_action/browser_action_handler.cc
+++ b/chrome/common/extensions/api/extension_action/browser_action_handler.cc
@@ -12,7 +12,7 @@
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/feature_switch.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 
 namespace extensions {
@@ -27,7 +27,7 @@
                                  string16* error) {
   const base::DictionaryValue* dict = NULL;
   if (!extension->manifest()->GetDictionary(
-          extension_manifest_keys::kBrowserAction, &dict)) {
+          manifest_keys::kBrowserAction, &dict)) {
     *error = ASCIIToUTF16(extension_manifest_errors::kInvalidBrowserAction);
     return false;
   }
@@ -58,7 +58,7 @@
 }
 
 const std::vector<std::string> BrowserActionHandler::Keys() const {
-  return SingleKey(extension_manifest_keys::kBrowserAction);
+  return SingleKey(manifest_keys::kBrowserAction);
 }
 
 }  // namespace extensions
diff --git a/chrome/common/extensions/api/extension_action/page_action_handler.cc b/chrome/common/extensions/api/extension_action/page_action_handler.cc
index f7b4b9c..7e1ddc5 100644
--- a/chrome/common/extensions/api/extension_action/page_action_handler.cc
+++ b/chrome/common/extensions/api/extension_action/page_action_handler.cc
@@ -12,7 +12,7 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "grit/generated_resources.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
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 15d61d8..ee770d9 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
@@ -10,7 +10,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/api/extension_action/script_badge_handler.cc b/chrome/common/extensions/api/extension_action/script_badge_handler.cc
index e58f89a..f42d266 100644
--- a/chrome/common/extensions/api/extension_action/script_badge_handler.cc
+++ b/chrome/common/extensions/api/extension_action/script_badge_handler.cc
@@ -11,12 +11,12 @@
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/feature_switch.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "extensions/common/install_warning.h"
+#include "extensions/common/manifest.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace extensions {
 
@@ -45,8 +45,7 @@
   // going to have any effect.
   if (!FeatureSwitch::script_badges()->IsEnabled()) {
     extension->AddInstallWarning(
-        InstallWarning(InstallWarning::FORMAT_TEXT,
-                       errors::kScriptBadgeRequiresFlag));
+        InstallWarning(errors::kScriptBadgeRequiresFlag, keys::kScriptBadge));
   }
 
   const base::DictionaryValue* dict = NULL;
@@ -68,14 +67,16 @@
 
   if (!action_info->default_title.empty()) {
     extension->AddInstallWarning(
-        InstallWarning(InstallWarning::FORMAT_TEXT,
-                       errors::kScriptBadgeTitleIgnored));
+        InstallWarning(errors::kScriptBadgeTitleIgnored,
+                       keys::kScriptBadge,
+                       keys::kPageActionDefaultTitle));
   }
 
   if (!action_info->default_icon.empty()) {
     extension->AddInstallWarning(
-        InstallWarning(InstallWarning::FORMAT_TEXT,
-                       errors::kScriptBadgeIconIgnored));
+        InstallWarning(errors::kScriptBadgeIconIgnored,
+                       keys::kScriptBadge,
+                       keys::kPageActionDefaultIcon));
   }
 
   SetActionInfoDefaults(extension, action_info.get());
diff --git a/chrome/common/extensions/api/extension_action/script_badge_manifest_unittest.cc b/chrome/common/extensions/api/extension_action/script_badge_manifest_unittest.cc
index e4258cc..0e233bb 100644
--- a/chrome/common/extensions/api/extension_action/script_badge_manifest_unittest.cc
+++ b/chrome/common/extensions/api/extension_action/script_badge_manifest_unittest.cc
@@ -10,6 +10,7 @@
 #include "chrome/common/extensions/feature_switch.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "extensions/common/install_warning.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -98,10 +99,10 @@
 
   EXPECT_THAT(StripMissingFlagWarning(extension->install_warnings()),
               testing::ElementsAre(
-                  InstallWarning(InstallWarning::FORMAT_TEXT,
-                                 errors::kScriptBadgeTitleIgnored),
-                  InstallWarning(InstallWarning::FORMAT_TEXT,
-                                 errors::kScriptBadgeIconIgnored)));
+                  InstallWarning(errors::kScriptBadgeTitleIgnored,
+                                 manifest_keys::kScriptBadge),
+                  InstallWarning(errors::kScriptBadgeIconIgnored,
+                                 manifest_keys::kScriptBadge)));
 
   const ExtensionIconSet& default_icon =
       script_badge_info->default_icon;
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index 0805b7e..92e30d3 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -18,9 +18,9 @@
 #include "base/values.h"
 #include "chrome/common/extensions/api/generated_schemas.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/features/feature.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 "grit/common_resources.h"
 #include "grit/extensions_api_resources.h"
@@ -243,8 +243,6 @@
       IDR_EXTENSION_API_JSON_DECLARATIVE_WEBREQUEST);
   RegisterSchemaResource("experimental.input.virtualKeyboard",
       IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD);
-  RegisterSchemaResource("experimental.processes",
-      IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES);
   RegisterSchemaResource("experimental.rlz",
       IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ);
   RegisterSchemaResource("runtime", IDR_EXTENSION_API_JSON_RUNTIME);
@@ -257,6 +255,7 @@
   RegisterSchemaResource("pageAction", IDR_EXTENSION_API_JSON_PAGEACTION);
   RegisterSchemaResource("pageActions", IDR_EXTENSION_API_JSON_PAGEACTIONS);
   RegisterSchemaResource("privacy", IDR_EXTENSION_API_JSON_PRIVACY);
+  RegisterSchemaResource("processes", IDR_EXTENSION_API_JSON_PROCESSES);
   RegisterSchemaResource("proxy", IDR_EXTENSION_API_JSON_PROXY);
   RegisterSchemaResource("scriptBadge", IDR_EXTENSION_API_JSON_SCRIPTBADGE);
   RegisterSchemaResource("streamsPrivate",
@@ -284,6 +283,7 @@
 }
 
 bool ExtensionAPI::IsAnyFeatureAvailableToContext(const std::string& api_name,
+                                                  const Extension* extension,
                                                   Feature::Context context,
                                                   const GURL& url) {
   FeatureProviderMap::iterator provider = dependency_providers_.find("api");
@@ -297,11 +297,11 @@
        i != features.end(); ++i) {
     const std::string& feature_name = *i;
     if (feature_name != api_name && feature_name.find(api_name + ".") == 0) {
-      if (IsAvailable(feature_name, NULL, context, url).is_available())
+      if (IsAvailable(feature_name, extension, context, url).is_available())
         return true;
     }
   }
-  return IsAvailable(api_name, NULL, context, url).is_available();
+  return IsAvailable(api_name, extension, context, url).is_available();
 }
 
 Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name,
diff --git a/chrome/common/extensions/api/extension_api.h b/chrome/common/extensions/api/extension_api.h
index e250419..ad8ae00 100644
--- a/chrome/common/extensions/api/extension_api.h
+++ b/chrome/common/extensions/api/extension_api.h
@@ -15,7 +15,7 @@
 #include "base/memory/singleton.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
-#include "chrome/common/extensions/features/feature.h"
+#include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
 #include "extensions/common/url_pattern_set.h"
 
@@ -77,6 +77,7 @@
   // Determines whether an API, or any parts of that API, are available in
   // |context|.
   bool IsAnyFeatureAvailableToContext(const std::string& api_name,
+                                      const Extension* extension,
                                       Feature::Context context,
                                       const GURL& url);
 
diff --git a/chrome/common/extensions/api/extension_api_stub.cc b/chrome/common/extensions/api/extension_api_stub.cc
index 7ec7b4e..add1f97 100644
--- a/chrome/common/extensions/api/extension_api_stub.cc
+++ b/chrome/common/extensions/api/extension_api_stub.cc
@@ -7,7 +7,7 @@
 
 #include "chrome/common/extensions/api/extension_api.h"
 
-#include "chrome/common/extensions/features/feature.h"
+#include "extensions/common/features/feature.h"
 
 namespace extensions {
 
@@ -30,6 +30,7 @@
 }
 
 bool ExtensionAPI::IsAnyFeatureAvailableToContext(const std::string& api_name,
+                                                  const Extension* extension,
                                                   Feature::Context context,
                                                   const GURL& url) {
   return false;
diff --git a/chrome/common/extensions/api/extension_api_unittest.cc b/chrome/common/extensions/api/extension_api_unittest.cc
index 89d6129..4feb34f 100644
--- a/chrome/common/extensions/api/extension_api_unittest.cc
+++ b/chrome/common/extensions/api/extension_api_unittest.cc
@@ -18,12 +18,14 @@
 #include "base/values.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/extension_builder.h"
 #include "chrome/common/extensions/extension_test_util.h"
 #include "chrome/common/extensions/features/api_feature.h"
 #include "chrome/common/extensions/features/base_feature_provider.h"
 #include "chrome/common/extensions/features/simple_feature.h"
-#include "chrome/common/extensions/manifest.h"
+#include "chrome/common/extensions/value_builder.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -251,24 +253,44 @@
 }
 
 TEST(ExtensionAPITest, IsAnyFeatureAvailableToContext) {
+  scoped_refptr<const Extension> app = ExtensionBuilder()
+    .SetManifest(DictionaryBuilder()
+      .Set("name", "app")
+      .Set("app", DictionaryBuilder()
+        .Set("background", DictionaryBuilder()
+          .Set("scripts", ListBuilder().Append("background.js"))))
+      .Set("version", "1")
+      .Set("manifest_version", 2)).Build();
+  scoped_refptr<const Extension> extension = ExtensionBuilder()
+    .SetManifest(DictionaryBuilder()
+      .Set("name", "extension")
+      .Set("version", "1")
+      .Set("manifest_version", 2)).Build();
+
   struct {
     std::string api_full_name;
     bool expect_is_available;
     Feature::Context context;
+    const Extension* extension;
     GURL url;
   } test_data[] = {
-    { "test1", false, Feature::WEB_PAGE_CONTEXT, GURL() },
-    { "test1", true, Feature::UNBLESSED_EXTENSION_CONTEXT, GURL() },
-    { "test2", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
-    { "test2", true, Feature::WEB_PAGE_CONTEXT, GURL("http://google.com") },
-    { "test2.foo", false, Feature::WEB_PAGE_CONTEXT,
+    { "test1", false, Feature::WEB_PAGE_CONTEXT, NULL, GURL() },
+    { "test1", true, Feature::UNBLESSED_EXTENSION_CONTEXT, NULL, GURL() },
+    { "test1", false, Feature::UNBLESSED_EXTENSION_CONTEXT, app.get(), GURL() },
+    { "test1", true, Feature::UNBLESSED_EXTENSION_CONTEXT, extension.get(),
+        GURL() },
+    { "test2", true, Feature::CONTENT_SCRIPT_CONTEXT, NULL, GURL() },
+    { "test2", true, Feature::WEB_PAGE_CONTEXT, NULL,
         GURL("http://google.com") },
-    { "test3", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
-    { "test3", true, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
-    { "test4.foo", true, Feature::CONTENT_SCRIPT_CONTEXT, GURL() },
-    { "test7", false, Feature::WEB_PAGE_CONTEXT, GURL("http://google.com") },
-    { "test7", true, Feature::WEB_PAGE_CONTEXT, GURL("http://foo.com") },
-    { "test7", false, Feature::WEB_PAGE_CONTEXT, GURL("http://bar.com") }
+    { "test2.foo", false, Feature::WEB_PAGE_CONTEXT, NULL,
+        GURL("http://google.com") },
+    { "test3", true, Feature::CONTENT_SCRIPT_CONTEXT, NULL, GURL() },
+    { "test3", true, Feature::WEB_PAGE_CONTEXT, NULL, GURL("http://foo.com") },
+    { "test4.foo", true, Feature::CONTENT_SCRIPT_CONTEXT, NULL, GURL() },
+    { "test7", false, Feature::WEB_PAGE_CONTEXT, NULL,
+        GURL("http://google.com") },
+    { "test7", true, Feature::WEB_PAGE_CONTEXT, NULL, GURL("http://foo.com") },
+    { "test7", false, Feature::WEB_PAGE_CONTEXT, NULL, GURL("http://bar.com") }
   };
 
   base::FilePath api_features_path;
@@ -296,6 +318,7 @@
 
     EXPECT_EQ(test_data[i].expect_is_available,
               api.IsAnyFeatureAvailableToContext(test_data[i].api_full_name,
+                                                 test_data[i].extension,
                                                  test_data[i].context,
                                                  test_data[i].url)) << i;
   }
@@ -371,71 +394,84 @@
   // scripts.
   EXPECT_FALSE(extension_api->IsAnyFeatureAvailableToContext(
       "runtime.getBackgroundPage",
+      NULL,
       Feature::CONTENT_SCRIPT_CONTEXT,
       GURL()));
   EXPECT_FALSE(extension_api->IsAnyFeatureAvailableToContext(
       "runtime.sendNativeMessage",
+      NULL,
       Feature::CONTENT_SCRIPT_CONTEXT,
       GURL()));
   // "runtime" also has unprivileged parts.
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "runtime.sendMessage",
+      NULL,
       Feature::CONTENT_SCRIPT_CONTEXT,
       GURL()));
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "runtime.id",
+      NULL,
       Feature::CONTENT_SCRIPT_CONTEXT,
       GURL()));
 
   // "storage" is completely unprivileged.
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "storage",
+      NULL,
       Feature::BLESSED_EXTENSION_CONTEXT,
       GURL()));
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "storage",
+      NULL,
       Feature::UNBLESSED_EXTENSION_CONTEXT,
       GURL()));
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "storage",
+      NULL,
       Feature::CONTENT_SCRIPT_CONTEXT,
       GURL()));
 
   // "extension" is partially unprivileged.
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "extension",
+      NULL,
       Feature::BLESSED_EXTENSION_CONTEXT,
       GURL()));
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "extension",
+      NULL,
       Feature::UNBLESSED_EXTENSION_CONTEXT,
       GURL()));
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "extension",
+      NULL,
       Feature::CONTENT_SCRIPT_CONTEXT,
       GURL()));
 
   // "history" is entirely privileged.
   EXPECT_TRUE(extension_api->IsAnyFeatureAvailableToContext(
       "history",
+      NULL,
       Feature::BLESSED_EXTENSION_CONTEXT,
       GURL()));
   EXPECT_FALSE(extension_api->IsAnyFeatureAvailableToContext(
       "history",
+      NULL,
       Feature::UNBLESSED_EXTENSION_CONTEXT,
       GURL()));
   EXPECT_FALSE(extension_api->IsAnyFeatureAvailableToContext(
       "history",
+      NULL,
       Feature::CONTENT_SCRIPT_CONTEXT,
       GURL()));
 }
 
 scoped_refptr<Extension> CreateHostedApp() {
   base::DictionaryValue values;
-  values.SetString(extension_manifest_keys::kName, "test");
-  values.SetString(extension_manifest_keys::kVersion, "0.1");
-  values.Set(extension_manifest_keys::kWebURLs, new base::ListValue());
-  values.SetString(extension_manifest_keys::kLaunchWebURL,
+  values.SetString(manifest_keys::kName, "test");
+  values.SetString(manifest_keys::kVersion, "0.1");
+  values.Set(manifest_keys::kWebURLs, new base::ListValue());
+  values.SetString(manifest_keys::kLaunchWebURL,
                    "http://www.example.com");
   std::string error;
   scoped_refptr<Extension> extension(Extension::Create(
@@ -448,9 +484,9 @@
 scoped_refptr<Extension> CreatePackagedAppWithPermissions(
     const std::set<std::string>& permissions) {
   base::DictionaryValue values;
-  values.SetString(extension_manifest_keys::kName, "test");
-  values.SetString(extension_manifest_keys::kVersion, "0.1");
-  values.SetString(extension_manifest_keys::kPlatformAppBackground,
+  values.SetString(manifest_keys::kName, "test");
+  values.SetString(manifest_keys::kVersion, "0.1");
+  values.SetString(manifest_keys::kPlatformAppBackground,
       "http://www.example.com");
 
   base::DictionaryValue* app = new base::DictionaryValue();
@@ -459,7 +495,7 @@
   scripts->Append(new base::StringValue("test.js"));
   background->Set("scripts", scripts);
   app->Set("background", background);
-  values.Set(extension_manifest_keys::kApp, app);
+  values.Set(manifest_keys::kApp, app);
   {
     scoped_ptr<base::ListValue> permissions_list(new base::ListValue());
     for (std::set<std::string>::const_iterator i = permissions.begin();
@@ -812,7 +848,7 @@
     { "history",        false },
     // Make sure we find the module name after stripping '.'
     { "runtime.abcd.onStartup",  true },
-    // Test Tabs functions.
+    // Test Tabs/Windows functions.
     { "tabs.create",      true },
     { "tabs.duplicate",   true },
     { "tabs.onRemoved",   true },
@@ -820,6 +856,10 @@
     { "tabs.update",      true },
     { "tabs.getSelected", true },
     { "tabs.onUpdated",   true },
+    { "windows.get",      true },
+    { "windows.create",   true },
+    { "windows.remove",   true },
+    { "windows.update",   true },
     // Test some whitelisted functions. These require no permissions.
     { "app.getDetails",           true },
     { "app.getDetailsForFrame",   true },
diff --git a/chrome/common/extensions/api/feedback_private.idl b/chrome/common/extensions/api/feedback_private.idl
index 5d9116c..42ac6e7 100644
--- a/chrome/common/extensions/api/feedback_private.idl
+++ b/chrome/common/extensions/api/feedback_private.idl
@@ -68,6 +68,11 @@
     // Sends a feedback report.
     static void sendFeedback(FeedbackInfo feedback,
                              SendFeedbackCallback callback);
+
+    // Gets localized translated strings for feedback. It returns the
+    // strings as a dictionary mapping from string identifier to the
+    // translated string to use in the feedback app UI.
+    static void getStrings(GetStringsCallback callback);
   };
 
   interface Events {
diff --git a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
index 07c0e60..dae1c93 100644
--- a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
+++ b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
@@ -11,12 +11,12 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/url_pattern.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/api/file_handlers/file_handlers_parser.cc b/chrome/common/extensions/api/file_handlers/file_handlers_parser.cc
index 78469f6..ce6ed1d 100644
--- a/chrome/common/extensions/api/file_handlers/file_handlers_parser.cc
+++ b/chrome/common/extensions/api/file_handlers/file_handlers_parser.cc
@@ -9,10 +9,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
+namespace errors = extension_manifest_errors;
 
 namespace extensions {
 
@@ -26,7 +27,7 @@
 const std::vector<FileHandlerInfo>* FileHandlers::GetFileHandlers(
     const Extension* extension) {
   FileHandlers* info = static_cast<FileHandlers*>(
-      extension->GetManifestData(extension_manifest_keys::kFileHandlers));
+      extension->GetManifestData(keys::kFileHandlers));
   return info ? &info->file_handlers : NULL;
 }
 
@@ -49,7 +50,7 @@
   if (handler_info.HasKey(keys::kFileHandlerTypes) &&
       !handler_info.GetList(keys::kFileHandlerTypes, &mime_types)) {
     *error = ErrorUtils::FormatErrorMessageUTF16(
-        extension_manifest_errors::kInvalidFileHandlerType, handler_id);
+        errors::kInvalidFileHandlerType, handler_id);
     return false;
   }
 
@@ -57,21 +58,21 @@
   if (handler_info.HasKey(keys::kFileHandlerExtensions) &&
       !handler_info.GetList(keys::kFileHandlerExtensions, &file_extensions)) {
     *error = ErrorUtils::FormatErrorMessageUTF16(
-        extension_manifest_errors::kInvalidFileHandlerExtension, handler_id);
+        errors::kInvalidFileHandlerExtension, handler_id);
     return false;
   }
 
   if ((!mime_types || mime_types->GetSize() == 0) &&
       (!file_extensions || file_extensions->GetSize() == 0)) {
     *error = ErrorUtils::FormatErrorMessageUTF16(
-        extension_manifest_errors::kInvalidFileHandlerNoTypeOrExtension,
+        errors::kInvalidFileHandlerNoTypeOrExtension,
         handler_id);
     return false;
   }
 
   if (handler_info.HasKey(keys::kFileHandlerTitle) &&
       !handler_info.GetString(keys::kFileHandlerTitle, &handler.title)) {
-    *error = ASCIIToUTF16(extension_manifest_errors::kInvalidFileHandlerTitle);
+    *error = ASCIIToUTF16(errors::kInvalidFileHandlerTitle);
     return false;
   }
 
@@ -80,7 +81,7 @@
     for (size_t i = 0; i < mime_types->GetSize(); ++i) {
       if (!mime_types->GetString(i, &type)) {
         *error = ErrorUtils::FormatErrorMessageUTF16(
-            extension_manifest_errors::kInvalidFileHandlerTypeElement,
+            errors::kInvalidFileHandlerTypeElement,
             handler_id,
             std::string(base::IntToString(i)));
         return false;
@@ -94,7 +95,7 @@
     for (size_t i = 0; i < file_extensions->GetSize(); ++i) {
       if (!file_extensions->GetString(i, &file_extension)) {
         *error = ErrorUtils::FormatErrorMessageUTF16(
-            extension_manifest_errors::kInvalidFileHandlerExtensionElement,
+            errors::kInvalidFileHandlerExtensionElement,
             handler_id,
             std::string(base::IntToString(i)));
         return false;
@@ -112,7 +113,7 @@
   const base::DictionaryValue* all_handlers = NULL;
   if (!extension->manifest()->GetDictionary(keys::kFileHandlers,
                                             &all_handlers)) {
-    *error = ASCIIToUTF16(extension_manifest_errors::kInvalidFileHandlers);
+    *error = ASCIIToUTF16(errors::kInvalidFileHandlers);
     return false;
   }
 
@@ -126,7 +127,7 @@
       if (!LoadFileHandler(iter.key(), *handler, &info->file_handlers, error))
         return false;
     } else {
-      *error = ASCIIToUTF16(extension_manifest_errors::kInvalidFileHandlers);
+      *error = ASCIIToUTF16(errors::kInvalidFileHandlers);
       return false;
     }
   }
diff --git a/chrome/common/extensions/api/file_system.idl b/chrome/common/extensions/api/file_system.idl
index 07914a6..50f099c 100644
--- a/chrome/common/extensions/api/file_system.idl
+++ b/chrome/common/extensions/api/file_system.idl
@@ -91,19 +91,21 @@
                             FileEntriesCallback callback);
 
     // Returns the file entry with the given id if it can be restored. This call
-    // will fail otherwise.
+    // will fail otherwise. This method is new in Chrome 30.
     static void restoreEntry(DOMString id, FileEntryCallback callback);
 
     // Returns whether a file entry for the given id can be restored, i.e.
-    // whether restoreEntry would succeed with this id now.
+    // whether restoreEntry would succeed with this id now. This method is new
+    // in Chrome 30.
     static void isRestorable(DOMString id, IsRestorableCallback callback);
 
     // Returns an id that can be passed to restoreEntry to regain access to a
     // given file entry. Only the 500 most recently used entries are retained,
     // where calls to retainEntry and restoreEntry count as use. If the app has
-    // the 'retainEntries' permission under 'fileSystem', entries are retained
-    // indefinitely. Otherwise, entries are retained only while the app is
-    // running and across restarts.
+    // the 'retainEntries' permission under 'fileSystem' (currently restricted
+    // to dev channel), entries are retained indefinitely. Otherwise, entries
+    // are retained only while the app is running and across restarts. This
+    // method is new in Chrome 30.
     static DOMString retainEntry([instanceOf=FileEntry] object fileEntry);
   };
 };
diff --git a/chrome/common/extensions/api/i18n/default_locale_handler.cc b/chrome/common/extensions/api/i18n/default_locale_handler.cc
index 363128f..eb7a78d 100644
--- a/chrome/common/extensions/api/i18n/default_locale_handler.cc
+++ b/chrome/common/extensions/api/i18n/default_locale_handler.cc
@@ -13,12 +13,12 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
diff --git a/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc b/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc
index e4403b0..1f5be34 100644
--- a/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc
+++ b/chrome/common/extensions/api/identity/extension_manifests_auth_unittest.cc
@@ -8,7 +8,7 @@
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc b/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc
index 67df919..2697528 100644
--- a/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc
+++ b/chrome/common/extensions/api/identity/oauth2_manifest_handler.cc
@@ -11,7 +11,7 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "extensions/common/error_utils.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/api/input_ime/input_components_handler.cc b/chrome/common/extensions/api/input_ime/input_components_handler.cc
index e25112b..0681647 100644
--- a/chrome/common/extensions/api/input_ime/input_components_handler.cc
+++ b/chrome/common/extensions/api/input_ime/input_components_handler.cc
@@ -11,11 +11,11 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
diff --git a/chrome/common/extensions/api/log_private.idl b/chrome/common/extensions/api/log_private.idl
index 2194357..31a22ec 100644
--- a/chrome/common/extensions/api/log_private.idl
+++ b/chrome/common/extensions/api/log_private.idl
@@ -18,6 +18,8 @@
     DOMString[] process;
     //  Only logs have level in |level| will be returned.
     DOMString[] level;
+    // Private information will be scrubbed if |scrub| is true.
+    boolean scrub;
   };
 
   // The class that contains log information.
diff --git a/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.cc b/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.cc
index 56e6c10..1935b29 100644
--- a/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.cc
+++ b/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.cc
@@ -11,10 +11,10 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "extensions/common/error_utils.h"
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 ManagedModeInfo::ManagedModeInfo() {
 }
 
diff --git a/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.h b/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.h
index 99b1ea6..5e825da 100644
--- a/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.h
+++ b/chrome/common/extensions/api/managed_mode_private/managed_mode_handler.h
@@ -10,9 +10,9 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/api/manifest_types.json b/chrome/common/extensions/api/manifest_types.json
index d7e8494..e14ed37 100644
--- a/chrome/common/extensions/api/manifest_types.json
+++ b/chrome/common/extensions/api/manifest_types.json
@@ -3,26 +3,30 @@
 // found in the LICENSE file.
 
 // The type schemas for structured manifest items. Not actually a callable API.
-// TODO(kalman): Expose these in the docs somewhere.
 
 [
   {
     "namespace": "manifestTypes",
     "description": "Schemas for structured manifest entries",
+    "compiler_options": {
+      "generate_error_messages": true
+    },
     "types": [
       {
         "id": "ExternallyConnectable",
         "type": "object",
-        "description": "The schema of the <code>externally_connectable</code> manifest property",
+        // Note: description commented out because externally_connectable.html
+        // already describes it, and the repetition looks odd.
+        // "description": "The <code>externally_connectable</code> manifest property declares which extensions, apps, and web pages can connect to your extension via $ref:runtime.connect and $ref:runtime.sendMessage.",
         "properties": {
-          "matches": {
-            "description": "<p>The URL patterns for web pages that are allowed to connect. If left empty or unspecified, no web pages can connect.</p><p>Patterns cannot include wildcard domains nor subdomains of (effective) top level domains; <code>*://google.com/*</code> and <code>http://*.chromium.org/*</code> are valid, while <code>&lt;all_urls&gt;</code>, <code>http://*/*</code>, <code>*://*.com/*</code>, and even <code>http://*.appspot.com/*</code> are not.</p>",
+          "ids": {
+            "description": "<p>The IDs of extensions or apps that are allowed to connect. If left empty or unspecified, no extensions or apps can connect.</p><p>The wildcard <code>\"*\"</code> will allow all extensions and apps to connect.</p>",
             "optional": true,
             "type": "array",
             "items": {"type": "string"}
           },
-          "ids": {
-            "description": "The IDs of extensions or apps that are allowed to connect. If left empty or unspecified, no extensions nor apps can connect. <code>*</code> will match all extension and app IDs.",
+          "matches": {
+            "description": "<p>The URL patterns for <em>web pages</em> that are allowed to connect. <em>This does not affect content scripts.</em> If left empty or unspecified, no web pages can connect.</p><p>Patterns cannot include wildcard domains nor subdomains of (effective) top level domains; <code>*://google.com/*</code> and <code>http://*.chromium.org/*</code> are valid, while <code>&lt;all_urls&gt;</code>, <code>http://*/*</code>, <code>*://*.com/*</code>, and even <code>http://*.appspot.com/*</code> are not.</p>",
             "optional": true,
             "type": "array",
             "items": {"type": "string"}
diff --git a/chrome/common/extensions/api/media_galleries_private.idl b/chrome/common/extensions/api/media_galleries_private.idl
index 5f40bf7..e04df52 100644
--- a/chrome/common/extensions/api/media_galleries_private.idl
+++ b/chrome/common/extensions/api/media_galleries_private.idl
@@ -47,24 +47,6 @@
   callback AddGalleryWatchCallback = void (AddGalleryWatchResult result);
   callback GetAllGalleryWatchCallback = void (DOMString[] galleryIds);
 
-  // These enum bits have moved to experimental.systemInfo.storage namespace.
-  // See experimental_system_info_storage.idl.
-  [inline_doc] enum EjectDeviceResultCode {
-    // The ejection command is successful -- the application can prompt the user
-    // to remove the device.
-    success,
-    // The device is in use by another application. The ejection did not
-    // succeed; the user should not remove the device until the other
-    // application is done with the device.
-    in_use,
-    // There is no such device known.
-    no_such_device,
-    // The ejection command failed.
-    failure
-  };
-
-  callback EjectDeviceCallback = void (EjectDeviceResultCode result);
-
   // A dictionary that describes a media galleries handler.
   [inline_doc] dictionary MediaGalleriesHandler {
     // Unique action id per extension.
@@ -88,9 +70,6 @@
     static void removeGalleryWatch(DOMString galleryId);
     static void getAllGalleryWatch(GetAllGalleryWatchCallback callback);
     static void removeAllGalleryWatch();
-    // The function has moved to system.storage namespace.
-    // See system_storage.idl.
-    static void ejectDevice(DOMString deviceId, EjectDeviceCallback callback);
     static void getHandlers(GetHandlersCallback callback);
   };
 };
diff --git a/chrome/common/extensions/api/media_galleries_private/media_galleries_handler.cc b/chrome/common/extensions/api/media_galleries_private/media_galleries_handler.cc
index f5231d3..b40becf 100644
--- a/chrome/common/extensions/api/media_galleries_private/media_galleries_handler.cc
+++ b/chrome/common/extensions/api/media_galleries_private/media_galleries_handler.cc
@@ -11,10 +11,10 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/api/media_player_private.json b/chrome/common/extensions/api/media_player_private.json
index da31398..45bf73c 100644
--- a/chrome/common/extensions/api/media_player_private.json
+++ b/chrome/common/extensions/api/media_player_private.json
@@ -10,93 +10,14 @@
     },
     "description": "none",
     "platforms": ["chromeos"],
-    "types": [
-      {
-        "id": "Playlist",
-        "type": "object",
-        "description": "Mediaplayer playlist stored in the browser (it exists even if the mediaplayer is closed).",
-        "properties": {
-          "items": {
-            "name": "items",
-            "type": "array",
-            "description": "Array of URLs for media files (in 'filesystem:' scheme for local files)",
-            "items": { "type": "string" }
-          },
-          "position": {
-            "type": "integer",
-            "description": "A position in the playlist."
-          }
-        }
-      }
-    ],
-    "functions": [
-      {
-        "name": "play",
-        "description": "Plays a new playlist from a given position.",
-        "parameters": [
-          {
-            "name": "items",
-            "type": "array",
-            "description": "Array of URLs for media files (in 'filesystem:' scheme for local files)",
-            "items": { "type": "string" }
-          },
-          {
-            "name": "position",
-            "type": "integer",
-            "description": "A position in the playlist."
-          }
-        ]
-      },
-      {
-        "name": "getPlaylist",
-        "type": "function",
-        "description": "Returns current playlist and position.",
-        "parameters": [
-          {
-            "name": "callback",
-            "type": "function",
-            "description": "Callback to retrieve the playlist.",
-            "parameters": [
-              {
-                "name": "playlist",
-                "$ref": "Playlist",
-                "description": "Mediaplayer playlist stored in the browser (it extsts even if the mediaplayer is closed)."
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "setWindowHeight",
-        "description": "Changes the height of the media player window.",
-        "parameters": [
-          {
-            "name": "height",
-            "type": "integer",
-            "description": "Height of the media player window (not including window title or borders)."
-          }
-        ]
-      },
-      {
-        "name": "closeWindow",
-        "description": "Closes the media player window.",
-        "parameters": []
-      }
-    ],
-    "events": [
+   "events": [
       {
         "name": "onNextTrack",
         "type": "function",
         "description": "Notifies that the next track was requested.",
         "parameters": []
       },
-      {
-        "name": "onPlaylistChanged",
-        "type": "function",
-        "description": "Notifies that playlist content or state has been changed. Data could be retrieved via 'getPlaylist'.",
-        "parameters": []
-      },
-      {
+     {
         "name": "onPrevTrack",
         "type": "function",
         "description": "Notifies that the previous tack was requested.",
diff --git a/chrome/common/extensions/api/omnibox/omnibox_handler.cc b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
index 7b95ac2..10bfd4f 100644
--- a/chrome/common/extensions/api/omnibox/omnibox_handler.cc
+++ b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
@@ -10,7 +10,7 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
@@ -24,7 +24,7 @@
 // static
 const std::string& OmniboxInfo::GetKeyword(const Extension* extension) {
   OmniboxInfo* info = static_cast<OmniboxInfo*>(
-      extension->GetManifestData(extension_manifest_keys::kOmnibox));
+      extension->GetManifestData(manifest_keys::kOmnibox));
   return info ? info->keyword : EmptyString();
 }
 
@@ -37,19 +37,19 @@
 bool OmniboxHandler::Parse(Extension* extension, string16* error) {
   scoped_ptr<OmniboxInfo> info(new OmniboxInfo);
   const base::DictionaryValue* dict = NULL;
-  if (!extension->manifest()->GetDictionary(extension_manifest_keys::kOmnibox,
+  if (!extension->manifest()->GetDictionary(manifest_keys::kOmnibox,
                                             &dict) ||
       !dict->GetString(kKeyword, &info->keyword) ||
       info->keyword.empty()) {
     *error = ASCIIToUTF16(extension_manifest_errors::kInvalidOmniboxKeyword);
     return false;
   }
-  extension->SetManifestData(extension_manifest_keys::kOmnibox, info.release());
+  extension->SetManifestData(manifest_keys::kOmnibox, info.release());
   return true;
 }
 
 const std::vector<std::string> OmniboxHandler::Keys() const {
-  return SingleKey(extension_manifest_keys::kOmnibox);
+  return SingleKey(manifest_keys::kOmnibox);
 }
 
 }  // namespace extensions
diff --git a/chrome/common/extensions/api/permissions.json b/chrome/common/extensions/api/permissions.json
index f6a03b7..3ce74b4 100644
--- a/chrome/common/extensions/api/permissions.json
+++ b/chrome/common/extensions/api/permissions.json
@@ -5,7 +5,7 @@
 [
   {
     "namespace": "permissions",
-    "description": "Use the <code>chrome.permissions</code> API to implement optional permissions. As of Chrome 16, you can request optional permissions during your extension's regular application flow rather than at install time, so users understand why the permissions are needed and use only those that are necessary.",
+    "description": "Use the <code>chrome.permissions</code> API to request <a href=\"#manifest\">declared optional permissions</a> at run time rather than install time, so users understand why the permissions are needed and grant only those that are necessary.",
     "types": [
       {
         "id": "Permissions",
diff --git a/chrome/common/extensions/api/plugins/plugins_handler.cc b/chrome/common/extensions/api/plugins/plugins_handler.cc
index d8decf6..5baa0df 100644
--- a/chrome/common/extensions/api/plugins/plugins_handler.cc
+++ b/chrome/common/extensions/api/plugins/plugins_handler.cc
@@ -9,11 +9,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
 #include "chrome/common/extensions/permissions/api_permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -21,10 +21,10 @@
 #include "base/win/metro.h"
 #endif
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 namespace {
 
 struct PluginManifestData : Extension::ManifestData {
diff --git a/chrome/common/extensions/api/processes.json b/chrome/common/extensions/api/processes.json
new file mode 100644
index 0000000..77b1ad7
--- /dev/null
+++ b/chrome/common/extensions/api/processes.json
@@ -0,0 +1,263 @@
+// Copyright 2013 The Chromium 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": "processes",
+    "description": "Use the <code>chrome.processes</code> API to interact with the browser's processes.",
+    "types": [
+      {
+        "id": "Process",
+        "type": "object",
+        "description": "An object containing information about one of the browser's processes.",
+        "properties": {
+          "id": {
+            "type": "integer",
+            "description": "Unique ID of the process provided by the browser."
+          },
+          "osProcessId": {
+            "type": "integer",
+            "description": "The ID of the process, as provided by the OS."
+          },
+          "type": {
+            "type": "string",
+            "enum": ["browser", "renderer", "extension", "notification", "plugin", "worker", "nacl", "utility", "gpu", "other"],
+            "description": "The type of process."
+          },
+          "profile": {
+            "type": "string",
+            "description": "The profile which the process is associated with."
+          },
+          "tabs": {
+            "type": "array",  "items": {"type": "integer", "minimum": 0},
+            "description": "Array of Tab IDs that have a page rendered by this process. The list will be non-empty for renderer processes only."
+          },
+          "cpu": {
+            "type": "number",
+            "optional": true,
+            "description": "The most recent measurement of the process CPU usage, between 0 and 100%. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "network": {
+            "type": "number",
+            "optional": true,
+            "description": "The most recent measurement of the process network usage, in bytes per second. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "privateMemory": {
+            "type": "number",
+            "optional": true,
+            "description": "The most recent measurement of the process private memory usage, in bytes. Only available when receiving the object as part of a callback from onUpdatedWithMemory or getProcessInfo with the includeMemory flag."
+          },
+          "jsMemoryAllocated": {
+            "type": "number",
+            "optional": true,
+            "description": "The most recent measurement of the process JavaScript allocated memory, in bytes. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "jsMemoryUsed": {
+            "type": "number",
+            "optional": true,
+            "description": "The most recent measurement of the process JavaScript memory used, in bytes. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "sqliteMemory": {
+            "type": "number",
+            "optional": true,
+            "description": "The most recent measurement of the process’s SQLite memory usage, in bytes. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "fps": {
+            "type": "number",
+            "optional": true,
+            "description": "The most recent measurement of the process frames per second. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "imageCache": {
+            "$ref": "Cache",
+            "optional": true,
+            "description": "The most recent information about the image cache for the process. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "scriptCache": {
+            "$ref": "Cache",
+            "optional": true,
+            "description": "The most recent information about the script cache for the process. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          },
+          "cssCache": {
+            "$ref": "Cache",
+            "optional": true,
+            "description": "The most recent information about the CSS cache for the process. Only available when receiving the object as part of a callback from onUpdated or onUpdatedWithMemory."
+          }
+        }
+      },
+      {
+        "id": "Cache",
+        "type": "object",
+        "description": "The Cache object contains information about the size and utilization of a cache used by the browser.",
+        "properties": {
+          "size": {
+            "type": "number",
+            "description": "The size of the cache, in bytes."
+          },
+          "liveSize": {
+            "type": "number",
+            "description": "The part of the cache that is utilized, in bytes."
+          }
+        }
+      }
+    ],
+    "functions": [
+      {
+        "name": "terminate",
+        "type": "function",
+        "description": "Terminates the specified renderer process. Equivalent to visiting about:crash, but without changing the tab's URL.",
+        "parameters": [
+          {
+            "name": "processId",
+            "type": "integer",
+            "minimum": 0,
+            "description": "The ID of the process to be terminated."
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "optional": true,
+            "parameters": [
+              {
+                "name": "didTerminate",
+                "type": "boolean",
+                "description": "True if terminating the process was successful, otherwise false."
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "getProcessIdForTab",
+        "type": "function",
+        "description": "Returns the ID of the renderer process for the specified tab.",
+        "parameters": [
+          {
+            "name": "tabId",
+            "type": "integer",
+            "minimum": 0,
+            "description": "The ID of the tab for which the renderer process ID is to be returned."
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "parameters": [
+              {
+                "name": "processId",
+                "type": "integer",
+                "description": "Process ID of the tab's renderer process."
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "getProcessInfo",
+        "type": "function",
+        "description": "Retrieves the process information for each process ID specified.",
+        "parameters": [
+          {
+            "name": "processIds",
+            "choices": [
+              {"type": "integer", "minimum": 0},
+              {"type": "array", "items": {"type": "integer", "minimum": 0}}
+            ],
+            "description": "The list of process IDs or single process ID for which to return the process information. An empty list indicates all processes are requested."
+          },
+          {
+            "name": "includeMemory",
+            "type": "boolean",
+            "description": "True if detailed memory usage is required. Note, collecting memory usage information incurs extra CPU usage and should only be queried for when needed."
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the processes information is collected.",
+            "parameters": [
+              {
+                "name": "processes",
+                "description": "A dictionary of Process objects for each requested process that is a live child process of the current browser process, indexed by process ID. Metrics requiring aggregation over time will not be populated in each Process object.",
+                "type": "object",
+                "additionalProperties": { "$ref": "Process" }
+              }
+            ]
+          }
+        ]
+      }
+    ],
+    "events": [
+      {
+        "name": "onUpdated",
+        "type": "function",
+        "description": "Fired each time the Task Manager updates its process statistics, providing the dictionary of updated Process objects, indexed by process ID.",
+        "parameters": [
+          {
+            "name": "processes",
+            "type": "object",
+            "description": "A dictionary of updated Process objects for each live process in the browser, indexed by process ID.  Metrics requiring aggregation over time will be populated in each Process object.",
+            "additionalProperties": { "$ref": "Process" }
+          }
+        ]
+      },
+      {
+        "name": "onUpdatedWithMemory",
+        "type": "function",
+        "description": "Fired each time the Task Manager updates its process statistics, providing the dictionary of updated Process objects, indexed by process ID. Identical to onUpdate, with the addition of memory usage details included in each Process object. Note, collecting memory usage information incurs extra CPU usage and should only be listened for when needed.",
+        "parameters": [
+          {
+            "name": "processes",
+            "type": "object",
+            "description": "A dictionary of updated Process objects for each live process in the browser, indexed by process ID.  Memory usage details will be included in each Process object.",
+            "additionalProperties": { "$ref": "Process" }
+          }
+        ]
+      },
+      {
+        "name": "onCreated",
+        "type": "function",
+        "description": "Fired each time a process is created, providing the corrseponding Process object.",
+        "parameters": [
+          {
+            "name": "process",
+            "description": "Details of the process that was created. Metrics requiring aggregation over time will not be populated in the object.",
+            "$ref": "Process"
+          }
+        ]
+      },
+      {
+        "name": "onUnresponsive",
+        "type": "function",
+        "description": "Fired each time a process becomes unresponsive, providing the corrseponding Process object.",
+        "parameters": [
+          {
+            "name": "process",
+            "description": "Details of the unresponsive process. Metrics requiring aggregation over time will not be populated in the object. Only available for renderer processes.",
+            "$ref": "Process"
+          }
+        ]
+      },
+      {
+        "name": "onExited",
+        "type": "function",
+        "description": "Fired each time a process is terminated, providing the type of exit.",
+        "parameters": [
+          {
+            "name": "processId",
+            "description": "The ID of the process that exited.",
+            "type": "integer"
+          },
+          {
+            "name": "exitType",
+            "description": "The type of exit that occurred for the process - normal, abnormal, killed, crashed. Only available for renderer processes.",
+            "type": "integer"
+          },
+          {
+            "name": "exitCode",
+            "description": "The exit code if the process exited abnormally. Only available for renderer processes.",
+            "type": "integer"
+          }
+        ]
+      }
+    ]
+  }
+]
diff --git a/chrome/common/extensions/api/session_restore.json b/chrome/common/extensions/api/session_restore.json
deleted file mode 100644
index e44a59c..0000000
--- a/chrome/common/extensions/api/session_restore.json
+++ /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.
-
-[
-  {
-    "namespace": "sessionRestore",
-    "description": "Use the <code>chrome.sessionRestore</code> API to query and restore tabs and windows from a browsing session.",
-    "types": [
-      {
-        "id": "ClosedEntry",
-        "type": "object",
-        "properties": {
-          "id": {"type": "integer", "minimum": 0, "description": "The ID of the browser session."},
-          "timestamp": {"type": "integer", "description": "The time when the window or tab was closed, represented in milliseconds since the epoch"},
-          "tab": {"$ref": "tabs.Tab", "optional": true, "description": "The closed $ref:tabs.Tab, if this entry describes a tab. Either this or $ref:ClosedEntry.window will be set."},
-          "window": {"$ref": "windows.Window", "optional": true, "description": "The closed $ref:windows.Window, if this entry describes a window. Either this or $ref:ClosedEntry.tab will be set."}
-        }
-      }
-    ],
-    "functions": [
-      {
-        "name": "getRecentlyClosed",
-        "type": "function",
-        "description": "Gets the list of recently closed tabs and/or windows.",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "options",
-            "optional": true,
-            "properties": {
-              "maxResults": {
-                "type": "integer",
-                "minimum": 0,
-                "maximum": 25,
-                "optional": true,
-                "description": "The maximum number of entries to be fetched in the requested list. Omit to fetch the maximum number of entries (25)."
-              },
-              "entryType": {
-                "type": "string",
-                "enum": ["tab", "window"],
-                "optional": true,
-                "description": "The type of entry to fetch. Omit to fetch all types of entries."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {
-                "name": "entries", "type": "array", "items": { "$ref": "ClosedEntry" }, "description": "The list of closed entries in reverse order that they were closed (the most recently closed tab or window will be at index <code>0</code>). If <code>entryType</code> is specified the entries will be only of that type, otherwise the entries may contain either tabs or windows.List of $ref:ClosedEntry representing the closed tab/window for the session."
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "restore",
-        "type": "function",
-        "description": "Reopens a $ref:ClosedEntry, with an optional callback to run when the entry has been restored.",
-        "parameters": [
-          {"type": "integer", "name": "id", "optional": true, "description": "The id of the $ref:ClosedEntry to restore."},
-          {"type": "function", "name": "callback", "optional": true, "parameters": []}
-        ]
-      }
-    ]
-  }
-]
diff --git a/chrome/common/extensions/api/sessions.json b/chrome/common/extensions/api/sessions.json
new file mode 100644
index 0000000..48c09e9
--- /dev/null
+++ b/chrome/common/extensions/api/sessions.json
@@ -0,0 +1,117 @@
+// Copyright 2013 The Chromium 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": "sessions",
+    "description": "Use the <code>chrome.sessions</code> API to query and restore tabs and windows from a browsing session.",
+    "types": [
+      {
+        "id": "Filter",
+        "type": "object",
+        "properties": {
+          "maxResults": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 25,
+            "optional": true,
+            "description": "The maximum number of entries to be fetched in the requested list. Omit this parameter to fetch the maximum number of entries ($ref:MAX_SESSION_RESULTS)."
+          }
+        }
+      },
+      {
+        "id": "Session",
+        "type": "object",
+        "properties": {
+          "lastModified": {"type": "integer", "description": "The time when the window or tab was closed or modified, represented in milliseconds since the epoch."},
+          "tab": {"$ref": "tabs.Tab", "optional": true, "description": "The $ref:tabs.Tab, if this entry describes a tab. Either this or $ref:Session.window will be set."},
+          "window": {"$ref": "windows.Window", "optional": true, "description": "The $ref:windows.Window, if this entry describes a window. Either this or $ref:Session.tab will be set."}
+        }
+      },
+      {
+        "id": "Device",
+        "type": "object",
+        "properties": {
+          "info": {"type": "string", "description": "Represents all information about a foreign device."},
+          "sessions": {"type": "array", "items": {"$ref": "Session"}, "description": "A list of open window sessions for the foreign device, sorted from most recently to least recently modified session."}
+        }
+      }
+    ],
+    "functions": [
+      {
+        "name": "getRecentlyClosed",
+        "type": "function",
+        "description": "Gets the list of recently closed tabs and/or windows.",
+        "parameters": [
+          {
+            "$ref": "Filter",
+            "name": "filter",
+            "optional": true
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "parameters": [
+              {
+                "name": "sessions", "type": "array", "items": { "$ref": "Session" }, "description": "The list of closed entries in reverse order that they were closed (the most recently closed tab or window will be at index <code>0</code>).The entries may contain either tabs or windows."
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "getDevices",
+        "type": "function",
+        "description": "Retrieves all devices with synced sessions.",
+        "parameters": [
+          {
+            "$ref": "Filter",
+            "name": "filter",
+            "optional": true
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "parameters": [
+              {
+                "name": "devices", "type": "array", "items": { "$ref": "Device" }, "description": "The list of $ref:Device objects for each synced session, sorted in order from device with most recently modified session to device with least recently modified session. $ref:tabs.Tab objects are sorted by recency in the $ref:windows.Window of the $ref:Session objects."
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "restore",
+        "type": "function",
+        "description": "Reopens a $ref:windows.Window or $ref:tabs.Tab, with an optional callback to run when the entry has been restored.",
+        "parameters": [
+          {
+            "type": "string",
+            "name": "sessionId",
+            "optional": true,
+            "description": "The $ref:windows.Window.sessionId, or $ref:tabs.Tab.sessionId to restore."
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "optional": true,
+            "parameters": [
+              {
+                "$ref": "Session",
+                "name": "restoredSession",
+                "description": "A $ref:Session containing the restored $ref:windows.Window or $ref:tabs.Tab object."
+              }
+            ]
+          }
+        ]
+      }
+    ],
+    "properties": {
+      "MAX_SESSION_RESULTS": {
+        "value": 25,
+        "description": "The maximum number of $ref:Session that will be included in a requested list."
+      }
+    }
+  }
+]
diff --git a/chrome/common/extensions/api/signedin_devices.idl b/chrome/common/extensions/api/signedin_devices.idl
new file mode 100644
index 0000000..06e9722
--- /dev/null
+++ b/chrome/common/extensions/api/signedin_devices.idl
@@ -0,0 +1,65 @@
+// 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 the <code>chrome.signedinDevices</code> API to get a list of devices
+// signed into chrome with the same account as the current profile.
+namespace signedinDevices {
+  enum OS {
+    win,
+    mac,
+    linux,
+    chrome_os,
+    android,
+    ios,
+    unknown
+  };
+
+  enum DeviceType {
+    desktop_or_laptop,
+    phone,
+    tablet,
+    unknown
+  };
+
+  dictionary DeviceInfo {
+    // Name of the device. This name is usually set by the user
+    // when setting up a device.
+    DOMString name;
+
+    // Unique Id for this device. Note: The id is meaningful only
+    // in the current device. This id cannot be used to refer to the
+    // same device from another device or extension.
+    DOMString id;
+
+    // The OS of the device.
+    OS os;
+
+    // Device Type.
+    DeviceType type;
+
+    // Version of chrome running in this device.
+    DOMString chromeVersion;
+  };
+
+  callback DeviceInfoCallback = void(DeviceInfo[] devices);
+
+  interface Functions {
+    // Gets the array of signed in devices, signed into the same account
+    // as the current profile.
+    // |isLocal|: If true only return the information for the local device. If
+    // false or omitted return the list of all devices including the local
+    // device.
+    // |callback|: The callback to be invoked with the array of DeviceInfo
+    // objects.
+    static void Get(optional boolean isLocal, DeviceInfoCallback callback);
+  };
+
+  interface Events {
+    // Fired if the DeviceInfo object of any of the signed in devices
+    // change or a new device is added or a device removed.
+    // |callback|: The callback to be invoked with the array of DeviceInfo
+    // objects.
+    static void onDeviceInfoChange(DeviceInfoCallback callback);
+  };
+};
\ No newline at end of file
diff --git a/chrome/common/extensions/api/sockets_udp.idl b/chrome/common/extensions/api/sockets_udp.idl
new file mode 100644
index 0000000..bfc432e
--- /dev/null
+++ b/chrome/common/extensions/api/sockets_udp.idl
@@ -0,0 +1,287 @@
+// Copyright 2013 The Chromium 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 the <code>chrome.sockets.udp</code> API to send and receive data over the
+// network using UDP connections. This API supersedes the UDP functionality
+// previously found in the "socket" API. Note that the socket ids created from
+// this namespace are not compatible with ids created in other namespaces.
+namespace sockets.udp {
+  // The socket properties specified in the <code>create</code> or
+  // <code>update</code> function. Each property is optional. If a property
+  // value is not specified, a default value is used when calling
+  // <code>create</code>, or the existing value if preserved when calling
+  // <code>update</code>.
+  dictionary SocketProperties {
+    // Flag indicating if the socket is left open when the event page of
+    // the application is unloaded (see
+    // <a href="http://developer.chrome.com/apps/app_lifecycle.html">Manage App
+    // Lifecycle</a>). The default value is "false." When the application is
+    // loaded, any sockets previously opened with persistent=true can be fetched
+    // with <code>getSockets</code>.
+    boolean? persistent;
+
+    // An application-defined string associated with the socket.
+    DOMString? name;
+
+    // The size of the buffer used to receive data. If the buffer is too small
+    // to receive the UDP packet, data is lost. The default value is 4096.
+    long? bufferSize;
+  };
+
+  // Result of <code>create</code> call.
+  dictionary CreateInfo {
+    // The ID of the newly created socket.
+    long socketId;
+  };
+
+  // Callback from the <code>create</code> method.
+  // |createInfo| : The result of the socket creation.
+  callback CreateCallback = void (CreateInfo createInfo);
+
+  // Callback from the <code>bind</code> method.
+  // |result| : The result code returned from the underlying network call.
+  // A negative value indicates an error.
+  callback BindCallback = void (long result);
+
+  // Result of the <code>send</code> method.
+  dictionary SendInfo {
+    // The result code returned from the underlying network call.
+    // A negative value indicates an error.
+    long result;
+
+    // The number of bytes sent (if result == 0)
+    long? bytesWritten;
+  };
+
+  // Callback from the <code>send</code> method.
+  // |sendInfo| : Result of the <code>send</code> method.
+  callback SendCallback = void (SendInfo sendInfo);
+
+  // Callback from the <code>close<code> method.
+  callback CloseCallback = void ();
+
+  // Callback from the <code>update</code> method.
+  callback UpdateCallback = void ();
+
+  // Result of the <code>getInfo</code> method.
+  dictionary SocketInfo {
+    // The socket identifier.
+    long socketId;
+
+    // Flag indicating whether the socket is left open when the application is
+    // suspended (see <code>SocketProperties.persistent</code>).
+    boolean persistent;
+
+    // Application-defined string associated with the socket.
+    DOMString? name;
+
+    // The size of the buffer used to receive data. If no buffer size has been
+    // specified explictly, the value is not provided.
+    long? bufferSize;
+
+    // If the underlying socket is bound, contains its local
+    // IPv4/6 address.
+    DOMString? localAddress;
+
+    // If the underlying socket is bound, contains its local port.
+    long? localPort;
+  };
+
+  // Callback from the <code>getInfo</code> method.
+  // |socketInfo| : Object containing the socket information.
+  callback GetInfoCallback = void (SocketInfo socketInfo);
+
+  // Callback from the <code>getSockets</code> method.
+  // |socketInfos| : Array of object containing socket information.
+  callback GetSocketsCallback = void (SocketInfo[] socketInfos);
+
+  // Callback from the <code>joinGroup</code> method.
+  // |result| : The result code returned from the underlying network call.
+  // A negative value indicates an error.
+  callback JoinGroupCallback = void (long result);
+
+  // Callback from the <code>leaveGroup</code> method.
+  // |result| : The result code returned from the underlying network call.
+  // A negative value indicates an error.
+  callback LeaveGroupCallback = void (long result);
+
+  // Callback from the <code>setMulticastTimeToLive</code> method.
+  // |result| : The result code returned from the underlying network call.
+  // A negative value indicates an error.
+  callback SetMulticastTimeToLiveCallback = void (long result);
+
+  // Callback from the <code>setMulticastLoopbackMode</code> method.
+  // |result| : The result code returned from the underlying network call.
+  // A negative value indicates an error.
+  callback SetMulticastLoopbackModeCallback = void (long result);
+
+  // Callback from the <code>getJoinedGroupsCallback</code> method.
+  // |groups| : Array of groups the socket joined.
+  callback GetJoinedGroupsCallback = void (DOMString[] groups);
+
+  // Data from an <code>onReceive</code> event.
+  dictionary ReceiveInfo {
+    // The socket ID.
+    long socketId;
+
+    // The UDP packet content (truncated to the current buffer size).
+    ArrayBuffer data;
+
+    // The address of the host the packet comes from.
+    DOMString remoteAddress;
+
+     // The port of the host the packet comes from.
+    long remotePort;
+  };
+
+  // Data from an <code>onReceiveError</code> event.
+  dictionary ReceiveErrorInfo {
+    // The socket ID.
+    long socketId;
+
+     // The result code returned from the underlying recvfrom() call.
+    long result;
+  };
+
+  interface Functions {
+    // Creates a UDP socket.
+    // |properties| : The socket properties (optional).
+    // |callback| : Called when the socket has been created.
+    static void create(optional SocketProperties properties,
+                       CreateCallback callback);
+
+    // Updates the socket properties.
+    // |socketId| : The socket ID.
+    // |properties| : The properties to update.
+    // |callback| : Called when the properties are updated.
+    static void update(long socketId,
+                       SocketProperties properties,
+                       UpdateCallback callback);
+
+    // Binds the local address for socket. When the <code>bind</code> operation
+    // completes successfully, <code>onReceive</code> events are raised
+    // when UDP packets arrive on the address/port specified. If a network
+    // error occurs while the runtime is receiving packets, an
+    // <code>onReceiveError</code> event is raised, at which point no more
+    // <code>onReceive</code> events will be raised for this socket.
+    // |socketId| : The socket ID.
+    // |address| : The address of the local machine. DNS name, IPv4 and IPv6
+    //  formats are supported. Use "0.0.0.0" to accept packets from all local
+    //  available network interfaces.
+    // |port| : The port of the local machine. Use "0" to bind to a free port.
+    // |callback| : Called when the <code>bind</code> operation completes.
+    static void bind(long socketId,
+                     DOMString address,
+                     long port,
+                     BindCallback callback);
+
+    // Sends data on the given UDP socket to the given address and port.
+    // |socketId| : The socket ID.
+    // |data| : The data to write.
+    // |address| : The address of the remote machine.
+    // |port| : The port of the remote machine.
+    // |callback| : Called when the <code>send</code> operation completes.
+    static void send(long socketId,
+                     ArrayBuffer data,
+                     DOMString address,
+                     long port,
+                     SendCallback callback);
+
+    // Closes the socket and releases the address/port the socket is bound to.
+    // Each socket created should be closed after use. The socket id is no
+    // no longer valid as soon at the function is called. However, the socket is
+    // guaranteed to be closed only when the callback is invoked.
+    // |socketId| : The socket ID.
+    // |callback| : Called when the <code>close</code> operation completes.
+    static void close(long socketId,
+                      optional CloseCallback callback);
+
+    // Retrieves the state of the given socket.
+    // |socketId| : The socket ID.
+    // |callback| : Called when the socket state is available.
+    static void getInfo(long socketId,
+                        GetInfoCallback callback);
+
+    // Retrieves the list of currently opened sockets owned by the application.
+    // |callback| : Called when the list of sockets is available.
+    static void getSockets(GetSocketsCallback callback);
+
+    // Joins the multicast group and starts to receive packets from that group.
+    // The socket must be bound to a local port before calling this method.
+    // |socketId| : The socket ID.
+    // |address| : The group address to join. Domain names are not supported.
+    // |callback| : Called when the <code>joinGroup</code> operation completes.
+    static void joinGroup(long socketId,
+                          DOMString address,
+                          JoinGroupCallback callback);
+
+    // Leaves the multicast group previously joined using
+    // <code>joinGroup</code>. This is only necessary to call if you plan to
+    // keep using the socketafterwards, since it will be done automatically by
+    // the OS when the socket is closed.
+    //
+    // Leaving the group will prevent the router from sending multicast
+    // datagrams to the local host, presuming no other process on the host is
+    // still joined to the group.
+    //
+    // |socketId| : The socket ID.
+    // |address| : The group address to leave. Domain names are not supported.
+    // |callback| : Called when the <code>leaveGroup</code> operation completes.
+    static void leaveGroup(long socketId,
+                           DOMString address,
+                           LeaveGroupCallback callback);
+
+    // Sets the time-to-live of multicast packets sent to the multicast group.
+    //
+    // Calling this method does not require multicast permissions.
+    //
+    // |socketId| : The socket ID.
+    // |ttl| : The time-to-live value.
+    // |callback| : Called when the configuration operation completes.
+    static void setMulticastTimeToLive(
+        long socketId,
+        long ttl,
+        SetMulticastTimeToLiveCallback callback);
+
+    // Sets whether multicast packets sent from the host to the multicast
+    // group will be looped back to the host.
+    //
+    // Note: the behavior of <code>setMulticastLoopbackMode</code> is slightly
+    // different between Windows and Unix-like systems. The inconsistency
+    // happens only when there is more than one application on the same host
+    // joined to the same multicast group while having different settings on
+    // multicast loopback mode. On Windows, the applications with loopback off
+    // will not RECEIVE the loopback packets; while on Unix-like systems, the
+    // applications with loopback off will not SEND the loopback packets to
+    // other applications on the same host. See MSDN: http://goo.gl/6vqbj
+    //
+    // Calling this method does not require multicast permissions.
+    //
+    // |socketId| : The socket ID.
+    // |enabled| : Indicate whether to enable loopback mode.
+    // |callback| : Called when the configuration operation completes.
+    static void setMulticastLoopbackMode(
+        long socketId,
+        boolean enabled,
+        SetMulticastLoopbackModeCallback callback);
+
+    // Gets the multicast group addresses the socket is currently joined to.
+    // |socketId| : The socket ID.
+    // |callback| : Called with an array of strings of the result.
+    static void getJoinedGroups(long socketId,
+                                GetJoinedGroupsCallback callback);
+  };
+
+  interface Events {
+    // Event raised when a UDP packet has been received for a given socket.
+    // |info| : The event data.
+    static void onReceive(ReceiveInfo info);
+
+    // Event raised when a network error occured while the runtime was waiting
+    // for data on the socket address and port. Once this event is raised, no
+    // more <code>onReceive</code> events will be raise for this socket.
+    // |info| : The event data.
+    static void onReceiveError(ReceiveErrorInfo info);
+  };
+};
diff --git a/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc b/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc
index 87f6226..dd33dc3 100644
--- a/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc
+++ b/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc
@@ -9,11 +9,11 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 #include "ui/base/l10n/l10n_util.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc b/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc
index 039cd2b..b258163 100644
--- a/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc
+++ b/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc
@@ -9,7 +9,7 @@
 
 namespace extensions {
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 SpellcheckDictionaryInfo::SpellcheckDictionaryInfo() {
diff --git a/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc b/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc
index 103b19b..6e49241 100644
--- a/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc
+++ b/chrome/common/extensions/api/storage/storage_schema_manifest_handler.cc
@@ -14,13 +14,13 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
-#include "chrome/common/policy/policy_schema.h"
+#include "components/policy/core/common/policy_schema.h"
 #include "extensions/common/install_warning.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 
-using extension_manifest_keys::kStorageManagedSchema;
+using extensions::manifest_keys::kStorageManagedSchema;
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc b/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
index 088a2d5..29b0c85 100644
--- a/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
+++ b/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
@@ -15,7 +15,7 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/features/feature_channel.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
diff --git a/chrome/common/extensions/api/sync_file_system.idl b/chrome/common/extensions/api/sync_file_system.idl
index 5eceabc..8cfbb99 100644
--- a/chrome/common/extensions/api/sync_file_system.idl
+++ b/chrome/common/extensions/api/sync_file_system.idl
@@ -64,7 +64,7 @@
     // On file deletion,
     // <code>fileEntry</code> information will still be available
     // but file will no longer exist.
-    [instanceOf=FileEntry] object fileEntry;
+    [instanceOf=Entry] object fileEntry;
 
     // Resulting file status after $ref:onFileStatusChanged event.
     // The status value can be <code>'synced'</code>,
@@ -85,8 +85,8 @@
   };
 
   dictionary FileStatusInfo {
-    // One of the FileEntry's originally given to getFileStatuses.
-    [instanceOf=FileEntry] object fileEntry;
+    // One of the Entry's originally given to getFileStatuses.
+    [instanceOf=Entry] object fileEntry;
 
     // The status value can be <code>'synced'</code>,
     // <code>'pending'</code> or <code>'conflicting'</code>.
@@ -165,7 +165,7 @@
     // <code>'pending'</code> or <code>'conflicting'</code>.
     // Note that <code>'conflicting'</code> state only happens when
     // the service's conflict resolution policy is set to <code>'manual'</code>.
-    static void getFileStatus([instanceOf=FileEntry] object fileEntry,
+    static void getFileStatus([instanceOf=Entry] object fileEntry,
                               GetFileStatusCallback callback);
 
     // Returns each $ref:FileStatus for the given <code>fileEntry</code> array.
diff --git a/chrome/common/extensions/api/system_indicator/system_indicator_handler.cc b/chrome/common/extensions/api/system_indicator/system_indicator_handler.cc
index 792a2c4..1636a42 100644
--- a/chrome/common/extensions/api/system_indicator/system_indicator_handler.cc
+++ b/chrome/common/extensions/api/system_indicator/system_indicator_handler.cc
@@ -24,7 +24,7 @@
 bool SystemIndicatorHandler::Parse(Extension* extension, string16* error) {
   const base::DictionaryValue* system_indicator_value = NULL;
   if (!extension->manifest()->GetDictionary(
-          extension_manifest_keys::kSystemIndicator, &system_indicator_value)) {
+          manifest_keys::kSystemIndicator, &system_indicator_value)) {
     *error = ASCIIToUTF16(extension_manifest_errors::kInvalidSystemIndicator);
     return false;
   }
@@ -45,7 +45,7 @@
 }
 
 const std::vector<std::string> SystemIndicatorHandler::Keys() const {
-  return SingleKey(extension_manifest_keys::kSystemIndicator);
+  return SingleKey(manifest_keys::kSystemIndicator);
 }
 
 }  // namespace extensions
diff --git a/chrome/common/extensions/api/tabs.json b/chrome/common/extensions/api/tabs.json
index c18f5c4..4b4077d 100644
--- a/chrome/common/extensions/api/tabs.json
+++ b/chrome/common/extensions/api/tabs.json
@@ -11,20 +11,23 @@
         "id": "Tab",
         "type": "object",
         "properties": {
-          "id": {"type": "integer", "minimum": 0, "description": "The ID of the tab. Tab IDs are unique within a browser session."},
+          "id": {"type": "integer", "minimum": 0, "optional": true, "description": "The ID of the tab. Tab IDs are unique within a browser session. Under some circumstances a Tab may not be assigned an ID, for example when querying foreign tabs using the $ref:sessions API, in which case a session ID may be present."},
           // TODO(kalman): Investigate how this is ending up as -1 (based on window type? a bug?) and whether it should be optional instead.
           "index": {"type": "integer", "minimum": -1, "description": "The zero-based index of the tab within its window."},
           "windowId": {"type": "integer", "minimum": 0, "description": "The ID of the window the tab is contained within."},
-          "openerTabId": {"type": "integer", "minimum": 0, "optional": true, "description": "The ID of the tab that opened this tab, if any. This will only be present if the opener tab still exists."},
+          "openerTabId": {"type": "integer", "minimum": 0, "optional": true, "description": "The ID of the tab that opened this tab, if any. This property is only present if the opener tab still exists."},
           "selected": {"type": "boolean", "description": "Whether the tab is selected.", "nodoc": true},
           "highlighted": {"type": "boolean", "description": "Whether the tab is highlighted."},
           "active": {"type": "boolean", "description": "Whether the tab is active in its window. (Does not necessarily mean the window is focused.)"},
           "pinned": {"type": "boolean", "description": "Whether the tab is pinned."},
-          "url": {"type": "string", "optional": true, "description": "The URL the tab is displaying. This will only be present if the extension has the 'tabs' or 'webNavigation' permission."},
-          "title": {"type": "string", "optional": true, "optional": true, "description": "The title of the tab. This will only be present if the extension has the 'tabs' or 'webNavigation' permission. It may also be an empty string if the tab is loading."},
-          "favIconUrl": {"type": "string", "optional": true, "optional": true, "description": "The URL of the tab's favicon. This will only be present if the extension has the 'tabs' or 'webNavigation' permission. It may also be an empty string if the tab is loading."},
+          "url": {"type": "string", "optional": true, "description": "The URL the tab is displaying. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
+          "title": {"type": "string", "optional": true, "optional": true, "description": "The title of the tab. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
+          "favIconUrl": {"type": "string", "optional": true, "optional": true, "description": "The URL of the tab's favicon. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission. It may also be an empty string if the tab is loading."},
           "status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."},
-          "incognito": {"type": "boolean", "description": "Whether the tab is in an incognito window."}
+          "incognito": {"type": "boolean", "description": "Whether the tab is in an incognito window."},
+          "width": {"type": "integer", "optional": true, "description": "The width of the tab in pixels."},
+          "height": {"type": "integer", "optional": true, "description": "The height of the tab in pixels."},
+          "sessionId": {"type": "string", "optional": true, "description": "The session ID used to uniquely identify a Tab obtained from the $ref:sessions API."}
         }
       },
       {
@@ -34,7 +37,7 @@
         "properties": {
           "code": {"type": "string", "optional": true, "description": "JavaScript or CSS code to inject."},
           "file": {"type": "string", "optional": true, "description": "JavaScript or CSS file to inject."},
-          "allFrames": {"type": "boolean", "optional": true, "description": "If allFrames is <code>true</code>, implies that the JavaScript or CSS should be injected into all frames of current page. By default, it's <code>false</code> and will only be injected into the top frame."},
+          "allFrames": {"type": "boolean", "optional": true, "description": "If allFrames is <code>true</code>, implies that the JavaScript or CSS should be injected into all frames of current page. By default, it's <code>false</code> and is only injected into the top frame."},
           "runAt": {
             "type": "string",
             "optional": true,
@@ -213,7 +216,7 @@
       {
         "name": "create",
         "type": "function",
-        "description": "Creates a new tab. Note: This function can be used without requesting the 'tabs' permission in the manifest.",
+        "description": "Creates a new tab.",
         "parameters": [
           {
             "type": "object",
@@ -277,7 +280,7 @@
       {
         "name": "duplicate",
         "type": "function",
-        "description": "Duplicates a tab. Note: This function can be used without requesting the 'tabs' permission in the manifest.",
+        "description": "Duplicates a tab.",
         "parameters": [
           {
             "type": "integer",
@@ -293,7 +296,7 @@
               {
                 "name": "tab",
                 "optional": true,
-                "description": "Details about the duplicated tab. The Tab object doesn't contain url, title and faviconUrl if the 'tabs' permission has not been requested.",
+                "description": "Details about the duplicated tab. The $ref:tabs.Tab object doesn't contain <code>url</code>, <code>title</code> and <code>favIconUrl</code> if the <code>\"tabs\"</code> permission has not been requested.",
                 "$ref": "Tab"
               }
             ]
@@ -425,7 +428,7 @@
       {
         "name": "update",
         "type": "function",
-        "description": "Modifies the properties of a tab. Properties that are not specified in <var>updateProperties</var> are not modified. Note: This function can be used without requesting the 'tabs' permission in the manifest.",
+        "description": "Modifies the properties of a tab. Properties that are not specified in <var>updateProperties</var> are not modified.",
         "parameters": [
           {
             "type": "integer",
@@ -481,7 +484,7 @@
                 "name": "tab",
                 "$ref": "Tab",
                 "optional": true,
-                "description": "Details about the updated tab, or <code>null</code> if the 'tabs' permission has not been requested."
+                "description": "Details about the updated tab. The $ref:tabs.Tab object doesn't contain <code>url</code>, <code>title</code> and <code>favIconUrl</code> if the <code>\"tabs\"</code> permission has not been requested."
               }
             ]
           }
@@ -558,7 +561,7 @@
       {
         "name": "remove",
         "type": "function",
-        "description": "Closes one or more tabs. Note: This function can be used without requesting the 'tabs' permission in the manifest.",
+        "description": "Closes one or more tabs.",
         "parameters": [
           {
             "name": "tabIds",
@@ -912,7 +915,7 @@
       {
         "name": "onRemoved",
         "type": "function",
-        "description": "Fired when a tab is closed. Note: A listener can be registered for this event without requesting the 'tabs' permission in the manifest.",
+        "description": "Fired when a tab is closed.",
         "parameters": [
           {"type": "integer", "name": "tabId", "minimum": 0},
           {
diff --git a/chrome/common/extensions/api/webview.json b/chrome/common/extensions/api/webview.json
index 7f2f6b7..7fe3548 100644
--- a/chrome/common/extensions/api/webview.json
+++ b/chrome/common/extensions/api/webview.json
@@ -6,8 +6,87 @@
   {
     "namespace": "webview",
     "description": "none",
+    "types": [
+      {
+        "id": "DataTypeSet",
+        "type": "object",
+        "description": "A set of data types. Missing data types are interpreted as <code>false</code>.",
+        "properties": {
+          "appcache": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Websites' appcaches."
+          },
+          "cookies": {
+            "type": "boolean",
+            "optional": true,
+            "description": "The browser's cookies."
+          },
+          "fileSystems": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Websites' file systems."
+          },
+          "indexedDB": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Websites' IndexedDB data."
+          },
+          "localStorage": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Websites' local storage data."
+          },
+          "webSQL": {
+            "type": "boolean",
+            "optional": true,
+            "description": "Websites' WebSQL data."
+          }
+        }
+      },
+      {
+        "id": "RemovalOptions",
+        "type": "object",
+        "description": "Options that determine exactly what data will be removed.",
+        "properties": {
+          "since": {
+            "type": "number",
+            "optional": true,
+            "description": "Remove data accumulated on or after this date, represented in milliseconds since the epoch (accessible via the <code>getTime</code> method of the JavaScript <code>Date</code> object). If absent, defaults to 0 (which would remove all browsing data)."
+          }
+        }
+      }
+    ],
     "functions": [
       {
+        "name": "clearData",
+        "type": "function",
+        "description": "Clears various types of browsing data stored in a storage partition of a <webview>.",
+        "parameters": [
+          {
+            "type": "integer",
+            "name": "instanceId",
+            "description": "The instance ID of the guest <webview> process."
+          },
+          {
+            "$ref": "RemovalOptions",
+            "name": "options"
+          },
+          {
+            "name": "dataToRemove",
+            "$ref": "DataTypeSet",
+            "description": "The set of data types to remove."
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when deletion has completed.",
+            "optional": true,
+            "parameters": []
+          }
+        ]
+      },
+      {
         "name": "executeScript",
         "type": "function",
         "description": "Injects JavaScript code into a <webview> page.",
diff --git a/chrome/common/extensions/api/windows.json b/chrome/common/extensions/api/windows.json
index 7e3d2d6..8ef02ac 100644
--- a/chrome/common/extensions/api/windows.json
+++ b/chrome/common/extensions/api/windows.json
@@ -14,27 +14,28 @@
         "id": "Window",
         "type": "object",
         "properties": {
-          "id": {"type": "integer", "optional": true, "minimum": 0, "description": "The ID of the window. Window IDs are unique within a browser session. Under some circumstances a Window may not be assigned an ID, for example when querying closed windows from the $ref:sessionRestore API."},
+          "id": {"type": "integer", "optional": true, "minimum": 0, "description": "The ID of the window. Window IDs are unique within a browser session. Under some circumstances a Window may not be assigned an ID, for example when querying windows using the $ref:sessions API, in which case a session ID may be present."},
           "focused": {"type": "boolean", "description": "Whether the window is currently the focused window."},
-          "top": {"type": "integer", "optional": true, "description": "The offset of the window from the top edge of the screen in pixels. Under some circumstances a Window may not be assigned top property, for example when querying closed windows from the $ref:sessionRestore API."},
-          "left": {"type": "integer", "optional": true, "description": "The offset of the window from the left edge of the screen in pixels. Under some circumstances a Window may not be assigned left property, for example when querying closed windows from the $ref:sessionRestore API."},
-          "width": {"type": "integer", "optional": true, "description": "The width of the window, including the frame, in pixels. Under some circumstances a Window may not be assigned width property, for example when querying closed windows from the $ref:sessionRestore API."},
-          "height": {"type": "integer", "optional": true, "description": "The height of the window, including the frame, in pixels. Under some circumstances a Window may not be assigned height property, for example when querying closed windows from the $ref:sessionRestore API."},
+          "top": {"type": "integer", "optional": true, "description": "The offset of the window from the top edge of the screen in pixels. Under some circumstances a Window may not be assigned top property, for example when querying closed windows from the $ref:sessions API."},
+          "left": {"type": "integer", "optional": true, "description": "The offset of the window from the left edge of the screen in pixels. Under some circumstances a Window may not be assigned left property, for example when querying closed windows from the $ref:sessions API."},
+          "width": {"type": "integer", "optional": true, "description": "The width of the window, including the frame, in pixels. Under some circumstances a Window may not be assigned width property, for example when querying closed windows from the $ref:sessions API."},
+          "height": {"type": "integer", "optional": true, "description": "The height of the window, including the frame, in pixels. Under some circumstances a Window may not be assigned height property, for example when querying closed windows from the $ref:sessions API."},
           "tabs": {"type": "array", "items": { "$ref": "tabs.Tab" }, "optional": true, "description": "Array of $ref:tabs.Tab objects representing the current tabs in the window."},
           "incognito": {"type": "boolean", "description": "Whether the window is incognito."},
           "type": {
             "type": "string",
             "optional": true,
-            "description": "The type of browser window this is. Under some circumstances a Window may not be assigned type property, for example when querying closed windows from the $ref:sessionRestore API.",
+            "description": "The type of browser window this is. Under some circumstances a Window may not be assigned type property, for example when querying closed windows from the $ref:sessions API.",
             "enum": ["normal", "popup", "panel", "app"]
           },
           "state": {
             "type": "string",
             "optional": true,
-            "description": "The state of this browser window. Under some circumstances a Window may not be assigned state property, for example when querying closed windows from the $ref:sessionRestore API.",
+            "description": "The state of this browser window. Under some circumstances a Window may not be assigned state property, for example when querying closed windows from the $ref:sessions API.",
             "enum": ["normal", "minimized", "maximized", "fullscreen"]
           },
-          "alwaysOnTop": {"type": "boolean", "description": "Whether the window is set to be always on top."}
+          "alwaysOnTop": {"type": "boolean", "description": "Whether the window is set to be always on top."},
+          "sessionId": {"type": "string", "optional": true, "description": "The session ID used to uniquely identify a Window obtained from the $ref:sessions API."}
         }
       }
     ],
@@ -61,7 +62,7 @@
             "optional": true,
             "description": "",
             "properties": {
-              "populate": {"type": "boolean", "optional": true, "description": "If true, the window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects" }
+              "populate": {"type": "boolean", "optional": true, "description": "If true, the $ref:windows.Window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission." }
             }
           },
           {
@@ -86,7 +87,7 @@
             "optional": true,
             "description": "",
             "properties": {
-              "populate": {"type": "boolean", "optional": true, "description": "If true, the window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects" }
+              "populate": {"type": "boolean", "optional": true, "description": "If true, the $ref:windows.Window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission." }
             }
           },
           {
@@ -111,7 +112,7 @@
             "optional": true,
             "description": "",
             "properties": {
-              "populate": {"type": "boolean", "optional": true, "description": "If true, the window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects" }
+              "populate": {"type": "boolean", "optional": true, "description": "If true, the $ref:windows.Window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission." }
             }
           },
           {
@@ -136,7 +137,7 @@
             "optional": true,
             "description": "",
             "properties": {
-              "populate": {"type": "boolean", "optional": true, "description": "If true, each window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects for that window." }
+              "populate": {"type": "boolean", "optional": true, "description": "If true, each $ref:windows.Window object will have a <var>tabs</var> property that contains a list of the $ref:tabs.Tab objects for that window. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission." }
             }
           },
           {
diff --git a/chrome/common/extensions/background_info.cc b/chrome/common/extensions/background_info.cc
index ae25782..dcce951 100644
--- a/chrome/common/extensions/background_info.cc
+++ b/chrome/common/extensions/background_info.cc
@@ -21,7 +21,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 using base::DictionaryValue;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace values = extension_manifest_values;
 namespace errors = extension_manifest_errors;
 
@@ -61,6 +61,12 @@
 }
 
 // static
+bool BackgroundInfo::HasGeneratedBackgroundPage(const Extension* extension) {
+  const BackgroundInfo& info = GetBackgroundInfo(extension);
+  return !info.background_scripts_.empty();
+}
+
+// static
 const std::vector<std::string>& BackgroundInfo::GetBackgroundScripts(
     const Extension* extension) {
   return GetBackgroundInfo(extension).background_scripts_;
diff --git a/chrome/common/extensions/background_info.h b/chrome/common/extensions/background_info.h
index 6fc8ec8..b375b8b 100644
--- a/chrome/common/extensions/background_info.h
+++ b/chrome/common/extensions/background_info.h
@@ -26,6 +26,7 @@
   static bool HasBackgroundPage(const Extension* extension);
   static bool HasPersistentBackgroundPage(const Extension* extension);
   static bool HasLazyBackgroundPage(const Extension* extension);
+  static bool HasGeneratedBackgroundPage(const Extension* extension);
   static bool AllowJSAccess(const Extension* extension);
 
   bool has_background_page() const {
diff --git a/chrome/common/extensions/command.cc b/chrome/common/extensions/command.cc
index 0d529f5..fffc55e 100644
--- a/chrome/common/extensions/command.cc
+++ b/chrome/common/extensions/command.cc
@@ -16,7 +16,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace values = extension_manifest_values;
 
 using extensions::ErrorUtils;
diff --git a/chrome/common/extensions/csp_handler.cc b/chrome/common/extensions/csp_handler.cc
index fbf2e48..5437f75 100644
--- a/chrome/common/extensions/csp_handler.cc
+++ b/chrome/common/extensions/csp_handler.cc
@@ -12,7 +12,7 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/manifest_handlers/sandboxed_page_info.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 using extensions::csp_validator::ContentSecurityPolicyIsLegal;
diff --git a/chrome/common/extensions/csp_validator.h b/chrome/common/extensions/csp_validator.h
index dc9c57a..d6d4a2f 100644
--- a/chrome/common/extensions/csp_validator.h
+++ b/chrome/common/extensions/csp_validator.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/app.js b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
new file mode 100644
index 0000000..1ca9448
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/app.js
@@ -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.
+
+function gotStream(stream) {
+  console.log("Received local stream");
+  var video = document.querySelector("video");
+  video.src = webkitURL.createObjectURL(stream);
+  localstream = stream;
+  stream.onended = function() { console.log("Ended"); };
+}
+
+function getUserMediaError() {
+  console.log("getUserMedia() failed.");
+}
+
+function onAccessApproved(id) {
+  if (!id) {
+    console.log("Access rejected.");
+    return;
+  }
+  navigator.webkitGetUserMedia({
+      audio:false,
+      video: { mandatory: { chromeMediaSource: "desktop",
+                            chromeMediaSourceId: id } }
+  }, gotStream, getUserMediaError);
+}
+
+document.querySelector('button').addEventListener('click', function(e) {
+  chrome.desktopCapture.chooseDesktopMedia(
+      ["screen", "window"], onAccessApproved );
+});
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/background.js b/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
new file mode 100644
index 0000000..6d17ac4
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
@@ -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.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  chrome.app.window.create('index.html', {
+    bounds: {
+      width: 700,
+      height: 600
+    }
+  });
+});
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/index.html b/chrome/common/extensions/docs/examples/api/desktopCapture/index.html
new file mode 100644
index 0000000..9387520
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/index.html
@@ -0,0 +1,24 @@
+<html>
+<head>
+<style>
+  body {
+    background: white;
+    display: -webkit-flex;
+    -webkit-justify-content: center;
+    -webkit-align-items: center;
+    -webkit-flex-direction: column;
+  }
+  video {
+    width: 640px;
+    height: 480px;
+    border: 1px solid #e2e2e2;
+    box-shadow: 0 1px 1px rgba(0,0,0,0.2);
+  }
+</style>
+</head>
+<body>
+  <video id="video" autoplay></video>
+  <p><button>Start</button></p>
+  <script src="app.js"></script>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/manifest.json b/chrome/common/extensions/docs/examples/api/desktopCapture/manifest.json
new file mode 100644
index 0000000..dfafb12
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/manifest.json
@@ -0,0 +1,17 @@
+{
+  "name": "Desktop Capture Example",
+  "version": "1",
+  "manifest_version": 2,
+  "icons": {
+    "16": "icon.png",
+    "128": "icon.png"
+  },
+  "app": {
+    "background": {
+      "scripts": ["background.js"]
+    }
+  },
+  "permissions": [
+    "desktopCapture"
+  ]
+}
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/bg.js b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/bg.js
new file mode 100644
index 0000000..10a311b
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/bg.js
@@ -0,0 +1,53 @@
+// 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.
+
+function matches(rule, item) {
+  if (rule.matcher == 'js')
+    return eval(rule.match_param);
+  if (rule.matcher == 'hostname') {
+    var link = document.createElement('a');
+    link.href = item.url.toLowerCase();
+    var host = (rule.match_param.indexOf(':') < 0) ? link.hostname : link.host;
+    return (host.indexOf(rule.match_param.toLowerCase()) ==
+            (host.length - rule.match_param.length));
+  }
+  if (rule.matcher == 'default')
+    return item.filename == rule.match_param;
+  if (rule.matcher == 'url-regex')
+    return (new RegExp(rule.match_param)).test(item.url);
+  if (rule.matcher == 'default-regex')
+    return (new RegExp(rule.match_param)).test(item.filename);
+  return false;
+}
+
+chrome.downloads.onDeterminingFilename.addListener(function(item, __suggest) {
+  function suggest(filename, conflictAction) {
+    __suggest({filename: filename,
+               conflictAction: conflictAction,
+               conflict_action: conflictAction});
+    // conflict_action was renamed to conflictAction in
+    // http://src.chromium.org/viewvc/chrome?view=rev&revision=214133
+    // which was first picked up in branch 1580.
+  }
+  var rules = localStorage.rules;
+  try {
+    rules = JSON.parse(rules);
+  } catch (e) {
+    localStorage.rules = JSON.stringify([]);
+  }
+  for (var index = 0; index < rules.length; ++index) {
+    var rule = rules[index];
+    if (rule.enabled &&
+        matches(rule, item) {
+      if (rule.action == 'overwrite') {
+        suggest(item.filename, 'overwrite');
+      } else if (rule.action == 'prompt') {
+        suggest(item.filename, 'prompt');
+      } else if (rule.action == 'js') {
+        eval(rule.action_js);
+      }
+      break;
+    }
+  }
+});
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/manifest.json b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/manifest.json
new file mode 100644
index 0000000..dd3fea2
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/manifest.json
@@ -0,0 +1,8 @@
+{"name": "Download Filename Controller",
+ "description": "Download Filename Controller",
+ "version": "0.1",
+ "background": {"scripts": ["bg.js"], "persistent": false},
+ "options_page": "options.html",
+ "permissions": ["downloads"],
+ "content_security_policy": "script-src 'self' chrome-extension-resource: 'unsafe-eval'; default-src 'self'",
+ "manifest_version": 2}
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/options.html b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/options.html
new file mode 100644
index 0000000..2375c33
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/options.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html>
+<head>
+<title>Download Filename Controller</title>
+<script src="options.js"></script>
+<link rel="stylesheet" type="text/css" href="options.css">
+</head>
+<body>
+<table id=rules></table>
+<button id=new>New Rule</button>
+<table hidden>
+<tr id=rule-template hidden>
+  <td class=nowrap><button class=move-up>&uarr;</button>
+    <button class=move-down>&darr;</button></td>
+  <td>
+    <select class=matcher>
+      <option value=hostname>Hostname</option>
+      <option value=url-regex>URL RegExp</option>
+      <option value=default>Default Filename</option>
+      <option value=default-regex>Default Filename RegExp</option>
+      <option value=js>Javascript</option>
+    </select>
+    <input type=text class=match-param>
+    <select class=action>
+      <option value=overwrite>Overwrite default filename</option>
+      <option value=prompt>Prompt if default filename exists</option>
+      <option value=js>Javascript</option>
+    </select>
+    <textarea class=action-js rows=5 cols=83>console.log(item.url)
+console.log(item.filename)
+// http://developer.chrome.com/extensions/downloads.html#type-DownloadItem
+// http://developer.chrome.com/extensions/downloads.html#type-FilenameConflictAction
+suggest('hello.txt', 'overwrite')</textarea></td>
+  <td><span class=nowrap><input type=checkbox class=enabled checked>
+      <label class=enabled-label>Enabled</label></span>
+    <button class=remove>Remove</button></td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/options.js b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/options.js
new file mode 100644
index 0000000..d25ae42
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/options.js
@@ -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.
+
+function Rule(data) {
+  var rules = document.getElementById('rules');
+  this.node = document.getElementById('rule-template').cloneNode(true);
+  this.node.id = 'rule' + (Rule.next_id++);
+  this.node.rule = this;
+  rules.appendChild(this.node);
+  this.node.hidden = false;
+
+  if (data) {
+    this.getElement('matcher').value = data.matcher;
+    this.getElement('match-param').value = data.match_param;
+    this.getElement('action').value = data.action;
+    this.getElement('action-js').value = data.action_js;
+    this.getElement('enabled').checked = data.enabled;
+  }
+
+  this.getElement('enabled-label').htmlFor = this.getElement('enabled').id =
+    this.node.id + '-enabled';
+
+  this.render();
+
+  this.getElement('matcher').onchange = storeRules;
+  this.getElement('match-param').onkeyup = storeRules;
+  this.getElement('action').onchange = storeRules;
+  this.getElement('action-js').onkeyup = storeRules;
+  this.getElement('enabled').onchange = storeRules;
+
+  var rule = this;
+  this.getElement('move-up').onclick = function() {
+    var sib = rule.node.previousSibling;
+    rule.node.parentNode.removeChild(rule.node);
+    sib.parentNode.insertBefore(rule.node, sib);
+    storeRules();
+  };
+  this.getElement('move-down').onclick = function() {
+    var parentNode = rule.node.parentNode;
+    var sib = rule.node.nextSibling.nextSibling;
+    parentNode.removeChild(rule.node);
+    if (sib) {
+      parentNode.insertBefore(rule.node, sib);
+    } else {
+      parentNode.appendChild(rule.node);
+    }
+    storeRules();
+  };
+  this.getElement('remove').onclick = function() {
+    rule.node.parentNode.removeChild(rule.node);
+    storeRules();
+  };
+  storeRules();
+}
+
+Rule.prototype.getElement = function(name) {
+  return document.querySelector('#' + this.node.id + ' .' + name);
+}
+
+Rule.prototype.render = function() {
+  this.getElement('move-up').disabled = !this.node.previousSibling;
+  this.getElement('move-down').disabled = !this.node.nextSibling;
+  this.getElement('action-js').style.display =
+    (this.getElement('action').value == 'js') ? 'block' : 'none';
+}
+
+Rule.next_id = 0;
+
+function loadRules() {
+  var rules = localStorage.rules;
+  try {
+    JSON.parse(rules).forEach(function(rule) {new Rule(rule);});
+  } catch (e) {
+    localStorage.rules = JSON.stringify([]);
+  }
+}
+
+function storeRules() {
+  localStorage.rules = JSON.stringify(Array.prototype.slice.apply(
+      document.getElementById('rules').childNodes).map(function(node) {
+    node.rule.render();
+    return {matcher: node.rule.getElement('matcher').value,
+            match_param: node.rule.getElement('match-param').value,
+            action: node.rule.getElement('action').value,
+            action_js: node.rule.getElement('action-js').value,
+            enabled: node.rule.getElement('enabled').checked};
+  }));
+}
+
+window.onload = function() {
+  loadRules();
+  document.getElementById('new').onclick = function() {
+    new Rule();
+  };
+}
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json b/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
index 3f59ae2..83d05e7 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
@@ -1,8 +1,8 @@
 {"extName": {
-   "message": "Modern Download Manager",
+   "message": "Download Manager Button",
    "description": "Extension name"},
  "extDesc": {
-   "message": "Modern Download Manager User Interface for Google Chrome",
+   "message": "Browser Action Download Manager User Interface for Google Chrome",
    "description": "Extension description"},
  "badChromeVersion": {
    "message": "The downloads API is only available on the canary, dev, and beta channels.",
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js b/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js
index 28e6075..b1f8f2c 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js
@@ -21,30 +21,33 @@
   ctx.stroke();
 }
 
-function drawProgressSpinner(ctx, stage) {
+Math.TAU = 2 * Math.PI;  // http://tauday.com/tau-manifesto
+
+function drawProgressArc(ctx, startAngle, endAngle) {
   var center = ctx.canvas.width/2;
-  var radius = center*0.9;
-  const segments = 16;
-  var segArc = 2 * Math.PI / segments;
   ctx.lineWidth = Math.round(ctx.canvas.width*0.1);
+  ctx.beginPath();
+  ctx.moveTo(center, center);
+  ctx.arc(center, center, center * 0.9, startAngle, endAngle, false);
+  ctx.fill();
+  ctx.stroke();
+}
+
+function drawUnknownProgressSpinner(ctx) {
+  var center = ctx.canvas.width/2;
+  const segments = 16;
+  var segArc = Math.TAU / segments;
   for (var seg = 0; seg < segments; ++seg) {
-    var color = ((stage == 'm') ? ((seg % 2) == 0) : (seg <= stage));
     ctx.fillStyle = ctx.strokeStyle = (
-      color ? colors.progressColor : colors.background);
-    ctx.moveTo(center, center);
-    ctx.beginPath();
-    ctx.arc(center, center, radius, (seg-4)*segArc, (seg-3)*segArc, false);
-    ctx.lineTo(center, center);
-    ctx.fill();
-    ctx.stroke();
+      ((seg % 2) == 0) ? colors.progressColor : colors.background);
+    drawProgressArc(ctx, (seg-4)*segArc, (seg-3)*segArc);
   }
-  ctx.strokeStyle = colors.background;
-  radius += ctx.lineWidth-1;
-  drawLine(ctx, center-radius, center, center+radius, center);
-  drawLine(ctx, center, center-radius, center, center+radius);
-  radius *= Math.sin(Math.PI/4);
-  drawLine(ctx, center-radius, center-radius, center+radius, center+radius);
-  drawLine(ctx, center-radius, center+radius, center+radius, center-radius);
+}
+
+function drawProgressSpinner(ctx, stage) {
+  ctx.fillStyle = ctx.strokeStyle = colors.progressColor;
+  var clocktop = -Math.TAU/4;
+  drawProgressArc(ctx, clocktop, clocktop + (stage * Math.TAU));
 }
 
 function drawArrow(ctx) {
@@ -102,7 +105,7 @@
 function drawCompleteBadge(ctx) {
   var s = ctx.canvas.width/100;
   ctx.beginPath();
-  ctx.arc(s*75, s*75, s*15, 0, 2*Math.PI, false);
+  ctx.arc(s*75, s*75, s*15, 0, Math.TAU, false);
   ctx.fillStyle = colors.complete;
   ctx.fill();
   ctx.strokeStyle = colors.background;
@@ -110,20 +113,25 @@
   ctx.stroke();
 }
 
-function drawIcon(side, stage, badge) {
+function drawIcon(side, options) {
   var canvas = document.createElement('canvas');
   canvas.width = canvas.height = side;
   document.body.appendChild(canvas);
   var ctx = canvas.getContext('2d');
-  if (stage != 'n') {
-    drawProgressSpinner(ctx, stage);
+  if (options.anyInProgress) {
+    if (options.anyMissingTotalBytes) {
+      drawUnknownProgressSpinner(ctx);
+    } else {
+      drawProgressSpinner(ctx, (options.totalBytesReceived /
+                                options.totalTotalBytes));
+    }
   }
   drawArrow(ctx);
-  if (badge == 'd') {
+  if (options.anyDangerous) {
     drawDangerBadge(ctx);
-  } else if (badge == 'p') {
+  } else if (options.anyPaused) {
     drawPausedBadge(ctx);
-  } else if (badge == 'c') {
+  } else if (options.anyRecentlyCompleted) {
     drawCompleteBadge(ctx);
   }
   return canvas;
@@ -144,9 +152,9 @@
   }
 }
 
-function setBrowserActionIcon(stage, badge) {
-  var canvas1 = drawIcon(19, stage, badge);
-  var canvas2 = drawIcon(38, stage, badge);
+function setBrowserActionIcon(options) {
+  var canvas1 = drawIcon(19, options);
+  var canvas2 = drawIcon(38, options);
   var imageData = {};
   imageData['' + canvas1.width] = canvas1.getContext('2d').getImageData(
         0, 0, canvas1.width, canvas1.height);
@@ -161,45 +169,41 @@
   pollProgress.tid = -1;
   chrome.downloads.search({}, function(items) {
     var popupLastOpened = parseInt(localStorage.popupLastOpened);
-    var totalTotalBytes = 0;
-    var totalBytesReceived = 0;
-    var anyMissingTotalBytes = false;
-    var anyDangerous = false;
-    var anyPaused = false;
-    var anyRecentlyCompleted = false;
-    var anyInProgress = false;
+    var options = {anyMissingTotalBytes: false,
+                   anyInProgress: false,
+                   anyRecentlyCompleted: false,
+                   anyPaused: false,
+                   anyDangerous: false,
+                   totalBytesReceived: 0,
+                   totalTotalBytes: 0};
     items.forEach(function(item) {
       if (item.state == 'in_progress') {
-        anyInProgress = true;
+        options.anyInProgress = true;
         if (item.totalBytes) {
-          totalTotalBytes += item.totalBytes;
-          totalBytesReceived += item.bytesReceived;
+          options.totalTotalBytes += item.totalBytes;
+          options.totalBytesReceived += item.bytesReceived;
         } else {
-          anyMissingTotalBytes = true;
+          options.anyMissingTotalBytes = true;
         }
         var dangerous = ((item.danger != 'safe') &&
                          (item.danger != 'accepted'));
-        anyDangerous = anyDangerous || dangerous;
-        anyPaused = anyPaused || item.paused;
+        options.anyDangerous = options.anyDangerous || dangerous;
+        options.anyPaused = options.anyPaused || item.paused;
       } else if ((item.state == 'complete') && item.endTime && !item.error) {
-        var ended = (new Date(item.endTime)).getTime();
-        var recentlyCompleted = (ended >= popupLastOpened);
-        anyRecentlyCompleted = anyRecentlyCompleted || recentlyCompleted;
+        options.anyRecentlyCompleted = (
+          options.anyRecentlyCompleted ||
+          ((new Date(item.endTime)).getTime() >= popupLastOpened));
         maybeOpen(item.id);
       }
     });
-    var stage = !anyInProgress ? 'n' : (anyMissingTotalBytes ? 'm' :
-      parseInt((totalBytesReceived / totalTotalBytes) * 15));
-    var badge = anyDangerous ? 'd' : (anyPaused ? 'p' :
-      (anyRecentlyCompleted ? 'c' : ''));
 
-    var targetIcon = stage + ' ' + badge;
+    var targetIcon = JSON.stringify(options);
     if (sessionStorage.currentIcon != targetIcon) {
-      setBrowserActionIcon(stage, badge);
+      setBrowserActionIcon(options);
       sessionStorage.currentIcon = targetIcon;
     }
 
-    if (anyInProgress &&
+    if (options.anyInProgress &&
         (pollProgress.tid < 0)) {
       pollProgress.start();
     }
@@ -249,7 +253,7 @@
   }
   if (request == 'icons') {
     [16, 19, 38, 128].forEach(function(s) {
-      var canvas = drawIcon(s, 'n', '');
+      var canvas = drawIcon(s);
       chrome.downloads.download({
         url: canvas.toDataURL('image/png', 1.0),
         filename: 'icon' + s + '.png',
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json b/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
index 6ae38ad..638e094 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
@@ -1,5 +1,5 @@
 {"name": "__MSG_extName__",
- "version": "0.1",
+ "version": "0.2",
  "manifest_version": 2,
  "description": "__MSG_extDesc__",
  "icons": {"128": "icon128.png"},
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css
index 967d512..bc19d1e 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css
@@ -23,6 +23,7 @@
 
 #head {
   position: fixed;
+  z-index: 2;
   width: 100%;
   left: 0;
   top: 0;
@@ -106,7 +107,7 @@
   position: absolute;
   border: 1px solid grey;
   background: white;
-  z-index: 1;
+  z-index: 3;
 }
 
 .complete-size,
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
index 6c88e3d..4a64dab 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
@@ -120,6 +120,16 @@
   return chrome.i18n.getMessage(prefix + 'Seconds', [seconds]);
 }
 
+function ratchetWidth(w) {
+  var current = parseInt(document.body.style.minWidth) || 0;
+  document.body.style.minWidth = Math.max(w, current) + 'px';
+}
+
+function ratchetHeight(h) {
+  var current = parseInt(document.body.style.minHeight) || 0;
+  document.body.style.minHeight = Math.max(h, current) + 'px';
+}
+
 function binarySearch(array, target, cmp) {
   var low = 0, high = array.length - 1, i, comparison;
   while (low <= high) {
@@ -219,9 +229,10 @@
   };
 
   item.more_mousemove = function(evt) {
+    var mouse = {x:evt.x, y:evt.y+document.body.scrollTop};
     if (item.getElement('more') &&
-        (pointInElement(evt, item.div) ||
-         pointInElement(evt, item.getElement('more')))) {
+        (pointInElement(mouse, item.div) ||
+         pointInElement(mouse, item.getElement('more')))) {
       return;
     }
     if (item.getElement('more')) {
@@ -229,7 +240,7 @@
     }
     window.removeEventListener('mousemove', item.more_mousemove);
   };
-  [item.getElement('icon'), item.getElement('more')].concat(
+  [item.div, item.getElement('more')].concat(
       item.getElement('more').children).forEach(function(elem) {
     elem.onmouseover = function() {
       arrayFrom(items_div.children).forEach(function(other) {
@@ -409,6 +420,13 @@
         item.startTime);
   }
 
+  ratchetWidth(item.getElement('icon').offsetWidth +
+               item.getElement('file-url').offsetWidth +
+               item.getElement('cancel').offsetWidth +
+               item.getElement('pause').offsetWidth +
+               item.getElement('resume').offsetWidth);
+  ratchetWidth(item.getElement('more').offsetWidth);
+
   this.maybeAccept();
 };
 
@@ -480,6 +498,8 @@
       DownloadItem.prototype.maybeAccept.accepting_danger) {
     return;
   }
+  ratchetWidth(400);
+  ratchetHeight(200);
   DownloadItem.prototype.maybeAccept.accepting_danger = true;
   chrome.downloads.acceptDanger(this.id, function() {
     DownloadItem.prototype.maybeAccept.accepting_danger = false;
@@ -714,10 +734,10 @@
   });
 
   window.onload = function() {
-    document.body.style.minWidth = (
+    ratchetWidth(
       document.getElementById('q-outer').offsetWidth +
       document.getElementById('clear-all').offsetWidth +
-      document.getElementById('open-folder').offsetWidth) + 'px';
+      document.getElementById('open-folder').offsetWidth);
     setLastOpened();
     loadI18nMessages();
     DownloadManager.loadItems.onWindowLoaded();
diff --git a/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/bg.js b/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/bg.js
index 1254bd1..1a717f1 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/bg.js
+++ b/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/bg.js
@@ -7,5 +7,9 @@
 
 chrome.downloads.onDeterminingFilename.addListener(function(item, suggest) {
   suggest({filename: item.filename,
-           conflict_action: 'overwrite'});
+           conflict_action: 'overwrite',
+           conflictAction: 'overwrite'});
+  // conflict_action was renamed to conflictAction in
+  // http://src.chromium.org/viewvc/chrome?view=rev&revision=214133
+  // which was first picked up in branch 1580.
 });
diff --git a/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json b/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json
index ad6b1b0..7a6e1f4 100644
--- a/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json
@@ -3,7 +3,7 @@
   "description": "Demonstrates usage and features of the event page",
   "version": "1.0",
   "manifest_version": 2,
-  "permissions": ["alarms", "tabs", "bookmarks", "declarativeWebRequest", "*://*.google.com/*"],
+  "permissions": ["alarms", "tabs", "bookmarks", "declarativeWebRequest", "*://*/*"],
   "background": {
     "scripts": ["background.js"],
     "persistent": false
diff --git a/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json b/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json
index a3c972d..ca9699c 100644
--- a/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json
@@ -3,7 +3,7 @@
   "version": "1.1",
   "description": "Adds a browser action that monitors resource usage of all browser processes.",
   "permissions": [
-    "experimental", "tabs"
+    "processes", "tabs"
   ],
   "browser_action": {
       "default_title": "Process Monitor",
diff --git a/chrome/common/extensions/docs/examples/api/processes/process_monitor/popup.js b/chrome/common/extensions/docs/examples/api/processes/process_monitor/popup.js
index b0ee288..61f00d5 100644
--- a/chrome/common/extensions/docs/examples/api/processes/process_monitor/popup.js
+++ b/chrome/common/extensions/docs/examples/api/processes/process_monitor/popup.js
@@ -4,7 +4,7 @@
 
 // Shows an updating list of process statistics.
 function init() {
-  chrome.experimental.processes.onUpdatedWithMemory.addListener(
+  chrome.processes.onUpdatedWithMemory.addListener(
     function(processes) {
       var table = "<table>\n" +
         "<tr><td><b>Process</b></td>" +
@@ -28,7 +28,7 @@
 
   document.getElementById("killProcess").onclick = function () {
     var procId = parseInt(prompt("Enter process ID"));
-    chrome.experimental.processes.terminate(procId);
+    chrome.processes.terminate(procId);
   }
 }
 
@@ -77,4 +77,4 @@
   return table;
 }
 
-document.addEventListener('DOMContentLoaded', init);
\ No newline at end of file
+document.addEventListener('DOMContentLoaded', init);
diff --git a/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json b/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json
index e321acf..bdbdb1e 100644
--- a/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json
@@ -3,7 +3,7 @@
   "version": "1.0",
   "description": "Adds a browser action showing which tabs share the current tab's process.",
   "permissions": [
-    "experimental", "tabs", "chrome://favicon/*"
+    "processes", "tabs", "chrome://favicon/*"
   ],
   "browser_action": {
       "default_title": "Show Tabs in this Process",
diff --git a/chrome/common/extensions/docs/examples/api/processes/show_tabs/popup.js b/chrome/common/extensions/docs/examples/api/processes/show_tabs/popup.js
index 76917a1..429d226 100644
--- a/chrome/common/extensions/docs/examples/api/processes/show_tabs/popup.js
+++ b/chrome/common/extensions/docs/examples/api/processes/show_tabs/popup.js
@@ -9,7 +9,7 @@
       var current = currentWindow.tabs.filter(function(tab) {
         return tab.active;
       })[0];
-      chrome.experimental.processes.getProcessIdForTab(current.id,
+      chrome.processes.getProcessIdForTab(current.id,
         function(pid) {
           var outputDiv = document.getElementById("tab-list");
           var titleDiv = document.getElementById("title");
@@ -38,7 +38,7 @@
 
     // Display tab in list if it is in the same process
     tabs.forEach(function(tab) {
-      chrome.experimental.processes.getProcessIdForTab(tab.id,
+      chrome.processes.getProcessIdForTab(tab.id,
         function(pid) {
           if (pid == processId) {
             displayTabInfo(tab.windowId, tab, outputDiv);
diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py
index a73a971..eec18e6 100644
--- a/chrome/common/extensions/docs/server2/api_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_data_source.py
@@ -102,6 +102,23 @@
   s = str(value)
   return ','.join([s[max(0, i - 3):i] for i in range(len(s), 0, -3)][::-1])
 
+def _GetAddRulesDefinitionFromEvents(events):
+  """Parses the dictionary |events| to find the definition of the method
+  addRules among functions of the type Event.
+  """
+  assert 'types' in events, \
+      'The dictionary |events| must contain the key "types".'
+  event_list = [t for t in events['types']
+                if 'name' in t and t['name'] == 'Event']
+  assert len(event_list) == 1, 'Exactly one type must be called "Event".'
+  event = event_list[0]
+  assert 'functions' in event, 'The type Event must contain "functions".'
+  result_list = [f for f in event['functions']
+                 if 'name' in f and f['name'] == 'addRules']
+  assert len(result_list) == 1, \
+      'Exactly one function must be called "addRules".'
+  return result_list[0]
+
 class _JSCModel(object):
   """Uses a Model from the JSON Schema Compiler and generates a dict that
   a Handlebar template can use for a data source.
@@ -113,6 +130,7 @@
                availability_finder,
                parse_cache,
                template_data_source,
+               add_rules_schema_function,
                idl=False):
     self._ref_resolver = ref_resolver
     self._disable_refs = disable_refs
@@ -122,6 +140,7 @@
     self._api_features = parse_cache.GetFromFile(
         '%s/_api_features.json' % svn_constants.API_PATH)
     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):
       self._namespace = None
@@ -146,15 +165,23 @@
   def ToDict(self):
     if self._namespace is None:
       return {}
-    return {
+    as_dict = {
       'name': self._namespace.name,
       'types': self._GenerateTypes(self._namespace.types.values()),
       'functions': self._GenerateFunctions(self._namespace.functions),
       'events': self._GenerateEvents(self._namespace.events),
       'properties': self._GenerateProperties(self._namespace.properties),
-      'intro_list': self._GetIntroTableList(),
-      'channel_warning': self._GetChannelWarning()
+      'introList': self._GetIntroTableList(),
+      'channelWarning': self._GetChannelWarning(),
+      'byName': {},
     }
+    # Make every type/function/event/property also accessible by name for
+    # rendering specific API entities rather than the whole thing at once, for
+    # example {{apis.manifestTypes.byName.ExternallyConnectable}}.
+    for item_type in ('types', 'functions', 'events', 'properties'):
+      as_dict['byName'].update(
+          (item['name'], item) for item in as_dict[item_type])
+    return as_dict
 
   def _GetIntroTableList(self):
     """Create a generic data structure that can be traversed by the templates
@@ -231,7 +258,7 @@
         manifest_content.append(make_code_node('"%s": {...}' % name))
       elif context == 'api':
         transitive_dependencies = (
-            self._api_features.get(context, {}).get('dependencies', []))
+            self._api_features.get(name, {}).get('dependencies', []))
         for transitive_dependency in transitive_dependencies:
           categorize_dependency(transitive_dependency)
       else:
@@ -285,7 +312,7 @@
     return None
 
   def _IsExperimental(self):
-     return self._namespace.name.startswith('experimental')
+    return self._namespace.name.startswith('experimental')
 
   def _GenerateTypes(self, types):
     return [self._GenerateType(t) for t in types]
@@ -336,24 +363,39 @@
     event_dict = {
       'name': event.simple_name,
       'description': self._FormatDescription(event.description),
-      'parameters': [self._GenerateProperty(p) for p in event.params],
-      'callback': self._GenerateCallback(event.callback),
       'filters': [self._GenerateProperty(f) for f in event.filters],
       'conditions': [self._GetLink(condition)
                      for condition in event.conditions],
       'actions': [self._GetLink(action) for action in event.actions],
       'supportsRules': event.supports_rules,
+      'supportsListeners': event.supports_listeners,
       'id': _CreateId(event, 'event')
     }
     if (event.parent is not None and
         not isinstance(event.parent, model.Namespace)):
       event_dict['parentName'] = event.parent.simple_name
-    if event.callback is not None:
-      # Show the callback as an extra parameter.
-      event_dict['parameters'].append(
-          self._GenerateCallbackProperty(event.callback))
-    if len(event_dict['parameters']) > 0:
-      event_dict['parameters'][-1]['last'] = True
+    # For the addRules method we can use the common definition, because addRules
+    # has the same signature for every event.
+    if event.supports_rules:
+      event_dict['addRulesFunction'] = self._add_rules_schema_function()
+    # We need to create the method description for addListener based on the
+    # information stored in |event|.
+    if event.supports_listeners:
+      callback_object = model.Function(parent=event,
+                                       name='callback',
+                                       json={},
+                                       namespace=event.parent,
+                                       origin='')
+      callback_object.params = event.params
+      if event.callback:
+        callback_object.callback = event.callback
+      callback_parameters = self._GenerateCallbackProperty(callback_object)
+      callback_parameters['last'] = True
+      event_dict['addListenerFunction'] = {
+        'name': 'addListener',
+        'callback': self._GenerateFunction(callback_object),
+        'parameters': [callback_parameters]
+      }
     return event_dict
 
   def _GenerateCallback(self, callback):
@@ -509,6 +551,9 @@
       self._ref_resolver_factory = None
       self._samples_data_source_factory = None
 
+      # This caches the result of _LoadAddRulesSchema.
+      self._add_rules_schema = None
+
     def SetSamplesDataSourceFactory(self, samples_data_source_factory):
       self._samples_data_source_factory = samples_data_source_factory
 
@@ -546,6 +591,15 @@
                            samples,
                            disable_refs)
 
+    def _LoadAddRulesSchema(self):
+      """ All events supporting rules have the addRules method. We source its
+      description from Event in events.json.
+      """
+      if self._add_rules_schema is None:
+        self._add_rules_schema = _GetAddRulesDefinitionFromEvents(
+            self._json_cache.GetFromFile('%s/events.json' % self._base_path))
+      return self._add_rules_schema
+
     def _LoadJsonAPI(self, api, disable_refs):
       return _JSCModel(
           json_parse.Parse(api)[0],
@@ -553,7 +607,8 @@
           disable_refs,
           self._availability_finder,
           self._parse_cache,
-          self._template_data_source).ToDict()
+          self._template_data_source,
+          self._LoadAddRulesSchema).ToDict()
 
     def _LoadIdlAPI(self, api, disable_refs):
       idl = idl_parser.IDLParser().ParseData(api)
@@ -564,6 +619,7 @@
           self._availability_finder,
           self._parse_cache,
           self._template_data_source,
+          self._LoadAddRulesSchema,
           idl=True).ToDict()
 
     def _GetIDLNames(self, base_dir, apis):
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 2f4d25d..8f452b9 100755
--- a/chrome/common/extensions/docs/server2/api_data_source_test.py
+++ b/chrome/common/extensions/docs/server2/api_data_source_test.py
@@ -13,7 +13,8 @@
                              _FormatValue,
                              _RemoveNoDocs,
                              _DetectInlineableTypes,
-                             _InlineDocs)
+                             _InlineDocs,
+                             _GetAddRulesDefinitionFromEvents)
 from collections import namedtuple
 from compiled_file_system import CompiledFileSystem
 from file_system import FileNotFoundError
@@ -96,7 +97,8 @@
                       False,
                       FakeAvailabilityFinder(),
                       self._json_cache,
-                      FakeTemplateDataSource()).ToDict()
+                      FakeTemplateDataSource(),
+                      None).ToDict()
     self.assertEquals('type-TypeA', dict_['types'][0]['id'])
     self.assertEquals('property-TypeA-b',
                       dict_['types'][0]['properties'][0]['id'])
@@ -114,7 +116,8 @@
                       False,
                       FakeAvailabilityFinder(),
                       self._json_cache,
-                      FakeTemplateDataSource()).ToDict()
+                      FakeTemplateDataSource(),
+                      None).ToDict()
     self.assertEquals(expected_json, dict_)
 
   def testFormatValue(self):
@@ -128,7 +131,8 @@
                       False,
                       FakeAvailabilityFinder(),
                       self._json_cache,
-                      FakeTemplateDataSource()).ToDict()
+                      FakeTemplateDataSource(),
+                      None).ToDict()
     self.assertEquals(_MakeLink('ref_test.html#type-type2', 'type2'),
                       _GetType(dict_, 'type1')['description'])
     self.assertEquals(
@@ -151,7 +155,8 @@
                       False,
                       FakeAvailabilityFinder(),
                       self._json_cache,
-                      FakeTemplateDataSource())
+                      FakeTemplateDataSource(),
+                      None)
     expected_list = [
       { 'title': 'Description',
         'content': [
@@ -286,5 +291,61 @@
     _InlineDocs(schema)
     self.assertEqual(expected_schema, schema)
 
+  def testGetAddRulesDefinitionFromEvents(self):
+    events = {}
+    # Missing 'types' completely.
+    self.assertRaises(AssertionError, _GetAddRulesDefinitionFromEvents, events)
+
+    events['types'] = []
+    # No type 'Event' defined.
+    self.assertRaises(AssertionError, _GetAddRulesDefinitionFromEvents, events)
+
+    events['types'].append({ 'name': 'Event' })
+    # 'Event' has no 'functions'.
+    self.assertRaises(AssertionError, _GetAddRulesDefinitionFromEvents, events)
+
+    events['types'][0]['functions'] = []
+    # No 'functions' named 'addRules'.
+    self.assertRaises(AssertionError, _GetAddRulesDefinitionFromEvents, events)
+
+    add_rules = { "name": "addRules" }
+    events['types'][0]['functions'].append(add_rules)
+    self.assertEqual(add_rules, _GetAddRulesDefinitionFromEvents(events))
+
+    events['types'][0]['functions'].append(add_rules)
+    # Duplicates are an error.
+    self.assertRaises(AssertionError, _GetAddRulesDefinitionFromEvents, events)
+
+  def _FakeLoadAddRulesSchema(self):
+    events = self._LoadJSON('add_rules_def_test.json')
+    return _GetAddRulesDefinitionFromEvents(events)
+
+  def testAddRules(self):
+    data_source = FakeAPIAndListDataSource(
+        self._LoadJSON('test_file_data_source.json'))
+    dict_ = _JSCModel(self._LoadJSON('add_rules_test.json')[0],
+                      self._CreateRefResolver('test_file_data_source.json'),
+                      False,
+                      FakeAvailabilityFinder(),
+                      self._json_cache,
+                      FakeTemplateDataSource(),
+                      self._FakeLoadAddRulesSchema).ToDict()
+    # Check that the first event has the addRulesFunction defined.
+    self.assertEquals('tester', dict_['name'])
+    self.assertEquals('rules', dict_['events'][0]['name'])
+    self.assertEquals('notable_name_to_check_for',
+                      dict_['events'][0]['addRulesFunction'][
+                          'parameters'][0]['name'])
+
+    # Check that the second event has no addRulesFunction defined.
+    self.assertEquals('noRules', dict_['events'][1]['name'])
+    self.assertFalse('addRulesFunction' in dict_['events'][1])
+    # But addListener should be defined.
+    self.assertEquals('tester', dict_['name'])
+    self.assertEquals('noRules', dict_['events'][1]['name'])
+    self.assertEquals('callback',
+                      dict_['events'][0]['addListenerFunction'][
+                          'parameters'][0]['name'])
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/chrome/common/extensions/docs/server2/api_list_data_source.py b/chrome/common/extensions/docs/server2/api_list_data_source.py
index bddec89..2e35ad6 100644
--- a/chrome/common/extensions/docs/server2/api_list_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_list_data_source.py
@@ -78,7 +78,7 @@
     names = []
     for platform in ['apps', 'extensions']:
       for category in ['chrome', 'experimental', 'private']:
-       names.extend(self.get(platform).get(category))
+        names.extend(self.get(platform).get(category))
     return [api_name['name'] for api_name in names]
 
   def get(self, key):
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index 9c33888..224939f 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-18-0
+version: 2-27-0
 runtime: python27
 api_version: 1
 threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/appengine_wrappers.py b/chrome/common/extensions/docs/server2/appengine_wrappers.py
index 86a43e4..130dad1 100644
--- a/chrome/common/extensions/docs/server2/appengine_wrappers.py
+++ b/chrome/common/extensions/docs/server2/appengine_wrappers.py
@@ -18,6 +18,14 @@
 def IsDevServer():
   return os.environ.get('SERVER_SOFTWARE', '').find('Development') == 0
 
+def IsDeadlineExceededError(error):
+  '''A general way of determining whether |error| is a DeadlineExceededError,
+  since there are 3 different types thrown by AppEngine and we might as well
+  handle them all the same way. For more info see:
+  https://developers.google.com/appengine/articles/deadlineexceedederrors
+  '''
+  return error.__class__.__name__ == 'DeadlineExceededError'
+
 # This will attempt to import the actual App Engine modules, and if it fails,
 # they will be replaced with fake modules. This is useful during testing.
 try:
@@ -29,7 +37,6 @@
   from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty
   import google.appengine.ext.db as db
   import google.appengine.ext.webapp as webapp
-  from google.appengine.runtime import DeadlineExceededError
 except ImportError:
   import re
   from StringIO import StringIO
@@ -65,9 +72,6 @@
     def wait(self):
       pass
 
-  class DeadlineExceededError(Exception):
-    pass
-
   class FakeUrlFetch(object):
     """A fake urlfetch module that uses the current
     |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers.
diff --git a/chrome/common/extensions/docs/server2/availability_finder.py b/chrome/common/extensions/docs/server2/availability_finder.py
index 69028b0..a0b6c45 100644
--- a/chrome/common/extensions/docs/server2/availability_finder.py
+++ b/chrome/common/extensions/docs/server2/availability_finder.py
@@ -226,7 +226,17 @@
 
     # Check for the API in the development channels.
     availability = None
+
     for channel_info in self._branch_utility.GetAllChannelInfo():
+      if channel_info.channel == 'trunk':
+        # Don't check trunk, since (a) there's no point, we know it's going to
+        # be available there, and (b) there is a bug with the current
+        # architecture and design of HostFileSystemCreator, where creating
+        # 'trunk' ignores the pinned revision (in fact, it bypasses every
+        # difference including whether the file system is patched).
+        # TODO(kalman): Fix HostFileSystemCreator and update this comment.
+        break
+
       available_channel = self._GetAvailableChannelForVersion(
           api_name,
           channel_info.version)
@@ -239,8 +249,9 @@
                                         channel_info.version)
         break
 
-    # The API should at least be available on trunk. It's a bug otherwise.
-    assert availability, 'No availability found for %s' % api_name
+    if availability is None:
+      trunk_info = self._branch_utility.GetChannelInfo('trunk')
+      availability = AvailabilityInfo(trunk_info.channel, trunk_info.version)
 
     # If the API is in stable, find the chrome version in which it became
     # stable.
diff --git a/chrome/common/extensions/docs/server2/compiled_file_system.py b/chrome/common/extensions/docs/server2/compiled_file_system.py
index 429d7f0..928d93d 100644
--- a/chrome/common/extensions/docs/server2/compiled_file_system.py
+++ b/chrome/common/extensions/docs/server2/compiled_file_system.py
@@ -82,7 +82,7 @@
     version = self._file_system.Stat(path).version
     cache_entry = self._list_object_store.Get(path).Get()
     if (cache_entry is not None) and (version == cache_entry.version):
-        return cache_entry._cache_data
+      return cache_entry._cache_data
     cache_data = self._populate_function(path, self._RecursiveList(path))
     self._list_object_store.Set(path, _CacheEntry(cache_data, version))
     return cache_data
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
index 902bb80..2a5bc64 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-18-0
+  target: 2-27-0
diff --git a/chrome/common/extensions/docs/server2/cron_servlet.py b/chrome/common/extensions/docs/server2/cron_servlet.py
index 15cd3d3..3a6b325 100644
--- a/chrome/common/extensions/docs/server2/cron_servlet.py
+++ b/chrome/common/extensions/docs/server2/cron_servlet.py
@@ -8,9 +8,10 @@
 
 from app_yaml_helper import AppYamlHelper
 from appengine_wrappers import (
-    GetAppVersion, DeadlineExceededError, IsDevServer, logservice)
+    GetAppVersion, IsDeadlineExceededError, IsDevServer, logservice)
 from branch_utility import BranchUtility
 from compiled_file_system import CompiledFileSystem
+from data_source_registry import DataSourceRegistry
 from empty_dir_file_system import EmptyDirFileSystem
 from file_system_util import CreateURLsFromPaths
 from github_file_system import GithubFileSystem
@@ -28,6 +29,54 @@
   def CreateServerInstance(self):
     return self._server_instance
 
+class _CronLogger(object):
+  '''Wraps the logging.* methods to prefix them with 'cron' and flush
+  immediately. The flushing is important because often these cron runs time
+  out and we lose the logs.
+  '''
+  def info(self, msg, *args):    self._log(logging.info, msg, args)
+  def warning(self, msg, *args): self._log(logging.warning, msg, args)
+  def error(self, msg, *args):   self._log(logging.error, msg, args)
+
+  def _log(self, logfn, msg, args):
+    try:
+      logfn('cron: %s' % msg, *args)
+    finally:
+      logservice.flush()
+
+_cronlog = _CronLogger()
+
+def _RequestEachItem(title, items, request_callback):
+  '''Runs a task |request_callback| named |title| for each item in |items|.
+  |request_callback| must take an item and return a servlet response.
+  Returns true if every item was successfully run, false if any return a
+  non-200 response or raise an exception.
+  '''
+  _cronlog.info('%s: starting', title)
+  success_count, failure_count = 0, 0
+  start_time = time.time()
+  try:
+    for i, item in enumerate(items):
+      def error_message(detail):
+        return '%s: error rendering %s (%s of %s): %s' % (
+            title, item, i + 1, len(items), detail)
+      try:
+        response = request_callback(item)
+        if response.status == 200:
+          success_count += 1
+        else:
+          _cronlog.error(error_message('response status %s', response.status))
+          failure_count += 1
+      except Exception as e:
+        _cronlog.error(error_message(traceback.format_exc()))
+        failure_count += 1
+        if IsDeadlineExceededError(e): raise
+  finally:
+    elapsed_seconds = time.time() - start_time
+    _cronlog.info('%s: rendered %s of %s with %s failures in %s seconds',
+        title, success_count, len(items), failure_count, elapsed_seconds);
+  return success_count == len(items)
+
 class CronServlet(Servlet):
   '''Servlet which runs a cron job.
   '''
@@ -54,11 +103,18 @@
       return GetAppVersion()
 
   def Get(self):
-    # Crons often time out, and when they do *and* then eventually try to
-    # flush logs they die. Turn off autoflush and manually do so at the end.
+    # Crons often time out, and if they do we need to make sure to flush the
+    # logs before the process gets killed (Python gives us a couple of
+    # seconds).
+    #
+    # So, manually flush logs at the end of the cron run. However, sometimes
+    # even that isn't enough, which is why in this file we use _cronlog and
+    # make it flush the log every time its used.
     logservice.AUTOFLUSH_ENABLED = False
     try:
       return self._GetImpl()
+    except BaseException:
+      _cronlog.error('Caught top-level exception! %s', traceback.format_exc())
     finally:
       logservice.flush()
 
@@ -69,100 +125,90 @@
     # the time these won't have changed since the last cron run, so it's a
     # little wasteful, but hopefully rendering is really fast (if it isn't we
     # have a problem).
-    logging.info('cron: starting')
+    _cronlog.info('starting')
 
     # This is returned every time RenderServlet wants to create a new
     # ServerInstance.
+    #
+    # TODO(kalman): IMPORTANT. This sometimes throws an exception, breaking
+    # everything. Need retry logic at the fetcher level.
     server_instance = self._GetSafeServerInstance()
 
-    def get_via_render_servlet(path):
+    def render(path):
       request = Request(path, self._request.host, self._request.headers)
       delegate = _SingletonRenderServletDelegate(server_instance)
       return RenderServlet(request, delegate).Get()
 
-    def run_cron_for_dir(d, path_prefix=''):
-      success = True
-      start_time = time.time()
-      files = dict(
-          CreateURLsFromPaths(server_instance.host_file_system, d, path_prefix))
-      logging.info('cron: rendering %s files from %s...' % (len(files), d))
-      try:
-        for i, path in enumerate(files):
-          error = None
-          try:
-            response = get_via_render_servlet(path)
-            if response.status != 200:
-              error = 'Got %s response' % response.status
-          except DeadlineExceededError:
-            logging.error(
-                'cron: deadline exceeded rendering %s (%s of %s): %s' % (
-                    path, i + 1, len(files), traceback.format_exc()))
-            raise
-          except error:
-            pass
-          if error:
-            logging.error('cron: error rendering %s: %s' % (path, error))
-            success = False
-      finally:
-        logging.info('cron: rendering %s files from %s took %s seconds' % (
-            len(files), d, time.time() - start_time))
-      return success
+    def request_files_in_dir(path, prefix=''):
+      '''Requests every file found under |path| in this host file system, with
+      a request prefix of |prefix|.
+      '''
+      files = [name for name, _ in
+          CreateURLsFromPaths(server_instance.host_file_system, path, prefix)]
+      return _RequestEachItem(path, files, render)
 
-    success = True
+    results = []
+
     try:
-      # Render all of the publicly accessible files.
-      cron_runs = [
-        # Note: rendering the public templates will pull in all of the private
-        # templates.
-        (svn_constants.PUBLIC_TEMPLATE_PATH, ''),
-        # Note: rendering the public templates will have pulled in the .js
-        # and manifest.json files (for listing examples on the API reference
-        # pages), but there are still images, CSS, etc.
-        (svn_constants.STATIC_PATH, 'static/'),
-      ]
+      # Rendering the public templates will also pull in all of the private
+      # templates.
+      results.append(request_files_in_dir(svn_constants.PUBLIC_TEMPLATE_PATH))
+
+      # Rendering the public templates will have pulled in the .js and
+      # manifest.json files (for listing examples on the API reference pages),
+      # but there are still images, CSS, etc.
+      results.append(request_files_in_dir(svn_constants.STATIC_PATH,
+                                          prefix='static/'))
+
+      # Samples are too expensive to run on the dev server, where there is no
+      # parallel fetch.
       if not IsDevServer():
-        cron_runs.append(
-            (svn_constants.EXAMPLES_PATH, 'extensions/examples/'))
+        # Fetch each individual sample file.
+        results.append(request_files_in_dir(svn_constants.EXAMPLES_PATH,
+                                            prefix='extensions/examples/'))
 
-      # Note: don't try to short circuit any of this stuff. We want to run
-      # the cron for all the directories regardless of intermediate
-      # failures.
-      for path, path_prefix in cron_runs:
-        success = run_cron_for_dir(path, path_prefix=path_prefix) and success
-
-      # TODO(kalman): Generic way for classes to request cron access. The next
-      # two special cases are ugly. It would potentially greatly speed up cron
-      # runs, too.
-
-      # Extension examples have zip files too. Well, so do apps, but the app
-      # file system doesn't get the Offline treatment so they don't need cron.
-      if not IsDevServer():
-        manifest_json = 'manifest.json'
+        # Fetch the zip file of each example (contains all the individual
+        # files).
         example_zips = []
         for root, _, files in server_instance.host_file_system.Walk(
             svn_constants.EXAMPLES_PATH):
           example_zips.extend(
-              root + '.zip' for name in files if name == manifest_json)
-        logging.info('cron: rendering %s example zips...' % len(example_zips))
+              root + '.zip' for name in files if name == 'manifest.json')
+        results.append(_RequestEachItem(
+            'example zips',
+            example_zips,
+            lambda path: render('extensions/examples/' + path)))
+
+      def run_cron(data_source):
+        title = data_source.__class__.__name__
+        _cronlog.info('%s: starting' % title)
         start_time = time.time()
         try:
-          success = success and all(
-              get_via_render_servlet('extensions/examples/%s' % z).status == 200
-              for z in example_zips)
+          data_source.Cron()
+        except Exception as e:
+          _cronlog.error('%s: error %s' % (title, traceback.format_exc()))
+          results.append(False)
+          if IsDeadlineExceededError(e): raise
         finally:
-          logging.info('cron: rendering %s example zips took %s seconds' % (
-              len(example_zips), time.time() - start_time))
+          _cronlog.info(
+              '%s: took %s seconds' % (title, time.time() - start_time))
 
-    except DeadlineExceededError:
-      success = False
+      for data_source in DataSourceRegistry.AsTemplateData(
+          server_instance).values():
+        run_cron(data_source)
 
-    logging.info('cron: running Redirector cron...')
-    server_instance.redirector.Cron()
+      run_cron(server_instance.redirector)
 
-    logging.info('cron: finished (%s)' % ('success' if success else 'failure',))
-
-    return (Response.Ok('Success') if success else
-            Response.InternalError('Failure'))
+    except Exception:
+      results.append(False)
+      # This should never actually happen (each cron step does its own
+      # conservative error checking), so re-raise no matter what it is.
+      raise
+    finally:
+      success = all(results)
+      _cronlog.info('finished (%s)', 'success' if success else 'FAILED')
+      return (Response.Ok('Success') if success else
+              Response.InternalError('Failure'))
 
   def _GetSafeServerInstance(self):
     '''Returns a ServerInstance with a host file system at a safe revision,
@@ -188,8 +234,8 @@
     safe_revision = app_yaml_handler.GetFirstRevisionGreaterThan(
         delegate.GetAppVersion()) - 1
 
-    logging.info('cron: app version %s is out of date, safe is %s' % (
-        delegate.GetAppVersion(), safe_revision))
+    _cronlog.info('app version %s is out of date, safe is %s',
+        delegate.GetAppVersion(), safe_revision)
 
     return self._CreateServerInstance(safe_revision)
 
diff --git a/chrome/common/extensions/docs/server2/cron_servlet_test.py b/chrome/common/extensions/docs/server2/cron_servlet_test.py
index 07775eb..dc60ab5 100755
--- a/chrome/common/extensions/docs/server2/cron_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/cron_servlet_test.py
@@ -97,7 +97,10 @@
             'extensions': {
               'storage.html': 'storage.html contents'
             },
-          }
+          },
+          'json': {
+            'strings.json': '{}'
+          },
         }
       }
     }
diff --git a/chrome/common/extensions/docs/server2/data_source.py b/chrome/common/extensions/docs/server2/data_source.py
new file mode 100644
index 0000000..6ca3da7
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/data_source.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.
+
+class DataSource(object):
+  '''A DataSource presents data to the template system.
+
+  DataSources are created with a ServerInstance. Anything in the ServerInstance
+  can be used by the DataSource to create or modify data into a form more
+  appropriate for usage by the template system.
+
+  DataSources may not share data with other DataSources. The output of a
+  DataSource is only useful to templates. Any data that must be shared, or is
+  useful in general, should be moved into ServerInstance.
+  '''
+  def Cron(self):
+    '''Must cache all files needed by |get| to persist them. Called on a live
+    file system and can access files not in cache.
+    '''
+    raise NotImplementedError(self.__class__)
+
+  def get(self, key):
+    '''Returns a dictionary or list that can be consumed by a template. Called
+    on an offline file system and can only access files in the cache.
+    '''
+    raise NotImplementedError(self.__class__)
diff --git a/chrome/common/extensions/docs/server2/data_source_registry.py b/chrome/common/extensions/docs/server2/data_source_registry.py
new file mode 100644
index 0000000..5aafeb6
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/data_source_registry.py
@@ -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.
+
+from strings_data_source import StringsDataSource
+
+class DataSourceRegistry(object):
+  '''Collects all DataSources and creates a context for templates to be rendered
+  in. All DataSources must conform to the DataSource interface.
+  '''
+  @staticmethod
+  def AsTemplateData(server_instance):
+    '''Return a context that can be used to render templates.
+    '''
+    registry = {
+      'strings': StringsDataSource
+    }
+
+    return dict(
+        (name, cls(server_instance)) for name, cls in registry.iteritems())
diff --git a/chrome/common/extensions/docs/server2/datastore_models.py b/chrome/common/extensions/docs/server2/datastore_models.py
index c9bbe0d..c05a0b9 100644
--- a/chrome/common/extensions/docs/server2/datastore_models.py
+++ b/chrome/common/extensions/docs/server2/datastore_models.py
@@ -2,8 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from appengine_wrappers import db
 import cPickle
+import traceback
+
+from appengine_wrappers import db
 
 # A collection of the data store models used throughout the server.
 # These values are global within datastore.
@@ -13,7 +15,16 @@
 
   @classmethod
   def CreateKey(cls, namespace, key):
-    return db.Key.from_path(cls.__name__, '%s/%s' % (namespace, key))
+    path = '%s/%s' % (namespace, key)
+    try:
+      return db.Key.from_path(cls.__name__, path)
+    except Exception:
+      # Probably AppEngine's BadValueError for the name being too long, but
+      # it's not documented which errors can actually be thrown here, so catch
+      # 'em all.
+      raise ValueError(
+          'Exception thrown when trying to create db.Key from path %s: %s' % (
+              path, traceback.format_exc()))
 
   @classmethod
   def CreateItem(cls, namespace, key, value):
diff --git a/chrome/common/extensions/docs/server2/features_utility.py b/chrome/common/extensions/docs/server2/features_utility.py
new file mode 100644
index 0000000..8db2819
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/features_utility.py
@@ -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.
+
+from copy import deepcopy
+
+def Parse(features_json):
+  '''Standardize the raw features file json |features_json| into a more regular
+  format. Return a dictionary of features, keyed by name. Each feature is
+  guaranteed to have a 'name' attribute and a 'platforms' attribute that is a
+  list of platforms the feature is relevant to. Valid platforms are 'app' or
+  'extension'. Other optional keys may be present in each feature.
+
+  Features with a 'whitelist' are only relevant to apps or extensions on that
+  whitelist and are not included in the retured features dictionary.
+  '''
+  features = {}
+
+  for name, value in features_json.iteritems():
+    # Some feature names corrispond 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
+
+    if 'whitelist' in value:
+      continue
+
+    features[name] = { 'platforms': [] }
+
+    platforms = value.pop('extension_types')
+    if platforms == 'all' or 'platform_app' in platforms:
+      features[name]['platforms'].append('app')
+    if platforms == 'all' or 'extension' in platforms:
+      features[name]['platforms'].append('extension')
+
+    features[name]['name'] = name
+    features[name].update(value)
+
+  return features
+
+def Filtered(features, platform=None):
+  '''Create a new features dictionary from |features| that contains only items
+  relevant to |platform|. Items retained are deepcopied. Returns new features
+  dictionary.
+  '''
+  filtered_features = {}
+
+  for name, feature in features.iteritems():
+    if not platform or platform in feature['platforms']:
+      filtered_features[name] = deepcopy(feature)
+
+  return filtered_features
+
+def MergedWith(features, other):
+  '''Merge |features| with an additional dictionary to create a new features
+  dictionary. If a feature is common to both |features| and |other|, then it is
+  merged using the standard dictionary update instead of being overwritten.
+  Returns the new features dictionary.
+  '''
+  for key, value in other.iteritems():
+    if key in features:
+      features[key].update(value)
+    else:
+      features[key] = value
+
+  return features
diff --git a/chrome/common/extensions/docs/server2/features_utility_test.py b/chrome/common/extensions/docs/server2/features_utility_test.py
new file mode 100755
index 0000000..313e451
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/features_utility_test.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.
+
+import unittest
+
+from features_utility import Parse, Filtered, MergedWith
+
+class FeaturesUtilityTest(unittest.TestCase):
+  def testFromJson(self):
+    raw_features_json = {
+      'doc1': {
+        'extension_types': ['extension', 'platform_app']
+      },
+      'doc2': {
+        'extension_types': ['hosted_app', 'packaged_app']
+      },
+      'doc3': {
+        'whitelist': 'hashhashashhashashhashashhash'
+      },
+      'doc4': [
+        { 'extension_types': 'all' },
+        { 'whitelist': 'hashhashashhashashhashashhash' }
+      ],
+      'doc5': {
+        'extension_types': ['extension']
+      },
+      'doc1.sub1': {
+        'extension_types': ['platform_app', 'hosted_app', 'packaged_app']
+      }
+    }
+
+    expected = {
+      'doc1': {
+        'platforms': ['app', 'extension'],
+        'name': 'doc1'
+      },
+      'doc2': {
+        'platforms': [],
+        'name': 'doc2'
+      },
+      'doc4': {
+        'platforms': ['app', 'extension'],
+        'name': 'doc4'
+      },
+      'doc5': {
+        'platforms': ['extension'],
+        'name': 'doc5'
+      },
+      'doc1.sub1': {
+        'platforms': ['app'],
+        'name': 'doc1.sub1'
+      }
+    }
+
+    self.assertEqual(expected, Parse(raw_features_json))
+
+  def testFilter(self):
+    unfiltered = {
+      'doc1': { 'platforms': ['app'] },
+      'doc2': { 'platforms': ['extension'] },
+      'doc3': { 'platforms': ['app', 'extension'] },
+      'doc4': { 'platforms': [] }
+    }
+
+    apps_names = set(('doc1', 'doc3'))
+    extension_names = set(('doc2', 'doc3'))
+
+    self.assertEqual(
+        apps_names, set(Filtered(unfiltered, 'app').keys()))
+    self.assertEqual(
+        extension_names, set(Filtered(unfiltered, 'extension').keys()))
+
+  def testMergeFeatures(self):
+    features = {
+      'doc1': {
+        'platforms': ['app']
+      },
+      'doc3': {
+        'name': 'doc3'
+      }
+    }
+
+    other = {
+      'doc1': {
+        'name': 'doc1',
+        'platforms': ['extension']
+      },
+      'doc2': {
+        'name': 'doc2'
+      },
+      'doc3': {
+        'platforms': ['extension', 'app']
+      }
+    }
+
+    expected = {
+      'doc1': {
+        'name': 'doc1',
+        'platforms': ['extension']
+      },
+      'doc2': {
+        'name': 'doc2'
+      },
+      'doc3': {
+        'name': 'doc3',
+        'platforms': ['extension', 'app']
+      }
+    }
+
+    self.assertEqual(expected, MergedWith(features, other))
+
+if __name__ == '__main__':
+  unittest.main()
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 54f829d..5c75f51 100755
--- a/chrome/common/extensions/docs/server2/github_file_system_test.py
+++ b/chrome/common/extensions/docs/server2/github_file_system_test.py
@@ -33,8 +33,8 @@
                      self._file_system.Read(['/']).Get())
 
   def testRead(self):
-   self.assertEqual(self._ReadLocalFile('expected_read.txt'),
-                    self._file_system.ReadSingle('/analytics/launch.js'))
+    self.assertEqual(self._ReadLocalFile('expected_read.txt'),
+                     self._file_system.ReadSingle('/analytics/launch.js'))
 
   def testStat(self):
     self.assertEqual(0, self._file_system.Stat('zipball').version)
diff --git a/chrome/common/extensions/docs/server2/host_file_system_creator.py b/chrome/common/extensions/docs/server2/host_file_system_creator.py
index 956ce30..cf74105 100644
--- a/chrome/common/extensions/docs/server2/host_file_system_creator.py
+++ b/chrome/common/extensions/docs/server2/host_file_system_creator.py
@@ -16,12 +16,12 @@
                object_store_creator,
                offline=False,
                constructor_for_test=None):
-     self._object_store_creator = object_store_creator
-     # Determines whether or not created file systems will be wrapped in an
-     # OfflineFileSystem.
-     self._offline = offline
-     # Provides custom create behavior, useful in tests.
-     self._constructor_for_test = constructor_for_test
+    self._object_store_creator = object_store_creator
+    # Determines whether or not created file systems will be wrapped in an
+    # OfflineFileSystem.
+    self._offline = offline
+    # Provides custom create behavior, useful in tests.
+    self._constructor_for_test = constructor_for_test
 
   def Create(self, branch='trunk', revision=None, offline=None):
     '''Creates either SVN file systems or specialized file systems from the
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source.py b/chrome/common/extensions/docs/server2/manifest_data_source.py
index d0c2c15..104fb12 100644
--- a/chrome/common/extensions/docs/server2/manifest_data_source.py
+++ b/chrome/common/extensions/docs/server2/manifest_data_source.py
@@ -2,14 +2,126 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from copy import deepcopy
-from operator import itemgetter
+import json
 
-from third_party.json_schema_compiler.json_parse import OrderedDict, Parse
+import features_utility as features
+from third_party.json_schema_compiler.json_parse import Parse
+
+def _ListifyAndSortDocs(features, app_name):
+  '''Convert a |feautres| dictionary, and all 'children' dictionaries, into
+  lists recursively. Sort lists first by 'level' then by name.
+  '''
+  def sort_key(item):
+    '''Key function to sort items primarily by level (according to index into
+    levels) then subsort by name.
+    '''
+    levels = ('required', 'recommended', 'only_one', 'optional')
+
+    return (levels.index(item.get('level', 'optional')), item['name'])
+
+  def coerce_example_to_feature(feature):
+    '''To display json in examples more clearly, convert the example of
+    |feature| into the feature format, with a name and children, to be rendered
+    by the templates. Only applicable to examples that are dictionaries.
+    '''
+    if not isinstance(feature.get('example'), dict):
+      if 'example' in feature:
+        feature['example'] = json.dumps(feature['example'])
+      return
+    # Add any keys/value pairs in the dict as children
+    for key, value in feature['example'].iteritems():
+      if not 'children' in feature:
+        feature['children'] = {}
+      feature['children'][key] = { 'name': key, 'example': value }
+    del feature['example']
+    del feature['has_example']
+
+  def convert_and_sort(features):
+    for key, value in features.items():
+      if 'example' in value:
+        value['has_example'] = True
+        example = json.dumps(value['example'])
+        if example == '{}':
+          value['example'] = '{...}'
+        elif example == '[]':
+          value['example'] = '[...]'
+        else:
+          coerce_example_to_feature(value)
+      if 'children' in value:
+        features[key]['children'] = convert_and_sort(value['children'])
+    return sorted(features.values(), key=sort_key)
+
+  # Replace {{title}} in the 'name' manifest property example with |app_name|
+  if 'name' in features:
+    name = features['name']
+    name['example'] = name['example'].replace('{{title}}', app_name)
+
+  features = convert_and_sort(features)
+
+  return features
+
+def _AddLevelAnnotations(features):
+  '''Add level annotations to |features|. |features| and children lists must be
+  sorted by 'level'. Annotations are added to the first item in a group of
+  features of the same 'level'.
+
+  The last item in a list has 'is_last' set to True.
+  '''
+  annotations = {
+    'required': 'Required',
+    'recommended': 'Recommended',
+    'only_one': 'Pick one (or none)',
+    'optional': 'Optional'
+  }
+
+  def add_annotation(item, annotation):
+    if not 'annotations' in item:
+      item['annotations'] = []
+    item['annotations'].insert(0, annotation)
+
+  def annotate(parent_level, features):
+    current_level = parent_level
+    for item in features:
+      level = item.get('level', 'optional')
+      if level != current_level:
+        add_annotation(item, annotations[level])
+        current_level = level
+      if 'children' in item:
+        annotate(level, item['children'])
+    if features:
+      features[-1]['is_last'] = True
+
+  annotate('required', features)
+  return features
+
+def _RestructureChildren(features):
+  '''Features whose names are of the form 'parent.child' are moved to be part
+  of the 'parent' dictionary under the key 'children'. Names are changed to
+  the 'child' section of the original name. Applied recursively so that
+  children can have children.
+  '''
+  def add_child(features, parent, child_name, value):
+    value['name'] = child_name
+    if not 'children' in features[parent]:
+      features[parent]['children'] = {}
+    features[parent]['children'][child_name] = value
+
+  def insert_children(features):
+    for name in features.keys():
+      if '.' in name:
+        value = features.pop(name)
+        parent, child_name = name.split('.', 1)
+        add_child(features, parent, child_name, value)
+
+    for value in features.values():
+      if 'children' in value:
+        insert_children(value['children'])
+
+  insert_children(features)
+  return features
 
 class ManifestDataSource(object):
-  '''Provides a template with access to manifest properties specific to apps or
-  extensions.
+  '''Provides access to the properties in manifest features.
   '''
   def __init__(self,
                compiled_fs_factory,
@@ -22,68 +134,36 @@
     self._cache = compiled_fs_factory.Create(
         self._CreateManifestData, ManifestDataSource)
 
-  def _ApplyAppsTransformations(self, manifest):
-    manifest['required'][0]['example'] = 'Application'
-    manifest['optional'][-1]['is_last'] = True
+  def GetFeatures(self):
+    '''Returns a dictionary of the contents of |_features_path| merged with
+    |_manifest_path|.
+    '''
+    manifest_json = Parse(self._file_system.ReadSingle(self._manifest_path))
+    manifest_features = features.Parse(
+        Parse(self._file_system.ReadSingle(self._features_path)))
 
-  def _ApplyExtensionsTransformations(self, manifest):
-    manifest['optional'][-1]['is_last'] = True
+    return features.MergedWith(manifest_features, manifest_json)
 
   def _CreateManifestData(self, _, content):
-    '''Take the contents of |_manifest_path| and create apps and extensions
-    versions of a manifest example based on the contents of |_features_path|.
+    '''Combine the contents of |_manifest_path| and |_features_path| and filter
+    the results into lists specific to apps or extensions for templates. Marks
+    up features with annotations.
     '''
-    def create_manifest_dict():
-      manifest_dict = OrderedDict()
-      for category in ('required', 'only_one', 'recommended', 'optional'):
-        manifest_dict[category] = []
-      return manifest_dict
+    def for_templates(manifest_features, platform):
+      return _AddLevelAnnotations(
+          _ListifyAndSortDocs(
+              _RestructureChildren(
+                  features.Filtered(manifest_features, platform)),
+              app_name=platform.capitalize()))
 
-    apps = create_manifest_dict()
-    extensions = create_manifest_dict()
+    manifest_json = Parse(self._file_system.ReadSingle(self._manifest_path))
+    manifest_features = features.MergedWith(
+        features.Parse(Parse(content)), manifest_json)
 
-    manifest_json = Parse(content)
-    features_json = Parse(self._file_system.ReadSingle(
-        self._features_path))
-
-    def add_property(feature, manifest_key, category):
-      '''If |feature|, from features_json, has the correct extension_types, add
-      |manifest_key| to either apps or extensions.
-      '''
-      added = False
-      extension_types = feature['extension_types']
-      if extension_types == 'all' or 'platform_app' in extension_types:
-        apps[category].append(deepcopy(manifest_key))
-        added = True
-      if extension_types == 'all' or 'extension' in extension_types:
-        extensions[category].append(deepcopy(manifest_key))
-        added = True
-      return added
-
-    # Property types are: required, only_one, recommended, and optional.
-    for category in manifest_json:
-      for manifest_key in manifest_json[category]:
-        # If a property is in manifest.json but not _manifest_features, this
-        # will cause an error.
-        feature = features_json[manifest_key['name']]
-        if add_property(feature, manifest_key, category):
-          del features_json[manifest_key['name']]
-
-    # All of the properties left in features_json are assumed to be optional.
-    for feature in features_json.keys():
-      item = features_json[feature]
-      # Handles instances where a features entry is a union with a whitelist.
-      if isinstance(item, list):
-        item = item[0]
-      add_property(item, {'name': feature}, 'optional')
-
-    apps['optional'].sort(key=itemgetter('name'))
-    extensions['optional'].sort(key=itemgetter('name'))
-
-    self._ApplyAppsTransformations(apps)
-    self._ApplyExtensionsTransformations(extensions)
-
-    return {'apps': apps, 'extensions': extensions}
+    return {
+      'apps': for_templates(manifest_features, 'app'),
+      'extensions': for_templates(manifest_features, 'extension')
+    }
 
   def get(self, key):
-    return self._cache.GetFromFile(self._manifest_path)[key]
+    return self._cache.GetFromFile(self._features_path)[key]
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source_test.py b/chrome/common/extensions/docs/server2/manifest_data_source_test.py
index 3f971b6..00e0c12 100755
--- a/chrome/common/extensions/docs/server2/manifest_data_source_test.py
+++ b/chrome/common/extensions/docs/server2/manifest_data_source_test.py
@@ -3,126 +3,242 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from copy import deepcopy
 import json
 import unittest
 
-from compiled_file_system import CompiledFileSystem
-from manifest_data_source import ManifestDataSource
-from object_store_creator import ObjectStoreCreator
-from test_file_system import TestFileSystem
+import manifest_data_source
 
-file_system = TestFileSystem({
-  "_manifest_features.json": json.dumps({
-    'req0': {
-      'extension_types': ['platform_app', 'extension']
-    },
-    'req1': {
-      'extension_types': 'all'
-    },
-    'opt0': {
-      'extension_types': ['extension']
-    },
-    'opt1': {
-      'extension_types': ['hosted_app']
-    },
-    'free0': {
-      'extension_types': ['platform_app']
-    },
-    'free1': {
-      'extension_types': ['platform_app', 'hosted_app', 'extension']
-    },
-    'only0': {
-      'extension_types': 'all'
-    },
-    'only1': {
-      'extension_types': ['platform_app']
-    },
-    'rec0': {
-    'extension_types': ['extension']
-    },
-    'rec1': {
-      'extension_types': ['platform_app', 'extension']
-    }
-  }),
-  "manifest.json": json.dumps({
-    'required': [
-      {
-        'name': 'req0',
-        'example': 'Extension'
+convert_and_annotate_docs = {
+  'name': {
+    'example': "My {{title}}",
+    'name': 'name',
+    'level': 'required'
+  },
+  'doc2': {
+    'level': 'required',
+    'name': 'doc2'
+  },
+  'doc1': {
+    'level': 'required',
+    'name': 'doc1',
+    'children': {
+      'sub1': {
+        'annotations': ['not so important'],
+        'level': 'optional',
+        'name': 'sub1'
       },
-      {'name': 'req1'}
-    ],
-    'only_one': [
-      {'name': 'only0'},
-      {'name': 'only1'}
-    ],
-    'recommended': [
-      {'name': 'rec0'},
-      {'name': 'rec1'}
-    ],
-    'optional': [
-      {'name': 'opt0'},
-      {'name': 'opt1'}
-    ]
-  })
-})
+      'sub2': {
+        'level': 'required',
+        'name': 'sub2'
+      }
+    }
+  },
+  'doc3': {
+    'level':  'only_one',
+    'name': 'doc3'
+  },
+  'doc4': {
+    'level': 'recommended',
+    'name': 'doc4'
+  },
+  'doc5': {
+    'level': 'only_one',
+    'name': 'doc5'
+  },
+  'doc6': {
+    'level': 'optional',
+    'name': 'doc6'
+  }
+}
 
 class ManifestDataSourceTest(unittest.TestCase):
-  def testCreateManifestData(self):
-    expected_extensions = {
-      'required': [
-        {
-          'name': 'req0',
-          'example': 'Extension'
-        },
-        {'name': 'req1'}
-      ],
-      'recommended': [
-        {'name': 'rec0'},
-        {'name': 'rec1'}
-      ],
-      'only_one': [
-        {'name': 'only0'}
-      ],
-      'optional': [
-        {'name': 'free1'},
-        {
-          'name': 'opt0',
-          'is_last': True
-        }
-      ]
+  def testListifyAndSortDocs(self):
+    expected_docs = [
+      {
+        'level': 'required',
+        'name': 'doc1',
+        'children': [
+          {
+            'level': 'required',
+            'name': 'sub2'
+          },
+          {
+            'annotations': ['not so important'],
+            'level': 'optional',
+            'name': 'sub1'
+          }
+        ]
+      },
+      {
+        'level': 'required',
+        'name': 'doc2'
+      },
+      {
+        'level': 'required',
+        'example': '"My App"',
+        'has_example': True,
+        'name': 'name'
+      },
+      {
+        'level': 'recommended',
+        'name': 'doc4'
+      },
+      {
+        'level': 'only_one',
+        'name': 'doc3'
+      },
+      {
+        'level': 'only_one',
+        'name': 'doc5'
+      },
+      {
+        'level': 'optional',
+        'name': 'doc6'
+      }
+    ]
+
+    self.assertEqual(expected_docs, manifest_data_source._ListifyAndSortDocs(
+        deepcopy(convert_and_annotate_docs), 'App'))
+
+  def testAnnotate(self):
+    expected_docs = [
+      {
+        'level': 'required',
+        'name': 'doc1',
+        'children': [
+          {
+            'level': 'required',
+            'name': 'sub2'
+          },
+          {
+            'annotations': ['Optional', 'not so important'],
+            'level': 'optional',
+            'name': 'sub1',
+            'is_last': True
+          }
+        ]
+      },
+      {
+        'level': 'required',
+        'name': 'doc2'
+      },
+      {
+        'name': 'name',
+        'level': 'required',
+        'example': '"My App"',
+        'has_example': True
+      },
+      {
+        'annotations': ['Recommended'],
+        'level': 'recommended',
+        'name': 'doc4'
+      },
+      {
+        'annotations': ['Pick one (or none)'],
+        'level': 'only_one',
+        'name': 'doc3'
+      },
+      {
+        'level': 'only_one',
+        'name': 'doc5'
+      },
+      {
+        'annotations': ['Optional'],
+        'level': 'optional',
+        'name': 'doc6',
+        'is_last': True
+      }
+    ]
+
+    annotated = manifest_data_source._ListifyAndSortDocs(
+        deepcopy(convert_and_annotate_docs), 'App')
+    manifest_data_source._AddLevelAnnotations(annotated)
+    self.assertEqual(expected_docs, annotated)
+
+  def testRestructureChildren(self):
+    docs = {
+      'doc1.sub2': {
+        'name': 'doc1.sub2'
+      },
+      'doc1': {
+        'name': 'doc1'
+      },
+      'doc2': {
+        'name': 'doc2'
+      },
+      'doc1.sub1.subsub1': {
+        'name': 'doc1.sub1.subsub1'
+      },
+      'doc1.sub1': {
+        'name': 'doc1.sub1'
+      }
     }
 
-    expected_apps = {
-      'required': [
-        {
-          'name': 'req0',
-          'example': 'Application'
-        },
-        {'name': 'req1'}
-      ],
-      'recommended': [
-        {'name': 'rec1'}
-      ],
-      'only_one': [
-        {'name': 'only0'},
-        {'name': 'only1'}
-      ],
-      'optional': [
-        {'name': 'free0'},
-        {
-          'name': 'free1',
-          'is_last': True
+    expected_docs = {
+      'doc1': {
+        'name': 'doc1',
+        'children': {
+          'sub1': {
+            'name': 'sub1',
+            'children': {
+              'subsub1': {
+                'name' :'subsub1'
+              }
+            }
+          },
+          'sub2': {
+            'name': 'sub2'
+          }
         }
-      ]
+      },
+      'doc2': {
+        'name': 'doc2'
+      }
     }
 
-    mds = ManifestDataSource(
-        CompiledFileSystem.Factory(file_system, ObjectStoreCreator.ForTest()),
-        file_system, 'manifest.json', '_manifest_features.json')
+    self.assertEqual(
+        expected_docs, manifest_data_source._RestructureChildren(docs))
 
-    self.assertEqual(expected_extensions, mds.get('extensions'))
-    self.assertEqual(expected_apps, mds.get('apps'))
+  def testExpandedExamples(self):
+    docs = {
+      'doc1': {
+        'name': 'doc1',
+        'example': {
+          'big': {
+            'nested': {
+              'json_example': ['with', 'more', 'json']
+            }
+          }
+        }
+      }
+    }
+
+    expected_docs = [
+      {
+        'name': 'doc1',
+        'children': [
+          {
+            'name': 'big',
+            'children': [
+              {
+                'name': 'nested',
+                'children': [
+                  {
+                    'name': 'json_example',
+                    'example': json.dumps(['with', 'more', 'json']),
+                    'has_example': True
+                  }
+                ]
+              }
+            ]
+          }
+        ]
+      }
+    ]
+
+    self.assertEqual(
+        expected_docs, manifest_data_source._ListifyAndSortDocs(docs, 'app'))
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/chrome/common/extensions/docs/server2/permissions_data_source.py b/chrome/common/extensions/docs/server2/permissions_data_source.py
new file mode 100644
index 0000000..8e608f1
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/permissions_data_source.py
@@ -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.
+
+from itertools import ifilter
+from operator import itemgetter
+
+import features_utility as features
+from third_party.json_schema_compiler.json_parse import Parse
+
+def _ListifyPermissions(permissions):
+  '''Filter out any permissions that do not have a description or with a name
+  that ends with Private then sort permissions features by name into a list.
+  '''
+  def filter_permissions(perm):
+    return 'description' in perm and not perm['name'].endswith('Private')
+
+  return sorted(
+      ifilter(filter_permissions, permissions.values()),
+      key=itemgetter('name'))
+
+def _AddDependencyDescriptions(permissions, api_features):
+  '''Use |api_features| to determine the dependencies APIs have on permissions.
+  Add descriptions to |permissions| based on those dependencies.
+  '''
+  for name, permission in permissions.iteritems():
+    # Don't overwrite the description created by expanding a partial template.
+    if 'description' in permission or not permission['platforms']:
+      continue
+
+    has_deps = False
+    if name in api_features:
+      for dependency in api_features[name].get('dependencies', ()):
+        if dependency.startswith('permission:'):
+          has_deps = True
+
+    if has_deps:
+      permission['partial'] = 'permissions/generic_description'
+
+class PermissionsDataSource(object):
+  '''Load and format permissions features to be used by templates. Requries a
+  template data source be set before use.
+  '''
+  def __init__(self,
+               compiled_fs_factory,
+               file_system,
+               api_features_path,
+               permissions_features_path,
+               permissions_json_path):
+    self._api_features_path = api_features_path
+    self._permissions_features_path = permissions_features_path
+    self._permissions_json_path = permissions_json_path
+    self._file_system = file_system
+    self._cache = compiled_fs_factory.Create(
+        self._CreatePermissionsDataSource, PermissionsDataSource)
+
+  def SetTemplateDataSource(self, template_data_source_factory):
+    '''Initialize a template data source to be used to render partial templates
+    into descriptions for permissions. Must be called before .get
+    '''
+    self._template_data_source = template_data_source_factory.Create(None, '')
+
+  def _CreatePermissionsDataSource(self, _, content):
+    '''Combine the contents of |_permissions_json_path| and
+    |_permissions_features_path|. Filter into lists, one for extensions and
+    one for apps.
+    '''
+    api_features = Parse(self._file_system.ReadSingle(self._api_features_path))
+
+    def filter_for_platform(permissions, platform):
+      return _ListifyPermissions(features.Filtered(permissions, platform))
+
+    permissions_json = Parse(self._file_system.ReadSingle(
+        self._permissions_json_path))
+    permission_features = features.MergedWith(
+        features.Parse(Parse(content)), permissions_json)
+
+    _AddDependencyDescriptions(permission_features, api_features)
+    # Turn partial templates into descriptions, ensure anchors are set.
+    for permission in permission_features.values():
+      if not 'anchor' in permission:
+        permission['anchor'] = permission['name']
+      if 'partial' in permission:
+        permission['description'] = self._template_data_source.get(
+            permission['partial'])
+        del permission['partial']
+
+    return {
+      'declare_apps': filter_for_platform(permission_features, 'app'),
+      'declare_extensions': filter_for_platform(
+          permission_features, 'extension')
+    }
+
+  def get(self, key):
+    return self._cache.GetFromFile(self._permissions_features_path)[key]
diff --git a/chrome/common/extensions/docs/server2/permissions_data_source_test.py b/chrome/common/extensions/docs/server2/permissions_data_source_test.py
new file mode 100755
index 0000000..4d77910
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/permissions_data_source_test.py
@@ -0,0 +1,146 @@
+#!/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 json
+import unittest
+
+from compiled_file_system import CompiledFileSystem
+from object_store_creator import ObjectStoreCreator
+from permissions_data_source import PermissionsDataSource
+from test_file_system import TestFileSystem
+
+class FakeTemplateDataSource(object):
+  class Factory():
+    def Create(self, *args):
+      return FakeTemplateDataSource()
+  def get(self, key):
+    return 'partial ' + key
+
+file_system = TestFileSystem({
+  'permissions.json': json.dumps({
+    'host-permissions': {
+      'name': 'match pattern',
+      'anchor': 'custom-anchor',
+      'platforms': ['app', 'extension'],
+      'partial': 'host_permissions.html',
+      'literal_name': True
+    },
+    'activeTab': {
+      'partial': 'active_tab.html'
+    },
+    'alarms': {
+      'partial': 'alarms.html'
+    },
+    'audioCapture': {
+      'partial': 'audio_capture.html'
+    },
+    'background': {
+      'partial': 'background.html'
+    }
+  }),
+  '_permission_features.json': json.dumps({
+    'activeTab': {
+      'extension_types': ['extension', 'packaged_app'],
+    },
+    'alarms': {
+      'extension_types': ['extension', 'packaged_app', 'platform_app'],
+    },
+      'audioCapture': {
+      'extension_types': ['platform_app']
+    },
+    'background': {
+      'extension_types': ['extension', 'packaged_app', 'hosted_app']
+    },
+    'commandLinePrivate': {
+      'extension_types': 'all'
+    },
+    'cookies': {
+      'extension_types': ['platform_app']
+    }
+  }),
+  '_api_features.json': json.dumps({
+    'cookies': {
+      'dependencies': ['permission:cookies']
+    }
+  })
+})
+
+class PermissionsDataSourceTest(unittest.TestCase):
+  def testCreatePermissionsDataSource(self):
+    expected_extensions = [
+      {
+        'name': 'activeTab',
+        'anchor': 'activeTab',
+        'platforms': ['extension'],
+        'description': 'partial active_tab.html'
+      },
+      {
+        'name': 'alarms',
+        'anchor': 'alarms',
+        'platforms': ['app', 'extension'],
+        'description': 'partial alarms.html'
+      },
+      {
+        'name': 'background',
+        'anchor': 'background',
+        'platforms': ['extension'],
+        'description': 'partial background.html'
+      },
+      {
+        'name': 'match pattern',
+        'anchor': 'custom-anchor',
+        'literal_name': True,
+        'description': 'partial host_permissions.html',
+        'platforms': ['app', 'extension']
+      }
+    ]
+
+    expected_apps = [
+      {
+        'name': 'alarms',
+        'anchor': 'alarms',
+        'platforms': ['app', 'extension'],
+        'description': 'partial alarms.html'
+      },
+      {
+        'name': 'audioCapture',
+        'anchor': 'audioCapture',
+        'description': 'partial audio_capture.html',
+        'platforms': ['app']
+      },
+      {
+        'anchor': 'cookies',
+        'name': 'cookies',
+        'description': 'partial permissions/generic_description',
+        'platforms': ['app']
+      },
+      {
+        'name': 'match pattern',
+        'anchor': 'custom-anchor',
+        'literal_name': True,
+        'description': 'partial host_permissions.html',
+        'platforms': ['app', 'extension']
+      }
+    ]
+
+    permissions_data_source = PermissionsDataSource(
+        CompiledFileSystem.Factory(file_system, ObjectStoreCreator.ForTest()),
+        file_system,
+        '_api_features.json',
+        '_permission_features.json',
+        'permissions.json')
+
+    permissions_data_source.SetTemplateDataSource(
+        FakeTemplateDataSource.Factory())
+
+    self.assertEqual(
+        expected_extensions,
+        permissions_data_source.get('declare_extensions'))
+    self.assertEqual(
+        expected_apps,
+        permissions_data_source.get('declare_apps'))
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/render_servlet.py b/chrome/common/extensions/docs/server2/render_servlet.py
index e9adcab..48dc4ce 100644
--- a/chrome/common/extensions/docs/server2/render_servlet.py
+++ b/chrome/common/extensions/docs/server2/render_servlet.py
@@ -5,7 +5,6 @@
 from fnmatch import fnmatch
 import logging
 import mimetypes
-import traceback
 from urlparse import urlsplit
 
 from file_system import FileNotFoundError
@@ -79,16 +78,15 @@
       elif path.endswith('.html'):
         content = templates.Render(path)
         content_type = 'text/html'
+      else:
+        content = None
     except FileNotFoundError:
-      logging.warning(traceback.format_exc())
       content = None
 
     headers = {'x-frame-options': 'sameorigin'}
     if content is None:
-      doc_class = path.split('/', 1)[0]
-      content = templates.Render('%s/404' % doc_class)
-      if not content:
-        content = templates.Render('extensions/404')
+      content = (templates.Render('%s/404' % path.split('/', 1)[0]) or
+                 templates.Render('extensions/404'))
       return Response.NotFound(content, headers=headers)
 
     if not content:
diff --git a/chrome/common/extensions/docs/server2/server_instance.py b/chrome/common/extensions/docs/server2/server_instance.py
index ded9c1c..80adefb 100644
--- a/chrome/common/extensions/docs/server2/server_instance.py
+++ b/chrome/common/extensions/docs/server2/server_instance.py
@@ -7,6 +7,7 @@
 from appengine_wrappers import IsDevServer
 from availability_finder import AvailabilityFinder
 from compiled_file_system import CompiledFileSystem
+from data_source_registry import DataSourceRegistry
 from empty_dir_file_system import EmptyDirFileSystem
 from example_zipper import ExampleZipper
 from manifest_data_source import ManifestDataSource
@@ -14,6 +15,7 @@
 from intro_data_source import IntroDataSource
 from object_store_creator import ObjectStoreCreator
 from path_canonicalizer import PathCanonicalizer
+from permissions_data_source import PermissionsDataSource
 from redirector import Redirector
 from reference_resolver import ReferenceResolver
 from samples_data_source import SamplesDataSource
@@ -101,21 +103,12 @@
         '/'.join((svn_constants.JSON_PATH, 'manifest.json')),
         '/'.join((svn_constants.API_PATH, '_manifest_features.json')))
 
-    self.template_data_source_factory = TemplateDataSource.Factory(
-        self.api_data_source_factory,
-        self.api_list_data_source_factory,
-        self.intro_data_source_factory,
-        self.samples_data_source_factory,
-        self.sidenav_data_source_factory,
+    self.permissions_data_source = PermissionsDataSource(
         self.compiled_host_fs_factory,
-        self.ref_resolver_factory,
-        self.manifest_data_source,
-        svn_constants.PUBLIC_TEMPLATE_PATH,
-        svn_constants.PRIVATE_TEMPLATE_PATH,
-        base_path)
-
-    self.api_data_source_factory.SetTemplateDataSource(
-        self.template_data_source_factory)
+        self.host_file_system,
+        '/'.join((svn_constants.API_PATH, '_api_features.json')),
+        '/'.join((svn_constants.API_PATH, '_permission_features.json')),
+        '/'.join((svn_constants.JSON_PATH, 'permissions.json')))
 
     self.example_zipper = ExampleZipper(
         self.compiled_host_fs_factory,
@@ -129,6 +122,30 @@
         self.host_file_system,
         svn_constants.PUBLIC_TEMPLATE_PATH)
 
+    self.strings_json_path = '/'.join((svn_constants.JSON_PATH, 'strings.json'))
+
+    self.template_data_source_factory = TemplateDataSource.Factory(
+        self.api_data_source_factory,
+        self.api_list_data_source_factory,
+        self.intro_data_source_factory,
+        self.samples_data_source_factory,
+        self.sidenav_data_source_factory,
+        self.compiled_host_fs_factory,
+        self.ref_resolver_factory,
+        self.manifest_data_source,
+        self.permissions_data_source,
+        svn_constants.PUBLIC_TEMPLATE_PATH,
+        svn_constants.PRIVATE_TEMPLATE_PATH,
+        base_path,
+        # TODO(jshumway): Remove this hack after data source registry
+        # transition, ServerInstance should not know about DataSourceRegistry.
+        DataSourceRegistry.AsTemplateData(self))
+
+    self.api_data_source_factory.SetTemplateDataSource(
+        self.template_data_source_factory)
+    self.permissions_data_source.SetTemplateDataSource(
+        self.template_data_source_factory)
+
   @staticmethod
   def ForTest(file_system):
     object_store_creator = ObjectStoreCreator.ForTest()
diff --git a/chrome/common/extensions/docs/server2/strings_data_source.py b/chrome/common/extensions/docs/server2/strings_data_source.py
new file mode 100644
index 0000000..5043361
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/strings_data_source.py
@@ -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.
+
+from data_source import DataSource
+from third_party.json_schema_compiler.json_parse import Parse
+
+class StringsDataSource(DataSource):
+  '''Provides templates with access to a key to string mapping defined in a
+  JSON configuration file.
+  '''
+  def __init__(self, server_instance):
+    self._cache = server_instance.compiled_host_fs_factory.Create(
+        lambda _, strings_json: Parse(strings_json), StringsDataSource)
+    self._strings_json_path = server_instance.strings_json_path
+
+  def Cron(self):
+    self._cache.GetFromFile(self._strings_json_path)
+
+  def get(self, key):
+    return self._cache.GetFromFile(self._strings_json_path)[key]
diff --git a/chrome/common/extensions/docs/server2/template_data_source.py b/chrome/common/extensions/docs/server2/template_data_source.py
index 7ad4dae..6faecc8 100644
--- a/chrome/common/extensions/docs/server2/template_data_source.py
+++ b/chrome/common/extensions/docs/server2/template_data_source.py
@@ -11,16 +11,6 @@
 
 _EXTENSIONS_URL = '/chrome/extensions'
 
-_STRING_CONSTANTS = {
-  'app': 'app',
-  'apps_title': 'Apps',
-  'extension': 'extension',
-  'extensions_title': 'Extensions',
-  'events': 'events',
-  'methods': 'methods',
-  'properties': 'properties',
-  }
-
 class TemplateDataSource(object):
   """Renders Handlebar templates, providing them with the context in which to
   render.
@@ -46,9 +36,11 @@
                  compiled_fs_factory,
                  ref_resolver_factory,
                  manifest_data_source,
+                 permissions_data_source,
                  public_template_path,
                  private_template_path,
-                 base_path):
+                 base_path,
+                 data_sources):
       self._api_data_source_factory = api_data_source_factory
       self._api_list_data_source_factory = api_list_data_source_factory
       self._intro_data_source_factory = intro_data_source_factory
@@ -57,10 +49,12 @@
       self._cache = compiled_fs_factory.Create(self._CreateTemplate,
                                                TemplateDataSource)
       self._ref_resolver = ref_resolver_factory.Create()
+      self._manifest_data_source = manifest_data_source
+      self._permissions_data_source = permissions_data_source
       self._public_template_path = public_template_path
       self._private_template_path = private_template_path
-      self._manifest_data_source = manifest_data_source
       self._base_path = base_path
+      self._data_sources = data_sources
 
     def _CreateTemplate(self, template_name, text):
       return Handlebar(self._ref_resolver.ResolveAllLinks(text))
@@ -76,9 +70,11 @@
           self._sidenav_data_source_factory.Create(path),
           self._cache,
           self._manifest_data_source,
+          self._permissions_data_source,
           self._public_template_path,
           self._private_template_path,
-          self._base_path)
+          self._base_path,
+          self._data_sources)
 
   def __init__(self,
                api_data_source,
@@ -88,9 +84,11 @@
                sidenav_data_source,
                cache,
                manifest_data_source,
+               permissions_data_source,
                public_template_path,
                private_template_path,
-               base_path):
+               base_path,
+               data_sources):
     self._api_list_data_source = api_list_data_source
     self._intro_data_source = intro_data_source
     self._samples_data_source = samples_data_source
@@ -100,7 +98,9 @@
     self._public_template_path = public_template_path
     self._private_template_path = private_template_path
     self._manifest_data_source = manifest_data_source
+    self._permissions_data_source = permissions_data_source
     self._base_path = base_path
+    self._data_sources = data_sources
 
   def Render(self, template_name):
     """This method will render a template named |template_name|, fetching all
@@ -111,21 +111,23 @@
     if template is None:
       return None
       # TODO error handling
-    render_data = template.render({
+    render_context = {
       'api_list': self._api_list_data_source,
       'apis': self._api_data_source,
       'intros': self._intro_data_source,
       'sidenavs': self._sidenav_data_source,
       'partials': self,
       'manifest_source': self._manifest_data_source,
+      'permissions': self._permissions_data_source,
       'samples': self._samples_data_source,
       'apps_samples_url': url_constants.GITHUB_BASE,
       'extensions_samples_url': url_constants.EXTENSIONS_SAMPLES,
       'static': self._base_path + '/static',
-      'strings': _STRING_CONSTANTS,
       'true': True,
       'false': False
-    })
+    }
+    render_context.update(self._data_sources)
+    render_data = template.render(render_context)
     if render_data.errors:
       logging.error('Handlebar error(s) rendering %s:\n%s' %
           (template_name, '  \n'.join(render_data.errors)))
diff --git a/chrome/common/extensions/docs/server2/template_data_source_test.py b/chrome/common/extensions/docs/server2/template_data_source_test.py
index a298b48..41cddab 100755
--- a/chrome/common/extensions/docs/server2/template_data_source_test.py
+++ b/chrome/common/extensions/docs/server2/template_data_source_test.py
@@ -13,6 +13,7 @@
 from local_file_system import LocalFileSystem
 from manifest_data_source import ManifestDataSource
 from object_store_creator import ObjectStoreCreator
+from permissions_data_source import PermissionsDataSource
 from reference_resolver import ReferenceResolver
 from template_data_source import TemplateDataSource
 from test_file_system import TestFileSystem
@@ -41,6 +42,8 @@
     self._fake_sidenav_data_source_factory = _FakeFactory()
     self._manifest_data_source = ManifestDataSource(
       _FakeFactory(), LocalFileSystem.Create(), '', '')
+    self._permissions_data_source = PermissionsDataSource(
+      _FakeFactory(), LocalFileSystem.Create(), '', '', '')
 
   def _ReadLocalFile(self, filename):
     with open(os.path.join(self._base_path, filename), 'r') as f:
@@ -76,10 +79,12 @@
         self._fake_sidenav_data_source_factory,
         compiled_fs_factory,
         reference_resolver_factory,
+        self._permissions_data_source,
         self._manifest_data_source,
         '.',
         '.',
-        ''))
+        '',
+        {}))
 
   def testSimple(self):
     self._base_path = os.path.join(self._base_path, 'simple')
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/stat b/chrome/common/extensions/docs/server2/test_data/file_system/stat
index df42b24..fe02844 100644
--- a/chrome/common/extensions/docs/server2/test_data/file_system/stat
+++ b/chrome/common/extensions/docs/server2/test_data/file_system/stat
@@ -1108,16 +1108,16 @@
 <tr class="vc_row_even">
 <td colspan="2">
 
-<a name="experimental_processes.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_processes.json?view=log" title="View file revision log">
+<a name="processes.json" href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/processes.json?view=log" title="View file revision log">
 
 <img src="/viewvc/*docroot*/images/text.png" alt="" width="16" height="16" />
-experimental_processes.json</a>
+processes.json</a>
 
 </td>
 
 
 
-<td>&nbsp;<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/experimental_processes.json?revision=137690&amp;view=markup" title="View file contents"><strong>137690</strong></a></td>
+<td>&nbsp;<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/api/processes.json?revision=137690&amp;view=markup" title="View file contents"><strong>137690</strong></a></td>
 
 <td>&nbsp;2 months</td>
 <td>&nbsp;nasko@chromium.org</td>
diff --git a/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json b/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json
index 5dc31a8..a6c9370 100644
--- a/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json
+++ b/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json
@@ -73,7 +73,7 @@
   "file_browser_private.json": "150806",
   "cloud_print_private.json": "149303",
   "omnibox.json": "124878",
-  "experimental_processes.json": "137690",
+  "processes.json": "137690",
   "proxy.json": "136588",
   "file_browser_handler_internal.json": "142683",
   "types.json": "146093",
diff --git a/chrome/common/extensions/docs/server2/test_data/subversion_file_system/docs_public_extensions_214898 b/chrome/common/extensions/docs/server2/test_data/subversion_file_system/docs_public_extensions_214898
index a3ce086..1aee4c2 100644
--- a/chrome/common/extensions/docs/server2/test_data/subversion_file_system/docs_public_extensions_214898
+++ b/chrome/common/extensions/docs/server2/test_data/subversion_file_system/docs_public_extensions_214898
@@ -1614,17 +1614,17 @@
 <tr class="vc_row_odd">
 <td colspan="2">
 
-<a name="experimental_processes.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_processes.html?view=log&amp;pathrev=214898" title="View file revision log">
+<a name="processes.html" href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/processes.html?view=log&amp;pathrev=214898" title="View file revision log">
 
 <img src="/viewvc/*docroot*/images/text.png" alt="" class="vc_icon" />
-experimental_processes.html</a>
+processes.html</a>
 
 </td>
 
 
 
 
-<td style="white-space: nowrap;">&nbsp;<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/experimental_processes.html?revision=157264&amp;pathrev=214898" title="View file contents"><strong>157264</strong></a>
+<td style="white-space: nowrap;">&nbsp;<a href="/viewvc/chrome/trunk/src/chrome/common/extensions/docs/templates/public/extensions/processes.html?revision=157264&amp;pathrev=214898" title="View file contents"><strong>157264</strong></a>
 
 </td>
 
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json b/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json
new file mode 100644
index 0000000..01fbab6
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json
@@ -0,0 +1,19 @@
+{
+  "namespace": "events",
+  "description": "A namespace to contain addRules.",
+  "types": [
+    {
+      "name": "Event",
+      "type": "object",
+      "description": "The object to contain addRules.",
+      "functions": [
+        {
+          "name": "addRules",
+          "type": "function",
+          "description": "Registers rules to handle events.",
+          "parameters": [ { "name": "notable_name_to_check_for" } ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_test.json b/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_test.json
new file mode 100644
index 0000000..992d79a
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_test.json
@@ -0,0 +1,26 @@
+[
+  {
+    "namespace": "tester",
+    "description": "A test api with a couple of events which support or do not support rules.",
+    "types": [
+    ],
+    "functions": [
+    ],
+    "events": [
+      {
+        "name": "rules",
+        "options": {
+          "supportsRules": true,
+          "conditions": [],
+          "actions": []
+        }
+      },
+      {
+        "name": "noRules",
+        "type": "function",
+        "description": "Listeners can be registered with this event.",
+        "parameters": []
+      }
+    ]
+  }
+]
diff --git a/chrome/common/extensions/docs/server2/test_data/test_json/expected_test_file.json b/chrome/common/extensions/docs/server2/test_data/test_json/expected_test_file.json
index 5d7a6d9..4c91dfd 100644
--- a/chrome/common/extensions/docs/server2/test_data/test_json/expected_test_file.json
+++ b/chrome/common/extensions/docs/server2/test_data/test_json/expected_test_file.json
@@ -4,7 +4,7 @@
       "name": "get",
       "parameters": [
         {
-          "parent_name": "get",
+          "parentName": "get",
           "functions": [],
           "choices": [
             {
@@ -44,7 +44,7 @@
           "description": "a param"
         },
         {
-          "parent_name": "get",
+          "parentName": "get",
           "last": true,
           "name": "callback",
           "simple_type": "function",
@@ -72,7 +72,7 @@
             },
             "optional": null,
             "id": "property-callback-results",
-            "parent_name": "callback",
+            "parentName": "callback",
             "functions": [],
             "last": true,
             "name": "results",
@@ -95,7 +95,7 @@
   "properties": [],
   "name": "tester",
   "description": "a test api",
-  "intro_list": [
+  "introList": [
     {
       "content": [
         {
@@ -140,7 +140,7 @@
     {
       "properties": [
         {
-          "parent_name": "TypeA",
+          "parentName": "TypeA",
           "functions": [],
           "name": "b",
           "parameters": [],
@@ -178,7 +178,7 @@
       "name": "EventA",
       "parameters": [
         {
-          "parent_name": "EventA",
+          "parentName": "EventA",
           "functions": [],
           "simple_type": "string",
           "name": "id",
@@ -198,7 +198,7 @@
           },
           "optional": null,
           "id": "property-EventA-bookmark",
-          "parent_name": "EventA",
+          "parentName": "EventA",
           "functions": [],
           "last": true,
           "name": "bookmark",
diff --git a/chrome/common/extensions/docs/server2/test_util.py b/chrome/common/extensions/docs/server2/test_util.py
index 02dc25f..d02bc92 100644
--- a/chrome/common/extensions/docs/server2/test_util.py
+++ b/chrome/common/extensions/docs/server2/test_util.py
@@ -11,12 +11,12 @@
 def EnableLogging(name):
   '''Returns the output of the log with |name| to stdout.
   '''
-  return _ReplaceLogging(name, lambda message: print(message))
+  return _ReplaceLogging(name, lambda message, *args: print(message % args))
 
 def DisableLogging(name):
   '''Disables the log with |name| for the duration of the decorated function.
   '''
-  return _ReplaceLogging(name, lambda _: None)
+  return _ReplaceLogging(name, lambda _, *args: None)
 
 def _ReplaceLogging(name, replacement):
   def decorator(fn):
diff --git a/chrome/common/extensions/docs/static/css/api.css b/chrome/common/extensions/docs/static/css/api.css
deleted file mode 100644
index 58175fa..0000000
--- a/chrome/common/extensions/docs/static/css/api.css
+++ /dev/null
@@ -1,42 +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.
- */
-
-.type_name,
-.variable,
-.property {
-  font-style: italic;
-}
-
-.api_reference div.summary {
-  border: 1px solid #93B4D9;
-  font-family: "Courier New", courier, monospace;
-  padding: 0.5em 0.5em 0.5em 2em;
-  text-indent: -1.5em;
-  background-color: #CADEF4;
-  margin-top: 1em;
-}
-
-/* This style is used because types with functions prefix the function with the
- * type name, using a lowercase first letter.
- */
-.api_reference .uncapitalize:first-letter {
-  text-transform: lowercase;
-}
-
-.api_reference .capitalize:first-letter {
-  text-transform: uppercase;
-}
-
-.api_reference div.description {
-  margin-left: 2em;
-}
-
-div.summary .subdued {
-  color: #7594B8;
-}
-
-.optional {
-  color: #7D7D7D;
-}
diff --git a/chrome/common/extensions/docs/static/css/site.css b/chrome/common/extensions/docs/static/css/site.css
index 5528b66..e1d96fa 100644
--- a/chrome/common/extensions/docs/static/css/site.css
+++ b/chrome/common/extensions/docs/static/css/site.css
@@ -3,26 +3,30 @@
  * found in the LICENSE file.
  */
 
+/*
+ * Site-wide styles.
+ */
+
 .hidden {
   display: none;
 }
 
 body {
+  background-color: white;
   font: 14px/22px 'Open Sans',arial,sans-serif;
   margin: auto;
   padding: 0;
-  background-color: white;
 }
 
 p.note,
 p.caution,
 p.warning {
-  margin: 1em 0 0 0;
-  padding: .2em .5em .2em .9em;
   background-color: #F5F5F5;
-  border-top: 1px solid;
   border-bottom: 1px solid;
+  border-top: 1px solid;
+  margin: 1em 0 0 0;
   overflow: hidden;
+  padding: .2em .5em .2em .9em;
 }
 
 p.note {
@@ -41,9 +45,9 @@
 }
 
 a, a:link {
-  text-decoration: none;
   color: #4787ed;
   font-weight: 600;
+  text-decoration: none;
 }
 
 a:active,
@@ -77,8 +81,8 @@
 .code,
 code,
 pre {
-  font-family: monospace;
   color: #080;
+  font-family: monospace;
 }
 
 .code,
@@ -87,13 +91,13 @@
 }
 
 pre {
-  font-size: 10pt;
   background-color: #F5F5F5;
+  font-size: 10pt;
   margin: 1em 0 0 0;
-  padding: .99em;
   overflow: auto;
-  word-wrap: break-word;
+  padding: .99em;
   position: relative;
+  word-wrap: break-word;
 }
 
 pre a {
@@ -105,15 +109,15 @@
 }
 
 pre[data-filename]::after {
-  content: attr(data-filename);
   background-color: darkGray;
-  right: 0;
-  top: 0;
-  position: absolute;
-  font-size: 16px;
   color: #FFF;
+  content: attr(data-filename);
+  font-size: 16px;
   padding: 2px 25px;
+  position: absolute;
+  right: 0;
   text-transform: uppercase;
+  top: 0;
 }
 
 dt {
@@ -126,28 +130,28 @@
 }
 
 dd {
+  font-weight: normal;
   margin: .4em 0 0 2em;
   padding: 0;
-  font-weight: normal;
 }
 
 #gc-container {
-  margin: auto;
+  height: auto;
   margin-top: 2em;
+  margin: auto;
   max-width: 1160px;
   padding: 0 50px;
-  height: auto;
 }
 
 #gc-topnav {
-  font-size: 1em;
-  margin: auto;
-  max-width: 1160px;
-  white-space: nowrap;
   background-color: white;
   border-bottom: 1px solid #F5F5F5;
+  font-size: 1em;
   line-height: 50px;
+  margin: auto;
+  max-width: 1160px;
   padding: 0 7px;
+  white-space: nowrap;
 }
 
 #gc-topnav * {
@@ -159,11 +163,11 @@
 }
 
 #gc-topnav li {
+  display: inline-block;
   font-weight: 600;
+  margin: 0 0 0 25px;
   text-transform: uppercase;
   white-space: nowrap;
-  display: inline-block;
-  margin: 0 0 0 25px;
 }
 #gc-topnav li:first-child {
   margin-left: 0;
@@ -187,8 +191,8 @@
 }
 
 #gc-topnav #chrome-logo a {
-  font-weight: 400;
   color: #77787a;
+  font-weight: 400;
   margin: 0;
 }
 
@@ -221,12 +225,12 @@
 #platform-chooser-popup {
   /* Make it appear to be an extension of the header. */
   background-color: white;
-  border: 1px solid #F5F5F5;
   border-top: none;
+  border: 1px solid #F5F5F5;
   z-index: 4;
   /* Ready to be shown by popup.js. */
-  position: absolute;
   display: none;
+  position: absolute;
   /* Align with the button, which have padding:6px. */
   left: -6px;
 }
@@ -234,8 +238,8 @@
 #platform-chooser-popup button {
   display: block;
   padding: 6px;
-  width: 100%;
   text-align: left;
+  width: 100%;
 }
 #platform-chooser-popup button:hover {
   color: #4787ed;
@@ -243,16 +247,16 @@
 
 button.google-button {
   background-color: #f5f5f5;
-  border: 1px solid rgba(0,0,0,0.1);
-  text-transform: uppercase;
   border-radius: 2px 0 0 0;
-    -webkit-border-radius: 2px 0 0 0;
     -moz-border-radius: 2px 0 0 0;
-  white-space: nowrap;
-  text-align: center;
+    -webkit-border-radius: 2px 0 0 0;
+  border: 1px solid rgba(0,0,0,0.1);
   height: 27px;
-  padding: 5px 12px;
   margin: 0;
+  padding: 5px 12px;
+  text-align: center;
+  text-transform: uppercase;
+  white-space: nowrap;
 }
 button.google-button:hover {
   border-color: #c6c6c6;
@@ -270,17 +274,17 @@
 #scroll-to-top,
 #send-feedback {
   border-bottom: none;
-  position: fixed;
   bottom: 0;
+  position: fixed;
   z-index: 5;
 }
 #scroll-to-top {
-  left: 0;
   border-left: 0;
+  left: 0;
 }
 #send-feedback {
-  right: 0;
   border-right: 0;
+  right: 0;
 }
 
 #gc-pagecontent {
@@ -288,9 +292,9 @@
 }
 
 #gc-pagecontent h1 {
-  line-height: 130%;
   font-size: 320%;
   font-weight: normal;
+  line-height: 130%;
 }
 
 #gc-pagecontent h2 {
@@ -318,8 +322,8 @@
   padding: 6px 12px;
 }
 #gc-pagecontent td {
-  padding: 6px 12px;
   border: 1px solid #36C;
+  padding: 6px 12px;
   vertical-align: top;
 }
 
@@ -335,10 +339,9 @@
   padding: 0;
 }
 
-#gc-pagecontent table.intro th {
-  border-style: none;
-  padding: 6px 12px;
-  text-align: left;
+#gc-pagecontent table.intro td.title {
+  font-weight: bold;
+  white-space: nowrap;
 }
 
 #gc-pagecontent table.intro td {
@@ -393,10 +396,10 @@
 }
 
 #gc-footer .text {
-  text-align: center;
   color: #666;
-  padding: 30px 0;
   margin: 0;
+  padding: 30px 0;
+  text-align: center;
 }
 
 #gc-sidebar {
@@ -407,9 +410,9 @@
 /* scroll.js adds and removes the floating class depending on the scroll
  * position. */
 #gc-sidebar.floating {
+  overflow: auto;
   position: fixed;
   top: 0; bottom: 0;
-  overflow: auto;
 }
 
 /* Sidebar link/button styling. */
@@ -417,8 +420,8 @@
 #gc-sidebar a {
   color: black;
   display: block;
-  position: relative;
   font-weight: normal;
+  position: relative;
 }
 #gc-sidebar a:hover,
 #gc-sidebar a.selected {
@@ -435,11 +438,11 @@
 }
 
 #gc-sidebar .toggleIndicator {
+  background: url(../images/toggle_sprite.png) no-repeat 0 0;
+  height: 8px;
   position: absolute;
   right: 0;
   top: 3px;
-  background: url(../images/toggle_sprite.png) no-repeat 0 0;
-  height: 8px;
   width: 8px;
 }
 #gc-sidebar .toggleIndicator.toggled {
@@ -449,23 +452,23 @@
 /* Sidebar list styling. */
 #gc-sidebar ul {
   list-style: none;
-  padding: 0;
   margin: 0;
+  padding: 0;
 }
 #gc-sidebar ul.level2 {
   margin-left: 10px;
   padding-top: 10px;
 }
 #gc-sidebar ul.level3 {
+  list-style: url(../images/sidearrow.png);
   margin-left: 20px;
   padding-top: 10px;
-  list-style: url(../images/sidearrow.png);
 }
 
 #gc-sidebar li {
+  line-height: 120%;
   margin: 0;
   padding: 8px 0;
-  line-height: 120%;
 }
 
 #gc-sidebar li.level2 {
@@ -477,33 +480,33 @@
 
 #toc {
   background-color: #F5F5F5;
-  float: right;
-  margin: 5px 0px 0px 0px;
-  padding: 5px;
-  width: 250px;
-  word-break: break-word;
+  border-bottom: 20px solid white;
   /* We want this element to have a visual left-margin of 20px, but margins on
      floated elements don't affect the borders and background of the elements
      they float over. So we add this border to force the issue. */
   border-left: 20px solid white;
-  border-bottom: 20px solid white;
-  z-index: 3;
+  float: right;
+  margin: 5px 0px 0px 0px;
+  padding: 5px;
   position: relative;
+  width: 250px;
+  word-break: break-word;
+  z-index: 3;
 }
 
 #toc * {
-  padding: 0;
   list-style: none;
-  white-space: nowrap;
   overflow: hidden;
+  padding: 0;
   text-overflow: ellipsis;
+  white-space: nowrap;
 }
 
 #toc h2 {
-  font-weight: bold;
-  font-size: 100%;
-  margin: 0;
   border: none;
+  font-size: 100%;
+  font-weight: bold;
+  margin: 0;
   padding: 0;
 }
 
@@ -512,8 +515,8 @@
 }
 
 #toc ol li {
-  margin: .5em 0 .5em 1em;
   line-height: 1.2em;
+  margin: .5em 0 .5em 1em;
 }
 
 #toc ol li ol {
@@ -562,28 +565,28 @@
 
 /* Tabbed pane with header (tabs) and content */
 tabs {
-  margin: 25px 0;
   display: block;
+  margin: 25px 0;
 }
 tabs header {
-  display: inline-block;
-  padding: 10px;
-  border: 1px solid #ccc;
-  margin-bottom: 0;
   background: inherit;
   border-bottom: 1px solid white;
+  border: 1px solid #ccc;
   cursor: auto;
+  display: inline-block;
+  margin-bottom: 0;
+  padding: 10px;
 }
 tabs header.unselected {
-  border-bottom: 1px solid #ccc;
   background: #eee;
+  border-bottom: 1px solid #ccc;
   cursor: pointer;
 }
 tabs content {
-  display: block;
-  padding: 20px;
   border: 1px solid #ccc;
+  display: block;
   margin-top: -1px;
+  padding: 20px;
 }
 tabs content.unselected {
   display: none;
@@ -592,3 +595,44 @@
   margin: 0;
   padding: 10px;
 }
+
+/*
+ * API references.
+ */
+
+.type_name,
+.variable,
+.property {
+  font-style: italic;
+}
+
+.api_reference div.summary {
+  background-color: #CADEF4;
+  border: 1px solid #93B4D9;
+  font-family: "Courier New", courier, monospace;
+  margin-top: 1em;
+  padding: 0.5em 0.5em 0.5em 2em;
+  text-indent: -1.5em;
+}
+
+/* This style is used because types with functions prefix the function with the
+ * type name, using a lowercase first letter. */
+.api_reference .uncapitalize:first-letter {
+  text-transform: lowercase;
+}
+
+.api_reference .capitalize:first-letter {
+  text-transform: uppercase;
+}
+
+.api_reference div.description {
+  margin-left: 2em;
+}
+
+div.summary .subdued {
+  color: #7594B8;
+}
+
+.optional {
+  color: #7D7D7D;
+}
diff --git a/chrome/common/extensions/docs/templates/articles/apps_manifest.html b/chrome/common/extensions/docs/templates/articles/apps_manifest.html
deleted file mode 100644
index ff9c038..0000000
--- a/chrome/common/extensions/docs/templates/articles/apps_manifest.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<h1>Formats: Manifest Files</h1>
-
-
-<p>
-Every extension, installable web app, and theme has a
-<a href="http://www.json.org">JSON</a>-formatted manifest file,
-named <code>manifest.json</code>,
-that provides important information.
-</p>
-
-<h2 id="overview"> Field summary </h2>
-
-<p>
-The following code shows the supported manifest fields,
-with links to the page that discusses each field.
-The only fields that are always required
-are <b>name</b> and <b>version</b>.
-</p>
-
-{{+partials.manifest_example manifest_source:manifest_source.apps}}
diff --git a/chrome/common/extensions/docs/templates/articles/background_pages.html b/chrome/common/extensions/docs/templates/articles/background_pages.html
index 2ff0e4c..50a42b4 100644
--- a/chrome/common/extensions/docs/templates/articles/background_pages.html
+++ b/chrome/common/extensions/docs/templates/articles/background_pages.html
@@ -81,7 +81,7 @@
 If you need the browser to start up early&mdash;so
 you can display notifications, for example&mdash;then
 you might also want to specify the
-<a href="declare_permissions.html#bg">"background" permission</a>.
+<a href="declare_permissions.html#background">"background" permission</a>.
 </p>
 
 
diff --git a/chrome/common/extensions/docs/templates/articles/declare_permissions.html b/chrome/common/extensions/docs/templates/articles/declare_permissions.html
index 0a9bf92..7b37c68 100644
--- a/chrome/common/extensions/docs/templates/articles/declare_permissions.html
+++ b/chrome/common/extensions/docs/templates/articles/declare_permissions.html
@@ -25,7 +25,7 @@
 declare the "storage" permission.
 </p>
 
-<p>
+<p id="manifest">
 Here's an example of the permissions part of a manifest file:
 </p>
 
@@ -44,9 +44,9 @@
 {{?is_apps}}
 <pre>
 "permissions": [
-    "serial",
-    "storage",
-    "videoCapture"
+  "serial",
+  "storage",
+  "videoCapture"
 ],
 </pre>
 {{/is_apps}}
@@ -55,371 +55,19 @@
 The following table lists the currently available permissions:
 </p>
 
-{{?is_apps}}
-<p class="note">
-<strong>Note:</strong>
-Hosted apps can use the
-"background", "clipboardRead", "clipboardWrite", "geolocation", "notifications",
-and "unlimitedStorage" permissions, but not any other permissions listed in this
-table.
-</p>
-{{/is_apps}}
-
 <table>
-<tr>
-  <th> Permission </th> <th> Description </th>
-</tr>
-<tr id="host-permission">
-  <td> <em>match pattern</em> </td>
-  <td> Specifies a <em>host permission</em>.
-       Required if the extension or app wants to interact
-       with the code running on pages.
-       Many capabilities, such as
-       <a href="xhr.html">cross-origin XMLHttpRequests</a>,
-       <a href="content_scripts.html#pi">programmatically injected
-       content scripts</a>, and
-       <a href="cookies.html">the extension's cookies API</a>
-       require host permissions. For details on the syntax, see
-       <a href="match_patterns.html">Match Patterns</a>.
-  </td>
-</tr>
-{{^is_apps}}
-<tr>
-  <td> "activeTab" </td>
-  <td> Requests that the extension be granted permissions according to the
-       <a href="activeTab.html">activeTab</a> specification.
-  </td>
-</tr>
-{{/is_apps}}
-<tr id="alarms">
-  <td> "alarms" </td>
-  <td> Required if the extension or app uses the
-       <a href="alarms.html">chrome.alarms</a> module.
-  </td>
-{{?is_apps}}
-<tr id="audioCapture">
-  <td> "audioCapture" </td>
-  <td> Requests that the app be granted permissions to capture audio
-       directly from the user's Microphone via the
-       <a href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html">getUserMedia</a> API.
-  </td>
-</tr>
-{{/is_apps}}
-<tr id="bg">
-  <td> "background" </td>
-  <td> <p>
-       Makes Chrome start up early and and shut down late,
-       so that apps and extensions can have a longer life.
-       </p>
-
-       <p>
-       When any installed hosted app, packaged app, or extension
-       has "background" permission, Chrome runs (invisibly)
-       as soon as the user logs into their computer&mdash;before
-       the user launches Chrome.
-       The "background" permission also makes Chrome continue running
-       (even after its last window is closed)
-       until the user explicitly quits Chrome.
-       </p>
-
-       <p class="note">
-       <b>Note:</b>
-       Disabled apps and extensions
-       are treated as if they aren't installed.
-       </p>
-
-       <p>
-       You typically use the "background" permission with a
-       <a href="background_pages.html">background page</a>,
-       <a href="event_pages.html">event page</a>
-       or (for hosted apps) a
-       <a href="http://code.google.com/chrome/apps/docs/background.html">background window</a>.
-       </p>
-       </td>
-</tr>
-{{?is_apps}}
-<tr id="bluetooth">
-  <td> "bluetooth" </td>
-  <td> Required if the app uses the
-       <a href="bluetooth.html">chrome.bluetooth</a> module.
-  </td>
-</tr>
-{{/is_apps}}
-{{^is_apps}}
-<tr>
-  <td> "bookmarks" </td>
-  <td> Required if the extension uses the
-       <a href="bookmarks.html">chrome.bookmarks</a> module. </td>
-</tr>
-<tr>
-  <td> "chrome://favicon/" </td>
-  <td> Required if the extension uses the
-       "chrome://favicon/<em>url</em>" mechanism
-       to display the favicon of a page.
-       For example, to display the favicon of http://www.google.com/,
-       you declare the "chrome://favicon/" permission
-       and use HTML code like this:
-       <pre>&lt;img src="chrome://favicon/http://www.google.com/"></pre>
-       </td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "clipboardRead" </td>
-  <td> Required if the extension or app uses
-       <code>document.execCommand('paste')</code>. </td>
-</tr>
-<tr>
-  <td> "clipboardWrite" </td>
-  <td> Indicates the extension or app uses
-       <code>document.execCommand('copy')</code> or
-       <code>document.execCommand('cut')</code>. This permission is <b>required
-       for hosted apps</b>; it's recommended for extensions and packaged apps.
-       </td>
-</tr>
-{{^is_apps}}
-<tr>
-  <td> "contentSettings" </td>
-  <td> Required if the extension uses the
-       <a href="contentSettings.html">chrome.contentSettings</a> module. </td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "contextMenus" </td>
-  <td> Required if the extension or app uses the
-       <a href="contextMenus.html">chrome.contextMenus</a> module. </td>
-</tr>
-{{^is_apps}}
-<tr>
-  <td> "cookies" </td>
-  <td> Required if the extension uses the
-       <a href="cookies.html">chrome.cookies</a> module. </td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "experimental" </td>
-  <td> Required if the extension or app uses any
-       <a href="experimental.html">chrome.experimental.* APIs</a>.</td>
-</tr>
-{{^is_apps}}
-<tr>
-  <td id="fileBrowserHandler"> "fileBrowserHandler" </td>
-  <td> Required if the extension uses the
-       <a href="fileBrowserHandler.html">fileBrowserhandler</a> module. </td>
-</tr>
-{{/is_apps}}
-{{?is_apps}}
-<tr>
-  <td id="fileSystem"> "fileSystem", "fileSystem.write",
-    "fileSystem.retainEntries" </td>
-  <td> Required if the app uses the
-       <a href="fileSystem.html">chrome.fileSystem</a> module.</td>
-</tr>
-{{/is_apps}}
-{{?is_apps}}
-<tr>
-  <td id="fullscreen"> "fullscreen" </td>
-  <td> Allows the app to use the <a href="app.window.html">app.window</a>
-       fullscreen state or the
-       <a href="https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html">HTML fullscreen API</a>.
-       See <a href="api_other.html">Other APIs</a> for behavior differences.</td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td id="geolocation"> "geolocation" </td>
-  <td> Allows the extension or app to use the proposed HTML5
-       <a href="http://dev.w3.org/geo/api/spec-source.html">geolocation API</a>
-       without prompting the user for permission. </td>
-</tr>
-{{^is_apps}}
-<tr>
-  <td> "history" </td>
-  <td> Required if the extension uses the
-       <a href="history.html">chrome.history</a> module. </td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "idle" </td>
-  <td> Required if the extension or app uses the
-       <a href="idle.html">chrome.idle</a> module. </td>
-</tr>
-{{^is_apps}}
-<tr>
-  <td> "management" </td>
-  <td> Required if the extension uses the
-       <a href="management.html">chrome.management</a> module. </td>
-</tr>
-{{/is_apps}}
-{{?is_apps}}
-<tr>
-  <td id="mediaGalleries"> "mediaGalleries": ["read"], "mediaGalleries": ["read", "allAutoDetected"] </td>
-  <td> Required if the app uses the
-       <a href="mediaGalleries.html">chrome.mediaGalleries</a> module. </td>
-</tr>
-{{/is_apps}}
-{{^is_apps}}
-<tr>
-  <td> "notifications" </td>
-  <td> Allows the extension to use the proposed HTML5
-       <a href="http://www.chromium.org/developers/design-documents/desktop-notifications/api-specification">notification API</a>
-       without calling permission methods
-       (such as <code>checkPermission()</code>).
-       For more information see
-       <a href="desktop_notifications.html">Desktop Notifications</a>.</td>
-</tr>
-{{/is_apps}}
-{{?is_apps}}
-<tr>
-  <td> "notifications" </td>
-  <td> Required if the app uses the
-       <a href="notifications.html">chrome.notifications</a> module.
-       Also allows the app to use the proposed HTML5
-       <a href="http://www.chromium.org/developers/design-documents/desktop-notifications/api-specification">notification API</a>
-       without calling permission methods
-       (such as <code>checkPermission()</code>).
-       For more information see
-       <a href="desktop_notifications.html">Desktop Notifications</a>.</td>
-</tr>
-{{/is_apps}}
-{{?is_apps}}
-<tr>
-  <td> "pointerLock" </td>
-  <td> Required to use
-       <a href="http://www.w3.org/TR/pointerlock/">Pointer Lock</a> via calls to
-       <code>webkitRequestPointerLock</code> or Pepper's
-       <a href="https://developers.google.com/native-client/peppercpp/classpp_1_1_mouse_lock">
-       Mouse Lock API</a>.
-       See <a href="api_other.html">Other APIs</a> for behavior differences.</td></td>
-</tr>
-{{/is_apps}}
-{{^is_apps}}
-<tr>
-  <td> "privacy" </td>
-  <td> Required if the extension uses the
-       <a href="privacy.html">chrome.privacy</a> module. </td>
-</tr>
-<tr>
-  <td> "proxy" </td>
-  <td> Required if the extension uses the
-       <a href="proxy.html">chrome.proxy</a> module. </td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "pushMessaging" </td>
-  <td> Required if the extension or app uses the
-       <a href="pushMessaging.html">chrome.pushMessaging</a> module. </td>
-</tr>
-{{?is_apps}}
-<tr>
-  <td id="serial"> "serial" </td>
-  <td> Required if the app uses the
-       <a href="serial.html">chrome.serial</a> module.</td>
-</tr>
-<tr>
-  <td id="socket"> "socket": ["rule1", "rule2"]  </td>
-  <td> Required if the app uses the
-       <a href="socket.html">chrome.socket</a> module.</td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "storage" </td>
-  <td> Required if the extension or app uses the
-       <a href="storage.html">chrome.storage</a> module. </td>
-</tr>
-{{?is_apps}}
-<tr>
-  <td id="syncFileSystem"> "syncFileSystem" </td>
-  <td> Required if the app uses the
-       <a href="syncFileSystem.html">chrome.syncFileSystem</a> module
-       to save and synchronize data on Google Drive.</td>
-</tr>
-{{/is_apps}}
-{{^is_apps}}
-<tr>
-  <td> "tabs" </td>
-  <td> Required if the extension uses the
-       <a href="tabs.html">chrome.tabs</a> or
-       <a href="windows.html">chrome.windows</a> module. </td>
-</tr>
-<tr>
-  <td> "tabCapture" </td>
-  <td> Required if the extension uses the
-       <a href="tabCapture.html">chrome.tabCapture</a> module. </td>
-</tr>
-<tr>
-  <td> "topSites" </td>
-  <td> Required if the extension uses the
-       <a href="topSites.html">chrome.topSites</a> module. </td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "tts" </td>
-  <td> Required if the extension or app uses the
-       <a href="tts.html">chrome.tts</a> module. </td>
-</tr>
-{{^is_apps}}
-<tr>
-  <td> "ttsEngine" </td>
-  <td> Required if the extension uses the
-       <a href="ttsEngine.html">chrome.ttsEngine</a> module. </td>
-</tr>
-{{/is_apps}}
-<tr>
-  <td> "unlimitedStorage"</td>
-  <td> Provides an unlimited quota for storing HTML5 client-side data,
-       such as databases and local storage files.
-       Without this permission, the extension or app is limited to
-       5 MB of local storage.
-
-      <p class="note">
-      <b>Note:</b>
-      This permission applies only to Web SQL Database and application cache
-      (see issue <a href="http://crbug.com/58985">58985</a>).
-      Also, it doesn't currently work with wildcard subdomains such as
-      <code>http://*.example.com</code>.
-      </p>
-  </td>
-<tr>
-{{?is_apps}}
-<tr>
-  <td id="usb"> "usb" </td>
-  <td> Required if the app uses the
-       <a href="usb.html">chrome.usb</a> module.</td>
-</tr>
-{{/is_apps}}
-{{?is_apps}}
-<tr id="videoCapture">
-  <td> "videoCapture" </td>
-  <td> Requests that the app be granted permissions to capture video
-       directly from the user's Web Cam via the
-       <a href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html">getUserMedia</a> API.
-  </td>
-</tr>
-{{/is_apps}}
-{{^is_apps}}
-<tr>
-  <td> "webNavigation" </td>
-  <td> Required if the extension uses the
-       <a href="webNavigation.html">chrome.webNavigation</a> module. </td>
-</tr>
-<tr>
-  <td> "webRequest" </td>
-  <td> Required if the extension uses the
-       <a href="webRequest.html">chrome.webRequest</a> module. </td>
-</tr>
-<tr>
-  <td> "webRequestBlocking" </td>
-  <td> Required if the extension uses the
-       <a href="webRequest.html">chrome.webRequest</a> module in a blocking
-       fashion. </td>
-</tr>
-{{/is_apps}}
-{{?is_apps}}
-<tr>
-  <td id="webview"> "webview" </td>
-  <td> Required if the app uses the
-       <a href="webview_tag.html">Webview Tag</a> to embed live content
-       from the web in the packaged app.</td>
-</tr>
-{{/is_apps}}
-</tr>
+  <tr>
+    <th>Permission</th>
+    <th>Description</th>
+  </tr>
+  {{#permissions}}
+  <tr id="{{anchor}}">
+    <td>
+      <code>"{{name}}"</code>
+    </td>
+    <td>
+      {{+description platform:platform name:name}}
+    </td>
+  </tr>
+  {{/permissions}}
 </table>
diff --git a/chrome/common/extensions/docs/templates/articles/extensions_manifest.html b/chrome/common/extensions/docs/templates/articles/extensions_manifest.html
deleted file mode 100644
index a6de39a..0000000
--- a/chrome/common/extensions/docs/templates/articles/extensions_manifest.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<h1>Formats: Manifest Files</h1>
-
-
-<p>
-Every extension, installable web app, and theme has a
-<a href="http://www.json.org">JSON</a>-formatted manifest file,
-named <code>manifest.json</code>,
-that provides important information.
-</p>
-
-<h2 id="overview"> Field summary </h2>
-
-<p>
-The following code shows the supported manifest fields,
-with links to the page that discusses each field.
-The only fields that are always required
-are <b>name</b> and <b>version</b>.
-</p>
-
-{{+partials.manifest_example manifest_source:manifest_source.extensions}}
diff --git a/chrome/common/extensions/docs/templates/articles/manifest.html b/chrome/common/extensions/docs/templates/articles/manifest.html
index 290094a..06536b1 100644
--- a/chrome/common/extensions/docs/templates/articles/manifest.html
+++ b/chrome/common/extensions/docs/templates/articles/manifest.html
@@ -17,641 +17,4 @@
 are <b>name</b> and <b>version</b>.
 </p>
 
-<pre>
-{
-  <em>// Required</em>
-  "<a href="#name">name</a>": "<em>My Extension</em>",
-  "<a href="#version">version</a>": "<em>versionString</em>",
-  "<a href="#manifest_version">manifest_version</a>": 2,
-{{?is_apps}}
-  "<a href="#app">app</a>": {...},
-{{/is_apps}}
-
-  <em>// Recommended</em>
-  "<a href="#description">description</a>": "<em>A plain text description</em>",
-  "<a href="#icons">icons</a>": { ... },
-  "<a href="#default_locale">default_locale</a>": "<em>en</em>",
-{{^is_apps}}
-
-  <em>// Pick one (or none)</em>
-  "<a href="browserAction.html">browser_action</a>": {...},
-  "<a href="pageAction.html">page_action</a>": {...},
-  "<a href="themes.html">theme</a>": {...},
-  "<a href="#app">app</a>": {...},
-{{/is_apps}}
-
-  <em>// Add any of these that you need</em>
-  "<a href="event_pages.html">background</a>": {"persistent": false, ...},
-  "<a href="background_pages.html">background</a>": {"persistent": true, ...},
-{{^is_apps}}
-  "<a href="override.html">chrome_url_overrides</a>": {...},
-{{/is_apps}}
-  "<a href="content_scripts.html">content_scripts</a>": [...],
-  "<a href="contentSecurityPolicy.html">content_security_policy</a>": "<em>policyString</em>",
-  "<a href="fileBrowserHandler.html">file_browser_handlers</a>": [...],
-  "<a href="#file_handlers">file_handlers</a>": {...},
-  "<a href="#homepage_url">homepage_url</a>": "http://<em>path/to/homepage</em>",
-  "<a href="#incognito">incognito</a>": "spanning" <em>or</em> "split",
-  "<a href="#key">key</a>": "<em>publicKey</em>",
-  "<a href="#minimum_chrome_version">minimum_chrome_version</a>": "<em>versionString</em>",
-
-  "<a href="#nacl_modules">nacl_modules</a>": [...],
-  "<a href="#kiosk_enabled">kiosk_enabled</a>": true,
-  "<a href="#offline_enabled">offline_enabled</a>": true,
-  "<a href="omnibox.html">omnibox</a>": { "keyword": "<em>aString</em>" },
-{{^is_apps}}
-  "<a href="options.html">options_page</a>": "<em>aFile</em>.html",
-{{/is_apps}}
-  "<a href="declare_permissions.html">permissions</a>": [...],
-  "<a href="npapi.html">plugins</a>": [...],
-  "<a href="#requirements">requirements</a>": {...},
-  "<a href="autoupdate.html">update_url</a>": "http://<em>path/to/updateInfo</em>.xml",
-  "<a href="#web_accessible_resources">web_accessible_resources</a>": [...],
-  "<a href="#sandbox">sandbox</a>": [...]
-}
-</pre>
-
-
-<h2 id="field_details">Field details</h2>
-
-<p>
-This section covers fields that aren't described in another page.
-For a complete list of fields,
-with links to where they're described in detail,
-see the <a href="#overview">Field summary</a>.
-</p>
-
-
-<h3 id="app">app</h3>
-
-<p>
-Used by <a href="../apps/app_lifecycle.html#eventpage">packaged apps</a>
-to specify the app's background scripts.
-Also used by <a href="https://developers.google.com/chrome/apps/docs/developers_guide#live">hosted apps</a>
-to specify the URLs that the app uses.
-</p>
-
-<h3 id="default_locale">default_locale</h3>
-
-<p>
-Specifies the subdirectory of <code>_locales</code>
-that contains the default strings for this extension.
-This field is <b>required</b> in extensions
-that have a <code>_locales</code> directory;
-it <b>must be absent</b> in extensions
-that have no <code>_locales</code> directory.
-For details, see
-<a href="i18n.html">Internationalization</a>.
-</p>
-
-<h3 id="description">description</h3>
-
-<p>
-A plain text string
-(no HTML or other formatting;
-no more than 132 characters)
-that describes the extension.
-The description should be suitable for both
-the browser's extension management UI
-and the <a href="https://chrome.google.com/webstore">Chrome Web Store</a>.
-You can specify locale-specific strings for this field;
-see <a href="i18n.html">Internationalization</a> for details.
-</p>
-
-<h3 id="file_handlers">file_handlers</h3>
-
-<p>
-Used by <a href="../apps/app_lifecycle.html#eventpage">packaged apps</a>
-to specify what types of files the app can handle. An app can have multiple <code>file_handlers</code>, with each one having an identifier, a list of MIME types and/or a list of file extensions that can be handled, and
-a title. The app can handle a file if it either has a matching file extension or
-has a matching MIME type.
-You can use a wildcard <code>"*"</code> in <code>types</code> or
-<code>extensions</code> to indicate that the app can handle any file type or
-<code>"<em>type</em>/*"</code> in <code>types</code> to indicate that the app
-can handle any file with a MIME type of <code><em>type</em></code>.
-Here's an example of specifying file handlers:
-</p>
-
-<pre>
-"file_handlers": {
-  "text": {
-    "types": [
-      "text/*"
-    ],
-    "title": "Text editor"
-  },
-  "image": {
-    "types": [
-      "image/png",
-      "image/jpeg"
-    ],
-    "extensions": [
-      "tiff"
-    ]
-    "title": "Image editor"
-  },
-  "any": {
-    "extensions": [
-      "*"
-    ]
-    "title": "Any file type editor"
-  }
-}
-</pre>
-
-<p>
-To handle files, apps also need to declare the $ref:fileSystem
-permission. Apps can then be passed files in the $ref:app.runtime.onLaunched
-event - either from the system
-file manager (currently supported on ChromeOS only) or by providing
-a path on the <a href="../apps/first_app.html#open">command line</a>.
-</p>
-
-<h3 id="homepage_url">homepage_url</h3>
-
-<p>
-The URL of the homepage for this extension. The extensions management page (chrome://extensions)
-will contain a link to this URL.  This field is particularly useful if you
-<a href="hosting.html">host the extension on your own site</a>. If you distribute your
-extension using the <a href="https://chrome.google.com/webstore">Chrome Web Store</a>,
-the homepage URL defaults to the extension's own page.
-</p>
-
-<h3 id="icons">icons</h3>
-
-<p>
-One or more icons that represent the extension, app, or theme.
-You should always provide a 128x128 icon;
-it's used during installation and by the Chrome Web Store.
-Extensions should also provide a 48x48 icon,
-which is used in the extensions management page
-(chrome://extensions).
-You can also specify a 16x16 icon to be used as the favicon
-for an extension's pages.
-The 16x16 icon is also displayed in the experimental extension
-<a href="infobars.html">infobar</a>
-feature.
-</p>
-
-<p>
-Icons should generally be in PNG format,
-because PNG has the best support for transparency.
-They can, however, be in any format supported by WebKit,
-including BMP, GIF, ICO, and JPEG.
-Here's an example of specifying the icons:
-</p>
-
-<pre>
-"icons": { "16": "icon16.png",
-           "48": "icon48.png",
-          "128": "icon128.png" },
-</pre>
-
-<p class="note">
-You may provide icons of any other size you wish, and Chrome will attempt to use
-the best size where appropriate. For example, Windows often requires 32-pixel
-icons, and if the app includes a 32-pixel icon, Chrome will choose that instead
-of shrinking a 48-pixel icon down. However, you should ensure that all of your
-icons are square, or unexpected behavior may result.
-</p>
-
-<p>
-If you upload your extension, app, or theme using the
-<a href="https://chrome.google.com/webstore/developer/dashboard">Chrome Developer Dashboard</a>,
-you'll need to upload additional images,
-including at least one screenshot of your extension.
-For more information,
-see the
-<a href="http://code.google.com/chrome/webstore/">Chrome Web Store
-developer documentation</a>.
-</p>
-
-<h3 id="incognito">incognito</h3>
-
-<p>
-Either "spanning" or "split", to specify how this extension 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.
-</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.
-</p>
-
-<h3 id="key">key</h3>
-
-<p>
-This value can be used to control
-the unique ID of an extension, app, or theme when
-it is loaded during development.
-</p>
-
-<p class="note">
-<b>Note:</b> You don't usually need to
-use this value. Instead, write your
-code so that the key value doesn't matter
-by using <a href="../extensions/overview.html#relative-urls">relative paths</a>
-and $ref:runtime.getURL.
-</p>
-
-<p>
-To get a suitable key value, first
-install your extension from a <code>.crx</code> file
-(you may need to
-<a href="https://chrome.google.com/webstore/developer/dashboard">upload your extension</a>
-or <a href="packaging.html">package it manually</a>).
-Then, in your
-<a href="http://www.chromium.org/user-experience/user-data-directory">user
-data directory</a>, look in the file
-<code>Default/Extensions/<em>&lt;extensionId&gt;</em>/<em>&lt;versionString&gt;</em>/manifest.json</code>.
-You will see the key value filled in there.
-</p>
-
-<h3 id="minimum_chrome_version">minimum_chrome_version</h3>
-
-<p>
-The version of Chrome that your extension, app, or theme requires, if any.
-The format for this string is the same as for the
-<a href="#version">version</a> field.
-
-<h3 id="name">name</h3>
-
-<p>
-A short, plain text string
-(no more than 45 characters)
-that identifies the extension.
-The name is used in the install dialog,
-extension management UI,
-and the <a href="https://chrome.google.com/webstore">store</a>.
-You can specify locale-specific strings for this field;
-see <a href="i18n.html">Internationalization</a> for details.
-</p>
-
-<h3 id="nacl_modules">nacl_modules</h3>
-
-<p>
-One or more mappings from MIME types to the Native Client module
-that handles each type.
-For example, the bold code in the following snippet
-registers a Native Client module as the content handler
-for the OpenOffice spreadsheet MIME type.
-</p>
-
-<pre>
-{
-  "name": "Native Client OpenOffice Spreadsheet Viewer",
-  "version": "0.1",
-  "description": "Open OpenOffice spreadsheets, right in your browser.",
-  <b>"nacl_modules": [{
-    "path": "OpenOfficeViewer.nmf",
-    "mime_type": "application/vnd.oasis.opendocument.spreadsheet"
-  }]</b>
-}
-</pre>
-
-<p>
-The value of "path" is the location of a Native Client manifest
-(a <code>.nmf</code> file)
-within the extension directory.
-For more information on Native Client and <code>.nmf</code> files, see the
-<a href="http://code.google.com/chrome/nativeclient/docs/technical_overview.html">Native Client Technical Overview</a>.
-</p>
-
-<p>
-Each MIME type can be associated with only one <code>.nmf</code> file,
-but a single <code>.nmf</code> file might handle multiple MIME types.
-The following example shows an extension
-with two <code>.nmf</code> files
-that handle three MIME types.
-</p>
-
-<pre>
-{
-  "name": "Spreadsheet Viewer",
-  "version": "0.1",
-  "description": "Open OpenOffice and Excel spreadsheets, right in your browser.",
-  "nacl_modules": [{
-    "path": "OpenOfficeViewer.nmf",
-    "mime_type": "application/vnd.oasis.opendocument.spreadsheet"
-  },
-  {
-    "path": "OpenOfficeViewer.nmf",
-    "mime_type": "application/vnd.oasis.opendocument.spreadsheet-template"
-  },
-  {
-    "path": "ExcelViewer.nmf",
-    "mime_type": "application/excel"
-  }]
-}
-</pre>
-
-<p class="note">
-<strong>Note:</strong>
-You can use Native Client modules in extensions
-without specifying "nacl_modules".
-Use "nacl_modules" only if you want the browser
-to use your Native Client module
-to display a particular type of content.
-</p>
-
-<h3 id="kiosk_enabled">kiosk_enabled</h3>
-
-<p>
-Whether the packaged app is designed to expected to work in ChromeOS kiosk mode.
-In kiosk mode, the platform app window will cover the entire surface of the
-display (forced full screen). The kiosk-enabled apps are expected to be designed
-with this constraint in mind.
-</p>
-
-<h3 id="offline_enabled">offline_enabled</h3>
-
-<p>
-Whether the app or extension is expected to work offline. When Chrome detects
-that it is offline, apps with this field set to true will be highlighted
-on the New Tab page.
-</p>
-
-<h3 id="requirements">requirements</h3>
-
-<p>
-Technologies required by the app or extension.
-Hosting sites such as the Chrome Web Store may use this list
-to dissuade users from installing apps or extensions
-that will not work on their computer.
-Supported requirements currently include "3D" and "plugins";
-additional requirements checks may be added in the future.
-</p>
-
-<p>
-The "3D" requirement denotes GPU hardware acceleration.
-The "webgl" requirement refers to the
-<a href="http://www.khronos.org/webgl/">WebGL API</a>.
-For more information on Chrome 3D graphics support,
-see the help article on
-<a href="http://www.google.com/support/chrome/bin/answer.py?answer=1220892">WebGL and 3D graphics</a>.
-You can list the 3D-related features your app requires,
-as demonstrated in the following example:
-</p>
-
-<pre>
-"requirements": {
-  "3D": {
-    "features": ["webgl"]
-  }
-}
-</pre>
-
-<p>
-The "plugins" requirement indicates
-if an app or extension requires NPAPI to run.
-This requirement is enabled by default
-when the manifest includes the
-<a href="npapi.html">"plugins" field</a>.
-For apps and extensions that still work when plugins aren't available,
-you can disable this requirement
-by setting NPAPI to false.
-You can also enable this requirement manually,
-by setting NPAPI to true,
-as shown in this example:
-</p>
-
-<pre>
-"requirements": {
-  "plugins": {
-    "npapi": true
-  }
-}
-</pre>
-
-
-<h3 id="version">version</h3>
-
-<p>
-One to four dot-separated integers
-identifying the version of this extension.
-A couple of rules apply to the integers:
-they must be between 0 and 65535, inclusive,
-and non-zero integers can't start with 0.
-For example, 99999 and 032 are both invalid.
-</p>
-
-<p>
-Here are some examples of valid versions:
-</p>
-
-<ul>
-  <li> <code>"version": "1"</code> </li>
-  <li> <code>"version": "1.0"</code> </li>
-  <li> <code>"version": "2.10.2"</code> </li>
-  <li> <code>"version": "3.1.2.4567"</code> </li>
-</ul>
-
-<p>
-The autoupdate system compares versions
-to determine whether an installed extension
-needs to be updated.
-If the published extension has a newer version string
-than the installed extension,
-then the extension is automatically updated.
-</p>
-
-<p>
-The comparison starts with the leftmost integers.
-If those integers are equal,
-the integers to the right are compared,
-and so on.
-For example, 1.2.0 is a newer version than 1.1.9.9999.
-</p>
-
-<p>
-A missing integer is equal to zero.
-For example, 1.1.9.9999 is newer than 1.1.
-</p>
-
-<p>
-For more information, see
-<a href="autoupdate.html">Autoupdating</a>.
-</p>
-
-
-
-<h3 id="manifest_version">manifest_version</h3>
-
-<p>
-One integer specifying the version of the manifest file format your package
-requires. As of Chrome 18, developers <em>should</em> specify <code>2</code>
-(without quotes) to use the format as described by this document:
-</p>
-
-<pre>"manifest_version": 2</pre>
-
-<p>
-Consider manifest version 1 <em>deprecated</em> as of Chrome 18. Version 2 is
-not yet <em>required</em>, but we will, at some point in the not-too-distant
-future, stop supporting packages using deprecated manifest versions. Extensions,
-applications, and themes that aren't ready to make the jump to the new manifest
-version in Chrome 18 can either explicitly specify version <code>1</code>, or
-leave the key off entirely.
-</p>
-
-<p>
-The changes between version 1 and version 2 of the manifest file format are
-described in detail in <a href="manifestVersion.html">the
-<code>manifest_version</code> documentation.</a>
-</p>
-
-<p class="caution">
-  Setting <code>manifest_version</code> 2 in Chrome 17 or lower is not
-  recommended. If your extension needs to work in older versions of Chrome,
-  stick with version 1 for the moment. We'll give you ample warning before
-  version 1 stops working.
-</p>
-
-<h3 id="web_accessible_resources">web_accessible_resources</h3>
-
-<p>
-An array of strings specifying the paths (relative to the package root) of
-packaged resources that are expected to be usable in the context of a web page.
-For example, an extension that injects a content script with the intention of
-building up some custom interface for <code>example.com</code> would whitelist
-any resources that interface requires (images, icons, stylesheets, scripts,
-etc.) as follows:
-</p>
-
-<pre>{
-  ...
-  "web_accessible_resources": [
-    "images/my-awesome-image1.png",
-    "images/my-amazing-icon1.png",
-    "style/double-rainbow.css",
-    "script/double-rainbow.js"
-  ],
-  ...
-}</pre>
-
-<p>
-These resources would then be available in a webpage via the URL
-<code>chrome-extension://[PACKAGE ID]/[PATH]</code>, which can be generated with
-the $ref:runtime.getURL method. Whitelisted resources are served with appropriate
-<a href="http://www.w3.org/TR/cors/">CORS</a> headers, so they're available via
-mechanisms like XHR.
-</p>
-
-<p>
-Injected content scripts themselves do not need to be whitelisted.
-</p>
-
-<p>
-Prior to manifest version 2 all resources within an extension could be accessed
-from any page on the web. This allowed a malicious website to
-<a href="http://en.wikipedia.org/wiki/Device_fingerprint">fingerprint</a> the
-extensions that a user has installed or exploit vulnerabilities (for example
-<a href="http://en.wikipedia.org/wiki/Cross-site_scripting">XSS bugs</a>)within
-installed extensions. Limiting availability to only resources which are
-explicitly intended to be web accessible serves to both minimize the available
-attack surface and protect the privacy of users.
-</p>
-
-<h4 id="availability">Default Availability</h4>
-
-<p>
-Resources inside of packages using <a href="#manifest_version"><code>manifest_version</code></a>
-2 or above are <strong>blocked by default</strong>, and must be whitelisted
-for use via this property.
-</p>
-
-<p>
-Resources inside of packages using <code>manifest_version</code> 1 are available
-by default, but <em>if</em> you do set this property, then it will be treated as
-a complete list of all whitelisted resources. Resources not listed will be
-blocked.
-</p>
-
-<h3 id="sandbox">sandbox</h3>
-
-<p>
-Defines an collection of app or extension pages that are to be served
-in a sandboxed unique origin, and optionally a Content Security Policy to use
-with them. Being in a sandbox has two implications:
-</p>
-
-<ol>
-<li>A sandboxed page will not have access to extension or app APIs, or
-direct access to non-sandboxed pages (it may communicate with them via
-<code>postMessage()</code>).</li>
-<li>
-  <p>A sandboxed page is not subject to the
-  <a href="../extensions/contentSecurityPolicy.html">Content Security Policy
-  (CSP)</a> used by the rest of the app or extension (it has its own separate
-  CSP value). This means that, for example, it can use inline script and
-  <code>eval</code>.</p>
-
-  <p>For example, here's how to specify that two extension pages are to be
-  served in a sandbox with a custom CSP:</p>
-
-  <pre>{
-  ...
-  "sandbox": {
-    "pages": [
-      "page1.html",
-      "directory/page2.html"
-    ]
-    <i>// content_security_policy is optional.</i>
-    "content_security_policy":
-        "sandbox allow-scripts; script-src https://www.google.com"
-  ],
-  ...
-}</pre>
-
-  <p>
-  If not specified, the default <code>content_security_policy</code> value is
-  <code>sandbox allow-scripts allow-forms</code>. You can specify your CSP
-  value to restrict the sandbox even further, but it must have the <code>sandbox</code>
-  directive and may not have the <code>allow-same-origin</code> token (see
-  <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-sandbox">the
-  HTML5 specification</a> for possible sandbox tokens).
-  </p>
-</li>
-</ol>
-
-<p>
-Note that you only need to list pages that you expected to be loaded in
-windows or frames. Resources used by sandboxed pages (e.g. stylesheets or
-JavaScript source files) do not need to appear in the
-<code>sandboxed_page</code> list, they will use the sandbox of the page
-that embeds them.
-</p>
-
-<p>
-<a href="sandboxingEval.html">"Using eval in Chrome Extensions. Safely."</a>
-goes into more detail about implementing a sandboxing workflow that enables use
-of libraries that would otherwise have issues executing under extension's
-<a href="../extensions/contentSecurityPolicy.html">default Content Security
-Policy</a>.
-</p>
-
-<p>
-Sandboxed page may only be specified when using
-<a href="#manifest_version"><code>manifest_version</code></a> 2 or above.
-</p>
+{{+partials.manifest_example manifest_source:manifest_source}}
diff --git a/chrome/common/extensions/docs/templates/articles/manifest/externally_connectable.html b/chrome/common/extensions/docs/templates/articles/manifest/externally_connectable.html
new file mode 100644
index 0000000..bb7033d
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/articles/manifest/externally_connectable.html
@@ -0,0 +1,38 @@
+<h1>externally_connectable</h1>
+
+<p>
+The <code>externally_connectable</code> manifest property declares which extensions, apps, and web pages can connect to your extension via <a href="../runtime.html#method-connect">runtime.connect</a> and <a href="../runtime.html#method-sendMessage">runtime.sendMessage</a>.
+</p>
+
+<p>
+For a tutorial on message passing see <a href="../messaging.html#external">cross-extension and app messaging</a> and <a href="../messaging.html#external-webpage">sending messages from web pages</a>.
+</p>
+
+<h2 id="manifest">Sample manifest.json</h2>
+<pre>
+{
+  "name": "My externally connectable {{platform}}",
+  "externally_connectable": {
+    // Extension and app IDs:
+    "ids": [
+      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+      "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+      ...
+    ],
+    // Alternatively, for all extensions and apps:
+    "ids": ["*"],
+    // Match patterns for <em>web pages</em>, not content scripts:
+    "matches": [
+      "https://*.google.com",
+      "*://*.chromium.org",
+      ...
+    ]
+  },
+  ...
+}
+</pre>
+
+<h2 id="reference">Reference</h2>
+<p class="api_reference">
+{{+partials.type @:apis.manifestTypes.byName.ExternallyConnectable}}
+</p>
diff --git a/chrome/common/extensions/docs/templates/articles/whats_new.html b/chrome/common/extensions/docs/templates/articles/whats_new.html
index 3614243..d5033fd 100644
--- a/chrome/common/extensions/docs/templates/articles/whats_new.html
+++ b/chrome/common/extensions/docs/templates/articles/whats_new.html
@@ -536,7 +536,7 @@
 
 <h4> Manifest changes </h4>
   <ul>
-    <li>The new <a href="declare_permissions.html#bg">background</a> permission
+    <li>The new <a href="declare_permissions.html#background">background</a> permission
       extends the life of Chrome,
       allowing your extension or app
       to run even when Chrome has no windows open.
@@ -629,13 +629,13 @@
 
 <h4> Additions to existing APIs </h4>
   <ul>
-    <li>The 
+    <li>The
       $ref:extension.getViews
       method can now return popup views.
-    <li>A new 
+    <li>A new
       $ref:windows.WINDOW_ID_NONE constant
       identifies when focus shifts away from the browser.
-    <li>The new 
+    <li>The new
       $ref:tabs.getCurrent method
       returns the tab associated with the currently executing script.
   </ul>
diff --git a/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html b/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html
index 3a716c2..0ee6b93 100644
--- a/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html
+++ b/chrome/common/extensions/docs/templates/intros/declarativeWebRequest.html
@@ -11,7 +11,7 @@
   ...
 <b>  "permissions": [
     "declarativeWebRequest",
-    "*://*.google.com"
+    "*://*/*"
   ]</b>,
   ...
 }</pre>
@@ -34,8 +34,8 @@
 All other actions require host permissions to all URLs.
 </p>
 <p>
-As an example, if <code>"*://*.google.com"</code> is the only host permission an
-extension has, than such an extension may set up a rule to
+As an example, if <code>"*://*.google.com/*"</code> is the only host permission
+an extension has, than such an extension may set up a rule to
 <ul>
   <li> cancel a request to "http://www.google.com" or "http://anything.else.com"
   <li> send a message when navigating to "http://www.google.com" but not to
diff --git a/chrome/common/extensions/docs/templates/intros/mediaGalleries.html b/chrome/common/extensions/docs/templates/intros/mediaGalleries.html
index 9f14be0..d01545a 100644
--- a/chrome/common/extensions/docs/templates/intros/mediaGalleries.html
+++ b/chrome/common/extensions/docs/templates/intros/mediaGalleries.html
@@ -1,31 +1,86 @@
 <h2 id="usage">Usage</h2>
 
-<p>
-Using the API, you can prompt the user for permission to access the media
-galleries. The permission dialog will contain common media locations for
-the platform and will allow the user to add additional locations. From those
-locations, only media files will be present in the file system objects.
-</p>
+<p>The mediaGalleries API lets you prompt the user for permission to access
+media galleries on the user's computer. The permission dialog contains common
+media locations for the platform and allows the user to specify additional
+locations. From those locations, only media files will be present in the file
+system objects.</p>
 
 <h2 id="manifest">Manifest</h2>
-<p>The media galleries API has two axes of permission parameters; the locations
-that can be accessed, and the types of access (read-only, copy-to, etc).</p>
 
-<p>On the location axis, specifying no location-type permission parameters
-means that
-no media galleries are accessible until the user grants permission to
-specific media galleries at runtime using the media gallery configuration
-dialog. This dialog can be programmatically triggered.  Alternatively,
-specifying the "allAutoDetected" permission parameter grants access to all
-auto-detected media galleries on the user's computer. However, this
-permission displays an install time prompt indicating that the app
-will have access to all of the user's media files.</p>
+<p>The media galleries API has two axes of permission parameters:</p>
 
-<p>On the access type axis, the "read" permission parameter grants the
-app the right to read files. This permission does not trigger an install
-time permission prompt because the user must still grant access to particular
-galleries, either with the "allAutoDetected" permission parameter or at
-runtime by using the media gallery management dialog. For example:</p>
+<ul>
+  <li>the locations that can be accessed</li>
+  <li>the type of access</li>
+</ul>
+
+<p>These two axes and the permission parameters on each axis are described
+in the table below:</p>
+
+<table>
+    <tr>
+      <th>Axis</th>
+      <th>Parameter</th>
+      <th>Effect</th>
+    </tr>
+    <tr>
+      <td rowspan="2">Locations</td>
+      <td>none</td>
+      <td>
+        If you do not specify a location permission parameter, your app will
+        not be able to access any media galleries until the user grants
+        permission to access specific media galleries at runtime using the
+        media gallery permission dialog.
+      </td>
+    </tr>
+    <tr>
+      <td>"allAutoDetected"</td>
+      <td>
+        Grants your app access to all auto-detected media galleries on the
+        user's computer. This permission causes an install-time prompt to be
+        displayed indicating that the app will have access to the user's media
+        files.
+      </td>
+    </tr>
+    <tr>
+      <td rowspan="2">Access&nbsp;type</td>
+      <td>"read"</td>
+      <td>Grants your app the right to read files in media galleries.</td>
+    </tr>
+    <tr>
+      <td>"copyTo"</td>
+      <td>
+        Grants your app the right to copy files into media galleries.
+        Only valid media files that Chrome is capable of playing or displaying
+        are permitted; files that Chrome is not able to validate will result
+        in a security error.
+      </td>
+    </tr>
+</table>
+
+<p>Notes:</p>
+<ul>
+  <li>The media gallery permission dialog can be triggered programmatically.
+  The user may have alternate media locations, so even if you specify
+  "allAutoDetected" permsission, it is still important to provide a mechanism
+  to open the permission dialog in your app.</li>
+
+  <li>There is no write access to media galleries due to the
+  file validation requirement. However, you can write files to
+  a different file system like the temporary file system, and then copy
+  the files into the desired media gallery.</li>
+
+  <li>You can specify "read" and "copyTo" to obtain both types of permissions
+  to media galleries.</li>
+
+  <li>Access type permissions do not trigger an install-time prompt
+  by themselves. However, the type of access will be reflected in the
+  media gallery permission dialog, as well as the install-time prompt if
+  "allAutoDetected" permission is requested.</li>
+</ul>
+
+<p>Below is an example of a manifest file with mediaGalleries permissions:</p>
 
 <pre>{
   "name": "My app",
@@ -36,13 +91,8 @@
   ...
 }</pre>
 
-<p>The above permission will trigger an install time permission prompt
+<p>This example manifest file will trigger an install-time permission prompt,
 and let the app read from all auto-detected media galleries on the
 user's computer. The user may add or remove galleries using the
-media gallery management dialog, after which the app will be able
-to read all the media files from galleries that the user has selected.</p>
-
-<p>Another possible access type is "copyTo". Specifying only "copyTo" on the
-access type axis will permit using accessible media galleries as a destination
-for copyTo() operations. "copyTo" and "read" can both be specified to obtain
-both types of permissions to accessible media galleries.</p>
+media gallery permission dialog, after which the app will be able
+to read all the media files from galleries that the user selected.</p>
diff --git a/chrome/common/extensions/docs/templates/intros/permissions.html b/chrome/common/extensions/docs/templates/intros/permissions.html
index 16b3ade..f97f050 100644
--- a/chrome/common/extensions/docs/templates/intros/permissions.html
+++ b/chrome/common/extensions/docs/templates/intros/permissions.html
@@ -1,55 +1,44 @@
-<p>
-  For general information about permissions and details about each permission,
-  see the <a href="declare_permissions.html">declare permissions</a> documentation.
-</p>
-
 <h2 id="howto"> Implementing optional permissions </h2>
 
 <h3 id="types">
-  Step 1: Decide which permissions are optional and required
+Step 1: Decide which permissions are required and which are optional
 </h3>
+
 <p>
-  Extensions should generally require permissions when they are needed for the
-  extension's basic functionality and employ optional permissions for optional
-  features.
+An extension can declare both required and optional permissions. In general, you should:
+<ul>
+  <li>Use required permissions when they are needed for your extension’s basic functionality.</li>
+  <li>Use optional permissions when they are needed for optional features in your extension.</li>
+</ul>
 </p>
 
 <p>
-  Advantages of optional permissions:
-  <ul>
-    <li>
-      Users run with less permissions since they enable only what is needed.
-    </li>
-    <li>
-      The extension can help explain why it needs particular permissions by
-      requesting them when the user enables the relevant feature.
-    </li>
-    <li>
-      Chrome can avoid disabling extensions that upgrade if they add permissions
-      as optional rather than required.
-    </li>
-  </ul>
+Advantages of <em>required</em> permissions:
+<ul>
+  <li><strong>Fewer prompts:</strong>
+      An extension can prompt the user once to accept all permissions.</li>
+  <li><strong>Simpler development:</strong>
+      Required permissions are guaranteed to be present.</li>
+</ul>
 </p>
 
 <p>
-  Advantages of required permissions:
-  <ul>
-    <li>
-      The extension can prompt the user once to accept all permissions.
-    </li>
-    <li>
-      They simplify extension development by guaranteeing which permissions are
-      present.
-    </li>
-  </ul>
+Advantages of <em>optional</em> permissions:
+<ul>
+  <li><strong>Better security:</strong>
+      Extensions run with fewer permissions since users only enable permissions that are needed.</li>
+  <li><strong>Better information for users:</strong>
+      An extension can explain why it needs a particular permission when the user enables the relevant feature.</li>
+  <li><strong>Easier upgrades:</strong>
+      When you upgrade your extension, Chrome will not disable it for your users if the upgrade adds optional rather than required permissions.</li>
+</ul>
 </p>
 
-
 <h3 id="manifest"> Step 2: Declare optional permissions in the manifest </h3>
 <p>
   Declare optional permissions in your <a href="manifest.html">extension
   manifest</a> with the <code>optional_permissions</code> key, using the
-  same format as the <a href="declare_permissions.html">permissions</a>
+  same format as the <a href="declare_permissions.html#manifest">permissions</a>
   field:
 
 <pre>{
@@ -61,7 +50,8 @@
 </p>
 
 <p>
-You can specify any of the following as optional permissions:
+You can specify any of the following as optional
+<a href="declare_permissions.html">permissions</a>:
 <ul>
   <li><i>host permissions</i></li>
   <li>background</li>
diff --git a/chrome/common/extensions/docs/templates/intros/tabs.html b/chrome/common/extensions/docs/templates/intros/tabs.html
index b652c54..c84806b 100644
--- a/chrome/common/extensions/docs/templates/intros/tabs.html
+++ b/chrome/common/extensions/docs/templates/intros/tabs.html
@@ -1,12 +1,15 @@
-<img src="{{static}}/images/tabs.png"
-     width="323" height="50" alt="Two tabs in a window" />
-
 <h2 id="manifest">Manifest</h2>
+
 <p>
-Almost all <code>chrome.tabs</code> methods require you to
-declare the "tabs" permission
-in the <a href="manifest.html">extension manifest</a>.
-For example:
+You can use most <code>chrome.tabs</code> methods and events without declaring
+any permissions in the extension's <a href="manifest.html">manifest</a> file.
+However, if you require access to the
+<code>$ref:[tabs.Tab.url url]</code>,
+<code>$ref:[tabs.Tab.title title]</code>, or
+<code>$ref:[tabs.Tab.favIconUrl favIconUrl]</code> properties of
+<code>$ref:tabs.Tab</code>,
+you must declare the <code>"tabs"</code> permission in the manifest,
+as shown below:
 </p>
 
 <pre>{
@@ -18,19 +21,14 @@
   ...
 }</pre>
 
-<p>
-Three methods ($ref:tabs.create,
-$ref:tabs.update and
-$ref:tabs.remove) and one event
-($ref:tabs.onRemoved) don't require the "tabs"
-permission.
-</p>
-
-
 <h2 id="examples"> Examples </h2>
 
 <p>
-You can find simple examples of using the tabs module in the
+<img src="{{static}}/images/tabs.png"
+     width="323" height="50" alt="Two tabs in a window" />
+<br>
+You can find simple examples of manipulating tabs with the
+<code>chrome.tabs</code> API in the
 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/tabs/">examples/api/tabs</a>
 directory.
 For other examples and for help in viewing the source code, see
diff --git a/chrome/common/extensions/docs/templates/intros/windows.html b/chrome/common/extensions/docs/templates/intros/windows.html
index 4dffb6a..40a2a50 100644
--- a/chrome/common/extensions/docs/templates/intros/windows.html
+++ b/chrome/common/extensions/docs/templates/intros/windows.html
@@ -1,14 +1,14 @@
-<img src="{{static}}/images/windows.png"
-     width="256" height="76" alt="Two windows, each with one tab" />
-
 <h2 id="manifest">Manifest</h2>
 <p>
-To use the windows API,
-you must declare the "tabs" permission
-in <a href="manifest.html">manifest.json</a>.
-(No, that isn't a typo &mdash;
-the window and tabs modules interact so closely we
-decided to just share one permission between them.)
+When requested, a <code>$ref:windows.Window</code>
+will contain an array of <code>$ref:tabs.Tab</code> objects.
+
+You must declare the <code>"tabs"</code> permission in your
+<a href="manifest.html">manifest</a> if you require access to the
+<code>$ref:[tabs.Tab.url url]</code>,
+<code>$ref:[tabs.Tab.title title]</code>, or
+<code>$ref:[tabs.Tab.favIconUrl favIconUrl]</code> properties of
+<code>$ref:tabs.Tab</code>.
 For example:
 </p>
 
@@ -49,6 +49,9 @@
 <h2 id="examples"> Examples </h2>
 
 <p>
+<img src="{{static}}/images/windows.png"
+     width="256" height="76" alt="Two windows, each with one tab" />
+<br>
 You can find simple examples of using the windows module in the
 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/windows/">examples/api/windows</a>
 directory.
diff --git a/chrome/common/extensions/docs/templates/json/intro_tables.json b/chrome/common/extensions/docs/templates/json/intro_tables.json
index a156fae..49ac954 100644
--- a/chrome/common/extensions/docs/templates/json/intro_tables.json
+++ b/chrome/common/extensions/docs/templates/json/intro_tables.json
@@ -50,7 +50,7 @@
         "text": "\"cookies\""
       },
       {
-        "link": "declare_permissions.html",
+        "link": "declare_permissions.html#host-permissions",
         "text": "host permissions"
       }
     ]
@@ -74,7 +74,7 @@
         "text": "\"declarativeWebRequest\""
       },
       {
-        "link": "declare_permissions.html",
+        "link": "declare_permissions.html#host-permissions",
         "text": "host permissions"
       }
     ]
@@ -154,6 +154,14 @@
       }
     ]
   },
+  "permissions": {
+    "Learn More": [
+      {
+        "link": "declare_permissions.html#host-permissions",
+        "text": "Declaring permissions"
+      }
+    ]
+  },
   "pushMessaging": {
     "Learn More": [
       {
@@ -242,8 +250,7 @@
   "tabs": {
     "Permissions": [
       {
-        "class": "code",
-        "text": "\"tabs\""
+        "partial": "intro_tables/tabs_permissions.html"
       }
     ]
   },
@@ -270,7 +277,7 @@
         "text": "\"webRequest\""
       },
       {
-        "link": "declare_permissions.html",
+        "link": "declare_permissions.html#host-permissions",
         "text": "host permissions"
       }
     ]
@@ -282,5 +289,12 @@
         "text": "Using Inline Installation"
       }
     ]
+  },
+  "windows": {
+    "Permissions": [
+      {
+        "partial": "intro_tables/windows_permissions.html"
+      }
+    ]
   }
 }
diff --git a/chrome/common/extensions/docs/templates/json/manifest.json b/chrome/common/extensions/docs/templates/json/manifest.json
index 4408a53..85e88fd 100644
--- a/chrome/common/extensions/docs/templates/json/manifest.json
+++ b/chrome/common/extensions/docs/templates/json/manifest.json
@@ -1,176 +1,152 @@
 {
-  "required": [
-    {
-      "documentation": "manifest/name.html",
-      "example": "My Extension",
-      "name": "name"
-    },
-    {
-      "documentation": "manifest/app.html",
-      "example": {},
-      "name": "app"
-    },
-    {
-      "documentation": "manifest/version.html",
-      "example": "versionString",
-      "name": "version"
-    },
-    {
-      "documentation": "manifest/manifest_version.html",
-      "example": 2,
-      "name": "manifest_version"
+  "app": {
+    "documentation": "manifest/app.html",
+    "example": {},
+    "level": "required"
+  },
+  "app.background": {
+    "example": {"scripts": ["background.js"]},
+    "level": "required"
+  },
+  "background": {
+    "documentation": "background_pages.html"
+  },
+  "background.persistent": {
+    "documentation": "event_pages.html",
+    "example": false,
+    "level": "recommended"
+  },
+  "browser_action": {
+    "documentation": "browserAction.html",
+    "example": {},
+    "level": "only_one"
+  },
+  "chrome_url_overrides": {
+    "documentation": "override.html",
+    "example": {}
+  },
+  "content_scripts": {
+    "documentation": "content_scripts.html",
+    "example": {}
+  },
+  "content_security_policy": {
+    "documentation": "contentSecurityPolicy.html",
+    "example": "policyString"
+  },
+  "default_locale": {
+    "documentation": "manifest/default_locale.html",
+    "example": "en",
+    "level": "recommended"
+  },
+  "description": {
+    "documentation": "manifest/description.html",
+    "example": "A plain text description",
+    "level": "recommended"
+  },
+  "externally_connectable": {
+    "documentation": "manifest/externally_connectable.html",
+    "example": {
+      "matches": ["*://*.example.com/*"]
     }
-  ],
-  "recommended": [
-    {
-      "documentation": "manifest/description.html",
-      "example": "A plain text description",
-      "name": "description"
-    },
-    {
-      "documentation": "manifest/icons.html",
-      "example": {},
-      "name": "icons"
-    },
-    {
-      "documentation": "manifest/default_locale.html",
-      "example": "en",
-      "name": "default_locale"
+  },
+  "file_browser_handlers": {
+    "documentation": "fileBrowserHandler.html",
+    "example": []
+  },
+  "file_handlers": {
+    "documentation": "manifest/file_handlers.html",
+    "example": {}
+  },
+  "homepage_url": {
+    "documentation": "manifest/homepage_url.html",
+    "example": "http://path/to/homepage"
+  },
+  "icons": {
+    "documentation": "manifest/icons.html",
+    "example": {},
+    "level": "recommended"
+  },
+  "incognito": {
+    "documentation": "manifest/incognito.html",
+    "example": "spanning or split"
+  },
+  "key": {
+    "documentation": "manifest/key.html",
+    "example": "publicKey"
+  },
+  "kiosk_enabled": {
+    "documentation": "manifest/kiosk_enabled.html",
+    "example": true
+  },
+  "manifest_version": {
+    "documentation": "manifest/manifest_version.html",
+    "example": 2,
+    "level": "required"
+  },
+  "minimum_chrome_version": {
+    "documentation": "manifest/minimum_chrome_version.html",
+    "example": "versionString"
+  },
+  "nacl_modules": {
+    "documentation": "manifest/nacl_modules.html",
+    "example": []
+  },
+  "name": {
+    "documentation": "manifest/name.html",
+    "example": "My {{title}}",
+    "level": "required"
+  },
+  "offline_enabled": {
+    "documentation": "manifest/offline_enabled.html",
+    "example": true
+  },
+  "omnibox": {
+    "documentation": "omnibox.html",
+    "example": {
+      "keyword": "aString"
     }
-  ],
-  "only_one": [
-    {
-      "documentation": "browserAction.html",
-      "example": {},
-      "name": "browser_action"
-    },
-    {
-      "documentation": "pageAction.html",
-      "example": {},
-      "name": "page_action"
-    },
-    {
-      "documentation": "themes.html",
-      "example": {},
-      "name": "theme"
-    }
-  ],
-  "optional": [
-    {
-      "documentation": "event_pages.html",
-      "example": {
-        "persistent": false
-      },
-      "name": "background"
-    },
-    {
-      "documentation": "background_pages.html",
-      "example": {
-        "persistent": true
-      },
-      "name": "background.persistent"
-    },
-    {
-      "documentation": "override.html",
-      "example": {},
-      "name": "chrome_url_overrides"
-    },
-    {
-      "documentation": "content_scripts.html",
-      "example": {},
-      "name": "content_scripts"
-    },
-    {
-      "documentation": "contentSecurityPolicy.html",
-      "example": "policyString",
-      "name": "content_security_policy"
-    },
-    {
-      "documentation": "fileBrowserHandler.html",
-      "example": [],
-      "name": "file_browser_handlers"
-    },
-    {
-      "documentation": "manifest/file_handlers.html",
-      "example": {},
-      "name": "file_handlers"
-    },
-    {
-      "documentation": "manifest/homepage_url.html",
-      "example": "http://path/to/homepage",
-      "name": "homepage_url"
-    },
-    {
-      "documentation": "manifest/incognito.html",
-      "example": "spanning or split",
-      "name": "incognito"
-    },
-    {
-      "documentation": "manifest/key.html",
-      "example": "publicKey",
-      "name": "key"
-    },
-    {
-      "documentation": "manifest/minimum_chrome_version.html",
-      "example": "versionString",
-      "name": "minimum_chrome_version"
-    },
-    {
-      "documentation": "manifest/nacl_modules.html",
-      "example": [],
-      "name": "nacl_modules"
-    },
-    {
-      "documentation": "manifest/kiosk_enabled.html",
-      "example": true,
-      "name": "kiosk_enabled"
-    },
-    {
-      "documentation": "manifest/offline_enabled.html",
-      "example": true,
-      "name": "offline_enabled"
-    },
-    {
-      "documentation": "omnibox.html",
-      "example": {
-        "keyword": "aString"
-      },
-      "name": "omnibox"
-    },
-    {
-      "documentation": "options.html",
-      "example": "aFile.html",
-      "name": "options_page"
-    },
-    {
-      "documentation": "declare_permissions.html",
-      "example": [],
-      "name": "permissions"
-    },
-    {
-      "documentation": "npapi.html",
-      "example": [],
-      "name": "plugins"
-    },
-    {
-      "documentation": "manifest/requirements.html",
-      "example": {},
-      "name": "requirements"
-    },
-    {
-      "documentation": "autoupdate.html",
-      "example": "http://path/to/updateInfo.xml",
-      "name": "update_url"
-    },
-    {
-      "documentation": "manifest/web_accessible_resources.html",
-      "example": [],
-      "name": "web_accessible_resources"
-    },
-    {
-      "documentation": "manifest/sandbox.html",
-      "example": [],
-      "name": "sandbox"
-    }
-  ]
+  },
+  "options_page": {
+    "documentation": "options.html",
+    "example": "aFile.html"
+  },
+  "page_action": {
+    "documentation": "pageAction.html",
+    "example": {},
+    "level": "only_one"
+  },
+  "permissions": {
+    "documentation": "declare_permissions.html",
+    "example": []
+  },
+  "plugins": {
+    "documentation": "npapi.html",
+    "example": []
+  },
+  "requirements": {
+    "documentation": "manifest/requirements.html",
+    "example": {}
+  },
+  "sandbox": {
+    "documentation": "manifest/sandbox.html",
+    "example": []
+  },
+  "theme": {
+    "documentation": "themes.html",
+    "example": {},
+    "level": "only_one"
+  },
+  "update_url": {
+    "documentation": "autoupdate.html",
+    "example": "http://path/to/updateInfo.xml"
+  },
+  "version": {
+    "documentation": "manifest/version.html",
+    "example": "versionString",
+    "level": "required"
+  },
+  "web_accessible_resources": {
+    "documentation": "manifest/web_accessible_resources.html",
+    "example": []
+  }
 }
diff --git a/chrome/common/extensions/docs/templates/json/permissions.json b/chrome/common/extensions/docs/templates/json/permissions.json
new file mode 100644
index 0000000..6479217
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/json/permissions.json
@@ -0,0 +1,62 @@
+{
+  "host-permissions": {
+    "anchor": "match-pattern",
+    "name": "[scheme]:[host]/*",
+    "partial": "permissions/host_permissions.html",
+    "platforms": ["app", "extension"]
+  },
+  "activeTab": {
+    "partial": "permissions/active_tab.html"
+  },
+  "audioCapture": {
+    "partial": "permissions/audio_capture.html"
+  },
+  "background": {
+    "partial": "permissions/background.html"
+  },
+  "chrome://favicon/": {
+    "anchor": "favicon",
+    "name": "chrome://favicon/",
+    "partial": "permissions/favicon.html",
+    "platforms": ["extension"]
+  },
+  "clipboardRead": {
+    "partial": "permissions/clipboard_read.html"
+  },
+  "clipboardWrite": {
+    "partial": "permissions/clipboard_write.html"
+  },
+  "experimental": {
+    "partial": "permissions/experimental.html"
+  },
+  "fullscreen": {
+    "partial": "permissions/fullscreen.html"
+  },
+  "geolocation": {
+    "partial": "permissions/geolocation.html"
+  },
+  "notifications": {
+    "partial": "permissions/notifications.html"
+  },
+  "pointerLock": {
+    "partial": "permissions/pointer_lock.html"
+  },
+  "syncFileSystem": {
+    "partial": "permissions/sync_file_system.html"
+  },
+  "tabCapture": {
+    "partial": "permissions/tab_capture.html"
+  },
+  "unlimitedStorage": {
+    "partial": "permissions/unlimited_storage.html"
+  },
+  "videoCapture": {
+    "partial": "permissions/video_capture.html"
+  },
+  "webRequestBlocking": {
+    "partial": "permissions/web_request_blocking.html"
+  },
+  "webview": {
+    "partial": "permissions/webview.html"
+  }
+}
diff --git a/chrome/common/extensions/docs/templates/json/strings.json b/chrome/common/extensions/docs/templates/json/strings.json
new file mode 100644
index 0000000..abdab97
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/json/strings.json
@@ -0,0 +1,9 @@
+{
+  "app": "app",
+  "apps_title": "Apps",
+  "extension": "extension",
+  "extensions_title": "Extensions",
+  "events": "events",
+  "methods": "methods",
+  "properties": "properties"
+}
diff --git a/chrome/common/extensions/docs/templates/private/api_property.html b/chrome/common/extensions/docs/templates/private/api_property.html
index 5f35ea8..4d12ceb 100644
--- a/chrome/common/extensions/docs/templates/private/api_property.html
+++ b/chrome/common/extensions/docs/templates/private/api_property.html
@@ -21,7 +21,7 @@
       Methods of <a href="#property-{{property.name}}">{{property.name}}</a>
     </h4>
     <dd><dl>{{#functions}}
-      {{+partials.function}}
+      {{+partials.function @:@}}
     {{/}}</dl></dd>
     {{/functions}}
   </div>
diff --git a/chrome/common/extensions/docs/templates/private/api_reference.html b/chrome/common/extensions/docs/templates/private/api_reference.html
index 859cd7d..9c38a70 100644
--- a/chrome/common/extensions/docs/templates/private/api_reference.html
+++ b/chrome/common/extensions/docs/templates/private/api_reference.html
@@ -3,7 +3,7 @@
   {{?api.types}}
     <h2 id="types">Types</h2>
     {{#api.types}}
-      {{+partials.type api:api display_name:name}}
+      {{+partials.type display_name:name}}
     {{/}}
   {{/api.types}}
   {{?api.properties}}
@@ -15,7 +15,7 @@
   {{?api.functions}}
     <h2 id="methods">Methods</h2>
     {{#api.functions}}
-      {{+partials.function api:api}}
+      {{+partials.function @:@ api:api}}
     {{/}}
   {{/api.functions}}
   {{?api.events}}
diff --git a/chrome/common/extensions/docs/templates/private/event.html b/chrome/common/extensions/docs/templates/private/event.html
index 898b831..8b5108d 100644
--- a/chrome/common/extensions/docs/templates/private/event.html
+++ b/chrome/common/extensions/docs/templates/private/event.html
@@ -1,41 +1,65 @@
 <div>
   <h4 id="{{id}}">{{name}}</h4>
-  <div class="summary">
-    <span class="subdued">{{?parentName}}{{parentName}}{{:}}chrome.{{api.name}}{{/}}.</span>{{name}}<span class="subdued">.addListener</span>(function({{#parameters}}{{+partials.parameter_item}}{{^last}}, {{/}}{{/}})<span class="subdued"> {...}</span>);
-  </div>
   <div class="description">
     {{?description}}<p>
       {{{description}}}
     </p>{{/description}}
-    {{?supportsRules}}
-      <p>See $ref:events.Event.addRules.</p>
-    {{/supportsRules}}
     {{?conditions}}
+    {{?supportsRules}}
       <h4>Supported conditions</h4>
-      <dl>
-        {{#conditions}}<div><dt>{{+partials.ref_link}}</dt></div>{{/}}
-      </dl>
+      <p>
+        The following conditions may be used in rules registered through
+        <a href="#{{id}}-{{addRulesFunction.name}}">
+          {{addRulesFunction.name}}
+        </a>.
+      </p>
+      <ul>
+        {{#conditions}}<div><li>{{+partials.ref_link}}</li></div>{{/}}
+      </ul>
+    {{/supportsRules}}
     {{/conditions}}
     {{?actions}}
+    {{?supportsRules}}
       <h4>Supported actions</h4>
-      <dl>
-        {{#actions}}<div><dt>{{+partials.ref_link}}</dt></div>{{/}}
-      </dl>
+      <p>
+        The following actions may be used in rules registered through
+        <a href="#{{id}}-{{addRulesFunction.name}}">
+          {{addRulesFunction.name}}
+        </a>.
+      </p>
+      <ul>
+        {{#actions}}<div><li>{{+partials.ref_link}}</li></div>{{/}}
+      </ul>
+    {{/supportsRules}}
     {{/actions}}
-    {{?parameters}}
-      <h4>Listener Parameters</h4>
-      <dl>
-        {{#parameters}}{{+partials.parameter_full}}{{/}}
-      </dl>
-      {{?callback}}
-      {{+partials.callback}}
-      {{/callback}}
-    {{/parameters}}
     {{?filters}}
       <h4>Filters</h4>
       <dl>
         {{#filters}}{{+partials.parameter_full}}{{/}}
       </dl>
     {{/filters}}
+    {{?supportsRules}}
+      {{-
+      TODO(vabr): For addRulesFunction it would be better to call
+      partials.function directly as follows:
+      {{+partials.function @:addRulesFunction
+                           parentName:name
+                           api:api
+                           parentId:id}}
+      but for some reason the parentName:name does not override the
+      'parentName' property of addRulesFunction (which is 'Event'). This will
+      get fixed as soon as we get rid of using @ in partials.function.
+      -}}
+      <h4 id="{{id}}-{{addRulesFunction.name}}">{{addRulesFunction.name}}</h4>
+      {{+partials.function_details function:addRulesFunction
+                                   parentName:name
+                                   api:api}}
+    {{/supportsRules}}
+    {{?supportsListeners}}
+      {{+partials.function @:addListenerFunction
+                           parentName:name
+                           api:api
+                           parentId:id}}
+    {{/supportsListeners}}
   </div>
 </div>
diff --git a/chrome/common/extensions/docs/templates/private/function.html b/chrome/common/extensions/docs/templates/private/function.html
index 3cfcd41..f1923a2 100644
--- a/chrome/common/extensions/docs/templates/private/function.html
+++ b/chrome/common/extensions/docs/templates/private/function.html
@@ -1,28 +1,6 @@
 <div>
-  <h4 id="{{id}}">{{name}}</h4>
-  <div class="summary{{^returns}} uncapitalize{{/}}">
-    <span>{{?returns}}{{+partials.variable_type}} {{/}}{{?parentName}}{{parentName}}{{:}}chrome.{{api.name}}{{/}}.{{name}}</span>({{#parameters}}{{+partials.parameter_item}}{{^last}}, {{/}}{{/}})
-  </div>
-  <div class="description">
-    {{?description}}
-    <p>
-      {{{description}}}
-    </p>
-    {{/description}}
-    {{?parameters}}
-    <h4>Parameters</h4>
-    <dl>
-      {{#parameters}}
-        {{+partials.parameter_full}}
-      {{/parameters}}
-    </dl>
-    {{/parameters}}
-    {{?callback}}
-      {{+partials.callback}}
-    {{/callback}}
-    {{?returns.is_object}}
-      <h4>Properties of return type</h4>
-      {{+partials.type @:returns api:api}}
-    {{/returns.is_object}}
-  </div>
+  <h4 id="{{?id}}{{id}}{{:}}{{?parentId}}{{parentId}}-{{name}}{{/}}{{/}}">
+    {{name}}
+  </h4>
+  {{+partials.function_details function:@ parentName:parentName api:api}}
 </div>
diff --git a/chrome/common/extensions/docs/templates/private/function_details.html b/chrome/common/extensions/docs/templates/private/function_details.html
new file mode 100644
index 0000000..6256042
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/function_details.html
@@ -0,0 +1,30 @@
+{{- Parameters:
+    |api|: the schema for the API that the function belongs to
+    |function|: the schema for the function
+    |parentName|: name of the parent object of the function
+-}}
+<div class="summary{{^function.returns}}{{?api}} uncapitalize{{/}}{{/}}">
+<span>{{?function.returns}}{{+partials.variable_type}} {{/}}{{?api}}chrome.{{api.name}}{{/}}{{?parentName}}.{{parentName}}{{/}}.{{function.name}}</span>({{#function.parameters}}{{+partials.parameter_item}}{{^last}}, {{/}}{{/}})
+</div>
+<div class="description">
+  {{?function.description}}
+  <p>
+    {{{function.description}}}
+  </p>
+  {{/function.description}}
+  {{?function.parameters}}
+  <h4>Parameters</h4>
+  <dl>
+    {{#function.parameters}}
+      {{+partials.parameter_full}}
+    {{/function.parameters}}
+  </dl>
+  {{/function.parameters}}
+  {{?function.callback}}
+    {{+partials.callback}}
+  {{/function.callback}}
+  {{?function.returns.is_object}}
+    <h4>Properties of return type</h4>
+    {{+partials.type @:function.returns}}
+  {{/function.returns.is_object}}
+</div>
diff --git a/chrome/common/extensions/docs/templates/private/header_body.html b/chrome/common/extensions/docs/templates/private/header_body.html
index 6a65960..c8f59ac 100644
--- a/chrome/common/extensions/docs/templates/private/header_body.html
+++ b/chrome/common/extensions/docs/templates/private/header_body.html
@@ -26,7 +26,7 @@
            target="_blank">Group</a>
       </li>
       <li>
-        <a href="http://stackoverflow.com/questions/tagged/google-chrome-{{platform}}"
+        <a href="http://stackoverflow.com/tags/google-chrome-{{platform}}/info"
            title="[google-chrome-{{platform}}] tag on Stack Overflow"
            target="_blank">Stack overflow</a>
       </li>
diff --git a/chrome/common/extensions/docs/templates/private/intro_table.html b/chrome/common/extensions/docs/templates/private/intro_table.html
index c6f9e54..4a9f3c5 100644
--- a/chrome/common/extensions/docs/templates/private/intro_table.html
+++ b/chrome/common/extensions/docs/templates/private/intro_table.html
@@ -1,9 +1,7 @@
-<table class="intro">
-  {{#api.intro_list}}
+<table class="intro" id="intro">
+  {{#api.introList}}
   <tr>
-    <td>
-      <strong>{{title}}:</strong>
-    </td>
+    <td class="title">{{title}}:</td>
     <td>
       {{#content}}
         {{?link}}<a href="{{link}}">{{/link}}
@@ -16,5 +14,5 @@
       {{/content}}
     </td>
   </tr>
-  {{/api.intro_list}}
+  {{/api.introList}}
 </table>
diff --git a/chrome/common/extensions/docs/templates/private/intro_tables/tabs_permissions.html b/chrome/common/extensions/docs/templates/private/intro_tables/tabs_permissions.html
new file mode 100644
index 0000000..56ce67c
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/intro_tables/tabs_permissions.html
@@ -0,0 +1,8 @@
+The majority of the <code>chrome.tabs</code> API can be used without declaring
+ any permission.
+ However, the
+ <code>"tabs"</code> permission is required in order to populate the
+ <code><a href="#property-Tab-url">url</a></code>,
+ <code><a href="#property-Tab-title">title</a></code>, and
+ <code><a href="#property-Tab-favIconUrl">favIconUrl</a></code> properties of
+ <code><a href="#type-Tab">Tab</a></code>.
diff --git a/chrome/common/extensions/docs/templates/private/intro_tables/windows_permissions.html b/chrome/common/extensions/docs/templates/private/intro_tables/windows_permissions.html
new file mode 100644
index 0000000..5f46c3f
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/intro_tables/windows_permissions.html
@@ -0,0 +1,8 @@
+The <code>chrome.windows</code> API can be used
+ without declaring any permission.
+ However, the <code>"tabs"</code> permission is
+ required in order to populate the
+ <code><a href="tabs.html#property-Tab-url">url</a></code>,
+ <code><a href="tabs.html#property-Tab-title">title</a></code>, and
+ <code><a href="tabs.html#property-Tab-favIconUrl">favIconUrl</a></code> properties of
+ <code><a href="tabs.html#type-Tab">Tab</a></code> objects.
diff --git a/chrome/common/extensions/docs/templates/private/manifest_example.html b/chrome/common/extensions/docs/templates/private/manifest_example.html
index ac4b730..05a60d8 100644
--- a/chrome/common/extensions/docs/templates/private/manifest_example.html
+++ b/chrome/common/extensions/docs/templates/private/manifest_example.html
@@ -1,17 +1,11 @@
 <pre>
 {
   <em>// Required</em>
-  {{+partials.manifest_properties properties:manifest_source.required}}
+  {{#manifest_source}}
+  {{?annotations}}
 
-  <em>// Recommended</em>
-  {{+partials.manifest_properties properties:manifest_source.recommended}}
-
-  {{?manifest_source.only_one}}
-  <em>// Pick one (or none)</em>
-  {{+partials.manifest_properties properties:manifest_source.only_one}}
-
-  {{/manifest_source.only_one}}
-  <em>// Optional</em>
-  {{+partials.manifest_properties properties:manifest_source.optional}}
+  {{/annotations}}
+  {{+partials.manifest_property}}
+  {{/manifest_source}}
 }
 </pre>
diff --git a/chrome/common/extensions/docs/templates/private/manifest_properties.html b/chrome/common/extensions/docs/templates/private/manifest_properties.html
deleted file mode 100644
index 5637891..0000000
--- a/chrome/common/extensions/docs/templates/private/manifest_properties.html
+++ /dev/null
@@ -1,6 +0,0 @@
-{{#properties}}
-{{?documentation}}
-"<a href="{{documentation}}">{{name}}</a>": <em>{{*example}}</em>{{^is_last}},{{/}}
-{{:documentation}}
-"{{name}}": ...{{^is_last}},{{/}}
-{{/documentation}}{{/properties}}
diff --git a/chrome/common/extensions/docs/templates/private/manifest_property.html b/chrome/common/extensions/docs/templates/private/manifest_property.html
new file mode 100644
index 0000000..fa312d9
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/manifest_property.html
@@ -0,0 +1,13 @@
+{{?annotations}}
+{{#annotations}}
+<em>// {{@}}</em>
+{{/annotations}}
+{{/annotations}}
+{{?documentation}}
+"<a href="{{documentation}}">{{name}}</a>":{{:documentation}}
+"{{name}}":{{^children}}{{^has_example}} ...{{/}}{{/}}{{/documentation}}
+{{?children}} {
+{{#children}}
+  {{+partials.manifest_property}}
+{{/}}
+}{{:children}}{{?has_example}} {{example}}{{/}}{{/}}{{^is_last}},{{/}}
diff --git a/chrome/common/extensions/docs/templates/private/permissions/active_tab.html b/chrome/common/extensions/docs/templates/private/permissions/active_tab.html
new file mode 100644
index 0000000..2b4e634
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/active_tab.html
@@ -0,0 +1 @@
+Requests that the extension be granted permissions according to the <a href="activeTab.html">activeTab</a> specification.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/audio_capture.html b/chrome/common/extensions/docs/templates/private/permissions/audio_capture.html
new file mode 100644
index 0000000..97d6acc
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/audio_capture.html
@@ -0,0 +1 @@
+Requests that the app be granted permissions to capture audio directly from the user's Microphone via the <a href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html">getUserMedia</a> API.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/background.html b/chrome/common/extensions/docs/templates/private/permissions/background.html
new file mode 100644
index 0000000..ed8ba55
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/background.html
@@ -0,0 +1,15 @@
+<p id="bg">
+Makes Chrome start up early and and shut down late, so that apps and extensions can have a longer life.
+</p>
+
+<p>
+When any installed hosted app, packaged app, or extension has "background" permission, Chrome runs (invisibly) as soon as the user logs into their computer&mdash;before the user launches Chrome. The "background" permission also makes Chrome continue running (even after its last window is closed) until the user explicitly quits Chrome.
+</p>
+
+<p class="note">
+  <b>Note:</b> Disabled apps and extensions are treated as if they aren't installed.
+</p>
+
+<p>
+You typically use the "background" permission with a <a href="background_pages.html">background page</a>, <a href="event_pages.html">event page</a> or (for hosted apps) a <a href="http://code.google.com/chrome/apps/docs/background.html">background window</a>.
+</p>
diff --git a/chrome/common/extensions/docs/templates/private/permissions/clipboard_read.html b/chrome/common/extensions/docs/templates/private/permissions/clipboard_read.html
new file mode 100644
index 0000000..ecba14a
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/clipboard_read.html
@@ -0,0 +1 @@
+Required if the extension or app uses <code>document.execCommand('paste')</code>.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/clipboard_write.html b/chrome/common/extensions/docs/templates/private/permissions/clipboard_write.html
new file mode 100644
index 0000000..df73683
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/clipboard_write.html
@@ -0,0 +1 @@
+Indicates the extension or app uses <code>document.execCommand('copy')</code> or <code>document.execCommand('cut')</code>. This permission is <b>required for hosted apps</b>; it's recommended for extensions and packaged apps.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/experimental.html b/chrome/common/extensions/docs/templates/private/permissions/experimental.html
new file mode 100644
index 0000000..3ccf6d5
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/experimental.html
@@ -0,0 +1 @@
+Required if the extension or app uses any <a href="experimental.html">chrome.experimental.* APIs</a>.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/favicon.html b/chrome/common/extensions/docs/templates/private/permissions/favicon.html
new file mode 100644
index 0000000..fda23f3
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/favicon.html
@@ -0,0 +1 @@
+Required if the extension uses the "chrome://favicon/<em>url</em>" mechanism to display the favicon of a page. For example, to display the favicon of http://www.google.com/, you declare the "chrome://favicon/" permission and use HTML code like this: <pre>&lt;img src="chrome://favicon/http://www.google.com/"></pre>
diff --git a/chrome/common/extensions/docs/templates/private/permissions/fullscreen.html b/chrome/common/extensions/docs/templates/private/permissions/fullscreen.html
new file mode 100644
index 0000000..de06359
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/fullscreen.html
@@ -0,0 +1 @@
+Allows the app to use the <a href="app.window.html">app.window</a> fullscreen state or the <a href="https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html">HTML fullscreen API</a>. See <a href="api_other.html">Other APIs</a> for behavior differences.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/generic_description.html b/chrome/common/extensions/docs/templates/private/permissions/generic_description.html
new file mode 100644
index 0000000..1cb1f42
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/generic_description.html
@@ -0,0 +1 @@
+Gives your {{platform}} access to the <a href="{{name}}.html">chrome.{{name}}</a> API.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/geolocation.html b/chrome/common/extensions/docs/templates/private/permissions/geolocation.html
new file mode 100644
index 0000000..bad52a7
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/geolocation.html
@@ -0,0 +1 @@
+Allows the extension or app to use the proposed HTML5 <a href="http://dev.w3.org/geo/api/spec-source.html">geolocation API</a> without prompting the user for permission.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/host_permissions.html b/chrome/common/extensions/docs/templates/private/permissions/host_permissions.html
new file mode 100644
index 0000000..17f4062
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/host_permissions.html
@@ -0,0 +1 @@
+Specifies a <em>host permission</em>. Required if the extension or app wants to interact with the code running on pages. Many capabilities, such as <a href="xhr.html">cross-origin XMLHttpRequests</a>, <a href="content_scripts.html#pi">programmatically injected content scripts</a>, and <a href="cookies.html">the extension's cookies API</a> require host permissions. For details on the syntax, see <a href="match_patterns.html">Match Patterns</a>.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/notifications.html b/chrome/common/extensions/docs/templates/private/permissions/notifications.html
new file mode 100644
index 0000000..ddc9a8a
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/notifications.html
@@ -0,0 +1,5 @@
+{{^is_apps}}
+Allows the extension to use the proposed HTML5 <a href="http://www.chromium.org/developers/design-documents/desktop-notifications/api-specification">notification API</a> without calling permission methods (such as <code>checkPermission()</code>). For more information see <a href="desktop_notifications.html">Desktop Notifications</a>.
+{{:is_apps}}
+Required if the app uses the <a href="notifications.html">chrome.notifications</a> module. Also allows the app to use the proposed HTML5 <a href="http://www.chromium.org/developers/design-documents/desktop-notifications/api-specification">notification API</a> without calling permission methods (such as <code>checkPermission()</code>). For more information see <a href="desktop_notifications.html">Desktop Notifications</a>.
+{{/is_apps}}
diff --git a/chrome/common/extensions/docs/templates/private/permissions/pointer_lock.html b/chrome/common/extensions/docs/templates/private/permissions/pointer_lock.html
new file mode 100644
index 0000000..0d7f3ca
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/pointer_lock.html
@@ -0,0 +1 @@
+Required to use <a href="http://www.w3.org/TR/pointerlock/">Pointer Lock</a> via calls to <code>webkitRequestPointerLock</code> or Pepper's <a href="https://developers.google.com/native-client/peppercpp/classpp_1_1_mouse_lock"> Mouse Lock API</a>. See <a href="api_other.html">Other APIs</a> for behavior differences.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/sync_file_system.html b/chrome/common/extensions/docs/templates/private/permissions/sync_file_system.html
new file mode 100644
index 0000000..52a283f
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/sync_file_system.html
@@ -0,0 +1 @@
+Required if the app uses the <a href="syncFileSystem.html">chrome.syncFileSystem</a> module to save and synchronize data on Google Drive.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/tab_capture.html b/chrome/common/extensions/docs/templates/private/permissions/tab_capture.html
new file mode 100644
index 0000000..7a90ee3
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/tab_capture.html
@@ -0,0 +1 @@
+Required if the extension uses the <a href="tabCapture.html">chrome.tabCapture</a> module.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/unlimited_storage.html b/chrome/common/extensions/docs/templates/private/permissions/unlimited_storage.html
new file mode 100644
index 0000000..eddee90
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/unlimited_storage.html
@@ -0,0 +1,5 @@
+Provides an unlimited quota for storing HTML5 client-side data, such as databases and local storage files. Without this permission, the extension or app is limited to 5 MB of local storage.
+
+<p class="note">
+<b>Note:</b> This permission applies only to Web SQL Database and application cache (see issue <a href="http://crbug.com/58985">58985</a>). Also, it doesn't currently work with wildcard subdomains such as <code>http://*.example.com</code>.
+</p>
diff --git a/chrome/common/extensions/docs/templates/private/permissions/video_capture.html b/chrome/common/extensions/docs/templates/private/permissions/video_capture.html
new file mode 100644
index 0000000..b6f186d
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/video_capture.html
@@ -0,0 +1 @@
+Requests that the app be granted permissions to capture video directly from the user's Web Cam via the <a href="http://dev.w3.org/2011/webrtc/editor/getusermedia.html">getUserMedia</a> API.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/web_request_blocking.html b/chrome/common/extensions/docs/templates/private/permissions/web_request_blocking.html
new file mode 100644
index 0000000..63721aa
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/web_request_blocking.html
@@ -0,0 +1 @@
+Required if the extension uses the <a href="webRequest.html">chrome.webRequest</a> module in a blocking fashion.
diff --git a/chrome/common/extensions/docs/templates/private/permissions/webview.html b/chrome/common/extensions/docs/templates/private/permissions/webview.html
new file mode 100644
index 0000000..aedb362
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/private/permissions/webview.html
@@ -0,0 +1 @@
+Required if the app uses the <a href="webview_tag.html">Webview Tag</a> to embed live content from the web in the packaged app.
diff --git a/chrome/common/extensions/docs/templates/private/property.html b/chrome/common/extensions/docs/templates/private/property.html
index d45acf0..782a402 100644
--- a/chrome/common/extensions/docs/templates/private/property.html
+++ b/chrome/common/extensions/docs/templates/private/property.html
@@ -12,5 +12,5 @@
 </dd>{{/description}}
 {{?array.is_object}}
   <h4>Properties of each item</h4>
-  {{+partials.type @:array api:api}}
+  {{+partials.type @:array}}
 {{/array.is_object}}
diff --git a/chrome/common/extensions/docs/templates/private/standard_apps_api.html b/chrome/common/extensions/docs/templates/private/standard_apps_api.html
index 9c13587..770d4ff 100644
--- a/chrome/common/extensions/docs/templates/private/standard_apps_api.html
+++ b/chrome/common/extensions/docs/templates/private/standard_apps_api.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     {{+partials.header_head}}
-    <link href="{{static}}/css/api.css" rel="stylesheet" type="text/css">
     {{+partials.title}}
   </head>
   <body>
@@ -11,9 +10,9 @@
       {{+partials.sidenav items:sidenavs.apps}}
       <div id="gc-pagecontent">
         <h1 class="page_title">chrome.{{api.name}}</h1>
-        {{?api.channel_warning.trunk}}{{+partials.warning_trunk}}{{/}}
-        {{?api.channel_warning.dev}}{{+partials.warning_dev}}{{/}}
-        {{?api.channel_warning.beta}}{{+partials.warning_beta}}{{/}}
+        {{?api.channelWarning.trunk}}{{+partials.warning_trunk}}{{/}}
+        {{?api.channelWarning.dev}}{{+partials.warning_dev}}{{/}}
+        {{?api.channelWarning.beta}}{{+partials.warning_beta}}{{/}}
         {{?intro.apps_toc}}
         {{+partials.table_of_contents toc_items:intro.apps_toc
                                       has_toc:true
diff --git a/chrome/common/extensions/docs/templates/private/standard_apps_article.html b/chrome/common/extensions/docs/templates/private/standard_apps_article.html
index 52b07be..77abbe8 100644
--- a/chrome/common/extensions/docs/templates/private/standard_apps_article.html
+++ b/chrome/common/extensions/docs/templates/private/standard_apps_article.html
@@ -16,7 +16,7 @@
                                       title:strings.apps_title}}
         {{/article.apps_toc}}
 {{- This may contain <pre> tags so it is not indented -}}
-{{+article.intro is_apps:true}}
+{{+article.intro platform:strings.app is_apps:true}}
       </div>
     </div>
   </body>
diff --git a/chrome/common/extensions/docs/templates/private/standard_extensions_api.html b/chrome/common/extensions/docs/templates/private/standard_extensions_api.html
index 0eaf2e7..b830809 100644
--- a/chrome/common/extensions/docs/templates/private/standard_extensions_api.html
+++ b/chrome/common/extensions/docs/templates/private/standard_extensions_api.html
@@ -2,7 +2,6 @@
 <html>
   <head>
     {{+partials.header_head}}
-    <link href="{{static}}/css/api.css" rel="stylesheet" type="text/css">
     {{+partials.title}}
   </head>
   <body>
@@ -11,9 +10,9 @@
       {{+partials.sidenav items:sidenavs.extensions}}
       <div id="gc-pagecontent">
         <h1 class="page_title">chrome.{{api.name}}</h1>
-        {{?api.channel_warning.trunk}}{{+partials.warning_trunk}}{{/}}
-        {{?api.channel_warning.dev}}{{+partials.warning_dev}}{{/}}
-        {{?api.channel_warning.beta}}{{+partials.warning_beta}}{{/}}
+        {{?api.channelWarning.trunk}}{{+partials.warning_trunk}}{{/}}
+        {{?api.channelWarning.dev}}{{+partials.warning_dev}}{{/}}
+        {{?api.channelWarning.beta}}{{+partials.warning_beta}}{{/}}
         {{?intro.extensions_toc}}
         {{+partials.table_of_contents toc_items:intro.extensions_toc
                                       has_toc:true
diff --git a/chrome/common/extensions/docs/templates/private/standard_extensions_article.html b/chrome/common/extensions/docs/templates/private/standard_extensions_article.html
index 55539d5..c81f0c6 100644
--- a/chrome/common/extensions/docs/templates/private/standard_extensions_article.html
+++ b/chrome/common/extensions/docs/templates/private/standard_extensions_article.html
@@ -16,7 +16,7 @@
                                       title:strings.extensions_title}}
         {{/article.extensions_toc}}
 {{- This may contain <pre> tags so it is not indented -}}
-{{+article.intro is_apps:false}}
+{{+article.intro platform:strings.extension is_apps:false}}
       </div>
     </div>
   </body>
diff --git a/chrome/common/extensions/docs/templates/private/type_item.html b/chrome/common/extensions/docs/templates/private/type_item.html
index 0e9f987..6c18127 100644
--- a/chrome/common/extensions/docs/templates/private/type_item.html
+++ b/chrome/common/extensions/docs/templates/private/type_item.html
@@ -5,6 +5,8 @@
 {{/display_name}}
 <dd>
   <dl>
-    {{#items +item_partial /}}
+    {{#items}}
+      {{+item_partial @:@}}
+    {{/items}}
   </dl>
 </dd>
diff --git a/chrome/common/extensions/docs/templates/public/apps/audio.html b/chrome/common/extensions/docs/templates/public/apps/audio.html
new file mode 100644
index 0000000..fc8642d
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/apps/audio.html
@@ -0,0 +1 @@
+{{+partials.standard_apps_api api:apis.audio}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/declare_permissions.html b/chrome/common/extensions/docs/templates/public/apps/declare_permissions.html
index 998bb68..66e2ecd 100644
--- a/chrome/common/extensions/docs/templates/public/apps/declare_permissions.html
+++ b/chrome/common/extensions/docs/templates/public/apps/declare_permissions.html
@@ -1 +1,2 @@
-{{+partials.standard_apps_article article:intros.declare_permissions}}
+{{+partials.standard_apps_article article:intros.declare_permissions
+                                  permissions:permissions.declare_apps}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/manifest.html b/chrome/common/extensions/docs/templates/public/apps/manifest.html
index a561d56..31d7c10 100644
--- a/chrome/common/extensions/docs/templates/public/apps/manifest.html
+++ b/chrome/common/extensions/docs/templates/public/apps/manifest.html
@@ -1 +1,2 @@
-{{+partials.standard_apps_article article:intros.apps_manifest}}
+{{+partials.standard_apps_article article:intros.manifest
+                                  manifest_source:manifest_source.apps}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/manifest/externally_connectable.html b/chrome/common/extensions/docs/templates/public/apps/manifest/externally_connectable.html
new file mode 100644
index 0000000..5d3cfbc
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/apps/manifest/externally_connectable.html
@@ -0,0 +1,2 @@
+{{+partials.standard_apps_article
+    article:intros.manifest/externally_connectable}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/audio.html b/chrome/common/extensions/docs/templates/public/extensions/audio.html
deleted file mode 100644
index 0bf6943..0000000
--- a/chrome/common/extensions/docs/templates/public/extensions/audio.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_extensions_api api:apis.audio}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/declare_permissions.html b/chrome/common/extensions/docs/templates/public/extensions/declare_permissions.html
index 910cc34..20524c4 100644
--- a/chrome/common/extensions/docs/templates/public/extensions/declare_permissions.html
+++ b/chrome/common/extensions/docs/templates/public/extensions/declare_permissions.html
@@ -1 +1,2 @@
-{{+partials.standard_extensions_article article:intros.declare_permissions}}
+{{+partials.standard_extensions_article article:intros.declare_permissions
+                                        permissions:permissions.declare_extensions}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/desktopCapture.html b/chrome/common/extensions/docs/templates/public/extensions/desktopCapture.html
new file mode 100644
index 0000000..0de6f23
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/extensions/desktopCapture.html
@@ -0,0 +1 @@
+{{+partials.standard_extensions_api api:apis.desktop_capture}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/experimental_processes.html b/chrome/common/extensions/docs/templates/public/extensions/experimental_processes.html
deleted file mode 100644
index ee75b84..0000000
--- a/chrome/common/extensions/docs/templates/public/extensions/experimental_processes.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_extensions_api api:apis.experimental_processes}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/manifest.html b/chrome/common/extensions/docs/templates/public/extensions/manifest.html
index 1cfeb9f..b473166 100644
--- a/chrome/common/extensions/docs/templates/public/extensions/manifest.html
+++ b/chrome/common/extensions/docs/templates/public/extensions/manifest.html
@@ -1 +1,3 @@
-{{+partials.standard_extensions_article article:intros.extensions_manifest}}
+{{+partials.standard_extensions_article
+    article:intros.manifest
+    manifest_source:manifest_source.extensions}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/manifest/externally_connectable.html b/chrome/common/extensions/docs/templates/public/extensions/manifest/externally_connectable.html
new file mode 100644
index 0000000..8bbc420
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/extensions/manifest/externally_connectable.html
@@ -0,0 +1,2 @@
+{{+partials.standard_extensions_article
+    article:intros.manifest/externally_connectable}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/processes.html b/chrome/common/extensions/docs/templates/public/extensions/processes.html
new file mode 100644
index 0000000..530b7a5
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/extensions/processes.html
@@ -0,0 +1 @@
+{{+partials.standard_extensions_api api:apis.processes}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/sessionRestore.html b/chrome/common/extensions/docs/templates/public/extensions/sessionRestore.html
deleted file mode 100644
index c23236c..0000000
--- a/chrome/common/extensions/docs/templates/public/extensions/sessionRestore.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_extensions_api api:apis.session_restore}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/sessions.html b/chrome/common/extensions/docs/templates/public/extensions/sessions.html
new file mode 100644
index 0000000..b825ba6
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/extensions/sessions.html
@@ -0,0 +1 @@
+{{+partials.standard_extensions_api api:apis.sessions}}
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index df10d27..7ed252d 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -21,7 +21,6 @@
 #include "base/values.h"
 #include "base/version.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
 #include "chrome/common/extensions/permissions/api_permission_set.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
@@ -31,6 +30,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/id_util.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/switches.h"
 #include "extensions/common/url_pattern_set.h"
 #include "grit/chromium_strings.h"
@@ -42,7 +42,7 @@
 #include "grit/generated_resources.h"
 #endif
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace values = extension_manifest_values;
 namespace errors = extension_manifest_errors;
 
@@ -390,22 +390,14 @@
   if (is_theme())
     return false;
 
-  // Don't show component extensions because they are only extensions as an
-  // implementation detail of Chrome.
-  if (location() == Manifest::COMPONENT &&
-      !CommandLine::ForCurrentProcess()->HasSwitch(
-        switches::kShowComponentExtensionOptions)) {
+  // Don't show component extensions and invisible apps.
+  if (ShouldNotBeVisible())
     return false;
-  }
 
   // Always show unpacked extensions and apps.
   if (Manifest::IsUnpackedLocation(location()))
     return true;
 
-  // Don't show apps that aren't visible in either launcher or ntp.
-  if (is_app() && !ShouldDisplayInAppLauncher() && !ShouldDisplayInNewTabPage())
-    return false;
-
   // Unless they are unpacked, never show hosted apps. Note: We intentionally
   // show packaged apps and platform apps because there are some pieces of
   // functionality that are only available in chrome://extensions/ but which
@@ -417,6 +409,26 @@
   return true;
 }
 
+bool Extension::ShouldNotBeVisible() const {
+  // Don't show component extensions because they are only extensions as an
+  // implementation detail of Chrome.
+  if (location() == Manifest::COMPONENT &&
+      !CommandLine::ForCurrentProcess()->HasSwitch(
+        switches::kShowComponentExtensionOptions)) {
+    return true;
+  }
+
+  // Always show unpacked extensions and apps.
+  if (Manifest::IsUnpackedLocation(location()))
+    return false;
+
+  // Don't show apps that aren't visible in either launcher or ntp.
+  if (is_app() && !ShouldDisplayInAppLauncher() && !ShouldDisplayInNewTabPage())
+    return true;
+
+  return false;
+}
+
 Extension::ManifestData* Extension::GetManifestData(const std::string& key)
     const {
   DCHECK(finished_parsing_manifest_ || thread_checker_.CalledOnValidThread());
@@ -752,13 +764,15 @@
   }
 
   manifest_version_ = manifest_->GetManifestVersion();
-  if (creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
-      manifest_version_ < kModernManifestVersion &&
-      !CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAllowLegacyExtensionManifests)) {
+  if (manifest_version_ < kModernManifestVersion &&
+      ((creation_flags_ & REQUIRE_MODERN_MANIFEST_VERSION &&
+        !CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kAllowLegacyExtensionManifests)) ||
+       GetType() == Manifest::TYPE_PLATFORM_APP)) {
     *error = ErrorUtils::FormatErrorMessageUTF16(
         errors::kInvalidManifestVersionOld,
-        base::IntToString(kModernManifestVersion));
+        base::IntToString(kModernManifestVersion),
+        is_platform_app() ? "apps" : "extensions");
     return false;
   }
 
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 87f1148..4d3b310 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -21,10 +21,10 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/install_warning.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/url_pattern.h"
 #include "extensions/common/url_pattern_set.h"
 #include "ui/base/accelerators/accelerator.h"
@@ -251,6 +251,11 @@
   // settings page (i.e. chrome://extensions).
   bool ShouldDisplayInExtensionSettings() const;
 
+  // Returns true if the extension should not be shown anywhere. This is
+  // mostly the same as the extension being a component extension, but also
+  // includes non-component apps that are hidden from the app launcher and ntp.
+  bool ShouldNotBeVisible() const;
+
   // Get the manifest data associated with the key, or NULL if there is none.
   // Can only be called after InitValue is finished.
   ManifestData* GetManifestData(const std::string& key) const;
diff --git a/chrome/common/extensions/extension_builder.h b/chrome/common/extensions/extension_builder.h
index c55eb73..4b4669d 100644
--- a/chrome/common/extensions/extension_builder.h
+++ b/chrome/common/extensions/extension_builder.h
@@ -8,8 +8,8 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/value_builder.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 class Extension;
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 52a8861..0148a7f 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -204,7 +204,8 @@
     // Launch via chrome.management.launchApp.
     APP_LAUNCH_EXTENSION_API,
 
-    // Launch using the --app or --app-id cmd line options.
+    // Launch an app via a shortcut. This includes using the --app or --app-id
+    // command line arguments, or via an app shim process on Mac.
     APP_LAUNCH_CMD_LINE_APP,
 
     // App launch by passing the URL on the cmd line (not using app switches).
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
index 29ed5ca..82bf462 100644
--- a/chrome/common/extensions/extension_file_util.cc
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -25,7 +25,6 @@
 #include "chrome/common/extensions/extension_l10n_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
 #include "chrome/common/extensions/manifest_handlers/theme_handler.h"
@@ -33,6 +32,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/install_warning.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "net/base/escape.h"
 #include "net/base/file_stream.h"
@@ -264,10 +264,11 @@
     return false;
 
   // Check children of extension root to see if any of them start with _ and is
-  // not on the reserved list.
-  if (!CheckForIllegalFilenames(extension->path(), error)) {
-    return false;
-  }
+  // not on the reserved list. We only warn, and do not block the loading of the
+  // extension.
+  std::string warning;
+  if (!CheckForIllegalFilenames(extension->path(), &warning))
+    warnings->push_back(extensions::InstallWarning(warning));
 
   // Check that extensions don't include private key files.
   std::vector<base::FilePath> private_keys =
@@ -284,7 +285,6 @@
   } else {
     for (size_t i = 0; i < private_keys.size(); ++i) {
       warnings->push_back(extensions::InstallWarning(
-          extensions::InstallWarning::FORMAT_TEXT,
           l10n_util::GetStringFUTF8(
               IDS_EXTENSION_CONTAINS_PRIVATE_KEY,
               private_keys[i].LossyDisplayName())));
diff --git a/chrome/common/extensions/extension_file_util.h b/chrome/common/extensions/extension_file_util.h
index 6335355..35db4e8 100644
--- a/chrome/common/extensions/extension_file_util.h
+++ b/chrome/common/extensions/extension_file_util.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_FILE_UTIL_H_
 #define CHROME_COMMON_EXTENSIONS_EXTENSION_FILE_UTIL_H_
 
-#include <string>
 #include <map>
+#include <string>
 
 #include "base/memory/ref_counted.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/message_bundle.h"
+#include "extensions/common/manifest.h"
 
 class ExtensionIconSet;
 class GURL;
@@ -88,7 +88,6 @@
 std::set<base::FilePath> GetBrowserImagePaths(
     const extensions::Extension* extension);
 
-
 // Returns a list of files that contain private keys inside |extension_dir|.
 std::vector<base::FilePath> FindPrivateKeyFiles(
     const base::FilePath& extension_dir);
diff --git a/chrome/common/extensions/extension_file_util_unittest.cc b/chrome/common/extensions/extension_file_util_unittest.cc
index 24e102c..3271595 100644
--- a/chrome/common/extensions/extension_file_util_unittest.cc
+++ b/chrome/common/extensions/extension_file_util_unittest.cc
@@ -12,9 +12,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #include "grit/generated_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,7 +23,7 @@
 using extensions::Extension;
 using extensions::Manifest;
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 class ExtensionFileUtilTest : public testing::Test {
 };
diff --git a/chrome/common/extensions/extension_l10n_util.cc b/chrome/common/extensions/extension_l10n_util.cc
index 807deae..ecb2574 100644
--- a/chrome/common/extensions/extension_l10n_util.cc
+++ b/chrome/common/extensions/extension_l10n_util.cc
@@ -25,7 +25,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 static std::string& GetProcessLocale() {
   CR_DEFINE_STATIC_LOCAL(std::string, locale, ());
@@ -167,6 +167,18 @@
   if (!LocalizeManifestValue(keys::kLaunchWebURL, messages, manifest, error))
     return false;
 
+  // Initialize description of commmands.
+  base::DictionaryValue* commands_handler = NULL;
+  if (manifest->GetDictionary(keys::kCommands, &commands_handler)) {
+    for (DictionaryValue::Iterator iter(*commands_handler); !iter.IsAtEnd();
+         iter.Advance()) {
+      key.assign(base::StringPrintf("commands.%s.description",
+                                    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 e5194ff..a1fe13d 100644
--- a/chrome/common/extensions/extension_l10n_util_unittest.cc
+++ b/chrome/common/extensions/extension_l10n_util_unittest.cc
@@ -22,7 +22,7 @@
 using extensions::MessageBundle;
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace {
 
@@ -249,6 +249,16 @@
   launch_web_url_tree->SetString("message", "http://www.google.com/");
   catalog->Set("launch_web_url", launch_web_url_tree);
 
+  base::DictionaryValue* first_command_description_tree =
+      new base::DictionaryValue();
+  first_command_description_tree->SetString("message", "first command");
+  catalog->Set("first_command_description", first_command_description_tree);
+
+  base::DictionaryValue* second_command_description_tree =
+      new base::DictionaryValue();
+  second_command_description_tree->SetString("message", "second command");
+  catalog->Set("second_command_description", second_command_description_tree);
+
   std::vector<linked_ptr<base::DictionaryValue> > catalogs;
   catalogs.push_back(catalog);
 
@@ -443,6 +453,48 @@
   EXPECT_TRUE(error.empty());
 }
 
+TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionCommandDescription) {
+  base::DictionaryValue manifest;
+  manifest.SetString(keys::kName, "__MSG_name__");
+  manifest.SetString(keys::kDescription, "__MSG_description__");
+  base::DictionaryValue* commands = new DictionaryValue();
+  std::string commands_title(keys::kCommands);
+  manifest.Set(commands_title, commands);
+
+  base::DictionaryValue* first_command = new DictionaryValue();
+  commands->Set("first_command", first_command);
+  first_command->SetString(keys::kDescription,
+                           "__MSG_first_command_description__");
+
+  base::DictionaryValue* second_command = new DictionaryValue();
+  commands->Set("second_command", second_command);
+  second_command->SetString(keys::kDescription,
+                            "__MSG_second_command_description__");
+
+  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);
+
+  ASSERT_TRUE(manifest.GetString("commands.first_command.description",
+                                 &result));
+  EXPECT_EQ("first command", result);
+
+  ASSERT_TRUE(manifest.GetString("commands.second_command.description",
+                                 &result));
+  EXPECT_EQ("second command", 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_manifest_constants.cc b/chrome/common/extensions/extension_manifest_constants.cc
index dff9e6b..69d51e8 100644
--- a/chrome/common/extensions/extension_manifest_constants.cc
+++ b/chrome/common/extensions/extension_manifest_constants.cc
@@ -4,147 +4,6 @@
 
 #include "chrome/common/extensions/extension_manifest_constants.h"
 
-namespace extension_manifest_keys {
-
-const char kAllFrames[] = "all_frames";
-const char kAltKey[] = "altKey";
-const char kApp[] = "app";
-const char kAudio[] = "audio";
-const char kBackgroundAllowJsAccess[] = "background.allow_js_access";
-const char kBackgroundPage[] = "background.page";
-const char kBackgroundPageLegacy[] = "background_page";
-const char kBackgroundPersistent[] = "background.persistent";
-const char kBackgroundScripts[] = "background.scripts";
-const char kBrowserAction[] = "browser_action";
-const char kChromeURLOverrides[] = "chrome_url_overrides";
-const char kCommands[] = "commands";
-const char kContentPack[] = "content_pack";
-const char kContentPackSites[] = "sites";
-const char kContentScripts[] = "content_scripts";
-const char kContentSecurityPolicy[] = "content_security_policy";
-const char kConvertedFromUserScript[] = "converted_from_user_script";
-const char kCss[] = "css";
-const char kCtrlKey[] = "ctrlKey";
-const char kCurrentLocale[] = "current_locale";
-const char kDefaultLocale[] = "default_locale";
-const char kDescription[] = "description";
-const char kDevToolsPage[] = "devtools_page";
-const char kDisplayInLauncher[] = "display_in_launcher";
-const char kDisplayInNewTabPage[] = "display_in_new_tab_page";
-const char kEventName[] = "event_name";
-const char kExcludeGlobs[] = "exclude_globs";
-const char kExcludeMatches[] = "exclude_matches";
-const char kExport[] = "export";
-const char kExternallyConnectable[] = "externally_connectable";
-const char kFileAccessList[] = "file_access";
-const char kFileFilters[] = "file_filters";
-const char kFileBrowserHandlers[] = "file_browser_handlers";
-const char kMediaGalleriesHandlers[] = "media_galleries_handlers";
-const char kFileHandlers[] = "file_handlers";
-const char kFileHandlerExtensions[] = "extensions";
-const char kFileHandlerTitle[] = "title";
-const char kFileHandlerTypes[] = "types";
-const char kHomepageURL[] = "homepage_url";
-const char kIcons[] = "icons";
-const char kId[] = "id";
-const char kImport[] = "import";
-const char kIncognito[] = "incognito";
-const char kIncludeGlobs[] = "include_globs";
-const char kInputComponents[] = "input_components";
-const char kIsolation[] = "app.isolation";
-const char kJs[] = "js";
-const char kKey[] = "key";
-const char kKeycode[] = "keyCode";
-const char kKioskEnabled[] = "kiosk_enabled";
-const char kLanguage[] = "language";
-const char kLaunch[] = "app.launch";
-const char kLaunchContainer[] = "app.launch.container";
-const char kLaunchHeight[] = "app.launch.height";
-const char kLaunchLocalPath[] = "app.launch.local_path";
-const char kLaunchWebURL[] = "app.launch.web_url";
-const char kLaunchWidth[] = "app.launch.width";
-const char kLayouts[] = "layouts";
-const char kManifestVersion[] = "manifest_version";
-const char kMatches[] = "matches";
-const char kMinimumChromeVersion[] = "minimum_chrome_version";
-const char kMinimumVersion[] = "minimum_version";
-const char kMIMETypes[] = "mime_types";
-const char kMimeTypesHandler[] = "mime_types_handler";
-const char kName[] = "name";
-const char kNaClModules[] = "nacl_modules";
-const char kNaClModulesMIMEType[] = "mime_type";
-const char kNaClModulesPath[] = "path";
-const char kOAuth2[] = "oauth2";
-const char kOAuth2AutoApprove[] = "oauth2.auto_approve";
-const char kOAuth2ClientId[] = "oauth2.client_id";
-const char kOAuth2Scopes[] = "oauth2.scopes";
-const char kOfflineEnabled[] = "offline_enabled";
-const char kOmnibox[] = "omnibox";
-const char kOmniboxKeyword[] = "omnibox.keyword";
-const char kOptionalPermissions[] = "optional_permissions";
-const char kOptionsPage[] = "options_page";
-const char kPageAction[] = "page_action";
-const char kPageActionDefaultIcon[] = "default_icon";
-const char kPageActionDefaultPopup[] = "default_popup";
-const char kPageActionDefaultTitle[] = "default_title";
-const char kPageActionIcons[] = "icons";
-const char kPageActionId[] = "id";
-const char kPageActionPopup[] = "popup";
-const char kPageActionPopupPath[] = "path";
-const char kPageActions[] = "page_actions";
-const char kPermissions[] = "permissions";
-const char kPlatformAppBackground[] = "app.background";
-const char kPlatformAppBackgroundPage[] = "app.background.page";
-const char kPlatformAppBackgroundScripts[] = "app.background.scripts";
-const char kPlatformAppContentSecurityPolicy[] = "app.content_security_policy";
-const char kPlugins[] = "plugins";
-const char kPluginsPath[] = "path";
-const char kPluginsPublic[] = "public";
-const char kPublicKey[] = "key";
-const char kResources[] = "resources";
-const char kRequirements[] = "requirements";
-const char kRunAt[] = "run_at";
-const char kSandboxedPages[] = "sandbox.pages";
-const char kSandboxedPagesCSP[] = "sandbox.content_security_policy";
-const char kScriptBadge[] = "script_badge";
-const char kShiftKey[] = "shiftKey";
-const char kShortcutKey[] = "shortcutKey";
-const char kSignature[] = "signature";
-const char kSpellcheck[] = "spellcheck";
-const char kSpellcheckDictionaryFormat[] = "dictionary_format";
-const char kSpellcheckDictionaryLanguage[] = "dictionary_language";
-const char kSpellcheckDictionaryLocale[] = "dictionary_locale";
-const char kSpellcheckDictionaryPath[] = "dictionary_path";
-const char kStorageManagedSchema[] = "storage.managed_schema";
-const char kSuggestedKey[] = "suggested_key";
-const char kSystemIndicator[] = "system_indicator";
-const char kSystemInfoDisplay[] = "systemInfo.display";
-const char kTheme[] = "theme";
-const char kThemeColors[] = "colors";
-const char kThemeDisplayProperties[] = "properties";
-const char kThemeImages[] = "images";
-const char kThemeTints[] = "tints";
-const char kTtsEngine[] = "tts_engine";
-const char kTtsGenderFemale[] = "female";
-const char kTtsGenderMale[] = "male";
-const char kTtsVoices[] = "voices";
-const char kTtsVoicesEventTypeEnd[] = "end";
-const char kTtsVoicesEventTypeError[] = "error";
-const char kTtsVoicesEventTypeMarker[] = "marker";
-const char kTtsVoicesEventTypeSentence[] = "sentence";
-const char kTtsVoicesEventTypeStart[] = "start";
-const char kTtsVoicesEventTypeWord[] = "word";
-const char kTtsVoicesEventTypes[] = "event_types";
-const char kTtsVoicesGender[] = "gender";
-const char kTtsVoicesLang[] = "lang";
-const char kTtsVoicesVoiceName[] = "voice_name";
-const char kType[] = "type";
-const char kUpdateURL[] = "update_url";
-const char kVersion[] = "version";
-const char kWebAccessibleResources[] = "web_accessible_resources";
-const char kWebURLs[] = "app.urls";
-}  // namespace extension_manifest_keys
-
 namespace extension_manifest_values {
 const char kBrowserActionCommandEvent[] = "_execute_browser_action";
 const char kIncognitoSplit[] = "split";
@@ -415,7 +274,7 @@
     "zero.";
 const char kInvalidManifestVersionOld[] =
     "The 'manifest_version' key must be present and set to * (without quotes). "
-    "See developer.chrome.com/extensions/manifestVersion.html for details.";
+    "See developer.chrome.com/*/manifestVersion.html for details.";
 const char kInvalidMatch[] =
     "Invalid value for 'content_scripts[*].matches[*]': *";
 const char kInvalidMatchCount[] =
@@ -603,8 +462,6 @@
     "Access to permission '*' denied.";
 const char kPermissionNotAllowedInManifest[] =
     "Permission '*' cannot be specified in the manifest.";
-const char kPlatformAppNeedsManifestVersion2[] =
-    "Packaged apps need manifest_version set to >= 2";
 const char kReservedMessageFound[] =
     "Reserved key * found in message catalog.";
 const char kScriptBadgeRequiresFlag[] =
diff --git a/chrome/common/extensions/extension_manifest_constants.h b/chrome/common/extensions/extension_manifest_constants.h
index cc56bb6..1d92c71 100644
--- a/chrome/common/extensions/extension_manifest_constants.h
+++ b/chrome/common/extensions/extension_manifest_constants.h
@@ -8,154 +8,10 @@
 #include <string>
 
 #include "base/basictypes.h"
+// TODO(yoz): Update includers to include this directly.
+#include "extensions/common/manifest_constants.h"
 #include "url/gurl.h"
 
-// Keys used in JSON representation of extensions.
-namespace extension_manifest_keys {
-  extern const char kAllFrames[];
-  extern const char kAltKey[];
-  extern const char kApp[];
-  extern const char kBackgroundAllowJsAccess[];
-  extern const char kBackgroundPage[];
-  extern const char kBackgroundPageLegacy[];
-  extern const char kBackgroundPersistent[];
-  extern const char kBackgroundScripts[];
-  extern const char kBrowserAction[];
-  extern const char kBrowseURLs[];
-  extern const char kChromeURLOverrides[];
-  extern const char kCommands[];
-  extern const char kContentPack[];
-  extern const char kContentPackSites[];
-  extern const char kContentScripts[];
-  extern const char kContentSecurityPolicy[];
-  extern const char kConvertedFromUserScript[];
-  extern const char kCss[];
-  extern const char kCtrlKey[];
-  extern const char kCurrentLocale[];
-  extern const char kDefaultLocale[];
-  extern const char kDescription[];
-  extern const char kDevToolsPage[];
-  extern const char kDisplayInLauncher[];
-  extern const char kDisplayInNewTabPage[];
-  extern const char kEventName[];
-  extern const char kExcludeGlobs[];
-  extern const char kExcludeMatches[];
-  extern const char kExport[];
-  extern const char kExternallyConnectable[];
-  extern const char kFileAccessList[];
-  extern const char kFileHandlers[];
-  extern const char kFileHandlerExtensions[];
-  extern const char kFileHandlerTitle[];
-  extern const char kFileHandlerTypes[];
-  extern const char kFileFilters[];
-  extern const char kFileBrowserHandlers[];
-  extern const char kMediaGalleriesHandlers[];
-  extern const char kHomepageURL[];
-  extern const char kIcons[];
-  extern const char kId[];
-  extern const char kImport[];
-  extern const char kIncognito[];
-  extern const char kIncludeGlobs[];
-  extern const char kInputComponents[];
-  extern const char kIntentDisposition[];
-  extern const char kIntentHref[];
-  extern const char kIntentPath[];
-  extern const char kIntents[];
-  extern const char kIntentTitle[];
-  extern const char kIntentType[];
-  extern const char kIsolation[];
-  extern const char kJs[];
-  extern const char kKey[];
-  extern const char kKeycode[];
-  extern const char kKioskEnabled[];
-  extern const char kLanguage[];
-  extern const char kLaunch[];
-  extern const char kLaunchContainer[];
-  extern const char kLaunchHeight[];
-  extern const char kLaunchLocalPath[];
-  extern const char kLaunchWebURL[];
-  extern const char kLaunchWidth[];
-  extern const char kLayouts[];
-  extern const char kManifestVersion[];
-  extern const char kMatches[];
-  extern const char kMIMETypes[];
-  extern const char kMimeTypesHandler[];
-  extern const char kMinimumChromeVersion[];
-  extern const char kMinimumVersion[];
-  extern const char kNaClModules[];
-  extern const char kNaClModulesMIMEType[];
-  extern const char kNaClModulesPath[];
-  extern const char kName[];
-  extern const char kOAuth2[];
-  extern const char kOAuth2AutoApprove[];
-  extern const char kOAuth2ClientId[];
-  extern const char kOAuth2Scopes[];
-  extern const char kOfflineEnabled[];
-  extern const char kOmnibox[];
-  extern const char kOmniboxKeyword[];
-  extern const char kOptionalPermissions[];
-  extern const char kOptionsPage[];
-  extern const char kPageAction[];
-  extern const char kPageActionDefaultIcon[];
-  extern const char kPageActionDefaultPopup[];
-  extern const char kPageActionDefaultTitle[];
-  extern const char kPageActionIcons[];
-  extern const char kPageActionId[];
-  extern const char kPageActionPopup[];
-  extern const char kPageActionPopupPath[];
-  extern const char kPageActions[];
-  extern const char kPermissions[];
-  extern const char kPlatformAppBackground[];
-  extern const char kPlatformAppBackgroundPage[];
-  extern const char kPlatformAppBackgroundScripts[];
-  extern const char kPlatformAppContentSecurityPolicy[];
-  extern const char kPlugins[];
-  extern const char kPluginsPath[];
-  extern const char kPluginsPublic[];
-  extern const char kPublicKey[];
-  extern const char kResources[];
-  extern const char kRequirements[];
-  extern const char kRunAt[];
-  extern const char kSandboxedPages[];
-  extern const char kSandboxedPagesCSP[];
-  extern const char kScriptBadge[];
-  extern const char kShiftKey[];
-  extern const char kShortcutKey[];
-  extern const char kSignature[];
-  extern const char kSpellcheck[];
-  extern const char kSpellcheckDictionaryFormat[];
-  extern const char kSpellcheckDictionaryLanguage[];
-  extern const char kSpellcheckDictionaryLocale[];
-  extern const char kSpellcheckDictionaryPath[];
-  extern const char kStorageManagedSchema[];
-  extern const char kSuggestedKey[];
-  extern const char kSystemIndicator[];
-  extern const char kTheme[];
-  extern const char kThemeColors[];
-  extern const char kThemeDisplayProperties[];
-  extern const char kThemeImages[];
-  extern const char kThemeTints[];
-  extern const char kTtsEngine[];
-  extern const char kTtsGenderFemale[];
-  extern const char kTtsGenderMale[];
-  extern const char kTtsVoices[];
-  extern const char kTtsVoicesEventTypeEnd[];
-  extern const char kTtsVoicesEventTypeError[];
-  extern const char kTtsVoicesEventTypeMarker[];
-  extern const char kTtsVoicesEventTypeSentence[];
-  extern const char kTtsVoicesEventTypeStart[];
-  extern const char kTtsVoicesEventTypeWord[];
-  extern const char kTtsVoicesEventTypes[];
-  extern const char kTtsVoicesGender[];
-  extern const char kTtsVoicesLang[];
-  extern const char kTtsVoicesVoiceName[];
-  extern const char kType[];
-  extern const char kUpdateURL[];
-  extern const char kVersion[];
-  extern const char kWebAccessibleResources[];
-  extern const char kWebURLs[];
-}  // namespace extension_manifest_keys
-
 // Some values expected in manifests.
 namespace extension_manifest_values {
   extern const char kBrowserActionCommandEvent[];
@@ -399,7 +255,6 @@
   extern const char kPermissionMustBeOptional[];
   extern const char kPermissionNotAllowed[];
   extern const char kPermissionNotAllowedInManifest[];
-  extern const char kPlatformAppNeedsManifestVersion2[];
   extern const char kOneUISurfaceOnly[];
   extern const char kReservedMessageFound[];
   extern const char kScriptBadgeRequiresFlag[];
diff --git a/chrome/common/extensions/extension_messages.cc b/chrome/common/extensions/extension_messages.cc
index 097a090..1530222 100644
--- a/chrome/common/extensions/extension_messages.cc
+++ b/chrome/common/extensions/extension_messages.cc
@@ -6,10 +6,10 @@
 
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/extensions/permissions/permissions_info.h"
 #include "content/public/common/common_param_traits.h"
+#include "extensions/common/manifest.h"
 
 using extensions::APIPermission;
 using extensions::APIPermissionInfo;
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 9403e29..c2fd98d 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -621,11 +621,6 @@
                      std::string /* extension_id */,
                      ExtensionHostMsg_APIActionOrEvent_Params)
 
-// Sent by the renderer to log a blocked API action to the activity log.
-IPC_MESSAGE_CONTROL2(ExtensionHostMsg_AddBlockedCallToActivityLog,
-                    std::string /* extension_id */,
-                    std::string /* api call function name */)
-
 // Sent by the renderer to log an event to the extension activity log.
 IPC_MESSAGE_CONTROL2(ExtensionHostMsg_AddEventToActivityLog,
                     std::string /* extension_id */,
diff --git a/chrome/common/extensions/extension_test_util.cc b/chrome/common/extensions/extension_test_util.cc
index 02e9b22..a4e66fb 100644
--- a/chrome/common/extensions/extension_test_util.cc
+++ b/chrome/common/extensions/extension_test_util.cc
@@ -11,7 +11,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_builder.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extensions::DictionaryBuilder;
@@ -46,8 +46,8 @@
 
 scoped_refptr<Extension> CreateExtensionWithID(std::string id) {
   base::DictionaryValue values;
-  values.SetString(extension_manifest_keys::kName, "test");
-  values.SetString(extension_manifest_keys::kVersion, "0.1");
+  values.SetString(extensions::manifest_keys::kName, "test");
+  values.SetString(extensions::manifest_keys::kVersion, "0.1");
   std::string error;
   return Extension::Create(base::FilePath(), extensions::Manifest::INTERNAL,
                            values, Extension::NO_FLAGS, id, &error);
diff --git a/chrome/common/extensions/extension_test_util.h b/chrome/common/extensions/extension_test_util.h
index 500bdb7..f6cdc1a 100644
--- a/chrome/common/extensions/extension_test_util.h
+++ b/chrome/common/extensions/extension_test_util.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "chrome/common/extensions/extension_builder.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 class Extension;
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index 43e9aed..f00cd3c 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -12,11 +12,11 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_test_util.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/url_constants.h"
 #include "extensions/common/extension_resource.h"
+#include "extensions/common/manifest.h"
 #include "net/base/mime_sniffer.h"
 #include "net/dns/mock_host_resolver.h"
 #include "skia/ext/image_operations.h"
diff --git a/chrome/common/extensions/features/complex_feature.h b/chrome/common/extensions/features/complex_feature.h
index 8653d3d..3cfa451 100644
--- a/chrome/common/extensions/features/complex_feature.h
+++ b/chrome/common/extensions/features/complex_feature.h
@@ -9,8 +9,8 @@
 
 #include "base/memory/scoped_vector.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/features/feature.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/features/feature.cc b/chrome/common/extensions/features/feature.cc
deleted file mode 100644
index d1ae538..0000000
--- a/chrome/common/extensions/features/feature.cc
+++ /dev/null
@@ -1,43 +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/common/extensions/features/feature.h"
-
-#include <map>
-
-#include "base/command_line.h"
-#include "base/lazy_instance.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-
-namespace extensions {
-
-// static
-Feature::Platform Feature::GetCurrentPlatform() {
-#if defined(OS_CHROMEOS)
-  return CHROMEOS_PLATFORM;
-#else
-  return UNSPECIFIED_PLATFORM;
-#endif
-}
-
-// static
-Feature::Location Feature::ConvertLocation(Manifest::Location location) {
-  if (location == Manifest::COMPONENT)
-    return COMPONENT_LOCATION;
-  else
-    return UNSPECIFIED_LOCATION;
-}
-
-// static
-Feature::Availability Feature::CreateAvailability(AvailabilityResult result,
-                                                  const std::string& message) {
-  return Availability(result, message);
-}
-
-Feature::Feature() : no_parent_(false) {}
-
-Feature::~Feature() {}
-
-}  // namespace extensions
diff --git a/chrome/common/extensions/features/feature.h b/chrome/common/extensions/features/feature.h
deleted file mode 100644
index 618da57..0000000
--- a/chrome/common/extensions/features/feature.h
+++ /dev/null
@@ -1,155 +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_FEATURES_FEATURE_H_
-#define CHROME_COMMON_EXTENSIONS_FEATURES_FEATURE_H_
-
-#include <set>
-#include <string>
-
-#include "base/values.h"
-#include "chrome/common/extensions/manifest.h"
-
-class GURL;
-
-namespace extensions {
-
-class Extension;
-
-// Represents a single feature accessible to an extension developer, such as a
-// top-level manifest key, a permission, or a programmatic API. A feature can
-// express requirements for where it can be accessed, and supports testing
-// support for those requirements.
-class Feature {
- public:
-  // The JavaScript contexts the feature is supported in.
-  enum Context {
-    UNSPECIFIED_CONTEXT,
-
-    // A context in a privileged extension process.
-    BLESSED_EXTENSION_CONTEXT,
-
-    // A context in an unprivileged extension process.
-    UNBLESSED_EXTENSION_CONTEXT,
-
-    // A context from a content script.
-    CONTENT_SCRIPT_CONTEXT,
-
-    // A normal web page. This should have an associated URL matching pattern.
-    WEB_PAGE_CONTEXT,
-  };
-
-  // The location required of extensions the feature is supported in.
-  enum Location {
-    UNSPECIFIED_LOCATION,
-    COMPONENT_LOCATION
-  };
-
-  // The platforms the feature is supported in.
-  enum Platform {
-    UNSPECIFIED_PLATFORM,
-    CHROMEOS_PLATFORM
-  };
-
-  // Whether a feature is available in a given situation or not, and if not,
-  // why not.
-  enum AvailabilityResult {
-    IS_AVAILABLE,
-    NOT_FOUND_IN_WHITELIST,
-    INVALID_URL,
-    INVALID_TYPE,
-    INVALID_CONTEXT,
-    INVALID_LOCATION,
-    INVALID_PLATFORM,
-    INVALID_MIN_MANIFEST_VERSION,
-    INVALID_MAX_MANIFEST_VERSION,
-    NOT_PRESENT,
-    UNSUPPORTED_CHANNEL,
-  };
-
-  // Container for AvailabiltyResult that also exposes a user-visible error
-  // message in cases where the feature is not available.
-  class Availability {
-   public:
-    AvailabilityResult result() const { return result_; }
-    bool is_available() const { return result_ == IS_AVAILABLE; }
-    const std::string& message() const { return message_; }
-
-   private:
-    friend class SimpleFeature;
-    friend class Feature;
-
-    // Instances should be created via Feature::CreateAvailability.
-    Availability(AvailabilityResult result, const std::string& message)
-        : result_(result), message_(message) { }
-
-    const AvailabilityResult result_;
-    const std::string message_;
-  };
-
-  Feature();
-  virtual ~Feature();
-
-  // Used by ChromeV8Context until the feature system is fully functional.
-  static Availability CreateAvailability(AvailabilityResult result,
-                                         const std::string& message);
-
-  const std::string& name() const { return name_; }
-  void set_name(const std::string& name) { name_ = name; }
-  const std::set<std::string>& dependencies() { return dependencies_; }
-  bool no_parent() const { return no_parent_; }
-
-  // Gets the platform the code is currently running on.
-  static Platform GetCurrentPlatform();
-
-  // Gets the Feature::Location value for the specified Manifest::Location.
-  static Location ConvertLocation(Manifest::Location extension_location);
-
-  virtual std::set<Context>* GetContexts() = 0;
-
-  // Tests whether this is an internal API or not.
-  virtual bool IsInternal() const = 0;
-
-  // Returns true if the feature is available to be parsed into a new extension
-  // manifest.
-  Availability IsAvailableToManifest(const std::string& extension_id,
-                                     Manifest::Type type,
-                                     Location location,
-                                     int manifest_version) const {
-    return IsAvailableToManifest(extension_id, type, location, manifest_version,
-                                 GetCurrentPlatform());
-  }
-  virtual Availability IsAvailableToManifest(const std::string& extension_id,
-                                             Manifest::Type type,
-                                             Location location,
-                                             int manifest_version,
-                                             Platform platform) const = 0;
-
-  // Returns true if the feature is available to be used in the specified
-  // extension and context.
-  Availability IsAvailableToContext(const Extension* extension,
-                                    Context context,
-                                    const GURL& url) const {
-    return IsAvailableToContext(extension, context, url, GetCurrentPlatform());
-  }
-  virtual Availability IsAvailableToContext(const Extension* extension,
-                                            Context context,
-                                            const GURL& url,
-                                            Platform platform) const = 0;
-
-  virtual std::string GetAvailabilityMessage(AvailabilityResult result,
-                                             Manifest::Type type,
-                                             const GURL& url) const = 0;
-
-  virtual bool IsIdInWhitelist(const std::string& extension_id) const = 0;
-
- protected:
-  std::string name_;
-  std::set<std::string> dependencies_;
-  bool no_parent_;
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_COMMON_EXTENSIONS_FEATURES_FEATURE_H_
diff --git a/chrome/common/extensions/features/manifest_feature.cc b/chrome/common/extensions/features/manifest_feature.cc
index 8d622a2..a8d6e42 100644
--- a/chrome/common/extensions/features/manifest_feature.cc
+++ b/chrome/common/extensions/features/manifest_feature.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/common/extensions/features/manifest_feature.h"
 
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
@@ -50,4 +50,4 @@
   return std::string();
 }
 
-}  // namespace
+}  // namespace extensions
diff --git a/chrome/common/extensions/features/simple_feature.h b/chrome/common/extensions/features/simple_feature.h
index 3e75b92..a2f307f 100644
--- a/chrome/common/extensions/features/simple_feature.h
+++ b/chrome/common/extensions/features/simple_feature.h
@@ -12,8 +12,8 @@
 #include "base/values.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/features/feature.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/incognito_handler.cc b/chrome/common/extensions/incognito_handler.cc
index 20a7471..29d1354 100644
--- a/chrome/common/extensions/incognito_handler.cc
+++ b/chrome/common/extensions/incognito_handler.cc
@@ -10,10 +10,10 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 IncognitoInfo::IncognitoInfo(bool incognito_split_mode)
     : split_mode(incognito_split_mode) {
 }
diff --git a/chrome/common/extensions/manifest.cc b/chrome/common/extensions/manifest.cc
deleted file mode 100644
index 008912a..0000000
--- a/chrome/common/extensions/manifest.cc
+++ /dev/null
@@ -1,263 +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/common/extensions/manifest.h"
-
-#include "base/basictypes.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/features/feature.h"
-#include "extensions/common/error_utils.h"
-#include "extensions/common/features/feature_provider.h"
-#include "extensions/common/install_warning.h"
-
-namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
-
-namespace extensions {
-
-namespace {
-
-// Rank extension locations in a way that allows
-// Manifest::GetHigherPriorityLocation() to compare locations.
-// An extension installed from two locations will have the location
-// with the higher rank, as returned by this function. The actual
-// integer values may change, and should never be persisted.
-int GetLocationRank(Manifest::Location location) {
-  const int kInvalidRank = -1;
-  int rank = kInvalidRank;  // Will CHECK that rank is not kInvalidRank.
-
-  switch (location) {
-    // Component extensions can not be overriden by any other type.
-    case Manifest::COMPONENT:
-      rank = 7;
-      break;
-
-    // Policy controlled extensions may not be overridden by any type
-    // that is not part of chrome.
-    case Manifest::EXTERNAL_POLICY_DOWNLOAD:
-      rank = 6;
-      break;
-
-    // A developer-loaded extension should override any installed type
-    // that a user can disable. Anything specified on the command-line should
-    // override one loaded via the extensions UI.
-    case Manifest::COMMAND_LINE:
-      rank = 5;
-      break;
-
-    case Manifest::UNPACKED:
-      rank = 4;
-      break;
-
-    // The relative priority of various external sources is not important,
-    // but having some order ensures deterministic behavior.
-    case Manifest::EXTERNAL_REGISTRY:
-      rank = 3;
-      break;
-
-    case Manifest::EXTERNAL_PREF:
-      rank = 2;
-      break;
-
-    case Manifest::EXTERNAL_PREF_DOWNLOAD:
-      rank = 1;
-      break;
-
-    // User installed extensions are overridden by any external type.
-    case Manifest::INTERNAL:
-      rank = 0;
-      break;
-
-    default:
-      NOTREACHED() << "Need to add new extension location " << location;
-  }
-
-  CHECK(rank != kInvalidRank);
-  return rank;
-}
-
-}  // namespace
-
-// static
-Manifest::Location Manifest::GetHigherPriorityLocation(
-    Location loc1, Location loc2) {
-  if (loc1 == loc2)
-    return loc1;
-
-  int loc1_rank = GetLocationRank(loc1);
-  int loc2_rank = GetLocationRank(loc2);
-
-  // If two different locations have the same rank, then we can not
-  // deterministicly choose a location.
-  CHECK(loc1_rank != loc2_rank);
-
-  // Highest rank has highest priority.
-  return (loc1_rank > loc2_rank ? loc1 : loc2 );
-}
-
-Manifest::Manifest(Location location, scoped_ptr<base::DictionaryValue> value)
-    : location_(location),
-      value_(value.Pass()),
-      type_(TYPE_UNKNOWN) {
-  if (value_->HasKey(keys::kTheme)) {
-    type_ = TYPE_THEME;
-  } else if (value_->HasKey(keys::kExport)) {
-    type_ = TYPE_SHARED_MODULE;
-  } else if (value_->HasKey(keys::kApp)) {
-    if (value_->Get(keys::kWebURLs, NULL) ||
-        value_->Get(keys::kLaunchWebURL, NULL)) {
-      type_ = TYPE_HOSTED_APP;
-    } else if (value_->Get(keys::kPlatformAppBackground, NULL)) {
-      type_ = TYPE_PLATFORM_APP;
-    } else {
-      type_ = TYPE_LEGACY_PACKAGED_APP;
-    }
-  } else {
-    type_ = TYPE_EXTENSION;
-  }
-  CHECK_NE(type_, TYPE_UNKNOWN);
-}
-
-Manifest::~Manifest() {
-}
-
-bool Manifest::ValidateManifest(
-    std::string* error,
-    std::vector<InstallWarning>* warnings) const {
-  *error = "";
-  if (type_ == Manifest::TYPE_PLATFORM_APP && GetManifestVersion() < 2) {
-    *error = errors::kPlatformAppNeedsManifestVersion2;
-    return false;
-  }
-
-  // Check every feature to see if its in the manifest. Note that this means
-  // we will ignore keys that are not features; we do this for forward
-  // compatibility.
-  // TODO(aa): Consider having an error here in the case of strict error
-  // checking to let developers know when they screw up.
-
-  FeatureProvider* provider = FeatureProvider::GetByName("manifest");
-  const std::vector<std::string>& feature_names =
-      provider->GetAllFeatureNames();
-  for (std::vector<std::string>::const_iterator feature_name =
-           feature_names.begin();
-       feature_name != feature_names.end(); ++feature_name) {
-    // Use Get instead of HasKey because the former uses path expansion.
-    if (!value_->Get(*feature_name, NULL))
-      continue;
-
-    Feature* feature = provider->GetFeature(*feature_name);
-    Feature::Availability result = feature->IsAvailableToManifest(
-        extension_id_, type_, Feature::ConvertLocation(location_),
-        GetManifestVersion());
-    if (!result.is_available())
-      warnings->push_back(InstallWarning(
-          InstallWarning::FORMAT_TEXT, result.message()));
-  }
-
-  // Also generate warnings for keys that are not features.
-  for (base::DictionaryValue::Iterator it(*value_); !it.IsAtEnd();
-       it.Advance()) {
-    if (!provider->GetFeature(it.key())) {
-      warnings->push_back(InstallWarning(
-          InstallWarning::FORMAT_TEXT,
-          base::StringPrintf("Unrecognized manifest key '%s'.",
-                             it.key().c_str())));
-    }
-  }
-  return true;
-}
-
-bool Manifest::HasKey(const std::string& key) const {
-  return CanAccessKey(key) && value_->HasKey(key);
-}
-
-bool Manifest::HasPath(const std::string& path) const {
-  base::Value* ignored = NULL;
-  return CanAccessPath(path) && value_->Get(path, &ignored);
-}
-
-bool Manifest::Get(
-    const std::string& path, const base::Value** out_value) const {
-  return CanAccessPath(path) && value_->Get(path, out_value);
-}
-
-bool Manifest::GetBoolean(
-    const std::string& path, bool* out_value) const {
-  return CanAccessPath(path) && value_->GetBoolean(path, out_value);
-}
-
-bool Manifest::GetInteger(
-    const std::string& path, int* out_value) const {
-  return CanAccessPath(path) && value_->GetInteger(path, out_value);
-}
-
-bool Manifest::GetString(
-    const std::string& path, std::string* out_value) const {
-  return CanAccessPath(path) && value_->GetString(path, out_value);
-}
-
-bool Manifest::GetString(
-    const std::string& path, string16* out_value) const {
-  return CanAccessPath(path) && value_->GetString(path, out_value);
-}
-
-bool Manifest::GetDictionary(
-    const std::string& path, const base::DictionaryValue** out_value) const {
-  return CanAccessPath(path) && value_->GetDictionary(path, out_value);
-}
-
-bool Manifest::GetList(
-    const std::string& path, const base::ListValue** out_value) const {
-  return CanAccessPath(path) && value_->GetList(path, out_value);
-}
-
-Manifest* Manifest::DeepCopy() const {
-  Manifest* manifest = new Manifest(
-      location_, scoped_ptr<base::DictionaryValue>(value_->DeepCopy()));
-  manifest->set_extension_id(extension_id_);
-  return manifest;
-}
-
-bool Manifest::Equals(const Manifest* other) const {
-  return other && value_->Equals(other->value());
-}
-
-int Manifest::GetManifestVersion() const {
-  // Platform apps were launched after manifest version 2 was the preferred
-  // version, so they default to that.
-  int manifest_version = type_ == TYPE_PLATFORM_APP ? 2 : 1;
-  value_->GetInteger(keys::kManifestVersion, &manifest_version);
-  return manifest_version;
-}
-
-bool Manifest::CanAccessPath(const std::string& path) const {
-  std::vector<std::string> components;
-  base::SplitString(path, '.', &components);
-  std::string key;
-  for (size_t i = 0; i < components.size(); ++i) {
-    key += components[i];
-    if (!CanAccessKey(key))
-      return false;
-    key += '.';
-  }
-  return true;
-}
-
-bool Manifest::CanAccessKey(const std::string& key) const {
-  Feature* feature = FeatureProvider::GetByName("manifest")->GetFeature(key);
-  if (!feature)
-    return true;
-
-  return feature->IsAvailableToManifest(
-      extension_id_, type_, Feature::ConvertLocation(location_),
-      GetManifestVersion()).is_available();
-}
-
-}  // namespace extensions
diff --git a/chrome/common/extensions/manifest.h b/chrome/common/extensions/manifest.h
deleted file mode 100644
index e43443d..0000000
--- a/chrome/common/extensions/manifest.h
+++ /dev/null
@@ -1,177 +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_MANIFEST_H_
-#define CHROME_COMMON_EXTENSIONS_MANIFEST_H_
-
-#include <map>
-#include <set>
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string16.h"
-#include "base/values.h"
-
-namespace extensions {
-struct InstallWarning;
-
-// Wraps the DictionaryValue form of extension's manifest. Enforces access to
-// properties of the manifest using ManifestFeatureProvider.
-class Manifest {
- public:
-  // What an extension was loaded from.
-  // NOTE: These values are stored as integers in the preferences and used
-  // in histograms so don't remove or reorder existing items.  Just append
-  // to the end.
-  enum Location {
-    INVALID_LOCATION,
-    INTERNAL,           // A crx file from the internal Extensions directory.
-    EXTERNAL_PREF,      // A crx file from an external directory (via prefs).
-    EXTERNAL_REGISTRY,  // A crx file from an external directory (via eg the
-                        // registry on Windows).
-    UNPACKED,           // From loading an unpacked extension from the
-                        // extensions settings page.
-    COMPONENT,          // An integral component of Chrome itself, which
-                        // happens to be implemented as an extension. We don't
-                        // show these in the management UI.
-    EXTERNAL_PREF_DOWNLOAD,    // A crx file from an external directory (via
-                               // prefs), installed from an update URL.
-    EXTERNAL_POLICY_DOWNLOAD,  // A crx file from an external directory (via
-                               // admin policies), installed from an update URL.
-    COMMAND_LINE,       // --load-extension.
-
-    NUM_LOCATIONS
-  };
-
-  // Do not change the order of entries or remove entries in this list
-  // as this is used in UMA_HISTOGRAM_ENUMERATIONs about extensions.
-  enum Type {
-    TYPE_UNKNOWN = 0,
-    TYPE_EXTENSION,
-    TYPE_THEME,
-    TYPE_USER_SCRIPT,
-    TYPE_HOSTED_APP,
-    // This is marked legacy because platform apps are preferred. For
-    // backwards compatibility, we can't remove support for packaged apps
-    TYPE_LEGACY_PACKAGED_APP,
-    TYPE_PLATFORM_APP,
-    TYPE_SHARED_MODULE
-  };
-
-  // Given two install sources, return the one which should take priority
-  // over the other. If an extension is installed from two sources A and B,
-  // its install source should be set to GetHigherPriorityLocation(A, B).
-  static Location GetHigherPriorityLocation(Location loc1, Location loc2);
-
-  // Whether the |location| is external or not.
-  static inline bool IsExternalLocation(Location location) {
-    return location == EXTERNAL_PREF ||
-           location == EXTERNAL_REGISTRY ||
-           location == EXTERNAL_PREF_DOWNLOAD ||
-           location == EXTERNAL_POLICY_DOWNLOAD;
-  }
-
-  // Whether the |location| is unpacked (no CRX) or not.
-  static inline bool IsUnpackedLocation(Location location) {
-    return location == UNPACKED || location == COMMAND_LINE;
-  }
-
-  // Whether extensions with |location| are auto-updatable or not.
-  static inline bool IsAutoUpdateableLocation(Location location) {
-    // Only internal and external extensions can be autoupdated.
-    return location == INTERNAL ||
-           IsExternalLocation(location);
-  }
-
-  // Unpacked extensions start off with file access since they are a developer
-  // feature.
-  static inline bool ShouldAlwaysAllowFileAccess(Location location) {
-    return IsUnpackedLocation(location);
-  }
-
-  Manifest(Location location, scoped_ptr<base::DictionaryValue> value);
-  virtual ~Manifest();
-
-  const std::string& extension_id() const { return extension_id_; }
-  void set_extension_id(const std::string& id) { extension_id_ = id; }
-
-  Location location() const { return location_; }
-
-  // Returns false and |error| will be non-empty if the manifest is malformed.
-  // |warnings| will be populated if there are keys in the manifest that cannot
-  // be specified by the extension type.
-  bool ValidateManifest(std::string* error,
-                        std::vector<InstallWarning>* warnings) const;
-
-  // The version of this extension's manifest. We increase the manifest
-  // version when making breaking changes to the extension system. If the
-  // manifest contains no explicit manifest version, this returns the current
-  // system default.
-  int GetManifestVersion() const;
-
-  // Returns the manifest type.
-  Type type() const { return type_; }
-
-  bool is_theme() const { return type_ == TYPE_THEME; }
-  bool is_app() const {
-    return is_legacy_packaged_app() || is_hosted_app() || is_platform_app();
-  }
-  bool is_platform_app() const { return type_ == TYPE_PLATFORM_APP; }
-  bool is_hosted_app() const { return type_ == TYPE_HOSTED_APP; }
-  bool is_legacy_packaged_app() const {
-    return type_ == TYPE_LEGACY_PACKAGED_APP;
-  }
-  bool is_extension() const { return type_ == TYPE_EXTENSION; }
-  bool is_shared_module() const { return type_ == TYPE_SHARED_MODULE; }
-
-  // These access the wrapped manifest value, returning false when the property
-  // does not exist or if the manifest type can't access it.
-  bool HasKey(const std::string& key) const;
-  bool HasPath(const std::string& path) const;
-  bool Get(const std::string& path, const base::Value** out_value) const;
-  bool GetBoolean(const std::string& path, bool* out_value) const;
-  bool GetInteger(const std::string& path, int* out_value) const;
-  bool GetString(const std::string& path, std::string* out_value) const;
-  bool GetString(const std::string& path, string16* out_value) const;
-  bool GetDictionary(const std::string& path,
-                     const base::DictionaryValue** out_value) const;
-  bool GetList(const std::string& path,
-               const base::ListValue** out_value) const;
-
-  // Returns a new Manifest equal to this one, passing ownership to
-  // the caller.
-  Manifest* DeepCopy() const;
-
-  // Returns true if this equals the |other| manifest.
-  bool Equals(const Manifest* other) const;
-
-  // Gets the underlying DictionaryValue representing the manifest.
-  // Note: only use this when you KNOW you don't need the validation.
-  const base::DictionaryValue* value() const { return value_.get(); }
-
- private:
-  // Returns true if the extension can specify the given |path|.
-  bool CanAccessPath(const std::string& path) const;
-  bool CanAccessKey(const std::string& key) const;
-
-  // A persistent, globally unique ID. An extension's ID is used in things
-  // like directory structures and URLs, and is expected to not change across
-  // versions. It is generated as a SHA-256 hash of the extension's public
-  // key, or as a hash of the path in the case of unpacked extensions.
-  std::string extension_id_;
-
-  // The location the extension was loaded from.
-  Location location_;
-
-  // The underlying dictionary representation of the manifest.
-  scoped_ptr<base::DictionaryValue> value_;
-
-  Type type_;
-
-  DISALLOW_COPY_AND_ASSIGN(Manifest);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_COMMON_EXTENSIONS_MANIFEST_H_
diff --git a/chrome/common/extensions/manifest_handler.h b/chrome/common/extensions/manifest_handler.h
index b4e9e93..42f989b 100644
--- a/chrome/common/extensions/manifest_handler.h
+++ b/chrome/common/extensions/manifest_handler.h
@@ -12,7 +12,7 @@
 #include "base/lazy_instance.h"
 #include "base/memory/linked_ptr.h"
 #include "base/strings/string16.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 class Extension;
diff --git a/chrome/common/extensions/manifest_handlers/app_isolation_info.cc b/chrome/common/extensions/manifest_handlers/app_isolation_info.cc
index 58bf371..a971db4 100644
--- a/chrome/common/extensions/manifest_handlers/app_isolation_info.cc
+++ b/chrome/common/extensions/manifest_handlers/app_isolation_info.cc
@@ -14,10 +14,10 @@
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "extensions/common/error_utils.h"
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 AppIsolationInfo::AppIsolationInfo(bool isolated_storage)
     : has_isolated_storage(isolated_storage) {
 }
diff --git a/chrome/common/extensions/manifest_handlers/app_isolation_info.h b/chrome/common/extensions/manifest_handlers/app_isolation_info.h
index 7ceb94e..e2f14f7 100644
--- a/chrome/common/extensions/manifest_handlers/app_isolation_info.h
+++ b/chrome/common/extensions/manifest_handlers/app_isolation_info.h
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_handlers/app_launch_info.cc b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
index 813f2b6..4b9ee12 100644
--- a/chrome/common/extensions/manifest_handlers/app_launch_info.cc
+++ b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
@@ -14,7 +14,7 @@
 #include "chrome/common/url_constants.h"
 #include "extensions/common/error_utils.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace values = extension_manifest_values;
 namespace errors = extension_manifest_errors;
 
diff --git a/chrome/common/extensions/manifest_handlers/app_launch_info.h b/chrome/common/extensions/manifest_handlers/app_launch_info.h
index 48502da..e1a31e6 100644
--- a/chrome/common/extensions/manifest_handlers/app_launch_info.h
+++ b/chrome/common/extensions/manifest_handlers/app_launch_info.h
@@ -10,8 +10,8 @@
 
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
+#include "extensions/common/manifest.h"
 #include "url/gurl.h"
 
 namespace extensions {
diff --git a/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc b/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc
index 8ff7eba..7f3377d 100644
--- a/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc
@@ -25,7 +25,7 @@
 
 namespace extensions {
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace values = extension_manifest_values;
 namespace errors = extension_manifest_errors;
 
diff --git a/chrome/common/extensions/manifest_handlers/externally_connectable.cc b/chrome/common/extensions/manifest_handlers/externally_connectable.cc
index 60f928c..0b55d74 100644
--- a/chrome/common/extensions/manifest_handlers/externally_connectable.cc
+++ b/chrome/common/extensions/manifest_handlers/externally_connectable.cc
@@ -9,10 +9,10 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/api/manifest_types.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/permissions/api_permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
 #include "extensions/common/url_pattern.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "url/gurl.h"
@@ -22,7 +22,6 @@
 namespace extensions {
 
 namespace externally_connectable_errors {
-const char kErrorInvalid[] = "Invalid value for 'externally_connectable'";
 const char kErrorInvalidMatchPattern[] = "Invalid match pattern '*'";
 const char kErrorInvalidId[] = "Invalid ID '*'";
 const char kErrorNothingSpecified[] =
@@ -35,7 +34,7 @@
     "Wildcard domain patterns such as \"*\" are not allowed";
 }  // namespace externally_connectable_errors
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = externally_connectable_errors;
 using api::manifest_types::ExternallyConnectable;
 
@@ -94,11 +93,9 @@
     std::vector<InstallWarning>* install_warnings,
     string16* error) {
   scoped_ptr<ExternallyConnectable> externally_connectable =
-      ExternallyConnectable::FromValue(value);
-  if (!externally_connectable) {
-    *error = UTF8ToUTF16(errors::kErrorInvalid);
+      ExternallyConnectable::FromValue(value, error);
+  if (!externally_connectable)
     return scoped_ptr<ExternallyConnectableInfo>();
-  }
 
   URLPatternSet matches;
 
@@ -118,9 +115,11 @@
       // Wildcard hosts are not allowed.
       if (pattern.host().empty()) {
         // Warning not error for forwards compatibility.
-        install_warnings->push_back(
-            InstallWarning::Text(ErrorUtils::FormatErrorMessage(
-                errors::kErrorWildcardHostsNotAllowed, *it)));
+        install_warnings->push_back(InstallWarning(
+            ErrorUtils::FormatErrorMessage(
+                errors::kErrorWildcardHostsNotAllowed, *it),
+            keys::kExternallyConnectable,
+            *it));
         continue;
       }
 
@@ -146,11 +145,13 @@
       // are not allowed. However just "appspot.com" is ok.
       if (registry_length == 0 && pattern.match_subdomains()) {
         // Warning not error for forwards compatibility.
-        install_warnings->push_back(InstallWarning::Text(
+        install_warnings->push_back(InstallWarning(
             ErrorUtils::FormatErrorMessage(
                 errors::kErrorTopLevelDomainsNotAllowed,
                 pattern.host().c_str(),
-                *it)));
+                *it),
+            keys::kExternallyConnectable,
+            *it));
         continue;
       }
 
@@ -179,8 +180,9 @@
 
   if (!externally_connectable->matches &&
       !externally_connectable->ids) {
-    install_warnings->push_back(InstallWarning::Text(
-        errors::kErrorNothingSpecified));
+    install_warnings->push_back(InstallWarning(
+        errors::kErrorNothingSpecified,
+        keys::kExternallyConnectable));
   }
 
   return make_scoped_ptr(
diff --git a/chrome/common/extensions/manifest_handlers/externally_connectable_unittest.cc b/chrome/common/extensions/manifest_handlers/externally_connectable_unittest.cc
index 78857c2..c215f2b 100644
--- a/chrome/common/extensions/manifest_handlers/externally_connectable_unittest.cc
+++ b/chrome/common/extensions/manifest_handlers/externally_connectable_unittest.cc
@@ -4,11 +4,11 @@
 
 #include <algorithm>
 
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/features/feature_channel.h"
 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -26,7 +26,7 @@
   ExternallyConnectableInfo* GetExternallyConnectableInfo(
       scoped_refptr<Extension> extension) {
     return static_cast<ExternallyConnectableInfo*>(extension->GetManifestData(
-        extension_manifest_keys::kExternallyConnectable));
+        manifest_keys::kExternallyConnectable));
   }
 
  private:
@@ -200,7 +200,7 @@
 
 TEST_F(ExternallyConnectableTest, ErrorWrongFormat) {
   LoadAndExpectError("externally_connectable_error_wrong_format.json",
-                     errors::kErrorInvalid);
+                     "expected dictionary, got string");
 }
 
 TEST_F(ExternallyConnectableTest, ErrorBadID) {
diff --git a/chrome/common/extensions/manifest_handlers/icons_handler.cc b/chrome/common/extensions/manifest_handlers/icons_handler.cc
index 3105937..a374249 100644
--- a/chrome/common/extensions/manifest_handlers/icons_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/icons_handler.cc
@@ -20,10 +20,10 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/size.h"
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 static base::LazyInstance<ExtensionIconSet> g_empty_icon_set =
     LAZY_INSTANCE_INITIALIZER;
 
diff --git a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.cc b/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.cc
index 3a77648..df2847c 100644
--- a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.cc
+++ b/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.cc
@@ -11,10 +11,10 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 KioskEnabledInfo::KioskEnabledInfo(bool is_kiosk_enabled)
     : kiosk_enabled(is_kiosk_enabled) {
 }
diff --git a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h b/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h
index 2aac01f..3c61b08 100644
--- a/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h
+++ b/chrome/common/extensions/manifest_handlers/kiosk_enabled_info.h
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc b/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc
index 4d6ca08..8a125df 100644
--- a/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc
+++ b/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc
@@ -13,7 +13,7 @@
 #include "grit/chromium_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
diff --git a/chrome/common/extensions/manifest_handlers/nacl_modules_handler.cc b/chrome/common/extensions/manifest_handlers/nacl_modules_handler.cc
index bf66bd1..78318e9 100644
--- a/chrome/common/extensions/manifest_handlers/nacl_modules_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/nacl_modules_handler.cc
@@ -14,7 +14,7 @@
 
 namespace extensions {
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/manifest_handlers/offline_enabled_info.cc b/chrome/common/extensions/manifest_handlers/offline_enabled_info.cc
index 3f32e52..4cc8ceb 100644
--- a/chrome/common/extensions/manifest_handlers/offline_enabled_info.cc
+++ b/chrome/common/extensions/manifest_handlers/offline_enabled_info.cc
@@ -11,10 +11,10 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 
-namespace keys = extension_manifest_keys;
-
 namespace extensions {
 
+namespace keys = manifest_keys;
+
 OfflineEnabledInfo::OfflineEnabledInfo(bool is_offline_enabled)
     : offline_enabled(is_offline_enabled) {
 }
diff --git a/chrome/common/extensions/manifest_handlers/offline_enabled_info.h b/chrome/common/extensions/manifest_handlers/offline_enabled_info.h
index ac50da8..a429a8c 100644
--- a/chrome/common/extensions/manifest_handlers/offline_enabled_info.h
+++ b/chrome/common/extensions/manifest_handlers/offline_enabled_info.h
@@ -9,8 +9,8 @@
 #include <vector>
 
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_handlers/requirements_handler.cc b/chrome/common/extensions/manifest_handlers/requirements_handler.cc
index d0b0ad0..e250d5a 100644
--- a/chrome/common/extensions/manifest_handlers/requirements_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/requirements_handler.cc
@@ -11,7 +11,7 @@
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "extensions/common/error_utils.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
diff --git a/chrome/common/extensions/manifest_handlers/requirements_handler.h b/chrome/common/extensions/manifest_handlers/requirements_handler.h
index da2bc8f..f99c1ac 100644
--- a/chrome/common/extensions/manifest_handlers/requirements_handler.h
+++ b/chrome/common/extensions/manifest_handlers/requirements_handler.h
@@ -9,8 +9,8 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_handler.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_handlers/sandboxed_page_info.cc b/chrome/common/extensions/manifest_handlers/sandboxed_page_info.cc
index 9d2d7b1..c6a3ee1 100644
--- a/chrome/common/extensions/manifest_handlers/sandboxed_page_info.cc
+++ b/chrome/common/extensions/manifest_handlers/sandboxed_page_info.cc
@@ -18,7 +18,7 @@
 
 namespace {
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 const char kDefaultSandboxedPageContentSecurityPolicy[] =
diff --git a/chrome/common/extensions/manifest_handlers/shared_module_info.cc b/chrome/common/extensions/manifest_handlers/shared_module_info.cc
index dd906b4..6bd8b03 100644
--- a/chrome/common/extensions/manifest_handlers/shared_module_info.cc
+++ b/chrome/common/extensions/manifest_handlers/shared_module_info.cc
@@ -15,7 +15,7 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace values = extension_manifest_values;
 namespace errors = extension_manifest_errors;
 
diff --git a/chrome/common/extensions/manifest_handlers/theme_handler.cc b/chrome/common/extensions/manifest_handlers/theme_handler.cc
index f5c8799..21dfb99 100644
--- a/chrome/common/extensions/manifest_handlers/theme_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/theme_handler.cc
@@ -9,13 +9,13 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/manifest_tests/extension_manifest_test.h b/chrome/common/extensions/manifest_tests/extension_manifest_test.h
index 7694e15..4555f5b 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifest_test.h
+++ b/chrome/common/extensions/manifest_tests/extension_manifest_test.h
@@ -11,7 +11,7 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/features/feature_channel.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class ExtensionManifestTest : public testing::Test {
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc
index d2d4fc7..7eefac2 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc
@@ -16,7 +16,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc
index 27d7918..f09ff58 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc
@@ -5,9 +5,9 @@
 #include "base/command_line.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc
index be0f0d3..ac672f2 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc
@@ -7,7 +7,7 @@
 #include "base/command_line.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
index ed579af..92bdf4b 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
@@ -18,7 +18,7 @@
 #endif
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
index 9a63f61..2393484 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
@@ -12,7 +12,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 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 3d361b0..b4e5f67 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/common/extensions/incognito_handler.h"
 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
+#include "extensions/common/error_utils.h"
 #include "extensions/common/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -36,9 +37,10 @@
 
   Testcase error_testcases[] = {
     Testcase("init_invalid_platform_app_2.json",
-        errors::kBackgroundRequiredForPlatformApps),
+             errors::kBackgroundRequiredForPlatformApps),
     Testcase("init_invalid_platform_app_3.json",
-        errors::kPlatformAppNeedsManifestVersion2),
+             ErrorUtils::FormatErrorMessage(
+                 errors::kInvalidManifestVersionOld, "2", "apps")),
   };
   RunTestcases(error_testcases, arraysize(error_testcases), EXPECT_TYPE_ERROR);
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc
index e0aa833..fc60bac 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_storage_unittest.cc
@@ -4,10 +4,10 @@
 
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 TEST_F(ExtensionManifestTest, StorageAPIManifestVersionAvailability) {
   base::DictionaryValue base_manifest;
diff --git a/chrome/common/extensions/manifest_unittest.cc b/chrome/common/extensions/manifest_unittest.cc
index 3f61c50..eb554a6 100644
--- a/chrome/common/extensions/manifest_unittest.cc
+++ b/chrome/common/extensions/manifest_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 #include <algorithm>
 #include <set>
@@ -12,14 +12,14 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/common/extensions/features/simple_feature.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/features/feature.h"
 #include "extensions/common/install_warning.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace extensions {
 
diff --git a/chrome/common/extensions/manifest_url_handler.cc b/chrome/common/extensions/manifest_url_handler.cc
index e1fe5ff..eb51201 100644
--- a/chrome/common/extensions/manifest_url_handler.cc
+++ b/chrome/common/extensions/manifest_url_handler.cc
@@ -14,12 +14,12 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
 #include "chrome/common/extensions/permissions/api_permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/url_constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -27,7 +27,7 @@
 #include "ui/keyboard/keyboard_constants.h"
 #endif
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
@@ -142,8 +142,7 @@
   }
   manifest_url->url_ = GURL(homepage_url_str);
   if (!manifest_url->url_.is_valid() ||
-      (!manifest_url->url_.SchemeIs("http") &&
-       !manifest_url->url_.SchemeIs("https"))) {
+      !manifest_url->url_.SchemeIsHTTPOrHTTPS()) {
     *error = ErrorUtils::FormatErrorMessageUTF16(
         errors::kInvalidHomepageURL, homepage_url_str);
     return false;
@@ -206,7 +205,7 @@
     // hosted apps require an absolute URL.
     GURL options_url(options_str);
     if (!options_url.is_valid() ||
-        !(options_url.SchemeIs("http") || options_url.SchemeIs("https"))) {
+        !options_url.SchemeIsHTTPOrHTTPS()) {
       *error = ASCIIToUTF16(errors::kInvalidOptionsPageInHostedApp);
       return false;
     }
@@ -287,7 +286,7 @@
                    !(extension->location() == Manifest::COMPONENT &&
                      page == chrome::kChromeUIFileManagerHost));
 #endif
-#if defined(USE_AURA)
+#if defined(OS_CHROMEOS)
     is_override = (is_override && page != keyboard::kKeyboardWebUIHost);
 #endif
 
diff --git a/chrome/common/extensions/mime_types_handler.cc b/chrome/common/extensions/mime_types_handler.cc
index c85aaed..6c77046 100644
--- a/chrome/common/extensions/mime_types_handler.cc
+++ b/chrome/common/extensions/mime_types_handler.cc
@@ -11,14 +11,14 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/url_pattern.h"
 #include "url/gurl.h"
 #include "url/url_util.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index 980be54..a92cab9 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -64,6 +64,7 @@
     kDeclarative,
     kDeclarativeContent,
     kDeclarativeWebRequest,
+    kDesktopCapture,
     kDeveloperPrivate,
     kDevtools,
     kDownloads,
@@ -107,14 +108,16 @@
     kPower,
     kPreferencesPrivate,
     kPrivacy,
+    kProcesses,
     kProxy,
     kPushMessaging,
     kRecoveryPrivate,
     kRtcPrivate,
     kScreensaver,
     kSerial,
-    kSessionRestore,
+    kSessions,
     kSocket,
+    kSocketsUdp,
     kStorage,
     kStreamsPrivate,
     kSyncFileSystem,
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 2850d13..53cf6b2 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -46,7 +46,14 @@
       PermissionMessage::kClipboard },
     { APIPermission::kClipboardWrite, "clipboardWrite" },
     { APIPermission::kDeclarativeContent, "declarativeContent" },
-    { APIPermission::kDeclarativeWebRequest, "declarativeWebRequest" },
+    { APIPermission::kDeclarativeWebRequest, "declarativeWebRequest",
+      APIPermissionInfo::kFlagNone,
+      IDS_EXTENSION_PROMPT_WARNING_DECLARATIVE_WEB_REQUEST,
+      PermissionMessage::kDeclarativeWebRequest },
+    { APIPermission::kDesktopCapture, "desktopCapture",
+      APIPermissionInfo::kFlagNone,
+      IDS_EXTENSION_PROMPT_WARNING_DESKTOP_CAPTURE,
+      PermissionMessage::kDesktopCapture },
     { APIPermission::kDownloads, "downloads", APIPermissionInfo::kFlagNone,
       IDS_EXTENSION_PROMPT_WARNING_DOWNLOADS,
       PermissionMessage::kDownloads },
@@ -116,7 +123,10 @@
     { APIPermission::kPrivacy, "privacy", APIPermissionInfo::kFlagNone,
       IDS_EXTENSION_PROMPT_WARNING_PRIVACY,
       PermissionMessage::kPrivacy },
-    { APIPermission::kSessionRestore, "sessionRestore" },
+    { APIPermission::kProcesses, "processes", APIPermissionInfo::kFlagNone,
+      IDS_EXTENSION_PROMPT_WARNING_TABS,
+      PermissionMessage::kTabs },
+    { APIPermission::kSessions, "sessions" },
     { APIPermission::kStorage, "storage" },
     { APIPermission::kSyncFileSystem, "syncFileSystem",
       APIPermissionInfo::kFlagNone,
@@ -246,6 +256,7 @@
     { APIPermission::kSocket, "socket",
       APIPermissionInfo::kFlagCannotBeOptional, 0,
       PermissionMessage::kNone, &CreateAPIPermission<SocketPermission> },
+    { APIPermission::kSocketsUdp, "sockets.udp" },
     { APIPermission::kAppCurrentWindowInternal, "app.currentWindowInternal" },
     { APIPermission::kAppRuntime, "app.runtime" },
     { APIPermission::kAppWindow, "app.window" },
diff --git a/chrome/common/extensions/permissions/permission_message.cc b/chrome/common/extensions/permissions/permission_message.cc
index 576cd1d..7840b57 100644
--- a/chrome/common/extensions/permissions/permission_message.cc
+++ b/chrome/common/extensions/permissions/permission_message.cc
@@ -18,7 +18,7 @@
 PermissionMessage PermissionMessage::CreateFromHostList(
     const std::set<std::string>& hosts) {
   std::vector<std::string> host_list(hosts.begin(), hosts.end());
-  DCHECK_GT(host_list.size(), 0UL);
+  DCHECK(host_list.size());
   ID message_id;
   string16 message;
   string16 details;
diff --git a/chrome/common/extensions/permissions/permission_message.h b/chrome/common/extensions/permissions/permission_message.h
index 518c393..dd35286 100644
--- a/chrome/common/extensions/permissions/permission_message.h
+++ b/chrome/common/extensions/permissions/permission_message.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/basictypes.h"
 #include "base/strings/string16.h"
 
 namespace extensions {
@@ -30,6 +31,7 @@
     kTabs,
     kManagement,
     kDebugger,
+    kDesktopCapture,
     kHosts1,
     kHosts2,
     kHosts3,
@@ -67,8 +69,11 @@
     kBluetoothDevices,
     kDownloadsOpen,
     kNetworkingPrivate,
+    kDeclarativeWebRequest,
     kEnumBoundary,
   };
+  COMPILE_ASSERT(PermissionMessage::kNone > PermissionMessage::kUnknown,
+                 kNone_not_greater_than_kUnknown);
 
   // Creates the corresponding permission message for a list of hosts. This is
   // simply a convenience method around the constructor, since the messages
diff --git a/chrome/common/extensions/permissions/permission_set.cc b/chrome/common/extensions/permissions/permission_set.cc
index 1ad5646..446c808 100644
--- a/chrome/common/extensions/permissions/permission_set.cc
+++ b/chrome/common/extensions/permissions/permission_set.cc
@@ -263,6 +263,14 @@
       }
     }
 
+    // The warning message for declarativeWebRequest permissions speaks about
+    // blocking parts of pages, which is a subset of what the "<all_urls>"
+    // access allows. Therefore we display only the "<all_urls>" warning message
+    // if both permissions are required.
+    if (id == PermissionMessage::kDeclarativeWebRequest &&
+        HasEffectiveAccessToAllHosts())
+      continue;
+
     messages.push_back(i->message());
   }
 
@@ -468,8 +476,6 @@
   std::set<PermissionMessage> messages;
   for (APIPermissionSet::const_iterator permission_it = apis_.begin();
        permission_it != apis_.end(); ++permission_it) {
-    DCHECK_GT(PermissionMessage::kNone,
-              PermissionMessage::kUnknown);
     if (permission_it->HasMessages()) {
       PermissionMessages new_messages = permission_it->GetMessages();
       messages.insert(new_messages.begin(), new_messages.end());
@@ -516,6 +522,14 @@
   PermissionMsgSet delta_warnings =
       base::STLSetDifference<PermissionMsgSet>(new_warnings, current_warnings);
 
+  // A special hack: the DWR permission is weaker than all hosts permission.
+  if (delta_warnings.size() == 1u &&
+      delta_warnings.begin()->id() ==
+          PermissionMessage::kDeclarativeWebRequest &&
+      HasEffectiveAccessToAllHosts()) {
+    return false;
+  }
+
   // We have less privileges if there are additional warnings present.
   return !delta_warnings.empty();
 }
@@ -545,11 +559,9 @@
   // considered an elevation, even though it is not (http://crbug.com/65337).
   std::set<std::string> new_hosts_set(GetDistinctHosts(new_list, false, false));
   std::set<std::string> old_hosts_set(GetDistinctHosts(old_list, false, false));
-  std::set<std::string> new_hosts_only;
-
-  std::set_difference(new_hosts_set.begin(), new_hosts_set.end(),
-                      old_hosts_set.begin(), old_hosts_set.end(),
-                      std::inserter(new_hosts_only, new_hosts_only.begin()));
+  std::set<std::string> new_hosts_only =
+      base::STLSetDifference<std::set<std::string> >(new_hosts_set,
+                                                     old_hosts_set);
 
   return !new_hosts_only.empty();
 }
diff --git a/chrome/common/extensions/permissions/permission_set.h b/chrome/common/extensions/permissions/permission_set.h
index 10e4d86..d2bdede 100644
--- a/chrome/common/extensions/permissions/permission_set.h
+++ b/chrome/common/extensions/permissions/permission_set.h
@@ -14,10 +14,10 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "base/strings/string16.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
 #include "chrome/common/extensions/permissions/api_permission_set.h"
 #include "chrome/common/extensions/permissions/permission_message.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/url_pattern_set.h"
 
 namespace extensions {
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 637fb54..977838c 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -653,7 +653,7 @@
   skip.insert(APIPermission::kPower);
   skip.insert(APIPermission::kPushMessaging);
   skip.insert(APIPermission::kScreensaver);
-  skip.insert(APIPermission::kSessionRestore);
+  skip.insert(APIPermission::kSessions);
   skip.insert(APIPermission::kStorage);
   skip.insert(APIPermission::kSystemCpu);
   skip.insert(APIPermission::kSystemDisplay);
@@ -674,7 +674,6 @@
 
   // These are warned as part of host permission checks.
   skip.insert(APIPermission::kDeclarativeContent);
-  skip.insert(APIPermission::kDeclarativeWebRequest);
   skip.insert(APIPermission::kPageCapture);
   skip.insert(APIPermission::kProxy);
   skip.insert(APIPermission::kTabCapture);
@@ -734,6 +733,7 @@
   skip.insert(APIPermission::kFileSystem);
   skip.insert(APIPermission::kFileSystemRetainEntries);
   skip.insert(APIPermission::kSocket);
+  skip.insert(APIPermission::kSocketsUdp);
   skip.insert(APIPermission::kUsbDevice);
 
   PermissionsInfo* info = PermissionsInfo::GetInstance();
@@ -821,6 +821,36 @@
   EXPECT_TRUE(Contains(warnings, "Use your camera"));
 }
 
+TEST(PermissionsTest, GetWarningMessages_DeclarativeWebRequest) {
+  // Test that if the declarativeWebRequest permission is present
+  // in combination with all hosts permission, then only the warning
+  // for host permissions is shown, because that covers the use of
+  // declarativeWebRequest.
+
+  // Until Declarative Web Request is in stable, let's make sure it is enabled
+  // on the current channel.
+  ScopedCurrentChannel sc(chrome::VersionInfo::CHANNEL_CANARY);
+
+  // First verify that declarativeWebRequest produces a message when host
+  // permissions do not cover all hosts.
+  scoped_refptr<Extension> extension =
+      LoadManifest("permissions", "web_request_com_host_permissions.json");
+  const PermissionSet* set = extension->GetActivePermissions().get();
+  std::vector<string16> warnings =
+      set->GetWarningMessages(extension->GetType());
+  EXPECT_TRUE(Contains(warnings, "Block parts of web pages"));
+  EXPECT_FALSE(Contains(warnings, "Access your data on all websites"));
+
+  // Now verify that declarativeWebRequest does not produce a message when host
+  // permissions do cover all hosts.
+  extension =
+      LoadManifest("permissions", "web_request_all_host_permissions.json");
+  set = extension->GetActivePermissions().get();
+  warnings = set->GetWarningMessages(extension->GetType());
+  EXPECT_FALSE(Contains(warnings, "Block parts of web pages"));
+  EXPECT_TRUE(Contains(warnings, "Access your data on all websites"));
+}
+
 TEST(PermissionsTest, GetWarningMessages_Serial) {
   scoped_refptr<Extension> extension =
       LoadManifest("permissions", "serial.json");
@@ -1332,4 +1362,18 @@
   permissions->GetPermissionMessages(Manifest::TYPE_EXTENSION);
 }
 
+TEST(PermissionsTest, HasLessPrivilegesThan_DeclarativeWebRequest) {
+  scoped_refptr<Extension> extension(
+      LoadManifest("permissions", "permissions_all_urls.json"));
+  scoped_refptr<const PermissionSet> permissions(
+      extension->GetActivePermissions());
+
+  scoped_refptr<Extension> extension_dwr(
+      LoadManifest("permissions", "web_request_all_host_permissions.json"));
+  scoped_refptr<const PermissionSet> permissions_dwr(
+      extension_dwr->GetActivePermissions());
+
+  EXPECT_FALSE(permissions->HasLessPrivilegesThan(permissions_dwr.get(),
+                                                  extension->GetType()));
+}
 }  // namespace extensions
diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc
index 8b5796e..139e4dc 100644
--- a/chrome/common/extensions/permissions/permissions_data.cc
+++ b/chrome/common/extensions/permissions/permissions_data.cc
@@ -14,8 +14,6 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/features/base_feature_provider.h"
-#include "chrome/common/extensions/features/feature.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/permissions/api_permission_set.h"
 #include "chrome/common/extensions/permissions/chrome_scheme_hosts.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
@@ -23,12 +21,14 @@
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/manifest.h"
 #include "extensions/common/switches.h"
 #include "extensions/common/url_pattern_set.h"
 #include "extensions/common/user_script.h"
 #include "url/gurl.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
@@ -157,8 +157,8 @@
       // Don't fail, but warn the developer that the manifest contains
       // unrecognized permissions. This may happen legitimately if the
       // extensions requests platform- or channel-specific permissions.
-      extension->AddInstallWarning(InstallWarning(InstallWarning::FORMAT_TEXT,
-                                                  availability.message()));
+      extension->AddInstallWarning(InstallWarning(availability.message(),
+                                                  feature->name()));
       to_remove.push_back(iter->id());
       continue;
     }
@@ -231,10 +231,11 @@
     // It's probably an unknown API permission. Do not throw an error so
     // extensions can retain backwards compatability (http://crbug.com/42742).
     extension->AddInstallWarning(InstallWarning(
-        InstallWarning::FORMAT_TEXT,
-        base::StringPrintf(
+       base::StringPrintf(
             "Permission '%s' is unknown or URL pattern is malformed.",
-            permission_str.c_str())));
+            permission_str.c_str()),
+        key,
+        permission_str));
   }
 
   return true;
diff --git a/chrome/common/extensions/sync_helper.cc b/chrome/common/extensions/sync_helper.cc
index c8b8dc4..e09e627 100644
--- a/chrome/common/extensions/sync_helper.cc
+++ b/chrome/common/extensions/sync_helper.cc
@@ -8,8 +8,8 @@
 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 namespace sync_helper {
diff --git a/chrome/common/extensions/sync_type_unittest.cc b/chrome/common/extensions/sync_type_unittest.cc
index 22678e9..3265196 100644
--- a/chrome/common/extensions/sync_type_unittest.cc
+++ b/chrome/common/extensions/sync_type_unittest.cc
@@ -6,13 +6,13 @@
 #include "chrome/common/extensions/api/plugins/plugins_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/sync_helper.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace extensions {
diff --git a/chrome/common/extensions/web_accessible_resources_handler.cc b/chrome/common/extensions/web_accessible_resources_handler.cc
index 80a34cd..8f1a0c1 100644
--- a/chrome/common/extensions/web_accessible_resources_handler.cc
+++ b/chrome/common/extensions/web_accessible_resources_handler.cc
@@ -9,12 +9,12 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/manifest.h"
 
 namespace extensions {
 
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 namespace errors = extension_manifest_errors;
 
 namespace {
diff --git a/chrome/common/extensions_api_resources.grd b/chrome/common/extensions_api_resources.grd
index 4530c23..f27310c 100644
--- a/chrome/common/extensions_api_resources.grd
+++ b/chrome/common/extensions_api_resources.grd
@@ -17,7 +17,6 @@
       <include name="IDR_EXTENSION_API_JSON_DECLARATIVE_WEBREQUEST" file="extensions\api\declarative_web_request.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_ECHOPRIVATE" file="extensions\api\echo_private.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD" file="extensions\api\experimental_input_virtual_keyboard.json" type="BINDATA" />
-      <include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES" file="extensions\api\experimental_processes.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ" file="extensions\api\experimental_rlz.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER" file="extensions\api\file_browser_handler.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE" file="extensions\api\file_browser_private.json" type="BINDATA" />
@@ -26,6 +25,7 @@
       <include name="IDR_EXTENSION_API_JSON_PAGEACTION" file="extensions\api\page_action.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_PAGEACTIONS" file="extensions\api\page_actions.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_PRIVACY" file="extensions\api\privacy.json" type="BINDATA" />
+      <include name="IDR_EXTENSION_API_JSON_PROCESSES" file="extensions\api\processes.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_PROXY" file="extensions\api\proxy.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_RUNTIME" file="extensions\api\runtime.json" type="BINDATA" />
       <include name="IDR_EXTENSION_API_JSON_SCRIPTBADGE" file="extensions\api\script_badge.json" type="BINDATA" />
diff --git a/chrome/common/json_schema/json_schema_constants.cc b/chrome/common/json_schema/json_schema_constants.cc
deleted file mode 100644
index bd341a9..0000000
--- a/chrome/common/json_schema/json_schema_constants.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 "chrome/common/json_schema/json_schema_constants.h"
-
-namespace json_schema_constants {
-
-const char kAdditionalProperties[] = "additionalProperties";
-const char kAny[] = "any";
-const char kArray[] = "array";
-const char kBoolean[] = "boolean";
-const char kChoices[] = "choices";
-const char kDescription[] = "description";
-const char kEnum[] = "enum";
-const char kId[] = "id";
-const char kInteger[] = "integer";
-const char kItems[] = "items";
-const char kMaximum[] = "maximum";
-const char kMaxItems[] = "maxItems";
-const char kMaxLength[] = "maxLength";
-const char kMinimum[] = "minimum";
-const char kMinItems[] = "minItems";
-const char kMinLength[] = "minLength";
-const char kNull[] = "null";
-const char kNumber[] = "number";
-const char kObject[] = "object";
-const char kOptional[] = "optional";
-const char kPattern[] = "pattern";
-const char kPatternProperties[] = "patternProperties";
-const char kProperties[] = "properties";
-const char kRef[] = "$ref";
-const char kSchema[] = "$schema";
-const char kString[] = "string";
-const char kTitle[] = "title";
-const char kType[] = "type";
-
-}  // namespace json_schema_constants
diff --git a/chrome/common/json_schema/json_schema_constants.h b/chrome/common/json_schema/json_schema_constants.h
deleted file mode 100644
index 1ca6a94..0000000
--- a/chrome/common/json_schema/json_schema_constants.h
+++ /dev/null
@@ -1,42 +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_JSON_SCHEMA_JSON_SCHEMA_CONSTANTS_H_
-#define CHROME_COMMON_JSON_SCHEMA_JSON_SCHEMA_CONSTANTS_H_
-
-// These constants are shared by code that uses JSON schemas.
-namespace json_schema_constants {
-
-extern const char kAdditionalProperties[];
-extern const char kAny[];
-extern const char kArray[];
-extern const char kBoolean[];
-extern const char kChoices[];
-extern const char kDescription[];
-extern const char kEnum[];
-extern const char kId[];
-extern const char kInteger[];
-extern const char kItems[];
-extern const char kMaximum[];
-extern const char kMaxItems[];
-extern const char kMaxLength[];
-extern const char kMinimum[];
-extern const char kMinItems[];
-extern const char kMinLength[];
-extern const char kNull[];
-extern const char kNumber[];
-extern const char kObject[];
-extern const char kOptional[];
-extern const char kPattern[];
-extern const char kPatternProperties[];
-extern const char kProperties[];
-extern const char kRef[];
-extern const char kSchema[];
-extern const char kString[];
-extern const char kTitle[];
-extern const char kType[];
-
-}  // namespace json_schema_constants
-
-#endif  // CHROME_COMMON_JSON_SCHEMA_JSON_SCHEMA_CONSTANTS_H_
diff --git a/chrome/common/json_schema/json_schema_validator.cc b/chrome/common/json_schema/json_schema_validator.cc
deleted file mode 100644
index 576923b..0000000
--- a/chrome/common/json_schema/json_schema_validator.cc
+++ /dev/null
@@ -1,727 +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/common/json_schema/json_schema_validator.h"
-
-#include <algorithm>
-#include <cfloat>
-#include <cmath>
-
-#include "base/json/json_reader.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-#include "chrome/common/json_schema/json_schema_constants.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace schema = json_schema_constants;
-
-namespace {
-
-double GetNumberValue(const base::Value* value) {
-  double result = 0;
-  CHECK(value->GetAsDouble(&result))
-      << "Unexpected value type: " << value->GetType();
-  return result;
-}
-
-bool IsValidType(const std::string& type) {
-  static const char* kValidTypes[] = {
-    schema::kAny,
-    schema::kArray,
-    schema::kBoolean,
-    schema::kInteger,
-    schema::kNull,
-    schema::kNumber,
-    schema::kObject,
-    schema::kString,
-  };
-  const char** end = kValidTypes + arraysize(kValidTypes);
-  return std::find(kValidTypes, end, type) != end;
-}
-
-// Maps a schema attribute name to its expected type.
-struct ExpectedType {
-  const char* key;
-  base::Value::Type type;
-};
-
-// Helper for std::lower_bound.
-bool CompareToString(const ExpectedType& entry, const std::string& key) {
-  return entry.key < key;
-}
-
-bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) {
-  // This array must be sorted, so that std::lower_bound can perform a
-  // binary search.
-  static const ExpectedType kExpectedTypes[] = {
-    // Note: kRef == "$ref", kSchema == "$schema"
-    { schema::kRef,                     base::Value::TYPE_STRING      },
-    { schema::kSchema,                  base::Value::TYPE_STRING      },
-
-    { schema::kAdditionalProperties,    base::Value::TYPE_DICTIONARY  },
-    { schema::kChoices,                 base::Value::TYPE_LIST        },
-    { schema::kDescription,             base::Value::TYPE_STRING      },
-    { schema::kEnum,                    base::Value::TYPE_LIST        },
-    { schema::kId,                      base::Value::TYPE_STRING      },
-    { schema::kMaxItems,                base::Value::TYPE_INTEGER     },
-    { schema::kMaxLength,               base::Value::TYPE_INTEGER     },
-    { schema::kMaximum,                 base::Value::TYPE_DOUBLE      },
-    { schema::kMinItems,                base::Value::TYPE_INTEGER     },
-    { schema::kMinLength,               base::Value::TYPE_INTEGER     },
-    { schema::kMinimum,                 base::Value::TYPE_DOUBLE      },
-    { schema::kOptional,                base::Value::TYPE_BOOLEAN     },
-    { schema::kProperties,              base::Value::TYPE_DICTIONARY  },
-    { schema::kTitle,                   base::Value::TYPE_STRING      },
-  };
-
-  bool has_type = false;
-  const base::ListValue* list_value = NULL;
-  const base::DictionaryValue* dictionary_value = NULL;
-  std::string string_value;
-
-  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
-    // Validate the "type" attribute, which may be a string or a list.
-    if (it.key() == schema::kType) {
-      switch (it.value().GetType()) {
-        case base::Value::TYPE_STRING:
-          it.value().GetAsString(&string_value);
-          if (!IsValidType(string_value)) {
-            *error = "Invalid value for type attribute";
-            return false;
-          }
-          break;
-        case base::Value::TYPE_LIST:
-          it.value().GetAsList(&list_value);
-          for (size_t i = 0; i < list_value->GetSize(); ++i) {
-            if (!list_value->GetString(i, &string_value) ||
-                !IsValidType(string_value)) {
-              *error = "Invalid value for type attribute";
-              return false;
-            }
-          }
-          break;
-        default:
-          *error = "Invalid value for type attribute";
-          return false;
-      }
-      has_type = true;
-      continue;
-    }
-
-    // Validate the "items" attribute, which is a schema or a list of schemas.
-    if (it.key() == schema::kItems) {
-      if (it.value().GetAsDictionary(&dictionary_value)) {
-        if (!IsValidSchema(dictionary_value, error)) {
-          DCHECK(!error->empty());
-          return false;
-        }
-      } else if (it.value().GetAsList(&list_value)) {
-        for (size_t i = 0; i < list_value->GetSize(); ++i) {
-          if (!list_value->GetDictionary(i, &dictionary_value)) {
-            *error = base::StringPrintf(
-                "Invalid entry in items attribute at index %d",
-                static_cast<int>(i));
-            return false;
-          }
-          if (!IsValidSchema(dictionary_value, error)) {
-            DCHECK(!error->empty());
-            return false;
-          }
-        }
-      } else {
-        *error = "Invalid value for items attribute";
-        return false;
-      }
-      continue;
-    }
-
-    // All the other attributes have a single valid type.
-    const ExpectedType* end = kExpectedTypes + arraysize(kExpectedTypes);
-    const ExpectedType* entry = std::lower_bound(
-        kExpectedTypes, end, it.key(), CompareToString);
-    if (entry == end || entry->key != it.key()) {
-      *error = base::StringPrintf("Invalid attribute %s", it.key().c_str());
-      return false;
-    }
-    if (!it.value().IsType(entry->type)) {
-      *error = base::StringPrintf("Invalid value for %s attribute",
-                                  it.key().c_str());
-      return false;
-    }
-
-    // base::Value::TYPE_INTEGER attributes must be >= 0.
-    // This applies to "minItems", "maxItems", "minLength" and "maxLength".
-    if (it.value().IsType(base::Value::TYPE_INTEGER)) {
-      int integer_value;
-      it.value().GetAsInteger(&integer_value);
-      if (integer_value < 0) {
-        *error = base::StringPrintf("Value of %s must be >= 0, got %d",
-                                    it.key().c_str(), integer_value);
-        return false;
-      }
-    }
-
-    // Validate the "properties" attribute. Each entry maps a key to a schema.
-    if (it.key() == schema::kProperties) {
-      it.value().GetAsDictionary(&dictionary_value);
-      for (base::DictionaryValue::Iterator it(*dictionary_value);
-           !it.IsAtEnd(); it.Advance()) {
-        if (!it.value().GetAsDictionary(&dictionary_value)) {
-          *error = "Invalid value for properties attribute";
-          return false;
-        }
-        if (!IsValidSchema(dictionary_value, error)) {
-          DCHECK(!error->empty());
-          return false;
-        }
-      }
-    }
-
-    // Validate "additionalProperties" attribute, which is a schema.
-    if (it.key() == schema::kAdditionalProperties) {
-      it.value().GetAsDictionary(&dictionary_value);
-      if (!IsValidSchema(dictionary_value, error)) {
-        DCHECK(!error->empty());
-        return false;
-      }
-    }
-
-    // Validate the values contained in an "enum" attribute.
-    if (it.key() == schema::kEnum) {
-      it.value().GetAsList(&list_value);
-      for (size_t i = 0; i < list_value->GetSize(); ++i) {
-        const base::Value* value = NULL;
-        list_value->Get(i, &value);
-        switch (value->GetType()) {
-          case base::Value::TYPE_NULL:
-          case base::Value::TYPE_BOOLEAN:
-          case base::Value::TYPE_INTEGER:
-          case base::Value::TYPE_DOUBLE:
-          case base::Value::TYPE_STRING:
-            break;
-          default:
-            *error = "Invalid value in enum attribute";
-            return false;
-        }
-      }
-    }
-
-    // Validate the schemas contained in a "choices" attribute.
-    if (it.key() == schema::kChoices) {
-      it.value().GetAsList(&list_value);
-      for (size_t i = 0; i < list_value->GetSize(); ++i) {
-        if (!list_value->GetDictionary(i, &dictionary_value)) {
-          *error = "Invalid choices attribute";
-          return false;
-        }
-        if (!IsValidSchema(dictionary_value, error)) {
-          DCHECK(!error->empty());
-          return false;
-        }
-      }
-    }
-  }
-
-  if (!has_type) {
-    *error = "Schema must have a type attribute";
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace
-
-
-JSONSchemaValidator::Error::Error() {
-}
-
-JSONSchemaValidator::Error::Error(const std::string& message)
-    : path(message) {
-}
-
-JSONSchemaValidator::Error::Error(const std::string& path,
-                                  const std::string& message)
-    : path(path), message(message) {
-}
-
-
-const char JSONSchemaValidator::kUnknownTypeReference[] =
-    "Unknown schema reference: *.";
-const char JSONSchemaValidator::kInvalidChoice[] =
-    "Value does not match any valid type choices.";
-const char JSONSchemaValidator::kInvalidEnum[] =
-    "Value does not match any valid enum choices.";
-const char JSONSchemaValidator::kObjectPropertyIsRequired[] =
-    "Property is required.";
-const char JSONSchemaValidator::kUnexpectedProperty[] =
-    "Unexpected property.";
-const char JSONSchemaValidator::kArrayMinItems[] =
-    "Array must have at least * items.";
-const char JSONSchemaValidator::kArrayMaxItems[] =
-    "Array must not have more than * items.";
-const char JSONSchemaValidator::kArrayItemRequired[] =
-    "Item is required.";
-const char JSONSchemaValidator::kStringMinLength[] =
-    "String must be at least * characters long.";
-const char JSONSchemaValidator::kStringMaxLength[] =
-    "String must not be more than * characters long.";
-const char JSONSchemaValidator::kStringPattern[] =
-    "String must match the pattern: *.";
-const char JSONSchemaValidator::kNumberMinimum[] =
-    "Value must not be less than *.";
-const char JSONSchemaValidator::kNumberMaximum[] =
-    "Value must not be greater than *.";
-const char JSONSchemaValidator::kInvalidType[] =
-    "Expected '*' but got '*'.";
-const char JSONSchemaValidator::kInvalidTypeIntegerNumber[] =
-    "Expected 'integer' but got 'number', consider using Math.round().";
-
-
-// static
-std::string JSONSchemaValidator::GetJSONSchemaType(const base::Value* value) {
-  switch (value->GetType()) {
-    case base::Value::TYPE_NULL:
-      return schema::kNull;
-    case base::Value::TYPE_BOOLEAN:
-      return schema::kBoolean;
-    case base::Value::TYPE_INTEGER:
-      return schema::kInteger;
-    case base::Value::TYPE_DOUBLE: {
-      double double_value = 0;
-      value->GetAsDouble(&double_value);
-      if (std::abs(double_value) <= std::pow(2.0, DBL_MANT_DIG) &&
-          double_value == floor(double_value)) {
-        return schema::kInteger;
-      } else {
-        return schema::kNumber;
-      }
-    }
-    case base::Value::TYPE_STRING:
-      return schema::kString;
-    case base::Value::TYPE_DICTIONARY:
-      return schema::kObject;
-    case base::Value::TYPE_LIST:
-      return schema::kArray;
-    default:
-      NOTREACHED() << "Unexpected value type: " << value->GetType();
-      return std::string();
-  }
-}
-
-// static
-std::string JSONSchemaValidator::FormatErrorMessage(const std::string& format,
-                                                    const std::string& s1) {
-  std::string ret_val = format;
-  ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
-  return ret_val;
-}
-
-// static
-std::string JSONSchemaValidator::FormatErrorMessage(const std::string& format,
-                                                    const std::string& s1,
-                                                    const std::string& s2) {
-  std::string ret_val = format;
-  ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
-  ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
-  return ret_val;
-}
-
-// static
-scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema(
-    const std::string& schema,
-    std::string* error) {
-  base::JSONParserOptions options = base::JSON_PARSE_RFC;
-  scoped_ptr<base::Value> json(
-      base::JSONReader::ReadAndReturnError(schema, options, NULL, error));
-  if (!json)
-    return scoped_ptr<base::DictionaryValue>();
-  base::DictionaryValue* dict = NULL;
-  if (!json->GetAsDictionary(&dict)) {
-    *error = "Schema must be a JSON object";
-    return scoped_ptr<base::DictionaryValue>();
-  }
-  if (!::IsValidSchema(dict, error))
-    return scoped_ptr<base::DictionaryValue>();
-  ignore_result(json.release());
-  return make_scoped_ptr(dict);
-}
-
-JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema)
-    : schema_root_(schema), default_allow_additional_properties_(false) {
-}
-
-JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema,
-                                         base::ListValue* types)
-    : schema_root_(schema), default_allow_additional_properties_(false) {
-  if (!types)
-    return;
-
-  for (size_t i = 0; i < types->GetSize(); ++i) {
-    base::DictionaryValue* type = NULL;
-    CHECK(types->GetDictionary(i, &type));
-
-    std::string id;
-    CHECK(type->GetString(schema::kId, &id));
-
-    CHECK(types_.find(id) == types_.end());
-    types_[id] = type;
-  }
-}
-
-JSONSchemaValidator::~JSONSchemaValidator() {}
-
-bool JSONSchemaValidator::Validate(const base::Value* instance) {
-  errors_.clear();
-  Validate(instance, schema_root_, std::string());
-  return errors_.empty();
-}
-
-void JSONSchemaValidator::Validate(const base::Value* instance,
-                                   const base::DictionaryValue* schema,
-                                   const std::string& path) {
-  // If this schema defines itself as reference type, save it in this.types.
-  std::string id;
-  if (schema->GetString(schema::kId, &id)) {
-    TypeMap::iterator iter = types_.find(id);
-    if (iter == types_.end())
-      types_[id] = schema;
-    else
-      DCHECK(iter->second == schema);
-  }
-
-  // If the schema has a $ref property, the instance must validate against
-  // that schema. It must be present in types_ to be referenced.
-  std::string ref;
-  if (schema->GetString(schema::kRef, &ref)) {
-    TypeMap::iterator type = types_.find(ref);
-    if (type == types_.end()) {
-      errors_.push_back(
-          Error(path, FormatErrorMessage(kUnknownTypeReference, ref)));
-    } else {
-      Validate(instance, type->second, path);
-    }
-    return;
-  }
-
-  // If the schema has a choices property, the instance must validate against at
-  // least one of the items in that array.
-  const base::ListValue* choices = NULL;
-  if (schema->GetList(schema::kChoices, &choices)) {
-    ValidateChoices(instance, choices, path);
-    return;
-  }
-
-  // If the schema has an enum property, the instance must be one of those
-  // values.
-  const base::ListValue* enumeration = NULL;
-  if (schema->GetList(schema::kEnum, &enumeration)) {
-    ValidateEnum(instance, enumeration, path);
-    return;
-  }
-
-  std::string type;
-  schema->GetString(schema::kType, &type);
-  CHECK(!type.empty());
-  if (type != schema::kAny) {
-    if (!ValidateType(instance, type, path))
-      return;
-
-    // These casts are safe because of checks in ValidateType().
-    if (type == schema::kObject) {
-      ValidateObject(static_cast<const base::DictionaryValue*>(instance),
-                     schema,
-                     path);
-    } else if (type == schema::kArray) {
-      ValidateArray(static_cast<const base::ListValue*>(instance),
-                    schema, path);
-    } else if (type == schema::kString) {
-      // Intentionally NOT downcasting to StringValue*. TYPE_STRING only implies
-      // GetAsString() can safely be carried out, not that it's a StringValue.
-      ValidateString(instance, schema, path);
-    } else if (type == schema::kNumber || type == schema::kInteger) {
-      ValidateNumber(instance, schema, path);
-    } else if (type != schema::kBoolean && type != schema::kNull) {
-      NOTREACHED() << "Unexpected type: " << type;
-    }
-  }
-}
-
-void JSONSchemaValidator::ValidateChoices(const base::Value* instance,
-                                          const base::ListValue* choices,
-                                          const std::string& path) {
-  size_t original_num_errors = errors_.size();
-
-  for (size_t i = 0; i < choices->GetSize(); ++i) {
-    const base::DictionaryValue* choice = NULL;
-    CHECK(choices->GetDictionary(i, &choice));
-
-    Validate(instance, choice, path);
-    if (errors_.size() == original_num_errors)
-      return;
-
-    // We discard the error from each choice. We only want to know if any of the
-    // validations succeeded.
-    errors_.resize(original_num_errors);
-  }
-
-  // Now add a generic error that no choices matched.
-  errors_.push_back(Error(path, kInvalidChoice));
-  return;
-}
-
-void JSONSchemaValidator::ValidateEnum(const base::Value* instance,
-                                       const base::ListValue* choices,
-                                       const std::string& path) {
-  for (size_t i = 0; i < choices->GetSize(); ++i) {
-    const base::Value* choice = NULL;
-    CHECK(choices->Get(i, &choice));
-    switch (choice->GetType()) {
-      case base::Value::TYPE_NULL:
-      case base::Value::TYPE_BOOLEAN:
-      case base::Value::TYPE_STRING:
-        if (instance->Equals(choice))
-          return;
-        break;
-
-      case base::Value::TYPE_INTEGER:
-      case base::Value::TYPE_DOUBLE:
-        if (instance->IsType(base::Value::TYPE_INTEGER) ||
-            instance->IsType(base::Value::TYPE_DOUBLE)) {
-          if (GetNumberValue(choice) == GetNumberValue(instance))
-            return;
-        }
-        break;
-
-      default:
-       NOTREACHED() << "Unexpected type in enum: " << choice->GetType();
-    }
-  }
-
-  errors_.push_back(Error(path, kInvalidEnum));
-}
-
-void JSONSchemaValidator::ValidateObject(const base::DictionaryValue* instance,
-                                         const base::DictionaryValue* schema,
-                                         const std::string& path) {
-  const base::DictionaryValue* properties = NULL;
-  schema->GetDictionary(schema::kProperties, &properties);
-  if (properties) {
-    for (base::DictionaryValue::Iterator it(*properties); !it.IsAtEnd();
-         it.Advance()) {
-      std::string prop_path = path.empty() ? it.key() : (path + "." + it.key());
-      const base::DictionaryValue* prop_schema = NULL;
-      CHECK(it.value().GetAsDictionary(&prop_schema));
-
-      const base::Value* prop_value = NULL;
-      if (instance->Get(it.key(), &prop_value)) {
-        Validate(prop_value, prop_schema, prop_path);
-      } else {
-        // Properties are required unless there is an optional field set to
-        // 'true'.
-        bool is_optional = false;
-        prop_schema->GetBoolean(schema::kOptional, &is_optional);
-        if (!is_optional) {
-          errors_.push_back(Error(prop_path, kObjectPropertyIsRequired));
-        }
-      }
-    }
-  }
-
-  const base::DictionaryValue* additional_properties_schema = NULL;
-  if (SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema))
-    return;
-
-  // Validate additional properties.
-  for (base::DictionaryValue::Iterator it(*instance); !it.IsAtEnd();
-       it.Advance()) {
-    if (properties && properties->HasKey(it.key()))
-      continue;
-
-    std::string prop_path = path.empty() ? it.key() : path + "." + it.key();
-    if (!additional_properties_schema) {
-      errors_.push_back(Error(prop_path, kUnexpectedProperty));
-    } else {
-      Validate(&it.value(), additional_properties_schema, prop_path);
-    }
-  }
-}
-
-void JSONSchemaValidator::ValidateArray(const base::ListValue* instance,
-                                        const base::DictionaryValue* schema,
-                                        const std::string& path) {
-  const base::DictionaryValue* single_type = NULL;
-  size_t instance_size = instance->GetSize();
-  if (schema->GetDictionary(schema::kItems, &single_type)) {
-    int min_items = 0;
-    if (schema->GetInteger(schema::kMinItems, &min_items)) {
-      CHECK(min_items >= 0);
-      if (instance_size < static_cast<size_t>(min_items)) {
-        errors_.push_back(Error(path, FormatErrorMessage(
-            kArrayMinItems, base::IntToString(min_items))));
-      }
-    }
-
-    int max_items = 0;
-    if (schema->GetInteger(schema::kMaxItems, &max_items)) {
-      CHECK(max_items >= 0);
-      if (instance_size > static_cast<size_t>(max_items)) {
-        errors_.push_back(Error(path, FormatErrorMessage(
-            kArrayMaxItems, base::IntToString(max_items))));
-      }
-    }
-
-    // If the items property is a single schema, each item in the array must
-    // validate against that schema.
-    for (size_t i = 0; i < instance_size; ++i) {
-      const base::Value* item = NULL;
-      CHECK(instance->Get(i, &item));
-      std::string i_str = base::UintToString(i);
-      std::string item_path = path.empty() ? i_str : (path + "." + i_str);
-      Validate(item, single_type, item_path);
-    }
-
-    return;
-  }
-
-  // Otherwise, the list must be a tuple type, where each item in the list has a
-  // particular schema.
-  ValidateTuple(instance, schema, path);
-}
-
-void JSONSchemaValidator::ValidateTuple(const base::ListValue* instance,
-                                        const base::DictionaryValue* schema,
-                                        const std::string& path) {
-  const base::ListValue* tuple_type = NULL;
-  schema->GetList(schema::kItems, &tuple_type);
-  size_t tuple_size = tuple_type ? tuple_type->GetSize() : 0;
-  if (tuple_type) {
-    for (size_t i = 0; i < tuple_size; ++i) {
-      std::string i_str = base::UintToString(i);
-      std::string item_path = path.empty() ? i_str : (path + "." + i_str);
-      const base::DictionaryValue* item_schema = NULL;
-      CHECK(tuple_type->GetDictionary(i, &item_schema));
-      const base::Value* item_value = NULL;
-      instance->Get(i, &item_value);
-      if (item_value && item_value->GetType() != base::Value::TYPE_NULL) {
-        Validate(item_value, item_schema, item_path);
-      } else {
-        bool is_optional = false;
-        item_schema->GetBoolean(schema::kOptional, &is_optional);
-        if (!is_optional) {
-          errors_.push_back(Error(item_path, kArrayItemRequired));
-          return;
-        }
-      }
-    }
-  }
-
-  const base::DictionaryValue* additional_properties_schema = NULL;
-  if (SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema))
-    return;
-
-  size_t instance_size = instance->GetSize();
-  if (additional_properties_schema) {
-    // Any additional properties must validate against the additionalProperties
-    // schema.
-    for (size_t i = tuple_size; i < instance_size; ++i) {
-      std::string i_str = base::UintToString(i);
-      std::string item_path = path.empty() ? i_str : (path + "." + i_str);
-      const base::Value* item_value = NULL;
-      CHECK(instance->Get(i, &item_value));
-      Validate(item_value, additional_properties_schema, item_path);
-    }
-  } else if (instance_size > tuple_size) {
-    errors_.push_back(Error(path, FormatErrorMessage(
-        kArrayMaxItems, base::UintToString(tuple_size))));
-  }
-}
-
-void JSONSchemaValidator::ValidateString(const base::Value* instance,
-                                         const base::DictionaryValue* schema,
-                                         const std::string& path) {
-  std::string value;
-  CHECK(instance->GetAsString(&value));
-
-  int min_length = 0;
-  if (schema->GetInteger(schema::kMinLength, &min_length)) {
-    CHECK(min_length >= 0);
-    if (value.size() < static_cast<size_t>(min_length)) {
-      errors_.push_back(Error(path, FormatErrorMessage(
-          kStringMinLength, base::IntToString(min_length))));
-    }
-  }
-
-  int max_length = 0;
-  if (schema->GetInteger(schema::kMaxLength, &max_length)) {
-    CHECK(max_length >= 0);
-    if (value.size() > static_cast<size_t>(max_length)) {
-      errors_.push_back(Error(path, FormatErrorMessage(
-          kStringMaxLength, base::IntToString(max_length))));
-    }
-  }
-
-  CHECK(!schema->HasKey(schema::kPattern)) << "Pattern is not supported.";
-}
-
-void JSONSchemaValidator::ValidateNumber(const base::Value* instance,
-                                         const base::DictionaryValue* schema,
-                                         const std::string& path) {
-  double value = GetNumberValue(instance);
-
-  // TODO(aa): It would be good to test that the double is not infinity or nan,
-  // but isnan and isinf aren't defined on Windows.
-
-  double minimum = 0;
-  if (schema->GetDouble(schema::kMinimum, &minimum)) {
-    if (value < minimum)
-      errors_.push_back(Error(path, FormatErrorMessage(
-          kNumberMinimum, base::DoubleToString(minimum))));
-  }
-
-  double maximum = 0;
-  if (schema->GetDouble(schema::kMaximum, &maximum)) {
-    if (value > maximum)
-      errors_.push_back(Error(path, FormatErrorMessage(
-          kNumberMaximum, base::DoubleToString(maximum))));
-  }
-}
-
-bool JSONSchemaValidator::ValidateType(const base::Value* instance,
-                                       const std::string& expected_type,
-                                       const std::string& path) {
-  std::string actual_type = GetJSONSchemaType(instance);
-  if (expected_type == actual_type ||
-      (expected_type == schema::kNumber && actual_type == schema::kInteger)) {
-    return true;
-  } else if (expected_type == schema::kInteger &&
-             actual_type == schema::kNumber) {
-    errors_.push_back(Error(path, kInvalidTypeIntegerNumber));
-    return false;
-  } else {
-    errors_.push_back(Error(path, FormatErrorMessage(
-        kInvalidType, expected_type, actual_type)));
-    return false;
-  }
-}
-
-bool JSONSchemaValidator::SchemaAllowsAnyAdditionalItems(
-    const base::DictionaryValue* schema,
-    const base::DictionaryValue** additional_properties_schema) {
-  // If the validator allows additional properties globally, and this schema
-  // doesn't override, then we can exit early.
-  schema->GetDictionary(schema::kAdditionalProperties,
-                        additional_properties_schema);
-
-  if (*additional_properties_schema) {
-    std::string additional_properties_type(schema::kAny);
-    CHECK((*additional_properties_schema)->GetString(
-        schema::kType, &additional_properties_type));
-    return additional_properties_type == schema::kAny;
-  } else {
-    return default_allow_additional_properties_;
-  }
-}
diff --git a/chrome/common/json_schema/json_schema_validator.h b/chrome/common/json_schema/json_schema_validator.h
deleted file mode 100644
index 3b42444..0000000
--- a/chrome/common/json_schema/json_schema_validator.h
+++ /dev/null
@@ -1,235 +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_COMMON_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
-#define CHROME_COMMON_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-class StringValue;
-class Value;
-}
-
-//==============================================================================
-// This class implements a subset of JSON Schema.
-// See: http://www.json.com/json-schema-proposal/ for more details.
-//
-// There is also an older JavaScript implementation of the same functionality in
-// chrome/renderer/resources/json_schema.js.
-//
-// The following features of JSON Schema are not implemented:
-// - requires
-// - unique
-// - disallow
-// - union types (but replaced with 'choices')
-// - number.maxDecimal
-// - string.pattern
-//
-// The following properties are not applicable to the interface exposed by
-// this class:
-// - options
-// - readonly
-// - title
-// - description
-// - format
-// - default
-// - transient
-// - hidden
-//
-// There are also these departures from the JSON Schema proposal:
-// - null counts as 'unspecified' for optional values
-// - added the 'choices' property, to allow specifying a list of possible types
-//   for a value
-// - by default an "object" typed schema does not allow additional properties.
-//   if present, "additionalProperties" is to be a schema against which all
-//   additional properties will be validated.
-//==============================================================================
-class JSONSchemaValidator {
- public:
-  // Details about a validation error.
-  struct Error {
-    Error();
-
-    explicit Error(const std::string& message);
-
-    Error(const std::string& path, const std::string& message);
-
-    // The path to the location of the error in the JSON structure.
-    std::string path;
-
-    // An english message describing the error.
-    std::string message;
-  };
-
-  // Error messages.
-  static const char kUnknownTypeReference[];
-  static const char kInvalidChoice[];
-  static const char kInvalidEnum[];
-  static const char kObjectPropertyIsRequired[];
-  static const char kUnexpectedProperty[];
-  static const char kArrayMinItems[];
-  static const char kArrayMaxItems[];
-  static const char kArrayItemRequired[];
-  static const char kStringMinLength[];
-  static const char kStringMaxLength[];
-  static const char kStringPattern[];
-  static const char kNumberMinimum[];
-  static const char kNumberMaximum[];
-  static const char kInvalidType[];
-  static const char kInvalidTypeIntegerNumber[];
-
-  // Classifies a Value as one of the JSON schema primitive types.
-  static std::string GetJSONSchemaType(const base::Value* value);
-
-  // Utility methods to format error messages. The first method can have one
-  // wildcard represented by '*', which is replaced with s1. The second method
-  // can have two, which are replaced by s1 and s2.
-  static std::string FormatErrorMessage(const std::string& format,
-                                        const std::string& s1);
-  static std::string FormatErrorMessage(const std::string& format,
-                                        const std::string& s1,
-                                        const std::string& s2);
-
-  // Verifies if |schema| is a valid JSON v3 schema. When this validation passes
-  // then |schema| is valid JSON that can be parsed into a DictionaryValue,
-  // and that DictionaryValue can be used to build a JSONSchemaValidator.
-  // Returns the parsed DictionaryValue when |schema| validated, otherwise
-  // returns NULL. In that case, |error| contains an error description.
-  static scoped_ptr<base::DictionaryValue> IsValidSchema(
-      const std::string& schema,
-      std::string* error);
-
-  // Creates a validator for the specified schema.
-  //
-  // NOTE: This constructor assumes that |schema| is well formed and valid.
-  // Errors will result in CHECK at runtime; this constructor should not be used
-  // with untrusted schemas.
-  explicit JSONSchemaValidator(base::DictionaryValue* schema);
-
-  // Creates a validator for the specified schema and user-defined types. Each
-  // type must be a valid JSONSchema type description with an additional "id"
-  // field. Schema objects in |schema| can refer to these types with the "$ref"
-  // property.
-  //
-  // NOTE: This constructor assumes that |schema| and |types| are well-formed
-  // and valid. Errors will result in CHECK at runtime; this constructor should
-  // not be used with untrusted schemas.
-  JSONSchemaValidator(base::DictionaryValue* schema, base::ListValue* types);
-
-  ~JSONSchemaValidator();
-
-  // Whether the validator allows additional items for objects and lists, beyond
-  // those defined by their schema, by default.
-  //
-  // This setting defaults to false: all items in an instance list or object
-  // must be defined by the corresponding schema.
-  //
-  // This setting can be overridden on individual object and list schemas by
-  // setting the "additionalProperties" field.
-  bool default_allow_additional_properties() const {
-    return default_allow_additional_properties_;
-  }
-
-  void set_default_allow_additional_properties(bool val) {
-    default_allow_additional_properties_ = val;
-  }
-
-  // Returns any errors from the last call to to Validate().
-  const std::vector<Error>& errors() const {
-    return errors_;
-  }
-
-  // Validates a JSON value. Returns true if the instance is valid, false
-  // otherwise. If false is returned any errors are available from the errors()
-  // getter.
-  bool Validate(const base::Value* instance);
-
- private:
-  typedef std::map<std::string, const base::DictionaryValue*> TypeMap;
-
-  // Each of the below methods handle a subset of the validation process. The
-  // path paramater is the path to |instance| from the root of the instance tree
-  // and is used in error messages.
-
-  // Validates any instance node against any schema node. This is called for
-  // every node in the instance tree, and it just decides which of the more
-  // detailed methods to call.
-  void Validate(const base::Value* instance,
-                const base::DictionaryValue* schema,
-                const std::string& path);
-
-  // Validates a node against a list of possible schemas. If any one of the
-  // schemas match, the node is valid.
-  void ValidateChoices(const base::Value* instance,
-                       const base::ListValue* choices,
-                       const std::string& path);
-
-  // Validates a node against a list of exact primitive values, eg 42, "foobar".
-  void ValidateEnum(const base::Value* instance,
-                    const base::ListValue* choices,
-                    const std::string& path);
-
-  // Validates a JSON object against an object schema node.
-  void ValidateObject(const base::DictionaryValue* instance,
-                      const base::DictionaryValue* schema,
-                      const std::string& path);
-
-  // Validates a JSON array against an array schema node.
-  void ValidateArray(const base::ListValue* instance,
-                     const base::DictionaryValue* schema,
-                     const std::string& path);
-
-  // Validates a JSON array against an array schema node configured to be a
-  // tuple. In a tuple, there is one schema node for each item expected in the
-  // array.
-  void ValidateTuple(const base::ListValue* instance,
-                     const base::DictionaryValue* schema,
-                     const std::string& path);
-
-  // Validate a JSON string against a string schema node.
-  void ValidateString(const base::Value* instance,
-                      const base::DictionaryValue* schema,
-                      const std::string& path);
-
-  // Validate a JSON number against a number schema node.
-  void ValidateNumber(const base::Value* instance,
-                      const base::DictionaryValue* schema,
-                      const std::string& path);
-
-  // Validates that the JSON node |instance| has |expected_type|.
-  bool ValidateType(const base::Value* instance,
-                    const std::string& expected_type,
-                    const std::string& path);
-
-  // Returns true if |schema| will allow additional items of any type.
-  bool SchemaAllowsAnyAdditionalItems(
-      const base::DictionaryValue* schema,
-      const base::DictionaryValue** addition_items_schema);
-
-  // The root schema node.
-  base::DictionaryValue* schema_root_;
-
-  // Map of user-defined name to type.
-  TypeMap types_;
-
-  // Whether we allow additional properties on objects by default. This can be
-  // overridden by the allow_additional_properties flag on an Object schema.
-  bool default_allow_additional_properties_;
-
-  // Errors accumulated since the last call to Validate().
-  std::vector<Error> errors_;
-
-
-  DISALLOW_COPY_AND_ASSIGN(JSONSchemaValidator);
-};
-
-#endif  // CHROME_COMMON_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
diff --git a/chrome/common/json_schema/json_schema_validator_unittest.cc b/chrome/common/json_schema/json_schema_validator_unittest.cc
deleted file mode 100644
index 1fc728f..0000000
--- a/chrome/common/json_schema/json_schema_validator_unittest.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// 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.
-
-#include "base/values.h"
-#include "chrome/common/json_schema/json_schema_validator.h"
-#include "chrome/common/json_schema/json_schema_validator_unittest_base.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class JSONSchemaValidatorCPPTest : public JSONSchemaValidatorTestBase {
- public:
-  JSONSchemaValidatorCPPTest()
-      : JSONSchemaValidatorTestBase(JSONSchemaValidatorTestBase::CPP) {
-  }
-
- protected:
-  virtual void ExpectValid(const std::string& test_source,
-                           base::Value* instance,
-                           base::DictionaryValue* schema,
-                           base::ListValue* types) OVERRIDE {
-    JSONSchemaValidator validator(schema, types);
-    if (validator.Validate(instance))
-      return;
-
-    for (size_t i = 0; i < validator.errors().size(); ++i) {
-      ADD_FAILURE() << test_source << ": "
-                    << validator.errors()[i].path << ": "
-                    << validator.errors()[i].message;
-    }
-  }
-
-  virtual void ExpectNotValid(
-      const std::string& test_source,
-      base::Value* instance, base::DictionaryValue* schema,
-      base::ListValue* types,
-      const std::string& expected_error_path,
-      const std::string& expected_error_message) OVERRIDE {
-    JSONSchemaValidator validator(schema, types);
-    if (validator.Validate(instance)) {
-      ADD_FAILURE() << test_source;
-      return;
-    }
-
-    ASSERT_EQ(1u, validator.errors().size()) << test_source;
-    EXPECT_EQ(expected_error_path, validator.errors()[0].path) << test_source;
-    EXPECT_EQ(expected_error_message, validator.errors()[0].message)
-        << test_source;
-  }
-};
-
-TEST_F(JSONSchemaValidatorCPPTest, Test) {
-  RunTests();
-}
-
-TEST(JSONSchemaValidator, IsValidSchema) {
-  std::string error;
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("\0", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("string", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("\"string\"", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("[]", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("{}", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
-      "{ \"type\": 123 }", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
-      "{ \"type\": \"invalid\" }", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
-      "{"
-      "  \"type\": \"object\","
-      "  \"properties\": []"  // Invalid properties type.
-      "}", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
-      "{"
-      "  \"type\": \"string\","
-      "  \"maxLength\": -1"  // Must be >= 0.
-      "}", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
-      "{"
-      "  \"type\": \"string\","
-      "  \"enum\": [ {} ],"  // "enum" must contain simple values.
-      "}", &error));
-  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
-      "{"
-      "  \"type\": \"array\","
-      "  \"items\": [ 123 ],"  // "items" must contain a schema or schemas.
-      "}", &error));
-  EXPECT_TRUE(JSONSchemaValidator::IsValidSchema(
-      "{ \"type\": \"object\" }", &error)) << error;
-  EXPECT_TRUE(JSONSchemaValidator::IsValidSchema(
-      "{ \"type\": [\"object\", \"array\"] }", &error)) << error;
-  EXPECT_TRUE(JSONSchemaValidator::IsValidSchema(
-      "{"
-      "  \"type\": [\"object\", \"array\"],"
-      "  \"properties\": {"
-      "    \"string-property\": {"
-      "      \"type\": \"string\","
-      "      \"minLength\": 1,"
-      "      \"maxLength\": 100,"
-      "      \"title\": \"The String Policy\","
-      "      \"description\": \"This policy controls the String widget.\""
-      "    },"
-      "    \"integer-property\": {"
-      "      \"type\": \"number\","
-      "      \"minimum\": 1000.0,"
-      "      \"maximum\": 9999.0"
-      "    },"
-      "    \"enum-property\": {"
-      "      \"type\": \"integer\","
-      "      \"enum\": [0, 1, 10, 100]"
-      "    },"
-      "    \"items-property\": {"
-      "      \"type\": \"array\","
-      "      \"items\": {"
-      "        \"type\": \"string\""
-      "      }"
-      "    },"
-      "    \"items-list-property\": {"
-      "      \"type\": \"array\","
-      "      \"items\": ["
-      "        { \"type\": \"string\" },"
-      "        { \"type\": \"integer\" }"
-      "      ]"
-      "    }"
-      "  },"
-      "  \"additionalProperties\": {"
-      "    \"type\": \"any\""
-      "  }"
-      "}", &error)) << error;
-}
diff --git a/chrome/common/json_schema/json_schema_validator_unittest_base.cc b/chrome/common/json_schema/json_schema_validator_unittest_base.cc
deleted file mode 100644
index 0f87a48..0000000
--- a/chrome/common/json_schema/json_schema_validator_unittest_base.cc
+++ /dev/null
@@ -1,726 +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/common/json_schema/json_schema_validator_unittest_base.h"
-
-#include <cfloat>
-#include <cmath>
-#include <limits>
-
-#include "base/file_util.h"
-#include "base/json/json_file_value_serializer.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/path_service.h"
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/json_schema/json_schema_constants.h"
-#include "chrome/common/json_schema/json_schema_validator.h"
-
-namespace schema = json_schema_constants;
-
-namespace {
-
-#define TEST_SOURCE base::StringPrintf("%s:%i", __FILE__, __LINE__)
-
-base::Value* LoadValue(const std::string& filename) {
-  base::FilePath path;
-  PathService::Get(chrome::DIR_TEST_DATA, &path);
-  path = path.AppendASCII("json_schema_validator").AppendASCII(filename);
-  EXPECT_TRUE(base::PathExists(path));
-
-  std::string error_message;
-  JSONFileValueSerializer serializer(path);
-  base::Value* result = serializer.Deserialize(NULL, &error_message);
-  if (!result)
-    ADD_FAILURE() << "Could not parse JSON: " << error_message;
-  return result;
-}
-
-base::Value* LoadValue(const std::string& filename, base::Value::Type type) {
-  scoped_ptr<base::Value> result(LoadValue(filename));
-  if (!result.get())
-    return NULL;
-  if (!result->IsType(type)) {
-    ADD_FAILURE() << "Expected type " << type << ", got: " << result->GetType();
-    return NULL;
-  }
-  return result.release();
-}
-
-base::ListValue* LoadList(const std::string& filename) {
-  return static_cast<base::ListValue*>(
-      LoadValue(filename, base::Value::TYPE_LIST));
-}
-
-base::DictionaryValue* LoadDictionary(const std::string& filename) {
-  return static_cast<base::DictionaryValue*>(
-      LoadValue(filename, base::Value::TYPE_DICTIONARY));
-}
-
-}  // namespace
-
-
-JSONSchemaValidatorTestBase::JSONSchemaValidatorTestBase(
-    JSONSchemaValidatorTestBase::ValidatorType type)
-    : type_(type) {
-}
-
-void JSONSchemaValidatorTestBase::RunTests() {
-  TestComplex();
-  TestStringPattern();
-  TestEnum();
-  TestChoices();
-  TestExtends();
-  TestObject();
-  TestTypeReference();
-  TestArrayTuple();
-  TestArrayNonTuple();
-  TestString();
-  TestNumber();
-  TestTypeClassifier();
-  TestTypes();
-}
-
-void JSONSchemaValidatorTestBase::TestComplex() {
-  scoped_ptr<base::DictionaryValue> schema(
-      LoadDictionary("complex_schema.json"));
-  scoped_ptr<base::ListValue> instance(LoadList("complex_instance.json"));
-
-  ASSERT_TRUE(schema.get());
-  ASSERT_TRUE(instance.get());
-
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  instance->Remove(instance->GetSize() - 1, NULL);
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  instance->Append(new base::DictionaryValue());
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "1",
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kNumber,
-                     schema::kObject));
-  instance->Remove(instance->GetSize() - 1, NULL);
-
-  base::DictionaryValue* item = NULL;
-  ASSERT_TRUE(instance->GetDictionary(0, &item));
-  item->SetString("url", "xxxxxxxxxxx");
-
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
-                 "0.url",
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kStringMaxLength, "10"));
-}
-
-void JSONSchemaValidatorTestBase::TestStringPattern() {
-  // Regex patterns not supported in CPP validator.
-  if (type_ == CPP)
-    return;
-
-  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
-  schema->SetString(schema::kType, schema::kString);
-  schema->SetString(schema::kPattern, "foo+");
-
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::StringValue("foo")).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::StringValue("foooooo")).get(),
-              schema.get(), NULL);
-  ExpectNotValid(TEST_SOURCE,
-                 scoped_ptr<base::Value>(new base::StringValue("bar")).get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kStringPattern, "foo+"));
-}
-
-void JSONSchemaValidatorTestBase::TestEnum() {
-  scoped_ptr<base::DictionaryValue> schema(LoadDictionary("enum_schema.json"));
-
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::StringValue("foo")).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(false)).get(),
-              schema.get(), NULL);
-
-  ExpectNotValid(TEST_SOURCE,
-                 scoped_ptr<base::Value>(new base::StringValue("42")).get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::kInvalidEnum);
-  ExpectNotValid(TEST_SOURCE,
-                 scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::kInvalidEnum);
-}
-
-void JSONSchemaValidatorTestBase::TestChoices() {
-  scoped_ptr<base::DictionaryValue> schema(
-      LoadDictionary("choices_schema.json"));
-
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-              schema.get(), NULL);
-
-  scoped_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
-  instance->SetString("foo", "bar");
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  ExpectNotValid(TEST_SOURCE,
-                 scoped_ptr<base::Value>(new base::StringValue("foo")).get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::kInvalidChoice);
-  ExpectNotValid(TEST_SOURCE,
-                 scoped_ptr<base::Value>(new base::ListValue()).get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::kInvalidChoice);
-
-  instance->SetInteger("foo", 42);
-  ExpectNotValid(TEST_SOURCE,
-                 instance.get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::kInvalidChoice);
-}
-
-void JSONSchemaValidatorTestBase::TestExtends() {
-  // TODO(aa): JS only
-}
-
-void JSONSchemaValidatorTestBase::TestObject() {
-  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
-  schema->SetString(schema::kType, schema::kObject);
-  schema->SetString("properties.foo.type", schema::kString);
-  schema->SetString("properties.bar.type", schema::kInteger);
-
-  scoped_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
-  instance->SetString("foo", "foo");
-  instance->SetInteger("bar", 42);
-
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  instance->SetBoolean("extra", true);
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
-                 "extra", JSONSchemaValidator::kUnexpectedProperty);
-
-  instance->Remove("extra", NULL);
-  instance->Remove("bar", NULL);
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "bar",
-                 JSONSchemaValidator::kObjectPropertyIsRequired);
-
-  instance->SetString("bar", "42");
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "bar",
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kInteger,
-                     schema::kString));
-
-  base::DictionaryValue* additional_properties = new base::DictionaryValue();
-  additional_properties->SetString(schema::kType, schema::kAny);
-  schema->Set(schema::kAdditionalProperties, additional_properties);
-
-  instance->SetInteger("bar", 42);
-  instance->SetBoolean("extra", true);
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  instance->SetString("extra", "foo");
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  additional_properties->SetString(schema::kType, schema::kBoolean);
-  instance->SetBoolean("extra", true);
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  instance->SetString("extra", "foo");
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
-                 "extra", JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kBoolean,
-                     schema::kString));
-
-  base::DictionaryValue* properties = NULL;
-  base::DictionaryValue* bar_property = NULL;
-  ASSERT_TRUE(schema->GetDictionary(schema::kProperties, &properties));
-  ASSERT_TRUE(properties->GetDictionary("bar", &bar_property));
-
-  bar_property->SetBoolean(schema::kOptional, true);
-  instance->Remove("extra", NULL);
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  instance->Remove("bar", NULL);
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  instance->Set("bar", base::Value::CreateNullValue());
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
-                 "bar", JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kInteger,
-                     schema::kNull));
-  instance->SetString("bar", "42");
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
-                 "bar", JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kInteger,
-                     schema::kString));
-}
-
-void JSONSchemaValidatorTestBase::TestTypeReference() {
-  scoped_ptr<base::ListValue> types(LoadList("reference_types.json"));
-  ASSERT_TRUE(types.get());
-
-  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
-  schema->SetString(schema::kType, schema::kObject);
-  schema->SetString("properties.foo.type", schema::kString);
-  schema->SetString("properties.bar.$ref", "Max10Int");
-  schema->SetString("properties.baz.$ref", "MinLengthString");
-
-  scoped_ptr<base::DictionaryValue> schema_inline(new base::DictionaryValue());
-  schema_inline->SetString(schema::kType, schema::kObject);
-  schema_inline->SetString("properties.foo.type", schema::kString);
-  schema_inline->SetString("properties.bar.id", "NegativeInt");
-  schema_inline->SetString("properties.bar.type", schema::kInteger);
-  schema_inline->SetInteger("properties.bar.maximum", 0);
-  schema_inline->SetString("properties.baz.$ref", "NegativeInt");
-
-  scoped_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
-  instance->SetString("foo", "foo");
-  instance->SetInteger("bar", 4);
-  instance->SetString("baz", "ab");
-
-  scoped_ptr<base::DictionaryValue> instance_inline(
-      new base::DictionaryValue());
-  instance_inline->SetString("foo", "foo");
-  instance_inline->SetInteger("bar", -4);
-  instance_inline->SetInteger("baz", -2);
-
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), types.get());
-  ExpectValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(), NULL);
-
-  // Validation failure, but successful schema reference.
-  instance->SetString("baz", "a");
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), types.get(),
-                 "baz", JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kStringMinLength, "2"));
-
-  instance_inline->SetInteger("bar", 20);
-  ExpectNotValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(), NULL,
-                 "bar", JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kNumberMaximum, "0"));
-
-  // Remove MinLengthString type.
-  types->Remove(types->GetSize() - 1, NULL);
-  instance->SetString("baz", "ab");
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), types.get(),
-                 "bar", JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kUnknownTypeReference,
-                     "Max10Int"));
-
-  // Remove internal type "NegativeInt".
-  schema_inline->Remove("properties.bar", NULL);
-  instance_inline->Remove("bar", NULL);
-  ExpectNotValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(), NULL,
-                 "baz", JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kUnknownTypeReference,
-                     "NegativeInt"));
-}
-
-void JSONSchemaValidatorTestBase::TestArrayTuple() {
-  scoped_ptr<base::DictionaryValue> schema(
-      LoadDictionary("array_tuple_schema.json"));
-  ASSERT_TRUE(schema.get());
-
-  scoped_ptr<base::ListValue> instance(new base::ListValue());
-  instance->Append(new base::StringValue("42"));
-  instance->Append(new base::FundamentalValue(42));
-
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  instance->Append(new base::StringValue("anything"));
-  ExpectNotValid(TEST_SOURCE,
-                 instance.get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kArrayMaxItems, "2"));
-
-  instance->Remove(1, NULL);
-  instance->Remove(1, NULL);
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "1",
-                 JSONSchemaValidator::kArrayItemRequired);
-
-  instance->Set(0, new base::FundamentalValue(42));
-  instance->Append(new base::FundamentalValue(42));
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "0",
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kString,
-                     schema::kInteger));
-
-  base::DictionaryValue* additional_properties = new base::DictionaryValue();
-  additional_properties->SetString(schema::kType, schema::kAny);
-  schema->Set(schema::kAdditionalProperties, additional_properties);
-  instance->Set(0, new base::StringValue("42"));
-  instance->Append(new base::StringValue("anything"));
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  instance->Set(2, new base::ListValue());
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  additional_properties->SetString(schema::kType, schema::kBoolean);
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "2",
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kBoolean,
-                     schema::kArray));
-  instance->Set(2, new base::FundamentalValue(false));
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  base::ListValue* items_schema = NULL;
-  base::DictionaryValue* item0_schema = NULL;
-  ASSERT_TRUE(schema->GetList(schema::kItems, &items_schema));
-  ASSERT_TRUE(items_schema->GetDictionary(0, &item0_schema));
-  item0_schema->SetBoolean(schema::kOptional, true);
-  instance->Remove(2, NULL);
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  // TODO(aa): I think this is inconsistent with the handling of NULL+optional
-  // for objects.
-  instance->Set(0, base::Value::CreateNullValue());
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  instance->Set(0, new base::FundamentalValue(42));
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "0",
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kString,
-                     schema::kInteger));
-}
-
-void JSONSchemaValidatorTestBase::TestArrayNonTuple() {
-  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
-  schema->SetString(schema::kType, schema::kArray);
-  schema->SetString("items.type", schema::kString);
-  schema->SetInteger(schema::kMinItems, 2);
-  schema->SetInteger(schema::kMaxItems, 3);
-
-  scoped_ptr<base::ListValue> instance(new base::ListValue());
-  instance->Append(new base::StringValue("x"));
-  instance->Append(new base::StringValue("x"));
-
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-  instance->Append(new base::StringValue("x"));
-  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
-
-  instance->Append(new base::StringValue("x"));
-  ExpectNotValid(TEST_SOURCE,
-                 instance.get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kArrayMaxItems, "3"));
-  instance->Remove(1, NULL);
-  instance->Remove(1, NULL);
-  instance->Remove(1, NULL);
-  ExpectNotValid(TEST_SOURCE,
-                 instance.get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kArrayMinItems, "2"));
-
-  instance->Remove(1, NULL);
-  instance->Append(new base::FundamentalValue(42));
-  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "1",
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kInvalidType,
-                     schema::kString,
-                     schema::kInteger));
-}
-
-void JSONSchemaValidatorTestBase::TestString() {
-  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
-  schema->SetString(schema::kType, schema::kString);
-  schema->SetInteger(schema::kMinLength, 1);
-  schema->SetInteger(schema::kMaxLength, 10);
-
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::StringValue("x")).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(
-                  new base::StringValue("xxxxxxxxxx")).get(),
-              schema.get(), NULL);
-
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::StringValue(std::string())).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kStringMinLength, "1"));
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::StringValue("xxxxxxxxxxx")).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kStringMaxLength, "10"));
-}
-
-void JSONSchemaValidatorTestBase::TestNumber() {
-  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
-  schema->SetString(schema::kType, schema::kNumber);
-  schema->SetInteger(schema::kMinimum, 1);
-  schema->SetInteger(schema::kMaximum, 100);
-  schema->SetInteger("maxDecimal", 2);
-
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(1)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(50)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(100)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(88.88)).get(),
-              schema.get(), NULL);
-
-  ExpectNotValid(TEST_SOURCE,
-                 scoped_ptr<base::Value>(new base::FundamentalValue(0.5)).get(),
-                 schema.get(),
-                 NULL,
-                 std::string(),
-                 JSONSchemaValidator::FormatErrorMessage(
-                     JSONSchemaValidator::kNumberMinimum, "1"));
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::FundamentalValue(100.1)).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kNumberMaximum, "100"));
-}
-
-void JSONSchemaValidatorTestBase::TestTypeClassifier() {
-  EXPECT_EQ(std::string(schema::kBoolean),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(
-                    new base::FundamentalValue(true)).get()));
-  EXPECT_EQ(std::string(schema::kBoolean),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(
-                    new base::FundamentalValue(false)).get()));
-
-  // It doesn't matter whether the C++ type is 'integer' or 'real'. If the
-  // number is integral and within the representable range of integers in
-  // double, it's classified as 'integer'.
-  EXPECT_EQ(std::string(schema::kInteger),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(new base::FundamentalValue(42)).get()));
-  EXPECT_EQ(std::string(schema::kInteger),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(new base::FundamentalValue(0)).get()));
-  EXPECT_EQ(std::string(schema::kInteger),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(new base::FundamentalValue(42)).get()));
-  EXPECT_EQ(std::string(schema::kInteger),
-            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
-                new base::FundamentalValue(pow(2.0, DBL_MANT_DIG))).get()));
-  EXPECT_EQ(std::string(schema::kInteger),
-            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
-                new base::FundamentalValue(pow(-2.0, DBL_MANT_DIG))).get()));
-
-  // "number" is only used for non-integral numbers, or numbers beyond what
-  // double can accurately represent.
-  EXPECT_EQ(std::string(schema::kNumber),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(
-                    new base::FundamentalValue(88.8)).get()));
-  EXPECT_EQ(std::string(schema::kNumber),
-            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
-                new base::FundamentalValue(pow(2.0, DBL_MANT_DIG) * 2)).get()));
-  EXPECT_EQ(std::string(schema::kNumber),
-            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
-                new base::FundamentalValue(
-                    pow(-2.0, DBL_MANT_DIG) * 2)).get()));
-
-  EXPECT_EQ(std::string(schema::kString),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(new base::StringValue("foo")).get()));
-  EXPECT_EQ(std::string(schema::kArray),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(new base::ListValue()).get()));
-  EXPECT_EQ(std::string(schema::kObject),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(new base::DictionaryValue()).get()));
-  EXPECT_EQ(std::string(schema::kNull),
-            JSONSchemaValidator::GetJSONSchemaType(
-                scoped_ptr<base::Value>(base::Value::CreateNullValue()).get()));
-}
-
-void JSONSchemaValidatorTestBase::TestTypes() {
-  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
-
-  // valid
-  schema->SetString(schema::kType, schema::kObject);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::DictionaryValue()).get(),
-              schema.get(), NULL);
-
-  schema->SetString(schema::kType, schema::kArray);
-  ExpectValid(TEST_SOURCE, scoped_ptr<base::Value>(new base::ListValue()).get(),
-              schema.get(), NULL);
-
-  schema->SetString(schema::kType, schema::kString);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::StringValue("foobar")).get(),
-              schema.get(), NULL);
-
-  schema->SetString(schema::kType, schema::kNumber);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(88.8)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(0)).get(),
-              schema.get(), NULL);
-
-  schema->SetString(schema::kType, schema::kInteger);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(0)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(
-                  new base::FundamentalValue(pow(2.0, DBL_MANT_DIG))).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(
-                  new base::FundamentalValue(pow(-2.0, DBL_MANT_DIG))).get(),
-              schema.get(), NULL);
-
-  schema->SetString(schema::kType, schema::kBoolean);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(false)).get(),
-              schema.get(), NULL);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(new base::FundamentalValue(true)).get(),
-              schema.get(), NULL);
-
-  schema->SetString(schema::kType, schema::kNull);
-  ExpectValid(TEST_SOURCE,
-              scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
-              schema.get(), NULL);
-
-  // not valid
-  schema->SetString(schema::kType, schema::kObject);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::ListValue()).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kInvalidType, schema::kObject, schema::kArray));
-
-  schema->SetString(schema::kType, schema::kObject);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kInvalidType, schema::kObject, schema::kNull));
-
-  schema->SetString(schema::kType, schema::kArray);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kInvalidType, schema::kArray, schema::kInteger));
-
-  schema->SetString(schema::kType, schema::kString);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
-                                              schema::kString,
-                                              schema::kInteger));
-
-  schema->SetString(schema::kType, schema::kNumber);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::StringValue("42")).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kInvalidType, schema::kNumber, schema::kString));
-
-  schema->SetString(schema::kType, schema::kInteger);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::FundamentalValue(88.8)).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::kInvalidTypeIntegerNumber);
-
-  schema->SetString(schema::kType, schema::kBoolean);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::FundamentalValue(1)).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
-                                              schema::kBoolean,
-                                              schema::kInteger));
-
-  schema->SetString(schema::kType, schema::kNull);
-  ExpectNotValid(
-      TEST_SOURCE,
-      scoped_ptr<base::Value>(new base::FundamentalValue(false)).get(),
-      schema.get(),
-      NULL,
-      std::string(),
-      JSONSchemaValidator::FormatErrorMessage(
-          JSONSchemaValidator::kInvalidType, schema::kNull, schema::kBoolean));
-}
diff --git a/chrome/common/json_schema/json_schema_validator_unittest_base.h b/chrome/common/json_schema/json_schema_validator_unittest_base.h
deleted file mode 100644
index 63988f5..0000000
--- a/chrome/common/json_schema/json_schema_validator_unittest_base.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-#ifndef CHROME_COMMON_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_UNITTEST_BASE_H_
-#define CHROME_COMMON_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_UNITTEST_BASE_H_
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-class DictionaryValue;
-class ListValue;
-class Value;
-}
-
-// Base class for unit tests for JSONSchemaValidator. There is currently only
-// one implementation, JSONSchemaValidatorCPPTest.
-//
-// TODO(aa): Refactor chrome/test/data/json_schema_test.js into
-// JSONSchemaValidatorJSTest that inherits from this.
-class JSONSchemaValidatorTestBase : public testing::Test {
- public:
-  enum ValidatorType {
-    CPP = 1,
-    JS = 2
-  };
-
-  explicit JSONSchemaValidatorTestBase(ValidatorType type);
-
-  void RunTests();
-
- protected:
-  virtual void ExpectValid(const std::string& test_source,
-                           base::Value* instance,
-                           base::DictionaryValue* schema,
-                           base::ListValue* types) = 0;
-
-  virtual void ExpectNotValid(const std::string& test_source,
-                              base::Value* instance,
-                              base::DictionaryValue* schema,
-                              base::ListValue* types,
-                              const std::string& expected_error_path,
-                              const std::string& expected_error_message) = 0;
-
- private:
-  void TestComplex();
-  void TestStringPattern();
-  void TestEnum();
-  void TestChoices();
-  void TestExtends();
-  void TestObject();
-  void TestTypeReference();
-  void TestArrayTuple();
-  void TestArrayNonTuple();
-  void TestString();
-  void TestNumber();
-  void TestTypeClassifier();
-  void TestTypes();
-
-  ValidatorType type_;
-};
-
-#endif  // CHROME_COMMON_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_UNITTEST_BASE_H_
diff --git a/chrome/common/local_discovery/local_discovery_messages.h b/chrome/common/local_discovery/local_discovery_messages.h
index cda9cc8..b98756e 100644
--- a/chrome/common/local_discovery/local_discovery_messages.h
+++ b/chrome/common/local_discovery/local_discovery_messages.h
@@ -58,6 +58,10 @@
 IPC_MESSAGE_CONTROL1(LocalDiscoveryMsg_DestroyLocalDomainResolver,
                      uint64 /* id */)
 
+// Stops local discovery in utility process. http://crbug.com/268466.
+IPC_MESSAGE_CONTROL0(LocalDiscoveryMsg_ShutdownLocalDiscovery)
+
+
 //------------------------------------------------------------------------------
 // Utility process host messages:
 // These are messages from the utility process to the browser.
diff --git a/chrome/common/media_galleries/picasa_types.h b/chrome/common/media_galleries/picasa_types.h
index e807bc1..6369c0a 100644
--- a/chrome/common/media_galleries/picasa_types.h
+++ b/chrome/common/media_galleries/picasa_types.h
@@ -17,8 +17,14 @@
 
 struct AlbumInfo;
 
-typedef std::set<base::FilePath> AlbumImages;
+// Map of de-duplicated filenames to the platform paths for a given album.
+// Example:
+//   Bar.jpg -> /path/to/Bar.jpg
+//   Foo.jpg -> /path/to/Foo.jpg
+//   Foo (1).jpg -> /path/to/another/Foo.jpg
+typedef std::map<std::string, base::FilePath> AlbumImages;
 typedef std::set<std::string> AlbumUIDSet;
+// Map of album uids to a collection of its images.
 typedef std::map<std::string, AlbumImages> AlbumImagesMap;
 typedef std::map<std::string, AlbumInfo> AlbumMap;
 
@@ -68,6 +74,10 @@
 struct FolderINIContents {
   base::FilePath folder_path;
   std::string ini_contents;
+
+  bool operator<(const FolderINIContents& that) const {
+    return folder_path < that.folder_path;
+  }
 };
 
 void CloseAlbumTableFiles(AlbumTableFiles* table_files);
diff --git a/chrome/common/metrics/variations/uniformity_field_trials.cc b/chrome/common/metrics/variations/uniformity_field_trials.cc
index ac7bcf9..fb666e1 100644
--- a/chrome/common/metrics/variations/uniformity_field_trials.cc
+++ b/chrome/common/metrics/variations/uniformity_field_trials.cc
@@ -4,9 +4,12 @@
 
 #include "chrome/common/metrics/variations/uniformity_field_trials.h"
 
+#include <string>
+
 #include "base/metrics/field_trial.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
+#include "chrome/common/metrics/variations/variation_ids.h"
 #include "chrome/common/metrics/variations/variations_util.h"
 
 namespace chrome_variations {
diff --git a/chrome/common/metrics/variations/variation_ids.h b/chrome/common/metrics/variations/variation_ids.h
index 8ce3617..4e1e9da 100644
--- a/chrome/common/metrics/variations/variation_ids.h
+++ b/chrome/common/metrics/variations/variation_ids.h
@@ -31,17 +31,15 @@
 //
 // Ex:
 // // Name: UMA-Uniformity-Trial-5-Percent
-// // Range: 330000 - 3300099
+// // Range: 330000 - 3300019
 // // The 5% Uniformity Trial. This is a reserved range.
-// UNIFORMITY_TRIAL_5_PERCENT_ID_START = 330000,
-// UNIFORMITY_TRIAL_5_PERCENT_ID_END   = 330099,
+// UNIFORMITY_TRIAL_5_PERCENT_ID_BASE = 330000,
+// UNIFORMITY_TRIAL_5_PERCENT_ID_LIMIT =
+//     UNIFORMITY_TRIAL_5_PERCENT_ID_BASE + 20,
 //
 // Anything within the range of a uint32 should be castable to an ID, but
 // please ensure that they are within the range of the min and max values.
-enum VariationID {
-  // Used to represent no associated Chrome variation ID.
-  EMPTY_ID = 0,
-
+enum ReservedVariationID {
   // The smallest possible Chrome Variation ID in the reserved range. The
   // first 10,000 values are reserved for internal variations infrastructure
   // use. Please do not use values in this range.
@@ -66,7 +64,7 @@
   // Name: UMA-Uniformity-Trial-50-Percent
   // Range: 3300135 - 3300136
   UNIFORMITY_50_PERCENT_BASE  = UNIFORMITY_20_PERCENT_LIMIT,
-  UNIFORMITY_50_PERCENT_LIMIT = UNIFORMITY_50_PERCENT_BASE+ 2,
+  UNIFORMITY_50_PERCENT_LIMIT = UNIFORMITY_50_PERCENT_BASE + 2,
 
   // Name: UMA-Dynamic-Binary-Uniformity-Trial
   // The dynamic uniformity trial is only specified on the server, this is just
@@ -88,10 +86,9 @@
   UNIFORMITY_DYNAMIC_TRIAL_LIMIT = UNIFORMITY_DYNAMIC_TRIAL_BASE + 6,
 
   // Some values reserved for unit and integration tests.
-  TEST_VALUE_A = 3300200,
-  TEST_VALUE_B = 3300201,
-  TEST_VALUE_C = 3300202,
-  TEST_VALUE_D = 3300203,
+  // Range: 3300159 - 3300299
+  TEST_VALUE_BASE = 3300200,
+  TEST_VALUE_LIMIT = TEST_VALUE_BASE + 100,
 
   // USABLE IDs BEGIN HERE.
   //
@@ -176,6 +173,8 @@
   EXTENDED_INSTANT_RANGE_ID_MAX           = 3310365,
   EXTENDED_INSTANT_RANGE2_ID_MIN          = 3310368,
   EXTENDED_INSTANT_RANGE2_ID_MAX          = 3310868,
+  EXTENDED_INSTANT_RANGE3_ID_MIN          = 3310871,
+  EXTENDED_INSTANT_RANGE3_ID_MAX          = 3311870,
 
   // Reserve 100 IDs to be used by autocomplete dynamic field trials.
   // The dynamic field trials are activated by a call to
@@ -234,7 +233,7 @@
   // NEXT ID: When adding new IDs, please add them above this section, starting
   // with the value of NEXT_ID, and updating NEXT_ID to (end of your reserved
   // range) + 1.
-  NEXT_ID = 3310871,
+  NEXT_ID = 3311871,
 
   // USABLE IDs END HERE.
   //
diff --git a/chrome/common/metrics/variations/variations_associated_data.h b/chrome/common/metrics/variations/variations_associated_data.h
index d191d38..78d89b6 100644
--- a/chrome/common/metrics/variations/variations_associated_data.h
+++ b/chrome/common/metrics/variations/variations_associated_data.h
@@ -9,8 +9,6 @@
 #include <string>
 
 #include "base/metrics/field_trial.h"
-#include "base/strings/string16.h"
-#include "chrome/common/metrics/variations/variation_ids.h"
 
 // This file provides various helpers that extend the functionality around
 // base::FieldTrial.
@@ -44,6 +42,10 @@
 
 namespace chrome_variations {
 
+typedef int VariationID;
+
+const VariationID EMPTY_ID = 0;
+
 // The Unique ID of a trial and its active group, where the name and group
 // identifiers are hashes of the trial and group name strings.
 struct ActiveGroupId {
diff --git a/chrome/common/metrics/variations/variations_associated_data_unittest.cc b/chrome/common/metrics/variations/variations_associated_data_unittest.cc
index 2a194af..b3832e6 100644
--- a/chrome/common/metrics/variations/variations_associated_data_unittest.cc
+++ b/chrome/common/metrics/variations/variations_associated_data_unittest.cc
@@ -11,6 +11,9 @@
 
 namespace {
 
+const VariationID TEST_VALUE_A = 3300200;
+const VariationID TEST_VALUE_B = 3300201;
+
 // Convenience helper to retrieve the chrome_variations::VariationID for a
 // FieldTrial. Note that this will do the group assignment in |trial| if not
 // already done.
diff --git a/chrome/common/metrics/variations/variations_util_unittest.cc b/chrome/common/metrics/variations/variations_util_unittest.cc
index c92da5b..e5845e5 100644
--- a/chrome/common/metrics/variations/variations_util_unittest.cc
+++ b/chrome/common/metrics/variations/variations_util_unittest.cc
@@ -18,6 +18,11 @@
 
 namespace {
 
+const VariationID TEST_VALUE_A = 3300200;
+const VariationID TEST_VALUE_B = 3300201;
+const VariationID TEST_VALUE_C = 3300202;
+const VariationID TEST_VALUE_D = 3300203;
+
 // Tests whether a field trial is active (i.e. group() has been called on it).
 bool IsFieldTrialActive(const std::string& trial_name) {
   base::FieldTrial::ActiveGroups active_groups;
diff --git a/chrome/common/ntp_logging_events.h b/chrome/common/ntp_logging_events.h
new file mode 100644
index 0000000..3a95a59
--- /dev/null
+++ b/chrome/common/ntp_logging_events.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_NTP_LOGGING_EVENTS_H_
+#define CHROME_COMMON_NTP_LOGGING_EVENTS_H_
+
+// The different types of events that are logged from the NTP.
+enum NTPLoggingEventType {
+  // The user moused over an NTP tile or title.
+  NTP_MOUSEOVER = 0,
+
+  // The page attempted to load a thumbnail image.
+  NTP_THUMBNAIL_ATTEMPT = 1,
+
+  // There was an error in loading a thumbnail image.
+  NTP_THUMBNAIL_ERROR = 2,
+
+  NTP_NUM_EVENT_TYPES
+};
+
+#endif  // CHROME_COMMON_NTP_LOGGING_EVENTS_H_
diff --git a/chrome/common/one_click_signin_messages.h b/chrome/common/one_click_signin_messages.h
deleted file mode 100644
index fcbb75a..0000000
--- a/chrome/common/one_click_signin_messages.h
+++ /dev/null
@@ -1,12 +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.
-
-// Multiply-included message file, hence no include guard.
-
-#include "content/public/common/password_form.h"
-#include "ipc/ipc_message_macros.h"
-
-#define IPC_MESSAGE_START OneClickSigninMsgStart
-
-IPC_MESSAGE_ROUTED1(OneClickSigninHostMsg_FormSubmitted, content::PasswordForm)
diff --git a/chrome/common/policy/OWNERS b/chrome/common/policy/OWNERS
deleted file mode 100644
index 317a807..0000000
--- a/chrome/common/policy/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-# This should match chrome/browser/policy/OWNERS
-mnissler@chromium.org
-pastarmovj@chromium.org
-joaodasilva@chromium.org
-bartfab@chromium.org
-atwilson@chromium.org
-pneubeck@chromium.org
diff --git a/chrome/common/policy/policy_schema.cc b/chrome/common/policy/policy_schema.cc
deleted file mode 100644
index cf60b77..0000000
--- a/chrome/common/policy/policy_schema.cc
+++ /dev/null
@@ -1,244 +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/policy/policy_schema.h"
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/stl_util.h"
-#include "chrome/common/json_schema/json_schema_constants.h"
-#include "chrome/common/json_schema/json_schema_validator.h"
-
-namespace policy {
-
-namespace {
-
-const char kJSONSchemaVersion[] = "http://json-schema.org/draft-03/schema#";
-
-// Describes the properties of a TYPE_DICTIONARY policy schema.
-class DictionaryPolicySchema : public PolicySchema {
- public:
-  static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema,
-                                        std::string* error);
-
-  virtual ~DictionaryPolicySchema();
-
-  virtual const PolicySchemaMap* GetProperties() const OVERRIDE;
-  virtual const PolicySchema* GetSchemaForAdditionalProperties() const OVERRIDE;
-
- private:
-  DictionaryPolicySchema();
-
-  PolicySchemaMap properties_;
-  scoped_ptr<PolicySchema> additional_properties_;
-
-  DISALLOW_COPY_AND_ASSIGN(DictionaryPolicySchema);
-};
-
-// Describes the items of a TYPE_LIST policy schema.
-class ListPolicySchema : public PolicySchema {
- public:
-  static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema,
-                                        std::string* error);
-
-  virtual ~ListPolicySchema();
-
-  virtual const PolicySchema* GetSchemaForItems() const OVERRIDE;
-
- private:
-  ListPolicySchema();
-
-  scoped_ptr<PolicySchema> items_schema_;
-
-  DISALLOW_COPY_AND_ASSIGN(ListPolicySchema);
-};
-
-bool SchemaTypeToValueType(const std::string& type_string,
-                           base::Value::Type* type) {
-  // Note: "any" is not an accepted type.
-  static const struct {
-    const char* schema_type;
-    base::Value::Type value_type;
-  } kSchemaToValueTypeMap[] = {
-    { json_schema_constants::kArray,        base::Value::TYPE_LIST       },
-    { json_schema_constants::kBoolean,      base::Value::TYPE_BOOLEAN    },
-    { json_schema_constants::kInteger,      base::Value::TYPE_INTEGER    },
-    { json_schema_constants::kNull,         base::Value::TYPE_NULL       },
-    { json_schema_constants::kNumber,       base::Value::TYPE_DOUBLE     },
-    { json_schema_constants::kObject,       base::Value::TYPE_DICTIONARY },
-    { json_schema_constants::kString,       base::Value::TYPE_STRING     },
-  };
-  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) {
-    if (kSchemaToValueTypeMap[i].schema_type == type_string) {
-      *type = kSchemaToValueTypeMap[i].value_type;
-      return true;
-    }
-  }
-  return false;
-}
-
-scoped_ptr<PolicySchema> ParseSchema(const base::DictionaryValue& schema,
-                                     std::string* error) {
-  std::string type_string;
-  if (!schema.GetString(json_schema_constants::kType, &type_string)) {
-    *error = "The schema type must be declared.";
-    return scoped_ptr<PolicySchema>();
-  }
-
-  base::Value::Type type = base::Value::TYPE_NULL;
-  if (!SchemaTypeToValueType(type_string, &type)) {
-    *error = "The \"any\" type can't be used.";
-    return scoped_ptr<PolicySchema>();
-  }
-
-  switch (type) {
-    case base::Value::TYPE_DICTIONARY:
-      return DictionaryPolicySchema::Parse(schema, error);
-    case base::Value::TYPE_LIST:
-      return ListPolicySchema::Parse(schema, error);
-    default:
-      return make_scoped_ptr(new PolicySchema(type));
-  }
-}
-
-DictionaryPolicySchema::DictionaryPolicySchema()
-    : PolicySchema(base::Value::TYPE_DICTIONARY) {}
-
-DictionaryPolicySchema::~DictionaryPolicySchema() {
-  STLDeleteValues(&properties_);
-}
-
-const PolicySchemaMap* DictionaryPolicySchema::GetProperties() const {
-  return &properties_;
-}
-
-const PolicySchema*
-    DictionaryPolicySchema::GetSchemaForAdditionalProperties() const {
-  return additional_properties_.get();
-}
-
-// static
-scoped_ptr<PolicySchema> DictionaryPolicySchema::Parse(
-    const base::DictionaryValue& schema,
-    std::string* error) {
-  scoped_ptr<DictionaryPolicySchema> dict_schema(new DictionaryPolicySchema());
-
-  const base::DictionaryValue* dict = NULL;
-  const base::DictionaryValue* properties = NULL;
-  if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) {
-    for (base::DictionaryValue::Iterator it(*properties);
-         !it.IsAtEnd(); it.Advance()) {
-      // This should have been verified by the JSONSchemaValidator.
-      CHECK(it.value().GetAsDictionary(&dict));
-      scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error);
-      if (!sub_schema)
-        return scoped_ptr<PolicySchema>();
-      dict_schema->properties_[it.key()] = sub_schema.release();
-    }
-  }
-
-  if (schema.GetDictionary(json_schema_constants::kAdditionalProperties,
-                           &dict)) {
-    scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error);
-    if (!sub_schema)
-      return scoped_ptr<PolicySchema>();
-    dict_schema->additional_properties_ = sub_schema.Pass();
-  }
-
-  return dict_schema.PassAs<PolicySchema>();
-}
-
-ListPolicySchema::ListPolicySchema()
-    : PolicySchema(base::Value::TYPE_LIST) {}
-
-ListPolicySchema::~ListPolicySchema() {}
-
-const PolicySchema* ListPolicySchema::GetSchemaForItems() const {
-  return items_schema_.get();
-}
-
-scoped_ptr<PolicySchema> ListPolicySchema::Parse(
-    const base::DictionaryValue& schema,
-    std::string* error) {
-  const base::DictionaryValue* dict = NULL;
-  if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) {
-    *error = "Arrays must declare a single schema for their items.";
-    return scoped_ptr<PolicySchema>();
-  }
-  scoped_ptr<PolicySchema> items_schema = ParseSchema(*dict, error);
-  if (!items_schema)
-    return scoped_ptr<PolicySchema>();
-
-  scoped_ptr<ListPolicySchema> list_schema(new ListPolicySchema());
-  list_schema->items_schema_ = items_schema.Pass();
-  return list_schema.PassAs<PolicySchema>();
-}
-
-}  // namespace
-
-PolicySchema::PolicySchema(base::Value::Type type)
-    : type_(type) {}
-
-PolicySchema::~PolicySchema() {}
-
-const PolicySchemaMap* PolicySchema::GetProperties() const {
-  NOTREACHED();
-  return NULL;
-}
-
-const PolicySchema* PolicySchema::GetSchemaForAdditionalProperties() const {
-  NOTREACHED();
-  return NULL;
-}
-
-const PolicySchema* PolicySchema::GetSchemaForProperty(
-    const std::string& key) const {
-  const PolicySchemaMap* properties = GetProperties();
-  PolicySchemaMap::const_iterator it = properties->find(key);
-  return it == properties->end() ? GetSchemaForAdditionalProperties()
-                                 : it->second;
-}
-
-const PolicySchema* PolicySchema::GetSchemaForItems() const {
-  NOTREACHED();
-  return NULL;
-}
-
-// static
-scoped_ptr<PolicySchema> PolicySchema::Parse(const std::string& content,
-                                             std::string* error) {
-  // Validate as a generic JSON schema.
-  scoped_ptr<base::DictionaryValue> dict =
-      JSONSchemaValidator::IsValidSchema(content, error);
-  if (!dict)
-    return scoped_ptr<PolicySchema>();
-
-  // Validate the schema version.
-  std::string string_value;
-  if (!dict->GetString(json_schema_constants::kSchema, &string_value) ||
-      string_value != kJSONSchemaVersion) {
-    *error = "Must declare JSON Schema v3 version in \"$schema\".";
-    return scoped_ptr<PolicySchema>();
-  }
-
-  // Validate the main type.
-  if (!dict->GetString(json_schema_constants::kType, &string_value) ||
-      string_value != json_schema_constants::kObject) {
-    *error =
-        "The main schema must have a type attribute with \"object\" value.";
-    return scoped_ptr<PolicySchema>();
-  }
-
-  // Checks for invalid attributes at the top-level.
-  if (dict->HasKey(json_schema_constants::kAdditionalProperties) ||
-      dict->HasKey(json_schema_constants::kPatternProperties)) {
-    *error = "\"additionalProperties\" and \"patternProperties\" are not "
-             "supported at the main schema.";
-    return scoped_ptr<PolicySchema>();
-  }
-
-  return ParseSchema(*dict, error);
-}
-
-}  // namespace policy
diff --git a/chrome/common/policy/policy_schema.h b/chrome/common/policy/policy_schema.h
deleted file mode 100644
index 75db591..0000000
--- a/chrome/common/policy/policy_schema.h
+++ /dev/null
@@ -1,69 +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_POLICY_POLICY_SCHEMA_H_
-#define CHROME_COMMON_POLICY_POLICY_SCHEMA_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/values.h"
-
-namespace policy {
-
-class PolicySchema;
-typedef std::map<std::string, PolicySchema*> PolicySchemaMap;
-
-// Maps known policy keys to their expected types, and recursively describes
-// the known keys within dictionary or list types.
-class PolicySchema {
- public:
-
-  // Parses |schema| as a JSON v3 schema, and additionally verifies that:
-  // - the version is JSON schema v3;
-  // - the top-level entry is of type "object";
-  // - the top-level object doesn't contain "additionalProperties" nor
-  //   "patternProperties";
-  // - each "property" maps to a schema with one "type";
-  // - the type "any" is not used.
-  // If all the checks pass then the parsed PolicySchema is returned; otherwise
-  // returns NULL.
-  static scoped_ptr<PolicySchema> Parse(const std::string& schema,
-                                        std::string* error);
-
-  explicit PolicySchema(base::Value::Type type);
-  virtual ~PolicySchema();
-
-  // Returns the expected type for this policy. At the top-level PolicySchema
-  // this is always TYPE_DICTIONARY.
-  base::Value::Type type() const { return type_; }
-
-  // It is invalid to call these methods when type() is not TYPE_DICTIONARY.
-  //
-  // GetProperties() returns a map of the known property names to their schemas;
-  // the map is never NULL.
-  // GetSchemaForAdditionalProperties() returns the schema that should be used
-  // for keys not found in the map, and may be NULL.
-  // GetSchemaForProperty() is a utility method that combines both, returning
-  // the mapped schema if found in GetProperties(), otherwise returning
-  // GetSchemaForAdditionalProperties().
-  virtual const PolicySchemaMap* GetProperties() const;
-  virtual const PolicySchema* GetSchemaForAdditionalProperties() const;
-  const PolicySchema* GetSchemaForProperty(const std::string& key) const;
-
-  // It is invalid to call this method when type() is not TYPE_LIST.
-  // Returns the type of the entries of this "array", which is never NULL.
-  virtual const PolicySchema* GetSchemaForItems() const;
-
- private:
-  const base::Value::Type type_;
-
-  DISALLOW_COPY_AND_ASSIGN(PolicySchema);
-};
-
-}  // namespace policy
-
-#endif  // CHROME_COMMON_POLICY_POLICY_SCHEMA_H_
diff --git a/chrome/common/policy/policy_schema_unittest.cc b/chrome/common/policy/policy_schema_unittest.cc
deleted file mode 100644
index 9f515a2..0000000
--- a/chrome/common/policy/policy_schema_unittest.cc
+++ /dev/null
@@ -1,194 +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/policy/policy_schema.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace policy {
-
-namespace {
-
-#define SCHEMA_VERSION "\"$schema\":\"http://json-schema.org/draft-03/schema#\""
-#define OBJECT_TYPE "\"type\":\"object\""
-
-bool ParseFails(const std::string& content) {
-  std::string error;
-  scoped_ptr<PolicySchema> schema = PolicySchema::Parse(content, &error);
-  EXPECT_TRUE(schema || !error.empty());
-  return !schema;
-}
-
-}  // namespace
-
-TEST(PolicySchemaTest, MinimalSchema) {
-  EXPECT_FALSE(ParseFails(
-      "{"
-        SCHEMA_VERSION ","
-        OBJECT_TYPE
-      "}"));
-}
-
-TEST(PolicySchemaTest, InvalidSchemas) {
-  EXPECT_TRUE(ParseFails(""));
-  EXPECT_TRUE(ParseFails("omg"));
-  EXPECT_TRUE(ParseFails("\"omg\""));
-  EXPECT_TRUE(ParseFails("123"));
-  EXPECT_TRUE(ParseFails("[]"));
-  EXPECT_TRUE(ParseFails("null"));
-  EXPECT_TRUE(ParseFails("{}"));
-  EXPECT_TRUE(ParseFails("{" SCHEMA_VERSION "}"));
-  EXPECT_TRUE(ParseFails("{" OBJECT_TYPE "}"));
-
-  EXPECT_TRUE(ParseFails(
-      "{"
-        SCHEMA_VERSION ","
-        OBJECT_TYPE ","
-        "\"additionalProperties\": { \"type\":\"object\" }"
-      "}"));
-
-  EXPECT_TRUE(ParseFails(
-      "{"
-        SCHEMA_VERSION ","
-        OBJECT_TYPE ","
-        "\"patternProperties\": { \"a+b*\": { \"type\": \"object\" } }"
-      "}"));
-
-  EXPECT_TRUE(ParseFails(
-      "{"
-        SCHEMA_VERSION ","
-        OBJECT_TYPE ","
-        "\"properties\": { \"Policy\": { \"type\": \"bogus\" } }"
-      "}"));
-
-  EXPECT_TRUE(ParseFails(
-      "{"
-        SCHEMA_VERSION ","
-        OBJECT_TYPE ","
-        "\"properties\": { \"Policy\": { \"type\": [\"string\", \"number\"] } }"
-      "}"));
-
-  EXPECT_TRUE(ParseFails(
-      "{"
-        SCHEMA_VERSION ","
-        OBJECT_TYPE ","
-        "\"properties\": { \"Policy\": { \"type\": \"any\" } }"
-      "}"));
-}
-
-TEST(PolicySchemaTest, ValidSchema) {
-  std::string error;
-  scoped_ptr<PolicySchema> schema = PolicySchema::Parse(
-      "{"
-        SCHEMA_VERSION ","
-        OBJECT_TYPE ","
-        "\"properties\": {"
-        "  \"Boolean\": { \"type\": \"boolean\" },"
-        "  \"Integer\": { \"type\": \"integer\" },"
-        "  \"Null\": { \"type\": \"null\" },"
-        "  \"Number\": { \"type\": \"number\" },"
-        "  \"String\": { \"type\": \"string\" },"
-        "  \"Array\": {"
-        "    \"type\": \"array\","
-        "    \"items\": { \"type\": \"string\" }"
-        "  },"
-        "  \"ArrayOfObjects\": {"
-        "    \"type\": \"array\","
-        "    \"items\": {"
-        "      \"type\": \"object\","
-        "      \"properties\": {"
-        "        \"one\": { \"type\": \"string\" },"
-        "        \"two\": { \"type\": \"integer\" }"
-        "      }"
-        "    }"
-        "  },"
-        "  \"ArrayOfArray\": {"
-        "    \"type\": \"array\","
-        "    \"items\": {"
-        "      \"type\": \"array\","
-        "      \"items\": { \"type\": \"string\" }"
-        "    }"
-        "  },"
-        "  \"Object\": {"
-        "    \"type\": \"object\","
-        "    \"properties\": {"
-        "      \"one\": { \"type\": \"boolean\" },"
-        "      \"two\": { \"type\": \"integer\" }"
-        "    },"
-        "    \"additionalProperties\": { \"type\": \"string\" }"
-        "  }"
-        "}"
-      "}", &error);
-  ASSERT_TRUE(schema) << error;
-
-  ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema->type());
-  EXPECT_FALSE(schema->GetSchemaForProperty("invalid"));
-
-  const PolicySchema* sub = schema->GetSchemaForProperty("Boolean");
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_BOOLEAN, sub->type());
-
-  sub = schema->GetSchemaForProperty("Integer");
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_INTEGER, sub->type());
-
-  sub = schema->GetSchemaForProperty("Null");
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_NULL, sub->type());
-
-  sub = schema->GetSchemaForProperty("Number");
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_DOUBLE, sub->type());
-  sub = schema->GetSchemaForProperty("String");
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_STRING, sub->type());
-
-  sub = schema->GetSchemaForProperty("Array");
-  ASSERT_TRUE(sub);
-  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
-  sub = sub->GetSchemaForItems();
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_STRING, sub->type());
-
-  sub = schema->GetSchemaForProperty("ArrayOfObjects");
-  ASSERT_TRUE(sub);
-  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
-  sub = sub->GetSchemaForItems();
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_DICTIONARY, sub->type());
-  const PolicySchema* subsub = sub->GetSchemaForProperty("one");
-  ASSERT_TRUE(subsub);
-  EXPECT_EQ(base::Value::TYPE_STRING, subsub->type());
-  subsub = sub->GetSchemaForProperty("two");
-  ASSERT_TRUE(subsub);
-  EXPECT_EQ(base::Value::TYPE_INTEGER, subsub->type());
-  subsub = sub->GetSchemaForProperty("invalid");
-  EXPECT_FALSE(subsub);
-
-  sub = schema->GetSchemaForProperty("ArrayOfArray");
-  ASSERT_TRUE(sub);
-  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
-  sub = sub->GetSchemaForItems();
-  ASSERT_TRUE(sub);
-  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
-  sub = sub->GetSchemaForItems();
-  ASSERT_TRUE(sub);
-  EXPECT_EQ(base::Value::TYPE_STRING, sub->type());
-
-  sub = schema->GetSchemaForProperty("Object");
-  ASSERT_TRUE(sub);
-  ASSERT_EQ(base::Value::TYPE_DICTIONARY, sub->type());
-  subsub = sub->GetSchemaForProperty("one");
-  ASSERT_TRUE(subsub);
-  EXPECT_EQ(base::Value::TYPE_BOOLEAN, subsub->type());
-  subsub = sub->GetSchemaForProperty("two");
-  ASSERT_TRUE(subsub);
-  EXPECT_EQ(base::Value::TYPE_INTEGER, subsub->type());
-  subsub = sub->GetSchemaForProperty("undeclared");
-  ASSERT_TRUE(subsub);
-  EXPECT_EQ(base::Value::TYPE_STRING, subsub->type());
-}
-
-}  // namespace policy
-
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 65b4c93..1376a4c 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -411,6 +411,11 @@
 const char kDefaultSearchProviderImageURL[] =
     "default_search_provider.image_url";
 
+// The URL (as understood by TemplateURLRef) the default search provider uses
+// for the new tab page.
+const char kDefaultSearchProviderNewTabURL[] =
+    "default_search_provider.new_tab_url";
+
 // The string of post parameters (as understood by TemplateURLRef) the default
 // search provider uses for searches by using POST.
 const char kDefaultSearchProviderSearchURLPostParams[] =
@@ -1292,6 +1297,14 @@
 extern const char kMessageCenterEnabledSyncNotifierIds[] =
     "message_center.enabled_sync_notifier_ids";
 
+// Dictionary pref that keeps track of per-extension settings. The keys are
+// extension ids.
+const char kExtensionsPref[] = "extensions.settings";
+
+// String pref for what version chrome was last time the extension prefs were
+// loaded.
+const char kExtensionsLastChromeVersion[] = "extensions.last_chrome_version";
+
 // *************** LOCAL STATE ***************
 // These are attached to the machine/installation
 
@@ -2544,4 +2557,10 @@
 // A boolean pref that enables the (private) pepper GetDeviceID() call.
 const char kEnableDRM[] = "settings.privacy.drm_enabled";
 
+// A boolean per-profile pref that signals if the watchdog extension is
+// installed and active. We need to know if the watchdog extension active for
+// ActivityLog initialization before the extension system is initialized.
+const char kWatchdogExtensionActive[] =
+    "profile.extensions.activity_log.watchdog_extension_active";
+
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index d1bfbe7..73f6f7b 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -169,6 +169,7 @@
 extern const char kDefaultSearchProviderSuggestURL[];
 extern const char kDefaultSearchProviderInstantURL[];
 extern const char kDefaultSearchProviderImageURL[];
+extern const char kDefaultSearchProviderNewTabURL[];
 extern const char kDefaultSearchProviderSearchURLPostParams[];
 extern const char kDefaultSearchProviderSuggestURLPostParams[];
 extern const char kDefaultSearchProviderInstantURLPostParams[];
@@ -442,6 +443,9 @@
 extern const char kMessageCenterDisabledSystemComponentIds[];
 extern const char kMessageCenterEnabledSyncNotifierIds[];
 
+extern const char kExtensionsPref[];
+extern const char kExtensionsLastChromeVersion[];
+
 // Local state prefs. Please add Profile prefs above instead.
 extern const char kCertRevocationCheckingEnabled[];
 extern const char kCertRevocationCheckingRequiredLocalAnchors[];
@@ -934,6 +938,8 @@
 extern const char kDRMSalt[];
 extern const char kEnableDRM[];
 
+extern const char kWatchdogExtensionActive[];
+
 }  // namespace prefs
 
 #endif  // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/common/print_messages.h b/chrome/common/print_messages.h
index dca63c3..258ee27 100644
--- a/chrome/common/print_messages.h
+++ b/chrome/common/print_messages.h
@@ -370,15 +370,16 @@
                            PrintMsg_PrintPages_Params
                                /* settings chosen by the user*/)
 
-#if defined(USE_X11)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 // Asks the browser to create a temporary file for the renderer to fill
 // in resulting NativeMetafile in printing.
-IPC_SYNC_MESSAGE_CONTROL0_2(PrintHostMsg_AllocateTempFileForPrinting,
+IPC_SYNC_MESSAGE_CONTROL1_2(PrintHostMsg_AllocateTempFileForPrinting,
+                            int /* render_view_id */,
                             base::FileDescriptor /* temp file fd */,
-                            int /* fd in browser*/)
+                            int /* fd in browser*/) // Used only by Chrome OS.
 IPC_MESSAGE_CONTROL2(PrintHostMsg_TempFileForPrintingWritten,
                      int /* render_view_id */,
-                     int /* fd in browser */)
+                     int /* fd in browser */) // Used only by Chrome OS.
 #endif
 
 // Asks the browser to do print preview.
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index e75e566..41de013 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -21,6 +21,7 @@
 #include "chrome/common/content_settings.h"
 #include "chrome/common/content_settings_pattern.h"
 #include "chrome/common/instant_types.h"
+#include "chrome/common/ntp_logging_events.h"
 #include "chrome/common/omnibox_focus_state.h"
 #include "chrome/common/search_provider.h"
 #include "chrome/common/translate/language_detection_details.h"
@@ -229,6 +230,9 @@
   IPC_STRUCT_TRAITS_MEMBER(contents)
 IPC_STRUCT_TRAITS_END()
 
+IPC_ENUM_TRAITS_MAX_VALUE(NTPLoggingEventType,
+                          NTP_NUM_EVENT_TYPES)
+
 //-----------------------------------------------------------------------------
 // RenderView messages
 // These are messages sent from the browser to the renderer process.
@@ -391,6 +395,12 @@
 IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_RequestThumbnailForContextNode_ACK,
                     SkBitmap /* thumbnail */)
 
+#if defined(OS_ANDROID)
+// Asks the renderer to return information about whether the current page can
+// be treated as a webapp.
+IPC_MESSAGE_ROUTED1(ChromeViewMsg_RetrieveWebappInformation,
+                    GURL /* expected_url */)
+#endif  // defined(OS_ANDROID)
 
 // JavaScript related messages -----------------------------------------------
 
@@ -617,6 +627,13 @@
 // a secure origin by a security policy.  The page may appear incomplete.
 IPC_MESSAGE_ROUTED0(ChromeViewHostMsg_DidBlockRunningInsecureContent)
 
+#if defined(OS_ANDROID)
+// Contains info about whether the current page can be treated as a webapp.
+IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_DidRetrieveWebappInformation,
+                    bool /* success */,
+                    bool /* is_webapp_capable */)
+#endif  // defined(OS_ANDROID)
+
 // Message sent from renderer to the browser when the element that is focused
 // has been touched. A bool is passed in this message which indicates if the
 // node is editable.
@@ -663,9 +680,10 @@
                      int /* routing id */,
                      float /* frames per second */)
 
-// Counts a mouseover event on an InstantExtended most visited tile.
-IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_CountMouseover,
-                    int /* page_id */)
+// Logs events from InstantExtended New Tab Pages.
+IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_LogEvent,
+                    int /* page_id */,
+                    NTPLoggingEventType /* event */)
 
 // Tells InstantExtended to set the omnibox focus state.
 IPC_MESSAGE_ROUTED2(ChromeViewHostMsg_FocusOmnibox,
diff --git a/chrome/common/translate/translate_util.cc b/chrome/common/translate/translate_util.cc
index 994e7ea..4391870 100644
--- a/chrome/common/translate/translate_util.cc
+++ b/chrome/common/translate/translate_util.cc
@@ -5,6 +5,9 @@
 #include "chrome/common/translate/translate_util.h"
 
 #include "base/basictypes.h"
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+#include "url/gurl.h"
 
 namespace TranslateUtil {
 
@@ -27,6 +30,8 @@
   {"tl", "fil"},
 };
 
+const char kSecurityOrigin[] = "https://translate.googleapis.com/";
+
 void ToTranslateLanguageSynonym(std::string* language) {
   // Apply liner search here because number of items in the list is just four.
   for (size_t i = 0; i < arraysize(kLanguageCodeSynonyms); ++i) {
@@ -47,4 +52,14 @@
   }
 }
 
+GURL GetTranslateSecurityOrigin() {
+  std::string security_origin(kSecurityOrigin);
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTranslateSecurityOrigin)) {
+    security_origin =
+        command_line->GetSwitchValueASCII(switches::kTranslateSecurityOrigin);
+  }
+  return GURL(security_origin);
+}
+
 }  // namespace TranslateUtil
diff --git a/chrome/common/translate/translate_util.h b/chrome/common/translate/translate_util.h
index be58a61..60a84b8 100644
--- a/chrome/common/translate/translate_util.h
+++ b/chrome/common/translate/translate_util.h
@@ -7,14 +7,22 @@
 
 #include <string>
 
+class GURL;
+
 namespace TranslateUtil {
 
+// Isolated world sets following security-origin by default.
+extern const char kSecurityOrigin[];
+
 // Converts language code synonym to use at Translate server.
 void ToTranslateLanguageSynonym(std::string* language);
 
 // Converts language code synonym to use at Chrome internal.
 void ToChromeLanguageSynonym(std::string* language);
 
-}  // namapace TranslateUtil
+// Get Security origin with which Translate runs.
+GURL GetTranslateSecurityOrigin();
+
+}  // namespace TranslateUtil
 
 #endif  // CHROME_COMMON_TRANSLATE_TRANSLATE_UTIL_H_
diff --git a/chrome/common/translate/translate_util_unittest.cc b/chrome/common/translate/translate_util_unittest.cc
index be710bd..67f7192 100644
--- a/chrome/common/translate/translate_util_unittest.cc
+++ b/chrome/common/translate/translate_util_unittest.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/common/translate/translate_util.h"
 
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 typedef testing::Test TranslateUtilTest;
 
@@ -49,3 +52,15 @@
   TranslateUtil::ToChromeLanguageSynonym(&language);
   EXPECT_EQ("fil", language);
 }
+
+TEST_F(TranslateUtilTest, SecurityOrigin) {
+  GURL origin = TranslateUtil::GetTranslateSecurityOrigin();
+  EXPECT_EQ(std::string(TranslateUtil::kSecurityOrigin), origin.spec());
+
+  const std::string running_origin("http://www.tamurayukari.com/");
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->AppendSwitchASCII(switches::kTranslateSecurityOrigin,
+                                  running_origin);
+  GURL modified_origin = TranslateUtil::GetTranslateSecurityOrigin();
+  EXPECT_EQ(running_origin, modified_origin.spec());
+}
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 1b256d6..711e592 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -17,6 +17,7 @@
 const char kDriveScheme[] = "drive";
 #endif
 
+const char kAboutComponentsURL[] = "about:components";
 const char kAboutPluginsURL[] = "about:plugins";
 const char kAboutVersionURL[] = "about:version";
 
@@ -29,6 +30,7 @@
 const char kChromeUICertificateViewerURL[] = "chrome://view-cert/";
 const char kChromeUIChromeURLsURL[] = "chrome://chrome-urls/";
 const char kChromeUICloudPrintResourcesURL[] = "chrome://cloudprintresources/";
+const char kChromeUIComponentsURL[] = "chrome://components/";
 const char kChromeUIConflictsURL[] = "chrome://conflicts/";
 const char kChromeUIConstrainedHTMLTestURL[] = "chrome://constrained-test/";
 const char kChromeUICrashesURL[] = "chrome://crashes/";
@@ -92,7 +94,6 @@
 
 #if defined(OS_CHROMEOS)
 const char kChromeUIActivationMessage[] = "chrome://activationmessage/";
-const char kChromeUIAppLaunchURL[] = "chrome://app-launch/";
 const char kChromeUIBluetoothPairingURL[] = "chrome://bluetooth-pairing/";
 const char kChromeUIChooseMobileNetworkURL[] =
     "chrome://choose-mobile-network/";
@@ -115,10 +116,6 @@
 const char kChromeUIUserImageURL[] = "chrome://userimage/";
 #endif
 
-#if defined(USE_ASH)
-const char kChromeUITransparencyURL[] = "chrome://transparency/";
-#endif
-
 #if defined(FILE_MANAGER_EXTENSION)
 const char kChromeUIFileManagerURL[] = "chrome://files/";
 #endif
@@ -196,6 +193,7 @@
 const char kChromeUIOmniboxHost[] = "omnibox";
 const char kChromeUIPerformanceMonitorHost[] = "performance";
 const char kChromeUIPluginsHost[] = "plugins";
+const char kChromeUIComponentsHost[] = "components";
 const char kChromeUIPolicyHost[] = "policy";
 const char kChromeUIProfileSigninConfirmationHost[] =
     "profile-signin-confirmation";
@@ -277,10 +275,6 @@
     "https://www.google.com/intl/%s/chrome/eula_text.html";
 #endif
 
-#if defined(USE_ASH)
-const char kChromeUITransparencyHost[] = "transparency";
-#endif
-
 #if defined(FILE_MANAGER_EXTENSION)
 const char kChromeUIFileManagerHost[] = "files";
 #endif
@@ -552,6 +546,7 @@
   kChromeUIFlashHost,
   kChromeUIInspectHost,
   kChromeUIPluginsHost,
+  kChromeUIComponentsHost,
   kChromeUISettingsHost,
 #endif
 #if defined(OS_WIN)
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index dc878ed..0809d6c 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -16,6 +16,7 @@
 namespace chrome {
 
 // TODO(msw): Resolve chrome_frame dependency on these constants.
+extern const char kAboutComponentsURL[];
 extern const char kAboutPluginsURL[];
 extern const char kAboutVersionURL[];
 
@@ -27,6 +28,7 @@
 extern const char kChromeUICertificateViewerURL[];
 extern const char kChromeUIChromeURLsURL[];
 extern const char kChromeUICloudPrintResourcesURL[];
+extern const char kChromeUIComponentsURL[];
 extern const char kChromeUIConflictsURL[];
 extern const char kChromeUIConstrainedHTMLTestURL[];
 extern const char kChromeUICrashesURL[];
@@ -87,7 +89,6 @@
 
 #if defined(OS_CHROMEOS)
 extern const char kChromeUIActivationMessage[];
-extern const char kChromeUIAppLaunchURL[];
 extern const char kChromeUIBluetoothPairingURL[];
 extern const char kChromeUIChooseMobileNetworkURL[];
 extern const char kChromeUIDiagnosticsURL[];
@@ -109,10 +110,6 @@
 extern const char kChromeUIUserImageURL[];
 #endif
 
-#if defined(USE_ASH)
-extern const char kChromeUITransparencyURL[];
-#endif
-
 #if defined(FILE_MANAGER_EXTENSION)
 extern const char kChromeUIFileManagerURL[];
 #endif
@@ -188,6 +185,7 @@
 extern const char kChromeUIOmniboxHost[];
 extern const char kChromeUIPerformanceMonitorHost[];
 extern const char kChromeUIPluginsHost[];
+extern const char kChromeUIComponentsHost[];
 extern const char kChromeUIPolicyHost[];
 extern const char kChromeUIProfileSigninConfirmationHost[];
 extern const char kChromeUIUserManagerHost[];
@@ -268,10 +266,6 @@
 extern const char kOnlineEulaURLPath[];
 #endif
 
-#if defined(USE_ASH)
-extern const char kChromeUITransparencyHost[];
-#endif
-
 #if defined(FILE_MANAGER_EXTENSION)
 extern const char kChromeUIFileManagerHost[];
 #endif
diff --git a/chrome/installer/gcapi/gcapi.cc b/chrome/installer/gcapi/gcapi.cc
index c4a2d6e..1797498 100644
--- a/chrome/installer/gcapi/gcapi.cc
+++ b/chrome/installer/gcapi/gcapi.cc
@@ -38,6 +38,7 @@
 #include "chrome/installer/gcapi/gcapi_reactivation.h"
 #include "chrome/installer/launcher_support/chrome_launcher_support.h"
 #include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/google_update_settings.h"
 #include "chrome/installer/util/util_constants.h"
 #include "chrome/installer/util/wmi.h"
 #include "google_update/google_update_idl.h"
@@ -69,6 +70,15 @@
 const wchar_t kNoChromeOfferUntil[] =
     L"SOFTWARE\\Google\\No Chrome Offer Until";
 
+const wchar_t kC1FPendingKey[] =
+    L"Software\\Google\\Common\\Rlz\\Events\\C";
+const wchar_t kC1FSentKey[] =
+    L"Software\\Google\\Common\\Rlz\\StatefulEvents\\C";
+const wchar_t kC1FKey[] = L"C1F";
+
+const wchar_t kRelaunchBrandcodeValue[] = L"RelaunchBrandcode";
+const wchar_t kRelaunchAllowedAfterValue[] = L"RelaunchAllowedAfter";
+
 // Prefix used to match the window class for Chrome windows.
 const wchar_t kChromeWindowClassPrefix[] = L"Chrome_WidgetWin_";
 
@@ -123,6 +133,22 @@
   return true;
 }
 
+// Offsets the current date by |months|. |months| must be between 0 and 12.
+// The returned date is in the YYYYMMDD format.
+DWORD FormatDateOffsetByMonths(int months) {
+  DCHECK(months >= 0 && months <= 12);
+
+  SYSTEMTIME now;
+  GetLocalTime(&now);
+  now.wMonth += months;
+  if (now.wMonth > 12) {
+    now.wMonth -= 12;
+    now.wYear += 1;
+  }
+
+  return now.wYear * 10000 + now.wMonth * 100 + now.wDay;
+}
+
 // Return true if we can re-offer Chrome; false, otherwise.
 // Each partner can only offer Chrome once every six months.
 bool CanReOfferChrome(BOOL set_flag) {
@@ -144,9 +170,7 @@
       0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
       NULL, &key, &disposition) == ERROR_SUCCESS) {
     // Get today's date, and format it as YYYYMMDD numeric value.
-    SYSTEMTIME now;
-    GetLocalTime(&now);
-    DWORD today = now.wYear * 10000 + now.wMonth * 100 + now.wDay;
+    DWORD today = FormatDateOffsetByMonths(0);
 
     // Cannot re-offer, if the timer already exists and is not expired yet.
     DWORD value_type = REG_DWORD;
@@ -165,13 +189,7 @@
       if (set_flag) {
         // Set expiration date for offer as six months from today,
         // represented as a YYYYMMDD numeric value.
-        SYSTEMTIME timer = now;
-        timer.wMonth = timer.wMonth + 6;
-        if (timer.wMonth > 12) {
-          timer.wMonth = timer.wMonth - 12;
-          timer.wYear = timer.wYear + 1;
-        }
-        DWORD value = timer.wYear * 10000 + timer.wMonth * 100 + timer.wDay;
+        DWORD value = FormatDateOffsetByMonths(6);
         ::RegSetValueEx(key, company, 0, REG_DWORD, (LPBYTE)&value,
                         sizeof(DWORD));
       }
@@ -183,28 +201,30 @@
   return can_re_offer;
 }
 
-// Helper function to read a value from registry. Returns true if value
-// is read successfully and stored in parameter value. Returns false otherwise.
-bool ReadValueFromRegistry(HKEY root_key, const wchar_t* sub_key,
-                           const wchar_t* value_name, wchar_t* value,
-                           size_t* size) {
-  HKEY key;
-  if ((::RegOpenKeyEx(root_key, sub_key, NULL,
-                      KEY_READ, &key) == ERROR_SUCCESS) &&
-      (::RegQueryValueEx(key, value_name, NULL, NULL,
-                         reinterpret_cast<LPBYTE>(value),
-                         reinterpret_cast<LPDWORD>(size)) == ERROR_SUCCESS)) {
-    ::RegCloseKey(key);
-    return true;
-  }
-  return false;
+bool IsChromeInstalled(HKEY root_key) {
+  RegKey key;
+  return key.Open(root_key, kChromeRegClientsKey, KEY_READ) == ERROR_SUCCESS &&
+         key.HasValue(kChromeRegVersion);
 }
 
-bool IsChromeInstalled(HKEY root_key) {
-  wchar_t version[64];
-  size_t size = _countof(version);
-  return ReadValueFromRegistry(root_key, kChromeRegClientsKey,
-                               kChromeRegVersion, version, &size);
+// Returns true if the |subkey| in |root| has the kC1FKey entry set to 1.
+bool RegKeyHasC1F(HKEY root, const wchar_t* subkey) {
+  RegKey key;
+  DWORD value;
+  return key.Open(root, subkey, KEY_READ) == ERROR_SUCCESS &&
+      key.ReadValueDW(kC1FKey, &value) == ERROR_SUCCESS &&
+      value == static_cast<DWORD>(1);
+}
+
+bool IsC1FSent() {
+  // The C1F RLZ key can either be in HKCU or in HKLM (the HKLM RLZ key is made
+  // readable to all-users via rlz_lib::CreateMachineState()) and can either be
+  // in sent or pending state. Return true if there is a match for any of these
+  // 4 states.
+  return RegKeyHasC1F(HKEY_CURRENT_USER, kC1FSentKey) ||
+      RegKeyHasC1F(HKEY_CURRENT_USER, kC1FPendingKey) ||
+      RegKeyHasC1F(HKEY_LOCAL_MACHINE, kC1FSentKey) ||
+      RegKeyHasC1F(HKEY_LOCAL_MACHINE, kC1FPendingKey);
 }
 
 enum WindowsVersion {
@@ -666,3 +686,104 @@
 
   return result;
 }
+
+BOOL __stdcall CanOfferRelaunch(const wchar_t** partner_brandcode_list,
+                                int partner_brandcode_list_length,
+                                int shell_mode,
+                                DWORD* error_code) {
+  DCHECK(error_code);
+
+  if (!partner_brandcode_list || partner_brandcode_list_length <= 0) {
+    if (error_code)
+      *error_code = RELAUNCH_ERROR_INVALID_INPUT;
+    return FALSE;
+  }
+
+  // These conditions need to be satisfied for relaunch:
+  // a) Chrome should be installed;
+  if (!IsChromeInstalled(HKEY_LOCAL_MACHINE) &&
+      (shell_mode != GCAPI_INVOKED_STANDARD_SHELL ||
+          !IsChromeInstalled(HKEY_CURRENT_USER))) {
+    if (error_code)
+      *error_code = RELAUNCH_ERROR_NOTINSTALLED;
+    return FALSE;
+  }
+
+  // b) the installed brandcode should belong to that partner (in
+  // brandcode_list);
+  std::wstring installed_brandcode;
+  bool valid_brandcode = false;
+  if (GoogleUpdateSettings::GetBrand(&installed_brandcode)) {
+    for (int i = 0; i < partner_brandcode_list_length; ++i) {
+      if (!_wcsicmp(installed_brandcode.c_str(), partner_brandcode_list[i])) {
+        valid_brandcode = true;
+        break;
+      }
+    }
+  }
+
+  if (!valid_brandcode) {
+    if (error_code)
+      *error_code = RELAUNCH_ERROR_INVALID_PARTNER;
+    return FALSE;
+  }
+
+  // c) C1F ping should not have been sent;
+  if (IsC1FSent()) {
+    if (error_code)
+      *error_code = RELAUNCH_ERROR_PINGS_SENT;
+    return FALSE;
+  }
+
+  // d) a minimum period (30 days) must have passed since Chrome was last used;
+  int days_since_last_run = GoogleChromeDaysSinceLastRun();
+  if (days_since_last_run >= 0 &&
+      days_since_last_run < kRelaunchMinDaysDormant) {
+    if (error_code)
+      *error_code = RELAUNCH_ERROR_NOTDORMANT;
+    return FALSE;
+  }
+
+  // e) a minimum period (6 months) must have passed since the previous
+  // relaunch offer for the current user;
+  RegKey key;
+  DWORD min_relaunch_date;
+  if (key.Open(HKEY_CURRENT_USER, kChromeRegClientStateKey,
+               KEY_QUERY_VALUE) == ERROR_SUCCESS &&
+      key.ReadValueDW(kRelaunchAllowedAfterValue,
+                      &min_relaunch_date) == ERROR_SUCCESS &&
+      FormatDateOffsetByMonths(0) < min_relaunch_date) {
+    if (error_code)
+      *error_code = RELAUNCH_ERROR_ALREADY_RELAUNCHED;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+BOOL __stdcall SetRelaunchOffered(const wchar_t** partner_brandcode_list,
+                                  int partner_brandcode_list_length,
+                                  const wchar_t* relaunch_brandcode,
+                                  int shell_mode,
+                                  DWORD* error_code) {
+  if (!CanOfferRelaunch(partner_brandcode_list, partner_brandcode_list_length,
+                        shell_mode, error_code))
+    return FALSE;
+
+  // Store the relaunched brand code and the minimum date for relaunch (6 months
+  // from now), and set the Omaha experiment label.
+  RegKey key;
+  if (key.Create(HKEY_CURRENT_USER, kChromeRegClientStateKey,
+                 KEY_SET_VALUE) != ERROR_SUCCESS ||
+      key.WriteValue(kRelaunchBrandcodeValue,
+                     relaunch_brandcode) != ERROR_SUCCESS ||
+      key.WriteValue(kRelaunchAllowedAfterValue,
+                     FormatDateOffsetByMonths(6)) != ERROR_SUCCESS ||
+      !SetRelaunchExperimentLabels(relaunch_brandcode, shell_mode)) {
+    if (error_code)
+      *error_code = RELAUNCH_ERROR_RELAUNCH_FAILED;
+    return FALSE;
+  }
+
+  return TRUE;
+}
diff --git a/chrome/installer/gcapi/gcapi.def b/chrome/installer/gcapi/gcapi.def
index e6abeae..2270c86 100644
--- a/chrome/installer/gcapi/gcapi.def
+++ b/chrome/installer/gcapi/gcapi.def
@@ -8,3 +8,5 @@
   GoogleChromeDaysSinceLastRun
   CanOfferReactivation
   ReactivateChrome
+  CanOfferRelaunch
+  SetRelaunchOffered
diff --git a/chrome/installer/gcapi/gcapi.h b/chrome/installer/gcapi/gcapi.h
index 1951c5b..a35293e 100644
--- a/chrome/installer/gcapi/gcapi.h
+++ b/chrome/installer/gcapi/gcapi.h
@@ -22,6 +22,15 @@
 #define REACTIVATE_ERROR_INVALID_INPUT           (1 << 3)
 #define REACTIVATE_ERROR_REACTIVATION_FAILED     (1 << 4)
 
+// Error conditions for CanOfferRelaunch().
+#define RELAUNCH_ERROR_NOTINSTALLED              (1 << 0)
+#define RELAUNCH_ERROR_INVALID_PARTNER           (1 << 1)
+#define RELAUNCH_ERROR_PINGS_SENT                (1 << 2)
+#define RELAUNCH_ERROR_NOTDORMANT                (1 << 3)
+#define RELAUNCH_ERROR_ALREADY_RELAUNCHED        (1 << 4)
+#define RELAUNCH_ERROR_INVALID_INPUT             (1 << 5)
+#define RELAUNCH_ERROR_RELAUNCH_FAILED           (1 << 6)
+
 // Flags to indicate how GCAPI is invoked
 #define GCAPI_INVOKED_STANDARD_SHELL             (1 << 0)
 #define GCAPI_INVOKED_UAC_ELEVATION              (1 << 1)
@@ -34,6 +43,10 @@
 // may be offered.
 const int kReactivationMinDaysDormant = 50;
 
+// The minimum number of days an installation can be dormant before a relaunch
+// may be offered.
+const int kRelaunchMinDaysDormant = 30;
+
 // This function returns TRUE if Google Chrome should be offered.
 // If the return is FALSE, the |reasons| DWORD explains why.  If you don't care
 // for the reason, you can pass NULL for |reasons|.
@@ -104,6 +117,33 @@
                                 int shell_mode,
                                 DWORD* error_code);
 
+// Returns true if a vendor may offer relaunch at this time. Returns false if
+// the vendor may not offer relaunching at this time, and places one of the
+// RELAUNCH_ERROR_XXX values in |error_code| if |error_code| is non-null. The
+// installed brandcode must be in |partner_brandcode_list|. |shell_mode| should
+// be set to one of GCAPI_INVOKED_STANDARD_SHELL or GCAPI_INVOKED_UAC_ELEVATION
+// depending on whether this method is invoked from an elevated or non-elevated
+// process.
+BOOL __stdcall CanOfferRelaunch(const wchar_t** partner_brandcode_list,
+                                int partner_brandcode_list_length,
+                                int shell_mode,
+                                DWORD* error_code);
+
+// Returns true if a vendor may relaunch at this time (and stores that a
+// relaunch was offered). Returns false if the vendor may not relaunch
+// at this time, and places one of the RELAUNCH_ERROR_XXX values in |error_code|
+// if |error_code| is non-null. As for |CanOfferRelaunch|, the installed
+// brandcode must be in |partner_brandcode_list|. |shell_mode| should be set to
+// one of GCAPI_INVOKED_STANDARD_SHELL or GCAPI_INVOKED_UAC_ELEVATION depending
+// on whether this method is invoked from an elevated or non-elevated process.
+// The |relaunch_brandcode| will be stored as the brandcode that was used for
+// offering this relaunch.
+BOOL __stdcall SetRelaunchOffered(const wchar_t** partner_brandcode_list,
+                                  int partner_brandcode_list_length,
+                                  const wchar_t* relaunch_brandcode,
+                                  int shell_mode,
+                                  DWORD* error_code);
+
 // Function pointer type declarations to use with GetProcAddress.
 typedef BOOL (__stdcall *GCCC_CompatibilityCheck)(BOOL, int, DWORD *);
 typedef BOOL (__stdcall *GCCC_LaunchGC)();
@@ -116,6 +156,15 @@
 typedef BOOL (__stdcall *GCCC_ReactivateChrome)(const wchar_t*,
                                                 int,
                                                 DWORD*);
+typedef BOOL (__stdcall *GCCC_CanOfferRelaunch)(const wchar_t**,
+                                                int,
+                                                int,
+                                                DWORD*);
+typedef BOOL (__stdcall *GCCC_SetRelaunchOffered)(const wchar_t**,
+                                                  int,
+                                                  const wchar_t*,
+                                                  int,
+                                                  DWORD*);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/chrome/installer/gcapi/gcapi_omaha_experiment.cc b/chrome/installer/gcapi/gcapi_omaha_experiment.cc
index 5314922..ac5899f 100644
--- a/chrome/installer/gcapi/gcapi_omaha_experiment.cc
+++ b/chrome/installer/gcapi/gcapi_omaha_experiment.cc
@@ -24,10 +24,7 @@
   return delta.InDays() / 7;
 }
 
-}  // namespace
-
-bool SetReactivationExperimentLabels(const wchar_t* brand_code,
-                                     int shell_mode) {
+bool SetLabel(const wchar_t* brand_code, const wchar_t* label, int shell_mode) {
   if (!brand_code) {
     return false;
   }
@@ -38,7 +35,8 @@
 
   string16 experiment_labels;
   base::SStringPrintf(&experiment_labels,
-                      L"reacbrand=%ls_%d|%ls",
+                      L"%ls=%ls_%d|%ls",
+                      label,
                       brand_code,
                       week_number,
                       installer::BuildExperimentDateString().c_str());
@@ -47,3 +45,14 @@
       shell_mode == GCAPI_INVOKED_UAC_ELEVATION,
       experiment_labels);
 }
+
+}  // namespace
+
+bool SetReactivationExperimentLabels(const wchar_t* brand_code,
+                                     int shell_mode) {
+  return SetLabel(brand_code, L"reacbrand", shell_mode);
+}
+
+bool SetRelaunchExperimentLabels(const wchar_t* brand_code, int shell_mode) {
+  return SetLabel(brand_code, L"relaunchbrand", shell_mode);
+}
diff --git a/chrome/installer/gcapi/gcapi_omaha_experiment.h b/chrome/installer/gcapi/gcapi_omaha_experiment.h
index 4d4be8a..babe41e 100644
--- a/chrome/installer/gcapi/gcapi_omaha_experiment.h
+++ b/chrome/installer/gcapi/gcapi_omaha_experiment.h
@@ -9,7 +9,16 @@
 // binaries registry keys for |brand_code|. This experiment label will have a
 // expiration date of now plus one year. If |shell_mode| is set to
 // GCAPI_INVOKED_UAC_ELEVATION, the value will be written to HKLM, otherwise
-// HKCU.
+// HKCU. A user cannot have both a reactivation label and a relaunch label set
+// at the same time (they are mutually exclusive).
 bool SetReactivationExperimentLabels(const wchar_t* brand_code, int shell_mode);
 
+// Writes a relaunch brand code experiment label in the Chrome product and
+// binaries registry keys for |brand_code|. This experiment label will have a
+// expiration date of now plus one year. If |shell_mode| is set to
+// GCAPI_INVOKED_UAC_ELEVATION, the value will be written to HKLM, otherwise
+// HKCU. A user cannot have both a reactivation label and a relaunch label set
+// at the same time (they are mutually exclusive).
+bool SetRelaunchExperimentLabels(const wchar_t* brand_code, int shell_mode);
+
 #endif  // CHROME_INSTALLER_GCAPI_GCAPI_OMAHA_EXPERIMENT_H_
diff --git a/chrome/installer/gcapi/gcapi_reactivation_test.cc b/chrome/installer/gcapi/gcapi_reactivation_test.cc
index cc552df..92987a2 100644
--- a/chrome/installer/gcapi/gcapi_reactivation_test.cc
+++ b/chrome/installer/gcapi/gcapi_reactivation_test.cc
@@ -22,17 +22,6 @@
 using base::TimeDelta;
 using base::win::RegKey;
 
-namespace {
-
-const wchar_t kExperimentLabels[] = L"experiment_labels";
-
-const wchar_t* kExperimentAppGuids[] = {
-    L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}",
-    L"{8A69D345-D564-463C-AFF1-A69D9E530F96}",
-};
-
-}
-
 class GCAPIReactivationTest : public ::testing::Test {
  protected:
   void SetUp() {
@@ -79,21 +68,15 @@
   }
 
   bool HasExperimentLabels(HKEY hive) {
-    int label_count = 0;
-    for (int i = 0; i < arraysize(kExperimentAppGuids); ++i) {
-      string16 client_state_path(google_update::kRegPathClientState);
-      client_state_path += L"\\";
-      client_state_path += kExperimentAppGuids[i];
+    string16 client_state_path(google_update::kRegPathClientState);
+    client_state_path.push_back(L'\\');
+    client_state_path.append(google_update::kChromeUpgradeCode);
 
-      RegKey client_state_key(hive,
-                              client_state_path.c_str(),
-                              KEY_QUERY_VALUE);
-      if (client_state_key.Valid() &&
-          client_state_key.HasValue(kExperimentLabels)) {
-        label_count++;
-      }
-    }
-    return label_count == arraysize(kExperimentAppGuids);
+    RegKey client_state_key(hive,
+                            client_state_path.c_str(),
+                            KEY_QUERY_VALUE);
+    return client_state_key.Valid() &&
+        client_state_key.HasValue(google_update::kExperimentLabels);
   }
 
   std::wstring GetReactivationString(HKEY hive) {
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include
index c5ec0f6..561b42a 100644
--- a/chrome/installer/linux/common/installer.include
+++ b/chrome/installer/linux/common/installer.include
@@ -118,7 +118,6 @@
   rm "${DEBUGFILE}" "${STRIPPEDFILE}"
 
   # resources
-  install -m 644 "${BUILDDIR}/${PROGNAME}.pak" "${STAGEDIR}/${INSTALLDIR}/"
   install -m 644 "${BUILDDIR}/resources.pak" "${STAGEDIR}/${INSTALLDIR}/"
   # TODO(mmoss): This has broken a couple times on adding new .pak files. Maybe
   # we should flag all installer files in FILES.cfg and get them from there, so
diff --git a/chrome/installer/linux/debian/expected_deps b/chrome/installer/linux/debian/expected_deps
index 0e16912..f545951 100644
--- a/chrome/installer/linux/debian/expected_deps
+++ b/chrome/installer/linux/debian/expected_deps
@@ -26,3 +26,4 @@
 libxfixes3
 libxrender1
 libxss1
+libxtst6
diff --git a/chrome/installer/linux/rpm/expected_deps_i386 b/chrome/installer/linux/rpm/expected_deps_i386
index a2434cf..b2d7944 100644
--- a/chrome/installer/linux/rpm/expected_deps_i386
+++ b/chrome/installer/linux/rpm/expected_deps_i386
@@ -70,3 +70,4 @@
 libXfixes.so.3
 libXrender.so.1
 libXss.so.1
+libXtst.so.6
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index e1cc80c..0d0fac3 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -60,3 +60,4 @@
 libXfixes.so.3()(64bit)
 libXrender.so.1()(64bit)
 libXss.so.1()(64bit)
+libXtst.so.6()(64bit)
diff --git a/chrome/installer/mini_installer.gyp b/chrome/installer/mini_installer.gyp
index 05d54d2..5f84d34 100644
--- a/chrome/installer/mini_installer.gyp
+++ b/chrome/installer/mini_installer.gyp
@@ -61,7 +61,6 @@
             ],
             'DelayLoadDLLs': [],
             'EntryPointSymbol': 'MainEntryPoint',
-            'GenerateMapFile': 'true',
             'IgnoreAllDefaultLibraries': 'true',
             'OptimizeForWindows98': '1',
             'SubSystem': '2',     # Set /SUBSYSTEM:WINDOWS
@@ -177,7 +176,13 @@
 
           # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
           'msvs_disabled_warnings': [ 4267, ],
-          
+
+          'variables': {
+            # Opt out the common compatibility manifest to work around
+            # crbug.com/272660.
+            # TODO(yukawa): Enable the common compatibility manifest again.
+            'win_exe_compatibility_manifest': '',
+          },
           'sources': [
             'mini_installer/chrome.release',
             'mini_installer/chrome_appid.cc',
diff --git a/chrome/installer/mini_installer.gypi b/chrome/installer/mini_installer.gypi
index ee9403c..78d90ff 100644
--- a/chrome/installer/mini_installer.gypi
+++ b/chrome/installer/mini_installer.gypi
@@ -48,7 +48,6 @@
     },
     'VCLinkerTool': {
       'OutputFile': '<(output_dir)/mini_installer.exe',
-      'MapFileName': '<(output_dir)/mini_installer.map',
       'RandomizedBaseAddress': '1',
       'DataExecutionPrevention': '0',
       'AdditionalLibraryDirectories': [
@@ -56,7 +55,6 @@
       ],
       'DelayLoadDLLs': [],
       'EntryPointSymbol': 'MainEntryPoint',
-      'GenerateMapFile': 'true',
       'IgnoreAllDefaultLibraries': 'true',
       'OptimizeForWindows98': '1',
       'SubSystem': '2',  # Set /SUBSYSTEM:WINDOWS
diff --git a/chrome/installer/mini_installer/mini_installer.exe.manifest b/chrome/installer/mini_installer/mini_installer.exe.manifest
index afb780f..8ff4c45 100644
--- a/chrome/installer/mini_installer/mini_installer.exe.manifest
+++ b/chrome/installer/mini_installer/mini_installer.exe.manifest
@@ -1,6 +1,23 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-  <!--The compatibility section will be merged from build/win/compatibility.manifest -->
+  <!--
+    Have compatibility section here instead of using
+      build/win/compatibility.manifest
+    to work around crbug.com/272660.
+    TODO(yukawa): Use build/win/compatibility.manifest again.
+  -->
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!--The ID below indicates application support for Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+      <!--The ID below indicates application support for Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+      <!--The ID below indicates application support for Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <!--The ID below indicates application support for Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+    </application>
+  </compatibility>
   <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
     <ms_asmv2:security>
       <ms_asmv2:requestedPrivileges>
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 15e2062..688df1c 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -87,7 +87,7 @@
   if (properties.has_shortcut_name())
     message.append(UTF16ToUTF8(properties.shortcut_name));
   else
-    message.append(UTF16ToUTF8(dist->GetAppShortCutName()));
+    message.append(UTF16ToUTF8(dist->GetDisplayName()));
   message.push_back('"');
 
   message.append(" shortcut to ");
@@ -330,7 +330,7 @@
         BrowserDistribution::CHROME_BROWSER);
     // TODO(grt): http://crbug.com/75152 Write a reference to a localized
     // resource for |display_name|.
-    string16 display_name(dist->GetAppShortCutName());
+    string16 display_name(dist->GetDisplayName());
     EscapeXmlAttributeValueInSingleQuotes(&display_name);
 
     // Fill the manifest with the desired values.
@@ -411,8 +411,11 @@
   if (!do_not_create_desktop_shortcut ||
       shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) {
     ShellUtil::ShortcutProperties desktop_properties(base_properties);
-    if (alternate_desktop_shortcut)
-      desktop_properties.set_shortcut_name(dist->GetAlternateApplicationName());
+    if (alternate_desktop_shortcut) {
+      desktop_properties.set_shortcut_name(
+          dist->GetShortcutName(
+              BrowserDistribution::SHORTCUT_CHROME_ALTERNATE));
+    }
     ExecuteAndLogShortcutOperation(
         ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, desktop_properties,
         shortcut_operation);
@@ -421,7 +424,9 @@
     // Desktop shortcut.
     if (!alternate_desktop_shortcut &&
         shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) {
-      desktop_properties.set_shortcut_name(dist->GetAlternateApplicationName());
+      desktop_properties.set_shortcut_name(
+          dist->GetShortcutName(
+              BrowserDistribution::SHORTCUT_CHROME_ALTERNATE));
       ExecuteAndLogShortcutOperation(
           ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, desktop_properties,
           shortcut_operation);
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc
index e992aa9..40f6ab1 100644
--- a/chrome/installer/setup/install_unittest.cc
+++ b/chrome/installer/setup/install_unittest.cc
@@ -117,23 +117,30 @@
         new base::ScopedPathOverride(base::DIR_COMMON_START_MENU,
                                      fake_common_start_menu_.path()));
 
-    string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+    string16 shortcut_name(
+        dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+        installer::kLnkExt);
     string16 alternate_shortcut_name(
-        dist_->GetAlternateApplicationName() + installer::kLnkExt);
+        dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME_ALTERNATE) +
+        installer::kLnkExt);
 
     user_desktop_shortcut_ =
         fake_user_desktop_.path().Append(shortcut_name);
     user_quick_launch_shortcut_ =
         fake_user_quick_launch_.path().Append(shortcut_name);
     user_start_menu_shortcut_ =
-        fake_start_menu_.path().Append(dist_->GetAppShortCutName())
+        fake_start_menu_.path().Append(
+            dist_->GetStartMenuShortcutSubfolder(
+                BrowserDistribution::SUBFOLDER_CHROME))
         .Append(shortcut_name);
     system_desktop_shortcut_ =
         fake_common_desktop_.path().Append(shortcut_name);
     system_quick_launch_shortcut_ =
         fake_default_user_quick_launch_.path().Append(shortcut_name);
     system_start_menu_shortcut_ =
-        fake_common_start_menu_.path().Append(dist_->GetAppShortCutName())
+        fake_common_start_menu_.path().Append(
+            dist_->GetStartMenuShortcutSubfolder(
+                BrowserDistribution::SUBFOLDER_CHROME))
         .Append(shortcut_name);
     user_alternate_desktop_shortcut_ =
         fake_user_desktop_.path().Append(alternate_shortcut_name);
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index b625954..d987670 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -438,7 +438,8 @@
     LOG(ERROR) << "Failed to get location for shortcut.";
   } else {
     uninstall_link = uninstall_link.Append(
-        product.distribution()->GetAppShortCutName());
+        product.distribution()->GetStartMenuShortcutSubfolder(
+            BrowserDistribution::SUBFOLDER_CHROME));
     uninstall_link = uninstall_link.Append(
         product.distribution()->GetUninstallLinkName() + installer::kLnkExt);
     VLOG(1) << "Deleting old uninstall shortcut (if present): "
@@ -722,8 +723,8 @@
     string16 uninstall_reg = browser_dist->GetUninstallRegPath();
     install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg);
     install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
-        installer::kUninstallDisplayNameField,
-        browser_dist->GetAppShortCutName(), true);
+        installer::kUninstallDisplayNameField, browser_dist->GetDisplayName(),
+        true);
     install_list->AddSetRegValueWorkItem(reg_root,
         uninstall_reg, installer::kUninstallStringField,
         quoted_uninstall_cmd.GetCommandLineString(), true);
@@ -736,7 +737,7 @@
     BrowserDistribution* dist = product.distribution();
     string16 chrome_icon = ShellUtil::FormatIconLocation(
         install_path.Append(dist->GetIconFilename()).value(),
-        dist->GetIconIndex());
+        dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME));
     install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
                                          L"DisplayIcon", chrome_icon, true);
     install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
@@ -786,7 +787,7 @@
   string16 version_key(dist->GetVersionKey());
   list->AddCreateRegKeyWorkItem(root, version_key);
 
-  string16 product_name(dist->GetAppShortCutName());
+  string16 product_name(dist->GetDisplayName());
   list->AddSetRegValueWorkItem(root, version_key, google_update::kRegNameField,
                                product_name, true);  // overwrite name also
   list->AddSetRegValueWorkItem(root, version_key,
@@ -845,7 +846,7 @@
     if (source_product->GetOemInstall(&oem_install)) {
       VLOG(1) << "Mirroring oeminstall=\"" << oem_install << "\" from "
               << BrowserDistribution::GetSpecificDistribution(source_type)->
-                    GetAppShortCutName();
+                     GetDisplayName();
       install_list->AddCreateRegKeyWorkItem(root_key, multi_key);
       // Always overwrite an old value.
       install_list->AddSetRegValueWorkItem(root_key, multi_key,
@@ -900,7 +901,7 @@
     if (have_eula_accepted) {
       VLOG(1) << "Mirroring eulaaccepted=" << eula_accepted << " from "
               << BrowserDistribution::GetSpecificDistribution(product_type)->
-                     GetAppShortCutName();
+                     GetDisplayName();
       install_list->AddCreateRegKeyWorkItem(root_key, multi_key);
       install_list->AddSetRegValueWorkItem(
           root_key, multi_key, google_update::kRegEULAAceptedField,
@@ -1433,13 +1434,13 @@
                                  const Product& product,
                                  WorkItemList* list) {
   string16 handler_class_uuid;
-  BrowserDistribution* distribution = product.distribution();
-  if (!distribution->GetCommandExecuteImplClsid(&handler_class_uuid)) {
+  BrowserDistribution* dist = product.distribution();
+  if (!dist->GetCommandExecuteImplClsid(&handler_class_uuid)) {
     if (InstallUtil::IsChromeSxSProcess()) {
       CleanupBadCanaryDelegateExecuteRegistration(target_path, list);
     } else {
       VLOG(1) << "No DelegateExecute verb handler processing to do for "
-              << distribution->GetAppShortCutName();
+              << dist->GetDisplayName();
     }
     return;
   }
@@ -1495,25 +1496,24 @@
                              const Product& product,
                              WorkItemList* list) {
   DCHECK(installer_state.operation() != InstallerState::UNINSTALL);
-  BrowserDistribution* distribution = product.distribution();
+  BrowserDistribution* dist = product.distribution();
 
   if (!product.is_chrome() || !installer_state.system_install()) {
     const char* install_level =
         installer_state.system_install() ? "system" : "user";
     VLOG(1) << "No Active Setup processing to do for " << install_level
-            << "-level " << distribution->GetAppShortCutName();
+            << "-level " << dist->GetDisplayName();
     return;
   }
   DCHECK(installer_state.RequiresActiveSetup());
 
   const HKEY root = HKEY_LOCAL_MACHINE;
-  const string16 active_setup_path(
-      InstallUtil::GetActiveSetupPath(distribution));
+  const string16 active_setup_path(InstallUtil::GetActiveSetupPath(dist));
 
   VLOG(1) << "Adding registration items for Active Setup.";
   list->AddCreateRegKeyWorkItem(root, active_setup_path);
   list->AddSetRegValueWorkItem(root, active_setup_path, L"",
-                               distribution->GetAppShortCutName(), true);
+                               dist->GetDisplayName(), true);
 
   base::FilePath active_setup_exe(installer_state.GetInstallerDirectory(
       new_version).Append(kActiveSetupExe));
@@ -1528,7 +1528,7 @@
   // TODO(grt): http://crbug.com/75152 Write a reference to a localized
   // resource.
   list->AddSetRegValueWorkItem(root, active_setup_path, L"Localized Name",
-                               distribution->GetAppShortCutName(), true);
+                               dist->GetDisplayName(), true);
 
   list->AddSetRegValueWorkItem(root, active_setup_path, L"IsInstalled",
                                static_cast<DWORD>(1U), true);
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index b02fb4e..171ac7c 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -204,7 +204,7 @@
           installer_state->AddProductFromState(type, *state);
           VLOG(1) << "Product already installed and must be included: "
                   << BrowserDistribution::GetSpecificDistribution(type)->
-                         GetAppShortCutName();
+                         GetDisplayName();
         }
       }
     }
@@ -338,9 +338,9 @@
                                                    &is_overridden);
       if (is_overridden && app_policy != binaries_policy) {
         LOG(ERROR) << "Found legacy Group Policy setting for "
-                   << dist->GetAppShortCutName() << " (value: " << app_policy
+                   << dist->GetDisplayName() << " (value: " << app_policy
                    << ") that does not match the setting for "
-                   << binaries_dist->GetAppShortCutName()
+                   << binaries_dist->GetDisplayName()
                    << " (value: " << binaries_policy << ").";
         settings_are_valid = false;
       }
@@ -355,7 +355,7 @@
     LOG(ERROR) << "Cannot apply update on account of inconsistent "
                   "Google Update Group Policy settings. Use the Group Policy "
                   "Editor to set the update policy override for the "
-               << binaries_dist->GetAppShortCutName()
+               << binaries_dist->GetDisplayName()
                << " application and try again.";
     *status = installer::INCONSISTENT_UPDATE_POLICY;
     installer_state.WriteInstallerResult(
@@ -505,7 +505,7 @@
       // Block downgrades from multi-install to single-install.
       if (product_state->is_multi_install()) {
         LOG(ERROR) << "Multi-install "
-                   << products[0]->distribution()->GetAppShortCutName()
+                   << products[0]->distribution()->GetDisplayName()
                    << " exists; aborting single install.";
         *status = installer::MULTI_INSTALLATION_EXISTS;
         installer_state->WriteInstallerResult(*status,
@@ -757,7 +757,7 @@
     VLOG(1) << "version on the system: "
             << product_state->version().GetString();
   } else if (!force_uninstall) {
-    LOG(ERROR) << product.distribution()->GetAppShortCutName()
+    LOG(ERROR) << product.distribution()->GetDisplayName()
                << " not found for uninstall.";
     return installer::CHROME_NOT_INSTALLED;
   }
@@ -929,7 +929,7 @@
     static const wchar_t kPleaseUninstallYourChromeMessage[] =
         L"You already have a full-installation (non-dev) of %1ls, please "
         L"uninstall it first using Add/Remove Programs in the control panel.";
-    string16 name(chrome_dist->GetAppShortCutName());
+    string16 name(chrome_dist->GetDisplayName());
     string16 message(base::StringPrintf(kPleaseUninstallYourChromeMessage,
                                         name.c_str()));
 
@@ -1241,7 +1241,7 @@
       InstallUtil::GetChromeVersion(browser_dist, true, &installed_version);
       if (!installed_version.IsValid()) {
         LOG(ERROR) << "No installation of "
-                   << browser_dist->GetAppShortCutName()
+                   << browser_dist->GetDisplayName()
                    << " found for system-level toast.";
       } else {
         product.LaunchUserExperiment(
@@ -1531,7 +1531,7 @@
       if (product_state != NULL &&
           (product_state->version().CompareTo(*installer_version) > 0)) {
         LOG(ERROR) << "Higher version of "
-                   << product.distribution()->GetAppShortCutName()
+                   << product.distribution()->GetDisplayName()
                    << " is already installed.";
         higher_products |= (1 << product.distribution()->GetType());
       }
@@ -1839,7 +1839,7 @@
         ::MessageBoxW(NULL,
                       installer::GetLocalizedString(
                           IDS_UNINSTALL_COMPLETE_BASE).c_str(),
-                      cf_install->distribution()->GetAppShortCutName().c_str(),
+                      cf_install->distribution()->GetDisplayName().c_str(),
                       MB_OK);
       }
     }
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 3de04fb..8ecdcb6 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -394,7 +394,7 @@
                             KEY_SET_VALUE);
     if (result != ERROR_SUCCESS) {
       LOG(ERROR) << "Failed opening ClientState key for "
-                 << dist->GetAppShortCutName() << " to migrate usagestats.";
+                 << dist->GetDisplayName() << " to migrate usagestats.";
     } else {
       state_key.WriteValue(google_update::kRegUsageStatsField, usagestats);
     }
@@ -416,7 +416,7 @@
       if (result == ERROR_SUCCESS &&
           channel_info.Initialize(state_key) &&
           product_to_migrate.SetChannelFlags(false, &channel_info)) {
-        VLOG(1) << "Moving " << dist->GetAppShortCutName()
+        VLOG(1) << "Moving " << dist->GetDisplayName()
                 << " to channel: " << channel_info.value();
         channel_info.Write(&state_key);
       }
@@ -431,10 +431,10 @@
   if (result == ERROR_SUCCESS) {
     installer::ChannelInfo channel_info;
     if (!channel_info.Initialize(state_key)) {
-      LOG(ERROR) << "Failed reading " << dist->GetAppShortCutName()
+      LOG(ERROR) << "Failed reading " << dist->GetDisplayName()
                  << " channel info.";
     } else if (channel_info.RemoveAllModifiersAndSuffixes()) {
-      VLOG(1) << "Moving " << dist->GetAppShortCutName()
+      VLOG(1) << "Moving " << dist->GetDisplayName()
               << " to channel: " << channel_info.value();
       channel_info.Write(&state_key);
     }
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index 30af416..7f8e7ce 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -103,7 +103,7 @@
              product_state != NULL && product_state->is_multi_install())
           << "Channel value for "
           << BrowserDistribution::GetSpecificDistribution(
-                 dist_type)->GetAppShortCutName()
+                 dist_type)->GetDisplayName()
           << " is somehow already set to the desired new value of "
           << channel_info.value();
     }
@@ -940,7 +940,7 @@
     const char* install_level =
         installer_state.system_install() ? "system" : "user";
     VLOG(1) << "No Active Setup processing to do for " << install_level
-            << "-level " << distribution->GetAppShortCutName();
+            << "-level " << distribution->GetDisplayName();
     return;
   }
 
@@ -1079,7 +1079,7 @@
 
   bool is_chrome = product.is_chrome();
 
-  VLOG(1) << "UninstallProduct: " << browser_dist->GetAppShortCutName();
+  VLOG(1) << "UninstallProduct: " << browser_dist->GetDisplayName();
 
   if (force_uninstall) {
     // Since --force-uninstall command line option is used, we are going to
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index 4f71141..8a24927 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -39,6 +39,9 @@
 const wchar_t kCommandExecuteImplUuid[] =
     L"{A2DF06F9-A21A-44A8-8A99-8B9C84F29160}";
 
+// The Chromium App Launcher icon is index 1; see chrome_exe.rc.
+const int kAppLauncherIconIndex = 1;
+
 // The BrowserDistribution objects are never freed.
 BrowserDistribution* g_browser_distribution = NULL;
 BrowserDistribution* g_chrome_frame_distribution = NULL;
@@ -154,12 +157,42 @@
   return L"Chromium";
 }
 
-string16 BrowserDistribution::GetAppShortCutName() {
-  return GetBaseAppName();
+string16 BrowserDistribution::GetDisplayName() {
+  return GetShortcutName(SHORTCUT_CHROME);
 }
 
-string16 BrowserDistribution::GetAlternateApplicationName() {
-  return L"The Internet";
+string16 BrowserDistribution::GetShortcutName(ShortcutType shortcut_type) {
+  switch (shortcut_type) {
+    case SHORTCUT_CHROME_ALTERNATE:
+      // TODO(calamity): Change IDS_OEM_MAIN_SHORTCUT_NAME in
+      // chromium_strings.grd to "The Internet" (so that it doesn't collide with
+      // the value in google_chrome_strings.grd) then change this to
+      // installer::GetLocalizedString(IDS_OEM_MAIN_SHORTCUT_NAME_BASE)
+      return L"The Internet";
+    case SHORTCUT_APP_LAUNCHER:
+      return installer::GetLocalizedString(IDS_APP_LIST_SHORTCUT_NAME_BASE);
+    default:
+      DCHECK_EQ(shortcut_type, SHORTCUT_CHROME);
+      return GetBaseAppName();
+  }
+}
+
+int BrowserDistribution::GetIconIndex(ShortcutType shortcut_type) {
+  if (shortcut_type == SHORTCUT_APP_LAUNCHER)
+    return kAppLauncherIconIndex;
+  DCHECK(shortcut_type == SHORTCUT_CHROME ||
+         shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type;
+  return 0;
+}
+
+string16 BrowserDistribution::GetIconFilename() {
+  return installer::kChromeExe;
+}
+
+string16 BrowserDistribution::GetStartMenuShortcutSubfolder(
+    Subfolder subfolder_type) {
+  DCHECK_EQ(subfolder_type, SUBFOLDER_CHROME);
+  return GetShortcutName(SHORTCUT_CHROME);
 }
 
 string16 BrowserDistribution::GetBaseAppId() {
@@ -228,16 +261,6 @@
   return true;
 }
 
-string16 BrowserDistribution::GetIconFilename() {
-  return string16();
-}
-
-int BrowserDistribution::GetIconIndex() {
-  // Assuming that main icon appears first alphabetically in the resource file
-  // for GetIconFilename().
-  return 0;
-}
-
 bool BrowserDistribution::GetChromeChannel(string16* channel) {
   return false;
 }
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index ca67c0b..b308c04 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -29,6 +29,17 @@
     NUM_TYPES
   };
 
+  enum ShortcutType {
+    SHORTCUT_CHROME,
+    SHORTCUT_CHROME_ALTERNATE,
+    SHORTCUT_APP_LAUNCHER
+  };
+
+  enum Subfolder {
+    SUBFOLDER_CHROME,
+    // TODO(calamity): add SUBFOLDER_APPS when refactoring chrome app dir code.
+  };
+
   virtual ~BrowserDistribution() {}
 
   static BrowserDistribution* GetDistribution();
@@ -53,10 +64,24 @@
   // at run-time.
   virtual string16 GetBaseAppName();
 
-  // Returns the localized name of the program.
-  virtual string16 GetAppShortCutName();
+  // Returns the localized display name of this distribution.
+  virtual string16 GetDisplayName();
 
-  virtual string16 GetAlternateApplicationName();
+  // Returns the localized name of the shortcut identified by |shortcut_type|
+  // for this distribution.
+  virtual string16 GetShortcutName(ShortcutType shortcut_type);
+
+  // Returns the index of the icon for the product identified by
+  // |shortcut_type|, inside the file specified by GetIconFilename().
+  virtual int GetIconIndex(ShortcutType shortcut_type);
+
+  // Returns the executable filename (not path) that contains the product icon.
+  virtual string16 GetIconFilename();
+
+  // Returns the localized name of the subfolder in the Start Menu identified by
+  // |subfolder_type| that this distribution should create shortcuts in. For
+  // SUBFOLDER_CHROME this returns GetShortcutName(SHORTCUT_CHROME).
+  virtual string16 GetStartMenuShortcutSubfolder(Subfolder subfolder_type);
 
   // Returns the unsuffixed appid of this program.
   // The AppUserModelId is a property of Windows programs.
@@ -96,13 +121,6 @@
 
   virtual bool CanCreateDesktopShortcuts();
 
-  // Returns the executable filename (not path) that contains the product icon.
-  virtual string16 GetIconFilename();
-
-  // Returns the index of the icon for the product, inside the file specified by
-  // GetIconFilename().
-  virtual int GetIconIndex();
-
   virtual bool GetChromeChannel(string16* channel);
 
   // Returns true if this distribution includes a DelegateExecute verb handler,
diff --git a/chrome/installer/util/chrome_app_host_distribution.cc b/chrome/installer/util/chrome_app_host_distribution.cc
index 7c40326..1c4c0e1 100644
--- a/chrome/installer/util/chrome_app_host_distribution.cc
+++ b/chrome/installer/util/chrome_app_host_distribution.cc
@@ -38,16 +38,14 @@
   return L"Google Chrome App Launcher";
 }
 
-string16 ChromeAppHostDistribution::GetAppShortCutName() {
-  const string16& product_name =
-      installer::GetLocalizedString(IDS_PRODUCT_APP_LAUNCHER_NAME_BASE);
-  return product_name;
+string16 ChromeAppHostDistribution::GetDisplayName() {
+  return GetShortcutName(SHORTCUT_APP_LAUNCHER);
 }
 
-string16 ChromeAppHostDistribution::GetAlternateApplicationName() {
-  const string16& product_name =
-      installer::GetLocalizedString(IDS_PRODUCT_APP_LAUNCHER_NAME_BASE);
-  return product_name;
+string16 ChromeAppHostDistribution::GetShortcutName(
+    ShortcutType shortcut_type) {
+  DCHECK_EQ(shortcut_type, SHORTCUT_APP_LAUNCHER);
+  return installer::GetLocalizedString(IDS_PRODUCT_APP_LAUNCHER_NAME_BASE);
 }
 
 string16 ChromeAppHostDistribution::GetBaseAppId() {
diff --git a/chrome/installer/util/chrome_app_host_distribution.h b/chrome/installer/util/chrome_app_host_distribution.h
index 5648abd..24e007a 100644
--- a/chrome/installer/util/chrome_app_host_distribution.h
+++ b/chrome/installer/util/chrome_app_host_distribution.h
@@ -15,12 +15,15 @@
  public:
   virtual string16 GetAppGuid() OVERRIDE;
 
+  virtual string16 GetDisplayName() OVERRIDE;
+
+  // This can only be called with SHORTCUT_APP_LAUNCHER for |shortcut_type|.
+  virtual string16 GetShortcutName(ShortcutType shortcut_type) OVERRIDE;
+
+  virtual string16 GetIconFilename() OVERRIDE;
+
   virtual string16 GetBaseAppName() OVERRIDE;
 
-  virtual string16 GetAppShortCutName() OVERRIDE;
-
-  virtual string16 GetAlternateApplicationName() OVERRIDE;
-
   virtual string16 GetBaseAppId() OVERRIDE;
 
   virtual string16 GetInstallSubDir() OVERRIDE;
@@ -51,8 +54,6 @@
 
   virtual bool CanCreateDesktopShortcuts() OVERRIDE;
 
-  virtual string16 GetIconFilename() OVERRIDE;
-
   virtual bool GetCommandExecuteImplClsid(
       string16* handler_class_uuid) OVERRIDE;
 
diff --git a/chrome/installer/util/chrome_app_host_operations.cc b/chrome/installer/util/chrome_app_host_operations.cc
index 361f952..cfd9570 100644
--- a/chrome/installer/util/chrome_app_host_operations.cc
+++ b/chrome/installer/util/chrome_app_host_operations.cc
@@ -108,7 +108,8 @@
   }
 
   if (!properties->has_icon())
-    properties->set_icon(target_exe, dist->GetIconIndex());
+    properties->set_icon(target_exe,
+        dist->GetIconIndex(BrowserDistribution::SHORTCUT_APP_LAUNCHER));
 
   if (!properties->has_app_id()) {
     std::vector<string16> components;
diff --git a/chrome/installer/util/chrome_browser_operations.cc b/chrome/installer/util/chrome_browser_operations.cc
index 59757e4..c376261 100644
--- a/chrome/installer/util/chrome_browser_operations.cc
+++ b/chrome/installer/util/chrome_browser_operations.cc
@@ -112,7 +112,8 @@
     properties->set_target(target_exe);
 
   if (!properties->has_icon()) {
-    int icon_index = dist->GetIconIndex();
+    int icon_index =
+        dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
     base::FilePath prefs_path(target_exe.DirName().AppendASCII(
         installer::kDefaultMasterPrefs));
     if (base::PathExists(prefs_path)) {
diff --git a/chrome/installer/util/chrome_frame_distribution.cc b/chrome/installer/util/chrome_frame_distribution.cc
index 68379d0..f968178 100644
--- a/chrome/installer/util/chrome_frame_distribution.cc
+++ b/chrome/installer/util/chrome_frame_distribution.cc
@@ -36,16 +36,15 @@
   return L"Google Chrome Frame";
 }
 
-string16 ChromeFrameDistribution::GetAppShortCutName() {
-  const string16& product_name =
-      installer::GetLocalizedString(IDS_PRODUCT_FRAME_NAME_BASE);
-  return product_name;
-}
-
-string16 ChromeFrameDistribution::GetAlternateApplicationName() {
-  const string16& product_name =
-      installer::GetLocalizedString(IDS_PRODUCT_FRAME_NAME_BASE);
-  return product_name;
+string16 ChromeFrameDistribution::GetShortcutName(ShortcutType shortcut_type) {
+  switch (shortcut_type) {
+    case SHORTCUT_CHROME:
+    case SHORTCUT_CHROME_ALTERNATE:
+      return installer::GetLocalizedString(IDS_PRODUCT_FRAME_NAME_BASE);
+    default:
+      NOTREACHED();
+      return string16();
+  }
 }
 
 string16 ChromeFrameDistribution::GetInstallSubDir() {
@@ -112,8 +111,14 @@
   return installer::kChromeExe;
 }
 
-int ChromeFrameDistribution::GetIconIndex() {
-  return 0;
+int ChromeFrameDistribution::GetIconIndex(ShortcutType shortcut_type) {
+  switch (shortcut_type) {
+    case SHORTCUT_CHROME:
+      return 0;
+    default:
+      NOTREACHED();
+      return 0;
+  }
 }
 
 bool ChromeFrameDistribution::CanSetAsDefault() {
diff --git a/chrome/installer/util/chrome_frame_distribution.h b/chrome/installer/util/chrome_frame_distribution.h
index ff49036..fa891d6 100644
--- a/chrome/installer/util/chrome_frame_distribution.h
+++ b/chrome/installer/util/chrome_frame_distribution.h
@@ -15,12 +15,12 @@
  public:
   virtual string16 GetAppGuid() OVERRIDE;
 
+  virtual string16 GetShortcutName(ShortcutType shortcut_type) OVERRIDE;
+
+  virtual int GetIconIndex(ShortcutType shortcut_type) OVERRIDE;
+
   virtual string16 GetBaseAppName() OVERRIDE;
 
-  virtual string16 GetAppShortCutName() OVERRIDE;
-
-  virtual string16 GetAlternateApplicationName() OVERRIDE;
-
   virtual string16 GetInstallSubDir() OVERRIDE;
 
   virtual string16 GetPublisherName() OVERRIDE;
@@ -47,8 +47,6 @@
 
   virtual string16 GetIconFilename() OVERRIDE;
 
-  virtual int GetIconIndex() OVERRIDE;
-
   virtual bool CanSetAsDefault() OVERRIDE;
 
   virtual bool CanCreateDesktopShortcuts() OVERRIDE;
diff --git a/chrome/installer/util/chromium_binaries_distribution.cc b/chrome/installer/util/chromium_binaries_distribution.cc
index 514dfa7..004e617 100644
--- a/chrome/installer/util/chromium_binaries_distribution.cc
+++ b/chrome/installer/util/chromium_binaries_distribution.cc
@@ -29,11 +29,12 @@
   return string16();
 }
 
-string16 ChromiumBinariesDistribution::GetAppShortCutName() {
+string16 ChromiumBinariesDistribution::GetDisplayName() {
   return kChromiumBinariesName;
 }
 
-string16 ChromiumBinariesDistribution::GetAlternateApplicationName() {
+string16 ChromiumBinariesDistribution::GetShortcutName(
+    ShortcutType shortcut_type) {
   NOTREACHED();
   return string16();
 }
@@ -93,7 +94,7 @@
   return false;
 }
 
-int ChromiumBinariesDistribution::GetIconIndex() {
+int ChromiumBinariesDistribution::GetIconIndex(ShortcutType shortcut_type) {
   NOTREACHED();
   return 0;
 }
diff --git a/chrome/installer/util/chromium_binaries_distribution.h b/chrome/installer/util/chromium_binaries_distribution.h
index e78bf86..43c87cc 100644
--- a/chrome/installer/util/chromium_binaries_distribution.h
+++ b/chrome/installer/util/chromium_binaries_distribution.h
@@ -15,12 +15,14 @@
  public:
   virtual string16 GetAppGuid() OVERRIDE;
 
+  virtual string16 GetDisplayName() OVERRIDE;
+
+  virtual string16 GetShortcutName(ShortcutType shortcut_type) OVERRIDE;
+
+  virtual int GetIconIndex(ShortcutType shortcut_type) OVERRIDE;
+
   virtual string16 GetBaseAppName() OVERRIDE;
 
-  virtual string16 GetAppShortCutName() OVERRIDE;
-
-  virtual string16 GetAlternateApplicationName() OVERRIDE;
-
   virtual string16 GetBaseAppId() OVERRIDE;
 
   virtual string16 GetInstallSubDir() OVERRIDE;
@@ -45,8 +47,6 @@
 
   virtual bool CanSetAsDefault() OVERRIDE;
 
-  virtual int GetIconIndex() OVERRIDE;
-
   virtual bool GetChromeChannel(string16* channel) OVERRIDE;
 
   virtual bool GetCommandExecuteImplClsid(
diff --git a/chrome/installer/util/google_chrome_binaries_distribution.cc b/chrome/installer/util/google_chrome_binaries_distribution.cc
index 16c177d..e5ad751 100644
--- a/chrome/installer/util/google_chrome_binaries_distribution.cc
+++ b/chrome/installer/util/google_chrome_binaries_distribution.cc
@@ -25,10 +25,16 @@
   return kChromeBinariesGuid;
 }
 
-string16 GoogleChromeBinariesDistribution::GetAppShortCutName() {
+string16 GoogleChromeBinariesDistribution::GetDisplayName() {
   return kChromeBinariesName;
 }
 
+string16 GoogleChromeBinariesDistribution::GetShortcutName(
+    ShortcutType shortcut_type) {
+  NOTREACHED();
+  return string16();
+}
+
 string16 GoogleChromeBinariesDistribution::GetStateKey() {
   return string16(google_update::kRegPathClientState)
       .append(1, L'\\')
diff --git a/chrome/installer/util/google_chrome_binaries_distribution.h b/chrome/installer/util/google_chrome_binaries_distribution.h
index ded49b8..aa0a1ee 100644
--- a/chrome/installer/util/google_chrome_binaries_distribution.h
+++ b/chrome/installer/util/google_chrome_binaries_distribution.h
@@ -13,7 +13,9 @@
  public:
   virtual string16 GetAppGuid();
 
-  virtual string16 GetAppShortCutName();
+  virtual string16 GetDisplayName();
+
+  virtual string16 GetShortcutName(ShortcutType shortcut_type);
 
   virtual string16 GetStateKey();
 
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index c7a7c3e..2ae5338 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -38,6 +38,9 @@
 const wchar_t kCommandExecuteImplUuid[] =
     L"{5C65F4B0-3651-4514-B207-D10CB699B14B}";
 
+// The Google Chrome App Launcher icon is index 5; see chrome_exe.rc.
+const int kAppLauncherIconIndex = 5;
+
 // Substitute the locale parameter in uninstall URL with whatever
 // Google Update tells us is the locale. In case we fail to find
 // the locale, we use US English.
@@ -125,16 +128,28 @@
   return L"Google Chrome";
 }
 
-string16 GoogleChromeDistribution::GetAppShortCutName() {
-  const string16& app_shortcut_name =
-      installer::GetLocalizedString(IDS_PRODUCT_NAME_BASE);
-  return app_shortcut_name;
+string16 GoogleChromeDistribution::GetShortcutName(ShortcutType shortcut_type) {
+  int string_id = IDS_PRODUCT_NAME_BASE;
+  switch (shortcut_type) {
+    case SHORTCUT_CHROME_ALTERNATE:
+      string_id = IDS_OEM_MAIN_SHORTCUT_NAME_BASE;
+      break;
+    case SHORTCUT_APP_LAUNCHER:
+      string_id = IDS_APP_LIST_SHORTCUT_NAME_BASE;
+      break;
+    default:
+      DCHECK_EQ(shortcut_type, SHORTCUT_CHROME);
+      break;
+  }
+  return installer::GetLocalizedString(string_id);
 }
 
-string16 GoogleChromeDistribution::GetAlternateApplicationName() {
-  const string16& alt_product_name =
-      installer::GetLocalizedString(IDS_OEM_MAIN_SHORTCUT_NAME_BASE);
-  return alt_product_name;
+int GoogleChromeDistribution::GetIconIndex(ShortcutType shortcut_type) {
+  if (shortcut_type == SHORTCUT_APP_LAUNCHER)
+    return kAppLauncherIconIndex;
+  DCHECK(shortcut_type == SHORTCUT_CHROME ||
+         shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type;
+  return 0;
 }
 
 string16 GoogleChromeDistribution::GetBaseAppId() {
diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h
index d3f148f..a00a31e 100644
--- a/chrome/installer/util/google_chrome_distribution.h
+++ b/chrome/installer/util/google_chrome_distribution.h
@@ -36,12 +36,14 @@
 
   virtual string16 GetAppGuid() OVERRIDE;
 
+  virtual string16 GetShortcutName(ShortcutType shortcut_type) OVERRIDE;
+
+  virtual string16 GetIconFilename() OVERRIDE;
+
+  virtual int GetIconIndex(ShortcutType shortcut_type) OVERRIDE;
+
   virtual string16 GetBaseAppName() OVERRIDE;
 
-  virtual string16 GetAppShortCutName() OVERRIDE;
-
-  virtual string16 GetAlternateApplicationName() OVERRIDE;
-
   virtual string16 GetBaseAppId() OVERRIDE;
 
   virtual string16 GetInstallSubDir() OVERRIDE;
@@ -71,8 +73,6 @@
 
   virtual string16 GetVersionKey() OVERRIDE;
 
-  virtual string16 GetIconFilename() OVERRIDE;
-
   virtual bool GetCommandExecuteImplClsid(
       string16* handler_class_uuid) OVERRIDE;
 
diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc
index 623870c..ff7638a 100644
--- a/chrome/installer/util/google_chrome_distribution_dummy.cc
+++ b/chrome/installer/util/google_chrome_distribution_dummy.cc
@@ -41,14 +41,14 @@
   return string16();
 }
 
-string16 GoogleChromeDistribution::GetAppShortCutName() {
+string16 GoogleChromeDistribution::GetShortcutName(ShortcutType shortcut_type) {
   NOTREACHED();
   return string16();
 }
 
-string16 GoogleChromeDistribution::GetAlternateApplicationName() {
+int GoogleChromeDistribution::GetIconIndex(ShortcutType shortcut_type) {
   NOTREACHED();
-  return string16();
+  return 0;
 }
 
 string16 GoogleChromeDistribution::GetBaseAppId() {
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc
index 5224a8c..1e623d9 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.cc
+++ b/chrome/installer/util/google_chrome_sxs_distribution.cc
@@ -18,6 +18,9 @@
 const wchar_t kBrowserAppId[] = L"ChromeCanary";
 const int kSxSIconIndex = 4;
 
+// The Chrome App Launcher Canary icon is index 6; see chrome_exe.rc.
+const int kSxSAppLauncherIconIndex = 6;
+
 }  // namespace
 
 GoogleChromeSxSDistribution::GoogleChromeSxSDistribution()
@@ -29,10 +32,21 @@
   return L"Google Chrome Canary";
 }
 
-string16 GoogleChromeSxSDistribution::GetAppShortCutName() {
-  const string16& shortcut_name =
-      installer::GetLocalizedString(IDS_SXS_SHORTCUT_NAME_BASE);
-  return shortcut_name;
+string16 GoogleChromeSxSDistribution::GetShortcutName(
+    ShortcutType shortcut_type) {
+  switch (shortcut_type) {
+    case SHORTCUT_CHROME_ALTERNATE:
+      // This should never be called. Returning the same string as Google Chrome
+      // preserves behavior, but it will result in a naming collision.
+      NOTREACHED();
+      return GoogleChromeDistribution::GetShortcutName(shortcut_type);
+    case SHORTCUT_APP_LAUNCHER:
+      return installer::GetLocalizedString(
+          IDS_APP_LIST_SHORTCUT_NAME_CANARY_BASE);
+    default:
+      DCHECK_EQ(shortcut_type, SHORTCUT_CHROME);
+      return installer::GetLocalizedString(IDS_SXS_SHORTCUT_NAME_BASE);
+  }
 }
 
 string16 GoogleChromeSxSDistribution::GetBaseAppId() {
@@ -53,7 +67,11 @@
   return false;
 }
 
-int GoogleChromeSxSDistribution::GetIconIndex() {
+int GoogleChromeSxSDistribution::GetIconIndex(ShortcutType shortcut_type) {
+  if (shortcut_type == SHORTCUT_APP_LAUNCHER)
+    return kSxSAppLauncherIconIndex;
+  DCHECK(shortcut_type == SHORTCUT_CHROME ||
+         shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type;
   return kSxSIconIndex;
 }
 
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.h b/chrome/installer/util/google_chrome_sxs_distribution.h
index 74a0cc3..5261a7a 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.h
+++ b/chrome/installer/util/google_chrome_sxs_distribution.h
@@ -20,12 +20,12 @@
 class GoogleChromeSxSDistribution : public GoogleChromeDistribution {
  public:
   virtual string16 GetBaseAppName() OVERRIDE;
-  virtual string16 GetAppShortCutName() OVERRIDE;
+  virtual string16 GetShortcutName(ShortcutType shortcut_type) OVERRIDE;
+  virtual int GetIconIndex(ShortcutType shortcut_type) OVERRIDE;
   virtual string16 GetBaseAppId() OVERRIDE;
   virtual string16 GetInstallSubDir() OVERRIDE;
   virtual string16 GetUninstallRegPath() OVERRIDE;
   virtual bool CanSetAsDefault() OVERRIDE;
-  virtual int GetIconIndex() OVERRIDE;
   virtual bool GetChromeChannel(string16* channel) OVERRIDE;
   virtual bool GetCommandExecuteImplClsid(
       string16* handler_class_uuid) OVERRIDE;
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index fd1ad19..c8c037d 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -223,12 +223,12 @@
 
   *version = Version();
   if (result == ERROR_SUCCESS && !version_str.empty()) {
-    VLOG(1) << "Existing " << dist->GetAppShortCutName() << " version found "
+    VLOG(1) << "Existing " << dist->GetDisplayName() << " version found "
             << version_str;
     *version = Version(WideToASCII(version_str));
   } else {
     DCHECK_EQ(ERROR_FILE_NOT_FOUND, result);
-    VLOG(1) << "No existing " << dist->GetAppShortCutName()
+    VLOG(1) << "No existing " << dist->GetDisplayName()
             << " install found.";
   }
 }
@@ -249,12 +249,12 @@
 
   *version = Version();
   if (result == ERROR_SUCCESS && !version_str.empty()) {
-    VLOG(1) << "Critical Update version for " << dist->GetAppShortCutName()
+    VLOG(1) << "Critical Update version for " << dist->GetDisplayName()
             << " found " << version_str;
     *version = Version(WideToASCII(version_str));
   } else {
     DCHECK_EQ(ERROR_FILE_NOT_FOUND, result);
-    VLOG(1) << "No existing " << dist->GetAppShortCutName()
+    VLOG(1) << "No existing " << dist->GetDisplayName()
             << " install found.";
   }
 }
diff --git a/chrome/installer/util/installation_validator.cc b/chrome/installer/util/installation_validator.cc
index f5fb140..649d792 100644
--- a/chrome/installer/util/installation_validator.cc
+++ b/chrome/installer/util/installation_validator.cc
@@ -211,7 +211,7 @@
     bool expected = flags_exp.find(check_list[i].exp_key) != flags_exp.end();
     if (check_list[i].val != expected) {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName() << ": "
+      LOG(ERROR) << ctx.dist->GetDisplayName() << ": "
                  << name << " command should " << (expected ? "" : "not ")
                  << check_list[i].msg << ".";
     }
@@ -415,7 +415,7 @@
       the_expectations.erase(expectation);
     } else {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << ctx.dist->GetDisplayName()
                  << " has an unexpected Google Update product command named \""
                  << cmd_id << "\".";
     }
@@ -426,7 +426,7 @@
   CommandExpectations::const_iterator end(the_expectations.end());
   for (; scan != end; ++scan) {
     *is_valid = false;
-    LOG(ERROR) << ctx.dist->GetAppShortCutName()
+    LOG(ERROR) << ctx.dist->GetDisplayName()
                << " is missing the Google Update product command named \""
                << scan->first << "\".";
   }
@@ -595,7 +595,7 @@
   if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(),
                                               setup_exe.value())) {
     *is_valid = false;
-    LOG(ERROR) << ctx.dist->GetAppShortCutName() << " path to " << purpose
+    LOG(ERROR) << ctx.dist->GetDisplayName() << " path to " << purpose
                << " is not " << expected_path.value() << ": "
                << setup_exe.value();
   }
@@ -613,7 +613,7 @@
     const SwitchExpectations::value_type& expectation = expected[i];
     if (command.HasSwitch(expectation.first) != expectation.second) {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName() << " " << source
+      LOG(ERROR) << ctx.dist->GetDisplayName() << " " << source
                  << (expectation.second ? " is missing" : " has") << " \""
                  << expectation.first << "\""
                  << (expectation.second ? "" : " but shouldn't") << ": "
@@ -680,14 +680,14 @@
   if (ctx.state.old_version() == NULL) {
     if (!ctx.state.rename_cmd().empty()) {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << ctx.dist->GetDisplayName()
                  << " has a rename command but no opv: "
                  << ctx.state.rename_cmd();
     }
   } else {
     if (ctx.state.rename_cmd().empty()) {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << ctx.dist->GetDisplayName()
                  << " has an opv but no rename command: "
                  << ctx.state.old_version()->GetString();
     } else {
@@ -714,14 +714,14 @@
               true,  // system-level
               BrowserDistribution::CHROME_BROWSER)) {
         *is_valid = false;
-        LOG(ERROR) << ctx.dist->GetAppShortCutName()
+        LOG(ERROR) << ctx.dist->GetDisplayName()
                    << " (" << ctx.state.version().GetString() << ") is "
                    << "installed without Chrome Binaries or a system-level "
                    << "Chrome.";
       }
     } else {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << ctx.dist->GetDisplayName()
                  << " (" << ctx.state.version().GetString() << ") is installed "
                  << "without Chrome Binaries.";
     }
@@ -729,7 +729,7 @@
     // Version must match that of binaries.
     if (ctx.state.version().CompareTo(binaries->version()) != 0) {
       *is_valid = false;
-      LOG(ERROR) << "Version of " << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << "Version of " << ctx.dist->GetDisplayName()
                  << " (" << ctx.state.version().GetString() << ") does not "
                     "match that of Chrome Binaries ("
                  << binaries->version().GetString() << ").";
@@ -738,7 +738,7 @@
     // Channel value must match that of binaries.
     if (!ctx.state.channel().Equals(binaries->channel())) {
       *is_valid = false;
-      LOG(ERROR) << "Channel name of " << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << "Channel name of " << ctx.dist->GetDisplayName()
                  << " (" << ctx.state.channel().value()
                  << ") does not match that of Chrome Binaries ("
                  << binaries->channel().value() << ").";
@@ -772,12 +772,12 @@
   if (ctx.state.GetUsageStats(&usagestats)) {
     if (!ctx.rules.UsageStatsAllowed(ctx)) {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << ctx.dist->GetDisplayName()
                  << " has a usagestats value (" << usagestats
                  << "), yet should not.";
     } else if (usagestats != 0 && usagestats != 1) {
       *is_valid = false;
-      LOG(ERROR) << ctx.dist->GetAppShortCutName()
+      LOG(ERROR) << ctx.dist->GetDisplayName()
                  << " has an unsupported usagestats value (" << usagestats
                  << ").";
     }
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc
index 07b75b3..bba1e3b 100644
--- a/chrome/installer/util/installer_state.cc
+++ b/chrome/installer/util/installer_state.cc
@@ -123,20 +123,20 @@
     Product* p = AddProductFromPreferences(
         BrowserDistribution::CHROME_BROWSER, prefs, machine_state);
     VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
-            << " distribution: " << p->distribution()->GetAppShortCutName();
+            << " distribution: " << p->distribution()->GetDisplayName();
   }
   if (prefs.install_chrome_frame()) {
     Product* p = AddProductFromPreferences(
         BrowserDistribution::CHROME_FRAME, prefs, machine_state);
     VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
-            << " distribution: " << p->distribution()->GetAppShortCutName();
+            << " distribution: " << p->distribution()->GetDisplayName();
   }
 
   if (prefs.install_chrome_app_launcher()) {
     Product* p = AddProductFromPreferences(
         BrowserDistribution::CHROME_APP_HOST, prefs, machine_state);
     VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
-            << " distribution: " << p->distribution()->GetAppShortCutName();
+            << " distribution: " << p->distribution()->GetDisplayName();
   }
 
   if (!is_uninstall && is_multi_install()) {
@@ -169,7 +169,7 @@
       Product* p = AddProductFromPreferences(
           BrowserDistribution::CHROME_BINARIES, prefs, machine_state);
       VLOG(1) << "Install distribution: "
-              << p->distribution()->GetAppShortCutName();
+              << p->distribution()->GetDisplayName();
     }
   }
 
@@ -208,7 +208,7 @@
           Product* p = AddProductFromPreferences(
               conditional_additions[i].type, prefs, machine_state);
           VLOG(1) << "Uninstall distribution: "
-                  << p->distribution()->GetAppShortCutName();
+                  << p->distribution()->GetDisplayName();
         }
       }
     }
@@ -271,7 +271,7 @@
       Product* p = AddProductFromPreferences(
           BrowserDistribution::CHROME_BINARIES, prefs, machine_state);
       VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
-              << " distribution: " << p->distribution()->GetAppShortCutName();
+              << " distribution: " << p->distribution()->GetDisplayName();
     }
   }
 
diff --git a/chrome/installer/util/prebuild/create_string_rc.py b/chrome/installer/util/prebuild/create_string_rc.py
index 12e68ce..03c17a0 100755
--- a/chrome/installer/util/prebuild/create_string_rc.py
+++ b/chrome/installer/util/prebuild/create_string_rc.py
@@ -78,6 +78,8 @@
   'IDS_APP_LAUNCHER_PRODUCT_DESCRIPTION',
   'IDS_APP_LAUNCHER_SHORTCUT_TOOLTIP',
   'IDS_UNINSTALL_APP_LAUNCHER',
+  'IDS_APP_LIST_SHORTCUT_NAME',
+  'IDS_APP_LIST_SHORTCUT_NAME_CANARY',
 ]
 
 # The ID of the first resource string.
diff --git a/chrome/installer/util/product.cc b/chrome/installer/util/product.cc
index dc70b16..44e7cef 100644
--- a/chrome/installer/util/product.cc
+++ b/chrome/installer/util/product.cc
@@ -168,7 +168,7 @@
                                    bool system_level) const {
   if (distribution_->HasUserExperiments()) {
     VLOG(1) << "LaunchUserExperiment status: " << status << " product: "
-            << distribution_->GetAppShortCutName()
+            << distribution_->GetDisplayName()
             << " system_level: " << system_level;
     operations_->LaunchUserExperiment(
         setup_path, options_, status, system_level);
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 57521e8..a5122d5 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -219,7 +219,9 @@
                                const string16& suffix,
                                ScopedVector<RegistryEntry>* entries) {
     string16 icon_path(
-        ShellUtil::FormatIconLocation(chrome_exe, dist->GetIconIndex()));
+        ShellUtil::FormatIconLocation(
+            chrome_exe,
+            dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
     string16 open_cmd(ShellUtil::GetChromeShellOpenCmd(chrome_exe));
     string16 delegate_command(ShellUtil::GetChromeDelegateCommand(chrome_exe));
     // For user-level installs: entries for the app id and DelegateExecute verb
@@ -317,7 +319,7 @@
       // resource for name, description, and company.
       entries->push_back(new RegistryEntry(
           chrome_application, ShellUtil::kRegApplicationName,
-          dist->GetAppShortCutName()));
+          dist->GetDisplayName()));
       entries->push_back(new RegistryEntry(
           chrome_application, ShellUtil::kRegApplicationDescription,
           dist->GetAppDescription()));
@@ -350,7 +352,9 @@
                                          const string16& suffix,
                                          ScopedVector<RegistryEntry>* entries) {
     const string16 icon_path(
-        ShellUtil::FormatIconLocation(chrome_exe, dist->GetIconIndex()));
+        ShellUtil::FormatIconLocation(
+            chrome_exe,
+            dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
     const string16 quoted_exe_path(L"\"" + chrome_exe + L"\"");
 
     // Register for the Start Menu "Internet" link (pre-Win7).
@@ -359,7 +363,7 @@
     // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see
     // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85).aspx#registering_the_display_name
     entries->push_back(new RegistryEntry(
-        start_menu_entry, dist->GetAppShortCutName()));
+        start_menu_entry, dist->GetDisplayName()));
     // Register the "open" verb for launching Chrome via the "Internet" link.
     entries->push_back(new RegistryEntry(
         start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path));
@@ -395,7 +399,7 @@
         capabilities, ShellUtil::kRegApplicationIcon, icon_path));
     entries->push_back(new RegistryEntry(
         capabilities, ShellUtil::kRegApplicationName,
-        dist->GetAppShortCutName()));
+        dist->GetDisplayName()));
 
     entries->push_back(new RegistryEntry(capabilities + L"\\Startmenu",
         L"StartMenuInternet", reg_app_name));
@@ -501,7 +505,9 @@
     // Protocols associations.
     string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
     string16 chrome_icon =
-        ShellUtil::FormatIconLocation(chrome_exe, dist->GetIconIndex());
+        ShellUtil::FormatIconLocation(
+            chrome_exe,
+            dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME));
     for (int i = 0; ShellUtil::kBrowserProtocolAssociations[i] != NULL; i++) {
       GetXPStyleUserProtocolEntries(ShellUtil::kBrowserProtocolAssociations[i],
                                     chrome_icon, chrome_open, entries);
@@ -906,7 +912,9 @@
   ScopedVector<RegistryEntry> entries;
   const string16 chrome_open(ShellUtil::GetChromeShellOpenCmd(chrome_exe));
   const string16 chrome_icon(
-      ShellUtil::FormatIconLocation(chrome_exe, dist->GetIconIndex()));
+      ShellUtil::FormatIconLocation(
+          chrome_exe,
+          dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME)));
   RegistryEntry::GetXPStyleUserProtocolEntries(protocol, chrome_icon,
                                                chrome_open, &entries);
   // Change the default protocol handler for current user.
@@ -919,17 +927,19 @@
 }
 
 // Returns |properties.shortcut_name| if the property is set, otherwise it
-// returns dist->GetAppShortcutName(). In any case, it makes sure the
-// return value is suffixed with ".lnk".
+// returns dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME). In any
+// case, it makes sure the return value is suffixed with ".lnk".
 string16 ExtractShortcutNameFromProperties(
     BrowserDistribution* dist,
     const ShellUtil::ShortcutProperties& properties) {
   DCHECK(dist);
   string16 shortcut_name;
-  if (properties.has_shortcut_name())
+  if (properties.has_shortcut_name()) {
     shortcut_name = properties.shortcut_name;
-  else
-    shortcut_name = dist->GetAppShortCutName();
+  } else {
+    shortcut_name =
+        dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME);
+  }
 
   if (!EndsWith(shortcut_name, installer::kLnkExt, false))
     shortcut_name.append(installer::kLnkExt);
@@ -1289,11 +1299,13 @@
   return success;
 }
 
-// Removes folder spsecified by {|location|, |dist|, |level|}.
-bool RemoveShortcutFolder(ShellUtil::ShortcutLocation location,
-                          BrowserDistribution* dist,
-                          ShellUtil::ShellChange level) {
 
+// If the folder specified by {|location|, |dist|, |level|} is empty, remove it.
+// Otherwise do nothing. Returns true on success, including the vacuous case
+// where no deletion occurred because directory is non-empty.
+bool RemoveShortcutFolderIfEmpty(ShellUtil::ShortcutLocation location,
+                                 BrowserDistribution* dist,
+                                 ShellUtil::ShellChange level) {
   // Explicitly whitelist locations, since accidental calls can be very harmful.
   if (location != ShellUtil::SHORTCUT_LOCATION_START_MENU &&
       location != ShellUtil::SHORTCUT_LOCATION_APP_SHORTCUTS) {
@@ -1306,7 +1318,8 @@
     LOG(WARNING) << "Cannot find path at location " << location;
     return false;
   }
-  if (!base::DeleteFile(shortcut_folder, true)) {
+  if (file_util::IsDirectoryEmpty(shortcut_folder) &&
+      !base::DeleteFile(shortcut_folder, true)) {
     LOG(ERROR) << "Cannot remove folder " << shortcut_folder.value();
     return false;
   }
@@ -1434,8 +1447,10 @@
     return false;
   }
 
-  if (add_folder_for_dist)
-    *path = path->Append(dist->GetAppShortCutName());
+  if (add_folder_for_dist) {
+    *path = path->Append(dist->GetStartMenuShortcutSubfolder(
+        BrowserDistribution::SUBFOLDER_CHROME));
+  }
 
   return true;
 }
@@ -2027,27 +2042,20 @@
   if (!ShellUtil::ShortcutLocationIsSupported(location))
     return true;  // Vacuous success.
 
-  switch (location) {
-    case SHORTCUT_LOCATION_START_MENU:  // Falls through.
-    case SHORTCUT_LOCATION_APP_SHORTCUTS:
-      return RemoveShortcutFolder(location, dist, level);
-
-    case SHORTCUT_LOCATION_TASKBAR_PINS:
-      return BatchShortcutAction(FilterTargetEq(target_exe).
-                                     AsShortcutFilterCallback(),
-                                 base::Bind(&ShortcutOpUnpin),
-                                 location,
-                                 dist,
-                                 level);
-
-    default:
-      return BatchShortcutAction(FilterTargetEq(target_exe).
-                                     AsShortcutFilterCallback(),
-                                 base::Bind(&ShortcutOpDelete),
-                                 location,
-                                 dist,
-                                 level);
+  FilterTargetEq shortcut_filter(target_exe);
+  // Main operation to apply to each shortcut in the directory specified.
+  ShortcutOperationCallback shortcut_operation(
+      location == SHORTCUT_LOCATION_TASKBAR_PINS ?
+          base::Bind(&ShortcutOpUnpin) : base::Bind(&ShortcutOpDelete));
+  bool success = BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
+                                     shortcut_operation, location, dist, level);
+  // Remove chrome-specific shortcut folders if they are now empty.
+  if (success &&
+      (location == SHORTCUT_LOCATION_START_MENU ||
+       location == SHORTCUT_LOCATION_APP_SHORTCUTS)) {
+    success = RemoveShortcutFolderIfEmpty(location, dist, level);
   }
+  return success;
 }
 
 // static
@@ -2060,14 +2068,11 @@
   if (!ShellUtil::ShortcutLocationIsSupported(location))
     return true;  // Vacuous success.
 
-  base::win::ShortcutProperties shortcut_properties(
-      TranslateShortcutProperties(properties));
-  return BatchShortcutAction(FilterTargetEq(target_exe).
-                                 AsShortcutFilterCallback(),
-                             base::Bind(&ShortcutOpUpdate, shortcut_properties),
-                             location,
-                             dist,
-                             level);
+  FilterTargetEq shortcut_filter(target_exe);
+  ShortcutOperationCallback shortcut_operation(
+      base::Bind(&ShortcutOpUpdate, TranslateShortcutProperties(properties)));
+  return BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
+                             shortcut_operation, location, dist, level);
 }
 
 bool ShellUtil::GetUserSpecificRegistrySuffix(string16* suffix) {
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index c1d0c32..7d42c3c 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -127,7 +127,7 @@
     }
 
     // Forces the shortcut's name to |shortcut_name_in|.
-    // Default: the current distribution's GetAppShortcutName().
+    // Default: the current distribution's GetShortcutName(SHORTCUT_CHROME).
     // The ".lnk" extension will automatically be added to this name.
     void set_shortcut_name(const string16& shortcut_name_in) {
       shortcut_name = shortcut_name_in;
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 647ec28..4000813 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -104,7 +104,9 @@
       case ShellUtil::SHORTCUT_LOCATION_START_MENU:
         expected_path = (properties.level == ShellUtil::CURRENT_USER) ?
             fake_start_menu_.path() : fake_common_start_menu_.path();
-        expected_path = expected_path.Append(dist_->GetAppShortCutName());
+        expected_path = expected_path.Append(
+            dist_->GetStartMenuShortcutSubfolder(
+                BrowserDistribution::SUBFOLDER_CHROME));
         break;
       default:
         ADD_FAILURE() << "Unknown location";
@@ -112,10 +114,12 @@
     }
 
     string16 shortcut_name;
-    if (properties.has_shortcut_name())
+    if (properties.has_shortcut_name()) {
       shortcut_name = properties.shortcut_name;
-    else
-      shortcut_name = dist_->GetAppShortCutName();
+    } else {
+      shortcut_name =
+          dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME);
+    }
     shortcut_name.append(installer::kLnkExt);
     expected_path = expected_path.Append(shortcut_name);
 
@@ -141,7 +145,7 @@
     if (properties.has_icon()) {
       expected_properties.set_icon(properties.icon, 0);
     } else {
-      int icon_index = dist->GetIconIndex();
+      int icon_index = dist->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME);
       expected_properties.set_icon(chrome_exe_, icon_index);
     }
 
@@ -200,12 +204,16 @@
   ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
                              ShellUtil::SYSTEM_LEVEL, &path);
   EXPECT_EQ(fake_default_user_quick_launch_.path(), path);
+  string16 start_menu_subfolder =
+      dist_->GetStartMenuShortcutSubfolder(
+          BrowserDistribution::SUBFOLDER_CHROME);
   ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
                              ShellUtil::CURRENT_USER, &path);
-  EXPECT_EQ(fake_start_menu_.path().Append(dist_->GetAppShortCutName()), path);
+  EXPECT_EQ(fake_start_menu_.path().Append(start_menu_subfolder),
+            path);
   ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist_,
                              ShellUtil::SYSTEM_LEVEL, &path);
-  EXPECT_EQ(fake_common_start_menu_.path().Append(dist_->GetAppShortCutName()),
+  EXPECT_EQ(fake_common_start_menu_.path().Append(start_menu_subfolder),
             path);
 }
 
@@ -308,7 +316,9 @@
 }
 
 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelWithSystemLevelPresent) {
-  string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+  string16 shortcut_name(
+      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
 
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
@@ -335,7 +345,9 @@
 }
 
 TEST_F(ShellUtilShortcutTest, CreateAlwaysUserWithSystemLevelPresent) {
-  string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+  string16 shortcut_name(
+      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
 
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
@@ -357,7 +369,9 @@
                   ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
                   ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+  string16 shortcut_name(
+      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
   base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name));
   ASSERT_TRUE(base::PathExists(shortcut_path));
 
@@ -374,7 +388,9 @@
                   ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
                   ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+  string16 shortcut_name(
+      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
   base::FilePath shortcut_path(
       fake_common_desktop_.path().Append(shortcut_name));
   ASSERT_TRUE(base::PathExists(shortcut_path));
@@ -423,7 +439,9 @@
                   ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
                   ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+  string16 shortcut_name(
+      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
   base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name));
   ASSERT_TRUE(base::PathExists(shortcut_path));
 
@@ -447,7 +465,9 @@
                   ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
                   ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+  string16 shortcut_name(
+      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
   base::FilePath shortcut_path(
       fake_common_desktop_.path().Append(shortcut_name));
   ASSERT_TRUE(base::PathExists(shortcut_path));
@@ -525,7 +545,9 @@
                   ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
   base::FilePath shortcut_folder(
-      fake_start_menu_.path().Append(dist_->GetAppShortCutName()));
+      fake_start_menu_.path().Append(
+          dist_->GetStartMenuShortcutSubfolder(
+              BrowserDistribution::SUBFOLDER_CHROME)));
   base::FileEnumerator file_counter(shortcut_folder, false,
                                     base::FileEnumerator::FILES);
   int count = 0;
@@ -552,7 +574,9 @@
                   ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
                   ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  string16 shortcut_name(dist_->GetAppShortCutName() + installer::kLnkExt);
+  string16 shortcut_name(
+      dist_->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
   base::FilePath shortcut_path(fake_user_desktop_.path().Append(shortcut_name));
   ASSERT_TRUE(base::PathExists(shortcut_path));
 
diff --git a/chrome/interactive_ui_tests.isolate b/chrome/interactive_ui_tests.isolate
index 554fdd0..057e0b9 100644
--- a/chrome/interactive_ui_tests.isolate
+++ b/chrome/interactive_ui_tests.isolate
@@ -14,7 +14,6 @@
         ],
         'isolate_dependency_tracked': [
           '../testing/xvfb.py',
-          '<(PRODUCT_DIR)/chrome.pak',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/pyproto/google/__init__.py',
           '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
@@ -32,8 +31,6 @@
           '../net/tools/testserver/testserver.py',
           '../net/tools/testserver/testserver_base.py',
           '../testing/test_env.py',
-          '../tools/swarm_client/run_isolated.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/interactive_ui_tests<(EXECUTABLE_SUFFIX)',
           '<(PRODUCT_DIR)/resources.pak',
         ],
@@ -41,6 +38,7 @@
           '../third_party/pyftpdlib/',
           '../third_party/pywebsocket/src/mod_pywebsocket/',
           '../third_party/tlslite/tlslite/',
+          '../tools/swarm_client/',
           'test/data/',
         ],
       },
diff --git a/chrome/nacl/nacl_exe_win_64.cc b/chrome/nacl/nacl_exe_win_64.cc
index 4e480d5..47e19c6 100644
--- a/chrome/nacl/nacl_exe_win_64.cc
+++ b/chrome/nacl/nacl_exe_win_64.cc
@@ -40,8 +40,6 @@
 // main() routine for the NaCl broker process.
 // This is necessary for supporting NaCl in Chrome on Win64.
 int NaClBrokerMain(const content::MainFunctionParams& parameters) {
-  const CommandLine& parsed_command_line = parameters.command_line;
-
   base::MessageLoopForIO main_message_loop;
   base::PlatformThread::SetName("CrNaClBrokerMain");
 
diff --git a/chrome/nacl/nacl_helper_linux.cc b/chrome/nacl/nacl_helper_linux.cc
index 9041793..e823b53 100644
--- a/chrome/nacl/nacl_helper_linux.cc
+++ b/chrome/nacl/nacl_helper_linux.cc
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <link.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/socket.h>
@@ -20,12 +21,12 @@
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
-#include "base/json/string_escape.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/global_descriptors.h"
 #include "base/posix/unix_domain_socket_linux.h"
+#include "base/process/kill.h"
 #include "base/rand_util.h"
 #include "components/nacl/loader/nacl_listener.h"
 #include "components/nacl/loader/nacl_sandbox_linux.h"
@@ -36,12 +37,16 @@
 
 namespace {
 
+struct NaClLoaderSystemInfo {
+  size_t prereserved_sandbox_size;
+  long number_of_cores;
+};
+
 // The child must mimic the behavior of zygote_main_linux.cc on the child
 // side of the fork. See zygote_main_linux.cc:HandleForkRequest from
 //   if (!child) {
 void BecomeNaClLoader(const std::vector<int>& child_fds,
-                      size_t prereserved_sandbox_size,
-                      int number_of_cores) {
+                      const NaClLoaderSystemInfo& system_info) {
   VLOG(1) << "NaCl loader: setting up IPC descriptor";
   // don't need zygote FD any more
   if (HANDLE_EINTR(close(kNaClZygoteDescriptor)) != 0)
@@ -56,61 +61,75 @@
 
   base::MessageLoopForIO main_message_loop;
   NaClListener listener;
-  listener.set_prereserved_sandbox_size(prereserved_sandbox_size);
-  listener.set_number_of_cores(number_of_cores);
+  listener.set_prereserved_sandbox_size(system_info.prereserved_sandbox_size);
+  listener.set_number_of_cores(system_info.number_of_cores);
   listener.Listen();
   _exit(0);
 }
 
+// Start the NaCl loader in a child created by the NaCl loader Zygote.
+void ChildNaClLoaderInit(const std::vector<int>& child_fds,
+                         const NaClLoaderSystemInfo& system_info) {
+  bool validack = false;
+  const size_t kMaxReadSize = 1024;
+  char buffer[kMaxReadSize];
+  // Wait until the parent process has discovered our PID.  We
+  // should not fork any child processes (which the seccomp
+  // sandbox does) until then, because that can interfere with the
+  // parent's discovery of our PID.
+  const int nread = HANDLE_EINTR(read(child_fds[kNaClParentFDIndex], buffer,
+                                      kMaxReadSize));
+  const std::string switch_prefix = std::string("--") +
+      switches::kProcessChannelID + std::string("=");
+  const size_t len = switch_prefix.length();
+
+  if (nread < 0) {
+    perror("read");
+    LOG(ERROR) << "read returned " << nread;
+  } else if (nread > static_cast<int>(len)) {
+    if (switch_prefix.compare(0, len, buffer, 0, len) == 0) {
+      VLOG(1) << "NaCl loader is synchronised with Chrome zygote";
+      CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kProcessChannelID,
+          std::string(&buffer[len], nread - len));
+      validack = true;
+    }
+  }
+  if (HANDLE_EINTR(close(child_fds[kNaClDummyFDIndex])) != 0)
+    LOG(ERROR) << "close(child_fds[kNaClDummyFDIndex]) failed";
+  if (HANDLE_EINTR(close(child_fds[kNaClParentFDIndex])) != 0)
+    LOG(ERROR) << "close(child_fds[kNaClParentFDIndex]) failed";
+  if (validack) {
+    BecomeNaClLoader(child_fds, system_info);
+  } else {
+    LOG(ERROR) << "Failed to synch with zygote";
+  }
+  _exit(1);
+}
+
+// Handle a fork request from the Zygote.
 // Some of this code was lifted from
 // content/browser/zygote_main_linux.cc:ForkWithRealPid()
-void HandleForkRequest(const std::vector<int>& child_fds,
-                       size_t prereserved_sandbox_size,
-                       int number_of_cores) {
-  VLOG(1) << "nacl_helper: forking";
-  pid_t childpid = fork();
-  if (childpid < 0) {
-    perror("fork");
-    LOG(ERROR) << "*** HandleForkRequest failed\n";
-    // fall through to parent case below
-  } else if (childpid == 0) {  // In the child process.
-    bool validack = false;
-    const size_t kMaxReadSize = 1024;
-    char buffer[kMaxReadSize];
-    // Wait until the parent process has discovered our PID.  We
-    // should not fork any child processes (which the seccomp
-    // sandbox does) until then, because that can interfere with the
-    // parent's discovery of our PID.
-    const int nread = HANDLE_EINTR(read(child_fds[kNaClParentFDIndex], buffer,
-                                        kMaxReadSize));
-    const std::string switch_prefix = std::string("--") +
-        switches::kProcessChannelID + std::string("=");
-    const size_t len = switch_prefix.length();
-
-    if (nread < 0) {
-      perror("read");
-      LOG(ERROR) << "read returned " << nread;
-    } else if (nread > static_cast<int>(len)) {
-      if (switch_prefix.compare(0, len, buffer, 0, len) == 0) {
-        VLOG(1) << "NaCl loader is synchronised with Chrome zygote";
-        CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-            switches::kProcessChannelID,
-            std::string(&buffer[len], nread - len));
-        validack = true;
-      }
-    }
-    if (HANDLE_EINTR(close(child_fds[kNaClDummyFDIndex])) != 0)
-      LOG(ERROR) << "close(child_fds[kNaClDummyFDIndex]) failed";
-    if (HANDLE_EINTR(close(child_fds[kNaClParentFDIndex])) != 0)
-      LOG(ERROR) << "close(child_fds[kNaClParentFDIndex]) failed";
-    if (validack) {
-      BecomeNaClLoader(child_fds, prereserved_sandbox_size, number_of_cores);
-    } else {
-      LOG(ERROR) << "Failed to synch with zygote";
-    }
-    // NOTREACHED
-    return;
+bool HandleForkRequest(const std::vector<int>& child_fds,
+                       const NaClLoaderSystemInfo& system_info,
+                       Pickle* output_pickle) {
+  if (kNaClParentFDIndex + 1 != child_fds.size()) {
+    LOG(ERROR) << "nacl_helper: unexpected number of fds, got "
+        << child_fds.size();
+    return false;
   }
+
+  VLOG(1) << "nacl_helper: forking";
+  pid_t child_pid = fork();
+  if (child_pid < 0) {
+    PLOG(ERROR) << "*** fork() failed.";
+  }
+
+  if (child_pid == 0) {
+    ChildNaClLoaderInit(child_fds, system_info);
+    NOTREACHED();
+  }
+
   // I am the parent.
   // First, close the dummy_fd so the sandbox won't find me when
   // looking for the child's pid in /proc. Also close other fds.
@@ -118,13 +137,47 @@
     if (HANDLE_EINTR(close(child_fds[i])) != 0)
       LOG(ERROR) << "close(child_fds[i]) failed";
   }
-  VLOG(1) << "nacl_helper: childpid is " << childpid;
-  // Now tell childpid to the Chrome zygote.
-  if (HANDLE_EINTR(send(kNaClZygoteDescriptor,
-                        &childpid, sizeof(childpid), MSG_EOR))
-      != sizeof(childpid)) {
-    LOG(ERROR) << "*** send() to zygote failed";
+  VLOG(1) << "nacl_helper: child_pid is " << child_pid;
+
+  // Now send child_pid (eventually -1 if fork failed) to the Chrome Zygote.
+  output_pickle->WriteInt(child_pid);
+  return true;
+}
+
+bool HandleGetTerminationStatusRequest(PickleIterator* input_iter,
+                                       Pickle* output_pickle) {
+  pid_t child_to_wait;
+  if (!input_iter->ReadInt(&child_to_wait)) {
+    LOG(ERROR) << "Could not read pid to wait for";
+    return false;
   }
+
+  bool known_dead;
+  if (!input_iter->ReadBool(&known_dead)) {
+    LOG(ERROR) << "Could not read known_dead status";
+    return false;
+  }
+  // TODO(jln): With NaCl, known_dead seems to never be set to true (unless
+  // called from the Zygote's kZygoteCommandReap command). This means that we
+  // will sometimes detect the process as still running when it's not. Fix
+  // this!
+
+  int exit_code;
+  base::TerminationStatus status;
+  // See the comment in the Zygote about known_dead.
+  if (known_dead) {
+    // Make sure to not perform a blocking wait on something that
+    // could still be alive.
+    if (kill(child_to_wait, SIGKILL)) {
+      PLOG(ERROR) << "kill (" << child_to_wait << ")";
+    }
+    status = base::WaitForTerminationStatus(child_to_wait, &exit_code);
+  } else {
+    status = base::GetTerminationStatus(child_to_wait, &exit_code);
+  }
+  output_pickle->WriteInt(static_cast<int>(status));
+  output_pickle->WriteInt(exit_code);
+  return true;
 }
 
 // This is a poor man's check on whether we are sandboxed.
@@ -137,7 +190,76 @@
   return true;
 }
 
-}  // namespace
+// Honor a command |command_type|. Eventual command parameters are
+// available in |input_iter| and eventual file descriptors attached to
+// the command are in |attached_fds|.
+// Reply to the command on |reply_fds|.
+bool HonorRequestAndReply(int reply_fd,
+                          int command_type,
+                          const std::vector<int>& attached_fds,
+                          const NaClLoaderSystemInfo& system_info,
+                          PickleIterator* input_iter) {
+  Pickle write_pickle;
+  bool have_to_reply = false;
+  // Commands must write anything to send back to |write_pickle|.
+  switch (command_type) {
+    case kNaClForkRequest:
+      have_to_reply = HandleForkRequest(attached_fds, system_info,
+                                        &write_pickle);
+      break;
+    case kNaClGetTerminationStatusRequest:
+      have_to_reply =
+          HandleGetTerminationStatusRequest(input_iter, &write_pickle);
+      break;
+    default:
+      LOG(ERROR) << "Unsupported command from Zygote";
+      return false;
+  }
+  if (!have_to_reply)
+    return false;
+  const std::vector<int> empty;  // We never send file descriptors back.
+  if (!UnixDomainSocket::SendMsg(reply_fd, write_pickle.data(),
+                                 write_pickle.size(), empty)) {
+    LOG(ERROR) << "*** send() to zygote failed";
+    return false;
+  }
+  return true;
+}
+
+// Read a request from the Zygote from |zygote_ipc_fd| and handle it.
+// Die on EOF from |zygote_ipc_fd|.
+bool HandleZygoteRequest(int zygote_ipc_fd,
+                         const NaClLoaderSystemInfo& system_info) {
+  std::vector<int> fds;
+  char buf[kNaClMaxIPCMessageLength];
+  const ssize_t msglen = UnixDomainSocket::RecvMsg(zygote_ipc_fd,
+      &buf, sizeof(buf), &fds);
+  // If the Zygote has started handling requests, we should be sandboxed via
+  // the setuid sandbox.
+  if (!IsSandboxed()) {
+    LOG(ERROR) << "NaCl helper process running without a sandbox!\n"
+      << "Most likely you need to configure your SUID sandbox "
+      << "correctly";
+  }
+  if (msglen == 0 || (msglen == -1 && errno == ECONNRESET)) {
+    // EOF from the browser. Goodbye!
+    _exit(0);
+  }
+  if (msglen < 0) {
+    PLOG(ERROR) << "nacl_helper: receive from zygote failed";
+    return false;
+  }
+
+  Pickle read_pickle(buf, msglen);
+  PickleIterator read_iter(read_pickle);
+  int command_type;
+  if (!read_iter.ReadInt(&command_type)) {
+    LOG(ERROR) << "Unable to read command from Zygote";
+    return false;
+  }
+  return HonorRequestAndReply(zygote_ipc_fd, command_type, fds, system_info,
+                              &read_iter);
+}
 
 static const char kNaClHelperReservedAtZero[] = "reserved_at_zero";
 static const char kNaClHelperRDebug[] = "r_debug";
@@ -206,6 +328,8 @@
   return prereserved_sandbox_size;
 }
 
+}  // namespace
+
 #if defined(ADDRESS_SANITIZER)
 // Do not install the SIGSEGV handler in ASan. This should make the NaCl
 // platform qualification test pass.
@@ -240,15 +364,17 @@
   // NSS is needed to perform hashing for validation caching.
   crypto::LoadNSSLibraries();
 #endif
-  std::vector<int> empty; // for SendMsg() calls
-  size_t prereserved_sandbox_size = CheckReservedAtZero();
-  int number_of_cores = sysconf(_SC_NPROCESSORS_ONLN);
+  const NaClLoaderSystemInfo system_info = {
+    CheckReservedAtZero(),
+    sysconf(_SC_NPROCESSORS_ONLN)
+  };
 
   CheckRDebug(argv[0]);
 
   // Check that IsSandboxed() works. We should not be sandboxed at this point.
   CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!";
 
+  const std::vector<int> empty;
   // Send the zygote a message to let it know we are ready to help
   if (!UnixDomainSocket::SendMsg(kNaClZygoteDescriptor,
                                  kNaClHelperStartupAck,
@@ -256,45 +382,13 @@
     LOG(ERROR) << "*** send() to zygote failed";
   }
 
+  // Now handle requests from the Zygote.
   while (true) {
-    int badpid = -1;
-    std::vector<int> fds;
-    static const unsigned kMaxMessageLength = 2048;
-    char buf[kMaxMessageLength];
-    const ssize_t msglen = UnixDomainSocket::RecvMsg(kNaClZygoteDescriptor,
-                                                     &buf, sizeof(buf), &fds);
-    // If the Zygote has started handling requests, we should be sandboxed via
-    // the setuid sandbox.
-    if (!IsSandboxed()) {
-      LOG(ERROR) << "NaCl helper process running without a sandbox!\n"
-                 << "Most likely you need to configure your SUID sandbox "
-                 << "correctly";
-    }
-    if (msglen == 0 || (msglen == -1 && errno == ECONNRESET)) {
-      // EOF from the browser. Goodbye!
-      _exit(0);
-    } else if (msglen < 0) {
-      LOG(ERROR) << "nacl_helper: receive from zygote failed, errno = "
-                 << errno;
-    } else if (msglen == sizeof(kNaClForkRequest) - 1 &&
-               memcmp(buf, kNaClForkRequest, msglen) == 0) {
-      if (kNaClParentFDIndex + 1 == fds.size()) {
-        HandleForkRequest(fds, prereserved_sandbox_size, number_of_cores);
-        continue;  // fork succeeded. Note: child does not return
-      } else {
-        LOG(ERROR) << "nacl_helper: unexpected number of fds, got "
-                   << fds.size();
-      }
-    } else {
-      LOG(ERROR) << "nacl_helper unrecognized request: "
-                 << base::GetDoubleQuotedJson(std::string(buf, buf + msglen));
-      _exit(-1);
-    }
-    // if fork fails, send PID=-1 to zygote
-    if (!UnixDomainSocket::SendMsg(kNaClZygoteDescriptor, &badpid,
-                                   sizeof(badpid), empty)) {
-      LOG(ERROR) << "*** send() to zygote failed";
-    }
+    bool request_handled = HandleZygoteRequest(kNaClZygoteDescriptor,
+                                               system_info);
+    // Do not turn this into a CHECK() without thinking about robustness
+    // against malicious IPC requests.
+    DCHECK(request_handled);
   }
-  CHECK(false);  // This routine must not return
+  NOTREACHED();
 }
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index 8d85303..cbb05e4 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/test/base/chrome_render_view_test.h"
+#include "components/autofill/content/renderer/autofill_agent.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index 975b4f4..44de922 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -6,7 +6,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/test/base/chrome_render_view_test.h"
 #include "components/autofill/content/renderer/autofill_agent.h"
+#include "components/autofill/content/renderer/form_autofill_util.h"
 #include "components/autofill/content/renderer/password_autofill_agent.h"
+#include "components/autofill/content/renderer/test_password_autofill_agent.h"
 #include "components/autofill/core/common/autofill_messages.h"
 #include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/form_field_data.h"
@@ -32,25 +34,49 @@
 namespace {
 
 // The name of the username/password element in the form.
-const char* const kUsernameName = "username";
-const char* const kPasswordName = "password";
+const char kUsernameName[] = "username";
+const char kPasswordName[] = "password";
 
-const char* const kAliceUsername = "alice";
-const char* const kAlicePassword = "password";
-const char* const kBobUsername = "bob";
-const char* const kBobPassword = "secret";
-const char* const kCarolUsername = "Carol";
-const char* const kCarolPassword = "test";
-const char* const kCarolAlternateUsername = "RealCarolUsername";
+const char kAliceUsername[] = "alice";
+const char kAlicePassword[] = "password";
+const char kBobUsername[] = "bob";
+const char kBobPassword[] = "secret";
+const char kCarolUsername[] = "Carol";
+const char kCarolPassword[] = "test";
+const char kCarolAlternateUsername[] = "RealCarolUsername";
 
 
-const char* const kFormHTML =
+const char kFormHTML[] =
     "<FORM name='LoginTestForm' action='http://www.bidule.com'>"
     "  <INPUT type='text' id='username'/>"
     "  <INPUT type='password' id='password'/>"
     "  <INPUT type='submit' value='Login'/>"
     "</FORM>";
 
+const char kVisibleFormHTML[] =
+    "<head> <style> form {display: inline;} </style> </head>"
+    "<body>"
+    "  <form>"
+    "    <div>"
+    "      <input type='password' id='password'/>"
+    "    </div>"
+    "  </form>"
+    "</body>";
+
+const char kEmptyFormHTML[] =
+    "<head> <style> form {display: inline;} </style> </head>"
+    "<body> <form> </form> </body>";
+
+const char kNonVisibleFormHTML[] =
+    "<head> <style> form {display: none;} </style> </head>"
+    "<body>"
+    "  <form>"
+    "    <div>"
+    "      <input type='password' id='password'/>"
+    "    </div>"
+    "  </form>"
+    "</body>";
+
 }  // namespace
 
 namespace autofill {
@@ -499,4 +525,54 @@
   CheckTextFieldsState(std::string(), false, std::string(), false);
 }
 
+TEST_F(PasswordAutofillAgentTest, IsWebNodeVisibleTest) {
+  WebKit::WebVector<WebKit::WebFormElement> forms1, forms2, forms3;
+  WebKit::WebFrame* frame;
+
+  LoadHTML(kVisibleFormHTML);
+  frame = GetMainFrame();
+  frame->document().forms(forms1);
+  ASSERT_EQ(1u, forms1.size());
+  EXPECT_TRUE(IsWebNodeVisible(forms1[0]));
+
+  LoadHTML(kEmptyFormHTML);
+  frame = GetMainFrame();
+  frame->document().forms(forms2);
+  ASSERT_EQ(1u, forms2.size());
+  EXPECT_FALSE(IsWebNodeVisible(forms2[0]));
+
+  LoadHTML(kNonVisibleFormHTML);
+  frame = GetMainFrame();
+  frame->document().forms(forms3);
+  ASSERT_EQ(1u, forms3.size());
+  EXPECT_FALSE(IsWebNodeVisible(forms3[0]));
+}
+
+TEST_F(PasswordAutofillAgentTest, SendPasswordFormsTest) {
+  render_thread_->sink().ClearMessages();
+  LoadHTML(kVisibleFormHTML);
+  const IPC::Message* message = render_thread_->sink()
+      .GetFirstMessageMatching(AutofillHostMsg_PasswordFormsRendered::ID);
+  EXPECT_TRUE(message);
+  Tuple1<std::vector<content::PasswordForm> > param;
+  AutofillHostMsg_PasswordFormsRendered::Read(message, &param);
+  EXPECT_TRUE(param.a.size());
+
+  render_thread_->sink().ClearMessages();
+  LoadHTML(kEmptyFormHTML);
+  message = render_thread_->sink().GetFirstMessageMatching(
+      AutofillHostMsg_PasswordFormsRendered::ID);
+  EXPECT_TRUE(message);
+  AutofillHostMsg_PasswordFormsRendered::Read(message, &param);
+  EXPECT_FALSE(param.a.size());
+
+  render_thread_->sink().ClearMessages();
+  LoadHTML(kNonVisibleFormHTML);
+  message = render_thread_->sink().GetFirstMessageMatching(
+      AutofillHostMsg_PasswordFormsRendered::ID);
+  EXPECT_TRUE(message);
+  AutofillHostMsg_PasswordFormsRendered::Read(message, &param);
+  EXPECT_FALSE(param.a.size());
+}
+
 }  // namespace autofill
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index 09ee4e3..1fa7a9c 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -44,7 +44,6 @@
 #include "chrome/renderer/net/prescient_networking_dispatcher.h"
 #include "chrome/renderer/net/renderer_net_predictor.h"
 #include "chrome/renderer/net_benchmarking_extension.h"
-#include "chrome/renderer/one_click_signin_agent.h"
 #include "chrome/renderer/page_load_histograms.h"
 #include "chrome/renderer/pepper/pepper_helper.h"
 #include "chrome/renderer/pepper/ppb_nacl_private_impl.h"
@@ -389,10 +388,6 @@
 #endif
 
   new NetErrorHelper(render_view);
-
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
-  new OneClickSigninAgent(render_view);
-#endif
 }
 
 void ChromeContentRendererClient::SetNumberOfViews(int number_of_views) {
@@ -579,12 +574,13 @@
       case ChromeViewHostMsg_GetPluginInfo_Status::kAllowed: {
         const char* kPnaclMimeType = "application/x-pnacl";
         if (actual_mime_type == kPnaclMimeType) {
-          if (!CommandLine::ForCurrentProcess()->HasSwitch(
-                  switches::kEnablePnacl)) {
+          if (CommandLine::ForCurrentProcess()->HasSwitch(
+                  switches::kDisablePnacl)) {
             frame->addMessageToConsole(
                 WebConsoleMessage(
                     WebConsoleMessage::LevelError,
-                    "Portable Native Client must be enabled in about:flags."));
+                    "Portable Native Client must not be disabled in"
+                    " about:flags."));
             placeholder = PluginPlaceholder::CreateBlockedPlugin(
                 render_view, frame, params, plugin, identifier, group_name,
                 IDR_BLOCKED_PLUGIN_HTML,
@@ -1303,5 +1299,9 @@
   return false;
 }
 
+bool ChromeContentRendererClient::ShouldReportDetailedMessageForSource(
+    const base::string16& source) const {
+  return GURL(source).SchemeIs(extensions::kExtensionScheme);
+}
 
 }  // namespace chrome
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index b4b7231..ef23b28 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -136,6 +136,8 @@
       WebKit::WebPluginContainer* container) OVERRIDE;
   virtual WebKit::WebSpeechSynthesizer* OverrideSpeechSynthesizer(
       WebKit::WebSpeechSynthesizerClient* client) OVERRIDE;
+  virtual bool ShouldReportDetailedMessageForSource(
+      const base::string16& source) const OVERRIDE;
   virtual bool AllowPepperMediaStreamAPI(const GURL& url) OVERRIDE;
 
   // For testing.
diff --git a/chrome/renderer/chrome_content_renderer_client_unittest.cc b/chrome/renderer/chrome_content_renderer_client_unittest.cc
index 6eb6c3f..9155400 100644
--- a/chrome/renderer/chrome_content_renderer_client_unittest.cc
+++ b/chrome/renderer/chrome_content_renderer_client_unittest.cc
@@ -7,8 +7,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_builder.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "content/public/common/webplugininfo.h"
+#include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
@@ -91,8 +91,8 @@
   if (is_hosted_app) {
     base::ListValue* url_list = new base::ListValue();
     url_list->Append(base::Value::CreateStringValue(app_url));
-    manifest.Set(extension_manifest_keys::kWebURLs, url_list);
-    manifest.SetString(extension_manifest_keys::kLaunchWebURL, app_url);
+    manifest.Set(extensions::manifest_keys::kWebURLs, url_list);
+    manifest.SetString(extensions::manifest_keys::kLaunchWebURL, app_url);
   }
   std::string error;
   return extensions::Extension::Create(base::FilePath(), location, manifest,
diff --git a/chrome/renderer/chrome_mock_render_thread.cc b/chrome/renderer/chrome_mock_render_thread.cc
index c4bb9c0..c92cb39 100644
--- a/chrome/renderer/chrome_mock_render_thread.cc
+++ b/chrome/renderer/chrome_mock_render_thread.cc
@@ -85,6 +85,7 @@
 #if defined(ENABLE_PRINTING)
 #if defined(OS_CHROMEOS)
 void ChromeMockRenderThread::OnAllocateTempFileForPrinting(
+    int render_view_id,
     base::FileDescriptor* renderer_fd,
     int* browser_fd) {
   renderer_fd->fd = *browser_fd = -1;
diff --git a/chrome/renderer/chrome_mock_render_thread.h b/chrome/renderer/chrome_mock_render_thread.h
index e4214f3..949e3ce 100644
--- a/chrome/renderer/chrome_mock_render_thread.h
+++ b/chrome/renderer/chrome_mock_render_thread.h
@@ -60,8 +60,9 @@
                                 int* port_id);
 
 #if defined(ENABLE_PRINTING)
-#if defined(OS_CHROMEOS)
-  void OnAllocateTempFileForPrinting(base::FileDescriptor* renderer_fd,
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+  void OnAllocateTempFileForPrinting(int render_view_id,
+                                     base::FileDescriptor* renderer_fd,
                                      int* browser_fd);
   void OnTempFileForPrintingWritten(int render_view_id, int browser_fd);
 #endif
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 282607c..ee8cabf 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -65,7 +65,8 @@
 
 namespace {
 
-static const int kCacheStatsDelayMS = 2000;
+const int kCacheStatsDelayMS = 2000;
+const size_t kUnitializedCacheCapacity = UINT_MAX;
 
 class RendererResourceDelegate : public content::ResourceDispatcherDelegate {
  public:
@@ -258,7 +259,11 @@
 ChromeRenderProcessObserver::ChromeRenderProcessObserver(
     chrome::ChromeContentRendererClient* client)
     : client_(client),
-      clear_cache_pending_(false) {
+      clear_cache_pending_(false),
+      webkit_initialized_(false),
+      pending_cache_min_dead_capacity_(0),
+      pending_cache_max_dead_capacity_(0),
+      pending_cache_capacity_(kUnitializedCacheCapacity) {
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
   if (command_line.HasSwitch(switches::kEnableWatchdog)) {
     // TODO(JAR): Need to implement renderer IO msgloop watchdog.
@@ -338,6 +343,13 @@
 }
 
 void ChromeRenderProcessObserver::WebKitInitialized() {
+  webkit_initialized_ = true;
+  if (pending_cache_capacity_ != kUnitializedCacheCapacity) {
+    WebCache::setCapacities(pending_cache_min_dead_capacity_,
+                            pending_cache_max_dead_capacity_,
+                            pending_cache_capacity_);
+  }
+
   // chrome-native: is a scheme used for placeholder navigations that allow
   // UIs to be drawn with platform native widgets instead of HTML.  These pages
   // should not be accessible, and should also be treated as empty documents
@@ -352,6 +364,10 @@
       native_scheme);
 }
 
+void ChromeRenderProcessObserver::OnRenderProcessShutdown() {
+  webkit_initialized_ = false;
+}
+
 void ChromeRenderProcessObserver::OnSetIsIncognitoProcess(
     bool is_incognito_process) {
   is_incognito_process_ = is_incognito_process;
@@ -370,12 +386,19 @@
 void ChromeRenderProcessObserver::OnSetCacheCapacities(size_t min_dead_capacity,
                                                        size_t max_dead_capacity,
                                                        size_t capacity) {
+  if (!webkit_initialized_) {
+    pending_cache_min_dead_capacity_ = min_dead_capacity;
+    pending_cache_max_dead_capacity_ = max_dead_capacity;
+    pending_cache_capacity_ = capacity;
+    return;
+  }
+
   WebCache::setCapacities(
       min_dead_capacity, max_dead_capacity, capacity);
 }
 
 void ChromeRenderProcessObserver::OnClearCache(bool on_navigation) {
-  if (on_navigation) {
+  if (on_navigation || !webkit_initialized_) {
     clear_cache_pending_ = true;
   } else {
     WebCache::clear();
@@ -384,7 +407,8 @@
 
 void ChromeRenderProcessObserver::OnGetCacheResourceStats() {
   WebCache::ResourceTypeStats stats;
-  WebCache::getResourceTypeStats(&stats);
+  if (webkit_initialized_)
+    WebCache::getResourceTypeStats(&stats);
   RenderThread::Get()->Send(new ChromeViewHostMsg_ResourceTypeStats(stats));
 }
 
@@ -404,7 +428,8 @@
 }
 
 void ChromeRenderProcessObserver::OnPurgeMemory() {
-  RenderThread::Get()->EnsureWebKitInitialized();
+  if (!webkit_initialized_)
+    return;
 
   // Clear the object cache (as much as possible; some live objects cannot be
   // freed).
@@ -431,7 +456,7 @@
 }
 
 void ChromeRenderProcessObserver::ExecutePendingClearCache() {
-  if (clear_cache_pending_) {
+  if (clear_cache_pending_ && webkit_initialized_) {
     clear_cache_pending_ = false;
     WebCache::clear();
   }
diff --git a/chrome/renderer/chrome_render_process_observer.h b/chrome/renderer/chrome_render_process_observer.h
index 1ba175b..e970802 100644
--- a/chrome/renderer/chrome_render_process_observer.h
+++ b/chrome/renderer/chrome_render_process_observer.h
@@ -52,6 +52,7 @@
   // RenderProcessObserver implementation.
   virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
   virtual void WebKitInitialized() OVERRIDE;
+  virtual void OnRenderProcessShutdown() OVERRIDE;
 
   void OnSetIsIncognitoProcess(bool is_incognito_process);
   void OnSetExtensionActivityLogEnabled(bool extension_activity_log_enabled);
@@ -79,6 +80,11 @@
   bool clear_cache_pending_;
   RendererContentSettingRules content_setting_rules_;
 
+  bool webkit_initialized_;
+  size_t pending_cache_min_dead_capacity_;
+  size_t pending_cache_max_dead_capacity_;
+  size_t pending_cache_capacity_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeRenderProcessObserver);
 };
 
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc
index c6a45fd..096fa50 100644
--- a/chrome/renderer/chrome_render_view_observer.cc
+++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -261,6 +261,8 @@
 #if defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(ChromeViewMsg_UpdateTopControlsState,
                         OnUpdateTopControlsState)
+    IPC_MESSAGE_HANDLER(ChromeViewMsg_RetrieveWebappInformation,
+                        OnRetrieveWebappInformation)
 #endif
     IPC_MESSAGE_HANDLER(ChromeViewMsg_SetWindowFeatures, OnSetWindowFeatures)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -337,6 +339,47 @@
     bool animate) {
   render_view()->UpdateTopControlsState(constraints, current, animate);
 }
+
+void ChromeRenderViewObserver::OnRetrieveWebappInformation(
+    const GURL& expected_url) {
+  bool webapp_capable = false;
+
+  WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
+  WebDocument document =
+      main_frame ? main_frame->document() : WebDocument();
+
+  WebElement head = document.isNull() ? WebElement() : document.head();
+  GURL document_url = document.isNull() ? GURL() : GURL(document.url());
+
+  // Make sure we're checking the right page.
+  bool success = document_url == expected_url;
+
+  // Search the DOM for the webapp <meta> tags.
+  if (!head.isNull()) {
+    WebNodeList children = head.childNodes();
+    for (unsigned i = 0; i < children.length(); ++i) {
+      WebNode child = children.item(i);
+      if (!child.isElementNode())
+        continue;
+      WebElement elem = child.to<WebElement>();
+
+      if (elem.hasTagName("meta") && elem.hasAttribute("name")) {
+        std::string name = elem.getAttribute("name").utf8();
+        WebString content = elem.getAttribute("content");
+        if (content == "yes" && (name == "mobile-web-app-capable"
+            || name == "apple-mobile-web-app-capable")) {
+          webapp_capable = true;
+        }
+      }
+    }
+  } else {
+    success = false;
+  }
+
+  Send(new ChromeViewHostMsg_DidRetrieveWebappInformation(routing_id(),
+                                                          success,
+                                                          webapp_capable));
+}
 #endif
 
 void ChromeRenderViewObserver::OnSetWindowFeatures(
@@ -380,6 +423,7 @@
     int thumbnail_min_area_pixels, gfx::Size thumbnail_max_size_pixels) {
   WebNode context_node = render_view()->GetContextMenuNode();
   SkBitmap thumbnail;
+  CHECK(!context_node.isNull());
   if (context_node.isElementNode()) {
     WebKit::WebImage image = context_node.to<WebElement>().imageContents();
     thumbnail = Downscale(image,
diff --git a/chrome/renderer/chrome_render_view_observer.h b/chrome/renderer/chrome_render_view_observer.h
index 82f36c0..67dd03e 100644
--- a/chrome/renderer/chrome_render_view_observer.h
+++ b/chrome/renderer/chrome_render_view_observer.h
@@ -141,6 +141,7 @@
   void OnUpdateTopControlsState(content::TopControlsState constraints,
                                 content::TopControlsState current,
                                 bool animate);
+  void OnRetrieveWebappInformation(const GURL& expected_url);
 #endif
   void OnSetWindowFeatures(const WebKit::WebWindowFeatures& window_features);
 
diff --git a/chrome/renderer/extensions/api_activity_logger.cc b/chrome/renderer/extensions/api_activity_logger.cc
index a6b95af..f42c1df 100644
--- a/chrome/renderer/extensions/api_activity_logger.cc
+++ b/chrome/renderer/extensions/api_activity_logger.cc
@@ -20,8 +20,6 @@
     : ChromeV8Extension(dispatcher, context) {
   RouteFunction("LogEvent", base::Bind(&APIActivityLogger::LogEvent));
   RouteFunction("LogAPICall", base::Bind(&APIActivityLogger::LogAPICall));
-  RouteFunction("LogBlockedCall",
-                base::Bind(&APIActivityLogger::LogBlockedCallWrapper));
 }
 
 // static
@@ -78,35 +76,4 @@
   }
 }
 
-// static
-void APIActivityLogger::LogBlockedCallWrapper(
-    const v8::FunctionCallbackInfo<v8::Value>& args) {
-  DCHECK_EQ(args.Length(), 3);
-  DCHECK(args[0]->IsString());
-  DCHECK(args[1]->IsString());
-  DCHECK(args[2]->IsNumber());
-  int result;
-  scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
-  converter->FromV8Value(args[2],
-                         v8::Context::GetCurrent())->GetAsInteger(&result);
-  LogBlockedCall(*v8::String::AsciiValue(args[0]),
-                 *v8::String::AsciiValue(args[1]),
-                 static_cast<Feature::AvailabilityResult>(result));
-}
-
-// static
-void APIActivityLogger::LogBlockedCall(const std::string& extension_id,
-                                       const std::string& function_name,
-                                       Feature::AvailabilityResult result) {
-  // We don't really want to bother logging if it isn't permission related.
-  if (result == Feature::INVALID_MIN_MANIFEST_VERSION ||
-      result == Feature::INVALID_MAX_MANIFEST_VERSION ||
-      result == Feature::UNSUPPORTED_CHANNEL)
-    return;
-  content::RenderThread::Get()->Send(
-      new ExtensionHostMsg_AddBlockedCallToActivityLog(extension_id,
-                                                       function_name));
-}
-
-
 }  // namespace extensions
diff --git a/chrome/renderer/extensions/api_activity_logger.h b/chrome/renderer/extensions/api_activity_logger.h
index 544ce5f..bfb9787 100644
--- a/chrome/renderer/extensions/api_activity_logger.h
+++ b/chrome/renderer/extensions/api_activity_logger.h
@@ -6,9 +6,9 @@
 #define CHROME_RENDERER_EXTENSIONS_API_ACTIVITY_LOGGER_H_
 
 #include <string>
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/renderer/extensions/chrome_v8_extension.h"
 #include "chrome/renderer/extensions/dispatcher.h"
+#include "extensions/common/features/feature.h"
 #include "v8/include/v8.h"
 
 namespace extensions {
@@ -20,11 +20,6 @@
  public:
   APIActivityLogger(Dispatcher* dispatcher, ChromeV8Context* context);
 
-  // This is to use to log blocked API calls.
-  static void LogBlockedCall(const std::string& extension_id,
-                             const std::string& function_name,
-                             Feature::AvailabilityResult result);
-
  private:
    // Used to distinguish API calls & events from each other in LogInternal.
    enum CallType {
@@ -46,13 +41,6 @@
    //    arg3 - any extra logging info as a string (optional)
    static void LogEvent(const v8::FunctionCallbackInfo<v8::Value>& args);
 
-   // This is invoked in binding.js with JavaScript arguments.
-   //    arg0 - extension ID as string
-   //    arg1 - Function name as a string
-   //    arg2 - Reason for the failure
-   static void LogBlockedCallWrapper(
-       const v8::FunctionCallbackInfo<v8::Value>& args);
-
    // LogAPICall and LogEvent are really the same underneath except for
    // how they are ultimately dispatched to the log.
    static void LogInternal(const CallType call_type,
diff --git a/chrome/renderer/extensions/api_definitions_natives.cc b/chrome/renderer/extensions/api_definitions_natives.cc
index 6bd6af0..316daaa 100644
--- a/chrome/renderer/extensions/api_definitions_natives.cc
+++ b/chrome/renderer/extensions/api_definitions_natives.cc
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-#include "chrome/common/extensions/features/feature.h"
+#include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
 
 namespace extensions {
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc
index 268727a..41238e7 100644
--- a/chrome/renderer/extensions/app_bindings.cc
+++ b/chrome/renderer/extensions/app_bindings.cc
@@ -12,13 +12,13 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "chrome/common/extensions/extension_set.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/renderer/extensions/chrome_v8_context.h"
 #include "chrome/renderer/extensions/console.h"
 #include "chrome/renderer/extensions/dispatcher.h"
 #include "chrome/renderer/extensions/extension_helper.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/v8_value_converter.h"
+#include "extensions/common/manifest.h"
 #include "grit/renderer_resources.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
diff --git a/chrome/renderer/extensions/chrome_v8_context.cc b/chrome/renderer/extensions/chrome_v8_context.cc
index e8e18ec..cdde47f 100644
--- a/chrome/renderer/extensions/chrome_v8_context.cc
+++ b/chrome/renderer/extensions/chrome_v8_context.cc
@@ -97,6 +97,7 @@
     const std::string& api_name) {
   return ExtensionAPI::GetSharedInstance()->IsAnyFeatureAvailableToContext(
       api_name,
+      extension_.get(),
       context_type_,
       UserScriptSlave::GetDataSourceURLForFrame(web_frame_));
 }
diff --git a/chrome/renderer/extensions/chrome_v8_context.h b/chrome/renderer/extensions/chrome_v8_context.h
index b8f70cb..930807b 100644
--- a/chrome/renderer/extensions/chrome_v8_context.h
+++ b/chrome/renderer/extensions/chrome_v8_context.h
@@ -9,11 +9,11 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/renderer/extensions/module_system.h"
 #include "chrome/renderer/extensions/request_sender.h"
 #include "chrome/renderer/extensions/safe_builtins.h"
 #include "chrome/renderer/extensions/scoped_persistent.h"
+#include "extensions/common/features/feature.h"
 #include "v8/include/v8.h"
 
 namespace WebKit {
diff --git a/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc b/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
index dab72d9..f0aceb1 100644
--- a/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
+++ b/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
@@ -4,9 +4,9 @@
 
 #include "base/message_loop/message_loop.h"
 #include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/renderer/extensions/chrome_v8_context.h"
 #include "chrome/renderer/extensions/chrome_v8_context_set.h"
+#include "extensions/common/features/feature.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "v8/include/v8.h"
diff --git a/chrome/renderer/extensions/content_watcher.cc b/chrome/renderer/extensions/content_watcher.cc
index 1cb3924..f4e5fff 100644
--- a/chrome/renderer/extensions/content_watcher.cc
+++ b/chrome/renderer/extensions/content_watcher.cc
@@ -10,6 +10,7 @@
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/render_view_visitor.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
@@ -129,44 +130,14 @@
 std::vector<base::StringPiece> ContentWatcher::FindMatchingSelectors(
     WebKit::WebFrame* frame) const {
   std::vector<base::StringPiece> result;
-  v8::HandleScope scope;
-
-  // Get the indices within |css_selectors_| that match elements in
-  // |frame|, as a JS Array.
-  v8::Local<v8::Value> selector_indices;
-  if (ModuleSystem* module_system = GetModuleSystem(frame)) {
-    v8::Context::Scope context_scope(frame->mainWorldScriptContext());
-    v8::Local<v8::Array> js_css_selectors =
-        v8::Array::New(css_selectors_.size());
-    for (size_t i = 0; i < css_selectors_.size(); ++i) {
-      js_css_selectors->Set(i, v8::String::New(css_selectors_[i].data(),
-                                               css_selectors_[i].size()));
-    }
-    std::vector<v8::Handle<v8::Value> > find_selectors_args;
-    find_selectors_args.push_back(js_css_selectors);
-    selector_indices = module_system->CallModuleMethod("contentWatcher",
-                                                       "FindMatchingSelectors",
-                                                       &find_selectors_args);
-  }
-  if (selector_indices.IsEmpty() || !selector_indices->IsArray())
-    return result;
-
-  // Iterate over the array, and extract the indices, laboriously
-  // converting them back to integers.
-  v8::Local<v8::Array> index_array = selector_indices.As<v8::Array>();
-  const size_t length = index_array->Length();
-  result.reserve(length);
-  for (size_t i = 0; i < length; ++i) {
-    v8::Local<v8::Value> index_value = index_array->Get(i);
-    if (!index_value->IsNumber())
-      continue;
-    double index = index_value->NumberValue();
-    // Make sure the index is within bounds.
-    if (index < 0 || css_selectors_.size() <= index)
-      continue;
-    // Push a StringPiece referring to the CSS selector onto the result.
-    result.push_back(
-        base::StringPiece(css_selectors_[static_cast<size_t>(index)]));
+  WebKit::WebDocument document = frame->document();
+  for (size_t i = 0; i < css_selectors_.size(); ++i) {
+    WebKit::WebExceptionCode exception = 0;
+    if (!document.querySelector(WebKit::WebString::fromUTF8(css_selectors_[i]),
+                                exception).isNull())
+      result.push_back(css_selectors_[i]);
+    DCHECK_EQ(0, exception)
+        << "We should already have checked that the selectors are valid.";
   }
   return result;
 }
diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc
index b569c0b..f3df304 100644
--- a/chrome/renderer/extensions/dispatcher.cc
+++ b/chrome/renderer/extensions/dispatcher.cc
@@ -18,14 +18,12 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/api/extension_api.h"
+#include "chrome/common/extensions/api/runtime.h"
 #include "chrome/common/extensions/background_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/common/extensions/features/feature_channel.h"
-#include "chrome/common/extensions/manifest.h"
 #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"
@@ -43,6 +41,7 @@
 #include "chrome/renderer/extensions/chrome_v8_extension.h"
 #include "chrome/renderer/extensions/content_watcher.h"
 #include "chrome/renderer/extensions/context_menus_custom_bindings.h"
+#include "chrome/renderer/extensions/document_custom_bindings.h"
 #include "chrome/renderer/extensions/dom_activity_logger.h"
 #include "chrome/renderer/extensions/event_bindings.h"
 #include "chrome/renderer/extensions/extension_custom_bindings.h"
@@ -78,7 +77,10 @@
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/v8_value_converter.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
 #include "extensions/common/view_type.h"
 #include "grit/common_resources.h"
 #include "grit/renderer_resources.h"
@@ -109,14 +111,14 @@
 
 namespace extensions {
 
+namespace runtime = api::runtime;
+
 namespace {
 
 static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
 static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
 static const char kEventModule[] = "event_bindings";
 static const char kEventDispatchFunction[] = "dispatchEvent";
-static const char kOnSuspendEvent[] = "runtime.onSuspend";
-static const char kOnSuspendCanceledEvent[] = "runtime.onSuspendCanceled";
 
 // Returns the global value for "chrome" from |context|. If one doesn't exist
 // creates a new object for it.
@@ -513,8 +515,7 @@
 }
 
 void Dispatcher::OnSetChannel(int channel) {
-  extensions::SetCurrentChannel(
-      static_cast<chrome::VersionInfo::Channel>(channel));
+  SetCurrentChannel(static_cast<chrome::VersionInfo::Channel>(channel));
 }
 
 void Dispatcher::OnMessageInvoke(const std::string& extension_id,
@@ -664,7 +665,7 @@
            it != extensions_.end(); ++it) {
         ExternallyConnectableInfo* info =
             static_cast<ExternallyConnectableInfo*>((*it)->GetManifestData(
-                extension_manifest_keys::kExternallyConnectable));
+                manifest_keys::kExternallyConnectable));
         if (info && info->matches.MatchesURL(context->GetURL())) {
           runtime_is_available = true;
           break;
@@ -688,6 +689,9 @@
         const std::string& api_name = *it;
         Feature* feature = feature_provider->GetFeature(api_name);
         DCHECK(feature);
+
+        // Internal APIs are included via require(api_name) from internal code
+        // rather than chrome[api_name].
         if (feature->IsInternal())
           continue;
 
@@ -704,28 +708,14 @@
         if (parent_feature_available)
           continue;
 
-        if (!context->IsAnyFeatureAvailableToContext(api_name)) {
-          DeregisterBinding(api_name, context);
-          continue;
-        }
-
-        RegisterBinding(api_name, context);
+        if (context->IsAnyFeatureAvailableToContext(api_name))
+          RegisterBinding(api_name, context);
       }
       break;
     }
   }
 }
 
-void Dispatcher::DeregisterBinding(const std::string& api_name,
-                                   ChromeV8Context* context) {
-  std::string bind_name;
-  v8::Handle<v8::Object> bind_object =
-      GetOrCreateBindObjectIfAvailable(api_name, &bind_name, context);
-  v8::Handle<v8::String> v8_bind_name = v8::String::New(bind_name.c_str());
-  if (!bind_object.IsEmpty() && bind_object->HasRealNamedProperty(v8_bind_name))
-    bind_object->Delete(v8_bind_name);
-}
-
 v8::Handle<v8::Object> Dispatcher::GetOrCreateBindObjectIfAvailable(
     const std::string& api_name,
     std::string* bind_name,
@@ -865,6 +855,9 @@
   module_system->RegisterNativeHandler("context_menus",
       scoped_ptr<NativeHandler>(
           new ContextMenusCustomBindings(this, context)));
+  module_system->RegisterNativeHandler("document_natives",
+      scoped_ptr<NativeHandler>(
+          new DocumentCustomBindings(this, context)));
   module_system->RegisterNativeHandler("extension",
       scoped_ptr<NativeHandler>(
           new ExtensionCustomBindings(this, context)));
@@ -1133,7 +1126,9 @@
         std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(),
                                                          id_hash.length());
         if (hexencoded_id_hash == "8C3741E3AF0B93B6E8E0DDD499BB0B74839EA578" ||
-            hexencoded_id_hash == "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB")
+            hexencoded_id_hash == "E703483CEF33DEC18B4B6DD84B5C776FB9182BDB" ||
+            hexencoded_id_hash == "1A26E32DE447A17CBE5E9750CDBA78F58539B39C" ||
+            hexencoded_id_hash == "59048028102D7B4C681DBC7BC6CD980C3DC66DA3")
           includeExperimental = true;
       }
       if (includeExperimental)
@@ -1300,11 +1295,11 @@
 }
 
 void Dispatcher::EnableCustomElementWhiteList() {
-  WebKit::WebRuntimeFeatures::enableCustomElements(true);
-  WebKit::WebCustomElement::allowTagName("webview");
+  WebKit::WebRuntimeFeatures::enableEmbedderCustomElements(true);
+  WebKit::WebCustomElement::addEmbedderCustomElementName("webview");
   // TODO(fsamuel): Add <adview> to the whitelist once it has been converted
   // into a custom element.
-  WebKit::WebCustomElement::allowTagName("browser-plugin");
+  WebKit::WebCustomElement::addEmbedderCustomElementName("browser-plugin");
 }
 
 void Dispatcher::AddOrRemoveBindings(const std::string& extension_id) {
@@ -1418,23 +1413,22 @@
   // the browser know when we are starting and stopping the event dispatch, so
   // that it still considers the extension idle despite any activity the suspend
   // event creates.
-  DispatchEvent(extension_id, kOnSuspendEvent);
+  DispatchEvent(extension_id, runtime::OnSuspend::kEventName);
   RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id));
 }
 
 void Dispatcher::OnCancelSuspend(const std::string& extension_id) {
-  DispatchEvent(extension_id, kOnSuspendCanceledEvent);
+  DispatchEvent(extension_id, runtime::OnSuspendCanceled::kEventName);
 }
 
 // TODO(kalman): This is checking for the wrong thing, it should be checking if
 // the frame's security origin is unique. The extension sandbox directive is
 // checked for in chrome/common/extensions/csp_handler.cc.
 bool Dispatcher::IsSandboxedPage(const GURL& url) const {
-  if (url.SchemeIs(extensions::kExtensionScheme)) {
+  if (url.SchemeIs(kExtensionScheme)) {
     const Extension* extension = extensions_.GetByID(url.host());
     if (extension) {
-      return extensions::SandboxedPageInfo::IsSandboxedPage(extension,
-                                                            url.path());
+      return SandboxedPageInfo::IsSandboxedPage(extension, url.path());
     }
   }
   return false;
@@ -1512,9 +1506,6 @@
 
   Feature::Availability availability = context->GetAvailability(function_name);
   if (!availability.is_available()) {
-    APIActivityLogger::LogBlockedCall(context->extension()->id(),
-                                      function_name,
-                                      availability.result());
     v8::ThrowException(v8::Exception::Error(
         v8::String::New(availability.message().c_str())));
   }
diff --git a/chrome/renderer/extensions/dispatcher.h b/chrome/renderer/extensions/dispatcher.h
index b145eab..1800076 100644
--- a/chrome/renderer/extensions/dispatcher.h
+++ b/chrome/renderer/extensions/dispatcher.h
@@ -13,13 +13,13 @@
 #include "base/memory/shared_memory.h"
 #include "base/timer/timer.h"
 #include "chrome/common/extensions/extension_set.h"
-#include "chrome/common/extensions/features/feature.h"
 #include "chrome/renderer/extensions/chrome_v8_context.h"
 #include "chrome/renderer/extensions/chrome_v8_context_set.h"
 #include "chrome/renderer/extensions/v8_schema_registry.h"
 #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/features/feature.h"
 #include "v8/include/v8.h"
 
 class ChromeRenderViewTest;
@@ -212,7 +212,6 @@
   void AddOrRemoveBindingsForContext(ChromeV8Context* context);
   void RegisterBinding(const std::string& api_name,
                        ChromeV8Context* context);
-  void DeregisterBinding(const std::string& api_name, ChromeV8Context* context);
   v8::Handle<v8::Object> GetOrCreateBindObjectIfAvailable(
       const std::string& api_name,
       std::string* bind_name,
diff --git a/chrome/renderer/extensions/document_custom_bindings.cc b/chrome/renderer/extensions/document_custom_bindings.cc
new file mode 100644
index 0000000..36406c2
--- /dev/null
+++ b/chrome/renderer/extensions/document_custom_bindings.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/renderer/extensions/document_custom_bindings.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "content/public/renderer/render_view.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "v8/include/v8.h"
+
+namespace extensions {
+
+DocumentCustomBindings::DocumentCustomBindings(
+    Dispatcher* dispatcher, ChromeV8Context* context)
+    : ChromeV8Extension(dispatcher, context) {
+  RouteFunction("RegisterElement",
+      base::Bind(&DocumentCustomBindings::RegisterElement,
+                 base::Unretained(this)));
+}
+
+// Attach an event name to an object.
+void DocumentCustomBindings::RegisterElement(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  content::RenderView* render_view = GetRenderView();
+  if (!render_view) {
+    return;
+  }
+
+  WebKit::WebView* web_view = render_view->GetWebView();
+  if (!web_view) {
+    return;
+  }
+
+  if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsObject()) {
+    NOTREACHED();
+    return;
+  }
+
+  std::string element_name(*v8::String::AsciiValue(args[0]));
+  v8::Local<v8::Object> options = args[1]->ToObject();
+
+  WebKit::WebExceptionCode ec = 0;
+  WebKit::WebDocument document = web_view->mainFrame()->document();
+  v8::Handle<v8::Value> constructor =
+      document.registerEmbedderCustomElement(
+          WebKit::WebString::fromUTF8(element_name), options, ec);
+  args.GetReturnValue().Set(constructor);
+}
+
+}  // namespace extensions
diff --git a/chrome/renderer/extensions/document_custom_bindings.h b/chrome/renderer/extensions/document_custom_bindings.h
new file mode 100644
index 0000000..4a16015
--- /dev/null
+++ b/chrome/renderer/extensions/document_custom_bindings.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_RENDERER_EXTENSIONS_DOCUMENT_CUSTOM_BINDINGS_H_
+#define CHROME_RENDERER_EXTENSIONS_DOCUMENT_CUSTOM_BINDINGS_H_
+
+#include "chrome/renderer/extensions/chrome_v8_extension.h"
+
+namespace extensions {
+
+// Implements custom bindings for document-level operations.
+class DocumentCustomBindings : public ChromeV8Extension {
+ public:
+  DocumentCustomBindings(Dispatcher* dispatcher, ChromeV8Context* context);
+
+ private:
+  // Registers the provided element as a custom element in Blink.
+  void RegisterElement(const v8::FunctionCallbackInfo<v8::Value>& args);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_RENDERER_EXTENSIONS_DOCUMENT_CUSTOM_BINDINGS_H_
diff --git a/chrome/renderer/extensions/messaging_bindings.cc b/chrome/renderer/extensions/messaging_bindings.cc
index a4c0d99..fec12f7 100644
--- a/chrome/renderer/extensions/messaging_bindings.cc
+++ b/chrome/renderer/extensions/messaging_bindings.cc
@@ -85,6 +85,7 @@
         base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this)));
     RouteFunction("PostMessage",
         base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this)));
+    // TODO(fsamuel, kalman): Move BindToGC out of messaging natives.
     RouteFunction("BindToGC",
         base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this)));
   }
diff --git a/chrome/renderer/extensions/runtime_custom_bindings.cc b/chrome/renderer/extensions/runtime_custom_bindings.cc
index 4f364a3..45663f9 100644
--- a/chrome/renderer/extensions/runtime_custom_bindings.cc
+++ b/chrome/renderer/extensions/runtime_custom_bindings.cc
@@ -9,14 +9,14 @@
 #include "base/values.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
-#include "chrome/common/extensions/features/feature.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/renderer/extensions/api_activity_logger.h"
 #include "chrome/renderer/extensions/chrome_v8_context.h"
 #include "chrome/renderer/extensions/dispatcher.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/v8_value_converter.h"
+#include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
+#include "extensions/common/manifest.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
@@ -54,9 +54,9 @@
   CHECK(args[0]->IsString() && args[1]->IsString());
 
   ExtensionMsg_ExternalConnectionInfo info;
-  info.source_id = context()->extension() ? context()->extension()->id() : "";
+  info.source_id = context()->GetExtensionID();
   info.target_id = *v8::String::Utf8Value(args[0]->ToString());
-  info.source_url = renderview->GetWebView()->mainFrame()->document().url();
+  info.source_url = context()->GetURL();
   std::string channel_name = *v8::String::Utf8Value(args[1]->ToString());
   int port_id = -1;
   renderview->Send(new ExtensionHostMsg_OpenChannelToExtension(
@@ -73,12 +73,8 @@
               GetExtensionForRenderView(),
               context()->context_type(),
               context()->GetURL());
-  if (!availability.is_available()) {
-    APIActivityLogger::LogBlockedCall(context()->extension()->id(),
-                                      "nativeMessaging",
-                                      availability.result());
+  if (!availability.is_available())
     return;
-  }
 
   // Get the current RenderView so that we can send a routed IPC message from
   // the correct source.
diff --git a/chrome/renderer/mock_printer.cc b/chrome/renderer/mock_printer.cc
index 9c16728..fdcbd0e 100644
--- a/chrome/renderer/mock_printer.cc
+++ b/chrome/renderer/mock_printer.cc
@@ -40,7 +40,7 @@
   }
 }
 
-} // end
+}  // namespace
 
 MockPrinterPage::MockPrinterPage(const void* source_data,
                                  uint32 source_size,
@@ -226,11 +226,6 @@
   MockPrinterPage* page_data = new MockPrinterPage(metafile_data.memory(),
                                                    params.data_size,
                                                    image);
-  if (!page_data) {
-    printer_status_ = PRINTER_ERROR;
-    return;
-  }
-
   scoped_refptr<MockPrinterPage> page(page_data);
   pages_.push_back(page);
 #endif
diff --git a/chrome/renderer/one_click_signin_agent.cc b/chrome/renderer/one_click_signin_agent.cc
deleted file mode 100644
index b59c4aa..0000000
--- a/chrome/renderer/one_click_signin_agent.cc
+++ /dev/null
@@ -1,29 +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/renderer/one_click_signin_agent.h"
-
-#include "chrome/common/one_click_signin_messages.h"
-#include "content/public/common/password_form.h"
-#include "content/public/renderer/document_state.h"
-#include "content/public/renderer/render_view.h"
-#include "third_party/WebKit/public/web/WebFormElement.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-
-OneClickSigninAgent::OneClickSigninAgent(
-    content::RenderView* render_view)
-    : content::RenderViewObserver(render_view) {
-}
-
-OneClickSigninAgent::~OneClickSigninAgent() {}
-
-void OneClickSigninAgent::WillSubmitForm(WebKit::WebFrame* frame,
-                                         const WebKit::WebFormElement& form) {
-  content::DocumentState* document_state =
-      content::DocumentState::FromDataSource(frame->provisionalDataSource());
-  if (document_state->password_form_data()) {
-    Send(new OneClickSigninHostMsg_FormSubmitted(routing_id(),
-         *(document_state->password_form_data())));
-  }
-}
diff --git a/chrome/renderer/one_click_signin_agent.h b/chrome/renderer/one_click_signin_agent.h
deleted file mode 100644
index 17cd0b7..0000000
--- a/chrome/renderer/one_click_signin_agent.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 CHROME_RENDERER_ONE_CLICK_SIGNIN_AGENT_H_
-#define CHROME_RENDERER_ONE_CLICK_SIGNIN_AGENT_H_
-
-#include "content/public/renderer/render_view_observer.h"
-
-// OneClickSigninAgent deals with oneclick signin related communications between
-// the renderer and the browser.  There is one OneClickSigninAgent per
-// RenderView.
-class OneClickSigninAgent : public content::RenderViewObserver {
-  public:
-    explicit OneClickSigninAgent(content::RenderView* render_view);
-    virtual ~OneClickSigninAgent();
-
-  private:
-    virtual void WillSubmitForm(WebKit::WebFrame* frame,
-                                const WebKit::WebFormElement& form) OVERRIDE;
-
-  DISALLOW_COPY_AND_ASSIGN(OneClickSigninAgent);
-};
-
-#endif  // CHROME_RENDERER_ONE_CLICK_SIGNIN_AGENT_H_
diff --git a/chrome/renderer/pepper/OWNERS b/chrome/renderer/pepper/OWNERS
index a114912..c4871e2 100644
--- a/chrome/renderer/pepper/OWNERS
+++ b/chrome/renderer/pepper/OWNERS
@@ -1,3 +1,4 @@
+bbudge@chromium.org
 brettw@chromium.org
 dmichael@chromium.org
 raymes@chromium.org
diff --git a/chrome/renderer/pepper/ppb_nacl_private_impl.cc b/chrome/renderer/pepper/ppb_nacl_private_impl.cc
index 7ad7383..00a3b2c 100644
--- a/chrome/renderer/pepper/ppb_nacl_private_impl.cc
+++ b/chrome/renderer/pepper/ppb_nacl_private_impl.cc
@@ -85,6 +85,7 @@
                            PP_Bool enable_ppapi_dev,
                            PP_Bool enable_dyncode_syscalls,
                            PP_Bool enable_exception_handling,
+                           PP_Bool enable_crash_throttling,
                            void* imc_handle,
                            struct PP_Var* error_message) {
   nacl::FileDescriptor result_socket;
@@ -122,7 +123,8 @@
                                  perm_bits,
                                  PP_ToBool(uses_irt),
                                  PP_ToBool(enable_dyncode_syscalls),
-                                 PP_ToBool(enable_exception_handling)),
+                                 PP_ToBool(enable_exception_handling),
+                                 PP_ToBool(enable_crash_throttling)),
           &launch_result,
           &error_message_string))) {
     return PP_EXTERNAL_PLUGIN_FAILED;
@@ -304,7 +306,7 @@
 
 PP_Bool IsPnaclEnabled() {
   return PP_FromBool(
-      CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePnacl));
+      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisablePnacl));
 }
 
 PP_ExternalPluginResult ReportNaClError(PP_Instance instance,
diff --git a/chrome/renderer/plugins/webview_plugin.cc b/chrome/renderer/plugins/webview_plugin.cc
index eb1fea7..2853a31 100644
--- a/chrome/renderer/plugins/webview_plugin.cc
+++ b/chrome/renderer/plugins/webview_plugin.cc
@@ -6,6 +6,7 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "content/public/renderer/web_preferences.h"
 #include "skia/ext/platform_canvas.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
@@ -19,7 +20,6 @@
 #include "third_party/WebKit/public/web/WebPluginContainer.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "webkit/common/webpreferences.h"
-#include "webkit/renderer/webpreferences_renderer.h"
 
 using WebKit::WebCanvas;
 using WebKit::WebCursorInfo;
@@ -50,14 +50,13 @@
 }
 
 // static
-WebViewPlugin* WebViewPlugin::Create(
-    WebViewPlugin::Delegate* delegate,
-    const WebPreferences& preferences,
-    const std::string& html_data,
-    const GURL& url) {
+WebViewPlugin* WebViewPlugin::Create(WebViewPlugin::Delegate* delegate,
+                                     const WebPreferences& preferences,
+                                     const std::string& html_data,
+                                     const GURL& url) {
   WebViewPlugin* plugin = new WebViewPlugin(delegate);
   WebView* web_view = plugin->web_view();
-  webkit_glue::ApplyWebPreferences(preferences, web_view);
+  content::ApplyWebPreferences(preferences, web_view);
   web_view->mainFrame()->loadHTMLString(html_data, url);
   return plugin;
 }
diff --git a/chrome/renderer/printing/print_web_view_helper.cc b/chrome/renderer/printing/print_web_view_helper.cc
index 5d68beb..d302341 100644
--- a/chrome/renderer/printing/print_web_view_helper.cc
+++ b/chrome/renderer/printing/print_web_view_helper.cc
@@ -22,6 +22,7 @@
 #include "chrome/renderer/prerender/prerender_helper.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/render_view.h"
+#include "content/public/renderer/web_preferences.h"
 #include "grit/browser_resources.h"
 #include "grit/generated_resources.h"
 #include "printing/metafile.h"
@@ -46,7 +47,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "webkit/common/webpreferences.h"
-#include "webkit/renderer/webpreferences_renderer.h"
 
 namespace printing {
 
@@ -668,7 +668,7 @@
 
   WebKit::WebView* web_view = WebKit::WebView::create(this);
   owns_web_view_ = true;
-  webkit_glue::ApplyWebPreferences(prefs, web_view);
+  content::ApplyWebPreferences(prefs, web_view);
   web_view->initializeMainFrame(this);
   frame_.Reset(web_view->mainFrame());
   node_to_print_.reset();
@@ -1163,19 +1163,13 @@
 
 void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only) {
   DCHECK(is_preview_enabled_);
-  WebKit::WebFrame* frame;
-  if (GetPrintFrame(&frame)) {
-    print_preview_context_.InitWithFrame(frame);
-    RequestPrintPreview(selection_only ?
-                        PRINT_PREVIEW_USER_INITIATED_SELECTION :
-                        PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME);
-  } else {
-    // This should not happen. Let's add a CHECK here to see how often this
-    // gets hit.
-    // TODO(thestig) Remove this later when we have sufficient usage of this
-    // code on the M19 stable channel.
-    CHECK(false);
-  }
+  WebKit::WebFrame* frame = NULL;
+  GetPrintFrame(&frame);
+  DCHECK(frame);
+  print_preview_context_.InitWithFrame(frame);
+  RequestPrintPreview(selection_only ?
+                      PRINT_PREVIEW_USER_INITIATED_SELECTION :
+                      PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME);
 }
 
 bool PrintWebViewHelper::IsPrintingEnabled() {
@@ -1311,7 +1305,7 @@
   const PrintMsg_PrintPages_Params& params = *print_pages_params_;
   const PrintMsg_Print_Params& print_params = params.params;
 
-#if !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
   // TODO(vitalybuka): should be page_count or valid pages from params.pages.
   // See http://crbug.com/161576
   Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(),
diff --git a/chrome/renderer/printing/print_web_view_helper.h b/chrome/renderer/printing/print_web_view_helper.h
index 989a47f..d10db97 100644
--- a/chrome/renderer/printing/print_web_view_helper.h
+++ b/chrome/renderer/printing/print_web_view_helper.h
@@ -231,7 +231,7 @@
   void FinishFramePrinting();
 
   // Prints the page listed in |params|.
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_ANDROID)
   void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
                          const gfx::Size& canvas_size,
                          WebKit::WebFrame* frame,
diff --git a/chrome/renderer/printing/print_web_view_helper_android.cc b/chrome/renderer/printing/print_web_view_helper_android.cc
new file mode 100644
index 0000000..95da0ce
--- /dev/null
+++ b/chrome/renderer/printing/print_web_view_helper_android.cc
@@ -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.
+
+// All the necessary logic already lives in print_web_view_helper_linux.cc.
+// We need a separate file for Android due to build/filename_rules.gypi rules.
+#include "chrome/renderer/printing/print_web_view_helper_linux.cc"
diff --git a/chrome/renderer/printing/print_web_view_helper_linux.cc b/chrome/renderer/printing/print_web_view_helper_linux.cc
index 3bdf60c..312acd2 100644
--- a/chrome/renderer/printing/print_web_view_helper_linux.cc
+++ b/chrome/renderer/printing/print_web_view_helper_linux.cc
@@ -4,10 +4,8 @@
 
 #include "chrome/renderer/printing/print_web_view_helper.h"
 
-#include "base/file_descriptor_posix.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
 #include "chrome/common/print_messages.h"
 #include "content/public/renderer/render_thread.h"
 #include "printing/metafile.h"
@@ -18,9 +16,11 @@
 #include "skia/ext/vector_canvas.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 
-#if !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 #include "base/process/process_handle.h"
-#endif  // !defined(OS_CHROMEOS)
+#else
+#include "base/file_descriptor_posix.h"
+#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 
 namespace printing {
 
@@ -101,12 +101,14 @@
   uint32 buf_size = metafile.GetDataSize();
   DCHECK_GT(buf_size, 0u);
 
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
   int sequence_number = -1;
   base::FileDescriptor fd;
 
   // Ask the browser to open a file for us.
-  Send(new PrintHostMsg_AllocateTempFileForPrinting(&fd, &sequence_number));
+  Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(),
+                                                    &fd,
+                                                    &sequence_number));
   if (!metafile.SaveToFD(fd))
     return false;
 
diff --git a/chrome/renderer/resources/extensions/ad_view.js b/chrome/renderer/resources/extensions/ad_view.js
index f6db9dd..da7792c 100644
--- a/chrome/renderer/resources/extensions/ad_view.js
+++ b/chrome/renderer/resources/extensions/ad_view.js
@@ -65,13 +65,6 @@
  // Empty for now.
 ];
 
-/**
- * List of events to blindly forward from the browser plugin to the <adview>.
- */
-var AD_VIEW_EVENTS = {
-  'sizechanged': ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'],
-};
-
 var createEvent = function(name) {
   var eventOpts = {supportsListeners: true, supportsFilters: true};
   return new eventBindings.Event(name, undefined, eventOpts);
@@ -468,10 +461,6 @@
   };
   this.browserPluginNode_.addEventListener('-internal-instanceid-allocated',
                                            onInstanceIdAllocated);
-
-  for (var eventName in AD_VIEW_EVENTS) {
-    this.setupEvent_(eventName, AD_VIEW_EVENTS[eventName]);
-  }
 }
 
 /**
@@ -493,22 +482,6 @@
 };
 
 /**
- * @private
- */
-AdView.prototype.setupEvent_ = function(eventname, attribs) {
-  var adviewNode = this.adviewNode_;
-  var internalname = '-internal-' + eventname;
-  this.browserPluginNode_.addEventListener(internalname, function(e) {
-    var evt = new Event(eventname, { bubbles: true });
-    var detail = e.detail ? JSON.parse(e.detail) : {};
-    $Array.forEach(attribs, function(attribName) {
-      evt[attribName] = detail[attribName];
-    });
-    adviewNode.dispatchEvent(evt);
-  });
-}
-
-/**
  * @public
  */
 AdView.prototype.dispatchEvent = function(eventname, detail) {
diff --git a/chrome/renderer/resources/extensions/binding.js b/chrome/renderer/resources/extensions/binding.js
index 820d002..4bb9b99 100644
--- a/chrome/renderer/resources/extensions/binding.js
+++ b/chrome/renderer/resources/extensions/binding.js
@@ -423,9 +423,6 @@
     if (!availability.is_available && $Object.keys(mod).length == 0) {
       console.error('chrome.' + schema.namespace + ' is not available: ' +
                         availability.message);
-      logActivity.LogBlockedCall(extensionId,
-                                 schema.namespace,
-                                 availability.result);
       return;
     }
 
diff --git a/chrome/renderer/resources/extensions/content_watcher.js b/chrome/renderer/resources/extensions/content_watcher.js
index 9c118ed..e343177 100644
--- a/chrome/renderer/resources/extensions/content_watcher.js
+++ b/chrome/renderer/resources/extensions/content_watcher.js
@@ -4,21 +4,6 @@
 
 var contentWatcherNative = requireNative("contentWatcherNative");
 
-// Returns the indices in |cssSelectors| that match any element on the page.
-exports.FindMatchingSelectors = function(cssSelectors) {
-  var result = []
-  $Array.forEach(cssSelectors, function(selector, index) {
-    try {
-      if (document.querySelector(selector) != null)
-        $Array.push(result, index);
-    } catch (exception) {
-      throw new Error("query Selector failed on '" + selector + "': " +
-                      exception.stack);
-    }
-  });
-  return result;
-};
-
 // Watches the page for all changes and calls FrameMutated (a C++ callback) in
 // response.
 var mutation_observer = new MutationObserver(contentWatcherNative.FrameMutated);
diff --git a/chrome/renderer/resources/extensions/last_error.js b/chrome/renderer/resources/extensions/last_error.js
index f368964..4445f02 100644
--- a/chrome/renderer/resources/extensions/last_error.js
+++ b/chrome/renderer/resources/extensions/last_error.js
@@ -27,8 +27,6 @@
     throw new Error('No chrome object to set error: ' + errorMessage);
   clear(targetChrome);  // in case somebody has set a sneaky getter/setter
 
-  console.error(errorMessage);
-
   var errorObject = { message: message };
   if (GetAvailability('extension.lastError').is_available)
     targetChrome.extension.lastError = errorObject;
diff --git a/chrome/renderer/resources/extensions/test_custom_bindings.js b/chrome/renderer/resources/extensions/test_custom_bindings.js
index fe330d3..cc2681e 100644
--- a/chrome/renderer/resources/extensions/test_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/test_custom_bindings.js
@@ -230,7 +230,7 @@
 
   apiFunctions.setHandleRequest('assertThrows',
                                 function(fn, self, args, message) {
-    assertTrue(typeof fn == 'function');
+    chromeTest.assertTrue(typeof fn == 'function');
     try {
       fn.apply(self, args);
       chromeTest.fail('Did not throw error: ' + fn);
diff --git a/chrome/renderer/resources/extensions/web_view.js b/chrome/renderer/resources/extensions/web_view.js
index 3cdf959..fbd0684 100644
--- a/chrome/renderer/resources/extensions/web_view.js
+++ b/chrome/renderer/resources/extensions/web_view.js
@@ -7,17 +7,26 @@
 // The actual tag is implemented via the browser plugin. The internals of this
 // are hidden via Shadow DOM.
 
-var addTagWatcher = require('tagWatcher').addTagWatcher;
+'use strict';
+
 var eventBindings = require('event_bindings');
+var DocumentNatives = requireNative('document_natives');
+var messagingNatives = requireNative('messaging_natives');
+var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
+var webRequestSchema =
+    requireNative('schema_registry').GetSchema('webRequest');
+
+// This secret enables hiding <webview> private members from the outside scope.
+// Outside of this file, |secret| is inaccessible. The only way to access the
+// <webview> element's internal members is via the |secret|. Since it's only
+// accessible by code here (and in web_view_experimental), only <webview>'s
+// API can access it and not external developers.
+var secret = {};
 
 /** @type {Array.<string>} */
 var WEB_VIEW_ATTRIBUTES = ['name', 'src', 'partition', 'autosize', 'minheight',
     'minwidth', 'maxheight', 'maxwidth'];
 
-var WEB_VIEW_EVENTS = {
-  'sizechanged': ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'],
-};
-
 var webViewInstanceIdCounter = 0;
 
 var createEvent = function(name) {
@@ -103,51 +112,52 @@
     evt: createEvent('webview.onResponsive'),
     fields: ['processId']
   },
+  'sizechanged': {
+    evt: createEvent('webview.onSizeChanged'),
+    fields: ['oldHeight', 'oldWidth', 'newHeight', 'newWidth']
+  },
   'unresponsive': {
     evt: createEvent('webview.onUnresponsive'),
     fields: ['processId']
   }
 };
 
-addTagWatcher('WEBVIEW', function(addedNode) { new WebView(addedNode); });
-
-/** @type {number} */
-WebView.prototype.entryCount_;
-
-/** @type {number} */
-WebView.prototype.currentEntryIndex_;
-
-/** @type {number} */
-WebView.prototype.processId_;
+// Implemented when the experimental API is available.
+WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {}
 
 /**
  * @constructor
  */
-function WebView(webviewNode) {
+function WebViewInternal(webviewNode) {
   this.webviewNode_ = webviewNode;
   this.browserPluginNode_ = this.createBrowserPluginNode_();
   var shadowRoot = this.webviewNode_.webkitCreateShadowRoot();
   shadowRoot.appendChild(this.browserPluginNode_);
 
-  this.setupFocusPropagation_();
-  this.setupWebviewNodeMethods_();
-  this.setupWebviewNodeProperties_();
   this.setupWebviewNodeAttributes_();
+  this.setupFocusPropagation_();
+  this.setupWebviewNodeProperties_();
   this.setupWebviewNodeEvents_();
-
-  // Experimental API
-  this.maybeSetupExperimentalAPI_();
 }
 
 /**
  * @private
  */
-WebView.prototype.createBrowserPluginNode_ = function() {
-  var browserPluginNode = document.createElement('object');
-  browserPluginNode.type = 'application/browser-plugin';
-  // The <object> node fills in the <webview> container.
-  browserPluginNode.style.width = '100%';
-  browserPluginNode.style.height = '100%';
+WebViewInternal.prototype.createBrowserPluginNode_ = function() {
+  // We create BrowserPlugin as a custom element in order to observe changes
+  // to attributes synchronously.
+  var browserPluginNode = new WebViewInternal.BrowserPlugin();
+  Object.defineProperty(browserPluginNode, 'internal_', {
+    enumerable: false,
+    writable: false,
+    value: function(key) {
+      if (key !== secret) {
+        return null;
+      }
+      return this;
+    }.bind(this)
+  });
+
   $Array.forEach(WEB_VIEW_ATTRIBUTES, function(attributeName) {
     // Only copy attributes that have been assigned values, rather than copying
     // a series of undefined attributes to BrowserPlugin.
@@ -170,7 +180,7 @@
 /**
  * @private
  */
-WebView.prototype.setupFocusPropagation_ = function() {
+WebViewInternal.prototype.setupFocusPropagation_ = function() {
   if (!this.webviewNode_.hasAttribute('tabIndex')) {
     // <webview> needs a tabIndex in order to respond to keyboard focus.
     // TODO(fsamuel): This introduces unexpected tab ordering. We need to find
@@ -192,73 +202,98 @@
 /**
  * @private
  */
-WebView.prototype.setupWebviewNodeMethods_ = function() {
-  // this.browserPluginNode_[apiMethod] are not necessarily defined immediately
-  // after the shadow object is appended to the shadow root.
-  var webviewNode = this.webviewNode_;
-  var browserPluginNode = this.browserPluginNode_;
-  var self = this;
-
-  webviewNode['canGoBack'] = function() {
-    return self.entryCount_ > 1 && self.currentEntryIndex_ > 0;
-  };
-
-  webviewNode['canGoForward'] = function() {
-    return self.currentEntryIndex_ >=0 &&
-        self.currentEntryIndex_ < (self.entryCount_ - 1);
-  };
-
-  webviewNode['back'] = function() {
-    webviewNode.go(-1);
-  };
-
-  webviewNode['forward'] = function() {
-    webviewNode.go(1);
-  };
-
-  webviewNode['getProcessId'] = function() {
-    return self.processId_;
-  };
-
-  webviewNode['go'] = function(relativeIndex) {
-    var instanceId = browserPluginNode.getGuestInstanceId();
-    if (!instanceId) {
-      return;
-    }
-    chrome.webview.go(instanceId, relativeIndex);
-  };
-
-  webviewNode['reload'] = function() {
-    var instanceId = browserPluginNode.getGuestInstanceId();
-    if (!instanceId) {
-      return;
-    }
-    chrome.webview.reload(instanceId);
-  };
-
-  webviewNode['stop'] = function() {
-    var instanceId = browserPluginNode.getGuestInstanceId();
-    if (!instanceId) {
-      return;
-    }
-    chrome.webview.stop(instanceId);
-  };
-
-  webviewNode['terminate'] = function() {
-    var instanceId = browserPluginNode.getGuestInstanceId();
-    if (!instanceId) {
-      return;
-    }
-    chrome.webview.terminate(instanceId);
-  };
-
-  this.setupExecuteCodeAPI_();
+WebViewInternal.prototype.canGoBack_ = function() {
+  return this.entryCount_ > 1 && this.currentEntryIndex_ > 0;
 };
 
 /**
  * @private
  */
-WebView.prototype.setupWebviewNodeProperties_ = function() {
+WebViewInternal.prototype.canGoForward_ = function() {
+  return this.currentEntryIndex_ >= 0 &&
+      this.currentEntryIndex_ < (this.entryCount_ - 1);
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.getProcessId_ = function() {
+  return this.processId_;
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.go_ = function(relativeIndex) {
+  if (!this.instanceId_) {
+    return;
+  }
+  chrome.webview.go(this.instanceId_, relativeIndex);
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.reload_ = function() {
+  if (!this.instanceId_) {
+    return;
+  }
+  chrome.webview.reload(this.instanceId_);
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.stop_ = function() {
+  if (!this.instanceId_) {
+    return;
+  }
+  chrome.webview.stop(this.instanceId_);
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.terminate_ = function() {
+  if (!this.instanceId_) {
+    return;
+  }
+  chrome.webview.terminate(this.instanceId_);
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.validateExecuteCodeCall_  = function() {
+  var ERROR_MSG_CANNOT_INJECT_SCRIPT = '<webview>: ' +
+      'Script cannot be injected into content until the page has loaded.';
+  if (!this.instanceId_) {
+    throw new Error(ERROR_MSG_CANNOT_INJECT_SCRIPT);
+  }
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.executeScript_ = function(var_args) {
+  this.validateExecuteCodeCall_();
+  var args = $Array.concat([this.instanceId_], $Array.slice(arguments));
+  $Function.apply(chrome.webview.executeScript, null, args);
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.insertCSS_ = function(var_args) {
+  this.validateExecuteCodeCall_();
+  var args = $Array.concat([this.instanceId_], $Array.slice(arguments));
+  $Function.apply(chrome.webview.insertCSS, null, args);
+};
+
+/**
+ * @private
+ */
+WebViewInternal.prototype.setupWebviewNodeProperties_ = function() {
   var ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE = '<webview>: ' +
     'contentWindow is not available at this time. It will become available ' +
         'when the page has finished loading.';
@@ -268,17 +303,28 @@
   $Array.forEach(WEB_VIEW_ATTRIBUTES, function(attributeName) {
     Object.defineProperty(this.webviewNode_, attributeName, {
       get: function() {
-        return browserPluginNode[attributeName];
+        if (browserPluginNode.hasOwnProperty(attributeName)) {
+          return browserPluginNode[attributeName];
+        } else {
+          return browserPluginNode.getAttribute(attributeName);
+        }
       },
       set: function(value) {
-        browserPluginNode[attributeName] = value;
+        if (browserPluginNode.hasOwnProperty(attributeName)) {
+          // Give the BrowserPlugin first stab at the attribute so that it can
+          // throw an exception if there is a problem. This attribute will then
+          // be propagated back to the <webview>.
+          browserPluginNode[attributeName] = value;
+        } else {
+          browserPluginNode.setAttribute(attributeName, value);
+        }
       },
       enumerable: true
     });
   }, this);
 
-  // We cannot use {writable: true} property descriptor because we want dynamic
-  // getter value.
+  // We cannot use {writable: true} property descriptor because we want a
+  // dynamic getter value.
   Object.defineProperty(this.webviewNode_, 'contentWindow', {
     get: function() {
       if (browserPluginNode.contentWindow)
@@ -293,67 +339,73 @@
 /**
  * @private
  */
-WebView.prototype.setupWebviewNodeAttributes_ = function() {
-  this.setupWebviewNodeObservers_();
-  this.setupBrowserPluginNodeObservers_();
+WebViewInternal.prototype.setupWebviewNodeAttributes_ = function() {
+  Object.defineProperty(this.webviewNode_, 'internal_', {
+    enumerable: false,
+    writable: false,
+    value: function(key) {
+      if (key !== secret) {
+        return null;
+      }
+      return this;
+    }.bind(this)
+  });
+  this.setupWebViewSrcAttributeMutationObserver_();
 };
 
 /**
  * @private
  */
-WebView.prototype.setupWebviewNodeObservers_ = function() {
-  // Map attribute modifications on the <webview> tag to property changes in
-  // the underlying <object> node.
-  var handleMutation = $Function.bind(function(mutation) {
-    this.handleWebviewAttributeMutation_(mutation);
-  }, this);
+WebViewInternal.prototype.setupWebViewSrcAttributeMutationObserver_ =
+    function() {
+  // The purpose of this mutation observer is to catch assignment to the src
+  // attribute without any changes to its value. This is useful in the case
+  // where the webview guest has crashed and navigating to the same address
+  // spawns off a new process.
+  var self = this;
   var observer = new MutationObserver(function(mutations) {
-    $Array.forEach(mutations, handleMutation);
+    $Array.forEach(mutations, function(mutation) {
+      var newValue = self.webviewNode_.getAttribute(mutation.attributeName);
+      if (mutation.oldValue != newValue) {
+        return;
+      }
+      self.handleWebviewAttributeMutation_(mutation.attributeName, newValue);
+    });
   });
-  observer.observe(
-      this.webviewNode_,
-      {attributes: true, attributeFilter: WEB_VIEW_ATTRIBUTES});
+  var params = {
+    attributes: true,
+    attributeOldValue: true,
+    attributeFilter: ['src']
+  };
+  observer.observe(this.webviewNode_, params);
 };
 
 /**
  * @private
  */
-WebView.prototype.setupBrowserPluginNodeObservers_ = function() {
-  var handleMutation = $Function.bind(function(mutation) {
-    this.handleBrowserPluginAttributeMutation_(mutation);
-  }, this);
-  var objectObserver = new MutationObserver(function(mutations) {
-    $Array.forEach(mutations, handleMutation);
-  });
-  objectObserver.observe(
-      this.browserPluginNode_,
-      {attributes: true, attributeFilter: WEB_VIEW_ATTRIBUTES});
-};
-
-/**
- * @private
- */
-WebView.prototype.handleWebviewAttributeMutation_ = function(mutation) {
+WebViewInternal.prototype.handleWebviewAttributeMutation_ =
+      function(name, newValue) {
   // This observer monitors mutations to attributes of the <webview> and
   // updates the BrowserPlugin properties accordingly. In turn, updating
   // a BrowserPlugin property will update the corresponding BrowserPlugin
   // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
   // details.
-  this.browserPluginNode_[mutation.attributeName] =
-      this.webviewNode_.getAttribute(mutation.attributeName);
+  if (this.browserPluginNode_.hasOwnProperty(name)) {
+    this.browserPluginNode_[name] = newValue;
+  } else {
+    this.browserPluginNode_.setAttribute(name, newValue);
+  }
 };
 
 /**
  * @private
  */
-WebView.prototype.handleBrowserPluginAttributeMutation_ = function(mutation) {
+WebViewInternal.prototype.handleBrowserPluginAttributeMutation_ =
+    function(name, oldValue, newValue) {
   // This observer monitors mutations to attributes of the BrowserPlugin and
   // updates the <webview> attributes accordingly.
-  if (!this.browserPluginNode_.hasAttribute(mutation.attributeName)) {
-    // If an attribute is removed from the BrowserPlugin, then remove it
-    // from the <webview> as well.
-    this.webviewNode_.removeAttribute(mutation.attributeName);
-  } else {
+  // |newValue| is null if the attribute |name| has been removed.
+  if (newValue != null) {
     // Update the <webview> attribute to match the BrowserPlugin attribute.
     // Note: Calling setAttribute on <webview> will trigger its mutation
     // observer which will then propagate that attribute to BrowserPlugin. In
@@ -361,18 +413,20 @@
     // again (such as navigation when crashed), this could end up in an infinite
     // loop. Thus, we avoid this loop by only updating the <webview> attribute
     // if the BrowserPlugin attributes differs from it.
-    var oldValue = this.webviewNode_.getAttribute(mutation.attributeName);
-    var newValue = this.browserPluginNode_.getAttribute(mutation.attributeName);
     if (newValue != oldValue) {
-      this.webviewNode_.setAttribute(mutation.attributeName, newValue);
+      this.webviewNode_.setAttribute(name, newValue);
     }
+  } else {
+    // If an attribute is removed from the BrowserPlugin, then remove it
+    // from the <webview> as well.
+    this.webviewNode_.removeAttribute(name);
   }
 };
 
 /**
  * @private
  */
-WebView.prototype.getWebviewExtEvents_ = function() {
+WebViewInternal.prototype.getWebviewExtEvents_ = function() {
   var experimentalExtEvents = this.maybeGetWebviewExperimentalExtEvents_();
   for (var eventName in experimentalExtEvents) {
     WEB_VIEW_EXT_EVENTS[eventName] = experimentalExtEvents[eventName];
@@ -383,7 +437,7 @@
 /**
  * @private
  */
-WebView.prototype.setupWebviewNodeEvents_ = function() {
+WebViewInternal.prototype.setupWebviewNodeEvents_ = function() {
   var self = this;
   this.viewInstanceId_ = ++webViewInstanceIdCounter;
   var onInstanceIdAllocated = function(e) {
@@ -402,16 +456,13 @@
   };
   this.browserPluginNode_.addEventListener('-internal-instanceid-allocated',
                                            onInstanceIdAllocated);
-
-  for (var eventName in WEB_VIEW_EVENTS) {
-    this.setupEvent_(eventName, WEB_VIEW_EVENTS[eventName]);
-  }
+  this.setupWebRequestEvents_();
 };
 
 /**
  * @private
  */
-WebView.prototype.setupExtEvent_ = function(eventName, eventInfo) {
+WebViewInternal.prototype.setupExtEvent_ = function(eventName, eventInfo) {
   var self = this;
   var webviewNode = this.webviewNode_;
   eventInfo.evt.addListener(function(event) {
@@ -435,23 +486,8 @@
 /**
  * @private
  */
-WebView.prototype.setupEvent_ = function(eventName, attribs) {
-  var webviewNode = this.webviewNode_;
-  var internalname = '-internal-' + eventName;
-  this.browserPluginNode_.addEventListener(internalname, function(e) {
-    var evt = new Event(eventName, { bubbles: true });
-    var detail = e.detail ? JSON.parse(e.detail) : {};
-    $Array.forEach(attribs, function(attribName) {
-      evt[attribName] = detail[attribName];
-    });
-    webviewNode.dispatchEvent(evt);
-  });
-};
-
-/**
- * @private
- */
-WebView.prototype.setupExtNewWindowEvent_ = function(event, webviewEvent) {
+WebViewInternal.prototype.setupExtNewWindowEvent_ =
+    function(event, webviewEvent) {
   var ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN = '<webview>: ' +
       'An action has already been taken for this "newwindow" event.';
 
@@ -472,22 +508,6 @@
   var requestId = event.requestId;
   var actionTaken = false;
 
-  var onTrackedObjectGone = function(requestId, e) {
-    var detail = e.detail ? JSON.parse(e.detail) : {};
-    if (detail.id != requestId) {
-      return;
-    }
-
-    // Avoid showing a warning message if the decision has already been made.
-    if (actionTaken) {
-      return;
-    }
-
-    chrome.webview.setPermission(self.instanceId_, requestId, false, '');
-    showWarningMessage();
-  };
-
-
   var validateCall = function () {
     if (actionTaken) {
       throw new Error(ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN);
@@ -533,11 +553,14 @@
 
   if (defaultPrevented) {
     // Make browser plugin track lifetime of |window|.
-    var onTrackedObjectGoneWithRequestId =
-        $Function.bind(onTrackedObjectGone, self, requestId);
-    browserPluginNode.addEventListener('-internal-trackedobjectgone',
-        onTrackedObjectGoneWithRequestId);
-    browserPluginNode['-internal-trackObjectLifetime'](window, requestId);
+    messagingNatives.BindToGC(window, function() {
+      // Avoid showing a warning message if the decision has already been made.
+      if (actionTaken) {
+        return;
+      }
+      chrome.webview.setPermission(self.instanceId_, requestId, false, '');
+      showWarningMessage();
+    });
   } else {
     actionTaken = true;
     // The default action is to discard the window.
@@ -546,42 +569,12 @@
   }
 };
 
-/**
- * @private
- */
-WebView.prototype.setupExecuteCodeAPI_ = function() {
-  var ERROR_MSG_CANNOT_INJECT_SCRIPT = '<webview>: ' +
-      'Script cannot be injected into content until the page has loaded.';
-
-  var self = this;
-  var validateCall = function() {
-    if (!self.browserPluginNode_.getGuestInstanceId()) {
-      throw new Error(ERROR_MSG_CANNOT_INJECT_SCRIPT);
-    }
-  };
-
-  this.webviewNode_['executeScript'] = function(var_args) {
-    validateCall();
-    var args = $Array.concat([self.browserPluginNode_.getGuestInstanceId()],
-                             $Array.slice(arguments));
-    $Function.apply(chrome.webview.executeScript, null, args);
-  }
-  this.webviewNode_['insertCSS'] = function(var_args) {
-    validateCall();
-    var args = $Array.concat([self.browserPluginNode_.getGuestInstanceId()],
-                             $Array.slice(arguments));
-    $Function.apply(chrome.webview.insertCSS, null, args);
-  }
-};
-
-/**
- * @private
- */
-WebView.prototype.getPermissionTypes_ = function() {
+WebViewInternal.prototype.getPermissionTypes_ = function() {
   return ['media', 'geolocation', 'pointerLock', 'download'];
 };
 
-WebView.prototype.setupExtPermissionEvent_ = function(event, webviewEvent) {
+WebViewInternal.prototype.setupExtPermissionEvent_ =
+    function(event, webviewEvent) {
   var ERROR_MSG_PERMISSION_ALREADY_DECIDED = '<webview>: ' +
       'Permission has already been decided for this "permissionrequest" event.';
 
@@ -600,21 +593,6 @@
   var requestId = event.requestId;
   var decisionMade = false;
 
-  var onTrackedObjectGone = function(requestId, permission, e) {
-    var detail = e.detail ? JSON.parse(e.detail) : {};
-    if (detail.id != requestId) {
-      return;
-    }
-
-    // Avoid showing a warning message if the decision has already been made.
-    if (decisionMade) {
-      return;
-    }
-
-    chrome.webview.setPermission(self.instanceId_, requestId, false, '');
-    showWarningMessage(permission);
-  };
-
   var validateCall = function() {
     if (decisionMade) {
       throw new Error(ERROR_MSG_PERMISSION_ALREADY_DECIDED);
@@ -642,12 +620,14 @@
 
   if (defaultPrevented) {
     // Make browser plugin track lifetime of |request|.
-    var onTrackedObjectGoneWithRequestId =
-        $Function.bind(
-            onTrackedObjectGone, self, requestId, event.permission);
-    browserPluginNode.addEventListener('-internal-trackedobjectgone',
-        onTrackedObjectGoneWithRequestId);
-    browserPluginNode['-internal-trackObjectLifetime'](request, requestId);
+    messagingNatives.BindToGC(request, function() {
+      // Avoid showing a warning message if the decision has already been made.
+      if (decisionMade) {
+        return;
+      }
+      chrome.webview.setPermission(self.instanceId_, requestId, false, '');
+      showWarningMessage(event.permission);
+    });
   } else {
     decisionMade = true;
     chrome.webview.setPermission(self.instanceId_, requestId, false, '');
@@ -656,22 +636,176 @@
 };
 
 /**
- * Implemented when the experimental API is available.
  * @private
  */
-WebView.prototype.maybeSetupExperimentalAPI_ = function() {};
+WebViewInternal.prototype.setupWebRequestEvents_ = function() {
+  var self = this;
+  var request = {};
+  var createWebRequestEvent = function(webRequestEvent) {
+    return function() {
+      if (!self[webRequestEvent.name + '_']) {
+        self[webRequestEvent.name + '_'] =
+            new WebRequestEvent(
+                'webview.' + webRequestEvent.name,
+                webRequestEvent.parameters,
+                webRequestEvent.extraParameters, null,
+                self.viewInstanceId_);
+      }
+      return self[webRequestEvent.name + '_'];
+    };
+  };
+
+  // Populate the WebRequest events from the API definition.
+  for (var i = 0; i < webRequestSchema.events.length; ++i) {
+    var webRequestEvent = createWebRequestEvent(webRequestSchema.events[i]);
+    Object.defineProperty(
+        request,
+        webRequestSchema.events[i].name,
+        {
+          get: webRequestEvent,
+          enumerable: true
+        }
+    );
+    this.maybeAttachWebRequestEventToWebview_(webRequestSchema.events[i].name,
+                                              webRequestEvent);
+  }
+  Object.defineProperty(
+      this.webviewNode_,
+      'request',
+      {
+        value: request,
+        enumerable: true,
+        writable: false
+      }
+  );
+};
+
+// Registers browser plugin <object> custom element.
+function registerBrowserPluginElement() {
+  var proto = Object.create(HTMLObjectElement.prototype);
+
+  proto.createdCallback = function() {
+    this.setAttribute('type', 'application/browser-plugin');
+    // The <object> node fills in the <webview> container.
+    this.style.width = '100%';
+    this.style.height = '100%';
+  };
+
+  proto.attributeChangedCallback = function(name, oldValue, newValue) {
+    if (!this.internal_) {
+      return;
+    }
+    var internal = this.internal_(secret);
+    internal.handleBrowserPluginAttributeMutation_(name, oldValue, newValue);
+  };
+
+  WebViewInternal.BrowserPlugin =
+      DocumentNatives.RegisterElement('browser-plugin', {prototype: proto});
+
+  delete proto.createdCallback;
+  delete proto.enteredDocumentCallback;
+  delete proto.leftDocumentCallback;
+  delete proto.attributeChangedCallback;
+}
+
+// Registers <webview> custom element.
+function registerWebViewElement() {
+  var proto = Object.create(HTMLElement.prototype);
+
+  proto.createdCallback = function() {
+    new WebViewInternal(this);
+  };
+
+  proto.attributeChangedCallback = function(name, oldValue, newValue) {
+    var internal = this.internal_(secret);
+    internal.handleWebviewAttributeMutation_(name, newValue);
+  };
+
+  proto.back = function() {
+    this.go(-1);
+  };
+
+  proto.forward = function() {
+    this.go(1);
+  };
+
+  proto.canGoBack = function() {
+    return this.internal_(secret).canGoBack_();
+  };
+
+  proto.canGoForward = function() {
+    return this.internal_(secret).canGoForward_();
+  };
+
+  proto.getProcessId = function() {
+    return this.internal_(secret).getProcessId_();
+  };
+
+  proto.go = function(relativeIndex) {
+    this.internal_(secret).go_(relativeIndex);
+  };
+
+  proto.reload = function() {
+    this.internal_(secret).reload_();
+  };
+
+  proto.stop = function() {
+    this.internal_(secret).stop_();
+  };
+
+  proto.terminate = function() {
+    this.internal_(secret).terminate_();
+  };
+
+  proto.executeScript = function(var_args) {
+    var internal = this.internal_(secret);
+    $Function.apply(internal.executeScript_, internal, arguments);
+  };
+
+  proto.insertCSS = function(var_args) {
+    var internal = this.internal_(secret);
+    $Function.apply(internal.insertCSS_, internal, arguments);
+  };
+  WebViewInternal.maybeRegisterExperimentalAPIs(proto, secret);
+
+  window.WebView =
+      DocumentNatives.RegisterElement('webview', {prototype: proto});
+
+  // Delete the callbacks so developers cannot call them and produce unexpected
+  // behavior.
+  delete proto.createdCallback;
+  delete proto.enteredDocumentCallback;
+  delete proto.leftDocumentCallback;
+  delete proto.attributeChangedCallback;
+}
+
+var useCapture = true;
+window.addEventListener('readystatechange', function listener(event) {
+  if (document.readyState == 'loading')
+    return;
+
+  registerBrowserPluginElement();
+  registerWebViewElement();
+  window.removeEventListener(event.type, listener, useCapture);
+}, useCapture);
 
 /**
  * Implemented when the experimental API is available.
  * @private
  */
-WebView.prototype.maybeSetupExtDialogEvent_ = function() {};
+WebViewInternal.prototype.maybeSetupExtDialogEvent_ = function() {};
 
 /**
  * Implemented when the experimental API is available.
  * @private
  */
-WebView.prototype.maybeGetWebviewExperimentalExtEvents_ = function() {};
+WebViewInternal.prototype.maybeGetWebviewExperimentalExtEvents_ = function() {};
 
-exports.WebView = WebView;
+/**
+ * Implemented when the experimental API is available.
+ * @private
+ */
+WebViewInternal.prototype.maybeAttachWebRequestEventToWebview_ = function() {};
+
+exports.WebViewInternal = WebViewInternal;
 exports.CreateEvent = createEvent;
diff --git a/chrome/renderer/resources/extensions/web_view_experimental.js b/chrome/renderer/resources/extensions/web_view_experimental.js
index 8498f92..7b3dd83 100644
--- a/chrome/renderer/resources/extensions/web_view_experimental.js
+++ b/chrome/renderer/resources/extensions/web_view_experimental.js
@@ -12,10 +12,11 @@
 // CHANNEL_CANARY.
 
 var createEvent = require('webView').CreateEvent;
+var messagingNatives = requireNative('messaging_natives');
 var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
 var webRequestSchema =
     requireNative('schema_registry').GetSchema('webRequest');
-var WebView = require('webView').WebView;
+var WebViewInternal = require('webView').WebViewInternal;
 
 var WEB_VIEW_EXPERIMENTAL_EXT_EVENTS = {
   'dialog': {
@@ -31,57 +32,14 @@
 /**
  * @private
  */
-WebView.prototype.maybeSetupExperimentalAPI_ = function() {
-  this.setupWebRequestEvents_();
-};
-
-/**
- * @private
- */
-WebView.prototype.setupWebRequestEvents_ = function() {
-  var self = this;
-  var request = {};
-  var createWebRequestEvent = function(webRequestEvent) {
-    return function() {
-      if (!self[webRequestEvent.name + '_']) {
-        self[webRequestEvent.name + '_'] =
-            new WebRequestEvent(
-                'webview.' + webRequestEvent.name,
-                webRequestEvent.parameters,
-                webRequestEvent.extraParameters, null,
-                self.viewInstanceId_);
-      }
-      return self[webRequestEvent.name + '_'];
-    };
-  };
-
-  // Populate the WebRequest events from the API definition.
-  for (var i = 0; i < webRequestSchema.events.length; ++i) {
-    var webRequestEvent = createWebRequestEvent(webRequestSchema.events[i]);
-    Object.defineProperty(
-        request,
-        webRequestSchema.events[i].name,
-        {
-          get: webRequestEvent,
-          enumerable: true
-        }
-    );
-    Object.defineProperty(
-        this.webviewNode_,
-        webRequestSchema.events[i].name,
-        {
-          get: webRequestEvent,
-          enumerable: true
-        }
-    );
-  }
+WebViewInternal.prototype.maybeAttachWebRequestEventToWebview_ =
+    function(eventName, webRequestEvent) {
   Object.defineProperty(
       this.webviewNode_,
-      'request',
+      eventName,
       {
-        value: request,
-        enumerable: true,
-        writable: false
+        get: webRequestEvent,
+        enumerable: true
       }
   );
 };
@@ -89,7 +47,8 @@
 /**
  * @private
  */
-WebView.prototype.maybeSetupExtDialogEvent_ = function(event, webviewEvent) {
+WebViewInternal.prototype.maybeSetupExtDialogEvent_ =
+    function(event, webviewEvent) {
   var showWarningMessage = function(dialogType) {
     var VOWELS = ['a', 'e', 'i', 'o', 'u'];
     var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.';
@@ -106,21 +65,6 @@
   var requestId = event.requestId;
   var actionTaken = false;
 
-  var onTrackedObjectGone = function(requestId, dialogType, e) {
-    var detail = e.detail ? JSON.parse(e.detail) : {};
-    if (detail.id != requestId) {
-      return;
-    }
-
-    // Avoid showing a warning message if the decision has already been made.
-    if (actionTaken) {
-      return;
-    }
-
-    chrome.webview.setPermission(self.instanceId_, requestId, false, '');
-    showWarningMessage(dialogType);
-  }
-
   var validateCall = function() {
     var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' +
         'An action has already been taken for this "dialog" event.';
@@ -153,12 +97,14 @@
   if (defaultPrevented) {
     // Tell the JavaScript garbage collector to track lifetime of |dialog| and
     // call back when the dialog object has been collected.
-    var onTrackedObjectGoneWithRequestId =
-        $Function.bind(
-            onTrackedObjectGone, self, requestId, event.messageType);
-    browserPluginNode.addEventListener('-internal-trackedobjectgone',
-        onTrackedObjectGoneWithRequestId);
-    browserPluginNode['-internal-trackObjectLifetime'](dialog, requestId);
+    messagingNatives.BindToGC(dialog, function() {
+      // Avoid showing a warning message if the decision has already been made.
+      if (actionTaken) {
+        return;
+      }
+      chrome.webview.setPermission(self.instanceId_, requestId, false, '');
+      showWarningMessage(event.messageType);
+    });
   } else {
     actionTaken = true;
     // The default action is equivalent to canceling the dialog.
@@ -170,6 +116,21 @@
 /**
  * @private
  */
-WebView.prototype.maybeGetWebviewExperimentalExtEvents_ = function() {
+WebViewInternal.prototype.maybeGetWebviewExperimentalExtEvents_ = function() {
   return WEB_VIEW_EXPERIMENTAL_EXT_EVENTS;
 };
+
+WebViewInternal.prototype.clearData_ = function(var_args) {
+  if (!this.instanceId_) {
+    return;
+  }
+  var args = $Array.concat([this.instanceId_], $Array.slice(arguments));
+  $Function.apply(chrome.webview.clearData, null, args);
+};
+
+WebViewInternal.maybeRegisterExperimentalAPIs = function(proto, secret) {
+  proto.clearData = function(var_args) {
+    var internal = this.internal_(secret);
+    $Function.apply(internal.clearData_, internal, arguments);
+  };
+};
diff --git a/chrome/renderer/resources/neterror.css b/chrome/renderer/resources/neterror.css
new file mode 100644
index 0000000..8d0c55c
--- /dev/null
+++ b/chrome/renderer/resources/neterror.css
@@ -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. */
+
+body {
+  background-color: #E6E6E6;
+  font-family: Helvetica, Arial, sans-serif;
+  font-size: 10pt;
+  margin: 50px 40px 20px 40px;
+  text-align: center;
+}
+
+#main-frame-error {
+  margin: auto;
+  max-width: 540px;
+  min-width: 200px;
+}
+
+/* Don't use the main frame div when the error is in a subframe. */
+html[subframe] #main-frame-error {
+  display: none;
+}
+
+/* Don't use the subframe error div when the error is in a main frame. */
+html:not([subframe]) #sub-frame-error {
+  display: none;
+}
+
+#box {
+  background-color: #fbfbfb;
+  border: 1px solid #AAA;
+  border-bottom: 1px solid #888;
+  border-radius: 3px;
+  color: black;
+<if expr="not is_android and not is_ios">
+  /* Not done on mobile for performance reasons. */
+  box-shadow: 0px 2px 2px #AAA;
+</if>
+}
+
+#diagnose-button {
+  margin-top: 20px;
+  margin-bottom: 10px;
+  -webkit-margin-start: 0px;
+}
+
+h1 {
+  color: #666;
+  margin: 10px 0px 25px 0px;
+  font-weight: normal;
+  font-size: 1.5em;
+}
+
+a {
+  color: #15c;
+  text-decoration: none;
+}
+
+.icon {
+  -webkit-user-select: none;
+}
+
+.icon-generic {
+  /**
+   * Can't access chrome://theme/IDR_ERROR_NETWORK_GENERIC from an untrusted
+   * renderer process, so embed the resource manually.
+   */
+  content: -webkit-image-set(
+      url('../../app/theme/default_100_percent/common/error_network_generic.png') 1x,
+      url('../../app/theme/default_200_percent/common/error_network_generic.png') 2x);
+}
+
+.icon-offline {
+  content: -webkit-image-set(
+      url('../../app/theme/default_100_percent/common/error_network_offline.png') 1x,
+      url('../../app/theme/default_200_percent/common/error_network_offline.png') 2x);
+}
+
+#content-top {
+  margin: 20px 20px 20px 25px;
+}
+
+#help-box-outer {
+  overflow: hidden;
+  -webkit-transition: height ease-in 218ms;
+}
+
+#help-box-inner {
+  background-color: #f9f9f9;
+  border-top: 1px solid #EEE;
+  color: #444;
+  padding: 25px 20px;
+  text-align: start;
+}
+
+#suggestions {
+  margin-top: 15px;
+}
+
+#sub-frame-error-details {
+  color: #8F8F8F;
+<if expr="not is_android and not is_ios">
+  /* Not done on mobile for performance reasons. */
+  text-shadow: 0 1px 0 rgba(255,255,255,0.3);
+</if>
+}
+
+[jscontent=failedUrl] {
+  overflow-wrap: break-word;
+}
+
+button {
+  border: 1px solid rgba(0, 0, 0, 0.25);
+  border-radius: 2px;
+  color: #444;
+  margin: 0px 5px;
+  min-height: 29px;
+  min-width: 65px;
+  -webkit-user-select: none;
+  padding: 8px 13px;
+<if expr="not is_android">
+  /* iOS does not support linear-gradient without a prefix. */
+  background-image: -webkit-linear-gradient(#ededed, #ededed 38%, #dedede);
+  text-shadow: 0 1px 0 rgb(240, 240, 240);
+</if>
+<if expr="is_android">
+  /* Android uses flat background colors. */
+  background-color: #ededed;
+  font-weight: bold;
+</if>
+<if expr="not is_android and not is_ios">
+  /* Not done on mobile for performance reasons. */
+  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.75);
+</if>
+}
+
+button:hover {
+  border: 1px solid rgba(0, 0, 0, 0.3);
+  color: #000;
+<if expr="not is_android">
+  background-image: -webkit-linear-gradient(#f0f0f0, #f0f0f0 38%, #e0e0e0);
+</if>
+<if expr="is_android">
+  background-color: #f0f0f0;
+</if>
+<if expr="not is_android and not is_ios">
+  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.95);
+</if>
+}
+
+button:active {
+  border: 1px solid rgba(0, 0, 0, 0.3);
+  color: #444;
+<if expr="not is_android">
+  background-image: -webkit-linear-gradient(#e7e7e7, #e7e7e7 38%, #d7d7d7);
+</if>
+<if expr="is_android">
+  background-color: #e7e7e7;
+</if>
+<if expr="not is_android and not is_ios">
+  box-shadow: none;
+</if>
+}
+
+#reload-button {
+  color: #fff;
+<if expr="not is_android">
+  background-image: -webkit-linear-gradient(#5d9aff, #5d9aff 38%, #5891f0);
+  border: 1px solid rgba(45, 102, 195, 1);
+  text-shadow: 0 1px 0 rgba(0,0,0,0.5);
+</if>
+<if expr="is_android">
+  background-color: rgb(39, 180, 231);
+  border: 1px solid rgb(0, 152, 206);
+</if>
+<if expr="not is_android and not is_ios">
+  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15), inset 0 1px 2px rgba(255, 255, 255, 0.2);
+</if>
+}
+
+#reload-button:hover {
+<if expr="not is_android">
+  background-image: -webkit-linear-gradient(#659efd, #659efd 38%, #6097f1);
+  border: 1px solid rgba(45, 102, 195, 1);
+</if>
+<if expr="not is_android and not is_ios">
+  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25), inset 0 1px 2px rgba(255, 255, 255, 0.2);
+</if>
+}
+
+#reload-button:active {
+<if expr="not is_android">
+  background-image: -webkit-linear-gradient(#6095ed, #6095ed 38%, #6095ed);
+  border: 1px solid rgb(38, 84, 160);
+</if>
+<if expr="is_android">
+  background-color: rgb(0, 152, 206);
+</if>
+<if expr="not is_android and not is_ios">
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
+</if>
+}
+
+.hidden {
+  display: none;
+}
+
+.suggestions {
+  margin-top: 18px;
+}
+
+.suggestion-header {
+  font-weight: bold;
+  margin-bottom: 4px;
+}
+
+.suggestion-body {
+  color: #777;
+}
+
+.error-code {
+  color: #A0A0A0;
+  margin-top: 15px;
+}
+
+/* Increase line height at higher resolutions. */
+@media (min-width: 641px) and (min-height: 641px) {
+  #help-box-inner {
+    line-height: 18px;
+  }
+}
+
+/* Decrease padding at low sizes. */
+@media (max-width: 640px), (max-height: 640px) {
+  body {
+    margin: 15px;
+  }
+  h1 {
+    margin: 10px 0px 15px 0px;
+  }
+  #content-top {
+    margin: 15px;
+  }
+  #help-box-inner {
+    padding: 20px;
+  }
+  .suggestions {
+    margin-top: 10px;
+  }
+  .suggestion-header {
+    margin-bottom: 0px;
+  }
+  .error-code {
+    margin-top: 10px;
+  }
+}
+
+/* Don't allow overflow when in a subframe. */
+html[subframe] body {
+  overflow: hidden;
+}
+
+#sub-frame-error {
+  -webkit-align-items: center;
+  background-color: #DDD;
+  display: -webkit-flex;
+  -webkit-flex-flow: column;
+  height: 100%;
+  -webkit-justify-content: center;
+  left: 0px;
+  position: absolute;
+  top: 0px;
+  width: 100%;
+}
+
+#sub-frame-error:hover {
+  background-color: #EEE;
+}
+
+#sub-frame-error-details {
+  margin: 0 10px;
+  visibility: hidden;
+}
+
+/* Show details only when hovering. */
+#sub-frame-error:hover #sub-frame-error-details {
+  visibility: visible;
+}
+
+/* If the iframe is too small, always hide the error code. */
+/* TODO(mmenke): See if overflow: no-display works better, once supported. */
+@media (max-width: 200px), (max-height: 95px) {
+  #sub-frame-error-details {
+    display: none;
+  }
+}
diff --git a/chrome/renderer/resources/neterror.html b/chrome/renderer/resources/neterror.html
index 8b81d1d..d28c508 100644
--- a/chrome/renderer/resources/neterror.html
+++ b/chrome/renderer/resources/neterror.html
@@ -1,354 +1,13 @@
 <!DOCTYPE html>
 <html i18n-values="dir:textdirection">
 <head>
-<meta name="viewport" content="width=device-width, initial-scale=1.0,
-                               maximum-scale=1.0, user-scalable=no">
-<title i18n-content="title">
-</title>
-<style>
-
-body {
-  background-color: #E6E6E6;
-  font-family: Helvetica, Arial, sans-serif;
-  font-size: 10pt;
-  margin: 50px 40px 20px 40px;
-  text-align: center;
-}
-
-#main-frame-error {
-  margin: auto;
-  max-width: 540px;
-  min-width: 200px;
-}
-
-/* Don't use the main frame div when the error is in a subframe. */
-html[subframe] #main-frame-error {
-  display: none;
-}
-
-/* Don't use the subframe error div when the error is in a main frame. */
-html:not([subframe]) #sub-frame-error {
-  display: none;
-}
-
-#box {
-  background-color: #fbfbfb;
-  border: 1px solid #AAA;
-  border-bottom: 1px solid #888;
-  border-radius: 3px;
-  color: black;
-<if expr="not is_android and not pp_ifdef('ios')">
-  /* Not done on mobile for performance reasons. */
-  box-shadow: 0px 2px 2px #AAA;
-</if>
-}
-
-#diagnose-button {
-  margin-top: 20px;
-  margin-bottom: 10px;
-  -webkit-margin-start: 0px;
-}
-
-h1 {
-  color: #666;
-  margin: 10px 0px 25px 0px;
-  font-weight: normal;
-  font-size: 1.5em;
-}
-
-a {
-  color: #15c;
-  text-decoration: none;
-}
-
-.icon {
-  -webkit-user-select: none;
-}
-
-.icon-generic {
-  /**
-   * Can't access chrome://theme/IDR_ERROR_NETWORK_GENERIC from an untrusted
-   * renderer process, so embed the resource manually.
-   */
-  content: -webkit-image-set(
-      url('../../app/theme/default_100_percent/common/error_network_generic.png') 1x,
-      url('../../app/theme/default_200_percent/common/error_network_generic.png') 2x);
-}
-
-.icon-offline {
-  content: -webkit-image-set(
-      url('../../app/theme/default_100_percent/common/error_network_offline.png') 1x,
-      url('../../app/theme/default_200_percent/common/error_network_offline.png') 2x);
-}
-
-#content-top {
-  margin: 20px 20px 20px 25px;
-}
-
-#help-box-outer {
-  overflow: hidden;
-  -webkit-transition: height ease-in 218ms;
-}
-
-#help-box-inner {
-  background-color: #f9f9f9;
-  border-top: 1px solid #EEE;
-  color: #444;
-  padding: 25px 20px;
-  text-align: start;
-}
-
-#suggestions {
-  margin-top: 15px;
-}
-
-#sub-frame-error-details {
-  color: #8F8F8F;
-<if expr="not is_android and not pp_ifdef('ios')">
-  /* Not done on mobile for performance reasons. */
-  text-shadow: 0 1px 0 rgba(255,255,255,0.3);
-</if>
-}
-
-[jscontent=failedUrl] {
-  overflow-wrap: break-word;
-}
-
-button {
-  border: 1px solid rgba(0, 0, 0, 0.25);
-  border-radius: 2px;
-  color: #444;
-  margin: 0px 5px;
-  min-height: 29px;
-  min-width: 65px;
-  -webkit-user-select: none;
-  padding: 8px 13px;
-<if expr="not is_android">
-  /* iOS does not support linear-gradient without a prefix. */
-  background-image: -webkit-linear-gradient(#ededed, #ededed 38%, #dedede);
-  text-shadow: 0 1px 0 rgb(240, 240, 240);
-</if>
-<if expr="is_android">
-  /* Android uses flat background colors. */
-  background-color: #ededed;
-  font-weight: bold;
-</if>
-<if expr="not is_android and not pp_ifdef('ios')">
-  /* Not done on mobile for performance reasons. */
-  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.75);
-</if>
-}
-
-button:hover {
-  border: 1px solid rgba(0, 0, 0, 0.3);
-  color: #000;
-<if expr="not is_android">
-  background-image: -webkit-linear-gradient(#f0f0f0, #f0f0f0 38%, #e0e0e0);
-</if>
-<if expr="is_android">
-  background-color: #f0f0f0;
-</if>
-<if expr="not is_android and not pp_ifdef('ios')">
-  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.95);
-</if>
-}
-
-button:active {
-  border: 1px solid rgba(0, 0, 0, 0.3);
-  color: #444;
-<if expr="not is_android">
-  background-image: -webkit-linear-gradient(#e7e7e7, #e7e7e7 38%, #d7d7d7);
-</if>
-<if expr="is_android">
-  background-color: #e7e7e7;
-</if>
-<if expr="not is_android and not pp_ifdef('ios')">
-  box-shadow: none;
-</if>
-}
-
-#reload-button {
-  color: #fff;
-<if expr="not is_android">
-  background-image: -webkit-linear-gradient(#5d9aff, #5d9aff 38%, #5891f0);
-  border: 1px solid rgba(45, 102, 195, 1);
-  text-shadow: 0 1px 0 rgba(0,0,0,0.5);
-</if>
-<if expr="is_android">
-  background-color: rgb(39, 180, 231);
-  border: 1px solid rgb(0, 152, 206);
-</if>
-<if expr="not is_android and not pp_ifdef('ios')">
-  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.15), inset 0 1px 2px rgba(255, 255, 255, 0.2);
-</if>
-}
-
-#reload-button:hover {
-<if expr="not is_android">
-  background-image: -webkit-linear-gradient(#659efd, #659efd 38%, #6097f1);
-  border: 1px solid rgba(45, 102, 195, 1);
-</if>
-<if expr="not is_android and not pp_ifdef('ios')">
-  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25), inset 0 1px 2px rgba(255, 255, 255, 0.2);
-</if>
-}
-
-#reload-button:active {
-<if expr="not is_android">
-  background-image: -webkit-linear-gradient(#6095ed, #6095ed 38%, #6095ed);
-  border: 1px solid rgb(38, 84, 160);
-</if>
-<if expr="is_android">
-  background-color: rgb(0, 152, 206);
-</if>
-<if expr="not is_android and not pp_ifdef('ios')">
-  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
-</if>
-}
-
-.hidden {
-  display: none;
-}
-
-.suggestions {
-  margin-top: 18px;
-}
-
-.suggestion-header {
-  font-weight: bold;
-  margin-bottom: 4px;
-}
-
-.suggestion-body {
-  color: #777;
-}
-
-.error-code {
-  color: #A0A0A0;
-  margin-top: 15px;
-}
-
-/* Increase line height at higher resolutions. */
-@media (min-width: 641px) and (min-height: 641px) {
-  #help-box-inner {
-    line-height: 18px;
-  }
-}
-
-/* Decrease padding at low sizes. */
-@media (max-width: 640px), (max-height: 640px) {
-  body {
-    margin: 15px;
-  }
-  h1 {
-    margin: 10px 0px 15px 0px;
-  }
-  #content-top {
-    margin: 15px;
-  }
-  #help-box-inner {
-    padding: 20px;
-  }
-  .suggestions {
-    margin-top: 10px;
-  }
-  .suggestion-header {
-    margin-bottom: 0px;
-  }
-  .error-code {
-    margin-top: 10px;
-  }
-}
-
-/* Don't allow overflow when in a subframe. */
-html[subframe] body {
-  overflow: hidden;
-}
-
-#sub-frame-error {
-  -webkit-align-items: center;
-  background-color: #DDD;
-  display: -webkit-flex;
-  -webkit-flex-flow: column;
-  height: 100%;
-  -webkit-justify-content: center;
-  left: 0px;
-  position: absolute;
-  top: 0px;
-  width: 100%;
-}
-
-#sub-frame-error:hover {
-  background-color: #EEE;
-}
-
-#sub-frame-error-details {
-  margin: 0 10px;
-  visibility: hidden;
-}
-
-/* Show details only when hovering. */
-#sub-frame-error:hover #sub-frame-error-details {
-  visibility: visible;
-}
-
-/* If the iframe is too small, always hide the error code. */
-/* TODO(mmenke): See if overflow: no-display works better, once supported. */
-@media (max-width: 200px), (max-height: 95px) {
-  #sub-frame-error-details {
-    display: none;
-  }
-}
-
-</style>
+  <meta name="viewport" content="width=device-width, initial-scale=1.0,
+                                 maximum-scale=1.0, user-scalable=no">
+  <title i18n-content="title"></title>
+  <link rel="stylesheet" href="neterror.css">
+  <script src="neterror.js"></script>
 </head>
 
-<script>
-
-function toggleHelpBox() {
-  var helpBoxOuter = document.getElementById('help-box-outer');
-  helpBoxOuter.classList.toggle('hidden');
-  var moreLessButton = document.getElementById('more-less-button');
-  if (helpBoxOuter.classList.contains('hidden')) {
-    moreLessButton.innerText = moreLessButton.moreText;
-  } else {
-    moreLessButton.innerText = moreLessButton.lessText;
-  }
-}
-
-function diagnoseErrors() {
-  var extension_id = "idddmepepmjcgiedknnmlbadcokidhoa";
-  var diagnose_frame = document.getElementById('diagnose-frame');
-  diagnose_frame.innerHTML =
-      '<iframe src="chrome-extension://' + extension_id +
-      '/index.html"></iframe>';
-
-}
-
-// Subframes use a different layout but the same html file.  This is to make it
-// easier to support platforms that load the error page via different
-// mechanisms (Currently just iOS).
-if (window.top.location != window.location)
-  document.documentElement.setAttribute('subframe', '');
-
-function updateForDnsProbe(strings) {
-  var context = new JsEvalContext(strings);
-  jstProcess(context, document.getElementById('help-box-outer'));
-  jstProcess(context, document.getElementById('details'));
-}
-
-<if expr="is_macosx or is_linux or is_android">
-//Re-orders buttons. Used on Mac, Linux, and Android, where reload should go on the right.
-function swapButtonOrder() {
-  reloadButton = document.getElementById('reload-button');
-  moreLessButton = document.getElementById('more-less-button');
-  reloadButton.parentNode.insertBefore(moreLessButton, reloadButton);
-}
-document.addEventListener("DOMContentLoaded", swapButtonOrder);
-</if>
-
-</script>
-
 <body id="t">
 <div id="main-frame-error">
  <div id="box">
diff --git a/chrome/renderer/resources/neterror.js b/chrome/renderer/resources/neterror.js
new file mode 100644
index 0000000..2dd8934
--- /dev/null
+++ b/chrome/renderer/resources/neterror.js
@@ -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.
+
+function toggleHelpBox() {
+  var helpBoxOuter = document.getElementById('help-box-outer');
+  helpBoxOuter.classList.toggle('hidden');
+  var moreLessButton = document.getElementById('more-less-button');
+  if (helpBoxOuter.classList.contains('hidden')) {
+    moreLessButton.innerText = moreLessButton.moreText;
+  } else {
+    moreLessButton.innerText = moreLessButton.lessText;
+  }
+}
+
+function diagnoseErrors() {
+  var extension_id = "idddmepepmjcgiedknnmlbadcokidhoa";
+  var diagnose_frame = document.getElementById('diagnose-frame');
+  diagnose_frame.innerHTML =
+      '<iframe src="chrome-extension://' + extension_id +
+      '/index.html"></iframe>';
+}
+
+// Subframes use a different layout but the same html file.  This is to make it
+// easier to support platforms that load the error page via different
+// mechanisms (Currently just iOS).
+if (window.top.location != window.location)
+  document.documentElement.setAttribute('subframe', '');
+
+function updateForDnsProbe(strings) {
+  var context = new JsEvalContext(strings);
+  jstProcess(context, document.getElementById('help-box-outer'));
+  jstProcess(context, document.getElementById('details'));
+}
+
+<if expr="is_macosx or is_ios or is_linux or is_android">
+// Re-orders buttons. Used on Mac, Linux, and Android, where reload should go
+// on the right.
+function swapButtonOrder() {
+  reloadButton = document.getElementById('reload-button');
+  moreLessButton = document.getElementById('more-less-button');
+  reloadButton.parentNode.insertBefore(moreLessButton, reloadButton);
+}
+document.addEventListener("DOMContentLoaded", swapButtonOrder);
+</if>
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc
index 05f5570..ad5d08b 100644
--- a/chrome/renderer/searchbox/searchbox.cc
+++ b/chrome/renderer/searchbox/searchbox.cc
@@ -158,9 +158,9 @@
 SearchBox::~SearchBox() {
 }
 
-void SearchBox::CountMouseover() {
-  render_view()->Send(new ChromeViewHostMsg_CountMouseover(
-      render_view()->GetRoutingID(), render_view()->GetPageId()));
+void SearchBox::LogEvent(NTPLoggingEventType event) {
+  render_view()->Send(new ChromeViewHostMsg_LogEvent(
+      render_view()->GetRoutingID(), render_view()->GetPageId(), event));
 }
 
 void SearchBox::DeleteMostVisitedItem(
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h
index 685c3cb..267c190 100644
--- a/chrome/renderer/searchbox/searchbox.h
+++ b/chrome/renderer/searchbox/searchbox.h
@@ -11,6 +11,7 @@
 #include "base/strings/string16.h"
 #include "chrome/common/instant_restricted_id_cache.h"
 #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"
@@ -28,8 +29,8 @@
   explicit SearchBox(content::RenderView* render_view);
   virtual ~SearchBox();
 
-  // Sends ChromeViewHostMsg_CountMouseover to the browser.
-  void CountMouseover();
+  // Sends ChromeViewHostMsg_LogEvent to the browser.
+  void LogEvent(NTPLoggingEventType event);
 
   // Sends ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem to the browser.
   void DeleteMostVisitedItem(InstantRestrictedID most_visited_item_id);
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index 75663b7..39c780d 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -12,6 +12,7 @@
 #include "chrome/common/autocomplete_match_type.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/instant_types.h"
+#include "chrome/common/ntp_logging_events.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/renderer/searchbox/searchbox.h"
 #include "content/public/renderer/render_view.h"
@@ -808,17 +809,16 @@
       GURL(chrome::kChromeSearchMostVisitedUrl));
   if (!render_view) return;
 
-  if (args.Length() < 1 || !args[0]->IsString())
+  if (args.Length() < 1 || !args[0]->IsNumber())
     return;
 
   DVLOG(1) << render_view << " LogEvent";
 
-  std::string histogram_name = *v8::String::Utf8Value(args[0]->ToString());
-
-  if (histogram_name == "NewTabPage.NumberOfMouseOvers")
-    SearchBox::Get(render_view)->CountMouseover();
-  else
-    DVLOG(1) << render_view << " Unsupported histogram name";
+  if (args[0]->Uint32Value() < NTP_NUM_EVENT_TYPES) {
+    NTPLoggingEventType event =
+        static_cast<NTPLoggingEventType>(args[0]->Uint32Value());
+    SearchBox::Get(render_view)->LogEvent(event);
+  }
 }
 
 // static
diff --git a/chrome/renderer/translate/translate_helper.cc b/chrome/renderer/translate/translate_helper.cc
index d4c5415..ee73f02 100644
--- a/chrome/renderer/translate/translate_helper.cc
+++ b/chrome/renderer/translate/translate_helper.cc
@@ -5,7 +5,6 @@
 #include "chrome/renderer/translate/translate_helper.h"
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
@@ -13,10 +12,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/translate/language_detection_util.h"
 #include "chrome/common/translate/translate_common_metrics.h"
+#include "chrome/common/translate/translate_util.h"
 #include "chrome/renderer/extensions/extension_groups.h"
 #include "chrome/renderer/isolated_world_ids.h"
 #include "content/public/renderer/render_view.h"
@@ -62,9 +61,6 @@
 // Isolated world sets following content-security-policy.
 const char kContentSecurityPolicy[] = "script-src 'self' 'unsafe-eval'";
 
-// Isolated world sets following security-origin by default.
-const char kSecurityOrigin[] = "https://translate.googleapis.com";
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -357,15 +353,10 @@
         chrome::ISOLATED_WORLD_ID_TRANSLATE,
         WebString::fromUTF8(kContentSecurityPolicy));
 
-    std::string security_origin(kSecurityOrigin);
-    CommandLine* command_line = CommandLine::ForCurrentProcess();
-    if (command_line->HasSwitch(switches::kTranslateSecurityOrigin)) {
-      security_origin =
-          command_line->GetSwitchValueASCII(switches::kTranslateSecurityOrigin);
-    }
+    GURL security_origin = TranslateUtil::GetTranslateSecurityOrigin();
     frame->setIsolatedWorldSecurityOrigin(
         chrome::ISOLATED_WORLD_ID_TRANSLATE,
-        WebSecurityOrigin::create(GURL(security_origin)));
+        WebSecurityOrigin::create(security_origin));
   }
 
   if (!IsTranslateLibAvailable()) {
diff --git a/chrome/renderer/web_apps.cc b/chrome/renderer/web_apps.cc
index bae800a..b5c3395 100644
--- a/chrome/renderer/web_apps.cc
+++ b/chrome/renderer/web_apps.cc
@@ -13,7 +13,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/common/json_schema/json_schema_validator.h"
 #include "chrome/common/web_application_info.h"
 #include "grit/common_resources.h"
 #include "grit/generated_resources.h"
diff --git a/chrome/sync_integration_tests.isolate b/chrome/sync_integration_tests.isolate
index 30fd0a5..5aa2463 100644
--- a/chrome/sync_integration_tests.isolate
+++ b/chrome/sync_integration_tests.isolate
@@ -14,7 +14,6 @@
         'isolate_dependency_tracked': [
           '../testing/test_env.py',
           '../testing/xvfb.py',
-          '<(PRODUCT_DIR)/chrome.pak',
           '<(PRODUCT_DIR)/chrome_100_percent.pak',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libppGoogleNaClPluginChrome.so',
@@ -44,11 +43,8 @@
     }],
     ['OS=="linux" or OS=="mac" or OS=="win"', {
       'variables': {
-        'isolate_dependency_tracked': [
-          '../tools/swarm_client/run_isolated.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
-        ],
         'isolate_dependency_untracked': [
+          '../tools/swarm_client/',
           '<(PRODUCT_DIR)/pyproto/',
         ],
       },
diff --git a/chrome/test/base/chrome_render_view_test.cc b/chrome/test/base/chrome_render_view_test.cc
index b642275..545a4f5 100644
--- a/chrome/test/base/chrome_render_view_test.cc
+++ b/chrome/test/base/chrome_render_view_test.cc
@@ -13,7 +13,9 @@
 #include "chrome/renderer/extensions/event_bindings.h"
 #include "chrome/renderer/extensions/extension_custom_bindings.h"
 #include "chrome/renderer/spellchecker/spellcheck.h"
+#include "components/autofill/content/renderer/autofill_agent.h"
 #include "components/autofill/content/renderer/password_autofill_agent.h"
+#include "components/autofill/content/renderer/test_password_autofill_agent.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/renderer/render_view.h"
@@ -64,7 +66,7 @@
   // RenderView doesn't expose its PasswordAutofillAgent or AutofillAgent
   // objects, because it has no need to store them directly (they're stored as
   // RenderViewObserver*).  So just create another set.
-  password_autofill_ = new PasswordAutofillAgent(view_);
+  password_autofill_ = new autofill::TestPasswordAutofillAgent(view_);
   autofill_agent_ = new AutofillAgent(view_, password_autofill_);
 }
 
diff --git a/chrome/test/base/chrome_render_view_test.h b/chrome/test/base/chrome_render_view_test.h
index 056f626..a1002d1 100644
--- a/chrome/test/base/chrome_render_view_test.h
+++ b/chrome/test/base/chrome_render_view_test.h
@@ -9,12 +9,11 @@
 
 #include "chrome/renderer/chrome_content_renderer_client.h"
 #include "chrome/renderer/chrome_mock_render_thread.h"
-#include "components/autofill/content/renderer/autofill_agent.h"
 #include "content/public/test/render_view_test.h"
 
 namespace autofill {
 class AutofillAgent;
-class PasswordAutofillAgent;
+class TestPasswordAutofillAgent;
 }
 
 namespace extensions {
@@ -34,7 +33,7 @@
   chrome::ChromeContentRendererClient chrome_content_renderer_client_;
   extensions::Dispatcher* extension_dispatcher_;
 
-  autofill::PasswordAutofillAgent* password_autofill_;
+  autofill::TestPasswordAutofillAgent* password_autofill_;
   autofill::AutofillAgent* autofill_agent_;
 
   // Naked pointer as ownership is with content::RenderViewTest::render_thread_.
diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h
index 6786342..8545846 100644
--- a/chrome/test/base/in_process_browser_test.h
+++ b/chrome/test/base/in_process_browser_test.h
@@ -14,10 +14,6 @@
 #include "content/public/test/browser_test_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/cros/network_library.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace base {
 #if defined(OS_MACOSX)
 namespace mac {
@@ -217,10 +213,6 @@
   // not ensure that Browsers are only created on the tested desktop).
   bool multi_desktop_test_;
 
-#if defined(OS_CHROMEOS)
-  chromeos::ScopedStubNetworkLibraryEnabler stub_network_library_enabler_;
-#endif  // defined(OS_CHROMEOS)
-
 #if defined(OS_MACOSX)
   base::mac::ScopedNSAutoreleasePool* autorelease_pool_;
 #endif  // OS_MACOSX
diff --git a/chrome/test/base/scoped_browser_locale.cc b/chrome/test/base/scoped_browser_locale.cc
new file mode 100644
index 0000000..c1538a1
--- /dev/null
+++ b/chrome/test/base/scoped_browser_locale.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 "chrome/test/base/scoped_browser_locale.h"
+
+#include "chrome/browser/browser_process.h"
+
+ScopedBrowserLocale::ScopedBrowserLocale(const std::string& new_locale)
+      : old_locale_(g_browser_process->GetApplicationLocale()) {
+  g_browser_process->SetApplicationLocale(new_locale);
+}
+
+ScopedBrowserLocale::~ScopedBrowserLocale() {
+  g_browser_process->SetApplicationLocale(old_locale_);
+}
diff --git a/chrome/test/base/scoped_browser_locale.h b/chrome/test/base/scoped_browser_locale.h
new file mode 100644
index 0000000..0f49b8c
--- /dev/null
+++ b/chrome/test/base/scoped_browser_locale.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_TEST_BASE_SCOPED_BROWSER_LOCALE_H_
+#define CHROME_TEST_BASE_SCOPED_BROWSER_LOCALE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+// Helper class to temporarily set the locale of the browser process.
+class ScopedBrowserLocale {
+ public:
+  explicit ScopedBrowserLocale(const std::string& new_locale);
+  ~ScopedBrowserLocale();
+
+ private:
+  const std::string old_locale_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedBrowserLocale);
+};
+
+#endif  // CHROME_TEST_BASE_SCOPED_BROWSER_LOCALE_H_
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 7147058..40cff07 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -70,8 +70,7 @@
   virtual LocationBar* GetLocationBar() const OVERRIDE;
   virtual void SetFocusToLocationBar(bool select_all) OVERRIDE {}
   virtual void UpdateReloadStopState(bool is_loading, bool force) OVERRIDE {}
-  virtual void UpdateToolbar(content::WebContents* contents,
-                             bool should_restore_state) OVERRIDE {}
+  virtual void UpdateToolbar(content::WebContents* contents) OVERRIDE {}
   virtual void FocusToolbar() OVERRIDE {}
   virtual void FocusAppMenu() OVERRIDE {}
   virtual void FocusBookmarksToolbar() OVERRIDE {}
@@ -107,7 +106,11 @@
 #endif
   virtual bool IsDownloadShelfVisible() const OVERRIDE;
   virtual DownloadShelf* GetDownloadShelf() OVERRIDE;
-  virtual void ConfirmBrowserCloseWithPendingDownloads() OVERRIDE {}
+  virtual void ConfirmBrowserCloseWithPendingDownloads(
+      int download_count,
+      Browser::DownloadClosePreventionType dialog_type,
+      bool app_modal,
+      const base::Callback<void(bool)>& callback) OVERRIDE {}
   virtual void UserChangedTheme() OVERRIDE {}
   virtual int GetExtraRenderViewHeight() const OVERRIDE;
   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE {}
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 318c14c..f53c423 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -167,6 +167,7 @@
     : start_time_(Time::Now()),
       testing_prefs_(NULL),
       incognito_(false),
+      force_incognito_(false),
       original_profile_(NULL),
       last_session_exited_cleanly_(true),
       browser_context_dependency_manager_(
@@ -184,6 +185,7 @@
     : start_time_(Time::Now()),
       testing_prefs_(NULL),
       incognito_(false),
+      force_incognito_(false),
       original_profile_(NULL),
       last_session_exited_cleanly_(true),
       profile_path_(path),
@@ -200,6 +202,7 @@
     : start_time_(Time::Now()),
       testing_prefs_(NULL),
       incognito_(false),
+      force_incognito_(false),
       original_profile_(NULL),
       last_session_exited_cleanly_(true),
       profile_path_(path),
@@ -221,11 +224,14 @@
     const base::FilePath& path,
     Delegate* delegate,
     scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy,
-    scoped_ptr<PrefServiceSyncable> prefs)
+    scoped_ptr<PrefServiceSyncable> prefs,
+    bool incognito,
+    const TestingFactories& factories)
     : start_time_(Time::Now()),
       prefs_(prefs.release()),
       testing_prefs_(NULL),
-      incognito_(false),
+      incognito_(incognito),
+      force_incognito_(false),
       original_profile_(NULL),
       last_session_exited_cleanly_(true),
       extension_special_storage_policy_(extension_policy),
@@ -241,6 +247,12 @@
     profile_path_ = temp_dir_.path();
   }
 
+  // Set any testing factories prior to initializing the services.
+  for (TestingFactories::const_iterator it = factories.begin();
+       it != factories.end(); ++it) {
+    it->first->SetTestingFactory(this, it->second);
+  }
+
   Init();
   // If caller supplied a delegate, delay the FinishInit invocation until other
   // tasks have run.
@@ -309,7 +321,11 @@
   extensions::ExtensionSystemFactory::GetInstance()->SetTestingFactory(
       this, extensions::TestExtensionSystem::Build);
 
-  browser_context_dependency_manager_->CreateBrowserContextServices(this, true);
+  // If there is no separate original profile specified for this profile, then
+  // force preferences to be registered - this allows tests to create a
+  // standalone incognito profile while still having prefs registered.
+  browser_context_dependency_manager_->CreateBrowserContextServicesForTest(
+      this, !original_profile_);
 
 #if defined(ENABLE_NOTIFICATIONS)
   // Install profile keyed service factory hooks for dummy/test services
@@ -330,6 +346,9 @@
 }
 
 TestingProfile::~TestingProfile() {
+  // Revert to non-incognito mode before shutdown.
+  force_incognito_ = false;
+
   // Any objects holding live URLFetchers should be deleted before teardown.
   TemplateURLFetcherFactory::ShutdownForProfile(this);
 
@@ -497,8 +516,6 @@
   content::WindowedNotificationObserver top_sites_loaded_observer(
       chrome::NOTIFICATION_TOP_SITES_LOADED,
       content::NotificationService::AllSources());
-  if (!HistoryServiceFactory::GetForProfile(this, Profile::EXPLICIT_ACCESS))
-    GetTopSites()->HistoryLoaded();
   top_sites_loaded_observer.Wait();
 }
 
@@ -526,18 +543,22 @@
 }
 
 bool TestingProfile::IsOffTheRecord() const {
-  return incognito_;
+  return force_incognito_ || incognito_;
 }
 
-void TestingProfile::SetOffTheRecordProfile(Profile* profile) {
-  incognito_profile_.reset(profile);
+void TestingProfile::SetOffTheRecordProfile(scoped_ptr<Profile> profile) {
+  DCHECK(!IsOffTheRecord());
+  incognito_profile_ = profile.Pass();
 }
 
 void TestingProfile::SetOriginalProfile(Profile* profile) {
+  DCHECK(IsOffTheRecord());
   original_profile_ = profile;
 }
 
 Profile* TestingProfile::GetOffTheRecordProfile() {
+  if (IsOffTheRecord())
+    return this;
   return incognito_profile_.get();
 }
 
@@ -552,8 +573,7 @@
 }
 
 bool TestingProfile::IsManaged() {
-  return GetPrefs()->GetBoolean(prefs::kProfileIsManaged) ||
-      !GetPrefs()->GetString(prefs::kManagedUserId).empty();
+  return !GetPrefs()->GetString(prefs::kManagedUserId).empty();
 }
 
 ExtensionService* TestingProfile::GetExtensionService() {
@@ -797,7 +817,8 @@
 
 TestingProfile::Builder::Builder()
     : build_called_(false),
-      delegate_(NULL) {
+      delegate_(NULL),
+      incognito_(false) {
 }
 
 TestingProfile::Builder::~Builder() {
@@ -821,6 +842,16 @@
   pref_service_ = prefs.Pass();
 }
 
+void TestingProfile::Builder::SetIncognito() {
+  incognito_ = true;
+}
+
+void TestingProfile::Builder::AddTestingFactory(
+    BrowserContextKeyedServiceFactory* service_factory,
+    BrowserContextKeyedServiceFactory::FactoryFunction callback) {
+  testing_factories_.push_back(std::make_pair(service_factory, callback));
+}
+
 scoped_ptr<TestingProfile> TestingProfile::Builder::Build() {
   DCHECK(!build_called_);
   build_called_ = true;
@@ -828,5 +859,7 @@
       path_,
       delegate_,
       extension_policy_,
-      pref_service_.Pass()));
+      pref_service_.Pass(),
+      incognito_,
+      testing_factories_));
 }
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 8e63e5a..03c95d4 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
 
 namespace content {
 class MockResourceContext;
@@ -59,6 +60,10 @@
   // Default constructor that cannot be used with multi-profiles.
   TestingProfile();
 
+  typedef std::vector<std::pair<
+      BrowserContextKeyedServiceFactory*,
+      BrowserContextKeyedServiceFactory::FactoryFunction> > TestingFactories;
+
   // Helper class for building an instance of TestingProfile (allows injecting
   // mocks for various services prior to profile initialization).
   // TODO(atwilson): Remove non-default constructors and various setters in
@@ -68,13 +73,19 @@
     Builder();
     ~Builder();
 
-    // Sets a Delegate to be called back when the Profile is fully initialized.
-    // This causes the final initialization to be performed via a task so the
-    // caller must run a MessageLoop. Caller maintains ownership of the Delegate
+    // Sets a Delegate to be called back during profile init. This causes the
+    // final initialization to be performed via a task so the caller must run
+    // a MessageLoop. Caller maintains ownership of the Delegate
     // and must manage its lifetime so it continues to exist until profile
     // initialization is complete.
     void SetDelegate(Delegate* delegate);
 
+    // Adds a testing factory to the TestingProfile. These testing factories
+    // are applied before the ProfileKeyedServices are created.
+    void AddTestingFactory(
+        BrowserContextKeyedServiceFactory* service_factory,
+        BrowserContextKeyedServiceFactory::FactoryFunction callback);
+
     // Sets the ExtensionSpecialStoragePolicy to be returned by
     // GetExtensionSpecialStoragePolicy().
     void SetExtensionSpecialStoragePolicy(
@@ -86,6 +97,9 @@
     // Sets the PrefService to be used by this profile.
     void SetPrefService(scoped_ptr<PrefServiceSyncable> prefs);
 
+    // Makes the Profile being built an incognito profile.
+    void SetIncognito();
+
     // Creates the TestingProfile using previously-set settings.
     scoped_ptr<TestingProfile> Build();
 
@@ -98,6 +112,8 @@
     scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy_;
     base::FilePath path_;
     Delegate* delegate_;
+    bool incognito_;
+    TestingFactories testing_factories_;
 
     DISALLOW_COPY_AND_ASSIGN(Builder);
   };
@@ -120,7 +136,9 @@
   TestingProfile(const base::FilePath& path,
                  Delegate* delegate,
                  scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy,
-                 scoped_ptr<PrefServiceSyncable> prefs);
+                 scoped_ptr<PrefServiceSyncable> prefs,
+                 bool incognito,
+                 const TestingFactories& factories);
 
   virtual ~TestingProfile();
 
@@ -186,9 +204,26 @@
 
   virtual TestingProfile* AsTestingProfile() OVERRIDE;
   virtual std::string GetProfileName() OVERRIDE;
-  void set_incognito(bool incognito) { incognito_ = incognito; }
+
+  // DEPRECATED, because it's fragile to change a profile from non-incognito
+  // to incognito after the ProfileKeyedServices have been created (some
+  // ProfileKeyedServices either should not exist in incognito mode, or will
+  // crash when they try to get references to other services they depend on,
+  // but do not exist in incognito mode).
+  // TODO(atwilson): Remove this API (http://crbug.com/277296).
+  //
+  // Changes a profile's to/from incognito mode temporarily - profile will be
+  // returned to non-incognito before destruction to allow services to
+  // properly shutdown. This is only supported for legacy tests - new tests
+  // should create a true incognito profile using Builder::SetIncognito() or
+  // by using the TestingProfile constructor that allows setting the incognito
+  // flag.
+  void ForceIncognito(bool force_incognito) {
+    force_incognito_ = force_incognito;
+  }
+
   // Assumes ownership.
-  virtual void SetOffTheRecordProfile(Profile* profile);
+  virtual void SetOffTheRecordProfile(scoped_ptr<Profile> profile);
   virtual void SetOriginalProfile(Profile* profile);
   virtual Profile* GetOffTheRecordProfile() OVERRIDE;
   virtual void DestroyOffTheRecordProfile() OVERRIDE {}
@@ -306,6 +341,7 @@
   std::wstring id_;
 
   bool incognito_;
+  bool force_incognito_;
   scoped_ptr<Profile> incognito_profile_;
   Profile* original_profile_;
 
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc
index e6f4748..644760c 100644
--- a/chrome/test/base/testing_profile_manager.cc
+++ b/chrome/test/base/testing_profile_manager.cc
@@ -16,10 +16,10 @@
 
 namespace testing {
 
-class ProfileManager : public ::ProfileManager {
+class ProfileManager : public ::ProfileManagerWithoutInit {
  public:
   explicit ProfileManager(const base::FilePath& user_data_dir)
-      : ::ProfileManager(user_data_dir) {}
+      : ::ProfileManagerWithoutInit(user_data_dir) {}
 
  protected:
   virtual Profile* CreateProfileHelper(
@@ -57,11 +57,10 @@
   profile_path = profile_path.AppendASCII(profile_name);
 
   // Create the profile and register it.
-  TestingProfile* profile = new TestingProfile(
-      profile_path,
-      NULL,
-      scoped_refptr<ExtensionSpecialStoragePolicy>(),
-      prefs.Pass());
+  TestingProfile::Builder builder;
+  builder.SetPath(profile_path);
+  builder.SetPrefService(prefs.Pass());
+  TestingProfile* profile = builder.Build().release();
   profile_manager_->AddProfile(profile);  // Takes ownership.
 
   // Update the user metadata.
diff --git a/chrome/test/base/view_event_test_base.cc b/chrome/test/base/view_event_test_base.cc
index 4654a7e..c37fe93 100644
--- a/chrome/test/base/view_event_test_base.cc
+++ b/chrome/test/base/view_event_test_base.cc
@@ -36,6 +36,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/audio/cras_audio_handler.h"
+#include "chromeos/network/network_handler.h"
 #endif
 
 namespace {
@@ -116,6 +117,7 @@
   message_center::MessageCenter::Initialize();
 #if defined(OS_CHROMEOS)
   chromeos::CrasAudioHandler::InitializeForTesting();
+  chromeos::NetworkHandler::Initialize();
 #endif  // OS_CHROMEOS
   ash::test::TestShellDelegate* shell_delegate =
       new ash::test::TestShellDelegate();
@@ -150,6 +152,7 @@
 #else
   ash::Shell::DeleteInstance();
 #if defined(OS_CHROMEOS)
+  chromeos::NetworkHandler::Shutdown();
   chromeos::CrasAudioHandler::Shutdown();
 #endif
   // Ash Shell can't just live on its own without a browser process, we need to
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index f5f1a6b..b052f0f 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -182,6 +182,22 @@
   return Status(kOk);
 }
 
+Status ParseExcludeSwitches(const base::Value& option,
+                            Capabilities* capabilities) {
+  const base::ListValue* switches = NULL;
+  if (!option.GetAsList(&switches))
+    return Status(kUnknownError, "'excludeSwitches' must be a list");
+  for (size_t i = 0; i < switches->GetSize(); ++i) {
+    std::string switch_name;
+    if (!switches->GetString(i, &switch_name)) {
+      return Status(kUnknownError,
+                    "each switch to be removed must be a string");
+    }
+    capabilities->exclude_switches.insert(switch_name);
+  }
+  return Status(kOk);
+}
+
 Status ParseDesktopChromeCapabilities(
     Log* log,
     const base::Value& capability,
@@ -201,6 +217,7 @@
   parser_map["prefs"] = base::Bind(&ParsePrefs);
   parser_map["localState"] = base::Bind(&ParseLocalState);
   parser_map["extensions"] = base::Bind(&ParseExtensions);
+  parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches);
 
   for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd();
        it.Advance()) {
diff --git a/chrome/test/chromedriver/capabilities.h b/chrome/test/chromedriver/capabilities.h
index 2ef9bb0..c5e243e 100644
--- a/chrome/test/chromedriver/capabilities.h
+++ b/chrome/test/chromedriver/capabilities.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_TEST_CHROMEDRIVER_CAPABILITIES_H_
 #define CHROME_TEST_CHROMEDRIVER_CAPABILITIES_H_
 
+#include <set>
 #include <string>
 #include <vector>
 
@@ -45,6 +46,10 @@
   scoped_ptr<base::DictionaryValue> local_state;
   std::vector<std::string> extensions;
   scoped_ptr<base::DictionaryValue> logging_prefs;
+
+  // Set of switches which should be removed from default list when launching
+  // Chrome.
+  std::set<std::string> exclude_switches;
 };
 
 #endif  // CHROME_TEST_CHROMEDRIVER_CAPABILITIES_H_
diff --git a/chrome/test/chromedriver/capabilities_unittest.cc b/chrome/test/chromedriver/capabilities_unittest.cc
index c5294ee..7596468 100644
--- a/chrome/test/chromedriver/capabilities_unittest.cc
+++ b/chrome/test/chromedriver/capabilities_unittest.cc
@@ -317,3 +317,19 @@
   Status status = capabilities.Parse(caps, &log);
   ASSERT_FALSE(status.IsOk());
 }
+
+TEST(ParseCapabilities, ExcludeSwitches) {
+  Capabilities capabilities;
+  base::ListValue exclude_switches;
+  exclude_switches.AppendString("switch1");
+  exclude_switches.AppendString("switch2");
+  base::DictionaryValue caps;
+  caps.Set("chromeOptions.excludeSwitches", exclude_switches.DeepCopy());
+  Logger log(Log::kError);
+  Status status = capabilities.Parse(caps, &log);
+  ASSERT_TRUE(status.IsOk());
+  ASSERT_EQ(2u, capabilities.exclude_switches.size());
+  const std::set<std::string>& switches = capabilities.exclude_switches;
+  ASSERT_TRUE(switches.find("switch1") != switches.end());
+  ASSERT_TRUE(switches.find("switch2") != switches.end());
+}
diff --git a/chrome/test/chromedriver/chrome/adb_impl.cc b/chrome/test/chromedriver/chrome/adb_impl.cc
index 363790c..5432d18 100644
--- a/chrome/test/chromedriver/chrome/adb_impl.cc
+++ b/chrome/test/chromedriver/chrome/adb_impl.cc
@@ -62,9 +62,10 @@
 };
 
 void ExecuteCommandOnIOThread(
-    const std::string& command, scoped_refptr<ResponseBuffer> response_buffer) {
+    const std::string& command, scoped_refptr<ResponseBuffer> response_buffer,
+    int port) {
   CHECK(base::MessageLoop::current()->IsType(base::MessageLoop::TYPE_IO));
-  AdbClientSocket::AdbQuery(5037, command,
+  AdbClientSocket::AdbQuery(port, command,
       base::Bind(&ResponseBuffer::OnResponse, response_buffer));
 }
 
@@ -72,8 +73,8 @@
 
 AdbImpl::AdbImpl(
     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
-    Log* log)
-    : io_task_runner_(io_task_runner), log_(log) {
+    Log* log, int port)
+    : io_task_runner_(io_task_runner), log_(log), port_(port) {
   CHECK(io_task_runner_.get());
 }
 
@@ -165,8 +166,7 @@
   std::string response;
   Status status = ExecuteHostShellCommand(
       device_serial,
-      "am start -W -n " + package + "/" + activity +
-      " -d \"data:text/html;charset=utf-8,\"",
+      "am start -W -n " + package + "/" + activity + " -d about:blank",
       &response);
   if (!status.IsOk())
     return status;
@@ -221,7 +221,7 @@
   log_->AddEntry(Log::kDebug, "Sending adb command: " + command);
   io_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&ExecuteCommandOnIOThread, command, response_buffer));
+      base::Bind(&ExecuteCommandOnIOThread, command, response_buffer, port_));
   Status status = response_buffer->GetResponse(
       response, base::TimeDelta::FromSeconds(30));
   if (status.IsOk())
diff --git a/chrome/test/chromedriver/chrome/adb_impl.h b/chrome/test/chromedriver/chrome/adb_impl.h
index 155af1c..80ce305 100644
--- a/chrome/test/chromedriver/chrome/adb_impl.h
+++ b/chrome/test/chromedriver/chrome/adb_impl.h
@@ -23,7 +23,7 @@
  public:
   explicit AdbImpl(
       const scoped_refptr<base::SingleThreadTaskRunner>& io_message_loop_proxy,
-      Log* log);
+      Log* log, int port);
   virtual ~AdbImpl();
 
   // Overridden from Adb:
@@ -61,6 +61,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
   Log* log_;
+  int port_;
 };
 
 #endif  // CHROME_TEST_CHROMEDRIVER_CHROME_ADB_IMPL_H_
diff --git a/chrome/test/chromedriver/chrome/local_state.txt b/chrome/test/chromedriver/chrome/local_state.txt
index 75b3067..a0d20c1 100644
--- a/chrome/test/chromedriver/chrome/local_state.txt
+++ b/chrome/test/chromedriver/chrome/local_state.txt
@@ -1,4 +1,7 @@
 {
+   "background_mode": {
+      "enabled": false
+   },
    "ssl": {
       "rev_checking": {
          "enabled": false
diff --git a/chrome/test/chromedriver/chrome/preferences.txt b/chrome/test/chromedriver/chrome/preferences.txt
index 32f4cb1..1ad1f7a 100644
--- a/chrome/test/chromedriver/chrome/preferences.txt
+++ b/chrome/test/chromedriver/chrome/preferences.txt
@@ -2,6 +2,9 @@
    "alternate_error_pages": {
       "enabled": false
    },
+   "autofill": {
+      "enabled": false
+   },
    "browser": {
       "check_default_browser": false
    },
@@ -33,7 +36,8 @@
          "notifications": 1,
          "popups": 1,
          "ppapi-broker": 1
-      }
+      },
+      "password_manager_enabled": false
    },
    "safebrowsing": {
       "enabled": false
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index d151d5d..6987a26 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -64,6 +64,16 @@
   return Status(kOk);
 }
 
+void AddSwitches(CommandLine* command,
+                 const char* switches[],
+                 size_t switch_count,
+                 const std::set<std::string>& exclude_switches) {
+  for (size_t i = 0; i < switch_count; ++i) {
+    if (exclude_switches.find(switches[i]) == exclude_switches.end())
+      command->AppendSwitch(switches[i]);
+  }
+}
+
 Status PrepareCommandLine(int port,
                           const Capabilities& capabilities,
                           CommandLine* prepared_command,
@@ -81,13 +91,35 @@
                                      program.value().c_str()));
   }
 
-  command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port));
-  command.AppendSwitch("no-first-run");
+  const char* excludable_switches[] = {
+      "disable-hang-monitor",
+      "disable-prompt-on-repost",
+      "full-memory-crash-report",
+      "no-first-run",
+      "disable-background-networking",
+      // TODO(chrisgao): Add "disable-sync" when chrome 30- is not supported.
+      // For chrome 30-, it leads to crash when opening chrome://settings.
+      "disable-web-resources",
+      "safebrowsing-disable-auto-update",
+      "safebrowsing-disable-download-protection",
+      "disable-client-side-phishing-detection",
+      "disable-component-update",
+      "disable-default-apps",
+  };
+
+  AddSwitches(&command, excludable_switches, arraysize(excludable_switches),
+              capabilities.exclude_switches);
+  AddSwitches(&command, kCommonSwitches, arraysize(kCommonSwitches),
+              capabilities.exclude_switches);
+
   command.AppendSwitch("enable-logging");
   command.AppendSwitchASCII("logging-level", "1");
-  command.AppendArg("data:text/html;charset=utf-8,");
+  command.AppendSwitchASCII("password-store", "basic");
+  command.AppendSwitch("use-mock-keychain");
+  command.AppendSwitchASCII("remote-debugging-port", base::IntToString(port));
 
   if (!command.HasSwitch("user-data-dir")) {
+    command.AppendArg("about:blank");
     if (!user_data_dir->CreateUniqueTempDir())
       return Status(kUnknownError, "cannot create temp dir for user data dir");
     command.AppendSwitchPath("user-data-dir", user_data_dir->path());
@@ -156,8 +188,6 @@
   if (status.IsError())
     return status;
 
-  for (size_t i = 0; i < arraysize(kCommonSwitches); i++)
-    command.AppendSwitch(kCommonSwitches[i]);
   base::LaunchOptions options;
 
 #if !defined(OS_WIN)
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index a0fe44a..ac5c478 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -217,6 +217,15 @@
   def MouseDoubleClick(self, button=0):
     self.ExecuteCommand(Command.MOUSE_DOUBLE_CLICK, {'button': button})
 
+  def TouchDown(self, x, y):
+    self.ExecuteCommand(Command.TOUCH_DOWN, {'x': x, 'y': y})
+
+  def TouchUp(self, x, y):
+    self.ExecuteCommand(Command.TOUCH_UP, {'x': x, 'y': y})
+
+  def TouchMove(self, x, y):
+    self.ExecuteCommand(Command.TOUCH_MOVE, {'x': x, 'y': y})
+
   def GetCookies(self):
     return self.ExecuteCommand(Command.GET_COOKIES)
 
diff --git a/chrome/test/chromedriver/client/webelement.py b/chrome/test/chromedriver/client/webelement.py
index a5a706a..b3e6a64 100644
--- a/chrome/test/chromedriver/client/webelement.py
+++ b/chrome/test/chromedriver/client/webelement.py
@@ -45,3 +45,6 @@
       for i in range(len(value)):
         typing.append(value[i])
     self._Execute(Command.SEND_KEYS_TO_ELEMENT, {'value': typing})
+
+  def GetLocation(self):
+    return self._Execute(Command.GET_ELEMENT_LOCATION)
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index 008c086..81e83a3 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -33,6 +33,7 @@
     const std::string& element_id,
     const ListValue* key_list) {
   bool is_displayed = false;
+  bool is_focused = false;
   base::Time start_time = base::Time::Now();
   while (true) {
     Status status = IsElementDisplayed(
@@ -41,25 +42,35 @@
       return status;
     if (is_displayed)
       break;
+    status = IsElementFocused(session, web_view, element_id, &is_focused);
+    if (status.IsError())
+      return status;
+    if (is_focused)
+      break;
     if ((base::Time::Now() - start_time).InMilliseconds() >=
         session->implicit_wait) {
       return Status(kElementNotVisible);
     }
     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
   }
+
   bool is_enabled = false;
   Status status = IsElementEnabled(session, web_view, element_id, &is_enabled);
   if (status.IsError())
     return status;
   if (!is_enabled)
     return Status(kInvalidElementState);
-  base::ListValue args;
-  args.Append(CreateElement(element_id));
-  scoped_ptr<base::Value> result;
-  status = web_view->CallFunction(
-      session->GetCurrentFrameId(), kFocusScript, args, &result);
-  if (status.IsError())
-    return status;
+
+  if (!is_focused) {
+    base::ListValue args;
+    args.Append(CreateElement(element_id));
+    scoped_ptr<base::Value> result;
+    status = web_view->CallFunction(
+        session->GetCurrentFrameId(), kFocusScript, args, &result);
+    if (status.IsError())
+      return status;
+  }
+
   return SendKeysOnWindow(web_view, key_list, true, &session->sticky_modifiers);
 }
 
diff --git a/chrome/test/chromedriver/element_util.cc b/chrome/test/chromedriver/element_util.cc
index ccf5409..6c4bca0 100644
--- a/chrome/test/chromedriver/element_util.cc
+++ b/chrome/test/chromedriver/element_util.cc
@@ -286,6 +286,32 @@
   return Status(kUnknownError);
 }
 
+Status GetActiveElement(
+    Session* session,
+    WebView* web_view,
+    scoped_ptr<base::Value>* value) {
+  base::ListValue args;
+  return web_view->CallFunction(
+      session->GetCurrentFrameId(),
+      "function() { return document.activeElement || document.body }",
+      args,
+      value);
+}
+
+Status IsElementFocused(
+    Session* session,
+    WebView* web_view,
+    const std::string& element_id,
+    bool* is_focused) {
+  scoped_ptr<base::Value> result;
+  Status status = GetActiveElement(session, web_view, &result);
+  if (status.IsError())
+    return status;
+  scoped_ptr<base::Value> element_dict(CreateElement(element_id));
+  *is_focused = result->Equals(element_dict.get());
+  return Status(kOk);
+}
+
 Status GetElementAttribute(
     Session* session,
     WebView* web_view,
diff --git a/chrome/test/chromedriver/element_util.h b/chrome/test/chromedriver/element_util.h
index 86bb2d1..0fbd766 100644
--- a/chrome/test/chromedriver/element_util.h
+++ b/chrome/test/chromedriver/element_util.h
@@ -34,6 +34,17 @@
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value);
 
+Status GetActiveElement(
+    Session* session,
+    WebView* web_view,
+    scoped_ptr<base::Value>* value);
+
+Status IsElementFocused(
+    Session* session,
+    WebView* web_view,
+    const std::string& element_id,
+    bool* is_focused);
+
 Status GetElementAttribute(
     Session* session,
     WebView* web_view,
diff --git a/chrome/test/chromedriver/run_buildbot_steps.py b/chrome/test/chromedriver/run_buildbot_steps.py
index af4a10b..2b1765d 100755
--- a/chrome/test/chromedriver/run_buildbot_steps.py
+++ b/chrome/test/chromedriver/run_buildbot_steps.py
@@ -178,18 +178,19 @@
 def main():
   parser = optparse.OptionParser()
   parser.add_option(
-      '', '--android-package',
-      help='Application package name, if running tests on Android.')
+      '', '--android-packages',
+      help='Comma separated list of application package names, '
+           'if running tests on Android.')
   parser.add_option(
       '-r', '--revision', type='string', default=None,
       help='Chromium revision')
   options, _ = parser.parse_args()
 
-  if not options.android_package:
+  if not options.android_packages:
     KillChromes()
   CleanTmpDir()
 
-  if options.android_package:
+  if options.android_packages:
     Download()
   else:
     if not options.revision:
@@ -204,12 +205,12 @@
       sys.executable,
       os.path.join(_THIS_DIR, 'test', 'run_all_tests.py'),
   ]
-  if options.android_package:
-    cmd.append('--android-package=' + options.android_package)
+  if options.android_packages:
+    cmd.append('--android-packages=' + options.android_packages)
 
   passed = (util.RunCommand(cmd) == 0)
 
-  if not options.android_package and passed:
+  if not options.android_packages and passed:
     MaybeRelease(options.revision)
 
 
diff --git a/chrome/test/chromedriver/server/chromedriver_server.cc b/chrome/test/chromedriver/server/chromedriver_server.cc
index c036814..6c40247 100644
--- a/chrome/test/chromedriver/server/chromedriver_server.cc
+++ b/chrome/test/chromedriver/server/chromedriver_server.cc
@@ -139,7 +139,8 @@
   lazy_tls_server.Pointer()->Set(temp_server.release());
 }
 
-void RunServer(Log::Level log_level, int port, const std::string& url_base) {
+void RunServer(Log::Level log_level, int port, const std::string& url_base,
+               int adb_port) {
   base::Thread io_thread("ChromeDriver IO");
   CHECK(io_thread.StartWithOptions(
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
@@ -150,7 +151,8 @@
   HttpHandler handler(cmd_run_loop.QuitClosure(),
                       io_thread.message_loop_proxy(),
                       &log,
-                      url_base);
+                      url_base,
+                      adb_port);
   HttpRequestHandlerFunc handle_request_func =
       base::Bind(&HandleRequestOnCmdThread, &handler);
 
@@ -181,6 +183,7 @@
 
   // Parse command line flags.
   int port = 9515;
+  int adb_port = 5037;
   std::string url_base;
   base::FilePath log_path;
   Log::Level log_level = Log::kError;
@@ -188,6 +191,7 @@
     std::string options;
     const char* kOptionAndDescriptions[] = {
         "port=PORT", "port to listen on",
+        "adb-port=PORT", "adb server port",
         "log-path=FILE", "write server log to file instead of stderr, "
             "increases log level to INFO",
         "verbose", "log verbosely",
@@ -208,6 +212,13 @@
       return 1;
     }
   }
+  if (cmd_line->HasSwitch("adb-port")) {
+    if (!base::StringToInt(cmd_line->GetSwitchValueASCII("adb-port"),
+                           &adb_port)) {
+      printf("Invalid adb-port. Exiting...\n");
+      return 1;
+    }
+  }
   if (cmd_line->HasSwitch("url-base"))
     url_base = cmd_line->GetSwitchValueASCII("url-base");
   if (url_base.empty() || url_base[0] != '/')
@@ -255,6 +266,6 @@
   if (!cmd_line->HasSwitch("verbose"))
     logging::SetMinLogLevel(logging::LOG_FATAL);
 
-  RunServer(log_level, port, url_base);
+  RunServer(log_level, port, url_base, adb_port);
   return 0;
 }
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index e619ce7..1211bbc 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -67,7 +67,8 @@
     const base::Closure& quit_func,
     const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     Log* log,
-    const std::string& url_base)
+    const std::string& url_base,
+    int adb_port)
     : quit_func_(quit_func),
       log_(log),
       url_base_(url_base),
@@ -78,7 +79,7 @@
 #endif
   context_getter_ = new URLRequestContextGetter(io_task_runner);
   socket_factory_ = CreateSyncWebSocketFactory(context_getter_.get());
-  adb_.reset(new AdbImpl(io_task_runner, log_));
+  adb_.reset(new AdbImpl(io_task_runner, log_, adb_port));
   device_manager_.reset(new DeviceManager(adb_.get()));
 
   CommandMapping commands[] = {
@@ -395,13 +396,13 @@
                      WrapToCommand(base::Bind(&ExecuteTouchSingleTap))),
       CommandMapping(kPost,
                      "session/:sessionId/touch/down",
-                     base::Bind(&UnimplementedCommand)),
+                     WrapToCommand(base::Bind(&ExecuteTouchDown))),
       CommandMapping(kPost,
                      "session/:sessionId/touch/up",
-                     base::Bind(&UnimplementedCommand)),
+                     WrapToCommand(base::Bind(&ExecuteTouchUp))),
       CommandMapping(kPost,
                      "session/:sessionId/touch/move",
-                     base::Bind(&UnimplementedCommand)),
+                     WrapToCommand(base::Bind(&ExecuteTouchMove))),
       CommandMapping(kPost,
                      "session/:sessionId/touch/scroll",
                      base::Bind(&UnimplementedCommand)),
diff --git a/chrome/test/chromedriver/server/http_handler.h b/chrome/test/chromedriver/server/http_handler.h
index 7332554..1329831 100644
--- a/chrome/test/chromedriver/server/http_handler.h
+++ b/chrome/test/chromedriver/server/http_handler.h
@@ -64,7 +64,8 @@
   HttpHandler(const base::Closure& quit_func,
               const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
               Log* log,
-              const std::string& url_base);
+              const std::string& url_base,
+              int adb_port);
   ~HttpHandler();
 
   void Handle(const net::HttpServerRequestInfo& request,
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py
index 7236c86..d8d6852 100755
--- a/chrome/test/chromedriver/test/run_all_tests.py
+++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -65,7 +65,7 @@
                    chrome_version_name=None, android_package=None):
   version_info = ''
   if chrome_version_name:
-    version_info = '(v%s)' % chrome_version_name
+    version_info = '(%s)' % chrome_version_name
   util.MarkBuildStepStart('python_tests%s' % version_info)
   code = util.RunCommand(
       _GenerateTestCommand('run_py_tests.py',
@@ -83,7 +83,7 @@
                  chrome_version_name=None, android_package=None):
   version_info = ''
   if chrome_version_name:
-    version_info = '(v%s)' % chrome_version_name
+    version_info = '(%s)' % chrome_version_name
   util.MarkBuildStepStart('java_tests%s' % version_info)
   code = util.RunCommand(
       _GenerateTestCommand('run_java_tests.py',
@@ -113,8 +113,9 @@
 def main():
   parser = optparse.OptionParser()
   parser.add_option(
-      '', '--android-package',
-      help='Application package name, if running tests on Android.')
+      '', '--android-packages',
+      help='Comma separated list of application package names, '
+           'if running tests on Android.')
   # Option 'chrome-version' is for desktop only.
   parser.add_option(
       '', '--chrome-version',
@@ -130,7 +131,7 @@
   server_name = 'chromedriver2_server' + exe_postfix
 
   required_build_outputs = [server_name]
-  if not options.android_package:
+  if not options.android_packages:
     required_build_outputs += [cpp_tests_name]
   build_dir = chrome_paths.GetBuildDir(required_build_outputs)
   print 'Using build outputs from', build_dir
@@ -153,15 +154,20 @@
     # For Windows bots: add ant, java(jre) and the like to system path.
     _AddToolsToSystemPathForWindows()
 
-  if options.android_package:
+  if options.android_packages:
     os.environ['PATH'] += os.pathsep + os.path.join(
         _THIS_DIR, os.pardir, 'chrome')
-    code1 = RunPythonTests(chromedriver,
-                           ref_chromedriver,
-                           android_package=options.android_package)
-    code2 = RunJavaTests(chromedriver,
-                         android_package=options.android_package)
-    return code1 or code2
+    code = 0
+    for package in options.android_packages.split(','):
+      code1 = RunPythonTests(chromedriver,
+                             ref_chromedriver,
+                             chrome_version_name=package,
+                             android_package=package)
+      code2 = RunJavaTests(chromedriver,
+                           chrome_version_name=package,
+                           android_package=package)
+      code = code or code1 or code2
+    return code
   else:
     latest_snapshot_revision = archive.GetLatestRevision(archive.Site.SNAPSHOT)
     versions = [
@@ -184,10 +190,10 @@
                              ref_chromedriver,
                              chrome=chrome_path,
                              chrome_version=version[0],
-                             chrome_version_name=version_name)
+                             chrome_version_name='v%s' % version_name)
       code2 = RunJavaTests(chromedriver, chrome=chrome_path,
                            chrome_version=version[0],
-                           chrome_version_name=version_name)
+                           chrome_version_name='v%s' % version_name)
       code = code or code1 or code2
     cpp_tests = os.path.join(build_dir, cpp_tests_name)
     return RunCppTests(cpp_tests) or code
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 2a19c6c..c347ce2 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -35,6 +35,15 @@
   from pylib import valgrind_tools
 
 
+_NEGATIVE_FILTER = {}
+_NEGATIVE_FILTER['HEAD'] = [
+    # https://code.google.com/p/chromedriver/issues/detail?id=213
+    'ChromeDriverTest.testClickElementInSubFrame',
+    # This test is flaky since it uses setTimeout.
+    # Re-enable once crbug.com/177511 is fixed and we can remove setTimeout.
+    'ChromeDriverTest.testAlert',
+]
+
 _DESKTOP_OS_SPECIFIC_FILTER = []
 if util.IsWindows():
   _DESKTOP_OS_SPECIFIC_FILTER = [
@@ -60,14 +69,12 @@
 
 _DESKTOP_NEGATIVE_FILTER = {}
 _DESKTOP_NEGATIVE_FILTER['HEAD'] = (
+    _NEGATIVE_FILTER['HEAD'] +
     _DESKTOP_OS_SPECIFIC_FILTER + [
-        # https://code.google.com/p/chromedriver/issues/detail?id=213
-        'ChromeDriverTest.testClickElementInSubFrame',
-        # This test is flaky since it uses setTimeout.
-        # Re-enable once crbug.com/177511 is fixed and we can remove setTimeout.
-        'ChromeDriverTest.testAlert',
-        # Desktop doesn't support TAP.
+        # Desktop doesn't support touch (without --touch-events).
         'ChromeDriverTest.testSingleTapElement',
+        'ChromeDriverTest.testTouchDownUpElement',
+        'ChromeDriverTest.testTouchMovedElement',
     ]
 )
 
@@ -80,15 +87,14 @@
 
 _ANDROID_NEGATIVE_FILTER = {}
 _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] = (
-    _DESKTOP_NEGATIVE_FILTER['HEAD'] + [
+    _NEGATIVE_FILTER['HEAD'] + [
         # Android doesn't support switches and extensions.
         'ChromeSwitchesCapabilityTest.*',
         'ChromeExtensionsCapabilityTest.*',
-        # https://code.google.com/p/chromedriver/issues/detail?id=262
-        'ChromeDriverTest.testCloseWindow',
-        'ChromeDriverTest.testGetWindowHandles',
-        'ChromeDriverTest.testSwitchToWindow',
+        # https://code.google.com/p/chromedriver/issues/detail?id=459
         'ChromeDriverTest.testShouldHandleNewWindowLoadingProperly',
+        # https://crbug.com/274650
+        'ChromeDriverTest.testCloseWindow',
         # https://code.google.com/p/chromedriver/issues/detail?id=259
         'ChromeDriverTest.testSendKeysToElement',
         # https://code.google.com/p/chromedriver/issues/detail?id=270
@@ -104,8 +110,21 @@
         'PerfTest.testColdExecuteScript',
     ]
 )
+_ANDROID_NEGATIVE_FILTER['com.android.chrome'] = (
+    _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] + [
+        # Touch support was added to devtools in Chrome v30.
+        'ChromeDriverTest.testTouchDownUpElement',
+        'ChromeDriverTest.testTouchMovedElement',
+    ]
+)
+_ANDROID_NEGATIVE_FILTER['com.chrome.beta'] = (
+    _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'])
 _ANDROID_NEGATIVE_FILTER['org.chromium.chrome.testshell'] = (
-    _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] + []
+    _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] + [
+        # ChromiumTestShell doesn't support multiple tabs.
+        'ChromeDriverTest.testGetWindowHandles',
+        'ChromeDriverTest.testSwitchToWindow',
+    ]
 )
 
 
@@ -353,7 +372,6 @@
         'document.body.innerHTML = "<div>old</div>";'
         'var div = document.getElementsByTagName("div")[0];'
         'div.addEventListener("click", function() {'
-        '  var div = document.getElementsByTagName("div")[0];'
         '  div.innerHTML="new<br>";'
         '});'
         'return div;')
@@ -364,14 +382,40 @@
     div = self._driver.ExecuteScript(
         'document.body.innerHTML = "<div>old</div>";'
         'var div = document.getElementsByTagName("div")[0];'
-        'div.addEventListener("click", function() {'
-        '  var div = document.getElementsByTagName("div")[0];'
+        'div.addEventListener("touchend", function() {'
         '  div.innerHTML="new<br>";'
         '});'
         'return div;')
     div.SingleTap()
     self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
 
+  def testTouchDownUpElement(self):
+    div = self._driver.ExecuteScript(
+        'document.body.innerHTML = "<div>old</div>";'
+        'var div = document.getElementsByTagName("div")[0];'
+        'div.addEventListener("touchend", function() {'
+        '  div.innerHTML="new<br>";'
+        '});'
+        'return div;')
+    loc = div.GetLocation()
+    self._driver.TouchDown(loc['x'], loc['y'])
+    self._driver.TouchUp(loc['x'], loc['y'])
+    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
+
+  def testTouchMovedElement(self):
+    div = self._driver.ExecuteScript(
+        'document.body.innerHTML = "<div>old</div>";'
+        'var div = document.getElementsByTagName("div")[0];'
+        'div.addEventListener("touchmove", function() {'
+        '  div.innerHTML="new<br>";'
+        '});'
+        'return div;')
+    loc = div.GetLocation()
+    self._driver.TouchDown(loc['x'], loc['y'])
+    self._driver.TouchMove(loc['x'] + 1, loc['y'] + 1)
+    self._driver.TouchUp(loc['x'] + 1, loc['y'] + 1)
+    self.assertEquals(1, len(self._driver.FindElements('tag name', 'br')))
+
   def testClickElementInSubFrame(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/frame_test.html'))
     frame = self._driver.FindElement('tag name', 'iframe')
@@ -404,7 +448,7 @@
     self.assertEquals('0123456789+-*/ Hi, there!', value)
 
   def testGetCurrentUrl(self):
-    self.assertTrue('data:' in self._driver.GetCurrentUrl())
+    self.assertTrue('about:blank' in self._driver.GetCurrentUrl())
 
   def testGoBackAndGoForward(self):
     self._driver.Load(self.GetHttpUrlForFile('/chromedriver/empty.html'))
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index b63c41e..80cbf00 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -161,10 +161,11 @@
     # http://crbug.com/156390
     'DragAndDropTest.*',
 
-    # Touch events are not yet supported.
+    # Flick touch events are not yet implemented.
     'TouchFlickTest.*',
+
+    # Scrolling touch events are not supported.
     'TouchScrollTest.*',
-    'TouchSingleTapTest.*',
 
     # These tests start multiple sessions, which is not supported on a single
     # Android device.
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index cec7479..ad62a9e 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -5,6 +5,7 @@
 #include "chrome/test/chromedriver/window_commands.h"
 
 #include <list>
+#include <string>
 
 #include "base/callback.h"
 #include "base/strings/string_number_conversions.h"
@@ -121,6 +122,67 @@
   return Status(kOk);
 }
 
+Status ScrollCoordinateInToView(
+    Session* session, WebView* web_view, int x, int y, int* offset_x,
+    int* offset_y) {
+  scoped_ptr<base::Value> value;
+  base::ListValue args;
+  args.AppendInteger(x);
+  args.AppendInteger(y);
+  Status status = web_view->CallFunction(
+      std::string(),
+      "function(x, y) {"
+      "  if (x < window.pageXOffset ||"
+      "      x >= window.pageXOffset + window.innerWidth ||"
+      "      y < window.pageYOffset ||"
+      "      y >= window.pageYOffset + window.innerHeight) {"
+      "    window.scrollTo(x - window.innerWidth/2, y - window.innerHeight/2);"
+      "  }"
+      "  return {"
+      "    view_x: Math.floor(window.pageXOffset),"
+      "    view_y: Math.floor(window.pageYOffset),"
+      "    view_width: Math.floor(window.innerWidth),"
+      "    view_height: Math.floor(window.innerHeight)};"
+      "}",
+      args,
+      &value);
+  if (!status.IsOk())
+    return status;
+  base::DictionaryValue* view_attrib;
+  value->GetAsDictionary(&view_attrib);
+  int view_x, view_y, view_width, view_height;
+  view_attrib->GetInteger("view_x", &view_x);
+  view_attrib->GetInteger("view_y", &view_y);
+  view_attrib->GetInteger("view_width", &view_width);
+  view_attrib->GetInteger("view_height", &view_height);
+  *offset_x = x - view_x;
+  *offset_y = y - view_y;
+  if (*offset_x < 0 || *offset_x >= view_width || *offset_y < 0 ||
+      *offset_y >= view_height)
+    return Status(kUnknownError, "Failed to scroll coordinate into view");
+  return Status(kOk);
+}
+
+Status ExecuteTouchEvent(
+    Session* session, WebView* web_view, TouchEventType type,
+    const base::DictionaryValue& params) {
+  int x, y;
+  if (!params.GetInteger("x", &x))
+    return Status(kUnknownError, "'x' must be an integer");
+  if (!params.GetInteger("y", &y))
+    return Status(kUnknownError, "'y' must be an integer");
+  int relative_x = x;
+  int relative_y = y;
+  Status status = ScrollCoordinateInToView(
+      session, web_view, x, y, &relative_x, &relative_y);
+  if (!status.IsOk())
+    return status;
+  std::list<TouchEvent> events;
+  events.push_back(
+      TouchEvent(type, relative_x, relative_y));
+  return web_view->DispatchTouchEvents(events);
+}
+
 }  // namespace
 
 Status ExecuteWindowCommand(
@@ -499,17 +561,36 @@
   return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
 }
 
+Status ExecuteTouchDown(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value) {
+  return ExecuteTouchEvent(session, web_view, kTouchStart, params);
+}
+
+Status ExecuteTouchUp(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value) {
+  return ExecuteTouchEvent(session, web_view, kTouchEnd, params);
+}
+
+Status ExecuteTouchMove(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value) {
+  return ExecuteTouchEvent(session, web_view, kTouchMove, params);
+}
+
 Status ExecuteGetActiveElement(
     Session* session,
     WebView* web_view,
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value) {
-  base::ListValue args;
-  return web_view->CallFunction(
-      session->GetCurrentFrameId(),
-      "function() { return document.activeElement || document.body }",
-      args,
-      value);
+  return GetActiveElement(session, web_view, value);
 }
 
 Status ExecuteSendKeysToActiveElement(
diff --git a/chrome/test/chromedriver/window_commands.h b/chrome/test/chromedriver/window_commands.h
index 8d0ee64..0178136 100644
--- a/chrome/test/chromedriver/window_commands.h
+++ b/chrome/test/chromedriver/window_commands.h
@@ -153,6 +153,27 @@
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value);
 
+// Touch press at a given coordinate.
+Status ExecuteTouchDown(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value);
+
+// Touch release at a given coordinate.
+Status ExecuteTouchUp(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value);
+
+// Touch move at a given coordinate.
+Status ExecuteTouchMove(
+    Session* session,
+    WebView* web_view,
+    const base::DictionaryValue& params,
+    scoped_ptr<base::Value>* value);
+
 Status ExecuteGetActiveElement(
     Session* session,
     WebView* web_view,
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
index 69167c5..9cac8a9 100644
--- a/chrome/test/functional/PYAUTO_TESTS
+++ b/chrome/test/functional/PYAUTO_TESTS
@@ -472,50 +472,6 @@
      ],
   },
 
-  # WebRTC MediaStream tests. Requires webcam and audio device to be present on
-  # the test machine.
-  'WEBRTC': {
-    'all': [
-      'media_stream_infobar',
-      'webrtc_brutality_test',
-      'webrtc_call',
-
-      # ==================================================
-      # Disabled tests that need to be investigated/fixed.
-      # ==================================================
-      # crbug.com/248079
-      '-webrtc_brutality_test.WebrtcBrutalityTest.testReloadsAfterGetUserMedia',
-    ],
-  },
-
-  # WebRTC / AppRTC Integration tests.
-  'WEBRTC_APPRTC': {
-    'all': [
-      'webrtc_apprtc_call',
-      # ==================================================
-      # Disabled tests that need to be investigated/fixed.
-      # ==================================================
-      # crbug.com/254412
-      '-webrtc_apprtc_call.WebrtcApprtcCallTest.testApprtcTabToTabCall',
-      '-webrtc_apprtc_call.WebrtcApprtcCallTest.testApprtcLoopbackCall',
-    ],
-  },
-
-  # WebRTC quality tests. The video quality test requires a webcam, an audio
-  # device and a special setup where the webcam plays a barcode-encoded video.
-  # The webrtc_audio_quality test requires additional configuration as described
-  # in the test's class comments.
-  'WEBRTC_QUALITY': {
-    'all': [
-      'webrtc_video_quality',
-      # Disabled until crbug.com/254437 is resolved.
-      '-webrtc_audio_quality',
-    ],
-    'mac': [
-      '-webrtc_audio_quality',  # Not implemented.
-    ],
-  },
-
   # Trace event tests.
   'TRACING': {
     'all': [
diff --git a/chrome/test/functional/ispy/ispy_core/app.yaml b/chrome/test/functional/ispy/ispy_core/app.yaml
new file mode 100644
index 0000000..cbed5f9
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/app.yaml
@@ -0,0 +1,17 @@
+application: google.com:ispy
+version: 1
+runtime: python27
+api_version: 1
+threadsafe: True
+
+handlers:
+- url: /.*
+  script: main.application
+
+libraries:
+- name: webapp2
+  version: latest
+- name: jinja2
+  version: latest
+- name: PIL
+  version: latest
diff --git a/tools/perf/page_sets/blank_page.html b/chrome/test/functional/ispy/ispy_core/handlers/__init__.py
similarity index 100%
copy from tools/perf/page_sets/blank_page.html
copy to chrome/test/functional/ispy/ispy_core/handlers/__init__.py
diff --git a/chrome/test/functional/ispy/ispy_core/handlers/command_handler.py b/chrome/test/functional/ispy/ispy_core/handlers/command_handler.py
new file mode 100644
index 0000000..fb625ee
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/handlers/command_handler.py
@@ -0,0 +1,357 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Request handler to allow restful interaction with tests and runs."""
+
+import json
+import os
+import sys
+import webapp2
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+
+from tests.rendering_test_manager import cloud_bucket
+from tests.rendering_test_manager import cloud_bucket_impl
+from tools import image_tools
+from tools import rendering_test_manager
+
+import ispy_auth_constants
+
+class MissingArgError(Exception):
+  pass
+
+
+def Command(*expected_parameters):
+  """Convenient decorator for Command functions the CommandHandler.
+
+  Args:
+    *expected_parameters: the expected parameters for the command.
+
+  Returns:
+    A decorated method that accepts a request object and returns nothing.
+  """
+  def _Decorate(method):
+    def _Wrapper(self, request):
+      # Try accessing all expected_parameters, if any are absent from the
+      #  request raise MissingArgError.
+      try:
+        for param in expected_parameters:
+          if not request.get(param):
+            raise MissingArgError('Argument: missing %s' % param)
+      # If a MissingArgError was raised, write an error response.
+      except MissingArgError, e:
+        self.response.headers['Content-Type'] = 'application/json'
+        self.response.out.write(json.dumps({'success': False, 'error': str(e)}))
+      else:
+        # If all parameters are present run the decorated method.
+        results = method(self, request)
+        self.response.headers['Content-Type'] = 'application/json'
+        self.response.out.write(json.dumps(results))
+    return _Wrapper
+  return _Decorate
+
+
+class CommandHandler(webapp2.RequestHandler):
+  """Command handler that allows restful interaction with tests and runs."""
+
+  def __init__(self, *args, **kwargs):
+    super(CommandHandler, self).__init__(*args, **kwargs)
+    self.command_functions = {
+        'upload_test': self._UploadTest,
+        'test_exists': self._TestExists,
+        'failure_exists': self._FailureExists,
+        'run_test': self._RunTest,
+        'upload_test_pink_out': self._UploadTestPinkOut,
+        'remove_test': self._RemoveTest,
+        'remove_failure': self._RemoveFailure,
+        'add_to_test_mask': self._AddToTestMask}
+
+  def post(self):
+    """Handles post requests.
+
+    This method accepts a post request that minimally has a 'command' parameter
+      which indicates which of the handler's commands to run. If the
+      command is not in the valid_commands dictionary, then an error
+      will be returned. All responses are json-encoded objects that
+      have either a Succeeded or Failed parameter indicating success or
+      failure in addition to other returned parameters specific to the command.
+    """
+    cmd = self.request.get('command')
+    if not cmd:
+      self._Error(self.request)
+      return
+    if cmd not in self.command_functions:
+      self._InvalidCommand(self.request)
+      return
+    self.bucket = cloud_bucket_impl.CloudBucketImpl(
+        ispy_auth_constants.KEY, ispy_auth_constants.SECRET,
+        ispy_auth_constants.BUCKET)
+    self.manager = rendering_test_manager.RenderingTestManager(self.bucket)
+    self.command_functions.get(cmd)(self.request)
+
+  @Command()
+  def _Error(self, request):
+    """This command returns an error when no command is given.
+
+    This command has no expected parameters.
+
+    Args:
+      request: A request object.
+
+    Returns:
+      A dictionary indicating a failure, and an error message indicating
+        that no command was specified.
+    """
+    return {'success': False, 'error': 'No command was specified.'}
+
+  @Command()
+  def _InvalidCommand(self, request):
+    """This command returns an error when an invalid command is given.
+
+    This command has no expected parameters.
+
+    Args:
+      request: a request object.
+
+    Returns:
+      A dictionary indicating a failure, and an error message
+        containing all possible valid commands.
+    """
+    return {'success': False,
+            'error': 'Invalid command. Valid commands are: %s.' %
+            ' '.join(self.command_functions.keys())}
+
+  @Command('batch_name', 'test_name', 'images')
+  def _UploadTest(self, request):
+    """Uploads an ispy-test to GCS.
+
+    This function uploads a collection of images as a 'test' to the
+      ispy server. A mask is then computed from these images, and the
+      first image in the images list and the mask are stored in the
+      GCS as an ispy-test.
+
+    This function is called for the command 'upload_test'.
+      Request Parameters:
+        test_name: The name of the test to be uploaded.
+        images: a json encoded list of base64 encoded png images.
+      Response JSON:
+        succeeded: True.
+
+    Args:
+      request: a request object.
+
+    Returns:
+      A dictionary indicating success or failure.
+    """
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    raw_images = request.get('images')
+    images = json.loads(raw_images)
+    self.manager.UploadTest(
+        batch_name, test_name,
+        [image_tools.DeserializeImage(image) for image in images])
+    return {'success': True}
+
+  @Command('batch_name', 'test_name', 'images', 'pink_out', 'RGB')
+  def _UploadTestPinkOut(self, request):
+    """Uploads an ispy-test to GCS with the pink_out workaround.
+
+    This function is called for the command 'upload_test_pink_out'.
+      Request Parameters:
+        test_name: The name of the test to be uploaded.
+        images: a json encoded list of base64 encoded png images.
+        pink_out: a base64 encoded png image.
+        RGB: a json list representing the RGB values of a color to mask out.
+      Response JSON:
+        succeeded: True.
+
+    Args:
+      request: a request object.
+
+    Returns:
+      A dictionary indicating success or failure.
+    """
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    rgb = json.loads(request.get('RGB'))
+    images = [image_tools.DeserializeImage(i)
+              for i in json.loads(request.get('images'))]
+    pink_out = image_tools.DeserializeImage(request.get('pink_out'))
+    # convert the pink_out into a mask
+    black = (0, 0, 0, 255)
+    white = (255, 255, 255, 255)
+    pink_out.putdata(
+        [black if px == (rgb[0], rgb[1], rgb[2], 255) else white
+         for px in pink_out.getdata()])
+    mask = image_tools.CreateMask(images)
+    mask = image_tools.InflateMask(image_tools.CreateMask(images), 7)
+    combined_mask = image_tools.AddMasks([mask, pink_out])
+    path = 'tests/%s/%s/' % (batch_name, test_name)
+    self.manager.UploadImage(path + 'expected.png',
+                             images[0])
+    self.manager.UploadImage(path + 'mask.png',
+                             combined_mask)
+    return {'success': True}
+
+  @Command('mask', 'batch_name', 'test_name')
+  def _AddToTestMask(self, request):
+    """Adds a another mask image to the existing mask for a given test.
+
+      Request Parameters:
+        mask: A RGBA png white/black mask image.
+        test_name: The name of a test in i-spy to add to.
+      Response JSON:
+        succeeded: True
+      Response Error:
+        error: if the test was not found in GCS.
+
+    Args:
+      request: A request object.
+
+    Returns:
+      A dictionary indicating success or failure.
+    """
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    mask_to_be_added = image_tools.InflateMask(
+        image_tools.DeserializeImage(request.get('mask')), 7)
+    if not self.manager.TestExists(batch_name, test_name):
+      return {'success': False, 'error': 'Test does not exist.'}
+    path = 'tests/%s/%s/mask.png' % (batch_name, test_name)
+    test_mask = self.manager.DownloadImage(path)
+    combined_mask = image_tools.AddMasks([test_mask, mask_to_be_added])
+    self.manager.UploadImage(path, combined_mask)
+    return {'success': True}
+
+  @Command('image', 'batch_name', 'test_name')
+  def _RunTest(self, request):
+    """Runs a test on GCS and stores a failure if it doesn't pass.
+
+    This method compares the submitted image with the expected and mask
+      images stored in GCS under the submitted test name. If there are
+      any differences between the submitted image and the expected test
+      image (with respect to the mask), the submitted image is stored
+      as a failure in GCS.
+
+    This method is run if the command parameter is set to 'run_test'.
+      Request Parameters:
+        'image': A base64 encoded screenshot that corresponds to a test in GCS.
+        'test_name': The name of the test that 'image' corresponds to.
+      Response JSON:
+        'succeeded': True
+
+    Args:
+      request: a request object
+
+    Returns:
+      A dictionary indicating success or failure.
+    """
+    raw_image = request.get('image')
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    image = image_tools.DeserializeImage(raw_image)
+    try:
+      self.manager.RunTest(batch_name, test_name, image)
+    except cloud_bucket.FileNotFoundError, e:
+      return {'success': False, 'error': str(e)}
+    else:
+      return {'success': True}
+
+  @Command('batch_name', 'test_name')
+  def _TestExists(self, request):
+    """Checks to see if a test exists in GCS.
+
+      This method confirms whether or not an expected image, and
+        mask exist under the given test_name in GCS. Returning true
+        only if all components of a test exist.
+
+      This method is run if the command parameter is 'test_exists'.
+        Request Parameters:
+          'test_name': The name of the test to look for.
+        Response JSON:
+          'exists': boolean indicating whether the test exists.
+          'succeeded': True.
+
+    Args:
+      request: a request object.
+
+    Returns:
+      A dictionary indicating success or failure, and if the command was
+        successful, whether the test exists.
+    """
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    return {'success': True, 'exists': self.manager.TestExists(batch_name,
+                                                                 test_name)}
+
+  @Command('batch_name', 'test_name')
+  def _FailureExists(self, request):
+    """Checks to see if a particular failed run exists in GCS.
+
+    This method is run if the command parameter is 'failure_exists'.
+      Request Parameters:
+        'test_name': the name of the test that failure occurred on.
+      Response JSON:
+        'exists': boolean indicating whether the failure exists.
+        'succeeded': True.
+
+    Args:
+      request: a request object.
+
+    Returns:
+      A dictionary indicating success or failure, and if the command was
+        successful, whether the failed run exists.
+    """
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    return {'success': True,
+            'exists': self.manager.FailureExists(
+                batch_name, test_name)}
+
+  @Command('batch_name', 'test_name')
+  def _RemoveTest(self, request):
+    """Removes a test and associated runs from GCS.
+
+    This method will locate all files in ispy's GCS datastore
+      associated with the given test_name, and remove them from GCS.
+      This includes the test's mask, expected image, and all failures
+      on the given test.
+
+    This method is run if the command parameter is 'remove_test'.
+      Request Parameters:
+        'test_name': the name of the test to remove.
+      Response JSON:
+        succeeded: True.
+
+    Args:
+      request: a request object.
+
+    Returns:
+      A dictionary indicating success or failure.
+    """
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    self.manager.RemoveTest(batch_name, test_name)
+    return {'success': True}
+
+  @Command('batch_name', 'test_name')
+  def _RemoveFailure(self, request):
+    """Removes a failure from GCS.
+
+    This method is run if the command parameter is 'remove_failure'.
+      Request Parameters:
+        'test_name': the name of the test in which the failure occurred.
+      Response JSON:
+        succeeded: True.
+
+    Args:
+      request: a request object.
+
+    Returns:
+      A dictionary indicating success or failure.
+    """
+    batch_name = request.get('batch_name')
+    test_name = request.get('test_name')
+    self.manager.RemoveFailure(batch_name, test_name)
+    return {'success': True}
diff --git a/chrome/test/functional/ispy/ispy_core/handlers/debug_view_handler.py b/chrome/test/functional/ispy/ispy_core/handlers/debug_view_handler.py
new file mode 100644
index 0000000..6ef4e9c
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/handlers/debug_view_handler.py
@@ -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.
+
+"""Request handler to display the debug view for a Failure."""
+
+import jinja2
+import os
+import sys
+import webapp2
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+import views
+
+JINJA = jinja2.Environment(
+    loader=jinja2.FileSystemLoader(os.path.dirname(views.__file__)),
+    extensions=['jinja2.ext.autoescape'])
+
+
+class DebugViewHandler(webapp2.RequestHandler):
+  """Request handler to display the debug view for a failure."""
+
+  def get(self):
+    """Handles get requests to the /debug_view page.
+
+    GET Parameters:
+      diff: The path to the diff image on a failure.
+      expected: The path to the expected image on a failure.
+      actual: The path to the actual image on a failure.
+    """
+    diff_path = self.request.get('diff')
+    expected_path = self.request.get('expected')
+    actual_path = self.request.get('actual')
+    data = {}
+
+    def _Encode(url):
+      return '/image?file_path=%s' % url
+
+    data['diff'] = _Encode(diff_path)
+    data['expected'] = _Encode(expected_path)
+    data['actual'] = _Encode(actual_path)
+    template = JINJA.get_template('debug_view.html')
+    self.response.write(template.render(data))
diff --git a/chrome/test/functional/ispy/ispy_core/handlers/image_handler.py b/chrome/test/functional/ispy/ispy_core/handlers/image_handler.py
new file mode 100644
index 0000000..3315196
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/handlers/image_handler.py
@@ -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.
+
+"""Request handler to display an image from ispy.googleplex.com."""
+
+import json
+import os
+import sys
+import webapp2
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+
+from tests.rendering_test_manager import cloud_bucket
+from tests.rendering_test_manager import cloud_bucket_impl
+
+import ispy_auth_constants
+
+
+class ImageHandler(webapp2.RequestHandler):
+  """A request handler to avoid the Same-Origin problem in the debug view."""
+
+  def get(self):
+    """Handles get requests to the ImageHandler.
+
+    GET Parameters:
+      file_path: A path to an image resource in Google Cloud Storage.
+    """
+    file_path = self.request.get('file_path')
+    if not file_path:
+      self.error(404)
+      return
+    bucket = cloud_bucket_impl.CloudBucketImpl(
+        ispy_auth_constants.KEY, ispy_auth_constants.SECRET,
+        ispy_auth_constants.BUCKET)
+    try:
+      image = bucket.DownloadFile(file_path)
+    except cloud_bucket.FileNotFoundError:
+      self.error(404)
+    else:
+      self.response.headers['Content-Type'] = 'image/png'
+      self.response.out.write(image)
diff --git a/chrome/test/functional/ispy/ispy_core/handlers/main_view_handler.py b/chrome/test/functional/ispy/ispy_core/handlers/main_view_handler.py
new file mode 100644
index 0000000..032cbab
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/handlers/main_view_handler.py
@@ -0,0 +1,117 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Request handler to serve the main_view page."""
+
+import jinja2
+import json
+import os
+import re
+import sys
+import webapp2
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+
+import views
+
+from tests.rendering_test_manager import cloud_bucket_impl
+from tools import rendering_test_manager
+
+import ispy_auth_constants
+
+JINJA = jinja2.Environment(
+    loader=jinja2.FileSystemLoader(os.path.dirname(views.__file__)),
+    extensions=['jinja2.ext.autoescape'])
+
+
+class MainViewHandler(webapp2.RequestHandler):
+  """Request handler to serve the main_view page."""
+
+  def get(self):
+    """Handles a get request to the main_view page.
+
+    If the batch_name parameter is specified, then a page displaying all of
+      the failed runs in the batch will be shown. Otherwise a view listing
+      all of the batches available for viewing will be displayed.
+    """
+    # Get parameters.
+    batch_name = self.request.get('batch_name')
+    # Set up rendering test manager.
+    bucket = cloud_bucket_impl.CloudBucketImpl(
+        ispy_auth_constants.KEY, ispy_auth_constants.SECRET,
+        ispy_auth_constants.BUCKET)
+    manager = rendering_test_manager.RenderingTestManager(bucket)
+    # Load the view.
+    if batch_name:
+      self._GetForBatch(batch_name, manager)
+      return
+    self._GetAllBatches(manager)
+
+  def _GetAllBatches(self, manager):
+    """Renders a list view of all of the batches available in GCS.
+
+    Args:
+      manager: An instance of rendering_test_manager.RenderingTestManager.
+    """
+    template = JINJA.get_template('list_view.html')
+    data = {}
+    batches = set([re.match(r'^tests/([^/]+)/.+$', path).groups()[0]
+                   for path in manager.GetAllPaths('tests/')])
+    base_url = '/?batch_name=%s'
+    data['links'] = [(batch, base_url % batch) for batch in batches]
+    self.response.write(template.render(data))
+
+  def _GetForBatch(self, batch_name, manager):
+    """Renders a sorted list of failure-rows for a given batch_name.
+
+    This method will produce a list of failure-rows that are sorted
+      in descending order by number of different pixels.
+
+    Args:
+      batch_name: The name of the batch to render failure rows from.
+      manager: An instance of rendering_test_manager.RenderingTestManager.
+    """
+    template = JINJA.get_template('main_view.html')
+    paths = set([path for path in manager.GetAllPaths('failures/' + batch_name)
+                 if path.endswith('actual.png')])
+    rows = [self._CreateRow(batch_name, path, manager)
+            for path in paths]
+    # Function that sorts by the different_pixels field in the failure-info.
+    def _Sorter(x, y):
+      return cmp(y['info']['different_pixels'],
+                 x['info']['different_pixels'])
+    self.response.write(template.render({'comparisons': sorted(rows, _Sorter)}))
+
+  def _CreateRow(self, batch_name, path, manager):
+    """Creates one failure-row.
+
+    This method builds a dictionary with the data necessary to display a
+      failure in the main_view html template.
+
+    Args:
+      batch_name: The name of the batch the failure is in.
+      path: A path to the failure's actual.png file.
+      manager: An instance of rendering_test_manager.RenderingTestManager.
+
+    Returns:
+      A dictionary with fields necessary to render a failure-row
+        in the main_view html template.
+    """
+    res = {}
+    pattern = r'^failures/%s/([^/]+)/.+$' % batch_name
+    res['test_name'] = re.match(
+        pattern, path).groups()[0]
+    res['batch_name'] = batch_name
+    res['info'] = json.loads(manager.cloud_bucket.DownloadFile(
+        '/failures/%s/%s/info.txt' % (res['batch_name'], res['test_name'])))
+    expected = 'tests/%s/%s/expected.png' % (batch_name, res['test_name'])
+    diff = 'failures/%s/%s/diff.png' % (batch_name, res['test_name'])
+    res['expected_path'] = expected
+    res['diff_path'] = diff
+    res['actual_path'] = path
+    res['expected'] = manager.cloud_bucket.GetURL(expected)
+    res['diff'] = manager.cloud_bucket.GetURL(diff)
+    res['actual'] = manager.cloud_bucket.GetURL(path)
+    return res
+
diff --git a/chrome/test/functional/ispy/ispy_core/handlers/update_mask_handler.py b/chrome/test/functional/ispy/ispy_core/handlers/update_mask_handler.py
new file mode 100644
index 0000000..c17d5d2
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/handlers/update_mask_handler.py
@@ -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.
+
+"""Request Handler to allow test mask updates."""
+
+import webapp2
+import re
+import sys
+import os
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from tools import rendering_test_manager
+from tools import image_tools
+from tests.rendering_test_manager import cloud_bucket_impl
+
+import ispy_auth_constants
+
+class UpdateMaskHandler(webapp2.RequestHandler):
+  """Request handler to allow test mask updates."""
+
+  def post(self):
+    """Accepts post requests.
+
+    This method will accept a post request containing device, site and
+      device_id parameters. This method takes the diff of the run
+      indicated by it's parameters and adds it to the mask of the run's
+      test. It will then delete the run it is applied to and redirect
+      to the device list view.
+    """
+    batch_name = self.request.get('batch_name')
+    test_name = self.request.get('test_name')
+
+    # Short-circuit if a parameter is missing.
+    if not (batch_name and test_name):
+      self.response.header['Content-Type'] = 'json/application'
+      self.response.write(json.dumps(
+          {'error': 'batch_name, and test_name, must be '
+                    'supplied to update a mask.'}))
+      return
+    # Otherwise, set up the rendering_test_manager.
+    self.bucket = cloud_bucket_impl.CloudBucketImpl(
+        ispy_auth_constants.KEY, ispy_auth_constants.SECRET,
+        ispy_auth_constants.BUCKET)
+    self.manager = rendering_test_manager.RenderingTestManager(self.bucket)
+    # Short-circuit if the failure does not exist.
+    if not self.manager.FailureExists(batch_name, test_name):
+      self.response.header['Content-Type'] = 'json/application'
+      self.response.write(json.dumps(
+        {'error': 'Could not update mask because failure does not exist.'}))
+      return
+    # Get the failure namedtuple (which also computes the diff).
+    failure = self.manager.GetFailure(batch_name, test_name)
+    # Get the mask of the image.
+    path = 'tests/%s/%s/mask.png' % (batch_name, test_name)
+    mask = self.manager.DownloadImage(path)
+    # Merge the masks.
+    combined_mask = image_tools.AddMasks([mask, failure.diff])
+    # Upload the combined mask in place of the original.
+    self.manager.UploadImage(path, combined_mask)
+    # Now that there is no div for the two images, remove the failure.
+    self.manager.RemoveFailure(batch_name, test_name)
+    # Redirect back to the sites list for the device.
+    self.redirect('/?batch_name=%s' % batch_name)
diff --git a/chrome/test/functional/ispy/ispy_core/ispy_auth_constants.py b/chrome/test/functional/ispy/ispy_core/ispy_auth_constants.py
new file mode 100644
index 0000000..c4263a8
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/ispy_auth_constants.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.
+
+"""Module to hold authentication constants used across handlers."""
+
+# This is a dummy file, when updating the I-Spy server, replace these
+#  empty strings with their correct values.
+
+KEY = 'GOOGxxxxxxxxxxxxxxxxxxx'
+SECRET = 'xxxxxxxxxxxxxxxx/xxxxxxxxxx/xxxxxxxxxxx'
+BUCKET = 'i-spy'
diff --git a/chrome/test/functional/ispy/ispy_core/main.py b/chrome/test/functional/ispy/ispy_core/main.py
new file mode 100644
index 0000000..5f9665e
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/main.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.
+
+import webapp2
+
+from handlers import command_handler
+from handlers import debug_view_handler
+from handlers import image_handler
+from handlers import main_view_handler
+from handlers import update_mask_handler
+
+application = webapp2.WSGIApplication(
+    [('/run_command?', command_handler.CommandHandler),
+     ('/update_mask?', update_mask_handler.UpdateMaskHandler),
+     ('/debug_view?', debug_view_handler.DebugViewHandler),
+     ('/image?', image_handler.ImageHandler),
+     ('/', main_view_handler.MainViewHandler)], debug=True)
diff --git a/chrome/test/functional/ispy/ispy_core/run_tests.py b/chrome/test/functional/ispy/ispy_core/run_tests.py
new file mode 100755
index 0000000..7b083fb
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/run_tests.py
@@ -0,0 +1,11 @@
+#!/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
+
+if __name__ == '__main__':
+  suite = unittest.TestLoader().discover('.', pattern='*test.py')
+  unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/cloud_bucket_impl.py b/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/cloud_bucket_impl.py
index e28fc7f..ebf18f0 100644
--- a/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/cloud_bucket_impl.py
+++ b/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/cloud_bucket_impl.py
@@ -3,12 +3,15 @@
 # found in the LICENSE file.
 
 """Implementation of CloudBucket using Google Cloud Storage as the backend."""
-
+import os
 import sys
-sys.path.append(sys.path.join('gsutil', 'third_party', 'boto'))
-# TODO(chris) check boto into ispy/third_party/
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
+                             'gsutil', 'third_party', 'boto'))
 import boto
 
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 from tests.rendering_test_manager import cloud_bucket
 
 
@@ -63,7 +66,9 @@
     key = boto.gs.key.Key(self.bucket)
     key.key = path
     if key.exists():
-      return key.generate_url(3600)
+      # Corrects a bug in boto that incorrectly generates a url
+      #  to a resource in Google Cloud Storage.
+      return key.generate_url(3600).replace('AWSAccessKeyId', 'GoogleAccessId')
     else:
       raise cloud_bucket.FileNotFoundError(path)
 
diff --git a/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/mock_cloud_bucket.py b/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/mock_cloud_bucket.py
index 7ae1def..5753a98 100644
--- a/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/mock_cloud_bucket.py
+++ b/chrome/test/functional/ispy/ispy_core/tests/rendering_test_manager/mock_cloud_bucket.py
@@ -4,6 +4,10 @@
 
 """Subclass of CloudBucket used for testing."""
 
+import os
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 from tests.rendering_test_manager import cloud_bucket
 
 
diff --git a/chrome/test/functional/ispy/ispy_core/tools/__init__.py b/chrome/test/functional/ispy/ispy_core/tools/__init__.py
index e69de29..d7a0128 100644
--- a/chrome/test/functional/ispy/ispy_core/tools/__init__.py
+++ b/chrome/test/functional/ispy/ispy_core/tools/__init__.py
@@ -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.
+
+"""This module provides a set of tools that I-Spy uses to perform tests.
+
+
+I-Spy breaks rendering-validations down into a hierarchy of batches,
+ tests, and failures.
+ A batch is a group of tests that is run together.
+ A test consists of two images, one image of the page that is known
+  to be rendered correctly, and another that is a white and black mask,
+  where white regions represent areas that should be exempted from pixel-
+  by-pixel comparisons. These masks are generated by taking a
+  succession of images from a view which is  known to be rendered correctly,
+  and masking the regions that change to prevent animated regions of the
+  page from breaking the tests. Tests can be run by submitting an image to
+  them. The submitted image will be compared against the regions of the
+  test's image (which is known to be rendered correctly) that are not
+  excluded by the test's mask. If the comparison fails, a failure is stored
+  in Google Cloud Storage.
+ A failure consists of the image which failed to compare to the test's image
+  and mask, and a black and white image representing the difference between
+  the failure's image and the test's."""
diff --git a/chrome/test/functional/ispy/ispy_core/tools/api_command_runner.py b/chrome/test/functional/ispy/ispy_core/tools/api_command_runner.py
new file mode 100644
index 0000000..e6cdb78
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/tools/api_command_runner.py
@@ -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.
+
+"""RunAPICommand function to authenticate with Ispy and run a command."""
+
+import re
+import requests
+
+
+class ServerSideError(Exception):
+  pass
+
+
+class UnknownError(Exception):
+  pass
+
+
+def RunAPICommand(command, parameters, email, app_specific_password):
+  """Performs the necessary authentication and runs an ispy api command.
+
+  Args:
+    command: The name of the command to run.
+    parameters: A List of 2-tuples (parameter-name, parameter-value).
+    email: A google.com email to connect to ispy with.
+    app_specific_password: An application specific password registered
+      to the given email account.
+
+  Returns:
+    A JSON representation of the result of the command.
+  """
+  app_name = 'google.com:ispy'
+  base_url = 'http://ispy.googleplex.com/'
+  # Use Requests to get an Auth key for the specified email/password.
+  data = {'Email': email, 'Passwd': app_specific_password, 'service': 'ah',
+          'source': app_name, 'accountType': 'GOOGLE'}
+  auth_keys_text = requests.post('https://google.com/accounts/ClientLogin',
+                                 data=data).text
+  auth_keys = dict(line.split('=')
+                   for line in auth_keys_text.split('\n') if line)
+  # Establish a session by logging into _ah/login
+  serv_args = {'continue': '', 'auth': auth_keys['Auth']}
+  r2 = requests.get(base_url + '_ah/login',
+                    params=serv_args, allow_redirects=False)
+  r3 = requests.post(base_url+'run_command',
+                     data=dict([('command', command)] + parameters.items()),
+                     cookies=r2.cookies)
+  try:
+    return r3.json()
+  except ValueError:
+    if '<html>' in r3.text:
+      match = re.match(r'^.+?<pre>(.+?)</pre>.+?$', r3.text, re.DOTALL)
+      if match:
+        raise ServerSideError(match.groups()[0])
+      else:
+        raise ServerSideError(r3.text)
+    else:
+      raise UnknownError(r3.text)
diff --git a/chrome/test/functional/ispy/ispy_core/tools/api_command_runner_functionaltest.py b/chrome/test/functional/ispy/ispy_core/tools/api_command_runner_functionaltest.py
new file mode 100644
index 0000000..c162383
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/tools/api_command_runner_functionaltest.py
@@ -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.
+
+from PIL import Image
+import json
+import os
+import sys
+import unittest
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from tools import api_command_runner
+from tools import image_tools
+import auth_constants
+
+class APICommandRunnerFunctionalTest(unittest.TestCase):
+  def setUp(self):
+    self.u = auth_constants.api_username
+    self.p = auth_constants.api_password
+
+  def Run(self, command, params, expected):
+    res = api_command_runner.RunAPICommand(command, params, self.u, self.p)
+    for item in expected.items():
+      self.assertTrue(res.has_key(item[0]))
+      self.assertEquals(res[item[0]], item[1])
+
+  def testRunner(self):
+    batch_test = {'batch_name': 'batch', 'test_name': 'test'}
+    white = image_tools.SerializeImage(Image.new(
+        'RGBA', (25, 25), (255, 255, 255, 255)))
+    black = image_tools.SerializeImage(Image.new(
+        'RGBA', (25, 25), (0, 0, 0, 255)))
+    pink = image_tools.SerializeImage(Image.new(
+        'RGBA', (25, 25), (255, 71, 191, 255)))
+    test_set = json.dumps([white, white])
+    # Removing a test.
+    self.Run('remove_test', batch_test, {'success': True})
+    # Uploading a test.
+    self.Run('upload_test', dict(batch_test.items() + [('images', test_set)]),
+             {'success': True})
+    # Check that the test we uploaded is there.
+    self.Run('test_exists', batch_test, {'success': True, 'exists': True})
+    # Check that we can run the test we uploaded.
+    self.Run('run_test', dict(batch_test.items() + [('image', black)]),
+             {'success': True})
+    # Check that the test we ran failed.
+    self.Run('failure_exists', batch_test, {'success': True, 'exists': True})
+    # Remove the failure.
+    self.Run('remove_failure', batch_test, {'success': True})
+    # Check that the failure was removed.
+    self.Run('failure_exists', batch_test, {'success': True, 'exists': False})
+    # Remove the test we added.
+    self.Run('remove_test', batch_test, {'success': True})
+    # Check that the test was removed.
+    self.Run('test_exists', batch_test, {'success': True, 'exists': False})
+    # Check that a bad command returns a failure.
+    self.Run('bad_command', {}, {'success': False})
+    # Check that missing parameters returns a failure.
+    self.Run('run_test', batch_test, {'success': False})
+    # Check that running a bad test returns a failure.
+    self.Run('run_test', {'batch_name': 'batch', 'test_name': 'doesnt_exist',
+                          'image': white},
+             {'success': False})
+    # Upload a test with the pinkout workaround (pink).
+    self.Run('upload_test_pink_out',
+             dict(batch_test.items() +
+                  [('images', test_set), ('pink_out', pink),
+                   ('RGB', json.dumps([255, 71, 191, 255]))]),
+             {'success': True})
+    # Check that the test is there.
+    self.Run('test_exists', batch_test, {'success': True})
+    # Run the test against a black image (traditionally fails).
+    self.Run('run_test', dict(batch_test.items() + [('image', black)]),
+             {'success': True})
+    # Check that the failure exists.
+    self.Run('failure_exists', batch_test, {'success': True, 'exists': True})
+    # Remove the test.
+    self.Run('remove_test', batch_test, {'success': True})
+    # Upload a test with the pinkout workaround (not pink).
+    self.Run('upload_test_pink_out',
+             dict(batch_test.items() +
+                  [('images', test_set), ('pink_out', black),
+                   ('RGB', json.dumps([255, 71, 191, 255]))]),
+             {'success': True})
+    # Check that the test exists.
+    self.Run('test_exists', batch_test, {'success': True})
+    # Run the test against a black image (traditionally fails).
+    self.Run('run_test', dict(batch_test.items() + [('image', black)]),
+             {'success': True})
+    # Check that a failure doesn't exist.
+    self.Run('failure_exists', batch_test, {'success': True, 'exists': False})
+    # Remove the test.
+    self.Run('remove_test', batch_test, {'success': True})
+    # Check that hte test doesn't exist.
+    self.Run('test_exists', batch_test, {'success': True, 'exists': False})
+    # Add a test.
+    self.Run('upload_test', dict(batch_test.items() + [('images', test_set)]),
+             {'success': True})
+    # At this point the mask is black, add a white image to the mask.
+    self.Run('add_to_test_mask', dict(batch_test.items() + [('mask', white)]),
+             {'success': True})
+    # Run the test against a black image.
+    self.Run('run_test', dict(batch_test.items() + [('image', black)]),
+             {'success': True})
+    # Check that a failure doesn't exist (because of the added mask).
+    self.Run('failure_exists', batch_test, {'success': True, 'exists': False})
+    # Remove the test.
+    self.Run('remove_test', batch_test, {'success': True})
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/test/functional/ispy/ispy_core/tools/image_tools_unittest.py b/chrome/test/functional/ispy/ispy_core/tools/image_tools_unittest.py
index 46f3702..52e4825 100644
--- a/chrome/test/functional/ispy/ispy_core/tools/image_tools_unittest.py
+++ b/chrome/test/functional/ispy/ispy_core/tools/image_tools_unittest.py
@@ -1,10 +1,14 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
+# 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 unittest
+import sys
+import os
 from PIL import Image
-import image_tools
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from tools import image_tools
 
 
 def _GenImage(size, color):
diff --git a/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager.py b/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager.py
index 9fd584c..d5f370c 100644
--- a/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager.py
+++ b/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager.py
@@ -4,10 +4,15 @@
 
 """Utilities for managing files in Google Cloud Storage."""
 
-from tools import image_tools
 import collections
-import posixpath
 import itertools
+import json
+import os
+import posixpath
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+from tools import image_tools
 
 
 class RenderingTestManager(object):
@@ -32,7 +37,8 @@
       image: a RGB PIL.Image to be uploaded.
     """
     self.cloud_bucket.UploadFile(
-        full_path, image_tools.SerializeImage(image), 'image/png')
+        full_path, image_tools.SerializeImage(image).decode('base64'),
+        'image/png')
 
   def DownloadImage(self, full_path):
     """Downloads an image from a location in GCS.
@@ -47,27 +53,29 @@
       cloud_bucket.NotFoundError: if the path to the image is not valid.
     """
     return image_tools.DeserializeImage(
-        self.cloud_bucket.DownloadFile(full_path))
+        self.cloud_bucket.DownloadFile(full_path).encode('base64'))
 
-  def UploadTest(self, test_name, images):
+  def UploadTest(self, batch_name, test_name, images):
     """Creates and uploads a test to GCS from a set of images and name.
 
     This method generates a mask from the uploaded images, then
       uploads the mask and first of the images to GCS as a test.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the name of the test.
       images: a list of RGB encoded PIL.Images
     """
-    path = posixpath.join('tests', test_name)
-    mask = image_tools.CreateMask(images)
+    path = posixpath.join('tests', batch_name, test_name)
+    mask = image_tools.InflateMask(image_tools.CreateMask(images), 7)
     self.UploadImage(posixpath.join(path, 'expected.png'), images[0])
     self.UploadImage(posixpath.join(path, 'mask.png'), mask)
 
-  def RunTest(self, test_name, run_name, actual):
+  def RunTest(self, batch_name, test_name, actual):
     """Runs an image comparison, and uploads discrepancies to GCS.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the name of the test to run.
       run_name: the name of this run of the test.
       actual: an RGB-encoded PIL.Image that is the actual result of the
@@ -76,15 +84,24 @@
     Raises:
       cloud_bucket.NotFoundError: if the given test_name is not found.
     """
-    path = posixpath.join('failures', test_name, run_name)
-    test = self.GetTest(test_name)
-    if not image_tools.SameImage(actual, test.expected):
+    path = posixpath.join('failures', batch_name, test_name)
+    test = self.GetTest(batch_name, test_name)
+    if not image_tools.SameImage(actual, test.expected, mask=test.mask):
       self.UploadImage(posixpath.join(path, 'actual.png'), actual)
+      diff = image_tools.VisualizeImageDifferences(
+          test.expected, actual, mask=test.mask)
+      diff_pxls = sum(1 if pxl == (255, 255, 255, 255) else 0
+                      for pxl in diff.getdata())
+      self.UploadImage(posixpath.join(path, 'diff.png'), diff)
+      self.cloud_bucket.UploadFile(
+          posixpath.join(path, 'info.txt'),
+          json.dumps({'different_pixels': diff_pxls}), 'application/json')
 
-  def GetTest(self, test_name):
+  def GetTest(self, batch_name, test_name):
     """Returns given test from GCS.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the name of the test to get from GCS.
 
     Returns:
@@ -93,71 +110,79 @@
     Raises:
       cloud_bucket.NotFoundError: if the test is not found in GCS.
     """
-    path = posixpath.join('tests', test_name)
+    path = posixpath.join('tests', batch_name, test_name)
     Test = collections.namedtuple('Test', ['expected', 'mask'])
     return Test(self.DownloadImage(posixpath.join(path, 'expected.png')),
                 self.DownloadImage(posixpath.join(path, 'mask.png')))
 
-  def TestExists(self, test_name):
+  def TestExists(self, batch_name, test_name):
     """Returns whether the given test exists in GCS.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the name of the test to look for.
 
     Returns:
       A boolean indicating whether the test exists.
     """
-    path = posixpath.join('tests', test_name)
+    path = posixpath.join('tests', batch_name, test_name)
     expected_image_exists = self.cloud_bucket.FileExists(
         posixpath.join(path, 'expected.png'))
     mask_image_exists = self.cloud_bucket.FileExists(
         posixpath.join(path, 'mask.png'))
     return expected_image_exists and mask_image_exists
 
-  def FailureExists(self, test_name, run_name):
+  def FailureExists(self, batch_name, test_name):
     """Returns whether the given run exists in GCS.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the name of the test that failed.
       run_name: the name of the run that the given test failed on.
 
     Returns:
       A boolean indicating whether the failure exists.
     """
-    failure_path = posixpath.join('failures', test_name, run_name)
+    failure_path = posixpath.join('failures', batch_name, test_name)
     actual_image_exists = self.cloud_bucket.FileExists(
         posixpath.join(failure_path, 'actual.png'))
-    return self.TestExists(test_name) and actual_image_exists
+    test_exists = self.TestExists(batch_name, test_name)
+    info_exists = self.cloud_bucket.FileExists(
+        posixpath.join(failure_path, 'info.txt'))
+    return test_exists and actual_image_exists and info_exists
 
-  def RemoveTest(self, test_name):
+  def RemoveTest(self, batch_name, test_name):
     """Removes a Test from GCS, and all associated failures with that test.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the name of the test to remove.
     """
-    test_path = posixpath.join('tests', test_name)
-    failure_path = posixpath.join('failures', test_name)
+    test_path = posixpath.join('tests', batch_name, test_name)
+    failure_path = posixpath.join('failures', batch_name, test_name)
     test_paths = self.cloud_bucket.GetAllPaths(test_path)
     failure_paths = self.cloud_bucket.GetAllPaths(failure_path)
     for path in itertools.chain(failure_paths, test_paths):
       self.cloud_bucket.RemoveFile(path)
 
-  def RemoveFailure(self, test_name, run_name):
+  def RemoveFailure(self, batch_name, test_name):
     """Removes a failure from GCS.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the test on which the failure to be removed occured.
       run_name: the name of the run on the given test that failed.
     """
-    failure_path = posixpath.join('failures', test_name, run_name)
+    failure_path = posixpath.join('failures', batch_name, test_name)
     failure_paths = self.cloud_bucket.GetAllPaths(failure_path)
     for path in failure_paths:
       self.cloud_bucket.RemoveFile(path)
 
-  def GetFailure(self, test_name, run_name):
+  def GetFailure(self, batch_name, test_name):
     """Returns a given test failure's expected, diff, and actual images.
 
     Args:
+      batch_name: the name of the batch.
       test_name: the name of the test the result corresponds to.
       run_name: the name of the result on the given test.
 
@@ -168,15 +193,17 @@
     Raises:
       cloud_bucket.NotFoundError: if the result is not found in GCS.
     """
-    test_path = posixpath.join('tests', test_name)
-    failure_path = posixpath.join('failures', test_name, run_name)
+    test_path = posixpath.join('tests', batch_name, test_name)
+    failure_path = posixpath.join('failures', batch_name, test_name)
     expected = self.DownloadImage(posixpath.join(test_path, 'expected.png'))
-    mask = self.DownloadImage(posixpath.join(test_path, 'mask.png'))
     actual = self.DownloadImage(posixpath.join(failure_path, 'actual.png'))
-    diff = image_tools.VisualizeImageDifferences(
-        expected, actual, mask=mask)
-    Failure = collections.namedtuple('Failure', ['expected', 'diff', 'actual'])
-    return Failure(expected, diff, actual)
+    diff = self.DownloadImage(posixpath.join(failure_path, 'diff.png'))
+    info = json.loads(self.cloud_bucket.DownloadFile(
+        posixpath.join(failure_path, 'info.txt')))
+    Failure = collections.namedtuple(
+        'Failure',
+        ['expected', 'diff', 'actual', 'info'])
+    return Failure(expected, diff, actual, info)
 
   def GetAllPaths(self, prefix):
     """Gets urls to all files in GCS whose path starts with a given prefix.
diff --git a/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager_unittest.py b/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager_unittest.py
index 843ab38..a0661f0 100644
--- a/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager_unittest.py
+++ b/chrome/test/functional/ispy/ispy_core/tools/rendering_test_manager_unittest.py
@@ -2,10 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import os
 from PIL import Image
-import unittest
 import sets
+import sys
+import unittest
 
+
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
 from tests.rendering_test_manager import mock_cloud_bucket
 from tests.rendering_test_manager import cloud_bucket
 from tools import rendering_test_manager
@@ -18,9 +22,9 @@
     # Set up structures that will be reused throughout testing.
     self.bucket = mock_cloud_bucket.MockCloudBucket()
     self.manager = rendering_test_manager.RenderingTestManager(self.bucket)
-    self.white = Image.new('RGB', (25, 25), (255, 255, 255))
-    self.red = Image.new('RGB', (25, 25), (255, 0, 0))
-    self.black = Image.new('RGB', (25, 25), (0, 0, 0))
+    self.white = Image.new('RGBA', (25, 25), (255, 255, 255, 255))
+    self.red = Image.new('RGBA', (25, 25), (255, 0, 0, 255))
+    self.black = Image.new('RGBA', (25, 25), (0, 0, 0, 255))
 
   def testUploadImage(self):
     self.bucket.Reset()
@@ -30,11 +34,11 @@
     self.manager.UploadImage('path/to/red.png', self.red)
     # Confirm that the images actually got uploaded.
     self.assertEquals(self.bucket.datastore['path/to/white.png'],
-                      image_tools.SerializeImage(self.white))
+                      image_tools.SerializeImage(self.white).decode('base64'))
     self.assertEquals(self.bucket.datastore['path/to/black.png'],
-                      image_tools.SerializeImage(self.black))
+                      image_tools.SerializeImage(self.black).decode('base64'))
     self.assertEquals(self.bucket.datastore['path/to/red.png'],
-                      image_tools.SerializeImage(self.red))
+                      image_tools.SerializeImage(self.red).decode('base64'))
 
   def testDownloadImage(self):
     self.bucket.Reset()
@@ -64,39 +68,39 @@
   def testUploadTest(self):
     self.bucket.Reset()
     # Upload some tests to the datastore.
-    self.manager.UploadTest('test1', [self.white, self.black])
-    self.manager.UploadTest('test2', [self.black, self.black])
+    self.manager.UploadTest('batch', 'test1', [self.white, self.black])
+    self.manager.UploadTest('batch', 'test2', [self.black, self.black])
     # Confirm that the tests were successfully uploaded.
-    self.assertEquals(self.bucket.datastore['tests/test1/expected.png'],
-                      image_tools.SerializeImage(self.white))
-    self.assertEquals(self.bucket.datastore['tests/test1/mask.png'],
-                      image_tools.SerializeImage(self.white))
-    self.assertEquals(self.bucket.datastore['tests/test2/expected.png'],
-                      image_tools.SerializeImage(self.black))
-    self.assertEquals(self.bucket.datastore['tests/test2/mask.png'],
-                      image_tools.SerializeImage(self.black))
+    self.assertEquals(self.bucket.datastore['tests/batch/test1/expected.png'],
+                      image_tools.SerializeImage(self.white).decode('base64'))
+    self.assertEquals(self.bucket.datastore['tests/batch/test1/mask.png'],
+                      image_tools.SerializeImage(self.white).decode('base64'))
+    self.assertEquals(self.bucket.datastore['tests/batch/test2/expected.png'],
+                      image_tools.SerializeImage(self.black).decode('base64'))
+    self.assertEquals(self.bucket.datastore['tests/batch/test2/mask.png'],
+                      image_tools.SerializeImage(self.black).decode('base64'))
 
   def testRunTest(self):
     self.bucket.Reset()
 
-    self.manager.UploadTest('test1', [self.red, self.red])
-    self.manager.RunTest('test1', 'run1', self.black)
+    self.manager.UploadTest('batch', 'test1', [self.red, self.red])
+    self.manager.RunTest('batch', 'test1', 'run1', self.black)
     self.assertEquals(
-        self.bucket.datastore['failures/test1/run1/actual.png'],
-        image_tools.SerializeImage(self.black))
-    self.manager.RunTest('test1', 'run2', self.red)
+        self.bucket.datastore['failures/batch/test1/run1/actual.png'],
+        image_tools.SerializeImage(self.black).decode('base64'))
+    self.manager.RunTest('batch', 'test1', 'run2', self.red)
     self.assertFalse(
-        self.bucket.datastore.has_key('failures/test1/run2/actual.png'))
+        self.bucket.datastore.has_key('failures/batch/test1/run2/actual.png'))
     self.assertRaises(cloud_bucket.FileNotFoundError, self.manager.RunTest,
-                      'test2', 'run1', self.black)
+                      'batch', 'test2', 'run1', self.black)
 
   def testGetTest(self):
     self.bucket.Reset()
     # Upload some tests to the datastore
-    self.manager.UploadTest('test1', [self.white, self.black])
-    self.manager.UploadTest('test2', [self.red, self.white])
-    test1 = self.manager.GetTest('test1')
-    test2 = self.manager.GetTest('test2')
+    self.manager.UploadTest('batch', 'test1', [self.white, self.black])
+    self.manager.UploadTest('batch', 'test2', [self.red, self.white])
+    test1 = self.manager.GetTest('batch', 'test1')
+    test2 = self.manager.GetTest('batch', 'test2')
     # Check that GetTest gets the appropriate tests.
     self.assertEquals(image_tools.SerializeImage(test1.expected),
                       image_tools.SerializeImage(self.white))
@@ -108,55 +112,55 @@
                       image_tools.SerializeImage(self.white))
     # Check that GetTest throws an error for a nonexistant test.
     self.assertRaises(
-        cloud_bucket.FileNotFoundError, self.manager.GetTest, 'test3')
+        cloud_bucket.FileNotFoundError, self.manager.GetTest, 'batch', 'test3')
 
   def testTestExists(self):
     self.bucket.Reset()
-    self.manager.UploadTest('test1', [self.white, self.black])
-    self.manager.UploadTest('test2', [self.white, self.black])
-    self.assertTrue(self.manager.TestExists('test1'))
-    self.assertTrue(self.manager.TestExists('test2'))
-    self.assertFalse(self.manager.TestExists('test3'))
+    self.manager.UploadTest('batch', 'test1', [self.white, self.black])
+    self.manager.UploadTest('batch', 'test2', [self.white, self.black])
+    self.assertTrue(self.manager.TestExists('batch', 'test1'))
+    self.assertTrue(self.manager.TestExists('batch', 'test2'))
+    self.assertFalse(self.manager.TestExists('batch', 'test3'))
 
   def testFailureExists(self):
     self.bucket.Reset()
-    self.manager.UploadTest('test1', [self.white, self.white])
-    self.manager.RunTest('test1', 'run1', self.black)
-    self.manager.RunTest('test1', 'run2', self.white)
-    self.assertTrue(self.manager.FailureExists('test1', 'run1'))
-    self.assertFalse(self.manager.FailureExists('test1', 'run2'))
+    self.manager.UploadTest('batch', 'test1', [self.white, self.white])
+    self.manager.RunTest('batch', 'test1', 'run1', self.black)
+    self.manager.RunTest('batch', 'test1', 'run2', self.white)
+    self.assertTrue(self.manager.FailureExists('batch', 'test1', 'run1'))
+    self.assertFalse(self.manager.FailureExists('batch', 'test1', 'run2'))
 
   def testRemoveTest(self):
     self.bucket.Reset()
-    self.manager.UploadTest('test1', [self.white, self.white])
-    self.manager.UploadTest('test2', [self.white, self.white])
-    self.assertTrue(self.manager.TestExists('test1'))
-    self.assertTrue(self.manager.TestExists('test2'))
-    self.manager.RemoveTest('test1')
-    self.assertFalse(self.manager.TestExists('test1'))
-    self.assertTrue(self.manager.TestExists('test2'))
-    self.manager.RemoveTest('test2')
-    self.assertFalse(self.manager.TestExists('test1'))
-    self.assertFalse(self.manager.TestExists('test2'))
+    self.manager.UploadTest('batch', 'test1', [self.white, self.white])
+    self.manager.UploadTest('batch', 'test2', [self.white, self.white])
+    self.assertTrue(self.manager.TestExists('batch', 'test1'))
+    self.assertTrue(self.manager.TestExists('batch', 'test2'))
+    self.manager.RemoveTest('batch', 'test1')
+    self.assertFalse(self.manager.TestExists('batch', 'test1'))
+    self.assertTrue(self.manager.TestExists('batch', 'test2'))
+    self.manager.RemoveTest('batch', 'test2')
+    self.assertFalse(self.manager.TestExists('batch', 'test1'))
+    self.assertFalse(self.manager.TestExists('batch', 'test2'))
 
   def testRemoveFailure(self):
     self.bucket.Reset()
-    self.manager.UploadTest('test1', [self.white, self.white])
-    self.manager.UploadTest('test2', [self.white, self.white])
-    self.manager.RunTest('test1', 'run1', self.black)
-    self.manager.RunTest('test1', 'run2', self.black)
-    self.manager.RemoveFailure('test1', 'run1')
-    self.assertFalse(self.manager.FailureExists('test1', 'run1'))
-    self.assertTrue(self.manager.TestExists('test1'))
-    self.assertTrue(self.manager.FailureExists('test1', 'run2'))
-    self.assertTrue(self.manager.TestExists('test2'))
+    self.manager.UploadTest('batch', 'test1', [self.white, self.white])
+    self.manager.UploadTest('batch', 'test2', [self.white, self.white])
+    self.manager.RunTest('batch', 'test1', 'run1', self.black)
+    self.manager.RunTest('batch', 'test1', 'run2', self.black)
+    self.manager.RemoveFailure('batch', 'test1', 'run1')
+    self.assertFalse(self.manager.FailureExists('batch', 'test1', 'run1'))
+    self.assertTrue(self.manager.TestExists('batch', 'test1'))
+    self.assertTrue(self.manager.FailureExists('batch', 'test1', 'run2'))
+    self.assertTrue(self.manager.TestExists('batch', 'test2'))
 
   def testGetFailure(self):
     self.bucket.Reset()
     # Upload a result
-    self.manager.UploadTest('test1', [self.red, self.red])
-    self.manager.RunTest('test1', 'run1', self.black)
-    res = self.manager.GetFailure('test1', 'run1')
+    self.manager.UploadTest('batch', 'test1', [self.red, self.red])
+    self.manager.RunTest('batch', 'test1', 'run1', self.black)
+    res = self.manager.GetFailure('batch', 'test1', 'run1')
     # Check that the function correctly got the result.
     self.assertEquals(image_tools.SerializeImage(res.expected),
                       image_tools.SerializeImage(self.red))
@@ -167,27 +171,27 @@
     # Check that the function raises an error when given non-existant results.
     self.assertRaises(cloud_bucket.FileNotFoundError,
                       self.manager.GetFailure,
-                      'test1', 'run2')
+                      'batch', 'test1', 'run2')
     self.assertRaises(cloud_bucket.FileNotFoundError,
                       self.manager.GetFailure,
-                      'test2', 'run1')
+                      'batch', 'test2', 'run1')
 
   def testGetAllPaths(self):
     self.bucket.Reset()
     # Upload some tests.
-    self.manager.UploadTest('test1', [self.white, self.black])
-    self.manager.UploadTest('test2', [self.red, self.white])
+    self.manager.UploadTest('batch', 'test1', [self.white, self.black])
+    self.manager.UploadTest('batch', 'test2', [self.red, self.white])
     # Check that the function gets all urls matching the prefix.
     self.assertEquals(
-        sets.Set(self.manager.GetAllPaths('tests/test')),
-        sets.Set(['tests/test1/expected.png',
-                  'tests/test1/mask.png',
-                  'tests/test2/expected.png',
-                  'tests/test2/mask.png']))
-    self.assertEquals(sets.Set(self.manager.GetAllPaths('tests/test1')),
-                      sets.Set(['tests/test1/expected.png',
-                                'tests/test1/mask.png']))
-    self.assertEquals(sets.Set(self.manager.GetAllPaths('tests/test3')),
+        sets.Set(self.manager.GetAllPaths('tests/batch/test')),
+        sets.Set(['tests/batch/test1/expected.png',
+                  'tests/batch/test1/mask.png',
+                  'tests/batch/test2/expected.png',
+                  'tests/batch/test2/mask.png']))
+    self.assertEquals(sets.Set(self.manager.GetAllPaths('tests/batch/test1')),
+                      sets.Set(['tests/batch/test1/expected.png',
+                                'tests/batch/test1/mask.png']))
+    self.assertEquals(sets.Set(self.manager.GetAllPaths('tests/batch/test3')),
                       sets.Set())
 
 
diff --git a/chrome/test/functional/ispy/ispy_core/tools/reverse_port_forwarder.py b/chrome/test/functional/ispy/ispy_core/tools/reverse_port_forwarder.py
index 289c116..0c45152 100644
--- a/chrome/test/functional/ispy/ispy_core/tools/reverse_port_forwarder.py
+++ b/chrome/test/functional/ispy/ispy_core/tools/reverse_port_forwarder.py
@@ -14,7 +14,6 @@
                              os.pardir, os.pardir, 'build', 'android'))
 from pylib import android_commands
 from pylib import forwarder
-from pylib import valgrind_tools
 
 
 class ReversePortForwarder(object):
@@ -54,16 +53,15 @@
     self._adb = android_commands.AndroidCommands(self._device_serial)
     self._adb.StartAdbServer()
     # Begin forwarding the device_ports to the host_ports.
-    self._forwarder = forwarder.Forwarder(self._cmd, 'Release')
-    self._forwarder.Run([
-        (self._device_http, self._host_http),
-        (self._device_https, self._host_https)],
-                        valgrind_tools.BaseTool())
+    forwarder.Forwarder.Map([(self._device_http, self._host_http),
+                             (self._device_https, self._host_https)],
+                            self._adb, build_type='Release', tool=None)
 
   def Stop(self):
     """Cleans up after the start call by closing the forwarder."""
     # shut down the forwarder.
-    self._forwarder.Close()
+    forwarder.Forwarder.UnmapDevicePort(self._device_http, self._adb)
+    forwarder.Forwarder.UnmapDevicePort(self._device_https, self._adb)
 
   def GetChromeArgs(self):
     """Makes a list of arguments to enable reverse port forwarding on chrome.
@@ -73,5 +71,5 @@
     """
     args = ['testing-fixed-http-port=%s' % self._device_http,
             'testing-fixed-https-port=%s' % self._device_https,
-            'host-resolver-rules=\'MAP * 127.0.0.1,EXCEPT, localhost\'']
+            'host-resolver-rules=\"MAP * 127.0.0.1,EXCEPT, localhost\"']
     return args
diff --git a/tools/perf/page_sets/blank_page.html b/chrome/test/functional/ispy/ispy_core/views/__init__.py
similarity index 100%
copy from tools/perf/page_sets/blank_page.html
copy to chrome/test/functional/ispy/ispy_core/views/__init__.py
diff --git a/chrome/test/functional/ispy/ispy_core/views/debug_view.html b/chrome/test/functional/ispy/ispy_core/views/debug_view.html
new file mode 100644
index 0000000..e5eb1cf
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/views/debug_view.html
@@ -0,0 +1,71 @@
+<html>
+  <head>
+    <style>
+      .hidden {
+        display: none;
+      }
+    </style>
+    <script>
+      // Set up a getImageData function.
+      var getImageData = function(id) {
+        // Set up an image with the src from the img_id.
+        var image = new Image();
+        image.src = document.getElementById(id).src;
+        // Create a canvas in memeory to hold the image.
+        var mem_canvas = document.createElement('canvas');
+        mem_canvas.setAttribute('width', image.width.toString());
+        mem_canvas.setAttribute('height', image.height.toString());
+        var mem_context = mem_canvas.getContext('2d');
+        // Draw the image into the canvas.
+        mem_context.drawImage(image, 0, 0);
+        // Extract the image from the canvas in editable form.
+        return mem_context.getImageData(0, 0, image.width, image.height);
+      };
+      // Set up a function to generate the image to be displayed.
+      var computeDiffAlpha = function(expected, diff, actual) {
+        // Go through all of the pixels in the diff.
+        for(var i=0; i<diff.data.length; i += 4) {
+          // If the pixel in the diff isn't white, use the expected pixel.
+          if ((diff.data[i] == 255 && diff.data[i + 1] == 255 &&
+               diff.data[i + 2] == 255 && diff.data[i + 3] == 255)) {
+            // If the diff pixel is not white, it should not be seen.
+            expected.data[i] = actual.data[i];
+            expected.data[i + 1] = actual.data[i + 1];
+            expected.data[i + 2] = actual.data[i + 2];
+            expected.data[i + 3] = actual.data[i + 3];
+          }
+          // Otherwise don't touch the actual_data pixel.
+        }
+        // Return the modified pixel data.
+        return expected;
+      };
+      // Set everything up to run after the document loads.
+      var loader = function() {    
+        var canvas = document.getElementById('image');
+        var context = canvas.getContext('2d');
+        var expected = getImageData('expected');
+        var diff = getImageData('diff');
+        var debug = computeDiffAlpha(getImageData('expected'), diff, getImageData('actual'));
+        var state = 'expected';
+        canvas.width = diff.width;
+        canvas.height = diff.height;
+        var swapper = setInterval(function() {                         
+          if (state === 'expected') {
+            state = 'debug';
+            context.putImageData(expected, 0, 0);
+          }
+          else {
+            state = 'expected';
+            context.putImageData(debug, 0, 0);
+          }
+        }, 1000);
+      };
+    </script>
+  </head>
+  <body onload="loader();">
+    <img class='hidden' id='expected' src="{{ expected }}"/>
+    <img class='hidden' id='diff' src="{{ diff }}"/>
+    <img class='hidden' id='actual' src="{{ actual }}"/>
+    <canvas id='image'></canvas>
+  </body>
+</html>
diff --git a/chrome/test/functional/ispy/ispy_core/views/diff_view.html b/chrome/test/functional/ispy/ispy_core/views/diff_view.html
new file mode 100644
index 0000000..6cf1083
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/views/diff_view.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html> 
+{% autoescape true %}
+<html>
+  <head>
+    <style>
+      #container {
+        display: table;
+        background-color:#A8A8A8;
+        border:2px solid black;
+      }
+      #row {
+        display: table-row;
+      }
+      #left, #right, #middle {
+        display: table-cell;
+        padding-right: 25px;
+        padding-left: 25px;
+      }
+      #left p, #right p, #middle p {
+        margin: 1px 1px;
+      }
+      #title {
+        display: block;
+        text-align: center;
+      }
+      #info-box {
+        background-color:#A8A8A8;
+        border:2px solid black;
+        display: block;
+        width: 400px;
+      }
+      .image {
+        width: 300px;
+      }
+    </style>
+  </head>
+  <body>
+    <span id="info-box"> Device: {{ device }}<br>
+                         Site: {{ site }}<br>
+                         Device_ID: {{ device_id }}</span>
+    <form action="/update_mask?{{ encoded_parameters }}" method="post">
+      <input type="submit" value="Ignore Diff"/>
+    </form>
+    <div id="container">
+      <div id="row">
+        <div id="left">
+          <span id="title">Expected</span><br>
+          <img class="image" src="{{ expected }}"> 
+        </div>
+        <div id="center">
+          <span id="title">Diff</span><br>
+          <img class="image" src="{{ diff }}">
+        </div>
+        <div id="right">
+          <span id="title">Actual</span><br>
+          <img class="image" src="{{ actual }}"> 
+        </div>
+      </div>
+    </div>
+  </body>
+</html>
+{% endautoescape %}
diff --git a/chrome/test/functional/ispy/ispy_core/views/list_view.html b/chrome/test/functional/ispy/ispy_core/views/list_view.html
new file mode 100644
index 0000000..fdbcab0
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/views/list_view.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+{% autoescape on %}
+<html>
+  <head>
+    <style>
+      #container {
+        display: table;
+        background-color:#A8A8A8;
+        border:2px solid black;
+        width: 600px
+      }
+      #row {
+        display: table-row;
+        border 1px solid gray;
+        width: 400px;
+        height: 25px;
+        border: 2px solid black;
+      }
+      #col {
+        display: table-cell;
+        padding-right: 25px;
+        padding-left: 25px;
+      }
+    </style>
+  </head>
+  <body>
+    <div id="container">
+      {% for link in links %}
+        <span id="row">
+          <a href="{{ link[1] }}">{{ link[0] }}</a>
+        </span>
+      {% endfor %}
+    </div>
+  </body>
+</html>
+{% endautoescape %}
diff --git a/chrome/test/functional/ispy/ispy_core/views/main_view.html b/chrome/test/functional/ispy/ispy_core/views/main_view.html
new file mode 100644
index 0000000..cd61d0c
--- /dev/null
+++ b/chrome/test/functional/ispy/ispy_core/views/main_view.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      .image {
+        height: 325px;
+      }
+      .cell {
+        padding-right: 25px;
+        padding-left: 25px;
+        float: left;
+      }
+      .info {
+        background-color:#A8A8A8;
+        width: 300px;
+      }
+      .row {
+        padding-top: 10px;
+        padding-bottom: 10px;
+        border-bottom: 2px solid black;
+        height: 350px;
+      }
+    </style>
+  </head>
+  <body>
+    {% for comp in comparisons %}
+      <div class="row">
+        <div class="cell">
+          Diff<br>
+          <img class="image" src={{ comp['diff'] }}>
+        </div>
+        <div class="cell">
+          Expected<br>
+          <img class="image" src={{ comp['expected'] }}>
+        </div>
+        <div class="cell">
+          Actual<br>
+          <img class="image" src={{ comp['actual'] }}>
+        </div>
+        <div class="cell">
+          <br>
+          <div class="info">
+            Test Name: {{ comp['test_name'] }}<br>
+            Run Name: {{ comp['run_name'] }}
+          </div>
+          <form action="/update_mask" method="post">
+            <input type="hidden" name="batch_name" value="{{ comp['batch_name'] }}"/>
+            <input type="hidden" name="test_name" value="{{ comp['test_name'] }}"/>
+            <input type="hidden" name="run_name" value="{{ comp['run_name'] }}"/>
+            <input type="submit" value="Ignore Diff"/>
+          </form>
+          <a href='/debug_view?diff={{ comp['diff_path'] }}&actual={{ comp['actual_path'] }}&expected={{ comp['expected_path'] }}'>Debug View</a>
+        </div>
+      </div>
+    {% endfor %}
+  </body>
+</html>
diff --git a/chrome/test/functional/media_stream_infobar.py b/chrome/test/functional/media_stream_infobar.py
deleted file mode 100755
index 686882a..0000000
--- a/chrome/test/functional/media_stream_infobar.py
+++ /dev/null
@@ -1,83 +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 pyauto_functional
-import pyauto
-import webrtc_test_base
-
-
-class MediaStreamInfobarTest(webrtc_test_base.WebrtcTestBase):
-  """Performs basic tests on the media stream infobar.
-
-  This infobar is used to grant or deny access to WebRTC capabilities for a
-  webpage. If a page calls the getUserMedia function the infobar will ask the
-  user if it is OK for the webpage to use the webcam or microphone on the user's
-  machine. These tests ensure that the infobar works as intended.
-  """
-
-  def ExtraChromeFlags(self):
-    """Adds flags to the Chrome command line."""
-    extra_flags = ['--enable-media-stream']
-    return pyauto.PyUITest.ExtraChromeFlags(self) + extra_flags
-
-  def testAllowingUserMedia(self):
-    """Test that selecting 'accept' gives us a media stream.
-
-    When the user clicks allow, the javascript should have the success callback
-    called with a media stream.
-    """
-    self.assertEquals('ok-got-stream',
-                      self._TestGetUserMedia(with_action='accept'))
-
-  def testDenyingUserMedia(self):
-    """Tests that selecting 'cancel' actually denies access to user media.
-
-    When the user clicks deny in the user media bar, the javascript should have
-    the error callback called with an error specification instead of the success
-    callback with a media stream. This is important since the user should be
-    able to deny the javascript to access the webcam.
-    """
-    # Error 1 = Permission denied
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self._TestGetUserMedia(with_action='cancel'))
-
-  def testDismissingUserMedia(self):
-    """Dismiss should be treated just like deny, which is described above."""
-    # Error 1 = Permission denied
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self._TestGetUserMedia(with_action='dismiss'))
-
-  def testConsecutiveGetUserMediaCalls(self):
-    """Ensures we deal appropriately with several consecutive requests."""
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self._TestGetUserMedia(with_action='dismiss'))
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self._TestGetUserMedia(with_action='cancel'))
-    self.assertEquals('ok-got-stream',
-                      self._TestGetUserMedia(with_action='accept'))
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self._TestGetUserMedia(with_action='cancel'))
-    self.assertEquals('ok-got-stream',
-                      self._TestGetUserMedia(with_action='accept'))
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self._TestGetUserMedia(with_action='dismiss'))
-
-  def _TestGetUserMedia(self, with_action):
-    """Runs getUserMedia in the test page and returns the result."""
-    url = self.GetFileURLForDataPath('webrtc', 'webrtc_jsep01_test.html')
-    self.NavigateToURL(url)
-
-    self.assertEquals('ok-requested', self.ExecuteJavascript(
-        'getUserMedia("{ audio: true, video: true, }")'))
-
-    self.WaitForInfobarCount(1)
-    self.PerformActionOnInfobar(with_action, infobar_index=0)
-    self.WaitForGetUserMediaResult(tab_index=0)
-
-    return self.GetUserMediaResult(tab_index=0)
-
-
-if __name__ == '__main__':
-  pyauto_functional.Main()
diff --git a/chrome/test/functional/webrtc_apprtc_call.py b/chrome/test/functional/webrtc_apprtc_call.py
deleted file mode 100755
index 986fa21..0000000
--- a/chrome/test/functional/webrtc_apprtc_call.py
+++ /dev/null
@@ -1,71 +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 random
-import time
-
-# Note: pyauto_functional must come before pyauto.
-import pyauto_functional
-import pyauto
-import webrtc_test_base
-
-
-class WebrtcApprtcCallTest(webrtc_test_base.WebrtcTestBase):
-  """Tests calling apprtc.appspot.com and setting up a call.
-
-  Prerequisites: This test case must run on a machine with a webcam, either
-  fake or real, and with some kind of audio device. The machine must have access
-  to the public Internet.
-
-  This should be considered an integration test: test failures could mean
-  that the AppRTC reference is broken, that WebRTC is broken, or both.
-  """
-
-  def tearDown(self):
-    pyauto.PyUITest.tearDown(self)
-    self.assertEquals('', self.CheckErrorsAndCrashes(),
-                      'Chrome crashed or hit a critical error during test.')
-
-  def testApprtcLoopbackCall(self):
-    self.NavigateToURL('http://apprtc.appspot.com/?debug=loopback')
-    self.WaitForInfobarCount(1, tab_index=0)
-    self.PerformActionOnInfobar('accept', infobar_index=0, tab_index=0)
-
-    self._WaitForCallEstablishment(tab_index=0)
-
-  def testApprtcTabToTabCall(self):
-    # Randomize the call session id. If we would use the same id we would risk
-    # getting problems with hung calls and lingering state in AppRTC.
-    random_call_id = 'pyauto%d' % random.randint(0, 65536)
-    apprtc_url = 'http://apprtc.appspot.com/?r=%s' % random_call_id
-
-    self.NavigateToURL(apprtc_url)
-    self.AppendTab(pyauto.GURL(apprtc_url))
-
-    self.WaitForInfobarCount(1, tab_index=0)
-    self.WaitForInfobarCount(1, tab_index=1)
-
-    self.PerformActionOnInfobar('accept', infobar_index=0, tab_index=0)
-    # TODO(phoglund): workaround for
-    # https://code.google.com/p/webrtc/issues/detail?id=1742
-    time.sleep(1)
-    self.PerformActionOnInfobar('accept', infobar_index=0, tab_index=1)
-
-    self._WaitForCallEstablishment(tab_index=0)
-    self._WaitForCallEstablishment(tab_index=1)
-
-  def _WaitForCallEstablishment(self, tab_index):
-    # AppRTC will set opacity to 1 for remote video when the call is up.
-    video_playing = self.WaitUntil(
-        function=lambda: self.GetDOMValue('remoteVideo.style.opacity',
-                                          tab_index=tab_index),
-        expect_retval='1')
-    self.assertTrue(video_playing,
-                    msg=('Timed out while waiting for '
-                         'remoteVideo.style.opacity to return 1.'))
-
-
-if __name__ == '__main__':
-  pyauto_functional.Main()
diff --git a/chrome/test/functional/webrtc_audio_quality.py b/chrome/test/functional/webrtc_audio_quality.py
deleted file mode 100755
index 8e1cff4..0000000
--- a/chrome/test/functional/webrtc_audio_quality.py
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/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 os
-import sys
-import tempfile
-import time
-
-import media.audio_tools as audio_tools
-
-# Note: pyauto_functional must come before pyauto.
-import pyauto_functional
-import pyauto
-import pyauto_utils
-import webrtc_test_base
-
-_MEDIA_PATH = os.path.abspath(os.path.join(pyauto.PyUITest.DataDir(),
-                                           'pyauto_private', 'webrtc'))
-if 'win32' in sys.platform:
-  _REFERENCE_FILE = os.path.join(_MEDIA_PATH, 'human-voice-win.wav')
-else:
-  _REFERENCE_FILE = os.path.join(_MEDIA_PATH, 'human-voice-linux.wav')
-_JAVASCRIPT_PATH = os.path.abspath(os.path.join(pyauto.PyUITest.DataDir(),
-                                                'webrtc'))
-
-
-class WebrtcAudioQualityTest(webrtc_test_base.WebrtcTestBase):
-  """Test we can set up a WebRTC call and play audio through it.
-
-  This test will only work on machines that have been configured to record their
-  own input*.
-
-  * On Linux:
-    1. # sudo apt-get install pavucontrol
-    2. For the user who will run the test: # pavucontrol
-    3. In a separate terminal, # arecord dummy
-    4. In pavucontrol, go to the recording tab.
-    5. For the ALSA plug-in [aplay]: ALSA Capture from, change from <x> to
-       <Monitor of x>, where x is whatever your primary sound device is called.
-    6. Try launching chrome as the target user on the target machine, try
-       playing, say, a YouTube video, and record with # arecord -f dat mine.dat.
-       Verify the recording with aplay (should have recorded what you played
-       from chrome).
-
-  * On Windows 7:
-    1. Control panel > Sound > Manage audio devices.
-    2. In the recording tab, right-click in an empty space in the pane with the
-       devices. Tick 'show disabled devices'.
-    3. You should see a 'stero mix' device - this is what your speakers output.
-       Right click > Properties.
-    4. In the Listen tab for the mix device, check the 'listen to this device'
-       checkbox. Ensure the mix device is the default recording device.
-    5. Launch chrome and try playing a video with sound. You should see movement
-       in the volume meter for the mix device. Configure the mix device to have
-       50 / 100 in level. Also go into the playback tab, right-click Speakers,
-       and set that level to 50 / 100. Otherwise you will get distortion in
-       the recording.
-  """
-  def setUp(self):
-    pyauto.PyUITest.setUp(self)
-    self.StartPeerConnectionServer()
-
-  def tearDown(self):
-    self.StopPeerConnectionServer()
-
-    pyauto.PyUITest.tearDown(self)
-    self.assertEquals('', self.CheckErrorsAndCrashes())
-
-  def testWebrtcAudioCallAndMeasureQuality(self):
-    """Measures how much WebRTC distorts speech.
-
-    The input file is about 9.3 seconds long and has had silence trimmed on both
-    sides. We will set up a WebRTC call, load the file with WebAudio in the
-    javascript, connect the WebAudio buffer node to the peer connection and play
-    it out on the other side (in a video tag).
-
-    We originally got the input file by playing a file through this test and
-    using the resulting file. The purpose is to lessen the impact on the score
-    from known distortions such as comfort noise. You can do such a rebase on
-    the _REFERENCE_FILE by setting REBASE=1 before running the test. The file
-    will end up in the system temp folder and will end with _webrtc.wav.
-
-    We then record what Chrome plays out. We give it plenty of time to play
-    the whole file over the connection, and then we trim silence on both ends.
-    That is finally fed into PESQ for comparison.
-    """
-    # We'll use a relative path since the javascript will be loading the file
-    # relative to where the javascript itself is.
-    self.assertTrue(os.path.exists(_MEDIA_PATH),
-                    msg='Missing pyauto_private in chrome/test/data: you need '
-                        'to check out src_internal in your .gclient to run '
-                        'this test.')
-
-    input_relative_path = os.path.relpath(_REFERENCE_FILE, _JAVASCRIPT_PATH)
-
-    def CallWithWebAudio():
-      self._AudioCallWithWebAudio(duration_seconds=15,
-                                  input_relative_path=input_relative_path)
-
-    def MeasureQuality(output_no_silence):
-      results = audio_tools.RunPESQ(_REFERENCE_FILE, output_no_silence,
-                                    sample_rate=16000)
-      self.assertTrue(results, msg=('Failed to compute PESQ (most likely, we '
-                                    'recorded only silence)'))
-      pyauto_utils.PrintPerfResult('audio_pesq', 'raw_mos', results[0], 'score')
-      pyauto_utils.PrintPerfResult('audio_pesq', 'mos_lqo', results[1], 'score')
-
-    self._RecordAndVerify(record_duration_seconds=20,
-                          sound_producing_function=CallWithWebAudio,
-                          verification_function=MeasureQuality)
-
-  def _AudioCallWithWebAudio(self, duration_seconds, input_relative_path):
-    self.LoadTestPageInTwoTabs(test_page='webrtc_audio_quality_test.html');
-
-    self.Connect('user_1', tab_index=0)
-    self.Connect('user_2', tab_index=1)
-
-    self.CreatePeerConnection(tab_index=0)
-    self.AddWebAudioFile(tab_index=0, input_relative_path=input_relative_path)
-
-    self.EstablishCall(from_tab_with_index=0, to_tab_with_index=1)
-
-    # Note: the media flow isn't necessarily established on the connection just
-    # because the ready state is ok on both sides. We sleep a bit between call
-    # establishment and playing to avoid cutting of the beginning of the audio
-    # file.
-    time.sleep(2)
-    self.PlayWebAudioFile(tab_index=0)
-
-    # Keep the call up while we detect audio.
-    time.sleep(duration_seconds)
-
-    # The hang-up will automatically propagate to the second tab.
-    self.HangUp(from_tab_with_index=0)
-    self.WaitUntilHangUpVerified(tab_index=1)
-
-    self.Disconnect(tab_index=0)
-    self.Disconnect(tab_index=1)
-
-    # Ensure we didn't miss any errors.
-    self.AssertNoFailures(tab_index=0)
-    self.AssertNoFailures(tab_index=1)
-
-  def _RecordAndVerify(self, record_duration_seconds, sound_producing_function,
-                       verification_function):
-    audio_tools.ForceMicrophoneVolumeTo100Percent()
-    rebase = 'REBASE' in os.environ
-
-    # The two temp files that will be potentially used in the test.
-    temp_file = None
-    file_no_silence = None
-    try:
-      temp_file = self._CreateTempFile()
-      record_thread = audio_tools.AudioRecorderThread(record_duration_seconds,
-                                                      temp_file,
-                                                      record_mono=True)
-      record_thread.start()
-      sound_producing_function()
-      record_thread.join()
-
-      if record_thread.error:
-        self.fail(record_thread.error)
-      file_no_silence = self._CreateTempFile()
-      audio_tools.RemoveSilence(temp_file, file_no_silence)
-
-      verification_function(file_no_silence)
-    finally:
-      # Delete the temporary files used by the test.
-      if temp_file:
-        os.remove(temp_file)
-      if file_no_silence and not rebase:
-        os.remove(file_no_silence)
-
-  def _CreateTempFile(self):
-    """Returns an absolute path to an empty temp file."""
-    file_handle, path = tempfile.mkstemp(suffix='_webrtc.wav')
-    os.close(file_handle)
-    return path
-
-
-if __name__ == '__main__':
-  pyauto_functional.Main()
\ No newline at end of file
diff --git a/chrome/test/functional/webrtc_brutality_test.py b/chrome/test/functional/webrtc_brutality_test.py
deleted file mode 100755
index b5852e2..0000000
--- a/chrome/test/functional/webrtc_brutality_test.py
+++ /dev/null
@@ -1,73 +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 pyauto_functional
-import webrtc_test_base
-
-
-class WebrtcBrutalityTest(webrtc_test_base.WebrtcTestBase):
-  """Tests how WebRTC deals with inconvenient reloads, etc."""
-
-  def testReloadsAfterGetUserMedia(self):
-    """Tests how we deal with reloads.
-
-    This test will quickly reload the page after running getUserMedia, which
-    will remove the pending request. This crashed the browser before the fix
-    for crbug.com/135043.
-
-    The test will make repeated getUserMedia requests with refreshes between
-    them. Sometimes it will click past the bar and then refresh.
-    """
-    if self.PlatformIsWinXP():
-      print 'Skipping this test on Windows XP due to flakiness.'
-      return
-    self.LoadTestPageInOneTab()
-    for i in range(1, 100):
-      if i % 10 == 0:
-        self.GetUserMedia(tab_index=0, action='accept')
-      else:
-        self._GetUserMediaWithoutTakingAction(tab_index=0)
-      self.ReloadTab(tab_index=0)
-
-  def testRepeatedGetUserMediaRequests(self):
-    """Tests how we deal with lots of consecutive getUserMedia requests.
-
-    The test will alternate unanswered requests with requests that get answered.
-    """
-    if self.PlatformIsWinXP():
-      print 'Skipping this test on Windows XP due to flakiness.'
-      return
-    self.LoadTestPageInOneTab()
-    for i in range(1, 100):
-      if i % 10 == 0:
-        self.GetUserMedia(tab_index=0, action='accept')
-      else:
-        self._GetUserMediaWithoutTakingAction(tab_index=0)
-
-  def testSuccessfulGetUserMediaAndThenReload(self):
-    """Waits for WebRTC to respond, and immediately reloads the tab."""
-    self.LoadTestPageInOneTab()
-    self.GetUserMedia(tab_index=0, action='accept')
-    self.ReloadTab(tab_index=0)
-
-  def testClosingTabAfterGetUserMedia(self):
-    """Tests closing the tab right after a getUserMedia call."""
-    self.LoadTestPageInOneTab()
-    self._GetUserMediaWithoutTakingAction(tab_index=0)
-    self.CloseTab(tab_index=0)
-
-  def testSuccessfulGetUserMediaAndThenClose(self):
-    """Waits for WebRTC to respond, and closes the tab."""
-    self.LoadTestPageInOneTab()
-    self.GetUserMedia(tab_index=0, action='accept')
-    self.CloseTab(tab_index=0)
-
-  def _GetUserMediaWithoutTakingAction(self, tab_index):
-    self.assertEquals('ok-requested', self.ExecuteJavascript(
-      'getUserMedia("{ audio: true, video: true, }")', tab_index=0))
-
-
-if __name__ == '__main__':
-  pyauto_functional.Main()
diff --git a/chrome/test/functional/webrtc_call.py b/chrome/test/functional/webrtc_call.py
deleted file mode 100755
index 8c54b11..0000000
--- a/chrome/test/functional/webrtc_call.py
+++ /dev/null
@@ -1,224 +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 time
-
-# This little construct ensures we can run even if we have a bad version of
-# psutil installed. If so, we'll just skip the test that needs it.
-_HAS_CORRECT_PSUTIL_VERSION = False
-try:
-  import psutil
-  if 'version_info' in dir(psutil):
-    # If psutil has any version info at all, it's recent enough.
-    _HAS_CORRECT_PSUTIL_VERSION = True
-except ImportError, e:
-  pass
-
-
-# Note: pyauto_functional must come before pyauto.
-import pyauto_functional
-import pyauto
-import pyauto_utils
-import webrtc_test_base
-
-
-class WebrtcCallTest(webrtc_test_base.WebrtcTestBase):
-  """Test we can set up a WebRTC call and disconnect it.
-
-  Prerequisites: This test case must run on a machine with a webcam, either
-  fake or real, and with some kind of audio device. You must make the
-  peerconnection_server target before you run.
-
-  The test case will launch a custom binary
-  (peerconnection_server) which will allow two WebRTC clients to find each
-  other. For more details, see the source code which is available at the site
-  http://code.google.com/p/libjingle/source/browse/ (make sure to browse to
-  trunk/talk/examples/peerconnection/server).
-  """
-
-  def setUp(self):
-    pyauto.PyUITest.setUp(self)
-    self.StartPeerConnectionServer()
-
-  def tearDown(self):
-    self.StopPeerConnectionServer()
-
-    pyauto.PyUITest.tearDown(self)
-    self.assertEquals('', self.CheckErrorsAndCrashes())
-
-  def _SimpleWebrtcCall(self, request_video, request_audio, duration_seconds=0):
-    """Tests we can call and hang up with WebRTC.
-
-    This test exercises pretty much the whole happy-case for the WebRTC
-    JavaScript API. Currently, it exercises a normal call setup using the API
-    defined at http://dev.w3.org/2011/webrtc/editor/webrtc.html. The API is
-    still evolving.
-
-    The test will load the supplied HTML file, which in turn will load different
-    javascript files depending on which version of the signaling protocol
-    we are running.
-    The supplied HTML file will be loaded in two tabs and tell the web
-    pages to start up WebRTC, which will acquire video and audio devices on the
-    system. This will launch a dialog in Chrome which we click past using the
-    automation controller. Then, we will order both tabs to connect the server,
-    which will make the two tabs aware of each other. Once that is done we order
-    one tab to call the other.
-
-    We make sure that the javascript tells us that the call succeeded, lets it
-    run for a while and try to hang up the call after that. We verify video is
-    playing by using the video detector.
-
-    Args:
-      request_video: Whether to request video.
-      request_audio: Whether to request audio.
-      duration_seconds: The number of seconds to keep the call up before
-        shutting it down.
-    """
-    self._SetupCall(request_video=request_video, request_audio=request_audio)
-
-    if duration_seconds:
-      print 'Call up: sleeping %d seconds...' % duration_seconds
-      time.sleep(duration_seconds);
-
-    # The hang-up will automatically propagate to the second tab.
-    self.HangUp(from_tab_with_index=0)
-    self.WaitUntilHangUpVerified(tab_index=1)
-
-    self.Disconnect(tab_index=0)
-    self.Disconnect(tab_index=1)
-
-    # Ensure we didn't miss any errors.
-    self.AssertNoFailures(tab_index=0)
-    self.AssertNoFailures(tab_index=1)
-
-  def testWebrtcCall(self):
-    self.LoadTestPageInTwoTabs()
-    self._SimpleWebrtcCall(request_video=True, request_audio=True)
-
-  def testWebrtcVideoOnlyCall(self):
-    self.LoadTestPageInTwoTabs()
-    self._SimpleWebrtcCall(request_video=True, request_audio=False)
-
-  def testWebrtcAudioOnlyCall(self):
-    self.LoadTestPageInTwoTabs()
-    self._SimpleWebrtcCall(request_video=False, request_audio=True)
-
-  def testWebrtcJsep01CallAndMeasureCpu20Seconds(self):
-    if not _HAS_CORRECT_PSUTIL_VERSION:
-      print ('WARNING: Can not run cpu/mem measurements with this version of '
-             'psutil. You must have at least psutil 0.4.1 installed for the '
-             'version of python you are running this test with.')
-      return
-
-    self.LoadTestPageInTwoTabs(test_page='webrtc_jsep01_test.html')
-
-    # Prepare CPU measurements.
-    renderer_process = self._GetChromeRendererProcess(tab_index=0)
-    renderer_process.get_cpu_percent()
-
-    self._SimpleWebrtcCall(request_video=True,
-                           request_audio=True,
-                           duration_seconds=20)
-
-    cpu_usage = renderer_process.get_cpu_percent(interval=0)
-    mem_usage_bytes = renderer_process.get_memory_info()[0]
-    mem_usage_kb = float(mem_usage_bytes) / 1024
-    pyauto_utils.PrintPerfResult('cpu', 'jsep01_call', cpu_usage, '%')
-    pyauto_utils.PrintPerfResult('memory', 'jsep01_call', mem_usage_kb, 'KiB')
-
-  def testLocalPreview(self):
-    """Brings up a local preview and ensures video is playing.
-
-    This test will launch a window with a single tab and run a getUserMedia call
-    which will give us access to the webcam and microphone. Then the javascript
-    code will hook up the webcam data to the local-view video tag. We will
-    detect video in that tag using the video detector, and if we see video
-    moving the test passes.
-    """
-    self.LoadTestPageInOneTab()
-    self.assertEquals('ok-got-stream', self.GetUserMedia(tab_index=0))
-    self._StartDetectingVideo(tab_index=0, video_element='local-view')
-
-    self._WaitForVideo(tab_index=0, expect_playing=True)
-
-  def testHandlesNewGetUserMediaRequestSeparately(self):
-    """Ensures WebRTC doesn't allow new requests to piggy-back on old ones."""
-    self.LoadTestPageInTwoTabs()
-
-    self.GetUserMedia(tab_index=0)
-    self.GetUserMedia(tab_index=1)
-    self.Connect("user_1", tab_index=0)
-    self.Connect("user_2", tab_index=1)
-
-    self.CreatePeerConnection(tab_index=0)
-    self.AddUserMediaLocalStream(tab_index=0)
-    self.EstablishCall(from_tab_with_index=0, to_tab_with_index=1)
-
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self.GetUserMedia(tab_index=0, action='cancel'))
-    self.assertEquals('failed-with-error-PERMISSION_DENIED',
-                      self.GetUserMedia(tab_index=0, action='dismiss'))
-
-  def _SetupCall(self, request_video, request_audio):
-    """Gets user media and establishes a call.
-
-    Assumes that two tabs are already opened with a suitable test page.
-
-    Args:
-      request_video: Whether to request video.
-      request_audio: Whether to request audio.
-    """
-    self.assertEquals('ok-got-stream', self.GetUserMedia(
-        tab_index=0, request_video=request_video, request_audio=request_audio))
-    self.assertEquals('ok-got-stream', self.GetUserMedia(
-        tab_index=1, request_video=request_video, request_audio=request_audio))
-    self.Connect('user_1', tab_index=0)
-    self.Connect('user_2', tab_index=1)
-
-    self.CreatePeerConnection(tab_index=0)
-    self.AddUserMediaLocalStream(tab_index=0)
-    self.EstablishCall(from_tab_with_index=0, to_tab_with_index=1)
-
-    if request_video:
-      self._StartDetectingVideo(tab_index=0, video_element='remote-view')
-      self._StartDetectingVideo(tab_index=1, video_element='remote-view')
-
-      self._WaitForVideo(tab_index=0, expect_playing=True)
-      self._WaitForVideo(tab_index=1, expect_playing=True)
-
-  def _StartDetectingVideo(self, tab_index, video_element):
-    self.assertEquals('ok-started', self.ExecuteJavascript(
-        'startDetection("%s", "frame-buffer", 320, 240)' % video_element,
-        tab_index=tab_index));
-
-  def _WaitForVideo(self, tab_index, expect_playing):
-    # TODO(phoglund): Remove this hack if we manage to get a more stable Linux
-    # bot to run these tests.
-    if self.IsLinux():
-      print "Linux; pretending to wait for video..."
-      time.sleep(1)
-      return
-
-    expect_retval='video-playing' if expect_playing else 'video-not-playing'
-
-    video_playing = self.WaitUntil(
-        function=lambda: self.ExecuteJavascript('isVideoPlaying()',
-                                                tab_index=tab_index),
-        expect_retval=expect_retval)
-    self.assertTrue(video_playing,
-                    msg= 'Timed out while waiting for isVideoPlaying to ' +
-                         'return ' + expect_retval + '.')
-
-  def _GetChromeRendererProcess(self, tab_index):
-    """Returns the Chrome renderer process as a psutil process wrapper."""
-    tab_info = self.GetBrowserInfo()['windows'][0]['tabs'][tab_index]
-    renderer_id = tab_info['renderer_pid']
-    if not renderer_id:
-      self.fail('Can not find the tab renderer process.')
-    return psutil.Process(renderer_id)
-
-
-if __name__ == '__main__':
-  pyauto_functional.Main()
diff --git a/chrome/test/functional/webrtc_test_base.py b/chrome/test/functional/webrtc_test_base.py
deleted file mode 100755
index 973691c..0000000
--- a/chrome/test/functional/webrtc_test_base.py
+++ /dev/null
@@ -1,215 +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 platform
-import re
-import subprocess
-
-import pyauto
-
-
-class MissingRequiredBinaryException(Exception):
-  pass
-
-
-class WebrtcTestBase(pyauto.PyUITest):
-  """This base class provides helpers for WebRTC calls."""
-
-  DEFAULT_TEST_PAGE = 'webrtc_jsep01_test.html'
-
-  def ExtraChromeFlags(self):
-    """Adds flags to the Chrome command line."""
-    extra_flags = ['--enable-data-channels', '--enable-dcheck']
-    return pyauto.PyUITest.ExtraChromeFlags(self) + extra_flags
-
-  def LoadTestPageInTwoTabs(self, test_page=DEFAULT_TEST_PAGE):
-    url = self.GetFileURLForDataPath('webrtc', test_page)
-    self.NavigateToURL(url)
-    self.AppendTab(pyauto.GURL(url))
-
-  def LoadTestPageInOneTab(self, test_page=DEFAULT_TEST_PAGE):
-    url = self.GetFileURLForDataPath('webrtc', test_page)
-    self.NavigateToURL(url)
-
-  def GetUserMedia(self, tab_index, action='accept',
-                   request_video=True, request_audio=True):
-    """Acquires webcam or mic for one tab and returns the result.
-
-    Args:
-      tab_index: The tab to request user media on.
-      action: The action to take on the info bar. Can be 'accept', 'cancel' or
-          'dismiss'.
-      request_video: Whether to request video.
-      request_audio: Whether to request audio.
-
-    Returns:
-      A string as specified by the getUserMedia javascript function.
-    """
-    constraints = '{ video: %s, audio: %s }' % (str(request_video).lower(),
-                                                str(request_audio).lower())
-    self.assertEquals('ok-requested', self.ExecuteJavascript(
-        'getUserMedia("%s")' % constraints, tab_index=tab_index))
-
-    self.WaitForInfobarCount(1, tab_index=tab_index)
-    self.PerformActionOnInfobar(action, infobar_index=0, tab_index=tab_index)
-    self.WaitForGetUserMediaResult(tab_index=0)
-
-    result = self.GetUserMediaResult(tab_index=0)
-    self.AssertNoFailures(tab_index)
-    return result
-
-  def WaitForGetUserMediaResult(self, tab_index):
-    """Waits until WebRTC has responded to a getUserMedia query.
-
-    Fails an assert if WebRTC doesn't respond within the default timeout.
-
-    Args:
-      tab_index: the tab to query.
-    """
-    def HasResult():
-      return self.GetUserMediaResult(tab_index) != 'not-called-yet'
-    self.assertTrue(self.WaitUntil(HasResult),
-                    msg='Timed out while waiting for getUserMedia callback.')
-
-  def GetUserMediaResult(self, tab_index):
-    """Retrieves WebRTC's answer to a user media query.
-
-    Args:
-      tab_index: the tab to query.
-
-    Returns:
-      Specified in obtainGetUserMediaResult() in getusermedia.js.
-    """
-    return self.ExecuteJavascript(
-        'obtainGetUserMediaResult()', tab_index=tab_index)
-
-  def AssertNoFailures(self, tab_index):
-    """Ensures the javascript hasn't registered any asynchronous errors.
-
-    Args:
-      tab_index: The tab to check.
-    """
-    self.assertEquals('ok-no-errors', self.ExecuteJavascript(
-        'getAnyTestFailures()', tab_index=tab_index))
-
-  def Connect(self, user_name, tab_index):
-    self.assertEquals('ok-connected', self.ExecuteJavascript(
-        'connect("http://localhost:8888", "%s")' % user_name,
-        tab_index=tab_index))
-    self.AssertNoFailures(tab_index)
-
-  def CreatePeerConnection(self, tab_index):
-    self.assertEquals('ok-peerconnection-created', self.ExecuteJavascript(
-        'preparePeerConnection()', tab_index=tab_index))
-
-  def AddUserMediaLocalStream(self, tab_index):
-    self.assertEquals('ok-added', self.ExecuteJavascript(
-        'addLocalStream()', tab_index=tab_index))
-
-  def AddWebAudioFile(self, tab_index, input_relative_path):
-    """The path must be relative to where the javascript is.
-
-    This call just loads and adds a file to a peer connection, but it doesn't
-    start to play it until you call PlayWebAudioFile.
-    """
-    self.assertEquals('ok-added', self.ExecuteJavascript(
-        'addAudioFile("%s")' % re.escape(input_relative_path),
-        tab_index=tab_index))
-
-  def PlayWebAudioFile(self, tab_index):
-    """Plays a web audio file which was added earlier."""
-    self.assertEquals('ok-playing', self.ExecuteJavascript(
-        'playAudioFile()', tab_index=tab_index))
-
-  def EstablishCall(self, from_tab_with_index, to_tab_with_index):
-    self.WaitUntilPeerConnects(tab_index=from_tab_with_index)
-
-    self.assertEquals('ok-negotiating', self.ExecuteJavascript(
-        'negotiateCall()', tab_index=from_tab_with_index))
-    self.AssertNoFailures(from_tab_with_index)
-
-    self.WaitUntilReadyState(ready_state='active',
-                             tab_index=from_tab_with_index)
-
-    # Double-check the call reached the other side.
-    self.WaitUntilReadyState(ready_state='active',
-                             tab_index=to_tab_with_index)
-
-  def HangUp(self, from_tab_with_index):
-    self.assertEquals('ok-call-hung-up', self.ExecuteJavascript(
-        'hangUp()', tab_index=from_tab_with_index))
-    self.WaitUntilHangUpVerified(tab_index=from_tab_with_index)
-    self.AssertNoFailures(tab_index=from_tab_with_index)
-
-  def WaitUntilPeerConnects(self, tab_index):
-    peer_connected = self.WaitUntil(
-        function=lambda: self.ExecuteJavascript('remotePeerIsConnected()',
-                                                tab_index=tab_index),
-        expect_retval='peer-connected')
-    self.assertTrue(peer_connected,
-                    msg='Timed out while waiting for peer to connect.')
-
-  def WaitUntilReadyState(self, ready_state, tab_index):
-    got_ready_state = self.WaitUntil(
-        function=lambda: self.ExecuteJavascript('getPeerConnectionReadyState()',
-                                                tab_index=tab_index),
-        expect_retval=ready_state)
-    self.assertTrue(got_ready_state,
-                    msg=('Timed out while waiting for peer connection ready '
-                         'state to change to %s for tab %d.' % (ready_state,
-                                                                tab_index)))
-
-  def WaitUntilHangUpVerified(self, tab_index):
-    self.WaitUntilReadyState('no-peer-connection', tab_index=tab_index)
-
-  def Disconnect(self, tab_index):
-    self.assertEquals('ok-disconnected', self.ExecuteJavascript(
-        'disconnect()', tab_index=tab_index))
-
-  def BinPathForPlatform(self, path):
-    """Form a platform specific path to a binary.
-
-    Args:
-      path(string): The path to the binary without an extension.
-    Return:
-      (string): The platform-specific bin path.
-    """
-    if self.IsWin():
-      path += '.exe'
-    return path
-
-  def PlatformIsWinXP(self):
-    """Check if the executing platform is Windows XP.
-
-    Return:
-      True if the platform is Windows XP.
-    """
-    return platform.system() == 'Windows' and platform.release() == 'XP'
-
-  def StartPeerConnectionServer(self):
-    """Starts peerconnection_server.
-
-    Peerconnection_server is a custom binary allowing two WebRTC clients to find
-    each other. For more details, see the source code which is available at the
-    site http://code.google.com/p/libjingle/source/browse/ (make sure to browse
-    to trunk/talk/examples/peerconnection/server).
-    """
-    # Start the peerconnection_server. It should be next to chrome.
-    binary_path = os.path.join(self.BrowserPath(), 'peerconnection_server')
-    binary_path = self.BinPathForPlatform(binary_path)
-
-    if not os.path.exists(binary_path):
-      raise MissingRequiredBinaryException(
-        'Could not locate peerconnection_server. Have you built the '
-        'peerconnection_server target? We expect to have a '
-        'peerconnection_server binary next to the chrome binary.')
-
-    self._server_process = subprocess.Popen(binary_path)
-
-  def StopPeerConnectionServer(self):
-    """Stops the peerconnection_server."""
-    assert self._server_process
-    self._server_process.kill()
diff --git a/chrome/test/functional/webrtc_video_quality.py b/chrome/test/functional/webrtc_video_quality.py
deleted file mode 100755
index 2b20f42..0000000
--- a/chrome/test/functional/webrtc_video_quality.py
+++ /dev/null
@@ -1,401 +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 subprocess
-import sys
-
-import pyauto_functional
-import pyauto
-import pyauto_paths
-import pyauto_utils
-import webrtc_test_base
-
-# If you change the port number, don't forget to modify video_extraction.js too.
-_PYWEBSOCKET_PORT_NUMBER = '12221'
-
-_HOME_ENV_NAME = 'HOMEPATH' if pyauto.PyUITest.IsWin() else 'HOME'
-_WORKING_DIR = os.path.join(os.environ[_HOME_ENV_NAME], 'webrtc_video_quality')
-
-# This is the reference file that is being played by the virtual web camera.
-_REFERENCE_YUV_FILE = os.path.join(_WORKING_DIR, 'reference_video.yuv')
-
-# The YUV file is the file produced by rgba_to_i420_converter.
-_OUTPUT_YUV_FILE = os.path.join(_WORKING_DIR, 'captured_video.yuv')
-
-
-class MissingRequiredToolException(Exception):
-  pass
-
-
-class FailedToRunToolException(Exception):
-  pass
-
-
-class WebrtcVideoQualityTest(webrtc_test_base.WebrtcTestBase):
-  """Test the video quality of the WebRTC output.
-
-  Prerequisites: This test case must run on a machine with a virtual webcam that
-  plays video from the reference file located in the location defined by
-  _REFERENCE_YUV_FILE. You must also compile the chromium_builder_webrtc target
-  before you run this test to get all the tools built.
-  The external compare_videos.py script also depends on two external executables
-  which must be located in the PATH when running this test.
-  * zxing (see the CPP version at https://code.google.com/p/zxing)
-  * ffmpeg 0.11.1 or compatible version (see http://www.ffmpeg.org)
-
-  The test case will launch a custom binary (peerconnection_server) which will
-  allow two WebRTC clients to find each other.
-
-  The test also runs several other custom binaries - rgba_to_i420 converter and
-  frame_analyzer. Both tools can be found under third_party/webrtc/tools. The
-  test also runs a stand alone Python implementation of a WebSocket server
-  (pywebsocket) and a barcode_decoder script.
-  """
-
-  def setUp(self):
-    pyauto.PyUITest.setUp(self)
-    if not os.path.exists(_WORKING_DIR):
-      self.fail('Cannot find the working directory for the reference video and '
-                'the temporary files: %s' % _WORKING_DIR)
-    if not os.path.exists(_REFERENCE_YUV_FILE):
-      self.fail('Cannot find the reference file to be used for video quality '
-                'comparison: %s' % _REFERENCE_YUV_FILE)
-    self.StartPeerConnectionServer()
-
-  def tearDown(self):
-    self._StopPywebsocketServer()
-    self.StopPeerConnectionServer()
-
-    pyauto.PyUITest.tearDown(self)
-    self.assertEquals('', self.CheckErrorsAndCrashes())
-
-  def _WebRtcCallWithHelperPage(self, test_page, helper_page):
-
-    """Tests we can call, let run for some time and hang up with WebRTC.
-
-    This test exercises pretty much the whole happy-case for the WebRTC
-    JavaScript API. Currently, it exercises a normal call setup using the API
-    defined at http://dev.w3.org/2011/webrtc/editor/webrtc.html. The API is
-    still evolving.
-
-    The test will load the supplied HTML file, which in turn will load different
-    javascript files depending on which version of the signaling protocol
-    we are running.
-    The supplied HTML files will be loaded in two tabs and tell the web
-    pages to start up WebRTC, which will acquire video and audio devices on the
-    system. This will launch a dialog in Chrome which we click past using the
-    automation controller. Then, we will order both tabs to connect the server,
-    which will make the two tabs aware of each other. Once that is done we order
-    one tab to call the other.
-
-    We make sure that the javascript tells us that the call succeeded, lets it
-    run for some time and try to hang up the call after that. While the call is
-    running, we capture frames with the help of the functions in the
-    video_extraction.js file.
-
-    Args:
-      test_page(string): The name of the test HTML page. It is looked for in the
-        webrtc directory under chrome/test/data.
-      helper_page(string): The name of the helper HTML page. It is looked for in
-        the same directory as the test_page.
-    """
-    assert helper_page
-    url = self.GetFileURLForDataPath('webrtc', test_page)
-    helper_url = self.GetFileURLForDataPath('webrtc', helper_page)
-
-    # Start the helper page in the first tab
-    self.NavigateToURL(helper_url)
-
-    # Start the test page in the second page.
-    self.AppendTab(pyauto.GURL(url))
-
-    self.assertEquals('ok-got-stream', self.GetUserMedia(tab_index=0))
-    self.assertEquals('ok-got-stream', self.GetUserMedia(tab_index=1))
-    self.Connect('user_1', tab_index=0)
-    self.Connect('user_2', tab_index=1)
-
-    self.CreatePeerConnection(tab_index=0)
-    self.AddUserMediaLocalStream(tab_index=0)
-    self.EstablishCall(from_tab_with_index=0, to_tab_with_index=1)
-
-    # Wait for JavaScript to capture all the frames. In the HTML file we specify
-    # how many seconds to capture frames.
-    done_capturing = self.WaitUntil(
-        function=lambda: self.ExecuteJavascript('doneFrameCapturing()',
-                                                tab_index=1),
-        expect_retval='done-capturing', retry_sleep=1.0,
-        # TODO(phoglund): Temporary fix; remove after 2013-04-01
-        timeout=90)
-
-    self.assertTrue(done_capturing,
-                    msg='Timed out while waiting frames to be captured.')
-
-    # The hang-up will automatically propagate to the second tab.
-    self.HangUp(from_tab_with_index=0)
-    self.WaitUntilHangUpVerified(tab_index=1)
-
-    self.Disconnect(tab_index=0)
-    self.Disconnect(tab_index=1)
-
-    # Ensure we didn't miss any errors.
-    self.AssertNoFailures(tab_index=0)
-    self.AssertNoFailures(tab_index=1)
-
-  def testVgaVideoQuality(self):
-    """Tests the WebRTC video output for a VGA video input.
-
-    On the bots we will be running fake webcam driver and we will feed a video
-    with overlaid barcodes. In order to run the analysis on the output, we need
-    to use the original input video as a reference video.
-    """
-    helper_page = webrtc_test_base.WebrtcTestBase.DEFAULT_TEST_PAGE
-    self._StartVideoQualityTest(test_page='webrtc_video_quality_test.html',
-                                helper_page=helper_page,
-                                reference_yuv=_REFERENCE_YUV_FILE, width=640,
-                                height=480)
-
-  def _StartVideoQualityTest(self, reference_yuv,
-                             test_page='webrtc_video_quality_test.html',
-                             helper_page='webrtc_jsep01_test.html',
-                             width=640, height=480):
-    """Captures video output into a canvas and sends it to a server.
-
-    This test captures the output frames of a WebRTC connection to a canvas and
-    later sends them over WebSocket to a WebSocket server implemented in Python.
-    At the server side we can store the frames for subsequent quality analysis.
-
-    After the frames are sent to the pywebsocket server, we run the RGBA to I420
-    converter, the barcode decoder and finally the frame analyzer. We also print
-    everything to the Perf Graph for visualization
-
-    Args:
-      reference_yuv(string): The name of the reference YUV video that will be
-        used in the analysis.
-      test_page(string): The name of the test HTML page. To be looked for in the
-        webrtc directory under chrome/test/data.
-      helper_page(string): The name of the HTML helper page. To be looked for in
-        the same directory as the test_page.
-      width(int): The width of the test video frames.
-      height(int): The height of the test video frames.
-    """
-    self._StartPywebsocketServer()
-
-    self._WebRtcCallWithHelperPage(test_page, helper_page)
-
-    # Wait for JavaScript to send all the frames to the server. The test will
-    # have quite a lot of frames to send, so it will take at least several
-    # seconds.
-    no_more_frames = self.WaitUntil(
-        function=lambda: self.ExecuteJavascript('haveMoreFramesToSend()',
-                                                tab_index=1),
-        expect_retval='no-more-frames', retry_sleep=1, timeout=150)
-    self.assertTrue(no_more_frames,
-                    msg='Timed out while waiting for frames to send.')
-
-    self.assertTrue(self._RunRGBAToI420Converter(width, height))
-
-    stats_file = os.path.join(_WORKING_DIR, 'pyauto_stats.txt')
-    analysis_result = self._CompareVideos(width, height, _OUTPUT_YUV_FILE,
-                                          reference_yuv, stats_file)
-    self._ProcessPsnrAndSsimOutput(analysis_result)
-    self._ProcessFramesCountOutput(analysis_result)
-
-  def _StartPywebsocketServer(self):
-    """Starts the pywebsocket server."""
-    print 'Starting pywebsocket server.'
-
-    # Pywebsocket source directory.
-    path_pyws_dir = os.path.join(pyauto_paths.GetThirdPartyDir(), 'pywebsocket',
-                                 'src')
-
-    # Pywebsocket standalone server.
-    path_to_pywebsocket= os.path.join(path_pyws_dir, 'mod_pywebsocket',
-                                      'standalone.py')
-
-    # Path to the data handler to handle data received by the server.
-    path_to_handler = os.path.join(pyauto_paths.GetSourceDir(), 'chrome',
-                                   'test', 'functional')
-
-    # The python interpreter binary.
-    python_interp = sys.executable
-
-    # The pywebsocket start command - we could add --log-level=debug for debug.
-    # -p stands for port, -d stands for root_directory (where the data handlers
-    # are).
-    start_cmd = [python_interp, path_to_pywebsocket,
-                 '-p', _PYWEBSOCKET_PORT_NUMBER,
-                 '-d', path_to_handler,]
-    env = os.environ
-    # Set PYTHONPATH to include the pywebsocket base directory.
-    env['PYTHONPATH'] = (path_pyws_dir + os.path.pathsep +
-                         env.get('PYTHONPATH', ''))
-
-    # Start the pywebsocket server. The server will not start instantly, so the
-    # code opening websockets to it should take this into account.
-    self._pywebsocket_server = subprocess.Popen(start_cmd, env=env)
-
-  def _StopPywebsocketServer(self):
-    """Stops the running instance of pywebsocket server."""
-    print 'Stopping pywebsocket server.'
-    if self._pywebsocket_server:
-      self._pywebsocket_server.kill()
-
-  def _RunRGBAToI420Converter(self, width, height):
-    """Runs the RGBA to I420 converter.
-
-    The rgba_to_i420_converter is part of the webrtc_test_tools target which
-    should be build prior to running this test. The resulting binary should live
-    next to Chrome.
-
-    Args:
-      width(int): The width of the frames to be converted and stitched together.
-      height(int): The height of the frames to be converted and stitched.
-
-    Returns:
-      (bool): True if the conversion is successful, false otherwise.
-    """
-    path_to_rgba_converter = os.path.join(self.BrowserPath(),
-                                          'rgba_to_i420_converter')
-    path_to_rgba_converter = os.path.abspath(path_to_rgba_converter)
-    path_to_rgba_converter = self.BinPathForPlatform(path_to_rgba_converter)
-
-    if not os.path.exists(path_to_rgba_converter):
-      raise webrtc_test_base.MissingRequiredBinaryException(
-          'Could not locate rgba_to_i420_converter! Did you build the '
-          'webrtc_test_tools target?')
-
-    # We produce an output file that will later be used as an input to the
-    # barcode decoder and frame analyzer tools.
-    start_cmd = [path_to_rgba_converter, '--frames_dir=%s' % _WORKING_DIR,
-                 '--output_file=%s' % _OUTPUT_YUV_FILE, '--width=%d' % width,
-                 '--height=%d' % height, '--delete_frames']
-    print 'Start command: ', ' '.join(start_cmd)
-    rgba_converter = subprocess.Popen(start_cmd, stdout=sys.stdout,
-                                      stderr=sys.stderr)
-    rgba_converter.wait()
-    return rgba_converter.returncode == 0
-
-  def _CompareVideos(self, width, height, captured_video_filename,
-                     reference_video_filename, stats_filename):
-    """Compares the captured video with the reference video.
-
-    The barcode decoder decodes the captured video containing barcodes overlaid
-    into every frame of the video (produced by rgba_to_i420_converter). It
-    produces a set of PNG images and a stats file that describes the relation
-    between the filenames and the (decoded) frame number of each frame.
-
-    Args:
-      width(int): The frames width of the video to be decoded.
-      height(int): The frames height of the video to be decoded.
-      captured_video_filename(string): The captured video file we want to
-        extract frame images and decode frame numbers from.
-      reference_video_filename(string): The reference video file we want to
-        compare the captured video quality with.
-      stats_filename(string): Filename for the output file containing
-        data that shows the relation between each frame filename and the
-        reference file's frame numbers.
-
-    Returns:
-      (string): The output of the script.
-
-    Raises:
-      FailedToRunToolException: If the script fails to run.
-    """
-    path_to_analyzer = os.path.join(self.BrowserPath(), 'frame_analyzer')
-    path_to_analyzer = os.path.abspath(path_to_analyzer)
-    path_to_analyzer = self.BinPathForPlatform(path_to_analyzer)
-
-    path_to_compare_script = os.path.join(pyauto_paths.GetThirdPartyDir(),
-                                          'webrtc', 'tools',
-                                          'compare_videos.py')
-    if not os.path.exists(path_to_compare_script):
-      raise MissingRequiredToolException('Cannot find the script at %s' %
-                                         path_to_compare_script)
-    python_interp = sys.executable
-    cmd = [
-      python_interp,
-      path_to_compare_script,
-      '--ref_video=%s' % reference_video_filename,
-      '--test_video=%s' % captured_video_filename,
-      '--frame_analyzer=%s' % path_to_analyzer,
-      '--yuv_frame_width=%d' % width,
-      '--yuv_frame_height=%d' % height,
-      '--stats_file=%s' % stats_filename,
-    ]
-    print 'Start command: ', ' '.join(cmd)
-
-    compare_videos = subprocess.Popen(cmd, stdout=subprocess.PIPE,
-                                      stderr=subprocess.PIPE)
-    output, error = compare_videos.communicate()
-    if compare_videos.returncode != 0:
-      raise FailedToRunToolException('Failed to run compare videos script!')
-
-    return output
-
-  def _ProcessFramesCountOutput(self, output):
-    """Processes the analyzer output for the different frame counts.
-
-    The frame analyzer outputs additional information about the number of unique
-    frames captured, The max number of repeated frames in a sequence and the
-    max number of skipped frames. These values are then written to the Perf
-    Graph. (Note: Some of the repeated or skipped frames will probably be due to
-    the imperfection of JavaScript timers.)
-
-    Args:
-      output(string): The output from the frame analyzer to be processed.
-    """
-    # The output from frame analyzer will be in the format:
-    # <PSNR and SSIM stats>
-    # Unique_frames_count:<value>
-    # Max_repeated:<value>
-    # Max_skipped:<value>
-    unique_fr_pos = output.rfind('Unique_frames_count')
-    result_str = output[unique_fr_pos:]
-
-    result_list = result_str.split()
-
-    for result in result_list:
-      colon_pos = result.find(':')
-      key = result[:colon_pos]
-      value = result[colon_pos+1:]
-      pyauto_utils.PrintPerfResult(key, 'VGA', value, '')
-
-  def _ProcessPsnrAndSsimOutput(self, output):
-    """Processes the analyzer output to extract the PSNR and SSIM values.
-
-    The frame analyzer produces PSNR and SSIM results for every unique frame
-    that has been captured. This method forms a list of all the psnr and ssim
-    values and passes it to PrintPerfResult() for printing on the Perf Graph.
-
-    Args:
-      output(string): The output from the frame analyzer to be processed.
-    """
-    # The output is in the format:
-    # BSTATS
-    # psnr ssim; psnr ssim; ... psnr ssim;
-    # ESTATS
-    stats_beginning = output.find('BSTATS')  # Get the beginning of the stats
-    stats_ending = output.find('ESTATS')  # Get the end of the stats
-    stats_str = output[(stats_beginning + len('BSTATS')):stats_ending]
-
-    stats_list = stats_str.split(';')
-
-    psnr = []
-    ssim = []
-
-    for item in stats_list:
-      item = item.strip()
-      if item != '':
-        entry = item.split(' ')
-        psnr.append(float(entry[0]))
-        ssim.append(float(entry[1]))
-
-    pyauto_utils.PrintPerfResult('PSNR', 'VGA', psnr, '')
-    pyauto_utils.PrintPerfResult('SSIM', 'VGA', ssim, '')
-
-
-if __name__ == '__main__':
-  pyauto_functional.Main()
diff --git a/chrome/test/mini_installer/config/chrome_installed.prop b/chrome/test/mini_installer/config/chrome_installed.prop
index 9db2a19..1b95385 100644
--- a/chrome/test/mini_installer/config/chrome_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_installed.prop
@@ -1,4 +1,13 @@
 {
+  "Files": {
+    "$LOCAL_APPDATA\\Google\\Chrome\\Application\\chrome.exe": {"exists": true},
+    "$LOCAL_APPDATA\\Google\\Chrome\\Application\\$MINI_INSTALLER_FILE_VERSION\\chrome.dll":
+        {"exists": true},
+    "$LOCAL_APPDATA\\Google\\Chrome\\Application\\$MINI_INSTALLER_FILE_VERSION\\Installer\\chrome.7z":
+        {"exists": true},
+    "$LOCAL_APPDATA\\Google\\Chrome\\Application\\$MINI_INSTALLER_FILE_VERSION\\Installer\\setup.exe":
+        {"exists": true}
+  },
   "RegistryEntries": {
     "HKEY_CURRENT_USER\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}":
         {"exists": true}
diff --git a/chrome/test/mini_installer/config/chrome_not_installed.prop b/chrome/test/mini_installer/config/chrome_not_installed.prop
index a9f7685..dfa4ffd 100644
--- a/chrome/test/mini_installer/config/chrome_not_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_not_installed.prop
@@ -1,4 +1,7 @@
 {
+  "Files": {
+    "$LOCAL_APPDATA\\Google\\Chrome\\Application": {"exists": false}
+  },
   "RegistryEntries": {
     "HKEY_CURRENT_USER\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}":
         {"exists": false}
diff --git a/chrome/test/mini_installer/config/config.config b/chrome/test/mini_installer/config/config.config
index ab70938..94725f6 100644
--- a/chrome/test/mini_installer/config/config.config
+++ b/chrome/test/mini_installer/config/config.config
@@ -4,7 +4,8 @@
     ["chrome_installed", ["chrome_installed.prop"]]
   ],
   "actions": [
-    ["install chrome", "mini_installer.exe --chrome --multi-install"],
+    ["install chrome",
+        "\"$MINI_INSTALLER\" --chrome --multi-install --do-not-launch-chrome"],
     ["uninstall chrome", "python uninstall_chrome.py"]
   ],
   "tests": [
diff --git a/chrome/test/mini_installer/file_verifier.py b/chrome/test/mini_installer/file_verifier.py
new file mode 100644
index 0000000..045cc4c
--- /dev/null
+++ b/chrome/test/mini_installer/file_verifier.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.
+
+import os
+
+import path_resolver
+
+
+def VerifyFiles(files):
+  """Verifies that the current files match the expectation dictionaries.
+
+  This method will throw an AssertionError if file state doesn't match the
+  provided expectation.
+
+  Args:
+    files: A dictionary whose keys are file paths and values are expectation
+        dictionaries. An expectation dictionary is a dictionary with the
+        following key and value:
+            'exists' a boolean indicating whether the file should exist.
+  """
+  for file_path, expectation in files.iteritems():
+    file_exists = os.path.exists(path_resolver.ResolvePath(file_path))
+    assert expectation['exists'] == file_exists, \
+        ('File %s exists' % file_path) if file_exists else \
+        ('File %s is missing' % file_path)
diff --git a/chrome/test/mini_installer/path_resolver.py b/chrome/test/mini_installer/path_resolver.py
new file mode 100644
index 0000000..570a584
--- /dev/null
+++ b/chrome/test/mini_installer/path_resolver.py
@@ -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.
+
+import os
+import string
+import win32api
+import win32com.client
+from win32com.shell import shell, shellcon
+
+
+def ResolvePath(path):
+  """Resolve variables in a file path, and return the resolved path.
+
+  This method resolves only variables defined below. It does not resolve
+  environment variables. Any dollar signs that are not part of variables must be
+  escaped with $$, otherwise a KeyError or a ValueError will be raised.
+
+  Args:
+    path: An absolute or relative path.
+
+  Returns:
+    A new path created by replacing
+        * $PROGRAM_FILES with the path to the Program Files folder,
+        * $LOCAL_APPDATA with the path to the Local Application Data folder,
+        * $MINI_INSTALLER with the path to the mini_installer, and
+        * $MINI_INSTALLER_FILE_VERSION with the file version of the
+            mini_installer.
+  """
+  program_files_path = shell.SHGetFolderPath(0, shellcon.CSIDL_PROGRAM_FILES,
+                                             None, 0)
+  local_appdata_path = shell.SHGetFolderPath(0, shellcon.CSIDL_LOCAL_APPDATA,
+                                             None, 0)
+  #TODO(sukolsak): Copy the mini_installer.exe from the build output into here.
+  mini_installer_path = os.path.abspath('mini_installer.exe')
+  mini_installer_file_version = win32com.client.Dispatch(
+      'Scripting.FileSystemObject').GetFileVersion(mini_installer_path)
+
+  variable_mapping = {
+      'PROGRAM_FILES': program_files_path,
+      'LOCAL_APPDATA': local_appdata_path,
+      'MINI_INSTALLER': mini_installer_path,
+      'MINI_INSTALLER_FILE_VERSION': mini_installer_file_version,
+  }
+  return string.Template(path).substitute(variable_mapping)
diff --git a/chrome/test/mini_installer/test_installer.py b/chrome/test/mini_installer/test_installer.py
index a983478..8f5d9af 100644
--- a/chrome/test/mini_installer/test_installer.py
+++ b/chrome/test/mini_installer/test_installer.py
@@ -15,6 +15,7 @@
 import subprocess
 import unittest
 
+import path_resolver
 import verifier
 
 
@@ -102,7 +103,11 @@
       raise AssertionError("In state '%s', %s" % (state, e))
 
   def _RunCommand(self, command):
-    subprocess.call(command, shell=True)
+    exit_status = subprocess.call(path_resolver.ResolvePath(command),
+                                  shell=True)
+    if exit_status != 0:
+      self.fail('Command %s returned non-zero exit status %s' % (command,
+                                                                 exit_status))
 
 
 def MergePropertyDictionaries(current_property, new_property):
diff --git a/chrome/test/mini_installer/uninstall_chrome.py b/chrome/test/mini_installer/uninstall_chrome.py
index fe2e870..3680940 100644
--- a/chrome/test/mini_installer/uninstall_chrome.py
+++ b/chrome/test/mini_installer/uninstall_chrome.py
@@ -2,9 +2,42 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import subprocess
+"""Uninstall Chrome.
 
-# TODO(sukolsak): This should read the uninstall command from the registry and
-# run that instead.
-subprocess.call('mini_installer.exe --uninstall --multi-install --chrome',
-                shell=True)
+This script reads the uninstall command from registry, calls it, and verifies
+the output status code.
+"""
+
+import _winreg
+import argparse
+import subprocess
+import sys
+
+
+def main():
+  parser = argparse.ArgumentParser(description='Uninstall Chrome.')
+  parser.add_argument('--system-level', dest='system_level',
+                      action='store_const', const=True, default=False,
+                      help='Uninstall Chrome at system level.')
+  args = parser.parse_args()
+
+  # TODO(sukolsak): Add support for uninstalling MSI-based Chrome installs when
+  # we support testing MSIs.
+  if args.system_level:
+    root_key = _winreg.HKEY_LOCAL_MACHINE
+  else:
+    root_key = _winreg.HKEY_CURRENT_USER
+  sub_key = ('SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\'
+             'Google Chrome')
+  key = _winreg.OpenKey(root_key, sub_key, 0, _winreg.KEY_QUERY_VALUE)
+  uninstall_string, _ = _winreg.QueryValueEx(key, 'UninstallString')
+  exit_status = subprocess.call(uninstall_string, shell=True)
+  # The exit status for successful uninstallation of Chrome is 19 (see
+  # chrome/installer/util/util_constants.h).
+  if exit_status != 19:
+    raise Exception('Could not uninstall Chrome. The installer exited with '
+                    'status %d.' % exit_status)
+  return 0
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/chrome/test/mini_installer/verifier.py b/chrome/test/mini_installer/verifier.py
index 8a735ba..1436040 100644
--- a/chrome/test/mini_installer/verifier.py
+++ b/chrome/test/mini_installer/verifier.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 file_verifier
 import registry_verifier
 
 
@@ -16,7 +17,9 @@
     property: A property dictionary.
   """
   for verifier_name, value in property.iteritems():
-    if verifier_name == 'RegistryEntries':
+    if verifier_name == 'Files':
+      file_verifier.VerifyFiles(value)
+    elif verifier_name == 'RegistryEntries':
       registry_verifier.VerifyRegistryEntries(value)
     else:
       # TODO(sukolsak): Implement other verifiers
diff --git a/chrome/test/nacl/nacl_browsertest.cc b/chrome/test/nacl/nacl_browsertest.cc
index e16aae4..2cad78a 100644
--- a/chrome/test/nacl/nacl_browsertest.cc
+++ b/chrome/test/nacl/nacl_browsertest.cc
@@ -15,40 +15,13 @@
 
 namespace {
 
-// These tests fail on Linux ASAN bots: <http://crbug.com/161709>.
-#if defined(OS_LINUX) && defined(ADDRESS_SANITIZER)
-#define MAYBE_SimpleLoad DISABLED_SimpleLoad
-#define MAYBE_ExitStatus0 DISABLED_ExitStatus0
-#define MAYBE_ExitStatus254 DISABLED_ExitStatus254
-#define MAYBE_ExitStatusNeg2 DISABLED_ExitStatusNeg2
-#define MAYBE_PPAPICore DISABLED_PPAPICore
-#define MAYBE_ProgressEvents DISABLED_ProgressEvents
-#define MAYBE_PnaclMimeType DISABLED_PnaclMimeType
-#define MAYBE_CrossOriginCORS DISABLED_CrossOriginCORS
-#define MAYBE_CrossOriginFail DISABLED_CrossOriginFail
-#define MAYBE_SameOriginCookie DISABLED_SameOriginCookie
-#define MAYBE_CORSNoCookie DISABLED_CORSNoCookie
-#define MAYBE_SysconfNprocessorsOnln DISABLED_SysconfNprocessorsOnln
-#else
-#define MAYBE_SimpleLoad SimpleLoad
-#define MAYBE_ExitStatus0 ExitStatus0
-#define MAYBE_ExitStatus254 ExitStatus254
-#define MAYBE_ExitStatusNeg2 ExitStatusNeg2
-#define MAYBE_PPAPICore PPAPICore
-#define MAYBE_ProgressEvents ProgressEvents
-#define MAYBE_PnaclMimeType PnaclMimeType
-#define MAYBE_CrossOriginCORS CrossOriginCORS
-#define MAYBE_CrossOriginFail CrossOriginFail
-#define MAYBE_SameOriginCookie SameOriginCookie
-#define MAYBE_CORSNoCookie CORSNoCookie
-# if defined(OS_WIN)
+#if defined(OS_WIN)
 #  define MAYBE_SysconfNprocessorsOnln DISABLED_SysconfNprocessorsOnln
-# else
+#else
 #  define MAYBE_SysconfNprocessorsOnln SysconfNprocessorsOnln
-# endif
 #endif
 
-NACL_BROWSER_TEST_F(NaClBrowserTest, MAYBE_SimpleLoad, {
+NACL_BROWSER_TEST_F(NaClBrowserTest, SimpleLoad, {
   RunLoadTest(FILE_PATH_LITERAL("nacl_load_test.html"));
 })
 
@@ -62,33 +35,29 @@
   RunNaClIntegrationTest(FILE_PATH_LITERAL("pnacl_error_handling.html"));
 }
 
-NACL_BROWSER_TEST_F(NaClBrowserTest, MAYBE_ExitStatus0, {
+NACL_BROWSER_TEST_F(NaClBrowserTest, ExitStatus0, {
   RunNaClIntegrationTest(FILE_PATH_LITERAL(
       "pm_exit_status_test.html?trigger=exit0&expected_exit=0"));
 })
 
-NACL_BROWSER_TEST_F(NaClBrowserTest, MAYBE_ExitStatus254, {
+NACL_BROWSER_TEST_F(NaClBrowserTest, ExitStatus254, {
   RunNaClIntegrationTest(FILE_PATH_LITERAL(
       "pm_exit_status_test.html?trigger=exit254&expected_exit=254"));
 })
 
-NACL_BROWSER_TEST_F(NaClBrowserTest, MAYBE_ExitStatusNeg2, {
+NACL_BROWSER_TEST_F(NaClBrowserTest, ExitStatusNeg2, {
   RunNaClIntegrationTest(FILE_PATH_LITERAL(
       "pm_exit_status_test.html?trigger=exitneg2&expected_exit=254"));
 })
 
-NACL_BROWSER_TEST_F(NaClBrowserTest, MAYBE_PPAPICore, {
+NACL_BROWSER_TEST_F(NaClBrowserTest, PPAPICore, {
   RunNaClIntegrationTest(FILE_PATH_LITERAL("ppapi_ppb_core.html"));
 })
 
-NACL_BROWSER_TEST_F(NaClBrowserTest, MAYBE_ProgressEvents, {
+NACL_BROWSER_TEST_F(NaClBrowserTest, ProgressEvents, {
   RunNaClIntegrationTest(FILE_PATH_LITERAL("ppapi_progress_events.html"));
 })
 
-NACL_BROWSER_TEST_F(NaClBrowserTest, MAYBE_PnaclMimeType, {
-  RunLoadTest(FILE_PATH_LITERAL("pnacl_mime_type.html"));
-})
-
 // Some versions of Visual Studio does not like preprocessor
 // conditionals inside the argument of a macro, so we put the
 // conditionals on a helper function.  We are already in an anonymous
@@ -144,19 +113,19 @@
     RunNaClIntegrationTest(path);
 })
 
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, MAYBE_CrossOriginCORS) {
+IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, CrossOriginCORS) {
   RunLoadTest(FILE_PATH_LITERAL("cross_origin/cors.html"));
 }
 
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, MAYBE_CrossOriginFail) {
+IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, CrossOriginFail) {
   RunLoadTest(FILE_PATH_LITERAL("cross_origin/fail.html"));
 }
 
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, MAYBE_SameOriginCookie) {
+IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, SameOriginCookie) {
   RunLoadTest(FILE_PATH_LITERAL("cross_origin/same_origin_cookie.html"));
 }
 
-IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, MAYBE_CORSNoCookie) {
+IN_PROC_BROWSER_TEST_F(NaClBrowserTestStatic, CORSNoCookie) {
   RunLoadTest(FILE_PATH_LITERAL("cross_origin/cors_no_cookie.html"));
 }
 
@@ -192,4 +161,12 @@
       "pnacl_exception_handling_disabled.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnacl, PnaclMimeType) {
+  RunLoadTest(FILE_PATH_LITERAL("pnacl_mime_type.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnaclDisabled, PnaclMimeType) {
+  RunLoadTest(FILE_PATH_LITERAL("pnacl_mime_type.html"));
+}
+
 }  // namespace
diff --git a/chrome/test/nacl/nacl_browsertest_uma.cc b/chrome/test/nacl/nacl_browsertest_uma.cc
index eaabd8a..a76776c 100644
--- a/chrome/test/nacl/nacl_browsertest_uma.cc
+++ b/chrome/test/nacl/nacl_browsertest_uma.cc
@@ -34,7 +34,7 @@
                                 LOAD_OK, 1);
 
   // Make sure we have other important histograms.
-  if (!IsPnacl()) {
+  if (!IsAPnaclTest()) {
     histograms.ExpectTotalCount("NaCl.Perf.StartupTime.LoadModule", 1);
     histograms.ExpectTotalCount("NaCl.Perf.StartupTime.Total", 1);
     histograms.ExpectTotalCount("NaCl.Perf.Size.Manifest", 1);
diff --git a/chrome/test/nacl/nacl_browsertest_util.cc b/chrome/test/nacl/nacl_browsertest_util.cc
index 1c171a7..ace7305 100644
--- a/chrome/test/nacl/nacl_browsertest_util.cc
+++ b/chrome/test/nacl/nacl_browsertest_util.cc
@@ -187,6 +187,15 @@
   }
 }
 
+static void AddPnaclDisabledParm(const base::FilePath::StringType& url,
+                                 base::FilePath::StringType* url_with_parm) {
+  if (url.find(FILE_PATH_LITERAL("?")) == base::FilePath::StringType::npos) {
+    *url_with_parm = url + FILE_PATH_LITERAL("?pnacl_disabled=1");
+  } else {
+    *url_with_parm = url + FILE_PATH_LITERAL("&pnacl_disabled=1");
+  }
+}
+
 NaClBrowserTestBase::NaClBrowserTestBase() {
 }
 
@@ -210,7 +219,11 @@
   return GetNaClVariantRoot(Variant(), document_root);
 }
 
-bool NaClBrowserTestBase::IsPnacl() {
+bool NaClBrowserTestBase::IsAPnaclTest() {
+  return false;
+}
+
+bool NaClBrowserTestBase::IsPnaclDisabled() {
   return false;
 }
 
@@ -233,11 +246,15 @@
 void NaClBrowserTestBase::RunLoadTest(
     const base::FilePath::StringType& test_file) {
   LoadTestMessageHandler handler;
-  base::FilePath::StringType test_file_with_parm = test_file;
-  if (IsPnacl()) {
-    AddPnaclParm(test_file, &test_file_with_parm);
+  base::FilePath::StringType test_file_with_pnacl = test_file;
+  if (IsAPnaclTest()) {
+    AddPnaclParm(test_file, &test_file_with_pnacl);
   }
-  bool ok = RunJavascriptTest(TestURL(test_file_with_parm), &handler);
+  base::FilePath::StringType test_file_with_both = test_file_with_pnacl;
+  if (IsPnaclDisabled()) {
+    AddPnaclDisabledParm(test_file_with_pnacl, &test_file_with_both);
+  }
+  bool ok = RunJavascriptTest(TestURL(test_file_with_both), &handler);
   ASSERT_TRUE(ok) << handler.error_message();
   ASSERT_TRUE(handler.test_passed()) << "Test failed.";
 }
@@ -245,11 +262,15 @@
 void NaClBrowserTestBase::RunNaClIntegrationTest(
     const base::FilePath::StringType& url_fragment) {
   NaClIntegrationMessageHandler handler;
-  base::FilePath::StringType url_fragment_with_parm = url_fragment;
-  if (IsPnacl()) {
-    AddPnaclParm(url_fragment, &url_fragment_with_parm);
+  base::FilePath::StringType url_fragment_with_pnacl = url_fragment;
+  if (IsAPnaclTest()) {
+    AddPnaclParm(url_fragment, &url_fragment_with_pnacl);
   }
-  bool ok = RunJavascriptTest(TestURL(url_fragment_with_parm), &handler);
+  base::FilePath::StringType url_fragment_with_both = url_fragment_with_pnacl;
+  if (IsPnaclDisabled()) {
+    AddPnaclDisabledParm(url_fragment_with_pnacl, &url_fragment_with_both);
+  }
+  bool ok = RunJavascriptTest(TestURL(url_fragment_with_both), &handler);
   ASSERT_TRUE(ok) << handler.error_message();
   ASSERT_TRUE(handler.test_passed()) << "Test failed.";
 }
@@ -278,13 +299,24 @@
   return FILE_PATH_LITERAL("pnacl");
 }
 
-bool NaClBrowserTestPnacl::IsPnacl() {
+bool NaClBrowserTestPnacl::IsAPnaclTest() {
   return true;
 }
 
-void NaClBrowserTestPnacl::SetUpCommandLine(CommandLine* command_line) {
+base::FilePath::StringType NaClBrowserTestPnaclDisabled::Variant() {
+  return FILE_PATH_LITERAL("pnacl");
+}
+
+bool NaClBrowserTestPnaclDisabled::IsAPnaclTest() {
+  return true;
+}
+
+bool NaClBrowserTestPnaclDisabled::IsPnaclDisabled() {
+  return true;
+}
+void NaClBrowserTestPnaclDisabled::SetUpCommandLine(CommandLine* command_line) {
   NaClBrowserTestBase::SetUpCommandLine(command_line);
-  command_line->AppendSwitch(switches::kEnablePnacl);
+  command_line->AppendSwitch(switches::kDisablePnacl);
 }
 
 NaClBrowserTestPnaclWithOldCache::NaClBrowserTestPnaclWithOldCache() {
diff --git a/chrome/test/nacl/nacl_browsertest_util.h b/chrome/test/nacl/nacl_browsertest_util.h
index e79b565..27e638b 100644
--- a/chrome/test/nacl/nacl_browsertest_util.h
+++ b/chrome/test/nacl/nacl_browsertest_util.h
@@ -74,7 +74,9 @@
   // Where are the files for this class of test located on disk?
   virtual bool GetDocumentRoot(base::FilePath* document_root);
 
-  virtual bool IsPnacl();
+  virtual bool IsAPnaclTest();
+
+  virtual bool IsPnaclDisabled();
 
   // Map a file relative to the variant directory to a URL served by the test
   // web server.
@@ -116,11 +118,22 @@
 
 class NaClBrowserTestPnacl : public NaClBrowserTestBase {
  public:
+  virtual base::FilePath::StringType Variant() OVERRIDE;
+
+  virtual bool IsAPnaclTest() OVERRIDE;
+};
+
+// Class used to test that when --disable-pnacl is specified the PNaCl mime
+// type is not available.
+class NaClBrowserTestPnaclDisabled : public NaClBrowserTestBase {
+ public:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
 
   virtual base::FilePath::StringType Variant() OVERRIDE;
 
-  virtual bool IsPnacl() OVERRIDE;
+  virtual bool IsAPnaclTest() OVERRIDE;
+
+  virtual bool IsPnaclDisabled() OVERRIDE;
 };
 
 // Temporary class for running tests with the old cache enabled. Once all the
@@ -137,12 +150,10 @@
   virtual bool GetDocumentRoot(base::FilePath* document_root) OVERRIDE;
 };
 
-// PNaCl's cache and PPB_FileIO currently trip up under ASAN:
-// https://code.google.com/p/chromium/issues/detail?id=171810
 // PNaCl tests take a long time on windows debug builds
 // and sometimes time out.  Disable until it is made faster:
 // https://code.google.com/p/chromium/issues/detail?id=177555
-#if defined(ADDRESS_SANITIZER) || (defined(OS_WIN) && !defined(NDEBUG))
+#if (defined(OS_WIN) && !defined(NDEBUG))
 #define MAYBE_PNACL(test_name) DISABLED_##test_name
 #else
 #define MAYBE_PNACL(test_name) test_name
@@ -157,7 +168,7 @@
 
 #else
 
-// Otherwise, we have Glibc, Newlib and PNaCl tests
+// Otherwise, we have Glibc, Newlib and Pnacl tests
 #define NACL_BROWSER_TEST_F(suite, name, body) \
 IN_PROC_BROWSER_TEST_F(suite##Newlib, name) \
 body \
diff --git a/chrome/test/perf/rendering/throughput_tests.cc b/chrome/test/perf/rendering/throughput_tests.cc
index 4aab2e7..a21c685 100644
--- a/chrome/test/perf/rendering/throughput_tests.cc
+++ b/chrome/test/perf/rendering/throughput_tests.cc
@@ -50,7 +50,8 @@
   kNone = 0,
   kInternal = 1 << 0,         // Test uses internal test data.
   kAllowExternalDNS = 1 << 1, // Test needs external DNS lookup.
-  kIsGpuCanvasTest = 1 << 2   // Test uses GPU accelerated canvas features.
+  kIsGpuCanvasTest = 1 << 2,  // Test uses GPU accelerated canvas features.
+  kIsFlaky = 1 << 3
 };
 
 enum ThroughputTestFlags {
@@ -369,7 +370,9 @@
       frames = &events_sw;
       EXPECT_EQ(0u, events_gpu.size());
     }
-    ASSERT_GT(frames->size(), 20u);
+    if (!(flags & kIsFlaky)) {
+      ASSERT_GT(frames->size(), 20u);
+    }
     // Cull a few leading and trailing events as they might be unreliable.
     TraceEventVector rate_events(frames->begin() + kIgnoreSomeFrames,
                                  frames->end() - kIgnoreSomeFrames);
@@ -379,7 +382,7 @@
 
     // Print perf results.
     double mean_ms = stats.mean_us / 1000.0;
-    double std_dev_ms = stats.standard_deviation_us / 1000.0 / 1000.0;
+    double std_dev_ms = stats.standard_deviation_us / 1000.0;
     std::string trace_name = use_compositor_thread_? "gpu_thread" :
                              ran_on_gpu ? "gpu" : "software";
     std::string mean_and_error = base::StringPrintf("%f,%f", mean_ms,
@@ -536,11 +539,13 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, DrawImageShadowGPU) {
-  RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest);
+  // TODO(junov): Fix test flakiness crbug.com/272383
+  RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest | kIsFlaky);
 }
 
 IN_PROC_BROWSER_TEST_F(ThroughputTestThread, DrawImageShadowGPU) {
-  RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest);
+  // TODO(junov): Fix test flakiness crbug.com/272383
+  RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest | kIsFlaky);
 }
 
 IN_PROC_BROWSER_TEST_F(ThroughputTestSW, CanvasToCanvasDrawSW) {
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 0aef3d5..5952b08 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -134,11 +134,6 @@
 // Interface tests.
 //
 
-// Disable tests under ASAN.  http://crbug.com/104832.
-// This is a bit heavy handed, but the majority of these tests fail under ASAN.
-// See bug for history.
-#if !defined(ADDRESS_SANITIZER)
-
 TEST_PPAPI_IN_PROCESS(Broker)
 // Flaky, http://crbug.com/111355
 TEST_PPAPI_OUT_OF_PROCESS(DISABLED_Broker)
@@ -477,7 +472,13 @@
       LIST_TEST(URLLoader_PrefetchBufferThreshold)
   );
 }
-IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, URLLoader) {
+// Timing out on Windows dbg. http://crbug.com/95005
+#if defined(OS_WIN) && !defined(NDEBUG)
+#define MAYBE_URLLoader DISABLED_URLLoader
+#else
+#define MAYBE_URLLoader URLLoader
+#endif
+IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, MAYBE_URLLoader) {
   RunTestViaHTTP(
       LIST_TEST(URLLoader_BasicGET)
       LIST_TEST(URLLoader_BasicPOST)
@@ -1312,8 +1313,13 @@
       LIST_TEST(AudioConfig_InvalidConfigs));
 }
 
-
-IN_PROC_BROWSER_TEST_F(PPAPITest, Audio) {
+// Flaky on ChromeOS dbg, http://crbug.com/277564.
+#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#define MAYBE_Audio DISABLED_Audio
+#else
+#define MAYBE_Audio Audio
+#endif
+IN_PROC_BROWSER_TEST_F(PPAPITest, MAYBE_Audio) {
   RunTest(LIST_TEST(Audio_Creation)
           LIST_TEST(Audio_DestroyNoStop)
           LIST_TEST(Audio_Failures)
@@ -1521,5 +1527,3 @@
 
 TEST_PPAPI_IN_PROCESS(TalkPrivate)
 TEST_PPAPI_OUT_OF_PROCESS(TalkPrivate)
-
-#endif // ADDRESS_SANITIZER
diff --git a/chrome/test/ppapi/ppapi_test.cc b/chrome/test/ppapi/ppapi_test.cc
index 28f3eff..0456e1e 100644
--- a/chrome/test/ppapi/ppapi_test.cc
+++ b/chrome/test/ppapi/ppapi_test.cc
@@ -328,9 +328,8 @@
   EXPECT_TRUE(PathService::Get(chrome::FILE_NACL_PLUGIN, &plugin_lib));
   EXPECT_TRUE(base::PathExists(plugin_lib));
 
-  // Enable running NaCl outside of the store.
+  // Enable running (non-portable) NaCl outside of the Chrome web store.
   command_line->AppendSwitch(switches::kEnableNaCl);
-  command_line->AppendSwitch(switches::kEnablePnacl);
   command_line->AppendSwitchASCII(switches::kAllowNaClSocketAPI, "127.0.0.1");
   command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
   command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
@@ -365,9 +364,8 @@
   EXPECT_TRUE(PathService::Get(chrome::FILE_NACL_PLUGIN, &plugin_lib));
   EXPECT_TRUE(base::PathExists(plugin_lib));
 
-  // Enable running NaCl outside of the store.
+  // Enable running (non-portable) NaCl outside of the Chrome web store.
   command_line->AppendSwitch(switches::kEnableNaCl);
-  command_line->AppendSwitch(switches::kEnablePnacl);
 }
 
 // Append the correct mode and testcase string
diff --git a/chrome/tools/build/chromeos/FILES.cfg b/chrome/tools/build/chromeos/FILES.cfg
index 4bf94e4..97e002a 100644
--- a/chrome/tools/build/chromeos/FILES.cfg
+++ b/chrome/tools/build/chromeos/FILES.cfg
@@ -33,10 +33,6 @@
     'buildtype': ['dev', 'official'],
   },
   {
-    'filename': 'chrome.pak',
-    'buildtype': ['dev', 'official'],
-  },
-  {
     'filename': 'chrome_100_percent.pak',
     'buildtype': ['dev', 'official'],
   },
diff --git a/chrome/tools/build/linux/FILES.cfg b/chrome/tools/build/linux/FILES.cfg
index 93bf017..a0a844e 100644
--- a/chrome/tools/build/linux/FILES.cfg
+++ b/chrome/tools/build/linux/FILES.cfg
@@ -36,10 +36,6 @@
     'buildtype': ['dev', 'official'],
   },
   {
-    'filename': 'chrome.pak',
-    'buildtype': ['dev', 'official'],
-  },
-  {
     'filename': 'chrome_100_percent.pak',
     'buildtype': ['dev', 'official'],
   },
diff --git a/chrome/tools/build/win/syzygy_instrument.py b/chrome/tools/build/win/syzygy_instrument.py
index 2454da7..75eaf2d 100755
--- a/chrome/tools/build/win/syzygy_instrument.py
+++ b/chrome/tools/build/win/syzygy_instrument.py
@@ -78,6 +78,9 @@
          '--output-pdb=%s' % os.path.abspath(
              os.path.join(dst_dir, os.path.basename(symbol)))]
 
+  if mode == "asan":
+    cmd.append('--no-augment-pdb')
+
   # If a filter was specified then pass it on to the instrumenter.
   if filter_file:
     cmd.append('--filter=%s' % os.path.abspath(filter_file))
diff --git a/chrome/tools/convert_dict/convert_dict.cc b/chrome/tools/convert_dict/convert_dict.cc
index 91082f6..02cafe3 100644
--- a/chrome/tools/convert_dict/convert_dict.cc
+++ b/chrome/tools/convert_dict/convert_dict.cc
@@ -93,7 +93,7 @@
     return PrintHelp();
 
   base::AtExitManager exit_manager;
-  icu_util::Initialize();
+  base::i18n::InitializeICU();
 
   base::FilePath file_base = base::FilePath(argv[1]);
 
diff --git a/chrome/unit_tests.isolate b/chrome/unit_tests.isolate
index 59b789d..8af8a9b 100644
--- a/chrome/unit_tests.isolate
+++ b/chrome/unit_tests.isolate
@@ -5,9 +5,6 @@
   'conditions': [
     ['OS=="android" or OS=="linux"', {
       'variables': {
-        'isolate_dependency_tracked': [
-          '<(PRODUCT_DIR)/chrome.pak',
-        ],
         'isolate_dependency_untracked': [
           '<(PRODUCT_DIR)/test_data/',
         ],
@@ -62,8 +59,6 @@
       'variables': {
         'isolate_dependency_tracked': [
           '../testing/test_env.py',
-          '../tools/swarm_client/run_isolated.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/unit_tests<(EXECUTABLE_SUFFIX)',
           'browser/safe_browsing/two_phase_testserver.py',
         ],
@@ -72,6 +67,7 @@
           '../third_party/pyftpdlib/',
           '../third_party/pywebsocket/',
           '../third_party/tlslite/',
+          '../tools/swarm_client/',
           '<(PRODUCT_DIR)/pyproto/',
         ],
       },
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS
index c2b5436..8cfb1c0 100644
--- a/chrome/utility/DEPS
+++ b/chrome/utility/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+content/public/child",
   "+content/public/utility",
+  "+extensions/common",
 
   # For generated headers.
   "+grit",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 7cc2f74..02bd5e5 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -17,7 +17,6 @@
 #include "chrome/common/extensions/chrome_extensions_client.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
-#include "chrome/common/extensions/manifest.h"
 #include "chrome/common/extensions/update_manifest.h"
 #include "chrome/common/safe_browsing/zip_analyzer.h"
 #include "chrome/utility/extensions/unpacker.h"
@@ -26,6 +25,7 @@
 #include "content/public/child/image_decoder_utils.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/utility/utility_thread.h"
+#include "extensions/common/manifest.h"
 #include "media/base/media.h"
 #include "media/base/media_file_checker.h"
 #include "printing/page_range.h"
@@ -147,6 +147,8 @@
                         OnParseITunesLibraryXmlFile)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParsePicasaPMPDatabase,
                         OnParsePicasaPMPDatabase)
+    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_IndexPicasaAlbumsContents,
+                        OnIndexPicasaAlbumsContents)
 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
 
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -591,15 +593,11 @@
   ReleaseProcessIfNeeded();
 }
 
-void OnIndexPicasaAlbumsContents(
+void ChromeContentUtilityClient::OnIndexPicasaAlbumsContents(
     const picasa::AlbumUIDSet& album_uids,
     const std::vector<picasa::FolderINIContents>& folders_inis) {
   picasa::PicasaAlbumsIndexer indexer(album_uids);
-  for (std::vector<picasa::FolderINIContents>::const_iterator it =
-           folders_inis.begin();
-       it != folders_inis.end(); ++it) {
-    indexer.ParseFolderINI(it->folder_path, it->ini_contents);
-  }
+  indexer.ParseFolderINI(folders_inis);
 
   Send(new ChromeUtilityHostMsg_IndexPicasaAlbumsContents_Finished(
       indexer.albums_images()));
diff --git a/chrome/utility/extensions/unpacker.cc b/chrome/utility/extensions/unpacker.cc
index e6bb4bc..8968549 100644
--- a/chrome/utility/extensions/unpacker.cc
+++ b/chrome/utility/extensions/unpacker.cc
@@ -22,10 +22,10 @@
 #include "chrome/common/extensions/extension_file_util.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
-#include "chrome/common/extensions/manifest.h"
 #include "content/public/child/image_decoder_utils.h"
 #include "content/public/common/common_param_traits.h"
 #include "extensions/common/constants.h"
+#include "extensions/common/manifest.h"
 #include "grit/generated_resources.h"
 #include "ipc/ipc_message_utils.h"
 #include "net/base/file_stream.h"
@@ -35,7 +35,7 @@
 #include "ui/gfx/size.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace {
 
diff --git a/chrome/utility/extensions/unpacker.h b/chrome/utility/extensions/unpacker.h
index 3f30615..53e866b 100644
--- a/chrome/utility/extensions/unpacker.h
+++ b/chrome/utility/extensions/unpacker.h
@@ -10,7 +10,7 @@
 
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
-#include "chrome/common/extensions/manifest.h"
+#include "extensions/common/manifest.h"
 
 class SkBitmap;
 
diff --git a/chrome/utility/extensions/unpacker_unittest.cc b/chrome/utility/extensions/unpacker_unittest.cc
index 8ddd737..b61a42c 100644
--- a/chrome/utility/extensions/unpacker_unittest.cc
+++ b/chrome/utility/extensions/unpacker_unittest.cc
@@ -17,7 +17,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 
 namespace errors = extension_manifest_errors;
-namespace keys = extension_manifest_keys;
+namespace keys = extensions::manifest_keys;
 
 namespace extensions {
 
diff --git a/chrome/utility/importer/bookmark_html_reader.cc b/chrome/utility/importer/bookmark_html_reader.cc
index 5d34d7b..c70df87 100644
--- a/chrome/utility/importer/bookmark_html_reader.cc
+++ b/chrome/utility/importer/bookmark_html_reader.cc
@@ -112,6 +112,16 @@
     std::string line;
     TrimString(lines[i], " ", &line);
 
+    // Remove "<HR>" if |line| starts with it. "<HR>" is the bookmark entries
+    // separator in Firefox that Chrome does not support. Note that there can be
+    // multiple "<HR>" tags at the beginning of a single line.
+    // See http://crbug.com/257474.
+    static const char kHrTag[] = "<HR>";
+    while (StartsWithASCII(line, kHrTag, false)) {
+      line.erase(0, arraysize(kHrTag) - 1);
+      TrimString(line, " ", &line);
+    }
+
     // Get the encoding of the bookmark file.
     if (internal::ParseCharsetFromLine(line, &charset))
       continue;
diff --git a/chrome/utility/importer/bookmark_html_reader_unittest.cc b/chrome/utility/importer/bookmark_html_reader_unittest.cc
index 72f42cf..6bfb16f 100644
--- a/chrome/utility/importer/bookmark_html_reader_unittest.cc
+++ b/chrome/utility/importer/bookmark_html_reader_unittest.cc
@@ -136,7 +136,30 @@
 
 namespace {
 
-void ExpectFirstFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
+class BookmarkHTMLReaderTestWithData : public testing::Test {
+ public:
+  virtual void SetUp() OVERRIDE;
+
+ protected:
+  void ExpectFirstFirefox2Bookmark(const ImportedBookmarkEntry& entry);
+  void ExpectSecondFirefox2Bookmark(const ImportedBookmarkEntry& entry);
+  void ExpectThirdFirefox2Bookmark(const ImportedBookmarkEntry& entry);
+  void ExpectFirstEpiphanyBookmark(const ImportedBookmarkEntry& entry);
+  void ExpectSecondEpiphanyBookmark(const ImportedBookmarkEntry& entry);
+  void ExpectFirstFirefox23Bookmark(const ImportedBookmarkEntry& entry);
+  void ExpectSecondFirefox23Bookmark(const ImportedBookmarkEntry& entry);
+  void ExpectThirdFirefox23Bookmark(const ImportedBookmarkEntry& entry);
+
+  base::FilePath test_data_path_;
+};
+
+void BookmarkHTMLReaderTestWithData::SetUp() {
+  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_path_));
+  test_data_path_ = test_data_path_.AppendASCII("bookmark_html_reader");
+}
+
+void BookmarkHTMLReaderTestWithData::ExpectFirstFirefox2Bookmark(
+    const ImportedBookmarkEntry& entry) {
   EXPECT_EQ(ASCIIToUTF16("Empty"), entry.title);
   EXPECT_TRUE(entry.is_folder);
   EXPECT_EQ(base::Time::FromTimeT(1295938143), entry.creation_time);
@@ -145,7 +168,8 @@
     EXPECT_EQ(ASCIIToUTF16("Empty's Parent"), entry.path.front());
 }
 
-void ExpectSecondFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
+void BookmarkHTMLReaderTestWithData::ExpectSecondFirefox2Bookmark(
+    const ImportedBookmarkEntry& entry) {
   EXPECT_EQ(ASCIIToUTF16("[Tamura Yukari.com]"), entry.title);
   EXPECT_FALSE(entry.is_folder);
   EXPECT_EQ(base::Time::FromTimeT(1234567890), entry.creation_time);
@@ -155,7 +179,8 @@
   EXPECT_EQ("http://www.tamurayukari.com/", entry.url.spec());
 }
 
-void ExpectThirdFirefox2Bookmark(const ImportedBookmarkEntry& entry) {
+void BookmarkHTMLReaderTestWithData::ExpectThirdFirefox2Bookmark(
+    const ImportedBookmarkEntry& entry) {
   EXPECT_EQ(ASCIIToUTF16("Google"), entry.title);
   EXPECT_FALSE(entry.is_folder);
   EXPECT_EQ(base::Time::FromTimeT(0000000000), entry.creation_time);
@@ -165,25 +190,53 @@
   EXPECT_EQ("http://www.google.com/", entry.url.spec());
 }
 
-void ExpectFirstEpiphanyBookmark(const ImportedBookmarkEntry& entry) {
+void BookmarkHTMLReaderTestWithData::ExpectFirstEpiphanyBookmark(
+    const ImportedBookmarkEntry& entry) {
   EXPECT_EQ(ASCIIToUTF16("[Tamura Yukari.com]"), entry.title);
   EXPECT_EQ("http://www.tamurayukari.com/", entry.url.spec());
   EXPECT_EQ(0U, entry.path.size());
 }
 
-void ExpectSecondEpiphanyBookmark(const ImportedBookmarkEntry& entry) {
+void BookmarkHTMLReaderTestWithData::ExpectSecondEpiphanyBookmark(
+    const ImportedBookmarkEntry& entry) {
   EXPECT_EQ(ASCIIToUTF16("Google"), entry.title);
   EXPECT_EQ("http://www.google.com/", entry.url.spec());
   EXPECT_EQ(0U, entry.path.size());
 }
 
+void BookmarkHTMLReaderTestWithData::ExpectFirstFirefox23Bookmark(
+    const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("Google"), entry.title);
+  EXPECT_FALSE(entry.is_folder);
+  EXPECT_EQ(base::Time::FromTimeT(1376102167), entry.creation_time);
+  EXPECT_EQ(0U, entry.path.size());
+  EXPECT_EQ("https://www.google.com/", entry.url.spec());
+}
+
+void BookmarkHTMLReaderTestWithData::ExpectSecondFirefox23Bookmark(
+    const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("Issues"), entry.title);
+  EXPECT_FALSE(entry.is_folder);
+  EXPECT_EQ(base::Time::FromTimeT(1376102304), entry.creation_time);
+  EXPECT_EQ(1U, entry.path.size());
+  EXPECT_EQ(ASCIIToUTF16("Chromium"), entry.path.front());
+  EXPECT_EQ("https://code.google.com/p/chromium/issues/list", entry.url.spec());
+}
+
+void BookmarkHTMLReaderTestWithData::ExpectThirdFirefox23Bookmark(
+    const ImportedBookmarkEntry& entry) {
+  EXPECT_EQ(ASCIIToUTF16("CodeSearch"), entry.title);
+  EXPECT_FALSE(entry.is_folder);
+  EXPECT_EQ(base::Time::FromTimeT(1376102224), entry.creation_time);
+  EXPECT_EQ(1U, entry.path.size());
+  EXPECT_EQ(ASCIIToUTF16("Chromium"), entry.path.front());
+  EXPECT_EQ("http://code.google.com/p/chromium/codesearch", entry.url.spec());
+}
+
 }  // namespace
 
-TEST(BookmarkHTMLReaderTest, Firefox2BookmarkFileImport) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
-  path = path.AppendASCII("firefox2.html");
+TEST_F(BookmarkHTMLReaderTestWithData, Firefox2BookmarkFileImport) {
+  base::FilePath path = test_data_path_.AppendASCII("firefox2.html");
 
   std::vector<ImportedBookmarkEntry> bookmarks;
   ImportBookmarksFile(base::Callback<bool(void)>(),
@@ -196,11 +249,22 @@
   ExpectThirdFirefox2Bookmark(bookmarks[2]);
 }
 
-TEST(BookmarkHTMLReaderTest, EpiphanyBookmarkFileImport) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
-  path = path.AppendASCII("epiphany.html");
+TEST_F(BookmarkHTMLReaderTestWithData, BookmarkFileWithHrTagImport) {
+  base::FilePath path = test_data_path_.AppendASCII("firefox23.html");
+
+  std::vector<ImportedBookmarkEntry> bookmarks;
+  ImportBookmarksFile(base::Callback<bool(void)>(),
+                      base::Callback<bool(const GURL&)>(),
+                      path, &bookmarks, NULL);
+
+  ASSERT_EQ(3U, bookmarks.size());
+  ExpectFirstFirefox23Bookmark(bookmarks[0]);
+  ExpectSecondFirefox23Bookmark(bookmarks[1]);
+  ExpectThirdFirefox23Bookmark(bookmarks[2]);
+}
+
+TEST_F(BookmarkHTMLReaderTestWithData, EpiphanyBookmarkFileImport) {
+  base::FilePath path = test_data_path_.AppendASCII("epiphany.html");
 
   std::vector<ImportedBookmarkEntry> bookmarks;
   ImportBookmarksFile(base::Callback<bool(void)>(),
@@ -225,12 +289,9 @@
 
 }  // namespace
 
-TEST(BookmarkHTMLReaderTest, CancellationCallback) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
+TEST_F(BookmarkHTMLReaderTestWithData, CancellationCallback) {
   // Use a file for testing that has multiple bookmarks.
-  path = path.AppendASCII("firefox2.html");
+  base::FilePath path = test_data_path_.AppendASCII("firefox2.html");
 
   std::vector<ImportedBookmarkEntry> bookmarks;
   CancelAfterFifteenCalls cancel_fifteen;
@@ -255,12 +316,9 @@
 
 }  // namespace
 
-TEST(BookmarkHTMLReaderTest, ValidURLCallback) {
-  base::FilePath path;
-  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
-  path = path.AppendASCII("bookmark_html_reader");
+TEST_F(BookmarkHTMLReaderTestWithData, ValidURLCallback) {
   // Use a file for testing that has multiple bookmarks.
-  path = path.AppendASCII("firefox2.html");
+  base::FilePath path = test_data_path_.AppendASCII("firefox2.html");
 
   std::vector<ImportedBookmarkEntry> bookmarks;
   ImportBookmarksFile(base::Callback<bool(void)>(),
diff --git a/chrome/utility/local_discovery/service_discovery_message_handler.cc b/chrome/utility/local_discovery/service_discovery_message_handler.cc
index 7591864..e6c84dd 100644
--- a/chrome/utility/local_discovery/service_discovery_message_handler.cc
+++ b/chrome/utility/local_discovery/service_discovery_message_handler.cc
@@ -147,7 +147,7 @@
 }
 
 ServiceDiscoveryMessageHandler::~ServiceDiscoveryMessageHandler() {
-  discovery_thread_.reset();
+  DCHECK(!discovery_thread_);
 }
 
 void ServiceDiscoveryMessageHandler::PreSandboxStartup() {
@@ -200,6 +200,8 @@
                         OnResolveLocalDomain)
     IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_DestroyLocalDomainResolver,
                         OnDestroyLocalDomainResolver)
+    IPC_MESSAGE_HANDLER(LocalDiscoveryMsg_ShutdownLocalDiscovery,
+                        ShutdownLocalDiscovery)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -338,6 +340,26 @@
   local_domain_resolvers_.erase(id);
 }
 
+void ServiceDiscoveryMessageHandler::ShutdownLocalDiscovery() {
+  discovery_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&ServiceDiscoveryMessageHandler::ShutdownOnIOThread,
+                 base::Unretained(this)));
+
+  // This will wait for message loop to drain, so ShutdownOnIOThread will
+  // definitely be called.
+  discovery_thread_.reset();
+}
+
+void ServiceDiscoveryMessageHandler::ShutdownOnIOThread() {
+  service_watchers_.clear();
+  service_resolvers_.clear();
+  local_domain_resolvers_.clear();
+
+  service_discovery_client_.reset();
+  mdns_client_.reset();
+}
+
 void ServiceDiscoveryMessageHandler::OnServiceUpdated(
     uint64 id,
     ServiceWatcher::UpdateType update,
diff --git a/chrome/utility/local_discovery/service_discovery_message_handler.h b/chrome/utility/local_discovery/service_discovery_message_handler.h
index 7537f5a..35c6b03 100644
--- a/chrome/utility/local_discovery/service_discovery_message_handler.h
+++ b/chrome/utility/local_discovery/service_discovery_message_handler.h
@@ -71,6 +71,9 @@
                           net::AddressFamily address_family);
   void DestroyLocalDomainResolver(uint64 id);
 
+  void ShutdownLocalDiscovery();
+  void ShutdownOnIOThread();
+
   // Is called by ServiceWatcher as callback.
   void OnServiceUpdated(uint64 id,
                         ServiceWatcher::UpdateType update,
diff --git a/chrome/utility/media_galleries/picasa_albums_indexer.cc b/chrome/utility/media_galleries/picasa_albums_indexer.cc
index 87c7a47..abaeb3d 100644
--- a/chrome/utility/media_galleries/picasa_albums_indexer.cc
+++ b/chrome/utility/media_galleries/picasa_albums_indexer.cc
@@ -4,11 +4,14 @@
 
 #include "chrome/utility/media_galleries/picasa_albums_indexer.h"
 
+#include <algorithm>
+#include <utility>
 #include <vector>
 
 #include "base/ini_parser.h"
 #include "base/logging.h"
 #include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
 
 namespace picasa {
 
@@ -16,6 +19,7 @@
 
 const char kAlbumSectionHeader[] = ".album:";
 const char kAlbumsKey[] = "albums";
+const int kMaxDedupeNumber = 1000;  // Chosen arbitrarily.
 
 class PicasaINIParser : public base::INIParser {
  public:
@@ -48,8 +52,28 @@
       if (album_map_it == albums_images_->end())
         continue;
 
-      album_map_it->second.insert(
-          folder_path_.Append(base::FilePath::FromUTF8Unsafe(section)));
+      base::FilePath filename = base::FilePath::FromUTF8Unsafe(section);
+      AlbumImages& album_images = album_map_it->second;
+
+      // If filename is first of its name in album, simply add.
+      if (album_images.insert(
+              std::make_pair(section, folder_path_.Append(filename))).second) {
+        continue;
+      }
+
+      // Otherwise, de-dupe by appending a number starting at (1).
+      for (int i = 1; i < kMaxDedupeNumber; ++i) {
+        std::string deduped_filename =
+            filename.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", i))
+                .AsUTF8Unsafe();
+
+        // Attempt to add the de-duped name.
+        if (album_images.insert(
+                std::make_pair(deduped_filename, folder_path_.Append(filename)))
+                .second) {
+          break;
+        }
+      }
     }
   }
 
@@ -70,9 +94,20 @@
 PicasaAlbumsIndexer::~PicasaAlbumsIndexer() {}
 
 void PicasaAlbumsIndexer::ParseFolderINI(
-    const base::FilePath& folder_path, const std::string& ini_contents) {
-  PicasaINIParser parser(folder_path, &albums_images_);
-  parser.Parse(ini_contents);
+    const std::vector<picasa::FolderINIContents>& folders_inis) {
+  // Make a copy for sorting
+  std::vector<picasa::FolderINIContents> folders_inis_sorted = folders_inis;
+
+  // Sort here so image names are deduplicated in a stable ordering.
+  std::sort(folders_inis_sorted.begin(), folders_inis_sorted.end());
+
+  for (std::vector<picasa::FolderINIContents>::const_iterator it =
+           folders_inis_sorted.begin();
+       it != folders_inis_sorted.end();
+       ++it) {
+    PicasaINIParser parser(it->folder_path, &albums_images_);
+    parser.Parse(it->ini_contents);
+  }
 }
 
 }  // namespace picasa
diff --git a/chrome/utility/media_galleries/picasa_albums_indexer.h b/chrome/utility/media_galleries/picasa_albums_indexer.h
index 9cb180f..0eead42 100644
--- a/chrome/utility/media_galleries/picasa_albums_indexer.h
+++ b/chrome/utility/media_galleries/picasa_albums_indexer.h
@@ -48,8 +48,8 @@
   ~PicasaAlbumsIndexer();
 
   // This method should be called once for each Folder in the PMP database.
-  void ParseFolderINI(const base::FilePath& folder_path,
-                      const std::string& ini_contents);
+  void ParseFolderINI(
+      const std::vector<picasa::FolderINIContents>& folders_inis);
 
   const AlbumImagesMap& albums_images() const { return albums_images_; }
 
diff --git a/chrome/utility/media_galleries/picasa_albums_indexer_unittest.cc b/chrome/utility/media_galleries/picasa_albums_indexer_unittest.cc
index 5714d0c..83ab66f 100644
--- a/chrome/utility/media_galleries/picasa_albums_indexer_unittest.cc
+++ b/chrome/utility/media_galleries/picasa_albums_indexer_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/files/file_path.h"
+#include "chrome/common/media_galleries/picasa_types.h"
 #include "chrome/utility/media_galleries/picasa_albums_indexer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -18,7 +19,7 @@
     "[InBoth.jpg]\n"
     "albums=e66fb059001aabcc69b262b7009fad90,18cb2df48aaa98e1c276b45cfcd81c95\n"
     "[.album:18cb2df48aaa98e1c276b45cfcd81c95]\n"
-    "name=CustomAlbum1\n"
+    "name=CustomAlbum2\n"
     "token=18cb2df48aaa98e1c276b45cfcd81c95\n"
     "date=2013-04-01T16:37:34-07:00\n"
     "[InFirst.jpg]\n"
@@ -32,8 +33,12 @@
   valid_album_uuids.insert("18cb2df48aaa98e1c276b45cfcd81c95");
   PicasaAlbumsIndexer indexer(valid_album_uuids);
 
-  base::FilePath folder_dir(FILE_PATH_LITERAL("/foo/baz"));
-  indexer.ParseFolderINI(folder_dir, test_ini_string);
+  std::vector<FolderINIContents> folders_inis;
+  FolderINIContents folder_ini;
+  folder_ini.folder_path = base::FilePath(FILE_PATH_LITERAL("/foo/baz"));
+  folder_ini.ini_contents = test_ini_string;
+  folders_inis.push_back(folder_ini);
+  indexer.ParseFolderINI(folders_inis);
 
   const AlbumImagesMap& albums_images = indexer.albums_images();
   AlbumImagesMap::const_iterator it;
@@ -41,14 +46,75 @@
   it = albums_images.find("e66fb059001aabcc69b262b7009fad90");
   ASSERT_NE(albums_images.end(), it);
   EXPECT_EQ(2u, it->second.size());
-  EXPECT_EQ(1u, it->second.count(folder_dir.AppendASCII("InBoth.jpg")));
-  EXPECT_EQ(1u, it->second.count(folder_dir.AppendASCII("InFirst.jpg")));
+  EXPECT_EQ(1u, it->second.count("InBoth.jpg"));
+  EXPECT_EQ(1u, it->second.count("InFirst.jpg"));
 
   it = albums_images.find("18cb2df48aaa98e1c276b45cfcd81c95");
   ASSERT_NE(albums_images.end(), it);
   EXPECT_EQ(2u, it->second.size());
-  EXPECT_EQ(1u, it->second.count(folder_dir.AppendASCII("InBoth.jpg")));
-  EXPECT_EQ(1u, it->second.count(folder_dir.AppendASCII("InSecond.jpg")));
+  EXPECT_EQ(1u, it->second.count("InBoth.jpg"));
+  EXPECT_EQ(1u, it->second.count("InSecond.jpg"));
+}
+
+TEST(PicasaAlbumsIndexerTest, DedupeNames) {
+  std::set<std::string> valid_album_uuids;
+  valid_album_uuids.insert("e66fb059001aabcc69b262b7009fad90");
+  valid_album_uuids.insert("18cb2df48aaa98e1c276b45cfcd81c95");
+  PicasaAlbumsIndexer indexer(valid_album_uuids);
+
+  std::vector<FolderINIContents> folders_inis;
+  FolderINIContents folder_ini;
+  folder_ini.folder_path = base::FilePath(FILE_PATH_LITERAL("/foo/baz"));
+  folder_ini.ini_contents = test_ini_string;
+  folders_inis.push_back(folder_ini);
+
+  // Add a second folder with just a duplicate InFirst.jpg.
+  folder_ini.folder_path = base::FilePath(FILE_PATH_LITERAL("/foo/second"));
+  folder_ini.ini_contents =
+      "[.album:e66fb059001aabcc69b262b7009fad90]\n"
+      "name=CustomAlbum1\n"
+      "token=e66fb059001aabcc69b262b7009fad90\n"
+      "date=2013-03-15T14:53:21-07:00\n"
+      "[InFirst.jpg]\n"
+      "albums=e66fb059001aabcc69b262b7009fad90\n";
+  folders_inis.push_back(folder_ini);
+
+  // Add a third folder with just a duplicate InFirst.jpg and InSecond.jpg.
+  folder_ini.folder_path = base::FilePath(FILE_PATH_LITERAL("/foo/third"));
+  folder_ini.ini_contents =
+      "[.album:e66fb059001aabcc69b262b7009fad90]\n"
+      "name=CustomAlbum1\n"
+      "token=e66fb059001aabcc69b262b7009fad90\n"
+      "date=2013-03-15T14:53:21-07:00\n"
+      "[.album:18cb2df48aaa98e1c276b45cfcd81c95]\n"
+      "name=CustomAlbum2\n"
+      "token=18cb2df48aaa98e1c276b45cfcd81c95\n"
+      "date=2013-04-01T16:37:34-07:00\n"
+      "[InFirst.jpg]\n"
+      "albums=e66fb059001aabcc69b262b7009fad90\n"
+      "[InSecond.jpg]\n"
+      "albums=18cb2df48aaa98e1c276b45cfcd81c95\n";
+  folders_inis.push_back(folder_ini);
+
+  indexer.ParseFolderINI(folders_inis);
+
+  const AlbumImagesMap& albums_images = indexer.albums_images();
+  AlbumImagesMap::const_iterator it;
+
+  it = albums_images.find("e66fb059001aabcc69b262b7009fad90");
+  ASSERT_NE(albums_images.end(), it);
+  EXPECT_EQ(4u, it->second.size());
+  EXPECT_EQ(1u, it->second.count("InBoth.jpg"));
+  EXPECT_EQ(1u, it->second.count("InFirst.jpg"));
+  EXPECT_EQ(1u, it->second.count("InFirst (1).jpg"));
+  EXPECT_EQ(1u, it->second.count("InFirst (2).jpg"));
+
+  it = albums_images.find("18cb2df48aaa98e1c276b45cfcd81c95");
+  ASSERT_NE(albums_images.end(), it);
+  EXPECT_EQ(3u, it->second.size());
+  EXPECT_EQ(1u, it->second.count("InBoth.jpg"));
+  EXPECT_EQ(1u, it->second.count("InSecond.jpg"));
+  EXPECT_EQ(1u, it->second.count("InSecond (1).jpg"));
 }
 
 TEST(PicasaAlbumsIndexerTest, EdgeCases) {
@@ -57,8 +123,12 @@
   valid_album_uuids.insert("18cb2df48aaa98e1c276b45cfcd81c95");
   PicasaAlbumsIndexer indexer(valid_album_uuids);
 
-  base::FilePath folder_dir(FILE_PATH_LITERAL("/foo/baz"));
-  indexer.ParseFolderINI(folder_dir, test_ini_string);
+  std::vector<FolderINIContents> folders_inis;
+  FolderINIContents folder_ini;
+  folder_ini.folder_path = base::FilePath(FILE_PATH_LITERAL("/foo/baz"));
+  folder_ini.ini_contents = test_ini_string;
+  folders_inis.push_back(folder_ini);
+  indexer.ParseFolderINI(folders_inis);
 
   const AlbumImagesMap& albums_images = indexer.albums_images();
   AlbumImagesMap::const_iterator it;
@@ -76,8 +146,8 @@
   it = albums_images.find("18cb2df48aaa98e1c276b45cfcd81c95");
   EXPECT_NE(albums_images.end(), it);
   EXPECT_EQ(2u, it->second.size());
-  EXPECT_EQ(1u, it->second.count(folder_dir.AppendASCII("InBoth.jpg")));
-  EXPECT_EQ(1u, it->second.count(folder_dir.AppendASCII("InSecond.jpg")));
+  EXPECT_EQ(1u, it->second.count("InBoth.jpg"));
+  EXPECT_EQ(1u, it->second.count("InSecond.jpg"));
 }
 
 }  // namespace
diff --git a/chrome_frame/chrome_frame.gyp b/chrome_frame/chrome_frame.gyp
index b495cc0..f9d13a5 100644
--- a/chrome_frame/chrome_frame.gyp
+++ b/chrome_frame/chrome_frame.gyp
@@ -412,7 +412,7 @@
         '../chrome/chrome.gyp:renderer',
         '../chrome/chrome.gyp:test_support_common',
         '../chrome/chrome_resources.gyp:chrome_resources',
-        '../content/content.gyp:content_app_browser',
+        '../content/content.gyp:content_app_both',
         '../content/content.gyp:content_gpu',
         '../content/content.gyp:test_support_content',
         '../net/net.gyp:net',
diff --git a/chrome_frame/chrome_launcher.cc b/chrome_frame/chrome_launcher.cc
index d9f3a9f..1a78407 100644
--- a/chrome_frame/chrome_launcher.cc
+++ b/chrome_frame/chrome_launcher.cc
@@ -132,7 +132,7 @@
   // doesn't get passed through to Chrome.
   for (int i = 1; i < num_args; ++i) {
     std::wstring trimmed_arg = TrimWhiteSpace(args[i]);
-    if (!IsValidArgument(trimmed_arg.c_str())) {
+    if (!IsValidArgument(trimmed_arg)) {
       success = false;
       break;
     }
diff --git a/chrome_frame/metrics_service.cc b/chrome_frame/metrics_service.cc
index ace75ed..515068f 100644
--- a/chrome_frame/metrics_service.cc
+++ b/chrome_frame/metrics_service.cc
@@ -94,7 +94,7 @@
     DVLOG(1) << __FUNCTION__;
   }
 
-  static HRESULT ChromeFrameMetricsDataUploader::UploadDataHelper(
+  static HRESULT UploadDataHelper(
       const std::string& upload_data,
       const std::string& server_url,
       const std::string& mime_type) {
diff --git a/chrome_frame/policy_settings.cc b/chrome_frame/policy_settings.cc
index 54d7ca1..fb8caf6 100644
--- a/chrome_frame/policy_settings.cc
+++ b/chrome_frame/policy_settings.cc
@@ -84,8 +84,8 @@
 
   DCHECK(value == RENDERER_NOT_SPECIFIED ||
          value == RENDER_IN_HOST ||
-         value == RENDER_IN_CHROME_FRAME) <<
-      "invalid default renderer setting: " << value;
+         value == RENDER_IN_CHROME_FRAME)
+      << "invalid default renderer setting: " << value;
 
   if (value != RENDER_IN_HOST && value != RENDER_IN_CHROME_FRAME) {
     DVLOG(1) << "default renderer not specified via policy";
@@ -105,6 +105,40 @@
 }
 
 // static
+void PolicySettings::ReadMetadataCheckSettings(
+    SkipMetadataCheck* skip_metadata_check) {
+  DCHECK(skip_metadata_check);
+
+  *skip_metadata_check = SKIP_METADATA_CHECK_NOT_SPECIFIED;
+
+  base::win::RegKey config_key;
+  DWORD value = SKIP_METADATA_CHECK_NOT_SPECIFIED;
+  string16 settings_value(
+      ASCIIToWide(policy::key::kSkipMetadataCheck));
+  for (int i = 0; i < arraysize(kRootKeys); ++i) {
+    if ((config_key.Open(kRootKeys[i], policy::kRegistryChromePolicyKey,
+                         KEY_READ) == ERROR_SUCCESS) &&
+        (config_key.ReadValueDW(settings_value.c_str(),
+                                &value) == ERROR_SUCCESS)) {
+      break;
+    }
+  }
+
+  DCHECK(value == SKIP_METADATA_CHECK_NOT_SPECIFIED ||
+         value == SKIP_METADATA_CHECK_NO ||
+         value == SKIP_METADATA_CHECK_YES)
+      << "invalid skip metadata check setting: " << value;
+
+  if (value != SKIP_METADATA_CHECK_NO && value != SKIP_METADATA_CHECK_YES) {
+    DVLOG(1) << "metadata check not specified via policy";
+  } else {
+    *skip_metadata_check = static_cast<SkipMetadataCheck>(value);
+    DVLOG(1) << "SkipMetadata check as specified via policy: "
+             << *skip_metadata_check;
+  }
+}
+
+// static
 void PolicySettings::ReadContentTypeSetting(
     std::vector<std::wstring>* content_type_list) {
   DCHECK(content_type_list);
@@ -156,6 +190,7 @@
 
 void PolicySettings::RefreshFromRegistry() {
   RendererForUrl default_renderer;
+  SkipMetadataCheck skip_metadata_check;
   std::vector<std::wstring> renderer_exclusion_list;
   std::vector<std::wstring> content_type_list;
   std::wstring application_locale;
@@ -165,6 +200,7 @@
 
   // Read the latest settings from the registry
   ReadUrlSettings(&default_renderer, &renderer_exclusion_list);
+  ReadMetadataCheckSettings(&skip_metadata_check);
   ReadContentTypeSetting(&content_type_list);
   ReadStringSetting(policy::key::kApplicationLocaleValue, &application_locale);
   ReadStringSetting(policy::key::kAdditionalLaunchParameters,
@@ -181,6 +217,7 @@
   using std::swap;
 
   swap(default_renderer_, default_renderer);
+  swap(skip_metadata_check_, skip_metadata_check);
   swap(renderer_exclusion_list_, renderer_exclusion_list);
   swap(content_type_list_, content_type_list);
   swap(application_locale_, application_locale);
diff --git a/chrome_frame/policy_settings.h b/chrome_frame/policy_settings.h
index 104f713..7b282d4 100644
--- a/chrome_frame/policy_settings.h
+++ b/chrome_frame/policy_settings.h
@@ -17,18 +17,28 @@
 // TODO(tommi): Use Chrome's classes for this (and the notification service).
 class PolicySettings {
  public:
-  typedef enum RendererForUrl {
+  enum RendererForUrl {
     RENDERER_NOT_SPECIFIED = -1,
     RENDER_IN_HOST,
     RENDER_IN_CHROME_FRAME,
   };
 
+  enum SkipMetadataCheck {
+    SKIP_METADATA_CHECK_NOT_SPECIFIED = -1,
+    SKIP_METADATA_CHECK_NO,
+    SKIP_METADATA_CHECK_YES,
+  };
+
   static PolicySettings* GetInstance();
 
   RendererForUrl default_renderer() const {
     return default_renderer_;
   }
 
+  SkipMetadataCheck skip_metadata_check() const {
+    return skip_metadata_check_;
+  }
+
   RendererForUrl GetRendererForUrl(const wchar_t* url);
 
   RendererForUrl GetRendererForContentType(const wchar_t* content_type);
@@ -52,6 +62,7 @@
   // Helper functions for reading settings from the registry
   static void ReadUrlSettings(RendererForUrl* default_renderer,
       std::vector<std::wstring>* renderer_exclusion_list);
+  static void ReadMetadataCheckSettings(SkipMetadataCheck* skip_metadata_check);
   static void ReadContentTypeSetting(
       std::vector<std::wstring>* content_type_list);
   static void ReadStringSetting(const char* value_name, std::wstring* value);
@@ -60,6 +71,7 @@
  protected:
   PolicySettings()
       : default_renderer_(RENDERER_NOT_SPECIFIED),
+        skip_metadata_check_(SKIP_METADATA_CHECK_NOT_SPECIFIED),
         additional_launch_parameters_(CommandLine::NO_PROGRAM),
         suppress_turndown_prompt_(false) {
     RefreshFromRegistry();
@@ -73,6 +85,7 @@
 
  protected:
   RendererForUrl default_renderer_;
+  SkipMetadataCheck skip_metadata_check_;
   std::vector<std::wstring> renderer_exclusion_list_;
   std::vector<std::wstring> content_type_list_;
   std::wstring application_locale_;
diff --git a/chrome_frame/protocol_sink_wrap.cc b/chrome_frame/protocol_sink_wrap.cc
index 93bf4d7..b94e7c0 100644
--- a/chrome_frame/protocol_sink_wrap.cc
+++ b/chrome_frame/protocol_sink_wrap.cc
@@ -4,6 +4,7 @@
 
 #include <htiframe.h>
 #include <mshtml.h>
+#include <algorithm>
 
 #include "chrome_frame/protocol_sink_wrap.h"
 
@@ -21,6 +22,8 @@
 #include "chrome_frame/policy_settings.h"
 #include "chrome_frame/utils.h"
 
+using std::min;
+
 // BINDSTATUS_SERVER_MIMETYPEAVAILABLE == 54. Introduced in IE 8, so
 // not in everyone's headers yet. See:
 // http://msdn.microsoft.com/en-us/library/ms775133(VS.85,loband).aspx
@@ -478,7 +481,8 @@
     last_chance = true;
   }
 
-  renderer_type_ = DetermineRendererType(buffer_, buffer_size_, last_chance);
+  renderer_type_ = SkipMetadataCheck() ? RENDERER_TYPE_OTHER
+      : DetermineRendererType(buffer_, buffer_size_, last_chance);
 
   if (renderer_type_ == RENDERER_TYPE_UNDETERMINED) {
     // do not report anything, we need more data.
diff --git a/chrome_frame/test/ie_event_sink.cc b/chrome_frame/test/ie_event_sink.cc
index 5ac8be9..9062a9c 100644
--- a/chrome_frame/test/ie_event_sink.cc
+++ b/chrome_frame/test/ie_event_sink.cc
@@ -230,8 +230,7 @@
 }
 
 HRESULT IEEventSink::Attach(IWebBrowser2* browser) {
-  DCHECK(browser);
-  HRESULT result;
+  HRESULT result = E_INVALIDARG;
   if (browser) {
     web_browser2_ = browser;
     FindIEProcessId();
diff --git a/chrome_frame/test/mock_ie_event_sink_actions.h b/chrome_frame/test/mock_ie_event_sink_actions.h
index 9c8f4c7..9aa57a1 100644
--- a/chrome_frame/test/mock_ie_event_sink_actions.h
+++ b/chrome_frame/test/mock_ie_event_sink_actions.h
@@ -36,11 +36,15 @@
 }
 
 // Returns true if the title of the page rendered in the window |arg| equals
-// |the_title|. For pages rendered in Chrome, the title of the parent of |arg|
-// is the page title. For pages rendered in IE, the title of the grandparent of
-// |arg| begins with the page title. To handle both cases, attempt a prefix
-// match on each window starting with the parent of |arg|.
-MATCHER_P(TabContentsTitleEq, the_title, "") {
+// |the_url| or |the_title|. For pages rendered in Chrome, the title of the
+// parent of |arg| is the page url or title. For pages rendered in IE, the title
+// of the grandparent of |arg| begins with the page url or title. To handle both
+// cases, attempt a prefix match on each window starting with the parent of
+// |arg|. Both url and title are matched to account for a race between the test
+// and Chrome when the window title is transitioned from the url to the title.
+MATCHER_P2(TabContentsTitleEq, the_url, the_title, "") {
+  const string16 url(the_url);
+  DCHECK(!url.empty());
   const string16 title(the_title);
   DCHECK(!title.empty());
   HWND parent = GetParent(arg);
@@ -53,8 +57,10 @@
       parent_title.resize(GetWindowText(parent, &parent_title[0],
                                         parent_title.size()));
       if (parent_title.size() >= title.size() &&
-          std::equal(title.begin(), title.end(), parent_title.begin())) {
-          return true;
+          std::equal(title.begin(), title.end(), parent_title.begin()) ||
+          parent_title.size() >= url.size() &&
+          std::equal(url.begin(), url.end(), parent_title.begin())) {
+        return true;
       }
       titles_found << "\"" << UTF16ToASCII(parent_title) << "\" ";
       parent = GetParent(parent);
diff --git a/chrome_frame/test/navigation_test.cc b/chrome_frame/test/navigation_test.cc
index 1f8485f..2f5ab33 100644
--- a/chrome_frame/test/navigation_test.cc
+++ b/chrome_frame/test/navigation_test.cc
@@ -205,7 +205,8 @@
   // Forward: 0
   EXPECT_CALL(ie_mock_, OnLoad(in_cf, StrEq(GetAnchorPageUrl(0))))
       .Times(testing::AtMost(1));
-  EXPECT_CALL(acc_observer, OnAccDocLoad(TabContentsTitleEq(title)))
+  EXPECT_CALL(acc_observer, OnAccDocLoad(TabContentsTitleEq(GetAnchorPageUrl(0),
+                                                            title)))
       .WillOnce(AccDoDefaultAction(AccObjectMatcher(L"*1", L"link")))
       .RetiresOnSaturation();
 
@@ -347,7 +348,8 @@
 
   EXPECT_CALL(ie_mock_, OnLoad(GetParam().invokes_cf(), StrEq(parent_url)));
   EXPECT_CALL(acc_observer,
-              OnAccDocLoad(TabContentsTitleEq(GetWindowOpenTitle())))
+              OnAccDocLoad(TabContentsTitleEq(parent_url,
+                                              GetWindowOpenTitle())))
       .WillOnce(AccLeftClick(AccObjectMatcher()));
 
   ie_mock_.ExpectNewWindow(&new_window_mock);
@@ -390,7 +392,8 @@
   // unless a click is involved.
   EXPECT_CALL(ie_mock_, OnLoad(GetParam().invokes_cf(), StrEq(parent_url)));
   EXPECT_CALL(acc_observer,
-              OnAccDocLoad(TabContentsTitleEq(GetWindowOpenTitle())))
+              OnAccDocLoad(TabContentsTitleEq(parent_url,
+                                              GetWindowOpenTitle())))
       .WillOnce(AccLeftClick(AccObjectMatcher()));
 
   ie_mock_.ExpectNewWindow(&new_window_mock);
@@ -485,7 +488,8 @@
   // Tell the page to open the popup. Some versions of IE will prevent a popup
   // unless a click is involved.
   EXPECT_CALL(acc_observer,
-              OnAccDocLoad(TabContentsTitleEq(GetWindowOpenTitle())))
+              OnAccDocLoad(TabContentsTitleEq(parent_url,
+                                              GetWindowOpenTitle())))
       .WillOnce(AccLeftClick(AccObjectMatcher()));
 
   // If the parent window is in CF, the child should always load in CF since
@@ -546,7 +550,8 @@
       .WillRepeatedly(SendResponse(&server_mock_, page1_));
   EXPECT_CALL(ie_mock_, OnLoad(page1_.invokes_cf(), StrEq(GetLinkPageUrl())));
   EXPECT_CALL(acc_observer,
-              OnAccDocLoad(TabContentsTitleEq(GetLinkPageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(GetLinkPageUrl(),
+                                              GetLinkPageTitle())))
       .WillOnce(AccDoDefaultAction(AccObjectMatcher(L"", L"link")))
       .RetiresOnSaturation();
 
@@ -650,7 +655,8 @@
   LaunchIEAndNavigate(kDownloadFromNewWin);
 }
 
-TEST_P(FullTabNavigationTest, FormPostBackForward) {
+// Flaky on ie6, http://crbug.com/255098.
+TEST_P(FullTabNavigationTest, DISABLED_FormPostBackForward) {
   bool in_cf = GetParam().invokes_cf();
   // Navigate to the form-get.html page:
   // - First set focus to chrome renderer window
@@ -668,7 +674,8 @@
   server_mock_.ExpectAndServeAnyRequests(GetParam());
   EXPECT_CALL(acc_observer, OnAccDocLoad(_)).Times(testing::AnyNumber());
 
-  EXPECT_CALL(acc_observer, OnAccDocLoad(TabContentsTitleEq(kFormPostTitle)))
+  EXPECT_CALL(acc_observer, OnAccDocLoad(TabContentsTitleEq(kFormPostUrl,
+                                                            kFormPostTitle)))
       .WillOnce(AccDoDefaultAction(AccObjectMatcher(L"Submit")))
       .RetiresOnSaturation();
 
@@ -1236,7 +1243,8 @@
   EXPECT_CALL(ie_mock_, OnLoad(false, StrEq(initial_url)));
 
   EXPECT_CALL(acc_observer,
-              OnAccDocLoad(TabContentsTitleEq(GetWindowOpenTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url,
+                                              GetWindowOpenTitle())))
       .WillOnce(AccLeftClick(AccObjectMatcher()))
       .RetiresOnSaturation();
 
diff --git a/chrome_frame/test/net/fake_external_tab.cc b/chrome_frame/test/net/fake_external_tab.cc
index d15bc1a..3922e96 100644
--- a/chrome_frame/test/net/fake_external_tab.cc
+++ b/chrome_frame/test/net/fake_external_tab.cc
@@ -331,7 +331,10 @@
     "HTTPSCRLSetTest.*",
 
     // Chrome Frame doesn't support GetFullRequestHeaders.
-    "URLRequestTest*.*_GetFullRequestHeaders"
+    "URLRequestTest*.*_GetFullRequestHeaders",
+
+    // IE redirects to data: URLs differently.
+    "URLRequestTestHTTP.RestrictDataRedirects"
   };
 
   const char* ie9_disabled_tests[] = {
diff --git a/chrome_frame/test/net/test_automation_provider.cc b/chrome_frame/test/net/test_automation_provider.cc
index 496e943..9acec9a 100644
--- a/chrome_frame/test/net/test_automation_provider.cc
+++ b/chrome_frame/test/net/test_automation_provider.cc
@@ -77,7 +77,7 @@
   if (CFTestsDisabled())
     return NULL;
 
-  if (request->url().SchemeIs("http") || request->url().SchemeIs("https")) {
+  if (request->url().SchemeIsHTTPOrHTTPS()) {
     // Only look at requests that don't have any user data.
     // ResourceDispatcherHost uses the user data for requests that it manages.
     // We don't want to mess with those.
diff --git a/chrome_frame/test/ui_test.cc b/chrome_frame/test/ui_test.cc
index f44fec1..8823a2e 100644
--- a/chrome_frame/test/ui_test.cc
+++ b/chrome_frame/test/ui_test.cc
@@ -360,7 +360,8 @@
 
 // Tests that Chrome gets re-instantiated after crash if we reload via
 // the address bar or via a new navigation.
-TEST_P(FullTabUITest, TabCrashReload) {
+// Flaky on ie7, http://crbug.com/277406.
+TEST_P(FullTabUITest, DISABLED_TabCrashReload) {
   using testing::DoAll;
 
   if (!GetParam().invokes_cf()) {
@@ -483,9 +484,11 @@
     InSequence expect_in_sequence_for_scope;
 
     // Open 'Save As' dialog.
+    string16 initial_url(GetTestUrl(L"save_as_context_menu.html"));
     const char* kSaveDlgCaption = "Save As";
     EXPECT_CALL(acc_observer_,
-                OnAccDocLoad(TabContentsTitleEq(L"Save As download test")))
+                OnAccDocLoad(TabContentsTitleEq(initial_url,
+                                                L"Save As download test")))
         .WillOnce(testing::DoAll(
             WatchWindow(&win_observer_mock, kSaveDlgCaption, ""),
             AccRightClick(AccObjectMatcher(L"", role))));
@@ -508,7 +511,7 @@
     EXPECT_CALL(win_observer_mock, OnWindowClose(_))
         .WillOnce(CloseWhenFileSaved(&ie_mock_, temp_file_path, 8000));
 
-    LaunchIENavigateAndLoop(GetTestUrl(L"save_as_context_menu.html"),
+    LaunchIENavigateAndLoop(initial_url,
                             kChromeFrameVeryLongNavigationTimeout);
     ASSERT_TRUE(file_util::DieFileDie(temp_file_path, false));
   }
@@ -529,16 +532,18 @@
   server_mock_.ExpectAndServeAnyRequests(CFInvocation::MetaTag());
   InSequence expect_in_sequence_for_scope;
 
+  string16 initial_url(GetSimplePageUrl());
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetSimplePageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url,
+                                              GetSimplePageTitle())))
       .WillOnce(OpenContextMenuAsync());
   EXPECT_CALL(acc_observer_, OnMenuPopup(_))
       .WillOnce(AccLeftClick(AccObjectMatcher(L"Reload")));
 
-  EXPECT_CALL(ie_mock_, OnLoad(IN_CF, StrEq(GetSimplePageUrl())))
+  EXPECT_CALL(ie_mock_, OnLoad(IN_CF, StrEq(initial_url)))
       .WillOnce(CloseBrowserMock(&ie_mock_));
 
-  LaunchIEAndNavigate(GetSimplePageUrl());
+  LaunchIEAndNavigate(initial_url);
 }
 
 // Test view source from the context menu.
@@ -554,10 +559,12 @@
   MockIEEventSink view_source_mock;
   view_source_mock.ExpectAnyNavigations();
   InSequence expect_in_sequence_for_scope;
+  string16 initial_url(GetSimplePageUrl());
 
   // View the page source.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetSimplePageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url,
+                                              GetSimplePageTitle())))
       .WillOnce(OpenContextMenuAsync());
   EXPECT_CALL(acc_observer_, OnMenuPopup(_))
       .WillOnce(AccLeftClick(AccObjectMatcher(L"View page source")));
@@ -567,7 +574,7 @@
   std::wstring view_source_url;
   view_source_url += UTF8ToWide(content::kViewSourceScheme);
   view_source_url += L":";
-  view_source_url += GetSimplePageUrl();
+  view_source_url += initial_url;
   std::wstring url_in_new_window = kChromeProtocolPrefix;
   url_in_new_window += view_source_url;
 
@@ -583,17 +590,19 @@
       .Times(testing::AtMost(1))
       .WillOnce(CloseBrowserMock(&ie_mock_));
 
-  LaunchIEAndNavigate(GetSimplePageUrl());
+  LaunchIEAndNavigate(initial_url);
 }
 
 TEST_F(ContextMenuTest, DISABLED_CFPageInfo) {
   server_mock_.ExpectAndServeAnyRequests(CFInvocation::MetaTag());
   MockWindowObserver win_observer_mock;
   InSequence expect_in_sequence_for_scope;
+  string16 initial_url(GetSimplePageUrl());
 
   // View page information.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetSimplePageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url,
+                                              GetSimplePageTitle())))
       .WillOnce(testing::DoAll(
           WatchWindow(&win_observer_mock, "", "Chrome_WidgetWin_*"),
           OpenContextMenuAsync()));
@@ -609,7 +618,7 @@
   EXPECT_CALL(win_observer_mock, OnWindowClose(_))
     .WillOnce(CloseBrowserMock(&ie_mock_));
 
-  LaunchIEAndNavigate(GetSimplePageUrl());
+  LaunchIEAndNavigate(initial_url);
 }
 
 TEST_F(ContextMenuTest, CFInspector) {
@@ -621,8 +630,10 @@
   // Devtools begins life with "Untitled" caption and it changes
   // later to the 'Developer Tools - <url> form.
   const char* kPageInfoCaptionPattern = "Untitled*";
+  string16 initial_url(GetSimplePageUrl());
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetSimplePageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url,
+                                              GetSimplePageTitle())))
       .WillOnce(testing::DoAll(
           WatchWindow(&win_observer_mock, kPageInfoCaptionPattern, ""),
           OpenContextMenuAsync()));
@@ -634,7 +645,7 @@
   EXPECT_CALL(win_observer_mock, OnWindowClose(_))
       .WillOnce(CloseBrowserMock(&ie_mock_));
 
-  LaunchIENavigateAndLoop(GetSimplePageUrl(),
+  LaunchIENavigateAndLoop(initial_url,
                           kChromeFrameVeryLongNavigationTimeout);
 }
 
@@ -677,9 +688,11 @@
   MockIEEventSink new_window_mock;
   new_window_mock.ExpectAnyNavigations();
   InSequence expect_in_sequence_for_scope;
+  string16 initial_url(GetSimplePageUrl());
 
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetSimplePageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url,
+                                              GetSimplePageTitle())))
       .WillOnce(OpenContextMenuAsync());
   EXPECT_CALL(acc_observer_, OnMenuPopup(_))
       .WillOnce(AccLeftClick(AccObjectMatcher(L"About*")));
@@ -698,16 +711,17 @@
       .Times(testing::AtMost(1))
       .WillOnce(CloseBrowserMock(&ie_mock_));
 
-  LaunchIEAndNavigate(GetSimplePageUrl());
+  LaunchIEAndNavigate(initial_url);
 }
 
 TEST_F(ContextMenuTest, IEOpen) {
   server_mock_.ExpectAndServeAnyRequests(CFInvocation::None());
   InSequence expect_in_sequence_for_scope;
+  string16 initial_url(GetLinkPageUrl());
 
   // Open the link through the context menu.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetLinkPageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url, GetLinkPageTitle())))
       .WillOnce(AccRightClick(AccObjectMatcher(L"", L"link")));
   EXPECT_CALL(acc_observer_, OnMenuPopup(_))
       .WillOnce(AccLeftClick(AccObjectMatcher(L"Open")));
@@ -717,7 +731,7 @@
           VerifyAddressBarUrl(&ie_mock_),
           CloseBrowserMock(&ie_mock_)));
 
-  LaunchIEAndNavigate(GetLinkPageUrl());
+  LaunchIEAndNavigate(initial_url);
 }
 
 TEST_F(ContextMenuTest, IEOpenInNewWindow) {
@@ -730,10 +744,11 @@
   MockIEEventSink new_window_mock;
   new_window_mock.ExpectAnyNavigations();
   InSequence expect_in_sequence_for_scope;
+  string16 initial_url(GetLinkPageUrl());
 
   // Open the link in a new window.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetLinkPageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url, GetLinkPageTitle())))
       .WillOnce(AccRightClick(AccObjectMatcher(L"", L"link")));
   EXPECT_CALL(acc_observer_, OnMenuPopup(_))
       .WillOnce(AccLeftClick(AccObjectMatcher(L"Open in New Window")));
@@ -748,7 +763,7 @@
       .Times(testing::AtMost(1))
       .WillOnce(CloseBrowserMock(&ie_mock_));
 
-  LaunchIEAndNavigate(GetLinkPageUrl());
+  LaunchIEAndNavigate(initial_url);
 }
 
 // Test Back/Forward from context menu.
@@ -761,11 +776,11 @@
   InSequence expect_in_sequence_for_scope;
 
   // Navigate to second page.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title1)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page1, title1)))
       .WillOnce(Navigate(&ie_mock_, page2));
 
   // Go back.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title2)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page2, title2)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_IE, page2),
           OpenContextMenuAsync()));
@@ -773,7 +788,7 @@
       .WillOnce(AccLeftClick(AccObjectMatcher(L"Back")));
 
   // Go forward.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title1)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page1, title1)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_IE, page1),
           OpenContextMenuAsync()));
@@ -792,10 +807,11 @@
   server_mock_.ExpectAndServeAnyRequests(CFInvocation::MetaTag());
   MockIEEventSink new_window_mock;
   new_window_mock.ExpectAnyNavigations();
+  string16 initial_url(GetLinkPageUrl());
 
   // Invoke 'Open link in new window' context menu item.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetLinkPageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url, GetLinkPageTitle())))
       .Times(testing::AtMost(2))
       .WillOnce(AccRightClick(AccObjectMatcher(L"", L"link")))
       .WillOnce(testing::Return());
@@ -808,23 +824,24 @@
   EXPECT_CALL(new_window_mock, OnQuit())
       .WillOnce(CloseBrowserMock(&ie_mock_));
 
-  LaunchIEAndNavigate(GetLinkPageUrl());
+  LaunchIEAndNavigate(initial_url);
 }
 
 // Test CF link context menu - Copy link address.
 TEST_F(ContextMenuTest, CFCopyLinkAddress) {
   server_mock_.ExpectAndServeAnyRequests(CFInvocation::MetaTag());
+  string16 initial_url(GetLinkPageUrl());
 
   // Invoke 'Copy link address' context menu item.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(GetLinkPageTitle())))
+              OnAccDocLoad(TabContentsTitleEq(initial_url, GetLinkPageTitle())))
       .WillOnce(AccRightClick(AccObjectMatcher(L"", L"link")));
   EXPECT_CALL(acc_observer_, OnMenuPopup(_))
       .WillOnce(testing::DoAll(
           AccLeftClick(AccObjectMatcher(L"Copy link address*")),
           CloseBrowserMock(&ie_mock_)));
 
-  LaunchIEAndNavigate(GetLinkPageUrl());
+  LaunchIEAndNavigate(initial_url);
 
   EXPECT_STREQ(GetSimplePageUrl().c_str(), GetClipboardText().c_str());
 }
@@ -837,7 +854,8 @@
 
   // Invoke "Cut" context menu item of text field.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(context_menu_page_title)))
+              OnAccDocLoad(TabContentsTitleEq(context_menu_page_url,
+                                              context_menu_page_title)))
       .WillOnce(testing::DoAll(
           AccRightClick(txtfield_matcher),
           AccWatchForOneValueChange(&acc_observer_, txtfield_matcher)));
@@ -861,7 +879,8 @@
 
   // Invoke "Copy" context menu item of text field.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(context_menu_page_title)))
+              OnAccDocLoad(TabContentsTitleEq(context_menu_page_url,
+                                              context_menu_page_title)))
       .WillOnce(testing::DoAll(
           AccRightClick(txtfield_matcher),
           AccWatchForOneValueChange(&acc_observer_, txtfield_matcher)));
@@ -887,7 +906,8 @@
 
   // Invoke "Paste" context menu item of text field.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(context_menu_page_title)))
+              OnAccDocLoad(TabContentsTitleEq(context_menu_page_url,
+                                              context_menu_page_title)))
       .WillOnce(testing::DoAll(
           AccRightClick(txtfield_matcher),
           AccWatchForOneValueChange(&acc_observer_, txtfield_matcher)));
@@ -911,7 +931,8 @@
 
   // Invoke 'Delete' context menu item of text field.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(context_menu_page_title)))
+              OnAccDocLoad(TabContentsTitleEq(context_menu_page_url,
+                                              context_menu_page_title)))
       .WillOnce(testing::DoAll(
           AccRightClick(txtfield_matcher),
           AccWatchForOneValueChange(&acc_observer_, txtfield_matcher)));
@@ -931,7 +952,8 @@
 
   // Invoke 'Select all' context menu item of text field.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(context_menu_page_title)))
+              OnAccDocLoad(TabContentsTitleEq(context_menu_page_url,
+                                              context_menu_page_title)))
       .WillOnce(AccRightClick(AccObjectMatcher(L"", L"editable text")));
   EXPECT_CALL(acc_observer_, OnMenuPopup(_))
       .WillOnce(testing::DoAll(
@@ -953,7 +975,8 @@
 
   // Change the value of text field to 'A'.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(context_menu_page_title)))
+              OnAccDocLoad(TabContentsTitleEq(context_menu_page_url,
+                                              context_menu_page_title)))
       .WillOnce(testing::DoAll(
           AccWatchForOneValueChange(&acc_observer_, txtfield_matcher),
           AccSendCharMessage(txtfield_matcher, L'A')));
@@ -982,7 +1005,8 @@
 
   // Change text field from its initial value to 'A'.
   EXPECT_CALL(acc_observer_,
-              OnAccDocLoad(TabContentsTitleEq(context_menu_page_title)))
+              OnAccDocLoad(TabContentsTitleEq(context_menu_page_url,
+                                              context_menu_page_title)))
       .WillOnce(testing::DoAll(
           AccWatchForOneValueChange(&acc_observer_, txtfield_matcher),
           AccSendCharMessage(txtfield_matcher, L'A')));
@@ -1033,19 +1057,19 @@
   InSequence expect_in_sequence_for_scope;
 
   // Navigate to second page.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title1)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page1, title1)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_CF, page1),
           Navigate(&ie_mock_, page2)));
 
   // Navigate to third page.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title2)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page2, title2)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_IE, page2),
           Navigate(&ie_mock_, page3)));
 
   // Go back.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title3)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page3, title3)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_CF, page3),
           OpenContextMenuAsync()));
@@ -1054,7 +1078,7 @@
       .WillOnce(AccLeftClick(AccObjectMatcher(L"Back")));
 
   // Go back
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title2)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page2, title2)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_IE, page2),
           OpenContextMenuAsync()));
@@ -1063,7 +1087,7 @@
       .WillOnce(AccLeftClick(AccObjectMatcher(L"Back")));
 
   // Go forward.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title1)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page1, title1)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_CF, page1),
           OpenContextMenuAsync()));
@@ -1072,7 +1096,7 @@
       .WillOnce(AccLeftClick(AccObjectMatcher(L"Forward")));
 
   // Go forward.
-  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(title2)))
+  EXPECT_CALL(acc_observer_, OnAccDocLoad(TabContentsTitleEq(page2, title2)))
       .WillOnce(testing::DoAll(
           VerifyPageLoad(&ie_mock_, IN_IE, page2),
           OpenContextMenuAsync()));
diff --git a/chrome_frame/urlmon_bind_status_callback.cc b/chrome_frame/urlmon_bind_status_callback.cc
index 006e20e..056ea5e 100644
--- a/chrome_frame/urlmon_bind_status_callback.cc
+++ b/chrome_frame/urlmon_bind_status_callback.cc
@@ -320,6 +320,8 @@
   ExceptionBarrier barrier;
 
   HRESULT hr = MayPlayBack(BSCF_LASTDATANOTIFICATION);
+  if (FAILED(hr))
+    return hr;
   hr = CallbackImpl::OnStopBinding(hresult, error);
   ReleaseBind();
   return hr;
diff --git a/chrome_frame/urlmon_moniker.cc b/chrome_frame/urlmon_moniker.cc
index d2d5b11..432dd92 100644
--- a/chrome_frame/urlmon_moniker.cc
+++ b/chrome_frame/urlmon_moniker.cc
@@ -243,6 +243,7 @@
   CComObject<BSCBStorageBind>* callback = NULL;
   if (ShouldWrapCallback(me, iid, bind_ctx)) {
     hr = CComObject<BSCBStorageBind>::CreateInstance(&callback);
+    DCHECK(SUCCEEDED(hr));
     auto_release_callback = callback;
     DCHECK_EQ(callback->m_dwRef, 1);
     hr = callback->Initialize(me, bind_ctx);
diff --git a/chrome_frame/utils.cc b/chrome_frame/utils.cc
index 149d721..02101ed 100644
--- a/chrome_frame/utils.cc
+++ b/chrome_frame/utils.cc
@@ -9,6 +9,7 @@
 #include <htiframe.h>
 #include <mshtml.h>
 #include <shlobj.h>
+#include <limits>
 
 #include "base/file_version_info.h"
 #include "base/lazy_instance.h"
@@ -65,6 +66,7 @@
 const wchar_t kChromeFrameConfigKey[] = L"Software\\Google\\ChromeFrame";
 const wchar_t kEnableBuggyBhoIntercept[] = L"EnableBuggyBhoIntercept";
 const wchar_t kEnableGCFRendererByDefault[] = L"IsDefaultRenderer";
+const wchar_t kSkipGCFMetadataCheck[] = L"SkipGCFMetadataCheck";
 const wchar_t kExcludeUAFromDomainList[] = L"ExcludeUAFromDomain";
 const wchar_t kPatchProtocols[] = L"PatchProtocols";
 const wchar_t kRenderInGCFUrlList[] = L"RenderInGcfUrls";
@@ -737,6 +739,24 @@
   return is_default != 0;
 }
 
+// Check for the registry key 'SkipGCFMetadataCheck' and if true, then
+// ignore presence of <meta http-equiv="X-UA-Compatible" content="chrome=1">
+bool SkipMetadataCheck() {
+  // Check policy settings
+  PolicySettings::SkipMetadataCheck metadataCheck =
+      PolicySettings::GetInstance()->skip_metadata_check();
+  if (metadataCheck != PolicySettings::SKIP_METADATA_CHECK_NOT_SPECIFIED)
+    return (metadataCheck == PolicySettings::SKIP_METADATA_CHECK_YES);
+
+  DWORD skip = 0;
+  RegKey config_key;
+  if (config_key.Open(HKEY_CURRENT_USER, kChromeFrameConfigKey,
+                      KEY_READ) == ERROR_SUCCESS) {
+    config_key.ReadValueDW(kSkipGCFMetadataCheck, &skip);
+  }
+  return skip != 0;
+}
+
 RendererType RendererTypeForUrl(const std::wstring& url) {
   // First check if the default renderer settings are specified by policy.
   // If so, then that overrides the user settings.
diff --git a/chrome_frame/utils.h b/chrome_frame/utils.h
index d0ee2fd..95b9756 100644
--- a/chrome_frame/utils.h
+++ b/chrome_frame/utils.h
@@ -276,6 +276,11 @@
 // Returns true if all HTML pages should be rendered in GCF by default.
 bool IsGcfDefaultRenderer();
 
+// Returns true if the presence of
+// <meta http-equiv="X-UA-Compatible" content="chrome=1">
+// in HTML pages should be ignored
+bool SkipMetadataCheck();
+
 // Check if this url is opting into Chrome Frame based on static settings.
 // Returns one of:
 // - RENDERER_TYPE_UNDETERMINED if not opt-in or if explicit opt-out
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 728cc40..5cfbdbe 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-4521.0.0
\ No newline at end of file
+4580.0.0
\ No newline at end of file
diff --git a/chromeos/attestation/attestation_constants.cc b/chromeos/attestation/attestation_constants.cc
index 9f3833b..51d4e44 100644
--- a/chromeos/attestation/attestation_constants.cc
+++ b/chromeos/attestation/attestation_constants.cc
@@ -9,6 +9,7 @@
 
 const char kEnterpriseMachineKey[] = "attest-ent-machine";
 const char kEnterpriseUserKey[] = "attest-ent-user";
+const char kContentProtectionKeyPrefix[] = "attest-cp-";
 
 }  // namespace attestation
 }  // namespace chromeos
diff --git a/chromeos/attestation/attestation_constants.h b/chromeos/attestation/attestation_constants.h
index a704cfc..1429004 100644
--- a/chromeos/attestation/attestation_constants.h
+++ b/chromeos/attestation/attestation_constants.h
@@ -10,17 +10,6 @@
 namespace chromeos {
 namespace attestation {
 
-// Options available for customizing an attestation certificate.
-enum AttestationCertificateOptions {
-  CERTIFICATE_OPTION_NONE = 0,
-  // A stable identifier is simply an identifier that is not affected by device
-  // state changes, including device recovery.
-  CERTIFICATE_INCLUDE_STABLE_ID = 1,
-  // Device state information contains a quoted assertion of whether the device
-  // is in verified mode.
-  CERTIFICATE_INCLUDE_DEVICE_STATE = 1 << 1,
-};
-
 // Key types supported by the Chrome OS attestation subsystem.
 enum AttestationKeyType {
   // The key will be associated with the device itself and will be available
@@ -48,6 +37,8 @@
   // Uses the following certificate options:
   //   CERTIFICATE_INCLUDE_DEVICE_STATE
   PROFILE_ENTERPRISE_USER_CERTIFICATE,
+  // A profile for certificates intended for protected content providers.
+  PROFILE_CONTENT_PROTECTION_CERTIFICATE,
 };
 
 // A key name for the Enterprise Machine Key.  This key should always be stored
@@ -58,6 +49,10 @@
 // a USER_KEY.
 CHROMEOS_EXPORT extern const char kEnterpriseUserKey[];
 
+// The key name prefix for content protection keys.  This prefix must be
+// appended with an origin-specific identifier to form the final key name.
+CHROMEOS_EXPORT extern const char kContentProtectionKeyPrefix[];
+
 }  // namespace attestation
 }  // namespace chromeos
 
diff --git a/chromeos/attestation/attestation_flow.cc b/chromeos/attestation/attestation_flow.cc
index 2fba761..9b22b65 100644
--- a/chromeos/attestation/attestation_flow.cc
+++ b/chromeos/attestation/attestation_flow.cc
@@ -59,36 +59,27 @@
     case PROFILE_ENTERPRISE_MACHINE_CERTIFICATE:
       return KEY_DEVICE;
     case PROFILE_ENTERPRISE_USER_CERTIFICATE:
+    case PROFILE_CONTENT_PROTECTION_CERTIFICATE:
       return KEY_USER;
   }
   NOTREACHED();
   return KEY_USER;
 }
 
-std::string GetKeyNameForProfile(
-    AttestationCertificateProfile profile) {
+std::string GetKeyNameForProfile(AttestationCertificateProfile profile,
+                                 const std::string& origin) {
   switch (profile) {
     case PROFILE_ENTERPRISE_MACHINE_CERTIFICATE:
       return kEnterpriseMachineKey;
     case PROFILE_ENTERPRISE_USER_CERTIFICATE:
       return kEnterpriseUserKey;
+    case PROFILE_CONTENT_PROTECTION_CERTIFICATE:
+      return std::string(kContentProtectionKeyPrefix) + origin;
   }
   NOTREACHED();
   return "";
 }
 
-int GetCertificateOptionsForProfile(
-    AttestationCertificateProfile profile) {
-  switch (profile) {
-    case PROFILE_ENTERPRISE_MACHINE_CERTIFICATE:
-      return CERTIFICATE_INCLUDE_STABLE_ID | CERTIFICATE_INCLUDE_DEVICE_STATE;
-    case PROFILE_ENTERPRISE_USER_CERTIFICATE:
-      return CERTIFICATE_INCLUDE_DEVICE_STATE;
-  }
-  NOTREACHED();
-  return CERTIFICATE_OPTION_NONE;
-}
-
 }  // namespace
 
 AttestationFlow::AttestationFlow(cryptohome::AsyncMethodCaller* async_caller,
@@ -105,6 +96,8 @@
 
 void AttestationFlow::GetCertificate(
     AttestationCertificateProfile certificate_profile,
+    const std::string& user_email,
+    const std::string& request_origin,
     bool force_new_key,
     const CertificateCallback& callback) {
   // If this device has not enrolled with the Privacy CA, we need to do that
@@ -113,6 +106,8 @@
       &AttestationFlow::StartCertificateRequest,
       weak_factory_.GetWeakPtr(),
       certificate_profile,
+      user_email,
+      request_origin,
       force_new_key,
       callback);
   base::Closure on_enroll_failure = base::Bind(callback, false, "");
@@ -196,14 +191,19 @@
 
 void AttestationFlow::StartCertificateRequest(
     AttestationCertificateProfile certificate_profile,
+    const std::string& user_email,
+    const std::string& request_origin,
     bool generate_new_key,
     const CertificateCallback& callback) {
   AttestationKeyType key_type = GetKeyTypeForProfile(certificate_profile);
-  std::string key_name = GetKeyNameForProfile(certificate_profile);
+  std::string key_name = GetKeyNameForProfile(certificate_profile,
+                                              request_origin);
   if (generate_new_key) {
     // Get the attestation service to create a Privacy CA certificate request.
     async_caller_->AsyncTpmAttestationCreateCertRequest(
-        GetCertificateOptionsForProfile(certificate_profile),
+        certificate_profile,
+        user_email,
+        request_origin,
         base::Bind(&AttestationFlow::SendCertificateRequestToPCA,
                    weak_factory_.GetWeakPtr(),
                    key_type,
@@ -223,6 +223,8 @@
         &AttestationFlow::StartCertificateRequest,
         weak_factory_.GetWeakPtr(),
         certificate_profile,
+        user_email,
+        request_origin,
         true,
         callback);
     cryptohome_client_->TpmAttestationDoesKeyExist(
diff --git a/chromeos/attestation/attestation_flow.h b/chromeos/attestation/attestation_flow.h
index 2c59f3b..bdbea1e 100644
--- a/chromeos/attestation/attestation_flow.h
+++ b/chromeos/attestation/attestation_flow.h
@@ -68,6 +68,12 @@
   // Parameters
   //   certificate_profile - Specifies what kind of certificate should be
   //                         requested from the CA.
+  //   user_email - The canonical email address of the currently active user.
+  //                This is ignored when not using the content protection
+  //                profile.
+  //   request_origin - For content protection profiles, certificate requests
+  //                    are origin-specific.  This string must uniquely identify
+  //                    the origin of the request.
   //   force_new_key - If set to true, a new key will be generated even if a key
   //                   already exists for the profile.  The new key will replace
   //                   the existing key on success.
@@ -75,6 +81,8 @@
   //              On success |result| will be true and |data| will contain the
   //              PCA-issued certificate chain in PEM format.
   virtual void GetCertificate(AttestationCertificateProfile certificate_profile,
+                              const std::string& user_email,
+                              const std::string& request_origin,
                               bool force_new_key,
                               const CertificateCallback& callback);
 
@@ -134,10 +142,14 @@
   // Parameters
   //   certificate_profile - Specifies what kind of certificate should be
   //                         requested from the CA.
+  //   user_email - The active user's canonical email.
+  //   request_origin - An identifier for the origin of this request.
   //   generate_new_key - If set to true a new key is generated.
   //   callback - Called when the operation completes.
   void StartCertificateRequest(
       const AttestationCertificateProfile certificate_profile,
+      const std::string& user_email,
+      const std::string& request_origin,
       bool generate_new_key,
       const CertificateCallback& callback);
 
diff --git a/chromeos/attestation/attestation_flow_unittest.cc b/chromeos/attestation/attestation_flow_unittest.cc
index ea819b0..9622230 100644
--- a/chromeos/attestation/attestation_flow_unittest.cc
+++ b/chromeos/attestation/attestation_flow_unittest.cc
@@ -99,7 +99,8 @@
 
   EXPECT_CALL(
       async_caller,
-      AsyncTpmAttestationCreateCertRequest(CERTIFICATE_INCLUDE_DEVICE_STATE, _))
+      AsyncTpmAttestationCreateCertRequest(PROFILE_ENTERPRISE_USER_CERTIFICATE,
+                                           "fake_email", "fake_origin", _))
           .Times(1)
           .InSequence(flow_order);
 
@@ -131,7 +132,8 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "fake_email",
+                      "fake_origin", true, mock_callback);
   Run();
 }
 
@@ -157,7 +159,8 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
+                      mock_callback);
   Run();
 }
 
@@ -186,7 +189,8 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
+                      mock_callback);
   Run();
 }
 
@@ -219,16 +223,17 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
+                      mock_callback);
   Run();
 }
 
 TEST_F(AttestationFlowTest, GetMachineCertificateAlreadyEnrolled) {
   StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
   async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
-  int options = CERTIFICATE_INCLUDE_DEVICE_STATE |
-                CERTIFICATE_INCLUDE_STABLE_ID;
-  EXPECT_CALL(async_caller, AsyncTpmAttestationCreateCertRequest(options, _))
+  EXPECT_CALL(async_caller,
+              AsyncTpmAttestationCreateCertRequest(
+                  PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, "", "", _))
       .Times(1);
   std::string fake_cert_response =
       cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest;
@@ -260,17 +265,17 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
-                      true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, "", "", true,
+                      mock_callback);
   Run();
 }
 
 TEST_F(AttestationFlowTest, GetCertificate_FailCreateCertRequest) {
   StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
   async_caller.SetUp(false, cryptohome::MOUNT_ERROR_NONE);
-  int options = CERTIFICATE_INCLUDE_DEVICE_STATE;
   EXPECT_CALL(async_caller,
-              AsyncTpmAttestationCreateCertRequest(options, _))
+              AsyncTpmAttestationCreateCertRequest(
+                  PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _))
       .Times(1);
 
   chromeos::MockCryptohomeClient client;
@@ -288,16 +293,17 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
+                      mock_callback);
   Run();
 }
 
 TEST_F(AttestationFlowTest, GetCertificate_CertRequestRejected) {
   StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
   async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
-  int options = CERTIFICATE_INCLUDE_DEVICE_STATE;
   EXPECT_CALL(async_caller,
-              AsyncTpmAttestationCreateCertRequest(options, _))
+              AsyncTpmAttestationCreateCertRequest(
+                  PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _))
       .Times(1);
 
   chromeos::MockCryptohomeClient client;
@@ -318,7 +324,8 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
+                      mock_callback);
   Run();
 }
 
@@ -341,15 +348,17 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, true, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", true,
+                      mock_callback);
   Run();
 }
 
 TEST_F(AttestationFlowTest, GetCertificate_CheckExisting) {
   StrictMock<cryptohome::MockAsyncMethodCaller> async_caller;
   async_caller.SetUp(true, cryptohome::MOUNT_ERROR_NONE);
-  int options = CERTIFICATE_INCLUDE_DEVICE_STATE;
-  EXPECT_CALL(async_caller, AsyncTpmAttestationCreateCertRequest(options, _))
+  EXPECT_CALL(async_caller,
+              AsyncTpmAttestationCreateCertRequest(
+                  PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", _))
       .Times(1);
   std::string fake_cert_response =
       cryptohome::MockAsyncMethodCaller::kFakeAttestationCertRequest;
@@ -384,8 +393,8 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE,
-                      false, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", false,
+                      mock_callback);
   Run();
 }
 
@@ -414,8 +423,8 @@
 
   scoped_ptr<ServerProxy> proxy_interface(proxy.release());
   AttestationFlow flow(&async_caller, &client, proxy_interface.Pass());
-  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE,
-                      false, mock_callback);
+  flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, "", "", false,
+                      mock_callback);
   Run();
 }
 
diff --git a/chromeos/attestation/mock_attestation_flow.h b/chromeos/attestation/mock_attestation_flow.h
index bda8a72..1950246 100644
--- a/chromeos/attestation/mock_attestation_flow.h
+++ b/chromeos/attestation/mock_attestation_flow.h
@@ -65,7 +65,9 @@
   MockAttestationFlow();
   virtual ~MockAttestationFlow();
 
-  MOCK_METHOD3(GetCertificate, void(AttestationCertificateProfile,
+  MOCK_METHOD5(GetCertificate, void(AttestationCertificateProfile,
+                                    const std::string&,
+                                    const std::string&,
                                     bool,
                                     const CertificateCallback&));
 };
diff --git a/chromeos/audio/audio_device.cc b/chromeos/audio/audio_device.cc
index 1448ec4..0ec9625 100644
--- a/chromeos/audio/audio_device.cc
+++ b/chromeos/audio/audio_device.cc
@@ -97,6 +97,7 @@
     display_name = node.name;
   else
     display_name = node.device_name;
+  device_name = node.device_name;
   priority = GetDevicePriority(type);
   active = node.active;
   plugged_time = node.plugged_time;
@@ -114,6 +115,9 @@
                       "display_name = %s ",
                       display_name.c_str());
   base::StringAppendF(&result,
+                      "device_name = %s ",
+                      device_name.c_str());
+  base::StringAppendF(&result,
                       "type = %s ",
                       GetTypeString(type).c_str());
   base::StringAppendF(&result,
diff --git a/chromeos/audio/audio_device.h b/chromeos/audio/audio_device.h
index 30712e2..5109ea2 100644
--- a/chromeos/audio/audio_device.h
+++ b/chromeos/audio/audio_device.h
@@ -31,6 +31,7 @@
   bool is_input;
   uint64 id;
   std::string display_name;
+  std::string device_name;
   AudioDeviceType type;
   uint8 priority;
   bool active;
diff --git a/chromeos/audio/cras_audio_handler.cc b/chromeos/audio/cras_audio_handler.cc
index ae206f9..3fa81cb 100644
--- a/chromeos/audio/cras_audio_handler.cc
+++ b/chromeos/audio/cras_audio_handler.cc
@@ -199,10 +199,10 @@
   FOR_EACH_OBSERVER(AudioObserver, observers_, OnOutputVolumeChanged());
 }
 
+// TODO: Rename the 'Percent' to something more meaningful.
 void CrasAudioHandler::SetInputGainPercent(int gain_percent) {
-  gain_percent = min(max(gain_percent, 0), 100);
-  if (gain_percent <= kMuteThresholdPercent)
-    gain_percent = 0;
+  // NOTE: We do not sanitize input gain values since the range is completely
+  // dependent on the device.
   input_gain_ = gain_percent;
 
   if (const AudioDevice* device = GetDeviceFromId(active_input_node_id_))
@@ -268,12 +268,14 @@
     return;
   }
 
-  value = min(max(value, 0), 100);
-  if (value <= kMuteThresholdPercent)
-    value = 0;
-
-  if (const AudioDevice* device = GetDeviceFromId(device_id))
+  if (const AudioDevice* device = GetDeviceFromId(device_id)) {
+    if (!device->is_input) {
+      value = min(max(value, 0), 100);
+      if (value <= kMuteThresholdPercent)
+        value = 0;
+    }
     audio_pref_handler_->SetVolumeGainValue(*device, value);
+  }
 }
 
 void CrasAudioHandler::SetMuteForDevice(uint64 device_id, bool mute_on) {
@@ -379,7 +381,8 @@
   input_mute_on_ = audio_pref_handler_->GetMuteValue(*device);
   input_gain_ = audio_pref_handler_->GetVolumeGainValue(*device);
   SetInputMuteInternal(input_mute_on_);
-  SetInputNodeGain(active_input_node_id_, input_gain_);
+  // TODO(rkc,jennyz): Set input gain once we decide on how to store
+  // the gain values since the range and step are both device specific.
 }
 
 void CrasAudioHandler::SetupAudioOutputState() {
@@ -391,6 +394,7 @@
   }
   output_mute_on_ = audio_pref_handler_->GetMuteValue(*device);
   output_volume_ = audio_pref_handler_->GetVolumeGainValue(*device);
+
   SetOutputMuteInternal(output_mute_on_);
   SetOutputNodeVolume(active_output_node_id_, output_volume_);
 }
@@ -466,13 +470,39 @@
       new_active_device.id == *current_active_node_id) {
     return false;
   }
-  if (GetDeviceFromId(*current_active_node_id))
-    audio_devices_[*current_active_node_id].active = false;
+
+  // Reset all other input or output devices' active status. The active audio
+  // device from the previous user session can be remembered by cras, but not
+  // in chrome. see crbug.com/273271.
+  for (AudioDeviceMap::iterator it = audio_devices_.begin();
+       it != audio_devices_.end(); ++it) {
+    if (it->second.is_input == new_active_device.is_input &&
+        it->second.id != new_active_device.id)
+      it->second.active = false;
+  }
+
+  // Set the current active input/output device to the new_active_device.
   *current_active_node_id = new_active_device.id;
   audio_devices_[*current_active_node_id].active = true;
   return true;
 }
 
+bool CrasAudioHandler::NonActiveDeviceUnplugged(
+    size_t old_devices_size,
+    size_t new_devices_size,
+    uint64 current_active_node) {
+  // There could be cases that more than one NodesChanged signals are
+  // triggered by cras for unplugging or plugging one audio devices, both coming
+  // with the same node data. After handling the first NodesChanged signal, the
+  // audio_devices_ can be overwritten by staled node data from handling 2nd
+  // NodesChanged signal. Therefore, we need to check if the device with
+  // current_active_node is consistently active or not.
+  // crbug.com/274641.
+  return (new_devices_size <= old_devices_size &&
+          GetDeviceFromId(current_active_node) &&
+          audio_devices_[current_active_node].active);
+}
+
 void CrasAudioHandler::SwitchToDevice(const AudioDevice& device) {
   if (device.is_input) {
     if (!ChangeActiveDevice(device, &active_input_node_id_))
@@ -489,6 +519,7 @@
 
 void CrasAudioHandler::UpdateDevicesAndSwitchActive(
     const AudioNodeList& nodes) {
+  size_t old_audio_devices_size = audio_devices_.size();
   audio_devices_.clear();
   has_alternative_input_ = false;
   has_alternative_output_ = false;
@@ -518,11 +549,20 @@
       output_devices_pq_.push(device);
   }
 
-  if (!input_devices_pq_.empty())
+  // If audio nodes change is caused by unplugging some non-active audio
+  // devices, the previously set active audio device will stay active.
+  // Otherwise, switch to a new active audio device according to their priority.
+  if (!NonActiveDeviceUnplugged(old_audio_devices_size,
+                                audio_devices_.size(),
+                                active_input_node_id_) &&
+      !input_devices_pq_.empty())
     SwitchToDevice(input_devices_pq_.top());
-
-  if (!output_devices_pq_.empty())
+  if (!NonActiveDeviceUnplugged(old_audio_devices_size,
+                                audio_devices_.size(),
+                                active_output_node_id_) &&
+      !output_devices_pq_.empty()) {
     SwitchToDevice(output_devices_pq_.top());
+  }
 }
 
 void CrasAudioHandler::HandleGetNodes(const chromeos::AudioNodeList& node_list,
diff --git a/chromeos/audio/cras_audio_handler.h b/chromeos/audio/cras_audio_handler.h
index 5df456e..b95f123 100644
--- a/chromeos/audio/cras_audio_handler.h
+++ b/chromeos/audio/cras_audio_handler.h
@@ -224,6 +224,12 @@
   bool ChangeActiveDevice(const AudioDevice& new_active_device,
                           uint64* current_active_node_id);
 
+  // Returns true if the audio nodes change is caused by some non-active
+  // audio nodes unplugged.
+  bool NonActiveDeviceUnplugged(size_t old_devices_size,
+                                size_t new_device_size,
+                                uint64 current_active_node);
+
   // Handles dbus callback for GetNodes.
   void HandleGetNodes(const chromeos::AudioNodeList& node_list, bool success);
 
diff --git a/chromeos/audio/cras_audio_handler_unittest.cc b/chromeos/audio/cras_audio_handler_unittest.cc
index 1fe67e9..48a1200 100644
--- a/chromeos/audio/cras_audio_handler_unittest.cc
+++ b/chromeos/audio/cras_audio_handler_unittest.cc
@@ -814,6 +814,127 @@
   EXPECT_TRUE(cras_audio_handler_->has_alternative_output());
 }
 
+TEST_F(CrasAudioHandlerTest, UnplugUSBHeadphonesWithActiveSpeaker) {
+  // Initialize with internal speaker and one usb headphone.
+  AudioNodeList audio_nodes;
+  audio_nodes.push_back(kInternalSpeaker);
+  audio_nodes.push_back(kUSBHeadphone1);
+  SetUpCrasAudioHandler(audio_nodes);
+  const size_t init_nodes_size = audio_nodes.size();
+
+  // Verify the audio devices size.
+  AudioDeviceList audio_devices;
+  cras_audio_handler_->GetAudioDevices(&audio_devices);
+  EXPECT_EQ(init_nodes_size, audio_devices.size());
+  EXPECT_EQ(0, test_observer_->audio_nodes_changed_count());
+
+  // Verify the usb headphone is selected as the active output initially.
+  EXPECT_EQ(0, test_observer_->active_output_node_changed_count());
+  AudioDevice active_output;
+  EXPECT_TRUE(cras_audio_handler_->GetActiveOutputDevice(&active_output));
+  EXPECT_EQ(kUSBHeadphone1.id, active_output.id);
+  EXPECT_EQ(kUSBHeadphone1.id, cras_audio_handler_->GetActiveOutputNode());
+  EXPECT_TRUE(cras_audio_handler_->has_alternative_output());
+
+  // Plug in the headphone jack.
+  audio_nodes.clear();
+  audio_nodes.push_back(kInternalSpeaker);
+  AudioNode usb_headphone_1(kUSBHeadphone1);
+  usb_headphone_1.active = true;
+  usb_headphone_1.plugged_time = 80000000;
+  audio_nodes.push_back(usb_headphone_1);
+  AudioNode headphone_jack(kHeadphone);
+  headphone_jack.plugged_time = 90000000;
+  audio_nodes.push_back(headphone_jack);
+  ChangeAudioNodes(audio_nodes);
+
+  // Verify the AudioNodesChanged event is fired and new audio device is added.
+  EXPECT_EQ(1, test_observer_->audio_nodes_changed_count());
+  cras_audio_handler_->GetAudioDevices(&audio_devices);
+  EXPECT_EQ(init_nodes_size + 1, audio_devices.size());
+
+  // Verify the active output device is switched to the headphone jack, which
+  // is plugged later, and ActiveOutputChanged event is fired.
+  EXPECT_EQ(1, test_observer_->active_output_node_changed_count());
+  EXPECT_TRUE(cras_audio_handler_->GetActiveOutputDevice(&active_output));
+  EXPECT_EQ(kHeadphone.id, active_output.id);
+  EXPECT_EQ(kHeadphone.id, cras_audio_handler_->GetActiveOutputNode());
+  EXPECT_TRUE(cras_audio_handler_->has_alternative_output());
+
+  // Select the speaker to be the active output device.
+  AudioDevice internal_speaker(kInternalSpeaker);
+  cras_audio_handler_->SwitchToDevice(internal_speaker);
+
+  // Verify the active output is switched to internal speaker, and the
+  // ActiveOutputNodeChanged event is fired.
+  EXPECT_EQ(2, test_observer_->active_output_node_changed_count());
+  EXPECT_TRUE(cras_audio_handler_->GetActiveOutputDevice(&active_output));
+  EXPECT_EQ(kInternalSpeaker.id, active_output.id);
+  EXPECT_EQ(kInternalSpeaker.id, cras_audio_handler_->GetActiveOutputNode());
+
+  // Unplug the usb headphone.
+  audio_nodes.clear();
+  AudioNode internal_speaker_node(kInternalSpeaker);
+  internal_speaker_node.active = true;
+  internal_speaker_node.plugged_time = 70000000;
+  audio_nodes.push_back(internal_speaker_node);
+  headphone_jack.active = false;
+  audio_nodes.push_back(headphone_jack);
+  ChangeAudioNodes(audio_nodes);
+
+  // Verify the AudioNodesChanged event is fired and one audio device is
+  // removed.
+  EXPECT_EQ(2, test_observer_->audio_nodes_changed_count());
+  cras_audio_handler_->GetAudioDevices(&audio_devices);
+  EXPECT_EQ(init_nodes_size, audio_devices.size());
+
+  // Verify the active output device remains to be speaker.
+  EXPECT_EQ(2, test_observer_->active_output_node_changed_count());
+  EXPECT_TRUE(cras_audio_handler_->GetActiveOutputDevice(&active_output));
+  EXPECT_EQ(kInternalSpeaker.id, active_output.id);
+  EXPECT_EQ(kInternalSpeaker.id, cras_audio_handler_->GetActiveOutputNode());
+  EXPECT_TRUE(cras_audio_handler_->has_alternative_output());
+}
+
+TEST_F(CrasAudioHandlerTest, OneActiveAudioOutputAfterLoginNewUserSession) {
+  // This tests the case found with crbug.com/273271.
+  // Initialize with internal speaker, bluetooth headphone and headphone jack
+  // for a new chrome session after user signs out from the previous session.
+  // Headphone jack is plugged in later than bluetooth headphone, but bluetooth
+  // headphone is selected as the active output by user from previous user
+  // session.
+  AudioNodeList audio_nodes;
+  audio_nodes.push_back(kInternalSpeaker);
+  AudioNode bluetooth_headphone(kBluetoothHeadset);
+  bluetooth_headphone.active = true;
+  bluetooth_headphone.plugged_time = 70000000;
+  audio_nodes.push_back(bluetooth_headphone);
+  AudioNode headphone_jack(kHeadphone);
+  headphone_jack.plugged_time = 80000000;
+  audio_nodes.push_back(headphone_jack);
+  SetUpCrasAudioHandler(audio_nodes);
+  const size_t init_nodes_size = audio_nodes.size();
+
+  // Verify the audio devices size.
+  AudioDeviceList audio_devices;
+  cras_audio_handler_->GetAudioDevices(&audio_devices);
+  EXPECT_EQ(init_nodes_size, audio_devices.size());
+  EXPECT_EQ(0, test_observer_->audio_nodes_changed_count());
+
+  // Verify the headphone jack is selected as the active output and all other
+  // audio devices are not active.
+  EXPECT_EQ(0, test_observer_->active_output_node_changed_count());
+  AudioDevice active_output;
+  EXPECT_TRUE(cras_audio_handler_->GetActiveOutputDevice(&active_output));
+  EXPECT_EQ(kHeadphone.id, active_output.id);
+  EXPECT_EQ(kHeadphone.id, cras_audio_handler_->GetActiveOutputNode());
+  EXPECT_TRUE(cras_audio_handler_->has_alternative_output());
+  for (size_t i = 0; i < audio_devices.size(); ++i) {
+    if (audio_devices[i].id != kHeadphone.id)
+      EXPECT_FALSE(audio_devices[i].active);
+  }
+}
+
 TEST_F(CrasAudioHandlerTest, PlugUSBMic) {
   // Set up initial audio devices, only with internal mic.
   AudioNodeList audio_nodes;
diff --git a/chromeos/cert_loader.cc b/chromeos/cert_loader.cc
index 964c777..060d464 100644
--- a/chromeos/cert_loader.cc
+++ b/chromeos/cert_loader.cc
@@ -52,7 +52,8 @@
   VLOG(1) << "CallOpenPersistentNSSDB";
 
   // Ensure we've opened the user's key/certificate database.
-  crypto::OpenPersistentNSSDB();
+  if (base::chromeos::IsRunningOnChromeOS())
+    crypto::OpenPersistentNSSDB();
   crypto::EnableTPMTokenForNSS();
 }
 
@@ -64,7 +65,6 @@
 void CertLoader::Initialize() {
   CHECK(!g_cert_loader);
   g_cert_loader = new CertLoader();
-  g_cert_loader->Init();
 }
 
 // static
@@ -86,7 +86,8 @@
 }
 
 CertLoader::CertLoader()
-    : certificates_requested_(false),
+    : initialize_tpm_for_test_(false),
+      certificates_requested_(false),
       certificates_loaded_(false),
       certificates_update_required_(false),
       certificates_update_running_(false),
@@ -95,14 +96,14 @@
           base::TimeDelta::FromMilliseconds(kInitialRequestDelayMs)),
       initialize_token_factory_(this),
       update_certificates_factory_(this) {
-}
-
-void CertLoader::Init() {
-  net::CertDatabase::GetInstance()->AddObserver(this);
   if (LoginState::IsInitialized())
     LoginState::Get()->AddObserver(this);
 }
 
+void CertLoader::InitializeTPMForTest() {
+  initialize_tpm_for_test_ = true;
+}
+
 void CertLoader::SetCryptoTaskRunner(
     const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) {
   crypto_task_runner_ = crypto_task_runner;
@@ -154,7 +155,11 @@
 
   // Ensure we only initialize the TPM token once.
   DCHECK_EQ(tpm_token_state_, TPM_STATE_UNKNOWN);
-  if (!base::chromeos::IsRunningOnChromeOS())
+  if (!initialize_tpm_for_test_ && !base::chromeos::IsRunningOnChromeOS())
+    tpm_token_state_ = TPM_DISABLED;
+
+  // Treat TPM as disabled for guest users since they do not store certs.
+  if (LoginState::IsInitialized() && LoginState::Get()->IsGuestUser())
     tpm_token_state_ = TPM_DISABLED;
 
   InitializeTokenAndLoadCertificates();
@@ -164,10 +169,6 @@
   CHECK(thread_checker_.CalledOnValidThread());
   VLOG(1) << "InitializeTokenAndLoadCertificates: " << tpm_token_state_;
 
-  // Treat TPM as disabled for guest users since they do not store certs.
-  if (LoginState::IsInitialized() && LoginState::Get()->IsGuestUser())
-    tpm_token_state_ = TPM_DISABLED;
-
   switch (tpm_token_state_) {
     case TPM_STATE_UNKNOWN: {
       crypto_task_runner_->PostTaskAndReply(
@@ -211,8 +212,6 @@
           base::Bind(&CertLoader::OnTPMTokenInitialized,
                      initialize_token_factory_.GetWeakPtr()));
       return;
-      tpm_token_state_ = TPM_TOKEN_INITIALIZED;
-      // FALL_THROUGH_INTENDED
     }
     case TPM_TOKEN_INITIALIZED: {
       StartLoadCertificates();
@@ -223,7 +222,7 @@
 
 void CertLoader::RetryTokenInitializationLater() {
   CHECK(thread_checker_.CalledOnValidThread());
-  LOG(WARNING) << "Re-Requesting Certificates later.";
+  LOG(WARNING) << "Retry token initialization later.";
   base::MessageLoop::current()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&CertLoader::InitializeTokenAndLoadCertificates,
@@ -324,8 +323,14 @@
 }
 
 void CertLoader::StartLoadCertificates() {
+  DCHECK(!certificates_loaded_ && !certificates_update_running_);
+  net::CertDatabase::GetInstance()->AddObserver(this);
+  LoadCertificates();
+}
+
+void CertLoader::LoadCertificates() {
   CHECK(thread_checker_.CalledOnValidThread());
-  VLOG(1) << "StartLoadCertificates: " << certificates_update_running_;
+  VLOG(1) << "LoadCertificates: " << certificates_update_running_;
 
   if (certificates_update_running_) {
     certificates_update_required_ = true;
@@ -361,7 +366,7 @@
 
   certificates_update_running_ = false;
   if (certificates_update_required_)
-    StartLoadCertificates();
+    LoadCertificates();
 }
 
 void CertLoader::NotifyCertificatesLoaded(bool initial_load) {
@@ -374,12 +379,12 @@
 
 void CertLoader::OnCertAdded(const net::X509Certificate* cert) {
   VLOG(1) << "OnCertAdded";
-  StartLoadCertificates();
+  LoadCertificates();
 }
 
 void CertLoader::OnCertRemoved(const net::X509Certificate* cert) {
   VLOG(1) << "OnCertRemoved";
-  StartLoadCertificates();
+  LoadCertificates();
 }
 
 void CertLoader::LoggedInStateChanged(LoginState::LoggedInState state) {
diff --git a/chromeos/cert_loader.h b/chromeos/cert_loader.h
index 75d2cd0..bc1123e 100644
--- a/chromeos/cert_loader.h
+++ b/chromeos/cert_loader.h
@@ -69,10 +69,15 @@
 
   static std::string GetPkcs11IdForCert(const net::X509Certificate& cert);
 
+  // By default, CertLoader tries to load the TPMToken only if running in a
+  // ChromeOS environment. Tests can call this function after Initialize() and
+  // before SetCryptoTaskRunner() to enable the TPM initialization.
+  void InitializeTPMForTest();
+
   // |crypto_task_runner| is the task runner that any synchronous crypto calls
   // should be made from, e.g. in Chrome this is the IO thread. Must be called
-  // after the thread is started. Certificate loading will not happen unless
-  // this is set.
+  // after the thread is started. Starts TPM initialization and Certificate
+  // loading.
   void SetCryptoTaskRunner(
       const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner);
 
@@ -105,7 +110,6 @@
   CertLoader();
   virtual ~CertLoader();
 
-  void Init();
   void MaybeRequestCertificates();
 
   // This is the cyclic chain of callbacks to initialize the TPM token and to
@@ -124,7 +128,15 @@
 
   // These calls handle the updating of the certificate list after the TPM token
   // was initialized.
+
+  // Start certificate loading. Must be called at most once.
   void StartLoadCertificates();
+
+  // Trigger a certificate load. If a certificate loading task is already in
+  // progress, will start a reload once the current task finised.
+  void LoadCertificates();
+
+  // Called if a certificate load task is finished.
   void UpdateCertificates(net::CertificateList* cert_list);
 
   void NotifyCertificatesLoaded(bool initial_load);
@@ -137,6 +149,8 @@
   // LoginState::Observer
   virtual void LoggedInStateChanged(LoginState::LoggedInState state) OVERRIDE;
 
+  bool initialize_tpm_for_test_;
+
   ObserverList<Observer> observers_;
 
   bool certificates_requested_;
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index 57fd83b..dae10d7 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -141,8 +141,6 @@
         'dbus/ibus/ibus_client.h',
         'dbus/ibus/ibus_component.cc',
         'dbus/ibus/ibus_component.h',
-        'dbus/ibus/ibus_config_client.cc',
-        'dbus/ibus/ibus_config_client.h',
         'dbus/ibus/ibus_constants.h',
         'dbus/ibus/ibus_engine_service.cc',
         'dbus/ibus/ibus_engine_service.h',
@@ -217,6 +215,8 @@
         'login/login_state.h',
         'network/certificate_pattern.cc',
         'network/certificate_pattern.h',
+        'network/client_cert_resolver.cc',
+        'network/client_cert_resolver.h',
         'network/client_cert_util.cc',
         'network/client_cert_util.h',
         'network/cros_network_functions.cc',
@@ -229,6 +229,8 @@
         'network/geolocation_handler.h',
         'network/managed_network_configuration_handler.cc',
         'network/managed_network_configuration_handler.h',
+        'network/managed_network_configuration_handler_impl.cc',
+        'network/managed_network_configuration_handler_impl.h',
         'network/managed_state.cc',
         'network/managed_state.h',
         'network/network_cert_migrator.cc',
@@ -294,6 +296,8 @@
         'network/shill_property_handler.h',
         'network/sms_watcher.cc',
         'network/sms_watcher.h',
+        'network/dhcp_proxy_script_fetcher_chromeos.cc',
+        'network/dhcp_proxy_script_fetcher_chromeos.h',
         'process_proxy/process_output_watcher.cc',
         'process_proxy/process_output_watcher.h',
         'process_proxy/process_proxy.cc',
@@ -377,6 +381,8 @@
         'disks/mock_disk_mount_manager.h',
         'ime/mock_component_extension_ime_manager_delegate.cc',
         'ime/mock_component_extension_ime_manager_delegate.h',
+        'network/mock_managed_network_configuration_handler.cc',
+        'network/mock_managed_network_configuration_handler.h',
         'network/onc/mock_certificate_importer.cc',
         'network/onc/mock_certificate_importer.h',
         'network/onc/onc_test_utils.cc',
@@ -420,8 +426,6 @@
         'dbus/mock_dbus_thread_manager_without_gmock.h',
         'dbus/ibus/mock_ibus_client.cc',
         'dbus/ibus/mock_ibus_client.h',
-        'dbus/ibus/mock_ibus_config_client.cc',
-        'dbus/ibus/mock_ibus_config_client.h',
         'dbus/ibus/mock_ibus_input_context_client.cc',
         'dbus/ibus/mock_ibus_input_context_client.h',
         'dbus/ibus/mock_ibus_engine_factory_service.cc',
@@ -468,7 +472,6 @@
         'dbus/gsm_sms_client_unittest.cc',
         'dbus/ibus/ibus_client_unittest.cc',
         'dbus/ibus/ibus_component_unittest.cc',
-        'dbus/ibus/ibus_config_client_unittest.cc',
         'dbus/ibus/ibus_engine_factory_service_unittest.cc',
         'dbus/ibus/ibus_engine_service_unittest.cc',
         'dbus/ibus/ibus_input_context_client_unittest.cc',
@@ -497,6 +500,7 @@
         'ime/input_method_whitelist_unittest.cc',
         'ime/xkeyboard_unittest.cc',
         'login/login_state_unittest.cc',
+        'network/client_cert_resolver_unittest.cc',
         'network/cros_network_functions_unittest.cc',
         'network/geolocation_handler_unittest.cc',
         'network/managed_network_configuration_handler_unittest.cc',
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 63945db..c4bec2a 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -195,5 +195,8 @@
 const char kUseNewNetworkConfigurationHandlers[] =
     "use-new-network-configuration-handlers";
 
+// Disables user image sync.
+const char kDisableUserImageSync[] = "disable-user-image-sync";
+
 }  // namespace switches
 }  // namespace chromeos
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 4d4b57f..1e99663 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -72,6 +72,7 @@
 CHROMEOS_EXPORT extern const char kSmsTestMessages[];
 CHROMEOS_EXPORT extern const char kStubCrosSettings[];
 CHROMEOS_EXPORT extern const char kUseNewNetworkConfigurationHandlers[];
+CHROMEOS_EXPORT extern const char kDisableUserImageSync[];
 
 }  // namespace switches
 }  // namespace chromeos
diff --git a/chromeos/cryptohome/async_method_caller.cc b/chromeos/cryptohome/async_method_caller.cc
index 92392d9..c9af98a 100644
--- a/chromeos/cryptohome/async_method_caller.cc
+++ b/chromeos/cryptohome/async_method_caller.cc
@@ -133,11 +133,15 @@
   }
 
   virtual void AsyncTpmAttestationCreateCertRequest(
-      int options,
+      chromeos::attestation::AttestationCertificateProfile certificate_profile,
+      const std::string& username,
+      const std::string& request_origin,
       const DataCallback& callback) OVERRIDE {
     DBusThreadManager::Get()->GetCryptohomeClient()->
         AsyncTpmAttestationCreateCertRequest(
-            options,
+            certificate_profile,
+            username,
+            request_origin,
             base::Bind(&AsyncMethodCallerImpl::RegisterAsyncDataCallback,
                        weak_ptr_factory_.GetWeakPtr(),
                        callback,
diff --git a/chromeos/cryptohome/async_method_caller.h b/chromeos/cryptohome/async_method_caller.h
index 7414284..e5ca604 100644
--- a/chromeos/cryptohome/async_method_caller.h
+++ b/chromeos/cryptohome/async_method_caller.h
@@ -9,6 +9,7 @@
 
 #include "base/basictypes.h"
 #include "base/callback_forward.h"
+#include "chromeos/attestation/attestation_constants.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/cryptohome_client.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
@@ -113,11 +114,15 @@
                                          const Callback& callback) = 0;
 
   // Asks cryptohomed to asynchronously create an attestation certificate
-  // request according to |options|, which is a combination of
-  // attestation::AttestationCertificateOptions.  On success the data sent to
-  // |callback| is a request to be sent to the Privacy CA.
+  // request according to |certificate_profile|.  Some profiles require that the
+  // |user_email| of the currently active user and an identifier of the
+  // |request_origin| be provided.  On success the data sent to |callback| is a
+  // request to be sent to the Privacy CA.  The |request_origin| may be sent to
+  // the Privacy CA but the |user_email| will never be sent.
   virtual void AsyncTpmAttestationCreateCertRequest(
-      int options,
+      chromeos::attestation::AttestationCertificateProfile certificate_profile,
+      const std::string& user_email,
+      const std::string& request_origin,
       const DataCallback& callback) = 0;
 
   // Asks cryptohomed to asynchronously finish an attestation certificate
diff --git a/chromeos/cryptohome/mock_async_method_caller.cc b/chromeos/cryptohome/mock_async_method_caller.cc
index 9bd8193..dcd59a0 100644
--- a/chromeos/cryptohome/mock_async_method_caller.cc
+++ b/chromeos/cryptohome/mock_async_method_caller.cc
@@ -51,9 +51,9 @@
   ON_CALL(*this, AsyncTpmAttestationEnroll(_, _))
       .WillByDefault(
           WithArgs<1>(Invoke(this, &MockAsyncMethodCaller::DoCallback)));
-  ON_CALL(*this, AsyncTpmAttestationCreateCertRequest(_, _))
+  ON_CALL(*this, AsyncTpmAttestationCreateCertRequest(_, _, _, _))
       .WillByDefault(
-          WithArgs<1>(Invoke(this,
+          WithArgs<3>(Invoke(this,
                              &MockAsyncMethodCaller::FakeCreateCertRequest)));
   ON_CALL(*this, AsyncTpmAttestationFinishCertRequest(_, _, _, _))
       .WillByDefault(
diff --git a/chromeos/cryptohome/mock_async_method_caller.h b/chromeos/cryptohome/mock_async_method_caller.h
index 74567ca..8f3796b 100644
--- a/chromeos/cryptohome/mock_async_method_caller.h
+++ b/chromeos/cryptohome/mock_async_method_caller.h
@@ -52,9 +52,12 @@
                void(const DataCallback& callback));
   MOCK_METHOD2(AsyncTpmAttestationEnroll,
                void(const std::string& pca_response, const Callback& callback));
-  MOCK_METHOD2(AsyncTpmAttestationCreateCertRequest,
-               void(int options,
-                    const DataCallback& callback));
+  MOCK_METHOD4(
+      AsyncTpmAttestationCreateCertRequest,
+      void(chromeos::attestation::AttestationCertificateProfile profile,
+           const std::string& user_email,
+           const std::string& request_origin,
+           const DataCallback& callback));
   MOCK_METHOD4(AsyncTpmAttestationFinishCertRequest,
                void(const std::string& pca_response,
                     chromeos::attestation::AttestationKeyType key_type,
diff --git a/chromeos/dbus/cras_audio_client_stub_impl.cc b/chromeos/dbus/cras_audio_client_stub_impl.cc
index b5b61c2..4efa107 100644
--- a/chromeos/dbus/cras_audio_client_stub_impl.cc
+++ b/chromeos/dbus/cras_audio_client_stub_impl.cc
@@ -34,7 +34,7 @@
   node_3.id = 10003;
   node_3.device_name = "Fake Bluetooth Headphone";
   node_3.type = "BLUETOOTH";
-  node_3.name = "Bluetooth Headphone";
+  node_3.name = "Headphone";
   node_3.active = false;
   node_list_.push_back(node_3);
 
@@ -53,7 +53,7 @@
   node_5.id = 10005;
   node_5.device_name = "Fake USB Mic";
   node_5.type = "USB";
-  node_5.name = "USB Mic";
+  node_5.name = "Mic";
   node_5.active = true;
   node_list_.push_back(node_5);
 
diff --git a/chromeos/dbus/cryptohome_client.cc b/chromeos/dbus/cryptohome_client.cc
index 445ba0b..965ef92 100644
--- a/chromeos/dbus/cryptohome_client.cc
+++ b/chromeos/dbus/cryptohome_client.cc
@@ -466,18 +466,17 @@
 
   // CryptohomeClient override.
   virtual void AsyncTpmAttestationCreateCertRequest(
-      int options,
+      attestation::AttestationCertificateProfile certificate_profile,
+      const std::string& user_email,
+      const std::string& request_origin,
       const AsyncMethodCallback& callback) OVERRIDE {
     dbus::MethodCall method_call(
         cryptohome::kCryptohomeInterface,
-        cryptohome::kCryptohomeAsyncTpmAttestationCreateCertRequest);
+        cryptohome::kCryptohomeAsyncTpmAttestationCreateCertRequestByProfile);
     dbus::MessageWriter writer(&method_call);
-    bool include_stable_id =
-        (options & attestation::CERTIFICATE_INCLUDE_STABLE_ID);
-    writer.AppendBool(include_stable_id);
-    bool include_device_state =
-        (options & attestation::CERTIFICATE_INCLUDE_DEVICE_STATE);
-    writer.AppendBool(include_device_state);
+    writer.AppendInt32(certificate_profile);
+    writer.AppendString(user_email);
+    writer.AppendString(request_origin);
     proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
                        base::Bind(&CryptohomeClientImpl::OnAsyncMethodCall,
                                   weak_ptr_factory_.GetWeakPtr(),
diff --git a/chromeos/dbus/cryptohome_client.h b/chromeos/dbus/cryptohome_client.h
index 0bfc978..38d4880 100644
--- a/chromeos/dbus/cryptohome_client.h
+++ b/chromeos/dbus/cryptohome_client.h
@@ -250,14 +250,18 @@
       const AsyncMethodCallback& callback) = 0;
 
   // Asynchronously creates an attestation certificate request according to
-  // |options|, which is a combination of AttestationCertificateOptions.
-  // |callback| will be called when the dbus call completes.  When the operation
-  // completes, the AsyncCallStatusWithDataHandler signal handler is called.
-  // The data that is sent with the signal is a certificate request to be sent
-  // to the Privacy CA.  The certificate request is completed by calling
-  // AsyncTpmAttestationFinishCertRequest.
+  // |certificate_profile|.  Some profiles require that the |user_email| of the
+  // currently active user and an identifier of the |request_origin| be
+  // provided.  |callback| will be called when the dbus call completes.  When
+  // the operation completes, the AsyncCallStatusWithDataHandler signal handler
+  // is called.  The data that is sent with the signal is a certificate request
+  // to be sent to the Privacy CA.  The certificate request is completed by
+  // calling AsyncTpmAttestationFinishCertRequest.  The |user_email| will not
+  // be included in the certificate request for the Privacy CA.
   virtual void AsyncTpmAttestationCreateCertRequest(
-      int options,
+      attestation::AttestationCertificateProfile certificate_profile,
+      const std::string& user_email,
+      const std::string& request_origin,
       const AsyncMethodCallback& callback) = 0;
 
   // Asynchronously finishes a certificate request operation.  The callback will
diff --git a/chromeos/dbus/cryptohome_client_stub.cc b/chromeos/dbus/cryptohome_client_stub.cc
index 96728a9..9942538 100644
--- a/chromeos/dbus/cryptohome_client_stub.cc
+++ b/chromeos/dbus/cryptohome_client_stub.cc
@@ -263,7 +263,9 @@
 }
 
 void CryptohomeClientStubImpl::AsyncTpmAttestationCreateCertRequest(
-    int options,
+    attestation::AttestationCertificateProfile certificate_profile,
+    const std::string& user_email,
+    const std::string& request_origin,
     const AsyncMethodCallback& callback) {
   ReturnAsyncMethodResult(callback, true);
 }
diff --git a/chromeos/dbus/cryptohome_client_stub.h b/chromeos/dbus/cryptohome_client_stub.h
index e38925a..8192600 100644
--- a/chromeos/dbus/cryptohome_client_stub.h
+++ b/chromeos/dbus/cryptohome_client_stub.h
@@ -90,7 +90,9 @@
       const std::string& pca_response,
       const AsyncMethodCallback& callback) OVERRIDE;
   virtual void AsyncTpmAttestationCreateCertRequest(
-      int options,
+      attestation::AttestationCertificateProfile certificate_profile,
+      const std::string& user_email,
+      const std::string& request_origin,
       const AsyncMethodCallback& callback) OVERRIDE;
   virtual void AsyncTpmAttestationFinishCertRequest(
       const std::string& pca_response,
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 0c28074..70ed816 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -30,7 +30,6 @@
 #include "chromeos/dbus/shill_service_client.h"
 #include "chromeos/dbus/system_clock_client.h"
 #include "chromeos/dbus/ibus/ibus_client.h"
-#include "chromeos/dbus/ibus/ibus_config_client.h"
 #include "chromeos/dbus/ibus/ibus_engine_factory_service.h"
 #include "chromeos/dbus/ibus/ibus_engine_service.h"
 #include "chromeos/dbus/ibus/ibus_input_context_client.h"
@@ -201,14 +200,10 @@
     ibus_address_ = ibus_address;
     VLOG(1) << "Connected to ibus-daemon: " << ibus_address;
 
-    DBusClientImplementationType client_type =
-        base::chromeos::IsRunningOnChromeOS() ? REAL_DBUS_CLIENT_IMPLEMENTATION
-                                              : STUB_DBUS_CLIENT_IMPLEMENTATION;
+    DBusClientImplementationType client_type = STUB_DBUS_CLIENT_IMPLEMENTATION;
 
     ibus_client_.reset(
         IBusClient::Create(client_type, ibus_bus_.get()));
-    ibus_config_client_.reset(
-        IBusConfigClient::Create(client_type, ibus_bus_.get()));
     ibus_input_context_client_.reset(
         IBusInputContextClient::Create(client_type));
     ibus_engine_factory_service_.reset(
@@ -336,10 +331,6 @@
     return ibus_client_.get();
   }
 
-  virtual IBusConfigClient* GetIBusConfigClient() OVERRIDE {
-    return ibus_config_client_.get();
-  }
-
   virtual IBusInputContextClient* GetIBusInputContextClient() OVERRIDE {
     return ibus_input_context_client_.get();
   }
@@ -350,14 +341,11 @@
 
   virtual IBusEngineService* GetIBusEngineService(
       const dbus::ObjectPath& object_path) OVERRIDE {
-    const DBusClientImplementationType client_type =
-        base::chromeos::IsRunningOnChromeOS() ? REAL_DBUS_CLIENT_IMPLEMENTATION
-                                              : STUB_DBUS_CLIENT_IMPLEMENTATION;
-
     if (ibus_engine_services_.find(object_path)
             == ibus_engine_services_.end()) {
       ibus_engine_services_[object_path] =
-          IBusEngineService::Create(client_type, ibus_bus_.get(), object_path);
+          IBusEngineService::Create(STUB_DBUS_CLIENT_IMPLEMENTATION,
+                                    ibus_bus_.get(), object_path);
     }
     return ibus_engine_services_[object_path];
   }
@@ -412,7 +400,6 @@
   scoped_ptr<SMSClient> sms_client_;
   scoped_ptr<UpdateEngineClient> update_engine_client_;
   scoped_ptr<IBusClient> ibus_client_;
-  scoped_ptr<IBusConfigClient> ibus_config_client_;
   scoped_ptr<IBusInputContextClient> ibus_input_context_client_;
   scoped_ptr<IBusEngineFactoryService> ibus_engine_factory_service_;
   std::map<dbus::ObjectPath, IBusEngineService*> ibus_engine_services_;
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index 07894ef..6d918af 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -37,7 +37,6 @@
 class DebugDaemonClient;
 class GsmSMSClient;
 class IBusClient;
-class IBusConfigClient;
 class IBusEngineFactoryService;
 class IBusEngineService;
 class IBusInputContextClient;
@@ -131,7 +130,6 @@
   virtual DebugDaemonClient* GetDebugDaemonClient() = 0;
   virtual GsmSMSClient* GetGsmSMSClient() = 0;
   virtual IBusClient* GetIBusClient() = 0;
-  virtual IBusConfigClient* GetIBusConfigClient() = 0;
   virtual IBusEngineFactoryService* GetIBusEngineFactoryService() = 0;
   virtual IBusEngineService* GetIBusEngineService(
       const dbus::ObjectPath& object_path) = 0;
diff --git a/chromeos/dbus/debug_daemon_client.cc b/chromeos/dbus/debug_daemon_client.cc
index 3efbe7d..cfb36c2 100644
--- a/chromeos/dbus/debug_daemon_client.cc
+++ b/chromeos/dbus/debug_daemon_client.cc
@@ -257,7 +257,7 @@
   virtual void GetPerfData(uint32_t duration,
                            const GetPerfDataCallback& callback) OVERRIDE {
     dbus::MethodCall method_call(debugd::kDebugdInterface,
-                                 debugd::kGetPerfData);
+                                 debugd::kGetRichPerfData);
     dbus::MessageWriter writer(&method_call);
     writer.AppendUint32(duration);
 
diff --git a/chromeos/dbus/fake_cryptohome_client.cc b/chromeos/dbus/fake_cryptohome_client.cc
index d13c0f7..c5df786 100644
--- a/chromeos/dbus/fake_cryptohome_client.cc
+++ b/chromeos/dbus/fake_cryptohome_client.cc
@@ -295,7 +295,9 @@
 }
 
 void FakeCryptohomeClient::AsyncTpmAttestationCreateCertRequest(
-    int options,
+    attestation::AttestationCertificateProfile certificate_profile,
+    const std::string& user_email,
+    const std::string& request_origin,
     const AsyncMethodCallback& callback) {
 }
 
diff --git a/chromeos/dbus/fake_cryptohome_client.h b/chromeos/dbus/fake_cryptohome_client.h
index a4e5bfb..e254648 100644
--- a/chromeos/dbus/fake_cryptohome_client.h
+++ b/chromeos/dbus/fake_cryptohome_client.h
@@ -91,7 +91,9 @@
       const std::string& pca_response,
       const AsyncMethodCallback& callback) OVERRIDE;
   virtual void AsyncTpmAttestationCreateCertRequest(
-      int options,
+      attestation::AttestationCertificateProfile certificate_profile,
+      const std::string& user_email,
+      const std::string& request_origin,
       const AsyncMethodCallback& callback) OVERRIDE;
   virtual void AsyncTpmAttestationFinishCertRequest(
       const std::string& pca_response,
diff --git a/chromeos/dbus/ibus/ibus_config_client.cc b/chromeos/dbus/ibus/ibus_config_client.cc
deleted file mode 100644
index 1e01d27..0000000
--- a/chromeos/dbus/ibus/ibus_config_client.cc
+++ /dev/null
@@ -1,318 +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 "chromeos/dbus/ibus/ibus_config_client.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "chromeos/dbus/ibus/ibus_constants.h"
-#include "chromeos/dbus/ibus/ibus_component.h"
-#include "dbus/bus.h"
-#include "dbus/message.h"
-#include "dbus/object_path.h"
-#include "dbus/object_proxy.h"
-
-namespace chromeos {
-
-namespace {
-
-// Called when the |signal| is connected.
-void OnSignalConnected(const std::string& interface,
-                       const std::string& signal,
-                       bool succeeded) {
-  LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
-                            << signal << " failed.";
-}
-
-// Called when the GetNameOwner method call is failed.
-void OnGetNameOwnerFail(dbus::ErrorResponse* response) {
-  // Do nothing, because method call sometimes fails due to bootstrap timing of
-  // ibus-memconf.
-}
-
-// The IBusConfigClient implementation.
-class IBusConfigClientImpl : public IBusConfigClient {
- public:
-  explicit IBusConfigClientImpl(dbus::Bus* bus)
-      : proxy_(NULL),
-        bus_(bus),
-        weak_ptr_factory_(this) {
-  }
-
-  virtual ~IBusConfigClientImpl() {}
-
-  // IBusConfigClient override.
-  virtual void InitializeAsync(const OnIBusConfigReady& on_ready) OVERRIDE {
-    // We should check that the ibus-config daemon actually works first, so we
-    // can't initialize synchronously.
-    // NameOwnerChanged signal will be emitted by ibus-daemon, but from the
-    // service name kDBusServiceName instead of kServiceName. The signal will be
-    // used to detect start of ibus-daemon.
-    dbus::ObjectProxy* dbus_proxy = bus_->GetObjectProxy(
-        ibus::kDBusServiceName,
-        dbus::ObjectPath(ibus::kDBusObjectPath));
-
-    // Watch NameOwnerChanged signal which is fired when the ibus-config daemon
-    // request its name ownership.
-    dbus_proxy->ConnectToSignal(
-        ibus::kDBusInterface,
-        ibus::kNameOwnerChangedSignal,
-        base::Bind(&IBusConfigClientImpl::OnNameOwnerChanged,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   on_ready),
-        base::Bind(&OnSignalConnected));
-
-    dbus::MethodCall method_call(ibus::kDBusInterface,
-                                 ibus::kGetNameOwnerMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendString(ibus::config::kServiceName);
-    dbus_proxy->CallMethodWithErrorCallback(
-        &method_call,
-        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::Bind(&IBusConfigClientImpl::OnGetNameOwner,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   on_ready),
-        base::Bind(&OnGetNameOwnerFail));
-  }
-
-  // IBusConfigClient override.
-  virtual void SetStringValue(const std::string& section,
-                              const std::string& key,
-                              const std::string& value,
-                              const ErrorCallback& error_callback) OVERRIDE {
-    if (!proxy_)
-      return;
-    DCHECK(!error_callback.is_null());
-    dbus::MethodCall method_call(ibus::config::kServiceInterface,
-                                 ibus::config::kSetValueMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendString(section);
-    writer.AppendString(key);
-    dbus::MessageWriter variant_writer(NULL);
-    writer.OpenVariant("s", &variant_writer);
-    variant_writer.AppendString(value);
-    writer.CloseContainer(&variant_writer);
-    CallWithDefaultCallback(&method_call, error_callback);
-  }
-
-  // IBusConfigClient override.
-  virtual void SetIntValue(const std::string& section,
-                           const std::string& key,
-                           int value,
-                           const ErrorCallback& error_callback) OVERRIDE {
-    if (!proxy_)
-      return;
-    DCHECK(!error_callback.is_null());
-    dbus::MethodCall method_call(ibus::config::kServiceInterface,
-                                 ibus::config::kSetValueMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendString(section);
-    writer.AppendString(key);
-    dbus::MessageWriter variant_writer(NULL);
-    writer.OpenVariant("i", &variant_writer);
-    variant_writer.AppendInt32(value);
-    writer.CloseContainer(&variant_writer);
-    CallWithDefaultCallback(&method_call, error_callback);
-  }
-
-  // IBusConfigClient override.
-  virtual void SetBoolValue(const std::string& section,
-                            const std::string& key,
-                            bool value,
-                            const ErrorCallback& error_callback) OVERRIDE {
-    if (!proxy_)
-      return;
-    DCHECK(!error_callback.is_null());
-    dbus::MethodCall method_call(ibus::config::kServiceInterface,
-                                 ibus::config::kSetValueMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendString(section);
-    writer.AppendString(key);
-    dbus::MessageWriter variant_writer(NULL);
-    writer.OpenVariant("b", &variant_writer);
-    variant_writer.AppendBool(value);
-    writer.CloseContainer(&variant_writer);
-    CallWithDefaultCallback(&method_call, error_callback);
-  }
-
-  // IBusConfigClient override.
-  virtual void SetStringListValue(
-      const std::string& section,
-      const std::string& key,
-      const std::vector<std::string>& value,
-      const ErrorCallback& error_callback) OVERRIDE {
-    if (!proxy_)
-      return;
-    DCHECK(!error_callback.is_null());
-    dbus::MethodCall method_call(ibus::config::kServiceInterface,
-                                 ibus::config::kSetValueMethod);
-    dbus::MessageWriter writer(&method_call);
-    writer.AppendString(section);
-    writer.AppendString(key);
-    dbus::MessageWriter variant_writer(NULL);
-    dbus::MessageWriter array_writer(NULL);
-
-    writer.OpenVariant("as", &variant_writer);
-    variant_writer.OpenArray("s", &array_writer);
-    for (size_t i = 0; i < value.size(); ++i) {
-      array_writer.AppendString(value[i]);
-    }
-    variant_writer.CloseContainer(&array_writer);
-    writer.CloseContainer(&variant_writer);
-    CallWithDefaultCallback(&method_call, error_callback);
-  }
-
- private:
-  void CallWithDefaultCallback(dbus::MethodCall* method_call,
-                               const ErrorCallback& error_callback) {
-    if (!proxy_)
-      return;
-    proxy_->CallMethodWithErrorCallback(
-        method_call,
-        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::Bind(&IBusConfigClientImpl::OnSetValue,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   error_callback),
-        base::Bind(&IBusConfigClientImpl::OnSetValueFail,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   error_callback));
-  }
-
-  void OnSetValue(const ErrorCallback& error_callback,
-                  dbus::Response* response) {
-    if (!response) {
-      LOG(ERROR) << "Response is NULL.";
-      error_callback.Run();
-      return;
-    }
-  }
-
-  void OnSetValueFail(const ErrorCallback& error_callback,
-                       dbus::ErrorResponse* response) {
-    error_callback.Run();
-  }
-
-  void OnNameOwnerChanged(const OnIBusConfigReady& on_ready,
-                          dbus::Signal* signal) {
-    DCHECK(signal);
-    std::string name;
-    std::string old_owner;
-    std::string new_owner;
-
-    dbus::MessageReader reader(signal);
-    if (!reader.PopString(&name) ||
-        !reader.PopString(&old_owner) ||
-        !reader.PopString(&new_owner)) {
-      DLOG(ERROR) << "Invalid response of NameOwnerChanged."
-                  << signal->ToString();
-      return;
-    }
-
-    if (name != ibus::config::kServiceName)
-      return;  // Not a signal for ibus-config.
-
-    if (!old_owner.empty() || new_owner.empty()) {
-      DVLOG(1) << "Unexpected name owner change: name=" << name
-               << ", old_owner=" << old_owner << ", new_owner=" << new_owner;
-      proxy_ = NULL;
-      return;
-    }
-
-    if (proxy_)
-      return;  // Already initialized.
-
-    proxy_ = bus_->GetObjectProxy(ibus::config::kServiceName,
-                                  dbus::ObjectPath(
-                                      ibus::config::kServicePath));
-    if (!on_ready.is_null())
-      on_ready.Run();
-  }
-
-  // Handles response of GetNameOwner.
-  void OnGetNameOwner(const OnIBusConfigReady& on_ready,
-                      dbus::Response* response) {
-    if (!response) {
-      LOG(ERROR) << "Response is NULL.";
-      return;
-    }
-    std::string owner;
-    dbus::MessageReader reader(response);
-
-    if (!reader.PopString(&owner)) {
-      LOG(ERROR) << "Invalid response of GetNameOwner."
-                 << response->ToString();
-      return;
-    }
-
-    // If the owner is empty, ibus-config daemon is not ready. So will
-    // initialize object proxy on NameOwnerChanged signal.
-    if (owner.empty())
-      return;
-
-    proxy_ = bus_->GetObjectProxy(ibus::config::kServiceName,
-                                  dbus::ObjectPath(
-                                      ibus::config::kServicePath));
-    if (!on_ready.is_null())
-      on_ready.Run();
-  }
-
-  dbus::ObjectProxy* proxy_;
-  dbus::Bus* bus_;
-  base::WeakPtrFactory<IBusConfigClientImpl> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(IBusConfigClientImpl);
-};
-
-// A stub implementation of IBusConfigClient.
-// A configuration framework based on ibus will not be used after Extension IME
-// migration.
-class IBusConfigClientStubImpl : public IBusConfigClient {
- public:
-  IBusConfigClientStubImpl() {}
-  virtual ~IBusConfigClientStubImpl() {}
-  virtual void InitializeAsync(const OnIBusConfigReady& on_ready) OVERRIDE {}
-  virtual void SetStringValue(const std::string& section,
-                              const std::string& key,
-                              const std::string& value,
-                              const ErrorCallback& error_callback) OVERRIDE {}
-  virtual void SetIntValue(const std::string& section,
-                           const std::string& key,
-                           int value,
-                           const ErrorCallback& error_callback) OVERRIDE {}
-  virtual void SetBoolValue(const std::string& section,
-                            const std::string& key,
-                            bool value,
-                            const ErrorCallback& error_callback) OVERRIDE {}
-  virtual void SetStringListValue(
-      const std::string& section,
-      const std::string& key,
-      const std::vector<std::string>& value,
-      const ErrorCallback& error_callback) OVERRIDE {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(IBusConfigClientStubImpl);
-};
-
-}  // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-// IBusConfigClient
-
-IBusConfigClient::IBusConfigClient() {}
-
-IBusConfigClient::~IBusConfigClient() {}
-
-// static
-IBusConfigClient* IBusConfigClient::Create(DBusClientImplementationType type,
-                                           dbus::Bus* bus) {
-  if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) {
-    return new IBusConfigClientImpl(bus);
-  }
-  DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
-  return new IBusConfigClientStubImpl();
-}
-
-}  // namespace chromeos
diff --git a/chromeos/dbus/ibus/ibus_config_client.h b/chromeos/dbus/ibus/ibus_config_client.h
deleted file mode 100644
index a7a384a..0000000
--- a/chromeos/dbus/ibus/ibus_config_client.h
+++ /dev/null
@@ -1,77 +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 CHROMEOS_DBUS_IBUS_IBUS_CONFIG_CLIENT_H_
-#define CHROMEOS_DBUS_IBUS_IBUS_CONFIG_CLIENT_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "chromeos/chromeos_export.h"
-#include "chromeos/dbus/dbus_client_implementation_type.h"
-#include "dbus/object_path.h"
-
-namespace dbus {
-class Bus;
-}  // namespace dbus
-
-namespace chromeos {
-
-class IBusComponent;
-class IBusInputContextClient;
-
-// A class to make the actual DBus calls for IBusConfig service.
-class CHROMEOS_EXPORT IBusConfigClient {
- public:
-  typedef base::Callback<void()> ErrorCallback;
-  typedef base::Callback<void()> OnIBusConfigReady;
-  virtual ~IBusConfigClient();
-
-  // Initializes IBusConfig asynchronously. |on_ready| will be called if it is
-  // ready.
-  virtual void InitializeAsync(const OnIBusConfigReady& on_ready) = 0;
-
-  // Requests the IBusConfig to set a string value.
-  virtual void SetStringValue(const std::string& section,
-                              const std::string& key,
-                              const std::string& value,
-                              const ErrorCallback& error_callback) = 0;
-
-  // Requests the IBusConfig to set a integer value.
-  virtual void SetIntValue(const std::string& section,
-                           const std::string& key,
-                           int value,
-                           const ErrorCallback& error_callback) = 0;
-
-  // Requests the IBusConfig to set a boolean value.
-  virtual void SetBoolValue(const std::string& section,
-                            const std::string& key,
-                            bool value,
-                            const ErrorCallback& error_callback) = 0;
-
-  // Requests the IBusConfig to set multiple string values.
-  virtual void SetStringListValue(const std::string& section,
-                                  const std::string& key,
-                                  const std::vector<std::string>& value,
-                                  const ErrorCallback& error_callback) = 0;
-
-  // Factory function, creates a new instance and returns ownership.
-  // For normal usage, access the singleton via DBusThreadManager::Get().
-  static CHROMEOS_EXPORT IBusConfigClient* Create(
-      DBusClientImplementationType type,
-      dbus::Bus* bus);
-
- protected:
-  // Create() should be used instead.
-  IBusConfigClient();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(IBusConfigClient);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROMEOS_DBUS_IBUS_IBUS_CONFIG_CLIENT_H_
diff --git a/chromeos/dbus/ibus/ibus_config_client_unittest.cc b/chromeos/dbus/ibus/ibus_config_client_unittest.cc
deleted file mode 100644
index 656bf4d..0000000
--- a/chromeos/dbus/ibus/ibus_config_client_unittest.cc
+++ /dev/null
@@ -1,627 +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 "chromeos/dbus/ibus/ibus_config_client.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/values.h"
-#include "chromeos/dbus/ibus/ibus_constants.h"
-#include "dbus/message.h"
-#include "dbus/mock_bus.h"
-#include "dbus/mock_object_proxy.h"
-#include "dbus/object_path.h"
-#include "dbus/values_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::Invoke;
-using testing::Return;
-using testing::_;
-
-namespace {
-const char kSection[] = "IBus/Section";
-const char kKey[] = "key";
-
-enum HandlerBehavior {
-  HANDLER_SUCCESS,
-  HANDLER_FAIL,
-};
-}  // namespace
-
-namespace chromeos {
-
-class MockErrorCallback {
- public:
-  MOCK_METHOD0(Run, void());
-};
-
-class MockOnIBusConfigReadyCallback {
- public:
-  MOCK_METHOD0(Run, void());
-};
-
-// The base class of each type specified SetValue function handler. This class
-// checks "section" and "key" field in SetValue message and callback success or
-// error callback based on given |success| flag.
-class SetValueVerifierBase {
- public:
-  SetValueVerifierBase(const std::string& expected_section,
-                       const std::string& expected_key,
-                       HandlerBehavior behavior)
-      : expected_section_(expected_section),
-        expected_key_(expected_key),
-        behavior_(behavior) {}
-
-  virtual ~SetValueVerifierBase() {}
-
-  // Handles SetValue method call. This function checks "section" and "key"
-  // field. For the "value" field, subclass checks it with over riding
-  // VeirfyVariant member function.
-  void Run(dbus::MethodCall* method_call,
-           int timeout_ms,
-           const dbus::ObjectProxy::ResponseCallback& callback,
-           const dbus::ObjectProxy::ErrorCallback& error_callback) {
-    dbus::MessageReader reader(method_call);
-    std::string section;
-    std::string key;
-
-    EXPECT_TRUE(reader.PopString(&section));
-    EXPECT_EQ(expected_section_, section);
-    EXPECT_TRUE(reader.PopString(&key));
-    EXPECT_EQ(expected_key_, key);
-    dbus::MessageReader variant_reader(NULL);
-    EXPECT_TRUE(reader.PopVariant(&variant_reader));
-
-    VerifyVariant(&variant_reader);
-
-    EXPECT_FALSE(reader.HasMoreData());
-    if (behavior_ == HANDLER_SUCCESS) {
-      scoped_ptr<dbus::Response> response(
-          dbus::Response::FromMethodCall(method_call));
-      callback.Run(response.get());
-    } else {
-      scoped_ptr<dbus::ErrorResponse> error_response(
-          dbus::ErrorResponse::FromMethodCall(method_call, "Error",
-                                              "Error Message"));
-      error_callback.Run(error_response.get());
-    }
-  }
-
-  // Verifies "value" field in SetValue method call.
-  virtual void VerifyVariant(dbus::MessageReader* reader) = 0;
-
- private:
-  const std::string expected_section_;
-  const std::string expected_key_;
-  const HandlerBehavior behavior_;
-
-  DISALLOW_COPY_AND_ASSIGN(SetValueVerifierBase);
-};
-
-// The class to verify SetStringValue method call arguments.
-class SetStringValueHandler : public SetValueVerifierBase {
- public:
-  SetStringValueHandler(const std::string& expected_key,
-                        const std::string& expected_section,
-                        const std::string& expected_value,
-                        HandlerBehavior behavior)
-      : SetValueVerifierBase(expected_section, expected_key, behavior),
-        expected_value_(expected_value) {}
-
-
-  // SetValueVerifierBase override.
-  virtual void VerifyVariant(dbus::MessageReader* reader) OVERRIDE {
-    std::string value;
-    EXPECT_TRUE(reader->PopString(&value));
-    EXPECT_EQ(expected_value_, value);
-  }
-
- private:
-  const std::string expected_value_;
-
-  DISALLOW_COPY_AND_ASSIGN(SetStringValueHandler);
-};
-
-// The class to verify SetIntValue method call arguments.
-class SetIntValueHandler : public SetValueVerifierBase {
- public:
-  SetIntValueHandler(const std::string& expected_key,
-                     const std::string& expected_section,
-                     int expected_value,
-                     HandlerBehavior behavior)
-      : SetValueVerifierBase(expected_section, expected_key, behavior),
-        expected_value_(expected_value) {}
-
-  // SetValueVerifierBase override.
-  virtual void VerifyVariant(dbus::MessageReader* reader) OVERRIDE {
-    int value = -1;
-    EXPECT_TRUE(reader->PopInt32(&value));
-    EXPECT_EQ(expected_value_, value);
-  }
-
- private:
-  const int expected_value_;
-
-  DISALLOW_COPY_AND_ASSIGN(SetIntValueHandler);
-};
-
-// The class to verify SetBoolValue method call arguments.
-class SetBoolValueHandler : public SetValueVerifierBase {
- public:
-  SetBoolValueHandler(const std::string& expected_key,
-                      const std::string& expected_section,
-                      bool expected_value,
-                      HandlerBehavior behavior)
-      : SetValueVerifierBase(expected_section, expected_key, behavior),
-        expected_value_(expected_value) {}
-
-  // SetValueVerifierBase override.
-  virtual void VerifyVariant(dbus::MessageReader* reader) OVERRIDE {
-    bool value = false;
-    EXPECT_TRUE(reader->PopBool(&value));
-    EXPECT_EQ(expected_value_, value);
-  }
-
- private:
-  const bool expected_value_;
-
-  DISALLOW_COPY_AND_ASSIGN(SetBoolValueHandler);
-};
-
-// The class to verify SetStringListValue method call arguments.
-class SetStringListValueHandler : public SetValueVerifierBase {
- public:
-  SetStringListValueHandler(const std::string& expected_key,
-                            const std::string& expected_section,
-                            const std::vector<std::string>& expected_value,
-                            HandlerBehavior behavior)
-      : SetValueVerifierBase(expected_section, expected_key, behavior),
-        expected_value_(expected_value) {}
-
-  // SetValueVerifierBase override
-  virtual void VerifyVariant(dbus::MessageReader* reader) OVERRIDE {
-    dbus::MessageReader array_reader(NULL);
-    ASSERT_TRUE(reader->PopArray(&array_reader));
-    for (size_t i = 0; i < expected_value_.size(); ++i) {
-      std::string value;
-      ASSERT_TRUE(array_reader.HasMoreData());
-      EXPECT_TRUE(array_reader.PopString(&value));
-      EXPECT_EQ(expected_value_[i], value);
-    }
-    EXPECT_FALSE(array_reader.HasMoreData());
-  }
-
- private:
-  const std::vector<std::string>& expected_value_;
-
-  DISALLOW_COPY_AND_ASSIGN(SetStringListValueHandler);
-};
-
-// The class verifies GetNameOwner method call and emits response callback
-// asynchronouslly.
-class MockGetNameOwnerMethodCallHandler {
- public:
-  MockGetNameOwnerMethodCallHandler() {}
-
-  // Handles CallMethod function.
-  void Run(dbus::MethodCall* method_call,
-           int timeout_ms,
-           const dbus::ObjectProxy::ResponseCallback& callback,
-           const dbus::ObjectProxy::ErrorCallback& error_callback) {
-    dbus::MessageReader reader(method_call);
-    std::string target_name;
-    EXPECT_TRUE(reader.PopString(&target_name));
-    EXPECT_EQ(ibus::config::kServiceName, target_name);
-    EXPECT_FALSE(reader.HasMoreData());
-
-    callback_ = callback;
-  }
-
-  // Invokes reply with given |callback_| in Run method.
-  void EmitReplyCallback(const std::string& owner) {
-    scoped_ptr<dbus::Response> response(dbus::Response::CreateEmpty());
-    dbus::MessageWriter writer(response.get());
-    writer.AppendString(owner);
-    callback_.Run(response.get());
-  }
-
- private:
-  dbus::ObjectProxy::ResponseCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockGetNameOwnerMethodCallHandler);
-};
-
-
-// The class emulate GetNameOwner signal.
-class NameOwnerChangedHandler {
- public:
-  NameOwnerChangedHandler() {}
-
-  // OnConnectToSignal mock function.
-  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) {
-    callback_ = signal_callback;
-    on_connected_callback.Run(interface_name, signal_name, true);
-  }
-
-  // Invokes reply with given |callback_| in Run method.
-  void InvokeSignal(const std::string& name,
-                    const std::string& old_owner,
-                    const std::string& new_owner) {
-    dbus::Signal signal(ibus::kDBusInterface, ibus::kGetNameOwnerMethod);
-    dbus::MessageWriter writer(&signal);
-    writer.AppendString(name);
-    writer.AppendString(old_owner);
-    writer.AppendString(new_owner);
-    callback_.Run(&signal);
-  }
-
- private:
-  dbus::ObjectProxy::SignalCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(NameOwnerChangedHandler);
-};
-
-
-class IBusConfigClientTest : public testing::Test {
- public:
-  IBusConfigClientTest() {}
-
- protected:
-  virtual void SetUp() OVERRIDE {
-    dbus::Bus::Options options;
-    mock_bus_ = new dbus::MockBus(options);
-    mock_proxy_ = new dbus::MockObjectProxy(mock_bus_.get(),
-                                            ibus::kServiceName,
-                                            dbus::ObjectPath(
-                                                ibus::config::kServicePath));
-    EXPECT_CALL(*mock_bus_.get(), ShutdownAndBlock());
-    client_.reset(IBusConfigClient::Create(REAL_DBUS_CLIENT_IMPLEMENTATION,
-                                           mock_bus_.get()));
-
-    // Surpress uninteresting mock function call warning.
-    EXPECT_CALL(*mock_bus_.get(), AssertOnOriginThread())
-        .WillRepeatedly(Return());
-  }
-
-  virtual void TearDown() OVERRIDE {
-    mock_bus_->ShutdownAndBlock();
-  }
-
-  // Initialize |client_| by replying valid owner name synchronously.
-  void InitializeSync() {
-    EXPECT_CALL(*mock_bus_.get(),
-                GetObjectProxy(ibus::config::kServiceName,
-                               dbus::ObjectPath(ibus::config::kServicePath)))
-        .WillOnce(Return(mock_proxy_.get()));
-
-    scoped_refptr<dbus::MockObjectProxy> mock_dbus_proxy
-        = new dbus::MockObjectProxy(mock_bus_.get(),
-                                    ibus::kDBusServiceName,
-                                    dbus::ObjectPath(ibus::kDBusObjectPath));
-    EXPECT_CALL(*mock_bus_.get(),
-                GetObjectProxy(ibus::kDBusServiceName,
-                               dbus::ObjectPath(ibus::kDBusObjectPath)))
-        .WillOnce(Return(mock_dbus_proxy.get()));
-
-    MockGetNameOwnerMethodCallHandler mock_get_name_owner_method_call;
-    EXPECT_CALL(*mock_dbus_proxy.get(), CallMethodWithErrorCallback(_, _, _, _))
-        .WillOnce(Invoke(&mock_get_name_owner_method_call,
-                         &MockGetNameOwnerMethodCallHandler::Run));
-    NameOwnerChangedHandler handler;
-    EXPECT_CALL(*mock_dbus_proxy.get(),
-                ConnectToSignal(
-                    ibus::kDBusInterface, ibus::kNameOwnerChangedSignal, _, _))
-        .WillOnce(
-             Invoke(&handler, &NameOwnerChangedHandler::OnConnectToSignal));
-    client_->InitializeAsync(base::Bind(&base::DoNothing));
-    mock_get_name_owner_method_call.EmitReplyCallback(":0.1");
-  }
-
-  // The IBus config client to be tested.
-  scoped_ptr<IBusConfigClient> client_;
-
-  // A message loop to emulate asynchronous behavior.
-  base::MessageLoop message_loop_;
-  scoped_refptr<dbus::MockBus> mock_bus_;
-  scoped_refptr<dbus::MockObjectProxy> mock_proxy_;
-};
-
-TEST_F(IBusConfigClientTest, SetStringValueTest) {
-  // Set expectations
-  InitializeSync();
-  const char value[] = "value";
-  SetStringValueHandler handler(kSection, kKey, value, HANDLER_SUCCESS);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run()).Times(0);
-
-  // Call SetStringValue.
-  client_->SetStringValue(kKey, kSection, value,
-                          base::Bind(&MockErrorCallback::Run,
-                                     base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, SetStringValueTest_Fail) {
-  // Set expectations
-  InitializeSync();
-  const char value[] = "value";
-  SetStringValueHandler handler(kSection, kKey, value, HANDLER_FAIL);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run());
-
-  // Call SetStringValue.
-  client_->SetStringValue(kKey, kSection, value,
-                          base::Bind(&MockErrorCallback::Run,
-                                     base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, SetIntValueTest) {
-  // Set expectations
-  InitializeSync();
-  const int value = 1234;
-  SetIntValueHandler handler(kSection, kKey, value, HANDLER_SUCCESS);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run()).Times(0);
-
-  // Call SetIntValue.
-  client_->SetIntValue(kKey, kSection, value,
-                       base::Bind(&MockErrorCallback::Run,
-                                  base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, SetIntValueTest_Fail) {
-  // Set expectations
-  InitializeSync();
-  const int value = 1234;
-  SetIntValueHandler handler(kSection, kKey, value, HANDLER_FAIL);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run());
-
-  // Call SetIntValue.
-  client_->SetIntValue(kKey, kSection, value,
-                       base::Bind(&MockErrorCallback::Run,
-                                  base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, SetBoolValueTest) {
-  // Set expectations
-  InitializeSync();
-  const bool value = true;
-  SetBoolValueHandler handler(kSection, kKey, value, HANDLER_SUCCESS);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run()).Times(0);
-
-  // Call SetBoolValue.
-  client_->SetBoolValue(kKey, kSection, value,
-                        base::Bind(&MockErrorCallback::Run,
-                                   base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, SetBoolValueTest_Fail) {
-  // Set expectations
-  InitializeSync();
-  const bool value = true;
-  SetBoolValueHandler handler(kSection, kKey, value, HANDLER_FAIL);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run());
-
-  // Call SetBoolValue.
-  client_->SetBoolValue(kKey, kSection, value,
-                       base::Bind(&MockErrorCallback::Run,
-                                  base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, SetStringListValueTest) {
-  // Set expectations
-  InitializeSync();
-  std::vector<std::string> value;
-  value.push_back("Sample value 1");
-  value.push_back("Sample value 2");
-
-  SetStringListValueHandler handler(kSection, kKey, value, HANDLER_SUCCESS);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run()).Times(0);
-
-  // Call SetStringListValue.
-  client_->SetStringListValue(kKey, kSection, value,
-                              base::Bind(&MockErrorCallback::Run,
-                                         base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, SetStringListValueTest_Fail) {
-  // Set expectations
-  InitializeSync();
-  std::vector<std::string> value;
-  value.push_back("Sample value 1");
-  value.push_back("Sample value 2");
-
-  SetStringListValueHandler handler(kSection, kKey, value, HANDLER_FAIL);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run());
-
-  // Call SetStringListValue.
-  client_->SetStringListValue(kKey, kSection, value,
-                              base::Bind(&MockErrorCallback::Run,
-                                         base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, IBusConfigDaemon_NotAvailableTest) {
-  MockGetNameOwnerMethodCallHandler mock_get_name_owner_method_call;
-
-  EXPECT_CALL(*mock_bus_.get(),
-              GetObjectProxy(ibus::kServiceName,
-                             dbus::ObjectPath(ibus::config::kServicePath)))
-      .Times(0);
-
-  scoped_refptr<dbus::MockObjectProxy> mock_dbus_proxy
-      = new dbus::MockObjectProxy(mock_bus_.get(),
-                                  ibus::kDBusServiceName,
-                                  dbus::ObjectPath(ibus::kDBusObjectPath));
-  EXPECT_CALL(*mock_bus_.get(),
-              GetObjectProxy(ibus::kDBusServiceName,
-                             dbus::ObjectPath(ibus::kDBusObjectPath)))
-      .WillOnce(Return(mock_dbus_proxy.get()));
-  EXPECT_CALL(*mock_dbus_proxy.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&mock_get_name_owner_method_call,
-                       &MockGetNameOwnerMethodCallHandler::Run));
-  NameOwnerChangedHandler handler;
-  EXPECT_CALL(*mock_dbus_proxy.get(),
-              ConnectToSignal(
-                  ibus::kDBusInterface, ibus::kNameOwnerChangedSignal, _, _))
-      .WillOnce(Invoke(&handler, &NameOwnerChangedHandler::OnConnectToSignal));
-  client_->InitializeAsync(base::Bind(&base::DoNothing));
-
-  // Passing empty string means there is no owner, thus ibus-config daemon is
-  // not ready.
-  mock_get_name_owner_method_call.EmitReplyCallback("");
-
-  // Make sure not crashing by function call without initialize.
-  const bool value = true;
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .Times(0);
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run()).Times(0);
-  client_->SetBoolValue(kKey, kSection, value,
-                        base::Bind(&MockErrorCallback::Run,
-                                   base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, IBusConfigDaemon_SlowInitializeTest) {
-  MockGetNameOwnerMethodCallHandler mock_get_name_owner_method_call;
-
-  EXPECT_CALL(*mock_bus_.get(),
-              GetObjectProxy(ibus::config::kServiceName,
-                             dbus::ObjectPath(ibus::config::kServicePath)))
-      .WillOnce(Return(mock_proxy_.get()));
-
-  scoped_refptr<dbus::MockObjectProxy> mock_dbus_proxy
-      = new dbus::MockObjectProxy(mock_bus_.get(),
-                                  ibus::kDBusServiceName,
-                                  dbus::ObjectPath(ibus::kDBusObjectPath));
-  EXPECT_CALL(*mock_bus_.get(),
-              GetObjectProxy(ibus::kDBusServiceName,
-                             dbus::ObjectPath(ibus::kDBusObjectPath)))
-      .WillOnce(Return(mock_dbus_proxy.get()));
-  EXPECT_CALL(*mock_dbus_proxy.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&mock_get_name_owner_method_call,
-                       &MockGetNameOwnerMethodCallHandler::Run));
-  NameOwnerChangedHandler name_owner_changed_handler;
-  EXPECT_CALL(*mock_dbus_proxy.get(),
-              ConnectToSignal(
-                  ibus::kDBusInterface, ibus::kNameOwnerChangedSignal, _, _))
-      .WillOnce(Invoke(&name_owner_changed_handler,
-                       &NameOwnerChangedHandler::OnConnectToSignal));
-  client_->InitializeAsync(base::Bind(&base::DoNothing));
-
-  // Passing empty string means there is no owner, thus ibus-config daemon is
-  // not ready.
-  mock_get_name_owner_method_call.EmitReplyCallback("");
-
-  // Fire NameOwnerChanged signal to emulate ibus-config daemon was acquired
-  // well-known name.
-  name_owner_changed_handler.InvokeSignal(ibus::config::kServiceName,
-                                          "",
-                                          ":0.1");
-
-  // Make sure it is possible to emit method calls.
-  const bool value = true;
-  SetBoolValueHandler handler(kSection, kKey, value, HANDLER_FAIL);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run());
-
-  // Call SetBoolValue.
-  client_->SetBoolValue(kKey, kSection, value,
-                       base::Bind(&MockErrorCallback::Run,
-                                  base::Unretained(&error_callback)));
-}
-
-TEST_F(IBusConfigClientTest, IBusConfigDaemon_ShutdownTest) {
-  MockGetNameOwnerMethodCallHandler mock_get_name_owner_method_call;
-
-  EXPECT_CALL(*mock_bus_.get(),
-              GetObjectProxy(ibus::config::kServiceName,
-                             dbus::ObjectPath(ibus::config::kServicePath)))
-      .WillRepeatedly(Return(mock_proxy_.get()));
-
-  scoped_refptr<dbus::MockObjectProxy> mock_dbus_proxy
-      = new dbus::MockObjectProxy(mock_bus_.get(),
-                                  ibus::kDBusServiceName,
-                                  dbus::ObjectPath(ibus::kDBusObjectPath));
-  EXPECT_CALL(*mock_bus_.get(),
-              GetObjectProxy(ibus::kDBusServiceName,
-                             dbus::ObjectPath(ibus::kDBusObjectPath)))
-      .WillOnce(Return(mock_dbus_proxy.get()));
-  EXPECT_CALL(*mock_dbus_proxy.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillOnce(Invoke(&mock_get_name_owner_method_call,
-                       &MockGetNameOwnerMethodCallHandler::Run));
-  NameOwnerChangedHandler name_owner_changed_handler;
-  EXPECT_CALL(*mock_dbus_proxy.get(),
-              ConnectToSignal(
-                  ibus::kDBusInterface, ibus::kNameOwnerChangedSignal, _, _))
-      .WillOnce(Invoke(&name_owner_changed_handler,
-                       &NameOwnerChangedHandler::OnConnectToSignal));
-  client_->InitializeAsync(base::Bind(&base::DoNothing));
-
-  const bool value = true;
-  SetBoolValueHandler handler(kSection, kKey, value, HANDLER_FAIL);
-  EXPECT_CALL(*mock_proxy_.get(), CallMethodWithErrorCallback(_, _, _, _))
-      .WillRepeatedly(Invoke(&handler, &SetValueVerifierBase::Run));
-  MockErrorCallback error_callback;
-  EXPECT_CALL(error_callback, Run()).WillRepeatedly(Return());
-
-  // Initialize succeeded sucessfully.
-  mock_get_name_owner_method_call.EmitReplyCallback(":0.2");
-
-  // Call SetBoolValue.
-  client_->SetBoolValue(kKey, kSection, value,
-                       base::Bind(&MockErrorCallback::Run,
-                                  base::Unretained(&error_callback)));
-
-  // Fire NameOwnerChanged signal to emulate shutting down the ibus-config
-  // daemon.
-  name_owner_changed_handler.InvokeSignal(ibus::config::kServiceName,
-                                          ":0.1",
-                                          "");
-
-  // Make sure not crashing on emitting method call.
-  client_->SetBoolValue(kKey, kSection, value,
-                       base::Bind(&MockErrorCallback::Run,
-                                  base::Unretained(&error_callback)));
-
-  // Fire NameOwnerChanged signal to emulate that ibus-daemon is revived.
-  name_owner_changed_handler.InvokeSignal(ibus::config::kServiceName,
-                                          "",
-                                          ":0.2");
-
-  // Make sure it is possible to emit method calls.
-  client_->SetBoolValue(kKey, kSection, value,
-                       base::Bind(&MockErrorCallback::Run,
-                                  base::Unretained(&error_callback)));
-}
-
-}  // namespace chromeos
diff --git a/chromeos/dbus/ibus/ibus_constants.h b/chromeos/dbus/ibus/ibus_constants.h
index cd81051..0f40e35 100644
--- a/chromeos/dbus/ibus/ibus_constants.h
+++ b/chromeos/dbus/ibus/ibus_constants.h
@@ -51,7 +51,7 @@
 const char kServicePath[] = "/org/freedesktop/IBus/Factory";
 const char kServiceInterface[] = "org.freedesktop.IBus.Factory";
 const char kCreateEngineMethod[] = "CreateEngine";
-}  // namespace engine factory
+}  // namespace engine_factory
 
 namespace engine {
 const char kServicePathPrefix[] = "/org/freedesktop/IBus/Engine/";
@@ -104,21 +104,6 @@
 const char kStateChangedMethod[] = "StateChanged";
 }  // namespace panel
 
-// Following variables indicate state of IBusProperty.
-enum IBusPropertyState {
-  IBUS_PROPERTY_STATE_UNCHECKED = 0,
-  IBUS_PROPERTY_STATE_CHECKED = 1,
-  IBUS_PROPERTY_STATE_INCONSISTENT = 2,
-};
-
-// Following button indicator value is introduced from
-// http://developer.gnome.org/gdk/stable/gdk-Event-Structures.html#GdkEventButton
-enum IBusMouseButton {
-  IBUS_MOUSE_BUTTON_LEFT = 1U,
-  IBUS_MOUSE_BUTTON_MIDDLE = 2U,
-  IBUS_MOUSE_BUTTON_RIGHT = 3U,
-};
-
 namespace config {
 const char kServiceName[] = "org.freedesktop.IBus.Config";
 const char kServicePath[] = "/org/freedesktop/IBus/Config";
@@ -126,20 +111,6 @@
 const char kSetValueMethod[] = "SetValue";
 }  // namespace config
 
-// We can't use ui/gfx/rect.h in chromeos/, so we should use ibus::Rect instead.
-struct Rect {
- Rect() : x(0), y(0), width(0), height(0) {}
- Rect(int x, int y, int width, int height)
-     : x(x),
-       y(y),
-       width(width),
-       height(height) {}
- int x;
- int y;
- int width;
- int height;
-};
-
 }  // namespace ibus
 }  // namespace chromeos
 
diff --git a/chromeos/dbus/ibus/ibus_engine_service.h b/chromeos/dbus/ibus/ibus_engine_service.h
index ac5c9ee..4913f4c 100644
--- a/chromeos/dbus/ibus/ibus_engine_service.h
+++ b/chromeos/dbus/ibus/ibus_engine_service.h
@@ -23,80 +23,9 @@
 class IBusLookupTable;
 class IBusProperty;
 class IBusText;
+class IBusEngineHandlerInterface;
 typedef ScopedVector<IBusProperty> IBusPropertyList;
 
-// A interface to handle the engine handler method call.
-class CHROMEOS_EXPORT IBusEngineHandlerInterface {
- public:
-  typedef base::Callback<void (bool consumed)> KeyEventDoneCallback;
-
-  // Following capability mask is introduced from
-  // http://ibus.googlecode.com/svn/docs/ibus-1.4/ibus-ibustypes.html#IBusCapabilite
-  // TODO(nona): Move to ibus_contants and merge one in ui/base/ime/*
-  enum IBusCapability {
-    IBUS_CAPABILITY_PREEDIT_TEXT = 1U,
-    IBUS_CAPABILITY_FOCUS = 8U,
-  };
-
-  virtual ~IBusEngineHandlerInterface() {}
-
-  // Called when the Chrome input field get the focus.
-  virtual void FocusIn() = 0;
-
-  // Called when the Chrome input field lose the focus.
-  virtual void FocusOut() = 0;
-
-  // Called when the IME is enabled.
-  virtual void Enable() = 0;
-
-  // Called when the IME is disabled.
-  virtual void Disable() = 0;
-
-  // Called when a property is activated or changed.
-  virtual void PropertyActivate(const std::string& property_name,
-                                ibus::IBusPropertyState property_state) = 0;
-
-  // Called when a property is shown.
-  virtual void PropertyShow(const std::string& property_name) = 0;
-
-  // Called when a property is hidden.
-  virtual void PropertyHide(const std::string& property_name) = 0;
-
-  // Called when the Chrome input field set their capabilities.
-  virtual void SetCapability(IBusCapability capability) = 0;
-
-  // Called when the IME is reset.
-  virtual void Reset() = 0;
-
-  // Called when the key event is received. The |keycode| is raw layout
-  // independent keycode. The |keysym| is result of XLookupString function
-  // which translate |keycode| to keyboard layout dependent symbol value.
-  // Actual implementation must call |callback| after key event handling.
-  // For example: key press event for 'd' key on us layout and dvorak layout.
-  //                  keyval keycode state
-  //      us layout :  0x64   0x20    0x00
-  //  dvorak layout :  0x65   0x20    0x00
-  virtual void ProcessKeyEvent(uint32 keysym, uint32 keycode, uint32 state,
-                               const KeyEventDoneCallback& callback) = 0;
-
-  // Called when the candidate in lookup table is clicked. The |index| is 0
-  // based candidate index in lookup table. The |state| is same value as
-  // GdkModifierType in
-  // http://developer.gnome.org/gdk/stable/gdk-Windows.html#GdkModifierType
-  virtual void CandidateClicked(uint32 index, ibus::IBusMouseButton button,
-                                uint32 state) = 0;
-
-  // Called when a new surrounding text is set. The |text| is surrounding text
-  // and |cursor_pos| is 0 based index of cursor position in |text|. If there is
-  // selection range, |anchor_pos| represents opposite index from |cursor_pos|.
-  // Otherwise |anchor_pos| is equal to |cursor_pos|.
-  virtual void SetSurroundingText(const std::string& text, uint32 cursor_pos,
-                                  uint32 anchor_pos) = 0;
-
- protected:
-  IBusEngineHandlerInterface() {}
-};
-
 // A class to make the actual DBus method call handling for IBusEngine service.
 // The exported method call is used by ibus-demon to process key event, because
 // Chrome works engine service if the extension IME is enabled. This class is
diff --git a/chromeos/dbus/ibus/ibus_engine_service_unittest.cc b/chromeos/dbus/ibus/ibus_engine_service_unittest.cc
index ff537ff..f1a0077 100644
--- a/chromeos/dbus/ibus/ibus_engine_service_unittest.cc
+++ b/chromeos/dbus/ibus/ibus_engine_service_unittest.cc
@@ -12,6 +12,7 @@
 #include "chromeos/dbus/ibus/ibus_lookup_table.h"
 #include "chromeos/dbus/ibus/ibus_property.h"
 #include "chromeos/dbus/ibus/ibus_text.h"
+#include "chromeos/ime/ibus_bridge.h"
 #include "dbus/message.h"
 #include "dbus/mock_bus.h"
 #include "dbus/mock_exported_object.h"
diff --git a/chromeos/dbus/ibus/ibus_input_context_client.h b/chromeos/dbus/ibus/ibus_input_context_client.h
index 6f10b47..ae787d4 100644
--- a/chromeos/dbus/ibus/ibus_input_context_client.h
+++ b/chromeos/dbus/ibus/ibus_input_context_client.h
@@ -12,6 +12,7 @@
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/dbus_client_implementation_type.h"
 #include "chromeos/dbus/ibus/ibus_constants.h"
+#include "chromeos/ime/ibus_bridge.h"
 #include "dbus/object_path.h"
 
 namespace dbus {
@@ -21,29 +22,7 @@
 namespace chromeos {
 
 class IBusText;
-
-class CHROMEOS_EXPORT IBusInputContextHandlerInterface {
- public:
-  // Called when the engine commit a text.
-  virtual void CommitText(const IBusText& text) = 0;
-
-  // Called when the engine forward a key event.
-  virtual void ForwardKeyEvent(uint32 keyval, uint32 keycode, uint32 state) = 0;
-
-  // Called when the engine update preedit stroing.
-  virtual void UpdatePreeditText(const IBusText& text,
-                                 uint32 cursor_pos,
-                                 bool visible) = 0;
-
-  // Called when the engine request showing preedit string.
-  virtual void ShowPreeditText() = 0;
-
-  // Called when the engine request hiding preedit string.
-  virtual void HidePreeditText() = 0;
-
-  // Called when the engine request deleting surrounding string.
-  virtual void DeleteSurroundingText(int32 offset, uint32 length) = 0;
-};
+class IBusInputContextHandlerInterface;
 
 // A class to make the actual DBus calls for IBusInputContext service.
 // The ibus-daemon creates object paths on demand, so the target object path is
diff --git a/chromeos/dbus/ibus/ibus_panel_service.h b/chromeos/dbus/ibus/ibus_panel_service.h
index a689ad6..a8dd263 100644
--- a/chromeos/dbus/ibus/ibus_panel_service.h
+++ b/chromeos/dbus/ibus/ibus_panel_service.h
@@ -12,6 +12,7 @@
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/dbus_client_implementation_type.h"
 #include "chromeos/dbus/ibus/ibus_constants.h"
+#include "chromeos/ime/ime_constants.h"
 
 namespace dbus {
 class Bus;
@@ -24,58 +25,10 @@
 class IBusLookupTable;
 class IBusProperty;
 class IBusText;
+class IBusPanelCandidateWindowHandlerInterface;
+class IBusPanelPropertyHandlerInterface;
 typedef ScopedVector<IBusProperty> IBusPropertyList;
 
-// A interface to handle the candidate window related method call.
-class CHROMEOS_EXPORT IBusPanelCandidateWindowHandlerInterface {
- public:
-  virtual ~IBusPanelCandidateWindowHandlerInterface() {}
-
-  // Called when the IME updates the lookup table.
-  virtual void UpdateLookupTable(const IBusLookupTable& table,
-                                 bool visible) = 0;
-
-  // Called when the IME hides the lookup table.
-  virtual void HideLookupTable() = 0;
-
-  // Called when the IME updates the auxiliary text. The |text| is given in
-  // UTF-8 encoding.
-  virtual void UpdateAuxiliaryText(const std::string& text, bool visible) = 0;
-
-  // Called when the IME hides the auxiliary text.
-  virtual void HideAuxiliaryText() = 0;
-
-  // Called when the IME updates the preedit text. The |text| is given in
-  // UTF-8 encoding.
-  virtual void UpdatePreeditText(const std::string& text, uint32 cursor_pos,
-                                 bool visible) = 0;
-
-  // Called when the IME hides the preedit text.
-  virtual void HidePreeditText() = 0;
-
-  // Called when the application changes its caret location.
-  virtual void SetCursorLocation(const ibus::Rect& cursor_location,
-                                 const ibus::Rect& composition_head) = 0;
-
- protected:
-  IBusPanelCandidateWindowHandlerInterface() {}
-};
-
-// A interface to handle the property related method call.
-class CHROMEOS_EXPORT IBusPanelPropertyHandlerInterface {
- public:
-  virtual ~IBusPanelPropertyHandlerInterface() {}
-
-  // Called when a new property is registered.
-  virtual void RegisterProperties(const IBusPropertyList& properties) = 0;
-
-  // Called when current property is updated.
-  virtual void UpdateProperty(const IBusProperty& property) = 0;
-
- protected:
-  IBusPanelPropertyHandlerInterface() {}
-};
-
 // A class to make the actual DBus method call handling for IBusPanel service.
 // The exported method call is used by ibus-daemon to process candidate window
 // related event, because Chrome works as candidate window. This class is
diff --git a/chromeos/dbus/ibus/ibus_property.cc b/chromeos/dbus/ibus/ibus_property.cc
index a66207c..5bb4ff4 100644
--- a/chromeos/dbus/ibus/ibus_property.cc
+++ b/chromeos/dbus/ibus/ibus_property.cc
@@ -9,6 +9,7 @@
 #include "chromeos/dbus/ibus/ibus_constants.h"
 #include "chromeos/dbus/ibus/ibus_object.h"
 #include "chromeos/dbus/ibus/ibus_text.h"
+#include "chromeos/ime/ime_constants.h"
 #include "dbus/message.h"
 
 namespace chromeos {
diff --git a/chromeos/dbus/ibus/mock_ibus_config_client.cc b/chromeos/dbus/ibus/mock_ibus_config_client.cc
deleted file mode 100644
index f32ffd0..0000000
--- a/chromeos/dbus/ibus/mock_ibus_config_client.cc
+++ /dev/null
@@ -1,44 +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 "chromeos/dbus/ibus/mock_ibus_config_client.h"
-
-#include <vector>
-
-namespace chromeos {
-
-MockIBusConfigClient::MockIBusConfigClient() {
-}
-
-MockIBusConfigClient::~MockIBusConfigClient() {}
-
-void MockIBusConfigClient::InitializeAsync(const OnIBusConfigReady& onready) {
-}
-
-void MockIBusConfigClient::SetStringValue(const std::string& key,
-                                          const std::string& section,
-                                          const std::string& value,
-                                          const ErrorCallback& error_callback) {
-}
-
-void MockIBusConfigClient::SetIntValue(const std::string& key,
-                                       const std::string& section,
-                                       int value,
-                                       const ErrorCallback& error_callback) {
-}
-
-void MockIBusConfigClient::SetBoolValue(const std::string& key,
-                                        const std::string& section,
-                                        bool value,
-                                        const ErrorCallback& error_callback) {
-}
-
-void MockIBusConfigClient::SetStringListValue(
-    const std::string& key,
-    const std::string& section,
-    const std::vector<std::string>& value,
-    const ErrorCallback& error_callback) {
-}
-
-}  // namespace chromeos
diff --git a/chromeos/dbus/ibus/mock_ibus_config_client.h b/chromeos/dbus/ibus/mock_ibus_config_client.h
deleted file mode 100644
index 2112dc1..0000000
--- a/chromeos/dbus/ibus/mock_ibus_config_client.h
+++ /dev/null
@@ -1,47 +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 CHROMEOS_DBUS_IBUS_MOCK_IBUS_CONFIG_CLIENT_H_
-#define CHROMEOS_DBUS_IBUS_MOCK_IBUS_CONFIG_CLIENT_H_
-
-#include <string>
-#include <vector>
-
-#include "chromeos/dbus/ibus/ibus_config_client.h"
-
-namespace chromeos {
-
-class MockIBusConfigClient : public IBusConfigClient {
- public:
-  MockIBusConfigClient();
-  virtual ~MockIBusConfigClient();
-  virtual void InitializeAsync(const OnIBusConfigReady& onready) OVERRIDE;
-
-  virtual void SetStringValue(const std::string& key,
-                              const std::string& section,
-                              const std::string& value,
-                              const ErrorCallback& error_callback) OVERRIDE;
-
-  virtual void SetIntValue(const std::string& key,
-                           const std::string& section,
-                           int value,
-                           const ErrorCallback& error_callback) OVERRIDE;
-
-  virtual void SetBoolValue(const std::string& key,
-                            const std::string& section,
-                            bool value,
-                            const ErrorCallback& error_callback) OVERRIDE;
-
-  virtual void SetStringListValue(const std::string& key,
-                                  const std::string& section,
-                                  const std::vector<std::string>& value,
-                                  const ErrorCallback& error_callback) OVERRIDE;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockIBusConfigClient);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROMEOS_DBUS_IBUS_MOCK_IBUS_CONFIG_CLIENT_H_
diff --git a/chromeos/dbus/mock_cryptohome_client.h b/chromeos/dbus/mock_cryptohome_client.h
index 05ae2a7..86986e6 100644
--- a/chromeos/dbus/mock_cryptohome_client.h
+++ b/chromeos/dbus/mock_cryptohome_client.h
@@ -92,9 +92,12 @@
   MOCK_METHOD2(AsyncTpmAttestationEnroll,
                void(const std::string& pca_response,
                     const AsyncMethodCallback& callback));
-  MOCK_METHOD2(AsyncTpmAttestationCreateCertRequest,
-               void(int options,
-                    const AsyncMethodCallback& callback));
+  MOCK_METHOD4(
+      AsyncTpmAttestationCreateCertRequest,
+      void(attestation::AttestationCertificateProfile certificate_profile,
+           const std::string& user_email,
+           const std::string& request_origin,
+           const AsyncMethodCallback& callback));
   MOCK_METHOD4(AsyncTpmAttestationFinishCertRequest,
                void(const std::string& pca_response,
                     attestation::AttestationKeyType key_type,
diff --git a/chromeos/dbus/mock_dbus_thread_manager.cc b/chromeos/dbus/mock_dbus_thread_manager.cc
index 6245e46..9cf664c 100644
--- a/chromeos/dbus/mock_dbus_thread_manager.cc
+++ b/chromeos/dbus/mock_dbus_thread_manager.cc
@@ -11,7 +11,6 @@
 #include "chromeos/dbus/fake_bluetooth_input_client.h"
 #include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
 #include "chromeos/dbus/ibus/mock_ibus_client.h"
-#include "chromeos/dbus/ibus/mock_ibus_config_client.h"
 #include "chromeos/dbus/ibus/mock_ibus_engine_factory_service.h"
 #include "chromeos/dbus/ibus/mock_ibus_engine_service.h"
 #include "chromeos/dbus/ibus/mock_ibus_input_context_client.h"
diff --git a/chromeos/dbus/mock_dbus_thread_manager.h b/chromeos/dbus/mock_dbus_thread_manager.h
index 60f61ee..16c4be1 100644
--- a/chromeos/dbus/mock_dbus_thread_manager.h
+++ b/chromeos/dbus/mock_dbus_thread_manager.h
@@ -79,7 +79,6 @@
   MOCK_METHOD0(GetSystemClockClient, SystemClockClient*(void));
   MOCK_METHOD0(GetUpdateEngineClient, UpdateEngineClient*(void));
   MOCK_METHOD0(GetIBusClient, IBusClient*(void));
-  MOCK_METHOD0(GetIBusConfigClient, IBusConfigClient*(void));
   MOCK_METHOD0(GetIBusInputContextClient, IBusInputContextClient*(void));
   MOCK_METHOD0(GetIBusEngineFactoryService, IBusEngineFactoryService*(void));
   MOCK_METHOD1(GetIBusEngineService,
diff --git a/chromeos/dbus/mock_dbus_thread_manager_without_gmock.cc b/chromeos/dbus/mock_dbus_thread_manager_without_gmock.cc
index 579d410..8bd95a1 100644
--- a/chromeos/dbus/mock_dbus_thread_manager_without_gmock.cc
+++ b/chromeos/dbus/mock_dbus_thread_manager_without_gmock.cc
@@ -21,7 +21,6 @@
 #include "chromeos/dbus/fake_system_clock_client.h"
 #include "chromeos/dbus/fake_update_engine_client.h"
 #include "chromeos/dbus/ibus/mock_ibus_client.h"
-#include "chromeos/dbus/ibus/mock_ibus_config_client.h"
 #include "chromeos/dbus/ibus/mock_ibus_engine_factory_service.h"
 #include "chromeos/dbus/ibus/mock_ibus_engine_service.h"
 #include "chromeos/dbus/ibus/mock_ibus_input_context_client.h"
@@ -75,7 +74,6 @@
   // Non-null bus address is used to ensure the connection to ibus-daemon.
   ibus_bus_ = reinterpret_cast<dbus::Bus*>(0xdeadbeef);
   mock_ibus_client_.reset(new MockIBusClient);
-  mock_ibus_config_client_.reset(new MockIBusConfigClient);
   mock_ibus_input_context_client_.reset(new MockIBusInputContextClient);
   mock_ibus_engine_service_.reset(new MockIBusEngineService);
   mock_ibus_engine_factory_service_.reset(new MockIBusEngineFactoryService);
@@ -217,10 +215,6 @@
   return mock_ibus_client_.get();
 }
 
-IBusConfigClient* MockDBusThreadManagerWithoutGMock::GetIBusConfigClient() {
-  return mock_ibus_config_client_.get();
-}
-
 IBusInputContextClient*
     MockDBusThreadManagerWithoutGMock::GetIBusInputContextClient() {
   return mock_ibus_input_context_client_.get();
diff --git a/chromeos/dbus/mock_dbus_thread_manager_without_gmock.h b/chromeos/dbus/mock_dbus_thread_manager_without_gmock.h
index f7c9479..f5c5841 100644
--- a/chromeos/dbus/mock_dbus_thread_manager_without_gmock.h
+++ b/chromeos/dbus/mock_dbus_thread_manager_without_gmock.h
@@ -35,7 +35,6 @@
 class FakeSystemClockClient;
 class FakeUpdateEngineClient;
 class MockIBusClient;
-class MockIBusConfigClient;
 class MockIBusEngineFactoryService;
 class MockIBusEngineService;
 class MockIBusInputContextClient;
@@ -86,7 +85,6 @@
   virtual SystemClockClient* GetSystemClockClient() OVERRIDE;
   virtual UpdateEngineClient* GetUpdateEngineClient() OVERRIDE;
   virtual IBusClient* GetIBusClient() OVERRIDE;
-  virtual IBusConfigClient* GetIBusConfigClient() OVERRIDE;
   virtual IBusInputContextClient* GetIBusInputContextClient() OVERRIDE;
   virtual IBusEngineFactoryService* GetIBusEngineFactoryService() OVERRIDE;
   virtual IBusEngineService* GetIBusEngineService(
@@ -159,10 +157,6 @@
     return mock_ibus_client_.get();
   }
 
-  MockIBusConfigClient* mock_ibus_config_client() {
-    return mock_ibus_config_client_.get();
-  }
-
   MockIBusInputContextClient* mock_ibus_input_context_client() {
     return mock_ibus_input_context_client_.get();
   }
@@ -207,7 +201,6 @@
   scoped_ptr<FakeUpdateEngineClient> fake_update_engine_client_;
 
   scoped_ptr<MockIBusClient> mock_ibus_client_;
-  scoped_ptr<MockIBusConfigClient> mock_ibus_config_client_;
   scoped_ptr<MockIBusInputContextClient> mock_ibus_input_context_client_;
   scoped_ptr<MockIBusEngineService> mock_ibus_engine_service_;
   scoped_ptr<MockIBusEngineFactoryService> mock_ibus_engine_factory_service_;
diff --git a/chromeos/dbus/shill_device_client_stub.cc b/chromeos/dbus/shill_device_client_stub.cc
index 33d5624..f7f39da 100644
--- a/chromeos/dbus/shill_device_client_stub.cc
+++ b/chromeos/dbus/shill_device_client_stub.cc
@@ -238,6 +238,10 @@
   // Add a cellular device. Used in SMS stub.
   AddDevice("stub_cellular_device1", flimflam::kTypeCellular,
             "/device/cellular1");
+  base::DictionaryValue* properties =
+      GetDeviceProperties("stub_cellular_device1");
+  properties->SetStringWithoutPathExpansion(flimflam::kCarrierProperty,
+                                            shill::kCarrierSprint);
 
   // Add a wimax device.
   AddDevice("stub_wimax_device1", flimflam::kTypeWimax,
diff --git a/chromeos/dbus/shill_service_client_stub.cc b/chromeos/dbus/shill_service_client_stub.cc
index 0f0e215..19dc65e 100644
--- a/chromeos/dbus/shill_service_client_stub.cc
+++ b/chromeos/dbus/shill_service_client_stub.cc
@@ -278,6 +278,30 @@
     const std::string& carrier,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
+  base::DictionaryValue* service_properties =
+      GetModifiableServiceProperties(service_path.value());
+  if (!service_properties) {
+    LOG(ERROR) << "Service not found: " << service_path.value();
+    error_callback.Run("Error.InvalidService", "Invalid Service");
+  }
+  SetServiceProperty(service_path.value(),
+                     flimflam::kActivationStateProperty,
+                     base::StringValue(flimflam::kActivationStateActivating));
+  base::TimeDelta delay;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kEnableStubInteractive)) {
+    const int kConnectDelaySeconds = 2;
+    delay = base::TimeDelta::FromSeconds(kConnectDelaySeconds);
+  }
+  // Set Activated after a delay
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&ShillServiceClientStub::SetCellularActivated,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 service_path,
+                 error_callback),
+      delay);
+
   base::MessageLoop::current()->PostTask(FROM_HERE, callback);
 }
 
@@ -618,4 +642,19 @@
   }
 }
 
+void ShillServiceClientStub::SetCellularActivated(
+    const dbus::ObjectPath& service_path,
+    const ErrorCallback& error_callback) {
+  SetProperty(service_path,
+              flimflam::kActivationStateProperty,
+              base::StringValue(flimflam::kActivationStateActivated),
+              base::Bind(&base::DoNothing),
+              error_callback);
+  SetProperty(service_path,
+              flimflam::kConnectableProperty,
+              base::FundamentalValue(true),
+              base::Bind(&base::DoNothing),
+              error_callback);
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/shill_service_client_stub.h b/chromeos/dbus/shill_service_client_stub.h
index 71cf224..824aa2a 100644
--- a/chromeos/dbus/shill_service_client_stub.h
+++ b/chromeos/dbus/shill_service_client_stub.h
@@ -113,6 +113,8 @@
       const std::string& service_path);
   PropertyObserverList& GetObserverList(const dbus::ObjectPath& device_path);
   void SetOtherServicesOffline(const std::string& service_path);
+  void SetCellularActivated(const dbus::ObjectPath& service_path,
+                            const ErrorCallback& error_callback);
 
   base::DictionaryValue stub_services_;
   // Observer list for each service.
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
index a8c1681..4e8f2a8 100644
--- a/chromeos/display/output_configurator.cc
+++ b/chromeos/display/output_configurator.cc
@@ -98,6 +98,16 @@
 
 }  // namespace
 
+OutputConfigurator::ModeInfo::ModeInfo()
+    : width(0),
+      height(0),
+      interlaced(false) {}
+
+OutputConfigurator::ModeInfo::ModeInfo(int width, int height, bool interlaced)
+    : width(width),
+      height(height),
+      interlaced(interlaced) {}
+
 OutputConfigurator::CoordinateTransformation::CoordinateTransformation()
     : x_scale(1.0),
       x_offset(0.0),
@@ -113,34 +123,59 @@
       selected_mode(None),
       x(0),
       y(0),
+      width_mm(0),
+      height_mm(0),
       is_internal(false),
       is_aspect_preserving_scaling(false),
       touch_device_id(0),
       display_id(0),
-      has_display_id(false) {}
+      has_display_id(false),
+      index(0) {}
 
-bool OutputConfigurator::TestApi::SendOutputChangeEvents(bool connected) {
-  XRRScreenChangeNotifyEvent screen_event;
-  memset(&screen_event, 0, sizeof(screen_event));
-  screen_event.type = xrandr_event_base_ + RRScreenChangeNotify;
-  configurator_->Dispatch(
-      reinterpret_cast<const base::NativeEvent>(&screen_event));
+OutputConfigurator::OutputSnapshot::~OutputSnapshot() {}
 
-  XRROutputChangeNotifyEvent notify_event;
-  memset(&notify_event, 0, sizeof(notify_event));
-  notify_event.type = xrandr_event_base_ + RRNotify;
-  notify_event.subtype = RRNotify_OutputChange;
-  notify_event.connection = connected ? RR_Connected : RR_Disconnected;
-  configurator_->Dispatch(
-      reinterpret_cast<const base::NativeEvent>(&notify_event));
+void OutputConfigurator::TestApi::SendScreenChangeEvent() {
+  XRRScreenChangeNotifyEvent event = {0};
+  event.type = xrandr_event_base_ + RRScreenChangeNotify;
+  configurator_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
+}
 
-  if (!configurator_->configure_timer_->IsRunning()) {
-    LOG(ERROR) << "ConfigureOutputs() timer not running";
+void OutputConfigurator::TestApi::SendOutputChangeEvent(RROutput output,
+                                                        RRCrtc crtc,
+                                                        RRMode mode,
+                                                        bool connected) {
+  XRROutputChangeNotifyEvent event = {0};
+  event.type = xrandr_event_base_ + RRNotify;
+  event.subtype = RRNotify_OutputChange;
+  event.output = output;
+  event.crtc = crtc;
+  event.mode = mode;
+  event.connection = connected ? RR_Connected : RR_Disconnected;
+  configurator_->Dispatch(reinterpret_cast<const base::NativeEvent>(&event));
+}
+
+bool OutputConfigurator::TestApi::TriggerConfigureTimeout() {
+  if (configurator_->configure_timer_.get() &&
+      configurator_->configure_timer_->IsRunning()) {
+    configurator_->configure_timer_.reset();
+    configurator_->ConfigureOutputs();
+    return true;
+  } else {
     return false;
   }
+}
 
-  configurator_->ConfigureOutputs();
-  return true;
+// static
+const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo(
+    const OutputSnapshot& output,
+    RRMode mode) {
+  std::map<RRMode, ModeInfo>::const_iterator it = output.mode_infos.find(mode);
+  if (it == output.mode_infos.end()) {
+    LOG(WARNING) << "Unable to find info about mode " << mode
+                 << " for output " << output.output;
+    return NULL;
+  }
+  return &it->second;
 }
 
 OutputConfigurator::OutputConfigurator()
@@ -184,15 +219,16 @@
       delegate_->GetOutputs(state_controller_);
   if (outputs.size() > 1 && background_color_argb)
     delegate_->SetBackgroundColor(background_color_argb);
-  EnterStateOrFallBackToSoftwareMirroring(
-      GetOutputState(outputs, power_state_), power_state_, outputs);
+  const OutputState new_state = GetOutputState(outputs, power_state_);
+  const bool success = EnterStateOrFallBackToSoftwareMirroring(
+      new_state, power_state_, outputs);
 
   // Force the DPMS on chrome startup as the driver doesn't always detect
   // that all displays are on when signing out.
   delegate_->ForceDPMSOn();
   delegate_->UngrabServer();
   delegate_->SendProjectingStateToPowerManager(IsProjecting(outputs));
-  NotifyOnDisplayChanged();
+  NotifyObservers(success, new_state);
 }
 
 void OutputConfigurator::Stop() {
@@ -213,20 +249,27 @@
   std::vector<OutputSnapshot> outputs =
       delegate_->GetOutputs(state_controller_);
 
+  const OutputState new_state = GetOutputState(outputs, power_state);
+  bool attempted_change = false;
+  bool success = false;
+
   bool only_if_single_internal_display =
       flags & kSetDisplayPowerOnlyIfSingleInternalDisplay;
   bool single_internal_display = outputs.size() == 1 && outputs[0].is_internal;
-  if ((single_internal_display || !only_if_single_internal_display) &&
-      EnterStateOrFallBackToSoftwareMirroring(
-          GetOutputState(outputs, power_state), power_state, outputs)) {
-    if (power_state != DISPLAY_POWER_ALL_OFF)  {
-      // Force the DPMS on since the driver doesn't always detect that it
-      // should turn on. This is needed when coming back from idle suspend.
+  if (single_internal_display || !only_if_single_internal_display) {
+    success = EnterStateOrFallBackToSoftwareMirroring(
+        new_state, power_state, outputs);
+    attempted_change = true;
+
+    // Force the DPMS on since the driver doesn't always detect that it
+    // should turn on. This is needed when coming back from idle suspend.
+    if (success && power_state != DISPLAY_POWER_ALL_OFF)
       delegate_->ForceDPMSOn();
-    }
   }
 
   delegate_->UngrabServer();
+  if (attempted_change)
+    NotifyObservers(success, new_state);
   return true;
 }
 
@@ -240,23 +283,18 @@
     // STATE_DUAL_EXTENDED to STATE_DUAL_EXTENDED.
     if (mirroring_controller_ && new_state == STATE_DUAL_EXTENDED)
       mirroring_controller_->SetSoftwareMirroring(false);
-    NotifyOnDisplayChanged();
+    NotifyObservers(true, new_state);
     return true;
   }
 
   delegate_->GrabServer();
   std::vector<OutputSnapshot> outputs =
       delegate_->GetOutputs(state_controller_);
-  bool success = EnterStateOrFallBackToSoftwareMirroring(
+  const bool success = EnterStateOrFallBackToSoftwareMirroring(
       new_state, power_state_, outputs);
   delegate_->UngrabServer();
 
-  if (success) {
-    NotifyOnDisplayChanged();
-  } else {
-    FOR_EACH_OBSERVER(
-        Observer, observers_, OnDisplayModeChangeFailed(new_state));
-  }
+  NotifyObservers(success, new_state);
   return success;
 }
 
@@ -265,28 +303,54 @@
     return true;
 
   if (event->type - xrandr_event_base_ == RRScreenChangeNotify) {
+    VLOG(1) << "Received RRScreenChangeNotify event";
     delegate_->UpdateXRandRConfiguration(event);
     return true;
   }
 
+  // Bail out early for everything except RRNotify_OutputChange events
+  // about an output getting connected or disconnected.
   if (event->type - xrandr_event_base_ != RRNotify)
     return true;
+  const XRRNotifyEvent* notify_event = reinterpret_cast<XRRNotifyEvent*>(event);
+  if (notify_event->subtype != RRNotify_OutputChange)
+    return true;
+  const XRROutputChangeNotifyEvent* output_change_event =
+      reinterpret_cast<XRROutputChangeNotifyEvent*>(event);
+  const int action = output_change_event->connection;
+  if (action != RR_Connected && action != RR_Disconnected)
+    return true;
 
-  XEvent* xevent = static_cast<XEvent*>(event);
-  XRRNotifyEvent* notify_event =
-      reinterpret_cast<XRRNotifyEvent*>(xevent);
-  if (notify_event->subtype == RRNotify_OutputChange) {
-    XRROutputChangeNotifyEvent* output_change_event =
-        reinterpret_cast<XRROutputChangeNotifyEvent*>(xevent);
-    if ((output_change_event->connection == RR_Connected) ||
-        (output_change_event->connection == RR_Disconnected)) {
-      // Connecting/Disconnecting display may generate multiple
-      // RRNotify. Defer configuring outputs to avoid
-      // grabbing X and configuring displays multiple times.
-      ScheduleConfigureOutputs();
+  const bool connected = (action == RR_Connected);
+  VLOG(1) << "Received RRNotify_OutputChange event:"
+          << " output=" << output_change_event->output
+          << " crtc=" << output_change_event->crtc
+          << " mode=" << output_change_event->mode
+          << " action=" << (connected ? "connected" : "disconnected");
+
+  bool found_changed_output = false;
+  for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin();
+       it != cached_outputs_.end(); ++it) {
+    if (it->output == output_change_event->output) {
+      if (connected && it->crtc == output_change_event->crtc &&
+          it->current_mode == output_change_event->mode) {
+        VLOG(1) << "Ignoring event describing already-cached state";
+        return true;
+      }
+      found_changed_output = true;
+      break;
     }
   }
 
+  if (!connected && !found_changed_output) {
+    VLOG(1) << "Ignoring event describing already-disconnected output";
+    return true;
+  }
+
+  // Connecting/disconnecting a display may generate multiple events. Defer
+  // configuring outputs to avoid grabbing X and configuring displays
+  // multiple times.
+  ScheduleConfigureOutputs();
   return true;
 }
 
@@ -357,22 +421,24 @@
   delegate_->GrabServer();
   std::vector<OutputSnapshot> outputs =
       delegate_->GetOutputs(state_controller_);
-  OutputState new_state = GetOutputState(outputs, power_state_);
-  bool success = EnterStateOrFallBackToSoftwareMirroring(
+  const OutputState new_state = GetOutputState(outputs, power_state_);
+  const bool success = EnterStateOrFallBackToSoftwareMirroring(
       new_state, power_state_, outputs);
   delegate_->UngrabServer();
 
-  if (success) {
-    NotifyOnDisplayChanged();
-  } else {
-    FOR_EACH_OBSERVER(
-        Observer, observers_, OnDisplayModeChangeFailed(new_state));
-  }
+  NotifyObservers(success, new_state);
   delegate_->SendProjectingStateToPowerManager(IsProjecting(outputs));
 }
 
-void OutputConfigurator::NotifyOnDisplayChanged() {
-  FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged());
+void OutputConfigurator::NotifyObservers(bool success,
+                                         OutputState attempted_state) {
+  if (success) {
+    FOR_EACH_OBSERVER(Observer, observers_,
+                      OnDisplayModeChanged(cached_outputs_));
+  } else {
+    FOR_EACH_OBSERVER(Observer, observers_,
+                      OnDisplayModeChangeFailed(attempted_state));
+  }
 }
 
 bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring(
@@ -434,9 +500,12 @@
         output->current_mode = output_power[i] ? output->selected_mode : None;
 
         if (output_power[i] || outputs.size() == 1) {
-          if (!delegate_->GetModeDetails(
-                  output->selected_mode, &width, &height, NULL))
+          const ModeInfo* mode_info =
+              GetModeInfo(*output, output->selected_mode);
+          if (!mode_info)
             return false;
+          width = mode_info->width;
+          height = mode_info->height;
         }
       }
       break;
@@ -449,9 +518,14 @@
         return false;
       }
 
-      if (!delegate_->GetModeDetails(
-              outputs[0].mirror_mode, &width, &height, NULL))
+      if (!outputs[0].mirror_mode)
         return false;
+      const ModeInfo* mode_info =
+          GetModeInfo(outputs[0], outputs[0].mirror_mode);
+      if (!mode_info)
+        return false;
+      width = mode_info->width;
+      height = mode_info->height;
 
       for (size_t i = 0; i < outputs.size(); ++i) {
         OutputSnapshot* output = &updated_outputs[i];
@@ -463,9 +537,9 @@
           // Otherwise, assume it is full screen, and use identity CTM.
           if (output->mirror_mode != output->native_mode &&
               output->is_aspect_preserving_scaling) {
-            output->transform = GetMirrorModeCTM(output);
+            output->transform = GetMirrorModeCTM(*output);
             mirrored_display_area_ratio_map_[output->touch_device_id] =
-                GetMirroredDisplayAreaRatio(output);
+                GetMirroredDisplayAreaRatio(*output);
           }
         }
       }
@@ -479,15 +553,7 @@
         return false;
       }
 
-      // Pairs are [width, height] corresponding to the given output's mode.
-      std::vector<std::pair<int, int> > mode_sizes(outputs.size());
-
       for (size_t i = 0; i < outputs.size(); ++i) {
-        if (!delegate_->GetModeDetails(outputs[i].selected_mode,
-                &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) {
-          return false;
-        }
-
         OutputSnapshot* output = &updated_outputs[i];
         output->x = 0;
         output->y = height ? height + kVerticalGap : 0;
@@ -496,17 +562,24 @@
         // Retain the full screen size even if all outputs are off so the
         // same desktop configuration can be restored when the outputs are
         // turned back on.
-        width = std::max<int>(width, mode_sizes[i].first);
-        height += (height ? kVerticalGap : 0) + mode_sizes[i].second;
+        const ModeInfo* mode_info =
+            GetModeInfo(outputs[i], outputs[i].selected_mode);
+        if (!mode_info)
+          return false;
+        width = std::max<int>(width, mode_info->width);
+        height += (height ? kVerticalGap : 0) + mode_info->height;
       }
 
       for (size_t i = 0; i < outputs.size(); ++i) {
         OutputSnapshot* output = &updated_outputs[i];
         if (output->touch_device_id) {
+          const ModeInfo* mode_info =
+              GetModeInfo(*output, output->selected_mode);
+          DCHECK(mode_info);
           CoordinateTransformation* ctm = &(output->transform);
-          ctm->x_scale = static_cast<float>(mode_sizes[i].first) / width;
+          ctm->x_scale = static_cast<float>(mode_info->width) / width;
           ctm->x_offset = static_cast<float>(output->x) / width;
-          ctm->y_scale = static_cast<float>(mode_sizes[i].second) / height;
+          ctm->y_scale = static_cast<float>(mode_info->height) / height;
           ctm->y_offset = static_cast<float>(output->y) / height;
         }
       }
@@ -576,24 +649,20 @@
 
 OutputConfigurator::CoordinateTransformation
 OutputConfigurator::GetMirrorModeCTM(
-    const OutputConfigurator::OutputSnapshot* output) {
+    const OutputConfigurator::OutputSnapshot& output) {
   CoordinateTransformation ctm;  // Default to identity
-  int native_mode_width = 0, native_mode_height = 0;
-  int mirror_mode_width = 0, mirror_mode_height = 0;
-  if (!delegate_->GetModeDetails(output->native_mode,
-          &native_mode_width, &native_mode_height, NULL) ||
-      !delegate_->GetModeDetails(output->mirror_mode,
-          &mirror_mode_width, &mirror_mode_height, NULL))
+  const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode);
+  const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode);
+
+  if (!native_mode_info || !mirror_mode_info ||
+      native_mode_info->height == 0 || mirror_mode_info->height == 0 ||
+      native_mode_info->width == 0 || mirror_mode_info->width == 0)
     return ctm;
 
-  if (native_mode_height == 0 || mirror_mode_height == 0 ||
-      native_mode_width == 0 || mirror_mode_width == 0)
-    return ctm;
-
-  float native_mode_ar = static_cast<float>(native_mode_width) /
-      static_cast<float>(native_mode_height);
-  float mirror_mode_ar = static_cast<float>(mirror_mode_width) /
-      static_cast<float>(mirror_mode_height);
+  float native_mode_ar = static_cast<float>(native_mode_info->width) /
+      static_cast<float>(native_mode_info->height);
+  float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) /
+      static_cast<float>(mirror_mode_info->height);
 
   if (mirror_mode_ar > native_mode_ar) {  // Letterboxing
     ctm.x_scale = 1.0;
@@ -614,24 +683,20 @@
 }
 
 float OutputConfigurator::GetMirroredDisplayAreaRatio(
-    const OutputConfigurator::OutputSnapshot* output) {
+    const OutputConfigurator::OutputSnapshot& output) {
   float area_ratio = 1.0f;
-  int native_mode_width = 0, native_mode_height = 0;
-  int mirror_mode_width = 0, mirror_mode_height = 0;
-  if (!delegate_->GetModeDetails(output->native_mode,
-          &native_mode_width, &native_mode_height, NULL) ||
-      !delegate_->GetModeDetails(output->mirror_mode,
-          &mirror_mode_width, &mirror_mode_height, NULL))
+  const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode);
+  const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode);
+
+  if (!native_mode_info || !mirror_mode_info ||
+      native_mode_info->height == 0 || mirror_mode_info->height == 0 ||
+      native_mode_info->width == 0 || mirror_mode_info->width == 0)
     return area_ratio;
 
-  if (native_mode_height == 0 || mirror_mode_height == 0 ||
-      native_mode_width == 0 || mirror_mode_width == 0)
-    return area_ratio;
-
-  float width_ratio = static_cast<float>(mirror_mode_width) /
-      static_cast<float>(native_mode_width);
-  float height_ratio = static_cast<float>(mirror_mode_height) /
-      static_cast<float>(native_mode_height);
+  float width_ratio = static_cast<float>(mirror_mode_info->width) /
+      static_cast<float>(native_mode_info->width);
+  float height_ratio = static_cast<float>(mirror_mode_info->height) /
+      static_cast<float>(native_mode_info->height);
 
   area_ratio = width_ratio * height_ratio;
   return area_ratio;
diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h
index fbc7804..5891785 100644
--- a/chromeos/display/output_configurator.h
+++ b/chromeos/display/output_configurator.h
@@ -42,6 +42,15 @@
     : public base::MessageLoop::Dispatcher,
       public base::MessagePumpObserver {
  public:
+  struct ModeInfo {
+    ModeInfo();
+    ModeInfo(int width, int height, bool interlaced);
+
+    int width;
+    int height;
+    bool interlaced;
+  };
+
   struct CoordinateTransformation {
     // Initialized to the identity transformation.
     CoordinateTransformation();
@@ -55,6 +64,7 @@
   // Information about an output's current state.
   struct OutputSnapshot {
     OutputSnapshot();
+    ~OutputSnapshot();
 
     RROutput output;
 
@@ -78,9 +88,16 @@
     int x;
     int y;
 
+    // Output's physical dimensions.
+    uint64 width_mm;
+    uint64 height_mm;
+
     bool is_internal;
     bool is_aspect_preserving_scaling;
 
+    // Map from mode IDs to details about the corresponding modes.
+    std::map<RRMode, ModeInfo> mode_infos;
+
     // XInput device ID or 0 if this output isn't a touchscreen.
     int touch_device_id;
 
@@ -90,18 +107,25 @@
     int64 display_id;
 
     bool has_display_id;
+
+    // This output's index in the array returned by XRandR. Stable even as
+    // outputs are connected or disconnected.
+    int index;
   };
 
   class Observer {
    public:
     virtual ~Observer() {}
 
-    // Called when the change of the display mode finished.  It will usually
-    // start the fading in the displays.
-    virtual void OnDisplayModeChanged() {}
+    // Called after the display mode has been changed. |output| contains the
+    // just-applied configuration. Note that the X server is no longer grabbed
+    // when this method is called, so the actual configuration could've changed
+    // already.
+    virtual void OnDisplayModeChanged(
+        const std::vector<OutputSnapshot>& outputs) {}
 
-    // Called when the change of the display mode is issued but failed.
-    // |failed_new_state| is the new state which the system failed to enter.
+    // Called after a display mode change attempt failed. |failed_new_state| is
+    // the new state which the system failed to enter.
     virtual void OnDisplayModeChangeFailed(OutputState failed_new_state) {}
   };
 
@@ -168,13 +192,6 @@
     virtual std::vector<OutputSnapshot> GetOutputs(
         const StateController* state_controller) = 0;
 
-    // Gets details corresponding to |mode|.  Parameters may be NULL.
-    // Returns true on success.
-    virtual bool GetModeDetails(RRMode mode,
-                                int* width,
-                                int* height,
-                                bool* interlaced) = 0;
-
     // Calls XRRSetCrtcConfig() with the given options but some of our default
     // output count and rotation arguments. Returns true on success.
     virtual bool ConfigureCrtc(RRCrtc crtc,
@@ -211,10 +228,18 @@
           xrandr_event_base_(xrandr_event_base) {}
     ~TestApi() {}
 
-    // Dispatches RRScreenChangeNotify and RRNotify_OutputChange events to
-    // |configurator_| and runs ConfigureOutputs().  Returns false if
-    // |configure_timer_| wasn't started.
-    bool SendOutputChangeEvents(bool connected);
+    // Dispatches an RRScreenChangeNotify event to |configurator_|.
+    void SendScreenChangeEvent();
+
+    // Dispatches an RRNotify_OutputChange event to |configurator_|.
+    void SendOutputChangeEvent(RROutput output,
+                               RRCrtc crtc,
+                               RRMode mode,
+                               bool connected);
+
+    // If |configure_timer_| is started, stops the timer, runs
+    // ConfigureOutputs(), and returns true; returns false otherwise.
+    bool TriggerConfigureTimeout();
 
    private:
     OutputConfigurator* configurator_;  // not owned
@@ -241,6 +266,11 @@
   // See crbug.com/130188 for initial discussion.
   static const int kVerticalGap = 60;
 
+  // Returns a pointer to the ModeInfo struct in |output| corresponding to
+  // |mode|, or NULL if the struct isn't present.
+  static const ModeInfo* GetModeInfo(const OutputSnapshot& output,
+                                     RRMode mode);
+
   OutputConfigurator();
   virtual ~OutputConfigurator();
 
@@ -322,8 +352,8 @@
   // Configure outputs.
   void ConfigureOutputs();
 
-  // Fires OnDisplayModeChanged() event to the observers.
-  void NotifyOnDisplayChanged();
+  // Notifies observers about an attempted state change.
+  void NotifyObservers(bool success, OutputState attempted_state);
 
   // Switches to the state specified in |output_state| and |power_state|.
   // If the hardware mirroring failed and |mirroring_controller_| is set,
@@ -352,12 +382,12 @@
   // |output| is the output on which mirror mode is being applied.
   // Returns the transformation or identity if computations fail.
   CoordinateTransformation GetMirrorModeCTM(
-      const OutputConfigurator::OutputSnapshot* output);
+      const OutputConfigurator::OutputSnapshot& output);
 
   // Returns the ratio between mirrored mode area and native mode area:
   // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height)
   float GetMirroredDisplayAreaRatio(
-      const OutputConfigurator::OutputSnapshot* output);
+      const OutputConfigurator::OutputSnapshot& output);
 
   StateController* state_controller_;
   SoftwareMirroringController* mirroring_controller_;
diff --git a/chromeos/display/output_configurator_unittest.cc b/chromeos/display/output_configurator_unittest.cc
index 96386f5..658e1ba 100644
--- a/chromeos/display/output_configurator_unittest.cc
+++ b/chromeos/display/output_configurator_unittest.cc
@@ -90,14 +90,21 @@
  public:
   static const int kXRandREventBase = 10;
 
-  TestDelegate() {}
+  TestDelegate() : configure_crtc_result_(true) {}
   virtual ~TestDelegate() {}
 
+  const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const {
+    return outputs_;
+  }
   void set_outputs(
       const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
     outputs_ = outputs;
   }
 
+  void set_configure_crtc_result(bool result) {
+    configure_crtc_result_ = result;
+  }
+
   // Returns a comma-separated string describing the actions that were
   // requested since the previous call to GetActionsAndClear() (i.e.
   // results are non-repeatable).
@@ -107,11 +114,6 @@
     return actions;
   }
 
-  // Adds a mode to be returned by GetModeDetails().
-  void AddMode(RRMode mode, int width, int height, bool interlaced) {
-    modes_[mode] = ModeDetails(width, height, interlaced);
-  }
-
   // OutputConfigurator::Delegate overrides:
   virtual void SetPanelFittingEnabled(bool enabled) OVERRIDE {}
   virtual void InitXRandRExtension(int* event_base) OVERRIDE {
@@ -131,30 +133,13 @@
       const OutputConfigurator::StateController* controller) OVERRIDE {
     return outputs_;
   }
-  virtual bool GetModeDetails(
-      RRMode mode,
-      int* width,
-      int* height,
-      bool* interlaced) OVERRIDE {
-    std::map<RRMode, ModeDetails>::const_iterator it = modes_.find(mode);
-    if (it == modes_.end())
-      return false;
-
-    if (width)
-      *width = it->second.width;
-    if (height)
-      *height = it->second.height;
-    if (interlaced)
-      *interlaced = it->second.interlaced;
-    return true;
-  }
   virtual bool ConfigureCrtc(RRCrtc crtc,
                              RRMode mode,
                              RROutput output,
                              int x,
                              int y) OVERRIDE {
     AppendAction(GetCrtcAction(crtc, x, y, mode, output));
-    return true;
+    return configure_crtc_result_;
   }
   virtual void CreateFrameBuffer(
       int width,
@@ -201,9 +186,64 @@
 
   std::string actions_;
 
+  // Return value returned by ConfigureCrtc().
+  bool configure_crtc_result_;
+
   DISALLOW_COPY_AND_ASSIGN(TestDelegate);
 };
 
+class TestObserver : public OutputConfigurator::Observer {
+ public:
+  explicit TestObserver(OutputConfigurator* configurator)
+      : configurator_(configurator) {
+    Reset();
+    configurator_->AddObserver(this);
+  }
+  virtual ~TestObserver() {
+    configurator_->RemoveObserver(this);
+  }
+
+  int num_changes() const { return num_changes_; }
+  int num_failures() const { return num_failures_; }
+  std::vector<OutputConfigurator::OutputSnapshot> latest_outputs() const {
+    return latest_outputs_;
+  }
+  OutputState latest_failed_state() const { return latest_failed_state_; }
+
+  void Reset() {
+    num_changes_ = 0;
+    num_failures_ = 0;
+    latest_outputs_.clear();
+    latest_failed_state_ = STATE_INVALID;
+  }
+
+  // OutputConfigurator::Observer overrides:
+  virtual void OnDisplayModeChanged(
+      const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
+    num_changes_++;
+    latest_outputs_ = outputs;
+  }
+
+  virtual void OnDisplayModeChangeFailed(OutputState failed_new_state)
+      OVERRIDE {
+    num_failures_++;
+    latest_failed_state_ = failed_new_state;
+  }
+
+ private:
+  OutputConfigurator* configurator_;  // Not owned.
+
+  // Number of times that OnDisplayMode*() has been called.
+  int num_changes_;
+  int num_failures_;
+
+  // Parameters most recently passed to OnDisplayMode*().
+  std::vector<OutputConfigurator::OutputSnapshot> latest_outputs_;
+  OutputState latest_failed_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestObserver);
+};
+
 class TestStateController : public OutputConfigurator::StateController {
  public:
   TestStateController() : state_(STATE_DUAL_EXTENDED) {}
@@ -250,7 +290,8 @@
 class OutputConfiguratorTest : public testing::Test {
  public:
   OutputConfiguratorTest()
-      : test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
+      : observer_(&configurator_),
+        test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
   virtual ~OutputConfiguratorTest() {}
 
   virtual void SetUp() OVERRIDE {
@@ -260,6 +301,14 @@
     configurator_.set_state_controller(&state_controller_);
     configurator_.set_mirroring_controller(&mirroring_controller_);
 
+    OutputConfigurator::ModeInfo small_mode_info;
+    small_mode_info.width = kSmallModeWidth;
+    small_mode_info.height = kSmallModeHeight;
+
+    OutputConfigurator::ModeInfo big_mode_info;
+    big_mode_info.width = kBigModeWidth;
+    big_mode_info.height = kBigModeHeight;
+
     OutputConfigurator::OutputSnapshot* o = &outputs_[0];
     o->output = 1;
     o->crtc = 10;
@@ -271,6 +320,7 @@
     o->y = 0;
     o->is_internal = true;
     o->is_aspect_preserving_scaling = true;
+    o->mode_infos[kSmallModeId] = small_mode_info;
     o->touch_device_id = 0;
     o->has_display_id = true;
 
@@ -285,12 +335,12 @@
     o->y = 0;
     o->is_internal = false;
     o->is_aspect_preserving_scaling = true;
+    o->mode_infos[kSmallModeId] = small_mode_info;
+    o->mode_infos[kBigModeId] = big_mode_info;
     o->touch_device_id = 0;
     o->has_display_id = true;
 
-    UpdateOutputs(2);
-    delegate_->AddMode(kSmallModeId, kSmallModeWidth, kSmallModeHeight, false);
-    delegate_->AddMode(kBigModeId, kBigModeWidth, kBigModeHeight, false);
+    UpdateOutputs(2, false);
   }
 
   void DisableNativeMirroring() {
@@ -308,18 +358,31 @@
   static const int kBigModeHeight = 1600;
 
   // Configures |delegate_| to return the first |num_outputs| entries from
-  // |outputs_|.
-  virtual void UpdateOutputs(size_t num_outputs) {
+  // |outputs_|. If |send_events| is true, also sends screen-change and
+  // output-change events to |configurator_| and triggers the configure
+  // timeout if one was scheduled.
+  void UpdateOutputs(size_t num_outputs, bool send_events) {
     ASSERT_LE(num_outputs, arraysize(outputs_));
     std::vector<OutputConfigurator::OutputSnapshot> outputs;
     for (size_t i = 0; i < num_outputs; ++i)
       outputs.push_back(outputs_[i]);
     delegate_->set_outputs(outputs);
+
+    if (send_events) {
+      test_api_.SendScreenChangeEvent();
+      for (size_t i = 0; i < arraysize(outputs_); ++i) {
+        const OutputConfigurator::OutputSnapshot output = outputs_[i];
+        bool connected = i < num_outputs;
+        test_api_.SendOutputChangeEvent(
+            output.output, output.crtc, output.current_mode, connected);
+      }
+      test_api_.TriggerConfigureTimeout();
+    }
   }
 
   // Initializes |configurator_| with a single internal display.
-  virtual void InitWithSingleOutput() {
-    UpdateOutputs(1);
+  void InitWithSingleOutput() {
+    UpdateOutputs(1, false);
     EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
     configurator_.Init(false);
     EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
@@ -337,6 +400,7 @@
   TestStateController state_controller_;
   TestMirroringController mirroring_controller_;
   OutputConfigurator configurator_;
+  TestObserver observer_;
   TestDelegate* delegate_;  // not owned
   OutputConfigurator::TestApi test_api_;
 
@@ -353,11 +417,11 @@
 
   // Connect a second output and check that the configurator enters
   // extended mode.
-  UpdateOutputs(2);
+  observer_.Reset();
+  state_controller_.set_state(STATE_DUAL_EXTENDED);
+  UpdateOutputs(2, true);
   const int kDualHeight =
       kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
-  state_controller_.set_state(STATE_DUAL_EXTENDED);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kBigModeWidth, kDualHeight,
                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
@@ -369,7 +433,9 @@
                         kUngrab, kProjectingOn, NULL),
             delegate_->GetActionsAndClear());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
+  observer_.Reset();
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
   EXPECT_EQ(JoinActions(kGrab,
                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
@@ -381,10 +447,11 @@
                         kUngrab, NULL),
             delegate_->GetActionsAndClear());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Disconnect the second output.
-  UpdateOutputs(1);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
+  observer_.Reset();
+  UpdateOutputs(1, true);
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
                             outputs_[0].crtc, 0).c_str(),
@@ -393,12 +460,12 @@
                         kUngrab, kProjectingOff, NULL),
             delegate_->GetActionsAndClear());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Software Mirroring
   DisableNativeMirroring();
-  UpdateOutputs(2);
   state_controller_.set_state(STATE_DUAL_EXTENDED);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+  UpdateOutputs(2, true);
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kBigModeWidth, kDualHeight,
                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
@@ -411,27 +478,32 @@
             delegate_->GetActionsAndClear());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
 
+  observer_.Reset();
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
-  EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
-            delegate_->GetActionsAndClear());
+  EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
-  // Setting STATE_DUAL_MIRROR should try to reconfigure
+  // Setting STATE_DUAL_MIRROR should try to reconfigure.
+  observer_.Reset();
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
   EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Set back to software mirror mode.
+  observer_.Reset();
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
   EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Disconnect the second output.
-  UpdateOutputs(1);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
+  observer_.Reset();
+  UpdateOutputs(1, true);
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
                             outputs_[0].crtc, 0).c_str(),
@@ -440,14 +512,15 @@
                         kUngrab, kProjectingOff, NULL),
             delegate_->GetActionsAndClear());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 }
 
 TEST_F(OutputConfiguratorTest, SetDisplayPower) {
   InitWithSingleOutput();
 
-  UpdateOutputs(2);
   state_controller_.set_state(STATE_DUAL_MIRROR);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+  observer_.Reset();
+  UpdateOutputs(2, true);
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
@@ -458,9 +531,11 @@
                         kUngrab, kProjectingOn, NULL),
             delegate_->GetActionsAndClear());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Turning off the internal display should switch the external display to
   // its native mode.
+  observer_.Reset();
   configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
                                 OutputConfigurator::kSetDisplayPowerNoFlags);
   EXPECT_EQ(JoinActions(kGrab,
@@ -473,9 +548,11 @@
                         kForceDPMS, kUngrab, NULL),
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // When all displays are turned off, the framebuffer should switch back
   // to the mirrored size.
+  observer_.Reset();
   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
                                 OutputConfigurator::kSetDisplayPowerNoFlags);
   EXPECT_EQ(JoinActions(kGrab,
@@ -489,8 +566,10 @@
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Turn all displays on and check that mirroring is still used.
+  observer_.Reset();
   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
                                 OutputConfigurator::kSetDisplayPowerNoFlags);
   EXPECT_EQ(JoinActions(kGrab,
@@ -504,17 +583,15 @@
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Software Mirroring
   DisableNativeMirroring();
-  UpdateOutputs(2);
-
+  state_controller_.set_state(STATE_DUAL_MIRROR);
+  observer_.Reset();
+  UpdateOutputs(2, true);
   const int kDualHeight =
       kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
-
-  state_controller_.set_state(STATE_DUAL_MIRROR);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
-  // Move to extended
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kBigModeWidth, kDualHeight,
                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
@@ -527,9 +604,11 @@
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Turning off the internal display should switch the external display to
   // its native mode.
+  observer_.Reset();
   configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
                                 OutputConfigurator::kSetDisplayPowerNoFlags);
   EXPECT_EQ(JoinActions(kGrab,
@@ -543,9 +622,11 @@
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // When all displays are turned off, the framebuffer should switch back
   // to the extended + software mirroring.
+  observer_.Reset();
   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
                                 OutputConfigurator::kSetDisplayPowerNoFlags);
   EXPECT_EQ(JoinActions(kGrab,
@@ -560,8 +641,10 @@
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
+  EXPECT_EQ(1, observer_.num_changes());
 
   // Turn all displays on and check that mirroring is still used.
+  observer_.Reset();
   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
                                 OutputConfigurator::kSetDisplayPowerNoFlags);
   EXPECT_EQ(JoinActions(kGrab,
@@ -576,7 +659,7 @@
             delegate_->GetActionsAndClear());
   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
-
+  EXPECT_EQ(1, observer_.num_changes());
 }
 
 TEST_F(OutputConfiguratorTest, SuspendAndResume) {
@@ -628,9 +711,8 @@
 
   // If a second, external display is connected, the displays shouldn't be
   // powered back on before suspending.
-  UpdateOutputs(2);
   state_controller_.set_state(STATE_DUAL_MIRROR);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+  UpdateOutputs(2, true);
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
@@ -657,9 +739,9 @@
   EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
             delegate_->GetActionsAndClear());
 
-  // If a display is disconnected while resuming, the configurator should
+  // If a display is disconnected while suspended, the configurator should
   // pick up the change.
-  UpdateOutputs(1);
+  UpdateOutputs(1, false);
   configurator_.ResumeDisplays();
   EXPECT_EQ(JoinActions(kGrab,
                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
@@ -671,7 +753,7 @@
 }
 
 TEST_F(OutputConfiguratorTest, Headless) {
-  UpdateOutputs(0);
+  UpdateOutputs(0, false);
   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
   configurator_.Init(false);
   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
@@ -691,11 +773,8 @@
             delegate_->GetActionsAndClear());
 
   // Connect an external display and check that it's configured correctly.
-  outputs_[0].is_internal = false;
-  outputs_[0].native_mode = kBigModeId;
-  outputs_[0].selected_mode = kBigModeId;
-  UpdateOutputs(1);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+  outputs_[0] = outputs_[1];
+  UpdateOutputs(1, true);
   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
                         GetFramebufferAction(kBigModeWidth, kBigModeHeight,
                             outputs_[0].crtc, 0).c_str(),
@@ -706,7 +785,7 @@
 }
 
 TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
-  UpdateOutputs(2);
+  UpdateOutputs(2, false);
   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
   configurator_.Init(false);
   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
@@ -725,46 +804,150 @@
 }
 
 TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
-  UpdateOutputs(0);
+  UpdateOutputs(0, false);
   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
   configurator_.Init(false);
   configurator_.Start(0);
+  observer_.Reset();
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
+  EXPECT_EQ(1, observer_.num_changes());
+  EXPECT_EQ(3, observer_.num_failures());
 
-  UpdateOutputs(1);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+  UpdateOutputs(1, true);
+  observer_.Reset();
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
+  EXPECT_EQ(1, observer_.num_changes());
+  EXPECT_EQ(3, observer_.num_failures());
 
-  UpdateOutputs(2);
   state_controller_.set_state(STATE_DUAL_EXTENDED);
-  EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
+  UpdateOutputs(2, true);
+  observer_.Reset();
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
+  EXPECT_EQ(2, observer_.num_changes());
+  EXPECT_EQ(2, observer_.num_failures());
 }
 
-TEST_F(OutputConfiguratorTest, GetOutputStateForDisplays) {
+TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) {
   outputs_[0].has_display_id = false;
-  UpdateOutputs(2);
-
+  UpdateOutputs(2, false);
   configurator_.Init(false);
-  configurator_.Start(0);
-
   state_controller_.set_state(STATE_DUAL_MIRROR);
-  test_api_.SendOutputChangeEvents(true);
+  configurator_.Start(0);
   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
+}
 
+TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) {
   outputs_[0].has_display_id = true;
-  UpdateOutputs(2);
-  test_api_.SendOutputChangeEvents(true);
+  UpdateOutputs(2, false);
+  configurator_.Init(false);
+  state_controller_.set_state(STATE_DUAL_MIRROR);
+  configurator_.Start(0);
   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
 }
 
+TEST_F(OutputConfiguratorTest, AvoidUnnecessaryProbes) {
+  InitWithSingleOutput();
+
+  // X sends several events just after the configurator starts. Check that
+  // the output change events don't trigger an additional probe, which can
+  // block the UI thread.
+  test_api_.SendScreenChangeEvent();
+  EXPECT_EQ(kUpdateXRandR, delegate_->GetActionsAndClear());
+
+  test_api_.SendOutputChangeEvent(
+      outputs_[0].output, outputs_[0].crtc, outputs_[0].current_mode, true);
+  test_api_.SendOutputChangeEvent(
+      outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
+  EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
+
+  // Send an event stating that the second output is connected and check
+  // that it gets updated.
+  state_controller_.set_state(STATE_DUAL_MIRROR);
+  UpdateOutputs(2, false);
+  test_api_.SendOutputChangeEvent(
+      outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, true);
+  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(JoinActions(kGrab,
+                        GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
+                            outputs_[0].crtc, outputs_[1].crtc).c_str(),
+                        GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+                            outputs_[0].output).c_str(),
+                        GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
+                            outputs_[1].output).c_str(),
+                        kUngrab, kProjectingOn, NULL),
+            delegate_->GetActionsAndClear());
+
+  // An event about the second output changing modes should trigger another
+  // reconfigure.
+  test_api_.SendOutputChangeEvent(
+      outputs_[1].output, outputs_[1].crtc, outputs_[1].native_mode, true);
+  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(JoinActions(kGrab,
+                        GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
+                            outputs_[0].crtc, outputs_[1].crtc).c_str(),
+                        GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+                            outputs_[0].output).c_str(),
+                        GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
+                            outputs_[1].output).c_str(),
+                        kUngrab, kProjectingOn, NULL),
+            delegate_->GetActionsAndClear());
+
+  // Disconnect the second output.
+  UpdateOutputs(1, true);
+  EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
+                        GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
+                            outputs_[0].crtc, 0).c_str(),
+                        GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+                            outputs_[0].output).c_str(),
+                        kUngrab, kProjectingOff, NULL),
+            delegate_->GetActionsAndClear());
+
+  // An additional event about the second output being disconnected should
+  // be ignored.
+  test_api_.SendOutputChangeEvent(
+      outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
+  EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
+
+  // Tell the delegate to report failure, which should result in the
+  // second output sticking with its native mode.
+  delegate_->set_configure_crtc_result(false);
+  UpdateOutputs(2, true);
+  EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
+                        GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
+                            outputs_[0].crtc, outputs_[1].crtc).c_str(),
+                        GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+                            outputs_[0].output).c_str(),
+                        GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
+                            outputs_[1].output).c_str(),
+                        kUngrab, kProjectingOn, NULL),
+            delegate_->GetActionsAndClear());
+
+  // An change event reporting a mode change on the second output should
+  // trigger another reconfigure.
+  delegate_->set_configure_crtc_result(true);
+  test_api_.SendOutputChangeEvent(
+      outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true);
+  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
+  EXPECT_EQ(JoinActions(kGrab,
+                        GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
+                            outputs_[0].crtc, outputs_[1].crtc).c_str(),
+                        GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
+                            outputs_[0].output).c_str(),
+                        GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
+                            outputs_[1].output).c_str(),
+                        kUngrab, kProjectingOn, NULL),
+            delegate_->GetActionsAndClear());
+}
+
 }  // namespace chromeos
diff --git a/chromeos/display/output_util.cc b/chromeos/display/output_util.cc
index d9d2913..4800a2d 100644
--- a/chromeos/display/output_util.cc
+++ b/chromeos/display/output_util.cc
@@ -331,8 +331,8 @@
       name.find(kInternal_DSI) == 0;
 }
 
-const XRRModeInfo* FindModeInfo(const XRRScreenResources* screen_resources,
-                                XID current_mode) {
+const XRRModeInfo* FindXRRModeInfo(const XRRScreenResources* screen_resources,
+                                   XID current_mode) {
   for (int m = 0; m < screen_resources->nmode; m++) {
     XRRModeInfo *mode = &screen_resources->modes[m];
     if (mode->id == current_mode)
@@ -353,7 +353,7 @@
   bool non_interlaced_found = false;
   for (int i = 0; i < output_info->nmode; ++i) {
     RRMode mode = output_info->modes[i];
-    const XRRModeInfo* info = FindModeInfo(screen_resources, mode);
+    const XRRModeInfo* info = FindXRRModeInfo(screen_resources, mode);
 
     if (info->width == width && info->height == height) {
       float rate = GetRefreshRate(info);
diff --git a/chromeos/display/output_util.h b/chromeos/display/output_util.h
index d464ba6..d2f1f01 100644
--- a/chromeos/display/output_util.h
+++ b/chromeos/display/output_util.h
@@ -65,7 +65,7 @@
 CHROMEOS_EXPORT bool IsInternalOutputName(const std::string& name);
 
 // Find a XRRModeInfo that matches |mode|.
-CHROMEOS_EXPORT const XRRModeInfo* FindModeInfo(
+CHROMEOS_EXPORT const XRRModeInfo* FindXRRModeInfo(
     const XRRScreenResources* screen_resources,
     XID mode);
 
diff --git a/chromeos/display/real_output_configurator_delegate.cc b/chromeos/display/real_output_configurator_delegate.cc
index 47fbd58..6d0c782 100644
--- a/chromeos/display/real_output_configurator_delegate.cc
+++ b/chromeos/display/real_output_configurator_delegate.cc
@@ -12,6 +12,8 @@
 #include <X11/extensions/Xrandr.h>
 
 #include <cmath>
+#include <set>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/message_loop/message_pump_aurax11.h"
@@ -115,68 +117,38 @@
   RRCrtc last_used_crtc = None;
 
   for (int i = 0; i < screen_->noutput && outputs.size() < 2; ++i) {
-    RROutput this_id = screen_->outputs[i];
-    XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, this_id);
+    RROutput output_id = screen_->outputs[i];
+    XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id);
     bool is_connected = (output_info->connection == RR_Connected);
 
-    if (is_connected) {
-      OutputConfigurator::OutputSnapshot to_populate;
-      to_populate.output = this_id;
-      to_populate.has_display_id =
-          GetDisplayId(this_id, i, &to_populate.display_id);
-      to_populate.is_internal = IsInternalOutput(output_info);
-      // Use the index as a valid display id even if the internal
-      // display doesn't have valid EDID because the index
-      // will never change.
-      if (!to_populate.has_display_id && to_populate.is_internal)
-        to_populate.has_display_id = true;
-
-      (outputs.empty() ? one_info : two_info) = output_info;
-
-      // Now, look up the current CRTC and any related info.
-      if (output_info->crtc) {
-        XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(
-            display_, screen_, output_info->crtc);
-        to_populate.current_mode = crtc_info->mode;
-        to_populate.x = crtc_info->x;
-        to_populate.y = crtc_info->y;
-        XRRFreeCrtcInfo(crtc_info);
-      }
-
-      // Assign a CRTC that isn't already in use.
-      for (int j = 0; j < output_info->ncrtc; ++j) {
-        if (output_info->crtcs[j] != last_used_crtc) {
-          to_populate.crtc = output_info->crtcs[j];
-          last_used_crtc = to_populate.crtc;
-          break;
-        }
-      }
-      to_populate.native_mode = GetOutputNativeMode(output_info);
-      if (to_populate.has_display_id) {
-        int width = 0, height = 0;
-        if (state_controller &&
-            state_controller->GetResolutionForDisplayId(
-                to_populate.display_id, &width, &height)) {
-          to_populate.selected_mode =
-              FindOutputModeMatchingSize(screen_, output_info, width, height);
-        }
-      }
-      // Fallback to native mode.
-      if (to_populate.selected_mode == None)
-        to_populate.selected_mode = to_populate.native_mode;
-
-      to_populate.is_aspect_preserving_scaling =
-          IsOutputAspectPreservingScaling(this_id);
-      to_populate.touch_device_id = None;
-
-      VLOG(2) << "Found display " << outputs.size() << ":"
-              << " output=" << to_populate.output
-              << " crtc=" << to_populate.crtc
-              << " current_mode=" << to_populate.current_mode;
-      outputs.push_back(to_populate);
-    } else {
+    if (!is_connected) {
       XRRFreeOutputInfo(output_info);
+      continue;
     }
+
+    (outputs.empty() ? one_info : two_info) = output_info;
+
+    OutputConfigurator::OutputSnapshot output = InitOutputSnapshot(
+        output_id, output_info, &last_used_crtc, i);
+
+    if (output.has_display_id) {
+      int width = 0, height = 0;
+      if (state_controller &&
+          state_controller->GetResolutionForDisplayId(
+              output.display_id, &width, &height)) {
+        output.selected_mode =
+            FindOutputModeMatchingSize(screen_, output_info, width, height);
+      }
+    }
+    // Fall back to native mode.
+    if (output.selected_mode == None)
+      output.selected_mode = output.native_mode;
+
+    VLOG(2) << "Found display " << outputs.size() << ":"
+            << " output=" << output.output
+            << " crtc=" << output.crtc
+            << " current_mode=" << output.current_mode;
+    outputs.push_back(output);
   }
 
   if (outputs.size() == 2) {
@@ -228,30 +200,6 @@
   return outputs;
 }
 
-bool RealOutputConfiguratorDelegate::GetModeDetails(RRMode mode,
-                                                    int* width,
-                                                    int* height,
-                                                    bool* interlaced) {
-  CHECK(screen_) << "Server not grabbed";
-  // TODO: Determine if we need to organize modes in a way which provides
-  // better than O(n) lookup time.  In many call sites, for example, the
-  // "next" mode is typically what we are looking for so using this
-  // helper might be too expensive.
-  for (int i = 0; i < screen_->nmode; ++i) {
-    if (mode == screen_->modes[i].id) {
-      const XRRModeInfo& info = screen_->modes[i];
-      if (width)
-        *width = info.width;
-      if (height)
-        *height = info.height;
-      if (interlaced)
-        *interlaced = info.modeFlags & RR_Interlace;
-      return true;
-    }
-  }
-  return false;
-}
-
 bool RealOutputConfiguratorDelegate::ConfigureCrtc(
     RRCrtc crtc,
     RRMode mode,
@@ -343,6 +291,85 @@
       SetIsProjecting(projecting);
 }
 
+bool RealOutputConfiguratorDelegate::GetModeDetails(RRMode mode,
+                                                    int* width,
+                                                    int* height,
+                                                    bool* interlaced) {
+  CHECK(screen_) << "Server not grabbed";
+  // TODO: Determine if we need to organize modes in a way which provides
+  // better than O(n) lookup time.  In many call sites, for example, the
+  // "next" mode is typically what we are looking for so using this
+  // helper might be too expensive.
+  for (int i = 0; i < screen_->nmode; ++i) {
+    if (mode == screen_->modes[i].id) {
+      const XRRModeInfo& info = screen_->modes[i];
+      if (width)
+        *width = info.width;
+      if (height)
+        *height = info.height;
+      if (interlaced)
+        *interlaced = info.modeFlags & RR_Interlace;
+      return true;
+    }
+  }
+  return false;
+}
+
+OutputConfigurator::OutputSnapshot
+RealOutputConfiguratorDelegate::InitOutputSnapshot(
+    RROutput id,
+    XRROutputInfo* info,
+    RRCrtc* last_used_crtc,
+    int index) {
+  OutputConfigurator::OutputSnapshot output;
+  output.output = id;
+  output.width_mm = info->mm_width;
+  output.height_mm = info->mm_height;
+  output.has_display_id = GetDisplayId(id, index, &output.display_id);
+  output.is_internal = IsInternalOutput(info);
+  output.index = index;
+
+  // Use the index as a valid display ID even if the internal
+  // display doesn't have valid EDID because the index
+  // will never change.
+  if (!output.has_display_id && output.is_internal)
+    output.has_display_id = true;
+
+  if (info->crtc) {
+    XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display_, screen_, info->crtc);
+    output.current_mode = crtc_info->mode;
+    output.x = crtc_info->x;
+    output.y = crtc_info->y;
+    XRRFreeCrtcInfo(crtc_info);
+  }
+
+  // Assign a CRTC that isn't already in use.
+  for (int i = 0; i < info->ncrtc; ++i) {
+    if (info->crtcs[i] != *last_used_crtc) {
+      output.crtc = info->crtcs[i];
+      *last_used_crtc = output.crtc;
+      break;
+    }
+  }
+
+  output.native_mode = GetOutputNativeMode(info);
+  output.is_aspect_preserving_scaling = IsOutputAspectPreservingScaling(id);
+  output.touch_device_id = None;
+
+  for (int i = 0; i < info->nmode; ++i) {
+    const RRMode mode = info->modes[i];
+    OutputConfigurator::ModeInfo mode_info;
+    if (GetModeDetails(mode, &mode_info.width, &mode_info.height,
+                       &mode_info.interlaced)) {
+      output.mode_infos.insert(std::make_pair(mode, mode_info));
+    } else {
+      LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode;
+    }
+  }
+
+  return output;
+}
+
 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs(
     const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
   CHECK(screen_) << "Server not grabbed";
@@ -362,25 +389,28 @@
     RRCrtc crtc = screen_->crtcs[i];
     RRMode mode = None;
     RROutput output = None;
+    const OutputConfigurator::ModeInfo* mode_info = NULL;
     for (std::vector<OutputConfigurator::OutputSnapshot>::const_iterator it =
          outputs.begin(); it != outputs.end(); ++it) {
       if (crtc == it->crtc) {
         mode = it->current_mode;
         output = it->output;
+        if (mode != None)
+          mode_info = OutputConfigurator::GetModeInfo(*it, mode);
         break;
       }
     }
 
-    if (mode != None) {
+    if (mode_info) {
       // In case our CRTC doesn't fit in our current framebuffer, disable it.
       // It'll get reenabled after we resize the framebuffer.
-      int mode_width = 0, mode_height = 0;
-      CHECK(GetModeDetails(mode, &mode_width, &mode_height, NULL));
       int current_width = DisplayWidth(display_, DefaultScreen(display_));
       int current_height = DisplayHeight(display_, DefaultScreen(display_));
-      if (mode_width > current_width || mode_height > current_height) {
+      if (mode_info->width > current_width ||
+          mode_info->height > current_height) {
         mode = None;
         output = None;
+        mode_info = NULL;
       }
     }
 
@@ -510,6 +540,7 @@
   if (valuator_x == None || valuator_y == None)
     return;
 
+  std::set<int> no_match_touchscreen;
   XIDeviceInfo* info = XIQueryDevice(display_, XIAllDevices, &ndevices);
   for (int i = 0; i < ndevices; i++) {
     if (!info[i].enabled || info[i].use != XIFloatingSlave)
@@ -554,12 +585,13 @@
     if (width > 0.0 && height > 0.0 && is_direct_touch) {
       size_t k = 0;
       for (; k < outputs->size(); k++) {
-        if ((*outputs)[k].native_mode == None ||
-            (*outputs)[k].touch_device_id != None)
+        OutputConfigurator::OutputSnapshot* output = &(*outputs)[k];
+        if (output->native_mode == None || output->touch_device_id != None)
           continue;
-        int native_mode_width = 0, native_mode_height = 0;
-        if (!GetModeDetails((*outputs)[k].native_mode, &native_mode_width,
-                            &native_mode_height, NULL))
+
+        const OutputConfigurator::ModeInfo* mode_info =
+            OutputConfigurator::GetModeInfo(*output, output->native_mode);
+        if (!mode_info)
           continue;
 
         // Allow 1 pixel difference between screen and touchscreen
@@ -567,23 +599,45 @@
         // 1024x768 touchscreen's resolution would be 1024x768, but for
         // some 1023x767.  It really depends on touchscreen's firmware
         // configuration.
-        if (std::abs(native_mode_width - width) <= 1.0 &&
-            std::abs(native_mode_height - height) <= 1.0) {
-          (*outputs)[k].touch_device_id = info[i].deviceid;
+        if (std::abs(mode_info->width - width) <= 1.0 &&
+            std::abs(mode_info->height - height) <= 1.0) {
+          output->touch_device_id = info[i].deviceid;
 
           VLOG(2) << "Found touchscreen for output #" << k
-                  << " id " << (*outputs)[k].touch_device_id
+                  << " id " << output->touch_device_id
                   << " width " << width
                   << " height " << height;
           break;
         }
       }
 
-      VLOG_IF(2, k == outputs->size())
-          << "No matching output - ignoring touchscreen"
-          << " id " << info[i].deviceid
-          << " width " << width
-          << " height " << height;
+      if (k == outputs->size()) {
+        no_match_touchscreen.insert(info[i].deviceid);
+        VLOG(2) << "No matching output for touchscreen"
+                << " id " << info[i].deviceid
+                << " width " << width
+                << " height " << height;
+      }
+
+    }
+  }
+
+  // Sometimes we can't find a matching screen for the touchscreen, e.g.
+  // due to the touchscreen's reporting range having no correlation with the
+  // screen's resolution. In this case, we arbitrarily assign unmatched
+  // touchscreens to unmatched screens.
+  for (std::set<int>::iterator it = no_match_touchscreen.begin();
+       it != no_match_touchscreen.end();
+       it++) {
+    for (size_t i = 0; i < outputs->size(); i++) {
+      if ((*outputs)[i].is_internal == false &&
+          (*outputs)[i].native_mode != None &&
+          (*outputs)[i].touch_device_id == None ) {
+        (*outputs)[i].touch_device_id = *it;
+        VLOG(2) << "Arbitrarily matching touchscreen "
+                << (*outputs)[i].touch_device_id << " to output #" << i;
+        break;
+      }
     }
   }
 
diff --git a/chromeos/display/real_output_configurator_delegate.h b/chromeos/display/real_output_configurator_delegate.h
index 9f083cf..2753ae5 100644
--- a/chromeos/display/real_output_configurator_delegate.h
+++ b/chromeos/display/real_output_configurator_delegate.h
@@ -39,11 +39,6 @@
   virtual void ForceDPMSOn() OVERRIDE;
   virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs(
       const OutputConfigurator::StateController* state_controller) OVERRIDE;
-  virtual bool GetModeDetails(
-      RRMode mode,
-      int* width,
-      int* height,
-      bool* interlaced) OVERRIDE;
   virtual bool ConfigureCrtc(
       RRCrtc crtc,
       RRMode mode,
@@ -60,6 +55,19 @@
   virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE;
 
  private:
+  // Gets details corresponding to |mode|. Parameters may be NULL. Returns
+  // true on success.
+  bool GetModeDetails(RRMode mode, int* width, int* height, bool* interlaced);
+
+  // Helper method for GetOutputs() that returns an OutputSnapshot struct based
+  // on the passed-in information. Further initialization is required (e.g.
+  // |selected_mode|, |mirror_mode|, and |touch_device_id|).
+  OutputConfigurator::OutputSnapshot InitOutputSnapshot(
+      RROutput id,
+      XRROutputInfo* info,
+      RRCrtc* last_used_crtc,
+      int index);
+
   // Destroys unused CRTCs and parks used CRTCs in a way which allows a
   // framebuffer resize. This is faster than turning them off, resizing,
   // then turning them back on.
diff --git a/chromeos/ime/ibus_bridge.h b/chromeos/ime/ibus_bridge.h
index 0931417..20b8018 100644
--- a/chromeos/ime/ibus_bridge.h
+++ b/chromeos/ime/ibus_bridge.h
@@ -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.
+// TODO(nona): Rename this file to ime_bridge.h
 
 #ifndef CHROMEOS_IME_IBUS_BRIDGE_H_
 #define CHROMEOS_IME_IBUS_BRIDGE_H_
@@ -9,12 +10,161 @@
 #include "base/basictypes.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/dbus/ibus/ibus_engine_factory_service.h"
+#include "chromeos/ime/ime_constants.h"
 
 namespace chromeos {
-class IBusInputContextHandlerInterface;
-class IBusEngineHandlerInterface;
-class IBusPanelCandidateWindowHandlerInterface;
-class IBusPanelPropertyHandlerInterface;
+
+class IBusText;
+class IBusLookupTable;
+class IBusProperty;
+typedef ScopedVector<IBusProperty> IBusPropertyList;
+
+class CHROMEOS_EXPORT IBusInputContextHandlerInterface {
+ public:
+  // Called when the engine commit a text.
+  virtual void CommitText(const IBusText& text) = 0;
+
+  // Called when the engine forward a key event.
+  virtual void ForwardKeyEvent(uint32 keyval, uint32 keycode, uint32 state) = 0;
+
+  // Called when the engine update preedit stroing.
+  virtual void UpdatePreeditText(const IBusText& text,
+                                 uint32 cursor_pos,
+                                 bool visible) = 0;
+
+  // Called when the engine request showing preedit string.
+  virtual void ShowPreeditText() = 0;
+
+  // Called when the engine request hiding preedit string.
+  virtual void HidePreeditText() = 0;
+
+  // Called when the engine request deleting surrounding string.
+  virtual void DeleteSurroundingText(int32 offset, uint32 length) = 0;
+};
+
+
+// A interface to handle the engine handler method call.
+class CHROMEOS_EXPORT IBusEngineHandlerInterface {
+ public:
+  typedef base::Callback<void (bool consumed)> KeyEventDoneCallback;
+
+  // Following capability mask is introduced from
+  // http://ibus.googlecode.com/svn/docs/ibus-1.4/ibus-ibustypes.html#IBusCapabilite
+  // TODO(nona): Move to ibus_contants and merge one in ui/base/ime/*
+  enum IBusCapability {
+    IBUS_CAPABILITY_PREEDIT_TEXT = 1U,
+    IBUS_CAPABILITY_FOCUS = 8U,
+  };
+
+  virtual ~IBusEngineHandlerInterface() {}
+
+  // Called when the Chrome input field get the focus.
+  virtual void FocusIn() = 0;
+
+  // Called when the Chrome input field lose the focus.
+  virtual void FocusOut() = 0;
+
+  // Called when the IME is enabled.
+  virtual void Enable() = 0;
+
+  // Called when the IME is disabled.
+  virtual void Disable() = 0;
+
+  // Called when a property is activated or changed.
+  virtual void PropertyActivate(const std::string& property_name,
+                                ibus::IBusPropertyState property_state) = 0;
+
+  // Called when a property is shown.
+  virtual void PropertyShow(const std::string& property_name) = 0;
+
+  // Called when a property is hidden.
+  virtual void PropertyHide(const std::string& property_name) = 0;
+
+  // Called when the Chrome input field set their capabilities.
+  virtual void SetCapability(IBusCapability capability) = 0;
+
+  // Called when the IME is reset.
+  virtual void Reset() = 0;
+
+  // Called when the key event is received. The |keycode| is raw layout
+  // independent keycode. The |keysym| is result of XLookupString function
+  // which translate |keycode| to keyboard layout dependent symbol value.
+  // Actual implementation must call |callback| after key event handling.
+  // For example: key press event for 'd' key on us layout and dvorak layout.
+  //                  keyval keycode state
+  //      us layout :  0x64   0x20    0x00
+  //  dvorak layout :  0x65   0x20    0x00
+  virtual void ProcessKeyEvent(uint32 keysym, uint32 keycode, uint32 state,
+                               const KeyEventDoneCallback& callback) = 0;
+
+  // Called when the candidate in lookup table is clicked. The |index| is 0
+  // based candidate index in lookup table. The |state| is same value as
+  // GdkModifierType in
+  // http://developer.gnome.org/gdk/stable/gdk-Windows.html#GdkModifierType
+  virtual void CandidateClicked(uint32 index, ibus::IBusMouseButton button,
+                                uint32 state) = 0;
+
+  // Called when a new surrounding text is set. The |text| is surrounding text
+  // and |cursor_pos| is 0 based index of cursor position in |text|. If there is
+  // selection range, |anchor_pos| represents opposite index from |cursor_pos|.
+  // Otherwise |anchor_pos| is equal to |cursor_pos|.
+  virtual void SetSurroundingText(const std::string& text, uint32 cursor_pos,
+                                  uint32 anchor_pos) = 0;
+
+ protected:
+  IBusEngineHandlerInterface() {}
+};
+
+// A interface to handle the candidate window related method call.
+class CHROMEOS_EXPORT IBusPanelCandidateWindowHandlerInterface {
+ public:
+  virtual ~IBusPanelCandidateWindowHandlerInterface() {}
+
+  // Called when the IME updates the lookup table.
+  virtual void UpdateLookupTable(const IBusLookupTable& table,
+                                 bool visible) = 0;
+
+  // Called when the IME hides the lookup table.
+  virtual void HideLookupTable() = 0;
+
+  // Called when the IME updates the auxiliary text. The |text| is given in
+  // UTF-8 encoding.
+  virtual void UpdateAuxiliaryText(const std::string& text, bool visible) = 0;
+
+  // Called when the IME hides the auxiliary text.
+  virtual void HideAuxiliaryText() = 0;
+
+  // Called when the IME updates the preedit text. The |text| is given in
+  // UTF-8 encoding.
+  virtual void UpdatePreeditText(const std::string& text, uint32 cursor_pos,
+                                 bool visible) = 0;
+
+  // Called when the IME hides the preedit text.
+  virtual void HidePreeditText() = 0;
+
+  // Called when the application changes its caret location.
+  virtual void SetCursorLocation(const ibus::Rect& cursor_location,
+                                 const ibus::Rect& composition_head) = 0;
+
+ protected:
+  IBusPanelCandidateWindowHandlerInterface() {}
+};
+
+// A interface to handle the property related method call.
+class CHROMEOS_EXPORT IBusPanelPropertyHandlerInterface {
+ public:
+  virtual ~IBusPanelPropertyHandlerInterface() {}
+
+  // Called when a new property is registered.
+  virtual void RegisterProperties(const IBusPropertyList& properties) = 0;
+
+  // Called when current property is updated.
+  virtual void UpdateProperty(const IBusProperty& property) = 0;
+
+ protected:
+  IBusPanelPropertyHandlerInterface() {}
+};
+
 
 // IBusBridge provides access of each IME related handler. This class is used
 // for IME implementation without ibus-daemon. The legacy ibus IME communicates
diff --git a/chromeos/ime/ibus_daemon_controller.cc b/chromeos/ime/ibus_daemon_controller.cc
index c328512..ec79904 100644
--- a/chromeos/ime/ibus_daemon_controller.cc
+++ b/chromeos/ime/ibus_daemon_controller.cc
@@ -291,7 +291,6 @@
     // production at this moment, only for Chrome OS on Linux Desktop.
     // TODO(nona): Remove InitIBusBus oncer all legacy ime is migrated to IME
     // extension API.
-    DCHECK(!base::chromeos::IsRunningOnChromeOS());
     DBusThreadManager::Get()->InitIBusBus("dummy address",
                                           base::Bind(&base::DoNothing));
     is_started_ = true;
@@ -329,12 +328,7 @@
     const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) {
   DCHECK(g_ibus_daemon_controller == NULL)
       << "Do not call Initialize function multiple times.";
-  if (base::chromeos::IsRunningOnChromeOS()) {
-    g_ibus_daemon_controller = new IBusDaemonControllerImpl(ui_task_runner,
-                                                            file_task_runner);
-  } else {
-    g_ibus_daemon_controller = new IBusDaemonControllerDaemonlessImpl();
-  }
+  g_ibus_daemon_controller = new IBusDaemonControllerDaemonlessImpl();
 }
 
 // static
diff --git a/chromeos/ime/ime_constants.h b/chromeos/ime/ime_constants.h
new file mode 100644
index 0000000..8dcfffa
--- /dev/null
+++ b/chromeos/ime/ime_constants.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 CHROMEOS_IME_IME_CONSTANTS_H_
+#define CHROMEOS_IME_IME_CONSTANTS_H_
+
+namespace chromeos {
+
+// TODO(nona): Remove ibus namespace
+namespace ibus {
+
+// Following button indicator value is introduced from
+// http://developer.gnome.org/gdk/stable/gdk-Event-Structures.html#GdkEventButton
+enum IBusMouseButton {
+  IBUS_MOUSE_BUTTON_LEFT = 1U,
+  IBUS_MOUSE_BUTTON_MIDDLE = 2U,
+  IBUS_MOUSE_BUTTON_RIGHT = 3U,
+};
+
+// Following variables indicate state of IBusProperty.
+enum IBusPropertyState {
+  IBUS_PROPERTY_STATE_UNCHECKED = 0,
+  IBUS_PROPERTY_STATE_CHECKED = 1,
+  IBUS_PROPERTY_STATE_INCONSISTENT = 2,
+};
+
+// We can't use ui/gfx/rect.h in chromeos/, so we should use ibus::Rect instead.
+struct Rect {
+ Rect() : x(0), y(0), width(0), height(0) {}
+ Rect(int x, int y, int width, int height)
+     : x(x),
+       y(y),
+       width(width),
+       height(height) {}
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+}  // namespace ibus
+}  // namespace chromeos
+
+#endif  // CHROMEOS_IME_IME_CONSTANTS_H_
diff --git a/chromeos/ime/input_method_manager.h b/chromeos/ime/input_method_manager.h
index 5a94455..7b18124 100644
--- a/chromeos/ime/input_method_manager.h
+++ b/chromeos/ime/input_method_manager.h
@@ -145,12 +145,6 @@
       const std::string& keyboard_id,
       std::vector<std::string>* input_method_ids) = 0;
 
-  // Updates a configuration of a system input method engine with |value|.
-  // Returns true if the configuration is correctly set.
-  virtual bool SetInputMethodConfig(const std::string& section,
-                                    const std::string& config_name,
-                                    const InputMethodConfigValue& value) = 0;
-
   // Adds an input method extension. This function does not takes ownership of
   // |instance|.
   virtual void AddInputMethodExtension(
diff --git a/chromeos/ime/input_method_whitelist.cc b/chromeos/ime/input_method_whitelist.cc
index cea052c..d798e09 100644
--- a/chromeos/ime/input_method_whitelist.cc
+++ b/chromeos/ime/input_method_whitelist.cc
@@ -6,12 +6,15 @@
 
 #include <vector>
 
+#include "base/strings/string_util.h"
 #include "chromeos/ime/input_method_descriptor.h"
 #include "chromeos/ime/input_methods.h"
 
 namespace chromeos {
 namespace input_method {
 
+const char kLanguageDelimiter[] = ",";
+
 InputMethodWhitelist::InputMethodWhitelist() {
   for (size_t i = 0; i < arraysize(kInputMethods); ++i) {
     supported_input_methods_.insert(kInputMethods[i].input_method_id);
@@ -35,7 +38,8 @@
     layouts.push_back(kInputMethods[i].xkb_layout_id);
 
     std::vector<std::string> languages;
-    languages.push_back(kInputMethods[i].language_code);
+    Tokenize(kInputMethods[i].language_code, kLanguageDelimiter, &languages);
+    DCHECK(!languages.empty());
 
     input_methods->push_back(InputMethodDescriptor(
         kInputMethods[i].input_method_id,
diff --git a/chromeos/ime/input_methods.txt b/chromeos/ime/input_methods.txt
index 2b4bc91..d1e33cf 100644
--- a/chromeos/ime/input_methods.txt
+++ b/chromeos/ime/input_methods.txt
@@ -1,27 +1,5 @@
-# The list of input methods that we support. The input methods metadata is
-# also defined here. We use this data for the following purposes.
-#
-# 1. Exclude unnecessary input methods. For example, we don't need
-#    "ja:anthy", and "zh:pinyin" engines in ibus-m17n since we have better
-#    alternatives outside of ibus-m17n. Excluding these input methods from
-#    the IBus engine XML files, such as /usr/share/ibus/component/m17n.xml,
-#    makes the startup time of the IBus daemon faster. This filtering is
-#    done using a python script at build time of ibus-m17n.
-#    See crosbug.com/4161 for details.
-#
-# 2. Provide the input methods metadata to Chrome at build time. Chrome
-#    needs to know about the supported input methods for the input method
-#    features, such as the input method switching and the options page,
-#    to work. Note that we can retrieve the same metadata from the IBus
-#    daemon, but Chrome needs be able to get the metadata without talking
-#    to the IBus daemon. This requirement comes from the fact that the
-#    IBus daemon should not run if the user is just using keyboard layouts
-#    such as US keyboard. The metadata generation is done using a python
-#    script at build time of Chrome. See crosbug.com/16961 for details.
-#
-# The order of the list is important. In Chrome's "Languages and input" options
-# page, we list input methods in this order, when more than one input methods
-# are available for a language (ex. French).
+# The list of keyboard layouts that we support. The keyboard layout metadata is
+# also defined here.
 #
 # Each non-comment line contains the following tab-separated columns.
 #
@@ -37,8 +15,7 @@
 #    three-letter ones (ISO 639-2/T and 639-2/B) here. For "en", "pt", and "zh",
 #    two-letter upper-case country code should be added (ex. "en-US", "zh-TW").
 #    See http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes for details.
-# 4) [optional] The #if condition for the input method.
-#    (ex. "defined(A)", "!defined(A)||defined(B)")
+#    We can specify multiple language code with comma separator.
 #
 # Notes:
 #   When adding a line to this list, please also add a mapping from the input
@@ -67,8 +44,8 @@
 #   that information in kHasLatinKeyboardLanguageList[] is still correct.
 
 # U.S. English
-xkb:us::eng	us	en-US
-xkb:us:intl:eng	us(intl)	en-US
+xkb:us::eng	us	en-US,en-AU,id,fil,ms
+xkb:us:intl:eng	us(intl)	en-US,nl,pt-BR
 xkb:us:altgr-intl:eng	us(altgr-intl)	en-US
 xkb:us:dvorak:eng	us(dvorak)	en-US
 xkb:us:colemak:eng	us(colemak)	en-US
@@ -114,7 +91,7 @@
 xkb:dk::dan	dk	da
 xkb:gr::gre	gr	el
 xkb:il::heb	il	he
-xkb:latam::spa	latam	es
+xkb:latam::spa	latam	es,es-419
 xkb:lt::lit	lt	lt
 xkb:lv:apostrophe:lav	lv(apostrophe)	lv
 xkb:hr::scr	hr	hr
diff --git a/chromeos/network/client_cert_resolver.cc b/chromeos/network/client_cert_resolver.cc
new file mode 100644
index 0000000..adbb9de
--- /dev/null
+++ b/chromeos/network/client_cert_resolver.cc
@@ -0,0 +1,450 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/network/client_cert_resolver.h"
+
+#include <cert.h>
+#include <certt.h>  // for (SECCertUsageEnum) certUsageAnyCA
+#include <pk11pub.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/stl_util.h"
+#include "base/task_runner.h"
+#include "base/threading/worker_pool.h"
+#include "base/time/time.h"
+#include "chromeos/cert_loader.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/shill_service_client.h"
+#include "chromeos/network/certificate_pattern.h"
+#include "chromeos/network/client_cert_util.h"
+#include "chromeos/network/managed_network_configuration_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_constants.h"
+#include "dbus/object_path.h"
+#include "net/cert/x509_certificate.h"
+
+namespace chromeos {
+
+// Describes a network |network_path| for which a matching certificate |cert_id|
+// was found.
+struct ClientCertResolver::NetworkAndMatchingCert {
+  NetworkAndMatchingCert(const std::string& network_path,
+                         client_cert::ConfigType config_type,
+                         const std::string& cert_id)
+      : service_path(network_path),
+        cert_config_type(config_type),
+        pkcs11_id(cert_id) {}
+
+  std::string service_path;
+  client_cert::ConfigType cert_config_type;
+  // The id of the matching certificate.
+  std::string pkcs11_id;
+};
+
+typedef std::vector<ClientCertResolver::NetworkAndMatchingCert>
+    NetworkCertMatches;
+
+namespace {
+
+// Returns true if |vector| contains |value|.
+template <class T>
+bool ContainsValue(const std::vector<T>& vector, const T& value) {
+  return find(vector.begin(), vector.end(), value) != vector.end();
+}
+
+// Returns true if a private key for certificate |cert| is installed.
+bool HasPrivateKey(const net::X509Certificate& cert) {
+  PK11SlotInfo* slot = PK11_KeyForCertExists(cert.os_cert_handle(), NULL, NULL);
+  if (!slot)
+    return false;
+
+  PK11_FreeSlot(slot);
+  return true;
+}
+
+// Describes a certificate which is issued by |issuer| (encoded as PEM).
+struct CertAndIssuer {
+  CertAndIssuer(const scoped_refptr<net::X509Certificate>& certificate,
+                const std::string& issuer)
+      : cert(certificate),
+        pem_encoded_issuer(issuer) {}
+
+  scoped_refptr<net::X509Certificate> cert;
+  std::string pem_encoded_issuer;
+};
+
+bool CompareCertExpiration(const CertAndIssuer& a,
+                           const CertAndIssuer& b) {
+  return (a.cert->valid_expiry() < b.cert->valid_expiry());
+}
+
+// Describes a network that is configured with the certificate pattern
+// |client_cert_pattern|.
+struct NetworkAndCertPattern {
+  NetworkAndCertPattern(const std::string& network_path,
+                        client_cert::ConfigType config_type,
+                        const CertificatePattern& pattern)
+      : service_path(network_path),
+        cert_config_type(config_type),
+        client_cert_pattern(pattern) {}
+  std::string service_path;
+  client_cert::ConfigType cert_config_type;
+  CertificatePattern client_cert_pattern;
+};
+
+// A unary predicate that returns true if the given CertAndIssuer matches the
+// certificate pattern of the NetworkAndCertPattern.
+struct MatchCertWithPattern {
+  MatchCertWithPattern(const NetworkAndCertPattern& pattern)
+      : net_and_pattern(pattern) {}
+
+  bool operator()(const CertAndIssuer& cert_and_issuer) {
+    const CertificatePattern& pattern = net_and_pattern.client_cert_pattern;
+    if (!pattern.issuer().Empty() &&
+        !client_cert::CertPrincipalMatches(pattern.issuer(),
+                                           cert_and_issuer.cert->issuer())) {
+      return false;
+    }
+    if (!pattern.subject().Empty() &&
+        !client_cert::CertPrincipalMatches(pattern.subject(),
+                                           cert_and_issuer.cert->subject())) {
+      return false;
+    }
+
+    const std::vector<std::string>& issuer_ca_pems = pattern.issuer_ca_pems();
+    if (!issuer_ca_pems.empty() &&
+        !ContainsValue(issuer_ca_pems, cert_and_issuer.pem_encoded_issuer)) {
+      return false;
+    }
+    return true;
+  }
+
+  NetworkAndCertPattern net_and_pattern;
+};
+
+// Searches for matches between |networks| and |certs| and writes matches to
+// |matches|. Because this calls NSS functions and is potentially slow, it must
+// be run on a worker thread.
+void FindCertificateMatches(const net::CertificateList& certs,
+                            std::vector<NetworkAndCertPattern>* networks,
+                            NetworkCertMatches* matches) {
+  // Filter all client certs and determines each certificate's issuer, which is
+  // required for the pattern matching.
+  std::vector<CertAndIssuer> client_certs;
+  for (net::CertificateList::const_iterator it = certs.begin();
+       it != certs.end(); ++it) {
+    const net::X509Certificate& cert = **it;
+    if (cert.valid_expiry().is_null() || cert.HasExpired() ||
+        !HasPrivateKey(cert)) {
+      continue;
+    }
+    scoped_refptr<net::X509Certificate> issuer =
+        net::X509Certificate::CreateFromHandle(
+            CERT_FindCertIssuer(
+                cert.os_cert_handle(), PR_Now(), certUsageAnyCA),
+            net::X509Certificate::OSCertHandles());
+    if (!issuer) {
+      LOG(ERROR) << "Couldn't find cert issuer.";
+      continue;
+    }
+    std::string pem_encoded_issuer;
+    if (!net::X509Certificate::GetPEMEncoded(issuer->os_cert_handle(),
+                                             &pem_encoded_issuer)) {
+      LOG(ERROR) << "Couldn't PEM-encode certificate.";
+      continue;
+    }
+    client_certs.push_back(CertAndIssuer(*it, pem_encoded_issuer));
+  }
+
+  std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration);
+
+  for (std::vector<NetworkAndCertPattern>::const_iterator it =
+           networks->begin();
+       it != networks->end(); ++it) {
+    std::vector<CertAndIssuer>::iterator cert_it = std::find_if(
+        client_certs.begin(), client_certs.end(), MatchCertWithPattern(*it));
+    if (cert_it == client_certs.end()) {
+      LOG(WARNING) << "Couldn't find a matching client cert for network "
+                   << it->service_path;
+      continue;
+    }
+    std::string pkcs11_id = CertLoader::GetPkcs11IdForCert(*cert_it->cert);
+    if (pkcs11_id.empty()) {
+      LOG(ERROR) << "Couldn't determine PKCS#11 ID.";
+      continue;
+    }
+    matches->push_back(ClientCertResolver::NetworkAndMatchingCert(
+        it->service_path, it->cert_config_type, pkcs11_id));
+  }
+}
+
+// Determines the type of the CertificatePattern configuration, i.e. is it a
+// pattern within an EAP, IPsec or OpenVPN configuration.
+client_cert::ConfigType OncToClientCertConfigurationType(
+    const base::DictionaryValue& network_config) {
+  using namespace ::chromeos::onc;
+
+  const base::DictionaryValue* wifi = NULL;
+  network_config.GetDictionaryWithoutPathExpansion(network_config::kWiFi,
+                                                   &wifi);
+  if (wifi) {
+    const base::DictionaryValue* eap = NULL;
+    wifi->GetDictionaryWithoutPathExpansion(wifi::kEAP, &eap);
+    if (!eap)
+      return client_cert::CONFIG_TYPE_NONE;
+    return client_cert::CONFIG_TYPE_EAP;
+  }
+
+  const base::DictionaryValue* vpn = NULL;
+  network_config.GetDictionaryWithoutPathExpansion(network_config::kVPN, &vpn);
+  if (vpn) {
+    const base::DictionaryValue* openvpn = NULL;
+    vpn->GetDictionaryWithoutPathExpansion(vpn::kOpenVPN, &openvpn);
+    if (openvpn)
+      return client_cert::CONFIG_TYPE_OPENVPN;
+
+    const base::DictionaryValue* ipsec = NULL;
+    vpn->GetDictionaryWithoutPathExpansion(vpn::kIPsec, &ipsec);
+    if (ipsec)
+      return client_cert::CONFIG_TYPE_IPSEC;
+
+    return client_cert::CONFIG_TYPE_NONE;
+  }
+
+  const base::DictionaryValue* ethernet = NULL;
+  network_config.GetDictionaryWithoutPathExpansion(network_config::kEthernet,
+                                                   &ethernet);
+  if (ethernet) {
+    const base::DictionaryValue* eap = NULL;
+    ethernet->GetDictionaryWithoutPathExpansion(wifi::kEAP, &eap);
+    if (eap)
+      return client_cert::CONFIG_TYPE_EAP;
+    return client_cert::CONFIG_TYPE_NONE;
+  }
+
+  return client_cert::CONFIG_TYPE_NONE;
+}
+
+void LogError(const std::string& service_path,
+              const std::string& dbus_error_name,
+              const std::string& dbus_error_message) {
+  network_handler::ShillErrorCallbackFunction(
+      "ClientCertResolver.SetProperties failed",
+      service_path,
+      network_handler::ErrorCallback(),
+      dbus_error_name,
+      dbus_error_message);
+}
+
+bool ClientCertificatesLoaded() {
+  if(!CertLoader::Get()->certificates_loaded()) {
+    VLOG(1) << "Certificates not loaded yet.";
+    return false;
+  }
+  if (!CertLoader::Get()->IsHardwareBacked()) {
+    VLOG(1) << "TPM is not available.";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+ClientCertResolver::ClientCertResolver()
+    : network_state_handler_(NULL),
+      managed_network_config_handler_(NULL),
+      weak_ptr_factory_(this) {
+}
+
+ClientCertResolver::~ClientCertResolver() {
+  if (network_state_handler_)
+    network_state_handler_->RemoveObserver(this, FROM_HERE);
+  if (CertLoader::IsInitialized())
+    CertLoader::Get()->RemoveObserver(this);
+  if (managed_network_config_handler_)
+    managed_network_config_handler_->RemoveObserver(this);
+}
+
+void ClientCertResolver::Init(
+    NetworkStateHandler* network_state_handler,
+    ManagedNetworkConfigurationHandler* managed_network_config_handler) {
+  DCHECK(network_state_handler);
+  network_state_handler_ = network_state_handler;
+  network_state_handler_->AddObserver(this, FROM_HERE);
+
+  DCHECK(managed_network_config_handler);
+  managed_network_config_handler_ = managed_network_config_handler;
+  managed_network_config_handler_->AddObserver(this);
+
+  CertLoader::Get()->AddObserver(this);
+}
+
+void ClientCertResolver::SetSlowTaskRunnerForTest(
+    const scoped_refptr<base::TaskRunner>& task_runner) {
+  slow_task_runner_for_test_ = task_runner;
+}
+
+void ClientCertResolver::NetworkListChanged() {
+  VLOG(2) << "NetworkListChanged.";
+  if (!ClientCertificatesLoaded())
+    return;
+  // Configure only networks that were not configured before.
+
+  // We'll drop networks from |resolved_networks_|, which are not known anymore.
+  std::set<std::string> old_resolved_networks;
+  old_resolved_networks.swap(resolved_networks_);
+
+  NetworkStateList networks;
+  network_state_handler_->GetNetworkList(&networks);
+
+  NetworkStateList networks_to_check;
+  for (NetworkStateList::const_iterator it = networks.begin();
+       it != networks.end(); ++it) {
+    // If this network is not managed, it cannot have a ClientCertPattern.
+    // We do this check here additionally to ResolveNetworks because it's cheap
+    // and prevents |resolved_networks_| from becoming too large.
+    if ((*it)->guid().empty())
+      continue;
+
+    const std::string& service_path = (*it)->path();
+    if (ContainsKey(old_resolved_networks, service_path)) {
+      resolved_networks_.insert(service_path);
+      continue;
+    }
+    networks_to_check.push_back(*it);
+  }
+
+  ResolveNetworks(networks_to_check);
+}
+
+void ClientCertResolver::OnCertificatesLoaded(
+    const net::CertificateList& cert_list,
+    bool initial_load) {
+  VLOG(2) << "OnCertificatesLoaded.";
+  if (!ClientCertificatesLoaded())
+    return;
+  // Compare all networks with all certificates.
+  NetworkStateList networks;
+  network_state_handler_->GetNetworkList(&networks);
+  ResolveNetworks(networks);
+}
+
+void ClientCertResolver::PolicyApplied(const std::string& service_path) {
+  VLOG(2) << "PolicyApplied " << service_path;
+  if (!ClientCertificatesLoaded())
+    return;
+  // Compare this network with all certificates.
+  const NetworkState* network =
+      network_state_handler_->GetNetworkState(service_path);
+  if (!network) {
+    LOG(ERROR) << "service path '" << service_path << "' unknown.";
+    return;
+  }
+  NetworkStateList networks;
+  networks.push_back(network);
+  ResolveNetworks(networks);
+}
+
+void ClientCertResolver::ResolveNetworks(
+    const NetworkStateList& networks) {
+  scoped_ptr<std::vector<NetworkAndCertPattern> > networks_with_pattern(
+      new std::vector<NetworkAndCertPattern>);
+
+  // Filter networks with ClientCertPattern. As ClientCertPatterns can only be
+  // set by policy, we check there.
+  for (NetworkStateList::const_iterator it = networks.begin();
+       it != networks.end(); ++it) {
+    const NetworkState* network = *it;
+
+    // In any case, don't check this network again in NetworkListChanged.
+    resolved_networks_.insert(network->path());
+
+    // If this network is not managed, it cannot have a ClientCertPattern.
+    if (network->guid().empty())
+      continue;
+
+    if (network->profile_path().empty()) {
+      LOG(ERROR) << "Network " << network->path()
+                 << " has a GUID but not profile path";
+      continue;
+    }
+    const base::DictionaryValue* policy =
+        managed_network_config_handler_->FindPolicyByGuidAndProfile(
+            network->guid(), network->profile_path());
+
+    if (!policy) {
+      VLOG(1) << "The policy for network " << network->path() << " with GUID "
+              << network->guid() << " is not available yet.";
+      // Skip this network for now. Once the policy is loaded, PolicyApplied()
+      // will retry.
+      continue;
+    }
+
+    VLOG(2) << "Inspecting network " << network->path();
+    // TODO(pneubeck): Access the ClientCertPattern without relying on
+    //   NetworkUIData, which also parses other things that we don't need here.
+    // The ONCSource is irrelevant here.
+    scoped_ptr<NetworkUIData> ui_data(
+        NetworkUIData::CreateFromONC(onc::ONC_SOURCE_NONE, *policy));
+
+    // Skip networks that don't have a ClientCertPattern.
+    if (ui_data->certificate_type() != CLIENT_CERT_TYPE_PATTERN)
+      continue;
+
+    client_cert::ConfigType config_type =
+        OncToClientCertConfigurationType(*policy);
+    if (config_type == client_cert::CONFIG_TYPE_NONE) {
+      LOG(ERROR) << "UIData contains a CertificatePattern, but the policy "
+                 << "doesn't. Network: " << network->path();
+      continue;
+    }
+
+    networks_with_pattern->push_back(NetworkAndCertPattern(
+        network->path(), config_type, ui_data->certificate_pattern()));
+  }
+  if (networks_with_pattern->empty())
+    return;
+
+  VLOG(2) << "Start task for resolving client cert patterns.";
+  base::TaskRunner* task_runner = slow_task_runner_for_test_.get();
+  if (!task_runner)
+    task_runner = base::WorkerPool::GetTaskRunner(true /* task is slow */);
+
+  NetworkCertMatches* matches = new NetworkCertMatches;
+  task_runner->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&FindCertificateMatches,
+                 CertLoader::Get()->cert_list(),
+                 base::Owned(networks_with_pattern.release()),
+                 matches),
+      base::Bind(&ClientCertResolver::ConfigureCertificates,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 base::Owned(matches)));
+}
+
+void ClientCertResolver::ConfigureCertificates(NetworkCertMatches* matches) {
+  for (NetworkCertMatches::const_iterator it = matches->begin();
+       it != matches->end(); ++it) {
+    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);
+    DBusThreadManager::Get()->GetShillServiceClient()->
+        SetProperties(dbus::ObjectPath(it->service_path),
+                        shill_properties,
+                        base::Bind(&base::DoNothing),
+                        base::Bind(&LogError, it->service_path));
+    network_state_handler_->RequestUpdateForNetwork(it->service_path);
+  }
+}
+
+}  // namespace chromeos
diff --git a/chromeos/network/client_cert_resolver.h b/chromeos/network/client_cert_resolver.h
new file mode 100644
index 0000000..a1be963
--- /dev/null
+++ b/chromeos/network/client_cert_resolver.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 CHROMEOS_NETWORK_CLIENT_CERT_RESOLVER_H_
+#define CHROMEOS_NETWORK_CLIENT_CERT_RESOLVER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/cert_loader.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/network/network_policy_observer.h"
+#include "chromeos/network/network_state_handler_observer.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace chromeos {
+
+class NetworkState;
+class NetworkStateHandler;
+class ManagedNetworkConfigurationHandler;
+
+// Observes the known networks. If a network is configured with a client
+// certificate pattern, this class searches for a matching client certificate.
+// Each time it finds a match, it configures the network accordingly.
+class CHROMEOS_EXPORT ClientCertResolver : public NetworkStateHandlerObserver,
+                                           public CertLoader::Observer,
+                                           public NetworkPolicyObserver {
+ public:
+  struct NetworkAndMatchingCert;
+
+  ClientCertResolver();
+  virtual ~ClientCertResolver();
+
+  void Init(NetworkStateHandler* network_state_handler,
+            ManagedNetworkConfigurationHandler* managed_network_config_handler);
+
+  // Sets the task runner that any slow calls will be made from, e.g. calls
+  // to the NSS database. If not set, uses base::WorkerPool.
+  void SetSlowTaskRunnerForTest(
+      const scoped_refptr<base::TaskRunner>& task_runner);
+
+ private:
+  typedef std::vector<const NetworkState*> NetworkStateList;
+
+   // NetworkStateHandlerObserver overrides
+  virtual void NetworkListChanged() OVERRIDE;
+
+  // CertLoader::Observer overrides
+  virtual void OnCertificatesLoaded(const net::CertificateList& cert_list,
+                                    bool initial_load) OVERRIDE;
+
+  // NetworkPolicyObserver overrides
+  virtual void PolicyApplied(const std::string& service_path) OVERRIDE;
+
+  // Check which networks of |networks| are configured with a client certificate
+  // pattern. Search for certificates, on the worker thread, and configure the
+  // networks for which a matching cert is found (see ConfigureCertificates).
+  void ResolveNetworks(const NetworkStateList& networks);
+
+  // |matches| contains networks for which a matching certificate was found.
+  // Configures these networks.
+  void ConfigureCertificates(std::vector<NetworkAndMatchingCert>* matches);
+
+  // The set of networks that were checked/resolved in previous passes. These
+  // networks are skipped in the NetworkListChanged notification.
+  std::set<std::string> resolved_networks_;
+
+  // Unowned associated (global or test) instance.
+  NetworkStateHandler* network_state_handler_;
+
+  // Unowned associated (global or test) instance.
+  ManagedNetworkConfigurationHandler* managed_network_config_handler_;
+
+  // TaskRunner for slow tasks.
+  scoped_refptr<base::TaskRunner> slow_task_runner_for_test_;
+
+  base::WeakPtrFactory<ClientCertResolver> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClientCertResolver);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_NETWORK_CLIENT_CERT_RESOLVER_H_
diff --git a/chromeos/network/client_cert_resolver_unittest.cc b/chromeos/network/client_cert_resolver_unittest.cc
new file mode 100644
index 0000000..12ee8e6
--- /dev/null
+++ b/chromeos/network/client_cert_resolver_unittest.cc
@@ -0,0 +1,281 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include "chromeos/network/client_cert_resolver.h"
+
+#include <cert.h>
+#include <pk11pub.h>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/shill_profile_client.h"
+#include "chromeos/dbus/shill_service_client.h"
+#include "chromeos/login/login_state.h"
+#include "chromeos/network/managed_network_configuration_handler_impl.h"
+#include "chromeos/network/network_configuration_handler.h"
+#include "chromeos/network/network_profile_handler.h"
+#include "chromeos/network/network_state_handler.h"
+#include "crypto/nss_util.h"
+#include "net/base/crypto_module.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_data_directory.h"
+#include "net/cert/nss_cert_database.h"
+#include "net/cert/x509_certificate.h"
+#include "net/test/cert_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+namespace {
+
+const char* kWifiStub = "wifi_stub";
+const char* kWifiSSID = "wifi_ssid";
+const char* kUserProfilePath = "user_profile";
+const char* kUserHash = "user_hash";
+
+}  // namespace
+
+class ClientCertResolverTest : public testing::Test {
+ public:
+  ClientCertResolverTest() {}
+  virtual ~ClientCertResolverTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(test_nssdb_.is_open());
+    slot_ = net::NSSCertDatabase::GetInstance()->GetPublicModule();
+    ASSERT_TRUE(slot_->os_module_handle());
+
+    LoginState::Initialize();
+
+    DBusThreadManager::InitializeWithStub();
+    service_test_ =
+        DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
+    profile_test_ =
+        DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
+    message_loop_.RunUntilIdle();
+    service_test_->ClearServices();
+    message_loop_.RunUntilIdle();
+
+    CertLoader::Initialize();
+    CertLoader* cert_loader = CertLoader::Get();
+    cert_loader->InitializeTPMForTest();
+    cert_loader->SetSlowTaskRunnerForTest(message_loop_.message_loop_proxy());
+    cert_loader->SetCryptoTaskRunner(message_loop_.message_loop_proxy());
+  }
+
+  virtual void TearDown() OVERRIDE {
+    client_cert_resolver_.reset();
+    managed_config_handler_.reset();
+    network_config_handler_.reset();
+    network_profile_handler_.reset();
+    network_state_handler_.reset();
+    CertLoader::Shutdown();
+    DBusThreadManager::Shutdown();
+    LoginState::Shutdown();
+    CleanupSlotContents();
+  }
+
+ protected:
+  // Imports a CA cert (stored as PEM in test_ca_cert_pem_) and a client
+  // certificate signed by that CA. Its PKCS#11 ID is stored in
+  // |test_pkcs11_id_|.
+  void SetupTestCerts() {
+    // Import a CA cert.
+    net::NSSCertDatabase* cert_db = net::NSSCertDatabase::GetInstance();
+    net::CertificateList ca_cert_list =
+        net::CreateCertificateListFromFile(net::GetTestCertsDirectory(),
+                                           "websocket_cacert.pem",
+                                           net::X509Certificate::FORMAT_AUTO);
+    ASSERT_TRUE(!ca_cert_list.empty());
+    net::NSSCertDatabase::ImportCertFailureList failures;
+    EXPECT_TRUE(cert_db->ImportCACerts(
+        ca_cert_list, net::NSSCertDatabase::TRUST_DEFAULT, &failures));
+    ASSERT_TRUE(failures.empty()) << net::ErrorToString(failures[0].net_error);
+
+    net::X509Certificate::GetPEMEncoded(ca_cert_list[0]->os_cert_handle(),
+                                        &test_ca_cert_pem_);
+    ASSERT_TRUE(!test_ca_cert_pem_.empty());
+
+    // Import a client cert signed by that CA.
+    scoped_refptr<net::CryptoModule> crypt_module = cert_db->GetPrivateModule();
+    std::string pkcs12_data;
+    ASSERT_TRUE(file_util::ReadFileToString(
+        net::GetTestCertsDirectory().Append("websocket_client_cert.p12"),
+        &pkcs12_data));
+
+    net::CertificateList client_cert_list;
+    ASSERT_EQ(net::OK,
+              cert_db->ImportFromPKCS12(crypt_module.get(),
+                                        pkcs12_data,
+                                        string16(),
+                                        false,
+                                        &client_cert_list));
+    ASSERT_TRUE(!client_cert_list.empty());
+    test_pkcs11_id_ = CertLoader::GetPkcs11IdForCert(*client_cert_list[0]);
+    ASSERT_TRUE(!test_pkcs11_id_.empty());
+  }
+
+  void SetupNetworkHandlers() {
+    network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
+    network_profile_handler_.reset(new NetworkProfileHandler());
+    network_config_handler_.reset(new NetworkConfigurationHandler());
+    managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
+    client_cert_resolver_.reset(new ClientCertResolver());
+
+    network_profile_handler_->Init(network_state_handler_.get());
+    network_config_handler_->Init(network_state_handler_.get());
+    managed_config_handler_->Init(network_state_handler_.get(),
+                                  network_profile_handler_.get(),
+                                  network_config_handler_.get());
+    client_cert_resolver_->Init(network_state_handler_.get(),
+                                managed_config_handler_.get());
+    client_cert_resolver_->SetSlowTaskRunnerForTest(
+        message_loop_.message_loop_proxy());
+
+    profile_test_->AddProfile(kUserProfilePath, kUserHash);
+  }
+
+  void SetupWifi() {
+    const bool add_to_visible = true;
+    const bool add_to_watchlist = true;
+    service_test_->AddService(kWifiStub,
+                              kWifiSSID,
+                              flimflam::kTypeWifi,
+                              flimflam::kStateOnline,
+                              add_to_visible,
+                              add_to_watchlist);
+    service_test_->SetServiceProperty(
+        kWifiStub, flimflam::kGuidProperty, base::StringValue(kWifiStub));
+
+    profile_test_->AddService(kUserProfilePath, kWifiStub);
+  }
+
+  // Setup a policy with a certificate pattern that matches any client cert that
+  // is signed by the test CA cert (stored in |test_ca_cert_pem_|). In
+  // particular it will match the test client cert.
+  void SetupPolicy() {
+    const char* kTestPolicyTemplate =
+        "[ { \"GUID\": \"wifi_stub\","
+        "    \"Name\": \"wifi_stub\","
+        "    \"Type\": \"WiFi\","
+        "    \"WiFi\": {"
+        "      \"Security\": \"WPA-EAP\","
+        "      \"SSID\": \"wifi_ssid\","
+        "      \"EAP\": {"
+        "        \"Outer\": \"EAP-TLS\","
+        "        \"ClientCertType\": \"Pattern\","
+        "        \"ClientCertPattern\": {"
+        "          \"IssuerCAPEMs\": [ \"%s\" ]"
+        "        }"
+        "      }"
+        "    }"
+        "} ]";
+    std::string policy_json =
+        base::StringPrintf(kTestPolicyTemplate, test_ca_cert_pem_.c_str());
+
+    std::string error;
+    scoped_ptr<base::Value> policy_value(base::JSONReader::ReadAndReturnError(
+        policy_json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error));
+    ASSERT_TRUE(policy_value) << error;
+
+    base::ListValue* policy = NULL;
+    ASSERT_TRUE(policy_value->GetAsList(&policy));
+
+    managed_config_handler_->SetPolicy(
+        onc::ONC_SOURCE_USER_POLICY, kUserHash, *policy);
+  }
+
+  void GetClientCertProperties(std::string* pkcs11_id) {
+    pkcs11_id->clear();
+    const base::DictionaryValue* properties =
+        service_test_->GetServiceProperties(kWifiStub);
+    if (!properties)
+      return;
+    properties->GetStringWithoutPathExpansion(flimflam::kEapCertIdProperty,
+                                              pkcs11_id);
+  }
+
+  ShillServiceClient::TestInterface* service_test_;
+  ShillProfileClient::TestInterface* profile_test_;
+  std::string test_pkcs11_id_;
+  scoped_refptr<net::X509Certificate> test_ca_cert_;
+  std::string test_ca_cert_pem_;
+  base::MessageLoop message_loop_;
+
+ private:
+  void CleanupSlotContents() {
+    CERTCertList* cert_list = PK11_ListCertsInSlot(slot_->os_module_handle());
+    for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
+         !CERT_LIST_END(node, cert_list);
+         node = CERT_LIST_NEXT(node)) {
+      scoped_refptr<net::X509Certificate> cert(
+          net::X509Certificate::CreateFromHandle(
+              node->cert, net::X509Certificate::OSCertHandles()));
+      net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(cert.get());
+    }
+    CERT_DestroyCertList(cert_list);
+  }
+
+  scoped_ptr<NetworkStateHandler> network_state_handler_;
+  scoped_ptr<NetworkProfileHandler> network_profile_handler_;
+  scoped_ptr<NetworkConfigurationHandler> network_config_handler_;
+  scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_;
+  scoped_ptr<ClientCertResolver> client_cert_resolver_;
+  scoped_refptr<net::CryptoModule> slot_;
+  crypto::ScopedTestNSSDB test_nssdb_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest);
+};
+
+TEST_F(ClientCertResolverTest, NoMatchingCertificates) {
+  SetupNetworkHandlers();
+  SetupPolicy();
+  message_loop_.RunUntilIdle();
+
+  SetupWifi();
+  message_loop_.RunUntilIdle();
+
+  // Verify that no client certificate was configured.
+  std::string pkcs11_id;
+  GetClientCertProperties(&pkcs11_id);
+  EXPECT_TRUE(pkcs11_id.empty());
+}
+
+TEST_F(ClientCertResolverTest, ResolveOnInitialization) {
+  SetupTestCerts();
+  SetupNetworkHandlers();
+  SetupPolicy();
+  message_loop_.RunUntilIdle();
+
+  SetupWifi();
+  message_loop_.RunUntilIdle();
+
+  // Verify that the resolver positively matched the pattern in the policy with
+  // the test client cert and configured the network.
+  std::string pkcs11_id;
+  GetClientCertProperties(&pkcs11_id);
+  EXPECT_EQ(test_pkcs11_id_, pkcs11_id);
+}
+
+TEST_F(ClientCertResolverTest, ResolveAfterPolicyApplication) {
+  SetupTestCerts();
+  SetupNetworkHandlers();
+  message_loop_.RunUntilIdle();
+
+  // The policy will trigger the creation of a new wifi service.
+  SetupPolicy();
+  message_loop_.RunUntilIdle();
+
+  // Verify that the resolver positively matched the pattern in the policy with
+  // the test client cert and configured the network.
+  std::string pkcs11_id;
+  GetClientCertProperties(&pkcs11_id);
+  EXPECT_EQ(test_pkcs11_id_, pkcs11_id);
+}
+
+}  // namespace chromeos
diff --git a/chromeos/network/dhcp_proxy_script_fetcher_chromeos.cc b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.cc
new file mode 100644
index 0000000..55149cd
--- /dev/null
+++ b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.cc
@@ -0,0 +1,88 @@
+// 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/network/dhcp_proxy_script_fetcher_chromeos.h"
+
+#include "base/task_runner_util.h"
+#include "chromeos/network/network_event_log.h"
+#include "chromeos/network/network_handler.h"
+#include "chromeos/network/network_state.h"
+#include "chromeos/network/network_state_handler.h"
+#include "net/proxy/proxy_script_fetcher.h"
+#include "net/proxy/proxy_script_fetcher_impl.h"
+#include "net/url_request/url_request_context.h"
+
+namespace chromeos {
+
+namespace {
+
+// Runs on NetworkHandler::Get()->message_loop().
+std::string GetPacUrlFromDefaultNetwork() {
+  if (!NetworkHandler::IsInitialized())
+    return std::string();
+  const NetworkState* default_network =
+      NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
+  if (default_network)
+    return default_network->web_proxy_auto_discovery_url().spec();
+  return std::string();
+}
+
+}  // namespace
+
+DhcpProxyScriptFetcherChromeos::DhcpProxyScriptFetcherChromeos(
+    net::URLRequestContext* url_request_context)
+    : url_request_context_(url_request_context),
+      weak_ptr_factory_(this) {
+  DCHECK(url_request_context_);
+  proxy_script_fetcher_.reset(
+      new net::ProxyScriptFetcherImpl(url_request_context_));
+  if (NetworkHandler::IsInitialized())
+    network_handler_message_loop_ = NetworkHandler::Get()->message_loop();
+}
+
+DhcpProxyScriptFetcherChromeos::~DhcpProxyScriptFetcherChromeos() {
+}
+
+int DhcpProxyScriptFetcherChromeos::Fetch(
+    base::string16* utf16_text,
+    const net::CompletionCallback& callback) {
+  if (!network_handler_message_loop_.get())
+    return net::ERR_PAC_NOT_IN_DHCP;
+  base::PostTaskAndReplyWithResult(
+      network_handler_message_loop_.get(),
+      FROM_HERE,
+      base::Bind(&GetPacUrlFromDefaultNetwork),
+      base::Bind(&DhcpProxyScriptFetcherChromeos::ContinueFetch,
+                 weak_ptr_factory_.GetWeakPtr(), utf16_text, callback));
+  return net::ERR_IO_PENDING;
+}
+
+void DhcpProxyScriptFetcherChromeos::Cancel() {
+  proxy_script_fetcher_->Cancel();
+}
+
+const GURL& DhcpProxyScriptFetcherChromeos::GetPacURL() const {
+  return pac_url_;
+}
+
+std::string DhcpProxyScriptFetcherChromeos::GetFetcherName() const {
+  return "chromeos";
+}
+
+void DhcpProxyScriptFetcherChromeos::ContinueFetch(
+    base::string16* utf16_text,
+    const net::CompletionCallback& callback,
+    std::string pac_url) {
+  NET_LOG_EVENT("DhcpProxyScriptFetcher", pac_url);
+  pac_url_ = GURL(pac_url);
+  if (pac_url_.is_empty()) {
+    callback.Run(net::ERR_PAC_NOT_IN_DHCP);
+    return;
+  }
+  int res = proxy_script_fetcher_->Fetch(pac_url_, utf16_text, callback);
+  if (res != net::ERR_IO_PENDING)
+    callback.Run(res);
+}
+
+}  // namespace chromeos
diff --git a/chromeos/network/dhcp_proxy_script_fetcher_chromeos.h b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.h
new file mode 100644
index 0000000..bf9c744
--- /dev/null
+++ b/chromeos/network/dhcp_proxy_script_fetcher_chromeos.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 CHROMEOS_NETWORK_DHCP_PROXY_SCRIPT_FETCHER_CHROMEOS_H_
+#define CHROMEOS_NETWORK_DHCP_PROXY_SCRIPT_FETCHER_CHROMEOS_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "chromeos/chromeos_export.h"
+#include "net/proxy/dhcp_proxy_script_fetcher.h"
+#include "url/gurl.h"
+
+namespace net {
+class URLRequestContext;
+class ProxyScriptFetcher;
+}
+
+namespace chromeos {
+
+// ChromeOS specific implementation of DhcpProxyScriptFetcher.
+// This looks up Service.WebProxyAutoDiscoveryUrl for the default network
+// from Shill and uses that to fetch the proxy script if available.
+class CHROMEOS_EXPORT DhcpProxyScriptFetcherChromeos
+    : public net::DhcpProxyScriptFetcher {
+ public:
+  explicit DhcpProxyScriptFetcherChromeos(
+      net::URLRequestContext* url_request_context);
+  virtual ~DhcpProxyScriptFetcherChromeos() OVERRIDE;
+
+  // net::DhcpProxyScriptFetcher
+  virtual int Fetch(base::string16* utf16_text,
+                    const net::CompletionCallback& callback) OVERRIDE;
+  virtual void Cancel() OVERRIDE;
+  virtual const GURL& GetPacURL() const OVERRIDE;
+  virtual std::string GetFetcherName() const OVERRIDE;
+
+ private:
+  void ContinueFetch(base::string16* utf16_text,
+                     const net::CompletionCallback& callback,
+                     std::string pac_url);
+
+  net::URLRequestContext* url_request_context_;  // Weak ptr
+  scoped_ptr<net::ProxyScriptFetcher> proxy_script_fetcher_;
+  scoped_refptr<base::MessageLoopProxy> network_handler_message_loop_;
+  base::WeakPtrFactory<DhcpProxyScriptFetcherChromeos> weak_ptr_factory_;
+
+  GURL pac_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(DhcpProxyScriptFetcherChromeos);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_NETWORK_DHCP_PROXY_SCRIPT_FETCHER_CHROMEOS_H_
diff --git a/chromeos/network/managed_network_configuration_handler.cc b/chromeos/network/managed_network_configuration_handler.cc
index 5ee791f..e517dd9 100644
--- a/chromeos/network/managed_network_configuration_handler.cc
+++ b/chromeos/network/managed_network_configuration_handler.cc
@@ -4,364 +4,22 @@
 
 #include "chromeos/network/managed_network_configuration_handler.h"
 
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/guid.h"
-#include "base/json/json_writer.h"
-#include "base/location.h"
 #include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
 #include "base/values.h"
-#include "chromeos/dbus/dbus_method_call_status.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/shill_manager_client.h"
-#include "chromeos/dbus/shill_profile_client.h"
-#include "chromeos/dbus/shill_service_client.h"
-#include "chromeos/network/network_configuration_handler.h"
-#include "chromeos/network/network_event_log.h"
-#include "chromeos/network/network_handler_callbacks.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_constants.h"
-#include "chromeos/network/onc/onc_merger.h"
-#include "chromeos/network/onc/onc_normalizer.h"
-#include "chromeos/network/onc/onc_signature.h"
-#include "chromeos/network/onc/onc_translator.h"
 #include "chromeos/network/onc/onc_utils.h"
-#include "chromeos/network/onc/onc_validator.h"
-#include "dbus/object_path.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
 
-namespace {
-
-// 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";
-
-// This fake credential contains a random postfix which is extremly unlikely to
-// be used by any user.
-const char kFakeCredential[] = "FAKE_CREDENTIAL_VPaJDV9x";
-
-std::string ToDebugString(onc::ONCSource source,
-                          const std::string& userhash) {
-  return source == onc::ONC_SOURCE_USER_POLICY ?
-      ("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)));
-}
-
-// Sets the UIData property in |shill_dictionary| to the serialization of
-// |ui_data|.
-void SetUIData(const NetworkUIData& ui_data,
-               base::DictionaryValue* shill_dictionary) {
-  base::DictionaryValue ui_data_dict;
-  ui_data.FillDictionary(&ui_data_dict);
-  std::string ui_data_blob;
-  base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
-  shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
-                                                  ui_data_blob);
-}
-
-// A dummy callback to ignore the result of Shill calls.
-void IgnoreString(const std::string& str) {
-}
-
-void LogErrorWithDict(const tracked_objects::Location& from_where,
-                      const std::string& error_name,
-                      scoped_ptr<base::DictionaryValue> error_data) {
-  LOG(ERROR) << from_where.ToString() << ": " << error_name;
-}
-
-void LogErrorMessage(const tracked_objects::Location& from_where,
-                     const std::string& error_name,
-                     const std::string& error_message) {
-  LOG(ERROR) << from_where.ToString() << ": " << error_message;
-}
-
-// Removes all kFakeCredential values from sensitive fields (determined by
-// onc::FieldIsCredential) of |onc_object|.
-void RemoveFakeCredentials(
-    const onc::OncValueSignature& signature,
-    base::DictionaryValue* onc_object) {
-  base::DictionaryValue::Iterator it(*onc_object);
-  while (!it.IsAtEnd()) {
-    base::Value* value = NULL;
-    std::string field_name = it.key();
-    // We need the non-const entry to remove nested values but DictionaryValue
-    // has no non-const iterator.
-    onc_object->GetWithoutPathExpansion(field_name, &value);
-    // Advance before delete.
-    it.Advance();
-
-    // If |value| is a dictionary, recurse.
-    base::DictionaryValue* nested_object = NULL;
-    if (value->GetAsDictionary(&nested_object)) {
-      const onc::OncFieldSignature* field_signature =
-          onc::GetFieldSignature(signature, field_name);
-
-      RemoveFakeCredentials(*field_signature->value_signature,
-                            nested_object);
-      continue;
-    }
-
-    // If |value| is a string, check if it is a fake credential.
-    std::string string_value;
-    if (value->GetAsString(&string_value) &&
-        onc::FieldIsCredential(signature, field_name)) {
-      if (string_value == kFakeCredential) {
-        // The value wasn't modified by the UI, thus we remove the field to keep
-        // the existing value that is stored in Shill.
-        onc_object->RemoveWithoutPathExpansion(field_name, NULL);
-      }
-      // Otherwise, the value is set and modified by the UI, thus we keep that
-      // value to overwrite whatever is stored in Shill.
-    }
-  }
-}
-
-// Creates a Shill property dictionary from the given arguments. The resulting
-// dictionary will be sent to Shill by the caller. Depending on the profile
-// type, |policy| is interpreted as the user or device policy and |settings| as
-// the user or shared settings.
-scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
-    const NetworkProfile& profile,
-    const std::string& guid,
-    const base::DictionaryValue* policy,
-    const base::DictionaryValue* settings) {
-  scoped_ptr<base::DictionaryValue> effective;
-  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
-  if (policy) {
-    if (profile.type() == NetworkProfile::TYPE_SHARED) {
-      effective = onc::MergeSettingsAndPoliciesToEffective(
-          NULL,  // no user policy
-          policy,  // device policy
-          NULL,  // no user settings
-          settings);  // shared settings
-      onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
-    } else if (profile.type() == NetworkProfile::TYPE_USER) {
-      effective = onc::MergeSettingsAndPoliciesToEffective(
-          policy,  // user policy
-          NULL,  // no device policy
-          settings,  // user settings
-          NULL);  // no shared settings
-      onc_source = onc::ONC_SOURCE_USER_POLICY;
-    } else {
-      NOTREACHED();
-    }
-  } else if (settings) {
-    effective.reset(settings->DeepCopy());
-    // TODO(pneubeck): change to source ONC_SOURCE_USER
-    onc_source = onc::ONC_SOURCE_NONE;
-  } else {
-    NOTREACHED();
-    onc_source = onc::ONC_SOURCE_NONE;
-  }
-
-  RemoveFakeCredentials(onc::kNetworkConfigurationSignature,
-                        effective.get());
-
-  effective->SetStringWithoutPathExpansion(onc::network_config::kGUID, guid);
-
-  // Remove irrelevant fields.
-  onc::Normalizer normalizer(true /* remove recommended fields */);
-  effective = normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
-                                         *effective);
-
-  scoped_ptr<base::DictionaryValue> shill_dictionary(
-      onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
-                                     *effective));
-
-  shill_dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
-                                                  profile.path);
-
-  scoped_ptr<NetworkUIData> ui_data;
-  if (policy)
-    ui_data = NetworkUIData::CreateFromONC(onc_source, *policy);
-  else
-    ui_data.reset(new NetworkUIData());
-
-  if (settings) {
-    // Shill doesn't know that sensitive data is contained in the UIData
-    // property and might write it into logs or other insecure places. Thus, we
-    // have to remove or mask credentials.
-    //
-    // Shill's GetProperties doesn't return credentials. Masking credentials
-    // instead of just removing them, allows remembering if a credential is set
-    // or not.
-    scoped_ptr<base::DictionaryValue> sanitized_settings(
-        onc::MaskCredentialsInOncObject(onc::kNetworkConfigurationSignature,
-                                        *settings,
-                                        kFakeCredential));
-    ui_data->set_user_settings(sanitized_settings.Pass());
-  }
-
-  SetUIData(*ui_data, shill_dictionary.get());
-
-  VLOG(2) << "Created Shill properties: " << *shill_dictionary;
-
-  return shill_dictionary.Pass();
-}
-
-// Returns true if |policy| matches |actual_network|, which must be part of a
-// ONC NetworkConfiguration. This should be the only such matching function
-// within Chrome. Shill does such matching in several functions for network
-// identification. For compatibility, we currently should stick to Shill's
-// matching behavior.
-bool IsPolicyMatching(const base::DictionaryValue& policy,
-                      const base::DictionaryValue& actual_network) {
-  std::string policy_type;
-  policy.GetStringWithoutPathExpansion(onc::network_config::kType,
-                                       &policy_type);
-  std::string network_type;
-  actual_network.GetStringWithoutPathExpansion(onc::network_config::kType,
-                                               &network_type);
-  if (policy_type != network_type)
-    return false;
-
-  if (network_type != onc::network_type::kWiFi)
-    return false;
-
-  const base::DictionaryValue* policy_wifi = NULL;
-  policy.GetDictionaryWithoutPathExpansion(onc::network_config::kWiFi,
-                                           &policy_wifi);
-  const base::DictionaryValue* actual_wifi = NULL;
-  actual_network.GetDictionaryWithoutPathExpansion(onc::network_config::kWiFi,
-                                                   &actual_wifi);
-  if (!policy_wifi || !actual_wifi)
-    return false;
-
-  std::string policy_ssid;
-  policy_wifi->GetStringWithoutPathExpansion(onc::wifi::kSSID, &policy_ssid);
-  std::string actual_ssid;
-  actual_wifi->GetStringWithoutPathExpansion(onc::wifi::kSSID, &actual_ssid);
-  return (policy_ssid == actual_ssid);
-}
-
-// Returns the policy from |policies| matching |actual_network|, if any exists.
-// Returns NULL otherwise. |actual_network| must be part of a ONC
-// NetworkConfiguration.
-const base::DictionaryValue* FindMatchingPolicy(
-    const ManagedNetworkConfigurationHandler::GuidToPolicyMap &policies,
-    const base::DictionaryValue& actual_network) {
-  for (ManagedNetworkConfigurationHandler::GuidToPolicyMap::const_iterator it =
-           policies.begin(); it != policies.end(); ++it) {
-    if (IsPolicyMatching(*it->second, actual_network))
-      return it->second;
-  }
-  return NULL;
-}
-
-const base::DictionaryValue* GetByGUID(
-    const ManagedNetworkConfigurationHandler::GuidToPolicyMap &policies,
-    const std::string& guid) {
-  ManagedNetworkConfigurationHandler::GuidToPolicyMap::const_iterator it =
-      policies.find(guid);
-  if (it == policies.end())
-    return NULL;
-  return it->second;
-}
-
-void TranslatePropertiesToOncAndRunCallback(
-    const network_handler::DictionaryResultCallback& callback,
-    const std::string& service_path,
-    const base::DictionaryValue& shill_properties) {
-  scoped_ptr<base::DictionaryValue> onc_network(
-      onc::TranslateShillServiceToONCPart(
-          shill_properties,
-          &onc::kNetworkWithStateSignature));
-  callback.Run(service_path, *onc_network);
-}
-
-}  // namespace
-
-// This class compares (entry point is Run()) |modified_policies| with the
-// existing entries in the provided Shill profile |profile|. It fetches all
-// entries in parallel (GetProfilePropertiesCallback), compares each entry with
-// the current policies (GetEntryCallback) and adds all missing policies
-// (~PolicyApplicator).
-class ManagedNetworkConfigurationHandler::PolicyApplicator
-    : public base::RefCounted<PolicyApplicator> {
- public:
-  typedef ManagedNetworkConfigurationHandler::GuidToPolicyMap GuidToPolicyMap;
-
-  // |modified_policies| must not be NULL and will be empty afterwards.
-  PolicyApplicator(base::WeakPtr<ManagedNetworkConfigurationHandler> handler,
-                   const NetworkProfile& profile,
-                   std::set<std::string>* modified_policies);
-
-  void Run();
-
- private:
-  friend class base::RefCounted<PolicyApplicator>;
-
-  // Called with the properties of the profile |profile_|. Requests the
-  // properties of each entry, which are processed by GetEntryCallback.
-  void GetProfilePropertiesCallback(
-      const base::DictionaryValue& profile_properties);
-
-  // Called with the properties of the profile entry |entry|. Checks whether the
-  // entry was previously managed, whether a current policy applies and then
-  // either updates, deletes or not touches the entry.
-  void GetEntryCallback(const std::string& entry,
-                        const base::DictionaryValue& entry_properties);
-
-  // Sends Shill the command to delete profile entry |entry| from |profile_|.
-  void DeleteEntry(const std::string& entry);
-
-  // Creates new entries for all remaining policies, i.e. for which not matching
-  // entry was found.
-  virtual ~PolicyApplicator();
-
-  std::set<std::string> remaining_policies_;
-  base::WeakPtr<ManagedNetworkConfigurationHandler> handler_;
-  NetworkProfile profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(PolicyApplicator);
-};
+ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() {}
 
 // static
 scoped_ptr<NetworkUIData> ManagedNetworkConfigurationHandler::GetUIData(
     const base::DictionaryValue& shill_dictionary) {
   std::string ui_data_blob;
-  if (shill_dictionary.GetStringWithoutPathExpansion(
-          flimflam::kUIDataProperty,
-          &ui_data_blob) &&
+  if (shill_dictionary.GetStringWithoutPathExpansion(flimflam::kUIDataProperty,
+                                                     &ui_data_blob) &&
       !ui_data_blob.empty()) {
     scoped_ptr<base::DictionaryValue> ui_data_dict =
         onc::ReadDictionaryFromJson(ui_data_blob);
@@ -374,624 +32,4 @@
   return scoped_ptr<NetworkUIData>();
 }
 
-void ManagedNetworkConfigurationHandler::GetManagedProperties(
-    const std::string& userhash,
-    const std::string& service_path,
-    const network_handler::DictionaryResultCallback& callback,
-    const network_handler::ErrorCallback& error_callback) {
-  if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
-    RunErrorCallback(service_path,
-                     kPoliciesNotInitialized,
-                     kPoliciesNotInitializedMessage,
-                     error_callback);
-    return;
-  }
-  network_configuration_handler_->GetProperties(
-      service_path,
-      base::Bind(
-          &ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback,
-          weak_ptr_factory_.GetWeakPtr(),
-          callback,
-          error_callback),
-      error_callback);
-}
-
-void ManagedNetworkConfigurationHandler::GetManagedPropertiesCallback(
-    const network_handler::DictionaryResultCallback& callback,
-    const network_handler::ErrorCallback& error_callback,
-    const std::string& service_path,
-    const base::DictionaryValue& shill_properties) {
-  std::string profile_path;
-  shill_properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty,
-                                                 &profile_path);
-  LOG(ERROR) << "Profile: " << profile_path;
-  const NetworkProfile* profile =
-      network_profile_handler_->GetProfileForPath(profile_path);
-  if (!profile) {
-    LOG(ERROR) << "No or no known profile received for service "
-            << service_path << ".";
-  }
-
-  scoped_ptr<NetworkUIData> ui_data = GetUIData(shill_properties);
-
-  const base::DictionaryValue* user_settings = NULL;
-  const base::DictionaryValue* shared_settings = NULL;
-
-  if (ui_data && profile) {
-    if (profile->type() == NetworkProfile::TYPE_SHARED)
-      shared_settings = ui_data->user_settings();
-    else if (profile->type() == NetworkProfile::TYPE_USER)
-      user_settings = ui_data->user_settings();
-    else
-      NOTREACHED();
-  } else if (profile) {
-    LOG(WARNING) << "Service " << service_path << " of profile "
-                 << profile_path << " contains no or no valid UIData.";
-    // TODO(pneubeck): add a conversion of user configured entries of old
-    // ChromeOS versions. We will have to use a heuristic to determine which
-    // properties _might_ be user configured.
-  }
-
-  scoped_ptr<base::DictionaryValue> active_settings(
-      onc::TranslateShillServiceToONCPart(
-          shill_properties,
-          &onc::kNetworkWithStateSignature));
-
-  std::string guid;
-  active_settings->GetStringWithoutPathExpansion(onc::network_config::kGUID,
-                                                 &guid);
-
-  const base::DictionaryValue* user_policy = NULL;
-  const base::DictionaryValue* device_policy = NULL;
-  if (!guid.empty() && profile) {
-    const GuidToPolicyMap* policies = GetPoliciesForProfile(*profile);
-    if (!policies) {
-      RunErrorCallback(service_path,
-                       kPoliciesNotInitialized,
-                       kPoliciesNotInitializedMessage,
-                       error_callback);
-      return;
-    }
-    const base::DictionaryValue* policy = GetByGUID(*policies, guid);
-    if (profile->type() == NetworkProfile::TYPE_SHARED)
-      device_policy = policy;
-    else if (profile->type() == NetworkProfile::TYPE_USER)
-      user_policy = policy;
-    else
-      NOTREACHED();
-  }
-
-  // This call also removes credentials from policies.
-  scoped_ptr<base::DictionaryValue> augmented_properties =
-      onc::MergeSettingsAndPoliciesToAugmented(
-          onc::kNetworkConfigurationSignature,
-          user_policy,
-          device_policy,
-          user_settings,
-          shared_settings,
-          active_settings.get());
-  callback.Run(service_path, *augmented_properties);
-}
-
-void ManagedNetworkConfigurationHandler::GetProperties(
-    const std::string& service_path,
-    const network_handler::DictionaryResultCallback& callback,
-    const network_handler::ErrorCallback& error_callback) const {
-  network_configuration_handler_->GetProperties(
-      service_path,
-      base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
-      error_callback);
-}
-
-void ManagedNetworkConfigurationHandler::SetProperties(
-    const std::string& service_path,
-    const base::DictionaryValue& user_settings,
-    const base::Closure& callback,
-    const network_handler::ErrorCallback& error_callback) const {
-  const NetworkState* state =
-      network_state_handler_->GetNetworkState(service_path);
-
-  if (!state) {
-    RunErrorCallback(service_path,
-                     kUnknownServicePath,
-                     kUnknownServicePathMessage,
-                     error_callback);
-    return;
-  }
-
-  std::string guid = state->guid();
-  if (guid.empty()) {
-    // 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);
-    return;
-  }
-
-  const std::string& profile_path = state->profile_path();
-  const NetworkProfile *profile =
-      network_profile_handler_->GetProfileForPath(profile_path);
-  if (!profile) {
-    RunErrorCallback(service_path,
-                     kUnknownProfilePath,
-                     kUnknownProfilePathMessage,
-                     error_callback);
-    return;
-  }
-
-  VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
-          << profile->ToDebugString();
-
-  const GuidToPolicyMap* policies = GetPoliciesForProfile(*profile);
-  if (!policies) {
-    RunErrorCallback(service_path,
-                     kPoliciesNotInitialized,
-                     kPoliciesNotInitializedMessage,
-                     error_callback);
-    return;
-  }
-
-  // Validate the ONC dictionary. We are liberal and ignore unknown field
-  // names. User settings are only partial ONC, thus we ignore missing fields.
-  onc::Validator validator(false,  // Ignore unknown fields.
-                           false,  // Ignore invalid recommended field names.
-                           false,  // Ignore missing fields.
-                           false);  // This ONC does not come from policy.
-
-  onc::Validator::Result validation_result;
-  scoped_ptr<base::DictionaryValue> validated_user_settings =
-      validator.ValidateAndRepairObject(
-          &onc::kNetworkConfigurationSignature,
-          user_settings,
-          &validation_result);
-
-  if (validation_result == onc::Validator::INVALID) {
-    RunErrorCallback(service_path,
-                     kInvalidUserSettings,
-                     kInvalidUserSettingsMessage,
-                     error_callback);
-    return;
-  }
-  if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
-    LOG(WARNING) << "Validation of ONC user settings produced warnings.";
-
-  const base::DictionaryValue* policy = GetByGUID(*policies, guid);
-  VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
-
-  scoped_ptr<base::DictionaryValue> shill_dictionary(CreateShillConfiguration(
-      *profile, guid, policy, validated_user_settings.get()));
-
-  network_configuration_handler_->SetProperties(
-      service_path, *shill_dictionary, callback, error_callback);
-}
-
-void ManagedNetworkConfigurationHandler::CreateConfiguration(
-    const std::string& userhash,
-    const base::DictionaryValue& properties,
-    const network_handler::StringResultCallback& callback,
-    const network_handler::ErrorCallback& error_callback) const {
-  const GuidToPolicyMap* policies = GetPoliciesForUser(userhash);
-  if (!policies) {
-    RunErrorCallback("",
-                     kPoliciesNotInitialized,
-                     kPoliciesNotInitializedMessage,
-                     error_callback);
-    return;
-  }
-
-  if (FindMatchingPolicy(*policies, properties)) {
-    RunErrorCallback("",
-                     kNetworkAlreadyConfigured,
-                     kNetworkAlreadyConfiguredMessage,
-                     error_callback);
-  }
-
-  const NetworkProfile* profile =
-      network_profile_handler_->GetProfileForUserhash(userhash);
-  if (!profile) {
-    RunErrorCallback("",
-                     kProfileNotInitialized,
-                     kProfileNotInitializedMessage,
-                     error_callback);
-  }
-
-  // TODO(pneubeck): In case of WiFi, check that no other configuration for the
-  // same {SSID, mode, security} exists. We don't support such multiple
-  // configurations, yet.
-
-  // Generate a new GUID for this configuration. Ignore the maybe provided GUID
-  // in |properties| as it is not our own and from an untrusted source.
-  std::string guid = base::GenerateGUID();
-  scoped_ptr<base::DictionaryValue> shill_dictionary(
-      CreateShillConfiguration(*profile, guid, NULL /*no policy*/,
-                               &properties));
-
-  network_configuration_handler_->CreateConfiguration(
-      *shill_dictionary, callback, error_callback);
-}
-
-void ManagedNetworkConfigurationHandler::RemoveConfiguration(
-    const std::string& service_path,
-    const base::Closure& callback,
-    const network_handler::ErrorCallback& error_callback) const {
-  network_configuration_handler_->RemoveConfiguration(
-      service_path, callback, error_callback);
-}
-
-void ManagedNetworkConfigurationHandler::SetPolicy(
-    onc::ONCSource onc_source,
-    const std::string& userhash,
-    const base::ListValue& network_configs_onc) {
-  VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
-          << ".";
-
-  // |userhash| must be empty for device policies.
-  DCHECK(onc_source != chromeos::onc::ONC_SOURCE_DEVICE_POLICY ||
-         userhash.empty());
-  GuidToPolicyMap& policies = policies_by_user_[userhash];
-
-  GuidToPolicyMap old_policies;
-  policies.swap(old_policies);
-
-  // This stores all GUIDs of policies that have changed or are new.
-  std::set<std::string> modified_policies;
-
-  for (base::ListValue::const_iterator it = network_configs_onc.begin();
-       it != network_configs_onc.end(); ++it) {
-    const base::DictionaryValue* network = NULL;
-    (*it)->GetAsDictionary(&network);
-    DCHECK(network);
-
-    std::string guid;
-    network->GetStringWithoutPathExpansion(onc::network_config::kGUID, &guid);
-    DCHECK(!guid.empty());
-
-    if (policies.count(guid) > 0) {
-      LOG(ERROR) << "ONC from " << ToDebugString(onc_source, userhash)
-                 << " contains several entries for the same GUID "
-                 << guid << ".";
-      delete policies[guid];
-    }
-    const base::DictionaryValue* new_entry = network->DeepCopy();
-    policies[guid] = new_entry;
-
-    const base::DictionaryValue* old_entry = old_policies[guid];
-    if (!old_entry || !old_entry->Equals(new_entry))
-      modified_policies.insert(guid);
-  }
-
-  STLDeleteValues(&old_policies);
-
-  const NetworkProfile* profile =
-      network_profile_handler_->GetProfileForUserhash(userhash);
-  if (!profile) {
-    VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
-            << "policy application.";
-    return;
-  }
-
-  scoped_refptr<PolicyApplicator> applicator = new PolicyApplicator(
-      weak_ptr_factory_.GetWeakPtr(),
-      *profile,
-      &modified_policies);
-  applicator->Run();
-}
-
-void ManagedNetworkConfigurationHandler::OnProfileAdded(
-    const NetworkProfile& profile) {
-  VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
-
-  const GuidToPolicyMap* policies = GetPoliciesForProfile(profile);
-  if (!policies) {
-    VLOG(1) << "The relevant policy is not initialized, "
-            << "postponing policy application.";
-    return;
-  }
-
-  std::set<std::string> policy_guids;
-  for (GuidToPolicyMap::const_iterator it = policies->begin();
-       it != policies->end(); ++it) {
-    policy_guids.insert(it->first);
-  }
-
-  scoped_refptr<PolicyApplicator> applicator = new PolicyApplicator(
-      weak_ptr_factory_.GetWeakPtr(),
-      profile,
-      &policy_guids);
-  applicator->Run();
-}
-
-const base::DictionaryValue*
-ManagedNetworkConfigurationHandler::FindPolicyByGUID(
-    const std::string userhash,
-    const std::string& guid,
-    onc::ONCSource* onc_source) const {
-  *onc_source = onc::ONC_SOURCE_NONE;
-
-  if (!userhash.empty()) {
-    const GuidToPolicyMap* user_policies = GetPoliciesForUser(userhash);
-    if (user_policies) {
-      GuidToPolicyMap::const_iterator found = user_policies->find(guid);
-      if (found != user_policies->end()) {
-        *onc_source = onc::ONC_SOURCE_USER_POLICY;
-        return found->second;
-      }
-    }
-  }
-
-  const GuidToPolicyMap* device_policies = GetPoliciesForUser(std::string());
-  if (device_policies) {
-    GuidToPolicyMap::const_iterator found = device_policies->find(guid);
-    if (found != device_policies->end()) {
-      *onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
-      return found->second;
-    }
-  }
-
-  return NULL;
-}
-
-void ManagedNetworkConfigurationHandler::OnProfileRemoved(
-    const NetworkProfile& profile) {
-  // Nothing to do in this case.
-}
-
-const ManagedNetworkConfigurationHandler::GuidToPolicyMap*
-ManagedNetworkConfigurationHandler::GetPoliciesForUser(
-    const std::string& userhash) const {
-  UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
-  if (it == policies_by_user_.end())
-    return NULL;
-  return &it->second;
-}
-
-const ManagedNetworkConfigurationHandler::GuidToPolicyMap*
-ManagedNetworkConfigurationHandler::GetPoliciesForProfile(
-    const NetworkProfile& profile) const {
-  DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
-         profile.userhash.empty());
-  return GetPoliciesForUser(profile.userhash);
-}
-
-ManagedNetworkConfigurationHandler::ManagedNetworkConfigurationHandler()
-    : network_state_handler_(NULL),
-      network_profile_handler_(NULL),
-      network_configuration_handler_(NULL),
-      weak_ptr_factory_(this) {
-}
-
-ManagedNetworkConfigurationHandler::~ManagedNetworkConfigurationHandler() {
-  network_profile_handler_->RemoveObserver(this);
-  for (UserToPoliciesMap::iterator it = policies_by_user_.begin();
-       it != policies_by_user_.end(); ++it) {
-    STLDeleteValues(&it->second);
-  }
-}
-
-void ManagedNetworkConfigurationHandler::Init(
-    NetworkStateHandler* network_state_handler,
-    NetworkProfileHandler* network_profile_handler,
-    NetworkConfigurationHandler* network_configuration_handler) {
-  network_state_handler_ = network_state_handler;
-  network_profile_handler_ = network_profile_handler;
-  network_configuration_handler_ = network_configuration_handler;
-  network_profile_handler_->AddObserver(this);
-}
-
-ManagedNetworkConfigurationHandler::PolicyApplicator::PolicyApplicator(
-    base::WeakPtr<ManagedNetworkConfigurationHandler> handler,
-    const NetworkProfile& profile,
-    std::set<std::string>* modified_policies)
-    : handler_(handler), profile_(profile) {
-  remaining_policies_.swap(*modified_policies);
-}
-
-void ManagedNetworkConfigurationHandler::PolicyApplicator::Run() {
-  DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
-      dbus::ObjectPath(profile_.path),
-      base::Bind(&PolicyApplicator::GetProfilePropertiesCallback, this),
-      base::Bind(&LogErrorMessage, FROM_HERE));
-}
-
-void ManagedNetworkConfigurationHandler::PolicyApplicator::
-    GetProfilePropertiesCallback(
-        const base::DictionaryValue& profile_properties) {
-  if (!handler_) {
-    LOG(WARNING) << "Handler destructed during policy application to profile "
-                 << profile_.ToDebugString();
-    return;
-  }
-
-  VLOG(2) << "Received properties for profile " << profile_.ToDebugString();
-  const base::ListValue* entries = NULL;
-  if (!profile_properties.GetListWithoutPathExpansion(
-          flimflam::kEntriesProperty, &entries)) {
-    LOG(ERROR) << "Profile " << profile_.ToDebugString()
-               << " doesn't contain the property "
-               << flimflam::kEntriesProperty;
-    return;
-  }
-
-  for (base::ListValue::const_iterator it = entries->begin();
-       it != entries->end();
-       ++it) {
-    std::string entry;
-    (*it)->GetAsString(&entry);
-
-    std::ostringstream entry_failure;
-    DBusThreadManager::Get()->GetShillProfileClient()
-        ->GetEntry(dbus::ObjectPath(profile_.path),
-                   entry,
-                   base::Bind(&PolicyApplicator::GetEntryCallback, this, entry),
-                   base::Bind(&LogErrorMessage, FROM_HERE));
-  }
-}
-
-void ManagedNetworkConfigurationHandler::PolicyApplicator::GetEntryCallback(
-    const std::string& entry,
-    const base::DictionaryValue& entry_properties) {
-  if (!handler_) {
-    LOG(WARNING) << "Handler destructed during policy application to profile "
-                 << profile_.ToDebugString();
-    return;
-  }
-
-  VLOG(2) << "Received properties for entry " << entry << " of profile "
-          << profile_.ToDebugString();
-
-  scoped_ptr<base::DictionaryValue> onc_part(
-      onc::TranslateShillServiceToONCPart(entry_properties,
-                                          &onc::kNetworkWithStateSignature));
-
-  std::string old_guid;
-  if (!onc_part->GetStringWithoutPathExpansion(onc::network_config::kGUID,
-                                               &old_guid)) {
-    VLOG(1) << "Entry " << entry << " of profile " << profile_.ToDebugString()
-            << " doesn't contain a GUID.";
-    // This might be an entry of an older ChromeOS version. Assume it to be
-    // unmanaged.
-  }
-
-  scoped_ptr<NetworkUIData> ui_data = GetUIData(entry_properties);
-  if (!ui_data) {
-    VLOG(1) << "Entry " << entry << " of profile " << profile_.ToDebugString()
-            << " contains no or no valid UIData.";
-    // This might be an entry of an older ChromeOS version. Assume it to be
-    // unmanaged. It's an inconsistency if there is a GUID but no UIData, thus
-    // clear the GUID just in case.
-    old_guid.clear();
-  }
-
-  bool was_managed = !old_guid.empty() && ui_data &&
-                     (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY ||
-                      ui_data->onc_source() == onc::ONC_SOURCE_USER_POLICY);
-
-  // The relevant policy must have been initialized, otherwise we hadn't Run
-  // this PolicyApplicator.
-  const GuidToPolicyMap& policies = *handler_->GetPoliciesForProfile(profile_);
-
-  const base::DictionaryValue* new_policy = NULL;
-  if (was_managed) {
-    // If we have a GUID that might match a current policy, do a lookup using
-    // that GUID at first. In particular this is necessary, as some networks
-    // can't be matched to policies by properties (e.g. VPN).
-    new_policy = GetByGUID(policies, old_guid);
-  }
-
-  if (!new_policy) {
-    // If we didn't find a policy by GUID, still a new policy might match.
-    new_policy = FindMatchingPolicy(policies, *onc_part);
-  }
-
-  if (new_policy) {
-    std::string new_guid;
-    new_policy->GetStringWithoutPathExpansion(onc::network_config::kGUID,
-                                              &new_guid);
-
-    VLOG_IF(1, was_managed && old_guid != new_guid)
-        << "Updating configuration previously managed by policy " << old_guid
-        << " with new policy " << new_guid << ".";
-    VLOG_IF(1, !was_managed) << "Applying policy " << new_guid
-                             << " to previously unmanaged "
-                             << "configuration.";
-
-    if (old_guid == new_guid &&
-        remaining_policies_.find(new_guid) == remaining_policies_.end()) {
-      VLOG(1) << "Not updating existing managed configuration with guid "
-              << new_guid << " because the policy didn't change.";
-    } else {
-      // Delete the entry to ensure that no old configuration remains.
-      // Don't do this if a policy is reapplied (e.g. after reboot) or updated
-      // (i.e. the GUID didn't change), in order to keep implicit state of
-      // Shill like "connected successfully before".
-      if (old_guid == new_guid) {
-        VLOG(1) << "Updating previously managed configuration with the "
-                << "updated policy " << new_guid << ".";
-      } else {
-        DeleteEntry(entry);
-      }
-
-      const base::DictionaryValue* user_settings =
-          ui_data ? ui_data->user_settings() : NULL;
-
-      // Write the new configuration.
-      scoped_ptr<base::DictionaryValue> shill_dictionary =
-          CreateShillConfiguration(
-              profile_, new_guid, new_policy, user_settings);
-      handler_->network_configuration_handler()
-          ->CreateConfiguration(*shill_dictionary,
-                                base::Bind(&IgnoreString),
-                                base::Bind(&LogErrorWithDict, FROM_HERE));
-      remaining_policies_.erase(new_guid);
-    }
-  } else if (was_managed) {
-    VLOG(1) << "Removing configuration previously managed by policy "
-            << old_guid << ", because the policy was removed.";
-
-    // Remove the entry, because the network was managed but isn't anymore.
-    // Note: An alternative might be to preserve the user settings, but it's
-    // unclear which values originating the policy should be removed.
-    DeleteEntry(entry);
-  } else {
-    VLOG(2) << "Ignore unmanaged entry.";
-
-    // The entry wasn't managed and doesn't match any current policy. Thus
-    // leave it as it is.
-  }
-}
-
-void ManagedNetworkConfigurationHandler::PolicyApplicator::DeleteEntry(
-    const std::string& entry) {
-  DBusThreadManager::Get()->GetShillProfileClient()
-      ->DeleteEntry(dbus::ObjectPath(profile_.path),
-                    entry,
-                    base::Bind(&base::DoNothing),
-                    base::Bind(&LogErrorMessage, FROM_HERE));
-}
-
-ManagedNetworkConfigurationHandler::PolicyApplicator::~PolicyApplicator() {
-  if (!handler_) {
-    LOG(WARNING) << "Handler destructed during policy application to profile "
-                 << profile_.ToDebugString();
-    return;
-  }
-
-  if (remaining_policies_.empty())
-    return;
-
-  VLOG(2) << "Create new managed network configurations in profile"
-          << profile_.ToDebugString() << ".";
-  // All profile entries were compared to policies. |configureGUIDs_| contains
-  // all matched policies. From the remainder of policies, new configurations
-  // have to be created.
-
-  // The relevant policy must have been initialized, otherwise we hadn't Run
-  // this PolicyApplicator.
-  const GuidToPolicyMap& policies = *handler_->GetPoliciesForProfile(profile_);
-
-  for (std::set<std::string>::iterator it = remaining_policies_.begin();
-       it != remaining_policies_.end();
-       ++it) {
-    const base::DictionaryValue* policy = GetByGUID(policies, *it);
-    if (!policy) {
-      LOG(ERROR) << "Policy " << *it << " doesn't exist anymore.";
-      continue;
-    }
-
-    VLOG(1) << "Creating new configuration managed by policy " << *it
-            << " in profile " << profile_.ToDebugString() << ".";
-
-    scoped_ptr<base::DictionaryValue> shill_dictionary =
-        CreateShillConfiguration(
-            profile_, *it, policy, NULL /* no user settings */);
-    handler_->network_configuration_handler()
-        ->CreateConfiguration(*shill_dictionary,
-                              base::Bind(&IgnoreString),
-                              base::Bind(&LogErrorWithDict, FROM_HERE));
-  }
-}
-
 }  // namespace chromeos
diff --git a/chromeos/network/managed_network_configuration_handler.h b/chromeos/network/managed_network_configuration_handler.h
index 0ac1e6e..46f7e97 100644
--- a/chromeos/network/managed_network_configuration_handler.h
+++ b/chromeos/network/managed_network_configuration_handler.h
@@ -5,17 +5,16 @@
 #ifndef CHROMEOS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_H_
 #define CHROMEOS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_H_
 
-#include <map>
 #include <string>
 
 #include "base/basictypes.h"
 #include "base/callback.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/weak_ptr.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/network/network_handler.h"
 #include "chromeos/network/network_handler_callbacks.h"
-#include "chromeos/network/network_profile_observer.h"
 #include "chromeos/network/onc/onc_constants.h"
 
 namespace base {
@@ -25,9 +24,7 @@
 
 namespace chromeos {
 
-class NetworkConfigurationHandler;
-class NetworkProfileHandler;
-class NetworkStateHandler;
+class NetworkPolicyObserver;
 class NetworkUIData;
 
 // The ManagedNetworkConfigurationHandler class is used to create and configure
@@ -54,13 +51,8 @@
 // error, including a symbolic name for the error and often some error message
 // that is suitable for logging. None of the error message text is meant for
 // user consumption.
-
-class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler
-    : public NetworkProfileObserver {
+class CHROMEOS_EXPORT ManagedNetworkConfigurationHandler {
  public:
-  typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
-  typedef std::map<std::string, GuidToPolicyMap> UserToPoliciesMap;
-
   virtual ~ManagedNetworkConfigurationHandler();
 
   // Returns the NetworkUIData parsed from the UIData property of
@@ -69,50 +61,53 @@
   static scoped_ptr<NetworkUIData> GetUIData(
       const base::DictionaryValue& shill_dictionary);
 
+  virtual void AddObserver(NetworkPolicyObserver* observer) = 0;
+  virtual void RemoveObserver(NetworkPolicyObserver* observer) = 0;
+
   // Provides the properties of the network with |service_path| to |callback|.
-  void GetProperties(
+  virtual void GetProperties(
       const std::string& service_path,
       const network_handler::DictionaryResultCallback& callback,
-      const network_handler::ErrorCallback& error_callback) const;
+      const network_handler::ErrorCallback& error_callback) const = 0;
 
   // Provides the managed properties of the network with |service_path| to
   // |callback|. |userhash| is only used to ensure that the user's policy is
   // already applied.
-  void GetManagedProperties(
+  virtual void GetManagedProperties(
       const std::string& userhash,
       const std::string& service_path,
       const network_handler::DictionaryResultCallback& callback,
-      const network_handler::ErrorCallback& error_callback);
+      const network_handler::ErrorCallback& error_callback) = 0;
 
   // Sets the user's settings of an already configured network with
   // |service_path|. A network can be initially configured by calling
   // CreateConfiguration or if it is managed by a policy. The given properties
   // will be merged with the existing settings, and it won't clear any existing
   // properties.
-  void SetProperties(
+  virtual void SetProperties(
       const std::string& service_path,
       const base::DictionaryValue& user_settings,
       const base::Closure& callback,
-      const network_handler::ErrorCallback& error_callback) const;
+      const network_handler::ErrorCallback& error_callback) const = 0;
 
   // Initially configures an unconfigured network with the given user settings
   // and returns the new identifier to |callback| if successful. Fails if the
   // network was already configured by a call to this function or because of a
   // policy. The new configuration will be owned by user |userhash|. If
   // |userhash| is empty, the new configuration will be shared.
-  void CreateConfiguration(
+  virtual void CreateConfiguration(
       const std::string& userhash,
       const base::DictionaryValue& properties,
       const network_handler::StringResultCallback& callback,
-      const network_handler::ErrorCallback& error_callback) const;
+      const network_handler::ErrorCallback& error_callback) const = 0;
 
   // Removes the user's configuration from the network with |service_path|. The
   // network may still show up in the visible networks after this, but no user
   // configuration will remain. If it was managed, it will still be configured.
-  void RemoveConfiguration(
+  virtual void RemoveConfiguration(
       const std::string& service_path,
       const base::Closure& callback,
-      const network_handler::ErrorCallback& error_callback) const;
+      const network_handler::ErrorCallback& error_callback) const = 0;
 
   // Only to be called by NetworkConfigurationUpdater or from tests.  Sets
   // |network_configs_onc| as the current policy of |onc_source|. The network
@@ -120,62 +115,26 @@
   // to Shill's profiles and enforced in future configurations until the policy
   // associated with |onc_source| is changed again with this function. For
   // device policies, |userhash| must be empty.
-  void SetPolicy(onc::ONCSource onc_source,
-                 const std::string& userhash,
-                 const base::ListValue& network_configs_onc);
+  virtual void SetPolicy(onc::ONCSource onc_source,
+                         const std::string& userhash,
+                         const base::ListValue& network_configs_onc) = 0;
 
   // Returns the user policy for user |userhash| or device policy, which has
   // |guid|. If |userhash| is empty, only looks for a device policy. If such
   // doesn't exist, returns NULL. Sets |onc_source| accordingly.
-  const base::DictionaryValue* FindPolicyByGUID(
+  virtual const base::DictionaryValue* FindPolicyByGUID(
       const std::string userhash,
       const std::string& guid,
-      onc::ONCSource* onc_source) const;
+      onc::ONCSource* onc_source) const = 0;
 
-  // NetworkProfileObserver overrides
-  virtual void OnProfileAdded(const NetworkProfile& profile) OVERRIDE;
-  virtual void OnProfileRemoved(const NetworkProfile& profile) OVERRIDE;
-
-  NetworkConfigurationHandler* network_configuration_handler() {
-    return network_configuration_handler_;
-  }
+  // Returns the policy with |guid| for profile |profile_path|. If such
+  // doesn't exist, returns NULL.
+  virtual const base::DictionaryValue* FindPolicyByGuidAndProfile(
+      const std::string& guid,
+      const std::string& profile_path) const = 0;
 
  private:
-  friend class NetworkHandler;
-  friend class ManagedNetworkConfigurationHandlerTest;
-  class PolicyApplicator;
-
-  ManagedNetworkConfigurationHandler();
-
-  void Init(NetworkStateHandler* network_state_handler,
-            NetworkProfileHandler* network_profile_handler,
-            NetworkConfigurationHandler* network_configuration_handler);
-
-
-  void GetManagedPropertiesCallback(
-      const network_handler::DictionaryResultCallback& callback,
-      const network_handler::ErrorCallback& error_callback,
-      const std::string& service_path,
-      const base::DictionaryValue& shill_properties);
-
-  const GuidToPolicyMap* GetPoliciesForUser(const std::string& userhash) const;
-  const GuidToPolicyMap* GetPoliciesForProfile(
-      const NetworkProfile& profile) const;
-
-  // The DictionaryValues of the nested maps are owned by this class and are
-  // explicitly deleted where necessary. If present, the empty string maps to
-  // the device policy.
-  UserToPoliciesMap policies_by_user_;
-
-  // Local references to the associated handler instances.
-  NetworkStateHandler* network_state_handler_;
-  NetworkProfileHandler* network_profile_handler_;
-  NetworkConfigurationHandler* network_configuration_handler_;
-
-  // For Shill client callbacks
-  base::WeakPtrFactory<ManagedNetworkConfigurationHandler> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ManagedNetworkConfigurationHandler);
+  DISALLOW_ASSIGN(ManagedNetworkConfigurationHandler);
 };
 
 }  // namespace chromeos
diff --git a/chromeos/network/managed_network_configuration_handler_impl.cc b/chromeos/network/managed_network_configuration_handler_impl.cc
new file mode 100644
index 0000000..f2133c3
--- /dev/null
+++ b/chromeos/network/managed_network_configuration_handler_impl.cc
@@ -0,0 +1,1015 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/network/managed_network_configuration_handler_impl.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/json/json_writer.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/shill_manager_client.h"
+#include "chromeos/dbus/shill_profile_client.h"
+#include "chromeos/dbus/shill_service_client.h"
+#include "chromeos/network/network_configuration_handler.h"
+#include "chromeos/network/network_event_log.h"
+#include "chromeos/network/network_policy_observer.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_constants.h"
+#include "chromeos/network/onc/onc_merger.h"
+#include "chromeos/network/onc/onc_normalizer.h"
+#include "chromeos/network/onc/onc_signature.h"
+#include "chromeos/network/onc/onc_translator.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "chromeos/network/onc/onc_validator.h"
+#include "dbus/object_path.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+namespace {
+
+// 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";
+
+// This fake credential contains a random postfix which is extremly unlikely to
+// be used by any user.
+const char kFakeCredential[] = "FAKE_CREDENTIAL_VPaJDV9x";
+
+std::string ToDebugString(onc::ONCSource source,
+                          const std::string& userhash) {
+  return source == onc::ONC_SOURCE_USER_POLICY ?
+      ("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)));
+}
+
+// Sets the UIData property in |shill_dictionary| to the serialization of
+// |ui_data|.
+void SetUIData(const NetworkUIData& ui_data,
+               base::DictionaryValue* shill_dictionary) {
+  base::DictionaryValue ui_data_dict;
+  ui_data.FillDictionary(&ui_data_dict);
+  std::string ui_data_blob;
+  base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
+  shill_dictionary->SetStringWithoutPathExpansion(flimflam::kUIDataProperty,
+                                                  ui_data_blob);
+}
+
+void LogErrorWithDict(const tracked_objects::Location& from_where,
+                      const std::string& error_name,
+                      scoped_ptr<base::DictionaryValue> error_data) {
+  LOG(ERROR) << from_where.ToString() << ": " << error_name;
+}
+
+void LogErrorMessage(const tracked_objects::Location& from_where,
+                     const std::string& error_name,
+                     const std::string& error_message) {
+  LOG(ERROR) << from_where.ToString() << ": " << error_message;
+}
+
+// Removes all kFakeCredential values from sensitive fields (determined by
+// onc::FieldIsCredential) of |onc_object|.
+void RemoveFakeCredentials(
+    const onc::OncValueSignature& signature,
+    base::DictionaryValue* onc_object) {
+  base::DictionaryValue::Iterator it(*onc_object);
+  while (!it.IsAtEnd()) {
+    base::Value* value = NULL;
+    std::string field_name = it.key();
+    // We need the non-const entry to remove nested values but DictionaryValue
+    // has no non-const iterator.
+    onc_object->GetWithoutPathExpansion(field_name, &value);
+    // Advance before delete.
+    it.Advance();
+
+    // If |value| is a dictionary, recurse.
+    base::DictionaryValue* nested_object = NULL;
+    if (value->GetAsDictionary(&nested_object)) {
+      const onc::OncFieldSignature* field_signature =
+          onc::GetFieldSignature(signature, field_name);
+
+      RemoveFakeCredentials(*field_signature->value_signature,
+                            nested_object);
+      continue;
+    }
+
+    // If |value| is a string, check if it is a fake credential.
+    std::string string_value;
+    if (value->GetAsString(&string_value) &&
+        onc::FieldIsCredential(signature, field_name)) {
+      if (string_value == kFakeCredential) {
+        // The value wasn't modified by the UI, thus we remove the field to keep
+        // the existing value that is stored in Shill.
+        onc_object->RemoveWithoutPathExpansion(field_name, NULL);
+      }
+      // Otherwise, the value is set and modified by the UI, thus we keep that
+      // value to overwrite whatever is stored in Shill.
+    }
+  }
+}
+
+// Creates a Shill property dictionary from the given arguments. The resulting
+// dictionary will be sent to Shill by the caller. Depending on the profile
+// type, |policy| is interpreted as the user or device policy and |settings| as
+// the user or shared settings.
+scoped_ptr<base::DictionaryValue> CreateShillConfiguration(
+    const NetworkProfile& profile,
+    const std::string& guid,
+    const base::DictionaryValue* policy,
+    const base::DictionaryValue* settings) {
+  scoped_ptr<base::DictionaryValue> effective;
+  onc::ONCSource onc_source = onc::ONC_SOURCE_NONE;
+  if (policy) {
+    if (profile.type() == NetworkProfile::TYPE_SHARED) {
+      effective = onc::MergeSettingsAndPoliciesToEffective(
+          NULL,  // no user policy
+          policy,  // device policy
+          NULL,  // no user settings
+          settings);  // shared settings
+      onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
+    } else if (profile.type() == NetworkProfile::TYPE_USER) {
+      effective = onc::MergeSettingsAndPoliciesToEffective(
+          policy,  // user policy
+          NULL,  // no device policy
+          settings,  // user settings
+          NULL);  // no shared settings
+      onc_source = onc::ONC_SOURCE_USER_POLICY;
+    } else {
+      NOTREACHED();
+    }
+  } else if (settings) {
+    effective.reset(settings->DeepCopy());
+    // TODO(pneubeck): change to source ONC_SOURCE_USER
+    onc_source = onc::ONC_SOURCE_NONE;
+  } else {
+    NOTREACHED();
+    onc_source = onc::ONC_SOURCE_NONE;
+  }
+
+  RemoveFakeCredentials(onc::kNetworkConfigurationSignature,
+                        effective.get());
+
+  effective->SetStringWithoutPathExpansion(onc::network_config::kGUID, guid);
+
+  // Remove irrelevant fields.
+  onc::Normalizer normalizer(true /* remove recommended fields */);
+  effective = normalizer.NormalizeObject(&onc::kNetworkConfigurationSignature,
+                                         *effective);
+
+  scoped_ptr<base::DictionaryValue> shill_dictionary(
+      onc::TranslateONCObjectToShill(&onc::kNetworkConfigurationSignature,
+                                     *effective));
+
+  shill_dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty,
+                                                  profile.path);
+
+  scoped_ptr<NetworkUIData> ui_data;
+  if (policy)
+    ui_data = NetworkUIData::CreateFromONC(onc_source, *policy);
+  else
+    ui_data.reset(new NetworkUIData());
+
+  if (settings) {
+    // Shill doesn't know that sensitive data is contained in the UIData
+    // property and might write it into logs or other insecure places. Thus, we
+    // have to remove or mask credentials.
+    //
+    // Shill's GetProperties doesn't return credentials. Masking credentials
+    // instead of just removing them, allows remembering if a credential is set
+    // or not.
+    scoped_ptr<base::DictionaryValue> sanitized_settings(
+        onc::MaskCredentialsInOncObject(onc::kNetworkConfigurationSignature,
+                                        *settings,
+                                        kFakeCredential));
+    ui_data->set_user_settings(sanitized_settings.Pass());
+  }
+
+  SetUIData(*ui_data, shill_dictionary.get());
+
+  VLOG(2) << "Created Shill properties: " << *shill_dictionary;
+
+  return shill_dictionary.Pass();
+}
+
+// Returns true if |policy| matches |actual_network|, which must be part of a
+// ONC NetworkConfiguration. This should be the only such matching function
+// within Chrome. Shill does such matching in several functions for network
+// identification. For compatibility, we currently should stick to Shill's
+// matching behavior.
+bool IsPolicyMatching(const base::DictionaryValue& policy,
+                      const base::DictionaryValue& actual_network) {
+  std::string policy_type;
+  policy.GetStringWithoutPathExpansion(onc::network_config::kType,
+                                       &policy_type);
+  std::string network_type;
+  actual_network.GetStringWithoutPathExpansion(onc::network_config::kType,
+                                               &network_type);
+  if (policy_type != network_type)
+    return false;
+
+  if (network_type != onc::network_type::kWiFi)
+    return false;
+
+  const base::DictionaryValue* policy_wifi = NULL;
+  policy.GetDictionaryWithoutPathExpansion(onc::network_config::kWiFi,
+                                           &policy_wifi);
+  const base::DictionaryValue* actual_wifi = NULL;
+  actual_network.GetDictionaryWithoutPathExpansion(onc::network_config::kWiFi,
+                                                   &actual_wifi);
+  if (!policy_wifi || !actual_wifi)
+    return false;
+
+  std::string policy_ssid;
+  policy_wifi->GetStringWithoutPathExpansion(onc::wifi::kSSID, &policy_ssid);
+  std::string actual_ssid;
+  actual_wifi->GetStringWithoutPathExpansion(onc::wifi::kSSID, &actual_ssid);
+  return (policy_ssid == actual_ssid);
+}
+
+// Returns the policy from |policies| matching |actual_network|, if any exists.
+// Returns NULL otherwise. |actual_network| must be part of a ONC
+// NetworkConfiguration.
+const base::DictionaryValue* FindMatchingPolicy(
+    const ManagedNetworkConfigurationHandlerImpl::GuidToPolicyMap& policies,
+    const base::DictionaryValue& actual_network) {
+  for (ManagedNetworkConfigurationHandlerImpl::GuidToPolicyMap::const_iterator
+           it = policies.begin();
+       it != policies.end(); ++it) {
+    if (IsPolicyMatching(*it->second, actual_network))
+      return it->second;
+  }
+  return NULL;
+}
+
+const base::DictionaryValue* GetByGUID(
+    const ManagedNetworkConfigurationHandlerImpl::GuidToPolicyMap& policies,
+    const std::string& guid) {
+  ManagedNetworkConfigurationHandlerImpl::GuidToPolicyMap::const_iterator it =
+      policies.find(guid);
+  if (it == policies.end())
+    return NULL;
+  return it->second;
+}
+
+void TranslatePropertiesToOncAndRunCallback(
+    const network_handler::DictionaryResultCallback& callback,
+    const std::string& service_path,
+    const base::DictionaryValue& shill_properties) {
+  scoped_ptr<base::DictionaryValue> onc_network(
+      onc::TranslateShillServiceToONCPart(
+          shill_properties,
+          &onc::kNetworkWithStateSignature));
+  callback.Run(service_path, *onc_network);
+}
+
+}  // namespace
+
+// This class compares (entry point is Run()) |modified_policies| with the
+// existing entries in the provided Shill profile |profile|. It fetches all
+// entries in parallel (GetProfilePropertiesCallback), compares each entry with
+// the current policies (GetEntryCallback) and adds all missing policies
+// (~PolicyApplicator).
+class ManagedNetworkConfigurationHandlerImpl::PolicyApplicator
+    : public base::RefCounted<PolicyApplicator> {
+ public:
+  typedef ManagedNetworkConfigurationHandlerImpl::GuidToPolicyMap
+      GuidToPolicyMap;
+
+  // |modified_policies| must not be NULL and will be empty afterwards.
+  PolicyApplicator(
+      base::WeakPtr<ManagedNetworkConfigurationHandlerImpl> handler,
+      const NetworkProfile& profile,
+      std::set<std::string>* modified_policies);
+
+  void Run();
+
+ private:
+  friend class base::RefCounted<PolicyApplicator>;
+
+  // Called with the properties of the profile |profile_|. Requests the
+  // properties of each entry, which are processed by GetEntryCallback.
+  void GetProfilePropertiesCallback(
+      const base::DictionaryValue& profile_properties);
+
+  // Called with the properties of the profile entry |entry|. Checks whether the
+  // entry was previously managed, whether a current policy applies and then
+  // either updates, deletes or not touches the entry.
+  void GetEntryCallback(const std::string& entry,
+                        const base::DictionaryValue& entry_properties);
+
+  // Sends Shill the command to delete profile entry |entry| from |profile_|.
+  void DeleteEntry(const std::string& entry);
+
+  // Creates new entries for all remaining policies, i.e. for which not matching
+  // entry was found.
+  virtual ~PolicyApplicator();
+
+  std::set<std::string> remaining_policies_;
+  base::WeakPtr<ManagedNetworkConfigurationHandlerImpl> handler_;
+  NetworkProfile profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyApplicator);
+};
+
+void ManagedNetworkConfigurationHandlerImpl::AddObserver(
+    NetworkPolicyObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::RemoveObserver(
+    NetworkPolicyObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::GetManagedProperties(
+    const std::string& userhash,
+    const std::string& service_path,
+    const network_handler::DictionaryResultCallback& callback,
+    const network_handler::ErrorCallback& error_callback) {
+  if (!GetPoliciesForUser(userhash) || !GetPoliciesForUser(std::string())) {
+    RunErrorCallback(service_path,
+                     kPoliciesNotInitialized,
+                     kPoliciesNotInitializedMessage,
+                     error_callback);
+    return;
+  }
+  network_configuration_handler_->GetProperties(
+      service_path,
+      base::Bind(
+          &ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback,
+          weak_ptr_factory_.GetWeakPtr(),
+          callback,
+          error_callback),
+      error_callback);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::GetManagedPropertiesCallback(
+    const network_handler::DictionaryResultCallback& callback,
+    const network_handler::ErrorCallback& error_callback,
+    const std::string& service_path,
+    const base::DictionaryValue& shill_properties) {
+  std::string profile_path;
+  shill_properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty,
+                                                 &profile_path);
+  LOG(ERROR) << "Profile: " << profile_path;
+  const NetworkProfile* profile =
+      network_profile_handler_->GetProfileForPath(profile_path);
+  if (!profile) {
+    LOG(ERROR) << "No or no known profile received for service "
+            << service_path << ".";
+  }
+
+  scoped_ptr<NetworkUIData> ui_data = GetUIData(shill_properties);
+
+  const base::DictionaryValue* user_settings = NULL;
+  const base::DictionaryValue* shared_settings = NULL;
+
+  if (ui_data && profile) {
+    if (profile->type() == NetworkProfile::TYPE_SHARED)
+      shared_settings = ui_data->user_settings();
+    else if (profile->type() == NetworkProfile::TYPE_USER)
+      user_settings = ui_data->user_settings();
+    else
+      NOTREACHED();
+  } else if (profile) {
+    LOG(WARNING) << "Service " << service_path << " of profile "
+                 << profile_path << " contains no or no valid UIData.";
+    // TODO(pneubeck): add a conversion of user configured entries of old
+    // ChromeOS versions. We will have to use a heuristic to determine which
+    // properties _might_ be user configured.
+  }
+
+  scoped_ptr<base::DictionaryValue> active_settings(
+      onc::TranslateShillServiceToONCPart(
+          shill_properties,
+          &onc::kNetworkWithStateSignature));
+
+  std::string guid;
+  active_settings->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+                                                 &guid);
+
+  const base::DictionaryValue* user_policy = NULL;
+  const base::DictionaryValue* device_policy = NULL;
+  if (!guid.empty() && profile) {
+    const GuidToPolicyMap* policies = GetPoliciesForProfile(*profile);
+    if (!policies) {
+      RunErrorCallback(service_path,
+                       kPoliciesNotInitialized,
+                       kPoliciesNotInitializedMessage,
+                       error_callback);
+      return;
+    }
+    const base::DictionaryValue* policy = GetByGUID(*policies, guid);
+    if (profile->type() == NetworkProfile::TYPE_SHARED)
+      device_policy = policy;
+    else if (profile->type() == NetworkProfile::TYPE_USER)
+      user_policy = policy;
+    else
+      NOTREACHED();
+  }
+
+  // This call also removes credentials from policies.
+  scoped_ptr<base::DictionaryValue> augmented_properties =
+      onc::MergeSettingsAndPoliciesToAugmented(
+          onc::kNetworkConfigurationSignature,
+          user_policy,
+          device_policy,
+          user_settings,
+          shared_settings,
+          active_settings.get());
+  callback.Run(service_path, *augmented_properties);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::GetProperties(
+    const std::string& service_path,
+    const network_handler::DictionaryResultCallback& callback,
+    const network_handler::ErrorCallback& error_callback) const {
+  network_configuration_handler_->GetProperties(
+      service_path,
+      base::Bind(&TranslatePropertiesToOncAndRunCallback, callback),
+      error_callback);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::SetProperties(
+    const std::string& service_path,
+    const base::DictionaryValue& user_settings,
+    const base::Closure& callback,
+    const network_handler::ErrorCallback& error_callback) const {
+  const NetworkState* state =
+      network_state_handler_->GetNetworkState(service_path);
+
+  if (!state) {
+    RunErrorCallback(service_path,
+                     kUnknownServicePath,
+                     kUnknownServicePathMessage,
+                     error_callback);
+    return;
+  }
+
+  std::string guid = state->guid();
+  if (guid.empty()) {
+    // 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);
+    return;
+  }
+
+  const std::string& profile_path = state->profile_path();
+  const NetworkProfile *profile =
+      network_profile_handler_->GetProfileForPath(profile_path);
+  if (!profile) {
+    RunErrorCallback(service_path,
+                     kUnknownProfilePath,
+                     kUnknownProfilePathMessage,
+                     error_callback);
+    return;
+  }
+
+  VLOG(2) << "SetProperties: Found GUID " << guid << " and profile "
+          << profile->ToDebugString();
+
+  const GuidToPolicyMap* policies = GetPoliciesForProfile(*profile);
+  if (!policies) {
+    RunErrorCallback(service_path,
+                     kPoliciesNotInitialized,
+                     kPoliciesNotInitializedMessage,
+                     error_callback);
+    return;
+  }
+
+  // Validate the ONC dictionary. We are liberal and ignore unknown field
+  // names. User settings are only partial ONC, thus we ignore missing fields.
+  onc::Validator validator(false,  // Ignore unknown fields.
+                           false,  // Ignore invalid recommended field names.
+                           false,  // Ignore missing fields.
+                           false);  // This ONC does not come from policy.
+
+  onc::Validator::Result validation_result;
+  scoped_ptr<base::DictionaryValue> validated_user_settings =
+      validator.ValidateAndRepairObject(
+          &onc::kNetworkConfigurationSignature,
+          user_settings,
+          &validation_result);
+
+  if (validation_result == onc::Validator::INVALID) {
+    RunErrorCallback(service_path,
+                     kInvalidUserSettings,
+                     kInvalidUserSettingsMessage,
+                     error_callback);
+    return;
+  }
+  if (validation_result == onc::Validator::VALID_WITH_WARNINGS)
+    LOG(WARNING) << "Validation of ONC user settings produced warnings.";
+
+  const base::DictionaryValue* policy = GetByGUID(*policies, guid);
+  VLOG(2) << "This configuration is " << (policy ? "" : "not ") << "managed.";
+
+  scoped_ptr<base::DictionaryValue> shill_dictionary(CreateShillConfiguration(
+      *profile, guid, policy, validated_user_settings.get()));
+
+  network_configuration_handler_->SetProperties(
+      service_path, *shill_dictionary, callback, error_callback);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::CreateConfiguration(
+    const std::string& userhash,
+    const base::DictionaryValue& properties,
+    const network_handler::StringResultCallback& callback,
+    const network_handler::ErrorCallback& error_callback) const {
+  const GuidToPolicyMap* policies = GetPoliciesForUser(userhash);
+  if (!policies) {
+    RunErrorCallback("",
+                     kPoliciesNotInitialized,
+                     kPoliciesNotInitializedMessage,
+                     error_callback);
+    return;
+  }
+
+  if (FindMatchingPolicy(*policies, properties)) {
+    RunErrorCallback("",
+                     kNetworkAlreadyConfigured,
+                     kNetworkAlreadyConfiguredMessage,
+                     error_callback);
+  }
+
+  const NetworkProfile* profile =
+      network_profile_handler_->GetProfileForUserhash(userhash);
+  if (!profile) {
+    RunErrorCallback("",
+                     kProfileNotInitialized,
+                     kProfileNotInitializedMessage,
+                     error_callback);
+  }
+
+  // TODO(pneubeck): In case of WiFi, check that no other configuration for the
+  // same {SSID, mode, security} exists. We don't support such multiple
+  // configurations, yet.
+
+  // Generate a new GUID for this configuration. Ignore the maybe provided GUID
+  // in |properties| as it is not our own and from an untrusted source.
+  std::string guid = base::GenerateGUID();
+  scoped_ptr<base::DictionaryValue> shill_dictionary(
+      CreateShillConfiguration(*profile, guid, NULL /*no policy*/,
+                               &properties));
+
+  network_configuration_handler_->CreateConfiguration(
+      *shill_dictionary, callback, error_callback);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::RemoveConfiguration(
+    const std::string& service_path,
+    const base::Closure& callback,
+    const network_handler::ErrorCallback& error_callback) const {
+  network_configuration_handler_->RemoveConfiguration(
+      service_path, callback, error_callback);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::SetPolicy(
+    onc::ONCSource onc_source,
+    const std::string& userhash,
+    const base::ListValue& network_configs_onc) {
+  VLOG(1) << "Setting policies from " << ToDebugString(onc_source, userhash)
+          << ".";
+
+  // |userhash| must be empty for device policies.
+  DCHECK(onc_source != chromeos::onc::ONC_SOURCE_DEVICE_POLICY ||
+         userhash.empty());
+  GuidToPolicyMap& policies = policies_by_user_[userhash];
+
+  GuidToPolicyMap old_policies;
+  policies.swap(old_policies);
+
+  // This stores all GUIDs of policies that have changed or are new.
+  std::set<std::string> modified_policies;
+
+  for (base::ListValue::const_iterator it = network_configs_onc.begin();
+       it != network_configs_onc.end(); ++it) {
+    const base::DictionaryValue* network = NULL;
+    (*it)->GetAsDictionary(&network);
+    DCHECK(network);
+
+    std::string guid;
+    network->GetStringWithoutPathExpansion(onc::network_config::kGUID, &guid);
+    DCHECK(!guid.empty());
+
+    if (policies.count(guid) > 0) {
+      LOG(ERROR) << "ONC from " << ToDebugString(onc_source, userhash)
+                 << " contains several entries for the same GUID "
+                 << guid << ".";
+      delete policies[guid];
+    }
+    const base::DictionaryValue* new_entry = network->DeepCopy();
+    policies[guid] = new_entry;
+
+    const base::DictionaryValue* old_entry = old_policies[guid];
+    if (!old_entry || !old_entry->Equals(new_entry))
+      modified_policies.insert(guid);
+  }
+
+  STLDeleteValues(&old_policies);
+
+  const NetworkProfile* profile =
+      network_profile_handler_->GetProfileForUserhash(userhash);
+  if (!profile) {
+    VLOG(1) << "The relevant Shill profile isn't initialized yet, postponing "
+            << "policy application.";
+    return;
+  }
+
+  scoped_refptr<PolicyApplicator> applicator = new PolicyApplicator(
+      weak_ptr_factory_.GetWeakPtr(),
+      *profile,
+      &modified_policies);
+  applicator->Run();
+}
+
+void ManagedNetworkConfigurationHandlerImpl::OnProfileAdded(
+    const NetworkProfile& profile) {
+  VLOG(1) << "Adding profile " << profile.ToDebugString() << "'.";
+
+  const GuidToPolicyMap* policies = GetPoliciesForProfile(profile);
+  if (!policies) {
+    VLOG(1) << "The relevant policy is not initialized, "
+            << "postponing policy application.";
+    return;
+  }
+
+  std::set<std::string> policy_guids;
+  for (GuidToPolicyMap::const_iterator it = policies->begin();
+       it != policies->end(); ++it) {
+    policy_guids.insert(it->first);
+  }
+
+  scoped_refptr<PolicyApplicator> applicator = new PolicyApplicator(
+      weak_ptr_factory_.GetWeakPtr(),
+      profile,
+      &policy_guids);
+  applicator->Run();
+}
+
+const base::DictionaryValue*
+ManagedNetworkConfigurationHandlerImpl::FindPolicyByGUID(
+    const std::string userhash,
+    const std::string& guid,
+    onc::ONCSource* onc_source) const {
+  *onc_source = onc::ONC_SOURCE_NONE;
+
+  if (!userhash.empty()) {
+    const GuidToPolicyMap* user_policies = GetPoliciesForUser(userhash);
+    if (user_policies) {
+      GuidToPolicyMap::const_iterator found = user_policies->find(guid);
+      if (found != user_policies->end()) {
+        *onc_source = onc::ONC_SOURCE_USER_POLICY;
+        return found->second;
+      }
+    }
+  }
+
+  const GuidToPolicyMap* device_policies = GetPoliciesForUser(std::string());
+  if (device_policies) {
+    GuidToPolicyMap::const_iterator found = device_policies->find(guid);
+    if (found != device_policies->end()) {
+      *onc_source = onc::ONC_SOURCE_DEVICE_POLICY;
+      return found->second;
+    }
+  }
+
+  return NULL;
+}
+
+const base::DictionaryValue*
+ManagedNetworkConfigurationHandlerImpl::FindPolicyByGuidAndProfile(
+    const std::string& guid,
+    const std::string& profile_path) const {
+  const NetworkProfile* profile =
+      network_profile_handler_->GetProfileForPath(profile_path);
+  if (!profile) {
+    LOG(ERROR) << "Profile path unknown: " << profile_path;
+    return NULL;
+  }
+
+  const GuidToPolicyMap* policies = GetPoliciesForProfile(*profile);
+  if (!policies)
+    return NULL;
+
+  GuidToPolicyMap::const_iterator it = policies->find(guid);
+  if (it == policies->end())
+    return NULL;
+  return it->second;
+}
+
+void ManagedNetworkConfigurationHandlerImpl::OnProfileRemoved(
+    const NetworkProfile& profile) {
+  // Nothing to do in this case.
+}
+
+const ManagedNetworkConfigurationHandlerImpl::GuidToPolicyMap*
+ManagedNetworkConfigurationHandlerImpl::GetPoliciesForUser(
+    const std::string& userhash) const {
+  UserToPoliciesMap::const_iterator it = policies_by_user_.find(userhash);
+  if (it == policies_by_user_.end())
+    return NULL;
+  return &it->second;
+}
+
+const ManagedNetworkConfigurationHandlerImpl::GuidToPolicyMap*
+ManagedNetworkConfigurationHandlerImpl::GetPoliciesForProfile(
+    const NetworkProfile& profile) const {
+  DCHECK(profile.type() != NetworkProfile::TYPE_SHARED ||
+         profile.userhash.empty());
+  return GetPoliciesForUser(profile.userhash);
+}
+
+ManagedNetworkConfigurationHandlerImpl::ManagedNetworkConfigurationHandlerImpl()
+    : network_state_handler_(NULL),
+      network_profile_handler_(NULL),
+      network_configuration_handler_(NULL),
+      weak_ptr_factory_(this) {}
+
+ManagedNetworkConfigurationHandlerImpl::
+    ~ManagedNetworkConfigurationHandlerImpl() {
+  network_profile_handler_->RemoveObserver(this);
+  for (UserToPoliciesMap::iterator it = policies_by_user_.begin();
+       it != policies_by_user_.end(); ++it) {
+    STLDeleteValues(&it->second);
+  }
+}
+
+void ManagedNetworkConfigurationHandlerImpl::Init(
+    NetworkStateHandler* network_state_handler,
+    NetworkProfileHandler* network_profile_handler,
+    NetworkConfigurationHandler* network_configuration_handler) {
+  network_state_handler_ = network_state_handler;
+  network_profile_handler_ = network_profile_handler;
+  network_configuration_handler_ = network_configuration_handler;
+  network_profile_handler_->AddObserver(this);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied(
+    const std::string& service_path) {
+  if (service_path.empty())
+    return;
+  FOR_EACH_OBSERVER(
+      NetworkPolicyObserver, observers_, PolicyApplied(service_path));
+}
+
+ManagedNetworkConfigurationHandlerImpl::PolicyApplicator::PolicyApplicator(
+    base::WeakPtr<ManagedNetworkConfigurationHandlerImpl> handler,
+    const NetworkProfile& profile,
+    std::set<std::string>* modified_policies)
+    : handler_(handler), profile_(profile) {
+  remaining_policies_.swap(*modified_policies);
+}
+
+void ManagedNetworkConfigurationHandlerImpl::PolicyApplicator::Run() {
+  DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
+      dbus::ObjectPath(profile_.path),
+      base::Bind(&PolicyApplicator::GetProfilePropertiesCallback, this),
+      base::Bind(&LogErrorMessage, FROM_HERE));
+}
+
+void ManagedNetworkConfigurationHandlerImpl::PolicyApplicator::
+    GetProfilePropertiesCallback(
+        const base::DictionaryValue& profile_properties) {
+  if (!handler_) {
+    LOG(WARNING) << "Handler destructed during policy application to profile "
+                 << profile_.ToDebugString();
+    return;
+  }
+
+  VLOG(2) << "Received properties for profile " << profile_.ToDebugString();
+  const base::ListValue* entries = NULL;
+  if (!profile_properties.GetListWithoutPathExpansion(
+          flimflam::kEntriesProperty, &entries)) {
+    LOG(ERROR) << "Profile " << profile_.ToDebugString()
+               << " doesn't contain the property "
+               << flimflam::kEntriesProperty;
+    return;
+  }
+
+  for (base::ListValue::const_iterator it = entries->begin();
+       it != entries->end();
+       ++it) {
+    std::string entry;
+    (*it)->GetAsString(&entry);
+
+    DBusThreadManager::Get()->GetShillProfileClient()
+        ->GetEntry(dbus::ObjectPath(profile_.path),
+                   entry,
+                   base::Bind(&PolicyApplicator::GetEntryCallback, this, entry),
+                   base::Bind(&LogErrorMessage, FROM_HERE));
+  }
+}
+
+void ManagedNetworkConfigurationHandlerImpl::PolicyApplicator::GetEntryCallback(
+    const std::string& entry,
+    const base::DictionaryValue& entry_properties) {
+  if (!handler_) {
+    LOG(WARNING) << "Handler destructed during policy application to profile "
+                 << profile_.ToDebugString();
+    return;
+  }
+
+  VLOG(2) << "Received properties for entry " << entry << " of profile "
+          << profile_.ToDebugString();
+
+  scoped_ptr<base::DictionaryValue> onc_part(
+      onc::TranslateShillServiceToONCPart(entry_properties,
+                                          &onc::kNetworkWithStateSignature));
+
+  std::string old_guid;
+  if (!onc_part->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+                                               &old_guid)) {
+    VLOG(1) << "Entry " << entry << " of profile " << profile_.ToDebugString()
+            << " doesn't contain a GUID.";
+    // This might be an entry of an older ChromeOS version. Assume it to be
+    // unmanaged.
+  }
+
+  scoped_ptr<NetworkUIData> ui_data = GetUIData(entry_properties);
+  if (!ui_data) {
+    VLOG(1) << "Entry " << entry << " of profile " << profile_.ToDebugString()
+            << " contains no or no valid UIData.";
+    // This might be an entry of an older ChromeOS version. Assume it to be
+    // unmanaged. It's an inconsistency if there is a GUID but no UIData, thus
+    // clear the GUID just in case.
+    old_guid.clear();
+  }
+
+  bool was_managed = !old_guid.empty() && ui_data &&
+                     (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY ||
+                      ui_data->onc_source() == onc::ONC_SOURCE_USER_POLICY);
+
+  // The relevant policy must have been initialized, otherwise we hadn't Run
+  // this PolicyApplicator.
+  const GuidToPolicyMap& policies = *handler_->GetPoliciesForProfile(profile_);
+
+  const base::DictionaryValue* new_policy = NULL;
+  if (was_managed) {
+    // If we have a GUID that might match a current policy, do a lookup using
+    // that GUID at first. In particular this is necessary, as some networks
+    // can't be matched to policies by properties (e.g. VPN).
+    new_policy = GetByGUID(policies, old_guid);
+  }
+
+  if (!new_policy) {
+    // If we didn't find a policy by GUID, still a new policy might match.
+    new_policy = FindMatchingPolicy(policies, *onc_part);
+  }
+
+  if (new_policy) {
+    std::string new_guid;
+    new_policy->GetStringWithoutPathExpansion(onc::network_config::kGUID,
+                                              &new_guid);
+
+    VLOG_IF(1, was_managed && old_guid != new_guid)
+        << "Updating configuration previously managed by policy " << old_guid
+        << " with new policy " << new_guid << ".";
+    VLOG_IF(1, !was_managed) << "Applying policy " << new_guid
+                             << " to previously unmanaged "
+                             << "configuration.";
+
+    if (old_guid == new_guid &&
+        remaining_policies_.find(new_guid) == remaining_policies_.end()) {
+      VLOG(1) << "Not updating existing managed configuration with guid "
+              << new_guid << " because the policy didn't change.";
+    } else {
+      // Delete the entry to ensure that no old configuration remains.
+      // Don't do this if a policy is reapplied (e.g. after reboot) or updated
+      // (i.e. the GUID didn't change), in order to keep implicit state of
+      // Shill like "connected successfully before".
+      if (old_guid == new_guid) {
+        VLOG(1) << "Updating previously managed configuration with the "
+                << "updated policy " << new_guid << ".";
+      } else {
+        DeleteEntry(entry);
+      }
+
+      const base::DictionaryValue* user_settings =
+          ui_data ? ui_data->user_settings() : NULL;
+
+      // Write the new configuration.
+      scoped_ptr<base::DictionaryValue> shill_dictionary =
+          CreateShillConfiguration(
+              profile_, new_guid, new_policy, user_settings);
+      handler_->network_configuration_handler()->CreateConfiguration(
+          *shill_dictionary,
+          base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
+                     handler_),
+          base::Bind(&LogErrorWithDict, FROM_HERE));
+      remaining_policies_.erase(new_guid);
+    }
+  } else if (was_managed) {
+    VLOG(1) << "Removing configuration previously managed by policy "
+            << old_guid << ", because the policy was removed.";
+
+    // Remove the entry, because the network was managed but isn't anymore.
+    // Note: An alternative might be to preserve the user settings, but it's
+    // unclear which values originating the policy should be removed.
+    DeleteEntry(entry);
+  } else {
+    VLOG(2) << "Ignore unmanaged entry.";
+
+    // The entry wasn't managed and doesn't match any current policy. Thus
+    // leave it as it is.
+  }
+}
+
+void ManagedNetworkConfigurationHandlerImpl::PolicyApplicator::DeleteEntry(
+    const std::string& entry) {
+  DBusThreadManager::Get()->GetShillProfileClient()
+      ->DeleteEntry(dbus::ObjectPath(profile_.path),
+                    entry,
+                    base::Bind(&base::DoNothing),
+                    base::Bind(&LogErrorMessage, FROM_HERE));
+}
+
+ManagedNetworkConfigurationHandlerImpl::PolicyApplicator::~PolicyApplicator() {
+  if (!handler_) {
+    LOG(WARNING) << "Handler destructed during policy application to profile "
+                 << profile_.ToDebugString();
+    return;
+  }
+
+  if (remaining_policies_.empty())
+    return;
+
+  VLOG(2) << "Create new managed network configurations in profile"
+          << profile_.ToDebugString() << ".";
+  // All profile entries were compared to policies. |configureGUIDs_| contains
+  // all matched policies. From the remainder of policies, new configurations
+  // have to be created.
+
+  // The relevant policy must have been initialized, otherwise we hadn't Run
+  // this PolicyApplicator.
+  const GuidToPolicyMap& policies = *handler_->GetPoliciesForProfile(profile_);
+
+  for (std::set<std::string>::iterator it = remaining_policies_.begin();
+       it != remaining_policies_.end();
+       ++it) {
+    const base::DictionaryValue* policy = GetByGUID(policies, *it);
+    if (!policy) {
+      LOG(ERROR) << "Policy " << *it << " doesn't exist anymore.";
+      continue;
+    }
+
+    VLOG(1) << "Creating new configuration managed by policy " << *it
+            << " in profile " << profile_.ToDebugString() << ".";
+
+    scoped_ptr<base::DictionaryValue> shill_dictionary =
+        CreateShillConfiguration(
+            profile_, *it, policy, NULL /* no user settings */);
+    handler_->network_configuration_handler()->CreateConfiguration(
+        *shill_dictionary,
+        base::Bind(&ManagedNetworkConfigurationHandlerImpl::OnPolicyApplied,
+                   handler_),
+        base::Bind(&LogErrorWithDict, FROM_HERE));
+  }
+}
+
+}  // namespace chromeos
diff --git a/chromeos/network/managed_network_configuration_handler_impl.h b/chromeos/network/managed_network_configuration_handler_impl.h
new file mode 100644
index 0000000..5baa796
--- /dev/null
+++ b/chromeos/network/managed_network_configuration_handler_impl.h
@@ -0,0 +1,137 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_IMPL_H_
+#define CHROMEOS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_IMPL_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/network/managed_network_configuration_handler.h"
+#include "chromeos/network/network_handler_callbacks.h"
+#include "chromeos/network/network_profile_observer.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace chromeos {
+
+class NetworkConfigurationHandler;
+struct NetworkProfile;
+class NetworkProfileHandler;
+class NetworkStateHandler;
+
+class CHROMEOS_EXPORT ManagedNetworkConfigurationHandlerImpl
+    : public ManagedNetworkConfigurationHandler,
+      public NetworkProfileObserver {
+ public:
+  typedef std::map<std::string, const base::DictionaryValue*> GuidToPolicyMap;
+  typedef std::map<std::string, GuidToPolicyMap> UserToPoliciesMap;
+
+  virtual ~ManagedNetworkConfigurationHandlerImpl();
+
+  // ManagedNetworkConfigurationHandler overrides
+  virtual void AddObserver(NetworkPolicyObserver* observer) OVERRIDE;
+  virtual void RemoveObserver(NetworkPolicyObserver* observer) OVERRIDE;
+
+  virtual void GetProperties(
+      const std::string& service_path,
+      const network_handler::DictionaryResultCallback& callback,
+      const network_handler::ErrorCallback& error_callback) const OVERRIDE;
+
+  virtual void GetManagedProperties(
+      const std::string& userhash,
+      const std::string& service_path,
+      const network_handler::DictionaryResultCallback& callback,
+      const network_handler::ErrorCallback& error_callback) OVERRIDE;
+
+  virtual void SetProperties(
+      const std::string& service_path,
+      const base::DictionaryValue& user_settings,
+      const base::Closure& callback,
+      const network_handler::ErrorCallback& error_callback) const OVERRIDE;
+
+  virtual void CreateConfiguration(
+      const std::string& userhash,
+      const base::DictionaryValue& properties,
+      const network_handler::StringResultCallback& callback,
+      const network_handler::ErrorCallback& error_callback) const OVERRIDE;
+
+  virtual void RemoveConfiguration(
+      const std::string& service_path,
+      const base::Closure& callback,
+      const network_handler::ErrorCallback& error_callback) const OVERRIDE;
+
+  virtual void SetPolicy(onc::ONCSource onc_source,
+                         const std::string& userhash,
+                         const base::ListValue& network_configs_onc) OVERRIDE;
+
+  virtual const base::DictionaryValue* FindPolicyByGUID(
+      const std::string userhash,
+      const std::string& guid,
+      onc::ONCSource* onc_source) const OVERRIDE;
+
+  virtual const base::DictionaryValue* FindPolicyByGuidAndProfile(
+      const std::string& guid,
+      const std::string& profile_path) const OVERRIDE;
+
+  // NetworkProfileObserver overrides
+  virtual void OnProfileAdded(const NetworkProfile& profile) OVERRIDE;
+  virtual void OnProfileRemoved(const NetworkProfile& profile) OVERRIDE;
+
+  NetworkConfigurationHandler* network_configuration_handler() {
+    return network_configuration_handler_;
+  }
+
+ private:
+  friend class ClientCertResolverTest;
+  friend class NetworkHandler;
+  friend class ManagedNetworkConfigurationHandlerTest;
+  class PolicyApplicator;
+
+  ManagedNetworkConfigurationHandlerImpl();
+
+  void Init(NetworkStateHandler* network_state_handler,
+            NetworkProfileHandler* network_profile_handler,
+            NetworkConfigurationHandler* network_configuration_handler);
+
+  void GetManagedPropertiesCallback(
+      const network_handler::DictionaryResultCallback& callback,
+      const network_handler::ErrorCallback& error_callback,
+      const std::string& service_path,
+      const base::DictionaryValue& shill_properties);
+
+  const GuidToPolicyMap* GetPoliciesForUser(const std::string& userhash) const;
+  const GuidToPolicyMap* GetPoliciesForProfile(
+      const NetworkProfile& profile) const;
+
+  void OnPolicyApplied(const std::string& service_path);
+
+  // The DictionaryValues of the nested maps are owned by this class and are
+  // explicitly deleted where necessary. If present, the empty string maps to
+  // the device policy.
+  UserToPoliciesMap policies_by_user_;
+
+  // Local references to the associated handler instances.
+  NetworkStateHandler* network_state_handler_;
+  NetworkProfileHandler* network_profile_handler_;
+  NetworkConfigurationHandler* network_configuration_handler_;
+
+  ObserverList<NetworkPolicyObserver> observers_;
+
+  // For Shill client callbacks
+  base::WeakPtrFactory<ManagedNetworkConfigurationHandlerImpl>
+      weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ManagedNetworkConfigurationHandlerImpl);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_IMPL_H_
diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc
index 4b0a1c7..dfeaebc 100644
--- a/chromeos/network/managed_network_configuration_handler_unittest.cc
+++ b/chromeos/network/managed_network_configuration_handler_unittest.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/network/managed_network_configuration_handler.h"
-
 #include <iostream>
 #include <sstream>
 
@@ -13,7 +11,7 @@
 #include "chromeos/dbus/mock_shill_manager_client.h"
 #include "chromeos/dbus/mock_shill_profile_client.h"
 #include "chromeos/dbus/mock_shill_service_client.h"
-#include "chromeos/dbus/shill_profile_client_stub.h"
+#include "chromeos/network/managed_network_configuration_handler_impl.h"
 #include "chromeos/network/network_configuration_handler.h"
 #include "chromeos/network/network_profile_handler.h"
 #include "chromeos/network/onc/onc_test_utils.h"
@@ -183,7 +181,7 @@
         NetworkConfigurationHandler::InitializeForTest(
             NULL /* no NetworkStateHandler */));
     managed_network_configuration_handler_.reset(
-        new ManagedNetworkConfigurationHandler());
+        new ManagedNetworkConfigurationHandlerImpl());
     managed_network_configuration_handler_->Init(
         NULL /* no NetworkStateHandler */,
         network_profile_handler_.get(),
@@ -259,7 +257,7 @@
   ShillProfileTestClient profiles_stub_;
   scoped_ptr<TestNetworkProfileHandler> network_profile_handler_;
   scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_;
-  scoped_ptr<ManagedNetworkConfigurationHandler>
+  scoped_ptr<ManagedNetworkConfigurationHandlerImpl>
         managed_network_configuration_handler_;
   base::MessageLoop message_loop_;
 
diff --git a/chromeos/network/mock_managed_network_configuration_handler.cc b/chromeos/network/mock_managed_network_configuration_handler.cc
new file mode 100644
index 0000000..1769264
--- /dev/null
+++ b/chromeos/network/mock_managed_network_configuration_handler.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 "chromeos/network/mock_managed_network_configuration_handler.h"
+
+namespace chromeos {
+
+MockManagedNetworkConfigurationHandler::
+    MockManagedNetworkConfigurationHandler() {
+}
+
+MockManagedNetworkConfigurationHandler::
+    ~MockManagedNetworkConfigurationHandler() {
+}
+
+}  // namespace chromeos
diff --git a/chromeos/network/mock_managed_network_configuration_handler.h b/chromeos/network/mock_managed_network_configuration_handler.h
new file mode 100644
index 0000000..0c377b9
--- /dev/null
+++ b/chromeos/network/mock_managed_network_configuration_handler.h
@@ -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.
+
+#ifndef CHROMEOS_NETWORK_MOCK_MANAGED_NETWORK_CONFIGURATION_HANDLER_H_
+#define CHROMEOS_NETWORK_MOCK_MANAGED_NETWORK_CONFIGURATION_HANDLER_H_
+
+#include "base/basictypes.h"
+#include "base/values.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/network/managed_network_configuration_handler.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT MockManagedNetworkConfigurationHandler
+    : public ManagedNetworkConfigurationHandler {
+ public:
+  MockManagedNetworkConfigurationHandler();
+  virtual ~MockManagedNetworkConfigurationHandler();
+
+  // ManagedNetworkConfigurationHandler overrides
+  MOCK_METHOD1(AddObserver, void(NetworkPolicyObserver* observer));
+  MOCK_METHOD1(RemoveObserver, void(NetworkPolicyObserver* observer));
+  MOCK_CONST_METHOD3(
+      GetProperties,
+      void(const std::string& service_path,
+           const network_handler::DictionaryResultCallback& callback,
+           const network_handler::ErrorCallback& error_callback));
+  MOCK_METHOD4(GetManagedProperties,
+               void(const std::string& userhash,
+                    const std::string& service_path,
+                    const network_handler::DictionaryResultCallback& callback,
+                    const network_handler::ErrorCallback& error_callback));
+  MOCK_CONST_METHOD4(
+      SetProperties,
+      void(const std::string& service_path,
+           const base::DictionaryValue& user_settings,
+           const base::Closure& callback,
+           const network_handler::ErrorCallback& error_callback));
+  MOCK_CONST_METHOD4(
+      CreateConfiguration,
+      void(const std::string& userhash,
+           const base::DictionaryValue& properties,
+           const network_handler::StringResultCallback& callback,
+           const network_handler::ErrorCallback& error_callback));
+  MOCK_CONST_METHOD3(
+      RemoveConfiguration,
+      void(const std::string& service_path,
+           const base::Closure& callback,
+           const network_handler::ErrorCallback& error_callback));
+  MOCK_METHOD3(SetPolicy,
+               void(onc::ONCSource onc_source,
+                    const std::string& userhash,
+                    const base::ListValue& network_configs_onc));
+  MOCK_CONST_METHOD3(FindPolicyByGUID,
+                     const base::DictionaryValue*(const std::string userhash,
+                                                  const std::string& guid,
+                                                  onc::ONCSource* onc_source));
+  MOCK_CONST_METHOD2(
+      FindPolicyByGuidAndProfile,
+      const base::DictionaryValue*(const std::string& guid,
+                                   const std::string& profile_path));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockManagedNetworkConfigurationHandler);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_NETWORK_MOCK_MANAGED_NETWORK_CONFIGURATION_HANDLER_H_
diff --git a/chromeos/network/network_cert_migrator.cc b/chromeos/network/network_cert_migrator.cc
index baca3c0..259f2a9 100644
--- a/chromeos/network/network_cert_migrator.cc
+++ b/chromeos/network/network_cert_migrator.cc
@@ -160,17 +160,16 @@
 
   void ClearNssProperty(const std::string& service_path,
                         const std::string& nss_key) {
-    DBusThreadManager::Get()->GetShillServiceClient()
-        ->SetProperty(dbus::ObjectPath(service_path),
-                      nss_key,
-                      base::StringValue(std::string()),
-                      base::Bind(&base::DoNothing),
-                      base::Bind(&network_handler::ShillErrorCallbackFunction,
-                                 "MigrationTask.SetProperty failed",
-                                 service_path,
-                                 network_handler::ErrorCallback()));
-    cert_migrator_->network_state_handler_
-        ->RequestUpdateForNetwork(service_path);
+    DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
+        dbus::ObjectPath(service_path),
+        nss_key,
+        base::StringValue(std::string()),
+        base::Bind(
+            &MigrationTask::NotifyNetworkStateHandler, this, service_path),
+        base::Bind(&network_handler::ShillErrorCallbackFunction,
+                   "MigrationTask.SetProperty failed",
+                   service_path,
+                   network_handler::ErrorCallback()));
   }
 
   scoped_refptr<net::X509Certificate> FindCertificateWithNickname(
@@ -193,16 +192,35 @@
     ca_cert_pems->AppendString(pem_encoded_cert);
     new_properties.SetWithoutPathExpansion(pem_key, ca_cert_pems.release());
 
-    DBusThreadManager::Get()->GetShillServiceClient()
-        ->SetProperties(dbus::ObjectPath(service_path),
-                        new_properties,
-                        base::Bind(&base::DoNothing),
-                        base::Bind(&network_handler::ShillErrorCallbackFunction,
-                                   "MigrationTask.SetProperties failed",
-                                   service_path,
-                                   network_handler::ErrorCallback()));
-    cert_migrator_->network_state_handler_
-        ->RequestUpdateForNetwork(service_path);
+    DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
+        dbus::ObjectPath(service_path),
+        new_properties,
+        base::Bind(
+            &MigrationTask::NotifyNetworkStateHandler, this, service_path),
+        base::Bind(&MigrationTask::LogErrorAndNotifyNetworkStateHandler,
+                   this,
+                   service_path));
+  }
+
+  void LogErrorAndNotifyNetworkStateHandler(const std::string& service_path,
+                                            const std::string& error_name,
+                                            const std::string& error_message) {
+    network_handler::ShillErrorCallbackFunction(
+        "MigrationTask.SetProperties failed",
+        service_path,
+        network_handler::ErrorCallback(),
+        error_name,
+        error_message);
+    NotifyNetworkStateHandler(service_path);
+  }
+
+  void NotifyNetworkStateHandler(const std::string& service_path) {
+    if (!cert_migrator_) {
+      VLOG(2) << "NetworkCertMigrator already destroyed. Aborting migration.";
+      return;
+    }
+    cert_migrator_->network_state_handler_->RequestUpdateForNetwork(
+        service_path);
   }
 
  private:
diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc
index 81f9759..f8acf26 100644
--- a/chromeos/network/network_configuration_handler.cc
+++ b/chromeos/network/network_configuration_handler.cc
@@ -63,9 +63,20 @@
     properties_copy->SetStringWithoutPathExpansion(
         flimflam::kNameProperty, name);
   }
-  network_handler::GetPropertiesCallback(
-      callback, error_callback, service_path, call_status,
-      *properties_copy.get());
+  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());
+    }
+  } else if (!callback.is_null()) {
+    callback.Run(service_path, *properties_copy.get());
+  }
 }
 
 void SetNetworkProfileErrorCallback(
@@ -88,7 +99,6 @@
       key == flimflam::kPassphraseProperty ||
       key == flimflam::kOpenVPNOTPProperty ||
       key == flimflam::kEapPrivateKeyProperty ||
-      key == flimflam::kEapPrivateKeyPasswordProperty ||
       key == flimflam::kEapPinProperty ||
       key == flimflam::kApnPasswordProperty;
 }
diff --git a/chromeos/network/network_configuration_handler.h b/chromeos/network/network_configuration_handler.h
index f1ee856..ee96639 100644
--- a/chromeos/network/network_configuration_handler.h
+++ b/chromeos/network/network_configuration_handler.h
@@ -82,11 +82,12 @@
                        const base::Closure& callback,
                        const network_handler::ErrorCallback& error_callback);
 
-  // Creates a network with the given properties in the active Shill profile,
-  // and returns the new service_path to |callback| if successful. See note on
-  // |callback| and |error_callback|, in class description above.
-  // This may also be used to update an existing matching configuration, see
-  // Shill documentation for Manager.ConfigureService and Manger.GetService.
+  // Creates a network with the given |properties| in the specified Shill
+  // profile, and returns the new service_path to |callback| if successful.
+  // kProfileProperty must be set in |properties|. See note on |callback| and
+  // |error_callback|, in the class description above. This may also be used to
+  // update an existing matching configuration, see Shill documentation for
+  // Manager.ConfigureServiceForProfile.
   void CreateConfiguration(
       const base::DictionaryValue& properties,
       const network_handler::StringResultCallback& callback,
@@ -111,6 +112,7 @@
       NetworkStateHandler* network_state_handler);
 
  protected:
+  friend class ClientCertResolverTest;
   friend class NetworkHandler;
   friend class NetworkConfigurationHandlerTest;
   friend class NetworkConfigurationHandlerStubTest;
diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc
index 842d4f5..f27ff4f 100644
--- a/chromeos/network/network_connection_handler.cc
+++ b/chromeos/network/network_connection_handler.cc
@@ -57,8 +57,8 @@
 
 bool NetworkRequiresActivation(const NetworkState* network) {
   return (network->type() == flimflam::kTypeCellular &&
-          (network->activation_state() != flimflam::kActivationStateActivated ||
-           network->cellular_out_of_credits()));
+      ((network->activation_state() != flimflam::kActivationStateActivated &&
+        network->activation_state() != flimflam::kActivationStateUnknown)));
 }
 
 bool VPNIsConfigured(const std::string& service_path,
@@ -93,7 +93,7 @@
     provider_properties.GetBooleanWithoutPathExpansion(
         flimflam::kL2tpIpsecPskRequiredProperty, &passphrase_required);
     if (passphrase_required) {
-      NET_LOG_EVENT("VPN: Passphrase Required", service_path);
+      NET_LOG_EVENT("VPN: PSK Required", service_path);
       return false;
     }
     NET_LOG_EVENT("VPN Is Configured", service_path);
@@ -334,6 +334,10 @@
   return pending_requests_.count(service_path) != 0;
 }
 
+bool NetworkConnectionHandler::HasPendingConnectRequest() {
+  return pending_requests_.size() > 0;
+}
+
 void NetworkConnectionHandler::NetworkListChanged() {
   CheckAllPendingRequests();
 }
diff --git a/chromeos/network/network_connection_handler.h b/chromeos/network/network_connection_handler.h
index 31fcfc5..4b363ef 100644
--- a/chromeos/network/network_connection_handler.h
+++ b/chromeos/network/network_connection_handler.h
@@ -117,6 +117,9 @@
   // has not completed (i.e. success or error callback has been called).
   bool HasConnectingNetwork(const std::string& service_path);
 
+  // Returns true if there are any pending connect requests.
+  bool HasPendingConnectRequest();
+
   // NetworkStateHandlerObserver
   virtual void NetworkListChanged() OVERRIDE;
   virtual void NetworkPropertiesUpdated(const NetworkState* network) OVERRIDE;
diff --git a/chromeos/network/network_event_log.cc b/chromeos/network/network_event_log.cc
index 96e3c1a..a4f359d 100644
--- a/chromeos/network/network_event_log.cc
+++ b/chromeos/network/network_event_log.cc
@@ -8,6 +8,7 @@
 
 #include "base/files/file_path.h"
 #include "base/i18n/time_formatting.h"
+#include "base/json/json_string_value_serializer.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -25,6 +26,7 @@
 class NetworkEventLog;
 NetworkEventLog* g_network_event_log = NULL;
 size_t g_max_network_event_log_entries = 4000;
+const char* kLogLevelName[] = {"Error", "User", "Event", "Debug"};
 
 struct LogEntry {
   LogEntry(const std::string& file,
@@ -37,9 +39,11 @@
                        bool show_file,
                        bool show_desc,
                        bool format_html) const;
+  void ToDictionary(base::DictionaryValue*) const;
 
   std::string GetNormalText(bool show_desc) const;
   std::string GetHtmlText(bool show_desc) const;
+  std::string GetAsJSON() const;
 
   void SendToVLogOrErrorLog() const;
 
@@ -65,8 +69,7 @@
       event(event),
       description(description),
       time(base::Time::Now()),
-      count(1) {
-}
+      count(1) {}
 
 std::string LogEntry::ToString(bool show_time,
                                bool show_file,
@@ -74,10 +77,10 @@
                                bool format_html) const {
   std::string line;
   if (show_time)
-    line += "[" + UTF16ToUTF8(base::TimeFormatShortDateAndTime(time)) + "] ";
+    line += "[" + UTF16ToUTF8(base::TimeFormatTimeOfDay(time)) + "] ";
   if (show_file) {
     std::string filestr = format_html ? net::EscapeForHTML(file) : file;
-    line += base::StringPrintf("%s:%d ", filestr.c_str(), file_line);
+    line += base::StringPrintf("%s:%d ", file.c_str(), file_line);
   }
   line += format_html ? GetHtmlText(show_desc) : GetNormalText(show_desc);
   if (count > 1)
@@ -85,6 +88,26 @@
   return line;
 }
 
+void LogEntry::ToDictionary(base::DictionaryValue* output) const {
+  output->SetString("timestamp", base::TimeFormatShortDateAndTime(time));
+  output->SetString("level", kLogLevelName[log_level]);
+  output->SetString("file",
+                    base::StringPrintf("%s:%d ", file.c_str(), file_line));
+  output->SetString("event", event);
+  output->SetString("description", description);
+}
+
+std::string LogEntry::GetAsJSON() const {
+  base::DictionaryValue entry;
+  ToDictionary(&entry);
+  std::string json;
+  JSONStringValueSerializer serializer(&json);
+  if (!serializer.Serialize(entry)) {
+    LOG(ERROR) << "Failed to serialize to JSON";
+  }
+  return json;
+}
+
 std::string LogEntry::GetNormalText(bool show_desc) const {
   std::string text = event;
   if (show_desc && !description.empty())
@@ -128,21 +151,23 @@
 
 bool LogEntry::ContentEquals(const LogEntry& other) const {
   return file == other.file &&
-      file_line == other.file_line &&
-      event == other.event &&
-      description == other.description;
+         file_line == other.file_line &&
+         event == other.event &&
+         description == other.description;
 }
 
 void GetFormat(const std::string& format_string,
                bool* show_time,
                bool* show_file,
                bool* show_desc,
-               bool* format_html) {
+               bool* format_html,
+               bool* format_json) {
   base::StringTokenizer tokens(format_string, ",");
   *show_time = false;
   *show_file = false;
   *show_desc = false;
   *format_html = false;
+  *format_json = false;
   while (tokens.GetNext()) {
     std::string tok(tokens.token());
     if (tok == "time")
@@ -153,6 +178,8 @@
       *show_desc = true;
     if (tok == "html")
       *format_html = true;
+    if (tok == "json")
+      *format_json = true;
   }
 }
 
@@ -194,8 +221,8 @@
     // Remove the first (oldest) non-error entry, or the oldest entry if more
     // than half the entries are errors.
     size_t error_count = 0;
-    for (LogEntryList::iterator iter = entries_.begin();
-         iter != entries_.end(); ++iter) {
+    for (LogEntryList::iterator iter = entries_.begin(); iter != entries_.end();
+         ++iter) {
       if (iter->log_level != LOG_LEVEL_ERROR) {
         entries_.erase(iter);
         break;
@@ -218,10 +245,12 @@
   if (entries_.empty())
     return "No Log Entries.";
 
-  bool show_time, show_file, show_desc, format_html;
-  GetFormat(format, &show_time, &show_file, &show_desc, &format_html);
+  bool show_time, show_file, show_desc, format_html, format_json;
+  GetFormat(
+      format, &show_time, &show_file, &show_desc, &format_html, &format_json);
 
   std::string result;
+  base::ListValue log_entries;
   if (order == OLDEST_FIRST) {
     size_t offset = 0;
     if (max_events > 0 && max_events < entries_.size()) {
@@ -230,7 +259,8 @@
       size_t shown_events = 0;
       size_t num_entries = 0;
       for (LogEntryList::const_reverse_iterator riter = entries_.rbegin();
-           riter != entries_.rend(); ++riter) {
+           riter != entries_.rend();
+           ++riter) {
         ++num_entries;
         if (riter->log_level > max_level)
           continue;
@@ -240,29 +270,46 @@
       offset = entries_.size() - num_entries;
     }
     for (LogEntryList::const_iterator iter = entries_.begin();
-         iter != entries_.end(); ++iter) {
+         iter != entries_.end();
+         ++iter) {
       if (offset > 0) {
         --offset;
         continue;
       }
       if (iter->log_level > max_level)
         continue;
-      result += (*iter).ToString(show_time, show_file, show_desc, format_html);
-      result += "\n";
+      if (format_json) {
+        log_entries.AppendString((*iter).GetAsJSON());
+      } else {
+        result +=
+            (*iter).ToString(show_time, show_file, show_desc, format_html);
+        result += "\n";
+      }
     }
   } else {
     size_t nlines = 0;
     // Iterate backwards through the list to show the most recent entries first.
     for (LogEntryList::const_reverse_iterator riter = entries_.rbegin();
-         riter != entries_.rend(); ++riter) {
+         riter != entries_.rend();
+         ++riter) {
       if (riter->log_level > max_level)
         continue;
-      result += (*riter).ToString(show_time, show_file, show_desc, format_html);
-      result += "\n";
+      if (format_json) {
+        log_entries.AppendString((*riter).GetAsJSON());
+      } else {
+        result +=
+            (*riter).ToString(show_time, show_file, show_desc, format_html);
+        result += "\n";
+      }
       if (max_events > 0 && ++nlines >= max_events)
         break;
     }
   }
+  if (format_json) {
+    JSONStringValueSerializer serializer(&result);
+    serializer.Serialize(log_entries);
+  }
+
   return result;
 }
 
@@ -281,15 +328,11 @@
   g_network_event_log = NULL;
 }
 
-bool IsInitialized() {
-  return g_network_event_log != NULL;
-}
+bool IsInitialized() { return g_network_event_log != NULL; }
 
 namespace internal {
 
-size_t GetMaxLogEntries() {
-  return g_max_network_event_log_entries;
-}
+size_t GetMaxLogEntries() { return g_max_network_event_log_entries; }
 
 void SetMaxLogEntries(size_t max_entries) {
   g_max_network_event_log_entries = max_entries;
diff --git a/chromeos/network/network_event_log.h b/chromeos/network/network_event_log.h
index 1957f20..2bdb451 100644
--- a/chromeos/network/network_event_log.h
+++ b/chromeos/network/network_event_log.h
@@ -80,8 +80,11 @@
 //  "file" - Include file and line number.
 //  "desc" - Include the description.
 //  "html" - Include html tags.
+//  "json" - Return as JSON format
 // Only events with |log_level| <= |max_level| are included in the output.
 // If |max_events| > 0, limits how many events are output.
+// If |json| is specified, returns a JSON list of dictionaries containing time,
+// level, file, event, and description.
 CHROMEOS_EXPORT std::string GetAsString(StringOrder order,
                                         const std::string& format,
                                         LogLevel max_level,
diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc
index ae272fa..47606ae 100644
--- a/chromeos/network/network_handler.cc
+++ b/chromeos/network/network_handler.cc
@@ -6,8 +6,9 @@
 
 #include "base/threading/worker_pool.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/network/client_cert_resolver.h"
 #include "chromeos/network/geolocation_handler.h"
-#include "chromeos/network/managed_network_configuration_handler.h"
+#include "chromeos/network/managed_network_configuration_handler_impl.h"
 #include "chromeos/network/network_cert_migrator.h"
 #include "chromeos/network/network_configuration_handler.h"
 #include "chromeos/network/network_connection_handler.h"
@@ -23,7 +24,8 @@
 
 static NetworkHandler* g_network_handler = NULL;
 
-NetworkHandler::NetworkHandler() {
+NetworkHandler::NetworkHandler()
+    : message_loop_(base::MessageLoopProxy::current()) {
   CHECK(DBusThreadManager::IsInitialized());
 
   network_event_log::Initialize();
@@ -31,11 +33,13 @@
   network_state_handler_.reset(new NetworkStateHandler());
   network_device_handler_.reset(new NetworkDeviceHandler());
   network_profile_handler_.reset(new NetworkProfileHandler());
-  if (CertLoader::IsInitialized())
-    network_cert_migrator_.reset(new NetworkCertMigrator());
   network_configuration_handler_.reset(new NetworkConfigurationHandler());
   managed_network_configuration_handler_.reset(
-      new ManagedNetworkConfigurationHandler());
+      new ManagedNetworkConfigurationHandlerImpl());
+  if (CertLoader::IsInitialized()) {
+    network_cert_migrator_.reset(new NetworkCertMigrator());
+    client_cert_resolver_.reset(new ClientCertResolver());
+  }
   network_connection_handler_.reset(new NetworkConnectionHandler());
   network_sms_handler_.reset(new NetworkSmsHandler());
   geolocation_handler_.reset(new GeolocationHandler());
@@ -48,8 +52,6 @@
 void NetworkHandler::Init() {
   network_state_handler_->InitShillPropertyHandler();
   network_profile_handler_->Init(network_state_handler_.get());
-  if (network_cert_migrator_)
-    network_cert_migrator_->Init(network_state_handler_.get());
   network_configuration_handler_->Init(network_state_handler_.get());
   managed_network_configuration_handler_->Init(
       network_state_handler_.get(),
@@ -57,6 +59,12 @@
       network_configuration_handler_.get());
   network_connection_handler_->Init(network_state_handler_.get(),
                                     network_configuration_handler_.get());
+  if (network_cert_migrator_)
+    network_cert_migrator_->Init(network_state_handler_.get());
+  if (client_cert_resolver_) {
+    client_cert_resolver_->Init(network_state_handler_.get(),
+                                managed_network_configuration_handler_.get());
+  }
   network_sms_handler_->Init();
   geolocation_handler_->Init();
 }
diff --git a/chromeos/network/network_handler.h b/chromeos/network/network_handler.h
index a791f9e..2197529 100644
--- a/chromeos/network/network_handler.h
+++ b/chromeos/network/network_handler.h
@@ -6,13 +6,17 @@
 #define CHROMEOS_NETWORK_NETWORK_HANDLER_H_
 
 #include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "chromeos/chromeos_export.h"
 
 namespace chromeos {
 
+class ClientCertResolver;
 class GeolocationHandler;
 class ManagedNetworkConfigurationHandler;
+class ManagedNetworkConfigurationHandlerImpl;
 class NetworkCertMigrator;
 class NetworkConfigurationHandler;
 class NetworkConnectionHandler;
@@ -38,6 +42,10 @@
   // Returns true if the global instance has been initialized.
   static bool IsInitialized();
 
+  // Returns the MessageLoopProxy for posting NetworkHandler calls from
+  // other threads.
+  base::MessageLoopProxy* message_loop() { return message_loop_.get(); }
+
   // Do not use these accessors within this module; all dependencies should be
   // explicit so that classes can be constructed explicitly in tests without
   // NetworkHandler.
@@ -57,13 +65,15 @@
   void Init();
 
   // The order of these determines the (inverse) destruction order.
+  scoped_refptr<base::MessageLoopProxy> message_loop_;
   scoped_ptr<NetworkStateHandler> network_state_handler_;
   scoped_ptr<NetworkDeviceHandler> network_device_handler_;
   scoped_ptr<NetworkProfileHandler> network_profile_handler_;
-  scoped_ptr<NetworkCertMigrator> network_cert_migrator_;
   scoped_ptr<NetworkConfigurationHandler> network_configuration_handler_;
-  scoped_ptr<ManagedNetworkConfigurationHandler>
+  scoped_ptr<ManagedNetworkConfigurationHandlerImpl>
       managed_network_configuration_handler_;
+  scoped_ptr<NetworkCertMigrator> network_cert_migrator_;
+  scoped_ptr<ClientCertResolver> client_cert_resolver_;
   scoped_ptr<NetworkConnectionHandler> network_connection_handler_;
   scoped_ptr<NetworkSmsHandler> network_sms_handler_;
   scoped_ptr<GeolocationHandler> geolocation_handler_;
diff --git a/chromeos/network/network_handler_callbacks.cc b/chromeos/network/network_handler_callbacks.cc
index 0dcc55f..e34d549 100644
--- a/chromeos/network/network_handler_callbacks.cc
+++ b/chromeos/network/network_handler_callbacks.cc
@@ -76,10 +76,9 @@
         network_handler::CreateErrorData(path,
                                          kDBusFailedError,
                                          kDBusFailedErrorMessage));
-    // Because network services are added and removed frequently, we will see
-    // these failures regularly, so log as events not errors.
-    NET_LOG_EVENT(base::StringPrintf("GetProperties failed: %d", call_status),
-                  path);
+    NET_LOG_ERROR(
+        base::StringPrintf("GetProperties failed. Status: %d", call_status),
+        path);
     if (!error_callback.is_null())
       error_callback.Run(kDBusFailedError, error_data.Pass());
   } else if (!callback.is_null()) {
diff --git a/chromeos/network/network_handler_callbacks.h b/chromeos/network/network_handler_callbacks.h
index 92fb1d1..f939ef3 100644
--- a/chromeos/network/network_handler_callbacks.h
+++ b/chromeos/network/network_handler_callbacks.h
@@ -19,6 +19,8 @@
 namespace chromeos {
 namespace network_handler {
 
+CHROMEOS_EXPORT extern const char kDBusFailedError[];
+CHROMEOS_EXPORT extern const char kDBusFailedErrorMessage[];
 CHROMEOS_EXPORT extern const char kErrorName[];
 CHROMEOS_EXPORT extern const char kErrorDetail[];
 CHROMEOS_EXPORT extern const char kDbusErrorName[];
diff --git a/chromeos/network/network_policy_observer.h b/chromeos/network/network_policy_observer.h
new file mode 100644
index 0000000..c51982e
--- /dev/null
+++ b/chromeos/network/network_policy_observer.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 CHROMEOS_NETWORK_NETWORK_POLICY_OBSERVER_H_
+#define CHROMEOS_NETWORK_NETWORK_POLICY_OBSERVER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace chromeos {
+
+class NetworkPolicyObserver {
+ public:
+  virtual void PolicyApplied(const std::string& service_path) = 0;
+
+ protected:
+  virtual ~NetworkPolicyObserver() {};
+
+ private:
+  DISALLOW_ASSIGN(NetworkPolicyObserver);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_NETWORK_NETWORK_POLICY_OBSERVER_H_
diff --git a/chromeos/network/network_profile.cc b/chromeos/network/network_profile.cc
index bfdfd90..f01b268 100644
--- a/chromeos/network/network_profile.cc
+++ b/chromeos/network/network_profile.cc
@@ -10,7 +10,6 @@
 namespace chromeos {
 
 std::string NetworkProfile::ToDebugString() const {
-  std::string result;
   if (type() == NetworkProfile::TYPE_SHARED) {
     return base::StringPrintf("NetworkProfile(SHARED, %s)",
                               path.c_str());
diff --git a/chromeos/network/network_profile_handler.h b/chromeos/network/network_profile_handler.h
index 15bb0fd..15f5228 100644
--- a/chromeos/network/network_profile_handler.h
+++ b/chromeos/network/network_profile_handler.h
@@ -60,6 +60,7 @@
   static const char kSharedProfilePath[];
 
  protected:
+  friend class ClientCertResolverTest;
   friend class NetworkHandler;
   NetworkProfileHandler();
 
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc
index 0e7aa26..0d0c790 100644
--- a/chromeos/network/network_state.cc
+++ b/chromeos/network/network_state.cc
@@ -117,8 +117,6 @@
     if (error_ == kErrorUnknown)
       error_.clear();
     return true;
-  } else if (key == shill::kErrorDetailsProperty) {
-    return GetStringValue(key, value, &error_details_);
   } else if (key == IPConfigProperty(flimflam::kAddressProperty)) {
     return GetStringValue(key, value, &ip_address_);
   } else if (key == IPConfigProperty(flimflam::kGatewayProperty)) {
@@ -132,6 +130,24 @@
     return true;
   } else if (key == IPConfigProperty(flimflam::kPrefixlenProperty)) {
     return GetIntegerValue(key, value, &prefix_length_);
+  } else if (key == IPConfigProperty(
+      shill::kWebProxyAutoDiscoveryUrlProperty)) {
+    std::string url_string;
+    if (!GetStringValue(key, value, &url_string))
+      return false;
+    if (url_string.empty()) {
+      web_proxy_auto_discovery_url_ = GURL();
+    } else {
+      GURL gurl(url_string);
+      if (!gurl.is_valid()) {
+        web_proxy_auto_discovery_url_ = gurl;
+      } else {
+        NET_LOG_ERROR("Invalid WebProxyAutoDiscoveryUrl: " + url_string,
+                      path());
+        web_proxy_auto_discovery_url_ = GURL();
+      }
+    }
+    return true;
   } else if (key == flimflam::kActivationStateProperty) {
     return GetStringValue(key, value, &activation_state_);
   } else if (key == flimflam::kRoamingStateProperty) {
@@ -227,8 +243,6 @@
 
   dictionary->SetStringWithoutPathExpansion(flimflam::kErrorProperty,
                                             error_);
-  dictionary->SetStringWithoutPathExpansion(shill::kErrorDetailsProperty,
-                                            error_details_);
 
   // IPConfig properties
   base::DictionaryValue* ipconfig_properties = new base::DictionaryValue;
@@ -242,7 +256,9 @@
                                                name_servers);
   ipconfig_properties->SetIntegerWithoutPathExpansion(
       flimflam::kPrefixlenProperty, prefix_length_);
-
+  ipconfig_properties->SetStringWithoutPathExpansion(
+      shill::kWebProxyAutoDiscoveryUrlProperty,
+      web_proxy_auto_discovery_url_.spec());
   dictionary->SetWithoutPathExpansion(shill::kIPConfigProperty,
                                       ipconfig_properties);
 
@@ -335,13 +351,13 @@
 std::string NetworkState::GetNameFromProperties(
     const std::string& service_path,
     const base::DictionaryValue& properties) {
-  std::string name;
+  std::string name, hex_ssid;
   properties.GetStringWithoutPathExpansion(flimflam::kNameProperty, &name);
-
-  std::string hex_ssid;
   properties.GetStringWithoutPathExpansion(flimflam::kWifiHexSsid, &hex_ssid);
 
   if (hex_ssid.empty()) {
+    if (name.empty())
+      return name;
     // Validate name for UTF8.
     std::string valid_ssid = ValidateUTF8(name);
     if (valid_ssid != name) {
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h
index 1e0c470..5752057 100644
--- a/chromeos/network/network_state.h
+++ b/chromeos/network/network_state.h
@@ -12,6 +12,7 @@
 #include "chromeos/network/managed_state.h"
 #include "chromeos/network/network_ui_data.h"
 #include "chromeos/network/onc/onc_constants.h"
+#include "url/gurl.h"
 
 namespace chromeos {
 
@@ -46,7 +47,6 @@
   const std::string& connection_state() const { return connection_state_; }
   const std::string& profile_path() const { return profile_path_; }
   const std::string& error() const { return error_; }
-  const std::string& error_details() const { return error_details_; }
   bool auto_connect() const { return auto_connect_; }
   bool favorite() const { return favorite_; }
   int priority() const { return priority_; }
@@ -57,6 +57,9 @@
   const std::string& gateway() const { return gateway_; }
   const std::vector<std::string>& dns_servers() const { return dns_servers_; }
   const int prefix_length() const { return prefix_length_; }
+  const GURL& web_proxy_auto_discovery_url() const {
+    return web_proxy_auto_discovery_url_;
+  }
   // Wireless property accessors
   int signal_strength() const { return signal_strength_; }
   bool connectable() const { return connectable_; }
@@ -129,7 +132,6 @@
   std::string connection_state_;
   std::string profile_path_;
   std::string error_;
-  std::string error_details_;
   bool auto_connect_;
   bool favorite_;
   int priority_;
@@ -144,6 +146,7 @@
   std::string gateway_;
   std::vector<std::string> dns_servers_;
   int prefix_length_;
+  GURL web_proxy_auto_discovery_url_;
   // Wireless properties
   int signal_strength_;
   bool connectable_;
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index 04b6e28..106537f 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -345,16 +345,14 @@
                          shill_property_handler_->AsWeakPtr()));
 }
 
-bool NetworkStateHandler::RequestUpdateForNetwork(
+void NetworkStateHandler::RequestUpdateForNetwork(
     const std::string& service_path) {
   NetworkState* network = GetModifiableNetworkState(service_path);
-  if (!network)
-    return false;  // Only request an update for known networks.
-  network->set_update_requested(true);
+  if (network)
+    network->set_update_requested(true);
   NET_LOG_EVENT("RequestUpdate", service_path);
   shill_property_handler_->RequestProperties(
       ManagedState::MANAGED_TYPE_NETWORK, service_path);
-  return true;
 }
 
 void NetworkStateHandler::RequestUpdateForAllNetworks() {
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h
index ab99e33..3ae7126 100644
--- a/chromeos/network/network_state_handler.h
+++ b/chromeos/network/network_state_handler.h
@@ -179,12 +179,13 @@
   void ConnectToBestWifiNetwork();
 
   // Request an update for an existing NetworkState, e.g. after configuring
-  // a network. This is a no-op if an update request is already pending.
-  // Returns true if the network exists and an update is requested or pending.
+  // a network. This is a no-op if an update request is already pending. To
+  // ensure that a change is picked up, this must be called after Shill
+  // acknowledged it (e.g. in the callback of a SetProperties).
   // When the properties are received, NetworkPropertiesUpdated will be
   // signaled for each member of |observers_|, regardless of whether any
   // properties actually changed.
-  bool RequestUpdateForNetwork(const std::string& service_path);
+  void RequestUpdateForNetwork(const std::string& service_path);
 
   // Request an update for all existing NetworkState entries, e.g. after
   // loading an ONC configuration file that may have updated one or more
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc
index 419ba8b..e32e4a5 100644
--- a/chromeos/network/network_state_handler_unittest.cc
+++ b/chromeos/network/network_state_handler_unittest.cc
@@ -376,8 +376,8 @@
   // Request an update for kShillManagerClientStubDefaultWireless.
   EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(
       kShillManagerClientStubDefaultWireless));
-  EXPECT_TRUE(network_state_handler_->RequestUpdateForNetwork(
-      kShillManagerClientStubDefaultWireless));
+  network_state_handler_->RequestUpdateForNetwork(
+      kShillManagerClientStubDefaultWireless);
   message_loop_.RunUntilIdle();
   EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(
       kShillManagerClientStubDefaultWireless));
diff --git a/chromeos/network/onc/onc_constants.cc b/chromeos/network/onc/onc_constants.cc
index 1a24cfe..16ae4ff 100644
--- a/chromeos/network/onc/onc_constants.cc
+++ b/chromeos/network/onc/onc_constants.cc
@@ -91,6 +91,12 @@
 const char kSupportNetworkScan[] = "SupportNetworkScan";
 }  // namespace cellular
 
+namespace cellular_provider {
+const char kCode[] = "Code";
+const char kCountry[] = "Country";
+const char kName[] = "Name";
+}  // namespace cellular_provider
+
 namespace connection_state {
 const char kConnected[] = "Connected";
 const char kConnecting[] = "Connecting";
diff --git a/chromeos/network/onc/onc_constants.h b/chromeos/network/onc/onc_constants.h
index c730a10..b0ab330 100644
--- a/chromeos/network/onc/onc_constants.h
+++ b/chromeos/network/onc/onc_constants.h
@@ -100,8 +100,6 @@
 CHROMEOS_EXPORT extern const char kMIN[];
 CHROMEOS_EXPORT extern const char kModelID[];
 CHROMEOS_EXPORT extern const char kNetworkTechnology[];
-CHROMEOS_EXPORT extern const char kOperatorCode[];
-CHROMEOS_EXPORT extern const char kOperatorName[];
 CHROMEOS_EXPORT extern const char kPRLVersion[];
 CHROMEOS_EXPORT extern const char kProviderRequiresRoaming[];
 CHROMEOS_EXPORT extern const char kRoamingState[];
@@ -113,6 +111,12 @@
 CHROMEOS_EXPORT extern const char kSupportNetworkScan[];
 }  // namespace cellular
 
+namespace cellular_provider {
+CHROMEOS_EXPORT extern const char kCode[];
+CHROMEOS_EXPORT extern const char kCountry[];
+CHROMEOS_EXPORT extern const char kName[];
+}  // namespace cellular_provider
+
 namespace connection_state {
 CHROMEOS_EXPORT extern const char kConnected[];
 CHROMEOS_EXPORT extern const char kConnecting[];
diff --git a/chromeos/network/onc/onc_normalizer.cc b/chromeos/network/onc/onc_normalizer.cc
index 3a3ada6..f7513a8 100644
--- a/chromeos/network/onc/onc_normalizer.cc
+++ b/chromeos/network/onc/onc_normalizer.cc
@@ -70,7 +70,7 @@
 namespace {
 
 void RemoveEntryUnless(base::DictionaryValue* dict,
-                       const std::string path,
+                       const std::string& path,
                        bool condition) {
   if (!condition)
     dict->RemoveWithoutPathExpansion(path, NULL);
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index d4c0bd1..b70b579 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -203,6 +203,13 @@
   { NULL }
 };
 
+const OncFieldSignature cellular_provider_fields[] = {
+  { cellular_provider::kCode, &kStringSignature },
+  { cellular_provider::kCountry, &kStringSignature },
+  { cellular_provider::kName, &kStringSignature },
+  { NULL }
+};
+
 const OncFieldSignature cellular_with_state_fields[] = {
   { kRecommended, &kRecommendedSignature },
   { cellular::kActivateOverNonCellularNetwork, &kBoolSignature },
@@ -215,7 +222,7 @@
   { cellular::kFirmwareRevision, &kStringSignature },
   { cellular::kFoundNetworks, &kStringSignature },
   { cellular::kHardwareRevision, &kStringSignature },
-  { cellular::kHomeProvider, &kStringSignature },
+  { cellular::kHomeProvider, &kCellularProviderSignature },
   { cellular::kICCID, &kStringSignature },
   { cellular::kIMEI, &kStringSignature },
   { cellular::kIMSI, &kStringSignature },
@@ -225,13 +232,11 @@
   { cellular::kMIN, &kStringSignature },
   { cellular::kModelID, &kStringSignature },
   { cellular::kNetworkTechnology, &kStringSignature },
-  { cellular::kOperatorCode, &kStringSignature },
-  { cellular::kOperatorName, &kStringSignature },
   { cellular::kPRLVersion, &kStringSignature },
   { cellular::kProviderRequiresRoaming, &kStringSignature },
   { cellular::kRoamingState, &kStringSignature },
   { cellular::kSelectedNetwork, &kStringSignature },
-  { cellular::kServingOperator, &kStringSignature },
+  { cellular::kServingOperator, &kCellularProviderSignature },
   { cellular::kSIMLockStatus, &kStringSignature },
   { cellular::kSIMPresent, &kStringSignature },
   { cellular::kSupportedCarriers, &kStringSignature },
@@ -362,6 +367,9 @@
 const OncValueSignature kCellularWithStateSignature = {
   Value::TYPE_DICTIONARY, cellular_with_state_fields, NULL
 };
+const OncValueSignature kCellularProviderSignature = {
+  Value::TYPE_DICTIONARY, cellular_provider_fields, NULL
+};
 
 const OncFieldSignature* GetFieldSignature(const OncValueSignature& signature,
                                            const std::string& onc_field_name) {
diff --git a/chromeos/network/onc/onc_signature.h b/chromeos/network/onc/onc_signature.h
index ef0cc31..0d95641 100644
--- a/chromeos/network/onc/onc_signature.h
+++ b/chromeos/network/onc/onc_signature.h
@@ -60,6 +60,7 @@
 CHROMEOS_EXPORT extern const OncValueSignature kNetworkWithStateSignature;
 CHROMEOS_EXPORT extern const OncValueSignature kWiFiWithStateSignature;
 CHROMEOS_EXPORT extern const OncValueSignature kCellularWithStateSignature;
+CHROMEOS_EXPORT extern const OncValueSignature kCellularProviderSignature;
 
 }  // namespace onc
 }  // namespace chromeos
diff --git a/chromeos/network/onc/onc_translation_tables.cc b/chromeos/network/onc/onc_translation_tables.cc
index d010752..5ee30dd 100644
--- a/chromeos/network/onc/onc_translation_tables.cc
+++ b/chromeos/network/onc/onc_translation_tables.cc
@@ -110,6 +110,13 @@
   { NULL }
 };
 
+const FieldTranslationEntry cellular_provider_fields[] = {
+  { cellular_provider::kCode, flimflam::kOperatorCodeKey },
+  { cellular_provider::kCountry, flimflam::kOperatorCountryKey },
+  { cellular_provider::kName, flimflam::kOperatorNameKey },
+  { NULL }
+};
+
 const FieldTranslationEntry cellular_with_state_fields[] = {
   { cellular::kActivateOverNonCellularNetwork,
     shill::kActivateOverNonCellularNetworkProperty },
@@ -132,8 +139,6 @@
   { cellular::kMIN, flimflam::kMinProperty },
   { cellular::kModelID, flimflam::kModelIDProperty },
   { cellular::kNetworkTechnology, flimflam::kNetworkTechnologyProperty },
-  { cellular::kOperatorCode, flimflam::kOperatorCodeProperty },
-  { cellular::kOperatorName, flimflam::kOperatorNameProperty },
   { cellular::kPRLVersion, flimflam::kPRLVersionProperty },
   { cellular::kProviderRequiresRoaming,
     shill::kProviderRequiresRoamingProperty },
@@ -170,6 +175,7 @@
   { &kVPNSignature, vpn_fields },
   { &kWiFiSignature, wifi_fields },
   { &kWiFiWithStateSignature, wifi_fields },
+  { &kCellularProviderSignature, cellular_provider_fields },
   { &kCellularWithStateSignature, cellular_with_state_fields },
   { &kNetworkWithStateSignature, network_fields },
   { &kNetworkConfigurationSignature, network_fields },
@@ -199,6 +205,7 @@
   { wifi::kWPA_PSK, flimflam::kSecurityPsk },
   { wifi::kWPA_EAP, flimflam::kSecurity8021x },
   { wifi::kWPA_PSK, flimflam::kSecurityRsn },
+  { wifi::kWPA_PSK, flimflam::kSecurityWpa },
   { NULL }
 };
 
diff --git a/chromeos/network/onc/onc_translator_shill_to_onc.cc b/chromeos/network/onc/onc_translator_shill_to_onc.cc
index 017c434..7782aa5 100644
--- a/chromeos/network/onc/onc_translator_shill_to_onc.cc
+++ b/chromeos/network/onc/onc_translator_shill_to_onc.cc
@@ -61,9 +61,16 @@
   void TranslateOpenVPN();
   void TranslateVPN();
   void TranslateWiFiWithState();
+  void TranslateCellularWithState();
   void TranslateNetworkWithState();
 
-  // Creates an ONC object from |shill_dictionary| according to the signature
+  // Creates an ONC object from |dictionary| according to the signature
+  // associated to |onc_field_name| and adds it to |onc_object_| at
+  // |onc_field_name|.
+  void TranslateAndAddNestedObject(const std::string& onc_field_name,
+                                   const base::DictionaryValue& dictionary);
+
+  // Creates an ONC object from |shill_dictionary_| according to the signature
   // associated to |onc_field_name| and adds it to |onc_object_| at
   // |onc_field_name|.
   void TranslateAndAddNestedObject(const std::string& onc_field_name);
@@ -108,6 +115,8 @@
     TranslateOpenVPN();
   } else if (onc_signature_ == &kWiFiWithStateSignature) {
     TranslateWiFiWithState();
+  } else if (onc_signature_ == &kCellularWithStateSignature) {
+    TranslateCellularWithState();
   } else {
     CopyPropertiesAccordingToSignature();
   }
@@ -196,17 +205,13 @@
   CopyPropertiesAccordingToSignature();
 }
 
-void ShillToONCTranslator::TranslateAndAddNestedObject(
-    const std::string& onc_field_name) {
-  const OncFieldSignature* field_signature =
-      GetFieldSignature(*onc_signature_, onc_field_name);
-  ShillToONCTranslator nested_translator(*shill_dictionary_,
-                                         *field_signature->value_signature);
-  scoped_ptr<base::DictionaryValue> nested_object =
-      nested_translator.CreateTranslatedONCObject();
-  if (nested_object->empty())
-    return;
-  onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
+void ShillToONCTranslator::TranslateCellularWithState() {
+  CopyPropertiesAccordingToSignature();
+  const base::DictionaryValue* serving_operator = NULL;
+  if (shill_dictionary_->GetDictionaryWithoutPathExpansion(
+        flimflam::kServingOperatorProperty, &serving_operator)) {
+    TranslateAndAddNestedObject(cellular::kServingOperator, *serving_operator);
+  }
 }
 
 void ShillToONCTranslator::TranslateNetworkWithState() {
@@ -241,6 +246,25 @@
   }
 }
 
+void ShillToONCTranslator::TranslateAndAddNestedObject(
+    const std::string& onc_field_name) {
+  TranslateAndAddNestedObject(onc_field_name, *shill_dictionary_);
+}
+
+void ShillToONCTranslator::TranslateAndAddNestedObject(
+    const std::string& onc_field_name,
+    const base::DictionaryValue& dictionary) {
+  const OncFieldSignature* field_signature =
+      GetFieldSignature(*onc_signature_, onc_field_name);
+  ShillToONCTranslator nested_translator(dictionary,
+                                         *field_signature->value_signature);
+  scoped_ptr<base::DictionaryValue> nested_object =
+      nested_translator.CreateTranslatedONCObject();
+  if (nested_object->empty())
+    return;
+  onc_object_->SetWithoutPathExpansion(onc_field_name, nested_object.release());
+}
+
 void ShillToONCTranslator::CopyPropertiesAccordingToSignature() {
   CopyPropertiesAccordingToSignature(onc_signature_);
 }
diff --git a/chromeos/network/onc/onc_translator_unittest.cc b/chromeos/network/onc/onc_translator_unittest.cc
index ef53fff..21d8cdf 100644
--- a/chromeos/network/onc/onc_translator_unittest.cc
+++ b/chromeos/network/onc/onc_translator_unittest.cc
@@ -87,6 +87,8 @@
     ::testing::Values(
         std::make_pair("shill_wifi_clientcert.json",
                        "translation_of_shill_wifi_clientcert.onc"),
+        std::make_pair("shill_wifi_wpa1.json",
+                       "translation_of_shill_wifi_wpa1.onc"),
         std::make_pair("shill_l2tpipsec.json",
                        "translation_of_shill_l2tpipsec.onc"),
         std::make_pair("shill_openvpn.json",
@@ -94,7 +96,9 @@
         std::make_pair("shill_openvpn_with_errors.json",
                        "translation_of_shill_openvpn_with_errors.onc"),
         std::make_pair("shill_wifi_with_state.json",
-                       "translation_of_shill_wifi_with_state.onc")));
+                       "translation_of_shill_wifi_with_state.onc"),
+        std::make_pair("shill_cellular_with_state.json",
+                       "translation_of_shill_cellular_with_state.onc")));
 
 }  // namespace onc
 }  // namespace chromeos
diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
index 7ae5aa8..a01e136 100644
--- a/chromeos/network/onc/onc_utils.cc
+++ b/chromeos/network/onc/onc_utils.cc
@@ -171,7 +171,7 @@
   return "unknown";
 }
 
-void ExpandField(const std::string fieldname,
+void ExpandField(const std::string& fieldname,
                  const StringSubstitution& substitution,
                  base::DictionaryValue* onc_object) {
   std::string user_string;
diff --git a/chromeos/network/shill_property_handler.cc b/chromeos/network/shill_property_handler.cc
index df3f06b..9eb67d7 100644
--- a/chromeos/network/shill_property_handler.cc
+++ b/chromeos/network/shill_property_handler.cc
@@ -566,6 +566,8 @@
                          flimflam::kPrefixlenProperty);
   UpdateIPConfigProperty(service_path, properties,
                          flimflam::kGatewayProperty);
+  UpdateIPConfigProperty(service_path, properties,
+                         shill::kWebProxyAutoDiscoveryUrlProperty);
 }
 
 void ShillPropertyHandler::UpdateIPConfigProperty(
diff --git a/chromeos/test/data/network/repaired_toplevel_partially_invalid.onc b/chromeos/test/data/network/repaired_toplevel_partially_invalid.onc
index c54741a..5af8c2e 100644
--- a/chromeos/test/data/network/repaired_toplevel_partially_invalid.onc
+++ b/chromeos/test/data/network/repaired_toplevel_partially_invalid.onc
@@ -14,7 +14,7 @@
           "Type": "OpenVPN",
           "OpenVPN": {
               "Port": 1194,
-              "Username": "abc ${LOGIN_ID} def",
+              "Username": "abc fake email def",
               "Recommended": [ "Username", "Password" ],
               "ClientCertType": "Pattern",
               "ClientCertPattern": {
diff --git a/chromeos/test/data/network/shill_cellular_with_state.json b/chromeos/test/data/network/shill_cellular_with_state.json
new file mode 100644
index 0000000..de1f21c
--- /dev/null
+++ b/chromeos/test/data/network/shill_cellular_with_state.json
@@ -0,0 +1,11 @@
+{
+  "Type": "cellular",
+  "Name": "Test Network",
+  "Cellular.ActivateOverNonCellularNetwork": false,
+  "Cellular.ActivationState": "activated",
+  "Cellular.ServingOperator": {
+    "code": "test-code",
+    "country": "test-country",
+    "name" : "test-name"
+  }
+}
diff --git a/chromeos/test/data/network/shill_wifi_wpa1.json b/chromeos/test/data/network/shill_wifi_wpa1.json
new file mode 100644
index 0000000..2d92618
--- /dev/null
+++ b/chromeos/test/data/network/shill_wifi_wpa1.json
@@ -0,0 +1,9 @@
+{
+  "GUID":"{64c4f86b-cf6a-4e4a-8eff-456def}",
+  "Mode":"managed",
+  "Name":"OpenWrt",
+  "Passphrase":"some passphrase",
+  "SSID":"OpenWrt",
+  "Security":"wpa",
+  "Type":"wifi"
+}
diff --git a/chromeos/test/data/network/translation_of_shill_cellular_with_state.onc b/chromeos/test/data/network/translation_of_shill_cellular_with_state.onc
new file mode 100644
index 0000000..77bd029
--- /dev/null
+++ b/chromeos/test/data/network/translation_of_shill_cellular_with_state.onc
@@ -0,0 +1,13 @@
+{
+  "Type": "Cellular",
+  "Name": "Test Network",
+  "Cellular": {
+    "ActivateOverNonCellularNetwork": false,
+    "ActivationState": "activated",
+    "ServingOperator": {
+      "Code": "test-code",
+      "Country": "test-country",
+      "Name": "test-name"
+    }
+  }
+}
diff --git a/chromeos/test/data/network/translation_of_shill_wifi_wpa1.onc b/chromeos/test/data/network/translation_of_shill_wifi_wpa1.onc
new file mode 100644
index 0000000..c23df0f
--- /dev/null
+++ b/chromeos/test/data/network/translation_of_shill_wifi_wpa1.onc
@@ -0,0 +1,10 @@
+{
+  "GUID":"{64c4f86b-cf6a-4e4a-8eff-456def}",
+  "Name":"OpenWrt",
+  "Type":"WiFi",
+  "WiFi":{
+    "Passphrase":"some passphrase",
+    "SSID":"OpenWrt",
+    "Security":"WPA-PSK"
+  }
+}
diff --git a/cloud_print/gcp20/prototype/cloud_print_request.cc b/cloud_print/gcp20/prototype/cloud_print_request.cc
index 2d36dcc..d8baec2 100644
--- a/cloud_print/gcp20/prototype/cloud_print_request.cc
+++ b/cloud_print/gcp20/prototype/cloud_print_request.cc
@@ -60,7 +60,6 @@
 void CloudPrintRequest::Run(
     const std::string& access_token,
     scoped_refptr<net::URLRequestContextGetter> context_getter) {
-
   if (!access_token.empty())
     fetcher_->AddExtraRequestHeader(base::StringPrintf(
         "Authorization: Bearer \"%s\"", access_token.c_str()));
@@ -106,13 +105,13 @@
                                            // this call.
 
   } else {
-    // TODO(maksymb): Add |server_http_code| and |server_api| info for errors.
+    // TODO(maksymb): Add Privet |server_http_code| and |server_api| support in
+    // case of server errors.
+    NOTIMPLEMENTED() << "HTTP code: " << http_code;
     delegate_->OnFetchError("dummy", -1, http_code);  // After this object can
                                                       // be deleted.
                                                       // Do *NOT* access members
                                                       // after this call.
-
-    NOTIMPLEMENTED() << "HTTP code: " << http_code;
   }
 }
 
diff --git a/cloud_print/gcp20/prototype/cloud_print_requester.cc b/cloud_print/gcp20/prototype/cloud_print_requester.cc
index 1154d62..ec40489 100644
--- a/cloud_print/gcp20/prototype/cloud_print_requester.cc
+++ b/cloud_print/gcp20/prototype/cloud_print_requester.cc
@@ -5,12 +5,14 @@
 #include "cloud_print/gcp20/prototype/cloud_print_requester.h"
 
 #include "base/bind.h"
+#include "base/json/json_writer.h"
 #include "base/md5.h"
 #include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "cloud_print/gcp20/prototype/cloud_print_url_request_context_getter.h"
 #include "google_apis/google_api_keys.h"
+#include "net/base/escape.h"
 #include "net/base/mime_util.h"
 #include "net/base/url_util.h"
 #include "net/http/http_status_code.h"
@@ -27,6 +29,11 @@
 const char kPrinterCapsValue[] = "capabilities";
 const char kPrinterCapsHashValue[] = "capsHash";
 const char kPrinterUserValue[] = "user";
+const char kPrinterGcpVersion[] = "gcp_version";
+const char kPrinterLocalSettings[] = "local_settings";
+
+// TODO(maksymb): Replace GCP Version with "2.0" once GCP Server will support it
+const char kGcpVersion[] = "1.5";
 
 const int kGaiaMaxRetries = 3;
 
@@ -47,6 +54,35 @@
   return url;
 }
 
+GURL CreatePrinterUrl(const std::string& device_id) {
+  GURL url(std::string(kCloudPrintUrl) + "/printer");
+  url = net::AppendQueryParameter(url, "printerid", device_id);
+  return url;
+}
+
+GURL CreateUpdateUrl(const std::string& device_id) {
+  GURL url(std::string(kCloudPrintUrl) + "/update");
+  url = net::AppendQueryParameter(url, "printerid", device_id);
+  return url;
+}
+
+std::string LocalSettingsToJson(const LocalSettings& settings) {
+  base::DictionaryValue dictionary;
+  scoped_ptr<base::DictionaryValue> current(new DictionaryValue);
+
+  // TODO(maksymb): Formalize text as constants.
+  current->SetBoolean("local_discovery", settings.local_discovery);
+  current->SetBoolean("access_token_enabled", settings.access_token_enabled);
+  current->SetBoolean("printer/local_printing_enabled",
+                         settings.local_printing_enabled);
+  current->SetInteger("xmpp_timeout_value", settings.xmpp_timeout_value);
+  dictionary.Set("current", current.release());
+
+  std::string local_settings;
+  base::JSONWriter::Write(&dictionary, &local_settings);
+  return local_settings;
+}
+
 }  // namespace
 
 using cloud_print_response_parser::Job;
@@ -73,6 +109,7 @@
 void CloudPrintRequester::StartRegistration(const std::string& proxy_id,
                                             const std::string& device_name,
                                             const std::string& user,
+                                            const LocalSettings& settings,
                                             const std::string& cdd) {
   std::string mime_boundary;
   int r1 = base::RandInt(0, kint32max);
@@ -98,6 +135,11 @@
                                   mime_boundary, std::string(), &data);
   net::AddMultipartValueForUpload(kPrinterUserValue, user,
                                   mime_boundary, std::string(), &data);
+  net::AddMultipartValueForUpload(kPrinterGcpVersion, kGcpVersion,
+                                  mime_boundary, std::string(), &data);
+  net::AddMultipartValueForUpload(kPrinterLocalSettings,
+                                  LocalSettingsToJson(settings),
+                                  mime_boundary, std::string(), &data);
   net::AddMultipartFinalDelimiterForUpload(mime_boundary, &data);
 
   request_ = CreatePost(
@@ -155,6 +197,33 @@
   request_->Run(delegate_->GetAccessToken(), context_getter_);
 }
 
+void CloudPrintRequester::RequestLocalSettings(const std::string& device_id) {
+  VLOG(3) << "Function: " << __FUNCTION__;
+  request_ = CreateGet(
+      CreatePrinterUrl(device_id),
+      base::Bind(&CloudPrintRequester::ParseLocalSettings, AsWeakPtr()));
+  request_->Run(delegate_->GetAccessToken(), context_getter_);
+}
+
+void CloudPrintRequester::SendLocalSettings(
+    const std::string& device_id,
+    const LocalSettings& settings) {
+  VLOG(3) << "Function: " << __FUNCTION__;
+
+  std::string data_mimetype = "application/x-www-form-urlencoded";
+  std::string data = base::StringPrintf(
+      "%s=%s",
+      kPrinterLocalSettings,
+      net::EscapeUrlEncodedData(LocalSettingsToJson(settings), false).c_str());
+
+  request_ = CreatePost(
+      CreateUpdateUrl(device_id),
+      data, data_mimetype,
+      base::Bind(&CloudPrintRequester::ParseLocalSettingUpdated, AsWeakPtr()));
+  request_->Run(delegate_->GetAccessToken(), context_getter_);
+}
+
+
 void CloudPrintRequester::OnFetchComplete(const std::string& response) {
   VLOG(3) << "Function: " << __FUNCTION__;
   ParserCallback callback = parser_callback_;
@@ -168,10 +237,15 @@
   VLOG(3) << "Function: " << __FUNCTION__;
   EraseRequest();
   current_print_job_.reset();
-  delegate_->OnServerError("Fetch error");
 
-  // TODO(maksymb): |server_api| and other
-  NOTIMPLEMENTED();
+  if (server_http_code == net::HTTP_FORBIDDEN) {
+    delegate_->OnAuthError();
+  } else {
+    delegate_->OnServerError("Fetch error");
+  }
+
+  // TODO(maksymb): Add Privet |server_http_code| and |server_api| support in
+  // case of server errors.
 }
 
 void CloudPrintRequester::OnFetchTimeoutReached() {
@@ -186,8 +260,8 @@
                                               int expires_in_seconds) {
   VLOG(3) << "Function: " << __FUNCTION__;
   gaia_.reset();
-  delegate_->OnGetAuthCodeResponseParsed(refresh_token,
-                                         access_token, expires_in_seconds);
+  delegate_->OnRegistrationFinished(refresh_token,
+                                    access_token, expires_in_seconds);
 }
 
 void CloudPrintRequester::OnRefreshTokenResponse(
@@ -340,3 +414,28 @@
   request_->Run(delegate_->GetAccessToken(), context_getter_);
 }
 
+void CloudPrintRequester::ParseLocalSettings(const std::string& response) {
+  VLOG(3) << "Function: " << __FUNCTION__;
+
+  std::string error_description;
+  LocalSettings settings;
+  LocalSettings::State state;
+
+  bool success = cloud_print_response_parser::ParseLocalSettingsResponse(
+      response,
+      &error_description,
+      &state,
+      &settings);
+
+  if (success) {
+    delegate_->OnLocalSettingsReceived(state, settings);
+  } else {
+    delegate_->OnServerError(error_description);
+  }
+}
+
+void CloudPrintRequester::ParseLocalSettingUpdated(
+    const std::string& response) {
+  delegate_->OnLocalSettingsUpdated();
+}
+
diff --git a/cloud_print/gcp20/prototype/cloud_print_requester.h b/cloud_print/gcp20/prototype/cloud_print_requester.h
index f9c2487..ff8306b 100644
--- a/cloud_print/gcp20/prototype/cloud_print_requester.h
+++ b/cloud_print/gcp20/prototype/cloud_print_requester.h
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "cloud_print/gcp20/prototype/cloud_print_request.h"
 #include "cloud_print/gcp20/prototype/cloud_print_response_parser.h"
+#include "cloud_print/gcp20/prototype/local_settings.h"
 #include "google_apis/gaia/gaia_oauth_client.h"
 
 class CloudPrintURLRequestContextGetter;
@@ -39,9 +40,9 @@
         const std::string& complete_invite_url,
         const std::string& device_id) = 0;
 
-    // Invoked when server respond for registration-getAuthCode query and
+    // Invoked when server responded for registration-getAuthCode query and
     // response is successfully parsed.
-    virtual void OnGetAuthCodeResponseParsed(
+    virtual void OnRegistrationFinished(
         const std::string& refresh_token,
         const std::string& access_token,
         int access_token_expires_in_seconds) = 0;
@@ -79,6 +80,14 @@
 
     // Invoked when printjob is marked as done on CloudPrint server.
     virtual void OnPrintJobDone() = 0;
+
+    // Invoked when local settings response was received.
+    virtual void OnLocalSettingsReceived(
+        LocalSettings::State state,
+        const LocalSettings& settings) = 0;
+
+    // Invoked when CURRENT local settings was updated on server.
+    virtual void OnLocalSettingsUpdated() = 0;
   };
 
   // Creates and initializes object.
@@ -94,7 +103,9 @@
   // Creates query to server for starting registration.
   void StartRegistration(const std::string& proxy_id,
                          const std::string& device_name,
-                         const std::string& user, const std::string& cdd);
+                         const std::string& user,
+                         const LocalSettings& settings,
+                         const std::string& cdd);
 
   // Creates request for completing registration and receiving refresh token.
   void CompleteRegistration();
@@ -112,6 +123,13 @@
   // Reports server that printjob has been printed.
   void SendPrintJobDone(const std::string& job_id);
 
+  // Requests /printer API to receive local settings.
+  void RequestLocalSettings(const std::string& device_id);
+
+  // Updates local settings on server.
+  void SendLocalSettings(const std::string& device_id,
+                         const LocalSettings& settings);
+
  private:
   typedef base::Callback<void(const std::string&)> ParserCallback;
 
@@ -166,6 +184,12 @@
   // Invoked after marking printjob as IN_PROGRESS.
   void ParsePrintJobInProgress(const std::string& response);
 
+  // Invoked after receiving local_settings.
+  void ParseLocalSettings(const std::string& response);
+
+  // Invoked after updating current local_settings.
+  void ParseLocalSettingUpdated(const std::string& response);
+
   // |request| contains |NULL| if no server response is awaiting. Otherwise wait
   // until callback will be called will be called and close connection.
   scoped_ptr<CloudPrintRequest> request_;
diff --git a/cloud_print/gcp20/prototype/cloud_print_response_parser.cc b/cloud_print/gcp20/prototype/cloud_print_response_parser.cc
index bc2742b..c43ed39 100644
--- a/cloud_print/gcp20/prototype/cloud_print_response_parser.cc
+++ b/cloud_print/gcp20/prototype/cloud_print_response_parser.cc
@@ -7,6 +7,7 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 
 namespace cloud_print_response_parser {
@@ -183,21 +184,101 @@
   }
 
   std::vector<Job> job_list(jobs->GetSize());
+  std::string create_time_str;
   for (size_t idx = 0; idx < job_list.size(); ++idx) {
     base::DictionaryValue* job = NULL;
     jobs->GetDictionary(idx, &job);
     if (!job->GetString("id", &job_list[idx].job_id) ||
-        !job->GetString("createTime", &job_list[idx].create_time) ||
+        !job->GetString("createTime", &create_time_str) ||
         !job->GetString("fileUrl", &job_list[idx].file_url) ||
         !job->GetString("ticketUrl", &job_list[idx].ticket_url) ||
         !job->GetString("title", &job_list[idx].title)) {
       *error_description = "Cannot parse job info.";
       return false;
     }
+    int64 create_time_ms = 0;
+    if (!base::StringToInt64(create_time_str, &create_time_ms)) {
+      *error_description = "Cannot convert time.";
+      return false;
+    }
+    job_list[idx].create_time =
+        base::Time::UnixEpoch() +
+        base::TimeDelta::FromMilliseconds(create_time_ms);
   }
 
   *list = job_list;
+  return true;
+}
 
+bool ParseLocalSettingsResponse(const std::string& response,
+                                std::string* error_description,
+                                LocalSettings::State* state,
+                                LocalSettings* settings) {
+  scoped_ptr<base::Value> json(base::JSONReader::Read(response));
+  base::DictionaryValue* response_dictionary = NULL;
+  bool json_success;
+  std::string message;
+  if (!GetJsonDictinaryAndCheckSuccess(json.get(), error_description,
+                                       &json_success, &message,
+                                       &response_dictionary)) {
+    return false;
+  }
+
+  if (!json_success) {  // Let's suppose our printer was deleted.
+    *state = LocalSettings::PRINTER_DELETED;
+    return true;
+  }
+
+  base::ListValue* list = NULL;
+  if (!response_dictionary->GetList("printers", &list)) {
+    *error_description = "No printers list specified.";
+    return false;
+  }
+
+  base::DictionaryValue* printer = NULL;
+  if (!list->GetDictionary(0, &printer)) {
+    *error_description = "Printers list is empty or printer is not dictionary.";
+    return false;
+  }
+
+  base::DictionaryValue* local_settings_dict = NULL;
+  if (!printer->GetDictionary("local_settings", &local_settings_dict)) {
+    *error_description = "No local_settings found.";
+    return false;
+  }
+
+  base::DictionaryValue* current = NULL;
+  if (!local_settings_dict->GetDictionary("current", &current)) {
+    *error_description = "No *current* local settings found.";
+    return false;
+  }
+
+  LocalSettings::State settings_state;
+  base::DictionaryValue* pending = NULL;
+  base::DictionaryValue* settings_to_parse = NULL;
+  if (local_settings_dict->GetDictionary("pending", &pending)) {
+    settings_to_parse = pending;
+    settings_state = LocalSettings::PENDING;
+  } else {
+    settings_to_parse = current;
+    settings_state = LocalSettings::CURRENT;
+  }
+
+  LocalSettings local_settings;
+  if (!settings_to_parse->GetBoolean("local_discovery",
+                                     &local_settings.local_discovery) ||
+      !settings_to_parse->GetBoolean("access_token_enabled",
+                                     &local_settings.access_token_enabled) ||
+      !settings_to_parse->GetBoolean("printer/local_printing_enabled",
+                                     &local_settings.local_printing_enabled) ||
+      !settings_to_parse->GetInteger("xmpp_timeout_value",
+                                     &local_settings.xmpp_timeout_value)) {
+    *error_description = "Cannot parse local_settings info.";
+    return false;
+  }
+
+  *state = settings_state;
+  *settings = local_settings;
   return true;
 }
 
diff --git a/cloud_print/gcp20/prototype/cloud_print_response_parser.h b/cloud_print/gcp20/prototype/cloud_print_response_parser.h
index 97a4c26..ff8daec 100644
--- a/cloud_print/gcp20/prototype/cloud_print_response_parser.h
+++ b/cloud_print/gcp20/prototype/cloud_print_response_parser.h
@@ -9,6 +9,8 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/time/time.h"
+#include "cloud_print/gcp20/prototype/local_settings.h"
 
 namespace base {
 
@@ -23,7 +25,7 @@
   ~Job();
 
   std::string job_id;
-  std::string create_time;
+  base::Time create_time;
   std::string file_url;
   std::string ticket_url;
   std::string title;
@@ -34,8 +36,7 @@
 };
 
 // Parses CloudPrint register start response to out parameters.
-// Returns |true| on success. Callback is called with description as a parameter
-// when parsing is failed.
+// Returns |true| on success.
 bool ParseRegisterStartResponse(const std::string& response,
                                 std::string* error_description,
                                 std::string* polling_url,
@@ -44,20 +45,25 @@
                                 std::string* device_id);
 
 // Parses CloudPrint register complete response to out parameters.
-// Returns |true| on success. Callback is called with description as a parameter
-// when parsing is failed.
+// Returns |true| on success.
 bool ParseRegisterCompleteResponse(const std::string& response,
                                    std::string* error_description,
                                    std::string* authorization_code,
                                    std::string* xmpp_jid);
 
 // Parses CloudPrint fetch response to out parameters.
-// Returns |true| on success. Callback is called with description as a parameter
-// when parsing is failed.
+// Returns |true| on success.
 bool ParseFetchResponse(const std::string& response,
                         std::string* error_description,
                         std::vector<Job>* list);
 
+// Parses CloudPrint printer response to get Local Settings.
+// Returns |true| on success.
+bool ParseLocalSettingsResponse(const std::string& response,
+                                std::string* error_description,
+                                LocalSettings::State* state,
+                                LocalSettings* settings);
+
 }  // namespace cloud_print_response_parser
 
 #endif  // CLOUD_PRINT_GCP20_PROTOTYPE_CLOUD_PRINT_RESPONSE_PARSER_H_
diff --git a/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.cc b/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.cc
index 6ad9023..6c7c235 100644
--- a/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.cc
+++ b/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.cc
@@ -61,7 +61,7 @@
 void CloudPrintXmppListener::Connect(const std::string& access_token) {
   access_token_ = access_token;
   ping_responses_pending_ = 0;
-  ping_scheduled_ = 0;
+  ping_scheduled_ = false;
 
   notifier::NotifierOptions options;
   options.request_context_getter = context_getter_;
@@ -81,7 +81,7 @@
   push_client_->UpdateCredentials(robot_email_, access_token_);
 }
 
-void CloudPrintXmppListener::set_standard_ping_interval(int interval) {
+void CloudPrintXmppListener::set_ping_interval(int interval) {
   standard_ping_interval_ = interval;
 }
 
diff --git a/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h b/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h
index 7c612fe..b2cf2b8 100644
--- a/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h
+++ b/cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h
@@ -71,7 +71,7 @@
   void Connect(const std::string& access_token);
 
   // Update ping interval when new local_settings was received.
-  void set_standard_ping_interval(int interval);
+  void set_ping_interval(int interval);
 
  private:
   // notifier::PushClientObserver methods:
diff --git a/cloud_print/gcp20/prototype/gcp20_device.cc b/cloud_print/gcp20/prototype/gcp20_device.cc
index 2d2c1d5..57972a3 100644
--- a/cloud_print/gcp20/prototype/gcp20_device.cc
+++ b/cloud_print/gcp20/prototype/gcp20_device.cc
@@ -20,21 +20,22 @@
     "usage: gcp20_device [switches] [options]\n"
     "\n"
     "switches:\n"
-    "  --disable-confirmation    disables confirmation of registration\n"
-    "  --disable-method-check    disables HTTP method checking (POST, GET)\n"
-    "  --disable-x-token         disables checking of X-Privet-Token "
-                                "HTTP header\n"
-    "  -h, --help                prints this message\n"
-    "  --no-announcement         disables DNS announcements\n"
-    "  --unicast-respond         DNS responses will be sent in unicast "
-                                "instead of multicast\n"
+    "  --disable-confirmation     disables confirmation of registration\n"
+    "  --disable-method-check     disables HTTP method checking (POST, GET)\n"
+    "  --disable-x-token          disables checking of X-Privet-Token "
+                                 "HTTP header\n"
+    "  -h, --help                 prints this message\n"
+    "  --no-announcement          disables DNS announcements\n"
+    "  --simulate-printing-errors simulates some errors for local printing\n"
+    "  --unicast-respond          DNS responses will be sent in unicast "
+                                 "instead of multicast\n"
     "\n"
     "options:\n"
-    "  --domain-name=<name>      sets, should ends with '.local'\n"
-    "  --http-port=<value>       sets port for HTTP server\n"
-    "  --service-name=<name>     sets DNS service name\n"
-    "  --state-path=<path>       sets path to file with registration state\n"
-    "  --ttl=<value>             sets TTL for DNS announcements\n"
+    "  --domain-name=<name>       sets, should ends with '.local'\n"
+    "  --http-port=<value>        sets port for HTTP server\n"
+    "  --service-name=<name>      sets DNS service name\n"
+    "  --state-path=<path>        sets path to file with registration state\n"
+    "  --ttl=<value>              sets TTL for DNS announcements\n"
     "\n"
     "WARNING: mDNS probing is not implemented\n";
 
diff --git a/cloud_print/gcp20/prototype/gcp20_device.gyp b/cloud_print/gcp20/prototype/gcp20_device.gyp
index b2e526f..0952344 100644
--- a/cloud_print/gcp20/prototype/gcp20_device.gyp
+++ b/cloud_print/gcp20/prototype/gcp20_device.gyp
@@ -48,8 +48,13 @@
         'dns_response_builder.h',
         'dns_sd_server.cc',
         'dns_sd_server.h',
+        'local_settings.h',
+        'local_print_job.cc',
+        'local_print_job.h',
         'print_job_handler.cc',
         'print_job_handler.h',
+        'printer_state.cc',
+        'printer_state.h',
         'printer.cc',
         'printer.h',
         'privet_http_server.cc',
@@ -86,6 +91,7 @@
       'target_name': 'gcp20_device_unittests',
       'type': 'executable',
       'sources': [
+        'printer_unittest.cc',
         'x_privet_token_unittest.cc',
       ],
       'dependencies': [
diff --git a/cloud_print/gcp20/prototype/local_print_job.cc b/cloud_print/gcp20/prototype/local_print_job.cc
new file mode 100644
index 0000000..cafdecf
--- /dev/null
+++ b/cloud_print/gcp20/prototype/local_print_job.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 "cloud_print/gcp20/prototype/local_print_job.h"
+
+LocalPrintJob::LocalPrintJob() : offline(false) {
+}
+
+LocalPrintJob::~LocalPrintJob() {
+}
+
+LocalPrintJob::Info::Info() : state(STATE_DRAFT), expires_in(-1) {
+}
+
+LocalPrintJob::Info::~Info() {
+}
+
diff --git a/cloud_print/gcp20/prototype/local_print_job.h b/cloud_print/gcp20/prototype/local_print_job.h
new file mode 100644
index 0000000..4959aff
--- /dev/null
+++ b/cloud_print/gcp20/prototype/local_print_job.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 CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_PRINT_JOB_H_
+#define CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_PRINT_JOB_H_
+
+#include <string>
+
+struct LocalPrintJob {
+  enum CreateResult {
+    CREATE_SUCCESS,
+    CREATE_INVALID_TICKET,
+    CREATE_PRINTER_BUSY,
+    CREATE_PRINTER_ERROR,
+  };
+
+  enum SaveResult {
+    SAVE_SUCCESS,
+    SAVE_INVALID_PRINT_JOB,
+    SAVE_INVALID_DOCUMENT_TYPE,
+    SAVE_INVALID_DOCUMENT,
+    SAVE_DOCUMENT_TOO_LARGE,
+    SAVE_PRINTER_BUSY,
+    SAVE_PRINTER_ERROR,
+  };
+
+  enum State {
+    STATE_DRAFT,
+    STATE_ABORTED,
+    STATE_DONE,
+  };
+
+  struct Info {
+    Info();
+    ~Info();
+
+    State state;
+    int expires_in;
+  };
+
+  LocalPrintJob();
+  ~LocalPrintJob();
+
+  std::string user_name;
+  std::string client_name;
+  std::string job_name;
+  std::string content;
+  std::string content_type;
+  bool offline;
+};
+
+#endif  // CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_PRINT_JOB_H_
+
diff --git a/cloud_print/gcp20/prototype/local_settings.h b/cloud_print/gcp20/prototype/local_settings.h
new file mode 100644
index 0000000..b2ec58f
--- /dev/null
+++ b/cloud_print/gcp20/prototype/local_settings.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 CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_SETTINGS_H_
+#define CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_SETTINGS_H_
+
+// Contains local settings.
+struct LocalSettings {
+  enum State {
+    CURRENT,
+    PENDING,
+    PRINTER_DELETED,
+  };
+
+  LocalSettings()
+      : local_discovery(true),
+        access_token_enabled(false),
+        local_printing_enabled(false),
+        xmpp_timeout_value(300) {
+  }
+  ~LocalSettings() {}
+
+  bool local_discovery;
+  bool access_token_enabled;
+  bool local_printing_enabled;
+  int xmpp_timeout_value;
+};
+
+#endif  // CLOUD_PRINT_GCP20_PROTOTYPE_LOCAL_SETTINGS_H_
+
diff --git a/cloud_print/gcp20/prototype/print_job_handler.cc b/cloud_print/gcp20/prototype/print_job_handler.cc
index c7549e4..7bbc1af 100644
--- a/cloud_print/gcp20/prototype/print_job_handler.cc
+++ b/cloud_print/gcp20/prototype/print_job_handler.cc
@@ -4,39 +4,248 @@
 
 #include "cloud_print/gcp20/prototype/print_job_handler.h"
 
+#include "base/bind.h"
+#include "base/command_line.h"
 #include "base/file_util.h"
+#include "base/format_macros.h"
+#include "base/guid.h"
 #include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/rand_util.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/time/time.h"
 
 namespace {
 
+const int kDraftExpirationSec = 10;
+const int kLocalPrintJobExpirationSec = 20;
+const int kErrorTimeoutSec = 30;
+
+// Errors simulation constants:
+const double kPaperJamProbability = 0.2;
+const int kTooManyDraftsTimeout = 10;
+const int kMaxDrafts = 5;
+
 const base::FilePath::CharType kJobsPath[] = FILE_PATH_LITERAL("printjobs");
 
+bool ValidateTicket(const std::string& ticket) {
+  return true;
+}
+
+std::string GenerateId() {
+  return StringToLowerASCII(base::GenerateGUID());
+}
+
 }  // namespace
 
+struct PrintJobHandler::LocalPrintJobExtended {
+  LocalPrintJobExtended(const LocalPrintJob& job, const std::string& ticket)
+      : data(job),
+        ticket(ticket),
+        state(LocalPrintJob::STATE_DRAFT) {}
+  LocalPrintJobExtended() : state(LocalPrintJob::STATE_DRAFT) {}
+  ~LocalPrintJobExtended() {}
+
+  LocalPrintJob data;
+  std::string ticket;
+  LocalPrintJob::State state;
+  base::Time expiration;
+};
+
+struct PrintJobHandler::LocalPrintJobDraft {
+  LocalPrintJobDraft() {}
+  LocalPrintJobDraft(const std::string& ticket, const base::Time& expiration)
+      : ticket(ticket),
+        expiration(expiration) {}
+  ~LocalPrintJobDraft() {}
+
+  std::string ticket;
+  base::Time expiration;
+};
+
+using base::StringPrintf;
+
 PrintJobHandler::PrintJobHandler() {
 }
 
 PrintJobHandler::~PrintJobHandler() {
 }
 
-bool PrintJobHandler::SavePrintJob(const std::string& data,
+LocalPrintJob::CreateResult PrintJobHandler::CreatePrintJob(
+    const std::string& ticket,
+    std::string* job_id_out,
+    // TODO(maksymb): Use base::TimeDelta for timeout values
+    int* expires_in_out,
+    // TODO(maksymb): Use base::TimeDelta for timeout values
+    int* error_timeout_out,
+    std::string* error_description) {
+  if (!ValidateTicket(ticket))
+    return LocalPrintJob::CREATE_INVALID_TICKET;
+
+  // Let's simulate at least some errors just for testing.
+  if (CommandLine::ForCurrentProcess()->HasSwitch("simulate-printing-errors")) {
+    if (base::RandDouble() <= kPaperJamProbability) {
+      *error_description = "Paper jam, try again";
+      return LocalPrintJob::CREATE_PRINTER_ERROR;
+    }
+
+    if (drafts.size() > kMaxDrafts) {  // Another simulation of error: business
+      *error_timeout_out = kTooManyDraftsTimeout;
+      return LocalPrintJob::CREATE_PRINTER_BUSY;
+    }
+  }
+
+  std::string id = GenerateId();
+  drafts[id] = LocalPrintJobDraft(
+      ticket,
+      base::Time::Now() + base::TimeDelta::FromSeconds(kDraftExpirationSec));
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&PrintJobHandler::ForgetDraft, AsWeakPtr(), id),
+      base::TimeDelta::FromSeconds(kDraftExpirationSec));
+
+  *job_id_out = id;
+  *expires_in_out = kDraftExpirationSec;
+  return LocalPrintJob::CREATE_SUCCESS;
+}
+
+LocalPrintJob::SaveResult PrintJobHandler::SaveLocalPrintJob(
+    const LocalPrintJob& job,
+    std::string* job_id_out,
+    int* expires_in_out,
+    std::string* error_description_out,
+    int* timeout_out) {
+  std::string id;
+  int expires_in;
+
+  switch (CreatePrintJob(std::string(), &id, &expires_in,
+                         timeout_out, error_description_out)) {
+    case LocalPrintJob::CREATE_INVALID_TICKET:
+      NOTREACHED();
+      return LocalPrintJob::SAVE_SUCCESS;
+
+    case LocalPrintJob::CREATE_PRINTER_BUSY:
+      return LocalPrintJob::SAVE_PRINTER_BUSY;
+
+    case LocalPrintJob::CREATE_PRINTER_ERROR:
+      return LocalPrintJob::SAVE_PRINTER_ERROR;
+
+    case LocalPrintJob::CREATE_SUCCESS:
+      *job_id_out = id;
+      return CompleteLocalPrintJob(job, id, expires_in_out,
+                                   error_description_out, timeout_out);
+
+    default:
+      NOTREACHED();
+      return LocalPrintJob::SAVE_SUCCESS;
+  }
+}
+
+LocalPrintJob::SaveResult PrintJobHandler::CompleteLocalPrintJob(
+    const LocalPrintJob& job,
+    const std::string& job_id,
+    int* expires_in_out,
+    std::string* error_description_out,
+    int* timeout_out) {
+  if (!drafts.count(job_id)) {
+    *timeout_out = kErrorTimeoutSec;
+    return LocalPrintJob::SAVE_INVALID_PRINT_JOB;
+  }
+
+  std::string suffix = StringPrintf("%s:%s",
+                                    job.user_name.c_str(),
+                                    job.client_name.c_str());
+  std::string file_extension;
+  // TODO(maksymb): Gather together this type checking with Printer
+  // supported types in kCdd.
+  if (job.content_type == "application/pdf") {
+    file_extension = "pdf";
+  } else if (job.content_type == "image/pwg-raster") {
+    file_extension = "pwg";
+  } else if (job.content_type == "image/jpeg") {
+    file_extension = "jpg";
+  } else {
+    error_description_out->clear();
+    return LocalPrintJob::SAVE_INVALID_DOCUMENT_TYPE;
+  }
+  CompleteDraft(job_id, job);
+  std::map<std::string, LocalPrintJobExtended>::iterator current_job =
+      jobs.find(job_id);
+
+  if (!SavePrintJob(current_job->second.data.content,
+                    current_job->second.ticket,
+                    base::Time::Now(),
+                    StringPrintf("%s", job_id.c_str()),
+                    suffix,
+                    current_job->second.data.job_name, file_extension)) {
+    SetJobState(job_id, LocalPrintJob::STATE_ABORTED);
+    *error_description_out = "IO error";
+    return LocalPrintJob::SAVE_PRINTER_ERROR;
+  }
+
+  SetJobState(job_id, LocalPrintJob::STATE_DONE);
+  *expires_in_out = static_cast<int>(GetJobExpiration(job_id).InSeconds());
+  return LocalPrintJob::SAVE_SUCCESS;
+}
+
+bool PrintJobHandler::GetJobState(const std::string& id,
+                                  LocalPrintJob::Info* info_out) {
+  using base::Time;
+
+  std::map<std::string, LocalPrintJobDraft>::iterator draft = drafts.find(id);
+  if (draft != drafts.end()) {
+    info_out->state = LocalPrintJob::STATE_DRAFT;
+    info_out->expires_in =
+        static_cast<int>((draft->second.expiration - Time::Now()).InSeconds());
+    return true;
+  }
+
+  std::map<std::string, LocalPrintJobExtended>::iterator job = jobs.find(id);
+  if (job != jobs.end()) {
+    info_out->state = job->second.state;
+    info_out->expires_in = static_cast<int>(GetJobExpiration(id).InSeconds());
+    return true;
+  }
+  return false;
+}
+
+bool PrintJobHandler::SavePrintJob(const std::string& content,
                                    const std::string& ticket,
-                                   const std::string& job_name,
-                                   const std::string& title) {
+                                   const base::Time& create_time,
+                                   const std::string& id,
+                                   const std::string& job_name_suffix,
+                                   // suffix is not extension
+                                   // it may be used to mark local printer jobs
+                                   const std::string& title,
+                                   const std::string& file_extension) {
   VLOG(1) << "Printing printjob: \"" + title + "\"";
   base::FilePath directory(kJobsPath);
 
-  using file_util::CreateDirectory;
-
-  if (!base::DirectoryExists(directory) && !CreateDirectory(directory)) {
+  if (!base::DirectoryExists(directory) &&
+      !file_util::CreateDirectory(directory)) {
     LOG(WARNING) << "Cannot create directory: " << directory.value();
     return false;
   }
 
+  base::Time::Exploded create_time_exploded;
+  create_time.UTCExplode(&create_time_exploded);
+  std::string job_name =
+      StringPrintf("%.4d%.2d%.2d-%.2d:%.2d:%.2d-%.3dms.%s",
+          create_time_exploded.year,
+          create_time_exploded.month,
+          create_time_exploded.day_of_month,
+          create_time_exploded.hour,
+          create_time_exploded.minute,
+          create_time_exploded.second,
+          create_time_exploded.millisecond,
+          id.c_str());
+  if (!job_name_suffix.empty())
+    job_name += "." + job_name_suffix;
   directory = directory.AppendASCII(job_name);
 
-  if (!base::DirectoryExists(directory) && !CreateDirectory(directory)) {
+  if (!base::DirectoryExists(directory) &&
+      !file_util::CreateDirectory(directory)) {
     LOG(WARNING) << "Cannot create directory: " << directory.value();
     return false;
   }
@@ -49,15 +258,67 @@
     return false;
   }
 
-  written = file_util::WriteFile(directory.AppendASCII("data.pdf"),
-                                 data.data(),
-                                 static_cast<int>(data.size()));
-  if (static_cast<size_t>(written) != data.size()) {
+  written = file_util::WriteFile(
+      directory.AppendASCII("data." + file_extension),
+      content.data(), static_cast<int>(content.size()));
+  if (static_cast<size_t>(written) != content.size()) {
     LOG(WARNING) << "Cannot save data.";
     return false;
   }
 
-  LOG(INFO) << "Saved printjob: " << job_name;
+  LOG(INFO) << "Saved printjob: " << job_name << ": " << title;
   return true;
 }
 
+void PrintJobHandler::SetJobState(const std::string& id,
+                                  LocalPrintJob::State state) {
+  DCHECK(!drafts.count(id)) << "Draft should be completed at first";
+
+  std::map<std::string, LocalPrintJobExtended>::iterator job = jobs.find(id);
+  DCHECK(job != jobs.end());
+  job->second.state = state;
+  switch (state) {
+    case LocalPrintJob::STATE_DRAFT:
+      NOTREACHED();
+      break;
+    case LocalPrintJob::STATE_ABORTED:
+    case LocalPrintJob::STATE_DONE:
+      job->second.expiration =
+          base::Time::Now() +
+          base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec);
+      base::MessageLoop::current()->PostDelayedTask(
+          FROM_HERE,
+          base::Bind(&PrintJobHandler::ForgetLocalJob, AsWeakPtr(), id),
+          base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec));
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void PrintJobHandler::CompleteDraft(const std::string& id,
+                                    const LocalPrintJob& job) {
+  std::map<std::string, LocalPrintJobDraft>::iterator draft = drafts.find(id);
+  if (draft != drafts.end()) {
+    jobs[id] = LocalPrintJobExtended(job, draft->second.ticket);
+    drafts.erase(draft);
+  }
+}
+
+// TODO(maksymb): Use base::Time for expiration
+base::TimeDelta PrintJobHandler::GetJobExpiration(const std::string& id) const {
+  DCHECK(jobs.count(id));
+  base::Time expiration = jobs.at(id).expiration;
+  if (expiration.is_null())
+    return base::TimeDelta::FromSeconds(kLocalPrintJobExpirationSec);
+  return expiration - base::Time::Now();
+}
+
+void PrintJobHandler::ForgetDraft(const std::string& id) {
+  drafts.erase(id);
+}
+
+void PrintJobHandler::ForgetLocalJob(const std::string& id) {
+  jobs.erase(id);
+}
+
diff --git a/cloud_print/gcp20/prototype/print_job_handler.h b/cloud_print/gcp20/prototype/print_job_handler.h
index 594e5a2..61c043a 100644
--- a/cloud_print/gcp20/prototype/print_job_handler.h
+++ b/cloud_print/gcp20/prototype/print_job_handler.h
@@ -5,21 +5,92 @@
 #ifndef CLOUD_PRINT_GCP20_PROTOTYPE_PRINT_JOB_HANDLER_H_
 #define CLOUD_PRINT_GCP20_PROTOTYPE_PRINT_JOB_HANDLER_H_
 
+#include <map>
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "cloud_print/gcp20/prototype/local_print_job.h"
 
-class PrintJobHandler {
+namespace base {
+
+class DictionaryValue;
+class Time;
+
+}  // namespace base
+
+class PrintJobHandler : public base::SupportsWeakPtr<PrintJobHandler> {
  public:
   PrintJobHandler();
   ~PrintJobHandler();
 
-  bool SavePrintJob(const std::string& data,
+  // Creates printer job draft
+  LocalPrintJob::CreateResult CreatePrintJob(
+      const std::string& ticket,
+      std::string* job_id_out,
+      int* expires_in_out,
+      int* error_timeout_out,
+      std::string* error_description_out);
+
+  // Creates printer job with empty ticket and "prints" it
+  LocalPrintJob::SaveResult SaveLocalPrintJob(
+      const LocalPrintJob& job,
+      std::string* job_id_out,
+      int* expires_in_out,
+      std::string* error_description_out,
+      int* timeout_out);
+
+  // Completes printer job from draft
+  LocalPrintJob::SaveResult CompleteLocalPrintJob(
+      const LocalPrintJob& job,
+      const std::string& job_id,
+      int* expires_in_out,
+      std::string* error_description_out,
+      int* timeout_out);
+
+  // Gives info about job
+  bool GetJobState(const std::string& id, LocalPrintJob::Info* info_out);
+
+  // Saving print job directly to drive
+  bool SavePrintJob(const std::string& content,
                     const std::string& ticket,
-                    const std::string& job_name,
-                    const std::string& title);
+                    const base::Time& create_time,
+                    const std::string& id,
+                    const std::string& job_name_suffix,
+                    const std::string& title,
+                    const std::string& file_extension);
 
  private:
+  // Contains ticket info and job info together
+  struct LocalPrintJobExtended;
+
+  // Contains job ticket
+  struct LocalPrintJobDraft;
+
+  // Contains all unexpired drafts
+  std::map<std::string, LocalPrintJobDraft> drafts;  // id -> draft
+
+  // Contains all unexpired jobs
+  std::map<std::string, LocalPrintJobExtended> jobs;  // id -> printjob
+
+  // Changes job state and creates timeouts to delete old jobs from memory
+  void SetJobState(const std::string& id, LocalPrintJob::State);
+
+  // Moves draft to jobs
+  void CompleteDraft(const std::string& id, const LocalPrintJob& job);
+
+  // Calculates expiration for job
+  // TODO(maksymb): Use base::Time for expiration
+  base::TimeDelta GetJobExpiration(const std::string& id) const;
+
+  // Erases draft from memory
+  void ForgetDraft(const std::string& id);
+
+  // Erases job from memory
+  void ForgetLocalJob(const std::string& id);
+
   DISALLOW_COPY_AND_ASSIGN(PrintJobHandler);
 };
 
diff --git a/cloud_print/gcp20/prototype/printer.cc b/cloud_print/gcp20/prototype/printer.cc
index 4583aa7..9513979 100644
--- a/cloud_print/gcp20/prototype/printer.cc
+++ b/cloud_print/gcp20/prototype/printer.cc
@@ -11,12 +11,14 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/file_util.h"
+#include "base/format_macros.h"
 #include "base/guid.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "cloud_print/gcp20/prototype/command_line_reader.h"
+#include "cloud_print/gcp20/prototype/local_settings.h"
 #include "cloud_print/gcp20/prototype/service_parameters.h"
 #include "cloud_print/gcp20/prototype/special_io.h"
 #include "net/base/net_util.h"
@@ -28,7 +30,6 @@
 
 const uint16 kHttpPortDefault = 10101;
 const uint32 kTtlDefault = 60*60;  // in seconds
-const int kXmppPingIntervalDefault = 5*60;  // in seconds
 
 const char kServiceType[] = "_privet._tcp.local";
 const char kServiceNamePrefixDefault[] = "first_gcp20_device";
@@ -39,38 +40,65 @@
 
 const char kUserConfirmationTitle[] = "Confirm registration: type 'y' if you "
                                       "agree and any other to discard\n";
-const int64 kUserConfirmationTimeout = 30;  // in seconds
-
-const uint32 kReconnectTimeout = 5;  // in seconds
+const int kUserConfirmationTimeout = 30;  // in seconds
+const int kRegistrationTimeout = 60;  // in seconds
+const int kReconnectTimeout = 5;  // in seconds
 
 const double kTimeToNextAccessTokenUpdate = 0.8;  // relatively to living time.
 
 const char kCdd[] =
 "{\n"
-" 'version': '1.0',\n"
-"  'printer': {\n"
-"    'vendor_capability': [\n"
+"  \"version\": \"1.0\",\n"
+"  \"printer\": {\n"
+"    \"supported_content_type\": [\n"
 "      {\n"
-"        'id': 'psk:MediaType',\n"
-"        'display_name': 'Media Type',\n"
-"        'type': 'SELECT',\n"
-"        'select_cap': {\n"
-"          'option': [\n"
+"        \"content_type\": \"application/pdf\"\n"
+"      },\n"
+"      {\n"
+"        \"content_type\": \"image/pwg-raster\"\n"
+"      },\n"
+"      {\n"
+"        \"content_type\": \"image/jpeg\"\n"
+"      }\n"
+"    ],\n"
+"    \"color\": {\n"
+"     \"option\": [\n"
+"        {\n"
+"          \"is_default\": true,\n"
+"          \"type\": \"STANDARD_COLOR\",\n"
+"          \"vendor_id\": \"CMYK\"\n"
+"        },\n"
+"        {\n"
+"          \"is_default\": false,\n"
+"          \"type\": \"STANDARD_MONOCHROME\",\n"
+"          \"vendor_id\": \"Gray\"\n"
+"        }\n"
+"      ]\n"
+"    },\n"
+"    \"vendor_capability\": [\n"
+"      {\n"
+"        \"id\": \"psk:MediaType\",\n"
+"        \"display_name\": \"Media Type\",\n"
+"        \"type\": \"SELECT\",\n"
+"        \"select_cap\": {\n"
+"          \"option\": [\n"
 "            {\n"
-"              'value': 'psk:Plain',\n"
-"              'display_name': 'Plain Paper',\n"
-"              'is_default': true\n"
+"              \"value\": \"psk:Plain\",\n"
+"              \"display_name\": \"Plain Paper\",\n"
+"              \"is_default\": true\n"
 "            },\n"
 "            {\n"
-"              'value': 'ns0000:Glossy',\n"
-"              'display_name': 'Glossy Photo',\n"
-"              'is_default': false\n"
+"              \"value\": \"ns0000:Glossy\",\n"
+"              \"display_name\": \"Glossy Photo\",\n"
+"              \"is_default\": false\n"
 "            }\n"
 "          ]\n"
 "        }\n"
 "      }\n"
 "    ],\n"
-"    'reverse_order': { 'default': false }\n"
+"    \"reverse_order\": {\n"
+"      \"default\": false\n"
+"    }\n"
 "  }\n"
 "}\n";
 
@@ -91,7 +119,6 @@
        iter != interfaces.end(); ++iter) {
     if (iter->address.size() == expected_address_size &&
         (interface_name.empty() || interface_name == iter->name)) {
-      LOG(INFO) << net::IPAddressToString(iter->address);
       return iter->address;
     }
   }
@@ -107,20 +134,13 @@
 
 using cloud_print_response_parser::Job;
 
-Printer::RegistrationInfo::RegistrationInfo()
-    : state(DEV_REG_UNREGISTERED),
-      confirmation_state(CONFIRMATION_PENDING) {
-}
-
-Printer::RegistrationInfo::~RegistrationInfo() {
-}
-
 Printer::Printer()
-    : http_server_(this),
-      connection_state_(OFFLINE),
+    : connection_state_(OFFLINE),
+      http_server_(this),
       on_idle_posted_(false),
       pending_local_settings_check_(false),
-      pending_print_jobs_check_(false) {
+      pending_print_jobs_check_(false),
+      pending_deletion_(false) {
 }
 
 Printer::~Printer() {
@@ -131,36 +151,10 @@
   if (IsRunning())
     return true;
 
-  // TODO(maksymb): Add switch for command line to control interface name.
-  net::IPAddressNumber ip = GetLocalIp("", false);
-  if (ip.empty()) {
-    LOG(ERROR) << "No local IP found. Cannot start printer.";
+  LoadFromFile();
+
+  if (state_.local_settings.local_discovery && !StartLocalDiscoveryServers())
     return false;
-  }
-  VLOG(1) << "Local address: " << net::IPAddressToString(ip);
-
-  uint16 port = command_line_reader::ReadHttpPort(kHttpPortDefault);
-
-  // Starting HTTP server.
-  if (!http_server_.Start(port))
-    return false;
-
-  if (!LoadFromFile())
-    reg_info_ = RegistrationInfo();
-
-  // Starting DNS-SD server.
-  std::string service_name_prefix =
-      command_line_reader::ReadServiceNamePrefix(kServiceNamePrefixDefault);
-  std::string service_domain_name =
-      command_line_reader::ReadDomainName(kServiceDomainNameDefault);
-  if (!dns_server_.Start(
-      ServiceParameters(kServiceType, service_name_prefix, service_domain_name,
-                        ip, port),
-      command_line_reader::ReadTtl(kTtlDefault),
-      CreateTxt())) {
-    http_server_.Shutdown();
-    return false;
-  }
 
   print_job_handler_.reset(new PrintJobHandler);
   xtoken_ = XPrivetToken();
@@ -175,6 +169,8 @@
 }
 
 void Printer::Stop() {
+  if (!IsRunning())
+    return;
   dns_server_.Shutdown();
   http_server_.Shutdown();
   requester_.reset();
@@ -182,32 +178,46 @@
   xmpp_listener_.reset();
 }
 
+std::string Printer::GetRawCdd() {
+  return kCdd;
+}
+
 void Printer::OnAuthError() {
   LOG(ERROR) << "Auth error occurred";
-  access_token_update_ = base::Time::Now();
-  ChangeState(OFFLINE);
-  // TODO(maksymb): Implement *instant* updating of access_token.
+  state_.access_token_update = base::Time();
+  FallOffline(true);
 }
 
 std::string Printer::GetAccessToken() {
-  return access_token_;
+  return state_.access_token;
 }
 
 PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationStart(
     const std::string& user) {
+  CheckRegistrationExpiration();
+
+  PrinterState::ConfirmationState conf_state = state_.confirmation_state;
+  if (state_.registration_state == PrinterState::REGISTRATION_ERROR ||
+      conf_state == PrinterState::CONFIRMATION_TIMEOUT ||
+      conf_state == PrinterState::CONFIRMATION_DISCARDED) {
+    state_ = PrinterState();
+  }
+
   PrivetHttpServer::RegistrationErrorStatus status = CheckCommonRegErrors(user);
   if (status != PrivetHttpServer::REG_ERROR_OK)
     return status;
 
-  if (reg_info_.state != RegistrationInfo::DEV_REG_UNREGISTERED)
+  if (state_.registration_state != PrinterState::UNREGISTERED)
     return PrivetHttpServer::REG_ERROR_INVALID_ACTION;
 
-  reg_info_ = RegistrationInfo();
-  reg_info_.user = user;
-  reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_STARTED;
+  UpdateRegistrationExpiration();
+
+  state_ = PrinterState();
+  state_.user = user;
+  state_.registration_state = PrinterState::REGISTRATION_STARTED;
 
   if (CommandLine::ForCurrentProcess()->HasSwitch("disable-confirmation")) {
-    reg_info_.confirmation_state = RegistrationInfo::CONFIRMATION_CONFIRMED;
+    state_.confirmation_state = PrinterState::CONFIRMATION_CONFIRMED;
     LOG(INFO) << "Registration confirmed by default.";
   } else {
     printf("%s", kUserConfirmationTitle);
@@ -218,7 +228,8 @@
         base::Bind(&Printer::WaitUserConfirmation, AsWeakPtr(), valid_until));
   }
 
-  requester_->StartRegistration(GenerateProxyId(), kPrinterName, user, kCdd);
+  requester_->StartRegistration(GenerateProxyId(), kPrinterName, user,
+                                state_.local_settings, kCdd);
 
   return PrivetHttpServer::REG_ERROR_OK;
 }
@@ -232,27 +243,29 @@
     return status;
 
   // Check if |action=start| was called, but |action=complete| wasn't.
-  if (reg_info_.state != RegistrationInfo::DEV_REG_REGISTRATION_STARTED &&
-      reg_info_.state !=
-          RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY)
+  if (state_.registration_state != PrinterState::REGISTRATION_STARTED &&
+      state_.registration_state !=
+          PrinterState::REGISTRATION_CLAIM_TOKEN_READY) {
     return PrivetHttpServer::REG_ERROR_INVALID_ACTION;
+  }
 
   // If |action=getClaimToken| is valid in this state (was checked above) then
   // check confirmation status.
-  if (reg_info_.confirmation_state != RegistrationInfo::CONFIRMATION_CONFIRMED)
-    return ConfirmationToRegistrationError(reg_info_.confirmation_state);
+  if (state_.confirmation_state != PrinterState::CONFIRMATION_CONFIRMED)
+    return ConfirmationToRegistrationError(state_.confirmation_state);
+
+  UpdateRegistrationExpiration();
 
   // If reply wasn't received yet, reply with |pending_user_action| error.
-  if (reg_info_.state == RegistrationInfo::DEV_REG_REGISTRATION_STARTED)
+  if (state_.registration_state == PrinterState::REGISTRATION_STARTED)
     return PrivetHttpServer::REG_ERROR_PENDING_USER_ACTION;
 
-  DCHECK_EQ(reg_info_.state,
-            RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY);
-  DCHECK_EQ(reg_info_.confirmation_state,
-            RegistrationInfo::CONFIRMATION_CONFIRMED);
+  DCHECK_EQ(state_.confirmation_state, PrinterState::CONFIRMATION_CONFIRMED);
+  DCHECK_EQ(state_.registration_state,
+            PrinterState::REGISTRATION_CLAIM_TOKEN_READY);
 
-  *token = reg_info_.registration_token;
-  *claim_url = reg_info_.complete_invite_url;
+  *token = state_.registration_token;
+  *claim_url = state_.complete_invite_url;
   return PrivetHttpServer::REG_ERROR_OK;
 }
 
@@ -263,17 +276,17 @@
   if (status != PrivetHttpServer::REG_ERROR_OK)
     return status;
 
-  if (reg_info_.state !=
-      RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY) {
+  if (state_.registration_state != PrinterState::REGISTRATION_CLAIM_TOKEN_READY)
     return PrivetHttpServer::REG_ERROR_INVALID_ACTION;
-  }
 
-  if (reg_info_.confirmation_state != RegistrationInfo::CONFIRMATION_CONFIRMED)
-    return ConfirmationToRegistrationError(reg_info_.confirmation_state);
+  UpdateRegistrationExpiration();
 
-  reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_COMPLETING;
+  if (state_.confirmation_state != PrinterState::CONFIRMATION_CONFIRMED)
+    return ConfirmationToRegistrationError(state_.confirmation_state);
+
+  state_.registration_state = PrinterState::REGISTRATION_COMPLETING;
   requester_->CompleteRegistration();
-  *device_id = reg_info_.device_id;
+  *device_id = state_.device_id;
 
   return PrivetHttpServer::REG_ERROR_OK;
 }
@@ -286,23 +299,28 @@
     return status;
   }
 
-  if (reg_info_.state == RegistrationInfo::DEV_REG_UNREGISTERED)
+  if (state_.registration_state == PrinterState::UNREGISTERED)
     return PrivetHttpServer::REG_ERROR_INVALID_ACTION;
 
-  reg_info_ = RegistrationInfo();
+  InvalidateRegistrationExpiration();
+
+  state_ = PrinterState();
+
   requester_.reset(new CloudPrintRequester(GetTaskRunner(), this));
 
   return PrivetHttpServer::REG_ERROR_OK;
 }
 
 void Printer::GetRegistrationServerError(std::string* description) {
-  DCHECK_EQ(reg_info_.state, RegistrationInfo::DEV_REG_REGISTRATION_ERROR) <<
-      "Method shouldn't be called when not needed.";
+  DCHECK_EQ(state_.registration_state, PrinterState::REGISTRATION_ERROR)
+      << "Method shouldn't be called when not needed.";
 
-  *description = reg_info_.error_description;
+  *description = state_.error_description;
 }
 
 void Printer::CreateInfo(PrivetHttpServer::DeviceInfo* info) {
+  CheckRegistrationExpiration();
+
   // TODO(maksymb): Replace "text" with constants.
 
   *info = PrivetHttpServer::DeviceInfo();
@@ -310,7 +328,7 @@
   info->name = kPrinterName;
   info->description = kPrinterDescription;
   info->url = kCloudPrintUrl;
-  info->id = reg_info_.device_id;
+  info->id = state_.device_id;
   info->device_state = "idle";
   info->connection_state = ConnectionStateToString(connection_state_);
   info->manufacturer = "Google";
@@ -321,35 +339,91 @@
 
   info->x_privet_token = xtoken_.GenerateXToken();
 
-  if (reg_info_.state == RegistrationInfo::DEV_REG_UNREGISTERED)
+  // TODO(maksymb): Create enum for available APIs and replace
+  // this API text names with constants from enum. API text names should be only
+  // known in PrivetHttpServer.
+  if (!IsRegistered()) {
     info->api.push_back("/privet/register");
+  } else {
+    info->api.push_back("/privet/capabilities");
+    if (IsLocalPrintingAllowed()) {
+      info->api.push_back("/privet/printer/createjob");
+      info->api.push_back("/privet/printer/submitdoc");
+      info->api.push_back("/privet/printer/jobstate");
+    }
+  }
 
   info->type.push_back("printer");
 }
 
 bool Printer::IsRegistered() const {
-  return reg_info_.state == RegistrationInfo::DEV_REG_REGISTERED;
+  return state_.registration_state == PrinterState::REGISTERED;
+}
+
+bool Printer::IsLocalPrintingAllowed() const {
+  return state_.local_settings.local_printing_enabled;
 }
 
 bool Printer::CheckXPrivetTokenHeader(const std::string& token) const {
   return xtoken_.CheckValidXToken(token);
 }
 
+scoped_ptr<base::DictionaryValue> Printer::GetCapabilities() {
+  scoped_ptr<base::Value> value(base::JSONReader::Read(kCdd));
+  base::DictionaryValue* dictionary_value = NULL;
+  value->GetAsDictionary(&dictionary_value);
+  return scoped_ptr<base::DictionaryValue>(dictionary_value->DeepCopy());
+}
+
+LocalPrintJob::CreateResult Printer::CreateJob(const std::string& ticket,
+                                               std::string* job_id,
+                                               int* expires_in,
+                                               int* error_timeout,
+                                               std::string* error_description) {
+  return print_job_handler_->CreatePrintJob(ticket, job_id, expires_in,
+                                            error_timeout, error_description);
+}
+
+LocalPrintJob::SaveResult Printer::SubmitDoc(const LocalPrintJob& job,
+                                             std::string* job_id,
+                                             int* expires_in,
+                                             std::string* error_description,
+                                             int* timeout) {
+  return print_job_handler_->SaveLocalPrintJob(job, job_id, expires_in,
+                                               error_description, timeout);
+}
+
+LocalPrintJob::SaveResult Printer::SubmitDocWithId(
+    const LocalPrintJob& job,
+    const std::string& job_id,
+    int* expires_in,
+    std::string* error_description,
+    int* timeout) {
+  return print_job_handler_->CompleteLocalPrintJob(job, job_id, expires_in,
+                                                   error_description, timeout);
+}
+
+bool Printer::GetJobState(const std::string& id, LocalPrintJob::Info* info) {
+  return print_job_handler_->GetJobState(id, info);
+}
+
 void Printer::OnRegistrationStartResponseParsed(
     const std::string& registration_token,
     const std::string& complete_invite_url,
     const std::string& device_id) {
-  reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY;
-  reg_info_.device_id = device_id;
-  reg_info_.registration_token = registration_token;
-  reg_info_.complete_invite_url = complete_invite_url;
+  state_.registration_state = PrinterState::REGISTRATION_CLAIM_TOKEN_READY;
+  state_.device_id = device_id;
+  state_.registration_token = registration_token;
+  state_.complete_invite_url = complete_invite_url;
 }
 
-void Printer::OnGetAuthCodeResponseParsed(const std::string& refresh_token,
-                                          const std::string& access_token,
-                                          int access_token_expires_in_seconds) {
-  reg_info_.state = RegistrationInfo::DEV_REG_REGISTERED;
-  reg_info_.refresh_token = refresh_token;
+void Printer::OnRegistrationFinished(const std::string& refresh_token,
+                                     const std::string& access_token,
+                                     int access_token_expires_in_seconds) {
+  InvalidateRegistrationExpiration();
+
+  state_.registration_state = PrinterState::REGISTERED;
+  state_.refresh_token = refresh_token;
   RememberAccessToken(access_token, access_token_expires_in_seconds);
   TryConnect();
 }
@@ -373,34 +447,30 @@
 }
 
 void Printer::OnXmppJidReceived(const std::string& xmpp_jid) {
-  reg_info_.xmpp_jid = xmpp_jid;
+  state_.xmpp_jid = xmpp_jid;
 }
 
 void Printer::OnRegistrationError(const std::string& description) {
   LOG(ERROR) << "server_error: " << description;
 
-  // TODO(maksymb): Implement waiting after error and timeout of registration.
-  reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_ERROR;
-  reg_info_.error_description = description;
+  SetRegistrationError(description);
 }
 
 void Printer::OnNetworkError() {
   VLOG(3) << "Function: " << __FUNCTION__;
-  ChangeState(OFFLINE);
+  FallOffline(false);
 }
 
 void Printer::OnServerError(const std::string& description) {
   VLOG(3) << "Function: " << __FUNCTION__;
   LOG(ERROR) << "Server error: " << description;
-
-  ChangeState(OFFLINE);
+  FallOffline(false);
 }
 
 void Printer::OnPrintJobsAvailable(const std::vector<Job>& jobs) {
   VLOG(3) << "Function: " << __FUNCTION__;
 
   LOG(INFO) << "Available printjobs: " << jobs.size();
-
   if (jobs.empty()) {
     pending_print_jobs_check_ = false;
     PostOnIdle();
@@ -414,11 +484,8 @@
 
 void Printer::OnPrintJobDownloaded(const Job& job) {
   VLOG(3) << "Function: " << __FUNCTION__;
-  print_job_handler_->SavePrintJob(
-      job.file,
-      job.ticket,
-      base::StringPrintf("%s.%s", job.create_time.c_str(), job.job_id.c_str()),
-      job.title);
+  print_job_handler_->SavePrintJob(job.file, job.ticket, job.create_time,
+                                   job.job_id, "remote", job.title, "pdf");
   requester_->SendPrintJobDone(job.job_id);
 }
 
@@ -427,6 +494,33 @@
   PostOnIdle();
 }
 
+void Printer::OnLocalSettingsReceived(LocalSettings::State state,
+                                      const LocalSettings& settings) {
+  pending_local_settings_check_ = false;
+  switch (state) {
+    case LocalSettings::CURRENT:
+      LOG(INFO) << "No new local settings";
+      PostOnIdle();
+      break;
+    case LocalSettings::PENDING:
+      LOG(INFO) << "New local settings were received";
+      ApplyLocalSettings(settings);
+      break;
+    case LocalSettings::PRINTER_DELETED:
+      LOG(WARNING) << "Printer was deleted on server";
+      pending_deletion_ = true;
+      PostOnIdle();
+      break;
+
+    default:
+      NOTREACHED();
+  }
+}
+
+void Printer::OnLocalSettingsUpdated() {
+  PostOnIdle();
+}
+
 void Printer::OnXmppConnected() {
   pending_local_settings_check_ = true;
   pending_print_jobs_check_ = true;
@@ -439,22 +533,22 @@
 }
 
 void Printer::OnXmppNetworkError() {
-  ChangeState(OFFLINE);
+  FallOffline(false);
 }
 
 void Printer::OnXmppNewPrintJob(const std::string& device_id) {
-  DCHECK_EQ(reg_info_.device_id, device_id) << "Data should contain printer_id";
+  DCHECK_EQ(state_.device_id, device_id) << "Data should contain printer_id";
   pending_print_jobs_check_ = true;
 }
 
 void Printer::OnXmppNewLocalSettings(const std::string& device_id) {
-  DCHECK_EQ(reg_info_.device_id, device_id) << "Data should contain printer_id";
-  NOTIMPLEMENTED();
+  DCHECK_EQ(state_.device_id, device_id) << "Data should contain printer_id";
+  pending_local_settings_check_ = true;
 }
 
 void Printer::OnXmppDeleteNotification(const std::string& device_id) {
-  DCHECK_EQ(reg_info_.device_id, device_id) << "Data should contain printer_id";
-  NOTIMPLEMENTED();
+  DCHECK_EQ(state_.device_id, device_id) << "Data should contain printer_id";
+  pending_deletion_ = true;
 }
 
 void Printer::TryConnect() {
@@ -465,8 +559,8 @@
     requester_.reset(new CloudPrintRequester(GetTaskRunner(), this));
 
   if (IsRegistered()) {
-    if (access_token_update_ < base::Time::Now()) {
-      requester_->UpdateAccesstoken(reg_info_.refresh_token);
+    if (state_.access_token_update < base::Time::Now()) {
+      requester_->UpdateAccesstoken(state_.refresh_token);
     } else {
       ConnectXmpp();
     }
@@ -478,9 +572,10 @@
 
 void Printer::ConnectXmpp() {
   xmpp_listener_.reset(
-      new CloudPrintXmppListener(reg_info_.xmpp_jid, kXmppPingIntervalDefault,
+      new CloudPrintXmppListener(state_.xmpp_jid,
+                                 state_.local_settings.xmpp_timeout_value,
                                  GetTaskRunner(), this));
-  xmpp_listener_->Connect(access_token_);
+  xmpp_listener_->Connect(state_.access_token);
 }
 
 void Printer::OnIdle() {
@@ -491,15 +586,18 @@
   if (connection_state_ != ONLINE)
     return;
 
-  if (access_token_update_ < base::Time::Now()) {
-    requester_->UpdateAccesstoken(reg_info_.refresh_token);
+  if (pending_deletion_) {
+    OnPrinterDeleted();
+    return;
+  }
+
+  if (state_.access_token_update < base::Time::Now()) {
+    requester_->UpdateAccesstoken(state_.refresh_token);
     return;
   }
 
   // TODO(maksymb): Check if privet-accesstoken was requested.
 
-  // TODO(maksymb): Check if local-printing was requested.
-
   if (pending_local_settings_check_) {
     GetLocalSettings();
     return;
@@ -516,50 +614,90 @@
         base::TimeDelta::FromMilliseconds(1000));
 }
 
-void Printer::GetLocalSettings() {
-  DCHECK(IsRegistered());
-
-  pending_local_settings_check_ = false;
-  PostOnIdle();
-}
-
 void Printer::FetchPrintJobs() {
   VLOG(3) << "Function: " << __FUNCTION__;
-
   DCHECK(IsRegistered());
-  requester_->FetchPrintJobs(reg_info_.device_id);
+  requester_->FetchPrintJobs(state_.device_id);
+}
+
+void Printer::GetLocalSettings() {
+  VLOG(3) << "Function: " << __FUNCTION__;
+  DCHECK(IsRegistered());
+  requester_->RequestLocalSettings(state_.device_id);
+}
+
+void Printer::ApplyLocalSettings(const LocalSettings& settings) {
+  state_.local_settings = settings;
+  SaveToFile();
+
+  if (state_.local_settings.local_discovery) {
+    bool success = StartLocalDiscoveryServers();
+    if (!success)
+      LOG(ERROR) << "Local discovery servers cannot be started";
+    // TODO(maksymb): If start failed try to start them again after some timeout
+  } else {
+    dns_server_.Shutdown();
+    http_server_.Shutdown();
+  }
+  xmpp_listener_->set_ping_interval(state_.local_settings.xmpp_timeout_value);
+
+  requester_->SendLocalSettings(state_.device_id, state_.local_settings);
+}
+
+void Printer::OnPrinterDeleted() {
+  pending_deletion_ = false;
+
+  state_ = PrinterState();
+
+  SaveToFile();
+  Stop();
+  Start();
 }
 
 void Printer::RememberAccessToken(const std::string& access_token,
                                   int expires_in_seconds) {
   using base::Time;
   using base::TimeDelta;
-  access_token_ = access_token;
+  state_.access_token = access_token;
   int64 time_to_update = static_cast<int64>(expires_in_seconds *
                                             kTimeToNextAccessTokenUpdate);
-  access_token_update_ = Time::Now() + TimeDelta::FromSeconds(time_to_update);
+  state_.access_token_update =
+      Time::Now() + TimeDelta::FromSeconds(time_to_update);
   VLOG(1) << "Current access_token: " << access_token;
   SaveToFile();
 }
 
-PrivetHttpServer::RegistrationErrorStatus Printer::CheckCommonRegErrors(
-    const std::string& user) const {
+void Printer::SetRegistrationError(const std::string& description) {
   DCHECK(!IsRegistered());
+  state_.registration_state = PrinterState::REGISTRATION_ERROR;
+  state_.error_description = description;
+}
 
-  if (reg_info_.state != RegistrationInfo::DEV_REG_UNREGISTERED &&
-      user != reg_info_.user) {
+PrivetHttpServer::RegistrationErrorStatus Printer::CheckCommonRegErrors(
+    const std::string& user) {
+  CheckRegistrationExpiration();
+  DCHECK(!IsRegistered());
+  if (connection_state_ != ONLINE)
+    return PrivetHttpServer::REG_ERROR_OFFLINE;
+
+  if (state_.registration_state != PrinterState::UNREGISTERED &&
+      user != state_.user) {
     return PrivetHttpServer::REG_ERROR_DEVICE_BUSY;
   }
 
-  if (reg_info_.state == RegistrationInfo::DEV_REG_REGISTRATION_ERROR)
+  if (state_.registration_state == PrinterState::REGISTRATION_ERROR)
     return PrivetHttpServer::REG_ERROR_SERVER_ERROR;
 
+  DCHECK_EQ(connection_state_, ONLINE);
+
   return PrivetHttpServer::REG_ERROR_OK;
 }
 
 void Printer::WaitUserConfirmation(base::Time valid_until) {
+  // TODO(maksymb): Move to separate class.
+
   if (base::Time::Now() > valid_until) {
-    reg_info_.confirmation_state = RegistrationInfo::CONFIRMATION_TIMEOUT;
+    state_.confirmation_state = PrinterState::CONFIRMATION_TIMEOUT;
     LOG(INFO) << "Confirmation timeout reached.";
     return;
   }
@@ -567,10 +705,10 @@
   if (_kbhit()) {
     int c = _getche();
     if (c == 'y' || c == 'Y') {
-      reg_info_.confirmation_state = RegistrationInfo::CONFIRMATION_CONFIRMED;
+      state_.confirmation_state = PrinterState::CONFIRMATION_CONFIRMED;
       LOG(INFO) << "Registration confirmed by user.";
     } else {
-      reg_info_.confirmation_state = RegistrationInfo::CONFIRMATION_DISCARDED;
+      state_.confirmation_state = PrinterState::CONFIRMATION_DISCARDED;
       LOG(INFO) << "Registration discarded by user.";
     }
     return;
@@ -593,7 +731,7 @@
   txt.push_back("note=" + std::string(kPrinterDescription));
   txt.push_back("url=" + std::string(kCloudPrintUrl));
   txt.push_back("type=printer");
-  txt.push_back("id=" + reg_info_.device_id);
+  txt.push_back("id=" + state_.device_id);
   txt.push_back("cs=" + ConnectionStateToString(connection_state_));
 
   return txt;
@@ -604,112 +742,31 @@
   file_path = file_path.AppendASCII(
       command_line_reader::ReadStatePath(kPrinterStatePathDefault));
 
-  base::DictionaryValue json;
-  // TODO(maksymb): Get rid of in-place constants.
-  if (IsRegistered()) {
-    json.SetBoolean("registered", true);
-    json.SetString("user", reg_info_.user);
-    json.SetString("device_id", reg_info_.device_id);
-    json.SetString("refresh_token", reg_info_.refresh_token);
-    json.SetString("xmpp_jid", reg_info_.xmpp_jid);
-    json.SetString("access_token", access_token_);
-    json.SetInteger("access_token_update",
-                    static_cast<int>(access_token_update_.ToTimeT()));
+  if (printer_state::SaveToFile(file_path, state_)) {
+    LOG(INFO) << "Printer state written to file";
   } else {
-    json.SetBoolean("registered", false);
+    LOG(INFO) << "Cannot write printer state to file";
   }
-
-  std::string json_str;
-  base::JSONWriter::WriteWithOptions(&json,
-                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
-                                     &json_str);
-  if (!file_util::WriteFile(file_path, json_str.data(),
-                            static_cast<int>(json_str.size()))) {
-    LOG(ERROR) << "Cannot write state.";
-  }
-  LOG(INFO) << "State written to file.";
 }
 
 bool Printer::LoadFromFile() {
+  state_ = PrinterState();
+
   base::FilePath file_path;
   file_path = file_path.AppendASCII(
       command_line_reader::ReadStatePath(kPrinterStatePathDefault));
+
   if (!base::PathExists(file_path)) {
-    LOG(INFO) << "Registration info is not found. Printer is unregistered.";
+    LOG(INFO) << "Printer state file not found";
     return false;
   }
 
-  LOG(INFO) << "Loading registration info from file.";
-  std::string json_str;
-  if (!file_util::ReadFileToString(file_path, &json_str)) {
-    LOG(ERROR) << "Cannot open file.";
-    return false;
+  if (printer_state::LoadFromFile(file_path, &state_)) {
+    LOG(INFO) << "Printer state loaded from file";
+  } else {
+    LOG(INFO) << "Reading/parsing printer state from file failed";
   }
 
-  scoped_ptr<base::Value> json_val(base::JSONReader::Read(json_str));
-  base::DictionaryValue* json = NULL;
-  if (!json_val || !json_val->GetAsDictionary(&json)) {
-    LOG(ERROR) << "Cannot read JSON dictionary from file.";
-    return false;
-  }
-
-  bool registered = false;
-  if (!json->GetBoolean("registered", &registered)) {
-    LOG(ERROR) << "Cannot parse |registered| state.";
-    return false;
-  }
-
-  if (!registered) {
-    reg_info_ = RegistrationInfo();
-    return true;
-  }
-
-  std::string user;
-  if (!json->GetString("user", &user)) {
-    LOG(ERROR) << "Cannot parse |user|.";
-    return false;
-  }
-
-  std::string device_id;
-  if (!json->GetString("device_id", &device_id)) {
-    LOG(ERROR) << "Cannot parse |device_id|.";
-    return false;
-  }
-
-  std::string refresh_token;
-  if (!json->GetString("refresh_token", &refresh_token)) {
-    LOG(ERROR) << "Cannot parse |refresh_token|.";
-    return false;
-  }
-
-  std::string xmpp_jid;
-  if (!json->GetString("xmpp_jid", &xmpp_jid)) {
-    LOG(ERROR) << "Cannot parse |xmpp_jid|.";
-    return false;
-  }
-
-  std::string access_token;
-  if (!json->GetString("access_token", &access_token)) {
-    LOG(ERROR) << "Cannot parse |access_token|.";
-    return false;
-  }
-
-  int access_token_update;
-  if (!json->GetInteger("access_token_update", &access_token_update)) {
-    LOG(ERROR) << "Cannot parse |access_token_update|.";
-    return false;
-  }
-
-  reg_info_ = RegistrationInfo();
-  reg_info_.state = RegistrationInfo::DEV_REG_REGISTERED;
-  reg_info_.user = user;
-  reg_info_.device_id = device_id;
-  reg_info_.refresh_token = refresh_token;
-  reg_info_.xmpp_jid = xmpp_jid;
-  using base::Time;
-  access_token_ = access_token;
-  access_token_update_ = Time::FromTimeT(access_token_update);
-
   return true;
 }
 
@@ -723,18 +780,77 @@
       base::Bind(&Printer::OnIdle, AsWeakPtr()));
 }
 
+void Printer::CheckRegistrationExpiration() {
+  if (!registration_expiration_.is_null() &&
+      registration_expiration_ < base::Time::Now()) {
+    state_ = PrinterState();
+    InvalidateRegistrationExpiration();
+  }
+}
+
+void Printer::UpdateRegistrationExpiration() {
+  registration_expiration_ =
+      base::Time::Now() + base::TimeDelta::FromSeconds(kRegistrationTimeout);
+}
+
+void Printer::InvalidateRegistrationExpiration() {
+  registration_expiration_ = base::Time();
+}
+
+bool Printer::StartLocalDiscoveryServers() {
+  if (!StartHttpServer())
+    return false;
+  if (!StartDnsServer()) {
+    http_server_.Shutdown();
+    return false;
+  }
+  return true;
+}
+
+bool Printer::StartDnsServer() {
+  DCHECK(state_.local_settings.local_discovery);
+
+  // TODO(maksymb): Add switch for command line to control interface name.
+  net::IPAddressNumber ip = GetLocalIp("", false);
+  if (ip.empty()) {
+    LOG(ERROR) << "No local IP found. Cannot start printer.";
+    return false;
+  }
+  VLOG(1) << "Local address: " << net::IPAddressToString(ip);
+
+  uint16 port = command_line_reader::ReadHttpPort(kHttpPortDefault);
+
+  std::string service_name_prefix =
+      command_line_reader::ReadServiceNamePrefix(kServiceNamePrefixDefault);
+  std::string service_domain_name =
+      command_line_reader::ReadDomainName(kServiceDomainNameDefault);
+
+  ServiceParameters params(kServiceType, service_name_prefix,
+                           service_domain_name, ip, port);
+
+  return dns_server_.Start(params,
+                           command_line_reader::ReadTtl(kTtlDefault),
+                           CreateTxt());
+}
+
+bool Printer::StartHttpServer() {
+  DCHECK(state_.local_settings.local_discovery);
+  using command_line_reader::ReadHttpPort;
+  return http_server_.Start(ReadHttpPort(kHttpPortDefault));
+}
+
 PrivetHttpServer::RegistrationErrorStatus
-    Printer::ConfirmationToRegistrationError(
-        RegistrationInfo::ConfirmationState state) {
+Printer::ConfirmationToRegistrationError(
+    PrinterState::ConfirmationState state) {
   switch (state) {
-    case RegistrationInfo::CONFIRMATION_PENDING:
+    case PrinterState::CONFIRMATION_PENDING:
       return PrivetHttpServer::REG_ERROR_PENDING_USER_ACTION;
-    case RegistrationInfo::CONFIRMATION_DISCARDED:
+    case PrinterState::CONFIRMATION_DISCARDED:
       return PrivetHttpServer::REG_ERROR_USER_CANCEL;
-    case RegistrationInfo::CONFIRMATION_CONFIRMED:
+    case PrinterState::CONFIRMATION_CONFIRMED:
       NOTREACHED();
       return PrivetHttpServer::REG_ERROR_OK;
-    case RegistrationInfo::CONFIRMATION_TIMEOUT:
+    case PrinterState::CONFIRMATION_TIMEOUT:
       return PrivetHttpServer::REG_ERROR_CONFIRMATION_TIMEOUT;
     default:
       NOTREACHED();
@@ -759,6 +875,23 @@
   }
 }
 
+void Printer::FallOffline(bool instant_reconnect) {
+  bool changed = ChangeState(OFFLINE);
+  DCHECK(changed) << "Falling offline from offline is now allowed";
+
+  if (!IsRegistered())
+    SetRegistrationError("Cannot access server during registration process");
+
+  if (instant_reconnect) {
+    TryConnect();
+  } else {
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&Printer::TryConnect, AsWeakPtr()),
+        base::TimeDelta::FromSeconds(kReconnectTimeout));
+  }
+}
+
 bool Printer::ChangeState(ConnectionState new_state) {
   if (connection_state_ == new_state)
     return false;
@@ -771,26 +904,9 @@
 
   dns_server_.UpdateMetadata(CreateTxt());
 
-  switch (connection_state_) {
-    case CONNECTING:
-      break;
-
-    case ONLINE:
-      break;
-
-    case OFFLINE:
-      requester_.reset();
-      xmpp_listener_.reset();
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&Printer::TryConnect, AsWeakPtr()),
-          base::TimeDelta::FromSeconds(kReconnectTimeout));
-
-    case NOT_CONFIGURED:
-      break;
-
-    default:
-      NOTREACHED();
+  if (connection_state_ == OFFLINE) {
+    requester_.reset();
+    xmpp_listener_.reset();
   }
 
   return true;
diff --git a/cloud_print/gcp20/prototype/printer.h b/cloud_print/gcp20/prototype/printer.h
index fab9189..69e8874 100644
--- a/cloud_print/gcp20/prototype/printer.h
+++ b/cloud_print/gcp20/prototype/printer.h
@@ -14,6 +14,7 @@
 #include "cloud_print/gcp20/prototype/cloud_print_xmpp_listener.h"
 #include "cloud_print/gcp20/prototype/dns_sd_server.h"
 #include "cloud_print/gcp20/prototype/print_job_handler.h"
+#include "cloud_print/gcp20/prototype/printer_state.h"
 #include "cloud_print/gcp20/prototype/privet_http_server.h"
 #include "cloud_print/gcp20/prototype/x_privet_token.h"
 
@@ -41,50 +42,7 @@
   void Stop();
 
  private:
-  struct RegistrationInfo {
-    enum RegistrationState {
-      DEV_REG_UNREGISTERED,
-      DEV_REG_REGISTRATION_STARTED,  // |action=start| was called,
-                                     // request to CloudPrint was sent.
-      DEV_REG_REGISTRATION_CLAIM_TOKEN_READY,  // The same as previous,
-                                               // but request reply is already
-                                               // received.
-      DEV_REG_REGISTRATION_COMPLETING,  // |action=complete| was called,
-                                        // |complete| request was sent.
-      DEV_REG_REGISTRATION_ERROR,  // Is set when server error was occurred.
-      DEV_REG_REGISTERED,
-    };
-
-    enum ConfirmationState {
-      CONFIRMATION_PENDING,
-      CONFIRMATION_CONFIRMED,
-      CONFIRMATION_DISCARDED,
-      CONFIRMATION_TIMEOUT,
-    };
-
-    RegistrationInfo();
-    ~RegistrationInfo();
-
-    std::string user;
-    std::string refresh_token;
-    std::string device_id;
-    std::string xmpp_jid;
-    RegistrationState state;
-    ConfirmationState confirmation_state;
-
-    std::string registration_token;
-    std::string complete_invite_url;
-
-    // Contains error response if |DEV_REG_REGISTRATION_ERROR| is set.
-    std::string error_description;
-  };
-
-  enum RegistrationAction {
-    REG_ACTION_START,
-    REG_ACTION_GET_CLAIM_TOKEN,
-    REG_ACTION_COMPLETE,
-    REG_ACTION_CANCEL
-  };
+  FRIEND_TEST_ALL_PREFIXES(Printer, ValidateCapabilities);
 
   enum ConnectionState {
     NOT_CONFIGURED,
@@ -93,6 +51,9 @@
     CONNECTING
   };
 
+  // For testing purposes.
+  static std::string GetRawCdd();
+
   // PrivetHttpServer::Delegate methods:
   virtual PrivetHttpServer::RegistrationErrorStatus RegistrationStart(
       const std::string& user) OVERRIDE;
@@ -108,14 +69,36 @@
   virtual void GetRegistrationServerError(std::string* description) OVERRIDE;
   virtual void CreateInfo(PrivetHttpServer::DeviceInfo* info) OVERRIDE;
   virtual bool IsRegistered() const OVERRIDE;
+  virtual bool IsLocalPrintingAllowed() const OVERRIDE;
   virtual bool CheckXPrivetTokenHeader(const std::string& token) const OVERRIDE;
+  virtual scoped_ptr<base::DictionaryValue> GetCapabilities() OVERRIDE;
+  virtual LocalPrintJob::CreateResult CreateJob(
+      const std::string& ticket,
+      std::string* job_id,
+      int* expires_in,
+      int* error_timeout,
+      std::string* error_description) OVERRIDE;
+  virtual LocalPrintJob::SaveResult SubmitDoc(
+      const LocalPrintJob& job,
+      std::string* job_id,
+      int* expires_in,
+      std::string* error_description,
+      int* timeout) OVERRIDE;
+  virtual LocalPrintJob::SaveResult SubmitDocWithId(
+      const LocalPrintJob& job,
+      const std::string& job_id,
+      int* expires_in,
+      std::string* error_description,
+      int* timeout) OVERRIDE;
+  virtual bool GetJobState(const std::string& id,
+                           LocalPrintJob::Info* info) OVERRIDE;
 
   // CloudRequester::Delegate methods:
   virtual void OnRegistrationStartResponseParsed(
       const std::string& registration_token,
       const std::string& complete_invite_url,
       const std::string& device_id) OVERRIDE;
-  virtual void OnGetAuthCodeResponseParsed(
+  virtual void OnRegistrationFinished(
       const std::string& refresh_token,
       const std::string& access_token,
       int access_token_expires_in_seconds) OVERRIDE;
@@ -132,6 +115,10 @@
   virtual void OnPrintJobDownloaded(
       const cloud_print_response_parser::Job& job) OVERRIDE;
   virtual void OnPrintJobDone() OVERRIDE;
+  virtual void OnLocalSettingsReceived(
+      LocalSettings::State state,
+      const LocalSettings& settings) OVERRIDE;
+  virtual void OnLocalSettingsUpdated() OVERRIDE;
 
   // CloudPrintXmppListener::Delegate methods:
   virtual void OnXmppConnected() OVERRIDE;
@@ -151,25 +138,30 @@
   // Do *NOT* call this method instantly. Only with |PostOnIdle|.
   void OnIdle();
 
-  // Method for checking printer status.
-  // (e.g. printjobs, local settings, deleted status).
-  void CheckPendingUpdates();
+  // Ask Cloud Print server for printjobs.
+  void FetchPrintJobs();
 
-  // Ask CloudPrint server for new local sendings.
+  // Ask Cloud Print server for new local sendings.
   void GetLocalSettings();
 
-  // Ask CloudPrint server for printjobs.
-  void FetchPrintJobs();
+  // Applies new local settings to printer.
+  void ApplyLocalSettings(const LocalSettings& settings);
+
+  // Used for erasing all printer info.
+  void OnPrinterDeleted();
 
   // Saves |access_token| and calculates time for next update.
   void RememberAccessToken(const std::string& access_token,
                            int expires_in_seconds);
 
+  // Sets registration state to error and adds description.
+  void SetRegistrationError(const std::string& description);
+
   // Checks if register call is called correctly (|user| is correct,
   // error is no set etc). Returns |false| if error status is put into |status|.
   // Otherwise no error was occurred.
   PrivetHttpServer::RegistrationErrorStatus CheckCommonRegErrors(
-      const std::string& user) const;
+      const std::string& user);
 
   // Checks if confirmation was received.
   void WaitUserConfirmation(base::Time valid_until);
@@ -187,16 +179,43 @@
   // Adds |OnIdle| method to the MessageLoop.
   void PostOnIdle();
 
+  // Registration timeout.
+  void CheckRegistrationExpiration();
+
+  // Delays expiration after user action.
+  void UpdateRegistrationExpiration();
+
+  // Deletes registration expiration at all.
+  void InvalidateRegistrationExpiration();
+
+  // Methods to start HTTP and DNS-SD servers. Return |true| if servers
+  // were started. If failed neither HTTP nor DNS-SD server will be running.
+  bool StartLocalDiscoveryServers();
+
+  // Methods to start HTTP and DNS-SD servers. Return |true| if servers
+  // were started.
+  bool StartDnsServer();
+  bool StartHttpServer();
+
   // Converts errors.
   PrivetHttpServer::RegistrationErrorStatus ConfirmationToRegistrationError(
-      RegistrationInfo::ConfirmationState state);
+      PrinterState::ConfirmationState state);
 
   std::string ConnectionStateToString(ConnectionState state) const;
 
-  // Changes state and update info in DNS server.
+  // Changes state to OFFLINE and posts TryReconnect.
+  // For registration reconnect is instant every time.
+  void FallOffline(bool instant_reconnect);
+
+  // Changes state and update info in DNS server. Returns |true| if state
+  // was changed (otherwise state was the same).
   bool ChangeState(ConnectionState new_state);
 
-  RegistrationInfo reg_info_;
+  // Contains printers workflow info.
+  PrinterState state_;
+
+  // Connection state of device.
+  ConnectionState connection_state_;
 
   // Contains DNS-SD server.
   DnsSdServer dns_server_;
@@ -204,9 +223,6 @@
   // Contains Privet HTTP server.
   PrivetHttpServer http_server_;
 
-  // Connection state of device.
-  ConnectionState connection_state_;
-
   // Contains CloudPrint client.
   scoped_ptr<CloudPrintRequester> requester_;
 
@@ -217,13 +233,12 @@
 
   scoped_ptr<PrintJobHandler> print_job_handler_;
 
-  // Last valid |access_token|.
-  std::string access_token_;
-  base::Time access_token_update_;
-
   // Uses for calculating uptime.
   base::Time starttime_;
 
+  // Uses to validate registration timeout.
+  base::Time registration_expiration_;
+
   // Used for preventing two and more OnIdle posted in message loop.
   bool on_idle_posted_;
 
@@ -233,6 +248,9 @@
   // Contains |true| if Printer has to check available printjobs.
   bool pending_print_jobs_check_;
 
+  // Contains |true| if Printer has to be deleted.
+  bool pending_deletion_;
+
   DISALLOW_COPY_AND_ASSIGN(Printer);
 };
 
diff --git a/cloud_print/gcp20/prototype/printer_state.cc b/cloud_print/gcp20/prototype/printer_state.cc
new file mode 100644
index 0000000..78dbaa99
--- /dev/null
+++ b/cloud_print/gcp20/prototype/printer_state.cc
@@ -0,0 +1,166 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cloud_print/gcp20/prototype/printer_state.h"
+
+#include "base/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace {
+
+const char kRegistered[] = "registered";
+const char kUser[] = "user";
+const char kDeviceId[] = "device_id";
+const char kRefreshToken[] = "refresh_token";
+const char kXmppJid[] = "xmpp_jid";
+const char kAccessToken[] = "access_token";
+const char kAccessTokenUpdate[] = "access_token_update";
+
+const char kLocalSettings[] = "local_settings";
+const char kLocalSettingsLocalDiscovery[] = "local_discovery";
+const char kLocalSettingsAccessTokenEnabled[] = "access_token_enabled";
+const char kLocalSettingsLocalPrintingEnabled[] =
+    "printer/local_printing_enabled";
+const char kLocalSettingsXmppTimeoutValue[] = "xmpp_timeout_value";
+
+}  // namespace
+
+PrinterState::PrinterState()
+    : registration_state(UNREGISTERED),
+      confirmation_state(CONFIRMATION_PENDING) {
+}
+
+PrinterState::~PrinterState() {
+}
+
+namespace printer_state {
+
+bool SaveToFile(const base::FilePath& path, const PrinterState& state) {
+  base::DictionaryValue json;
+  if (state.registration_state == PrinterState::REGISTERED) {
+    json.SetBoolean(kRegistered, true);
+    json.SetString(kUser, state.user);
+    json.SetString(kDeviceId, state.device_id);
+    json.SetString(kRefreshToken, state.refresh_token);
+    json.SetString(kXmppJid, state.xmpp_jid);
+    json.SetString(kAccessToken, state.access_token);
+    json.SetInteger(kAccessTokenUpdate,
+                    static_cast<int>(state.access_token_update.ToTimeT()));
+
+    scoped_ptr<base::DictionaryValue> local_settings(new base::DictionaryValue);
+    local_settings->SetBoolean(kLocalSettingsLocalDiscovery,
+                               state.local_settings.local_discovery);
+    local_settings->SetBoolean(kLocalSettingsAccessTokenEnabled,
+                               state.local_settings.access_token_enabled);
+    local_settings->SetBoolean(kLocalSettingsLocalPrintingEnabled,
+                               state.local_settings.local_printing_enabled);
+    local_settings->SetInteger(kLocalSettingsXmppTimeoutValue,
+                               state.local_settings.xmpp_timeout_value);
+    json.Set(kLocalSettings, local_settings.release());
+  } else {
+    json.SetBoolean(kRegistered, false);
+  }
+
+  std::string json_str;
+  base::JSONWriter::WriteWithOptions(&json,
+                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
+                                     &json_str);
+  return !!file_util::WriteFile(path, json_str.data(),
+                                static_cast<int>(json_str.size()));
+}
+
+bool LoadFromFile(const base::FilePath& path, PrinterState* state) {
+  std::string json_str;
+  if (!file_util::ReadFileToString(path, &json_str)) {
+    LOG(ERROR) << "Cannot open file.";
+    return false;
+  }
+
+  scoped_ptr<base::Value> json_val(base::JSONReader::Read(json_str));
+  base::DictionaryValue* json = NULL;
+  if (!json_val || !json_val->GetAsDictionary(&json)) {
+    LOG(ERROR) << "Cannot read JSON dictionary from file.";
+    return false;
+  }
+
+  bool registered = false;
+  if (!json->GetBoolean(kRegistered, &registered)) {
+    LOG(ERROR) << "Cannot parse |registered| state.";
+    return false;
+  }
+
+  if (!registered)
+    return true;
+
+  std::string user;
+  if (!json->GetString(kUser, &user)) {
+    LOG(ERROR) << "Cannot parse |user|.";
+    return false;
+  }
+
+  std::string device_id;
+  if (!json->GetString(kDeviceId, &device_id)) {
+    LOG(ERROR) << "Cannot parse |device_id|.";
+    return false;
+  }
+
+  std::string refresh_token;
+  if (!json->GetString(kRefreshToken, &refresh_token)) {
+    LOG(ERROR) << "Cannot parse |refresh_token|.";
+    return false;
+  }
+
+  std::string xmpp_jid;
+  if (!json->GetString(kXmppJid, &xmpp_jid)) {
+    LOG(ERROR) << "Cannot parse |xmpp_jid|.";
+    return false;
+  }
+
+  std::string access_token;
+  if (!json->GetString(kAccessToken, &access_token)) {
+    LOG(ERROR) << "Cannot parse |access_token|.";
+    return false;
+  }
+
+  int access_token_update;
+  if (!json->GetInteger(kAccessTokenUpdate, &access_token_update)) {
+    LOG(ERROR) << "Cannot parse |access_token_update|.";
+    return false;
+  }
+
+  LocalSettings local_settings;
+  base::DictionaryValue* settings_dict;
+  if (!json->GetDictionary(kLocalSettings, &settings_dict)) {
+    LOG(WARNING) << "Cannot read |local_settings|. Reset to default.";
+  } else {
+    if (!settings_dict->GetBoolean(kLocalSettingsLocalDiscovery,
+                                   &local_settings.local_discovery) ||
+        !settings_dict->GetBoolean(kLocalSettingsAccessTokenEnabled,
+                                   &local_settings.access_token_enabled) ||
+        !settings_dict->GetBoolean(kLocalSettingsLocalPrintingEnabled,
+                                   &local_settings.local_printing_enabled) ||
+        !settings_dict->GetInteger(kLocalSettingsXmppTimeoutValue,
+                                   &local_settings.xmpp_timeout_value)) {
+      LOG(WARNING) << "Cannot parse |local_settings|. Reset to default.";
+      local_settings = LocalSettings();
+    }
+  }
+
+  *state = PrinterState();
+  state->registration_state = PrinterState::REGISTERED;
+  state->user = user;
+  state->device_id = device_id;
+  state->refresh_token = refresh_token;
+  state->xmpp_jid = xmpp_jid;
+  state->access_token = access_token;
+  state->access_token_update = base::Time::FromTimeT(access_token_update);
+  state->local_settings = local_settings;
+  return true;
+}
+
+}  // namespace printer_state
+
diff --git a/cloud_print/gcp20/prototype/printer_state.h b/cloud_print/gcp20/prototype/printer_state.h
new file mode 100644
index 0000000..6ad0554
--- /dev/null
+++ b/cloud_print/gcp20/prototype/printer_state.h
@@ -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.
+
+#ifndef CLOUD_PRINT_GCP20_PROTOTYPE_PRINTER_STATE_H_
+#define CLOUD_PRINT_GCP20_PROTOTYPE_PRINTER_STATE_H_
+
+#include <string>
+
+#include "base/time/time.h"
+#include "cloud_print/gcp20/prototype/local_settings.h"
+
+namespace base {
+
+class FilePath;
+
+}  // namespace base
+
+struct PrinterState {
+  enum RegistrationState {
+    UNREGISTERED,
+    REGISTRATION_STARTED,  // |action=start| was called,
+                           // request to CloudPrint was sent.
+    REGISTRATION_CLAIM_TOKEN_READY,  // The same as previous, but request
+                                     // reply is already received.
+    REGISTRATION_COMPLETING,  // |action=complete| was called,
+                              // |complete| request was sent.
+    REGISTRATION_ERROR,  // Is set when server error was occurred.
+    REGISTERED,
+  };
+
+  enum ConfirmationState {
+    CONFIRMATION_PENDING,
+    CONFIRMATION_CONFIRMED,
+    CONFIRMATION_DISCARDED,
+    CONFIRMATION_TIMEOUT,
+  };
+
+  PrinterState();
+  ~PrinterState();
+
+  // Registration process info
+  std::string user;
+  std::string registration_token;
+  std::string complete_invite_url;
+  RegistrationState registration_state;
+  ConfirmationState confirmation_state;
+
+  // Printer workflow info
+  std::string refresh_token;
+  std::string device_id;
+  std::string xmpp_jid;
+  LocalSettings local_settings;
+
+  // Last valid |access_token|.
+  std::string access_token;
+  base::Time access_token_update;
+
+  // Contains error if |REGISTRATION_ERROR| is set.
+  std::string error_description;
+};
+
+namespace printer_state {
+
+//
+bool SaveToFile(const base::FilePath& path, const PrinterState& state);
+
+//
+bool LoadFromFile(const base::FilePath& path, PrinterState* state);
+
+}  // namespace printer_state
+
+#endif  // CLOUD_PRINT_GCP20_PROTOTYPE_PRINTER_STATE_H_
+
diff --git a/cloud_print/gcp20/prototype/printer_unittest.cc b/cloud_print/gcp20/prototype/printer_unittest.cc
new file mode 100644
index 0000000..afce69b
--- /dev/null
+++ b/cloud_print/gcp20/prototype/printer_unittest.cc
@@ -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.
+
+#include "cloud_print/gcp20/prototype/printer.h"
+
+#include "base/basictypes.h"
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(Printer, ValidateCapabilities) {
+  int error_code;
+  std::string error_msg;
+  scoped_ptr<base::Value> value(
+      base::JSONReader::ReadAndReturnError(Printer::GetRawCdd(), 0,
+                                           &error_code, &error_msg));
+  ASSERT_TRUE(!!value) << error_msg;
+
+  base::DictionaryValue* dictionary_value = NULL;
+  EXPECT_TRUE(value->GetAsDictionary(&dictionary_value)) << "Not a dictionary";
+}
+
diff --git a/cloud_print/gcp20/prototype/privet_http_server.cc b/cloud_print/gcp20/prototype/privet_http_server.cc
index 0a21059..4251a4f 100644
--- a/cloud_print/gcp20/prototype/privet_http_server.cc
+++ b/cloud_print/gcp20/prototype/privet_http_server.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/json/json_writer.h"
+#include "base/strings/stringprintf.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "net/base/url_util.h"
@@ -17,6 +18,14 @@
 const int kDeviceBusyTimeout = 30;  // in seconds
 const int kPendingUserActionTimeout = 5;  // in seconds
 
+const char kPrivetInfo[] = "/privet/info";
+const char kPrivetRegister[] = "/privet/register";
+const char kPrivetAccessToken[] = "/privet/accesstoken";
+const char kPrivetCapabilities[] = "/privet/capabilities";
+const char kPrivetPrinterCreateJob[] = "/privet/printer/createjob";
+const char kPrivetPrinterSubmitDoc[] = "/privet/printer/submitdoc";
+const char kPrivetPrinterJobState[] = "/privet/printer/jobstate";
+
 // {"error":|error_type|}
 scoped_ptr<base::DictionaryValue> CreateError(const std::string& error_type) {
   scoped_ptr<base::DictionaryValue> error(new base::DictionaryValue);
@@ -34,7 +43,7 @@
   return error.Pass();
 }
 
-// {"error":|error_type|, "timeout":|timout|}
+// {"error":|error_type|, "timeout":|timeout|}
 scoped_ptr<base::DictionaryValue> CreateErrorWithTimeout(
     const std::string& error_type,
     int timeout) {
@@ -43,19 +52,37 @@
   return error.Pass();
 }
 
+// Converts state to string.
+std::string LocalPrintJobStateToString(LocalPrintJob::State state) {
+  switch (state) {
+    case LocalPrintJob::STATE_DRAFT:
+      return "draft";
+      break;
+    case LocalPrintJob::STATE_ABORTED:
+      return "done";
+      break;
+    case LocalPrintJob::STATE_DONE:
+      return "done";
+      break;
+    default:
+      NOTREACHED();
+      return std::string();
+  }
+}
+
+
 // Returns |true| if |request| should be GET method.
 bool IsGetMethod(const std::string& request) {
-  return request == "/privet/info"/* ||
-         request == "/privet/accesstoken" ||
-         request == "/privet/capabilities" ||
-         request == "/privet/printer/jobstate"*/;
+  return request == kPrivetInfo ||
+         request == kPrivetCapabilities ||
+         request == kPrivetPrinterJobState;
 }
 
 // Returns |true| if |request| should be POST method.
 bool IsPostMethod(const std::string& request) {
-  return request == "/privet/register"/* ||
-         request == "/privet/printer/createjob" ||
-         request == "/privet/printer/submitdoc"*/;
+  return request == kPrivetRegister ||
+         request == kPrivetPrinterCreateJob ||
+         request == kPrivetPrinterSubmitDoc;
 }
 
 }  // namespace
@@ -118,7 +145,7 @@
       return;
     }
 
-    if (url.path() != "/privet/info" &&
+    if (url.path() != kPrivetInfo &&
         !delegate_->CheckXPrivetTokenHeader(iter->second)) {
       server_->Send(connection_id, net::HTTP_OK,
                     "{\"error\":\"invalid_x_privet_token\"}",
@@ -128,8 +155,7 @@
   }
 
   std::string response;
-  net::HttpStatusCode status_code =
-      ProcessHttpRequest(url, info.data, &response);
+  net::HttpStatusCode status_code = ProcessHttpRequest(url, info, &response);
 
   server_->Send(connection_id, status_code, response, "application/json");
 }
@@ -175,15 +201,23 @@
 
 net::HttpStatusCode PrivetHttpServer::ProcessHttpRequest(
     const GURL& url,
-    const std::string& data,
+    const net::HttpServerRequestInfo& info,
     std::string* response) {
   net::HttpStatusCode status_code = net::HTTP_OK;
   scoped_ptr<base::DictionaryValue> json_response;
 
-  if (url.path() == "/privet/info") {
+  if (url.path() == kPrivetInfo) {
     json_response = ProcessInfo(&status_code);
-  } else if (url.path() == "/privet/register") {
+  } else if (url.path() == kPrivetRegister) {
     json_response = ProcessRegister(url, &status_code);
+  } else if (url.path() == kPrivetCapabilities) {
+    json_response = ProcessCapabilities(&status_code);
+  } else if (url.path() == kPrivetPrinterCreateJob) {
+    json_response = ProcessCreateJob(url, info.data, &status_code);
+  } else if (url.path() == kPrivetPrinterSubmitDoc) {
+    json_response = ProcessSubmitDoc(url, info, &status_code);
+  } else if (url.path() == kPrivetPrinterJobState) {
+    json_response = ProcessJobState(url, &status_code);
   } else {
     NOTREACHED();
   }
@@ -236,9 +270,147 @@
   return response.Pass();
 }
 
+scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessCapabilities(
+    net::HttpStatusCode* status_code) const {
+  if (!delegate_->IsRegistered()) {
+    *status_code = net::HTTP_NOT_FOUND;
+    return scoped_ptr<base::DictionaryValue>();
+  }
+
+  return delegate_->GetCapabilities();
+}
+
+scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessCreateJob(
+    const GURL& url,
+    const std::string& body,
+    net::HttpStatusCode* status_code) const {
+  if (!delegate_->IsRegistered() || !delegate_->IsLocalPrintingAllowed()) {
+    *status_code = net::HTTP_NOT_FOUND;
+    return scoped_ptr<base::DictionaryValue>();
+  }
+
+  std::string job_id;
+  // TODO(maksymb): Use base::Time for expiration
+  int expires_in = 0;
+  // TODO(maksymb): Use base::TimeDelta for timeout values
+  int error_timeout = -1;
+  std::string error_description;
+
+  LocalPrintJob::CreateResult result =
+      delegate_->CreateJob(body, &job_id, &expires_in,
+                           &error_timeout, &error_description);
+
+  scoped_ptr<base::DictionaryValue> response;
+  *status_code = net::HTTP_OK;
+  switch (result) {
+    case LocalPrintJob::CREATE_SUCCESS:
+      response.reset(new DictionaryValue);
+      response->SetString("job_id", job_id);
+      response->SetInteger("expires_in", expires_in);
+      return response.Pass();
+
+    case LocalPrintJob::CREATE_INVALID_TICKET:
+      return CreateError("invalid_ticket");
+    case LocalPrintJob::CREATE_PRINTER_BUSY:
+      return CreateErrorWithTimeout("printer_busy", error_timeout);
+    case LocalPrintJob::CREATE_PRINTER_ERROR:
+      return CreateErrorWithDescription("printer_error", error_description);
+  }
+  return scoped_ptr<base::DictionaryValue>();
+}
+
+scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessSubmitDoc(
+    const GURL& url,
+    const net::HttpServerRequestInfo& info,
+    net::HttpStatusCode* status_code) const {
+  if (!delegate_->IsRegistered() || !delegate_->IsLocalPrintingAllowed()) {
+    *status_code = net::HTTP_NOT_FOUND;
+    return scoped_ptr<base::DictionaryValue>();
+  }
+
+  using net::GetValueForKeyInQuery;
+
+  // Parse query
+  LocalPrintJob job;
+  std::string offline;
+  std::string job_id;
+  bool job_name_present = GetValueForKeyInQuery(url, "job_name", &job.job_name);
+  bool job_id_present = GetValueForKeyInQuery(url, "job_id", &job_id);
+  GetValueForKeyInQuery(url, "client_name", &job.client_name);
+  GetValueForKeyInQuery(url, "user_name", &job.user_name);
+  GetValueForKeyInQuery(url, "offline", &offline);
+  job.offline = (offline == "1");
+  job.content_type = info.GetHeaderValue("content-type");
+  job.content = info.data;
+
+  // Call delegate
+  // TODO(maksymb): Use base::Time for expiration
+  int expires_in = 0;
+  std::string error_description;
+  int timeout;
+  LocalPrintJob::SaveResult status = job_id_present
+      ? delegate_->SubmitDocWithId(job, job_id, &expires_in,
+                                   &error_description, &timeout)
+      : delegate_->SubmitDoc(job, &job_id, &expires_in,
+                             &error_description, &timeout);
+
+  // Create response
+  *status_code = net::HTTP_OK;
+  scoped_ptr<base::DictionaryValue> response(new DictionaryValue);
+  switch (status) {
+    case LocalPrintJob::SAVE_SUCCESS:
+      response->SetString("job_id", job_id);
+      response->SetInteger("expires_in", expires_in);
+      response->SetString("job_type", job.content_type);
+      response->SetString(
+          "job_size",
+          base::StringPrintf("%u", static_cast<uint32>(job.content.size())));
+      if (job_name_present)
+        response->SetString("job_name", job.job_name);
+      return response.Pass();
+
+    case LocalPrintJob::SAVE_INVALID_PRINT_JOB:
+      return CreateErrorWithTimeout("invalid_print_job", timeout);
+    case LocalPrintJob::SAVE_INVALID_DOCUMENT_TYPE:
+      return CreateError("invalid_document_type");
+    case LocalPrintJob::SAVE_INVALID_DOCUMENT:
+      return CreateError("invalid_document");
+    case LocalPrintJob::SAVE_DOCUMENT_TOO_LARGE:
+      return CreateError("document_too_large");
+    case LocalPrintJob::SAVE_PRINTER_BUSY:
+      return CreateErrorWithTimeout("printer_busy", -2);
+    case LocalPrintJob::SAVE_PRINTER_ERROR:
+      return CreateErrorWithDescription("printer_error", error_description);
+    default:
+      NOTREACHED();
+      return scoped_ptr<base::DictionaryValue>();
+  }
+}
+
+scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessJobState(
+    const GURL& url,
+    net::HttpStatusCode* status_code) const {
+  if (!delegate_->IsRegistered() || !delegate_->IsLocalPrintingAllowed()) {
+    *status_code = net::HTTP_NOT_FOUND;
+    return scoped_ptr<base::DictionaryValue>();
+  }
+
+  std::string job_id;
+  net::GetValueForKeyInQuery(url, "job_id", &job_id);
+  LocalPrintJob::Info info;
+  if (!delegate_->GetJobState(job_id, &info))
+    return CreateError("invalid_print_job");
+
+  scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue);
+  response->SetString("job_id", job_id);
+  response->SetString("state", LocalPrintJobStateToString(info.state));
+  response->SetInteger("expires_in", info.expires_in);
+  return response.Pass();
+}
+
 scoped_ptr<base::DictionaryValue> PrivetHttpServer::ProcessRegister(
     const GURL& url,
-    net::HttpStatusCode* status_code) {
+    net::HttpStatusCode* status_code) const {
   if (delegate_->IsRegistered()) {
     *status_code = net::HTTP_NOT_FOUND;
     return scoped_ptr<base::DictionaryValue>();
@@ -315,6 +487,10 @@
     case REG_ERROR_INVALID_ACTION:
       *current_response = CreateError("invalid_action");
       break;
+    case REG_ERROR_OFFLINE:
+      *current_response = CreateError("offline");
+      break;
+
     case REG_ERROR_SERVER_ERROR: {
       std::string description;
       delegate_->GetRegistrationServerError(&description);
@@ -328,4 +504,3 @@
   };
 }
 
-
diff --git a/cloud_print/gcp20/prototype/privet_http_server.h b/cloud_print/gcp20/prototype/privet_http_server.h
index fc80d90..eb082c6 100644
--- a/cloud_print/gcp20/prototype/privet_http_server.h
+++ b/cloud_print/gcp20/prototype/privet_http_server.h
@@ -10,7 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/values.h"
-#include "net/http/http_status_code.h"
+#include "cloud_print/gcp20/prototype/local_print_job.h"
 #include "net/server/http_server.h"
 #include "net/server/http_server_request_info.h"
 
@@ -29,6 +29,7 @@
     REG_ERROR_USER_CANCEL,
     REG_ERROR_CONFIRMATION_TIMEOUT,
     REG_ERROR_INVALID_ACTION,
+    REG_ERROR_OFFLINE,
     REG_ERROR_SERVER_ERROR
   };
 
@@ -57,8 +58,6 @@
 
   class Delegate {
    public:
-    Delegate() {}
-
     virtual ~Delegate() {}
 
     // Invoked when registration is starting.
@@ -86,11 +85,46 @@
     // Invoked when /privet/info is called.
     virtual void CreateInfo(DeviceInfo* info) = 0;
 
-    // Invoked for checking should /privet/register be exposed.
+    // Invoked for checking wether /privet/register should be exposed.
     virtual bool IsRegistered() const = 0;
 
+    // Invoked for checking wether /privet/printer/* should be exposed.
+    virtual bool IsLocalPrintingAllowed() const = 0;
+
     // Invoked when XPrivetToken has to be checked.
     virtual bool CheckXPrivetTokenHeader(const std::string& token) const = 0;
+
+    // Invoked for getting capabilities.
+    virtual scoped_ptr<base::DictionaryValue> GetCapabilities() = 0;
+
+    // Invoked for creating a job.
+    virtual LocalPrintJob::CreateResult CreateJob(
+        const std::string& ticket,
+        std::string* job_id,
+        int* expires_in,
+        // TODO(maksymb): Use base::TimeDelta for timeouts
+        int* error_timeout,
+        std::string* error_description) = 0;
+
+    // Invoked for simple local printing.
+    virtual LocalPrintJob::SaveResult SubmitDoc(
+        const LocalPrintJob& job,
+        std::string* job_id,
+        int* expires_in,
+        std::string* error_description,
+        int* timeout) = 0;
+
+    // Invoked for advanced local printing.
+    virtual LocalPrintJob::SaveResult SubmitDocWithId(
+        const LocalPrintJob& job,
+        const std::string& job_id,
+        int* expires_in,
+        std::string* error_description,
+        int* timeout) = 0;
+
+    // Invoked for getting job status.
+    virtual bool GetJobState(const std::string& job_id,
+                             LocalPrintJob::Info* info) = 0;
   };
 
   // Constructor doesn't start server.
@@ -129,20 +163,37 @@
 
   // Processes http request after all preparations (XPrivetHeader check,
   // data handling etc.)
-  net::HttpStatusCode ProcessHttpRequest(const GURL& url,
-                                         const std::string& data,
-                                         std::string* response);
+  net::HttpStatusCode ProcessHttpRequest(
+      const GURL& url,
+      const net::HttpServerRequestInfo& info,
+      std::string* response);
 
   // Pivet API methods. Return reference to NULL if output should be empty.
   scoped_ptr<base::DictionaryValue> ProcessInfo(
       net::HttpStatusCode* status_code) const;
-  scoped_ptr<base::DictionaryValue> ProcessReset(
-      net::HttpStatusCode* status_code);
+
+  scoped_ptr<base::DictionaryValue> ProcessCapabilities(
+      net::HttpStatusCode* status_code) const;
+
+  scoped_ptr<base::DictionaryValue> ProcessCreateJob(
+      const GURL& url,
+      const std::string& body,
+      net::HttpStatusCode* status_code) const;
+
+  scoped_ptr<base::DictionaryValue> ProcessSubmitDoc(
+      const GURL& url,
+      const net::HttpServerRequestInfo& info,
+      net::HttpStatusCode* status_code) const;
+
+  scoped_ptr<base::DictionaryValue> ProcessJobState(
+      const GURL& url,
+      net::HttpStatusCode* status_code) const;
+
   scoped_ptr<base::DictionaryValue> ProcessRegister(
       const GURL& url,
-      net::HttpStatusCode* status_code);
+      net::HttpStatusCode* status_code) const;
 
-  // Proccesses current status and depending on it replaces (or not)
+  // Processes current status and depending on it replaces (or not)
   // |current_response| with error or empty response.
   void ProcessRegistrationStatus(
       RegistrationErrorStatus status,
diff --git a/cloud_print/service/service_state.cc b/cloud_print/service/service_state.cc
index f2badde..69c1790 100644
--- a/cloud_print/service/service_state.cc
+++ b/cloud_print/service/service_state.cc
@@ -201,7 +201,6 @@
   std::vector<std::string> lines;
   Tokenize(fetcher_delegate.data(), "\r\n", &lines);
   for (size_t i = 0; i < lines.size(); ++i) {
-    std::vector<std::string> tokens;
     if (StartsWithASCII(lines[i], kAuthStart, false))
       return lines[i].substr(arraysize(kAuthStart) - 1);
   }
diff --git a/components/OWNERS b/components/OWNERS
index 7884fe2..ff02f9e 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -8,8 +8,11 @@
 per-file breakpad.gypi=rsesek@chromium.org
 per-file breakpad.gypi=thestig@chromium.org
 
-per-file tracing*=jbauman@chromium.org
-per-file tracing*=nduca@chromium.org
+per-file json_schema.gypi=asargent@chromium.org
+per-file json_schema.gypi=calamity@chromium.org
+per-file json_schema.gypi=kalman@chromium.org
+per-file json_schema.gypi=koz@chromium.org
+per-file json_schema.gypi=mpcomplete@chromium.org
 
 per-file nacl*=bradchen@chromium.org
 per-file nacl*=bradnelson@chromium.org
@@ -21,9 +24,19 @@
 per-file navigation_interception.gypi=joth@chromium.org
 per-file navigation_interception.gypi=mkosiba@chromium.org
 
+per-file policy.gypi=mnissler@chromium.org
+per-file policy.gypi=pastarmovj@chromium.org
+per-file policy.gypi=joaodasilva@chromium.org
+per-file policy.gypi=bartfab@chromium.org
+per-file policy.gypi=atwilson@chromium.org
+per-file policy.gypi=pneubeck@chromium.org
+
 per-file sessions.gypi=marja@chromium.org
 per-file sessions.gypi=sky@chromium.org
 
+per-file tracing*=jbauman@chromium.org
+per-file tracing*=nduca@chromium.org
+
 per-file user_prefs.gypi=battre@chromium.org
 per-file user_prefs.gypi=bauerb@chromium.org
 per-file user_prefs.gypi=mnissler@chromium.org
diff --git a/components/autofill/content/browser/wallet/wallet_client.cc b/components/autofill/content/browser/wallet/wallet_client.cc
index bb5c525..6a02596 100644
--- a/components/autofill/content/browser/wallet/wallet_client.cc
+++ b/components/autofill/content/browser/wallet/wallet_client.cc
@@ -258,6 +258,7 @@
 const char kInstrumentType[] = "instrument.type";
 const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
 const char kMerchantDomainKey[] = "merchant_domain";
+const char kNewWalletUser[] = "new_wallet_user";
 const char kPhoneNumberRequired[] = "phone_number_required";
 const char kReasonKey[] = "reason";
 const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
@@ -281,12 +282,14 @@
     const std::string& address_id,
     const GURL& source_url,
     const std::string& google_transaction_id,
-    const std::vector<RiskCapability> risk_capabilities)
+    const std::vector<RiskCapability> risk_capabilities,
+    bool new_wallet_user)
     : instrument_id(instrument_id),
       address_id(address_id),
       source_url(source_url),
       google_transaction_id(google_transaction_id),
-      risk_capabilities(risk_capabilities) {}
+      risk_capabilities(risk_capabilities),
+      new_wallet_user(new_wallet_user) {}
 
 WalletClient::FullWalletRequest::~FullWalletRequest() {}
 
@@ -368,6 +371,7 @@
   request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
   request_dict.SetBoolean(kUseMinimalAddresses, false);
   request_dict.SetBoolean(kPhoneNumberRequired, true);
+  request_dict.SetBoolean(kNewWalletUser, full_wallet_request.new_wallet_user);
 
   request_dict.SetString(kSelectedInstrumentIdKey,
                          full_wallet_request.instrument_id);
diff --git a/components/autofill/content/browser/wallet/wallet_client.h b/components/autofill/content/browser/wallet/wallet_client.h
index d4f9607..8ce6a3a 100644
--- a/components/autofill/content/browser/wallet/wallet_client.h
+++ b/components/autofill/content/browser/wallet/wallet_client.h
@@ -110,7 +110,8 @@
                       const std::string& address_id,
                       const GURL& source_url,
                       const std::string& google_transaction_id,
-                      const std::vector<RiskCapability> risk_capabilities);
+                      const std::vector<RiskCapability> risk_capabilities,
+                      bool new_wallet_user);
     ~FullWalletRequest();
 
     // The ID of the backing instrument. Should have been selected by the user
@@ -130,6 +131,9 @@
     // The Risk challenges supported by the user of WalletClient
     std::vector<RiskCapability> risk_capabilities;
 
+    // True if the user does not have Wallet profile.
+    bool new_wallet_user;
+
    private:
     DISALLOW_ASSIGN(FullWalletRequest);
   };
diff --git a/components/autofill/content/browser/wallet/wallet_client_unittest.cc b/components/autofill/content/browser/wallet/wallet_client_unittest.cc
index 031e5cd..5e230c9 100644
--- a/components/autofill/content/browser/wallet/wallet_client_unittest.cc
+++ b/components/autofill/content/browser/wallet/wallet_client_unittest.cc
@@ -319,6 +319,23 @@
         "\"feature\":\"REQUEST_AUTOCOMPLETE\","
         "\"google_transaction_id\":\"google_transaction_id\","
         "\"merchant_domain\":\"https://example.com/\","
+        "\"new_wallet_user\":false,"
+        "\"phone_number_required\":true,"
+        "\"risk_params\":\"risky business\","
+        "\"selected_address_id\":\"shipping_address_id\","
+        "\"selected_instrument_id\":\"instrument_id\","
+        "\"supported_risk_challenge\":"
+        "["
+        "],"
+        "\"use_minimal_addresses\":false"
+    "}";
+
+const char kGetFullWalletValidRequestNewUser[] =
+    "{"
+        "\"feature\":\"REQUEST_AUTOCOMPLETE\","
+        "\"google_transaction_id\":\"google_transaction_id\","
+        "\"merchant_domain\":\"https://example.com/\","
+        "\"new_wallet_user\":true,"
         "\"phone_number_required\":true,"
         "\"risk_params\":\"risky business\","
         "\"selected_address_id\":\"shipping_address_id\","
@@ -334,6 +351,7 @@
         "\"feature\":\"REQUEST_AUTOCOMPLETE\","
         "\"google_transaction_id\":\"google_transaction_id\","
         "\"merchant_domain\":\"https://example.com/\","
+        "\"new_wallet_user\":false,"
         "\"phone_number_required\":true,"
         "\"risk_params\":\"risky business\","
         "\"selected_address_id\":\"shipping_address_id\","
@@ -1037,7 +1055,8 @@
       "shipping_address_id",
       GURL(kMerchantUrl),
       "google_transaction_id",
-      std::vector<WalletClient::RiskCapability>());
+      std::vector<WalletClient::RiskCapability>(),
+      false);
   wallet_client_->GetFullWallet(full_wallet_request);
 
   VerifyAndFinishFormEncodedRequest(net::HTTP_OK,
@@ -1047,6 +1066,26 @@
   EXPECT_EQ(1U, delegate_.full_wallets_received());
 }
 
+TEST_F(WalletClientTest, GetFullWalletSuccessNewuser) {
+  delegate_.ExpectLogWalletApiCallDuration(AutofillMetrics::GET_FULL_WALLET, 1);
+  delegate_.ExpectBaselineMetrics();
+
+  WalletClient::FullWalletRequest full_wallet_request(
+      "instrument_id",
+      "shipping_address_id",
+      GURL(kMerchantUrl),
+      "google_transaction_id",
+      std::vector<WalletClient::RiskCapability>(),
+      true);
+  wallet_client_->GetFullWallet(full_wallet_request);
+
+  VerifyAndFinishFormEncodedRequest(net::HTTP_OK,
+                                    kGetFullWalletValidRequestNewUser,
+                                    kGetFullWalletValidResponse,
+                                    3U);
+  EXPECT_EQ(1U, delegate_.full_wallets_received());
+}
+
 TEST_F(WalletClientTest, GetFullWalletWithRiskCapabilitesSuccess) {
   delegate_.ExpectLogWalletApiCallDuration(AutofillMetrics::GET_FULL_WALLET, 1);
   delegate_.ExpectBaselineMetrics();
@@ -1058,7 +1097,8 @@
       "shipping_address_id",
       GURL(kMerchantUrl),
       "google_transaction_id",
-      risk_capabilities);
+      risk_capabilities,
+      false);
   wallet_client_->GetFullWallet(full_wallet_request);
 
   VerifyAndFinishFormEncodedRequest(
@@ -1082,7 +1122,8 @@
       "shipping_address_id",
       GURL(kMerchantUrl),
       "google_transaction_id",
-      std::vector<WalletClient::RiskCapability>());
+      std::vector<WalletClient::RiskCapability>(),
+      false);
   wallet_client_->GetFullWallet(full_wallet_request);
 
   VerifyAndFinishFormEncodedRequest(net::HTTP_OK,
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index e8509c7..ca4c46b 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -292,6 +292,10 @@
   MaybeShowAutocheckoutBubble();
 }
 
+void AutofillAgent::OrientationChangeEvent(int orientation) {
+  HideAutofillUI();
+}
+
 void AutofillAgent::MaybeShowAutocheckoutBubble() {
   if (element_.isNull() || !element_.focused())
     return;
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 9236246..c85f8ce 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -73,6 +73,7 @@
   virtual void ZoomLevelChanged() OVERRIDE;
   virtual void DidChangeScrollOffset(WebKit::WebFrame* frame) OVERRIDE;
   virtual void FocusedNodeChanged(const WebKit::WebNode& node) OVERRIDE;
+  virtual void OrientationChangeEvent(int orientation) OVERRIDE;
 
   // PageClickListener:
   virtual void InputElementClicked(const WebKit::WebInputElement& element,
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 55f3a03..907342b 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -599,6 +599,27 @@
   return "UNKNOWN";
 }
 
+// Recursively checks whether |node| or any of its children have a non-empty
+// bounding box. The recursion depth is bounded by |depth|.
+bool IsWebNodeVisibleImpl(const WebKit::WebNode& node, const int depth) {
+  if (depth < 0)
+    return false;
+  if (node.hasNonEmptyBoundingBox())
+    return true;
+
+  // The childNodes method is not a const method. Therefore it cannot be called
+  // on a const reference. Therefore we need a const cast.
+  const WebKit::WebNodeList& children =
+      const_cast<WebKit::WebNode&>(node).childNodes();
+  size_t length = children.length();
+  for (size_t i = 0; i < length; ++i) {
+    const WebKit::WebNode& item = children.item(i);
+    if (IsWebNodeVisibleImpl(item, depth - 1))
+      return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 const size_t kMaxParseableFields = 100;
@@ -634,6 +655,14 @@
   return identifier;
 }
 
+bool IsWebNodeVisible(const WebKit::WebNode& node) {
+  // In the bug http://crbug.com/237216 the form's bounding box is empty
+  // however the form has non empty children. Thus we need to look at the
+  // form's children.
+  int kNodeSearchDepth = 2;
+  return IsWebNodeVisibleImpl(node, kNodeSearchDepth);
+}
+
 bool ClickElement(const WebDocument& document,
                   const WebElementDescriptor& element_descriptor) {
   WebString web_descriptor = WebString::fromUTF8(element_descriptor.descriptor);
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index 5a12418..3f2bac9 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -14,6 +14,7 @@
 class WebFormElement;
 class WebFormControlElement;
 class WebInputElement;
+class WebNode;
 }
 
 namespace autofill {
@@ -61,6 +62,10 @@
 // autofilled. {Text, Radiobutton, Checkbox}.
 bool IsAutofillableInputElement(const WebKit::WebInputElement* element);
 
+// Recursively checks whether |node| or any of its children have a non-empty
+// bounding box.
+bool IsWebNodeVisible(const WebKit::WebNode& node);
+
 // Returns the form's |name| attribute if non-empty; otherwise the form's |id|
 // attribute.
 const base::string16 GetFormIdentifier(const WebKit::WebFormElement& form);
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index b6294ab..4782b11 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -24,6 +24,7 @@
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
+#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 
@@ -348,11 +349,16 @@
   return ShowSuggestionPopup(iter->second.fill_data, element);
 }
 
+bool PasswordAutofillAgent::OriginCanAccessPasswordManager(
+    const WebKit::WebSecurityOrigin& origin) {
+  return origin.canAccessPasswordManager();
+}
+
 void PasswordAutofillAgent::SendPasswordForms(WebKit::WebFrame* frame,
-                                                bool only_visible) {
+                                              bool only_visible) {
   // Make sure that this security origin is allowed to use password manager.
   WebKit::WebSecurityOrigin origin = frame->document().securityOrigin();
-  if (!origin.canAccessPasswordManager())
+  if (!OriginCanAccessPasswordManager(origin))
     return;
 
   WebKit::WebVector<WebKit::WebFormElement> forms;
@@ -364,7 +370,7 @@
 
     // If requested, ignore non-rendered forms, e.g. those styled with
     // display:none.
-    if (only_visible && !form.hasNonEmptyBoundingBox())
+    if (only_visible && !IsWebNodeVisible(form))
       continue;
 
     scoped_ptr<content::PasswordForm> password_form(
@@ -381,8 +387,8 @@
   }
 
   if (only_visible) {
-    Send(new AutofillHostMsg_PasswordFormsRendered(
-        routing_id(), password_forms));
+    Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(),
+                                                   password_forms));
   } else {
     Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms));
   }
@@ -428,6 +434,65 @@
   FrameClosing(frame);
 }
 
+void PasswordAutofillAgent::WillSendSubmitEvent(
+    WebKit::WebFrame* frame,
+    const WebKit::WebFormElement& form) {
+  // Some login forms have onSubmit handlers that put a hash of the password
+  // into a hidden field and then clear the password (http://crbug.com/28910).
+  // This method gets called before any of those handlers run, so save away
+  // a copy of the password in case it gets lost.
+  provisionally_saved_forms_[frame].reset(
+      content::CreatePasswordForm(form).release());
+}
+
+void PasswordAutofillAgent::WillSubmitForm(WebKit::WebFrame* frame,
+                                           const WebKit::WebFormElement& form) {
+  scoped_ptr<content::PasswordForm> submitted_form =
+      content::CreatePasswordForm(form);
+
+  // If there is a provisionally saved password, copy over the previous
+  // password value so we get the user's typed password, not the value that
+  // may have been transformed for submit.
+  // TODO(gcasto): Do we need to have this action equality check? Is it trying
+  // to prevent accidentally copying over passwords from a different form?
+  if (submitted_form) {
+    if (provisionally_saved_forms_[frame].get() &&
+        submitted_form->action == provisionally_saved_forms_[frame]->action) {
+      submitted_form->password_value =
+          provisionally_saved_forms_[frame]->password_value;
+    }
+
+    // Some observers depend on sending this information now instead of when
+    // the frame starts loading. If there are redirects that cause a new
+    // RenderView to be instantiated (such as redirects to the WebStore)
+    // we will never get to finish the load.
+    Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(),
+                                                   *submitted_form));
+    // Remove reference since we have already submitted this form.
+    provisionally_saved_forms_.erase(frame);
+  }
+}
+
+void PasswordAutofillAgent::DidStartProvisionalLoad(WebKit::WebFrame* frame) {
+  if (!frame->parent()) {
+    // If the navigation is not triggered by a user gesture, e.g. by some ajax
+    // callback, then inherit the submitted password form from the previous
+    // state. This fixes the no password save issue for ajax login, tracked in
+    // [http://crbug/43219]. Note that there are still some sites that this
+    // fails for because they use some element other than a submit button to
+    // trigger submission (which means WillSendSubmitEvent will not be called).
+    if (!WebKit::WebUserGestureIndicator::isProcessingUserGesture() &&
+        provisionally_saved_forms_[frame].get()) {
+      Send(new AutofillHostMsg_PasswordFormSubmitted(
+          routing_id(),
+          *provisionally_saved_forms_[frame]));
+      provisionally_saved_forms_.erase(frame);
+    }
+    // Clear the whole map during main frame navigation.
+    provisionally_saved_forms_.clear();
+  }
+}
+
 void PasswordAutofillAgent::OnFillPasswordForm(
     const PasswordFormFillData& form_data) {
   if (usernames_usage_ == NOTHING_TO_AUTOFILL) {
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 30fef62..5c64223 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <vector>
 
+#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "components/autofill/core/common/password_form_fill_data.h"
 #include "content/public/renderer/render_view_observer.h"
@@ -16,6 +17,7 @@
 namespace WebKit {
 class WebInputElement;
 class WebKeyboardEvent;
+class WebSecurityOrigin;
 class WebView;
 }
 
@@ -48,6 +50,10 @@
   // Returns true if any suggestions were shown, false otherwise.
   bool ShowSuggestions(const WebKit::WebInputElement& element);
 
+ protected:
+  virtual bool OriginCanAccessPasswordManager(
+      const WebKit::WebSecurityOrigin& origin);
+
  private:
   friend class PasswordAutofillAgentTest;
 
@@ -67,14 +73,21 @@
     PasswordInfo() : backspace_pressed_last(false) {}
   };
   typedef std::map<WebKit::WebElement, PasswordInfo> LoginToPasswordInfoMap;
+  typedef std::map<WebKit::WebFrame*,
+                   linked_ptr<content::PasswordForm> > FrameToPasswordFormMap;
 
   // RenderViewObserver:
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+  virtual void DidStartProvisionalLoad(WebKit::WebFrame* frame) OVERRIDE;
   virtual void DidStartLoading() OVERRIDE;
   virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame) OVERRIDE;
   virtual void DidFinishLoad(WebKit::WebFrame* frame) OVERRIDE;
   virtual void FrameDetached(WebKit::WebFrame* frame) OVERRIDE;
   virtual void FrameWillClose(WebKit::WebFrame* frame) OVERRIDE;
+  virtual void WillSendSubmitEvent(WebKit::WebFrame* frame,
+                                   const WebKit::WebFormElement& form) OVERRIDE;
+  virtual void WillSubmitForm(WebKit::WebFrame* frame,
+                              const WebKit::WebFormElement& form) OVERRIDE;
 
   // RenderView IPC handlers:
   void OnFillPasswordForm(const PasswordFormFillData& form_data);
@@ -123,6 +136,10 @@
   // Pointer to the WebView. Used to access page scale factor.
   WebKit::WebView* web_view_;
 
+  // Set if the user might be submitting a password form on the current page,
+  // but the submit may still fail (i.e. doesn't pass JavaScript validation).
+  FrameToPasswordFormMap provisionally_saved_forms_;
+
   base::WeakPtrFactory<PasswordAutofillAgent> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent);
diff --git a/components/autofill/content/renderer/test_password_autofill_agent.cc b/components/autofill/content/renderer/test_password_autofill_agent.cc
new file mode 100644
index 0000000..10252d4
--- /dev/null
+++ b/components/autofill/content/renderer/test_password_autofill_agent.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 "components/autofill/content/renderer/test_password_autofill_agent.h"
+
+namespace autofill {
+
+TestPasswordAutofillAgent::TestPasswordAutofillAgent(
+    content::RenderView* render_view)
+    : PasswordAutofillAgent(render_view) {}
+
+TestPasswordAutofillAgent::~TestPasswordAutofillAgent() {}
+
+bool TestPasswordAutofillAgent::OriginCanAccessPasswordManager(
+    const WebKit::WebSecurityOrigin& origin) {
+  return true;
+}
+
+}  // namespace autofill
diff --git a/components/autofill/content/renderer/test_password_autofill_agent.h b/components/autofill/content/renderer/test_password_autofill_agent.h
new file mode 100644
index 0000000..1045ae0
--- /dev/null
+++ b/components/autofill/content/renderer/test_password_autofill_agent.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 COMPONENTS_AUTOFILL_CONTENT_RENDERER_TEST_PASSWORD_AUTOFILL_AGENT_H_
+#define COMPONENTS_AUTOFILL_CONTENT_RENDERER_TEST_PASSWORD_AUTOFILL_AGENT_H_
+
+#include "components/autofill/content/renderer/password_autofill_agent.h"
+
+namespace autofill {
+
+class TestPasswordAutofillAgent : public PasswordAutofillAgent {
+ public:
+  explicit TestPasswordAutofillAgent(content::RenderView* render_view);
+  virtual ~TestPasswordAutofillAgent();
+
+ private:
+  // Always returns true. This allows browser tests with "data: " URL scheme to
+  // work with the password manager.
+  // PasswordAutofillAgent:
+  virtual bool OriginCanAccessPasswordManager(
+      const WebKit::WebSecurityOrigin& origin) OVERRIDE;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CONTENT_RENDERER_TEST_PASSWORD_AUTOFILL_AGENT_H_
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 7c08e5f..0a2b582 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -99,7 +99,9 @@
   }
 
   void MakeProfileIncognito() {
-    profile_->set_incognito(true);
+    // Switch to an incognito profile.
+    profile_->ForceIncognito(true);
+    DCHECK(profile_->IsOffTheRecord());
   }
 
   base::MessageLoopForUI message_loop_;
diff --git a/components/autofill/core/common/autofill_messages.h b/components/autofill/core/common/autofill_messages.h
index a432887..b17ae64 100644
--- a/components/autofill/core/common/autofill_messages.h
+++ b/components/autofill/core/common/autofill_messages.h
@@ -38,7 +38,8 @@
   IPC_STRUCT_TRAITS_MEMBER(retrieval_method)
 IPC_STRUCT_TRAITS_END()
 
-IPC_ENUM_TRAITS(autofill::WebElementDescriptor::RetrievalMethod)
+IPC_ENUM_TRAITS_MAX_VALUE(autofill::WebElementDescriptor::RetrievalMethod,
+                          autofill::WebElementDescriptor::NONE)
 
 IPC_STRUCT_TRAITS_BEGIN(autofill::FormFieldData)
   IPC_STRUCT_TRAITS_MEMBER(label)
@@ -99,7 +100,9 @@
   IPC_STRUCT_TRAITS_MEMBER(realm)
 IPC_STRUCT_TRAITS_END()
 
-IPC_ENUM_TRAITS(WebKit::WebFormElement::AutocompleteResult)
+IPC_ENUM_TRAITS_MAX_VALUE(
+    WebKit::WebFormElement::AutocompleteResult,
+    WebKit::WebFormElement::AutocompleteResultErrorInvalid)
 
 // Autofill messages sent from the browser to the renderer.
 
@@ -209,6 +212,10 @@
 IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormsRendered,
                     std::vector<content::PasswordForm> /* forms */)
 
+// Notification that this password form was submitted by the user.
+IPC_MESSAGE_ROUTED1(AutofillHostMsg_PasswordFormSubmitted,
+                    content::PasswordForm /* form */)
+
 // Notification that a form has been submitted.  The user hit the button.
 IPC_MESSAGE_ROUTED2(AutofillHostMsg_FormSubmitted,
                     autofill::FormData /* form */,
diff --git a/components/browser_context_keyed_service/browser_context_dependency_manager.cc b/components/browser_context_keyed_service/browser_context_dependency_manager.cc
index 1031f4e..6613423 100644
--- a/components/browser_context_keyed_service/browser_context_dependency_manager.cc
+++ b/components/browser_context_keyed_service/browser_context_dependency_manager.cc
@@ -40,9 +40,22 @@
 }
 
 void BrowserContextDependencyManager::CreateBrowserContextServices(
-    content::BrowserContext* context, bool is_testing_context) {
+    content::BrowserContext* context) {
+  DoCreateBrowserContextServices(context, false, false);
+}
+
+void BrowserContextDependencyManager::CreateBrowserContextServicesForTest(
+    content::BrowserContext* context,
+    bool force_register_prefs) {
+  DoCreateBrowserContextServices(context, true, force_register_prefs);
+}
+
+void BrowserContextDependencyManager::DoCreateBrowserContextServices(
+    content::BrowserContext* context,
+    bool is_testing_context,
+    bool force_register_prefs) {
   TRACE_EVENT0("browser",
-    "BrowserContextDependencyManager::CreateBrowserContextServices")
+    "BrowserContextDependencyManager::DoCreateBrowserContextServices")
 #ifndef NDEBUG
   // Unmark |context| as dead. This exists because of unit tests, which will
   // often have similar stack structures. 0xWhatever might be created, go out
@@ -64,9 +77,12 @@
     BrowserContextKeyedBaseFactory* factory =
         static_cast<BrowserContextKeyedBaseFactory*>(construction_order[i]);
 
-    if (!context->IsOffTheRecord()) {
+    if (!context->IsOffTheRecord() || force_register_prefs) {
       // We only register preferences on normal contexts because the incognito
-      // context shares the pref service with the normal one.
+      // context shares the pref service with the normal one. Always register
+      // for standalone testing contexts (testing contexts that don't have an
+      // "original" profile set) as otherwise the preferences won't be
+      // registered.
       factory->RegisterUserPrefsOnBrowserContext(context);
     }
 
diff --git a/components/browser_context_keyed_service/browser_context_dependency_manager.h b/components/browser_context_keyed_service/browser_context_dependency_manager.h
index 3e96eff..5482aaa 100644
--- a/components/browser_context_keyed_service/browser_context_dependency_manager.h
+++ b/components/browser_context_keyed_service/browser_context_dependency_manager.h
@@ -34,12 +34,22 @@
                BrowserContextKeyedBaseFactory* dependee);
 
   // Called by each BrowserContext to alert us of its creation. Several services
-  // want to be started when a context is created. Testing configuration is also
-  // done at this time. (If you want your BrowserContextKeyedService to be
-  // started with the BrowserContext, override BrowserContextKeyedBaseFactory::
-  // ServiceIsCreatedWithBrowserContext() to return true.)
-  void CreateBrowserContextServices(content::BrowserContext* context,
-                                    bool is_testing_context);
+  // want to be started when a context is created. If you want your
+  // BrowserContextKeyedService to be started with the BrowserContext, override
+  // BrowserContextKeyedBaseFactory::ServiceIsCreatedWithBrowserContext() to
+  // return true. This method also registers any service-related preferences
+  // for non-incognito profiles.
+  void CreateBrowserContextServices(content::BrowserContext* context);
+
+  // Similar to CreateBrowserContextServices(), except this is used for creating
+  // test BrowserContexts - these contexts will not create services for any
+  // BrowserContextKeyedBaseFactories that return true from
+  // ServiceIsNULLWhileTesting(). Callers can pass |force_register_prefs| as
+  // true to have preferences registered even for incognito profiles - this
+  // allows tests to specify a standalone incognito profile without an
+  // associated normal profile.
+  void CreateBrowserContextServicesForTest(content::BrowserContext* context,
+                                           bool force_register_prefs);
 
   // Called by each BrowserContext to alert us that we should destroy services
   // associated with it.
@@ -58,6 +68,11 @@
   friend class BrowserContextDependencyManagerUnittests;
   friend struct DefaultSingletonTraits<BrowserContextDependencyManager>;
 
+  // Helper function used by CreateBrowserContextServices[ForTest].
+  void DoCreateBrowserContextServices(content::BrowserContext* context,
+                                      bool is_testing_context,
+                                      bool force_register_prefs);
+
   BrowserContextDependencyManager();
   virtual ~BrowserContextDependencyManager();
 
diff --git a/components/browser_context_keyed_service/browser_context_keyed_base_factory.cc b/components/browser_context_keyed_service/browser_context_keyed_base_factory.cc
index e6caa69..cc3f487 100644
--- a/components/browser_context_keyed_service/browser_context_keyed_base_factory.cc
+++ b/components/browser_context_keyed_service/browser_context_keyed_base_factory.cc
@@ -68,7 +68,6 @@
   // to enforce a uniquenes check here because some tests create one context and
   // multiple services of the same type attached to that context (serially, not
   // parallel) and we don't want to register multiple times on the same context.
-  DCHECK(!context->IsOffTheRecord());
 
   std::set<content::BrowserContext*>::iterator it =
       registered_preferences_.find(context);
diff --git a/components/component_strings.grd b/components/component_strings.grd
index ba3840e..b50c4da 100644
--- a/components/component_strings.grd
+++ b/components/component_strings.grd
@@ -77,11 +77,11 @@
          be 'nb'. -->
     <output filename="component_strings_nb.pak" type="data_package" lang="no" />
     <output filename="component_strings_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="component_strings_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="component_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="component_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
diff --git a/components/components.gyp b/components/components.gyp
index 61c496c..602650c 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -15,7 +15,9 @@
     'breakpad.gypi',
     'browser_context_keyed_service.gypi',
     'components_tests.gypi',
+    'json_schema.gypi',
     'navigation_interception.gypi',
+    'policy.gypi',
     'sessions.gypi',
     'user_prefs.gypi',
     'visitedlink.gypi',
diff --git a/components/components_tests.gypi b/components/components_tests.gypi
index b8e5600..61346d0 100644
--- a/components/components_tests.gypi
+++ b/components/components_tests.gypi
@@ -13,6 +13,9 @@
             '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',
+            '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',
             'sessions/serialized_navigation_entry_unittest.cc',
             'test/run_all_unittests.cc',
@@ -38,11 +41,17 @@
             # Dependencies of encryptor
             'encryptor',
 
+            # Dependencies of json_schema
+            'json_schema',
+
             # Dependencies of intercept_navigation_resource_throttle_unittest.cc
             '../content/content.gyp:test_support_content',
             '../skia/skia.gyp:skia',
             'navigation_interception',
 
+            # Dependencies of policy
+            'policy_component',
+
             # Dependencies of sessions
             '../third_party/protobuf/protobuf.gyp:protobuf_lite',
             'sessions',
@@ -87,6 +96,11 @@
                 'ldflags': ['-rdynamic'],
             },
             }],
+            ['configuration_policy==1', {
+              'sources': [
+                'policy/core/common/policy_schema_unittest.cc',
+              ],
+            }],
           ],
           # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
           'msvs_disabled_warnings': [4267, ],
diff --git a/components/components_unittests.isolate b/components/components_unittests.isolate
index 0c18d8f..f60a380 100644
--- a/components/components_unittests.isolate
+++ b/components/components_unittests.isolate
@@ -8,6 +8,9 @@
         'isolate_dependency_tracked': [
           '<(PRODUCT_DIR)/content_resources.pak',
         ],
+        'isolate_dependency_untracked': [
+          'test/data/',
+        ],
       },
     }],
   ],
diff --git a/components/json_schema.gypi b/components/json_schema.gypi
new file mode 100644
index 0000000..510f97d
--- /dev/null
+++ b/components/json_schema.gypi
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'json_schema',
+      'type': 'static_library',
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../ui/ui.gyp:ui',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'json_schema/json_schema_constants.cc',
+        'json_schema/json_schema_constants.h',
+        'json_schema/json_schema_validator.cc',
+        'json_schema/json_schema_validator.h',
+      ],
+    },
+  ],
+}
diff --git a/components/json_schema/DEPS b/components/json_schema/DEPS
new file mode 100644
index 0000000..e7cf2c6
--- /dev/null
+++ b/components/json_schema/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+ui/base",
+]
diff --git a/chrome/common/json_schema/OWNERS b/components/json_schema/OWNERS
similarity index 100%
rename from chrome/common/json_schema/OWNERS
rename to components/json_schema/OWNERS
diff --git a/components/json_schema/README b/components/json_schema/README
new file mode 100644
index 0000000..c7453db
--- /dev/null
+++ b/components/json_schema/README
@@ -0,0 +1,6 @@
+The //components/json_schema component provides:
+
+a) JSON schema constants, which can be used to inspect schema objects.
+
+b) The JSONSchemaValidator class, which can be used to parse and validate JSON
+schemas, and to validate JSON objects against the parsed schema.
diff --git a/components/json_schema/json_schema_constants.cc b/components/json_schema/json_schema_constants.cc
new file mode 100644
index 0000000..0152cfc
--- /dev/null
+++ b/components/json_schema/json_schema_constants.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 "components/json_schema/json_schema_constants.h"
+
+namespace json_schema_constants {
+
+const char kAdditionalProperties[] = "additionalProperties";
+const char kAny[] = "any";
+const char kArray[] = "array";
+const char kBoolean[] = "boolean";
+const char kChoices[] = "choices";
+const char kDescription[] = "description";
+const char kEnum[] = "enum";
+const char kId[] = "id";
+const char kInteger[] = "integer";
+const char kItems[] = "items";
+const char kMaximum[] = "maximum";
+const char kMaxItems[] = "maxItems";
+const char kMaxLength[] = "maxLength";
+const char kMinimum[] = "minimum";
+const char kMinItems[] = "minItems";
+const char kMinLength[] = "minLength";
+const char kNull[] = "null";
+const char kNumber[] = "number";
+const char kObject[] = "object";
+const char kOptional[] = "optional";
+const char kPattern[] = "pattern";
+const char kPatternProperties[] = "patternProperties";
+const char kProperties[] = "properties";
+const char kRef[] = "$ref";
+const char kSchema[] = "$schema";
+const char kString[] = "string";
+const char kTitle[] = "title";
+const char kType[] = "type";
+
+}  // namespace json_schema_constants
diff --git a/components/json_schema/json_schema_constants.h b/components/json_schema/json_schema_constants.h
new file mode 100644
index 0000000..5c64ebb
--- /dev/null
+++ b/components/json_schema/json_schema_constants.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 COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_CONSTANTS_H_
+#define COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_CONSTANTS_H_
+
+// These constants are shared by code that uses JSON schemas.
+namespace json_schema_constants {
+
+extern const char kAdditionalProperties[];
+extern const char kAny[];
+extern const char kArray[];
+extern const char kBoolean[];
+extern const char kChoices[];
+extern const char kDescription[];
+extern const char kEnum[];
+extern const char kId[];
+extern const char kInteger[];
+extern const char kItems[];
+extern const char kMaximum[];
+extern const char kMaxItems[];
+extern const char kMaxLength[];
+extern const char kMinimum[];
+extern const char kMinItems[];
+extern const char kMinLength[];
+extern const char kNull[];
+extern const char kNumber[];
+extern const char kObject[];
+extern const char kOptional[];
+extern const char kPattern[];
+extern const char kPatternProperties[];
+extern const char kProperties[];
+extern const char kRef[];
+extern const char kSchema[];
+extern const char kString[];
+extern const char kTitle[];
+extern const char kType[];
+
+}  // namespace json_schema_constants
+
+#endif  // COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_CONSTANTS_H_
diff --git a/components/json_schema/json_schema_validator.cc b/components/json_schema/json_schema_validator.cc
new file mode 100644
index 0000000..3816a76
--- /dev/null
+++ b/components/json_schema/json_schema_validator.cc
@@ -0,0 +1,727 @@
+// Copyright 2013 The Chromium Authors. 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/json_schema/json_schema_validator.h"
+
+#include <algorithm>
+#include <cfloat>
+#include <cmath>
+
+#include "base/json/json_reader.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "components/json_schema/json_schema_constants.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace schema = json_schema_constants;
+
+namespace {
+
+double GetNumberValue(const base::Value* value) {
+  double result = 0;
+  CHECK(value->GetAsDouble(&result))
+      << "Unexpected value type: " << value->GetType();
+  return result;
+}
+
+bool IsValidType(const std::string& type) {
+  static const char* kValidTypes[] = {
+    schema::kAny,
+    schema::kArray,
+    schema::kBoolean,
+    schema::kInteger,
+    schema::kNull,
+    schema::kNumber,
+    schema::kObject,
+    schema::kString,
+  };
+  const char** end = kValidTypes + arraysize(kValidTypes);
+  return std::find(kValidTypes, end, type) != end;
+}
+
+// Maps a schema attribute name to its expected type.
+struct ExpectedType {
+  const char* key;
+  base::Value::Type type;
+};
+
+// Helper for std::lower_bound.
+bool CompareToString(const ExpectedType& entry, const std::string& key) {
+  return entry.key < key;
+}
+
+bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) {
+  // This array must be sorted, so that std::lower_bound can perform a
+  // binary search.
+  static const ExpectedType kExpectedTypes[] = {
+    // Note: kRef == "$ref", kSchema == "$schema"
+    { schema::kRef,                     base::Value::TYPE_STRING      },
+    { schema::kSchema,                  base::Value::TYPE_STRING      },
+
+    { schema::kAdditionalProperties,    base::Value::TYPE_DICTIONARY  },
+    { schema::kChoices,                 base::Value::TYPE_LIST        },
+    { schema::kDescription,             base::Value::TYPE_STRING      },
+    { schema::kEnum,                    base::Value::TYPE_LIST        },
+    { schema::kId,                      base::Value::TYPE_STRING      },
+    { schema::kMaxItems,                base::Value::TYPE_INTEGER     },
+    { schema::kMaxLength,               base::Value::TYPE_INTEGER     },
+    { schema::kMaximum,                 base::Value::TYPE_DOUBLE      },
+    { schema::kMinItems,                base::Value::TYPE_INTEGER     },
+    { schema::kMinLength,               base::Value::TYPE_INTEGER     },
+    { schema::kMinimum,                 base::Value::TYPE_DOUBLE      },
+    { schema::kOptional,                base::Value::TYPE_BOOLEAN     },
+    { schema::kProperties,              base::Value::TYPE_DICTIONARY  },
+    { schema::kTitle,                   base::Value::TYPE_STRING      },
+  };
+
+  bool has_type = false;
+  const base::ListValue* list_value = NULL;
+  const base::DictionaryValue* dictionary_value = NULL;
+  std::string string_value;
+
+  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
+    // Validate the "type" attribute, which may be a string or a list.
+    if (it.key() == schema::kType) {
+      switch (it.value().GetType()) {
+        case base::Value::TYPE_STRING:
+          it.value().GetAsString(&string_value);
+          if (!IsValidType(string_value)) {
+            *error = "Invalid value for type attribute";
+            return false;
+          }
+          break;
+        case base::Value::TYPE_LIST:
+          it.value().GetAsList(&list_value);
+          for (size_t i = 0; i < list_value->GetSize(); ++i) {
+            if (!list_value->GetString(i, &string_value) ||
+                !IsValidType(string_value)) {
+              *error = "Invalid value for type attribute";
+              return false;
+            }
+          }
+          break;
+        default:
+          *error = "Invalid value for type attribute";
+          return false;
+      }
+      has_type = true;
+      continue;
+    }
+
+    // Validate the "items" attribute, which is a schema or a list of schemas.
+    if (it.key() == schema::kItems) {
+      if (it.value().GetAsDictionary(&dictionary_value)) {
+        if (!IsValidSchema(dictionary_value, error)) {
+          DCHECK(!error->empty());
+          return false;
+        }
+      } else if (it.value().GetAsList(&list_value)) {
+        for (size_t i = 0; i < list_value->GetSize(); ++i) {
+          if (!list_value->GetDictionary(i, &dictionary_value)) {
+            *error = base::StringPrintf(
+                "Invalid entry in items attribute at index %d",
+                static_cast<int>(i));
+            return false;
+          }
+          if (!IsValidSchema(dictionary_value, error)) {
+            DCHECK(!error->empty());
+            return false;
+          }
+        }
+      } else {
+        *error = "Invalid value for items attribute";
+        return false;
+      }
+      continue;
+    }
+
+    // All the other attributes have a single valid type.
+    const ExpectedType* end = kExpectedTypes + arraysize(kExpectedTypes);
+    const ExpectedType* entry = std::lower_bound(
+        kExpectedTypes, end, it.key(), CompareToString);
+    if (entry == end || entry->key != it.key()) {
+      *error = base::StringPrintf("Invalid attribute %s", it.key().c_str());
+      return false;
+    }
+    if (!it.value().IsType(entry->type)) {
+      *error = base::StringPrintf("Invalid value for %s attribute",
+                                  it.key().c_str());
+      return false;
+    }
+
+    // base::Value::TYPE_INTEGER attributes must be >= 0.
+    // This applies to "minItems", "maxItems", "minLength" and "maxLength".
+    if (it.value().IsType(base::Value::TYPE_INTEGER)) {
+      int integer_value;
+      it.value().GetAsInteger(&integer_value);
+      if (integer_value < 0) {
+        *error = base::StringPrintf("Value of %s must be >= 0, got %d",
+                                    it.key().c_str(), integer_value);
+        return false;
+      }
+    }
+
+    // Validate the "properties" attribute. Each entry maps a key to a schema.
+    if (it.key() == schema::kProperties) {
+      it.value().GetAsDictionary(&dictionary_value);
+      for (base::DictionaryValue::Iterator it(*dictionary_value);
+           !it.IsAtEnd(); it.Advance()) {
+        if (!it.value().GetAsDictionary(&dictionary_value)) {
+          *error = "Invalid value for properties attribute";
+          return false;
+        }
+        if (!IsValidSchema(dictionary_value, error)) {
+          DCHECK(!error->empty());
+          return false;
+        }
+      }
+    }
+
+    // Validate "additionalProperties" attribute, which is a schema.
+    if (it.key() == schema::kAdditionalProperties) {
+      it.value().GetAsDictionary(&dictionary_value);
+      if (!IsValidSchema(dictionary_value, error)) {
+        DCHECK(!error->empty());
+        return false;
+      }
+    }
+
+    // Validate the values contained in an "enum" attribute.
+    if (it.key() == schema::kEnum) {
+      it.value().GetAsList(&list_value);
+      for (size_t i = 0; i < list_value->GetSize(); ++i) {
+        const base::Value* value = NULL;
+        list_value->Get(i, &value);
+        switch (value->GetType()) {
+          case base::Value::TYPE_NULL:
+          case base::Value::TYPE_BOOLEAN:
+          case base::Value::TYPE_INTEGER:
+          case base::Value::TYPE_DOUBLE:
+          case base::Value::TYPE_STRING:
+            break;
+          default:
+            *error = "Invalid value in enum attribute";
+            return false;
+        }
+      }
+    }
+
+    // Validate the schemas contained in a "choices" attribute.
+    if (it.key() == schema::kChoices) {
+      it.value().GetAsList(&list_value);
+      for (size_t i = 0; i < list_value->GetSize(); ++i) {
+        if (!list_value->GetDictionary(i, &dictionary_value)) {
+          *error = "Invalid choices attribute";
+          return false;
+        }
+        if (!IsValidSchema(dictionary_value, error)) {
+          DCHECK(!error->empty());
+          return false;
+        }
+      }
+    }
+  }
+
+  if (!has_type) {
+    *error = "Schema must have a type attribute";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+
+JSONSchemaValidator::Error::Error() {
+}
+
+JSONSchemaValidator::Error::Error(const std::string& message)
+    : path(message) {
+}
+
+JSONSchemaValidator::Error::Error(const std::string& path,
+                                  const std::string& message)
+    : path(path), message(message) {
+}
+
+
+const char JSONSchemaValidator::kUnknownTypeReference[] =
+    "Unknown schema reference: *.";
+const char JSONSchemaValidator::kInvalidChoice[] =
+    "Value does not match any valid type choices.";
+const char JSONSchemaValidator::kInvalidEnum[] =
+    "Value does not match any valid enum choices.";
+const char JSONSchemaValidator::kObjectPropertyIsRequired[] =
+    "Property is required.";
+const char JSONSchemaValidator::kUnexpectedProperty[] =
+    "Unexpected property.";
+const char JSONSchemaValidator::kArrayMinItems[] =
+    "Array must have at least * items.";
+const char JSONSchemaValidator::kArrayMaxItems[] =
+    "Array must not have more than * items.";
+const char JSONSchemaValidator::kArrayItemRequired[] =
+    "Item is required.";
+const char JSONSchemaValidator::kStringMinLength[] =
+    "String must be at least * characters long.";
+const char JSONSchemaValidator::kStringMaxLength[] =
+    "String must not be more than * characters long.";
+const char JSONSchemaValidator::kStringPattern[] =
+    "String must match the pattern: *.";
+const char JSONSchemaValidator::kNumberMinimum[] =
+    "Value must not be less than *.";
+const char JSONSchemaValidator::kNumberMaximum[] =
+    "Value must not be greater than *.";
+const char JSONSchemaValidator::kInvalidType[] =
+    "Expected '*' but got '*'.";
+const char JSONSchemaValidator::kInvalidTypeIntegerNumber[] =
+    "Expected 'integer' but got 'number', consider using Math.round().";
+
+
+// static
+std::string JSONSchemaValidator::GetJSONSchemaType(const base::Value* value) {
+  switch (value->GetType()) {
+    case base::Value::TYPE_NULL:
+      return schema::kNull;
+    case base::Value::TYPE_BOOLEAN:
+      return schema::kBoolean;
+    case base::Value::TYPE_INTEGER:
+      return schema::kInteger;
+    case base::Value::TYPE_DOUBLE: {
+      double double_value = 0;
+      value->GetAsDouble(&double_value);
+      if (std::abs(double_value) <= std::pow(2.0, DBL_MANT_DIG) &&
+          double_value == floor(double_value)) {
+        return schema::kInteger;
+      } else {
+        return schema::kNumber;
+      }
+    }
+    case base::Value::TYPE_STRING:
+      return schema::kString;
+    case base::Value::TYPE_DICTIONARY:
+      return schema::kObject;
+    case base::Value::TYPE_LIST:
+      return schema::kArray;
+    default:
+      NOTREACHED() << "Unexpected value type: " << value->GetType();
+      return std::string();
+  }
+}
+
+// static
+std::string JSONSchemaValidator::FormatErrorMessage(const std::string& format,
+                                                    const std::string& s1) {
+  std::string ret_val = format;
+  ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
+  return ret_val;
+}
+
+// static
+std::string JSONSchemaValidator::FormatErrorMessage(const std::string& format,
+                                                    const std::string& s1,
+                                                    const std::string& s2) {
+  std::string ret_val = format;
+  ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
+  ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
+  return ret_val;
+}
+
+// static
+scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema(
+    const std::string& schema,
+    std::string* error) {
+  base::JSONParserOptions options = base::JSON_PARSE_RFC;
+  scoped_ptr<base::Value> json(
+      base::JSONReader::ReadAndReturnError(schema, options, NULL, error));
+  if (!json)
+    return scoped_ptr<base::DictionaryValue>();
+  base::DictionaryValue* dict = NULL;
+  if (!json->GetAsDictionary(&dict)) {
+    *error = "Schema must be a JSON object";
+    return scoped_ptr<base::DictionaryValue>();
+  }
+  if (!::IsValidSchema(dict, error))
+    return scoped_ptr<base::DictionaryValue>();
+  ignore_result(json.release());
+  return make_scoped_ptr(dict);
+}
+
+JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema)
+    : schema_root_(schema), default_allow_additional_properties_(false) {
+}
+
+JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema,
+                                         base::ListValue* types)
+    : schema_root_(schema), default_allow_additional_properties_(false) {
+  if (!types)
+    return;
+
+  for (size_t i = 0; i < types->GetSize(); ++i) {
+    base::DictionaryValue* type = NULL;
+    CHECK(types->GetDictionary(i, &type));
+
+    std::string id;
+    CHECK(type->GetString(schema::kId, &id));
+
+    CHECK(types_.find(id) == types_.end());
+    types_[id] = type;
+  }
+}
+
+JSONSchemaValidator::~JSONSchemaValidator() {}
+
+bool JSONSchemaValidator::Validate(const base::Value* instance) {
+  errors_.clear();
+  Validate(instance, schema_root_, std::string());
+  return errors_.empty();
+}
+
+void JSONSchemaValidator::Validate(const base::Value* instance,
+                                   const base::DictionaryValue* schema,
+                                   const std::string& path) {
+  // If this schema defines itself as reference type, save it in this.types.
+  std::string id;
+  if (schema->GetString(schema::kId, &id)) {
+    TypeMap::iterator iter = types_.find(id);
+    if (iter == types_.end())
+      types_[id] = schema;
+    else
+      DCHECK(iter->second == schema);
+  }
+
+  // If the schema has a $ref property, the instance must validate against
+  // that schema. It must be present in types_ to be referenced.
+  std::string ref;
+  if (schema->GetString(schema::kRef, &ref)) {
+    TypeMap::iterator type = types_.find(ref);
+    if (type == types_.end()) {
+      errors_.push_back(
+          Error(path, FormatErrorMessage(kUnknownTypeReference, ref)));
+    } else {
+      Validate(instance, type->second, path);
+    }
+    return;
+  }
+
+  // If the schema has a choices property, the instance must validate against at
+  // least one of the items in that array.
+  const base::ListValue* choices = NULL;
+  if (schema->GetList(schema::kChoices, &choices)) {
+    ValidateChoices(instance, choices, path);
+    return;
+  }
+
+  // If the schema has an enum property, the instance must be one of those
+  // values.
+  const base::ListValue* enumeration = NULL;
+  if (schema->GetList(schema::kEnum, &enumeration)) {
+    ValidateEnum(instance, enumeration, path);
+    return;
+  }
+
+  std::string type;
+  schema->GetString(schema::kType, &type);
+  CHECK(!type.empty());
+  if (type != schema::kAny) {
+    if (!ValidateType(instance, type, path))
+      return;
+
+    // These casts are safe because of checks in ValidateType().
+    if (type == schema::kObject) {
+      ValidateObject(static_cast<const base::DictionaryValue*>(instance),
+                     schema,
+                     path);
+    } else if (type == schema::kArray) {
+      ValidateArray(static_cast<const base::ListValue*>(instance),
+                    schema, path);
+    } else if (type == schema::kString) {
+      // Intentionally NOT downcasting to StringValue*. TYPE_STRING only implies
+      // GetAsString() can safely be carried out, not that it's a StringValue.
+      ValidateString(instance, schema, path);
+    } else if (type == schema::kNumber || type == schema::kInteger) {
+      ValidateNumber(instance, schema, path);
+    } else if (type != schema::kBoolean && type != schema::kNull) {
+      NOTREACHED() << "Unexpected type: " << type;
+    }
+  }
+}
+
+void JSONSchemaValidator::ValidateChoices(const base::Value* instance,
+                                          const base::ListValue* choices,
+                                          const std::string& path) {
+  size_t original_num_errors = errors_.size();
+
+  for (size_t i = 0; i < choices->GetSize(); ++i) {
+    const base::DictionaryValue* choice = NULL;
+    CHECK(choices->GetDictionary(i, &choice));
+
+    Validate(instance, choice, path);
+    if (errors_.size() == original_num_errors)
+      return;
+
+    // We discard the error from each choice. We only want to know if any of the
+    // validations succeeded.
+    errors_.resize(original_num_errors);
+  }
+
+  // Now add a generic error that no choices matched.
+  errors_.push_back(Error(path, kInvalidChoice));
+  return;
+}
+
+void JSONSchemaValidator::ValidateEnum(const base::Value* instance,
+                                       const base::ListValue* choices,
+                                       const std::string& path) {
+  for (size_t i = 0; i < choices->GetSize(); ++i) {
+    const base::Value* choice = NULL;
+    CHECK(choices->Get(i, &choice));
+    switch (choice->GetType()) {
+      case base::Value::TYPE_NULL:
+      case base::Value::TYPE_BOOLEAN:
+      case base::Value::TYPE_STRING:
+        if (instance->Equals(choice))
+          return;
+        break;
+
+      case base::Value::TYPE_INTEGER:
+      case base::Value::TYPE_DOUBLE:
+        if (instance->IsType(base::Value::TYPE_INTEGER) ||
+            instance->IsType(base::Value::TYPE_DOUBLE)) {
+          if (GetNumberValue(choice) == GetNumberValue(instance))
+            return;
+        }
+        break;
+
+      default:
+       NOTREACHED() << "Unexpected type in enum: " << choice->GetType();
+    }
+  }
+
+  errors_.push_back(Error(path, kInvalidEnum));
+}
+
+void JSONSchemaValidator::ValidateObject(const base::DictionaryValue* instance,
+                                         const base::DictionaryValue* schema,
+                                         const std::string& path) {
+  const base::DictionaryValue* properties = NULL;
+  schema->GetDictionary(schema::kProperties, &properties);
+  if (properties) {
+    for (base::DictionaryValue::Iterator it(*properties); !it.IsAtEnd();
+         it.Advance()) {
+      std::string prop_path = path.empty() ? it.key() : (path + "." + it.key());
+      const base::DictionaryValue* prop_schema = NULL;
+      CHECK(it.value().GetAsDictionary(&prop_schema));
+
+      const base::Value* prop_value = NULL;
+      if (instance->Get(it.key(), &prop_value)) {
+        Validate(prop_value, prop_schema, prop_path);
+      } else {
+        // Properties are required unless there is an optional field set to
+        // 'true'.
+        bool is_optional = false;
+        prop_schema->GetBoolean(schema::kOptional, &is_optional);
+        if (!is_optional) {
+          errors_.push_back(Error(prop_path, kObjectPropertyIsRequired));
+        }
+      }
+    }
+  }
+
+  const base::DictionaryValue* additional_properties_schema = NULL;
+  if (SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema))
+    return;
+
+  // Validate additional properties.
+  for (base::DictionaryValue::Iterator it(*instance); !it.IsAtEnd();
+       it.Advance()) {
+    if (properties && properties->HasKey(it.key()))
+      continue;
+
+    std::string prop_path = path.empty() ? it.key() : path + "." + it.key();
+    if (!additional_properties_schema) {
+      errors_.push_back(Error(prop_path, kUnexpectedProperty));
+    } else {
+      Validate(&it.value(), additional_properties_schema, prop_path);
+    }
+  }
+}
+
+void JSONSchemaValidator::ValidateArray(const base::ListValue* instance,
+                                        const base::DictionaryValue* schema,
+                                        const std::string& path) {
+  const base::DictionaryValue* single_type = NULL;
+  size_t instance_size = instance->GetSize();
+  if (schema->GetDictionary(schema::kItems, &single_type)) {
+    int min_items = 0;
+    if (schema->GetInteger(schema::kMinItems, &min_items)) {
+      CHECK(min_items >= 0);
+      if (instance_size < static_cast<size_t>(min_items)) {
+        errors_.push_back(Error(path, FormatErrorMessage(
+            kArrayMinItems, base::IntToString(min_items))));
+      }
+    }
+
+    int max_items = 0;
+    if (schema->GetInteger(schema::kMaxItems, &max_items)) {
+      CHECK(max_items >= 0);
+      if (instance_size > static_cast<size_t>(max_items)) {
+        errors_.push_back(Error(path, FormatErrorMessage(
+            kArrayMaxItems, base::IntToString(max_items))));
+      }
+    }
+
+    // If the items property is a single schema, each item in the array must
+    // validate against that schema.
+    for (size_t i = 0; i < instance_size; ++i) {
+      const base::Value* item = NULL;
+      CHECK(instance->Get(i, &item));
+      std::string i_str = base::Uint64ToString(i);
+      std::string item_path = path.empty() ? i_str : (path + "." + i_str);
+      Validate(item, single_type, item_path);
+    }
+
+    return;
+  }
+
+  // Otherwise, the list must be a tuple type, where each item in the list has a
+  // particular schema.
+  ValidateTuple(instance, schema, path);
+}
+
+void JSONSchemaValidator::ValidateTuple(const base::ListValue* instance,
+                                        const base::DictionaryValue* schema,
+                                        const std::string& path) {
+  const base::ListValue* tuple_type = NULL;
+  schema->GetList(schema::kItems, &tuple_type);
+  size_t tuple_size = tuple_type ? tuple_type->GetSize() : 0;
+  if (tuple_type) {
+    for (size_t i = 0; i < tuple_size; ++i) {
+      std::string i_str = base::Uint64ToString(i);
+      std::string item_path = path.empty() ? i_str : (path + "." + i_str);
+      const base::DictionaryValue* item_schema = NULL;
+      CHECK(tuple_type->GetDictionary(i, &item_schema));
+      const base::Value* item_value = NULL;
+      instance->Get(i, &item_value);
+      if (item_value && item_value->GetType() != base::Value::TYPE_NULL) {
+        Validate(item_value, item_schema, item_path);
+      } else {
+        bool is_optional = false;
+        item_schema->GetBoolean(schema::kOptional, &is_optional);
+        if (!is_optional) {
+          errors_.push_back(Error(item_path, kArrayItemRequired));
+          return;
+        }
+      }
+    }
+  }
+
+  const base::DictionaryValue* additional_properties_schema = NULL;
+  if (SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema))
+    return;
+
+  size_t instance_size = instance->GetSize();
+  if (additional_properties_schema) {
+    // Any additional properties must validate against the additionalProperties
+    // schema.
+    for (size_t i = tuple_size; i < instance_size; ++i) {
+      std::string i_str = base::Uint64ToString(i);
+      std::string item_path = path.empty() ? i_str : (path + "." + i_str);
+      const base::Value* item_value = NULL;
+      CHECK(instance->Get(i, &item_value));
+      Validate(item_value, additional_properties_schema, item_path);
+    }
+  } else if (instance_size > tuple_size) {
+    errors_.push_back(Error(path, FormatErrorMessage(
+        kArrayMaxItems, base::Uint64ToString(tuple_size))));
+  }
+}
+
+void JSONSchemaValidator::ValidateString(const base::Value* instance,
+                                         const base::DictionaryValue* schema,
+                                         const std::string& path) {
+  std::string value;
+  CHECK(instance->GetAsString(&value));
+
+  int min_length = 0;
+  if (schema->GetInteger(schema::kMinLength, &min_length)) {
+    CHECK(min_length >= 0);
+    if (value.size() < static_cast<size_t>(min_length)) {
+      errors_.push_back(Error(path, FormatErrorMessage(
+          kStringMinLength, base::IntToString(min_length))));
+    }
+  }
+
+  int max_length = 0;
+  if (schema->GetInteger(schema::kMaxLength, &max_length)) {
+    CHECK(max_length >= 0);
+    if (value.size() > static_cast<size_t>(max_length)) {
+      errors_.push_back(Error(path, FormatErrorMessage(
+          kStringMaxLength, base::IntToString(max_length))));
+    }
+  }
+
+  CHECK(!schema->HasKey(schema::kPattern)) << "Pattern is not supported.";
+}
+
+void JSONSchemaValidator::ValidateNumber(const base::Value* instance,
+                                         const base::DictionaryValue* schema,
+                                         const std::string& path) {
+  double value = GetNumberValue(instance);
+
+  // TODO(aa): It would be good to test that the double is not infinity or nan,
+  // but isnan and isinf aren't defined on Windows.
+
+  double minimum = 0;
+  if (schema->GetDouble(schema::kMinimum, &minimum)) {
+    if (value < minimum)
+      errors_.push_back(Error(path, FormatErrorMessage(
+          kNumberMinimum, base::DoubleToString(minimum))));
+  }
+
+  double maximum = 0;
+  if (schema->GetDouble(schema::kMaximum, &maximum)) {
+    if (value > maximum)
+      errors_.push_back(Error(path, FormatErrorMessage(
+          kNumberMaximum, base::DoubleToString(maximum))));
+  }
+}
+
+bool JSONSchemaValidator::ValidateType(const base::Value* instance,
+                                       const std::string& expected_type,
+                                       const std::string& path) {
+  std::string actual_type = GetJSONSchemaType(instance);
+  if (expected_type == actual_type ||
+      (expected_type == schema::kNumber && actual_type == schema::kInteger)) {
+    return true;
+  } else if (expected_type == schema::kInteger &&
+             actual_type == schema::kNumber) {
+    errors_.push_back(Error(path, kInvalidTypeIntegerNumber));
+    return false;
+  } else {
+    errors_.push_back(Error(path, FormatErrorMessage(
+        kInvalidType, expected_type, actual_type)));
+    return false;
+  }
+}
+
+bool JSONSchemaValidator::SchemaAllowsAnyAdditionalItems(
+    const base::DictionaryValue* schema,
+    const base::DictionaryValue** additional_properties_schema) {
+  // If the validator allows additional properties globally, and this schema
+  // doesn't override, then we can exit early.
+  schema->GetDictionary(schema::kAdditionalProperties,
+                        additional_properties_schema);
+
+  if (*additional_properties_schema) {
+    std::string additional_properties_type(schema::kAny);
+    CHECK((*additional_properties_schema)->GetString(
+        schema::kType, &additional_properties_type));
+    return additional_properties_type == schema::kAny;
+  } else {
+    return default_allow_additional_properties_;
+  }
+}
diff --git a/components/json_schema/json_schema_validator.h b/components/json_schema/json_schema_validator.h
new file mode 100644
index 0000000..4584a9d
--- /dev/null
+++ b/components/json_schema/json_schema_validator.h
@@ -0,0 +1,235 @@
+// Copyright 2013 The Chromium Authors. 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_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
+#define COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class StringValue;
+class Value;
+}
+
+//==============================================================================
+// This class implements a subset of JSON Schema.
+// See: http://www.json.com/json-schema-proposal/ for more details.
+//
+// There is also an older JavaScript implementation of the same functionality in
+// chrome/renderer/resources/json_schema.js.
+//
+// The following features of JSON Schema are not implemented:
+// - requires
+// - unique
+// - disallow
+// - union types (but replaced with 'choices')
+// - number.maxDecimal
+// - string.pattern
+//
+// The following properties are not applicable to the interface exposed by
+// this class:
+// - options
+// - readonly
+// - title
+// - description
+// - format
+// - default
+// - transient
+// - hidden
+//
+// There are also these departures from the JSON Schema proposal:
+// - null counts as 'unspecified' for optional values
+// - added the 'choices' property, to allow specifying a list of possible types
+//   for a value
+// - by default an "object" typed schema does not allow additional properties.
+//   if present, "additionalProperties" is to be a schema against which all
+//   additional properties will be validated.
+//==============================================================================
+class JSONSchemaValidator {
+ public:
+  // Details about a validation error.
+  struct Error {
+    Error();
+
+    explicit Error(const std::string& message);
+
+    Error(const std::string& path, const std::string& message);
+
+    // The path to the location of the error in the JSON structure.
+    std::string path;
+
+    // An english message describing the error.
+    std::string message;
+  };
+
+  // Error messages.
+  static const char kUnknownTypeReference[];
+  static const char kInvalidChoice[];
+  static const char kInvalidEnum[];
+  static const char kObjectPropertyIsRequired[];
+  static const char kUnexpectedProperty[];
+  static const char kArrayMinItems[];
+  static const char kArrayMaxItems[];
+  static const char kArrayItemRequired[];
+  static const char kStringMinLength[];
+  static const char kStringMaxLength[];
+  static const char kStringPattern[];
+  static const char kNumberMinimum[];
+  static const char kNumberMaximum[];
+  static const char kInvalidType[];
+  static const char kInvalidTypeIntegerNumber[];
+
+  // Classifies a Value as one of the JSON schema primitive types.
+  static std::string GetJSONSchemaType(const base::Value* value);
+
+  // Utility methods to format error messages. The first method can have one
+  // wildcard represented by '*', which is replaced with s1. The second method
+  // can have two, which are replaced by s1 and s2.
+  static std::string FormatErrorMessage(const std::string& format,
+                                        const std::string& s1);
+  static std::string FormatErrorMessage(const std::string& format,
+                                        const std::string& s1,
+                                        const std::string& s2);
+
+  // Verifies if |schema| is a valid JSON v3 schema. When this validation passes
+  // then |schema| is valid JSON that can be parsed into a DictionaryValue,
+  // and that DictionaryValue can be used to build a JSONSchemaValidator.
+  // Returns the parsed DictionaryValue when |schema| validated, otherwise
+  // returns NULL. In that case, |error| contains an error description.
+  static scoped_ptr<base::DictionaryValue> IsValidSchema(
+      const std::string& schema,
+      std::string* error);
+
+  // Creates a validator for the specified schema.
+  //
+  // NOTE: This constructor assumes that |schema| is well formed and valid.
+  // Errors will result in CHECK at runtime; this constructor should not be used
+  // with untrusted schemas.
+  explicit JSONSchemaValidator(base::DictionaryValue* schema);
+
+  // Creates a validator for the specified schema and user-defined types. Each
+  // type must be a valid JSONSchema type description with an additional "id"
+  // field. Schema objects in |schema| can refer to these types with the "$ref"
+  // property.
+  //
+  // NOTE: This constructor assumes that |schema| and |types| are well-formed
+  // and valid. Errors will result in CHECK at runtime; this constructor should
+  // not be used with untrusted schemas.
+  JSONSchemaValidator(base::DictionaryValue* schema, base::ListValue* types);
+
+  ~JSONSchemaValidator();
+
+  // Whether the validator allows additional items for objects and lists, beyond
+  // those defined by their schema, by default.
+  //
+  // This setting defaults to false: all items in an instance list or object
+  // must be defined by the corresponding schema.
+  //
+  // This setting can be overridden on individual object and list schemas by
+  // setting the "additionalProperties" field.
+  bool default_allow_additional_properties() const {
+    return default_allow_additional_properties_;
+  }
+
+  void set_default_allow_additional_properties(bool val) {
+    default_allow_additional_properties_ = val;
+  }
+
+  // Returns any errors from the last call to to Validate().
+  const std::vector<Error>& errors() const {
+    return errors_;
+  }
+
+  // Validates a JSON value. Returns true if the instance is valid, false
+  // otherwise. If false is returned any errors are available from the errors()
+  // getter.
+  bool Validate(const base::Value* instance);
+
+ private:
+  typedef std::map<std::string, const base::DictionaryValue*> TypeMap;
+
+  // Each of the below methods handle a subset of the validation process. The
+  // path paramater is the path to |instance| from the root of the instance tree
+  // and is used in error messages.
+
+  // Validates any instance node against any schema node. This is called for
+  // every node in the instance tree, and it just decides which of the more
+  // detailed methods to call.
+  void Validate(const base::Value* instance,
+                const base::DictionaryValue* schema,
+                const std::string& path);
+
+  // Validates a node against a list of possible schemas. If any one of the
+  // schemas match, the node is valid.
+  void ValidateChoices(const base::Value* instance,
+                       const base::ListValue* choices,
+                       const std::string& path);
+
+  // Validates a node against a list of exact primitive values, eg 42, "foobar".
+  void ValidateEnum(const base::Value* instance,
+                    const base::ListValue* choices,
+                    const std::string& path);
+
+  // Validates a JSON object against an object schema node.
+  void ValidateObject(const base::DictionaryValue* instance,
+                      const base::DictionaryValue* schema,
+                      const std::string& path);
+
+  // Validates a JSON array against an array schema node.
+  void ValidateArray(const base::ListValue* instance,
+                     const base::DictionaryValue* schema,
+                     const std::string& path);
+
+  // Validates a JSON array against an array schema node configured to be a
+  // tuple. In a tuple, there is one schema node for each item expected in the
+  // array.
+  void ValidateTuple(const base::ListValue* instance,
+                     const base::DictionaryValue* schema,
+                     const std::string& path);
+
+  // Validate a JSON string against a string schema node.
+  void ValidateString(const base::Value* instance,
+                      const base::DictionaryValue* schema,
+                      const std::string& path);
+
+  // Validate a JSON number against a number schema node.
+  void ValidateNumber(const base::Value* instance,
+                      const base::DictionaryValue* schema,
+                      const std::string& path);
+
+  // Validates that the JSON node |instance| has |expected_type|.
+  bool ValidateType(const base::Value* instance,
+                    const std::string& expected_type,
+                    const std::string& path);
+
+  // Returns true if |schema| will allow additional items of any type.
+  bool SchemaAllowsAnyAdditionalItems(
+      const base::DictionaryValue* schema,
+      const base::DictionaryValue** addition_items_schema);
+
+  // The root schema node.
+  base::DictionaryValue* schema_root_;
+
+  // Map of user-defined name to type.
+  TypeMap types_;
+
+  // Whether we allow additional properties on objects by default. This can be
+  // overridden by the allow_additional_properties flag on an Object schema.
+  bool default_allow_additional_properties_;
+
+  // Errors accumulated since the last call to Validate().
+  std::vector<Error> errors_;
+
+
+  DISALLOW_COPY_AND_ASSIGN(JSONSchemaValidator);
+};
+
+#endif  // COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_H_
diff --git a/components/json_schema/json_schema_validator_unittest.cc b/components/json_schema/json_schema_validator_unittest.cc
new file mode 100644
index 0000000..4844ed1
--- /dev/null
+++ b/components/json_schema/json_schema_validator_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright 2013 The Chromium Authors. 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/values.h"
+#include "components/json_schema/json_schema_validator.h"
+#include "components/json_schema/json_schema_validator_unittest_base.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class JSONSchemaValidatorCPPTest : public JSONSchemaValidatorTestBase {
+ public:
+  JSONSchemaValidatorCPPTest()
+      : JSONSchemaValidatorTestBase(JSONSchemaValidatorTestBase::CPP) {
+  }
+
+ protected:
+  virtual void ExpectValid(const std::string& test_source,
+                           base::Value* instance,
+                           base::DictionaryValue* schema,
+                           base::ListValue* types) OVERRIDE {
+    JSONSchemaValidator validator(schema, types);
+    if (validator.Validate(instance))
+      return;
+
+    for (size_t i = 0; i < validator.errors().size(); ++i) {
+      ADD_FAILURE() << test_source << ": "
+                    << validator.errors()[i].path << ": "
+                    << validator.errors()[i].message;
+    }
+  }
+
+  virtual void ExpectNotValid(
+      const std::string& test_source,
+      base::Value* instance, base::DictionaryValue* schema,
+      base::ListValue* types,
+      const std::string& expected_error_path,
+      const std::string& expected_error_message) OVERRIDE {
+    JSONSchemaValidator validator(schema, types);
+    if (validator.Validate(instance)) {
+      ADD_FAILURE() << test_source;
+      return;
+    }
+
+    ASSERT_EQ(1u, validator.errors().size()) << test_source;
+    EXPECT_EQ(expected_error_path, validator.errors()[0].path) << test_source;
+    EXPECT_EQ(expected_error_message, validator.errors()[0].message)
+        << test_source;
+  }
+};
+
+TEST_F(JSONSchemaValidatorCPPTest, Test) {
+  RunTests();
+}
+
+TEST(JSONSchemaValidator, IsValidSchema) {
+  std::string error;
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("\0", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("string", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("\"string\"", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("[]", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema("{}", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
+      "{ \"type\": 123 }", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
+      "{ \"type\": \"invalid\" }", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
+      "{"
+      "  \"type\": \"object\","
+      "  \"properties\": []"  // Invalid properties type.
+      "}", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
+      "{"
+      "  \"type\": \"string\","
+      "  \"maxLength\": -1"  // Must be >= 0.
+      "}", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
+      "{"
+      "  \"type\": \"string\","
+      "  \"enum\": [ {} ],"  // "enum" must contain simple values.
+      "}", &error));
+  EXPECT_FALSE(JSONSchemaValidator::IsValidSchema(
+      "{"
+      "  \"type\": \"array\","
+      "  \"items\": [ 123 ],"  // "items" must contain a schema or schemas.
+      "}", &error));
+  EXPECT_TRUE(JSONSchemaValidator::IsValidSchema(
+      "{ \"type\": \"object\" }", &error)) << error;
+  EXPECT_TRUE(JSONSchemaValidator::IsValidSchema(
+      "{ \"type\": [\"object\", \"array\"] }", &error)) << error;
+  EXPECT_TRUE(JSONSchemaValidator::IsValidSchema(
+      "{"
+      "  \"type\": [\"object\", \"array\"],"
+      "  \"properties\": {"
+      "    \"string-property\": {"
+      "      \"type\": \"string\","
+      "      \"minLength\": 1,"
+      "      \"maxLength\": 100,"
+      "      \"title\": \"The String Policy\","
+      "      \"description\": \"This policy controls the String widget.\""
+      "    },"
+      "    \"integer-property\": {"
+      "      \"type\": \"number\","
+      "      \"minimum\": 1000.0,"
+      "      \"maximum\": 9999.0"
+      "    },"
+      "    \"enum-property\": {"
+      "      \"type\": \"integer\","
+      "      \"enum\": [0, 1, 10, 100]"
+      "    },"
+      "    \"items-property\": {"
+      "      \"type\": \"array\","
+      "      \"items\": {"
+      "        \"type\": \"string\""
+      "      }"
+      "    },"
+      "    \"items-list-property\": {"
+      "      \"type\": \"array\","
+      "      \"items\": ["
+      "        { \"type\": \"string\" },"
+      "        { \"type\": \"integer\" }"
+      "      ]"
+      "    }"
+      "  },"
+      "  \"additionalProperties\": {"
+      "    \"type\": \"any\""
+      "  }"
+      "}", &error)) << error;
+}
diff --git a/components/json_schema/json_schema_validator_unittest_base.cc b/components/json_schema/json_schema_validator_unittest_base.cc
new file mode 100644
index 0000000..2e936a2
--- /dev/null
+++ b/components/json_schema/json_schema_validator_unittest_base.cc
@@ -0,0 +1,730 @@
+// Copyright 2013 The Chromium Authors. 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/json_schema/json_schema_validator_unittest_base.h"
+
+#include <cfloat>
+#include <cmath>
+#include <limits>
+
+#include "base/base_paths.h"
+#include "base/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+#include "components/json_schema/json_schema_constants.h"
+#include "components/json_schema/json_schema_validator.h"
+
+namespace schema = json_schema_constants;
+
+namespace {
+
+#define TEST_SOURCE base::StringPrintf("%s:%i", __FILE__, __LINE__)
+
+base::Value* LoadValue(const std::string& filename) {
+  base::FilePath path;
+  PathService::Get(base::DIR_SOURCE_ROOT, &path);
+  path = path.AppendASCII("components")
+             .AppendASCII("test")
+             .AppendASCII("data")
+             .AppendASCII("json_schema")
+             .AppendASCII(filename);
+  EXPECT_TRUE(base::PathExists(path));
+
+  std::string error_message;
+  JSONFileValueSerializer serializer(path);
+  base::Value* result = serializer.Deserialize(NULL, &error_message);
+  if (!result)
+    ADD_FAILURE() << "Could not parse JSON: " << error_message;
+  return result;
+}
+
+base::Value* LoadValue(const std::string& filename, base::Value::Type type) {
+  scoped_ptr<base::Value> result(LoadValue(filename));
+  if (!result.get())
+    return NULL;
+  if (!result->IsType(type)) {
+    ADD_FAILURE() << "Expected type " << type << ", got: " << result->GetType();
+    return NULL;
+  }
+  return result.release();
+}
+
+base::ListValue* LoadList(const std::string& filename) {
+  return static_cast<base::ListValue*>(
+      LoadValue(filename, base::Value::TYPE_LIST));
+}
+
+base::DictionaryValue* LoadDictionary(const std::string& filename) {
+  return static_cast<base::DictionaryValue*>(
+      LoadValue(filename, base::Value::TYPE_DICTIONARY));
+}
+
+}  // namespace
+
+
+JSONSchemaValidatorTestBase::JSONSchemaValidatorTestBase(
+    JSONSchemaValidatorTestBase::ValidatorType type)
+    : type_(type) {
+}
+
+void JSONSchemaValidatorTestBase::RunTests() {
+  TestComplex();
+  TestStringPattern();
+  TestEnum();
+  TestChoices();
+  TestExtends();
+  TestObject();
+  TestTypeReference();
+  TestArrayTuple();
+  TestArrayNonTuple();
+  TestString();
+  TestNumber();
+  TestTypeClassifier();
+  TestTypes();
+}
+
+void JSONSchemaValidatorTestBase::TestComplex() {
+  scoped_ptr<base::DictionaryValue> schema(
+      LoadDictionary("complex_schema.json"));
+  scoped_ptr<base::ListValue> instance(LoadList("complex_instance.json"));
+
+  ASSERT_TRUE(schema.get());
+  ASSERT_TRUE(instance.get());
+
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  instance->Remove(instance->GetSize() - 1, NULL);
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  instance->Append(new base::DictionaryValue());
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "1",
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kNumber,
+                     schema::kObject));
+  instance->Remove(instance->GetSize() - 1, NULL);
+
+  base::DictionaryValue* item = NULL;
+  ASSERT_TRUE(instance->GetDictionary(0, &item));
+  item->SetString("url", "xxxxxxxxxxx");
+
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
+                 "0.url",
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kStringMaxLength, "10"));
+}
+
+void JSONSchemaValidatorTestBase::TestStringPattern() {
+  // Regex patterns not supported in CPP validator.
+  if (type_ == CPP)
+    return;
+
+  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
+  schema->SetString(schema::kType, schema::kString);
+  schema->SetString(schema::kPattern, "foo+");
+
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::StringValue("foo")).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::StringValue("foooooo")).get(),
+              schema.get(), NULL);
+  ExpectNotValid(TEST_SOURCE,
+                 scoped_ptr<base::Value>(new base::StringValue("bar")).get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kStringPattern, "foo+"));
+}
+
+void JSONSchemaValidatorTestBase::TestEnum() {
+  scoped_ptr<base::DictionaryValue> schema(LoadDictionary("enum_schema.json"));
+
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::StringValue("foo")).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(false)).get(),
+              schema.get(), NULL);
+
+  ExpectNotValid(TEST_SOURCE,
+                 scoped_ptr<base::Value>(new base::StringValue("42")).get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::kInvalidEnum);
+  ExpectNotValid(TEST_SOURCE,
+                 scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::kInvalidEnum);
+}
+
+void JSONSchemaValidatorTestBase::TestChoices() {
+  scoped_ptr<base::DictionaryValue> schema(
+      LoadDictionary("choices_schema.json"));
+
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+              schema.get(), NULL);
+
+  scoped_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
+  instance->SetString("foo", "bar");
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  ExpectNotValid(TEST_SOURCE,
+                 scoped_ptr<base::Value>(new base::StringValue("foo")).get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::kInvalidChoice);
+  ExpectNotValid(TEST_SOURCE,
+                 scoped_ptr<base::Value>(new base::ListValue()).get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::kInvalidChoice);
+
+  instance->SetInteger("foo", 42);
+  ExpectNotValid(TEST_SOURCE,
+                 instance.get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::kInvalidChoice);
+}
+
+void JSONSchemaValidatorTestBase::TestExtends() {
+  // TODO(aa): JS only
+}
+
+void JSONSchemaValidatorTestBase::TestObject() {
+  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
+  schema->SetString(schema::kType, schema::kObject);
+  schema->SetString("properties.foo.type", schema::kString);
+  schema->SetString("properties.bar.type", schema::kInteger);
+
+  scoped_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
+  instance->SetString("foo", "foo");
+  instance->SetInteger("bar", 42);
+
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  instance->SetBoolean("extra", true);
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
+                 "extra", JSONSchemaValidator::kUnexpectedProperty);
+
+  instance->Remove("extra", NULL);
+  instance->Remove("bar", NULL);
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "bar",
+                 JSONSchemaValidator::kObjectPropertyIsRequired);
+
+  instance->SetString("bar", "42");
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "bar",
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kInteger,
+                     schema::kString));
+
+  base::DictionaryValue* additional_properties = new base::DictionaryValue();
+  additional_properties->SetString(schema::kType, schema::kAny);
+  schema->Set(schema::kAdditionalProperties, additional_properties);
+
+  instance->SetInteger("bar", 42);
+  instance->SetBoolean("extra", true);
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  instance->SetString("extra", "foo");
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  additional_properties->SetString(schema::kType, schema::kBoolean);
+  instance->SetBoolean("extra", true);
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  instance->SetString("extra", "foo");
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
+                 "extra", JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kBoolean,
+                     schema::kString));
+
+  base::DictionaryValue* properties = NULL;
+  base::DictionaryValue* bar_property = NULL;
+  ASSERT_TRUE(schema->GetDictionary(schema::kProperties, &properties));
+  ASSERT_TRUE(properties->GetDictionary("bar", &bar_property));
+
+  bar_property->SetBoolean(schema::kOptional, true);
+  instance->Remove("extra", NULL);
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  instance->Remove("bar", NULL);
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  instance->Set("bar", base::Value::CreateNullValue());
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
+                 "bar", JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kInteger,
+                     schema::kNull));
+  instance->SetString("bar", "42");
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL,
+                 "bar", JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kInteger,
+                     schema::kString));
+}
+
+void JSONSchemaValidatorTestBase::TestTypeReference() {
+  scoped_ptr<base::ListValue> types(LoadList("reference_types.json"));
+  ASSERT_TRUE(types.get());
+
+  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
+  schema->SetString(schema::kType, schema::kObject);
+  schema->SetString("properties.foo.type", schema::kString);
+  schema->SetString("properties.bar.$ref", "Max10Int");
+  schema->SetString("properties.baz.$ref", "MinLengthString");
+
+  scoped_ptr<base::DictionaryValue> schema_inline(new base::DictionaryValue());
+  schema_inline->SetString(schema::kType, schema::kObject);
+  schema_inline->SetString("properties.foo.type", schema::kString);
+  schema_inline->SetString("properties.bar.id", "NegativeInt");
+  schema_inline->SetString("properties.bar.type", schema::kInteger);
+  schema_inline->SetInteger("properties.bar.maximum", 0);
+  schema_inline->SetString("properties.baz.$ref", "NegativeInt");
+
+  scoped_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
+  instance->SetString("foo", "foo");
+  instance->SetInteger("bar", 4);
+  instance->SetString("baz", "ab");
+
+  scoped_ptr<base::DictionaryValue> instance_inline(
+      new base::DictionaryValue());
+  instance_inline->SetString("foo", "foo");
+  instance_inline->SetInteger("bar", -4);
+  instance_inline->SetInteger("baz", -2);
+
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), types.get());
+  ExpectValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(), NULL);
+
+  // Validation failure, but successful schema reference.
+  instance->SetString("baz", "a");
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), types.get(),
+                 "baz", JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kStringMinLength, "2"));
+
+  instance_inline->SetInteger("bar", 20);
+  ExpectNotValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(), NULL,
+                 "bar", JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kNumberMaximum, "0"));
+
+  // Remove MinLengthString type.
+  types->Remove(types->GetSize() - 1, NULL);
+  instance->SetString("baz", "ab");
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), types.get(),
+                 "bar", JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kUnknownTypeReference,
+                     "Max10Int"));
+
+  // Remove internal type "NegativeInt".
+  schema_inline->Remove("properties.bar", NULL);
+  instance_inline->Remove("bar", NULL);
+  ExpectNotValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(), NULL,
+                 "baz", JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kUnknownTypeReference,
+                     "NegativeInt"));
+}
+
+void JSONSchemaValidatorTestBase::TestArrayTuple() {
+  scoped_ptr<base::DictionaryValue> schema(
+      LoadDictionary("array_tuple_schema.json"));
+  ASSERT_TRUE(schema.get());
+
+  scoped_ptr<base::ListValue> instance(new base::ListValue());
+  instance->Append(new base::StringValue("42"));
+  instance->Append(new base::FundamentalValue(42));
+
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  instance->Append(new base::StringValue("anything"));
+  ExpectNotValid(TEST_SOURCE,
+                 instance.get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kArrayMaxItems, "2"));
+
+  instance->Remove(1, NULL);
+  instance->Remove(1, NULL);
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "1",
+                 JSONSchemaValidator::kArrayItemRequired);
+
+  instance->Set(0, new base::FundamentalValue(42));
+  instance->Append(new base::FundamentalValue(42));
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "0",
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kString,
+                     schema::kInteger));
+
+  base::DictionaryValue* additional_properties = new base::DictionaryValue();
+  additional_properties->SetString(schema::kType, schema::kAny);
+  schema->Set(schema::kAdditionalProperties, additional_properties);
+  instance->Set(0, new base::StringValue("42"));
+  instance->Append(new base::StringValue("anything"));
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  instance->Set(2, new base::ListValue());
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  additional_properties->SetString(schema::kType, schema::kBoolean);
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "2",
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kBoolean,
+                     schema::kArray));
+  instance->Set(2, new base::FundamentalValue(false));
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  base::ListValue* items_schema = NULL;
+  base::DictionaryValue* item0_schema = NULL;
+  ASSERT_TRUE(schema->GetList(schema::kItems, &items_schema));
+  ASSERT_TRUE(items_schema->GetDictionary(0, &item0_schema));
+  item0_schema->SetBoolean(schema::kOptional, true);
+  instance->Remove(2, NULL);
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  // TODO(aa): I think this is inconsistent with the handling of NULL+optional
+  // for objects.
+  instance->Set(0, base::Value::CreateNullValue());
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  instance->Set(0, new base::FundamentalValue(42));
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "0",
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kString,
+                     schema::kInteger));
+}
+
+void JSONSchemaValidatorTestBase::TestArrayNonTuple() {
+  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
+  schema->SetString(schema::kType, schema::kArray);
+  schema->SetString("items.type", schema::kString);
+  schema->SetInteger(schema::kMinItems, 2);
+  schema->SetInteger(schema::kMaxItems, 3);
+
+  scoped_ptr<base::ListValue> instance(new base::ListValue());
+  instance->Append(new base::StringValue("x"));
+  instance->Append(new base::StringValue("x"));
+
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+  instance->Append(new base::StringValue("x"));
+  ExpectValid(TEST_SOURCE, instance.get(), schema.get(), NULL);
+
+  instance->Append(new base::StringValue("x"));
+  ExpectNotValid(TEST_SOURCE,
+                 instance.get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kArrayMaxItems, "3"));
+  instance->Remove(1, NULL);
+  instance->Remove(1, NULL);
+  instance->Remove(1, NULL);
+  ExpectNotValid(TEST_SOURCE,
+                 instance.get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kArrayMinItems, "2"));
+
+  instance->Remove(1, NULL);
+  instance->Append(new base::FundamentalValue(42));
+  ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), NULL, "1",
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kInvalidType,
+                     schema::kString,
+                     schema::kInteger));
+}
+
+void JSONSchemaValidatorTestBase::TestString() {
+  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
+  schema->SetString(schema::kType, schema::kString);
+  schema->SetInteger(schema::kMinLength, 1);
+  schema->SetInteger(schema::kMaxLength, 10);
+
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::StringValue("x")).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(
+                  new base::StringValue("xxxxxxxxxx")).get(),
+              schema.get(), NULL);
+
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::StringValue(std::string())).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kStringMinLength, "1"));
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::StringValue("xxxxxxxxxxx")).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kStringMaxLength, "10"));
+}
+
+void JSONSchemaValidatorTestBase::TestNumber() {
+  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
+  schema->SetString(schema::kType, schema::kNumber);
+  schema->SetInteger(schema::kMinimum, 1);
+  schema->SetInteger(schema::kMaximum, 100);
+  schema->SetInteger("maxDecimal", 2);
+
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(1)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(50)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(100)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(88.88)).get(),
+              schema.get(), NULL);
+
+  ExpectNotValid(TEST_SOURCE,
+                 scoped_ptr<base::Value>(new base::FundamentalValue(0.5)).get(),
+                 schema.get(),
+                 NULL,
+                 std::string(),
+                 JSONSchemaValidator::FormatErrorMessage(
+                     JSONSchemaValidator::kNumberMinimum, "1"));
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::FundamentalValue(100.1)).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kNumberMaximum, "100"));
+}
+
+void JSONSchemaValidatorTestBase::TestTypeClassifier() {
+  EXPECT_EQ(std::string(schema::kBoolean),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(
+                    new base::FundamentalValue(true)).get()));
+  EXPECT_EQ(std::string(schema::kBoolean),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(
+                    new base::FundamentalValue(false)).get()));
+
+  // It doesn't matter whether the C++ type is 'integer' or 'real'. If the
+  // number is integral and within the representable range of integers in
+  // double, it's classified as 'integer'.
+  EXPECT_EQ(std::string(schema::kInteger),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(new base::FundamentalValue(42)).get()));
+  EXPECT_EQ(std::string(schema::kInteger),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(new base::FundamentalValue(0)).get()));
+  EXPECT_EQ(std::string(schema::kInteger),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(new base::FundamentalValue(42)).get()));
+  EXPECT_EQ(std::string(schema::kInteger),
+            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
+                new base::FundamentalValue(pow(2.0, DBL_MANT_DIG))).get()));
+  EXPECT_EQ(std::string(schema::kInteger),
+            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
+                new base::FundamentalValue(pow(-2.0, DBL_MANT_DIG))).get()));
+
+  // "number" is only used for non-integral numbers, or numbers beyond what
+  // double can accurately represent.
+  EXPECT_EQ(std::string(schema::kNumber),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(
+                    new base::FundamentalValue(88.8)).get()));
+  EXPECT_EQ(std::string(schema::kNumber),
+            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
+                new base::FundamentalValue(pow(2.0, DBL_MANT_DIG) * 2)).get()));
+  EXPECT_EQ(std::string(schema::kNumber),
+            JSONSchemaValidator::GetJSONSchemaType(scoped_ptr<base::Value>(
+                new base::FundamentalValue(
+                    pow(-2.0, DBL_MANT_DIG) * 2)).get()));
+
+  EXPECT_EQ(std::string(schema::kString),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(new base::StringValue("foo")).get()));
+  EXPECT_EQ(std::string(schema::kArray),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(new base::ListValue()).get()));
+  EXPECT_EQ(std::string(schema::kObject),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(new base::DictionaryValue()).get()));
+  EXPECT_EQ(std::string(schema::kNull),
+            JSONSchemaValidator::GetJSONSchemaType(
+                scoped_ptr<base::Value>(base::Value::CreateNullValue()).get()));
+}
+
+void JSONSchemaValidatorTestBase::TestTypes() {
+  scoped_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
+
+  // valid
+  schema->SetString(schema::kType, schema::kObject);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::DictionaryValue()).get(),
+              schema.get(), NULL);
+
+  schema->SetString(schema::kType, schema::kArray);
+  ExpectValid(TEST_SOURCE, scoped_ptr<base::Value>(new base::ListValue()).get(),
+              schema.get(), NULL);
+
+  schema->SetString(schema::kType, schema::kString);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::StringValue("foobar")).get(),
+              schema.get(), NULL);
+
+  schema->SetString(schema::kType, schema::kNumber);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(88.8)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(0)).get(),
+              schema.get(), NULL);
+
+  schema->SetString(schema::kType, schema::kInteger);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(0)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(
+                  new base::FundamentalValue(pow(2.0, DBL_MANT_DIG))).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(
+                  new base::FundamentalValue(pow(-2.0, DBL_MANT_DIG))).get(),
+              schema.get(), NULL);
+
+  schema->SetString(schema::kType, schema::kBoolean);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(false)).get(),
+              schema.get(), NULL);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(new base::FundamentalValue(true)).get(),
+              schema.get(), NULL);
+
+  schema->SetString(schema::kType, schema::kNull);
+  ExpectValid(TEST_SOURCE,
+              scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
+              schema.get(), NULL);
+
+  // not valid
+  schema->SetString(schema::kType, schema::kObject);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::ListValue()).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kInvalidType, schema::kObject, schema::kArray));
+
+  schema->SetString(schema::kType, schema::kObject);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(base::Value::CreateNullValue()).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kInvalidType, schema::kObject, schema::kNull));
+
+  schema->SetString(schema::kType, schema::kArray);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kInvalidType, schema::kArray, schema::kInteger));
+
+  schema->SetString(schema::kType, schema::kString);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::FundamentalValue(42)).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
+                                              schema::kString,
+                                              schema::kInteger));
+
+  schema->SetString(schema::kType, schema::kNumber);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::StringValue("42")).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kInvalidType, schema::kNumber, schema::kString));
+
+  schema->SetString(schema::kType, schema::kInteger);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::FundamentalValue(88.8)).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::kInvalidTypeIntegerNumber);
+
+  schema->SetString(schema::kType, schema::kBoolean);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::FundamentalValue(1)).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
+                                              schema::kBoolean,
+                                              schema::kInteger));
+
+  schema->SetString(schema::kType, schema::kNull);
+  ExpectNotValid(
+      TEST_SOURCE,
+      scoped_ptr<base::Value>(new base::FundamentalValue(false)).get(),
+      schema.get(),
+      NULL,
+      std::string(),
+      JSONSchemaValidator::FormatErrorMessage(
+          JSONSchemaValidator::kInvalidType, schema::kNull, schema::kBoolean));
+}
diff --git a/components/json_schema/json_schema_validator_unittest_base.h b/components/json_schema/json_schema_validator_unittest_base.h
new file mode 100644
index 0000000..7b4854e
--- /dev/null
+++ b/components/json_schema/json_schema_validator_unittest_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 COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_UNITTEST_BASE_H_
+#define COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_UNITTEST_BASE_H_
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class Value;
+}
+
+// Base class for unit tests for JSONSchemaValidator. There is currently only
+// one implementation, JSONSchemaValidatorCPPTest.
+//
+// TODO(aa): Refactor chrome/test/data/json_schema_test.js into
+// JSONSchemaValidatorJSTest that inherits from this.
+class JSONSchemaValidatorTestBase : public testing::Test {
+ public:
+  enum ValidatorType {
+    CPP = 1,
+    JS = 2
+  };
+
+  explicit JSONSchemaValidatorTestBase(ValidatorType type);
+
+  void RunTests();
+
+ protected:
+  virtual void ExpectValid(const std::string& test_source,
+                           base::Value* instance,
+                           base::DictionaryValue* schema,
+                           base::ListValue* types) = 0;
+
+  virtual void ExpectNotValid(const std::string& test_source,
+                              base::Value* instance,
+                              base::DictionaryValue* schema,
+                              base::ListValue* types,
+                              const std::string& expected_error_path,
+                              const std::string& expected_error_message) = 0;
+
+ private:
+  void TestComplex();
+  void TestStringPattern();
+  void TestEnum();
+  void TestChoices();
+  void TestExtends();
+  void TestObject();
+  void TestTypeReference();
+  void TestArrayTuple();
+  void TestArrayNonTuple();
+  void TestString();
+  void TestNumber();
+  void TestTypeClassifier();
+  void TestTypes();
+
+  ValidatorType type_;
+};
+
+#endif  // COMPONENTS_JSON_SCHEMA_JSON_SCHEMA_VALIDATOR_UNITTEST_BASE_H_
diff --git a/components/nacl/common/nacl_cmd_line.cc b/components/nacl/common/nacl_cmd_line.cc
index b21a671..d9bbd65 100644
--- a/components/nacl/common/nacl_cmd_line.cc
+++ b/components/nacl/common/nacl_cmd_line.cc
@@ -18,7 +18,6 @@
   // TODO(gregoryd): check which flags of those below can be supported.
   static const char* const kSwitchNames[] = {
     switches::kNoSandbox,
-    switches::kTestNaClSandbox,
     switches::kDisableBreakpad,
     switches::kFullMemoryCrashReport,
     switches::kEnableLogging,
diff --git a/components/nacl/common/nacl_helper_linux.h b/components/nacl/common/nacl_helper_linux.h
index 732b215..a9324b3 100644
--- a/components/nacl/common/nacl_helper_linux.h
+++ b/components/nacl/common/nacl_helper_linux.h
@@ -9,10 +9,15 @@
 // constants used to implement communication between the nacl_helper
 // process and the Chrome zygote.
 
+#define kNaClMaxIPCMessageLength 2048
+
 // Used by Helper to tell Zygote it has started successfully.
 #define kNaClHelperStartupAck "NACLHELPER_OK"
-// Used by Zygote to ask Helper to fork a new NaCl loader.
-#define kNaClForkRequest "NACLFORK"
+
+enum NaClZygoteIPCCommand {
+  kNaClForkRequest,
+  kNaClGetTerminationStatusRequest,
+};
 
 // The next set of constants define global Linux file descriptors.
 // For communications between NaCl loader and browser.
diff --git a/components/nacl/common/nacl_host_messages.h b/components/nacl/common/nacl_host_messages.h
index d9a835b..0e3880a 100644
--- a/components/nacl/common/nacl_host_messages.h
+++ b/components/nacl/common/nacl_host_messages.h
@@ -26,6 +26,7 @@
   IPC_STRUCT_TRAITS_MEMBER(uses_irt)
   IPC_STRUCT_TRAITS_MEMBER(enable_dyncode_syscalls)
   IPC_STRUCT_TRAITS_MEMBER(enable_exception_handling)
+  IPC_STRUCT_TRAITS_MEMBER(enable_crash_throttling)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(nacl::NaClLaunchResult)
diff --git a/components/nacl/common/nacl_switches.cc b/components/nacl/common/nacl_switches.cc
index b9db537..0dfdc94 100644
--- a/components/nacl/common/nacl_switches.cc
+++ b/components/nacl/common/nacl_switches.cc
@@ -36,7 +36,4 @@
 // Causes the process to run as a NativeClient loader.
 const char kNaClLoaderProcess[]             = "nacl-loader";
 
-// Runs the security test for the NaCl loader sandbox.
-const char kTestNaClSandbox[]               = "test-nacl-sandbox";
-
 }  // namespace switches
diff --git a/components/nacl/common/nacl_switches.h b/components/nacl/common/nacl_switches.h
index 8b12206..9bc1bcb 100644
--- a/components/nacl/common/nacl_switches.h
+++ b/components/nacl/common/nacl_switches.h
@@ -18,7 +18,6 @@
 extern const char kNaClGdbScript[];
 extern const char kNaClLoaderCmdPrefix[];
 extern const char kNaClLoaderProcess[];
-extern const char kTestNaClSandbox[];
 
 }  // namespace switches
 
diff --git a/components/nacl/common/nacl_types.cc b/components/nacl/common/nacl_types.cc
index dea0239..6b2f51e 100644
--- a/components/nacl/common/nacl_types.cc
+++ b/components/nacl/common/nacl_types.cc
@@ -24,7 +24,8 @@
       permission_bits(0),
       uses_irt(false),
       enable_dyncode_syscalls(false),
-      enable_exception_handling(false)  {
+      enable_exception_handling(false),
+      enable_crash_throttling(false) {
 }
 
 NaClLaunchParams::NaClLaunchParams(const std::string& manifest_url,
@@ -32,13 +33,15 @@
                                    uint32 permission_bits,
                                    bool uses_irt,
                                    bool enable_dyncode_syscalls,
-                                   bool enable_exception_handling)
+                                   bool enable_exception_handling,
+                                   bool enable_crash_throttling)
     : manifest_url(manifest_url),
       render_view_id(render_view_id),
       permission_bits(permission_bits),
       uses_irt(uses_irt),
       enable_dyncode_syscalls(enable_dyncode_syscalls),
-      enable_exception_handling(enable_exception_handling)  {
+      enable_exception_handling(enable_exception_handling),
+      enable_crash_throttling(enable_crash_throttling) {
 }
 
 NaClLaunchParams::NaClLaunchParams(const NaClLaunchParams& l) {
@@ -48,6 +51,7 @@
   uses_irt = l.uses_irt;
   enable_dyncode_syscalls = l.enable_dyncode_syscalls;
   enable_exception_handling = l.enable_exception_handling;
+  enable_crash_throttling = l.enable_crash_throttling;
 }
 
 NaClLaunchParams::~NaClLaunchParams() {
diff --git a/components/nacl/common/nacl_types.h b/components/nacl/common/nacl_types.h
index b3fee25..47fccdd 100644
--- a/components/nacl/common/nacl_types.h
+++ b/components/nacl/common/nacl_types.h
@@ -70,7 +70,8 @@
   NaClLaunchParams();
   NaClLaunchParams(const std::string& u, int r, uint32 p, bool uses_irt,
                    bool enable_dyncode_syscalls,
-                   bool enable_exception_handling);
+                   bool enable_exception_handling,
+                   bool enable_crash_throttling);
   NaClLaunchParams(const NaClLaunchParams& l);
   ~NaClLaunchParams();
 
@@ -80,6 +81,7 @@
   bool uses_irt;
   bool enable_dyncode_syscalls;
   bool enable_exception_handling;
+  bool enable_crash_throttling;
 };
 
 struct NaClLaunchResult {
diff --git a/components/nacl/loader/nacl_main.cc b/components/nacl/loader/nacl_main.cc
index a9ec5c9..15b6fd2 100644
--- a/components/nacl/loader/nacl_main.cc
+++ b/components/nacl/loader/nacl_main.cc
@@ -29,10 +29,7 @@
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
   NaClMainPlatformDelegate platform(parameters);
-
-  platform.PlatformInitialize();
   bool no_sandbox = parsed_command_line.HasSwitch(switches::kNoSandbox);
-  platform.InitSandboxTests(no_sandbox);
 
 #if defined(OS_POSIX)
   // The number of cores must be obtained before the invocation of
@@ -43,25 +40,14 @@
   if (!no_sandbox) {
     platform.EnableSandbox();
   }
-  bool sandbox_test_result = platform.RunSandboxTests();
-
-  if (sandbox_test_result) {
-    NaClListener listener;
+  NaClListener listener;
 #if defined(OS_POSIX)
-    listener.set_number_of_cores(number_of_cores);
+  listener.set_number_of_cores(number_of_cores);
 #endif
-    listener.Listen();
-  } else {
-    // This indirectly prevents the test-harness-success-cookie from being set,
-    // as a way of communicating test failure, because the nexe won't reply.
-    // TODO(jvoung): find a better way to indicate failure that doesn't
-    // require waiting for a timeout.
-    VLOG(1) << "Sandbox test failed: Not launching NaCl process";
-  }
+
+  listener.Listen();
 #else
   NOTIMPLEMENTED() << " not implemented startup, plugin startup dialog etc.";
 #endif
-
-  platform.PlatformUninitialize();
   return 0;
 }
diff --git a/components/nacl/loader/nacl_main_platform_delegate.h b/components/nacl/loader/nacl_main_platform_delegate.h
index 191831c..ca740b8 100644
--- a/components/nacl/loader/nacl_main_platform_delegate.h
+++ b/components/nacl/loader/nacl_main_platform_delegate.h
@@ -5,38 +5,20 @@
 #ifndef CHROME_NACL_NACL_MAIN_PLATFORM_DELEGATE_H_
 #define CHROME_NACL_NACL_MAIN_PLATFORM_DELEGATE_H_
 
-#include "base/native_library.h"
+#include "base/basictypes.h"
 #include "content/public/common/main_function_params.h"
 
-typedef bool (*RunNaClLoaderTests)(void);
-const char kNaClLoaderTestCall[] = "RunNaClLoaderTests";
-
 class NaClMainPlatformDelegate {
  public:
   explicit NaClMainPlatformDelegate(
       const content::MainFunctionParams& parameters);
   ~NaClMainPlatformDelegate();
 
-  // Called first thing and last thing in the process' lifecycle, i.e. before
-  // the sandbox is enabled.
-  void PlatformInitialize();
-  void PlatformUninitialize();
-
-  // Gives us an opportunity to initialize state used for tests before enabling
-  // the sandbox.
-  void InitSandboxTests(bool no_sandbox);
-
   // Initiate Lockdown.
   void EnableSandbox();
 
-  // Runs the sandbox tests for the NaCl Loader, if tests supplied.
-  // Cannot run again, after this (resources freed).
-  // Returns false if the tests are supplied and fail.
-  bool RunSandboxTests();
-
  private:
   const content::MainFunctionParams& parameters_;
-  base::NativeLibrary sandbox_test_module_;
 
   DISALLOW_COPY_AND_ASSIGN(NaClMainPlatformDelegate);
 };
diff --git a/components/nacl/loader/nacl_main_platform_delegate_linux.cc b/components/nacl/loader/nacl_main_platform_delegate_linux.cc
index e9d2f73..cbe886b 100644
--- a/components/nacl/loader/nacl_main_platform_delegate_linux.cc
+++ b/components/nacl/loader/nacl_main_platform_delegate_linux.cc
@@ -4,28 +4,14 @@
 
 #include "components/nacl/loader/nacl_main_platform_delegate.h"
 
-#include "base/command_line.h"
-
 NaClMainPlatformDelegate::NaClMainPlatformDelegate(
     const content::MainFunctionParams& parameters)
-    : parameters_(parameters), sandbox_test_module_(NULL) {
+    : parameters_(parameters) {
 }
 
 NaClMainPlatformDelegate::~NaClMainPlatformDelegate() {
 }
 
-void NaClMainPlatformDelegate::PlatformInitialize() {
-}
-
-void NaClMainPlatformDelegate::PlatformUninitialize() {
-}
-
-void NaClMainPlatformDelegate::InitSandboxTests(bool no_sandbox) {
-  // The sandbox is started in the zygote process: zygote_main_linux.cc
-  // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
-  return;
-}
-
 void NaClMainPlatformDelegate::EnableSandbox() {
   // The setuid sandbox is started in the zygote process: zygote_main_linux.cc
   // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
@@ -43,9 +29,3 @@
   // At best, NaCl will not work.  At worst, enabling the seccomp sandbox
   // could create a hole in the NaCl sandbox.
 }
-
-bool NaClMainPlatformDelegate::RunSandboxTests() {
-  // The sandbox is started in the zygote process: zygote_main_linux.cc
-  // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox
-  return true;
-}
diff --git a/components/nacl/loader/nacl_main_platform_delegate_mac.mm b/components/nacl/loader/nacl_main_platform_delegate_mac.mm
index 67ddced..78fa539 100644
--- a/components/nacl/loader/nacl_main_platform_delegate_mac.mm
+++ b/components/nacl/loader/nacl_main_platform_delegate_mac.mm
@@ -5,78 +5,22 @@
 #include "components/nacl/loader/nacl_main_platform_delegate.h"
 
 #import <Cocoa/Cocoa.h>
-#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/native_library.h"
 #include "components/nacl/common/nacl_sandbox_type_mac.h"
 #include "components/nacl/common/nacl_switches.h"
 #include "content/public/common/sandbox_init.h"
 
 NaClMainPlatformDelegate::NaClMainPlatformDelegate(
     const content::MainFunctionParams& parameters)
-    : parameters_(parameters), sandbox_test_module_(NULL) {
+    : parameters_(parameters) {
 }
 
 NaClMainPlatformDelegate::~NaClMainPlatformDelegate() {
 }
 
-// TODO(jvoung): see if this old comment (from renderer_main_platform...)
-// is relevant to the nacl loader.
-// TODO(mac-port): Any code needed to initialize a process for purposes of
-// running a NaClLoader needs to also be reflected in chrome_main.cc for
-// --single-process support.
-void NaClMainPlatformDelegate::PlatformInitialize() {
-}
-
-void NaClMainPlatformDelegate::PlatformUninitialize() {
-}
-
-void NaClMainPlatformDelegate::InitSandboxTests(bool no_sandbox) {
-  const CommandLine& command_line = parameters_.command_line;
-
-  DVLOG(1) << "Started NaClLdr with ";
-  const std::vector<std::string>& argstrings = command_line.argv();
-  for (std::vector<std::string>::const_iterator ii = argstrings.begin();
-       ii != argstrings.end(); ++ii)
-    DVLOG(1) << *ii;
-
-  // Be sure not to load the sandbox test DLL if the sandbox isn't on.
-  // Comment-out guard and recompile if you REALLY want to test w/out the SB.
-  // TODO(jvoung): allow testing without sandbox, but change expected ret vals.
-  if (!no_sandbox) {
-    base::FilePath test_dll_name =
-      command_line.GetSwitchValuePath(switches::kTestNaClSandbox);
-    if (!test_dll_name.empty()) {
-      sandbox_test_module_ = base::LoadNativeLibrary(test_dll_name, NULL);
-      CHECK(sandbox_test_module_);
-    }
-  }
-}
-
 void NaClMainPlatformDelegate::EnableSandbox() {
   CHECK(content::InitializeSandbox(NACL_SANDBOX_TYPE_NACL_LOADER,
                                    base::FilePath()))
       << "Error initializing sandbox for " << switches::kNaClLoaderProcess;
 }
-
-bool NaClMainPlatformDelegate::RunSandboxTests() {
-  // TODO(jvoung): Win and mac should share this identical code.
-  bool result = true;
-  if (sandbox_test_module_) {
-    RunNaClLoaderTests run_security_tests =
-      reinterpret_cast<RunNaClLoaderTests>(
-        base::GetFunctionPointerFromNativeLibrary(sandbox_test_module_,
-                                                  kNaClLoaderTestCall));
-    if (run_security_tests) {
-      DVLOG(1) << "Running NaCl Loader security tests";
-      result = (*run_security_tests)();
-    } else {
-      VLOG(1) << "Failed to get NaCl sandbox test function";
-      result = false;
-    }
-    base::UnloadNativeLibrary(sandbox_test_module_);
-    sandbox_test_module_ = NULL;
-  }
-  return result;
-}
diff --git a/components/nacl/loader/nacl_main_platform_delegate_win.cc b/components/nacl/loader/nacl_main_platform_delegate_win.cc
index e79fe17..f530961 100644
--- a/components/nacl/loader/nacl_main_platform_delegate_win.cc
+++ b/components/nacl/loader/nacl_main_platform_delegate_win.cc
@@ -4,59 +4,17 @@
 
 #include "components/nacl/loader/nacl_main_platform_delegate.h"
 
-#include "base/command_line.h"
-#include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/native_library.h"
-#include "components/nacl/common/nacl_switches.h"
 #include "sandbox/win/src/sandbox.h"
 
 NaClMainPlatformDelegate::NaClMainPlatformDelegate(
     const content::MainFunctionParams& parameters)
-    : parameters_(parameters), sandbox_test_module_(NULL) {
+    : parameters_(parameters) {
 }
 
 NaClMainPlatformDelegate::~NaClMainPlatformDelegate() {
 }
 
-void NaClMainPlatformDelegate::PlatformInitialize() {
-  // Be mindful of what resources you acquire here. They can be used by
-  // malicious code if the renderer gets compromised.
-}
-
-void NaClMainPlatformDelegate::PlatformUninitialize() {
-}
-
-void NaClMainPlatformDelegate::InitSandboxTests(bool no_sandbox) {
-  const CommandLine& command_line = parameters_.command_line;
-
-  DVLOG(1) << "Started NaClLdr with " << command_line.GetCommandLineString();
-
-  sandbox::TargetServices* target_services =
-      parameters_.sandbox_info->target_services;
-
-  if (target_services && !no_sandbox) {
-    base::FilePath test_dll_name =
-      command_line.GetSwitchValuePath(switches::kTestNaClSandbox);
-    if (!test_dll_name.empty()) {
-      // At this point, hack on the suffix according to with bitness
-      // of your windows process.
-#if defined(_WIN64)
-      DVLOG(1) << "Using 64-bit test dll\n";
-      test_dll_name = test_dll_name.InsertBeforeExtension(L"64");
-      test_dll_name = test_dll_name.ReplaceExtension(L"dll");
-#else
-      DVLOG(1) << "Using 32-bit test dll\n";
-      test_dll_name = test_dll_name.ReplaceExtension(L"dll");
-#endif
-      DVLOG(1) << "Loading test lib " << test_dll_name.value() << "\n";
-      sandbox_test_module_ = base::LoadNativeLibrary(test_dll_name, NULL);
-      CHECK(sandbox_test_module_);
-      VLOG(1) << "Testing NaCl sandbox\n";
-    }
-  }
-}
-
 void NaClMainPlatformDelegate::EnableSandbox() {
   sandbox::TargetServices* target_services =
       parameters_.sandbox_info->target_services;
@@ -71,24 +29,3 @@
   // Turn the sandbox on.
   target_services->LowerToken();
 }
-
-bool NaClMainPlatformDelegate::RunSandboxTests() {
-  // TODO(jvoung): Win and mac should share this code.
-  bool result = true;
-  if (sandbox_test_module_) {
-    RunNaClLoaderTests run_security_tests =
-      reinterpret_cast<RunNaClLoaderTests>(
-        base::GetFunctionPointerFromNativeLibrary(sandbox_test_module_,
-                                                  kNaClLoaderTestCall));
-    if (run_security_tests) {
-      DVLOG(1) << "Running NaCl Loader security tests";
-      result = (*run_security_tests)();
-    } else {
-      VLOG(1) << "Failed to get NaCl sandbox test function";
-      result = false;
-    }
-    base::UnloadNativeLibrary(sandbox_test_module_);
-    sandbox_test_module_ = NULL;
-  }
-  return result;
-}
diff --git a/components/nacl/zygote/nacl_fork_delegate_linux.cc b/components/nacl/zygote/nacl_fork_delegate_linux.cc
index 8445342..d94ad6b 100644
--- a/components/nacl/zygote/nacl_fork_delegate_linux.cc
+++ b/components/nacl/zygote/nacl_fork_delegate_linux.cc
@@ -17,8 +17,10 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/path_service.h"
+#include "base/pickle.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/unix_domain_socket_linux.h"
+#include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "components/nacl/common/nacl_helper_linux.h"
@@ -63,6 +65,41 @@
 }
 #endif
 
+// Send an IPC request on |ipc_channel|. The request is contained in
+// |request_pickle| and can have file descriptors attached in |attached_fds|.
+// |reply_data_buffer| must be allocated by the caller and will contain the
+// reply. The size of the reply will be written to |reply_size|.
+// This code assumes that only one thread can write to |ipc_channel| to make
+// requests.
+bool SendIPCRequestAndReadReply(int ipc_channel,
+                                const std::vector<int>& attached_fds,
+                                const Pickle& request_pickle,
+                                char* reply_data_buffer,
+                                size_t reply_data_buffer_size,
+                                ssize_t* reply_size) {
+  DCHECK_LE(static_cast<size_t>(kNaClMaxIPCMessageLength),
+            reply_data_buffer_size);
+  DCHECK(reply_size);
+
+  if (!UnixDomainSocket::SendMsg(ipc_channel, request_pickle.data(),
+                                 request_pickle.size(), attached_fds)) {
+    LOG(ERROR) << "SendIPCRequestAndReadReply: SendMsg failed";
+    return false;
+  }
+
+  // Then read the remote reply.
+  std::vector<int> received_fds;
+  const ssize_t msg_len =
+      UnixDomainSocket::RecvMsg(ipc_channel, reply_data_buffer,
+                                reply_data_buffer_size, &received_fds);
+  if (msg_len <= 0) {
+    LOG(ERROR) << "SendIPCRequestAndReadReply: RecvMsg failed";
+    return false;
+  }
+  *reply_size = msg_len;
+  return true;
+}
+
 }  // namespace.
 
 NaClForkDelegate::NaClForkDelegate()
@@ -219,22 +256,34 @@
 }
 
 pid_t NaClForkDelegate::Fork(const std::vector<int>& fds) {
-  base::ProcessId naclchild;
   VLOG(1) << "NaClForkDelegate::Fork";
 
   DCHECK(fds.size() == kNaClParentFDIndex + 1);
-  if (!UnixDomainSocket::SendMsg(fd_, kNaClForkRequest,
-                                 strlen(kNaClForkRequest), fds)) {
-    LOG(ERROR) << "NaClForkDelegate::Fork: SendMsg failed";
+
+  // First, send a remote fork request.
+  Pickle write_pickle;
+  write_pickle.WriteInt(kNaClForkRequest);
+
+  char reply_buf[kNaClMaxIPCMessageLength];
+  ssize_t reply_size = 0;
+  bool got_reply =
+      SendIPCRequestAndReadReply(fd_, fds, write_pickle,
+                                 reply_buf, sizeof(reply_buf), &reply_size);
+  if (!got_reply) {
+    LOG(ERROR) << "Could not perform remote fork.";
     return -1;
   }
-  int nread = HANDLE_EINTR(read(fd_, &naclchild, sizeof(naclchild)));
-  if (nread != sizeof(naclchild)) {
-    LOG(ERROR) << "NaClForkDelegate::Fork: read failed";
+
+  // Now see if the other end managed to fork.
+  Pickle reply_pickle(reply_buf, reply_size);
+  PickleIterator iter(reply_pickle);
+  pid_t nacl_child;
+  if (!iter.ReadInt(&nacl_child)) {
+    LOG(ERROR) << "NaClForkDelegate::Fork: pickle failed";
     return -1;
   }
-  VLOG(1) << "nacl_child is " << naclchild << " (" << nread << " bytes)";
-  return naclchild;
+  VLOG(1) << "nacl_child is " << nacl_child;
+  return nacl_child;
 }
 
 bool NaClForkDelegate::AckChild(const int fd,
@@ -246,3 +295,47 @@
   }
   return true;
 }
+
+bool NaClForkDelegate::GetTerminationStatus(pid_t pid, bool known_dead,
+                                            base::TerminationStatus* status,
+                                            int* exit_code) {
+  VLOG(1) << "NaClForkDelegate::GetTerminationStatus";
+  DCHECK(status);
+  DCHECK(exit_code);
+
+  Pickle write_pickle;
+  write_pickle.WriteInt(kNaClGetTerminationStatusRequest);
+  write_pickle.WriteInt(pid);
+  write_pickle.WriteBool(known_dead);
+
+  const std::vector<int> empty_fds;
+  char reply_buf[kNaClMaxIPCMessageLength];
+  ssize_t reply_size = 0;
+  bool got_reply =
+      SendIPCRequestAndReadReply(fd_, empty_fds, write_pickle,
+                                 reply_buf, sizeof(reply_buf), &reply_size);
+  if (!got_reply) {
+    LOG(ERROR) << "Could not perform remote GetTerminationStatus.";
+    return false;
+  }
+
+  Pickle reply_pickle(reply_buf, reply_size);
+  PickleIterator iter(reply_pickle);
+  int termination_status;
+  if (!iter.ReadInt(&termination_status) ||
+      termination_status < 0 ||
+      termination_status >= base::TERMINATION_STATUS_MAX_ENUM) {
+    LOG(ERROR) << "GetTerminationStatus: pickle failed";
+    return false;
+  }
+
+  int remote_exit_code;
+  if (!iter.ReadInt(&remote_exit_code)) {
+    LOG(ERROR) << "GetTerminationStatus: pickle failed";
+    return false;
+  }
+
+  *status = static_cast<base::TerminationStatus>(termination_status);
+  *exit_code = remote_exit_code;
+  return true;
+}
diff --git a/components/nacl/zygote/nacl_fork_delegate_linux.h b/components/nacl/zygote/nacl_fork_delegate_linux.h
index 5812f33..a5ec534 100644
--- a/components/nacl/zygote/nacl_fork_delegate_linux.h
+++ b/components/nacl/zygote/nacl_fork_delegate_linux.h
@@ -31,6 +31,9 @@
   virtual pid_t Fork(const std::vector<int>& fds) OVERRIDE;
   virtual bool AckChild(int fd,
                         const std::string& channel_switch) OVERRIDE;
+  virtual bool GetTerminationStatus(pid_t pid, bool known_dead,
+                                    base::TerminationStatus* status,
+                                    int* exit_code) OVERRIDE;
 
  private:
   // These values are reported via UMA and hence they become permanent
diff --git a/components/policy.gypi b/components/policy.gypi
new file mode 100644
index 0000000..5295ba4
--- /dev/null
+++ b/components/policy.gypi
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'policy_component',
+      'type': '<(component)',
+      'dependencies': [
+        '../base/base.gyp:base',
+        'json_schema',
+      ],
+      'defines': [
+        'POLICY_COMPONENT_IMPLEMENTATION',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'conditions': [
+        ['configuration_policy==1', {
+          'sources': [
+            'policy/core/common/policy_schema.cc',
+            'policy/core/common/policy_schema.h',
+            '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
+          'sources': [
+            'policy/stub_to_remove.cc',
+          ],
+        }],
+      ],
+    },
+  ],
+}
diff --git a/components/policy/OWNERS b/components/policy/OWNERS
new file mode 100644
index 0000000..dbccb7c
--- /dev/null
+++ b/components/policy/OWNERS
@@ -0,0 +1,6 @@
+mnissler@chromium.org
+pastarmovj@chromium.org
+joaodasilva@chromium.org
+bartfab@chromium.org
+atwilson@chromium.org
+pneubeck@chromium.org
diff --git a/components/policy/core/common/policy_schema.cc b/components/policy/core/common/policy_schema.cc
new file mode 100644
index 0000000..8c3145c
--- /dev/null
+++ b/components/policy/core/common/policy_schema.cc
@@ -0,0 +1,244 @@
+// Copyright 2013 The Chromium Authors. 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_schema.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "components/json_schema/json_schema_constants.h"
+#include "components/json_schema/json_schema_validator.h"
+
+namespace policy {
+
+namespace {
+
+const char kJSONSchemaVersion[] = "http://json-schema.org/draft-03/schema#";
+
+// Describes the properties of a TYPE_DICTIONARY policy schema.
+class DictionaryPolicySchema : public PolicySchema {
+ public:
+  static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema,
+                                        std::string* error);
+
+  virtual ~DictionaryPolicySchema();
+
+  virtual const PolicySchemaMap* GetProperties() const OVERRIDE;
+  virtual const PolicySchema* GetSchemaForAdditionalProperties() const OVERRIDE;
+
+ private:
+  DictionaryPolicySchema();
+
+  PolicySchemaMap properties_;
+  scoped_ptr<PolicySchema> additional_properties_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryPolicySchema);
+};
+
+// Describes the items of a TYPE_LIST policy schema.
+class ListPolicySchema : public PolicySchema {
+ public:
+  static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema,
+                                        std::string* error);
+
+  virtual ~ListPolicySchema();
+
+  virtual const PolicySchema* GetSchemaForItems() const OVERRIDE;
+
+ private:
+  ListPolicySchema();
+
+  scoped_ptr<PolicySchema> items_schema_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListPolicySchema);
+};
+
+bool SchemaTypeToValueType(const std::string& type_string,
+                           base::Value::Type* type) {
+  // Note: "any" is not an accepted type.
+  static const struct {
+    const char* schema_type;
+    base::Value::Type value_type;
+  } kSchemaToValueTypeMap[] = {
+    { json_schema_constants::kArray,        base::Value::TYPE_LIST       },
+    { json_schema_constants::kBoolean,      base::Value::TYPE_BOOLEAN    },
+    { json_schema_constants::kInteger,      base::Value::TYPE_INTEGER    },
+    { json_schema_constants::kNull,         base::Value::TYPE_NULL       },
+    { json_schema_constants::kNumber,       base::Value::TYPE_DOUBLE     },
+    { json_schema_constants::kObject,       base::Value::TYPE_DICTIONARY },
+    { json_schema_constants::kString,       base::Value::TYPE_STRING     },
+  };
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) {
+    if (kSchemaToValueTypeMap[i].schema_type == type_string) {
+      *type = kSchemaToValueTypeMap[i].value_type;
+      return true;
+    }
+  }
+  return false;
+}
+
+scoped_ptr<PolicySchema> ParseSchema(const base::DictionaryValue& schema,
+                                     std::string* error) {
+  std::string type_string;
+  if (!schema.GetString(json_schema_constants::kType, &type_string)) {
+    *error = "The schema type must be declared.";
+    return scoped_ptr<PolicySchema>();
+  }
+
+  base::Value::Type type = base::Value::TYPE_NULL;
+  if (!SchemaTypeToValueType(type_string, &type)) {
+    *error = "The \"any\" type can't be used.";
+    return scoped_ptr<PolicySchema>();
+  }
+
+  switch (type) {
+    case base::Value::TYPE_DICTIONARY:
+      return DictionaryPolicySchema::Parse(schema, error);
+    case base::Value::TYPE_LIST:
+      return ListPolicySchema::Parse(schema, error);
+    default:
+      return make_scoped_ptr(new PolicySchema(type));
+  }
+}
+
+DictionaryPolicySchema::DictionaryPolicySchema()
+    : PolicySchema(base::Value::TYPE_DICTIONARY) {}
+
+DictionaryPolicySchema::~DictionaryPolicySchema() {
+  STLDeleteValues(&properties_);
+}
+
+const PolicySchemaMap* DictionaryPolicySchema::GetProperties() const {
+  return &properties_;
+}
+
+const PolicySchema*
+    DictionaryPolicySchema::GetSchemaForAdditionalProperties() const {
+  return additional_properties_.get();
+}
+
+// static
+scoped_ptr<PolicySchema> DictionaryPolicySchema::Parse(
+    const base::DictionaryValue& schema,
+    std::string* error) {
+  scoped_ptr<DictionaryPolicySchema> dict_schema(new DictionaryPolicySchema());
+
+  const base::DictionaryValue* dict = NULL;
+  const base::DictionaryValue* properties = NULL;
+  if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) {
+    for (base::DictionaryValue::Iterator it(*properties);
+         !it.IsAtEnd(); it.Advance()) {
+      // This should have been verified by the JSONSchemaValidator.
+      CHECK(it.value().GetAsDictionary(&dict));
+      scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error);
+      if (!sub_schema)
+        return scoped_ptr<PolicySchema>();
+      dict_schema->properties_[it.key()] = sub_schema.release();
+    }
+  }
+
+  if (schema.GetDictionary(json_schema_constants::kAdditionalProperties,
+                           &dict)) {
+    scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error);
+    if (!sub_schema)
+      return scoped_ptr<PolicySchema>();
+    dict_schema->additional_properties_ = sub_schema.Pass();
+  }
+
+  return dict_schema.PassAs<PolicySchema>();
+}
+
+ListPolicySchema::ListPolicySchema()
+    : PolicySchema(base::Value::TYPE_LIST) {}
+
+ListPolicySchema::~ListPolicySchema() {}
+
+const PolicySchema* ListPolicySchema::GetSchemaForItems() const {
+  return items_schema_.get();
+}
+
+scoped_ptr<PolicySchema> ListPolicySchema::Parse(
+    const base::DictionaryValue& schema,
+    std::string* error) {
+  const base::DictionaryValue* dict = NULL;
+  if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) {
+    *error = "Arrays must declare a single schema for their items.";
+    return scoped_ptr<PolicySchema>();
+  }
+  scoped_ptr<PolicySchema> items_schema = ParseSchema(*dict, error);
+  if (!items_schema)
+    return scoped_ptr<PolicySchema>();
+
+  scoped_ptr<ListPolicySchema> list_schema(new ListPolicySchema());
+  list_schema->items_schema_ = items_schema.Pass();
+  return list_schema.PassAs<PolicySchema>();
+}
+
+}  // namespace
+
+PolicySchema::PolicySchema(base::Value::Type type)
+    : type_(type) {}
+
+PolicySchema::~PolicySchema() {}
+
+const PolicySchemaMap* PolicySchema::GetProperties() const {
+  NOTREACHED();
+  return NULL;
+}
+
+const PolicySchema* PolicySchema::GetSchemaForAdditionalProperties() const {
+  NOTREACHED();
+  return NULL;
+}
+
+const PolicySchema* PolicySchema::GetSchemaForProperty(
+    const std::string& key) const {
+  const PolicySchemaMap* properties = GetProperties();
+  PolicySchemaMap::const_iterator it = properties->find(key);
+  return it == properties->end() ? GetSchemaForAdditionalProperties()
+                                 : it->second;
+}
+
+const PolicySchema* PolicySchema::GetSchemaForItems() const {
+  NOTREACHED();
+  return NULL;
+}
+
+// static
+scoped_ptr<PolicySchema> PolicySchema::Parse(const std::string& content,
+                                             std::string* error) {
+  // Validate as a generic JSON schema.
+  scoped_ptr<base::DictionaryValue> dict =
+      JSONSchemaValidator::IsValidSchema(content, error);
+  if (!dict)
+    return scoped_ptr<PolicySchema>();
+
+  // Validate the schema version.
+  std::string string_value;
+  if (!dict->GetString(json_schema_constants::kSchema, &string_value) ||
+      string_value != kJSONSchemaVersion) {
+    *error = "Must declare JSON Schema v3 version in \"$schema\".";
+    return scoped_ptr<PolicySchema>();
+  }
+
+  // Validate the main type.
+  if (!dict->GetString(json_schema_constants::kType, &string_value) ||
+      string_value != json_schema_constants::kObject) {
+    *error =
+        "The main schema must have a type attribute with \"object\" value.";
+    return scoped_ptr<PolicySchema>();
+  }
+
+  // Checks for invalid attributes at the top-level.
+  if (dict->HasKey(json_schema_constants::kAdditionalProperties) ||
+      dict->HasKey(json_schema_constants::kPatternProperties)) {
+    *error = "\"additionalProperties\" and \"patternProperties\" are not "
+             "supported at the main schema.";
+    return scoped_ptr<PolicySchema>();
+  }
+
+  return ParseSchema(*dict, error);
+}
+
+}  // namespace policy
diff --git a/components/policy/core/common/policy_schema.h b/components/policy/core/common/policy_schema.h
new file mode 100644
index 0000000..c48ee6f
--- /dev/null
+++ b/components/policy/core/common/policy_schema.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 COMPONENTS_POLICY_CORE_COMMON_POLICY_SCHEMA_H_
+#define COMPONENTS_POLICY_CORE_COMMON_POLICY_SCHEMA_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "components/policy/policy_export.h"
+
+namespace policy {
+
+class PolicySchema;
+typedef std::map<std::string, PolicySchema*> PolicySchemaMap;
+
+// Maps known policy keys to their expected types, and recursively describes
+// the known keys within dictionary or list types.
+class POLICY_EXPORT PolicySchema {
+ public:
+
+  // Parses |schema| as a JSON v3 schema, and additionally verifies that:
+  // - the version is JSON schema v3;
+  // - the top-level entry is of type "object";
+  // - the top-level object doesn't contain "additionalProperties" nor
+  //   "patternProperties";
+  // - each "property" maps to a schema with one "type";
+  // - the type "any" is not used.
+  // If all the checks pass then the parsed PolicySchema is returned; otherwise
+  // returns NULL.
+  static scoped_ptr<PolicySchema> Parse(const std::string& schema,
+                                        std::string* error);
+
+  explicit PolicySchema(base::Value::Type type);
+  virtual ~PolicySchema();
+
+  // Returns the expected type for this policy. At the top-level PolicySchema
+  // this is always TYPE_DICTIONARY.
+  base::Value::Type type() const { return type_; }
+
+  // It is invalid to call these methods when type() is not TYPE_DICTIONARY.
+  //
+  // GetProperties() returns a map of the known property names to their schemas;
+  // the map is never NULL.
+  // GetSchemaForAdditionalProperties() returns the schema that should be used
+  // for keys not found in the map, and may be NULL.
+  // GetSchemaForProperty() is a utility method that combines both, returning
+  // the mapped schema if found in GetProperties(), otherwise returning
+  // GetSchemaForAdditionalProperties().
+  virtual const PolicySchemaMap* GetProperties() const;
+  virtual const PolicySchema* GetSchemaForAdditionalProperties() const;
+  const PolicySchema* GetSchemaForProperty(const std::string& key) const;
+
+  // It is invalid to call this method when type() is not TYPE_LIST.
+  // Returns the type of the entries of this "array", which is never NULL.
+  virtual const PolicySchema* GetSchemaForItems() const;
+
+ private:
+  const base::Value::Type type_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicySchema);
+};
+
+}  // namespace policy
+
+#endif  // COMPONENTS_POLICY_CORE_COMMON_POLICY_SCHEMA_H_
diff --git a/components/policy/core/common/policy_schema_unittest.cc b/components/policy/core/common/policy_schema_unittest.cc
new file mode 100644
index 0000000..bfbdd65
--- /dev/null
+++ b/components/policy/core/common/policy_schema_unittest.cc
@@ -0,0 +1,193 @@
+// Copyright 2013 The Chromium Authors. 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_schema.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace {
+
+#define SCHEMA_VERSION "\"$schema\":\"http://json-schema.org/draft-03/schema#\""
+#define OBJECT_TYPE "\"type\":\"object\""
+
+bool ParseFails(const std::string& content) {
+  std::string error;
+  scoped_ptr<PolicySchema> schema = PolicySchema::Parse(content, &error);
+  EXPECT_TRUE(schema || !error.empty());
+  return !schema;
+}
+
+}  // namespace
+
+TEST(PolicySchemaTest, MinimalSchema) {
+  EXPECT_FALSE(ParseFails(
+      "{"
+        SCHEMA_VERSION ","
+        OBJECT_TYPE
+      "}"));
+}
+
+TEST(PolicySchemaTest, InvalidSchemas) {
+  EXPECT_TRUE(ParseFails(""));
+  EXPECT_TRUE(ParseFails("omg"));
+  EXPECT_TRUE(ParseFails("\"omg\""));
+  EXPECT_TRUE(ParseFails("123"));
+  EXPECT_TRUE(ParseFails("[]"));
+  EXPECT_TRUE(ParseFails("null"));
+  EXPECT_TRUE(ParseFails("{}"));
+  EXPECT_TRUE(ParseFails("{" SCHEMA_VERSION "}"));
+  EXPECT_TRUE(ParseFails("{" OBJECT_TYPE "}"));
+
+  EXPECT_TRUE(ParseFails(
+      "{"
+        SCHEMA_VERSION ","
+        OBJECT_TYPE ","
+        "\"additionalProperties\": { \"type\":\"object\" }"
+      "}"));
+
+  EXPECT_TRUE(ParseFails(
+      "{"
+        SCHEMA_VERSION ","
+        OBJECT_TYPE ","
+        "\"patternProperties\": { \"a+b*\": { \"type\": \"object\" } }"
+      "}"));
+
+  EXPECT_TRUE(ParseFails(
+      "{"
+        SCHEMA_VERSION ","
+        OBJECT_TYPE ","
+        "\"properties\": { \"Policy\": { \"type\": \"bogus\" } }"
+      "}"));
+
+  EXPECT_TRUE(ParseFails(
+      "{"
+        SCHEMA_VERSION ","
+        OBJECT_TYPE ","
+        "\"properties\": { \"Policy\": { \"type\": [\"string\", \"number\"] } }"
+      "}"));
+
+  EXPECT_TRUE(ParseFails(
+      "{"
+        SCHEMA_VERSION ","
+        OBJECT_TYPE ","
+        "\"properties\": { \"Policy\": { \"type\": \"any\" } }"
+      "}"));
+}
+
+TEST(PolicySchemaTest, ValidSchema) {
+  std::string error;
+  scoped_ptr<PolicySchema> schema = PolicySchema::Parse(
+      "{"
+        SCHEMA_VERSION ","
+        OBJECT_TYPE ","
+        "\"properties\": {"
+        "  \"Boolean\": { \"type\": \"boolean\" },"
+        "  \"Integer\": { \"type\": \"integer\" },"
+        "  \"Null\": { \"type\": \"null\" },"
+        "  \"Number\": { \"type\": \"number\" },"
+        "  \"String\": { \"type\": \"string\" },"
+        "  \"Array\": {"
+        "    \"type\": \"array\","
+        "    \"items\": { \"type\": \"string\" }"
+        "  },"
+        "  \"ArrayOfObjects\": {"
+        "    \"type\": \"array\","
+        "    \"items\": {"
+        "      \"type\": \"object\","
+        "      \"properties\": {"
+        "        \"one\": { \"type\": \"string\" },"
+        "        \"two\": { \"type\": \"integer\" }"
+        "      }"
+        "    }"
+        "  },"
+        "  \"ArrayOfArray\": {"
+        "    \"type\": \"array\","
+        "    \"items\": {"
+        "      \"type\": \"array\","
+        "      \"items\": { \"type\": \"string\" }"
+        "    }"
+        "  },"
+        "  \"Object\": {"
+        "    \"type\": \"object\","
+        "    \"properties\": {"
+        "      \"one\": { \"type\": \"boolean\" },"
+        "      \"two\": { \"type\": \"integer\" }"
+        "    },"
+        "    \"additionalProperties\": { \"type\": \"string\" }"
+        "  }"
+        "}"
+      "}", &error);
+  ASSERT_TRUE(schema) << error;
+
+  ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema->type());
+  EXPECT_FALSE(schema->GetSchemaForProperty("invalid"));
+
+  const PolicySchema* sub = schema->GetSchemaForProperty("Boolean");
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_BOOLEAN, sub->type());
+
+  sub = schema->GetSchemaForProperty("Integer");
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, sub->type());
+
+  sub = schema->GetSchemaForProperty("Null");
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_NULL, sub->type());
+
+  sub = schema->GetSchemaForProperty("Number");
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_DOUBLE, sub->type());
+  sub = schema->GetSchemaForProperty("String");
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_STRING, sub->type());
+
+  sub = schema->GetSchemaForProperty("Array");
+  ASSERT_TRUE(sub);
+  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
+  sub = sub->GetSchemaForItems();
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_STRING, sub->type());
+
+  sub = schema->GetSchemaForProperty("ArrayOfObjects");
+  ASSERT_TRUE(sub);
+  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
+  sub = sub->GetSchemaForItems();
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_DICTIONARY, sub->type());
+  const PolicySchema* subsub = sub->GetSchemaForProperty("one");
+  ASSERT_TRUE(subsub);
+  EXPECT_EQ(base::Value::TYPE_STRING, subsub->type());
+  subsub = sub->GetSchemaForProperty("two");
+  ASSERT_TRUE(subsub);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, subsub->type());
+  subsub = sub->GetSchemaForProperty("invalid");
+  EXPECT_FALSE(subsub);
+
+  sub = schema->GetSchemaForProperty("ArrayOfArray");
+  ASSERT_TRUE(sub);
+  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
+  sub = sub->GetSchemaForItems();
+  ASSERT_TRUE(sub);
+  ASSERT_EQ(base::Value::TYPE_LIST, sub->type());
+  sub = sub->GetSchemaForItems();
+  ASSERT_TRUE(sub);
+  EXPECT_EQ(base::Value::TYPE_STRING, sub->type());
+
+  sub = schema->GetSchemaForProperty("Object");
+  ASSERT_TRUE(sub);
+  ASSERT_EQ(base::Value::TYPE_DICTIONARY, sub->type());
+  subsub = sub->GetSchemaForProperty("one");
+  ASSERT_TRUE(subsub);
+  EXPECT_EQ(base::Value::TYPE_BOOLEAN, subsub->type());
+  subsub = sub->GetSchemaForProperty("two");
+  ASSERT_TRUE(subsub);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, subsub->type());
+  subsub = sub->GetSchemaForProperty("undeclared");
+  ASSERT_TRUE(subsub);
+  EXPECT_EQ(base::Value::TYPE_STRING, subsub->type());
+}
+
+}  // namespace policy
diff --git a/components/policy/policy_export.h b/components/policy/policy_export.h
new file mode 100644
index 0000000..47376ac
--- /dev/null
+++ b/components/policy/policy_export.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 COMPONENTS_POLICY_POLICY_EXPORT_H_
+#define COMPONENTS_POLICY_POLICY_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(POLICY_COMPONENT_IMPLEMENTATION)
+#define POLICY_EXPORT __declspec(dllexport)
+#else
+#define POLICY_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_PREFS_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(POLICY_COMPONENT_IMPLEMENTATION)
+#define POLICY_EXPORT __attribute__((visibility("default")))
+#else
+#define POLICY_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define POLICY_EXPORT
+#endif
+
+#endif  // COMPONENTS_POLICY_POLICY_EXPORT_H_
diff --git a/components/policy/stub_to_remove.cc b/components/policy/stub_to_remove.cc
new file mode 100644
index 0000000..6e352ac
--- /dev/null
+++ b/components/policy/stub_to_remove.cc
@@ -0,0 +1,6 @@
+// Copyright 2013 The Chromium 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/array_tuple_schema.json b/components/test/data/json_schema/array_tuple_schema.json
new file mode 100644
index 0000000..a9bea68
--- /dev/null
+++ b/components/test/data/json_schema/array_tuple_schema.json
@@ -0,0 +1,11 @@
+{
+  "type": "array",
+  "items": [
+    {
+      "type": "string"
+    },
+    {
+      "type": "integer"
+    }
+  ]
+}
diff --git a/components/test/data/json_schema/choices_schema.json b/components/test/data/json_schema/choices_schema.json
new file mode 100644
index 0000000..bd0f1a5
--- /dev/null
+++ b/components/test/data/json_schema/choices_schema.json
@@ -0,0 +1,7 @@
+{
+  "choices": [
+    { "type": "null" },
+    { "type": "integer", "minimum": 42, "maximum": 43 },
+    { "type": "object", "properties": { "foo": { "type": "string" } } }
+  ]
+}
diff --git a/components/test/data/json_schema/complex_instance.json b/components/test/data/json_schema/complex_instance.json
new file mode 100644
index 0000000..1fb193b
--- /dev/null
+++ b/components/test/data/json_schema/complex_instance.json
@@ -0,0 +1,9 @@
+[
+  {
+    "id": 42,
+    "url": "google.com",
+    "index": 2,
+    "selected": true
+  },
+  88.8
+]
diff --git a/components/test/data/json_schema/complex_schema.json b/components/test/data/json_schema/complex_schema.json
new file mode 100644
index 0000000..bf0d6b8
--- /dev/null
+++ b/components/test/data/json_schema/complex_schema.json
@@ -0,0 +1,33 @@
+{
+  "type": "array",
+  "items": [
+    {
+      "type": "object",
+      "properties": {
+        "id": {
+          "type": "integer",
+          "minimum": 1
+        },
+        "url": {
+          "type": "string",
+          "maxLength": 10,
+          "optional": true
+        },
+        "index": {
+          "type": "integer",
+          "minimum": 0,
+          "optional": true
+        },
+        "selected": {
+          "type": "boolean",
+          "optional": true
+        }
+      }
+    },
+    {
+      "type": "number",
+      "optional": true
+    }
+  ]
+}
+
diff --git a/components/test/data/json_schema/enum_schema.json b/components/test/data/json_schema/enum_schema.json
new file mode 100644
index 0000000..ae0c12a
--- /dev/null
+++ b/components/test/data/json_schema/enum_schema.json
@@ -0,0 +1,3 @@
+{
+  "enum": ["foo", 42, false]
+}
diff --git a/components/test/data/json_schema/reference_types.json b/components/test/data/json_schema/reference_types.json
new file mode 100644
index 0000000..8f77334
--- /dev/null
+++ b/components/test/data/json_schema/reference_types.json
@@ -0,0 +1,12 @@
+[
+  {
+    "id": "MinLengthString",
+    "type": "string",
+    "minLength": 2
+  },
+  {
+    "id": "Max10Int",
+    "type": "integer",
+    "maximum": 10
+  }
+]
diff --git a/components/test/data/web_database/version_52.sql b/components/test/data/web_database/version_52.sql
new file mode 100644
index 0000000..ec362a6
--- /dev/null
+++ b/components/test/data/web_database/version_52.sql
@@ -0,0 +1,33 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+INSERT INTO "meta" VALUES('version','52');
+INSERT INTO "meta" VALUES('last_compatible_version','48');
+INSERT INTO "meta" VALUES('Default Search Provider ID','2');
+INSERT INTO "meta" VALUES('Builtin Keyword Version','62');
+CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type));
+CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern));
+CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR);
+INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}',1,'',0,0,'UTF-8',1,'{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&q={searchTerms}&{google:cursorPosition}{google:zeroPrefixUrl}{google:pageClassification}sugkey={google:suggestAPIKeyParameter}',1,0,'{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:instantEnabledParameter}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}',0,'2BB4ECA1-7D0F-2FB9-45B0-AD87B8298C9D','["{google:baseURL}#q={searchTerms}","{google:baseURL}search#q={searchTerms}","{google:baseURL}webhp#q={searchTerms}"]','espv','{google:baseURL}searchbyimage/upload','','','','encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource}');
+INSERT INTO "keywords" VALUES(3,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,'',0,0,'UTF-8',1,'http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,'',0,'A0226B1A-8662-A160-C4D4-078608DBD17E','[]','','','','','','');
+INSERT INTO "keywords" VALUES(4,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,'',0,0,'UTF-8',1,'http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,'',0,'531278E0-9380-7556-D9A0-9F85AA1DCF06','[]','','','','','','');
+INSERT INTO "keywords" VALUES(5,'AOL','aol.com','http://search.aol.com/favicon.ico','http://search.aol.com/aol/search?query={searchTerms}',1,'',0,0,'UTF-8',1,'http://autocomplete.search.aol.com/autocomplete/get?output=json&it=&q={searchTerms}',35,0,'',0,'680838DC-A89F-7598-901A-C6B849F94F67','[]','','','','','','');
+INSERT INTO "keywords" VALUES(6,'Ask','ask.com','http://sp.ask.com/sh/i/a16/favicon/favicon.ico','http://www.ask.com/web?q={searchTerms}',1,'',0,0,'UTF-8',1,'http://ss.ask.com/query?q={searchTerms}&li=ff',4,0,'',0,'25AC092A-10E6-EA19-11CE-55382548F3DC','[]','','','','','','');
+CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
+CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
+CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
+CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
+CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '');
+CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
+CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '');
+CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
+CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
+CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
+CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
+CREATE INDEX web_intents_index ON web_intents (action);
+CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
+CREATE INDEX web_apps_url_index ON web_apps (url);
+CREATE INDEX autofill_name ON autofill (name);
+CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
+CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
+COMMIT;
diff --git a/components/tracing_untrusted.gyp b/components/tracing_untrusted.gyp
index f2215de..1991ec2 100644
--- a/components/tracing_untrusted.gyp
+++ b/components/tracing_untrusted.gyp
@@ -26,7 +26,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libtracing_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'sources': [
diff --git a/components/web_modal/OWNERS b/components/web_modal/OWNERS
new file mode 100644
index 0000000..ddd924d
--- /dev/null
+++ b/components/web_modal/OWNERS
@@ -0,0 +1,2 @@
+wittman@chromium.org
+ben@chromium.org
diff --git a/components/web_modal/native_web_contents_modal_dialog_manager.h b/components/web_modal/native_web_contents_modal_dialog_manager.h
index 7145a08..4df3680 100644
--- a/components/web_modal/native_web_contents_modal_dialog_manager.h
+++ b/components/web_modal/native_web_contents_modal_dialog_manager.h
@@ -13,6 +13,8 @@
 
 namespace web_modal {
 
+class WebContentsModalDialogHost;
+
 // Interface from NativeWebContentsModalDialogManager to
 // WebContentsModalDialogManager.
 class NativeWebContentsModalDialogManagerDelegate {
@@ -54,6 +56,9 @@
   // Runs a pulse animation for the web contents modal dialog.
   virtual void PulseDialog(NativeWebContentsModalDialog dialog) = 0;
 
+  // Called when the host view for the dialog has changed.
+  virtual void HostChanged(WebContentsModalDialogHost* new_host) = 0;
+
  protected:
   NativeWebContentsModalDialogManager() {}
 
diff --git a/components/web_modal/web_contents_modal_dialog_host.h b/components/web_modal/web_contents_modal_dialog_host.h
index 499925c..b14c6e8 100644
--- a/components/web_modal/web_contents_modal_dialog_host.h
+++ b/components/web_modal/web_contents_modal_dialog_host.h
@@ -18,6 +18,7 @@
   virtual ~WebContentsModalDialogHostObserver();
 
   virtual void OnPositionRequiresUpdate() = 0;
+  virtual void OnHostDestroying() = 0;
 
  protected:
   WebContentsModalDialogHostObserver();
diff --git a/components/web_modal/web_contents_modal_dialog_manager.cc b/components/web_modal/web_contents_modal_dialog_manager.cc
index 0e07f8d..f30b6a0 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.cc
+++ b/components/web_modal/web_contents_modal_dialog_manager.cc
@@ -25,6 +25,13 @@
   DCHECK(child_dialogs_.empty());
 }
 
+void WebContentsModalDialogManager::SetDelegate(
+    WebContentsModalDialogManagerDelegate* d) {
+  delegate_ = d;
+  // Delegate can be NULL on Views/Win32 during tab drag.
+  native_manager_->HostChanged(d ? d->GetWebContentsModalDialogHost() : NULL);
+}
+
 void WebContentsModalDialogManager::ShowDialog(
     NativeWebContentsModalDialog dialog) {
   child_dialogs_.push_back(dialog);
diff --git a/components/web_modal/web_contents_modal_dialog_manager.h b/components/web_modal/web_contents_modal_dialog_manager.h
index e2548c0..09115f0 100644
--- a/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/components/web_modal/web_contents_modal_dialog_manager.h
@@ -29,7 +29,7 @@
   virtual ~WebContentsModalDialogManager();
 
   WebContentsModalDialogManagerDelegate* delegate() const { return delegate_; }
-  void set_delegate(WebContentsModalDialogManagerDelegate* d) { delegate_ = d; }
+  void SetDelegate(WebContentsModalDialogManagerDelegate* d);
 
   static NativeWebContentsModalDialogManager* CreateNativeManager(
       NativeWebContentsModalDialogManagerDelegate* native_delegate);
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 1268896..42c46bc 100644
--- a/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
+++ b/components/web_modal/web_contents_modal_dialog_manager_unittest.cc
@@ -4,12 +4,9 @@
 
 #include "components/web_modal/native_web_contents_modal_dialog_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_renderer_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
-
 namespace web_modal {
 
 class WebContentsModalDialogManagerTest
@@ -24,9 +21,9 @@
 class NativeWebContentsModalDialogManagerCloseTest
     : public NativeWebContentsModalDialogManager {
  public:
-  NativeWebContentsModalDialogManagerCloseTest(
+  explicit NativeWebContentsModalDialogManagerCloseTest(
       NativeWebContentsModalDialogManagerDelegate* delegate)
-      : delegate_(delegate) {}
+      : close_count_(0), delegate_(delegate) {}
   virtual void ManageDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
   }
   virtual void ShowDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
@@ -35,19 +32,26 @@
   }
   virtual void CloseDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
     delegate_->WillClose(dialog);
-    close_count++;
+    ++close_count_;
   }
   virtual void FocusDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
   }
   virtual void PulseDialog(NativeWebContentsModalDialog dialog) OVERRIDE {
   }
+  virtual void HostChanged(WebContentsModalDialogHost* new_host) OVERRIDE {
+  }
 
-  int close_count;
+  int close_count() const { return close_count_; }
+
+ private:
+  int close_count_;
   NativeWebContentsModalDialogManagerDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerCloseTest);
 };
 
-NativeWebContentsModalDialogManager* WebContentsModalDialogManager::
-CreateNativeManager(
+NativeWebContentsModalDialogManager*
+WebContentsModalDialogManager::CreateNativeManager(
     NativeWebContentsModalDialogManagerDelegate* native_delegate) {
   return new NativeWebContentsModalDialogManagerCloseTest(native_delegate);
 }
@@ -61,21 +65,22 @@
   NativeWebContentsModalDialogManagerCloseTest* native_manager =
       new NativeWebContentsModalDialogManagerCloseTest(
           web_contents_modal_dialog_manager);
-  native_manager->close_count = 0;
 
+  // |web_contents_modal_dialog_manager| owns |native_manager| as a result.
   test_api.ResetNativeManager(native_manager);
 
   const int kWindowCount = 4;
-  for (int i = 0; i < kWindowCount; i++)
+  for (int i = 0; i < kWindowCount; i++) {
     // WebContentsModalDialogManager treats the NativeWebContentsModalDialog as
     // an opaque type, so creating fake NativeWebContentsModalDialogs using
     // reinterpret_cast is valid.
     web_contents_modal_dialog_manager->ShowDialog(
         reinterpret_cast<NativeWebContentsModalDialog>(i));
-  EXPECT_EQ(native_manager->close_count, 0);
+  }
+  EXPECT_EQ(0, native_manager->close_count());
 
   test_api.CloseAllDialogs();
-  EXPECT_EQ(native_manager->close_count, kWindowCount);
+  EXPECT_EQ(kWindowCount, native_manager->close_count());
 }
 
 }  // namespace web_modal
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index e4e44ef..161fb80 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -14,7 +14,7 @@
 // corresponding changes must happen in the unit tests, and new migration test
 // added.  See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
 // static
-const int WebDatabase::kCurrentVersionNumber = 52;
+const int WebDatabase::kCurrentVersionNumber = 53;
 
 namespace {
 
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc
index 5e6ef6e..770e153 100644
--- a/components/webdata/common/web_database_migration_unittest.cc
+++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -247,7 +247,7 @@
   DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
 };
 
-const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 52;
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 53;
 
 void WebDatabaseMigrationTest::LoadDatabase(
     const base::FilePath::StringType& file) {
@@ -2029,8 +2029,9 @@
 }
 
 // Tests that the columns |image_url|, |search_url_post_params|,
-// |suggest_url_post_params|, |instant_url_post_params|, |image_url_post_params|
-// are added to the keyword table schema for a version 52 database.
+// |suggest_url_post_params|, |instant_url_post_params|, and
+// |image_url_post_params| are added to the keyword table schema for a version
+// 50 database.
 TEST_F(WebDatabaseMigrationTest, MigrateVersion50ToCurrent) {
   ASSERT_NO_FATAL_FAILURE(
       LoadDatabase(FILE_PATH_LITERAL("version_50.sql")));
@@ -2080,3 +2081,39 @@
                                            "image_url_post_params"));
   }
 }
+
+// Tests that the column |new_tab_url| is added to the keyword table schema for
+// a version 52 database.
+TEST_F(WebDatabaseMigrationTest, MigrateVersion52ToCurrent) {
+  ASSERT_NO_FATAL_FAILURE(
+      LoadDatabase(FILE_PATH_LITERAL("version_52.sql")));
+
+  // Verify pre-conditions.  These are expectations for version 52 of the
+  // database.
+  {
+    sql::Connection connection;
+    ASSERT_TRUE(connection.Open(GetDatabasePath()));
+    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+    sql::MetaTable meta_table;
+    ASSERT_TRUE(meta_table.Init(&connection, 52, 52));
+
+    ASSERT_FALSE(connection.DoesColumnExist("keywords", "new_tab_url"));
+  }
+
+  DoMigration();
+
+  // Verify post-conditions.  These are expectations for current version of the
+  // database.
+  {
+    sql::Connection connection;
+    ASSERT_TRUE(connection.Open(GetDatabasePath()));
+    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
+
+    // Check version.
+    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
+
+    // New columns should have been created.
+    EXPECT_TRUE(connection.DoesColumnExist("keywords", "new_tab_url"));
+  }
+}
diff --git a/content/DEPS b/content/DEPS
index 11aa6bd..389f18f 100644
--- a/content/DEPS
+++ b/content/DEPS
@@ -33,6 +33,7 @@
   "+grit/ui_strings.h",
   "+grit/webkit_resources.h",
   "+grit/webkit_strings.h",
+  "+grit/webui_resources.h",
   "+grit/webui_resources_map.h",
 
   "+dbus",
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 6554d57..07e846f 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -26,17 +26,23 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "content/browser/browser_main.h"
+#include "content/browser/gpu/gpu_process_host.h"
 #include "content/common/set_process_title.h"
 #include "content/common/url_schemes.h"
+#include "content/gpu/gpu_main_thread.h"
 #include "content/public/app/content_main_delegate.h"
 #include "content/public/app/startup_helper_win.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/utility_process_host.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
 #include "content/public/common/sandbox_init.h"
+#include "content/renderer/renderer_main_thread.h"
+#include "content/utility/utility_main_thread.h"
 #include "crypto/nss_util.h"
 #include "ipc/ipc_switches.h"
 #include "media/base/media.h"
@@ -424,6 +430,13 @@
 #endif  // !CHROME_MULTIPLE_DLL_BROWSER
   };
 
+#if !defined(CHROME_MULTIPLE_DLL_BROWSER)
+  UtilityProcessHost::RegisterUtilityMainThreadFactory(CreateUtilityMainThread);
+  RenderProcessHost::RegisterRendererMainThreadFactory(
+      CreateRendererMainThread);
+  GpuProcessHost::RegisterGpuMainThreadFactory(CreateGpuMainThread);
+#endif
+
   for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {
     if (process_type == kMainFunctions[i].name) {
       if (delegate) {
@@ -703,7 +716,7 @@
     RegisterPathProvider();
     RegisterContentSchemes(true);
 
-    CHECK(icu_util::Initialize());
+    CHECK(base::i18n::InitializeICU());
 
     InitializeStatsTable(command_line);
 
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 39be989..3a85518 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -10,10 +10,6 @@
   "+ui/webui",
   "+win8/util",
 
-  # For single-process mode.
-  "+content/child/child_process.h",
-  "+content/utility/utility_thread_impl.h",
-
   # TODO(joi): This was misplaced; need to move it somewhere else,
   # since //content shouldn't depend on //components, which is a layer
   # above.
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 0be9ba5..a631c69 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -17,7 +17,7 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/accessibility_browser_test_utils.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index ae7efe2..37217c7 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -7,6 +7,7 @@
 #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 "content/browser/accessibility/browser_accessibility_manager.h"
 #include "content/common/accessibility_messages.h"
 
@@ -64,22 +65,20 @@
 
 void BrowserAccessibility::InitializeData(const AccessibilityNodeData& src) {
   DCHECK_EQ(renderer_id_, src.id);
-  name_ = src.name;
-  value_ = src.value;
   role_ = src.role;
   state_ = src.state;
   string_attributes_ = src.string_attributes;
   int_attributes_ = src.int_attributes;
   float_attributes_ = src.float_attributes;
   bool_attributes_ = src.bool_attributes;
+  intlist_attributes_ = src.intlist_attributes;
   html_attributes_ = src.html_attributes;
   location_ = src.location;
-  indirect_child_ids_ = src.indirect_child_ids;
-  line_breaks_ = src.line_breaks;
-  cell_ids_ = src.cell_ids;
-  unique_cell_ids_ = src.unique_cell_ids;
   instance_active_ = true;
 
+  GetStringAttribute(AccessibilityNodeData::ATTR_NAME, &name_);
+  GetStringAttribute(AccessibilityNodeData::ATTR_VALUE, &value_);
+
   PreInitialize();
 }
 
@@ -223,55 +222,197 @@
   delete this;
 }
 
-bool BrowserAccessibility::GetBoolAttribute(
-    BoolAttribute attribute, bool* value) const {
-  BoolAttrMap::const_iterator iter = bool_attributes_.find(attribute);
-  if (iter != bool_attributes_.end()) {
-    *value = iter->second;
-    return true;
+bool BrowserAccessibility::HasBoolAttribute(BoolAttribute attribute) const {
+  for (size_t i = 0; i < bool_attributes_.size(); ++i) {
+    if (bool_attributes_[i].first == attribute)
+      return true;
   }
 
   return false;
 }
 
+
+bool BrowserAccessibility::GetBoolAttribute(BoolAttribute attribute) const {
+  for (size_t i = 0; i < bool_attributes_.size(); ++i) {
+    if (bool_attributes_[i].first == attribute)
+      return bool_attributes_[i].second;
+  }
+
+  return false;
+}
+
+bool BrowserAccessibility::GetBoolAttribute(
+    BoolAttribute attribute, bool* value) const {
+  for (size_t i = 0; i < bool_attributes_.size(); ++i) {
+    if (bool_attributes_[i].first == attribute) {
+      *value = bool_attributes_[i].second;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool BrowserAccessibility::HasFloatAttribute(FloatAttribute attribute) const {
+  for (size_t i = 0; i < float_attributes_.size(); ++i) {
+    if (float_attributes_[i].first == attribute)
+      return true;
+  }
+
+  return false;
+}
+
+float BrowserAccessibility::GetFloatAttribute(FloatAttribute attribute) const {
+  for (size_t i = 0; i < float_attributes_.size(); ++i) {
+    if (float_attributes_[i].first == attribute)
+      return float_attributes_[i].second;
+  }
+
+  return 0.0;
+}
+
 bool BrowserAccessibility::GetFloatAttribute(
     FloatAttribute attribute, float* value) const {
-  FloatAttrMap::const_iterator iter = float_attributes_.find(attribute);
-  if (iter != float_attributes_.end()) {
-    *value = iter->second;
-    return true;
+  for (size_t i = 0; i < float_attributes_.size(); ++i) {
+    if (float_attributes_[i].first == attribute) {
+      *value = float_attributes_[i].second;
+      return true;
+    }
   }
 
   return false;
 }
 
+bool BrowserAccessibility::HasIntAttribute(IntAttribute attribute) const {
+  for (size_t i = 0; i < int_attributes_.size(); ++i) {
+    if (int_attributes_[i].first == attribute)
+      return true;
+  }
+
+  return false;
+}
+
+int BrowserAccessibility::GetIntAttribute(IntAttribute attribute) const {
+  for (size_t i = 0; i < int_attributes_.size(); ++i) {
+    if (int_attributes_[i].first == attribute)
+      return int_attributes_[i].second;
+  }
+
+  return 0;
+}
+
 bool BrowserAccessibility::GetIntAttribute(
     IntAttribute attribute, int* value) const {
-  IntAttrMap::const_iterator iter = int_attributes_.find(attribute);
-  if (iter != int_attributes_.end()) {
-    *value = iter->second;
-    return true;
+  for (size_t i = 0; i < int_attributes_.size(); ++i) {
+    if (int_attributes_[i].first == attribute) {
+      *value = int_attributes_[i].second;
+      return true;
+    }
   }
 
   return false;
 }
 
+bool BrowserAccessibility::HasStringAttribute(StringAttribute attribute) const {
+  for (size_t i = 0; i < string_attributes_.size(); ++i) {
+    if (string_attributes_[i].first == attribute)
+      return true;
+  }
+
+  return false;
+}
+
+const std::string& BrowserAccessibility::GetStringAttribute(
+    StringAttribute attribute) const {
+  CR_DEFINE_STATIC_LOCAL(std::string, empty_string, ());
+  for (size_t i = 0; i < string_attributes_.size(); ++i) {
+    if (string_attributes_[i].first == attribute)
+      return string_attributes_[i].second;
+  }
+
+  return empty_string;
+}
+
 bool BrowserAccessibility::GetStringAttribute(
+    StringAttribute attribute, std::string* value) const {
+  for (size_t i = 0; i < string_attributes_.size(); ++i) {
+    if (string_attributes_[i].first == attribute) {
+      *value = string_attributes_[i].second;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+string16 BrowserAccessibility::GetString16Attribute(
+    StringAttribute attribute) const {
+  std::string value_utf8;
+  if (!GetStringAttribute(attribute, &value_utf8))
+    return string16();
+  return UTF8ToUTF16(value_utf8);
+}
+
+bool BrowserAccessibility::GetString16Attribute(
     StringAttribute attribute,
     string16* value) const {
-  StringAttrMap::const_iterator iter = string_attributes_.find(attribute);
-  if (iter != string_attributes_.end()) {
-    *value = iter->second;
-    return true;
+  std::string value_utf8;
+  if (!GetStringAttribute(attribute, &value_utf8))
+    return false;
+  *value = UTF8ToUTF16(value_utf8);
+  return true;
+}
+
+void BrowserAccessibility::SetStringAttribute(
+    StringAttribute attribute, const std::string& value) {
+  for (size_t i = 0; i < string_attributes_.size(); ++i) {
+    if (string_attributes_[i].first == attribute) {
+      string_attributes_[i].second = value;
+      return;
+    }
+  }
+  if (!value.empty())
+    string_attributes_.push_back(std::make_pair(attribute, value));
+}
+
+bool BrowserAccessibility::HasIntListAttribute(
+    AccessibilityNodeData::IntListAttribute attribute) const {
+  for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
+    if (intlist_attributes_[i].first == attribute)
+      return true;
+  }
+
+  return false;
+}
+
+const std::vector<int32>& BrowserAccessibility::GetIntListAttribute(
+    AccessibilityNodeData::IntListAttribute attribute) const {
+  CR_DEFINE_STATIC_LOCAL(std::vector<int32>, empty_vector, ());
+  for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
+    if (intlist_attributes_[i].first == attribute)
+      return intlist_attributes_[i].second;
+  }
+
+  return empty_vector;
+}
+
+bool BrowserAccessibility::GetIntListAttribute(
+    AccessibilityNodeData::IntListAttribute attribute,
+    std::vector<int32>* value) const {
+  for (size_t i = 0; i < intlist_attributes_.size(); ++i) {
+    if (intlist_attributes_[i].first == attribute) {
+      *value = intlist_attributes_[i].second;
+      return true;
+    }
   }
 
   return false;
 }
 
 bool BrowserAccessibility::GetHtmlAttribute(
-    const char* html_attr, string16* value) const {
+    const char* html_attr, std::string* value) const {
   for (size_t i = 0; i < html_attributes_.size(); i++) {
-    const string16& attr = html_attributes_[i].first;
+    const std::string& attr = html_attributes_[i].first;
     if (LowerCaseEqualsASCII(attr, html_attr)) {
       *value = html_attributes_[i].second;
       return true;
@@ -281,6 +422,15 @@
   return false;
 }
 
+bool BrowserAccessibility::GetHtmlAttribute(
+    const char* html_attr, string16* value) const {
+  std::string value_utf8;
+  if (!GetHtmlAttribute(html_attr, &value_utf8))
+    return false;
+  *value = UTF8ToUTF16(value_utf8);
+  return true;
+}
+
 bool BrowserAccessibility::GetAriaTristate(
     const char* html_attr,
     bool* is_defined,
@@ -327,12 +477,12 @@
           role_ == AccessibilityNodeData::ROLE_TEXTAREA);
 }
 
-string16 BrowserAccessibility::GetTextRecursive() const {
+std::string BrowserAccessibility::GetTextRecursive() const {
   if (!name_.empty()) {
     return name_;
   }
 
-  string16 result;
+  std::string result;
   for (size_t i = 0; i < children_.size(); ++i)
     result += children_[i]->GetTextRecursive();
   return result;
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index 8fda68f..33eb60d 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/strings/string16.h"
 #include "build/build_config.h"
 #include "content/common/accessibility_node_data.h"
 #include "content/common/content_export.h"
@@ -26,12 +27,6 @@
 class BrowserAccessibilityGtk;
 #endif
 
-typedef std::map<AccessibilityNodeData::BoolAttribute, bool> BoolAttrMap;
-typedef std::map<AccessibilityNodeData::FloatAttribute, float> FloatAttrMap;
-typedef std::map<AccessibilityNodeData::IntAttribute, int> IntAttrMap;
-typedef std::map<AccessibilityNodeData::StringAttribute, string16>
-    StringAttrMap;
-
 ////////////////////////////////////////////////////////////////////////////////
 //
 // BrowserAccessibility
@@ -136,49 +131,21 @@
   // Accessors
   //
 
-  const BoolAttrMap& bool_attributes() const {
-    return bool_attributes_;
-  }
-
-  const FloatAttrMap& float_attributes() const {
-    return float_attributes_;
-  }
-
-  const IntAttrMap& int_attributes() const {
-    return int_attributes_;
-  }
-
-  const StringAttrMap& string_attributes() const {
-    return string_attributes_;
-  }
-
   const std::vector<BrowserAccessibility*>& children() const {
     return children_;
   }
-  const std::vector<std::pair<string16, string16> >& html_attributes() const {
+  const std::vector<std::pair<std::string, std::string> >&
+  html_attributes() const {
     return html_attributes_;
   }
   int32 index_in_parent() const { return index_in_parent_; }
-  const std::vector<int32>& indirect_child_ids() const {
-    return indirect_child_ids_;
-  }
-  const std::vector<int32>& line_breaks() const {
-    return line_breaks_;
-  }
-  const std::vector<int32>& cell_ids() const {
-    return cell_ids_;
-  }
-  const std::vector<int32>& unique_cell_ids() const {
-    return unique_cell_ids_;
-  }
   gfx::Rect location() const { return location_; }
   BrowserAccessibilityManager* manager() const { return manager_; }
-  const string16& name() const { return name_; }
+  const std::string& name() const { return name_; }
   int32 renderer_id() const { return renderer_id_; }
   int32 role() const { return role_; }
-  const string16& role_name() const { return role_name_; }
   int32 state() const { return state_; }
-  const string16& value() const { return value_; }
+  const std::string& value() const { return value_; }
   bool instance_active() const { return instance_active_; }
 
 #if defined(OS_MACOSX) && __OBJC__
@@ -189,29 +156,63 @@
   BrowserAccessibilityGtk* ToBrowserAccessibilityGtk();
 #endif
 
-  // Retrieve the value of a bool attribute from the bool attribute
-  // map and returns true if found.
-  bool GetBoolAttribute(
-      AccessibilityNodeData::BoolAttribute attr, bool* value) const;
+  // Accessing accessibility attributes:
+  //
+  // There are dozens of possible attributes for an accessibility node,
+  // but only a few tend to apply to any one object, so we store them
+  // in sparse arrays of <attribute id, attribute value> pairs, organized
+  // by type (bool, int, float, string, int list).
+  //
+  // There are three accessors for each type of attribute: one that returns
+  // true if the attribute is present and false if not, one that takes a
+  // pointer argument and returns true if the attribute is present (if you
+  // need to distinguish between the default value and a missing attribute),
+  // and another that returns the default value for that type if the
+  // attribute is not present. In addition, strings can be returned as
+  // either std::string or string16, for convenience.
 
-  // Retrieve the value of a float attribute from the float attribute
-  // map and returns true if found.
+  bool HasBoolAttribute(AccessibilityNodeData::BoolAttribute attr) const;
+  bool GetBoolAttribute(AccessibilityNodeData::BoolAttribute attr) const;
+  bool GetBoolAttribute(AccessibilityNodeData::BoolAttribute attr,
+                        bool* value) const;
+
+  bool HasFloatAttribute(AccessibilityNodeData::FloatAttribute attr) const;
+  float GetFloatAttribute(AccessibilityNodeData::FloatAttribute attr) const;
   bool GetFloatAttribute(AccessibilityNodeData::FloatAttribute attr,
                          float* value) const;
 
-  // Retrieve the value of an integer attribute from the integer attribute
-  // map and returns true if found.
+  bool HasIntAttribute(AccessibilityNodeData::IntAttribute attribute) const;
+  int GetIntAttribute(AccessibilityNodeData::IntAttribute attribute) const;
   bool GetIntAttribute(AccessibilityNodeData::IntAttribute attribute,
                        int* value) const;
 
-  // Retrieve the value of a string attribute from the attribute map and
-  // returns true if found.
-  bool GetStringAttribute(
-      AccessibilityNodeData::StringAttribute attribute, string16* value) const;
+  bool HasStringAttribute(
+      AccessibilityNodeData::StringAttribute attribute) const;
+  const std::string& GetStringAttribute(
+      AccessibilityNodeData::StringAttribute attribute) const;
+  bool GetStringAttribute(AccessibilityNodeData::StringAttribute attribute,
+                          std::string* value) const;
+
+  bool GetString16Attribute(AccessibilityNodeData::StringAttribute attribute,
+                            string16* value) const;
+  string16 GetString16Attribute(
+      AccessibilityNodeData::StringAttribute attribute) const;
+
+  bool HasIntListAttribute(
+      AccessibilityNodeData::IntListAttribute attribute) const;
+  const std::vector<int32>& GetIntListAttribute(
+      AccessibilityNodeData::IntListAttribute attribute) const;
+  bool GetIntListAttribute(AccessibilityNodeData::IntListAttribute attribute,
+                           std::vector<int32>* value) const;
+
+  void SetStringAttribute(
+      AccessibilityNodeData::StringAttribute attribute,
+      const std::string& value);
 
   // Retrieve the value of a html attribute from the attribute map and
   // returns true if found.
   bool GetHtmlAttribute(const char* attr, string16* value) const;
+  bool GetHtmlAttribute(const char* attr, std::string* value) const;
 
   // Utility method to handle special cases for ARIA booleans, tristates and
   // booleans which have a "mixed" state.
@@ -236,7 +237,7 @@
   bool IsEditableText() const;
 
   // Append the text from this node and its children.
-  string16 GetTextRecursive() const;
+  std::string GetTextRecursive() const;
 
  protected:
   // Perform platform specific initialization. This can be called multiple times
@@ -264,21 +265,23 @@
   std::vector<BrowserAccessibility*> children_;
 
   // Accessibility metadata from the renderer
-  string16 name_;
-  string16 value_;
-  BoolAttrMap bool_attributes_;
-  IntAttrMap int_attributes_;
-  FloatAttrMap float_attributes_;
-  StringAttrMap string_attributes_;
-  std::vector<std::pair<string16, string16> > html_attributes_;
+  std::string name_;
+  std::string value_;
+  std::vector<std::pair<
+      AccessibilityNodeData::BoolAttribute, bool> > bool_attributes_;
+  std::vector<std::pair<
+      AccessibilityNodeData::FloatAttribute, float> > float_attributes_;
+  std::vector<std::pair<
+      AccessibilityNodeData::IntAttribute, int> > int_attributes_;
+  std::vector<std::pair<
+      AccessibilityNodeData::StringAttribute, std::string> > string_attributes_;
+  std::vector<std::pair<
+      AccessibilityNodeData::IntListAttribute, std::vector<int32> > >
+          intlist_attributes_;
+  std::vector<std::pair<std::string, std::string> > html_attributes_;
   int32 role_;
   int32 state_;
-  string16 role_name_;
   gfx::Rect location_;
-  std::vector<int32> indirect_child_ids_;
-  std::vector<int32> line_breaks_;
-  std::vector<int32> cell_ids_;
-  std::vector<int32> unique_cell_ids_;
 
   // BrowserAccessibility objects are reference-counted on some platforms.
   // When we're done with this object and it's removed from our accessibility
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index 8ff37ec..a31539a 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -174,16 +174,15 @@
     return string16();
   }
 
-  string16 description;
-  GetStringAttribute(AccessibilityNodeData::ATTR_DESCRIPTION, &description);
-
+  string16 description = GetString16Attribute(
+      AccessibilityNodeData::ATTR_DESCRIPTION);
   string16 text;
   if (!name().empty())
-    text = name();
+    text = base::UTF8ToUTF16(name());
   else if (!description.empty())
     text = description;
   else if (!value().empty())
-    text = value();
+    text = base::UTF8ToUTF16(value());
 
   if (text.empty() && HasOnlyStaticTextChildren()) {
     for (uint32 i = 0; i < child_count(); i++) {
@@ -361,8 +360,8 @@
 }
 
 bool BrowserAccessibilityAndroid::IsIframe() const {
-  string16 html_tag;
-  GetStringAttribute(AccessibilityNodeData::ATTR_HTML_TAG, &html_tag);
+  string16 html_tag = GetString16Attribute(
+      AccessibilityNodeData::ATTR_HTML_TAG);
   return html_tag == ASCIIToUTF16("iframe");
 }
 
@@ -370,9 +369,9 @@
   BrowserAccessibility::PostInitialize();
 
   if (IsEditableText()) {
-    if (value_ != new_value_) {
+    if (base::UTF8ToUTF16(value_) != new_value_) {
       old_value_ = new_value_;
-      new_value_ = value_;
+      new_value_ = base::UTF8ToUTF16(value_);
     }
   }
 
@@ -380,8 +379,8 @@
     manager_->NotifyAccessibilityEvent(AccessibilityNotificationAlert, this);
 
   string16 live;
-  if (GetStringAttribute(AccessibilityNodeData::ATTR_CONTAINER_LIVE_STATUS,
-                         &live)) {
+  if (GetString16Attribute(
+      AccessibilityNodeData::ATTR_CONTAINER_LIVE_STATUS, &live)) {
     NotifyLiveRegionUpdate(live);
   }
 
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 9d49767..8285e9d 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -33,15 +33,10 @@
 
 // Returns an autoreleased copy of the AccessibilityNodeData's attribute.
 NSString* NSStringForStringAttribute(
-    const std::map<StringAttribute, string16>& attributes,
+    BrowserAccessibility* browserAccessibility,
     StringAttribute attribute) {
-  std::map<StringAttribute, string16>::const_iterator iter =
-      attributes.find(attribute);
-  NSString* returnValue = @"";
-  if (iter != attributes.end()) {
-    returnValue = base::SysUTF16ToNSString(iter->second);
-  }
-  return returnValue;
+  return base::SysUTF8ToNSString(
+      browserAccessibility->GetStringAttribute(attribute));
 }
 
 struct MapEntry {
@@ -353,34 +348,29 @@
 
 - (NSString*)accessKey {
   return NSStringForStringAttribute(
-      browserAccessibility_->string_attributes(),
-      AccessibilityNodeData::ATTR_ACCESS_KEY);
+      browserAccessibility_, AccessibilityNodeData::ATTR_ACCESS_KEY);
 }
 
 - (NSNumber*)ariaAtomic {
-  bool boolValue = false;
-  browserAccessibility_->GetBoolAttribute(
-      AccessibilityNodeData::ATTR_LIVE_ATOMIC, &boolValue);
+  bool boolValue = browserAccessibility_->GetBoolAttribute(
+      AccessibilityNodeData::ATTR_LIVE_ATOMIC);
   return [NSNumber numberWithBool:boolValue];
 }
 
 - (NSNumber*)ariaBusy {
-  bool boolValue = false;
-  browserAccessibility_->GetBoolAttribute(
-      AccessibilityNodeData::ATTR_LIVE_BUSY, &boolValue);
+  bool boolValue = browserAccessibility_->GetBoolAttribute(
+      AccessibilityNodeData::ATTR_LIVE_BUSY);
   return [NSNumber numberWithBool:boolValue];
 }
 
 - (NSString*)ariaLive {
   return NSStringForStringAttribute(
-      browserAccessibility_->string_attributes(),
-      AccessibilityNodeData::ATTR_LIVE_STATUS);
+      browserAccessibility_, AccessibilityNodeData::ATTR_LIVE_STATUS);
 }
 
 - (NSString*)ariaRelevant {
   return NSStringForStringAttribute(
-      browserAccessibility_->string_attributes(),
-      AccessibilityNodeData::ATTR_LIVE_RELEVANT);
+      browserAccessibility_, AccessibilityNodeData::ATTR_LIVE_RELEVANT);
 }
 
 // Returns an array of BrowserAccessibilityCocoa objects, representing the
@@ -401,10 +391,11 @@
     }
 
     // Also, add indirect children (if any).
-    for (uint32 i = 0;
-         i < browserAccessibility_->indirect_child_ids().size();
-         ++i) {
-      int32 child_id = browserAccessibility_->indirect_child_ids()[i];
+    const std::vector<int32>& indirectChildIds =
+        browserAccessibility_->GetIntListAttribute(
+            AccessibilityNodeData::ATTR_INDIRECT_CHILD_IDS);
+    for (uint32 i = 0; i < indirectChildIds.size(); ++i) {
+      int32 child_id = indirectChildIds[i];
       BrowserAccessibility* child =
           browserAccessibility_->manager()->GetFromRendererID(child_id);
 
@@ -437,7 +428,8 @@
 
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   const std::vector<int32>& uniqueCellIds =
-      browserAccessibility_->unique_cell_ids();
+      browserAccessibility_->GetIntListAttribute(
+          AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   for (size_t i = 0; i < uniqueCellIds.size(); ++i) {
     int id = uniqueCellIds[i];
     BrowserAccessibility* cell =
@@ -473,35 +465,34 @@
 }
 
 - (NSString*)description {
-  const std::map<StringAttribute, string16>& attributes =
-      browserAccessibility_->string_attributes();
-  std::map<StringAttribute, string16>::const_iterator iter =
-      attributes.find(AccessibilityNodeData::ATTR_DESCRIPTION);
-  if (iter != attributes.end())
-    return base::SysUTF16ToNSString(iter->second);
+  std::string description;
+  if (browserAccessibility_->GetStringAttribute(
+          AccessibilityNodeData::ATTR_DESCRIPTION, &description)) {
+    return base::SysUTF8ToNSString(description);
+  }
 
   // If the role is anything other than an image, or if there's
   // a title or title UI element, just return an empty string.
   if (![[self role] isEqualToString:NSAccessibilityImageRole])
     return @"";
-  if (!browserAccessibility_->name().empty())
+  if (browserAccessibility_->HasStringAttribute(
+          AccessibilityNodeData::ATTR_NAME)) {
     return @"";
+  }
   if ([self titleUIElement])
     return @"";
 
   // The remaining case is an image where there's no other title.
   // Return the base part of the filename as the description.
-  iter = attributes.find(AccessibilityNodeData::ATTR_URL);
-  if (iter != attributes.end()) {
-    string16 filename = iter->second;
+  std::string url;
+  if (browserAccessibility_->GetStringAttribute(
+          AccessibilityNodeData::ATTR_URL, &url)) {
     // Given a url like http://foo.com/bar/baz.png, just return the
     // base name, e.g., "baz.png".
-    size_t leftIndex = filename.size();
-    while (leftIndex > 0 && filename[leftIndex - 1] != '/')
-      leftIndex--;
-    string16 basename = filename.substr(leftIndex);
-
-    return base::SysUTF16ToNSString(basename);
+    size_t leftIndex = url.rfind('/');
+    std::string basename =
+        leftIndex != std::string::npos ? url.substr(leftIndex) : url;
+    return base::SysUTF8ToNSString(basename);
   }
 
   return @"";
@@ -526,9 +517,8 @@
   AccessibilityNodeData::Role role = [self internalRole];
   if (role == AccessibilityNodeData::ROLE_ROW ||
       role == AccessibilityNodeData::ROLE_TREE_ITEM) {
-    int level = 0;
-    browserAccessibility_->GetIntAttribute(
-        AccessibilityNodeData::ATTR_HIERARCHICAL_LEVEL, &level);
+    int level = browserAccessibility_->GetIntAttribute(
+        AccessibilityNodeData::ATTR_HIERARCHICAL_LEVEL);
     // Mac disclosureLevel is 0-based, but web levels are 1-based.
     if (level > 0)
       level--;
@@ -581,23 +571,18 @@
 
 - (NSString*)help {
   return NSStringForStringAttribute(
-      browserAccessibility_->string_attributes(),
-      AccessibilityNodeData::ATTR_HELP);
+      browserAccessibility_, AccessibilityNodeData::ATTR_HELP);
 }
 
 - (NSNumber*)index {
   if ([self internalRole] == AccessibilityNodeData::ROLE_COLUMN) {
-    int columnIndex;
-    if (browserAccessibility_->GetIntAttribute(
-            AccessibilityNodeData::ATTR_TABLE_COLUMN_INDEX, &columnIndex)) {
-      return [NSNumber numberWithInt:columnIndex];
-    }
+    int columnIndex = browserAccessibility_->GetIntAttribute(
+          AccessibilityNodeData::ATTR_TABLE_COLUMN_INDEX);
+    return [NSNumber numberWithInt:columnIndex];
   } else if ([self internalRole] == AccessibilityNodeData::ROLE_ROW) {
-    int rowIndex;
-    if (browserAccessibility_->GetIntAttribute(
-            AccessibilityNodeData::ATTR_TABLE_ROW_INDEX, &rowIndex)) {
-      return [NSNumber numberWithInt:rowIndex];
-    }
+    int rowIndex = browserAccessibility_->GetIntAttribute(
+        AccessibilityNodeData::ATTR_TABLE_ROW_INDEX);
+    return [NSNumber numberWithInt:rowIndex];
   }
 
   return nil;
@@ -626,23 +611,20 @@
 }
 
 - (NSNumber*)loadingProgress {
-  float floatValue = 0.0;
-  browserAccessibility_->GetFloatAttribute(
-      AccessibilityNodeData::ATTR_DOC_LOADING_PROGRESS, &floatValue);
+  float floatValue = browserAccessibility_->GetFloatAttribute(
+      AccessibilityNodeData::ATTR_DOC_LOADING_PROGRESS);
   return [NSNumber numberWithFloat:floatValue];
 }
 
 - (NSNumber*)maxValue {
-  float floatValue = 0.0;
-  browserAccessibility_->GetFloatAttribute(
-      AccessibilityNodeData::ATTR_MAX_VALUE_FOR_RANGE, &floatValue);
+  float floatValue = browserAccessibility_->GetFloatAttribute(
+      AccessibilityNodeData::ATTR_MAX_VALUE_FOR_RANGE);
   return [NSNumber numberWithFloat:floatValue];
 }
 
 - (NSNumber*)minValue {
-  float floatValue = 0.0;
-  browserAccessibility_->GetFloatAttribute(
-      AccessibilityNodeData::ATTR_MIN_VALUE_FOR_RANGE, &floatValue);
+  float floatValue = browserAccessibility_->GetFloatAttribute(
+      AccessibilityNodeData::ATTR_MIN_VALUE_FOR_RANGE);
   return [NSNumber numberWithFloat:floatValue];
 }
 
@@ -728,18 +710,15 @@
 
   if ([role isEqualToString:NSAccessibilityGroupRole] ||
       [role isEqualToString:NSAccessibilityRadioButtonRole]) {
-    const std::vector<std::pair<string16, string16> >& htmlAttributes =
-        browserAccessibility_->html_attributes();
-    AccessibilityNodeData::Role browserAccessibilityRole = [self internalRole];
-    if ((browserAccessibilityRole != AccessibilityNodeData::ROLE_GROUP &&
-         browserAccessibilityRole != AccessibilityNodeData::ROLE_LIST_ITEM) ||
-         browserAccessibilityRole == AccessibilityNodeData::ROLE_TAB) {
-      for (size_t i = 0; i < htmlAttributes.size(); ++i) {
-        const std::pair<string16, string16>& htmlAttribute = htmlAttributes[i];
-        if (htmlAttribute.first == ASCIIToUTF16("role")) {
-          // TODO(dtseng): This is not localized; see crbug/84814.
-          return base::SysUTF16ToNSString(htmlAttribute.second);
-        }
+    std::string role;
+    if (browserAccessibility_->GetHtmlAttribute("role", &role)) {
+      AccessibilityNodeData::Role internalRole =
+          [self internalRole];
+      if ((internalRole != AccessibilityNodeData::ROLE_GROUP &&
+           internalRole != AccessibilityNodeData::ROLE_LIST_ITEM) ||
+          internalRole == AccessibilityNodeData::ROLE_TAB) {
+        // TODO(dtseng): This is not localized; see crbug/84814.
+        return base::SysUTF8ToNSString(role);
       }
     }
   }
@@ -767,7 +746,8 @@
 
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   const std::vector<int32>& uniqueCellIds =
-      browserAccessibility_->unique_cell_ids();
+      browserAccessibility_->GetIntListAttribute(
+          AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   for (size_t i = 0; i < uniqueCellIds.size(); ++i) {
     int id = uniqueCellIds[i];
     BrowserAccessibility* cell =
@@ -804,7 +784,8 @@
     }
   } else if ([self internalRole] == AccessibilityNodeData::ROLE_COLUMN) {
     const std::vector<int32>& indirectChildIds =
-        browserAccessibility_->indirect_child_ids();
+        browserAccessibility_->GetIntListAttribute(
+            AccessibilityNodeData::ATTR_INDIRECT_CHILD_IDS);
     for (uint32 i = 0; i < indirectChildIds.size(); ++i) {
       int id = indirectChildIds[i];
       BrowserAccessibility* rowElement =
@@ -832,8 +813,7 @@
   }
 
   NSString* htmlTag = NSStringForStringAttribute(
-      browserAccessibility_->string_attributes(),
-      AccessibilityNodeData::ATTR_HTML_TAG);
+      browserAccessibility_, AccessibilityNodeData::ATTR_HTML_TAG);
 
   if (browserAccessibilityRole == AccessibilityNodeData::ROLE_LIST) {
     if ([htmlTag isEqualToString:@"ul"] ||
@@ -864,7 +844,8 @@
 }
 
 - (NSString*)title {
-  return base::SysUTF16ToNSString(browserAccessibility_->name());
+  return NSStringForStringAttribute(
+      browserAccessibility_, AccessibilityNodeData::ATTR_NAME);
 }
 
 - (id)titleUIElement {
@@ -884,9 +865,7 @@
       [[self role] isEqualToString:@"AXWebArea"] ?
           AccessibilityNodeData::ATTR_DOC_URL :
           AccessibilityNodeData::ATTR_URL;
-  return NSStringForStringAttribute(
-      browserAccessibility_->string_attributes(),
-      urlAttribute);
+  return NSStringForStringAttribute(browserAccessibility_, urlAttribute);
 }
 
 - (id)value {
@@ -895,7 +874,7 @@
   // to approximate Cocoa ax behavior best as we can.
   NSString* role = [self role];
   if ([role isEqualToString:@"AXHeading"]) {
-    int level;
+    int level = 0;
     if (browserAccessibility_->GetIntAttribute(
             AccessibilityNodeData::ATTR_HIERARCHICAL_LEVEL, &level)) {
       return [NSNumber numberWithInt:level];
@@ -913,11 +892,10 @@
             1 :
             value;
 
-    bool mixed = false;
-    browserAccessibility_->GetBoolAttribute(
-        AccessibilityNodeData::ATTR_BUTTON_MIXED, &mixed);
-    if (mixed)
+    if (browserAccessibility_->GetBoolAttribute(
+        AccessibilityNodeData::ATTR_BUTTON_MIXED)) {
       value = 2;
+    }
     return [NSNumber numberWithInt:value];
   } else if ([role isEqualToString:NSAccessibilityProgressIndicatorRole] ||
              [role isEqualToString:NSAccessibilitySliderRole] ||
@@ -928,26 +906,24 @@
       return [NSNumber numberWithFloat:floatValue];
     }
   } else if ([role isEqualToString:NSAccessibilityColorWellRole]) {
-    int r, g, b;
-    browserAccessibility_->GetIntAttribute(
-        AccessibilityNodeData::ATTR_COLOR_VALUE_RED, &r);
-    browserAccessibility_->GetIntAttribute(
-        AccessibilityNodeData::ATTR_COLOR_VALUE_GREEN, &g);
-    browserAccessibility_->GetIntAttribute(
-        AccessibilityNodeData::ATTR_COLOR_VALUE_BLUE, &b);
+    int r = browserAccessibility_->GetIntAttribute(
+        AccessibilityNodeData::ATTR_COLOR_VALUE_RED);
+    int g = browserAccessibility_->GetIntAttribute(
+        AccessibilityNodeData::ATTR_COLOR_VALUE_GREEN);
+    int b = browserAccessibility_->GetIntAttribute(
+        AccessibilityNodeData::ATTR_COLOR_VALUE_BLUE);
     // This string matches the one returned by a native Mac color well.
     return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1",
                 r / 255., g / 255., b / 255.];
   }
 
-  return base::SysUTF16ToNSString(browserAccessibility_->value());
+  return NSStringForStringAttribute(
+      browserAccessibility_, AccessibilityNodeData::ATTR_VALUE);
 }
 
 - (NSString*)valueDescription {
-  if (!browserAccessibility_->value().empty())
-    return base::SysUTF16ToNSString(browserAccessibility_->value());
-  else
-    return nil;
+  return NSStringForStringAttribute(
+      browserAccessibility_, AccessibilityNodeData::ATTR_VALUE);
 }
 
 - (NSValue*)visibleCharacterRange {
@@ -958,7 +934,8 @@
 - (NSArray*)visibleCells {
   NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease];
   const std::vector<int32>& uniqueCellIds =
-      browserAccessibility_->unique_cell_ids();
+      browserAccessibility_->GetIntListAttribute(
+          AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
   for (size_t i = 0; i < uniqueCellIds.size(); ++i) {
     int id = uniqueCellIds[i];
     BrowserAccessibility* cell =
@@ -1013,7 +990,8 @@
     if ([attribute isEqualToString:
         NSAccessibilityInsertionPointLineNumberAttribute]) {
       const std::vector<int32>& line_breaks =
-          browserAccessibility_->line_breaks();
+          browserAccessibility_->GetIntListAttribute(
+              AccessibilityNodeData::ATTR_LINE_BREAKS);
       for (int i = 0; i < static_cast<int>(line_breaks.size()); ++i) {
         if (line_breaks[i] > selStart)
           return [NSNumber numberWithInt:i];
@@ -1021,8 +999,9 @@
       return [NSNumber numberWithInt:static_cast<int>(line_breaks.size())];
     }
     if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
-      return base::SysUTF16ToNSString(browserAccessibility_->value().substr(
-          selStart, selLength));
+      std::string value = browserAccessibility_->GetStringAttribute(
+          AccessibilityNodeData::ATTR_VALUE);
+      return base::SysUTF8ToNSString(value.substr(selStart, selLength));
     }
     if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
       return [NSValue valueWithRange:NSMakeRange(selStart, selLength)];
@@ -1038,14 +1017,17 @@
   if (!browserAccessibility_)
     return nil;
 
-  const std::vector<int32>& line_breaks = browserAccessibility_->line_breaks();
+  const std::vector<int32>& line_breaks =
+      browserAccessibility_->GetIntListAttribute(
+          AccessibilityNodeData::ATTR_LINE_BREAKS);
   int len = static_cast<int>(browserAccessibility_->value().size());
 
   if ([attribute isEqualToString:
       NSAccessibilityStringForRangeParameterizedAttribute]) {
     NSRange range = [(NSValue*)parameter rangeValue];
-    return base::SysUTF16ToNSString(
-        browserAccessibility_->value().substr(range.location, range.length));
+    std::string value = browserAccessibility_->GetStringAttribute(
+        AccessibilityNodeData::ATTR_VALUE);
+    return base::SysUTF8ToNSString(value.substr(range.location, range.length));
   }
 
   if ([attribute isEqualToString:
@@ -1081,12 +1063,10 @@
     NSArray* array = parameter;
     int column = [[array objectAtIndex:0] intValue];
     int row = [[array objectAtIndex:1] intValue];
-    int num_columns = 0;
-    int num_rows = 0;
-    browserAccessibility_->GetIntAttribute(
-        AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT, &num_columns);
-    browserAccessibility_->GetIntAttribute(
-        AccessibilityNodeData::ATTR_TABLE_ROW_COUNT, &num_rows);
+    int num_columns = browserAccessibility_->GetIntAttribute(
+        AccessibilityNodeData::ATTR_TABLE_COLUMN_COUNT);
+    int num_rows = browserAccessibility_->GetIntAttribute(
+        AccessibilityNodeData::ATTR_TABLE_ROW_COUNT);
     if (column < 0 || column >= num_columns ||
         row < 0 || row >= num_rows) {
       return nil;
@@ -1335,16 +1315,15 @@
   }
 
   // Live regions.
-  string16 s;
-  if (browserAccessibility_->GetStringAttribute(
-          AccessibilityNodeData::ATTR_LIVE_STATUS, &s)) {
+  if (browserAccessibility_->HasStringAttribute(
+          AccessibilityNodeData::ATTR_LIVE_STATUS)) {
     [ret addObjectsFromArray:[NSArray arrayWithObjects:
         @"AXARIALive",
         @"AXARIARelevant",
         nil]];
   }
-  if (browserAccessibility_->GetStringAttribute(
-          AccessibilityNodeData::ATTR_CONTAINER_LIVE_STATUS, &s)) {
+  if (browserAccessibility_->HasStringAttribute(
+          AccessibilityNodeData::ATTR_CONTAINER_LIVE_STATUS)) {
     [ret addObjectsFromArray:[NSArray arrayWithObjects:
         @"AXARIAAtomic",
         @"AXARIABusy",
@@ -1352,9 +1331,8 @@
   }
 
   // Title UI Element.
-  int i;
-  if (browserAccessibility_->GetIntAttribute(
-          AccessibilityNodeData::ATTR_TITLE_UI_ELEMENT, &i)) {
+  if (browserAccessibility_->HasIntAttribute(
+          AccessibilityNodeData::ATTR_TITLE_UI_ELEMENT)) {
     [ret addObjectsFromArray:[NSArray arrayWithObjects:
          NSAccessibilityTitleUIElementAttribute,
          nil]];
@@ -1387,10 +1365,8 @@
     return GetState(browserAccessibility_,
         AccessibilityNodeData::STATE_FOCUSABLE);
   if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
-    bool canSetValue = false;
-    browserAccessibility_->GetBoolAttribute(
-        AccessibilityNodeData::ATTR_CAN_SET_VALUE, &canSetValue);
-    return canSetValue;
+    return browserAccessibility_->GetBoolAttribute(
+        AccessibilityNodeData::ATTR_CAN_SET_VALUE);
   }
   if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute] &&
       ([[self role] isEqualToString:NSAccessibilityTextFieldRole] ||
diff --git a/content/browser/accessibility/browser_accessibility_gtk.cc b/content/browser/accessibility/browser_accessibility_gtk.cc
index 5036428..f1a1f34 100644
--- a/content/browser/accessibility/browser_accessibility_gtk.cc
+++ b/content/browser/accessibility/browser_accessibility_gtk.cc
@@ -178,7 +178,8 @@
   BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object);
   if (!obj)
     return NULL;
-  return obj->atk_acc_name().c_str();
+
+  return obj->GetStringAttribute(AccessibilityNodeData::ATTR_NAME).c_str();
 }
 
 static const gchar* browser_accessibility_get_description(
@@ -186,7 +187,9 @@
   BrowserAccessibilityGtk* obj = ToBrowserAccessibilityGtk(atk_object);
   if (!obj)
     return NULL;
-  return obj->atk_acc_description().c_str();
+
+  return obj->GetStringAttribute(
+      AccessibilityNodeData::ATTR_DESCRIPTION).c_str();
 }
 
 static AtkObject* browser_accessibility_get_parent(AtkObject* atk_object) {
@@ -467,12 +470,6 @@
 }
 
 void BrowserAccessibilityGtk::InitRoleAndState() {
-  atk_acc_name_ = UTF16ToUTF8(name());
-
-  string16 description;
-  GetStringAttribute(AccessibilityNodeData::ATTR_DESCRIPTION, &description);
-  atk_acc_description_ = UTF16ToUTF8(description);
-
   switch(role_) {
     case AccessibilityNodeData::ROLE_DOCUMENT:
     case AccessibilityNodeData::ROLE_ROOT_WEB_AREA:
diff --git a/content/browser/accessibility/browser_accessibility_gtk.h b/content/browser/accessibility/browser_accessibility_gtk.h
index 8f3a2e3..c8895e3 100644
--- a/content/browser/accessibility/browser_accessibility_gtk.h
+++ b/content/browser/accessibility/browser_accessibility_gtk.h
@@ -68,8 +68,6 @@
   AtkObject* GetAtkObject() const;
 
   AtkRole atk_role() { return atk_role_; }
-  const std::string& atk_acc_name() { return atk_acc_name_; }
-  const std::string& atk_acc_description() { return atk_acc_description_; }
 
   // BrowserAccessibility methods.
   virtual void PreInitialize() OVERRIDE;
@@ -83,8 +81,6 @@
 
   AtkObject* atk_object_;
   AtkRole atk_role_;
-  std::string atk_acc_name_;
-  std::string atk_acc_description_;
   int interface_mask_;
 
  private:
diff --git a/content/browser/accessibility/browser_accessibility_mac_unittest.mm b/content/browser/accessibility/browser_accessibility_mac_unittest.mm
index 45137ec..9f12138 100644
--- a/content/browser/accessibility/browser_accessibility_mac_unittest.mm
+++ b/content/browser/accessibility/browser_accessibility_mac_unittest.mm
@@ -68,14 +68,13 @@
     root.location.set_width(500);
     root.location.set_height(100);
     root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA;
-    root.string_attributes[AccessibilityNodeData::ATTR_HELP] =
-        ASCIIToUTF16("HelpText");
+    root.AddStringAttribute(AccessibilityNodeData::ATTR_HELP, "HelpText");
     root.child_ids.push_back(1001);
     root.child_ids.push_back(1002);
 
     AccessibilityNodeData child1;
     child1.id = 1001;
-    child1.name = ASCIIToUTF16("Child1");
+    child1.SetName("Child1");
     child1.location.set_width(250);
     child1.location.set_height(100);
     child1.role = AccessibilityNodeData::ROLE_BUTTON;
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index 7def574..10c8b54 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -338,11 +338,13 @@
     instance = CreateNode(NULL, src.id, 0);
   }
 
-  if (src.bool_attributes.find(
-          AccessibilityNodeData::ATTR_UPDATE_LOCATION_ONLY) !=
-              src.bool_attributes.end()) {
-    instance->SetLocation(src.location);
-    return true;
+  // TODO(dmazzoni): avoid a linear scan here.
+  for (size_t i = 0; i < src.bool_attributes.size(); i++) {
+    if (src.bool_attributes[i].first ==
+        AccessibilityNodeData::ATTR_UPDATE_LOCATION_ONLY) {
+      instance->SetLocation(src.location);
+      return true;
+    }
   }
 
   // Update all of the node-specific data, like its role, state, name, etc.
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index 5cb03cd..5ba5a2e 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -92,19 +92,19 @@
   // BrowserAccessibilityManager.
   AccessibilityNodeData button;
   button.id = 2;
-  button.name = UTF8ToUTF16("Button");
+  button.SetName("Button");
   button.role = AccessibilityNodeData::ROLE_BUTTON;
   button.state = 0;
 
   AccessibilityNodeData checkbox;
   checkbox.id = 3;
-  checkbox.name = UTF8ToUTF16("Checkbox");
+  checkbox.SetName("Checkbox");
   checkbox.role = AccessibilityNodeData::ROLE_CHECKBOX;
   checkbox.state = 0;
 
   AccessibilityNodeData root;
   root.id = 1;
-  root.name = UTF8ToUTF16("Document");
+  root.SetName("Document");
   root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA;
   root.state = 0;
   root.child_ids.push_back(2);
@@ -170,25 +170,25 @@
 
   AccessibilityNodeData tree1_child1;
   tree1_child1.id = 2;
-  tree1_child1.name = UTF8ToUTF16("Child1");
+  tree1_child1.SetName("Child1");
   tree1_child1.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_child1.state = 0;
 
   AccessibilityNodeData tree1_child2;
   tree1_child2.id = 3;
-  tree1_child2.name = UTF8ToUTF16("Child2");
+  tree1_child2.SetName("Child2");
   tree1_child2.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_child2.state = 0;
 
   AccessibilityNodeData tree1_child3;
   tree1_child3.id = 4;
-  tree1_child3.name = UTF8ToUTF16("Child3");
+  tree1_child3.SetName("Child3");
   tree1_child3.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_child3.state = 0;
 
   AccessibilityNodeData tree1_root;
   tree1_root.id = 1;
-  tree1_root.name = UTF8ToUTF16("Document");
+  tree1_root.SetName("Document");
   tree1_root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA;
   tree1_root.state = 0;
   tree1_root.child_ids.push_back(2);
@@ -205,13 +205,13 @@
 
   AccessibilityNodeData tree2_child0;
   tree2_child0.id = 5;
-  tree2_child0.name = UTF8ToUTF16("Child0");
+  tree2_child0.SetName("Child0");
   tree2_child0.role = AccessibilityNodeData::ROLE_BUTTON;
   tree2_child0.state = 0;
 
   AccessibilityNodeData tree2_root;
   tree2_root.id = 1;
-  tree2_root.name = UTF8ToUTF16("DocumentChanged");
+  tree2_root.SetName("DocumentChanged");
   tree2_root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA;
   tree2_root.state = 0;
   tree2_root.child_ids.push_back(5);
@@ -302,46 +302,46 @@
 
   AccessibilityNodeData tree1_grandchild1;
   tree1_grandchild1.id = 4;
-  tree1_grandchild1.name = UTF8ToUTF16("GrandChild1");
+  tree1_grandchild1.SetName("GrandChild1");
   tree1_grandchild1.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_grandchild1.state = 0;
 
   AccessibilityNodeData tree1_child1;
   tree1_child1.id = 3;
-  tree1_child1.name = UTF8ToUTF16("Child1");
+  tree1_child1.SetName("Child1");
   tree1_child1.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_child1.state = 0;
   tree1_child1.child_ids.push_back(4);
 
   AccessibilityNodeData tree1_grandchild2;
   tree1_grandchild2.id = 6;
-  tree1_grandchild2.name = UTF8ToUTF16("GrandChild1");
+  tree1_grandchild2.SetName("GrandChild1");
   tree1_grandchild2.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_grandchild2.state = 0;
 
   AccessibilityNodeData tree1_child2;
   tree1_child2.id = 5;
-  tree1_child2.name = UTF8ToUTF16("Child2");
+  tree1_child2.SetName("Child2");
   tree1_child2.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_child2.state = 0;
   tree1_child2.child_ids.push_back(6);
 
   AccessibilityNodeData tree1_grandchild3;
   tree1_grandchild3.id = 8;
-  tree1_grandchild3.name = UTF8ToUTF16("GrandChild3");
+  tree1_grandchild3.SetName("GrandChild3");
   tree1_grandchild3.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_grandchild3.state = 0;
 
   AccessibilityNodeData tree1_child3;
   tree1_child3.id = 7;
-  tree1_child3.name = UTF8ToUTF16("Child3");
+  tree1_child3.SetName("Child3");
   tree1_child3.role = AccessibilityNodeData::ROLE_BUTTON;
   tree1_child3.state = 0;
   tree1_child3.child_ids.push_back(8);
 
   AccessibilityNodeData tree1_container;
   tree1_container.id = 2;
-  tree1_container.name = UTF8ToUTF16("Container");
+  tree1_container.SetName("Container");
   tree1_container.role = AccessibilityNodeData::ROLE_GROUP;
   tree1_container.state = 0;
   tree1_container.child_ids.push_back(3);
@@ -350,7 +350,7 @@
 
   AccessibilityNodeData tree1_root;
   tree1_root.id = 1;
-  tree1_root.name = UTF8ToUTF16("Document");
+  tree1_root.SetName("Document");
   tree1_root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA;
   tree1_root.state = 0;
   tree1_root.child_ids.push_back(2);
@@ -369,20 +369,20 @@
 
   AccessibilityNodeData tree2_grandchild0;
   tree2_grandchild0.id = 9;
-  tree2_grandchild0.name = UTF8ToUTF16("GrandChild0");
+  tree2_grandchild0.SetName("GrandChild0");
   tree2_grandchild0.role = AccessibilityNodeData::ROLE_BUTTON;
   tree2_grandchild0.state = 0;
 
   AccessibilityNodeData tree2_child0;
   tree2_child0.id = 10;
-  tree2_child0.name = UTF8ToUTF16("Child0");
+  tree2_child0.SetName("Child0");
   tree2_child0.role = AccessibilityNodeData::ROLE_BUTTON;
   tree2_child0.state = 0;
   tree2_child0.child_ids.push_back(9);
 
   AccessibilityNodeData tree2_container;
   tree2_container.id = 2;
-  tree2_container.name = UTF8ToUTF16("Container");
+  tree2_container.SetName("Container");
   tree2_container.role = AccessibilityNodeData::ROLE_GROUP;
   tree2_container.state = 0;
   tree2_container.child_ids.push_back(10);
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc
index 792adc4..614dd8f 100644
--- a/content/browser/accessibility/browser_accessibility_win.cc
+++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -457,7 +457,7 @@
   if (!target)
     return E_INVALIDARG;
 
-  string16 name_str = target->name_;
+  std::string name_str = target->name();
 
   // If the name is empty, see if it's labeled by another element.
   if (name_str.empty()) {
@@ -474,7 +474,7 @@
   if (name_str.empty())
     return S_FALSE;
 
-  *name = SysAllocString(name_str.c_str());
+  *name = SysAllocString(UTF8ToUTF16(name_str).c_str());
 
   DCHECK(*name);
   return S_OK;
@@ -557,8 +557,33 @@
   if (!target)
     return E_INVALIDARG;
 
-  *value = SysAllocString(target->value_.c_str());
+  if (target->ia_role() == ROLE_SYSTEM_PROGRESSBAR ||
+      target->ia_role() == ROLE_SYSTEM_SCROLLBAR ||
+      target->ia_role() == ROLE_SYSTEM_SLIDER) {
+    string16 value_text = target->GetValueText();
+    *value = SysAllocString(value_text.c_str());
+    DCHECK(*value);
+    return S_OK;
+  }
 
+  // Expose color well value.
+  if (target->ia2_role() == IA2_ROLE_COLOR_CHOOSER) {
+    int r = target->GetIntAttribute(
+        AccessibilityNodeData::ATTR_COLOR_VALUE_RED);
+    int g = target->GetIntAttribute(
+        AccessibilityNodeData::ATTR_COLOR_VALUE_GREEN);
+    int b = target->GetIntAttribute(
+        AccessibilityNodeData::ATTR_COLOR_VALUE_BLUE);
+    string16 value_text;
+    value_text = base::IntToString16((r * 100) / 255) + L"% red " +
+                 base::IntToString16((g * 100) / 255) + L"% green " +
+                 base::IntToString16((b * 100) / 255) + L"% blue";
+    *value = SysAllocString(value_text.c_str());
+    DCHECK(*value);
+    return S_OK;
+  }
+
+  *value = SysAllocString(UTF8ToUTF16(target->value()).c_str());
   DCHECK(*value);
   return S_OK;
 }
@@ -1014,9 +1039,11 @@
   if (row < 0 || row >= rows || column < 0 || column >= columns)
     return E_INVALIDARG;
 
-  DCHECK_EQ(columns * rows, static_cast<int>(cell_ids_.size()));
+  const std::vector<int32>& cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
+  DCHECK_EQ(columns * rows, static_cast<int>(cell_ids.size()));
 
-  int cell_id = cell_ids_[row * columns + column];
+  int cell_id = cell_ids[row * columns + column];
   BrowserAccessibilityWin* cell = GetFromRendererID(cell_id);
   if (cell) {
     *accessible = static_cast<IAccessible*>(cell->NewReference());
@@ -1061,10 +1088,14 @@
   if (row < 0 || row >= rows || column < 0 || column >= columns)
     return E_INVALIDARG;
 
-  DCHECK_EQ(columns * rows, static_cast<int>(cell_ids_.size()));
-  int cell_id = cell_ids_[row * columns + column];
-  for (size_t i = 0; i < unique_cell_ids_.size(); ++i) {
-    if (unique_cell_ids_[i] == cell_id) {
+  const std::vector<int32>& cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
+  const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
+  DCHECK_EQ(columns * rows, static_cast<int>(cell_ids.size()));
+  int cell_id = cell_ids[row * columns + column];
+  for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
+    if (unique_cell_ids[i] == cell_id) {
       *cell_index = (long)i;
       return S_OK;
     }
@@ -1094,13 +1125,17 @@
   if (column < 0 || column >= columns)
     return E_INVALIDARG;
 
+  const std::vector<int32>& cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
   for (int i = 0; i < rows; ++i) {
-    int cell_id = cell_ids_[i * columns + column];
+    int cell_id = cell_ids[i * columns + column];
     BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
         manager_->GetFromRendererID(cell_id));
     if (cell && cell->role_ == AccessibilityNodeData::ROLE_COLUMN_HEADER) {
-      if (cell->name_.size() > 0) {
-        *description = SysAllocString(cell->name_.c_str());
+      string16 cell_name = cell->GetString16Attribute(
+          AccessibilityNodeData::ATTR_NAME);
+      if (cell_name.size() > 0) {
+        *description = SysAllocString(cell_name.c_str());
         return S_OK;
       }
 
@@ -1135,7 +1170,9 @@
   if (row < 0 || row >= rows || column < 0 || column >= columns)
     return E_INVALIDARG;
 
-  int cell_id = cell_ids_[row * columns + column];
+  const std::vector<int32>& cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
+  int cell_id = cell_ids[row * columns + column];
   BrowserAccessibilityWin* cell = static_cast<BrowserAccessibilityWin*>(
       manager_->GetFromRendererID(cell_id));
   int colspan;
@@ -1165,13 +1202,15 @@
   if (!column_index)
     return E_INVALIDARG;
 
-  int cell_id_count = static_cast<int>(unique_cell_ids_.size());
+  const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
+  int cell_id_count = static_cast<int>(unique_cell_ids.size());
   if (cell_index < 0)
     return E_INVALIDARG;
   if (cell_index >= cell_id_count)
     return S_FALSE;
 
-  int cell_id = unique_cell_ids_[cell_index];
+  int cell_id = unique_cell_ids[cell_index];
   BrowserAccessibilityWin* cell =
       manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   int col_index;
@@ -1273,13 +1312,17 @@
   if (row < 0 || row >= rows)
     return E_INVALIDARG;
 
+  const std::vector<int32>& cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
   for (int i = 0; i < columns; ++i) {
-    int cell_id = cell_ids_[row * columns + i];
+    int cell_id = cell_ids[row * columns + i];
     BrowserAccessibilityWin* cell =
         manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
     if (cell && cell->role_ == AccessibilityNodeData::ROLE_ROW_HEADER) {
-      if (cell->name_.size() > 0) {
-        *description = SysAllocString(cell->name_.c_str());
+      string16 cell_name = cell->GetString16Attribute(
+          AccessibilityNodeData::ATTR_NAME);
+      if (cell_name.size() > 0) {
+        *description = SysAllocString(cell_name.c_str());
         return S_OK;
       }
 
@@ -1313,7 +1356,9 @@
   if (row < 0 || row >= rows || column < 0 || column >= columns)
     return E_INVALIDARG;
 
-  int cell_id = cell_ids_[row * columns + column];
+  const std::vector<int32>& cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
+  int cell_id = cell_ids[row * columns + column];
   BrowserAccessibilityWin* cell =
       manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   int rowspan;
@@ -1343,13 +1388,15 @@
   if (!row_index)
     return E_INVALIDARG;
 
-  int cell_id_count = static_cast<int>(unique_cell_ids_.size());
+  const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
+  int cell_id_count = static_cast<int>(unique_cell_ids.size());
   if (cell_index < 0)
     return E_INVALIDARG;
   if (cell_index >= cell_id_count)
     return S_FALSE;
 
-  int cell_id = unique_cell_ids_[cell_index];
+  int cell_id = unique_cell_ids[cell_index];
   BrowserAccessibilityWin* cell =
       manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   int cell_row_index;
@@ -1470,13 +1517,15 @@
   if (!row || !column || !row_extents || !column_extents || !is_selected)
     return E_INVALIDARG;
 
-  int cell_id_count = static_cast<int>(unique_cell_ids_.size());
+  const std::vector<int32>& unique_cell_ids = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
+  int cell_id_count = static_cast<int>(unique_cell_ids.size());
   if (index < 0)
     return E_INVALIDARG;
   if (index >= cell_id_count)
     return S_FALSE;
 
-  int cell_id = unique_cell_ids_[index];
+  int cell_id = unique_cell_ids[index];
   BrowserAccessibilityWin* cell =
       manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
   int rowspan;
@@ -1610,8 +1659,11 @@
   if (columns <= 0 || rows <= 0 || column < 0 || column >= columns)
     return S_FALSE;
 
+  const std::vector<int32>& cell_ids = table->GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
+
   for (int i = 0; i < rows; ++i) {
-    int cell_id = table->cell_ids()[i * columns + column];
+    int cell_id = cell_ids[i * columns + column];
     BrowserAccessibilityWin* cell =
         manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
     if (cell && cell->role_ == AccessibilityNodeData::ROLE_COLUMN_HEADER)
@@ -1622,7 +1674,7 @@
       (*n_column_header_cells) * sizeof(cell_accessibles[0])));
   int index = 0;
   for (int i = 0; i < rows; ++i) {
-    int cell_id = table->cell_ids()[i * columns + column];
+    int cell_id = cell_ids[i * columns + column];
     BrowserAccessibilityWin* cell =
         manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
     if (cell && cell->role_ == AccessibilityNodeData::ROLE_COLUMN_HEADER) {
@@ -1706,8 +1758,11 @@
   if (columns <= 0 || rows <= 0 || row < 0 || row >= rows)
     return S_FALSE;
 
+  const std::vector<int32>& cell_ids = table->GetIntListAttribute(
+      AccessibilityNodeData::ATTR_CELL_IDS);
+
   for (int i = 0; i < columns; ++i) {
-    int cell_id = table->cell_ids()[row * columns + i];
+    int cell_id = cell_ids[row * columns + i];
     BrowserAccessibilityWin* cell =
         manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
     if (cell && cell->role_ == AccessibilityNodeData::ROLE_ROW_HEADER)
@@ -1718,7 +1773,7 @@
       (*n_row_header_cells) * sizeof(cell_accessibles[0])));
   int index = 0;
   for (int i = 0; i < columns; ++i) {
-    int cell_id = table->cell_ids()[row * columns + i];
+    int cell_id = cell_ids[row * columns + i];
     BrowserAccessibilityWin* cell =
         manager_->GetFromRendererID(cell_id)->ToBrowserAccessibilityWin();
     if (cell && cell->role_ == AccessibilityNodeData::ROLE_ROW_HEADER) {
@@ -2334,13 +2389,13 @@
   }
 
   string16 tag;
-  if (GetStringAttribute(AccessibilityNodeData::ATTR_HTML_TAG, &tag))
+  if (GetString16Attribute(AccessibilityNodeData::ATTR_HTML_TAG, &tag))
     *node_name = SysAllocString(tag.c_str());
   else
     *node_name = NULL;
 
   *name_space_id = 0;
-  *node_value = SysAllocString(value_.c_str());
+  *node_value = SysAllocString(UTF8ToUTF16(value_).c_str());
   *num_children = children_.size();
   *unique_id = unique_id_win_;
 
@@ -2373,9 +2428,11 @@
     *num_attribs = html_attributes_.size();
 
   for (unsigned short i = 0; i < *num_attribs; ++i) {
-    attrib_names[i] = SysAllocString(html_attributes_[i].first.c_str());
+    attrib_names[i] = SysAllocString(
+        UTF8ToUTF16(html_attributes_[i].first).c_str());
     name_space_id[i] = 0;
-    attrib_values[i] = SysAllocString(html_attributes_[i].second.c_str());
+    attrib_values[i] = SysAllocString(
+        UTF8ToUTF16(html_attributes_[i].second).c_str());
   }
   return S_OK;
 }
@@ -2394,10 +2451,11 @@
   for (unsigned short i = 0; i < num_attribs; ++i) {
     name_space_id[i] = 0;
     bool found = false;
-    string16 name = (LPCWSTR)attrib_names[i];
+    std::string name = UTF16ToUTF8((LPCWSTR)attrib_names[i]);
     for (unsigned int j = 0;  j < html_attributes_.size(); ++j) {
       if (html_attributes_[j].first == name) {
-        attrib_values[i] = SysAllocString(html_attributes_[j].second.c_str());
+        attrib_values[i] = SysAllocString(
+            UTF8ToUTF16(html_attributes_[j].second).c_str());
         found = true;
         break;
       }
@@ -2425,7 +2483,7 @@
 
   string16 display;
   if (max_style_properties == 0 ||
-      !GetStringAttribute(AccessibilityNodeData::ATTR_DISPLAY, &display)) {
+      !GetString16Attribute(AccessibilityNodeData::ATTR_DISPLAY, &display)) {
     *num_style_properties = 0;
     return S_OK;
   }
@@ -2454,8 +2512,8 @@
     string16 name = (LPCWSTR)style_properties[i];
     StringToLowerASCII(&name);
     if (name == L"display") {
-      string16 display;
-      GetStringAttribute(AccessibilityNodeData::ATTR_DISPLAY, &display);
+      string16 display = GetString16Attribute(
+          AccessibilityNodeData::ATTR_DISPLAY);
       style_values[i] = SysAllocString(display.c_str());
     } else {
       style_values[i] = NULL;
@@ -2579,12 +2637,8 @@
   if (!dom_text)
     return E_INVALIDARG;
 
-  if (name_.empty())
-    return S_FALSE;
-
-  *dom_text = SysAllocString(name_.c_str());
-  DCHECK(*dom_text);
-  return S_OK;
+  return GetStringAttributeAsBstr(
+      AccessibilityNodeData::ATTR_NAME, dom_text);
 }
 
 //
@@ -2773,24 +2827,7 @@
   if (ia_role_ == ROLE_SYSTEM_PROGRESSBAR ||
       ia_role_ == ROLE_SYSTEM_SCROLLBAR ||
       ia_role_ == ROLE_SYSTEM_SLIDER) {
-    float fval;
-    if (value_.empty() &&
-        GetFloatAttribute(AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, &fval)) {
-      // TODO(dmazzoni): Use ICU to localize this?
-      value_ = UTF8ToUTF16(base::DoubleToString(fval));
-    }
-    ia2_attributes_.push_back(L"valuetext:" + value_);
-  }
-
-  // Expose color well value.
-  if (ia2_role_ == IA2_ROLE_COLOR_CHOOSER) {
-    int r, g, b;
-    GetIntAttribute(AccessibilityNodeData::ATTR_COLOR_VALUE_RED, &r);
-    GetIntAttribute(AccessibilityNodeData::ATTR_COLOR_VALUE_GREEN, &g);
-    GetIntAttribute(AccessibilityNodeData::ATTR_COLOR_VALUE_BLUE, &b);
-    value_ = base::IntToString16((r * 100) / 255) + L"% red " +
-             base::IntToString16((g * 100) / 255) + L"% green " +
-             base::IntToString16((b * 100) / 255) + L"% blue";
+    ia2_attributes_.push_back(L"valuetext:" + GetValueText());
   }
 
   // Expose table cell index.
@@ -2799,7 +2836,8 @@
     while (table && table->role() != AccessibilityNodeData::ROLE_TABLE)
       table = table->parent();
     if (table) {
-      const std::vector<int32>& unique_cell_ids = table->unique_cell_ids();
+      const std::vector<int32>& unique_cell_ids = table->GetIntListAttribute(
+          AccessibilityNodeData::ATTR_UNIQUE_CELL_IDS);
       for (size_t i = 0; i < unique_cell_ids.size(); ++i) {
         if (unique_cell_ids[i] == renderer_id_) {
           ia2_attributes_.push_back(
@@ -2830,22 +2868,21 @@
   // always returns the primary name in "name" and the secondary name,
   // if any, in "description".
 
-  string16 description, help, title_attr;
-  int title_elem_id = 0;
-  GetIntAttribute(AccessibilityNodeData::ATTR_TITLE_UI_ELEMENT, &title_elem_id);
-  GetStringAttribute(AccessibilityNodeData::ATTR_DESCRIPTION, &description);
-  GetStringAttribute(AccessibilityNodeData::ATTR_HELP, &help);
+  int title_elem_id = GetIntAttribute(
+      AccessibilityNodeData::ATTR_TITLE_UI_ELEMENT);
+  std::string help = GetStringAttribute(AccessibilityNodeData::ATTR_HELP);
+  std::string description = GetStringAttribute(
+      AccessibilityNodeData::ATTR_DESCRIPTION);
 
   // WebKit annoyingly puts the title in the description if there's no other
   // description, which just confuses the rest of the logic. Put it back.
   // Now "help" is always the value of the "title" attribute, if present.
+  std::string title_attr;
   if (GetHtmlAttribute("title", &title_attr) &&
       description == title_attr &&
       help.empty()) {
     help = description;
     description.clear();
-    string_attributes_[AccessibilityNodeData::ATTR_DESCRIPTION].clear();
-    string_attributes_[AccessibilityNodeData::ATTR_HELP] = help;
   }
 
   // Now implement the main logic: the descripion should become the name if
@@ -2854,21 +2891,18 @@
   if (!description.empty()) {
     name_ = description;
     description.clear();
-    string_attributes_[AccessibilityNodeData::ATTR_DESCRIPTION] = description;
   }
   if (!help.empty() && description.empty()) {
     description = help;
-    string_attributes_[AccessibilityNodeData::ATTR_DESCRIPTION] = help;
-    string_attributes_[AccessibilityNodeData::ATTR_HELP].clear();
+    help.clear();
   }
   if (!description.empty() && name_.empty() && !title_elem_id) {
     name_ = description;
     description.clear();
-    string_attributes_[AccessibilityNodeData::ATTR_DESCRIPTION].clear();
   }
 
   // If it's a text field, also consider the placeholder.
-  string16 placeholder;
+  std::string placeholder;
   if (role_ == AccessibilityNodeData::ROLE_TEXT_FIELD &&
       HasState(AccessibilityNodeData::STATE_FOCUSABLE) &&
       GetHtmlAttribute("placeholder", &placeholder)) {
@@ -2876,10 +2910,12 @@
       name_ = placeholder;
     } else if (description.empty()) {
       description = placeholder;
-      string_attributes_[AccessibilityNodeData::ATTR_DESCRIPTION] = description;
     }
   }
 
+  SetStringAttribute(AccessibilityNodeData::ATTR_DESCRIPTION, description);
+  SetStringAttribute(AccessibilityNodeData::ATTR_HELP, help);
+
   // On Windows, the value of a document should be its url.
   if (role_ == AccessibilityNodeData::ROLE_ROOT_WEB_AREA ||
       role_ == AccessibilityNodeData::ROLE_WEB_AREA) {
@@ -2898,7 +2934,6 @@
 
   // If this doesn't have a value and is linked then set its value to the url
   // attribute. This allows screen readers to read an empty link's destination.
-  string16 url;
   if (value_.empty() && (ia_state_ & STATE_SYSTEM_LINKED))
     GetStringAttribute(AccessibilityNodeData::ATTR_URL, &value_);
 
@@ -2931,7 +2966,7 @@
   for (unsigned int i = 0; i < children().size(); ++i) {
     BrowserAccessibility* child = children()[i];
     if (child->role() == AccessibilityNodeData::ROLE_STATIC_TEXT) {
-      hypertext_ += child->name();
+      hypertext_ += UTF8ToUTF16(child->name());
     } else {
       hyperlink_offset_to_index_[hypertext_.size()] = hyperlinks_.size();
       hypertext_ += kEmbeddedCharacter;
@@ -3035,7 +3070,7 @@
     BSTR* value_bstr) {
   string16 str;
 
-  if (!GetStringAttribute(attribute, &str))
+  if (!GetString16Attribute(attribute, &str))
     return S_FALSE;
 
   if (str.empty())
@@ -3051,7 +3086,7 @@
     AccessibilityNodeData::StringAttribute attribute,
     const char* ia2_attr) {
   string16 value;
-  if (GetStringAttribute(attribute, &value))
+  if (GetString16Attribute(attribute, &value))
     ia2_attributes_.push_back(ASCIIToUTF16(ia2_attr) + L":" + value);
 }
 
@@ -3069,16 +3104,27 @@
     AccessibilityNodeData::IntAttribute attribute,
     const char* ia2_attr) {
   int value;
-  if (GetIntAttribute(attribute, &value))
+  if (GetIntAttribute(attribute, &value)) {
     ia2_attributes_.push_back(ASCIIToUTF16(ia2_attr) + L":" +
                               base::IntToString16(value));
+  }
 }
 
-const string16& BrowserAccessibilityWin::TextForIAccessibleText() {
+string16 BrowserAccessibilityWin::GetValueText() {
+  float fval;
+  string16 value = UTF8ToUTF16(value_);
+  if (value.empty() &&
+      GetFloatAttribute(AccessibilityNodeData::ATTR_VALUE_FOR_RANGE, &fval)) {
+    value = UTF8ToUTF16(base::DoubleToString(fval));
+  }
+  return value;
+}
+
+string16 BrowserAccessibilityWin::TextForIAccessibleText() {
   if (IsEditableText())
-    return value_;
+    return UTF8ToUTF16(value_);
   return (role_ == AccessibilityNodeData::ROLE_STATIC_TEXT) ?
-      name_ : hypertext_;
+      UTF8ToUTF16(name_) : hypertext_;
 }
 
 void BrowserAccessibilityWin::HandleSpecialTextOffset(const string16& text,
@@ -3111,8 +3157,10 @@
     ui::TextBoundaryDirection direction) {
   HandleSpecialTextOffset(text, &start_offset);
   ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary);
+  const std::vector<int32>& line_breaks = GetIntListAttribute(
+      AccessibilityNodeData::ATTR_LINE_BREAKS);
   return ui::FindAccessibleTextBoundary(
-      text, line_breaks_, boundary, start_offset, direction);
+      text, line_breaks, boundary, start_offset, direction);
 }
 
 BrowserAccessibilityWin* BrowserAccessibilityWin::GetFromRendererID(
@@ -3184,18 +3232,14 @@
   if (GetHtmlAttribute("aria-invalid", &invalid))
     ia2_state_ |= IA2_STATE_INVALID_ENTRY;
 
-  bool mixed = false;
-  GetBoolAttribute(AccessibilityNodeData::ATTR_BUTTON_MIXED, &mixed);
-  if (mixed)
+  if (GetBoolAttribute(AccessibilityNodeData::ATTR_BUTTON_MIXED))
     ia_state_ |= STATE_SYSTEM_MIXED;
 
-  bool editable = false;
-  GetBoolAttribute(AccessibilityNodeData::ATTR_CAN_SET_VALUE, &editable);
-  if (editable)
+  if (GetBoolAttribute(AccessibilityNodeData::ATTR_CAN_SET_VALUE))
     ia2_state_ |= IA2_STATE_EDITABLE;
 
-  string16 html_tag;
-  GetStringAttribute(AccessibilityNodeData::ATTR_HTML_TAG, &html_tag);
+  string16 html_tag = GetString16Attribute(
+      AccessibilityNodeData::ATTR_HTML_TAG);
   ia_role_ = 0;
   ia2_role_ = 0;
   switch (role_) {
@@ -3307,8 +3351,8 @@
       ia_state_ |= STATE_SYSTEM_READONLY;
       break;
     case AccessibilityNodeData::ROLE_GROUP: {
-      string16 aria_role;
-      GetStringAttribute(AccessibilityNodeData::ATTR_ROLE, &aria_role);
+      string16 aria_role = GetString16Attribute(
+          AccessibilityNodeData::ATTR_ROLE);
       if (aria_role == L"group" || html_tag == L"fieldset") {
         ia_role_ = ROLE_SYSTEM_GROUPING;
       } else if (html_tag == L"li") {
@@ -3507,8 +3551,8 @@
       ia_role_ = ROLE_SYSTEM_PAGETAB;
       break;
     case AccessibilityNodeData::ROLE_TABLE: {
-      string16 aria_role;
-      GetStringAttribute(AccessibilityNodeData::ATTR_ROLE, &aria_role);
+      string16 aria_role = GetString16Attribute(
+          AccessibilityNodeData::ATTR_ROLE);
       if (aria_role == L"treegrid") {
         ia_role_ = ROLE_SYSTEM_OUTLINE;
       } else {
@@ -3609,9 +3653,7 @@
   }
   if (!HasState(AccessibilityNodeData::STATE_READONLY))
     ia_state_ &= ~(STATE_SYSTEM_READONLY);
-  bool aria_readonly = false;
-  GetBoolAttribute(AccessibilityNodeData::ATTR_ARIA_READONLY, &aria_readonly);
-  if (aria_readonly)
+  if (GetBoolAttribute(AccessibilityNodeData::ATTR_ARIA_READONLY))
     ia_state_ |= STATE_SYSTEM_READONLY;
 
   // The role should always be set.
diff --git a/content/browser/accessibility/browser_accessibility_win.h b/content/browser/accessibility/browser_accessibility_win.h
index b659932..db8040e 100644
--- a/content/browser/accessibility/browser_accessibility_win.h
+++ b/content/browser/accessibility/browser_accessibility_win.h
@@ -771,6 +771,7 @@
   // Accessors.
   int32 ia_role() const { return ia_role_; }
   int32 ia_state() const { return ia_state_; }
+  const string16& role_name() const { return role_name_; }
   int32 ia2_role() const { return ia2_role_; }
   int32 ia2_state() const { return ia2_state_; }
   const std::vector<string16>& ia2_attributes() const {
@@ -816,9 +817,13 @@
   void IntAttributeToIA2(AccessibilityNodeData::IntAttribute attribute,
                          const char* ia2_attr);
 
+  // Get the value text, which might come from the floating-point
+  // value for some roles.
+  string16 GetValueText();
+
   // Get the text of this node for the purposes of IAccessibleText - it may
   // be the name, it may be the value, etc. depending on the role.
-  const string16& TextForIAccessibleText();
+  string16 TextForIAccessibleText();
 
   // If offset is a member of IA2TextSpecialOffsets this function updates the
   // value of offset and returns, otherwise offset remains unchanged.
@@ -847,6 +852,7 @@
   // IAccessible role and state.
   int32 ia_role_;
   int32 ia_state_;
+  string16 role_name_;
 
   // IAccessible2 role and state.
   int32 ia2_role_;
diff --git a/content/browser/accessibility/browser_accessibility_win_unittest.cc b/content/browser/accessibility/browser_accessibility_win_unittest.cc
index 98a5d40..c65c1f3 100644
--- a/content/browser/accessibility/browser_accessibility_win_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_win_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/scoped_variant.h"
@@ -113,19 +114,19 @@
   // BrowserAccessibilityManager.
   AccessibilityNodeData button;
   button.id = 2;
-  button.name = L"Button";
+  button.SetName("Button");
   button.role = AccessibilityNodeData::ROLE_BUTTON;
   button.state = 0;
 
   AccessibilityNodeData checkbox;
   checkbox.id = 3;
-  checkbox.name = L"Checkbox";
+  checkbox.SetName("Checkbox");
   checkbox.role = AccessibilityNodeData::ROLE_CHECKBOX;
   checkbox.state = 0;
 
   AccessibilityNodeData root;
   root.id = 1;
-  root.name = L"Document";
+  root.SetName("Document");
   root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA;
   root.state = 0;
   root.child_ids.push_back(2);
@@ -183,12 +184,12 @@
   AccessibilityNodeData text;
   text.id = 2;
   text.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
-  text.name = L"old text";
+  text.SetName("old text");
   text.state = 0;
 
   AccessibilityNodeData root;
   root.id = 1;
-  root.name = L"Document";
+  root.SetName("Document");
   root.role = AccessibilityNodeData::ROLE_ROOT_WEB_AREA;
   root.state = 0;
   root.child_ids.push_back(2);
@@ -225,11 +226,15 @@
   text_accessible.Release();
 
   // Notify the BrowserAccessibilityManager that the text child has changed.
-  text.name = L"new text";
+  AccessibilityNodeData text2;
+  text2.id = 2;
+  text2.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
+  text2.SetName("new text");
+  text2.SetName("old text");
   AccessibilityHostMsg_NotificationParams param;
   param.notification_type = AccessibilityNotificationChildrenChanged;
-  param.nodes.push_back(text);
-  param.id = text.id;
+  param.nodes.push_back(text2);
+  param.id = text2.id;
   std::vector<AccessibilityHostMsg_NotificationParams> notifications;
   notifications.push_back(param);
   manager->OnAccessibilityNotifications(notifications);
@@ -314,12 +319,17 @@
 }
 
 TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
+  std::string text1_value = "One two three.\nFour five six.";
+
   AccessibilityNodeData text1;
   text1.id = 11;
   text1.role = AccessibilityNodeData::ROLE_TEXT_FIELD;
   text1.state = 0;
-  text1.value = L"One two three.\nFour five six.";
-  text1.line_breaks.push_back(15);
+  text1.AddStringAttribute(AccessibilityNodeData::ATTR_VALUE, text1_value);
+  std::vector<int32> line_breaks;
+  line_breaks.push_back(15);
+  text1.AddIntListAttribute(
+      AccessibilityNodeData::ATTR_LINE_BREAKS, line_breaks);
 
   AccessibilityNodeData root;
   root.id = 1;
@@ -344,7 +354,7 @@
 
   base::win::ScopedBstr text;
   ASSERT_EQ(S_OK, text1_obj->get_text(0, text1_len, text.Receive()));
-  ASSERT_EQ(text1.value, string16(text));
+  ASSERT_EQ(text1_value, base::UTF16ToUTF8(string16(text)));
   text.Reset();
 
   ASSERT_EQ(S_OK, text1_obj->get_text(0, 4, text.Receive()));
@@ -405,17 +415,20 @@
 }
 
 TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
+  const std::string text1_name = "One two three.";
+  const std::string text2_name = " Four five six.";
+
   AccessibilityNodeData text1;
   text1.id = 11;
   text1.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
   text1.state = 1 << AccessibilityNodeData::STATE_READONLY;
-  text1.name = L"One two three.";
+  text1.SetName(text1_name);
 
   AccessibilityNodeData text2;
   text2.id = 12;
   text2.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
   text2.state = 1 << AccessibilityNodeData::STATE_READONLY;
-  text2.name = L" Four five six.";
+  text2.SetName(text2_name);
 
   AccessibilityNodeData root;
   root.id = 1;
@@ -439,7 +452,7 @@
 
   base::win::ScopedBstr text;
   ASSERT_EQ(S_OK, root_obj->get_text(0, text_len, text.Receive()));
-  EXPECT_EQ(text1.name + text2.name, string16(text));
+  EXPECT_EQ(text1_name + text2_name, base::UTF16ToUTF8(string16(text)));
 
   long hyperlink_count;
   ASSERT_EQ(S_OK, root_obj->get_nHyperlinks(&hyperlink_count));
@@ -468,22 +481,27 @@
 }
 
 TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
+  const std::string text1_name = "One two three.";
+  const std::string text2_name = " Four five six.";
+  const std::string button1_text_name = "red";
+  const std::string link1_text_name = "blue";
+
   AccessibilityNodeData text1;
   text1.id = 11;
   text1.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
   text1.state = 1 << AccessibilityNodeData::STATE_READONLY;
-  text1.name = L"One two three.";
+  text1.SetName(text1_name);
 
   AccessibilityNodeData text2;
   text2.id = 12;
   text2.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
   text2.state = 1 << AccessibilityNodeData::STATE_READONLY;
-  text2.name = L" Four five six.";
+  text2.SetName(text2_name);
 
   AccessibilityNodeData button1, button1_text;
   button1.id = 13;
   button1_text.id = 15;
-  button1_text.name = L"red";
+  button1_text.SetName(button1_text_name);
   button1.role = AccessibilityNodeData::ROLE_BUTTON;
   button1_text.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
   button1.state = 1 << AccessibilityNodeData::STATE_READONLY;
@@ -493,7 +511,7 @@
   AccessibilityNodeData link1, link1_text;
   link1.id = 14;
   link1_text.id = 16;
-  link1_text.name = L"blue";
+  link1_text.SetName(link1_text_name);
   link1.role = AccessibilityNodeData::ROLE_LINK;
   link1_text.role = AccessibilityNodeData::ROLE_STATIC_TEXT;
   link1.state = 1 << AccessibilityNodeData::STATE_READONLY;
@@ -527,8 +545,10 @@
 
   base::win::ScopedBstr text;
   ASSERT_EQ(S_OK, root_obj->get_text(0, text_len, text.Receive()));
-  const string16 embed = BrowserAccessibilityWin::kEmbeddedCharacter;
-  EXPECT_EQ(text1.name + embed + text2.name + embed, string16(text));
+  const std::string embed = base::UTF16ToUTF8(
+      BrowserAccessibilityWin::kEmbeddedCharacter);
+  EXPECT_EQ(text1_name + embed + text2_name + embed,
+            UTF16ToUTF8(string16(text)));
   text.Reset();
 
   long hyperlink_count;
@@ -545,7 +565,8 @@
   EXPECT_EQ(S_OK,
             hyperlink.QueryInterface<IAccessibleText>(hypertext.Receive()));
   EXPECT_EQ(S_OK, hypertext->get_text(0, 3, text.Receive()));
-  EXPECT_STREQ(L"red", text);
+  EXPECT_STREQ(button1_text_name.c_str(),
+               base::UTF16ToUTF8(string16(text)).c_str());
   text.Reset();
   hyperlink.Release();
   hypertext.Release();
@@ -554,7 +575,8 @@
   EXPECT_EQ(S_OK,
             hyperlink.QueryInterface<IAccessibleText>(hypertext.Receive()));
   EXPECT_EQ(S_OK, hypertext->get_text(0, 4, text.Receive()));
-  EXPECT_STREQ(L"blue", text);
+  EXPECT_STREQ(link1_text_name.c_str(),
+               base::UTF16ToUTF8(string16(text)).c_str());
   text.Reset();
   hyperlink.Release();
   hypertext.Release();
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index 5e3effe..1acceab 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -10,7 +10,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_widget_host_view.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/accessibility_browser_test_utils.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
@@ -89,16 +89,15 @@
 }
 
 // Convenience method to get the value of a particular AccessibilityNodeData
-// node attribute as a UTF-8 const char*.
+// node attribute as a UTF-8 string.
 std::string CrossPlatformAccessibilityBrowserTest::GetAttr(
     const AccessibilityNodeData& node,
     const AccessibilityNodeData::StringAttribute attr) {
-  std::map<AccessibilityNodeData::StringAttribute, string16>::const_iterator
-      iter = node.string_attributes.find(attr);
-  if (iter != node.string_attributes.end())
-    return UTF16ToUTF8(iter->second);
-  else
-    return std::string();
+  for (size_t i = 0; i < node.string_attributes.size(); ++i) {
+    if (node.string_attributes[i].first == attr)
+      return node.string_attributes[i].second;
+  }
+  return std::string();
 }
 
 // Convenience method to get the value of a particular AccessibilityNodeData
@@ -106,12 +105,11 @@
 int CrossPlatformAccessibilityBrowserTest::GetIntAttr(
     const AccessibilityNodeData& node,
     const AccessibilityNodeData::IntAttribute attr) {
-  std::map<AccessibilityNodeData::IntAttribute, int32>::const_iterator iter =
-      node.int_attributes.find(attr);
-  if (iter != node.int_attributes.end())
-    return iter->second;
-  else
-    return -1;
+  for (size_t i = 0; i < node.int_attributes.size(); ++i) {
+    if (node.int_attributes[i].first == attr)
+      return node.int_attributes[i].second;
+  }
+  return -1;
 }
 
 // Convenience method to get the value of a particular AccessibilityNodeData
@@ -119,12 +117,11 @@
 bool CrossPlatformAccessibilityBrowserTest::GetBoolAttr(
     const AccessibilityNodeData& node,
     const AccessibilityNodeData::BoolAttribute attr) {
-  std::map<AccessibilityNodeData::BoolAttribute, bool>::const_iterator iter =
-      node.bool_attributes.find(attr);
-  if (iter != node.bool_attributes.end())
-    return iter->second;
-  else
-    return false;
+  for (size_t i = 0; i < node.bool_attributes.size(); ++i) {
+    if (node.bool_attributes[i].first == attr)
+      return node.bool_attributes[i].second;
+  }
+  return false;
 }
 
 // Marked flaky per http://crbug.com/101984
@@ -152,7 +149,9 @@
   EXPECT_STREQ(
       "text/html",
       GetAttr(tree, AccessibilityNodeData::ATTR_DOC_MIMETYPE).c_str());
-  EXPECT_STREQ("Accessibility Test", UTF16ToUTF8(tree.name).c_str());
+  EXPECT_STREQ(
+      "Accessibility Test",
+      GetAttr(tree, AccessibilityNodeData::ATTR_NAME).c_str());
   EXPECT_EQ(AccessibilityNodeData::ROLE_ROOT_WEB_AREA, tree.role);
 
   // Check properites of the BODY element.
@@ -171,15 +170,17 @@
   EXPECT_EQ(AccessibilityNodeData::ROLE_BUTTON, button.role);
   EXPECT_STREQ(
       "input", GetAttr(button, AccessibilityNodeData::ATTR_HTML_TAG).c_str());
-  EXPECT_STREQ("push", UTF16ToUTF8(button.name).c_str());
+  EXPECT_STREQ(
+      "push",
+      GetAttr(button, AccessibilityNodeData::ATTR_NAME).c_str());
   EXPECT_STREQ(
       "inline-block",
       GetAttr(button, AccessibilityNodeData::ATTR_DISPLAY).c_str());
   ASSERT_EQ(2U, button.html_attributes.size());
-  EXPECT_STREQ("type", UTF16ToUTF8(button.html_attributes[0].first).c_str());
-  EXPECT_STREQ("button", UTF16ToUTF8(button.html_attributes[0].second).c_str());
-  EXPECT_STREQ("value", UTF16ToUTF8(button.html_attributes[1].first).c_str());
-  EXPECT_STREQ("push", UTF16ToUTF8(button.html_attributes[1].second).c_str());
+  EXPECT_STREQ("type", button.html_attributes[0].first.c_str());
+  EXPECT_STREQ("button", button.html_attributes[0].second.c_str());
+  EXPECT_STREQ("value", button.html_attributes[1].first.c_str());
+  EXPECT_STREQ("push", button.html_attributes[1].second.c_str());
 
   const AccessibilityNodeDataTreeNode& checkbox = body.children[1];
   EXPECT_EQ(AccessibilityNodeData::ROLE_CHECKBOX, checkbox.role);
@@ -189,10 +190,8 @@
       "inline-block",
       GetAttr(checkbox, AccessibilityNodeData::ATTR_DISPLAY).c_str());
   ASSERT_EQ(1U, checkbox.html_attributes.size());
-  EXPECT_STREQ(
-      "type", UTF16ToUTF8(checkbox.html_attributes[0].first).c_str());
-  EXPECT_STREQ(
-    "checkbox", UTF16ToUTF8(checkbox.html_attributes[0].second).c_str());
+  EXPECT_STREQ("type", checkbox.html_attributes[0].first.c_str());
+  EXPECT_STREQ("checkbox", checkbox.html_attributes[0].second.c_str());
 }
 
 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
@@ -217,7 +216,9 @@
       "input", GetAttr(text, AccessibilityNodeData::ATTR_HTML_TAG).c_str());
   EXPECT_EQ(0, GetIntAttr(text, AccessibilityNodeData::ATTR_TEXT_SEL_START));
   EXPECT_EQ(0, GetIntAttr(text, AccessibilityNodeData::ATTR_TEXT_SEL_END));
-  EXPECT_STREQ("Hello, world.", UTF16ToUTF8(text.value).c_str());
+  EXPECT_STREQ(
+      "Hello, world.",
+      GetAttr(text, AccessibilityNodeData::ATTR_VALUE).c_str());
 
   // TODO(dmazzoni): as soon as more accessibility code is cross-platform,
   // this code should test that the accessible info is dynamically updated
@@ -246,7 +247,9 @@
       "input", GetAttr(text, AccessibilityNodeData::ATTR_HTML_TAG).c_str());
   EXPECT_EQ(0, GetIntAttr(text, AccessibilityNodeData::ATTR_TEXT_SEL_START));
   EXPECT_EQ(13, GetIntAttr(text, AccessibilityNodeData::ATTR_TEXT_SEL_END));
-  EXPECT_STREQ("Hello, world.", UTF16ToUTF8(text.value).c_str());
+  EXPECT_STREQ(
+      "Hello, world.",
+      GetAttr(text, AccessibilityNodeData::ATTR_VALUE).c_str());
 }
 
 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
@@ -276,13 +279,22 @@
   const AccessibilityNodeDataTreeNode& column1 = table.children[1];
   EXPECT_EQ(AccessibilityNodeData::ROLE_COLUMN, column1.role);
   EXPECT_EQ(0U, column1.children.size());
-  EXPECT_EQ(1U, column1.indirect_child_ids.size());
-  EXPECT_EQ(cell1.id, column1.indirect_child_ids[0]);
+  EXPECT_EQ(1U, column1.intlist_attributes.size());
+  EXPECT_EQ(AccessibilityNodeData::ATTR_INDIRECT_CHILD_IDS,
+            column1.intlist_attributes[0].first);
+  const std::vector<int32> column1_indirect_child_ids =
+      column1.intlist_attributes[0].second;
+  EXPECT_EQ(1U, column1_indirect_child_ids.size());
+  EXPECT_EQ(cell1.id, column1_indirect_child_ids[0]);
   const AccessibilityNodeDataTreeNode& column2 = table.children[2];
   EXPECT_EQ(AccessibilityNodeData::ROLE_COLUMN, column2.role);
   EXPECT_EQ(0U, column2.children.size());
-  EXPECT_EQ(1U, column2.indirect_child_ids.size());
-  EXPECT_EQ(cell2.id, column2.indirect_child_ids[0]);
+  EXPECT_EQ(AccessibilityNodeData::ATTR_INDIRECT_CHILD_IDS,
+            column2.intlist_attributes[0].first);
+  const std::vector<int32> column2_indirect_child_ids =
+      column2.intlist_attributes[0].second;
+  EXPECT_EQ(1U, column2_indirect_child_ids.size());
+  EXPECT_EQ(cell2.id, column2_indirect_child_ids[0]);
 }
 
 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
@@ -329,7 +341,9 @@
 
   const AccessibilityNodeDataTreeNode& button1 = body.children[0];
   EXPECT_EQ(AccessibilityNodeData::ROLE_BUTTON, button1.role);
-  EXPECT_STREQ("Button 1", UTF16ToUTF8(button1.name).c_str());
+  EXPECT_STREQ(
+      "Button 1",
+      GetAttr(button1, AccessibilityNodeData::ATTR_NAME).c_str());
 
   const AccessibilityNodeDataTreeNode& iframe = body.children[1];
   EXPECT_STREQ("iframe",
@@ -349,11 +363,13 @@
 
   const AccessibilityNodeDataTreeNode& button2 = sub_body.children[0];
   EXPECT_EQ(AccessibilityNodeData::ROLE_BUTTON, button2.role);
-  EXPECT_STREQ("Button 2", UTF16ToUTF8(button2.name).c_str());
+  EXPECT_STREQ("Button 2",
+               GetAttr(button2, AccessibilityNodeData::ATTR_NAME).c_str());
 
   const AccessibilityNodeDataTreeNode& button3 = body.children[2];
   EXPECT_EQ(AccessibilityNodeData::ROLE_BUTTON, button3.role);
-  EXPECT_STREQ("Button 3", UTF16ToUTF8(button3.name).c_str());
+  EXPECT_STREQ("Button 3",
+               GetAttr(button3, AccessibilityNodeData::ATTR_NAME).c_str());
 }
 
 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
@@ -413,13 +429,17 @@
   const AccessibilityNodeDataTreeNode& cell3 = table.children[1].children[0];
   const AccessibilityNodeDataTreeNode& cell4 = table.children[1].children[1];
 
-  ASSERT_EQ(6U, table.cell_ids.size());
-  EXPECT_EQ(cell1.id, table.cell_ids[0]);
-  EXPECT_EQ(cell1.id, table.cell_ids[1]);
-  EXPECT_EQ(cell2.id, table.cell_ids[2]);
-  EXPECT_EQ(cell3.id, table.cell_ids[3]);
-  EXPECT_EQ(cell4.id, table.cell_ids[4]);
-  EXPECT_EQ(cell4.id, table.cell_ids[5]);
+  ASSERT_EQ(AccessibilityNodeData::ATTR_CELL_IDS,
+            table.intlist_attributes[0].first);
+  const std::vector<int32>& table_cell_ids =
+      table.intlist_attributes[0].second;
+  ASSERT_EQ(6U, table_cell_ids.size());
+  EXPECT_EQ(cell1.id, table_cell_ids[0]);
+  EXPECT_EQ(cell1.id, table_cell_ids[1]);
+  EXPECT_EQ(cell2.id, table_cell_ids[2]);
+  EXPECT_EQ(cell3.id, table_cell_ids[3]);
+  EXPECT_EQ(cell4.id, table_cell_ids[4]);
+  EXPECT_EQ(cell4.id, table_cell_ids[5]);
 
   EXPECT_EQ(0, GetIntAttr(cell1,
                           AccessibilityNodeData::ATTR_TABLE_CELL_COLUMN_INDEX));
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index d0ff119..355cc32 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -21,7 +21,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/url_constants.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/accessibility_browser_test_utils.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc
index 35da3af..5e7940d 100644
--- a/content/browser/android/browser_jni_registrar.cc
+++ b/content/browser/android/browser_jni_registrar.cc
@@ -9,7 +9,7 @@
 #include "content/browser/accessibility/browser_accessibility_android.h"
 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
 #include "content/browser/android/android_browser_process.h"
-#include "content/browser/android/browser_startup_config.h"
+#include "content/browser/android/browser_startup_controller.h"
 #include "content/browser/android/child_process_launcher_android.h"
 #include "content/browser/android/content_settings.h"
 #include "content/browser/android/content_video_view.h"
@@ -42,7 +42,7 @@
     {"AndroidBrowserProcess", content::RegisterAndroidBrowserProcess},
     {"BrowserAccessibilityManager",
      content::RegisterBrowserAccessibilityManager},
-    {"BrowserStartupConfiguration", content::RegisterBrowserStartupConfig},
+    {"BrowserStartupController", content::RegisterBrowserStartupController},
     {"ChildProcessLauncher", content::RegisterChildProcessLauncher},
     {"ContentSettings", content::ContentSettings::RegisterContentSettings},
     {"ContentViewRenderView",
diff --git a/content/browser/android/browser_startup_config.cc b/content/browser/android/browser_startup_config.cc
deleted file mode 100644
index 3e74208..0000000
--- a/content/browser/android/browser_startup_config.cc
+++ /dev/null
@@ -1,25 +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/android/browser_startup_config.h"
-
-#include "base/android/jni_android.h"
-#include "jni/BrowserStartupConfig_jni.h"
-
-namespace content {
-
-bool BrowserMayStartAsynchronously() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  return Java_BrowserStartupConfig_browserMayStartAsynchonously(env);
-}
-
-void BrowserStartupComplete(int result) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_BrowserStartupConfig_browserStartupComplete(env, result);
-}
-
-bool RegisterBrowserStartupConfig(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-}  // namespace content
diff --git a/content/browser/android/browser_startup_config.h b/content/browser/android/browser_startup_config.h
deleted file mode 100644
index 95575f2..0000000
--- a/content/browser/android/browser_startup_config.h
+++ /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.
-
-#ifndef CONTENT_BROWSER_BROWSER_STARTUP_CONFIGURATION_H_
-#define CONTENT_BROWSER_BROWSER_STARTUP_CONFIGURATION_H_
-
-#include <jni.h>
-
-namespace content {
-
-bool BrowserMayStartAsynchronously();
-void BrowserStartupComplete(int result);
-
-bool RegisterBrowserStartupConfig(JNIEnv* env);
-
-}  // namespace content
-#endif  // CONTENT_BROWSER_BROWSER_STARTUP_CONFIGURATION_H_
diff --git a/content/browser/android/browser_startup_controller.cc b/content/browser/android/browser_startup_controller.cc
new file mode 100644
index 0000000..6b90ce2
--- /dev/null
+++ b/content/browser/android/browser_startup_controller.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 "content/browser/android/browser_startup_controller.h"
+
+#include "base/android/jni_android.h"
+#include "jni/BrowserStartupController_jni.h"
+
+namespace content {
+
+bool BrowserMayStartAsynchronously() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return Java_BrowserStartupController_browserMayStartAsynchonously(env);
+}
+
+void BrowserStartupComplete(int result) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_BrowserStartupController_browserStartupComplete(env, result);
+}
+
+bool RegisterBrowserStartupController(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+}  // namespace content
diff --git a/content/browser/android/browser_startup_controller.h b/content/browser/android/browser_startup_controller.h
new file mode 100644
index 0000000..6fa334e
--- /dev/null
+++ b/content/browser/android/browser_startup_controller.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 CONTENT_BROWSER_BROWSER_STARTUP_CONTROLLER_H_
+#define CONTENT_BROWSER_BROWSER_STARTUP_CONTROLLER_H_
+
+#include <jni.h>
+
+namespace content {
+
+bool BrowserMayStartAsynchronously();
+void BrowserStartupComplete(int result);
+
+bool RegisterBrowserStartupController(JNIEnv* env);
+
+}  // namespace content
+#endif  // CONTENT_BROWSER_BROWSER_STARTUP_CONTROLLER_H_
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 80fe628..7f13d6c 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -1472,14 +1472,22 @@
 void ContentViewCoreImpl::EvaluateJavaScript(JNIEnv* env,
                                              jobject obj,
                                              jstring script,
-                                             jobject callback) {
-  RenderViewHost* host = web_contents_->GetRenderViewHost();
-  DCHECK(host);
+                                             jobject callback,
+                                             jboolean start_renderer) {
+  RenderViewHost* rvh = web_contents_->GetRenderViewHost();
+  DCHECK(rvh);
+
+  if (start_renderer && !rvh->IsRenderViewLive()) {
+    if (!web_contents_->CreateRenderViewForInitialEmptyDocument()) {
+      LOG(ERROR) << "Failed to create RenderView in EvaluateJavaScript";
+      return;
+    }
+  }
 
   if (!callback) {
     // No callback requested.
-    host->ExecuteJavascriptInWebFrame(string16(),  // frame_xpath
-                                      ConvertJavaStringToUTF16(env, script));
+    rvh->ExecuteJavascriptInWebFrame(string16(),  // frame_xpath
+                                     ConvertJavaStringToUTF16(env, script));
     return;
   }
 
@@ -1490,7 +1498,7 @@
   content::RenderViewHost::JavascriptResultCallback c_callback =
       base::Bind(&JavaScriptResultCallback, j_callback);
 
-  host->ExecuteJavascriptInWebFrameCallbackResult(
+  rvh->ExecuteJavascriptInWebFrameCallbackResult(
       string16(),  // frame_xpath
       ConvertJavaStringToUTF16(env, script),
       c_callback);
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index ab7da6d..f3cf755 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -155,7 +155,8 @@
   void EvaluateJavaScript(JNIEnv* env,
                           jobject obj,
                           jstring script,
-                          jobject callback);
+                          jobject callback,
+                          jboolean start_renderer);
   int GetNativeImeAdapter(JNIEnv* env, jobject obj);
   void SetFocus(JNIEnv* env, jobject obj, jboolean focused);
   void ScrollFocusedEditableNodeIntoView(JNIEnv* env, jobject obj);
diff --git a/content/browser/android/date_time_chooser_android.cc b/content/browser/android/date_time_chooser_android.cc
index 0c3ba2d..7c91ff0 100644
--- a/content/browser/android/date_time_chooser_android.cc
+++ b/content/browser/android/date_time_chooser_android.cc
@@ -24,7 +24,14 @@
   explicit DateTimeIPCSender(RenderViewHost* sender);
   virtual ~DateTimeIPCSender() {}
   void ReplaceDateTime(int dialog_type,
-      int year, int month, int day, int hour, int minute, int second, int week);
+                       int year,
+                       int month,
+                       int day,
+                       int hour,
+                       int minute,
+                       int second,
+                       int milli,
+                       int week);
   void CancelDialog();
 
  private:
@@ -36,9 +43,15 @@
   : RenderViewHostObserver(sender) {
 }
 
-void DateTimeChooserAndroid::DateTimeIPCSender::ReplaceDateTime(
-    int dialog_type,
-    int year, int month, int day, int hour, int minute, int second, int week) {
+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;
@@ -46,6 +59,7 @@
   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));
@@ -76,30 +90,60 @@
          text_input_type_time, text_input_type_week);
 }
 
-void DateTimeChooserAndroid::ReplaceDateTime(
-    JNIEnv* env, jobject, int dialog_type,
-    int year, int month, int day, int hour, int minute, int second, int week) {
+void DateTimeChooserAndroid::ReplaceDateTime(JNIEnv* env,
+                                             jobject,
+                                             int dialog_type,
+                                             int year,
+                                             int month,
+                                             int day,
+                                             int hour,
+                                             int minute,
+                                             int second,
+                                             int milli,
+                                             int week) {
   sender_->ReplaceDateTime(
-      dialog_type, year, month, day, hour, minute, second, week);
+      dialog_type, year, month, day, hour, minute, second, milli, week);
 }
 
 void DateTimeChooserAndroid::CancelDialog(JNIEnv* env, jobject) {
   sender_->CancelDialog();
 }
 
-void DateTimeChooserAndroid::ShowDialog(
-    ContentViewCore* content, RenderViewHost* sender,
-    int type, int year, int month, int day,
-    int hour, int minute, int second, int week, double min, double max) {
+void DateTimeChooserAndroid::ShowDialog(ContentViewCore* content,
+                                        RenderViewHost* sender,
+                                        int type,
+                                        int year,
+                                        int month,
+                                        int day,
+                                        int hour,
+                                        int minute,
+                                        int second,
+                                        int milli,
+                                        int week,
+                                        double min,
+                                        double max,
+                                        double step) {
   if (sender_)
     delete sender_;
   sender_ = new DateTimeIPCSender(sender);
 
   JNIEnv* env = AttachCurrentThread();
   j_date_time_chooser_.Reset(Java_DateTimeChooserAndroid_createDateTimeChooser(
-      env, content->GetJavaObject().obj(),
+      env,
+      content->GetJavaObject().obj(),
       reinterpret_cast<intptr_t>(this),
-      type, year, month, day, hour, minute, second, week, min, max));
+      type,
+      year,
+      month,
+      day,
+      hour,
+      minute,
+      second,
+      milli,
+      week,
+      min,
+      max,
+      step));
 }
 
 // ----------------------------------------------------------------------------
diff --git a/content/browser/android/date_time_chooser_android.h b/content/browser/android/date_time_chooser_android.h
index 646ba3c..68cb456 100644
--- a/content/browser/android/date_time_chooser_android.h
+++ b/content/browser/android/date_time_chooser_android.h
@@ -24,14 +24,31 @@
   // DateTimeChooser implementation:
   void ShowDialog(ContentViewCore* content,
                   RenderViewHost* sender,
-                  int type, int year, int month, int day,
-                  int hour, int minute, int second, int week,
-                  double min, double max);
+                  int type,
+                  int year,
+                  int month,
+                  int day,
+                  int hour,
+                  int minute,
+                  int second,
+                  int milli,
+                  int week,
+                  double min,
+                  double max,
+                  double step);
 
   // Replaces the current value with the one passed the different fields
-  void ReplaceDateTime(JNIEnv* env, jobject, jint dialog_type,
-                       jint year, jint month, jint day,
-                       jint hour, jint minute, jint second, jint week);
+  void ReplaceDateTime(JNIEnv* env,
+                       jobject,
+                       jint dialog_type,
+                       jint year,
+                       jint month,
+                       jint day,
+                       jint hour,
+                       jint minute,
+                       jint second,
+                       jint milli,
+                       jint week);
 
   // Closes the dialog without propagating any changes.
   void CancelDialog(JNIEnv* env, jobject);
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index 74048d8..8fcebf4 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -16,13 +16,20 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/renderer/android/synchronous_compositor_factory.h"
+#include "content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h"
+#include "gpu/command_buffer/client/gl_in_process_context.h"
+#include "gpu/command_buffer/service/stream_texture_manager_in_process_android.h"
+#include "ui/gl/android/surface_texture_bridge.h"
 #include "ui/gl/gl_surface.h"
 #include "webkit/common/gpu/context_provider_in_process.h"
+#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 
 namespace content {
 
 namespace {
 
+using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+
 int GetInProcessRendererId() {
   content::RenderProcessHost::iterator it =
       content::RenderProcessHost::AllHostsIterator();
@@ -38,9 +45,38 @@
   return id;
 }
 
+class VideoContextProvider
+    : public StreamTextureFactorySynchronousImpl::ContextProvider {
+ public:
+  VideoContextProvider(
+      const scoped_refptr<cc::ContextProvider>& context_provider,
+      gpu::GLInProcessContext* gl_in_process_context)
+      : context_provider_(context_provider),
+        gl_in_process_context_(gl_in_process_context) {}
+
+  virtual scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture(
+      uint32 stream_id) OVERRIDE {
+    return gl_in_process_context_->GetSurfaceTexture(stream_id);
+  }
+
+  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+    return context_provider_->Context3d();
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<VideoContextProvider>;
+  virtual ~VideoContextProvider() {}
+
+  scoped_refptr<cc::ContextProvider> context_provider_;
+  gpu::GLInProcessContext* gl_in_process_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(VideoContextProvider);
+};
+
 class SynchronousCompositorFactoryImpl : public SynchronousCompositorFactory {
  public:
-  SynchronousCompositorFactoryImpl() {
+  SynchronousCompositorFactoryImpl()
+      : wrapped_gl_context_for_main_thread_(NULL) {
     SynchronousCompositorFactory::SetInstance(this);
   }
 
@@ -65,15 +101,52 @@
     return &synchronous_input_event_filter_;
   }
 
+  scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
+  CreateOffscreenContext() {
+    if (!gfx::GLSurface::InitializeOneOff())
+      return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
+
+    const char* allowed_extensions = "*";
+    const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
+
+    WebKit::WebGraphicsContext3D::Attributes attributes;
+    attributes.antialias = false;
+    attributes.shareResources = true;
+    attributes.noAutomaticFlushes = true;
+
+    gpu::GLInProcessContextAttribs in_process_attribs;
+    WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
+        attributes, &in_process_attribs);
+    scoped_ptr<gpu::GLInProcessContext> context(
+        gpu::GLInProcessContext::CreateContext(true,
+                                               NULL,
+                                               gfx::Size(1, 1),
+                                               attributes.shareResources,
+                                               allowed_extensions,
+                                               in_process_attribs,
+                                               gpu_preference));
+
+    wrapped_gl_context_for_main_thread_ = context.get();
+    if (!context.get())
+      return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
+
+    return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
+        WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
+            context.Pass(), attributes));
+  }
+
   virtual scoped_refptr<cc::ContextProvider>
   GetOffscreenContextProviderForMainThread() OVERRIDE {
     if (!offscreen_context_for_main_thread_.get() ||
         offscreen_context_for_main_thread_->DestroyedOnMainThread()) {
       offscreen_context_for_main_thread_ =
-          webkit::gpu::ContextProviderInProcess::Create();
+          webkit::gpu::ContextProviderInProcess::Create(
+              CreateOffscreenContext());
       if (offscreen_context_for_main_thread_.get() &&
-          !offscreen_context_for_main_thread_->BindToCurrentThread())
+          !offscreen_context_for_main_thread_->BindToCurrentThread()) {
         offscreen_context_for_main_thread_ = NULL;
+        wrapped_gl_context_for_main_thread_ = NULL;
+      }
     }
     return offscreen_context_for_main_thread_;
   }
@@ -90,11 +163,21 @@
     if (!offscreen_context_for_compositor_thread_.get() ||
         offscreen_context_for_compositor_thread_->DestroyedOnMainThread()) {
       offscreen_context_for_compositor_thread_ =
-          webkit::gpu::ContextProviderInProcess::Create();
+          webkit::gpu::ContextProviderInProcess::CreateOffscreen();
     }
     return offscreen_context_for_compositor_thread_;
   }
 
+  virtual scoped_ptr<StreamTextureFactory> CreateStreamTextureFactory(
+      int view_id) OVERRIDE {
+    scoped_refptr<VideoContextProvider> context_provider =
+        new VideoContextProvider(offscreen_context_for_main_thread_,
+                                 wrapped_gl_context_for_main_thread_);
+    return make_scoped_ptr(new StreamTextureFactorySynchronousImpl(
+                               context_provider.get(), view_id))
+        .PassAs<StreamTextureFactory>();
+  }
+
  private:
   SynchronousInputEventFilter synchronous_input_event_filter_;
 
@@ -102,6 +185,9 @@
   // not usage.
   base::Lock offscreen_context_for_compositor_thread_creation_lock_;
   scoped_refptr<cc::ContextProvider> offscreen_context_for_main_thread_;
+  // This is a pointer to the context owned by
+  // |offscreen_context_for_main_thread_|.
+  gpu::GLInProcessContext* wrapped_gl_context_for_main_thread_;
   scoped_refptr<cc::ContextProvider> offscreen_context_for_compositor_thread_;
 };
 
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 a6115e9..1faed9e 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
@@ -13,7 +13,6 @@
 #include "cc/output/output_surface_client.h"
 #include "cc/output/software_output_device.h"
 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
-#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "gpu/command_buffer/client/gl_in_process_context.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -22,18 +21,18 @@
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/transform.h"
 #include "ui/gl/gl_surface.h"
+#include "webkit/common/gpu/context_provider_in_process.h"
 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 
-
 namespace content {
 
 namespace {
 
-scoped_ptr<WebKit::WebGraphicsContext3D> CreateWebGraphicsContext3D(
-    scoped_refptr<gfx::GLSurface> surface) {
+scoped_ptr<webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl>
+CreateWebGraphicsContext3D(scoped_refptr<gfx::GLSurface> surface) {
   using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
   if (!gfx::GLSurface::InitializeOneOff())
-    return scoped_ptr<WebKit::WebGraphicsContext3D>();
+    return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
 
   const char* allowed_extensions = "*";
   const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
@@ -54,11 +53,10 @@
                                                  gpu_preference));
 
   if (!context.get())
-    return scoped_ptr<WebKit::WebGraphicsContext3D>();
+    return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>();
 
-  return scoped_ptr<WebKit::WebGraphicsContext3D>(
-      WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
-          context.Pass(), attributes));
+  return WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
+      context.Pass(), attributes).Pass();
 }
 
 void DidActivatePendingTree(int routing_id) {
@@ -176,8 +174,8 @@
 void SynchronousCompositorOutputSurface::SwapBuffers(
     cc::CompositorFrame* frame) {
   if (!ForcedDrawToSoftwareDevice()) {
-    DCHECK(context3d());
-    context3d()->shallowFlushCHROMIUM();
+    DCHECK(context_provider_);
+    context_provider_->Context3d()->shallowFlushCHROMIUM();
   }
   SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
   if (delegate)
@@ -197,14 +195,17 @@
 
 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
     scoped_refptr<gfx::GLSurface> surface,
-    scoped_refptr<cc::ContextProvider> offscreen_context) {
+    scoped_refptr<cc::ContextProvider> offscreen_context_provider) {
   DCHECK(CalledOnValidThread());
   DCHECK(HasClient());
-  DCHECK(!context3d_);
+  DCHECK(!context_provider_);
   DCHECK(surface);
 
-  return InitializeAndSetContext3D(
-      CreateWebGraphicsContext3D(surface).Pass(), offscreen_context);
+  scoped_refptr<cc::ContextProvider> onscreen_context_provider =
+      webkit::gpu::ContextProviderInProcess::Create(
+          CreateWebGraphicsContext3D(surface));
+  return InitializeAndSetContext3d(onscreen_context_provider,
+                                   offscreen_context_provider);
 }
 
 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
@@ -218,7 +219,7 @@
     bool stencil_enabled) {
   DCHECK(CalledOnValidThread());
   DCHECK(HasClient());
-  DCHECK(context3d());
+  DCHECK(context_provider_);
 
   gfx::Transform adjusted_transform = transform;
   AdjustTransformForClip(&adjusted_transform, clip);
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 3ab1498..86f048b 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.h
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.h
@@ -63,7 +63,7 @@
   // Partial SynchronousCompositor API implementation.
   bool InitializeHwDraw(
       scoped_refptr<gfx::GLSurface> surface,
-      scoped_refptr<cc::ContextProvider> offscreen_context);
+      scoped_refptr<cc::ContextProvider> offscreen_context_provider);
   void ReleaseHwDraw();
   bool DemandDrawHw(gfx::Size surface_size,
                     const gfx::Transform& transform,
diff --git a/content/browser/android/tracing_intent_handler.cc b/content/browser/android/tracing_intent_handler.cc
index 2760916..324f805 100644
--- a/content/browser/android/tracing_intent_handler.cc
+++ b/content/browser/android/tracing_intent_handler.cc
@@ -16,7 +16,7 @@
 TracingIntentHandler* g_trace_intent_handler = NULL;
 
 TracingIntentHandler::TracingIntentHandler(const base::FilePath& path)
-    : TraceSubscriberStdio(path) {
+    : TraceSubscriberStdio(path, FILE_TYPE_ARRAY, false) {
   TraceController::GetInstance()->BeginTracing(
       this,
       std::string("-test*"),
diff --git a/content/browser/android/web_contents_observer_android.cc b/content/browser/android/web_contents_observer_android.cc
index 67d8482..d9a1507 100644
--- a/content/browser/android/web_contents_observer_android.cc
+++ b/content/browser/android/web_contents_observer_android.cc
@@ -66,8 +66,8 @@
   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
   if (obj.is_null())
     return;
-  ScopedJavaLocalRef<jstring> jstring_url(
-      ConvertUTF8ToJavaString(env, web_contents()->GetURL().spec()));
+  ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
+      env, web_contents()->GetVisibleURL().spec()));
   Java_WebContentsObserverAndroid_didStartLoading(
       env, obj.obj(), jstring_url.obj());
 }
@@ -78,8 +78,8 @@
   ScopedJavaLocalRef<jobject> obj(weak_java_observer_.get(env));
   if (obj.is_null())
     return;
-  ScopedJavaLocalRef<jstring> jstring_url(
-      ConvertUTF8ToJavaString(env, web_contents()->GetURL().spec()));
+  ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
+      env, web_contents()->GetLastCommittedURL().spec()));
   Java_WebContentsObserverAndroid_didStopLoading(
       env, obj.obj(), jstring_url.obj());
 }
diff --git a/content/browser/aura/browser_compositor_output_surface.cc b/content/browser/aura/browser_compositor_output_surface.cc
index 11fbe0c..36e5dcd 100644
--- a/content/browser/aura/browser_compositor_output_surface.cc
+++ b/content/browser/aura/browser_compositor_output_surface.cc
@@ -11,6 +11,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "cc/output/compositor_frame.h"
 #include "content/browser/aura/reflector_impl.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/compositor_switches.h"
@@ -18,12 +19,12 @@
 namespace content {
 
 BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
-    scoped_ptr<WebKit::WebGraphicsContext3D> context,
+    const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
     int surface_id,
     IDMap<BrowserCompositorOutputSurface>* output_surface_map,
     base::MessageLoopProxy* compositor_message_loop,
     base::WeakPtr<ui::Compositor> compositor)
-    : OutputSurface(context.Pass()),
+    : OutputSurface(context_provider),
       surface_id_(surface_id),
       output_surface_map_(output_surface_map),
       compositor_message_loop_(compositor_message_loop),
@@ -70,12 +71,13 @@
 void BrowserCompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
   DCHECK(frame->gl_frame_data);
 
-  WebGraphicsContext3DCommandBufferImpl* command_buffer =
-      static_cast<WebGraphicsContext3DCommandBufferImpl*>(context3d());
+  WebGraphicsContext3DCommandBufferImpl* command_buffer_context =
+      static_cast<WebGraphicsContext3DCommandBufferImpl*>(
+          context_provider_->Context3d());
   CommandBufferProxyImpl* command_buffer_proxy =
-      command_buffer->GetCommandBufferProxy();
+      command_buffer_context->GetCommandBufferProxy();
   DCHECK(command_buffer_proxy);
-  context3d()->shallowFlushCHROMIUM();
+  context_provider_->Context3d()->shallowFlushCHROMIUM();
   command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
 
   if (reflector_.get()) {
diff --git a/content/browser/aura/browser_compositor_output_surface.h b/content/browser/aura/browser_compositor_output_surface.h
index 4b891bd..f9ec3c8 100644
--- a/content/browser/aura/browser_compositor_output_surface.h
+++ b/content/browser/aura/browser_compositor_output_surface.h
@@ -15,7 +15,9 @@
 namespace ui { class Compositor; }
 
 namespace content {
+class ContextProviderCommandBuffer;
 class ReflectorImpl;
+class WebGraphicsContext3DCommandBufferImpl;
 
 // Adapts a WebGraphicsContext3DCommandBufferImpl into a
 // cc::OutputSurface that also handles vsync parameter updates
@@ -25,7 +27,7 @@
       public base::NonThreadSafe {
  public:
   BrowserCompositorOutputSurface(
-      scoped_ptr<WebKit::WebGraphicsContext3D> context,
+      const scoped_refptr<ContextProviderCommandBuffer>& context,
       int surface_id,
       IDMap<BrowserCompositorOutputSurface>* output_surface_map,
       base::MessageLoopProxy* compositor_message_loop,
diff --git a/content/browser/aura/gpu_process_transport_factory.cc b/content/browser/aura/gpu_process_transport_factory.cc
index 47b1533..3c55282 100644
--- a/content/browser/aura/gpu_process_transport_factory.cc
+++ b/content/browser/aura/gpu_process_transport_factory.cc
@@ -74,6 +74,7 @@
   // ImageTransportFactory overrides:
   virtual void OnLostResources() OVERRIDE {
     DeleteTexture();
+    host_context_ = NULL;
   }
 
  protected:
@@ -90,9 +91,8 @@
     }
   }
 
-  // A raw pointer. This |ImageTransportClientTexture| will be destroyed
-  // before the |host_context_| via
-  // |ImageTransportFactoryObserver::OnLostContext()| handlers.
+  // The OnLostResources() callback will happen before this context
+  // pointer is destroyed.
   WebKit::WebGraphicsContext3D* host_context_;
   unsigned texture_id_;
 
@@ -199,12 +199,6 @@
   return CreateContextCommon(swap_client, 0);
 }
 
-scoped_ptr<WebKit::WebGraphicsContext3D>
-GpuProcessTransportFactory::CreateOffscreenContext() {
-  return CreateOffscreenCommandBufferContext()
-      .PassAs<WebKit::WebGraphicsContext3D>();
-}
-
 scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
     ui::Compositor* compositor) {
 #if defined(OS_WIN)
@@ -225,15 +219,18 @@
   if (!data)
     data = CreatePerCompositorData(compositor);
 
-  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context;
+  scoped_refptr<ContextProviderCommandBuffer> context_provider;
+
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing)) {
-    context =
-        CreateContextCommon(data->swap_client->AsWeakPtr(), data->surface_id);
+    context_provider = ContextProviderCommandBuffer::Create(
+        GpuProcessTransportFactory::CreateContextCommon(
+            data->swap_client->AsWeakPtr(),
+            data->surface_id));
   }
-  if (!context) {
+  if (!context_provider.get()) {
     if (ui::Compositor::WasInitializedWithThread()) {
-      LOG(FATAL) << "Failed to create UI context, but can't use software "
+      LOG(FATAL) << "Failed to create UI context, but can't use software"
                  " compositing with browser threaded compositing. Aborting.";
     }
 
@@ -255,7 +252,7 @@
 
   scoped_ptr<BrowserCompositorOutputSurface> surface(
       new BrowserCompositorOutputSurface(
-          context.PassAs<WebKit::WebGraphicsContext3D>(),
+          context_provider,
           per_compositor_data_[compositor]->surface_id,
           &output_surface_map_,
           base::MessageLoopProxy::current().get(),
@@ -390,12 +387,13 @@
 
 scoped_refptr<cc::ContextProvider>
 GpuProcessTransportFactory::OffscreenContextProviderForMainThread() {
-  if (!shared_contexts_main_thread_.get() ||
-      shared_contexts_main_thread_->DestroyedOnMainThread()) {
+  // Don't check for DestroyedOnMainThread() here. We hear about context
+  // loss for this context through the lost context callback. If the context
+  // is lost, we want to leave this ContextProvider available until the lost
+  // context notification is sent to the ImageTransportFactoryObserver clients.
+  if (!shared_contexts_main_thread_.get()) {
     shared_contexts_main_thread_ = ContextProviderCommandBuffer::Create(
-        base::Bind(&GpuProcessTransportFactory::
-                       CreateOffscreenCommandBufferContext,
-                   base::Unretained(this)));
+        GpuProcessTransportFactory::CreateOffscreenCommandBufferContext());
     if (shared_contexts_main_thread_) {
       shared_contexts_main_thread_->SetLostContextCallback(base::Bind(
           &GpuProcessTransportFactory::
@@ -411,12 +409,12 @@
 
 scoped_refptr<cc::ContextProvider>
 GpuProcessTransportFactory::OffscreenContextProviderForCompositorThread() {
-  if (!shared_contexts_compositor_thread_.get() ||
-      shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
+  // The lifetime of this context is tied to the main thread context so that
+  // they are always in the same share group. So do not check for
+  // DestroyedOnMainThread().
+  if (!shared_contexts_compositor_thread_.get()) {
     shared_contexts_compositor_thread_ = ContextProviderCommandBuffer::Create(
-        base::Bind(&GpuProcessTransportFactory::
-                       CreateOffscreenCommandBufferContext,
-                   base::Unretained(this)));
+        GpuProcessTransportFactory::CreateOffscreenCommandBufferContext());
   }
   return shared_contexts_compositor_thread_;
 }
@@ -500,18 +498,29 @@
 
 void GpuProcessTransportFactory::OnLostMainThreadSharedContext() {
   LOG(ERROR) << "Lost UI shared context.";
+
   // Keep old resources around while we call the observers, but ensure that
   // new resources are created if needed.
+  // Kill shared contexts for both threads in tandem so they are always in
+  // the same share group.
 
-  scoped_refptr<ContextProviderCommandBuffer> old_contexts_main_thread =
+  scoped_refptr<cc::ContextProvider> lost_shared_contexts_main_thread =
       shared_contexts_main_thread_;
+  scoped_refptr<cc::ContextProvider> lost_shared_contexts_compositor_thread =
+      shared_contexts_compositor_thread_;
   shared_contexts_main_thread_ = NULL;
+  shared_contexts_compositor_thread_ = NULL;
 
-  scoped_ptr<GLHelper> old_helper(gl_helper_.release());
+  scoped_ptr<GLHelper> lost_gl_helper = gl_helper_.Pass();
 
   FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
                     observer_list_,
                     OnLostResources());
+
+  // Kill things that use the shared context before killing the shared context.
+  lost_gl_helper.reset();
+  lost_shared_contexts_main_thread = NULL;
+  lost_shared_contexts_compositor_thread = NULL;
 }
 
 }  // namespace content
diff --git a/content/browser/aura/gpu_process_transport_factory.h b/content/browser/aura/gpu_process_transport_factory.h
index 72b88d5..56d3e55 100644
--- a/content/browser/aura/gpu_process_transport_factory.h
+++ b/content/browser/aura/gpu_process_transport_factory.h
@@ -35,9 +35,7 @@
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
   CreateOffscreenCommandBufferContext();
 
-  // ContextFactory implementation.
-  virtual scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext()
-      OVERRIDE;
+  // ui::ContextFactory implementation.
   virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
       ui::Compositor* compositor) OVERRIDE;
   virtual scoped_refptr<ui::Reflector> CreateReflector(
@@ -46,6 +44,10 @@
   virtual void RemoveReflector(
       scoped_refptr<ui::Reflector> reflector) OVERRIDE;
   virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE;
+  virtual scoped_refptr<cc::ContextProvider>
+      OffscreenContextProviderForMainThread() OVERRIDE;
+  virtual scoped_refptr<cc::ContextProvider>
+      OffscreenContextProviderForCompositorThread() OVERRIDE;
   virtual bool DoesCreateTestContexts() OVERRIDE;
 
   // ImageTransportFactory implementation.
@@ -66,12 +68,6 @@
   virtual void RemoveObserver(
       ImageTransportFactoryObserver* observer) OVERRIDE;
 
-  // ui::ContextFactory implementation.
-  virtual scoped_refptr<cc::ContextProvider>
-      OffscreenContextProviderForMainThread() OVERRIDE;
-  virtual scoped_refptr<cc::ContextProvider>
-      OffscreenContextProviderForCompositorThread() OVERRIDE;
-
   void OnLostContext(ui::Compositor* compositor);
 
  private:
diff --git a/content/browser/aura/reflector_impl.cc b/content/browser/aura/reflector_impl.cc
index 1e26cf8..78726ec 100644
--- a/content/browser/aura/reflector_impl.cc
+++ b/content/browser/aura/reflector_impl.cc
@@ -68,7 +68,8 @@
 // ImplThread.
 void ReflectorImpl::AttachToOutputSurface(
     BrowserCompositorOutputSurface* output_surface) {
-  gl_helper_.reset(new GLHelper(output_surface->context3d()));
+  gl_helper_.reset(
+      new GLHelper(output_surface->context_provider()->Context3d()));
   output_surface->SetReflector(this);
 }
 
diff --git a/content/browser/aura/software_output_device_win.cc b/content/browser/aura/software_output_device_win.cc
index 0332e3e..1a5af46 100644
--- a/content/browser/aura/software_output_device_win.cc
+++ b/content/browser/aura/software_output_device_win.cc
@@ -11,6 +11,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/canvas_skia_paint.h"
 #include "ui/gfx/gdi_util.h"
+#include "ui/gfx/skia_util.h"
 
 namespace content {
 
@@ -98,4 +99,12 @@
   }
 }
 
+void SoftwareOutputDeviceWin::CopyToBitmap(
+    gfx::Rect rect, SkBitmap* output) {
+  DCHECK(contents_);
+  SkDevice* device = contents_->sk_canvas()->getDevice();
+  const SkBitmap& bitmap = device->accessBitmap(false);
+  bitmap.extractSubset(output, gfx::RectToSkIRect(rect));
+}
+
 }  // namespace content
diff --git a/content/browser/aura/software_output_device_win.h b/content/browser/aura/software_output_device_win.h
index 93568c2..9c0655b 100644
--- a/content/browser/aura/software_output_device_win.h
+++ b/content/browser/aura/software_output_device_win.h
@@ -28,6 +28,7 @@
   virtual void Resize(gfx::Size viewport_size) OVERRIDE;
   virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE;
   virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE;
+  virtual void CopyToBitmap(gfx::Rect rect, SkBitmap* output) OVERRIDE;
 
  private:
   HWND hwnd_;
diff --git a/content/browser/bookmarklet_browsertest.cc b/content/browser/bookmarklet_browsertest.cc
index 02f4193..35523ee 100644
--- a/content/browser/bookmarklet_browsertest.cc
+++ b/content/browser/bookmarklet_browsertest.cc
@@ -6,7 +6,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index c51b5c5..8bf6503 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -23,10 +23,11 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/timer/hi_res_timer_manager.h"
 #include "content/browser/browser_thread_impl.h"
-#include "content/browser/device_orientation/device_motion_service.h"
+#include "content/browser/device_orientation/device_inertial_sensor_service.h"
 #include "content/browser/download/save_file_manager.h"
 #include "content/browser/gamepad/gamepad_service.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.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_process_host_ui_shim.h"
@@ -43,7 +44,6 @@
 #include "content/browser/webui/url_data_manager.h"
 #include "content/public/browser/browser_main_parts.h"
 #include "content/public/browser/browser_shutdown.h"
-#include "content/public/browser/compositor_util.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/content_switches.h"
@@ -52,6 +52,7 @@
 #include "crypto/nss_util.h"
 #include "media/audio/audio_manager.h"
 #include "media/base/media.h"
+#include "media/base/user_input_monitor.h"
 #include "media/midi/midi_manager.h"
 #include "net/base/network_change_notifier.h"
 #include "net/socket/client_socket_factory.h"
@@ -64,7 +65,7 @@
 
 #if defined(OS_ANDROID)
 #include "base/android/jni_android.h"
-#include "content/browser/android/browser_startup_config.h"
+#include "content/browser/android/browser_startup_controller.h"
 #include "content/browser/android/surface_texture_peer_browser_impl.h"
 #endif
 
@@ -795,7 +796,7 @@
   // Must happen after the I/O thread is shutdown since this class lives on the
   // I/O thread and isn't threadsafe.
   GamepadService::GetInstance()->Terminate();
-  DeviceMotionService::GetInstance()->Shutdown();
+  DeviceInertialSensorService::GetInstance()->Shutdown();
 
   URLDataManager::DeleteDataSources();
 #endif  // !defined(OS_IOS)
@@ -872,6 +873,14 @@
         audio_manager_.get(), media_stream_manager_.get()));
   }
 
+  {
+    TRACE_EVENT0(
+        "startup",
+        "BrowserMainLoop::BrowserThreadsStarted::InitUserInputMonitor");
+    user_input_monitor_ = media::UserInputMonitor::Create(
+        io_thread_->message_loop_proxy(), main_thread_->message_loop_proxy());
+  }
+
   // Alert the clipboard class to which threads are allowed to access the
   // clipboard:
   std::vector<base::PlatformThreadId> allowed_clipboard_threads;
@@ -887,8 +896,13 @@
   // 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) &&
-      IsForceCompositingModeEnabled() &&
+      always_uses_gpu &&
       !parsed_command_line_.HasSwitch(switches::kDisableGpuProcessPrelaunch) &&
       !parsed_command_line_.HasSwitch(switches::kSingleProcess) &&
       !parsed_command_line_.HasSwitch(switches::kInProcessGPU)) {
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index 7b2879f..83dbafd 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -26,6 +26,7 @@
 namespace media {
 class AudioManager;
 class MIDIManager;
+class UserInputMonitor;
 }  // namespace media
 
 namespace net {
@@ -86,6 +87,9 @@
   MediaStreamManager* media_stream_manager() const {
     return media_stream_manager_.get();
   }
+  media::UserInputMonitor* user_input_monitor() const {
+    return user_input_monitor_.get();
+  }
   media::MIDIManager* midi_manager() const { return midi_manager_.get(); }
   base::Thread* indexed_db_thread() const { return indexed_db_thread_.get(); }
 
@@ -122,6 +126,8 @@
   scoped_ptr<base::PowerMonitor> power_monitor_;
   scoped_ptr<base::HighResolutionTimerManager> hi_res_timer_manager_;
   scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+  // user_input_monitor_ has to outlive audio_manager_, so declared first.
+  scoped_ptr<media::UserInputMonitor> user_input_monitor_;
   scoped_ptr<media::AudioManager> audio_manager_;
   scoped_ptr<media::MIDIManager> midi_manager_;
   scoped_ptr<AudioMirroringManager> audio_mirroring_manager_;
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index 06c94cc..96e60e1 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -15,6 +15,7 @@
 #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"
+#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -42,6 +43,7 @@
 #include "content/public/common/drop_data.h"
 #include "content/public/common/media_stream_request.h"
 #include "content/public/common/result_codes.h"
+#include "content/public/common/url_utils.h"
 #include "net/url_request/url_request.h"
 #include "third_party/WebKit/public/web/WebCursorInfo.h"
 #include "ui/base/keycodes/keyboard_codes.h"
@@ -127,7 +129,7 @@
               // in the fact whether the embedder/app has geolocation
               // permission. Therefore we use an invalid |bridge_id|.
               -1 /* bridge_id */,
-              web_contents->GetURL(),
+              web_contents->GetLastCommittedURL(),
               geolocation_callback);
           return;
         }
@@ -347,7 +349,9 @@
       pending_lock_request_(false),
       embedder_visible_(true),
       next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID),
-      has_render_view_(has_render_view) {
+      has_render_view_(has_render_view),
+      last_seen_auto_size_enabled_(false),
+      is_in_destruction_(false) {
   DCHECK(web_contents);
   web_contents->SetDelegate(this);
   if (opener)
@@ -421,6 +425,7 @@
 }
 
 void BrowserPluginGuest::Destroy() {
+  is_in_destruction_ = true;
   if (!attached() && opener())
     opener()->pending_new_windows_.erase(this);
   DestroyUnattachedWindows();
@@ -541,6 +546,18 @@
         GetWebContents()->GetRenderViewHost());
     guest_rvh->SetInputMethodActive(true);
   }
+
+  // Inform the embedder of the guest's information.
+  // We pull the partition information from the site's URL, which is of the form
+  // guest://site/{persist}?{partition_name}.
+  const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
+  BrowserPluginMsg_Attach_ACK_Params ack_params;
+  ack_params.storage_partition_id = site_url.query();
+  ack_params.persist_storage =
+      site_url.path().find("persist") != std::string::npos;
+  ack_params.name = name_;
+  SendMessageToEmbedder(
+      new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
 }
 
 BrowserPluginGuest::~BrowserPluginGuest() {
@@ -764,6 +781,10 @@
 
 base::SharedMemory* BrowserPluginGuest::GetDamageBufferFromEmbedder(
     const BrowserPluginHostMsg_ResizeGuest_Params& params) {
+  if (!attached()) {
+    LOG(WARNING) << "Attempting to map a damage buffer prior to attachment.";
+    return NULL;
+  }
 #if defined(OS_WIN)
   base::ProcessHandle handle =
       embedder_web_contents_->GetRenderProcessHost()->GetHandle();
@@ -1123,18 +1144,6 @@
 
   Initialize(embedder_web_contents, params);
 
-  // Inform the embedder of the guest's information.
-  // We pull the partition information from the site's URL, which is of the form
-  // guest://site/{persist}?{partition_name}.
-  const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
-  BrowserPluginMsg_Attach_ACK_Params ack_params;
-  ack_params.storage_partition_id = site_url.query();
-  ack_params.persist_storage =
-      site_url.path().find("persist") != std::string::npos;
-  ack_params.name = name_;
-  SendMessageToEmbedder(
-      new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
-
   SendQueuedMessages();
 
   RecordAction(UserMetricsAction("BrowserPlugin.Guest.Attached"));
@@ -1259,7 +1268,7 @@
                    base::Value::CreateBooleanValue(last_unlocked_by_target));
   request_info.Set(browser_plugin::kURL,
                    base::Value::CreateStringValue(
-                       web_contents()->GetURL().spec()));
+                       web_contents()->GetLastCommittedURL().spec()));
 
   RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK,
                     new PointerLockRequest(this),
@@ -1283,6 +1292,21 @@
   // should never be sent to BrowserPluginGuest (browser process).
   DCHECK(!src.empty());
   if (!src.empty()) {
+    // Do not allow navigating a guest to schemes other than known safe schemes.
+    // This will block the embedder trying to load unwanted schemes, e.g.
+    // chrome://settings.
+    if (!ChildProcessSecurityPolicyImpl::GetInstance()->IsWebSafeScheme(
+            url.scheme()) &&
+        !ChildProcessSecurityPolicyImpl::GetInstance()->IsPseudoScheme(
+            url.scheme())) {
+      if (delegate_) {
+        std::string error_type;
+        RemoveChars(net::ErrorToString(net::ERR_ABORTED), "net::", &error_type);
+        delegate_->LoadAbort(true /* is_top_level */, url, error_type);
+      }
+      return;
+    }
+
     // As guests do not swap processes on navigation, only navigations to
     // normal web URLs are supported.  No protocol handlers are installed for
     // other schemes (e.g., WebUI or extensions), and no permissions or bindings
@@ -1316,6 +1340,13 @@
       render_widget_host->NotifyScreenInfoChanged();
     }
   }
+  // When autosize is turned off and as a result there is a layout change, we
+  // send a sizechanged event.
+  if (!auto_size_enabled_ && last_seen_auto_size_enabled_ &&
+      !params.view_rect.size().IsEmpty() && delegate_) {
+    delegate_->SizeChanged(last_seen_view_size_, params.view_rect.size());
+    last_seen_auto_size_enabled_ = false;
+  }
   // Invalid damage buffer means we are in HW compositing mode,
   // so just resize the WebContents and repaint if needed.
   if (!base::SharedMemory::IsHandleValid(params.damage_buffer_handle)) {
@@ -1578,6 +1609,16 @@
       params.flags);
   relay_params.needs_ack = params.needs_ack;
 
+  bool size_changed = last_seen_view_size_ != params.view_size;
+  gfx::Size old_size = last_seen_view_size_;
+  last_seen_view_size_ = params.view_size;
+
+  if ((auto_size_enabled_ || last_seen_auto_size_enabled_) &&
+      size_changed && delegate_) {
+    delegate_->SizeChanged(old_size, last_seen_view_size_);
+  }
+  last_seen_auto_size_enabled_ = auto_size_enabled_;
+
   // HW accelerated case, acknowledge resize only
   if (!params.needs_ack || !damage_buffer_) {
     relay_params.damage_buffer_sequence_id = 0;
diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h
index 2044e49..74624ef 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.h
+++ b/content/browser/browser_plugin/browser_plugin_guest.h
@@ -136,6 +136,7 @@
   bool focused() const { return focused_; }
   bool visible() const { return guest_visible_; }
   void clear_damage_buffer() { damage_buffer_.reset(); }
+  bool is_in_destruction() { return is_in_destruction_; }
 
   BrowserPluginGuest* opener() const { return opener_.get(); }
 
@@ -515,6 +516,13 @@
   // this guest is attached.
   bool has_render_view_;
 
+  // Last seen size of guest contents (by OnUpdateRect).
+  gfx::Size last_seen_view_size_;
+  // Last seen autosize attribute state (by OnUpdateRect).
+  bool last_seen_auto_size_enabled_;
+
+  bool is_in_destruction_;
+
   // This is a queue of messages that are destined to be sent to the embedder
   // once the guest is attached to a particular embedder.
   std::queue<IPC::Message*> pending_messages_;
diff --git a/content/browser/browser_plugin/browser_plugin_host_browsertest.cc b/content/browser/browser_plugin/browser_plugin_host_browsertest.cc
index 4fc2ae8..8112296 100644
--- a/content/browser/browser_plugin/browser_plugin_host_browsertest.cc
+++ b/content/browser/browser_plugin/browser_plugin_host_browsertest.cc
@@ -26,7 +26,7 @@
 #include "content/public/common/drop_data.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/net_util.h"
@@ -786,63 +786,6 @@
   test_guest()->WaitForBlur();
 }
 
-// This test verifies that if a browser plugin is in autosize mode before
-// navigation then the guest starts auto-sized.
-IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AutoSizeBeforeNavigation) {
-  const char* kEmbedderURL = "/browser_plugin_embedder.html";
-  const std::string embedder_code =
-      "document.getElementById('plugin').minwidth = 300;"
-      "document.getElementById('plugin').minheight = 200;"
-      "document.getElementById('plugin').maxwidth = 600;"
-      "document.getElementById('plugin').maxheight = 400;"
-      "document.getElementById('plugin').autosize = true;";
-  StartBrowserPluginTest(
-      kEmbedderURL, kHTMLForGuestWithSize, true, embedder_code);
-  // Verify that the guest has been auto-sized.
-  test_guest()->WaitForViewSize(gfx::Size(300, 400));
-}
-
-// This test verifies that enabling autosize resizes the guest and triggers
-// a 'sizechanged' event.
-IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, AutoSizeAfterNavigation) {
-  const char* kEmbedderURL = "/browser_plugin_embedder.html";
-  StartBrowserPluginTest(
-      kEmbedderURL, kHTMLForGuestWithSize, true, std::string());
-  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
-      test_embedder()->web_contents()->GetRenderViewHost());
-
-  {
-    const string16 expected_title = ASCIIToUTF16("AutoSize(300, 400)");
-    content::TitleWatcher title_watcher(test_embedder()->web_contents(),
-                                        expected_title);
-    ExecuteSyncJSFunction(
-        rvh,
-        "document.getElementById('plugin').minwidth = 300;"
-        "document.getElementById('plugin').minheight = 200;"
-        "document.getElementById('plugin').maxwidth = 600;"
-        "document.getElementById('plugin').maxheight = 400;"
-        "document.getElementById('plugin').autosize = true;");
-    string16 actual_title = title_watcher.WaitAndGetTitle();
-    EXPECT_EQ(expected_title, actual_title);
-  }
-  {
-    // Change the minwidth and verify that it causes relayout.
-    const string16 expected_title = ASCIIToUTF16("AutoSize(350, 400)");
-    content::TitleWatcher title_watcher(test_embedder()->web_contents(),
-                                        expected_title);
-    ExecuteSyncJSFunction(
-        rvh, "document.getElementById('plugin').minwidth = 350;");
-    string16 actual_title = title_watcher.WaitAndGetTitle();
-    EXPECT_EQ(expected_title, actual_title);
-  }
-  {
-    // Turn off autoSize and verify that the guest resizes to fit the container.
-    ExecuteSyncJSFunction(
-        rvh, "document.getElementById('plugin').autosize = null;");
-    test_guest()->WaitForViewSize(gfx::Size(640, 480));
-  }
-}
-
 // Test for regression http://crbug.com/162961.
 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, GetRenderViewHostAtPositionTest) {
   const char kEmbedderURL[] = "/browser_plugin_embedder.html";
@@ -858,79 +801,6 @@
             test_embedder()->last_rvh_at_position_response());
 }
 
-// This test verifies that all autosize attributes can be removed
-// without crashing the plugin, or throwing errors.
-IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, RemoveAutosizeAttributes) {
-  const char* kEmbedderURL = "/browser_plugin_embedder.html";
-  const std::string embedder_code =
-      "document.getElementById('plugin').minwidth = 300;"
-      "document.getElementById('plugin').minheight = 200;"
-      "document.getElementById('plugin').maxwidth = 600;"
-      "document.getElementById('plugin').maxheight = 400;"
-      "document.getElementById('plugin').name = 'name';"
-      "document.getElementById('plugin').src = 'foo';"
-      "document.getElementById('plugin').autosize = '';";
-  StartBrowserPluginTest(
-      kEmbedderURL, kHTMLForGuestWithSize, true, embedder_code);
-  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
-      test_embedder()->web_contents()->GetRenderViewHost());
-  RemoveAttributes(rvh, "maxheight, maxwidth, minheight, minwidth, autosize");
-
-  // Verify that the guest resizes to fit the container (and hasn't crashed).
-  test_guest()->WaitForViewSize(gfx::Size(640, 480));
-  EXPECT_TRUE(IsAttributeNull(rvh, "maxheight"));
-  EXPECT_TRUE(IsAttributeNull(rvh, "maxwidth"));
-  EXPECT_TRUE(IsAttributeNull(rvh, "minheight"));
-  EXPECT_TRUE(IsAttributeNull(rvh, "minwidth"));
-  EXPECT_TRUE(IsAttributeNull(rvh, "autosize"));
-}
-
-// This test verifies that autosize works when some of the parameters are unset.
-IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, PartialAutosizeAttributes) {
-  const char* kEmbedderURL = "/browser_plugin_embedder.html";
-  const std::string embedder_code =
-      "document.getElementById('plugin').minwidth = 300;"
-      "document.getElementById('plugin').minheight = 200;"
-      "document.getElementById('plugin').maxwidth = 700;"
-      "document.getElementById('plugin').maxheight = 600;"
-      "document.getElementById('plugin').autosize = '';";
-  StartBrowserPluginTest(
-      kEmbedderURL, kHTMLForGuestWithSize, true, embedder_code);
-  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
-      test_embedder()->web_contents()->GetRenderViewHost());
-  {
-    // Remove an autosize attribute and verify that it causes relayout.
-    const string16 expected_title = ASCIIToUTF16("AutoSize(640, 400)");
-    content::TitleWatcher title_watcher(test_embedder()->web_contents(),
-                                        expected_title);
-    RemoveAttributes(rvh, "minwidth");
-    string16 actual_title = title_watcher.WaitAndGetTitle();
-    EXPECT_EQ(expected_title, actual_title);
-  }
-  {
-    // Remove an autosize attribute and verify that it causes relayout.
-    // Also tests that when minwidth > maxwidth, minwidth = maxwidth.
-    const string16 expected_title = ASCIIToUTF16("AutoSize(700, 480)");
-    content::TitleWatcher title_watcher(test_embedder()->web_contents(),
-                                        expected_title);
-    RemoveAttributes(rvh, "maxheight");
-    ExecuteSyncJSFunction(
-        rvh, "document.getElementById('plugin').minwidth = 800;"
-             "document.getElementById('plugin').minheight = 800;");
-    string16 actual_title = title_watcher.WaitAndGetTitle();
-    EXPECT_EQ(expected_title, actual_title);
-  }
-  {
-    // Remove maxwidth and make sure the size returns to plugin size.
-    const string16 expected_title = ASCIIToUTF16("AutoSize(640, 480)");
-    content::TitleWatcher title_watcher(test_embedder()->web_contents(),
-                                        expected_title);
-    RemoveAttributes(rvh, "maxwidth");
-    string16 actual_title = title_watcher.WaitAndGetTitle();
-    EXPECT_EQ(expected_title, actual_title);
-  }
-}
-
 // This test verifies that if IME is enabled in the embedder, it is also enabled
 // in the guest.
 IN_PROC_BROWSER_TEST_F(BrowserPluginHostTest, VerifyInputMethodActive) {
diff --git a/content/browser/browser_thread_impl.h b/content/browser/browser_thread_impl.h
index b16bb36..167cc3b 100644
--- a/content/browser/browser_thread_impl.h
+++ b/content/browser/browser_thread_impl.h
@@ -60,6 +60,7 @@
 
   // For testing.
   friend class ContentTestSuiteBaseListener;
+  friend class TestBrowserThreadBundle;
   static void FlushThreadPoolHelper();
 
   // The identifier of this thread.  Only one thread can exist with a given
diff --git a/content/browser/byte_stream.cc b/content/browser/byte_stream.cc
index a8b8f29..7b0f9fb 100644
--- a/content/browser/byte_stream.cc
+++ b/content/browser/byte_stream.cc
@@ -61,6 +61,7 @@
   virtual void Flush() OVERRIDE;
   virtual void Close(int status) OVERRIDE;
   virtual void RegisterCallback(const base::Closure& source_callback) OVERRIDE;
+  virtual size_t GetTotalBufferedBytes() const OVERRIDE;
 
   // PostTask target from |ByteStreamReaderImpl::MaybeUpdateInput|.
   static void UpdateWindow(scoped_refptr<LifetimeFlag> lifetime_flag,
@@ -209,6 +210,18 @@
     scoped_refptr<net::IOBuffer> buffer, size_t byte_count) {
   DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
 
+  // Check overflow.
+  //
+  // TODO(tyoshino): Discuss with content/browser/download developer and if
+  // they're fine with, set smaller limit and make it configurable.
+  size_t space_limit = std::numeric_limits<size_t>::max() -
+      GetTotalBufferedBytes();
+  if (byte_count > space_limit) {
+    // TODO(tyoshino): Tell the user that Write() failed.
+    // Ignore input.
+    return false;
+  }
+
   input_contents_.push_back(std::make_pair(buffer, byte_count));
   input_contents_size_ += byte_count;
 
@@ -216,7 +229,7 @@
   if (input_contents_size_ > total_buffer_size_ / kFractionBufferBeforeSending)
     PostToPeer(false, 0);
 
-  return (input_contents_size_ + output_size_used_ <= total_buffer_size_);
+  return GetTotalBufferedBytes() <= total_buffer_size_;
 }
 
 void ByteStreamWriterImpl::Flush() {
@@ -236,6 +249,13 @@
   space_available_callback_ = source_callback;
 }
 
+size_t ByteStreamWriterImpl::GetTotalBufferedBytes() const {
+  DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+  // This sum doesn't overflow since Write() fails if this sum is going to
+  // overflow.
+  return input_contents_size_ + output_size_used_;
+}
+
 // static
 void ByteStreamWriterImpl::UpdateWindow(
     scoped_refptr<LifetimeFlag> lifetime_flag, ByteStreamWriterImpl* target,
@@ -248,15 +268,16 @@
 
 void ByteStreamWriterImpl::UpdateWindowInternal(size_t bytes_consumed) {
   DCHECK(my_task_runner_->RunsTasksOnCurrentThread());
+
+  bool was_above_limit = GetTotalBufferedBytes() > total_buffer_size_;
+
   DCHECK_GE(output_size_used_, bytes_consumed);
   output_size_used_ -= bytes_consumed;
 
   // Callback if we were above the limit and we're now <= to it.
-  size_t total_known_size_used =
-      input_contents_size_ + output_size_used_;
+  bool no_longer_above_limit = GetTotalBufferedBytes() <= total_buffer_size_;
 
-  if (total_known_size_used <= total_buffer_size_ &&
-      (total_known_size_used + bytes_consumed > total_buffer_size_) &&
+  if (no_longer_above_limit && was_above_limit &&
       !space_available_callback_.is_null())
     space_available_callback_.Run();
 }
diff --git a/content/browser/byte_stream.h b/content/browser/byte_stream.h
index 0b5640d..60b0163 100644
--- a/content/browser/byte_stream.h
+++ b/content/browser/byte_stream.h
@@ -153,6 +153,10 @@
   // or after callbacks may be called).
   // The callback will not be called after ByteStreamWriter destruction.
   virtual void RegisterCallback(const base::Closure& source_callback) = 0;
+
+  // Returns the number of bytes sent to the reader but not yet reported by
+  // the reader as read.
+  virtual size_t GetTotalBufferedBytes() const = 0;
 };
 
 class CONTENT_EXPORT ByteStreamReader {
diff --git a/content/browser/byte_stream_unittest.cc b/content/browser/byte_stream_unittest.cc
index 04c5ae3..f814e2f 100644
--- a/content/browser/byte_stream_unittest.cc
+++ b/content/browser/byte_stream_unittest.cc
@@ -5,6 +5,7 @@
 #include "content/browser/byte_stream.h"
 
 #include <deque>
+#include <limits>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -116,7 +117,10 @@
   EXPECT_FALSE(Write(byte_stream_input.get(), 1024));
   // Flush
   byte_stream_input->Close(0);
+  EXPECT_EQ(4 * 1024U + 1U, byte_stream_input->GetTotalBufferedBytes());
   message_loop_.RunUntilIdle();
+  // Data already sent to reader is also counted in.
+  EXPECT_EQ(4 * 1024U + 1U, byte_stream_input->GetTotalBufferedBytes());
 
   // Pull the IO buffers out; do we get the same buffers and do they
   // have the same contents?
@@ -144,6 +148,10 @@
 
   EXPECT_EQ(ByteStreamReader::STREAM_COMPLETE,
             byte_stream_output->Read(&output_io_buffer, &output_length));
+
+  message_loop_.RunUntilIdle();
+  // Reader now knows that all data is read out.
+  EXPECT_EQ(1024U, byte_stream_input->GetTotalBufferedBytes());
 }
 
 // Confirm that Flush() method makes the writer to send written contents to
@@ -579,4 +587,27 @@
             byte_stream_output->Read(&output_io_buffer, &output_length));
 }
 
+TEST_F(ByteStreamTest, ByteStream_WriteOverflow) {
+  scoped_ptr<ByteStreamWriter> byte_stream_input;
+  scoped_ptr<ByteStreamReader> byte_stream_output;
+  CreateByteStream(
+      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
+      std::numeric_limits<size_t>::max(),
+      &byte_stream_input, &byte_stream_output);
+
+  EXPECT_TRUE(Write(byte_stream_input.get(), 1));
+  // 1 + size_t max -> Overflow.
+  scoped_refptr<net::IOBuffer> empty_io_buffer;
+  EXPECT_FALSE(byte_stream_input->Write(empty_io_buffer,
+                                        std::numeric_limits<size_t>::max()));
+  message_loop_.RunUntilIdle();
+
+  // The first write is below PostToPeer threshold. We shouldn't get anything
+  // from the output.
+  scoped_refptr<net::IOBuffer> output_io_buffer;
+  size_t output_length;
+  EXPECT_EQ(ByteStreamReader::STREAM_EMPTY,
+            byte_stream_output->Read(&output_io_buffer, &output_length));
+}
+
 }  // namespace content
diff --git a/content/browser/child_process_security_policy_browsertest.cc b/content/browser/child_process_security_policy_browsertest.cc
index db27a53..c7cfe39 100644
--- a/content/browser/child_process_security_policy_browsertest.cc
+++ b/content/browser/child_process_security_policy_browsertest.cc
@@ -10,7 +10,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/result_codes.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index d7640d3..b47cbd2 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -289,7 +289,7 @@
 
   // We know about the following pseudo schemes and treat them specially.
   RegisterPseudoScheme(chrome::kAboutScheme);
-  RegisterPseudoScheme(chrome::kJavaScriptScheme);
+  RegisterPseudoScheme(kJavaScriptScheme);
   RegisterPseudoScheme(kViewSourceScheme);
 }
 
diff --git a/content/browser/child_process_security_policy_unittest.cc b/content/browser/child_process_security_policy_unittest.cc
index b914eac..2469648 100644
--- a/content/browser/child_process_security_policy_unittest.cc
+++ b/content/browser/child_process_security_policy_unittest.cc
@@ -119,7 +119,7 @@
       ChildProcessSecurityPolicyImpl::GetInstance();
 
   EXPECT_TRUE(p->IsPseudoScheme(chrome::kAboutScheme));
-  EXPECT_TRUE(p->IsPseudoScheme(chrome::kJavaScriptScheme));
+  EXPECT_TRUE(p->IsPseudoScheme(kJavaScriptScheme));
   EXPECT_TRUE(p->IsPseudoScheme(kViewSourceScheme));
 
   EXPECT_FALSE(p->IsPseudoScheme("registered-pseudo-scheme"));
diff --git a/content/browser/database_browsertest.cc b/content/browser/database_browsertest.cc
index 305d8ff..373a06f 100644
--- a/content/browser/database_browsertest.cc
+++ b/content/browser/database_browsertest.cc
@@ -11,7 +11,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "content/test/net/url_request_mock_http_job.h"
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory.h b/content/browser/device_orientation/data_fetcher_shared_memory.h
index dc5e92a..9d378eb 100644
--- a/content/browser/device_orientation/data_fetcher_shared_memory.h
+++ b/content/browser/device_orientation/data_fetcher_shared_memory.h
@@ -5,48 +5,21 @@
 #ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_SHARED_MEMORY_H_
 #define CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_SHARED_MEMORY_H_
 
-#include "content/browser/device_orientation/device_data.h"
-#include "content/common/device_motion_hardware_buffer.h"
-
-namespace WebKit {
-class WebDeviceMotionData;
-}
+#include "content/browser/device_orientation/data_fetcher_shared_memory_base.h"
 
 namespace content {
 
-class CONTENT_EXPORT DataFetcherSharedMemory {
+class CONTENT_EXPORT DataFetcherSharedMemory
+    : public DataFetcherSharedMemoryBase {
+
  public:
-  DataFetcherSharedMemory()
-      : device_motion_buffer_(NULL),
-        started_(false) { }
+  DataFetcherSharedMemory();
   virtual ~DataFetcherSharedMemory();
 
-  // Returns true if this fetcher needs explicit calls to fetch the data.
-  // Called from any thread.
-  virtual bool NeedsPolling();
-
-  // If this fetcher NeedsPolling() is true, this method will update the
-  // buffer with the latest device motion data.
-  // Returns true if there was any motion data to update the buffer with.
-  // Called from the DeviceMotionProvider::PollingThread.
-  virtual bool FetchDeviceMotionDataIntoBuffer();
-
-  // Returns true if the relevant sensors could be successfully activated.
-  // This method should be called before any calls to
-  // FetchDeviceMotionDataIntoBuffer().
-  // If NeedsPolling() is true this method should be called from the
-  // PollingThread.
-  virtual bool StartFetchingDeviceMotionData(
-      DeviceMotionHardwareBuffer* buffer);
-
-  // Indicates to the fetcher to stop fetching device data.
-  // If NeedsPolling() is true this method should be called from the
-  // PollingThread.
-  virtual void StopFetchingDeviceMotionData();
-
  private:
-  DeviceMotionHardwareBuffer* device_motion_buffer_;
-  bool started_;
+
+  virtual bool Start(ConsumerType consumer_type) OVERRIDE;
+  virtual bool Stop(ConsumerType consumer_type) OVERRIDE;
 
   DISALLOW_COPY_AND_ASSIGN(DataFetcherSharedMemory);
 };
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_android.cc b/content/browser/device_orientation/data_fetcher_shared_memory_android.cc
index 8f6e202..8d4a9d0 100644
--- a/content/browser/device_orientation/data_fetcher_shared_memory_android.cc
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_android.cc
@@ -2,39 +2,52 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "data_fetcher_shared_memory.h"
+#include "content/browser/device_orientation/data_fetcher_shared_memory.h"
 
 #include "base/logging.h"
-#include "data_fetcher_impl_android.h"
+#include "content/browser/device_orientation/data_fetcher_impl_android.h"
+#include "content/common/device_motion_hardware_buffer.h"
+#include "content/common/device_orientation/device_orientation_hardware_buffer.h"
 
 namespace content {
 
+DataFetcherSharedMemory::DataFetcherSharedMemory() {
+}
+
 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
-  if (started_)
-    StopFetchingDeviceMotionData();
 }
 
-bool DataFetcherSharedMemory::NeedsPolling() {
+bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) {
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      if (void* buffer = InitSharedMemoryBuffer(consumer_type,
+          sizeof(DeviceMotionHardwareBuffer))) {
+        return DataFetcherImplAndroid::GetInstance()->
+            StartFetchingDeviceMotionData(
+                static_cast<DeviceMotionHardwareBuffer*>(buffer));
+      }
+      break;
+    case CONSUMER_TYPE_ORIENTATION:
+      NOTIMPLEMENTED();
+      break;
+    default:
+      NOTREACHED();
+  }
   return false;
 }
 
-bool DataFetcherSharedMemory::FetchDeviceMotionDataIntoBuffer() {
-  NOTREACHED();
+bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      DataFetcherImplAndroid::GetInstance()->StopFetchingDeviceMotionData();
+      return true;
+    case CONSUMER_TYPE_ORIENTATION:
+      NOTIMPLEMENTED();
+      break;
+    default:
+      NOTREACHED();
+  }
   return false;
 }
 
-bool DataFetcherSharedMemory::StartFetchingDeviceMotionData(
-    DeviceMotionHardwareBuffer* buffer) {
-  DCHECK(buffer);
-  device_motion_buffer_ = buffer;
-  started_ = DataFetcherImplAndroid::GetInstance()->
-      StartFetchingDeviceMotionData(buffer);
-  return started_;
-}
-
-void DataFetcherSharedMemory::StopFetchingDeviceMotionData() {
-  DataFetcherImplAndroid::GetInstance()->StopFetchingDeviceMotionData();
-  started_ = false;
-}
-
 }  // namespace content
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_base.cc b/content/browser/device_orientation/data_fetcher_shared_memory_base.cc
new file mode 100644
index 0000000..167b787
--- /dev/null
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_base.cc
@@ -0,0 +1,197 @@
+// Copyright 2013 The Chromium Authors. 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/device_orientation/data_fetcher_shared_memory_base.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/threading/thread.h"
+#include "base/timer/timer.h"
+
+namespace content {
+
+namespace {
+const int kPeriodInMilliseconds = 100;
+}
+
+class DataFetcherSharedMemoryBase::PollingThread : public base::Thread {
+ public:
+  PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher);
+  virtual ~PollingThread();
+
+  void SetConsumers(int consumers_bitmask);
+  unsigned GetConsumersBitmask() const { return consumers_bitmask_; }
+
+ private:
+
+  void DoPoll();
+
+  unsigned consumers_bitmask_;
+  DataFetcherSharedMemoryBase* fetcher_;
+  scoped_ptr<base::RepeatingTimer<PollingThread> > timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PollingThread);
+};
+
+// --- PollingThread methods
+
+DataFetcherSharedMemoryBase::PollingThread::PollingThread(
+    const char* name, DataFetcherSharedMemoryBase* fetcher)
+    : base::Thread(name), consumers_bitmask_(0), fetcher_(fetcher) {
+}
+
+DataFetcherSharedMemoryBase::PollingThread::~PollingThread() {
+}
+
+void DataFetcherSharedMemoryBase::PollingThread::SetConsumers(
+    int consumers_bitmask) {
+  consumers_bitmask_ = consumers_bitmask;
+  if (!consumers_bitmask_) {
+    timer_.reset(); // will also stop the timer.
+    return;
+  }
+
+  if (!timer_)
+    timer_.reset(new base::RepeatingTimer<PollingThread>());
+
+  timer_->Start(FROM_HERE,
+                base::TimeDelta::FromMilliseconds(kPeriodInMilliseconds),
+                this, &PollingThread::DoPoll);
+}
+
+void DataFetcherSharedMemoryBase::PollingThread::DoPoll() {
+  DCHECK(fetcher_);
+  DCHECK(consumers_bitmask_);
+  fetcher_->Fetch(consumers_bitmask_);
+}
+
+// --- end of PollingThread methods
+
+DataFetcherSharedMemoryBase::DataFetcherSharedMemoryBase()
+    :  started_consumers_(0) {
+}
+
+DataFetcherSharedMemoryBase::~DataFetcherSharedMemoryBase() {
+  StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
+  StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+
+  // make sure polling thread stops asap.
+  if (polling_thread_)
+    polling_thread_->Stop();
+
+  STLDeleteContainerPairSecondPointers(shared_memory_map_.begin(),
+      shared_memory_map_.end());
+}
+
+bool DataFetcherSharedMemoryBase::StartFetchingDeviceData(
+    ConsumerType consumer_type) {
+  if (started_consumers_ & consumer_type)
+    return true;
+
+  if (!Start(consumer_type))
+    return false;
+
+  started_consumers_ |= consumer_type;
+
+  if (IsPolling()) {
+    if (!InitAndStartPollingThreadIfNecessary()) {
+      Stop(consumer_type);
+      started_consumers_ ^= consumer_type;
+      return false;
+    }
+    polling_thread_->message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&PollingThread::SetConsumers,
+                   base::Unretained(polling_thread_.get()),
+                   started_consumers_));
+  }
+  return true;
+}
+
+bool DataFetcherSharedMemoryBase::StopFetchingDeviceData(
+    ConsumerType consumer_type) {
+  if (!(started_consumers_ & consumer_type))
+    return true;
+
+  if (!Stop(consumer_type))
+    return false;
+
+  started_consumers_ ^= consumer_type;
+
+  if (IsPolling()) {
+    polling_thread_->message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&PollingThread::SetConsumers,
+                   base::Unretained(polling_thread_.get()),
+                   started_consumers_));
+  }
+  return true;
+}
+
+base::SharedMemoryHandle
+DataFetcherSharedMemoryBase::GetSharedMemoryHandleForProcess(
+    ConsumerType consumer_type, base::ProcessHandle process) {
+  SharedMemoryMap::const_iterator it = shared_memory_map_.find(consumer_type);
+  if (it == shared_memory_map_.end())
+    return base::SharedMemory::NULLHandle();
+
+  base::SharedMemoryHandle renderer_handle;
+  it->second->ShareToProcess(process, &renderer_handle);
+  return renderer_handle;
+}
+
+bool DataFetcherSharedMemoryBase::InitAndStartPollingThreadIfNecessary() {
+  if (polling_thread_)
+    return true;
+
+  polling_thread_.reset(
+      new PollingThread("Inertial Device Sensor poller", this));
+
+  if (!polling_thread_->Start()) {
+      LOG(ERROR) << "Failed to start inertial sensor data polling thread";
+      return false;
+  }
+  return true;
+}
+
+void DataFetcherSharedMemoryBase::Fetch(unsigned consumer_bitmask) {
+  NOTIMPLEMENTED();
+}
+
+bool DataFetcherSharedMemoryBase::IsPolling() const {
+  return false;
+}
+
+base::SharedMemory* DataFetcherSharedMemoryBase::InitSharedMemory(
+    ConsumerType consumer_type, size_t buffer_size) {
+  SharedMemoryMap::const_iterator it = shared_memory_map_.find(consumer_type);
+  if (it != shared_memory_map_.end())
+    return it->second;
+
+  base::SharedMemory* new_shared_mem = new base::SharedMemory;
+  if (new_shared_mem->CreateAndMapAnonymous(buffer_size)) {
+    if (void* mem = new_shared_mem->memory()) {
+      memset(mem, 0, buffer_size);
+      shared_memory_map_[consumer_type] = new_shared_mem;
+      return new_shared_mem;
+    }
+  }
+  LOG(ERROR) << "Failed to initialize shared memory";
+  return NULL;
+}
+
+void* DataFetcherSharedMemoryBase::InitSharedMemoryBuffer(
+    ConsumerType consumer_type, size_t buffer_size) {
+  if (base::SharedMemory* shared_memory = InitSharedMemory(consumer_type,
+      buffer_size))
+    return shared_memory->memory();
+  return NULL;
+}
+
+base::MessageLoop* DataFetcherSharedMemoryBase::GetPollingMessageLoop() const {
+  return polling_thread_ ? polling_thread_->message_loop() : NULL;
+}
+
+}  // namespace content
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_base.h b/content/browser/device_orientation/data_fetcher_shared_memory_base.h
new file mode 100644
index 0000000..a449596
--- /dev/null
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_base.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_SHARED_MEMORY_BASE_H_
+#define CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_SHARED_MEMORY_BASE_H_
+
+#include <map>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "content/browser/device_orientation/inertial_sensor_consts.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Sensor data fetchers should derive from this base class and implement
+// the abstract Start() and Stop() methods.
+// If the fetcher requires polling it should also implement IsPolling()
+// to return true and the Fetch() method which will be called from the
+// polling thread to fetch data at regular intervals.
+class CONTENT_EXPORT DataFetcherSharedMemoryBase {
+ public:
+
+  // Starts updating the shared memory buffer with sensor data at
+  // regular intervals. Returns true if the relevant sensors could
+  // be successfully activated.
+  bool StartFetchingDeviceData(ConsumerType consumer_type);
+
+  // Stops updating the shared memory buffer. Returns true if the
+  // relevant sensors could be successfully deactivated.
+  bool StopFetchingDeviceData(ConsumerType consumer_type);
+
+  // Returns the shared memory handle of the device sensor data
+  // duplicated into the given process. This method should only be
+  // called after a call to StartFetchingDeviceData method with
+  // corresponding |consumer_type| parameter.
+  base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
+      ConsumerType consumer_type, base::ProcessHandle process);
+
+ protected:
+  class PollingThread;
+
+  DataFetcherSharedMemoryBase();
+  virtual ~DataFetcherSharedMemoryBase();
+
+  void* InitSharedMemoryBuffer(ConsumerType consumer_type, size_t buffer_size);
+
+  // Returns the message loop of the polling thread.
+  // Returns NULL if there is no polling thread.
+  base::MessageLoop* GetPollingMessageLoop() const;
+
+  // If IsPolling() is true this method is called from the |polling_thread_|
+  // at regular intervals.
+  virtual void Fetch(unsigned consumer_bitmask);
+
+  // Returns true if this fetcher needs to use a polling thread to
+  // fetch the sensor data.
+  virtual bool IsPolling() const;
+
+  // Start() method should call InitSharedMemoryBuffer() and cache the obtained
+  // pointer for efficienty and thread-safety.
+  virtual bool Start(ConsumerType consumer_type) = 0;
+  virtual bool Stop(ConsumerType consumer_type) = 0;
+
+ private:
+  bool InitAndStartPollingThreadIfNecessary();
+  base::SharedMemory* InitSharedMemory(ConsumerType consumer_type,
+      size_t buffer_size);
+
+  unsigned started_consumers_;
+
+  scoped_ptr<PollingThread> polling_thread_;
+
+  // Owning pointers. Objects in the map are deleted in dtor.
+  typedef std::map<ConsumerType, base::SharedMemory*> SharedMemoryMap;
+  SharedMemoryMap shared_memory_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(DataFetcherSharedMemoryBase);
+};
+
+}
+
+#endif  // CONTENT_BROWSER_DEVICE_ORIENTATION_DATA_FETCHER_SHARED_MEMORY_BASE_H_
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc b/content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc
new file mode 100644
index 0000000..b580872
--- /dev/null
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright 2013 The Chromium Authors. 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/device_orientation/data_fetcher_shared_memory_base.h"
+
+#include "base/logging.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "content/common/device_motion_hardware_buffer.h"
+#include "content/common/device_orientation/device_orientation_hardware_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+const int kPeriodInMilliseconds = 100;
+
+
+class FakeDataFetcher : public DataFetcherSharedMemoryBase {
+ public:
+  FakeDataFetcher()
+      : start_(false, false),
+        stop_(false, false),
+        updated_motion_(false, false),
+        updated_orientation_(false, false) {
+  }
+  virtual ~FakeDataFetcher() { }
+
+  bool Init(ConsumerType consumer_type) {
+    switch (consumer_type) {
+      case CONSUMER_TYPE_MOTION:
+        motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(
+             InitSharedMemoryBuffer(consumer_type,
+                 sizeof(DeviceMotionHardwareBuffer)));
+        break;
+      case CONSUMER_TYPE_ORIENTATION:
+        orientation_buffer_ = static_cast<DeviceOrientationHardwareBuffer*>(
+            InitSharedMemoryBuffer(consumer_type,
+                sizeof(DeviceOrientationHardwareBuffer)));
+        break;
+      default:
+        return false;
+    }
+    return true;
+  }
+
+  void UpdateMotion() {
+    DeviceMotionHardwareBuffer* buffer = GetMotionBuffer();
+    ASSERT_TRUE(buffer);
+    buffer->seqlock.WriteBegin();
+    buffer->data.interval = kPeriodInMilliseconds;
+    buffer->seqlock.WriteEnd();
+    updated_motion_.Signal();
+  }
+
+  void UpdateOrientation() {
+    DeviceOrientationHardwareBuffer* buffer = GetOrientationBuffer();
+    ASSERT_TRUE(buffer);
+    buffer->seqlock.WriteBegin();
+    buffer->data.alpha = 1;
+    buffer->seqlock.WriteEnd();
+    updated_orientation_.Signal();
+  }
+
+  DeviceMotionHardwareBuffer* GetMotionBuffer() const {
+    return motion_buffer_;
+  }
+
+  DeviceOrientationHardwareBuffer* GetOrientationBuffer() const {
+    return orientation_buffer_;
+  }
+
+  void WaitForStart() {
+    start_.Wait();
+  }
+
+  void WaitForStop() {
+    stop_.Wait();
+  }
+
+  void WaitForUpdateMotion() {
+    updated_motion_.Wait();
+  }
+
+  void WaitForUpdateOrientation() {
+    updated_orientation_.Wait();
+  }
+
+ protected:
+  base::WaitableEvent start_;
+  base::WaitableEvent stop_;
+  base::WaitableEvent updated_motion_;
+  base::WaitableEvent updated_orientation_;
+
+ private:
+  DeviceMotionHardwareBuffer* motion_buffer_;
+  DeviceOrientationHardwareBuffer* orientation_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDataFetcher);
+};
+
+class FakeNonPollingDataFetcher : public FakeDataFetcher {
+ public:
+  FakeNonPollingDataFetcher() { }
+  virtual ~FakeNonPollingDataFetcher() { }
+
+  virtual bool Start(ConsumerType consumer_type) OVERRIDE {
+    Init(consumer_type);
+    switch (consumer_type) {
+      case CONSUMER_TYPE_MOTION:
+        UpdateMotion();
+        break;
+      case CONSUMER_TYPE_ORIENTATION:
+        UpdateOrientation();
+        break;
+      default:
+        return false;
+    }
+    start_.Signal();
+    return true;
+  }
+
+  virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
+    stop_.Signal();
+    return true;
+  }
+
+  virtual bool IsPolling() const OVERRIDE {
+    return false;
+  }
+
+  virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
+    FAIL() << "fetch should not be called, "
+        << "because this is a non-polling fetcher";
+  }
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(FakeNonPollingDataFetcher);
+};
+
+class FakePollingDataFetcher : public FakeDataFetcher {
+ public:
+  FakePollingDataFetcher() { }
+  virtual ~FakePollingDataFetcher() { }
+
+  virtual bool Start(ConsumerType consumer_type) OVERRIDE {
+    Init(consumer_type);
+    start_.Signal();
+    return true;
+  }
+
+  virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
+    stop_.Signal();
+    return true;
+  }
+
+  virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
+    DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+
+    if (consumer_bitmask & CONSUMER_TYPE_ORIENTATION)
+      UpdateOrientation();
+    else if (consumer_bitmask & CONSUMER_TYPE_MOTION)
+      UpdateMotion();
+    else
+      FAIL() << "wrong consumer bitmask";
+  }
+
+  virtual bool IsPolling() const OVERRIDE {
+    return true;
+  }
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(FakePollingDataFetcher);
+};
+
+
+TEST(DataFetcherSharedMemoryBaseTest, DoesStartMotion) {
+    FakeNonPollingDataFetcher* mock_data_fetcher =
+      new FakeNonPollingDataFetcher();
+  EXPECT_FALSE(mock_data_fetcher->IsPolling());
+
+  EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(CONSUMER_TYPE_MOTION));
+  mock_data_fetcher->WaitForStart();
+
+  EXPECT_EQ(kPeriodInMilliseconds,
+      mock_data_fetcher->GetMotionBuffer()->data.interval);
+
+  mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
+  mock_data_fetcher->WaitForStop();
+}
+
+TEST(DataFetcherSharedMemoryBaseTest, DoesStartOrientation) {
+  FakeNonPollingDataFetcher* mock_data_fetcher =
+      new FakeNonPollingDataFetcher();
+  EXPECT_FALSE(mock_data_fetcher->IsPolling());
+
+  EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(
+      CONSUMER_TYPE_ORIENTATION));
+  mock_data_fetcher->WaitForStart();
+
+  EXPECT_EQ(1, mock_data_fetcher->GetOrientationBuffer()->data.alpha);
+
+  mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+  mock_data_fetcher->WaitForStop();
+}
+
+TEST(DataFetcherSharedMemoryBaseTest, DoesPollMotion) {
+    FakePollingDataFetcher* mock_data_fetcher =
+      new FakePollingDataFetcher();
+  EXPECT_TRUE(mock_data_fetcher->IsPolling());
+
+  EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(CONSUMER_TYPE_MOTION));
+  mock_data_fetcher->WaitForStart();
+  mock_data_fetcher->WaitForUpdateMotion();
+
+  EXPECT_EQ(kPeriodInMilliseconds,
+      mock_data_fetcher->GetMotionBuffer()->data.interval);
+
+  mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
+  mock_data_fetcher->WaitForStop();
+}
+
+TEST(DataFetcherSharedMemoryBaseTest, DoesPollOrientation) {
+  FakePollingDataFetcher* mock_data_fetcher =
+      new FakePollingDataFetcher();
+  EXPECT_TRUE(mock_data_fetcher->IsPolling());
+
+  EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(
+      CONSUMER_TYPE_ORIENTATION));
+  mock_data_fetcher->WaitForStart();
+  mock_data_fetcher->WaitForUpdateOrientation();
+
+  EXPECT_EQ(1, mock_data_fetcher->GetOrientationBuffer()->data.alpha);
+
+  mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+  mock_data_fetcher->WaitForStop();
+}
+
+}  // namespace
+
+}  // namespace content
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_default.cc b/content/browser/device_orientation/data_fetcher_shared_memory_default.cc
index 0f66fc7..693019f 100644
--- a/content/browser/device_orientation/data_fetcher_shared_memory_default.cc
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_default.cc
@@ -5,39 +5,62 @@
 #include "data_fetcher_shared_memory.h"
 
 #include "base/logging.h"
+#include "content/common/device_motion_hardware_buffer.h"
+#include "content/common/device_orientation/device_orientation_hardware_buffer.h"
 
-namespace content {
+namespace {
 
-DataFetcherSharedMemory::~DataFetcherSharedMemory() {
-  if (started_)
-    StopFetchingDeviceMotionData();
-}
-
-bool DataFetcherSharedMemory::NeedsPolling() {
-  return false;
-}
-
-bool DataFetcherSharedMemory::FetchDeviceMotionDataIntoBuffer() {
-  NOTREACHED();
-  return false;
-}
-
-bool DataFetcherSharedMemory::StartFetchingDeviceMotionData(
-    DeviceMotionHardwareBuffer* buffer) {
+static bool SetMotionBuffer(content::DeviceMotionHardwareBuffer* buffer,
+    bool enabled) {
   DCHECK(buffer);
-  device_motion_buffer_ = buffer;
-  device_motion_buffer_->seqlock.WriteBegin();
-  device_motion_buffer_->data.allAvailableSensorsAreActive = true;
-  device_motion_buffer_->seqlock.WriteEnd();
-  started_ = true;
+  buffer->seqlock.WriteBegin();
+  buffer->data.allAvailableSensorsAreActive = enabled;
+  buffer->seqlock.WriteEnd();
   return true;
 }
 
-void DataFetcherSharedMemory::StopFetchingDeviceMotionData() {
-  device_motion_buffer_->seqlock.WriteBegin();
-  device_motion_buffer_->data.allAvailableSensorsAreActive = false;
-  device_motion_buffer_->seqlock.WriteEnd();
-  started_ = false;
+}
+
+namespace content {
+
+DataFetcherSharedMemory::DataFetcherSharedMemory() {
+}
+
+DataFetcherSharedMemory::~DataFetcherSharedMemory() {
+}
+
+bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) {
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      if (void* buffer = InitSharedMemoryBuffer(consumer_type,
+          sizeof(DeviceMotionHardwareBuffer)))
+        return SetMotionBuffer(
+            static_cast<DeviceMotionHardwareBuffer*>(buffer), true);
+      break;
+    case CONSUMER_TYPE_ORIENTATION:
+      NOTIMPLEMENTED();
+      break;
+    default:
+      NOTREACHED();
+  }
+  return false;
+}
+
+bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      if (void* buffer = InitSharedMemoryBuffer(consumer_type,
+          sizeof(DeviceMotionHardwareBuffer)))
+        return SetMotionBuffer(
+            static_cast<DeviceMotionHardwareBuffer*>(buffer), false);
+      break;
+    case CONSUMER_TYPE_ORIENTATION:
+      NOTIMPLEMENTED();
+      break;
+    default:
+      NOTREACHED();
+  }
+  return false;
 }
 
 }  // namespace content
diff --git a/content/browser/device_orientation/device_inertial_sensor_service.cc b/content/browser/device_orientation/device_inertial_sensor_service.cc
new file mode 100644
index 0000000..ee90be1
--- /dev/null
+++ b/content/browser/device_orientation/device_inertial_sensor_service.cc
@@ -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.
+
+#include "content/browser/device_orientation/device_inertial_sensor_service.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "content/browser/device_orientation/data_fetcher_shared_memory.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+DeviceInertialSensorService::DeviceInertialSensorService()
+    : num_motion_readers_(0),
+      num_orientation_readers_(0),
+      is_shutdown_(false) {
+}
+
+DeviceInertialSensorService::~DeviceInertialSensorService() {
+}
+
+DeviceInertialSensorService* DeviceInertialSensorService::GetInstance() {
+  return Singleton<DeviceInertialSensorService,
+                   LeakySingletonTraits<DeviceInertialSensorService> >::get();
+}
+
+void DeviceInertialSensorService::AddConsumer(ConsumerType consumer_type) {
+  if (!ChangeNumberConsumers(consumer_type, 1))
+    return;
+
+  DCHECK(GetNumberConsumers(consumer_type));
+
+  if (!data_fetcher_)
+    data_fetcher_.reset(new DataFetcherSharedMemory);
+  data_fetcher_->StartFetchingDeviceData(consumer_type);
+}
+
+void DeviceInertialSensorService::RemoveConsumer(ConsumerType consumer_type) {
+  if (!ChangeNumberConsumers(consumer_type, -1))
+    return;
+
+  if (GetNumberConsumers(consumer_type) == 0)
+    data_fetcher_->StopFetchingDeviceData(consumer_type);
+}
+
+bool DeviceInertialSensorService::ChangeNumberConsumers(
+    ConsumerType consumer_type, int delta) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (is_shutdown_)
+    return false;
+
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      num_motion_readers_ += delta;
+      DCHECK(num_motion_readers_ >= 0);
+      return true;
+    case CONSUMER_TYPE_ORIENTATION:
+      num_orientation_readers_ += delta;
+      DCHECK(num_orientation_readers_ >= 0);
+      return true;
+    default:
+      NOTREACHED();
+  }
+  return false;
+}
+
+int DeviceInertialSensorService::GetNumberConsumers(
+    ConsumerType consumer_type) const {
+  switch (consumer_type) {
+    case CONSUMER_TYPE_MOTION:
+      return num_motion_readers_;
+    case CONSUMER_TYPE_ORIENTATION:
+      return num_orientation_readers_;
+    default:
+      NOTREACHED();
+  }
+  return 0;
+}
+
+base::SharedMemoryHandle
+DeviceInertialSensorService::GetSharedMemoryHandleForProcess(
+    ConsumerType consumer_type, base::ProcessHandle handle) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return data_fetcher_->GetSharedMemoryHandleForProcess(consumer_type, handle);
+}
+
+void DeviceInertialSensorService::Shutdown() {
+  data_fetcher_.reset();
+  is_shutdown_ = true;
+}
+
+}  // namespace content
diff --git a/content/browser/device_orientation/device_inertial_sensor_service.h b/content/browser/device_orientation/device_inertial_sensor_service.h
new file mode 100644
index 0000000..028d155
--- /dev/null
+++ b/content/browser/device_orientation/device_inertial_sensor_service.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 CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_INERTIAL_SENSOR_SERVICE_H_
+#define CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_INERTIAL_SENSOR_SERVICE_H_
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/singleton.h"
+#include "base/threading/thread_checker.h"
+#include "content/browser/device_orientation/inertial_sensor_consts.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class DataFetcherSharedMemory;
+class RenderProcessHost;
+
+// Owns the DeviceMotionProvider (the background polling thread) and keeps
+// track of the number of consumers currently using the data (and pausing
+// the provider when not in use).
+class CONTENT_EXPORT DeviceInertialSensorService {
+ public:
+  // Returns the DeviceInertialSensorService singleton.
+  static DeviceInertialSensorService* GetInstance();
+
+  // Increments the number of users of the provider. The Provider is running
+  // when there's > 0 users, and is paused when the count drops to 0.
+  // Must be called on the I/O thread.
+  void AddConsumer(ConsumerType consumer_type);
+
+  // Removes a consumer. Should be matched with an AddConsumer call.
+  // Must be called on the I/O thread.
+  void RemoveConsumer(ConsumerType cosumer_type);
+
+  // Returns the shared memory handle of the device motion data duplicated
+  // into the given process.
+  base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
+      ConsumerType consumer_type, base::ProcessHandle handle);
+
+  // Stop/join with the background polling thread in |provider_|.
+  void Shutdown();
+
+ private:
+  friend struct DefaultSingletonTraits<DeviceInertialSensorService>;
+
+  DeviceInertialSensorService();
+  virtual ~DeviceInertialSensorService();
+
+  bool ChangeNumberConsumers(ConsumerType consumer_type,
+      int delta);
+  int GetNumberConsumers(ConsumerType consumer_type) const;
+
+  int num_motion_readers_;
+  int num_orientation_readers_;
+  bool is_shutdown_;
+  scoped_ptr<DataFetcherSharedMemory> data_fetcher_;
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeviceInertialSensorService);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_INERTIAL_SENSOR_SERVICE_H_
diff --git a/content/browser/device_orientation/device_motion_message_filter.cc b/content/browser/device_orientation/device_motion_message_filter.cc
index 3c619c6..bc33cac 100644
--- a/content/browser/device_orientation/device_motion_message_filter.cc
+++ b/content/browser/device_orientation/device_motion_message_filter.cc
@@ -4,7 +4,7 @@
 
 #include "content/browser/device_orientation/device_motion_message_filter.h"
 
-#include "content/browser/device_orientation/device_motion_service.h"
+#include "content/browser/device_orientation/device_inertial_sensor_service.h"
 #include "content/common/device_orientation/device_motion_messages.h"
 
 namespace content {
@@ -16,7 +16,8 @@
 DeviceMotionMessageFilter::~DeviceMotionMessageFilter() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   if (is_started_)
-    DeviceMotionService::GetInstance()->RemoveConsumer();
+    DeviceInertialSensorService::GetInstance()->RemoveConsumer(
+        CONSUMER_TYPE_MOTION);
 }
 
 bool DeviceMotionMessageFilter::OnMessageReceived(
@@ -40,7 +41,8 @@
   if (is_started_)
     return;
   is_started_ = true;
-  DeviceMotionService::GetInstance()->AddConsumer();
+  DeviceInertialSensorService::GetInstance()->AddConsumer(
+      CONSUMER_TYPE_MOTION);
   DidStartDeviceMotionPolling();
 }
 
@@ -49,13 +51,15 @@
   if (!is_started_)
     return;
   is_started_ = false;
-  DeviceMotionService::GetInstance()->RemoveConsumer();
+  DeviceInertialSensorService::GetInstance()->RemoveConsumer(
+      CONSUMER_TYPE_MOTION);
 }
 
 void DeviceMotionMessageFilter::DidStartDeviceMotionPolling() {
   Send(new DeviceMotionMsg_DidStartPolling(
-      DeviceMotionService::GetInstance()->GetSharedMemoryHandleForProcess(
-          PeerHandle())));
+      DeviceInertialSensorService::GetInstance()->
+          GetSharedMemoryHandleForProcess(
+              CONSUMER_TYPE_MOTION, PeerHandle())));
 }
 
 }  // namespace content
diff --git a/content/browser/device_orientation/device_motion_provider.cc b/content/browser/device_orientation/device_motion_provider.cc
deleted file mode 100644
index e88d5af..0000000
--- a/content/browser/device_orientation/device_motion_provider.cc
+++ /dev/null
@@ -1,172 +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/device_orientation/device_motion_provider.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/threading/thread.h"
-#include "base/timer/timer.h"
-#include "content/browser/device_orientation/data_fetcher_shared_memory.h"
-#include "content/common/device_motion_hardware_buffer.h"
-
-namespace content {
-
-namespace {
-const int kPeriodInMilliseconds = 100;
-}
-
-class DeviceMotionProvider::PollingThread : public base::Thread {
- public:
-  explicit PollingThread(const char* name);
-  virtual ~PollingThread();
-
-  void StartPolling(DataFetcherSharedMemory* fetcher,
-                    DeviceMotionHardwareBuffer* buffer);
-  void StopPolling();
-
- private:
-  void DoPoll();
-
-  scoped_ptr<base::RepeatingTimer<PollingThread> > timer_;
-  DataFetcherSharedMemory* fetcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(PollingThread);
-};
-
-// ---- PollingThread methods
-
-DeviceMotionProvider::PollingThread::PollingThread(const char* name)
-    : base::Thread(name) {
-}
-
-DeviceMotionProvider::PollingThread::~PollingThread() {
-}
-
-void DeviceMotionProvider::PollingThread::StartPolling(
-    DataFetcherSharedMemory* fetcher, DeviceMotionHardwareBuffer* buffer) {
-  DCHECK(base::MessageLoop::current() == message_loop());
-  DCHECK(!timer_);
-
-  fetcher_ = fetcher;
-  fetcher_->StartFetchingDeviceMotionData(buffer);
-  timer_.reset(new base::RepeatingTimer<PollingThread>());
-  timer_->Start(FROM_HERE,
-                base::TimeDelta::FromMilliseconds(kPeriodInMilliseconds),
-                this, &PollingThread::DoPoll);
-}
-
-void DeviceMotionProvider::PollingThread::StopPolling() {
-  DCHECK(base::MessageLoop::current() == message_loop());
-  DCHECK(fetcher_);
-  // this will also stop the timer before killing it.
-  timer_.reset();
-  fetcher_->StopFetchingDeviceMotionData();
-}
-
-void DeviceMotionProvider::PollingThread::DoPoll() {
-  DCHECK(base::MessageLoop::current() == message_loop());
-  fetcher_->FetchDeviceMotionDataIntoBuffer();
-}
-
-// ---- end PollingThread methods
-
-DeviceMotionProvider::DeviceMotionProvider()
-    : is_started_(false) {
-  Initialize();
-}
-
-DeviceMotionProvider::DeviceMotionProvider(
-    scoped_ptr<DataFetcherSharedMemory> fetcher)
-    : is_started_(false) {
-  data_fetcher_ = fetcher.Pass();
-  Initialize();
-}
-
-DeviceMotionProvider::~DeviceMotionProvider() {
-  StopFetchingDeviceMotionData();
-  // make sure polling thread stops before data_fetcher_ gets deleted.
-  if (polling_thread_)
-    polling_thread_->Stop();
-  data_fetcher_.reset();
-}
-
-void DeviceMotionProvider::Initialize() {
-  size_t data_size = sizeof(DeviceMotionHardwareBuffer);
-  bool res = device_motion_shared_memory_.CreateAndMapAnonymous(data_size);
-  // TODO(timvolodine): consider not crashing the browser if the check fails.
-  CHECK(res);
-  DeviceMotionHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
-  memset(hwbuf, 0, sizeof(DeviceMotionHardwareBuffer));
-}
-
-base::SharedMemoryHandle DeviceMotionProvider::GetSharedMemoryHandleForProcess(
-    base::ProcessHandle process) {
-  base::SharedMemoryHandle renderer_handle;
-  device_motion_shared_memory_.ShareToProcess(process, &renderer_handle);
-  return renderer_handle;
-}
-
-void DeviceMotionProvider::StartFetchingDeviceMotionData() {
-  if (is_started_)
-    return;
-
-  if (!data_fetcher_)
-    data_fetcher_.reset(new DataFetcherSharedMemory);
-
-  if (data_fetcher_->NeedsPolling()) {
-    if (!polling_thread_)
-        CreateAndStartPollingThread();
-
-    polling_thread_->message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&PollingThread::StartPolling,
-                   base::Unretained(polling_thread_.get()),
-                   data_fetcher_.get(),
-                   SharedMemoryAsHardwareBuffer()));
-  } else {
-    data_fetcher_->StartFetchingDeviceMotionData(
-        SharedMemoryAsHardwareBuffer());
-  }
-
-  is_started_ = true;
-}
-
-void DeviceMotionProvider::CreateAndStartPollingThread() {
-  polling_thread_.reset(
-      new PollingThread("Device Motion poller"));
-
-  if (!polling_thread_->Start()) {
-      LOG(ERROR) << "Failed to start Device Motion data polling thread";
-      return;
-  }
-}
-
-void DeviceMotionProvider::StopFetchingDeviceMotionData() {
-  if (!is_started_)
-    return;
-
-  DCHECK(data_fetcher_);
-
-  if (data_fetcher_->NeedsPolling()) {
-    DCHECK(polling_thread_);
-    polling_thread_->message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&PollingThread::StopPolling,
-                   base::Unretained(polling_thread_.get())));
-  } else {
-    data_fetcher_->StopFetchingDeviceMotionData();
-  }
-
-  is_started_ = false;
-}
-
-DeviceMotionHardwareBuffer*
-DeviceMotionProvider::SharedMemoryAsHardwareBuffer() {
-  void* mem = device_motion_shared_memory_.memory();
-  CHECK(mem);
-  return static_cast<DeviceMotionHardwareBuffer*>(mem);
-}
-
-}  // namespace content
diff --git a/content/browser/device_orientation/device_motion_provider.h b/content/browser/device_orientation/device_motion_provider.h
deleted file mode 100644
index 8fd36de..0000000
--- a/content/browser/device_orientation/device_motion_provider.h
+++ /dev/null
@@ -1,56 +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_DEVICE_ORIENTATION_DEVICE_MOTION_PROVIDER_H_
-#define CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_MOTION_PROVIDER_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/shared_memory.h"
-#include "content/common/content_export.h"
-#include "content/common/device_motion_hardware_buffer.h"
-
-namespace content {
-class DataFetcherSharedMemory;
-
-// This class owns the shared memory buffer for Device Motion and makes
-// sure the data is fetched into that buffer.
-// When DataFetcherSharedMemory::NeedsPolling() is true, it starts a
-// background polling thread to make sure the data is fetched at regular
-// intervals.
-class CONTENT_EXPORT DeviceMotionProvider {
- public:
-  DeviceMotionProvider();
-
-  // Creates provider with a custom fetcher. Used for testing.
-  explicit DeviceMotionProvider(scoped_ptr<DataFetcherSharedMemory> fetcher);
-
-  virtual ~DeviceMotionProvider();
-
-  // Returns the shared memory handle of the device motion data duplicated
-  // into the given process.
-  base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
-      base::ProcessHandle renderer_process);
-
-  void StartFetchingDeviceMotionData();
-  void StopFetchingDeviceMotionData();
-
- private:
-  class PollingThread;
-
-  void Initialize();
-  void CreateAndStartPollingThread();
-
-  DeviceMotionHardwareBuffer* SharedMemoryAsHardwareBuffer();
-
-  base::SharedMemory device_motion_shared_memory_;
-  scoped_ptr<DataFetcherSharedMemory> data_fetcher_;
-  scoped_ptr<PollingThread> polling_thread_;
-  bool is_started_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeviceMotionProvider);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_MOTION_PROVIDER_H_
diff --git a/content/browser/device_orientation/device_motion_provider_unittest.cc b/content/browser/device_orientation/device_motion_provider_unittest.cc
deleted file mode 100644
index cd0f3d8..0000000
--- a/content/browser/device_orientation/device_motion_provider_unittest.cc
+++ /dev/null
@@ -1,98 +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/device_orientation/device_motion_provider.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/waitable_event.h"
-#include "content/browser/device_orientation/data_fetcher_shared_memory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-namespace {
-
-const int kPeriodInMilliseconds = 100;
-
-class FakeDataFetcherSharedMemory : public DataFetcherSharedMemory {
- public:
-  FakeDataFetcherSharedMemory()
-      : start_fetching_data_(false, false),
-        stop_fetching_data_(false, false),
-        fetched_data_(false, false) {
-  }
-  virtual ~FakeDataFetcherSharedMemory() { }
-
-  virtual bool NeedsPolling() OVERRIDE {
-    return true;
-  }
-
-  virtual bool FetchDeviceMotionDataIntoBuffer() OVERRIDE {
-    buffer_->seqlock.WriteBegin();
-    buffer_->data.interval = kPeriodInMilliseconds;
-    buffer_->seqlock.WriteEnd();
-    fetched_data_.Signal();
-    return true;
-  }
-
-  virtual bool StartFetchingDeviceMotionData(
-    DeviceMotionHardwareBuffer* buffer) OVERRIDE {
-    buffer_ = buffer;
-    start_fetching_data_.Signal();
-    return true;
-  }
-
-  virtual void StopFetchingDeviceMotionData() OVERRIDE {
-    stop_fetching_data_.Signal();
-  }
-
-  void WaitForStart() {
-    start_fetching_data_.Wait();
-  }
-
-  void WaitForStop() {
-    stop_fetching_data_.Wait();
-  }
-
-  void WaitForDataFetch() {
-    fetched_data_.Wait();
-  }
-
-  DeviceMotionHardwareBuffer* GetBuffer() {
-    return buffer_;
-  }
-
- private:
-  base::WaitableEvent start_fetching_data_;
-  base::WaitableEvent stop_fetching_data_;
-  base::WaitableEvent fetched_data_;
-  DeviceMotionHardwareBuffer* buffer_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeDataFetcherSharedMemory);
-};
-
-
-TEST(DeviceMotionProviderTest, DoesPolling) {
-  FakeDataFetcherSharedMemory* mock_data_fetcher =
-      new FakeDataFetcherSharedMemory();
-  EXPECT_TRUE(mock_data_fetcher->NeedsPolling());
-
-  scoped_ptr<DeviceMotionProvider> provider(new DeviceMotionProvider(
-      scoped_ptr<DataFetcherSharedMemory>(mock_data_fetcher)));
-
-  provider->StartFetchingDeviceMotionData();
-  mock_data_fetcher->WaitForStart();
-  mock_data_fetcher->WaitForDataFetch();
-
-  EXPECT_EQ(kPeriodInMilliseconds,
-      mock_data_fetcher->GetBuffer()->data.interval);
-
-  provider->StopFetchingDeviceMotionData();
-  mock_data_fetcher->WaitForStop();
-}
-
-}  // namespace
-
-}  // namespace content
diff --git a/content/browser/device_orientation/device_motion_service.cc b/content/browser/device_orientation/device_motion_service.cc
deleted file mode 100644
index 48b784b..0000000
--- a/content/browser/device_orientation/device_motion_service.cc
+++ /dev/null
@@ -1,65 +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/device_orientation/device_motion_service.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "content/browser/device_orientation/device_motion_provider.h"
-#include "content/public/browser/render_process_host.h"
-
-namespace content {
-
-DeviceMotionService::DeviceMotionService()
-    : num_readers_(0),
-      is_shutdown_(false) {
-}
-
-DeviceMotionService::~DeviceMotionService() {
-}
-
-DeviceMotionService* DeviceMotionService::GetInstance() {
-  return Singleton<DeviceMotionService,
-                   LeakySingletonTraits<DeviceMotionService> >::get();
-}
-
-void DeviceMotionService::AddConsumer() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (is_shutdown_)
-    return;
-
-  num_readers_++;
-  DCHECK(num_readers_ > 0);
-  if (!provider_.get())
-    provider_.reset(new DeviceMotionProvider);
-  provider_->StartFetchingDeviceMotionData();
-}
-
-void DeviceMotionService::RemoveConsumer() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (is_shutdown_)
-    return;
-
-  --num_readers_;
-  DCHECK(num_readers_ >= 0);
-
-  if (num_readers_ == 0) {
-    LOG(INFO) << "ACTIVE service stop fetching";
-    provider_->StopFetchingDeviceMotionData();
-  }
-}
-
-void DeviceMotionService::Shutdown() {
-  provider_.reset();
-  is_shutdown_ = true;
-}
-
-base::SharedMemoryHandle DeviceMotionService::GetSharedMemoryHandleForProcess(
-    base::ProcessHandle handle) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  return provider_->GetSharedMemoryHandleForProcess(handle);
-}
-
-}  // namespace content
diff --git a/content/browser/device_orientation/device_motion_service.h b/content/browser/device_orientation/device_motion_service.h
deleted file mode 100644
index 0720bb9..0000000
--- a/content/browser/device_orientation/device_motion_service.h
+++ /dev/null
@@ -1,65 +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_DEVICE_ORIENTATION_DEVICE_MOTION_SERVICE_H_
-#define CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_MOTION_SERVICE_H_
-
-#include "base/basictypes.h"
-#include "base/callback_forward.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/shared_memory.h"
-#include "base/memory/singleton.h"
-#include "base/threading/thread_checker.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class DataFetcherSharedMemory;
-class DeviceMotionProvider;
-class RenderProcessHost;
-
-// Owns the DeviceMotionProvider (the background polling thread) and keeps
-// track of the number of consumers currently using the data (and pausing
-// the provider when not in use).
-class CONTENT_EXPORT DeviceMotionService {
- public:
-  // Returns the DeviceMotionService singleton.
-  static DeviceMotionService* GetInstance();
-
-  // Increments the number of users of the provider. The Provider is running
-  // when there's > 0 users, and is paused when the count drops to 0.
-  //
-  // Must be called on the I/O thread.
-  void AddConsumer();
-
-  // Removes a consumer. Should be matched with an AddConsumer call.
-  //
-  // Must be called on the I/O thread.
-  void RemoveConsumer();
-
-  // Returns the shared memory handle of the device motion data duplicated
-  // into the given process.
-  base::SharedMemoryHandle GetSharedMemoryHandleForProcess(
-      base::ProcessHandle handle);
-
-  // Stop/join with the background thread in DeviceMotionProvider |provider_|.
-  void Shutdown();
-
- private:
-  friend struct DefaultSingletonTraits<DeviceMotionService>;
-
-  DeviceMotionService();
-  virtual ~DeviceMotionService();
-
-  int num_readers_;
-  bool is_shutdown_;
-  scoped_ptr<DeviceMotionProvider> provider_;
-  base::ThreadChecker thread_checker_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeviceMotionService);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DEVICE_ORIENTATION_DEVICE_MOTION_SERVICE_H_
diff --git a/content/browser/device_orientation/device_orientation_browsertest.cc b/content/browser/device_orientation/device_orientation_browsertest.cc
index 17d9446..92a83c7 100644
--- a/content/browser/device_orientation/device_orientation_browsertest.cc
+++ b/content/browser/device_orientation/device_orientation_browsertest.cc
@@ -11,7 +11,7 @@
 #include "content/browser/device_orientation/provider.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 
@@ -71,7 +71,7 @@
 
   // Check that the page got the event it expected and that the provider
   // saw requests for adding and removing an observer.
-  EXPECT_EQ("pass", shell()->web_contents()->GetURL().ref());
+  EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
   EXPECT_TRUE(provider->added_observer_);
   EXPECT_TRUE(provider->removed_observer_);
 }
diff --git a/content/browser/device_orientation/device_orientation_message_filter.cc b/content/browser/device_orientation/device_orientation_message_filter.cc
index cbb1e67..f4acd94 100644
--- a/content/browser/device_orientation/device_orientation_message_filter.cc
+++ b/content/browser/device_orientation/device_orientation_message_filter.cc
@@ -4,7 +4,7 @@
 
 #include "content/browser/device_orientation/device_orientation_message_filter.h"
 
-#include "content/browser/device_orientation/device_motion_service.h"
+#include "content/browser/device_orientation/device_inertial_sensor_service.h"
 #include "content/common/device_orientation/device_orientation_messages.h"
 
 namespace content {
@@ -15,10 +15,9 @@
 
 DeviceOrientationMessageFilter::~DeviceOrientationMessageFilter() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  if (is_started_) {
-    // TODO(timvolodine): insert a proper call to DeviceSensorService here,
-    // similar to DeviceMotionService::GetInstance()->RemoveConsumer();
-  }
+  if (is_started_)
+    DeviceInertialSensorService::GetInstance()->RemoveConsumer(
+        CONSUMER_TYPE_ORIENTATION);
 }
 
 bool DeviceOrientationMessageFilter::OnMessageReceived(
@@ -43,8 +42,8 @@
   if (is_started_)
     return;
   is_started_ = true;
-  // TODO(timvolodine): insert a proper call to DeviceSensorService here,
-  // similar to DeviceMotionService::GetInstance()->AddConsumer();
+  DeviceInertialSensorService::GetInstance()->AddConsumer(
+      CONSUMER_TYPE_ORIENTATION);
   DidStartDeviceOrientationPolling();
 }
 
@@ -54,17 +53,16 @@
   if (!is_started_)
     return;
   is_started_ = false;
-  // TODO(timvolodine): insert a proper call to DeviceSensorService here,
-  // similar to DeviceMotionService::GetInstance()->RemoveConsumer();
+  DeviceInertialSensorService::GetInstance()->RemoveConsumer(
+      CONSUMER_TYPE_ORIENTATION);
 }
 
 void DeviceOrientationMessageFilter::DidStartDeviceOrientationPolling() {
-  NOTIMPLEMENTED();
-  // TODO(timvolodine): insert a proper call to the generalized Service here,
-  // similar to
-  // Send(new DeviceOrientationMsg_DidStartPolling(
-  //     DeviceMotionService::GetInstance()->GetSharedMemoryHandleForProcess(
-  //        PeerHandle())));
+  Send(new DeviceOrientationMsg_DidStartPolling(
+      DeviceInertialSensorService::GetInstance()->
+          GetSharedMemoryHandleForProcess(
+              CONSUMER_TYPE_ORIENTATION,
+              PeerHandle())));
 }
 
 }  // namespace content
diff --git a/content/browser/device_orientation/inertial_sensor_consts.h b/content/browser/device_orientation/inertial_sensor_consts.h
new file mode 100644
index 0000000..312b18b
--- /dev/null
+++ b/content/browser/device_orientation/inertial_sensor_consts.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 CONTENT_BROWSER_DEVICE_ORIENTATION_INERTIAL_SENSOR_CONSTS_H_
+#define CONTENT_BROWSER_DEVICE_ORIENTATION_INERTIAL_SENSOR_CONSTS_H_
+
+namespace content {
+
+// Constants related to the Device Motion/Device Orientation APIs.
+
+enum ConsumerType {
+  CONSUMER_TYPE_MOTION = 1 << 0,
+  CONSUMER_TYPE_ORIENTATION = 1 << 1,
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVICE_ORIENTATION_INERTIAL_SENSOR_CONSTS_H_
diff --git a/content/browser/devtools/browser_protocol.json b/content/browser/devtools/browser_protocol.json
new file mode 100644
index 0000000..ecc1bc3
--- /dev/null
+++ b/content/browser/devtools/browser_protocol.json
@@ -0,0 +1,48 @@
+{
+    "version": { "major": "1", "minor": "0" },
+    "domains": [{
+        "domain": "SystemInfo",
+        "description": "The SystemInfo domain defines methods and events for querying low-level system information.",
+        "hidden": true,
+        "types": [
+            {
+                "id": "GPUDevice",
+                "type": "object",
+                "properties": [
+                    { "name": "vendorId", "type": "number", "description": "PCI ID of the GPU vendor, if available; 0 otherwise." },
+                    { "name": "deviceId", "type": "number", "description": "PCI ID of the GPU device, if available; 0 otherwise." },
+                    { "name": "vendorString", "type": "string", "description": "String description of the GPU vendor, if the PCI ID is not available." },
+                    { "name": "deviceString", "type": "string", "description": "String description of the GPU device, if the PCI ID is not available." }
+                ],
+                "description": "Describes a single graphics processor (GPU)."
+            },
+            {
+                "id": "GPUInfo",
+                "type": "object",
+                "properties": [
+                    { "name": "devices", "type": "array", "items": { "$ref": "GPUDevice" }, "description": "The graphics devices on the system. Element 0 is the primary GPU." },
+                    { "name": "auxAttributes", "type": "object", "optional": "true", "description": "An optional dictionary of additional GPU related attributes." }
+                ],
+                "description": "Provides information about the GPU(s) on the system."
+            },
+            {
+                "id": "SystemInfo",
+                "type": "object",
+                "properties": [
+                    { "name": "gpu", "$ref": "GPUInfo", "description": "Information about the GPUs on the system." },
+                    { "name": "modelName", "type": "string", "description": "A platform-dependent description of the model of the machine. On Mac OS, this is, for example, 'MacBookPro 10.1'. Will be the empty string if not supported." }
+                ],
+                "description": "Provides information about the system."
+            }
+        ],
+        "commands": [
+            {
+                "name": "getInfo",
+                "description": "Returns information about the system.",
+                "returns": [
+                    { "name": "info", "$ref": "SystemInfo", "description": "Information about the system." }
+                ]
+            }
+        ]
+    }]
+}
diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc
index 47bdfd7..c670df3 100644
--- a/content/browser/devtools/devtools_http_handler_impl.cc
+++ b/content/browser/devtools/devtools_http_handler_impl.cc
@@ -22,6 +22,7 @@
 #include "content/browser/devtools/devtools_browser_target.h"
 #include "content/browser/devtools/devtools_protocol.h"
 #include "content/browser/devtools/devtools_protocol_constants.h"
+#include "content/browser/devtools/devtools_system_info_handler.h"
 #include "content/browser/devtools/devtools_tracing_handler.h"
 #include "content/browser/devtools/tethering_handler.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -383,6 +384,10 @@
         TetheringHandler::kDomain,
         new TetheringHandler(delegate_.get()),
         false /* handle on this thread */);
+    browser_target_->RegisterDomainHandler(
+        devtools::SystemInfo::kName,
+        new DevToolsSystemInfoHandler(),
+        true /* handle on UI thread */);
 
     server_->AcceptWebSocket(connection_id, request);
     return;
diff --git a/content/browser/devtools/devtools_protocol.cc b/content/browser/devtools/devtools_protocol.cc
index 8398084..948ed6b 100644
--- a/content/browser/devtools/devtools_protocol.cc
+++ b/content/browser/devtools/devtools_protocol.cc
@@ -190,6 +190,11 @@
   SendRawMessage(notification->Serialize());
 }
 
+void DevToolsProtocol::Handler::SendAsyncResponse(
+    scoped_refptr<DevToolsProtocol::Response> response) {
+  SendRawMessage(response->Serialize());
+}
+
 void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
   if (!notifier_.is_null())
     notifier_.Run(message);
diff --git a/content/browser/devtools/devtools_protocol.h b/content/browser/devtools/devtools_protocol.h
index 0012947..2f7ce0b 100644
--- a/content/browser/devtools/devtools_protocol.h
+++ b/content/browser/devtools/devtools_protocol.h
@@ -141,6 +141,8 @@
     void SendNotification(const std::string& method,
                           base::DictionaryValue* params);
 
+    void SendAsyncResponse(scoped_refptr<DevToolsProtocol::Response> response);
+
     // Sends message to client, the caller is presumed to properly
     // format the message.
     void SendRawMessage(const std::string& message);
diff --git a/content/browser/devtools/devtools_protocol_constants.cc b/content/browser/devtools/devtools_protocol_constants.cc
index c689ea1..b25c5c8 100644
--- a/content/browser/devtools/devtools_protocol_constants.cc
+++ b/content/browser/devtools/devtools_protocol_constants.cc
@@ -7,33 +7,69 @@
 namespace content {
 namespace devtools {
 
-namespace Inspector {
-namespace detached {
-  const char kName[] = "Inspector.detached";
-  const char kParamReason[] = "reason";
-}  // detached
-namespace targetCrashed {
-  const char kName[] = "Inspector.targetCrashed";
-}  // targetCrashed
-}  // Inspector
-
 namespace DOM {
+
 namespace setFileInputFiles {
   const char kName[] = "DOM.setFileInputFiles";
   const char kParamFiles[] = "files";
 }  // setFileInputFiles
+
 }  // DOM
 
+namespace Input {
+
+const char kParamType[] = "type";
+const char kParamModifiers[] = "modifiers";
+const char kParamTimestamp[] = "timestamp";
+const char kParamDeviceSpace[] = "deviceSpace";
+const char kParamX[] = "x";
+const char kParamY[] = "y";
+
+namespace dispatchMouseEvent {
+  const char kName[] = "Input.dispatchMouseEvent";
+  const char kParamButton[] = "button";
+  const char kParamClickCount[] = "clickCount";
+}  // dispatchMouseEvent
+
+namespace dispatchGestureEvent {
+  const char kName[] = "Input.dispatchGestureEvent";
+  const char kParamDeltaX[] = "deltaX";
+  const char kParamDeltaY[] = "deltaY";
+  const char kParamPinchScale[] = "pinchScale";
+}  // dispatchGestureEvent
+
+}  // Input
+
+namespace Inspector {
+
+namespace detached {
+  const char kName[] = "Inspector.detached";
+  const char kParamReason[] = "reason";
+}  // detached
+
+namespace targetCrashed {
+  const char kName[] = "Inspector.targetCrashed";
+}  // targetCrashed
+
+}  // Inspector
+
 namespace Page {
+
+namespace disable {
+  const char kName[] = "Page.disable";
+}  // disable
+
 namespace handleJavaScriptDialog {
   const char kName[] = "Page.handleJavaScriptDialog";
   const char kParamAccept[] = "accept";
   const char kParamPromptText[] = "promptText";
 }  // handleJavaScriptDialog
+
 namespace navigate {
   const char kName[] = "Page.navigate";
   const char kParamUrl[] = "url";
 }  // navigate
+
 namespace captureScreenshot {
   const char kName[] = "Page.captureScreenshot";
   const char kParamFormat[] = "format";
@@ -41,12 +77,31 @@
   const char kParamScale[] = "scale";
   const char kResponseData[] = "data";
 }  // captureScreenshot
+
+namespace startScreencast {
+  const char kName[] = "Page.startScreencast";
+  const char kParamFormat[] = "format";
+  const char kParamQuality[] = "quality";
+  const char kParamScale[] = "scale";
+}  // startScreencast
+
+namespace stopScreencast {
+  const char kName[] = "Page.stopScreencast";
+}  // stopScreencast
+
+namespace screencastFrame {
+  const char kName[] = "Page.screencastFrame";
+  const char kResponseData[] = "data";
+}  // screencastFrame
+
 }  // Page
 
 namespace Worker {
+
 namespace disconnectedFromWorker {
   const char kName[] = "Worker.disconnectedFromWorker";
 }  // disconnectedFromWorker
+
 }  // Worker
 
 namespace Tracing {
@@ -70,8 +125,17 @@
   const char kName[] = "Tracing.dataCollected";
   const char kValue[] = "value";
 }
+
 }  // Tracing
 
+namespace SystemInfo {
+  const char kName[] = "SystemInfo";
+
+namespace getInfo {
+  const char kName[] = "SystemInfo.getInfo";
+}  // getInfo
+}  // SystemInfo
+
 }  // devtools
 }  // content
 
diff --git a/content/browser/devtools/devtools_protocol_constants.h b/content/browser/devtools/devtools_protocol_constants.h
index a054933..7d06add 100644
--- a/content/browser/devtools/devtools_protocol_constants.h
+++ b/content/browser/devtools/devtools_protocol_constants.h
@@ -14,72 +14,138 @@
 namespace content {
 namespace devtools {
 
-namespace Inspector {
-namespace detached {
-  extern const char kName[];
-  extern const char kParamReason[];
-}  // detached
-namespace targetCrashed {
-  extern const char kName[];
-}  // targetCrashed
-}  // Inspector
-
 namespace DOM {
-namespace setFileInputFiles {
-  extern const char kName[];
-  extern const char kParamFiles[];
-}  // setFileInputFiles
+
+  namespace setFileInputFiles {
+    extern const char kName[];
+    extern const char kParamFiles[];
+  }  // setFileInputFiles
+
 }  // DOM
 
+namespace Input {
+
+  extern const char kParamType[];
+  extern const char kParamModifiers[];
+  extern const char kParamTimestamp[];
+  extern const char kParamDeviceSpace[];
+  extern const char kParamX[];
+  extern const char kParamY[];
+
+  namespace dispatchMouseEvent {
+    extern const char kName[];
+    extern const char kParamX[];
+    extern const char kParamY[];
+    extern const char kParamButton[];
+    extern const char kParamClickCount[];
+  }  // dispatchMouseEvent
+
+  namespace dispatchGestureEvent {
+    extern const char kName[];
+    extern const char kParamDeltaX[];
+    extern const char kParamDeltaY[];
+    extern const char kParamPinchScale[];
+  }  // dispatchGestureEvent
+
+}  // Input
+
+namespace Inspector {
+
+  namespace detached {
+    extern const char kName[];
+    extern const char kParamReason[];
+  }  // detached
+
+  namespace targetCrashed {
+    extern const char kName[];
+  }  // targetCrashed
+
+}  // Inspector
+
 namespace Page {
-namespace handleJavaScriptDialog {
-  extern const char kName[];
-  extern const char kParamAccept[];
-  extern const char kParamPromptText[];
-}  // handleJavaScriptDialog
-namespace navigate {
-  extern const char kName[];
-  extern const char kParamUrl[];
-}  // navigate
-namespace captureScreenshot {
-  extern const char kName[];
-  extern const char kParamFormat[];
-  extern const char kParamQuality[];
-  extern const char kParamScale[];
-  extern const char kResponseData[];
-}  // captureScreenshot
+
+  namespace disable {
+    extern const char kName[];
+  }  // disable
+
+  namespace handleJavaScriptDialog {
+    extern const char kName[];
+    extern const char kParamAccept[];
+    extern const char kParamPromptText[];
+  }  // handleJavaScriptDialog
+
+  namespace navigate {
+    extern const char kName[];
+    extern const char kParamUrl[];
+  }  // navigate
+
+  namespace captureScreenshot {
+    extern const char kName[];
+    extern const char kParamFormat[];
+    extern const char kParamQuality[];
+    extern const char kParamScale[];
+    extern const char kResponseData[];
+  }  // captureScreenshot
+
+  namespace startScreencast {
+    extern const char kName[];
+    extern const char kParamFormat[];
+    extern const char kParamQuality[];
+    extern const char kParamScale[];
+  }  // startScreencast
+
+  namespace stopScreencast {
+    extern const char kName[];
+  }  // stopScreencast
+
+  namespace screencastFrame {
+    extern const char kName[];
+    extern const char kResponseData[];
+  }  // screencastFrame
+
 }  // Page
 
 namespace Tracing {
   extern const char kName[];
 
-namespace start {
-  extern const char kName[];
-  extern const char kCategories[];
-  extern const char kTraceOptions[];
-}  // start
+  namespace start {
+    extern const char kName[];
+    extern const char kCategories[];
+    extern const char kTraceOptions[];
+  }  // start
 
-namespace end {
-  extern const char kName[];
-}
+  namespace end {
+    extern const char kName[];
+  }
 
-namespace tracingComplete {
-  extern const char kName[];
-}
+  namespace tracingComplete {
+    extern const char kName[];
+  }
 
-namespace dataCollected {
-  extern const char kName[];
-  extern const char kValue[];
-}
+  namespace dataCollected {
+    extern const char kName[];
+    extern const char kValue[];
+  }
+
 }  // Tracing
 
-
 namespace Worker {
-namespace disconnectedFromWorker {
-  extern const char kName[];
-}  // disconnectedFromWorker
+
+  namespace disconnectedFromWorker {
+    extern const char kName[];
+  }  // disconnectedFromWorker
+
 }  // Worker
 
+
+namespace SystemInfo {
+  extern const char kName[];
+
+namespace getInfo {
+  extern const char kName[];
+}  // getInfo
+}  // SystemInfo
+
 }  // devtools
 }  // content
 
diff --git a/content/browser/devtools/devtools_system_info_handler.cc b/content/browser/devtools/devtools_system_info_handler.cc
new file mode 100644
index 0000000..1fee642
--- /dev/null
+++ b/content/browser/devtools/devtools_system_info_handler.cc
@@ -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.
+
+#include "content/browser/devtools/devtools_system_info_handler.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/values.h"
+#include "content/browser/devtools/devtools_protocol_constants.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "gpu/config/gpu_info.h"
+
+namespace content {
+
+namespace {
+
+const char kAuxAttributes[] = "auxAttributes";
+const char kDeviceId[] = "deviceId";
+const char kDeviceString[] = "deviceString";
+const char kDevices[] = "devices";
+const char kGPU[] = "gpu";
+const char kModelName[] = "modelName";
+const char kVendorId[] = "vendorId";
+const char kVendorString[] = "vendorString";
+
+class AuxGPUInfoEnumerator : public gpu::GPUInfo::Enumerator {
+ public:
+  AuxGPUInfoEnumerator(base::DictionaryValue* dictionary)
+      : dictionary_(dictionary),
+        in_aux_attributes_(false) { }
+
+  virtual void AddInt64(const char* name, int64 value) OVERRIDE {
+    if (in_aux_attributes_)
+      dictionary_->SetDouble(name, value);
+  }
+
+  virtual void AddInt(const char* name, int value) OVERRIDE {
+    if (in_aux_attributes_)
+      dictionary_->SetInteger(name, value);
+  }
+
+  virtual void AddString(const char* name, const std::string& value) OVERRIDE {
+    if (in_aux_attributes_)
+      dictionary_->SetString(name, value);
+  }
+
+  virtual void AddBool(const char* name, bool value) OVERRIDE {
+    if (in_aux_attributes_)
+      dictionary_->SetBoolean(name, value);
+  }
+
+  virtual void AddTimeDeltaInSecondsF(const char* name,
+                                      const base::TimeDelta& value) OVERRIDE {
+    if (in_aux_attributes_)
+      dictionary_->SetDouble(name, value.InSecondsF());
+  }
+
+  virtual void BeginGPUDevice() OVERRIDE {
+  }
+
+  virtual void EndGPUDevice() OVERRIDE {
+  }
+
+  virtual void BeginAuxAttributes() OVERRIDE {
+    in_aux_attributes_ = true;
+  }
+
+  virtual void EndAuxAttributes() OVERRIDE {
+    in_aux_attributes_ = false;
+  }
+
+ private:
+  base::DictionaryValue* dictionary_;
+  bool in_aux_attributes_;
+};
+
+base::DictionaryValue* GPUDeviceToDictionary(
+    const gpu::GPUInfo::GPUDevice& device) {
+  base::DictionaryValue* result = new base::DictionaryValue;
+  result->SetInteger(kVendorId, device.vendor_id);
+  result->SetInteger(kDeviceId, device.device_id);
+  result->SetString(kVendorString, device.vendor_string);
+  result->SetString(kDeviceString, device.device_string);
+  return result;
+}
+
+}  // namespace
+
+DevToolsSystemInfoHandler::DevToolsSystemInfoHandler() {
+  RegisterCommandHandler(devtools::SystemInfo::getInfo::kName,
+                         base::Bind(&DevToolsSystemInfoHandler::OnGetInfo,
+                                    base::Unretained(this)));
+}
+
+DevToolsSystemInfoHandler::~DevToolsSystemInfoHandler() {
+}
+
+scoped_refptr<DevToolsProtocol::Response>
+DevToolsSystemInfoHandler::OnGetInfo(
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  gpu::GPUInfo gpu_info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
+  base::DictionaryValue* gpu_dict = new base::DictionaryValue;
+
+  base::ListValue* devices = new base::ListValue;
+  devices->Append(GPUDeviceToDictionary(gpu_info.gpu));
+  for (size_t ii = 0; ii < gpu_info.secondary_gpus.size(); ++ii) {
+    devices->Append(GPUDeviceToDictionary(gpu_info.secondary_gpus[ii]));
+  }
+  gpu_dict->Set(kDevices, devices);
+
+  base::DictionaryValue* aux_attributes = new base::DictionaryValue;
+  AuxGPUInfoEnumerator enumerator(aux_attributes);
+  gpu_info.EnumerateFields(&enumerator);
+  gpu_dict->Set(kAuxAttributes, aux_attributes);
+
+  base::DictionaryValue* system_dict = new base::DictionaryValue;
+  system_dict->SetString(kModelName, gpu_info.machine_model);
+  system_dict->Set(kGPU, gpu_dict);
+  return command->SuccessResponse(system_dict);
+}
+
+}  // namespace content
diff --git a/content/browser/devtools/devtools_system_info_handler.h b/content/browser/devtools/devtools_system_info_handler.h
new file mode 100644
index 0000000..afaf042
--- /dev/null
+++ b/content/browser/devtools/devtools_system_info_handler.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 CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SYSTEM_INFO_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SYSTEM_INFO_HANDLER_H_
+
+#include "content/browser/devtools/devtools_protocol.h"
+
+namespace content {
+
+// This class provides information to DevTools about the system it's running on.
+class DevToolsSystemInfoHandler
+    : public DevToolsProtocol::Handler {
+ public:
+  DevToolsSystemInfoHandler();
+  virtual ~DevToolsSystemInfoHandler();
+
+ private:
+  scoped_refptr<DevToolsProtocol::Response> OnGetInfo(
+      scoped_refptr<DevToolsProtocol::Command> command);
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsSystemInfoHandler);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_SYSTEM_INFO_HANDLER_H_
diff --git a/content/browser/devtools/render_view_devtools_agent_host.cc b/content/browser/devtools/render_view_devtools_agent_host.cc
index 7455c16..bcde4e5 100644
--- a/content/browser/devtools/render_view_devtools_agent_host.cc
+++ b/content/browser/devtools/render_view_devtools_agent_host.cc
@@ -17,6 +17,7 @@
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/devtools_messages.h"
+#include "content/common/view_messages.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
@@ -194,6 +195,11 @@
 }
 
 void RenderViewDevToolsAgentHost::OnClientDetached() {
+  overrides_handler_->OnClientDetached();
+  ClientDetachedFromRenderer();
+}
+
+void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() {
   if (!render_view_host_)
     return;
 
@@ -278,7 +284,7 @@
 }
 
 void RenderViewDevToolsAgentHost::DisconnectRenderViewHost() {
-  OnClientDetached();
+  ClientDetachedFromRenderer();
   rvh_observer_.reset();
   render_view_host_ = NULL;
 }
@@ -311,11 +317,17 @@
     IPC_MESSAGE_HANDLER(DevToolsHostMsg_ClearBrowserCache, OnClearBrowserCache)
     IPC_MESSAGE_HANDLER(DevToolsHostMsg_ClearBrowserCookies,
                         OnClearBrowserCookies)
+    IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame,
+                                handled = false; OnSwapCompositorFrame())
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
 }
 
+void RenderViewDevToolsAgentHost::OnSwapCompositorFrame() {
+  overrides_handler_->OnSwapCompositorFrame();
+}
+
 void RenderViewDevToolsAgentHost::OnSaveAgentRuntimeState(
     const std::string& state) {
   if (!render_view_host_)
diff --git a/content/browser/devtools/render_view_devtools_agent_host.h b/content/browser/devtools/render_view_devtools_agent_host.h
index 00f73a6..4732ca4 100644
--- a/content/browser/devtools/render_view_devtools_agent_host.h
+++ b/content/browser/devtools/render_view_devtools_agent_host.h
@@ -59,12 +59,15 @@
   void RenderViewHostDestroyed(RenderViewHost* rvh);
   void RenderViewCrashed();
   bool OnRvhMessageReceived(const IPC::Message& message);
+  void OnSwapCompositorFrame();
 
   void OnDispatchOnInspectorFrontend(const std::string& message);
   void OnSaveAgentRuntimeState(const std::string& state);
   void OnClearBrowserCache();
   void OnClearBrowserCookies();
 
+  void ClientDetachedFromRenderer();
+
   RenderViewHost* render_view_host_;
   scoped_ptr<DevToolsAgentHostRvhObserver> rvh_observer_;
   scoped_ptr<RendererOverridesHandler> overrides_handler_;
diff --git a/content/browser/devtools/renderer_overrides_handler.cc b/content/browser/devtools/renderer_overrides_handler.cc
index 5726667..3e9ffc3 100644
--- a/content/browser/devtools/renderer_overrides_handler.cc
+++ b/content/browser/devtools/renderer_overrides_handler.cc
@@ -15,7 +15,9 @@
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/devtools/devtools_protocol_constants.h"
 #include "content/browser/devtools/devtools_tracing_handler.h"
+#include "content/browser/renderer_host/dip_util.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/port/browser/render_widget_host_view_port.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -28,13 +30,18 @@
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/page_transition_types.h"
 #include "content/public/common/referrer.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/size_conversions.h"
 #include "ui/snapshot/snapshot.h"
 #include "url/gurl.h"
 
-using base::TimeTicks;
+using WebKit::WebGestureEvent;
+using WebKit::WebInputEvent;
+using WebKit::WebMouseEvent;
+
+namespace content {
 
 namespace {
 
@@ -42,9 +49,49 @@
 static const char kJpeg[] = "jpeg";
 static int kDefaultScreenshotQuality = 80;
 
-}  // namespace
+void ParseCaptureParameters(DevToolsProtocol::Command* command,
+                            std::string* format,
+                            int* quality,
+                            double* scale) {
+  *quality = kDefaultScreenshotQuality;
+  *scale = 1;
+  base::DictionaryValue* params = command->params();
+  if (params) {
+    params->GetString(devtools::Page::captureScreenshot::kParamFormat,
+                      format);
+    params->GetInteger(devtools::Page::captureScreenshot::kParamQuality,
+                       quality);
+    params->GetDouble(devtools::Page::captureScreenshot::kParamScale,
+                      scale);
+  }
+  if (format->empty())
+    *format = kPng;
+  if (*quality < 0 || *quality > 100)
+    *quality = kDefaultScreenshotQuality;
+  if (*scale <= 0 || *scale > 1)
+    *scale = 1;
+}
 
-namespace content {
+void ParseGenericInputParams(base::DictionaryValue* params,
+                             WebInputEvent* event) {
+  int modifiers = 0;
+  if (params->GetInteger(devtools::Input::kParamModifiers,
+                         &modifiers)) {
+    if (modifiers & 1)
+      event->modifiers |= WebInputEvent::AltKey;
+    if (modifiers & 2)
+      event->modifiers |= WebInputEvent::ControlKey;
+    if (modifiers & 4)
+      event->modifiers |= WebInputEvent::MetaKey;
+    if (modifiers & 8)
+      event->modifiers |= WebInputEvent::ShiftKey;
+  }
+
+  params->GetDouble(devtools::Input::kParamTimestamp,
+                    &event->timeStampSeconds);
+}
+
+}  // namespace
 
 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
     : agent_(agent),
@@ -55,6 +102,10 @@
           &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles,
           base::Unretained(this)));
   RegisterCommandHandler(
+      devtools::Page::disable::kName,
+      base::Bind(
+          &RendererOverridesHandler::PageDisable, base::Unretained(this)));
+  RegisterCommandHandler(
       devtools::Page::handleJavaScriptDialog::kName,
       base::Bind(
           &RendererOverridesHandler::PageHandleJavaScriptDialog,
@@ -69,10 +120,62 @@
       base::Bind(
           &RendererOverridesHandler::PageCaptureScreenshot,
           base::Unretained(this)));
+  RegisterCommandHandler(
+      devtools::Page::startScreencast::kName,
+      base::Bind(
+          &RendererOverridesHandler::PageStartScreencast,
+          base::Unretained(this)));
+  RegisterCommandHandler(
+      devtools::Page::stopScreencast::kName,
+      base::Bind(
+          &RendererOverridesHandler::PageStopScreencast,
+          base::Unretained(this)));
+  RegisterCommandHandler(
+      devtools::Input::dispatchMouseEvent::kName,
+      base::Bind(
+          &RendererOverridesHandler::InputDispatchMouseEvent,
+          base::Unretained(this)));
+  RegisterCommandHandler(
+      devtools::Input::dispatchGestureEvent::kName,
+      base::Bind(
+          &RendererOverridesHandler::InputDispatchGestureEvent,
+          base::Unretained(this)));
 }
 
 RendererOverridesHandler::~RendererOverridesHandler() {}
 
+void RendererOverridesHandler::OnClientDetached() {
+  screencast_command_ = NULL;
+}
+
+void RendererOverridesHandler::OnSwapCompositorFrame() {
+  if (!screencast_command_)
+    return;
+
+  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());
+
+  gfx::Rect view_bounds = host->GetView()->GetViewBounds();
+  gfx::Size snapshot_size = gfx::ToFlooredSize(
+      gfx::ScaleSize(view_bounds.size(), scale));
+
+  view_port->CopyFromCompositingSurface(
+      view_bounds, snapshot_size,
+      base::Bind(&RendererOverridesHandler::ScreenshotCaptured,
+                 weak_factory_.GetWeakPtr(),
+                 scoped_refptr<DevToolsProtocol::Command>(), format, quality,
+                 scale));
+}
+
+
+// DOM agent handlers  --------------------------------------------------------
+
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
     scoped_refptr<DevToolsProtocol::Command> command) {
@@ -96,6 +199,16 @@
   return NULL;
 }
 
+
+// Page agent handlers  -------------------------------------------------------
+
+scoped_refptr<DevToolsProtocol::Response>
+RendererOverridesHandler::PageDisable(
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  screencast_command_ = NULL;
+  return NULL;
+}
+
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageHandleJavaScriptDialog(
     scoped_refptr<DevToolsProtocol::Command> command) {
@@ -155,25 +268,10 @@
 scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageCaptureScreenshot(
     scoped_refptr<DevToolsProtocol::Command> command) {
-  // Parse input parameters.
   std::string format;
   int quality = kDefaultScreenshotQuality;
   double scale = 1;
-  base::DictionaryValue* params = command->params();
-  if (params) {
-    params->GetString(devtools::Page::captureScreenshot::kParamFormat,
-                      &format);
-    params->GetInteger(devtools::Page::captureScreenshot::kParamQuality,
-                       &quality);
-    params->GetDouble(devtools::Page::captureScreenshot::kParamScale,
-                      &scale);
-  }
-  if (format.empty())
-    format = kPng;
-  if (quality < 0 || quality > 100)
-    quality = kDefaultScreenshotQuality;
-  if (scale <= 0 || scale > 1)
-    scale = 1;
+  ParseCaptureParameters(command.get(), &format, &quality, &scale);
 
   RenderViewHost* host = agent_->GetRenderViewHost();
   gfx::Rect view_bounds = host->GetView()->GetViewBounds();
@@ -210,6 +308,21 @@
   return command->AsyncResponsePromise();
 }
 
+scoped_refptr<DevToolsProtocol::Response>
+RendererOverridesHandler::PageStartScreencast(
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  screencast_command_ = command;
+  OnSwapCompositorFrame();
+  return command->SuccessResponse(NULL);
+}
+
+scoped_refptr<DevToolsProtocol::Response>
+RendererOverridesHandler::PageStopScreencast(
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  screencast_command_ = NULL;
+  return command->SuccessResponse(NULL);
+}
+
 void RendererOverridesHandler::ScreenshotCaptured(
     scoped_refptr<DevToolsProtocol::Command> command,
     const std::string& format,
@@ -218,9 +331,10 @@
     bool success,
     const SkBitmap& bitmap) {
   if (!success) {
-    SendRawMessage(
-        command->InternalErrorResponse("Unable to capture screenshot")->
-            Serialize());
+    if (command) {
+      SendAsyncResponse(
+          command->InternalErrorResponse("Unable to capture screenshot"));
+    }
     return;
   }
 
@@ -247,27 +361,193 @@
   }
 
   if (!encoded) {
-    SendRawMessage(
-        command->InternalErrorResponse("Unable to encode screenshot")->
-            Serialize());
+    if (command) {
+      SendAsyncResponse(
+          command->InternalErrorResponse("Unable to encode screenshot"));
+    }
     return;
   }
 
   std::string base_64_data;
   if (!base::Base64Encode(base::StringPiece(
-                             reinterpret_cast<char*>(&data[0]),
-                             data.size()),
+                              reinterpret_cast<char*>(&data[0]),
+                              data.size()),
                           &base_64_data)) {
-    SendRawMessage(
-        command->InternalErrorResponse("Unable to base64 encode screenshot")->
-            Serialize());
+    if (command) {
+      SendAsyncResponse(
+          command->InternalErrorResponse("Unable to base64 encode"));
+    }
     return;
   }
 
   base::DictionaryValue* response = new base::DictionaryValue();
-  response->SetString(
-      devtools::Page::captureScreenshot::kResponseData, base_64_data);
-  SendRawMessage(command->SuccessResponse(response)->Serialize());
+  if (command) {
+    response->SetString(
+        devtools::Page::captureScreenshot::kResponseData, base_64_data);
+    SendAsyncResponse(command->SuccessResponse(response));
+  } else {
+    response->SetString(
+        devtools::Page::screencastFrame::kResponseData, base_64_data);
+    SendNotification(devtools::Page::screencastFrame::kName, response);
+  }
+}
+
+
+// Input agent handlers  ------------------------------------------------------
+
+scoped_refptr<DevToolsProtocol::Response>
+RendererOverridesHandler::InputDispatchMouseEvent(
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  base::DictionaryValue* params = command->params();
+  if (!params)
+    return NULL;
+
+  bool device_space = false;
+  if (!params->GetBoolean(devtools::Input::kParamDeviceSpace,
+                          &device_space) ||
+      !device_space) {
+    return NULL;
+  }
+
+  RenderViewHost* host = agent_->GetRenderViewHost();
+  WebKit::WebMouseEvent mouse_event;
+  ParseGenericInputParams(params, &mouse_event);
+
+  std::string type;
+  if (params->GetString(devtools::Input::kParamType,
+                        &type)) {
+    if (type == "mousePressed")
+      mouse_event.type = WebInputEvent::MouseDown;
+    else if (type == "mouseReleased")
+      mouse_event.type = WebInputEvent::MouseUp;
+    else if (type == "mouseMoved")
+      mouse_event.type = WebInputEvent::MouseMove;
+    else
+      return NULL;
+  } else {
+    return NULL;
+  }
+
+  int x;
+  int y;
+  if (!params->GetInteger(devtools::Input::kParamX, &x) ||
+      !params->GetInteger(devtools::Input::kParamY, &y)) {
+    return NULL;
+  }
+
+  float device_scale_factor = ui::GetScaleFactorScale(
+      GetScaleFactorForView(host->GetView()));
+  mouse_event.x = floor(x / device_scale_factor);
+  mouse_event.y = floor(y / device_scale_factor);
+  mouse_event.windowX = mouse_event.x;
+  mouse_event.windowY = mouse_event.y;
+  mouse_event.globalX = mouse_event.x;
+  mouse_event.globalY = mouse_event.y;
+
+  params->GetInteger(devtools::Input::dispatchMouseEvent::kParamClickCount,
+                     &mouse_event.clickCount);
+
+  std::string button;
+  if (!params->GetString(devtools::Input::dispatchMouseEvent::kParamButton,
+                         &button)) {
+    return NULL;
+  }
+
+  if (button == "none") {
+    mouse_event.button = WebMouseEvent::ButtonNone;
+  } else if (button == "left") {
+    mouse_event.button = WebMouseEvent::ButtonLeft;
+    mouse_event.modifiers |= WebInputEvent::LeftButtonDown;
+  } else if (button == "middle") {
+    mouse_event.button = WebMouseEvent::ButtonMiddle;
+    mouse_event.modifiers |= WebInputEvent::MiddleButtonDown;
+  } else if (button == "right") {
+    mouse_event.button = WebMouseEvent::ButtonRight;
+    mouse_event.modifiers |= WebInputEvent::RightButtonDown;
+  } else {
+    return NULL;
+  }
+
+  host->ForwardMouseEvent(mouse_event);
+  return command->SuccessResponse(NULL);
+}
+
+scoped_refptr<DevToolsProtocol::Response>
+RendererOverridesHandler::InputDispatchGestureEvent(
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  base::DictionaryValue* params = command->params();
+  if (!params)
+    return NULL;
+
+  RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
+      agent_->GetRenderViewHost());
+  WebKit::WebGestureEvent event;
+  ParseGenericInputParams(params, &event);
+
+  std::string type;
+  if (params->GetString(devtools::Input::kParamType,
+                        &type)) {
+    if (type == "scrollBegin")
+      event.type = WebInputEvent::GestureScrollBegin;
+    else if (type == "scrollUpdate")
+      event.type = WebInputEvent::GestureScrollUpdate;
+    else if (type == "scrollEnd")
+      event.type = WebInputEvent::GestureScrollEnd;
+    else if (type == "tapDown")
+      event.type = WebInputEvent::GestureTapDown;
+    else if (type == "tap")
+      event.type = WebInputEvent::GestureTap;
+    else if (type == "pinchBegin")
+      event.type = WebInputEvent::GesturePinchBegin;
+    else if (type == "pinchUpdate")
+      event.type = WebInputEvent::GesturePinchUpdate;
+    else if (type == "pinchEnd")
+      event.type = WebInputEvent::GesturePinchEnd;
+    else
+      return NULL;
+  } else {
+    return NULL;
+  }
+
+  float device_scale_factor = ui::GetScaleFactorScale(
+      GetScaleFactorForView(host->GetView()));
+
+  int x;
+  int y;
+  if (!params->GetInteger(devtools::Input::kParamX, &x) ||
+      !params->GetInteger(devtools::Input::kParamY, &y)) {
+    return NULL;
+  }
+  event.x = floor(x / device_scale_factor);
+  event.y = floor(y / device_scale_factor);
+  event.globalX = event.x;
+  event.globalY = event.y;
+
+  if (type == "scrollUpdate") {
+    int dx;
+    int dy;
+    if (!params->GetInteger(
+            devtools::Input::dispatchGestureEvent::kParamDeltaX, &dx) ||
+        !params->GetInteger(
+            devtools::Input::dispatchGestureEvent::kParamDeltaY, &dy)) {
+      return NULL;
+    }
+    event.data.scrollUpdate.deltaX = floor(dx / device_scale_factor);
+    event.data.scrollUpdate.deltaY = floor(dy / device_scale_factor);
+  }
+
+  if (type == "pinchUpdate") {
+    double scale;
+    if (!params->GetDouble(
+        devtools::Input::dispatchGestureEvent::kParamPinchScale,
+        &scale)) {
+      return NULL;
+    }
+    event.data.pinchUpdate.scale = static_cast<float>(scale);
+  }
+
+  host->ForwardGestureEvent(event);
+  return command->SuccessResponse(NULL);
 }
 
 }  // namespace content
diff --git a/content/browser/devtools/renderer_overrides_handler.h b/content/browser/devtools/renderer_overrides_handler.h
index 1d4213d..d369ccd 100644
--- a/content/browser/devtools/renderer_overrides_handler.h
+++ b/content/browser/devtools/renderer_overrides_handler.h
@@ -26,16 +26,29 @@
   explicit RendererOverridesHandler(DevToolsAgentHost* agent);
   virtual ~RendererOverridesHandler();
 
+  void OnClientDetached();
+  void OnSwapCompositorFrame();
+
  private:
+
+  // DOM domain.
   scoped_refptr<DevToolsProtocol::Response>
       GrantPermissionsForSetFileInputFiles(
           scoped_refptr<DevToolsProtocol::Command> command);
+
+  // Page domain.
+  scoped_refptr<DevToolsProtocol::Response> PageDisable(
+      scoped_refptr<DevToolsProtocol::Command> command);
   scoped_refptr<DevToolsProtocol::Response> PageHandleJavaScriptDialog(
       scoped_refptr<DevToolsProtocol::Command> command);
   scoped_refptr<DevToolsProtocol::Response> PageNavigate(
       scoped_refptr<DevToolsProtocol::Command> command);
   scoped_refptr<DevToolsProtocol::Response> PageCaptureScreenshot(
       scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> PageStartScreencast(
+      scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> PageStopScreencast(
+      scoped_refptr<DevToolsProtocol::Command> command);
 
   void ScreenshotCaptured(
       scoped_refptr<DevToolsProtocol::Command> command,
@@ -45,8 +58,15 @@
       bool success,
       const SkBitmap& bitmap);
 
+  // Input domain.
+  scoped_refptr<DevToolsProtocol::Response> InputDispatchMouseEvent(
+      scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> InputDispatchGestureEvent(
+      scoped_refptr<DevToolsProtocol::Command> command);
+
   DevToolsAgentHost* agent_;
   base::WeakPtrFactory<RendererOverridesHandler> weak_factory_;
+  scoped_refptr<DevToolsProtocol::Command> screencast_command_;
   DISALLOW_COPY_AND_ASSIGN(RendererOverridesHandler);
 };
 
diff --git a/content/browser/dom_storage/dom_storage_browsertest.cc b/content/browser/dom_storage/dom_storage_browsertest.cc
index 54da50a..b2aa9f1 100644
--- a/content/browser/dom_storage/dom_storage_browsertest.cc
+++ b/content/browser/dom_storage/dom_storage_browsertest.cc
@@ -7,7 +7,7 @@
 #include "content/common/dom_storage/dom_storage_types.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/net_util.h"
@@ -25,7 +25,8 @@
     // a #pass or #fail ref.
     Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
     NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
-    std::string result = the_browser->web_contents()->GetURL().ref();
+    std::string result =
+        the_browser->web_contents()->GetLastCommittedURL().ref();
     if (result != "pass") {
       std::string js_result;
       ASSERT_TRUE(ExecuteScriptAndExtractString(
diff --git a/content/browser/dom_storage/dom_storage_host.cc b/content/browser/dom_storage/dom_storage_host.cc
index 296d52e..14d288d 100644
--- a/content/browser/dom_storage/dom_storage_host.cc
+++ b/content/browser/dom_storage/dom_storage_host.cc
@@ -30,12 +30,8 @@
     return false;  // Indicates the renderer gave us very bad data.
   NamespaceAndArea references;
   references.namespace_ = context_->GetStorageNamespace(namespace_id);
-  if (!references.namespace_.get()) {
-    // TODO(michaeln): Fix crbug/134003 and return false here.
-    // Until then return true to avoid crashing the renderer for
-    // sending a bad message.
-    return true;
-  }
+  if (!references.namespace_.get())
+    return false;
   references.area_ = references.namespace_->OpenStorageArea(origin);
   DCHECK(references.area_.get());
   connections_[connection_id] = references;
@@ -54,12 +50,8 @@
     int connection_id, DOMStorageValuesMap* map) {
   map->clear();
   DOMStorageArea* area = GetOpenArea(connection_id);
-  if (!area) {
-    // TODO(michaeln): Fix crbug/134003 and return false here.
-    // Until then return true to avoid crashing the renderer
-    // for sending a bad message.
-    return true;
-  }
+  if (!area)
+    return false;
   if (!area->IsLoadedInMemory()) {
     DOMStorageNamespace* ns = GetNamespace(connection_id);
     DCHECK(ns);
@@ -101,12 +93,8 @@
     const base::string16& value, const GURL& page_url,
     base::NullableString16* old_value) {
   DOMStorageArea* area = GetOpenArea(connection_id);
-  if (!area) {
-    // TODO(michaeln): Fix crbug/134003 and return false here.
-    // Until then return true to allow the renderer to operate
-    // to a limited degree out of its cache.
-    return true;
-  }
+  if (!area)
+    return false;
   if (!area->SetItem(key, value, old_value))
     return false;
   if (old_value->is_null() || old_value->string() != value)
diff --git a/content/browser/dom_storage/session_storage_database_unittest.cc b/content/browser/dom_storage/session_storage_database_unittest.cc
index 9722d72..2f86c3b 100644
--- a/content/browser/dom_storage/session_storage_database_unittest.cc
+++ b/content/browser/dom_storage/session_storage_database_unittest.cc
@@ -219,7 +219,6 @@
 
   for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) {
     std::string namespace_id;
-    std::string origin;
     if (IsNamespaceKey(it->first, &namespace_id)) {
       found_namespace_ids.insert(namespace_id);
       ++valid_keys;
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 79ad19c..b638cfa 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -22,12 +22,14 @@
 #include "content/public/browser/power_save_blocker.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/webplugininfo.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/download_test_observer.h"
 #include "content/public/test/test_file_error_injector.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_download_manager_delegate.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_download_manager_delegate.h"
+#include "content/shell/browser/shell_network_delegate.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "content/test/net/url_request_mock_http_job.h"
@@ -1598,4 +1600,42 @@
   EXPECT_TRUE(EnsureNoPendingDownloads());
 }
 
+// Check that the cookie policy is correctly updated when downloading a file
+// that redirects cross origin.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, CookiePolicy) {
+  ASSERT_TRUE(test_server()->Start());
+  net::HostPortPair host_port = test_server()->host_port_pair();
+  DCHECK_EQ(host_port.host(), std::string("127.0.0.1"));
+
+  // Block third-party cookies.
+  ShellNetworkDelegate::SetAcceptAllCookies(false);
+
+  // |url| redirects to a different origin |download| which tries to set a
+  // cookie.
+  std::string download(base::StringPrintf(
+      "http://localhost:%d/set-cookie?A=B", host_port.port()));
+  GURL url(test_server()->GetURL("server-redirect?" + download));
+
+  // Download the file.
+  SetupEnsureNoPendingDownloads();
+  scoped_ptr<DownloadUrlParameters> dl_params(
+      DownloadUrlParameters::FromWebContents(shell()->web_contents(), url));
+  scoped_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
+  DownloadManagerForShell(shell())->DownloadUrl(dl_params.Pass());
+  observer->WaitForFinished();
+
+  // Get the important info from other threads and check it.
+  EXPECT_TRUE(EnsureNoPendingDownloads());
+
+  std::vector<DownloadItem*> downloads;
+  DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+  ASSERT_EQ(1u, downloads.size());
+  ASSERT_EQ(DownloadItem::COMPLETE, downloads[0]->GetState());
+
+  // Check that the cookies were correctly set.
+  EXPECT_EQ("A=B",
+            content::GetCookies(shell()->web_contents()->GetBrowserContext(),
+                                GURL(download)));
+}
+
 }  // namespace content
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
index 867b76f..49e418c 100644
--- a/content/browser/download/download_file_unittest.cc
+++ b/content/browser/download/download_file_unittest.cc
@@ -76,6 +76,7 @@
   DownloadFileTest() :
       observer_(new StrictMock<MockDownloadDestinationObserver>),
       observer_factory_(observer_.get()),
+      input_stream_(NULL),
       bytes_(-1),
       bytes_per_sec_(-1),
       hash_state_("xyzzy"),
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index eba2833..0865c04 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -435,7 +435,8 @@
   static const size_t kTestDataLen;
 
   DownloadManagerTest()
-      : ui_thread_(BrowserThread::UI, &message_loop_),
+      : callback_called_(false),
+        ui_thread_(BrowserThread::UI, &message_loop_),
         file_thread_(BrowserThread::FILE, &message_loop_),
         next_download_id_(0) {
   }
diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc
index 3b4844e..ed4edff 100644
--- a/content/browser/download/download_resource_handler.cc
+++ b/content/browser/download/download_resource_handler.cc
@@ -103,6 +103,9 @@
     const GURL& url,
     ResourceResponse* response,
     bool* defer) {
+  // We treat a download as a main frame load, and thus update the policy URL
+  // on redirects.
+  request_->set_first_party_for_cookies(url);
   return true;
 }
 
diff --git a/content/browser/download/download_resource_handler.h b/content/browser/download/download_resource_handler.h
index d38068d..60fbc94 100644
--- a/content/browser/download/download_resource_handler.h
+++ b/content/browser/download/download_resource_handler.h
@@ -49,7 +49,6 @@
                                 uint64 position,
                                 uint64 size) OVERRIDE;
 
-  // Not needed, as this event handler ought to be the final resource.
   virtual bool OnRequestRedirected(int request_id,
                                    const GURL& url,
                                    ResourceResponse* response,
diff --git a/content/browser/download/drag_download_file_browsertest.cc b/content/browser/download/drag_download_file_browsertest.cc
index fc35d6c..a4f5005 100644
--- a/content/browser/download/drag_download_file_browsertest.cc
+++ b/content/browser/download/drag_download_file_browsertest.cc
@@ -16,9 +16,9 @@
 #include "content/public/common/content_client.h"
 #include "content/public/test/download_test_observer.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_download_manager_delegate.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_download_manager_delegate.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "content/test/net/url_request_mock_http_job.h"
diff --git a/content/browser/download/file_metadata_mac.mm b/content/browser/download/file_metadata_mac.mm
index fc0556e..9dc504f 100644
--- a/content/browser/download/file_metadata_mac.mm
+++ b/content/browser/download/file_metadata_mac.mm
@@ -132,7 +132,7 @@
   // need to set the values that the OS can't infer.
 
   if (![quarantine_properties valueForKey:(NSString*)kLSQuarantineTypeKey]) {
-    CFStringRef type = (source.SchemeIs("http") || source.SchemeIs("https"))
+    CFStringRef type = source.SchemeIsHTTPOrHTTPS()
                        ? kLSQuarantineTypeWebDownload
                        : kLSQuarantineTypeOtherDownload;
     [quarantine_properties setValue:(NSString*)type
diff --git a/content/browser/download/file_metadata_unittest_linux.cc b/content/browser/download/file_metadata_unittest_linux.cc
index bc8666e..4a3ebca 100644
--- a/content/browser/download/file_metadata_unittest_linux.cc
+++ b/content/browser/download/file_metadata_unittest_linux.cc
@@ -30,7 +30,8 @@
  public:
   FileMetadataLinuxTest()
       : source_url_("http://www.source.com"),
-        referrer_url_("http://www.referrer.com") {}
+        referrer_url_("http://www.referrer.com"),
+        is_xattr_supported_(false) {}
 
   const base::FilePath& test_file() const {
     return test_file_;
diff --git a/content/browser/download/mhtml_generation_browsertest.cc b/content/browser/download/mhtml_generation_browsertest.cc
index 07bffed..7e99fb2 100644
--- a/content/browser/download/mhtml_generation_browsertest.cc
+++ b/content/browser/download/mhtml_generation_browsertest.cc
@@ -9,7 +9,7 @@
 #include "base/run_loop.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index a386a2b..8a9781d 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -971,11 +971,11 @@
     // sub-resource's link can be replaced with local file path, which
     // sub-resource's link need to be replaced with absolute URL which
     // point to its internet address because it got error when saving its data.
-    SaveItem* save_item = NULL;
+
     // Start a new SaveItem job if we still have job in waiting queue.
     if (waiting_item_queue_.size()) {
       DCHECK(wait_state_ == NET_FILES);
-      save_item = waiting_item_queue_.front();
+      SaveItem* save_item = waiting_item_queue_.front();
       if (save_item->save_source() != SaveFileCreateInfo::SAVE_FILE_FROM_DOM) {
         SaveNextFile(false);
       } else if (!in_process_count()) {
diff --git a/content/browser/download/save_package_browsertest.cc b/content/browser/download/save_package_browsertest.cc
index cfa63ed..3910332 100644
--- a/content/browser/download/save_package_browsertest.cc
+++ b/content/browser/download/save_package_browsertest.cc
@@ -4,7 +4,7 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "content/browser/download/save_package.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 
diff --git a/content/browser/download/save_package_unittest.cc b/content/browser/download/save_package_unittest.cc
index 9c8f29f..c0aa3f8 100644
--- a/content/browser/download/save_package_unittest.cc
+++ b/content/browser/download/save_package_unittest.cc
@@ -434,7 +434,7 @@
                         base::FilePath(kTestDir).Append(file_name));
   NavigateAndCommit(view_source_url);
   EXPECT_EQ(actual_url, GetUrlToBeSaved());
-  EXPECT_EQ(view_source_url, contents()->GetURL());
+  EXPECT_EQ(view_source_url, contents()->GetLastCommittedURL());
 }
 
 }  // namespace content
diff --git a/content/browser/fileapi/browser_file_system_helper.cc b/content/browser/fileapi/browser_file_system_helper.cc
index e809857..6df6f1f 100644
--- a/content/browser/fileapi/browser_file_system_helper.cc
+++ b/content/browser/fileapi/browser_file_system_helper.cc
@@ -55,7 +55,9 @@
 
   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
   scoped_refptr<base::SequencedTaskRunner> file_task_runner =
-      pool->GetSequencedTaskRunner(pool->GetNamedSequenceToken("FileAPI"));
+      pool->GetSequencedTaskRunnerWithShutdownBehavior(
+          pool->GetNamedSequenceToken("FileAPI"),
+          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
 
   // Setting up additional filesystem backends.
   ScopedVector<fileapi::FileSystemBackend> additional_backends;
diff --git a/content/browser/fileapi/file_system_browsertest.cc b/content/browser/fileapi/file_system_browsertest.cc
index 7c464a3..eafb1b1 100644
--- a/content/browser/fileapi/file_system_browsertest.cc
+++ b/content/browser/fileapi/file_system_browsertest.cc
@@ -13,7 +13,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "webkit/browser/quota/quota_manager.h"
@@ -36,7 +36,8 @@
     LOG(INFO) << "Navigating to URL and blocking.";
     NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
     LOG(INFO) << "Navigation done.";
-    std::string result = the_browser->web_contents()->GetURL().ref();
+    std::string result =
+        the_browser->web_contents()->GetLastCommittedURL().ref();
     if (result != "pass") {
       std::string js_result;
       ASSERT_TRUE(ExecuteScriptAndExtractString(
diff --git a/content/browser/fileapi/fileapi_message_filter.cc b/content/browser/fileapi/fileapi_message_filter.cc
index d5e903b..66db0d7 100644
--- a/content/browser/fileapi/fileapi_message_filter.cc
+++ b/content/browser/fileapi/fileapi_message_filter.cc
@@ -632,10 +632,10 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
   scoped_refptr<Stream> stream(GetStreamForURL(url));
-  if (!stream.get()) {
-    NOTREACHED();
+  // Stream instances may be deleted on error. Just abort if there's no Stream
+  // instance for |url| in the registry.
+  if (!stream.get())
     return;
-  }
 
   // Data for stream is delivered as TYPE_BYTES item.
   if (item.type() != BlobData::Item::TYPE_BYTES) {
@@ -663,10 +663,8 @@
   }
 
   scoped_refptr<Stream> stream(GetStreamForURL(url));
-  if (!stream.get()) {
-    NOTREACHED();
+  if (!stream.get())
     return;
-  }
 
   stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size);
 }
@@ -676,17 +674,15 @@
   scoped_refptr<Stream> stream(GetStreamForURL(url));
   if (stream.get())
     stream->Finalize();
-  else
-    NOTREACHED();
 }
 
 void FileAPIMessageFilter::OnCloneStream(
     const GURL& url, const GURL& src_url) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  if (!GetStreamForURL(src_url)) {
-    NOTREACHED();
+  // Abort if there's no Stream instance for |src_url| (source Stream which
+  // we're going to make |url| point to) in the registry.
+  if (!GetStreamForURL(src_url))
     return;
-  }
 
   stream_context_->registry()->CloneStream(url, src_url);
   stream_urls_.insert(url.spec());
@@ -695,10 +691,8 @@
 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 
-  if (!GetStreamForURL(url).get()) {
-    NOTREACHED();
+  if (!GetStreamForURL(url).get())
     return;
-  }
 
   stream_context_->registry()->UnregisterStream(url);
   stream_urls_.erase(url.spec());
@@ -806,7 +800,7 @@
     base::PlatformFileError result,
     const base::PlatformFileInfo& info,
     const base::FilePath& platform_path,
-    const scoped_refptr<webkit_blob::ShareableFileReference>& snapshot_file) {
+    const scoped_refptr<webkit_blob::ShareableFileReference>& /* unused */) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   operations_.erase(request_id);
 
@@ -815,7 +809,8 @@
     return;
   }
 
-  scoped_refptr<webkit_blob::ShareableFileReference> file_ref = snapshot_file;
+  scoped_refptr<webkit_blob::ShareableFileReference> file_ref =
+      webkit_blob::ShareableFileReference::Get(platform_path);
   if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
           process_id_, platform_path)) {
     // Give per-file read permission to the snapshot file if it hasn't it yet.
diff --git a/content/browser/fileapi/fileapi_message_filter.h b/content/browser/fileapi/fileapi_message_filter.h
index 8680f24..e3b64a1 100644
--- a/content/browser/fileapi/fileapi_message_filter.h
+++ b/content/browser/fileapi/fileapi_message_filter.h
@@ -196,7 +196,9 @@
                              int permissions,
                              base::PlatformFileError* error);
 
-  // Retrieves the Stream object for |url| from |stream_context_|.
+  // Retrieves the Stream object for |url| from |stream_context_|. Returns unset
+  // scoped_refptr when there's no Stream instance for the given |url|
+  // registered with stream_context_->registry().
   scoped_refptr<Stream> GetStreamForURL(const GURL& url);
 
   fileapi::FileSystemOperationRunner* operation_runner() {
diff --git a/content/browser/geolocation/core_location_data_provider_mac.h b/content/browser/geolocation/core_location_data_provider_mac.h
deleted file mode 100644
index 29204aa..0000000
--- a/content/browser/geolocation/core_location_data_provider_mac.h
+++ /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.
-
-// This file declares a CoreLocation data provider class that allows the
-// CoreLocation framework to run on the UI thread, since the Geolocation API's
-// providers all live on the IO thread
-
-#ifndef CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_
-#define CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/memory/ref_counted.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/geoposition.h"
-
-#import <Foundation/Foundation.h>
-
-@class CoreLocationWrapperMac;
-
-namespace content {
-class CoreLocationProviderMac;
-
-// Data provider class that allows CoreLocation to run in Chrome's UI thread
-// while existing on any of Chrome's threads (in this case the IO thread)
-class CoreLocationDataProviderMac
-    : public base::RefCountedThreadSafe<CoreLocationDataProviderMac> {
- public:
-  CoreLocationDataProviderMac();
-
-  bool StartUpdating(CoreLocationProviderMac* provider);
-  void StopUpdating();
-
-  void UpdatePosition(Geoposition* position);
-
- private:
-  friend class base::RefCountedThreadSafe<CoreLocationDataProviderMac>;
-  ~CoreLocationDataProviderMac();
-
-  // These must execute in BrowserThread::UI
-  void StartUpdatingTask();
-  void StopUpdatingTask();
-  // This must execute in the origin thread (IO thread)
-  void PositionUpdated(Geoposition position);
-
-  // The wrapper class that supplies this class with position data
-  base::scoped_nsobject<CoreLocationWrapperMac> wrapper_;
-  // The LocationProvider class that should receive position data
-  CoreLocationProviderMac* provider_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_
diff --git a/content/browser/geolocation/core_location_data_provider_mac.mm b/content/browser/geolocation/core_location_data_provider_mac.mm
deleted file mode 100644
index 8b1cf82..0000000
--- a/content/browser/geolocation/core_location_data_provider_mac.mm
+++ /dev/null
@@ -1,256 +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.
-
-// This file contains the class definitions for the CoreLocation data provider
-// class and the accompanying Objective C wrapper class. This data provider
-// is used to allow the CoreLocation wrapper to run on the UI thread, since
-// CLLocationManager's start and stop updating methods must be called from a
-// thread with an active NSRunLoop.  Currently only the UI thread appears to
-// fill that requirement.
-
-#include "content/browser/geolocation/core_location_data_provider_mac.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "content/browser/geolocation/core_location_provider_mac.h"
-#include "content/browser/geolocation/geolocation_provider_impl.h"
-
-using content::CoreLocationDataProviderMac;
-using content::Geoposition;
-
-// A few required declarations since the CoreLocation headers are not available
-// with the Mac OS X 10.5 SDK.
-// TODO(jorgevillatoro): Remove these declarations when we build against 10.6
-
-// This idea was borrowed from wifi_data_provider_corewlan_mac.mm
-typedef double CLLocationDegrees;
-typedef double CLLocationAccuracy;
-typedef double CLLocationSpeed;
-typedef double CLLocationDirection;
-typedef double CLLocationDistance;
-typedef struct {
-  CLLocationDegrees latitude;
-  CLLocationDegrees longitude;
-} CLLocationCoordinate2D;
-
-enum {
-  kCLErrorLocationUnknown  = 0,
-  kCLErrorDenied
-};
-
-@interface CLLocationManager : NSObject
-+ (BOOL)locationServicesEnabled;
-@property(assign) id delegate;
-- (void)startUpdatingLocation;
-- (void)stopUpdatingLocation;
-@end
-
-@interface CLLocation : NSObject<NSCopying, NSCoding>
-@property(readonly) CLLocationCoordinate2D coordinate;
-@property(readonly) CLLocationDistance altitude;
-@property(readonly) CLLocationAccuracy horizontalAccuracy;
-@property(readonly) CLLocationAccuracy verticalAccuracy;
-@property(readonly) CLLocationDirection course;
-@property(readonly) CLLocationSpeed speed;
-@end
-
-@protocol CLLocationManagerDelegate
-- (void)locationManager:(CLLocationManager*)manager
-    didUpdateToLocation:(CLLocation*)newLocation
-           fromLocation:(CLLocation*)oldLocation;
-- (void)locationManager:(CLLocationManager*)manager
-       didFailWithError:(NSError*)error;
-@end
-
-// This wrapper class receives CLLocation objects from CoreLocation, converts
-// them to Geoposition objects, and passes them on to the data provider class
-// Note: This class has some specific threading requirements, inherited from
-//       CLLocationManager.  The location manaager's start and stop updating
-//       methods must be called from a thread that has an active run loop (which
-//       seems to only be the UI thread)
-@interface CoreLocationWrapperMac : NSObject<CLLocationManagerDelegate>
-{
- @private
-  NSBundle* bundle_;
-  Class locationManagerClass_;
-  id locationManager_;
-  CoreLocationDataProviderMac* dataProvider_;
-}
-
-- (id)initWithDataProvider:(CoreLocationDataProviderMac*)dataProvider;
-- (void)dealloc;
-
-// Can be called from any thread since it does not require an NSRunLoop. However
-// it is not threadsafe to receive concurrent calls until after a first
-// successful call (to avoid |bundle_| being double initialized)
-- (BOOL)locationDataAvailable;
-
-// These should always be called from BrowserThread::UI
-- (void)startLocation;
-- (void)stopLocation;
-
-// These should only be called by CLLocationManager
-- (void)locationManager:(CLLocationManager*)manager
-    didUpdateToLocation:(CLLocation*)newLocation
-           fromLocation:(CLLocation*)oldLocation;
-- (void)locationManager:(CLLocationManager*)manager
-       didFailWithError:(NSError*)error;
-- (BOOL)loadCoreLocationBundle;
-
-@end
-
-@implementation CoreLocationWrapperMac
-
-- (id)initWithDataProvider:(CoreLocationDataProviderMac*)dataProvider {
-  DCHECK(dataProvider);
-  dataProvider_ = dataProvider;
-  self = [super init];
-  return self;
-}
-
-- (void)dealloc {
-  [locationManager_ setDelegate:nil];
-  [locationManager_ release];
-  [locationManagerClass_ release];
-  [bundle_ release];
-  [super dealloc];
-}
-
-// Load the bundle and check to see if location services are enabled
-// but don't do anything else
-- (BOOL)locationDataAvailable {
-  return ([self loadCoreLocationBundle] &&
-          [locationManagerClass_ locationServicesEnabled]);
-}
-
-- (void)startLocation {
-  if ([self locationDataAvailable]) {
-    if (!locationManager_) {
-      locationManager_ = [[locationManagerClass_ alloc] init];
-      [locationManager_ setDelegate:self];
-    }
-    [locationManager_ startUpdatingLocation];
-  }
-}
-
-- (void)stopLocation {
-  [locationManager_ stopUpdatingLocation];
-}
-
-- (void)locationManager:(CLLocationManager*)manager
-    didUpdateToLocation:(CLLocation*)newLocation
-           fromLocation:(CLLocation*)oldLocation {
-  Geoposition position;
-  position.latitude  = [newLocation coordinate].latitude;
-  position.longitude = [newLocation coordinate].longitude;
-  position.altitude  = [newLocation altitude];
-  position.accuracy  = [newLocation horizontalAccuracy];
-  position.altitude_accuracy = [newLocation verticalAccuracy];
-  position.speed = [newLocation speed];
-  position.heading = [newLocation course];
-  position.timestamp = base::Time::Now();
-  position.error_code = Geoposition::ERROR_CODE_NONE;
-  dataProvider_->UpdatePosition(&position);
-}
-
-- (void)locationManager:(CLLocationManager*)manager
-       didFailWithError:(NSError*)error {
-  Geoposition position;
-  switch ([error code]) {
-    case kCLErrorLocationUnknown:
-      position.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
-      break;
-    case kCLErrorDenied:
-      position.error_code = Geoposition::ERROR_CODE_PERMISSION_DENIED;
-      break;
-    default:
-      NOTREACHED() << "Unknown CoreLocation error: " << [error code];
-      return;
-  }
-  dataProvider_->UpdatePosition(&position);
-}
-
-- (BOOL)loadCoreLocationBundle {
-  if (!bundle_) {
-    bundle_ = [[NSBundle alloc]
-        initWithPath:@"/System/Library/Frameworks/CoreLocation.framework"];
-    if (!bundle_) {
-      DLOG(WARNING) << "Couldn't load CoreLocation Framework";
-      return NO;
-    }
-
-    locationManagerClass_ = [bundle_ classNamed:@"CLLocationManager"];
-  }
-
-  return YES;
-}
-
-@end
-
-namespace content {
-
-CoreLocationDataProviderMac::CoreLocationDataProviderMac() {
-  if (base::MessageLoop::current() !=
-      GeolocationProviderImpl::GetInstance()->message_loop()) {
-    NOTREACHED() << "CoreLocation data provider must be created on "
-        "the Geolocation thread.";
-  }
-  provider_ = NULL;
-  wrapper_.reset([[CoreLocationWrapperMac alloc] initWithDataProvider:this]);
-}
-
-CoreLocationDataProviderMac::~CoreLocationDataProviderMac() {
-}
-
-// Returns true if the CoreLocation wrapper can load the framework and
-// location services are enabled.  The pointer argument will only be accessed
-// in the origin thread.
-bool CoreLocationDataProviderMac::
-    StartUpdating(CoreLocationProviderMac* provider) {
-  DCHECK(provider);
-  DCHECK(!provider_) << "StartUpdating called twice";
-  if (![wrapper_ locationDataAvailable]) return false;
-  provider_ = provider;
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&CoreLocationDataProviderMac::StartUpdatingTask, this));
-  return true;
-}
-
-// Clears provider_ so that any leftover messages from CoreLocation get ignored
-void CoreLocationDataProviderMac::StopUpdating() {
-  provider_ = NULL;
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&CoreLocationDataProviderMac::StopUpdatingTask, this));
-}
-
-void CoreLocationDataProviderMac::UpdatePosition(Geoposition *position) {
-  GeolocationProviderImpl::GetInstance()->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&CoreLocationDataProviderMac::PositionUpdated, this,
-                 *position));
-}
-
-// Runs in BrowserThread::UI
-void CoreLocationDataProviderMac::StartUpdatingTask() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  [wrapper_ startLocation];
-}
-
-// Runs in BrowserThread::UI
-void CoreLocationDataProviderMac::StopUpdatingTask() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  [wrapper_ stopLocation];
-}
-
-void CoreLocationDataProviderMac::PositionUpdated(Geoposition position) {
-  DCHECK(base::MessageLoop::current() ==
-         GeolocationProviderImpl::GetInstance()->message_loop());
-  if (provider_)
-    provider_->SetPosition(&position);
-}
-
-}  // namespace content
diff --git a/content/browser/geolocation/core_location_provider_mac.h b/content/browser/geolocation/core_location_provider_mac.h
deleted file mode 100644
index b4186d4..0000000
--- a/content/browser/geolocation/core_location_provider_mac.h
+++ /dev/null
@@ -1,40 +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.
-
-// This file declares a CoreLocation provider that runs on Mac OS X (10.6).
-// Public for testing only - for normal usage this  header should not be
-// required, as location_provider.h declares the needed factory function.
-
-#ifndef CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_
-#define CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_
-
-#include "content/browser/geolocation/location_provider_base.h"
-#include "content/public/common/geoposition.h"
-
-namespace content {
-class CoreLocationDataProviderMac;
-
-class CoreLocationProviderMac : public LocationProviderBase {
- public:
-  explicit CoreLocationProviderMac();
-  virtual ~CoreLocationProviderMac();
-
-  // LocationProvider
-  virtual bool StartProvider(bool high_accuracy) OVERRIDE;
-  virtual void StopProvider() OVERRIDE;
-  virtual void GetPosition(Geoposition* position) OVERRIDE;
-  virtual void OnPermissionGranted() OVERRIDE;
-
-  // Receives new positions and calls UpdateListeners
-  void SetPosition(Geoposition* position);
-
- private:
-  bool is_updating_;
-  CoreLocationDataProviderMac* data_provider_;
-  Geoposition position_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_
diff --git a/content/browser/geolocation/core_location_provider_mac.mm b/content/browser/geolocation/core_location_provider_mac.mm
deleted file mode 100644
index 1c3aca1..0000000
--- a/content/browser/geolocation/core_location_provider_mac.mm
+++ /dev/null
@@ -1,68 +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/geolocation/core_location_provider_mac.h"
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "content/browser/geolocation/core_location_data_provider_mac.h"
-#include "content/public/common/content_switches.h"
-
-namespace content {
-
-CoreLocationProviderMac::CoreLocationProviderMac()
-    : is_updating_(false) {
-  data_provider_ = new CoreLocationDataProviderMac();
-  data_provider_->AddRef();
-}
-
-CoreLocationProviderMac::~CoreLocationProviderMac() {
-  data_provider_->StopUpdating();
-  data_provider_->Release();
-}
-
-bool CoreLocationProviderMac::StartProvider(bool high_accuracy) {
-  // StartProvider maybe called multiple times. For example, to update the high
-  // accuracy hint.
-  // TODO(jknotten): Support high_accuracy hint in underlying data provider.
-  if (is_updating_)
-    return true;
-
-  is_updating_ = data_provider_->StartUpdating(this);
-  return true;
-}
-
-void CoreLocationProviderMac::StopProvider() {
-  data_provider_->StopUpdating();
-  is_updating_ = false;
-}
-
-void CoreLocationProviderMac::GetPosition(Geoposition* position) {
-  DCHECK(position);
-  *position = position_;
-  DCHECK(position->Validate() ||
-         position->error_code != Geoposition::ERROR_CODE_NONE);
-}
-
-void CoreLocationProviderMac::OnPermissionGranted() {
-}
-
-void CoreLocationProviderMac::SetPosition(Geoposition* position) {
-  DCHECK(position);
-  position_ = *position;
-  DCHECK(position->Validate() ||
-         position->error_code != Geoposition::ERROR_CODE_NONE);
-
-  NotifyCallback(position_);
-}
-
-LocationProvider* NewSystemLocationProvider() {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kExperimentalLocationFeatures)) {
-    return new CoreLocationProviderMac;
-  }
-  return NULL;
-}
-
-}  // namespace content
diff --git a/content/browser/geolocation/device_data_provider.h b/content/browser/geolocation/device_data_provider.h
index d890735..3c69fe8 100644
--- a/content/browser/geolocation/device_data_provider.h
+++ b/content/browser/geolocation/device_data_provider.h
@@ -4,20 +4,19 @@
 
 // A device data provider provides data from the device that is used by a
 // NetworkLocationProvider to obtain a position fix. This data may be either
-// cell radio data or wifi data. For a given type of data, we use a singleton
-// instance of the device data provider, which is used by multiple
-// NetworkLocationProvider objects.
+// wifi data or (currently not used) cell radio data. For a given type of data,
+// we use a singleton instance of the device data provider, which is used by
+// multiple NetworkLocationProvider objects.
 //
-// This file providers DeviceDataProvider, which provides static methods to
+// This file provides DeviceDataProvider, which provides static methods to
 // access the singleton instance. The singleton instance uses a private
 // implementation to abstract across platforms and also to allow mock providers
 // to be used for testing.
 //
 // This file also provides DeviceDataProviderImplBase, a base class which
-// provides commom functionality for the private implementations.
+// provides common functionality for the private implementations.
 //
-// This file also declares the data structures used to represent cell radio data
-// and wifi data.
+// This file also declares the data structure used to represent wifi data.
 
 #ifndef CONTENT_BROWSER_GEOLOCATION_DEVICE_DATA_PROVIDER_H_
 #define CONTENT_BROWSER_GEOLOCATION_DEVICE_DATA_PROVIDER_H_
@@ -30,7 +29,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
-#include "base/threading/non_thread_safe.h"
 #include "content/common/content_export.h"
 
 namespace content {
@@ -96,7 +94,11 @@
     DCHECK(client_loop_);
   }
 
-  virtual bool StartDataProvider() = 0;
+  // Tells the provider to start looking for data. Listeners will start
+  // receiving notifications after this call.
+  virtual void StartDataProvider() = 0;
+  // Tells the provider to stop looking for data. Listeners will stop
+  // receiving notifications after this call.
   virtual void StopDataProvider() = 0;
   virtual bool GetData(DataType* data) = 0;
 
@@ -104,23 +106,19 @@
   // This is required to pass as a parameter when making the callback to
   // listeners.
   void SetContainer(DeviceDataProvider<DataType>* container) {
-    DCHECK(CalledOnClientThread());
     container_ = container;
   }
 
   typedef typename DeviceDataProvider<DataType>::ListenerInterface
           ListenerInterface;
   void AddListener(ListenerInterface* listener) {
-    DCHECK(CalledOnClientThread());
     listeners_.insert(listener);
   }
   bool RemoveListener(ListenerInterface* listener) {
-    DCHECK(CalledOnClientThread());
     return listeners_.erase(listener) == 1;
   }
 
   bool has_listeners() const {
-    DCHECK(CalledOnClientThread());
     return !listeners_.empty();
   }
 
@@ -133,7 +131,7 @@
     // Always make the notify callback via a posted task, so we can unwind
     // callstack here and make callback without causing client re-entrancy.
     client_loop_->PostTask(FROM_HERE, base::Bind(
-        &DeviceDataProviderImplBase<DataType>::NotifyListenersInClientLoop,
+        &DeviceDataProviderImplBase<DataType>::DoNotifyListeners,
         this));
   }
 
@@ -144,8 +142,7 @@
   base::MessageLoop* client_loop() const { return client_loop_; }
 
  private:
-  void NotifyListenersInClientLoop() {
-    DCHECK(CalledOnClientThread());
+  void DoNotifyListeners() {
     // It's possible that all the listeners (and the container) went away
     // whilst this task was pending. This is fine; the loop will be a no-op.
     typename ListenersSet::const_iterator iter = listeners_.begin();
@@ -175,7 +172,7 @@
 // location providers. These location providers access the instance through the
 // Register and Unregister methods.
 template<typename DataType>
-class DeviceDataProvider : public base::NonThreadSafe {
+class DeviceDataProvider {
  public:
   // Interface to be implemented by listeners to a device data provider.
   class ListenerInterface {
@@ -188,7 +185,7 @@
 
   // Sets the factory function which will be used by Register to create the
   // implementation used by the singleton instance. This factory approach is
-  // used to abastract accross both platform-specific implementation and to
+  // used both to abstract accross platform-specific implementations and to
   // inject mock implementations for testing.
   typedef DeviceDataProviderImplBase<DataType>* (*ImplFactoryFunction)(void);
   static void SetFactory(ImplFactoryFunction factory_function_in) {
@@ -202,20 +199,17 @@
   // Adds a listener, which will be called back with DeviceDataUpdateAvailable
   // whenever new data is available. Returns the singleton instance.
   static DeviceDataProvider* Register(ListenerInterface* listener) {
-    bool need_to_start_thread = false;
+    bool need_to_start_provider = false;
     if (!instance_) {
       instance_ = new DeviceDataProvider();
-      need_to_start_thread = true;
+      need_to_start_provider = true;
     }
     DCHECK(instance_);
-    DCHECK(instance_->CalledOnValidThread());
     instance_->AddListener(listener);
     // Start the provider after adding the listener, to avoid any race in
     // it receiving an early callback.
-    if (need_to_start_thread) {
-      bool started = instance_->StartDataProvider();
-      DCHECK(started);
-    }
+    if (need_to_start_provider)
+      instance_->StartDataProvider();
     return instance_;
   }
 
@@ -223,7 +217,6 @@
   // instance. Return value indicates success.
   static bool Unregister(ListenerInterface* listener) {
     DCHECK(instance_);
-    DCHECK(instance_->CalledOnValidThread());
     DCHECK(instance_->has_listeners());
     if (!instance_->RemoveListener(listener)) {
       return false;
@@ -243,7 +236,6 @@
   // value indicates whether this is all the data the provider could ever
   // obtain.
   bool GetData(DataType* data) {
-    DCHECK(this->CalledOnValidThread());
     return impl_->GetData(data);
   }
 
@@ -273,8 +265,8 @@
     return impl_->has_listeners();
   }
 
-  bool StartDataProvider() {
-    return impl_->StartDataProvider();
+  void StartDataProvider() {
+    impl_->StartDataProvider();
   }
 
   void StopDataProvider() {
diff --git a/content/browser/geolocation/empty_device_data_provider.h b/content/browser/geolocation/empty_device_data_provider.h
index 76653f5..eb526d9 100644
--- a/content/browser/geolocation/empty_device_data_provider.h
+++ b/content/browser/geolocation/empty_device_data_provider.h
@@ -19,7 +19,7 @@
   virtual ~EmptyDeviceDataProvider() {}
 
   // DeviceDataProviderImplBase implementation
-  virtual bool StartDataProvider() { return true; }
+  virtual void StartDataProvider() { }
   virtual void StopDataProvider() { }
   virtual bool GetData(DataType *data) {
     DCHECK(data);
diff --git a/content/browser/geolocation/geolocation_provider_impl.h b/content/browser/geolocation/geolocation_provider_impl.h
index d4b5afb..68e83a8 100644
--- a/content/browser/geolocation/geolocation_provider_impl.h
+++ b/content/browser/geolocation/geolocation_provider_impl.h
@@ -25,11 +25,8 @@
 // This is the main API to the geolocation subsystem. The application will hold
 // a single instance of this class and can register multiple clients to be
 // notified of location changes:
-// * Observers are registered by AddLocationUpdateCallback() and will keep
-//   receiving updates
-//   until unregistered by RemoveLocationUpdateCallback().
-// * Callbacks are registered by RequestCallback() and will be called exactly
-//   once when the next update becomes available.
+// * Callbacks are registered by AddLocationUpdateCallback() and will keep
+//   receiving updates until unregistered by RemoveLocationUpdateCallback().
 // The application must instantiate the GeolocationProvider on the IO thread and
 // must communicate with it on the same thread.
 // The underlying location arbitrator will only be enabled whilst there is at
diff --git a/content/browser/geolocation/location_arbitrator_impl.cc b/content/browser/geolocation/location_arbitrator_impl.cc
index 49c1c10..4befee2 100644
--- a/content/browser/geolocation/location_arbitrator_impl.cc
+++ b/content/browser/geolocation/location_arbitrator_impl.cc
@@ -160,7 +160,7 @@
 }
 
 LocationProvider* GeolocationArbitratorImpl::NewSystemLocationProvider() {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
   return NULL;
 #else
   return content::NewSystemLocationProvider();
diff --git a/content/browser/geolocation/network_location_provider.cc b/content/browser/geolocation/network_location_provider.cc
index 82171a0..0ea890c 100644
--- a/content/browser/geolocation/network_location_provider.cc
+++ b/content/browser/geolocation/network_location_provider.cc
@@ -118,7 +118,10 @@
   // Create the position cache.
   position_cache_.reset(new PositionCache());
 
-  request_.reset(new NetworkLocationRequest(url_context_getter, url, this));
+  NetworkLocationRequest::LocationResponseCallback callback =
+      base::Bind(&NetworkLocationProvider::LocationResponseAvailable,
+                 base::Unretained(this));
+  request_.reset(new NetworkLocationRequest(url_context_getter, url, callback));
 }
 
 NetworkLocationProvider::~NetworkLocationProvider() {
@@ -156,7 +159,6 @@
   OnDeviceDataUpdated();
 }
 
-// NetworkLocationRequest::ListenerInterface implementation.
 void NetworkLocationProvider::LocationResponseAvailable(
     const Geoposition& position,
     bool server_error,
diff --git a/content/browser/geolocation/network_location_provider.h b/content/browser/geolocation/network_location_provider.h
index a1ba5b3..84ecfd9 100644
--- a/content/browser/geolocation/network_location_provider.h
+++ b/content/browser/geolocation/network_location_provider.h
@@ -28,8 +28,7 @@
 class NetworkLocationProvider
     : public base::NonThreadSafe,
       public LocationProviderBase,
-      public WifiDataProvider::ListenerInterface,
-      public NetworkLocationRequest::ListenerInterface {
+      public WifiDataProvider::ListenerInterface {
  public:
   // Cache of recently resolved locations. Public for tests.
   class CONTENT_EXPORT PositionCache {
@@ -93,11 +92,10 @@
   // DeviceDataProvider::ListenerInterface implementation.
   virtual void DeviceDataUpdateAvailable(WifiDataProvider* provider) OVERRIDE;
 
-  // NetworkLocationRequest::ListenerInterface implementation.
-  virtual void LocationResponseAvailable(const Geoposition& position,
-                                         bool server_error,
-                                         const string16& access_token,
-                                         const WifiData& wifi_data) OVERRIDE;
+  void LocationResponseAvailable(const Geoposition& position,
+                                 bool server_error,
+                                 const string16& access_token,
+                                 const WifiData& wifi_data);
 
   scoped_refptr<AccessTokenStore> access_token_store_;
 
diff --git a/content/browser/geolocation/network_location_provider_unittest.cc b/content/browser/geolocation/network_location_provider_unittest.cc
index edfada7..b0d9c25 100644
--- a/content/browser/geolocation/network_location_provider_unittest.cc
+++ b/content/browser/geolocation/network_location_provider_unittest.cc
@@ -76,9 +76,8 @@
   }
 
   // DeviceDataProviderImplBase implementation.
-  virtual bool StartDataProvider() {
+  virtual void StartDataProvider() {
     ++start_calls_;
-    return true;
   }
   virtual void StopDataProvider() {
     ++stop_calls_;
diff --git a/content/browser/geolocation/network_location_request.cc b/content/browser/geolocation/network_location_request.cc
index 74a77e1..d11a474 100644
--- a/content/browser/geolocation/network_location_request.cc
+++ b/content/browser/geolocation/network_location_request.cc
@@ -70,10 +70,10 @@
 NetworkLocationRequest::NetworkLocationRequest(
     net::URLRequestContextGetter* context,
     const GURL& url,
-    ListenerInterface* listener)
-        : url_context_(context), listener_(listener),
+    LocationResponseCallback callback)
+        : url_context_(context),
+          callback_(callback),
           url_(url) {
-  DCHECK(listener);
 }
 
 NetworkLocationRequest::~NetworkLocationRequest() {
@@ -139,10 +139,8 @@
         100);
   }
 
-  DCHECK(listener_);
-  DVLOG(1) << "NetworkLocationRequest::Run() : Calling listener with position.";
-  listener_->LocationResponseAvailable(position, server_error, access_token,
-                                       wifi_data_);
+  DVLOG(1) << "NetworkLocationRequest::OnURLFetchComplete() : run callback.";
+  callback_.Run(position, server_error, access_token, wifi_data_);
 }
 
 // Local functions.
diff --git a/content/browser/geolocation/network_location_request.h b/content/browser/geolocation/network_location_request.h
index 36e843b..56a6004 100644
--- a/content/browser/geolocation/network_location_request.h
+++ b/content/browser/geolocation/network_location_request.h
@@ -27,25 +27,20 @@
  public:
   // ID passed to URLFetcher::Create(). Used for testing.
   CONTENT_EXPORT static int url_fetcher_id_for_tests;
-  // Interface for receiving callbacks from a NetworkLocationRequest object.
-  class ListenerInterface {
-   public:
-    // Updates the listener with a new position. server_error indicates whether
-    // was a server or network error - either no response or a 500 error code.
-    virtual void LocationResponseAvailable(
-        const Geoposition& position,
-        bool server_error,
-        const string16& access_token,
-        const WifiData& wifi_data) = 0;
 
-   protected:
-    virtual ~ListenerInterface() {}
-  };
+  // Called when a new geo position is available. The second argument indicates
+  // whether there was a server error or not. It is true when there was a
+  // server or network error - either no response or a 500 error code.
+  typedef base::Callback<void(const Geoposition& /* position */,
+                              bool /* server_error */,
+                              const string16& /* access_token */,
+                              const WifiData& /* wifi_data */)>
+      LocationResponseCallback;
 
   // |url| is the server address to which the request wil be sent.
   NetworkLocationRequest(net::URLRequestContextGetter* context,
                          const GURL& url,
-                         ListenerInterface* listener);
+                         LocationResponseCallback callback);
   virtual ~NetworkLocationRequest();
 
   // Makes a new request. Returns true if the new request was successfully
@@ -62,7 +57,7 @@
   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
 
   scoped_refptr<net::URLRequestContextGetter> url_context_;
-  ListenerInterface* listener_;
+  LocationResponseCallback callback_;
   const GURL url_;
   scoped_ptr<net::URLFetcher> url_fetcher_;
 
diff --git a/content/browser/geolocation/wifi_data_provider_chromeos.cc b/content/browser/geolocation/wifi_data_provider_chromeos.cc
index b4222d7..951d2d3 100644
--- a/content/browser/geolocation/wifi_data_provider_chromeos.cc
+++ b/content/browser/geolocation/wifi_data_provider_chromeos.cc
@@ -29,7 +29,7 @@
 WifiDataProviderChromeOs::~WifiDataProviderChromeOs() {
 }
 
-bool WifiDataProviderChromeOs::StartDataProvider() {
+void WifiDataProviderChromeOs::StartDataProvider() {
   DCHECK(CalledOnClientThread());
 
   DCHECK(polling_policy_ == NULL);
@@ -40,7 +40,6 @@
                                kNoWifiPollingIntervalMilliseconds>);
 
   ScheduleStart();
-  return true;
 }
 
 void WifiDataProviderChromeOs::StopDataProvider() {
diff --git a/content/browser/geolocation/wifi_data_provider_chromeos.h b/content/browser/geolocation/wifi_data_provider_chromeos.h
index ac8902c..4c8a80c 100644
--- a/content/browser/geolocation/wifi_data_provider_chromeos.h
+++ b/content/browser/geolocation/wifi_data_provider_chromeos.h
@@ -16,7 +16,7 @@
   WifiDataProviderChromeOs();
 
   // WifiDataProviderImplBase
-  virtual bool StartDataProvider() OVERRIDE;
+  virtual void StartDataProvider() OVERRIDE;
   virtual void StopDataProvider() OVERRIDE;
   virtual bool GetData(WifiData* data) OVERRIDE;
 
diff --git a/content/browser/geolocation/wifi_data_provider_common.cc b/content/browser/geolocation/wifi_data_provider_common.cc
index 2642176..9132752 100644
--- a/content/browser/geolocation/wifi_data_provider_common.cc
+++ b/content/browser/geolocation/wifi_data_provider_common.cc
@@ -25,40 +25,14 @@
 }
 
 WifiDataProviderCommon::WifiDataProviderCommon()
-    : Thread("Geolocation_wifi_provider"),
-      is_first_scan_complete_(false),
+    : is_first_scan_complete_(false),
       weak_factory_(this) {
 }
 
 WifiDataProviderCommon::~WifiDataProviderCommon() {
-  // Thread must be stopped before entering destructor chain to avoid race
-  // conditions; see comment in DeviceDataProvider::Unregister.
-  DCHECK(!IsRunning());  // Must call StopDataProvider before destroying me.
 }
 
-bool WifiDataProviderCommon::StartDataProvider() {
-  DCHECK(CalledOnClientThread());
-  DCHECK(!IsRunning());  // StartDataProvider must only be called once.
-  return Start();
-}
-
-void WifiDataProviderCommon::StopDataProvider() {
-  DCHECK(CalledOnClientThread());
-  Stop();
-}
-
-bool WifiDataProviderCommon::GetData(WifiData* data) {
-  DCHECK(CalledOnClientThread());
-  DCHECK(data);
-  base::AutoLock lock(data_mutex_);
-  *data = wifi_data_;
-  // If we've successfully completed a scan, indicate that we have all of the
-  // data we can get.
-  return is_first_scan_complete_;
-}
-
-// Thread implementation
-void WifiDataProviderCommon::Init() {
+void WifiDataProviderCommon::StartDataProvider() {
   DCHECK(wlan_api_ == NULL);
   wlan_api_.reset(NewWlanApi());
   if (wlan_api_ == NULL) {
@@ -76,23 +50,26 @@
   ScheduleNextScan(0);
 }
 
-void WifiDataProviderCommon::CleanUp() {
-  // Destroy these instances in the thread on which they were created.
+void WifiDataProviderCommon::StopDataProvider() {
   wlan_api_.reset();
   polling_policy_.reset();
 }
 
+bool WifiDataProviderCommon::GetData(WifiData* data) {
+  *data = wifi_data_;
+  // If we've successfully completed a scan, indicate that we have all of the
+  // data we can get.
+  return is_first_scan_complete_;
+}
+
 void WifiDataProviderCommon::DoWifiScanTask() {
   bool update_available = false;
   WifiData new_data;
   if (!wlan_api_->GetAccessPointData(&new_data.access_point_data)) {
     ScheduleNextScan(polling_policy_->NoWifiInterval());
   } else {
-    {
-      base::AutoLock lock(data_mutex_);
-      update_available = wifi_data_.DiffersSignificantly(new_data);
-      wifi_data_ = new_data;
-    }
+    update_available = wifi_data_.DiffersSignificantly(new_data);
+    wifi_data_ = new_data;
     polling_policy_->UpdatePollingInterval(update_available);
     ScheduleNextScan(polling_policy_->PollingInterval());
   }
@@ -103,7 +80,7 @@
 }
 
 void WifiDataProviderCommon::ScheduleNextScan(int interval) {
-  message_loop()->PostDelayedTask(
+  client_loop()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&WifiDataProviderCommon::DoWifiScanTask,
                  weak_factory_.GetWeakPtr()),
diff --git a/content/browser/geolocation/wifi_data_provider_common.h b/content/browser/geolocation/wifi_data_provider_common.h
index e4bed57..205eae3 100644
--- a/content/browser/geolocation/wifi_data_provider_common.h
+++ b/content/browser/geolocation/wifi_data_provider_common.h
@@ -11,7 +11,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/threading/thread.h"
 #include "content/browser/geolocation/device_data_provider.h"
 #include "content/common/content_export.h"
 
@@ -61,14 +60,10 @@
 
 // Base class to promote code sharing between platform specific wifi data
 // providers. It's optional for specific platforms to derive this, but if they
-// do threading and polling is taken care of by this base class, and all the
-// platform need do is provide the underlying WLAN access API and policy policy,
-// both of which will be create & accessed in the worker thread (only).
-// Also designed this way to promotes ease of testing the cross-platform
-// behavior w.r.t. polling & threading.
-class CONTENT_EXPORT WifiDataProviderCommon
-    : public WifiDataProviderImplBase,
-      private base::Thread {
+// do polling behavior is taken care of by this base class, and all the platform
+// need do is provide the underlying WLAN access API and polling policy.
+// Also designed this way to for ease of testing the cross-platform behavior.
+class CONTENT_EXPORT WifiDataProviderCommon : public WifiDataProviderImplBase {
  public:
   // Interface to abstract the low level data OS library call, and to allow
   // mocking (hence public).
@@ -82,7 +77,7 @@
   WifiDataProviderCommon();
 
   // WifiDataProviderImplBase implementation
-  virtual bool StartDataProvider() OVERRIDE;
+  virtual void StartDataProvider() OVERRIDE;
   virtual void StopDataProvider() OVERRIDE;
   virtual bool GetData(WifiData* data) OVERRIDE;
 
@@ -96,21 +91,15 @@
   virtual PollingPolicyInterface* NewPollingPolicy() = 0;
 
  private:
-  // Thread implementation
-  virtual void Init() OVERRIDE;
-  virtual void CleanUp() OVERRIDE;
-
-  // Task which run in the child thread.
+  // Runs a scan. Notifies the listeners if new data is found.
   void DoWifiScanTask();
 
   // Will schedule a scan; i.e. enqueue DoWifiScanTask deferred task.
   void ScheduleNextScan(int interval);
 
   WifiData wifi_data_;
-  base::Lock data_mutex_;
 
-  // Whether we've successfully completed a scan for WiFi data (or the polling
-  // thread has terminated early).
+  // Whether we've successfully completed a scan for WiFi data.
   bool is_first_scan_complete_;
 
   // Underlying OS wifi API.
@@ -119,7 +108,7 @@
   // Controls the polling update interval.
   scoped_ptr<PollingPolicyInterface> polling_policy_;
 
-  // Holder for the tasks which run on the thread; takes care of cleanup.
+  // Holder for delayed tasks; takes care of cleanup.
   base::WeakPtrFactory<WifiDataProviderCommon> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(WifiDataProviderCommon);
diff --git a/content/browser/geolocation/wifi_data_provider_common_unittest.cc b/content/browser/geolocation/wifi_data_provider_common_unittest.cc
index 9d1b9fb..2873720 100644
--- a/content/browser/geolocation/wifi_data_provider_common_unittest.cc
+++ b/content/browser/geolocation/wifi_data_provider_common_unittest.cc
@@ -146,7 +146,7 @@
       .Times(AtLeast(1));
   EXPECT_CALL(*polling_policy_, PollingInterval())
       .Times(AtLeast(1));
-  EXPECT_TRUE(provider_->StartDataProvider());
+  provider_->StartDataProvider();
   main_message_loop_.Run();
   SUCCEED();
 }
@@ -188,7 +188,7 @@
       .Times(AtLeast(1));
   EXPECT_CALL(*polling_policy_, PollingInterval())
       .Times(AtLeast(1));
-  EXPECT_TRUE(provider_->StartDataProvider());
+  provider_->StartDataProvider();
   main_message_loop_.Run();
   // Check we had at least one call. The worker thread may have raced ahead
   // and made multiple calls.
@@ -211,7 +211,7 @@
   single_access_point.ssid = ASCIIToUTF16("foossid");
   wlan_api_->data_out_.insert(single_access_point);
 
-  EXPECT_TRUE(provider_->StartDataProvider());
+  provider_->StartDataProvider();
   main_message_loop_.Run();
   EXPECT_GT(wlan_api_->calls_, 0);
   WifiData data;
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index a0cf1e2..77dda3f 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/browser/compositor_util.h"
+#include "content/browser/gpu/compositor_util.h"
 
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
diff --git a/content/browser/gpu/compositor_util.h b/content/browser/gpu/compositor_util.h
new file mode 100644
index 0000000..06b8f1d
--- /dev/null
+++ b/content/browser/gpu/compositor_util.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_GPU_COMPOSITOR_UTIL_H_
+#define CONTENT_BROWSER_GPU_COMPOSITOR_UTIL_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Returns true if the threaded compositor is on (via flags or field trial).
+CONTENT_EXPORT bool IsThreadedCompositingEnabled();
+
+// Returns true if force-compositing-mode is on (via flags or field trial).
+CONTENT_EXPORT bool IsForceCompositingModeEnabled();
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_GPU_COMPOSITOR_UTIL_H_
diff --git a/content/browser/gpu/gpu_crash_browsertest.cc b/content/browser/gpu/gpu_crash_browsertest.cc
index eafbc68..98650d3 100644
--- a/content/browser/gpu/gpu_crash_browsertest.cc
+++ b/content/browser/gpu/gpu_crash_browsertest.cc
@@ -10,7 +10,7 @@
 #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/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index bb3e5b1..3ff628a 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -358,6 +358,13 @@
 }
 
 bool GpuDataManagerImplPrivate::IsFeatureBlacklisted(int feature) const {
+#if defined(OS_CHROMEOS)
+  if (feature == gpu::GPU_FEATURE_TYPE_PANEL_FITTING &&
+      CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisablePanelFitting)) {
+    return true;
+  }
+#endif  // OS_CHROMEOS
   if (use_swiftshader_) {
     // Skia's software rendering is probably more efficient than going through
     // software emulation of the GPU, so use that.
@@ -736,6 +743,11 @@
                                     IntSetToString(gpu_driver_bugs_));
   }
 
+  if (IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE) &&
+      !command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) {
+    command_line->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+  }
+
 #if defined(OS_WIN)
   // DisplayLink 7.1 and earlier can cause the GPU process to crash on startup.
   // http://crbug.com/177611
@@ -829,6 +841,7 @@
     prefs->accelerated_compositing_enabled = true;
     prefs->accelerated_compositing_for_3d_transforms_enabled = true;
     prefs->accelerated_compositing_for_plugins_enabled = true;
+    prefs->accelerated_compositing_for_video_enabled = true;
   }
 
 #if defined(USE_AURA)
@@ -1246,4 +1259,3 @@
 }
 
 }  // namespace content
-
diff --git a/content/browser/gpu/gpu_functional_browsertest.cc b/content/browser/gpu/gpu_functional_browsertest.cc
index b3c2a57..1bef1fb 100644
--- a/content/browser/gpu/gpu_functional_browsertest.cc
+++ b/content/browser/gpu/gpu_functional_browsertest.cc
@@ -10,7 +10,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index 0e778c2..0340077 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -15,9 +15,9 @@
 #include "base/sys_info.h"
 #include "base/values.h"
 #include "cc/base/switches.h"
+#include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/compositor_util.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
diff --git a/content/browser/gpu/gpu_memory_test.cc b/content/browser/gpu/gpu_memory_test.cc
index cb74a62..1ccfab6 100644
--- a/content/browser/gpu/gpu_memory_test.cc
+++ b/content/browser/gpu/gpu_memory_test.cc
@@ -12,7 +12,7 @@
 #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/shell.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"
diff --git a/content/browser/gpu/gpu_pixel_browsertest.cc b/content/browser/gpu/gpu_pixel_browsertest.cc
index 5909321..3eaf857 100644
--- a/content/browser/gpu/gpu_pixel_browsertest.cc
+++ b/content/browser/gpu/gpu_pixel_browsertest.cc
@@ -16,7 +16,7 @@
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "gpu/config/gpu_test_config.h"
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 8cbb7aa..7839ea7 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -278,43 +278,6 @@
 
 }  // anonymous namespace
 
-// Single process not supported in multiple dll mode currently.
-#if !defined(CHROME_MULTIPLE_DLL)
-// This class creates a GPU thread (instead of a GPU process), when running
-// with --in-process-gpu or --single-process.
-class GpuMainThread : public base::Thread {
- public:
-  explicit GpuMainThread(const std::string& channel_id)
-      : base::Thread("Chrome_InProcGpuThread"),
-        channel_id_(channel_id),
-        gpu_process_(NULL) {
-  }
-
-  virtual ~GpuMainThread() {
-    Stop();
-  }
-
- protected:
-  virtual void Init() OVERRIDE {
-    gpu_process_ = new GpuProcess();
-    // The process object takes ownership of the thread object, so do not
-    // save and delete the pointer.
-    gpu_process_->set_main_thread(new GpuChildThread(channel_id_));
-  }
-
-  virtual void CleanUp() OVERRIDE {
-    delete gpu_process_;
-  }
-
- private:
-  std::string channel_id_;
-  // Deleted in CleanUp() on the gpu thread, so don't use smart pointers.
-  GpuProcess* gpu_process_;
-
-  DISALLOW_COPY_AND_ASSIGN(GpuMainThread);
-};
-#endif  // !CHROME_MULTIPLE_DLL
-
 // static
 bool GpuProcessHost::ValidateHost(GpuProcessHost* host) {
   if (!host)
@@ -401,6 +364,13 @@
   }
 }
 
+GpuMainThreadFactoryFunction g_gpu_main_thread_factory = NULL;
+
+void GpuProcessHost::RegisterGpuMainThreadFactory(
+    GpuMainThreadFactoryFunction create) {
+  g_gpu_main_thread_factory = create;
+}
+
 // static
 GpuProcessHost* GpuProcessHost::FromID(int host_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
@@ -598,19 +568,15 @@
   if (channel_id.empty())
     return false;
 
-  // Single process not supported in multiple dll mode currently.
-#if !defined(CHROME_MULTIPLE_DLL)
-  if (in_process_) {
+  if (in_process_ && g_gpu_main_thread_factory) {
     CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kDisableGpuWatchdog);
 
-    in_process_gpu_thread_.reset(new GpuMainThread(channel_id));
+    in_process_gpu_thread_.reset(g_gpu_main_thread_factory(channel_id));
     in_process_gpu_thread_->Start();
 
     OnProcessLaunched();  // Fake a callback that the process is ready.
-  } else
-#endif  // !CHROME_MULTIPLE_DLL
-      if (!LaunchGpuProcess(channel_id)) {
+  } else if (!LaunchGpuProcess(channel_id)) {
     return false;
   }
 
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 8908a10..32345b7 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -44,6 +44,8 @@
 class RenderWidgetHostViewFrameSubscriber;
 class ShaderDiskCache;
 
+typedef base::Thread* (*GpuMainThreadFactoryFunction)(const std::string& id);
+
 class GpuProcessHost : public BrowserChildProcessHostDelegate,
                        public IPC::Sender,
                        public base::NonThreadSafe {
@@ -82,6 +84,9 @@
                                       CauseForGpuLaunch cause,
                                       IPC::Message* message);
 
+  CONTENT_EXPORT static void RegisterGpuMainThreadFactory(
+      GpuMainThreadFactoryFunction create);
+
   // Get the GPU process host for the GPU process with the given ID. Returns
   // null if the process no longer exists.
   static GpuProcessHost* FromID(int host_id);
@@ -214,9 +219,7 @@
   bool swiftshader_rendering_;
   GpuProcessKind kind_;
 
-#if !defined(CHROME_MULTIPLE_DLL)
-  scoped_ptr<GpuMainThread> in_process_gpu_thread_;
-#endif
+  scoped_ptr<base::Thread> in_process_gpu_thread_;
 
   // Whether we actually launched a GPU process.
   bool process_launched_;
diff --git a/content/browser/gpu/webgl_conformance_test.cc b/content/browser/gpu/webgl_conformance_test.cc
index 79f3078..e8fb8a5 100644
--- a/content/browser/gpu/webgl_conformance_test.cc
+++ b/content/browser/gpu/webgl_conformance_test.cc
@@ -10,7 +10,7 @@
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "gpu/config/gpu_test_config.h"
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index ab010cb..e41e281 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -21,7 +21,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "webkit/browser/database/database_util.h"
@@ -46,7 +46,8 @@
     LOG(INFO) << "Navigating to URL and blocking.";
     NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
     LOG(INFO) << "Navigation done.";
-    std::string result = the_browser->web_contents()->GetURL().ref();
+    std::string result =
+        the_browser->web_contents()->GetLastCommittedURL().ref();
     if (result != "pass") {
       std::string js_result;
       ASSERT_TRUE(ExecuteScriptAndExtractString(
diff --git a/content/browser/indexed_db/indexed_db_cursor.cc b/content/browser/indexed_db/indexed_db_cursor.cc
index 1ee13e7..cb254d9 100644
--- a/content/browser/indexed_db/indexed_db_cursor.cc
+++ b/content/browser/indexed_db/indexed_db_cursor.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/indexed_db/indexed_db_cursor.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "content/browser/indexed_db/indexed_db_callbacks.h"
 #include "content/browser/indexed_db/indexed_db_database_error.h"
@@ -12,53 +13,6 @@
 
 namespace content {
 
-class IndexedDBCursor::CursorIterationOperation
-    : public IndexedDBTransaction::Operation {
- public:
-  CursorIterationOperation(scoped_refptr<IndexedDBCursor> cursor,
-                           scoped_ptr<IndexedDBKey> key,
-                           scoped_refptr<IndexedDBCallbacks> callbacks)
-      : cursor_(cursor), key_(key.Pass()), callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  scoped_refptr<IndexedDBCursor> cursor_;
-  scoped_ptr<IndexedDBKey> key_;
-  scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
-class IndexedDBCursor::CursorAdvanceOperation
-    : public IndexedDBTransaction::Operation {
- public:
-  CursorAdvanceOperation(scoped_refptr<IndexedDBCursor> cursor,
-                         uint32 count,
-                         scoped_refptr<IndexedDBCallbacks> callbacks)
-      : cursor_(cursor), count_(count), callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  scoped_refptr<IndexedDBCursor> cursor_;
-  uint32 count_;
-  scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
-class IndexedDBCursor::CursorPrefetchIterationOperation
-    : public IndexedDBTransaction::Operation {
- public:
-  CursorPrefetchIterationOperation(scoped_refptr<IndexedDBCursor> cursor,
-                                   int number_to_fetch,
-                                   scoped_refptr<IndexedDBCallbacks> callbacks)
-      : cursor_(cursor),
-        number_to_fetch_(number_to_fetch),
-        callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  scoped_refptr<IndexedDBCursor> cursor_;
-  int number_to_fetch_;
-  scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
 IndexedDBCursor::IndexedDBCursor(
     scoped_ptr<IndexedDBBackingStore::Cursor> cursor,
     indexed_db::CursorType cursor_type,
@@ -81,7 +35,11 @@
   IDB_TRACE("IndexedDBCursor::Continue");
 
   transaction_->ScheduleTask(
-      task_type_, new CursorIterationOperation(this, key.Pass(), callbacks));
+      task_type_,
+      base::Bind(&IndexedDBCursor::CursorIterationOperation,
+                 this,
+                 base::Passed(&key),
+                 callbacks));
 }
 
 void IndexedDBCursor::Advance(uint32 count,
@@ -89,35 +47,38 @@
   IDB_TRACE("IndexedDBCursor::Advance");
 
   transaction_->ScheduleTask(
-      new CursorAdvanceOperation(this, count, callbacks));
+      task_type_,
+      base::Bind(
+          &IndexedDBCursor::CursorAdvanceOperation, this, count, callbacks));
 }
 
-void IndexedDBCursor::CursorAdvanceOperation::Perform(
+void IndexedDBCursor::CursorAdvanceOperation(
+    uint32 count,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
     IndexedDBTransaction* /*transaction*/) {
-  IDB_TRACE("CursorAdvanceOperation");
-  if (!cursor_->cursor_ || !cursor_->cursor_->Advance(count_)) {
-    cursor_->cursor_.reset();
-    callbacks_->OnSuccess(static_cast<std::string*>(NULL));
+  IDB_TRACE("IndexedDBCursor::CursorAdvanceOperation");
+  if (!cursor_ || !cursor_->Advance(count)) {
+    cursor_.reset();
+    callbacks->OnSuccess(static_cast<std::string*>(NULL));
     return;
   }
 
-  callbacks_->OnSuccess(
-      cursor_->key(), cursor_->primary_key(), cursor_->Value());
+  callbacks->OnSuccess(key(), primary_key(), Value());
 }
 
-void IndexedDBCursor::CursorIterationOperation::Perform(
+void IndexedDBCursor::CursorIterationOperation(
+    scoped_ptr<IndexedDBKey> key,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
     IndexedDBTransaction* /*transaction*/) {
-  IDB_TRACE("CursorIterationOperation");
-  if (!cursor_->cursor_ ||
-      !cursor_->cursor_->Continue(key_.get(),
-                                  IndexedDBBackingStore::Cursor::SEEK)) {
-    cursor_->cursor_.reset();
-    callbacks_->OnSuccess(static_cast<std::string*>(NULL));
+  IDB_TRACE("IndexedDBCursor::CursorIterationOperation");
+  if (!cursor_ ||
+      !cursor_->Continue(key.get(), IndexedDBBackingStore::Cursor::SEEK)) {
+    cursor_.reset();
+    callbacks->OnSuccess(static_cast<std::string*>(NULL));
     return;
   }
 
-  callbacks_->OnSuccess(
-      cursor_->key(), cursor_->primary_key(), cursor_->Value());
+  callbacks->OnSuccess(this->key(), primary_key(), Value());
 }
 
 void IndexedDBCursor::PrefetchContinue(
@@ -127,38 +88,43 @@
 
   transaction_->ScheduleTask(
       task_type_,
-      new CursorPrefetchIterationOperation(this, number_to_fetch, callbacks));
+      base::Bind(&IndexedDBCursor::CursorPrefetchIterationOperation,
+                 this,
+                 number_to_fetch,
+                 callbacks));
 }
 
-void IndexedDBCursor::CursorPrefetchIterationOperation::Perform(
+void IndexedDBCursor::CursorPrefetchIterationOperation(
+    int number_to_fetch,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
     IndexedDBTransaction* /*transaction*/) {
-  IDB_TRACE("CursorPrefetchIterationOperation");
+  IDB_TRACE("IndexedDBCursor::CursorPrefetchIterationOperation");
 
   std::vector<IndexedDBKey> found_keys;
   std::vector<IndexedDBKey> found_primary_keys;
   std::vector<std::string> found_values;
 
-  if (cursor_->cursor_)
-    cursor_->saved_cursor_.reset(cursor_->cursor_->Clone());
+  if (cursor_)
+    saved_cursor_.reset(cursor_->Clone());
   const size_t max_size_estimate = 10 * 1024 * 1024;
   size_t size_estimate = 0;
 
-  for (int i = 0; i < number_to_fetch_; ++i) {
-    if (!cursor_->cursor_ || !cursor_->cursor_->Continue()) {
-      cursor_->cursor_.reset();
+  for (int i = 0; i < number_to_fetch; ++i) {
+    if (!cursor_ || !cursor_->Continue()) {
+      cursor_.reset();
       break;
     }
 
-    found_keys.push_back(cursor_->cursor_->key());
-    found_primary_keys.push_back(cursor_->cursor_->primary_key());
+    found_keys.push_back(cursor_->key());
+    found_primary_keys.push_back(cursor_->primary_key());
 
-    switch (cursor_->cursor_type_) {
+    switch (cursor_type_) {
       case indexed_db::CURSOR_KEY_ONLY:
         found_values.push_back(std::string());
         break;
       case indexed_db::CURSOR_KEY_AND_VALUE: {
         std::string value;
-        value.swap(*cursor_->cursor_->Value());
+        value.swap(*cursor_->Value());
         size_estimate += value.size();
         found_values.push_back(value);
         break;
@@ -166,19 +132,19 @@
       default:
         NOTREACHED();
     }
-    size_estimate += cursor_->cursor_->key().size_estimate();
-    size_estimate += cursor_->cursor_->primary_key().size_estimate();
+    size_estimate += cursor_->key().size_estimate();
+    size_estimate += cursor_->primary_key().size_estimate();
 
     if (size_estimate > max_size_estimate)
       break;
   }
 
   if (!found_keys.size()) {
-    callbacks_->OnSuccess(static_cast<std::string*>(NULL));
+    callbacks->OnSuccess(static_cast<std::string*>(NULL));
     return;
   }
 
-  callbacks_->OnSuccessWithPrefetch(
+  callbacks->OnSuccessWithPrefetch(
       found_keys, found_primary_keys, found_values);
 }
 
diff --git a/content/browser/indexed_db/indexed_db_cursor.h b/content/browser/indexed_db/indexed_db_cursor.h
index 2cf9d4f..db59630 100644
--- a/content/browser/indexed_db/indexed_db_cursor.h
+++ b/content/browser/indexed_db/indexed_db_cursor.h
@@ -41,15 +41,22 @@
   }
   void Close();
 
+  void CursorIterationOperation(scoped_ptr<IndexedDBKey> key,
+                                scoped_refptr<IndexedDBCallbacks> callbacks,
+                                IndexedDBTransaction* transaction);
+  void CursorAdvanceOperation(uint32 count,
+                              scoped_refptr<IndexedDBCallbacks> callbacks,
+                              IndexedDBTransaction* transaction);
+  void CursorPrefetchIterationOperation(
+      int number_to_fetch,
+      scoped_refptr<IndexedDBCallbacks> callbacks,
+      IndexedDBTransaction* transaction);
+
  private:
   friend class base::RefCounted<IndexedDBCursor>;
 
   ~IndexedDBCursor();
 
-  class CursorIterationOperation;
-  class CursorAdvanceOperation;
-  class CursorPrefetchIterationOperation;
-
   IndexedDBDatabase::TaskType task_type_;
   indexed_db::CursorType cursor_type_;
   const scoped_refptr<IndexedDBTransaction> transaction_;
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 9eb5774..78d5b6a 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -29,345 +29,6 @@
 
 namespace content {
 
-class CreateObjectStoreOperation : public IndexedDBTransaction::Operation {
- public:
-  CreateObjectStoreOperation(
-      scoped_refptr<IndexedDBBackingStore> backing_store,
-      const IndexedDBObjectStoreMetadata& object_store_metadata)
-      : backing_store_(backing_store),
-        object_store_metadata_(object_store_metadata) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const IndexedDBObjectStoreMetadata object_store_metadata_;
-};
-
-class DeleteObjectStoreOperation : public IndexedDBTransaction::Operation {
- public:
-  DeleteObjectStoreOperation(
-      scoped_refptr<IndexedDBBackingStore> backing_store,
-      const IndexedDBObjectStoreMetadata& object_store_metadata)
-      : backing_store_(backing_store),
-        object_store_metadata_(object_store_metadata) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const IndexedDBObjectStoreMetadata object_store_metadata_;
-};
-
-class IndexedDBDatabase::VersionChangeOperation
-    : public IndexedDBTransaction::Operation {
- public:
-  VersionChangeOperation(scoped_refptr<IndexedDBDatabase> database,
-                         int64 transaction_id,
-                         int64 version,
-                         scoped_refptr<IndexedDBCallbacks> callbacks,
-                         scoped_ptr<IndexedDBConnection> connection,
-                         WebKit::WebIDBCallbacks::DataLoss data_loss)
-      : database_(database),
-        transaction_id_(transaction_id),
-        version_(version),
-        callbacks_(callbacks),
-        connection_(connection.Pass()),
-        data_loss_(data_loss) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  scoped_refptr<IndexedDBDatabase> database_;
-  int64 transaction_id_;
-  int64 version_;
-  scoped_refptr<IndexedDBCallbacks> callbacks_;
-  scoped_ptr<IndexedDBConnection> connection_;
-  WebKit::WebIDBCallbacks::DataLoss data_loss_;
-};
-
-class CreateObjectStoreAbortOperation : public IndexedDBTransaction::Operation {
- public:
-  CreateObjectStoreAbortOperation(scoped_refptr<IndexedDBDatabase> database,
-                                  int64 object_store_id)
-      : database_(database), object_store_id_(object_store_id) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBDatabase> database_;
-  const int64 object_store_id_;
-};
-
-class DeleteObjectStoreAbortOperation : public IndexedDBTransaction::Operation {
- public:
-  DeleteObjectStoreAbortOperation(
-      scoped_refptr<IndexedDBDatabase> database,
-      const IndexedDBObjectStoreMetadata& object_store_metadata)
-      : database_(database), object_store_metadata_(object_store_metadata) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  scoped_refptr<IndexedDBDatabase> database_;
-  IndexedDBObjectStoreMetadata object_store_metadata_;
-};
-
-class IndexedDBDatabase::VersionChangeAbortOperation
-    : public IndexedDBTransaction::Operation {
- public:
-  VersionChangeAbortOperation(scoped_refptr<IndexedDBDatabase> database,
-                              const string16& previous_version,
-                              int64 previous_int_version)
-      : database_(database),
-        previous_version_(previous_version),
-        previous_int_version_(previous_int_version) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  scoped_refptr<IndexedDBDatabase> database_;
-  string16 previous_version_;
-  int64 previous_int_version_;
-};
-
-class CreateIndexOperation : public IndexedDBTransaction::Operation {
- public:
-  CreateIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-                       int64 object_store_id,
-                       const IndexedDBIndexMetadata& index_metadata)
-      : backing_store_(backing_store),
-        object_store_id_(object_store_id),
-        index_metadata_(index_metadata) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 object_store_id_;
-  const IndexedDBIndexMetadata index_metadata_;
-};
-
-class DeleteIndexOperation : public IndexedDBTransaction::Operation {
- public:
-  DeleteIndexOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-                       int64 object_store_id,
-                       const IndexedDBIndexMetadata& index_metadata)
-      : backing_store_(backing_store),
-        object_store_id_(object_store_id),
-        index_metadata_(index_metadata) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 object_store_id_;
-  const IndexedDBIndexMetadata index_metadata_;
-};
-
-class CreateIndexAbortOperation : public IndexedDBTransaction::Operation {
- public:
-  CreateIndexAbortOperation(scoped_refptr<IndexedDBDatabase> database,
-                            int64 object_store_id,
-                            int64 index_id)
-      : database_(database),
-        object_store_id_(object_store_id),
-        index_id_(index_id) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBDatabase> database_;
-  const int64 object_store_id_;
-  const int64 index_id_;
-};
-
-class DeleteIndexAbortOperation : public IndexedDBTransaction::Operation {
- public:
-  DeleteIndexAbortOperation(scoped_refptr<IndexedDBDatabase> database,
-                            int64 object_store_id,
-                            const IndexedDBIndexMetadata& index_metadata)
-      : database_(database),
-        object_store_id_(object_store_id),
-        index_metadata_(index_metadata) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBDatabase> database_;
-  const int64 object_store_id_;
-  const IndexedDBIndexMetadata index_metadata_;
-};
-
-class GetOperation : public IndexedDBTransaction::Operation {
- public:
-  GetOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-               int64 database_id,
-               int64 object_store_id,
-               int64 index_id,
-               const IndexedDBKeyPath& key_path,
-               const bool auto_increment,
-               scoped_ptr<IndexedDBKeyRange> key_range,
-               indexed_db::CursorType cursor_type,
-               scoped_refptr<IndexedDBCallbacks> callbacks)
-      : backing_store_(backing_store),
-        database_id_(database_id),
-        object_store_id_(object_store_id),
-        index_id_(index_id),
-        key_path_(key_path),
-        auto_increment_(auto_increment),
-        key_range_(key_range.Pass()),
-        cursor_type_(cursor_type),
-        callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 database_id_;
-  const int64 object_store_id_;
-  const int64 index_id_;
-  const IndexedDBKeyPath key_path_;
-  const bool auto_increment_;
-  const scoped_ptr<IndexedDBKeyRange> key_range_;
-  const indexed_db::CursorType cursor_type_;
-  const scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
-class PutOperation : public IndexedDBTransaction::Operation {
- public:
-  PutOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-               int64 database_id,
-               const IndexedDBObjectStoreMetadata& object_store,
-               std::string* value,
-               scoped_ptr<IndexedDBKey> key,
-               IndexedDBDatabase::PutMode put_mode,
-               scoped_refptr<IndexedDBCallbacks> callbacks,
-               const std::vector<int64>& index_ids,
-               const std::vector<IndexedDBDatabase::IndexKeys>& index_keys)
-      : backing_store_(backing_store),
-        database_id_(database_id),
-        object_store_(object_store),
-        key_(key.Pass()),
-        put_mode_(put_mode),
-        callbacks_(callbacks),
-        index_ids_(index_ids),
-        index_keys_(index_keys) {
-    value_.swap(*value);
-  }
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 database_id_;
-  const IndexedDBObjectStoreMetadata object_store_;
-  std::string value_;
-  scoped_ptr<IndexedDBKey> key_;
-  const IndexedDBDatabase::PutMode put_mode_;
-  const scoped_refptr<IndexedDBCallbacks> callbacks_;
-  const std::vector<int64> index_ids_;
-  const std::vector<IndexedDBDatabase::IndexKeys> index_keys_;
-};
-
-class SetIndexesReadyOperation : public IndexedDBTransaction::Operation {
- public:
-  explicit SetIndexesReadyOperation(size_t index_count)
-      : index_count_(index_count) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const size_t index_count_;
-};
-
-class OpenCursorOperation : public IndexedDBTransaction::Operation {
- public:
-  OpenCursorOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-                      int64 database_id,
-                      int64 object_store_id,
-                      int64 index_id,
-                      scoped_ptr<IndexedDBKeyRange> key_range,
-                      indexed_db::CursorDirection direction,
-                      indexed_db::CursorType cursor_type,
-                      IndexedDBDatabase::TaskType task_type,
-                      scoped_refptr<IndexedDBCallbacks> callbacks)
-      : backing_store_(backing_store),
-        database_id_(database_id),
-        object_store_id_(object_store_id),
-        index_id_(index_id),
-        key_range_(key_range.Pass()),
-        direction_(direction),
-        cursor_type_(cursor_type),
-        task_type_(task_type),
-        callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 database_id_;
-  const int64 object_store_id_;
-  const int64 index_id_;
-  const scoped_ptr<IndexedDBKeyRange> key_range_;
-  const indexed_db::CursorDirection direction_;
-  const indexed_db::CursorType cursor_type_;
-  const IndexedDBDatabase::TaskType task_type_;
-  const scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
-class CountOperation : public IndexedDBTransaction::Operation {
- public:
-  CountOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-                 int64 database_id,
-                 int64 object_store_id,
-                 int64 index_id,
-                 scoped_ptr<IndexedDBKeyRange> key_range,
-                 scoped_refptr<IndexedDBCallbacks> callbacks)
-      : backing_store_(backing_store),
-        database_id_(database_id),
-        object_store_id_(object_store_id),
-        index_id_(index_id),
-        key_range_(key_range.Pass()),
-        callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 database_id_;
-  const int64 object_store_id_;
-  const int64 index_id_;
-  const scoped_ptr<IndexedDBKeyRange> key_range_;
-  const scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
-class DeleteRangeOperation : public IndexedDBTransaction::Operation {
- public:
-  DeleteRangeOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-                       int64 database_id,
-                       int64 object_store_id,
-                       scoped_ptr<IndexedDBKeyRange> key_range,
-                       scoped_refptr<IndexedDBCallbacks> callbacks)
-      : backing_store_(backing_store),
-        database_id_(database_id),
-        object_store_id_(object_store_id),
-        key_range_(key_range.Pass()),
-        callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 database_id_;
-  const int64 object_store_id_;
-  const scoped_ptr<IndexedDBKeyRange> key_range_;
-  const scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
-class ClearOperation : public IndexedDBTransaction::Operation {
- public:
-  ClearOperation(scoped_refptr<IndexedDBBackingStore> backing_store,
-                 int64 database_id,
-                 int64 object_store_id,
-                 scoped_refptr<IndexedDBCallbacks> callbacks)
-      : backing_store_(backing_store),
-        database_id_(database_id),
-        object_store_id_(object_store_id),
-        callbacks_(callbacks) {}
-  virtual void Perform(IndexedDBTransaction* transaction) OVERRIDE;
-
- private:
-  const scoped_refptr<IndexedDBBackingStore> backing_store_;
-  const int64 database_id_;
-  const int64 object_store_id_;
-  const scoped_refptr<IndexedDBCallbacks> callbacks_;
-};
-
 // PendingOpenCall has a scoped_refptr<IndexedDBDatabaseCallbacks> because it
 // isn't a connection yet.
 class IndexedDBDatabase::PendingOpenCall {
@@ -474,11 +135,10 @@
 }
 }
 
-IndexedDBDatabase::IndexedDBDatabase(
-    const string16& name,
-    IndexedDBBackingStore* backing_store,
-    IndexedDBFactory* factory,
-    const Identifier& unique_identifier)
+IndexedDBDatabase::IndexedDBDatabase(const string16& name,
+                                     IndexedDBBackingStore* backing_store,
+                                     IndexedDBFactory* factory,
+                                     const Identifier& unique_identifier)
     : backing_store_(backing_store),
       metadata_(name,
                 kInvalidId,
@@ -647,25 +307,31 @@
       IndexedDBDatabase::kMinimumIndexId);
 
   transaction->ScheduleTask(
-      new CreateObjectStoreOperation(backing_store_, object_store_metadata),
-      new CreateObjectStoreAbortOperation(this, object_store_id));
+      base::Bind(&IndexedDBDatabase::CreateObjectStoreOperation,
+                 this,
+                 object_store_metadata),
+      base::Bind(&IndexedDBDatabase::CreateObjectStoreAbortOperation,
+                 this,
+                 object_store_id));
 
   AddObjectStore(object_store_metadata, object_store_id);
 }
 
-void CreateObjectStoreOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("CreateObjectStoreOperation");
+void IndexedDBDatabase::CreateObjectStoreOperation(
+    const IndexedDBObjectStoreMetadata& object_store_metadata,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::CreateObjectStoreOperation");
   if (!backing_store_->CreateObjectStore(
           transaction->BackingStoreTransaction(),
           transaction->database()->id(),
-          object_store_metadata_.id,
-          object_store_metadata_.name,
-          object_store_metadata_.key_path,
-          object_store_metadata_.auto_increment)) {
+          object_store_metadata.id,
+          object_store_metadata.name,
+          object_store_metadata.key_path,
+          object_store_metadata.auto_increment)) {
     transaction->Abort(IndexedDBDatabaseError(
         WebKit::WebIDBDatabaseExceptionUnknownError,
         ASCIIToUTF16("Internal error creating object store '") +
-            object_store_metadata_.name + ASCIIToUTF16("'.")));
+            object_store_metadata.name + ASCIIToUTF16("'.")));
     return;
   }
 }
@@ -685,8 +351,12 @@
       metadata_.object_stores[object_store_id];
 
   transaction->ScheduleTask(
-      new DeleteObjectStoreOperation(backing_store_, object_store_metadata),
-      new DeleteObjectStoreAbortOperation(this, object_store_metadata));
+      base::Bind(&IndexedDBDatabase::DeleteObjectStoreOperation,
+                 this,
+                 object_store_metadata),
+      base::Bind(&IndexedDBDatabase::DeleteObjectStoreAbortOperation,
+                 this,
+                 object_store_metadata));
   RemoveObjectStore(object_store_id);
 }
 
@@ -709,34 +379,46 @@
       name, index_id, key_path, unique, multi_entry);
 
   transaction->ScheduleTask(
-      new CreateIndexOperation(backing_store_, object_store_id, index_metadata),
-      new CreateIndexAbortOperation(this, object_store_id, index_id));
+      base::Bind(&IndexedDBDatabase::CreateIndexOperation,
+                 this,
+                 object_store_id,
+                 index_metadata),
+      base::Bind(&IndexedDBDatabase::CreateIndexAbortOperation,
+                 this,
+                 object_store_id,
+                 index_id));
 
   AddIndex(object_store_id, index_metadata, index_id);
 }
 
-void CreateIndexOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("CreateIndexOperation");
+void IndexedDBDatabase::CreateIndexOperation(
+    int64 object_store_id,
+    const IndexedDBIndexMetadata& index_metadata,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::CreateIndexOperation");
   if (!backing_store_->CreateIndex(transaction->BackingStoreTransaction(),
                                    transaction->database()->id(),
-                                   object_store_id_,
-                                   index_metadata_.id,
-                                   index_metadata_.name,
-                                   index_metadata_.key_path,
-                                   index_metadata_.unique,
-                                   index_metadata_.multi_entry)) {
+                                   object_store_id,
+                                   index_metadata.id,
+                                   index_metadata.name,
+                                   index_metadata.key_path,
+                                   index_metadata.unique,
+                                   index_metadata.multi_entry)) {
     string16 error_string = ASCIIToUTF16("Internal error creating index '") +
-                            index_metadata_.name + ASCIIToUTF16("'.");
+                            index_metadata.name + ASCIIToUTF16("'.");
     transaction->Abort(IndexedDBDatabaseError(
         WebKit::WebIDBDatabaseExceptionUnknownError, error_string));
     return;
   }
 }
 
-void CreateIndexAbortOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("CreateIndexAbortOperation");
+void IndexedDBDatabase::CreateIndexAbortOperation(
+    int64 object_store_id,
+    int64 index_id,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::CreateIndexAbortOperation");
   DCHECK(!transaction);
-  database_->RemoveIndex(object_store_id_, index_id_);
+  RemoveIndex(object_store_id, index_id);
 }
 
 void IndexedDBDatabase::DeleteIndex(int64 transaction_id,
@@ -754,31 +436,42 @@
       metadata_.object_stores[object_store_id].indexes[index_id];
 
   transaction->ScheduleTask(
-      new DeleteIndexOperation(backing_store_, object_store_id, index_metadata),
-      new DeleteIndexAbortOperation(this, object_store_id, index_metadata));
+      base::Bind(&IndexedDBDatabase::DeleteIndexOperation,
+                 this,
+                 object_store_id,
+                 index_metadata),
+      base::Bind(&IndexedDBDatabase::DeleteIndexAbortOperation,
+                 this,
+                 object_store_id,
+                 index_metadata));
 
   RemoveIndex(object_store_id, index_id);
 }
 
-void DeleteIndexOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("DeleteIndexOperation");
+void IndexedDBDatabase::DeleteIndexOperation(
+    int64 object_store_id,
+    const IndexedDBIndexMetadata& index_metadata,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::DeleteIndexOperation");
   bool ok = backing_store_->DeleteIndex(transaction->BackingStoreTransaction(),
                                         transaction->database()->id(),
-                                        object_store_id_,
-                                        index_metadata_.id);
+                                        object_store_id,
+                                        index_metadata.id);
   if (!ok) {
     string16 error_string = ASCIIToUTF16("Internal error deleting index '") +
-                            index_metadata_.name + ASCIIToUTF16("'.");
+                            index_metadata.name + ASCIIToUTF16("'.");
     transaction->Abort(IndexedDBDatabaseError(
         WebKit::WebIDBDatabaseExceptionUnknownError, error_string));
   }
 }
 
-void DeleteIndexAbortOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("DeleteIndexAbortOperation");
+void IndexedDBDatabase::DeleteIndexAbortOperation(
+    int64 object_store_id,
+    const IndexedDBIndexMetadata& index_metadata,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::DeleteIndexAbortOperation");
   DCHECK(!transaction);
-  database_->AddIndex(
-      object_store_id_, index_metadata_, IndexedDBIndexMetadata::kInvalidId);
+  AddIndex(object_store_id, index_metadata, IndexedDBIndexMetadata::kInvalidId);
 }
 
 void IndexedDBDatabase::Commit(int64 transaction_id) {
@@ -821,61 +514,68 @@
 
   if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
     return;
-  const IndexedDBObjectStoreMetadata& object_store_metadata =
-      metadata_.object_stores[object_store_id];
 
-  transaction->ScheduleTask(new GetOperation(
-      backing_store_,
-      metadata_.id,
+  transaction->ScheduleTask(base::Bind(
+      &IndexedDBDatabase::GetOperation,
+      this,
       object_store_id,
       index_id,
-      object_store_metadata.key_path,
-      object_store_metadata.auto_increment,
-      key_range.Pass(),
+      Passed(&key_range),
       key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
       callbacks));
 }
 
-void GetOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("GetOperation");
+void IndexedDBDatabase::GetOperation(
+    int64 object_store_id,
+    int64 index_id,
+    scoped_ptr<IndexedDBKeyRange> key_range,
+    indexed_db::CursorType cursor_type,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::GetOperation");
+
+  DCHECK(metadata_.object_stores.find(object_store_id) !=
+         metadata_.object_stores.end());
+  const IndexedDBObjectStoreMetadata& object_store_metadata =
+      metadata_.object_stores[object_store_id];
 
   const IndexedDBKey* key;
 
   scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
-  if (key_range_->IsOnlyKey()) {
-    key = &key_range_->lower();
+  if (key_range->IsOnlyKey()) {
+    key = &key_range->lower();
   } else {
-    if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
-      DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY);
+    if (index_id == IndexedDBIndexMetadata::kInvalidId) {
+      DCHECK_NE(cursor_type, indexed_db::CURSOR_KEY_ONLY);
       // ObjectStore Retrieval Operation
       backing_store_cursor = backing_store_->OpenObjectStoreCursor(
           transaction->BackingStoreTransaction(),
-          database_id_,
-          object_store_id_,
-          *key_range_,
+          id(),
+          object_store_id,
+          *key_range,
           indexed_db::CURSOR_NEXT);
-    } else if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) {
+    } else if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
       // Index Value Retrieval Operation
       backing_store_cursor = backing_store_->OpenIndexKeyCursor(
           transaction->BackingStoreTransaction(),
-          database_id_,
-          object_store_id_,
-          index_id_,
-          *key_range_,
+          id(),
+          object_store_id,
+          index_id,
+          *key_range,
           indexed_db::CURSOR_NEXT);
     } else {
       // Index Referenced Value Retrieval Operation
       backing_store_cursor = backing_store_->OpenIndexCursor(
           transaction->BackingStoreTransaction(),
-          database_id_,
-          object_store_id_,
-          index_id_,
-          *key_range_,
+          id(),
+          object_store_id,
+          index_id,
+          *key_range,
           indexed_db::CURSOR_NEXT);
     }
 
     if (!backing_store_cursor) {
-      callbacks_->OnSuccess();
+      callbacks->OnSuccess();
       return;
     }
 
@@ -884,82 +584,84 @@
 
   scoped_ptr<IndexedDBKey> primary_key;
   bool ok;
-  if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
+  if (index_id == IndexedDBIndexMetadata::kInvalidId) {
     // Object Store Retrieval Operation
     std::string value;
     ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
-                                   database_id_,
-                                   object_store_id_,
+                                   id(),
+                                   object_store_id,
                                    *key,
                                    &value);
     if (!ok) {
-      callbacks_->OnError(
+      callbacks->OnError(
           IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                  "Internal error in GetRecord."));
       return;
     }
 
     if (value.empty()) {
-      callbacks_->OnSuccess();
+      callbacks->OnSuccess();
       return;
     }
 
-    if (auto_increment_ && !key_path_.IsNull()) {
-      callbacks_->OnSuccess(&value, *key, key_path_);
+    if (object_store_metadata.auto_increment &&
+        !object_store_metadata.key_path.IsNull()) {
+      callbacks->OnSuccess(&value, *key, object_store_metadata.key_path);
       return;
     }
 
-    callbacks_->OnSuccess(&value);
+    callbacks->OnSuccess(&value);
     return;
   }
 
   // From here we are dealing only with indexes.
   ok = backing_store_->GetPrimaryKeyViaIndex(
       transaction->BackingStoreTransaction(),
-      database_id_,
-      object_store_id_,
-      index_id_,
+      id(),
+      object_store_id,
+      index_id,
       *key,
       &primary_key);
   if (!ok) {
-    callbacks_->OnError(
+    callbacks->OnError(
         IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                "Internal error in GetPrimaryKeyViaIndex."));
     return;
   }
   if (!primary_key) {
-    callbacks_->OnSuccess();
+    callbacks->OnSuccess();
     return;
   }
-  if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) {
+  if (cursor_type == indexed_db::CURSOR_KEY_ONLY) {
     // Index Value Retrieval Operation
-    callbacks_->OnSuccess(*primary_key);
+    callbacks->OnSuccess(*primary_key);
     return;
   }
 
   // Index Referenced Value Retrieval Operation
   std::string value;
   ok = backing_store_->GetRecord(transaction->BackingStoreTransaction(),
-                                 database_id_,
-                                 object_store_id_,
+                                 id(),
+                                 object_store_id,
                                  *primary_key,
                                  &value);
   if (!ok) {
-    callbacks_->OnError(
+    callbacks->OnError(
         IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                "Internal error in GetRecord."));
     return;
   }
 
   if (value.empty()) {
-    callbacks_->OnSuccess();
+    callbacks->OnSuccess();
     return;
   }
-  if (auto_increment_ && !key_path_.IsNull()) {
-    callbacks_->OnSuccess(&value, *primary_key, key_path_);
+  if (object_store_metadata.auto_increment &&
+      !object_store_metadata.key_path.IsNull()) {
+    callbacks->OnSuccess(&value, *primary_key, object_store_metadata.key_path);
     return;
   }
-  callbacks_->OnSuccess(&value);
+  callbacks->OnSuccess(&value);
 }
 
 static scoped_ptr<IndexedDBKey> GenerateKey(
@@ -982,8 +684,7 @@
   if (current_number < 0 || current_number > max_generator_value)
     return make_scoped_ptr(new IndexedDBKey());
 
-  return make_scoped_ptr(
-      new IndexedDBKey(current_number, WebIDBKeyTypeNumber));
+  return make_scoped_ptr(new IndexedDBKey(current_number, WebIDBKeyTypeNumber));
 }
 
 static bool UpdateKeyGenerator(
@@ -991,18 +692,30 @@
     scoped_refptr<IndexedDBTransaction> transaction,
     int64 database_id,
     int64 object_store_id,
-    const IndexedDBKey* key,
+    const IndexedDBKey& key,
     bool check_current) {
-  DCHECK(key);
-  DCHECK_EQ(WebIDBKeyTypeNumber, key->type());
+  DCHECK_EQ(WebIDBKeyTypeNumber, key.type());
   return backing_store->MaybeUpdateKeyGeneratorCurrentNumber(
       transaction->BackingStoreTransaction(),
       database_id,
       object_store_id,
-      static_cast<int64>(floor(key->number())) + 1,
+      static_cast<int64>(floor(key.number())) + 1,
       check_current);
 }
 
+struct IndexedDBDatabase::PutOperationParams {
+  PutOperationParams() {}
+  int64 object_store_id;
+  std::string value;
+  scoped_ptr<IndexedDBKey> key;
+  IndexedDBDatabase::PutMode put_mode;
+  scoped_refptr<IndexedDBCallbacks> callbacks;
+  std::vector<int64> index_ids;
+  std::vector<IndexKeys> index_keys;
+
+  DISALLOW_COPY_AND_ASSIGN(PutOperationParams);
+};
+
 void IndexedDBDatabase::Put(int64 transaction_id,
                             int64 object_store_id,
                             std::string* value,
@@ -1019,65 +732,70 @@
 
   if (!ValidateObjectStoreId(object_store_id))
     return;
-  const IndexedDBObjectStoreMetadata& object_store_metadata =
-      metadata_.object_stores[object_store_id];
 
   DCHECK(key);
-  DCHECK(object_store_metadata.auto_increment || key->IsValid());
-  transaction->ScheduleTask(new PutOperation(backing_store_,
-                                             id(),
-                                             object_store_metadata,
-                                             value,
-                                             key.Pass(),
-                                             put_mode,
-                                             callbacks,
-                                             index_ids,
-                                             index_keys));
+  scoped_ptr<PutOperationParams> params(new PutOperationParams());
+  params->object_store_id = object_store_id;
+  params->value.swap(*value);
+  params->key = key.Pass();
+  params->put_mode = put_mode;
+  params->callbacks = callbacks;
+  params->index_ids = index_ids;
+  params->index_keys = index_keys;
+  transaction->ScheduleTask(base::Bind(
+      &IndexedDBDatabase::PutOperation, this, base::Passed(&params)));
 }
 
-void PutOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("PutOperation");
+void IndexedDBDatabase::PutOperation(scoped_ptr<PutOperationParams> params,
+                                     IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::PutOperation");
   DCHECK_NE(transaction->mode(), indexed_db::TRANSACTION_READ_ONLY);
-  DCHECK_EQ(index_ids_.size(), index_keys_.size());
+  DCHECK_EQ(params->index_ids.size(), params->index_keys.size());
   bool key_was_generated = false;
 
+  DCHECK(metadata_.object_stores.find(params->object_store_id) !=
+         metadata_.object_stores.end());
+  const IndexedDBObjectStoreMetadata& object_store =
+      metadata_.object_stores[params->object_store_id];
+  DCHECK(object_store.auto_increment || params->key->IsValid());
+
   scoped_ptr<IndexedDBKey> key;
-  if (put_mode_ != IndexedDBDatabase::CURSOR_UPDATE &&
-      object_store_.auto_increment && !key_->IsValid()) {
-    scoped_ptr<IndexedDBKey> auto_inc_key = GenerateKey(
-        backing_store_, transaction, database_id_, object_store_.id);
+  if (params->put_mode != IndexedDBDatabase::CURSOR_UPDATE &&
+      object_store.auto_increment && !params->key->IsValid()) {
+    scoped_ptr<IndexedDBKey> auto_inc_key =
+        GenerateKey(backing_store_, transaction, id(), params->object_store_id);
     key_was_generated = true;
     if (!auto_inc_key->IsValid()) {
-      callbacks_->OnError(
+      params->callbacks->OnError(
           IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionConstraintError,
                                  "Maximum key generator value reached."));
       return;
     }
     key = auto_inc_key.Pass();
   } else {
-    key = key_.Pass();
+    key = params->key.Pass();
   }
 
   DCHECK(key->IsValid());
 
   IndexedDBBackingStore::RecordIdentifier record_identifier;
-  if (put_mode_ == IndexedDBDatabase::ADD_ONLY) {
+  if (params->put_mode == IndexedDBDatabase::ADD_ONLY) {
     bool found = false;
     bool ok = backing_store_->KeyExistsInObjectStore(
         transaction->BackingStoreTransaction(),
-        database_id_,
-        object_store_.id,
-        *key.get(),
+        id(),
+        params->object_store_id,
+        *key,
         &record_identifier,
         &found);
     if (!ok) {
-      callbacks_->OnError(
+      params->callbacks->OnError(
           IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                  "Internal error checking key existence."));
       return;
     }
     if (found) {
-      callbacks_->OnError(
+      params->callbacks->OnError(
           IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionConstraintError,
                                  "Key already exists in the object store."));
       return;
@@ -1088,24 +806,24 @@
   string16 error_message;
   bool obeys_constraints = false;
   bool backing_store_success = MakeIndexWriters(transaction,
-                                                backing_store_,
-                                                database_id_,
-                                                object_store_,
+                                                backing_store_.get(),
+                                                id(),
+                                                object_store,
                                                 *key,
                                                 key_was_generated,
-                                                index_ids_,
-                                                index_keys_,
+                                                params->index_ids,
+                                                params->index_keys,
                                                 &index_writers,
                                                 &error_message,
                                                 &obeys_constraints);
   if (!backing_store_success) {
-    callbacks_->OnError(IndexedDBDatabaseError(
+    params->callbacks->OnError(IndexedDBDatabaseError(
         WebKit::WebIDBDatabaseExceptionUnknownError,
         "Internal error: backing store error updating index keys."));
     return;
   }
   if (!obeys_constraints) {
-    callbacks_->OnError(IndexedDBDatabaseError(
+    params->callbacks->OnError(IndexedDBDatabaseError(
         WebKit::WebIDBDatabaseExceptionConstraintError, error_message));
     return;
   }
@@ -1114,13 +832,13 @@
   // transaction in case of error.
   backing_store_success =
       backing_store_->PutRecord(transaction->BackingStoreTransaction(),
-                                database_id_,
-                                object_store_.id,
-                                *key.get(),
-                                value_,
+                                id(),
+                                params->object_store_id,
+                                *key,
+                                params->value,
                                 &record_identifier);
   if (!backing_store_success) {
-    callbacks_->OnError(IndexedDBDatabaseError(
+    params->callbacks->OnError(IndexedDBDatabaseError(
         WebKit::WebIDBDatabaseExceptionUnknownError,
         "Internal error: backing store error performing put/add."));
     return;
@@ -1129,30 +847,30 @@
   for (size_t i = 0; i < index_writers.size(); ++i) {
     IndexWriter* index_writer = index_writers[i];
     index_writer->WriteIndexKeys(record_identifier,
-                                 backing_store_,
+                                 backing_store_.get(),
                                  transaction->BackingStoreTransaction(),
-                                 database_id_,
-                                 object_store_.id);
+                                 id(),
+                                 params->object_store_id);
   }
 
-  if (object_store_.auto_increment &&
-      put_mode_ != IndexedDBDatabase::CURSOR_UPDATE &&
+  if (object_store.auto_increment &&
+      params->put_mode != IndexedDBDatabase::CURSOR_UPDATE &&
       key->type() == WebIDBKeyTypeNumber) {
     bool ok = UpdateKeyGenerator(backing_store_,
                                  transaction,
-                                 database_id_,
-                                 object_store_.id,
-                                 key.get(),
+                                 id(),
+                                 params->object_store_id,
+                                 *key,
                                  !key_was_generated);
     if (!ok) {
-      callbacks_->OnError(
+      params->callbacks->OnError(
           IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                  "Internal error updating key generator."));
       return;
     }
   }
 
-  callbacks_->OnSuccess(*key);
+  params->callbacks->OnSuccess(*key);
 }
 
 void IndexedDBDatabase::SetIndexKeys(int64 transaction_id,
@@ -1240,16 +958,34 @@
     return;
   DCHECK_EQ(transaction->mode(), indexed_db::TRANSACTION_VERSION_CHANGE);
 
-  transaction->ScheduleTask(IndexedDBDatabase::PREEMPTIVE_TASK,
-                            new SetIndexesReadyOperation(index_ids.size()));
+  transaction->ScheduleTask(
+      IndexedDBDatabase::PREEMPTIVE_TASK,
+      base::Bind(&IndexedDBDatabase::SetIndexesReadyOperation,
+                 this,
+                 index_ids.size()));
 }
 
-void SetIndexesReadyOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("SetIndexesReadyOperation");
-  for (size_t i = 0; i < index_count_; ++i)
+void IndexedDBDatabase::SetIndexesReadyOperation(
+    size_t index_count,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::SetIndexesReadyOperation");
+  for (size_t i = 0; i < index_count; ++i)
     transaction->DidCompletePreemptiveEvent();
 }
 
+struct IndexedDBDatabase::OpenCursorOperationParams {
+  OpenCursorOperationParams() {}
+  int64 object_store_id;
+  int64 index_id;
+  scoped_ptr<IndexedDBKeyRange> key_range;
+  indexed_db::CursorDirection direction;
+  indexed_db::CursorType cursor_type;
+  IndexedDBDatabase::TaskType task_type;
+  scoped_refptr<IndexedDBCallbacks> callbacks;
+
+  DISALLOW_COPY_AND_ASSIGN(OpenCursorOperationParams);
+};
+
 void IndexedDBDatabase::OpenCursor(
     int64 transaction_id,
     int64 object_store_id,
@@ -1267,66 +1003,72 @@
   if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
     return;
 
-  transaction->ScheduleTask(new OpenCursorOperation(
-      backing_store_,
-      id(),
-      object_store_id,
-      index_id,
-      key_range.Pass(),
-      direction,
-      key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE,
-      task_type,
-      callbacks));
+  scoped_ptr<OpenCursorOperationParams> params(new OpenCursorOperationParams());
+  params->object_store_id = object_store_id;
+  params->index_id = index_id;
+  params->key_range = key_range.Pass();
+  params->direction = direction;
+  params->cursor_type =
+      key_only ? indexed_db::CURSOR_KEY_ONLY : indexed_db::CURSOR_KEY_AND_VALUE;
+  params->task_type = task_type;
+  params->callbacks = callbacks;
+  transaction->ScheduleTask(base::Bind(
+      &IndexedDBDatabase::OpenCursorOperation, this, base::Passed(&params)));
 }
 
-void OpenCursorOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("OpenCursorOperation");
+void IndexedDBDatabase::OpenCursorOperation(
+    scoped_ptr<OpenCursorOperationParams> params,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::OpenCursorOperation");
 
   // The frontend has begun indexing, so this pauses the transaction
   // until the indexing is complete. This can't happen any earlier
   // because we don't want to switch to early mode in case multiple
   // indexes are being created in a row, with Put()'s in between.
-  if (task_type_ == IndexedDBDatabase::PREEMPTIVE_TASK)
+  if (params->task_type == IndexedDBDatabase::PREEMPTIVE_TASK)
     transaction->AddPreemptiveEvent();
 
   scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
-  if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
-    DCHECK_NE(cursor_type_, indexed_db::CURSOR_KEY_ONLY);
+  if (params->index_id == IndexedDBIndexMetadata::kInvalidId) {
+    DCHECK_NE(params->cursor_type, indexed_db::CURSOR_KEY_ONLY);
     backing_store_cursor = backing_store_->OpenObjectStoreCursor(
         transaction->BackingStoreTransaction(),
-        database_id_,
-        object_store_id_,
-        *key_range_,
-        direction_);
+        id(),
+        params->object_store_id,
+        *params->key_range,
+        params->direction);
   } else {
-    DCHECK_EQ(task_type_, IndexedDBDatabase::NORMAL_TASK);
-    if (cursor_type_ == indexed_db::CURSOR_KEY_ONLY) {
+    DCHECK_EQ(params->task_type, IndexedDBDatabase::NORMAL_TASK);
+    if (params->cursor_type == indexed_db::CURSOR_KEY_ONLY) {
       backing_store_cursor = backing_store_->OpenIndexKeyCursor(
           transaction->BackingStoreTransaction(),
-          database_id_,
-          object_store_id_,
-          index_id_,
-          *key_range_,
-          direction_);
+          id(),
+          params->object_store_id,
+          params->index_id,
+          *params->key_range,
+          params->direction);
     } else {
       backing_store_cursor = backing_store_->OpenIndexCursor(
           transaction->BackingStoreTransaction(),
-          database_id_,
-          object_store_id_,
-          index_id_,
-          *key_range_,
-          direction_);
+          id(),
+          params->object_store_id,
+          params->index_id,
+          *params->key_range,
+          params->direction);
     }
   }
 
   if (!backing_store_cursor) {
-    callbacks_->OnSuccess(static_cast<std::string*>(NULL));
+    params->callbacks->OnSuccess(static_cast<std::string*>(NULL));
     return;
   }
 
-  scoped_refptr<IndexedDBCursor> cursor = new IndexedDBCursor(
-      backing_store_cursor.Pass(), cursor_type_, task_type_, transaction);
-  callbacks_->OnSuccess(
+  scoped_refptr<IndexedDBCursor> cursor =
+      new IndexedDBCursor(backing_store_cursor.Pass(),
+                          params->cursor_type,
+                          params->task_type,
+                          transaction);
+  params->callbacks->OnSuccess(
       cursor, cursor->key(), cursor->primary_key(), cursor->Value());
 }
 
@@ -1343,37 +1085,42 @@
   if (!ValidateObjectStoreIdAndOptionalIndexId(object_store_id, index_id))
     return;
 
-  transaction->ScheduleTask(new CountOperation(backing_store_,
-                                               id(),
-                                               object_store_id,
-                                               index_id,
-                                               key_range.Pass(),
-                                               callbacks));
+  transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::CountOperation,
+                                       this,
+                                       object_store_id,
+                                       index_id,
+                                       base::Passed(&key_range),
+                                       callbacks));
 }
 
-void CountOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("CountOperation");
+void IndexedDBDatabase::CountOperation(
+    int64 object_store_id,
+    int64 index_id,
+    scoped_ptr<IndexedDBKeyRange> key_range,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::CountOperation");
   uint32 count = 0;
   scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor;
 
-  if (index_id_ == IndexedDBIndexMetadata::kInvalidId) {
+  if (index_id == IndexedDBIndexMetadata::kInvalidId) {
     backing_store_cursor = backing_store_->OpenObjectStoreKeyCursor(
         transaction->BackingStoreTransaction(),
-        database_id_,
-        object_store_id_,
-        *key_range_,
+        id(),
+        object_store_id,
+        *key_range,
         indexed_db::CURSOR_NEXT);
   } else {
     backing_store_cursor = backing_store_->OpenIndexKeyCursor(
         transaction->BackingStoreTransaction(),
-        database_id_,
-        object_store_id_,
-        index_id_,
-        *key_range_,
+        id(),
+        object_store_id,
+        index_id,
+        *key_range,
         indexed_db::CURSOR_NEXT);
   }
   if (!backing_store_cursor) {
-    callbacks_->OnSuccess(count);
+    callbacks->OnSuccess(count);
     return;
   }
 
@@ -1381,7 +1128,7 @@
     ++count;
   } while (backing_store_cursor->Continue());
 
-  callbacks_->OnSuccess(count);
+  callbacks->OnSuccess(count);
 }
 
 void IndexedDBDatabase::DeleteRange(
@@ -1398,27 +1145,34 @@
   if (!ValidateObjectStoreId(object_store_id))
     return;
 
-  transaction->ScheduleTask(new DeleteRangeOperation(
-      backing_store_, id(), object_store_id, key_range.Pass(), callbacks));
+  transaction->ScheduleTask(base::Bind(&IndexedDBDatabase::DeleteRangeOperation,
+                                       this,
+                                       object_store_id,
+                                       base::Passed(&key_range),
+                                       callbacks));
 }
 
-void DeleteRangeOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("DeleteRangeOperation");
+void IndexedDBDatabase::DeleteRangeOperation(
+    int64 object_store_id,
+    scoped_ptr<IndexedDBKeyRange> key_range,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::DeleteRangeOperation");
   scoped_ptr<IndexedDBBackingStore::Cursor> backing_store_cursor =
       backing_store_->OpenObjectStoreCursor(
           transaction->BackingStoreTransaction(),
-          database_id_,
-          object_store_id_,
-          *key_range_,
+          id(),
+          object_store_id,
+          *key_range,
           indexed_db::CURSOR_NEXT);
   if (backing_store_cursor) {
     do {
       if (!backing_store_->DeleteRecord(
               transaction->BackingStoreTransaction(),
-              database_id_,
-              object_store_id_,
+              id(),
+              object_store_id,
               backing_store_cursor->record_identifier())) {
-        callbacks_->OnError(
+        callbacks->OnError(
             IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                    "Internal error deleting data in range"));
         return;
@@ -1426,7 +1180,7 @@
     } while (backing_store_cursor->Continue());
   }
 
-  callbacks_->OnSuccess();
+  callbacks->OnSuccess();
 }
 
 void IndexedDBDatabase::Clear(int64 transaction_id,
@@ -1441,64 +1195,70 @@
   if (!ValidateObjectStoreId(object_store_id))
     return;
 
-  transaction->ScheduleTask(
-      new ClearOperation(backing_store_, id(), object_store_id, callbacks));
+  transaction->ScheduleTask(base::Bind(
+      &IndexedDBDatabase::ClearOperation, this, object_store_id, callbacks));
 }
 
-void ClearOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("ObjectStoreClearOperation");
-  if (!backing_store_->ClearObjectStore(transaction->BackingStoreTransaction(),
-                                        database_id_,
-                                        object_store_id_)) {
-    callbacks_->OnError(
+void IndexedDBDatabase::ClearOperation(
+    int64 object_store_id,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::ObjectStoreClearOperation");
+  if (!backing_store_->ClearObjectStore(
+          transaction->BackingStoreTransaction(), id(), object_store_id)) {
+    callbacks->OnError(
         IndexedDBDatabaseError(WebKit::WebIDBDatabaseExceptionUnknownError,
                                "Internal error clearing object store"));
     return;
   }
-  callbacks_->OnSuccess();
+  callbacks->OnSuccess();
 }
 
-void DeleteObjectStoreOperation::Perform(IndexedDBTransaction* transaction) {
-  IDB_TRACE("DeleteObjectStoreOperation");
+void IndexedDBDatabase::DeleteObjectStoreOperation(
+    const IndexedDBObjectStoreMetadata& object_store_metadata,
+    IndexedDBTransaction* transaction) {
+  IDB_TRACE("IndexedDBDatabase::DeleteObjectStoreOperation");
   bool ok =
       backing_store_->DeleteObjectStore(transaction->BackingStoreTransaction(),
                                         transaction->database()->id(),
-                                        object_store_metadata_.id);
+                                        object_store_metadata.id);
   if (!ok) {
     string16 error_string =
         ASCIIToUTF16("Internal error deleting object store '") +
-        object_store_metadata_.name + ASCIIToUTF16("'.");
+        object_store_metadata.name + ASCIIToUTF16("'.");
     transaction->Abort(IndexedDBDatabaseError(
         WebKit::WebIDBDatabaseExceptionUnknownError, error_string));
   }
 }
 
-void IndexedDBDatabase::VersionChangeOperation::Perform(
+void IndexedDBDatabase::VersionChangeOperation(
+    int64 version,
+    scoped_refptr<IndexedDBCallbacks> callbacks,
+    scoped_ptr<IndexedDBConnection> connection,
+    WebKit::WebIDBCallbacks::DataLoss data_loss,
     IndexedDBTransaction* transaction) {
-  IDB_TRACE("VersionChangeOperation");
-  int64 database_id = database_->id();
-  int64 old_version = database_->metadata_.int_version;
-  DCHECK_GT(version_, old_version);
-  database_->metadata_.int_version = version_;
-  if (!database_->backing_store_->UpdateIDBDatabaseIntVersion(
+  IDB_TRACE("IndexedDBDatabase::VersionChangeOperation");
+  int64 old_version = metadata_.int_version;
+  DCHECK_GT(version, old_version);
+  metadata_.int_version = version;
+  if (!backing_store_->UpdateIDBDatabaseIntVersion(
           transaction->BackingStoreTransaction(),
-          database_id,
-          database_->metadata_.int_version)) {
+          id(),
+          metadata_.int_version)) {
     IndexedDBDatabaseError error(
         WebKit::WebIDBDatabaseExceptionUnknownError,
         ASCIIToUTF16(
             "Internal error writing data to stable storage when "
             "updating version."));
-    callbacks_->OnError(error);
+    callbacks->OnError(error);
     transaction->Abort(error);
     return;
   }
-  DCHECK(!database_->pending_second_half_open_);
-
-  database_->pending_second_half_open_.reset(new PendingSuccessCall(
-      callbacks_, connection_.get(), transaction_id_, version_));
-  callbacks_->OnUpgradeNeeded(
-      old_version, connection_.Pass(), database_->metadata(), data_loss_);
+  DCHECK(!pending_second_half_open_);
+  pending_second_half_open_.reset(new PendingSuccessCall(
+      callbacks, connection.get(), transaction->id(), version));
+  callbacks->OnUpgradeNeeded(
+      old_version, connection.Pass(), metadata(), data_loss);
 }
 
 void IndexedDBDatabase::TransactionStarted(IndexedDBTransaction* transaction) {
@@ -1545,8 +1305,8 @@
       // Connection was already minted for OnUpgradeNeeded callback.
       scoped_ptr<IndexedDBConnection> connection;
 
-      pending_second_half_open_->Callbacks()->OnSuccess(
-          connection.Pass(), this->metadata());
+      pending_second_half_open_->Callbacks()->OnSuccess(connection.Pass(),
+                                                        this->metadata());
       pending_second_half_open_.reset();
     }
     ProcessPendingCalls();
@@ -1765,8 +1525,8 @@
          it != connections_.end();
          ++it) {
       if (*it != connection.get()) {
-        (*it)->callbacks()->OnVersionChange(
-            metadata_.int_version, requested_version);
+        (*it)->callbacks()->OnVersionChange(metadata_.int_version,
+                                            requested_version);
       }
     }
     // TODO(jsbell): Remove the call to OnBlocked and instead wait
@@ -1816,14 +1576,16 @@
       transactions_[transaction_id];
 
   transaction->ScheduleTask(
-      new VersionChangeOperation(this,
-                                 transaction_id,
-                                 requested_version,
-                                 callbacks,
-                                 connection.Pass(),
-                                 data_loss),
-      new VersionChangeAbortOperation(
-          this, metadata_.version, metadata_.int_version));
+      base::Bind(&IndexedDBDatabase::VersionChangeOperation,
+                 this,
+                 requested_version,
+                 callbacks,
+                 base::Passed(&connection),
+                 data_loss),
+      base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation,
+                 this,
+                 metadata_.version,
+                 metadata_.int_version));
 
   DCHECK(!pending_second_half_open_);
 }
@@ -1925,27 +1687,31 @@
   }
 }
 
-void CreateObjectStoreAbortOperation::Perform(
+void IndexedDBDatabase::CreateObjectStoreAbortOperation(
+    int64 object_store_id,
     IndexedDBTransaction* transaction) {
-  IDB_TRACE("CreateObjectStoreAbortOperation");
+  IDB_TRACE("IndexedDBDatabase::CreateObjectStoreAbortOperation");
   DCHECK(!transaction);
-  database_->RemoveObjectStore(object_store_id_);
+  RemoveObjectStore(object_store_id);
 }
 
-void DeleteObjectStoreAbortOperation::Perform(
+void IndexedDBDatabase::DeleteObjectStoreAbortOperation(
+    const IndexedDBObjectStoreMetadata& object_store_metadata,
     IndexedDBTransaction* transaction) {
-  IDB_TRACE("DeleteObjectStoreAbortOperation");
+  IDB_TRACE("IndexedDBDatabase::DeleteObjectStoreAbortOperation");
   DCHECK(!transaction);
-  database_->AddObjectStore(object_store_metadata_,
-                            IndexedDBObjectStoreMetadata::kInvalidId);
+  AddObjectStore(object_store_metadata,
+                 IndexedDBObjectStoreMetadata::kInvalidId);
 }
 
-void IndexedDBDatabase::VersionChangeAbortOperation::Perform(
+void IndexedDBDatabase::VersionChangeAbortOperation(
+    const string16& previous_version,
+    int64 previous_int_version,
     IndexedDBTransaction* transaction) {
-  IDB_TRACE("VersionChangeAbortOperation");
+  IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation");
   DCHECK(!transaction);
-  database_->metadata_.version = previous_version_;
-  database_->metadata_.int_version = previous_int_version_;
+  metadata_.version = previous_version;
+  metadata_.int_version = previous_int_version;
 }
 
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_database.h b/content/browser/indexed_db/indexed_db_database.h
index 9c617f5..7bfa61c 100644
--- a/content/browser/indexed_db/indexed_db_database.h
+++ b/content/browser/indexed_db/indexed_db_database.h
@@ -173,14 +173,72 @@
   // Number of pending deletes, blocked on other connections.
   size_t PendingDeleteCount() const;
 
+  // Asynchronous tasks scheduled within transactions:
+  void CreateObjectStoreOperation(
+      const IndexedDBObjectStoreMetadata& object_store_metadata,
+      IndexedDBTransaction* transaction);
+  void CreateObjectStoreAbortOperation(int64 object_store_id,
+                                       IndexedDBTransaction* transaction);
+  void DeleteObjectStoreOperation(
+      const IndexedDBObjectStoreMetadata& object_store_metadata,
+      IndexedDBTransaction* transaction);
+  void DeleteObjectStoreAbortOperation(
+      const IndexedDBObjectStoreMetadata& object_store_metadata,
+      IndexedDBTransaction* transaction);
+  void VersionChangeOperation(int64 version,
+                              scoped_refptr<IndexedDBCallbacks> callbacks,
+                              scoped_ptr<IndexedDBConnection> connection,
+                              WebKit::WebIDBCallbacks::DataLoss data_loss,
+                              IndexedDBTransaction* transaction);
+  void VersionChangeAbortOperation(const string16& previous_version,
+                                   int64 previous_int_version,
+                                   IndexedDBTransaction* transaction);
+  void CreateIndexOperation(int64 object_store_id,
+                            const IndexedDBIndexMetadata& index_metadata,
+                            IndexedDBTransaction* transaction);
+  void DeleteIndexOperation(int64 object_store_id,
+                            const IndexedDBIndexMetadata& index_metadata,
+                            IndexedDBTransaction* transaction);
+  void CreateIndexAbortOperation(int64 object_store_id,
+                                 int64 index_id,
+                                 IndexedDBTransaction* transaction);
+  void DeleteIndexAbortOperation(int64 object_store_id,
+                                 const IndexedDBIndexMetadata& index_metadata,
+                                 IndexedDBTransaction* transaction);
+  void GetOperation(int64 object_store_id,
+                    int64 index_id,
+                    scoped_ptr<IndexedDBKeyRange> key_range,
+                    indexed_db::CursorType cursor_type,
+                    scoped_refptr<IndexedDBCallbacks> callbacks,
+                    IndexedDBTransaction* transaction);
+  struct PutOperationParams;
+  void PutOperation(scoped_ptr<PutOperationParams> params,
+                    IndexedDBTransaction* transaction);
+  void SetIndexesReadyOperation(size_t index_count,
+                                IndexedDBTransaction* transaction);
+  struct OpenCursorOperationParams;
+  void OpenCursorOperation(scoped_ptr<OpenCursorOperationParams> params,
+                           IndexedDBTransaction* transaction);
+  void CountOperation(int64 object_store_id,
+                      int64 index_id,
+                      scoped_ptr<IndexedDBKeyRange> key_range,
+                      scoped_refptr<IndexedDBCallbacks> callbacks,
+                      IndexedDBTransaction* transaction);
+  void DeleteRangeOperation(int64 object_store_id,
+                            scoped_ptr<IndexedDBKeyRange> key_range,
+                            scoped_refptr<IndexedDBCallbacks> callbacks,
+                            IndexedDBTransaction* transaction);
+  void ClearOperation(int64 object_store_id,
+                      scoped_refptr<IndexedDBCallbacks> callbacks,
+                      IndexedDBTransaction* transaction);
+
  private:
   friend class base::RefCounted<IndexedDBDatabase>;
 
-  IndexedDBDatabase(
-      const string16& name,
-      IndexedDBBackingStore* database,
-      IndexedDBFactory* factory,
-      const Identifier& unique_identifier);
+  IndexedDBDatabase(const string16& name,
+                    IndexedDBBackingStore* database,
+                    IndexedDBFactory* factory,
+                    const Identifier& unique_identifier);
   ~IndexedDBDatabase();
 
   bool IsOpenConnectionBlocked() const;
@@ -216,12 +274,6 @@
   bool ValidateObjectStoreIdAndNewIndexId(int64 object_store_id,
                                           int64 index_id) const;
 
-  class VersionChangeOperation;
-
-  // When a "versionchange" transaction aborts, these restore the back-end
-  // object hierarchy.
-  class VersionChangeAbortOperation;
-
   scoped_refptr<IndexedDBBackingStore> backing_store_;
   IndexedDBDatabaseMetadata metadata_;
 
diff --git a/content/browser/indexed_db/indexed_db_internals_ui.cc b/content/browser/indexed_db/indexed_db_internals_ui.cc
index a5c90c4..230b788 100644
--- a/content/browser/indexed_db/indexed_db_internals_ui.cc
+++ b/content/browser/indexed_db/indexed_db_internals_ui.cc
@@ -257,9 +257,6 @@
 void IndexedDBInternalsUI::OnForcedClose(const base::FilePath& partition_path,
                                          const GURL& origin_url,
                                          size_t connection_count) {
-
-  scoped_refptr<IndexedDBContextImpl> context;
-
   web_ui()->CallJavascriptFunction(
       "indexeddb.onForcedClose",
       base::StringValue(partition_path.value()),
@@ -281,7 +278,7 @@
       DownloadUrlParameters::FromWebContents(web_ui()->GetWebContents(), url));
   DownloadManager* dlm = BrowserContext::GetDownloadManager(browser_context);
 
-  const GURL referrer(web_ui()->GetWebContents()->GetURL());
+  const GURL referrer(web_ui()->GetWebContents()->GetLastCommittedURL());
   dl_params->set_referrer(
       content::Referrer(referrer, WebKit::WebReferrerPolicyDefault));
 
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/content/browser/indexed_db/indexed_db_leveldb_coding.cc
index 0086b82..588f9ef 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.cc
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding.cc
@@ -14,139 +14,137 @@
 #include "content/common/indexed_db/indexed_db_key.h"
 #include "content/common/indexed_db/indexed_db_key_path.h"
 
+// LevelDB Coding Scheme
+// =====================
+//
 // LevelDB stores key/value pairs. Keys and values are strings of bytes,
 // normally of type std::string.
 //
-// The keys in the backing store are variable-length tuples with different types
-// of fields. Each key in the backing store starts with a ternary prefix:
-// (database id, object store id, index id). For each, 0 is reserved for
-// meta-data.
+// The keys in the backing store are variable-length tuples with different
+// types of fields. Each key in the backing store starts with a ternary
+// prefix: (database id, object store id, index id). For each, 0 is reserved
+// for metadata. See KeyPrefix::Decode() for details of the prefix coding.
+//
 // The prefix makes sure that data for a specific database, object store, and
-// index are grouped together. The locality is important for performance: common
-// operations should only need a minimal number of seek operations. For example,
-// all the meta-data for a database is grouped together so that reading that
-// meta-data only requires one seek.
+// index are grouped together. The locality is important for performance:
+// common operations should only need a minimal number of seek operations. For
+// example, all the metadata for a database is grouped together so that
+// reading that metadata only requires one seek.
 //
 // Each key type has a class (in square brackets below) which knows how to
 // encode, decode, and compare that key type.
 //
-// Global meta-data have keys with prefix (0,0,0), followed by a type byte:
-//
-//     <0, 0, 0, 0>                                           =>
-// IndexedDB/LevelDB schema version [SchemaVersionKey]
-//     <0, 0, 0, 1>                                           => The maximum
-// database id ever allocated [MaxDatabaseIdKey]
-//     <0, 0, 0, 2>                                           =>
-// SerializedScriptValue version [DataVersionKey]
-//     <0, 0, 0, 100, database id>                            => Existence
-// implies the database id is in the free list [DatabaseFreeListKey]
-//     <0, 0, 0, 201, utf16 origin name, utf16 database name> => Database id
-// [DatabaseNameKey]
+// Strings (origins, names, etc) are encoded as UTF-16BE.
 //
 //
-// Database meta-data:
+// Global metadata
+// ---------------
+// The prefix is <0, 0, 0>, followed by a metadata type byte:
 //
-//     Again, the prefix is followed by a type byte.
-//
-//     <database id, 0, 0, 0> => utf16 origin name [DatabaseMetaDataKey]
-//     <database id, 0, 0, 1> => utf16 database name [DatabaseMetaDataKey]
-//     <database id, 0, 0, 2> => utf16 user version data [DatabaseMetaDataKey]
-//     <database id, 0, 0, 3> => maximum object store id ever allocated
-// [DatabaseMetaDataKey]
-//     <database id, 0, 0, 4> => user integer version (var int)
-// [DatabaseMetaDataKey]
+// <0, 0, 0, 0> => backing store schema version [SchemaVersionKey]
+// <0, 0, 0, 1> => maximum allocated database [MaxDatabaseIdKey]
+// <0, 0, 0, 2> => SerializedScriptValue version [DataVersionKey]
+// <0, 0, 0, 100, database id>
+//   => Existence implies the database id is in the free list
+//      [DatabaseFreeListKey]
+// <0, 0, 0, 201, origin, database name> => Database id [DatabaseNameKey]
 //
 //
-// Object store meta-data:
+// Database metadata: [DatabaseMetaDataKey]
+// ----------------------------------------
+// The prefix is <database id, 0, 0> followed by a metadata type byte:
 //
-//     The prefix is followed by a type byte, then a variable-length integer,
-// and then another type byte.
-//
-//     <database id, 0, 0, 50, object store id, 0> => utf16 object store name
-// [ObjectStoreMetaDataKey]
-//     <database id, 0, 0, 50, object store id, 1> => utf16 key path
-// [ObjectStoreMetaDataKey]
-//     <database id, 0, 0, 50, object store id, 2> => has auto increment
-// [ObjectStoreMetaDataKey]
-//     <database id, 0, 0, 50, object store id, 3> => is evictable
-// [ObjectStoreMetaDataKey]
-//     <database id, 0, 0, 50, object store id, 4> => last "version" number
-// [ObjectStoreMetaDataKey]
-//     <database id, 0, 0, 50, object store id, 5> => maximum index id ever
-// allocated [ObjectStoreMetaDataKey]
-//     <database id, 0, 0, 50, object store id, 6> => has key path (vs. null)
-// [ObjectStoreMetaDataKey]
-//     <database id, 0, 0, 50, object store id, 7> => key generator current
-// number [ObjectStoreMetaDataKey]
+// <database id, 0, 0, 0> => origin name
+// <database id, 0, 0, 1> => database name
+// <database id, 0, 0, 2> => IDB string version data (obsolete)
+// <database id, 0, 0, 3> => maximum allocated object store id
+// <database id, 0, 0, 4> => IDB integer version (var int)
 //
 //
-// Index meta-data:
+// Object store metadata: [ObjectStoreMetaDataKey]
+// -----------------------------------------------
+// The prefix is <database id, 0, 0>, followed by a type byte (50), then the
+// object store id (var int), then a metadata type byte.
 //
-//     The prefix is followed by a type byte, then two variable-length integers,
-// and then another type byte.
+// <database id, 0, 0, 50, object store id, 0> => object store name
+// <database id, 0, 0, 50, object store id, 1> => key path
+// <database id, 0, 0, 50, object store id, 2> => auto increment flag
+// <database id, 0, 0, 50, object store id, 3> => is evictable
+// <database id, 0, 0, 50, object store id, 4> => last "version" number
+// <database id, 0, 0, 50, object store id, 5> => maximum allocated index id
+// <database id, 0, 0, 50, object store id, 6> => has key path flag (obsolete)
+// <database id, 0, 0, 50, object store id, 7> => key generator current number
 //
-//     <database id, 0, 0, 100, object store id, index id, 0> => utf16 index
-// name [IndexMetaDataKey]
-//     <database id, 0, 0, 100, object store id, index id, 1> => are index keys
-// unique [IndexMetaDataKey]
-//     <database id, 0, 0, 100, object store id, index id, 2> => utf16 key path
-// [IndexMetaDataKey]
-//     <database id, 0, 0, 100, object store id, index id, 3> => is index
-// multi-entry [IndexMetaDataKey]
+// The key path was originally just a string (#1) or null (identified by flag,
+// #6). To support null, string, or array the coding is now identified by the
+// leading bytes in #1 - see EncodeIDBKeyPath.
+//
+// The "version" field is used to weed out stale index data. Whenever new
+// object store data is inserted, it gets a new "version" number, and new
+// index data is written with this number. When the index is used for
+// look-ups, entries are validated against the "exists" entries, and records
+// with old "version" numbers are deleted when they are encountered in
+// GetPrimaryKeyViaIndex, IndexCursorImpl::LoadCurrentRow and
+// IndexKeyCursorImpl::LoadCurrentRow.
 //
 //
-// Other object store and index meta-data:
+// Index metadata: [IndexMetaDataKey]
+// ----------------------------------
+// The prefix is <database id, 0, 0>, followed by a type byte (100), then the
+// object store id (var int), then the index id (var int), then a metadata
+// type byte.
 //
-//     The prefix is followed by a type byte. The object store and index id are
-// variable length integers, the utf16 strings are variable length strings.
-//
-//     <database id, 0, 0, 150, object store id>                   => existence
-// implies the object store id is in the free list [ObjectStoreFreeListKey]
-//     <database id, 0, 0, 151, object store id, index id>         => existence
-// implies the index id is in the free list [IndexFreeListKey]
-//     <database id, 0, 0, 200, utf16 object store name>           => object
-// store id [ObjectStoreNamesKey]
-//     <database id, 0, 0, 201, object store id, utf16 index name> => index id
-// [IndexNamesKey]
+// <database id, 0, 0, 100, object store id, index id, 0> => index name
+// <database id, 0, 0, 100, object store id, index id, 1> => unique flag
+// <database id, 0, 0, 100, object store id, index id, 2> => key path
+// <database id, 0, 0, 100, object store id, index id, 3> => multi-entry flag
 //
 //
-// Object store data:
+// Other object store and index metadata
+// -------------------------------------
+// The prefix is <database id, 0, 0> followed by a type byte. The object
+// store and index id are variable length integers, the names are variable
+// length strings.
 //
-//     The prefix is followed by a type byte. The user key is an encoded
-// IndexedDBKey.
-//
-//     <database id, object store id, 1, user key> => "version", serialized
-// script value [ObjectStoreDataKey]
+// <database id, 0, 0, 150, object store id>
+//   => existence implies the object store id is in the free list
+//      [ObjectStoreFreeListKey]
+// <database id, 0, 0, 151, object store id, index id>
+//   => existence implies the index id is in the free list [IndexFreeListKey]
+// <database id, 0, 0, 200, object store name>
+//   => object store id [ObjectStoreNamesKey]
+// <database id, 0, 0, 201, object store id, index name>
+//   => index id [IndexNamesKey]
 //
 //
-// "Exists" entry:
+// Object store data: [ObjectStoreDataKey]
+// ---------------------------------------
+// The prefix is followed by a type byte and the encoded IDB primary key. The
+// data has a "version" prefix followed by the serialized script value.
 //
-//     The prefix is followed by a type byte. The user key is an encoded
-// IndexedDBKey.
-//
-//     <database id, object store id, 2, user key> => "version" [ExistsEntryKey]
+// <database id, object store id, 1, user key>
+//   => "version", serialized script value
 //
 //
-// Index data:
+// "Exists" entry: [ExistsEntryKey]
+// --------------------------------
+// The prefix is followed by a type byte and the encoded IDB primary key.
 //
-//     The prefix is followed by a type byte. The index key is an encoded
-// IndexedDBKey. The sequence number is a variable length integer.
-//     The primary key is an encoded IndexedDBKey.
+// <database id, object store id, 2, user key> => "version"
 //
-//     <database id, object store id, index id, index key, sequence number,
-// primary key> => "version", primary key [IndexDataKey]
 //
-//     (The sequence number is obsolete; it was used to allow two entries with
-//     the same user (index) key in non-unique indexes prior to the inclusion of
-//     the primary key in the data. The "version" field is used to weed out
-// stale
-//     index data. Whenever new object store data is inserted, it gets a new
-//     "version" number, and new index data is written with this number. When
-//     the index is used for look-ups, entries are validated against the
-//     "exists" entries, and records with old "version" numbers are deleted
-//     when they are encountered in get_primary_key_via_index,
-//     IndexCursorImpl::load_current_row, and
-// IndexKeyCursorImpl::load_current_row).
+// Index data
+// ----------
+// The prefix is followed by a type byte, the encoded IDB index key, a
+// "sequence" number (obsolete; var int), and the encoded IDB primary key.
+//
+// <database id, object store id, index id, index key, sequence number,
+//   primary key> => "version", primary key [IndexDataKey]
+//
+// The sequence number is obsolete; it was used to allow two entries with the
+// same user (index) key in non-unique indexes prior to the inclusion of the
+// primary key in the data.
+
 
 using base::StringPiece;
 using WebKit::WebIDBKeyType;
@@ -744,7 +742,10 @@
 namespace {
 
 template <typename KeyType>
-int Compare(const StringPiece& a, const StringPiece& b, bool, bool* ok) {
+int Compare(const StringPiece& a,
+            const StringPiece& b,
+            bool only_compare_index_keys,
+            bool* ok) {
   KeyType key_a;
   KeyType key_b;
 
@@ -766,7 +767,7 @@
 template <>
 int Compare<ExistsEntryKey>(const StringPiece& a,
                             const StringPiece& b,
-                            bool,
+                            bool only_compare_index_keys,
                             bool* ok) {
   KeyPrefix prefix_a;
   KeyPrefix prefix_b;
@@ -793,7 +794,7 @@
 template <>
 int Compare<ObjectStoreDataKey>(const StringPiece& a,
                                 const StringPiece& b,
-                                bool,
+                                bool only_compare_index_keys,
                                 bool* ok) {
   KeyPrefix prefix_a;
   KeyPrefix prefix_b;
@@ -820,7 +821,7 @@
 template <>
 int Compare<IndexDataKey>(const StringPiece& a,
                           const StringPiece& b,
-                          bool ignore_duplicates,
+                          bool only_compare_index_keys,
                           bool* ok) {
   KeyPrefix prefix_a;
   KeyPrefix prefix_b;
@@ -845,7 +846,7 @@
   int result = CompareEncodedIDBKeys(&slice_a, &slice_b, ok);
   if (!*ok || result)
     return result;
-  if (ignore_duplicates)
+  if (only_compare_index_keys)
     return 0;
 
   // sequence number [optional]
@@ -877,7 +878,7 @@
 
 int Compare(const StringPiece& a,
             const StringPiece& b,
-            bool index_keys,
+            bool only_compare_index_keys,
             bool* ok) {
   StringPiece slice_a(a);
   StringPiece slice_b(b);
@@ -918,11 +919,12 @@
       if (type_byte_a < kMaxSimpleGlobalMetaDataTypeByte)
         return 0;
 
-      const bool ignore_duplicates = false;
       if (type_byte_a == kDatabaseFreeListTypeByte)
-        return Compare<DatabaseFreeListKey>(a, b, ignore_duplicates, ok);
+        return Compare<DatabaseFreeListKey>(
+            a, b, only_compare_index_keys, ok);
       if (type_byte_a == kDatabaseNameTypeByte)
-        return Compare<DatabaseNameKey>(a, b, ignore_duplicates, ok);
+        return Compare<DatabaseNameKey>(
+            a, b, /*only_compare_index_keys*/ false, ok);
       break;
     }
 
@@ -947,19 +949,24 @@
       if (type_byte_a < DatabaseMetaDataKey::MAX_SIMPLE_METADATA_TYPE)
         return 0;
 
-      const bool ignore_duplicates = false;
       if (type_byte_a == kObjectStoreMetaDataTypeByte)
-        return Compare<ObjectStoreMetaDataKey>(a, b, ignore_duplicates, ok);
+        return Compare<ObjectStoreMetaDataKey>(
+            a, b, only_compare_index_keys, ok);
       if (type_byte_a == kIndexMetaDataTypeByte)
-        return Compare<IndexMetaDataKey>(a, b, ignore_duplicates, ok);
+        return Compare<IndexMetaDataKey>(
+            a, b, /*only_compare_index_keys*/ false, ok);
       if (type_byte_a == kObjectStoreFreeListTypeByte)
-        return Compare<ObjectStoreFreeListKey>(a, b, ignore_duplicates, ok);
+        return Compare<ObjectStoreFreeListKey>(
+            a, b, only_compare_index_keys, ok);
       if (type_byte_a == kIndexFreeListTypeByte)
-        return Compare<IndexFreeListKey>(a, b, ignore_duplicates, ok);
+        return Compare<IndexFreeListKey>(
+            a, b, /*only_compare_index_keys*/ false, ok);
       if (type_byte_a == kObjectStoreNamesTypeByte)
-        return Compare<ObjectStoreNamesKey>(a, b, ignore_duplicates, ok);
+        return Compare<ObjectStoreNamesKey>(
+            a, b, only_compare_index_keys, ok);
       if (type_byte_a == kIndexNamesKeyTypeByte)
-        return Compare<IndexNamesKey>(a, b, ignore_duplicates, ok);
+        return Compare<IndexNamesKey>(
+            a, b, /*only_compare_index_keys*/ false, ok);
       break;
     }
 
@@ -969,8 +976,8 @@
       // TODO(jsbell): This case of non-existing user keys should not have to be
       // handled this way.
 
-      const bool ignore_duplicates = false;
-      return Compare<ObjectStoreDataKey>(a, b, ignore_duplicates, ok);
+      return Compare<ObjectStoreDataKey>(
+          a, b, /*only_compare_index_keys*/ false, ok);
     }
 
     case KeyPrefix::EXISTS_ENTRY: {
@@ -979,8 +986,8 @@
       // TODO(jsbell): This case of non-existing user keys should not have to be
       // handled this way.
 
-      const bool ignore_duplicates = false;
-      return Compare<ExistsEntryKey>(a, b, ignore_duplicates, ok);
+      return Compare<ExistsEntryKey>(
+          a, b, /*only_compare_index_keys*/ false, ok);
     }
 
     case KeyPrefix::INDEX_DATA: {
@@ -989,8 +996,7 @@
       // TODO(jsbell): This case of non-existing user keys should not have to be
       // handled this way.
 
-      bool ignore_duplicates = index_keys;
-      return Compare<IndexDataKey>(a, b, ignore_duplicates, ok);
+      return Compare<IndexDataKey>(a, b, only_compare_index_keys, ok);
     }
 
     case KeyPrefix::INVALID_TYPE:
@@ -1004,9 +1010,11 @@
 
 }  // namespace
 
-int Compare(const StringPiece& a, const StringPiece& b, bool index_keys) {
+int Compare(const StringPiece& a,
+            const StringPiece& b,
+            bool only_compare_index_keys) {
   bool ok;
-  int result = Compare(a, b, index_keys, &ok);
+  int result = Compare(a, b, only_compare_index_keys, &ok);
   DCHECK(ok);
   if (!ok)
     return 0;
@@ -1782,7 +1790,7 @@
 }
 
 int IndexDataKey::Compare(const IndexDataKey& other,
-                          bool ignore_duplicates,
+                          bool only_compare_index_keys,
                           bool* ok) {
   DCHECK_GE(database_id_, 0);
   DCHECK_GE(object_store_id_, 0);
@@ -1791,7 +1799,7 @@
       CompareEncodedIDBKeys(encoded_user_key_, other.encoded_user_key_, ok);
   if (!*ok || result)
     return result;
-  if (ignore_duplicates)
+  if (only_compare_index_keys)
     return 0;
   result = CompareEncodedIDBKeys(
       encoded_primary_key_, other.encoded_primary_key_, ok);
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.h b/content/browser/indexed_db/indexed_db_leveldb_coding.h
index ecd8b9b..974c27a 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -402,7 +402,9 @@
   CONTENT_EXPORT static std::string EncodeMaxKey(int64 database_id,
                                                  int64 object_store_id,
                                                  int64 index_id);
-  int Compare(const IndexDataKey& other, bool ignore_duplicates, bool* ok);
+  int Compare(const IndexDataKey& other,
+              bool only_compare_index_keys,
+              bool* ok);
   int64 DatabaseId() const;
   int64 ObjectStoreId() const;
   int64 IndexId() const;
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc
index b096f3b..ee38d0b 100644
--- a/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -23,15 +23,14 @@
 
 void IndexedDBTransaction::TaskQueue::clear() {
   while (!queue_.empty())
-    scoped_ptr<Operation> task(pop());
+    queue_.pop();
 }
 
-scoped_ptr<IndexedDBTransaction::Operation>
-IndexedDBTransaction::TaskQueue::pop() {
+IndexedDBTransaction::Operation IndexedDBTransaction::TaskQueue::pop() {
   DCHECK(!queue_.empty());
-  scoped_ptr<Operation> task(queue_.front());
+  Operation task(queue_.front());
   queue_.pop();
-  return task.Pass();
+  return task;
 }
 
 IndexedDBTransaction::TaskStack::TaskStack() {}
@@ -39,15 +38,14 @@
 
 void IndexedDBTransaction::TaskStack::clear() {
   while (!stack_.empty())
-    scoped_ptr<Operation> task(pop());
+    stack_.pop();
 }
 
-scoped_ptr<IndexedDBTransaction::Operation>
-IndexedDBTransaction::TaskStack::pop() {
+IndexedDBTransaction::Operation IndexedDBTransaction::TaskStack::pop() {
   DCHECK(!stack_.empty());
-  scoped_ptr<Operation> task(stack_.top());
+  Operation task(stack_.top());
   stack_.pop();
-  return task.Pass();
+  return task;
 }
 
 IndexedDBTransaction::IndexedDBTransaction(
@@ -78,9 +76,16 @@
   DCHECK(abort_task_stack_.empty());
 }
 
+void IndexedDBTransaction::ScheduleTask(Operation task, Operation abort_task) {
+  if (state_ == FINISHED)
+    return;
+  task_queue_.push(task);
+  abort_task_stack_.push(abort_task);
+  EnsureTasksRunning();
+}
+
 void IndexedDBTransaction::ScheduleTask(IndexedDBDatabase::TaskType type,
-                                        Operation* task,
-                                        Operation* abort_task) {
+                                        Operation task) {
   if (state_ == FINISHED)
     return;
 
@@ -88,10 +93,10 @@
     task_queue_.push(task);
   else
     preemptive_task_queue_.push(task);
+  EnsureTasksRunning();
+}
 
-  if (abort_task)
-    abort_task_stack_.push(abort_task);
-
+void IndexedDBTransaction::EnsureTasksRunning() {
   if (state_ == UNUSED) {
     Start();
   } else if (state_ == RUNNING && !should_process_queue_) {
@@ -126,8 +131,8 @@
 
   // Run the abort tasks, if any.
   while (!abort_task_stack_.empty()) {
-    scoped_ptr<Operation> task(abort_task_stack_.pop());
-    task->Perform(0);
+    Operation task(abort_task_stack_.pop());
+    task.Run(0);
   }
   preemptive_task_queue_.clear();
   task_queue_.clear();
@@ -272,8 +277,8 @@
       pending_preemptive_events_ ? &preemptive_task_queue_ : &task_queue_;
   while (!task_queue->empty() && state_ != FINISHED) {
     DCHECK_EQ(state_, RUNNING);
-    scoped_ptr<Operation> task(task_queue->pop());
-    task->Perform(this);
+    Operation task(task_queue->pop());
+    task.Run(this);
 
     // Event itself may change which queue should be processed next.
     task_queue =
diff --git a/content/browser/indexed_db/indexed_db_transaction.h b/content/browser/indexed_db/indexed_db_transaction.h
index 51b1c0a..8356a13 100644
--- a/content/browser/indexed_db/indexed_db_transaction.h
+++ b/content/browser/indexed_db/indexed_db_transaction.h
@@ -23,6 +23,8 @@
 
 class IndexedDBTransaction : public base::RefCounted<IndexedDBTransaction> {
  public:
+  typedef base::Callback<void(IndexedDBTransaction*)> Operation;
+
   IndexedDBTransaction(int64 id,
                        scoped_refptr<IndexedDBDatabaseCallbacks> callbacks,
                        const std::set<int64>& object_store_ids,
@@ -32,29 +34,16 @@
   virtual void Abort();
   void Commit();
 
-  class Operation {
-   public:
-    Operation() {}
-    virtual ~Operation() {}
-    virtual void Perform(IndexedDBTransaction* transaction) = 0;
-  };
-
   void Abort(const IndexedDBDatabaseError& error);
   void Run();
   indexed_db::TransactionMode mode() const { return mode_; }
   const std::set<int64>& scope() const { return object_store_ids_; }
-  void ScheduleTask(Operation* task) {
-    ScheduleTask(IndexedDBDatabase::NORMAL_TASK, task, NULL);
+  void ScheduleTask(Operation task) {
+    ScheduleTask(IndexedDBDatabase::NORMAL_TASK, task);
   }
-  void ScheduleTask(Operation* task, Operation* abort_task) {
-    ScheduleTask(IndexedDBDatabase::NORMAL_TASK, task, abort_task);
-  }
-  void ScheduleTask(IndexedDBDatabase::TaskType task_type, Operation* task) {
-    ScheduleTask(task_type, task, NULL);
-  }
-  void ScheduleTask(IndexedDBDatabase::TaskType task_type,
-                    Operation* task,
-                    Operation* abort_task);
+
+  void ScheduleTask(Operation task, Operation abort_task);
+  void ScheduleTask(IndexedDBDatabase::TaskType, Operation task);
   void RegisterOpenCursor(IndexedDBCursor* cursor);
   void UnregisterOpenCursor(IndexedDBCursor* cursor);
   void AddPreemptiveEvent() { pending_preemptive_events_++; }
@@ -84,6 +73,7 @@
     FINISHED,       // Either aborted or committed.
   };
 
+  void EnsureTasksRunning();
   void Start();
 
   bool IsTaskQueueEmpty() const;
@@ -106,12 +96,12 @@
     TaskQueue();
     ~TaskQueue();
     bool empty() const { return queue_.empty(); }
-    void push(Operation* task) { queue_.push(task); }
-    scoped_ptr<Operation> pop();
+    void push(Operation task) { queue_.push(task); }
+    Operation pop();
     void clear();
 
    private:
-    std::queue<Operation*> queue_;
+    std::queue<Operation> queue_;
   };
 
   class TaskStack {
@@ -119,12 +109,12 @@
     TaskStack();
     ~TaskStack();
     bool empty() const { return stack_.empty(); }
-    void push(Operation* task) { stack_.push(task); }
-    scoped_ptr<Operation> pop();
+    void push(Operation task) { stack_.push(task); }
+    Operation pop();
     void clear();
 
    private:
-    std::stack<Operation*> stack_;
+    std::stack<Operation> stack_;
   };
 
   TaskQueue task_queue_;
diff --git a/content/browser/loader/resource_dispatcher_host_browsertest.cc b/content/browser/loader/resource_dispatcher_host_browsertest.cc
index cb8896f..0a763fe 100644
--- a/content/browser/loader/resource_dispatcher_host_browsertest.cc
+++ b/content/browser/loader/resource_dispatcher_host_browsertest.cc
@@ -15,9 +15,9 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_network_delegate.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_network_delegate.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "content/test/net/url_request_failed_job.h"
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index c37137d..d4f6e53 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -1191,7 +1191,7 @@
     const std::string& http_method,
     const std::string& mime_type,
     ResourceType::Type resource_type) {
-  if (!url.is_valid() || !(url.SchemeIs("http") || url.SchemeIs("https")))
+  if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS())
     return;
 
   filter_->GetURLRequestContext(resource_type)->http_transaction_factory()->
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
index 7e70c45..0277783 100644
--- a/content/browser/loader/resource_scheduler.cc
+++ b/content/browser/loader/resource_scheduler.cc
@@ -81,6 +81,8 @@
         ready_(false),
         deferred_(false),
         scheduler_(scheduler) {
+    TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_,
+                             "url", request->url().spec());
   }
 
   virtual ~ScheduledResourceRequest() {
@@ -88,6 +90,7 @@
   }
 
   void Start() {
+    TRACE_EVENT_ASYNC_STEP0("net", "URLRequest", request_, "Queued");
     ready_ = true;
     if (deferred_ && request_->status().is_success()) {
       deferred_ = false;
diff --git a/content/browser/media/encrypted_media_browsertest.cc b/content/browser/media/encrypted_media_browsertest.cc
index ce5dc4e..90d07b2 100644
--- a/content/browser/media/encrypted_media_browsertest.cc
+++ b/content/browser/media/encrypted_media_browsertest.cc
@@ -9,7 +9,7 @@
 #include "content/browser/media/media_browsertest.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 
 #include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
 
@@ -243,7 +243,7 @@
   TestFrameSizeChange(GetParam(), kEnded);
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4) {
   std::tr1::tuple<const char*, SrcType> test_params = GetParam();
   // MP4 without MSE is not support yet, http://crbug.com/170793.
@@ -265,7 +265,7 @@
   TestMSESimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly,
                         std::tr1::get<0>(test_params), kEnded);
 }
-#endif
+#endif  // defined(USE_PROPRIETARY_CODECS)
 
 // Run only when WV CDM is available.
 #if defined(WIDEVINE_CDM_AVAILABLE)
@@ -294,7 +294,7 @@
                         kWidevineKeySystem);
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 IN_PROC_BROWSER_TEST_F(WVEncryptedMediaTest, Playback_VideoOnly_MP4) {
   TestMSESimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly,
                         kWidevineKeySystem);
@@ -304,7 +304,7 @@
   TestMSESimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly,
                         kWidevineKeySystem);
 }
-#endif  // defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#endif  // defined(USE_PROPRIETARY_CODECS)
 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
 
 }  // namespace content
diff --git a/content/browser/media/media_browsertest.cc b/content/browser/media/media_browsertest.cc
index 1d83035..488d8f0 100644
--- a/content/browser/media/media_browsertest.cc
+++ b/content/browser/media/media_browsertest.cc
@@ -9,7 +9,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils.h"
 
 // TODO(wolenetz): Fix Media.YUV* tests on MSVS 2012 x64. crbug.com/180074
@@ -117,7 +117,7 @@
   PlayVideo("bear_silent.webm", GetParam());
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearMp4) {
   PlayVideo("bear.mp4", GetParam());
 }
@@ -139,7 +139,7 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 IN_PROC_BROWSER_TEST_P(MediaTest, VideoBearAviMp3Mpeg4) {
   PlayVideo("bear_mpeg4_mp3.avi", GetParam());
 }
@@ -217,7 +217,7 @@
   RunColorFormatTest("yuv420p.webm", "ENDED");
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 IN_PROC_BROWSER_TEST_F(MediaTest, MAYBE(Yuv420pH264)) {
   RunColorFormatTest("yuv420p.mp4", "ENDED");
 }
@@ -239,7 +239,7 @@
 IN_PROC_BROWSER_TEST_F(MediaTest, Yuv420pMpeg4) {
   RunColorFormatTest("yuv420p.avi", "ENDED");
 }
-#endif
-#endif
+#endif  // defined(OS_CHROMEOS)
+#endif  // defined(USE_PROPRIETARY_CODECS)
 
 }  // namespace content
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc
index 273eeae..22f164d 100644
--- a/content/browser/media/media_internals.cc
+++ b/content/browser/media/media_internals.cc
@@ -9,6 +9,7 @@
 #include "base/strings/stringprintf.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_ui.h"
+#include "media/audio/audio_parameters.h"
 #include "media/base/media_log.h"
 #include "media/base/media_log_event.h"
 
@@ -20,11 +21,15 @@
 
 MediaInternals::~MediaInternals() {}
 
+namespace {
+std::string FormatAudioStreamName(void* host, int stream_id) {
+  return base::StringPrintf("audio_streams.%p:%d", host, stream_id);
+}
+}
+
 void MediaInternals::OnDeleteAudioStream(void* host, int stream_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  std::string stream = base::StringPrintf("audio_streams.%p:%d",
-                                          host, stream_id);
-  DeleteItem(stream);
+  DeleteItem(FormatAudioStreamName(host, stream_id));
 }
 
 void MediaInternals::OnSetAudioStreamPlaying(
@@ -34,8 +39,55 @@
                     "playing", new base::FundamentalValue(playing));
 }
 
-void MediaInternals::OnSetAudioStreamStatus(
-    void* host, int stream_id, const std::string& status) {
+void MediaInternals::OnAudioStreamCreated(void* host,
+                                          int stream_id,
+                                          const media::AudioParameters& params,
+                                          const std::string& input_device_id) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  StoreAudioStream(host,
+                   stream_id,
+                   "input_device_id",
+                   Value::CreateStringValue(input_device_id));
+
+  StoreAudioStream(
+      host, stream_id, "status", Value::CreateStringValue("created"));
+
+  StoreAudioStream(
+      host, stream_id, "stream_id", Value::CreateIntegerValue(stream_id));
+
+  StoreAudioStream(host,
+                   stream_id,
+                   "input_channels",
+                   Value::CreateIntegerValue(params.input_channels()));
+
+  StoreAudioStream(host,
+                   stream_id,
+                   "frames_per_buffer",
+                   Value::CreateIntegerValue(params.frames_per_buffer()));
+
+  StoreAudioStream(host,
+                   stream_id,
+                   "sample_rate",
+                   Value::CreateIntegerValue(params.sample_rate()));
+
+  StoreAudioStream(host,
+                   stream_id,
+                   "output_channels",
+                   Value::CreateIntegerValue(params.channels()));
+
+  StoreAudioStream(
+      host,
+      stream_id,
+      "channel_layout",
+      Value::CreateStringValue(ChannelLayoutToString(params.channel_layout())));
+
+  SendEverything();
+}
+
+void MediaInternals::OnSetAudioStreamStatus(void* host,
+                                            int stream_id,
+                                            const std::string& status) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   UpdateAudioStream(host, stream_id,
                     "status", new base::StringValue(status));
@@ -92,13 +144,21 @@
 MediaInternals::MediaInternals() {
 }
 
+void MediaInternals::StoreAudioStream(void* host,
+                                      int stream_id,
+                                      const std::string& property,
+                                      base::Value* value) {
+  StoreItem(FormatAudioStreamName(host, stream_id), property, value);
+}
+
 void MediaInternals::UpdateAudioStream(void* host,
                                        int stream_id,
                                        const std::string& property,
                                        base::Value* value) {
-  std::string stream = base::StringPrintf("audio_streams.%p:%d",
-                                          host, stream_id);
-  UpdateItem("media.addAudioStream", stream, property, value);
+  UpdateItem("media.updateAudioStream",
+             FormatAudioStreamName(host, stream_id),
+             property,
+             value);
 }
 
 void MediaInternals::DeleteItem(const std::string& item) {
@@ -107,9 +167,9 @@
   SendUpdate("media.onItemDeleted", value.get());
 }
 
-void MediaInternals::UpdateItem(
-    const std::string& update_fn, const std::string& id,
-    const std::string& property, base::Value* value) {
+base::DictionaryValue* MediaInternals::StoreItem(const std::string& id,
+                                                 const std::string& property,
+                                                 base::Value* value) {
   base::DictionaryValue* item_properties;
   if (!data_.GetDictionary(id, &item_properties)) {
     item_properties = new base::DictionaryValue();
@@ -117,6 +177,14 @@
     item_properties->SetString("id", id);
   }
   item_properties->Set(property, value);
+  return item_properties;
+}
+
+void MediaInternals::UpdateItem(const std::string& update_fn,
+                                const std::string& id,
+                                const std::string& property,
+                                base::Value* value) {
+  base::DictionaryValue* item_properties = StoreItem(id, property, value);
   SendUpdate(update_fn, item_properties);
 }
 
diff --git a/content/browser/media/media_internals.h b/content/browser/media/media_internals.h
index 4a4d2ef..24b314e 100644
--- a/content/browser/media/media_internals.h
+++ b/content/browser/media/media_internals.h
@@ -16,6 +16,7 @@
 #include "content/public/common/media_stream_request.h"
 
 namespace media {
+class AudioParameters;
 struct MediaLogEvent;
 }
 
@@ -36,8 +37,14 @@
   virtual void OnDeleteAudioStream(void* host, int stream_id);
 
   // Called when an audio stream is set to playing or paused.
-  virtual void OnSetAudioStreamPlaying(void* host, int stream_id,
-                                       bool playing);
+  virtual void OnSetAudioStreamPlaying(void* host, int stream_id, bool playing);
+
+  // Called when an audio stream is created with the parameters that
+  // it attempts to use to make the stream.
+  virtual void OnAudioStreamCreated(void* host,
+                                    int stream_id,
+                                    const media::AudioParameters& params,
+                                    const std::string& input_device_id);
 
   // Called when the status of an audio stream is set to "created", "closed", or
   // "error".
@@ -73,9 +80,21 @@
   void UpdateAudioStream(void* host, int stream_id,
                          const std::string& property, base::Value* value);
 
+  // See UpdateAudioStream.  The difference is that StoreAudioStream does not
+  // immediately send the data to the client, instead it waits until
+  // SendEverything is called.
+  void StoreAudioStream(void* host,
+                        int stream_id,
+                        const std::string& property,
+                        base::Value* value);
+
   // Removes |item| from |data_|.
   void DeleteItem(const std::string& item);
 
+  base::DictionaryValue* StoreItem(const std::string& id,
+                                   const std::string& property,
+                                   base::Value* value);
+
   // Sets data_.id.property = value and notifies attached UIs using update_fn.
   // id may be any depth, e.g. "video.decoders.1.2.3"
   void UpdateItem(const std::string& update_fn, const std::string& id,
diff --git a/content/browser/media/media_internals_unittest.cc b/content/browser/media/media_internals_unittest.cc
index 58c8f91..173ba36 100644
--- a/content/browser/media/media_internals_unittest.cc
+++ b/content/browser/media/media_internals_unittest.cc
@@ -7,7 +7,10 @@
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
 #include "content/public/test/test_browser_thread.h"
+#include "media/audio/audio_parameters.h"
+#include "media/base/channel_layout.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -58,6 +61,46 @@
   scoped_ptr<MediaInternals> internals_;
 };
 
+TEST_F(MediaInternalsTest, AudioStreamCreatedSendsMessage) {
+  media::AudioParameters params =
+      media::AudioParameters(media::AudioParameters::AUDIO_PCM_LINEAR,
+                             media::CHANNEL_LAYOUT_MONO,
+                             48000,
+                             16,
+                             129);
+
+  const int stream_id = 0;
+  const std::string device_id = "test";
+  const std::string name =
+      base::StringPrintf("audio_streams.%p:%d", this, stream_id);
+
+  internals_->OnAudioStreamCreated(this, stream_id, params, device_id);
+
+  std::string channel_layout;
+  data()->GetString(name + ".channel_layout", &channel_layout);
+  EXPECT_EQ("MONO", channel_layout);
+
+  int sample_rate;
+  data()->GetInteger(name + ".sample_rate", &sample_rate);
+  EXPECT_EQ(params.sample_rate(), sample_rate);
+
+  int frames_per_buffer;
+  data()->GetInteger(name + ".frames_per_buffer", &frames_per_buffer);
+  EXPECT_EQ(params.frames_per_buffer(), frames_per_buffer);
+
+  int output_channels;
+  data()->GetInteger(name + ".output_channels", &output_channels);
+  EXPECT_EQ(params.channels(), output_channels);
+
+  std::string device_id_out;
+  data()->GetString(name + ".input_device_id", &device_id_out);
+  EXPECT_EQ(device_id, device_id_out);
+
+  int input_channels;
+  data()->GetInteger(name + ".input_channels", &input_channels);
+  EXPECT_EQ(params.input_channels(), input_channels);
+}
+
 TEST_F(MediaInternalsTest, UpdateAddsNewItem) {
   UpdateItem("some.item", "testing", new base::FundamentalValue(true));
   bool testing = false;
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc
index 58b3d3f..31deb44 100644
--- a/content/browser/media/webrtc_browsertest.cc
+++ b/content/browser/media/webrtc_browsertest.cc
@@ -8,7 +8,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -19,16 +19,21 @@
 
 namespace {
 
-std::string GenerateGetUserMediaCall(int min_width,
+static const char kGetUserMedia[] = "getUserMedia";
+static const char kGetUserMediaWithAnalysis[] = "getUserMediaWithAnalysis";
+
+std::string GenerateGetUserMediaCall(const char* function_name,
+                                     int min_width,
                                      int max_width,
                                      int min_height,
                                      int max_height,
                                      int min_frame_rate,
                                      int max_frame_rate) {
   return base::StringPrintf(
-      "getUserMedia({video: {mandatory: {minWidth: %d, maxWidth: %d, "
+      "%s({video: {mandatory: {minWidth: %d, maxWidth: %d, "
       "minHeight: %d, maxHeight: %d, minFrameRate: %d, maxFrameRate: %d}, "
       "optional: []}});",
+      function_name,
       min_width,
       max_width,
       min_height,
@@ -46,6 +51,10 @@
   virtual ~WebrtcBrowserTest() {}
 
   virtual void SetUpOnMainThread() OVERRIDE {
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+  }
+
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     // We need fake devices in this test since we want to run on naked VMs. We
     // assume these switches are set by default in content_browsertests.
     ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
@@ -53,7 +62,9 @@
     ASSERT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch(
         switches::kUseFakeUIForMediaStream));
 
-    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+    // The video playback will not work without a GPU, so force its use here.
+    // This may not be available on all VMs though.
+    command_line->AppendSwitch(switches::kUseGpuInTests);
   }
 
  protected:
@@ -258,19 +269,19 @@
 
   std::vector<std::string> list_of_get_user_media_calls;
   list_of_get_user_media_calls.push_back(
-      GenerateGetUserMediaCall(320, 320, 180, 180, 30, 30));
+      GenerateGetUserMediaCall(kGetUserMedia, 320, 320, 180, 180, 30, 30));
   list_of_get_user_media_calls.push_back(
-      GenerateGetUserMediaCall(320, 320, 240, 240, 30, 30));
+      GenerateGetUserMediaCall(kGetUserMedia, 320, 320, 240, 240, 30, 30));
   list_of_get_user_media_calls.push_back(
-      GenerateGetUserMediaCall(640, 640, 360, 360, 30, 30));
+      GenerateGetUserMediaCall(kGetUserMedia, 640, 640, 360, 360, 30, 30));
   list_of_get_user_media_calls.push_back(
-      GenerateGetUserMediaCall(640, 640, 480, 480, 30, 30));
+      GenerateGetUserMediaCall(kGetUserMedia, 640, 640, 480, 480, 30, 30));
   list_of_get_user_media_calls.push_back(
-      GenerateGetUserMediaCall(960, 960, 720, 720, 30, 30));
+      GenerateGetUserMediaCall(kGetUserMedia, 960, 960, 720, 720, 30, 30));
   list_of_get_user_media_calls.push_back(
-      GenerateGetUserMediaCall(1280, 1280, 720, 720, 30, 30));
+      GenerateGetUserMediaCall(kGetUserMedia, 1280, 1280, 720, 720, 30, 30));
   list_of_get_user_media_calls.push_back(
-      GenerateGetUserMediaCall(1920, 1920, 1080, 1080, 30, 30));
+      GenerateGetUserMediaCall(kGetUserMedia, 1920, 1920, 1080, 1080, 30, 30));
 
   for (std::vector<std::string>::iterator const_iterator =
            list_of_get_user_media_calls.begin();
@@ -283,6 +294,26 @@
   }
 }
 
+// This test calls getUserMedia and checks for aspect ratio behavior.
+IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, TestGetUserMediaAspectRatio) {
+  GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
+
+  std::string constraints_4_3 = GenerateGetUserMediaCall(
+      kGetUserMediaWithAnalysis, 640, 640, 480, 480, 30, 30);
+  std::string constraints_16_9 = GenerateGetUserMediaCall(
+      kGetUserMediaWithAnalysis, 640, 640, 360, 360, 30, 30);
+
+  // TODO(mcasas): add more aspect ratios, in particular 16:10 crbug.com/275594.
+
+  NavigateToURL(shell(), url);
+  EXPECT_TRUE(ExecuteJavascript(constraints_4_3));
+  ExpectTitle("4:3 letterbox");
+
+  NavigateToURL(shell(), url);
+  EXPECT_TRUE(ExecuteJavascript(constraints_16_9));
+  ExpectTitle("16:9 letterbox");
+}
+
 IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, AddTwoMediaStreamsToOnePC) {
   GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
   NavigateToURL(shell(), url);
diff --git a/content/browser/media/webrtc_identity_store_backend.cc b/content/browser/media/webrtc_identity_store_backend.cc
index a86cc20..9ec73e9 100644
--- a/content/browser/media/webrtc_identity_store_backend.cc
+++ b/content/browser/media/webrtc_identity_store_backend.cc
@@ -194,10 +194,13 @@
 
     // Kick off loading the DB.
     scoped_ptr<IdentityMap> out_map(new IdentityMap());
+    base::Closure task(
+        base::Bind(&SqlLiteStorage::Load, sql_lite_storage_, out_map.get()));
+    // |out_map| will be NULL after this call.
     if (BrowserThread::PostTaskAndReply(
             BrowserThread::DB,
             FROM_HERE,
-            base::Bind(&SqlLiteStorage::Load, sql_lite_storage_, out_map.get()),
+            task,
             base::Bind(&WebRTCIdentityStoreBackend::OnLoaded,
                        this,
                        base::Passed(&out_map)))) {
diff --git a/content/browser/media/webrtc_internals_browsertest.cc b/content/browser/media/webrtc_internals_browsertest.cc
index 19c2574..b458276 100644
--- a/content/browser/media/webrtc_internals_browsertest.cc
+++ b/content/browser/media/webrtc_internals_browsertest.cc
@@ -9,7 +9,7 @@
 #include "base/values.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -118,10 +118,17 @@
 
 static const int64 FAKE_TIME_STAMP = 3600000;
 
-class WebRTCInternalsBrowserTest: public ContentBrowserTest {
+#if defined(OS_WIN)
+// All tests are flaky on Windows: crbug.com/277322.
+#define MAYBE_WebRTCInternalsBrowserTest DISABLED_WebRTCInternalsBrowserTest
+#else
+#define MAYBE_WebRTCInternalsBrowserTest WebRTCInternalsBrowserTest
+#endif
+
+class MAYBE_WebRTCInternalsBrowserTest: public ContentBrowserTest {
  public:
-  WebRTCInternalsBrowserTest() {}
-  virtual ~WebRTCInternalsBrowserTest() {}
+  MAYBE_WebRTCInternalsBrowserTest() {}
+  virtual ~MAYBE_WebRTCInternalsBrowserTest() {}
 
   virtual void SetUpOnMainThread() OVERRIDE {
     // We need fake devices in this test since we want to run on naked VMs. We
@@ -395,7 +402,8 @@
   }
 };
 
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest, AddAndRemovePeerConnection) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest,
+                       AddAndRemovePeerConnection) {
   GURL url("chrome://webrtc-internals");
   NavigateToURL(shell(), url);
 
@@ -416,7 +424,8 @@
   VerifyNoElementWithId(pc_2.getIdString());
 }
 
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest, UpdateAllPeerConnections) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest,
+                       UpdateAllPeerConnections) {
   GURL url("chrome://webrtc-internals");
   NavigateToURL(shell(), url);
 
@@ -433,7 +442,7 @@
   VerifyPeerConnectionEntry(pc_1);
 }
 
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest, UpdatePeerConnection) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest, UpdatePeerConnection) {
   GURL url("chrome://webrtc-internals");
   NavigateToURL(shell(), url);
 
@@ -470,7 +479,7 @@
 }
 
 // Tests that adding random named stats updates the dataSeries and graphs.
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest, AddStats) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest, AddStats) {
   GURL url("chrome://webrtc-internals");
   NavigateToURL(shell(), url);
 
@@ -496,7 +505,7 @@
 }
 
 // Tests that the bandwidth estimation values are drawn on a single graph.
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest, BweCompoundGraph) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest, BweCompoundGraph) {
   GURL url("chrome://webrtc-internals");
   NavigateToURL(shell(), url);
 
@@ -536,7 +545,7 @@
 
 // Tests that the total packet/byte count is converted to count per second,
 // and the converted data is drawn.
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest, ConvertedGraphs) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest, ConvertedGraphs) {
   GURL url("chrome://webrtc-internals");
   NavigateToURL(shell(), url);
 
@@ -575,16 +584,11 @@
   }
 }
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
 // Timing out on ARM linux bot: http://crbug.com/238490
-#define MAYBE_WithRealPeerConnectionCall DISABLED_WithRealPeerConnectionCall
-#else
-#define MAYBE_WithRealPeerConnectionCall WithRealPeerConnectionCall
-#endif
-
+// Disabling due to failure on Linux, Mac, Win: http://crbug.com/272413
 // Sanity check of the page content under a real PeerConnection call.
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest,
-                       MAYBE_WithRealPeerConnectionCall) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest,
+                       DISABLED_WithRealPeerConnectionCall) {
   // Start a peerconnection call in the first window.
   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
   GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
@@ -666,7 +670,7 @@
   EXPECT_GT(count, 0);
 }
 
-IN_PROC_BROWSER_TEST_F(WebRTCInternalsBrowserTest, CreatePageDump) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRTCInternalsBrowserTest, CreatePageDump) {
   GURL url("chrome://webrtc-internals");
   NavigateToURL(shell(), url);
 
diff --git a/content/browser/mime_registry_message_filter.cc b/content/browser/mime_registry_message_filter.cc
index 49a0500..f23cc00 100644
--- a/content/browser/mime_registry_message_filter.cc
+++ b/content/browser/mime_registry_message_filter.cc
@@ -30,8 +30,6 @@
                         OnGetMimeTypeFromExtension)
     IPC_MESSAGE_HANDLER(MimeRegistryMsg_GetMimeTypeFromFile,
                         OnGetMimeTypeFromFile)
-    IPC_MESSAGE_HANDLER(MimeRegistryMsg_GetPreferredExtensionForMimeType,
-                        OnGetPreferredExtensionForMimeType)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -47,9 +45,4 @@
   net::GetMimeTypeFromFile(file_path, mime_type);
 }
 
-void MimeRegistryMessageFilter::OnGetPreferredExtensionForMimeType(
-    const std::string& mime_type, base::FilePath::StringType* extension) {
-  net::GetPreferredExtensionForMimeType(mime_type, extension);
-}
-
 }  // namespace content
diff --git a/content/browser/mime_registry_message_filter.h b/content/browser/mime_registry_message_filter.h
index 4a719a5..e86fe19 100644
--- a/content/browser/mime_registry_message_filter.h
+++ b/content/browser/mime_registry_message_filter.h
@@ -27,9 +27,6 @@
                                   std::string* mime_type);
   void OnGetMimeTypeFromFile(const base::FilePath& file_path,
                              std::string* mime_type);
-  void OnGetPreferredExtensionForMimeType(
-      const std::string& mime_type,
-      base::FilePath::StringType* extension);
 };
 
 }  // namespace content
diff --git a/content/browser/plugin_browsertest.cc b/content/browser/plugin_browsertest.cc
index c1dfa1f..37e1fa9 100644
--- a/content/browser/plugin_browsertest.cc
+++ b/content/browser/plugin_browsertest.cc
@@ -9,8 +9,8 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/shell/browser/shell.h"
 #include "content/shell/common/shell_switches.h"
-#include "content/shell/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "content/test/net/url_request_mock_http_job.h"
diff --git a/content/browser/plugin_data_remover_impl_browsertest.cc b/content/browser/plugin_data_remover_impl_browsertest.cc
index 37672ee..8308a51 100644
--- a/content/browser/plugin_data_remover_impl_browsertest.cc
+++ b/content/browser/plugin_data_remover_impl_browsertest.cc
@@ -11,7 +11,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 
 namespace content {
diff --git a/content/browser/plugin_service_impl_browsertest.cc b/content/browser/plugin_service_impl_browsertest.cc
index 1abf725..e99f3e5 100644
--- a/content/browser/plugin_service_impl_browsertest.cc
+++ b/content/browser/plugin_service_impl_browsertest.cc
@@ -15,7 +15,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
diff --git a/content/browser/power_save_blocker_chromeos.cc b/content/browser/power_save_blocker_chromeos.cc
index 9eda5c4..f9a6722 100644
--- a/content/browser/power_save_blocker_chromeos.cc
+++ b/content/browser/power_save_blocker_chromeos.cc
@@ -27,10 +27,8 @@
 
   void ApplyBlock() {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-    if (!chromeos::DBusThreadManager::IsInitialized()) {
-      LOG(WARNING) << "DBusThreadManager not initialized";
+    if (!chromeos::DBusThreadManager::IsInitialized())
       return;
-    }
 
     chromeos::PowerPolicyController* controller =
         chromeos::DBusThreadManager::Get()->GetPowerPolicyController();
@@ -48,10 +46,9 @@
 
   void RemoveBlock() {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-    if (!chromeos::DBusThreadManager::IsInitialized()) {
-      LOG(WARNING) << "DBusThreadManager not initialized";
+    if (!chromeos::DBusThreadManager::IsInitialized())
       return;
-    }
+
     chromeos::DBusThreadManager::Get()->GetPowerPolicyController()->
         RemoveWakeLock(block_id_);
   }
diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS
index 34decdb..0848d36 100644
--- a/content/browser/renderer_host/DEPS
+++ b/content/browser/renderer_host/DEPS
@@ -5,10 +5,6 @@
   "+third_party/zlib",
   "+third_party/libyuv",
 
-  # For single-process mode.
-  "+content/renderer/render_process_impl.h",
-  "+content/renderer/render_thread_impl.h",
-
   # The renderer_host files should only call upwards in the layering via the
   # delegate interfaces.
   "-content/browser/web_contents",
diff --git a/content/browser/renderer_host/backing_store_win.cc b/content/browser/renderer_host/backing_store_win.cc
index 5ccafbb..aea1985 100644
--- a/content/browser/renderer_host/backing_store_win.cc
+++ b/content/browser/renderer_host/backing_store_win.cc
@@ -104,6 +104,7 @@
     float scale_factor,
     const base::Closure& completion_callback,
     bool* scheduled_completion_callback) {
+  TRACE_EVENT0("content", "BackingStoreWin::PaintToBackingStore");
   *scheduled_completion_callback = false;
   gfx::Size size_in_pixels = gfx::ToCeiledSize(gfx::ScaleSize(
     size(), scale_factor));
@@ -155,6 +156,7 @@
 
 bool BackingStoreWin::CopyFromBackingStore(const gfx::Rect& rect,
                                            skia::PlatformBitmap* output) {
+  TRACE_EVENT0("content", "BackingStoreWin::CopyFromBackingStore");
   // TODO(kevers): Make sure this works with HiDPI backing stores.
   if (!output->Allocate(rect.width(), rect.height(), true))
     return false;
@@ -168,6 +170,7 @@
 void BackingStoreWin::ScrollBackingStore(const gfx::Vector2d& delta,
                                          const gfx::Rect& clip_rect,
                                          const gfx::Size& view_size) {
+  TRACE_EVENT0("content", "BackingStoreWin::ScrollBackingStore");
   // TODO(darin): this doesn't work if delta x() and y() are both non-zero!
   DCHECK(delta.x() == 0 || delta.y() == 0);
 
diff --git a/content/browser/renderer_host/clipboard_message_filter.cc b/content/browser/renderer_host/clipboard_message_filter.cc
index 46475df..2ad3546 100644
--- a/content/browser/renderer_host/clipboard_message_filter.cc
+++ b/content/browser/renderer_host/clipboard_message_filter.cc
@@ -198,7 +198,6 @@
     const SkBitmap& bitmap, IPC::Message* reply_msg) {
   base::SharedMemoryHandle image_handle = base::SharedMemory::NULLHandle();
   uint32 image_size = 0;
-  std::string reply_data;
   if (!bitmap.isNull()) {
     std::vector<unsigned char> png_data;
     SkAutoLockPixels lock(bitmap);
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 94ab139..359a6e1 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -26,6 +26,7 @@
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
 #include "content/browser/gpu/gpu_surface_tracker.h"
 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/gl_helper.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
@@ -37,6 +38,7 @@
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "ui/gfx/android/device_display_info.h"
 #include "ui/gfx/android/java_bitmap.h"
+#include "webkit/common/gpu/context_provider_in_process.h"
 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 
 namespace gfx {
@@ -48,8 +50,9 @@
 // Used for drawing directly to the screen. Bypasses resizing and swaps.
 class DirectOutputSurface : public cc::OutputSurface {
  public:
-  DirectOutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
-      : cc::OutputSurface(context3d.Pass()) {
+  DirectOutputSurface(
+      const scoped_refptr<cc::ContextProvider>& context_provider)
+      : cc::OutputSurface(context_provider) {
     capabilities_.adjust_deadline_for_parent = false;
   }
 
@@ -57,23 +60,26 @@
     surface_size_ = size;
   }
   virtual void SwapBuffers(cc::CompositorFrame*) OVERRIDE {
-    context3d()->shallowFlushCHROMIUM();
+    context_provider_->Context3d()->shallowFlushCHROMIUM();
   }
 };
 
 // Used to override capabilities_.adjust_deadline_for_parent to false
 class OutputSurfaceWithoutParent : public cc::OutputSurface {
  public:
-  OutputSurfaceWithoutParent(scoped_ptr<WebKit::WebGraphicsContext3D> context3d)
-      : cc::OutputSurface(context3d.Pass()) {
+  OutputSurfaceWithoutParent(
+      const scoped_refptr<
+        content::ContextProviderCommandBuffer>& context_provider)
+      : cc::OutputSurface(context_provider) {
     capabilities_.adjust_deadline_for_parent = false;
   }
 
   virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
-    content::WebGraphicsContext3DCommandBufferImpl* command_buffer =
-      static_cast<content::WebGraphicsContext3DCommandBufferImpl*>(context3d());
+    content::WebGraphicsContext3DCommandBufferImpl* command_buffer_context =
+        static_cast<content::WebGraphicsContext3DCommandBufferImpl*>(
+            context_provider_->Context3d());
     content::CommandBufferProxyImpl* command_buffer_proxy =
-        command_buffer->GetCommandBufferProxy();
+        command_buffer_context->GetCommandBufferProxy();
     DCHECK(command_buffer_proxy);
     command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
 
@@ -358,6 +364,41 @@
   return true;
 }
 
+static scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
+CreateGpuProcessViewContext(
+    const WebKit::WebGraphicsContext3D::Attributes attributes,
+    int surface_id,
+    base::WeakPtr<CompositorImpl> compositor_impl) {
+  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
+  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),
+          WebGraphicsContext3DCommandBufferImpl::kNoLimit
+  )) {
+    LOG(ERROR) << "Failed to create 3D context for compositor.";
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+  }
+  return context.Pass();
+}
+
 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
     bool fallback) {
   WebKit::WebGraphicsContext3D::Attributes attrs;
@@ -365,47 +406,33 @@
   attrs.noAutomaticFlushes = true;
 
   if (g_use_direct_gl) {
-    scoped_ptr<WebKit::WebGraphicsContext3D> context(
-        webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
-            CreateViewContext(attrs, window_));
-    if (!window_) {
-      return scoped_ptr<cc::OutputSurface>(
-          new DirectOutputSurface(context.Pass()));
-    }
+    using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+    scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d =
+        WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
+            attrs, window_);
+    scoped_refptr<webkit::gpu::ContextProviderInProcess> context_provider =
+        webkit::gpu::ContextProviderInProcess::Create(context3d.Pass());
 
-    return make_scoped_ptr(new cc::OutputSurface(context.Pass()));
-  } else {
-    DCHECK(window_ && surface_id_);
-    GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
-    GURL url("chrome://gpu/Compositor::createContext3D");
-    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
-        new WebGraphicsContext3DCommandBufferImpl(surface_id_,
-                                                  url,
-                                                  factory,
-                                                  weak_factory_.GetWeakPtr()));
-    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(
-        attrs,
-        false,
-        CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
-        64 * 1024,  // command buffer size
-        std::min(full_screen_texture_size_in_bytes,
-        kDefaultStartTransferBufferSize),
-        kDefaultMinTransferBufferSize,
-        std::min(3 * full_screen_texture_size_in_bytes,
-                 kDefaultMaxTransferBufferSize))) {
-      LOG(ERROR) << "Failed to create 3D context for compositor.";
-      return scoped_ptr<cc::OutputSurface>();
-    }
-    return scoped_ptr<cc::OutputSurface>(
-        new OutputSurfaceWithoutParent(
-            context.PassAs<WebKit::WebGraphicsContext3D>()));
+    scoped_ptr<cc::OutputSurface> output_surface;
+    if (!window_)
+      output_surface.reset(new DirectOutputSurface(context_provider));
+    else
+      output_surface.reset(new cc::OutputSurface(context_provider));
+    return output_surface.Pass();
   }
+
+  DCHECK(window_);
+  DCHECK(surface_id_);
+
+  scoped_refptr<ContextProviderCommandBuffer> context_provider =
+      ContextProviderCommandBuffer::Create(CreateGpuProcessViewContext(
+          attrs, surface_id_, weak_factory_.GetWeakPtr()));
+  if (!context_provider.get()) {
+    LOG(ERROR) << "Failed to create 3D context for compositor.";
+    return scoped_ptr<cc::OutputSurface>();
+  }
+  return scoped_ptr<cc::OutputSurface>(
+      new OutputSurfaceWithoutParent(context_provider));
 }
 
 void CompositorImpl::OnLostResources() {
diff --git a/content/browser/renderer_host/image_transport_factory_android.cc b/content/browser/renderer_host/image_transport_factory_android.cc
index efe9235..bc0d365 100644
--- a/content/browser/renderer_host/image_transport_factory_android.cc
+++ b/content/browser/renderer_host/image_transport_factory_android.cc
@@ -125,11 +125,12 @@
       false,
       CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
       64 * 1024,  // command buffer size
-      std::min(full_screen_texture_size_in_bytes,
-               kDefaultStartTransferBufferSize),
-      kDefaultMinTransferBufferSize,
+      64 * 1024,  // starting buffer size
+      64 * 1024,  // min buffer size
       std::min(3 * full_screen_texture_size_in_bytes,
-               kDefaultMaxTransferBufferSize));
+               kDefaultMaxTransferBufferSize),
+      WebGraphicsContext3DCommandBufferImpl::kNoLimit
+  );
 
   if (context_->makeContextCurrent())
     context_->pushGroupMarkerEXT(
diff --git a/content/browser/renderer_host/input/immediate_input_router.cc b/content/browser/renderer_host/input/immediate_input_router.cc
index 96e8bb9..368619c 100644
--- a/content/browser/renderer_host/input/immediate_input_router.cc
+++ b/content/browser/renderer_host/input/immediate_input_router.cc
@@ -85,6 +85,9 @@
       has_touch_handler_(false),
       touch_event_queue_(new TouchEventQueue(this)),
       gesture_event_filter_(new GestureEventFilter(this)) {
+  enable_no_touch_to_renderer_while_scrolling_ =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kNoTouchToRendererWhileScrolling) == "1";
   DCHECK(process);
   DCHECK(client);
 }
@@ -199,6 +202,7 @@
 
 void ImmediateInputRouter::SendGestureEvent(
     const GestureEventWithLatencyInfo& gesture_event) {
+  HandleGestureScroll(gesture_event);
   if (!client_->OnSendGestureEvent(gesture_event))
     return;
   FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
@@ -252,6 +256,7 @@
 
 void ImmediateInputRouter::SendGestureEventImmediately(
     const GestureEventWithLatencyInfo& gesture_event) {
+  HandleGestureScroll(gesture_event);
   if (!client_->OnSendGestureEventImmediately(gesture_event))
     return;
   FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
@@ -556,4 +561,19 @@
   touch_event_queue_->ProcessTouchAck(ack_result, latency_info);
 }
 
+void ImmediateInputRouter::HandleGestureScroll(
+    const GestureEventWithLatencyInfo& gesture_event) {
+  if (!enable_no_touch_to_renderer_while_scrolling_)
+    return;
+
+  // Once scrolling is started stop forwarding touch move events to renderer.
+  if (gesture_event.event.type == WebInputEvent::GestureScrollBegin)
+    touch_event_queue_->set_no_touch_move_to_renderer(true);
+
+  if (gesture_event.event.type == WebInputEvent::GestureScrollEnd ||
+      gesture_event.event.type == WebInputEvent::GestureFlingStart) {
+    touch_event_queue_->set_no_touch_move_to_renderer(false);
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/input/immediate_input_router.h b/content/browser/renderer_host/input/immediate_input_router.h
index 270ca3d..0bfa19f 100644
--- a/content/browser/renderer_host/input/immediate_input_router.h
+++ b/content/browser/renderer_host/input/immediate_input_router.h
@@ -73,6 +73,8 @@
   }
 
 private:
+  friend class ImmediateInputRouterTest;
+
   // TouchEventQueueClient
   virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
                                InputEventAckState ack_result) OVERRIDE;
@@ -127,6 +129,9 @@
   void ProcessTouchAck(InputEventAckState ack_result,
                        const ui::LatencyInfo& latency_info);
 
+  void HandleGestureScroll(
+      const GestureEventWithLatencyInfo& gesture_event);
+
   int routing_id() const { return routing_id_; }
 
 
@@ -186,6 +191,10 @@
   // not sent to the renderer.
   bool has_touch_handler_;
 
+  // Whether enabling the optimization that sending no touch move events to
+  // renderer while scrolling.
+  bool enable_no_touch_to_renderer_while_scrolling_;
+
   scoped_ptr<TouchEventQueue> touch_event_queue_;
   scoped_ptr<GestureEventFilter> gesture_event_filter_;
 
diff --git a/content/browser/renderer_host/input/immediate_input_router_unittest.cc b/content/browser/renderer_host/input/immediate_input_router_unittest.cc
index ed725ee..371e02e 100644
--- a/content/browser/renderer_host/input/immediate_input_router_unittest.cc
+++ b/content/browser/renderer_host/input/immediate_input_router_unittest.cc
@@ -548,6 +548,14 @@
     return touch_event_queue()->GetLatestEvent().event;
   }
 
+  void EnableNoTouchToRendererWhileScrolling() {
+    input_router_->enable_no_touch_to_renderer_while_scrolling_ = true;
+  }
+
+  bool no_touch_move_to_renderer() {
+    return touch_event_queue()->no_touch_move_to_renderer_;
+  }
+
   TouchEventQueue* touch_event_queue() const {
     return input_router_->touch_event_queue();
   }
@@ -2165,4 +2173,93 @@
   EXPECT_EQ(client_->acked_wheel_event().deltaY, -5);
 }
 
+// Tests that no touch move events are sent to renderer during scrolling.
+TEST_F(ImmediateInputRouterTest, NoTouchMoveWhileScroll) {
+  EnableNoTouchToRendererWhileScrolling();
+  set_debounce_interval_time_ms(0);
+  input_router_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true));
+  process_->sink().ClearMessages();
+
+  // First touch press.
+  PressTouchPoint(0, 1);
+  SendTouchEvent();
+  EXPECT_EQ(1U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::TouchStart,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  // Touch move will trigger scroll.
+  MoveTouchPoint(0, 20, 5);
+  SendTouchEvent();
+  EXPECT_EQ(1U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::TouchMove,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  SimulateGestureEvent(WebInputEvent::GestureScrollBegin,
+                       WebGestureEvent::Touchscreen);
+  EXPECT_EQ(1U, process_->sink().message_count());
+  EXPECT_TRUE(no_touch_move_to_renderer());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::GestureScrollBegin,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  // Touch move should not be sent to renderer.
+  MoveTouchPoint(0, 30, 5);
+  SendTouchEvent();
+  EXPECT_EQ(0U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+
+  // Touch moves become ScrollUpdate.
+  SimulateGestureScrollUpdateEvent(20, 4, 0);
+  EXPECT_TRUE(no_touch_move_to_renderer());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::GestureScrollUpdate,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  // Touch move should not be sent to renderer.
+  MoveTouchPoint(0, 65, 10);
+  SendTouchEvent();
+  EXPECT_EQ(0U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+
+  // Touch end should still be sent to renderer.
+  ReleaseTouchPoint(0);
+  SendTouchEvent();
+  EXPECT_EQ(1U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::TouchEnd,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  // On GestureScrollEnd, resume sending touch moves to renderer.
+  SimulateGestureEvent(WebKit::WebInputEvent::GestureScrollEnd,
+                       WebGestureEvent::Touchscreen);
+  EXPECT_EQ(1U, process_->sink().message_count());
+  EXPECT_FALSE(no_touch_move_to_renderer());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::GestureScrollEnd,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  // Now touch events should come through to renderer.
+  PressTouchPoint(80, 10);
+  SendTouchEvent();
+  EXPECT_EQ(1U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::TouchStart,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  MoveTouchPoint(0, 80, 20);
+  SendTouchEvent();
+  EXPECT_EQ(1U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::TouchMove,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+
+  ReleaseTouchPoint(0);
+  SendTouchEvent();
+  EXPECT_EQ(1U, process_->sink().message_count());
+  process_->sink().ClearMessages();
+  SendInputEventACK(WebInputEvent::TouchEnd,
+                    INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+}
 }  // namespace content
diff --git a/content/browser/renderer_host/input/touch_event_queue.cc b/content/browser/renderer_host/input/touch_event_queue.cc
index c1675b9..e22c05d 100644
--- a/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/content/browser/renderer_host/input/touch_event_queue.cc
@@ -91,7 +91,8 @@
 
 TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client)
     : client_(client),
-      dispatching_touch_ack_(false) {
+      dispatching_touch_ack_(false),
+      no_touch_move_to_renderer_(false) {
   DCHECK(client);
 }
 
@@ -212,6 +213,10 @@
   if (event.type == WebKit::WebInputEvent::TouchStart)
     return true;
 
+  if (event.type == WebKit::WebInputEvent::TouchMove &&
+      no_touch_move_to_renderer_)
+    return false;
+
   for (unsigned int i = 0; i < event.touchesLength; ++i) {
     const WebKit::WebTouchPoint& point = event.touches[i];
     // If a point has been stationary, then don't take it into account.
diff --git a/content/browser/renderer_host/input/touch_event_queue.h b/content/browser/renderer_host/input/touch_event_queue.h
index 23dda66..358fae9 100644
--- a/content/browser/renderer_host/input/touch_event_queue.h
+++ b/content/browser/renderer_host/input/touch_event_queue.h
@@ -61,6 +61,10 @@
     return touch_queue_.empty();
   }
 
+  void set_no_touch_move_to_renderer(bool value) {
+    no_touch_move_to_renderer_ = value;
+  }
+
  private:
   friend class MockRenderWidgetHost;
   friend class ImmediateInputRouterTest;
@@ -88,6 +92,11 @@
   // Used to defer touch forwarding when ack dispatch triggers |QueueEvent()|.
   bool dispatching_touch_ack_;
 
+  // Don't send touch move events to renderer. This is enabled when the page
+  // is scrolling. This behaviour is currently enabled only on aura behind a
+  // flag.
+  bool no_touch_move_to_renderer_;
+
   DISALLOW_COPY_AND_ASSIGN(TouchEventQueue);
 };
 
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc
index 4a2f731..1c02109 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -51,11 +51,12 @@
 AudioInputRendererHost::AudioInputRendererHost(
     media::AudioManager* audio_manager,
     MediaStreamManager* media_stream_manager,
-    AudioMirroringManager* audio_mirroring_manager)
+    AudioMirroringManager* audio_mirroring_manager,
+    media::UserInputMonitor* user_input_monitor)
     : audio_manager_(audio_manager),
       media_stream_manager_(media_stream_manager),
-      audio_mirroring_manager_(audio_mirroring_manager) {
-}
+      audio_mirroring_manager_(audio_mirroring_manager),
+      user_input_monitor_(user_input_monitor) {}
 
 AudioInputRendererHost::~AudioInputRendererHost() {
   DCHECK(audio_entries_.empty());
@@ -272,20 +273,23 @@
     entry->controller = media::AudioInputController::CreateForStream(
         audio_manager_->GetMessageLoop(),
         this,
-        WebContentsAudioInputStream::Create(
-            device_id, audio_params, audio_manager_->GetWorkerLoop(),
-            audio_mirroring_manager_),
-        entry->writer.get());
+        WebContentsAudioInputStream::Create(device_id,
+                                            audio_params,
+                                            audio_manager_->GetWorkerLoop(),
+                                            audio_mirroring_manager_),
+        entry->writer.get(),
+        user_input_monitor_);
   } else {
     // TODO(henrika): replace CreateLowLatency() with Create() as soon
     // as satish has ensured that Speech Input also uses the default low-
     // latency path. See crbug.com/112472 for details.
-    entry->controller = media::AudioInputController::CreateLowLatency(
-        audio_manager_,
-        this,
-        audio_params,
-        device_id,
-        entry->writer.get());
+    entry->controller =
+        media::AudioInputController::CreateLowLatency(audio_manager_,
+                                                      this,
+                                                      audio_params,
+                                                      device_id,
+                                                      entry->writer.get(),
+                                                      user_input_monitor_);
   }
 
   if (!entry->controller.get()) {
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.h b/content/browser/renderer_host/media/audio_input_renderer_host.h
index d16ebfa..5df1fc6 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.h
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.h
@@ -44,6 +44,7 @@
 namespace media {
 class AudioManager;
 class AudioParameters;
+class UserInputMonitor;
 }
 
 namespace content {
@@ -55,10 +56,11 @@
       public media::AudioInputController::EventHandler {
  public:
   // Called from UI thread from the owner of this object.
-  AudioInputRendererHost(
-      media::AudioManager* audio_manager,
-      MediaStreamManager* media_stream_manager,
-      AudioMirroringManager* audio_mirroring_manager);
+  // |user_input_monitor| is used for typing detection and can be NULL.
+  AudioInputRendererHost(media::AudioManager* audio_manager,
+                         MediaStreamManager* media_stream_manager,
+                         AudioMirroringManager* audio_mirroring_manager,
+                         media::UserInputMonitor* user_input_monitor);
 
   // BrowserMessageFilter implementation.
   virtual void OnChannelClosing() OVERRIDE;
@@ -154,6 +156,9 @@
   // A map of stream IDs to audio sources.
   AudioEntryMap audio_entries_;
 
+  // Raw pointer of the UserInputMonitor.
+  media::UserInputMonitor* user_input_monitor_;
+
   DISALLOW_COPY_AND_ASSIGN(AudioInputRendererHost);
 };
 
diff --git a/content/browser/renderer_host/media/audio_input_sync_writer.cc b/content/browser/renderer_host/media/audio_input_sync_writer.cc
index 572abf3..369e0a8 100644
--- a/content/browser/renderer_host/media/audio_input_sync_writer.cc
+++ b/content/browser/renderer_host/media/audio_input_sync_writer.cc
@@ -29,14 +29,17 @@
   socket_->Send(&bytes, sizeof(bytes));
 }
 
-uint32 AudioInputSyncWriter::Write(
-    const void* data, uint32 size, double volume) {
+uint32 AudioInputSyncWriter::Write(const void* data,
+                                   uint32 size,
+                                   double volume,
+                                   bool key_pressed) {
   uint8* ptr = static_cast<uint8*>(shared_memory_->memory());
   ptr += current_segment_id_ * shared_memory_segment_size_;
   media::AudioInputBuffer* buffer =
       reinterpret_cast<media::AudioInputBuffer*>(ptr);
   buffer->params.volume = volume;
   buffer->params.size = size;
+  buffer->params.key_pressed = key_pressed;
   memcpy(buffer->audio, data, size);
 
   if (++current_segment_id_ >= shared_memory_segment_count_)
diff --git a/content/browser/renderer_host/media/audio_input_sync_writer.h b/content/browser/renderer_host/media/audio_input_sync_writer.h
index 4cfe9e3..d16911f 100644
--- a/content/browser/renderer_host/media/audio_input_sync_writer.h
+++ b/content/browser/renderer_host/media/audio_input_sync_writer.h
@@ -28,7 +28,10 @@
 
   // media::AudioOutputController::SyncWriter implementation.
   virtual void UpdateRecordedBytes(uint32 bytes) OVERRIDE;
-  virtual uint32 Write(const void* data, uint32 size, double volume) OVERRIDE;
+  virtual uint32 Write(const void* data,
+                       uint32 size,
+                       double volume,
+                       bool key_pressed) OVERRIDE;
   virtual void Close() OVERRIDE;
 
   bool Init();
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
index 53f2eb2..dbfd0d5 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -354,8 +354,10 @@
         render_process_id_, entry->render_view_id(), entry->controller());
   }
   audio_entries_.insert(std::make_pair(stream_id, entry.release()));
-  if (media_internals_)
-    media_internals_->OnSetAudioStreamStatus(this, stream_id, "created");
+  if (media_internals_) {
+    media_internals_->OnAudioStreamCreated(
+        this, stream_id, params, input_device_id);
+  }
 }
 
 void AudioRendererHost::OnPlayStream(int stream_id) {
diff --git a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
index 42fecc0..26c0963 100644
--- a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc
@@ -207,8 +207,6 @@
   }
 
   void Create(bool unified_stream) {
-    EXPECT_CALL(*observer_,
-                OnSetAudioStreamStatus(_, kStreamId, "created"));
     EXPECT_CALL(*host_.get(), OnStreamCreated(kStreamId, _))
         .WillOnce(DoAll(Assign(&is_stream_active_, true),
                         QuitMessageLoop(message_loop_.get())));
diff --git a/content/browser/renderer_host/media/desktop_capture_device.cc b/content/browser/renderer_host/media/desktop_capture_device.cc
index 5a03e46..9549633 100644
--- a/content/browser/renderer_host/media/desktop_capture_device.cc
+++ b/content/browser/renderer_host/media/desktop_capture_device.cc
@@ -23,7 +23,19 @@
 namespace content {
 
 namespace {
+
 const int kBytesPerPixel = 4;
+
+webrtc::DesktopRect ComputeLetterboxRect(
+    const webrtc::DesktopSize& max_size,
+    const webrtc::DesktopSize& source_size) {
+  gfx::Rect result = media::ComputeLetterboxRegion(
+      gfx::Rect(0, 0, max_size.width(), max_size.height()),
+      gfx::Size(source_size.width(), source_size.height()));
+  return webrtc::DesktopRect::MakeLTRB(
+      result.x(), result.y(), result.right(), result.bottom());
+}
+
 }  // namespace
 
 class DesktopCaptureDevice::Core
@@ -34,8 +46,7 @@
        scoped_ptr<webrtc::DesktopCapturer> capturer);
 
   // Implementation of VideoCaptureDevice methods.
-  void Allocate(int width, int height,
-                int frame_rate,
+  void Allocate(const media::VideoCaptureCapability& capture_format,
                 EventHandler* event_handler);
   void Start();
   void Stop();
@@ -51,11 +62,16 @@
 
   // Helper methods that run on the |task_runner_|. Posted from the
   // corresponding public methods.
-  void DoAllocate(int width, int height, int frame_rate);
+  void DoAllocate(const media::VideoCaptureCapability& capture_format);
   void DoStart();
   void DoStop();
   void DoDeAllocate();
 
+  // Chooses new output properties based on the supplied source size and the
+  // properties requested to Allocate(), and dispatches OnFrameInfo[Changed]
+  // notifications.
+  void RefreshCaptureFormat(const webrtc::DesktopSize& frame_size);
+
   // Helper to schedule capture tasks.
   void ScheduleCaptureTimer();
 
@@ -78,24 +94,23 @@
   base::Lock event_handler_lock_;
   EventHandler* event_handler_;
 
-  // Requested size specified to Allocate().
-  webrtc::DesktopSize requested_size_;
+  // Requested video capture format (width, height, frame rate, etc).
+  media::VideoCaptureCapability requested_format_;
 
-  // Frame rate specified to Allocate().
-  int frame_rate_;
+  // Actual video capture format being generated.
+  media::VideoCaptureCapability capture_format_;
 
-  // Empty until the first frame has been captured, and the output dimensions
-  // chosen based on the capture frame's size, and any caller-supplied
-  // size constraints.
-  webrtc::DesktopSize output_size_;
-
-  // Size of the most recently received frame.
+  // Size of frame most recently captured from the source.
   webrtc::DesktopSize previous_frame_size_;
 
-  // DesktopFrame into which captured frames are scaled, if the source size does
-  // not match |output_size_|. If the source and output have the same dimensions
-  // then this is NULL.
-  scoped_ptr<webrtc::DesktopFrame> scaled_frame_;
+  // DesktopFrame into which captured frames are down-scaled and/or letterboxed,
+  // depending upon the caller's requested capture capabilities. If frames can
+  // be returned to the caller directly then this is NULL.
+  scoped_ptr<webrtc::DesktopFrame> output_frame_;
+
+  // Sub-rectangle of |output_frame_| into which the source will be scaled
+  // and/or letterboxed.
+  webrtc::DesktopRect output_rect_;
 
   // True between DoStart() and DoStop(). Can't just check |event_handler_|
   // because |event_handler_| is used on the caller thread.
@@ -125,12 +140,12 @@
 DesktopCaptureDevice::Core::~Core() {
 }
 
-void DesktopCaptureDevice::Core::Allocate(int width, int height,
-                                         int frame_rate,
-                                         EventHandler* event_handler) {
-  DCHECK_GT(width, 0);
-  DCHECK_GT(height, 0);
-  DCHECK_GT(frame_rate, 0);
+void DesktopCaptureDevice::Core::Allocate(
+    const media::VideoCaptureCapability& capture_format,
+    EventHandler* event_handler) {
+  DCHECK_GT(capture_format.width, 0);
+  DCHECK_GT(capture_format.height, 0);
+  DCHECK_GT(capture_format.frame_rate, 0);
 
   {
     base::AutoLock auto_lock(event_handler_lock_);
@@ -139,7 +154,7 @@
 
   task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&Core::DoAllocate, this, width, height, frame_rate));
+      base::Bind(&Core::DoAllocate, this, capture_format));
 }
 
 void DesktopCaptureDevice::Core::Start() {
@@ -180,95 +195,76 @@
 
   scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
 
-  // If an |output_size_| hasn't yet been chosen then choose one, based upon
-  // the source frame size and the requested size supplied to Allocate().
-  if (output_size_.is_empty()) {
-    // Treat the requested size as upper bounds on width & height.
-    // TODO(wez): Constraints should be passed from getUserMedia to Allocate.
-    output_size_.set(
-        std::min(frame->size().width(), requested_size_.width()),
-        std::min(frame->size().height(), requested_size_.height()));
-
-    // Inform the EventHandler of the output dimensions, format and frame rate.
-    media::VideoCaptureCapability caps;
-    caps.width = output_size_.width();
-    caps.height = output_size_.height();
-    caps.frame_rate = frame_rate_;
-    caps.color = media::VideoCaptureCapability::kARGB;
-    caps.expected_capture_delay =
-        base::Time::kMillisecondsPerSecond / frame_rate_;
-    caps.interlaced = false;
-
-    base::AutoLock auto_lock(event_handler_lock_);
-    if (event_handler_)
-      event_handler_->OnFrameInfo(caps);
-  }
+  // Handle initial frame size and size changes.
+  RefreshCaptureFormat(frame->size());
 
   if (!started_)
     return;
 
-  size_t output_bytes = output_size_.width() * output_size_.height() *
+  webrtc::DesktopSize output_size(capture_format_.width,
+                                  capture_format_.height);
+  size_t output_bytes = output_size.width() * output_size.height() *
       webrtc::DesktopFrame::kBytesPerPixel;
+  const uint8_t* output_data = NULL;
 
-  if (frame->size().equals(output_size_)) {
+  if (frame->size().equals(output_size)) {
     // If the captured frame matches the output size, we can return the pixel
     // data directly, without scaling.
-    scaled_frame_.reset();
+    output_data = frame->data();
+  } else {
+    // Otherwise we need to down-scale and/or letterbox to the target format.
 
-    base::AutoLock auto_lock(event_handler_lock_);
-    if (event_handler_) {
-      event_handler_->OnIncomingCapturedFrame(
-          frame->data(), output_bytes, base::Time::Now(), 0, false, false);
+    // Allocate a buffer of the correct size to scale the frame into.
+    // |output_frame_| is cleared whenever |output_rect_| changes, so we don't
+    // need to worry about clearing out stale pixel data in letterboxed areas.
+    if (!output_frame_) {
+      output_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
+      memset(output_frame_->data(), 0, output_bytes);
     }
-    return;
+    DCHECK(output_frame_->size().equals(output_size));
+
+    // TODO(wez): Optimize this to scale only changed portions of the output,
+    // using ARGBScaleClip().
+    uint8_t* output_rect_data = output_frame_->data() +
+        output_frame_->stride() * output_rect_.top() +
+        webrtc::DesktopFrame::kBytesPerPixel * output_rect_.left();
+    libyuv::ARGBScale(frame->data(), frame->stride(),
+                      frame->size().width(), frame->size().height(),
+                      output_rect_data, output_frame_->stride(),
+                      output_rect_.width(), output_rect_.height(),
+                      libyuv::kFilterBilinear);
+    output_data = output_frame_->data();
   }
 
-  // If the output size differs from the frame size (e.g. the source has changed
-  // from its original dimensions, or the caller specified size constraints)
-  // then we need to scale the image.
-  if (!scaled_frame_)
-    scaled_frame_.reset(new webrtc::BasicDesktopFrame(output_size_));
-  DCHECK(scaled_frame_->size().equals(output_size_));
-
-  // If the source frame size changed then clear |scaled_frame_|'s pixels.
-  if (!previous_frame_size_.equals(frame->size())) {
-    previous_frame_size_ = frame->size();
-    memset(scaled_frame_->data(), 0, output_bytes);
-  }
-
-  // Determine the output size preserving aspect, and center in output buffer.
-  gfx::Rect scaled_rect = media::ComputeLetterboxRegion(
-      gfx::Rect(0, 0, output_size_.width(), output_size_.height()),
-      gfx::Size(frame->size().width(), frame->size().height()));
-  uint8* scaled_data = scaled_frame_->data() +
-      scaled_frame_->stride() * scaled_rect.y() +
-      webrtc::DesktopFrame::kBytesPerPixel * scaled_rect.x();
-
-  // TODO(wez): Optimize this to scale only changed portions of the output,
-  // using ARGBScaleClip().
-  libyuv::ARGBScale(frame->data(), frame->stride(),
-                    frame->size().width(), frame->size().height(),
-                    scaled_data, scaled_frame_->stride(),
-                    scaled_rect.width(), scaled_rect.height(),
-                    libyuv::kFilterBilinear);
-
   base::AutoLock auto_lock(event_handler_lock_);
   if (event_handler_) {
-    event_handler_->OnIncomingCapturedFrame(
-        scaled_frame_->data(), output_bytes,
-        base::Time::Now(), 0, false, false);
+    event_handler_->OnIncomingCapturedFrame(output_data, output_bytes,
+                                            base::Time::Now(), 0, false, false);
   }
 }
 
-void DesktopCaptureDevice::Core::DoAllocate(int width,
-                                            int height,
-                                            int frame_rate) {
+void DesktopCaptureDevice::Core::DoAllocate(
+    const media::VideoCaptureCapability& capture_format) {
   DCHECK(task_runner_->RunsTasksOnCurrentThread());
   DCHECK(desktop_capturer_);
 
-  requested_size_.set(width, height);
-  output_size_.set(0, 0);
-  frame_rate_ = frame_rate;
+  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 ==
+      media::VariableResolutionVideoCaptureDevice) {
+    capture_format_.frame_size_type =
+        media::VariableResolutionVideoCaptureDevice;
+  }
+
+  // This capturer always outputs ARGB, non-interlaced.
+  capture_format_.color = media::VideoCaptureCapability::kARGB;
+  capture_format_.interlaced = false;
 
   desktop_capturer_->Start(this);
 
@@ -288,14 +284,63 @@
 void DesktopCaptureDevice::Core::DoStop() {
   DCHECK(task_runner_->RunsTasksOnCurrentThread());
   started_ = false;
-  scaled_frame_.reset();
+  output_frame_.reset();
+  previous_frame_size_.set(0, 0);
 }
 
 void DesktopCaptureDevice::Core::DoDeAllocate() {
   DCHECK(task_runner_->RunsTasksOnCurrentThread());
   DoStop();
   desktop_capturer_.reset();
-  output_size_.set(0, 0);
+}
+
+void DesktopCaptureDevice::Core::RefreshCaptureFormat(
+    const webrtc::DesktopSize& frame_size) {
+  if (previous_frame_size_.equals(frame_size))
+    return;
+
+  // Clear the output frame, if any, since it will either need resizing, or
+  // clearing of stale data in letterbox areas, anyway.
+  output_frame_.reset();
+
+  if (previous_frame_size_.is_empty() ||
+      requested_format_.frame_size_type ==
+          media::VariableResolutionVideoCaptureDevice) {
+    // If this is the first frame, or the receiver supports variable resolution
+    // then determine the output size by treating the requested width & height
+    // as maxima.
+    if (frame_size.width() > requested_format_.width ||
+        frame_size.height() > requested_format_.height) {
+      output_rect_ = ComputeLetterboxRect(
+          webrtc::DesktopSize(requested_format_.width,
+                              requested_format_.height),
+          frame_size);
+      output_rect_.Translate(-output_rect_.left(), -output_rect_.top());
+    } else {
+      output_rect_ = webrtc::DesktopRect::MakeSize(frame_size);
+    }
+    capture_format_.width = output_rect_.width();
+    capture_format_.height = output_rect_.height();
+
+    {
+      base::AutoLock auto_lock(event_handler_lock_);
+      if (event_handler_) {
+        if (previous_frame_size_.is_empty()) {
+          event_handler_->OnFrameInfo(capture_format_);
+        } else {
+          event_handler_->OnFrameInfoChanged(capture_format_);
+        }
+      }
+    }
+  } else {
+    // Otherwise the output frame size cannot change, so just scale and
+    // letterbox.
+    output_rect_ = ComputeLetterboxRect(
+        webrtc::DesktopSize(capture_format_.width, capture_format_.height),
+        frame_size);
+  }
+
+  previous_frame_size_ = frame_size;
 }
 
 void DesktopCaptureDevice::Core::ScheduleCaptureTimer() {
@@ -303,7 +348,7 @@
   capture_task_posted_ = true;
   task_runner_->PostDelayedTask(
       FROM_HERE, base::Bind(&Core::OnCaptureTimer, this),
-      base::TimeDelta::FromSeconds(1) / frame_rate_);
+      base::TimeDelta::FromSeconds(1) / capture_format_.frame_rate);
 }
 
 void DesktopCaptureDevice::Core::OnCaptureTimer() {
@@ -394,11 +439,8 @@
 
 void DesktopCaptureDevice::Allocate(
     const media::VideoCaptureCapability& capture_format,
-    EventHandler* observer) {
-  core_->Allocate(capture_format.width,
-                  capture_format.height,
-                  capture_format.frame_rate,
-                  observer);
+    EventHandler* event_handler) {
+  core_->Allocate(capture_format, event_handler);
 }
 
 void DesktopCaptureDevice::Start() {
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 0f14585..cf050f5 100644
--- a/content/browser/renderer_host/media/desktop_capture_device_unittest.cc
+++ b/content/browser/renderer_host/media/desktop_capture_device_unittest.cc
@@ -17,7 +17,9 @@
 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
 
 using ::testing::_;
+using ::testing::AnyNumber;
 using ::testing::DoAll;
+using ::testing::Expectation;
 using ::testing::InvokeWithoutArgs;
 using ::testing::SaveArg;
 
@@ -25,6 +27,10 @@
 
 namespace {
 
+MATCHER_P2(EqualsCaptureCapability, width, height, "") {
+  return arg.width == width && arg.height == height;
+}
+
 const int kTestFrameWidth1 = 100;
 const int kTestFrameHeight1 = 100;
 const int kTestFrameWidth2 = 200;
@@ -38,6 +44,8 @@
   MOCK_METHOD0(ReserveOutputBuffer, scoped_refptr<media::VideoFrame>());
   MOCK_METHOD0(OnError, void());
   MOCK_METHOD1(OnFrameInfo, void(const media::VideoCaptureCapability& info));
+  MOCK_METHOD1(OnFrameInfoChanged,
+      void(const media::VideoCaptureCapability& info));
   MOCK_METHOD6(OnIncomingCapturedFrame, void(const uint8* data,
                                              int length,
                                              base::Time timestamp,
@@ -141,8 +149,9 @@
   EXPECT_EQ(caps.width * caps.height * 4, frame_size);
 }
 
-// Test that screen capturer can handle resolution change without crashing.
-TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChange) {
+// Test that screen capturer behaves correctly if the source frame size changes
+// but the caller cannot cope with variable resolution output.
+TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
   FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
 
   DesktopCaptureDevice capture_device(
@@ -154,11 +163,14 @@
   int frame_size;
 
   MockFrameObserver frame_observer;
-  EXPECT_CALL(frame_observer, OnFrameInfo(_))
+  Expectation frame_info_called = EXPECT_CALL(frame_observer, OnFrameInfo(_))
       .WillOnce(SaveArg<0>(&caps));
+  EXPECT_CALL(frame_observer, OnFrameInfoChanged(_))
+      .Times(0);
   EXPECT_CALL(frame_observer, OnError())
       .Times(0);
   EXPECT_CALL(frame_observer, OnIncomingCapturedFrame(_, _, _, _, _, _))
+      .After(frame_info_called)
       .WillRepeatedly(DoAll(
           SaveArg<1>(&frame_size),
           InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
@@ -171,13 +183,16 @@
       0,
       false,
       media::ConstantResolutionVideoCaptureDevice);
+
   capture_device.Allocate(capture_format, &frame_observer);
   capture_device.Start();
-  // Capture first frame.
+
+  // Capture at least two frames, to ensure that the source frame size has
+  // changed while capturing.
   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
   done_event.Reset();
-  // Capture second frame.
   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+
   capture_device.Stop();
   capture_device.DeAllocate();
 
@@ -190,4 +205,67 @@
   EXPECT_EQ(caps.width * caps.height * 4, frame_size);
 }
 
+// Test that screen capturer behaves correctly if the source frame size changes
+// and the caller can cope with variable resolution output.
+TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
+  FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
+
+  DesktopCaptureDevice capture_device(
+      worker_pool_->GetSequencedTaskRunner(worker_pool_->GetSequenceToken()),
+      scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
+
+  media::VideoCaptureCapability caps;
+  base::WaitableEvent done_event(false, false);
+
+  MockFrameObserver frame_observer;
+  Expectation frame_info_called = EXPECT_CALL(frame_observer, OnFrameInfo(_))
+      .WillOnce(SaveArg<0>(&caps));
+  Expectation first_info_changed = EXPECT_CALL(frame_observer,
+      OnFrameInfoChanged(EqualsCaptureCapability(kTestFrameWidth2,
+                                                 kTestFrameHeight2)))
+      .After(frame_info_called);
+  Expectation second_info_changed = EXPECT_CALL(frame_observer,
+      OnFrameInfoChanged(EqualsCaptureCapability(kTestFrameWidth1,
+                                                 kTestFrameHeight1)))
+      .After(first_info_changed);
+  EXPECT_CALL(frame_observer, OnFrameInfoChanged(_))
+      .Times(AnyNumber())
+      .After(second_info_changed);
+  EXPECT_CALL(frame_observer, OnError())
+      .Times(0);
+  EXPECT_CALL(frame_observer, OnIncomingCapturedFrame(_, _, _, _, _, _))
+      .After(frame_info_called)
+      .WillRepeatedly(
+          InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal));
+
+  media::VideoCaptureCapability capture_format(
+      kTestFrameWidth2,
+      kTestFrameHeight2,
+      kFrameRate,
+      media::VideoCaptureCapability::kI420,
+      0,
+      false,
+      media::VariableResolutionVideoCaptureDevice);
+
+  capture_device.Allocate(capture_format, &frame_observer);
+  capture_device.Start();
+
+  // Capture at least three frames, to ensure that the source frame size has
+  // changed at least twice while capturing.
+  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+  done_event.Reset();
+  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+  done_event.Reset();
+  EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
+
+  capture_device.Stop();
+  capture_device.DeAllocate();
+
+  EXPECT_EQ(kTestFrameWidth1, caps.width);
+  EXPECT_EQ(kTestFrameHeight1, caps.height);
+  EXPECT_EQ(kFrameRate, caps.frame_rate);
+  EXPECT_EQ(media::VideoCaptureCapability::kARGB, caps.color);
+  EXPECT_FALSE(caps.interlaced);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/media/midi_host.cc b/content/browser/renderer_host/media/midi_host.cc
index 6ed473a..b0b0e76 100644
--- a/content/browser/renderer_host/media/midi_host.cc
+++ b/content/browser/renderer_host/media/midi_host.cc
@@ -94,6 +94,9 @@
   if (!midi_manager_)
     return;
 
+  if (data.empty())
+    return;
+
   base::AutoLock auto_lock(in_flight_lock_);
 
   // Sanity check that we won't send too much.
@@ -107,20 +110,15 @@
   // TODO(toyoshim): allow System Exclusive if browser has granted
   // this client access.  We'll likely need to pass a GURL
   // here to compare against our permissions.
-  if (data.size() > 0 && data[0] >= kSysExMessage)
+  if (data[0] >= kSysExMessage)
       return;
 
-#if defined(OS_ANDROID)
-  // TODO(toyoshim): figure out why data() method does not compile on Android.
-  NOTIMPLEMENTED();
-#else
   midi_manager_->DispatchSendMIDIData(
       this,
       port,
-      data.data(),
+      &data[0],
       data.size(),
       timestamp);
-#endif
 
   sent_bytes_in_flight_ += data.size();
 }
diff --git a/content/browser/renderer_host/p2p/OWNERS b/content/browser/renderer_host/p2p/OWNERS
index 17c3a1e..f12c2d6 100644
--- a/content/browser/renderer_host/p2p/OWNERS
+++ b/content/browser/renderer_host/p2p/OWNERS
@@ -1,2 +1,3 @@
-sergeyu@chromium.org
 hclam@chromium.org
+mallinath@chromium.org
+sergeyu@chromium.org
diff --git a/content/browser/renderer_host/p2p/socket_dispatcher_host.cc b/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
index f1249d5..2e0715f 100644
--- a/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
+++ b/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
@@ -51,7 +51,9 @@
 
     net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
     int result = resolver_.Resolve(
-        info, &addresses_,
+        info,
+        net::DEFAULT_PRIORITY,
+        &addresses_,
         base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone,
                    base::Unretained(this)),
         net::BoundNetLog());
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.cc b/content/browser/renderer_host/p2p/socket_host_tcp.cc
index 8e13bf8..314026e 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -136,7 +136,9 @@
     StartTls();
   } else {
     if (IsPseudoTlsClientSocket(type_)) {
-      socket_.reset(new jingle_glue::FakeSSLClientSocket(socket_.release()));
+      scoped_ptr<net::StreamSocket> transport_socket = socket_.Pass();
+      socket_.reset(
+          new jingle_glue::FakeSSLClientSocket(transport_socket.Pass()));
     }
 
     // If we are not doing TLS, we are ready to send data now.
@@ -155,7 +157,7 @@
 
   scoped_ptr<net::ClientSocketHandle> socket_handle(
       new net::ClientSocketHandle());
-  socket_handle->set_socket(socket_.release());
+  socket_handle->SetSocket(socket_.Pass());
 
   net::SSLClientSocketContext context;
   context.cert_verifier = url_context_->GetURLRequestContext()->cert_verifier();
@@ -171,8 +173,8 @@
       net::ClientSocketFactory::GetDefaultFactory();
   DCHECK(socket_factory);
 
-  socket_.reset(socket_factory->CreateSSLClientSocket(
-      socket_handle.release(), dest_host_port_pair, ssl_config, context));
+  socket_ = socket_factory->CreateSSLClientSocket(
+      socket_handle.Pass(), dest_host_port_pair, ssl_config, context);
   int status = socket_->Connect(
       base::Bind(&P2PSocketHostTcpBase::ProcessTlsConnectDone,
                  base::Unretained(this)));
diff --git a/content/browser/renderer_host/pepper/OWNERS b/content/browser/renderer_host/pepper/OWNERS
index dc19a03..33d4c55 100644
--- a/content/browser/renderer_host/pepper/OWNERS
+++ b/content/browser/renderer_host/pepper/OWNERS
@@ -1,3 +1,4 @@
+bbudge@chromium.org
 dmichael@chromium.org
 raymes@chromium.org
 yzshen@chromium.org
diff --git a/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h b/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h
index 994e9c2..e999579 100644
--- a/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h
+++ b/content/browser/renderer_host/pepper/pepper_external_file_ref_backend.h
@@ -68,6 +68,8 @@
   scoped_refptr<base::TaskRunner> task_runner_;
 
   base::WeakPtrFactory<PepperExternalFileRefBackend> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PepperExternalFileRefBackend);
 };
 
 }  // namespace content
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 1a10da7..42344be 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
@@ -58,11 +58,11 @@
                                                          PP_FileSystemType type)
     : ResourceHost(host->GetPpapiHost(), instance, resource),
       browser_ppapi_host_(host),
-      weak_factory_(this),
       type_(type),
       opened_(false),
       fs_context_(NULL),
-      called_open_(false) {
+      called_open_(false),
+      weak_factory_(this) {
 }
 
 PepperFileSystemBrowserHost::~PepperFileSystemBrowserHost() {
diff --git a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h
index 3eb146e..525dd06 100644
--- a/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h
+++ b/content/browser/renderer_host/pepper/pepper_file_system_browser_host.h
@@ -60,7 +60,6 @@
       const std::string& fsid);
 
   BrowserPpapiHost* browser_ppapi_host_;
-  base::WeakPtrFactory<PepperFileSystemBrowserHost> weak_factory_;
 
   PP_FileSystemType type_;
   bool opened_;  // whether open is successful.
@@ -68,6 +67,8 @@
   scoped_refptr<fileapi::FileSystemContext> fs_context_;
   bool called_open_;  // whether open has been called.
 
+  base::WeakPtrFactory<PepperFileSystemBrowserHost> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PepperFileSystemBrowserHost);
 };
 
diff --git a/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc b/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
index e0e17b3..d342ee7 100644
--- a/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_host_resolver_message_filter.cc
@@ -179,6 +179,7 @@
       new PepperLookupRequest<ReplyMessageContext>(
           host_resolver,
           request_info,
+          net::DEFAULT_PRIORITY,
           bound_info.release(),
           base::Bind(&PepperHostResolverMessageFilter::OnLookupFinished, this));
   lookup_request->Start();
diff --git a/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h b/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h
index fb8a6cf..197a1bc 100644
--- a/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h
+++ b/content/browser/renderer_host/pepper/pepper_internal_file_ref_backend.h
@@ -82,6 +82,8 @@
   mutable fileapi::FileSystemURL fs_url_;
 
   base::WeakPtrFactory<PepperInternalFileRefBackend> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PepperInternalFileRefBackend);
 };
 
 }  // namespace content
diff --git a/content/browser/renderer_host/pepper/pepper_lookup_request.h b/content/browser/renderer_host/pepper/pepper_lookup_request.h
index bcb9a60..da116fd 100644
--- a/content/browser/renderer_host/pepper/pepper_lookup_request.h
+++ b/content/browser/renderer_host/pepper/pepper_lookup_request.h
@@ -24,20 +24,23 @@
   // callback, when lookup will finish.
   PepperLookupRequest(net::HostResolver* resolver,
                       const net::HostResolver::RequestInfo& request_info,
+                      net::RequestPriority priority,
                       T* bound_info,
                       const LookupRequestCallback& callback)
       : resolver_(resolver),
         request_info_(request_info),
+        priority_(priority),
         bound_info_(bound_info),
-        callback_(callback) {
-  }
+        callback_(callback) {}
 
   void Start() {
-    int result = resolver_.Resolve(
-        request_info_, &addresses_,
-        base::Bind(&PepperLookupRequest<T>::OnLookupFinished,
-                   base::Unretained(this)),
-        net::BoundNetLog());
+    int result =
+        resolver_.Resolve(request_info_,
+                          priority_,
+                          &addresses_,
+                          base::Bind(&PepperLookupRequest<T>::OnLookupFinished,
+                                     base::Unretained(this)),
+                          net::BoundNetLog());
     if (result != net::ERR_IO_PENDING)
       OnLookupFinished(result);
   }
@@ -50,6 +53,7 @@
 
   net::SingleRequestHostResolver resolver_;
   net::HostResolver::RequestInfo request_info_;
+  net::RequestPriority priority_;
   scoped_ptr<T> bound_info_;
   LookupRequestCallback callback_;
 
diff --git a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
index a5b95ce..630dda0 100644
--- a/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
+++ b/content/browser/renderer_host/pepper/pepper_renderer_connection.cc
@@ -72,8 +72,8 @@
 
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP_EX(PepperRendererConnection, msg, *message_was_ok)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_CreateResourceHostFromHost,
-                        OnMsgCreateResourceHostFromHost)
+    IPC_MESSAGE_HANDLER(PpapiHostMsg_CreateResourceHostsFromHost,
+                        OnMsgCreateResourceHostsFromHost)
     IPC_MESSAGE_HANDLER(PpapiHostMsg_FileRef_GetInfoForRenderer,
                         OnMsgFileRefGetInfoForRenderer)
     IPC_MESSAGE_HANDLER(ViewHostMsg_DidCreateInProcessInstance,
@@ -86,45 +86,48 @@
   return handled;
 }
 
-void PepperRendererConnection::OnMsgCreateResourceHostFromHost(
+void PepperRendererConnection::OnMsgCreateResourceHostsFromHost(
     int routing_id,
     int child_process_id,
     const ppapi::proxy::ResourceMessageCallParams& params,
     PP_Instance instance,
-    const IPC::Message& nested_msg) {
+    const std::vector<IPC::Message>& nested_msgs) {
   BrowserPpapiHostImpl* host = GetHostForChildProcess(child_process_id);
 
-  int pending_resource_host_id;
+  std::vector<int> pending_resource_host_ids(nested_msgs.size(), 0);
   if (!host) {
     DLOG(ERROR) << "Invalid plugin process ID.";
-    pending_resource_host_id = 0;
   } else {
-    // FileRef_CreateExternal is only permitted from the renderer. Because of
-    // this, we handle this message here and not in
-    // content_browser_pepper_host_factory.cc.
-    scoped_ptr<ppapi::host::ResourceHost> resource_host;
-    if (host->IsValidInstance(instance)) {
-      if (nested_msg.type() == PpapiHostMsg_FileRef_CreateExternal::ID) {
-        base::FilePath external_path;
-        if (ppapi::UnpackMessage<PpapiHostMsg_FileRef_CreateExternal>(
-            nested_msg, &external_path)) {
-          resource_host.reset(new PepperFileRefHost(
-              host, instance, params.pp_resource(), external_path));
+    for (size_t i = 0; i < nested_msgs.size(); ++i) {
+      // FileRef_CreateExternal is only permitted from the renderer. Because of
+      // this, we handle this message here and not in
+      // content_browser_pepper_host_factory.cc.
+      scoped_ptr<ppapi::host::ResourceHost> resource_host;
+      if (host->IsValidInstance(instance)) {
+        if (nested_msgs[i].type() == PpapiHostMsg_FileRef_CreateExternal::ID) {
+          base::FilePath external_path;
+          if (ppapi::UnpackMessage<PpapiHostMsg_FileRef_CreateExternal>(
+              nested_msgs[i], &external_path)) {
+            resource_host.reset(new PepperFileRefHost(
+                host, instance, params.pp_resource(), external_path));
+          }
         }
       }
-    }
 
-    if (!resource_host.get()) {
-      resource_host = host->GetPpapiHost()->CreateResourceHost(params,
-                                                               instance,
-                                                               nested_msg);
+      if (!resource_host.get()) {
+        resource_host = host->GetPpapiHost()->CreateResourceHost(
+            params, instance, nested_msgs[i]);
+      }
+
+      if (resource_host.get()) {
+        pending_resource_host_ids[i] =
+            host->GetPpapiHost()->AddPendingResourceHost(resource_host.Pass());
+      }
     }
-    pending_resource_host_id =
-        host->GetPpapiHost()->AddPendingResourceHost(resource_host.Pass());
   }
 
-  Send(new PpapiHostMsg_CreateResourceHostFromHostReply(
-       routing_id, params.sequence(), pending_resource_host_id));
+  Send(new PpapiHostMsg_CreateResourceHostsFromHostReply(
+       routing_id, params.sequence(), pending_resource_host_ids));
 }
 
 void PepperRendererConnection::OnMsgFileRefGetInfoForRenderer(
diff --git a/content/browser/renderer_host/pepper/pepper_renderer_connection.h b/content/browser/renderer_host/pepper/pepper_renderer_connection.h
index 4392346..24cbc2c 100644
--- a/content/browser/renderer_host/pepper/pepper_renderer_connection.h
+++ b/content/browser/renderer_host/pepper/pepper_renderer_connection.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_RENDERER_CONNECTION_H_
 #define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_RENDERER_CONNECTION_H_
 
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
@@ -45,12 +47,12 @@
   // PepperRendererConnection, which serves as the host for in-process plugins.
   BrowserPpapiHostImpl* GetHostForChildProcess(int child_process_id) const;
 
-  void OnMsgCreateResourceHostFromHost(
+  void OnMsgCreateResourceHostsFromHost(
       int routing_id,
       int child_process_id,
       const ppapi::proxy::ResourceMessageCallParams& params,
       PP_Instance instance,
-      const IPC::Message& nested_msg);
+      const std::vector<IPC::Message>& nested_msgs);
 
   void OnMsgFileRefGetInfoForRenderer(
       int routing_id,
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket.cc
index f05be87..c5b752a 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket.cc
@@ -87,10 +87,12 @@
 
   connection_state_ = CONNECT_IN_PROGRESS;
   net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port));
-  resolver_.reset(new net::SingleRequestHostResolver(
-      manager_->GetHostResolver()));
+  resolver_.reset(
+      new net::SingleRequestHostResolver(manager_->GetHostResolver()));
   int net_result = resolver_->Resolve(
-      request_info, &address_list_,
+      request_info,
+      net::DEFAULT_PRIORITY,
+      &address_list_,
       base::Bind(&PepperTCPSocket::OnResolveCompleted, base::Unretained(this)),
       net::BoundNetLog());
   if (net_result != net::ERR_IO_PENDING)
@@ -141,16 +143,16 @@
   connection_state_ = SSL_HANDSHAKE_IN_PROGRESS;
   // TODO(raymes,rsleevi): Use trusted/untrusted certificates when connecting.
 
-  net::ClientSocketHandle* handle = new net::ClientSocketHandle();
-  handle->set_socket(socket_.release());
+  scoped_ptr<net::ClientSocketHandle> handle(new net::ClientSocketHandle());
+  handle->SetSocket(socket_.Pass());
   net::ClientSocketFactory* factory =
       net::ClientSocketFactory::GetDefaultFactory();
   net::HostPortPair host_port_pair(server_name, server_port);
   net::SSLClientSocketContext ssl_context;
   ssl_context.cert_verifier = manager_->GetCertVerifier();
   ssl_context.transport_security_state = manager_->GetTransportSecurityState();
-  socket_.reset(factory->CreateSSLClientSocket(
-      handle, host_port_pair, manager_->ssl_config(), ssl_context));
+  socket_ = factory->CreateSSLClientSocket(
+      handle.Pass(), host_port_pair, manager_->ssl_config(), ssl_context);
   if (!socket_) {
     LOG(WARNING) << "Failed to create an SSL client socket.";
     OnSSLHandshakeCompleted(net::ERR_UNEXPECTED);
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc
index 9ee8036..de64924 100644
--- a/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -8,7 +8,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_notification_tracker.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 2dd784a..39b3eda 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -52,6 +52,7 @@
 #include "content/browser/fileapi/chrome_blob_storage_context.h"
 #include "content/browser/fileapi/fileapi_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"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/gpu/shader_disk_cache.h"
@@ -118,8 +119,6 @@
 #include "content/public/common/process_type.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/common/url_constants.h"
-#include "content/renderer/render_process_impl.h"
-#include "content/renderer/render_thread_impl.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "ipc/ipc_channel.h"
 #include "ipc/ipc_logging.h"
@@ -157,8 +156,6 @@
 namespace content {
 namespace {
 
-base::MessageLoop* g_in_process_thread;
-
 void CacheShaderInfo(int32 id, base::FilePath path) {
   ShaderCacheFactory::GetInstance()->SetCacheInfo(id, path);
 }
@@ -167,57 +164,6 @@
   ShaderCacheFactory::GetInstance()->RemoveCacheInfo(id);
 }
 
-}  // namespace
-
-#if !defined(CHROME_MULTIPLE_DLL)
-
-// This class creates the IO thread for the renderer when running in
-// single-process mode.  It's not used in multi-process mode.
-class RendererMainThread : public base::Thread {
- public:
-  explicit RendererMainThread(const std::string& channel_id)
-      : Thread("Chrome_InProcRendererThread"),
-        channel_id_(channel_id) {
-  }
-
-  virtual ~RendererMainThread() {
-    Stop();
-  }
-
- protected:
-  virtual void Init() OVERRIDE {
-    render_process_.reset(new RenderProcessImpl());
-    new RenderThreadImpl(channel_id_);
-    g_in_process_thread = message_loop();
-  }
-
-  virtual void CleanUp() OVERRIDE {
-    g_in_process_thread = NULL;
-    render_process_.reset();
-
-    // It's a little lame to manually set this flag.  But the single process
-    // RendererThread will receive the WM_QUIT.  We don't need to assert on
-    // this thread, so just force the flag manually.
-    // If we want to avoid this, we could create the InProcRendererThread
-    // directly with _beginthreadex() rather than using the Thread class.
-    // We used to set this flag in the Init function above. However there
-    // other threads like WebThread which are created by this thread
-    // which resets this flag. Please see Thread::StartWithOptions. Setting
-    // this flag to true in Cleanup works around these problems.
-    SetThreadWasQuitProperly(true);
-  }
-
- private:
-  std::string channel_id_;
-  scoped_ptr<RenderProcess> render_process_;
-
-  DISALLOW_COPY_AND_ASSIGN(RendererMainThread);
-};
-
-#endif
-
-namespace {
-
 // Helper class that we pass to ResourceMessageFilter so that it can find the
 // right net::URLRequestContext for a request.
 class RendererURLRequestContextSelector
@@ -339,6 +285,20 @@
 
 }  // namespace
 
+RendererMainThreadFactoryFunction g_renderer_main_thread_factory = NULL;
+
+void RenderProcessHost::RegisterRendererMainThreadFactory(
+    RendererMainThreadFactoryFunction create) {
+  g_renderer_main_thread_factory = create;
+}
+
+base::MessageLoop* g_in_process_thread;
+
+base::MessageLoop*
+    RenderProcessHostImpl::GetInProcessRendererThreadForTesting() {
+  return g_in_process_thread;
+}
+
 // Stores the maximum number of renderer processes the content module can
 // create.
 static size_t g_max_renderer_count_override = 0;
@@ -511,15 +471,14 @@
   CreateMessageFilters();
 
   // Single-process mode not supported in multiple-dll mode currently.
-#if !defined(CHROME_MULTIPLE_DLL)
-  if (run_renderer_in_process()) {
+  if (run_renderer_in_process() && g_renderer_main_thread_factory) {
     // Crank up a thread and run the initialization there.  With the way that
     // messages flow between the browser and renderer, this thread is required
     // to prevent a deadlock in single-process mode.  Since the primordial
     // thread in the renderer process runs the WebKit code and can sometimes
     // make blocking calls to the UI thread (i.e. this thread), they need to run
     // on separate threads.
-    in_process_renderer_.reset(new RendererMainThread(channel_id));
+    in_process_renderer_.reset(g_renderer_main_thread_factory(channel_id));
 
     base::Thread::Options options;
 #if defined(OS_WIN) && !defined(OS_MACOSX)
@@ -532,10 +491,10 @@
 #endif
     in_process_renderer_->StartWithOptions(options);
 
+    g_in_process_thread = in_process_renderer_->message_loop();
+
     OnProcessLaunched();  // Fake a callback that the process is ready.
-  } else
-#endif  // !CHROME_MULTIPLE_DLL
-  {
+  } else {
     // Build command line for renderer.  We call AppendRendererCommandLine()
     // first so the process type argument will appear first.
     CommandLine* cmd_line = new CommandLine(renderer_path);
@@ -617,11 +576,14 @@
   channel_->AddFilter(new AudioInputRendererHost(
       audio_manager,
       media_stream_manager,
-      BrowserMainLoop::GetInstance()->audio_mirroring_manager()));
-  channel_->AddFilter(new AudioRendererHost(
-      GetID(), audio_manager,
       BrowserMainLoop::GetInstance()->audio_mirroring_manager(),
-      media_internals, media_stream_manager));
+      BrowserMainLoop::GetInstance()->user_input_monitor()));
+  channel_->AddFilter(new AudioRendererHost(
+      GetID(),
+      audio_manager,
+      BrowserMainLoop::GetInstance()->audio_mirroring_manager(),
+      media_internals,
+      media_stream_manager));
   channel_->AddFilter(
       new MIDIHost(BrowserMainLoop::GetInstance()->midi_manager()));
   channel_->AddFilter(new MIDIDispatcherHost(GetID(), browser_context));
@@ -856,6 +818,9 @@
                                     field_trial_states);
   }
 
+  if (content::IsThreadedCompositingEnabled())
+    command_line->AppendSwitch(switches::kEnableThreadedCompositing);
+
   GetContentClient()->browser()->AppendExtraCommandLineSwitches(
       command_line, GetID());
 
@@ -943,6 +908,7 @@
     switches::kEnableWebRtcAecRecordings,
     switches::kEnableWebRtcTcpServerSocket,
     switches::kEnableWebRtcHWDecoding,
+    switches::kEnableWebRtcHWEncoding,
 #endif
     switches::kDisableWebKitMediaSource,
     switches::kEnableOverscrollNotifications,
@@ -1613,11 +1579,6 @@
     map->RegisterProcess(site, process);
 }
 
-base::MessageLoop*
-    RenderProcessHostImpl::GetInProcessRendererThreadForTesting() {
-  return g_in_process_thread;
-}
-
 void RenderProcessHostImpl::ProcessDied(bool already_dead) {
   // Our child process has died.  If we didn't expect it, it's a crash.
   // In any case, we need to let everyone know it's gone.
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 72ec846..9d195f5 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -264,10 +264,8 @@
   // This is used to clear our cache five seconds after the last use.
   base::DelayTimer<RenderProcessHostImpl> cached_dibs_cleaner_;
 
-#if !defined(CHROME_MULTIPLE_DLL)
   // Used in single-process mode.
-  scoped_ptr<RendererMainThread> in_process_renderer_;
-#endif
+  scoped_ptr<base::Thread> in_process_renderer_;
 
   // True after Init() has been called. We can't just check channel_ because we
   // also reset that in the case of process termination.
diff --git a/content/browser/renderer_host/render_view_host_browsertest.cc b/content/browser/renderer_host/render_view_host_browsertest.cc
index 4255d05..20fec72 100644
--- a/content/browser/renderer_host/render_view_host_browsertest.cc
+++ b/content/browser/renderer_host/render_view_host_browsertest.cc
@@ -13,7 +13,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/host_port_pair.h"
diff --git a/content/browser/renderer_host/render_view_host_delegate.cc b/content/browser/renderer_host/render_view_host_delegate.cc
index 5ef5dc0..7bc3753 100644
--- a/content/browser/renderer_host/render_view_host_delegate.cc
+++ b/content/browser/renderer_host/render_view_host_delegate.cc
@@ -25,7 +25,7 @@
 
 bool RenderViewHostDelegate::AddMessageToConsole(
     int32 level, const string16& message, int32 line_no,
-    const string16& source_id) {
+    const string16& source_id, const string16& stack_trace) {
   return false;
 }
 
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 5ce2a44..21b22b3 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -274,7 +274,8 @@
   virtual bool AddMessageToConsole(int32 level,
                                    const string16& message,
                                    int32 line_no,
-                                   const string16& source_id);
+                                   const string16& source_id,
+                                   const string16& stack_trace);
 
   // Return a dummy RendererPreferences object that will be used by the renderer
   // associated with the owning RenderViewHost.
@@ -299,6 +300,7 @@
   // Notification that the renderer has become unresponsive. The
   // delegate can use this notification to show a warning to the user.
   virtual void RendererUnresponsive(RenderViewHost* render_view_host,
+                                    bool is_during_before_unload,
                                     bool is_during_unload) {}
 
   // Notification that a previously unresponsive renderer has become
diff --git a/content/browser/renderer_host/render_view_host_factory.cc b/content/browser/renderer_host/render_view_host_factory.cc
index 20d15d3..5cffd13 100644
--- a/content/browser/renderer_host/render_view_host_factory.cc
+++ b/content/browser/renderer_host/render_view_host_factory.cc
@@ -19,14 +19,15 @@
     RenderWidgetHostDelegate* widget_delegate,
     int routing_id,
     int main_frame_routing_id,
-    bool swapped_out) {
+    bool swapped_out,
+    bool hidden) {
   if (factory_) {
     return factory_->CreateRenderViewHost(instance, delegate, widget_delegate,
                                           routing_id, main_frame_routing_id,
                                           swapped_out);
   }
   return new RenderViewHostImpl(instance, delegate, widget_delegate, routing_id,
-                                main_frame_routing_id, swapped_out);
+                                main_frame_routing_id, swapped_out, hidden);
 }
 
 // static
diff --git a/content/browser/renderer_host/render_view_host_factory.h b/content/browser/renderer_host/render_view_host_factory.h
index 6226187..b046635 100644
--- a/content/browser/renderer_host/render_view_host_factory.h
+++ b/content/browser/renderer_host/render_view_host_factory.h
@@ -29,7 +29,8 @@
       RenderWidgetHostDelegate* widget_delegate,
       int routing_id,
       int main_frame_routing_id,
-      bool swapped_out);
+      bool swapped_out,
+      bool hidden);
 
   // Returns true if there is currently a globally-registered factory.
   static bool has_factory() {
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 56801c0..c841f28 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -153,8 +153,12 @@
     RenderWidgetHostDelegate* widget_delegate,
     int routing_id,
     int main_frame_routing_id,
-    bool swapped_out)
-    : RenderWidgetHostImpl(widget_delegate, instance->GetProcess(), routing_id),
+    bool swapped_out,
+    bool hidden)
+    : RenderWidgetHostImpl(widget_delegate,
+                           instance->GetProcess(),
+                           routing_id,
+                           hidden),
       delegate_(delegate),
       instance_(static_cast<SiteInstanceImpl*>(instance)),
       waiting_for_drag_context_response_(false),
@@ -259,6 +263,7 @@
   // Ensure the RenderView sets its opener correctly.
   params.opener_route_id = opener_route_id;
   params.swapped_out = is_swapped_out_;
+  params.hidden = is_hidden();
   params.next_page_id = next_page_id;
   GetWebScreenInfo(&params.screen_info);
   params.accessibility_mode = accessibility_mode();
@@ -338,7 +343,7 @@
   //
   // WebKit doesn't send throb notifications for JavaScript URLs, so we
   // don't want to either.
-  if (!params.url.SchemeIs(chrome::kJavaScriptScheme))
+  if (!params.url.SchemeIs(kJavaScriptScheme))
     delegate_->DidStartLoading(this);
 
   FOR_EACH_OBSERVER(RenderViewHostObserver, observers_, Navigate(params.url));
@@ -736,7 +741,8 @@
   // This must be done after sending the reply since RenderView can't close
   // correctly while waiting for a response.
   if (is_waiting && are_javascript_messages_suppressed_)
-    delegate_->RendererUnresponsive(this, is_waiting);
+    delegate_->RendererUnresponsive(
+        this, is_waiting_for_beforeunload_ack_, is_waiting_for_unload_ack_);
 }
 
 void RenderViewHostImpl::DragSourceEndedAt(
@@ -763,6 +769,12 @@
 }
 
 void RenderViewHostImpl::AllowBindings(int bindings_flags) {
+  // Never grant any bindings to browser plugin guests.
+  if (GetProcess()->IsGuest()) {
+    NOTREACHED() << "Never grant bindings to a guest process.";
+    return;
+  }
+
   // Ensure we aren't granting WebUI bindings to a process that has already
   // been used for non-privileged views.
   if (bindings_flags & BINDINGS_POLICY_WEB_UI &&
@@ -777,12 +789,6 @@
       return;
   }
 
-  // Never grant any bindings to browser plugin guests.
-  if (GetProcess()->IsGuest()) {
-    NOTREACHED() << "Never grant bindings to a guest process.";
-    return;
-  }
-
   if (bindings_flags & BINDINGS_POLICY_WEB_UI) {
     ChildProcessSecurityPolicyImpl::GetInstance()->GrantWebUIBindings(
         GetProcess()->GetID());
@@ -1239,8 +1245,6 @@
     FilterURL(policy, process, false, &(*it));
   }
   FilterURL(policy, process, true, &validated_params.searchable_form_url);
-  FilterURL(policy, process, true, &validated_params.password_form.origin);
-  FilterURL(policy, process, true, &validated_params.password_form.action);
 
   // Without this check, the renderer can trick the browser into using
   // filenames it can't access in a future session restore.
@@ -1464,7 +1468,7 @@
       ChildProcessSecurityPolicyImpl::GetInstance();
 
   // Allow drag of Javascript URLs to enable bookmarklet drag to bookmark bar.
-  if (!filtered_data.url.SchemeIs(chrome::kJavaScriptScheme))
+  if (!filtered_data.url.SchemeIs(kJavaScriptScheme))
     FilterURL(policy, process, true, &filtered_data.url);
   FilterURL(policy, process, false, &filtered_data.html_base_url);
   // Filter out any paths that the renderer didn't have access to. This prevents
@@ -1519,9 +1523,12 @@
     int32 level,
     const string16& message,
     int32 line_no,
-    const string16& source_id) {
-  if (delegate_->AddMessageToConsole(level, message, line_no, source_id))
+    const string16& source_id,
+    const string16& stack_trace) {
+  if (delegate_->AddMessageToConsole(
+          level, message, line_no, source_id, stack_trace)) {
     return;
+  }
   // Pass through log level only on WebUI pages to limit console spew.
   int32 resolved_level = HasWebUIScheme(delegate_->GetURL()) ? level : 0;
 
@@ -1595,7 +1602,7 @@
 
 void RenderViewHostImpl::NotifyRendererUnresponsive() {
   delegate_->RendererUnresponsive(
-      this, is_waiting_for_beforeunload_ack_ || is_waiting_for_unload_ack_);
+      this, is_waiting_for_beforeunload_ack_, is_waiting_for_unload_ack_);
 }
 
 void RenderViewHostImpl::NotifyRendererResponsive() {
@@ -1953,7 +1960,7 @@
   // allows unwanted cross-domain access.
   GURL url = params.contents_url;
   if (params.is_html &&
-      (url.SchemeIs(chrome::kJavaScriptScheme) ||
+      (url.SchemeIs(kJavaScriptScheme) ||
        url.SchemeIs(chrome::kFileScheme))) {
     return;
   }
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 20caaf5..91353d5 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -110,7 +110,8 @@
   // |routing_id| could be a valid route id, or it could be MSG_ROUTING_NONE, in
   // which case RenderWidgetHost will create a new one.  |swapped_out| indicates
   // whether the view should initially be swapped out (e.g., for an opener
-  // frame being rendered by another process).
+  // frame being rendered by another process). |hidden| indicates whether the
+  // view is initially hidden or visible.
   //
   // The |session_storage_namespace| parameter allows multiple render views and
   // WebContentses to share the same session storage (part of the WebStorage
@@ -123,7 +124,8 @@
       RenderWidgetHostDelegate* widget_delegate,
       int routing_id,
       int main_frame_routing_id,
-      bool swapped_out);
+      bool swapped_out,
+      bool hidden);
   virtual ~RenderViewHostImpl();
 
   // RenderViewHost implementation.
@@ -553,7 +555,8 @@
   void OnAddMessageToConsole(int32 level,
                              const string16& message,
                              int32 line_no,
-                             const string16& source_id);
+                             const string16& source_id,
+                             const string16& stack_trace);
   void OnUpdateInspectorSetting(const std::string& key,
                                 const std::string& value);
   void OnShouldCloseACK(
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 4053d65..828dadc 100644
--- a/content/browser/renderer_host/render_view_host_manager_browsertest.cc
+++ b/content/browser/renderer_host/render_view_host_manager_browsertest.cc
@@ -25,7 +25,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/net_util.h"
@@ -86,7 +86,7 @@
   // Wait for the navigation in the new window to finish, if it hasn't.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/navigate_opener.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> blank_site_instance(
@@ -153,7 +153,8 @@
   // Wait for the window to open.
   Shell* new_shell = new_shell_observer.GetShell();
 
-  EXPECT_EQ("/files/title2.html", new_shell->web_contents()->GetURL().path());
+  EXPECT_EQ("/files/title2.html",
+            new_shell->web_contents()->GetVisibleURL().path());
 
   // Wait for the cross-site transition in the new tab to finish.
   WaitForLoadStop(new_shell->web_contents());
@@ -207,7 +208,8 @@
   Shell* new_shell = new_shell_observer.GetShell();
 
   // Opens in new window.
-  EXPECT_EQ("/files/title2.html", new_shell->web_contents()->GetURL().path());
+  EXPECT_EQ("/files/title2.html",
+            new_shell->web_contents()->GetVisibleURL().path());
 
   // Wait for the cross-site transition in the new tab to finish.
   WaitForLoadStop(new_shell->web_contents());
@@ -262,7 +264,7 @@
   // Wait for the cross-site transition in the new tab to finish.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/title2.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> blank_site_instance(
@@ -308,7 +310,8 @@
 
   // Opens in same window.
   EXPECT_EQ(1u, Shell::windows().size());
-  EXPECT_EQ("/files/title2.html", shell()->web_contents()->GetURL().path());
+  EXPECT_EQ("/files/title2.html",
+            shell()->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> noref_site_instance(
@@ -376,7 +379,7 @@
   // Wait for the navigation in the new tab to finish, if it hasn't.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/navigate_opener.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> blank_site_instance(
@@ -456,7 +459,7 @@
   // Wait for the navigation in the new tab to finish, if it hasn't.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/title2.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> blank_site_instance(
@@ -562,7 +565,8 @@
   // send it to post_message.html on a different site.
   WebContents* foo_contents = new_shell->web_contents();
   WaitForLoadStop(foo_contents);
-  EXPECT_EQ("/files/navigate_opener.html", foo_contents->GetURL().path());
+  EXPECT_EQ("/files/navigate_opener.html",
+            foo_contents->GetLastCommittedURL().path());
   NavigateToURL(new_shell, https_server.GetURL("files/post_message.html"));
   scoped_refptr<SiteInstance> foo_site_instance(
       foo_contents->GetSiteInstance());
@@ -581,7 +585,7 @@
   Shell* new_shell2 = new_shell_observer2.GetShell();
   WebContents* new_contents = new_shell2->web_contents();
   WaitForLoadStop(new_contents);
-  EXPECT_EQ("/files/title2.html", new_contents->GetURL().path());
+  EXPECT_EQ("/files/title2.html", new_contents->GetLastCommittedURL().path());
   NavigateToURL(new_shell2, test_server()->GetURL("files/post_message.html"));
   EXPECT_EQ(orig_site_instance, new_contents->GetSiteInstance());
   RenderViewHostManager* new_manager =
@@ -698,7 +702,7 @@
   // Wait for the navigation in the new window to finish, if it hasn't.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/navigate_opener.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> blank_site_instance(
@@ -765,7 +769,7 @@
   // Wait for the navigation in the new window to finish, if it hasn't.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/navigate_opener.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> opened_site_instance(
@@ -829,7 +833,8 @@
   scoped_refptr<SiteInstance> post_nav_site_instance(
       shell()->web_contents()->GetSiteInstance());
   EXPECT_EQ(orig_site_instance, post_nav_site_instance);
-  EXPECT_EQ("/nocontent", shell()->web_contents()->GetURL().path());
+  EXPECT_EQ("/nocontent",
+            shell()->web_contents()->GetVisibleURL().path());
   EXPECT_EQ("/files/click-noreferrer-links.html",
             shell()->web_contents()->GetController().
                 GetLastCommittedEntry()->GetVirtualURL().path());
@@ -847,7 +852,8 @@
 
   // Opens in same tab.
   EXPECT_EQ(1u, Shell::windows().size());
-  EXPECT_EQ("/files/title2.html", shell()->web_contents()->GetURL().path());
+  EXPECT_EQ("/files/title2.html",
+            shell()->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   scoped_refptr<SiteInstance> noref_site_instance(
@@ -1073,7 +1079,7 @@
   // Wait for the navigation in the new tab to finish, if it hasn't.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/navigate_opener.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   RenderViewHost* rvh = new_shell->web_contents()->GetRenderViewHost();
 
@@ -1104,7 +1110,7 @@
   }
 
   EXPECT_EQ("/files/navigate_opener.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   EXPECT_EQ(rvh, new_shell->web_contents()->GetRenderViewHost());
 
@@ -1187,7 +1193,7 @@
   // view-source URL, we create a new SiteInstance.
   RenderViewHost* blank_rvh = shell()->web_contents()->GetRenderViewHost();
   SiteInstance* blank_site_instance = blank_rvh->GetSiteInstance();
-  EXPECT_EQ(shell()->web_contents()->GetURL(), GURL::EmptyGURL());
+  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), GURL::EmptyGURL());
   EXPECT_EQ(blank_site_instance->GetSiteURL(), GURL::EmptyGURL());
   rvh_observers.AddObserverToRVH(blank_rvh);
 
@@ -1269,7 +1275,7 @@
   // Wait for the navigation in the new window to finish, if it hasn't.
   WaitForLoadStop(new_shell->web_contents());
   EXPECT_EQ("/files/title1.html",
-            new_shell->web_contents()->GetURL().path());
+            new_shell->web_contents()->GetLastCommittedURL().path());
 
   // Should have the same SiteInstance.
   EXPECT_EQ(orig_site_instance, new_shell->web_contents()->GetSiteInstance());
@@ -1286,7 +1292,7 @@
   // Make sure it ends up at the right page.
   WaitForLoadStop(shell()->web_contents());
   EXPECT_EQ(https_server.GetURL("files/title1.html"),
-            shell()->web_contents()->GetURL());
+            shell()->web_contents()->GetLastCommittedURL());
   EXPECT_EQ(new_site_instance, shell()->web_contents()->GetSiteInstance());
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_browsertest.cc b/content/browser/renderer_host/render_widget_host_browsertest.cc
index 9f11299..bfdf6a5 100644
--- a/content/browser/renderer_host/render_widget_host_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_browsertest.cc
@@ -7,7 +7,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_paths.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/net_util.h"
@@ -46,8 +46,14 @@
   base::FilePath test_dir_;
 };
 
+// Disabled on Windows and CrOS because it is flaky: crbug.com/272379.
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#define MAYBE_GetSnapshotFromRendererTest DISABLED_GetSnapshotFromRendererTest
+#else
+#define MAYBE_GetSnapshotFromRendererTest GetSnapshotFromRendererTest
+#endif
 IN_PROC_BROWSER_TEST_F(RenderWidgetHostBrowserTest,
-                       GetSnapshotFromRendererTest) {
+                       MAYBE_GetSnapshotFromRendererTest) {
   base::RunLoop run_loop;
 
   NavigateToURL(shell(), GURL(net::FilePathToFileURL(
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index edd21fe..16892a1 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -22,6 +22,7 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/compositor_frame_ack.h"
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
+#include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
 #include "content/browser/gpu/gpu_surface_tracker.h"
@@ -40,7 +41,6 @@
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
 #include "content/port/browser/render_widget_host_view_port.h"
-#include "content/public/browser/compositor_util.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
@@ -115,7 +115,8 @@
 
 RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
                                            RenderProcessHost* process,
-                                           int routing_id)
+                                           int routing_id,
+                                           bool hidden)
     : view_(NULL),
       renderer_initialized_(false),
       hung_renderer_delay_ms_(kHungRendererDelayMs),
@@ -124,11 +125,12 @@
       routing_id_(routing_id),
       surface_id_(0),
       is_loading_(false),
-      is_hidden_(false),
+      is_hidden_(hidden),
       is_fullscreen_(false),
       is_accelerated_compositing_active_(false),
       repaint_ack_pending_(false),
       resize_ack_pending_(false),
+      screen_info_out_of_date_(false),
       overdraw_bottom_height_(0.f),
       should_auto_resize_(false),
       waiting_for_screen_rects_ack_(false),
@@ -175,9 +177,11 @@
   g_routing_id_widget_map.Get().insert(std::make_pair(
       RenderWidgetHostID(process->GetID(), routing_id_), this));
   process_->AddRoute(routing_id_, this);
-  // Because the widget initializes as is_hidden_ == false,
-  // tell the process host that we're alive.
-  process_->WidgetRestored();
+
+  // If we're initially visible, tell the process host that we're alive.
+  // Otherwise we'll notify the process host when we are first shown.
+  if (!hidden)
+    process_->WidgetRestored();
 
   accessibility_mode_ =
       BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode();
@@ -479,6 +483,9 @@
 }
 
 void RenderWidgetHostImpl::WasHidden() {
+  if (is_hidden_)
+    return;
+
   is_hidden_ = true;
 
   // Don't bother reporting hung state when we aren't active.
@@ -499,7 +506,6 @@
 }
 
 void RenderWidgetHostImpl::WasShown() {
-  // When we create the widget, it is created as *not* hidden.
   if (!is_hidden_)
     return;
   is_hidden_ = false;
@@ -565,7 +571,7 @@
 
   bool size_changed = new_size != last_requested_size_;
   bool side_payload_changed =
-      !screen_info_.get() ||
+      screen_info_out_of_date_ ||
       old_physical_backing_size != physical_backing_size_ ||
       was_fullscreen != is_fullscreen_ ||
       old_overdraw_bottom_height != overdraw_bottom_height_;
@@ -838,20 +844,20 @@
   Send(new ViewMsg_UpdateRect_ACK(GetRoutingID()));
 }
 
-void RenderWidgetHostImpl::ScheduleComposite() {
+bool RenderWidgetHostImpl::ScheduleComposite() {
   if (is_hidden_ || !is_accelerated_compositing_active_ ||
-      current_size_.IsEmpty()) {
-      return;
+      current_size_.IsEmpty() || repaint_ack_pending_ ||
+      resize_ack_pending_ || view_being_painted_) {
+    return false;
   }
 
   // Send out a request to the renderer to paint the view if required.
-  if (!repaint_ack_pending_ && !resize_ack_pending_ && !view_being_painted_) {
-    repaint_start_time_ = TimeTicks::Now();
-    repaint_ack_pending_ = true;
-    TRACE_EVENT_ASYNC_BEGIN0(
-        "renderer_host", "RenderWidgetHostImpl::repaint_ack_pending_", this);
-    Send(new ViewMsg_Repaint(routing_id_, current_size_));
-  }
+  repaint_start_time_ = TimeTicks::Now();
+  repaint_ack_pending_ = true;
+  TRACE_EVENT_ASYNC_BEGIN0(
+      "renderer_host", "RenderWidgetHostImpl::repaint_ack_pending_", this);
+  Send(new ViewMsg_Repaint(routing_id_, current_size_));
+  return true;
 }
 
 void RenderWidgetHostImpl::StartHangMonitorTimeout(TimeDelta delay) {
@@ -1134,6 +1140,7 @@
     static_cast<RenderWidgetHostViewPort*>(GetView())->GetScreenInfo(result);
   else
     RenderWidgetHostViewPort::GetDefaultScreenInfo(result);
+  screen_info_out_of_date_ = false;
 }
 
 const NativeWebKeyboardEvent*
@@ -1150,6 +1157,7 @@
 }
 
 void RenderWidgetHostImpl::InvalidateScreenInfo() {
+  screen_info_out_of_date_ = true;
   screen_info_.reset();
 }
 
@@ -1482,7 +1490,9 @@
       ack.gl_frame_data = frame->gl_frame_data.Pass();
       ack.gl_frame_data->sync_point = 0;
     } else if (frame->delegated_frame_data) {
-      ack.resources.swap(frame->delegated_frame_data->resource_list);
+      cc::TransferableResource::ReturnResources(
+          frame->delegated_frame_data->resource_list,
+          &ack.resources);
     } else if (frame->software_frame_data) {
       ack.last_software_frame_id = frame->software_frame_data->id;
     }
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 362c6d7..2004c0b 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -93,7 +93,8 @@
   // |delegate| goes away.
   RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
                        RenderProcessHost* process,
-                       int routing_id);
+                       int routing_id,
+                       bool hidden);
   virtual ~RenderWidgetHostImpl();
 
   // Similar to RenderWidgetHost::FromID, but returning the Impl object.
@@ -267,9 +268,9 @@
   void DonePaintingToBackingStore();
 
   // GPU accelerated version of GetBackingStore function. This will
-  // trigger a re-composite to the view. If a resize is pending, it will
-  // block briefly waiting for an ack from the renderer.
-  void ScheduleComposite();
+  // trigger a re-composite to the view. It may fail if a resize is pending, or
+  // if a composite has already been requested and not acked yet.
+  bool ScheduleComposite();
 
   // Starts a hang monitor timeout. If there's already a hang monitor timeout
   // the new one will only fire if it has a shorter delay than the time
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 960ce5e..980fb66 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -225,7 +225,7 @@
       RenderWidgetHostDelegate* delegate,
       RenderProcessHost* process,
       int routing_id)
-      : RenderWidgetHostImpl(delegate, process, routing_id),
+      : RenderWidgetHostImpl(delegate, process, routing_id, false),
         unresponsive_timer_fired_(false) {
     immediate_input_router_ =
         static_cast<ImmediateInputRouter*>(input_router_.get());
@@ -857,13 +857,12 @@
 // -----------------------------------------------------------------------------
 
 TEST_F(RenderWidgetHostTest, Resize) {
-  // The initial bounds is the empty rect, but the screen info hasn't been sent
-  // yet, so setting it to the same thing should send the resize message.
+  // The initial bounds is the empty rect, and the screen info hasn't been sent
+  // yet, so setting it to the same thing shouldn't send the resize message.
   view_->set_bounds(gfx::Rect());
   host_->WasResized();
   EXPECT_FALSE(host_->resize_ack_pending_);
-  EXPECT_EQ(gfx::Size(), host_->last_requested_size_);
-  EXPECT_TRUE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
+  EXPECT_FALSE(process_->sink().GetUniqueMessageMatching(ViewMsg_Resize::ID));
 
   // Setting the bounds to a "real" rect should send out the notification.
   // but should not expect ack for empty physical backing size.
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 8c52017..2369044 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1308,6 +1308,7 @@
     current_frame_size_ = ConvertSizeToDIP(
         current_surface_->device_scale_factor(), current_surface_->size());
     CheckResizeLock();
+    framebuffer_holder_ = NULL;
   } else if (is_compositing_active && framebuffer_holder_) {
     cc::TextureMailbox mailbox = framebuffer_holder_->GetMailbox();
     window_->layer()->SetTextureMailbox(mailbox,
@@ -1319,6 +1320,7 @@
     window_->layer()->SetExternalTexture(NULL);
     resize_lock_.reset();
     host_->WasResized();
+    framebuffer_holder_ = NULL;
   }
 }
 
@@ -1446,9 +1448,11 @@
         frame_data->render_pass_list.back()->output_rect.size(),
         1.f/frame_device_scale_factor));
   }
+  framebuffer_holder_ = NULL;
   if (ShouldSkipFrame(frame_size_in_dip)) {
     cc::CompositorFrameAck ack;
-    ack.resources.swap(frame_data->resource_list);
+    cc::TransferableResource::ReturnResources(frame_data->resource_list,
+                                              &ack.resources);
     RenderWidgetHostImpl::SendSwapCompositorFrameAck(
         host_->GetRoutingID(), output_surface_id,
         host_->GetProcess()->GetID(), ack);
@@ -1526,6 +1530,7 @@
                  AsWeakPtr(),
                  output_surface_id,
                  frame_data->id)));
+  bool first_frame = !framebuffer_holder_;
   framebuffer_holder_.swap(holder);
   cc::TextureMailbox mailbox = framebuffer_holder_->GetMailbox();
   DCHECK(mailbox.IsSharedMemory());
@@ -1538,8 +1543,18 @@
       ConvertRectToDIP(frame_device_scale_factor, damage_rect));
 
   ui::Compositor* compositor = GetCompositor();
-  if (compositor)
+  if (compositor) {
     compositor->SetLatencyInfo(latency_info);
+    if (first_frame) {
+      // Send swap for first frame, because no frame will be released due to
+      // that.
+      AddOnCommitCallbackAndDisableLocks(
+          base::Bind(&RenderWidgetHostViewAura::SendSoftwareFrameAck,
+                     AsWeakPtr(),
+                     output_surface_id,
+                     0));
+    }
+  }
   if (paint_observer_)
     paint_observer_->OnUpdateCompositorContent();
   DidReceiveFrameFromRenderer();
@@ -1557,6 +1572,7 @@
 void RenderWidgetHostViewAura::OnSwapCompositorFrame(
     uint32 output_surface_id,
     scoped_ptr<cc::CompositorFrame> frame) {
+  TRACE_EVENT0("content", "RenderWidgetHostViewAura::OnSwapCompositorFrame");
   if (frame->delegated_frame_data) {
     SwapDelegatedFrame(output_surface_id,
                        frame->delegated_frame_data.Pass(),
@@ -1620,6 +1636,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;
 
   if (!SwapBuffersPrepare(surface_rect,
                           surface_scale_factor,
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 03f7d5c..304ad69 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
@@ -84,7 +84,7 @@
     sink_ = &process_host->sink();
 
     parent_host_ = new RenderWidgetHostImpl(
-        &delegate_, process_host, MSG_ROUTING_NONE);
+        &delegate_, process_host, MSG_ROUTING_NONE, false);
     parent_view_ = static_cast<RenderWidgetHostViewAura*>(
         RenderWidgetHostView::CreateViewForWidget(parent_host_));
     parent_view_->InitAsChild(NULL);
@@ -92,7 +92,7 @@
         aura_test_helper_->root_window(), gfx::Rect());
 
     widget_host_ = new RenderWidgetHostImpl(
-        &delegate_, process_host, MSG_ROUTING_NONE);
+        &delegate_, process_host, MSG_ROUTING_NONE, false);
     widget_host_->Init();
     view_ = static_cast<RenderWidgetHostViewAura*>(
         RenderWidgetHostView::CreateViewForWidget(widget_host_));
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 2b47ff1..05ce07d 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -6,19 +6,19 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/renderer_host/dip_util.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
 #include "content/port/browser/render_widget_host_view_port.h"
-#include "content/public/browser/compositor_util.h"
 #include "content/public/browser/render_view_host.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/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "media/base/video_frame.h"
@@ -373,8 +373,18 @@
 // Tests that the callback passed to CopyFromCompositingSurfaceToVideoFrame is
 // always called, even when the RenderWidgetHost is deleting in the middle of
 // an async copy.
+//
+// Test is flaky on Win Aura. http://crbug.com/276783
+#if (defined(OS_WIN) && defined(USE_AURA)) || \
+    (defined(OS_CHROMEOS) && !defined(NDEBUG))
+#define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
+  DISABLED_CopyFromCompositingSurface_CallbackDespiteDelete
+#else
+#define MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete \
+  CopyFromCompositingSurface_CallbackDespiteDelete
+#endif
 IN_PROC_BROWSER_TEST_F(CompositingRenderWidgetHostViewBrowserTest,
-                       CopyFromCompositingSurface_CallbackDespiteDelete) {
+                       MAYBE_CopyFromCompositingSurface_CallbackDespiteDelete) {
   SET_UP_SURFACE_OR_PASS_TEST(NULL);
   RenderWidgetHostViewPort* const view = GetRenderWidgetHostViewPort();
   if (!view->CanCopyToVideoFrame()) {
@@ -638,7 +648,8 @@
 
     // The page is loaded in the renderer, wait for a new frame to arrive.
     uint32 frame = rwhvp->RendererFrameNumber();
-    GetRenderWidgetHost()->ScheduleComposite();
+    while (!GetRenderWidgetHost()->ScheduleComposite())
+      GiveItSomeTime();
     while (rwhvp->RendererFrameNumber() == frame)
       GiveItSomeTime();
 
diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.cc b/content/browser/renderer_host/render_widget_host_view_gtk.cc
index ddaf952..33bd552 100644
--- a/content/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/content/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -561,6 +561,8 @@
       compositing_surface_(gfx::kNullPluginWindow),
       last_mouse_down_(NULL) {
   host_->SetView(this);
+  if (host_->is_hidden())
+    WasHidden();
 }
 
 RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() {
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 097468f..b49ca41 100644
--- a/content/browser/renderer_host/render_widget_host_view_guest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_guest.cc
@@ -67,14 +67,22 @@
 }
 
 void RenderWidgetHostViewGuest::WasShown() {
-  if (!is_hidden_)
+  // If the WebContents associated with us showed an interstitial page in the
+  // beginning, the teardown path might call WasShown() while |host_| is in
+  // the process of destruction. Avoid calling WasShown below in this case.
+  // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
+  // first place: http://crbug.com/273089.
+  //
+  // |guest_| is NULL during test.
+  if (!is_hidden_ || (guest_ && guest_->is_in_destruction()))
     return;
   is_hidden_ = false;
   host_->WasShown();
 }
 
 void RenderWidgetHostViewGuest::WasHidden() {
-  if (is_hidden_)
+  // |guest_| is NULL during test.
+  if (is_hidden_ || (guest_ && guest_->is_in_destruction()))
     return;
   is_hidden_ = true;
   host_->WasHidden();
diff --git a/content/browser/renderer_host/render_widget_host_view_guest_unittest.cc b/content/browser/renderer_host/render_widget_host_view_guest_unittest.cc
index 959f5e4..a112634 100644
--- a/content/browser/renderer_host/render_widget_host_view_guest_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_guest_unittest.cc
@@ -32,7 +32,7 @@
     MockRenderProcessHost* process_host =
         new MockRenderProcessHost(browser_context_.get());
     widget_host_ = new RenderWidgetHostImpl(
-        &delegate_, process_host, MSG_ROUTING_NONE);
+        &delegate_, process_host, MSG_ROUTING_NONE, false);
     view_ = new RenderWidgetHostViewGuest(
         widget_host_, NULL, new TestRenderWidgetHostView(widget_host_));
   }
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
index 0d3ee0a..ba92843 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper_unittest.mm
@@ -78,7 +78,7 @@
       RenderWidgetHostDelegate* delegate,
       RenderProcessHost* process,
       int routing_id)
-    : RenderWidgetHostImpl(delegate, process, routing_id),
+    : RenderWidgetHostImpl(delegate, process, routing_id, false),
       edit_command_message_count_(0) {
   }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
index 3c91bc6..8bf811c 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac_unittest.mm
@@ -101,7 +101,7 @@
   MockRenderWidgetHostImpl(RenderWidgetHostDelegate* delegate,
                            RenderProcessHost* process,
                            int routing_id)
-      : RenderWidgetHostImpl(delegate, process, routing_id) {
+      : RenderWidgetHostImpl(delegate, process, routing_id, false) {
   }
 
   MOCK_METHOD0(Focus, void());
@@ -264,7 +264,7 @@
       new MockRenderProcessHost(&browser_context);
   // Owned by its |cocoa_view()|.
   RenderWidgetHostImpl* rwh = new RenderWidgetHostImpl(
-      &delegate, process_host, MSG_ROUTING_NONE);
+      &delegate, process_host, MSG_ROUTING_NONE, false);
   RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>(
       RenderWidgetHostView::CreateViewForWidget(rwh));
 
@@ -298,7 +298,7 @@
       new MockRenderProcessHost(&browser_context);
   // Owned by its |cocoa_view()|.
   RenderWidgetHostImpl* rwh = new RenderWidgetHostImpl(
-      &delegate, process_host, MSG_ROUTING_NONE);
+      &delegate, process_host, MSG_ROUTING_NONE, false);
   RenderWidgetHostViewMac* view = static_cast<RenderWidgetHostViewMac*>(
       RenderWidgetHostView::CreateViewForWidget(rwh));
 
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 dcf3873..b36b5e0 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.cc
+++ b/content/browser/renderer_host/render_widget_host_view_win.cc
@@ -312,7 +312,7 @@
 
   MONITORINFOEX monitor_info;
   monitor_info.cbSize = sizeof(MONITORINFOEX);
-  if (!GetMonitorInfo(monitor, &monitor_info))
+  if (!base::win::GetMonitorInfoWrapper(monitor, &monitor_info))
     return;
 
   DEVMODE dev_mode;
@@ -762,6 +762,7 @@
     const gfx::Vector2d& scroll_delta,
     const std::vector<gfx::Rect>& copy_rects,
     const ui::LatencyInfo& latency_info) {
+  TRACE_EVENT0("content", "RenderWidgetHostViewWin::DidUpdateBackingStore");
   software_latency_info_.MergeWith(latency_info);
   if (is_hidden_)
     return;
@@ -780,6 +781,7 @@
   }
 
   if (!scroll_rect.IsEmpty()) {
+    TRACE_EVENT0("content", "ScrollWindowEx");
     gfx::Rect pixel_rect = ui::win::DIPToScreenRect(scroll_rect);
     // Damage might not be DIP aligned.
     pixel_rect.Inset(-1, -1);
@@ -895,7 +897,8 @@
   if (!accelerated_surface_)
     return;
 
-  if (!target || target->format() != media::VideoFrame::YV12)
+  if (!target || (target->format() != media::VideoFrame::YV12 &&
+                  target->format() != media::VideoFrame::I420))
     return;
 
   if (src_subrect.IsEmpty())
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
index 76070bc..7a35dd8 100644
--- a/content/browser/renderer_host/render_widget_host_view_win_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_win_browsertest.cc
@@ -10,11 +10,11 @@
 #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/test_utils.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
-#include "content/test/content_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"
diff --git a/content/browser/renderer_host/smooth_scroll_gesture_controller_unittest.cc b/content/browser/renderer_host/smooth_scroll_gesture_controller_unittest.cc
index 95d2647..9e70aca 100644
--- a/content/browser/renderer_host/smooth_scroll_gesture_controller_unittest.cc
+++ b/content/browser/renderer_host/smooth_scroll_gesture_controller_unittest.cc
@@ -59,7 +59,7 @@
       RenderWidgetHostDelegate* delegate,
       RenderProcessHost* process,
       int routing_id)
-      : RenderWidgetHostImpl(delegate, process, routing_id) {
+      : RenderWidgetHostImpl(delegate, process, routing_id, false) {
   }
   virtual ~MockRenderWidgetHost() {}
 };
diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc
index 129591c..1b58f6a 100644
--- a/content/browser/renderer_host/test_render_view_host.cc
+++ b/content/browser/renderer_host/test_render_view_host.cc
@@ -15,7 +15,6 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/page_state.h"
-#include "content/public/common/password_form.h"
 #include "content/test/test_web_contents.h"
 #include "media/base/video_frame.h"
 #include "ui/gfx/rect.h"
@@ -42,7 +41,6 @@
   params->should_update_history = false;
   params->searchable_form_url = GURL();
   params->searchable_form_encoding = std::string();
-  params->password_form = PasswordForm();
   params->security_info = std::string();
   params->gesture = NavigationGestureUser;
   params->was_within_same_page = false;
@@ -247,7 +245,8 @@
                          widget_delegate,
                          routing_id,
                          main_frame_routing_id,
-                         swapped_out),
+                         swapped_out,
+                         false /* hidden */),
       render_view_created_(false),
       delete_counter_(NULL),
       simulate_fetch_via_proxy_(false),
@@ -333,7 +332,6 @@
   params.should_update_history = true;
   params.searchable_form_url = GURL();
   params.searchable_form_encoding = std::string();
-  params.password_form = PasswordForm();
   params.security_info = std::string();
   params.gesture = NavigationGestureUser;
   params.contents_mime_type = contents_mime_type_;
diff --git a/content/browser/renderer_host/text_input_client_mac_unittest.mm b/content/browser/renderer_host/text_input_client_mac_unittest.mm
index 2a4c6d7..0993018 100644
--- a/content/browser/renderer_host/text_input_client_mac_unittest.mm
+++ b/content/browser/renderer_host/text_input_client_mac_unittest.mm
@@ -42,7 +42,7 @@
         widget_(&delegate_,
                 process_factory_.CreateRenderProcessHost(
                     &browser_context_, NULL),
-                MSG_ROUTING_NONE),
+                MSG_ROUTING_NONE, false),
         thread_("TextInputClientMacTestThread") {}
 
   // Accessor for the TextInputClientMac instance.
diff --git a/content/browser/resources/media/media_internals.css b/content/browser/resources/media/media_internals.css
index d83b6b7..56c64e5 100644
--- a/content/browser/resources/media/media_internals.css
+++ b/content/browser/resources/media/media_internals.css
@@ -25,18 +25,6 @@
   padding: 0 10px;
 }
 
-.audio-stream[status='created'] {
-  color: blue;
-}
-
-.audio-stream[status='closed'] {
-  text-decoration: line-through;
-}
-
-.audio-stream[status='error'] {
-  color: red;
-}
-
 #cache-entries ul,
 #media-players ul,
 #media-players {
diff --git a/content/browser/resources/media/media_internals.js b/content/browser/resources/media/media_internals.js
index c3e3a1e..f5b357c 100644
--- a/content/browser/resources/media/media_internals.js
+++ b/content/browser/resources/media/media_internals.js
@@ -60,16 +60,22 @@
      */
     function printStream(stream) {
       var out = document.createElement('li');
-      out.id = stream.id;
-      out.className = 'audio-stream';
-      out.setAttribute('status', stream.status);
 
-      out.textContent += 'Audio stream ' + stream.id.split('.')[1];
-      out.textContent += ' is ' + (stream.playing ? 'playing' : 'paused');
-      if (typeof stream.volume != 'undefined') {
-        out.textContent += ' at ' + (stream.volume * 100).toFixed(0);
-        out.textContent += '% volume.';
+      function tableFromObject(obj) {
+        var table = document.createElement('table');
+        for (var key in obj) {
+          var value = obj[key];
+          var row = table.insertRow(-1);
+          var k = row.insertCell(-1);
+          var v = row.insertCell(-1);
+          k.appendChild(document.createTextNode(key));
+          v.appendChild(document.createTextNode(value.toString()));
+        }
+        return table;
       }
+
+      out.appendChild(tableFromObject(stream));
+
       return out;
     }
 
@@ -111,7 +117,7 @@
    * Add it to audioStreams and update the page.
    * @param {Object} stream JSON representation of an audio stream.
    */
-  function addAudioStream(stream) {
+  function updateAudioStream(stream) {
     audioStreams.addItem(stream);
     printAudioStreams();
   }
@@ -262,7 +268,7 @@
 
   return {
     initialize: initialize,
-    addAudioStream: addAudioStream,
+    updateAudioStream: updateAudioStream,
     cacheEntriesByKey: cacheEntriesByKey,
     onReceiveEverything: onReceiveEverything,
     onItemDeleted: onItemDeleted,
diff --git a/content/browser/resources/media/new/client_renderer.js b/content/browser/resources/media/new/client_renderer.js
new file mode 100644
index 0000000..6acb302
--- /dev/null
+++ b/content/browser/resources/media/new/client_renderer.js
@@ -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.
+
+var ClientRenderer = (function() {
+  var ClientRenderer = function() {
+    this.playerListElement = document.getElementById('player-list');
+    this.propertiesTable = document.getElementById('property-table');
+    this.selectedPlayer = null;
+  };
+
+  function removeChildren(element) {
+    while (element.hasChildNodes()) {
+      element.removeChild(element.lastChild);
+    }
+  };
+
+  ClientRenderer.prototype = {
+    /**
+     * Called when a player is added to the collection.
+     * @param players The entire map of id -> player.
+     * @param player_added The player that is added.
+     */
+    playerAdded: function(players, player_added) {
+      this.redrawList_(players);
+    },
+
+    /**
+     * Called when a playre is removed from the collection.
+     * @param players The entire map of id -> player.
+     * @param player_added The player that was removed.
+     */
+    playerRemoved: function(players, player_removed) {
+      this.redrawList_(players);
+    },
+
+    /**
+     * Called when a property on a player is changed.
+     * @param players The entire map of id -> player.
+     * @param player The player that had its property changed.
+     * @param key The name of the property that was changed.
+     * @param value The new value of the property.
+     */
+    playerUpdated: function(players, player, key, value) {
+      if (player === this.selectedPlayer) {
+        this.drawSelectedPlayer_();
+      }
+      if (key === 'name' || key === 'url') {
+        this.redrawList_(players);
+      }
+    },
+
+    redrawList_: function(players) {
+      removeChildren(this.playerListElement);
+
+      function createButton(player, select_cb) {
+        var button = document.createElement('button');
+        var usableName = player.properties.name ||
+            player.properties.url ||
+            'player ' + player.id;
+
+        button.appendChild(document.createTextNode(usableName));
+        button.onclick = function() {
+          select_cb(player);
+        };
+
+        return button;
+      };
+
+      for (id in players) {
+        var li = document.createElement('li');
+        li.appendChild(createButton(players[id], this.select_.bind(this)));
+        this.playerListElement.appendChild(li);
+      }
+    },
+
+    select_: function(player) {
+      this.selectedPlayer = player;
+      this.drawSelectedPlayer_();
+    },
+
+    drawSelectedPlayer_: function() {
+      removeChildren(this.propertiesTable);
+
+      for (key in this.selectedPlayer.properties) {
+        var value = this.selectedPlayer.properties[key];
+        var row = this.propertiesTable.insertRow(-1);
+        var keyCell = row.insertCell(-1);
+        var valueCell = row.insertCell(-1);
+
+        keyCell.appendChild(document.createTextNode(key));
+        valueCell.appendChild(document.createTextNode(value));
+      }
+    }
+  };
+
+  return ClientRenderer;
+})();
diff --git a/content/browser/resources/media/new/integration_test.html b/content/browser/resources/media/new/integration_test.html
deleted file mode 100644
index 3a5225c..0000000
--- a/content/browser/resources/media/new/integration_test.html
+++ /dev/null
@@ -1,86 +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.
--->
-<!DOCTYPE html>
-<html>
-  <head>
-    <script src="webui_resource_test.js"></script>
-    <script src="util.js"></script>
-    <script src="player_manager.js"></script>
-    <script src="player_info.js"></script>
-    <script src="main.js"></script>
-  </head>
-  <body>
-    <script>
-      window.setUp = function() {
-        var doNothing = function() {};
-        var mockRenderer = {
-          redrawList: doNothing,
-          update: doNothing,
-          select: doNothing
-        };
-
-        var manager = new PlayerManager(mockRenderer);
-        media.initialize(manager);
-
-        window.playerManager = manager;
-      };
-
-      // The renderer and player ids are completely arbitrarily.
-      var TEST_RENDERER = 12;
-      var TEST_PLAYER = 4;
-      var TEST_NAME = TEST_RENDERER + ':' + TEST_PLAYER;
-
-      // Correctly use the information from a media event.
-      window.testOnMediaEvent = function() {
-        var event = {
-          ticksMillis: 132,
-          renderer: TEST_RENDERER,
-          player: TEST_PLAYER,
-          params: {
-            fps: 60,
-            other: 'hi'
-          }
-        };
-
-        window.media.onMediaEvent(event);
-        var info = window.playerManager.players_[TEST_NAME];
-
-        assertEquals(event.ticksMillis, info.firstTimestamp_);
-        assertEquals(TEST_NAME, info.id);
-        assertEquals(event.params.fps, info.properties.fps);
-      };
-
-      // Remove a player.
-      window.testOnRenderTerminated = function() {
-        window.testOnMediaEvent();
-
-        window.playerManager.shouldRemovePlayer_ = function() {
-          return true;
-        };
-
-        window.media.onRendererTerminated(TEST_RENDERER);
-        assertEquals(undefined, window.playerManager.players_[TEST_NAME]);
-      };
-
-      // Audio Streams are weird, they are handled separately
-      window.testAddAudioStream = function() {
-        var event = {
-          id: 'ID',
-          status: 'created',
-          playing: true
-        };
-
-        window.media.addAudioStream(event);
-
-        var player = window.playerManager.players_[event.id];
-        assertTrue(undefined !== player);
-        assertEquals(event.playing, player.properties['playing']);
-      };
-
-      runTests();
-    </script>
-  </body>
-</html>
diff --git a/content/browser/resources/media/new/media_internals.html b/content/browser/resources/media/new/media_internals.html
index 0e95353..bc2a4de 100644
--- a/content/browser/resources/media/new/media_internals.html
+++ b/content/browser/resources/media/new/media_internals.html
@@ -8,11 +8,11 @@
 <head>
   <meta charset="utf-8">
   <title i18n-content="Media Internals"></title>
-
-  <script src="chrome://media-internals/media_internals.js"></script>
 </head>
 
 <body>
-  Hello World
+  <ul id="player-list"></ul>
+  <table id="property-table"></table>
+  <script src="chrome://media-internals/media_internals.js"></script>
 </body>
 </html>
diff --git a/content/browser/resources/media/new/media_internals.js b/content/browser/resources/media/new/media_internals.js
index 103ef74..a795273 100644
--- a/content/browser/resources/media/new/media_internals.js
+++ b/content/browser/resources/media/new/media_internals.js
@@ -4,15 +4,10 @@
 
 var media = {};
 
-var doNothing = function() {};
+<include src="util.js"/>
+<include src="player_info.js"/>
+<include src="player_manager.js"/>
+<include src="client_renderer.js"/>
+<include src="main.js"/>
 
-// Silence the backend calls.
-media.initialize = doNothing;
-media.addAudioStream = doNothing;
-media.cacheEntriesByKey = doNothing;
-media.onReceiveEverything = doNothing;
-media.onItemDeleted = doNothing;
-media.onRendererTerminated = doNothing;
-media.onNetUpdate = doNothing;
-media.onReceiveConstants = doNothing;
-media.onMediaEvent = doNothing;
+media.initialize(new PlayerManager(new ClientRenderer()));
diff --git a/content/browser/resources/media/new/player_info_test.html b/content/browser/resources/media/new/player_info_test.html
deleted file mode 100644
index 46cc05e..0000000
--- a/content/browser/resources/media/new/player_info_test.html
+++ /dev/null
@@ -1,146 +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.
--->
-<!DOCTYPE html>
-<html>
-  <head>
-    <script src="webui_resource_test.js"></script>
-    <script src="player_manager.js"></script>
-    <script src="player_info.js"></script>
-  </head>
-  <body>
-    <script>
-      window.setUp = function() {
-        window.pi = new PlayerInfo('example_id');
-      };
-
-      window.tearDown = function() {
-        window.pi = null;
-      };
-
-      // Test that an ID is set correctly.
-      window.testConstructorStringID = function() {
-        assertEquals('example_id', window.pi.id);
-      };
-
-      // Test that numerical IDs are valid.
-      window.testConstructorNumberId = function() {
-        var pi = new PlayerInfo(5);
-        assertEquals(5, pi.id);
-      };
-
-      // Make sure that a new PlayerInfo has no events.
-      window.testEmptyEvents = function() {
-        assertEquals(0, window.pi.allEvents.length);
-      };
-
-      // Check that the most recent property gets updated.
-      window.testAddProperty = function() {
-        var key = 'key',
-          value = 'value',
-          value2 = 'value2';
-
-        window.pi.addProperty(0, key, value);
-        assertEquals(value, window.pi.properties[key]);
-
-        window.pi.addProperty(0, key, value2);
-        assertEquals(value2, window.pi.properties[key]);
-
-      };
-
-      // Make sure that the first timestamp that gets sent
-      // is recorded as the base timestamp.
-      window.testFirstTimestamp = function() {
-        var pi = new PlayerInfo('example_ID');
-        var timestamp = 5000;
-        pi.addProperty(timestamp, 'key', 'value');
-
-        assertEquals(timestamp, pi.firstTimestamp_);
-      };
-
-      // Adding a property with a non-string key should
-      // throw an exception.
-      window.testWrongKeyType = function() {
-        var pi = new PlayerInfo('example_ID');
-        assertThrows(function() {
-          pi.addProperty(0, 5, 'some value');
-        });
-      };
-
-      // Subsequent events should have their log offset based
-      // on the first timestamp added.
-      window.testAddPropertyTimestampOffset = function() {
-        var firstTimestamp = 500,
-          secondTimestamp = 550,
-          deltaT = secondTimestamp - firstTimestamp,
-          key = 'key',
-          value = 'value';
-
-        var pi = new PlayerInfo('example_ID');
-        pi.addProperty(firstTimestamp, key, value);
-        pi.addProperty(secondTimestamp, key, value);
-
-        assertEquals(firstTimestamp, pi.firstTimestamp_);
-        assertEquals(0, pi.allEvents[0].time);
-        assertEquals(deltaT, pi.allEvents[1].time);
-
-        assertTrue(undefined !== pi.pastValues[key]);
-
-        console.log(pi.pastValues);
-
-        assertEquals(0, pi.pastValues[key][0].time);
-        assertEquals(deltaT, pi.pastValues[key][1].time);
-      };
-
-      // Check to make sure that properties are correctly
-      // added to the relevant pastValues array.
-      window.testAddPropertyPastValues = function() {
-        var pi = new PlayerInfo('example_ID'),
-          timestamp = 50,
-          key = 'key',
-          value = 'value';
-
-        pi.addProperty(timestamp, key, value);
-
-        assertEquals(value, pi.pastValues[key][0].value);
-        assertEquals(key, pi.pastValues[key][0].key);
-        assertEquals(0, pi.pastValues[key][0].time);
-      };
-
-      // The list of all events should be recorded in correctly.
-      window.testAllEvents = function() {
-        var pi = new PlayerInfo('example_ID'),
-          timestamp = 50,
-          key = 'key',
-          value = 'value',
-          key2 = 'key2',
-          value2 = 'value2';
-
-        pi.addProperty(timestamp, key, value);
-        assertEquals(value, pi.allEvents[0].value);
-        assertEquals(key, pi.allEvents[0].key);
-
-        pi.addProperty(timestamp, key2, value2);
-        assertEquals(value2, pi.allEvents[1].value);
-        assertEquals(key2, pi.allEvents[1].key);
-      };
-
-      // Using noRecord should make it not show up in allEvents,
-      // but it should still show up in pastValues[key].
-      window.testNoRecord = function() {
-        var pi = new PlayerInfo('example_ID'),
-          timestamp = 50,
-          key = 'key',
-          value = 'value';
-        pi.addPropertyNoRecord(timestamp, key, value);
-
-        assertEquals(value, pi.properties[key]);
-        assertEquals(0, pi.allEvents.length);
-        assertEquals(1, pi.pastValues[key].length);
-      };
-      runTests();
-    </script>
-  </body>
-</html>
diff --git a/content/browser/resources/media/new/player_manager.js b/content/browser/resources/media/new/player_manager.js
index 3de9335..4ef1a93 100644
--- a/content/browser/resources/media/new/player_manager.js
+++ b/content/browser/resources/media/new/player_manager.js
@@ -4,20 +4,17 @@
 
 /**
  * @fileoverview Keeps track of all the existing
- * PlayerProperty objects and is the entry-point for messages from the backend.
+ * PlayerInfo objects and is the entry-point for messages from the backend.
+ *
+ * The events captured by PlayerManager (add, remove, update) are relayed
+ * to the clientRenderer which it can choose to use to modify the UI.
  */
 var PlayerManager = (function() {
   'use strict';
 
-  function PlayerManager(renderManager) {
+  function PlayerManager(clientRenderer) {
     this.players_ = {};
-    this.renderman_ = renderManager;
-    renderManager.playerManager = this;
-
-    this.shouldRemovePlayer_ = function() {
-      // This is only temporary until we get the UI hooked up.
-      return true;
-    };
+    this.clientRenderer_ = clientRenderer;
   }
 
   PlayerManager.prototype = {
@@ -31,8 +28,7 @@
       }
       // Make the PlayerProperty and add it to the mapping
       this.players_[id] = new PlayerInfo(id);
-
-      this.renderman_.redrawList();
+      this.clientRenderer_.playerAdded(this.players_, this.players_[id]);
     },
 
     /**
@@ -40,45 +36,21 @@
      * @param id The ID of the player to remove.
      */
     removePlayer: function(id) {
-      // Look at the check box to see if we should actually
-      // remove it from the UI
-      if (this.shouldRemovePlayer_()) {
-        delete this.players_[id];
-        this.renderman_.redrawList();
-      } else if (this.players_[id]) {
-        // Set a property on it to be removed at a later time
-        this.players_[id].toRemove = true;
-      }
-    },
-
-    /**
-     * Selects a player and displays it on the UI.
-     * This method is called from the UI.
-     * @param id The ID of the player to display.
-     */
-    selectPlayer: function(id) {
-      if (!this.players_[id]) {
-        throw new Error('[selectPlayer] Id ' + id + ' does not exist.');
-      }
-
-      this.renderman_.select(id);
+      delete this.players_[id];
+      this.clientRenderer_.playerRemoved(this.players_, this.players_[id]);
     },
 
     updatePlayerInfoNoRecord: function(id, timestamp, key, value) {
       if (!this.players_[id]) {
-        console.error('[updatePlayerInfo] Id ' + id +
-          ' does not exist');
+        console.error('[updatePlayerInfo] Id ' + id + ' does not exist');
         return;
       }
 
       this.players_[id].addPropertyNoRecord(timestamp, key, value);
-
-      // If we can potentially rename the player, do so.
-      if (key === 'name' || key === 'url') {
-        this.renderman_.redrawList();
-      }
-
-      this.renderman_.update();
+      this.clientRenderer_.playerUpdated(this.players_,
+                                         this.players_[id],
+                                         key,
+                                         value);
     },
 
     /**
@@ -91,19 +63,15 @@
      */
     updatePlayerInfo: function(id, timestamp, key, value) {
       if (!this.players_[id]) {
-        console.error('[updatePlayerInfo] Id ' + id +
-          ' does not exist');
+        console.error('[updatePlayerInfo] Id ' + id + ' does not exist');
         return;
       }
 
       this.players_[id].addProperty(timestamp, key, value);
-
-      // If we can potentially rename the player, do so.
-      if (key === 'name' || key === 'url') {
-        this.renderman_.redrawList();
-      }
-
-      this.renderman_.update();
+      this.clientRenderer_.playerUpdated(this.players_,
+                                         this.players_[id],
+                                         key,
+                                         value);
     }
   };
 
diff --git a/content/browser/resources/media/new/player_manager_test.html b/content/browser/resources/media/new/player_manager_test.html
deleted file mode 100644
index eff78b5..0000000
--- a/content/browser/resources/media/new/player_manager_test.html
+++ /dev/null
@@ -1,155 +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.
--->
-<!DOCTYPE html>
-<html>
-  <head>
-    <script src="webui_resource_test.js"></script>
-    <script src="player_manager.js"></script>
-    <script src="player_info.js"></script>
-  </head>
-  <body>
-    <script>
-      var doNothing = function() {
-      };
-
-      var emptyRenderMan = {
-        redrawList: doNothing,
-        update: doNothing,
-        select: doNothing
-      };
-
-      window.setUp = function() {
-        window.pm = new PlayerManager(emptyRenderMan);
-      };
-
-      window.tearDown = function() {
-        window.pm = null;
-      };
-
-      // Test a normal case of .addPlayer
-      window.testAddPlayer = function() {
-        window.pm.addPlayer('someid');
-        assertTrue(undefined !== window.pm.players_['someid']);
-      };
-
-      // Make sure that adding a player forces a redraw
-      // on the renderManager.
-      window.testAddPlayerForceRedraw = function() {
-        var redrew = false;
-        var mockRenderManager = {
-          redrawList: function() {
-            redrew = true;
-          }
-        };
-        var pm = new PlayerManager(mockRenderManager);
-
-        pm.addPlayer('someid');
-        assertTrue(redrew);
-      };
-
-      // On occasion, the backend will add an existing ID multiple times.
-      // make sure this doesn't break anything.
-      window.testAddPlayerAlreadyExisting = function() {
-        window.pm.addPlayer('someid');
-        window.pm.addPlayer('someid');
-        assertTrue(undefined !== window.pm.players_['someid']);
-      };
-
-      // If the removal is set, make sure that a player
-      // gets removed from the PlayerManager.
-      window.testRemovePlayerShouldRemove = function() {
-        // Because we don't have the checkbox.
-        window.pm.shouldRemovePlayer_ = function() {
-          return true;
-        };
-        window.pm.addPlayer('someid');
-        assertTrue(undefined !== window.pm.players_['someid']);
-        window.pm.removePlayer('someid');
-        assertTrue(undefined === window.pm.players_['someid']);
-      };
-
-      // On the removal of a player, the renderer should be forced
-      // to redraw the list.
-      window.testRemovePlayerRedraw = function() {
-        var redrew = false;
-
-        var fakeObj = {
-          redrawList: function() {
-            redrew = true;
-          }
-        };
-
-        var pm = new PlayerManager(fakeObj);
-        // Because we don't have the checkbox;
-        pm.shouldRemovePlayer_ = function() {
-          return true;
-        };
-
-
-        pm.addPlayer('someid');
-        assertTrue(undefined !== pm.players_['someid']);
-        pm.removePlayer('someid');
-        assertTrue(undefined === pm.players_['someid']);
-
-        assertTrue(redrew);
-      };
-
-      // If you shouldn't remove the player, the player shouldn't be
-      // removed.
-      window.testRemovePlayerNoRemove = function() {
-        window.pm = new PlayerManager(emptyRenderMan);
-        // Because we don't have the checkbox;
-        window.pm.shouldRemovePlayer_ = function() {
-          return false;
-        };
-        window.pm.addPlayer('someid');
-        assertTrue(undefined !== window.pm.players_['someid']);
-        window.pm.removePlayer('someid');
-        assertTrue(undefined !== window.pm.players_['someid']);
-      };
-
-
-      // Removing a nonexistant player shouldn't break anything
-      // The backend also occasionally does this.
-      window.testRemovePlayerNonExistant = function() {
-        // Because we don't have the checkbox;
-        window.pm.shouldRemovePlayer_ = function() {
-          return false;
-        };
-        window.pm.removePlayer('someid');
-        assertTrue(undefined === window.pm.players_['someid']);
-      };
-
-      // Trying to select a non-existant player should throw
-      // an exception
-      window.testSelectNonExistant = function() {
-        assertThrows(function() {
-          window.pm.selectPlayer('someId');
-        });
-      };
-
-      // Selecting an existing player should trigger a redraw
-      window.testSelectExistingPlayer = function() {
-        var selected = false;
-        var redrew = false;
-        var pm = new PlayerManager({
-          select: function() {
-            selected = true;
-          },
-          redrawList: function() {
-            redrew = true;
-          }
-        });
-        pm.addPlayer('someId');
-        pm.selectPlayer('someId');
-
-        assertTrue(selected);
-        assertTrue(redrew);
-      };
-    runTests();
-    </script>
-  </body>
-</html>
diff --git a/content/browser/resources/media/new/webui_resource_test.js b/content/browser/resources/media/new/webui_resource_test.js
deleted file mode 100644
index 6b05a30..0000000
--- a/content/browser/resources/media/new/webui_resource_test.js
+++ /dev/null
@@ -1,210 +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.
-
-/**
- * Tests that an observation matches the expected value.
- * @param {Object} expected The expected value.
- * @param {Object} observed The actual value.
- * @param {string=} opt_message Optional message to include with a test
- *     failure.
- */
-function assertEquals(expected, observed, opt_message) {
-  if (observed !== expected) {
-    var message = 'Assertion Failed\n  Observed: ' + observed +
-      '\n  Expected: ' + expected;
-    if (opt_message)
-      message = message + '\n  ' + opt_message;
-    throw new Error(message);
-  }
-}
-
-/**
- * Verifies that a test result is true.
- * @param {boolean} observed The observed value.
- * @param {string=} opt_message Optional message to include with a test
- *     failure.
- */
-function assertTrue(observed, opt_message) {
-  assertEquals(true, observed, opt_message);
-}
-
-/**
- * Verifies that a test result is false.
- * @param {boolean} observed The observed value.
- * @param {string=} opt_message Optional message to include with a test
- *     failure.
- */
-function assertFalse(observed, opt_message) {
-  assertEquals(false, observed, opt_message);
-}
-
-/**
- * Verifies that the observed and reference values differ.
- * @param {Object} reference The target value for comparison.
- * @param {Object} observed The test result.
- * @param {string=} opt_message Optional message to include with a test
- *     failure.
- */
-function assertNotEqual(reference, observed, opt_message) {
-  if (observed === reference) {
-    var message = 'Assertion Failed\n  Observed: ' + observed +
-      '\n  Reference: ' + reference;
-    if (opt_message)
-      message = message + '\n  ' + opt_message;
-    throw new Error(message);
-  }
-}
-
-/**
- * Verifies that a test evaluation results in an exception.
- * @param {!Function} f The test function.
- */
-function assertThrows(f) {
-  var triggeredError = false;
-  try {
-    f();
-  } catch (err) {
-    triggeredError = true;
-  }
-  if (!triggeredError)
-    throw new Error('Assertion Failed: throw expected.');
-}
-
-/**
- * Verifies that the contents of the expected and observed arrays match.
- * @param {!Array} expected The expected result.
- * @param {!Array} observed The actual result.
- */
-function assertArrayEquals(expected, observed) {
-  var v1 = Array.prototype.slice.call(expected);
-  var v2 = Array.prototype.slice.call(observed);
-  var equal = v1.length == v2.length;
-  if (equal) {
-    for (var i = 0; i < v1.length; i++) {
-      if (v1[i] !== v2[i]) {
-        equal = false;
-        break;
-      }
-    }
-  }
-  if (!equal) {
-    var message =
-      ['Assertion Failed', 'Observed: ' + v2, 'Expected: ' + v1].join('\n  ');
-    throw new Error(message);
-  }
-}
-
-/**
- * Verifies that the expected and observed result have the same content.
- * @param {*} expected The expected result.
- * @param {*} observed The actual result.
- */
-function assertDeepEquals(expected, observed, opt_message) {
-  if (typeof expected == 'object' && expected != null) {
-    assertNotEqual(null, observed);
-    for (var key in expected) {
-      assertTrue(key in observed, opt_message);
-      assertDeepEquals(expected[key], observed[key], opt_message);
-    }
-    for (var key in observed) {
-      assertTrue(key in expected, opt_message);
-    }
-  } else {
-    assertEquals(expected, observed, opt_message);
-  }
-}
-
-/**
- * Defines runTests.
- */
-(function(exports) {
-  /**
-   * List of test cases.
-   * @type {Array.<string>} List of function names for tests to run.
-   */
-  var testCases = [];
-
-  /**
-   * Indicates if all tests have run successfully.
-   * @type {boolean}
-   */
-  var cleanTestRun = true;
-
-  /**
-   * Armed during setup of a test to call the matching tear down code.
-   * @type {Function}
-   */
-  var pendingTearDown = null;
-
-  /**
-   * Runs all functions starting with test and reports success or
-   * failure of the test suite.
-   */
-  function runTests() {
-    for (var name in window) {
-      if (typeof window[name] == 'function' && /^test/.test(name))
-        testCases.push(name);
-    }
-    if (!testCases.length) {
-      console.error('Failed to find test cases.');
-      cleanTestRun = false;
-    }
-    continueTesting();
-  }
-
-  function reportPass(name) {
-    'use strict';
-    var text = document.createTextNode(name + ': PASSED');
-    var span = document.createElement('span');
-    span.appendChild(text);
-    document.body.appendChild(span);
-    document.body.appendChild(document.createElement('br'));
-  }
-
-  function reportFail(name) {
-    'use strict';
-    var text = document.createTextNode(name + ': =========FAILED=======');
-    var span = document.createElement('span');
-    span.appendChild(text);
-    document.body.appendChild(span);
-    document.body.appendChild(document.createElement('br'));
-  }
-
-  /**
-   * Runs the next test in the queue. Reports the test results if the queue is
-   * empty.
-   */
-  function continueTesting() {
-    if (pendingTearDown) {
-      pendingTearDown();
-      pendingTearDown = null;
-    }
-    if (testCases.length > 0) {
-      var fn = testCases.pop();
-      var isAsyncTest = window[fn].length;
-      try {
-        if (window.setUp)
-          window.setUp();
-        pendingTearDown = window.tearDown;
-        window[fn](continueTesting);
-        reportPass(fn);
-      } catch (err) {
-        reportFail(fn);
-        console.error('Failure in test ' + fn + '\n' + err);
-        console.log(err.stack);
-        cleanTestRun = false;
-      }
-      // Asynchronous tests must manually call continueTesting when complete.
-      if (!isAsyncTest)
-        continueTesting();
-    }
-    if (testCases.length) {
-      domAutomationController.setAutomationId(1);
-      domAutomationController.send('PENDING');
-    }
-  };
-
-  exports.runTests = runTests;
-})(this);
-
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index bc554c2..2eb7b51 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -9,7 +9,7 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 
diff --git a/content/browser/session_history_browsertest.cc b/content/browser/session_history_browsertest.cc
index d0bd950..7d006b6 100644
--- a/content/browser/session_history_browsertest.cc
+++ b/content/browser/session_history_browsertest.cc
@@ -12,7 +12,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -89,7 +89,7 @@
   }
 
   GURL GetTabURL() {
-    return shell()->web_contents()->GetURL();
+    return shell()->web_contents()->GetLastCommittedURL();
   }
 
   GURL GetURL(const std::string file) {
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 4268067..ade96cb 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -26,7 +26,7 @@
 
   // We treat javascript: as the same site as any URL since it is actually
   // a modifier on existing pages.
-  if (url.SchemeIs(chrome::kJavaScriptScheme))
+  if (url.SchemeIs(kJavaScriptScheme))
     return true;
 
   return url == GURL(kChromeUICrashURL) ||
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 3485fc5..e37ac97 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -13,7 +13,7 @@
 #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/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc
index 8e4c7a8..59b7474 100644
--- a/content/browser/speech/speech_recognition_browsertest.cc
+++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -18,7 +18,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/fake_speech_recognition_manager.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -69,7 +69,7 @@
     // then sets the URL fragment as 'pass' if it received the expected string.
     LoadAndStartSpeechRecognitionTest(filename);
 
-    EXPECT_EQ("pass", shell()->web_contents()->GetURL().ref());
+    EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
   }
 
   // ContentBrowserTest methods.
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc
index 2081b2f..2dae430 100644
--- a/content/browser/speech/speech_recognizer_impl.cc
+++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -564,7 +564,7 @@
       new OnDataConverter(input_parameters, output_parameters));
 
   audio_controller_ = AudioInputController::Create(
-      audio_manager, this, input_parameters, device_id_);
+      audio_manager, this, input_parameters, device_id_, NULL);
 
   if (!audio_controller_.get()) {
     return Abort(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_AUDIO));
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 361b4d1..d68b174 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -112,7 +112,6 @@
     return;
   }
 
-  std::set<GURL>::const_iterator origin;
   size_t* origins_to_delete_count = new size_t(origins.size());
   for (std::set<GURL>::const_iterator origin = origins.begin();
        origin != origins.end(); ++origin) {
@@ -305,6 +304,9 @@
                    GetDatabaseTracker()));
   }
 
+  if (GetFileSystemContext())
+    GetFileSystemContext()->Shutdown();
+
   if (GetDOMStorageContext())
     GetDOMStorageContext()->Shutdown();
 }
diff --git a/content/browser/streams/stream.cc b/content/browser/streams/stream.cc
index f5abe02..5d20fe6 100644
--- a/content/browser/streams/stream.cc
+++ b/content/browser/streams/stream.cc
@@ -23,10 +23,11 @@
 Stream::Stream(StreamRegistry* registry,
                StreamWriteObserver* write_observer,
                const GURL& url)
-    : data_bytes_read_(0),
-      can_add_data_(true),
+    : can_add_data_(true),
       url_(url),
       data_length_(0),
+      data_bytes_read_(0),
+      last_total_buffered_bytes_(0),
       registry_(registry),
       read_observer_(NULL),
       write_observer_(write_observer),
@@ -67,19 +68,50 @@
   write_observer_ = NULL;
 }
 
+void Stream::Abort() {
+  // Clear all buffer. It's safe to clear reader_ here since the same thread
+  // is used for both input and output operation.
+  writer_.reset();
+  reader_.reset();
+  ClearBuffer();
+  can_add_data_ = false;
+  registry_->UnregisterStream(url());
+}
+
 void Stream::AddData(scoped_refptr<net::IOBuffer> buffer, size_t size) {
+  if (!writer_.get())
+    return;
+
+  size_t current_buffered_bytes = writer_->GetTotalBufferedBytes();
+  if (!registry_->UpdateMemoryUsage(url(), current_buffered_bytes, size)) {
+    Abort();
+    return;
+  }
+
+  // Now it's guaranteed that this doesn't overflow. This must be done before
+  // Write() since GetTotalBufferedBytes() may return different value after
+  // Write() call, so if we use the new value, information in this instance and
+  // one in |registry_| become inconsistent.
+  last_total_buffered_bytes_ = current_buffered_bytes + size;
+
   can_add_data_ = writer_->Write(buffer, size);
 }
 
 void Stream::AddData(const char* data, size_t size) {
+  if (!writer_.get())
+    return;
+
   scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(size));
   memcpy(io_buffer->data(), data, size);
-  can_add_data_ = writer_->Write(io_buffer, size);
+  AddData(io_buffer, size);
 }
 
 void Stream::Finalize() {
+  if (!writer_.get())
+    return;
+
   writer_->Close(0);
-  writer_.reset(NULL);
+  writer_.reset();
 
   // Continue asynchronously.
   base::MessageLoopProxy::current()->PostTask(
@@ -90,10 +122,17 @@
 Stream::StreamState Stream::ReadRawData(net::IOBuffer* buf,
                                         int buf_size,
                                         int* bytes_read) {
+  DCHECK(buf);
+  DCHECK(bytes_read);
+
   *bytes_read = 0;
   if (!data_.get()) {
-    data_length_ = 0;
-    data_bytes_read_ = 0;
+    DCHECK(!data_length_);
+    DCHECK(!data_bytes_read_);
+
+    if (!reader_.get())
+      return STREAM_ABORTED;
+
     ByteStreamReader::StreamState state = reader_->Read(&data_, &data_length_);
     switch (state) {
       case ByteStreamReader::STREAM_HAS_DATA:
@@ -113,7 +152,7 @@
   memcpy(buf->data(), data_->data() + data_bytes_read_, to_read);
   data_bytes_read_ += to_read;
   if (data_bytes_read_ >= data_length_)
-    data_ = NULL;
+    ClearBuffer();
 
   *bytes_read = to_read;
   return STREAM_HAS_DATA;
@@ -150,4 +189,10 @@
     read_observer_->OnDataAvailable(this);
 }
 
+void Stream::ClearBuffer() {
+  data_ = NULL;
+  data_length_ = 0;
+  data_bytes_read_ = 0;
+}
+
 }  // namespace content
diff --git a/content/browser/streams/stream.h b/content/browser/streams/stream.h
index 85edc88..a0599de 100644
--- a/content/browser/streams/stream.h
+++ b/content/browser/streams/stream.h
@@ -36,6 +36,7 @@
     STREAM_HAS_DATA,
     STREAM_COMPLETE,
     STREAM_EMPTY,
+    STREAM_ABORTED,
   };
 
   // Creates a stream.
@@ -81,6 +82,15 @@
 
   const GURL& url() const { return url_; }
 
+  // For StreamRegistry to remember the last memory usage reported to it.
+  size_t last_total_buffered_bytes() const {
+    return last_total_buffered_bytes_;
+  }
+
+ protected:
+  // Stops accepting new data and make ReadRawData() return STREAM_ABORTED.
+  void Abort();
+
  private:
   friend class base::RefCountedThreadSafe<Stream>;
 
@@ -89,13 +99,25 @@
   void OnSpaceAvailable();
   void OnDataAvailable();
 
-  size_t data_bytes_read_;
+  // Clears |data_| and related variables.
+  void ClearBuffer();
+
   bool can_add_data_;
 
   GURL url_;
 
+  // Buffer for storing data read from |reader_| but not yet read out from this
+  // Stream by ReadRawData() method.
   scoped_refptr<net::IOBuffer> data_;
+  // Number of bytes read from |reader_| into |data_| including bytes already
+  // read out.
   size_t data_length_;
+  // Number of bytes in |data_| that are already read out.
+  size_t data_bytes_read_;
+
+  // Last value returned by writer_->TotalBufferedBytes() in AddData(). Stored
+  // in order to check memory usage.
+  size_t last_total_buffered_bytes_;
 
   scoped_ptr<ByteStreamWriter> writer_;
   scoped_ptr<ByteStreamReader> reader_;
diff --git a/content/browser/streams/stream_registry.cc b/content/browser/streams/stream_registry.cc
index 39d24b3..1a83c41 100644
--- a/content/browser/streams/stream_registry.cc
+++ b/content/browser/streams/stream_registry.cc
@@ -8,7 +8,15 @@
 
 namespace content {
 
-StreamRegistry::StreamRegistry() {
+namespace {
+// The maximum size of memory each StreamRegistry instance is allowed to use
+// for its Stream instances.
+const size_t kDefaultMaxMemoryUsage = 1024 * 1024 * 1024U;  // 1GiB
+}
+
+StreamRegistry::StreamRegistry()
+    : total_memory_usage_(0),
+      max_memory_usage_(kDefaultMaxMemoryUsage) {
 }
 
 StreamRegistry::~StreamRegistry() {
@@ -42,7 +50,38 @@
 
 void StreamRegistry::UnregisterStream(const GURL& url) {
   DCHECK(CalledOnValidThread());
+
+  StreamMap::iterator iter = streams_.find(url);
+  if (iter == streams_.end())
+    return;
+
+  size_t buffered_bytes = iter->second->last_total_buffered_bytes();
+  DCHECK_LE(buffered_bytes, total_memory_usage_);
+  total_memory_usage_ -= buffered_bytes;
   streams_.erase(url);
 }
 
+bool StreamRegistry::UpdateMemoryUsage(const GURL& url,
+                                       size_t current_size,
+                                       size_t increase) {
+  DCHECK(CalledOnValidThread());
+
+  StreamMap::iterator iter = streams_.find(url);
+  // A Stream must be registered with its parent registry to get memory.
+  if (iter == streams_.end())
+    return false;
+
+  size_t last_size = iter->second->last_total_buffered_bytes();
+  DCHECK_LE(last_size, total_memory_usage_);
+  size_t usage_of_others = total_memory_usage_ - last_size;
+  DCHECK_LE(current_size, last_size);
+  size_t current_total_memory_usage = usage_of_others + current_size;
+
+  if (increase > max_memory_usage_ - current_total_memory_usage)
+    return false;
+
+  total_memory_usage_ = current_total_memory_usage + increase;
+  return true;
+}
+
 }  // namespace content
diff --git a/content/browser/streams/stream_registry.h b/content/browser/streams/stream_registry.h
index e75c97c..a359411 100644
--- a/content/browser/streams/stream_registry.h
+++ b/content/browser/streams/stream_registry.h
@@ -32,20 +32,37 @@
 
   void UnregisterStream(const GURL& url);
 
+  // Called by Stream instances to request increase of memory usage. If the
+  // total memory usage for this registry is going to exceed the limit,
+  // returns false. Otherwise, updates |total_memory_usage_| and returns true.
+  //
+  // |current_size| is the up-to-date size of ByteStream of the Stream instance
+  // and |increase| must be the amount of data going to be added to the Stream
+  // instance.
+  bool UpdateMemoryUsage(const GURL& url, size_t current_size, size_t increase);
+
   // Gets the stream associated with |url|.  Returns NULL if there is no such
   // stream.
   scoped_refptr<Stream> GetStream(const GURL& url);
 
+  void set_max_memory_usage_for_testing(size_t size) {
+    max_memory_usage_ = size;
+  }
+
  private:
   typedef std::map<GURL, scoped_refptr<Stream> > StreamMap;
 
   StreamMap streams_;
 
+  size_t total_memory_usage_;
+
+  // Maximum amount of memory allowed to use for Stream instances registered
+  // with this registry.
+  size_t max_memory_usage_;
+
   DISALLOW_COPY_AND_ASSIGN(StreamRegistry);
 };
 
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_STREAMS_STREAM_REGISTRY_H_
-
-
diff --git a/content/browser/streams/stream_unittest.cc b/content/browser/streams/stream_unittest.cc
index 36add1d..a2d9593 100644
--- a/content/browser/streams/stream_unittest.cc
+++ b/content/browser/streams/stream_unittest.cc
@@ -41,7 +41,7 @@
 
 class TestStreamReader : public StreamReadObserver {
  public:
-  TestStreamReader() : buffer_(new net::GrowableIOBuffer()) {
+  TestStreamReader() : buffer_(new net::GrowableIOBuffer()), completed_(false) {
   }
   virtual ~TestStreamReader() {}
 
@@ -50,8 +50,25 @@
     scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
 
     int bytes_read = 0;
-    while (stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read) ==
-           Stream::STREAM_HAS_DATA) {
+    while (true) {
+      Stream::StreamState state =
+          stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read);
+      switch (state) {
+        case Stream::STREAM_HAS_DATA:
+          // TODO(tyoshino): Move these expectations to the beginning of Read()
+          // method once Stream::Finalize() is fixed.
+          EXPECT_FALSE(completed_);
+          break;
+        case Stream::STREAM_COMPLETE:
+          completed_ = true;
+          return;
+        case Stream::STREAM_EMPTY:
+          EXPECT_FALSE(completed_);
+          return;
+        case Stream::STREAM_ABORTED:
+          EXPECT_FALSE(completed_);
+          return;
+      }
       size_t old_capacity = buffer_->capacity();
       buffer_->SetCapacity(old_capacity + bytes_read);
       memcpy(buffer_->StartOfBuffer() + old_capacity,
@@ -65,8 +82,13 @@
 
   scoped_refptr<net::GrowableIOBuffer> buffer() { return buffer_; }
 
+  bool completed() const {
+    return completed_;
+  }
+
  private:
   scoped_refptr<net::GrowableIOBuffer> buffer_;
+  bool completed_;
 };
 
 class TestStreamWriter : public StreamWriteObserver {
@@ -137,14 +159,38 @@
   scoped_refptr<net::IOBuffer> buffer(NewIOBuffer(kBufferSize));
   writer.Write(stream.get(), buffer, kBufferSize);
   stream->Finalize();
-  reader.Read(stream.get());
   base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(reader.completed());
 
   ASSERT_EQ(reader.buffer()->capacity(), kBufferSize);
   for (int i = 0; i < kBufferSize; i++)
     EXPECT_EQ(buffer->data()[i], reader.buffer()->data()[i]);
 }
 
+// Test that even if a reader receives an empty buffer, once TransferData()
+// method is called on it with |source_complete| = true, following Read() calls
+// on it never returns STREAM_EMPTY. Together with StreamTest.Stream above, this
+// guarantees that Reader::Read() call returns only STREAM_HAS_DATA
+// or STREAM_COMPLETE in |data_available_callback_| call corresponding to
+// Writer::Close().
+TEST_F(StreamTest, ClosedReaderDoesNotReturnStreamEmpty) {
+  TestStreamReader reader;
+  TestStreamWriter writer;
+
+  GURL url("blob://stream");
+  scoped_refptr<Stream> stream(
+      new Stream(registry_.get(), &writer, url));
+  EXPECT_TRUE(stream->SetReadObserver(&reader));
+
+  const int kBufferSize = 0;
+  scoped_refptr<net::IOBuffer> buffer(NewIOBuffer(kBufferSize));
+  stream->AddData(buffer, kBufferSize);
+  stream->Finalize();
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_TRUE(reader.completed());
+  EXPECT_EQ(0, reader.buffer()->capacity());
+}
+
 TEST_F(StreamTest, GetStream) {
   TestStreamWriter writer;
 
@@ -207,4 +253,59 @@
   ASSERT_FALSE(stream2.get());
 }
 
+TEST_F(StreamTest, MemoryExceedMemoryUsageLimit) {
+  TestStreamWriter writer1;
+  TestStreamWriter writer2;
+
+  GURL url1("blob://stream");
+  scoped_refptr<Stream> stream1(
+      new Stream(registry_.get(), &writer1, url1));
+
+  GURL url2("blob://stream2");
+  scoped_refptr<Stream> stream2(
+      new Stream(registry_.get(), &writer2, url2));
+
+  const int kMaxMemoryUsage = 1500000;
+  registry_->set_max_memory_usage_for_testing(kMaxMemoryUsage);
+
+  const int kBufferSize = 1000000;
+  scoped_refptr<net::IOBuffer> buffer(NewIOBuffer(kBufferSize));
+  writer1.Write(stream1.get(), buffer, kBufferSize);
+  // Make transfer happen.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  writer2.Write(stream2.get(), buffer, kBufferSize);
+
+  // Written data (1000000 * 2) exceeded limit (1500000). |stream2| should be
+  // unregistered with |registry_|.
+  EXPECT_EQ(NULL, registry_->GetStream(url2).get());
+
+  writer1.Write(stream1.get(), buffer, kMaxMemoryUsage - kBufferSize);
+  // Should be accepted since stream2 is unregistered and the new data is not
+  // so big to exceed the limit.
+  EXPECT_FALSE(registry_->GetStream(url1).get() == NULL);
+}
+
+TEST_F(StreamTest, UnderMemoryUsageLimit) {
+  TestStreamWriter writer;
+  TestStreamReader reader;
+
+  GURL url("blob://stream");
+  scoped_refptr<Stream> stream(new Stream(registry_.get(), &writer, url));
+  EXPECT_TRUE(stream->SetReadObserver(&reader));
+
+  registry_->set_max_memory_usage_for_testing(1500000);
+
+  const int kBufferSize = 1000000;
+  scoped_refptr<net::IOBuffer> buffer(NewIOBuffer(kBufferSize));
+  writer.Write(stream.get(), buffer, kBufferSize);
+
+  // Run loop to make |reader| consume the data.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  writer.Write(stream.get(), buffer, kBufferSize);
+
+  EXPECT_EQ(stream.get(), registry_->GetStream(url).get());
+}
+
 }  // namespace content
diff --git a/content/browser/streams/stream_url_request_job.cc b/content/browser/streams/stream_url_request_job.cc
index e36c5d4..09b9e6d 100644
--- a/content/browser/streams/stream_url_request_job.cc
+++ b/content/browser/streams/stream_url_request_job.cc
@@ -39,19 +39,42 @@
 void StreamURLRequestJob::OnDataAvailable(Stream* stream) {
   // Clear the IO_PENDING status.
   SetStatus(net::URLRequestStatus());
-  if (pending_buffer_.get()) {
-    int bytes_read;
-    stream_->ReadRawData(
-        pending_buffer_.get(), pending_buffer_size_, &bytes_read);
+  // Do nothing if pending_buffer_ is empty, i.e. there's no ReadRawData()
+  // operation waiting for IO completion.
+  if (!pending_buffer_.get())
+    return;
 
-    // Clear the buffers before notifying the read is complete, so that it is
-    // safe for the observer to read.
-    pending_buffer_ = NULL;
-    pending_buffer_size_ = 0;
+  // pending_buffer_ is set to the IOBuffer instance provided to ReadRawData()
+  // by URLRequestJob.
 
-    total_bytes_read_ += bytes_read;
-    NotifyReadComplete(bytes_read);
+  int bytes_read;
+  switch (stream_->ReadRawData(
+      pending_buffer_.get(), pending_buffer_size_, &bytes_read)) {
+    case Stream::STREAM_HAS_DATA:
+      DCHECK_GT(bytes_read, 0);
+      break;
+    case Stream::STREAM_COMPLETE:
+      // Ensure this. Calling NotifyReadComplete call with 0 signals
+      // completion.
+      bytes_read = 0;
+      break;
+    case Stream::STREAM_EMPTY:
+      NOTREACHED();
+      break;
+    case Stream::STREAM_ABORTED:
+      // Handle this as connection reset.
+      NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                       net::ERR_CONNECTION_RESET));
+      break;
   }
+
+  // Clear the buffers before notifying the read is complete, so that it is
+  // safe for the observer to read.
+  pending_buffer_ = NULL;
+  pending_buffer_size_ = 0;
+
+  total_bytes_read_ += bytes_read;
+  NotifyReadComplete(bytes_read);
 }
 
 // net::URLRequestJob methods.
@@ -74,6 +97,7 @@
   if (request_failed_)
     return true;
 
+  DCHECK(buf);
   DCHECK(bytes_read);
   int to_read = buf_size;
   if (max_range_ && to_read) {
@@ -96,6 +120,11 @@
       pending_buffer_size_ = to_read;
       SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
       return false;
+    case Stream::STREAM_ABORTED:
+      // Handle this as connection reset.
+      NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
+                                       net::ERR_CONNECTION_RESET));
+      return false;
   }
   NOTREACHED();
   return false;
@@ -167,7 +196,6 @@
 
   // TODO(zork): Share these with BlobURLRequestJob.
   net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR;
-  std::string status_txt;
   switch (error_code) {
     case net::ERR_ACCESS_DENIED:
       status_code = net::HTTP_FORBIDDEN;
diff --git a/content/browser/tracing/trace_controller_impl.cc b/content/browser/tracing/trace_controller_impl.cc
index 54e0c86..53e4ea5 100644
--- a/content/browser/tracing/trace_controller_impl.cc
+++ b/content/browser/tracing/trace_controller_impl.cc
@@ -26,9 +26,11 @@
 class AutoStopTraceSubscriberStdio : public TraceSubscriberStdio {
  public:
   AutoStopTraceSubscriberStdio(const base::FilePath& file_path)
-      : TraceSubscriberStdio(file_path) {}
+      : TraceSubscriberStdio(file_path,
+                             FILE_TYPE_PROPERTY_LIST,
+                             false) {}
 
-  static void EndStartupTrace(TraceSubscriberStdio* subscriber) {
+  static void EndStartupTrace(AutoStopTraceSubscriberStdio* subscriber) {
     if (!TraceControllerImpl::GetInstance()->EndTracingAsync(subscriber))
       delete subscriber;
     // else, the tracing will end asynchronously in OnEndTracingComplete().
diff --git a/content/browser/tracing/trace_subscriber_stdio.cc b/content/browser/tracing/trace_subscriber_stdio.cc
index b5f6e82..35b9646 100644
--- a/content/browser/tracing/trace_subscriber_stdio.cc
+++ b/content/browser/tracing/trace_subscriber_stdio.cc
@@ -14,39 +14,78 @@
 namespace content {
 
 // All method calls on this class are done on a SequencedWorkerPool thread.
-class TraceSubscriberStdioImpl
-    : public base::RefCountedThreadSafe<TraceSubscriberStdioImpl> {
+class TraceSubscriberStdio::TraceSubscriberStdioWorker
+    : public base::RefCountedThreadSafe<TraceSubscriberStdioWorker> {
  public:
-  explicit TraceSubscriberStdioImpl(const base::FilePath& path)
+  TraceSubscriberStdioWorker(const base::FilePath& path,
+                             FileType file_type,
+                             bool has_system_trace)
       : path_(path),
-        file_(0) {}
+        file_type_(file_type),
+        has_system_trace_(has_system_trace),
+        file_(0),
+        needs_comma_(false),
+        wrote_trace_(false),
+        has_pending_system_trace_(false),
+        wrote_system_trace_(false) {}
 
-  void OnStart() {
+  void OnTraceStart() {
     DCHECK(!file_);
-    trace_buffer_.SetOutputCallback(
-        base::Bind(&TraceSubscriberStdioImpl::Write, this));
     file_ = file_util::OpenFile(path_, "w+");
-    if (IsValid()) {
-      LOG(INFO) << "Logging performance trace to file: " << path_.value();
-      trace_buffer_.Start();
-    } else {
+    if (!IsValid()) {
       LOG(ERROR) << "Failed to open performance trace file: " << path_.value();
+      return;
+    }
+
+    LOG(INFO) << "Logging performance trace to file: " << path_.value();
+    if (file_type_ == FILE_TYPE_PROPERTY_LIST)
+      WriteString("{\"traceEvents\":");
+    WriteString("[");
+  }
+
+  void OnTraceData(const scoped_refptr<base::RefCountedString>& data_ptr) {
+    if (!IsValid())
+      return;
+    if (needs_comma_)
+      WriteString(",");
+    WriteString(data_ptr->data());
+    needs_comma_ = true;
+  }
+
+  void OnSystemTraceData(
+      const scoped_refptr<base::RefCountedString>& data_ptr) {
+    if (wrote_trace_) {
+      WriteSystemTrace(data_ptr);
+      End();
+    } else {
+      pending_system_trace_ = data_ptr;
+      has_pending_system_trace_ = true;
     }
   }
 
-  void OnData(const scoped_refptr<base::RefCountedString>& data_ptr) {
-    trace_buffer_.AddFragment(data_ptr->data());
-  }
+  void OnTraceEnd() {
+    if (!IsValid())
+      return;
+    WriteString("]");
 
-  void OnEnd() {
-    trace_buffer_.Finish();
-    CloseFile();
+    wrote_trace_ = true;
+
+    if (!has_system_trace_ || wrote_system_trace_) {
+      End();
+      return;
+    }
+
+    WriteString(",");
+    if (has_pending_system_trace_) {
+      WriteSystemTrace(pending_system_trace_);
+      End();
+    }
   }
 
  private:
-  friend class base::RefCountedThreadSafe<TraceSubscriberStdioImpl>;
+  friend class base::RefCountedThreadSafe<TraceSubscriberStdioWorker>;
 
-  ~TraceSubscriberStdioImpl() {
+  ~TraceSubscriberStdioWorker() {
     CloseFile();
   }
 
@@ -58,32 +97,79 @@
     if (file_) {
       fclose(file_);
       file_ = 0;
+
     }
-    // This is important, as it breaks a reference cycle.
-    trace_buffer_.SetOutputCallback(
-        base::debug::TraceResultBuffer::OutputCallback());
   }
 
-  void Write(const std::string& output_str) {
+  void End() {
+    if (file_type_ == FILE_TYPE_PROPERTY_LIST)
+      WriteString("}");
+    CloseFile();
+  }
+
+  void WriteSystemTrace(const scoped_refptr<base::RefCountedString>& data_ptr) {
+    // Newlines need to be replaced with the string "\n" to be parsed correctly.
+    // Double quotes need to be replaced with the string "\"".
+    // System logs are ASCII.
+    const std::string& data = data_ptr->data();
+    const char* chars = data.c_str();
+    WriteString("\"systemTraceEvents\":\"");
+    size_t old_index = 0;
+    for (size_t new_index = data.find_first_of("\n\"");
+         std::string::npos != new_index;
+         old_index = new_index + 1,
+         new_index = data.find_first_of("\n\"", old_index)) {
+      WriteChars(chars + old_index, new_index - old_index);
+      if (chars[new_index] == '\n')
+        WriteChars("\\n", 2);
+      else
+        WriteChars("\\\"", 2);
+    }
+    WriteChars(chars + old_index, data.size() - old_index);
+    WriteString("\"");
+    wrote_system_trace_ = true;
+  }
+
+  void WriteChars(const char* output_chars, size_t size) {
+    if (size == 0)
+      return;
+
     if (IsValid()) {
-      size_t written = fwrite(output_str.data(), 1, output_str.size(), file_);
-      if (written != output_str.size()) {
+      size_t written = fwrite(output_chars, 1, size, file_);
+      if (written != size) {
         LOG(ERROR) << "Error " << ferror(file_) << " in fwrite() to trace file";
         CloseFile();
       }
     }
   }
 
+  void WriteString(const std::string& output_str) {
+    WriteChars(output_str.data(), output_str.size());
+  }
+
   base::FilePath path_;
+  const FileType file_type_;
+  const bool has_system_trace_;
   FILE* file_;
-  base::debug::TraceResultBuffer trace_buffer_;
+  bool needs_comma_;
+  bool wrote_trace_;
+  bool has_pending_system_trace_;
+  bool wrote_system_trace_;
+  scoped_refptr<base::RefCountedString> pending_system_trace_;
+  DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdioWorker);
 };
 
-TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path)
-    : impl_(new TraceSubscriberStdioImpl(path)) {
+TraceSubscriberStdio::TraceSubscriberStdio(const base::FilePath& path,
+                                           FileType file_type,
+                                           bool has_system_trace)
+    : worker_(new TraceSubscriberStdioWorker(path,
+                                             file_type,
+                                             has_system_trace)) {
+  if (has_system_trace)
+    CHECK_EQ(FILE_TYPE_PROPERTY_LIST, file_type);
   BrowserThread::PostBlockingPoolSequencedTask(
       __FILE__, FROM_HERE,
-      base::Bind(&TraceSubscriberStdioImpl::OnStart, impl_));
+      base::Bind(&TraceSubscriberStdioWorker::OnTraceStart, worker_));
 }
 
 TraceSubscriberStdio::~TraceSubscriberStdio() {
@@ -92,14 +178,23 @@
 void TraceSubscriberStdio::OnEndTracingComplete() {
   BrowserThread::PostBlockingPoolSequencedTask(
       __FILE__, FROM_HERE,
-      base::Bind(&TraceSubscriberStdioImpl::OnEnd, impl_));
+      base::Bind(&TraceSubscriberStdioWorker::OnTraceEnd, worker_));
 }
 
 void TraceSubscriberStdio::OnTraceDataCollected(
     const scoped_refptr<base::RefCountedString>& data_ptr) {
   BrowserThread::PostBlockingPoolSequencedTask(
       __FILE__, FROM_HERE,
-      base::Bind(&TraceSubscriberStdioImpl::OnData, impl_, data_ptr));
+      base::Bind(&TraceSubscriberStdioWorker::OnTraceData, worker_, data_ptr));
+}
+
+void TraceSubscriberStdio::OnEndSystemTracing(
+    const scoped_refptr<base::RefCountedString>& events_str_ptr) {
+  BrowserThread::PostBlockingPoolSequencedTask(
+      __FILE__, FROM_HERE,
+      base::Bind(&TraceSubscriberStdioWorker::OnSystemTraceData,
+                 worker_,
+                 events_str_ptr));
 }
 
 }  // namespace content
diff --git a/content/browser/tracing/trace_subscriber_stdio.h b/content/browser/tracing/trace_subscriber_stdio.h
index 06a70db..b9fc4f7 100644
--- a/content/browser/tracing/trace_subscriber_stdio.h
+++ b/content/browser/tracing/trace_subscriber_stdio.h
@@ -17,14 +17,24 @@
 
 namespace content {
 
-class TraceSubscriberStdioImpl;
-
 // Stdio implementation of TraceSubscriber. Use this to write traces to a file.
 class CONTENT_EXPORT TraceSubscriberStdio
     : NON_EXPORTED_BASE(public TraceSubscriber) {
  public:
-  // Creates or overwrites the specified file. Check IsValid() for success.
-  explicit TraceSubscriberStdio(const base::FilePath& path);
+  enum FileType {
+    // Output file as array, representing trace events:
+    // [event1, event2, ...]
+    FILE_TYPE_ARRAY,
+    // Output file as property list with one or two items:
+    // {traceEvents: [event1, event2, ...],
+    //  systemTraceEvents: "event1\nevent2\n..." // optional}
+    FILE_TYPE_PROPERTY_LIST
+  };
+
+  // has_system_trace indicates whether system trace events are expected.
+  TraceSubscriberStdio(const base::FilePath& path,
+                       FileType file_type,
+                       bool has_system_trace);
   virtual ~TraceSubscriberStdio();
 
   // Implementation of TraceSubscriber
@@ -32,8 +42,13 @@
   virtual void OnTraceDataCollected(
       const scoped_refptr<base::RefCountedString>& data_ptr) OVERRIDE;
 
+  // To be used as callback to DebugDaemonClient::RequestStopSystemTracing().
+  virtual void OnEndSystemTracing(
+      const scoped_refptr<base::RefCountedString>& events_str_ptr);
+
  private:
-  scoped_refptr<TraceSubscriberStdioImpl> impl_;
+  class TraceSubscriberStdioWorker;
+  scoped_refptr<TraceSubscriberStdioWorker> worker_;
   DISALLOW_COPY_AND_ASSIGN(TraceSubscriberStdio);
 };
 
diff --git a/content/browser/tracing/trace_subscriber_stdio_unittest.cc b/content/browser/tracing/trace_subscriber_stdio_unittest.cc
index 0b0e7c2..0a3be3a 100644
--- a/content/browser/tracing/trace_subscriber_stdio_unittest.cc
+++ b/content/browser/tracing/trace_subscriber_stdio_unittest.cc
@@ -14,12 +14,14 @@
 
 class TraceSubscriberStdioTest : public ::testing::Test {};
 
-TEST_F(TraceSubscriberStdioTest, CanWriteDataToFile) {
+TEST_F(TraceSubscriberStdioTest, CanWriteArray) {
   base::ScopedTempDir trace_dir;
   ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
   base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
   {
-    TraceSubscriberStdio subscriber(trace_file);
+    TraceSubscriberStdio subscriber(trace_file,
+                                    TraceSubscriberStdio::FILE_TYPE_ARRAY,
+                                    false);
 
     std::string foo("foo");
     subscriber.OnTraceDataCollected(
@@ -37,4 +39,94 @@
   EXPECT_EQ("[foo,bar]", result);
 }
 
+TEST_F(TraceSubscriberStdioTest, CanWritePropertyList) {
+  base::ScopedTempDir trace_dir;
+  ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
+  base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
+  {
+    TraceSubscriberStdio subscriber(
+        trace_file,
+        TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
+        false);
+
+    std::string foo("foo");
+    subscriber.OnTraceDataCollected(
+        make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
+
+    std::string bar("bar");
+    subscriber.OnTraceDataCollected(
+        make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
+
+    subscriber.OnEndTracingComplete();
+  }
+  BrowserThread::GetBlockingPool()->FlushForTesting();
+  std::string result;
+  EXPECT_TRUE(file_util::ReadFileToString(trace_file, &result));
+  EXPECT_EQ("{\"traceEvents\":[foo,bar]}", result);
+}
+
+TEST_F(TraceSubscriberStdioTest, CanWriteSystemDataFirst) {
+  base::ScopedTempDir trace_dir;
+  ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
+  base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
+  {
+    TraceSubscriberStdio subscriber(
+        trace_file,
+        TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
+        true);
+
+    std::string foo("foo");
+    subscriber.OnTraceDataCollected(
+        make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
+
+    std::string bar("bar");
+    subscriber.OnTraceDataCollected(
+        make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
+
+    std::string systemTrace("event1\nev\"ent\"2\n");
+    subscriber.OnEndSystemTracing(
+        make_scoped_refptr(base::RefCountedString::TakeString(&systemTrace)));
+    subscriber.OnEndTracingComplete();
+  }
+  BrowserThread::GetBlockingPool()->FlushForTesting();
+  std::string result;
+  EXPECT_TRUE(file_util::ReadFileToString(trace_file, &result));
+  EXPECT_EQ(
+    "{\"traceEvents\":[foo,bar],\""
+    "systemTraceEvents\":\"event1\\nev\\\"ent\\\"2\\n\"}",
+    result);
+}
+
+TEST_F(TraceSubscriberStdioTest, CanWriteSystemDataLast) {
+  base::ScopedTempDir trace_dir;
+  ASSERT_TRUE(trace_dir.CreateUniqueTempDir());
+  base::FilePath trace_file(trace_dir.path().AppendASCII("trace.txt"));
+  {
+    TraceSubscriberStdio subscriber(
+        trace_file,
+        TraceSubscriberStdio::FILE_TYPE_PROPERTY_LIST,
+        true);
+
+    std::string foo("foo");
+    subscriber.OnTraceDataCollected(
+        make_scoped_refptr(base::RefCountedString::TakeString(&foo)));
+
+    std::string bar("bar");
+    subscriber.OnTraceDataCollected(
+        make_scoped_refptr(base::RefCountedString::TakeString(&bar)));
+
+    std::string systemTrace("event1\nev\"ent\"2\n");
+    subscriber.OnEndTracingComplete();
+    subscriber.OnEndSystemTracing(
+        make_scoped_refptr(base::RefCountedString::TakeString(&systemTrace)));
+  }
+  BrowserThread::GetBlockingPool()->FlushForTesting();
+  std::string result;
+  EXPECT_TRUE(file_util::ReadFileToString(trace_file, &result));
+  EXPECT_EQ(
+    "{\"traceEvents\":[foo,bar],\""
+    "systemTraceEvents\":\"event1\\nev\\\"ent\\\"2\\n\"}",
+    result);
+}
+
 }  // namespace content
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index 2e56218..766b82e 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -16,7 +16,6 @@
 #include "base/synchronization/waitable_event.h"
 #include "content/browser/browser_child_process_host_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/child/child_process.h"
 #include "content/common/child_process_host_impl.h"
 #include "content/common/utility_messages.h"
 #include "content/public/browser/browser_thread.h"
@@ -24,7 +23,6 @@
 #include "content/public/browser/utility_process_host_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/process_type.h"
-#include "content/utility/utility_thread_impl.h"
 #include "ipc/ipc_switches.h"
 #include "ui/base/ui_base_switches.h"
 
@@ -53,53 +51,8 @@
 };
 #endif
 
-// We want to ensure there's only one utility thread running at a time, as there
-// are many globals used in the utility process.
-static base::LazyInstance<base::Lock> g_one_utility_thread_lock;
 
-// Single process not supported in multiple dll mode currently.
-#if !defined(CHROME_MULTIPLE_DLL)
-class UtilityMainThread : public base::Thread {
- public:
-  UtilityMainThread(const std::string& channel_id)
-      : Thread("Chrome_InProcUtilityThread"),
-        channel_id_(channel_id) {
-  }
-
-  virtual ~UtilityMainThread() {
-    Stop();
-  }
-
- private:
-  // base::Thread implementation:
-  virtual void Init() OVERRIDE {
-    // We need to return right away or else the main thread that started us will
-    // hang.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&UtilityMainThread::InitInternal, base::Unretained(this)));
-  }
-
-  virtual void CleanUp() OVERRIDE {
-    child_process_.reset();
-
-    // See comment in RendererMainThread.
-    SetThreadWasQuitProperly(true);
-    g_one_utility_thread_lock.Get().Release();
-  }
-
-  void InitInternal() {
-    g_one_utility_thread_lock.Get().Acquire();
-    child_process_.reset(new ChildProcess());
-    child_process_->set_main_thread(new UtilityThreadImpl(channel_id_));
-  }
-
-  std::string channel_id_;
-  scoped_ptr<ChildProcess> child_process_;
-
-  DISALLOW_COPY_AND_ASSIGN(UtilityMainThread);
-};
-#endif  // !CHROME_MULTIPLE_DLL
+UtilityMainThreadFactoryFunction g_utility_main_thread_factory = NULL;
 
 UtilityProcessHost* UtilityProcessHost::Create(
     UtilityProcessHostClient* client,
@@ -107,6 +60,11 @@
   return new UtilityProcessHostImpl(client, client_task_runner);
 }
 
+void UtilityProcessHost::RegisterUtilityMainThreadFactory(
+    UtilityMainThreadFactoryFunction create) {
+  g_utility_main_thread_factory = create;
+}
+
 UtilityProcessHostImpl::UtilityProcessHostImpl(
     UtilityProcessHostClient* client,
     base::SequencedTaskRunner* client_task_runner)
@@ -196,15 +154,13 @@
     return false;
 
   // Single process not supported in multiple dll mode currently.
-#if !defined(CHROME_MULTIPLE_DLL)
-  if (RenderProcessHost::run_renderer_in_process()) {
+  if (RenderProcessHost::run_renderer_in_process() &&
+      g_utility_main_thread_factory) {
     // See comment in RenderProcessHostImpl::Init() for the background on why we
     // support single process mode this way.
-    in_process_thread_.reset(new UtilityMainThread(channel_id));
+    in_process_thread_.reset(g_utility_main_thread_factory(channel_id));
     in_process_thread_->Start();
-  } else
-#endif  // !CHROME_MULTIPLE_DLL
-  {
+  } else {
     const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
     int child_flags = child_flags_;
 
diff --git a/content/browser/utility_process_host_impl.h b/content/browser/utility_process_host_impl.h
index 6eecd3d..5443e09 100644
--- a/content/browser/utility_process_host_impl.h
+++ b/content/browser/utility_process_host_impl.h
@@ -18,11 +18,11 @@
 
 namespace base {
 class SequencedTaskRunner;
+class Thread;
 }
 
 namespace content {
 class BrowserChildProcessHostImpl;
-class UtilityMainThread;
 
 class CONTENT_EXPORT UtilityProcessHostImpl
     : public NON_EXPORTED_BASE(UtilityProcessHost),
@@ -83,10 +83,8 @@
 
   scoped_ptr<BrowserChildProcessHostImpl> process_;
 
-#if !defined(CHROME_MULTIPLE_DLL)
   // Used in single-process mode instead of process_.
-  scoped_ptr<UtilityMainThread> in_process_thread_;
-#endif
+  scoped_ptr<base::Thread> in_process_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(UtilityProcessHostImpl);
 };
diff --git a/content/browser/web_contents/interstitial_page_impl.cc b/content/browser/web_contents/interstitial_page_impl.cc
index 232217d..c12d01c 100644
--- a/content/browser/web_contents/interstitial_page_impl.cc
+++ b/content/browser/web_contents/interstitial_page_impl.cc
@@ -503,6 +503,7 @@
                              this,
                              MSG_ROUTING_NONE,
                              MSG_ROUTING_NONE,
+                             false,
                              false);
   web_contents_->RenderViewForInterstitialPageCreated(render_view_host);
   return render_view_host;
diff --git a/content/browser/web_contents/render_view_host_manager.cc b/content/browser/web_contents/render_view_host_manager.cc
index 9d29a09..2c92430 100644
--- a/content/browser/web_contents/render_view_host_manager.cc
+++ b/content/browser/web_contents/render_view_host_manager.cc
@@ -83,7 +83,7 @@
   render_view_host_ = static_cast<RenderViewHostImpl*>(
       RenderViewHostFactory::Create(
           site_instance, render_view_delegate_, render_widget_delegate_,
-          routing_id, main_frame_routing_id, false));
+          routing_id, main_frame_routing_id, false, delegate_->IsHidden()));
 
   // Keep track of renderer processes as they start to shut down or are
   // crashed/killed.
@@ -642,8 +642,10 @@
 int RenderViewHostManager::CreateRenderView(
     SiteInstance* instance,
     int opener_route_id,
-    bool swapped_out) {
+    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
@@ -662,7 +664,8 @@
                                       render_widget_delegate_,
                                       MSG_ROUTING_NONE,
                                       MSG_ROUTING_NONE,
-                                      swapped_out));
+                                      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.
@@ -894,7 +897,8 @@
 
     // Create a non-swapped-out pending RVH with the given opener and navigate
     // it.
-    int route_id = CreateRenderView(new_instance, opener_route_id, false);
+    int route_id = CreateRenderView(new_instance, opener_route_id, false,
+                                    delegate_->IsHidden());
     if (route_id == MSG_ROUTING_NONE)
       return NULL;
 
diff --git a/content/browser/web_contents/render_view_host_manager.h b/content/browser/web_contents/render_view_host_manager.h
index 8c5071d..aacc90b 100644
--- a/content/browser/web_contents/render_view_host_manager.h
+++ b/content/browser/web_contents/render_view_host_manager.h
@@ -97,6 +97,10 @@
     // 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() {}
   };
@@ -181,7 +185,8 @@
   // will be used for a pending cross-site navigation.
   int CreateRenderView(SiteInstance* instance,
                        int opener_route_id,
-                       bool swapped_out);
+                       bool swapped_out,
+                       bool hidden);
 
   // Called when a provisional load on the given renderer is aborted.
   void RendererAbortedProvisionalLoad(RenderViewHost* render_view_host);
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 ce0a702..c0fb65c 100644
--- a/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
+++ b/content/browser/web_contents/touch_editable_impl_aura_browsertest.cc
@@ -16,7 +16,7 @@
 #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/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "ui/aura/root_window.h"
@@ -333,8 +333,15 @@
   DISALLOW_COPY_AND_ASSIGN(TouchEditableImplAuraTest);
 };
 
+#if defined(OS_CHROMEOS)
+#define MAYBE_TouchSelectionOriginatingFromWebpageTest \
+    DISABLED_TouchSelectionOriginatingFromWebpageTest
+#else
+#define MAYBE_TouchSelectionOriginatingFromWebpageTest \
+    TouchSelectionOriginatingFromWebpageTest
+#endif
 IN_PROC_BROWSER_TEST_F(TouchEditableImplAuraTest,
-                       TouchSelectionOriginatingFromWebpageTest) {
+                       MAYBE_TouchSelectionOriginatingFromWebpageTest) {
   TestTouchSelectionOriginatingFromWebpage();
 }
 
diff --git a/content/browser/web_contents/web_contents_drag_win.cc b/content/browser/web_contents/web_contents_drag_win.cc
index 68e2788..cb24210 100644
--- a/content/browser/web_contents/web_contents_drag_win.cc
+++ b/content/browser/web_contents/web_contents_drag_win.cc
@@ -163,7 +163,7 @@
 
   drag_source_ = new WebDragSource(source_window_, web_contents_);
 
-  const GURL& page_url = web_contents_->GetURL();
+  const GURL& page_url = web_contents_->GetLastCommittedURL();
   const std::string& page_encoding = web_contents_->GetEncoding();
 
   // If it is not drag-out, do the drag-and-drop in the current UI thread.
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 551be51..7d999ec 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -29,6 +29,7 @@
 #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/host_zoom_map_impl.h"
@@ -53,7 +54,6 @@
 #include "content/port/browser/render_widget_host_view_port.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/color_chooser.h"
-#include "content/public/browser/compositor_util.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/download_manager.h"
@@ -1049,9 +1049,7 @@
   if (is_being_destroyed_)
     return;
 
-  // While capturer_count_ was greater than zero, the WasHidden() calls to RWHV
-  // were being prevented.  If there are no more capturers, make the call now.
-  if (capturer_count_ == 0 && !should_normally_be_visible_) {
+  if (IsHidden()) {
     DVLOG(1) << "Executing delayed WasHidden().";
     WasHidden();
   }
@@ -1157,7 +1155,7 @@
 
 void WebContentsImpl::Stop() {
   render_manager_.Stop();
-  FOR_EACH_OBSERVER(WebContentsObserver, observers_, StopNavigation());
+  FOR_EACH_OBSERVER(WebContentsObserver, observers_, NavigationStopped());
 }
 
 WebContents* WebContentsImpl::Clone() {
@@ -1422,23 +1420,6 @@
     int main_frame_route_id,
     const ViewHostMsg_CreateWindow_Params& params,
     SessionStorageNamespace* session_storage_namespace) {
-  if (delegate_ &&
-      !delegate_->ShouldCreateWebContents(this,
-                                          route_id,
-                                          params.window_container_type,
-                                          params.frame_name,
-                                          params.target_url,
-                                          params.referrer,
-                                          params.disposition,
-                                          params.features,
-                                          params.user_gesture,
-                                          params.opener_suppressed)) {
-    GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
-    GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
-        main_frame_route_id);
-    return;
-  }
-
   // We usually create the new window in the same BrowsingInstance (group of
   // script-related windows), by passing in the current SiteInstance.  However,
   // if the opener is being suppressed (in a non-guest), we create a new
@@ -1450,12 +1431,6 @@
       SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) :
       GetSiteInstance();
 
-  // Create the new web contents. This will automatically create the new
-  // WebContentsView. In the future, we may want to create the view separately.
-  WebContentsImpl* new_contents =
-      new WebContentsImpl(GetBrowserContext(),
-                          params.opener_suppressed ? NULL : this);
-
   // We must assign the SessionStorageNamespace before calling Init().
   //
   // http://crbug.com/142685
@@ -1470,6 +1445,27 @@
   SessionStorageNamespaceImpl* session_storage_namespace_impl =
       static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace);
   CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context));
+
+  if (delegate_ &&
+      !delegate_->ShouldCreateWebContents(this,
+                                          route_id,
+                                          params.window_container_type,
+                                          params.frame_name,
+                                          params.target_url,
+                                          partition_id,
+                                          session_storage_namespace)) {
+    GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
+    GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
+        main_frame_route_id);
+    return;
+  }
+
+  // Create the new web contents. This will automatically create the new
+  // WebContentsView. In the future, we may want to create the view separately.
+  WebContentsImpl* new_contents =
+      new WebContentsImpl(GetBrowserContext(),
+                          params.opener_suppressed ? NULL : this);
+
   new_contents->GetController().SetSessionStorageNamespace(
       partition_id,
       session_storage_namespace);
@@ -1488,6 +1484,8 @@
     BrowserPluginGuest::CreateWithOpener(instance_id, new_contents_impl,
         GetBrowserPluginGuest(), !!new_contents_impl->opener());
   }
+  if (params.disposition == NEW_BACKGROUND_TAB)
+    create_params.initially_hidden = true;
   new_contents->Init(create_params);
 
   // Save the window for later if we're not suppressing the opener (since it
@@ -1549,7 +1547,7 @@
                                       WebKit::WebPopupType popup_type) {
   RenderProcessHost* process = GetRenderProcessHost();
   RenderWidgetHostImpl* widget_host =
-      new RenderWidgetHostImpl(this, process, route_id);
+      new RenderWidgetHostImpl(this, process, route_id, IsHidden());
   created_widgets_.insert(widget_host);
 
   RenderWidgetHostViewPort* widget_view = RenderWidgetHostViewPort::FromRWHV(
@@ -1806,7 +1804,7 @@
     // do not generate content.  What we really need is a message from the
     // renderer telling us that a new page was not created.  The same message
     // could be used for mailto: URLs and the like.
-    if (entry.GetURL().SchemeIs(chrome::kJavaScriptScheme))
+    if (entry.GetURL().SchemeIs(kJavaScriptScheme))
       return false;
   }
 
@@ -2430,10 +2428,20 @@
 
 void WebContentsImpl::OnOpenDateTimeDialog(
     const ViewHostMsg_DateTimeDialogValue_Params& value) {
-  date_time_chooser_->ShowDialog(
-      ContentViewCore::FromWebContents(this), GetRenderViewHost(),
-      value.dialog_type, value.year, value.month, value.day, value.hour,
-      value.minute, value.second, value.week, value.minimum, value.maximum);
+  date_time_chooser_->ShowDialog(ContentViewCore::FromWebContents(this),
+                                 GetRenderViewHost(),
+                                 value.dialog_type,
+                                 value.year,
+                                 value.month,
+                                 value.day,
+                                 value.hour,
+                                 value.minute,
+                                 value.second,
+                                 value.milli,
+                                 value.week,
+                                 value.minimum,
+                                 value.maximum,
+                                 value.step);
 }
 
 #endif
@@ -3417,7 +3425,8 @@
 bool WebContentsImpl::AddMessageToConsole(int32 level,
                                           const string16& message,
                                           int32 line_no,
-                                          const string16& source_id) {
+                                          const string16& source_id,
+                                          const string16& stack_trace) {
   if (!delegate_)
     return false;
   return delegate_->AddMessageToConsole(this, level, message, line_no,
@@ -3434,7 +3443,8 @@
 
 int WebContentsImpl::CreateSwappedOutRenderView(
     SiteInstance* instance) {
-  return render_manager_.CreateRenderView(instance, MSG_ROUTING_NONE, true);
+  return render_manager_.CreateRenderView(instance, MSG_ROUTING_NONE,
+                                          true, true);
 }
 
 void WebContentsImpl::OnUserGesture() {
@@ -3452,6 +3462,7 @@
 }
 
 void WebContentsImpl::RendererUnresponsive(RenderViewHost* rvh,
+                                           bool is_during_beforeunload,
                                            bool is_during_unload) {
   // Don't show hung renderer dialog for a swapped out RVH.
   if (rvh != GetRenderViewHost())
@@ -3465,7 +3476,7 @@
   if (DevToolsAgentHost::IsDebuggerAttached(this))
     return;
 
-  if (is_during_unload) {
+  if (is_during_beforeunload || is_during_unload) {
     // Hang occurred while firing the beforeunload/unload handler.
     // Pretend the handler fired so tab closing continues as if it had.
     rvhi->set_sudden_termination_allowed(true);
@@ -3474,10 +3485,17 @@
       return;
 
     // If the tab hangs in the beforeunload/unload handler there's really
-    // nothing we can do to recover. Pretend the unload listeners have
-    // all fired and close the tab. If the hang is in the beforeunload handler
-    // then the user will not have the option of cancelling the close.
-    Close(rvh);
+    // nothing we can do to recover. If the hang is in the beforeunload handler,
+    // pretend the beforeunload listeners have all fired and allow the delegate
+    // to continue closing; the user will not have the option of cancelling the
+    // close. Otherwise, pretend the unload listeners have all fired and close
+    // the tab.
+    bool close = true;
+    if (is_during_beforeunload) {
+      delegate_->BeforeUnloadFired(this, true, &close);
+    }
+    if (close)
+      Close(rvh);
     return;
   }
 
@@ -3604,7 +3622,8 @@
 
   // Create a swapped out RenderView in the given SiteInstance if none exists,
   // setting its opener to the given route_id.  Return the new view's route_id.
-  return render_manager_.CreateRenderView(instance, opener_route_id, true);
+  return render_manager_.CreateRenderView(instance, opener_route_id,
+                                          true, true);
 }
 
 NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() {
@@ -3654,6 +3673,13 @@
   return true;
 }
 
+#if defined(OS_ANDROID)
+bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() {
+  return CreateRenderViewForRenderManager(GetRenderViewHost(),
+                                          MSG_ROUTING_NONE);
+}
+#endif
+
 void WebContentsImpl::OnDialogClosed(RenderViewHost* rvh,
                                      IPC::Message* reply_msg,
                                      bool success,
@@ -3684,6 +3710,10 @@
     rwh_view->SetSize(GetView()->GetContainerSize());
 }
 
+bool WebContentsImpl::IsHidden() {
+  return capturer_count_ == 0 && !should_normally_be_visible_;
+}
+
 RenderViewHostImpl* WebContentsImpl::GetRenderViewHostImpl() {
   return static_cast<RenderViewHostImpl*>(GetRenderViewHost());
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 21ec675..bb56ddb 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -153,6 +153,13 @@
   JavaBridgeDispatcherHostManager* java_bridge_dispatcher_host_manager() const {
     return java_bridge_dispatcher_host_manager_.get();
   }
+
+  // In Android WebView, the RenderView needs created even there is no
+  // navigation entry, this allows Android WebViews to use
+  // javascript: URLs that load into the DOMWindow before the first page
+  // load. This is not safe to do in any context that a web page could get a
+  // reference to the DOMWindow before the first page load.
+  bool CreateRenderViewForInitialEmptyDocument();
 #endif
 
   // Expose the render manager for testing.
@@ -400,13 +407,15 @@
   virtual bool AddMessageToConsole(int32 level,
                                    const string16& message,
                                    int32 line_no,
-                                   const string16& source_id) OVERRIDE;
+                                   const string16& source_id,
+                                   const string16& stack_trace) OVERRIDE;
   virtual RendererPreferences GetRendererPrefs(
       BrowserContext* browser_context) const OVERRIDE;
   virtual WebPreferences GetWebkitPrefs() OVERRIDE;
   virtual void OnUserGesture() OVERRIDE;
   virtual void OnIgnoredUIEvent() OVERRIDE;
   virtual void RendererUnresponsive(RenderViewHost* render_view_host,
+                                    bool is_during_beforeunload,
                                     bool is_during_unload) OVERRIDE;
   virtual void RendererResponsive(RenderViewHost* render_view_host) OVERRIDE;
   virtual void LoadStateChanged(const GURL& url,
@@ -492,6 +501,7 @@
   virtual bool FocusLocationBarByDefault() OVERRIDE;
   virtual void SetFocusToLocationBar(bool select_all) OVERRIDE;
   virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) OVERRIDE;
+  virtual bool IsHidden() OVERRIDE;
 
   // NotificationObserver ------------------------------------------------------
 
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 0cb9fe2..70ab523 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -14,7 +14,7 @@
 #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/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
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 e0f34ab..df90be7 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -18,7 +18,7 @@
 #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/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "ui/aura/root_window.h"
diff --git a/content/browser/web_contents/web_drag_source_mac.mm b/content/browser/web_contents/web_drag_source_mac.mm
index f523323..ee365d6 100644
--- a/content/browser/web_contents/web_drag_source_mac.mm
+++ b/content/browser/web_contents/web_drag_source_mac.mm
@@ -200,7 +200,7 @@
     NSURL* url = [NSURL URLWithString:SysUTF8ToNSString(dropData_->url.spec())];
     // If NSURL creation failed, check for a badly-escaped JavaScript URL.
     // Strip out any existing escapes and then re-escape uniformly.
-    if (!url && dropData_->url.SchemeIs(chrome::kJavaScriptScheme)) {
+    if (!url && dropData_->url.SchemeIs(content::kJavaScriptScheme)) {
       net::UnescapeRule::Type unescapeRules =
           net::UnescapeRule::SPACES |
           net::UnescapeRule::URL_SPECIAL_CHARS |
@@ -383,7 +383,8 @@
         filePath,
         fileStream.Pass(),
         downloadURL_,
-        content::Referrer(contents_->GetURL(), dropData_->referrer_policy),
+        content::Referrer(contents_->GetLastCommittedURL(),
+                          dropData_->referrer_policy),
         contents_->GetEncoding(),
         contents_));
 
diff --git a/content/browser/webkit_browsertest.cc b/content/browser/webkit_browsertest.cc
index 24c24a6..5394f5b 100644
--- a/content/browser/webkit_browsertest.cc
+++ b/content/browser/webkit_browsertest.cc
@@ -4,7 +4,7 @@
 
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "content/test/net/url_request_abort_on_end_job.h"
diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc
index 23cdc3d..42d0d11 100644
--- a/content/browser/webui/shared_resources_data_source.cc
+++ b/content/browser/webui/shared_resources_data_source.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
+#include "base/strings/string_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_constants.h"
@@ -14,10 +15,37 @@
 
 namespace {
 
+const char kAppImagesPath[] = "images/apps/";
+const char kAppImagesPath2x[] = "images/2x/apps/";
+
+const char kReplacement[] = "../../resources/default_100_percent/common/";
+const char kReplacement2x[] = "../../resources/default_200_percent/common/";
+
+// This entire method is a hack introduced to be able to handle apps images
+// that exist in the ui/resources directory. From JS/CSS, we still load the
+// image as if it were chrome://resources/images/apps/myappimage.png, if that
+// path doesn't exist, we check to see if it that image exists in the relative
+// path to ui/resources instead.
+// TODO(rkc): Once we have a separate source for apps, remove this code.
+bool AppsRelativePathMatch(const std::string& path,
+                           const std::string& compareto) {
+  if (StartsWithASCII(path, kAppImagesPath, false)) {
+    if (compareto ==
+        (kReplacement + path.substr(arraysize(kAppImagesPath) - 1)))
+      return true;
+  } else if (StartsWithASCII(path, kAppImagesPath2x, false)) {
+    if (compareto ==
+        (kReplacement2x + path.substr(arraysize(kAppImagesPath) - 1)))
+      return true;
+  }
+  return false;
+}
+
 int PathToIDR(const std::string& path) {
   int idr = -1;
   for (size_t i = 0; i < kWebuiResourcesSize; ++i) {
-    if (kWebuiResources[i].name == path) {
+    if ((path == kWebuiResources[i].name) ||
+        AppsRelativePathMatch(path, kWebuiResources[i].name)) {
       idr = kWebuiResources[i].value;
       break;
     }
diff --git a/content/browser/webui/web_ui_controller_factory_registry.cc b/content/browser/webui/web_ui_controller_factory_registry.cc
index 675bd8f..ede404d 100644
--- a/content/browser/webui/web_ui_controller_factory_registry.cc
+++ b/content/browser/webui/web_ui_controller_factory_registry.cc
@@ -82,7 +82,7 @@
     bool data_urls_allowed) const {
   return UseWebUIForURL(browser_context, url) ||
       // javascript: URLs are allowed to run in Web UI pages.
-      url.SchemeIs(chrome::kJavaScriptScheme) ||
+      url.SchemeIs(kJavaScriptScheme) ||
       // It's possible to load about:blank in a Web UI renderer.
       // See http://crbug.com/42547
       url.spec() == kAboutBlankURL ||
diff --git a/content/browser/webui/web_ui_data_source_impl.cc b/content/browser/webui/web_ui_data_source_impl.cc
index b564e57..63e08bc 100644
--- a/content/browser/webui/web_ui_data_source_impl.cc
+++ b/content/browser/webui/web_ui_data_source_impl.cc
@@ -49,6 +49,9 @@
     return parent_->StartDataRequest(path, render_process_id, render_view_id,
                                      callback);
   }
+  virtual bool ShouldReplaceExistingSource() const OVERRIDE {
+    return parent_->replace_existing_source_;
+  }
   virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
     return parent_->add_csp_;
   }
@@ -81,7 +84,8 @@
       object_src_set_(false),
       frame_src_set_(false),
       deny_xframe_options_(true),
-      disable_set_font_strings_(false) {
+      disable_set_font_strings_(false),
+      replace_existing_source_(true) {
 }
 
 WebUIDataSourceImpl::~WebUIDataSourceImpl() {
@@ -134,6 +138,10 @@
   filter_callback_ = callback;
 }
 
+void WebUIDataSourceImpl::DisableReplaceExistingSource() {
+  replace_existing_source_ = false;
+}
+
 void WebUIDataSourceImpl::DisableContentSecurityPolicy() {
   add_csp_ = false;
 }
diff --git a/content/browser/webui/web_ui_data_source_impl.h b/content/browser/webui/web_ui_data_source_impl.h
index 0b6f8a3..1f81004 100644
--- a/content/browser/webui/web_ui_data_source_impl.h
+++ b/content/browser/webui/web_ui_data_source_impl.h
@@ -42,6 +42,7 @@
   virtual void SetDefaultResource(int resource_id) OVERRIDE;
   virtual void SetRequestFilter(
       const WebUIDataSource::HandleRequestCallback& callback) OVERRIDE;
+  virtual void DisableReplaceExistingSource() OVERRIDE;
   virtual void DisableContentSecurityPolicy() OVERRIDE;
   virtual void OverrideContentSecurityPolicyObjectSrc(
       const std::string& data) OVERRIDE;
@@ -99,6 +100,7 @@
   std::string frame_src_;
   bool deny_xframe_options_;
   bool disable_set_font_strings_;
+  bool replace_existing_source_;
 
   DISALLOW_COPY_AND_ASSIGN(WebUIDataSourceImpl);
 };
diff --git a/content/browser/worker_host/test/worker_browsertest.cc b/content/browser/worker_host/test/worker_browsertest.cc
index ca87c5d..326e01f 100644
--- a/content/browser/worker_host/test/worker_browsertest.cc
+++ b/content/browser/worker_host/test/worker_browsertest.cc
@@ -17,9 +17,9 @@
 #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/shell.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_resource_dispatcher_host_delegate.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/test_data_directory.h"
diff --git a/content/child/fileapi/webfilesystem_callback_adapters.cc b/content/child/fileapi/webfilesystem_callback_adapters.cc
deleted file mode 100644
index de5a59c..0000000
--- a/content/child/fileapi/webfilesystem_callback_adapters.cc
+++ /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.
-
-#include "content/child/fileapi/webfilesystem_callback_adapters.h"
-
-#include <string>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/WebKit/public/platform/WebFileInfo.h"
-#include "third_party/WebKit/public/platform/WebFileSystem.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/web/WebFileSystemCallbacks.h"
-#include "url/gurl.h"
-#include "webkit/common/fileapi/directory_entry.h"
-#include "webkit/common/fileapi/file_system_util.h"
-#include "webkit/glue/webkit_glue.h"
-
-using WebKit::WebFileInfo;
-using WebKit::WebFileSystemCallbacks;
-using WebKit::WebFileSystemEntry;
-using WebKit::WebString;
-using WebKit::WebVector;
-
-namespace content {
-
-void FileStatusCallbackAdapter(
-    WebKit::WebFileSystemCallbacks* callbacks,
-    base::PlatformFileError error) {
-  if (error == base::PLATFORM_FILE_OK)
-    callbacks->didSucceed();
-  else
-    callbacks->didFail(::fileapi::PlatformFileErrorToWebFileError(error));
-}
-
-void OpenFileSystemCallbackAdapter(
-    WebKit::WebFileSystemCallbacks* callbacks,
-    const std::string& name, const GURL& root) {
-  callbacks->didOpenFileSystem(UTF8ToUTF16(name), root);
-}
-
-}  // namespace content
diff --git a/content/child/fileapi/webfilesystem_callback_adapters.h b/content/child/fileapi/webfilesystem_callback_adapters.h
deleted file mode 100644
index a6fb83c..0000000
--- a/content/child/fileapi/webfilesystem_callback_adapters.h
+++ /dev/null
@@ -1,33 +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_CHILD_FILEAPI_WEBFILESYSTEM_CALLBACK_ADAPTERS_H_
-#define CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_CALLBACK_ADAPTERS_H_
-
-#include "base/basictypes.h"
-#include "base/platform_file.h"
-
-class GURL;
-
-namespace fileapi {
-struct DirectoryEntry;
-}
-
-namespace WebKit {
-class WebFileSystemCallbacks;
-}
-
-namespace content {
-
-void FileStatusCallbackAdapter(
-    WebKit::WebFileSystemCallbacks* callbacks,
-    base::PlatformFileError error);
-
-void OpenFileSystemCallbackAdapter(
-    WebKit::WebFileSystemCallbacks* callbacks,
-    const std::string& name, const GURL& root);
-
-}  // namespace content
-
-#endif  // CONTENT_CHILD_FILEAPI_WEBFILESYSTEM_CALLBACK_ADAPTERS_H_
diff --git a/content/child/fileapi/webfilesystem_impl.cc b/content/child/fileapi/webfilesystem_impl.cc
index 052bce4..b811c27 100644
--- a/content/child/fileapi/webfilesystem_impl.cc
+++ b/content/child/fileapi/webfilesystem_impl.cc
@@ -5,15 +5,14 @@
 #include "content/child/fileapi/webfilesystem_impl.h"
 
 #include "base/bind.h"
-#include "base/id_map.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop_proxy.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_local.h"
 #include "content/child/child_thread.h"
 #include "content/child/fileapi/file_system_dispatcher.h"
-#include "content/child/fileapi/webfilesystem_callback_adapters.h"
 #include "content/child/fileapi/webfilewriter_impl.h"
 #include "content/common/fileapi/file_system_messages.h"
 #include "third_party/WebKit/public/platform/WebFileInfo.h"
@@ -38,62 +37,8 @@
 
 namespace {
 
-class CallbacksMap;
-
-base::LazyInstance<base::ThreadLocalPointer<CallbacksMap> >::Leaky
-    g_callbacks_map_tls = LAZY_INSTANCE_INITIALIZER;
-
-// TODO(kinuko): Integrate this into WebFileSystemImpl when blink side
-// becomes ready to make WebFileSystemImpl thread-local.
-class CallbacksMap : public WorkerTaskRunner::Observer {
- public:
-  static CallbacksMap* Get() {
-    return g_callbacks_map_tls.Pointer()->Get();
-  }
-
-  static CallbacksMap* GetOrCreate() {
-    if (g_callbacks_map_tls.Pointer()->Get())
-      return g_callbacks_map_tls.Pointer()->Get();
-    CallbacksMap* map = new CallbacksMap;
-    if (WorkerTaskRunner::Instance()->CurrentWorkerId())
-      WorkerTaskRunner::Instance()->AddStopObserver(map);
-    return map;
-  }
-
-  virtual ~CallbacksMap() {
-    IDMap<WebFileSystemCallbacks>::iterator iter(&callbacks_);
-    while (!iter.IsAtEnd()) {
-      iter.GetCurrentValue()->didFail(WebKit::WebFileErrorAbort);
-      iter.Advance();
-    }
-    g_callbacks_map_tls.Pointer()->Set(NULL);
-  }
-
-  // webkit_glue::WorkerTaskRunner::Observer implementation.
-  virtual void OnWorkerRunLoopStopped() OVERRIDE {
-    delete this;
-  }
-
-  int RegisterCallbacks(WebFileSystemCallbacks* callbacks) {
-    return callbacks_.Add(callbacks);
-  }
-
-  WebFileSystemCallbacks* GetAndUnregisterCallbacks(
-      int callbacks_id) {
-    WebFileSystemCallbacks* callbacks = callbacks_.Lookup(callbacks_id);
-    callbacks_.Remove(callbacks_id);
-    return callbacks;
-  }
-
- private:
-  CallbacksMap() {
-    g_callbacks_map_tls.Pointer()->Set(this);
-  }
-
-  IDMap<WebFileSystemCallbacks> callbacks_;
-
-  DISALLOW_COPY_AND_ASSIGN(CallbacksMap);
-};
+base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl> >::Leaky
+    g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER;
 
 class WaitableCallbackResults {
  public:
@@ -161,10 +106,12 @@
 // Run WebFileSystemCallbacks's |method| with |params|.
 template <typename Method, typename Params>
 void RunCallbacks(int callbacks_id, Method method, const Params& params) {
-  if (!CallbacksMap::Get())
+  WebFileSystemImpl* filesystem =
+      WebFileSystemImpl::ThreadSpecificInstance(NULL);
+  if (!filesystem)
     return;
   WebFileSystemCallbacks* callbacks =
-      CallbacksMap::Get()->GetAndUnregisterCallbacks(callbacks_id);
+      filesystem->GetAndUnregisterCallbacks(callbacks_id);
   DCHECK(callbacks);
   DispatchToMethod(callbacks, method, params);
 }
@@ -193,6 +140,21 @@
       base::Bind(&RunCallbacks<Method, Params>, callbacks_id, method, params));
 }
 
+//-----------------------------------------------------------------------------
+// Callback adapters. Callbacks must be called on the original calling thread,
+// so these callback adapters relay back the results to the calling thread
+// if necessary.
+
+void OpenFileSystemCallbackAdapter(
+    int thread_id, int callbacks_id,
+    WaitableCallbackResults* waitable_results,
+    const std::string& name, const GURL& root) {
+  CallbackFileSystemCallbacks(
+      thread_id, callbacks_id, waitable_results,
+      &WebFileSystemCallbacks::didOpenFileSystem,
+      MakeTuple(UTF8ToUTF16(name), root));
+}
+
 void StatusCallbackAdapter(int thread_id, int callbacks_id,
                            WaitableCallbackResults* waitable_results,
                            base::PlatformFileError error) {
@@ -241,11 +203,13 @@
     WebKit::WebFileWriterClient* client,
     base::MessageLoopProxy* main_thread_loop,
     const base::PlatformFileInfo& file_info) {
-  if (!CallbacksMap::Get())
+  WebFileSystemImpl* filesystem =
+      WebFileSystemImpl::ThreadSpecificInstance(NULL);
+  if (!filesystem)
     return;
 
   WebFileSystemCallbacks* callbacks =
-      CallbacksMap::Get()->GetAndUnregisterCallbacks(callbacks_id);
+      filesystem->GetAndUnregisterCallbacks(callbacks_id);
   DCHECK(callbacks);
 
   if (file_info.is_directory || file_info.size < 0) {
@@ -278,11 +242,13 @@
     const base::PlatformFileInfo& file_info,
     const base::FilePath& platform_path,
     int request_id) {
-  if (!CallbacksMap::Get())
+  WebFileSystemImpl* filesystem =
+      WebFileSystemImpl::ThreadSpecificInstance(NULL);
+  if (!filesystem)
     return;
 
   WebFileSystemCallbacks* callbacks =
-      CallbacksMap::Get()->GetAndUnregisterCallbacks(callbacks_id);
+      filesystem->GetAndUnregisterCallbacks(callbacks_id);
   DCHECK(callbacks);
 
   WebFileInfo web_file_info;
@@ -312,18 +278,89 @@
 
 }  // namespace
 
-WebFileSystemImpl::~WebFileSystemImpl() {
+//-----------------------------------------------------------------------------
+// WebFileSystemImpl
+
+WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance(
+    base::MessageLoopProxy* main_thread_loop) {
+  if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_loop)
+    return g_webfilesystem_tls.Pointer()->Get();
+  WebFileSystemImpl* filesystem = new WebFileSystemImpl(main_thread_loop);
+  if (WorkerTaskRunner::Instance()->CurrentWorkerId())
+    WorkerTaskRunner::Instance()->AddStopObserver(filesystem);
+  return filesystem;
+}
+
+void WebFileSystemImpl::DeleteThreadSpecificInstance() {
+  DCHECK(!WorkerTaskRunner::Instance()->CurrentWorkerId());
+  if (g_webfilesystem_tls.Pointer()->Get())
+    delete g_webfilesystem_tls.Pointer()->Get();
 }
 
 WebFileSystemImpl::WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop)
     : main_thread_loop_(main_thread_loop) {
+  g_webfilesystem_tls.Pointer()->Set(this);
+}
+
+WebFileSystemImpl::~WebFileSystemImpl() {
+  IDMap<WebFileSystemCallbacks>::iterator iter(&callbacks_);
+  while (!iter.IsAtEnd()) {
+    iter.GetCurrentValue()->didFail(WebKit::WebFileErrorAbort);
+    iter.Advance();
+  }
+  g_webfilesystem_tls.Pointer()->Set(NULL);
+}
+
+void WebFileSystemImpl::OnWorkerRunLoopStopped() {
+  delete this;
+}
+
+void WebFileSystemImpl::openFileSystem(
+    const WebKit::WebURL& storage_partition,
+    WebKit::WebFileSystemType type,
+    bool create,
+    WebKit::WebFileSystemCallbacks* callbacks) {
+  int callbacks_id = RegisterCallbacks(callbacks);
+  WaitableCallbackResults* waitable_results =
+      WaitableCallbackResults::MaybeCreate(callbacks);
+  CallDispatcherOnMainThread(
+      main_thread_loop_.get(),
+      &FileSystemDispatcher::OpenFileSystem,
+      MakeTuple(GURL(storage_partition),
+                static_cast<fileapi::FileSystemType>(type),
+                0 /* size (not used) */, create,
+                base::Bind(&OpenFileSystemCallbackAdapter,
+                           CurrentWorkerId(), callbacks_id,
+                           base::Unretained(waitable_results)),
+                base::Bind(&StatusCallbackAdapter,
+                           CurrentWorkerId(), callbacks_id,
+                           base::Unretained(waitable_results))),
+      make_scoped_ptr(waitable_results));
+}
+
+void WebFileSystemImpl::deleteFileSystem(
+    const WebKit::WebURL& storage_partition,
+    WebKit::WebFileSystemType type,
+    WebKit::WebFileSystemCallbacks* callbacks) {
+  int callbacks_id = RegisterCallbacks(callbacks);
+  WaitableCallbackResults* waitable_results =
+      WaitableCallbackResults::MaybeCreate(callbacks);
+  CallDispatcherOnMainThread(
+      main_thread_loop_.get(),
+      &FileSystemDispatcher::DeleteFileSystem,
+      MakeTuple(GURL(storage_partition),
+                static_cast<fileapi::FileSystemType>(type),
+                base::Bind(&StatusCallbackAdapter,
+                           CurrentWorkerId(), callbacks_id,
+                           base::Unretained(waitable_results))),
+      make_scoped_ptr(waitable_results));
 }
 
 void WebFileSystemImpl::move(
     const WebKit::WebURL& src_path,
     const WebKit::WebURL& dest_path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -340,7 +377,7 @@
     const WebKit::WebURL& src_path,
     const WebKit::WebURL& dest_path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -356,7 +393,7 @@
 void WebFileSystemImpl::remove(
     const WebKit::WebURL& path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -372,7 +409,7 @@
 void WebFileSystemImpl::removeRecursively(
     const WebKit::WebURL& path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -388,7 +425,7 @@
 void WebFileSystemImpl::readMetadata(
     const WebKit::WebURL& path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -408,7 +445,7 @@
     const WebKit::WebURL& path,
     bool exclusive,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -425,7 +462,7 @@
     const WebKit::WebURL& path,
     bool exclusive,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -441,7 +478,7 @@
 void WebFileSystemImpl::fileExists(
     const WebKit::WebURL& path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -457,7 +494,7 @@
 void WebFileSystemImpl::directoryExists(
     const WebKit::WebURL& path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -473,7 +510,7 @@
 void WebFileSystemImpl::readDirectory(
     const WebKit::WebURL& path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -500,7 +537,7 @@
     const WebURL& path,
     WebKit::WebFileWriterClient* client,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -520,7 +557,7 @@
 void WebFileSystemImpl::createSnapshotFileAndReadMetadata(
     const WebKit::WebURL& path,
     WebKit::WebFileSystemCallbacks* callbacks) {
-  int callbacks_id = CallbacksMap::GetOrCreate()->RegisterCallbacks(callbacks);
+  int callbacks_id = RegisterCallbacks(callbacks);
   WaitableCallbackResults* waitable_results =
       WaitableCallbackResults::MaybeCreate(callbacks);
   CallDispatcherOnMainThread(
@@ -537,4 +574,15 @@
       make_scoped_ptr(waitable_results));
 }
 
+int WebFileSystemImpl::RegisterCallbacks(WebFileSystemCallbacks* callbacks) {
+  return callbacks_.Add(callbacks);
+}
+
+WebFileSystemCallbacks* WebFileSystemImpl::GetAndUnregisterCallbacks(
+    int callbacks_id) {
+  WebFileSystemCallbacks* callbacks = callbacks_.Lookup(callbacks_id);
+  callbacks_.Remove(callbacks_id);
+  return callbacks;
+}
+
 }  // namespace content
diff --git a/content/child/fileapi/webfilesystem_impl.h b/content/child/fileapi/webfilesystem_impl.h
index d9a2584..d439158 100644
--- a/content/child/fileapi/webfilesystem_impl.h
+++ b/content/child/fileapi/webfilesystem_impl.h
@@ -7,8 +7,11 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/id_map.h"
 #include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
 #include "third_party/WebKit/public/platform/WebFileSystem.h"
+#include "webkit/child/worker_task_runner.h"
 
 namespace base {
 class MessageLoopProxy;
@@ -22,12 +25,38 @@
 
 namespace content {
 
-class WebFileSystemImpl : public WebKit::WebFileSystem {
+class WebFileSystemImpl
+    : public WebKit::WebFileSystem,
+      public webkit_glue::WorkerTaskRunner::Observer,
+      public base::NonThreadSafe {
  public:
+  // Returns thread-specific instance.  If non-null |main_thread_loop|
+  // is given and no thread-specific instance has been created it may
+  // create a new instance.
+  static WebFileSystemImpl* ThreadSpecificInstance(
+      base::MessageLoopProxy* main_thread_loop);
+
+  // Deletes thread-specific instance (if exists). For workers it deletes
+  // itself in OnWorkerRunLoopStopped(), but for an instance created on the
+  // main thread this method must be called.
+  static void DeleteThreadSpecificInstance();
+
   explicit WebFileSystemImpl(base::MessageLoopProxy* main_thread_loop);
   virtual ~WebFileSystemImpl();
 
+  // webkit_glue::WorkerTaskRunner::Observer implementation.
+  virtual void OnWorkerRunLoopStopped() OVERRIDE;
+
   // WebFileSystem implementation.
+  virtual void openFileSystem(
+      const WebKit::WebURL& storage_partition,
+      const WebKit::WebFileSystemType type,
+      bool create,
+      WebKit::WebFileSystemCallbacks*);
+  virtual void deleteFileSystem(
+      const WebKit::WebURL& storage_partition,
+      const WebKit::WebFileSystemType type,
+      WebKit::WebFileSystemCallbacks*);
   virtual void move(
       const WebKit::WebURL& src_path,
       const WebKit::WebURL& dest_path,
@@ -72,8 +101,15 @@
       const WebKit::WebURL& path,
       WebKit::WebFileSystemCallbacks*);
 
+  int RegisterCallbacks(WebKit::WebFileSystemCallbacks* callbacks);
+  WebKit::WebFileSystemCallbacks* GetAndUnregisterCallbacks(
+      int callbacks_id);
+
  private:
   scoped_refptr<base::MessageLoopProxy> main_thread_loop_;
+  IDMap<WebKit::WebFileSystemCallbacks> callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebFileSystemImpl);
 };
 
 }  // namespace content
diff --git a/content/child/fileapi/webfilewriter_base.cc b/content/child/fileapi/webfilewriter_base.cc
new file mode 100644
index 0000000..fd0a207
--- /dev/null
+++ b/content/child/fileapi/webfilewriter_base.cc
@@ -0,0 +1,152 @@
+// Copyright 2013 The Chromium Authors. 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/fileapi/webfilewriter_base.h"
+
+#include "base/logging.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebFileError.h"
+#include "third_party/WebKit/public/web/WebFileWriterClient.h"
+#include "webkit/common/fileapi/file_system_util.h"
+
+using fileapi::PlatformFileErrorToWebFileError;
+
+namespace content {
+
+WebFileWriterBase::WebFileWriterBase(const GURL& path,
+                                     WebKit::WebFileWriterClient* client)
+    : path_(path),
+      client_(client),
+      operation_(kOperationNone),
+      cancel_state_(kCancelNotInProgress) {}
+
+WebFileWriterBase::~WebFileWriterBase() {}
+
+void WebFileWriterBase::truncate(long long length) {
+  DCHECK(kOperationNone == operation_);
+  DCHECK(kCancelNotInProgress == cancel_state_);
+  operation_ = kOperationTruncate;
+  DoTruncate(path_, length);
+}
+
+void WebFileWriterBase::write(long long position,
+                              const WebKit::WebURL& blob_url) {
+  DCHECK(kOperationNone == operation_);
+  DCHECK(kCancelNotInProgress == cancel_state_);
+  operation_ = kOperationWrite;
+  DoWrite(path_, blob_url, position);
+}
+
+// When we cancel a write/truncate, we always get back the result of the write
+// before the result of the cancel, no matter what happens.
+// So we'll get back either
+//   success [of the write/truncate, in a DidWrite(XXX, true)/DidSucceed() call]
+//     followed by failure [of the cancel]; or
+//   failure [of the write, either from cancel or other reasons] followed by
+//     the result of the cancel.
+// In the write case, there could also be queued up non-terminal DidWrite calls
+// before any of that comes back, but there will always be a terminal write
+// response [success or failure] after them, followed by the cancel result, so
+// we can ignore non-terminal write responses, take the terminal write success
+// or the first failure as the last write response, then know that the next
+// thing to come back is the cancel response.  We only notify the
+// AsyncFileWriterClient when it's all over.
+void WebFileWriterBase::cancel() {
+  // Check for the cancel passing the previous operation's return in-flight.
+  if (kOperationWrite != operation_ && kOperationTruncate != operation_)
+    return;
+  if (kCancelNotInProgress != cancel_state_)
+    return;
+  cancel_state_ = kCancelSent;
+  DoCancel();
+}
+
+void WebFileWriterBase::DidFinish(base::PlatformFileError error_code) {
+  if (error_code == base::PLATFORM_FILE_OK)
+    DidSucceed();
+  else
+    DidFail(error_code);
+}
+
+void WebFileWriterBase::DidWrite(int64 bytes, bool complete) {
+  DCHECK(kOperationWrite == operation_);
+  switch (cancel_state_) {
+    case kCancelNotInProgress:
+      if (complete)
+        operation_ = kOperationNone;
+      client_->didWrite(bytes, complete);
+      break;
+    case kCancelSent:
+      // This is the success call of the write, which we'll eat, even though
+      // it succeeded before the cancel got there.  We accepted the cancel call,
+      // so the write will eventually return an error.
+      if (complete)
+        cancel_state_ = kCancelReceivedWriteResponse;
+      break;
+    case kCancelReceivedWriteResponse:
+    default:
+      NOTREACHED();
+  }
+}
+
+void WebFileWriterBase::DidSucceed() {
+  // Write never gets a DidSucceed call, so this is either a cancel or truncate
+  // response.
+  switch (cancel_state_) {
+    case kCancelNotInProgress:
+      // A truncate succeeded, with no complications.
+      DCHECK(kOperationTruncate == operation_);
+      operation_ = kOperationNone;
+      client_->didTruncate();
+      break;
+    case kCancelSent:
+      DCHECK(kOperationTruncate == operation_);
+      // This is the success call of the truncate, which we'll eat, even though
+      // it succeeded before the cancel got there.  We accepted the cancel call,
+      // so the truncate will eventually return an error.
+      cancel_state_ = kCancelReceivedWriteResponse;
+      break;
+    case kCancelReceivedWriteResponse:
+      // This is the success of the cancel operation.
+      FinishCancel();
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void WebFileWriterBase::DidFail(base::PlatformFileError error_code) {
+  DCHECK(kOperationNone != operation_);
+  switch (cancel_state_) {
+    case kCancelNotInProgress:
+      // A write or truncate failed.
+      operation_ = kOperationNone;
+      client_->didFail(PlatformFileErrorToWebFileError(error_code));
+      break;
+    case kCancelSent:
+      // This is the failure of a write or truncate; the next message should be
+      // the result of the cancel.  We don't assume that it'll be a success, as
+      // the write/truncate could have failed for other reasons.
+      cancel_state_ = kCancelReceivedWriteResponse;
+      break;
+    case kCancelReceivedWriteResponse:
+      // The cancel reported failure, meaning that the write or truncate
+      // finished before the cancel got there.  But we suppressed the
+      // write/truncate's response, and will now report that it was cancelled.
+      FinishCancel();
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+void WebFileWriterBase::FinishCancel() {
+  DCHECK(kCancelReceivedWriteResponse == cancel_state_);
+  DCHECK(kOperationNone != operation_);
+  cancel_state_ = kCancelNotInProgress;
+  operation_ = kOperationNone;
+  client_->didFail(WebKit::WebFileErrorAbort);
+}
+
+}  // namespace content
diff --git a/content/child/fileapi/webfilewriter_base.h b/content/child/fileapi/webfilewriter_base.h
new file mode 100644
index 0000000..d3873dc
--- /dev/null
+++ b/content/child/fileapi/webfilewriter_base.h
@@ -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.
+
+#ifndef CONTENT_CHILD_FILEAPI_WEBFILEWRITER_BASE_H_
+#define CONTENT_CHILD_FILEAPI_WEBFILEWRITER_BASE_H_
+
+#include "base/platform_file.h"
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/web/WebFileWriter.h"
+#include "url/gurl.h"
+
+namespace WebKit {
+class WebFileWriterClient;
+class WebURL;
+}
+
+namespace content {
+
+class CONTENT_EXPORT WebFileWriterBase
+    : public NON_EXPORTED_BASE(WebKit::WebFileWriter) {
+ public:
+  WebFileWriterBase(const GURL& path, WebKit::WebFileWriterClient* client);
+  virtual ~WebFileWriterBase();
+
+  // WebFileWriter implementation
+  virtual void truncate(long long length);
+  virtual void write(long long position, const WebKit::WebURL& blobURL);
+  virtual void cancel();
+
+ protected:
+  // This calls DidSucceed() or DidFail() based on the value of |error_code|.
+  void DidFinish(base::PlatformFileError error_code);
+
+  void DidWrite(int64 bytes, bool complete);
+  void DidSucceed();
+  void DidFail(base::PlatformFileError error_code);
+
+  // Derived classes must provide these methods to asynchronously perform
+  // 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 DoWrite(const GURL& path,
+                       const GURL& blob_url,
+                       int64 offset) = 0;
+  virtual void DoCancel() = 0;
+
+ private:
+  enum OperationType {
+    kOperationNone,
+    kOperationWrite,
+    kOperationTruncate
+  };
+
+  enum CancelState {
+    kCancelNotInProgress,
+    kCancelSent,
+    kCancelReceivedWriteResponse,
+  };
+
+  void FinishCancel();
+
+  GURL path_;
+  WebKit::WebFileWriterClient* client_;
+  OperationType operation_;
+  CancelState cancel_state_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_FILEAPI_WEBFILEWRITER_BASE_H_
diff --git a/content/child/fileapi/webfilewriter_base_unittest.cc b/content/child/fileapi/webfilewriter_base_unittest.cc
new file mode 100644
index 0000000..9215081
--- /dev/null
+++ b/content/child/fileapi/webfilewriter_base_unittest.cc
@@ -0,0 +1,411 @@
+// Copyright 2013 The Chromium Authors. 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/fileapi/webfilewriter_base.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebFileError.h"
+#include "third_party/WebKit/public/web/WebFileWriterClient.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+// We use particular offsets to trigger particular behaviors
+// in the TestableFileWriter.
+const int kNoOffset = -1;
+const int kBasicFileTruncate_Offset = 1;
+const int kErrorFileTruncate_Offset = 2;
+const int kCancelFileTruncate_Offset = 3;
+const int kCancelFailedTruncate_Offset = 4;
+const int kBasicFileWrite_Offset = 1;
+const int kErrorFileWrite_Offset = 2;
+const int kMultiFileWrite_Offset = 3;
+const int kCancelFileWriteBeforeCompletion_Offset = 4;
+const int kCancelFileWriteAfterCompletion_Offset = 5;
+
+GURL mock_path_as_gurl() {
+  return GURL("MockPath");
+}
+
+}  // namespace
+
+class TestableFileWriter : public WebFileWriterBase {
+ public:
+  explicit TestableFileWriter(WebKit::WebFileWriterClient* client)
+      : WebFileWriterBase(mock_path_as_gurl(), client) {
+    reset();
+  }
+
+  void reset() {
+    received_truncate_ = false;
+    received_truncate_path_ = GURL();
+    received_truncate_offset_ = kNoOffset;
+    received_write_ = false;
+    received_write_path_ = GURL();
+    received_write_offset_ = kNoOffset;
+    received_write_blob_url_ = GURL();
+    received_cancel_ = false;
+  }
+
+  bool received_truncate_;
+  GURL received_truncate_path_;
+  int64 received_truncate_offset_;
+  bool received_write_;
+  GURL received_write_path_;
+  GURL received_write_blob_url_;
+  int64 received_write_offset_;
+  bool received_cancel_;
+
+ protected:
+  virtual void DoTruncate(const GURL& path, int64 offset) OVERRIDE {
+    received_truncate_ = true;
+    received_truncate_path_ = path;
+    received_truncate_offset_ = offset;
+
+    if (offset == kBasicFileTruncate_Offset) {
+      DidSucceed();
+    } else if (offset == kErrorFileTruncate_Offset) {
+      DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND);
+    } else if (offset == kCancelFileTruncate_Offset) {
+      cancel();
+      DidSucceed();  // truncate completion
+      DidSucceed();  // cancel completion
+    } else if (offset == kCancelFailedTruncate_Offset) {
+      cancel();
+      DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND);  // truncate completion
+      DidSucceed();  // cancel completion
+    } else {
+      FAIL();
+    }
+  }
+
+  virtual void DoWrite(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 DoCancel() OVERRIDE {
+    received_cancel_ = true;
+  }
+};
+
+class FileWriterTest : public testing::Test,
+                       public WebKit::WebFileWriterClient {
+ public:
+  FileWriterTest() {
+    reset();
+  }
+
+  WebKit::WebFileWriter* writer() {
+    return testable_writer_.get();
+  }
+
+  // WebFileWriterClient overrides
+  virtual void didWrite(long long bytes, bool complete) {
+    EXPECT_FALSE(received_did_write_complete_);
+    ++received_did_write_count_;
+    received_did_write_bytes_total_ += bytes;
+    if (complete)
+      received_did_write_complete_ = true;
+
+    if (delete_in_client_callback_)
+      testable_writer_.reset(NULL);
+  }
+
+  virtual void didTruncate() {
+    EXPECT_FALSE(received_did_truncate_);
+    received_did_truncate_ = true;
+    if (delete_in_client_callback_)
+      testable_writer_.reset(NULL);
+  }
+
+  virtual void didFail(WebKit::WebFileError error) {
+    EXPECT_FALSE(received_did_fail_);
+    received_did_fail_ = true;
+    fail_error_received_ = error;
+    if (delete_in_client_callback_)
+      testable_writer_.reset(NULL);
+  }
+
+ protected:
+  void reset() {
+    testable_writer_.reset(new TestableFileWriter(this));
+    delete_in_client_callback_ = false;
+    received_did_write_count_ = 0;
+    received_did_write_bytes_total_ = 0;
+    received_did_write_complete_ = false;
+    received_did_truncate_ = false;
+    received_did_fail_ = false;
+    fail_error_received_ = static_cast<WebKit::WebFileError>(0);
+  }
+
+  scoped_ptr<TestableFileWriter> testable_writer_;
+  bool delete_in_client_callback_;
+
+  // Observed WebFileWriterClient artifacts.
+  int received_did_write_count_;
+  long long received_did_write_bytes_total_;
+  bool received_did_write_complete_;
+  bool received_did_truncate_;
+  bool received_did_fail_;
+  WebKit::WebFileError fail_error_received_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileWriterTest);
+};
+
+TEST_F(FileWriterTest, BasicFileWrite) {
+  // Call the webkit facing api.
+  const GURL kBlobUrl("blob://bloburl/");
+  writer()->write(kBasicFileWrite_Offset, kBlobUrl);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_write_);
+  EXPECT_EQ(testable_writer_->received_write_path_,
+            mock_path_as_gurl());
+  EXPECT_EQ(kBasicFileWrite_Offset,
+            testable_writer_->received_write_offset_);
+  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_FALSE(testable_writer_->received_truncate_);
+  EXPECT_FALSE(testable_writer_->received_cancel_);
+
+  // Check that the client gets called correctly.
+  EXPECT_EQ(1, received_did_write_count_);
+  EXPECT_TRUE(received_did_write_complete_);
+  EXPECT_EQ(1, received_did_write_bytes_total_);
+  EXPECT_FALSE(received_did_truncate_);
+  EXPECT_FALSE(received_did_fail_);
+}
+
+TEST_F(FileWriterTest, BasicFileTruncate) {
+  // Call the webkit facing api.
+  writer()->truncate(kBasicFileTruncate_Offset);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_truncate_);
+  EXPECT_EQ(mock_path_as_gurl(),
+            testable_writer_->received_truncate_path_);
+  EXPECT_EQ(kBasicFileTruncate_Offset,
+            testable_writer_->received_truncate_offset_);
+  EXPECT_FALSE(testable_writer_->received_write_);
+  EXPECT_FALSE(testable_writer_->received_cancel_);
+
+  // Check that the client gets called correctly.
+  EXPECT_TRUE(received_did_truncate_);
+  EXPECT_EQ(0, received_did_write_count_);
+  EXPECT_FALSE(received_did_fail_);
+}
+
+TEST_F(FileWriterTest, ErrorFileWrite) {
+  // Call the webkit facing api.
+  const GURL kBlobUrl("blob://bloburl/");
+  writer()->write(kErrorFileWrite_Offset, kBlobUrl);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_write_);
+  EXPECT_EQ(testable_writer_->received_write_path_,
+            mock_path_as_gurl());
+  EXPECT_EQ(kErrorFileWrite_Offset,
+            testable_writer_->received_write_offset_);
+  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_FALSE(testable_writer_->received_truncate_);
+  EXPECT_FALSE(testable_writer_->received_cancel_);
+
+  // Check that the client gets called correctly.
+  EXPECT_TRUE(received_did_fail_);
+  EXPECT_EQ(WebKit::WebFileErrorNotFound, fail_error_received_);
+  EXPECT_EQ(0, received_did_write_count_);
+  EXPECT_FALSE(received_did_truncate_);
+}
+
+TEST_F(FileWriterTest, ErrorFileTruncate) {
+  // Call the webkit facing api.
+  writer()->truncate(kErrorFileTruncate_Offset);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_truncate_);
+  EXPECT_EQ(mock_path_as_gurl(),
+            testable_writer_->received_truncate_path_);
+  EXPECT_EQ(kErrorFileTruncate_Offset,
+            testable_writer_->received_truncate_offset_);
+  EXPECT_FALSE(testable_writer_->received_write_);
+  EXPECT_FALSE(testable_writer_->received_cancel_);
+
+  // Check that the client gets called correctly.
+  EXPECT_TRUE(received_did_fail_);
+  EXPECT_EQ(WebKit::WebFileErrorNotFound, fail_error_received_);
+  EXPECT_FALSE(received_did_truncate_);
+  EXPECT_EQ(0, received_did_write_count_);
+}
+
+TEST_F(FileWriterTest, MultiFileWrite) {
+  // Call the webkit facing api.
+  const GURL kBlobUrl("blob://bloburl/");
+  writer()->write(kMultiFileWrite_Offset, kBlobUrl);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_write_);
+  EXPECT_EQ(testable_writer_->received_write_path_,
+            mock_path_as_gurl());
+  EXPECT_EQ(kMultiFileWrite_Offset,
+            testable_writer_->received_write_offset_);
+  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_FALSE(testable_writer_->received_truncate_);
+  EXPECT_FALSE(testable_writer_->received_cancel_);
+
+  // Check that the client gets called correctly.
+  EXPECT_EQ(3, received_did_write_count_);
+  EXPECT_TRUE(received_did_write_complete_);
+  EXPECT_EQ(3, received_did_write_bytes_total_);
+  EXPECT_FALSE(received_did_truncate_);
+  EXPECT_FALSE(received_did_fail_);
+}
+
+TEST_F(FileWriterTest, CancelFileWriteBeforeCompletion) {
+  // Call the webkit facing api.
+  const GURL kBlobUrl("blob://bloburl/");
+  writer()->write(kCancelFileWriteBeforeCompletion_Offset, kBlobUrl);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_write_);
+  EXPECT_EQ(testable_writer_->received_write_path_,
+            mock_path_as_gurl());
+  EXPECT_EQ(kCancelFileWriteBeforeCompletion_Offset,
+            testable_writer_->received_write_offset_);
+  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_TRUE(testable_writer_->received_cancel_);
+  EXPECT_FALSE(testable_writer_->received_truncate_);
+
+  // Check that the client gets called correctly.
+  EXPECT_TRUE(received_did_fail_);
+  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
+  EXPECT_EQ(1, received_did_write_count_);
+  EXPECT_FALSE(received_did_write_complete_);
+  EXPECT_EQ(1, received_did_write_bytes_total_);
+  EXPECT_FALSE(received_did_truncate_);
+}
+
+TEST_F(FileWriterTest, CancelFileWriteAfterCompletion) {
+  // Call the webkit facing api.
+  const GURL kBlobUrl("blob://bloburl/");
+  writer()->write(kCancelFileWriteAfterCompletion_Offset, kBlobUrl);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_write_);
+  EXPECT_EQ(testable_writer_->received_write_path_,
+            mock_path_as_gurl());
+  EXPECT_EQ(kCancelFileWriteAfterCompletion_Offset,
+            testable_writer_->received_write_offset_);
+  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
+  EXPECT_TRUE(testable_writer_->received_cancel_);
+  EXPECT_FALSE(testable_writer_->received_truncate_);
+
+  // Check that the client gets called correctly.
+  EXPECT_TRUE(received_did_fail_);
+  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
+  EXPECT_EQ(1, received_did_write_count_);
+  EXPECT_FALSE(received_did_write_complete_);
+  EXPECT_EQ(1, received_did_write_bytes_total_);
+  EXPECT_FALSE(received_did_truncate_);
+}
+
+TEST_F(FileWriterTest, CancelFileTruncate) {
+  // Call the webkit facing api.
+  writer()->truncate(kCancelFileTruncate_Offset);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_truncate_);
+  EXPECT_EQ(mock_path_as_gurl(),
+            testable_writer_->received_truncate_path_);
+  EXPECT_EQ(kCancelFileTruncate_Offset,
+            testable_writer_->received_truncate_offset_);
+  EXPECT_TRUE(testable_writer_->received_cancel_);
+  EXPECT_FALSE(testable_writer_->received_write_);
+
+  // Check that the client gets called correctly.
+  EXPECT_TRUE(received_did_fail_);
+  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
+  EXPECT_FALSE(received_did_truncate_);
+  EXPECT_EQ(0, received_did_write_count_);
+}
+
+TEST_F(FileWriterTest, CancelFailedTruncate) {
+  // Call the webkit facing api.
+  writer()->truncate(kCancelFailedTruncate_Offset);
+
+  // Check that the derived class gets called correctly.
+  EXPECT_TRUE(testable_writer_->received_truncate_);
+  EXPECT_EQ(mock_path_as_gurl(),
+            testable_writer_->received_truncate_path_);
+  EXPECT_EQ(kCancelFailedTruncate_Offset,
+            testable_writer_->received_truncate_offset_);
+  EXPECT_TRUE(testable_writer_->received_cancel_);
+  EXPECT_FALSE(testable_writer_->received_write_);
+
+  // Check that the client gets called correctly.
+  EXPECT_TRUE(received_did_fail_);
+  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
+  EXPECT_FALSE(received_did_truncate_);
+  EXPECT_EQ(0, received_did_write_count_);
+}
+
+TEST_F(FileWriterTest, DeleteInCompletionCallbacks) {
+  delete_in_client_callback_ = true;
+  writer()->write(kBasicFileWrite_Offset, GURL("blob://bloburl/"));
+  EXPECT_FALSE(testable_writer_.get());
+
+  reset();
+  delete_in_client_callback_ = true;
+  writer()->truncate(kBasicFileTruncate_Offset);
+  EXPECT_FALSE(testable_writer_.get());
+
+  reset();
+  delete_in_client_callback_ = true;
+  writer()->write(kErrorFileWrite_Offset, GURL("blob://bloburl/"));
+  EXPECT_FALSE(testable_writer_.get());
+
+  reset();
+  delete_in_client_callback_ = true;
+  writer()->truncate(kErrorFileTruncate_Offset);
+  EXPECT_FALSE(testable_writer_.get());
+
+  // Not crashing counts as passing.
+}
+
+}  // namespace content
diff --git a/content/child/fileapi/webfilewriter_impl.h b/content/child/fileapi/webfilewriter_impl.h
index e7b49b6..69b979b 100644
--- a/content/child/fileapi/webfilewriter_impl.h
+++ b/content/child/fileapi/webfilewriter_impl.h
@@ -8,12 +8,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
-#include "webkit/renderer/fileapi/webfilewriter_base.h"
+#include "content/child/fileapi/webfilewriter_base.h"
 
 namespace content {
 
 // An implementation of WebFileWriter for use in chrome renderers and workers.
-class WebFileWriterImpl : public fileapi::WebFileWriterBase,
+class WebFileWriterImpl : public WebFileWriterBase,
                           public base::SupportsWeakPtr<WebFileWriterImpl> {
  public:
   enum Type {
diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h
index cd75a8c..116c24b 100644
--- a/content/common/accessibility_messages.h
+++ b/content/common/accessibility_messages.h
@@ -26,14 +26,13 @@
 IPC_ENUM_TRAITS(content::AccessibilityNodeData::BoolAttribute)
 IPC_ENUM_TRAITS(content::AccessibilityNodeData::FloatAttribute)
 IPC_ENUM_TRAITS(content::AccessibilityNodeData::IntAttribute)
+IPC_ENUM_TRAITS(content::AccessibilityNodeData::IntListAttribute)
 IPC_ENUM_TRAITS(content::AccessibilityNodeData::Role)
 IPC_ENUM_TRAITS(content::AccessibilityNodeData::State)
 IPC_ENUM_TRAITS(content::AccessibilityNodeData::StringAttribute)
 
 IPC_STRUCT_TRAITS_BEGIN(content::AccessibilityNodeData)
   IPC_STRUCT_TRAITS_MEMBER(id)
-  IPC_STRUCT_TRAITS_MEMBER(name)
-  IPC_STRUCT_TRAITS_MEMBER(value)
   IPC_STRUCT_TRAITS_MEMBER(role)
   IPC_STRUCT_TRAITS_MEMBER(state)
   IPC_STRUCT_TRAITS_MEMBER(location)
@@ -41,12 +40,9 @@
   IPC_STRUCT_TRAITS_MEMBER(int_attributes)
   IPC_STRUCT_TRAITS_MEMBER(float_attributes)
   IPC_STRUCT_TRAITS_MEMBER(bool_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(child_ids)
-  IPC_STRUCT_TRAITS_MEMBER(indirect_child_ids)
+  IPC_STRUCT_TRAITS_MEMBER(intlist_attributes)
   IPC_STRUCT_TRAITS_MEMBER(html_attributes)
-  IPC_STRUCT_TRAITS_MEMBER(line_breaks)
-  IPC_STRUCT_TRAITS_MEMBER(cell_ids)
-  IPC_STRUCT_TRAITS_MEMBER(unique_cell_ids)
+  IPC_STRUCT_TRAITS_MEMBER(child_ids)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_BEGIN(AccessibilityHostMsg_NotificationParams)
diff --git a/content/common/accessibility_node_data.cc b/content/common/accessibility_node_data.cc
index 6848dea..dfc3231 100644
--- a/content/common/accessibility_node_data.cc
+++ b/content/common/accessibility_node_data.cc
@@ -41,6 +41,35 @@
 AccessibilityNodeData::~AccessibilityNodeData() {
 }
 
+void AccessibilityNodeData::AddStringAttribute(
+    StringAttribute attribute, const std::string& value) {
+  string_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AccessibilityNodeData::AddIntAttribute(
+    IntAttribute attribute, int value) {
+  int_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AccessibilityNodeData::AddFloatAttribute(
+    FloatAttribute attribute, float value) {
+  float_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AccessibilityNodeData::AddBoolAttribute(
+    BoolAttribute attribute, bool value) {
+  bool_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AccessibilityNodeData::AddIntListAttribute(
+    IntListAttribute attribute, const std::vector<int32>& value) {
+  intlist_attributes.push_back(std::make_pair(attribute, value));
+}
+
+void AccessibilityNodeData::SetName(std::string name) {
+  string_attributes.push_back(std::make_pair(ATTR_NAME, name));
+}
+
 AccessibilityNodeDataTreeNode::AccessibilityNodeDataTreeNode()
   : AccessibilityNodeData() {
 }
@@ -270,27 +299,14 @@
   if (state & (1 << STATE_VISITED))
     result += " VISITED";
 
-  std::string tmp = UTF16ToUTF8(name);
-  RemoveChars(tmp, "\n", &tmp);
-  if (!tmp.empty())
-    result += " name=" + tmp;
-
-  tmp = UTF16ToUTF8(value);
-  RemoveChars(tmp, "\n", &tmp);
-  if (!tmp.empty())
-    result += " value=" + tmp;
-
   result += " (" + IntToString(location.x()) + ", " +
                    IntToString(location.y()) + ")-(" +
                    IntToString(location.width()) + ", " +
                    IntToString(location.height()) + ")";
 
-  for (std::map<IntAttribute, int32>::const_iterator iter =
-           int_attributes.begin();
-       iter != int_attributes.end();
-       ++iter) {
-    std::string value = IntToString(iter->second);
-    switch (iter->first) {
+  for (size_t i = 0; i < int_attributes.size(); ++i) {
+    std::string value = IntToString(int_attributes[i].second);
+    switch (int_attributes[i].first) {
       case ATTR_SCROLL_X:
         result += " scroll_x=" + value;
         break;
@@ -366,12 +382,9 @@
     }
   }
 
-  for (std::map<StringAttribute, string16>::const_iterator iter =
-           string_attributes.begin();
-       iter != string_attributes.end();
-       ++iter) {
-    std::string value = UTF16ToUTF8(iter->second);
-    switch (iter->first) {
+  for (size_t i = 0; i < string_attributes.size(); ++i) {
+    std::string value = string_attributes[i].second;
+    switch (string_attributes[i].first) {
       case ATTR_DOC_URL:
         result += " doc_url=" + value;
         break;
@@ -423,15 +436,18 @@
       case ATTR_URL:
         result += " url=" + value;
         break;
+      case ATTR_NAME:
+        result += " name=" + value;
+        break;
+      case ATTR_VALUE:
+        result += " value=" + value;
+        break;
     }
   }
 
-  for (std::map<FloatAttribute, float>::const_iterator iter =
-           float_attributes.begin();
-       iter != float_attributes.end();
-       ++iter) {
-    std::string value = DoubleToString(iter->second);
-    switch (iter->first) {
+  for (size_t i = 0; i < float_attributes.size(); ++i) {
+    std::string value = DoubleToString(float_attributes[i].second);
+    switch (float_attributes[i].first) {
       case ATTR_DOC_LOADING_PROGRESS:
         result += " doc_progress=" + value;
         break;
@@ -447,12 +463,9 @@
     }
   }
 
-  for (std::map<BoolAttribute, bool>::const_iterator iter =
-           bool_attributes.begin();
-       iter != bool_attributes.end();
-       ++iter) {
-    std::string value = iter->second ? "true" : "false";
-    switch (iter->first) {
+  for (size_t i = 0; i < bool_attributes.size(); ++i) {
+    std::string value = bool_attributes[i].second ? "true" : "false";
+    switch (bool_attributes[i].first) {
       case ATTR_DOC_LOADED:
         result += " doc_loaded=" + value;
         break;
@@ -483,18 +496,27 @@
     }
   }
 
+  for (size_t i = 0; i < intlist_attributes.size(); ++i) {
+    const std::vector<int32>& values = intlist_attributes[i].second;
+    switch (intlist_attributes[i].first) {
+      case ATTR_INDIRECT_CHILD_IDS:
+        result += " indirect_child_ids=" + IntVectorToString(values);
+        break;
+      case ATTR_LINE_BREAKS:
+        result += " line_breaks=" + IntVectorToString(values);
+        break;
+      case ATTR_CELL_IDS:
+        result += " cell_ids=" + IntVectorToString(values);
+        break;
+      case ATTR_UNIQUE_CELL_IDS:
+        result += " unique_cell_ids=" + IntVectorToString(values);
+        break;
+    }
+  }
+
   if (!child_ids.empty())
     result += " child_ids=" + IntVectorToString(child_ids);
 
-  if (!indirect_child_ids.empty())
-    result += " indirect_child_ids=" + IntVectorToString(indirect_child_ids);
-
-  if (!line_breaks.empty())
-    result += " line_breaks=" + IntVectorToString(line_breaks);
-
-  if (!cell_ids.empty())
-    result += " cell_ids=" + IntVectorToString(cell_ids);
-
   return result;
 }
 
diff --git a/content/common/accessibility_node_data.h b/content/common/accessibility_node_data.h
index e4a206f..db6db40 100644
--- a/content/common/accessibility_node_data.h
+++ b/content/common/accessibility_node_data.h
@@ -191,11 +191,13 @@
     ATTR_DISPLAY,
     ATTR_HELP,
     ATTR_HTML_TAG,
+    ATTR_NAME,
     ATTR_LIVE_RELEVANT,
     ATTR_LIVE_STATUS,
     ATTR_ROLE,
     ATTR_SHORTCUT,
     ATTR_URL,
+    ATTR_VALUE,
   };
 
   enum IntAttribute {
@@ -276,9 +278,41 @@
     ATTR_UPDATE_LOCATION_ONLY,
   };
 
+  enum IntListAttribute {
+    // Ids of nodes that are children of this node logically, but are
+    // not children of this node in the tree structure. As an example,
+    // a table cell is a child of a row, and an 'indirect' child of a
+    // column.
+    ATTR_INDIRECT_CHILD_IDS,
+
+    // Character indices where line breaks occur.
+    ATTR_LINE_BREAKS,
+
+    // For a table, the cell ids in row-major order, with duplicate entries
+    // when there's a rowspan or colspan, and with -1 for missing cells.
+    // There are always exactly rows * columns entries.
+    ATTR_CELL_IDS,
+
+    // For a table, the unique cell ids in row-major order of their first
+    // occurrence.
+    ATTR_UNIQUE_CELL_IDS
+  };
+
   AccessibilityNodeData();
   virtual ~AccessibilityNodeData();
 
+  void AddStringAttribute(StringAttribute attribute,
+                          const std::string& value);
+  void AddIntAttribute(IntAttribute attribute, int value);
+  void AddFloatAttribute(FloatAttribute attribute, float value);
+  void AddBoolAttribute(BoolAttribute attribute, bool value);
+  void AddIntListAttribute(IntListAttribute attribute,
+                           const std::vector<int32>& value);
+
+  // Convenience function, mainly for writing unit tests.
+  // Equivalent to AddStringAttribute(ATTR_NAME, name).
+  void SetName(std::string name);
+
   #ifndef NDEBUG
   virtual std::string DebugString(bool recursive) const;
   #endif
@@ -286,28 +320,17 @@
   // This is a simple serializable struct. All member variables should be
   // public and copyable.
   int32 id;
-  string16 name;
-  string16 value;
   Role role;
   uint32 state;
   gfx::Rect location;
-  std::map<StringAttribute, string16> string_attributes;
-  std::map<IntAttribute, int32> int_attributes;
-  std::map<FloatAttribute, float> float_attributes;
-  std::map<BoolAttribute, bool> bool_attributes;
+  std::vector<std::pair<StringAttribute, std::string> > string_attributes;
+  std::vector<std::pair<IntAttribute, int32> > int_attributes;
+  std::vector<std::pair<FloatAttribute, float> > float_attributes;
+  std::vector<std::pair<BoolAttribute, bool> > bool_attributes;
+  std::vector<std::pair<IntListAttribute, std::vector<int32> > >
+      intlist_attributes;
+  std::vector<std::pair<std::string, std::string> > html_attributes;
   std::vector<int32> child_ids;
-  std::vector<int32> indirect_child_ids;
-  std::vector<std::pair<string16, string16> > html_attributes;
-  std::vector<int32> line_breaks;
-
-  // For a table, the cell ids in row-major order, with duplicate entries
-  // when there's a rowspan or colspan, and with -1 for missing cells.
-  // There are always exactly rows * columns entries.
-  std::vector<int32> cell_ids;
-
-  // For a table, the unique cell ids in row-major order of their first
-  // occurrence.
-  std::vector<int32> unique_cell_ids;
 };
 
 // For testing and debugging only: this subclass of AccessibilityNodeData
diff --git a/content/common/browser_plugin/browser_plugin_constants.cc b/content/common/browser_plugin/browser_plugin_constants.cc
index 9ba17bc..6da58e9 100644
--- a/content/common/browser_plugin/browser_plugin_constants.cc
+++ b/content/common/browser_plugin/browser_plugin_constants.cc
@@ -54,10 +54,6 @@
 const char kMessageText[] = "messageText";
 const char kMessageType[] = "messageType";
 const char kName[] = "name";
-const char kNewHeight[] = "newHeight";
-const char kNewWidth[] = "newWidth";
-const char kOldHeight[] = "oldHeight";
-const char kOldWidth[] = "oldWidth";
 const char kPermission[] = "permission";
 const char kPermissionTypeDialog[] = "dialog";
 const char kPermissionTypeDownload[] = "download";
diff --git a/content/common/browser_plugin/browser_plugin_constants.h b/content/common/browser_plugin/browser_plugin_constants.h
index 7776a82..8e911f0 100644
--- a/content/common/browser_plugin/browser_plugin_constants.h
+++ b/content/common/browser_plugin/browser_plugin_constants.h
@@ -42,9 +42,6 @@
 extern const char kAttributePartition[];
 extern const char kAttributeSrc[];
 
-// Events.
-extern const char kEventSizeChanged[];
-
 // Parameters/properties on events.
 extern const char kDefaultPromptText[];
 extern const char kId[];
@@ -54,10 +51,6 @@
 extern const char kMessageText[];
 extern const char kMessageType[];
 extern const char kName[];
-extern const char kNewHeight[];
-extern const char kNewWidth[];
-extern const char kOldHeight[];
-extern const char kOldWidth[];
 extern const char kPermission[];
 extern const char kPermissionTypeDialog[];
 extern const char kPermissionTypeDownload[];
diff --git a/content/common/cc_messages.h b/content/common/cc_messages.h
index 380d453..ca4ddc1 100644
--- a/content/common/cc_messages.h
+++ b/content/common/cc_messages.h
@@ -21,6 +21,7 @@
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/quads/yuv_video_draw_quad.h"
+#include "cc/resources/returned_resource.h"
 #include "cc/resources/transferable_resource.h"
 #include "content/common/content_export.h"
 #include "gpu/ipc/gpu_command_buffer_traits.h"
@@ -221,6 +222,13 @@
   IPC_STRUCT_TRAITS_MEMBER(mailbox)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(cc::ReturnedResource)
+  IPC_STRUCT_TRAITS_MEMBER(id)
+  IPC_STRUCT_TRAITS_MEMBER(sync_point)
+  IPC_STRUCT_TRAITS_MEMBER(filter)
+  IPC_STRUCT_TRAITS_MEMBER(count)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(cc::BeginFrameArgs)
   IPC_STRUCT_TRAITS_MEMBER(frame_time)
   IPC_STRUCT_TRAITS_MEMBER(deadline)
diff --git a/content/common/gpu/DEPS b/content/common/gpu/DEPS
index f42f973..7d19c09 100644
--- a/content/common/gpu/DEPS
+++ b/content/common/gpu/DEPS
@@ -3,6 +3,7 @@
   "+libEGL",
   "+libGLESv2",
   "+media/video/video_decode_accelerator.h",
+  "+media/video/video_encode_accelerator.h",
   "+skia",
   "+third_party/mesa",
 
diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc
index 96e75ad..65c1c75 100644
--- a/content/common/gpu/client/context_provider_command_buffer.cc
+++ b/content/common/gpu/client/context_provider_command_buffer.cc
@@ -5,7 +5,9 @@
 #include "content/common/gpu/client/context_provider_command_buffer.h"
 
 #include "base/callback_helpers.h"
+#include "cc/output/managed_memory_policy.h"
 #include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
+#include "webkit/common/gpu/managed_memory_policy_convert.h"
 
 namespace content {
 
@@ -29,6 +31,28 @@
   ContextProviderCommandBuffer* provider_;
 };
 
+class ContextProviderCommandBuffer::SwapBuffersCompleteCallbackProxy
+    : public WebKit::WebGraphicsContext3D::
+          WebGraphicsSwapBuffersCompleteCallbackCHROMIUM {
+ public:
+  explicit SwapBuffersCompleteCallbackProxy(
+      ContextProviderCommandBuffer* provider)
+      : provider_(provider) {
+    provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(this);
+  }
+
+  virtual ~SwapBuffersCompleteCallbackProxy() {
+    provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(NULL);
+  }
+
+  virtual void onSwapBuffersComplete() {
+    provider_->OnSwapBuffersComplete();
+  }
+
+ private:
+  ContextProviderCommandBuffer* provider_;
+};
+
 class ContextProviderCommandBuffer::MemoryAllocationCallbackProxy
     : public WebKit::WebGraphicsContext3D::
           WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
@@ -43,8 +67,8 @@
   }
 
   virtual void onMemoryAllocationChanged(
-      WebKit::WebGraphicsMemoryAllocation alloc) {
-    provider_->OnMemoryAllocationChanged(!!alloc.gpuResourceSizeInBytes);
+      WebKit::WebGraphicsMemoryAllocation allocation) {
+    provider_->OnMemoryAllocationChanged(allocation);
   }
 
  private:
@@ -52,18 +76,21 @@
 };
 
 scoped_refptr<ContextProviderCommandBuffer>
-ContextProviderCommandBuffer::Create(const CreateCallback& create_callback) {
-  scoped_refptr<ContextProviderCommandBuffer> provider =
-      new ContextProviderCommandBuffer;
-  if (!provider->InitializeOnMainThread(create_callback))
+ContextProviderCommandBuffer::Create(
+    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d) {
+  if (!context3d)
     return NULL;
-  return provider;
+
+  return new ContextProviderCommandBuffer(context3d.Pass());
 }
 
-ContextProviderCommandBuffer::ContextProviderCommandBuffer()
-    : leak_on_destroy_(false),
+ContextProviderCommandBuffer::ContextProviderCommandBuffer(
+    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d)
+    : context3d_(context3d.Pass()),
+      leak_on_destroy_(false),
       destroyed_(false) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK(context3d_);
   context_thread_checker_.DetachFromThread();
 }
 
@@ -80,16 +107,6 @@
   }
 }
 
-bool ContextProviderCommandBuffer::InitializeOnMainThread(
-    const CreateCallback& create_callback) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
-  DCHECK(!context3d_);
-  DCHECK(!create_callback.is_null());
-  context3d_ = create_callback.Run();
-  return !!context3d_;
-}
-
 bool ContextProviderCommandBuffer::BindToCurrentThread() {
   DCHECK(context3d_);
 
@@ -103,6 +120,10 @@
     return false;
 
   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;
 }
 
@@ -125,8 +146,6 @@
 
   gr_context_.reset(
       new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
-  memory_allocation_callback_proxy_.reset(
-      new MemoryAllocationCallbackProxy(this));
   return gr_context_->get();
 }
 
@@ -151,6 +170,34 @@
     base::ResetAndReturn(&lost_context_callback_).Run();
 }
 
+void ContextProviderCommandBuffer::OnSwapBuffersComplete() {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+  if (!swap_buffers_complete_callback_.is_null())
+    swap_buffers_complete_callback_.Run();
+}
+
+void ContextProviderCommandBuffer::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 =
+      webkit::gpu::ManagedMemoryPolicyConvert::Convert(
+          allocation,
+          &discard_backbuffer_when_not_visible);
+
+  memory_policy_changed_callback_.Run(
+      policy, discard_backbuffer_when_not_visible);
+}
+
 bool ContextProviderCommandBuffer::DestroyedOnMainThread() {
   DCHECK(main_thread_checker_.CalledOnValidThread());
 
@@ -161,15 +208,25 @@
 void ContextProviderCommandBuffer::SetLostContextCallback(
     const LostContextCallback& lost_context_callback) {
   DCHECK(context_thread_checker_.CalledOnValidThread());
-  DCHECK(lost_context_callback_.is_null());
+  DCHECK(lost_context_callback_.is_null() ||
+         lost_context_callback.is_null());
   lost_context_callback_ = lost_context_callback;
 }
 
-void ContextProviderCommandBuffer::OnMemoryAllocationChanged(
-    bool nonzero_allocation) {
+void ContextProviderCommandBuffer::SetSwapBuffersCompleteCallback(
+    const SwapBuffersCompleteCallback& swap_buffers_complete_callback) {
   DCHECK(context_thread_checker_.CalledOnValidThread());
-  if (gr_context_)
-    gr_context_->SetMemoryLimit(nonzero_allocation);
+  DCHECK(swap_buffers_complete_callback_.is_null() ||
+         swap_buffers_complete_callback.is_null());
+  swap_buffers_complete_callback_ = swap_buffers_complete_callback;
+}
+
+void ContextProviderCommandBuffer::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;
 }
 
 }  // namespace content
diff --git a/content/common/gpu/client/context_provider_command_buffer.h b/content/common/gpu/client/context_provider_command_buffer.h
index dd21499..efaf87a 100644
--- a/content/common/gpu/client/context_provider_command_buffer.h
+++ b/content/common/gpu/client/context_provider_command_buffer.h
@@ -23,10 +23,8 @@
 // WebGraphicsContext3DCommandBufferImpl context and a GrContext.
 class ContextProviderCommandBuffer : public cc::ContextProvider {
  public:
-  typedef base::Callback<
-      scoped_ptr<WebGraphicsContext3DCommandBufferImpl>(void)> CreateCallback;
   static scoped_refptr<ContextProviderCommandBuffer> Create(
-      const CreateCallback& create_callback);
+      scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d);
 
   virtual bool BindToCurrentThread() OVERRIDE;
   virtual WebGraphicsContext3DCommandBufferImpl* Context3d() OVERRIDE;
@@ -35,6 +33,12 @@
   virtual bool DestroyedOnMainThread() OVERRIDE;
   virtual void SetLostContextCallback(
       const LostContextCallback& lost_context_callback) OVERRIDE;
+  virtual void SetSwapBuffersCompleteCallback(
+      const SwapBuffersCompleteCallback& swap_buffers_complete_callback)
+      OVERRIDE;
+  virtual void SetMemoryPolicyChangedCallback(
+      const MemoryPolicyChangedCallback& memory_policy_changed_callback)
+      OVERRIDE;
 
   void set_leak_on_destroy() {
     base::AutoLock lock(main_thread_lock_);
@@ -42,15 +46,14 @@
   }
 
  protected:
-  ContextProviderCommandBuffer();
+  ContextProviderCommandBuffer(
+      scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d);
   virtual ~ContextProviderCommandBuffer();
 
-  // This must be called immedately after creating this object, and it should
-  // be thrown away if this returns false.
-  bool InitializeOnMainThread(const CreateCallback& create_callback);
-
   void OnLostContext();
-  void OnMemoryAllocationChanged(bool nonzero_allocation);
+  void OnSwapBuffersComplete();
+  void OnMemoryAllocationChanged(
+      const WebKit::WebGraphicsMemoryAllocation& allocation);
 
  private:
   base::ThreadChecker main_thread_checker_;
@@ -60,6 +63,8 @@
   scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
 
   LostContextCallback lost_context_callback_;
+  SwapBuffersCompleteCallback swap_buffers_complete_callback_;
+  MemoryPolicyChangedCallback memory_policy_changed_callback_;
 
   base::Lock main_thread_lock_;
   bool leak_on_destroy_;
@@ -68,6 +73,10 @@
   class LostContextCallbackProxy;
   scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_;
 
+  class SwapBuffersCompleteCallbackProxy;
+  scoped_ptr<SwapBuffersCompleteCallbackProxy>
+      swap_buffers_complete_callback_proxy_;
+
   class MemoryAllocationCallbackProxy;
   scoped_ptr<MemoryAllocationCallbackProxy> memory_allocation_callback_proxy_;
 };
diff --git a/content/common/gpu/client/gl_helper_scaling.cc b/content/common/gpu/client/gl_helper_scaling.cc
index 88f33dc..ee90016 100644
--- a/content/common/gpu/client/gl_helper_scaling.cc
+++ b/content/common/gpu/client/gl_helper_scaling.cc
@@ -543,18 +543,13 @@
     vertex_header.append(
         "precision highp float;\n"
         "attribute vec2 a_position;\n"
-        "attribute vec2 a_texcoord;\n");
+        "attribute vec2 a_texcoord;\n"
+        "uniform vec4 src_subrect;\n");
 
     fragment_header.append(
         "precision mediump float;\n"
         "uniform sampler2D s_texture;\n");
 
-    shared_variables.append(
-        "uniform vec4 src_subrect;\n"
-        "uniform vec2 src_pixelsize;\n"
-        "uniform vec2 dst_pixelsize;\n"
-        "uniform vec2 scaling_vector;\n");
-
     vertex_program.append(
         "  gl_Position = vec4(a_position, 0.0, 1.0);\n"
         "  vec2 texcoord = src_subrect.xy + a_texcoord * src_subrect.zw;\n");
@@ -573,6 +568,9 @@
         // or exactly 4x.
         shared_variables.append(
             "varying vec4 v_texcoords;\n");  // 2 texcoords packed in one quad
+        vertex_header.append(
+            "uniform vec2 scaling_vector;\n"
+            "uniform vec2 dst_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
             "  step /= 4.0;\n"
@@ -582,7 +580,7 @@
         fragment_program.append(
             "  gl_FragColor = (texture2D(s_texture, v_texcoords.xy) +\n"
             "                  texture2D(s_texture, v_texcoords.zw)) / 2.0;\n");
-         break;
+        break;
 
       case SHADER_BILINEAR3:
         // This is kind of like doing 1.5 passes of the BILINEAR shader.
@@ -590,6 +588,9 @@
         shared_variables.append(
             "varying vec4 v_texcoords1;\n"  // 2 texcoords packed in one quad
             "varying vec2 v_texcoords2;\n");
+        vertex_header.append(
+            "uniform vec2 scaling_vector;\n"
+            "uniform vec2 dst_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
             "  step /= 3.0;\n"
@@ -600,13 +601,16 @@
             "  gl_FragColor = (texture2D(s_texture, v_texcoords1.xy) +\n"
             "                  texture2D(s_texture, v_texcoords1.zw) +\n"
             "                  texture2D(s_texture, v_texcoords2)) / 3.0;\n");
-         break;
+        break;
 
       case SHADER_BILINEAR4:
         // This is equivialent to three passes of the BILINEAR shader above,
         // It can be used to scale an image down 2.0x-4.0x or exactly 8x.
         shared_variables.append(
             "varying vec4 v_texcoords[2];\n");
+        vertex_header.append(
+            "uniform vec2 scaling_vector;\n"
+            "uniform vec2 dst_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
             "  step /= 8.0;\n"
@@ -620,7 +624,7 @@
             "      texture2D(s_texture, v_texcoords[0].zw) +\n"
             "      texture2D(s_texture, v_texcoords[1].xy) +\n"
             "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
-         break;
+        break;
 
       case SHADER_BILINEAR2X2:
         // This is equivialent to four passes of the BILINEAR shader above.
@@ -629,6 +633,8 @@
         // scale an image down by exactly 4x in both dimensions.
         shared_variables.append(
             "varying vec4 v_texcoords[2];\n");
+        vertex_header.append(
+            "uniform vec2 dst_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = src_subrect.zw / 4.0 / dst_pixelsize;\n"
             "  v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n"
@@ -641,7 +647,7 @@
             "      texture2D(s_texture, v_texcoords[0].zw) +\n"
             "      texture2D(s_texture, v_texcoords[1].xy) +\n"
             "      texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
-         break;
+        break;
 
       case SHADER_BICUBIC_HALF_1D:
         // This scales down texture by exactly half in one dimension.
@@ -653,6 +659,9 @@
             "const float CenterWeight = 35.0 / 64.0;\n"
             "const float LobeWeight = -3.0 / 64.0;\n"
             "varying vec4 v_texcoords[2];\n");
+        vertex_header.append(
+            "uniform vec2 scaling_vector;\n"
+            "uniform vec2 src_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = src_subrect.zw * scaling_vector / src_pixelsize;\n"
             "  v_texcoords[0].xy = texcoord - LobeDist * step;\n"
@@ -683,6 +692,8 @@
         vertex_program.append(
             "  v_texcoord = texcoord;\n");
         fragment_header.append(
+            "uniform vec2 src_pixelsize;\n"
+            "uniform vec2 scaling_vector;\n"
             "const float a = -0.5;\n"
             // This function is equivialent to calling the bicubic
             // function with x-1, x, 1-x and 2-x
@@ -718,8 +729,10 @@
         // because single-component textures are not renderable on all
         // architectures.
         shared_variables.append(
-            "varying vec4 v_texcoords[2];\n"
-            "uniform vec4 color_weights;\n");
+            "varying vec4 v_texcoords[2];\n");
+        vertex_header.append(
+            "uniform vec2 scaling_vector;\n"
+            "uniform vec2 dst_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
             "  step /= 4.0;\n"
@@ -727,6 +740,8 @@
             "  v_texcoords[0].zw = texcoord - step * 0.5;\n"
             "  v_texcoords[1].xy = texcoord + step * 0.5;\n"
             "  v_texcoords[1].zw = texcoord + step * 1.5;\n");
+        fragment_header.append(
+            "uniform vec4 color_weights;\n");
         fragment_program.append(
             "  gl_FragColor = color_weights * mat4(\n"
             "    vec4(texture2D(s_texture, v_texcoords[0].xy).rgb, 1.0),\n"
@@ -765,6 +780,9 @@
         //
         shared_variables.append(
             "varying vec4 v_texcoords[2];\n");
+        vertex_header.append(
+            "uniform vec2 scaling_vector;\n"
+            "uniform vec2 dst_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
             "  step /= 4.0;\n"
@@ -806,6 +824,9 @@
         // interpolation in the sampler takes care of that.
         shared_variables.append(
             "varying vec4 v_texcoords;\n");
+        vertex_header.append(
+            "uniform vec2 scaling_vector;\n"
+            "uniform vec2 dst_pixelsize;\n");
         vertex_program.append(
             "  vec2 step = scaling_vector * src_subrect.zw / dst_pixelsize;\n"
             "  step /= 2.0;\n"
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index 601c06d..2ee9f8e 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -13,6 +13,7 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
 #include "content/common/gpu/gpu_messages.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "ipc/ipc_sync_message_filter.h"
@@ -184,6 +185,21 @@
   return proxy->CreateVideoDecoder(profile, client).Pass();
 }
 
+scoped_ptr<media::VideoEncodeAccelerator> GpuChannelHost::CreateVideoEncoder(
+    media::VideoEncodeAccelerator::Client* client) {
+  TRACE_EVENT0("gpu", "GpuChannelHost::CreateVideoEncoder");
+
+  scoped_ptr<media::VideoEncodeAccelerator> vea;
+  int32 route_id = MSG_ROUTING_NONE;
+  if (!Send(new GpuChannelMsg_CreateVideoEncoder(&route_id)))
+    return vea.Pass();
+  if (route_id == MSG_ROUTING_NONE)
+    return vea.Pass();
+
+  vea.reset(new GpuVideoEncodeAcceleratorHost(client, this, route_id));
+  return vea.Pass();
+}
+
 void GpuChannelHost::DestroyCommandBuffer(
     CommandBufferProxyImpl* command_buffer) {
   TRACE_EVENT0("gpu", "GpuChannelHost::DestroyCommandBuffer");
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index 6decd17..9aa3673 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -23,6 +23,7 @@
 #include "ipc/ipc_channel_proxy.h"
 #include "ipc/ipc_sync_channel.h"
 #include "media/video/video_decode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/size.h"
 #include "ui/gl/gpu_preference.h"
@@ -128,6 +129,10 @@
       media::VideoCodecProfile profile,
       media::VideoDecodeAccelerator::Client* client);
 
+  // Creates a video encoder in the GPU process.
+  scoped_ptr<media::VideoEncodeAccelerator> CreateVideoEncoder(
+      media::VideoEncodeAccelerator::Client* client);
+
   // Destroy a command buffer created by this channel.
   void DestroyCommandBuffer(CommandBufferProxyImpl* command_buffer);
 
diff --git a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
index 66c39f9..fcf36bf 100644
--- a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
+++ b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
@@ -37,11 +37,13 @@
 
 void GpuVideoDecodeAcceleratorHost::OnChannelError() {
   DLOG(ERROR) << "GpuVideoDecodeAcceleratorHost::OnChannelError()";
-  OnErrorNotification(PLATFORM_FAILURE);
   if (channel_) {
     channel_->RemoveRoute(decoder_route_id_);
     channel_ = NULL;
   }
+  // See OnErrorNotification for why this needs to be the last thing in this
+  // function.
+  OnErrorNotification(PLATFORM_FAILURE);
 }
 
 bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) {
@@ -65,6 +67,8 @@
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   DCHECK(handled);
+  // See OnErrorNotification for why |this| mustn't be used after
+  // OnErrorNotification might have been called above.
   return handled;
 }
 
@@ -165,6 +169,8 @@
     DLOG(ERROR) << "Send(" << message_type << ") failed";
     error = true;
   }
+  // See OnErrorNotification for why this needs to be the last thing in this
+  // function.
   if (error)
     OnErrorNotification(PLATFORM_FAILURE);
 }
@@ -219,9 +225,13 @@
   DCHECK(CalledOnValidThread());
   if (!client_)
     return;
-  client_->NotifyError(
+
+  // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
+  // last thing done on this stack!
+  media::VideoDecodeAccelerator::Client* client = NULL;
+  std::swap(client, client_);
+  client->NotifyError(
       static_cast<media::VideoDecodeAccelerator::Error>(error));
-  client_ = NULL;
 }
 
 }  // namespace content
diff --git a/content/common/gpu/client/gpu_video_encode_accelerator_host.cc b/content/common/gpu/client/gpu_video_encode_accelerator_host.cc
new file mode 100644
index 0000000..36d99e8
--- /dev/null
+++ b/content/common/gpu/client/gpu_video_encode_accelerator_host.cc
@@ -0,0 +1,227 @@
+// Copyright 2013 The Chromium Authors. 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_video_encode_accelerator_host.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/media/gpu_video_encode_accelerator.h"
+#include "media/base/video_frame.h"
+
+namespace content {
+
+GpuVideoEncodeAcceleratorHost::GpuVideoEncodeAcceleratorHost(
+    media::VideoEncodeAccelerator::Client* client,
+    const scoped_refptr<GpuChannelHost>& gpu_channel_host,
+    int32 route_id)
+    : client_(client),
+      client_ptr_factory_(client_),
+      channel_(gpu_channel_host),
+      route_id_(route_id),
+      next_frame_id_(0) {
+  channel_->AddRoute(route_id_, AsWeakPtr());
+}
+
+GpuVideoEncodeAcceleratorHost::~GpuVideoEncodeAcceleratorHost() {
+  if (channel_)
+    channel_->RemoveRoute(route_id_);
+}
+
+// static
+std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+GpuVideoEncodeAcceleratorHost::GetSupportedProfiles() {
+  return GpuVideoEncodeAccelerator::GetSupportedProfiles();
+}
+
+bool GpuVideoEncodeAcceleratorHost::OnMessageReceived(
+    const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAcceleratorHost, message)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInitializeDone,
+                        OnNotifyInitializeDone)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers,
+                        OnRequireBitstreamBuffers)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyInputDone,
+                        OnNotifyInputDone)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady,
+                        OnBitstreamBufferReady)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderHostMsg_NotifyError,
+                        OnNotifyError)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  DCHECK(handled);
+  // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
+  // have been called above.
+  return handled;
+}
+
+void GpuVideoEncodeAcceleratorHost::OnChannelError() {
+  DLOG(ERROR) << "OnChannelError()";
+  if (channel_) {
+    channel_->RemoveRoute(route_id_);
+    channel_ = NULL;
+  }
+  // See OnNotifyError for why this needs to be the last thing in this
+  // function.
+  OnNotifyError(kPlatformFailureError);
+}
+
+void GpuVideoEncodeAcceleratorHost::Initialize(
+    media::VideoFrame::Format input_format,
+    const gfx::Size& input_visible_size,
+    media::VideoCodecProfile output_profile,
+    uint32 initial_bitrate) {
+  Send(new AcceleratedVideoEncoderMsg_Initialize(route_id_,
+                                                 input_format,
+                                                 input_visible_size,
+                                                 output_profile,
+                                                 initial_bitrate));
+}
+
+void GpuVideoEncodeAcceleratorHost::Encode(
+    const scoped_refptr<media::VideoFrame>& frame,
+    bool force_keyframe) {
+  if (!channel_)
+    return;
+  if (!base::SharedMemory::IsHandleValid(frame->shared_memory_handle())) {
+    DLOG(ERROR) << "Encode(): cannot encode frame not backed by shared memory";
+    NotifyError(kPlatformFailureError);
+    return;
+  }
+  base::SharedMemoryHandle handle =
+      channel_->ShareToGpuProcess(frame->shared_memory_handle());
+  if (!base::SharedMemory::IsHandleValid(handle)) {
+    DLOG(ERROR) << "Encode(): failed to duplicate buffer handle for GPU "
+                   "process";
+    NotifyError(kPlatformFailureError);
+    return;
+  }
+
+  // We assume that planar frame data passed here is packed and contiguous.
+  const size_t plane_count = media::VideoFrame::NumPlanes(frame->format());
+  size_t frame_size = 0;
+  for (size_t i = 0; i < plane_count; ++i) {
+    // Cast DCHECK parameters to void* to avoid printing uint8* as a string.
+    DCHECK_EQ(reinterpret_cast<void*>(frame->data(i)),
+              reinterpret_cast<void*>((frame->data(0) + frame_size)))
+        << "plane=" << i;
+    frame_size += frame->stride(i) * frame->rows(i);
+  }
+
+  Send(new AcceleratedVideoEncoderMsg_Encode(
+      route_id_, next_frame_id_, handle, frame_size, force_keyframe));
+  frame_map_[next_frame_id_] = frame;
+
+  // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
+  next_frame_id_ = (next_frame_id_ + 1) & 0x3FFFFFFF;
+}
+
+void GpuVideoEncodeAcceleratorHost::UseOutputBitstreamBuffer(
+    const media::BitstreamBuffer& buffer) {
+  if (!channel_)
+    return;
+  base::SharedMemoryHandle handle =
+      channel_->ShareToGpuProcess(buffer.handle());
+  if (!base::SharedMemory::IsHandleValid(handle)) {
+    DLOG(ERROR) << "UseOutputBitstreamBuffer(): failed to duplicate buffer "
+                   "handle for GPU process: buffer.id()=" << buffer.id();
+    NotifyError(kPlatformFailureError);
+    return;
+  }
+  Send(new AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer(
+      route_id_, buffer.id(), handle, buffer.size()));
+}
+
+void GpuVideoEncodeAcceleratorHost::RequestEncodingParametersChange(
+    uint32 bitrate,
+    uint32 framerate) {
+  Send(new AcceleratedVideoEncoderMsg_RequestEncodingParametersChange(
+      route_id_, bitrate, framerate));
+}
+
+void GpuVideoEncodeAcceleratorHost::Destroy() {
+  Send(new GpuChannelMsg_DestroyVideoEncoder(route_id_));
+  delete this;
+}
+
+void GpuVideoEncodeAcceleratorHost::NotifyError(Error error) {
+  DVLOG(2) << "NotifyError(): error=" << error;
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&media::VideoEncodeAccelerator::Client::NotifyError,
+                 client_ptr_factory_.GetWeakPtr(),
+                 error));
+}
+
+void GpuVideoEncodeAcceleratorHost::OnNotifyInitializeDone() {
+  DVLOG(2) << "OnNotifyInitializeDone()";
+  if (client_)
+    client_->NotifyInitializeDone();
+}
+
+void GpuVideoEncodeAcceleratorHost::OnRequireBitstreamBuffers(
+    uint32 input_count,
+    const gfx::Size& input_coded_size,
+    uint32 output_buffer_size) {
+  DVLOG(2) << "OnRequireBitstreamBuffers(): input_count=" << input_count
+           << ", input_coded_size=" << input_coded_size.ToString()
+           << ", output_buffer_size=" << output_buffer_size;
+  if (client_) {
+    client_->RequireBitstreamBuffers(
+        input_count, input_coded_size, output_buffer_size);
+  }
+}
+
+void GpuVideoEncodeAcceleratorHost::OnNotifyInputDone(int32 frame_id) {
+  DVLOG(3) << "OnNotifyInputDone(): frame_id=" << frame_id;
+  if (!frame_map_.erase(frame_id)) {
+    DLOG(ERROR) << "OnNotifyInputDone(): "
+                   "invalid frame_id=" << frame_id;
+    // See OnNotifyError for why this needs to be the last thing in this
+    // function.
+    OnNotifyError(kPlatformFailureError);
+    return;
+  }
+}
+
+void GpuVideoEncodeAcceleratorHost::OnBitstreamBufferReady(
+    int32 bitstream_buffer_id,
+    uint32 payload_size,
+    bool key_frame) {
+  DVLOG(3) << "OnBitstreamBufferReady(): "
+              "bitstream_buffer_id=" << bitstream_buffer_id
+           << ", payload_size=" << payload_size
+           << ", key_frame=" << key_frame;
+  if (client_)
+    client_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
+}
+
+void GpuVideoEncodeAcceleratorHost::OnNotifyError(Error error) {
+  DVLOG(2) << "OnNotifyError(): error=" << error;
+  if (!client_)
+    return;
+  client_ptr_factory_.InvalidateWeakPtrs();
+
+  // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
+  // last thing done on this stack!
+  media::VideoEncodeAccelerator::Client* client = NULL;
+  std::swap(client_, client);
+  client->NotifyError(error);
+}
+
+void GpuVideoEncodeAcceleratorHost::Send(IPC::Message* message) {
+  if (!channel_) {
+    DLOG(ERROR) << "Send(): no channel";
+    delete message;
+    NotifyError(kPlatformFailureError);
+  } else if (!channel_->Send(message)) {
+    DLOG(ERROR) << "Send(): sending failed: message->type()="
+                << message->type();
+    NotifyError(kPlatformFailureError);
+  }
+}
+
+}  // namespace content
diff --git a/content/common/gpu/client/gpu_video_encode_accelerator_host.h b/content/common/gpu/client/gpu_video_encode_accelerator_host.h
new file mode 100644
index 0000000..860955d
--- /dev/null
+++ b/content/common/gpu/client/gpu_video_encode_accelerator_host.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 CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_
+#define CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_
+
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "ipc/ipc_listener.h"
+#include "media/video/video_encode_accelerator.h"
+
+namespace gfx {
+
+class Size;
+
+}  // namespace gfx
+
+namespace media {
+
+class VideoFrame;
+
+}  // namespace media
+
+namespace content {
+
+class GpuChannelHost;
+
+// This class is the renderer-side host for the VideoEncodeAccelerator in the
+// GPU process, coordinated over IPC.
+class GpuVideoEncodeAcceleratorHost
+    : public IPC::Listener,
+      public media::VideoEncodeAccelerator,
+      public base::SupportsWeakPtr<GpuVideoEncodeAcceleratorHost> {
+ public:
+  // |client| is assumed to outlive this object.  Since the GpuChannelHost does
+  // _not_ own this object, a reference to |gpu_channel_host| is taken.
+  GpuVideoEncodeAcceleratorHost(
+      media::VideoEncodeAccelerator::Client* client,
+      const scoped_refptr<GpuChannelHost>& gpu_channel_host,
+      int32 route_id);
+  virtual ~GpuVideoEncodeAcceleratorHost();
+
+  // Static query for the supported profiles.  This query proxies to
+  // GpuVideoEncodeAccelerator::GetSupportedProfiles().
+  static std::vector<SupportedProfile> GetSupportedProfiles();
+
+  // IPC::Listener implementation.
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+  virtual void OnChannelError() OVERRIDE;
+
+  // media::VideoEncodeAccelerator implementation.
+  virtual void Initialize(media::VideoFrame::Format format,
+                          const gfx::Size& input_visible_size,
+                          media::VideoCodecProfile output_profile,
+                          uint32 initial_bitrate) OVERRIDE;
+  virtual void Encode(const scoped_refptr<media::VideoFrame>& frame,
+                      bool force_keyframe) OVERRIDE;
+  virtual void UseOutputBitstreamBuffer(
+      const media::BitstreamBuffer& buffer) OVERRIDE;
+  virtual void RequestEncodingParametersChange(uint32 bitrate,
+                                               uint32 framerate_num) OVERRIDE;
+  virtual void Destroy() OVERRIDE;
+
+ private:
+  // Notify |client_| when an error has occured.  Used when notifying from
+  // within a media::VideoEncodeAccelerator entry point, to avoid re-entrancy.
+  void NotifyError(Error error);
+
+  // IPC handlers, proxying media::VideoEncodeAccelerator::Client for the GPU
+  // process.
+  void OnNotifyInitializeDone();
+  void OnRequireBitstreamBuffers(uint32 input_count,
+                                 const gfx::Size& input_coded_size,
+                                 uint32 output_buffer_size);
+  void OnNotifyInputDone(int32 frame_id);
+  void OnBitstreamBufferReady(int32 bitstream_buffer_id,
+                              uint32 payload_size,
+                              bool key_frame);
+  void OnNotifyError(Error error);
+
+  void Send(IPC::Message* message);
+
+  // Weak pointer for client callbacks on the
+  // media::VideoEncodeAccelerator::Client interface.
+  media::VideoEncodeAccelerator::Client* client_;
+  // |client_ptr_factory_| is used for callbacks that need to be done through
+  // a PostTask() to avoid re-entrancy on the client.
+  base::WeakPtrFactory<VideoEncodeAccelerator::Client> client_ptr_factory_;
+
+  // IPC channel and route ID.
+  scoped_refptr<GpuChannelHost> channel_;
+  const int32 route_id_;
+
+  // media::VideoFrames sent to the encoder.
+  // base::IDMap not used here, since that takes pointers, not scoped_refptr.
+  typedef base::hash_map<int32, scoped_refptr<media::VideoFrame> > FrameMap;
+  FrameMap frame_map_;
+
+  // ID serial number for the next frame to send to the GPU process.
+  int32 next_frame_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuVideoEncodeAcceleratorHost);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_GPU_CLIENT_GPU_VIDEO_ENCODE_ACCELERATOR_HOST_H_
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
index a4dd1d5..80f4ebd 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -234,7 +234,8 @@
       command_buffer_size_(0),
       start_transfer_buffer_size_(0),
       min_transfer_buffer_size_(0),
-      max_transfer_buffer_size_(0) {
+      max_transfer_buffer_size_(0),
+      mapped_memory_limit_(gpu::gles2::GLES2Implementation::kNoLimit) {
 #if (defined(OS_MACOSX) || defined(OS_WIN)) && !defined(USE_AURA)
   // Get ViewMsg_SwapBuffers_ACK from browser for single-threaded path.
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
@@ -266,7 +267,8 @@
                     kDefaultCommandBufferSize,
                     kDefaultStartTransferBufferSize,
                     kDefaultMinTransferBufferSize,
-                    kDefaultMaxTransferBufferSize);
+                    kDefaultMaxTransferBufferSize,
+                    gpu::gles2::GLES2Implementation::kNoLimit);
 }
 
 bool WebGraphicsContext3DCommandBufferImpl::Initialize(
@@ -276,7 +278,8 @@
     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 max_transfer_buffer_size,
+    size_t mapped_memory_limit) {
   TRACE_EVENT0("gpu", "WebGfxCtx3DCmdBfrImpl::initialize");
 
   attributes_ = attributes;
@@ -297,6 +300,7 @@
   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;
 }
@@ -480,7 +484,8 @@
   if (!real_gl_->Initialize(
       start_transfer_buffer_size_,
       min_transfer_buffer_size_,
-      max_transfer_buffer_size_)) {
+      max_transfer_buffer_size_,
+      mapped_memory_limit_)) {
     return false;
   }
 
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
index c9f2368..363ff62 100644
--- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
+++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h
@@ -76,6 +76,10 @@
     : public WebKit::WebGraphicsContext3D,
       public base::SupportsWeakPtr<WebGraphicsContext3DCommandBufferImpl> {
  public:
+  enum MappedMemoryReclaimLimit {
+    kNoLimit = 0,
+  };
+
   WebGraphicsContext3DCommandBufferImpl(
       int surface_id,
       const GURL& active_url,
@@ -90,7 +94,8 @@
                   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 max_transfer_buffer_size,
+                  size_t mapped_memory_reclaim_limit);
 
   bool InitializeWithDefaultBufferSizes(const Attributes& attributes,
                                         bool bind_generates_resources,
@@ -757,6 +762,7 @@
   size_t start_transfer_buffer_size_;
   size_t min_transfer_buffer_size_;
   size_t max_transfer_buffer_size_;
+  size_t mapped_memory_limit_;
 };
 
 }  // namespace content
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
index 2e26fac..2b920d3 100644
--- a/content/common/gpu/gpu_channel.cc
+++ b/content/common/gpu/gpu_channel.cc
@@ -20,6 +20,7 @@
 #include "base/timer/timer.h"
 #include "content/common/gpu/gpu_channel_manager.h"
 #include "content/common/gpu/gpu_messages.h"
+#include "content/common/gpu/media/gpu_video_encode_accelerator.h"
 #include "content/common/gpu/sync_point_manager.h"
 #include "content/public/common/content_switches.h"
 #include "crypto/hmac.h"
@@ -754,9 +755,12 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg)
     IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer,
-                                    OnCreateOffscreenCommandBuffer)
+                        OnCreateOffscreenCommandBuffer)
     IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
-                                    OnDestroyCommandBuffer)
+                        OnDestroyCommandBuffer)
+    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoEncoder, OnCreateVideoEncoder)
+    IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyVideoEncoder,
+                        OnDestroyVideoEncoder)
 #if defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(GpuChannelMsg_RegisterStreamTextureProxy,
                         OnRegisterStreamTextureProxy)
@@ -899,6 +903,26 @@
   }
 }
 
+void GpuChannel::OnCreateVideoEncoder(int32* route_id) {
+  TRACE_EVENT0("gpu", "GpuChannel::OnCreateVideoEncoder");
+
+  *route_id = GenerateRouteID();
+  GpuVideoEncodeAccelerator* encoder =
+      new GpuVideoEncodeAccelerator(this, *route_id);
+  router_.AddRoute(*route_id, encoder);
+  video_encoders_.AddWithID(encoder, *route_id);
+}
+
+void GpuChannel::OnDestroyVideoEncoder(int32 route_id) {
+  TRACE_EVENT1(
+      "gpu", "GpuChannel::OnDestroyVideoEncoder", "route_id", route_id);
+  GpuVideoEncodeAccelerator* encoder = video_encoders_.Lookup(route_id);
+  if (!encoder)
+    return;
+  router_.RemoveRoute(route_id);
+  video_encoders_.Remove(route_id);
+}
+
 #if defined(OS_ANDROID)
 void GpuChannel::OnRegisterStreamTextureProxy(
     int32 stream_id, int32* route_id) {
diff --git a/content/common/gpu/gpu_channel.h b/content/common/gpu/gpu_channel.h
index 8d775f0..0692b90 100644
--- a/content/common/gpu/gpu_channel.h
+++ b/content/common/gpu/gpu_channel.h
@@ -11,6 +11,7 @@
 #include "base/id_map.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process/process.h"
 #include "build/build_config.h"
@@ -49,9 +50,10 @@
 
 namespace content {
 class GpuChannelManager;
-struct GpuRenderingStats;
-class GpuWatchdog;
 class GpuChannelMessageFilter;
+struct GpuRenderingStats;
+class GpuVideoEncodeAccelerator;
+class GpuWatchdog;
 
 // Encapsulates an IPC channel between the GPU process and one renderer
 // process. On the renderer side there's a corresponding GpuChannelHost.
@@ -173,6 +175,8 @@
       const GPUCreateCommandBufferConfig& init_params,
       int32* route_id);
   void OnDestroyCommandBuffer(int32 route_id);
+  void OnCreateVideoEncoder(int32* route_id);
+  void OnDestroyVideoEncoder(int32 route_id);
 
 #if defined(OS_ANDROID)
   // Register the StreamTextureProxy class with the gpu process so that all
@@ -238,6 +242,9 @@
   StubMap stubs_;
 #endif  // defined (ENABLE_GPU)
 
+  typedef IDMap<GpuVideoEncodeAccelerator, IDMapOwnPointer> EncoderMap;
+  EncoderMap video_encoders_;
+
   bool log_messages_;  // True if we should log sent and received messages.
   gpu::gles2::DisallowedFeatures disallowed_features_;
   GpuWatchdog* watchdog_;
diff --git a/content/common/gpu/gpu_memory_manager.cc b/content/common/gpu/gpu_memory_manager.cc
index 21d5163..88d7861 100644
--- a/content/common/gpu/gpu_memory_manager.cc
+++ b/content/common/gpu/gpu_memory_manager.cc
@@ -79,8 +79,12 @@
 #endif
 
   // On Android, always discard everything that is nonvisible.
-  // On Mac, use as little memory as possible to avoid stability issues.
-#if defined(OS_ANDROID) || defined(OS_MACOSX)
+  // On Linux and Mac, use as little memory as possible to avoid stability
+  // issues.
+  // http://crbug.com/145600 (Linux)
+  // http://crbug.com/141377 (Mac)
+#if defined(OS_ANDROID) || defined(OS_MACOSX) || \
+    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
   allow_nonvisible_memory_ = false;
 #else
   allow_nonvisible_memory_ = true;
@@ -496,10 +500,12 @@
 
 uint64 GpuMemoryManager::ComputeClientAllocationWhenNonvisible(
     GpuMemoryManagerClientState* client_state) {
-
   if (!client_state->managed_memory_stats_received_)
     return 0;
 
+  if (!allow_nonvisible_memory_)
+    return 0;
+
   return 9 * client_state->managed_memory_stats_.bytes_required / 8;
 }
 
@@ -644,10 +650,6 @@
         bytes_available_total - bytes_allocated_visible);
   }
 
-  // Clamp the amount of memory available to non-visible clients.
-  if (!allow_nonvisible_memory_)
-    bytes_available_nonvisible = 0;
-
   // Determine which now-visible clients should keep their contents when
   // they are made nonvisible.
   for (ClientStateList::const_iterator it = clients_visible_mru_.begin();
@@ -774,11 +776,12 @@
 
     allocation.renderer_allocation.bytes_limit_when_visible =
         client_state->bytes_allocation_when_visible_;
-    // Use a more conservative memory allocation policy on Mac because the
-    // platform is unstable when under memory pressure.
-    // http://crbug.com/141377
+    // 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 =
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
         GpuMemoryAllocationForRenderer::kPriorityCutoffAllowNiceToHave;
 #else
         GpuMemoryAllocationForRenderer::kPriorityCutoffAllowEverything;
diff --git a/content/common/gpu/gpu_memory_manager.h b/content/common/gpu/gpu_memory_manager.h
index caaead5..415d127 100644
--- a/content/common/gpu/gpu_memory_manager.h
+++ b/content/common/gpu/gpu_memory_manager.h
@@ -92,6 +92,8 @@
   FRIEND_TEST_ALL_PREFIXES(GpuMemoryManagerTest,
                            BackgroundMru);
   FRIEND_TEST_ALL_PREFIXES(GpuMemoryManagerTest,
+                           AllowNonvisibleMemory);
+  FRIEND_TEST_ALL_PREFIXES(GpuMemoryManagerTest,
                            BackgroundDiscardPersistent);
   FRIEND_TEST_ALL_PREFIXES(GpuMemoryManagerTest,
                            UnmanagedTracking);
diff --git a/content/common/gpu/gpu_memory_manager_unittest.cc b/content/common/gpu/gpu_memory_manager_unittest.cc
index 263c585..e008a47 100644
--- a/content/common/gpu/gpu_memory_manager_unittest.cc
+++ b/content/common/gpu/gpu_memory_manager_unittest.cc
@@ -160,6 +160,7 @@
   GpuMemoryManagerTest()
       : memmgr_(0, kFrontbufferLimitForTest) {
     memmgr_.TestingDisableScheduleManage();
+    memmgr_.allow_nonvisible_memory_ = true;
   }
 
   virtual void SetUp() {
@@ -674,8 +675,6 @@
   memmgr_.TestingSetMinimumClientAllocation(8);
 
   uint64 bytes_when_not_visible_expected = 6u;
-  if (!memmgr_.allow_nonvisible_memory_)
-    bytes_when_not_visible_expected = 0;
 
   FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true);
   FakeClient stub2(&memmgr_, GenerateUniqueSurfaceId(), true);
@@ -720,6 +719,31 @@
   EXPECT_GE(stub3.BytesWhenNotVisible(), bytes_when_not_visible_expected);
 }
 
+TEST_F(GpuMemoryManagerTest, AllowNonvisibleMemory) {
+  memmgr_.TestingSetAvailableGpuMemory(512);
+  memmgr_.TestingSetMinimumClientAllocation(16);
+
+  FakeClient stub1(&memmgr_, GenerateUniqueSurfaceId(), true);
+  FakeClient stub2(&memmgr_, GenerateUniqueSurfaceId(), true);
+  FakeClient stub3(&memmgr_, GenerateUniqueSurfaceId(), true);
+
+  memmgr_.allow_nonvisible_memory_ = true;
+  stub1.SetVisible(true);
+  SetClientStats(&stub1, 20, 80);
+  SetClientStats(&stub2, 20, 80);
+  SetClientStats(&stub3, 20, 80);
+  Manage();
+  EXPECT_GT(stub1.BytesWhenNotVisible(), 0u);
+  EXPECT_GT(stub2.BytesWhenNotVisible(), 0u);
+  EXPECT_GT(stub3.BytesWhenNotVisible(), 0u);
+
+  memmgr_.allow_nonvisible_memory_ = false;
+  Manage();
+  EXPECT_EQ(stub1.BytesWhenNotVisible(), 0u);
+  EXPECT_EQ(stub2.BytesWhenNotVisible(), 0u);
+  EXPECT_EQ(stub3.BytesWhenNotVisible(), 0u);
+}
+
 // Test that once a backgrounded client has dropped its resources, it
 // doesn't get them back until it becomes visible again.
 TEST_F(GpuMemoryManagerTest, BackgroundDiscardPersistent) {
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 5749c37..49493d9 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -23,7 +23,9 @@
 #include "gpu/ipc/gpu_command_buffer_traits.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_message_macros.h"
+#include "media/base/video_frame.h"
 #include "media/video/video_decode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
 #include "ui/base/latency_info.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/size.h"
@@ -217,6 +219,10 @@
   IPC_STRUCT_TRAITS_MEMBER(total_processing_commands_time)
 IPC_STRUCT_TRAITS_END()
 
+IPC_ENUM_TRAITS(media::VideoFrame::Format)
+
+IPC_ENUM_TRAITS(media::VideoEncodeAccelerator::Error)
+
 //------------------------------------------------------------------------------
 // GPU Messages
 // These are messages from the browser to the GPU process.
@@ -447,6 +453,12 @@
 IPC_MESSAGE_CONTROL1(GpuChannelMsg_GenerateMailboxNamesReply,
                      std::vector<gpu::Mailbox> /* mailbox_names */)
 
+// Create a new GPU-accelerated video encoder.
+IPC_SYNC_MESSAGE_CONTROL0_1(GpuChannelMsg_CreateVideoEncoder,
+                            int32 /* route_id */)
+
+IPC_MESSAGE_CONTROL1(GpuChannelMsg_DestroyVideoEncoder, int32 /* route_id */)
+
 #if defined(OS_ANDROID)
 // Register the StreamTextureProxy class with the GPU process, so that
 // the renderer process will get notified whenever a frame becomes available.
@@ -690,3 +702,64 @@
 // Video decoder has encountered an error.
 IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_ErrorNotification,
                     uint32) /* Error ID */
+
+//------------------------------------------------------------------------------
+// Accelerated Video Encoder Messages
+// These messages are sent from the Renderer process to GPU process.
+
+// Initialize the accelerated encoder.
+IPC_MESSAGE_ROUTED4(AcceleratedVideoEncoderMsg_Initialize,
+                    media::VideoFrame::Format /* input_format */,
+                    gfx::Size /* input_visible_size */,
+                    media::VideoCodecProfile /* output_profile */,
+                    uint32 /* initial_bitrate */)
+
+// Queue a input buffer to the encoder to encode. |frame_id| will be returned by
+// AcceleratedVideoEncoderHostMsg_NotifyEncodeDone.
+IPC_MESSAGE_ROUTED4(AcceleratedVideoEncoderMsg_Encode,
+                    int32 /* frame_id */,
+                    base::SharedMemoryHandle /* buffer_handle */,
+                    uint32 /* buffer_size */,
+                    bool /* force_keyframe */)
+
+// Queue a buffer to the encoder for use in returning output.  |buffer_id| will
+// be returned by AcceleratedVideoEncoderHostMsg_BitstreamBufferReady.
+IPC_MESSAGE_ROUTED3(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
+                    int32 /* buffer_id */,
+                    base::SharedMemoryHandle /* buffer_handle */,
+                    uint32 /* buffer_size */)
+
+// Request a runtime encoding parameter change.
+IPC_MESSAGE_ROUTED2(AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
+                    uint32 /* bitrate */,
+                    uint32 /* framerate */)
+
+//------------------------------------------------------------------------------
+// Accelerated Video Encoder Host Messages
+// These messages are sent from GPU process to Renderer process.
+
+// Notify of the completion of initialization.
+IPC_MESSAGE_ROUTED0(AcceleratedVideoEncoderHostMsg_NotifyInitializeDone)
+
+// Notify renderer of the input/output buffer requirements of the encoder.
+IPC_MESSAGE_ROUTED3(AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers,
+                    uint32 /* input_count */,
+                    gfx::Size /* input_coded_size */,
+                    uint32 /* output_buffer_size */)
+
+// Notify the renderer that the encoder has finished using an input buffer.
+// There is no congruent entry point in the media::VideoEncodeAccelerator
+// interface, in VEA this same done condition is indicated by dropping the
+// reference to the media::VideoFrame passed to VEA::Encode().
+IPC_MESSAGE_ROUTED1(AcceleratedVideoEncoderHostMsg_NotifyInputDone,
+                    int32 /* frame_id */)
+
+// Notify the renderer that an output buffer has been filled with encoded data.
+IPC_MESSAGE_ROUTED3(AcceleratedVideoEncoderHostMsg_BitstreamBufferReady,
+                    int32 /* bitstream_buffer_id */,
+                    uint32 /* payload_size */,
+                    bool /* key_frame */)
+
+// Report error condition.
+IPC_MESSAGE_ROUTED1(AcceleratedVideoEncoderHostMsg_NotifyError,
+                    media::VideoEncodeAccelerator::Error /* error */)
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator.cc
index f999070..fa4dc5c 100644
--- a/content/common/gpu/media/dxva_video_decode_accelerator.cc
+++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc
@@ -185,6 +185,10 @@
     return picture_buffer_.id();
   }
 
+  gfx::Size size() const {
+    return picture_buffer_.size();
+  }
+
  private:
   explicit DXVAPictureBuffer(const media::PictureBuffer& buffer);
 
@@ -289,8 +293,7 @@
 
   D3DSURFACE_DESC texture_desc;
   decoding_texture_->GetLevelDesc(0, &texture_desc);
-  // TODO(ananta)
-  // We need to support mid stream resize.
+
   if (texture_desc.Width != surface_desc.Width ||
       texture_desc.Height != surface_desc.Height) {
     NOTREACHED() << "Decode surface of different dimension than texture";
@@ -565,6 +568,9 @@
   RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized),
       "Invalid state: " << state_, ILLEGAL_STATE,);
 
+  if (output_picture_buffers_.empty())
+    return;
+
   OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id);
   RETURN_AND_NOTIFY_ON_FAILURE(it != output_picture_buffers_.end(),
       "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,);
@@ -876,10 +882,7 @@
 
   // We only read the surface description, which contains its width/height when
   // we need the picture buffers from the client. Once we have those, then they
-  // are reused. This won't work if the frame sizes change mid stream.
-  // There is a TODO comment in the
-  // DXVAVideoDecodeAccelerator::RequestPictureBuffers function which talks
-  // about supporting this.
+  // are reused.
   D3DSURFACE_DESC surface_desc;
   hr = surface->GetDesc(&surface_desc);
   RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false);
@@ -919,6 +922,19 @@
           hr, "Failed to get D3D surface from output sample",
           PLATFORM_FAILURE,);
 
+      D3DSURFACE_DESC surface_desc;
+      hr = surface->GetDesc(&surface_desc);
+      RETURN_AND_NOTIFY_ON_HR_FAILURE(
+          hr, "Failed to get surface description", PLATFORM_FAILURE,);
+
+      if (surface_desc.Width !=
+              static_cast<uint32>(index->second->size().width()) ||
+          surface_desc.Height !=
+              static_cast<uint32>(index->second->size().height())) {
+        HandleResolutionChanged(surface_desc.Width, surface_desc.Height);
+        return;
+      }
+
       RETURN_AND_NOTIFY_ON_FAILURE(
           index->second->CopyOutputSampleDataToPictureBuffer(
               surface),
@@ -988,8 +1004,6 @@
 
 void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) {
   // This task could execute after the decoder has been torn down.
-  // TODO(ananta)
-  // We need to support mid stream resize.
   if (state_ != kUninitialized && client_) {
     client_->ProvidePictureBuffers(
         kNumPictureBuffers,
@@ -1132,4 +1146,29 @@
       base::AsWeakPtr(this), input_buffer_id));
 }
 
+void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width,
+                                                         int height) {
+  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &DXVAVideoDecodeAccelerator::DismissStaleBuffers,
+      base::AsWeakPtr(this), output_picture_buffers_));
+
+  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+      &DXVAVideoDecodeAccelerator::RequestPictureBuffers,
+      base::AsWeakPtr(this), width, height));
+
+  output_picture_buffers_.clear();
+}
+
+void DXVAVideoDecodeAccelerator::DismissStaleBuffers(
+    const OutputBuffers& picture_buffers) {
+  OutputBuffers::const_iterator index;
+
+  for (index = picture_buffers.begin();
+       index != picture_buffers.end();
+       ++index) {
+    DVLOG(1) << "Dismissing picture id: " << index->second->id();
+    client_->DismissPictureBuffer(index->second->id());
+  }
+}
+
 }  // namespace content
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.h b/content/common/gpu/media/dxva_video_decode_accelerator.h
index b137946..26b1ba7 100644
--- a/content/common/gpu/media/dxva_video_decode_accelerator.h
+++ b/content/common/gpu/media/dxva_video_decode_accelerator.h
@@ -147,6 +147,15 @@
   // Helper for handling the Decode operation.
   void DecodeInternal(const base::win::ScopedComPtr<IMFSample>& input_sample);
 
+  // Handles mid stream resolution changes.
+  void HandleResolutionChanged(int width, int height);
+
+  struct DXVAPictureBuffer;
+  typedef std::map<int32, linked_ptr<DXVAPictureBuffer> > OutputBuffers;
+
+  // Tells the client to dismiss the stale picture buffers passed in.
+  void DismissStaleBuffers(const OutputBuffers& picture_buffers);
+
   // To expose client callbacks from VideoDecodeAccelerator.
   media::VideoDecodeAccelerator::Client* client_;
 
@@ -186,11 +195,8 @@
   // List of decoded output samples.
   PendingOutputSamples pending_output_samples_;
 
-  struct DXVAPictureBuffer;
-
   // This map maintains the picture buffers passed the client for decoding.
   // The key is the picture buffer id.
-  typedef std::map<int32, linked_ptr<DXVAPictureBuffer> > OutputBuffers;
   OutputBuffers output_picture_buffers_;
 
   // Set to true if we requested picture slots from the client.
diff --git a/content/common/gpu/media/exynos_video_encode_accelerator.cc b/content/common/gpu/media/exynos_video_encode_accelerator.cc
new file mode 100644
index 0000000..4b9d38f
--- /dev/null
+++ b/content/common/gpu/media/exynos_video_encode_accelerator.cc
@@ -0,0 +1,1490 @@
+// Copyright 2013 The Chromium Authors. 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/media/exynos_video_encode_accelerator.h"
+
+#include <fcntl.h>
+#include <linux/videodev2.h>
+#include <poll.h>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+
+#include "base/callback.h"
+#include "base/debug/trace_event.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/posix/eintr_wrapper.h"
+#include "media/base/bitstream_buffer.h"
+
+#define NOTIFY_ERROR(x)                                            \
+  do {                                                             \
+    SetEncoderState(kError);                                       \
+    DLOG(ERROR) << "calling NotifyError(): " << x;                 \
+    NotifyError(x);                                                \
+  } while (0)
+
+#define IOCTL_OR_ERROR_RETURN(fd, type, arg)                       \
+  do {                                                             \
+    if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) {                 \
+      DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
+      NOTIFY_ERROR(kPlatformFailureError);                         \
+      return;                                                      \
+    }                                                              \
+  } while (0)
+
+#define IOCTL_OR_ERROR_RETURN_FALSE(fd, type, arg)                 \
+  do {                                                             \
+    if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) {                 \
+      DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
+      NOTIFY_ERROR(kPlatformFailureError);                         \
+      return false;                                                \
+    }                                                              \
+  } while (0)
+
+namespace content {
+
+namespace {
+
+const char kExynosGscDevice[] = "/dev/gsc1";
+const char kExynosMfcDevice[] = "/dev/mfc-enc";
+
+// File descriptors we need to poll, one-bit flag for each.
+enum PollFds {
+  kPollGsc = (1 << 0),
+  kPollMfc = (1 << 1),
+};
+
+}  // anonymous namespace
+
+struct ExynosVideoEncodeAccelerator::BitstreamBufferRef {
+  BitstreamBufferRef(int32 id, scoped_ptr<base::SharedMemory> shm, size_t size)
+      : id(id), shm(shm.Pass()), size(size) {}
+  const int32 id;
+  const scoped_ptr<base::SharedMemory> shm;
+  const size_t size;
+};
+
+
+ExynosVideoEncodeAccelerator::GscInputRecord::GscInputRecord()
+    : at_device(false) {}
+
+ExynosVideoEncodeAccelerator::GscOutputRecord::GscOutputRecord()
+    : at_device(false), mfc_input(-1) {}
+
+ExynosVideoEncodeAccelerator::MfcInputRecord::MfcInputRecord()
+    : at_device(false) {
+  fd[0] = fd[1] = -1;
+}
+
+ExynosVideoEncodeAccelerator::MfcOutputRecord::MfcOutputRecord()
+    : at_device(false) {}
+
+ExynosVideoEncodeAccelerator::ExynosVideoEncodeAccelerator(
+    media::VideoEncodeAccelerator::Client* client)
+    : child_message_loop_proxy_(base::MessageLoopProxy::current()),
+      weak_this_ptr_factory_(this),
+      weak_this_(weak_this_ptr_factory_.GetWeakPtr()),
+      client_ptr_factory_(client),
+      client_(client_ptr_factory_.GetWeakPtr()),
+      encoder_thread_("ExynosEncoderThread"),
+      encoder_state_(kUninitialized),
+      output_buffer_byte_size_(0),
+      stream_header_size_(0),
+      input_format_fourcc_(0),
+      output_format_fourcc_(0),
+      gsc_fd_(-1),
+      gsc_input_streamon_(false),
+      gsc_input_buffer_queued_count_(0),
+      gsc_output_streamon_(false),
+      gsc_output_buffer_queued_count_(0),
+      mfc_fd_(-1),
+      mfc_input_streamon_(false),
+      mfc_input_buffer_queued_count_(0),
+      mfc_output_streamon_(false),
+      mfc_output_buffer_queued_count_(0),
+      device_poll_thread_("ExynosEncoderDevicePollThread"),
+      device_poll_interrupt_fd_(-1) {
+  DCHECK(client_);
+}
+
+ExynosVideoEncodeAccelerator::~ExynosVideoEncodeAccelerator() {
+  DCHECK(!encoder_thread_.IsRunning());
+  DCHECK(!device_poll_thread_.IsRunning());
+
+  if (device_poll_interrupt_fd_ != -1) {
+    HANDLE_EINTR(close(device_poll_interrupt_fd_));
+    device_poll_interrupt_fd_ = -1;
+  }
+  if (gsc_fd_ != -1) {
+    DestroyGscInputBuffers();
+    DestroyGscOutputBuffers();
+    HANDLE_EINTR(close(gsc_fd_));
+    gsc_fd_ = -1;
+  }
+  if (mfc_fd_ != -1) {
+    DestroyMfcInputBuffers();
+    DestroyMfcOutputBuffers();
+    HANDLE_EINTR(close(mfc_fd_));
+    mfc_fd_ = -1;
+  }
+}
+
+void ExynosVideoEncodeAccelerator::Initialize(
+    media::VideoFrame::Format input_format,
+    const gfx::Size& input_visible_size,
+    media::VideoCodecProfile output_profile,
+    uint32 initial_bitrate) {
+  DVLOG(3) << "Initialize(): input_format=" << input_format
+           << ", input_visible_size=" << input_visible_size.ToString()
+           << ", output_profile=" << output_profile
+           << ", initial_bitrate=" << initial_bitrate;
+
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK_EQ(encoder_state_, kUninitialized);
+
+  input_visible_size_ = input_visible_size;
+  input_allocated_size_.SetSize((input_visible_size_.width() + 0xF) & ~0xF,
+                                (input_visible_size_.height() + 0xF) & ~0xF);
+  converted_visible_size_.SetSize((input_visible_size_.width() + 0x1) & ~0x1,
+                                  (input_visible_size_.height() + 0x1) & ~0x1);
+  converted_allocated_size_.SetSize(
+      (converted_visible_size_.width() + 0xF) & ~0xF,
+      (converted_visible_size_.height() + 0xF) & ~0xF);
+  output_visible_size_ = converted_visible_size_;
+
+  switch (input_format) {
+    case media::VideoFrame::RGB32:
+      input_format_fourcc_ = V4L2_PIX_FMT_RGB32;
+      break;
+    case media::VideoFrame::I420:
+      input_format_fourcc_ = V4L2_PIX_FMT_YUV420M;
+      break;
+    default:
+      NOTIFY_ERROR(kInvalidArgumentError);
+      return;
+  }
+
+  if (output_profile >= media::H264PROFILE_MIN &&
+      output_profile <= media::H264PROFILE_MAX) {
+    output_format_fourcc_ = V4L2_PIX_FMT_H264;
+  } else {
+    NOTIFY_ERROR(kInvalidArgumentError);
+    return;
+  }
+
+  // Open the color conversion device.
+  DVLOG(2) << "Initialize(): opening GSC device: " << kExynosGscDevice;
+  gsc_fd_ =
+      HANDLE_EINTR(open(kExynosGscDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
+  if (gsc_fd_ == -1) {
+    DPLOG(ERROR) << "Initialize(): could not open GSC device: "
+                 << kExynosGscDevice;
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  // Capabilities check.
+  struct v4l2_capability caps;
+  memset(&caps, 0, sizeof(caps));
+  const __u32 kCapsRequired = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+                              V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING;
+  IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_QUERYCAP, &caps);
+  if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
+    DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
+                   "caps check failed: 0x" << std::hex << caps.capabilities;
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  // Open the video encoder device.
+  DVLOG(2) << "Initialize(): opening MFC device: " << kExynosMfcDevice;
+  mfc_fd_ =
+      HANDLE_EINTR(open(kExynosMfcDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
+  if (mfc_fd_ == -1) {
+    DPLOG(ERROR) << "Initialize(): could not open MFC device: "
+                 << kExynosMfcDevice;
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  memset(&caps, 0, sizeof(caps));
+  IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_QUERYCAP, &caps);
+  if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
+    DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
+                   "caps check failed: 0x" << std::hex << caps.capabilities;
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  // Create the interrupt fd.
+  DCHECK_EQ(device_poll_interrupt_fd_, -1);
+  device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+  if (device_poll_interrupt_fd_ == -1) {
+    DPLOG(ERROR) << "Initialize(): eventfd() failed";
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  DVLOG(3)
+      << "Initialize(): input_visible_size_=" << input_visible_size_.ToString()
+      << ", input_allocated_size_=" << input_allocated_size_.ToString()
+      << ", converted_visible_size_=" << converted_visible_size_.ToString()
+      << ", converted_allocated_size_=" << converted_allocated_size_.ToString()
+      << ", output_visible_size_=" << output_visible_size_.ToString();
+
+  if (!CreateGscInputBuffers() || !CreateGscOutputBuffers())
+    return;
+
+  // MFC setup for encoding is rather particular in ordering:
+  //
+  // 1. Format (VIDIOC_S_FMT) set first on OUTPUT and CAPTURE queues.
+  // 2. VIDIOC_REQBUFS, VIDIOC_QBUF, and VIDIOC_STREAMON on CAPTURE queue.
+  // 3. VIDIOC_REQBUFS (and later VIDIOC_QBUF and VIDIOC_STREAMON) on OUTPUT
+  //    queue.
+  //
+  // Unfortunately, we cannot do (3) in Initialize() here since we have no
+  // buffers to QBUF in step (2) until the client has provided output buffers
+  // through UseOutputBitstreamBuffer().  So, we just do (1), and the
+  // VIDIOC_REQBUFS part of (2) here.  The rest is done the first time we get
+  // a UseOutputBitstreamBuffer() callback.
+
+  if (!SetMfcFormats())
+    return;
+
+  // VIDIOC_REQBUFS on CAPTURE queue.
+  if (!CreateMfcOutputBuffers())
+    return;
+
+
+  if (!encoder_thread_.Start()) {
+    DLOG(ERROR) << "Initialize(): encoder thread failed to start";
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  RequestEncodingParametersChange(initial_bitrate, kInitialFramerate);
+
+  SetEncoderState(kInitialized);
+
+  child_message_loop_proxy_->PostTask(
+      FROM_HERE, base::Bind(&Client::NotifyInitializeDone, client_));
+
+  child_message_loop_proxy_->PostTask(
+      FROM_HERE,
+      base::Bind(&Client::RequireBitstreamBuffers,
+                 client_,
+                 gsc_input_buffer_map_.size(),
+                 input_allocated_size_,
+                 output_buffer_byte_size_));
+}
+
+void ExynosVideoEncodeAccelerator::Encode(
+    const scoped_refptr<media::VideoFrame>& frame,
+    bool force_keyframe) {
+  DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe;
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+
+  encoder_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&ExynosVideoEncodeAccelerator::EncodeTask,
+                 base::Unretained(this),
+                 frame,
+                 force_keyframe));
+}
+
+void ExynosVideoEncodeAccelerator::UseOutputBitstreamBuffer(
+    const media::BitstreamBuffer& buffer) {
+  DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id();
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+
+  if (buffer.size() < output_buffer_byte_size_) {
+    NOTIFY_ERROR(kInvalidArgumentError);
+    return;
+  }
+
+  scoped_ptr<base::SharedMemory> shm(
+      new base::SharedMemory(buffer.handle(), false));
+  if (!shm->Map(buffer.size())) {
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  scoped_ptr<BitstreamBufferRef> buffer_ref(
+      new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size()));
+  encoder_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
+                 base::Unretained(this),
+                 base::Passed(&buffer_ref)));
+}
+
+void ExynosVideoEncodeAccelerator::RequestEncodingParametersChange(
+    uint32 bitrate,
+    uint32 framerate) {
+  DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
+           << ", framerate=" << framerate;
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+
+  encoder_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask,
+          base::Unretained(this),
+          bitrate,
+          framerate));
+}
+
+void ExynosVideoEncodeAccelerator::Destroy() {
+  DVLOG(3) << "Destroy()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+
+  // We're destroying; cancel all callbacks.
+  client_ptr_factory_.InvalidateWeakPtrs();
+
+  // If the encoder thread is running, destroy using posted task.
+  if (encoder_thread_.IsRunning()) {
+    encoder_thread_.message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&ExynosVideoEncodeAccelerator::DestroyTask,
+                   base::Unretained(this)));
+    // DestroyTask() will put the encoder into kError state and cause all tasks
+    // to no-op.
+    encoder_thread_.Stop();
+  } else {
+    // Otherwise, call the destroy task directly.
+    DestroyTask();
+  }
+
+  // Set to kError state just in case.
+  SetEncoderState(kError);
+
+  delete this;
+}
+
+// static
+std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+ExynosVideoEncodeAccelerator::GetSupportedProfiles() {
+  std::vector<SupportedProfile> profiles(1);
+  SupportedProfile& profile = profiles[0];
+  profile.profile = media::H264PROFILE_MAIN;
+  profile.max_resolution.SetSize(1920, 1088);
+  profile.max_framerate.numerator = 30;
+  profile.max_framerate.denominator = 1;
+  return profiles;
+}
+
+void ExynosVideoEncodeAccelerator::EncodeTask(
+    const scoped_refptr<media::VideoFrame>& frame, bool force_keyframe) {
+  DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe;
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+  DCHECK_NE(encoder_state_, kUninitialized);
+
+  if (encoder_state_ == kError) {
+    DVLOG(2) << "EncodeTask(): early out: kError state";
+    return;
+  }
+
+  encoder_input_queue_.push_back(frame);
+  EnqueueGsc();
+
+  if (force_keyframe) {
+    // TODO(sheu): this presently makes for slightly imprecise encoding
+    // parameters updates.  To precisely align the parameter updates with the
+    // incoming input frame, we should track the parameters through the GSC
+    // pipeline and only apply them when the MFC input is about to be queued.
+    struct v4l2_ext_control ctrls[1];
+    struct v4l2_ext_controls control;
+    memset(&ctrls, 0, sizeof(ctrls));
+    memset(&control, 0, sizeof(control));
+    ctrls[0].id    = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE;
+    ctrls[0].value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME;
+    control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
+    control.count = 1;
+    control.controls = ctrls;
+    IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
+  }
+}
+
+void ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
+    scoped_ptr<BitstreamBufferRef> buffer_ref) {
+  DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id;
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+
+  encoder_output_queue_.push_back(
+      linked_ptr<BitstreamBufferRef>(buffer_ref.release()));
+  EnqueueMfc();
+
+  if (encoder_state_ == kInitialized) {
+    // Finish setting up our MFC OUTPUT queue.  See: Initialize().
+    // VIDIOC_REQBUFS on OUTPUT queue.
+    if (!CreateMfcInputBuffers())
+      return;
+    if (!StartDevicePoll())
+      return;
+    encoder_state_ = kEncoding;
+  }
+}
+
+void ExynosVideoEncodeAccelerator::DestroyTask() {
+  DVLOG(3) << "DestroyTask()";
+
+  // DestroyTask() should run regardless of encoder_state_.
+
+  // Stop streaming and the device_poll_thread_.
+  StopDevicePoll();
+
+  // Set our state to kError, and early-out all tasks.
+  encoder_state_ = kError;
+}
+
+void ExynosVideoEncodeAccelerator::ServiceDeviceTask() {
+  DVLOG(3) << "ServiceDeviceTask()";
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+  DCHECK_NE(encoder_state_, kUninitialized);
+  DCHECK_NE(encoder_state_, kInitialized);
+
+  if (encoder_state_ == kError) {
+    DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
+    return;
+  }
+
+  DequeueGsc();
+  DequeueMfc();
+  EnqueueGsc();
+  EnqueueMfc();
+
+  // Clear the interrupt fd.
+  if (!ClearDevicePollInterrupt())
+    return;
+
+  unsigned int poll_fds = 0;
+  // Add GSC fd, if we should poll on it.
+  // GSC has to wait until both input and output buffers are queued.
+  if (gsc_input_buffer_queued_count_ > 0 && gsc_output_buffer_queued_count_ > 0)
+    poll_fds |= kPollGsc;
+  // Add MFC fd, if we should poll on it.
+  // MFC can be polled as soon as either input or output buffers are queued.
+  if (mfc_input_buffer_queued_count_ + mfc_output_buffer_queued_count_ > 0)
+    poll_fds |= kPollMfc;
+
+  // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
+  // so either:
+  // * device_poll_thread_ is running normally
+  // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
+  //   in which case we're in kError state, and we should have early-outed
+  //   already.
+  DCHECK(device_poll_thread_.message_loop());
+  // Queue the DevicePollTask() now.
+  device_poll_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
+                 base::Unretained(this),
+                 poll_fds));
+
+  DVLOG(2) << "ServiceDeviceTask(): buffer counts: ENC["
+           << encoder_input_queue_.size() << "] => GSC["
+           << gsc_free_input_buffers_.size() << "+"
+           << gsc_input_buffer_queued_count_ << "/"
+           << gsc_input_buffer_map_.size() << "->"
+           << gsc_free_output_buffers_.size() << "+"
+           << gsc_output_buffer_queued_count_ << "/"
+           << gsc_output_buffer_map_.size() << "] => "
+           << mfc_ready_input_buffers_.size() << " => MFC["
+           << mfc_free_input_buffers_.size() << "+"
+           << mfc_input_buffer_queued_count_ << "/"
+           << mfc_input_buffer_map_.size() << "->"
+           << mfc_free_output_buffers_.size() << "+"
+           << mfc_output_buffer_queued_count_ << "/"
+           << mfc_output_buffer_map_.size() << "] => OUT["
+           << encoder_output_queue_.size() << "]";
+}
+
+void ExynosVideoEncodeAccelerator::EnqueueGsc() {
+  DVLOG(3) << "EnqueueGsc()";
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+
+  const int old_gsc_inputs_queued = gsc_input_buffer_queued_count_;
+  while (!encoder_input_queue_.empty() && !gsc_free_input_buffers_.empty()) {
+    if (!EnqueueGscInputRecord())
+      return;
+  }
+  if (old_gsc_inputs_queued == 0 && gsc_input_buffer_queued_count_ != 0) {
+    // We started up a previously empty queue.
+    // Queue state changed; signal interrupt.
+    if (!SetDevicePollInterrupt())
+      return;
+    // Start VIDIOC_STREAMON if we haven't yet.
+    if (!gsc_input_streamon_) {
+      __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+      IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_STREAMON, &type);
+      gsc_input_streamon_ = true;
+    }
+  }
+
+  // Enqueue a GSC output, only if we need one.  GSC output buffers write
+  // directly to MFC input buffers, so we'll have to check for free MFC input
+  // buffers as well.
+  // GSC is liable to race conditions if more than one output buffer is
+  // simultaneously enqueued, so enqueue just one.
+  if (gsc_input_buffer_queued_count_ != 0 &&
+      gsc_output_buffer_queued_count_ == 0 &&
+      !gsc_free_output_buffers_.empty() && !mfc_free_input_buffers_.empty()) {
+    const int old_gsc_outputs_queued = gsc_output_buffer_queued_count_;
+    if (!EnqueueGscOutputRecord())
+      return;
+    if (old_gsc_outputs_queued == 0 && gsc_output_buffer_queued_count_ != 0) {
+      // We just started up a previously empty queue.
+      // Queue state changed; signal interrupt.
+      if (!SetDevicePollInterrupt())
+        return;
+      // Start VIDIOC_STREAMON if we haven't yet.
+      if (!gsc_output_streamon_) {
+        __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+        IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_STREAMON, &type);
+        gsc_output_streamon_ = true;
+      }
+    }
+  }
+  DCHECK_LE(gsc_output_buffer_queued_count_, 1);
+}
+
+void ExynosVideoEncodeAccelerator::DequeueGsc() {
+  DVLOG(3) << "DequeueGsc()";
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+
+  // Dequeue completed GSC input (VIDEO_OUTPUT) buffers, and recycle to the free
+  // list.
+  struct v4l2_buffer dqbuf;
+  struct v4l2_plane planes[3];
+  while (gsc_input_buffer_queued_count_ > 0) {
+    DCHECK(gsc_input_streamon_);
+    memset(&dqbuf, 0, sizeof(dqbuf));
+    memset(&planes, 0, sizeof(planes));
+    dqbuf.type     = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    dqbuf.memory   = V4L2_MEMORY_USERPTR;
+    dqbuf.m.planes = planes;
+    dqbuf.length   = arraysize(planes);
+    if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
+      if (errno == EAGAIN) {
+        // EAGAIN if we're just out of buffers to dequeue.
+        break;
+      }
+      DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
+      NOTIFY_ERROR(kPlatformFailureError);
+      return;
+    }
+    GscInputRecord& input_record = gsc_input_buffer_map_[dqbuf.index];
+    DCHECK(input_record.at_device);
+    DCHECK(input_record.frame.get());
+    input_record.at_device = false;
+    input_record.frame = NULL;
+    gsc_free_input_buffers_.push_back(dqbuf.index);
+    gsc_input_buffer_queued_count_--;
+  }
+
+  // Dequeue completed GSC output (VIDEO_CAPTURE) buffers, and recycle to the
+  // free list.  Queue the corresponding MFC buffer to the GSC->MFC holding
+  // queue.
+  while (gsc_output_buffer_queued_count_ > 0) {
+    DCHECK(gsc_output_streamon_);
+    memset(&dqbuf, 0, sizeof(dqbuf));
+    memset(&planes, 0, sizeof(planes));
+    dqbuf.type     = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    dqbuf.memory   = V4L2_MEMORY_DMABUF;
+    dqbuf.m.planes = planes;
+    dqbuf.length   = 2;
+    if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
+      if (errno == EAGAIN) {
+        // EAGAIN if we're just out of buffers to dequeue.
+        break;
+      }
+      DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
+      NOTIFY_ERROR(kPlatformFailureError);
+      return;
+    }
+    GscOutputRecord& output_record = gsc_output_buffer_map_[dqbuf.index];
+    DCHECK(output_record.at_device);
+    DCHECK(output_record.mfc_input != -1);
+    mfc_ready_input_buffers_.push_back(output_record.mfc_input);
+    output_record.at_device = false;
+    output_record.mfc_input = -1;
+    gsc_free_output_buffers_.push_back(dqbuf.index);
+    gsc_output_buffer_queued_count_--;
+  }
+}
+void ExynosVideoEncodeAccelerator::EnqueueMfc() {
+  DVLOG(3) << "EnqueueMfc()";
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+
+  // Enqueue all the MFC inputs we can.
+  const int old_mfc_inputs_queued = mfc_input_buffer_queued_count_;
+  while (!mfc_ready_input_buffers_.empty()) {
+    if (!EnqueueMfcInputRecord())
+      return;
+  }
+  if (old_mfc_inputs_queued == 0 && mfc_input_buffer_queued_count_ != 0) {
+    // We just started up a previously empty queue.
+    // Queue state changed; signal interrupt.
+    if (!SetDevicePollInterrupt())
+      return;
+    // Start VIDIOC_STREAMON if we haven't yet.
+    if (!mfc_input_streamon_) {
+      __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+      IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_STREAMON, &type);
+      mfc_input_streamon_ = true;
+    }
+  }
+
+  // Enqueue all the MFC outputs we can.
+  const int old_mfc_outputs_queued = mfc_output_buffer_queued_count_;
+  while (!mfc_free_output_buffers_.empty() && !encoder_output_queue_.empty()) {
+    if (!EnqueueMfcOutputRecord())
+      return;
+  }
+  if (old_mfc_outputs_queued == 0 && mfc_output_buffer_queued_count_ != 0) {
+    // We just started up a previously empty queue.
+    // Queue state changed; signal interrupt.
+    if (!SetDevicePollInterrupt())
+      return;
+    // Start VIDIOC_STREAMON if we haven't yet.
+    if (!mfc_output_streamon_) {
+      __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+      IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_STREAMON, &type);
+      mfc_output_streamon_ = true;
+    }
+  }
+}
+
+void ExynosVideoEncodeAccelerator::DequeueMfc() {
+  DVLOG(3) << "DequeueMfc()";
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+
+  // Dequeue completed MFC input (VIDEO_OUTPUT) buffers, and recycle to the free
+  // list.
+  struct v4l2_buffer dqbuf;
+  struct v4l2_plane planes[2];
+  while (mfc_input_buffer_queued_count_ > 0) {
+    DCHECK(mfc_input_streamon_);
+    memset(&dqbuf, 0, sizeof(dqbuf));
+    memset(&planes, 0, sizeof(planes));
+    dqbuf.type     = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    dqbuf.memory   = V4L2_MEMORY_MMAP;
+    dqbuf.m.planes = planes;
+    dqbuf.length   = 2;
+    if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
+      if (errno == EAGAIN) {
+        // EAGAIN if we're just out of buffers to dequeue.
+        break;
+      }
+      DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
+      NOTIFY_ERROR(kPlatformFailureError);
+      return;
+    }
+    MfcInputRecord& input_record = mfc_input_buffer_map_[dqbuf.index];
+    DCHECK(input_record.at_device);
+    input_record.at_device = false;
+    mfc_free_input_buffers_.push_back(dqbuf.index);
+    mfc_input_buffer_queued_count_--;
+  }
+
+  // Dequeue completed MFC output (VIDEO_CAPTURE) buffers, and recycle to the
+  // free list.  Notify the client that an output buffer is complete.
+  while (mfc_output_buffer_queued_count_ > 0) {
+    DCHECK(mfc_output_streamon_);
+    memset(&dqbuf, 0, sizeof(dqbuf));
+    memset(planes, 0, sizeof(planes));
+    dqbuf.type     = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    dqbuf.memory   = V4L2_MEMORY_USERPTR;
+    dqbuf.m.planes = planes;
+    dqbuf.length   = 1;
+    if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
+      if (errno == EAGAIN) {
+        // EAGAIN if we're just out of buffers to dequeue.
+        break;
+      }
+      DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
+      NOTIFY_ERROR(kPlatformFailureError);
+      return;
+    }
+    const bool key_frame = ((dqbuf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0);
+    const size_t output_size = dqbuf.m.planes[0].bytesused;
+    MfcOutputRecord& output_record = mfc_output_buffer_map_[dqbuf.index];
+    DCHECK(output_record.at_device);
+    DCHECK(output_record.buffer_ref.get());
+    uint8* data =
+        reinterpret_cast<uint8*>(output_record.buffer_ref->shm->memory());
+    if (stream_header_size_ == 0) {
+      // Assume that the first buffer dequeued is the stream header.
+      stream_header_size_ = output_size;
+      stream_header_.reset(new uint8[stream_header_size_]);
+      memcpy(stream_header_.get(), data, stream_header_size_);
+    }
+    if (key_frame &&
+        output_buffer_byte_size_ - stream_header_size_ >= output_size) {
+      // Insert stream header before every keyframe.
+      memmove(data + stream_header_size_, data, output_size);
+      memcpy(data, stream_header_.get(), stream_header_size_);
+    }
+    DVLOG(3) << "DequeueMfc(): returning "
+                "bitstream_buffer_id=" << output_record.buffer_ref->id
+             << ", key_frame=" << key_frame;
+    child_message_loop_proxy_->PostTask(
+        FROM_HERE,
+        base::Bind(&Client::BitstreamBufferReady,
+                   client_,
+                   output_record.buffer_ref->id,
+                   dqbuf.m.planes[0].bytesused,
+                   key_frame));
+    output_record.at_device = false;
+    output_record.buffer_ref.reset();
+    mfc_free_output_buffers_.push_back(dqbuf.index);
+    mfc_output_buffer_queued_count_--;
+  }
+}
+
+bool ExynosVideoEncodeAccelerator::EnqueueGscInputRecord() {
+  DVLOG(3) << "EnqueueGscInputRecord()";
+  DCHECK(!encoder_input_queue_.empty());
+  DCHECK(!gsc_free_input_buffers_.empty());
+
+  // Enqueue a GSC input (VIDEO_OUTPUT) buffer for an input video frame
+  scoped_refptr<media::VideoFrame> frame = encoder_input_queue_.front();
+  const int gsc_buffer = gsc_free_input_buffers_.back();
+  GscInputRecord& input_record = gsc_input_buffer_map_[gsc_buffer];
+  DCHECK(!input_record.at_device);
+  DCHECK(!input_record.frame.get());
+  struct v4l2_buffer qbuf;
+  struct v4l2_plane qbuf_planes[3];
+  memset(&qbuf, 0, sizeof(qbuf));
+  memset(qbuf_planes, 0, sizeof(qbuf_planes));
+  qbuf.index    = gsc_buffer;
+  qbuf.type     = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  qbuf.memory   = V4L2_MEMORY_USERPTR;
+  qbuf.m.planes = qbuf_planes;
+  switch (input_format_fourcc_) {
+    case V4L2_PIX_FMT_RGB32: {
+      qbuf.m.planes[0].bytesused = input_allocated_size_.GetArea() * 4;
+      qbuf.m.planes[0].length    = input_allocated_size_.GetArea() * 4;
+      qbuf.m.planes[0].m.userptr = reinterpret_cast<unsigned long>(
+          frame->data(media::VideoFrame::kRGBPlane));
+      qbuf.length = 1;
+      break;
+    }
+    case V4L2_PIX_FMT_YUV420M: {
+      qbuf.m.planes[0].bytesused = input_allocated_size_.GetArea();
+      qbuf.m.planes[0].length    = input_allocated_size_.GetArea();
+      qbuf.m.planes[0].m.userptr = reinterpret_cast<unsigned long>(
+          frame->data(media::VideoFrame::kYPlane));
+      qbuf.m.planes[1].bytesused = input_allocated_size_.GetArea() / 4;
+      qbuf.m.planes[1].length    = input_allocated_size_.GetArea() / 4;
+      qbuf.m.planes[1].m.userptr = reinterpret_cast<unsigned long>(
+          frame->data(media::VideoFrame::kUPlane));
+      qbuf.m.planes[2].bytesused = input_allocated_size_.GetArea() / 4;
+      qbuf.m.planes[2].length    = input_allocated_size_.GetArea() / 4;
+      qbuf.m.planes[2].m.userptr = reinterpret_cast<unsigned long>(
+          frame->data(media::VideoFrame::kVPlane));
+      qbuf.length = 3;
+      break;
+    }
+    default:
+      NOTREACHED();
+      NOTIFY_ERROR(kIllegalStateError);
+      return false;
+  }
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_QBUF, &qbuf);
+  input_record.at_device = true;
+  input_record.frame = frame;
+  encoder_input_queue_.pop_front();
+  gsc_free_input_buffers_.pop_back();
+  gsc_input_buffer_queued_count_++;
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::EnqueueGscOutputRecord() {
+  DVLOG(3) << "EnqueueGscOutputRecord()";
+  DCHECK(!gsc_free_output_buffers_.empty());
+  DCHECK(!mfc_free_input_buffers_.empty());
+
+  // Enqueue a GSC output (VIDEO_CAPTURE) buffer.
+  const int gsc_buffer = gsc_free_output_buffers_.back();
+  const int mfc_buffer = mfc_free_input_buffers_.back();
+  GscOutputRecord& output_record = gsc_output_buffer_map_[gsc_buffer];
+  MfcInputRecord& input_record = mfc_input_buffer_map_[mfc_buffer];
+  DCHECK(!output_record.at_device);
+  DCHECK_EQ(output_record.mfc_input, -1);
+  DCHECK(!input_record.at_device);
+  struct v4l2_buffer qbuf;
+  struct v4l2_plane qbuf_planes[2];
+  memset(&qbuf, 0, sizeof(qbuf));
+  memset(qbuf_planes, 0, sizeof(qbuf_planes));
+  qbuf.index            = gsc_buffer;
+  qbuf.type             = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  qbuf.memory           = V4L2_MEMORY_DMABUF;
+  qbuf.m.planes         = qbuf_planes;
+  qbuf.m.planes[0].m.fd = input_record.fd[0];
+  qbuf.m.planes[1].m.fd = input_record.fd[1];
+  qbuf.length           = 2;
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_QBUF, &qbuf);
+  output_record.at_device = true;
+  output_record.mfc_input = mfc_buffer;
+  mfc_free_input_buffers_.pop_back();
+  gsc_free_output_buffers_.pop_back();
+  gsc_output_buffer_queued_count_++;
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::EnqueueMfcInputRecord() {
+  DVLOG(3) << "EnqueueMfcInputRecord()";
+  DCHECK(!mfc_ready_input_buffers_.empty());
+
+  // Enqueue a MFC input (VIDEO_OUTPUT) buffer.
+  const int mfc_buffer = mfc_ready_input_buffers_.front();
+  MfcInputRecord& input_record = mfc_input_buffer_map_[mfc_buffer];
+  DCHECK(!input_record.at_device);
+  struct v4l2_buffer qbuf;
+  struct v4l2_plane qbuf_planes[2];
+  memset(&qbuf, 0, sizeof(qbuf));
+  memset(qbuf_planes, 0, sizeof(qbuf_planes));
+  qbuf.index     = mfc_buffer;
+  qbuf.type      = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  qbuf.memory    = V4L2_MEMORY_MMAP;
+  qbuf.m.planes  = qbuf_planes;
+  qbuf.length    = 2;
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_QBUF, &qbuf);
+  input_record.at_device = true;
+  mfc_ready_input_buffers_.pop_front();
+  mfc_input_buffer_queued_count_++;
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::EnqueueMfcOutputRecord() {
+  DVLOG(3) << "EnqueueMfcOutputRecord()";
+  DCHECK(!mfc_free_output_buffers_.empty());
+  DCHECK(!encoder_output_queue_.empty());
+
+  // Enqueue a MFC output (VIDEO_CAPTURE) buffer.
+  linked_ptr<BitstreamBufferRef> output_buffer = encoder_output_queue_.back();
+  const int mfc_buffer = mfc_free_output_buffers_.back();
+  MfcOutputRecord& output_record = mfc_output_buffer_map_[mfc_buffer];
+  DCHECK(!output_record.at_device);
+  DCHECK(!output_record.buffer_ref.get());
+  struct v4l2_buffer qbuf;
+  struct v4l2_plane qbuf_planes[1];
+  memset(&qbuf, 0, sizeof(qbuf));
+  memset(qbuf_planes, 0, sizeof(qbuf_planes));
+  qbuf.index                 = mfc_buffer;
+  qbuf.type                  = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  qbuf.memory                = V4L2_MEMORY_USERPTR;
+  qbuf.m.planes              = qbuf_planes;
+  qbuf.m.planes[0].bytesused = output_buffer->size;
+  qbuf.m.planes[0].length    = output_buffer->size;
+  qbuf.m.planes[0].m.userptr =
+      reinterpret_cast<unsigned long>(output_buffer->shm->memory());
+  qbuf.length                = 1;
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_QBUF, &qbuf);
+  output_record.at_device = true;
+  output_record.buffer_ref = output_buffer;
+  encoder_output_queue_.pop_back();
+  mfc_free_output_buffers_.pop_back();
+  mfc_output_buffer_queued_count_++;
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::StartDevicePoll() {
+  DVLOG(3) << "StartDevicePoll()";
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+  DCHECK(!device_poll_thread_.IsRunning());
+
+  // Start up the device poll thread and schedule its first DevicePollTask().
+  if (!device_poll_thread_.Start()) {
+    DLOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
+    NOTIFY_ERROR(kPlatformFailureError);
+    return false;
+  }
+  // Enqueue a poll task with no devices to poll on -- it will wait only on the
+  // interrupt fd.
+  device_poll_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
+                 base::Unretained(this),
+                 0));
+
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::StopDevicePoll() {
+  DVLOG(3) << "StopDevicePoll()";
+
+  // Signal the DevicePollTask() to stop, and stop the device poll thread.
+  if (!SetDevicePollInterrupt())
+    return false;
+  device_poll_thread_.Stop();
+  // Clear the interrupt now, to be sure.
+  if (!ClearDevicePollInterrupt())
+    return false;
+
+  // Stop streaming.
+  if (gsc_input_streamon_) {
+    __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_STREAMOFF, &type);
+  }
+  gsc_input_streamon_ = false;
+  if (gsc_output_streamon_) {
+    __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_STREAMOFF, &type);
+  }
+  gsc_output_streamon_ = false;
+  if (mfc_input_streamon_) {
+    __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+    IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_STREAMOFF, &type);
+  }
+  mfc_input_streamon_ = false;
+  if (mfc_output_streamon_) {
+    __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+    IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_STREAMOFF, &type);
+  }
+  mfc_output_streamon_ = false;
+
+  // Reset all our accounting info.
+  encoder_input_queue_.clear();
+  gsc_free_input_buffers_.clear();
+  for (size_t i = 0; i < gsc_input_buffer_map_.size(); ++i) {
+    GscInputRecord& input_record = gsc_input_buffer_map_[i];
+    input_record.at_device = false;
+    input_record.frame = NULL;
+    gsc_free_input_buffers_.push_back(i);
+  }
+  gsc_input_buffer_queued_count_ = 0;
+  gsc_free_output_buffers_.clear();
+  for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i) {
+    GscOutputRecord& output_record = gsc_output_buffer_map_[i];
+    output_record.at_device = false;
+    output_record.mfc_input = -1;
+    gsc_free_output_buffers_.push_back(i);
+  }
+  gsc_output_buffer_queued_count_ = 0;
+  mfc_ready_input_buffers_.clear();
+  mfc_free_input_buffers_.clear();
+  for (size_t i = 0; i < mfc_input_buffer_map_.size(); ++i) {
+    MfcInputRecord& input_record = mfc_input_buffer_map_[i];
+    input_record.at_device = false;
+    mfc_free_input_buffers_.push_back(i);
+  }
+  mfc_input_buffer_queued_count_ = 0;
+  mfc_free_output_buffers_.clear();
+  for (size_t i = 0; i < mfc_output_buffer_map_.size(); ++i) {
+    MfcOutputRecord& output_record = mfc_output_buffer_map_[i];
+    output_record.at_device = false;
+    output_record.buffer_ref.reset();
+    mfc_free_output_buffers_.push_back(i);
+  }
+  mfc_output_buffer_queued_count_ = 0;
+  encoder_output_queue_.clear();
+
+  DVLOG(3) << "StopDevicePoll(): device poll stopped";
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::SetDevicePollInterrupt() {
+  DVLOG(3) << "SetDevicePollInterrupt()";
+
+  // We might get called here if we fail during initialization, in which case we
+  // don't have a file descriptor.
+  if (device_poll_interrupt_fd_ == -1)
+    return true;
+
+  const uint64 buf = 1;
+  if (HANDLE_EINTR((write(device_poll_interrupt_fd_, &buf, sizeof(buf)))) <
+      static_cast<ssize_t>(sizeof(buf))) {
+    DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed";
+    NOTIFY_ERROR(kPlatformFailureError);
+    return false;
+  }
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::ClearDevicePollInterrupt() {
+  DVLOG(3) << "ClearDevicePollInterrupt()";
+
+  // We might get called here if we fail during initialization, in which case we
+  // don't have a file descriptor.
+  if (device_poll_interrupt_fd_ == -1)
+    return true;
+
+  uint64 buf;
+  if (HANDLE_EINTR(read(device_poll_interrupt_fd_, &buf, sizeof(buf))) <
+      static_cast<ssize_t>(sizeof(buf))) {
+    if (errno == EAGAIN) {
+      // No interrupt flag set, and we're reading nonblocking.  Not an error.
+      return true;
+    } else {
+      DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
+      NOTIFY_ERROR(kPlatformFailureError);
+      return false;
+    }
+  }
+  return true;
+}
+
+void ExynosVideoEncodeAccelerator::DevicePollTask(unsigned int poll_fds) {
+  DVLOG(3) << "DevicePollTask()";
+  DCHECK_EQ(device_poll_thread_.message_loop(), base::MessageLoop::current());
+  DCHECK_NE(device_poll_interrupt_fd_, -1);
+
+  // This routine just polls the set of device fds, and schedules a
+  // ServiceDeviceTask() on encoder_thread_ when processing needs to occur.
+  // Other threads may notify this task to return early by writing to
+  // device_poll_interrupt_fd_.
+  struct pollfd pollfds[3];
+  nfds_t nfds;
+
+  // Add device_poll_interrupt_fd_;
+  pollfds[0].fd = device_poll_interrupt_fd_;
+  pollfds[0].events = POLLIN | POLLERR;
+  nfds = 1;
+
+  // Add GSC fd, if we should poll on it.
+  // GSC has to wait until both input and output buffers are queued.
+  if (poll_fds & kPollGsc) {
+    DVLOG(3) << "DevicePollTask(): adding GSC to poll() set";
+    pollfds[nfds].fd = gsc_fd_;
+    pollfds[nfds].events = POLLIN | POLLOUT | POLLERR;
+    nfds++;
+  }
+  if (poll_fds & kPollMfc) {
+    DVLOG(3) << "DevicePollTask(): adding MFC to poll() set";
+    pollfds[nfds].fd = mfc_fd_;
+    pollfds[nfds].events = POLLIN | POLLOUT | POLLERR;
+    nfds++;
+  }
+
+  // Poll it!
+  if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
+    DPLOG(ERROR) << "DevicePollTask(): poll() failed";
+    NOTIFY_ERROR(kPlatformFailureError);
+    return;
+  }
+
+  // All processing should happen on ServiceDeviceTask(), since we shouldn't
+  // touch encoder state from this thread.
+  encoder_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&ExynosVideoEncodeAccelerator::ServiceDeviceTask,
+                 base::Unretained(this)));
+}
+
+void ExynosVideoEncodeAccelerator::NotifyError(Error error) {
+  DVLOG(1) << "NotifyError(): error=" << error;
+
+  if (!child_message_loop_proxy_->BelongsToCurrentThread()) {
+    child_message_loop_proxy_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &ExynosVideoEncodeAccelerator::NotifyError, weak_this_, error));
+    return;
+  }
+
+  if (client_) {
+    client_->NotifyError(error);
+    client_ptr_factory_.InvalidateWeakPtrs();
+  }
+}
+
+void ExynosVideoEncodeAccelerator::SetEncoderState(State state) {
+  DVLOG(3) << "SetEncoderState(): state=" << state;
+
+  // We can touch encoder_state_ only if this is the encoder thread or the
+  // encoder thread isn't running.
+  if (encoder_thread_.message_loop() != NULL &&
+      encoder_thread_.message_loop() != base::MessageLoop::current()) {
+    encoder_thread_.message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&ExynosVideoEncodeAccelerator::SetEncoderState,
+                   base::Unretained(this),
+                   state));
+  } else {
+    encoder_state_ = state;
+  }
+}
+
+void ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
+    uint32 bitrate,
+    uint32 framerate) {
+  DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate
+           << ", framerate=" << framerate;
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+
+  if (bitrate < 1)
+    bitrate = 1;
+  if (framerate < 1)
+    framerate = 1;
+
+  struct v4l2_ext_control ctrls[1];
+  struct v4l2_ext_controls control;
+  memset(&ctrls, 0, sizeof(ctrls));
+  memset(&control, 0, sizeof(control));
+  ctrls[0].id    = V4L2_CID_MPEG_VIDEO_BITRATE;
+  ctrls[0].value = bitrate;
+  control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
+  control.count = arraysize(ctrls);
+  control.controls = ctrls;
+  IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
+
+  struct v4l2_streamparm parms;
+  memset(&parms, 0, sizeof(parms));
+  parms.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  // Note that we are provided "frames per second" but V4L2 expects "time per
+  // frame"; hence we provide the reciprocal of the framerate here.
+  parms.parm.output.timeperframe.numerator = 1;
+  parms.parm.output.timeperframe.denominator = framerate;
+  IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_S_PARM, &parms);
+}
+
+bool ExynosVideoEncodeAccelerator::CreateGscInputBuffers() {
+  DVLOG(3) << "CreateGscInputBuffers()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK_EQ(encoder_state_, kUninitialized);
+  DCHECK(!gsc_input_streamon_);
+
+  struct v4l2_control control;
+  memset(&control, 0, sizeof(control));
+  control.id    = V4L2_CID_ROTATE;
+  control.value = 0;
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
+
+  // HFLIP actually seems to control vertical mirroring for GSC, and vice-versa.
+  memset(&control, 0, sizeof(control));
+  control.id    = V4L2_CID_HFLIP;
+  control.value = 0;
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
+
+  memset(&control, 0, sizeof(control));
+  control.id    = V4L2_CID_VFLIP;
+  control.value = 0;
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
+
+  memset(&control, 0, sizeof(control));
+  control.id    = V4L2_CID_ALPHA_COMPONENT;
+  control.value = 255;
+  if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_S_CTRL, &control)) != 0) {
+    // TODO(posciak): This is a  temporary hack and should be removed when
+    // all platforms migrate to kernel >=3.8.
+    memset(&control, 0, sizeof(control));
+    control.id    = V4L2_CID_GLOBAL_ALPHA;
+    control.value = 255;
+    IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
+  }
+
+  struct v4l2_format format;
+  memset(&format, 0, sizeof(format));
+  format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  format.fmt.pix_mp.width  = input_allocated_size_.width();
+  format.fmt.pix_mp.height = input_allocated_size_.height();
+  format.fmt.pix_mp.pixelformat = input_format_fourcc_;
+  switch (input_format_fourcc_) {
+    case V4L2_PIX_FMT_RGB32:
+      format.fmt.pix_mp.plane_fmt[0].sizeimage =
+          input_allocated_size_.GetArea() * 4;
+      format.fmt.pix_mp.plane_fmt[0].bytesperline =
+          input_allocated_size_.width() * 4;
+      format.fmt.pix_mp.num_planes = 1;
+      break;
+    case V4L2_PIX_FMT_YUV420M:
+      format.fmt.pix_mp.plane_fmt[0].sizeimage =
+          input_allocated_size_.GetArea();
+      format.fmt.pix_mp.plane_fmt[0].bytesperline =
+          input_allocated_size_.width();
+      format.fmt.pix_mp.plane_fmt[1].sizeimage =
+          input_allocated_size_.GetArea() / 4;
+      format.fmt.pix_mp.plane_fmt[1].bytesperline =
+          input_allocated_size_.width() / 2;
+      format.fmt.pix_mp.plane_fmt[2].sizeimage =
+          input_allocated_size_.GetArea() / 4;
+      format.fmt.pix_mp.plane_fmt[2].bytesperline =
+          input_allocated_size_.width() / 2;
+      format.fmt.pix_mp.num_planes = 3;
+      break;
+    default:
+      NOTREACHED();
+      NOTIFY_ERROR(kIllegalStateError);
+      return false;
+  }
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_FMT, &format);
+
+  struct v4l2_crop crop;
+  memset(&crop, 0, sizeof(crop));
+  crop.type     = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  crop.c.left   = 0;
+  crop.c.top    = 0;
+  crop.c.width  = input_visible_size_.width();
+  crop.c.height = input_visible_size_.height();
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CROP, &crop);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count  = kGscInputBufferCount;
+  reqbufs.type   = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_USERPTR;
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
+
+  DCHECK(gsc_input_buffer_map_.empty());
+  gsc_input_buffer_map_.resize(reqbufs.count);
+  for (size_t i = 0; i < gsc_input_buffer_map_.size(); ++i)
+    gsc_free_input_buffers_.push_back(i);
+
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::CreateGscOutputBuffers() {
+  DVLOG(3) << "CreateGscOutputBuffers()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK_EQ(encoder_state_, kUninitialized);
+  DCHECK(!gsc_output_streamon_);
+
+  struct v4l2_format format;
+  memset(&format, 0, sizeof(format));
+  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  format.fmt.pix_mp.width = converted_allocated_size_.width();
+  format.fmt.pix_mp.height = converted_allocated_size_.height();
+  format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
+  format.fmt.pix_mp.plane_fmt[0].sizeimage =
+      converted_allocated_size_.GetArea();
+  format.fmt.pix_mp.plane_fmt[1].sizeimage =
+      converted_allocated_size_.GetArea() / 2;
+  format.fmt.pix_mp.plane_fmt[0].bytesperline =
+      converted_allocated_size_.width();
+  format.fmt.pix_mp.plane_fmt[1].bytesperline =
+      converted_allocated_size_.width();
+  format.fmt.pix_mp.num_planes = 2;
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_FMT, &format);
+
+  struct v4l2_crop crop;
+  memset(&crop, 0, sizeof(crop));
+  crop.type     = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  crop.c.left   = 0;
+  crop.c.top    = 0;
+  crop.c.width  = converted_visible_size_.width();
+  crop.c.height = converted_visible_size_.height();
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CROP, &crop);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count  = kGscOutputBufferCount;
+  reqbufs.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_DMABUF;
+  IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
+
+  DCHECK(gsc_output_buffer_map_.empty());
+  gsc_output_buffer_map_.resize(reqbufs.count);
+  for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i)
+    gsc_free_output_buffers_.push_back(i);
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::SetMfcFormats() {
+  DVLOG(3) << "SetMfcFormats()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(!mfc_input_streamon_);
+  DCHECK(!mfc_output_streamon_);
+
+  // VIDIOC_S_FMT on OUTPUT queue.
+  struct v4l2_format format;
+  memset(&format, 0, sizeof(format));
+  format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  format.fmt.pix_mp.width = input_allocated_size_.width();
+  format.fmt.pix_mp.height = input_allocated_size_.height();
+  format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
+  format.fmt.pix_mp.num_planes = 2;
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_FMT, &format);
+  // We read direct from GSC, so we rely on the HW not changing our set
+  // size/stride.
+  DCHECK_EQ(format.fmt.pix_mp.plane_fmt[0].sizeimage,
+            static_cast<__u32>(input_allocated_size_.GetArea()));
+  DCHECK_EQ(format.fmt.pix_mp.plane_fmt[0].bytesperline,
+            static_cast<__u32>(input_allocated_size_.width()));
+  DCHECK_EQ(format.fmt.pix_mp.plane_fmt[1].sizeimage,
+            static_cast<__u32>(input_allocated_size_.GetArea() / 2));
+  DCHECK_EQ(format.fmt.pix_mp.plane_fmt[1].bytesperline,
+            static_cast<__u32>(input_allocated_size_.width()));
+
+  struct v4l2_crop crop;
+  memset(&crop, 0, sizeof(crop));
+  crop.type     = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+  crop.c.left   = 0;
+  crop.c.top    = 0;
+  crop.c.width  = input_visible_size_.width();
+  crop.c.height = input_visible_size_.height();
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_CROP, &crop);
+
+  // VIDIOC_S_FMT on CAPTURE queue.
+  output_buffer_byte_size_ = kMfcOutputBufferSize;
+  memset(&format, 0, sizeof(format));
+  format.type                   = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  format.fmt.pix_mp.width       = output_visible_size_.width();
+  format.fmt.pix_mp.height      = output_visible_size_.height();
+  format.fmt.pix_mp.pixelformat = output_format_fourcc_;
+  format.fmt.pix_mp.plane_fmt[0].sizeimage = output_buffer_byte_size_;
+  format.fmt.pix_mp.num_planes  = 1;
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_FMT, &format);
+
+  struct v4l2_ext_control ctrls[6];
+  struct v4l2_ext_controls control;
+  memset(&ctrls, 0, sizeof(ctrls));
+  memset(&control, 0, sizeof(control));
+  // No B-frames, for lowest decoding latency.
+  ctrls[0].id    = V4L2_CID_MPEG_VIDEO_B_FRAMES;
+  ctrls[0].value = 0;
+  // Enable variable bitrate control.
+  ctrls[1].id    = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
+  ctrls[1].value = 1;
+  // Enable "loose" variable bitrate.
+  ctrls[2].id    = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF;
+  ctrls[2].value = 10;
+  // Force bitrate control to average over a GOP (for tight bitrate tolerance).
+  ctrls[3].id    = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT;
+  ctrls[3].value = 1;
+  // Quantization parameter maximum value (for variable bitrate control).
+  ctrls[4].id    = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
+  ctrls[4].value = 51;
+  // Separate stream header so we can cache it and insert into the stream.
+  ctrls[5].id    = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
+  ctrls[5].value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE;
+  control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
+  control.count = arraysize(ctrls);
+  control.controls = ctrls;
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
+
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::CreateMfcInputBuffers() {
+  DVLOG(3) << "CreateMfcInputBuffers()";
+  // This function runs on encoder_thread_ after output buffers have been
+  // provided by the client.
+  DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
+  DCHECK(!mfc_input_streamon_);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = 1;  // Driver will allocate the appropriate number of buffers.
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_MMAP;
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
+
+  DCHECK(mfc_input_buffer_map_.empty());
+  mfc_input_buffer_map_.resize(reqbufs.count);
+  for (size_t i = 0; i < mfc_input_buffer_map_.size(); ++i) {
+    MfcInputRecord& input_record = mfc_input_buffer_map_[i];
+    for (int j = 0; j < 2; ++j) {
+      // Export the DMABUF fd so GSC can write to it.
+      struct v4l2_exportbuffer expbuf;
+      memset(&expbuf, 0, sizeof(expbuf));
+      expbuf.type  = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+      expbuf.index = i;
+      expbuf.plane = j;
+      expbuf.flags = O_CLOEXEC;
+      IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_EXPBUF, &expbuf);
+      input_record.fd[j] = expbuf.fd;
+    }
+    mfc_free_input_buffers_.push_back(i);
+  }
+
+  return true;
+}
+
+bool ExynosVideoEncodeAccelerator::CreateMfcOutputBuffers() {
+  DVLOG(3) << "CreateMfcOutputBuffers()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(!mfc_output_streamon_);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = kMfcOutputBufferCount;
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_USERPTR;
+  IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
+
+  DCHECK(mfc_output_buffer_map_.empty());
+  mfc_output_buffer_map_.resize(reqbufs.count);
+  for (size_t i = 0; i < mfc_output_buffer_map_.size(); ++i)
+    mfc_free_output_buffers_.push_back(i);
+
+  return true;
+}
+
+void ExynosVideoEncodeAccelerator::DestroyGscInputBuffers() {
+  DVLOG(3) << "DestroyGscInputBuffers()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(!gsc_input_streamon_);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = 0;
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_USERPTR;
+  if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
+    DPLOG(ERROR) << "DestroyGscInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
+
+  gsc_input_buffer_map_.clear();
+  gsc_free_input_buffers_.clear();
+}
+
+void ExynosVideoEncodeAccelerator::DestroyGscOutputBuffers() {
+  DVLOG(3) << "DestroyGscOutputBuffers()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(!gsc_output_streamon_);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = 0;
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_DMABUF;
+  if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
+    DPLOG(ERROR) << "DestroyGscOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
+
+  gsc_output_buffer_map_.clear();
+  gsc_free_output_buffers_.clear();
+}
+
+void ExynosVideoEncodeAccelerator::DestroyMfcInputBuffers() {
+  DVLOG(3) << "DestroyMfcInputBuffers()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(!mfc_input_streamon_);
+
+  for (size_t buf = 0; buf < mfc_input_buffer_map_.size(); ++buf) {
+    MfcInputRecord& input_record = mfc_input_buffer_map_[buf];
+
+    for (size_t plane = 0; plane < arraysize(input_record.fd); ++plane)
+      HANDLE_EINTR(close(mfc_input_buffer_map_[buf].fd[plane]));
+  }
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = 0;
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_MMAP;
+  if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
+    DPLOG(ERROR) << "DestroyMfcInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
+
+  mfc_input_buffer_map_.clear();
+  mfc_free_input_buffers_.clear();
+}
+
+void ExynosVideoEncodeAccelerator::DestroyMfcOutputBuffers() {
+  DVLOG(3) << "DestroyMfcOutputBuffers()";
+  DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(!mfc_output_streamon_);
+
+  struct v4l2_requestbuffers reqbufs;
+  memset(&reqbufs, 0, sizeof(reqbufs));
+  reqbufs.count = 0;
+  reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+  reqbufs.memory = V4L2_MEMORY_USERPTR;
+  if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
+    DPLOG(ERROR) << "DestroyMfcOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
+
+  mfc_output_buffer_map_.clear();
+  mfc_free_output_buffers_.clear();
+}
+
+}  // namespace content
diff --git a/content/common/gpu/media/exynos_video_encode_accelerator.h b/content/common/gpu/media/exynos_video_encode_accelerator.h
new file mode 100644
index 0000000..5b4102c
--- /dev/null
+++ b/content/common/gpu/media/exynos_video_encode_accelerator.h
@@ -0,0 +1,303 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_
+#define CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_
+
+#include <list>
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
+#include "media/video/video_encode_accelerator.h"
+#include "ui/gfx/size.h"
+
+namespace base {
+
+class MessageLoopProxy;
+
+}  // namespace base
+
+namespace media {
+
+class BitstreamBuffer;
+
+}  // namespace media
+
+namespace content {
+
+// This class handles Exynos video encode acceleration by interfacing with the
+// V4L2 devices exported by the Multi Format Codec and GScaler hardware blocks
+// on the Exynos platform.  The threading model of this class is the same as the
+// ExynosVideoDecodeAccelerator (from which class this was designed).
+class ExynosVideoEncodeAccelerator : public media::VideoEncodeAccelerator {
+ public:
+  explicit ExynosVideoEncodeAccelerator(
+      media::VideoEncodeAccelerator::Client* client);
+  virtual ~ExynosVideoEncodeAccelerator();
+
+  // media::VideoEncodeAccelerator implementation.
+  virtual void Initialize(media::VideoFrame::Format format,
+                          const gfx::Size& input_visible_size,
+                          media::VideoCodecProfile output_profile,
+                          uint32 initial_bitrate) OVERRIDE;
+  virtual void Encode(const scoped_refptr<media::VideoFrame>& frame,
+                      bool force_keyframe) OVERRIDE;
+  virtual void UseOutputBitstreamBuffer(
+      const media::BitstreamBuffer& buffer) OVERRIDE;
+  virtual void RequestEncodingParametersChange(uint32 bitrate,
+                                               uint32 framerate) OVERRIDE;
+  virtual void Destroy() OVERRIDE;
+
+  static std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+      GetSupportedProfiles();
+
+ private:
+  // Auto-destroy reference for BitstreamBuffer, for tracking buffers passed to
+  // this instance.
+  struct BitstreamBufferRef;
+
+  // Record for GSC input buffers.
+  struct GscInputRecord {
+    GscInputRecord();
+    bool at_device;
+    scoped_refptr<media::VideoFrame> frame;
+  };
+
+  // Record for GSC output buffers.
+  struct GscOutputRecord {
+    GscOutputRecord();
+    bool at_device;
+    int mfc_input;
+  };
+
+  // Record for MFC input buffers.
+  struct MfcInputRecord {
+    MfcInputRecord();
+    bool at_device;
+    int fd[2];
+  };
+
+  // Record for MFC output buffers.
+  struct MfcOutputRecord {
+    MfcOutputRecord();
+    bool at_device;
+    linked_ptr<BitstreamBufferRef> buffer_ref;
+  };
+
+  enum {
+    kInitialFramerate = 30,
+    // These are rather subjectively tuned.
+    kGscInputBufferCount = 2,
+    kGscOutputBufferCount = 2,
+    kMfcOutputBufferCount = 2,
+    // MFC hardware does not report required output buffer size correctly.
+    // Use maximum theoretical size to avoid hanging the hardware.
+    kMfcOutputBufferSize = (2 * 1024 * 1024),
+  };
+
+  // Internal state of the encoder.
+  enum State {
+    kUninitialized,  // Initialize() not yet called.
+    kInitialized,    // Initialize() returned true; ready to start encoding.
+    kEncoding,       // Encoding frames.
+    kError,          // Error in encoder state.
+  };
+
+  //
+  // Encoding tasks, to be run on encode_thread_.
+  //
+
+  // Encode a GSC input buffer.
+  void EncodeTask(const scoped_refptr<media::VideoFrame>& frame,
+                  bool force_keyframe);
+
+  // Add a BitstreamBuffer to the queue of buffers ready to be used for encoder
+  // output.
+  void UseOutputBitstreamBufferTask(scoped_ptr<BitstreamBufferRef> buffer_ref);
+
+  // Device destruction task.
+  void DestroyTask();
+
+  // Service I/O on the V4L2 devices.  This task should only be scheduled from
+  // DevicePollTask().
+  void ServiceDeviceTask();
+
+  // Handle the various device queues.
+  void EnqueueGsc();
+  void DequeueGsc();
+  void EnqueueMfc();
+  void DequeueMfc();
+  // Enqueue a buffer on the corresponding queue.  Returns false on fatal error.
+  bool EnqueueGscInputRecord();
+  bool EnqueueGscOutputRecord();
+  bool EnqueueMfcInputRecord();
+  bool EnqueueMfcOutputRecord();
+
+  // Attempt to start/stop device_poll_thread_.
+  bool StartDevicePoll();
+  bool StopDevicePoll();
+  // Set/clear the device poll interrupt (using device_poll_interrupt_fd_).
+  bool SetDevicePollInterrupt();
+  bool ClearDevicePollInterrupt();
+
+  //
+  // Device tasks, to be run on device_poll_thread_.
+  //
+
+  // The device task.
+  void DevicePollTask(unsigned int poll_fds);
+
+  //
+  // Safe from any thread.
+  //
+
+  // Error notification (using PostTask() to child thread, if necessary).
+  void NotifyError(Error error);
+
+  // Set the encoder_thread_ state (using PostTask to encoder thread, if
+  // necessary).
+  void SetEncoderState(State state);
+
+  //
+  // Other utility functions.  Called on encoder_thread_, unless
+  // encoder_thread_ is not yet started, in which case the child thread can call
+  // these (e.g. in Initialize() or Destroy()).
+  //
+
+  // Change the parameters of encoding.
+  void RequestEncodingParametersChangeTask(uint32 bitrate, uint32 framerate);
+
+  // Create the buffers we need.
+  bool CreateGscInputBuffers();
+  bool CreateGscOutputBuffers();
+  bool SetMfcFormats();
+  bool CreateMfcInputBuffers();
+  bool CreateMfcOutputBuffers();
+
+  // Destroy these buffers.
+  void DestroyGscInputBuffers();
+  void DestroyGscOutputBuffers();
+  void DestroyMfcInputBuffers();
+  void DestroyMfcOutputBuffers();
+
+  // Our original calling message loop for the child thread.
+  const scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
+
+  // WeakPtr<> pointing to |this| for use in posting tasks from the encoder or
+  // device worker threads back to the child thread.  Because the worker threads
+  // are members of this class, any task running on those threads is guaranteed
+  // that this object is still alive.  As a result, tasks posted from the child
+  // thread to the encoder or device thread should use base::Unretained(this),
+  // and tasks posted the other way should use |weak_this_|.
+  base::WeakPtrFactory<ExynosVideoEncodeAccelerator> weak_this_ptr_factory_;
+  base::WeakPtr<ExynosVideoEncodeAccelerator> weak_this_;
+
+  // To expose client callbacks from VideoEncodeAccelerator.
+  // NOTE: all calls to these objects *MUST* be executed on
+  // child_message_loop_proxy_.
+  base::WeakPtrFactory<Client> client_ptr_factory_;
+  base::WeakPtr<Client> client_;
+
+  //
+  // Encoder state, owned and operated by encoder_thread_.
+  // Before encoder_thread_ has started, the encoder state is managed by
+  // the child (main) thread.  After encoder_thread_ has started, the encoder
+  // thread should be the only one managing these.
+  //
+
+  // This thread services tasks posted from the VEA API entry points by the
+  // child thread and device service callbacks posted from the device thread.
+  base::Thread encoder_thread_;
+  // Encoder state.
+  State encoder_state_;
+  // The visible/allocated sizes of the input frame.
+  gfx::Size input_visible_size_;
+  gfx::Size input_allocated_size_;
+  // The visible/allocated sizes of the color-converted intermediate frame.
+  gfx::Size converted_visible_size_;
+  gfx::Size converted_allocated_size_;
+  // The logical visible size of the output frame.
+  gfx::Size output_visible_size_;
+  // The required byte size of output BitstreamBuffers.
+  size_t output_buffer_byte_size_;
+
+  // We need to provide the stream header with every keyframe, to allow
+  // midstream decoding restarts.  Store it here.
+  scoped_ptr<uint8[]> stream_header_;
+  size_t stream_header_size_;
+
+  // V4L2 formats for input frames and the output stream.
+  uint32 input_format_fourcc_;
+  uint32 output_format_fourcc_;
+
+  // Video frames ready to be encoded.
+  std::list<scoped_refptr<media::VideoFrame> > encoder_input_queue_;
+
+  // GSC color conversion device.
+  int gsc_fd_;
+  // GSC input queue state.
+  bool gsc_input_streamon_;
+  // GSC input buffers enqueued to device.
+  int gsc_input_buffer_queued_count_;
+  // GSC input buffers ready to use; LIFO since we don't care about ordering.
+  std::vector<int> gsc_free_input_buffers_;
+  // Mapping of int index to GSC input buffer record.
+  std::vector<GscInputRecord> gsc_input_buffer_map_;
+
+  // GSC output queue state.
+  bool gsc_output_streamon_;
+  // GSC output buffers enqueued to device.
+  int gsc_output_buffer_queued_count_;
+  // GSC output buffers ready to use; LIFO since we don't care about ordering.
+  std::vector<int> gsc_free_output_buffers_;
+  // Mapping of int index to GSC output buffer record.
+  std::vector<GscOutputRecord> gsc_output_buffer_map_;
+
+  // MFC input buffers filled by GSC, waiting to be queued to MFC.
+  std::list<int> mfc_ready_input_buffers_;
+
+  // MFC video encoding device.
+  int mfc_fd_;
+
+  // MFC input queue state.
+  bool mfc_input_streamon_;
+  // MFC input buffers enqueued to device.
+  int mfc_input_buffer_queued_count_;
+  // MFC input buffers ready to use; LIFO since we don't care about ordering.
+  std::vector<int> mfc_free_input_buffers_;
+  // Mapping of int index to MFC input buffer record.
+  std::vector<MfcInputRecord> mfc_input_buffer_map_;
+
+  // MFC output queue state.
+  bool mfc_output_streamon_;
+  // MFC output buffers enqueued to device.
+  int mfc_output_buffer_queued_count_;
+  // MFC output buffers ready to use; LIFO since we don't care about ordering.
+  std::vector<int> mfc_free_output_buffers_;
+  // Mapping of int index to MFC output buffer record.
+  std::vector<MfcOutputRecord> mfc_output_buffer_map_;
+
+  // Bitstream buffers ready to be used to return encoded output, as a LIFO
+  // since we don't care about ordering.
+  std::vector<linked_ptr<BitstreamBufferRef> > encoder_output_queue_;
+
+  //
+  // The device polling thread handles notifications of V4L2 device changes.
+  // TODO(sheu): replace this thread with an TYPE_IO encoder_thread_.
+  //
+
+  // The thread.
+  base::Thread device_poll_thread_;
+  // eventfd fd to signal device poll thread when its poll() should be
+  // interrupted.
+  int device_poll_interrupt_fd_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExynosVideoEncodeAccelerator);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_
diff --git a/content/common/gpu/media/gpu_video_encode_accelerator.cc b/content/common/gpu/media/gpu_video_encode_accelerator.cc
new file mode 100644
index 0000000..30f63b3
--- /dev/null
+++ b/content/common/gpu/media/gpu_video_encode_accelerator.cc
@@ -0,0 +1,243 @@
+// Copyright 2013 The Chromium Authors. 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/media/gpu_video_encode_accelerator.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "build/build_config.h"
+#include "content/common/gpu/gpu_channel.h"
+#include "content/common/gpu/gpu_messages.h"
+#include "ipc/ipc_message_macros.h"
+#include "media/base/video_frame.h"
+
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
+#include "content/common/gpu/media/exynos_video_encode_accelerator.h"
+#endif
+
+namespace content {
+
+GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(GpuChannel* gpu_channel,
+                                                     int32 route_id)
+    : weak_this_factory_(this),
+      channel_(gpu_channel),
+      route_id_(route_id),
+      input_format_(media::VideoFrame::INVALID),
+      output_buffer_size_(0) {}
+
+GpuVideoEncodeAccelerator::~GpuVideoEncodeAccelerator() {
+  if (encoder_)
+    encoder_.release()->Destroy();
+}
+
+bool GpuVideoEncodeAccelerator::OnMessageReceived(const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(GpuVideoEncodeAccelerator, message)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Initialize, OnInitialize)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_Encode, OnEncode)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoEncoderMsg_UseOutputBitstreamBuffer,
+                        OnUseOutputBitstreamBuffer)
+    IPC_MESSAGE_HANDLER(
+        AcceleratedVideoEncoderMsg_RequestEncodingParametersChange,
+        OnRequestEncodingParametersChange)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void GpuVideoEncodeAccelerator::OnChannelError() {
+  NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+  if (channel_)
+    channel_ = NULL;
+}
+
+void GpuVideoEncodeAccelerator::NotifyInitializeDone() {
+  Send(new AcceleratedVideoEncoderHostMsg_NotifyInitializeDone(route_id_));
+}
+
+void GpuVideoEncodeAccelerator::RequireBitstreamBuffers(
+    unsigned int input_count,
+    const gfx::Size& input_coded_size,
+    size_t output_buffer_size) {
+  Send(new AcceleratedVideoEncoderHostMsg_RequireBitstreamBuffers(
+      route_id_, input_count, input_coded_size, output_buffer_size));
+  input_coded_size_ = input_coded_size;
+  output_buffer_size_ = output_buffer_size;
+}
+
+void GpuVideoEncodeAccelerator::BitstreamBufferReady(int32 bitstream_buffer_id,
+                                                     size_t payload_size,
+                                                     bool key_frame) {
+  Send(new AcceleratedVideoEncoderHostMsg_BitstreamBufferReady(
+      route_id_, bitstream_buffer_id, payload_size, key_frame));
+}
+
+void GpuVideoEncodeAccelerator::NotifyError(
+    media::VideoEncodeAccelerator::Error error) {
+  Send(new AcceleratedVideoEncoderHostMsg_NotifyError(route_id_, error));
+}
+
+// static
+std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+GpuVideoEncodeAccelerator::GetSupportedProfiles() {
+  std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
+
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
+  profiles = ExynosVideoEncodeAccelerator::GetSupportedProfiles();
+#endif
+
+  // TODO(sheu): return platform-specific profiles.
+  return profiles;
+}
+
+void GpuVideoEncodeAccelerator::CreateEncoder() {
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL) && defined(USE_X11)
+  encoder_.reset(new ExynosVideoEncodeAccelerator(this));
+#endif
+}
+
+void GpuVideoEncodeAccelerator::OnInitialize(
+    media::VideoFrame::Format input_format,
+    const gfx::Size& input_visible_size,
+    media::VideoCodecProfile output_profile,
+    uint32 initial_bitrate) {
+  DVLOG(2) << "GpuVideoEncodeAccelerator::OnInitialize(): "
+              "input_format=" << input_format
+           << ", input_visible_size=" << input_visible_size.ToString()
+           << ", output_profile=" << output_profile
+           << ", initial_bitrate=" << initial_bitrate;
+  DCHECK(!encoder_);
+
+  if (input_visible_size.width() > kint32max / input_visible_size.height()) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnInitialize(): "
+                   "input_visible_size too large";
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+
+  CreateEncoder();
+  if (!encoder_) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnInitialize(): VEA creation "
+                   "failed";
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+  encoder_->Initialize(
+      input_format, input_visible_size, output_profile, initial_bitrate);
+  input_format_ = input_format;
+  input_visible_size_ = input_visible_size;
+}
+
+void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
+                                         base::SharedMemoryHandle buffer_handle,
+                                         uint32 buffer_size,
+                                         bool force_keyframe) {
+  DVLOG(3) << "GpuVideoEncodeAccelerator::OnEncode(): frame_id=" << frame_id
+           << ", buffer_size=" << buffer_size
+           << ", force_keyframe=" << force_keyframe;
+  if (!encoder_)
+    return;
+  if (frame_id < 0) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): invalid frame_id="
+                << frame_id;
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+
+  scoped_ptr<base::SharedMemory> shm(
+      new base::SharedMemory(buffer_handle, true));
+  if (!shm->Map(buffer_size)) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
+                   "could not map frame_id=" << frame_id;
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+
+  scoped_refptr<media::VideoFrame> frame =
+      media::VideoFrame::WrapExternalSharedMemory(
+          input_format_,
+          input_coded_size_,
+          gfx::Rect(input_visible_size_),
+          input_visible_size_,
+          reinterpret_cast<uint8*>(shm->memory()),
+          buffer_handle,
+          base::TimeDelta(),
+          // It's turtles all the way down...
+          base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
+                     base::MessageLoopProxy::current(),
+                     FROM_HERE,
+                     base::Bind(&GpuVideoEncodeAccelerator::EncodeFrameFinished,
+                                weak_this_factory_.GetWeakPtr(),
+                                frame_id,
+                                base::Passed(&shm))));
+
+  if (!frame) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnEncode(): "
+                   "could not create VideoFrame for frame_id=" << frame_id;
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+
+  encoder_->Encode(frame, force_keyframe);
+}
+
+void GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(
+    int32 buffer_id,
+    base::SharedMemoryHandle buffer_handle,
+    uint32 buffer_size) {
+  DVLOG(3) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
+              "buffer_id=" << buffer_id
+           << ", buffer_size=" << buffer_size;
+  if (!encoder_)
+    return;
+  if (buffer_id < 0) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
+                   "invalid buffer_id=" << buffer_id;
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+  if (buffer_size < output_buffer_size_) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::OnUseOutputBitstreamBuffer(): "
+                   "buffer too small for buffer_id=" << buffer_id;
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+  encoder_->UseOutputBitstreamBuffer(
+      media::BitstreamBuffer(buffer_id, buffer_handle, buffer_size));
+}
+
+void GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(
+    uint32 bitrate,
+    uint32 framerate) {
+  DVLOG(2) << "GpuVideoEncodeAccelerator::OnRequestEncodingParametersChange(): "
+              "bitrate=" << bitrate
+           << ", framerate=" << framerate;
+  if (!encoder_)
+    return;
+  encoder_->RequestEncodingParametersChange(bitrate, framerate);
+}
+
+void GpuVideoEncodeAccelerator::EncodeFrameFinished(
+    int32 frame_id,
+    scoped_ptr<base::SharedMemory> shm) {
+  Send(new AcceleratedVideoEncoderHostMsg_NotifyInputDone(route_id_, frame_id));
+  // Just let shm fall out of scope.
+}
+
+void GpuVideoEncodeAccelerator::Send(IPC::Message* message) {
+  if (!channel_) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::Send(): no channel";
+    delete message;
+    return;
+  } else if (!channel_->Send(message)) {
+    DLOG(ERROR) << "GpuVideoEncodeAccelerator::Send(): sending failed: "
+                   "message->type()=" << message->type();
+    NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+}
+
+}  // namespace content
diff --git a/content/common/gpu/media/gpu_video_encode_accelerator.h b/content/common/gpu/media/gpu_video_encode_accelerator.h
new file mode 100644
index 0000000..5a48295
--- /dev/null
+++ b/content/common/gpu/media/gpu_video_encode_accelerator.h
@@ -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.
+
+#ifndef CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ENCODE_ACCELERATOR_H_
+#define CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ENCODE_ACCELERATOR_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "ipc/ipc_listener.h"
+#include "media/video/video_encode_accelerator.h"
+#include "ui/gfx/size.h"
+
+namespace base {
+
+class SharedMemory;
+
+}  // namespace base
+
+namespace content {
+
+class GpuChannel;
+
+// This class encapsulates the GPU process view of a VideoEncodeAccelerator,
+// wrapping the platform-specific VideoEncodeAccelerator instance.  It handles
+// IPC coming in from the renderer and passes it to the underlying VEA.
+class GpuVideoEncodeAccelerator : public IPC::Listener,
+                                  public media::VideoEncodeAccelerator::Client {
+ public:
+  GpuVideoEncodeAccelerator(GpuChannel* gpu_channel, int32 route_id);
+  virtual ~GpuVideoEncodeAccelerator();
+
+  // IPC::Listener implementation
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+  virtual void OnChannelError() OVERRIDE;
+
+  // media::VideoEncodeAccelerator::Client implementation.
+  virtual void NotifyInitializeDone() OVERRIDE;
+  virtual void RequireBitstreamBuffers(unsigned int input_count,
+                                       const gfx::Size& input_coded_size,
+                                       size_t output_buffer_size) OVERRIDE;
+  virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
+                                    size_t payload_size,
+                                    bool key_frame) OVERRIDE;
+  virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
+
+  // Static query for supported profiles.  This query calls the appropriate
+  // platform-specific version.
+  static std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+      GetSupportedProfiles();
+
+ private:
+  // Create the appropriate platform-specific VEA.
+  void CreateEncoder();
+
+  // IPC handlers, proxying media::VideoEncodeAccelerator for the renderer
+  // process.
+  void OnInitialize(media::VideoFrame::Format input_format,
+                    const gfx::Size& input_visible_size,
+                    media::VideoCodecProfile output_profile,
+                    uint32 initial_bitrate);
+  void OnEncode(int32 frame_id,
+                base::SharedMemoryHandle buffer_handle,
+                uint32 buffer_size,
+                bool force_keyframe);
+  void OnUseOutputBitstreamBuffer(int32 buffer_id,
+                                  base::SharedMemoryHandle buffer_handle,
+                                  uint32 buffer_size);
+  void OnRequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
+
+  void EncodeFrameFinished(int32 frame_id, scoped_ptr<base::SharedMemory> shm);
+
+  void Send(IPC::Message* message);
+
+  // Weak pointer for media::VideoFrames that refer back to |this|.
+  base::WeakPtrFactory<GpuVideoEncodeAccelerator> weak_this_factory_;
+
+  // The GpuChannel owns this GpuVideoEncodeAccelerator and will outlive |this|.
+  GpuChannel* channel_;
+  const int32 route_id_;
+
+  // Owned pointer to the underlying VideoEncodeAccelerator.
+  scoped_ptr<media::VideoEncodeAccelerator> encoder_;
+
+  // Video encoding parameters.
+  media::VideoFrame::Format input_format_;
+  gfx::Size input_visible_size_;
+  gfx::Size input_coded_size_;
+  size_t output_buffer_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuVideoEncodeAccelerator);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_GPU_MEDIA_GPU_VIDEO_ENCODE_ACCELERATOR_H_
diff --git a/content/common/gpu/media/vaapi_h264_decoder.cc b/content/common/gpu/media/vaapi_h264_decoder.cc
index 78570b1..77739ce 100644
--- a/content/common/gpu/media/vaapi_h264_decoder.cc
+++ b/content/common/gpu/media/vaapi_h264_decoder.cc
@@ -1441,6 +1441,10 @@
   size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb),
                                  static_cast<int>(H264DPB::kDPBMaxSize));
   DVLOG(1) << "Codec level: " << level << ", DPB size: " << max_dpb_size;
+  if (max_dpb_size == 0) {
+    DVLOG(1) << "Invalid DPB Size";
+    return false;
+  }
 
   dpb_.set_max_num_pics(max_dpb_size);
 
diff --git a/content/common/gpu/stream_texture_manager_android.h b/content/common/gpu/stream_texture_manager_android.h
index 9421d6a..9da84d9 100644
--- a/content/common/gpu/stream_texture_manager_android.h
+++ b/content/common/gpu/stream_texture_manager_android.h
@@ -30,7 +30,7 @@
   virtual ~StreamTextureManagerAndroid();
 
   // implement gpu::StreamTextureManager:
-  virtual GLuint CreateStreamTexture(uint32 service_id,
+  virtual uint32 CreateStreamTexture(uint32 service_id,
                                      uint32 client_id) OVERRIDE;
   virtual void DestroyStreamTexture(uint32 service_id) OVERRIDE;
   virtual gpu::StreamTexture* LookupStreamTexture(uint32 service_id) OVERRIDE;
diff --git a/content/common/handle_enumerator_win.cc b/content/common/handle_enumerator_win.cc
index 98e232e..4e17aa2 100644
--- a/content/common/handle_enumerator_win.cc
+++ b/content/common/handle_enumerator_win.cc
@@ -174,8 +174,6 @@
         output.append(ASCIIToUTF16("\tFILE_WRITE_DATA\n"));
       if (access & FILE_WRITE_EA)
         output.append(ASCIIToUTF16("\tFILE_WRITE_EA\n"));
-      if (access & FILE_WRITE_EA)
-        output.append(ASCIIToUTF16("\tFILE_WRITE_EA\n"));
       break;
     case DirectoryHandle:
       if (access & FILE_ADD_FILE)
diff --git a/content/common/media/media_stream_options.cc b/content/common/media/media_stream_options.cc
index 4a3ace5..e042d8c 100644
--- a/content/common/media/media_stream_options.cc
+++ b/content/common/media/media_stream_options.cc
@@ -13,6 +13,7 @@
 const char kMediaStreamSourceInfoId[] = "sourceId";
 const char kMediaStreamSourceTab[] = "tab";
 const char kMediaStreamSourceScreen[] = "screen";
+const char kMediaStreamSourceDesktop[] = "desktop";
 const char kMediaStreamSourceSystem[] = "system";
 
 StreamOptions::StreamOptions()
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index e3faf26..bbb1aa4 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -19,6 +19,7 @@
 CONTENT_EXPORT extern const char kMediaStreamSourceInfoId[];
 CONTENT_EXPORT extern const char kMediaStreamSourceTab[];
 CONTENT_EXPORT extern const char kMediaStreamSourceScreen[];
+CONTENT_EXPORT extern const char kMediaStreamSourceDesktop[];
 CONTENT_EXPORT extern const char kMediaStreamSourceSystem[];
 
 // StreamOptions is a Chromium representation of WebKit's
diff --git a/content/common/mime_registry_messages.h b/content/common/mime_registry_messages.h
index e698369..3246721 100644
--- a/content/common/mime_registry_messages.h
+++ b/content/common/mime_registry_messages.h
@@ -20,7 +20,4 @@
 IPC_SYNC_MESSAGE_CONTROL1_1(MimeRegistryMsg_GetMimeTypeFromFile,
                             base::FilePath /* file_path */,
                             std::string /* mime_type */)
-IPC_SYNC_MESSAGE_CONTROL1_1(MimeRegistryMsg_GetPreferredExtensionForMimeType,
-                            std::string /* mime_type */,
-                            base::FilePath::StringType /* extension */)
 
diff --git a/content/common/sandbox_init_win.cc b/content/common/sandbox_init_win.cc
index 3afa122..dffb334 100644
--- a/content/common/sandbox_init_win.cc
+++ b/content/common/sandbox_init_win.cc
@@ -15,8 +15,6 @@
 
 bool InitializeSandbox(sandbox::SandboxInterfaceInfo* sandbox_info) {
   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  std::string process_type =
-      command_line.GetSwitchValueASCII(switches::kProcessType);
   sandbox::BrokerServices* broker_services = sandbox_info->broker_services;
   if (broker_services) {
     if (!InitBrokerServices(broker_services))
diff --git a/content/common/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_seccomp_bpf_linux.cc
index 5d8c42a..d6ebdad 100644
--- a/content/common/sandbox_seccomp_bpf_linux.cc
+++ b/content/common/sandbox_seccomp_bpf_linux.cc
@@ -1794,13 +1794,18 @@
   static const char kDevMfcDecPath[] = "/dev/mfc-dec";
   static const char kDevGsc1Path[] = "/dev/gsc1";
 
+  // Devices needed for video encode acceleration on ARM.
+  static const char kDevMfcEncPath[] = "/dev/mfc-enc";
+
   read_whitelist->push_back(kMali0Path);
   read_whitelist->push_back(kDevMfcDecPath);
   read_whitelist->push_back(kDevGsc1Path);
+  read_whitelist->push_back(kDevMfcEncPath);
 
   write_whitelist->push_back(kMali0Path);
   write_whitelist->push_back(kDevMfcDecPath);
   write_whitelist->push_back(kDevGsc1Path);
+  write_whitelist->push_back(kDevMfcEncPath);
 }
 
 void AddArmTegraGpuWhitelist(std::vector<std::string>* read_whitelist,
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 9ab0e99..a90e645 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -229,7 +229,6 @@
   IPC_STRUCT_TRAITS_MEMBER(should_update_history)
   IPC_STRUCT_TRAITS_MEMBER(searchable_form_url)
   IPC_STRUCT_TRAITS_MEMBER(searchable_form_encoding)
-  IPC_STRUCT_TRAITS_MEMBER(password_form)
   IPC_STRUCT_TRAITS_MEMBER(contents_mime_type)
   IPC_STRUCT_TRAITS_MEMBER(socket_address)
 IPC_STRUCT_TRAITS_END()
@@ -391,9 +390,11 @@
   IPC_STRUCT_MEMBER(int, hour)
   IPC_STRUCT_MEMBER(int, minute)
   IPC_STRUCT_MEMBER(int, second)
+  IPC_STRUCT_MEMBER(int, milli)
   IPC_STRUCT_MEMBER(int, week)
   IPC_STRUCT_MEMBER(double, minimum)
   IPC_STRUCT_MEMBER(double, maximum)
+  IPC_STRUCT_MEMBER(double, step)
 IPC_STRUCT_END()
 
 IPC_STRUCT_BEGIN(ViewHostMsg_DidFailProvisionalLoadWithError_Params)
@@ -713,6 +714,9 @@
   // Whether the RenderView should initially be swapped out.
   IPC_STRUCT_MEMBER(bool, swapped_out)
 
+  // Whether the RenderView should initially be hidden.
+  IPC_STRUCT_MEMBER(bool, hidden)
+
   // The initial page ID to use for this view, which must be larger than any
   // existing navigation that might be loaded in the view.  Page IDs are unique
   // to a view and are only updated by the renderer after this initial value.
@@ -2010,11 +2014,12 @@
 
 // WebKit and JavaScript error messages to log to the console
 // or debugger UI.
-IPC_MESSAGE_ROUTED4(ViewHostMsg_AddMessageToConsole,
+IPC_MESSAGE_ROUTED5(ViewHostMsg_AddMessageToConsole,
                     int32, /* log level */
                     string16, /* msg */
                     int32, /* line number */
-                    string16 /* source id */)
+                    string16, /* source id */
+                    string16 /* stack trace */ )
 
 // Sent by the renderer process to indicate that a plugin instance has crashed.
 // Note: |plugin_pid| should not be trusted. The corresponding process has
diff --git a/content/content.gyp b/content/content.gyp
index 0305664..c68fd3a 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -46,7 +46,6 @@
           'target_name': 'content',
           'type': 'none',
           'dependencies': [
-            'content_app_browser',
             'content_browser',
             'content_child',
             'content_common',
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index da6449c..49e7987 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -12,7 +12,7 @@
     '../skia/skia.gyp:skia',
     '../sql/sql.gyp:sql',
     '../third_party/re2/re2.gyp:re2',
-    '../third_party/zlib/zlib.gyp:zip',
+    '../third_party/zlib/google/zip.gyp:zip',
     '../third_party/zlib/zlib.gyp:zlib',
     '../ui/snapshot/snapshot.gyp:snapshot',
     '../ui/ui.gyp:ui',
@@ -64,7 +64,6 @@
     'public/browser/child_process_data.h',
     'public/browser/child_process_security_policy.h',
     'public/browser/color_chooser.h',
-    'public/browser/compositor_util.h',
     'public/browser/certificate_request_result_type.h',
     'public/browser/content_browser_client.cc',
     'public/browser/content_browser_client.h',
@@ -240,8 +239,8 @@
     'browser/android/browser_jni_registrar.h',
     'browser/android/browser_media_player_manager.cc',
     'browser/android/browser_media_player_manager.h',
-    'browser/android/browser_startup_config.cc',
-    'browser/android/browser_startup_config.h',
+    'browser/android/browser_startup_controller.cc',
+    'browser/android/browser_startup_controller.h',
     'browser/android/child_process_launcher_android.cc',
     'browser/android/child_process_launcher_android.h',
     'browser/android/content_settings.cc',
@@ -371,6 +370,8 @@
     'browser/devtools/devtools_protocol.h',
     'browser/devtools/devtools_protocol_constants.cc',
     'browser/devtools/devtools_protocol_constants.h',
+    'browser/devtools/devtools_system_info_handler.cc',
+    'browser/devtools/devtools_system_info_handler.h',
     'browser/devtools/devtools_tracing_handler.h',
     'browser/devtools/devtools_tracing_handler.cc',
     'browser/devtools/ipc_devtools_agent_host.cc',
@@ -399,17 +400,18 @@
     'browser/device_orientation/data_fetcher_orientation_android.cc',
     'browser/device_orientation/data_fetcher_orientation_android.h',
     'browser/device_orientation/data_fetcher_shared_memory_android.cc',
+    'browser/device_orientation/data_fetcher_shared_memory_base.cc',
+    'browser/device_orientation/data_fetcher_shared_memory_base.h',
     'browser/device_orientation/data_fetcher_shared_memory_default.cc',
     'browser/device_orientation/data_fetcher_shared_memory.h',
     'browser/device_orientation/device_data.h',
+    'browser/device_orientation/device_inertial_sensor_service.cc',
+    'browser/device_orientation/device_inertial_sensor_service.h',
     'browser/device_orientation/device_motion_message_filter.cc',
     'browser/device_orientation/device_motion_message_filter.h',
-    'browser/device_orientation/device_motion_provider.cc',
-    'browser/device_orientation/device_motion_provider.h',
-    'browser/device_orientation/device_motion_service.cc',
-    'browser/device_orientation/device_motion_service.h',
     'browser/device_orientation/device_orientation_message_filter.cc',
     'browser/device_orientation/device_orientation_message_filter.h',
+    'browser/device_orientation/inertial_sensor_consts.h',
     'browser/device_orientation/message_filter.cc',
     'browser/device_orientation/message_filter.h',
     'browser/device_orientation/observer_delegate.cc',
@@ -528,10 +530,6 @@
     'browser/gamepad/gamepad_standard_mappings_win.cc',
     'browser/gamepad/xbox_data_fetcher_mac.cc',
     'browser/gamepad/xbox_data_fetcher_mac.h',
-    'browser/geolocation/core_location_data_provider_mac.h',
-    'browser/geolocation/core_location_data_provider_mac.mm',
-    'browser/geolocation/core_location_provider_mac.h',
-    'browser/geolocation/core_location_provider_mac.mm',
     'browser/geolocation/device_data_provider.cc',
     'browser/geolocation/device_data_provider.h',
     'browser/geolocation/empty_device_data_provider.cc',
@@ -572,6 +570,7 @@
     'browser/gpu/browser_gpu_channel_host_factory.cc',
     'browser/gpu/browser_gpu_channel_host_factory.h',
     'browser/gpu/compositor_util.cc',
+    'browser/gpu/compositor_util.h',
     'browser/gpu/gpu_data_manager_impl.cc',
     'browser/gpu/gpu_data_manager_impl.h',
     'browser/gpu/gpu_data_manager_impl_private.cc',
diff --git a/content/content_browser.target.darwin-arm.mk b/content/content_browser.target.darwin-arm.mk
index abe0bc0..59a86ce 100644
--- a/content/content_browser.target.darwin-arm.mk
+++ b/content/content_browser.target.darwin-arm.mk
@@ -83,7 +83,7 @@
 	content/browser/android/android_browser_process.cc \
 	content/browser/android/browser_jni_registrar.cc \
 	content/browser/android/browser_media_player_manager.cc \
-	content/browser/android/browser_startup_config.cc \
+	content/browser/android/browser_startup_controller.cc \
 	content/browser/android/child_process_launcher_android.cc \
 	content/browser/android/content_settings.cc \
 	content/browser/android/content_startup_flags.cc \
@@ -140,6 +140,7 @@
 	content/browser/devtools/devtools_netlog_observer.cc \
 	content/browser/devtools/devtools_protocol.cc \
 	content/browser/devtools/devtools_protocol_constants.cc \
+	content/browser/devtools/devtools_system_info_handler.cc \
 	content/browser/devtools/devtools_tracing_handler.cc \
 	content/browser/devtools/ipc_devtools_agent_host.cc \
 	content/browser/devtools/render_view_devtools_agent_host.cc \
@@ -150,9 +151,9 @@
 	content/browser/device_orientation/data_fetcher_impl_android.cc \
 	content/browser/device_orientation/data_fetcher_orientation_android.cc \
 	content/browser/device_orientation/data_fetcher_shared_memory_android.cc \
+	content/browser/device_orientation/data_fetcher_shared_memory_base.cc \
+	content/browser/device_orientation/device_inertial_sensor_service.cc \
 	content/browser/device_orientation/device_motion_message_filter.cc \
-	content/browser/device_orientation/device_motion_provider.cc \
-	content/browser/device_orientation/device_motion_service.cc \
 	content/browser/device_orientation/device_orientation_message_filter.cc \
 	content/browser/device_orientation/message_filter.cc \
 	content/browser/device_orientation/observer_delegate.cc \
diff --git a/content/content_browser.target.darwin-mips.mk b/content/content_browser.target.darwin-mips.mk
index 2067108..ceb4a39 100644
--- a/content/content_browser.target.darwin-mips.mk
+++ b/content/content_browser.target.darwin-mips.mk
@@ -83,7 +83,7 @@
 	content/browser/android/android_browser_process.cc \
 	content/browser/android/browser_jni_registrar.cc \
 	content/browser/android/browser_media_player_manager.cc \
-	content/browser/android/browser_startup_config.cc \
+	content/browser/android/browser_startup_controller.cc \
 	content/browser/android/child_process_launcher_android.cc \
 	content/browser/android/content_settings.cc \
 	content/browser/android/content_startup_flags.cc \
@@ -140,6 +140,7 @@
 	content/browser/devtools/devtools_netlog_observer.cc \
 	content/browser/devtools/devtools_protocol.cc \
 	content/browser/devtools/devtools_protocol_constants.cc \
+	content/browser/devtools/devtools_system_info_handler.cc \
 	content/browser/devtools/devtools_tracing_handler.cc \
 	content/browser/devtools/ipc_devtools_agent_host.cc \
 	content/browser/devtools/render_view_devtools_agent_host.cc \
@@ -150,9 +151,9 @@
 	content/browser/device_orientation/data_fetcher_impl_android.cc \
 	content/browser/device_orientation/data_fetcher_orientation_android.cc \
 	content/browser/device_orientation/data_fetcher_shared_memory_android.cc \
+	content/browser/device_orientation/data_fetcher_shared_memory_base.cc \
+	content/browser/device_orientation/device_inertial_sensor_service.cc \
 	content/browser/device_orientation/device_motion_message_filter.cc \
-	content/browser/device_orientation/device_motion_provider.cc \
-	content/browser/device_orientation/device_motion_service.cc \
 	content/browser/device_orientation/device_orientation_message_filter.cc \
 	content/browser/device_orientation/message_filter.cc \
 	content/browser/device_orientation/observer_delegate.cc \
diff --git a/content/content_browser.target.darwin-x86.mk b/content/content_browser.target.darwin-x86.mk
index b3835c9..9dd9f43 100644
--- a/content/content_browser.target.darwin-x86.mk
+++ b/content/content_browser.target.darwin-x86.mk
@@ -83,7 +83,7 @@
 	content/browser/android/android_browser_process.cc \
 	content/browser/android/browser_jni_registrar.cc \
 	content/browser/android/browser_media_player_manager.cc \
-	content/browser/android/browser_startup_config.cc \
+	content/browser/android/browser_startup_controller.cc \
 	content/browser/android/child_process_launcher_android.cc \
 	content/browser/android/content_settings.cc \
 	content/browser/android/content_startup_flags.cc \
@@ -140,6 +140,7 @@
 	content/browser/devtools/devtools_netlog_observer.cc \
 	content/browser/devtools/devtools_protocol.cc \
 	content/browser/devtools/devtools_protocol_constants.cc \
+	content/browser/devtools/devtools_system_info_handler.cc \
 	content/browser/devtools/devtools_tracing_handler.cc \
 	content/browser/devtools/ipc_devtools_agent_host.cc \
 	content/browser/devtools/render_view_devtools_agent_host.cc \
@@ -150,9 +151,9 @@
 	content/browser/device_orientation/data_fetcher_impl_android.cc \
 	content/browser/device_orientation/data_fetcher_orientation_android.cc \
 	content/browser/device_orientation/data_fetcher_shared_memory_android.cc \
+	content/browser/device_orientation/data_fetcher_shared_memory_base.cc \
+	content/browser/device_orientation/device_inertial_sensor_service.cc \
 	content/browser/device_orientation/device_motion_message_filter.cc \
-	content/browser/device_orientation/device_motion_provider.cc \
-	content/browser/device_orientation/device_motion_service.cc \
 	content/browser/device_orientation/device_orientation_message_filter.cc \
 	content/browser/device_orientation/message_filter.cc \
 	content/browser/device_orientation/observer_delegate.cc \
diff --git a/content/content_browser.target.linux-arm.mk b/content/content_browser.target.linux-arm.mk
index abe0bc0..59a86ce 100644
--- a/content/content_browser.target.linux-arm.mk
+++ b/content/content_browser.target.linux-arm.mk
@@ -83,7 +83,7 @@
 	content/browser/android/android_browser_process.cc \
 	content/browser/android/browser_jni_registrar.cc \
 	content/browser/android/browser_media_player_manager.cc \
-	content/browser/android/browser_startup_config.cc \
+	content/browser/android/browser_startup_controller.cc \
 	content/browser/android/child_process_launcher_android.cc \
 	content/browser/android/content_settings.cc \
 	content/browser/android/content_startup_flags.cc \
@@ -140,6 +140,7 @@
 	content/browser/devtools/devtools_netlog_observer.cc \
 	content/browser/devtools/devtools_protocol.cc \
 	content/browser/devtools/devtools_protocol_constants.cc \
+	content/browser/devtools/devtools_system_info_handler.cc \
 	content/browser/devtools/devtools_tracing_handler.cc \
 	content/browser/devtools/ipc_devtools_agent_host.cc \
 	content/browser/devtools/render_view_devtools_agent_host.cc \
@@ -150,9 +151,9 @@
 	content/browser/device_orientation/data_fetcher_impl_android.cc \
 	content/browser/device_orientation/data_fetcher_orientation_android.cc \
 	content/browser/device_orientation/data_fetcher_shared_memory_android.cc \
+	content/browser/device_orientation/data_fetcher_shared_memory_base.cc \
+	content/browser/device_orientation/device_inertial_sensor_service.cc \
 	content/browser/device_orientation/device_motion_message_filter.cc \
-	content/browser/device_orientation/device_motion_provider.cc \
-	content/browser/device_orientation/device_motion_service.cc \
 	content/browser/device_orientation/device_orientation_message_filter.cc \
 	content/browser/device_orientation/message_filter.cc \
 	content/browser/device_orientation/observer_delegate.cc \
diff --git a/content/content_browser.target.linux-mips.mk b/content/content_browser.target.linux-mips.mk
index 2067108..ceb4a39 100644
--- a/content/content_browser.target.linux-mips.mk
+++ b/content/content_browser.target.linux-mips.mk
@@ -83,7 +83,7 @@
 	content/browser/android/android_browser_process.cc \
 	content/browser/android/browser_jni_registrar.cc \
 	content/browser/android/browser_media_player_manager.cc \
-	content/browser/android/browser_startup_config.cc \
+	content/browser/android/browser_startup_controller.cc \
 	content/browser/android/child_process_launcher_android.cc \
 	content/browser/android/content_settings.cc \
 	content/browser/android/content_startup_flags.cc \
@@ -140,6 +140,7 @@
 	content/browser/devtools/devtools_netlog_observer.cc \
 	content/browser/devtools/devtools_protocol.cc \
 	content/browser/devtools/devtools_protocol_constants.cc \
+	content/browser/devtools/devtools_system_info_handler.cc \
 	content/browser/devtools/devtools_tracing_handler.cc \
 	content/browser/devtools/ipc_devtools_agent_host.cc \
 	content/browser/devtools/render_view_devtools_agent_host.cc \
@@ -150,9 +151,9 @@
 	content/browser/device_orientation/data_fetcher_impl_android.cc \
 	content/browser/device_orientation/data_fetcher_orientation_android.cc \
 	content/browser/device_orientation/data_fetcher_shared_memory_android.cc \
+	content/browser/device_orientation/data_fetcher_shared_memory_base.cc \
+	content/browser/device_orientation/device_inertial_sensor_service.cc \
 	content/browser/device_orientation/device_motion_message_filter.cc \
-	content/browser/device_orientation/device_motion_provider.cc \
-	content/browser/device_orientation/device_motion_service.cc \
 	content/browser/device_orientation/device_orientation_message_filter.cc \
 	content/browser/device_orientation/message_filter.cc \
 	content/browser/device_orientation/observer_delegate.cc \
diff --git a/content/content_browser.target.linux-x86.mk b/content/content_browser.target.linux-x86.mk
index b3835c9..9dd9f43 100644
--- a/content/content_browser.target.linux-x86.mk
+++ b/content/content_browser.target.linux-x86.mk
@@ -83,7 +83,7 @@
 	content/browser/android/android_browser_process.cc \
 	content/browser/android/browser_jni_registrar.cc \
 	content/browser/android/browser_media_player_manager.cc \
-	content/browser/android/browser_startup_config.cc \
+	content/browser/android/browser_startup_controller.cc \
 	content/browser/android/child_process_launcher_android.cc \
 	content/browser/android/content_settings.cc \
 	content/browser/android/content_startup_flags.cc \
@@ -140,6 +140,7 @@
 	content/browser/devtools/devtools_netlog_observer.cc \
 	content/browser/devtools/devtools_protocol.cc \
 	content/browser/devtools/devtools_protocol_constants.cc \
+	content/browser/devtools/devtools_system_info_handler.cc \
 	content/browser/devtools/devtools_tracing_handler.cc \
 	content/browser/devtools/ipc_devtools_agent_host.cc \
 	content/browser/devtools/render_view_devtools_agent_host.cc \
@@ -150,9 +151,9 @@
 	content/browser/device_orientation/data_fetcher_impl_android.cc \
 	content/browser/device_orientation/data_fetcher_orientation_android.cc \
 	content/browser/device_orientation/data_fetcher_shared_memory_android.cc \
+	content/browser/device_orientation/data_fetcher_shared_memory_base.cc \
+	content/browser/device_orientation/device_inertial_sensor_service.cc \
 	content/browser/device_orientation/device_motion_message_filter.cc \
-	content/browser/device_orientation/device_motion_provider.cc \
-	content/browser/device_orientation/device_motion_service.cc \
 	content/browser/device_orientation/device_orientation_message_filter.cc \
 	content/browser/device_orientation/message_filter.cc \
 	content/browser/device_orientation/observer_delegate.cc \
diff --git a/content/content_browsertests.isolate b/content/content_browsertests.isolate
index 55b0f56..7312750 100644
--- a/content/content_browsertests.isolate
+++ b/content/content_browsertests.isolate
@@ -45,8 +45,6 @@
       'variables': {
         'isolate_dependency_tracked': [
           '../testing/test_env.py',
-          '../tools/swarm_client/run_isolated.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/content_browsertests<(EXECUTABLE_SUFFIX)',
         ],
         'isolate_dependency_untracked': [
@@ -56,6 +54,7 @@
           '../third_party/pyftpdlib/',
           '../third_party/pywebsocket/',
           '../third_party/tlslite/',
+          '../tools/swarm_client/',
         ],
       },
     }],
diff --git a/content/content_child.gypi b/content/content_child.gypi
index dd980e3..3fe2250 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -43,10 +43,10 @@
     'child/db_message_filter.h',
     'child/fileapi/file_system_dispatcher.cc',
     'child/fileapi/file_system_dispatcher.h',
-    'child/fileapi/webfilesystem_callback_adapters.cc',
-    'child/fileapi/webfilesystem_callback_adapters.h',
     'child/fileapi/webfilesystem_impl.cc',
     'child/fileapi/webfilesystem_impl.h',
+    'child/fileapi/webfilewriter_base.cc',
+    'child/fileapi/webfilewriter_base.h',
     'child/fileapi/webfilewriter_impl.cc',
     'child/fileapi/webfilewriter_impl.h',
     'child/image_decoder.cc',
diff --git a/content/content_child.target.darwin-arm.mk b/content/content_child.target.darwin-arm.mk
index 05d5a51..9c49ca4 100644
--- a/content/content_child.target.darwin-arm.mk
+++ b/content/content_child.target.darwin-arm.mk
@@ -42,8 +42,8 @@
 	content/child/database_util.cc \
 	content/child/db_message_filter.cc \
 	content/child/fileapi/file_system_dispatcher.cc \
-	content/child/fileapi/webfilesystem_callback_adapters.cc \
 	content/child/fileapi/webfilesystem_impl.cc \
+	content/child/fileapi/webfilewriter_base.cc \
 	content/child/fileapi/webfilewriter_impl.cc \
 	content/child/image_decoder.cc \
 	content/child/indexed_db/indexed_db_dispatcher.cc \
diff --git a/content/content_child.target.darwin-mips.mk b/content/content_child.target.darwin-mips.mk
index 455d867..821477e 100644
--- a/content/content_child.target.darwin-mips.mk
+++ b/content/content_child.target.darwin-mips.mk
@@ -42,8 +42,8 @@
 	content/child/database_util.cc \
 	content/child/db_message_filter.cc \
 	content/child/fileapi/file_system_dispatcher.cc \
-	content/child/fileapi/webfilesystem_callback_adapters.cc \
 	content/child/fileapi/webfilesystem_impl.cc \
+	content/child/fileapi/webfilewriter_base.cc \
 	content/child/fileapi/webfilewriter_impl.cc \
 	content/child/image_decoder.cc \
 	content/child/indexed_db/indexed_db_dispatcher.cc \
diff --git a/content/content_child.target.darwin-x86.mk b/content/content_child.target.darwin-x86.mk
index dff3426..ad31966 100644
--- a/content/content_child.target.darwin-x86.mk
+++ b/content/content_child.target.darwin-x86.mk
@@ -42,8 +42,8 @@
 	content/child/database_util.cc \
 	content/child/db_message_filter.cc \
 	content/child/fileapi/file_system_dispatcher.cc \
-	content/child/fileapi/webfilesystem_callback_adapters.cc \
 	content/child/fileapi/webfilesystem_impl.cc \
+	content/child/fileapi/webfilewriter_base.cc \
 	content/child/fileapi/webfilewriter_impl.cc \
 	content/child/image_decoder.cc \
 	content/child/indexed_db/indexed_db_dispatcher.cc \
diff --git a/content/content_child.target.linux-arm.mk b/content/content_child.target.linux-arm.mk
index 05d5a51..9c49ca4 100644
--- a/content/content_child.target.linux-arm.mk
+++ b/content/content_child.target.linux-arm.mk
@@ -42,8 +42,8 @@
 	content/child/database_util.cc \
 	content/child/db_message_filter.cc \
 	content/child/fileapi/file_system_dispatcher.cc \
-	content/child/fileapi/webfilesystem_callback_adapters.cc \
 	content/child/fileapi/webfilesystem_impl.cc \
+	content/child/fileapi/webfilewriter_base.cc \
 	content/child/fileapi/webfilewriter_impl.cc \
 	content/child/image_decoder.cc \
 	content/child/indexed_db/indexed_db_dispatcher.cc \
diff --git a/content/content_child.target.linux-mips.mk b/content/content_child.target.linux-mips.mk
index 455d867..821477e 100644
--- a/content/content_child.target.linux-mips.mk
+++ b/content/content_child.target.linux-mips.mk
@@ -42,8 +42,8 @@
 	content/child/database_util.cc \
 	content/child/db_message_filter.cc \
 	content/child/fileapi/file_system_dispatcher.cc \
-	content/child/fileapi/webfilesystem_callback_adapters.cc \
 	content/child/fileapi/webfilesystem_impl.cc \
+	content/child/fileapi/webfilewriter_base.cc \
 	content/child/fileapi/webfilewriter_impl.cc \
 	content/child/image_decoder.cc \
 	content/child/indexed_db/indexed_db_dispatcher.cc \
diff --git a/content/content_child.target.linux-x86.mk b/content/content_child.target.linux-x86.mk
index dff3426..ad31966 100644
--- a/content/content_child.target.linux-x86.mk
+++ b/content/content_child.target.linux-x86.mk
@@ -42,8 +42,8 @@
 	content/child/database_util.cc \
 	content/child/db_message_filter.cc \
 	content/child/fileapi/file_system_dispatcher.cc \
-	content/child/fileapi/webfilesystem_callback_adapters.cc \
 	content/child/fileapi/webfilesystem_impl.cc \
+	content/child/fileapi/webfilewriter_base.cc \
 	content/child/fileapi/webfilewriter_impl.cc \
 	content/child/image_decoder.cc \
 	content/child/indexed_db/indexed_db_dispatcher.cc \
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 0577548..18ecdea 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -197,6 +197,8 @@
     'common/gpu/client/gpu_channel_host.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',
+    'common/gpu/client/gpu_video_encode_accelerator_host.h',
     'common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc',
     'common/gpu/client/webgraphicscontext3d_command_buffer_impl.h',
     'common/gpu/gpu_channel.cc',
@@ -235,6 +237,8 @@
     'common/gpu/media/h264_parser.h',
     'common/gpu/media/gpu_video_decode_accelerator.cc',
     'common/gpu/media/gpu_video_decode_accelerator.h',
+    'common/gpu/media/gpu_video_encode_accelerator.cc',
+    'common/gpu/media/gpu_video_encode_accelerator.h',
     'common/gpu/sync_point_manager.h',
     'common/gpu/sync_point_manager.cc',
     'common/gpu/texture_image_transport_surface.h',
@@ -486,6 +490,8 @@
       'sources': [
         'common/gpu/media/exynos_video_decode_accelerator.cc',
         'common/gpu/media/exynos_video_decode_accelerator.h',
+        'common/gpu/media/exynos_video_encode_accelerator.cc',
+        'common/gpu/media/exynos_video_encode_accelerator.h',
       ],
       'include_dirs': [
         '<(DEPTH)/third_party/khronos',
diff --git a/content/content_common.target.darwin-arm.mk b/content/content_common.target.darwin-arm.mk
index 2ac0690..0aced76 100644
--- a/content/content_common.target.darwin-arm.mk
+++ b/content/content_common.target.darwin-arm.mk
@@ -88,6 +88,7 @@
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.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 \
 	content/common/gpu/gpu_channel.cc \
 	content/common/gpu/gpu_channel_manager.cc \
@@ -103,6 +104,7 @@
 	content/common/gpu/media/h264_bit_reader.cc \
 	content/common/gpu/media/h264_parser.cc \
 	content/common/gpu/media/gpu_video_decode_accelerator.cc \
+	content/common/gpu/media/gpu_video_encode_accelerator.cc \
 	content/common/gpu/sync_point_manager.cc \
 	content/common/gpu/texture_image_transport_surface.cc \
 	content/common/indexed_db/indexed_db_key.cc \
diff --git a/content/content_common.target.darwin-mips.mk b/content/content_common.target.darwin-mips.mk
index 2a2a7f3..6fdb22c 100644
--- a/content/content_common.target.darwin-mips.mk
+++ b/content/content_common.target.darwin-mips.mk
@@ -88,6 +88,7 @@
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.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 \
 	content/common/gpu/gpu_channel.cc \
 	content/common/gpu/gpu_channel_manager.cc \
@@ -103,6 +104,7 @@
 	content/common/gpu/media/h264_bit_reader.cc \
 	content/common/gpu/media/h264_parser.cc \
 	content/common/gpu/media/gpu_video_decode_accelerator.cc \
+	content/common/gpu/media/gpu_video_encode_accelerator.cc \
 	content/common/gpu/sync_point_manager.cc \
 	content/common/gpu/texture_image_transport_surface.cc \
 	content/common/indexed_db/indexed_db_key.cc \
diff --git a/content/content_common.target.darwin-x86.mk b/content/content_common.target.darwin-x86.mk
index c517380..8adec50 100644
--- a/content/content_common.target.darwin-x86.mk
+++ b/content/content_common.target.darwin-x86.mk
@@ -88,6 +88,7 @@
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.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 \
 	content/common/gpu/gpu_channel.cc \
 	content/common/gpu/gpu_channel_manager.cc \
@@ -103,6 +104,7 @@
 	content/common/gpu/media/h264_bit_reader.cc \
 	content/common/gpu/media/h264_parser.cc \
 	content/common/gpu/media/gpu_video_decode_accelerator.cc \
+	content/common/gpu/media/gpu_video_encode_accelerator.cc \
 	content/common/gpu/sync_point_manager.cc \
 	content/common/gpu/texture_image_transport_surface.cc \
 	content/common/indexed_db/indexed_db_key.cc \
diff --git a/content/content_common.target.linux-arm.mk b/content/content_common.target.linux-arm.mk
index 2ac0690..0aced76 100644
--- a/content/content_common.target.linux-arm.mk
+++ b/content/content_common.target.linux-arm.mk
@@ -88,6 +88,7 @@
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.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 \
 	content/common/gpu/gpu_channel.cc \
 	content/common/gpu/gpu_channel_manager.cc \
@@ -103,6 +104,7 @@
 	content/common/gpu/media/h264_bit_reader.cc \
 	content/common/gpu/media/h264_parser.cc \
 	content/common/gpu/media/gpu_video_decode_accelerator.cc \
+	content/common/gpu/media/gpu_video_encode_accelerator.cc \
 	content/common/gpu/sync_point_manager.cc \
 	content/common/gpu/texture_image_transport_surface.cc \
 	content/common/indexed_db/indexed_db_key.cc \
diff --git a/content/content_common.target.linux-mips.mk b/content/content_common.target.linux-mips.mk
index 2a2a7f3..6fdb22c 100644
--- a/content/content_common.target.linux-mips.mk
+++ b/content/content_common.target.linux-mips.mk
@@ -88,6 +88,7 @@
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.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 \
 	content/common/gpu/gpu_channel.cc \
 	content/common/gpu/gpu_channel_manager.cc \
@@ -103,6 +104,7 @@
 	content/common/gpu/media/h264_bit_reader.cc \
 	content/common/gpu/media/h264_parser.cc \
 	content/common/gpu/media/gpu_video_decode_accelerator.cc \
+	content/common/gpu/media/gpu_video_encode_accelerator.cc \
 	content/common/gpu/sync_point_manager.cc \
 	content/common/gpu/texture_image_transport_surface.cc \
 	content/common/indexed_db/indexed_db_key.cc \
diff --git a/content/content_common.target.linux-x86.mk b/content/content_common.target.linux-x86.mk
index c517380..8adec50 100644
--- a/content/content_common.target.linux-x86.mk
+++ b/content/content_common.target.linux-x86.mk
@@ -88,6 +88,7 @@
 	content/common/gpu/client/gl_helper_scaling.cc \
 	content/common/gpu/client/gpu_channel_host.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 \
 	content/common/gpu/gpu_channel.cc \
 	content/common/gpu/gpu_channel_manager.cc \
@@ -103,6 +104,7 @@
 	content/common/gpu/media/h264_bit_reader.cc \
 	content/common/gpu/media/h264_parser.cc \
 	content/common/gpu/media/gpu_video_decode_accelerator.cc \
+	content/common/gpu/media/gpu_video_encode_accelerator.cc \
 	content/common/gpu/sync_point_manager.cc \
 	content/common/gpu/texture_image_transport_surface.cc \
 	content/common/indexed_db/indexed_db_key.cc \
diff --git a/content/content_gpu.gypi b/content/content_gpu.gypi
index e1a28ba..5dba0ac 100644
--- a/content/content_gpu.gypi
+++ b/content/content_gpu.gypi
@@ -14,6 +14,8 @@
     'gpu/gpu_process.h',
     'gpu/gpu_child_thread.cc',
     'gpu/gpu_child_thread.h',
+    'gpu/gpu_main_thread.cc',
+    'gpu/gpu_main_thread.h',
     'gpu/gpu_watchdog_thread.cc',
     'gpu/gpu_watchdog_thread.h',
   ],
diff --git a/content/content_gpu.target.darwin-arm.mk b/content/content_gpu.target.darwin-arm.mk
index c5fa5fd..c9f57b0 100644
--- a/content/content_gpu.target.darwin-arm.mk
+++ b/content/content_gpu.target.darwin-arm.mk
@@ -29,6 +29,7 @@
 	content/gpu/gpu_main.cc \
 	content/gpu/gpu_process.cc \
 	content/gpu/gpu_child_thread.cc \
+	content/gpu/gpu_main_thread.cc \
 	content/gpu/gpu_watchdog_thread.cc
 
 
diff --git a/content/content_gpu.target.darwin-mips.mk b/content/content_gpu.target.darwin-mips.mk
index c0be759..afc3eb0 100644
--- a/content/content_gpu.target.darwin-mips.mk
+++ b/content/content_gpu.target.darwin-mips.mk
@@ -29,6 +29,7 @@
 	content/gpu/gpu_main.cc \
 	content/gpu/gpu_process.cc \
 	content/gpu/gpu_child_thread.cc \
+	content/gpu/gpu_main_thread.cc \
 	content/gpu/gpu_watchdog_thread.cc
 
 
diff --git a/content/content_gpu.target.darwin-x86.mk b/content/content_gpu.target.darwin-x86.mk
index 25b35b1..143a300 100644
--- a/content/content_gpu.target.darwin-x86.mk
+++ b/content/content_gpu.target.darwin-x86.mk
@@ -29,6 +29,7 @@
 	content/gpu/gpu_main.cc \
 	content/gpu/gpu_process.cc \
 	content/gpu/gpu_child_thread.cc \
+	content/gpu/gpu_main_thread.cc \
 	content/gpu/gpu_watchdog_thread.cc
 
 
diff --git a/content/content_gpu.target.linux-arm.mk b/content/content_gpu.target.linux-arm.mk
index c5fa5fd..c9f57b0 100644
--- a/content/content_gpu.target.linux-arm.mk
+++ b/content/content_gpu.target.linux-arm.mk
@@ -29,6 +29,7 @@
 	content/gpu/gpu_main.cc \
 	content/gpu/gpu_process.cc \
 	content/gpu/gpu_child_thread.cc \
+	content/gpu/gpu_main_thread.cc \
 	content/gpu/gpu_watchdog_thread.cc
 
 
diff --git a/content/content_gpu.target.linux-mips.mk b/content/content_gpu.target.linux-mips.mk
index c0be759..afc3eb0 100644
--- a/content/content_gpu.target.linux-mips.mk
+++ b/content/content_gpu.target.linux-mips.mk
@@ -29,6 +29,7 @@
 	content/gpu/gpu_main.cc \
 	content/gpu/gpu_process.cc \
 	content/gpu/gpu_child_thread.cc \
+	content/gpu/gpu_main_thread.cc \
 	content/gpu/gpu_watchdog_thread.cc
 
 
diff --git a/content/content_gpu.target.linux-x86.mk b/content/content_gpu.target.linux-x86.mk
index 25b35b1..143a300 100644
--- a/content/content_gpu.target.linux-x86.mk
+++ b/content/content_gpu.target.linux-x86.mk
@@ -29,6 +29,7 @@
 	content/gpu/gpu_main.cc \
 	content/gpu/gpu_process.cc \
 	content/gpu/gpu_child_thread.cc \
+	content/gpu/gpu_main_thread.cc \
 	content/gpu/gpu_watchdog_thread.cc
 
 
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
index 0ea4ad4..cfba343 100644
--- a/content/content_jni.gypi
+++ b/content/content_jni.gypi
@@ -13,7 +13,7 @@
     'public/android/java/src/org/chromium/content/app/LibraryLoader.java',
     'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java',
     'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java',
-    'public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java',
+    'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java',
     'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java',
     'public/android/java/src/org/chromium/content/browser/ContentSettings.java',
     'public/android/java/src/org/chromium/content/browser/ContentVideoView.java',
diff --git a/content/content_jni_headers.target.darwin-arm.mk b/content/content_jni_headers.target.darwin-arm.mk
index a70d861..d6e91e1 100644
--- a/content/content_jni_headers.target.darwin-arm.mk
+++ b/content/content_jni_headers.target.darwin-arm.mk
@@ -16,7 +16,7 @@
 
 
 ### Generated for rule "content_content_gyp_content_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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -67,15 +67,15 @@
 .PHONY: content_content_jni_headers_gyp_rule_trigger
 content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h
 
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_local_path := $(LOCAL_PATH)
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupController.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
 
 .PHONY: content_content_jni_headers_gyp_rule_trigger
-content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h
+content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h
 
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
@@ -325,7 +325,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
@@ -360,7 +360,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
diff --git a/content/content_jni_headers.target.darwin-mips.mk b/content/content_jni_headers.target.darwin-mips.mk
index 6a09177..2de4453 100644
--- a/content/content_jni_headers.target.darwin-mips.mk
+++ b/content/content_jni_headers.target.darwin-mips.mk
@@ -16,7 +16,7 @@
 
 
 ### Generated for rule "content_content_gyp_content_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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -67,15 +67,15 @@
 .PHONY: content_content_jni_headers_gyp_rule_trigger
 content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h
 
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_local_path := $(LOCAL_PATH)
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupController.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
 
 .PHONY: content_content_jni_headers_gyp_rule_trigger
-content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h
+content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h
 
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
@@ -325,7 +325,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
@@ -360,7 +360,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
diff --git a/content/content_jni_headers.target.darwin-x86.mk b/content/content_jni_headers.target.darwin-x86.mk
index 8dc9989..879717a 100644
--- a/content/content_jni_headers.target.darwin-x86.mk
+++ b/content/content_jni_headers.target.darwin-x86.mk
@@ -16,7 +16,7 @@
 
 
 ### Generated for rule "content_content_gyp_content_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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -67,15 +67,15 @@
 .PHONY: content_content_jni_headers_gyp_rule_trigger
 content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h
 
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_local_path := $(LOCAL_PATH)
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupController.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
 
 .PHONY: content_content_jni_headers_gyp_rule_trigger
-content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h
+content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h
 
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
@@ -325,7 +325,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
@@ -360,7 +360,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
diff --git a/content/content_jni_headers.target.linux-arm.mk b/content/content_jni_headers.target.linux-arm.mk
index a70d861..d6e91e1 100644
--- a/content/content_jni_headers.target.linux-arm.mk
+++ b/content/content_jni_headers.target.linux-arm.mk
@@ -16,7 +16,7 @@
 
 
 ### Generated for rule "content_content_gyp_content_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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -67,15 +67,15 @@
 .PHONY: content_content_jni_headers_gyp_rule_trigger
 content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h
 
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_local_path := $(LOCAL_PATH)
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupController.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
 
 .PHONY: content_content_jni_headers_gyp_rule_trigger
-content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h
+content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h
 
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
@@ -325,7 +325,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
@@ -360,7 +360,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
diff --git a/content/content_jni_headers.target.linux-mips.mk b/content/content_jni_headers.target.linux-mips.mk
index 6a09177..2de4453 100644
--- a/content/content_jni_headers.target.linux-mips.mk
+++ b/content/content_jni_headers.target.linux-mips.mk
@@ -16,7 +16,7 @@
 
 
 ### Generated for rule "content_content_gyp_content_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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -67,15 +67,15 @@
 .PHONY: content_content_jni_headers_gyp_rule_trigger
 content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h
 
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_local_path := $(LOCAL_PATH)
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupController.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
 
 .PHONY: content_content_jni_headers_gyp_rule_trigger
-content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h
+content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h
 
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
@@ -325,7 +325,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
@@ -360,7 +360,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
diff --git a/content/content_jni_headers.target.linux-x86.mk b/content/content_jni_headers.target.linux-x86.mk
index 8dc9989..879717a 100644
--- a/content/content_jni_headers.target.linux-x86.mk
+++ b/content/content_jni_headers.target.linux-x86.mk
@@ -16,7 +16,7 @@
 
 
 ### Generated for rule "content_content_gyp_content_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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/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)/content/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['public/android/java/src/org/chromium/content/app/ChildProcessService.java', 'public/android/java/src/org/chromium/content/app/ContentMain.java', 'public/android/java/src/org/chromium/content/app/LibraryLoader.java', 'public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java', 'public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java', 'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java', 'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java', 'public/android/java/src/org/chromium/content/browser/ContentSettings.java', 'public/android/java/src/org/chromium/content/browser/ContentVideoView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewCore.java', 'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java', 'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java', 'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java', 'public/android/java/src/org/chromium/content/browser/DownloadController.java', 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java', 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java', 'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java', 'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java', 'public/android/java/src/org/chromium/content/browser/LocationProvider.java', 'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java', 'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java', 'public/android/java/src/org/chromium/content/browser/SmoothScroller.java', 'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java', 'public/android/java/src/org/chromium/content/browser/TouchPoint.java', 'public/android/java/src/org/chromium/content/browser/TracingIntentHandler.java', 'public/android/java/src/org/chromium/content/browser/VibrationMessageFilter.java', 'public/android/java/src/org/chromium/content/browser/WebContentsObserverAndroid.java', 'public/android/java/src/org/chromium/content/common/CommandLine.java', 'public/android/java/src/org/chromium/content/common/DeviceTelephonyInfo.java', 'public/android/java/src/org/chromium/content/common/TraceEvent.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/content/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -67,15 +67,15 @@
 .PHONY: content_content_jni_headers_gyp_rule_trigger
 content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h
 
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_local_path := $(LOCAL_PATH)
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h: $(LOCAL_PATH)/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.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)/content/jni; cd $(gyp_local_path)/content; ../base/android/jni_generator/jni_generator.py --input_file public/android/java/src/org/chromium/content/browser/BrowserStartupController.java --output_dir "$(gyp_shared_intermediate_dir)/content/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
 
 .PHONY: content_content_jni_headers_gyp_rule_trigger
-content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h
+content_content_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h
 
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
@@ -325,7 +325,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
@@ -360,7 +360,7 @@
 	$(gyp_shared_intermediate_dir)/content/jni/LibraryLoader_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/BrowserAccessibilityManager_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/AndroidBrowserProcess_jni.h \
-	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupConfig_jni.h \
+	$(gyp_shared_intermediate_dir)/content/jni/BrowserStartupController_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ChildProcessLauncher_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentSettings_jni.h \
 	$(gyp_shared_intermediate_dir)/content/jni/ContentVideoView_jni.h \
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index fc539f1..53f1219 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -23,7 +23,6 @@
     '../webkit/renderer/compositor_bindings/compositor_bindings.gyp:webkit_compositor_support',
     '../webkit/renderer/webkit_renderer.gyp:webkit_renderer',
     '../webkit/storage_common.gyp:webkit_storage_common',
-    '../webkit/storage_renderer.gyp:webkit_storage_renderer',
     '../webkit/support/webkit_support.gyp:glue',
     '../webkit/support/webkit_support.gyp:glue_child',
   ],
@@ -57,6 +56,7 @@
     'public/renderer/render_view_observer_tracker.h',
     'public/renderer/render_view_visitor.h',
     'public/renderer/v8_value_converter.h',
+    'public/renderer/web_preferences.h',
     'renderer/accessibility/accessibility_node_serializer.cc',
     'renderer/accessibility/accessibility_node_serializer.h',
     'renderer/accessibility/renderer_accessibility.cc',
@@ -215,8 +215,8 @@
     'renderer/media/preload.h',
     'renderer/media/render_media_log.cc',
     'renderer/media/render_media_log.h',
-    'renderer/media/renderer_gpu_video_decoder_factories.cc',
-    'renderer/media/renderer_gpu_video_decoder_factories.h',
+    'renderer/media/renderer_gpu_video_accelerator_factories.cc',
+    'renderer/media/renderer_gpu_video_accelerator_factories.h',
     'renderer/media/renderer_webaudiodevice_impl.cc',
     'renderer/media/renderer_webaudiodevice_impl.h',
     'renderer/media/renderer_webmidiaccessor_impl.cc',
@@ -250,8 +250,8 @@
     'renderer/media/webmediaplayer_params.h',
     'renderer/media/webmediaplayer_util.cc',
     'renderer/media/webmediaplayer_util.h',
-    'renderer/media/webmediasourceclient_impl.cc',
-    'renderer/media/webmediasourceclient_impl.h',
+    'renderer/media/webmediasource_impl.cc',
+    'renderer/media/webmediasource_impl.h',
     'renderer/media/websourcebuffer_impl.cc',
     'renderer/media/websourcebuffer_impl.h',
     'renderer/memory_benchmarking_extension.cc',
@@ -359,8 +359,6 @@
     'renderer/pepper/ppb_file_ref_impl.h',
     'renderer/pepper/ppb_flash_message_loop_impl.cc',
     'renderer/pepper/ppb_flash_message_loop_impl.h',
-    'renderer/pepper/ppb_gpu_blacklist_private_impl.cc',
-    'renderer/pepper/ppb_gpu_blacklist_private_impl.h',
     'renderer/pepper/ppb_graphics_3d_impl.cc',
     'renderer/pepper/ppb_graphics_3d_impl.h',
     'renderer/pepper/ppb_image_data_impl.cc',
@@ -388,6 +386,8 @@
     'renderer/pepper/renderer_ppapi_host_impl.cc',
     'renderer/pepper/renderer_ppapi_host_impl.h',
     'renderer/pepper/renderer_restrict_dispatch_group.h',
+    'renderer/pepper/resource_converter.cc',
+    'renderer/pepper/resource_converter.h',
     'renderer/pepper/resource_creation_impl.cc',
     'renderer/pepper/resource_creation_impl.h',
     'renderer/pepper/url_request_info_util.cc',
@@ -439,8 +439,6 @@
     'renderer/render_process.h',
     'renderer/render_process_impl.cc',
     'renderer/render_process_impl.h',
-    'renderer/render_process_visibility_manager.cc',
-    'renderer/render_process_visibility_manager.h',
     'renderer/render_thread_impl.cc',
     'renderer/render_thread_impl.h',
     'renderer/render_view_impl.cc',
@@ -467,6 +465,8 @@
     'renderer/renderer_main_platform_delegate_linux.cc',
     'renderer/renderer_main_platform_delegate_mac.mm',
     'renderer/renderer_main_platform_delegate_win.cc',
+    'renderer/renderer_main_thread.cc',
+    'renderer/renderer_main_thread.h',
     'renderer/renderer_webapplicationcachehost_impl.cc',
     'renderer/renderer_webapplicationcachehost_impl.h',
     'renderer/renderer_webcookiejar_impl.cc',
@@ -475,8 +475,6 @@
     'renderer/renderer_webcolorchooser_impl.h',
     'renderer/renderer_webkitplatformsupport_impl.cc',
     'renderer/renderer_webkitplatformsupport_impl.h',
-    'renderer/rendering_benchmark.cc',
-    'renderer/rendering_benchmark.h',
     'renderer/sad_plugin.cc',
     'renderer/sad_plugin.h',
     'renderer/savable_resources.cc',
@@ -499,12 +497,13 @@
     'renderer/v8_value_converter_impl.h',
     'renderer/webclipboard_impl.cc',
     'renderer/webclipboard_impl.h',
-    'renderer/webcrypto_impl.cc',
-    'renderer/webcrypto_impl.h',
+    'renderer/web_preferences.cc',
     'renderer/web_ui_extension.cc',
     'renderer/web_ui_extension.h',
     'renderer/web_ui_extension_data.cc',
     'renderer/web_ui_extension_data.h',
+    'renderer/webcrypto_impl.cc',
+    'renderer/webcrypto_impl.h',
     'renderer/websharedworker_proxy.cc',
     'renderer/websharedworker_proxy.h',
     'renderer/websharedworkerrepository_impl.cc',
@@ -612,6 +611,10 @@
         'renderer/media/rtc_video_decoder.h',
         'renderer/media/rtc_video_decoder_factory.cc',
         'renderer/media/rtc_video_decoder_factory.h',
+        'renderer/media/rtc_video_encoder.cc',
+        'renderer/media/rtc_video_encoder.h',
+        'renderer/media/rtc_video_encoder_factory.cc',
+        'renderer/media/rtc_video_encoder_factory.h',
         'renderer/media/video_destination_handler.cc',
         'renderer/media/video_destination_handler.h',
         'renderer/media/video_source_handler.cc',
diff --git a/content/content_renderer.target.darwin-arm.mk b/content/content_renderer.target.darwin-arm.mk
index 6eca06a..2ee5958 100644
--- a/content/content_renderer.target.darwin-arm.mk
+++ b/content/content_renderer.target.darwin-arm.mk
@@ -114,7 +114,7 @@
 	content/renderer/media/midi_message_filter.cc \
 	content/renderer/media/pepper_platform_video_decoder.cc \
 	content/renderer/media/render_media_log.cc \
-	content/renderer/media/renderer_gpu_video_decoder_factories.cc \
+	content/renderer/media/renderer_gpu_video_accelerator_factories.cc \
 	content/renderer/media/renderer_webaudiodevice_impl.cc \
 	content/renderer/media/renderer_webmidiaccessor_impl.cc \
 	content/renderer/media/rtc_video_renderer.cc \
@@ -130,7 +130,7 @@
 	content/renderer/media/webmediaplayer_ms.cc \
 	content/renderer/media/webmediaplayer_params.cc \
 	content/renderer/media/webmediaplayer_util.cc \
-	content/renderer/media/webmediasourceclient_impl.cc \
+	content/renderer/media/webmediasource_impl.cc \
 	content/renderer/media/websourcebuffer_impl.cc \
 	content/renderer/memory_benchmarking_extension.cc \
 	content/renderer/menu_item_builder.cc \
@@ -153,7 +153,6 @@
 	content/renderer/ime_event_guard.cc \
 	content/renderer/render_frame_impl.cc \
 	content/renderer/render_process_impl.cc \
-	content/renderer/render_process_visibility_manager.cc \
 	content/renderer/render_thread_impl.cc \
 	content/renderer/render_view_impl.cc \
 	content/renderer/render_view_impl_android.cc \
@@ -166,11 +165,11 @@
 	content/renderer/renderer_date_time_picker.cc \
 	content/renderer/renderer_main.cc \
 	content/renderer/renderer_main_platform_delegate_android.cc \
+	content/renderer/renderer_main_thread.cc \
 	content/renderer/renderer_webapplicationcachehost_impl.cc \
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
-	content/renderer/rendering_benchmark.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
@@ -182,9 +181,10 @@
 	content/renderer/text_input_client_observer.cc \
 	content/renderer/v8_value_converter_impl.cc \
 	content/renderer/webclipboard_impl.cc \
-	content/renderer/webcrypto_impl.cc \
+	content/renderer/web_preferences.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
+	content/renderer/webcrypto_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.darwin-mips.mk b/content/content_renderer.target.darwin-mips.mk
index 7fea705..4b2aa86 100644
--- a/content/content_renderer.target.darwin-mips.mk
+++ b/content/content_renderer.target.darwin-mips.mk
@@ -114,7 +114,7 @@
 	content/renderer/media/midi_message_filter.cc \
 	content/renderer/media/pepper_platform_video_decoder.cc \
 	content/renderer/media/render_media_log.cc \
-	content/renderer/media/renderer_gpu_video_decoder_factories.cc \
+	content/renderer/media/renderer_gpu_video_accelerator_factories.cc \
 	content/renderer/media/renderer_webaudiodevice_impl.cc \
 	content/renderer/media/renderer_webmidiaccessor_impl.cc \
 	content/renderer/media/rtc_video_renderer.cc \
@@ -130,7 +130,7 @@
 	content/renderer/media/webmediaplayer_ms.cc \
 	content/renderer/media/webmediaplayer_params.cc \
 	content/renderer/media/webmediaplayer_util.cc \
-	content/renderer/media/webmediasourceclient_impl.cc \
+	content/renderer/media/webmediasource_impl.cc \
 	content/renderer/media/websourcebuffer_impl.cc \
 	content/renderer/memory_benchmarking_extension.cc \
 	content/renderer/menu_item_builder.cc \
@@ -153,7 +153,6 @@
 	content/renderer/ime_event_guard.cc \
 	content/renderer/render_frame_impl.cc \
 	content/renderer/render_process_impl.cc \
-	content/renderer/render_process_visibility_manager.cc \
 	content/renderer/render_thread_impl.cc \
 	content/renderer/render_view_impl.cc \
 	content/renderer/render_view_impl_android.cc \
@@ -166,11 +165,11 @@
 	content/renderer/renderer_date_time_picker.cc \
 	content/renderer/renderer_main.cc \
 	content/renderer/renderer_main_platform_delegate_android.cc \
+	content/renderer/renderer_main_thread.cc \
 	content/renderer/renderer_webapplicationcachehost_impl.cc \
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
-	content/renderer/rendering_benchmark.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
@@ -182,9 +181,10 @@
 	content/renderer/text_input_client_observer.cc \
 	content/renderer/v8_value_converter_impl.cc \
 	content/renderer/webclipboard_impl.cc \
-	content/renderer/webcrypto_impl.cc \
+	content/renderer/web_preferences.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
+	content/renderer/webcrypto_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.darwin-x86.mk b/content/content_renderer.target.darwin-x86.mk
index 69eff0d..dafdccf 100644
--- a/content/content_renderer.target.darwin-x86.mk
+++ b/content/content_renderer.target.darwin-x86.mk
@@ -114,7 +114,7 @@
 	content/renderer/media/midi_message_filter.cc \
 	content/renderer/media/pepper_platform_video_decoder.cc \
 	content/renderer/media/render_media_log.cc \
-	content/renderer/media/renderer_gpu_video_decoder_factories.cc \
+	content/renderer/media/renderer_gpu_video_accelerator_factories.cc \
 	content/renderer/media/renderer_webaudiodevice_impl.cc \
 	content/renderer/media/renderer_webmidiaccessor_impl.cc \
 	content/renderer/media/rtc_video_renderer.cc \
@@ -130,7 +130,7 @@
 	content/renderer/media/webmediaplayer_ms.cc \
 	content/renderer/media/webmediaplayer_params.cc \
 	content/renderer/media/webmediaplayer_util.cc \
-	content/renderer/media/webmediasourceclient_impl.cc \
+	content/renderer/media/webmediasource_impl.cc \
 	content/renderer/media/websourcebuffer_impl.cc \
 	content/renderer/memory_benchmarking_extension.cc \
 	content/renderer/menu_item_builder.cc \
@@ -153,7 +153,6 @@
 	content/renderer/ime_event_guard.cc \
 	content/renderer/render_frame_impl.cc \
 	content/renderer/render_process_impl.cc \
-	content/renderer/render_process_visibility_manager.cc \
 	content/renderer/render_thread_impl.cc \
 	content/renderer/render_view_impl.cc \
 	content/renderer/render_view_impl_android.cc \
@@ -166,11 +165,11 @@
 	content/renderer/renderer_date_time_picker.cc \
 	content/renderer/renderer_main.cc \
 	content/renderer/renderer_main_platform_delegate_android.cc \
+	content/renderer/renderer_main_thread.cc \
 	content/renderer/renderer_webapplicationcachehost_impl.cc \
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
-	content/renderer/rendering_benchmark.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
@@ -182,9 +181,10 @@
 	content/renderer/text_input_client_observer.cc \
 	content/renderer/v8_value_converter_impl.cc \
 	content/renderer/webclipboard_impl.cc \
-	content/renderer/webcrypto_impl.cc \
+	content/renderer/web_preferences.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
+	content/renderer/webcrypto_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.linux-arm.mk b/content/content_renderer.target.linux-arm.mk
index 6eca06a..2ee5958 100644
--- a/content/content_renderer.target.linux-arm.mk
+++ b/content/content_renderer.target.linux-arm.mk
@@ -114,7 +114,7 @@
 	content/renderer/media/midi_message_filter.cc \
 	content/renderer/media/pepper_platform_video_decoder.cc \
 	content/renderer/media/render_media_log.cc \
-	content/renderer/media/renderer_gpu_video_decoder_factories.cc \
+	content/renderer/media/renderer_gpu_video_accelerator_factories.cc \
 	content/renderer/media/renderer_webaudiodevice_impl.cc \
 	content/renderer/media/renderer_webmidiaccessor_impl.cc \
 	content/renderer/media/rtc_video_renderer.cc \
@@ -130,7 +130,7 @@
 	content/renderer/media/webmediaplayer_ms.cc \
 	content/renderer/media/webmediaplayer_params.cc \
 	content/renderer/media/webmediaplayer_util.cc \
-	content/renderer/media/webmediasourceclient_impl.cc \
+	content/renderer/media/webmediasource_impl.cc \
 	content/renderer/media/websourcebuffer_impl.cc \
 	content/renderer/memory_benchmarking_extension.cc \
 	content/renderer/menu_item_builder.cc \
@@ -153,7 +153,6 @@
 	content/renderer/ime_event_guard.cc \
 	content/renderer/render_frame_impl.cc \
 	content/renderer/render_process_impl.cc \
-	content/renderer/render_process_visibility_manager.cc \
 	content/renderer/render_thread_impl.cc \
 	content/renderer/render_view_impl.cc \
 	content/renderer/render_view_impl_android.cc \
@@ -166,11 +165,11 @@
 	content/renderer/renderer_date_time_picker.cc \
 	content/renderer/renderer_main.cc \
 	content/renderer/renderer_main_platform_delegate_android.cc \
+	content/renderer/renderer_main_thread.cc \
 	content/renderer/renderer_webapplicationcachehost_impl.cc \
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
-	content/renderer/rendering_benchmark.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
@@ -182,9 +181,10 @@
 	content/renderer/text_input_client_observer.cc \
 	content/renderer/v8_value_converter_impl.cc \
 	content/renderer/webclipboard_impl.cc \
-	content/renderer/webcrypto_impl.cc \
+	content/renderer/web_preferences.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
+	content/renderer/webcrypto_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.linux-mips.mk b/content/content_renderer.target.linux-mips.mk
index 7fea705..4b2aa86 100644
--- a/content/content_renderer.target.linux-mips.mk
+++ b/content/content_renderer.target.linux-mips.mk
@@ -114,7 +114,7 @@
 	content/renderer/media/midi_message_filter.cc \
 	content/renderer/media/pepper_platform_video_decoder.cc \
 	content/renderer/media/render_media_log.cc \
-	content/renderer/media/renderer_gpu_video_decoder_factories.cc \
+	content/renderer/media/renderer_gpu_video_accelerator_factories.cc \
 	content/renderer/media/renderer_webaudiodevice_impl.cc \
 	content/renderer/media/renderer_webmidiaccessor_impl.cc \
 	content/renderer/media/rtc_video_renderer.cc \
@@ -130,7 +130,7 @@
 	content/renderer/media/webmediaplayer_ms.cc \
 	content/renderer/media/webmediaplayer_params.cc \
 	content/renderer/media/webmediaplayer_util.cc \
-	content/renderer/media/webmediasourceclient_impl.cc \
+	content/renderer/media/webmediasource_impl.cc \
 	content/renderer/media/websourcebuffer_impl.cc \
 	content/renderer/memory_benchmarking_extension.cc \
 	content/renderer/menu_item_builder.cc \
@@ -153,7 +153,6 @@
 	content/renderer/ime_event_guard.cc \
 	content/renderer/render_frame_impl.cc \
 	content/renderer/render_process_impl.cc \
-	content/renderer/render_process_visibility_manager.cc \
 	content/renderer/render_thread_impl.cc \
 	content/renderer/render_view_impl.cc \
 	content/renderer/render_view_impl_android.cc \
@@ -166,11 +165,11 @@
 	content/renderer/renderer_date_time_picker.cc \
 	content/renderer/renderer_main.cc \
 	content/renderer/renderer_main_platform_delegate_android.cc \
+	content/renderer/renderer_main_thread.cc \
 	content/renderer/renderer_webapplicationcachehost_impl.cc \
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
-	content/renderer/rendering_benchmark.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
@@ -182,9 +181,10 @@
 	content/renderer/text_input_client_observer.cc \
 	content/renderer/v8_value_converter_impl.cc \
 	content/renderer/webclipboard_impl.cc \
-	content/renderer/webcrypto_impl.cc \
+	content/renderer/web_preferences.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
+	content/renderer/webcrypto_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.linux-x86.mk b/content/content_renderer.target.linux-x86.mk
index 69eff0d..dafdccf 100644
--- a/content/content_renderer.target.linux-x86.mk
+++ b/content/content_renderer.target.linux-x86.mk
@@ -114,7 +114,7 @@
 	content/renderer/media/midi_message_filter.cc \
 	content/renderer/media/pepper_platform_video_decoder.cc \
 	content/renderer/media/render_media_log.cc \
-	content/renderer/media/renderer_gpu_video_decoder_factories.cc \
+	content/renderer/media/renderer_gpu_video_accelerator_factories.cc \
 	content/renderer/media/renderer_webaudiodevice_impl.cc \
 	content/renderer/media/renderer_webmidiaccessor_impl.cc \
 	content/renderer/media/rtc_video_renderer.cc \
@@ -130,7 +130,7 @@
 	content/renderer/media/webmediaplayer_ms.cc \
 	content/renderer/media/webmediaplayer_params.cc \
 	content/renderer/media/webmediaplayer_util.cc \
-	content/renderer/media/webmediasourceclient_impl.cc \
+	content/renderer/media/webmediasource_impl.cc \
 	content/renderer/media/websourcebuffer_impl.cc \
 	content/renderer/memory_benchmarking_extension.cc \
 	content/renderer/menu_item_builder.cc \
@@ -153,7 +153,6 @@
 	content/renderer/ime_event_guard.cc \
 	content/renderer/render_frame_impl.cc \
 	content/renderer/render_process_impl.cc \
-	content/renderer/render_process_visibility_manager.cc \
 	content/renderer/render_thread_impl.cc \
 	content/renderer/render_view_impl.cc \
 	content/renderer/render_view_impl_android.cc \
@@ -166,11 +165,11 @@
 	content/renderer/renderer_date_time_picker.cc \
 	content/renderer/renderer_main.cc \
 	content/renderer/renderer_main_platform_delegate_android.cc \
+	content/renderer/renderer_main_thread.cc \
 	content/renderer/renderer_webapplicationcachehost_impl.cc \
 	content/renderer/renderer_webcookiejar_impl.cc \
 	content/renderer/renderer_webcolorchooser_impl.cc \
 	content/renderer/renderer_webkitplatformsupport_impl.cc \
-	content/renderer/rendering_benchmark.cc \
 	content/renderer/sad_plugin.cc \
 	content/renderer/savable_resources.cc \
 	content/renderer/scoped_clipboard_writer_glue.cc \
@@ -182,9 +181,10 @@
 	content/renderer/text_input_client_observer.cc \
 	content/renderer/v8_value_converter_impl.cc \
 	content/renderer/webclipboard_impl.cc \
-	content/renderer/webcrypto_impl.cc \
+	content/renderer/web_preferences.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
+	content/renderer/webcrypto_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_resources.target.darwin-arm.mk b/content/content_resources.target.darwin-arm.mk
index 6179268..87db013 100644
--- a/content/content_resources.target.darwin-arm.mk
+++ b/content/content_resources.target.darwin-arm.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/client_renderer.js $(LOCAL_PATH)/content/browser/resources/media/new/main.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/new/player_info.js $(LOCAL_PATH)/content/browser/resources/media/new/player_manager.js $(LOCAL_PATH)/content/browser/resources/media/new/util.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from content_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/content; mkdir -p $(gyp_shared_intermediate_dir)/content/grit $(gyp_shared_intermediate_dir)/content; python ../tools/grit/grit.py -i content_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/content" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/content/content_resources.target.darwin-mips.mk b/content/content_resources.target.darwin-mips.mk
index 6179268..87db013 100644
--- a/content/content_resources.target.darwin-mips.mk
+++ b/content/content_resources.target.darwin-mips.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/client_renderer.js $(LOCAL_PATH)/content/browser/resources/media/new/main.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/new/player_info.js $(LOCAL_PATH)/content/browser/resources/media/new/player_manager.js $(LOCAL_PATH)/content/browser/resources/media/new/util.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from content_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/content; mkdir -p $(gyp_shared_intermediate_dir)/content/grit $(gyp_shared_intermediate_dir)/content; python ../tools/grit/grit.py -i content_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/content" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/content/content_resources.target.darwin-x86.mk b/content/content_resources.target.darwin-x86.mk
index 6179268..87db013 100644
--- a/content/content_resources.target.darwin-x86.mk
+++ b/content/content_resources.target.darwin-x86.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/client_renderer.js $(LOCAL_PATH)/content/browser/resources/media/new/main.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/new/player_info.js $(LOCAL_PATH)/content/browser/resources/media/new/player_manager.js $(LOCAL_PATH)/content/browser/resources/media/new/util.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from content_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/content; mkdir -p $(gyp_shared_intermediate_dir)/content/grit $(gyp_shared_intermediate_dir)/content; python ../tools/grit/grit.py -i content_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/content" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/content/content_resources.target.linux-arm.mk b/content/content_resources.target.linux-arm.mk
index 6179268..87db013 100644
--- a/content/content_resources.target.linux-arm.mk
+++ b/content/content_resources.target.linux-arm.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/client_renderer.js $(LOCAL_PATH)/content/browser/resources/media/new/main.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/new/player_info.js $(LOCAL_PATH)/content/browser/resources/media/new/player_manager.js $(LOCAL_PATH)/content/browser/resources/media/new/util.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from content_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/content; mkdir -p $(gyp_shared_intermediate_dir)/content/grit $(gyp_shared_intermediate_dir)/content; python ../tools/grit/grit.py -i content_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/content" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/content/content_resources.target.linux-mips.mk b/content/content_resources.target.linux-mips.mk
index 6179268..87db013 100644
--- a/content/content_resources.target.linux-mips.mk
+++ b/content/content_resources.target.linux-mips.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/client_renderer.js $(LOCAL_PATH)/content/browser/resources/media/new/main.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/new/player_info.js $(LOCAL_PATH)/content/browser/resources/media/new/player_manager.js $(LOCAL_PATH)/content/browser/resources/media/new/util.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from content_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/content; mkdir -p $(gyp_shared_intermediate_dir)/content/grit $(gyp_shared_intermediate_dir)/content; python ../tools/grit/grit.py -i content_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/content" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/content/content_resources.target.linux-x86.mk b/content/content_resources.target.linux-x86.mk
index 6179268..87db013 100644
--- a/content/content_resources.target.linux-x86.mk
+++ b/content/content_resources.target.linux-x86.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/content/grit/content_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/content/grit/content_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/content/content_resources.grd $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.css $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.html $(LOCAL_PATH)/content/browser/resources/accessibility/accessibility.js $(LOCAL_PATH)/content/browser/resources/gpu/browser_bridge.js $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.html $(LOCAL_PATH)/content/browser/resources/gpu/gpu_internals.js $(LOCAL_PATH)/content/browser/resources/gpu/info_view.css $(LOCAL_PATH)/content/browser/resources/gpu/info_view.html $(LOCAL_PATH)/content/browser/resources/gpu/info_view.js $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.css $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.html $(LOCAL_PATH)/content/browser/resources/indexed_db/indexeddb_internals.js $(LOCAL_PATH)/content/browser/resources/media/cache_entry.js $(LOCAL_PATH)/content/browser/resources/media/data_series.js $(LOCAL_PATH)/content/browser/resources/media/disjoint_range_set.js $(LOCAL_PATH)/content/browser/resources/media/dump_creator.js $(LOCAL_PATH)/content/browser/resources/media/event_list.js $(LOCAL_PATH)/content/browser/resources/media/item_store.js $(LOCAL_PATH)/content/browser/resources/media/media_internals.css $(LOCAL_PATH)/content/browser/resources/media/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/media_player.js $(LOCAL_PATH)/content/browser/resources/media/metrics.js $(LOCAL_PATH)/content/browser/resources/media/new/client_renderer.js $(LOCAL_PATH)/content/browser/resources/media/new/main.js $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.html $(LOCAL_PATH)/content/browser/resources/media/new/media_internals.js $(LOCAL_PATH)/content/browser/resources/media/new/player_info.js $(LOCAL_PATH)/content/browser/resources/media/new/player_manager.js $(LOCAL_PATH)/content/browser/resources/media/new/util.js $(LOCAL_PATH)/content/browser/resources/media/peer_connection_update_table.js $(LOCAL_PATH)/content/browser/resources/media/ssrc_info_manager.js $(LOCAL_PATH)/content/browser/resources/media/stats_graph_helper.js $(LOCAL_PATH)/content/browser/resources/media/stats_table.js $(LOCAL_PATH)/content/browser/resources/media/timeline_graph_view.js $(LOCAL_PATH)/content/browser/resources/media/util.js $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.css $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.html $(LOCAL_PATH)/content/browser/resources/media/webrtc_internals.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from content_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/content; mkdir -p $(gyp_shared_intermediate_dir)/content/grit $(gyp_shared_intermediate_dir)/content; python ../tools/grit/grit.py -i content_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/content" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index ae9012e..e6e5b6a 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -68,11 +68,73 @@
         'shell/app/shell_main_delegate.h',
         'shell/app/shell_main_delegate_mac.h',
         'shell/app/shell_main_delegate_mac.mm',
-        'shell/app/webkit_test_platform_support.h',
         'shell/app/webkit_test_platform_support_android.cc',
+        'shell/app/webkit_test_platform_support.h',
         'shell/app/webkit_test_platform_support_linux.cc',
         'shell/app/webkit_test_platform_support_mac.mm',
         'shell/app/webkit_test_platform_support_win.cc',
+        'shell/browser/minimal_shell.cc',
+        'shell/browser/minimal_shell.h',
+        'shell/browser/notify_done_forwarder.cc',
+        'shell/browser/notify_done_forwarder.h',
+        'shell/browser/shell_android.cc',
+        'shell/browser/shell_application_mac.h',
+        'shell/browser/shell_application_mac.mm',
+        'shell/browser/shell_aura.cc',
+        'shell/browser/shell_browser_context.cc',
+        'shell/browser/shell_browser_context.h',
+        'shell/browser/shell_browser_main.cc',
+        'shell/browser/shell_browser_main.h',
+        'shell/browser/shell_browser_main_parts.cc',
+        'shell/browser/shell_browser_main_parts.h',
+        'shell/browser/shell_browser_main_parts_mac.mm',
+        'shell/browser/shell.cc',
+        'shell/browser/shell_content_browser_client.cc',
+        'shell/browser/shell_content_browser_client.h',
+        'shell/browser/shell_devtools_delegate.cc',
+        'shell/browser/shell_devtools_delegate.h',
+        'shell/browser/shell_devtools_frontend.cc',
+        'shell/browser/shell_devtools_frontend.h',
+        'shell/browser/shell_download_manager_delegate.cc',
+        'shell/browser/shell_download_manager_delegate.h',
+        'shell/browser/shell_gtk.cc',
+        'shell/browser/shell.h',
+        'shell/browser/shell_javascript_dialog_gtk.cc',
+        'shell/browser/shell_javascript_dialog.h',
+        'shell/browser/shell_javascript_dialog_mac.mm',
+        'shell/browser/shell_javascript_dialog_manager.cc',
+        'shell/browser/shell_javascript_dialog_manager.h',
+        'shell/browser/shell_javascript_dialog_win.cc',
+        'shell/browser/shell_layout_tests_android.cc',
+        'shell/browser/shell_layout_tests_android.h',
+        'shell/browser/shell_login_dialog.cc',
+        'shell/browser/shell_login_dialog_gtk.cc',
+        'shell/browser/shell_login_dialog.h',
+        'shell/browser/shell_login_dialog_mac.mm',
+        'shell/browser/shell_mac.mm',
+        'shell/browser/shell_message_filter.cc',
+        'shell/browser/shell_message_filter.h',
+        'shell/browser/shell_net_log.cc',
+        'shell/browser/shell_net_log.h',
+        'shell/browser/shell_network_delegate.cc',
+        'shell/browser/shell_network_delegate.h',
+        'shell/browser/shell_plugin_service_filter.cc',
+        'shell/browser/shell_plugin_service_filter.h',
+        'shell/browser/shell_quota_permission_context.cc',
+        'shell/browser/shell_quota_permission_context.h',
+        'shell/browser/shell_resource_dispatcher_host_delegate.cc',
+        'shell/browser/shell_resource_dispatcher_host_delegate.h',
+        'shell/browser/shell_url_request_context_getter.cc',
+        'shell/browser/shell_url_request_context_getter.h',
+        'shell/browser/shell_web_contents_view_delegate_android.cc',
+        'shell/browser/shell_web_contents_view_delegate_creator.h',
+        'shell/browser/shell_web_contents_view_delegate_gtk.cc',
+        'shell/browser/shell_web_contents_view_delegate.h',
+        'shell/browser/shell_web_contents_view_delegate_mac.mm',
+        'shell/browser/shell_web_contents_view_delegate_win.cc',
+        'shell/browser/shell_win.cc',
+        'shell/browser/webkit_test_controller.cc',
+        'shell/browser/webkit_test_controller.h',
         'shell/common/shell_content_client.cc',
         'shell/common/shell_content_client.h',
         'shell/common/shell_messages.cc',
@@ -85,10 +147,6 @@
         'shell/common/webkit_test_helpers.h',
         'shell/geolocation/shell_access_token_store.cc',
         'shell/geolocation/shell_access_token_store.h',
-        'shell/minimal_shell.cc',
-        'shell/minimal_shell.h',
-        'shell/notify_done_forwarder.cc',
-        'shell/notify_done_forwarder.h',
         'shell/renderer/gc_extension.cc',
         'shell/renderer/gc_extension.h',
         'shell/renderer/shell_content_renderer_client.cc',
@@ -99,64 +157,6 @@
         'shell/renderer/shell_render_view_observer.h',
         'shell/renderer/webkit_test_runner.cc',
         'shell/renderer/webkit_test_runner.h',
-        'shell/shell.cc',
-        'shell/shell.h',
-        'shell/shell_android.cc',
-        'shell/shell_aura.cc',
-        'shell/shell_gtk.cc',
-        'shell/shell_mac.mm',
-        'shell/shell_win.cc',
-        'shell/shell_application_mac.h',
-        'shell/shell_application_mac.mm',
-        'shell/shell_browser_context.cc',
-        'shell/shell_browser_context.h',
-        'shell/shell_browser_main.cc',
-        'shell/shell_browser_main.h',
-        'shell/shell_browser_main_parts.cc',
-        'shell/shell_browser_main_parts.h',
-        'shell/shell_browser_main_parts_mac.mm',
-        'shell/shell_content_browser_client.cc',
-        'shell/shell_content_browser_client.h',
-        'shell/shell_devtools_delegate.cc',
-        'shell/shell_devtools_delegate.h',
-        'shell/shell_devtools_frontend.cc',
-        'shell/shell_devtools_frontend.h',
-        'shell/shell_download_manager_delegate.cc',
-        'shell/shell_download_manager_delegate.h',
-        'shell/shell_javascript_dialog_manager.cc',
-        'shell/shell_javascript_dialog_manager.h',
-        'shell/shell_javascript_dialog_gtk.cc',
-        'shell/shell_javascript_dialog_mac.mm',
-        'shell/shell_javascript_dialog_win.cc',
-        'shell/shell_javascript_dialog.h',
-        'shell/shell_layout_tests_android.cc',
-        'shell/shell_layout_tests_android.h',
-        'shell/shell_login_dialog_gtk.cc',
-        'shell/shell_login_dialog_mac.mm',
-        'shell/shell_login_dialog.cc',
-        'shell/shell_login_dialog.h',
-        'shell/shell_message_filter.cc',
-        'shell/shell_message_filter.h',
-        'shell/shell_net_log.cc',
-        'shell/shell_net_log.h',
-        'shell/shell_network_delegate.cc',
-        'shell/shell_network_delegate.h',
-        'shell/shell_plugin_service_filter.cc',
-        'shell/shell_plugin_service_filter.h',
-        'shell/shell_quota_permission_context.cc',
-        'shell/shell_quota_permission_context.h',
-        'shell/shell_resource_dispatcher_host_delegate.cc',
-        'shell/shell_resource_dispatcher_host_delegate.h',
-        'shell/shell_url_request_context_getter.cc',
-        'shell/shell_url_request_context_getter.h',
-        'shell/shell_web_contents_view_delegate_android.cc',
-        'shell/shell_web_contents_view_delegate_creator.h',
-        'shell/shell_web_contents_view_delegate_gtk.cc',
-        'shell/shell_web_contents_view_delegate_mac.mm',
-        'shell/shell_web_contents_view_delegate_win.cc',
-        'shell/shell_web_contents_view_delegate.h',
-        'shell/webkit_test_controller.cc',
-        'shell/webkit_test_controller.h',
       ],
       'msvs_settings': {
         'VCLinkerTool': {
@@ -220,8 +220,8 @@
             '../ui/ui.gyp:ui_resources',
           ],
           'sources/': [
-            ['exclude', 'shell/shell_gtk.cc'],
-            ['exclude', 'shell/shell_win.cc'],
+            ['exclude', 'shell/browser/shell_gtk.cc'],
+            ['exclude', 'shell/browser/shell_win.cc'],
           ],
         }],  # use_aura==1
         ['chromeos==1', {
@@ -241,8 +241,8 @@
         }],
         ['enable_plugins==0', {
           'sources/': [
-            ['exclude', 'shell/shell_plugin_service_filter.cc'],
-            ['exclude', 'shell/shell_plugin_service_filter.h'],
+            ['exclude', 'shell/browser/shell_plugin_service_filter.cc'],
+            ['exclude', 'shell/browser/shell_plugin_service_filter.h'],
           ],
         }]
       ],
@@ -723,6 +723,8 @@
             '../base/base.gyp:base_java',
             '../media/media.gyp:media_java',
             '../net/net.gyp:net_java',
+            '../tools/android/forwarder/forwarder.gyp:forwarder',
+            '../tools/android/md5sum/md5sum.gyp:md5sum',
             '../ui/ui.gyp:ui_java',
           ],
           'variables': {
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 59158ca..783106d 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -14,6 +14,7 @@
         '../skia/skia.gyp:skia',
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
+        '../ui/ui.gyp:ui_resources',
         '../ui/ui.gyp:ui_test_support',
         '../url/url.gyp:url_lib',
         'content_app_both',
@@ -124,6 +125,8 @@
         'test/net/url_request_slow_download_job.h',
         'test/net/url_request_abort_on_end_job.cc',
         'test/net/url_request_abort_on_end_job.h',
+        'test/ppapi_unittest.cc',
+        'test/ppapi_unittest.h',
         'test/test_content_browser_client.cc',
         'test/test_content_browser_client.h',
         'test/test_content_client.cc',
@@ -166,6 +169,7 @@
         }, {  # OS != "ios"
           'dependencies': [
             'content_child',
+            'content_gpu',
             'content_ppapi_plugin',
             'content_renderer',
             'content_utility',
@@ -182,7 +186,6 @@
             '../webkit/support/webkit_support.gyp:webkit_support_common',
             '../webkit/storage_browser.gyp:webkit_storage_browser',
             '../webkit/storage_common.gyp:webkit_storage_common',
-            '../webkit/storage_renderer.gyp:webkit_storage_renderer',
           ],
         }],
         ['OS == "win" or toolkit_uses_gtk == 1', {
@@ -280,7 +283,7 @@
         'browser/byte_stream_unittest.cc',
         'browser/child_process_security_policy_unittest.cc',
         'browser/device_orientation/data_fetcher_impl_android_unittest.cc',
-        'browser/device_orientation/device_motion_provider_unittest.cc',
+        'browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc',
         'browser/device_orientation/provider_unittest.cc',
         'browser/devtools/devtools_http_handler_unittest.cc',
         'browser/devtools/devtools_manager_unittest.cc',
@@ -390,6 +393,7 @@
         'browser/web_contents/web_drag_source_mac_unittest.mm',
         'browser/webui/web_ui_data_source_unittest.cc',
         'browser/webui/web_ui_message_handler_unittest.cc',
+        'child/fileapi/webfilewriter_base_unittest.cc',
         'child/indexed_db/indexed_db_dispatcher_unittest.cc',
         'child/indexed_db/proxy_webidbcursor_impl_unittest.cc',
         'child/npapi/plugin_lib_unittest.cc',
@@ -443,8 +447,6 @@
         'renderer/pepper/host_var_tracker_unittest.cc',
         'renderer/pepper/mock_resource.h',
         'renderer/pepper/pepper_broker_unittest.cc',
-        'renderer/pepper/ppapi_unittest.cc',
-        'renderer/pepper/ppapi_unittest.h',
         'renderer/pepper/quota_file_io_unittest.cc',
         'renderer/pepper/v8_var_converter_unittest.cc',
         'renderer/render_thread_impl_unittest.cc',
@@ -511,11 +513,11 @@
         '../webkit/browser/fileapi/mock_file_system_options.h',
         '../webkit/browser/fileapi/native_file_util_unittest.cc',
         '../webkit/browser/fileapi/obfuscated_file_util_unittest.cc',
-        '../webkit/browser/fileapi/sandbox_context_unittest.cc',
         '../webkit/browser/fileapi/sandbox_database_test_helper.cc',
         '../webkit/browser/fileapi/sandbox_database_test_helper.h',
         '../webkit/browser/fileapi/sandbox_directory_database_unittest.cc',
         '../webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc',
+        '../webkit/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc',
         '../webkit/browser/fileapi/sandbox_file_system_test_helper.cc',
         '../webkit/browser/fileapi/sandbox_file_system_test_helper.h',
         '../webkit/browser/fileapi/sandbox_isolated_origin_database_unittest.cc',
@@ -549,7 +551,6 @@
         '../webkit/browser/quota/quota_temporary_storage_evictor_unittest.cc',
         '../webkit/browser/quota/usage_tracker_unittest.cc',
         '../webkit/renderer/cpp_variant_unittest.cc',
-        '../webkit/renderer/fileapi/webfilewriter_base_unittest.cc',
       ],
       'conditions': [
         ['OS == "ios"', {
@@ -587,7 +588,6 @@
             '../webkit/renderer/webkit_renderer.gyp:webkit_renderer',
             '../webkit/storage_browser.gyp:webkit_storage_browser',
             '../webkit/storage_common.gyp:webkit_storage_common',
-            '../webkit/storage_renderer.gyp:webkit_storage_renderer',
             '../webkit/support/webkit_support.gyp:glue',
             '../webkit/support/webkit_support.gyp:glue_child',
           ],
@@ -747,6 +747,7 @@
             'content_gpu',
             'content_plugin',
             'content_renderer',
+            'content_resources.gyp:content_resources',
             'content_shell_lib',
             'content_shell_pak',
             'test_support_content',
@@ -869,6 +870,7 @@
             'test/content_test_launcher.cc',
             'test/cpp_binding_example.cc',
             'test/cpp_binding_example.h',
+            'test/webui_resource_browsertest.cc',
           ],
           'conditions': [
             ['chromeos==0', {
@@ -1238,7 +1240,6 @@
             '../media/media.gyp:media_test_support',
             '../net/net.gyp:net_java',
             '../net/net.gyp:net_javatests',
-            '../tools/android/forwarder2/forwarder.gyp:forwarder2',
           ],
           'variables': {
             'apk_name': 'ContentShellTest',
diff --git a/content/content_unittests.isolate b/content/content_unittests.isolate
index 94e3863..b39101c 100644
--- a/content/content_unittests.isolate
+++ b/content/content_unittests.isolate
@@ -40,6 +40,9 @@
         'isolate_dependency_tracked': [
           '<(PRODUCT_DIR)/content_unittests<(EXECUTABLE_SUFFIX)',
         ],
+        'isolate_dependency_untracked': [
+          '../tools/swarm_client/',
+        ],
       },
     }],
     ['OS=="mac"', {
diff --git a/content/content_utility.gypi b/content/content_utility.gypi
index 96aef6c..a152c95 100644
--- a/content/content_utility.gypi
+++ b/content/content_utility.gypi
@@ -12,6 +12,8 @@
     'public/utility/utility_thread.cc',
     'public/utility/utility_thread.h',
     'utility/utility_main.cc',
+    'utility/utility_main_thread.cc',
+    'utility/utility_main_thread.h',
     'utility/utility_thread_impl.cc',
     'utility/utility_thread_impl.h',
   ],
diff --git a/content/content_utility.target.darwin-arm.mk b/content/content_utility.target.darwin-arm.mk
index beaed0a..e0fd58f 100644
--- a/content/content_utility.target.darwin-arm.mk
+++ b/content/content_utility.target.darwin-arm.mk
@@ -26,6 +26,7 @@
 	content/public/utility/content_utility_client.cc \
 	content/public/utility/utility_thread.cc \
 	content/utility/utility_main.cc \
+	content/utility/utility_main_thread.cc \
 	content/utility/utility_thread_impl.cc
 
 
diff --git a/content/content_utility.target.darwin-mips.mk b/content/content_utility.target.darwin-mips.mk
index 372ff20..fca90ca 100644
--- a/content/content_utility.target.darwin-mips.mk
+++ b/content/content_utility.target.darwin-mips.mk
@@ -26,6 +26,7 @@
 	content/public/utility/content_utility_client.cc \
 	content/public/utility/utility_thread.cc \
 	content/utility/utility_main.cc \
+	content/utility/utility_main_thread.cc \
 	content/utility/utility_thread_impl.cc
 
 
diff --git a/content/content_utility.target.darwin-x86.mk b/content/content_utility.target.darwin-x86.mk
index 75f3d9e..f91db30 100644
--- a/content/content_utility.target.darwin-x86.mk
+++ b/content/content_utility.target.darwin-x86.mk
@@ -26,6 +26,7 @@
 	content/public/utility/content_utility_client.cc \
 	content/public/utility/utility_thread.cc \
 	content/utility/utility_main.cc \
+	content/utility/utility_main_thread.cc \
 	content/utility/utility_thread_impl.cc
 
 
diff --git a/content/content_utility.target.linux-arm.mk b/content/content_utility.target.linux-arm.mk
index beaed0a..e0fd58f 100644
--- a/content/content_utility.target.linux-arm.mk
+++ b/content/content_utility.target.linux-arm.mk
@@ -26,6 +26,7 @@
 	content/public/utility/content_utility_client.cc \
 	content/public/utility/utility_thread.cc \
 	content/utility/utility_main.cc \
+	content/utility/utility_main_thread.cc \
 	content/utility/utility_thread_impl.cc
 
 
diff --git a/content/content_utility.target.linux-mips.mk b/content/content_utility.target.linux-mips.mk
index 372ff20..fca90ca 100644
--- a/content/content_utility.target.linux-mips.mk
+++ b/content/content_utility.target.linux-mips.mk
@@ -26,6 +26,7 @@
 	content/public/utility/content_utility_client.cc \
 	content/public/utility/utility_thread.cc \
 	content/utility/utility_main.cc \
+	content/utility/utility_main_thread.cc \
 	content/utility/utility_thread_impl.cc
 
 
diff --git a/content/content_utility.target.linux-x86.mk b/content/content_utility.target.linux-x86.mk
index 75f3d9e..f91db30 100644
--- a/content/content_utility.target.linux-x86.mk
+++ b/content/content_utility.target.linux-x86.mk
@@ -26,6 +26,7 @@
 	content/public/utility/content_utility_client.cc \
 	content/public/utility/utility_thread.cc \
 	content/utility/utility_main.cc \
+	content/utility/utility_main_thread.cc \
 	content/utility/utility_thread_impl.cc
 
 
diff --git a/content/gpu/gpu_main_thread.cc b/content/gpu/gpu_main_thread.cc
new file mode 100644
index 0000000..65fef13
--- /dev/null
+++ b/content/gpu/gpu_main_thread.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/gpu/gpu_main_thread.h"
+
+#include "content/gpu/gpu_child_thread.h"
+#include "content/gpu/gpu_process.h"
+
+namespace content {
+
+GpuMainThread::GpuMainThread(const std::string& channel_id)
+    : base::Thread("Chrome_InProcGpuThread"),
+      channel_id_(channel_id),
+      gpu_process_(NULL) {
+}
+
+GpuMainThread::~GpuMainThread() {
+  Stop();
+}
+
+void GpuMainThread::Init() {
+  gpu_process_ = new GpuProcess();
+  // The process object takes ownership of the thread object, so do not
+  // save and delete the pointer.
+  gpu_process_->set_main_thread(new GpuChildThread(channel_id_));
+}
+
+void GpuMainThread::CleanUp() {
+  delete gpu_process_;
+}
+
+base::Thread* CreateGpuMainThread(const std::string& channel_id) {
+  return new GpuMainThread(channel_id);
+}
+
+}  // namespace content
diff --git a/content/gpu/gpu_main_thread.h b/content/gpu/gpu_main_thread.h
new file mode 100644
index 0000000..f34f431
--- /dev/null
+++ b/content/gpu/gpu_main_thread.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_GPU_GPU_MAIN_THREAD_H_
+#define CONTENT_GPU_GPU_MAIN_THREAD_H_
+
+#include "base/threading/thread.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class GpuProcess;
+
+// This class creates a GPU thread (instead of a GPU process), when running
+// with --in-process-gpu or --single-process.
+class GpuMainThread : public base::Thread {
+ public:
+  explicit GpuMainThread(const std::string& channel_id);
+  virtual ~GpuMainThread();
+
+ protected:
+  virtual void Init() OVERRIDE;
+  virtual void CleanUp() OVERRIDE;
+
+ private:
+  std::string channel_id_;
+  // Deleted in CleanUp() on the gpu thread, so don't use smart pointers.
+  GpuProcess* gpu_process_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuMainThread);
+};
+
+CONTENT_EXPORT base::Thread* CreateGpuMainThread(const std::string& channel_id);
+
+}  // namespace content
+
+#endif  // CONTENT_GPU_GPU_MAIN_THREAD_H_
diff --git a/content/public/android/java/res/layout/multi_field_time_picker_dialog.xml b/content/public/android/java/res/layout/multi_field_time_picker_dialog.xml
new file mode 100644
index 0000000..f6dfec3
--- /dev/null
+++ b/content/public/android/java/res/layout/multi_field_time_picker_dialog.xml
@@ -0,0 +1,122 @@
+<?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="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
+    android:orientation="vertical"
+    android:gravity="start">
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/time_picker_dialog_title"
+	android:textSize="20sp"
+	android:paddingStart="5dp"
+	android:paddingEnd="5dp"
+	android:paddingBottom="5dp"
+	android:paddingTop="5dp"
+	android:gravity="start"
+	android:textColor="#33B5E5"
+    />
+
+    <View
+	android:layout_width="fill_parent"
+	android:layout_height="2dp"
+	android:paddingBottom="5dp"
+	android:paddingTop="5dp"
+	android:background="#33B5E5"/>
+
+    <LinearLayout
+	android:layout_width="wrap_content"
+	android:layout_height="wrap_content"
+	android:layout_gravity="center_horizontal"
+	android:orientation="horizontal"
+	android:gravity="center">
+
+	<NumberPicker
+	    android:id="@+id/hour"
+	    android:layout_width="0dip"
+	    android:layout_weight=".2"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:layout_marginStart="4dip"
+	    android:layout_marginEnd="4dip"
+	    android:focusable="true"
+	    android:focusableInTouchMode="true"
+	    android:contentDescription="@string/accessibility_time_picker_hour"
+	    />
+	<TextView
+	    android:layout_width="wrap_content"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:text="@string/time_picker_dialog_hour_minute_separator"
+	    />
+	<NumberPicker
+	    android:id="@+id/minute"
+	    android:layout_width="0dip"
+	    android:layout_weight=".2"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:layout_marginStart="4dip"
+	    android:layout_marginEnd="4dip"
+	    android:focusable="true"
+	    android:focusableInTouchMode="true"
+	    android:contentDescription="@string/accessibility_time_picker_minute"
+	    />
+	<TextView
+	    android:id="@+id/second_colon"
+	    android:layout_width="wrap_content"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:text="@string/time_picker_dialog_minute_second_separator"	    />
+	<NumberPicker
+	    android:id="@+id/second"
+	    android:layout_width="0dip"
+	    android:layout_weight=".2"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:layout_marginStart="4dip"
+	    android:layout_marginEnd="4dip"
+	    android:focusable="true"
+	    android:focusableInTouchMode="true"
+	    android:contentDescription="@string/accessibility_time_picker_second"
+	    />
+	<TextView
+	    android:id="@+id/second_dot"
+	    android:layout_width="wrap_content"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:text="@string/time_picker_dialog_second_subsecond_separator"
+	    />
+	<NumberPicker
+	    android:id="@+id/milli"
+	    android:layout_width="0dip"
+	    android:layout_weight=".2"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:layout_marginStart="4dip"
+	    android:layout_marginEnd="4dip"
+	    android:focusable="true"
+	    android:focusableInTouchMode="true"
+	    android:contentDescription="@string/accessibility_time_picker_milli"
+	    />
+	<NumberPicker
+	    android:id="@+id/ampm"
+	    android:layout_width="0dip"
+	    android:layout_weight=".2"
+	    android:textSize="12sp"
+	    android:layout_height="wrap_content"
+	    android:layout_marginStart="4dip"
+	    android:layout_marginEnd="4dip"
+	    android:focusable="true"
+	    android:focusableInTouchMode="true"
+	    android:contentDescription="@string/accessibility_time_picker_ampm"
+	    />
+    </LinearLayout>
+</LinearLayout>
diff --git a/content/public/android/java/resource_map/org/chromium/content/R.java b/content/public/android/java/resource_map/org/chromium/content/R.java
index ea93683..4b0ef83 100644
--- a/content/public/android/java/resource_map/org/chromium/content/R.java
+++ b/content/public/android/java/resource_map/org/chromium/content/R.java
@@ -25,15 +25,23 @@
         public static int ondemand_overlay;
     }
     public static final class id {
+        public static int ampm;
         public static int date_picker;
-        public static int position_in_year;
+        public static int hour;
+        public static int milli;
+        public static int minute;
         public static int pickers;
+        public static int position_in_year;
+        public static int second;
+        public static int second_colon;
+        public static int second_dot;
         public static int time_picker;
         public static int year;
     }
     public static final class layout {
         public static int date_time_picker_dialog;
         public static int two_field_date_picker;
+        public static int multi_field_time_picker_dialog;
     }
     public static final class string {
         public static int accessibility_content_view;
@@ -54,6 +62,11 @@
         public static int media_player_error_title;
         public static int media_player_loading_video;
         public static int month_picker_dialog_title;
+        public static int time_picker_dialog_am;
+        public static int time_picker_dialog_hour_minute_separator;
+        public static int time_picker_dialog_minute_second_separator;
+        public static int time_picker_dialog_second_subsecond_separator;
+        public static int time_picker_dialog_pm;
         public static int week_picker_dialog_title;
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java b/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java
index 38cd2df..bf64b4f 100644
--- a/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java
+++ b/content/public/android/java/src/org/chromium/content/app/LibraryLoader.java
@@ -64,6 +64,14 @@
         }
     }
 
+    /**
+     * Checks if library is fully loaded and initialized.
+     */
+    public static boolean isInitialized() {
+        synchronized (sLock) {
+            return sInitialized;
+        }
+    }
 
     /**
      * Loads the library and blocks until the load completes. The caller is responsible
diff --git a/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java b/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java
index bf046f9..b1b72ba 100644
--- a/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java
+++ b/content/public/android/java/src/org/chromium/content/browser/AndroidBrowserProcess.java
@@ -14,6 +14,7 @@
 import org.chromium.content.common.ProcessInitException;
 
 @JNINamespace("content")
+// TODO(nyquist) Remove this class, and move the functionality to BrowserStartupController.
 public class AndroidBrowserProcess {
     private static final String TAG = "BrowserProcessMain";
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java
deleted file mode 100644
index f784c7a..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupConfig.java
+++ /dev/null
@@ -1,43 +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.
-
-package org.chromium.content.browser;
-
-import org.chromium.base.CalledByNative;
-import org.chromium.base.JNINamespace;
-/**
- * This class controls how C++ browser main loop is run.
- */
-@JNINamespace("content")
-public class BrowserStartupConfig {
-    public interface StartupCallback {
-        void run(int startupResult);
-    }
-
-    private static boolean sBrowserMayStartAsynchronously = false;
-    private static StartupCallback sBrowserStartupCompleteCallback = null;
-
-    @CalledByNative
-    private static boolean browserMayStartAsynchonously() {
-        return sBrowserMayStartAsynchronously;
-    }
-
-    @CalledByNative
-    private static void browserStartupComplete(int result) {
-        if(sBrowserStartupCompleteCallback != null) {
-            sBrowserStartupCompleteCallback.run(result);
-        }
-    }
-
-    /**
-     * Set browser to start asynchronously. May only be called before contentMain.start(). If it
-     * has been called then contentMain.start() will queue up a series of UI tasks to complete
-     * browser initialization.
-     * @param browserStartupCompleteCallback If not null called when browser startup is complete.
-     */
-    public static void setAsync(StartupCallback browserStartupCompleteCallback) {
-        sBrowserMayStartAsynchronously = true;
-        sBrowserStartupCompleteCallback = browserStartupCompleteCallback;
-    }
-}
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java
new file mode 100644
index 0000000..e6b3a67
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java
@@ -0,0 +1,235 @@
+// Copyright 2013 The Chromium 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.Context;
+import android.os.Handler;
+import android.util.Log;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.ThreadUtils;
+import org.chromium.content.common.ProcessInitException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class controls how C++ browser main loop is started and ensures it happens only once.
+ *
+ * It supports kicking off the startup sequence in an asynchronous way. Startup can be called as
+ * many times as needed (for instance, multiple activities for the same application), but the
+ * browser process will still only be initialized once. All requests to start the browser will
+ * always get their callback executed; if the browser process has already been started, the callback
+ * is called immediately, else it is called when initialization is complete.
+ *
+ * All communication with this class must happen on the main thread.
+ *
+ * This is a singleton, and stores a reference to the application context.
+ */
+@JNINamespace("content")
+public class BrowserStartupController {
+
+    public interface StartupCallback {
+        void onSuccess(boolean alreadyStarted);
+        void onFailure();
+    }
+
+    private static final String TAG = "BrowserStartupController";
+
+    // Helper constants for {@link StartupCallback#onSuccess}.
+    private static final boolean ALREADY_STARTED = true;
+    private static final boolean NOT_ALREADY_STARTED = false;
+
+    // Helper constants for {@link #executeEnqueuedCallbacks(int, boolean)}.
+    @VisibleForTesting
+    static final int STARTUP_SUCCESS = -1;
+    @VisibleForTesting
+    static final int STARTUP_FAILURE = 1;
+
+    private static BrowserStartupController sInstance;
+
+    private static boolean sBrowserMayStartAsynchronously = false;
+
+    private static void setAsynchronousStartupConfig() {
+        sBrowserMayStartAsynchronously = true;
+    }
+
+    @CalledByNative
+    private static boolean browserMayStartAsynchonously() {
+        return sBrowserMayStartAsynchronously;
+    }
+
+    @VisibleForTesting
+    @CalledByNative
+    static void browserStartupComplete(int result) {
+        if (sInstance != null) {
+            sInstance.executeEnqueuedCallbacks(result, NOT_ALREADY_STARTED);
+        }
+    }
+
+    // A list of callbacks that should be called when the async startup of the browser process is
+    // complete.
+    private final List<StartupCallback> mAsyncStartupCallbacks;
+
+    // The context is set on creation, but the reference is cleared after the browser process
+    // initialization has been started, since it is not needed anymore. This is to ensure the
+    // context is not leaked.
+    private Context mContext;
+
+    // Whether the async startup of the browser process has started.
+    private boolean mHasStartedInitializingBrowserProcess;
+
+    // Whether the async startup of the browser process is complete.
+    private boolean mAsyncStartupDone;
+
+    // This field is set after startup has been completed based on whether the startup was a success
+    // or not. It is used when later requests to startup come in that happen after the initial set
+    // of enqueued callbacks have been executed.
+    private boolean mStartupSuccess;
+
+    BrowserStartupController(Context context) {
+        mContext = context;
+        mAsyncStartupCallbacks = new ArrayList<StartupCallback>();
+    }
+
+    public static BrowserStartupController get(Context context) {
+        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
+        ThreadUtils.assertOnUiThread();
+        if (sInstance == null) {
+            sInstance = new BrowserStartupController(context.getApplicationContext());
+        }
+        return sInstance;
+    }
+
+    @VisibleForTesting
+    static BrowserStartupController overrideInstanceForTest(BrowserStartupController controller) {
+        if (sInstance == null) {
+            sInstance = controller;
+        }
+        return sInstance;
+    }
+
+    /**
+     * Start the browser process asynchronously. This will set up a queue of UI thread tasks to
+     * initialize the browser process.
+     * <p/>
+     * Note that this can only be called on the UI thread.
+     *
+     * @param callback the callback to be called when browser startup is complete.
+     */
+    public void startBrowserProcessesAsync(final StartupCallback callback) {
+        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
+        if (mAsyncStartupDone) {
+            // Browser process initialization has already been completed, so we can immediately post
+            // the callback.
+            postStartupCompleted(callback);
+            return;
+        }
+
+        // Browser process has not been fully started yet, so we defer executing the callback.
+        mAsyncStartupCallbacks.add(callback);
+
+        if (!mHasStartedInitializingBrowserProcess) {
+            // This is the first time we have been asked to start the browser process. We set the
+            // flag that indicates that we have kicked off starting the browser process.
+            mHasStartedInitializingBrowserProcess = true;
+
+            enableAsynchronousStartup();
+
+            // Try to initialize the Android browser process.
+            tryToInitializeBrowserProcess();
+        }
+    }
+
+    private void tryToInitializeBrowserProcess() {
+        try {
+            assert mContext != null;
+            boolean wasAlreadyInitialized = initializeAndroidBrowserProcess();
+            // The context is not needed anymore, so clear the member field to not leak.
+            mContext = null;
+            if (wasAlreadyInitialized) {
+                // Something has already initialized the browser process before we got to setup the
+                // async startup. This means that we will never get a callback, so manually call
+                // them now, and just assume that the startup was successful.
+                Log.w(TAG, "Browser process was initialized without BrowserStartupController");
+                enqueueCallbackExecution(STARTUP_SUCCESS, ALREADY_STARTED);
+            }
+        } catch (ProcessInitException e) {
+            Log.e(TAG, "Unable to start browser process.", e);
+            // ProcessInitException could mean one of two things:
+            // 1) The LibraryLoader failed.
+            // 2) ContentMain failed to start.
+            // It is unclear whether the browser tasks have already been started, and in case they
+            // have not, post a message to execute all the callbacks. Whichever call to
+            // executeEnqueuedCallbacks comes first will trigger the callbacks, but since the list
+            // of callbacks is then cleared, they will only be called once.
+            enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
+        }
+    }
+
+    public void addStartupCompletedObserver(StartupCallback callback) {
+        ThreadUtils.assertOnUiThread();
+        if (mAsyncStartupDone)
+            postStartupCompleted(callback);
+        else
+            mAsyncStartupCallbacks.add(callback);
+    }
+
+    private void executeEnqueuedCallbacks(int startupResult, boolean alreadyStarted) {
+        assert ThreadUtils.runningOnUiThread() : "Callback from browser startup from wrong thread.";
+        mAsyncStartupDone = true;
+        for (StartupCallback asyncStartupCallback : mAsyncStartupCallbacks) {
+            if (startupResult > 0) {
+                asyncStartupCallback.onFailure();
+            } else {
+                mStartupSuccess = true;
+                asyncStartupCallback.onSuccess(alreadyStarted);
+            }
+        }
+        // We don't want to hold on to any objects after we do not need them anymore.
+        mAsyncStartupCallbacks.clear();
+    }
+
+    private void enqueueCallbackExecution(final int startupFailure, final boolean alreadyStarted) {
+        new Handler().post(new Runnable() {
+            @Override
+            public void run() {
+                executeEnqueuedCallbacks(startupFailure, alreadyStarted);
+            }
+        });
+    }
+
+    private void postStartupCompleted(final StartupCallback callback) {
+        new Handler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mStartupSuccess)
+                    callback.onSuccess(ALREADY_STARTED);
+                else
+                    callback.onFailure();
+            }
+        });
+    }
+
+    /**
+     * Ensure that the browser process will be asynchronously started up. This also ensures that we
+     * get a call to {@link #browserStartupComplete} when the browser startup is complete.
+     */
+    @VisibleForTesting
+    void enableAsynchronousStartup() {
+        setAsynchronousStartupConfig();
+    }
+
+    /**
+     * @return whether the process was already initialized, so native was not instructed to start.
+     */
+    @VisibleForTesting
+    boolean initializeAndroidBrowserProcess() throws ProcessInitException {
+        return !AndroidBrowserProcess.init(mContext, AndroidBrowserProcess.MAX_RENDERERS_LIMIT);
+    }
+}
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
index 682ce08..9715f63 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnection.java
@@ -21,6 +21,7 @@
 
 import org.chromium.base.CalledByNative;
 import org.chromium.base.CpuFeatures;
+import org.chromium.base.SysUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.content.app.ChildProcessService;
 import org.chromium.content.common.CommandLine;
@@ -94,9 +95,9 @@
 
     // Synchronization: While most internal flow occurs on the UI thread, the public API
     // (specifically start and stop) may be called from any thread, hence all entry point methods
-    // into the class are synchronized on the ChildProcessConnection instance to protect access to
-    // these members. But see also the TODO where AsyncBoundServiceConnection is created.
-    private final Object mUiThreadLock = new Object();
+    // into the class are synchronized on the lock to protect access to these members. But see also
+    // the TODO where AsyncBoundServiceConnection is created.
+    private final Object mLock = new Object();
     private IChildProcessService mService = null;
     // Set to true when the service connect is finished, even if it fails.
     private boolean mServiceConnectComplete = false;
@@ -186,7 +187,7 @@
 
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
-            synchronized(mUiThreadLock) {
+            synchronized(mLock) {
                 // A flag from the parent class ensures we run the post-connection logic only once
                 // (instead of once per each ChildServiceConnection).
                 if (mServiceConnectComplete) {
@@ -252,7 +253,7 @@
     }
 
     IChildProcessService getService() {
-        synchronized(mUiThreadLock) {
+        synchronized(mLock) {
             return mService;
         }
     }
@@ -273,7 +274,7 @@
      *                    the command line parameters must instead be passed to setupConnection().
      */
     void start(String[] commandLine) {
-        synchronized(mUiThreadLock) {
+        synchronized(mLock) {
             TraceEvent.begin();
             assert !ThreadUtils.runningOnUiThread();
 
@@ -300,7 +301,7 @@
             FileDescriptorInfo[] filesToBeMapped,
             IChildProcessCallback processCallback,
             ConnectionCallbacks connectionCallbacks) {
-        synchronized(mUiThreadLock) {
+        synchronized(mLock) {
             TraceEvent.begin();
             assert mConnectionParams == null;
             mConnectionCallbacks = connectionCallbacks;
@@ -319,7 +320,7 @@
      * this multiple times.
      */
     void stop() {
-        synchronized(mUiThreadLock) {
+        synchronized(mLock) {
             mInitialBinding.unbind();
             mStrongBinding.unbind();
             mWaivedBinding.unbind();
@@ -420,7 +421,7 @@
      * renderer will not be killed immediately after the call.
      */
     void removeInitialBinding() {
-        synchronized(mUiThreadLock) {
+        synchronized(mLock) {
             if (!mInitialBinding.isBound()) {
                 // While it is safe to post and execute the unbinding multiple times, we prefer to
                 // avoid spamming the message queue.
@@ -430,7 +431,7 @@
         ThreadUtils.postOnUiThreadDelayed(new Runnable() {
             @Override
             public void run() {
-                synchronized(mUiThreadLock) {
+                synchronized(mLock) {
                     mInitialBinding.unbind();
                 }
             }
@@ -444,7 +445,7 @@
      * multiple bindings, we count the requests and unbind when the count drops to zero.
      */
     void attachAsActive() {
-        synchronized(mUiThreadLock) {
+        synchronized(mLock) {
             if (mService == null) {
                 Log.w(TAG, "The connection is not bound for " + mPID);
                 return;
@@ -456,17 +457,19 @@
         }
     }
 
-    private static final long DETACH_AS_ACTIVE_DELAY_MILLIS = 5 * 1000;  // Five seconds.
+    private static final long DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS = 5 * 1000;  // Five seconds.
 
     /**
-     * Called when the service is no longer considered active. Actual binding is removed after a
-     * fixed delay period so that the renderer will not be killed immediately after the call.
+     * Called when the service is no longer considered active. For devices that are not considered
+     * low memory the actual binding is removed after a fixed delay period so that the renderer will
+     * not be killed immediately after the call. We don't delay the unbinding for low memory devices
+     * to avoid putting the OS there on strain of having multiple renderers it can't kill.
      */
     void detachAsActive() {
         ThreadUtils.postOnUiThreadDelayed(new Runnable() {
             @Override
             public void run() {
-                synchronized(mUiThreadLock) {
+                synchronized(mLock) {
                     if (mService == null) {
                         Log.w(TAG, "The connection is not bound for " + mPID);
                         return;
@@ -478,14 +481,14 @@
                     }
                 }
             }
-        }, DETACH_AS_ACTIVE_DELAY_MILLIS);
+        }, SysUtils.isLowEndDevice() ? 0 : DETACH_AS_ACTIVE_HIGH_END_DELAY_MILLIS);
     }
 
     /**
      * @return The connection PID, or 0 if not yet connected.
      */
     int getPid() {
-        synchronized(mUiThreadLock) {
+        synchronized(mLock) {
             return mPID;
         }
     }
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 c1d7b0a..b047909 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
@@ -101,6 +101,9 @@
             setVerticalScrollBarEnabled(false);
         }
 
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+
         mContentViewCore = new ContentViewCore(context);
         mContentViewCore.initialize(this, this, nativeWebContents, windowAndroid,
                 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN ?
@@ -335,6 +338,11 @@
         mContentViewCore.getContentViewGestureHandler().setIgnoreSingleTap(value);
     }
 
+    /** @see ContentViewGestureHandler#setIgnoreRemainingTouchEvents */
+    public void setIgnoreRemainingTouchEvents() {
+        mContentViewCore.getContentViewGestureHandler().setIgnoreRemainingTouchEvents();
+    }
+
     /**
      * Modify the ContentView magnification level. The effect of calling this
      * method is exactly as after "pinch zoom".
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 6b65a9c..eac5605 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
@@ -757,8 +757,6 @@
         mContainerViewInternals = internalDispatcher;
 
         mContainerView.setWillNotDraw(false);
-        mContainerView.setFocusable(true);
-        mContainerView.setFocusableInTouchMode(true);
         mContainerView.setClickable(true);
 
         mZoomManager = new ZoomManager(mContext, this);
@@ -1375,7 +1373,20 @@
     public void evaluateJavaScript(
             String script, JavaScriptCallback callback) throws IllegalStateException {
         checkIsAlive();
-        nativeEvaluateJavaScript(mNativeContentViewCore, script, callback);
+        nativeEvaluateJavaScript(mNativeContentViewCore, script, callback, false);
+    }
+
+    /**
+     * Injects the passed Javascript code in the current page and evaluates it.
+     * If there is no page existing, a new one will be created.
+     *
+     * @param script The Javascript to execute.
+     * @throws IllegalStateException If the ContentView has been destroyed.
+     */
+    public void evaluateJavaScriptEvenIfNotYetNavigated(String script)
+            throws IllegalStateException {
+        checkIsAlive();
+        nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true);
     }
 
     /**
@@ -1870,7 +1881,10 @@
 
     private void handleTapOrPress(
             long timeMs, float xPix, float yPix, int isLongPressOrTap, boolean showPress) {
-        if (!mContainerView.isFocused()) mContainerView.requestFocus();
+        if (mContainerView.isFocusable() && mContainerView.isFocusableInTouchMode()
+                && !mContainerView.isFocused())  {
+            mContainerView.requestFocus();
+        }
 
         if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix);
 
@@ -1905,6 +1919,10 @@
         mZoomManager.updateMultiTouchSupport(supportsMultiTouchZoom);
     }
 
+    public void updateDoubleTapDragSupport(boolean supportsDoubleTapDrag) {
+        mContentViewGestureHandler.updateDoubleTapDragSupport(supportsDoubleTapDrag);
+    }
+
     public void selectPopupMenuItems(int[] indices) {
         if (mNativeContentViewCore != 0) {
             nativeSelectPopupMenuItems(mNativeContentViewCore, indices);
@@ -2865,6 +2883,7 @@
      * Enable or disable native accessibility features.
      */
     public void setNativeAccessibilityState(boolean enabled) {
+        if (mNativeContentViewCore == 0) return;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
             nativeSetAccessibilityEnabled(mNativeContentViewCore, enabled);
         }
@@ -3121,7 +3140,7 @@
     private native void nativeClearHistory(int nativeContentViewCoreImpl);
 
     private native void nativeEvaluateJavaScript(int nativeContentViewCoreImpl,
-            String script, JavaScriptCallback callback);
+            String script, JavaScriptCallback callback, boolean startRenderer);
 
     private native int nativeGetNativeImeAdapter(int nativeContentViewCoreImpl);
 
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 053aa9a..e82f01d 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
@@ -81,6 +81,10 @@
     // we will first show the press state, then trigger the click.
     private boolean mShowPressIsCalled;
 
+    // This flag is used for ignoring the remaining touch events, i.e., All the events until the
+    // next ACTION_DOWN. This is automatically set to false on the next ACTION_DOWN.
+    private boolean mIgnoreRemainingTouchEvents;
+
     // TODO(klobag): this is to avoid a bug in GestureDetector. With multi-touch,
     // mAlwaysInTapRegion is not reset. So when the last finger is up, onSingleTapUp()
     // will be mistakenly fired.
@@ -176,6 +180,7 @@
     static final int DOUBLE_TAP_DRAG_MODE_NONE = 0;
     static final int DOUBLE_TAP_DRAG_MODE_DETECTION_IN_PROGRESS = 1;
     static final int DOUBLE_TAP_DRAG_MODE_ZOOM = 2;
+    static final int DOUBLE_TAP_DRAG_MODE_DISABLED = 3;
 
     private class TouchEventTimeoutHandler implements Runnable {
         private static final int TOUCH_EVENT_TIMEOUT = 200;
@@ -510,6 +515,7 @@
 
                     @Override
                     public boolean onDoubleTapEvent(MotionEvent e) {
+                        if (isDoubleTapDragDisabled()) return false;
                         switch (e.getActionMasked()) {
                             case MotionEvent.ACTION_DOWN:
                                 sendShowPressCancelIfNecessary(e);
@@ -569,7 +575,8 @@
                     @Override
                     public void onLongPress(MotionEvent e) {
                         if (!mZoomManager.isScaleGestureDetectionInProgress() &&
-                                mDoubleTapDragMode == DOUBLE_TAP_DRAG_MODE_NONE) {
+                                (mDoubleTapDragMode == DOUBLE_TAP_DRAG_MODE_NONE ||
+                                 isDoubleTapDragDisabled())) {
                             sendShowPressCancelIfNecessary(e);
                             sendMotionEventAsGesture(GESTURE_LONG_PRESS, e, null);
                         }
@@ -664,6 +671,7 @@
      *              to send. This argument is an optional and can be null.
      */
     void endDoubleTapDragMode(MotionEvent event) {
+        if (isDoubleTapDragDisabled()) return;
         if (mDoubleTapDragMode == DOUBLE_TAP_DRAG_MODE_ZOOM) {
             if (event == null) event = obtainActionCancelMotionEvent();
             pinchEnd(event.getEventTime());
@@ -763,12 +771,32 @@
     }
 
     /**
+     * Cancel the current touch event sequence by sending ACTION_CANCEL and ignore all the
+     * subsequent events until the next ACTION_DOWN.
+     *
+     * One example usecase is stop processing the touch events when showing context popup menu.
+     */
+    public void setIgnoreRemainingTouchEvents() {
+        onTouchEvent(obtainActionCancelMotionEvent());
+        mIgnoreRemainingTouchEvents = true;
+    }
+
+    /**
      * Handle the incoming MotionEvent.
      * @return Whether the event was handled.
      */
     boolean onTouchEvent(MotionEvent event) {
         try {
             TraceEvent.begin("onTouchEvent");
+
+            if (mIgnoreRemainingTouchEvents) {
+                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                    mIgnoreRemainingTouchEvents = false;
+                } else {
+                    return false;
+                }
+            }
+
             mLongPressDetector.cancelLongPressIfNeeded(event);
             mSnapScrollController.setSnapScrollingMode(event);
             // Notify native that scrolling has stopped whenever a down action is processed prior to
@@ -1148,4 +1176,15 @@
     boolean hasScheduledTouchTimeoutEventForTesting() {
         return mTouchEventTimeoutHandler.hasScheduledTimeoutEventForTesting();
     }
+
+    public void updateDoubleTapDragSupport(boolean supportDoubleTapDrag) {
+        assert (mDoubleTapDragMode == DOUBLE_TAP_DRAG_MODE_DISABLED ||
+                mDoubleTapDragMode == DOUBLE_TAP_DRAG_MODE_NONE);
+        mDoubleTapDragMode = supportDoubleTapDrag ?
+                DOUBLE_TAP_DRAG_MODE_NONE : DOUBLE_TAP_DRAG_MODE_DISABLED;
+    }
+
+    private boolean isDoubleTapDragDisabled() {
+        return mDoubleTapDragMode == DOUBLE_TAP_DRAG_MODE_DISABLED;
+    }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java b/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java
index 54a0c56..eb9cf0e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java
+++ b/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java
@@ -11,17 +11,16 @@
 import android.hardware.SensorManager;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.Looper;
 import android.util.Log;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 
 import org.chromium.base.CalledByNative;
+import org.chromium.base.CollectionUtil;
 import org.chromium.base.JNINamespace;
 import org.chromium.base.WeakContext;
 
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -38,14 +37,14 @@
     private Handler mHandler;
 
     // The lock to access the mHandler.
-    private Object mHandlerLock = new Object();
+    private final Object mHandlerLock = new Object();
 
     // Non-zero if and only if we're listening for events.
     // To avoid race conditions on the C++ side, access must be synchronized.
     private int mNativePtr;
 
     // The lock to access the mNativePtr.
-    private Object mNativePtrLock = new Object();
+    private final Object mNativePtrLock = new Object();
 
     // The acceleration vector including gravity expressed in the body frame.
     private float[] mAccelerationIncludingGravityVector;
@@ -67,17 +66,17 @@
     static final int DEVICE_ORIENTATION = 0;
     static final int DEVICE_MOTION = 1;
 
-    static final ImmutableSet<Integer> DEVICE_ORIENTATION_SENSORS = ImmutableSet.of(
+    static final Set<Integer> DEVICE_ORIENTATION_SENSORS = CollectionUtil.newHashSet(
             Sensor.TYPE_ACCELEROMETER,
             Sensor.TYPE_MAGNETIC_FIELD);
 
-    static final ImmutableSet<Integer> DEVICE_MOTION_SENSORS = ImmutableSet.of(
+    static final Set<Integer> DEVICE_MOTION_SENSORS = CollectionUtil.newHashSet(
             Sensor.TYPE_ACCELEROMETER,
             Sensor.TYPE_LINEAR_ACCELERATION,
             Sensor.TYPE_GYROSCOPE);
 
     @VisibleForTesting
-    final Set<Integer> mActiveSensors = Sets.newHashSet();
+    final Set<Integer> mActiveSensors = new HashSet<Integer>();
     boolean mDeviceMotionIsActive = false;
     boolean mDeviceOrientationIsActive = false;
 
@@ -122,7 +121,7 @@
 
     @CalledByNative
     public int getNumberActiveDeviceMotionSensors() {
-        Set<Integer> deviceMotionSensors = Sets.newHashSet(DEVICE_MOTION_SENSORS);
+        Set<Integer> deviceMotionSensors = new HashSet<Integer>(DEVICE_MOTION_SENSORS);
         deviceMotionSensors.removeAll(mActiveSensors);
         return DEVICE_MOTION_SENSORS.size() - deviceMotionSensors.size();
     }
@@ -138,7 +137,7 @@
      */
     @CalledByNative
     public void stop(int eventType) {
-        Set<Integer> sensorsToRemainActive = Sets.newHashSet();
+        Set<Integer> sensorsToRemainActive = new HashSet<Integer>();
         synchronized (mNativePtrLock) {
             switch (eventType) {
                 case DEVICE_ORIENTATION:
@@ -156,7 +155,7 @@
                     return;
             }
 
-            Set<Integer> sensorsToDeactivate = Sets.newHashSet(mActiveSensors);
+            Set<Integer> sensorsToDeactivate = new HashSet<Integer>(mActiveSensors);
             sensorsToDeactivate.removeAll(sensorsToRemainActive);
             unregisterSensors(sensorsToDeactivate);
             setEventTypeActive(eventType, false);
@@ -298,9 +297,9 @@
      *                            activated. When false the method return true if at least one
      *                            sensor in sensorTypes could be activated.
      */
-    private boolean registerSensors(Iterable<Integer> sensorTypes, int rateInMilliseconds,
+    private boolean registerSensors(Set<Integer> sensorTypes, int rateInMilliseconds,
             boolean failOnMissingSensor) {
-        Set<Integer> sensorsToActivate = Sets.newHashSet(sensorTypes);
+        Set<Integer> sensorsToActivate = new HashSet<Integer>(sensorTypes);
         sensorsToActivate.removeAll(mActiveSensors);
         boolean success = false;
 
@@ -442,6 +441,7 @@
             mSensorManager = sensorManager;
         }
 
+        @Override
         public boolean registerListener(SensorEventListener listener, int sensorType, int rate,
                 Handler handler) {
             List<Sensor> sensors = mSensorManager.getSensorList(sensorType);
@@ -451,6 +451,7 @@
             return mSensorManager.registerListener(listener, sensors.get(0), rate, handler);
         }
 
+        @Override
         public void unregisterListener(SensorEventListener listener, int sensorType) {
             List<Sensor> sensors = mSensorManager.getSensorList(sensorType);
             if (!sensors.isEmpty()) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java b/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java
index 5d0de5a..b8f2085 100644
--- a/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java
+++ b/content/public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java
@@ -5,6 +5,7 @@
 package org.chromium.content.browser;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.MediaMetadataRetriever;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
@@ -63,6 +64,12 @@
         ConnectivityManager mConnectivityManager =
                 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
         if (mConnectivityManager != null) {
+            if (context.checkCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_NETWORK_STATE) !=
+                    PackageManager.PERMISSION_GRANTED) {
+                return new MediaMetadata(0, 0, 0, false);
+            }
+
             NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
             if (info == null) {
                 return new MediaMetadata(durationInMilliseconds, width, height, success);
@@ -100,12 +107,18 @@
                 }
                 retriever.setDataSource(url, headersMap);
             }
-            durationInMilliseconds = Integer.parseInt(
-                    retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
-            width = Integer.parseInt(
-                    retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
-            height = Integer.parseInt(
-                    retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
+            String duration = retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_DURATION);
+            String videoWidth = retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
+            String videoHeight = retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
+            if (duration == null || videoWidth == null || videoHeight == null) {
+                return new MediaMetadata(durationInMilliseconds, width, height, success);
+            }
+            durationInMilliseconds = Integer.parseInt(duration);
+            width = Integer.parseInt(videoWidth);
+            height = Integer.parseInt(videoHeight);
             success = true;
         } catch (IllegalArgumentException e) {
             Log.e(TAG, "Invalid url: " + e);
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java
index 0c58217..9ca9f95 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java
@@ -28,10 +28,11 @@
             @Override
             public void replaceDateTime(
                     int dialogType,
-                    int year, int month, int day, int hour, int minute, int second, int week) {
+                    int year, int month, int day, int hour, int minute,
+                    int second, int milli, int week) {
                 nativeReplaceDateTime(mNativeDateTimeChooserAndroid,
                         dialogType,
-                        year, month, day, hour, minute, second, week);
+                        year, month, day, hour, minute, second, milli, week);
             }
 
             @Override
@@ -42,9 +43,11 @@
     }
 
     private void showDialog(int dialogType, int year, int month, int monthDay,
-            int hour, int minute, int second, int week, double min, double max) {
-        mInputDialogContainer.showDialog(dialogType, year, month, monthDay,
-                hour, minute, second, week, min, max);
+                            int hour, int minute, int second, int milli,
+                            int week, double min, double max, double step) {
+        mInputDialogContainer.showDialog(
+            dialogType, year, month, monthDay,
+            hour, minute, second, milli, week, min, max, step);
     }
 
     @CalledByNative
@@ -52,16 +55,21 @@
             ContentViewCore contentViewCore,
             int nativeDateTimeChooserAndroid, int dialogType,
             int year, int month, int day,
-            int hour, int minute, int second, int week, double min, double max) {
+            int hour, int minute, int second, int milli, int week,
+            double min, double max, double step) {
         DateTimeChooserAndroid chooser =
                 new DateTimeChooserAndroid(
-                        contentViewCore.getContext(), nativeDateTimeChooserAndroid);
-        chooser.showDialog(dialogType, year, month, day, hour, minute, second, week, min, max);
+                        contentViewCore.getContext(),
+                        nativeDateTimeChooserAndroid);
+        chooser.showDialog(
+            dialogType, year, month, day, hour, minute, second, milli,
+            week, min, max, step);
         return chooser;
     }
 
     @CalledByNative
-    private static void initializeDateInputTypes(int textInputTypeDate, int textInputTypeDateTime,
+    private static void initializeDateInputTypes(
+            int textInputTypeDate, int textInputTypeDateTime,
             int textInputTypeDateTimeLocal, int textInputTypeMonth,
             int textInputTypeTime, int textInputTypeWeek) {
         InputDialogContainer.initializeInputTypes(textInputTypeDate,
@@ -69,9 +77,10 @@
                 textInputTypeMonth, textInputTypeTime, textInputTypeWeek);
     }
 
-    private native void nativeReplaceDateTime(int nativeDateTimeChooserAndroid,
-            int dialogType,
-            int year, int month, int day, int hour, int minute, int second, int week);
+    private native void nativeReplaceDateTime(
+            int nativeDateTimeChooserAndroid, int dialogType,
+            int year, int month, int day, int hour, int minute,
+            int second, int milli, int week);
 
     private native void nativeCancelDialog(int nativeDateTimeChooserAndroid);
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java b/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java
index 07dd7e0..fffe130 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java
@@ -19,6 +19,7 @@
 import android.widget.TimePicker;
 
 import org.chromium.content.browser.input.DateTimePickerDialog.OnDateTimeSetListener;
+import org.chromium.content.browser.input.MultiFieldTimePickerDialog.OnMultiFieldTimeSetListener;
 import org.chromium.content.browser.input.TwoFieldDatePickerDialog;
 import org.chromium.content.R;
 
@@ -32,7 +33,7 @@
     interface InputActionDelegate {
         void cancelDateTimeDialog();
         void replaceDateTime(int dialogType,
-                int year, int month, int day, int hour, int minute, int second, int week);
+            int year, int month, int day, int hour, int minute, int second, int milli, int week);
     }
 
     // Default values used in Time representations of selected date/time before formatting.
@@ -93,7 +94,7 @@
     }
 
     private Time normalizeTime(int year, int month, int monthDay,
-            int hour, int minute, int second)  {
+                               int hour, int minute, int second) {
         Time result = new Time();
         if (year == 0 && month == 0 && monthDay == 0 && hour == 0 &&
                 minute == 0 && second == 0) {
@@ -108,7 +109,8 @@
     }
 
     void showDialog(final int dialogType, int year, int month, int monthDay,
-            int hour, int minute, int second, int week, double min, double max) {
+                    int hour, int minute, int second, int milli, int week,
+                    double min, double max, double step) {
         if (isDialogShowing()) mDialog.dismiss();
 
         // Java Date dialogs like longs but Blink prefers doubles..
@@ -118,7 +120,12 @@
         // In any case the cast here is safe given the above restrictions.
         long minTime = (long) min;
         long maxTime = (long) max;
+        int stepTime = (int) step;
 
+        if (milli > 1000) {
+            second += milli / 1000;
+            milli %= 1000;
+        }
         Time time = normalizeTime(year, month, monthDay, hour, minute, second);
         if (dialogType == sTextInputTypeDate) {
             DatePickerDialog dialog = new DatePickerDialog(mContext,
@@ -129,9 +136,12 @@
             dialog.setTitle(mContext.getText(R.string.date_picker_dialog_title));
             mDialog = dialog;
         } else if (dialogType == sTextInputTypeTime) {
-            mDialog = TimeDialog.create(mContext, new TimeListener(dialogType),
-                    time.hour, time.minute, DateFormat.is24HourFormat(mContext),
-                    minTime, maxTime);
+            mDialog = new MultiFieldTimePickerDialog(
+                mContext, 0 /* theme */ ,
+                time.hour, time.minute, time.second, milli,
+                (int) minTime, (int) maxTime, stepTime,
+                DateFormat.is24HourFormat(mContext),
+                new FullTimeListener(dialogType));
         } else if (dialogType == sTextInputTypeDateTime ||
                 dialogType == sTextInputTypeDateTimeLocal) {
             mDialog = new DateTimePickerDialog(mContext,
@@ -172,7 +182,7 @@
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         mDialogAlreadyDismissed = true;
-                        mInputActionDelegate.replaceDateTime(dialogType, 0, 0, 0, 0, 0, 0, 0);
+                        mInputActionDelegate.replaceDateTime(dialogType, 0, 0, 0, 0, 0, 0, 0, 0);
                     }
                 });
 
@@ -223,6 +233,22 @@
         }
     }
 
+  private class FullTimeListener implements OnMultiFieldTimeSetListener {
+        private final int mDialogType;
+        FullTimeListener(int dialogType) {
+            mDialogType = dialogType;
+        }
+
+        @Override
+        public void onTimeSet(int hourOfDay, int minute, int second, int milli) {
+            if (!mDialogAlreadyDismissed) {
+                setFieldDateTimeValue(mDialogType,
+                        YEAR_DEFAULT, MONTH_DEFAULT, MONTHDAY_DEFAULT,
+                        hourOfDay, minute, second, milli, WEEK_DEFAULT, HTML_TIME_FORMAT);
+            }
+        }
+    }
+
     private class DateTimeListener implements OnDateTimeSetListener {
         private final boolean mLocal;
         private final int mDialogType;
@@ -274,6 +300,17 @@
         mDialogAlreadyDismissed = true;
 
         mInputActionDelegate.replaceDateTime(dialogType,
-                year, month, monthDay, hourOfDay, minute, 0 /* second */, week);
+            year, month, monthDay, hourOfDay, minute, 0 /* second */, 0 /* milli */, week);
+    }
+
+    private void setFieldDateTimeValue(int dialogType,
+            int year, int month, int monthDay, int hourOfDay,
+            int minute, int second, int milli, int week, String dateFormat) {
+        // Prevents more than one callback being sent to the native
+        // side when the dialog triggers multiple events.
+        mDialogAlreadyDismissed = true;
+
+        mInputActionDelegate.replaceDateTime(
+            dialogType, year, month, monthDay, hourOfDay, minute, second, milli, week);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/MultiFieldTimePickerDialog.java b/content/public/android/java/src/org/chromium/content/browser/input/MultiFieldTimePickerDialog.java
new file mode 100644
index 0000000..f2ab32b
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/input/MultiFieldTimePickerDialog.java
@@ -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.
+
+package org.chromium.content.browser.input;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.NumberPicker;
+
+import org.chromium.content.R;
+
+import java.util.ArrayList;
+
+/**
+ * A time picker dialog with upto 5 number pickers left to right:
+ *  hour, minute, second, milli, AM/PM.
+ *
+ * If is24hourFormat is true then AM/PM picker is not displayed and
+ * hour range is 0..23. Otherwise hour range is 1..12.
+ * The milli picker is not displayed if step >= SECOND_IN_MILLIS
+ * The second picker is not displayed if step >= MINUTE_IN_MILLIS.
+ */
+public class MultiFieldTimePickerDialog
+        extends AlertDialog implements OnClickListener {
+
+    private final NumberPicker mHourSpinner;
+    private final NumberPicker mMinuteSpinner;
+    private final NumberPicker mSecSpinner;
+    private final NumberPicker mMilliSpinner;
+    private final NumberPicker mAmPmSpinner;
+    private final OnMultiFieldTimeSetListener mListener;
+    private final int mStep;
+    private final int mBaseMilli;
+    private final boolean mIs24hourFormat;
+
+    public interface OnMultiFieldTimeSetListener {
+        void onTimeSet(int hourOfDay, int minute, int second, int milli);
+    }
+
+    private final static int SECOND_IN_MILLIS = 1000;
+    private final static int MINUTE_IN_MILLIS = 60 * SECOND_IN_MILLIS;
+    private final static int HOUR_IN_MILLIS = 60 * MINUTE_IN_MILLIS;
+
+    public MultiFieldTimePickerDialog(
+            Context context,
+            int theme,
+            int hour, int minute, int second, int milli,
+            int min, int max, int step, boolean is24hourFormat,
+            OnMultiFieldTimeSetListener listener) {
+        super(context, theme);
+        mListener = listener;
+        mStep = step;
+        mIs24hourFormat = is24hourFormat;
+
+        if (min >= max) {
+            min = 0;
+            max = 24 * HOUR_IN_MILLIS - 1;
+        }
+        if (step < 0 || step >= 24 * HOUR_IN_MILLIS) {
+            step = MINUTE_IN_MILLIS;
+        }
+
+        LayoutInflater inflater =
+                (LayoutInflater) context.getSystemService(
+                        Context.LAYOUT_INFLATER_SERVICE);
+        View view = inflater.inflate(R.layout.multi_field_time_picker_dialog, null);
+        setView(view);
+
+        mHourSpinner = (NumberPicker) view.findViewById(R.id.hour);
+        mMinuteSpinner = (NumberPicker) view.findViewById(R.id.minute);
+        mSecSpinner = (NumberPicker) view.findViewById(R.id.second);
+        mMilliSpinner = (NumberPicker) view.findViewById(R.id.milli);
+        mAmPmSpinner = (NumberPicker) view.findViewById(R.id.ampm);
+
+        int minHour = min / HOUR_IN_MILLIS;
+        int maxHour = max / HOUR_IN_MILLIS;
+        min -= minHour * HOUR_IN_MILLIS;
+        max -= maxHour * HOUR_IN_MILLIS;
+
+        if (minHour == maxHour) {
+            mHourSpinner.setEnabled(false);
+            hour = minHour;
+        }
+
+        if (is24hourFormat) {
+            mAmPmSpinner.setVisibility(View.GONE);
+        } else {
+            int minAmPm = minHour / 12;
+            int maxAmPm = maxHour / 12;
+            int amPm = hour / 12;
+            mAmPmSpinner.setMinValue(minAmPm);
+            mAmPmSpinner.setMaxValue(maxAmPm);
+            mAmPmSpinner.setDisplayedValues(new String[] {
+                    context.getString(R.string.time_picker_dialog_am),
+                    context.getString(R.string.time_picker_dialog_pm)
+                });
+
+            hour %= 12;
+            if (hour == 0) {
+                hour = 12;
+            }
+            if (minAmPm == maxAmPm) {
+                mAmPmSpinner.setEnabled(false);
+                amPm = minAmPm;
+
+                minHour %= 12;
+                maxHour %= 12;
+                if (minHour == 0 && maxHour == 0) {
+                    minHour = 12;
+                    maxHour = 12;
+                } else if (minHour == 0) {
+                    minHour = maxHour;
+                    maxHour = 12;
+                } else if (maxHour == 0) {
+                    maxHour = 12;
+                }
+            } else {
+                minHour = 1;
+                maxHour = 12;
+            }
+            mAmPmSpinner.setValue(amPm);
+        }
+
+        if (minHour == maxHour) {
+            mHourSpinner.setEnabled(false);
+        }
+        mHourSpinner.setMinValue(minHour);
+        mHourSpinner.setMaxValue(maxHour);
+        mHourSpinner.setValue(hour);
+
+        NumberFormatter twoDigitPaddingFormatter = new NumberFormatter("%02d");
+
+        int minMinute = min / MINUTE_IN_MILLIS;
+        int maxMinute = max / MINUTE_IN_MILLIS;
+        min -= minMinute * MINUTE_IN_MILLIS;
+        max -= maxMinute * MINUTE_IN_MILLIS;
+
+        if (minHour == maxHour) {
+            mMinuteSpinner.setMinValue(minMinute);
+            mMinuteSpinner.setMaxValue(maxMinute);
+            if (minMinute == maxMinute) {
+                // Set this otherwise the box is empty until you stroke it.
+                mMinuteSpinner.setDisplayedValues(
+                    new String[] { twoDigitPaddingFormatter.format(minMinute) });
+                mMinuteSpinner.setEnabled(false);
+                minute = minMinute;
+            }
+        } else {
+            mMinuteSpinner.setMinValue(0);
+            mMinuteSpinner.setMaxValue(59);
+        }
+
+        if (step >= HOUR_IN_MILLIS) {
+            mMinuteSpinner.setEnabled(false);
+        }
+
+        mMinuteSpinner.setValue(minute);
+        mMinuteSpinner.setFormatter(twoDigitPaddingFormatter);
+
+        if (step >= MINUTE_IN_MILLIS) {
+            // Remove the ':' in front of the second spinner as well.
+            view.findViewById(R.id.second_colon).setVisibility(View.GONE);
+            mSecSpinner.setVisibility(View.GONE);
+        }
+
+        int minSecond = min / SECOND_IN_MILLIS;
+        int maxSecond = max / SECOND_IN_MILLIS;
+        min -= minSecond * SECOND_IN_MILLIS;
+        max -= maxSecond * SECOND_IN_MILLIS;
+
+        if (minHour == maxHour && minMinute == maxMinute) {
+            mSecSpinner.setMinValue(minSecond);
+            mSecSpinner.setMaxValue(maxSecond);
+            if (minSecond == maxSecond) {
+                // Set this otherwise the box is empty until you stroke it.
+                mSecSpinner.setDisplayedValues(
+                    new String[] { twoDigitPaddingFormatter.format(minSecond) });
+                mSecSpinner.setEnabled(false);
+                second = minSecond;
+            }
+        } else {
+            mSecSpinner.setMinValue(0);
+            mSecSpinner.setMaxValue(59);
+        }
+
+        mSecSpinner.setValue(second);
+        mSecSpinner.setFormatter(twoDigitPaddingFormatter);
+
+        if (step >= SECOND_IN_MILLIS) {
+            // Remove the '.' in front of the milli spinner as well.
+            view.findViewById(R.id.second_dot).setVisibility(View.GONE);
+            mMilliSpinner.setVisibility(View.GONE);
+        }
+
+        // Round to the nearest step.
+        milli = ((milli + step / 2) / step) * step;
+        if (step == 1 || step == 10 || step == 100) {
+            if (minHour == maxHour && minMinute == maxMinute &&
+                minSecond == maxSecond) {
+                mMilliSpinner.setMinValue(min / step);
+                mMilliSpinner.setMaxValue(max / step);
+
+                if (min == max) {
+                    mMilliSpinner.setEnabled(false);
+                    milli = min;
+                }
+            } else {
+                mMilliSpinner.setMinValue(0);
+                mMilliSpinner.setMaxValue(999 / step);
+            }
+
+            if (step == 1) {
+                mMilliSpinner.setFormatter(new NumberFormatter("%03d"));
+            } else if (step == 10) {
+                mMilliSpinner.setFormatter(new NumberFormatter("%02d"));
+            } else if (step == 100) {
+                mMilliSpinner.setFormatter(new NumberFormatter("%d"));
+            }
+            mMilliSpinner.setValue(milli / step);
+            mBaseMilli = 0;
+        } else if (step < SECOND_IN_MILLIS) {
+            // Non-decimal step value.
+            ArrayList<String> strValue = new ArrayList<String>();
+            for (int i = min; i < max; i += step) {
+                strValue.add(String.format("%03d", i));
+            }
+            mMilliSpinner.setMinValue(0);
+            mMilliSpinner.setMaxValue(strValue.size() - 1);
+            mMilliSpinner.setValue( (milli - min) / step);
+            mMilliSpinner.setDisplayedValues(
+                strValue.toArray(new String[strValue.size()]));
+            mBaseMilli = min;
+        } else {
+            mBaseMilli = 0;
+        }
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        notifyDateSet();
+    }
+
+    private void notifyDateSet() {
+        int hour = mHourSpinner.getValue();
+        int minute = mMinuteSpinner.getValue();
+        int sec = mSecSpinner.getValue();
+        int milli = mMilliSpinner.getValue() * mStep + mBaseMilli;
+        if (!mIs24hourFormat) {
+            int ampm = mAmPmSpinner.getValue();
+            if (hour == 12) {
+                hour = 0;
+            }
+            hour += ampm * 12;
+        }
+        mListener.onTimeSet(hour, minute, sec, milli);
+    }
+
+    @Override
+    protected void onStop() {
+        if (Build.VERSION.SDK_INT >= 16) {
+            // The default behavior of dialogs changed in JellyBean and onwards.
+            // Dismissing a dialog (by pressing back for example)
+            // applies the chosen date. This code is added here so that the custom
+            // pickers behave the same as the internal DatePickerDialog.
+            notifyDateSet();
+        }
+        super.onStop();
+    }
+
+    private static class NumberFormatter implements NumberPicker.Formatter {
+        private final String mFormat;
+
+        NumberFormatter(String format) {
+            mFormat = format;
+        }
+
+        @Override
+        public String format(int value) {
+            return String.format(mFormat, value);
+        }
+    }
+}
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/TimeDialog.java b/content/public/android/java/src/org/chromium/content/browser/input/TimeDialog.java
deleted file mode 100644
index 60d196f..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/input/TimeDialog.java
+++ /dev/null
@@ -1,70 +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.
-
-package org.chromium.content.browser.input;
-
-import android.app.TimePickerDialog;
-import android.content.Context;
-import android.text.format.Time;
-import android.widget.TimePicker;
-
-/**
- * Wrapper on {@code TimePickerDialog} to control min and max times.
- */
-public class TimeDialog extends TimePickerDialog {
-
-    private Time mMinTime;
-    private Time mMaxTime;
-
-    public static TimeDialog create(Context context, OnTimeSetListener callBack,
-            int hour, int minute, boolean is24HourView, long min, long max) {
-        Time time = getBoundedTime(hour, minute, min, max);
-        return new TimeDialog(context, callBack, time.hour, time.minute,
-                is24HourView, min, max);
-    }
-
-    private TimeDialog(
-            Context context, OnTimeSetListener callBack,
-            int hourOfDay, int minute, boolean is24HourView, long min, long max) {
-        super(context, callBack, hourOfDay, minute, is24HourView);
-        if (min >= max) {
-            mMinTime = getTimeForHourAndMinute(0, 0);
-            mMaxTime = getTimeForHourAndMinute(23, 59);
-        } else {
-            mMinTime = getTimeForMillis(min);
-            mMaxTime = getTimeForMillis(max);
-        }
-     }
-
-     @Override
-     public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
-         Time time = getBoundedTime(hourOfDay, minute,
-                 mMinTime.toMillis(true), mMaxTime.toMillis(true));
-         super.onTimeChanged(view, time.hour, time.minute);
-         updateTime(time.hour, time.minute);
-     }
-
-     private static Time getBoundedTime(int hour, int minute,
-             long min, long max) {
-         Time time = getTimeForHourAndMinute(hour, minute);
-         if (time.toMillis(true) < min) {
-             return getTimeForMillis(min);
-         } else if (time.toMillis(true) > max) {
-             return getTimeForMillis(max);
-         }
-         return time;
-     }
-
-     private static Time getTimeForMillis(long millis) {
-         Time time = new Time("GMT");
-         time.set(millis);
-         return time;
-     }
-
-     private static Time getTimeForHourAndMinute(int hour, int minute) {
-         Time time = new Time("GMT");
-         time.set(0, minute, hour, 1, 0, 1970);
-         return time;
-     }
-}
diff --git a/content/public/android/java/strings/android_content_strings.grd b/content/public/android/java/strings/android_content_strings.grd
index 69aabb4..6589a0f 100644
--- a/content/public/android/java/strings/android_content_strings.grd
+++ b/content/public/android/java/strings/android_content_strings.grd
@@ -11,10 +11,10 @@
       <message desc="Content description for the content view that holds the web contents [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_CONTENT_VIEW">
         Web View
       </message>
-      <message desc="Label for 'set' button in date picker dialog, used to replace the contents of a field with the chosen date [CHAR-LIMIT=12]" name="IDS_DATE_PICKER_DIALOG_SET">
+      <message desc="Label for 'set' button in date picker dialog and time picker dialog, used to replace the contents of a field with the chosen date or time [CHAR-LIMIT=12]" name="IDS_DATE_PICKER_DIALOG_SET">
         Set
       </message>
-      <message desc="Label for 'clear' button in date picker dialog, used to replace the contents of a field with the empty string [CHAR-LIMIT=12]" name="IDS_DATE_PICKER_DIALOG_CLEAR">
+      <message desc="Label for 'clear' button in date picker dialog and time picker dialog, used to replace the contents of a field with the empty string [CHAR-LIMIT=12]" name="IDS_DATE_PICKER_DIALOG_CLEAR">
         Clear
       </message>
       <message desc="Title for the date picker dialog, which can be used to choose a date. [CHAR-LIMIT=32]" name="IDS_DATE_PICKER_DIALOG_TITLE">
@@ -23,6 +23,24 @@
       <message desc="Title for the date/time picker dialog, which can be used to choose a date and time. [CHAR-LIMIT=32]" name="IDS_DATE_TIME_PICKER_DIALOG_TITLE">
         Set date and time
       </message>
+      <message desc="Title for the time picker dialog, which can be used to choose a time. [CHAR-LIMIT=32]" name="IDS_TIME_PICKER_DIALOG_TITLE">
+        Set time
+      </message>
+      <message desc="Value for AM in AM/PM in the time picker dialog. AM represents the morning (ante-meridiem). [CHAR-LIMIT=2]" name="IDS_TIME_PICKER_DIALOG_AM">
+        AM
+      </message>
+      <message desc="Value for PM in AM/PM in the time picker dialog. PM represents the afternoon (post-meridiem). [CHAR-LIMIT=2]" name="IDS_TIME_PICKER_DIALOG_PM">
+        PM
+      </message>
+      <message desc="Separator used between hours and minutes in the time pickerr dialog (hh:mm) [CHAR-LIMIT=1]" name="IDS_TIME_PICKER_DIALOG_HOUR_MINUTE_SEPARATOR">
+        :
+      </message>
+      <message desc="Separator used between minutes and seconds in the time picker dialog (hh:mm:ss) [CHAR-LIMIT=1]" name="IDS_TIME_PICKER_DIALOG_MINUTE_SECOND_SEPARATOR">
+        :
+      </message>
+      <message desc="Separator used between seconds and subseconds in the time picker dialog (hh:mm:ss.sss) [CHAR-LIMIT=1]" name="IDS_TIME_PICKER_DIALOG_SECOND_SUBSECOND_SEPARATOR">
+        .
+      </message>
       <message desc="Title for the month picker dialog, which can be used to choose a month. [CHAR-LIMIT=32]" name="IDS_MONTH_PICKER_DIALOG_TITLE">
         Set month
       </message>
@@ -44,6 +62,21 @@
       <message desc="Content description for the date time picker year component. [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_DATE_PICKER_YEAR">
         Year
       </message>
+      <message desc="Content description for the time picker hour component. [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_TIME_PICKER_HOUR">
+        Hour
+      </message>
+      <message desc="Content description for the time picker minute component. [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_TIME_PICKER_MINUTE">
+        Minute
+      </message>
+      <message desc="Content description for the time picker second component. [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_TIME_PICKER_SECOND">
+        Second
+      </message>
+      <message desc="Content description for the time picker milli component. [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_TIME_PICKER_MILLI">
+        Millisecond
+      </message>
+      <message desc="Content description for the time picker AM/PM component. [CHAR-LIMIT=32]" name="IDS_ACCESSIBILITY_TIME_PICKER_AMPM">
+        AM/PM
+      </message>
       <message desc="NO DESCRIPTION [CHAR-LIMIT=32]" name="IDS_MEDIA_PLAYER_ERROR_TITLE">
         Cannot play video
       </message>
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
new file mode 100644
index 0000000..541c96e
--- /dev/null
+++ b/content/public/android/javatests/src/org/chromium/content/browser/BrowserStartupControllerTest.java
@@ -0,0 +1,357 @@
+// Copyright 2013 The Chromium 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.Context;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.content.common.ProcessInitException;
+
+public class BrowserStartupControllerTest extends InstrumentationTestCase {
+
+    private TestBrowserStartupController mController;
+
+    private static class TestBrowserStartupController extends BrowserStartupController {
+
+        private boolean mThrowProcessInitException;
+        private int mStartupResult;
+        private boolean mAlreadyInitialized = false;
+        private int mInitializedCounter = 0;
+        private boolean mCallbackWasSetup;
+
+        private TestBrowserStartupController(Context context) {
+            super(context);
+        }
+
+        @Override
+        void enableAsynchronousStartup() {
+            mCallbackWasSetup = true;
+        }
+
+        @Override
+        boolean initializeAndroidBrowserProcess() throws ProcessInitException {
+            mInitializedCounter++;
+            if (mThrowProcessInitException) {
+                throw new ProcessInitException(4);
+            }
+            if (!mAlreadyInitialized) {
+                // Post to the UI thread to emulate what would happen in a real scenario.
+                ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                    @Override
+                    public void run() {
+                        BrowserStartupController.browserStartupComplete(mStartupResult);
+                    }
+                });
+            }
+            return mAlreadyInitialized;
+        }
+
+        private boolean hasBeenInitializedOneTime() {
+            return mInitializedCounter == 1;
+        }
+    }
+
+    private static class TestStartupCallback implements BrowserStartupController.StartupCallback {
+        private boolean mWasSuccess;
+        private boolean mWasFailure;
+        private boolean mHasStartupResult;
+        private boolean mAlreadyStarted;
+
+        @Override
+        public void onSuccess(boolean alreadyStarted) {
+            assert !mHasStartupResult;
+            mWasSuccess = true;
+            mAlreadyStarted = alreadyStarted;
+            mHasStartupResult = true;
+        }
+
+        @Override
+        public void onFailure() {
+            assert !mHasStartupResult;
+            mWasFailure = true;
+            mHasStartupResult = true;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Context context = new AdvancedMockContext(getInstrumentation().getTargetContext());
+        mController = new TestBrowserStartupController(context);
+        // Setting the static singleton instance field enables more correct testing, since it is
+        // is possible to call {@link BrowserStartupController#browserStartupComplete(int)} instead
+        // of {@link BrowserStartupController#executeEnqueuedCallbacks(int, boolean)} directly.
+        BrowserStartupController.overrideInstanceForTest(mController);
+    }
+
+    @SmallTest
+    public void testSingleAsynchronousStartupRequest() {
+        mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
+        final TestStartupCallback callback = new TestStartupCallback();
+
+        // Kick off the asynchronous startup request.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback);
+            }
+        });
+
+        assertTrue("The callback should have been setup", mController.mCallbackWasSetup);
+        assertTrue("The browser process should have been initialized one time.",
+                mController.hasBeenInitializedOneTime());
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        assertTrue("Callback should have been a success.", callback.mWasSuccess);
+        assertFalse("Callback should be told that the browser process was not already started.",
+                callback.mAlreadyStarted);
+    }
+
+    @SmallTest
+    public void testMultipleAsynchronousStartupRequests() {
+        mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
+        final TestStartupCallback callback1 = new TestStartupCallback();
+        final TestStartupCallback callback2 = new TestStartupCallback();
+        final TestStartupCallback callback3 = new TestStartupCallback();
+
+        // Kick off the asynchronous startup requests.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback1);
+            }
+        });
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback2);
+            }
+        });
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.addStartupCompletedObserver(callback3);
+            }
+        });
+
+        assertTrue("The callback should have been setup", mController.mCallbackWasSetup);
+        assertTrue("The browser process should have been initialized one time.",
+                mController.hasBeenInitializedOneTime());
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
+        assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
+        assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
+        assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
+        assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
+        assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
+        // Some startup tasks might have been enqueued after the browser process was started, but
+        // not the first one which kicked of the startup.
+        assertFalse("Callback 1 should be told that the browser process was not already started.",
+                callback1.mAlreadyStarted);
+    }
+
+    @SmallTest
+    public void testConsecutiveAsynchronousStartupRequests() {
+        mController.mStartupResult = BrowserStartupController.STARTUP_SUCCESS;
+        final TestStartupCallback callback1 = new TestStartupCallback();
+        final TestStartupCallback callback2 = new TestStartupCallback();
+
+        // Kick off the asynchronous startup requests.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback1);
+            }
+        });
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.addStartupCompletedObserver(callback2);
+            }
+        });
+
+        assertTrue("The callback should have been setup", mController.mCallbackWasSetup);
+        assertTrue("The browser process should have been initialized one time.",
+                mController.hasBeenInitializedOneTime());
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
+        assertTrue("Callback 1 should have been a success.", callback1.mWasSuccess);
+        assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
+        assertTrue("Callback 2 should have been a success.", callback2.mWasSuccess);
+
+        final TestStartupCallback callback3 = new TestStartupCallback();
+        final TestStartupCallback callback4 = new TestStartupCallback();
+
+        // Kick off more asynchronous startup requests.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback3);
+            }
+        });
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.addStartupCompletedObserver(callback4);
+            }
+        });
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
+        assertTrue("Callback 3 should have been a success.", callback3.mWasSuccess);
+        assertTrue("Callback 3 should be told that the browser process was already started.",
+                callback3.mAlreadyStarted);
+        assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
+        assertTrue("Callback 4 should have been a success.", callback4.mWasSuccess);
+        assertTrue("Callback 4 should be told that the browser process was already started.",
+                callback4.mAlreadyStarted);
+    }
+
+    @SmallTest
+    public void testSingleFailedAsynchronousStartupRequest() {
+        mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
+        final TestStartupCallback callback = new TestStartupCallback();
+
+        // Kick off the asynchronous startup request.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback);
+            }
+        });
+
+        assertTrue("The callback should have been setup", mController.mCallbackWasSetup);
+        assertTrue("The browser process should have been initialized one time.",
+                mController.hasBeenInitializedOneTime());
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        assertTrue("Callback should have been a failure.", callback.mWasFailure);
+    }
+
+    @SmallTest
+    public void testConsecutiveFailedAsynchronousStartupRequests() {
+        mController.mStartupResult = BrowserStartupController.STARTUP_FAILURE;
+        final TestStartupCallback callback1 = new TestStartupCallback();
+        final TestStartupCallback callback2 = new TestStartupCallback();
+
+        // Kick off the asynchronous startup requests.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback1);
+            }
+        });
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.addStartupCompletedObserver(callback2);
+            }
+        });
+
+        assertTrue("The callback should have been setup", mController.mCallbackWasSetup);
+        assertTrue("The browser process should have been initialized one time.",
+                mController.hasBeenInitializedOneTime());
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback 1 should have been executed.", callback1.mHasStartupResult);
+        assertTrue("Callback 1 should have been a failure.", callback1.mWasFailure);
+        assertTrue("Callback 2 should have been executed.", callback2.mHasStartupResult);
+        assertTrue("Callback 2 should have been a failure.", callback2.mWasFailure);
+
+        final TestStartupCallback callback3 = new TestStartupCallback();
+        final TestStartupCallback callback4 = new TestStartupCallback();
+
+        // Kick off more asynchronous startup requests.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback3);
+            }
+        });
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.addStartupCompletedObserver(callback4);
+            }
+        });
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback 3 should have been executed.", callback3.mHasStartupResult);
+        assertTrue("Callback 3 should have been a failure.", callback3.mWasFailure);
+        assertTrue("Callback 4 should have been executed.", callback4.mHasStartupResult);
+        assertTrue("Callback 4 should have been a failure.", callback4.mWasFailure);
+    }
+
+    @SmallTest
+    public void testAndroidBrowserStartupThrowsException() {
+        mController.mThrowProcessInitException = true;
+        final TestStartupCallback callback = new TestStartupCallback();
+
+        // Kick off the asynchronous startup request.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback);
+            }
+        });
+
+        assertTrue("The callback should have been setup", mController.mCallbackWasSetup);
+        assertTrue("The browser process should have been initialized one time.",
+                mController.hasBeenInitializedOneTime());
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        assertTrue("Callback should have been a failure.", callback.mWasFailure);
+    }
+
+    @SmallTest
+    public void testAndroidBrowserProcessAlreadyInitializedByOtherPartsOfCode() {
+        mController.mAlreadyInitialized = true;
+        final TestStartupCallback callback = new TestStartupCallback();
+
+        // Kick off the asynchronous startup request.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mController.startBrowserProcessesAsync(callback);
+            }
+        });
+
+        assertTrue("The callback should have been setup", mController.mCallbackWasSetup);
+        assertTrue("The browser process should have been initialized one time.",
+                mController.hasBeenInitializedOneTime());
+
+        // Wait for callbacks to complete.
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("Callback should have been executed.", callback.mHasStartupResult);
+        assertTrue("Callback should have been a success.", callback.mWasSuccess);
+        assertTrue("Callback should be told that the browser process was already started.",
+                callback.mAlreadyStarted);
+    }
+}
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 2647b3a..f7d29e4 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
@@ -890,6 +890,73 @@
     }
 
     /**
+     * Verify that double tap drag zoom feature is not invoked
+     * when it is disabled..
+     * @throws Exception
+     */
+    @SmallTest
+    @Feature({"Gestures"})
+    public void testDoubleTapDragZoomNothingWhenDisabled() throws Exception {
+        final long downTime1 = SystemClock.uptimeMillis();
+        final long downTime2 = downTime1 + 100;
+
+        GestureRecordingMotionEventDelegate mockDelegate =
+                new GestureRecordingMotionEventDelegate();
+        mGestureHandler = new ContentViewGestureHandler(
+                getInstrumentation().getTargetContext(), mockDelegate,
+                new MockZoomManager(getInstrumentation().getTargetContext(), null),
+                ContentViewCore.INPUT_EVENTS_DELIVERED_AT_VSYNC);
+
+        mGestureHandler.updateDoubleTapDragSupport(false);
+
+        MotionEvent 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);
+        // As double tap and drag to zoom is disabled, we won't handle
+        // the move event.
+        assertFalse(mGestureHandler.onTouchEvent(event));
+
+        assertFalse("No GESTURE_SCROLL_START should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_SCROLL_START));
+        assertTrue("No GESTURE_PINCH_BEGIN should have been sent",
+                ContentViewGestureHandler.GESTURE_PINCH_BEGIN !=
+                mockDelegate.mMostRecentGestureEvent.mType);
+
+        event = MotionEvent.obtain(
+                downTime2, downTime2 + 10, MotionEvent.ACTION_MOVE,
+                FAKE_COORD_X, FAKE_COORD_Y + 200, 0);
+        assertFalse(mGestureHandler.onTouchEvent(event));
+        assertFalse("No GESTURE_SCROLL_BY should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_SCROLL_BY));
+        assertTrue("No 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);
+        assertFalse(mGestureHandler.onTouchEvent(event));
+        assertFalse("No GESTURE_PINCH_END should have been sent",
+                mockDelegate.mGestureTypeList.contains(
+                        ContentViewGestureHandler.GESTURE_PINCH_END));
+    }
+
+    /**
      * Mock MotionEventDelegate that remembers the most recent gesture event.
      */
     static class GestureRecordingMotionEventDelegate implements MotionEventDelegate {
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 d880a96..998f036 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
@@ -26,15 +26,6 @@
             "<body>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</body>" +
             "</html>");
 
-    private void assertWaitForPageScaleFactor(final float scale) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return getContentViewCore().getScale() == scale;
-            }
-        }));
-    }
-
     private void assertWaitForScroll(final boolean hugLeft, final boolean hugTop)
             throws InterruptedException {
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
@@ -79,7 +70,7 @@
 
         launchContentShellWithUrl(LARGE_PAGE);
         assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
-        assertWaitForPageScaleFactor(1.0f);
+        assertWaitForPageScaleFactorMatch(1.0f);
 
         assertEquals(0, getContentViewCore().getNativeScrollXForTest());
         assertEquals(0, getContentViewCore().getNativeScrollYForTest());
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/DeviceMotionAndOrientationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/DeviceMotionAndOrientationTest.java
index 2b51c22..eca1851 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/DeviceMotionAndOrientationTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/DeviceMotionAndOrientationTest.java
@@ -4,26 +4,13 @@
 
 package org.chromium.content.browser;
 
-import org.chromium.base.ActivityStatus;
-import org.chromium.base.test.util.Feature;
-import org.chromium.content.app.LibraryLoader;
-import org.chromium.content.common.CommandLine;
-import org.chromium.content.common.ProcessInitException;
-import org.chromium.content_shell_apk.ContentShellApplication;
-
+import android.hardware.Sensor;
+import android.hardware.SensorEventListener;
+import android.os.Handler;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.test.UiThreadTest;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.os.Handler;
 
-import com.google.common.collect.Sets;
-
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
 import java.util.Set;
 
 
@@ -95,7 +82,8 @@
                 mDeviceMotionAndOrientation.mActiveSensors.containsAll(
                         DeviceMotionAndOrientation.DEVICE_ORIENTATION_SENSORS));
 
-        Set<Integer> union = Sets.newHashSet(DeviceMotionAndOrientation.DEVICE_ORIENTATION_SENSORS);
+        Set<Integer> union = new HashSet<Integer>(
+            DeviceMotionAndOrientation.DEVICE_ORIENTATION_SENSORS);
         union.addAll(DeviceMotionAndOrientation.DEVICE_MOTION_SENSORS);
 
         assertEquals(union.size(), mDeviceMotionAndOrientation.mActiveSensors.size());
@@ -144,7 +132,7 @@
                 mDeviceMotionAndOrientation.mActiveSensors.containsAll(
                         DeviceMotionAndOrientation.DEVICE_ORIENTATION_SENSORS));
 
-        Set<Integer> diff = Sets.newHashSet(DeviceMotionAndOrientation.DEVICE_MOTION_SENSORS);
+        Set<Integer> diff = new HashSet<Integer>(DeviceMotionAndOrientation.DEVICE_MOTION_SENSORS);
         diff.removeAll(DeviceMotionAndOrientation.DEVICE_ORIENTATION_SENSORS);
 
         assertEquals(diff.size(), mMockSensorManager.numUnRegistered);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index a12007f..e4c1a5f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -61,7 +61,7 @@
         mContentView = getActivity().getActiveContentView();
         mCallbackContainer = new TestCallbackHelperContainer(mContentView);
         // TODO(aurimas) remove this wait once crbug.com/179511 is fixed.
-        assertWaitForPageScaleFactor(1);
+        assertWaitForPageScaleFactorMatch(1);
         DOMUtils.clickNode(this, mContentView, mCallbackContainer, "input_text");
         assertWaitForKeyboardStatus(true);
 
@@ -286,17 +286,6 @@
                 });
     }
 
-
-
-    private void assertWaitForPageScaleFactor(final float scale) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return getContentViewCore().getScale() == scale;
-            }
-        }));
-    }
-
     private void assertWaitForKeyboardStatus(final boolean show) throws InterruptedException {
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java
index d2697b7..91e6124 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java
@@ -87,8 +87,12 @@
     }
 
 
-    @MediumTest
-    @Feature({"TextSelection", "TextInput", "Main"})
+    /**
+     * @MediumTest
+     * @Feature({"TextSelection", "TextInput", "Main"})
+     * http://crbug.com/169648
+     */
+    @DisabledTest
     public void testKeyEventHidesHandle() throws Throwable {
         launchWithUrl(TEXTAREA_DATA_URL);
         clickNodeToShowInsertionHandle(TEXTAREA_ID);
diff --git a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
index a887ffb..6f56449 100644
--- a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
@@ -58,6 +58,8 @@
         assertEquals(1, sObjectCount.get());
 
         instance = null;
+        // Ensure compiler / instrumentation does not strip out the assignment.
+        assertTrue(instance == null);
         collectGarbage();
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
@@ -81,6 +83,8 @@
         }
 
         instances = null;
+        // Ensure compiler / instrumentation does not strip out the assignment.
+        assertTrue(instances == null);
         collectGarbage();
         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
diff --git a/content/public/browser/browser_plugin_guest_delegate.h b/content/public/browser/browser_plugin_guest_delegate.h
index 11facb9..f52e9e3 100644
--- a/content/public/browser/browser_plugin_guest_delegate.h
+++ b/content/public/browser/browser_plugin_guest_delegate.h
@@ -11,6 +11,8 @@
 #include "base/values.h"
 #include "content/common/content_export.h"
 #include "content/public/common/browser_plugin_permission_type.h"
+#include "ui/gfx/size.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -39,6 +41,11 @@
 
   virtual bool HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
 
+  // Notification that a load in the guest resulted in abort.
+  virtual void LoadAbort(bool is_top_level,
+                         const GURL& url,
+                         const std::string& error_type) {}
+
   // Notification that the guest is no longer hung.
   virtual void RendererResponsive() {}
 
@@ -57,6 +64,10 @@
       BrowserPluginPermissionType permission_type,
       const base::DictionaryValue& request_info,
       const PermissionResponseCallback& callback);
+
+  // Notifies that the content size of the guest has changed in autosize mode.
+  virtual void SizeChanged(const gfx::Size& old_size,
+                           const gfx::Size& new_size) {}
 };
 
 }  // namespace content
diff --git a/content/public/browser/browser_url_handler.h b/content/public/browser/browser_url_handler.h
index d880fd3..4fabec3 100644
--- a/content/public/browser/browser_url_handler.h
+++ b/content/public/browser/browser_url_handler.h
@@ -44,6 +44,11 @@
                                      bool* reverse_on_redirect) = 0;
 
   // Add the specified handler pair to the list of URL handlers.
+  //
+  // Note that normally, the reverse handler is only used if the modified URL is
+  // not modified, e.g., by adding a hash fragment. To support this behavior,
+  // register the forward and reverse handlers separately, each with a
+  // null_handler() for the opposite direction.
   virtual void AddHandlerPair(URLHandler handler,
                               URLHandler reverse_handler) = 0;
 
diff --git a/content/public/browser/compositor_util.h b/content/public/browser/compositor_util.h
deleted file mode 100644
index a237d07..0000000
--- a/content/public/browser/compositor_util.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_PUBLIC_BROWSER_COMPOSITOR_UTIL_H_
-#define CONTENT_PUBLIC_BROWSER_COMPOSITOR_UTIL_H_
-
-#include "content/common/content_export.h"
-
-namespace content {
-
-// Returns true if the threaded compositor is on (via flags or field trial).
-CONTENT_EXPORT bool IsThreadedCompositingEnabled();
-
-// Returns true if force-compositing-mode is on (via flags or field trial).
-CONTENT_EXPORT bool IsForceCompositingModeEnabled();
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_BROWSER_COMPOSITOR_UTIL_H_
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index ccc1e72..35627c7 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -30,6 +30,9 @@
 
 namespace content {
 
+typedef base::Thread* (*RendererMainThreadFactoryFunction)(
+    const std::string& id);
+
 // Interface that represents the browser side of the browser <-> renderer
 // communication channel. There will generally be one RenderProcessHost per
 // renderer process.
@@ -248,6 +251,9 @@
   // Returns the current max number of renderer processes used by the content
   // module.
   static size_t GetMaxRendererProcessCount();
+
+  static void RegisterRendererMainThreadFactory(
+      RendererMainThreadFactoryFunction create);
 };
 
 }  // namespace content.
diff --git a/content/public/browser/utility_process_host.h b/content/public/browser/utility_process_host.h
index 4c7e192..d85df1e 100644
--- a/content/public/browser/utility_process_host.h
+++ b/content/public/browser/utility_process_host.h
@@ -6,6 +6,7 @@
 #define CONTENT_PUBLIC_BROWSER_UTILITY_PROCESS_HOST_H_
 
 #include "base/process/launch.h"
+#include "base/threading/thread.h"
 #include "content/common/content_export.h"
 #include "ipc/ipc_sender.h"
 
@@ -18,6 +19,9 @@
 class UtilityProcessHostClient;
 struct ChildProcessData;
 
+typedef base::Thread* (*UtilityMainThreadFactoryFunction)(
+    const std::string& id);
+
 // This class acts as the browser-side host to a utility child process.  A
 // utility process is a short-lived process that is created to run a specific
 // task.  This class lives solely on the IO thread.
@@ -66,6 +70,9 @@
 #if defined(OS_POSIX)
   virtual void SetEnv(const base::EnvironmentVector& env) = 0;
 #endif
+
+  CONTENT_EXPORT static void RegisterUtilityMainThreadFactory(
+      UtilityMainThreadFactoryFunction create);
 };
 
 };  // namespace content
diff --git a/content/public/browser/web_contents.cc b/content/public/browser/web_contents.cc
index ef1ab68..d854767 100644
--- a/content/public/browser/web_contents.cc
+++ b/content/public/browser/web_contents.cc
@@ -14,6 +14,7 @@
       opener(NULL),
       routing_id(MSG_ROUTING_NONE),
       main_frame_routing_id(MSG_ROUTING_NONE),
+      initially_hidden(false),
       context(NULL) {}
 
 WebContents::CreateParams::CreateParams(
@@ -23,6 +24,7 @@
       opener(NULL),
       routing_id(MSG_ROUTING_NONE),
       main_frame_routing_id(MSG_ROUTING_NONE),
+      initially_hidden(false),
       context(NULL) {}
 
 }  // namespace content
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 86b51a2..ac30001 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -92,6 +92,9 @@
     // Initial size of the new WebContent's view. Can be (0, 0) if not needed.
     gfx::Size initial_size;
 
+    // True if the contents should be initially hidden.
+    bool initially_hidden;
+
     // Used to specify the location context which display the new view should
     // belong. This can be NULL if not needed.
     gfx::NativeView context;
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 6810002..47e30b2 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -127,11 +127,8 @@
     WindowContainerType window_container_type,
     const string16& frame_name,
     const GURL& target_url,
-    const Referrer& referrer,
-    WindowOpenDisposition disposition,
-    const WebKit::WebWindowFeatures& features,
-    bool user_gesture,
-    bool opener_suppressed) {
+    const std::string& partition_id,
+    SessionStorageNamespace* session_storage_namespace) {
   return true;
 }
 
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 23d2336..69ac871 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -37,6 +37,7 @@
 class JavaScriptDialogManager;
 class PageState;
 class RenderViewHost;
+class SessionStorageNamespace;
 class WebContents;
 class WebContentsImpl;
 struct ContextMenuParams;
@@ -300,11 +301,8 @@
       WindowContainerType window_container_type,
       const string16& frame_name,
       const GURL& target_url,
-      const Referrer& referrer,
-      WindowOpenDisposition disposition,
-      const WebKit::WebWindowFeatures& features,
-      bool user_gesture,
-      bool opener_suppressed);
+      const std::string& partition_id,
+      SessionStorageNamespace* session_storage_namespace);
 
   // Notifies the delegate about the creation of a new WebContents. This
   // typically happens when popups are created.
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index 241a74b..d46f315 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -27,7 +27,7 @@
 // An observer API implemented by classes which are interested in various page
 // load events from WebContents.  They also get a chance to filter IPC messages.
 //
-// Since a WebContents can be a delegate to almost arbitrarly many
+// Since a WebContents can be a delegate to almost arbitrarily many
 // RenderViewHosts, it is important to check in those WebContentsObserver
 // methods which take a RenderViewHost that the event came from the
 // RenderViewHost the observer cares about.
@@ -104,7 +104,7 @@
       RenderViewHost* render_view_host) {}
 
   // This method is invoked when the provisional load was successfully
-  // commited. The |render_view_host| is now the current RenderViewHost of the
+  // committed. The |render_view_host| is now the current RenderViewHost of the
   // WebContents.
   //
   // If the navigation only changed the reference fragment, or was triggered
@@ -192,10 +192,10 @@
   virtual void DidStartLoading(RenderViewHost* render_view_host) {}
   virtual void DidStopLoading(RenderViewHost* render_view_host) {}
 
-  // This method is invoked when the navigation from the browser process. If
-  // there are ongoing navigations, the respective failure methods will also be
-  // invoked.
-  virtual void StopNavigation() {}
+  // When WebContents::Stop() is called, the WebContents stops loading and then
+  // invokes this method. If there are ongoing navigations, their respective
+  // failure methods will also be invoked.
+  virtual void NavigationStopped() {}
 
   // This indicates that the next navigation was triggered by a user gesture.
   virtual void DidGetUserGesture() {}
@@ -218,7 +218,7 @@
   virtual void PluginCrashed(const base::FilePath& plugin_path,
                              base::ProcessId plugin_pid) {}
 
-  // Notication that the given plugin has hung or become unhung. This
+  // Notification that the given plugin has hung or become unhung. This
   // notification is only for Pepper plugins.
   //
   // The plugin_child_id is the unique child process ID from the plugin. Note
diff --git a/content/public/browser/web_ui_data_source.h b/content/public/browser/web_ui_data_source.h
index 76d0d7e..f3692b3 100644
--- a/content/public/browser/web_ui_data_source.h
+++ b/content/public/browser/web_ui_data_source.h
@@ -78,6 +78,11 @@
   // NOTE: it's not acceptable to call DisableContentSecurityPolicy for new
   // pages, see URLDataSource::ShouldAddContentSecurityPolicy and talk to
   // tsepez.
+
+  // Currently only used by embedders for WebUIs with multiple instances, could
+  // have been useful for NTP as well if it wasn't implementing URLDataSource
+  // itself.
+  virtual void DisableReplaceExistingSource() = 0;
   virtual void DisableContentSecurityPolicy() = 0;
   virtual void OverrideContentSecurityPolicyObjectSrc(
       const std::string& data) = 0;
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 5169ba4..36f707f 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -10,6 +10,9 @@
 // override for developers who need the old behavior for testing.
 const char kAllowFileAccessFromFiles[]      = "allow-file-access-from-files";
 
+// Allows filters (SkImageFilter objects) to be sent between processes over IPC
+const char kAllowFiltersOverIPC[]           = "allow-filters-over-ipc";
+
 // Enables the sandboxed processes to run without a job object assigned to them.
 // This flag is required to allow Chrome to run in RemoteApps or Citrix. This
 // flag can reduce the security of the sandboxed processes and allow them to do
@@ -531,11 +534,6 @@
 // Enable WebRTC to open TCP server sockets.
 const char kEnableWebRtcTcpServerSocket[]   = "enable-webrtc-tcp-server-socket";
 
-// Enables experimental features for the geolocation API.
-// Current features:
-// - CoreLocation support for Mac OS X 10.6
-const char kExperimentalLocationFeatures[]  = "experimental-location-features";
-
 // Load NPAPI plugins from the specified directory.
 const char kExtraPluginDir[]                = "extra-plugin-dir";
 
@@ -782,6 +780,10 @@
 // Runs the security test for the renderer sandbox.
 const char kTestSandbox[]                   = "test-sandbox";
 
+// Enables not sending touch events to renderer while scrolling.
+const char kNoTouchToRendererWhileScrolling[] =
+    "no-touch-to-renderer-while-scrolling";
+
 // Causes TRACE_EVENT flags to be recorded from startup. Optionally, can
 // specify the specific trace categories to include (e.g.
 // --trace-startup=base,net) otherwise, all events are recorded. Setting this
@@ -873,6 +875,9 @@
 // Enables HW decode acceleration for WebRTC.
 const char kEnableWebRtcHWDecoding[]        = "enable-webrtc-hw-decoding";
 
+// Enables HW encode acceleration for WebRTC.
+const char kEnableWebRtcHWEncoding[] = "enable-webrtc-hw-encoding";
+
 #endif
 
 #if defined(OS_ANDROID)
@@ -935,7 +940,4 @@
 
 // Don't dump stuff here, follow the same order as the header.
 
-// Allows filters (SkImageFilter objects) to be sent between processes over IPC
-const char kAllowFiltersOverIPC[] = "allow-filters-over-ipc";
-
 }  // namespace switches
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 949400a..f2a0829 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -15,6 +15,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 kAllowFileAccessFromFiles[];
+CONTENT_EXPORT extern const char kAllowFiltersOverIPC[];
 CONTENT_EXPORT extern const char kAllowNoSandboxJob[];
 extern const char kAllowSandboxDebugging[];
 extern const char kAllowWebUICompositing[];
@@ -159,7 +160,6 @@
 CONTENT_EXPORT extern const char kEnableWebGLDraftExtensions[];
 extern const char kEnableWebMIDI[];
 extern const char kEnableWebRtcTcpServerSocket[];
-CONTENT_EXPORT extern const char kExperimentalLocationFeatures[];
 CONTENT_EXPORT extern const char kExtraPluginDir[];
 CONTENT_EXPORT extern const char kForceCompositingMode[];
 extern const char kForceFieldTrials[];
@@ -224,6 +224,7 @@
 CONTENT_EXPORT extern const char kTestingFixedHttpPort[];
 CONTENT_EXPORT extern const char kTestingFixedHttpsPort[];
 CONTENT_EXPORT extern const char kTestSandbox[];
+CONTENT_EXPORT extern const char kNoTouchToRendererWhileScrolling[];
 extern const char kTraceStartup[];
 extern const char kTraceStartupDuration[];
 extern const char kTraceStartupFile[];
@@ -248,6 +249,7 @@
 CONTENT_EXPORT extern const char kEnableSCTPDataChannels[];
 extern const char kEnableWebRtcAecRecordings[];
 extern const char kEnableWebRtcHWDecoding[];
+extern const char kEnableWebRtcHWEncoding[];
 #endif
 
 #if defined(OS_ANDROID)
@@ -283,8 +285,6 @@
 // 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).
 
-CONTENT_EXPORT extern const char kAllowFiltersOverIPC[];
-
 }  // namespace switches
 
 #endif  // CONTENT_PUBLIC_COMMON_CONTENT_SWITCHES_H_
diff --git a/content/public/common/frame_navigate_params.h b/content/public/common/frame_navigate_params.h
index 0625175..2f9656a 100644
--- a/content/public/common/frame_navigate_params.h
+++ b/content/public/common/frame_navigate_params.h
@@ -10,7 +10,6 @@
 
 #include "content/common/content_export.h"
 #include "content/public/common/page_transition_types.h"
-#include "content/public/common/password_form.h"
 #include "content/public/common/referrer.h"
 #include "net/base/host_port_pair.h"
 #include "url/gurl.h"
@@ -59,9 +58,6 @@
   GURL searchable_form_url;
   std::string searchable_form_encoding;
 
-  // See password_form.h.
-  content::PasswordForm password_form;
-
   // Contents MIME type of main frame.
   std::string contents_mime_type;
 
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc
index 71ab648..e380faa 100644
--- a/content/public/common/url_constants.cc
+++ b/content/public/common/url_constants.cc
@@ -21,11 +21,11 @@
 const char kGuestScheme[] = "chrome-guest";
 const char kHttpScheme[] = "http";
 const char kHttpsScheme[] = "https";
-const char kJavaScriptScheme[] = "javascript";
 }  // namespace chrome
 
 namespace content {
 
+const char kJavaScriptScheme[] = "javascript";
 const char kMailToScheme[] = "mailto";
 const char kMetadataScheme[] = "metadata";
 const char kSwappedOutScheme[] = "swappedout";
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h
index ef17684..68a7ac4 100644
--- a/content/public/common/url_constants.h
+++ b/content/public/common/url_constants.h
@@ -27,11 +27,11 @@
 CONTENT_EXPORT extern const char kGuestScheme[];
 CONTENT_EXPORT extern const char kHttpScheme[];
 CONTENT_EXPORT extern const char kHttpsScheme[];
-CONTENT_EXPORT extern const char kJavaScriptScheme[];
 }  // namespace chrome
 
 namespace content {
 
+CONTENT_EXPORT extern const char kJavaScriptScheme[];
 CONTENT_EXPORT extern const char kMailToScheme[];
 CONTENT_EXPORT extern const char kMetadataScheme[];
 CONTENT_EXPORT extern const char kSwappedOutScheme[];
diff --git a/content/public/common/zygote_fork_delegate_linux.h b/content/public/common/zygote_fork_delegate_linux.h
index 7beda6d..a5ea9f2 100644
--- a/content/public/common/zygote_fork_delegate_linux.h
+++ b/content/public/common/zygote_fork_delegate_linux.h
@@ -10,6 +10,10 @@
 #include <string>
 #include <vector>
 
+// TODO(jln) base::TerminationStatus should be forward declared when switching
+// to C++11.
+#include "base/process/kill.h"
+
 namespace content {
 
 // The ZygoteForkDelegate allows the Chrome Linux zygote to delegate
@@ -40,15 +44,26 @@
                        int* uma_sample, int* uma_boundary_value) = 0;
 
   // Delegate forks, returning a -1 on failure. Outside the
-  // suid sandbox, Fork() returns the Linux process ID. Inside
-  // the sandbox, returns a positive integer, with PID discovery
-  // handled by the sandbox.
+  // suid sandbox, Fork() returns the Linux process ID.
+  // This method is not aware of any potential pid namespaces, so it'll
+  // return a raw pid just like fork() would.
   virtual pid_t Fork(const std::vector<int>& fds) = 0;
 
-  // After a successful for, signal the child to indicate that
+  // After a successful fork, signal the child to indicate that
   // the child's PID has been received. Also communicate the
   // channel switch as a part of acknowledgement message.
   virtual bool AckChild(int fd, const std::string& channel_switch) = 0;
+
+  // The fork delegate must also assume the role of waiting for its children
+  // since the caller will not be their parents and cannot do it. |pid| here
+  // should be a pid that has been returned by the Fork() method. i.e. This
+  // method is completely unaware of eventual PID namespaces due to sandboxing.
+  // |known_dead| indicates that the process is already dead and that a
+  // blocking wait() should be performed. In this case, GetTerminationStatus()
+  // will send a SIGKILL to the target process first.
+  virtual bool GetTerminationStatus(pid_t pid, bool known_dead,
+                                    base::TerminationStatus* status,
+                                    int* exit_code) = 0;
 };
 
 }  // namespace content
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index c190f09..a5b6b31 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -182,4 +182,9 @@
   return false;
 }
 
+bool ContentRendererClient::ShouldReportDetailedMessageForSource(
+    const base::string16& source) const {
+  return false;
+}
+
 }  // namespace content
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index a00e1a9..f3ecf7d 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -243,6 +243,15 @@
 
   // Returns true if the page at |url| can use Pepper MediaStream APIs.
   virtual bool AllowPepperMediaStreamAPI(const GURL& url);
+
+  // Returns true if we should report a detailed message (including a stack
+  // trace) for console [logs|errors|exceptions]. |source| is the WebKit-
+  // reported source for the error; this can point to a page or a script,
+  // and can be external (e.g., "http://www.google.com"), extension-related
+  // (e.g., "chrome-extension://<extension_id>/background.js"), or internal
+  // (e.g., "event_bindings" or "schemaUtils").
+  virtual bool ShouldReportDetailedMessageForSource(
+      const base::string16& source) const;
 };
 
 }  // namespace content
diff --git a/content/public/renderer/document_state.cc b/content/public/renderer/document_state.cc
index 235fc89..9add6b0 100644
--- a/content/public/renderer/document_state.cc
+++ b/content/public/renderer/document_state.cc
@@ -4,7 +4,6 @@
 
 #include "content/public/renderer/document_state.h"
 
-#include "content/public/common/password_form.h"
 #include "content/public/renderer/navigation_state.h"
 
 namespace content {
@@ -26,11 +25,6 @@
 
 DocumentState::~DocumentState() {}
 
-void DocumentState::set_password_form_data(
-    scoped_ptr<PasswordForm> data) {
-  password_form_data_.reset(data.release());
-}
-
 void DocumentState::set_navigation_state(NavigationState* navigation_state) {
   navigation_state_.reset(navigation_state);
 }
diff --git a/content/public/renderer/document_state.h b/content/public/renderer/document_state.h
index 40a5f42..cd9fd58 100644
--- a/content/public/renderer/document_state.h
+++ b/content/public/renderer/document_state.h
@@ -18,7 +18,6 @@
 namespace content {
 
 class NavigationState;
-struct PasswordForm;
 
 // The RenderView stores an instance of this class in the "extra data" of each
 // WebDataSource (see RenderView::DidCreateDataSource).
@@ -162,20 +161,6 @@
     was_fetched_via_proxy_ = value;
   }
 
-  // If set, contains the PasswordForm that we believe triggered the current
-  // navigation (there is some ambiguity in the case of javascript initiated
-  // navigations). This information is used by the PasswordManager to determine
-  // if the user should be prompted to save their password.
-  //
-  // Note that setting this field doesn't affect where the data is sent or what
-  // origin we associate it with, only whether we prompt the user to save it.
-  // That is, a false positive is a usability issue (e.g. may try to save a
-  // mis-typed password) not a security issue.
-  PasswordForm* password_form_data() const {
-    return password_form_data_.get();
-  }
-  void set_password_form_data(scoped_ptr<PasswordForm> data);
-
   void set_was_prefetcher(bool value) { was_prefetcher_ = value; }
   bool was_prefetcher() const { return was_prefetcher_; }
 
@@ -220,8 +205,6 @@
   net::HttpResponseInfo::ConnectionInfo connection_info_;
   bool was_fetched_via_proxy_;
 
-  scoped_ptr<PasswordForm> password_form_data_;
-
   // A prefetcher is a page that contains link rel=prefetch elements.
   bool was_prefetcher_;
   bool was_referred_by_prefetcher_;
diff --git a/content/public/renderer/render_view_observer.h b/content/public/renderer/render_view_observer.h
index 4bb7dd8..10dad33 100644
--- a/content/public/renderer/render_view_observer.h
+++ b/content/public/renderer/render_view_observer.h
@@ -67,6 +67,8 @@
                             WebKit::WebFrame* frame) {}
   virtual void FrameDetached(WebKit::WebFrame* frame) {}
   virtual void FrameWillClose(WebKit::WebFrame* frame) {}
+  virtual void WillSendSubmitEvent(WebKit::WebFrame* frame,
+                                   const WebKit::WebFormElement& form) {}
   virtual void WillSubmitForm(WebKit::WebFrame* frame,
                               const WebKit::WebFormElement& form) {}
   virtual void DidCreateDataSource(WebKit::WebFrame* frame,
@@ -92,6 +94,7 @@
   // These match incoming IPCs.
   virtual void Navigate(const GURL& url) {}
   virtual void ClosePage() {}
+  virtual void OrientationChangeEvent(int orientation) {}
 
   // IPC::Listener implementation.
   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
diff --git a/content/public/renderer/renderer_ppapi_host.h b/content/public/renderer/renderer_ppapi_host.h
index 329961e..2922ff3 100644
--- a/content/public/renderer/renderer_ppapi_host.h
+++ b/content/public/renderer/renderer_ppapi_host.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_PUBLIC_RENDERER_RENDERER_PPAPI_HOST_H_
 #define CONTENT_PUBLIC_RENDERER_RENDERER_PPAPI_HOST_H_
 
+#include <vector>
+
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
 #include "base/platform_file.h"
@@ -110,16 +112,16 @@
   virtual bool IsRunningInProcess() const = 0;
 
   // There are times when the renderer needs to create a ResourceHost in the
-  // browser. This function does so asynchronously. |nested_msg| is the
-  // resource host creation message and |instance| is the PP_Instance which
+  // browser. This function does so asynchronously. |nested_msgs| is a list of
+  // resource host creation messages and |instance| is the PP_Instance which
   // the resource will belong to. |callback| will be called with the pending
-  // host ID when the ResourceHost has been created. This can be passed back
-  // to the plugin to attach to the ResourceHost. A pending ID of 0 will be
-  // passed to the callback upon error.
-  virtual void CreateBrowserResourceHost(
+  // host IDs when the ResourceHosts have been created. This can be passed back
+  // to the plugin to attach to the ResourceHosts. Pending IDs of 0 will be
+  // passed to the callback if a ResourceHost fails to be created.
+  virtual void CreateBrowserResourceHosts(
       PP_Instance instance,
-      const IPC::Message& nested_msg,
-      const base::Callback<void(int)>& callback) const = 0;
+      const std::vector<IPC::Message>& nested_msgs,
+      const base::Callback<void(const std::vector<int>&)>& callback) const = 0;
 
  protected:
   virtual ~RendererPpapiHost() {}
diff --git a/content/public/renderer/web_preferences.h b/content/public/renderer/web_preferences.h
new file mode 100644
index 0000000..f383843
--- /dev/null
+++ b/content/public/renderer/web_preferences.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 CONTENT_PUBLIC_RENDERER_WEB_PREFERENCES_H_
+#define CONTENT_PUBLIC_RENDERER_WEB_PREFERENCES_H_
+
+#include "content/common/content_export.h"
+
+struct WebPreferences;
+
+namespace WebKit {
+class WebView;
+}
+
+namespace content {
+
+CONTENT_EXPORT void ApplyWebPreferences(const WebPreferences& prefs,
+                                        WebKit::WebView* web_view);
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_RENDERER_WEB_PREFERENCES_H_
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index ae04f50..9a0f317 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -102,11 +102,6 @@
 
   command_line->AppendSwitch(switches::kSkipGpuDataLoading);
 
-  MainFunctionParams params(*command_line);
-  params.ui_task =
-      new base::Closure(
-          base::Bind(&BrowserTestBase::ProxyRunTestOnMainThreadLoop, this));
-
 #if defined(USE_AURA)
   // Use test contexts for browser tests unless they override and force us to
   // use a real context.
@@ -152,6 +147,12 @@
   }
 
   SetUpInProcessBrowserTestFixture();
+
+  MainFunctionParams params(*command_line);
+  params.ui_task =
+      new base::Closure(
+          base::Bind(&BrowserTestBase::ProxyRunTestOnMainThreadLoop, this));
+
 #if defined(OS_ANDROID)
   BrowserMainRunner::Create()->Initialize(params);
   // We are done running the test by now. During teardown we
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index c801cd5..13846df 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -24,12 +24,14 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_view.h"
 #include "content/public/test/test_utils.h"
+#include "grit/webui_resources.h"
 #include "net/base/net_util.h"
 #include "net/cookies/cookie_store.h"
 #include "net/test/python_utils.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/resource_bundle.h"
 
 static const int kDefaultWsPort = 8880;
 
@@ -374,6 +376,39 @@
                                               result);
 }
 
+bool ExecuteWebUIResourceTest(
+    const internal::ToRenderViewHost& adapter,
+    const std::vector<int>& js_resource_ids) {
+  // Inject WebUI test runner script first prior to other scripts required to
+  // run the test as scripts may depend on it being declared.
+  std::vector<int> ids;
+  ids.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST);
+  ids.insert(ids.end(), js_resource_ids.begin(), js_resource_ids.end());
+
+  std::string script;
+  for (std::vector<int>::iterator iter = ids.begin();
+       iter != ids.end();
+       ++iter) {
+    ResourceBundle::GetSharedInstance().GetRawDataResource(*iter)
+        .AppendToString(&script);
+    script.append("\n");
+  }
+  if (!content::ExecuteScript(adapter, script))
+    return false;
+
+  content::DOMMessageQueue message_queue;
+  if (!content::ExecuteScript(adapter, "runTests()"))
+    return false;
+
+  std::string message;
+  do {
+    if (!message_queue.WaitForMessage(&message))
+      return false;
+  } while (message.compare("\"PENDING\"") == 0);
+
+  return message.compare("\"SUCCESS\"") == 0;
+}
+
 std::string GetCookies(BrowserContext* browser_context, const GURL& url) {
   std::string cookies;
   base::WaitableEvent event(true, false);
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index ece2805..4dce33e 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -147,6 +147,13 @@
                                    const std::string& script,
                                    std::string* result) WARN_UNUSED_RESULT;
 
+// Executes the WebUI resource test runner injecting each resource ID in
+// |js_resource_ids| prior to executing the tests.
+//
+// Returns true if tests ran successfully, false otherwise.
+bool ExecuteWebUIResourceTest(const internal::ToRenderViewHost& adapter,
+                              const std::vector<int>& js_resource_ids);
+
 // Returns the cookies for the given url.
 std::string GetCookies(BrowserContext* browser_context, const GURL& url);
 
diff --git a/content/public/test/content_test_suite_base.cc b/content/public/test/content_test_suite_base.cc
index 5bf5b5e..f245683 100644
--- a/content/public/test/content_test_suite_base.cc
+++ b/content/public/test/content_test_suite_base.cc
@@ -10,9 +10,15 @@
 #include "base/test/test_suite.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/browser/browser_thread_impl.h"
+#include "content/browser/gpu/gpu_process_host.h"
 #include "content/common/url_schemes.h"
+#include "content/gpu/gpu_main_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/utility_process_host.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_paths.h"
+#include "content/renderer/renderer_main_thread.h"
+#include "content/utility/utility_main_thread.h"
 #include "media/base/media.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_base_paths.h"
@@ -60,6 +66,13 @@
   ui::shell_dialogs::RegisterJni(env);
 #endif
 
+#if !defined(OS_IOS)
+  UtilityProcessHost::RegisterUtilityMainThreadFactory(CreateUtilityMainThread);
+  RenderProcessHost::RegisterRendererMainThreadFactory(
+      CreateRendererMainThread);
+  GpuProcessHost::RegisterGpuMainThreadFactory(CreateGpuMainThread);
+#endif
+
   if (external_libraries_enabled_)
     media::InitializeMediaLibraryForTesting();
 
diff --git a/content/public/test/layouttest_support.h b/content/public/test/layouttest_support.h
index 01577bd..5d972f3 100644
--- a/content/public/test/layouttest_support.h
+++ b/content/public/test/layouttest_support.h
@@ -9,6 +9,7 @@
 
 namespace WebKit {
 class WebDeviceMotionData;
+class WebDeviceOrientationData;
 class WebGamepads;
 struct WebSize;
 }
@@ -44,6 +45,10 @@
 // a listener through WebKitPlatformSupport::setDeviceMotionListener().
 void SetMockDeviceMotionData(const WebKit::WebDeviceMotionData& data);
 
+// Sets WebDeviceOrientationData that should be used when registering
+// a listener through WebKitPlatformSupport::setDeviceOrientationListener().
+void SetMockDeviceOrientationData(const WebKit::WebDeviceOrientationData& data);
+
 // Returns the length of the local session history of a render view.
 int GetLocalSessionHistoryLength(RenderView* render_view);
 
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index df772f6..4136fe0 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -175,9 +175,10 @@
       kSurfaceId,
       kInvalidSessionStorageNamespaceId,
       string16(),
-      false,
-      false,
-      1,
+      false, // is_renderer_created
+      false, // swapped_out
+      false, // hidden
+      1, // next_page_id
       WebKit::WebScreenInfo(),
       AccessibilityModeOff,
       true);
diff --git a/content/public/test/test_browser_thread.h b/content/public/test/test_browser_thread.h
index c4c386b..fd3116c 100644
--- a/content/public/test/test_browser_thread.h
+++ b/content/public/test/test_browser_thread.h
@@ -18,6 +18,7 @@
 
 class TestBrowserThreadImpl;
 
+// Deprecated: use TestBrowserThreadBundle instead. See http://crbug.com/272091
 // A BrowserThread for unit tests; this lets unit tests in chrome/ create
 // BrowserThread instances.
 class TestBrowserThread {
diff --git a/content/public/test/test_browser_thread_bundle.cc b/content/public/test/test_browser_thread_bundle.cc
index 7d2e58e..86ff725 100644
--- a/content/public/test/test_browser_thread_bundle.cc
+++ b/content/public/test/test_browser_thread_bundle.cc
@@ -6,6 +6,7 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "content/browser/browser_thread_impl.h"
 #include "content/public/test/test_browser_thread.h"
 
 namespace content {
@@ -19,6 +20,12 @@
 }
 
 TestBrowserThreadBundle::~TestBrowserThreadBundle() {
+  // To avoid memory leaks, we must ensure that any tasks posted to the blocking
+  // pool via PostTaskAndReply are able to reply back to the originating thread.
+  // Thus we must flush the blocking pool while the browser threads still exist.
+  base::RunLoop().RunUntilIdle();
+  BrowserThreadImpl::FlushThreadPoolHelper();
+
   // To ensure a clean teardown, each thread's message loop must be flushed
   // just before the thread is destroyed. But destroying a fake thread does not
   // automatically flush the message loop, so we have to do it manually.
@@ -36,6 +43,11 @@
   base::RunLoop().RunUntilIdle();
   db_thread_.reset();
   base::RunLoop().RunUntilIdle();
+  // This is the point at which we normally shut down the thread pool. So flush
+  // it again in case any shutdown tasks have been posted to the pool from the
+  // threads above.
+  BrowserThreadImpl::FlushThreadPoolHelper();
+  base::RunLoop().RunUntilIdle();
   ui_thread_.reset();
   base::RunLoop().RunUntilIdle();
 }
diff --git a/content/public/test/test_browser_thread_bundle.h b/content/public/test/test_browser_thread_bundle.h
index 64d30fe..2f4db0b 100644
--- a/content/public/test/test_browser_thread_bundle.h
+++ b/content/public/test/test_browser_thread_bundle.h
@@ -17,6 +17,14 @@
 // Unit tests should use base::RunLoop (e.g., base::RunLoop().RunUntilIdle()).
 // TODO(phajdan.jr): Revise this comment after switch to Aura.
 //
+// The TestBrowserThreadBundle will also flush the blocking pool on destruction.
+// We do this to avoid memory leaks, particularly in the case of threads posting
+// tasks to the blocking pool via PostTaskAndReply. By ensuring that the tasks
+// are run while the originating TestBroswserThreads still exist, we prevent
+// leakage of PostTaskAndReplyRelay objects. We also flush the blocking pool
+// again at the point where it would normally be shut down, to better simulate
+// the normal thread shutdown process.
+//
 // Some tests using the IO thread expect a MessageLoopForIO. Passing
 // IO_MAINLOOP will use a MessageLoopForIO for the main MessageLoop.
 // Most of the time, this avoids needing to use a REAL_IO_THREAD.
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc
index 0c3e355..c29a239 100644
--- a/content/public/test/test_launcher.cc
+++ b/content/public/test/test_launcher.cc
@@ -86,7 +86,17 @@
     }
   }
 
-  CommandLine new_cmd_line(command_line);
+  CommandLine new_cmd_line(command_line.GetProgram());
+  CommandLine::SwitchMap switches = command_line.GetSwitches();
+
+  // Strip out gtest_output flag because otherwise we would overwrite results
+  // of the other tests.
+  switches.erase(base::kGTestOutputFlag);
+
+  for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
+       iter != switches.end(); ++iter) {
+    new_cmd_line.AppendSwitchNative(iter->first, iter->second);
+  }
 
   // Always enable disabled tests.  This method is not called with disabled
   // tests unless this flag was specified to the browser test executable.
diff --git a/content/renderer/accessibility/accessibility_node_serializer.cc b/content/renderer/accessibility/accessibility_node_serializer.cc
index f7a9138..e6cca96 100644
--- a/content/renderer/accessibility/accessibility_node_serializer.cc
+++ b/content/renderer/accessibility/accessibility_node_serializer.cc
@@ -46,6 +46,10 @@
   return parent.equals(ancestor);
 }
 
+  bool IsTrue(std::string html_value) {
+  return LowerCaseEqualsASCII(html_value, "true");
+}
+
 // Provides a conversion between the WebKit::WebAccessibilityRole and a role
 // supported on the Browser side. Listed alphabetically by the
 // WebKit::WebAccessibilityRole (except for default role).
@@ -351,56 +355,64 @@
 void SerializeAccessibilityNode(
     const WebAccessibilityObject& src,
     AccessibilityNodeData* dst) {
-  dst->name = src.title();
   dst->role = ConvertRole(src.roleValue());
   dst->state = ConvertState(src);
   dst->location = src.boundingBoxRect();
   dst->id = src.axID();
+  std::string name = UTF16ToUTF8(src.title());
 
-  if (src.valueDescription().length())
-    dst->value = src.valueDescription();
-  else
-    dst->value = src.stringValue();
+  std::string value;
+  if (src.valueDescription().length()) {
+    dst->AddStringAttribute(dst->ATTR_VALUE,
+                            UTF16ToUTF8(src.valueDescription()));
+  } else {
+    dst->AddStringAttribute(dst->ATTR_VALUE, UTF16ToUTF8(src.stringValue()));
+  }
 
   if (dst->role == AccessibilityNodeData::ROLE_COLOR_WELL) {
     int r, g, b;
     src.colorValue(r, g, b);
-    dst->int_attributes[dst->ATTR_COLOR_VALUE_RED] = r;
-    dst->int_attributes[dst->ATTR_COLOR_VALUE_GREEN] = g;
-    dst->int_attributes[dst->ATTR_COLOR_VALUE_BLUE] = b;
+    dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_RED, r);
+    dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_GREEN, g);
+    dst->AddIntAttribute(dst->ATTR_COLOR_VALUE_BLUE, b);
   }
 
   if (src.accessKey().length())
-    dst->string_attributes[dst->ATTR_ACCESS_KEY] = src.accessKey();
+    dst->AddStringAttribute(dst->ATTR_ACCESS_KEY, UTF16ToUTF8(src.accessKey()));
   if (src.actionVerb().length())
-    dst->string_attributes[dst->ATTR_ACTION] = src.actionVerb();
+    dst->AddStringAttribute(dst->ATTR_ACTION, UTF16ToUTF8(src.actionVerb()));
   if (src.isAriaReadOnly())
-    dst->bool_attributes[dst->ATTR_ARIA_READONLY] = true;
+    dst->AddBoolAttribute(dst->ATTR_ARIA_READONLY, true);
   if (src.isButtonStateMixed())
-    dst->bool_attributes[dst->ATTR_BUTTON_MIXED] = true;
+    dst->AddBoolAttribute(dst->ATTR_BUTTON_MIXED, true);
   if (src.canSetValueAttribute())
-    dst->bool_attributes[dst->ATTR_CAN_SET_VALUE] = true;
-  if (src.accessibilityDescription().length())
-    dst->string_attributes[dst->ATTR_DESCRIPTION] =
-        src.accessibilityDescription();
-  if (src.hasComputedStyle())
-    dst->string_attributes[dst->ATTR_DISPLAY] = src.computedStyleDisplay();
+    dst->AddBoolAttribute(dst->ATTR_CAN_SET_VALUE, true);
+  if (src.accessibilityDescription().length()) {
+    dst->AddStringAttribute(dst->ATTR_DESCRIPTION,
+                            UTF16ToUTF8(src.accessibilityDescription()));
+  }
+  if (src.hasComputedStyle()) {
+    dst->AddStringAttribute(dst->ATTR_DISPLAY,
+                            UTF16ToUTF8(src.computedStyleDisplay()));
+  }
   if (src.helpText().length())
-    dst->string_attributes[dst->ATTR_HELP] = src.helpText();
-  if (src.keyboardShortcut().length())
-    dst->string_attributes[dst->ATTR_SHORTCUT] = src.keyboardShortcut();
+    dst->AddStringAttribute(dst->ATTR_HELP, UTF16ToUTF8(src.helpText()));
+  if (src.keyboardShortcut().length()) {
+    dst->AddStringAttribute(dst->ATTR_SHORTCUT,
+                            UTF16ToUTF8(src.keyboardShortcut()));
+  }
   if (!src.titleUIElement().isDetached()) {
-    dst->int_attributes[dst->ATTR_TITLE_UI_ELEMENT] =
-        src.titleUIElement().axID();
+    dst->AddIntAttribute(dst->ATTR_TITLE_UI_ELEMENT,
+                         src.titleUIElement().axID());
   }
   if (!src.url().isEmpty())
-    dst->string_attributes[dst->ATTR_URL] = src.url().spec().utf16();
+    dst->AddStringAttribute(dst->ATTR_URL, src.url().spec());
 
   if (dst->role == dst->ROLE_HEADING)
-    dst->int_attributes[dst->ATTR_HIERARCHICAL_LEVEL] = src.headingLevel();
+    dst->AddIntAttribute(dst->ATTR_HIERARCHICAL_LEVEL, src.headingLevel());
   else if ((dst->role == dst->ROLE_TREE_ITEM || dst->role == dst->ROLE_ROW) &&
            src.hierarchicalLevel() > 0) {
-    dst->int_attributes[dst->ATTR_HIERARCHICAL_LEVEL] = src.hierarchicalLevel();
+    dst->AddIntAttribute(dst->ATTR_HIERARCHICAL_LEVEL, src.hierarchicalLevel());
   }
 
   // Treat the active list box item as focused.
@@ -412,6 +424,10 @@
 
   WebNode node = src.node();
   bool is_iframe = false;
+  std::string live_atomic;
+  std::string live_busy;
+  std::string live_status;
+  std::string live_relevant;
 
   if (!node.isNull() && node.isElementNode()) {
     WebElement element = node.to<WebElement>();
@@ -423,143 +439,163 @@
     // TODO(ctguil): The tagName in WebKit is lower cased but
     // HTMLElement::nodeName calls localNameUpper. Consider adding
     // a WebElement method that returns the original lower cased tagName.
-    dst->string_attributes[dst->ATTR_HTML_TAG] =
-        StringToLowerASCII(string16(element.tagName()));
+    dst->AddStringAttribute(
+        dst->ATTR_HTML_TAG,
+        StringToLowerASCII(UTF16ToUTF8(element.tagName())));
     for (unsigned i = 0; i < element.attributeCount(); ++i) {
-      string16 name = StringToLowerASCII(string16(
+      std::string name = StringToLowerASCII(UTF16ToUTF8(
           element.attributeLocalName(i)));
-      string16 value = element.attributeValue(i);
-      dst->html_attributes.push_back(
-          std::pair<string16, string16>(name, value));
+      std::string value = UTF16ToUTF8(element.attributeValue(i));
+      dst->html_attributes.push_back(std::make_pair(name, value));
     }
 
     if (dst->role == dst->ROLE_EDITABLE_TEXT ||
         dst->role == dst->ROLE_TEXTAREA ||
         dst->role == dst->ROLE_TEXT_FIELD) {
-      dst->int_attributes[dst->ATTR_TEXT_SEL_START] = src.selectionStart();
-      dst->int_attributes[dst->ATTR_TEXT_SEL_END] = src.selectionEnd();
+      dst->AddIntAttribute(dst->ATTR_TEXT_SEL_START, src.selectionStart());
+      dst->AddIntAttribute(dst->ATTR_TEXT_SEL_END, src.selectionEnd());
 
       WebVector<int> src_line_breaks;
       src.lineBreaks(src_line_breaks);
-      dst->line_breaks.reserve(src_line_breaks.size());
-      for (size_t i = 0; i < src_line_breaks.size(); ++i)
-        dst->line_breaks.push_back(src_line_breaks[i]);
+      if (src_line_breaks.size() > 0) {
+        std::vector<int32> line_breaks;
+        line_breaks.reserve(src_line_breaks.size());
+        for (size_t i = 0; i < src_line_breaks.size(); ++i)
+          line_breaks.push_back(src_line_breaks[i]);
+        dst->AddIntListAttribute(dst->ATTR_LINE_BREAKS, line_breaks);
+      }
     }
 
     // ARIA role.
     if (element.hasAttribute("role")) {
-      dst->string_attributes[dst->ATTR_ROLE] = element.getAttribute("role");
+      dst->AddStringAttribute(dst->ATTR_ROLE,
+                              UTF16ToUTF8(element.getAttribute("role")));
     }
 
     // Live region attributes
-    if (element.hasAttribute("aria-atomic")) {
-      dst->bool_attributes[dst->ATTR_LIVE_ATOMIC] =
-          LowerCaseEqualsASCII(element.getAttribute("aria-atomic"), "true");
-    }
-    if (element.hasAttribute("aria-busy")) {
-      dst->bool_attributes[dst->ATTR_LIVE_BUSY] =
-          LowerCaseEqualsASCII(element.getAttribute("aria-busy"), "true");
-    }
-    if (element.hasAttribute("aria-live")) {
-      dst->string_attributes[dst->ATTR_LIVE_STATUS] =
-          element.getAttribute("aria-live");
-    }
-    if (element.hasAttribute("aria-relevant")) {
-      dst->string_attributes[dst->ATTR_LIVE_RELEVANT] =
-          element.getAttribute("aria-relevant");
-    }
+    live_atomic = UTF16ToUTF8(element.getAttribute("aria-atomic"));
+    live_busy = UTF16ToUTF8(element.getAttribute("aria-busy"));
+    live_status = UTF16ToUTF8(element.getAttribute("aria-live"));
+    live_relevant = UTF16ToUTF8(element.getAttribute("aria-relevant"));
   }
 
   // Walk up the parent chain to set live region attributes of containers
-
+  std::string container_live_atomic;
+  std::string container_live_busy;
+  std::string container_live_status;
+  std::string container_live_relevant;
   WebAccessibilityObject container_accessible = src;
   while (!container_accessible.isDetached()) {
     WebNode container_node = container_accessible.node();
     if (!container_node.isNull() && container_node.isElementNode()) {
-      WebElement container_elem =
-          container_node.to<WebElement>();
+      WebElement container_elem = container_node.to<WebElement>();
       if (container_elem.hasAttribute("aria-atomic") &&
-          dst->bool_attributes.find(dst->ATTR_CONTAINER_LIVE_ATOMIC) ==
-          dst->bool_attributes.end()) {
-        dst->bool_attributes[dst->ATTR_CONTAINER_LIVE_ATOMIC] =
-            LowerCaseEqualsASCII(container_elem.getAttribute("aria-atomic"),
-                                 "true");
+          container_live_atomic.empty()) {
+        container_live_atomic =
+            UTF16ToUTF8(container_elem.getAttribute("aria-atomic"));
       }
       if (container_elem.hasAttribute("aria-busy") &&
-          dst->bool_attributes.find(dst->ATTR_CONTAINER_LIVE_BUSY) ==
-          dst->bool_attributes.end()) {
-        dst->bool_attributes[dst->ATTR_CONTAINER_LIVE_BUSY] =
-            LowerCaseEqualsASCII(container_elem.getAttribute("aria-busy"),
-                                 "true");
+          container_live_busy.empty()) {
+        container_live_busy =
+            UTF16ToUTF8(container_elem.getAttribute("aria-busy"));
       }
       if (container_elem.hasAttribute("aria-live") &&
-          dst->string_attributes.find(dst->ATTR_CONTAINER_LIVE_STATUS) ==
-          dst->string_attributes.end()) {
-        dst->string_attributes[dst->ATTR_CONTAINER_LIVE_STATUS] =
-            container_elem.getAttribute("aria-live");
+          container_live_status.empty()) {
+        container_live_status =
+            UTF16ToUTF8(container_elem.getAttribute("aria-live"));
       }
       if (container_elem.hasAttribute("aria-relevant") &&
-          dst->string_attributes.find(dst->ATTR_CONTAINER_LIVE_RELEVANT) ==
-          dst->string_attributes.end()) {
-        dst->string_attributes[dst->ATTR_CONTAINER_LIVE_RELEVANT] =
-            container_elem.getAttribute("aria-relevant");
+          container_live_relevant.empty()) {
+        container_live_relevant =
+            UTF16ToUTF8(container_elem.getAttribute("aria-relevant"));
       }
     }
     container_accessible = container_accessible.parentObject();
   }
 
+  if (!live_atomic.empty())
+    dst->AddBoolAttribute(dst->ATTR_LIVE_ATOMIC, IsTrue(live_atomic));
+  if (!live_busy.empty())
+    dst->AddBoolAttribute(dst->ATTR_LIVE_BUSY, IsTrue(live_busy));
+  if (!live_status.empty())
+    dst->AddStringAttribute(dst->ATTR_LIVE_STATUS, live_status);
+  if (!live_relevant.empty())
+    dst->AddStringAttribute(dst->ATTR_LIVE_RELEVANT, live_relevant);
+
+  if (!container_live_atomic.empty()) {
+    dst->AddBoolAttribute(dst->ATTR_CONTAINER_LIVE_ATOMIC,
+                          IsTrue(container_live_atomic));
+  }
+  if (!container_live_busy.empty()) {
+    dst->AddBoolAttribute(dst->ATTR_CONTAINER_LIVE_BUSY,
+                          IsTrue(container_live_busy));
+  }
+  if (!container_live_status.empty()) {
+    dst->AddStringAttribute(dst->ATTR_CONTAINER_LIVE_STATUS,
+                            container_live_status);
+  }
+  if (!container_live_relevant.empty()) {
+    dst->AddStringAttribute(dst->ATTR_CONTAINER_LIVE_RELEVANT,
+                            container_live_relevant);
+  }
+
   if (dst->role == dst->ROLE_PROGRESS_INDICATOR ||
       dst->role == dst->ROLE_SCROLLBAR ||
       dst->role == dst->ROLE_SLIDER ||
       dst->role == dst->ROLE_SPIN_BUTTON) {
-    dst->float_attributes[dst->ATTR_VALUE_FOR_RANGE] = src.valueForRange();
-    dst->float_attributes[dst->ATTR_MAX_VALUE_FOR_RANGE] =
-        src.maxValueForRange();
-    dst->float_attributes[dst->ATTR_MIN_VALUE_FOR_RANGE] =
-        src.minValueForRange();
+    dst->AddFloatAttribute(dst->ATTR_VALUE_FOR_RANGE, src.valueForRange());
+    dst->AddFloatAttribute(dst->ATTR_MAX_VALUE_FOR_RANGE,
+                           src.maxValueForRange());
+    dst->AddFloatAttribute(dst->ATTR_MIN_VALUE_FOR_RANGE,
+                           src.minValueForRange());
   }
 
   if (dst->role == dst->ROLE_DOCUMENT ||
       dst->role == dst->ROLE_WEB_AREA) {
-    dst->string_attributes[dst->ATTR_HTML_TAG] = ASCIIToUTF16("#document");
+    dst->AddStringAttribute(dst->ATTR_HTML_TAG, "#document");
     const WebDocument& document = src.document();
-    if (dst->name.empty())
-      dst->name = document.title();
-    dst->string_attributes[dst->ATTR_DOC_TITLE] = document.title();
-    dst->string_attributes[dst->ATTR_DOC_URL] = document.url().spec().utf16();
-    dst->string_attributes[dst->ATTR_DOC_MIMETYPE] =
-        ASCIIToUTF16(document.isXHTMLDocument() ? "text/xhtml" : "text/html");
-    dst->bool_attributes[dst->ATTR_DOC_LOADED] = src.isLoaded();
-    dst->float_attributes[dst->ATTR_DOC_LOADING_PROGRESS] =
-        src.estimatedLoadingProgress();
+    if (name.empty())
+      name = UTF16ToUTF8(document.title());
+    dst->AddStringAttribute(dst->ATTR_DOC_TITLE, UTF16ToUTF8(document.title()));
+    dst->AddStringAttribute(dst->ATTR_DOC_URL, document.url().spec());
+    dst->AddStringAttribute(
+        dst->ATTR_DOC_MIMETYPE,
+        document.isXHTMLDocument() ? "text/xhtml" : "text/html");
+    dst->AddBoolAttribute(dst->ATTR_DOC_LOADED, src.isLoaded());
+    dst->AddFloatAttribute(dst->ATTR_DOC_LOADING_PROGRESS,
+                           src.estimatedLoadingProgress());
 
     const WebDocumentType& doctype = document.doctype();
-    if (!doctype.isNull())
-      dst->string_attributes[dst->ATTR_DOC_DOCTYPE] = doctype.name();
+    if (!doctype.isNull()) {
+      dst->AddStringAttribute(dst->ATTR_DOC_DOCTYPE,
+                              UTF16ToUTF8(doctype.name()));
+    }
 
     const gfx::Size& scroll_offset = document.frame()->scrollOffset();
-    dst->int_attributes[dst->ATTR_SCROLL_X] = scroll_offset.width();
-    dst->int_attributes[dst->ATTR_SCROLL_Y] = scroll_offset.height();
+    dst->AddIntAttribute(dst->ATTR_SCROLL_X, scroll_offset.width());
+    dst->AddIntAttribute(dst->ATTR_SCROLL_Y, scroll_offset.height());
 
     const gfx::Size& min_offset = document.frame()->minimumScrollOffset();
-    dst->int_attributes[dst->ATTR_SCROLL_X_MIN] = min_offset.width();
-    dst->int_attributes[dst->ATTR_SCROLL_Y_MIN] = min_offset.height();
+    dst->AddIntAttribute(dst->ATTR_SCROLL_X_MIN, min_offset.width());
+    dst->AddIntAttribute(dst->ATTR_SCROLL_Y_MIN, min_offset.height());
 
     const gfx::Size& max_offset = document.frame()->maximumScrollOffset();
-    dst->int_attributes[dst->ATTR_SCROLL_X_MAX] = max_offset.width();
-    dst->int_attributes[dst->ATTR_SCROLL_Y_MAX] = max_offset.height();
+    dst->AddIntAttribute(dst->ATTR_SCROLL_X_MAX, max_offset.width());
+    dst->AddIntAttribute(dst->ATTR_SCROLL_Y_MAX, max_offset.height());
   }
 
   if (dst->role == dst->ROLE_TABLE) {
     int column_count = src.columnCount();
     int row_count = src.rowCount();
     if (column_count > 0 && row_count > 0) {
-      std::set<int> unique_cell_id_set;
-      dst->int_attributes[dst->ATTR_TABLE_COLUMN_COUNT] = column_count;
-      dst->int_attributes[dst->ATTR_TABLE_ROW_COUNT] = row_count;
+      std::set<int32> unique_cell_id_set;
+      std::vector<int32> cell_ids;
+      std::vector<int32> unique_cell_ids;
+      dst->AddIntAttribute(dst->ATTR_TABLE_COLUMN_COUNT, column_count);
+      dst->AddIntAttribute(dst->ATTR_TABLE_ROW_COUNT, row_count);
       WebAccessibilityObject header = src.headerContainerObject();
       if (!header.isDetached())
-        dst->int_attributes[dst->ATTR_TABLE_HEADER_ID] = header.axID();
+        dst->AddIntAttribute(dst->ATTR_TABLE_HEADER_ID, header.axID());
       for (int i = 0; i < column_count * row_count; ++i) {
         WebAccessibilityObject cell = src.cellForColumnAndRow(
             i % column_count, i / column_count);
@@ -568,39 +604,43 @@
           cell_id = cell.axID();
           if (unique_cell_id_set.find(cell_id) == unique_cell_id_set.end()) {
             unique_cell_id_set.insert(cell_id);
-            dst->unique_cell_ids.push_back(cell_id);
+            unique_cell_ids.push_back(cell_id);
           }
         }
-        dst->cell_ids.push_back(cell_id);
+        cell_ids.push_back(cell_id);
       }
+      dst->AddIntListAttribute(dst->ATTR_CELL_IDS, cell_ids);
+      dst->AddIntListAttribute(dst->ATTR_UNIQUE_CELL_IDS, unique_cell_ids);
     }
   }
 
   if (dst->role == dst->ROLE_ROW) {
-    dst->int_attributes[dst->ATTR_TABLE_ROW_INDEX] = src.rowIndex();
+    dst->AddIntAttribute(dst->ATTR_TABLE_ROW_INDEX, src.rowIndex());
     WebAccessibilityObject header = src.rowHeader();
     if (!header.isDetached())
-      dst->int_attributes[dst->ATTR_TABLE_ROW_HEADER_ID] = header.axID();
+      dst->AddIntAttribute(dst->ATTR_TABLE_ROW_HEADER_ID, header.axID());
   }
 
   if (dst->role == dst->ROLE_COLUMN) {
-    dst->int_attributes[dst->ATTR_TABLE_COLUMN_INDEX] = src.columnIndex();
+    dst->AddIntAttribute(dst->ATTR_TABLE_COLUMN_INDEX, src.columnIndex());
     WebAccessibilityObject header = src.columnHeader();
     if (!header.isDetached())
-      dst->int_attributes[dst->ATTR_TABLE_COLUMN_HEADER_ID] = header.axID();
+      dst->AddIntAttribute(dst->ATTR_TABLE_COLUMN_HEADER_ID, header.axID());
   }
 
   if (dst->role == dst->ROLE_CELL ||
       dst->role == dst->ROLE_ROW_HEADER ||
       dst->role == dst->ROLE_COLUMN_HEADER) {
-    dst->int_attributes[dst->ATTR_TABLE_CELL_COLUMN_INDEX] =
-        src.cellColumnIndex();
-    dst->int_attributes[dst->ATTR_TABLE_CELL_COLUMN_SPAN] =
-        src.cellColumnSpan();
-    dst->int_attributes[dst->ATTR_TABLE_CELL_ROW_INDEX] = src.cellRowIndex();
-    dst->int_attributes[dst->ATTR_TABLE_CELL_ROW_SPAN] = src.cellRowSpan();
+    dst->AddIntAttribute(dst->ATTR_TABLE_CELL_COLUMN_INDEX,
+                         src.cellColumnIndex());
+    dst->AddIntAttribute(dst->ATTR_TABLE_CELL_COLUMN_SPAN,
+                         src.cellColumnSpan());
+    dst->AddIntAttribute(dst->ATTR_TABLE_CELL_ROW_INDEX, src.cellRowIndex());
+    dst->AddIntAttribute(dst->ATTR_TABLE_CELL_ROW_SPAN, src.cellRowSpan());
   }
 
+  dst->AddStringAttribute(dst->ATTR_NAME, name);
+
   // Add the ids of *indirect* children - those who are children of this node,
   // but whose parent is *not* this node. One example is a table
   // cell, which is a child of both a row and a column. Because the cell's
@@ -609,8 +649,13 @@
   int child_count = src.childCount();
   for (int i = 0; i < child_count; ++i) {
     WebAccessibilityObject child = src.childAt(i);
+    std::vector<int32> indirect_child_ids;
     if (!is_iframe && !child.isDetached() && !IsParentUnignoredOf(src, child))
-      dst->indirect_child_ids.push_back(child.axID());
+      indirect_child_ids.push_back(child.axID());
+    if (indirect_child_ids.size() > 0) {
+      dst->AddIntListAttribute(
+          dst->ATTR_INDIRECT_CHILD_IDS, indirect_child_ids);
+    }
   }
 }
 
diff --git a/content/renderer/accessibility/renderer_accessibility_complete.cc b/content/renderer/accessibility/renderer_accessibility_complete.cc
index abce9c8..1d92ba6 100644
--- a/content/renderer/accessibility/renderer_accessibility_complete.cc
+++ b/content/renderer/accessibility/renderer_accessibility_complete.cc
@@ -405,8 +405,8 @@
     AccessibilityNodeData& serialized_node = notification_msg.nodes[i];
     serialized_node.id = location_changes[i]->id;
     serialized_node.location = location_changes[i]->location;
-    serialized_node.bool_attributes[
-        AccessibilityNodeData::ATTR_UPDATE_LOCATION_ONLY] = true;
+    serialized_node.AddBoolAttribute(
+        AccessibilityNodeData::ATTR_UPDATE_LOCATION_ONLY, true);
   }
 
   notification_msgs->push_back(notification_msg);
diff --git a/content/renderer/android/synchronous_compositor_factory.h b/content/renderer/android/synchronous_compositor_factory.h
index 234a033..bd625be 100644
--- a/content/renderer/android/synchronous_compositor_factory.h
+++ b/content/renderer/android/synchronous_compositor_factory.h
@@ -20,6 +20,7 @@
 namespace content {
 
 class InputHandlerManagerClient;
+class StreamTextureFactory;
 
 // Decouples creation from usage of the parts needed for the synchonous
 // compositor rendering path. In practice this is only used in single
@@ -44,6 +45,8 @@
       GetOffscreenContextProviderForMainThread() = 0;
   virtual scoped_refptr<cc::ContextProvider>
       GetOffscreenContextProviderForCompositorThread() = 0;
+  virtual scoped_ptr<StreamTextureFactory> CreateStreamTextureFactory(
+      int view_id) = 0;
 
  protected:
   SynchronousCompositorFactory() {}
diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc
index 03fffc1..23537a5 100644
--- a/content/renderer/browser_plugin/browser_plugin.cc
+++ b/content/renderer/browser_plugin/browser_plugin.cc
@@ -71,6 +71,7 @@
     WebKit::WebFrame* frame,
     const WebPluginParams& params)
     : guest_instance_id_(browser_plugin::kInstanceIDNone),
+      attached_(false),
       render_view_(render_view->AsWeakPtr()),
       render_view_routing_id_(render_view->GetRoutingID()),
       container_(NULL),
@@ -85,7 +86,6 @@
       content_window_routing_id_(MSG_ROUTING_NONE),
       plugin_focused_(false),
       visible_(true),
-      size_changed_in_flight_(false),
       before_first_navigation_(true),
       mouse_locked_(false),
       browser_plugin_manager_(render_view->GetBrowserPluginManager()),
@@ -280,7 +280,8 @@
     // BrowserPlugin and sending a BrowserPluginHostMsg_CreateGuest to the
     // browser process in order to create a new guest.
     if (before_first_navigation_) {
-      browser_plugin_manager()->AllocateInstanceID(this);
+      browser_plugin_manager()->AllocateInstanceID(
+          weak_ptr_factory_.GetWeakPtr());
       before_first_navigation_ = false;
     }
     return true;
@@ -330,21 +331,6 @@
                                            resize_guest_params));
 }
 
-void BrowserPlugin::SizeChangedDueToAutoSize(const gfx::Size& old_view_size) {
-  size_changed_in_flight_ = false;
-
-  std::map<std::string, base::Value*> props;
-  props[browser_plugin::kOldHeight] =
-      new base::FundamentalValue(old_view_size.height());
-  props[browser_plugin::kOldWidth] =
-      new base::FundamentalValue(old_view_size.width());
-  props[browser_plugin::kNewHeight] =
-      new base::FundamentalValue(last_view_size_.height());
-  props[browser_plugin::kNewWidth] =
-      new base::FundamentalValue(last_view_size_.width());
-  TriggerEvent(browser_plugin::kEventSizeChanged, &props);
-}
-
 // static
 bool BrowserPlugin::UsesDamageBuffer(
     const BrowserPluginMsg_UpdateRect_Params& params) {
@@ -409,6 +395,7 @@
             params.storage_partition_id;
     UpdateDOMAttribute(browser_plugin::kAttributePartition, partition_name);
   }
+  attached_ = true;
 }
 
 void BrowserPlugin::OnBuffersSwapped(
@@ -515,8 +502,9 @@
   // In HW mode, we need to do it here so we can continue sending
   // resize messages when needed.
   if (params.is_resize_ack ||
-      (!params.needs_ack && (auto_size || auto_size_ack_pending_)))
+      (!params.needs_ack && (auto_size || auto_size_ack_pending_))) {
     resize_ack_received_ = true;
+  }
 
   auto_size_ack_pending_ = false;
 
@@ -559,24 +547,7 @@
   if (auto_size && (params.view_size != last_view_size_)) {
     if (backing_store_)
       backing_store_->Clear(SK_ColorWHITE);
-    gfx::Size old_view_size = last_view_size_;
     last_view_size_ = params.view_size;
-    // Schedule a SizeChanged instead of calling it directly to ensure that
-    // the backing store has been updated before the developer attempts to
-    // resize to avoid flicker. |size_changed_in_flight_| acts as a form of
-    // flow control for SizeChanged events. If the guest's view size is changing
-    // rapidly before a SizeChanged event fires, then we avoid scheduling
-    // another SizeChanged event. SizeChanged reads the new size from
-    // |last_view_size_| so we can be sure that it always fires an event
-    // with the last seen view size.
-    if (container_ && !size_changed_in_flight_) {
-      size_changed_in_flight_ = true;
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&BrowserPlugin::SizeChangedDueToAutoSize,
-                     base::Unretained(this),
-                     old_view_size));
-    }
   }
 
   if (UsesDamageBuffer(params)) {
@@ -828,62 +799,6 @@
   container()->element().dispatchEvent(event);
 }
 
-void BrowserPlugin::OnTrackedObjectGarbageCollected(int id) {
-  // Remove from alive objects.
-  std::map<int, TrackedV8ObjectID*>::iterator iter =
-      tracked_v8_objects_.find(id);
-  if (iter != tracked_v8_objects_.end())
-    tracked_v8_objects_.erase(iter);
-
-  std::map<std::string, base::Value*> props;
-  props[browser_plugin::kId] = new base::FundamentalValue(id);
-  TriggerEvent(browser_plugin::kEventInternalTrackedObjectGone, &props);
-}
-
-void BrowserPlugin::TrackObjectLifetime(const NPVariant* request, int id) {
-  // An object of a given ID can only be tracked once.
-  if (tracked_v8_objects_.find(id) != tracked_v8_objects_.end())
-    return;
-
-  v8::Isolate* isolate = v8::Isolate::GetCurrent();
-  v8::Persistent<v8::Value> weak_request(
-      isolate, WebKit::WebBindings::toV8Value(request));
-
-  TrackedV8ObjectID* new_item =
-      new std::pair<int, base::WeakPtr<BrowserPlugin> >(
-          id, weak_ptr_factory_.GetWeakPtr());
-
-  std::pair<std::map<int, TrackedV8ObjectID*>::iterator, bool>
-      result = tracked_v8_objects_.insert(
-          std::make_pair(id, new_item));
-  CHECK(result.second);  // Inserted in the map.
-  TrackedV8ObjectID* request_item = result.first->second;
-  weak_request.MakeWeak(static_cast<void*>(request_item),
-                        WeakCallbackForTrackedObject);
-}
-
-// static
-void BrowserPlugin::WeakCallbackForTrackedObject(
-    v8::Isolate* isolate, v8::Persistent<v8::Value>* object, void* param) {
-
-  TrackedV8ObjectID* item_ptr = static_cast<TrackedV8ObjectID*>(param);
-  int object_id = item_ptr->first;
-  base::WeakPtr<BrowserPlugin> plugin = item_ptr->second;
-  delete item_ptr;
-
-  object->Dispose();
-  if (plugin.get()) {
-    // Asynchronously remove item from |tracked_v8_objects_|.
-    // Note that we are using weak pointer for the following PostTask, so we
-    // don't need to worry about BrowserPlugin going away.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&BrowserPlugin::OnTrackedObjectGarbageCollected,
-                   plugin,
-                   object_id));
-  }
-}
-
 void BrowserPlugin::UpdateGuestFocusState() {
   if (!HasGuestInstanceID())
     return;
@@ -1089,7 +1004,7 @@
   int old_width = width();
   int old_height = height();
   plugin_rect_ = window_rect;
-  if (!HasGuestInstanceID())
+  if (!attached())
     return;
 
   // In AutoSize mode, guests don't care when the BrowserPlugin container is
diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h
index d18906a..001f2d7 100644
--- a/content/renderer/browser_plugin/browser_plugin.h
+++ b/content/renderer/browser_plugin/browser_plugin.h
@@ -40,6 +40,7 @@
   RenderViewImpl* render_view() const { return render_view_.get(); }
   int render_view_routing_id() const { return render_view_routing_id_; }
   int guest_instance_id() const { return guest_instance_id_; }
+  bool attached() const { return attached_; }
 
   static BrowserPlugin* FromContainer(WebKit::WebPluginContainer* container);
 
@@ -115,10 +116,6 @@
 
   // A request to enable hardware compositing.
   void EnableCompositing(bool enable);
-  // A request from content client to track lifetime of a JavaScript object.
-  // This is used to track permission request objects, and new window API
-  // window objects.
-  void TrackObjectLifetime(const NPVariant* request, int id);
 
   // Returns true if |point| lies within the bounds of the plugin rectangle.
   // Not OK to use this function for making security-sensitive decision since it
@@ -270,9 +267,6 @@
   // Informs the guest of an updated autosize state.
   void UpdateGuestAutoSizeState(bool current_auto_size);
 
-  // Informs the BrowserPlugin that guest has changed its size in autosize mode.
-  void SizeChangedDueToAutoSize(const gfx::Size& old_view_size);
-
   // Indicates whether a damage buffer was used by the guest process for the
   // provided |params|.
   static bool UsesDamageBuffer(
@@ -283,14 +277,6 @@
   bool UsesPendingDamageBuffer(
       const BrowserPluginMsg_UpdateRect_Params& params);
 
-  // Called when the tracked object of |id| ID becomes unreachable in
-  // JavaScript.
-  void OnTrackedObjectGarbageCollected(int id);
-  // V8 garbage collection callback for |object|.
-  static void WeakCallbackForTrackedObject(v8::Isolate* isolate,
-                                           v8::Persistent<v8::Value>* object,
-                                           void* param);
-
   // IPC message handlers.
   // Please keep in alphabetical order.
   void OnAdvanceFocus(int instance_id, bool reverse);
@@ -312,6 +298,9 @@
   // This is the browser-process-allocated instance ID that uniquely identifies
   // a guest WebContents.
   int guest_instance_id_;
+  // This indicates whether this BrowserPlugin has been attached to a
+  // WebContents.
+  bool attached_;
   base::WeakPtr<RenderViewImpl> render_view_;
   // We cache the |render_view_|'s routing ID because we need it on destruction.
   // If the |render_view_| is destroyed before the BrowserPlugin is destroyed
@@ -343,7 +332,6 @@
   WebCursor cursor_;
 
   gfx::Size last_view_size_;
-  bool size_changed_in_flight_;
   bool before_first_navigation_;
   bool mouse_locked_;
 
diff --git a/content/renderer/browser_plugin/browser_plugin_bindings.cc b/content/renderer/browser_plugin/browser_plugin_bindings.cc
index a102558..bc20ea4 100644
--- a/content/renderer/browser_plugin/browser_plugin_bindings.cc
+++ b/content/renderer/browser_plugin/browser_plugin_bindings.cc
@@ -284,49 +284,6 @@
   DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingAttachWindowTo);
 };
 
-// Note: This is a method that is used internally by the <webview> shim only.
-// This should not be exposed to developers.
-class BrowserPluginBindingGetGuestInstanceID :
-    public BrowserPluginMethodBinding {
- public:
-  BrowserPluginBindingGetGuestInstanceID()
-      : BrowserPluginMethodBinding(
-          browser_plugin::kMethodGetGuestInstanceId, 0) {
-  }
-
-  virtual bool Invoke(BrowserPluginBindings* bindings,
-                      const NPVariant* args,
-                      NPVariant* result) OVERRIDE {
-    int guest_instance_id = bindings->instance()->guest_instance_id();
-    INT32_TO_NPVARIANT(guest_instance_id, *result);
-    return true;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingGetGuestInstanceID);
-};
-
-// Note: This is a method that is used internally by the <webview> shim only.
-// This should not be exposed to developers.
-class BrowserPluginBindingTrackObjectLifetime
-    : public BrowserPluginMethodBinding {
- public:
-  BrowserPluginBindingTrackObjectLifetime()
-      : BrowserPluginMethodBinding(
-          browser_plugin::kMethodInternalTrackObjectLifetime, 2) {
-  }
-
-  virtual bool Invoke(BrowserPluginBindings* bindings,
-                      const NPVariant* args,
-                      NPVariant* result) OVERRIDE {
-    bindings->instance()->TrackObjectLifetime(args, IntFromNPVariant(args[1]));
-    return true;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrowserPluginBindingTrackObjectLifetime);
-};
-
 // BrowserPluginPropertyBinding ------------------------------------------------
 
 class BrowserPluginPropertyBinding {
@@ -548,7 +505,6 @@
                            NPVariant* result) OVERRIDE {
     std::string name = bindings->instance()->GetNameAttribute();
     return StringToNPVariant(name, result);
-    return true;
   }
   virtual bool SetProperty(BrowserPluginBindings* bindings,
                            NPObject* np_obj,
@@ -589,10 +545,12 @@
       UpdateDOMAttribute(bindings, new_value);
       std::string error_message;
       if (!bindings->instance()->ParsePartitionAttribute(&error_message)) {
-        WebBindings::setException(
-            np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
         // Reset to old value on error.
         UpdateDOMAttribute(bindings, old_value);
+        // Exceptions must be set as the last operation before returning to
+        // script.
+        WebBindings::setException(
+            np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
         return false;
       }
     }
@@ -643,10 +601,12 @@
       UpdateDOMAttribute(bindings, new_value);
       std::string error_message;
       if (!bindings->instance()->ParseSrcAttribute(&error_message)) {
-        WebBindings::setException(
-            np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
         // Reset to old value on error.
         UpdateDOMAttribute(bindings, old_value);
+        // Exceptions must be set as the last operation before returning to
+        // script.
+        WebBindings::setException(
+            np_obj, static_cast<const NPUTF8 *>(error_message.c_str()));
         return false;
       }
     }
@@ -655,6 +615,8 @@
   virtual void RemoveProperty(BrowserPluginBindings* bindings,
                               NPObject* np_obj) OVERRIDE {
     std::string old_value = bindings->instance()->GetSrcAttribute();
+    if (old_value.empty())
+      return;
     // Remove the DOM attribute to trigger the mutation observer when it is
     // restored to its original value again.
     bindings->instance()->RemoveDOMAttribute(name());
@@ -685,8 +647,6 @@
 
   method_bindings_.push_back(new BrowserPluginBindingAttach);
   method_bindings_.push_back(new BrowserPluginBindingAttachWindowTo);
-  method_bindings_.push_back(new BrowserPluginBindingGetGuestInstanceID);
-  method_bindings_.push_back(new BrowserPluginBindingTrackObjectLifetime);
 
   property_bindings_.push_back(new BrowserPluginPropertyBindingAutoSize);
   property_bindings_.push_back(new BrowserPluginPropertyBindingContentWindow);
diff --git a/content/renderer/browser_plugin/browser_plugin_browsertest.cc b/content/renderer/browser_plugin/browser_plugin_browsertest.cc
index 1ad07e9..693752c 100644
--- a/content/renderer/browser_plugin/browser_plugin_browsertest.cc
+++ b/content/renderer/browser_plugin/browser_plugin_browsertest.cc
@@ -172,8 +172,13 @@
       msg, &iter, params))
     return NULL;
 
-  return static_cast<MockBrowserPlugin*>(
+  MockBrowserPlugin* browser_plugin = static_cast<MockBrowserPlugin*>(
       browser_plugin_manager()->GetBrowserPlugin(instance_id));
+
+  BrowserPluginMsg_Attach_ACK_Params attach_ack_params;
+  browser_plugin->OnAttachACK(instance_id, attach_ack_params);
+
+  return browser_plugin;
 }
 
 // This test verifies that an initial resize occurs when we instantiate the
diff --git a/content/renderer/browser_plugin/browser_plugin_manager.h b/content/renderer/browser_plugin/browser_plugin_manager.h
index 54c4bbd..7e08a1e 100644
--- a/content/renderer/browser_plugin/browser_plugin_manager.h
+++ b/content/renderer/browser_plugin/browser_plugin_manager.h
@@ -40,7 +40,7 @@
 
   explicit BrowserPluginManager(RenderViewImpl* render_view);
 
-  // Creates a new BrowserPlugin object with a unique identifier.
+  // Creates a new BrowserPlugin object.
   // BrowserPlugin is responsible for associating itself with the
   // BrowserPluginManager via AddBrowserPlugin. When it is destroyed, it is
   // responsible for removing its association via RemoveBrowserPlugin.
@@ -48,7 +48,12 @@
       RenderViewImpl* render_view,
       WebKit::WebFrame* frame,
       const WebKit::WebPluginParams& params) = 0;
-  virtual void AllocateInstanceID(BrowserPlugin* browser_plugin) = 0;
+
+  // Asynchronously requests a new browser-process-allocated instance ID.
+  // After the browser process allocates an ID, it calls back into the
+  // |browser_plugin| if it's still alive.
+  virtual void AllocateInstanceID(
+      const base::WeakPtr<BrowserPlugin>& browser_plugin) = 0;
 
   void AddBrowserPlugin(int guest_instance_id, BrowserPlugin* browser_plugin);
   void RemoveBrowserPlugin(int guest_instance_id);
diff --git a/content/renderer/browser_plugin/browser_plugin_manager_impl.cc b/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
index 2f7cdac..e7732f8 100644
--- a/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
+++ b/content/renderer/browser_plugin/browser_plugin_manager_impl.cc
@@ -30,10 +30,10 @@
 }
 
 void BrowserPluginManagerImpl::AllocateInstanceID(
-    BrowserPlugin* browser_plugin) {
+    const base::WeakPtr<BrowserPlugin>& browser_plugin) {
   int request_id = ++request_id_counter_;
-  pending_allocate_guest_instance_id_requests_.AddWithID(browser_plugin,
-                                                         request_id);
+  pending_allocate_guest_instance_id_requests_.insert(
+      std::make_pair(request_id, browser_plugin));
   Send(new BrowserPluginHostMsg_AllocateInstanceID(
       browser_plugin->render_view_routing_id(), request_id));
 }
@@ -79,11 +79,15 @@
     const IPC::Message& message,
     int request_id,
     int guest_instance_id) {
-  BrowserPlugin* plugin =
-    pending_allocate_guest_instance_id_requests_.Lookup(request_id);
+  InstanceIDMap::iterator it =
+      pending_allocate_guest_instance_id_requests_.find(request_id);
+  if (it == pending_allocate_guest_instance_id_requests_.end())
+    return;
+
+  const base::WeakPtr<BrowserPlugin> plugin(it->second);
   if (!plugin)
     return;
-  pending_allocate_guest_instance_id_requests_.Remove(request_id);
+  pending_allocate_guest_instance_id_requests_.erase(request_id);
   plugin->OnInstanceIDAllocated(guest_instance_id);
 }
 
diff --git a/content/renderer/browser_plugin/browser_plugin_manager_impl.h b/content/renderer/browser_plugin/browser_plugin_manager_impl.h
index 9045d9d..30ee72c 100644
--- a/content/renderer/browser_plugin/browser_plugin_manager_impl.h
+++ b/content/renderer/browser_plugin/browser_plugin_manager_impl.h
@@ -5,12 +5,11 @@
 #ifndef CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_IMPL_H_
 #define CONTENT_RENDERER_BROWSER_PLUGIN_BROWSER_PLUGIN_MANAGER_IMPL_H_
 
+#include <map>
+
 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
 #include "ui/gfx/size.h"
 
-struct BrowserPluginMsg_UpdateRect_Params;
-class WebCursor;
-
 namespace gfx {
 class Point;
 }
@@ -26,7 +25,8 @@
       RenderViewImpl* render_view,
       WebKit::WebFrame* frame,
       const WebKit::WebPluginParams& params) OVERRIDE;
-  virtual void AllocateInstanceID(BrowserPlugin* browser_plugin) OVERRIDE;
+  virtual void AllocateInstanceID(
+      const base::WeakPtr<BrowserPlugin>& browser_plugin) OVERRIDE;
 
   // IPC::Sender implementation.
   virtual bool Send(IPC::Message* msg) OVERRIDE;
@@ -46,7 +46,8 @@
                                  const gfx::Point& position);
 
   int request_id_counter_;
-  IDMap<BrowserPlugin> pending_allocate_guest_instance_id_requests_;
+  typedef std::map<int, const base::WeakPtr<BrowserPlugin> > InstanceIDMap;
+  InstanceIDMap pending_allocate_guest_instance_id_requests_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserPluginManagerImpl);
 };
diff --git a/content/renderer/browser_plugin/mock_browser_plugin.h b/content/renderer/browser_plugin/mock_browser_plugin.h
index ac12aa3..acd001b 100644
--- a/content/renderer/browser_plugin/mock_browser_plugin.h
+++ b/content/renderer/browser_plugin/mock_browser_plugin.h
@@ -18,6 +18,7 @@
   virtual ~MockBrowserPlugin();
 
   // Allow poking at a few private members.
+  using BrowserPlugin::OnAttachACK;
   using BrowserPlugin::guest_crashed_;
   using BrowserPlugin::pending_damage_buffer_;
   using BrowserPlugin::damage_buffer_sequence_id_;
diff --git a/content/renderer/browser_plugin/mock_browser_plugin_manager.cc b/content/renderer/browser_plugin/mock_browser_plugin_manager.cc
index c3b8fd8..9007f6e 100644
--- a/content/renderer/browser_plugin/mock_browser_plugin_manager.cc
+++ b/content/renderer/browser_plugin/mock_browser_plugin_manager.cc
@@ -28,13 +28,13 @@
 }
 
 void MockBrowserPluginManager::AllocateInstanceID(
-    BrowserPlugin* browser_plugin) {
+    const base::WeakPtr<BrowserPlugin>& browser_plugin) {
   int guest_instance_id = ++guest_instance_id_counter_;
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
       base::Bind(&MockBrowserPluginManager::AllocateInstanceIDACK,
                  this,
-                 base::Unretained(browser_plugin),
+                 browser_plugin.get(),
                  guest_instance_id));
 }
 
diff --git a/content/renderer/browser_plugin/mock_browser_plugin_manager.h b/content/renderer/browser_plugin/mock_browser_plugin_manager.h
index eda85f1..78ae0be 100644
--- a/content/renderer/browser_plugin/mock_browser_plugin_manager.h
+++ b/content/renderer/browser_plugin/mock_browser_plugin_manager.h
@@ -22,7 +22,8 @@
       RenderViewImpl* render_view,
       WebKit::WebFrame* frame,
       const WebKit::WebPluginParams& params) OVERRIDE;
-  virtual void AllocateInstanceID(BrowserPlugin* browser_plugin) OVERRIDE;
+  virtual void AllocateInstanceID(
+      const base::WeakPtr<BrowserPlugin>& browser_plugin) OVERRIDE;
 
   // Provides access to the messages that have been received by this thread.
   IPC::TestSink& sink() { return sink_; }
diff --git a/content/renderer/date_time_formatter.cc b/content/renderer/date_time_formatter.cc
index 7cdc4bd..a0ce77b 100644
--- a/content/renderer/date_time_formatter.cc
+++ b/content/renderer/date_time_formatter.cc
@@ -28,10 +28,61 @@
   patterns_[ui::TEXT_INPUT_TYPE_WEEK] = "Y-'W'ww";
 }
 
+// Returns true if icu_value parses as a valid for the specified date/time
+// pattern. The date/time pattern given is for icu::SimpleDateFormat.
+static bool TryPattern(const char* pattern,
+                       const icu::UnicodeString& icu_value) {
+  icu::UnicodeString time_pattern = pattern;
+  UErrorCode success = U_ZERO_ERROR;
+  icu::SimpleDateFormat formatter(time_pattern, success);
+  formatter.parse(icu_value, success);
+  return success == U_ZERO_ERROR;
+}
+
+// For a time value represented as a string find the longest time
+// pattern which matches it. A valid time can have hours and minutes
+// or hours, minutes and seconds or hour, minutes, seconds and upto 3
+// digits of fractional seconds. Specify step in milliseconds, it is 1000
+// times the value specified as "step" in the "<input type=time step=...>
+// HTML fragment. A value of 60000 or more indicates that seconds
+// are not expected and a value of 1000 or more indicates that fractional
+// seconds are not expected.
+static const char* FindLongestTimePatternWhichMatches(const std::string& value,
+                                                      double step) {
+  const char* pattern = "HH:mm";
+  if (step >= 60000)
+    return pattern;
+
+  icu::UnicodeString icu_value = icu::UnicodeString::fromUTF8(
+      icu::StringPiece(value.data(), value.size()));
+  const char* last_pattern = pattern;
+  pattern = "HH:mm:ss";
+  if (!TryPattern(pattern, icu_value))
+    return last_pattern;
+  if (step >= 1000)
+    return pattern;
+  last_pattern = pattern;
+  pattern = "HH:mm:ss.S";
+  if (!TryPattern(pattern, icu_value))
+    return last_pattern;
+  last_pattern = pattern;
+  pattern = "HH:mm:ss.SS";
+  if (!TryPattern(pattern, icu_value))
+    return last_pattern;
+  last_pattern = pattern;
+  pattern = "HH:mm:ss.SSS";
+  if (!TryPattern(pattern, icu_value))
+    return last_pattern;
+  return pattern;
+}
+
 DateTimeFormatter::DateTimeFormatter(
     const WebKit::WebDateTimeChooserParams& source)
-  : formatted_string_(source.currentValue.utf8()) {
+    : formatted_string_(source.currentValue.utf8()) {
   CreatePatternMap();
+  if (source.type == WebKit::WebDateTimeInputTypeTime)
+    time_pattern_ =
+        FindLongestTimePatternWhichMatches(formatted_string_, source.step);
   ExtractType(source);
   if (!ParseValues()) {
     type_ = ui::TEXT_INPUT_TYPE_NONE;
@@ -40,22 +91,41 @@
   }
 }
 
-DateTimeFormatter::DateTimeFormatter(
-    ui::TextInputType type,
-    int year, int month, int day, int hour, int minute, int second,
-    int week_year, int week)
-  : type_(type),
-    year_(year),
-    month_(month),
-    day_(day),
-    hour_(hour),
-    minute_(minute),
-    second_(second),
-    week_year_(week_year),
-    week_(week) {
+DateTimeFormatter::DateTimeFormatter(ui::TextInputType type,
+                                     int year,
+                                     int month,
+                                     int day,
+                                     int hour,
+                                     int minute,
+                                     int second,
+                                     int milli,
+                                     int week_year,
+                                     int week)
+    : type_(type),
+      year_(year),
+      month_(month),
+      day_(day),
+      hour_(hour),
+      minute_(minute),
+      second_(second),
+      milli_(milli),
+      week_year_(week_year),
+      week_(week) {
   CreatePatternMap();
-  pattern_ = type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX ?
-      &patterns_[type_] : &patterns_[ui::TEXT_INPUT_TYPE_NONE];
+  if (type_ == ui::TEXT_INPUT_TYPE_TIME && (second != 0 || milli != 0)) {
+    if (milli == 0)
+      time_pattern_ = "HH:mm:ss";
+    else if (milli % 100 == 0)
+      time_pattern_ = "HH:mm:ss.S";
+    else if (milli % 10 == 0)
+      time_pattern_ = "HH:mm:ss.SS";
+    else
+      time_pattern_ = "HH:mm:ss.SSS";
+    pattern_ = &time_pattern_;
+  } else {
+    pattern_ = type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX ?
+        &patterns_[type_] : &patterns_[ui::TEXT_INPUT_TYPE_NONE];
+  }
 
   formatted_string_ = FormatString();
 }
@@ -87,9 +157,9 @@
   return second_;
 }
 
-int DateTimeFormatter::GetWeekYear() const {
-  return week_year_;
-}
+int DateTimeFormatter::GetMilli() const { return milli_; }
+
+int DateTimeFormatter::GetWeekYear() const { return week_year_; }
 
 int DateTimeFormatter::GetWeek() const {
   return week_;
@@ -105,9 +175,8 @@
 
 const std::string DateTimeFormatter::FormatString() const {
   UErrorCode success = U_ZERO_ERROR;
-  if (year_ == 0 && month_ == 0 && day_ == 0 &&
-      hour_ == 0 && minute_ == 0 && second_ == 0 &&
-      week_year_ == 0 && week_ == 0) {
+  if (year_ == 0 && month_ == 0 && day_ == 0 && hour_ == 0 && minute_ == 0 &&
+      second_ == 0 && milli_ == 0 && week_year_ == 0 && week_ == 0) {
     return std::string();
   }
 
@@ -129,6 +198,7 @@
       calendar.set(UCAL_HOUR_OF_DAY, hour_);
       calendar.set(UCAL_MINUTE, minute_);
       calendar.set(UCAL_SECOND, second_);
+      calendar.set(UCAL_MILLISECOND, milli_);
     }
     icu::SimpleDateFormat formatter(*pattern_, success);
     icu::UnicodeString formatted_time;
@@ -194,7 +264,8 @@
   icu::UnicodeString icu_value = icu::UnicodeString::fromUTF8(
       icu::StringPiece(formatted_string_.data(), formatted_string_.size()));
   if (type_ > 0 && type_ <= ui::TEXT_INPUT_TYPE_MAX) {
-    const icu::UnicodeString pattern = patterns_[type_];
+    const icu::UnicodeString pattern =
+        type_ == ui::TEXT_INPUT_TYPE_TIME ? time_pattern_ : patterns_[type_];
     icu::SimpleDateFormat formatter(pattern, success);
     formatter.parse(icu_value, success);
     if (success <= U_ZERO_ERROR) {
@@ -205,6 +276,7 @@
       hour_ = ExtractValue(cal, UCAL_HOUR_OF_DAY);  // 24h format
       minute_ = ExtractValue(cal, UCAL_MINUTE);
       second_ = ExtractValue(cal, UCAL_SECOND);
+      milli_ = ExtractValue(cal, UCAL_MILLISECOND);
       week_year_ = ExtractValue(cal, UCAL_YEAR_WOY);
       week_ = ExtractValue(cal, UCAL_WEEK_OF_YEAR);
     }
@@ -220,6 +292,7 @@
   hour_ = 0;
   minute_ = 0;
   second_ = 0;
+  milli_ = 0;
   week_year_ = 0;
   week_ = 0;
 }
diff --git a/content/renderer/date_time_formatter.h b/content/renderer/date_time_formatter.h
index ad4c020..b2b7341 100644
--- a/content/renderer/date_time_formatter.h
+++ b/content/renderer/date_time_formatter.h
@@ -20,15 +20,21 @@
 namespace content {
 
 // Converts between a text string representing a date/time and
-// a set of year/month/day/hour/minute/second and vice versa.
+// a set of year/month/day/hour/minute/second/milli and vice versa.
 // It is timezone agnostic.
 class CONTENT_EXPORT DateTimeFormatter {
  public:
   explicit DateTimeFormatter(const WebKit::WebDateTimeChooserParams& source);
-  DateTimeFormatter(
-      ui::TextInputType type,
-      int year, int month, int day, int hour, int minute, int second,
-      int week_year, int week);
+  DateTimeFormatter(ui::TextInputType type,
+                    int year,
+                    int month,
+                    int day,
+                    int hour,
+                    int minute,
+                    int second,
+                    int milli,
+                    int week_year,
+                    int week);
   ~DateTimeFormatter();
 
   int GetYear() const;
@@ -37,6 +43,7 @@
   int GetHour() const;
   int GetMinute() const;
   int GetSecond() const;
+  int GetMilli() const;
   int GetWeekYear() const;
   int GetWeek() const;
   ui::TextInputType GetType() const;
@@ -53,12 +60,14 @@
 
   ui::TextInputType type_;
   icu::UnicodeString patterns_[ui::TEXT_INPUT_TYPE_MAX + 1];
+  icu::UnicodeString time_pattern_;
   int year_;
   int month_;
   int day_;
   int hour_;
   int minute_;
   int second_;
+  int milli_;
   int week_year_;
   int week_;
   const icu::UnicodeString* pattern_;
diff --git a/content/renderer/date_time_formatter_unittest.cc b/content/renderer/date_time_formatter_unittest.cc
index 5b61b71..0d8b07f 100644
--- a/content/renderer/date_time_formatter_unittest.cc
+++ b/content/renderer/date_time_formatter_unittest.cc
@@ -73,6 +73,42 @@
   EXPECT_EQ(2013, sut4.GetWeekYear());
   EXPECT_EQ(15, sut4.GetWeek());
   EXPECT_EQ(ui::TEXT_INPUT_TYPE_WEEK, sut4.GetType());
+
+  params.currentValue = "12:15";
+  params.type = WebKit::WebDateTimeInputTypeTime;
+  DateTimeFormatter sut5(params);
+  EXPECT_EQ(12, sut5.GetHour());
+  EXPECT_EQ(15, sut5.GetMinute());
+  EXPECT_EQ(0, sut5.GetSecond());
+  EXPECT_EQ(0, sut5.GetMilli());
+  EXPECT_EQ(ui::TEXT_INPUT_TYPE_TIME, sut5.GetType());
+
+  params.currentValue = "12:15:02";
+  params.type = WebKit::WebDateTimeInputTypeTime;
+  DateTimeFormatter sut6(params);
+  EXPECT_EQ(12, sut6.GetHour());
+  EXPECT_EQ(15, sut6.GetMinute());
+  EXPECT_EQ(02, sut6.GetSecond());
+  EXPECT_EQ(0, sut6.GetMilli());
+  EXPECT_EQ(ui::TEXT_INPUT_TYPE_TIME, sut6.GetType());
+
+  params.currentValue = "12:15:02.1";
+  params.type = WebKit::WebDateTimeInputTypeTime;
+  DateTimeFormatter sut7(params);
+  EXPECT_EQ(12, sut7.GetHour());
+  EXPECT_EQ(15, sut7.GetMinute());
+  EXPECT_EQ(02, sut7.GetSecond());
+  EXPECT_EQ(100, sut7.GetMilli());
+  EXPECT_EQ(ui::TEXT_INPUT_TYPE_TIME, sut7.GetType());
+
+  params.currentValue = "12:15:02.123";
+  params.type = WebKit::WebDateTimeInputTypeTime;
+  DateTimeFormatter sut8(params);
+  EXPECT_EQ(12, sut8.GetHour());
+  EXPECT_EQ(15, sut8.GetMinute());
+  EXPECT_EQ(02, sut8.GetSecond());
+  EXPECT_EQ(123, sut8.GetMilli());
+  EXPECT_EQ(ui::TEXT_INPUT_TYPE_TIME, sut8.GetType());
 }
 
 
@@ -130,42 +166,60 @@
 
 
 TEST(RendererDateTimePickerTest, TestParserValidDateInputs) {
-  DateTimeFormatter sut(ui::TEXT_INPUT_TYPE_MONTH, 2012, 11, 1, 0, 0, 0, 0, 0);
+  DateTimeFormatter sut(
+      ui::TEXT_INPUT_TYPE_MONTH, 2012, 11, 1, 0, 0, 0, 0, 0, 0);
   EXPECT_EQ("2012-12", sut.GetFormattedValue());
 
-
-  DateTimeFormatter sut2(ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL,
-                         2013, 3, 23, 15, 47, 0, 0, 0);
+  DateTimeFormatter sut2(
+      ui::TEXT_INPUT_TYPE_DATE_TIME_LOCAL, 2013, 3, 23, 15, 47, 0, 0, 0, 0);
   EXPECT_EQ("2013-04-23T15:47", sut2.GetFormattedValue());
 
-  DateTimeFormatter sut3(ui::TEXT_INPUT_TYPE_WEEK, 0, 0, 0, 0, 0, 0, 2012, 2);
+  DateTimeFormatter sut3(
+      ui::TEXT_INPUT_TYPE_WEEK, 0, 0, 0, 0, 0, 0, 0, 2012, 2);
   EXPECT_EQ("2012-W02", sut3.GetFormattedValue());
 }
 
+TEST(RendererDateTimePickerTest, TestParserValidTimeInputs) {
+  DateTimeFormatter sut(
+      ui::TEXT_INPUT_TYPE_TIME, 0, 0, 0, 12, 15, 0, 0, 0, 0);
+  EXPECT_EQ("12:15", sut.GetFormattedValue());
+
+  DateTimeFormatter sut2(
+      ui::TEXT_INPUT_TYPE_TIME, 0, 0, 0, 12, 15, 02, 0, 0, 0);
+  EXPECT_EQ("12:15:02", sut2.GetFormattedValue());
+
+  DateTimeFormatter sut3(
+      ui::TEXT_INPUT_TYPE_TIME, 0, 0, 0, 12, 15, 02, 123, 0, 0);
+  EXPECT_EQ("12:15:02.123", sut3.GetFormattedValue());
+}
+
 TEST(RendererDateTimePickerTest, TestParserInvalidDateInputs) {
-  DateTimeFormatter sut(ui::TEXT_INPUT_TYPE_WEEK, 0, 0, 0, 0, 0, 0, 0, 0);
+  DateTimeFormatter sut(ui::TEXT_INPUT_TYPE_WEEK, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   EXPECT_EQ("", sut.GetFormattedValue());
 
-  DateTimeFormatter sut2(ui::TEXT_INPUT_TYPE_NONE, 2013, 3, 23, 0, 0, 0, 0, 0);
+  DateTimeFormatter sut2(
+      ui::TEXT_INPUT_TYPE_NONE, 2013, 3, 23, 0, 0, 0, 0, 0, 0);
   EXPECT_EQ("", sut2.GetFormattedValue());
 
-  DateTimeFormatter sut3(ui::TEXT_INPUT_TYPE_NONE, 2013, 14, 32, 0, 0, 0, 0, 0);
+  DateTimeFormatter sut3(
+      ui::TEXT_INPUT_TYPE_NONE, 2013, 14, 32, 0, 0, 0, 0, 0, 0);
   EXPECT_EQ("", sut3.GetFormattedValue());
 
-  DateTimeFormatter sut4(ui::TEXT_INPUT_TYPE_DATE, 0, 0, 0, 0, 0, 0, 0, 0);
+  DateTimeFormatter sut4(ui::TEXT_INPUT_TYPE_DATE, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   EXPECT_EQ("", sut4.GetFormattedValue());
 
-  DateTimeFormatter sut5(ui::TEXT_INPUT_TYPE_TIME, 0, 0, 0, 0, 0, 0, 0, 0);
+  DateTimeFormatter sut5(ui::TEXT_INPUT_TYPE_TIME, 0, 0, 0, 0, 0, 0, 0, 0, 0);
   EXPECT_EQ("", sut5.GetFormattedValue());
 
-  DateTimeFormatter sut6(ui::TEXT_INPUT_TYPE_PASSWORD, 23, 0, 0, 0, 5, 0, 0, 0);
+  DateTimeFormatter sut6(
+      ui::TEXT_INPUT_TYPE_PASSWORD, 23, 0, 0, 0, 5, 0, 0, 0, 0);
   EXPECT_EQ("", sut6.GetFormattedValue());
 
-  DateTimeFormatter sut7(ui::TEXT_INPUT_TYPE_MAX, 23, 0, 0, 0, 5, 0, 0, 0);
+  DateTimeFormatter sut7(ui::TEXT_INPUT_TYPE_MAX, 23, 0, 0, 0, 5, 0, 0, 0, 0);
   EXPECT_EQ("", sut7.GetFormattedValue());
 
   DateTimeFormatter sut8(
-      static_cast<ui::TextInputType>(10000), 23, 0, 0, 0, 5, 0, 0, 0);
+      static_cast<ui::TextInputType>(10000), 23, 0, 0, 0, 5, 0, 0, 0, 0);
   EXPECT_EQ("", sut8.GetFormattedValue());
 }
 } // namespace content
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index caa4c43..bcc4fc6 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -15,11 +15,16 @@
 #include "content/public/renderer/render_view_observer.h"
 #include "content/public/test/test_utils.h"
 #include "content/renderer/savable_resources.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_request_context.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebElement.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
@@ -29,11 +34,6 @@
 #include "third_party/WebKit/public/web/WebPageSerializer.h"
 #include "third_party/WebKit/public/web/WebPageSerializerClient.h"
 #include "third_party/WebKit/public/web/WebView.h"
-#include "third_party/WebKit/public/platform/WebCString.h"
-#include "third_party/WebKit/public/platform/WebData.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
 
 using WebKit::WebCString;
 using WebKit::WebData;
diff --git a/content/renderer/gpu/compositor_output_surface.cc b/content/renderer/gpu/compositor_output_surface.cc
index 4d72863..e44f832 100644
--- a/content/renderer/gpu/compositor_output_surface.cc
+++ b/content/renderer/gpu/compositor_output_surface.cc
@@ -10,15 +10,13 @@
 #include "cc/output/compositor_frame_ack.h"
 #include "cc/output/output_surface_client.h"
 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/content_switches.h"
 #include "content/renderer/render_thread_impl.h"
 #include "ipc/ipc_forwarding_message_filter.h"
 #include "ipc/ipc_sync_channel.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-
-using WebKit::WebGraphicsContext3D;
 
 namespace {
 // There are several compositor surfaces in a process, but they share the same
@@ -50,11 +48,10 @@
 CompositorOutputSurface::CompositorOutputSurface(
     int32 routing_id,
     uint32 output_surface_id,
-    WebGraphicsContext3DCommandBufferImpl* context3D,
-    cc::SoftwareOutputDevice* software_device,
+    const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+    scoped_ptr<cc::SoftwareOutputDevice> software_device,
     bool use_swap_compositor_frame_message)
-    : OutputSurface(scoped_ptr<WebKit::WebGraphicsContext3D>(context3D),
-                    make_scoped_ptr(software_device)),
+    : OutputSurface(context_provider, software_device.Pass()),
       output_surface_id_(output_surface_id),
       use_swap_compositor_frame_message_(use_swap_compositor_frame_message),
       output_surface_filter_(
@@ -72,6 +69,8 @@
   DetachFromThread();
   message_sender_ = RenderThreadImpl::current()->sync_message_filter();
   DCHECK(message_sender_.get());
+  if (software_device)
+    capabilities_.max_frames_pending = 1;
 }
 
 CompositorOutputSurface::~CompositorOutputSurface() {
@@ -101,6 +100,18 @@
   return true;
 }
 
+void CompositorOutputSurface::EnsureBackbuffer() {
+  if (software_device())
+    software_device()->EnsureBackbuffer();
+  OutputSurface::EnsureBackbuffer();
+}
+
+void CompositorOutputSurface::DiscardBackbuffer() {
+  if (software_device())
+    software_device()->DiscardBackbuffer();
+  OutputSurface::DiscardBackbuffer();
+}
+
 void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
   if (use_swap_compositor_frame_message_) {
     Send(new ViewHostMsg_SwapCompositorFrame(routing_id_,
@@ -111,12 +122,13 @@
   }
 
   if (frame->gl_frame_data) {
-    WebGraphicsContext3DCommandBufferImpl* command_buffer =
-        static_cast<WebGraphicsContext3DCommandBufferImpl*>(context3d());
+    WebGraphicsContext3DCommandBufferImpl* command_buffer_context =
+        static_cast<WebGraphicsContext3DCommandBufferImpl*>(
+            context_provider_->Context3d());
     CommandBufferProxyImpl* command_buffer_proxy =
-        command_buffer->GetCommandBufferProxy();
+        command_buffer_context->GetCommandBufferProxy();
     DCHECK(command_buffer_proxy);
-    context3d()->shallowFlushCHROMIUM();
+    context_provider_->Context3d()->shallowFlushCHROMIUM();
     command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
   }
 
diff --git a/content/renderer/gpu/compositor_output_surface.h b/content/renderer/gpu/compositor_output_surface.h
index ff59872..73a1ce4 100644
--- a/content/renderer/gpu/compositor_output_surface.h
+++ b/content/renderer/gpu/compositor_output_surface.h
@@ -31,8 +31,7 @@
 }
 
 namespace content {
-
-class WebGraphicsContext3DCommandBufferImpl;
+class ContextProviderCommandBuffer;
 
 // This class can be created only on the main thread, but then becomes pinned
 // to a fixed thread when bindToClient is called.
@@ -43,11 +42,12 @@
   static IPC::ForwardingMessageFilter* CreateFilter(
       base::TaskRunner* target_task_runner);
 
-  CompositorOutputSurface(int32 routing_id,
-                          uint32 output_surface_id,
-                          WebGraphicsContext3DCommandBufferImpl* context3d,
-                          cc::SoftwareOutputDevice* software,
-                          bool use_swap_compositor_frame_message);
+  CompositorOutputSurface(
+      int32 routing_id,
+      uint32 output_surface_id,
+      const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+      scoped_ptr<cc::SoftwareOutputDevice> software,
+      bool use_swap_compositor_frame_message);
   virtual ~CompositorOutputSurface();
 
   // cc::OutputSurface implementation.
@@ -56,6 +56,8 @@
 #if defined(OS_ANDROID)
   virtual void SetNeedsBeginFrame(bool enable) OVERRIDE;
 #endif
+  virtual void EnsureBackbuffer() OVERRIDE;
+  virtual void DiscardBackbuffer() OVERRIDE;
 
   // TODO(epenner): This seems out of place here and would be a better fit
   // int CompositorThread after it is fully refactored (http://crbug/170828)
diff --git a/content/renderer/gpu/compositor_software_output_device.cc b/content/renderer/gpu/compositor_software_output_device.cc
index 21fad4e..948e3e7 100644
--- a/content/renderer/gpu/compositor_software_output_device.cc
+++ b/content/renderer/gpu/compositor_software_output_device.cc
@@ -116,6 +116,21 @@
   viewport_size_ = viewport_size;
 }
 
+void CompositorSoftwareOutputDevice::DiscardBackbuffer() {
+  // Keep non-ACKed buffers in awaiting_ack_ until they get acknowledged.
+  for (size_t i = 0; i < buffers_.size(); ++i) {
+    if (!buffers_[i]->free()) {
+      awaiting_ack_.push_back(buffers_[i]);
+      buffers_[i] = NULL;
+    }
+  }
+  buffers_.clear();
+  current_index_ = -1;
+}
+
+void CompositorSoftwareOutputDevice::EnsureBackbuffer() {
+}
+
 SkCanvas* CompositorSoftwareOutputDevice::BeginPaint(gfx::Rect damage_rect) {
   DCHECK(CalledOnValidThread());
 
diff --git a/content/renderer/gpu/compositor_software_output_device.h b/content/renderer/gpu/compositor_software_output_device.h
index 49b90c2..e658dfb 100644
--- a/content/renderer/gpu/compositor_software_output_device.h
+++ b/content/renderer/gpu/compositor_software_output_device.h
@@ -30,6 +30,8 @@
 
   virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE;
   virtual void EndPaint(cc::SoftwareFrameData* frame_data) OVERRIDE;
+  virtual void EnsureBackbuffer() OVERRIDE;
+  virtual void DiscardBackbuffer() OVERRIDE;
 
   virtual void ReclaimSoftwareFrame(unsigned id) OVERRIDE;
 
diff --git a/content/renderer/gpu/delegated_compositor_output_surface.cc b/content/renderer/gpu/delegated_compositor_output_surface.cc
index 2e53923..02ad158 100644
--- a/content/renderer/gpu/delegated_compositor_output_surface.cc
+++ b/content/renderer/gpu/delegated_compositor_output_surface.cc
@@ -9,12 +9,12 @@
 DelegatedCompositorOutputSurface::DelegatedCompositorOutputSurface(
     int32 routing_id,
     uint32 output_surface_id,
-    WebGraphicsContext3DCommandBufferImpl* context3d,
-    cc::SoftwareOutputDevice* software)
+    const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+    scoped_ptr<cc::SoftwareOutputDevice> software)
     : CompositorOutputSurface(routing_id,
                               output_surface_id,
-                              context3d,
-                              software,
+                              context_provider,
+                              software.Pass(),
                               true) {
   capabilities_.delegated_rendering = true;
   capabilities_.max_frames_pending = 1;
diff --git a/content/renderer/gpu/delegated_compositor_output_surface.h b/content/renderer/gpu/delegated_compositor_output_surface.h
index c3a7dbb..1e02c3d 100644
--- a/content/renderer/gpu/delegated_compositor_output_surface.h
+++ b/content/renderer/gpu/delegated_compositor_output_surface.h
@@ -14,8 +14,8 @@
   DelegatedCompositorOutputSurface(
       int32 routing_id,
       uint32 output_surface_id,
-      WebGraphicsContext3DCommandBufferImpl* context3d,
-      cc::SoftwareOutputDevice* software);
+      const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+      scoped_ptr<cc::SoftwareOutputDevice> software);
   virtual ~DelegatedCompositorOutputSurface() {}
 };
 
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index a274d0d..8d2920a 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -11,17 +11,16 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string_number_conversions.h"
+#include "cc/layers/layer.h"
 #include "content/common/browser_rendering_stats.h"
 #include "content/common/gpu/gpu_rendering_stats.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/renderer/gpu/render_widget_compositor.h"
 #include "content/renderer/render_view_impl.h"
-#include "content/renderer/rendering_benchmark.h"
 #include "content/renderer/skia_benchmarking_extension.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebImageCache.h"
 #include "third_party/WebKit/public/web/WebView.h"
-#include "third_party/WebKit/public/web/WebViewBenchmarkSupport.h"
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkGraphics.h"
 #include "third_party/skia/include/core/SkPicture.h"
@@ -38,7 +37,6 @@
 using WebKit::WebRenderingStatsImpl;
 using WebKit::WebSize;
 using WebKit::WebView;
-using WebKit::WebViewBenchmarkSupport;
 
 const char kGpuBenchmarkingExtensionName[] = "v8/GpuBenchmarking";
 
@@ -60,9 +58,9 @@
 
 namespace {
 
-class SkPictureRecorder : public WebViewBenchmarkSupport::PaintClient {
+class SkPictureSerializer {
  public:
-  explicit SkPictureRecorder(const base::FilePath& dirpath)
+  explicit SkPictureSerializer(const base::FilePath& dirpath)
       : dirpath_(dirpath),
         layer_id_(0) {
     // Let skia register known effect subclasses. This basically enables
@@ -70,13 +68,19 @@
     content::SkiaBenchmarkingExtension::InitSkGraphics();
   }
 
-  virtual WebCanvas* willPaint(const WebSize& size) {
-    return picture_.beginRecording(size.width, size.height);
-  }
+  // Recursively serializes the layer tree.
+  // Each layer in the tree is serialized into a separate skp file
+  // in the given directory.
+  void Serialize(const cc::Layer* layer) {
+    const cc::LayerList& children = layer->children();
+    for (size_t i = 0; i < children.size(); ++i) {
+      Serialize(children[i].get());
+    }
 
-  virtual void didPaint(WebCanvas* canvas) {
-    DCHECK(canvas == picture_.getRecordingCanvas());
-    picture_.endRecording();
+    skia::RefPtr<SkPicture> picture = layer->GetPicture();
+    if (!picture)
+      return;
+
     // Serialize picture to file.
     // TODO(alokp): Note that for this to work Chrome needs to be launched with
     // --no-sandbox command-line flag. Get rid of this limitation.
@@ -86,13 +90,12 @@
     DCHECK(!filepath.empty());
     SkFILEWStream file(filepath.c_str());
     DCHECK(file.isValid());
-    picture_.serialize(&file, &EncodeBitmapToData);
+    picture->serialize(&file, &EncodeBitmapToData);
   }
 
  private:
   base::FilePath dirpath_;
   int layer_id_;
-  SkPicture picture_;
 };
 
 class RenderingStatsEnumerator : public cc::RenderingStats::Enumerator {
@@ -334,8 +337,16 @@
     if (!web_view)
       return;
 
-    WebViewBenchmarkSupport* benchmark_support = web_view->benchmarkSupport();
-    if (!benchmark_support)
+    RenderViewImpl* render_view_impl = RenderViewImpl::FromWebView(web_view);
+    if (!render_view_impl)
+      return;
+
+    RenderWidgetCompositor* compositor = render_view_impl->compositor();
+    if (!compositor)
+      return;
+
+    const cc::Layer* root_layer = compositor->GetRootLayer();
+    if (!root_layer)
       return;
 
     base::FilePath dirpath(
@@ -349,9 +360,8 @@
       return;
     }
 
-    SkPictureRecorder recorder(dirpath);
-    benchmark_support->paint(&recorder,
-                             WebViewBenchmarkSupport::PaintModeEverything);
+    SkPictureSerializer serializer(dirpath);
+    serializer.Serialize(root_layer);
   }
 
   static void OnSmoothScrollCompleted(
diff --git a/content/renderer/gpu/mailbox_output_surface.cc b/content/renderer/gpu/mailbox_output_surface.cc
index 6d38483..4c4b721 100644
--- a/content/renderer/gpu/mailbox_output_surface.cc
+++ b/content/renderer/gpu/mailbox_output_surface.cc
@@ -21,12 +21,12 @@
 MailboxOutputSurface::MailboxOutputSurface(
     int32 routing_id,
     uint32 output_surface_id,
-    WebGraphicsContext3DCommandBufferImpl* context3D,
-    cc::SoftwareOutputDevice* software_device)
+    const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+    scoped_ptr<cc::SoftwareOutputDevice> software_device)
     : CompositorOutputSurface(routing_id,
                               output_surface_id,
-                              context3D,
-                              software_device,
+                              context_provider,
+                              software_device.Pass(),
                               true),
       fbo_(0),
       is_backbuffer_discarded_(false) {
@@ -37,8 +37,10 @@
 MailboxOutputSurface::~MailboxOutputSurface() {
   DiscardBackbuffer();
   while (!pending_textures_.empty()) {
-    if (pending_textures_.front().texture_id)
-      context3d_->deleteTexture(pending_textures_.front().texture_id);
+    if (pending_textures_.front().texture_id) {
+      context_provider_->Context3d()->deleteTexture(
+          pending_textures_.front().texture_id);
+    }
     pending_textures_.pop_front();
   }
 }
@@ -46,6 +48,8 @@
 void MailboxOutputSurface::EnsureBackbuffer() {
   is_backbuffer_discarded_ = false;
 
+  WebKit::WebGraphicsContext3D* context3d = context_provider_->Context3d();
+
   if (!current_backing_.texture_id) {
     // Find a texture of matching size to recycle.
     while (!returned_textures_.empty()) {
@@ -53,33 +57,33 @@
       if (texture.size == surface_size_) {
         current_backing_ = texture;
         if (current_backing_.sync_point)
-          context3d_->waitSyncPoint(current_backing_.sync_point);
+          context3d->waitSyncPoint(current_backing_.sync_point);
         returned_textures_.pop();
         break;
       }
 
-      context3d_->deleteTexture(texture.texture_id);
+      context3d->deleteTexture(texture.texture_id);
       returned_textures_.pop();
     }
 
     if (!current_backing_.texture_id) {
-      current_backing_.texture_id = context3d_->createTexture();
+      current_backing_.texture_id = context3d->createTexture();
       current_backing_.size = surface_size_;
-      context3d_->bindTexture(GL_TEXTURE_2D, current_backing_.texture_id);
-      context3d_->texParameteri(
+      context3d->bindTexture(GL_TEXTURE_2D, current_backing_.texture_id);
+      context3d->texParameteri(
           GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-      context3d_->texParameteri(
+      context3d->texParameteri(
           GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-      context3d_->texParameteri(
+      context3d->texParameteri(
           GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-      context3d_->texParameteri(
+      context3d->texParameteri(
           GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-      context3d_->texImage2D(
+      context3d->texImage2D(
           GL_TEXTURE_2D, 0, GL_RGBA,
           surface_size_.width(), surface_size_.height(), 0,
           GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-      context3d_->genMailboxCHROMIUM(current_backing_.mailbox.name);
-      context3d_->produceTextureCHROMIUM(
+      context3d->genMailboxCHROMIUM(current_backing_.mailbox.name);
+      context3d->produceTextureCHROMIUM(
           GL_TEXTURE_2D, current_backing_.mailbox.name);
     }
   }
@@ -88,20 +92,22 @@
 void MailboxOutputSurface::DiscardBackbuffer() {
   is_backbuffer_discarded_ = true;
 
+  WebKit::WebGraphicsContext3D* context3d = context_provider_->Context3d();
+
   if (current_backing_.texture_id) {
-    context3d_->deleteTexture(current_backing_.texture_id);
+    context3d->deleteTexture(current_backing_.texture_id);
     current_backing_ = TransferableFrame();
   }
 
   while (!returned_textures_.empty()) {
     const TransferableFrame& frame = returned_textures_.front();
-    context3d_->deleteTexture(frame.texture_id);
+    context3d->deleteTexture(frame.texture_id);
     returned_textures_.pop();
   }
 
   if (fbo_) {
-    context3d_->bindFramebuffer(GL_FRAMEBUFFER, fbo_);
-    context3d_->deleteFramebuffer(fbo_);
+    context3d->bindFramebuffer(GL_FRAMEBUFFER, fbo_);
+    context3d->deleteFramebuffer(fbo_);
     fbo_ = 0;
   }
 }
@@ -120,10 +126,12 @@
   EnsureBackbuffer();
   DCHECK(current_backing_.texture_id);
 
+  WebKit::WebGraphicsContext3D* context3d = context_provider_->Context3d();
+
   if (!fbo_)
-    fbo_ = context3d_->createFramebuffer();
-  context3d_->bindFramebuffer(GL_FRAMEBUFFER, fbo_);
-  context3d_->framebufferTexture2D(
+    fbo_ = context3d->createFramebuffer();
+  context3d->bindFramebuffer(GL_FRAMEBUFFER, fbo_);
+  context3d->framebufferTexture2D(
       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
       current_backing_.texture_id, 0);
 }
@@ -156,7 +164,7 @@
     if (!is_backbuffer_discarded_) {
       returned_textures_.push(*it);
     } else {
-      context3d_->deleteTexture(it->texture_id);
+      context_provider_->Context3d()->deleteTexture(it->texture_id);
     }
 
     pending_textures_.erase(it);
@@ -167,7 +175,7 @@
     // the oldest texture we sent.
     uint32 texture_id = pending_textures_.front().texture_id;
     if (texture_id)
-      context3d_->deleteTexture(texture_id);
+      context_provider_->Context3d()->deleteTexture(texture_id);
     pending_textures_.pop_front();
   }
   CompositorOutputSurface::OnSwapAck(output_surface_id, ack);
@@ -178,11 +186,13 @@
   DCHECK(!surface_size_.IsEmpty());
   DCHECK(surface_size_ == current_backing_.size);
   DCHECK(frame->gl_frame_data->size == current_backing_.size);
-  DCHECK(!current_backing_.mailbox.IsZero() || context3d_->isContextLost());
+  DCHECK(!current_backing_.mailbox.IsZero() ||
+         context_provider_->Context3d()->isContextLost());
 
   frame->gl_frame_data->mailbox = current_backing_.mailbox;
-  context3d_->flush();
-  frame->gl_frame_data->sync_point = context3d_->insertSyncPoint();
+  context_provider_->Context3d()->flush();
+  frame->gl_frame_data->sync_point =
+      context_provider_->Context3d()->insertSyncPoint();
   CompositorOutputSurface::SwapBuffers(frame);
 
   pending_textures_.push_back(current_backing_);
diff --git a/content/renderer/gpu/mailbox_output_surface.h b/content/renderer/gpu/mailbox_output_surface.h
index 4151430..c2455b9 100644
--- a/content/renderer/gpu/mailbox_output_surface.h
+++ b/content/renderer/gpu/mailbox_output_surface.h
@@ -23,10 +23,11 @@
 // to a fixed thread when bindToClient is called.
 class MailboxOutputSurface : public CompositorOutputSurface {
  public:
-  MailboxOutputSurface(int32 routing_id,
-                       uint32 output_surface_id,
-                       WebGraphicsContext3DCommandBufferImpl* context3d,
-                       cc::SoftwareOutputDevice* software);
+  MailboxOutputSurface(
+      int32 routing_id,
+      uint32 output_surface_id,
+      const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+      scoped_ptr<cc::SoftwareOutputDevice> software_device);
   virtual ~MailboxOutputSurface();
 
   // cc::OutputSurface implementation.
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index c3becc8..e7a7e3e 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -372,6 +372,10 @@
   layer_tree_host_->NotifyInputThrottledUntilCommit();
 }
 
+const cc::Layer* RenderWidgetCompositor::GetRootLayer() const {
+  return layer_tree_host_->root_layer();
+}
+
 bool RenderWidgetCompositor::initialize(cc::LayerTreeSettings settings) {
   scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy =
       RenderThreadImpl::current()->compositor_message_loop_proxy();
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index a1cc4ab..689d2d7 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -20,6 +20,7 @@
 
 namespace cc {
 class InputHandler;
+class Layer;
 class LayerTreeHost;
 }
 
@@ -51,6 +52,7 @@
   void SetLatencyInfo(const ui::LatencyInfo& latency_info);
   int GetLayerTreeId() const;
   void NotifyInputThrottledUntilCommit();
+  const cc::Layer* GetRootLayer() const;
 
   // WebLayerTreeView implementation.
   virtual void setSurfaceReady();
diff --git a/content/renderer/media/android/audio_decoder_android.cc b/content/renderer/media/android/audio_decoder_android.cc
index 1fbdf5f..4194431 100644
--- a/content/renderer/media/android/audio_decoder_android.cc
+++ b/content/renderer/media/android/audio_decoder_android.cc
@@ -101,6 +101,296 @@
   return sample * (sample < 0 ? kMinScale : kMaxScale);
 }
 
+// A basic WAVE file decoder.  See
+// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ for a
+// basic guide to the WAVE file format.
+class WAVEDecoder {
+ public:
+  WAVEDecoder(const uint8* data, size_t data_size);
+  ~WAVEDecoder();
+
+  // Try to decode the data as a WAVE file.  If the data is a supported
+  // WAVE file, |destination_bus| is filled with the decoded data and
+  // DecodeWAVEFile returns true.  Otherwise, DecodeWAVEFile returns
+  // false.
+  bool DecodeWAVEFile(WebKit::WebAudioBus* destination_bus);
+
+ private:
+  // Minimum number of bytes in a WAVE file to hold all of the data we
+  // need to interpret it as a WAVE file.
+  static const unsigned kMinimumWAVLength = 44;
+
+  // Number of bytes in the chunk ID field.
+  static const unsigned kChunkIDLength = 4;
+
+  // Number of bytes in the chunk size field.
+  static const unsigned kChunkSizeLength = 4;
+
+  // Number of bytes in the format field of the "RIFF" chunk.
+  static const unsigned kFormatFieldLength = 4;
+
+  // Number of bytes in a valid "fmt" chunk.
+  static const unsigned kFMTChunkLength = 16;
+
+  // Supported audio format in a WAVE file.
+  // TODO(rtoy): Consider supporting other formats here, if necessary.
+  static const int16_t kAudioFormatPCM = 1;
+
+  // Maximum number (inclusive) of bytes per sample supported by this
+  // decoder.
+  static const unsigned kMaximumBytesPerSample = 3;
+
+  // Read an unsigned integer of |length| bytes from |buffer|.  The
+  // integer is interpreted as being in little-endian order.
+  uint32_t ReadUnsignedInteger(const uint8_t* buffer, size_t length);
+
+  // Read a PCM sample from the WAVE data at |pcm_data|.
+  int16_t ReadPCMSample(const uint8_t* pcm_data);
+
+  // Read a WAVE chunk header including the chunk ID and chunk size.
+  // Returns false if the header could not be read.
+  bool ReadChunkHeader();
+
+  // Read and parse the "fmt" chunk.  Returns false if the fmt chunk
+  // could not be read or contained unsupported formats.
+  bool ReadFMTChunk();
+
+  // Read data chunk and save it to |destination_bus|.  Returns false
+  // if the data chunk could not be read correctly.
+  bool CopyDataChunkToBus(WebKit::WebAudioBus* destination_bus);
+
+  // The WAVE chunk ID that identifies the chunk.
+  uint8_t chunk_id_[kChunkIDLength];
+
+  // The number of bytes in the data portion of the chunk.
+  size_t chunk_size_;
+
+  // The current position within the WAVE file.
+  const uint8_t* buffer_;
+
+  // Points one byte past the end of the in-memory WAVE file.  Used for
+  // detecting if we've reached the end of the file.
+  const uint8_t* buffer_end_;
+
+  size_t bytes_per_sample_;
+
+  uint16_t number_of_channels_;
+
+  // Sample rate of the WAVE data, in Hz.
+  uint32_t sample_rate_;
+
+  DISALLOW_COPY_AND_ASSIGN(WAVEDecoder);
+};
+
+WAVEDecoder::WAVEDecoder(const uint8_t* encoded_data, size_t data_size)
+    : buffer_(encoded_data),
+      buffer_end_(encoded_data + 1),
+      bytes_per_sample_(0),
+      number_of_channels_(0),
+      sample_rate_(0) {
+  if (buffer_ + data_size > buffer_)
+    buffer_end_ = buffer_ + data_size;
+}
+
+WAVEDecoder::~WAVEDecoder() {}
+
+uint32_t WAVEDecoder::ReadUnsignedInteger(const uint8_t* buffer,
+                                          size_t length) {
+  unsigned value = 0;
+
+  if (length == 0 || length > sizeof(value)) {
+    DCHECK(false) << "ReadUnsignedInteger: Invalid length: " << length;
+    return 0;
+  }
+
+  // All integer fields in a WAVE file are little-endian.
+  for (size_t k = length; k > 0; --k)
+    value = (value << 8) + buffer[k - 1];
+
+  return value;
+}
+
+int16_t WAVEDecoder::ReadPCMSample(const uint8_t* pcm_data) {
+  uint32_t unsigned_sample = ReadUnsignedInteger(pcm_data, bytes_per_sample_);
+  int16_t sample;
+
+  // Convert the unsigned data into a 16-bit PCM sample.
+  switch (bytes_per_sample_) {
+    case 1:
+      sample = (unsigned_sample - 128) << 8;
+      break;
+    case 2:
+      sample = static_cast<int16_t>(unsigned_sample);
+      break;
+    case 3:
+      // Android currently converts 24-bit WAVE data into 16-bit
+      // samples by taking the high-order 16 bits without rounding.
+      // We do the same here for consistency.
+      sample = static_cast<int16_t>(unsigned_sample >> 8);
+      break;
+    default:
+      sample = 0;
+      break;
+  }
+  return sample;
+}
+
+bool WAVEDecoder::ReadChunkHeader() {
+  if (buffer_ + kChunkIDLength + kChunkSizeLength >= buffer_end_)
+    return false;
+
+  memcpy(chunk_id_, buffer_, kChunkIDLength);
+
+  chunk_size_ = ReadUnsignedInteger(buffer_ + kChunkIDLength, kChunkSizeLength);
+
+  // Adjust for padding
+  if (chunk_size_ % 2)
+    ++chunk_size_;
+
+  return true;
+}
+
+bool WAVEDecoder::ReadFMTChunk() {
+  // The fmt chunk has basic info about the format of the audio
+  // data.  Only a basic PCM format is supported.
+  if (chunk_size_ < kFMTChunkLength) {
+    DVLOG(1) << "FMT chunk too short: " << chunk_size_;
+    return 0;
+  }
+
+  uint16_t audio_format = ReadUnsignedInteger(buffer_, 2);
+
+  if (audio_format != kAudioFormatPCM) {
+    DVLOG(1) << "Audio format not supported: " << audio_format;
+    return false;
+  }
+
+  number_of_channels_ = ReadUnsignedInteger(buffer_ + 2, 2);
+  sample_rate_ = ReadUnsignedInteger(buffer_ + 4, 4);
+  unsigned bits_per_sample = ReadUnsignedInteger(buffer_ + 14, 2);
+
+  // Sanity checks.
+
+  if (!number_of_channels_ ||
+      number_of_channels_ > media::limits::kMaxChannels) {
+    DVLOG(1) << "Unsupported number of channels: " << number_of_channels_;
+    return false;
+  }
+
+  if (sample_rate_ < media::limits::kMinSampleRate ||
+      sample_rate_ > media::limits::kMaxSampleRate) {
+    DVLOG(1) << "Unsupported sample rate: " << sample_rate_;
+    return false;
+  }
+
+  // We only support 8, 16, and 24 bits per sample.
+  if (bits_per_sample == 8 || bits_per_sample == 16 || bits_per_sample == 24) {
+    bytes_per_sample_ = bits_per_sample / 8;
+    return true;
+  }
+
+  DVLOG(1) << "Unsupported bits per sample: " << bits_per_sample;
+  return false;
+}
+
+bool WAVEDecoder::CopyDataChunkToBus(WebKit::WebAudioBus* destination_bus) {
+  // The data chunk contains the audio data itself.
+  if (!bytes_per_sample_ || bytes_per_sample_ > kMaximumBytesPerSample) {
+    DVLOG(1) << "WARNING: data chunk without preceeding fmt chunk,"
+             << " or invalid bytes per sample.";
+    return false;
+  }
+
+  VLOG(0) << "Decoding WAVE file: " << number_of_channels_ << " channels, "
+          << sample_rate_ << " kHz, "
+          << chunk_size_ / bytes_per_sample_ / number_of_channels_
+          << " frames, " << 8 * bytes_per_sample_ << " bits/sample";
+
+  // Create the destination bus of the appropriate size and then decode
+  // the data into the bus.
+  size_t number_of_frames =
+      chunk_size_ / bytes_per_sample_ / number_of_channels_;
+
+  destination_bus->initialize(
+      number_of_channels_, number_of_frames, sample_rate_);
+
+  for (size_t m = 0; m < number_of_frames; ++m) {
+    for (uint16_t k = 0; k < number_of_channels_; ++k) {
+      int16_t sample = ReadPCMSample(buffer_);
+
+      buffer_ += bytes_per_sample_;
+      destination_bus->channelData(k)[m] = ConvertSampleToFloat(sample);
+    }
+  }
+
+  return true;
+}
+
+bool WAVEDecoder::DecodeWAVEFile(WebKit::WebAudioBus* destination_bus) {
+  // Parse and decode WAVE file. If we can't parse it, return false.
+
+  if (buffer_ + kMinimumWAVLength > buffer_end_) {
+    DVLOG(1) << "Buffer too small to contain full WAVE header: ";
+    return false;
+  }
+
+  // Do we have a RIFF file?
+  ReadChunkHeader();
+  if (memcmp(chunk_id_, "RIFF", kChunkIDLength) != 0) {
+    DVLOG(1) << "RIFF missing";
+    return false;
+  }
+  buffer_ += kChunkIDLength + kChunkSizeLength;
+
+  // Check the format field of the RIFF chunk
+  memcpy(chunk_id_, buffer_, kFormatFieldLength);
+  if (memcmp(chunk_id_, "WAVE", kFormatFieldLength) != 0) {
+    DVLOG(1) << "Invalid WAVE file:  missing WAVE header";
+    return false;
+  }
+  // Advance past the format field
+  buffer_ += kFormatFieldLength;
+
+  // We have a WAVE file.  Start parsing the chunks.
+
+  while (buffer_ < buffer_end_) {
+    if (!ReadChunkHeader()) {
+      DVLOG(1) << "Couldn't read chunk header";
+      return false;
+    }
+
+    // Consume the chunk ID and chunk size
+    buffer_ += kChunkIDLength + kChunkSizeLength;
+
+    // Make sure we can read all chunk_size bytes.
+    if (buffer_ + chunk_size_ > buffer_end_) {
+      DVLOG(1) << "Insufficient bytes to read chunk of size " << chunk_size_;
+      return false;
+    }
+
+    if (memcmp(chunk_id_, "fmt ", kChunkIDLength) == 0) {
+      if (!ReadFMTChunk())
+        return false;
+    } else if (memcmp(chunk_id_, "data", kChunkIDLength) == 0) {
+      // Return after reading the data chunk, whether we succeeded or
+      // not.
+      return CopyDataChunkToBus(destination_bus);
+    } else {
+      // Ignore these chunks that we don't know about.
+      VLOG(0) << "Ignoring WAVE chunk `" << chunk_id_ << "' size "
+              << chunk_size_;
+    }
+
+    // Advance to next chunk.
+    buffer_ += chunk_size_;
+  }
+
+  // If we get here, that means we didn't find a data chunk, so we
+  // couldn't handle this WAVE file.
+
+  return false;
+}
+
 // The number of frames is known so preallocate the destination
 // bus and copy the pcm data to the destination bus as it's being
 // received.
@@ -178,6 +468,14 @@
   }
 }
 
+static bool TryWAVEFileDecoder(WebKit::WebAudioBus* destination_bus,
+                               const uint8_t* encoded_data,
+                               size_t data_size) {
+  WAVEDecoder decoder(encoded_data, data_size);
+
+  return decoder.DecodeWAVEFile(destination_bus);
+}
+
 // To decode audio data, we want to use the Android MediaCodec class.
 // But this can't run in a sandboxed process so we need initiate the
 // request to MediaCodec in the browser.  To do this, we create a
@@ -188,6 +486,13 @@
 bool DecodeAudioFileData(WebKit::WebAudioBus* destination_bus, const char* data,
                          size_t data_size, double sample_rate,
                          scoped_refptr<ThreadSafeSender> sender) {
+  // Try to decode the data as a WAVE file first.  If it can't be
+  // decoded, use MediaCodec.  See crbug.com/259048.
+  if (TryWAVEFileDecoder(
+          destination_bus, reinterpret_cast<const uint8_t*>(data), data_size)) {
+    return true;
+  }
+
   AudioDecoderIO audio_decoder(data, data_size);
 
   if (!audio_decoder.IsValid())
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 1193766..5600285 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -8,7 +8,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "content/renderer/media/android/webmediaplayer_proxy_android.h"
 #include "content/renderer/media/webmediaplayer_util.h"
-#include "content/renderer/media/webmediasourceclient_impl.h"
+#include "content/renderer/media/webmediasource_impl.h"
 #include "media/base/android/demuxer_stream_player_params.h"
 #include "media/base/bind_to_loop.h"
 #include "media/base/demuxer_stream.h"
@@ -37,35 +37,44 @@
 
 namespace content {
 
-// TODO(xhwang): BIND_TO_RENDER_LOOP* force posts callback! Since everything
-// works on the same thread in this class, not all force posts are necessary.
-
 #define BIND_TO_RENDER_LOOP(function) \
-  media::BindToLoop(base::MessageLoopProxy::current(), \
-                    base::Bind(function, weak_this_.GetWeakPtr()))
+  media::BindToLoop(main_loop_, \
+                    base::Bind(function, main_weak_this_.GetWeakPtr()))
 
 #define BIND_TO_RENDER_LOOP_1(function, arg1) \
-  media::BindToLoop(base::MessageLoopProxy::current(), \
-                    base::Bind(function, weak_this_.GetWeakPtr(), arg1))
+  media::BindToLoop(main_loop_, \
+                    base::Bind(function, main_weak_this_.GetWeakPtr(), arg1))
 
-#define BIND_TO_RENDER_LOOP_2(function, arg1, arg2) \
-  media::BindToLoop(base::MessageLoopProxy::current(), \
-                    base::Bind(function, weak_this_.GetWeakPtr(), arg1, arg2))
-
-#define BIND_TO_RENDER_LOOP_3(function, arg1, arg2, arg3) \
-  media::BindToLoop(base::MessageLoopProxy::current(), \
-                    base::Bind(function, \
-                               weak_this_.GetWeakPtr(), arg1, arg2, arg3))
+#if defined(GOOGLE_TV)
+#define DCHECK_BELONG_TO_MEDIA_LOOP() \
+    DCHECK(media_loop_->BelongsToCurrentThread())
+#else
+#define DCHECK_BELONG_TO_MEDIA_LOOP() \
+    DCHECK(main_loop_->BelongsToCurrentThread())
+#endif
 
 static void LogMediaSourceError(const scoped_refptr<media::MediaLog>& media_log,
                                 const std::string& error) {
   media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
 }
 
-MediaSourceDelegate::MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy,
-                                         int player_id,
-                                         media::MediaLog* media_log)
-    : weak_this_(this),
+MediaSourceDelegate::MediaSourceDelegate(
+    WebMediaPlayerProxyAndroid* proxy,
+    int player_id,
+    const scoped_refptr<base::MessageLoopProxy>& media_loop,
+    media::MediaLog* media_log)
+    : main_weak_this_(this),
+      media_weak_this_(this),
+      main_loop_(base::MessageLoopProxy::current()),
+#if defined(GOOGLE_TV)
+      media_loop_(media_loop),
+      send_read_from_demuxer_ack_cb_(
+          BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendReadFromDemuxerAck)),
+      send_seek_request_ack_cb_(
+          BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendSeekRequestAck)),
+      send_demuxer_ready_cb_(
+          BIND_TO_RENDER_LOOP(&MediaSourceDelegate::SendDemuxerReady)),
+#endif
       proxy_(proxy),
       player_id_(player_id),
       media_log_(media_log),
@@ -80,6 +89,7 @@
 }
 
 MediaSourceDelegate::~MediaSourceDelegate() {
+  DCHECK(main_loop_->BelongsToCurrentThread());
   DVLOG(1) << "~MediaSourceDelegate() : " << player_id_;
   DCHECK(!chunk_demuxer_);
   DCHECK(!demuxer_);
@@ -90,6 +100,7 @@
 }
 
 void MediaSourceDelegate::Destroy() {
+  DCHECK(main_loop_->BelongsToCurrentThread());
   DVLOG(1) << "Destroy() : " << player_id_;
   if (!demuxer_) {
     delete this;
@@ -98,10 +109,30 @@
 
   duration_change_cb_.Reset();
   update_network_state_cb_.Reset();
-  media_source_.reset();
+  media_source_opened_cb_.Reset();
   proxy_ = NULL;
 
-  demuxer_ = NULL;
+  main_weak_this_.InvalidateWeakPtrs();
+  DCHECK(!main_weak_this_.HasWeakPtrs());
+
+  if (chunk_demuxer_)
+    chunk_demuxer_->Shutdown();
+#if defined(GOOGLE_TV)
+  // |this| will be transfered to the callback StopDemuxer() and
+  // OnDemuxerStopDone(). they own |this| and OnDemuxerStopDone() will delete
+  // it when called. Hence using base::Unretained(this) is safe here.
+  media_loop_->PostTask(FROM_HERE,
+                        base::Bind(&MediaSourceDelegate::StopDemuxer,
+                        base::Unretained(this)));
+#else
+  StopDemuxer();
+#endif
+}
+
+void MediaSourceDelegate::StopDemuxer() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
+  DCHECK(demuxer_);
+
   audio_stream_ = NULL;
   video_stream_ = NULL;
   // TODO(xhwang): Figure out if we need to Reset the DDSs after Seeking or
@@ -109,29 +140,29 @@
   audio_decrypting_demuxer_stream_.reset();
   video_decrypting_demuxer_stream_.reset();
 
-  weak_this_.InvalidateWeakPtrs();
-  DCHECK(!weak_this_.HasWeakPtrs());
+  media_weak_this_.InvalidateWeakPtrs();
+  DCHECK(!media_weak_this_.HasWeakPtrs());
 
-  if (chunk_demuxer_) {
-    // The callback OnDemuxerStopDone() owns |this| and will delete it when
-    // called. Hence using base::Unretained(this) is safe here.
-    chunk_demuxer_->Stop(base::Bind(&MediaSourceDelegate::OnDemuxerStopDone,
-                                    base::Unretained(this)));
-  }
+  // The callback OnDemuxerStopDone() owns |this| and will delete it when
+  // called. Hence using base::Unretained(this) is safe here.
+  demuxer_->Stop(media::BindToLoop(main_loop_,
+      base::Bind(&MediaSourceDelegate::OnDemuxerStopDone,
+                 base::Unretained(this))));
 }
 
 void MediaSourceDelegate::InitializeMediaSource(
-    WebKit::WebMediaSource* media_source,
+    const MediaSourceOpenedCB& media_source_opened_cb,
     const media::NeedKeyCB& need_key_cb,
     const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
     const UpdateNetworkStateCB& update_network_state_cb,
     const DurationChangeCB& duration_change_cb) {
-  DCHECK(media_source);
-  media_source_.reset(media_source);
+  DCHECK(main_loop_->BelongsToCurrentThread());
+  DCHECK(!media_source_opened_cb.is_null());
+  media_source_opened_cb_ = media_source_opened_cb;
   need_key_cb_ = need_key_cb;
   set_decryptor_ready_cb_ = set_decryptor_ready_cb;
-  update_network_state_cb_ = update_network_state_cb;
-  duration_change_cb_ = duration_change_cb;
+  update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
+  duration_change_cb_ = media::BindToCurrentLoop(duration_change_cb);
   access_unit_size_ = kAccessUnitSizeForMediaSource;
 
   chunk_demuxer_.reset(new media::ChunkDemuxer(
@@ -142,23 +173,40 @@
       base::Bind(&LogMediaSourceError, media_log_)));
   demuxer_ = chunk_demuxer_.get();
 
-  chunk_demuxer_->Initialize(this,
-      BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
+#if defined(GOOGLE_TV)
+  // |this| will be retained until StopDemuxer() is posted, so Unretained() is
+  // safe here.
+  media_loop_->PostTask(FROM_HERE,
+                        base::Bind(&MediaSourceDelegate::InitializeDemuxer,
+                        base::Unretained(this)));
+#else
+  InitializeDemuxer();
+#endif
+}
+
+void MediaSourceDelegate::InitializeDemuxer() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
+  demuxer_->Initialize(this, base::Bind(&MediaSourceDelegate::OnDemuxerInitDone,
+                                        media_weak_this_.GetWeakPtr()));
 }
 
 #if defined(GOOGLE_TV)
 void MediaSourceDelegate::InitializeMediaStream(
     media::Demuxer* demuxer,
     const UpdateNetworkStateCB& update_network_state_cb) {
+  DCHECK(main_loop_->BelongsToCurrentThread());
   DCHECK(demuxer);
   demuxer_ = demuxer;
-  update_network_state_cb_ = update_network_state_cb;
+  update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
   // When playing Media Stream, don't wait to accumulate multiple packets per
   // IPC communication.
   access_unit_size_ = 1;
 
-  demuxer_->Initialize(this,
-      BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerInitDone));
+  // |this| will be retained until StopDemuxer() is posted, so Unretained() is
+  // safe here.
+  media_loop_->PostTask(FROM_HERE,
+                        base::Bind(&MediaSourceDelegate::InitializeDemuxer,
+                        base::Unretained(this)));
 }
 #endif
 
@@ -185,13 +233,14 @@
 }
 
 void MediaSourceDelegate::Seek(base::TimeDelta time, unsigned seek_request_id) {
+  DCHECK(main_loop_->BelongsToCurrentThread());
   DVLOG(1) << "Seek(" << time.InSecondsF() << ") : " << player_id_;
 
   last_seek_time_ = time;
   last_seek_request_id_ = seek_request_id;
 
   if (chunk_demuxer_) {
-    if (seeking_) {
+    if (IsSeeking()) {
       chunk_demuxer_->CancelPendingSeek(time);
       return;
     }
@@ -199,10 +248,22 @@
     chunk_demuxer_->StartWaitingForSeek(time);
   }
 
-  seeking_ = true;
-  demuxer_->Seek(time,
-                 BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnDemuxerSeekDone,
-                                       seek_request_id));
+  SetSeeking(true);
+#if defined(GOOGLE_TV)
+  media_loop_->PostTask(FROM_HERE,
+                        base::Bind(&MediaSourceDelegate::SeekInternal,
+                                   base::Unretained(this),
+                                   time, seek_request_id));
+#else
+  SeekInternal(time, seek_request_id);
+#endif
+}
+
+void MediaSourceDelegate::SeekInternal(base::TimeDelta time,
+                                       unsigned request_id) {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
+  demuxer_->Seek(time, base::Bind(&MediaSourceDelegate::OnDemuxerSeekDone,
+                                  media_weak_this_.GetWeakPtr(), request_id));
 }
 
 void MediaSourceDelegate::SetTotalBytes(int64 total_bytes) {
@@ -220,45 +281,61 @@
 
 void MediaSourceDelegate::SetDuration(base::TimeDelta duration) {
   DVLOG(1) << "SetDuration(" << duration.InSecondsF() << ") : " << player_id_;
-  // Notify our owner (e.g. WebMediaPlayerAndroid) that
-  // duration has changed.
+  // Notify our owner (e.g. WebMediaPlayerAndroid) that duration has changed.
+  // |duration_change_cb_| is bound to the main thread.
   if (!duration_change_cb_.is_null())
     duration_change_cb_.Run(duration);
 }
 
 void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type) {
+  DCHECK(main_loop_->BelongsToCurrentThread());
+#if defined(GOOGLE_TV)
+  media_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&MediaSourceDelegate::OnReadFromDemuxerInternal,
+                 base::Unretained(this), type));
+#else
+  OnReadFromDemuxerInternal(type);
+#endif
+}
+
+void MediaSourceDelegate::OnReadFromDemuxerInternal(
+    media::DemuxerStream::Type type) {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "OnReadFromDemuxer(" << type << ") : " << player_id_;
-  if (seeking_)
+  if (IsSeeking())
     return;  // Drop the request during seeking.
 
   DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO);
   // The access unit size should have been initialized properly at this stage.
   DCHECK_GT(access_unit_size_, 0u);
-  MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params =
-      type == DemuxerStream::AUDIO ? &audio_params_ : &video_params_;
+  scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params(
+      new MediaPlayerHostMsg_ReadFromDemuxerAck_Params());
   params->type = type;
   params->access_units.resize(access_unit_size_);
-  ReadFromDemuxerStream(type, params, 0);
+  ReadFromDemuxerStream(type, params.Pass(), 0);
 }
 
 void MediaSourceDelegate::ReadFromDemuxerStream(
     media::DemuxerStream::Type type,
-    MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
+    scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params,
     size_t index) {
-  DCHECK(!seeking_);
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   // DemuxerStream::Read() always returns the read callback asynchronously.
   DemuxerStream* stream =
       (type == DemuxerStream::AUDIO) ? audio_stream_ : video_stream_;
-  stream->Read(base::Bind(&MediaSourceDelegate::OnBufferReady,
-                          weak_this_.GetWeakPtr(), type, params, index));
+  stream->Read(base::Bind(
+      &MediaSourceDelegate::OnBufferReady,
+      media_weak_this_.GetWeakPtr(), type, base::Passed(&params), index));
 }
 
 void MediaSourceDelegate::OnBufferReady(
     media::DemuxerStream::Type type,
-    MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
+    scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params,
     size_t index,
     DemuxerStream::Status status,
     const scoped_refptr<media::DecoderBuffer>& buffer) {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "OnBufferReady(" << index << ", " << status << ", "
            << ((!buffer || buffer->end_of_stream()) ?
                -1 : buffer->timestamp().InMilliseconds())
@@ -267,9 +344,8 @@
 
   // No new OnReadFromDemuxer() will be called during seeking. So this callback
   // must be from previous OnReadFromDemuxer() call and should be ignored.
-  if (seeking_) {
+  if (IsSeeking()) {
     DVLOG(1) << "OnBufferReady(): Ignore previous read during seeking.";
-    params->access_units.clear();
     return;
   }
 
@@ -288,7 +364,6 @@
     case DemuxerStream::kAborted:
       // Because the abort was caused by the seek, don't respond ack.
       DVLOG(1) << "OnBufferReady() : Aborted";
-      params->access_units.clear();
       return;
 
     case DemuxerStream::kConfigChanged:
@@ -348,7 +423,7 @@
             buffer->decrypt_config()->subsamples();
       }
       if (++index < params->access_units.size()) {
-        ReadFromDemuxerStream(type, params, index);
+        ReadFromDemuxerStream(type, params.Pass(), index);
         return;
       }
       break;
@@ -357,19 +432,29 @@
       NOTREACHED();
   }
 
-  if (proxy_)
-    proxy_->ReadFromDemuxerAck(player_id_, *params);
+#if defined(GOOGLE_TV)
+  send_read_from_demuxer_ack_cb_.Run(params.Pass());
+#else
+  SendReadFromDemuxerAck(params.Pass());
+#endif
+}
 
-  params->access_units.clear();
+void MediaSourceDelegate::SendReadFromDemuxerAck(
+    scoped_ptr<MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params) {
+  DCHECK(main_loop_->BelongsToCurrentThread());
+  if (!IsSeeking() && proxy_)
+    proxy_->ReadFromDemuxerAck(player_id_, *params);
 }
 
 void MediaSourceDelegate::OnDemuxerError(media::PipelineStatus status) {
   DVLOG(1) << "OnDemuxerError(" << status << ") : " << player_id_;
+  // |update_network_state_cb_| is bound to the main thread.
   if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
     update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
 }
 
 void MediaSourceDelegate::OnDemuxerInitDone(media::PipelineStatus status) {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "OnDemuxerInitDone(" << status << ") : " << player_id_;
   DCHECK(demuxer_);
 
@@ -402,6 +487,7 @@
 }
 
 void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "InitAudioDecryptingDemuxerStream() : " << player_id_;
   DCHECK(!set_decryptor_ready_cb_.is_null());
 
@@ -409,11 +495,12 @@
       base::MessageLoopProxy::current(), set_decryptor_ready_cb_));
   audio_decrypting_demuxer_stream_->Initialize(
       audio_stream_,
-      BIND_TO_RENDER_LOOP(
-          &MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone));
+      base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
+                 media_weak_this_.GetWeakPtr()));
 }
 
 void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "InitVideoDecryptingDemuxerStream() : " << player_id_;
   DCHECK(!set_decryptor_ready_cb_.is_null());
 
@@ -421,12 +508,13 @@
       base::MessageLoopProxy::current(), set_decryptor_ready_cb_));
   video_decrypting_demuxer_stream_->Initialize(
       video_stream_,
-      BIND_TO_RENDER_LOOP(
-          &MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone));
+      base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
+                 media_weak_this_.GetWeakPtr()));
 }
 
 void MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone(
     media::PipelineStatus status) {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "OnAudioDecryptingDemuxerStreamInitDone(" << status
            << ") : " << player_id_;
   DCHECK(demuxer_);
@@ -450,6 +538,7 @@
 
 void MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone(
     media::PipelineStatus status) {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "OnVideoDecryptingDemuxerStreamInitDone(" << status
            << ") : " << player_id_;
   DCHECK(demuxer_);
@@ -467,8 +556,9 @@
 
 void MediaSourceDelegate::OnDemuxerSeekDone(unsigned seek_request_id,
                                             media::PipelineStatus status) {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "OnDemuxerSeekDone(" << status << ") : " << player_id_;
-  DCHECK(seeking_);
+  DCHECK(IsSeeking());
 
   if (status != media::PIPELINE_OK) {
     OnDemuxerError(status);
@@ -479,10 +569,7 @@
   if (seek_request_id != last_seek_request_id_) {
     if (chunk_demuxer_)
       chunk_demuxer_->StartWaitingForSeek(last_seek_time_);
-    demuxer_->Seek(
-        last_seek_time_,
-        BIND_TO_RENDER_LOOP_1(&MediaSourceDelegate::OnDemuxerSeekDone,
-                              last_seek_request_id_));
+    SeekInternal(last_seek_time_, last_seek_request_id_);
     return;
   }
 
@@ -490,46 +577,73 @@
 }
 
 void MediaSourceDelegate::ResetAudioDecryptingDemuxerStream() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "ResetAudioDecryptingDemuxerStream() : " << player_id_;
   if (audio_decrypting_demuxer_stream_) {
     audio_decrypting_demuxer_stream_->Reset(
         base::Bind(&MediaSourceDelegate::ResetVideoDecryptingDemuxerStream,
-                   weak_this_.GetWeakPtr()));
+                   media_weak_this_.GetWeakPtr()));
   } else {
     ResetVideoDecryptingDemuxerStream();
   }
 }
 
 void MediaSourceDelegate::ResetVideoDecryptingDemuxerStream() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "ResetVideoDecryptingDemuxerStream()";
+#if defined(GOOGLE_TV)
+  if (video_decrypting_demuxer_stream_)
+    video_decrypting_demuxer_stream_->Reset(send_seek_request_ack_cb_);
+  else
+    send_seek_request_ack_cb_.Run();
+#else
   if (video_decrypting_demuxer_stream_) {
     video_decrypting_demuxer_stream_->Reset(
         base::Bind(&MediaSourceDelegate::SendSeekRequestAck,
-                   weak_this_.GetWeakPtr()));
+                   main_weak_this_.GetWeakPtr()));
   } else {
     SendSeekRequestAck();
   }
+#endif
 }
 
 void MediaSourceDelegate::SendSeekRequestAck() {
   DVLOG(1) << "SendSeekRequestAck() : " << player_id_;
-  seeking_ = false;
+  SetSeeking(false);
   proxy_->SeekRequestAck(player_id_, last_seek_request_id_);
   last_seek_request_id_ = 0;
 }
 
 void MediaSourceDelegate::OnDemuxerStopDone() {
+  DCHECK(main_loop_->BelongsToCurrentThread());
   DVLOG(1) << "OnDemuxerStopDone() : " << player_id_;
   chunk_demuxer_.reset();
+  demuxer_ = NULL;
   delete this;
 }
 
 void MediaSourceDelegate::OnMediaConfigRequest() {
+#if defined(GOOGLE_TV)
+  if (!media_loop_->BelongsToCurrentThread()) {
+    media_loop_->PostTask(FROM_HERE,
+        base::Bind(&MediaSourceDelegate::OnMediaConfigRequest,
+                   base::Unretained(this)));
+    return;
+  }
+#endif
   if (CanNotifyDemuxerReady())
     NotifyDemuxerReady();
 }
 
 void MediaSourceDelegate::NotifyKeyAdded(const std::string& key_system) {
+#if defined(GOOGLE_TV)
+  if (!media_loop_->BelongsToCurrentThread()) {
+    media_loop_->PostTask(FROM_HERE,
+        base::Bind(&MediaSourceDelegate::NotifyKeyAdded,
+                   base::Unretained(this), key_system));
+    return;
+  }
+#endif
   DVLOG(1) << "NotifyKeyAdded() : " << player_id_;
   // TODO(kjyoun): Enhance logic to detect when to call NotifyDemuxerReady()
   // For now, we calls it when the first key is added. See
@@ -545,6 +659,7 @@
 }
 
 bool MediaSourceDelegate::CanNotifyDemuxerReady() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   // This can happen when a key is added before the demuxer is initialized.
   // See NotifyKeyAdded().
   // TODO(kjyoun): Remove NotifyDemxuerReady() call from NotifyKeyAdded() so
@@ -558,36 +673,49 @@
 }
 
 void MediaSourceDelegate::NotifyDemuxerReady() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   DVLOG(1) << "NotifyDemuxerReady() : " << player_id_;
   DCHECK(CanNotifyDemuxerReady());
 
-  MediaPlayerHostMsg_DemuxerReady_Params params;
+  scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params(
+      new MediaPlayerHostMsg_DemuxerReady_Params());
   if (audio_stream_) {
     media::AudioDecoderConfig config = audio_stream_->audio_decoder_config();
-    params.audio_codec = config.codec();
-    params.audio_channels =
+    params->audio_codec = config.codec();
+    params->audio_channels =
         media::ChannelLayoutToChannelCount(config.channel_layout());
-    params.audio_sampling_rate = config.samples_per_second();
-    params.is_audio_encrypted = config.is_encrypted();
-    params.audio_extra_data = std::vector<uint8>(
+    params->audio_sampling_rate = config.samples_per_second();
+    params->is_audio_encrypted = config.is_encrypted();
+    params->audio_extra_data = std::vector<uint8>(
         config.extra_data(), config.extra_data() + config.extra_data_size());
   }
   if (video_stream_) {
     media::VideoDecoderConfig config = video_stream_->video_decoder_config();
-    params.video_codec = config.codec();
-    params.video_size = config.natural_size();
-    params.is_video_encrypted = config.is_encrypted();
-    params.video_extra_data = std::vector<uint8>(
+    params->video_codec = config.codec();
+    params->video_size = config.natural_size();
+    params->is_video_encrypted = config.is_encrypted();
+    params->video_extra_data = std::vector<uint8>(
         config.extra_data(), config.extra_data() + config.extra_data_size());
   }
-  params.duration_ms = GetDurationMs();
-  params.key_system = HasEncryptedStream() ? key_system_ : "";
+  params->duration_ms = GetDurationMs();
+  params->key_system = HasEncryptedStream() ? key_system_ : "";
 
+#if defined(GOOGLE_TV)
+  send_demuxer_ready_cb_.Run(params.Pass());
+#else
+  SendDemuxerReady(params.Pass());
+#endif
+}
+
+void MediaSourceDelegate::SendDemuxerReady(
+    scoped_ptr<MediaPlayerHostMsg_DemuxerReady_Params> params) {
+  DCHECK(main_loop_->BelongsToCurrentThread());
   if (proxy_)
-    proxy_->DemuxerReady(player_id_, params);
+    proxy_->DemuxerReady(player_id_, *params);
 }
 
 int MediaSourceDelegate::GetDurationMs() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   if (!chunk_demuxer_)
     return -1;
 
@@ -601,10 +729,11 @@
 }
 
 void MediaSourceDelegate::OnDemuxerOpened() {
-  if (!media_source_)
+  DCHECK(main_loop_->BelongsToCurrentThread());
+  if (media_source_opened_cb_.is_null())
     return;
 
-  media_source_->open(new WebMediaSourceClientImpl(
+  media_source_opened_cb_.Run(new WebMediaSourceImpl(
       chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
 }
 
@@ -612,6 +741,7 @@
                                     const std::string& type,
                                     scoped_ptr<uint8[]> init_data,
                                     int init_data_size) {
+  DCHECK(main_loop_->BelongsToCurrentThread());
   if (need_key_cb_.is_null())
     return;
 
@@ -626,10 +756,21 @@
 }
 
 bool MediaSourceDelegate::HasEncryptedStream() {
+  DCHECK_BELONG_TO_MEDIA_LOOP();
   return (audio_stream_ &&
           audio_stream_->audio_decoder_config().is_encrypted()) ||
          (video_stream_ &&
           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_;
+}
+
 }  // namespace content
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h
index 88b9b2d..2d5851c 100644
--- a/content/renderer/media/android/media_source_delegate.h
+++ b/content/renderer/media/android/media_source_delegate.h
@@ -9,8 +9,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
-#include "media/base/android/demuxer_stream_player_params.h"
 #include "media/base/decryptor.h"
 #include "media/base/demuxer.h"
 #include "media/base/media_keys.h"
@@ -25,6 +25,7 @@
 class DecryptingDemuxerStream;
 class DemuxerStream;
 class MediaLog;
+struct MediaPlayerHostMsg_DemuxerReady_Params;
 struct MediaPlayerHostMsg_ReadFromDemuxerAck_Params;
 }
 
@@ -34,6 +35,8 @@
 
 class MediaSourceDelegate : public media::DemuxerHost {
  public:
+  typedef base::Callback<void(WebKit::WebMediaSourceNew*)>
+      MediaSourceOpenedCB;
   typedef base::Callback<void(WebKit::WebMediaPlayer::NetworkState)>
       UpdateNetworkStateCB;
   typedef base::Callback<void(const base::TimeDelta&)> DurationChangeCB;
@@ -49,12 +52,13 @@
 
   MediaSourceDelegate(WebMediaPlayerProxyAndroid* proxy,
                       int player_id,
+                      const scoped_refptr<base::MessageLoopProxy>& media_loop,
                       media::MediaLog* media_log);
 
   // Initialize the MediaSourceDelegate. |media_source| will be owned by
   // this object after this call.
   void InitializeMediaSource(
-      WebKit::WebMediaSource* media_source,
+      const MediaSourceOpenedCB& media_source_opened_cb,
       const media::NeedKeyCB& need_key_cb,
       const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
       const UpdateNetworkStateCB& update_network_state_cb,
@@ -89,6 +93,13 @@
   void Destroy();
 
  private:
+  typedef base::Callback<void(
+      scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params)>
+          ReadFromDemuxerAckCB;
+  typedef base::Callback<void(
+      scoped_ptr<media::MediaPlayerHostMsg_DemuxerReady_Params> params)>
+          DemuxerReadyCB;
+
   // This is private to enforce use of the Destroyer.
   virtual ~MediaSourceDelegate();
 
@@ -138,26 +149,54 @@
                                               const std::string& language);
   void NotifyDemuxerReady();
   bool CanNotifyDemuxerReady();
+  void SendDemuxerReady(
+      scoped_ptr<media::MediaPlayerHostMsg_DemuxerReady_Params> params);
 
+  void StopDemuxer();
+  void InitializeDemuxer();
+  void SeekInternal(base::TimeDelta time, unsigned seek_request_id);
+  void OnReadFromDemuxerInternal(media::DemuxerStream::Type type);
   // Reads an access unit from the demuxer stream |stream| and stores it in
   // the |index|th access unit in |params|.
   void ReadFromDemuxerStream(
       media::DemuxerStream::Type type,
-      media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
+      scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params,
       size_t index);
   void OnBufferReady(
       media::DemuxerStream::Type type,
-      media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params* params,
+      scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params,
       size_t index,
       media::DemuxerStream::Status status,
       const scoped_refptr<media::DecoderBuffer>& buffer);
 
+  void SendReadFromDemuxerAck(
+      scoped_ptr<media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params> params);
+
   // Helper function for calculating duration.
   int GetDurationMs();
 
   bool HasEncryptedStream();
 
-  base::WeakPtrFactory<MediaSourceDelegate> weak_this_;
+  void SetSeeking(bool seeking);
+  bool IsSeeking() const;
+
+  // Weak pointer must be dereferenced and invalidated on the same thread.
+  base::WeakPtrFactory<MediaSourceDelegate> main_weak_this_;
+  base::WeakPtrFactory<MediaSourceDelegate> media_weak_this_;
+
+  // Message loop for main renderer thread.
+  const scoped_refptr<base::MessageLoopProxy> main_loop_;
+#if defined(GOOGLE_TV)
+  // Message loop for the media thread.
+  // When there is high load in the render thread, the reading from |demuxer_|
+  // and its read-callback loops run very slowly.  To improve the response time
+  // of the readings, we run tasks related to |demuxer_| in the media thread.
+  const scoped_refptr<base::MessageLoopProxy> media_loop_;
+
+  ReadFromDemuxerAckCB send_read_from_demuxer_ack_cb_;
+  base::Closure send_seek_request_ack_cb_;
+  DemuxerReadyCB send_demuxer_ready_cb_;
+#endif
 
   WebMediaPlayerProxyAndroid* proxy_;
   int player_id_;
@@ -167,7 +206,6 @@
   DurationChangeCB duration_change_cb_;
 
   scoped_ptr<media::ChunkDemuxer> chunk_demuxer_;
-  scoped_ptr<WebKit::WebMediaSource> media_source_;
   media::Demuxer* demuxer_;
   bool is_demuxer_ready_;
 
@@ -184,6 +222,7 @@
   // Keep a list of buffered time ranges.
   WebKit::WebTimeRanges buffered_web_time_ranges_;
 
+  MediaSourceOpenedCB media_source_opened_cb_;
   media::NeedKeyCB need_key_cb_;
 
   // The currently selected key system. Empty string means that no key system
@@ -194,10 +233,10 @@
   // through GenerateKeyRequest() directly from WebKit.
   std::string init_data_type_;
 
-  media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params audio_params_;
-  media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params video_params_;
-
+  // Lock used to serialize access for |seeking_|.
+  mutable base::Lock seeking_lock_;
   bool seeking_;
+
   base::TimeDelta last_seek_time_;
   unsigned last_seek_request_id_;
 
diff --git a/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc b/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc
index 88878d5..de0ca92 100644
--- a/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc
+++ b/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.cc
@@ -4,31 +4,175 @@
 
 #include "content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h"
 
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/process/process.h"
+#include "base/synchronization/lock.h"
+#include "cc/output/context_provider.h"
+#include "content/common/android/surface_texture_peer.h"
+#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
+#include "ui/gl/android/surface_texture_bridge.h"
+
 namespace content {
 
-StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl() {}
+namespace {
+
+class StreamTextureProxyImpl
+    : public StreamTextureProxy,
+      public base::SupportsWeakPtr<StreamTextureProxyImpl> {
+ public:
+  explicit StreamTextureProxyImpl(
+      StreamTextureFactorySynchronousImpl::ContextProvider* provider);
+  virtual ~StreamTextureProxyImpl();
+
+  // StreamTextureProxy implementation:
+  virtual void BindToCurrentThread(int32 stream_id) OVERRIDE;
+  virtual bool IsBoundToThread() OVERRIDE { return loop_.get() != NULL; }
+  virtual void SetClient(cc::VideoFrameProvider::Client* client) OVERRIDE;
+  virtual void Release() OVERRIDE;
+
+ private:
+  void OnFrameAvailable();
+
+  scoped_refptr<base::MessageLoopProxy> loop_;
+  base::Lock client_lock_;
+  cc::VideoFrameProvider::Client* client_;
+  base::Closure callback_;
+
+  scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider>
+      context_provider_;
+  scoped_refptr<gfx::SurfaceTextureBridge> surface_texture_;
+
+  float current_matrix_[16];
+  bool has_updated_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxyImpl);
+};
+
+StreamTextureProxyImpl::StreamTextureProxyImpl(
+    StreamTextureFactorySynchronousImpl::ContextProvider* provider)
+    : context_provider_(provider), has_updated_(false) {
+  std::fill(current_matrix_, current_matrix_ + 16, 0);
+}
+
+StreamTextureProxyImpl::~StreamTextureProxyImpl() {}
+
+void StreamTextureProxyImpl::Release() {
+  SetClient(NULL);
+  if (!loop_->BelongsToCurrentThread())
+    loop_->DeleteSoon(FROM_HERE, this);
+  else
+    delete this;
+}
+
+void StreamTextureProxyImpl::SetClient(cc::VideoFrameProvider::Client* client) {
+  base::AutoLock lock(client_lock_);
+  client_ = client;
+}
+
+void StreamTextureProxyImpl::BindToCurrentThread(int stream_id) {
+  loop_ = base::MessageLoopProxy::current();
+
+  surface_texture_ = context_provider_->GetSurfaceTexture(stream_id);
+  if (!surface_texture_) {
+    LOG(ERROR) << "Failed to get SurfaceTexture for stream.";
+    return;
+  }
+
+  callback_ =
+      base::Bind(&StreamTextureProxyImpl::OnFrameAvailable, AsWeakPtr());
+  surface_texture_->SetFrameAvailableCallback(callback_);
+}
+
+void StreamTextureProxyImpl::OnFrameAvailable() {
+  // GetTransformMatrix only returns something valid after both is true:
+  // - OnFrameAvailable was called
+  // - we called UpdateTexImage
+  if (has_updated_) {
+    float matrix[16];
+    surface_texture_->GetTransformMatrix(matrix);
+
+    if (memcmp(current_matrix_, matrix, sizeof(matrix)) != 0) {
+      memcpy(current_matrix_, matrix, sizeof(matrix));
+
+      base::AutoLock lock(client_lock_);
+      if (client_)
+        client_->DidUpdateMatrix(current_matrix_);
+    }
+  }
+  // OnFrameAvailable being called a second time implies that we called
+  // updateTexImage since after we received the first frame.
+  has_updated_ = true;
+
+  base::AutoLock lock(client_lock_);
+  if (client_)
+    client_->DidReceiveFrame();
+}
+
+}  // namespace
+
+StreamTextureFactorySynchronousImpl::StreamTextureFactorySynchronousImpl(
+    ContextProvider* context_provider,
+    int view_id)
+    : context_provider_(context_provider), view_id_(view_id) {}
+
 StreamTextureFactorySynchronousImpl::~StreamTextureFactorySynchronousImpl() {}
 
 StreamTextureProxy* StreamTextureFactorySynchronousImpl::CreateProxy() {
-  return NULL;
+  return new StreamTextureProxyImpl(context_provider_);
 }
 
 void StreamTextureFactorySynchronousImpl::EstablishPeer(int32 stream_id,
-                                                        int player_id) {}
+                                                        int player_id) {
+  scoped_refptr<gfx::SurfaceTextureBridge> surface_texture =
+      context_provider_->GetSurfaceTexture(stream_id);
+  if (surface_texture) {
+    SurfaceTexturePeer::GetInstance()->EstablishSurfaceTexturePeer(
+        base::Process::Current().handle(),
+        surface_texture,
+        view_id_,
+        player_id);
+  }
+}
 
 unsigned StreamTextureFactorySynchronousImpl::CreateStreamTexture(
     unsigned texture_target,
     unsigned* texture_id,
     gpu::Mailbox* texture_mailbox,
     unsigned* texture_mailbox_sync_point) {
-  return 0;
+  WebKit::WebGraphicsContext3D* context = context_provider_->Context3d();
+  unsigned stream_id = 0;
+  if (context->makeContextCurrent()) {
+    *texture_id = context->createTexture();
+    stream_id = context->createStreamTextureCHROMIUM(*texture_id);
+
+    context->genMailboxCHROMIUM(texture_mailbox->name);
+    context->bindTexture(texture_target, *texture_id);
+    context->produceTextureCHROMIUM(texture_target, texture_mailbox->name);
+
+    context->flush();
+    *texture_mailbox_sync_point = context->insertSyncPoint();
+  }
+  return stream_id;
 }
 
 void StreamTextureFactorySynchronousImpl::DestroyStreamTexture(
-    unsigned texture_id) {}
+    unsigned texture_id) {
+  WebKit::WebGraphicsContext3D* context = context_provider_->Context3d();
+  if (context->makeContextCurrent()) {
+    context->destroyStreamTextureCHROMIUM(texture_id);
+    context->deleteTexture(texture_id);
+    context->flush();
+  }
+}
 
 void StreamTextureFactorySynchronousImpl::SetStreamTextureSize(
-    int32 texture_id,
+    int32 stream_id,
     const gfx::Size& size) {}
 
 }  // namespace content
diff --git a/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h b/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h
index 52fc65a..50f9e80 100644
--- a/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h
+++ b/content/renderer/media/android/stream_texture_factory_android_synchronous_impl.h
@@ -5,14 +5,36 @@
 #ifndef CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_FACTORY_ANDROID_SYNCHRONOUS_IMPL_H_
 #define CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_FACTORY_ANDROID_SYNCHRONOUS_IMPL_H_
 
+#include "base/memory/ref_counted.h"
 #include "content/renderer/media/android/stream_texture_factory_android.h"
 
+namespace gfx {
+class SurfaceTextureBridge;
+}
+
+namespace WebKit {
+class WebGraphicsContext3D;
+}
+
 namespace content {
 
 // Factory for when using synchronous compositor in Android WebView.
 class StreamTextureFactorySynchronousImpl : public StreamTextureFactory {
  public:
-  StreamTextureFactorySynchronousImpl();
+  class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
+   public:
+    virtual scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture(
+        uint32 stream_id) = 0;
+
+    virtual WebKit::WebGraphicsContext3D* Context3d() = 0;
+
+   protected:
+    friend class base::RefCountedThreadSafe<ContextProvider>;
+    virtual ~ContextProvider() {}
+  };
+
+  StreamTextureFactorySynchronousImpl(ContextProvider* context_provider,
+                                      int view_id);
   virtual ~StreamTextureFactorySynchronousImpl();
 
   virtual StreamTextureProxy* CreateProxy() OVERRIDE;
@@ -23,10 +45,13 @@
       gpu::Mailbox* texture_mailbox,
       unsigned* texture_mailbox_sync_point) OVERRIDE;
   virtual void DestroyStreamTexture(unsigned texture_id) OVERRIDE;
-  virtual void SetStreamTextureSize(int32 texture_id,
+  virtual void SetStreamTextureSize(int32 stream_id,
                                     const gfx::Size& size) OVERRIDE;
 
  private:
+  scoped_refptr<ContextProvider> context_provider_;
+  int view_id_;
+
   DISALLOW_COPY_AND_ASSIGN(StreamTextureFactorySynchronousImpl);
 };
 
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 4c6b4aa..f8eea96 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -65,12 +65,14 @@
     RendererMediaPlayerManager* manager,
     WebMediaPlayerProxyAndroid* proxy,
     StreamTextureFactory* factory,
+    const scoped_refptr<base::MessageLoopProxy>& media_loop,
     media::MediaLog* media_log)
     : frame_(frame),
       client_(client),
       delegate_(delegate),
       buffered_(1u),
       main_loop_(base::MessageLoopProxy::current()),
+      media_loop_(media_loop),
       ignore_metadata_duration_change_(false),
       pending_seek_(0),
       seeking_(false),
@@ -193,26 +195,34 @@
 #endif
 }
 
-void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) {
-  load(url, NULL, cors_mode);
-}
-
-void WebMediaPlayerAndroid::load(const WebURL& url,
-                                 WebMediaSource* media_source,
+void WebMediaPlayerAndroid::load(LoadType load_type,
+                                 const WebKit::WebURL& url,
                                  CORSMode cors_mode) {
-  source_type_ = MediaPlayerAndroid::SOURCE_TYPE_URL;
+#if defined(GOOGLE_TV)
+  // TODO(acolwell): Remove this hack once Blink-side changes land.
+  if (load_type == LoadTypeURL && media_stream_client_)
+    load_type = LoadTypeMediaStream;
+#endif
+
+  switch (load_type) {
+    case LoadTypeURL:
+      source_type_ = MediaPlayerAndroid::SOURCE_TYPE_URL;
+      break;
+    case LoadTypeMediaSource:
+      source_type_ = MediaPlayerAndroid::SOURCE_TYPE_MSE;
+      break;
+    case LoadTypeMediaStream:
+#if defined(GOOGLE_TV)
+      source_type_ = MediaPlayerAndroid::SOURCE_TYPE_MSE;
+#else
+      source_type_ = MediaPlayerAndroid::SOURCE_TYPE_URL;
+#endif
+      break;
+  }
+
   has_media_metadata_ = false;
   has_media_info_ = false;
 
-  if (media_source)
-    source_type_ = MediaPlayerAndroid::SOURCE_TYPE_MSE;
-#if defined(GOOGLE_TV)
-  if (media_stream_client_) {
-    DCHECK(!media_source);
-    source_type_ = MediaPlayerAndroid::SOURCE_TYPE_STREAM;
-  }
-#endif
-
   media::SetDecryptorReadyCB set_decryptor_ready_cb;
   if (decryptor_) {  // |decryptor_| can be NULL is EME if not enabled.
     set_decryptor_ready_cb = base::Bind(&ProxyDecryptor::SetDecryptorReadyCB,
@@ -222,11 +232,12 @@
   if (source_type_ != MediaPlayerAndroid::SOURCE_TYPE_URL) {
     has_media_info_ = true;
     media_source_delegate_.reset(
-        new MediaSourceDelegate(proxy_, player_id_, media_log_));
+        new MediaSourceDelegate(proxy_, player_id_, media_loop_, media_log_));
     // |media_source_delegate_| is owned, so Unretained() is safe here.
     if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE) {
       media_source_delegate_->InitializeMediaSource(
-          media_source,
+          base::Bind(&WebMediaPlayerAndroid::OnMediaSourceOpened,
+                     base::Unretained(this)),
           base::Bind(&WebMediaPlayerAndroid::OnNeedKey, base::Unretained(this)),
           set_decryptor_ready_cb,
           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
@@ -1113,6 +1124,11 @@
                       destination_url_gurl);
 }
 
+void WebMediaPlayerAndroid::OnMediaSourceOpened(
+    WebKit::WebMediaSourceNew* web_media_source) {
+  client_->mediaSourceOpened(web_media_source);
+}
+
 void WebMediaPlayerAndroid::OnNeedKey(const std::string& session_id,
                                       const std::string& type,
                                       scoped_ptr<uint8[]> init_data,
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 1937536..03f511c 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -77,6 +77,7 @@
       RendererMediaPlayerManager* manager,
       WebMediaPlayerProxyAndroid* proxy,
       StreamTextureFactory* factory,
+      const scoped_refptr<base::MessageLoopProxy>& media_loop,
       media::MediaLog* media_log);
   virtual ~WebMediaPlayerAndroid();
 
@@ -86,10 +87,9 @@
   virtual bool canEnterFullscreen() const;
 
   // Resource loading.
-  virtual void load(const WebKit::WebURL& url, CORSMode cors_mode);
-  virtual void load(const WebKit::WebURL& url,
-                    WebKit::WebMediaSource* media_source,
-                    CORSMode cors_mode);
+  virtual void load(LoadType load_type,
+                    const WebKit::WebURL& url,
+                    CORSMode cors_mode) OVERRIDE;
 
   // Playback controls.
   virtual void play();
@@ -220,6 +220,8 @@
                     const std::vector<uint8>& message,
                     const std::string& destination_url);
 
+  void OnMediaSourceOpened(WebKit::WebMediaSourceNew* web_media_source);
+
   void OnNeedKey(const std::string& type,
                  const std::string& session_id,
                  scoped_ptr<uint8[]> init_data,
@@ -302,6 +304,9 @@
   // Message loop for main renderer thread.
   const scoped_refptr<base::MessageLoopProxy> main_loop_;
 
+  // Message loop for media thread.
+  const scoped_refptr<base::MessageLoopProxy> media_loop_;
+
   // URL of the media file to be fetched.
   GURL url_;
 
diff --git a/content/renderer/media/crypto/content_decryption_module_factory.cc b/content/renderer/media/crypto/content_decryption_module_factory.cc
index 9310101..1e33528 100644
--- a/content/renderer/media/crypto/content_decryption_module_factory.cc
+++ b/content/renderer/media/crypto/content_decryption_module_factory.cc
@@ -24,8 +24,8 @@
 
 #if defined(ENABLE_PEPPER_CDMS)
 // Returns the PepperPluginInstanceImpl associated with the Helper Plugin.
-// If a non-NULL pointer is returned, the caller must call closeHelperPlugin()
-// when the Helper Plugin is no longer needed.
+// If a non-NULL pointer is returned, the caller must call
+// closeHelperPluginSoon() when the Helper Plugin is no longer needed.
 static scoped_refptr<PepperPluginInstanceImpl> CreateHelperPlugin(
     const std::string& plugin_type,
     WebKit::WebMediaPlayerClient* web_media_player_client,
@@ -73,18 +73,17 @@
                              key_message_cb,
                              destroy_plugin_cb);
 
-  if (!decryptor) {
-    ContentDecryptionModuleFactory::DestroyHelperPlugin(
-        web_media_player_client);
-  }
+  if (!decryptor)
+    destroy_plugin_cb.Run();
   // Else the new object will call destroy_plugin_cb to destroy Helper Plugin.
 
   return scoped_ptr<media::MediaKeys>(decryptor.Pass());
 }
 
 void ContentDecryptionModuleFactory::DestroyHelperPlugin(
-    WebKit::WebMediaPlayerClient* web_media_player_client) {
-  web_media_player_client->closeHelperPlugin();
+    WebKit::WebMediaPlayerClient* web_media_player_client,
+    WebKit::WebFrame* web_frame) {
+  web_media_player_client->closeHelperPluginSoon(web_frame);
 }
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
diff --git a/content/renderer/media/crypto/content_decryption_module_factory.h b/content/renderer/media/crypto/content_decryption_module_factory.h
index f891128..cb435cd 100644
--- a/content/renderer/media/crypto/content_decryption_module_factory.h
+++ b/content/renderer/media/crypto/content_decryption_module_factory.h
@@ -40,7 +40,8 @@
 
 #if defined(ENABLE_PEPPER_CDMS)
   static void DestroyHelperPlugin(
-      WebKit::WebMediaPlayerClient* web_media_player_client);
+      WebKit::WebMediaPlayerClient* web_media_player_client,
+      WebKit::WebFrame* web_frame);
 #endif  // defined(ENABLE_PEPPER_CDMS)
 };
 
diff --git a/content/renderer/media/crypto/key_systems_info.cc b/content/renderer/media/crypto/key_systems_info.cc
index 46d0309..fc9f8ba 100644
--- a/content/renderer/media/crypto/key_systems_info.cc
+++ b/content/renderer/media/crypto/key_systems_info.cc
@@ -62,7 +62,7 @@
   // Clear Key.
   { "video/webm", "vorbis,vp8,vp8.0", kClearKeyKeySystem },
   { "audio/webm", "vorbis", kClearKeyKeySystem },
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   { "video/mp4", "avc1,mp4a", kClearKeyKeySystem },
   { "audio/mp4", "mp4a", kClearKeyKeySystem },
 #endif
@@ -70,7 +70,7 @@
   // External Clear Key (used for testing).
   { "video/webm", "vorbis,vp8,vp8.0", kExternalClearKeyKeySystem },
   { "audio/webm", "vorbis", kExternalClearKeyKeySystem },
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   { "video/mp4", "avc1,mp4a", kExternalClearKeyKeySystem },
   { "audio/mp4", "mp4a", kExternalClearKeyKeySystem },
 #endif
@@ -81,14 +81,14 @@
   { "audio/webm", "vorbis", kWidevineKeySystem },
   { "video/webm", "vorbis,vp8,vp8.0", kWidevineBaseKeySystem },
   { "audio/webm", "vorbis", kWidevineBaseKeySystem },
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 #if defined(WIDEVINE_CDM_CENC_SUPPORT_AVAILABLE)
   { "video/mp4", kWidevineVideoMp4Codecs, kWidevineKeySystem },
   { "video/mp4", kWidevineVideoMp4Codecs, kWidevineBaseKeySystem },
   { "audio/mp4", kWidevineAudioMp4Codecs, kWidevineKeySystem },
   { "audio/mp4", kWidevineAudioMp4Codecs, kWidevineBaseKeySystem },
 #endif  // defined(WIDEVINE_CDM_CENC_SUPPORT_AVAILABLE)
-#endif  // defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#endif  // defined(USE_PROPRIETARY_CODECS)
 #endif  // WIDEVINE_CDM_AVAILABLE
 };
 
diff --git a/content/renderer/media/crypto/key_systems_unittest.cc b/content/renderer/media/crypto/key_systems_unittest.cc
index 241cfaf..8199f15 100644
--- a/content/renderer/media/crypto/key_systems_unittest.cc
+++ b/content/renderer/media/crypto/key_systems_unittest.cc
@@ -18,7 +18,7 @@
 
 using WebKit::WebString;
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 #define EXPECT_PROPRIETARY EXPECT_TRUE
 #else
 #define EXPECT_PROPRIETARY EXPECT_FALSE
diff --git a/content/renderer/media/crypto/proxy_decryptor.cc b/content/renderer/media/crypto/proxy_decryptor.cc
index 6f77317..53fae47 100644
--- a/content/renderer/media/crypto/proxy_decryptor.cc
+++ b/content/renderer/media/crypto/proxy_decryptor.cc
@@ -14,7 +14,7 @@
 #if defined(ENABLE_PEPPER_CDMS)
 void ProxyDecryptor::DestroyHelperPlugin() {
   ContentDecryptionModuleFactory::DestroyHelperPlugin(
-      web_media_player_client_);
+      web_media_player_client_, web_frame_);
 }
 #endif  // defined(ENABLE_PEPPER_CDMS)
 
diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc
index 2d19ae0..b60daf4 100644
--- a/content/renderer/media/media_stream_dependency_factory.cc
+++ b/content/renderer/media/media_stream_dependency_factory.cc
@@ -16,6 +16,7 @@
 #include "content/renderer/media/rtc_peer_connection_handler.h"
 #include "content/renderer/media/rtc_video_capturer.h"
 #include "content/renderer/media/rtc_video_decoder_factory.h"
+#include "content/renderer/media/rtc_video_encoder_factory.h"
 #include "content/renderer/media/video_capture_impl_manager.h"
 #include "content/renderer/media/webaudio_capturer_source.h"
 #include "content/renderer/media/webrtc_audio_device_impl.h"
@@ -27,7 +28,7 @@
 #include "content/renderer/p2p/port_allocator.h"
 #include "content/renderer/render_thread_impl.h"
 #include "jingle/glue/thread_wrapper.h"
-#include "media/filters/gpu_video_decoder_factories.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
@@ -488,27 +489,32 @@
     audio_device_ = new WebRtcAudioDeviceImpl();
 
     scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
+    scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
 
     const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
-    if (cmd_line->HasSwitch(switches::kEnableWebRtcHWDecoding)) {
-      scoped_refptr<base::MessageLoopProxy> media_loop_proxy =
-          RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy();
-      scoped_refptr<RendererGpuVideoDecoderFactories> gpu_factories =
-          RenderThreadImpl::current()->GetGpuFactories(media_loop_proxy);
-      if (gpu_factories.get() != NULL)
+    scoped_refptr<base::MessageLoopProxy> media_loop_proxy =
+        RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy();
+    scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories =
+        RenderThreadImpl::current()->GetGpuFactories(media_loop_proxy);
+#if !defined(GOOGLE_TV)
+    if (cmd_line->HasSwitch(switches::kEnableWebRtcHWDecoding))
+      if (gpu_factories)
         decoder_factory.reset(new RTCVideoDecoderFactory(gpu_factories));
-    }
-#if defined(GOOGLE_TV)
+#else
     // PeerConnectionFactory will hold the ownership of this
     // VideoDecoderFactory.
-    decoder_factory.reset(decoder_factory_tv_ = new RTCVideoDecoderFactoryTv);
+    decoder_factory.reset(decoder_factory_tv_ = new RTCVideoDecoderFactoryTv());
 #endif
 
+    if (cmd_line->HasSwitch(switches::kEnableWebRtcHWEncoding))
+      if (gpu_factories)
+        encoder_factory.reset(new RTCVideoEncoderFactory(gpu_factories));
+
     scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory(
         webrtc::CreatePeerConnectionFactory(worker_thread_,
                                             signaling_thread_,
                                             audio_device_.get(),
-                                            NULL,
+                                            encoder_factory.release(),
                                             decoder_factory.release()));
     if (factory.get())
       pc_factory_ = factory;
@@ -611,13 +617,13 @@
       new content::MediaStreamSourceExtraData(webaudio_capturer_source.get());
 
   // Create a LocalAudioSource object which holds audio options.
-  // Use audio constraints where all values are false, i.e., disable
+  // Use audio constraints where all values are true, i.e., enable
   // echo cancellation, automatic gain control, noise suppression and
   // high-pass filter. SetLocalAudioSource() affects core audio parts in
   // third_party/Libjingle.
-  WebAudioConstraints webaudio_audio_constraints_all_false;
+  WebAudioConstraints webaudio_audio_constraints_all_true;
   source_data->SetLocalAudioSource(
-      CreateLocalAudioSource(&webaudio_audio_constraints_all_false).get());
+      CreateLocalAudioSource(&webaudio_audio_constraints_all_true).get());
   source->setExtraData(source_data);
 
   // Replace the default source with WebAudio as source instead.
diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc
index 5edc4cc..6ce995e 100644
--- a/content/renderer/media/media_stream_impl.cc
+++ b/content/renderer/media/media_stream_impl.cc
@@ -75,6 +75,11 @@
       options->video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
       options->video_device_id =
           DesktopMediaID(DesktopMediaID::TYPE_SCREEN, 0).ToString();
+    } else if (video_stream_source == kMediaStreamSourceDesktop) {
+      options->video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
+      options->video_device_id = GetStreamConstraint(
+          user_media_request.videoConstraints(),
+          kMediaStreamSourceId, true);
     }
   }
 }
diff --git a/content/renderer/media/peer_connection_tracker.cc b/content/renderer/media/peer_connection_tracker.cc
index 44f4445..597c645 100644
--- a/content/renderer/media/peer_connection_tracker.cc
+++ b/content/renderer/media/peer_connection_tracker.cc
@@ -161,15 +161,9 @@
     return NULL;
 
   DictionaryValue* dict = new base::DictionaryValue();
-  if (!dict)
-    return NULL;
   dict->SetDouble("timestamp", report.timestamp);
 
   base::ListValue* values = new base::ListValue();
-  if (!values) {
-    delete dict;
-    return NULL;
-  }
   dict->Set("values", values);
 
   for (size_t i = 0; i < report.values.size(); ++i) {
@@ -189,14 +183,10 @@
     return NULL;
 
   result.reset(new base::DictionaryValue());
-  if (!result)
-    return NULL;
-
   // Note:
   // The format must be consistent with what webrtc_internals.js expects.
   // If you change it here, you must change webrtc_internals.js as well.
-  if (stats)
-    result->Set("stats", stats.release());
+  result->Set("stats", stats.release());
   result->SetString("id", report.id);
   result->SetString("type", report.type);
 
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
new file mode 100644
index 0000000..f586497
--- /dev/null
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -0,0 +1,428 @@
+// Copyright 2013 The Chromium Authors. 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/renderer_gpu_video_accelerator_factories.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "base/bind.h"
+#include "content/child/child_thread.h"
+#include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/ipc/command_buffer_proxy.h"
+#include "third_party/skia/include/core/SkPixelRef.h"
+
+namespace content {
+
+RendererGpuVideoAcceleratorFactories::~RendererGpuVideoAcceleratorFactories() {}
+RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories(
+    GpuChannelHost* gpu_channel_host,
+    const scoped_refptr<base::MessageLoopProxy>& message_loop,
+    WebGraphicsContext3DCommandBufferImpl* context)
+    : message_loop_(message_loop),
+      main_message_loop_(base::MessageLoopProxy::current()),
+      gpu_channel_host_(gpu_channel_host),
+      aborted_waiter_(true, false),
+      message_loop_async_waiter_(false, false),
+      render_thread_async_waiter_(false, false) {
+  // |context| is only required to support HW-accelerated decode.
+  if (!context)
+    return;
+
+  if (message_loop_->BelongsToCurrentThread()) {
+    AsyncGetContext(context);
+    message_loop_async_waiter_.Reset();
+    return;
+  }
+  // Wait for the context to be acquired.
+  message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncGetContext,
+                 // Unretained to avoid ref/deref'ing |*this|, which is not yet
+                 // stored in a scoped_refptr.  Safe because the Wait() below
+                 // keeps us alive until this task completes.
+                 base::Unretained(this),
+                 // OK to pass raw because the pointee is only deleted on the
+                 // compositor thread, and only as the result of a PostTask from
+                 // the render thread which can only happen after this function
+                 // returns, so our PostTask will run first.
+                 context));
+  message_loop_async_waiter_.Wait();
+}
+
+RendererGpuVideoAcceleratorFactories::RendererGpuVideoAcceleratorFactories()
+    : aborted_waiter_(true, false),
+      message_loop_async_waiter_(false, false),
+      render_thread_async_waiter_(false, false) {}
+
+void RendererGpuVideoAcceleratorFactories::AsyncGetContext(
+    WebGraphicsContext3DCommandBufferImpl* context) {
+  context_ = context->AsWeakPtr();
+  if (context_.get()) {
+    if (context_->makeContextCurrent()) {
+      // Called once per media player, but is a no-op after the first one in
+      // each renderer.
+      context_->insertEventMarkerEXT("GpuVDAContext3D");
+    }
+  }
+  message_loop_async_waiter_.Signal();
+}
+
+scoped_ptr<media::VideoDecodeAccelerator>
+RendererGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator(
+    media::VideoCodecProfile profile,
+    media::VideoDecodeAccelerator::Client* client) {
+  if (message_loop_->BelongsToCurrentThread()) {
+    AsyncCreateVideoDecodeAccelerator(profile, client);
+    message_loop_async_waiter_.Reset();
+    return vda_.Pass();
+  }
+  // The VDA is returned in the vda_ member variable by the
+  // AsyncCreateVideoDecodeAccelerator() function.
+  message_loop_->PostTask(FROM_HERE,
+                          base::Bind(&RendererGpuVideoAcceleratorFactories::
+                                         AsyncCreateVideoDecodeAccelerator,
+                                     this,
+                                     profile,
+                                     client));
+
+  base::WaitableEvent* objects[] = {&aborted_waiter_,
+                                    &message_loop_async_waiter_};
+  if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) {
+    // If we are aborting and the VDA is created by the
+    // AsyncCreateVideoDecodeAccelerator() function later we need to ensure
+    // that it is destroyed on the same thread.
+    message_loop_->PostTask(FROM_HERE,
+                            base::Bind(&RendererGpuVideoAcceleratorFactories::
+                                           AsyncDestroyVideoDecodeAccelerator,
+                                       this));
+    return scoped_ptr<media::VideoDecodeAccelerator>();
+  }
+  return vda_.Pass();
+}
+
+scoped_ptr<media::VideoEncodeAccelerator>
+RendererGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator(
+    media::VideoEncodeAccelerator::Client* client) {
+  if (message_loop_->BelongsToCurrentThread()) {
+    AsyncCreateVideoEncodeAccelerator(client);
+    message_loop_async_waiter_.Reset();
+    return vea_.Pass();
+  }
+  // The VEA is returned in the vea_ member variable by the
+  // AsyncCreateVideoEncodeAccelerator() function.
+  message_loop_->PostTask(FROM_HERE,
+                          base::Bind(&RendererGpuVideoAcceleratorFactories::
+                                         AsyncCreateVideoEncodeAccelerator,
+                                     this,
+                                     client));
+
+  base::WaitableEvent* objects[] = {&aborted_waiter_,
+                                    &message_loop_async_waiter_};
+  if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) {
+    // If we are aborting and the VDA is created by the
+    // AsyncCreateVideoEncodeAccelerator() function later we need to ensure
+    // that it is destroyed on the same thread.
+    message_loop_->PostTask(FROM_HERE,
+                            base::Bind(&RendererGpuVideoAcceleratorFactories::
+                                           AsyncDestroyVideoEncodeAccelerator,
+                                       this));
+    return scoped_ptr<media::VideoEncodeAccelerator>();
+  }
+  return vea_.Pass();
+}
+
+void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoDecodeAccelerator(
+    media::VideoCodecProfile profile,
+    media::VideoDecodeAccelerator::Client* client) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
+  if (context_.get() && context_->GetCommandBufferProxy()) {
+    vda_ = gpu_channel_host_->CreateVideoDecoder(
+        context_->GetCommandBufferProxy()->GetRouteID(), profile, client);
+  }
+  message_loop_async_waiter_.Signal();
+}
+
+void RendererGpuVideoAcceleratorFactories::AsyncCreateVideoEncodeAccelerator(
+    media::VideoEncodeAccelerator::Client* client) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+
+  vea_ = gpu_channel_host_->CreateVideoEncoder(client).Pass();
+  message_loop_async_waiter_.Signal();
+}
+
+uint32 RendererGpuVideoAcceleratorFactories::CreateTextures(
+    int32 count,
+    const gfx::Size& size,
+    std::vector<uint32>* texture_ids,
+    std::vector<gpu::Mailbox>* texture_mailboxes,
+    uint32 texture_target) {
+  uint32 sync_point = 0;
+
+  if (message_loop_->BelongsToCurrentThread()) {
+    AsyncCreateTextures(count, size, texture_target, &sync_point);
+    texture_ids->swap(created_textures_);
+    texture_mailboxes->swap(created_texture_mailboxes_);
+    message_loop_async_waiter_.Reset();
+    return sync_point;
+  }
+  message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncCreateTextures,
+                 this,
+                 count,
+                 size,
+                 texture_target,
+                 &sync_point));
+
+  base::WaitableEvent* objects[] = {&aborted_waiter_,
+                                    &message_loop_async_waiter_};
+  if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
+    return 0;
+  texture_ids->swap(created_textures_);
+  texture_mailboxes->swap(created_texture_mailboxes_);
+  return sync_point;
+}
+
+void RendererGpuVideoAcceleratorFactories::AsyncCreateTextures(
+    int32 count,
+    const gfx::Size& size,
+    uint32 texture_target,
+    uint32* sync_point) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+  DCHECK(texture_target);
+
+  if (!context_.get()) {
+    message_loop_async_waiter_.Signal();
+    return;
+  }
+  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
+  created_textures_.resize(count);
+  created_texture_mailboxes_.resize(count);
+  gles2->GenTextures(count, &created_textures_[0]);
+  for (int i = 0; i < count; ++i) {
+    gles2->ActiveTexture(GL_TEXTURE0);
+    uint32 texture_id = created_textures_[i];
+    gles2->BindTexture(texture_target, texture_id);
+    gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    if (texture_target == GL_TEXTURE_2D) {
+      gles2->TexImage2D(texture_target,
+                        0,
+                        GL_RGBA,
+                        size.width(),
+                        size.height(),
+                        0,
+                        GL_RGBA,
+                        GL_UNSIGNED_BYTE,
+                        NULL);
+    }
+    gles2->GenMailboxCHROMIUM(created_texture_mailboxes_[i].name);
+    gles2->ProduceTextureCHROMIUM(texture_target,
+                                  created_texture_mailboxes_[i].name);
+  }
+
+  // We need a glFlush here to guarantee the decoder (in the GPU process) can
+  // use the texture ids we return here.  Since textures are expected to be
+  // reused, this should not be unacceptably expensive.
+  gles2->Flush();
+  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
+
+  *sync_point = gles2->InsertSyncPointCHROMIUM();
+  message_loop_async_waiter_.Signal();
+}
+
+void RendererGpuVideoAcceleratorFactories::DeleteTexture(uint32 texture_id) {
+  if (message_loop_->BelongsToCurrentThread()) {
+    AsyncDeleteTexture(texture_id);
+    return;
+  }
+  message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncDeleteTexture,
+                 this,
+                 texture_id));
+}
+
+void RendererGpuVideoAcceleratorFactories::AsyncDeleteTexture(
+    uint32 texture_id) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+  if (!context_.get())
+    return;
+
+  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
+  gles2->DeleteTextures(1, &texture_id);
+  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
+}
+
+void RendererGpuVideoAcceleratorFactories::WaitSyncPoint(uint32 sync_point) {
+  if (message_loop_->BelongsToCurrentThread()) {
+    AsyncWaitSyncPoint(sync_point);
+    message_loop_async_waiter_.Reset();
+    return;
+  }
+
+  message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncWaitSyncPoint,
+                 this,
+                 sync_point));
+  base::WaitableEvent* objects[] = {&aborted_waiter_,
+                                    &message_loop_async_waiter_};
+  base::WaitableEvent::WaitMany(objects, arraysize(objects));
+}
+
+void RendererGpuVideoAcceleratorFactories::AsyncWaitSyncPoint(
+    uint32 sync_point) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+  if (!context_) {
+    message_loop_async_waiter_.Signal();
+    return;
+  }
+
+  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
+  gles2->WaitSyncPointCHROMIUM(sync_point);
+  message_loop_async_waiter_.Signal();
+}
+
+void RendererGpuVideoAcceleratorFactories::ReadPixels(uint32 texture_id,
+                                                      uint32 texture_target,
+                                                      const gfx::Size& size,
+                                                      const SkBitmap& pixels) {
+  // SkBitmaps use the SkPixelRef object to refcount the underlying pixels.
+  // Multiple SkBitmaps can share a SkPixelRef instance. We use this to
+  // ensure that the underlying pixels in the SkBitmap passed in remain valid
+  // until the AsyncReadPixels() call completes.
+  read_pixels_bitmap_.setPixelRef(pixels.pixelRef());
+
+  if (!message_loop_->BelongsToCurrentThread()) {
+    message_loop_->PostTask(
+        FROM_HERE,
+        base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncReadPixels,
+                   this,
+                   texture_id,
+                   texture_target,
+                   size));
+    base::WaitableEvent* objects[] = {&aborted_waiter_,
+                                      &message_loop_async_waiter_};
+    if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
+      return;
+  } else {
+    AsyncReadPixels(texture_id, texture_target, size);
+    message_loop_async_waiter_.Reset();
+  }
+  read_pixels_bitmap_.setPixelRef(NULL);
+}
+
+void RendererGpuVideoAcceleratorFactories::AsyncReadPixels(
+    uint32 texture_id,
+    uint32 texture_target,
+    const gfx::Size& size) {
+  DCHECK(message_loop_->BelongsToCurrentThread());
+  if (!context_.get()) {
+    message_loop_async_waiter_.Signal();
+    return;
+  }
+
+  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
+
+  GLuint tmp_texture;
+  gles2->GenTextures(1, &tmp_texture);
+  gles2->BindTexture(texture_target, tmp_texture);
+  gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  context_->copyTextureCHROMIUM(
+      texture_target, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
+
+  GLuint fb;
+  gles2->GenFramebuffers(1, &fb);
+  gles2->BindFramebuffer(GL_FRAMEBUFFER, fb);
+  gles2->FramebufferTexture2D(
+      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target, tmp_texture, 0);
+  gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
+  gles2->ReadPixels(0,
+                    0,
+                    size.width(),
+                    size.height(),
+                    GL_BGRA_EXT,
+                    GL_UNSIGNED_BYTE,
+                    read_pixels_bitmap_.pixelRef()->pixels());
+  gles2->DeleteFramebuffers(1, &fb);
+  gles2->DeleteTextures(1, &tmp_texture);
+  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
+  message_loop_async_waiter_.Signal();
+}
+
+base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory(
+    size_t size) {
+  if (main_message_loop_->BelongsToCurrentThread()) {
+    return ChildThread::current()->AllocateSharedMemory(size);
+  }
+  main_message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&RendererGpuVideoAcceleratorFactories::AsyncCreateSharedMemory,
+                 this,
+                 size));
+
+  base::WaitableEvent* objects[] = {&aborted_waiter_,
+                                    &render_thread_async_waiter_};
+  if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
+    return NULL;
+  return shared_memory_segment_.release();
+}
+
+void RendererGpuVideoAcceleratorFactories::AsyncCreateSharedMemory(
+    size_t size) {
+  DCHECK_EQ(base::MessageLoop::current(),
+            ChildThread::current()->message_loop());
+
+  shared_memory_segment_.reset(
+      ChildThread::current()->AllocateSharedMemory(size));
+  render_thread_async_waiter_.Signal();
+}
+
+scoped_refptr<base::MessageLoopProxy>
+RendererGpuVideoAcceleratorFactories::GetMessageLoop() {
+  return message_loop_;
+}
+
+void RendererGpuVideoAcceleratorFactories::Abort() { aborted_waiter_.Signal(); }
+
+bool RendererGpuVideoAcceleratorFactories::IsAborted() {
+  return aborted_waiter_.IsSignaled();
+}
+
+scoped_refptr<RendererGpuVideoAcceleratorFactories>
+RendererGpuVideoAcceleratorFactories::Clone() {
+  scoped_refptr<RendererGpuVideoAcceleratorFactories> factories =
+      new RendererGpuVideoAcceleratorFactories();
+  factories->message_loop_ = message_loop_;
+  factories->main_message_loop_ = main_message_loop_;
+  factories->gpu_channel_host_ = gpu_channel_host_;
+  factories->context_ = context_;
+  return factories;
+}
+
+void
+RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoDecodeAccelerator() {
+  // OK to release because Destroy() will delete the VDA instance.
+  if (vda_)
+    vda_.release()->Destroy();
+}
+
+void
+RendererGpuVideoAcceleratorFactories::AsyncDestroyVideoEncodeAccelerator() {
+  // OK to release because Destroy() will delete the VDA instance.
+  if (vea_)
+    vea_.release()->Destroy();
+}
+
+}  // namespace content
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.h b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
new file mode 100644
index 0000000..fcc4ffb
--- /dev/null
+++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
@@ -0,0 +1,149 @@
+// Copyright 2013 The Chromium Authors. 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_RENDERER_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
+#define CONTENT_RENDERER_MEDIA_RENDERER_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/common/content_export.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/size.h"
+
+namespace base {
+class MessageLoopProxy;
+class WaitableEvent;
+}
+
+namespace content {
+class GpuChannelHost;
+class WebGraphicsContext3DCommandBufferImpl;
+
+// Glue code to expose functionality needed by media::GpuVideoAccelerator to
+// RenderViewImpl.  This class is entirely an implementation detail of
+// RenderViewImpl and only has its own header to allow extraction of its
+// implementation from render_view_impl.cc which is already far too large.
+//
+// The public methods of the class can be called from any thread, and are
+// internally trampolined to the appropriate thread.  GPU/GL-related calls go to
+// the constructor-argument loop (the media thread), and shmem-related calls go
+// to the render thread.
+class CONTENT_EXPORT RendererGpuVideoAcceleratorFactories
+    : public media::GpuVideoAcceleratorFactories {
+ public:
+  // Takes a ref on |gpu_channel_host| and tests |context| for loss before each
+  // use.
+  RendererGpuVideoAcceleratorFactories(
+      GpuChannelHost* gpu_channel_host,
+      const scoped_refptr<base::MessageLoopProxy>& message_loop,
+      WebGraphicsContext3DCommandBufferImpl* wgc3dcbi);
+
+  // media::GpuVideoAcceleratorFactories implementation.
+  virtual scoped_ptr<media::VideoDecodeAccelerator>
+      CreateVideoDecodeAccelerator(
+          media::VideoCodecProfile profile,
+          media::VideoDecodeAccelerator::Client* client) OVERRIDE;
+  virtual scoped_ptr<media::VideoEncodeAccelerator>
+      CreateVideoEncodeAccelerator(
+          media::VideoEncodeAccelerator::Client* client) OVERRIDE;
+  // Creates textures and produces them into mailboxes. Returns a sync point to
+  // wait on before using the mailboxes, or 0 on failure.
+  virtual uint32 CreateTextures(int32 count,
+                                const gfx::Size& size,
+                                std::vector<uint32>* texture_ids,
+                                std::vector<gpu::Mailbox>* texture_mailboxes,
+                                uint32 texture_target) OVERRIDE;
+  virtual void DeleteTexture(uint32 texture_id) OVERRIDE;
+  virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE;
+  virtual void ReadPixels(uint32 texture_id,
+                          uint32 texture_target,
+                          const gfx::Size& size,
+                          const SkBitmap& pixels) OVERRIDE;
+  virtual base::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
+  virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE;
+  virtual void Abort() OVERRIDE;
+  virtual bool IsAborted() OVERRIDE;
+  scoped_refptr<RendererGpuVideoAcceleratorFactories> Clone();
+
+ protected:
+  friend class base::RefCountedThreadSafe<RendererGpuVideoAcceleratorFactories>;
+  virtual ~RendererGpuVideoAcceleratorFactories();
+
+ private:
+  RendererGpuVideoAcceleratorFactories();
+
+  // Helper for the constructor to acquire the ContentGLContext on
+  // |message_loop_|.
+  void AsyncGetContext(WebGraphicsContext3DCommandBufferImpl* context);
+
+  // Async versions of the public methods.  They use output parameters instead
+  // of return values and each takes a WaitableEvent* param to signal completion
+  // (except for DeleteTexture, which is fire-and-forget).
+  // AsyncCreateSharedMemory runs on the renderer thread and the rest run on
+  // |message_loop_|.
+  // AsyncCreateVideoDecodeAccelerator returns its output in the |vda_| member.
+  // AsyncCreateVideoEncodeAccelerator returns its output in the |vea_| member.
+  void AsyncCreateVideoDecodeAccelerator(
+      media::VideoCodecProfile profile,
+      media::VideoDecodeAccelerator::Client* client);
+  void AsyncCreateVideoEncodeAccelerator(
+      media::VideoEncodeAccelerator::Client* client);
+  void AsyncCreateTextures(int32 count,
+                           const gfx::Size& size,
+                           uint32 texture_target,
+                           uint32* sync_point);
+  void AsyncDeleteTexture(uint32 texture_id);
+  void AsyncWaitSyncPoint(uint32 sync_point);
+  void AsyncReadPixels(uint32 texture_id,
+                       uint32 texture_target,
+                       const gfx::Size& size);
+  void AsyncCreateSharedMemory(size_t size);
+  void AsyncDestroyVideoDecodeAccelerator();
+  void AsyncDestroyVideoEncodeAccelerator();
+
+  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::MessageLoopProxy> main_message_loop_;
+  scoped_refptr<GpuChannelHost> gpu_channel_host_;
+  base::WeakPtr<WebGraphicsContext3DCommandBufferImpl> context_;
+
+  // This event is signaled if we have been asked to Abort().
+  base::WaitableEvent aborted_waiter_;
+
+  // This event is signaled by asynchronous tasks posted to |message_loop_| to
+  // indicate their completion.
+  // e.g. AsyncCreateVideoDecodeAccelerator()/AsyncCreateTextures() etc.
+  base::WaitableEvent message_loop_async_waiter_;
+
+  // This event is signaled by asynchronous tasks posted to the renderer thread
+  // message loop to indicate their completion. e.g. AsyncCreateSharedMemory.
+  base::WaitableEvent render_thread_async_waiter_;
+
+  // The vda returned by the CreateVideoDecodeAccelerator function.
+  scoped_ptr<media::VideoDecodeAccelerator> vda_;
+
+  // The vea returned by the CreateVideoEncodeAccelerator function.
+  scoped_ptr<media::VideoEncodeAccelerator> vea_;
+
+  // Shared memory segment which is returned by the CreateSharedMemory()
+  // function.
+  scoped_ptr<base::SharedMemory> shared_memory_segment_;
+
+  // Bitmap returned by ReadPixels().
+  SkBitmap read_pixels_bitmap_;
+
+  // Textures returned by the CreateTexture() function.
+  std::vector<uint32> created_textures_;
+  std::vector<gpu::Mailbox> created_texture_mailboxes_;
+
+  DISALLOW_COPY_AND_ASSIGN(RendererGpuVideoAcceleratorFactories);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_RENDERER_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
diff --git a/content/renderer/media/renderer_gpu_video_decoder_factories.cc b/content/renderer/media/renderer_gpu_video_decoder_factories.cc
deleted file mode 100644
index d33e590..0000000
--- a/content/renderer/media/renderer_gpu_video_decoder_factories.cc
+++ /dev/null
@@ -1,338 +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/renderer/media/renderer_gpu_video_decoder_factories.h"
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include "base/bind.h"
-#include "content/child/child_thread.h"
-#include "content/common/gpu/client/gpu_channel_host.h"
-#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/ipc/command_buffer_proxy.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-
-namespace content {
-
-RendererGpuVideoDecoderFactories::~RendererGpuVideoDecoderFactories() {}
-RendererGpuVideoDecoderFactories::RendererGpuVideoDecoderFactories(
-    GpuChannelHost* gpu_channel_host,
-    const scoped_refptr<base::MessageLoopProxy>& message_loop,
-    WebGraphicsContext3DCommandBufferImpl* context)
-    : message_loop_(message_loop),
-      main_message_loop_(base::MessageLoopProxy::current()),
-      gpu_channel_host_(gpu_channel_host),
-      aborted_waiter_(true, false),
-      message_loop_async_waiter_(false, false),
-      render_thread_async_waiter_(false, false) {
-  if (message_loop_->BelongsToCurrentThread()) {
-    AsyncGetContext(context);
-    message_loop_async_waiter_.Reset();
-    return;
-  }
-  // Wait for the context to be acquired.
-  message_loop_->PostTask(FROM_HERE, base::Bind(
-      &RendererGpuVideoDecoderFactories::AsyncGetContext,
-      // Unretained to avoid ref/deref'ing |*this|, which is not yet stored in a
-      // scoped_refptr.  Safe because the Wait() below keeps us alive until this
-      // task completes.
-      base::Unretained(this),
-      // OK to pass raw because the pointee is only deleted on the compositor
-      // thread, and only as the result of a PostTask from the render thread
-      // which can only happen after this function returns, so our PostTask will
-      // run first.
-      context));
-  message_loop_async_waiter_.Wait();
-}
-
-RendererGpuVideoDecoderFactories::RendererGpuVideoDecoderFactories()
-    : aborted_waiter_(true, false),
-      message_loop_async_waiter_(false, false),
-      render_thread_async_waiter_(false, false) {}
-
-void RendererGpuVideoDecoderFactories::AsyncGetContext(
-    WebGraphicsContext3DCommandBufferImpl* context) {
-  context_ = context->AsWeakPtr();
-  if (context_.get()) {
-    if (context_->makeContextCurrent()) {
-      // Called once per media player, but is a no-op after the first one in
-      // each renderer.
-      context_->insertEventMarkerEXT("GpuVDAContext3D");
-    }
-  }
-  message_loop_async_waiter_.Signal();
-}
-
-media::VideoDecodeAccelerator*
-RendererGpuVideoDecoderFactories::CreateVideoDecodeAccelerator(
-    media::VideoCodecProfile profile,
-    media::VideoDecodeAccelerator::Client* client) {
-  if (message_loop_->BelongsToCurrentThread()) {
-    AsyncCreateVideoDecodeAccelerator(profile, client);
-    message_loop_async_waiter_.Reset();
-    return vda_.release();
-  }
-  // The VDA is returned in the vda_ member variable by the
-  // AsyncCreateVideoDecodeAccelerator() function.
-  message_loop_->PostTask(FROM_HERE, base::Bind(
-      &RendererGpuVideoDecoderFactories::AsyncCreateVideoDecodeAccelerator,
-      this, profile, client));
-
-  base::WaitableEvent* objects[] = {&aborted_waiter_,
-                                    &message_loop_async_waiter_};
-  if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0) {
-    // If we are aborting and the VDA is created by the
-    // AsyncCreateVideoDecodeAccelerator() function later we need to ensure
-    // that it is destroyed on the same thread.
-    message_loop_->PostTask(FROM_HERE, base::Bind(
-        &RendererGpuVideoDecoderFactories::AsyncDestroyVideoDecodeAccelerator,
-        this));
-    return NULL;
-  }
-  return vda_.release();
-}
-
-void RendererGpuVideoDecoderFactories::AsyncCreateVideoDecodeAccelerator(
-      media::VideoCodecProfile profile,
-      media::VideoDecodeAccelerator::Client* client) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (context_.get() && context_->GetCommandBufferProxy()) {
-    vda_ = gpu_channel_host_->CreateVideoDecoder(
-        context_->GetCommandBufferProxy()->GetRouteID(), profile, client);
-  }
-  message_loop_async_waiter_.Signal();
-}
-
-uint32 RendererGpuVideoDecoderFactories::CreateTextures(
-    int32 count, const gfx::Size& size,
-    std::vector<uint32>* texture_ids,
-    std::vector<gpu::Mailbox>* texture_mailboxes,
-    uint32 texture_target) {
-  uint32 sync_point = 0;
-
-  if (message_loop_->BelongsToCurrentThread()) {
-    AsyncCreateTextures(count, size, texture_target, &sync_point);
-    texture_ids->swap(created_textures_);
-    texture_mailboxes->swap(created_texture_mailboxes_);
-    message_loop_async_waiter_.Reset();
-    return sync_point;
-  }
-  message_loop_->PostTask(FROM_HERE, base::Bind(
-      &RendererGpuVideoDecoderFactories::AsyncCreateTextures, this,
-      count, size, texture_target, &sync_point));
-
-  base::WaitableEvent* objects[] = {&aborted_waiter_,
-                                    &message_loop_async_waiter_};
-  if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
-    return 0;
-  texture_ids->swap(created_textures_);
-  texture_mailboxes->swap(created_texture_mailboxes_);
-  return sync_point;
-}
-
-void RendererGpuVideoDecoderFactories::AsyncCreateTextures(
-    int32 count, const gfx::Size& size, uint32 texture_target,
-    uint32* sync_point) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  DCHECK(texture_target);
-
-  if (!context_.get()) {
-    message_loop_async_waiter_.Signal();
-    return;
-  }
-  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
-  created_textures_.resize(count);
-  created_texture_mailboxes_.resize(count);
-  gles2->GenTextures(count, &created_textures_[0]);
-  for (int i = 0; i < count; ++i) {
-    gles2->ActiveTexture(GL_TEXTURE0);
-    uint32 texture_id = created_textures_[i];
-    gles2->BindTexture(texture_target, texture_id);
-    gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-    if (texture_target == GL_TEXTURE_2D) {
-      gles2->TexImage2D(texture_target, 0, GL_RGBA, size.width(), size.height(),
-                        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-    }
-    gles2->GenMailboxCHROMIUM(created_texture_mailboxes_[i].name);
-    gles2->ProduceTextureCHROMIUM(texture_target,
-                                  created_texture_mailboxes_[i].name);
-  }
-
-  // We need a glFlush here to guarantee the decoder (in the GPU process) can
-  // use the texture ids we return here.  Since textures are expected to be
-  // reused, this should not be unacceptably expensive.
-  gles2->Flush();
-  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
-
-  *sync_point = gles2->InsertSyncPointCHROMIUM();
-  message_loop_async_waiter_.Signal();
-}
-
-void RendererGpuVideoDecoderFactories::DeleteTexture(uint32 texture_id) {
-  if (message_loop_->BelongsToCurrentThread()) {
-    AsyncDeleteTexture(texture_id);
-    return;
-  }
-  message_loop_->PostTask(FROM_HERE, base::Bind(
-      &RendererGpuVideoDecoderFactories::AsyncDeleteTexture, this, texture_id));
-}
-
-void RendererGpuVideoDecoderFactories::AsyncDeleteTexture(uint32 texture_id) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  if (!context_.get())
-    return;
-
-  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
-  gles2->DeleteTextures(1, &texture_id);
-  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
-}
-
-void RendererGpuVideoDecoderFactories::WaitSyncPoint(uint32 sync_point) {
-  if (message_loop_->BelongsToCurrentThread()) {
-    AsyncWaitSyncPoint(sync_point);
-    message_loop_async_waiter_.Reset();
-    return;
-  }
-
-  message_loop_->PostTask(FROM_HERE, base::Bind(
-      &RendererGpuVideoDecoderFactories::AsyncWaitSyncPoint,
-      this,
-      sync_point));
-  base::WaitableEvent* objects[] = {&aborted_waiter_,
-                                    &message_loop_async_waiter_};
-  base::WaitableEvent::WaitMany(objects, arraysize(objects));
-}
-
-void RendererGpuVideoDecoderFactories::AsyncWaitSyncPoint(uint32 sync_point) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  if (!context_) {
-    message_loop_async_waiter_.Signal();
-    return;
-  }
-
-  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
-  gles2->WaitSyncPointCHROMIUM(sync_point);
-  message_loop_async_waiter_.Signal();
-}
-
-void RendererGpuVideoDecoderFactories::ReadPixels(
-    uint32 texture_id, uint32 texture_target, const gfx::Size& size,
-    const SkBitmap& pixels) {
-  // SkBitmaps use the SkPixelRef object to refcount the underlying pixels.
-  // Multiple SkBitmaps can share a SkPixelRef instance. We use this to
-  // ensure that the underlying pixels in the SkBitmap passed in remain valid
-  // until the AsyncReadPixels() call completes.
-  read_pixels_bitmap_.setPixelRef(pixels.pixelRef());
-
-  if (!message_loop_->BelongsToCurrentThread()) {
-    message_loop_->PostTask(FROM_HERE, base::Bind(
-        &RendererGpuVideoDecoderFactories::AsyncReadPixels, this,
-        texture_id, texture_target, size));
-    base::WaitableEvent* objects[] = {&aborted_waiter_,
-                                      &message_loop_async_waiter_};
-    if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
-      return;
-  } else {
-    AsyncReadPixels(texture_id, texture_target, size);
-    message_loop_async_waiter_.Reset();
-  }
-  read_pixels_bitmap_.setPixelRef(NULL);
-}
-
-void RendererGpuVideoDecoderFactories::AsyncReadPixels(
-    uint32 texture_id, uint32 texture_target, const gfx::Size& size) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  if (!context_.get()) {
-    message_loop_async_waiter_.Signal();
-    return;
-  }
-
-  gpu::gles2::GLES2Implementation* gles2 = context_->GetImplementation();
-
-  GLuint tmp_texture;
-  gles2->GenTextures(1, &tmp_texture);
-  gles2->BindTexture(texture_target, tmp_texture);
-  gles2->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  gles2->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-  gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-  gles2->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-  context_->copyTextureCHROMIUM(
-      texture_target, texture_id, tmp_texture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
-
-  GLuint fb;
-  gles2->GenFramebuffers(1, &fb);
-  gles2->BindFramebuffer(GL_FRAMEBUFFER, fb);
-  gles2->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                              texture_target, tmp_texture, 0);
-  gles2->PixelStorei(GL_PACK_ALIGNMENT, 4);
-  gles2->ReadPixels(0, 0, size.width(), size.height(), GL_BGRA_EXT,
-      GL_UNSIGNED_BYTE, read_pixels_bitmap_.pixelRef()->pixels());
-  gles2->DeleteFramebuffers(1, &fb);
-  gles2->DeleteTextures(1, &tmp_texture);
-  DCHECK_EQ(gles2->GetError(), static_cast<GLenum>(GL_NO_ERROR));
-  message_loop_async_waiter_.Signal();
-}
-
-base::SharedMemory* RendererGpuVideoDecoderFactories::CreateSharedMemory(
-    size_t size) {
-  if (main_message_loop_->BelongsToCurrentThread()) {
-    return ChildThread::current()->AllocateSharedMemory(size);
-  }
-  main_message_loop_->PostTask(FROM_HERE, base::Bind(
-      &RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory, this,
-      size));
-
-  base::WaitableEvent* objects[] = {&aborted_waiter_,
-                                    &render_thread_async_waiter_};
-  if (base::WaitableEvent::WaitMany(objects, arraysize(objects)) == 0)
-    return NULL;
-  return shared_memory_segment_.release();
-}
-
-void RendererGpuVideoDecoderFactories::AsyncCreateSharedMemory(size_t size) {
-  DCHECK_EQ(base::MessageLoop::current(),
-            ChildThread::current()->message_loop());
-
-  shared_memory_segment_.reset(
-      ChildThread::current()->AllocateSharedMemory(size));
-  render_thread_async_waiter_.Signal();
-}
-
-scoped_refptr<base::MessageLoopProxy>
-RendererGpuVideoDecoderFactories::GetMessageLoop() {
-  return message_loop_;
-}
-
-void RendererGpuVideoDecoderFactories::Abort() {
-  aborted_waiter_.Signal();
-}
-
-bool RendererGpuVideoDecoderFactories::IsAborted() {
-  return aborted_waiter_.IsSignaled();
-}
-
-scoped_refptr<media::GpuVideoDecoderFactories>
-RendererGpuVideoDecoderFactories::Clone() {
-  scoped_refptr<RendererGpuVideoDecoderFactories> factories =
-      new RendererGpuVideoDecoderFactories();
-  factories->message_loop_ = message_loop_;
-  factories->main_message_loop_ = main_message_loop_;
-  factories->gpu_channel_host_ = gpu_channel_host_;
-  factories->context_ = context_;
-  return factories;
-}
-
-void RendererGpuVideoDecoderFactories::AsyncDestroyVideoDecodeAccelerator() {
-  // OK to release because Destroy() will delete the VDA instance.
-  if (vda_)
-    vda_.release()->Destroy();
-}
-
-}  // namespace content
diff --git a/content/renderer/media/renderer_gpu_video_decoder_factories.h b/content/renderer/media/renderer_gpu_video_decoder_factories.h
deleted file mode 100644
index 32f9bcd..0000000
--- a/content/renderer/media/renderer_gpu_video_decoder_factories.h
+++ /dev/null
@@ -1,138 +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_MEDIA_RENDERER_GPU_VIDEO_DECODER_FACTORIES_H_
-#define CONTENT_RENDERER_MEDIA_RENDERER_GPU_VIDEO_DECODER_FACTORIES_H_
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/synchronization/waitable_event.h"
-#include "content/common/content_export.h"
-#include "media/filters/gpu_video_decoder_factories.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/size.h"
-
-namespace base {
-class MessageLoopProxy;
-class WaitableEvent;
-}
-
-namespace content {
-class GpuChannelHost;
-class WebGraphicsContext3DCommandBufferImpl;
-
-// Glue code to expose functionality needed by media::GpuVideoDecoder to
-// RenderViewImpl.  This class is entirely an implementation detail of
-// RenderViewImpl and only has its own header to allow extraction of its
-// implementation from render_view_impl.cc which is already far too large.
-//
-// The public methods of the class can be called from any thread, and are
-// internally trampolined to the appropriate thread.  GPU/GL-related calls go to
-// the constructor-argument loop (the media thread), and shmem-related calls go
-// to the render thread.
-class CONTENT_EXPORT RendererGpuVideoDecoderFactories
-    : public media::GpuVideoDecoderFactories {
- public:
-  // Takes a ref on |gpu_channel_host| and tests |context| for loss before each
-  // use.
-  RendererGpuVideoDecoderFactories(
-      GpuChannelHost* gpu_channel_host,
-      const scoped_refptr<base::MessageLoopProxy>& message_loop,
-      WebGraphicsContext3DCommandBufferImpl* wgc3dcbi);
-
-  // media::GpuVideoDecoderFactories implementation.
-  virtual media::VideoDecodeAccelerator* CreateVideoDecodeAccelerator(
-      media::VideoCodecProfile profile,
-      media::VideoDecodeAccelerator::Client* client) OVERRIDE;
-  // Creates textures and produces them into mailboxes. Returns a sync point to
-  // wait on before using the mailboxes, or 0 on failure.
-  virtual uint32 CreateTextures(
-      int32 count, const gfx::Size& size,
-      std::vector<uint32>* texture_ids,
-      std::vector<gpu::Mailbox>* texture_mailboxes,
-      uint32 texture_target) OVERRIDE;
-  virtual void DeleteTexture(uint32 texture_id) OVERRIDE;
-  virtual void WaitSyncPoint(uint32 sync_point) OVERRIDE;
-  virtual void ReadPixels(uint32 texture_id,
-                          uint32 texture_target,
-                          const gfx::Size& size,
-                          const SkBitmap& pixels) OVERRIDE;
-  virtual base::SharedMemory* CreateSharedMemory(size_t size) OVERRIDE;
-  virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() OVERRIDE;
-  virtual void Abort() OVERRIDE;
-  virtual bool IsAborted() OVERRIDE;
-
-  // Makes a copy of |this|.
-  scoped_refptr<media::GpuVideoDecoderFactories> Clone();
-
- protected:
-  friend class base::RefCountedThreadSafe<RendererGpuVideoDecoderFactories>;
-  virtual ~RendererGpuVideoDecoderFactories();
-
- private:
-  RendererGpuVideoDecoderFactories();
-
-  // Helper for the constructor to acquire the ContentGLContext on
-  // |message_loop_|.
-  void AsyncGetContext(WebGraphicsContext3DCommandBufferImpl* context);
-
-  // Async versions of the public methods.  They use output parameters instead
-  // of return values and each takes a WaitableEvent* param to signal completion
-  // (except for DeleteTexture, which is fire-and-forget).
-  // AsyncCreateSharedMemory runs on the renderer thread and the rest run on
-  // |message_loop_|.
-  // The AsyncCreateVideoDecodeAccelerator returns its output in the vda_
-  // member.
-  void AsyncCreateVideoDecodeAccelerator(
-      media::VideoCodecProfile profile,
-      media::VideoDecodeAccelerator::Client* client);
-  void AsyncCreateTextures(int32 count, const gfx::Size& size,
-                           uint32 texture_target, uint32* sync_point);
-  void AsyncDeleteTexture(uint32 texture_id);
-  void AsyncWaitSyncPoint(uint32 sync_point);
-  void AsyncReadPixels(uint32 texture_id, uint32 texture_target,
-                       const gfx::Size& size);
-  void AsyncCreateSharedMemory(size_t size);
-  void AsyncDestroyVideoDecodeAccelerator();
-
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
-  scoped_refptr<base::MessageLoopProxy> main_message_loop_;
-  scoped_refptr<GpuChannelHost> gpu_channel_host_;
-  base::WeakPtr<WebGraphicsContext3DCommandBufferImpl> context_;
-
-  // This event is signaled if we have been asked to Abort().
-  base::WaitableEvent aborted_waiter_;
-
-  // This event is signaled by asynchronous tasks posted to |message_loop_| to
-  // indicate their completion.
-  // e.g. AsyncCreateVideoDecodeAccelerator()/AsyncCreateTextures() etc.
-  base::WaitableEvent message_loop_async_waiter_;
-
-  // This event is signaled by asynchronous tasks posted to the renderer thread
-  // message loop to indicate their completion. e.g. AsyncCreateSharedMemory.
-  base::WaitableEvent render_thread_async_waiter_;
-
-  // The vda returned by the CreateVideoAcclelerator function.
-  scoped_ptr<media::VideoDecodeAccelerator> vda_;
-
-  // Shared memory segment which is returned by the CreateSharedMemory()
-  // function.
-  scoped_ptr<base::SharedMemory> shared_memory_segment_;
-
-  // Bitmap returned by ReadPixels().
-  SkBitmap read_pixels_bitmap_;
-
-  // Textures returned by the CreateTexture() function.
-  std::vector<uint32> created_textures_;
-  std::vector<gpu::Mailbox> created_texture_mailboxes_;
-
-  DISALLOW_COPY_AND_ASSIGN(RendererGpuVideoDecoderFactories);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_RENDERER_GPU_VIDEO_DECODER_FACTORIES_H_
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index 12904f1..c048b6b 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -13,7 +13,7 @@
 #include "base/task_runner_util.h"
 #include "content/child/child_thread.h"
 #include "media/base/bind_to_loop.h"
-#include "media/filters/gpu_video_decoder_factories.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 #include "third_party/webrtc/system_wrappers/interface/ref_count.h"
 
 namespace content {
@@ -69,7 +69,7 @@
 RTCVideoDecoder::BufferData::~BufferData() {}
 
 RTCVideoDecoder::RTCVideoDecoder(
-    const scoped_refptr<media::GpuVideoDecoderFactories>& factories)
+    const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories)
     : weak_factory_(this),
       weak_this_(weak_factory_.GetWeakPtr()),
       factories_(factories),
@@ -122,7 +122,7 @@
 
 scoped_ptr<RTCVideoDecoder> RTCVideoDecoder::Create(
     webrtc::VideoCodecType type,
-    const scoped_refptr<media::GpuVideoDecoderFactories>& factories) {
+    const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories) {
   scoped_ptr<RTCVideoDecoder> decoder;
   // Convert WebRTC codec type to media codec profile.
   media::VideoCodecProfile profile;
@@ -136,8 +136,8 @@
   }
 
   decoder.reset(new RTCVideoDecoder(factories));
-  decoder->vda_
-      .reset(factories->CreateVideoDecodeAccelerator(profile, decoder.get()));
+  decoder->vda_ =
+      factories->CreateVideoDecodeAccelerator(profile, decoder.get()).Pass();
   // vda can be NULL if VP8 is not supported.
   if (decoder->vda_ != NULL) {
     decoder->state_ = INITIALIZED;
@@ -195,8 +195,17 @@
     // Return an error to request a key frame.
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
-  if (inputImage._frameType == webrtc::kKeyFrame)
+  if (inputImage._frameType == webrtc::kKeyFrame) {
+    DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x"
+             << inputImage._encodedHeight;
     frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight);
+  } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_,
+                                     reset_bitstream_buffer_id_)) {
+    // TODO(wuchengli): VDA should handle it. Remove this when
+    // http://crosbug.com/p/21913 is fixed.
+    DVLOG(1) << "The first frame should be a key frame. Drop this.";
+    return WEBRTC_VIDEO_CODEC_ERROR;
+  }
 
   // Create buffer metadata.
   BufferData buffer_data(next_bitstream_buffer_id_,
@@ -397,7 +406,7 @@
       visible_rect,
       natural_size,
       timestamp_ms,
-      base::Bind(&media::GpuVideoDecoderFactories::ReadPixels,
+      base::Bind(&media::GpuVideoAcceleratorFactories::ReadPixels,
                  factories_,
                  pb.texture_id(),
                  decoder_texture_target_,
@@ -526,6 +535,12 @@
   return diff < ID_HALF;
 }
 
+bool RTCVideoDecoder::IsFirstBufferAfterReset(int32 id_buffer, int32 id_reset) {
+  if (id_reset == ID_INVALID)
+    return id_buffer == 0;
+  return id_buffer == ((id_reset + 1) & ID_LAST);
+}
+
 void RTCVideoDecoder::SaveToDecodeBuffers_Locked(
     const webrtc::EncodedImage& input_image,
     scoped_ptr<SHMBuffer> shm_buffer,
diff --git a/content/renderer/media/rtc_video_decoder.h b/content/renderer/media/rtc_video_decoder.h
index 11e5852..13adf37 100644
--- a/content/renderer/media/rtc_video_decoder.h
+++ b/content/renderer/media/rtc_video_decoder.h
@@ -30,7 +30,7 @@
 
 namespace media {
 class DecoderBuffer;
-class GpuVideoDecoderFactories;
+class GpuVideoAcceleratorFactories;
 }
 
 namespace content {
@@ -52,7 +52,7 @@
   // run on the message loop of |factories|.
   static scoped_ptr<RTCVideoDecoder> Create(
       webrtc::VideoCodecType type,
-      const scoped_refptr<media::GpuVideoDecoderFactories>& factories);
+      const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories);
 
   // webrtc::VideoDecoder implementation.
   // Called on WebRTC DecodingThread.
@@ -110,10 +110,11 @@
   };
 
   FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, IsBufferAfterReset);
+  FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, IsFirstBufferAfterReset);
 
   // The meessage loop of |factories| will be saved to |vda_loop_proxy_|.
   RTCVideoDecoder(
-      const scoped_refptr<media::GpuVideoDecoderFactories>& factories);
+      const scoped_refptr<media::GpuVideoAcceleratorFactories>& factories);
 
   void Initialize(base::WaitableEvent* waiter);
 
@@ -126,6 +127,10 @@
   // This handles the wraparound.
   bool IsBufferAfterReset(int32 id_buffer, int32 id_reset);
 
+  // Returns true if bitstream buffer |id_buffer| is the first buffer after
+  // |id_reset|.
+  bool IsFirstBufferAfterReset(int32 id_buffer, int32 id_reset);
+
   // Saves a WebRTC buffer in |decode_buffers_| for decode.
   void SaveToDecodeBuffers_Locked(const webrtc::EncodedImage& input_image,
                                   scoped_ptr<SHMBuffer> shm_buffer,
@@ -197,7 +202,7 @@
   base::WeakPtrFactory<RTCVideoDecoder> weak_factory_;
   base::WeakPtr<RTCVideoDecoder> weak_this_;
 
-  scoped_refptr<media::GpuVideoDecoderFactories> factories_;
+  scoped_refptr<media::GpuVideoAcceleratorFactories> factories_;
 
   // The message loop to run callbacks on. This is from |factories_|.
   scoped_refptr<base::MessageLoopProxy> vda_loop_proxy_;
diff --git a/content/renderer/media/rtc_video_decoder_factory.cc b/content/renderer/media/rtc_video_decoder_factory.cc
index e621735..57b6a58 100644
--- a/content/renderer/media/rtc_video_decoder_factory.cc
+++ b/content/renderer/media/rtc_video_decoder_factory.cc
@@ -6,14 +6,13 @@
 
 #include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "content/renderer/media/renderer_gpu_video_decoder_factories.h"
+#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
 #include "content/renderer/media/rtc_video_decoder.h"
-#include "media/filters/gpu_video_decoder_factories.h"
 
 namespace content {
 
 RTCVideoDecoderFactory::RTCVideoDecoderFactory(
-    const scoped_refptr<RendererGpuVideoDecoderFactories>& gpu_factories)
+    const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
     : gpu_factories_(gpu_factories) {
   DVLOG(2) << "RTCVideoDecoderFactory";
 }
@@ -25,7 +24,7 @@
 webrtc::VideoDecoder* RTCVideoDecoderFactory::CreateVideoDecoder(
     webrtc::VideoCodecType type) {
   DVLOG(2) << "CreateVideoDecoder";
-  // RendererGpuVideoDecoderFactories is not thread safe. It cannot be shared
+  // GpuVideoAcceleratorFactories is not thread safe. It cannot be shared
   // by different decoders. This method runs on Chrome_libJingle_WorkerThread
   // and the child thread is blocked while this runs. We cannot create new gpu
   // factories here. Clone one instead.
diff --git a/content/renderer/media/rtc_video_decoder_factory.h b/content/renderer/media/rtc_video_decoder_factory.h
index 1455d7b..f7a42a3 100644
--- a/content/renderer/media/rtc_video_decoder_factory.h
+++ b/content/renderer/media/rtc_video_decoder_factory.h
@@ -11,23 +11,19 @@
 #include "third_party/libjingle/source/talk/media/webrtc/webrtcvideodecoderfactory.h"
 #include "third_party/webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
 
-namespace media {
-class GpuVideoDecoderFactories;
-}
-
 namespace webrtc {
 class VideoDecoder;
 }
 
 namespace content {
-class RendererGpuVideoDecoderFactories;
+class RendererGpuVideoAcceleratorFactories;
 
 // TODO(wuchengli): add unittest.
 class CONTENT_EXPORT RTCVideoDecoderFactory
     : NON_EXPORTED_BASE(public cricket::WebRtcVideoDecoderFactory) {
  public:
   explicit RTCVideoDecoderFactory(
-      const scoped_refptr<RendererGpuVideoDecoderFactories>& gpu_factories);
+      const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
   virtual ~RTCVideoDecoderFactory();
 
   // Runs on Chrome_libJingle_WorkerThread. The child thread is blocked while
@@ -40,7 +36,7 @@
   virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
 
  private:
-  scoped_refptr<RendererGpuVideoDecoderFactories> gpu_factories_;
+  scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
 
   DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderFactory);
 };
diff --git a/content/renderer/media/rtc_video_decoder_unittest.cc b/content/renderer/media/rtc_video_decoder_unittest.cc
index 2ffeb3e..ba27a57 100644
--- a/content/renderer/media/rtc_video_decoder_unittest.cc
+++ b/content/renderer/media/rtc_video_decoder_unittest.cc
@@ -8,7 +8,7 @@
 #include "base/threading/thread.h"
 #include "content/renderer/media/rtc_video_decoder.h"
 #include "media/base/gmock_callback_support.h"
-#include "media/filters/mock_gpu_video_decoder_factories.h"
+#include "media/filters/mock_gpu_video_accelerator_factories.h"
 #include "media/video/mock_video_decode_accelerator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -25,7 +25,7 @@
                             webrtc::DecodedImageCallback {
  public:
   RTCVideoDecoderTest()
-      : mock_gpu_factories_(new media::MockGpuVideoDecoderFactories),
+      : mock_gpu_factories_(new media::MockGpuVideoAcceleratorFactories),
         vda_thread_("vda_thread"),
         idle_waiter_(false, false) {
     memset(&codec_, 0, sizeof(codec_));
@@ -37,11 +37,11 @@
     mock_vda_ = new media::MockVideoDecodeAccelerator;
     EXPECT_CALL(*mock_gpu_factories_, GetMessageLoop())
         .WillRepeatedly(Return(vda_loop_proxy_));
-    EXPECT_CALL(*mock_gpu_factories_, CreateVideoDecodeAccelerator(_, _))
+    EXPECT_CALL(*mock_gpu_factories_, DoCreateVideoDecodeAccelerator(_, _))
         .WillRepeatedly(
              Return(static_cast<media::VideoDecodeAccelerator*>(NULL)));
     EXPECT_CALL(*mock_gpu_factories_,
-                CreateVideoDecodeAccelerator(media::VP8PROFILE_MAIN, _))
+                DoCreateVideoDecodeAccelerator(media::VP8PROFILE_MAIN, _))
         .WillRepeatedly(Return(mock_vda_));
     EXPECT_CALL(*mock_gpu_factories_, Abort()).WillRepeatedly(Return());
     EXPECT_CALL(*mock_gpu_factories_, CreateSharedMemory(_))
@@ -94,7 +94,7 @@
   }
 
  protected:
-  scoped_refptr<media::MockGpuVideoDecoderFactories> mock_gpu_factories_;
+  scoped_refptr<media::MockGpuVideoAcceleratorFactories> mock_gpu_factories_;
   media::MockVideoDecodeAccelerator* mock_vda_;
   scoped_ptr<RTCVideoDecoder> rtc_decoder_;
   webrtc::VideoCodec codec_;
@@ -192,4 +192,28 @@
                                                 RTCVideoDecoder::ID_LAST));
 }
 
+TEST_F(RTCVideoDecoderTest, IsFirstBufferAfterReset) {
+  EXPECT_TRUE(
+      rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_INVALID));
+  EXPECT_FALSE(
+      rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_INVALID));
+  EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(0, 0));
+  EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset(1, 0));
+  EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(2, 0));
+
+  EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_HALF,
+                                                     RTCVideoDecoder::ID_HALF));
+  EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset(
+      RTCVideoDecoder::ID_HALF + 1, RTCVideoDecoder::ID_HALF));
+  EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(
+      RTCVideoDecoder::ID_HALF + 2, RTCVideoDecoder::ID_HALF));
+
+  EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_LAST,
+                                                     RTCVideoDecoder::ID_LAST));
+  EXPECT_TRUE(
+      rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_LAST));
+  EXPECT_FALSE(
+      rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_LAST));
+}
+
 }  // content
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc
new file mode 100644
index 0000000..416317d
--- /dev/null
+++ b/content/renderer/media/rtc_video_encoder.cc
@@ -0,0 +1,658 @@
+// Copyright 2013 The Chromium Authors. 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/rtc_video_encoder.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/synchronization/waitable_event.h"
+#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
+#include "media/base/bitstream_buffer.h"
+#include "media/base/video_frame.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/video/video_encode_accelerator.h"
+
+#define NOTIFY_ERROR(x)                             \
+  do {                                              \
+    DLOG(ERROR) << "calling NotifyError(): " << x;  \
+    NotifyError(x);                                 \
+  } while (0)
+
+namespace content {
+
+// This private class of RTCVideoEncoder does the actual work of communicating
+// with a media::VideoEncodeAccelerator for handling video encoding.  It can
+// be created on any thread, but should subsequently be posted to (and Destroy()
+// called on) a single thread.  Callbacks to RTCVideoEncoder are posted to the
+// thread on which the instance was constructed.
+//
+// This class separates state related to the thread that RTCVideoEncoder
+// operates on (presently the libjingle worker thread) from the thread that
+// |gpu_factories_| provides for accelerator operations (presently the media
+// thread).  The RTCVideoEncoder class can be deleted directly by WebRTC, while
+// RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA.
+class RTCVideoEncoder::Impl
+    : public media::VideoEncodeAccelerator::Client,
+      public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
+ public:
+  Impl(
+      const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
+      const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
+
+  // Create the VEA and call Initialize() on it.  Called once per instantiation,
+  // and then the instance is bound forevermore to whichever thread made the
+  // call.
+  // RTCVideoEncoder expects to be able to call this function synchronously from
+  // its own thread, hence the |async_waiter| and |async_retval| arguments.
+  void CreateAndInitializeVEA(const gfx::Size& input_visible_size,
+                              uint32 bitrate,
+                              media::VideoCodecProfile profile,
+                              base::WaitableEvent* async_waiter,
+                              int32_t* async_retval);
+  // Enqueue a frame from WebRTC for encoding.
+  // RTCVideoEncoder expects to be able to call this function synchronously from
+  // its own thread, hence the |async_waiter| and |async_retval| arguments.
+  void Enqueue(const webrtc::I420VideoFrame* input_frame,
+               bool force_keyframe,
+               base::WaitableEvent* async_waiter,
+               int32_t* async_retval);
+
+  // RTCVideoEncoder is given a buffer to be passed to WebRTC through the
+  // RTCVideoEncoder::ReturnEncodedImage() function.  When that is complete,
+  // the buffer is returned to Impl by its index using this function.
+  void UseOutputBitstreamBufferId(int32 bitstream_buffer_id);
+
+  // Request encoding parameter change for the underlying encoder.
+  void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
+
+  // Destroy this Impl's encoder.  The destructor is not explicitly called, as
+  // Impl is a base::RefCountedThreadSafe.
+  void Destroy();
+
+  // media::VideoEncodeAccelerator::Client implementation.
+  virtual void NotifyInitializeDone() OVERRIDE;
+  virtual void RequireBitstreamBuffers(unsigned int input_count,
+                                       const gfx::Size& input_coded_size,
+                                       size_t output_buffer_size) OVERRIDE;
+  virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
+                                    size_t payload_size,
+                                    bool key_frame) OVERRIDE;
+  virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
+
+ private:
+  friend class base::RefCountedThreadSafe<Impl>;
+
+  enum {
+    kInputBufferExtraCount = 1,  // The number of input buffers allocated, more
+                                 // than what is requested by
+                                 // VEA::RequireBitstreamBuffers().
+    kOutputBufferCount = 3,
+  };
+
+  virtual ~Impl();
+
+  // Perform encoding on an input frame from the input queue.
+  void EncodeOneFrame();
+
+  // Notify that an input frame is finished for encoding.  |index| is the index
+  // of the completed frame in |input_buffers_|.
+  void EncodeFrameFinished(int index);
+
+  // Set up/signal |async_waiter_| and |async_retval_|; see declarations below.
+  void RegisterAsyncWaiter(base::WaitableEvent* waiter, int32_t* retval);
+  void SignalAsyncWaiter(int32_t retval);
+
+  base::ThreadChecker thread_checker_;
+
+  // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
+  // notifications.
+  const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
+
+  // The message loop on which to post callbacks to |weak_encoder_|.
+  const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
+
+  // Factory for creating VEAs, shared memory buffers, etc.
+  const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
+
+  // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
+  // Do this by waiting on the |async_waiter_| and returning the return value in
+  // |async_retval_| when initialization completes, encoding completes, or
+  // an error occurs.
+  base::WaitableEvent* async_waiter_;
+  int32_t* async_retval_;
+
+  // The underlying VEA to perform encoding on.
+  scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
+
+  // Next input frame.  Since there is at most one next frame, a single-element
+  // queue is sufficient.
+  const webrtc::I420VideoFrame* input_next_frame_;
+
+  // Whether to encode a keyframe next.
+  bool input_next_frame_keyframe_;
+
+  // Frame sizes.
+  gfx::Size input_frame_coded_size_;
+  gfx::Size input_visible_size_;
+
+  // Shared memory buffers for input/output with the VEA.
+  ScopedVector<base::SharedMemory> input_buffers_;
+  ScopedVector<base::SharedMemory> output_buffers_;
+
+  // Input buffers ready to be filled with input from Encode().  As a LIFO since
+  // we don't care about ordering.
+  std::vector<int> input_buffers_free_;
+
+  // Timestamp of first frame returned from encoder.  We calculate subsequent
+  // capture times as deltas from this base.
+  base::Time time_base_;
+
+  DISALLOW_COPY_AND_ASSIGN(Impl);
+};
+
+RTCVideoEncoder::Impl::Impl(
+    const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
+    const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
+    : weak_encoder_(weak_encoder),
+      encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
+      gpu_factories_(gpu_factories),
+      async_waiter_(NULL),
+      async_retval_(NULL),
+      input_next_frame_(NULL),
+      input_next_frame_keyframe_(false) {
+  thread_checker_.DetachFromThread();
+}
+
+void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
+    const gfx::Size& input_visible_size,
+    uint32 bitrate,
+    media::VideoCodecProfile profile,
+    base::WaitableEvent* async_waiter,
+    int32_t* async_retval) {
+  DVLOG(3) << "Impl::CreateAndInitializeVEA()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  RegisterAsyncWaiter(async_waiter, async_retval);
+
+  // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
+  if (bitrate > kuint32max / 1000) {
+    NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
+    return;
+  }
+
+  video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(this).Pass();
+  if (!video_encoder_) {
+    NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+  input_visible_size_ = input_visible_size;
+  video_encoder_->Initialize(
+      media::VideoFrame::I420, input_visible_size_, profile, bitrate * 1000);
+}
+
+void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame,
+                                    bool force_keyframe,
+                                    base::WaitableEvent* async_waiter,
+                                    int32_t* async_retval) {
+  DVLOG(3) << "Impl::Enqueue()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!input_next_frame_);
+
+  RegisterAsyncWaiter(async_waiter, async_retval);
+  input_next_frame_ = input_frame;
+  input_next_frame_keyframe_ = force_keyframe;
+
+  if (!input_buffers_free_.empty())
+    EncodeOneFrame();
+}
+
+void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId(
+    int32 bitstream_buffer_id) {
+  DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): "
+              "bitstream_buffer_id=" << bitstream_buffer_id;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (video_encoder_) {
+    video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
+        bitstream_buffer_id,
+        output_buffers_[bitstream_buffer_id]->handle(),
+        output_buffers_[bitstream_buffer_id]->mapped_size()));
+  }
+}
+
+void RTCVideoEncoder::Impl::RequestEncodingParametersChange(uint32 bitrate,
+                                                            uint32 framerate) {
+  DVLOG(3) << "Impl::RequestEncodingParametersChange(): bitrate=" << bitrate
+           << ", framerate=" << framerate;
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
+  if (bitrate > kuint32max / 1000) {
+    NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
+    return;
+  }
+
+  if (video_encoder_)
+    video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate);
+}
+
+void RTCVideoEncoder::Impl::Destroy() {
+  DVLOG(3) << "Impl::Destroy()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (video_encoder_)
+    video_encoder_.release()->Destroy();
+}
+
+void RTCVideoEncoder::Impl::NotifyInitializeDone() {
+  DVLOG(3) << "Impl::NotifyInitializeDone()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
+}
+
+void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
+    unsigned int input_count,
+    const gfx::Size& input_coded_size,
+    size_t output_buffer_size) {
+  DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count
+           << ", input_coded_size=" << input_coded_size.ToString()
+           << ", output_buffer_size=" << output_buffer_size;
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (!video_encoder_)
+    return;
+
+  input_frame_coded_size_ = input_coded_size;
+
+  for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
+    base::SharedMemory* shm =
+        gpu_factories_->CreateSharedMemory(input_coded_size.GetArea() * 3 / 2);
+    if (!shm) {
+      DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
+                     "failed to create input buffer " << i;
+      NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+      return;
+    }
+    input_buffers_.push_back(shm);
+    input_buffers_free_.push_back(i);
+  }
+
+  for (int i = 0; i < kOutputBufferCount; ++i) {
+    base::SharedMemory* shm =
+        gpu_factories_->CreateSharedMemory(output_buffer_size);
+    if (!shm) {
+      DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
+                     "failed to create output buffer " << i;
+      NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+      return;
+    }
+    output_buffers_.push_back(shm);
+  }
+
+  // Immediately provide all output buffers to the VEA.
+  for (size_t i = 0; i < output_buffers_.size(); ++i) {
+    video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
+        i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size()));
+  }
+}
+
+void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
+                                                 size_t payload_size,
+                                                 bool key_frame) {
+  DVLOG(3) << "Impl::BitstreamBufferReady(): "
+              "bitstream_buffer_id=" << bitstream_buffer_id
+           << ", payload_size=" << payload_size
+           << ", key_frame=" << key_frame;
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (bitstream_buffer_id < 0 ||
+      bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) {
+    DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id="
+                << bitstream_buffer_id;
+    NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+  base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
+  if (payload_size > output_buffer->mapped_size()) {
+    DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid payload_size="
+                << payload_size;
+    NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+    return;
+  }
+
+  const base::Time now = base::Time::Now();
+  if (time_base_.is_null())
+    time_base_ = now;
+  const base::TimeDelta delta = now - time_base_;
+
+  scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage(
+      reinterpret_cast<uint8_t*>(output_buffer->memory()),
+      payload_size,
+      output_buffer->mapped_size()));
+  image->_encodedWidth = input_visible_size_.width();
+  image->_encodedHeight = input_visible_size_.height();
+  // Convert capture time to 90 kHz RTP timestamp.
+  image->_timeStamp = (delta * 90000).InSeconds();
+  image->capture_time_ms_ = delta.InMilliseconds();
+  image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
+  image->_completeFrame = true;
+
+  encoder_message_loop_proxy_->PostTask(
+      FROM_HERE,
+      base::Bind(&RTCVideoEncoder::ReturnEncodedImage,
+                 weak_encoder_,
+                 base::Passed(&image),
+                 bitstream_buffer_id));
+}
+
+void RTCVideoEncoder::Impl::NotifyError(
+    media::VideoEncodeAccelerator::Error error) {
+  DVLOG(3) << "Impl::NotifyError(): error=" << error;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  int32_t retval;
+  switch (error) {
+    case media::VideoEncodeAccelerator::kInvalidArgumentError:
+      retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+      break;
+    default:
+      retval = WEBRTC_VIDEO_CODEC_ERROR;
+  }
+
+  if (video_encoder_)
+    video_encoder_.release()->Destroy();
+
+  if (async_waiter_) {
+    SignalAsyncWaiter(retval);
+  } else {
+    encoder_message_loop_proxy_->PostTask(
+        FROM_HERE,
+        base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval));
+  }
+}
+
+RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
+
+void RTCVideoEncoder::Impl::EncodeOneFrame() {
+  DVLOG(3) << "Impl::EncodeOneFrame()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(input_next_frame_);
+  DCHECK(!input_buffers_free_.empty());
+
+  // EncodeOneFrame() may re-enter EncodeFrameFinished() if VEA::Encode() fails,
+  // we receive a VEA::NotifyError(), and the media::VideoFrame we pass to
+  // Encode() gets destroyed early.  Handle this by resetting our
+  // input_next_frame_* state before we hand off the VideoFrame to the VEA.
+  const webrtc::I420VideoFrame* next_frame = input_next_frame_;
+  bool next_frame_keyframe = input_next_frame_keyframe_;
+  input_next_frame_ = NULL;
+  input_next_frame_keyframe_ = false;
+
+  if (!video_encoder_) {
+    SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_ERROR);
+    return;
+  }
+
+  const int index = input_buffers_free_.back();
+  base::SharedMemory* input_buffer = input_buffers_[index];
+
+  // Do a strided copy of the input frame to match the input requirements for
+  // the encoder.
+  // TODO(sheu): support zero-copy from WebRTC.  http://crbug.com/269312
+  const uint8_t* src = next_frame->buffer(webrtc::kYPlane);
+  uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory());
+  uint8* const y_dst = dst;
+  int width = input_frame_coded_size_.width();
+  int stride = next_frame->stride(webrtc::kYPlane);
+  for (int i = 0; i < next_frame->height(); ++i) {
+    memcpy(dst, src, width);
+    src += stride;
+    dst += width;
+  }
+  src = next_frame->buffer(webrtc::kUPlane);
+  width = input_frame_coded_size_.width() / 2;
+  stride = next_frame->stride(webrtc::kUPlane);
+  for (int i = 0; i < next_frame->height() / 2; ++i) {
+    memcpy(dst, src, width);
+    src += stride;
+    dst += width;
+  }
+  src = next_frame->buffer(webrtc::kVPlane);
+  width = input_frame_coded_size_.width() / 2;
+  stride = next_frame->stride(webrtc::kVPlane);
+  for (int i = 0; i < next_frame->height() / 2; ++i) {
+    memcpy(dst, src, width);
+    src += stride;
+    dst += width;
+  }
+
+  scoped_refptr<media::VideoFrame> frame =
+      media::VideoFrame::WrapExternalSharedMemory(
+          media::VideoFrame::I420,
+          input_frame_coded_size_,
+          gfx::Rect(input_visible_size_),
+          input_visible_size_,
+          y_dst,
+          input_buffer->handle(),
+          base::TimeDelta(),
+          base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index));
+
+  video_encoder_->Encode(frame, next_frame_keyframe);
+  input_buffers_free_.pop_back();
+  SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
+}
+
+void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) {
+  DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_GE(index, 0);
+  DCHECK_LT(index, static_cast<int>(input_buffers_.size()));
+  input_buffers_free_.push_back(index);
+  if (input_next_frame_)
+    EncodeOneFrame();
+}
+
+void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent* waiter,
+                                                int32_t* retval) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!async_waiter_);
+  DCHECK(!async_retval_);
+  async_waiter_ = waiter;
+  async_retval_ = retval;
+}
+
+void RTCVideoEncoder::Impl::SignalAsyncWaiter(int32_t retval) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  *async_retval_ = retval;
+  async_waiter_->Signal();
+  async_retval_ = NULL;
+  async_waiter_ = NULL;
+}
+
+#undef NOTIFY_ERROR
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// RTCVideoEncoder
+//
+////////////////////////////////////////////////////////////////////////////////
+
+RTCVideoEncoder::RTCVideoEncoder(
+    webrtc::VideoCodecType type,
+    media::VideoCodecProfile profile,
+    const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
+    : video_codec_type_(type),
+      video_codec_profile_(profile),
+      gpu_factories_(gpu_factories),
+      encoded_image_callback_(NULL),
+      impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) {
+  DVLOG(1) << "RTCVideoEncoder(): profile=" << profile;
+}
+
+RTCVideoEncoder::~RTCVideoEncoder() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  Release();
+  DCHECK(!impl_);
+}
+
+int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
+                                    int32_t number_of_cores,
+                                    uint32_t max_payload_size) {
+  DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
+           << ", width=" << codec_settings->width
+           << ", height=" << codec_settings->height
+           << ", startBitrate=" << codec_settings->startBitrate;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!impl_);
+
+  weak_this_factory_.reset(new base::WeakPtrFactory<RTCVideoEncoder>(this));
+  impl_ = new Impl(weak_this_factory_->GetWeakPtr(), gpu_factories_);
+  base::WaitableEvent initialization_waiter(true, false);
+  int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  gpu_factories_->GetMessageLoop()->PostTask(
+      FROM_HERE,
+      base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
+                 impl_,
+                 gfx::Size(codec_settings->width, codec_settings->height),
+                 codec_settings->startBitrate,
+                 video_codec_profile_,
+                 &initialization_waiter,
+                 &initialization_retval));
+
+  // webrtc::VideoEncoder expects this call to be synchronous.
+  initialization_waiter.Wait();
+  return initialization_retval;
+}
+
+int32_t RTCVideoEncoder::Encode(
+    const webrtc::I420VideoFrame& input_image,
+    const webrtc::CodecSpecificInfo* codec_specific_info,
+    const std::vector<webrtc::VideoFrameType>* frame_types) {
+  DVLOG(3) << "Encode()";
+  // TODO(sheu): figure out why this check fails.
+  // DCHECK(thread_checker_.CalledOnValidThread());
+  if (!impl_) {
+    DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_;
+    return impl_status_;
+  }
+
+  base::WaitableEvent encode_waiter(true, false);
+  int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  gpu_factories_->GetMessageLoop()->PostTask(
+      FROM_HERE,
+      base::Bind(&RTCVideoEncoder::Impl::Enqueue,
+                 impl_,
+                 &input_image,
+                 (frame_types->front() == webrtc::kKeyFrame),
+                 &encode_waiter,
+                 &encode_retval));
+
+  // webrtc::VideoEncoder expects this call to be synchronous.
+  encode_waiter.Wait();
+  DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval;
+  return encode_retval;
+}
+
+int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
+    webrtc::EncodedImageCallback* callback) {
+  DVLOG(3) << "RegisterEncodeCompleteCallback()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (!impl_) {
+    DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_;
+    return impl_status_;
+  }
+
+  encoded_image_callback_ = callback;
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t RTCVideoEncoder::Release() {
+  DVLOG(3) << "Release()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Reset the gpu_factory_, in case we reuse this encoder.
+  gpu_factories_->Abort();
+  gpu_factories_ = gpu_factories_->Clone();
+  if (impl_) {
+    gpu_factories_->GetMessageLoop()->PostTask(
+        FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
+    impl_ = NULL;
+    weak_this_factory_.reset();
+    impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
+  }
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
+  DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
+           << ", rtt=" << rtt;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // Ignored.
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
+  DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate
+           << ", frame_rate=" << frame_rate;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (!impl_) {
+    DVLOG(3) << "SetRates(): returning " << impl_status_;
+    return impl_status_;
+  }
+
+  gpu_factories_->GetMessageLoop()->PostTask(
+      FROM_HERE,
+      base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange,
+                 impl_,
+                 new_bit_rate,
+                 frame_rate));
+  return WEBRTC_VIDEO_CODEC_OK;
+}
+
+void RTCVideoEncoder::ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,
+                                         int32 bitstream_buffer_id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DVLOG(3) << "ReturnEncodedImage(): "
+              "bitstream_buffer_id=" << bitstream_buffer_id;
+
+  if (!encoded_image_callback_)
+    return;
+
+  webrtc::CodecSpecificInfo info;
+  info.codecType = video_codec_type_;
+
+  // Generate a header describing a single fragment.
+  webrtc::RTPFragmentationHeader header;
+  header.VerifyAndAllocateFragmentationHeader(1);
+  header.fragmentationOffset[0] = 0;
+  header.fragmentationLength[0] = image->_length;
+  header.fragmentationPlType[0] = 0;
+  header.fragmentationTimeDiff[0] = 0;
+
+  int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header);
+  if (retval < 0) {
+    DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
+             << retval;
+  }
+
+  // The call through webrtc::EncodedImageCallback is synchronous, so we can
+  // immediately recycle the output buffer back to the Impl.
+  gpu_factories_->GetMessageLoop()->PostTask(
+      FROM_HERE,
+      base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId,
+                 impl_,
+                 bitstream_buffer_id));
+}
+
+void RTCVideoEncoder::NotifyError(int32_t error) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DVLOG(1) << "NotifyError(): error=" << error;
+
+  impl_status_ = error;
+  gpu_factories_->GetMessageLoop()->PostTask(
+      FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
+  impl_ = NULL;
+}
+
+}  // namespace content
diff --git a/content/renderer/media/rtc_video_encoder.h b/content/renderer/media/rtc_video_encoder.h
new file mode 100644
index 0000000..22d4c50
--- /dev/null
+++ b/content/renderer/media/rtc_video_encoder.h
@@ -0,0 +1,104 @@
+// Copyright 2013 The Chromium Authors. 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_RTC_VIDEO_ENCODER_H_
+#define CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "media/base/video_decoder_config.h"
+#include "third_party/webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
+#include "ui/gfx/size.h"
+
+namespace base {
+
+class MessageLoopProxy;
+
+}  // namespace base
+
+namespace content {
+
+class RendererGpuVideoAcceleratorFactories;
+
+// RTCVideoEncoder uses a media::VideoEncodeAccelerator to implement a
+// webrtc::VideoEncoder class for WebRTC.  Internally, VEA methods are
+// trampolined to a private RTCVideoEncoder::Impl instance.  The Impl class runs
+// on the worker thread queried from the |gpu_factories_|, which is presently
+// the media thread.  RTCVideoEncoder itself is run and destroyed on the thread
+// it is constructed on, which is presently the libjingle worker thread.
+// Callbacks from the Impl due to its VEA::Client notifications are also posted
+// back to RTCVideoEncoder on this thread.
+class CONTENT_EXPORT RTCVideoEncoder
+    : NON_EXPORTED_BASE(public webrtc::VideoEncoder) {
+ public:
+  RTCVideoEncoder(
+      webrtc::VideoCodecType type,
+      media::VideoCodecProfile profile,
+      const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
+  virtual ~RTCVideoEncoder();
+
+  // webrtc::VideoEncoder implementation.  Tasks are posted to |impl_| using the
+  // appropriate VEA methods.
+  virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
+                             int32_t number_of_cores,
+                             uint32_t max_payload_size) OVERRIDE;
+  virtual int32_t Encode(
+      const webrtc::I420VideoFrame& input_image,
+      const webrtc::CodecSpecificInfo* codec_specific_info,
+      const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
+  virtual int32_t RegisterEncodeCompleteCallback(
+      webrtc::EncodedImageCallback* callback) OVERRIDE;
+  virtual int32_t Release() OVERRIDE;
+  virtual int32_t SetChannelParameters(uint32_t packet_loss, int rtt) OVERRIDE;
+  virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
+
+ private:
+  class Impl;
+  friend class RTCVideoEncoder::Impl;
+
+  // Return an encoded output buffer to WebRTC.
+  void ReturnEncodedImage(scoped_ptr<webrtc::EncodedImage> image,
+                          int32 bitstream_buffer_id);
+
+  void NotifyError(int32_t error);
+
+  base::ThreadChecker thread_checker_;
+
+  // The video codec type, as reported to WebRTC.
+  const webrtc::VideoCodecType video_codec_type_;
+
+  // The video codec profile, to configure the encoder to encode to.
+  const media::VideoCodecProfile video_codec_profile_;
+
+  // Factory for creating VEAs, shared memory buffers, etc.
+  scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
+
+  // Weak pointer and factory for posting back VEA::Client notifications to
+  // RTCVideoEncoder.
+  scoped_ptr<base::WeakPtrFactory<RTCVideoEncoder> > weak_this_factory_;
+
+  // webrtc::VideoEncoder encode complete callback.
+  webrtc::EncodedImageCallback* encoded_image_callback_;
+
+  // The RTCVideoEncoder::Impl that does all the work.
+  scoped_refptr<Impl> impl_;
+
+  // We cannot immediately return error conditions to the WebRTC user of this
+  // class, as there is no error callback in the webrtc::VideoEncoder interface.
+  // Instead, we cache an error status here and return it the next time an
+  // interface entry point is called.
+  int32_t impl_status_;
+
+  DISALLOW_COPY_AND_ASSIGN(RTCVideoEncoder);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_H_
diff --git a/content/renderer/media/rtc_video_encoder_factory.cc b/content/renderer/media/rtc_video_encoder_factory.cc
new file mode 100644
index 0000000..3ff4272
--- /dev/null
+++ b/content/renderer/media/rtc_video_encoder_factory.cc
@@ -0,0 +1,110 @@
+// Copyright 2013 The Chromium Authors. 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/rtc_video_encoder_factory.h"
+
+#include "content/common/gpu/client/gpu_video_encode_accelerator_host.h"
+#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
+#include "content/renderer/media/rtc_video_encoder.h"
+#include "media/video/video_encode_accelerator.h"
+
+namespace content {
+
+namespace {
+
+// Translate from media::VideoEncodeAccelerator::SupportedProfile to
+// cricket::WebRtcVideoEncoderFactory::VideoCodec
+cricket::WebRtcVideoEncoderFactory::VideoCodec VEAToWebRTCCodec(
+    const media::VideoEncodeAccelerator::SupportedProfile& profile) {
+  webrtc::VideoCodecType type = webrtc::kVideoCodecUnknown;
+  std::string name;
+  int width = 0, height = 0, fps = 0;
+
+  if (profile.profile >= media::VP8PROFILE_MIN &&
+      profile.profile <= media::VP8PROFILE_MAX) {
+    type = webrtc::kVideoCodecVP8;
+    name = "VP8";
+  } else if (profile.profile >= media::H264PROFILE_MIN &&
+             profile.profile <= media::H264PROFILE_MAX) {
+    type = webrtc::kVideoCodecGeneric;
+    name = "CAST1";
+  }
+
+  if (type != webrtc::kVideoCodecUnknown) {
+    width = profile.max_resolution.width();
+    height = profile.max_resolution.height();
+    fps = profile.max_framerate.numerator;
+    DCHECK_EQ(profile.max_framerate.denominator, 1U);
+  }
+
+  return cricket::WebRtcVideoEncoderFactory::VideoCodec(
+      type, name, width, height, fps);
+}
+
+// Translate from cricket::WebRtcVideoEncoderFactory::VideoCodec to
+// media::VideoCodecProfile.  Pick a default profile for each codec type.
+media::VideoCodecProfile WebRTCCodecToVideoCodecProfile(
+    webrtc::VideoCodecType type) {
+  switch (type) {
+    case webrtc::kVideoCodecVP8:
+      return media::VP8PROFILE_MAIN;
+    case webrtc::kVideoCodecGeneric:
+      return media::H264PROFILE_MAIN;
+    default:
+      return media::VIDEO_CODEC_PROFILE_UNKNOWN;
+  }
+}
+
+}  // anonymous namespace
+
+RTCVideoEncoderFactory::RTCVideoEncoderFactory(
+    const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories)
+    : gpu_factories_(gpu_factories) {
+  // Query media::VideoEncodeAccelerator (statically) for our supported codecs.
+  std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles =
+      GpuVideoEncodeAcceleratorHost::GetSupportedProfiles();
+  for (size_t i = 0; i < profiles.size(); ++i) {
+    VideoCodec codec = VEAToWebRTCCodec(profiles[i]);
+    if (codec.type != webrtc::kVideoCodecUnknown)
+      codecs_.push_back(codec);
+  }
+}
+
+RTCVideoEncoderFactory::~RTCVideoEncoderFactory() {}
+
+webrtc::VideoEncoder* RTCVideoEncoderFactory::CreateVideoEncoder(
+    webrtc::VideoCodecType type) {
+  bool found = false;
+  for (size_t i = 0; i < codecs_.size(); ++i) {
+    if (codecs_[i].type == type) {
+      found = true;
+      break;
+    }
+  }
+  if (!found)
+    return NULL;
+  // GpuVideoAcceleratorFactories is not thread safe. It cannot be shared
+  // by different encoders. Since we aren't running on the child thread and
+  // cannot create a new factory, clone one instead.
+  return new RTCVideoEncoder(
+      type, WebRTCCodecToVideoCodecProfile(type), gpu_factories_->Clone());
+}
+
+void RTCVideoEncoderFactory::AddObserver(Observer* observer) {
+  // No-op: our codec list is populated on installation.
+}
+
+void RTCVideoEncoderFactory::RemoveObserver(Observer* observer) {}
+
+const std::vector<cricket::WebRtcVideoEncoderFactory::VideoCodec>&
+RTCVideoEncoderFactory::codecs() const {
+  return codecs_;
+}
+
+void RTCVideoEncoderFactory::DestroyVideoEncoder(
+    webrtc::VideoEncoder* encoder) {
+  delete encoder;
+}
+
+}  // namespace content
diff --git a/content/renderer/media/rtc_video_encoder_factory.h b/content/renderer/media/rtc_video_encoder_factory.h
new file mode 100644
index 0000000..b07ccda
--- /dev/null
+++ b/content/renderer/media/rtc_video_encoder_factory.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 CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_
+#define CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoencoderfactory.h"
+
+namespace content {
+
+class RendererGpuVideoAcceleratorFactories;
+
+// This class creates RTCVideoEncoder instances (each wrapping a
+// media::VideoEncodeAccelerator) on behalf of the WebRTC stack.
+class CONTENT_EXPORT RTCVideoEncoderFactory
+    : NON_EXPORTED_BASE(public cricket::WebRtcVideoEncoderFactory) {
+ public:
+  explicit RTCVideoEncoderFactory(
+      const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories);
+  virtual ~RTCVideoEncoderFactory();
+
+  // cricket::WebRtcVideoEncoderFactory implementation.
+  virtual webrtc::VideoEncoder* CreateVideoEncoder(
+      webrtc::VideoCodecType type) OVERRIDE;
+  virtual void AddObserver(Observer* observer) OVERRIDE;
+  virtual void RemoveObserver(Observer* observer) OVERRIDE;
+  virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
+  virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
+
+ private:
+  const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_;
+
+  // Codec support list of cricket::WebRtcVideoEncoderFactory::VideoCodec
+  // instances.
+  std::vector<VideoCodec> codecs_;
+
+  DISALLOW_COPY_AND_ASSIGN(RTCVideoEncoderFactory);
+};
+
+}  // namespace content
+
+#endif  //  CONTENT_RENDERER_MEDIA_RTC_VIDEO_ENCODER_FACTORY_H_
diff --git a/content/renderer/media/webaudio_capturer_source.cc b/content/renderer/media/webaudio_capturer_source.cc
index 0ab8dc3..35cd99c 100644
--- a/content/renderer/media/webaudio_capturer_source.cc
+++ b/content/renderer/media/webaudio_capturer_source.cc
@@ -96,7 +96,7 @@
   int capture_frames = params_.frames_per_buffer();
   while (fifo_->frames() >= capture_frames) {
     fifo_->Consume(capture_bus_.get(), 0, capture_frames);
-    callback_->Capture(capture_bus_.get(), 0, 1.0);
+    callback_->Capture(capture_bus_.get(), 0, 1.0, false);
   }
 }
 
diff --git a/content/renderer/media/webmediaplayer_impl.cc b/content/renderer/media/webmediaplayer_impl.cc
index 227d0cf..c651764 100644
--- a/content/renderer/media/webmediaplayer_impl.cc
+++ b/content/renderer/media/webmediaplayer_impl.cc
@@ -27,7 +27,7 @@
 #include "content/renderer/media/webmediaplayer_delegate.h"
 #include "content/renderer/media/webmediaplayer_params.h"
 #include "content/renderer/media/webmediaplayer_util.h"
-#include "content/renderer/media/webmediasourceclient_impl.h"
+#include "content/renderer/media/webmediasource_impl.h"
 #include "content/renderer/pepper/pepper_webplugin_impl.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "media/audio/null_audio_sink.h"
@@ -43,16 +43,16 @@
 #include "media/filters/ffmpeg_audio_decoder.h"
 #include "media/filters/ffmpeg_demuxer.h"
 #include "media/filters/ffmpeg_video_decoder.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 #include "media/filters/gpu_video_decoder.h"
-#include "media/filters/gpu_video_decoder_factories.h"
 #include "media/filters/opus_audio_decoder.h"
 #include "media/filters/video_renderer_base.h"
 #include "media/filters/vpx_video_decoder.h"
+#include "third_party/WebKit/public/platform/WebMediaSource.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/web/WebMediaSource.h"
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "v8/include/v8.h"
@@ -246,24 +246,18 @@
 
 }  // anonymous namespace
 
-void WebMediaPlayerImpl::load(const WebKit::WebURL& url, CORSMode cors_mode) {
-  load(url, NULL, cors_mode);
-}
-
-void WebMediaPlayerImpl::load(const WebKit::WebURL& url,
-                              WebKit::WebMediaSource* media_source,
+void WebMediaPlayerImpl::load(LoadType load_type, const WebKit::WebURL& url,
                               CORSMode cors_mode) {
   if (!defer_load_cb_.is_null()) {
     defer_load_cb_.Run(base::Bind(
-        &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), url, media_source,
-        cors_mode));
+        &WebMediaPlayerImpl::DoLoad, AsWeakPtr(), load_type, url, cors_mode));
     return;
   }
-  DoLoad(url, media_source, cors_mode);
+  DoLoad(load_type, url, cors_mode);
 }
 
-void WebMediaPlayerImpl::DoLoad(const WebKit::WebURL& url,
-                                WebKit::WebMediaSource* media_source,
+void WebMediaPlayerImpl::DoLoad(LoadType load_type,
+                                const WebKit::WebURL& url,
                                 CORSMode cors_mode) {
   DCHECK(main_loop_->BelongsToCurrentThread());
 
@@ -273,6 +267,8 @@
   // Set subresource URL for crash reporting.
   base::debug::SetCrashKeyValue("subresource_url", gurl.spec());
 
+  load_type_ = load_type;
+
   // Handle any volume/preload changes that occurred before load().
   setVolume(GetClient()->volume());
   setPreload(GetClient()->preload());
@@ -282,9 +278,9 @@
   media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
 
   // Media source pipelines can start immediately.
-  if (media_source) {
+  if (load_type == LoadTypeMediaSource) {
     supports_save_ = false;
-    StartPipeline(media_source);
+    StartPipeline();
     return;
   }
 
@@ -300,7 +296,7 @@
           &WebMediaPlayerImpl::DataSourceInitialized,
           AsWeakPtr(), gurl));
 
-  is_local_source_ = !gurl.SchemeIs("http") && !gurl.SchemeIs("https");
+  is_local_source_ = !gurl.SchemeIsHTTPOrHTTPS();
 }
 
 void WebMediaPlayerImpl::play() {
@@ -912,10 +908,9 @@
   Repaint();
 }
 
-void WebMediaPlayerImpl::OnDemuxerOpened(
-    scoped_ptr<WebKit::WebMediaSource> media_source) {
+void WebMediaPlayerImpl::OnDemuxerOpened() {
   DCHECK(main_loop_->BelongsToCurrentThread());
-  media_source->open(new WebMediaSourceClientImpl(
+  GetClient()->mediaSourceOpened(new WebMediaSourceImpl(
       chunk_demuxer_, base::Bind(&LogMediaSourceError, media_log_)));
 }
 
@@ -1011,7 +1006,7 @@
     return;
   }
 
-  StartPipeline(NULL);
+  StartPipeline();
 }
 
 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
@@ -1025,15 +1020,16 @@
           "is_downloading_data", is_downloading));
 }
 
-void WebMediaPlayerImpl::StartPipeline(WebKit::WebMediaSource* media_source) {
+void WebMediaPlayerImpl::StartPipeline() {
   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
   bool increase_preroll_on_underflow = true;
 
   // Keep track if this is a MSE or non-MSE playback.
-  UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback", (media_source != NULL));
+  UMA_HISTOGRAM_BOOLEAN("Media.MSE.Playback",
+                        (load_type_ == LoadTypeMediaSource));
 
   // Figure out which demuxer to use.
-  if (!media_source) {
+  if (load_type_ != LoadTypeMediaSource) {
     DCHECK(!chunk_demuxer_);
     DCHECK(data_source_);
 
@@ -1052,10 +1048,8 @@
           base::Bind(&WebMediaPlayerImpl::OnTextTrack, base::Unretained(this));
     }
 
-    scoped_ptr<WebKit::WebMediaSource> ms(media_source);
     chunk_demuxer_ = new media::ChunkDemuxer(
-        BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnDemuxerOpened,
-                              base::Passed(&ms)),
+        BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDemuxerOpened),
         BIND_TO_RENDER_LOOP_1(&WebMediaPlayerImpl::OnNeedKey, ""),
         add_text_track_cb,
         base::Bind(&LogMediaSourceError, media_log_));
@@ -1104,8 +1098,10 @@
   // Create our video decoders and renderer.
   ScopedVector<media::VideoDecoder> video_decoders;
 
-  if (gpu_factories_.get())
-    video_decoders.push_back(new media::GpuVideoDecoder(gpu_factories_));
+  if (gpu_factories_.get()) {
+    video_decoders.push_back(
+        new media::GpuVideoDecoder(gpu_factories_, media_log_));
+  }
 
   // TODO(phajdan.jr): Remove ifdefs when libvpx with vp9 support is released
   // (http://crbug.com/174287) .
diff --git a/content/renderer/media/webmediaplayer_impl.h b/content/renderer/media/webmediaplayer_impl.h
index 23b1ddf..e9ad902 100644
--- a/content/renderer/media/webmediaplayer_impl.h
+++ b/content/renderer/media/webmediaplayer_impl.h
@@ -56,7 +56,7 @@
 namespace media {
 class ChunkDemuxer;
 class FFmpegDemuxer;
-class GpuVideoDecoderFactories;
+class GpuVideoAcceleratorFactories;
 class MediaLog;
 }
 
@@ -87,10 +87,9 @@
       const WebMediaPlayerParams& params);
   virtual ~WebMediaPlayerImpl();
 
-  virtual void load(const WebKit::WebURL& url, CORSMode cors_mode);
-  virtual void load(const WebKit::WebURL& url,
-                    WebKit::WebMediaSource* media_source,
-                    CORSMode cors_mode);
+  virtual void load(LoadType load_type,
+                    const WebKit::WebURL& url,
+                    CORSMode cors_mode) OVERRIDE;
 
   // Playback controls.
   virtual void play();
@@ -187,7 +186,7 @@
   void OnPipelineError(media::PipelineStatus error);
   void OnPipelineBufferingState(
       media::Pipeline::BufferingState buffering_state);
-  void OnDemuxerOpened(scoped_ptr<WebKit::WebMediaSource> media_source);
+  void OnDemuxerOpened();
   void OnKeyAdded(const std::string& session_id);
   void OnKeyError(const std::string& session_id,
                   media::MediaKeys::KeyError error_code,
@@ -207,8 +206,8 @@
  private:
   // Called after |defer_load_cb_| has decided to allow the load. If
   // |defer_load_cb_| is null this is called immediately.
-  void DoLoad(const WebKit::WebURL& url,
-              WebKit::WebMediaSource* media_source,
+  void DoLoad(LoadType load_type,
+              const WebKit::WebURL& url,
               CORSMode cors_mode);
 
   // Called after asynchronous initialization of a data source completed.
@@ -218,9 +217,7 @@
   void NotifyDownloading(bool is_downloading);
 
   // Finishes starting the pipeline due to a call to load().
-  //
-  // A non-null |media_source| will construct a Media Source pipeline.
-  void StartPipeline(WebKit::WebMediaSource* media_source);
+  void StartPipeline();
 
   // Helpers that set the network/ready state and notifies the client if
   // they've changed.
@@ -282,6 +279,9 @@
   // has been selected.
   WebKit::WebString current_key_system_;
 
+  // The LoadType passed in the |load_type| parameter of the load() call.
+  LoadType load_type_;
+
   // Playback state.
   //
   // TODO(scherkus): we have these because Pipeline favours the simplicity of a
@@ -318,8 +318,8 @@
 
   bool incremented_externally_allocated_memory_;
 
-  // Factories for supporting GpuVideoDecoder. May be null.
-  scoped_refptr<media::GpuVideoDecoderFactories> gpu_factories_;
+  // Factories for supporting video accelerators. May be null.
+  scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
 
   // Routes audio playback to either AudioRendererSink or WebAudio.
   scoped_refptr<WebAudioSourceProviderImpl> audio_source_provider_;
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc
index a1eed03..63f41ec 100644
--- a/content/renderer/media/webmediaplayer_ms.cc
+++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -91,10 +91,16 @@
     delegate_->PlayerGone(this);
 }
 
-void WebMediaPlayerMS::load(const WebKit::WebURL& url, CORSMode cors_mode) {
+void WebMediaPlayerMS::load(LoadType load_type,
+                            const WebKit::WebURL& url,
+                            CORSMode cors_mode) {
   DVLOG(1) << "WebMediaPlayerMS::load";
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  // TODO(acolwell): Change this to DCHECK_EQ(load_type,
+  // LoadTypeMediaStream) once Blink-side changes land.
+  DCHECK_NE(load_type, LoadTypeMediaSource);
+
   GURL gurl(url);
 
   setVolume(GetClient()->volume());
@@ -128,12 +134,6 @@
   }
 }
 
-void WebMediaPlayerMS::load(const WebKit::WebURL& url,
-                            WebKit::WebMediaSource* media_source,
-                            CORSMode cors_mode) {
-  NOTIMPLEMENTED();
-}
-
 void WebMediaPlayerMS::play() {
   DVLOG(1) << "WebMediaPlayerMS::play";
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/content/renderer/media/webmediaplayer_ms.h b/content/renderer/media/webmediaplayer_ms.h
index fae271b..1ed75a3 100644
--- a/content/renderer/media/webmediaplayer_ms.h
+++ b/content/renderer/media/webmediaplayer_ms.h
@@ -63,9 +63,8 @@
                    media::MediaLog* media_log);
   virtual ~WebMediaPlayerMS();
 
-  virtual void load(const WebKit::WebURL& url, CORSMode cors_mode) OVERRIDE;
-  virtual void load(const WebKit::WebURL& url,
-                    WebKit::WebMediaSource* media_source,
+  virtual void load(LoadType load_type,
+                    const WebKit::WebURL& url,
                     CORSMode cors_mode) OVERRIDE;
 
   // Playback controls.
diff --git a/content/renderer/media/webmediaplayer_params.cc b/content/renderer/media/webmediaplayer_params.cc
index 04fe310..a05abbf 100644
--- a/content/renderer/media/webmediaplayer_params.cc
+++ b/content/renderer/media/webmediaplayer_params.cc
@@ -7,7 +7,7 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "media/base/audio_renderer_sink.h"
 #include "media/base/media_log.h"
-#include "media/filters/gpu_video_decoder_factories.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 
 namespace content {
 
@@ -15,7 +15,7 @@
     const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
     const base::Callback<void(const base::Closure&)>& defer_load_cb,
     const scoped_refptr<media::AudioRendererSink>& audio_renderer_sink,
-    const scoped_refptr<media::GpuVideoDecoderFactories>& gpu_factories,
+    const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories,
     const scoped_refptr<media::MediaLog>& media_log)
     : message_loop_proxy_(message_loop_proxy),
       defer_load_cb_(defer_load_cb),
diff --git a/content/renderer/media/webmediaplayer_params.h b/content/renderer/media/webmediaplayer_params.h
index 4347a4a..bf39864 100644
--- a/content/renderer/media/webmediaplayer_params.h
+++ b/content/renderer/media/webmediaplayer_params.h
@@ -14,7 +14,7 @@
 
 namespace media {
 class AudioRendererSink;
-class GpuVideoDecoderFactories;
+class GpuVideoAcceleratorFactories;
 class MediaLog;
 }
 
@@ -30,7 +30,7 @@
       const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
       const base::Callback<void(const base::Closure&)>& defer_load_cb,
       const scoped_refptr<media::AudioRendererSink>& audio_renderer_sink,
-      const scoped_refptr<media::GpuVideoDecoderFactories>& gpu_factories,
+      const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories,
       const scoped_refptr<media::MediaLog>& media_log);
   ~WebMediaPlayerParams();
 
@@ -46,7 +46,8 @@
     return audio_renderer_sink_;
   }
 
-  const scoped_refptr<media::GpuVideoDecoderFactories>& gpu_factories() const {
+  const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories()
+      const {
     return gpu_factories_;
   }
 
@@ -58,7 +59,7 @@
   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
   base::Callback<void(const base::Closure&)> defer_load_cb_;
   scoped_refptr<media::AudioRendererSink> audio_renderer_sink_;
-  scoped_refptr<media::GpuVideoDecoderFactories> gpu_factories_;
+  scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
   scoped_refptr<media::MediaLog> media_log_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(WebMediaPlayerParams);
diff --git a/content/renderer/media/webmediaplayer_util.h b/content/renderer/media/webmediaplayer_util.h
index 9a06268..007980c 100644
--- a/content/renderer/media/webmediaplayer_util.h
+++ b/content/renderer/media/webmediaplayer_util.h
@@ -8,8 +8,8 @@
 #include "base/time/time.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/ranges.h"
+#include "third_party/WebKit/public/platform/WebTimeRange.h"
 #include "third_party/WebKit/public/web/WebMediaPlayer.h"
-#include "third_party/WebKit/public/web/WebTimeRange.h"
 
 namespace content {
 
diff --git a/content/renderer/media/webmediasource_impl.cc b/content/renderer/media/webmediasource_impl.cc
new file mode 100644
index 0000000..275b29a
--- /dev/null
+++ b/content/renderer/media/webmediasource_impl.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 "content/renderer/media/webmediasource_impl.h"
+
+#include "base/guid.h"
+#include "content/renderer/media/websourcebuffer_impl.h"
+#include "media/filters/chunk_demuxer.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+
+using ::WebKit::WebString;
+using ::WebKit::WebMediaSourceNew;
+
+namespace content {
+
+#define COMPILE_ASSERT_MATCHING_STATUS_ENUM(webkit_name, chromium_name) \
+  COMPILE_ASSERT(static_cast<int>(WebMediaSourceNew::webkit_name) == \
+                 static_cast<int>(media::ChunkDemuxer::chromium_name),  \
+                 mismatching_status_enums)
+COMPILE_ASSERT_MATCHING_STATUS_ENUM(AddStatusOk, kOk);
+COMPILE_ASSERT_MATCHING_STATUS_ENUM(AddStatusNotSupported, kNotSupported);
+COMPILE_ASSERT_MATCHING_STATUS_ENUM(AddStatusReachedIdLimit, kReachedIdLimit);
+#undef COMPILE_ASSERT_MATCHING_STATUS_ENUM
+
+WebMediaSourceImpl::WebMediaSourceImpl(
+    media::ChunkDemuxer* demuxer, media::LogCB log_cb)
+    : demuxer_(demuxer),
+      log_cb_(log_cb) {
+  DCHECK(demuxer_);
+}
+
+WebMediaSourceImpl::~WebMediaSourceImpl() {}
+
+WebMediaSourceNew::AddStatus WebMediaSourceImpl::addSourceBuffer(
+    const WebKit::WebString& type,
+    const WebKit::WebVector<WebKit::WebString>& codecs,
+    WebKit::WebSourceBuffer** source_buffer) {
+  std::string id = base::GenerateGUID();
+  std::vector<std::string> new_codecs(codecs.size());
+  for (size_t i = 0; i < codecs.size(); ++i)
+    new_codecs[i] = codecs[i].utf8().data();
+  WebMediaSourceNew::AddStatus result =
+      static_cast<WebMediaSourceNew::AddStatus>(
+          demuxer_->AddId(id, type.utf8().data(), new_codecs));
+
+  if (result == WebMediaSourceNew::AddStatusOk)
+    *source_buffer = new WebSourceBufferImpl(id, demuxer_);
+
+  return result;
+}
+
+double WebMediaSourceImpl::duration() {
+  return demuxer_->GetDuration();
+}
+
+void WebMediaSourceImpl::setDuration(double new_duration) {
+  DCHECK_GE(new_duration, 0);
+  demuxer_->SetDuration(new_duration);
+}
+
+void WebMediaSourceImpl::markEndOfStream(
+    WebMediaSourceNew::EndOfStreamStatus status) {
+  media::PipelineStatus pipeline_status = media::PIPELINE_OK;
+
+  switch (status) {
+    case WebMediaSourceNew::EndOfStreamStatusNoError:
+      break;
+    case WebMediaSourceNew::EndOfStreamStatusNetworkError:
+      pipeline_status = media::PIPELINE_ERROR_NETWORK;
+      break;
+    case WebMediaSourceNew::EndOfStreamStatusDecodeError:
+      pipeline_status = media::PIPELINE_ERROR_DECODE;
+      break;
+    default:
+      NOTIMPLEMENTED();
+  }
+
+  demuxer_->MarkEndOfStream(pipeline_status);
+}
+
+void WebMediaSourceImpl::unmarkEndOfStream() {
+  demuxer_->UnmarkEndOfStream();
+}
+
+}  // namespace content
diff --git a/content/renderer/media/webmediasource_impl.h b/content/renderer/media/webmediasource_impl.h
new file mode 100644
index 0000000..a09790b
--- /dev/null
+++ b/content/renderer/media/webmediasource_impl.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_RENDERER_MEDIA_WEBMEDIASOURCE_IMPL_H_
+#define CONTENT_RENDERER_MEDIA_WEBMEDIASOURCE_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "media/base/media_log.h"
+#include "third_party/WebKit/public/platform/WebMediaSource.h"
+
+namespace media {
+class ChunkDemuxer;
+}
+
+namespace content {
+
+class WebMediaSourceImpl : public WebKit::WebMediaSourceNew {
+ public:
+  WebMediaSourceImpl(media::ChunkDemuxer* demuxer, media::LogCB log_cb);
+  virtual ~WebMediaSourceImpl();
+
+  // WebKit::WebMediaSourceNew implementation.
+  virtual AddStatus addSourceBuffer(
+      const WebKit::WebString& type,
+      const WebKit::WebVector<WebKit::WebString>& codecs,
+      WebKit::WebSourceBuffer** source_buffer) OVERRIDE;
+  virtual double duration() OVERRIDE;
+  virtual void setDuration(double duration) OVERRIDE;
+  virtual void markEndOfStream(EndOfStreamStatus status) OVERRIDE;
+  virtual void unmarkEndOfStream() OVERRIDE;
+
+ private:
+  media::ChunkDemuxer* demuxer_;  // Owned by WebMediaPlayerImpl.
+  media::LogCB log_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebMediaSourceImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_WEBMEDIASOURCE_IMPL_H_
diff --git a/content/renderer/media/webmediasourceclient_impl.cc b/content/renderer/media/webmediasourceclient_impl.cc
deleted file mode 100644
index 66a3f02..0000000
--- a/content/renderer/media/webmediasourceclient_impl.cc
+++ /dev/null
@@ -1,93 +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/webmediasourceclient_impl.h"
-
-#include "base/guid.h"
-#include "content/renderer/media/websourcebuffer_impl.h"
-#include "media/filters/chunk_demuxer.h"
-#include "third_party/WebKit/public/platform/WebCString.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-
-using ::WebKit::WebString;
-using ::WebKit::WebMediaSourceClient;
-
-namespace content {
-
-#define COMPILE_ASSERT_MATCHING_STATUS_ENUM(webkit_name, chromium_name) \
-  COMPILE_ASSERT(static_cast<int>(WebMediaSourceClient::webkit_name) == \
-                 static_cast<int>(media::ChunkDemuxer::chromium_name),  \
-                 mismatching_status_enums)
-COMPILE_ASSERT_MATCHING_STATUS_ENUM(AddStatusOk, kOk);
-COMPILE_ASSERT_MATCHING_STATUS_ENUM(AddStatusNotSupported, kNotSupported);
-COMPILE_ASSERT_MATCHING_STATUS_ENUM(AddStatusReachedIdLimit, kReachedIdLimit);
-#undef COMPILE_ASSERT_MATCHING_STATUS_ENUM
-
-WebMediaSourceClientImpl::WebMediaSourceClientImpl(
-    media::ChunkDemuxer* demuxer, media::LogCB log_cb)
-    : demuxer_(demuxer),
-      log_cb_(log_cb) {
-  DCHECK(demuxer_);
-}
-
-WebMediaSourceClientImpl::~WebMediaSourceClientImpl() {}
-
-WebMediaSourceClient::AddStatus WebMediaSourceClientImpl::addSourceBuffer(
-    const WebKit::WebString& type,
-    const WebKit::WebVector<WebKit::WebString>& codecs,
-    WebKit::WebSourceBuffer** source_buffer) {
-  std::string id = base::GenerateGUID();
-  std::vector<std::string> new_codecs(codecs.size());
-  for (size_t i = 0; i < codecs.size(); ++i)
-    new_codecs[i] = codecs[i].utf8().data();
-  WebMediaSourceClient::AddStatus result =
-      static_cast<WebMediaSourceClient::AddStatus>(
-          demuxer_->AddId(id, type.utf8().data(), new_codecs));
-
-  if (result == WebMediaSourceClient::AddStatusOk)
-    *source_buffer = new WebSourceBufferImpl(id, demuxer_);
-
-  return result;
-}
-
-double WebMediaSourceClientImpl::duration() {
-  return demuxer_->GetDuration();
-}
-
-void WebMediaSourceClientImpl::setDuration(double new_duration) {
-  DCHECK_GE(new_duration, 0);
-  demuxer_->SetDuration(new_duration);
-}
-
-// TODO(acolwell): Remove this once endOfStream() is removed from Blink.
-void WebMediaSourceClientImpl::endOfStream(
-    WebMediaSourceClient::EndOfStreamStatus status) {
-  markEndOfStream(status);
-}
-
-void WebMediaSourceClientImpl::markEndOfStream(
-    WebMediaSourceClient::EndOfStreamStatus status) {
-  media::PipelineStatus pipeline_status = media::PIPELINE_OK;
-
-  switch (status) {
-    case WebMediaSourceClient::EndOfStreamStatusNoError:
-      break;
-    case WebMediaSourceClient::EndOfStreamStatusNetworkError:
-      pipeline_status = media::PIPELINE_ERROR_NETWORK;
-      break;
-    case WebMediaSourceClient::EndOfStreamStatusDecodeError:
-      pipeline_status = media::PIPELINE_ERROR_DECODE;
-      break;
-    default:
-      NOTIMPLEMENTED();
-  }
-
-  demuxer_->MarkEndOfStream(pipeline_status);
-}
-
-void WebMediaSourceClientImpl::unmarkEndOfStream() {
-  demuxer_->UnmarkEndOfStream();
-}
-
-}  // namespace content
diff --git a/content/renderer/media/webmediasourceclient_impl.h b/content/renderer/media/webmediasourceclient_impl.h
deleted file mode 100644
index bebdd54..0000000
--- a/content/renderer/media/webmediasourceclient_impl.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 CONTENT_RENDERER_MEDIA_WEBMEDIASOURCECLIENT_IMPL_H_
-#define CONTENT_RENDERER_MEDIA_WEBMEDIASOURCECLIENT_IMPL_H_
-
-#include <string>
-#include <vector>
-
-#include "media/base/media_log.h"
-#include "third_party/WebKit/public/web/WebMediaSourceClient.h"
-
-namespace media {
-class ChunkDemuxer;
-}
-
-namespace content {
-
-class WebMediaSourceClientImpl : public WebKit::WebMediaSourceClient {
- public:
-  WebMediaSourceClientImpl(media::ChunkDemuxer* demuxer, media::LogCB log_cb);
-  virtual ~WebMediaSourceClientImpl();
-
-  // WebKit::WebMediaSourceClient implementation.
-  virtual AddStatus addSourceBuffer(
-      const WebKit::WebString& type,
-      const WebKit::WebVector<WebKit::WebString>& codecs,
-      WebKit::WebSourceBuffer** source_buffer) OVERRIDE;
-  virtual double duration() OVERRIDE;
-  virtual void setDuration(double duration) OVERRIDE;
-  // TODO(acolwell): Remove this once endOfStream() is removed from Blink.
-  virtual void endOfStream(EndOfStreamStatus status);
-  virtual void markEndOfStream(EndOfStreamStatus status) OVERRIDE;
-  virtual void unmarkEndOfStream() OVERRIDE;
-
- private:
-  media::ChunkDemuxer* demuxer_;  // Owned by WebMediaPlayerImpl.
-  media::LogCB log_cb_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebMediaSourceClientImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_WEBMEDIASOURCECLIENT_IMPL_H_
diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc
index 238b2a2..26b0fd7 100644
--- a/content/renderer/media/webrtc_audio_capturer.cc
+++ b/content/renderer/media/webrtc_audio_capturer.cc
@@ -102,14 +102,16 @@
                    int number_of_channels,
                    int number_of_frames,
                    int audio_delay_milliseconds,
-                   int volume) {
+                   int volume,
+                   bool key_pressed) {
     base::AutoLock lock(lock_);
     if (delegate_) {
       delegate_->CaptureData(audio_data,
                              number_of_channels,
                              number_of_frames,
                              audio_delay_milliseconds,
-                             volume);
+                             volume,
+                             key_pressed);
     }
   }
 
@@ -424,10 +426,11 @@
 
 void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source,
                                   int audio_delay_milliseconds,
-                                  double volume) {
-  // This callback is driven by AudioInputDevice::AudioThreadCallback if
-  // |source_| is AudioInputDevice, otherwise it is driven by client's
-  // CaptureCallback.
+                                  double volume,
+                                  bool key_pressed) {
+// This callback is driven by AudioInputDevice::AudioThreadCallback if
+// |source_| is AudioInputDevice, otherwise it is driven by client's
+// CaptureCallback.
 #if defined(OS_WIN) || defined(OS_MACOSX)
   DCHECK_LE(volume, 1.0);
 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
@@ -471,8 +474,11 @@
        it != tracks.end();
        ++it) {
     (*it)->CaptureData(buffer_ref_while_calling->buffer(),
-                       audio_source->channels(), audio_source->frames(),
-                       audio_delay_milliseconds, volume_);
+                       audio_source->channels(),
+                       audio_source->frames(),
+                       audio_delay_milliseconds,
+                       volume,
+                       key_pressed);
   }
 }
 
diff --git a/content/renderer/media/webrtc_audio_capturer.h b/content/renderer/media/webrtc_audio_capturer.h
index e85ea04..caa88d0 100644
--- a/content/renderer/media/webrtc_audio_capturer.h
+++ b/content/renderer/media/webrtc_audio_capturer.h
@@ -108,7 +108,8 @@
   // Called on the AudioInputDevice audio thread.
   virtual void Capture(media::AudioBus* audio_source,
                        int audio_delay_milliseconds,
-                       double volume) OVERRIDE;
+                       double volume,
+                       bool key_pressed) OVERRIDE;
   virtual void OnCaptureError() OVERRIDE;
 
   // Reconfigures the capturer with a new buffer size and capture parameters.
diff --git a/content/renderer/media/webrtc_audio_capturer_sink_owner.cc b/content/renderer/media/webrtc_audio_capturer_sink_owner.cc
index cb6a813..59de510 100644
--- a/content/renderer/media/webrtc_audio_capturer_sink_owner.cc
+++ b/content/renderer/media/webrtc_audio_capturer_sink_owner.cc
@@ -18,13 +18,19 @@
                                               int number_of_frames,
                                               int audio_delay_milliseconds,
                                               int current_volume,
-                                              bool need_audio_processing) {
+                                              bool need_audio_processing,
+                                              bool key_pressed) {
   base::AutoLock lock(lock_);
   if (delegate_) {
-    return delegate_->CaptureData(channels, audio_data, sample_rate,
-                                  number_of_channels, number_of_frames,
-                                  audio_delay_milliseconds, current_volume,
-                                  need_audio_processing);
+    delegate_->CaptureData(channels,
+                           audio_data,
+                           sample_rate,
+                           number_of_channels,
+                           number_of_frames,
+                           audio_delay_milliseconds,
+                           current_volume,
+                           need_audio_processing,
+                           key_pressed);
   }
 
   return 0;
diff --git a/content/renderer/media/webrtc_audio_capturer_sink_owner.h b/content/renderer/media/webrtc_audio_capturer_sink_owner.h
index a3641b8..f338209 100644
--- a/content/renderer/media/webrtc_audio_capturer_sink_owner.h
+++ b/content/renderer/media/webrtc_audio_capturer_sink_owner.h
@@ -31,7 +31,8 @@
                           int number_of_frames,
                           int audio_delay_milliseconds,
                           int current_volume,
-                          bool need_audio_processing) OVERRIDE;
+                          bool need_audio_processing,
+                          bool key_pressed) OVERRIDE;
 
   virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE;
 
diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc
index c40e0a2..93e024b 100644
--- a/content/renderer/media/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc_audio_device_impl.cc
@@ -59,7 +59,8 @@
                                        int number_of_frames,
                                        int audio_delay_milliseconds,
                                        int current_volume,
-                                       bool need_audio_processing) {
+                                       bool need_audio_processing,
+                                       bool key_pressed) {
   int total_delay_ms = 0;
   {
     base::AutoLock auto_lock(lock_);
@@ -75,11 +76,9 @@
   // Write audio samples in blocks of 10 milliseconds to the registered
   // webrtc::AudioTransport sink. Keep writing until our internal byte
   // buffer is empty.
-  // TODO(niklase): Wire up the key press detection.
   const int16* audio_buffer = audio_data;
   const int samples_per_10_msec = (sample_rate / 100);
   int accumulated_audio_samples = 0;
-  bool key_pressed = false;
   uint32_t new_volume = 0;
   while (accumulated_audio_samples < number_of_frames) {
     // Deliver 10ms of recorded 16-bit linear PCM audio.
diff --git a/content/renderer/media/webrtc_audio_device_impl.h b/content/renderer/media/webrtc_audio_device_impl.h
index ef3cb7c..b644178 100644
--- a/content/renderer/media/webrtc_audio_device_impl.h
+++ b/content/renderer/media/webrtc_audio_device_impl.h
@@ -223,7 +223,8 @@
                           int number_of_frames,
                           int audio_delay_milliseconds,
                           int current_volume,
-                          bool need_audio_processing) = 0;
+                          bool need_audio_processing,
+                          bool key_pressed) = 0;
 
   // Set the format for the capture audio parameters.
   virtual void SetCaptureFormat(const media::AudioParameters& params) = 0;
@@ -339,7 +340,8 @@
                           int number_of_frames,
                           int audio_delay_milliseconds,
                           int current_volume,
-                          bool need_audio_processing) OVERRIDE;
+                          bool need_audio_processing,
+                          bool key_pressed) OVERRIDE;
 
   // Called on the main render thread.
   virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE;
diff --git a/content/renderer/media/webrtc_audio_device_unittest.cc b/content/renderer/media/webrtc_audio_device_unittest.cc
index 6746ab6..a612531 100644
--- a/content/renderer/media/webrtc_audio_device_unittest.cc
+++ b/content/renderer/media/webrtc_audio_device_unittest.cc
@@ -221,7 +221,8 @@
                           int number_of_frames,
                           int audio_delay_milliseconds,
                           int current_volume,
-                          bool need_audio_processing) OVERRIDE {
+                          bool need_audio_processing,
+                          bool key_pressed) OVERRIDE {
     // Signal that a callback has been received.
     event_->Signal();
     return 0;
@@ -381,8 +382,13 @@
     capturer_sink->CaptureData(
         voe_channels,
         reinterpret_cast<int16*>(capture_data.get() + input_packet_size * j),
-        params.sample_rate(), params.channels(), params.frames_per_buffer(),
-        kHardwareLatencyInMs, 1.0, enable_apm);
+        params.sample_rate(),
+        params.channels(),
+        params.frames_per_buffer(),
+        kHardwareLatencyInMs,
+        1.0,
+        enable_apm,
+        false);
 
     // Receiving data from WebRtc.
     renderer_source->RenderData(
@@ -766,8 +772,6 @@
     return;
 
   EXPECT_CALL(media_observer(),
-      OnSetAudioStreamStatus(_, 1, StrEq("created")));
-  EXPECT_CALL(media_observer(),
       OnSetAudioStreamPlaying(_, 1, true));
   EXPECT_CALL(media_observer(),
       OnSetAudioStreamStatus(_, 1, StrEq("closed")));
diff --git a/content/renderer/media/webrtc_local_audio_renderer.cc b/content/renderer/media/webrtc_local_audio_renderer.cc
index 11c125f..af65d8d 100644
--- a/content/renderer/media/webrtc_local_audio_renderer.cc
+++ b/content/renderer/media/webrtc_local_audio_renderer.cc
@@ -52,13 +52,14 @@
 
 // content::WebRtcAudioCapturerSink implementation
 int WebRtcLocalAudioRenderer::CaptureData(const std::vector<int>& channels,
-                                           const int16* audio_data,
-                                           int sample_rate,
-                                           int number_of_channels,
-                                           int number_of_frames,
-                                           int audio_delay_milliseconds,
-                                           int current_volume,
-                                           bool need_audio_processing) {
+                                          const int16* audio_data,
+                                          int sample_rate,
+                                          int number_of_channels,
+                                          int number_of_frames,
+                                          int audio_delay_milliseconds,
+                                          int current_volume,
+                                          bool need_audio_processing,
+                                          bool key_pressed) {
   TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::CaptureData");
   base::AutoLock auto_lock(thread_lock_);
 
diff --git a/content/renderer/media/webrtc_local_audio_renderer.h b/content/renderer/media/webrtc_local_audio_renderer.h
index 2930393..f58aee3 100644
--- a/content/renderer/media/webrtc_local_audio_renderer.h
+++ b/content/renderer/media/webrtc_local_audio_renderer.h
@@ -78,7 +78,8 @@
                           int number_of_frames,
                           int audio_delay_milliseconds,
                           int current_volume,
-                          bool need_audio_processing) OVERRIDE;
+                          bool need_audio_processing,
+                          bool key_pressed) OVERRIDE;
 
   // Can be called on different user thread.
   virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE;
diff --git a/content/renderer/media/webrtc_local_audio_track.cc b/content/renderer/media/webrtc_local_audio_track.cc
index de86a3c..cae6bfe 100644
--- a/content/renderer/media/webrtc_local_audio_track.cc
+++ b/content/renderer/media/webrtc_local_audio_track.cc
@@ -47,7 +47,8 @@
                                         int number_of_channels,
                                         int number_of_frames,
                                         int audio_delay_milliseconds,
-                                        int volume) {
+                                        int volume,
+                                        bool key_pressed) {
   scoped_refptr<WebRtcAudioCapturer> capturer;
   std::vector<int> voe_channels;
   int sample_rate = 0;
@@ -68,10 +69,15 @@
 
   // Feed the data to the sinks.
   for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) {
-    int new_volume = (*it)->CaptureData(voe_channels, audio_data, sample_rate,
-                                        number_of_channels, number_of_frames,
-                                        audio_delay_milliseconds, volume,
-                                        need_audio_processing_);
+    int new_volume = (*it)->CaptureData(voe_channels,
+                                        audio_data,
+                                        sample_rate,
+                                        number_of_channels,
+                                        number_of_frames,
+                                        audio_delay_milliseconds,
+                                        volume,
+                                        need_audio_processing_,
+                                        key_pressed);
     if (new_volume != 0 && capturer.get())
       capturer->SetVolume(new_volume);
   }
diff --git a/content/renderer/media/webrtc_local_audio_track.h b/content/renderer/media/webrtc_local_audio_track.h
index 7cb8c85..0f4e712 100644
--- a/content/renderer/media/webrtc_local_audio_track.h
+++ b/content/renderer/media/webrtc_local_audio_track.h
@@ -61,7 +61,8 @@
                    int number_of_channels,
                    int number_of_frames,
                    int audio_delay_milliseconds,
-                   int volume);
+                   int volume,
+                   bool key_pressed);
 
   // Method called by the capturer to set the audio parameters used by source
   // of the capture data..
diff --git a/content/renderer/media/webrtc_local_audio_track_unittest.cc b/content/renderer/media/webrtc_local_audio_track_unittest.cc
index 4720e45..b75ca79 100644
--- a/content/renderer/media/webrtc_local_audio_track_unittest.cc
+++ b/content/renderer/media/webrtc_local_audio_track_unittest.cc
@@ -50,7 +50,7 @@
           static_cast<media::AudioCapturerSource::CaptureCallback*>(
               capturer_.get());
       audio_bus_->Zero();
-      callback->Capture(audio_bus_.get(), 0, 0);
+      callback->Capture(audio_bus_.get(), 0, 0, false);
 
       // Sleep 1ms to yield the resource for the main thread.
       base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
@@ -103,20 +103,27 @@
                   int number_of_frames,
                   int audio_delay_milliseconds,
                   int current_volume,
-                  bool need_audio_processing) OVERRIDE {
-    CaptureData(channels.size(), sample_rate, number_of_channels,
-                number_of_frames, audio_delay_milliseconds, current_volume,
-                need_audio_processing);
+                  bool need_audio_processing,
+                  bool key_pressed) OVERRIDE {
+    CaptureData(channels.size(),
+                sample_rate,
+                number_of_channels,
+                number_of_frames,
+                audio_delay_milliseconds,
+                current_volume,
+                need_audio_processing,
+                key_pressed);
     return 0;
   }
-  MOCK_METHOD7(CaptureData, void(int number_of_network_channels,
-                                 int sample_rate,
-                                 int number_of_channels,
-                                 int number_of_frames,
-                                 int audio_delay_milliseconds,
-                                 int current_volume,
-                                 bool need_audio_processing));
-
+  MOCK_METHOD8(CaptureData,
+               void(int number_of_network_channels,
+                    int sample_rate,
+                    int number_of_channels,
+                    int number_of_frames,
+                    int audio_delay_milliseconds,
+                    int current_volume,
+                    bool need_audio_processing,
+                    bool key_pressed));
   MOCK_METHOD1(SetCaptureFormat, void(const media::AudioParameters& params));
 };
 
@@ -173,10 +180,16 @@
   const media::AudioParameters params = capturer_->audio_parameters();
   base::WaitableEvent event(false, false);
   EXPECT_CALL(*sink, SetCaptureFormat(_)).WillOnce(Return());
-  EXPECT_CALL(*sink, CaptureData(
-      kNumberOfNetworkChannels, params.sample_rate(), params.channels(),
-      params.frames_per_buffer(), 0, 0, false))
-      .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event));
+  EXPECT_CALL(*sink,
+              CaptureData(kNumberOfNetworkChannels,
+                          params.sample_rate(),
+                          params.channels(),
+                          params.frames_per_buffer(),
+                          0,
+                          0,
+                          false,
+                          false)).Times(AtLeast(1))
+      .WillRepeatedly(SignalEvent(&event));
   track->AddSink(sink.get());
 
   EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
@@ -207,18 +220,29 @@
   const media::AudioParameters params = capturer_->audio_parameters();
   base::WaitableEvent event(false, false);
   EXPECT_CALL(*sink, SetCaptureFormat(_)).WillOnce(Return());
-  EXPECT_CALL(*sink, CaptureData(
-      1, params.sample_rate(), params.channels(),
-      params.frames_per_buffer(), 0, 0, false))
-      .Times(0);
+  EXPECT_CALL(*sink,
+              CaptureData(1,
+                          params.sample_rate(),
+                          params.channels(),
+                          params.frames_per_buffer(),
+                          0,
+                          0,
+                          false,
+                          false)).Times(0);
   track->AddSink(sink.get());
   EXPECT_FALSE(event.TimedWait(TestTimeouts::tiny_timeout()));
 
   event.Reset();
-  EXPECT_CALL(*sink, CaptureData(
-      1, params.sample_rate(), params.channels(),
-      params.frames_per_buffer(), 0, 0, false))
-      .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event));
+  EXPECT_CALL(*sink,
+              CaptureData(1,
+                          params.sample_rate(),
+                          params.channels(),
+                          params.frames_per_buffer(),
+                          0,
+                          0,
+                          false,
+                          false)).Times(AtLeast(1))
+      .WillRepeatedly(SignalEvent(&event));
   EXPECT_TRUE(track->set_enabled(true));
   EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
   track->RemoveSink(sink.get());
@@ -243,10 +267,16 @@
   const media::AudioParameters params = capturer_->audio_parameters();
   base::WaitableEvent event_1(false, false);
   EXPECT_CALL(*sink_1, SetCaptureFormat(_)).WillOnce(Return());
-  EXPECT_CALL(*sink_1, CaptureData(
-      1, params.sample_rate(), params.channels(),
-      params.frames_per_buffer(), 0, 0, false))
-      .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event_1));
+  EXPECT_CALL(*sink_1,
+              CaptureData(1,
+                          params.sample_rate(),
+                          params.channels(),
+                          params.frames_per_buffer(),
+                          0,
+                          0,
+                          false,
+                          false)).Times(AtLeast(1))
+      .WillRepeatedly(SignalEvent(&event_1));
   track_1->AddSink(sink_1.get());
   EXPECT_TRUE(event_1.TimedWait(TestTimeouts::tiny_timeout()));
 
@@ -264,14 +294,26 @@
   scoped_ptr<MockWebRtcAudioCapturerSink> sink_2(
         new MockWebRtcAudioCapturerSink());
   EXPECT_CALL(*sink_2, SetCaptureFormat(_)).WillOnce(Return());
-  EXPECT_CALL(*sink_1, CaptureData(
-      1, params.sample_rate(), params.channels(),
-      params.frames_per_buffer(), 0, 0, false))
-      .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event_1));
-  EXPECT_CALL(*sink_2, CaptureData(
-      1, params.sample_rate(), params.channels(),
-      params.frames_per_buffer(), 0, 0, false))
-      .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event_2));
+  EXPECT_CALL(*sink_1,
+              CaptureData(1,
+                          params.sample_rate(),
+                          params.channels(),
+                          params.frames_per_buffer(),
+                          0,
+                          0,
+                          false,
+                          false)).Times(AtLeast(1))
+      .WillRepeatedly(SignalEvent(&event_1));
+  EXPECT_CALL(*sink_2,
+              CaptureData(1,
+                          params.sample_rate(),
+                          params.channels(),
+                          params.frames_per_buffer(),
+                          0,
+                          0,
+                          false,
+                          false)).Times(AtLeast(1))
+      .WillRepeatedly(SignalEvent(&event_2));
   track_2->AddSink(sink_2.get());
   EXPECT_TRUE(event_1.TimedWait(TestTimeouts::tiny_timeout()));
   EXPECT_TRUE(event_2.TimedWait(TestTimeouts::tiny_timeout()));
@@ -319,7 +361,7 @@
   scoped_ptr<MockWebRtcAudioCapturerSink> sink(
       new MockWebRtcAudioCapturerSink());
   event.Reset();
-  EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false))
+  EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false, false))
       .Times(AnyNumber()).WillRepeatedly(Return());
   EXPECT_CALL(*sink, SetCaptureFormat(_)).Times(1);
   track_1->AddSink(sink.get());
@@ -339,7 +381,7 @@
   track_1->Stop();
   track_1 = NULL;
 
-  EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false))
+  EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false, false))
       .Times(AnyNumber()).WillRepeatedly(Return());
   EXPECT_CALL(*sink, SetCaptureFormat(_)).Times(1);
   track_2->AddSink(sink.get());
@@ -396,8 +438,10 @@
   // Verify the data flow by connecting the |sink_1| to |track_1|.
   scoped_ptr<MockWebRtcAudioCapturerSink> sink_1(
       new MockWebRtcAudioCapturerSink());
-  EXPECT_CALL(*sink_1.get(), CaptureData(kNumberOfNetworkChannelsForTrack1,
-                                         48000, 2, _, 0, 0, false))
+  EXPECT_CALL(
+      *sink_1.get(),
+      CaptureData(
+          kNumberOfNetworkChannelsForTrack1, 48000, 2, _, 0, 0, false, false))
       .Times(AnyNumber()).WillRepeatedly(Return());
   EXPECT_CALL(*sink_1.get(), SetCaptureFormat(_)).Times(1);
   track_1->AddSink(sink_1.get());
@@ -433,8 +477,10 @@
   // Verify the data flow by connecting the |sink_2| to |track_2|.
   scoped_ptr<MockWebRtcAudioCapturerSink> sink_2(
       new MockWebRtcAudioCapturerSink());
-  EXPECT_CALL(*sink_2, CaptureData(kNumberOfNetworkChannelsForTrack2,
-                                     44100, 1, _, 0, 0, false))
+  EXPECT_CALL(
+      *sink_2,
+      CaptureData(
+          kNumberOfNetworkChannelsForTrack2, 44100, 1, _, 0, 0, false, false))
       .Times(AnyNumber()).WillRepeatedly(Return());
   EXPECT_CALL(*sink_2, SetCaptureFormat(_)).Times(1);
   track_2->AddSink(sink_2.get());
diff --git a/content/renderer/npapi/webplugin_impl.cc b/content/renderer/npapi/webplugin_impl.cc
index 21e80b6..d898011 100644
--- a/content/renderer/npapi/webplugin_impl.cc
+++ b/content/renderer/npapi/webplugin_impl.cc
@@ -716,7 +716,7 @@
 
   if (strcmp(method, "GET") != 0) {
     // We're only going to route HTTP/HTTPS requests
-    if (!(complete_url.SchemeIs("http") || complete_url.SchemeIs("https")))
+    if (!complete_url.SchemeIsHTTPOrHTTPS())
       return INVALID_URL;
   }
 
diff --git a/content/renderer/pepper/OWNERS b/content/renderer/pepper/OWNERS
index c5db5bd..cb5435c 100644
--- a/content/renderer/pepper/OWNERS
+++ b/content/renderer/pepper/OWNERS
@@ -1,3 +1,4 @@
+bbudge@chromium.org
 dmichael@chromium.org
 raymes@chromium.org
 yzshen@chromium.org
diff --git a/content/renderer/pepper/host_var_tracker_unittest.cc b/content/renderer/pepper/host_var_tracker_unittest.cc
index 0c4d00d..24932db 100644
--- a/content/renderer/pepper/host_var_tracker_unittest.cc
+++ b/content/renderer/pepper/host_var_tracker_unittest.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/pepper/ppapi_unittest.h"
-
 #include "base/memory/scoped_ptr.h"
 #include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/host_var_tracker.h"
@@ -11,6 +9,7 @@
 #include "content/renderer/pepper/npapi_glue.h"
 #include "content/renderer/pepper/npobject_var.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/test/ppapi_unittest.h"
 #include "ppapi/c/pp_var.h"
 #include "ppapi/c/ppp_instance.h"
 #include "third_party/npapi/bindings/npruntime.h"
diff --git a/content/renderer/pepper/message_channel.cc b/content/renderer/pepper/message_channel.cc
index 7cd7430..a468880 100644
--- a/content/renderer/pepper/message_channel.cc
+++ b/content/renderer/pepper/message_channel.cc
@@ -16,6 +16,7 @@
 #include "content/renderer/pepper/plugin_module.h"
 #include "content/renderer/pepper/v8_var_converter.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/scoped_pp_var.h"
 #include "ppapi/shared_impl/var.h"
 #include "ppapi/shared_impl/var_tracker.h"
 #include "third_party/WebKit/public/web/WebBindings.h"
@@ -67,42 +68,6 @@
   return WebBindings::getStringIdentifier(kPostMessage) == identifier;
 }
 
-bool NPVariantToPPVar(const NPVariant* variant, PP_Var* result) {
-  switch (variant->type) {
-    case NPVariantType_Void:
-      *result = PP_MakeUndefined();
-      return true;
-    case NPVariantType_Null:
-      *result = PP_MakeNull();
-      return true;
-    case NPVariantType_Bool:
-      *result = PP_MakeBool(PP_FromBool(NPVARIANT_TO_BOOLEAN(*variant)));
-      return true;
-    case NPVariantType_Int32:
-      *result = PP_MakeInt32(NPVARIANT_TO_INT32(*variant));
-      return true;
-    case NPVariantType_Double:
-      *result = PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant));
-      return true;
-    case NPVariantType_String:
-      *result = StringVar::StringToPPVar(
-          NPVARIANT_TO_STRING(*variant).UTF8Characters,
-          NPVARIANT_TO_STRING(*variant).UTF8Length);
-      return true;
-    case NPVariantType_Object: {
-      // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it
-      // shouldn't result in a deep copy.
-      v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant);
-      if (!V8VarConverter::FromV8Value(v8_value, v8::Context::GetCurrent(),
-                                       result)) {
-        return false;
-      }
-      return true;
-    }
-  }
-  return false;
-}
-
 // Copy a PP_Var in to a PP_Var that is appropriate for sending via postMessage.
 // This currently just copies the value.  For a string Var, the result is a
 // PP_Var with the a copy of |var|'s string contents and a reference count of 1.
@@ -188,15 +153,7 @@
   if (IdentifierIsPostMessage(name) && (arg_count == 1)) {
     MessageChannel* message_channel = ToMessageChannel(np_obj);
     if (message_channel) {
-      PP_Var argument = PP_MakeUndefined();
-      if (!NPVariantToPPVar(&args[0], &argument)) {
-        PpapiGlobals::Get()->LogWithSource(
-            message_channel->instance()->pp_instance(),
-            PP_LOGLEVEL_ERROR, std::string(), kV8ToVarConversionError);
-        return false;
-      }
-      message_channel->PostMessageToNative(argument);
-      PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(argument);
+      message_channel->NPVariantToPPVar(&args[0]);
       return true;
     } else {
       return false;
@@ -321,6 +278,19 @@
 }  // namespace
 
 // MessageChannel --------------------------------------------------------------
+struct MessageChannel::VarConversionResult {
+  VarConversionResult(const ppapi::ScopedPPVar& r, bool s)
+      : result(r),
+        success(s),
+        conversion_completed(true) {}
+  VarConversionResult()
+      : success(false),
+        conversion_completed(false) {}
+  ppapi::ScopedPPVar result;
+  bool success;
+  bool conversion_completed;
+};
+
 MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {
 }
 
@@ -341,6 +311,59 @@
   np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
 }
 
+void MessageChannel::NPVariantToPPVar(const NPVariant* variant) {
+  converted_var_queue_.push_back(VarConversionResult());
+  std::list<VarConversionResult>::iterator result_iterator =
+      --converted_var_queue_.end();
+  switch (variant->type) {
+    case NPVariantType_Void:
+      NPVariantToPPVarComplete(result_iterator,
+          ppapi::ScopedPPVar(PP_MakeUndefined()), true);
+      return;
+    case NPVariantType_Null:
+      NPVariantToPPVarComplete(result_iterator,
+          ppapi::ScopedPPVar(PP_MakeNull()), true);
+      return;
+    case NPVariantType_Bool:
+      NPVariantToPPVarComplete(result_iterator,
+          ppapi::ScopedPPVar(
+              PP_MakeBool(PP_FromBool(NPVARIANT_TO_BOOLEAN(*variant)))),
+          true);
+      return;
+    case NPVariantType_Int32:
+      NPVariantToPPVarComplete(result_iterator,
+          ppapi::ScopedPPVar(
+              PP_MakeInt32(NPVARIANT_TO_INT32(*variant))),
+          true);
+      return;
+    case NPVariantType_Double:
+      NPVariantToPPVarComplete(result_iterator,
+          ppapi::ScopedPPVar(
+              PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant))),
+          true);
+      return;
+    case NPVariantType_String:
+      NPVariantToPPVarComplete(result_iterator,
+          ppapi::ScopedPPVar(ppapi::ScopedPPVar::PassRef(),
+                             StringVar::StringToPPVar(
+                                 NPVARIANT_TO_STRING(*variant).UTF8Characters,
+                                 NPVARIANT_TO_STRING(*variant).UTF8Length)),
+          true);
+      return;
+    case NPVariantType_Object: {
+      // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it
+      // shouldn't result in a deep copy.
+      v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant);
+      V8VarConverter().FromV8Value(v8_value, v8::Context::GetCurrent(),
+          base::Bind(&MessageChannel::NPVariantToPPVarComplete,
+              weak_ptr_factory_.GetWeakPtr(), result_iterator));
+      return;
+    }
+  }
+  NPVariantToPPVarComplete(result_iterator,
+      ppapi::ScopedPPVar(PP_MakeUndefined()), false);
+}
+
 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
   v8::HandleScope scope;
 
@@ -360,7 +383,7 @@
   v8::Context::Scope context_scope(context);
 
   v8::Handle<v8::Value> v8_val;
-  if (!V8VarConverter::ToV8Value(message_data, context, &v8_val)) {
+  if (!V8VarConverter().ToV8Value(message_data, context, &v8_val)) {
     PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(),
         PP_LOGLEVEL_ERROR, std::string(), kVarToV8ConversionError);
     return;
@@ -419,6 +442,24 @@
     early_message_queue_state_ = QUEUE_MESSAGES;
 }
 
+void MessageChannel::NPVariantToPPVarComplete(
+    const std::list<VarConversionResult>::iterator& result_iterator,
+    const ppapi::ScopedPPVar& result,
+    bool success) {
+  *result_iterator = VarConversionResult(result, success);
+  std::list<VarConversionResult>::iterator it = converted_var_queue_.begin();
+  while (it != converted_var_queue_.end() && it->conversion_completed) {
+    if (it->success) {
+      PostMessageToNative(it->result.get());
+    } else {
+      PpapiGlobals::Get()->LogWithSource(instance()->pp_instance(),
+          PP_LOGLEVEL_ERROR, std::string(), kV8ToVarConversionError);
+    }
+
+    converted_var_queue_.erase(it++);
+  }
+}
+
 void MessageChannel::DrainEarlyMessageQueue() {
   // Take a reference on the PluginInstance. This is because JavaScript code
   // may delete the plugin, which would destroy the PluginInstance and its
diff --git a/content/renderer/pepper/message_channel.h b/content/renderer/pepper/message_channel.h
index b377b51..9c8c28d 100644
--- a/content/renderer/pepper/message_channel.h
+++ b/content/renderer/pepper/message_channel.h
@@ -6,6 +6,7 @@
 #define CONTENT_RENDERER_PEPPER_MESSAGE_CHANNEL_H_
 
 #include <deque>
+#include <list>
 
 #include "base/memory/weak_ptr.h"
 #include "ppapi/shared_impl/resource.h"
@@ -14,6 +15,10 @@
 
 struct PP_Var;
 
+namespace ppapi {
+class ScopedPPVar;
+}
+
 namespace content {
 
 class PepperPluginInstanceImpl;
@@ -47,6 +52,10 @@
   explicit MessageChannel(PepperPluginInstanceImpl* instance);
   ~MessageChannel();
 
+  // Converts an NPVariant to a PP_Var. This occurs asynchronously and
+  // NPVariantToPPVarComplete will be called upon completion.
+  void NPVariantToPPVar(const NPVariant* variant);
+
   // Post a message to the onmessage handler for this channel's instance
   // asynchronously.
   void PostMessageToJavaScript(PP_Var message_data);
@@ -76,6 +85,17 @@
   void StopQueueingJavaScriptMessages();
 
  private:
+  // Struct for storing the result of a NPVariant being converted to a PP_Var.
+  struct VarConversionResult;
+
+  // This is called when an NPVariant is finished being converted.
+  // |result_iteartor| is an iterator into |converted_var_queue_| where the
+  // result should be stored.
+  void NPVariantToPPVarComplete(
+      const std::list<VarConversionResult>::iterator& result_iterator,
+      const ppapi::ScopedPPVar& result,
+      bool success);
+
   PepperPluginInstanceImpl* instance_;
 
   // We pass all non-postMessage calls through to the passthrough_object_.
@@ -113,6 +133,12 @@
   };
   EarlyMessageQueueState early_message_queue_state_;
 
+  // This queue stores vars that have been converted from NPVariants. Because
+  // conversion can happen asynchronously, the queue stores the var until all
+  // previous vars have been converted before calling PostMessage to ensure that
+  // the order in which messages are processed is preserved.
+  std::list<VarConversionResult> converted_var_queue_;
+
   DISALLOW_COPY_AND_ASSIGN(MessageChannel);
 };
 
diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.cc b/content/renderer/pepper/mock_renderer_ppapi_host.cc
index e1de551..8000d40 100644
--- a/content/renderer/pepper/mock_renderer_ppapi_host.cc
+++ b/content/renderer/pepper/mock_renderer_ppapi_host.cc
@@ -78,12 +78,12 @@
   return false;
 }
 
-void MockRendererPpapiHost::CreateBrowserResourceHost(
+void MockRendererPpapiHost::CreateBrowserResourceHosts(
     PP_Instance instance,
-    const IPC::Message& nested_msg,
-    const base::Callback<void(int)>& callback) const {
+    const std::vector<IPC::Message>& nested_msg,
+    const base::Callback<void(const std::vector<int>&)>& callback) const {
   NOTIMPLEMENTED();
-  callback.Run(0);
+  callback.Run(std::vector<int>());
   return;
 }
 
diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.h b/content/renderer/pepper/mock_renderer_ppapi_host.h
index 7a18ad2..8f22d23 100644
--- a/content/renderer/pepper/mock_renderer_ppapi_host.h
+++ b/content/renderer/pepper/mock_renderer_ppapi_host.h
@@ -49,10 +49,11 @@
       base::PlatformFile handle,
       bool should_close_source) OVERRIDE;
   virtual bool IsRunningInProcess() const OVERRIDE;
-  virtual void CreateBrowserResourceHost(
+  virtual void CreateBrowserResourceHosts(
       PP_Instance instance,
-      const IPC::Message& nested_msg,
-      const base::Callback<void(int)>& callback) const OVERRIDE;
+      const std::vector<IPC::Message>& nested_msgs,
+      const base::Callback<void(
+          const std::vector<int>&)>& callback) const OVERRIDE;
 
  private:
   ppapi::proxy::ResourceMessageTestSink sink_;
diff --git a/content/renderer/pepper/pepper_browser_connection.cc b/content/renderer/pepper/pepper_browser_connection.cc
index 3032576..6bbec3d 100644
--- a/content/renderer/pepper/pepper_browser_connection.cc
+++ b/content/renderer/pepper/pepper_browser_connection.cc
@@ -32,8 +32,8 @@
 
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(PepperBrowserConnection, msg)
-    IPC_MESSAGE_HANDLER(PpapiHostMsg_CreateResourceHostFromHostReply,
-                        OnMsgCreateResourceHostFromHostReply)
+    IPC_MESSAGE_HANDLER(PpapiHostMsg_CreateResourceHostsFromHostReply,
+                        OnMsgCreateResourceHostsFromHostReply)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -49,9 +49,9 @@
       instance,
       // Browser provides the render process id.
       PepperRendererInstanceData(0,
-                                  render_view_id,
-                                  document_url,
-                                  plugin_url)));
+                                 render_view_id,
+                                 document_url,
+                                 plugin_url)));
 }
 
 void PepperBrowserConnection::DidDeleteInProcessInstance(PP_Instance instance) {
@@ -61,17 +61,17 @@
 void PepperBrowserConnection::SendBrowserCreate(
     int child_process_id,
     PP_Instance instance,
-    const IPC::Message& nested_msg,
+    const std::vector<IPC::Message>& nested_msgs,
     const PendingResourceIDCallback& callback) {
   int32_t sequence_number = GetNextSequence();
   pending_create_map_[sequence_number] = callback;
   ppapi::proxy::ResourceMessageCallParams params(0, sequence_number);
-  Send(new PpapiHostMsg_CreateResourceHostFromHost(
+  Send(new PpapiHostMsg_CreateResourceHostsFromHost(
       routing_id(),
       child_process_id,
       params,
       instance,
-      nested_msg));
+      nested_msgs));
 }
 
 void PepperBrowserConnection::SendBrowserFileRefGetInfo(
@@ -84,15 +84,15 @@
       routing_id(), child_process_id, sequence_number, resources));
 }
 
-void PepperBrowserConnection::OnMsgCreateResourceHostFromHostReply(
+void PepperBrowserConnection::OnMsgCreateResourceHostsFromHostReply(
     int32_t sequence_number,
-    int pending_resource_host_id) {
+    const std::vector<int>& pending_resource_host_ids) {
   // Check that the message is destined for the plugin this object is associated
   // with.
   std::map<int32_t, PendingResourceIDCallback>::iterator it =
       pending_create_map_.find(sequence_number);
   if (it != pending_create_map_.end()) {
-    it->second.Run(pending_resource_host_id);
+    it->second.Run(pending_resource_host_ids);
     pending_create_map_.erase(it);
   } else {
     NOTREACHED();
diff --git a/content/renderer/pepper/pepper_browser_connection.h b/content/renderer/pepper/pepper_browser_connection.h
index 9fde7d2..ab43409 100644
--- a/content/renderer/pepper/pepper_browser_connection.h
+++ b/content/renderer/pepper/pepper_browser_connection.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
@@ -26,7 +27,8 @@
     : public RenderViewObserver,
       public RenderViewObserverTracker<PepperBrowserConnection> {
  public:
-  typedef base::Callback<void(int)> PendingResourceIDCallback;
+  typedef base::Callback<void(const std::vector<int>&)>
+      PendingResourceIDCallback;
   typedef base::Callback<void(
       const std::vector<PP_Resource>&,
       const std::vector<PP_FileSystemType>&,
@@ -41,12 +43,12 @@
   // TODO(teravest): Instead of having separate methods per message, we should
   // add generic functionality similar to PluginResource::Call().
 
-  // Sends a request to the browser to create a ResourceHost for the given
+  // Sends a request to the browser to create ResourceHosts for the given
   // |instance| of a plugin identified by |child_process_id|. |callback| will be
-  // run when a reply is received with the pending resource ID.
+  // run when a reply is received with the pending resource IDs.
   void SendBrowserCreate(PP_Instance instance,
                          int child_process_id,
-                         const IPC::Message& create_message,
+                         const std::vector<IPC::Message>& create_messages,
                          const PendingResourceIDCallback& callback);
 
   // Sends a request to the browser to get information about the given FileRef
@@ -67,8 +69,9 @@
 
  private:
   // Message handlers.
-  void OnMsgCreateResourceHostFromHostReply(int32_t sequence_number,
-                                            int pending_resource_host_id);
+  void OnMsgCreateResourceHostsFromHostReply(
+      int32_t sequence_number,
+      const std::vector<int>& pending_resource_host_ids);
   void OnMsgFileRefGetInfoReply(
       int32_t sequence_number,
       const std::vector<PP_Resource>& resources,
diff --git a/content/renderer/pepper/pepper_file_io_host.cc b/content/renderer/pepper/pepper_file_io_host.cc
index 73255e2..6b9cfc5 100644
--- a/content/renderer/pepper/pepper_file_io_host.cc
+++ b/content/renderer/pepper/pepper_file_io_host.cc
@@ -142,8 +142,8 @@
       quota_policy_(quota::kQuotaLimitTypeUnknown),
       is_running_in_process_(host->IsRunningInProcess()),
       open_flags_(0),
-      weak_factory_(this),
-      routing_id_(RenderThreadImpl::current()->GenerateRoutingID()) {
+      routing_id_(RenderThreadImpl::current()->GenerateRoutingID()),
+      weak_factory_(this) {
       ChildThread::current()->AddRoute(routing_id_, this);
 }
 
diff --git a/content/renderer/pepper/pepper_file_io_host.h b/content/renderer/pepper/pepper_file_io_host.h
index 3384e34..0e26174 100644
--- a/content/renderer/pepper/pepper_file_io_host.h
+++ b/content/renderer/pepper/pepper_file_io_host.h
@@ -130,8 +130,6 @@
 
   int32_t open_flags_;
 
-  base::WeakPtrFactory<PepperFileIOHost> weak_factory_;
-
   ppapi::FileIOStateManager state_manager_;
 
   int routing_id_;
@@ -141,6 +139,8 @@
 
   IDMap<AsyncOpenFileCallback> pending_async_open_files_;
 
+  base::WeakPtrFactory<PepperFileIOHost> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PepperFileIOHost);
 };
 
diff --git a/content/renderer/pepper/pepper_file_system_host.cc b/content/renderer/pepper/pepper_file_system_host.cc
index f823e38..00c580b 100644
--- a/content/renderer/pepper/pepper_file_system_host.cc
+++ b/content/renderer/pepper/pepper_file_system_host.cc
@@ -48,10 +48,10 @@
                                            PP_FileSystemType type)
     : ResourceHost(host->GetPpapiHost(), instance, resource),
       renderer_ppapi_host_(host),
-      weak_factory_(this),
       type_(type),
       opened_(false),
-      called_open_(false) {
+      called_open_(false),
+      weak_factory_(this) {
 }
 
 PepperFileSystemHost::~PepperFileSystemHost() {
diff --git a/content/renderer/pepper/pepper_file_system_host.h b/content/renderer/pepper/pepper_file_system_host.h
index 1f44051..3ff8d4d 100644
--- a/content/renderer/pepper/pepper_file_system_host.h
+++ b/content/renderer/pepper/pepper_file_system_host.h
@@ -50,13 +50,14 @@
 
   RendererPpapiHost* renderer_ppapi_host_;
   ppapi::host::ReplyMessageContext reply_context_;
-  base::WeakPtrFactory<PepperFileSystemHost> weak_factory_;
 
   PP_FileSystemType type_;
   bool opened_;  // whether open is successful.
   GURL root_url_;
   bool called_open_;  // whether open has been called.
 
+  base::WeakPtrFactory<PepperFileSystemHost> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PepperFileSystemHost);
 };
 
diff --git a/content/renderer/pepper/pepper_video_destination_host.h b/content/renderer/pepper/pepper_video_destination_host.h
index fd5cfe7..1f48190 100644
--- a/content/renderer/pepper/pepper_video_destination_host.h
+++ b/content/renderer/pepper/pepper_video_destination_host.h
@@ -40,10 +40,10 @@
 
   RendererPpapiHost* renderer_ppapi_host_;
 
-  base::WeakPtrFactory<PepperVideoDestinationHost> weak_factory_;
-
   scoped_ptr<FrameWriterInterface> frame_writer_;
 
+  base::WeakPtrFactory<PepperVideoDestinationHost> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PepperVideoDestinationHost);
 };
 
diff --git a/content/renderer/pepper/pepper_video_source_host.cc b/content/renderer/pepper/pepper_video_source_host.cc
index eb37144..2a8bd93 100644
--- a/content/renderer/pepper/pepper_video_source_host.cc
+++ b/content/renderer/pepper/pepper_video_source_host.cc
@@ -65,10 +65,10 @@
     PP_Resource resource)
     : ResourceHost(host->GetPpapiHost(), instance, resource),
       renderer_ppapi_host_(host),
-      weak_factory_(this),
       source_handler_(new VideoSourceHandler(NULL)),
-      frame_receiver_(new FrameReceiver(weak_factory_.GetWeakPtr())),
-      get_frame_pending_(false) {
+      get_frame_pending_(false),
+      weak_factory_(this) {
+  frame_receiver_ = new FrameReceiver(weak_factory_.GetWeakPtr());
 }
 
 PepperVideoSourceHost::~PepperVideoSourceHost() {
diff --git a/content/renderer/pepper/pepper_video_source_host.h b/content/renderer/pepper/pepper_video_source_host.h
index e5fbaa8..f2ddfa4 100644
--- a/content/renderer/pepper/pepper_video_source_host.h
+++ b/content/renderer/pepper/pepper_video_source_host.h
@@ -71,8 +71,6 @@
 
   RendererPpapiHost* renderer_ppapi_host_;
 
-  base::WeakPtrFactory<PepperVideoSourceHost> weak_factory_;
-
   ppapi::host::ReplyMessageContext reply_context_;
 
   scoped_ptr<VideoSourceHandler> source_handler_;
@@ -81,6 +79,8 @@
   scoped_ptr<cricket::VideoFrame> last_frame_;
   bool get_frame_pending_;
 
+  base::WeakPtrFactory<PepperVideoSourceHost> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PepperVideoSourceHost);
 };
 
diff --git a/content/renderer/pepper/plugin_module.cc b/content/renderer/pepper/plugin_module.cc
index 7a06929..04a5041 100644
--- a/content/renderer/pepper/plugin_module.cc
+++ b/content/renderer/pepper/plugin_module.cc
@@ -21,7 +21,6 @@
 #include "content/renderer/pepper/pepper_hung_plugin_filter.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
 #include "content/renderer/pepper/pepper_plugin_registry.h"
-#include "content/renderer/pepper/ppb_gpu_blacklist_private_impl.h"
 #include "content/renderer/pepper/ppb_image_data_impl.h"
 #include "content/renderer/pepper/ppb_proxy_impl.h"
 #include "content/renderer/pepper/ppb_scrollbar_impl.h"
@@ -107,7 +106,6 @@
 #include "ppapi/c/private/ppb_flash_menu.h"
 #include "ppapi/c/private/ppb_flash_message_loop.h"
 #include "ppapi/c/private/ppb_flash_print.h"
-#include "ppapi/c/private/ppb_gpu_blacklist_private.h"
 #include "ppapi/c/private/ppb_host_resolver_private.h"
 #include "ppapi/c/private/ppb_instance_private.h"
 #include "ppapi/c/private/ppb_network_list_private.h"
diff --git a/content/renderer/pepper/ppapi_unittest.cc b/content/renderer/pepper/ppapi_unittest.cc
deleted file mode 100644
index f46eb6b..0000000
--- a/content/renderer/pepper/ppapi_unittest.cc
+++ /dev/null
@@ -1,118 +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/renderer/pepper/ppapi_unittest.h"
-
-#include "base/message_loop/message_loop.h"
-#include "content/renderer/pepper/gfx_conversion.h"
-#include "content/renderer/pepper/host_globals.h"
-#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
-#include "content/renderer/pepper/plugin_module.h"
-#include "ppapi/c/pp_errors.h"
-#include "ppapi/c/pp_var.h"
-#include "ppapi/c/ppp_instance.h"
-#include "ppapi/shared_impl/ppapi_globals.h"
-#include "ppapi/shared_impl/ppapi_permissions.h"
-
-namespace content {
-
-namespace {
-
-PpapiUnittest* current_unittest = NULL;
-
-const void* MockGetInterface(const char* interface_name) {
-  return current_unittest->GetMockInterface(interface_name);
-}
-
-int MockInitializeModule(PP_Module, PPB_GetInterface) {
-  return PP_OK;
-}
-
-// PPP_Instance implementation ------------------------------------------------
-
-PP_Bool Instance_DidCreate(PP_Instance pp_instance,
-                           uint32_t argc,
-                           const char* argn[],
-                           const char* argv[]) {
-  return PP_TRUE;
-}
-
-void Instance_DidDestroy(PP_Instance instance) {
-}
-
-void Instance_DidChangeView(PP_Instance pp_instance, PP_Resource view) {
-}
-
-void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
-}
-
-PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
-                                    PP_Resource pp_url_loader) {
-  return PP_FALSE;
-}
-
-static PPP_Instance mock_instance_interface = {
-  &Instance_DidCreate,
-  &Instance_DidDestroy,
-  &Instance_DidChangeView,
-  &Instance_DidChangeFocus,
-  &Instance_HandleDocumentLoad
-};
-
-}  // namespace
-
-// PpapiUnittest --------------------------------------------------------------
-
-PpapiUnittest::PpapiUnittest() {
-  DCHECK(!current_unittest);
-  current_unittest = this;
-}
-
-PpapiUnittest::~PpapiUnittest() {
-  DCHECK(current_unittest == this);
-  current_unittest = NULL;
-}
-
-void PpapiUnittest::SetUp() {
-  message_loop_.reset(new base::MessageLoop());
-
-  // Initialize the mock module.
-  module_ = new PluginModule("Mock plugin", base::FilePath(),
-                             ppapi::PpapiPermissions());
-  ppapi::PpapiGlobals::Get()->ResetMainThreadMessageLoopForTesting();
-  PepperPluginInfo::EntryPoints entry_points;
-  entry_points.get_interface = &MockGetInterface;
-  entry_points.initialize_module = &MockInitializeModule;
-  ASSERT_TRUE(module_->InitAsInternalPlugin(entry_points));
-
-  // Initialize the mock instance.
-  instance_ = PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL());
-}
-
-void PpapiUnittest::TearDown() {
-  instance_ = NULL;
-  module_ = NULL;
-  message_loop_.reset();
-  PluginModule::ResetHostGlobalsForTest();
-}
-
-const void* PpapiUnittest::GetMockInterface(const char* interface_name) const {
-  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE_1_0) == 0)
-    return &mock_instance_interface;
-  return NULL;
-}
-
-void PpapiUnittest::ShutdownModule() {
-  DCHECK(instance_->HasOneRef());
-  instance_ = NULL;
-  DCHECK(module_->HasOneRef());
-  module_ = NULL;
-}
-
-void PpapiUnittest::SetViewSize(int width, int height) const {
-  instance_->view_data_.rect = PP_FromGfxRect(gfx::Rect(0, 0, width, height));
-  instance_->view_data_.clip_rect = instance_->view_data_.rect;
-}
-
-}  // namespace content
diff --git a/content/renderer/pepper/ppapi_unittest.h b/content/renderer/pepper/ppapi_unittest.h
deleted file mode 100644
index 4bca4e9..0000000
--- a/content/renderer/pepper/ppapi_unittest.h
+++ /dev/null
@@ -1,55 +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 CONTENT_RENDERER_PEPPER_PPAPI_UNITTEST_H_
-#define CONTENT_RENDERER_PEPPER_PPAPI_UNITTEST_H_
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-class MessageLoop;
-}
-
-namespace content {
-
-class PepperPluginInstanceImpl;
-class PluginModule;
-
-class PpapiUnittest : public testing::Test {
- public:
-  PpapiUnittest();
-  virtual ~PpapiUnittest();
-
-  virtual void SetUp();
-  virtual void TearDown();
-
-  PluginModule* module() const { return module_.get(); }
-  PepperPluginInstanceImpl* instance() const { return instance_.get(); }
-
-  // Provides access to the interfaces implemented by the test. The default one
-  // implements PPP_INSTANCE.
-  virtual const void* GetMockInterface(const char* interface_name) const;
-
-  // Deletes the instance and module to simulate module shutdown.
-  void ShutdownModule();
-
-  // Sets the view size of the plugin instance.
-  void SetViewSize(int width, int height) const;
-
- private:
-  // Note: module must be declared first since we want it to get destroyed last.
-  scoped_refptr<PluginModule> module_;
-  scoped_refptr<PepperPluginInstanceImpl> instance_;
-
-  scoped_ptr<base::MessageLoop> message_loop_;
-
-  DISALLOW_COPY_AND_ASSIGN(PpapiUnittest);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_PEPPER_PPAPI_UNITTEST_H_
diff --git a/content/renderer/pepper/ppb_gpu_blacklist_private_impl.cc b/content/renderer/pepper/ppb_gpu_blacklist_private_impl.cc
deleted file mode 100644
index 8db33bd..0000000
--- a/content/renderer/pepper/ppb_gpu_blacklist_private_impl.cc
+++ /dev/null
@@ -1,38 +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 "content/renderer/pepper/ppb_gpu_blacklist_private_impl.h"
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "content/public/common/content_switches.h"
-
-// todo(nfullagar): Remove this private interface when the SRPC proxy is
-// permanently disabled.
-
-namespace content {
-
-namespace {
-
-PP_Bool IsGpuBlacklisted() {
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line)
-    return PP_FromBool(
-        command_line->HasSwitch(switches::kDisablePepper3d));
-  return PP_TRUE;
-}
-
-}  // namespace
-
-const PPB_GpuBlacklist_Private ppb_gpu_blacklist = {
-  &IsGpuBlacklisted,
-};
-
-// static
-const PPB_GpuBlacklist_Private* PPB_GpuBlacklist_Private_Impl::GetInterface() {
-  return &ppb_gpu_blacklist;
-}
-
-}  // namespace content
-
diff --git a/content/renderer/pepper/ppb_gpu_blacklist_private_impl.h b/content/renderer/pepper/ppb_gpu_blacklist_private_impl.h
deleted file mode 100644
index 7ff2e90..0000000
--- a/content/renderer/pepper/ppb_gpu_blacklist_private_impl.h
+++ /dev/null
@@ -1,20 +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 CONTENT_RENDERER_PEPPER_PPB_GPU_BLACKLIST_PRIVATE_IMPL_H_
-#define CONTENT_RENDERER_PEPPER_PPB_GPU_BLACKLIST_PRIVATE_IMPL_H_
-
-#include "ppapi/c/private/ppb_gpu_blacklist_private.h"
-
-namespace content {
-
-class PPB_GpuBlacklist_Private_Impl {
- public:
-  static const PPB_GpuBlacklist_Private* GetInterface();
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_PEPPER_PPB_GPU_BLACKLIST_PRIVATE_IMPL_H_
-
diff --git a/content/renderer/pepper/quota_file_io_unittest.cc b/content/renderer/pepper/quota_file_io_unittest.cc
index 3d0df1c..2321c9f 100644
--- a/content/renderer/pepper/quota_file_io_unittest.cc
+++ b/content/renderer/pepper/quota_file_io_unittest.cc
@@ -14,8 +14,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/platform_file.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
-#include "content/renderer/pepper/ppapi_unittest.h"
 #include "content/renderer/pepper/quota_file_io.h"
+#include "content/test/ppapi_unittest.h"
 
 using base::MessageLoopProxy;
 using base::PlatformFile;
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.cc b/content/renderer/pepper/renderer_ppapi_host_impl.cc
index dd78352..b94eac7 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.cc
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.cc
@@ -225,19 +225,19 @@
   return is_running_in_process_;
 }
 
-void RendererPpapiHostImpl::CreateBrowserResourceHost(
+void RendererPpapiHostImpl::CreateBrowserResourceHosts(
     PP_Instance instance,
-    const IPC::Message& nested_msg,
-    const base::Callback<void(int)>& callback) const {
+    const std::vector<IPC::Message>& nested_msgs,
+    const base::Callback<void(const std::vector<int>&)>& callback) const {
   RenderView* render_view = GetRenderViewForInstance(instance);
   PepperBrowserConnection* browser_connection =
       PepperBrowserConnection::Get(render_view);
   if (!browser_connection) {
-    callback.Run(0);
+    callback.Run(std::vector<int>(nested_msgs.size(), 0));
   } else {
     browser_connection->SendBrowserCreate(module_->GetPluginChildId(),
                                           instance,
-                                          nested_msg,
+                                          nested_msgs,
                                           callback);
   }
 }
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.h b/content/renderer/pepper/renderer_ppapi_host_impl.h
index 935f38d..b7a0a53 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.h
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.h
@@ -92,10 +92,11 @@
       base::PlatformFile handle,
       bool should_close_source) OVERRIDE;
   virtual bool IsRunningInProcess() const OVERRIDE;
-  virtual void CreateBrowserResourceHost(
+  virtual void CreateBrowserResourceHosts(
       PP_Instance instance,
-      const IPC::Message& nested_msg,
-      const base::Callback<void(int)>& callback) const OVERRIDE;
+      const std::vector<IPC::Message>& nested_msgs,
+      const base::Callback<void(
+          const std::vector<int>&)>& callback) const OVERRIDE;
 
  private:
   RendererPpapiHostImpl(PluginModule* module,
diff --git a/content/renderer/pepper/resource_converter.cc b/content/renderer/pepper/resource_converter.cc
new file mode 100644
index 0000000..4df384a
--- /dev/null
+++ b/content/renderer/pepper/resource_converter.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 "content/renderer/pepper/resource_converter.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+
+namespace content {
+
+ResourceConverter::~ResourceConverter() {
+}
+
+ResourceConverterImpl::ResourceConverterImpl() {
+}
+
+ResourceConverterImpl::~ResourceConverterImpl() {
+}
+
+void ResourceConverterImpl::ShutDown(
+    const base::Callback<void(bool)>& callback) {
+  // TODO(raymes): Implement the creation of a browser resource host here.
+  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
+}
+
+}  // namespace content
diff --git a/content/renderer/pepper/resource_converter.h b/content/renderer/pepper/resource_converter.h
new file mode 100644
index 0000000..28d06ef
--- /dev/null
+++ b/content/renderer/pepper/resource_converter.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_RENDERER_PEPPER_RESOURCE_CONVERTER_H
+#define CONTENT_RENDERER_PEPPER_RESOURCE_CONVERTER_H
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+// This class is responsible for converting V8 vars to Pepper resources.
+class CONTENT_EXPORT ResourceConverter {
+ public:
+  virtual ~ResourceConverter();
+
+ // ShutDown must be called before any vars created by the ResourceConverter
+  // are valid. It handles creating any resource hosts that need to be created.
+  virtual void ShutDown(const base::Callback<void(bool)>& callback) = 0;
+};
+
+class ResourceConverterImpl : public ResourceConverter {
+ public:
+  ResourceConverterImpl();
+  virtual ~ResourceConverterImpl();
+  virtual void ShutDown(const base::Callback<void(bool)>& callback) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResourceConverterImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_PEPPER_RESOURCE_CONVERTER_H
diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc
index 8942c45..cf56da4 100644
--- a/content/renderer/pepper/v8_var_converter.cc
+++ b/content/renderer/pepper/v8_var_converter.cc
@@ -8,10 +8,13 @@
 #include <stack>
 #include <string>
 
+#include "base/bind.h"
 #include "base/containers/hash_tables.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/renderer/pepper/host_array_buffer_var.h"
+#include "content/renderer/pepper/resource_converter.h"
 #include "ppapi/shared_impl/array_var.h"
 #include "ppapi/shared_impl/dictionary_var.h"
 #include "ppapi/shared_impl/var.h"
@@ -61,7 +64,6 @@
 }  // namespace BASE_HASH_NAMESPACE
 
 namespace content {
-namespace V8VarConverter {
 
 namespace {
 
@@ -165,7 +167,8 @@
                     PP_Var* result,
                     bool* did_create,
                     HandleVarMap* visited_handles,
-                    ParentHandleSet* parent_handles) {
+                    ParentHandleSet* parent_handles,
+                    ResourceConverter* resource_converter) {
   CHECK(!val.IsEmpty());
   *did_create = false;
 
@@ -231,6 +234,21 @@
 
 }  // namespace
 
+V8VarConverter::V8VarConverter()
+    : message_loop_proxy_(base::MessageLoopProxy::current()),
+      resource_converter_(new ResourceConverterImpl()) {
+}
+
+V8VarConverter::V8VarConverter(
+    const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
+    scoped_ptr<ResourceConverter> resource_converter)
+    : message_loop_proxy_(message_loop_proxy),
+      resource_converter_(resource_converter.release()) {
+}
+
+V8VarConverter::~V8VarConverter() {
+}
+
 // To/FromV8Value use a stack-based DFS search to traverse V8/Var graph. Each
 // iteration, the top node on the stack examined. If the node has not been
 // visited yet (i.e. sentinel == false) then it is added to the list of parents
@@ -241,9 +259,9 @@
 // node at the top of the stack has already been visited, then we pop it off the
 // stack and erase it from the list of parents.
 // static
-bool ToV8Value(const PP_Var& var,
-               v8::Handle<v8::Context> context,
-               v8::Handle<v8::Value>* result) {
+bool V8VarConverter::ToV8Value(const PP_Var& var,
+                               v8::Handle<v8::Context> context,
+                               v8::Handle<v8::Value>* result) {
   v8::Context::Scope context_scope(context);
   v8::HandleScope handle_scope;
 
@@ -344,9 +362,10 @@
   return true;
 }
 
-bool FromV8Value(v8::Handle<v8::Value> val,
-                 v8::Handle<v8::Context> context,
-                 PP_Var* result) {
+void V8VarConverter::FromV8Value(
+    v8::Handle<v8::Value> val,
+    v8::Handle<v8::Context> context,
+    const base::Callback<void(const ScopedPPVar&, bool)>& callback) {
   v8::Context::Scope context_scope(context);
   v8::HandleScope handle_scope;
 
@@ -373,8 +392,11 @@
 
     bool did_create = false;
     if (!GetOrCreateVar(current_v8, &current_var, &did_create,
-                        &visited_handles, &parent_handles)) {
-      return false;
+                        &visited_handles, &parent_handles,
+                        resource_converter_.get())) {
+      message_loop_proxy_->PostTask(FROM_HERE,
+          base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+      return;
     }
 
     if (is_root) {
@@ -391,22 +413,30 @@
       ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
       if (!array_var) {
         NOTREACHED();
-        return false;
+        message_loop_proxy_->PostTask(FROM_HERE,
+            base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+        return;
       }
 
       for (uint32 i = 0; i < v8_array->Length(); ++i) {
         v8::TryCatch try_catch;
         v8::Handle<v8::Value> child_v8 = v8_array->Get(i);
-        if (try_catch.HasCaught())
-          return false;
+        if (try_catch.HasCaught()) {
+          message_loop_proxy_->PostTask(FROM_HERE,
+              base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+          return;
+        }
 
         if (!v8_array->HasRealIndexedProperty(i))
           continue;
 
         PP_Var child_var;
         if (!GetOrCreateVar(child_v8, &child_var, &did_create,
-                            &visited_handles, &parent_handles)) {
-          return false;
+                            &visited_handles, &parent_handles,
+                            resource_converter_.get())) {
+          message_loop_proxy_->PostTask(FROM_HERE,
+              base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+          return;
         }
         if (did_create && child_v8->IsObject())
           stack.push(child_v8);
@@ -421,7 +451,9 @@
       DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
       if (!dict_var) {
         NOTREACHED();
-        return false;
+        message_loop_proxy_->PostTask(FROM_HERE,
+            base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+        return;
       }
 
       v8::Handle<v8::Array> property_names(v8_object->GetOwnPropertyNames());
@@ -432,7 +464,9 @@
         if (!key->IsString() && !key->IsNumber()) {
           NOTREACHED() << "Key \"" << *v8::String::AsciiValue(key) << "\" "
                           "is neither a string nor a number";
-          return false;
+          message_loop_proxy_->PostTask(FROM_HERE,
+              base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+          return;
         }
 
         // Skip all callbacks: crbug.com/139933
@@ -443,13 +477,19 @@
 
         v8::TryCatch try_catch;
         v8::Handle<v8::Value> child_v8 = v8_object->Get(key);
-        if (try_catch.HasCaught())
-          return false;
+        if (try_catch.HasCaught()) {
+          message_loop_proxy_->PostTask(FROM_HERE,
+              base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+          return;
+        }
 
         PP_Var child_var;
         if (!GetOrCreateVar(child_v8, &child_var, &did_create,
-                            &visited_handles, &parent_handles)) {
-          return false;
+                            &visited_handles, &parent_handles,
+                            resource_converter_.get())) {
+          message_loop_proxy_->PostTask(FROM_HERE,
+              base::Bind(callback, ScopedPPVar(PP_MakeUndefined()), false));
+          return;
         }
         if (did_create && child_v8->IsObject())
           stack.push(child_v8);
@@ -460,9 +500,7 @@
       }
     }
   }
-  *result = root.Release();
-  return true;
+  resource_converter_->ShutDown(base::Bind(callback, root));
 }
 
-}  // namespace V8VarConverter
 }  // namespace content
diff --git a/content/renderer/pepper/v8_var_converter.h b/content/renderer/pepper/v8_var_converter.h
index 87a6b36..a9865c3 100644
--- a/content/renderer/pepper/v8_var_converter.h
+++ b/content/renderer/pepper/v8_var_converter.h
@@ -7,27 +7,57 @@
 
 
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "ppapi/c/pp_var.h"
 #include "v8/include/v8.h"
 #include "content/common/content_export.h"
 
+namespace ppapi {
+class ScopedPPVar;
+}
+
 namespace content {
-namespace V8VarConverter {
 
-// Converts the given PP_Var to a v8::Value. True is returned upon success.
-bool CONTENT_EXPORT ToV8Value(const PP_Var& var,
-                              v8::Handle<v8::Context> context,
-                              v8::Handle<v8::Value>* result);
-// Converts the given v8::Value to a PP_Var. True is returned upon success.
-// Every PP_Var in the reference graph of which |result| is apart will have
-// a refcount equal to the number of references to it in the graph. |result|
-// will have one additional reference.
-bool CONTENT_EXPORT FromV8Value(v8::Handle<v8::Value> val,
-                                v8::Handle<v8::Context> context,
-                                PP_Var* result);
+class ResourceConverter;
 
-}  // namespace V8VarConverter
+class CONTENT_EXPORT V8VarConverter {
+ public:
+  V8VarConverter();
+  // Constructor for testing.
+  V8VarConverter(
+      const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
+      scoped_ptr<ResourceConverter> resource_converter);
+  ~V8VarConverter();
+
+  // Converts the given PP_Var to a v8::Value. True is returned upon success.
+  bool ToV8Value(const PP_Var& var,
+                 v8::Handle<v8::Context> context,
+                 v8::Handle<v8::Value>* result);
+
+  // Converts the given v8::Value to a PP_Var. Every PP_Var in the reference
+  // graph in the result will have a refcount equal to the number of references
+  // to it in the graph. The root of the result will have one additional
+  // reference. The callback is run when conversion is complete with the
+  // resulting var and a bool indicating success or failure. Conversion is
+  // asynchronous because converting some resources may result in communication
+  // across IPC. |context| is guaranteed to only be used synchronously.
+  void FromV8Value(
+      v8::Handle<v8::Value> val,
+      v8::Handle<v8::Context> context,
+      const base::Callback<void(const ppapi::ScopedPPVar&, bool)>& callback);
+
+ private:
+  // The message loop to run the callback to |FromV8Value| from.
+  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+
+  // The converter to use for converting V8 vars to resources.
+  scoped_ptr<ResourceConverter> resource_converter_;
+
+  DISALLOW_COPY_AND_ASSIGN(V8VarConverter);
+};
+
 }  // namespace content
 
 #endif  // CONTENT_RENDERER_PEPPER_V8_VAR_CONVERTER_H
diff --git a/content/renderer/pepper/v8_var_converter_unittest.cc b/content/renderer/pepper/v8_var_converter_unittest.cc
index c98766f..c27a3b9 100644
--- a/content/renderer/pepper/v8_var_converter_unittest.cc
+++ b/content/renderer/pepper/v8_var_converter_unittest.cc
@@ -9,7 +9,10 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
 #include "base/values.h"
+#include "content/renderer/pepper/resource_converter.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_var.h"
 #include "ppapi/shared_impl/array_var.h"
@@ -39,6 +42,14 @@
 
 namespace {
 
+class MockResourceConverter : public content::ResourceConverter {
+ public:
+  virtual ~MockResourceConverter() {}
+  virtual void ShutDown(const base::Callback<void(bool)>& callback) OVERRIDE {
+    callback.Run(true);
+  }
+};
+
 // Maps PP_Var IDs to the V8 value handle they correspond to.
 typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap;
 
@@ -133,7 +144,15 @@
 class V8VarConverterTest : public testing::Test {
  public:
   V8VarConverterTest()
-      : isolate_(v8::Isolate::GetCurrent()) {}
+      : isolate_(v8::Isolate::GetCurrent()),
+        conversion_success_(false),
+        conversion_event_(true, false),
+        callback_thread_("callback_thread") {
+    callback_thread_.Start();
+    converter_.reset(new V8VarConverter(
+        callback_thread_.message_loop_proxy(),
+        scoped_ptr<ResourceConverter>(new MockResourceConverter).Pass()));
+  }
   virtual ~V8VarConverterTest() {}
 
   // testing::Test implementation.
@@ -150,17 +169,38 @@
   }
 
  protected:
+  bool FromV8ValueSync(v8::Handle<v8::Value> val,
+                       v8::Handle<v8::Context> context,
+                       PP_Var* result) {
+    converter_->FromV8Value(val, context, base::Bind(
+        &V8VarConverterTest::FromV8ValueComplete, base::Unretained(this)));
+    conversion_event_.Wait();
+    conversion_event_.Reset();
+    if (conversion_success_)
+      *result = conversion_result_;
+    return conversion_success_;
+  }
+
+  void FromV8ValueComplete(const ScopedPPVar& scoped_var, bool success) {
+    conversion_success_ = success;
+    if (success) {
+      ScopedPPVar var = scoped_var;
+      conversion_result_ = var.Release();
+    }
+    conversion_event_.Signal();
+  }
+
   bool RoundTrip(const PP_Var& var, PP_Var* result) {
     v8::HandleScope handle_scope(isolate_);
     v8::Context::Scope context_scope(isolate_, context_);
     v8::Local<v8::Context> context =
         v8::Local<v8::Context>::New(isolate_, context_);
     v8::Handle<v8::Value> v8_result;
-    if (!V8VarConverter::ToV8Value(var, context, &v8_result))
+    if (!converter_->ToV8Value(var, context, &v8_result))
       return false;
     if (!Equals(var, v8_result))
       return false;
-    if (!V8VarConverter::FromV8Value(v8_result, context, result))
+    if (!FromV8ValueSync(v8_result, context, result))
       return false;
     return true;
   }
@@ -180,8 +220,15 @@
   // Context for the JavaScript in the test.
   v8::Persistent<v8::Context> context_;
 
+  scoped_ptr<V8VarConverter> converter_;
+
  private:
   TestGlobals globals_;
+
+  PP_Var conversion_result_;
+  bool conversion_success_;
+  base::WaitableEvent conversion_event_;
+  base::Thread callback_thread_;
 };
 
 }  // namespace
@@ -293,8 +340,8 @@
 
     // Array <-> dictionary cycle.
     dictionary->SetWithStringKey("1", release_array.get());
-    ASSERT_FALSE(V8VarConverter::ToV8Value(release_dictionary.get(),
-                                           context, &v8_result));
+    ASSERT_FALSE(converter_->ToV8Value(release_dictionary.get(),
+                                       context, &v8_result));
     // Break the cycle.
     // TODO(raymes): We need some better machinery for releasing vars with
     // cycles. Remove the code below once we have that.
@@ -302,8 +349,8 @@
 
     // Array with self reference.
     array->Set(0, release_array.get());
-    ASSERT_FALSE(V8VarConverter::ToV8Value(release_array.get(),
-                                           context, &v8_result));
+    ASSERT_FALSE(converter_->ToV8Value(release_array.get(),
+                                       context, &v8_result));
     // Break the self reference.
     array->Set(0, PP_MakeUndefined());
   }
@@ -320,11 +367,11 @@
     object->Set(v8::String::New(key.c_str(), key.length()), array);
     array->Set(0, object);
 
-    ASSERT_FALSE(V8VarConverter::FromV8Value(object, context, &var_result));
+    ASSERT_FALSE(FromV8ValueSync(object, context, &var_result));
 
     // Array with self reference.
     array->Set(0, array);
-    ASSERT_FALSE(V8VarConverter::FromV8Value(array, context, &var_result));
+    ASSERT_FALSE(FromV8ValueSync(array, context, &var_result));
   }
 }
 
@@ -358,7 +405,7 @@
     ASSERT_FALSE(object.IsEmpty());
 
     PP_Var actual;
-    ASSERT_TRUE(V8VarConverter::FromV8Value(object,
+    ASSERT_TRUE(FromV8ValueSync(object,
         v8::Local<v8::Context>::New(isolate_, context_), &actual));
     ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual);
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 92bfb3d..07620e7 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -7,8 +7,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "content/child/appcache/appcache_dispatcher.h"
-#include "content/child/fileapi/file_system_dispatcher.h"
-#include "content/child/fileapi/webfilesystem_callback_adapters.h"
 #include "content/child/quota_dispatcher.h"
 #include "content/child/request_extra_data.h"
 #include "content/common/socket_stream_handle_data.h"
@@ -35,7 +33,6 @@
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebFileSystemCallbacks.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebNavigationPolicy.h"
 #include "third_party/WebKit/public/web/WebPlugin.h"
@@ -49,7 +46,6 @@
 
 using WebKit::WebDataSource;
 using WebKit::WebDocument;
-using WebKit::WebFileSystemCallbacks;
 using WebKit::WebFrame;
 using WebKit::WebNavigationPolicy;
 using WebKit::WebPluginParams;
@@ -274,6 +270,17 @@
 
 WebKit::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
     WebKit::WebFrame* frame,
+    WebKit::WebDataSource::ExtraData* extra_data,
+    const WebKit::WebURLRequest& request,
+    WebKit::WebNavigationType type,
+    WebKit::WebNavigationPolicy default_policy,
+    bool is_redirect) {
+  return render_view_->decidePolicyForNavigation(
+      frame, extra_data, request, type, default_policy, is_redirect);
+}
+
+WebKit::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation(
+    WebKit::WebFrame* frame,
     const WebKit::WebURLRequest& request,
     WebKit::WebNavigationType type,
     WebKit::WebNavigationPolicy default_policy,
@@ -284,13 +291,9 @@
 
 void RenderFrameImpl::willSendSubmitEvent(WebKit::WebFrame* frame,
                                           const WebKit::WebFormElement& form) {
-  // Some login forms have onSubmit handlers that put a hash of the password
-  // into a hidden field and then clear the password. (Issue 28910.)
-  // This method gets called before any of those handlers run, so save away
-  // a copy of the password in case it gets lost.
-  DocumentState* document_state =
-      DocumentState::FromDataSource(frame->dataSource());
-  document_state->set_password_form_data(CreatePasswordForm(form));
+  // Call back to RenderViewImpl for observers to be notified.
+  // TODO(nasko): Remove once we have RenderFrameObserver.
+  render_view_->willSendSubmitEvent(frame, form);
 }
 
 void RenderFrameImpl::willSubmitForm(WebKit::WebFrame* frame,
@@ -311,25 +314,6 @@
   internal_data->set_searchable_form_url(web_searchable_form_data.url());
   internal_data->set_searchable_form_encoding(
       web_searchable_form_data.encoding().utf8());
-  scoped_ptr<PasswordForm> password_form_data =
-      CreatePasswordForm(form);
-
-  // In order to save the password that the user actually typed and not one
-  // that may have gotten transformed by the site prior to submit, recover it
-  // from the form contents already stored by |willSendSubmitEvent| into the
-  // dataSource's NavigationState (as opposed to the provisionalDataSource's,
-  // which is what we're storing into now.)
-  if (password_form_data) {
-    DocumentState* old_document_state =
-        DocumentState::FromDataSource(frame->dataSource());
-    if (old_document_state) {
-      PasswordForm* old_form_data = old_document_state->password_form_data();
-      if (old_form_data && old_form_data->action == password_form_data->action)
-        password_form_data->password_value = old_form_data->password_value;
-    }
-  }
-
-  document_state->set_password_form_data(password_form_data.Pass());
 
   // Call back to RenderViewImpl for observers to be notified.
   // TODO(nasko): Remove once we have RenderFrameObserver.
@@ -762,47 +746,6 @@
                                   false));
 }
 
-void RenderFrameImpl::openFileSystem(
-    WebKit::WebFrame* frame,
-    WebKit::WebFileSystemType type,
-    long long size,
-    bool create,
-    WebKit::WebFileSystemCallbacks* callbacks) {
-  DCHECK(callbacks);
-
-  WebSecurityOrigin origin = frame->document().securityOrigin();
-  if (origin.isUnique()) {
-    // Unique origins cannot store persistent state.
-    callbacks->didFail(WebKit::WebFileErrorAbort);
-    return;
-  }
-
-  ChildThread::current()->file_system_dispatcher()->OpenFileSystem(
-      GURL(origin.toString()), static_cast<fileapi::FileSystemType>(type),
-      size, create,
-      base::Bind(&OpenFileSystemCallbackAdapter, callbacks),
-      base::Bind(&FileStatusCallbackAdapter, callbacks));
-}
-
-void RenderFrameImpl::deleteFileSystem(
-    WebKit::WebFrame* frame,
-    WebKit::WebFileSystemType type,
-    WebKit::WebFileSystemCallbacks* callbacks) {
-  DCHECK(callbacks);
-
-  WebSecurityOrigin origin = frame->document().securityOrigin();
-  if (origin.isUnique()) {
-    // Unique origins cannot store persistent state.
-    callbacks->didSucceed();
-    return;
-  }
-
-  ChildThread::current()->file_system_dispatcher()->DeleteFileSystem(
-      GURL(origin.toString()),
-      static_cast<fileapi::FileSystemType>(type),
-      base::Bind(&FileStatusCallbackAdapter, callbacks));
-}
-
 void RenderFrameImpl::requestStorageQuota(
     WebKit::WebFrame* frame,
     WebKit::WebStorageQuotaType type,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index f4686b2..fe8ff87 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -71,6 +71,14 @@
       const WebKit::WebString& suggested_name);
   virtual WebKit::WebNavigationPolicy decidePolicyForNavigation(
       WebKit::WebFrame* frame,
+      WebKit::WebDataSource::ExtraData* extra_data,
+      const WebKit::WebURLRequest& request,
+      WebKit::WebNavigationType type,
+      WebKit::WebNavigationPolicy default_policy,
+      bool is_redirect);
+  // DEPRECATED
+  virtual WebKit::WebNavigationPolicy decidePolicyForNavigation(
+      WebKit::WebFrame* frame,
       const WebKit::WebURLRequest& request,
       WebKit::WebNavigationType type,
       WebKit::WebNavigationPolicy default_policy,
@@ -145,16 +153,6 @@
   virtual void reportFindInPageSelection(int request_id,
                                          int active_match_ordinal,
                                          const WebKit::WebRect& sel);
-  virtual void openFileSystem(
-      WebKit::WebFrame* frame,
-      WebKit::WebFileSystemType type,
-      long long size,
-      bool create,
-      WebKit::WebFileSystemCallbacks* callbacks);
-  virtual void deleteFileSystem(
-      WebKit::WebFrame* frame,
-      WebKit::WebFileSystemType type,
-      WebKit::WebFileSystemCallbacks* callbacks);
   virtual void requestStorageQuota(
       WebKit::WebFrame* frame,
       WebKit::WebStorageQuotaType type,
diff --git a/content/renderer/render_process_visibility_manager.cc b/content/renderer/render_process_visibility_manager.cc
deleted file mode 100644
index ed84bdf..0000000
--- a/content/renderer/render_process_visibility_manager.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 "content/renderer/render_process_visibility_manager.h"
-
-#include "base/logging.h"
-#include "base/memory/memory_pressure_listener.h"
-
-namespace content {
-
-RenderProcessVisibilityManager::RenderProcessVisibilityManager()
-    : num_visible_render_widgets_(0) {
-}
-
-RenderProcessVisibilityManager::~RenderProcessVisibilityManager() {
-}
-
-// static
-RenderProcessVisibilityManager* RenderProcessVisibilityManager::GetInstance() {
-  return Singleton<RenderProcessVisibilityManager>::get();
-}
-
-void RenderProcessVisibilityManager::WidgetVisibilityChanged(bool visible) {
-#if !defined(SYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE)
-  num_visible_render_widgets_ += visible ? 1 : -1;
-  DCHECK_LE(0, num_visible_render_widgets_);
-  if (num_visible_render_widgets_ == 0) {
-    // TODO(vollick): Remove this this heavy-handed approach once we're polling
-    // the real system memory pressure.
-    base::MemoryPressureListener::NotifyMemoryPressure(
-        base::MemoryPressureListener::MEMORY_PRESSURE_MODERATE);
-  }
-#endif
-}
-
-}  // namespace content
diff --git a/content/renderer/render_process_visibility_manager.h b/content/renderer/render_process_visibility_manager.h
deleted file mode 100644
index 290da81..0000000
--- a/content/renderer/render_process_visibility_manager.h
+++ /dev/null
@@ -1,32 +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_RENDER_PROCESS_VISIBILITY_MANAGER_H_
-#define CONTENT_RENDERER_RENDER_PROCESS_VISIBILITY_MANAGER_H_
-
-#include "base/memory/singleton.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class CONTENT_EXPORT RenderProcessVisibilityManager {
- public:
-  static RenderProcessVisibilityManager* GetInstance();
-
-  void WidgetVisibilityChanged(bool visible);
-
- private:
-  friend struct DefaultSingletonTraits<RenderProcessVisibilityManager>;
-
-  RenderProcessVisibilityManager();
-  ~RenderProcessVisibilityManager();
-
-  int num_visible_render_widgets_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderProcessVisibilityManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_RENDER_PROCESS_VISIBILITY_MANAGER_H_
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index b1e4a71..085d452 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -77,7 +77,6 @@
 #include "content/renderer/memory_benchmarking_extension.h"
 #include "content/renderer/p2p/socket_dispatcher.h"
 #include "content/renderer/render_process_impl.h"
-#include "content/renderer/render_process_visibility_manager.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
 #include "content/renderer/skia_benchmarking_extension.h"
@@ -87,9 +86,10 @@
 #include "ipc/ipc_platform_file.h"
 #include "media/base/audio_hardware_config.h"
 #include "media/base/media.h"
-#include "media/filters/gpu_video_decoder_factories.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
+#include "third_party/skia/include/core/SkGraphics.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebColorName.h"
 #include "third_party/WebKit/public/web/WebDatabase.h"
@@ -622,29 +622,25 @@
 }
 
 void RenderThreadImpl::WidgetHidden() {
-  DCHECK(hidden_widget_count_ < widget_count_);
+  DCHECK_LT(hidden_widget_count_, widget_count_);
   hidden_widget_count_++;
 
-  RenderProcessVisibilityManager* manager =
-      RenderProcessVisibilityManager::GetInstance();
-  manager->WidgetVisibilityChanged(false);
-
-  if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
-    return;
+  if (widget_count_ && hidden_widget_count_ == widget_count_) {
+#if !defined(SYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE)
+    // TODO(vollick): Remove this this heavy-handed approach once we're polling
+    // the real system memory pressure.
+    base::MemoryPressureListener::NotifyMemoryPressure(
+        base::MemoryPressureListener::MEMORY_PRESSURE_MODERATE);
+#endif
+    if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
+      ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
   }
-
-  if (widget_count_ && hidden_widget_count_ == widget_count_)
-    ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
 }
 
 void RenderThreadImpl::WidgetRestored() {
   DCHECK_GT(hidden_widget_count_, 0);
   hidden_widget_count_--;
 
-  RenderProcessVisibilityManager* manager =
-      RenderProcessVisibilityManager::GetInstance();
-  manager->WidgetVisibilityChanged(true);
-
   if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
     return;
   }
@@ -887,22 +883,20 @@
   idle_notifications_to_skip_ = 2;
 }
 
-scoped_refptr<RendererGpuVideoDecoderFactories>
+scoped_refptr<RendererGpuVideoAcceleratorFactories>
 RenderThreadImpl::GetGpuFactories(
     const scoped_refptr<base::MessageLoopProxy>& factories_loop) {
   DCHECK(IsMainThread());
 
   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
-  scoped_refptr<RendererGpuVideoDecoderFactories> gpu_factories;
+  scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories;
   WebGraphicsContext3DCommandBufferImpl* context3d = NULL;
   if (!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
     context3d = GetGpuVDAContext3D();
-  if (context3d) {
-    GpuChannelHost* gpu_channel_host = GetGpuChannel();
-    if (gpu_channel_host) {
-      gpu_factories = new RendererGpuVideoDecoderFactories(
-          gpu_channel_host, factories_loop, context3d);
-    }
+  GpuChannelHost* gpu_channel_host = GetGpuChannel();
+  if (gpu_channel_host) {
+    gpu_factories = new RendererGpuVideoAcceleratorFactories(
+        gpu_channel_host, factories_loop, context3d);
   }
   return gpu_factories;
 }
@@ -964,9 +958,7 @@
   if (!shared_contexts_main_thread_.get() ||
       shared_contexts_main_thread_->DestroyedOnMainThread()) {
     shared_contexts_main_thread_ =
-        ContextProviderCommandBuffer::Create(
-            base::Bind(&RenderThreadImpl::CreateOffscreenContext3d,
-                       base::Unretained(this)));
+        ContextProviderCommandBuffer::Create(CreateOffscreenContext3d());
     if (shared_contexts_main_thread_.get() &&
         !shared_contexts_main_thread_->BindToCurrentThread())
       shared_contexts_main_thread_ = NULL;
@@ -988,9 +980,7 @@
   if (!shared_contexts_compositor_thread_.get() ||
       shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
     shared_contexts_compositor_thread_ =
-        ContextProviderCommandBuffer::Create(
-            base::Bind(&RenderThreadImpl::CreateOffscreenContext3d,
-                       base::Unretained(this)));
+        ContextProviderCommandBuffer::Create(CreateOffscreenContext3d());
   }
   return shared_contexts_compositor_thread_;
 }
@@ -1148,6 +1138,7 @@
       params.frame_name,
       false,
       params.swapped_out,
+      params.hidden,
       params.next_page_id,
       params.screen_info,
       params.accessibility_mode,
@@ -1277,6 +1268,10 @@
     v8::V8::LowMemoryNotification();
     // Clear the image cache.
     WebKit::WebImageCache::clear();
+    // Purge Skia font cache, by setting it to 0 and then again to the previous
+    // limit.
+    size_t font_cache_limit = SkGraphics::SetFontCacheLimit(0);
+    SkGraphics::SetFontCacheLimit(font_cache_limit);
   } else {
     // Otherwise trigger a couple of v8 GCs using IdleNotification.
     if (!v8::V8::IdleNotification())
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index fd2cfff..d11a498 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -19,7 +19,7 @@
 #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_decoder_factories.h"
+#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
 #include "ipc/ipc_channel_proxy.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -55,7 +55,6 @@
 
 namespace media {
 class AudioHardwareConfig;
-class GpuVideoDecoderFactories;
 }
 
 namespace v8 {
@@ -258,9 +257,8 @@
   // not sent for at least one notification delay.
   void PostponeIdleNotification();
 
-  // Gets gpu factories, which will run on |factories_loop|. Returns NULL if VDA
-  // is disabled or a graphics context cannot be obtained.
-  scoped_refptr<RendererGpuVideoDecoderFactories> GetGpuFactories(
+  // Gets gpu factories, which will run on |factories_loop|.
+  scoped_refptr<RendererGpuVideoAcceleratorFactories> GetGpuFactories(
       const scoped_refptr<base::MessageLoopProxy>& factories_loop);
 
   // Returns a graphics context shared among all
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 125f4c3..3fbf1d9 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -20,8 +20,8 @@
 #include "content/public/renderer/navigation_state.h"
 #include "content/public/test/render_view_test.h"
 #include "content/renderer/render_view_impl.h"
+#include "content/shell/browser/shell_content_browser_client.h"
 #include "content/shell/common/shell_content_client.h"
-#include "content/shell/shell_content_browser_client.h"
 #include "content/test/mock_keyboard.h"
 #include "net/base/net_errors.h"
 #include "net/cert/cert_status_flags.h"
@@ -34,6 +34,7 @@
 #include "third_party/WebKit/public/web/WebDataSource.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebHistoryItem.h"
+#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "third_party/WebKit/public/web/WebWindowFeatures.h"
 #include "ui/base/keycodes/keyboard_codes.h"
@@ -58,6 +59,7 @@
 using WebKit::WebFrame;
 using WebKit::WebInputEvent;
 using WebKit::WebMouseEvent;
+using WebKit::WebRuntimeFeatures;
 using WebKit::WebString;
 using WebKit::WebTextDirection;
 using WebKit::WebURLError;
@@ -119,6 +121,17 @@
     mock_keyboard_.reset(new MockKeyboard());
   }
 
+  virtual ~RenderViewImplTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    RenderViewTest::SetUp();
+    // This test depends on Blink flag InputModeAttribute, which is enabled
+    // under only test. Content browser test doesn't enable the feature so we
+    // need enable it manually.
+    // TODO(yoichio): Remove this if InputMode feature is enabled by default.
+    WebRuntimeFeatures::enableInputModeAttribute(true);
+  }
+
   RenderViewImpl* view() {
     return static_cast<RenderViewImpl*>(view_);
   }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 2f57b82..32f323f 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -32,10 +32,7 @@
 #include "content/child/appcache/appcache_dispatcher.h"
 #include "content/child/appcache/web_application_cache_host_impl.h"
 #include "content/child/child_thread.h"
-#include "content/child/fileapi/file_system_dispatcher.h"
-#include "content/child/fileapi/webfilesystem_callback_adapters.h"
 #include "content/child/npapi/webplugin_delegate_impl.h"
-#include "content/child/quota_dispatcher.h"
 #include "content/child/request_extra_data.h"
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/clipboard_messages.h"
@@ -67,9 +64,9 @@
 #include "content/public/renderer/document_state.h"
 #include "content/public/renderer/history_item_serialization.h"
 #include "content/public/renderer/navigation_state.h"
-#include "content/public/renderer/password_form_conversion_utils.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "content/public/renderer/render_view_visitor.h"
+#include "content/public/renderer/web_preferences.h"
 #include "content/renderer/accessibility/renderer_accessibility.h"
 #include "content/renderer/accessibility/renderer_accessibility_complete.h"
 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
@@ -132,7 +129,7 @@
 #include "media/base/filter_collection.h"
 #include "media/base/media_switches.h"
 #include "media/filters/audio_renderer_impl.h"
-#include "media/filters/gpu_video_decoder_factories.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 #include "net/base/data_url.h"
 #include "net/base/escape.h"
 #include "net/base/net_errors.h"
@@ -140,7 +137,6 @@
 #include "net/http/http_util.h"
 #include "third_party/WebKit/public/platform/WebCString.h"
 #include "third_party/WebKit/public/platform/WebDragData.h"
-#include "third_party/WebKit/public/platform/WebFileSystemType.h"
 #include "third_party/WebKit/public/platform/WebHTTPBody.h"
 #include "third_party/WebKit/public/platform/WebImage.h"
 #include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
@@ -165,7 +161,6 @@
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebElement.h"
 #include "third_party/WebKit/public/web/WebFileChooserParams.h"
-#include "third_party/WebKit/public/web/WebFileSystemCallbacks.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
 #include "third_party/WebKit/public/web/WebFormControlElement.h"
 #include "third_party/WebKit/public/web/WebFormElement.h"
@@ -185,6 +180,7 @@
 #include "third_party/WebKit/public/web/WebPluginDocument.h"
 #include "third_party/WebKit/public/web/WebPluginParams.h"
 #include "third_party/WebKit/public/web/WebRange.h"
+#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebSearchableFormData.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
@@ -206,7 +202,6 @@
 #include "ui/shell_dialogs/selected_file_info.h"
 #include "v8/include/v8.h"
 #include "webkit/child/weburlresponse_extradata_impl.h"
-#include "webkit/renderer/webpreferences_renderer.h"
 
 #if defined(OS_ANDROID)
 #include <cpu-features.h>
@@ -217,9 +212,9 @@
 #include "content/renderer/android/content_detector.h"
 #include "content/renderer/android/email_detector.h"
 #include "content/renderer/android/phone_number_detector.h"
+#include "content/renderer/android/synchronous_compositor_factory.h"
 #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/stream_texture_factory_android_synchronous_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"
@@ -276,8 +271,6 @@
 using WebKit::WebExternalPopupMenu;
 using WebKit::WebExternalPopupMenuClient;
 using WebKit::WebFileChooserCompletion;
-using WebKit::WebFileSystem;
-using WebKit::WebFileSystemCallbacks;
 using WebKit::WebFindOptions;
 using WebKit::WebFormControlElement;
 using WebKit::WebFormElement;
@@ -311,6 +304,7 @@
 using WebKit::WebRange;
 using WebKit::WebRect;
 using WebKit::WebReferrerPolicy;
+using WebKit::WebRuntimeFeatures;
 using WebKit::WebScriptSource;
 using WebKit::WebSearchableFormData;
 using WebKit::WebSecurityOrigin;
@@ -780,7 +774,8 @@
 RenderViewImpl::RenderViewImpl(RenderViewImplParams* params)
     : RenderWidget(WebKit::WebPopupTypeNone,
                    params->screen_info,
-                   params->swapped_out),
+                   params->swapped_out,
+                   params->hidden),
       webkit_preferences_(params->webkit_prefs),
       send_content_state_immediately_(false),
       enabled_bindings_(0),
@@ -900,6 +895,8 @@
   // Take a reference on behalf of the RenderThread.  This will be balanced
   // when we receive ViewMsg_ClosePage.
   AddRef();
+  if (is_hidden_)
+    RenderThread::Get()->WidgetHidden();
 
   // If this is a popup, we must wait for the CreatingNew_ACK message before
   // completing initialization.  Otherwise, we can finish it now.
@@ -920,7 +917,7 @@
   webview()->settings()->setAcceleratedCompositingForFixedRootBackgroundEnabled(
       ShouldUseAcceleratedFixedRootBackground(device_scale_factor_));
 
-  webkit_glue::ApplyWebPreferences(webkit_preferences_, webview());
+  ApplyWebPreferences(webkit_preferences_, webview());
   webview()->initializeMainFrame(main_render_frame_.get());
 
   if (switches::IsTouchDragDropEnabled())
@@ -1073,6 +1070,7 @@
     const string16& frame_name,
     bool is_renderer_created,
     bool swapped_out,
+    bool hidden,
     int32 next_page_id,
     const WebKit::WebScreenInfo& screen_info,
     AccessibilityMode accessibility_mode,
@@ -1090,6 +1088,7 @@
       frame_name,
       is_renderer_created,
       swapped_out,
+      hidden,
       next_page_id,
       screen_info,
       accessibility_mode,
@@ -1991,10 +1990,6 @@
   params.searchable_form_url = internal_data->searchable_form_url();
   params.searchable_form_encoding = internal_data->searchable_form_encoding();
 
-  const PasswordForm* password_form_data = document_state->password_form_data();
-  if (password_form_data)
-    params.password_form = *password_form_data;
-
   params.gesture = navigation_gesture_;
   navigation_gesture_ = NavigationGestureUnknown;
 
@@ -2342,9 +2337,10 @@
       surface_id,
       cloned_session_storage_namespace_id,
       string16(),  // WebCore will take care of setting the correct name.
-      true,
-      false,
-      1,
+      true,  // is_renderer_created
+      false, // swapped_out
+      false, // hidden
+      1,     // next_page_id
       screen_info_,
       accessibility_mode_,
       allow_partial_swap_);
@@ -2387,9 +2383,21 @@
   return new WebStorageNamespaceImpl(session_storage_namespace_id_);
 }
 
+bool RenderViewImpl::shouldReportDetailedMessageForSource(
+    const WebString& source) {
+  return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
+      source);
+}
+
 void RenderViewImpl::didAddMessageToConsole(
     const WebConsoleMessage& message, const WebString& source_name,
     unsigned source_line) {
+  didAddMessageToConsole(message, source_name, source_line, WebString());
+}
+
+void RenderViewImpl::didAddMessageToConsole(
+    const WebConsoleMessage& message, const WebString& source_name,
+    unsigned source_line, const WebString& stack_trace) {
   logging::LogSeverity log_severity = logging::LOG_VERBOSE;
   switch (message.level) {
     case WebConsoleMessage::LevelDebug:
@@ -2412,7 +2420,8 @@
                                            static_cast<int32>(log_severity),
                                            message.text,
                                            static_cast<int32>(source_line),
-                                           source_name));
+                                           source_name,
+                                           stack_trace));
 }
 
 void RenderViewImpl::printPage(WebFrame* frame) {
@@ -2687,6 +2696,10 @@
       RenderViewObserver, observers_, DidRequestShowContextMenu(frame, data));
 }
 
+void RenderViewImpl::clearContextMenu() {
+  context_menu_node_.reset();
+}
+
 void RenderViewImpl::setStatusText(const WebString& text) {
 }
 
@@ -3024,7 +3037,9 @@
 
   scoped_ptr<StreamTextureFactory> stream_texture_factory;
   if (UsingSynchronousRendererCompositor()) {
-    stream_texture_factory.reset(new StreamTextureFactorySynchronousImpl);
+    SynchronousCompositorFactory* factory =
+        SynchronousCompositorFactory::GetInstance();
+    stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_);
   } else {
     stream_texture_factory.reset(new StreamTextureFactoryImpl(
         context_provider->Context3d(), gpu_channel_host, routing_id_));
@@ -3038,6 +3053,7 @@
           media_player_manager_.get(),
           media_player_proxy_,
           stream_texture_factory.release(),
+          RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(),
           new RenderMediaLog()));
 #if defined(ENABLE_WEBRTC) && defined(GOOGLE_TV)
   if (media_stream_client_->IsMediaStream(url)) {
@@ -3066,7 +3082,7 @@
     DVLOG(1) << "Using AudioRendererMixerManager-provided sink: " << sink.get();
   }
 
-  scoped_refptr<media::GpuVideoDecoderFactories> gpu_factories =
+  scoped_refptr<media::GpuVideoAcceleratorFactories> gpu_factories =
       RenderThreadImpl::current()->GetGpuFactories(
           RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy());
 
@@ -3380,7 +3396,8 @@
 
 void RenderViewImpl::willSendSubmitEvent(WebKit::WebFrame* frame,
     const WebKit::WebFormElement& form) {
-  NOTREACHED();
+  FOR_EACH_OBSERVER(
+      RenderViewObserver, observers_, WillSendSubmitEvent(frame, form));
 }
 
 void RenderViewImpl::willSubmitForm(WebFrame* frame,
@@ -3482,7 +3499,7 @@
   InternalDocumentStateData* internal_data =
       InternalDocumentStateData::FromDocumentState(document_state);
 
-  if (!params.url.SchemeIs(chrome::kJavaScriptScheme) &&
+  if (!params.url.SchemeIs(kJavaScriptScheme) &&
       params.navigation_type == ViewMsg_Navigate_Type::RESTORE) {
     // We're doing a load of a page that was restored from the last session. By
     // default this prefers the cache over loading (LOAD_PREFERRING_CACHE) which
@@ -3515,7 +3532,7 @@
   // A navigation resulting from loading a javascript URL should not be treated
   // as a browser initiated event.  Instead, we want it to look as if the page
   // initiated any load resulting from JS execution.
-  if (!params.url.SchemeIs(chrome::kJavaScriptScheme)) {
+  if (!params.url.SchemeIs(kJavaScriptScheme)) {
     navigation_state = NavigationState::CreateBrowserInitiated(
         params.page_id,
         params.pending_history_list_offset,
@@ -3594,23 +3611,6 @@
   if (is_top_most) {
     navigation_gesture_ = WebUserGestureIndicator::isProcessingUserGesture() ?
         NavigationGestureUser : NavigationGestureAuto;
-
-    // If the navigation is not triggered by a user gesture, e.g. by some ajax
-    // callback, then inherit the submitted password form from the previous
-    // state. This fixes the no password save issue for ajax login, tracked in
-    // [http://crbug/43219]. Note that there are still some sites that this
-    // fails for because they use some element other than a submit button to
-    // trigger submission.
-    if (navigation_gesture_ == NavigationGestureAuto) {
-      DocumentState* old_document_state = DocumentState::FromDataSource(
-          frame->dataSource());
-      const content::PasswordForm* old_password_form =
-          old_document_state->password_form_data();
-      if (old_password_form) {
-        document_state->set_password_form_data(
-            make_scoped_ptr(new content::PasswordForm(*old_password_form)));
-      }
-    }
   } else if (frame->parent()->isLoading()) {
     // Take note of AUTO_SUBFRAME loads here, so that we can know how to
     // load an error page.  See didFailProvisionalLoad.
@@ -3960,9 +3960,6 @@
   new_state->set_was_within_same_page(true);
 
   didCommitProvisionalLoad(frame, is_new_navigation);
-
-  WebDataSource* datasource = frame->view()->mainFrame()->dataSource();
-  UpdateTitle(frame, datasource->pageTitle(), datasource->pageTitleDirection());
 }
 
 void RenderViewImpl::didUpdateCurrentHistoryItem(WebFrame* frame) {
@@ -4239,22 +4236,6 @@
   NOTREACHED();
 }
 
-void RenderViewImpl::openFileSystem(
-    WebFrame* frame,
-    WebKit::WebFileSystemType type,
-    long long size,
-    bool create,
-    WebFileSystemCallbacks* callbacks) {
-  NOTREACHED();
-}
-
-void RenderViewImpl::deleteFileSystem(
-    WebFrame* frame,
-    WebKit::WebFileSystemType type ,
-    WebFileSystemCallbacks* callbacks) {
-  NOTREACHED();
-}
-
 void RenderViewImpl::requestStorageQuota(
     WebFrame* frame,
     WebStorageQuotaType type,
@@ -5033,6 +5014,9 @@
 void RenderViewImpl::OnAllowBindings(int enabled_bindings_flags) {
   if ((enabled_bindings_flags & BINDINGS_POLICY_WEB_UI) &&
       !(enabled_bindings_ & BINDINGS_POLICY_WEB_UI)) {
+    // WebUI uses <dialog> which is not yet enabled by default in Chrome.
+    WebRuntimeFeatures::enableDialogElement(true);
+
     RenderThread::Get()->RegisterExtension(WebUIExtension::Get());
     new WebUIExtensionData(this);
   }
@@ -5100,7 +5084,7 @@
 
 void RenderViewImpl::OnUpdateWebPreferences(const WebPreferences& prefs) {
   webkit_preferences_ = prefs;
-  webkit_glue::ApplyWebPreferences(webkit_preferences_, webview());
+  ApplyWebPreferences(webkit_preferences_, webview());
 }
 
 void RenderViewImpl::OnUpdateTimezone() {
@@ -5270,6 +5254,9 @@
 }
 
 void RenderViewImpl::OnOrientationChangeEvent(int orientation) {
+  FOR_EACH_OBSERVER(RenderViewObserver,
+                    observers_,
+                    OrientationChangeEvent(orientation));
   webview()->mainFrame()->sendOrientationChangeEvent(orientation);
 }
 
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index c57c03a..8571234 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -18,6 +18,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/process/process.h"
+#include "base/strings/string16.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "cc/input/top_controls_state.h"
@@ -41,7 +42,6 @@
 #include "content/renderer/renderer_webcookiejar_impl.h"
 #include "content/renderer/stats_collection_observer.h"
 #include "ipc/ipc_platform_file.h"
-#include "third_party/WebKit/public/platform/WebFileSystem.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
 #include "third_party/WebKit/public/web/WebDataSource.h"
@@ -212,6 +212,7 @@
       const string16& frame_name,
       bool is_renderer_created,
       bool swapped_out,
+      bool hidden,
       int32 next_page_id,
       const WebKit::WebScreenInfo& screen_info,
       AccessibilityMode accessibility_mode,
@@ -445,10 +446,18 @@
       const WebKit::WebPopupMenuInfo& popup_menu_info,
       WebKit::WebExternalPopupMenuClient* popup_menu_client);
   virtual WebKit::WebStorageNamespace* createSessionStorageNamespace();
+  virtual bool shouldReportDetailedMessageForSource(
+      const WebKit::WebString& source);
+  // TODO(rdevlin.cronin): Remove this version once
+  // https://codereview.chromium.org/18822004/ lands.
   virtual void didAddMessageToConsole(
       const WebKit::WebConsoleMessage& message,
       const WebKit::WebString& source_name,
       unsigned source_line);
+  virtual void didAddMessageToConsole(
+      const WebKit::WebConsoleMessage& message,
+      const WebKit::WebString& source_name,
+      unsigned source_line, const WebKit::WebString& stack_trace);
   virtual void printPage(WebKit::WebFrame* frame);
   virtual WebKit::WebNotificationPresenter* notificationPresenter();
   virtual bool enumerateChosenDirectory(
@@ -484,6 +493,7 @@
                                           const WebKit::WebString& message);
   virtual void showContextMenu(WebKit::WebFrame* frame,
                                const WebKit::WebContextMenuData& data);
+  virtual void clearContextMenu();
   virtual void setStatusText(const WebKit::WebString& text);
   virtual void setMouseOverURL(const WebKit::WebURL& url);
   virtual void setKeyboardFocusURL(const WebKit::WebURL& url);
@@ -654,14 +664,6 @@
   virtual void reportFindInPageSelection(int request_id,
                                          int active_match_ordinal,
                                          const WebKit::WebRect& sel);
-  virtual void openFileSystem(WebKit::WebFrame* frame,
-                              WebKit::WebFileSystemType type,
-                              long long size,
-                              bool create,
-                              WebKit::WebFileSystemCallbacks* callbacks);
-  virtual void deleteFileSystem(WebKit::WebFrame* frame,
-                                WebKit::WebFileSystemType type,
-                                WebKit::WebFileSystemCallbacks* callbacks);
   virtual void requestStorageQuota(
       WebKit::WebFrame* frame,
       WebKit::WebStorageQuotaType type,
diff --git a/content/renderer/render_view_impl_params.cc b/content/renderer/render_view_impl_params.cc
index daceb5b..ce966e1 100644
--- a/content/renderer/render_view_impl_params.cc
+++ b/content/renderer/render_view_impl_params.cc
@@ -18,6 +18,7 @@
     const string16& frame_name,
     bool is_renderer_created,
     bool swapped_out,
+    bool hidden,
     int32 next_page_id,
     const WebKit::WebScreenInfo& screen_info,
     AccessibilityMode accessibility_mode,
@@ -33,6 +34,7 @@
       frame_name(frame_name),
       is_renderer_created(is_renderer_created),
       swapped_out(swapped_out),
+      hidden(hidden),
       next_page_id(next_page_id),
       screen_info(screen_info),
       accessibility_mode(accessibility_mode),
diff --git a/content/renderer/render_view_impl_params.h b/content/renderer/render_view_impl_params.h
index 4b66e04..f652c0a 100644
--- a/content/renderer/render_view_impl_params.h
+++ b/content/renderer/render_view_impl_params.h
@@ -35,6 +35,7 @@
                        const string16& frame_name,
                        bool is_renderer_created,
                        bool swapped_out,
+                       bool hidden,
                        int32 next_page_id,
                        const WebKit::WebScreenInfo& screen_info,
                        AccessibilityMode accessibility_mode,
@@ -52,6 +53,7 @@
   const string16& frame_name;
   bool is_renderer_created;
   bool swapped_out;
+  bool hidden;
   int32 next_page_id;
   const WebKit::WebScreenInfo& screen_info;
   AccessibilityMode accessibility_mode;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 7a19c8e..53b8839 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -19,6 +19,7 @@
 #include "cc/output/output_surface.h"
 #include "cc/trees/layer_tree_host.h"
 #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/input_messages.h"
 #include "content/common/swapped_out_messages.h"
@@ -34,7 +35,6 @@
 #include "content/renderer/ime_event_guard.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
 #include "content/renderer/render_process.h"
-#include "content/renderer/render_process_visibility_manager.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
 #include "ipc/ipc_sync_message.h"
@@ -188,7 +188,8 @@
 
 RenderWidget::RenderWidget(WebKit::WebPopupType popup_type,
                            const WebKit::WebScreenInfo& screen_info,
-                           bool swapped_out)
+                           bool swapped_out,
+                           bool hidden)
     : routing_id_(MSG_ROUTING_NONE),
       surface_id_(0),
       webwidget_(NULL),
@@ -204,7 +205,7 @@
       using_asynchronous_swapbuffers_(false),
       num_swapbuffers_complete_pending_(0),
       did_show_(false),
-      is_hidden_(false),
+      is_hidden_(hidden),
       is_fullscreen_(false),
       needs_repainting_on_restore_(false),
       has_focus_(false),
@@ -238,8 +239,6 @@
   is_threaded_compositing_enabled_ =
       CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableThreadedCompositing);
-
-  RenderProcessVisibilityManager::GetInstance()->WidgetVisibilityChanged(true);
 }
 
 RenderWidget::~RenderWidget() {
@@ -254,7 +253,7 @@
     current_paint_buf_ = NULL;
   }
   // If we are swapped out, we have released already.
-  if (!is_swapped_out_)
+  if (!is_swapped_out_ && RenderProcess::current())
     RenderProcess::current()->ReleaseProcess();
 }
 
@@ -264,7 +263,7 @@
                                    const WebKit::WebScreenInfo& screen_info) {
   DCHECK(opener_id != MSG_ROUTING_NONE);
   scoped_refptr<RenderWidget> widget(
-      new RenderWidget(popup_type, screen_info, false));
+      new RenderWidget(popup_type, screen_info, false, false));
   if (widget->Init(opener_id)) {  // adds reference on success.
     return widget.get();
   }
@@ -312,6 +311,8 @@
     // Take a reference on behalf of the RenderThread.  This will be balanced
     // when we receive ViewMsg_Close.
     AddRef();
+    if (is_hidden_)
+      RenderThread::Get()->WidgetHidden();
     return true;
   } else {
     // The above Send can fail when the tab is closing.
@@ -669,37 +670,54 @@
   attributes.stencil = false;
   if (command_line.HasSwitch(cc::switches::kForceDirectLayerDrawing))
     attributes.stencil = true;
-  WebGraphicsContext3DCommandBufferImpl* context = NULL;
-  if (!fallback)
-    context = CreateGraphicsContext3D(attributes);
+  scoped_refptr<ContextProviderCommandBuffer> context_provider;
+  if (!fallback) {
+    context_provider = ContextProviderCommandBuffer::Create(
+        CreateGraphicsContext3D(attributes));
+  }
 
-  if (!context) {
+  if (!context_provider.get()) {
     if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing))
       return scoped_ptr<cc::OutputSurface>();
-    return scoped_ptr<cc::OutputSurface>(
-        new CompositorOutputSurface(routing_id(),
-                                    output_surface_id,
-                                    NULL,
-                                    new CompositorSoftwareOutputDevice(),
-                                    true));
+
+    scoped_ptr<cc::SoftwareOutputDevice> software_device(
+        new CompositorSoftwareOutputDevice());
+
+    return scoped_ptr<cc::OutputSurface>(new CompositorOutputSurface(
+        routing_id(),
+        output_surface_id,
+        NULL,
+        software_device.Pass(),
+        true));
   }
 
   if (command_line.HasSwitch(switches::kEnableDelegatedRenderer) &&
       !command_line.HasSwitch(switches::kDisableDelegatedRenderer)) {
     DCHECK(is_threaded_compositing_enabled_);
     return scoped_ptr<cc::OutputSurface>(
-        new DelegatedCompositorOutputSurface(routing_id(), output_surface_id,
-                                             context, NULL));
+        new DelegatedCompositorOutputSurface(
+            routing_id(),
+            output_surface_id,
+            context_provider,
+            scoped_ptr<cc::SoftwareOutputDevice>()));
   }
   if (command_line.HasSwitch(cc::switches::kCompositeToMailbox)) {
     DCHECK(is_threaded_compositing_enabled_);
     return scoped_ptr<cc::OutputSurface>(
-        new MailboxOutputSurface(routing_id(), output_surface_id,
-                                 context, NULL));
+        new MailboxOutputSurface(
+            routing_id(),
+            output_surface_id,
+            context_provider,
+            scoped_ptr<cc::SoftwareOutputDevice>()));
   }
+  bool use_swap_compositor_frame_message = false;
   return scoped_ptr<cc::OutputSurface>(
-      new CompositorOutputSurface(routing_id(), output_surface_id,
-                                  context, NULL, false));
+      new CompositorOutputSurface(
+          routing_id(),
+          output_surface_id,
+          context_provider,
+          scoped_ptr<cc::SoftwareOutputDevice>(),
+          use_swap_compositor_frame_message));
 }
 
 void RenderWidget::OnViewContextSwapBuffersAborted() {
@@ -1020,7 +1038,7 @@
       base::TimeDelta paint_time =
           base::TimeTicks::HighResNow() - paint_begin_ticks;
       if (!is_accelerated_compositing_active_)
-        software_stats_.total_paint_time += paint_time;
+        software_stats_.main_stats.paint_time += paint_time;
     }
 #endif
   } else {
@@ -1035,7 +1053,7 @@
       base::TimeDelta paint_time =
           base::TimeTicks::HighResNow() - paint_begin_ticks;
       if (!is_accelerated_compositing_active_)
-        software_stats_.total_paint_time += paint_time;
+        software_stats_.main_stats.paint_time += paint_time;
     }
 
     // Flush to underlying bitmap.  TODO(darin): is this needed?
@@ -1047,7 +1065,7 @@
 
   if (kEnableGpuBenchmarking) {
     int64 num_pixels_processed = rect.width() * rect.height();
-    software_stats_.total_pixels_painted += num_pixels_processed;
+    software_stats_.main_stats.painted_pixel_count += num_pixels_processed;
   }
 }
 
@@ -1254,8 +1272,8 @@
   last_do_deferred_update_time_ = frame_begin_ticks;
 
   if (!is_accelerated_compositing_active_) {
-    software_stats_.animation_frame_count++;
-    software_stats_.screen_frame_count++;
+    software_stats_.main_stats.animation_frame_count++;
+    software_stats_.main_stats.screen_frame_count++;
   }
 
   // OK, save the pending update to a local since painting may cause more
@@ -2436,14 +2454,14 @@
   if (compositor_)
     compositor_->GetRenderingStats(&stats.rendering_stats);
 
-  stats.rendering_stats.animation_frame_count +=
-      software_stats_.animation_frame_count;
-  stats.rendering_stats.screen_frame_count +=
-      software_stats_.screen_frame_count;
-  stats.rendering_stats.total_paint_time +=
-      software_stats_.total_paint_time;
-  stats.rendering_stats.total_pixels_painted +=
-      software_stats_.total_pixels_painted;
+  stats.rendering_stats.main_stats.animation_frame_count +=
+      software_stats_.main_stats.animation_frame_count;
+  stats.rendering_stats.main_stats.screen_frame_count +=
+      software_stats_.main_stats.screen_frame_count;
+  stats.rendering_stats.main_stats.paint_time +=
+      software_stats_.main_stats.paint_time;
+  stats.rendering_stats.main_stats.painted_pixel_count +=
+      software_stats_.main_stats.painted_pixel_count;
 }
 
 bool RenderWidget::GetGpuRenderingStats(GpuRenderingStats* stats) const {
@@ -2506,13 +2524,14 @@
   return true;
 }
 
-WebGraphicsContext3DCommandBufferImpl* RenderWidget::CreateGraphicsContext3D(
+scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
+RenderWidget::CreateGraphicsContext3D(
     const WebKit::WebGraphicsContext3D::Attributes& attributes) {
   if (!webwidget_)
-    return NULL;
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
   if (CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableGpuCompositing))
-    return NULL;
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
   scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
       new WebGraphicsContext3DCommandBufferImpl(
           surface_id(),
@@ -2524,8 +2543,8 @@
           attributes,
           false /* bind generates resources */,
           CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
-    return NULL;
-  return context.release();
+    return scoped_ptr<WebGraphicsContext3DCommandBufferImpl>();
+  return context.Pass();
 }
 
 }  // namespace content
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index dea17b6..ec3609a 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -227,7 +227,8 @@
 
   RenderWidget(WebKit::WebPopupType popup_type,
                const WebKit::WebScreenInfo& screen_info,
-               bool swapped_out);
+               bool swapped_out,
+               bool hidden);
 
   virtual ~RenderWidget();
 
@@ -511,7 +512,7 @@
   virtual void hasTouchEventHandlers(bool has_handlers);
 
   // Creates a 3D context associated with this view.
-  WebGraphicsContext3DCommandBufferImpl* CreateGraphicsContext3D(
+  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateGraphicsContext3D(
       const WebKit::WebGraphicsContext3D::Attributes& attributes);
 
   bool OnSnapshotHelper(const gfx::Rect& src_subrect, SkBitmap* bitmap);
diff --git a/content/renderer/render_widget_fullscreen.cc b/content/renderer/render_widget_fullscreen.cc
index 79fc8c3..5798285 100644
--- a/content/renderer/render_widget_fullscreen.cc
+++ b/content/renderer/render_widget_fullscreen.cc
@@ -25,7 +25,7 @@
 
 RenderWidgetFullscreen::RenderWidgetFullscreen(
     const WebKit::WebScreenInfo& screen_info)
-    : RenderWidget(WebKit::WebPopupTypeNone, screen_info, false) {
+    : RenderWidget(WebKit::WebPopupTypeNone, screen_info, false, false) {
 }
 
 RenderWidgetFullscreen::~RenderWidgetFullscreen() {}
diff --git a/content/renderer/renderer_date_time_picker.cc b/content/renderer/renderer_date_time_picker.cc
index 47d22f7..86d268a 100644
--- a/content/renderer/renderer_date_time_picker.cc
+++ b/content/renderer/renderer_date_time_picker.cc
@@ -43,9 +43,11 @@
     message.hour = parser.GetHour();
     message.minute = parser.GetMinute();
     message.second = parser.GetSecond();
+    message.milli = parser.GetMilli();
   }
   message.minimum = chooser_params_.minimum;
   message.maximum = chooser_params_.maximum;
+  message.step = chooser_params_.step;
   Send(new ViewHostMsg_OpenDateTimeDialog(routing_id(), message));
   return true;
 }
@@ -64,10 +66,16 @@
 void RendererDateTimePicker::OnReplaceDateTime(
     const ViewHostMsg_DateTimeDialogValue_Params& value) {
 
-  DateTimeFormatter formatter(
-      static_cast<ui::TextInputType>(value.dialog_type),
-      value.year, value.month, value.day,
-      value.hour, value.minute, value.second, value.year, value.week);
+  DateTimeFormatter formatter(static_cast<ui::TextInputType>(value.dialog_type),
+                              value.year,
+                              value.month,
+                              value.day,
+                              value.hour,
+                              value.minute,
+                              value.second,
+                              value.milli,
+                              value.year,
+                              value.week);
 
   if (chooser_completion_)
     chooser_completion_->didChooseValue(WebString::fromUTF8(
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index 0a8b0d8..2d298a6 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -34,6 +34,11 @@
 #include "webkit/child/webkit_child_helpers.h"
 #include "webkit/glue/webkit_glue.h"
 
+#if defined(OS_ANDROID)
+#include "base/android/sys_utils.h"
+#include "third_party/skia/include/core/SkGraphics.h"
+#endif  // OS_ANDROID
+
 #if defined(OS_MACOSX)
 #include <Carbon/Carbon.h>
 #include <signal.h>
@@ -133,6 +138,13 @@
   }
 #endif
 
+#if defined(OS_ANDROID)
+  const int kMB = 1024 * 1024;
+  size_t font_cache_limit =
+      base::android::SysUtils::IsLowEndDevice() ? kMB : 8 * kMB;
+  SkGraphics::SetFontCacheLimit(font_cache_limit);
+#endif
+
   // This function allows pausing execution using the --renderer-startup-dialog
   // flag allowing us to attach a debugger.
   // Do not move this function down since that would mean we can't easily debug
@@ -181,8 +193,6 @@
   base::FieldTrialList field_trial_list(NULL);
   // Ensure any field trials in browser are reflected into renderer.
   if (parsed_command_line.HasSwitch(switches::kForceFieldTrials)) {
-    std::string persistent = parsed_command_line.GetSwitchValueASCII(
-        switches::kForceFieldTrials);
     // Field trials are created in an "activated" state to ensure they get
     // reported in crash reports.
     bool result = base::FieldTrialList::CreateTrialsFromString(
diff --git a/content/renderer/renderer_main_platform_delegate_android.cc b/content/renderer/renderer_main_platform_delegate_android.cc
index 3a92a4f..4a19706 100644
--- a/content/renderer/renderer_main_platform_delegate_android.cc
+++ b/content/renderer/renderer_main_platform_delegate_android.cc
@@ -5,6 +5,11 @@
 #include "content/renderer/renderer_main_platform_delegate.h"
 #include "base/logging.h"
 
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+#include "content/public/common/content_switches.h"
+#include "v8/src/third_party/vtune/v8-vtune.h"
+#endif
+
 namespace content {
 
 RendererMainPlatformDelegate::RendererMainPlatformDelegate(
@@ -16,6 +21,11 @@
 }
 
 void RendererMainPlatformDelegate::PlatformInitialize() {
+#ifdef ENABLE_VTUNE_JIT_INTERFACE
+  const CommandLine& command_line = parameters_.command_line;
+  if (command_line.HasSwitch(switches::kEnableVtune))
+    vTune::InitializeVtuneForV8();
+#endif
 }
 
 void RendererMainPlatformDelegate::PlatformUninitialize() {
diff --git a/content/renderer/renderer_main_thread.cc b/content/renderer/renderer_main_thread.cc
new file mode 100644
index 0000000..c6704c8
--- /dev/null
+++ b/content/renderer/renderer_main_thread.cc
@@ -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.
+
+#include "content/renderer/renderer_main_thread.h"
+
+#include "content/renderer/render_process.h"
+#include "content/renderer/render_process_impl.h"
+#include "content/renderer/render_thread_impl.h"
+
+namespace content {
+
+RendererMainThread::RendererMainThread(const std::string& channel_id)
+    : Thread("Chrome_InProcRendererThread"), channel_id_(channel_id) {
+}
+
+RendererMainThread::~RendererMainThread() {
+  Stop();
+}
+
+void RendererMainThread::Init() {
+  render_process_.reset(new RenderProcessImpl());
+  new RenderThreadImpl(channel_id_);
+}
+
+void RendererMainThread::CleanUp() {
+  render_process_.reset();
+
+  // It's a little lame to manually set this flag.  But the single process
+  // RendererThread will receive the WM_QUIT.  We don't need to assert on
+  // this thread, so just force the flag manually.
+  // If we want to avoid this, we could create the InProcRendererThread
+  // directly with _beginthreadex() rather than using the Thread class.
+  // We used to set this flag in the Init function above. However there
+  // other threads like WebThread which are created by this thread
+  // which resets this flag. Please see Thread::StartWithOptions. Setting
+  // this flag to true in Cleanup works around these problems.
+  SetThreadWasQuitProperly(true);
+}
+
+base::Thread* CreateRendererMainThread(const std::string& channel_id) {
+  return new RendererMainThread(channel_id);
+}
+
+}  // namespace content
diff --git a/content/renderer/renderer_main_thread.h b/content/renderer/renderer_main_thread.h
new file mode 100644
index 0000000..dca7cb8
--- /dev/null
+++ b/content/renderer/renderer_main_thread.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_RENDERER_MAIN_THREAD_H_
+#define CONTENT_RENDERER_RENDERER_MAIN_THREAD_H_
+
+#include <string>
+
+#include "base/threading/thread.h"
+#include "content/common/content_export.h"
+
+namespace content {
+class RenderProcess;
+
+// This class creates the IO thread for the renderer when running in
+// single-process mode.  It's not used in multi-process mode.
+class RendererMainThread : public base::Thread {
+ public:
+  explicit RendererMainThread(const std::string& channel_id);
+  virtual ~RendererMainThread();
+
+ protected:
+  virtual void Init() OVERRIDE;
+  virtual void CleanUp() OVERRIDE;
+
+ private:
+  std::string channel_id_;
+  scoped_ptr<RenderProcess> render_process_;
+
+  DISALLOW_COPY_AND_ASSIGN(RendererMainThread);
+};
+
+CONTENT_EXPORT base::Thread* CreateRendererMainThread(
+    const std::string& channel_id);
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_RENDERER_MAIN_THREAD_H_
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.cc b/content/renderer/renderer_webkitplatformsupport_impl.cc
index d5156a1..afa6bc0 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.cc
+++ b/content/renderer/renderer_webkitplatformsupport_impl.cc
@@ -128,6 +128,8 @@
     LAZY_INSTANCE_INITIALIZER;
 base::LazyInstance<WebKit::WebDeviceMotionData>::Leaky
     g_test_device_motion_data = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<WebKit::WebDeviceOrientationData>::Leaky
+    g_test_device_orientation_data = LAZY_INSTANCE_INITIALIZER;
 
 //------------------------------------------------------------------------------
 
@@ -148,8 +150,6 @@
       const WebKit::WebString& file_extension);
   virtual WebKit::WebString mimeTypeFromFile(
       const WebKit::WebString& file_path);
-  virtual WebKit::WebString preferredExtensionForMIMEType(
-      const WebKit::WebString& mime_type);
 };
 
 class RendererWebKitPlatformSupportImpl::FileUtilities
@@ -225,6 +225,7 @@
 }
 
 RendererWebKitPlatformSupportImpl::~RendererWebKitPlatformSupportImpl() {
+  WebFileSystemImpl::DeleteThreadSpecificInstance();
 }
 
 //------------------------------------------------------------------------------
@@ -374,9 +375,7 @@
 //------------------------------------------------------------------------------
 
 WebFileSystem* RendererWebKitPlatformSupportImpl::fileSystem() {
-  if (!web_file_system_)
-    web_file_system_.reset(new WebFileSystemImpl(child_thread_loop_.get()));
-  return web_file_system_.get();
+  return WebFileSystemImpl::ThreadSpecificInstance(child_thread_loop_.get());
 }
 
 //------------------------------------------------------------------------------
@@ -484,21 +483,6 @@
   return ASCIIToUTF16(mime_type);
 }
 
-WebString
-RendererWebKitPlatformSupportImpl::MimeRegistry::preferredExtensionForMIMEType(
-    const WebString& mime_type) {
-  if (IsPluginProcess())
-    return SimpleWebMimeRegistryImpl::preferredExtensionForMIMEType(mime_type);
-
-  // The sandbox restricts our access to the registry, so we need to proxy
-  // these calls over to the browser process.
-  base::FilePath::StringType file_extension;
-  RenderThread::Get()->Send(
-      new MimeRegistryMsg_GetPreferredExtensionForMimeType(
-          UTF16ToASCII(mime_type), &file_extension));
-  return base::FilePath(file_extension).AsUTF16Unsafe();
-}
-
 //------------------------------------------------------------------------------
 
 bool RendererWebKitPlatformSupportImpl::FileUtilities::getFileInfo(
@@ -1027,11 +1011,27 @@
 
 void RendererWebKitPlatformSupportImpl::setDeviceOrientationListener(
     WebKit::WebDeviceOrientationListener* listener) {
-  if (!device_orientation_event_pump_) {
-    device_orientation_event_pump_.reset(new DeviceOrientationEventPump);
-    device_orientation_event_pump_->Attach(RenderThreadImpl::current());
+  if (g_test_device_orientation_data == 0) {
+    if (!device_orientation_event_pump_) {
+      device_orientation_event_pump_.reset(new DeviceOrientationEventPump);
+      device_orientation_event_pump_->Attach(RenderThreadImpl::current());
+    }
+    device_orientation_event_pump_->SetListener(listener);
+  } else if (listener) {
+    // Testing mode: just echo the test data to the listener.
+    base::MessageLoopProxy::current()->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &WebKit::WebDeviceOrientationListener::didChangeDeviceOrientation,
+            base::Unretained(listener),
+            g_test_device_orientation_data.Get()));
   }
-  device_orientation_event_pump_->SetListener(listener);
+}
+
+// static
+void RendererWebKitPlatformSupportImpl::SetMockDeviceOrientationDataForTesting(
+    const WebKit::WebDeviceOrientationData& data) {
+  g_test_device_orientation_data.Get() = data;
 }
 
 //------------------------------------------------------------------------------
diff --git a/content/renderer/renderer_webkitplatformsupport_impl.h b/content/renderer/renderer_webkitplatformsupport_impl.h
index 358f119..1ec2a6c 100644
--- a/content/renderer/renderer_webkitplatformsupport_impl.h
+++ b/content/renderer/renderer_webkitplatformsupport_impl.h
@@ -29,6 +29,7 @@
 
 namespace WebKit {
 class WebDeviceMotionData;
+class WebDeviceOrientationData;
 class WebGraphicsContext3DProvider;
 }
 
@@ -166,6 +167,10 @@
   // Set WebDeviceMotionData to return when setDeviceMotionListener is invoked.
   static void SetMockDeviceMotionDataForTesting(
       const WebKit::WebDeviceMotionData& data);
+  // Set WebDeviceOrientationData to return when setDeviceOrientationListener
+  // is invoked.
+  static void SetMockDeviceOrientationDataForTesting(
+      const WebKit::WebDeviceOrientationData& data);
 
  private:
   bool CheckPreparsedJsCachingEnabled() const;
diff --git a/content/renderer/rendering_benchmark.cc b/content/renderer/rendering_benchmark.cc
deleted file mode 100644
index 5415bdd..0000000
--- a/content/renderer/rendering_benchmark.cc
+++ /dev/null
@@ -1,12 +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/renderer/rendering_benchmark.h"
-
-namespace content {
-
-RenderingBenchmark::RenderingBenchmark(const std::string& name) : name_(name) {}
-RenderingBenchmark::~RenderingBenchmark() {}
-
-}  // namespace content
diff --git a/content/renderer/rendering_benchmark.h b/content/renderer/rendering_benchmark.h
deleted file mode 100644
index 44b5a84..0000000
--- a/content/renderer/rendering_benchmark.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 CONTENT_RENDERER_RENDERING_BENCHMARK_H_
-#define CONTENT_RENDERER_RENDERING_BENCHMARK_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-
-namespace WebKit {
-class WebViewBenchmarkSupport;
-}
-
-namespace content {
-class RenderingBenchmarkResults;
-
-class RenderingBenchmark {
- public:
-  explicit RenderingBenchmark(const std::string& name);
-  virtual ~RenderingBenchmark();
-
-  virtual void SetUp(WebKit::WebViewBenchmarkSupport* benchmarkSupport) {}
-
-  virtual double Run(WebKit::WebViewBenchmarkSupport* benchmarkSupport) = 0;
-
-  virtual void TearDown(WebKit::WebViewBenchmarkSupport* benchmarkSupport) {}
-
-  const std::string& name() { return name_; }
-
- private:
-  const std::string name_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderingBenchmark);
-};
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_RENDERING_BENCHMARK_H_
diff --git a/content/renderer/resource_fetcher_browsertest.cc b/content/renderer/resource_fetcher_browsertest.cc
index a96bbf5..573fe4d 100644
--- a/content/renderer/resource_fetcher_browsertest.cc
+++ b/content/renderer/resource_fetcher_browsertest.cc
@@ -13,7 +13,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
diff --git a/content/renderer/savable_resources.cc b/content/renderer/savable_resources.cc
index d21da17..f1b2fde 100644
--- a/content/renderer/savable_resources.cc
+++ b/content/renderer/savable_resources.cc
@@ -89,7 +89,7 @@
   // Ignore those URLs which are not standard protocols. Because FTP
   // protocol does no have cache mechanism, we will skip all
   // sub-resources if they use FTP protocol.
-  if (!u.SchemeIs("http") && !u.SchemeIs("https") && !u.SchemeIs("file"))
+  if (!u.SchemeIsHTTPOrHTTPS() && !u.SchemeIs("file"))
     return;
   // Ignore duplicated resource link.
   if (!unique_check->resources_set->insert(u).second)
diff --git a/content/renderer/savable_resources_browsertest.cc b/content/renderer/savable_resources_browsertest.cc
index 38c3c6c..a7ad83a 100644
--- a/content/renderer/savable_resources_browsertest.cc
+++ b/content/renderer/savable_resources_browsertest.cc
@@ -9,7 +9,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/renderer/render_view.h"
 #include "content/renderer/savable_resources.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/net_util.h"
diff --git a/content/renderer/web_preferences.cc b/content/renderer/web_preferences.cc
new file mode 100644
index 0000000..210ad46
--- /dev/null
+++ b/content/renderer/web_preferences.cc
@@ -0,0 +1,351 @@
+// Copyright 2013 The Chromium Authors. 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/renderer/web_preferences.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURL.h"
+#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
+#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
+#include "third_party/WebKit/public/web/WebSettings.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
+#include "webkit/common/webpreferences.h"
+
+using WebKit::WebNetworkStateNotifier;
+using WebKit::WebRuntimeFeatures;
+using WebKit::WebSettings;
+using WebKit::WebString;
+using WebKit::WebURL;
+using WebKit::WebView;
+
+namespace content {
+
+namespace {
+
+typedef void (*SetFontFamilyWrapper)(WebKit::WebSettings*,
+                                     const base::string16&,
+                                     UScriptCode);
+
+void setStandardFontFamilyWrapper(WebSettings* settings,
+                                  const base::string16& font,
+                                  UScriptCode script) {
+  settings->setStandardFontFamily(font, script);
+}
+
+void setFixedFontFamilyWrapper(WebSettings* settings,
+                               const base::string16& font,
+                               UScriptCode script) {
+  settings->setFixedFontFamily(font, script);
+}
+
+void setSerifFontFamilyWrapper(WebSettings* settings,
+                               const base::string16& font,
+                               UScriptCode script) {
+  settings->setSerifFontFamily(font, script);
+}
+
+void setSansSerifFontFamilyWrapper(WebSettings* settings,
+                                   const base::string16& font,
+                                   UScriptCode script) {
+  settings->setSansSerifFontFamily(font, script);
+}
+
+void setCursiveFontFamilyWrapper(WebSettings* settings,
+                                 const base::string16& font,
+                                 UScriptCode script) {
+  settings->setCursiveFontFamily(font, script);
+}
+
+void setFantasyFontFamilyWrapper(WebSettings* settings,
+                                 const base::string16& font,
+                                 UScriptCode script) {
+  settings->setFantasyFontFamily(font, script);
+}
+
+void setPictographFontFamilyWrapper(WebSettings* settings,
+                                    const base::string16& font,
+                                    UScriptCode script) {
+  settings->setPictographFontFamily(font, script);
+}
+
+// If |scriptCode| is a member of a family of "similar" script codes, returns
+// the script code in that family that is used by WebKit for font selection
+// purposes.  For example, USCRIPT_KATAKANA_OR_HIRAGANA and USCRIPT_JAPANESE are
+// considered equivalent for the purposes of font selection.  WebKit uses the
+// script code USCRIPT_KATAKANA_OR_HIRAGANA.  So, if |scriptCode| is
+// USCRIPT_JAPANESE, the function returns USCRIPT_KATAKANA_OR_HIRAGANA.  WebKit
+// uses different scripts than the ones in Chrome pref names because the version
+// of ICU included on certain ports does not have some of the newer scripts.  If
+// |scriptCode| is not a member of such a family, returns |scriptCode|.
+UScriptCode GetScriptForWebSettings(UScriptCode scriptCode) {
+  switch (scriptCode) {
+  case USCRIPT_HIRAGANA:
+  case USCRIPT_KATAKANA:
+  case USCRIPT_JAPANESE:
+    return USCRIPT_KATAKANA_OR_HIRAGANA;
+  case USCRIPT_KOREAN:
+    return USCRIPT_HANGUL;
+  default:
+    return scriptCode;
+  }
+}
+
+void ApplyFontsFromMap(const webkit_glue::ScriptFontFamilyMap& map,
+                       SetFontFamilyWrapper setter,
+                       WebSettings* settings) {
+  for (webkit_glue::ScriptFontFamilyMap::const_iterator it = map.begin();
+       it != map.end();
+       ++it) {
+    int32 script = u_getPropertyValueEnum(UCHAR_SCRIPT, (it->first).c_str());
+    if (script >= 0 && script < USCRIPT_CODE_LIMIT) {
+      UScriptCode code = static_cast<UScriptCode>(script);
+      (*setter)(settings, it->second, GetScriptForWebSettings(code));
+    }
+  }
+}
+
+}  // namespace
+
+void ApplyWebPreferences(const WebPreferences& prefs, WebView* web_view) {
+  WebSettings* settings = web_view->settings();
+  ApplyFontsFromMap(prefs.standard_font_family_map,
+                    setStandardFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.fixed_font_family_map,
+                    setFixedFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.serif_font_family_map,
+                    setSerifFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.sans_serif_font_family_map,
+                    setSansSerifFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.cursive_font_family_map,
+                    setCursiveFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.fantasy_font_family_map,
+                    setFantasyFontFamilyWrapper, settings);
+  ApplyFontsFromMap(prefs.pictograph_font_family_map,
+                    setPictographFontFamilyWrapper, settings);
+  settings->setDefaultFontSize(prefs.default_font_size);
+  settings->setDefaultFixedFontSize(prefs.default_fixed_font_size);
+  settings->setMinimumFontSize(prefs.minimum_font_size);
+  settings->setMinimumLogicalFontSize(prefs.minimum_logical_font_size);
+  settings->setDefaultTextEncodingName(ASCIIToUTF16(prefs.default_encoding));
+  settings->setJavaScriptEnabled(prefs.javascript_enabled);
+  settings->setWebSecurityEnabled(prefs.web_security_enabled);
+  settings->setJavaScriptCanOpenWindowsAutomatically(
+      prefs.javascript_can_open_windows_automatically);
+  settings->setLoadsImagesAutomatically(prefs.loads_images_automatically);
+  settings->setImagesEnabled(prefs.images_enabled);
+  settings->setPluginsEnabled(prefs.plugins_enabled);
+  settings->setDOMPasteAllowed(prefs.dom_paste_enabled);
+  settings->setNeedsSiteSpecificQuirks(prefs.site_specific_quirks_enabled);
+  settings->setShrinksStandaloneImagesToFit(
+      prefs.shrinks_standalone_images_to_fit);
+  settings->setUsesEncodingDetector(prefs.uses_universal_detector);
+  settings->setTextAreasAreResizable(prefs.text_areas_are_resizable);
+  settings->setAllowScriptsToCloseWindows(prefs.allow_scripts_to_close_windows);
+  if (prefs.user_style_sheet_enabled)
+    settings->setUserStyleSheetLocation(prefs.user_style_sheet_location);
+  else
+    settings->setUserStyleSheetLocation(WebURL());
+  settings->setAuthorAndUserStylesEnabled(prefs.author_and_user_styles_enabled);
+  settings->setDownloadableBinaryFontsEnabled(prefs.remote_fonts_enabled);
+  settings->setJavaScriptCanAccessClipboard(
+      prefs.javascript_can_access_clipboard);
+  settings->setXSSAuditorEnabled(prefs.xss_auditor_enabled);
+  settings->setDNSPrefetchingEnabled(prefs.dns_prefetching_enabled);
+  settings->setLocalStorageEnabled(prefs.local_storage_enabled);
+  settings->setSyncXHRInDocumentsEnabled(prefs.sync_xhr_in_documents_enabled);
+  WebRuntimeFeatures::enableDatabase(prefs.databases_enabled);
+  settings->setOfflineWebApplicationCacheEnabled(
+      prefs.application_cache_enabled);
+  settings->setCaretBrowsingEnabled(prefs.caret_browsing_enabled);
+  settings->setHyperlinkAuditingEnabled(prefs.hyperlink_auditing_enabled);
+  settings->setCookieEnabled(prefs.cookie_enabled);
+
+  // This setting affects the behavior of links in an editable region:
+  // clicking the link should select it rather than navigate to it.
+  // Safari uses the same default. It is unlikley an embedder would want to
+  // change this, since it would break existing rich text editors.
+  settings->setEditableLinkBehaviorNeverLive();
+
+  settings->setJavaEnabled(prefs.java_enabled);
+
+  // By default, allow_universal_access_from_file_urls is set to false and thus
+  // we mitigate attacks from local HTML files by not granting file:// URLs
+  // universal access. Only test shell will enable this.
+  settings->setAllowUniversalAccessFromFileURLs(
+      prefs.allow_universal_access_from_file_urls);
+  settings->setAllowFileAccessFromFileURLs(
+      prefs.allow_file_access_from_file_urls);
+
+  // Enable the web audio API if requested on the command line.
+  settings->setWebAudioEnabled(prefs.webaudio_enabled);
+
+  // Enable experimental WebGL support if requested on command line
+  // and support is compiled in.
+  settings->setExperimentalWebGLEnabled(prefs.experimental_webgl_enabled);
+
+  // Disable GL multisampling if requested on command line.
+  settings->setOpenGLMultisamplingEnabled(prefs.gl_multisampling_enabled);
+
+  // Enable privileged WebGL extensions for Chrome extensions or if requested
+  // on command line.
+  settings->setPrivilegedWebGLExtensionsEnabled(
+      prefs.privileged_webgl_extensions_enabled);
+
+  // Enable WebGL errors to the JS console if requested.
+  settings->setWebGLErrorsToConsoleEnabled(
+      prefs.webgl_errors_to_console_enabled);
+
+  // Enables accelerated compositing for overflow scroll.
+  settings->setAcceleratedCompositingForOverflowScrollEnabled(
+      prefs.accelerated_compositing_for_overflow_scroll_enabled);
+
+  // Enables accelerated compositing for scrollable frames if requested on
+  // command line.
+  settings->setAcceleratedCompositingForScrollableFramesEnabled(
+      prefs.accelerated_compositing_for_scrollable_frames_enabled);
+
+  // Enables composited scrolling for frames if requested on command line.
+  settings->setCompositedScrollingForFramesEnabled(
+      prefs.composited_scrolling_for_frames_enabled);
+
+  // Uses the mock theme engine for scrollbars.
+  settings->setMockScrollbarsEnabled(prefs.mock_scrollbars_enabled);
+
+  settings->setThreadedHTMLParser(prefs.threaded_html_parser);
+
+  // Display visualization of what has changed on the screen using an
+  // overlay of rects, if requested on the command line.
+  settings->setShowPaintRects(prefs.show_paint_rects);
+
+  // Enable gpu-accelerated compositing if requested on the command line.
+  settings->setAcceleratedCompositingEnabled(
+      prefs.accelerated_compositing_enabled);
+
+  // Enable gpu-accelerated 2d canvas if requested on the command line.
+  settings->setAccelerated2dCanvasEnabled(prefs.accelerated_2d_canvas_enabled);
+
+  settings->setMinimumAccelerated2dCanvasSize(
+      prefs.minimum_accelerated_2d_canvas_size);
+
+  // Disable antialiasing for 2d canvas if requested on the command line.
+  settings->setAntialiased2dCanvasEnabled(
+      !prefs.antialiased_2d_canvas_disabled);
+
+  // Enable gpu-accelerated filters if requested on the command line.
+  settings->setAcceleratedFiltersEnabled(prefs.accelerated_filters_enabled);
+
+  // Enable gesture tap highlight if requested on the command line.
+  settings->setGestureTapHighlightEnabled(prefs.gesture_tap_highlight_enabled);
+
+  // Enabling accelerated layers from the command line enabled accelerated
+  // 3D CSS, Video, and Animations.
+  settings->setAcceleratedCompositingFor3DTransformsEnabled(
+      prefs.accelerated_compositing_for_3d_transforms_enabled);
+  settings->setAcceleratedCompositingForVideoEnabled(
+      prefs.accelerated_compositing_for_video_enabled);
+  settings->setAcceleratedCompositingForAnimationEnabled(
+      prefs.accelerated_compositing_for_animation_enabled);
+
+  // Enabling accelerated plugins if specified from the command line.
+  settings->setAcceleratedCompositingForPluginsEnabled(
+      prefs.accelerated_compositing_for_plugins_enabled);
+
+  // WebGL and accelerated 2D canvas are always gpu composited.
+  settings->setAcceleratedCompositingForCanvasEnabled(
+      prefs.experimental_webgl_enabled || prefs.accelerated_2d_canvas_enabled);
+
+  // Enable memory info reporting to page if requested on the command line.
+  settings->setMemoryInfoEnabled(prefs.memory_info_enabled);
+
+  settings->setAsynchronousSpellCheckingEnabled(
+      prefs.asynchronous_spell_checking_enabled);
+  settings->setUnifiedTextCheckerEnabled(prefs.unified_textchecker_enabled);
+
+  for (webkit_glue::WebInspectorPreferences::const_iterator it =
+           prefs.inspector_settings.begin();
+       it != prefs.inspector_settings.end();
+       ++it) {
+    web_view->setInspectorSetting(WebString::fromUTF8(it->first),
+                                  WebString::fromUTF8(it->second));
+  }
+
+  // Tabs to link is not part of the settings. WebCore calls
+  // ChromeClient::tabsToLinks which is part of the glue code.
+  web_view->setTabsToLinks(prefs.tabs_to_links);
+
+  settings->setFullScreenEnabled(prefs.fullscreen_enabled);
+  settings->setAllowDisplayOfInsecureContent(
+      prefs.allow_displaying_insecure_content);
+  settings->setAllowRunningOfInsecureContent(
+      prefs.allow_running_insecure_content);
+  settings->setPasswordEchoEnabled(prefs.password_echo_enabled);
+  settings->setShouldPrintBackgrounds(prefs.should_print_backgrounds);
+  settings->setEnableScrollAnimator(prefs.enable_scroll_animator);
+  settings->setVisualWordMovementEnabled(prefs.visual_word_movement_enabled);
+
+  settings->setCSSStickyPositionEnabled(prefs.css_sticky_position_enabled);
+  settings->setExperimentalCSSCustomFilterEnabled(prefs.css_shaders_enabled);
+  settings->setRegionBasedColumnsEnabled(prefs.region_based_columns_enabled);
+
+  WebRuntimeFeatures::enableLazyLayout(prefs.lazy_layout_enabled);
+  WebRuntimeFeatures::enableTouch(prefs.touch_enabled);
+  settings->setDeviceSupportsTouch(prefs.device_supports_touch);
+  settings->setDeviceSupportsMouse(prefs.device_supports_mouse);
+  settings->setEnableTouchAdjustment(prefs.touch_adjustment_enabled);
+
+  settings->setFixedPositionCreatesStackingContext(
+      prefs.fixed_position_creates_stacking_context);
+
+  settings->setDeferredImageDecodingEnabled(
+      prefs.deferred_image_decoding_enabled);
+  settings->setShouldRespectImageOrientation(
+      prefs.should_respect_image_orientation);
+
+  settings->setUnsafePluginPastingEnabled(false);
+  settings->setEditingBehavior(
+      static_cast<WebSettings::EditingBehavior>(prefs.editing_behavior));
+
+  settings->setSupportsMultipleWindows(prefs.supports_multiple_windows);
+
+  settings->setViewportEnabled(prefs.viewport_enabled);
+  settings->setInitializeAtMinimumPageScale(
+      prefs.initialize_at_minimum_page_scale);
+
+  settings->setSmartInsertDeleteEnabled(prefs.smart_insert_delete_enabled);
+
+  settings->setSpatialNavigationEnabled(prefs.spatial_navigation_enabled);
+
+  settings->setSelectionIncludesAltImageText(true);
+
+#if defined(OS_ANDROID)
+  settings->setAllowCustomScrollbarInMainFrame(false);
+  settings->setTextAutosizingEnabled(prefs.text_autosizing_enabled);
+  settings->setTextAutosizingFontScaleFactor(prefs.font_scale_factor);
+  web_view->setIgnoreViewportTagScaleLimits(prefs.force_enable_zoom);
+  settings->setAutoZoomFocusedNodeToLegibleScale(true);
+  settings->setDoubleTapToZoomEnabled(prefs.double_tap_to_zoom_enabled);
+  settings->setMediaPlaybackRequiresUserGesture(
+      prefs.user_gesture_required_for_media_playback);
+  settings->setDefaultVideoPosterURL(
+        ASCIIToUTF16(prefs.default_video_poster_url.spec()));
+  settings->setSupportDeprecatedTargetDensityDPI(
+      prefs.support_deprecated_target_density_dpi);
+  settings->setUseWideViewport(prefs.use_wide_viewport);
+#endif
+
+  WebNetworkStateNotifier::setOnLine(prefs.is_online);
+  settings->setExperimentalWebSocketEnabled(
+      prefs.experimental_websocket_enabled);
+  settings->setPinchVirtualViewportEnabled(
+      prefs.pinch_virtual_viewport_enabled);
+
+  settings->setPinchOverlayScrollbarThickness(
+      prefs.pinch_overlay_scrollbar_thickness);
+}
+
+}  // namespace content
diff --git a/content/shell/android/shell_apk/res/values/strings.xml b/content/shell/android/shell_apk/res/values/strings.xml
new file mode 100644
index 0000000..18f1c59
--- /dev/null
+++ b/content/shell/android/shell_apk/res/values/strings.xml
@@ -0,0 +1,11 @@
+<?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>
+    <string name="browser_process_initialization_failed">Initialization failed.</string>
+</resources>
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
index 3f7ceb0..2d819e9 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -12,13 +12,14 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.widget.Toast;
 
 import org.chromium.base.ChromiumActivity;
 import org.chromium.base.MemoryPressureListener;
 import org.chromium.content.app.LibraryLoader;
 import org.chromium.content.browser.ActivityContentVideoViewClient;
 import org.chromium.content.browser.AndroidBrowserProcess;
-import org.chromium.content.browser.BrowserStartupConfig;
+import org.chromium.content.browser.BrowserStartupController;
 import org.chromium.content.browser.ContentVideoViewClient;
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewClient;
@@ -65,7 +66,7 @@
     private BroadcastReceiver mReceiver;
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         // Initializing the command line must occur before loading the library.
@@ -81,50 +82,54 @@
         DeviceUtils.addDeviceSpecificUserAgentSwitch(this);
         try {
             LibraryLoader.ensureInitialized();
-
-            setContentView(R.layout.content_shell_activity);
-            mShellManager = (ShellManager) findViewById(R.id.shell_container);
-            mWindowAndroid = new WindowAndroid(this);
-            mWindowAndroid.restoreInstanceState(savedInstanceState);
-            mShellManager.setWindow(mWindowAndroid);
-
-            String startupUrl = getUrlFromIntent(getIntent());
-            if (!TextUtils.isEmpty(startupUrl)) {
-                mShellManager.setStartupUrl(Shell.sanitizeUrl(startupUrl));
-            }
-
-            if (!CommandLine.getInstance().hasSwitch(CommandLine.DUMP_RENDER_TREE)) {
-                BrowserStartupConfig.setAsync(new BrowserStartupConfig.StartupCallback() {
-
-                    @Override
-                    public void run(int startupResult) {
-                        if (startupResult > 0) {
-                            // TODO: Show error message.
-                            Log.e(TAG, "ContentView initialization failed.");
-                            finish();
-                        } else {
-                            finishInitialization();
-                        }
-                    }
-                });
-            }
-
-            if (!AndroidBrowserProcess.init(this, AndroidBrowserProcess.MAX_RENDERERS_LIMIT)) {
-                String shellUrl = ShellManager.DEFAULT_SHELL_URL;
-                if (savedInstanceState != null
-                        && savedInstanceState.containsKey(ACTIVE_SHELL_URL_KEY)) {
-                    shellUrl = savedInstanceState.getString(ACTIVE_SHELL_URL_KEY);
-                }
-                mShellManager.launchShell(shellUrl);
-                finishInitialization();
-            }
         } catch (ProcessInitException e) {
             Log.e(TAG, "ContentView initialization failed.", e);
             finish();
+            return;
+        }
+
+        setContentView(R.layout.content_shell_activity);
+        mShellManager = (ShellManager) findViewById(R.id.shell_container);
+        mWindowAndroid = new WindowAndroid(this);
+        mWindowAndroid.restoreInstanceState(savedInstanceState);
+        mShellManager.setWindow(mWindowAndroid);
+
+        String startupUrl = getUrlFromIntent(getIntent());
+        if (!TextUtils.isEmpty(startupUrl)) {
+            mShellManager.setStartupUrl(Shell.sanitizeUrl(startupUrl));
+        }
+
+        if (CommandLine.getInstance().hasSwitch(CommandLine.DUMP_RENDER_TREE)) {
+            try {
+                if (!AndroidBrowserProcess.init(this, AndroidBrowserProcess.MAX_RENDERERS_LIMIT)) {
+                    finishInitialization(savedInstanceState);
+                }
+            } catch (ProcessInitException e) {
+                initializationFailed();
+            }
+        } else {
+            BrowserStartupController.get(this).startBrowserProcessesAsync(
+                    new BrowserStartupController.StartupCallback() {
+                @Override
+                public void onSuccess(boolean alreadyStarted) {
+                    finishInitialization(savedInstanceState);
+                }
+
+                @Override
+                public void onFailure() {
+                    initializationFailed();
+                }
+            });
         }
     }
 
-    private void finishInitialization() {
+    private void finishInitialization(Bundle savedInstanceState) {
+        String shellUrl = ShellManager.DEFAULT_SHELL_URL;
+        if (savedInstanceState != null
+                && savedInstanceState.containsKey(ACTIVE_SHELL_URL_KEY)) {
+            shellUrl = savedInstanceState.getString(ACTIVE_SHELL_URL_KEY);
+        }
+        mShellManager.launchShell(shellUrl);
         getActiveContentView().setContentViewClient(new ContentViewClient() {
             @Override
             public ContentVideoViewClient getContentVideoViewClient() {
@@ -133,6 +138,14 @@
         });
     }
 
+    private void initializationFailed() {
+        Log.e(TAG, "ContentView initialization failed.");
+        Toast.makeText(ContentShellActivity.this,
+                R.string.browser_process_initialization_failed,
+                Toast.LENGTH_SHORT).show();
+        finish();
+    }
+
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
diff --git a/content/shell/android/shell_jni_registrar.cc b/content/shell/android/shell_jni_registrar.cc
index 504eda7..bd71354 100644
--- a/content/shell/android/shell_jni_registrar.cc
+++ b/content/shell/android/shell_jni_registrar.cc
@@ -7,7 +7,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_registrar.h"
 #include "content/shell/android/shell_manager.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 
 namespace {
 
diff --git a/content/shell/android/shell_manager.cc b/content/shell/android/shell_manager.cc
index 08df6a4..9dbd46d 100644
--- a/content/shell/android/shell_manager.cc
+++ b/content/shell/android/shell_manager.cc
@@ -10,9 +10,9 @@
 #include "base/bind.h"
 #include "base/lazy_instance.h"
 #include "content/public/browser/web_contents.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_content_browser_client.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 "jni/ShellManager_jni.h"
 #include "url/gurl.h"
 
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index b5adadb..8e60a32 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -14,10 +14,10 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/layouttest_support.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"
 #include "content/shell/common/shell_switches.h"
 #include "content/shell/renderer/shell_content_renderer_client.h"
-#include "content/shell/shell_browser_main.h"
-#include "content/shell/shell_content_browser_client.h"
 #include "net/cookies/cookie_monster.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
@@ -125,8 +125,6 @@
 #endif
     command_line.AppendSwitch(switches::kSkipGpuDataLoading);
     command_line.AppendSwitch(switches::kDisableGpuVsync);
-    command_line.AppendSwitch(switches::kEnableExperimentalWebPlatformFeatures);
-    command_line.AppendSwitch(switches::kEnableCssShaders);
     command_line.AppendSwitchASCII(switches::kTouchEvents,
                                    switches::kTouchEventsEnabled);
     command_line.AppendSwitch(switches::kEnableGestureTapHighlight);
@@ -139,6 +137,12 @@
     command_line.AppendSwitch(cc::switches::kDisableImplSidePainting);
 #endif
 
+    if (!command_line.HasSwitch(switches::kStableReleaseMode)) {
+      command_line.AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+      command_line.AppendSwitch(switches::kEnableCssShaders);
+    }
+
     if (!command_line.HasSwitch(switches::kEnableThreadedCompositing))
       command_line.AppendSwitch(cc::switches::kDisableThreadedAnimation);
 
diff --git a/content/shell/browser/minimal_shell.cc b/content/shell/browser/minimal_shell.cc
new file mode 100644
index 0000000..e7e88f8
--- /dev/null
+++ b/content/shell/browser/minimal_shell.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 "content/shell/browser/minimal_shell.h"
+
+#include "ui/aura/client/default_capture_client.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/test_activation_client.h"
+#include "ui/views/corewm/compound_event_filter.h"
+#include "ui/views/corewm/input_method_event_filter.h"
+
+namespace content {
+
+MinimalShell::MinimalShell(const gfx::Size& default_window_size) {
+  root_window_.reset(new aura::RootWindow(
+      aura::RootWindow::CreateParams(
+          gfx::Rect(default_window_size))));
+  root_window_->Init();
+  aura::client::SetStackingClient(root_window_.get(), this);
+
+  focus_client_.reset(new aura::FocusManager);
+  aura::client::SetFocusClient(root_window_.get(), focus_client_.get());
+
+  root_window_event_filter_ = new views::corewm::CompoundEventFilter;
+  // Pass ownership of the filter to the root_window.
+  root_window_->SetEventFilter(root_window_event_filter_);
+
+  input_method_filter_.reset(new views::corewm::InputMethodEventFilter(
+      root_window_->GetAcceleratedWidget()));
+  input_method_filter_->SetInputMethodPropertyInRootWindow(
+      root_window_.get());
+  root_window_event_filter_->AddHandler(input_method_filter_.get());
+
+  test_activation_client_.reset(
+      new aura::test::TestActivationClient(root_window_.get()));
+
+  capture_client_.reset(
+      new aura::client::DefaultCaptureClient(root_window_.get()));
+}
+
+MinimalShell::~MinimalShell() {
+  root_window_event_filter_->RemoveHandler(input_method_filter_.get());
+}
+
+aura::Window* MinimalShell::GetDefaultParent(
+    aura::Window* context,
+    aura::Window* window,
+    const gfx::Rect& bounds) {
+  return root_window_.get();
+}
+
+}  // namespace content
diff --git a/content/shell/browser/minimal_shell.h b/content/shell/browser/minimal_shell.h
new file mode 100644
index 0000000..1388da9
--- /dev/null
+++ b/content/shell/browser/minimal_shell.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 CONTENT_SHELL_BROWSER_MINIMAL_SHELL_H_
+#define CONTENT_SHELL_BROWSER_MINIMAL_SHELL_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/client/stacking_client.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+namespace client {
+class DefaultCaptureClient;
+class FocusClient;
+}
+namespace test {
+class TestActivationClient;
+}
+}
+
+namespace gfx {
+class Rect;
+class Size;
+}
+
+namespace views {
+namespace corewm {
+class CompoundEventFilter;
+class InputMethodEventFilter;
+}
+}
+
+namespace content {
+
+// 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 {
+ public:
+  explicit MinimalShell(const gfx::Size& default_window_size);
+  virtual ~MinimalShell();
+
+  // Overridden from client::StackingClient:
+  virtual aura::Window* GetDefaultParent(aura::Window* context,
+                                         aura::Window* window,
+                                         const gfx::Rect& bounds) OVERRIDE;
+
+ private:
+  scoped_ptr<aura::RootWindow> root_window_;
+
+  // Owned by RootWindow
+  views::corewm::CompoundEventFilter* root_window_event_filter_;
+
+  scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
+  scoped_ptr<views::corewm::InputMethodEventFilter> input_method_filter_;
+  scoped_ptr<aura::test::TestActivationClient> test_activation_client_;
+  scoped_ptr<aura::client::FocusClient> focus_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(MinimalShell);
+};
+
+}  // namespace content;
+
+#endif  // CONTENT_SHELL_BROWSER_MINIMAL_SHELL_H_
diff --git a/content/shell/browser/notify_done_forwarder.cc b/content/shell/browser/notify_done_forwarder.cc
new file mode 100644
index 0000000..6d8f104
--- /dev/null
+++ b/content/shell/browser/notify_done_forwarder.cc
@@ -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.
+
+#include "content/shell/browser/notify_done_forwarder.h"
+
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_messages.h"
+
+namespace content {
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(NotifyDoneForwarder);
+
+NotifyDoneForwarder::NotifyDoneForwarder(WebContents* web_contents)
+    : WebContentsObserver(web_contents) {}
+
+NotifyDoneForwarder::~NotifyDoneForwarder() {}
+
+bool NotifyDoneForwarder::OnMessageReceived(const IPC::Message& message) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(NotifyDoneForwarder, message)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinishedInSecondaryWindow,
+                        OnTestFinishedInSecondaryWindow)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void NotifyDoneForwarder::OnTestFinishedInSecondaryWindow() {
+  WebKitTestController::Get()->TestFinishedInSecondaryWindow();
+}
+
+}  // namespace content
diff --git a/content/shell/browser/notify_done_forwarder.h b/content/shell/browser/notify_done_forwarder.h
new file mode 100644
index 0000000..e5a2f3f
--- /dev/null
+++ b/content/shell/browser/notify_done_forwarder.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 CONTENT_SHELL_BROWSER_NOTIFY_DONE_FORWARDER_H_
+#define CONTENT_SHELL_BROWSER_NOTIFY_DONE_FORWARDER_H_
+
+#include "base/basictypes.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+
+class NotifyDoneForwarder : public WebContentsObserver,
+                            public WebContentsUserData<NotifyDoneForwarder> {
+ public:
+  virtual ~NotifyDoneForwarder();
+
+  // WebContentsObserver implementation.
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ private:
+  friend class WebContentsUserData<NotifyDoneForwarder>;
+
+  explicit NotifyDoneForwarder(WebContents* web_contents);
+
+  void OnTestFinishedInSecondaryWindow();
+
+  DISALLOW_COPY_AND_ASSIGN(NotifyDoneForwarder);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_NOTIFY_DONE_FORWARDER_H_
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc
new file mode 100644
index 0000000..c8616d3
--- /dev/null
+++ b/content/shell/browser/shell.cc
@@ -0,0 +1,367 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell.h"
+
+#include "base/auto_reset.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.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 "content/public/browser/devtools_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_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/renderer_preferences.h"
+#include "content/shell/browser/notify_done_forwarder.h"
+#include "content/shell/browser/shell_browser_main_parts.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_devtools_frontend.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_messages.h"
+#include "content/shell/common/shell_switches.h"
+
+namespace content {
+
+const int Shell::kDefaultTestWindowWidthDip = 800;
+const int Shell::kDefaultTestWindowHeightDip = 600;
+
+std::vector<Shell*> Shell::windows_;
+base::Callback<void(Shell*)> Shell::shell_created_callback_;
+
+bool Shell::quit_message_loop_ = true;
+
+class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
+ public:
+  DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
+      : WebContentsObserver(web_contents),
+        shell_(shell) {
+  }
+
+  // WebContentsObserver
+  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
+    shell_->OnDevToolsWebContentsDestroyed();
+  }
+
+ private:
+  Shell* shell_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
+};
+
+Shell::Shell(WebContents* web_contents)
+    : devtools_frontend_(NULL),
+      is_fullscreen_(false),
+      window_(NULL),
+      url_edit_view_(NULL),
+#if defined(OS_WIN) && !defined(USE_AURA)
+      default_edit_wnd_proc_(0),
+#endif
+      headless_(false) {
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kDumpRenderTree))
+    headless_ = true;
+  registrar_.Add(this, NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
+      Source<WebContents>(web_contents));
+  windows_.push_back(this);
+
+  if (!shell_created_callback_.is_null()) {
+    shell_created_callback_.Run(this);
+    shell_created_callback_.Reset();
+  }
+}
+
+Shell::~Shell() {
+  PlatformCleanUp();
+
+  for (size_t i = 0; i < windows_.size(); ++i) {
+    if (windows_[i] == this) {
+      windows_.erase(windows_.begin() + i);
+      break;
+    }
+  }
+
+  if (windows_.empty() && quit_message_loop_)
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::MessageLoop::QuitClosure());
+}
+
+Shell* Shell::CreateShell(WebContents* web_contents,
+                          const gfx::Size& initial_size) {
+  Shell* shell = new Shell(web_contents);
+  shell->PlatformCreateWindow(initial_size.width(), initial_size.height());
+
+  shell->web_contents_.reset(web_contents);
+  web_contents->SetDelegate(shell);
+
+  shell->PlatformSetContents();
+
+  shell->PlatformResizeSubViews();
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+    web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
+    web_contents->GetRenderViewHost()->SyncRendererPrefs();
+  }
+
+  return shell;
+}
+
+void Shell::CloseAllWindows() {
+  base::AutoReset<bool> auto_reset(&quit_message_loop_, false);
+  DevToolsManager::GetInstance()->CloseAllClientHosts();
+  std::vector<Shell*> open_windows(windows_);
+  for (size_t i = 0; i < open_windows.size(); ++i)
+    open_windows[i]->Close();
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void Shell::SetShellCreatedCallback(
+    base::Callback<void(Shell*)> shell_created_callback) {
+  DCHECK(shell_created_callback_.is_null());
+  shell_created_callback_ = shell_created_callback;
+}
+
+Shell* Shell::FromRenderViewHost(RenderViewHost* rvh) {
+  for (size_t i = 0; i < windows_.size(); ++i) {
+    if (windows_[i]->web_contents() &&
+        windows_[i]->web_contents()->GetRenderViewHost() == rvh) {
+      return windows_[i];
+    }
+  }
+  return NULL;
+}
+
+// static
+void Shell::Initialize() {
+  PlatformInitialize(
+      gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
+}
+
+Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
+                              const GURL& url,
+                              SiteInstance* site_instance,
+                              int routing_id,
+                              const gfx::Size& initial_size) {
+  WebContents::CreateParams create_params(browser_context, site_instance);
+  create_params.routing_id = routing_id;
+  if (!initial_size.IsEmpty())
+    create_params.initial_size = initial_size;
+  else
+    create_params.initial_size =
+        gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
+  WebContents* web_contents = WebContents::Create(create_params);
+  Shell* shell = CreateShell(web_contents, create_params.initial_size);
+  if (!url.is_empty())
+    shell->LoadURL(url);
+  return shell;
+}
+
+void Shell::LoadURL(const GURL& url) {
+  LoadURLForFrame(url, std::string());
+}
+
+void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) {
+  NavigationController::LoadURLParams params(url);
+  params.transition_type = PageTransitionFromInt(
+      PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR);
+  params.frame_name = frame_name;
+  web_contents_->GetController().LoadURLWithParams(params);
+  web_contents_->GetView()->Focus();
+}
+
+void Shell::GoBackOrForward(int offset) {
+  web_contents_->GetController().GoToOffset(offset);
+  web_contents_->GetView()->Focus();
+}
+
+void Shell::Reload() {
+  web_contents_->GetController().Reload(false);
+  web_contents_->GetView()->Focus();
+}
+
+void Shell::Stop() {
+  web_contents_->Stop();
+  web_contents_->GetView()->Focus();
+}
+
+void Shell::UpdateNavigationControls() {
+  int current_index = web_contents_->GetController().GetCurrentEntryIndex();
+  int max_index = web_contents_->GetController().GetEntryCount() - 1;
+
+  PlatformEnableUIControl(BACK_BUTTON, current_index > 0);
+  PlatformEnableUIControl(FORWARD_BUTTON, current_index < max_index);
+  PlatformEnableUIControl(STOP_BUTTON, web_contents_->IsLoading());
+}
+
+void Shell::ShowDevTools() {
+  if (devtools_frontend_) {
+    devtools_frontend_->Focus();
+    return;
+  }
+  devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
+  devtools_observer_.reset(new DevToolsWebContentsObserver(
+      this, devtools_frontend_->frontend_shell()->web_contents()));
+}
+
+void Shell::CloseDevTools() {
+  if (!devtools_frontend_)
+    return;
+  devtools_observer_.reset();
+  devtools_frontend_->Close();
+  devtools_frontend_ = NULL;
+}
+
+gfx::NativeView Shell::GetContentView() {
+  if (!web_contents_)
+    return NULL;
+  return web_contents_->GetView()->GetNativeView();
+}
+
+WebContents* Shell::OpenURLFromTab(WebContents* source,
+                                   const OpenURLParams& params) {
+  // The only one we implement for now.
+  DCHECK(params.disposition == CURRENT_TAB);
+  NavigationController::LoadURLParams load_url_params(params.url);
+  load_url_params.referrer = params.referrer;
+  load_url_params.transition_type = params.transition;
+  load_url_params.extra_headers = params.extra_headers;
+  load_url_params.should_replace_current_entry =
+      params.should_replace_current_entry;
+
+  if (params.transferred_global_request_id != GlobalRequestID()) {
+    load_url_params.is_renderer_initiated = params.is_renderer_initiated;
+    load_url_params.transferred_global_request_id =
+        params.transferred_global_request_id;
+  } else if (params.is_renderer_initiated) {
+    load_url_params.is_renderer_initiated = true;
+  }
+
+  source->GetController().LoadURLWithParams(load_url_params);
+  return source;
+}
+
+void Shell::LoadingStateChanged(WebContents* source) {
+  UpdateNavigationControls();
+  PlatformSetIsLoading(source->IsLoading());
+}
+
+void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
+                                       bool enter_fullscreen) {
+#if defined(OS_ANDROID)
+  PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
+#endif
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+  if (is_fullscreen_ != enter_fullscreen) {
+    is_fullscreen_ = enter_fullscreen;
+    web_contents->GetRenderViewHost()->WasResized();
+  }
+}
+
+bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
+#if defined(OS_ANDROID)
+  return PlatformIsFullscreenForTabOrPending(web_contents);
+#else
+  return is_fullscreen_;
+#endif
+}
+
+void Shell::RequestToLockMouse(WebContents* web_contents,
+                               bool user_gesture,
+                               bool last_unlocked_by_target) {
+  web_contents->GotResponseToLockMouseRequest(true);
+}
+
+void Shell::CloseContents(WebContents* source) {
+  Close();
+}
+
+bool Shell::CanOverscrollContent() const {
+#if defined(USE_AURA)
+  return true;
+#else
+  return false;
+#endif
+}
+
+void Shell::WebContentsCreated(WebContents* source_contents,
+                               int64 source_frame_id,
+                               const string16& frame_name,
+                               const GURL& target_url,
+                               WebContents* new_contents) {
+  CreateShell(new_contents, source_contents->GetView()->GetContainerSize());
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    NotifyDoneForwarder::CreateForWebContents(new_contents);
+}
+
+void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
+  PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
+}
+
+JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
+  if (!dialog_manager_)
+    dialog_manager_.reset(new ShellJavaScriptDialogManager());
+  return dialog_manager_.get();
+}
+
+bool Shell::AddMessageToConsole(WebContents* source,
+                                int32 level,
+                                const string16& message,
+                                int32 line_no,
+                                const string16& source_id) {
+  return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
+}
+
+void Shell::RendererUnresponsive(WebContents* source) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+  WebKitTestController::Get()->RendererUnresponsive();
+}
+
+void Shell::ActivateContents(WebContents* contents) {
+  contents->GetRenderViewHost()->Focus();
+}
+
+void Shell::DeactivateContents(WebContents* contents) {
+  contents->GetRenderViewHost()->Blur();
+}
+
+void Shell::WorkerCrashed(WebContents* source) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+  WebKitTestController::Get()->WorkerCrashed();
+}
+
+void Shell::Observe(int type,
+                    const NotificationSource& source,
+                    const NotificationDetails& details) {
+  if (type == NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
+    std::pair<NavigationEntry*, bool>* title =
+        Details<std::pair<NavigationEntry*, bool> >(details).ptr();
+
+    if (title->first) {
+      string16 text = title->first->GetTitle();
+      PlatformSetTitle(text);
+    }
+  } else {
+    NOTREACHED();
+  }
+}
+
+void Shell::OnDevToolsWebContentsDestroyed() {
+  devtools_observer_.reset();
+  devtools_frontend_ = NULL;
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
new file mode 100644
index 0000000..24c58c8
--- /dev/null
+++ b/content/shell/browser/shell.h
@@ -0,0 +1,286 @@
+// Copyright 2013 The Chromium Authors. 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_BROWSER_SHELL_H_
+#define CONTENT_SHELL_BROWSER_SHELL_H_
+
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "ipc/ipc_channel.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/size.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#include "ui/base/gtk/gtk_signal.h"
+
+typedef struct _GtkToolItem GtkToolItem;
+#elif defined(OS_ANDROID)
+#include "base/android/scoped_java_ref.h"
+#elif defined(USE_AURA)
+#if defined(OS_CHROMEOS)
+namespace content {
+class MinimalShell;
+}
+#endif
+namespace views {
+class Widget;
+class ViewsDelegate;
+}
+#endif
+
+class GURL;
+namespace content {
+
+class BrowserContext;
+class ShellDevToolsFrontend;
+class ShellJavaScriptDialogManager;
+class SiteInstance;
+class WebContents;
+
+// This represents one window of the Content Shell, i.e. all the UI including
+// buttons and url bar, as well as the web content area.
+class Shell : public WebContentsDelegate,
+              public NotificationObserver {
+ public:
+  static const int kDefaultTestWindowWidthDip;
+  static const int kDefaultTestWindowHeightDip;
+
+  virtual ~Shell();
+
+  void LoadURL(const GURL& url);
+  void LoadURLForFrame(const GURL& url, const std::string& frame_name);
+  void GoBackOrForward(int offset);
+  void Reload();
+  void Stop();
+  void UpdateNavigationControls();
+  void Close();
+  void ShowDevTools();
+  void CloseDevTools();
+#if (defined(OS_WIN) && !defined(USE_AURA)) || \
+    defined(TOOLKIT_GTK) || defined(OS_MACOSX)
+  // Resizes the main window to the given dimensions.
+  void SizeTo(int width, int height);
+#endif
+
+  // Do one time initialization at application startup.
+  static void Initialize();
+
+  static Shell* CreateNewWindow(BrowserContext* browser_context,
+                                const GURL& url,
+                                SiteInstance* site_instance,
+                                int routing_id,
+                                const gfx::Size& initial_size);
+
+  // Returns the Shell object corresponding to the given RenderViewHost.
+  static Shell* FromRenderViewHost(RenderViewHost* rvh);
+
+  // Returns the currently open windows.
+  static std::vector<Shell*>& windows() { return windows_; }
+
+  // Closes all windows and returns. This runs a message loop.
+  static void CloseAllWindows();
+
+  // Closes all windows and exits.
+  static void PlatformExit();
+
+  // Used for content_browsertests. Called once.
+  static void SetShellCreatedCallback(
+      base::Callback<void(Shell*)> shell_created_callback);
+
+  WebContents* web_contents() const { return web_contents_.get(); }
+  gfx::NativeWindow window() { return window_; }
+
+#if defined(OS_MACOSX)
+  // Public to be called by an ObjC bridge object.
+  void ActionPerformed(int control);
+  void URLEntered(std::string url_string);
+#elif defined(OS_ANDROID)
+  // Registers the Android Java to native methods.
+  static bool Register(JNIEnv* env);
+#endif
+
+  // WebContentsDelegate
+  virtual WebContents* OpenURLFromTab(WebContents* source,
+                                      const OpenURLParams& params) OVERRIDE;
+  virtual void LoadingStateChanged(WebContents* source) OVERRIDE;
+#if defined(OS_ANDROID)
+  virtual void LoadProgressChanged(WebContents* source,
+                                   double progress) OVERRIDE;
+#endif
+  virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
+                                          bool enter_fullscreen) OVERRIDE;
+  virtual bool IsFullscreenForTabOrPending(
+      const WebContents* web_contents) const OVERRIDE;
+  virtual void RequestToLockMouse(WebContents* web_contents,
+                                  bool user_gesture,
+                                  bool last_unlocked_by_target) OVERRIDE;
+  virtual void CloseContents(WebContents* source) OVERRIDE;
+  virtual bool CanOverscrollContent() const OVERRIDE;
+  virtual void WebContentsCreated(WebContents* source_contents,
+                                  int64 source_frame_id,
+                                  const string16& frame_name,
+                                  const GURL& target_url,
+                                  WebContents* new_contents) OVERRIDE;
+  virtual void DidNavigateMainFramePostCommit(
+      WebContents* web_contents) OVERRIDE;
+  virtual JavaScriptDialogManager* GetJavaScriptDialogManager() OVERRIDE;
+#if defined(OS_MACOSX)
+  virtual void HandleKeyboardEvent(
+      WebContents* source,
+      const NativeWebKeyboardEvent& event) OVERRIDE;
+#endif
+  virtual bool AddMessageToConsole(WebContents* source,
+                                   int32 level,
+                                   const string16& message,
+                                   int32 line_no,
+                                   const string16& source_id) OVERRIDE;
+  virtual void RendererUnresponsive(WebContents* source) OVERRIDE;
+  virtual void ActivateContents(WebContents* contents) OVERRIDE;
+  virtual void DeactivateContents(WebContents* contents) OVERRIDE;
+  virtual void WorkerCrashed(WebContents* source) OVERRIDE;
+
+ private:
+  enum UIControl {
+    BACK_BUTTON,
+    FORWARD_BUTTON,
+    STOP_BUTTON
+  };
+
+  class DevToolsWebContentsObserver;
+
+  explicit Shell(WebContents* web_contents);
+
+  // Helper to create a new Shell given a newly created WebContents.
+  static Shell* CreateShell(WebContents* web_contents,
+                            const gfx::Size& initial_size);
+
+  // Helper for one time initialization of application
+  static void PlatformInitialize(const gfx::Size& default_window_size);
+
+  // All the methods that begin with Platform need to be implemented by the
+  // platform specific Shell implementation.
+  // Called from the destructor to let each platform do any necessary cleanup.
+  void PlatformCleanUp();
+  // Creates the main window GUI.
+  void PlatformCreateWindow(int width, int height);
+  // Links the WebContents into the newly created window.
+  void PlatformSetContents();
+  // Resize the content area and GUI.
+  void PlatformResizeSubViews();
+  // Enable/disable a button.
+  void PlatformEnableUIControl(UIControl control, bool is_enabled);
+  // Updates the url in the url bar.
+  void PlatformSetAddressBarURL(const GURL& url);
+  // Sets whether the spinner is spinning.
+  void PlatformSetIsLoading(bool loading);
+  // Set the title of shell window
+  void PlatformSetTitle(const string16& title);
+#if defined(OS_ANDROID)
+  void PlatformToggleFullscreenModeForTab(WebContents* web_contents,
+                                          bool enter_fullscreen);
+  bool PlatformIsFullscreenForTabOrPending(
+      const WebContents* web_contents) const;
+#endif
+
+  gfx::NativeView GetContentView();
+
+  // NotificationObserver
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE;
+
+  void OnDevToolsWebContentsDestroyed();
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+  static ATOM RegisterWindowClass();
+  static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+  static LRESULT CALLBACK EditWndProc(HWND, UINT, WPARAM, LPARAM);
+#elif defined(TOOLKIT_GTK)
+  CHROMEGTK_CALLBACK_0(Shell, void, OnBackButtonClicked);
+  CHROMEGTK_CALLBACK_0(Shell, void, OnForwardButtonClicked);
+  CHROMEGTK_CALLBACK_0(Shell, void, OnReloadButtonClicked);
+  CHROMEGTK_CALLBACK_0(Shell, void, OnStopButtonClicked);
+  CHROMEGTK_CALLBACK_0(Shell, void, OnURLEntryActivate);
+  CHROMEGTK_CALLBACK_0(Shell, gboolean, OnWindowDestroyed);
+
+  CHROMEG_CALLBACK_3(Shell, gboolean, OnCloseWindowKeyPressed, GtkAccelGroup*,
+                     GObject*, guint, GdkModifierType);
+  CHROMEG_CALLBACK_3(Shell, gboolean, OnNewWindowKeyPressed, GtkAccelGroup*,
+                     GObject*, guint, GdkModifierType);
+  CHROMEG_CALLBACK_3(Shell, gboolean, OnHighlightURLView, GtkAccelGroup*,
+                     GObject*, guint, GdkModifierType);
+  CHROMEG_CALLBACK_3(Shell, gboolean, OnReloadKeyPressed, GtkAccelGroup*,
+                     GObject*, guint, GdkModifierType);
+#endif
+
+  scoped_ptr<ShellJavaScriptDialogManager> dialog_manager_;
+
+  scoped_ptr<WebContents> web_contents_;
+
+  scoped_ptr<DevToolsWebContentsObserver> devtools_observer_;
+  ShellDevToolsFrontend* devtools_frontend_;
+
+  bool is_fullscreen_;
+
+  gfx::NativeWindow window_;
+  gfx::NativeEditView url_edit_view_;
+
+  // Notification manager
+  NotificationRegistrar registrar_;
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+  WNDPROC default_edit_wnd_proc_;
+  static HINSTANCE instance_handle_;
+#elif defined(TOOLKIT_GTK)
+  GtkWidget* vbox_;
+
+  GtkToolItem* back_button_;
+  GtkToolItem* forward_button_;
+  GtkToolItem* reload_button_;
+  GtkToolItem* stop_button_;
+
+  GtkWidget* spinner_;
+  GtkToolItem* spinner_item_;
+
+  int content_width_;
+  int content_height_;
+  int ui_elements_height_; // height of menubar, toolbar, etc.
+#elif defined(OS_ANDROID)
+  base::android::ScopedJavaGlobalRef<jobject> java_object_;
+#elif defined(USE_AURA)
+#if defined(OS_CHROMEOS)
+  static content::MinimalShell* minimal_shell_;
+#endif
+  static views::ViewsDelegate* views_delegate_;
+
+  views::Widget* window_widget_;
+#elif defined(OS_MACOSX)
+  int content_width_;
+  int content_height_;
+#endif
+
+  bool headless_;
+
+  // A container of all the open windows. We use a vector so we can keep track
+  // of ordering.
+  static std::vector<Shell*> windows_;
+
+  static base::Callback<void(Shell*)> shell_created_callback_;
+
+  // True if the destructur of Shell should post a quit closure on the current
+  // message loop if the destructed Shell object was the last one.
+  static bool quit_message_loop_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_H_
diff --git a/content/shell/browser/shell_android.cc b/content/shell/browser/shell_android.cc
new file mode 100644
index 0000000..d827e96
--- /dev/null
+++ b/content/shell/browser/shell_android.cc
@@ -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.
+
+#include "content/shell/browser/shell.h"
+
+#include <jni.h>
+
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "content/public/common/content_switches.h"
+#include "content/shell/android/shell_manager.h"
+#include "jni/Shell_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
+
+namespace content {
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  DCHECK(command_line->HasSwitch(switches::kForceCompositingMode));
+  DCHECK(command_line->HasSwitch(switches::kEnableThreadedCompositing));
+}
+
+void Shell::PlatformCleanUp() {
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
+  Java_Shell_onUpdateUrl(env, java_object_.obj(), j_url.obj());
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+  JNIEnv* env = AttachCurrentThread();
+  Java_Shell_setIsLoading(env, java_object_.obj(), loading);
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+  java_object_.Reset(AttachCurrentThread(), CreateShellView(this));
+}
+
+void Shell::PlatformSetContents() {
+  JNIEnv* env = AttachCurrentThread();
+  Java_Shell_initFromNativeTabContents(
+      env, java_object_.obj(), reinterpret_cast<jint>(web_contents()));
+}
+
+void Shell::PlatformResizeSubViews() {
+  // Not needed; subviews are bound.
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+  NOTIMPLEMENTED();
+}
+
+void Shell::LoadProgressChanged(WebContents* source, double progress) {
+  JNIEnv* env = AttachCurrentThread();
+  Java_Shell_onLoadProgressChanged(env, java_object_.obj(), progress);
+}
+
+void Shell::PlatformToggleFullscreenModeForTab(WebContents* web_contents,
+                                               bool enter_fullscreen) {
+  JNIEnv* env = AttachCurrentThread();
+  Java_Shell_toggleFullscreenModeForTab(
+      env, java_object_.obj(), enter_fullscreen);
+}
+
+bool Shell::PlatformIsFullscreenForTabOrPending(
+    const WebContents* web_contents) const {
+  JNIEnv* env = AttachCurrentThread();
+  return Java_Shell_isFullscreenForTabOrPending(env, java_object_.obj());
+}
+
+void Shell::Close() {
+  CloseShellView(java_object_.obj());
+  java_object_.Reset();
+  delete this;
+}
+
+// static
+bool Shell::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_application_mac.h b/content/shell/browser/shell_application_mac.h
new file mode 100644
index 0000000..bcba5a5
--- /dev/null
+++ b/content/shell/browser/shell_application_mac.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 CONTENT_SHELL_BROWSER_SHELL_APPLICATION_MAC_H_
+#define CONTENT_SHELL_BROWSER_SHELL_APPLICATION_MAC_H_
+
+#include "base/mac/scoped_sending_event.h"
+#include "base/message_loop/message_pump_mac.h"
+
+@interface ShellCrApplication : NSApplication<CrAppProtocol,
+                                              CrAppControlProtocol> {
+ @private
+  BOOL handlingSendEvent_;
+}
+
+// CrAppProtocol:
+- (BOOL)isHandlingSendEvent;
+
+// CrAppControlProtocol:
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
+
+- (IBAction)newDocument:(id)sender;
+
+@end
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_APPLICATION_MAC_H_
diff --git a/content/shell/browser/shell_application_mac.mm b/content/shell/browser/shell_application_mac.mm
new file mode 100644
index 0000000..e18df5b
--- /dev/null
+++ b/content/shell/browser/shell_application_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 "content/shell/browser/shell_application_mac.h"
+
+#include "base/auto_reset.h"
+#include "content/public/common/url_constants.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 "url/gurl.h"
+
+@implementation ShellCrApplication
+
+- (BOOL)isHandlingSendEvent {
+  return handlingSendEvent_;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+  base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
+  [super sendEvent:event];
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+  handlingSendEvent_ = handlingSendEvent;
+}
+
+- (IBAction)newDocument:(id)sender {
+  content::ShellBrowserContext* browserContext =
+      content::ShellContentBrowserClient::Get()->browser_context();
+  content::Shell::CreateNewWindow(browserContext,
+                                  GURL(content::kAboutBlankURL),
+                                  NULL,
+                                  MSG_ROUTING_NONE,
+                                  gfx::Size());
+}
+
+@end
diff --git a/content/shell/browser/shell_aura.cc b/content/shell/browser/shell_aura.cc
new file mode 100644
index 0000000..ba3366e
--- /dev/null
+++ b/content/shell/browser/shell_aura.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 "content/shell/browser/shell.h"
+
+#include "base/command_line.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/events/event.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/test/desktop_test_views_delegate.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "content/shell/browser/minimal_shell.h"
+#include "ui/aura/test/test_screen.h"
+#endif
+
+#if defined(OS_WIN)
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+namespace content {
+
+namespace {
+// ViewDelegate implementation for aura content shell
+class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate {
+ public:
+  ShellViewsDelegateAura() : use_transparent_windows_(false) {
+  }
+
+  virtual ~ShellViewsDelegateAura() {
+  }
+
+  void SetUseTransparentWindows(bool transparent) {
+    use_transparent_windows_ = transparent;
+  }
+
+  // Overridden from views::TestViewsDelegate:
+  virtual bool UseTransparentWindows() const OVERRIDE {
+    return use_transparent_windows_;
+  }
+
+ private:
+  bool use_transparent_windows_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura);
+};
+
+// Maintain the UI controls and web view for content shell
+class ShellWindowDelegateView : public views::WidgetDelegateView,
+                                public views::TextfieldController,
+                                public views::ButtonListener {
+ public:
+  enum UIControl {
+    BACK_BUTTON,
+    FORWARD_BUTTON,
+    STOP_BUTTON
+  };
+
+  ShellWindowDelegateView(Shell* shell)
+    : shell_(shell),
+      toolbar_view_(new View),
+      contents_view_(new View) {
+  }
+  virtual ~ShellWindowDelegateView() {}
+
+  // Update the state of UI controls
+  void SetAddressBarURL(const GURL& url) {
+    url_entry_->SetText(ASCIIToUTF16(url.spec()));
+  }
+  void SetWebContents(WebContents* web_contents) {
+    contents_view_->SetLayoutManager(new views::FillLayout());
+    web_view_ = new views::WebView(web_contents->GetBrowserContext());
+    web_view_->SetWebContents(web_contents);
+    web_contents->GetView()->Focus();
+    contents_view_->AddChildView(web_view_);
+    Layout();
+  }
+  void SetWindowTitle(const string16& title) { title_ = title; }
+  void EnableUIControl(UIControl control, bool is_enabled) {
+    if (control == BACK_BUTTON) {
+      back_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
+          : views::CustomButton::STATE_DISABLED);
+    } else if (control == FORWARD_BUTTON) {
+      forward_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
+          : views::CustomButton::STATE_DISABLED);
+    } else if (control == STOP_BUTTON) {
+      stop_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
+          : views::CustomButton::STATE_DISABLED);
+    }
+  }
+
+ private:
+  // Initialize the UI control contained in shell window
+  void InitShellWindow() {
+    set_background(views::Background::CreateStandardPanelBackground());
+
+    views::GridLayout* layout = new views::GridLayout(this);
+    SetLayoutManager(layout);
+
+    views::ColumnSet* column_set = layout->AddColumnSet(0);
+    column_set->AddPaddingColumn(0, 2);
+    column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+                          views::GridLayout::USE_PREF, 0, 0);
+    column_set->AddPaddingColumn(0, 2);
+
+    layout->AddPaddingRow(0, 2);
+
+    // Add toolbar buttons and URL text field
+    {
+      layout->StartRow(0, 0);
+      views::GridLayout* toolbar_layout = new views::GridLayout(toolbar_view_);
+      toolbar_view_->SetLayoutManager(toolbar_layout);
+
+      views::ColumnSet* toolbar_column_set =
+          toolbar_layout->AddColumnSet(0);
+      // Back button
+      back_button_ = new views::LabelButton(this, ASCIIToUTF16("Back"));
+      back_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+      gfx::Size back_button_size = back_button_->GetPreferredSize();
+      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+                                    views::GridLayout::CENTER, 0,
+                                    views::GridLayout::FIXED,
+                                    back_button_size.width(),
+                                    back_button_size.width() / 2);
+      // Forward button
+      forward_button_ = new views::LabelButton(this, ASCIIToUTF16("Forward"));
+      forward_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+      gfx::Size forward_button_size = forward_button_->GetPreferredSize();
+      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+                                    views::GridLayout::CENTER, 0,
+                                    views::GridLayout::FIXED,
+                                    forward_button_size.width(),
+                                    forward_button_size.width() / 2);
+      // Refresh button
+      refresh_button_ = new views::LabelButton(this, ASCIIToUTF16("Refresh"));
+      refresh_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+      gfx::Size refresh_button_size = refresh_button_->GetPreferredSize();
+      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+                                    views::GridLayout::CENTER, 0,
+                                    views::GridLayout::FIXED,
+                                    refresh_button_size.width(),
+                                    refresh_button_size.width() / 2);
+      // Stop button
+      stop_button_ = new views::LabelButton(this, ASCIIToUTF16("Stop"));
+      stop_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+      gfx::Size stop_button_size = stop_button_->GetPreferredSize();
+      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+                                    views::GridLayout::CENTER, 0,
+                                    views::GridLayout::FIXED,
+                                    stop_button_size.width(),
+                                    stop_button_size.width() / 2);
+      toolbar_column_set->AddPaddingColumn(0, 2);
+      // URL entry
+      url_entry_ = new views::Textfield();
+      url_entry_->SetController(this);
+      toolbar_column_set->AddColumn(views::GridLayout::FILL,
+                                    views::GridLayout::FILL, 1,
+                                    views::GridLayout::USE_PREF, 0, 0);
+
+      // Fill up the first row
+      toolbar_layout->StartRow(0, 0);
+      toolbar_layout->AddView(back_button_);
+      toolbar_layout->AddView(forward_button_);
+      toolbar_layout->AddView(refresh_button_);
+      toolbar_layout->AddView(stop_button_);
+      toolbar_layout->AddView(url_entry_);
+
+      layout->AddView(toolbar_view_);
+    }
+
+    layout->AddPaddingRow(0, 5);
+
+    // Add web contents view as the second row
+    {
+      layout->StartRow(1, 0);
+      layout->AddView(contents_view_);
+    }
+
+    layout->AddPaddingRow(0, 5);
+  }
+  // Overridden from TextfieldController
+  virtual void ContentsChanged(views::Textfield* sender,
+                               const string16& new_contents) OVERRIDE {
+  }
+  virtual bool HandleKeyEvent(views::Textfield* sender,
+                              const ui::KeyEvent& key_event) OVERRIDE {
+   if (sender == url_entry_ && key_event.key_code() == ui::VKEY_RETURN) {
+     std::string text = UTF16ToUTF8(url_entry_->text());
+     GURL url(text);
+     if (!url.has_scheme()) {
+       url = GURL(std::string("http://") + std::string(text));
+       url_entry_->SetText(ASCIIToUTF16(url.spec()));
+     }
+     shell_->LoadURL(url);
+     return true;
+   }
+   return false;
+  }
+
+  // Overridden from ButtonListener
+  virtual void ButtonPressed(views::Button* sender,
+                             const ui::Event& event) OVERRIDE {
+    if (sender == back_button_)
+      shell_->GoBackOrForward(-1);
+    else if (sender == forward_button_)
+      shell_->GoBackOrForward(1);
+    else if (sender == refresh_button_)
+      shell_->Reload();
+    else if (sender == stop_button_)
+      shell_->Stop();
+  }
+
+  // Overridden from WidgetDelegateView
+  virtual bool CanResize() const OVERRIDE { return true; }
+  virtual bool CanMaximize() const OVERRIDE { return true; }
+  virtual string16 GetWindowTitle() const OVERRIDE {
+    return title_;
+  }
+  virtual void WindowClosing() OVERRIDE {
+    if (shell_) {
+      delete shell_;
+      shell_ = NULL;
+    }
+  }
+  virtual View* GetContentsView() OVERRIDE { return this; }
+
+  // Overridden from View
+  virtual void ViewHierarchyChanged(
+      const ViewHierarchyChangedDetails& details) OVERRIDE {
+    if (details.is_add && details.child == this) {
+      InitShellWindow();
+    }
+  }
+
+ private:
+  // Hold a reference of Shell for deleting it when the window is closing
+  Shell* shell_;
+
+  // Window title
+  string16 title_;
+
+  // Toolbar view contains forward/backward/reload button and URL entry
+  View* toolbar_view_;
+  views::LabelButton* back_button_;
+  views::LabelButton* forward_button_;
+  views::LabelButton* refresh_button_;
+  views::LabelButton* stop_button_;
+  views::Textfield* url_entry_;
+
+  // Contents view contains the web contents view
+  View* contents_view_;
+  views::WebView* web_view_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView);
+};
+
+}  // namespace
+
+#if defined(OS_CHROMEOS)
+MinimalShell* Shell::minimal_shell_ = NULL;
+#endif
+views::ViewsDelegate* Shell::views_delegate_ = NULL;
+
+// static
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+#if defined(OS_WIN)
+  _setmode(_fileno(stdout), _O_BINARY);
+  _setmode(_fileno(stderr), _O_BINARY);
+#endif
+#if defined(OS_CHROMEOS)
+  chromeos::DBusThreadManager::Initialize();
+  gfx::Screen::SetScreenInstance(
+      gfx::SCREEN_TYPE_NATIVE, aura::TestScreen::Create());
+  minimal_shell_ = new content::MinimalShell(default_window_size);
+#else
+  gfx::Screen::SetScreenInstance(
+      gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
+#endif
+  views_delegate_ = new ShellViewsDelegateAura();
+}
+
+void Shell::PlatformExit() {
+  std::vector<Shell*> windows = windows_;
+  for (std::vector<Shell*>::iterator it = windows.begin();
+       it != windows.end(); ++it) {
+    if (!(*it)->headless_)
+      (*it)->window_widget_->Close();
+  }
+#if defined(OS_CHROMEOS)
+  if (minimal_shell_)
+    delete minimal_shell_;
+#endif
+  if (views_delegate_)
+    delete views_delegate_;
+#if defined(OS_CHROMEOS)
+  chromeos::DBusThreadManager::Shutdown();
+#endif
+  aura::Env::DeleteInstance();
+}
+
+void Shell::PlatformCleanUp() {
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+  if (headless_)
+    return;
+  ShellWindowDelegateView* delegate_view =
+    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+  if (control == BACK_BUTTON) {
+    delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON,
+        is_enabled);
+  } else if (control == FORWARD_BUTTON) {
+    delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON,
+        is_enabled);
+  } else if (control == STOP_BUTTON) {
+    delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON,
+        is_enabled);
+  }
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+  if (headless_)
+    return;
+  ShellWindowDelegateView* delegate_view =
+    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+  delegate_view->SetAddressBarURL(url);
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+  if (headless_)
+    return;
+#if defined(OS_CHROMEOS)
+  window_widget_ =
+      views::Widget::CreateWindowWithContextAndBounds(
+          new ShellWindowDelegateView(this),
+          minimal_shell_->GetDefaultParent(NULL, NULL, gfx::Rect()),
+          gfx::Rect(0, 0, width, height));
+#else
+  window_widget_ =
+      views::Widget::CreateWindowWithBounds(new ShellWindowDelegateView(this),
+               gfx::Rect(0, 0, width, height));
+#endif
+
+  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_widget_->Show();
+}
+
+void Shell::PlatformSetContents() {
+  if (headless_)
+    return;
+  ShellWindowDelegateView* delegate_view =
+    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+  delegate_view->SetWebContents(web_contents_.get());
+}
+
+void Shell::PlatformResizeSubViews() {
+}
+
+void Shell::Close() {
+  if (headless_)
+    return;
+  window_widget_->CloseNow();
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+  if (headless_)
+    return;
+  ShellWindowDelegateView* delegate_view =
+    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+  delegate_view->SetWindowTitle(title);
+  window_widget_->UpdateWindowTitle();
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc
new file mode 100644
index 0000000..c6dbb99
--- /dev/null
+++ b/content/shell/browser/shell_browser_context.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 "content/shell/browser/shell_browser_context.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/threading/thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_switches.h"
+#include "content/shell/browser/shell_download_manager_delegate.h"
+#include "content/shell/browser/shell_url_request_context_getter.h"
+#include "content/shell/common/shell_switches.h"
+
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#elif defined(OS_LINUX)
+#include "base/nix/xdg_util.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#endif
+
+namespace content {
+
+class ShellBrowserContext::ShellResourceContext : public ResourceContext {
+ public:
+  ShellResourceContext() : getter_(NULL) {}
+  virtual ~ShellResourceContext() {}
+
+  // ResourceContext implementation:
+  virtual net::HostResolver* GetHostResolver() OVERRIDE {
+    CHECK(getter_);
+    return getter_->host_resolver();
+  }
+  virtual net::URLRequestContext* GetRequestContext() OVERRIDE {
+    CHECK(getter_);
+    return getter_->GetURLRequestContext();
+  }
+  virtual bool AllowMicAccess(const GURL& origin) OVERRIDE {
+    return false;
+  }
+  virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE {
+    return false;
+  }
+
+  void set_url_request_context_getter(ShellURLRequestContextGetter* getter) {
+    getter_ = getter;
+  }
+
+ private:
+  ShellURLRequestContextGetter* getter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellResourceContext);
+};
+
+ShellBrowserContext::ShellBrowserContext(bool off_the_record,
+                                         net::NetLog* net_log)
+    : off_the_record_(off_the_record),
+      net_log_(net_log),
+      ignore_certificate_errors_(false),
+      resource_context_(new ShellResourceContext) {
+  InitWhileIOAllowed();
+}
+
+ShellBrowserContext::~ShellBrowserContext() {
+  if (resource_context_) {
+    BrowserThread::DeleteSoon(
+      BrowserThread::IO, FROM_HERE, resource_context_.release());
+  }
+}
+
+void ShellBrowserContext::InitWhileIOAllowed() {
+  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+  if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors) ||
+      cmd_line->HasSwitch(switches::kDumpRenderTree)) {
+    ignore_certificate_errors_ = true;
+  }
+  if (cmd_line->HasSwitch(switches::kContentShellDataPath)) {
+    path_ = cmd_line->GetSwitchValuePath(switches::kContentShellDataPath);
+    return;
+  }
+#if defined(OS_WIN)
+  CHECK(PathService::Get(base::DIR_LOCAL_APP_DATA, &path_));
+  path_ = path_.Append(std::wstring(L"content_shell"));
+#elif defined(OS_LINUX)
+  scoped_ptr<base::Environment> env(base::Environment::Create());
+  base::FilePath config_dir(
+      base::nix::GetXDGDirectory(env.get(),
+                                 base::nix::kXdgConfigHomeEnvVar,
+                                 base::nix::kDotConfigDir));
+  path_ = config_dir.Append("content_shell");
+#elif defined(OS_MACOSX)
+  CHECK(PathService::Get(base::DIR_APP_DATA, &path_));
+  path_ = path_.Append("Chromium Content Shell");
+#elif defined(OS_ANDROID)
+  CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &path_));
+  path_ = path_.Append(FILE_PATH_LITERAL("content_shell"));
+#else
+  NOTIMPLEMENTED();
+#endif
+
+  if (!base::PathExists(path_))
+    file_util::CreateDirectory(path_);
+}
+
+base::FilePath ShellBrowserContext::GetPath() const {
+  return path_;
+}
+
+bool ShellBrowserContext::IsOffTheRecord() const {
+  return off_the_record_;
+}
+
+DownloadManagerDelegate* ShellBrowserContext::GetDownloadManagerDelegate()  {
+  DownloadManager* manager = BrowserContext::GetDownloadManager(this);
+
+  if (!download_manager_delegate_.get()) {
+    download_manager_delegate_ = new ShellDownloadManagerDelegate();
+    download_manager_delegate_->SetDownloadManager(manager);
+    CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+    if (cmd_line->HasSwitch(switches::kDumpRenderTree)) {
+      download_manager_delegate_->SetDownloadBehaviorForTesting(
+          path_.Append(FILE_PATH_LITERAL("downloads")));
+    }
+  }
+
+  return download_manager_delegate_.get();
+}
+
+net::URLRequestContextGetter* ShellBrowserContext::GetRequestContext()  {
+  return GetDefaultStoragePartition(this)->GetURLRequestContext();
+}
+
+net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext(
+    ProtocolHandlerMap* protocol_handlers) {
+  DCHECK(!url_request_getter_.get());
+  url_request_getter_ = new ShellURLRequestContextGetter(
+      ignore_certificate_errors_,
+      GetPath(),
+      BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO),
+      BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE),
+      protocol_handlers,
+      net_log_);
+  resource_context_->set_url_request_context_getter(url_request_getter_.get());
+  return url_request_getter_.get();
+}
+
+net::URLRequestContextGetter*
+    ShellBrowserContext::GetRequestContextForRenderProcess(
+        int renderer_child_id)  {
+  return GetRequestContext();
+}
+
+net::URLRequestContextGetter*
+    ShellBrowserContext::GetMediaRequestContext()  {
+  return GetRequestContext();
+}
+
+net::URLRequestContextGetter*
+    ShellBrowserContext::GetMediaRequestContextForRenderProcess(
+        int renderer_child_id)  {
+  return GetRequestContext();
+}
+
+net::URLRequestContextGetter*
+    ShellBrowserContext::GetMediaRequestContextForStoragePartition(
+        const base::FilePath& partition_path,
+        bool in_memory) {
+  return GetRequestContext();
+}
+
+void ShellBrowserContext::RequestMIDISysExPermission(
+      int render_process_id,
+      int render_view_id,
+      const GURL& requesting_frame,
+      const MIDISysExPermissionCallback& callback) {
+  // Always reject requests for LayoutTests for now.
+  // TODO(toyoshim): Make it programmable to improve test coverage.
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+    callback.Run(false);
+    return;
+  }
+  // TODO(toyoshim): Implement. http://crbug.com/257618 .
+  callback.Run(false);
+}
+
+net::URLRequestContextGetter*
+    ShellBrowserContext::CreateRequestContextForStoragePartition(
+        const base::FilePath& partition_path,
+        bool in_memory,
+        ProtocolHandlerMap* protocol_handlers) {
+  return NULL;
+}
+
+ResourceContext* ShellBrowserContext::GetResourceContext()  {
+  return resource_context_.get();
+}
+
+GeolocationPermissionContext*
+    ShellBrowserContext::GetGeolocationPermissionContext()  {
+  return NULL;
+}
+
+quota::SpecialStoragePolicy* ShellBrowserContext::GetSpecialStoragePolicy() {
+  return NULL;
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_browser_context.h b/content/shell/browser/shell_browser_context.h
new file mode 100644
index 0000000..ec71591
--- /dev/null
+++ b/content/shell/browser/shell_browser_context.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 CONTENT_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_
+#define CONTENT_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/content_browser_client.h"
+#include "net/url_request/url_request_job_factory.h"
+
+namespace net {
+class NetLog;
+}
+
+namespace content {
+
+class DownloadManagerDelegate;
+class ResourceContext;
+class ShellDownloadManagerDelegate;
+class ShellURLRequestContextGetter;
+
+class ShellBrowserContext : public BrowserContext {
+ public:
+  ShellBrowserContext(bool off_the_record, net::NetLog* net_log);
+  virtual ~ShellBrowserContext();
+
+  // BrowserContext implementation.
+  virtual base::FilePath GetPath() const OVERRIDE;
+  virtual bool IsOffTheRecord() const OVERRIDE;
+  virtual DownloadManagerDelegate* GetDownloadManagerDelegate() OVERRIDE;
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+  virtual net::URLRequestContextGetter* GetRequestContextForRenderProcess(
+      int renderer_child_id) OVERRIDE;
+  virtual net::URLRequestContextGetter* GetMediaRequestContext() OVERRIDE;
+  virtual net::URLRequestContextGetter* GetMediaRequestContextForRenderProcess(
+      int renderer_child_id) OVERRIDE;
+  virtual net::URLRequestContextGetter*
+      GetMediaRequestContextForStoragePartition(
+          const base::FilePath& partition_path,
+          bool in_memory) OVERRIDE;
+  virtual void RequestMIDISysExPermission(
+      int render_process_id,
+      int render_view_id,
+      const GURL& requesting_frame,
+      const MIDISysExPermissionCallback& callback) OVERRIDE;
+  virtual ResourceContext* GetResourceContext() OVERRIDE;
+  virtual GeolocationPermissionContext*
+      GetGeolocationPermissionContext() OVERRIDE;
+  virtual quota::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE;
+
+  net::URLRequestContextGetter* CreateRequestContext(
+      ProtocolHandlerMap* protocol_handlers);
+  net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
+      const base::FilePath& partition_path,
+      bool in_memory,
+      ProtocolHandlerMap* protocol_handlers);
+
+ private:
+  class ShellResourceContext;
+
+  // Performs initialization of the ShellBrowserContext while IO is still
+  // allowed on the current thread.
+  void InitWhileIOAllowed();
+
+  bool off_the_record_;
+  net::NetLog* net_log_;
+  bool ignore_certificate_errors_;
+  base::FilePath path_;
+  scoped_ptr<ShellResourceContext> resource_context_;
+  scoped_refptr<ShellDownloadManagerDelegate> download_manager_delegate_;
+  scoped_refptr<ShellURLRequestContextGetter> url_request_getter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellBrowserContext);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_
diff --git a/content/shell/browser/shell_browser_main.cc b/content/shell/browser/shell_browser_main.cc
new file mode 100644
index 0000000..ac520d6
--- /dev/null
+++ b/content/shell/browser/shell_browser_main.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 "content/shell/browser/shell_browser_main.h"
+
+#include <iostream>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#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/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/browser/browser_main_runner.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_switches.h"
+#include "content/shell/common/webkit_test_helpers.h"
+#include "net/base/net_util.h"
+#include "webkit/support/webkit_support.h"
+
+#if defined(OS_ANDROID)
+#include "base/run_loop.h"
+#include "content/shell/browser/shell_layout_tests_android.h"
+#endif
+
+namespace {
+
+GURL GetURLForLayoutTest(const std::string& test_name,
+                         base::FilePath* current_working_directory,
+                         bool* enable_pixel_dumping,
+                         std::string* expected_pixel_hash) {
+  // A test name is formated like file:///path/to/test'--pixel-test'pixelhash
+  std::string path_or_url = test_name;
+  std::string pixel_switch;
+  std::string pixel_hash;
+  std::string::size_type separator_position = path_or_url.find('\'');
+  if (separator_position != std::string::npos) {
+    pixel_switch = path_or_url.substr(separator_position + 1);
+    path_or_url.erase(separator_position);
+  }
+  separator_position = pixel_switch.find('\'');
+  if (separator_position != std::string::npos) {
+    pixel_hash = pixel_switch.substr(separator_position + 1);
+    pixel_switch.erase(separator_position);
+  }
+  if (enable_pixel_dumping) {
+    *enable_pixel_dumping =
+        (pixel_switch == "--pixel-test" || pixel_switch == "-p");
+  }
+  if (expected_pixel_hash)
+    *expected_pixel_hash = pixel_hash;
+
+  GURL test_url;
+#if defined(OS_ANDROID)
+  if (content::GetTestUrlForAndroid(path_or_url, &test_url))
+    return test_url;
+#endif
+
+  test_url = GURL(path_or_url);
+  if (!(test_url.is_valid() && test_url.has_scheme())) {
+    // We're outside of the message loop here, and this is a test.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+#if defined(OS_WIN)
+    std::wstring wide_path_or_url =
+        base::SysNativeMBToWide(path_or_url);
+    base::FilePath local_file(wide_path_or_url);
+#else
+    base::FilePath local_file(path_or_url);
+#endif
+    if (!base::PathExists(local_file)) {
+      local_file = content::GetWebKitRootDirFilePath()
+          .Append(FILE_PATH_LITERAL("LayoutTests")).Append(local_file);
+    }
+    test_url = net::FilePathToFileURL(base::MakeAbsoluteFilePath(local_file));
+  }
+  base::FilePath local_path;
+  if (current_working_directory) {
+    // We're outside of the message loop here, and this is a test.
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    if (net::FileURLToFilePath(test_url, &local_path))
+      *current_working_directory = local_path.DirName();
+    else
+      file_util::GetCurrentDirectory(current_working_directory);
+  }
+  return test_url;
+}
+
+bool GetNextTest(const CommandLine::StringVector& args,
+                 size_t* position,
+                 std::string* test) {
+  if (*position >= args.size())
+    return false;
+  if (args[*position] == FILE_PATH_LITERAL("-"))
+    return !!std::getline(std::cin, *test, '\n');
+#if defined(OS_WIN)
+  *test = WideToUTF8(args[(*position)++]);
+#else
+  *test = args[(*position)++];
+#endif
+  return true;
+}
+
+}  // namespace
+
+// Main routine for running as the Browser process.
+int ShellBrowserMain(
+    const content::MainFunctionParams& parameters,
+    const scoped_ptr<content::BrowserMainRunner>& main_runner) {
+  bool layout_test_mode =
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
+  base::ScopedTempDir browser_context_path_for_layout_tests;
+
+  if (layout_test_mode) {
+    CHECK(browser_context_path_for_layout_tests.CreateUniqueTempDir());
+    CHECK(!browser_context_path_for_layout_tests.path().MaybeAsASCII().empty());
+    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        switches::kContentShellDataPath,
+        browser_context_path_for_layout_tests.path().MaybeAsASCII());
+
+#if defined(OS_ANDROID)
+    content::EnsureInitializeForAndroidLayoutTests();
+#endif
+  }
+
+  int exit_code = main_runner->Initialize(parameters);
+  DCHECK_LT(exit_code, 0)
+      << "BrowserMainRunner::Initialize failed in ShellBrowserMain";
+
+  if (exit_code >= 0)
+    return exit_code;
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+        switches::kCheckLayoutTestSysDeps)) {
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::MessageLoop::QuitClosure());
+    main_runner->Run();
+    content::Shell::CloseAllWindows();
+    main_runner->Shutdown();
+    return 0;
+  }
+
+  if (layout_test_mode) {
+    content::WebKitTestController test_controller;
+    {
+      // We're outside of the message loop here, and this is a test.
+      base::ThreadRestrictions::ScopedAllowIO allow_io;
+      base::FilePath temp_path;
+      file_util::GetTempDir(&temp_path);
+      test_controller.SetTempPath(temp_path);
+    }
+    std::string test_string;
+    CommandLine::StringVector args =
+        CommandLine::ForCurrentProcess()->GetArgs();
+    size_t command_line_position = 0;
+    bool ran_at_least_once = false;
+
+#if defined(OS_ANDROID)
+    std::cout << "#READY\n";
+    std::cout.flush();
+#endif
+
+    while (GetNextTest(args, &command_line_position, &test_string)) {
+      if (test_string.empty())
+        continue;
+      if (test_string == "QUIT")
+        break;
+
+      bool enable_pixel_dumps;
+      std::string pixel_hash;
+      base::FilePath cwd;
+      GURL test_url = GetURLForLayoutTest(
+          test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
+      if (!content::WebKitTestController::Get()->PrepareForLayoutTest(
+              test_url, cwd, enable_pixel_dumps, pixel_hash)) {
+        break;
+      }
+
+      ran_at_least_once = true;
+#if defined(OS_ANDROID)
+      // The message loop on Android is provided by the system, and does not
+      // offer a blocking Run() method. For layout tests, use a nested loop
+      // together with a base::RunLoop so it can block until a QuitClosure.
+      base::RunLoop run_loop;
+      run_loop.Run();
+#else
+      main_runner->Run();
+#endif
+
+      if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())
+        break;
+    }
+    if (!ran_at_least_once) {
+      base::MessageLoop::current()->PostTask(FROM_HERE,
+                                             base::MessageLoop::QuitClosure());
+      main_runner->Run();
+    }
+
+#if defined(OS_ANDROID)
+    // Android should only execute Shutdown() here when running layout tests.
+    main_runner->Shutdown();
+#endif
+
+    exit_code = 0;
+  }
+
+#if !defined(OS_ANDROID)
+  if (!layout_test_mode)
+    exit_code = main_runner->Run();
+
+  main_runner->Shutdown();
+#endif
+
+  return exit_code;
+}
diff --git a/content/shell/browser/shell_browser_main.h b/content/shell/browser/shell_browser_main.h
new file mode 100644
index 0000000..d361fa3
--- /dev/null
+++ b/content/shell/browser/shell_browser_main.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 CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_H_
+#define CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace content {
+class BrowserMainRunner;
+struct MainFunctionParams;
+}
+
+int ShellBrowserMain(
+    const content::MainFunctionParams& parameters,
+    const scoped_ptr<content::BrowserMainRunner>& main_runner);
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_H_
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc
new file mode 100644
index 0000000..6f7da00
--- /dev/null
+++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -0,0 +1,175 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_browser_main_parts.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "cc/base/switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/main_function_params.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_devtools_delegate.h"
+#include "content/shell/browser/shell_net_log.h"
+#include "content/shell/common/shell_switches.h"
+#include "grit/net_resources.h"
+#include "net/base/net_module.h"
+#include "net/base/net_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
+#include "webkit/browser/quota/quota_manager.h"
+
+#if defined(ENABLE_PLUGINS)
+#include "content/public/browser/plugin_service.h"
+#include "content/shell/browser/shell_plugin_service_filter.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "net/android/network_change_notifier_factory_android.h"
+#include "net/base/network_change_notifier.h"
+#endif
+
+#if defined(USE_AURA) && defined(USE_X11)
+#include "ui/base/touch/touch_factory_x11.h"
+#endif
+
+namespace content {
+
+namespace {
+
+// Default quota for each origin is 5MB.
+const int kDefaultLayoutTestQuotaBytes = 5 * 1024 * 1024;
+
+GURL GetStartupURL() {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kContentBrowserTest))
+    return GURL();
+  const CommandLine::StringVector& args = command_line->GetArgs();
+
+#if defined(OS_ANDROID)
+  // Delay renderer creation on Android until surface is ready.
+  return GURL();
+#endif
+
+  if (args.empty())
+    return GURL("http://www.google.com/");
+
+  GURL url(args[0]);
+  if (url.is_valid() && url.has_scheme())
+    return url;
+
+  return net::FilePathToFileURL(base::FilePath(args[0]));
+}
+
+base::StringPiece PlatformResourceProvider(int key) {
+  if (key == IDR_DIR_HEADER_HTML) {
+    base::StringPiece html_data =
+        ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
+            IDR_DIR_HEADER_HTML);
+    return html_data;
+  }
+  return base::StringPiece();
+}
+
+}  // namespace
+
+ShellBrowserMainParts::ShellBrowserMainParts(
+    const MainFunctionParams& parameters)
+    : BrowserMainParts(), parameters_(parameters), run_message_loop_(true) {}
+
+ShellBrowserMainParts::~ShellBrowserMainParts() {
+}
+
+#if !defined(OS_MACOSX)
+void ShellBrowserMainParts::PreMainMessageLoopStart() {
+#if defined(USE_AURA) && defined(USE_X11)
+  ui::TouchFactory::SetTouchDeviceListFromCommandLine();
+#endif
+}
+#endif
+
+void ShellBrowserMainParts::PostMainMessageLoopStart() {
+#if defined(OS_ANDROID)
+  base::MessageLoopForUI::current()->Start();
+#endif
+}
+
+void ShellBrowserMainParts::PreEarlyInitialization() {
+#if defined(OS_ANDROID)
+  net::NetworkChangeNotifier::SetFactory(
+      new net::NetworkChangeNotifierFactoryAndroid());
+
+  CommandLine::ForCurrentProcess()->AppendSwitch(
+      cc::switches::kCompositeToMailbox);
+#endif
+}
+
+void ShellBrowserMainParts::PreMainMessageLoopRun() {
+  net_log_.reset(new ShellNetLog());
+  browser_context_.reset(new ShellBrowserContext(false, net_log_.get()));
+  off_the_record_browser_context_.reset(
+      new ShellBrowserContext(true, net_log_.get()));
+
+  Shell::Initialize();
+  net::NetModule::SetResourceProvider(PlatformResourceProvider);
+
+  devtools_delegate_.reset(new ShellDevToolsDelegate(browser_context_.get()));
+
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+    Shell::CreateNewWindow(browser_context_.get(),
+                           GetStartupURL(),
+                           NULL,
+                           MSG_ROUTING_NONE,
+                           gfx::Size());
+  }
+
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+    quota::QuotaManager* quota_manager =
+        BrowserContext::GetDefaultStoragePartition(browser_context())
+            ->GetQuotaManager();
+    BrowserThread::PostTask(
+        BrowserThread::IO,
+        FROM_HERE,
+        base::Bind(&quota::QuotaManager::SetTemporaryGlobalOverrideQuota,
+                   quota_manager,
+                   kDefaultLayoutTestQuotaBytes *
+                       quota::QuotaManager::kPerHostTemporaryPortion,
+                   quota::QuotaCallback()));
+#if defined(ENABLE_PLUGINS)
+    PluginService* plugin_service = PluginService::GetInstance();
+    plugin_service_filter_.reset(new ShellPluginServiceFilter);
+    plugin_service->SetFilter(plugin_service_filter_.get());
+#endif
+  }
+
+  if (parameters_.ui_task) {
+    parameters_.ui_task->Run();
+    delete parameters_.ui_task;
+    run_message_loop_ = false;
+  }
+}
+
+bool ShellBrowserMainParts::MainMessageLoopRun(int* result_code)  {
+  return !run_message_loop_;
+}
+
+void ShellBrowserMainParts::PostMainMessageLoopRun() {
+#if defined(USE_AURA)
+  Shell::PlatformExit();
+#endif
+  if (devtools_delegate_)
+    devtools_delegate_->Stop();
+  browser_context_.reset();
+  off_the_record_browser_context_.reset();
+}
+
+}  // namespace
diff --git a/content/shell/browser/shell_browser_main_parts.h b/content/shell/browser/shell_browser_main_parts.h
new file mode 100644
index 0000000..990e1c5
--- /dev/null
+++ b/content/shell/browser/shell_browser_main_parts.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 CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_
+#define CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/browser_main_parts.h"
+#include "content/public/common/main_function_params.h"
+
+namespace base {
+class Thread;
+}
+
+namespace net {
+class NetLog;
+}
+
+namespace content {
+
+class ShellBrowserContext;
+class ShellDevToolsDelegate;
+class ShellPluginServiceFilter;
+
+class ShellBrowserMainParts : public BrowserMainParts {
+ public:
+  explicit ShellBrowserMainParts(const MainFunctionParams& parameters);
+  virtual ~ShellBrowserMainParts();
+
+  // BrowserMainParts overrides.
+  virtual void PreEarlyInitialization() OVERRIDE;
+  virtual void PreMainMessageLoopStart() OVERRIDE;
+  virtual void PostMainMessageLoopStart() OVERRIDE;
+  virtual void PreMainMessageLoopRun() OVERRIDE;
+  virtual bool MainMessageLoopRun(int* result_code) OVERRIDE;
+  virtual void PostMainMessageLoopRun() OVERRIDE;
+
+  ShellDevToolsDelegate* devtools_delegate() {
+    return devtools_delegate_.get();
+  }
+
+  ShellBrowserContext* browser_context() { return browser_context_.get(); }
+  ShellBrowserContext* off_the_record_browser_context() {
+    return off_the_record_browser_context_.get();
+  }
+
+  net::NetLog* net_log() { return net_log_.get(); }
+
+ private:
+  scoped_ptr<net::NetLog> net_log_;
+  scoped_ptr<ShellBrowserContext> browser_context_;
+  scoped_ptr<ShellBrowserContext> off_the_record_browser_context_;
+
+  // For running content_browsertests.
+  const MainFunctionParams parameters_;
+  bool run_message_loop_;
+
+  scoped_ptr<ShellDevToolsDelegate> devtools_delegate_;
+#if defined(ENABLE_PLUGINS)
+  scoped_ptr<ShellPluginServiceFilter> plugin_service_filter_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ShellBrowserMainParts);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_
diff --git a/content/shell/browser/shell_browser_main_parts_mac.mm b/content/shell/browser/shell_browser_main_parts_mac.mm
new file mode 100644
index 0000000..a933705
--- /dev/null
+++ b/content/shell/browser/shell_browser_main_parts_mac.mm
@@ -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 "content/shell/browser/shell_browser_main_parts.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/bundle_locations.h"
+#include "base/mac/scoped_nsobject.h"
+#include "content/shell/browser/shell_application_mac.h"
+
+namespace content {
+
+void ShellBrowserMainParts::PreMainMessageLoopStart() {
+  // Force the NSApplication subclass to be used.
+  [ShellCrApplication sharedApplication];
+
+  base::scoped_nsobject<NSNib> nib(
+      [[NSNib alloc] initWithNibNamed:@"MainMenu"
+                               bundle:base::mac::FrameworkBundle()]);
+  [nib instantiateNibWithOwner:NSApp topLevelObjects:nil];
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
new file mode 100644
index 0000000..c837929
--- /dev/null
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -0,0 +1,277 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_content_browser_client.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.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/resource_dispatcher_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_main_parts.h"
+#include "content/shell/browser/shell_devtools_delegate.h"
+#include "content/shell/browser/shell_message_filter.h"
+#include "content/shell/browser/shell_net_log.h"
+#include "content/shell/browser/shell_quota_permission_context.h"
+#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
+#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_messages.h"
+#include "content/shell/common/shell_switches.h"
+#include "content/shell/common/webkit_test_helpers.h"
+#include "content/shell/geolocation/shell_access_token_store.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
+#include "webkit/common/webpreferences.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/path_utils.h"
+#include "base/path_service.h"
+#include "base/platform_file.h"
+#include "content/shell/android/shell_descriptors.h"
+#endif
+
+namespace content {
+
+namespace {
+
+ShellContentBrowserClient* g_browser_client;
+bool g_swap_processes_for_redirect = false;
+
+}  // namespace
+
+ShellContentBrowserClient* ShellContentBrowserClient::Get() {
+  return g_browser_client;
+}
+
+void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
+  g_swap_processes_for_redirect = swap;
+}
+
+ShellContentBrowserClient::ShellContentBrowserClient()
+    : shell_browser_main_parts_(NULL) {
+  DCHECK(!g_browser_client);
+  g_browser_client = this;
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+  webkit_source_dir_ = GetWebKitRootDirFilePath();
+}
+
+ShellContentBrowserClient::~ShellContentBrowserClient() {
+  g_browser_client = NULL;
+}
+
+BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
+    const MainFunctionParams& parameters) {
+  shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
+  return shell_browser_main_parts_;
+}
+
+void ShellContentBrowserClient::RenderProcessHostCreated(
+    RenderProcessHost* host) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+  host->GetChannel()->AddFilter(new ShellMessageFilter(
+      host->GetID(),
+      BrowserContext::GetDefaultStoragePartition(browser_context())
+          ->GetDatabaseTracker(),
+      BrowserContext::GetDefaultStoragePartition(browser_context())
+          ->GetQuotaManager(),
+      BrowserContext::GetDefaultStoragePartition(browser_context())
+          ->GetURLRequestContext()));
+  host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_));
+  registrar_.Add(this,
+                 NOTIFICATION_RENDERER_PROCESS_CREATED,
+                 Source<RenderProcessHost>(host));
+  registrar_.Add(this,
+                 NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+                 Source<RenderProcessHost>(host));
+}
+
+net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
+    BrowserContext* content_browser_context,
+    ProtocolHandlerMap* protocol_handlers) {
+  ShellBrowserContext* shell_browser_context =
+      ShellBrowserContextForBrowserContext(content_browser_context);
+  return shell_browser_context->CreateRequestContext(protocol_handlers);
+}
+
+net::URLRequestContextGetter*
+ShellContentBrowserClient::CreateRequestContextForStoragePartition(
+    BrowserContext* content_browser_context,
+    const base::FilePath& partition_path,
+    bool in_memory,
+    ProtocolHandlerMap* protocol_handlers) {
+  ShellBrowserContext* shell_browser_context =
+      ShellBrowserContextForBrowserContext(content_browser_context);
+  return shell_browser_context->CreateRequestContextForStoragePartition(
+      partition_path, in_memory, protocol_handlers);
+}
+
+bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
+  if (!url.is_valid())
+    return false;
+  DCHECK_EQ(url.scheme(), StringToLowerASCII(url.scheme()));
+  // Keep in sync with ProtocolHandlers added by
+  // ShellURLRequestContextGetter::GetURLRequestContext().
+  static const char* const kProtocolList[] = {
+      chrome::kBlobScheme,
+      chrome::kFileSystemScheme,
+      chrome::kChromeUIScheme,
+      chrome::kChromeDevToolsScheme,
+      chrome::kDataScheme,
+      chrome::kFileScheme,
+  };
+  for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
+    if (url.scheme() == kProtocolList[i])
+      return true;
+  }
+  return false;
+}
+
+void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
+    CommandLine* command_line, int child_process_id) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    command_line->AppendSwitch(switches::kDumpRenderTree);
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kExposeInternalsForTesting))
+    command_line->AppendSwitch(switches::kExposeInternalsForTesting);
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStableReleaseMode))
+    command_line->AppendSwitch(switches::kStableReleaseMode);
+}
+
+void ShellContentBrowserClient::OverrideWebkitPrefs(
+    RenderViewHost* render_view_host,
+    const GURL& url,
+    WebPreferences* prefs) {
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+  WebKitTestController::Get()->OverrideWebkitPrefs(prefs);
+}
+
+void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
+  resource_dispatcher_host_delegate_.reset(
+      new ShellResourceDispatcherHostDelegate());
+  ResourceDispatcherHost::Get()->SetDelegate(
+      resource_dispatcher_host_delegate_.get());
+}
+
+std::string ShellContentBrowserClient::GetDefaultDownloadName() {
+  return "download";
+}
+
+bool ShellContentBrowserClient::SupportsBrowserPlugin(
+    content::BrowserContext* browser_context, const GURL& url) {
+  return CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableBrowserPluginForAllViewTypes);
+}
+
+WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate(
+    WebContents* web_contents) {
+#if !defined(USE_AURA)
+  return CreateShellWebContentsViewDelegate(web_contents);
+#else
+  return NULL;
+#endif
+}
+
+QuotaPermissionContext*
+ShellContentBrowserClient::CreateQuotaPermissionContext() {
+  return new ShellQuotaPermissionContext();
+}
+
+net::NetLog* ShellContentBrowserClient::GetNetLog() {
+  return shell_browser_main_parts_->net_log();
+}
+
+bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
+    ResourceContext* resource_context,
+    const GURL& current_url,
+    const GURL& new_url) {
+  return g_swap_processes_for_redirect;
+}
+
+#if defined(OS_ANDROID)
+void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
+    const CommandLine& command_line,
+    int child_process_id,
+    std::vector<content::FileDescriptorInfo>* mappings) {
+  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);
+  CHECK(r);
+  pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
+  pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
+
+  base::PlatformFile f =
+      base::CreatePlatformFile(pak_file, flags, NULL, NULL);
+  if (f == base::kInvalidPlatformFileValue) {
+    NOTREACHED() << "Failed to open file when creating renderer process: "
+                 << "content_shell.pak";
+  }
+  mappings->push_back(
+      content::FileDescriptorInfo(kShellPakDescriptor,
+                                  base::FileDescriptor(f, true)));
+}
+#endif
+
+void ShellContentBrowserClient::Observe(int type,
+                                        const NotificationSource& source,
+                                        const NotificationDetails& details) {
+  switch (type) {
+    case NOTIFICATION_RENDERER_PROCESS_CREATED: {
+      registrar_.Remove(this,
+                        NOTIFICATION_RENDERER_PROCESS_CREATED,
+                        source);
+      registrar_.Remove(this,
+                        NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+                        source);
+      break;
+    }
+
+    case NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
+      registrar_.Remove(this,
+                        NOTIFICATION_RENDERER_PROCESS_CREATED,
+                        source);
+      registrar_.Remove(this,
+                        NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+                        source);
+      break;
+    }
+
+    default:
+      NOTREACHED();
+  }
+}
+
+ShellBrowserContext* ShellContentBrowserClient::browser_context() {
+  return shell_browser_main_parts_->browser_context();
+}
+
+ShellBrowserContext*
+    ShellContentBrowserClient::off_the_record_browser_context() {
+  return shell_browser_main_parts_->off_the_record_browser_context();
+}
+
+AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
+  return new ShellAccessTokenStore(browser_context());
+}
+
+ShellBrowserContext*
+ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
+    BrowserContext* content_browser_context) {
+  if (content_browser_context == browser_context())
+    return browser_context();
+  DCHECK_EQ(content_browser_context, off_the_record_browser_context());
+  return off_the_record_browser_context();
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
new file mode 100644
index 0000000..15285ca
--- /dev/null
+++ b/content/shell/browser/shell_content_browser_client.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_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_
+#define CONTENT_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/platform_file.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace content {
+
+class ShellBrowserContext;
+class ShellBrowserMainParts;
+class ShellResourceDispatcherHostDelegate;
+
+class ShellContentBrowserClient : public ContentBrowserClient,
+                                  public NotificationObserver {
+ public:
+  // Gets the current instance.
+  static ShellContentBrowserClient* Get();
+
+  static void SetSwapProcessesForRedirect(bool swap);
+
+  ShellContentBrowserClient();
+  virtual ~ShellContentBrowserClient();
+
+  // ContentBrowserClient overrides.
+  virtual BrowserMainParts* CreateBrowserMainParts(
+      const MainFunctionParams& parameters) OVERRIDE;
+  virtual void RenderProcessHostCreated(RenderProcessHost* host) OVERRIDE;
+  virtual net::URLRequestContextGetter* CreateRequestContext(
+      BrowserContext* browser_context,
+      ProtocolHandlerMap* protocol_handlers) OVERRIDE;
+  virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
+      BrowserContext* browser_context,
+      const base::FilePath& partition_path,
+      bool in_memory,
+      ProtocolHandlerMap* protocol_handlers) OVERRIDE;
+  virtual bool IsHandledURL(const GURL& url) OVERRIDE;
+  virtual void AppendExtraCommandLineSwitches(CommandLine* command_line,
+                                              int child_process_id) OVERRIDE;
+  virtual void OverrideWebkitPrefs(RenderViewHost* render_view_host,
+                                   const GURL& url,
+                                   WebPreferences* prefs) OVERRIDE;
+  virtual void ResourceDispatcherHostCreated() OVERRIDE;
+  virtual AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
+  virtual std::string GetDefaultDownloadName() OVERRIDE;
+  virtual bool SupportsBrowserPlugin(content::BrowserContext* browser_context,
+                                     const GURL& url) OVERRIDE;
+  virtual WebContentsViewDelegate* GetWebContentsViewDelegate(
+      WebContents* web_contents) OVERRIDE;
+  virtual QuotaPermissionContext* CreateQuotaPermissionContext() OVERRIDE;
+  virtual net::NetLog* GetNetLog() OVERRIDE;
+  virtual bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context,
+                                              const GURL& current_url,
+                                              const GURL& new_url) OVERRIDE;
+
+#if defined(OS_ANDROID)
+  virtual void GetAdditionalMappedFilesForChildProcess(
+      const CommandLine& command_line,
+      int child_process_id,
+      std::vector<content::FileDescriptorInfo>* mappings) OVERRIDE;
+#endif
+
+  // NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE;
+
+  ShellBrowserContext* browser_context();
+  ShellBrowserContext* off_the_record_browser_context();
+  ShellResourceDispatcherHostDelegate* resource_dispatcher_host_delegate() {
+    return resource_dispatcher_host_delegate_.get();
+  }
+  ShellBrowserMainParts* shell_browser_main_parts() {
+    return shell_browser_main_parts_;
+  }
+
+ private:
+  ShellBrowserContext* ShellBrowserContextForBrowserContext(
+      BrowserContext* content_browser_context);
+
+  scoped_ptr<ShellResourceDispatcherHostDelegate>
+      resource_dispatcher_host_delegate_;
+
+  base::FilePath webkit_source_dir_;
+
+  ShellBrowserMainParts* shell_browser_main_parts_;
+
+  NotificationRegistrar registrar_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_
diff --git a/content/shell/browser/shell_devtools_delegate.cc b/content/shell/browser/shell_devtools_delegate.cc
new file mode 100644
index 0000000..0a01405
--- /dev/null
+++ b/content/shell/browser/shell_devtools_delegate.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 "content/shell/browser/shell_devtools_delegate.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/public/browser/devtools_http_handler.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell.h"
+#include "grit/shell_resources.h"
+#include "net/socket/tcp_listen_socket.h"
+#include "ui/base/resource/resource_bundle.h"
+
+#if defined(OS_ANDROID)
+#include "content/public/browser/android/devtools_auth.h"
+#include "net/socket/unix_domain_socket_posix.h"
+#endif
+
+namespace {
+
+net::StreamListenSocketFactory* CreateSocketFactory() {
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+#if defined(OS_ANDROID)
+  std::string socket_name = "content_shell_devtools_remote";
+  if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
+    socket_name = command_line.GetSwitchValueASCII(
+        switches::kRemoteDebuggingSocketName);
+  }
+  return new net::UnixDomainSocketWithAbstractNamespaceFactory(
+      socket_name, "", base::Bind(&content::CanUserConnectToDevTools));
+#else
+  // See if the user specified a port on the command line (useful for
+  // automation). If not, use an ephemeral port by specifying 0.
+  int port = 0;
+  if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
+    int temp_port;
+    std::string port_str =
+        command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
+    if (base::StringToInt(port_str, &temp_port) &&
+        temp_port > 0 && temp_port < 65535) {
+      port = temp_port;
+    } else {
+      DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
+    }
+  }
+  return new net::TCPListenSocketFactory("127.0.0.1", port);
+#endif
+}
+}  // namespace
+
+namespace content {
+
+ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext* browser_context)
+    : browser_context_(browser_context) {
+  // Note that Content Shell always used bundled DevTools frontend,
+  // even on Android, because the shell is used for running layout tests.
+  devtools_http_handler_ =
+      DevToolsHttpHandler::Start(CreateSocketFactory(), std::string(), this);
+}
+
+ShellDevToolsDelegate::~ShellDevToolsDelegate() {
+}
+
+void ShellDevToolsDelegate::Stop() {
+  // The call below destroys this.
+  devtools_http_handler_->Stop();
+}
+
+std::string ShellDevToolsDelegate::GetDiscoveryPageHTML() {
+  return ResourceBundle::GetSharedInstance().GetRawDataResource(
+      IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE).as_string();
+}
+
+bool ShellDevToolsDelegate::BundlesFrontendResources() {
+  return true;
+}
+
+base::FilePath ShellDevToolsDelegate::GetDebugFrontendDir() {
+  return base::FilePath();
+}
+
+std::string ShellDevToolsDelegate::GetPageThumbnailData(const GURL& url) {
+  return std::string();
+}
+
+RenderViewHost* ShellDevToolsDelegate::CreateNewTarget() {
+  Shell* shell = Shell::CreateNewWindow(browser_context_,
+                                        GURL(kAboutBlankURL),
+                                        NULL,
+                                        MSG_ROUTING_NONE,
+                                        gfx::Size());
+  return shell->web_contents()->GetRenderViewHost();
+}
+
+DevToolsHttpHandlerDelegate::TargetType
+ShellDevToolsDelegate::GetTargetType(RenderViewHost*) {
+  return kTargetTypeTab;
+}
+
+std::string ShellDevToolsDelegate::GetViewDescription(
+    content::RenderViewHost*) {
+  return std::string();
+}
+
+scoped_refptr<net::StreamListenSocket>
+ShellDevToolsDelegate::CreateSocketForTethering(
+    net::StreamListenSocket::Delegate* delegate,
+    std::string* name) {
+  return NULL;
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_devtools_delegate.h b/content/shell/browser/shell_devtools_delegate.h
new file mode 100644
index 0000000..a218738
--- /dev/null
+++ b/content/shell/browser/shell_devtools_delegate.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_SHELL_BROWSER_SHELL_DEVTOOLS_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/public/browser/devtools_http_handler_delegate.h"
+
+namespace content {
+
+class BrowserContext;
+class DevToolsHttpHandler;
+
+class ShellDevToolsDelegate : public DevToolsHttpHandlerDelegate {
+ public:
+  explicit ShellDevToolsDelegate(BrowserContext* browser_context);
+  virtual ~ShellDevToolsDelegate();
+
+  // Stops http server.
+  void Stop();
+
+  // DevToolsHttpProtocolHandler::Delegate overrides.
+  virtual std::string GetDiscoveryPageHTML() OVERRIDE;
+  virtual bool BundlesFrontendResources() OVERRIDE;
+  virtual base::FilePath GetDebugFrontendDir() OVERRIDE;
+  virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE;
+  virtual RenderViewHost* CreateNewTarget() OVERRIDE;
+  virtual TargetType GetTargetType(RenderViewHost*) OVERRIDE;
+  virtual std::string GetViewDescription(content::RenderViewHost*) OVERRIDE;
+  virtual scoped_refptr<net::StreamListenSocket> CreateSocketForTethering(
+      net::StreamListenSocket::Delegate* delegate,
+      std::string* name) OVERRIDE;
+
+  DevToolsHttpHandler* devtools_http_handler() {
+    return devtools_http_handler_;
+  }
+
+ private:
+  BrowserContext* browser_context_;
+  DevToolsHttpHandler* devtools_http_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellDevToolsDelegate);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_DELEGATE_H_
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc
new file mode 100644
index 0000000..8c3f74b
--- /dev/null
+++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_devtools_frontend.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "content/public/browser/devtools_http_handler.h"
+#include "content/public/browser/devtools_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/content_client.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_main_parts.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_devtools_delegate.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/net_util.h"
+
+namespace content {
+
+namespace {
+
+// DevTools frontend path for inspector LayoutTests.
+GURL GetDevToolsPathAsURL() {
+  base::FilePath dir_exe;
+  if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
+    NOTREACHED();
+    return GURL();
+  }
+#if defined(OS_MACOSX)
+  // On Mac, the executable is in
+  // out/Release/Content Shell.app/Contents/MacOS/Content Shell.
+  // We need to go up 3 directories to get to out/Release.
+  dir_exe = dir_exe.AppendASCII("../../..");
+#endif
+  base::FilePath dev_tools_path = dir_exe.AppendASCII(
+      "resources/inspector/devtools.html");
+  return net::FilePathToFileURL(dev_tools_path);
+}
+
+}  // namespace
+
+// static
+ShellDevToolsFrontend* ShellDevToolsFrontend::Show(
+    WebContents* inspected_contents) {
+  Shell* shell = Shell::CreateNewWindow(inspected_contents->GetBrowserContext(),
+                                        GURL(),
+                                        NULL,
+                                        MSG_ROUTING_NONE,
+                                        gfx::Size());
+  ShellDevToolsFrontend* devtools_frontend = new ShellDevToolsFrontend(
+      shell,
+      DevToolsAgentHost::GetOrCreateFor(inspected_contents->GetRenderViewHost())
+          .get());
+
+  ShellDevToolsDelegate* delegate = ShellContentBrowserClient::Get()->
+      shell_browser_main_parts()->devtools_delegate();
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    shell->LoadURL(GetDevToolsPathAsURL());
+  else
+    shell->LoadURL(delegate->devtools_http_handler()->GetFrontendURL(NULL));
+
+  return devtools_frontend;
+}
+
+void ShellDevToolsFrontend::Focus() {
+  web_contents()->GetView()->Focus();
+}
+
+void ShellDevToolsFrontend::Close() {
+  frontend_shell_->Close();
+}
+
+ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell,
+                                             DevToolsAgentHost* agent_host)
+    : WebContentsObserver(frontend_shell->web_contents()),
+      frontend_shell_(frontend_shell),
+      agent_host_(agent_host) {
+  frontend_host_.reset(
+      DevToolsClientHost::CreateDevToolsFrontendHost(web_contents(), this));
+}
+
+ShellDevToolsFrontend::~ShellDevToolsFrontend() {
+}
+
+void ShellDevToolsFrontend::RenderViewCreated(
+    RenderViewHost* render_view_host) {
+  DevToolsClientHost::SetupDevToolsFrontendClient(
+      web_contents()->GetRenderViewHost());
+  DevToolsManager* manager = DevToolsManager::GetInstance();
+  manager->RegisterDevToolsClientHostFor(agent_host_.get(),
+                                         frontend_host_.get());
+}
+
+void ShellDevToolsFrontend::WebContentsDestroyed(WebContents* web_contents) {
+  DevToolsManager::GetInstance()->ClientHostClosing(frontend_host_.get());
+  delete this;
+}
+
+void ShellDevToolsFrontend::InspectedContentsClosing() {
+  frontend_shell_->Close();
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_devtools_frontend.h b/content/shell/browser/shell_devtools_frontend.h
new file mode 100644
index 0000000..b6a617f
--- /dev/null
+++ b/content/shell/browser/shell_devtools_frontend.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 CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_FRONTEND_H_
+#define CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_FRONTEND_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/devtools_client_host.h"
+#include "content/public/browser/devtools_frontend_host_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+
+class RenderViewHost;
+class Shell;
+class WebContents;
+
+class ShellDevToolsFrontend : public WebContentsObserver,
+                              public DevToolsFrontendHostDelegate {
+ public:
+  static ShellDevToolsFrontend* Show(WebContents* inspected_contents);
+  void Focus();
+  void Close();
+
+  Shell* frontend_shell() const { return frontend_shell_; }
+
+ private:
+  ShellDevToolsFrontend(Shell* frontend_shell, DevToolsAgentHost* agent_host);
+  virtual ~ShellDevToolsFrontend();
+
+  // WebContentsObserver overrides
+  virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
+  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+
+  // DevToolsFrontendHostDelegate implementation
+  virtual void ActivateWindow() OVERRIDE {}
+  virtual void ChangeAttachedWindowHeight(unsigned height) OVERRIDE {}
+  virtual void CloseWindow() OVERRIDE {}
+  virtual void MoveWindow(int x, int y) OVERRIDE {}
+  virtual void SetDockSide(const std::string& side) OVERRIDE {}
+  virtual void OpenInNewTab(const std::string& url) OVERRIDE {}
+  virtual void SaveToFile(const std::string& url,
+                          const std::string& content,
+                          bool save_as) OVERRIDE {}
+  virtual void AppendToFile(const std::string& url,
+                            const std::string& content) OVERRIDE {}
+  virtual void RequestFileSystems() OVERRIDE {}
+  virtual void AddFileSystem() OVERRIDE {}
+  virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE {}
+  virtual void IndexPath(int request_id,
+                         const std::string& file_system_path) OVERRIDE {}
+  virtual void StopIndexing(int request_id) OVERRIDE {}
+  virtual void SearchInPath(int request_id,
+                            const std::string& file_system_path,
+                            const std::string& query) OVERRIDE {}
+
+  virtual void InspectedContentsClosing() OVERRIDE;
+
+  Shell* frontend_shell_;
+  scoped_refptr<DevToolsAgentHost> agent_host_;
+  scoped_ptr<DevToolsClientHost> frontend_host_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellDevToolsFrontend);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_FRONTEND_H_
diff --git a/content/shell/browser/shell_download_manager_delegate.cc b/content/shell/browser/shell_download_manager_delegate.cc
new file mode 100644
index 0000000..1dbbea7
--- /dev/null
+++ b/content/shell/browser/shell_download_manager_delegate.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 "content/shell/browser/shell_download_manager_delegate.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <commdlg.h>
+#endif
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/net_util.h"
+
+namespace content {
+
+ShellDownloadManagerDelegate::ShellDownloadManagerDelegate()
+    : download_manager_(NULL),
+      suppress_prompting_(false) {
+  // Balanced in Shutdown();
+  AddRef();
+}
+
+ShellDownloadManagerDelegate::~ShellDownloadManagerDelegate(){
+}
+
+
+void ShellDownloadManagerDelegate::SetDownloadManager(
+    DownloadManager* download_manager) {
+  download_manager_ = download_manager;
+}
+
+void ShellDownloadManagerDelegate::Shutdown() {
+  Release();
+}
+
+bool ShellDownloadManagerDelegate::DetermineDownloadTarget(
+    DownloadItem* download,
+    const DownloadTargetCallback& callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  // This assignment needs to be here because even at the call to
+  // SetDownloadManager, the system is not fully initialized.
+  if (default_download_path_.empty()) {
+    default_download_path_ = download_manager_->GetBrowserContext()->GetPath().
+        Append(FILE_PATH_LITERAL("Downloads"));
+  }
+
+  if (!download->GetForcedFilePath().empty()) {
+    callback.Run(download->GetForcedFilePath(),
+                 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+                 DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+                 download->GetForcedFilePath());
+    return true;
+  }
+
+  base::FilePath generated_name = net::GenerateFileName(
+      download->GetURL(),
+      download->GetContentDisposition(),
+      EmptyString(),
+      download->GetSuggestedFilename(),
+      download->GetMimeType(),
+      "download");
+
+  BrowserThread::PostTask(
+      BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(
+          &ShellDownloadManagerDelegate::GenerateFilename,
+          this, download->GetId(), callback, generated_name,
+          default_download_path_));
+  return true;
+}
+
+bool ShellDownloadManagerDelegate::ShouldOpenDownload(
+      DownloadItem* item,
+      const DownloadOpenDelayedCallback& callback) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree) &&
+      WebKitTestController::Get()->IsMainWindow(item->GetWebContents()) &&
+      item->GetMimeType() == "text/html") {
+    WebKitTestController::Get()->OpenURL(
+        net::FilePathToFileURL(item->GetFullPath()));
+  }
+  return true;
+}
+
+void ShellDownloadManagerDelegate::GetNextId(
+    const DownloadIdCallback& callback) {
+  static uint32 next_id = DownloadItem::kInvalidId + 1;
+  callback.Run(next_id++);
+}
+
+void ShellDownloadManagerDelegate::GenerateFilename(
+    uint32 download_id,
+    const DownloadTargetCallback& callback,
+    const base::FilePath& generated_name,
+    const base::FilePath& suggested_directory) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  if (!base::PathExists(suggested_directory))
+    file_util::CreateDirectory(suggested_directory);
+
+  base::FilePath suggested_path(suggested_directory.Append(generated_name));
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind(
+          &ShellDownloadManagerDelegate::OnDownloadPathGenerated,
+          this, download_id, callback, suggested_path));
+}
+
+void ShellDownloadManagerDelegate::OnDownloadPathGenerated(
+    uint32 download_id,
+    const DownloadTargetCallback& callback,
+    const base::FilePath& suggested_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (suppress_prompting_) {
+    // Testing exit.
+    callback.Run(suggested_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+                 DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+                 suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")));
+    return;
+  }
+
+  ChooseDownloadPath(download_id, callback, suggested_path);
+}
+
+void ShellDownloadManagerDelegate::ChooseDownloadPath(
+    uint32 download_id,
+    const DownloadTargetCallback& callback,
+    const base::FilePath& suggested_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DownloadItem* item = download_manager_->GetDownload(download_id);
+  if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
+    return;
+
+  base::FilePath result;
+#if defined(OS_WIN) && !defined(USE_AURA)
+  std::wstring file_part = base::FilePath(suggested_path).BaseName().value();
+  wchar_t file_name[MAX_PATH];
+  base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
+  OPENFILENAME save_as;
+  ZeroMemory(&save_as, sizeof(save_as));
+  save_as.lStructSize = sizeof(OPENFILENAME);
+  save_as.hwndOwner = item->GetWebContents()->GetView()->GetNativeView();
+  save_as.lpstrFile = file_name;
+  save_as.nMaxFile = arraysize(file_name);
+
+  std::wstring directory;
+  if (!suggested_path.empty())
+    directory = suggested_path.DirName().value();
+
+  save_as.lpstrInitialDir = directory.c_str();
+  save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
+                  OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
+
+  if (GetSaveFileName(&save_as))
+    result = base::FilePath(std::wstring(save_as.lpstrFile));
+#elif defined(TOOLKIT_GTK)
+  GtkWidget *dialog;
+  gfx::NativeWindow parent_window;
+  std::string base_name = base::FilePath(suggested_path).BaseName().value();
+
+  parent_window = item->GetWebContents()->GetView()->GetTopLevelNativeWindow();
+  dialog = gtk_file_chooser_dialog_new("Save File",
+                                       parent_window,
+                                       GTK_FILE_CHOOSER_ACTION_SAVE,
+                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                       GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+                                       NULL);
+  gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
+                                                 TRUE);
+  gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
+                                    base_name.c_str());
+
+  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+    char *filename;
+    filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+    result = base::FilePath(filename);
+    g_free(filename);
+  }
+  gtk_widget_destroy(dialog);
+#else
+  NOTIMPLEMENTED();
+#endif
+
+  callback.Run(result, DownloadItem::TARGET_DISPOSITION_PROMPT,
+               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result);
+}
+
+void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting(
+    const base::FilePath& default_download_path) {
+  default_download_path_ = default_download_path;
+  suppress_prompting_ = true;
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_download_manager_delegate.h b/content/shell/browser/shell_download_manager_delegate.h
new file mode 100644
index 0000000..afd57e7
--- /dev/null
+++ b/content/shell/browser/shell_download_manager_delegate.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 CONTENT_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/download_manager_delegate.h"
+
+namespace content {
+
+class DownloadManager;
+
+class ShellDownloadManagerDelegate
+    : public DownloadManagerDelegate,
+      public base::RefCountedThreadSafe<ShellDownloadManagerDelegate> {
+ public:
+  ShellDownloadManagerDelegate();
+
+  void SetDownloadManager(DownloadManager* manager);
+
+  virtual void Shutdown() OVERRIDE;
+  virtual bool DetermineDownloadTarget(
+      DownloadItem* download,
+      const DownloadTargetCallback& callback) OVERRIDE;
+  virtual bool ShouldOpenDownload(
+      DownloadItem* item,
+      const DownloadOpenDelayedCallback& callback) OVERRIDE;
+  virtual void GetNextId(const DownloadIdCallback& callback) OVERRIDE;
+
+  // Inhibits prompting and sets the default download path.
+  void SetDownloadBehaviorForTesting(
+      const base::FilePath& default_download_path);
+
+ protected:
+  // To allow subclasses for testing.
+  virtual ~ShellDownloadManagerDelegate();
+
+ private:
+  friend class base::RefCountedThreadSafe<ShellDownloadManagerDelegate>;
+
+
+  void GenerateFilename(uint32 download_id,
+                        const DownloadTargetCallback& callback,
+                        const base::FilePath& generated_name,
+                        const base::FilePath& suggested_directory);
+  void OnDownloadPathGenerated(uint32 download_id,
+                               const DownloadTargetCallback& callback,
+                               const base::FilePath& suggested_path);
+  void ChooseDownloadPath(uint32 download_id,
+                          const DownloadTargetCallback& callback,
+                          const base::FilePath& suggested_path);
+
+  DownloadManager* download_manager_;
+  base::FilePath default_download_path_;
+  bool suppress_prompting_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellDownloadManagerDelegate);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
diff --git a/content/shell/browser/shell_gtk.cc b/content/shell/browser/shell_gtk.cc
new file mode 100644
index 0000000..a06a6a0
--- /dev/null
+++ b/content/shell/browser/shell_gtk.cc
@@ -0,0 +1,339 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell.h"
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/renderer_preferences.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+
+namespace content {
+
+namespace {
+
+// Callback for Debug > Show web inspector... menu item.
+gboolean ShowWebInspectorActivated(GtkWidget* widget, Shell* shell) {
+  shell->ShowDevTools();
+  return FALSE;  // Don't stop this message.
+}
+
+GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text,
+                        GCallback callback, Shell* shell) {
+  GtkWidget* entry = gtk_menu_item_new_with_label(text);
+  g_signal_connect(entry, "activate", callback, shell);
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu_widget), entry);
+  return entry;
+}
+
+GtkWidget* CreateMenu(GtkWidget* menu_bar, const char* text) {
+  GtkWidget* menu_widget = gtk_menu_new();
+  GtkWidget* menu_header = gtk_menu_item_new_with_label(text);
+  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_header), menu_widget);
+  gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_header);
+  return menu_widget;
+}
+
+GtkWidget* CreateMenuBar(Shell* shell) {
+  GtkWidget* menu_bar = gtk_menu_bar_new();
+  GtkWidget* debug_menu = CreateMenu(menu_bar, "Debug");
+  AddMenuEntry(debug_menu, "Show web inspector...",
+               G_CALLBACK(ShowWebInspectorActivated), shell);
+  return menu_bar;
+}
+
+}  // namespace
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+}
+
+void Shell::PlatformCleanUp() {
+  // Nothing to clean up; GTK will clean up the widgets shortly after.
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+  if (headless_)
+    return;
+
+  GtkToolItem* item = NULL;
+  switch (control) {
+    case BACK_BUTTON:
+      item = back_button_;
+      break;
+    case FORWARD_BUTTON:
+      item = forward_button_;
+      break;
+    case STOP_BUTTON:
+      item = stop_button_;
+      break;
+    default:
+      NOTREACHED() << "Unknown UI control";
+      return;
+  }
+  gtk_widget_set_sensitive(GTK_WIDGET(item), is_enabled);
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+  if (headless_)
+    return;
+
+  gtk_entry_set_text(GTK_ENTRY(url_edit_view_), url.spec().c_str());
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+  if (headless_)
+    return;
+
+  if (loading)
+    gtk_spinner_start(GTK_SPINNER(spinner_));
+  else
+    gtk_spinner_stop(GTK_SPINNER(spinner_));
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+  ui_elements_height_ = 0;
+  if (headless_) {
+    SizeTo(width, height);
+    return;
+  }
+
+  window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+  gtk_window_set_title(window_, "Content Shell");
+  g_signal_connect(G_OBJECT(window_), "destroy",
+                   G_CALLBACK(OnWindowDestroyedThunk), this);
+
+  vbox_ = gtk_vbox_new(FALSE, 0);
+
+  // Create the menu bar.
+  GtkWidget* menu_bar = CreateMenuBar(this);
+  gtk_box_pack_start(GTK_BOX(vbox_), menu_bar, FALSE, FALSE, 0);
+
+  // Create the object that mediates accelerators.
+  GtkAccelGroup* accel_group = gtk_accel_group_new();
+  gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group);
+
+  // Set global window handling accelerators:
+  gtk_accel_group_connect(
+      accel_group, GDK_w, GDK_CONTROL_MASK,
+      GTK_ACCEL_VISIBLE,
+      g_cclosure_new(G_CALLBACK(OnCloseWindowKeyPressedThunk),
+                     this, NULL));
+
+  gtk_accel_group_connect(
+      accel_group, GDK_n, GDK_CONTROL_MASK,
+      GTK_ACCEL_VISIBLE,
+      g_cclosure_new(G_CALLBACK(OnNewWindowKeyPressedThunk),
+                    this, NULL));
+
+  gtk_accel_group_connect(
+    accel_group, GDK_F5, (GdkModifierType)0,
+      GTK_ACCEL_VISIBLE,
+      g_cclosure_new(G_CALLBACK(OnReloadKeyPressedThunk),
+                    this, NULL));
+
+  GtkWidget* toolbar = gtk_toolbar_new();
+  // Turn off the labels on the toolbar buttons.
+  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
+
+  back_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
+  g_signal_connect(back_button_, "clicked",
+                   G_CALLBACK(&OnBackButtonClickedThunk), this);
+  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), back_button_, -1 /* append */);
+  gtk_widget_add_accelerator(GTK_WIDGET(back_button_), "clicked", accel_group,
+                             GDK_Left, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
+
+  forward_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
+  g_signal_connect(forward_button_, "clicked",
+                   G_CALLBACK(&OnForwardButtonClickedThunk), this);
+  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), forward_button_, -1 /* append */);
+  gtk_widget_add_accelerator(GTK_WIDGET(forward_button_), "clicked",
+                             accel_group,
+                             GDK_Right, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
+
+  reload_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH);
+  g_signal_connect(reload_button_, "clicked",
+                   G_CALLBACK(&OnReloadButtonClickedThunk), this);
+  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), reload_button_, -1 /* append */);
+  gtk_widget_add_accelerator(GTK_WIDGET(reload_button_), "clicked",
+                             accel_group,
+                             GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
+
+  stop_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_STOP);
+  g_signal_connect(stop_button_, "clicked",
+                   G_CALLBACK(&OnStopButtonClickedThunk), this);
+  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), stop_button_, -1 /* append */);
+
+  url_edit_view_ = gtk_entry_new();
+  g_signal_connect(G_OBJECT(url_edit_view_), "activate",
+                   G_CALLBACK(&OnURLEntryActivateThunk), this);
+
+  gtk_accel_group_connect(
+      accel_group, GDK_l, GDK_CONTROL_MASK,
+      GTK_ACCEL_VISIBLE,
+      g_cclosure_new(G_CALLBACK(OnHighlightURLViewThunk),
+                     this, NULL));
+
+  GtkToolItem* tool_item = gtk_tool_item_new();
+  gtk_container_add(GTK_CONTAINER(tool_item), url_edit_view_);
+  gtk_tool_item_set_expand(tool_item, TRUE);
+  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1 /* append */);
+
+  // Center a 20x20 spinner in a 26x24 area.
+  GtkWidget* spinner_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
+  gtk_alignment_set_padding(GTK_ALIGNMENT(spinner_alignment), 2, 2, 4, 4);
+  spinner_ = gtk_spinner_new();
+  gtk_widget_set_size_request(spinner_, 20, 20);
+  gtk_container_add(GTK_CONTAINER(spinner_alignment), spinner_);
+
+  spinner_item_ = gtk_tool_item_new();
+  gtk_container_add(GTK_CONTAINER(spinner_item_), spinner_alignment);
+  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), spinner_item_, -1 /* append */);
+
+  gtk_box_pack_start(GTK_BOX(vbox_), toolbar, FALSE, FALSE, 0);
+
+  gtk_container_add(GTK_CONTAINER(window_), vbox_);
+
+  // Trigger layout of the UI elements, so that we can measure their
+  // heights. The width and height passed to this method are meant for the web
+  // contents view, not the top-level window. Since Gtk only seems to provide a
+  // suitable resizing function for top-level windows, we need to know how to
+  // convert from web contents view size to top-level window size.
+  gtk_widget_show_all(GTK_WIDGET(vbox_));
+
+  // Measure the heights of the UI elements, now that they have been laid out.
+  GtkRequisition elm_size;
+  gtk_widget_size_request(menu_bar, &elm_size);
+  ui_elements_height_ += elm_size.height;
+  gtk_widget_size_request(toolbar, &elm_size);
+  ui_elements_height_ += elm_size.height;
+
+  // We're ready to set an initial window size.
+  SizeTo(width, height);
+
+  // Finally, show the window.
+  gtk_widget_show_all(GTK_WIDGET(window_));
+}
+
+void Shell::PlatformSetContents() {
+  if (headless_)
+    return;
+
+  WebContentsView* content_view = web_contents_->GetView();
+  gtk_container_add(GTK_CONTAINER(vbox_), content_view->GetNativeView());
+}
+
+void Shell::SizeTo(int width, int height) {
+  content_width_ = width;
+  content_height_ = height;
+
+  // Prefer setting the top level window's size (if we have one), rather than
+  // setting the inner widget's minimum size (so that the user can shrink the
+  // window if she wants).
+  if (window_) {
+    gtk_window_resize(window_, width, height + ui_elements_height_);
+  } else if (web_contents_) {
+    gtk_widget_set_size_request(web_contents_->GetView()->GetNativeView(),
+                                width, height);
+  }
+}
+
+void Shell::PlatformResizeSubViews() {
+  SizeTo(content_width_, content_height_);
+}
+
+void Shell::Close() {
+  if (headless_) {
+    delete this;
+    return;
+  }
+
+  gtk_widget_destroy(GTK_WIDGET(window_));
+}
+
+void Shell::OnBackButtonClicked(GtkWidget* widget) {
+  GoBackOrForward(-1);
+}
+
+void Shell::OnForwardButtonClicked(GtkWidget* widget) {
+  GoBackOrForward(1);
+}
+
+void Shell::OnReloadButtonClicked(GtkWidget* widget) {
+  Reload();
+}
+
+void Shell::OnStopButtonClicked(GtkWidget* widget) {
+  Stop();
+}
+
+void Shell::OnURLEntryActivate(GtkWidget* entry) {
+  const gchar* str = gtk_entry_get_text(GTK_ENTRY(entry));
+  GURL url(str);
+  if (!url.has_scheme())
+    url = GURL(std::string("http://") + std::string(str));
+  LoadURL(GURL(url));
+}
+
+// Callback for when the main window is destroyed.
+gboolean Shell::OnWindowDestroyed(GtkWidget* window) {
+  delete this;
+  return FALSE;  // Don't stop this message.
+}
+
+gboolean Shell::OnCloseWindowKeyPressed(GtkAccelGroup* accel_group,
+                                        GObject* acceleratable,
+                                        guint keyval,
+                                        GdkModifierType modifier) {
+  gtk_widget_destroy(GTK_WIDGET(window_));
+  return TRUE;
+}
+
+gboolean Shell::OnNewWindowKeyPressed(GtkAccelGroup* accel_group,
+                                      GObject* acceleratable,
+                                      guint keyval,
+                                      GdkModifierType modifier) {
+  ShellBrowserContext* browser_context =
+      ShellContentBrowserClient::Get()->browser_context();
+  Shell::CreateNewWindow(browser_context,
+                         GURL(),
+                         NULL,
+                         MSG_ROUTING_NONE,
+                         gfx::Size());
+  return TRUE;
+}
+
+gboolean Shell::OnHighlightURLView(GtkAccelGroup* accel_group,
+                                   GObject* acceleratable,
+                                   guint keyval,
+                                   GdkModifierType modifier) {
+  gtk_widget_grab_focus(GTK_WIDGET(url_edit_view_));
+  return TRUE;
+}
+
+gboolean Shell::OnReloadKeyPressed(GtkAccelGroup* accel_group,
+                                   GObject* acceleratable,
+                                   guint keyval,
+                                   GdkModifierType modifier) {
+  Reload();
+  return TRUE;
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+  if (headless_)
+    return;
+
+  std::string title_utf8 = UTF16ToUTF8(title);
+  gtk_window_set_title(GTK_WINDOW(window_), title_utf8.c_str());
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog.h b/content/shell/browser/shell_javascript_dialog.h
new file mode 100644
index 0000000..4001334
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog.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 CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_H_
+#define CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_H_
+
+#include "content/public/browser/javascript_dialog_manager.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/base/gtk/gtk_signal.h"
+#endif
+
+#if defined(OS_MACOSX)
+#if __OBJC__
+@class ShellJavaScriptDialogHelper;
+#else
+class ShellJavaScriptDialogHelper;
+#endif  // __OBJC__
+#endif  // defined(OS_MACOSX)
+
+namespace content {
+
+class ShellJavaScriptDialogManager;
+
+class ShellJavaScriptDialog {
+ public:
+  ShellJavaScriptDialog(
+      ShellJavaScriptDialogManager* manager,
+      gfx::NativeWindow parent_window,
+      JavaScriptMessageType message_type,
+      const string16& message_text,
+      const string16& default_prompt_text,
+      const JavaScriptDialogManager::DialogClosedCallback& callback);
+  ~ShellJavaScriptDialog();
+
+  // Called to cancel a dialog mid-flight.
+  void Cancel();
+
+ private:
+  ShellJavaScriptDialogManager* manager_;
+  JavaScriptDialogManager::DialogClosedCallback callback_;
+
+#if defined(OS_MACOSX)
+  ShellJavaScriptDialogHelper* helper_;  // owned
+#elif defined(OS_WIN)
+  JavaScriptMessageType message_type_;
+  HWND dialog_win_;
+  string16 message_text_;
+  string16 default_prompt_text_;
+  static INT_PTR CALLBACK DialogProc(HWND dialog, UINT message, WPARAM wparam,
+                                     LPARAM lparam);
+#elif defined(TOOLKIT_GTK)
+  GtkWidget* gtk_dialog_;
+  gfx::NativeWindow parent_window_;
+  CHROMEGTK_CALLBACK_1(ShellJavaScriptDialog, void, OnResponse, int);
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ShellJavaScriptDialog);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_H_
diff --git a/content/shell/browser/shell_javascript_dialog_gtk.cc b/content/shell/browser/shell_javascript_dialog_gtk.cc
new file mode 100644
index 0000000..87bd6f3
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_gtk.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 "content/shell/browser/shell_javascript_dialog.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/shell/app/resource.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+
+namespace {
+
+const char kPromptTextId[] = "content_shell_prompt_text";
+
+// If there's a text entry in the dialog, get the text from the first one and
+// return it.
+string16 GetPromptText(GtkDialog* dialog) {
+  GtkWidget* widget = static_cast<GtkWidget*>(
+      g_object_get_data(G_OBJECT(dialog), kPromptTextId));
+  if (widget)
+    return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(widget)));
+  return string16();
+}
+
+}  // namespace
+
+
+namespace content {
+
+ShellJavaScriptDialog::ShellJavaScriptDialog(
+    ShellJavaScriptDialogManager* manager,
+    gfx::NativeWindow parent_window,
+    JavaScriptMessageType message_type,
+    const string16& message_text,
+    const string16& default_prompt_text,
+    const JavaScriptDialogManager::DialogClosedCallback& callback)
+    : manager_(manager),
+      callback_(callback),
+      parent_window_(parent_window) {
+  GtkButtonsType buttons = GTK_BUTTONS_NONE;
+  GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER;
+
+  switch (message_type) {
+    case content::JAVASCRIPT_MESSAGE_TYPE_ALERT:
+      buttons = GTK_BUTTONS_NONE;
+      gtk_message_type = GTK_MESSAGE_WARNING;
+      break;
+
+    case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
+      buttons = GTK_BUTTONS_CANCEL;
+      gtk_message_type = GTK_MESSAGE_QUESTION;
+      break;
+
+    case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT:
+      buttons = GTK_BUTTONS_CANCEL;
+      gtk_message_type = GTK_MESSAGE_QUESTION;
+      break;
+
+    default:
+      NOTREACHED();
+  }
+
+  gtk_dialog_ = gtk_message_dialog_new(parent_window_,
+                                       GTK_DIALOG_MODAL,
+                                       gtk_message_type,
+                                       buttons,
+                                       "%s",
+                                       UTF16ToUTF8(message_text).c_str());
+  g_signal_connect(gtk_dialog_,
+                   "delete-event",
+                   G_CALLBACK(gtk_widget_hide_on_delete),
+                   NULL);
+  gtk_window_set_title(GTK_WINDOW(gtk_dialog_), "JavaScript");
+
+  GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_),
+                                               GTK_STOCK_OK,
+                                               GTK_RESPONSE_OK);
+
+  if (message_type != content::JAVASCRIPT_MESSAGE_TYPE_PROMPT)
+    gtk_widget_grab_focus(ok_button);
+
+  if (message_type == content::JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
+    GtkWidget* content_area =
+        gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_));
+    GtkWidget* text_box = gtk_entry_new();
+    gtk_entry_set_text(GTK_ENTRY(text_box),
+                       UTF16ToUTF8(default_prompt_text).c_str());
+    gtk_box_pack_start(GTK_BOX(content_area), text_box, TRUE, TRUE, 0);
+    g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box);
+    gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE);
+  }
+
+  gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
+  g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnResponseThunk), this);
+  gtk_widget_show_all(GTK_WIDGET(gtk_dialog_));
+}
+
+ShellJavaScriptDialog::~ShellJavaScriptDialog() {
+}
+
+void ShellJavaScriptDialog::Cancel() {
+}
+
+void ShellJavaScriptDialog::OnResponse(GtkWidget* dialog, int response_id) {
+  switch (response_id) {
+    case GTK_RESPONSE_OK:
+      callback_.Run(true, GetPromptText(GTK_DIALOG(dialog)));
+      break;
+    case GTK_RESPONSE_CANCEL:
+    case GTK_RESPONSE_DELETE_EVENT:
+      callback_.Run(false, string16());
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  gtk_widget_destroy(dialog);
+
+  manager_->DialogClosed(this);
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog_mac.mm b/content/shell/browser/shell_javascript_dialog_mac.mm
new file mode 100644
index 0000000..fe9de98
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_mac.mm
@@ -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/shell/browser/shell_javascript_dialog.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+
+// Helper object that receives the notification that the dialog/sheet is
+// going away. Is responsible for cleaning itself up.
+@interface ShellJavaScriptDialogHelper : NSObject<NSAlertDelegate> {
+ @private
+  base::scoped_nsobject<NSAlert> alert_;
+  NSTextField* textField_;  // WEAK; owned by alert_
+
+  // Copies of the fields in ShellJavaScriptDialog because they're private.
+  content::ShellJavaScriptDialogManager* manager_;
+  content::JavaScriptDialogManager::DialogClosedCallback callback_;
+}
+
+- (id)initHelperWithManager:(content::ShellJavaScriptDialogManager*)manager
+   andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback;
+- (NSAlert*)alert;
+- (NSTextField*)textField;
+- (void)alertDidEnd:(NSAlert*)alert
+         returnCode:(int)returnCode
+        contextInfo:(void*)contextInfo;
+- (void)cancel;
+
+@end
+
+@implementation ShellJavaScriptDialogHelper
+
+- (id)initHelperWithManager:(content::ShellJavaScriptDialogManager*)manager
+  andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback {
+  if (self = [super init]) {
+    manager_ = manager;
+    callback_ = callback;
+  }
+
+  return self;
+}
+
+- (NSAlert*)alert {
+  alert_.reset([[NSAlert alloc] init]);
+  return alert_;
+}
+
+- (NSTextField*)textField {
+  textField_ = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)];
+  [[textField_ cell] setLineBreakMode:NSLineBreakByTruncatingTail];
+  [alert_ setAccessoryView:textField_];
+  [textField_ release];
+
+  return textField_;
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+         returnCode:(int)returnCode
+        contextInfo:(void*)contextInfo {
+  if (returnCode == NSRunStoppedResponse)
+    return;
+
+  bool success = returnCode == NSAlertFirstButtonReturn;
+  string16 input;
+  if (textField_)
+    input = base::SysNSStringToUTF16([textField_ stringValue]);
+
+  content::ShellJavaScriptDialog* native_dialog =
+      reinterpret_cast<content::ShellJavaScriptDialog*>(contextInfo);
+  callback_.Run(success, input);
+  manager_->DialogClosed(native_dialog);
+}
+
+- (void)cancel {
+  [NSApp endSheet:[alert_ window]];
+  alert_.reset();
+}
+
+@end
+
+namespace content {
+
+ShellJavaScriptDialog::ShellJavaScriptDialog(
+    ShellJavaScriptDialogManager* manager,
+    gfx::NativeWindow parent_window,
+    JavaScriptMessageType message_type,
+    const string16& message_text,
+    const string16& default_prompt_text,
+    const JavaScriptDialogManager::DialogClosedCallback& callback)
+    : manager_(manager),
+      callback_(callback) {
+  bool text_field = message_type == JAVASCRIPT_MESSAGE_TYPE_PROMPT;
+  bool one_button = message_type == JAVASCRIPT_MESSAGE_TYPE_ALERT;
+
+  helper_ =
+      [[ShellJavaScriptDialogHelper alloc] initHelperWithManager:manager
+                                                     andCallback:callback];
+
+  // Show the modal dialog.
+  NSAlert* alert = [helper_ alert];
+  NSTextField* field = nil;
+  if (text_field) {
+    field = [helper_ textField];
+    [field setStringValue:base::SysUTF16ToNSString(default_prompt_text)];
+  }
+  [alert setDelegate:helper_];
+  [alert setInformativeText:base::SysUTF16ToNSString(message_text)];
+  [alert setMessageText:@"Javascript alert"];
+  [alert addButtonWithTitle:@"OK"];
+  if (!one_button) {
+    NSButton* other = [alert addButtonWithTitle:@"Cancel"];
+    [other setKeyEquivalent:@"\e"];
+  }
+
+  [alert
+      beginSheetModalForWindow:nil  // nil here makes it app-modal
+                 modalDelegate:helper_
+                didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+                   contextInfo:this];
+
+  if ([alert accessoryView])
+    [[alert window] makeFirstResponder:[alert accessoryView]];
+}
+
+ShellJavaScriptDialog::~ShellJavaScriptDialog() {
+  [helper_ release];
+}
+
+void ShellJavaScriptDialog::Cancel() {
+  [helper_ cancel];
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog_manager.cc b/content/shell/browser/shell_javascript_dialog_manager.cc
new file mode 100644
index 0000000..1476f7c
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_manager.cc
@@ -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.
+
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/browser/shell_javascript_dialog.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/net_util.h"
+
+namespace content {
+
+ShellJavaScriptDialogManager::ShellJavaScriptDialogManager() {
+}
+
+ShellJavaScriptDialogManager::~ShellJavaScriptDialogManager() {
+}
+
+void ShellJavaScriptDialogManager::RunJavaScriptDialog(
+    WebContents* web_contents,
+    const GURL& origin_url,
+    const std::string& accept_lang,
+    JavaScriptMessageType javascript_message_type,
+    const string16& message_text,
+    const string16& default_prompt_text,
+    const DialogClosedCallback& callback,
+    bool* did_suppress_message) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+    callback.Run(true, string16());
+    return;
+  }
+
+  if (!dialog_request_callback_.is_null()) {
+    dialog_request_callback_.Run();
+    callback.Run(true, string16());
+    dialog_request_callback_.Reset();
+    return;
+  }
+
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+  *did_suppress_message = false;
+
+  if (dialog_) {
+    // One dialog at a time, please.
+    *did_suppress_message = true;
+    return;
+  }
+
+  string16 new_message_text = net::FormatUrl(origin_url, accept_lang) +
+                              ASCIIToUTF16("\n\n") +
+                              message_text;
+  gfx::NativeWindow parent_window =
+      web_contents->GetView()->GetTopLevelNativeWindow();
+
+  dialog_.reset(new ShellJavaScriptDialog(this,
+                                          parent_window,
+                                          javascript_message_type,
+                                          new_message_text,
+                                          default_prompt_text,
+                                          callback));
+#else
+  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+  *did_suppress_message = true;
+  return;
+#endif
+}
+
+void ShellJavaScriptDialogManager::RunBeforeUnloadDialog(
+    WebContents* web_contents,
+    const string16& message_text,
+    bool is_reload,
+    const DialogClosedCallback& callback) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+    callback.Run(true, string16());
+    return;
+  }
+
+  if (!dialog_request_callback_.is_null()) {
+    dialog_request_callback_.Run();
+    callback.Run(true, string16());
+    dialog_request_callback_.Reset();
+    return;
+  }
+
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+  if (dialog_) {
+    // Seriously!?
+    callback.Run(true, string16());
+    return;
+  }
+
+  string16 new_message_text =
+      message_text +
+      ASCIIToUTF16("\n\nIs it OK to leave/reload this page?");
+
+  gfx::NativeWindow parent_window =
+      web_contents->GetView()->GetTopLevelNativeWindow();
+
+  dialog_.reset(new ShellJavaScriptDialog(this,
+                                          parent_window,
+                                          JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
+                                          new_message_text,
+                                          string16(),  // default_prompt_text
+                                          callback));
+#else
+  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+  callback.Run(true, string16());
+  return;
+#endif
+}
+
+void ShellJavaScriptDialogManager::CancelActiveAndPendingDialogs(
+    WebContents* web_contents) {
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+  if (dialog_) {
+    dialog_->Cancel();
+    dialog_.reset();
+  }
+#else
+  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+#endif
+}
+
+void ShellJavaScriptDialogManager::WebContentsDestroyed(
+    WebContents* web_contents) {
+}
+
+void ShellJavaScriptDialogManager::DialogClosed(ShellJavaScriptDialog* dialog) {
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+  DCHECK_EQ(dialog, dialog_.get());
+  dialog_.reset();
+#else
+  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+#endif
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog_manager.h b/content/shell/browser/shell_javascript_dialog_manager.h
new file mode 100644
index 0000000..763736f
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_manager.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 CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/javascript_dialog_manager.h"
+
+namespace content {
+
+class ShellJavaScriptDialog;
+
+class ShellJavaScriptDialogManager : public JavaScriptDialogManager {
+ public:
+  ShellJavaScriptDialogManager();
+  virtual ~ShellJavaScriptDialogManager();
+
+  // JavaScriptDialogManager:
+  virtual void RunJavaScriptDialog(
+      WebContents* web_contents,
+      const GURL& origin_url,
+      const std::string& accept_lang,
+      JavaScriptMessageType javascript_message_type,
+      const string16& message_text,
+      const string16& default_prompt_text,
+      const DialogClosedCallback& callback,
+      bool* did_suppress_message) OVERRIDE;
+
+  virtual void RunBeforeUnloadDialog(
+      WebContents* web_contents,
+      const string16& message_text,
+      bool is_reload,
+      const DialogClosedCallback& callback) OVERRIDE;
+
+  virtual void CancelActiveAndPendingDialogs(
+      WebContents* web_contents) OVERRIDE;
+
+  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+
+  // Called by the ShellJavaScriptDialog when it closes.
+  void DialogClosed(ShellJavaScriptDialog* dialog);
+
+  // Used for content_browsertests.
+  void set_dialog_request_callback(const base::Closure& callback) {
+    dialog_request_callback_ = callback;
+  }
+
+ private:
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+  // The dialog being shown. No queueing.
+  scoped_ptr<ShellJavaScriptDialog> dialog_;
+#else
+  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+#endif
+
+  base::Closure dialog_request_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellJavaScriptDialogManager);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
diff --git a/content/shell/browser/shell_javascript_dialog_win.cc b/content/shell/browser/shell_javascript_dialog_win.cc
new file mode 100644
index 0000000..a59639e
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_win.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 "content/shell/browser/shell_javascript_dialog.h"
+
+#include "base/strings/string_util.h"
+#include "content/shell/app/resource.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+
+namespace content {
+
+class ShellJavaScriptDialog;
+
+INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog,
+                                                   UINT message,
+                                                   WPARAM wparam,
+                                                   LPARAM lparam) {
+  switch (message) {
+    case WM_INITDIALOG: {
+      SetWindowLongPtr(dialog, DWLP_USER, static_cast<LONG_PTR>(lparam));
+      ShellJavaScriptDialog* owner =
+          reinterpret_cast<ShellJavaScriptDialog*>(lparam);
+      owner->dialog_win_ = dialog;
+      SetDlgItemText(dialog, IDC_DIALOGTEXT, owner->message_text_.c_str());
+      if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT)
+        SetDlgItemText(dialog, IDC_PROMPTEDIT,
+                       owner->default_prompt_text_.c_str());
+      break;
+    }
+    case WM_DESTROY: {
+      ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
+          GetWindowLongPtr(dialog, DWLP_USER));
+      if (owner->dialog_win_) {
+        owner->dialog_win_ = 0;
+        owner->callback_.Run(false, string16());
+        owner->manager_->DialogClosed(owner);
+      }
+      break;
+    }
+    case WM_COMMAND: {
+      ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
+          GetWindowLongPtr(dialog, DWLP_USER));
+      string16 user_input;
+      bool finish = false;
+      bool result;
+      switch (LOWORD(wparam)) {
+        case IDOK:
+          finish = true;
+          result = true;
+          if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
+            int length =
+                GetWindowTextLength(GetDlgItem(dialog, IDC_PROMPTEDIT)) + 1;
+            GetDlgItemText(dialog, IDC_PROMPTEDIT,
+                           WriteInto(&user_input, length), length);
+          }
+          break;
+        case IDCANCEL:
+          finish = true;
+          result = false;
+          break;
+      }
+      if (finish) {
+        owner->dialog_win_ = 0;
+        owner->callback_.Run(result, user_input);
+        DestroyWindow(dialog);
+        owner->manager_->DialogClosed(owner);
+      }
+      break;
+    }
+    default:
+      return DefWindowProc(dialog, message, wparam, lparam);
+  }
+  return 0;
+}
+
+ShellJavaScriptDialog::ShellJavaScriptDialog(
+    ShellJavaScriptDialogManager* manager,
+    gfx::NativeWindow parent_window,
+    JavaScriptMessageType message_type,
+    const string16& message_text,
+    const string16& default_prompt_text,
+    const JavaScriptDialogManager::DialogClosedCallback& callback)
+    : manager_(manager),
+      callback_(callback),
+      message_text_(message_text),
+      default_prompt_text_(default_prompt_text),
+      message_type_(message_type) {
+  int dialog_type;
+  if (message_type == JAVASCRIPT_MESSAGE_TYPE_ALERT)
+    dialog_type = IDD_ALERT;
+  else if (message_type == JAVASCRIPT_MESSAGE_TYPE_CONFIRM)
+    dialog_type = IDD_CONFIRM;
+  else // JAVASCRIPT_MESSAGE_TYPE_PROMPT
+    dialog_type = IDD_PROMPT;
+
+  dialog_win_ = CreateDialogParam(GetModuleHandle(0),
+                                  MAKEINTRESOURCE(dialog_type), 0, DialogProc,
+                                  reinterpret_cast<LPARAM>(this));
+  ShowWindow(dialog_win_, SW_SHOWNORMAL);
+}
+
+ShellJavaScriptDialog::~ShellJavaScriptDialog() {
+  Cancel();
+}
+
+void ShellJavaScriptDialog::Cancel() {
+  if (dialog_win_)
+    DestroyWindow(dialog_win_);
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_layout_tests_android.cc b/content/shell/browser/shell_layout_tests_android.cc
new file mode 100644
index 0000000..de94b8c
--- /dev/null
+++ b/content/shell/browser/shell_layout_tests_android.cc
@@ -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.
+
+#include "content/shell/browser/shell_layout_tests_android.h"
+
+#include "base/android/fifo_utils.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/message_loop/message_loop.h"
+#include "content/public/test/nested_message_pump_android.h"
+#include "content/shell/common/shell_switches.h"
+#include "jni/ShellLayoutTestUtils_jni.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Path to search for when translating a layout test path to an URL.
+const char kAndroidLayoutTestPath[] =
+    "/data/local/tmp/third_party/WebKit/LayoutTests/";
+
+// The base URL from which layout tests are being served on Android.
+const char kAndroidLayoutTestBase[] = "http://127.0.0.1:8000/all-tests/";
+
+base::FilePath GetTestFilesDirectory(JNIEnv* env) {
+  ScopedJavaLocalRef<jstring> directory =
+      content::Java_ShellLayoutTestUtils_getApplicationFilesDirectory(
+          env, base::android::GetApplicationContext());
+  return base::FilePath(ConvertJavaStringToUTF8(directory));
+}
+
+void EnsureCreateFIFO(const base::FilePath& path) {
+  unlink(path.value().c_str());
+  CHECK(base::android::CreateFIFO(path, 0666))
+    << "Unable to create the Android's FIFO: " << path.value().c_str();
+}
+
+base::MessagePump* CreateMessagePumpForUI() {
+  return new content::NestedMessagePumpAndroid();
+}
+
+}  // namespace
+
+namespace content {
+
+bool GetTestUrlForAndroid(std::string& path_or_url, GURL* url) {
+  if (path_or_url.find(kAndroidLayoutTestPath) == std::string::npos)
+    return false;
+
+  std::string test_location(kAndroidLayoutTestBase);
+  test_location.append(path_or_url.substr(strlen(kAndroidLayoutTestPath)));
+
+  *url = GURL(test_location);
+  return true;
+}
+
+void EnsureInitializeForAndroidLayoutTests() {
+  CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree));
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  content::NestedMessagePumpAndroid::RegisterJni(env);
+  content::RegisterNativesImpl(env);
+
+  bool success = base::MessageLoop::InitMessagePumpForUIFactory(
+      &CreateMessagePumpForUI);
+  CHECK(success) << "Unable to initialize the message pump for Android.";
+
+  // Android will need three FIFOs to communicate with the Blink test runner,
+  // one for each of [stdout, stderr, stdin].
+  base::FilePath files_dir(GetTestFilesDirectory(env));
+
+  base::FilePath stdout_fifo(files_dir.Append(FILE_PATH_LITERAL("test.fifo")));
+  EnsureCreateFIFO(stdout_fifo);
+
+  base::FilePath stderr_fifo(
+      files_dir.Append(FILE_PATH_LITERAL("stderr.fifo")));
+  EnsureCreateFIFO(stderr_fifo);
+
+  base::FilePath stdin_fifo(files_dir.Append(FILE_PATH_LITERAL("stdin.fifo")));
+  EnsureCreateFIFO(stdin_fifo);
+
+  // Redirecting stdout needs to happen before redirecting stdin, which needs
+  // to happen before redirecting stderr.
+  success = base::android::RedirectStream(stdout, stdout_fifo, "w") &&
+            base::android::RedirectStream(stdin, stdin_fifo, "r") &&
+            base::android::RedirectStream(stderr, stderr_fifo, "w");
+
+  CHECK(success) << "Unable to initialize the Android FIFOs.";
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_layout_tests_android.h b/content/shell/browser/shell_layout_tests_android.h
new file mode 100644
index 0000000..7410954
--- /dev/null
+++ b/content/shell/browser/shell_layout_tests_android.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 CONTENT_SHELL_BROWSER_SHELL_LAYOUT_TESTS_ANDROID_H_
+#define CONTENT_SHELL_BROWSER_SHELL_LAYOUT_TESTS_ANDROID_H_
+
+#include <string>
+
+class GURL;
+
+namespace content {
+
+// On Android, all passed tests will be paths to a local temporary directory.
+// However, because we can't transfer all test files to the device, translate
+// those paths to a local, forwarded URL so the host can serve them.
+bool GetTestUrlForAndroid(std::string& path_or_url, GURL* url);
+
+// Initialize the nested message loop and FIFOs for Android, and verify that
+// all has been set up using a few appropriate CHECK()s.
+void EnsureInitializeForAndroidLayoutTests();
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_LAYOUT_TESTS_ANDROID_H_
diff --git a/content/shell/browser/shell_login_dialog.cc b/content/shell/browser/shell_login_dialog.cc
new file mode 100644
index 0000000..f1639e9
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog.cc
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_login_dialog.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "net/base/auth.h"
+#include "net/url_request/url_request.h"
+#include "ui/base/text/text_elider.h"
+
+namespace content {
+
+ShellLoginDialog::ShellLoginDialog(
+    net::AuthChallengeInfo* auth_info,
+    net::URLRequest* request) : auth_info_(auth_info),
+                                request_(request) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&ShellLoginDialog::PrepDialog, this,
+                 ASCIIToUTF16(auth_info->challenger.ToString()),
+                 UTF8ToUTF16(auth_info->realm)));
+}
+
+void ShellLoginDialog::OnRequestCancelled() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&ShellLoginDialog::PlatformRequestCancelled, this));
+}
+
+void ShellLoginDialog::UserAcceptedAuth(const string16& username,
+                                        const string16& password) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&ShellLoginDialog::SendAuthToRequester, this,
+                 true, username, password));
+}
+
+void ShellLoginDialog::UserCancelledAuth() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&ShellLoginDialog::SendAuthToRequester, this,
+                 false, string16(), string16()));
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&ShellLoginDialog::PlatformCleanUp, this));
+}
+
+ShellLoginDialog::~ShellLoginDialog() {
+  // Cannot post any tasks here; this object is going away and cannot be
+  // referenced/dereferenced.
+}
+
+#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK)
+// Bogus implementations for linking. They are never called because
+// ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL.
+// TODO: implement ShellLoginDialog for other platforms, drop this #if
+void ShellLoginDialog::PlatformCreateDialog(const string16& message) {}
+void ShellLoginDialog::PlatformCleanUp() {}
+void ShellLoginDialog::PlatformRequestCancelled() {}
+#endif
+
+void ShellLoginDialog::PrepDialog(const string16& host,
+                                  const string16& realm) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  // The realm is controlled by the remote server, so there is no reason to
+  // believe it is of a reasonable length.
+  string16 elided_realm;
+  ui::ElideString(realm, 120, &elided_realm);
+
+  string16 explanation =
+      ASCIIToUTF16("The server ") + host +
+      ASCIIToUTF16(" requires a username and password.");
+
+  if (!elided_realm.empty()) {
+    explanation += ASCIIToUTF16(" The server says: ");
+    explanation += elided_realm;
+    explanation += ASCIIToUTF16(".");
+  }
+
+  PlatformCreateDialog(explanation);
+}
+
+void ShellLoginDialog::SendAuthToRequester(bool success,
+                                           const string16& username,
+                                           const string16& password) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  if (success)
+    request_->SetAuth(net::AuthCredentials(username, password));
+  else
+    request_->CancelAuth();
+  ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_);
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&ShellLoginDialog::PlatformCleanUp, this));
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_login_dialog.h b/content/shell/browser/shell_login_dialog.h
new file mode 100644
index 0000000..d9b0504
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog.h
@@ -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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_
+#define CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_
+
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/base/gtk/gtk_signal.h"
+#endif
+
+#if defined(OS_MACOSX)
+#if __OBJC__
+@class ShellLoginDialogHelper;
+#else
+class ShellLoginDialogHelper;
+#endif  // __OBJC__
+#endif  // defined(OS_MACOSX)
+
+namespace net {
+class AuthChallengeInfo;
+class URLRequest;
+}
+
+namespace content {
+
+// This class provides a dialog box to ask the user for credentials. Useful in
+// ResourceDispatcherHostDelegate::CreateLoginDelegate.
+class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate {
+ public:
+  // Threading: IO thread.
+  ShellLoginDialog(net::AuthChallengeInfo* auth_info, net::URLRequest* request);
+
+  // ResourceDispatcherHostLoginDelegate implementation:
+  // Threading: IO thread.
+  virtual void OnRequestCancelled() OVERRIDE;
+
+  // Called by the platform specific code when the user responds. Public because
+  // the aforementioned platform specific code may not have access to private
+  // members. Not to be called from client code.
+  // Threading: UI thread.
+  void UserAcceptedAuth(const string16& username, const string16& password);
+  void UserCancelledAuth();
+
+ protected:
+  // Threading: any
+  virtual ~ShellLoginDialog();
+
+ private:
+  // All the methods that begin with Platform need to be implemented by the
+  // platform specific LoginDialog implementation.
+  // Creates the dialog.
+  // Threading: UI thread.
+  void PlatformCreateDialog(const string16& message);
+  // Called from the destructor to let each platform do any necessary cleanup.
+  // Threading: UI thread.
+  void PlatformCleanUp();
+  // Called from OnRequestCancelled if the request was cancelled.
+  // Threading: UI thread.
+  void PlatformRequestCancelled();
+
+  // Sets up dialog creation.
+  // Threading: UI thread.
+  void PrepDialog(const string16& host, const string16& realm);
+
+  // Sends the authentication to the requester.
+  // Threading: IO thread.
+  void SendAuthToRequester(bool success,
+                           const string16& username,
+                           const string16& password);
+
+  // Who/where/what asked for the authentication.
+  // Threading: IO thread.
+  scoped_refptr<net::AuthChallengeInfo> auth_info_;
+
+  // The request that wants login data.
+  // Threading: IO thread.
+  net::URLRequest* request_;
+
+#if defined(OS_MACOSX)
+  // Threading: UI thread.
+  ShellLoginDialogHelper* helper_;  // owned
+#elif defined(TOOLKIT_GTK)
+  GtkWidget* username_entry_;
+  GtkWidget* password_entry_;
+  GtkWidget* root_;
+  CHROMEGTK_CALLBACK_1(ShellLoginDialog, void, OnResponse, int);
+#endif
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_
diff --git a/content/shell/browser/shell_login_dialog_gtk.cc b/content/shell/browser/shell_login_dialog_gtk.cc
new file mode 100644
index 0000000..b08b449
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog_gtk.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 "content/shell/browser/shell_login_dialog.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "ui/base/gtk/gtk_hig_constants.h"
+
+namespace content {
+
+void ShellLoginDialog::PlatformCreateDialog(const string16& message) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  int render_process_id;
+  int render_view_id;
+  if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderView(
+          &render_process_id,  &render_view_id)) {
+    NOTREACHED();
+  }
+
+  WebContents* web_contents = NULL;
+  RenderViewHost* render_view_host =
+      RenderViewHost::FromID(render_process_id, render_view_id);
+  if (render_view_host)
+    web_contents = WebContents::FromRenderViewHost(render_view_host);
+  DCHECK(web_contents);
+
+  gfx::NativeWindow parent_window =
+      web_contents->GetView()->GetTopLevelNativeWindow();
+
+  root_ = gtk_message_dialog_new(parent_window,
+                                 GTK_DIALOG_MODAL,
+                                 GTK_MESSAGE_INFO,
+                                 GTK_BUTTONS_OK_CANCEL,
+                                 "Please log in.");
+
+  GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(root_));
+  GtkWidget* label = gtk_label_new(UTF16ToUTF8(message).c_str());
+  gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+  gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0);
+
+  username_entry_ = gtk_entry_new();
+  gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);
+
+  password_entry_ = gtk_entry_new();
+  gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
+  gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
+
+  GtkWidget* table = gtk_table_new(2, 2, FALSE);
+  gtk_table_set_col_spacing(GTK_TABLE(table), 0, ui::kLabelSpacing);
+  gtk_table_set_row_spacings(GTK_TABLE(table), ui::kControlSpacing);
+
+  GtkWidget* username_label = gtk_label_new("Username:");
+  gtk_misc_set_alignment(GTK_MISC(username_label), 0, 0.5);
+
+  gtk_table_attach(GTK_TABLE(table), username_label, 0, 1, 0, 1, GTK_FILL,
+                   GTK_FILL, 0, 0);
+  gtk_table_attach_defaults(GTK_TABLE(table), username_entry_, 1, 2, 0, 1);
+
+  GtkWidget* password_label = gtk_label_new("Password:");
+  gtk_misc_set_alignment(GTK_MISC(password_label), 0, 0.5);
+
+  gtk_table_attach(GTK_TABLE(table), password_label, 0, 1, 1, 2, GTK_FILL,
+                   GTK_FILL, 0, 0);
+  gtk_table_attach_defaults(GTK_TABLE(table), password_entry_, 1, 2, 1, 2);
+
+  gtk_box_pack_start(GTK_BOX(content_area), table, FALSE, FALSE, 0);
+
+  g_signal_connect(root_, "response", G_CALLBACK(OnResponseThunk), this);
+  gtk_widget_grab_focus(username_entry_);
+  gtk_widget_show_all(GTK_WIDGET(root_));
+}
+
+void ShellLoginDialog::PlatformCleanUp() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void ShellLoginDialog::PlatformRequestCancelled() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void ShellLoginDialog::OnResponse(GtkWidget* sender, int response_id) {
+  switch (response_id) {
+    case GTK_RESPONSE_OK:
+      UserAcceptedAuth(
+          UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
+          UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
+      break;
+    case GTK_RESPONSE_CANCEL:
+    case GTK_RESPONSE_DELETE_EVENT:
+      UserCancelledAuth();
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  gtk_widget_destroy(root_);
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_login_dialog_mac.mm b/content/shell/browser/shell_login_dialog_mac.mm
new file mode 100644
index 0000000..447aa58
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog_mac.mm
@@ -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 "content/shell/browser/shell_login_dialog.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#import "ui/base/cocoa/nib_loading.h"
+
+namespace {
+
+const int kUsernameFieldTag = 1;
+const int kPasswordFieldTag = 2;
+
+}  // namespace
+
+// Helper object that receives the notification that the dialog/sheet is
+// going away.
+@interface ShellLoginDialogHelper : NSObject<NSAlertDelegate> {
+ @private
+  base::scoped_nsobject<NSAlert> alert_;
+  NSTextField* usernameField_;  // WEAK; owned by alert_
+  NSSecureTextField* passwordField_;  // WEAK; owned by alert_
+}
+
+- (NSAlert*)alert;
+- (NSView*)accessoryView;
+- (void)focus;
+- (void)alertDidEnd:(NSAlert*)alert
+         returnCode:(int)returnCode
+        contextInfo:(void*)contextInfo;
+- (void)cancel;
+
+@end
+
+@implementation ShellLoginDialogHelper
+
+- (NSAlert*)alert {
+  alert_.reset([[NSAlert alloc] init]);
+  [alert_ setAccessoryView:[self accessoryView]];
+  return alert_;
+}
+
+- (NSView*)accessoryView {
+  NSView* accessory_view = ui::GetViewFromNib(@"HttpAuth");
+  if (!accessory_view)
+    return nil;
+
+  usernameField_ = [accessory_view viewWithTag:kUsernameFieldTag];
+  passwordField_ = [accessory_view viewWithTag:kPasswordFieldTag];
+  return accessory_view;
+}
+
+- (void)focus {
+  [[alert_ window] makeFirstResponder:usernameField_];
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+         returnCode:(int)returnCode
+        contextInfo:(void*)contextInfo {
+  if (returnCode == NSRunStoppedResponse)
+    return;
+
+  content::ShellLoginDialog* this_dialog =
+      reinterpret_cast<content::ShellLoginDialog*>(contextInfo);
+  if (returnCode == NSAlertFirstButtonReturn) {
+    this_dialog->UserAcceptedAuth(
+        base::SysNSStringToUTF16([usernameField_ stringValue]),
+        base::SysNSStringToUTF16([passwordField_ stringValue]));
+  } else {
+    this_dialog->UserCancelledAuth();
+  }
+}
+
+- (void)cancel {
+  [NSApp endSheet:[alert_ window]];
+  alert_.reset();
+}
+
+@end
+
+namespace content {
+
+void ShellLoginDialog::PlatformCreateDialog(const string16& message) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  helper_ = [[ShellLoginDialogHelper alloc] init];
+
+  // Show the modal dialog.
+  NSAlert* alert = [helper_ alert];
+  [alert setDelegate:helper_];
+  [alert setInformativeText:base::SysUTF16ToNSString(message)];
+  [alert setMessageText:@"Please log in."];
+  [alert addButtonWithTitle:@"OK"];
+  NSButton* other = [alert addButtonWithTitle:@"Cancel"];
+  [other setKeyEquivalent:@"\e"];
+  [alert
+      beginSheetModalForWindow:nil  // nil here makes it app-modal
+                 modalDelegate:helper_
+                didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+                   contextInfo:this];
+
+  [helper_ focus];
+}
+
+void ShellLoginDialog::PlatformCleanUp() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  [helper_ release];
+  helper_ = nil;
+}
+
+void ShellLoginDialog::PlatformRequestCancelled() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  [helper_ cancel];
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_mac.mm b/content/shell/browser/shell_mac.mm
new file mode 100644
index 0000000..ca6a0ff
--- /dev/null
+++ b/content/shell/browser/shell_mac.mm
@@ -0,0 +1,334 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/app/resource.h"
+#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
+#include "url/gurl.h"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+enum {
+  NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
+  NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8
+};
+
+#endif // MAC_OS_X_VERSION_10_7
+
+// Receives notification that the window is closing so that it can start the
+// tear-down process. Is responsible for deleting itself when done.
+@interface ContentShellWindowDelegate : NSObject<NSWindowDelegate> {
+ @private
+  content::Shell* shell_;
+}
+- (id)initWithShell:(content::Shell*)shell;
+@end
+
+@implementation ContentShellWindowDelegate
+
+- (id)initWithShell:(content::Shell*)shell {
+  if ((self = [super init])) {
+    shell_ = shell;
+  }
+  return self;
+}
+
+// Called when the window is about to close. Perform the self-destruction
+// sequence by getting rid of the shell and removing it and the window from
+// the various global lists. By returning YES, we allow the window to be
+// removed from the screen.
+- (BOOL)windowShouldClose:(id)window {
+  [window autorelease];
+  delete shell_;
+  [self release];
+
+  return YES;
+}
+
+- (void)performAction:(id)sender {
+  shell_->ActionPerformed([sender tag]);
+}
+
+- (void)takeURLStringValueFrom:(id)sender {
+  shell_->URLEntered(base::SysNSStringToUTF8([sender stringValue]));
+}
+
+@end
+
+@interface CrShellWindow : UnderlayOpenGLHostingWindow {
+ @private
+  content::Shell* shell_;
+}
+- (void)setShell:(content::Shell*)shell;
+- (void)showDevTools:(id)sender;
+@end
+
+@implementation CrShellWindow
+
+- (void)setShell:(content::Shell*)shell {
+  shell_ = shell;
+}
+
+- (void)showDevTools:(id)sender {
+  shell_->ShowDevTools();
+}
+
+@end
+
+namespace {
+
+NSString* kWindowTitle = @"Content Shell";
+
+// Layout constants (in view coordinates)
+const CGFloat kButtonWidth = 72;
+const CGFloat kURLBarHeight = 24;
+
+// The minimum size of the window's content (in view coordinates)
+const CGFloat kMinimumWindowWidth = 400;
+const CGFloat kMinimumWindowHeight = 300;
+
+void MakeShellButton(NSRect* rect,
+                     NSString* title,
+                     NSView* parent,
+                     int control,
+                     NSView* target,
+                     NSString* key,
+                     NSUInteger modifier) {
+  base::scoped_nsobject<NSButton> button(
+      [[NSButton alloc] initWithFrame:*rect]);
+  [button setTitle:title];
+  [button setBezelStyle:NSSmallSquareBezelStyle];
+  [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
+  [button setTarget:target];
+  [button setAction:@selector(performAction:)];
+  [button setTag:control];
+  [button setKeyEquivalent:key];
+  [button setKeyEquivalentModifierMask:modifier];
+  [parent addSubview:button];
+  rect->origin.x += kButtonWidth;
+}
+
+}  // namespace
+
+namespace content {
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+}
+
+void Shell::PlatformCleanUp() {
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+  if (headless_)
+    return;
+
+  int id;
+  switch (control) {
+    case BACK_BUTTON:
+      id = IDC_NAV_BACK;
+      break;
+    case FORWARD_BUTTON:
+      id = IDC_NAV_FORWARD;
+      break;
+    case STOP_BUTTON:
+      id = IDC_NAV_STOP;
+      break;
+    default:
+      NOTREACHED() << "Unknown UI control";
+      return;
+  }
+  [[[window_ contentView] viewWithTag:id] setEnabled:is_enabled];
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+  if (headless_)
+    return;
+
+  NSString* url_string = base::SysUTF8ToNSString(url.spec());
+  [url_edit_view_ setStringValue:url_string];
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+  if (headless_) {
+    content_width_ = width;
+    content_height_ = height;
+    return;
+  }
+
+  NSRect initial_window_bounds =
+      NSMakeRect(0, 0, width, height + kURLBarHeight);
+  NSRect content_rect = initial_window_bounds;
+  NSUInteger style_mask = NSTitledWindowMask |
+                          NSClosableWindowMask |
+                          NSMiniaturizableWindowMask |
+                          NSResizableWindowMask;
+  CrShellWindow* window =
+      [[CrShellWindow alloc] initWithContentRect:content_rect
+                                       styleMask:style_mask
+                                         backing:NSBackingStoreBuffered
+                                           defer:NO];
+  window_ = window;
+  [window setShell:this];
+  [window_ setTitle:kWindowTitle];
+  NSView* content = [window_ contentView];
+
+  // If the window is allowed to get too small, it will wreck the view bindings.
+  NSSize min_size = NSMakeSize(kMinimumWindowWidth, kMinimumWindowHeight);
+  min_size = [content convertSize:min_size toView:nil];
+  // Note that this takes window coordinates.
+  [window_ setContentMinSize:min_size];
+
+  // Set the shell window to participate in Lion Fullscreen mode. Set
+  // Setting this flag has no effect on Snow Leopard or earlier.
+  NSUInteger collectionBehavior = [window_ collectionBehavior];
+  collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+  [window_ setCollectionBehavior:collectionBehavior];
+
+  // Rely on the window delegate to clean us up rather than immediately
+  // releasing when the window gets closed. We use the delegate to do
+  // everything from the autorelease pool so the shell isn't on the stack
+  // during cleanup (ie, a window close from javascript).
+  [window_ setReleasedWhenClosed:NO];
+
+  // Create a window delegate to watch for when it's asked to go away. It will
+  // clean itself up so we don't need to hold a reference.
+  ContentShellWindowDelegate* delegate =
+      [[ContentShellWindowDelegate alloc] initWithShell:this];
+  [window_ setDelegate:delegate];
+
+  NSRect button_frame =
+      NSMakeRect(0, NSMaxY(initial_window_bounds) - kURLBarHeight,
+                 kButtonWidth, kURLBarHeight);
+
+  MakeShellButton(&button_frame, @"Back", content, IDC_NAV_BACK,
+                  (NSView*)delegate, @"[", NSCommandKeyMask);
+  MakeShellButton(&button_frame, @"Forward", content, IDC_NAV_FORWARD,
+                  (NSView*)delegate, @"]", NSCommandKeyMask);
+  MakeShellButton(&button_frame, @"Reload", content, IDC_NAV_RELOAD,
+                  (NSView*)delegate, @"r", NSCommandKeyMask);
+  MakeShellButton(&button_frame, @"Stop", content, IDC_NAV_STOP,
+                  (NSView*)delegate, @".", NSCommandKeyMask);
+
+  button_frame.size.width =
+      NSWidth(initial_window_bounds) - NSMinX(button_frame);
+  base::scoped_nsobject<NSTextField> url_edit_view(
+      [[NSTextField alloc] initWithFrame:button_frame]);
+  [content addSubview:url_edit_view];
+  [url_edit_view setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
+  [url_edit_view setTarget:delegate];
+  [url_edit_view setAction:@selector(takeURLStringValueFrom:)];
+  [[url_edit_view cell] setWraps:NO];
+  [[url_edit_view cell] setScrollable:YES];
+  url_edit_view_ = url_edit_view.get();
+
+  // show the window
+  [window_ makeKeyAndOrderFront:nil];
+}
+
+void Shell::PlatformSetContents() {
+  NSView* web_view = web_contents_->GetView()->GetNativeView();
+  [web_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+
+  if (headless_) {
+    SizeTo(content_width_, content_height_);
+    return;
+  }
+
+  NSView* content = [window_ contentView];
+  [content addSubview:web_view];
+
+  NSRect frame = [content bounds];
+  frame.size.height -= kURLBarHeight;
+  [web_view setFrame:frame];
+  [web_view setNeedsDisplay:YES];
+}
+
+void Shell::SizeTo(int width, int height) {
+  if (!headless_) {
+    NOTREACHED();
+    return;
+  }
+  NSView* web_view = web_contents_->GetView()->GetNativeView();
+  NSRect frame = NSMakeRect(0, 0, width, height);
+  [web_view setFrame:frame];
+}
+
+void Shell::PlatformResizeSubViews() {
+  // Not needed; subviews are bound.
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+  if (headless_)
+    return;
+
+  NSString* title_string = base::SysUTF16ToNSString(title);
+  [window_ setTitle:title_string];
+}
+
+void Shell::Close() {
+  if (headless_)
+    delete this;
+  else
+    [window_ performClose:nil];
+}
+
+void Shell::ActionPerformed(int control) {
+  switch (control) {
+    case IDC_NAV_BACK:
+      GoBackOrForward(-1);
+      break;
+    case IDC_NAV_FORWARD:
+      GoBackOrForward(1);
+      break;
+    case IDC_NAV_RELOAD:
+      Reload();
+      break;
+    case IDC_NAV_STOP:
+      Stop();
+      break;
+  }
+}
+
+void Shell::URLEntered(std::string url_string) {
+  if (!url_string.empty()) {
+    GURL url(url_string);
+    if (!url.has_scheme())
+      url = GURL("http://" + url_string);
+    LoadURL(url);
+  }
+}
+
+void Shell::HandleKeyboardEvent(WebContents* source,
+                                const NativeWebKeyboardEvent& event) {
+  if (event.skip_in_browser)
+    return;
+
+  // The event handling to get this strictly right is a tangle; cheat here a bit
+  // by just letting the menus have a chance at it.
+  if ([event.os_event type] == NSKeyDown) {
+    if (([event.os_event modifierFlags] & NSCommandKeyMask) &&
+        [[event.os_event characters] isEqual:@"l"]) {
+      [window_ makeFirstResponder:url_edit_view_];
+      return;
+    }
+
+    [[NSApp mainMenu] performKeyEquivalent:event.os_event];
+  }
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_message_filter.cc b/content/shell/browser/shell_message_filter.cc
new file mode 100644
index 0000000..c7c4cca
--- /dev/null
+++ b/content/shell/browser/shell_message_filter.cc
@@ -0,0 +1,105 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_message_filter.h"
+
+#include "base/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_network_delegate.h"
+#include "content/shell/common/shell_messages.h"
+#include "net/base/net_errors.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "webkit/browser/database/database_tracker.h"
+#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/browser/quota/quota_manager.h"
+
+namespace content {
+
+ShellMessageFilter::ShellMessageFilter(
+    int render_process_id,
+    webkit_database::DatabaseTracker* database_tracker,
+    quota::QuotaManager* quota_manager,
+    net::URLRequestContextGetter* request_context_getter)
+    : render_process_id_(render_process_id),
+      database_tracker_(database_tracker),
+      quota_manager_(quota_manager),
+      request_context_getter_(request_context_getter) {
+}
+
+ShellMessageFilter::~ShellMessageFilter() {
+}
+
+void ShellMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
+                                                  BrowserThread::ID* thread) {
+  if (message.type() == ShellViewHostMsg_ClearAllDatabases::ID)
+    *thread = BrowserThread::FILE;
+}
+
+bool ShellMessageFilter::OnMessageReceived(const IPC::Message& message,
+                                           bool* message_was_ok) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP_EX(ShellMessageFilter, message, *message_was_ok)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ReadFileToString, OnReadFileToString)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_RegisterIsolatedFileSystem,
+                        OnRegisterIsolatedFileSystem)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ClearAllDatabases, OnClearAllDatabases)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_SetDatabaseQuota, OnSetDatabaseQuota)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_AcceptAllCookies, OnAcceptAllCookies)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_DeleteAllCookies, OnDeleteAllCookies)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+
+  return handled;
+}
+
+void ShellMessageFilter::OnReadFileToString(const base::FilePath& local_file,
+                                            std::string* contents) {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  file_util::ReadFileToString(local_file, contents);
+}
+
+void ShellMessageFilter::OnRegisterIsolatedFileSystem(
+    const std::vector<base::FilePath>& absolute_filenames,
+    std::string* filesystem_id) {
+  fileapi::IsolatedContext::FileInfoSet files;
+  ChildProcessSecurityPolicy* policy =
+      ChildProcessSecurityPolicy::GetInstance();
+  for (size_t i = 0; i < absolute_filenames.size(); ++i) {
+    files.AddPath(absolute_filenames[i], NULL);
+    if (!policy->CanReadFile(render_process_id_, absolute_filenames[i]))
+      policy->GrantReadFile(render_process_id_, absolute_filenames[i]);
+  }
+  *filesystem_id =
+      fileapi::IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files);
+  policy->GrantReadFileSystem(render_process_id_, *filesystem_id);
+}
+
+void ShellMessageFilter::OnClearAllDatabases() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+  database_tracker_->DeleteDataModifiedSince(
+      base::Time(), net::CompletionCallback());
+}
+
+void ShellMessageFilter::OnSetDatabaseQuota(int quota) {
+  quota_manager_->SetTemporaryGlobalOverrideQuota(
+      quota * quota::QuotaManager::kPerHostTemporaryPortion,
+      quota::QuotaCallback());
+}
+
+void ShellMessageFilter::OnAcceptAllCookies(bool accept) {
+  ShellNetworkDelegate::SetAcceptAllCookies(accept);
+}
+
+void ShellMessageFilter::OnDeleteAllCookies() {
+  request_context_getter_->GetURLRequestContext()->cookie_store()
+      ->GetCookieMonster()
+      ->DeleteAllAsync(net::CookieMonster::DeleteCallback());
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_message_filter.h b/content/shell/browser/shell_message_filter.h
new file mode 100644
index 0000000..135a915
--- /dev/null
+++ b/content/shell/browser/shell_message_filter.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 CONTENT_SHELL_BROWSER_SHELL_MESSAGE_FILTER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_MESSAGE_FILTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "content/public/browser/browser_message_filter.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace quota {
+class QuotaManager;
+}
+
+namespace webkit_database {
+class DatabaseTracker;
+}
+
+namespace content {
+
+class ShellMessageFilter : public BrowserMessageFilter {
+ public:
+  ShellMessageFilter(int render_process_id,
+                     webkit_database::DatabaseTracker* database_tracker,
+                     quota::QuotaManager* quota_manager,
+                     net::URLRequestContextGetter* request_context_getter);
+
+ private:
+  virtual ~ShellMessageFilter();
+
+  // BrowserMessageFilter implementation.
+  virtual void OverrideThreadForMessage(const IPC::Message& message,
+                                        BrowserThread::ID* thread) OVERRIDE;
+  virtual bool OnMessageReceived(const IPC::Message& message,
+                                 bool* message_was_ok) OVERRIDE;
+
+  void OnReadFileToString(const base::FilePath& local_file,
+                          std::string* contents);
+  void OnRegisterIsolatedFileSystem(
+      const std::vector<base::FilePath>& absolute_filenames,
+      std::string* filesystem_id);
+  void OnClearAllDatabases();
+  void OnSetDatabaseQuota(int quota);
+  void OnAcceptAllCookies(bool accept);
+  void OnDeleteAllCookies();
+
+  int render_process_id_;
+
+  webkit_database::DatabaseTracker* database_tracker_;
+  quota::QuotaManager* quota_manager_;
+  net::URLRequestContextGetter* request_context_getter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellMessageFilter);
+};
+
+}  // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_MESSAGE_FILTER_H_
diff --git a/content/shell/browser/shell_net_log.cc b/content/shell/browser/shell_net_log.cc
new file mode 100644
index 0000000..97276d6
--- /dev/null
+++ b/content/shell/browser/shell_net_log.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 "content/shell/browser/shell_net_log.h"
+
+#include <stdio.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/values.h"
+#include "content/public/common/content_switches.h"
+#include "net/base/net_log_logger.h"
+
+namespace content {
+
+namespace {
+
+base::DictionaryValue* GetShellConstants() {
+  base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
+
+  // Add a dictionary with client information
+  base::DictionaryValue* dict = new DictionaryValue();
+
+  dict->SetString("name", "content_shell");
+  dict->SetString("command_line",
+                  CommandLine::ForCurrentProcess()->GetCommandLineString());
+
+  constants_dict->Set("clientInfo", dict);
+
+  return constants_dict;
+}
+
+}  // namespace
+
+ShellNetLog::ShellNetLog() {
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+  if (command_line->HasSwitch(switches::kLogNetLog)) {
+    base::FilePath log_path =
+        command_line->GetSwitchValuePath(switches::kLogNetLog);
+    // Much like logging.h, bypass threading restrictions by using fopen
+    // directly.  Have to write on a thread that's shutdown to handle events on
+    // shutdown properly, and posting events to another thread as they occur
+    // would result in an unbounded buffer size, so not much can be gained by
+    // doing this on another thread.  It's only used when debugging, so
+    // performance is not a big concern.
+    FILE* file = NULL;
+#if defined(OS_WIN)
+    file = _wfopen(log_path.value().c_str(), L"w");
+#elif defined(OS_POSIX)
+    file = fopen(log_path.value().c_str(), "w");
+#endif
+
+    if (file == NULL) {
+      LOG(ERROR) << "Could not open file " << log_path.value()
+                 << " for net logging";
+    } else {
+      scoped_ptr<base::Value> constants(GetShellConstants());
+      net_log_logger_.reset(new net::NetLogLogger(file, *constants));
+      net_log_logger_->StartObserving(this);
+    }
+  }
+}
+
+ShellNetLog::~ShellNetLog() {
+  // Remove the observer we own before we're destroyed.
+  if (net_log_logger_)
+    RemoveThreadSafeObserver(net_log_logger_.get());
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_net_log.h b/content/shell/browser/shell_net_log.h
new file mode 100644
index 0000000..9846917
--- /dev/null
+++ b/content/shell/browser/shell_net_log.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 CONTENT_SHELL_BROWSER_SHELL_NET_LOG_H_
+#define CONTENT_SHELL_BROWSER_SHELL_NET_LOG_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "net/base/net_log_logger.h"
+
+namespace content {
+
+class ShellNetLog : public net::NetLog {
+ public:
+  ShellNetLog();
+  virtual ~ShellNetLog();
+
+ private:
+  scoped_ptr<net::NetLogLogger> net_log_logger_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellNetLog);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_NET_LOG_H_
diff --git a/content/shell/browser/shell_network_delegate.cc b/content/shell/browser/shell_network_delegate.cc
new file mode 100644
index 0000000..560426f
--- /dev/null
+++ b/content/shell/browser/shell_network_delegate.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 "content/shell/browser/shell_network_delegate.h"
+
+#include "net/base/net_errors.h"
+#include "net/base/static_cookie_policy.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+namespace {
+bool g_accept_all_cookies = true;
+}
+
+ShellNetworkDelegate::ShellNetworkDelegate() {
+}
+
+ShellNetworkDelegate::~ShellNetworkDelegate() {
+}
+
+void ShellNetworkDelegate::SetAcceptAllCookies(bool accept) {
+  g_accept_all_cookies = accept;
+}
+
+int ShellNetworkDelegate::OnBeforeURLRequest(
+    net::URLRequest* request,
+    const net::CompletionCallback& callback,
+    GURL* new_url) {
+  return net::OK;
+}
+
+int ShellNetworkDelegate::OnBeforeSendHeaders(
+    net::URLRequest* request,
+    const net::CompletionCallback& callback,
+    net::HttpRequestHeaders* headers) {
+  return net::OK;
+}
+
+void ShellNetworkDelegate::OnSendHeaders(
+    net::URLRequest* request,
+    const net::HttpRequestHeaders& headers) {
+}
+
+int ShellNetworkDelegate::OnHeadersReceived(
+    net::URLRequest* request,
+    const net::CompletionCallback& callback,
+    const net::HttpResponseHeaders* original_response_headers,
+    scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
+  return net::OK;
+}
+
+void ShellNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
+                                            const GURL& new_location) {
+}
+
+void ShellNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
+}
+
+void ShellNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
+                                          int bytes_read) {
+}
+
+void ShellNetworkDelegate::OnCompleted(net::URLRequest* request, bool started) {
+}
+
+void ShellNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {
+}
+
+void ShellNetworkDelegate::OnPACScriptError(int line_number,
+                                            const string16& error) {
+}
+
+ShellNetworkDelegate::AuthRequiredResponse ShellNetworkDelegate::OnAuthRequired(
+    net::URLRequest* request,
+    const net::AuthChallengeInfo& auth_info,
+    const AuthCallback& callback,
+    net::AuthCredentials* credentials) {
+  return AUTH_REQUIRED_RESPONSE_NO_ACTION;
+}
+
+bool ShellNetworkDelegate::OnCanGetCookies(const net::URLRequest& request,
+                                           const net::CookieList& cookie_list) {
+  net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
+      net::StaticCookiePolicy::ALLOW_ALL_COOKIES :
+      net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
+  net::StaticCookiePolicy policy(policy_type);
+  int rv = policy.CanGetCookies(
+      request.url(), request.first_party_for_cookies());
+  return rv == net::OK;
+}
+
+bool ShellNetworkDelegate::OnCanSetCookie(const net::URLRequest& request,
+                                          const std::string& cookie_line,
+                                          net::CookieOptions* options) {
+  net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
+      net::StaticCookiePolicy::ALLOW_ALL_COOKIES :
+      net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
+  net::StaticCookiePolicy policy(policy_type);
+  int rv = policy.CanSetCookie(
+      request.url(), request.first_party_for_cookies());
+  return rv == net::OK;
+}
+
+bool ShellNetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
+                                           const base::FilePath& path) const {
+  return true;
+}
+
+bool ShellNetworkDelegate::OnCanThrottleRequest(
+    const net::URLRequest& request) const {
+  return false;
+}
+
+int ShellNetworkDelegate::OnBeforeSocketStreamConnect(
+    net::SocketStream* socket,
+    const net::CompletionCallback& callback) {
+  return net::OK;
+}
+
+void ShellNetworkDelegate::OnRequestWaitStateChange(
+    const net::URLRequest& request,
+    RequestWaitState waiting) {
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_network_delegate.h b/content/shell/browser/shell_network_delegate.h
new file mode 100644
index 0000000..a3ce0a2
--- /dev/null
+++ b/content/shell/browser/shell_network_delegate.h
@@ -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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "net/base/network_delegate.h"
+
+namespace content {
+
+class ShellNetworkDelegate : public net::NetworkDelegate {
+ public:
+  ShellNetworkDelegate();
+  virtual ~ShellNetworkDelegate();
+
+  static void SetAcceptAllCookies(bool accept);
+
+ private:
+  // net::NetworkDelegate implementation.
+  virtual int OnBeforeURLRequest(net::URLRequest* request,
+                                 const net::CompletionCallback& callback,
+                                 GURL* new_url) OVERRIDE;
+  virtual int OnBeforeSendHeaders(net::URLRequest* request,
+                                  const net::CompletionCallback& callback,
+                                  net::HttpRequestHeaders* headers) OVERRIDE;
+  virtual void OnSendHeaders(net::URLRequest* request,
+                             const net::HttpRequestHeaders& headers) OVERRIDE;
+  virtual int OnHeadersReceived(
+      net::URLRequest* request,
+      const net::CompletionCallback& callback,
+      const net::HttpResponseHeaders* original_response_headers,
+      scoped_refptr<net::HttpResponseHeaders>*
+          override_response_headers) OVERRIDE;
+  virtual void OnBeforeRedirect(net::URLRequest* request,
+                                const GURL& new_location) OVERRIDE;
+  virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
+  virtual void OnRawBytesRead(const net::URLRequest& request,
+                              int bytes_read) OVERRIDE;
+  virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE;
+  virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE;
+  virtual void OnPACScriptError(int line_number,
+                                const string16& error) OVERRIDE;
+  virtual AuthRequiredResponse OnAuthRequired(
+      net::URLRequest* request,
+      const net::AuthChallengeInfo& auth_info,
+      const AuthCallback& callback,
+      net::AuthCredentials* credentials) OVERRIDE;
+  virtual bool OnCanGetCookies(const net::URLRequest& request,
+                               const net::CookieList& cookie_list) OVERRIDE;
+  virtual bool OnCanSetCookie(const net::URLRequest& request,
+                              const std::string& cookie_line,
+                              net::CookieOptions* options) OVERRIDE;
+  virtual bool OnCanAccessFile(const net::URLRequest& request,
+                               const base::FilePath& path) const OVERRIDE;
+  virtual bool OnCanThrottleRequest(
+      const net::URLRequest& request) const OVERRIDE;
+  virtual int OnBeforeSocketStreamConnect(
+      net::SocketStream* stream,
+      const net::CompletionCallback& callback) OVERRIDE;
+  virtual void OnRequestWaitStateChange(const net::URLRequest& request,
+                                        RequestWaitState state) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_
diff --git a/content/shell/browser/shell_plugin_service_filter.cc b/content/shell/browser/shell_plugin_service_filter.cc
new file mode 100644
index 0000000..d41b9bd
--- /dev/null
+++ b/content/shell/browser/shell_plugin_service_filter.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 "content/shell/browser/shell_plugin_service_filter.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/webplugininfo.h"
+
+namespace content {
+
+ShellPluginServiceFilter::ShellPluginServiceFilter() {}
+
+ShellPluginServiceFilter::~ShellPluginServiceFilter() {}
+
+bool ShellPluginServiceFilter::IsPluginAvailable(
+    int render_process_id,
+    int render_view_id,
+    const void* context,
+    const GURL& url,
+    const GURL& policy_url,
+    WebPluginInfo* plugin) {
+  return plugin->name == ASCIIToUTF16("WebKit Test PlugIn");
+}
+
+bool ShellPluginServiceFilter::CanLoadPlugin(int render_process_id,
+                                             const base::FilePath& path) {
+  return true;
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_plugin_service_filter.h b/content/shell/browser/shell_plugin_service_filter.h
new file mode 100644
index 0000000..3e9cb5d
--- /dev/null
+++ b/content/shell/browser/shell_plugin_service_filter.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_SHELL_BROWSER_SHELL_PLUGIN_SERVICE_FILTER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_PLUGIN_SERVICE_FILTER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/public/browser/plugin_service_filter.h"
+
+namespace content {
+
+class ShellPluginServiceFilter : public PluginServiceFilter {
+ public:
+  ShellPluginServiceFilter();
+  virtual ~ShellPluginServiceFilter();
+
+  // PluginServiceFilter implementation.
+  virtual bool IsPluginAvailable(int render_process_id,
+                                 int render_view_id,
+                                 const void* context,
+                                 const GURL& url,
+                                 const GURL& policy_url,
+                                 WebPluginInfo* plugin) OVERRIDE;
+
+  virtual bool CanLoadPlugin(int render_process_id,
+                             const base::FilePath& path) OVERRIDE;
+
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(ShellPluginServiceFilter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_PLUGIN_SERVICE_FILTER_H_
diff --git a/content/shell/browser/shell_quota_permission_context.cc b/content/shell/browser/shell_quota_permission_context.cc
new file mode 100644
index 0000000..064322f
--- /dev/null
+++ b/content/shell/browser/shell_quota_permission_context.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 "content/shell/browser/shell_quota_permission_context.h"
+
+#include "webkit/common/quota/quota_types.h"
+
+namespace content {
+
+ShellQuotaPermissionContext::ShellQuotaPermissionContext() {}
+
+void ShellQuotaPermissionContext::RequestQuotaPermission(
+    const GURL& origin_url,
+    quota::StorageType type,
+    int64 requested_quota,
+    int render_process_id,
+    int render_view_id,
+    const PermissionCallback& callback) {
+  if (type != quota::kStorageTypePersistent) {
+    // For now we only support requesting quota with this interface
+    // for Persistent storage type.
+    callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
+    return;
+  }
+
+  callback.Run(QUOTA_PERMISSION_RESPONSE_ALLOW);
+}
+
+ShellQuotaPermissionContext::~ShellQuotaPermissionContext() {}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_quota_permission_context.h b/content/shell/browser/shell_quota_permission_context.h
new file mode 100644
index 0000000..381338d
--- /dev/null
+++ b/content/shell/browser/shell_quota_permission_context.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 CONTENT_SHELL_BROWSER_SHELL_QUOTA_PERMISSION_CONTEXT_H_
+#define CONTENT_SHELL_BROWSER_SHELL_QUOTA_PERMISSION_CONTEXT_H_
+
+#include "base/compiler_specific.h"
+#include "content/public/browser/quota_permission_context.h"
+
+namespace content {
+
+class ShellQuotaPermissionContext : public QuotaPermissionContext {
+ public:
+  ShellQuotaPermissionContext();
+
+  // The callback will be dispatched on the IO thread.
+  virtual void RequestQuotaPermission(
+      const GURL& origin_url,
+      quota::StorageType type,
+      int64 new_quota,
+      int render_process_id,
+      int render_view_id,
+      const PermissionCallback& callback) OVERRIDE;
+
+ private:
+  virtual ~ShellQuotaPermissionContext();
+
+  DISALLOW_COPY_AND_ASSIGN(ShellQuotaPermissionContext);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_QUOTA_PERMISSION_CONTEXT_H_
diff --git a/content/shell/browser/shell_resource_dispatcher_host_delegate.cc b/content/shell/browser/shell_resource_dispatcher_host_delegate.cc
new file mode 100644
index 0000000..d0994b1
--- /dev/null
+++ b/content/shell/browser/shell_resource_dispatcher_host_delegate.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 "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
+
+#include "base/command_line.h"
+#include "content/shell/browser/shell_login_dialog.h"
+#include "content/shell/common/shell_switches.h"
+
+namespace content {
+
+ShellResourceDispatcherHostDelegate::ShellResourceDispatcherHostDelegate() {
+}
+
+ShellResourceDispatcherHostDelegate::~ShellResourceDispatcherHostDelegate() {
+}
+
+bool ShellResourceDispatcherHostDelegate::AcceptAuthRequest(
+    net::URLRequest* request,
+    net::AuthChallengeInfo* auth_info) {
+  bool accept_auth_request =
+      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
+  return accept_auth_request;
+}
+
+ResourceDispatcherHostLoginDelegate*
+ShellResourceDispatcherHostDelegate::CreateLoginDelegate(
+    net::AuthChallengeInfo* auth_info, net::URLRequest* request) {
+  if (!login_request_callback_.is_null()) {
+    login_request_callback_.Run();
+    login_request_callback_.Reset();
+    return NULL;
+  }
+
+#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK)
+// TODO: implement ShellLoginDialog for other platforms, drop this #if
+  return NULL;
+#else
+  return new ShellLoginDialog(auth_info, request);
+#endif
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_resource_dispatcher_host_delegate.h b/content/shell/browser/shell_resource_dispatcher_host_delegate.h
new file mode 100644
index 0000000..90e6d4c
--- /dev/null
+++ b/content/shell/browser/shell_resource_dispatcher_host_delegate.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_SHELL_BROWSER_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+
+namespace content {
+
+class ShellResourceDispatcherHostDelegate
+    : public ResourceDispatcherHostDelegate {
+ public:
+  ShellResourceDispatcherHostDelegate();
+  virtual ~ShellResourceDispatcherHostDelegate();
+
+  // ResourceDispatcherHostDelegate implementation.
+  virtual bool AcceptAuthRequest(net::URLRequest* request,
+                                 net::AuthChallengeInfo* auth_info) OVERRIDE;
+  virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
+      net::AuthChallengeInfo* auth_info, net::URLRequest* request) OVERRIDE;
+
+  // Used for content_browsertests.
+  void set_login_request_callback(
+      base::Callback<void()> login_request_callback) {
+    login_request_callback_ = login_request_callback;
+  }
+
+ private:
+  base::Callback<void()> login_request_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellResourceDispatcherHostDelegate);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
diff --git a/content/shell/browser/shell_url_request_context_getter.cc b/content/shell/browser/shell_url_request_context_getter.cc
new file mode 100644
index 0000000..dfdb852
--- /dev/null
+++ b/content/shell/browser/shell_url_request_context_getter.cc
@@ -0,0 +1,231 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_url_request_context_getter.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/worker_pool.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell_network_delegate.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/cache_type.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/dns/host_resolver.h"
+#include "net/dns/mapped_host_resolver.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/http/transport_security_state.h"
+#include "net/proxy/proxy_service.h"
+#include "net/ssl/default_server_bound_cert_store.h"
+#include "net/ssl/server_bound_cert_service.h"
+#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/url_request/data_protocol_handler.h"
+#include "net/url_request/file_protocol_handler.h"
+#include "net/url_request/protocol_intercept_job_factory.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_context_storage.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+
+namespace content {
+
+namespace {
+
+void InstallProtocolHandlers(net::URLRequestJobFactoryImpl* job_factory,
+                             ProtocolHandlerMap* protocol_handlers) {
+  for (ProtocolHandlerMap::iterator it =
+           protocol_handlers->begin();
+       it != protocol_handlers->end();
+       ++it) {
+    bool set_protocol = job_factory->SetProtocolHandler(
+        it->first, it->second.release());
+    DCHECK(set_protocol);
+  }
+  protocol_handlers->clear();
+}
+
+}  // namespace
+
+ShellURLRequestContextGetter::ShellURLRequestContextGetter(
+    bool ignore_certificate_errors,
+    const base::FilePath& base_path,
+    base::MessageLoop* io_loop,
+    base::MessageLoop* file_loop,
+    ProtocolHandlerMap* protocol_handlers,
+    net::NetLog* net_log)
+    : ignore_certificate_errors_(ignore_certificate_errors),
+      base_path_(base_path),
+      io_loop_(io_loop),
+      file_loop_(file_loop),
+      net_log_(net_log) {
+  // Must first be created on the UI thread.
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  std::swap(protocol_handlers_, *protocol_handlers);
+
+  // We must create the proxy config service on the UI loop on Linux because it
+  // must synchronously run on the glib message loop. This will be passed to
+  // the URLRequestContextStorage on the IO thread in GetURLRequestContext().
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+    proxy_config_service_.reset(
+        net::ProxyService::CreateSystemProxyConfigService(
+            io_loop_->message_loop_proxy().get(), file_loop_));
+  }
+}
+
+ShellURLRequestContextGetter::~ShellURLRequestContextGetter() {
+}
+
+net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+  if (!url_request_context_) {
+    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+    url_request_context_.reset(new net::URLRequestContext());
+    url_request_context_->set_net_log(net_log_);
+    network_delegate_.reset(new ShellNetworkDelegate);
+    if (command_line.HasSwitch(switches::kDumpRenderTree))
+      ShellNetworkDelegate::SetAcceptAllCookies(false);
+    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_server_bound_cert_service(new net::ServerBoundCertService(
+        new net::DefaultServerBoundCertStore(NULL),
+        base::WorkerPool::GetTaskRunner(true)));
+    storage_->set_http_user_agent_settings(
+        new net::StaticHttpUserAgentSettings("en-us,en", EmptyString()));
+
+    scoped_ptr<net::HostResolver> host_resolver(
+        net::HostResolver::CreateDefaultResolver(
+            url_request_context_->net_log()));
+
+    storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
+    storage_->set_transport_security_state(new net::TransportSecurityState);
+    if (command_line.HasSwitch(switches::kDumpRenderTree)) {
+      storage_->set_proxy_service(net::ProxyService::CreateDirect());
+    } else {
+      // TODO(jam): use v8 if possible, look at chrome code.
+      storage_->set_proxy_service(
+          net::ProxyService::CreateUsingSystemProxyResolver(
+          proxy_config_service_.release(),
+          0,
+          url_request_context_->net_log()));
+    }
+    storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
+    storage_->set_http_auth_handler_factory(
+        net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
+    storage_->set_http_server_properties(
+        scoped_ptr<net::HttpServerProperties>(
+            new net::HttpServerPropertiesImpl()));
+
+    base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
+    net::HttpCache::DefaultBackend* main_backend =
+        new net::HttpCache::DefaultBackend(
+            net::DISK_CACHE,
+#if defined(OS_ANDROID)
+            // TODO(rdsmith): Remove when default backend for Android is
+            // changed to simple cache.
+            net::CACHE_BACKEND_SIMPLE,
+#else
+            net::CACHE_BACKEND_DEFAULT,
+#endif
+            cache_path,
+            0,
+            BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)
+                .get());
+
+    net::HttpNetworkSession::Params network_session_params;
+    network_session_params.cert_verifier =
+        url_request_context_->cert_verifier();
+    network_session_params.transport_security_state =
+        url_request_context_->transport_security_state();
+    network_session_params.server_bound_cert_service =
+        url_request_context_->server_bound_cert_service();
+    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_auth_handler_factory =
+        url_request_context_->http_auth_handler_factory();
+    network_session_params.network_delegate =
+        network_delegate_.get();
+    network_session_params.http_server_properties =
+        url_request_context_->http_server_properties();
+    network_session_params.net_log =
+        url_request_context_->net_log();
+    network_session_params.ignore_certificate_errors =
+        ignore_certificate_errors_;
+    if (command_line.HasSwitch(switches::kTestingFixedHttpPort)) {
+      int value;
+      base::StringToInt(command_line.GetSwitchValueASCII(
+          switches::kTestingFixedHttpPort), &value);
+      network_session_params.testing_fixed_http_port = value;
+    }
+    if (command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
+      int value;
+      base::StringToInt(command_line.GetSwitchValueASCII(
+          switches::kTestingFixedHttpsPort), &value);
+      network_session_params.testing_fixed_https_port = value;
+    }
+    if (command_line.HasSwitch(switches::kHostResolverRules)) {
+      scoped_ptr<net::MappedHostResolver> mapped_host_resolver(
+          new net::MappedHostResolver(host_resolver.Pass()));
+      mapped_host_resolver->SetRulesFromString(
+          command_line.GetSwitchValueASCII(switches::kHostResolverRules));
+      host_resolver = mapped_host_resolver.Pass();
+    }
+
+    // Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
+    storage_->set_host_resolver(host_resolver.Pass());
+    network_session_params.host_resolver =
+        url_request_context_->host_resolver();
+
+    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());
+    // Keep ProtocolHandlers added in sync with
+    // ShellContentBrowserClient::IsHandledURL().
+    InstallProtocolHandlers(job_factory.get(), &protocol_handlers_);
+    bool set_protocol = job_factory->SetProtocolHandler(
+        chrome::kDataScheme,
+        new net::DataProtocolHandler);
+    DCHECK(set_protocol);
+    set_protocol = job_factory->SetProtocolHandler(
+        chrome::kFileScheme,
+        new net::FileProtocolHandler(
+            content::BrowserThread::GetBlockingPool()->
+                GetTaskRunnerWithShutdownBehavior(
+                    base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
+    DCHECK(set_protocol);
+    storage_->set_job_factory(job_factory.release());
+  }
+
+  return url_request_context_.get();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+    ShellURLRequestContextGetter::GetNetworkTaskRunner() const {
+  return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+}
+
+net::HostResolver* ShellURLRequestContextGetter::host_resolver() {
+  return url_request_context_->host_resolver();
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_url_request_context_getter.h b/content/shell/browser/shell_url_request_context_getter.h
new file mode 100644
index 0000000..b18c0a9
--- /dev/null
+++ b/content/shell/browser/shell_url_request_context_getter.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 CONTENT_SHELL_BROWSER_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/content_browser_client.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_job_factory.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace net {
+class HostResolver;
+class MappedHostResolver;
+class NetworkDelegate;
+class NetLog;
+class ProxyConfigService;
+class URLRequestContextStorage;
+}
+
+namespace content {
+
+class ShellURLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+  ShellURLRequestContextGetter(
+      bool ignore_certificate_errors,
+      const base::FilePath& base_path,
+      base::MessageLoop* io_loop,
+      base::MessageLoop* file_loop,
+      ProtocolHandlerMap* protocol_handlers,
+      net::NetLog* net_log);
+
+  // net::URLRequestContextGetter implementation.
+  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
+  virtual scoped_refptr<base::SingleThreadTaskRunner>
+      GetNetworkTaskRunner() const OVERRIDE;
+
+  net::HostResolver* host_resolver();
+
+ protected:
+  virtual ~ShellURLRequestContextGetter();
+
+ private:
+  bool ignore_certificate_errors_;
+  base::FilePath base_path_;
+  base::MessageLoop* io_loop_;
+  base::MessageLoop* file_loop_;
+  net::NetLog* net_log_;
+
+  scoped_ptr<net::ProxyConfigService> proxy_config_service_;
+  scoped_ptr<net::NetworkDelegate> network_delegate_;
+  scoped_ptr<net::URLRequestContextStorage> storage_;
+  scoped_ptr<net::URLRequestContext> url_request_context_;
+  ProtocolHandlerMap protocol_handlers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ShellURLRequestContextGetter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/content/shell/browser/shell_web_contents_view_delegate.h b/content/shell/browser/shell_web_contents_view_delegate.h
new file mode 100644
index 0000000..86d97b4
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate.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 CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
+
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view_delegate.h"
+#include "content/public/common/context_menu_params.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/base/gtk/gtk_signal.h"
+#include "ui/base/gtk/owned_widget_gtk.h"
+#endif
+
+namespace content {
+
+class ShellWebContentsViewDelegate : public WebContentsViewDelegate {
+ public:
+  explicit ShellWebContentsViewDelegate(WebContents* web_contents);
+  virtual ~ShellWebContentsViewDelegate();
+
+  // Overridden from WebContentsViewDelegate:
+  virtual void ShowContextMenu(const ContextMenuParams& params) OVERRIDE;
+  virtual WebDragDestDelegate* GetDragDestDelegate() OVERRIDE;
+
+#if defined(TOOLKIT_GTK)
+  virtual void Initialize(GtkWidget* expanded_container,
+                          ui::FocusStoreGtk* focus_store) OVERRIDE;
+  virtual gfx::NativeView GetNativeView() const OVERRIDE;
+  virtual void Focus() OVERRIDE;
+  virtual gboolean OnNativeViewFocusEvent(GtkWidget* widget,
+                                          GtkDirectionType type,
+                                          gboolean* return_value) OVERRIDE;
+#elif defined(OS_MACOSX)
+  virtual NSObject<RenderWidgetHostViewMacDelegate>*
+      CreateRenderWidgetHostViewDelegate(
+          RenderWidgetHost* render_widget_host) OVERRIDE;
+  void ActionPerformed(int id);
+#elif defined(OS_WIN)
+  virtual void StoreFocus() OVERRIDE;
+  virtual void RestoreFocus() OVERRIDE;
+  virtual bool Focus() OVERRIDE;
+  virtual void TakeFocus(bool reverse) OVERRIDE;
+  virtual void SizeChanged(const gfx::Size& size) OVERRIDE;
+  void MenuItemSelected(int selection);
+#endif
+
+ private:
+  WebContents* web_contents_;
+  ContextMenuParams params_;
+
+#if defined(TOOLKIT_GTK)
+  ui::OwnedWidgetGtk floating_;
+  GtkWidget* expanded_container_;
+
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnBackMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnForwardMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnReloadMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnOpenURLMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnCutMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnCopyMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnPasteMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnDeleteMenuActivated);
+  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+                       OnInspectMenuActivated);
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ShellWebContentsViewDelegate);
+};
+
+}  // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
diff --git a/content/shell/browser/shell_web_contents_view_delegate_android.cc b/content/shell/browser/shell_web_contents_view_delegate_android.cc
new file mode 100644
index 0000000..3da5475
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_android.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/shell/browser/shell_web_contents_view_delegate.h"
+
+#include "base/command_line.h"
+#include "content/public/browser/android/content_view_core.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+    WebContents* web_contents) {
+  return new ShellWebContentsViewDelegate(web_contents);
+}
+
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+    WebContents* web_contents)
+    : web_contents_(web_contents) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+    const ContextMenuParams& params) {
+  if (params.is_editable && params.selection_text.empty()) {
+    content::ContentViewCore* content_view_core =
+        ContentViewCore::FromWebContents(web_contents_);
+    if (content_view_core) {
+      content_view_core->ShowPastePopup(params.selection_start.x(),
+                                        params.selection_start.y());
+    }
+  }
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+  return NULL;
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_web_contents_view_delegate_creator.h b/content/shell/browser/shell_web_contents_view_delegate_creator.h
new file mode 100644
index 0000000..819ce1e
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_creator.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 CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
+#define CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
+
+namespace content {
+
+class WebContents;
+class WebContentsViewDelegate;
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+    WebContents* web_contents);
+
+}  // namespace content
+
+#endif //CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
diff --git a/content/shell/browser/shell_web_contents_view_delegate_gtk.cc b/content/shell/browser/shell_web_contents_view_delegate_gtk.cc
new file mode 100644
index 0000000..4c98257
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_gtk.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 "content/shell/browser/shell_web_contents_view_delegate.h"
+
+#include "base/command_line.h"
+#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/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_main_parts.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_devtools_frontend.h"
+#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
+#include "content/shell/common/shell_switches.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+#include "ui/base/gtk/focus_store_gtk.h"
+#include "ui/base/gtk/gtk_floating_container.h"
+
+using WebKit::WebContextMenuData;
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+    WebContents* web_contents) {
+  return new ShellWebContentsViewDelegate(web_contents);
+}
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+    WebContents* web_contents)
+    : web_contents_(web_contents),
+      floating_(gtk_floating_container_new()) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+  floating_.Destroy();
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+    const ContextMenuParams& params) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+
+  GtkWidget* menu = gtk_menu_new();
+
+  params_ = params;
+  bool has_link = !params_.unfiltered_link_url.is_empty();
+  bool has_selection = !params_.selection_text.empty();
+
+  if (params_.media_type == WebContextMenuData::MediaTypeNone &&
+      !has_link &&
+      !has_selection &&
+      !params_.is_editable) {
+    GtkWidget* back_menu = gtk_menu_item_new_with_label("Back");
+    gtk_menu_append(GTK_MENU(menu), back_menu);
+    g_signal_connect(back_menu,
+                     "activate",
+                     G_CALLBACK(OnBackMenuActivatedThunk),
+                     this);
+    gtk_widget_set_sensitive(back_menu,
+                             web_contents_->GetController().CanGoBack());
+
+    GtkWidget* forward_menu = gtk_menu_item_new_with_label("Forward");
+    gtk_menu_append(GTK_MENU(menu), forward_menu);
+    g_signal_connect(forward_menu,
+                     "activate",
+                     G_CALLBACK(OnForwardMenuActivatedThunk),
+                     this);
+    gtk_widget_set_sensitive(forward_menu,
+                             web_contents_->GetController().CanGoForward());
+
+    GtkWidget* reload_menu = gtk_menu_item_new_with_label("Reload");
+    gtk_menu_append(GTK_MENU(menu), reload_menu);
+    g_signal_connect(reload_menu,
+                     "activate",
+                     G_CALLBACK(OnReloadMenuActivatedThunk),
+                     this);
+
+    GtkWidget* navigate_separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(menu), navigate_separator);
+  }
+
+  if (has_link) {
+    GtkWidget* open_menu = gtk_menu_item_new_with_label("Open in New Window");
+    gtk_menu_append(GTK_MENU(menu), open_menu);
+    g_signal_connect(open_menu,
+                     "activate",
+                     G_CALLBACK(OnOpenURLMenuActivatedThunk),
+                     this);
+
+    GtkWidget* link_separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(menu), link_separator);
+  }
+
+  if (params_.is_editable) {
+    GtkWidget* cut_menu = gtk_menu_item_new_with_label("Cut");
+    gtk_menu_append(GTK_MENU(menu), cut_menu);
+    g_signal_connect(cut_menu,
+                     "activate",
+                     G_CALLBACK(OnCutMenuActivatedThunk),
+                     this);
+    gtk_widget_set_sensitive(
+        cut_menu,
+        params_.edit_flags & WebContextMenuData::CanCut);
+
+    GtkWidget* copy_menu = gtk_menu_item_new_with_label("Copy");
+    gtk_menu_append(GTK_MENU(menu), copy_menu);
+    g_signal_connect(copy_menu,
+                     "activate",
+                     G_CALLBACK(OnCopyMenuActivatedThunk),
+                     this);
+    gtk_widget_set_sensitive(
+        copy_menu,
+        params_.edit_flags & WebContextMenuData::CanCopy);
+
+    GtkWidget* paste_menu = gtk_menu_item_new_with_label("Paste");
+    gtk_menu_append(GTK_MENU(menu), paste_menu);
+    g_signal_connect(paste_menu,
+                     "activate",
+                     G_CALLBACK(OnPasteMenuActivatedThunk),
+                     this);
+    gtk_widget_set_sensitive(
+        paste_menu,
+        params_.edit_flags & WebContextMenuData::CanPaste);
+
+    GtkWidget* delete_menu = gtk_menu_item_new_with_label("Delete");
+    gtk_menu_append(GTK_MENU(menu), delete_menu);
+    g_signal_connect(delete_menu,
+                     "activate",
+                     G_CALLBACK(OnDeleteMenuActivatedThunk),
+                     this);
+    gtk_widget_set_sensitive(
+        delete_menu,
+        params_.edit_flags & WebContextMenuData::CanDelete);
+
+    GtkWidget* edit_separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(menu), edit_separator);
+  } else if (has_selection) {
+    GtkWidget* copy_menu = gtk_menu_item_new_with_label("Copy");
+    gtk_menu_append(GTK_MENU(menu), copy_menu);
+    g_signal_connect(copy_menu,
+                     "activate",
+                     G_CALLBACK(OnCopyMenuActivatedThunk),
+                     this);
+
+    GtkWidget* copy_separator = gtk_separator_menu_item_new();
+    gtk_menu_append(GTK_MENU(menu), copy_separator);
+  }
+
+  GtkWidget* inspect_menu = gtk_menu_item_new_with_label("Inspect...");
+  gtk_menu_append(GTK_MENU(menu), inspect_menu);
+  g_signal_connect(inspect_menu,
+                   "activate",
+                   G_CALLBACK(OnInspectMenuActivatedThunk),
+                   this);
+
+  gtk_widget_show_all(menu);
+
+  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, GDK_CURRENT_TIME);
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+  return NULL;
+}
+
+void ShellWebContentsViewDelegate::Initialize(GtkWidget* expanded_container,
+                                              ui::FocusStoreGtk* focus_store) {
+  expanded_container_ = expanded_container;
+
+  gtk_container_add(GTK_CONTAINER(floating_.get()), expanded_container_);
+  gtk_widget_show(floating_.get());
+}
+
+gfx::NativeView ShellWebContentsViewDelegate::GetNativeView() const {
+  return floating_.get();
+}
+
+void ShellWebContentsViewDelegate::Focus() {
+  GtkWidget* widget = web_contents_->GetView()->GetContentNativeView();
+  if (widget)
+    gtk_widget_grab_focus(widget);
+}
+
+gboolean ShellWebContentsViewDelegate::OnNativeViewFocusEvent(
+    GtkWidget* widget,
+    GtkDirectionType type,
+    gboolean* return_value) {
+  return false;
+}
+
+void ShellWebContentsViewDelegate::OnBackMenuActivated(GtkWidget* widget) {
+  web_contents_->GetController().GoToOffset(-1);
+  web_contents_->GetView()->Focus();
+}
+
+void ShellWebContentsViewDelegate::OnForwardMenuActivated(GtkWidget* widget) {
+  web_contents_->GetController().GoToOffset(1);
+  web_contents_->GetView()->Focus();
+}
+
+void ShellWebContentsViewDelegate::OnReloadMenuActivated(GtkWidget* widget) {
+  web_contents_->GetController().Reload(false);
+  web_contents_->GetView()->Focus();
+}
+
+void ShellWebContentsViewDelegate::OnOpenURLMenuActivated(GtkWidget* widget) {
+  ShellBrowserContext* browser_context =
+      ShellContentBrowserClient::Get()->browser_context();
+  Shell::CreateNewWindow(browser_context,
+                         params_.link_url,
+                         NULL,
+                         MSG_ROUTING_NONE,
+                         gfx::Size());
+}
+
+void ShellWebContentsViewDelegate::OnCutMenuActivated(GtkWidget* widget) {
+  web_contents_->GetRenderViewHost()->Cut();
+}
+
+void ShellWebContentsViewDelegate::OnCopyMenuActivated(GtkWidget* widget) {
+  web_contents_->GetRenderViewHost()->Copy();
+}
+
+void ShellWebContentsViewDelegate::OnPasteMenuActivated(GtkWidget* widget) {
+  web_contents_->GetRenderViewHost()->Paste();
+}
+
+void ShellWebContentsViewDelegate::OnDeleteMenuActivated(GtkWidget* widget) {
+  web_contents_->GetRenderViewHost()->Delete();
+}
+
+void ShellWebContentsViewDelegate::OnInspectMenuActivated(GtkWidget* widget) {
+  ShellDevToolsFrontend::Show(web_contents_);
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_web_contents_view_delegate_mac.mm b/content/shell/browser/shell_web_contents_view_delegate_mac.mm
new file mode 100644
index 0000000..00196af
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_mac.mm
@@ -0,0 +1,277 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_web_contents_view_delegate.h"
+
+#import  <Cocoa/Cocoa.h>
+
+#include "base/command_line.h"
+#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/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_main_parts.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_devtools_frontend.h"
+#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
+#include "content/shell/common/shell_switches.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+
+using WebKit::WebContextMenuData;
+
+enum {
+  ShellContextMenuItemCutTag = 0,
+  ShellContextMenuItemCopyTag,
+  ShellContextMenuItemPasteTag,
+  ShellContextMenuItemDeleteTag,
+  ShellContextMenuItemOpenLinkTag,
+  ShellContextMenuItemBackTag,
+  ShellContextMenuItemForwardTag,
+  ShellContextMenuItemReloadTag,
+  ShellContextMenuItemInspectTag
+};
+
+@interface ShellContextMenuDelegate : NSObject<NSMenuDelegate> {
+ @private
+  content::ShellWebContentsViewDelegate* delegate_;
+}
+@end
+
+@implementation ShellContextMenuDelegate
+- (id)initWithDelegate:(content::ShellWebContentsViewDelegate*) delegate {
+  if ((self = [super init])) {
+    delegate_ = delegate;
+  }
+  return self;
+}
+
+- (void)itemSelected:(id)sender {
+  NSInteger tag = [sender tag];
+  delegate_->ActionPerformed(tag);
+}
+@end
+
+namespace {
+
+NSMenuItem* MakeContextMenuItem(NSString* title,
+                                NSInteger tag,
+                                NSMenu* menu,
+                                BOOL enabled,
+                                ShellContextMenuDelegate* delegate) {
+  NSMenuItem* menu_item =
+      [[NSMenuItem alloc] initWithTitle:title
+                                 action:@selector(itemSelected:)
+                          keyEquivalent:@""];
+  [menu_item setTarget:delegate];
+  [menu_item setTag:tag];
+  [menu_item setEnabled:enabled];
+  [menu addItem:menu_item];
+
+  return menu_item;
+}
+
+}  // namespace
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+  WebContents* web_contents) {
+  return new ShellWebContentsViewDelegate(web_contents);
+}
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+    WebContents* web_contents)
+    : web_contents_(web_contents) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+    const ContextMenuParams& params) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+
+  params_ = params;
+  bool has_link = !params_.unfiltered_link_url.is_empty();
+  bool has_selection = ! params_.selection_text.empty();
+
+  NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+  ShellContextMenuDelegate* delegate =
+      [[ShellContextMenuDelegate alloc] initWithDelegate:this];
+  [menu setDelegate:delegate];
+  [menu setAutoenablesItems:NO];
+
+  if (params.media_type == WebContextMenuData::MediaTypeNone &&
+      !has_link &&
+      !has_selection &&
+      !params_.is_editable) {
+    BOOL back_menu_enabled =
+        web_contents_->GetController().CanGoBack() ? YES : NO;
+    MakeContextMenuItem(@"Back",
+                        ShellContextMenuItemBackTag,
+                        menu,
+                        back_menu_enabled,
+                        delegate);
+
+    BOOL forward_menu_enabled =
+        web_contents_->GetController().CanGoForward() ? YES : NO;
+    MakeContextMenuItem(@"Forward",
+                        ShellContextMenuItemForwardTag,
+                        menu,
+                        forward_menu_enabled,
+                        delegate);
+
+    MakeContextMenuItem(@"Reload",
+                        ShellContextMenuItemReloadTag,
+                        menu,
+                        YES,
+                        delegate);
+
+    NSMenuItem* separator = [NSMenuItem separatorItem];
+    [menu addItem:separator];
+  }
+
+  if (has_link) {
+    MakeContextMenuItem(@"Open In New Window",
+                        ShellContextMenuItemOpenLinkTag,
+                        menu,
+                        YES,
+                        delegate);
+
+    NSMenuItem* separator = [NSMenuItem separatorItem];
+    [menu addItem:separator];
+  }
+
+  if (params_.is_editable) {
+    BOOL cut_menu_enabled =
+        (params_.edit_flags & WebContextMenuData::CanCut) ? YES : NO;
+    MakeContextMenuItem(@"Cut",
+                        ShellContextMenuItemCutTag,
+                        menu,
+                        cut_menu_enabled,
+                        delegate);
+
+    BOOL copy_menu_enabled =
+        (params_.edit_flags & WebContextMenuData::CanCopy) ? YES : NO;
+    MakeContextMenuItem(@"Copy",
+                        ShellContextMenuItemCopyTag,
+                        menu,
+                        copy_menu_enabled,
+                        delegate);
+
+    BOOL paste_menu_enabled =
+        (params_.edit_flags & WebContextMenuData::CanPaste) ? YES : NO;
+    MakeContextMenuItem(@"Paste",
+                        ShellContextMenuItemPasteTag,
+                        menu,
+                        paste_menu_enabled,
+                        delegate);
+
+    BOOL delete_menu_enabled =
+        (params_.edit_flags & WebContextMenuData::CanDelete) ? YES : NO;
+    MakeContextMenuItem(@"Delete",
+                        ShellContextMenuItemDeleteTag,
+                        menu,
+                        delete_menu_enabled,
+                        delegate);
+
+    NSMenuItem* separator = [NSMenuItem separatorItem];
+    [menu addItem:separator];
+  } else if (has_selection) {
+    MakeContextMenuItem(@"Copy",
+                        ShellContextMenuItemCopyTag,
+                        menu,
+                        YES,
+                        delegate);
+
+    NSMenuItem* separator = [NSMenuItem separatorItem];
+    [menu addItem:separator];
+  }
+
+  MakeContextMenuItem(@"Inspect",
+                      ShellContextMenuItemInspectTag,
+                      menu,
+                      YES,
+                      delegate);
+
+  NSView* parent_view = web_contents_->GetView()->GetContentNativeView();
+  NSEvent* currentEvent = [NSApp currentEvent];
+  NSWindow* window = [parent_view window];
+  NSPoint position = [window mouseLocationOutsideOfEventStream];
+  NSTimeInterval eventTime = [currentEvent timestamp];
+  NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
+                                           location:position
+                                      modifierFlags:NSRightMouseDownMask
+                                          timestamp:eventTime
+                                       windowNumber:[window windowNumber]
+                                            context:nil
+                                        eventNumber:0
+                                         clickCount:1
+                                           pressure:1.0];
+
+  [NSMenu popUpContextMenu:menu
+                 withEvent:clickEvent
+                   forView:parent_view];
+}
+
+void ShellWebContentsViewDelegate::ActionPerformed(int tag) {
+  switch (tag) {
+    case ShellContextMenuItemCutTag:
+      web_contents_->GetRenderViewHost()->Cut();
+      break;
+    case ShellContextMenuItemCopyTag:
+      web_contents_->GetRenderViewHost()->Copy();
+      break;
+    case ShellContextMenuItemPasteTag:
+      web_contents_->GetRenderViewHost()->Paste();
+      break;
+    case ShellContextMenuItemDeleteTag:
+      web_contents_->GetRenderViewHost()->Delete();
+      break;
+    case ShellContextMenuItemOpenLinkTag: {
+      ShellBrowserContext* browser_context =
+          ShellContentBrowserClient::Get()->browser_context();
+      Shell::CreateNewWindow(browser_context,
+                             params_.link_url,
+                             NULL,
+                             MSG_ROUTING_NONE,
+                             gfx::Size());
+      break;
+    }
+    case ShellContextMenuItemBackTag:
+      web_contents_->GetController().GoToOffset(-1);
+      web_contents_->GetView()->Focus();
+      break;
+    case ShellContextMenuItemForwardTag:
+      web_contents_->GetController().GoToOffset(1);
+      web_contents_->GetView()->Focus();
+      break;
+    case ShellContextMenuItemReloadTag: {
+      web_contents_->GetController().Reload(false);
+      web_contents_->GetView()->Focus();
+      break;
+    }
+    case ShellContextMenuItemInspectTag: {
+      ShellDevToolsFrontend::Show(web_contents_);
+      break;
+    }
+  }
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+  return NULL;
+}
+
+NSObject<RenderWidgetHostViewMacDelegate>*
+ShellWebContentsViewDelegate::CreateRenderWidgetHostViewDelegate(
+    content::RenderWidgetHost* render_widget_host) {
+  return NULL;
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_web_contents_view_delegate_win.cc b/content/shell/browser/shell_web_contents_view_delegate_win.cc
new file mode 100644
index 0000000..cd387f0
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_win.cc
@@ -0,0 +1,254 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell_web_contents_view_delegate.h"
+
+#include "base/command_line.h"
+#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/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_main_parts.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_devtools_frontend.h"
+#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
+#include "content/shell/common/shell_switches.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+
+using WebKit::WebContextMenuData;
+
+namespace {
+
+enum {
+  ShellContextMenuItemCutId = 10001,
+  ShellContextMenuItemCopyId,
+  ShellContextMenuItemPasteId,
+  ShellContextMenuItemDeleteId,
+  ShellContextMenuItemOpenLinkId,
+  ShellContextMenuItemBackId,
+  ShellContextMenuItemForwardId,
+  ShellContextMenuItemReloadId,
+  ShellContextMenuItemInspectId
+};
+
+void MakeContextMenuItem(HMENU menu,
+                         int menu_index,
+                         LPTSTR text,
+                         UINT id,
+                         bool enabled) {
+  MENUITEMINFO mii = {0};
+  mii.cbSize = sizeof(mii);
+  mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA | MIIM_STRING | MIIM_STATE;
+  mii.fState = enabled ? MFS_ENABLED : (MF_DISABLED | MFS_GRAYED);
+  mii.fType = MFT_STRING;
+  mii.wID = id;
+  mii.dwTypeData = text;
+
+  InsertMenuItem(menu, menu_index, TRUE, &mii);
+}
+
+}  // namespace
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+    WebContents* web_contents) {
+  return new ShellWebContentsViewDelegate(web_contents);
+}
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+    WebContents* web_contents)
+    : web_contents_(web_contents) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+    const ContextMenuParams& params) {
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+    return;
+
+  params_ = params;
+  bool has_link = !params_.unfiltered_link_url.is_empty();
+  bool has_selection = !params_.selection_text.empty();
+
+  HMENU menu = CreateMenu();
+  HMENU sub_menu = CreatePopupMenu();
+  AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)sub_menu, L"");
+
+  int index = 0;
+  if (params_.media_type == WebContextMenuData::MediaTypeNone &&
+      !has_link &&
+      !has_selection &&
+      !params_.is_editable) {
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Back",
+                        ShellContextMenuItemBackId,
+                        web_contents_->GetController().CanGoBack());
+
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Forward",
+                        ShellContextMenuItemForwardId,
+                        web_contents_->GetController().CanGoForward());
+
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Reload",
+                        ShellContextMenuItemReloadId,
+                        true);
+
+    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+    index++;
+  }
+
+  if (has_link) {
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Open in New Window",
+                        ShellContextMenuItemOpenLinkId,
+                        true);
+    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+    index++;
+  }
+
+  if (params_.is_editable) {
+    bool cut_enabled = ((params_.edit_flags & WebContextMenuData::CanCut) != 0);
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Cut",
+                        ShellContextMenuItemCutId,
+                        cut_enabled);
+
+    bool copy_enabled =
+        ((params_.edit_flags & WebContextMenuData::CanCopy) != 0);
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Copy",
+                        ShellContextMenuItemCopyId,
+                        copy_enabled);
+
+    bool paste_enabled =
+        ((params_.edit_flags & WebContextMenuData::CanPaste) != 0);
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Paste",
+                        ShellContextMenuItemPasteId,
+                        paste_enabled);
+    bool delete_enabled =
+        ((params_.edit_flags & WebContextMenuData::CanDelete) != 0);
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Delete",
+                        ShellContextMenuItemDeleteId,
+                        delete_enabled);
+
+    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+    index++;
+  } else if (has_selection) {
+    MakeContextMenuItem(sub_menu,
+                        index++,
+                        L"Copy",
+                        ShellContextMenuItemCopyId,
+                        true);
+
+    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+    index++;
+  }
+
+  MakeContextMenuItem(sub_menu,
+                      index++,
+                      L"Inspect...",
+                      ShellContextMenuItemInspectId,
+                      true);
+#if defined(USE_AURA)
+  NOTIMPLEMENTED();
+#else
+  gfx::Point screen_point(params.x, params.y);
+  POINT point = screen_point.ToPOINT();
+  ClientToScreen(web_contents_->GetView()->GetNativeView(), &point);
+
+  int selection =
+      TrackPopupMenu(sub_menu,
+                     TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
+                     point.x, point.y,
+                     0,
+                     web_contents_->GetView()->GetContentNativeView(),
+                     NULL);
+
+  MenuItemSelected(selection);
+#endif
+  DestroyMenu(menu);
+}
+
+void ShellWebContentsViewDelegate::MenuItemSelected(int selection) {
+  switch (selection) {
+    case ShellContextMenuItemCutId:
+      web_contents_->GetRenderViewHost()->Cut();
+      break;
+    case ShellContextMenuItemCopyId:
+      web_contents_->GetRenderViewHost()->Copy();
+      break;
+    case ShellContextMenuItemPasteId:
+      web_contents_->GetRenderViewHost()->Paste();
+      break;
+    case ShellContextMenuItemDeleteId:
+      web_contents_->GetRenderViewHost()->Delete();
+      break;
+    case ShellContextMenuItemOpenLinkId: {
+      ShellBrowserContext* browser_context =
+          ShellContentBrowserClient::Get()->browser_context();
+      Shell::CreateNewWindow(browser_context,
+                             params_.link_url,
+                             NULL,
+                             MSG_ROUTING_NONE,
+                             gfx::Size());
+      break;
+    }
+    case ShellContextMenuItemBackId:
+      web_contents_->GetController().GoToOffset(-1);
+      web_contents_->GetView()->Focus();
+      break;
+    case ShellContextMenuItemForwardId:
+      web_contents_->GetController().GoToOffset(1);
+      web_contents_->GetView()->Focus();
+      break;
+    case ShellContextMenuItemReloadId:
+      web_contents_->GetController().Reload(false);
+      web_contents_->GetView()->Focus();
+      break;
+    case ShellContextMenuItemInspectId: {
+      ShellDevToolsFrontend::Show(web_contents_);
+      break;
+    }
+  }
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+  return NULL;
+}
+
+void ShellWebContentsViewDelegate::StoreFocus() {
+}
+
+void ShellWebContentsViewDelegate::RestoreFocus() {
+}
+
+bool ShellWebContentsViewDelegate::Focus() {
+  return false;
+}
+
+void ShellWebContentsViewDelegate::TakeFocus(bool reverse) {
+}
+
+void ShellWebContentsViewDelegate::SizeChanged(const gfx::Size& size) {
+}
+
+}  // namespace content
diff --git a/content/shell/browser/shell_win.cc b/content/shell/browser/shell_win.cc
new file mode 100644
index 0000000..d1bb402
--- /dev/null
+++ b/content/shell/browser/shell_win.cc
@@ -0,0 +1,285 @@
+// Copyright 2013 The Chromium Authors. 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/browser/shell.h"
+
+#include <windows.h>
+#include <commctrl.h>
+#include <fcntl.h>
+#include <io.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/wrapped_window_proc.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/app/resource.h"
+#include "ui/base/win/hwnd_util.h"
+
+namespace {
+
+const wchar_t kWindowTitle[] = L"Content Shell";
+const wchar_t kWindowClass[] = L"CONTENT_SHELL";
+
+const int kButtonWidth = 72;
+const int kURLBarHeight = 24;
+
+const int kMaxURLLength = 1024;
+
+}  // namespace
+
+namespace content {
+
+HINSTANCE Shell::instance_handle_;
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+  _setmode(_fileno(stdout), _O_BINARY);
+  _setmode(_fileno(stderr), _O_BINARY);
+  INITCOMMONCONTROLSEX InitCtrlEx;
+  InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
+  InitCtrlEx.dwICC  = ICC_STANDARD_CLASSES;
+  InitCommonControlsEx(&InitCtrlEx);
+  RegisterWindowClass();
+}
+
+void Shell::PlatformExit() {
+  std::vector<Shell*> windows = windows_;
+  for (std::vector<Shell*>::iterator it = windows.begin();
+       it != windows.end(); ++it)
+    DestroyWindow((*it)->window_);
+}
+
+void Shell::PlatformCleanUp() {
+  // When the window is destroyed, tell the Edit field to forget about us,
+  // otherwise we will crash.
+  ui::SetWindowProc(url_edit_view_, default_edit_wnd_proc_);
+  ui::SetWindowUserData(url_edit_view_, NULL);
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+  int id;
+  switch (control) {
+    case BACK_BUTTON:
+      id = IDC_NAV_BACK;
+      break;
+    case FORWARD_BUTTON:
+      id = IDC_NAV_FORWARD;
+      break;
+    case STOP_BUTTON:
+      id = IDC_NAV_STOP;
+      break;
+    default:
+      NOTREACHED() << "Unknown UI control";
+      return;
+  }
+  EnableWindow(GetDlgItem(window_, id), is_enabled);
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+  std::wstring url_string = UTF8ToWide(url.spec());
+  SendMessage(url_edit_view_, WM_SETTEXT, 0,
+              reinterpret_cast<LPARAM>(url_string.c_str()));
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+  window_ = CreateWindow(kWindowClass, kWindowTitle,
+                         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+                         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+                         NULL, NULL, instance_handle_, NULL);
+  ui::SetWindowUserData(window_, this);
+
+  HWND hwnd;
+  int x = 0;
+
+  hwnd = CreateWindow(L"BUTTON", L"Back",
+                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+                      x, 0, kButtonWidth, kURLBarHeight,
+                      window_, (HMENU) IDC_NAV_BACK, instance_handle_, 0);
+  x += kButtonWidth;
+
+  hwnd = CreateWindow(L"BUTTON", L"Forward",
+                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+                      x, 0, kButtonWidth, kURLBarHeight,
+                      window_, (HMENU) IDC_NAV_FORWARD, instance_handle_, 0);
+  x += kButtonWidth;
+
+  hwnd = CreateWindow(L"BUTTON", L"Reload",
+                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+                      x, 0, kButtonWidth, kURLBarHeight,
+                      window_, (HMENU) IDC_NAV_RELOAD, instance_handle_, 0);
+  x += kButtonWidth;
+
+  hwnd = CreateWindow(L"BUTTON", L"Stop",
+                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+                      x, 0, kButtonWidth, kURLBarHeight,
+                      window_, (HMENU) IDC_NAV_STOP, instance_handle_, 0);
+  x += kButtonWidth;
+
+  // This control is positioned by PlatformResizeSubViews.
+  url_edit_view_ = CreateWindow(L"EDIT", 0,
+                                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT |
+                                ES_AUTOVSCROLL | ES_AUTOHSCROLL,
+                                x, 0, 0, 0, window_, 0, instance_handle_, 0);
+
+  default_edit_wnd_proc_ = ui::SetWindowProc(url_edit_view_,
+                                             Shell::EditWndProc);
+  ui::SetWindowUserData(url_edit_view_, this);
+
+  ShowWindow(window_, SW_SHOW);
+
+  SizeTo(width, height);
+}
+
+void Shell::PlatformSetContents() {
+  SetParent(web_contents_->GetView()->GetNativeView(), window_);
+}
+
+void Shell::SizeTo(int width, int height) {
+  RECT rc, rw;
+  GetClientRect(window_, &rc);
+  GetWindowRect(window_, &rw);
+
+  int client_width = rc.right - rc.left;
+  int window_width = rw.right - rw.left;
+  window_width = (window_width - client_width) + width;
+
+  int client_height = rc.bottom - rc.top;
+  int window_height = rw.bottom - rw.top;
+  window_height = (window_height - client_height) + height;
+
+  // Add space for the url bar.
+  window_height += kURLBarHeight;
+
+  SetWindowPos(window_, NULL, 0, 0, window_width, window_height,
+               SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void Shell::PlatformResizeSubViews() {
+  RECT rc;
+  GetClientRect(window_, &rc);
+
+  int x = kButtonWidth * 4;
+  MoveWindow(url_edit_view_, x, 0, rc.right - x, kURLBarHeight, TRUE);
+
+  MoveWindow(GetContentView(), 0, kURLBarHeight, rc.right,
+             rc.bottom - kURLBarHeight, TRUE);
+}
+
+void Shell::Close() {
+  DestroyWindow(window_);
+}
+
+ATOM Shell::RegisterWindowClass() {
+  WNDCLASSEX window_class;
+  base::win::InitializeWindowClass(
+      kWindowClass,
+      &Shell::WndProc,
+      CS_HREDRAW | CS_VREDRAW,
+      0,
+      0,
+      LoadCursor(NULL, IDC_ARROW),
+      NULL,
+      MAKEINTRESOURCE(IDC_CONTENTSHELL),
+      NULL,
+      NULL,
+      &window_class);
+  instance_handle_ = window_class.hInstance;
+  return RegisterClassEx(&window_class);
+}
+
+LRESULT CALLBACK Shell::WndProc(HWND hwnd, UINT message, WPARAM wParam,
+                                LPARAM lParam) {
+  Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
+
+  switch (message) {
+    case WM_COMMAND: {
+      int id = LOWORD(wParam);
+      switch (id) {
+        case IDM_NEW_WINDOW:
+          CreateNewWindow(
+              shell->web_contents()->GetBrowserContext(),
+              GURL(), NULL, MSG_ROUTING_NONE, gfx::Size());
+          break;
+        case IDM_CLOSE_WINDOW:
+          DestroyWindow(hwnd);
+          break;
+        case IDM_EXIT:
+          PlatformExit();
+          break;
+        case IDM_SHOW_DEVELOPER_TOOLS:
+          shell->ShowDevTools();
+          break;
+        case IDC_NAV_BACK:
+          shell->GoBackOrForward(-1);
+          break;
+        case IDC_NAV_FORWARD:
+          shell->GoBackOrForward(1);
+          break;
+        case IDC_NAV_RELOAD:
+          shell->Reload();
+          break;
+        case IDC_NAV_STOP:
+          shell->Stop();
+          break;
+      }
+      break;
+    }
+    case WM_DESTROY: {
+      delete shell;
+      return 0;
+    }
+
+    case WM_SIZE: {
+      if (shell->GetContentView())
+        shell->PlatformResizeSubViews();
+      return 0;
+    }
+
+    case WM_WINDOWPOSCHANGED: {
+      // Notify the content view that the window position of its parent window
+      // has been changed by sending window message
+      gfx::NativeView native_view = shell->GetContentView();
+      if (native_view) {
+        SendMessage(native_view, message, wParam, lParam);
+      }
+      break;
+   }
+  }
+
+  return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+LRESULT CALLBACK Shell::EditWndProc(HWND hwnd, UINT message,
+                                    WPARAM wParam, LPARAM lParam) {
+  Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
+
+  switch (message) {
+    case WM_CHAR:
+      if (wParam == VK_RETURN) {
+        wchar_t str[kMaxURLLength + 1];  // Leave room for adding a NULL;
+        *(str) = kMaxURLLength;
+        LRESULT str_len = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)str);
+        if (str_len > 0) {
+          str[str_len] = 0;  // EM_GETLINE doesn't NULL terminate.
+          GURL url(str);
+          if (!url.has_scheme())
+            url = GURL(std::wstring(L"http://") + std::wstring(str));
+          shell->LoadURL(url);
+        }
+
+        return 0;
+      }
+  }
+
+  return CallWindowProc(shell->default_edit_wnd_proc_, hwnd, message, wParam,
+                        lParam);
+}
+
+void Shell::PlatformSetTitle(const string16& text) {
+  ::SetWindowText(window_, text.c_str());
+}
+
+}  // namespace content
diff --git a/content/shell/browser/webkit_test_controller.cc b/content/shell/browser/webkit_test_controller.cc
new file mode 100644
index 0000000..40ed9c5
--- /dev/null
+++ b/content/shell/browser/webkit_test_controller.cc
@@ -0,0 +1,632 @@
+// Copyright 2013 The Chromium Authors. 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/browser/webkit_test_controller.h"
+
+#include <iostream>
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "content/public/browser/devtools_manager.h"
+#include "content/public/browser/gpu_data_manager.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.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/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.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/common/shell_messages.h"
+#include "content/shell/common/shell_switches.h"
+#include "content/shell/common/webkit_test_helpers.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace content {
+
+const int kTestSVGWindowWidthDip = 480;
+const int kTestSVGWindowHeightDip = 360;
+
+// WebKitTestResultPrinter ----------------------------------------------------
+
+WebKitTestResultPrinter::WebKitTestResultPrinter(
+    std::ostream* output, std::ostream* error)
+    : state_(DURING_TEST),
+      capture_text_only_(false),
+      encode_binary_data_(false),
+      output_(output),
+      error_(error) {
+}
+
+WebKitTestResultPrinter::~WebKitTestResultPrinter() {
+}
+
+void WebKitTestResultPrinter::PrintTextHeader() {
+  if (state_ != DURING_TEST)
+    return;
+  if (!capture_text_only_)
+    *output_ << "Content-Type: text/plain\n";
+  state_ = IN_TEXT_BLOCK;
+}
+
+void WebKitTestResultPrinter::PrintTextBlock(const std::string& block) {
+  if (state_ != IN_TEXT_BLOCK)
+    return;
+  *output_ << block;
+}
+
+void WebKitTestResultPrinter::PrintTextFooter() {
+  if (state_ != IN_TEXT_BLOCK)
+    return;
+  if (!capture_text_only_) {
+    *output_ << "#EOF\n";
+    output_->flush();
+  }
+  state_ = IN_IMAGE_BLOCK;
+}
+
+void WebKitTestResultPrinter::PrintImageHeader(
+    const std::string& actual_hash,
+    const std::string& expected_hash) {
+  if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
+    return;
+  *output_ << "\nActualHash: " << actual_hash << "\n";
+  if (!expected_hash.empty())
+    *output_ << "\nExpectedHash: " << expected_hash << "\n";
+}
+
+void WebKitTestResultPrinter::PrintImageBlock(
+    const std::vector<unsigned char>& png_image) {
+  if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
+    return;
+  *output_ << "Content-Type: image/png\n";
+  if (encode_binary_data_) {
+    PrintEncodedBinaryData(png_image);
+    return;
+  }
+
+  *output_ << "Content-Length: " << png_image.size() << "\n";
+  output_->write(
+      reinterpret_cast<const char*>(&png_image[0]), png_image.size());
+}
+
+void WebKitTestResultPrinter::PrintImageFooter() {
+  if (state_ != IN_IMAGE_BLOCK)
+    return;
+  if (!capture_text_only_) {
+    *output_ << "#EOF\n";
+    *error_ << "#EOF\n";
+    output_->flush();
+    error_->flush();
+  }
+  state_ = AFTER_TEST;
+}
+
+void WebKitTestResultPrinter::PrintAudioHeader() {
+  DCHECK_EQ(state_, DURING_TEST);
+  if (!capture_text_only_)
+    *output_ << "Content-Type: audio/wav\n";
+  state_ = IN_AUDIO_BLOCK;
+}
+
+void WebKitTestResultPrinter::PrintAudioBlock(
+    const std::vector<unsigned char>& audio_data) {
+  if (state_ != IN_AUDIO_BLOCK || capture_text_only_)
+    return;
+  if (encode_binary_data_) {
+    PrintEncodedBinaryData(audio_data);
+    return;
+  }
+
+  *output_ << "Content-Length: " << audio_data.size() << "\n";
+  output_->write(
+      reinterpret_cast<const char*>(&audio_data[0]), audio_data.size());
+}
+
+void WebKitTestResultPrinter::PrintAudioFooter() {
+  if (state_ != IN_AUDIO_BLOCK)
+    return;
+  if (!capture_text_only_) {
+    *output_ << "#EOF\n";
+    *error_ << "#EOF\n";
+    output_->flush();
+    error_->flush();
+  }
+  state_ = IN_IMAGE_BLOCK;
+}
+
+void WebKitTestResultPrinter::AddMessage(const std::string& message) {
+  AddMessageRaw(message + "\n");
+}
+
+void WebKitTestResultPrinter::AddMessageRaw(const std::string& message) {
+  if (state_ != DURING_TEST)
+    return;
+  *output_ << message;
+}
+
+void WebKitTestResultPrinter::AddErrorMessage(const std::string& message) {
+  if (!capture_text_only_)
+    *error_ << message << "\n";
+  if (state_ != DURING_TEST)
+    return;
+  PrintTextHeader();
+  *output_ << message << "\n";
+  PrintTextFooter();
+  PrintImageFooter();
+}
+
+void WebKitTestResultPrinter::PrintEncodedBinaryData(
+    const std::vector<unsigned char>& data) {
+  *output_ << "Content-Transfer-Encoding: base64\n";
+
+  std::string data_base64;
+  const bool success = base::Base64Encode(
+      base::StringPiece(reinterpret_cast<const char*>(&data[0]), data.size()),
+      &data_base64);
+  DCHECK(success);
+
+  *output_ << "Content-Length: " << data_base64.length() << "\n";
+  output_->write(data_base64.c_str(), data_base64.length());
+}
+
+
+// WebKitTestController -------------------------------------------------------
+
+WebKitTestController* WebKitTestController::instance_ = NULL;
+
+// static
+WebKitTestController* WebKitTestController::Get() {
+  DCHECK(instance_);
+  return instance_;
+}
+
+WebKitTestController::WebKitTestController()
+    : main_window_(NULL),
+      test_phase_(BETWEEN_TESTS) {
+  CHECK(!instance_);
+  instance_ = this;
+  printer_.reset(new WebKitTestResultPrinter(&std::cout, &std::cerr));
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEncodeBinary))
+    printer_->set_encode_binary_data(true);
+  registrar_.Add(this,
+                 NOTIFICATION_RENDERER_PROCESS_CREATED,
+                 NotificationService::AllSources());
+  GpuDataManager::GetInstance()->AddObserver(this);
+  ResetAfterLayoutTest();
+}
+
+WebKitTestController::~WebKitTestController() {
+  DCHECK(CalledOnValidThread());
+  CHECK(instance_ == this);
+  CHECK(test_phase_ == BETWEEN_TESTS);
+  GpuDataManager::GetInstance()->RemoveObserver(this);
+  DiscardMainWindow();
+  instance_ = NULL;
+}
+
+bool WebKitTestController::PrepareForLayoutTest(
+    const GURL& test_url,
+    const base::FilePath& current_working_directory,
+    bool enable_pixel_dumping,
+    const std::string& expected_pixel_hash) {
+  DCHECK(CalledOnValidThread());
+  test_phase_ = DURING_TEST;
+  current_working_directory_ = current_working_directory;
+  enable_pixel_dumping_ = enable_pixel_dumping;
+  expected_pixel_hash_ = expected_pixel_hash;
+  test_url_ = test_url;
+  printer_->reset();
+  ShellBrowserContext* browser_context =
+      ShellContentBrowserClient::Get()->browser_context();
+  if (test_url.spec().find("compositing/") != std::string::npos)
+    is_compositing_test_ = true;
+  initial_size_ = gfx::Size(
+      Shell::kDefaultTestWindowWidthDip, Shell::kDefaultTestWindowHeightDip);
+  // The W3C SVG layout tests use a different size than the other layout tests.
+  if (test_url.spec().find("W3C-SVG-1.1") != std::string::npos)
+    initial_size_ = gfx::Size(kTestSVGWindowWidthDip, kTestSVGWindowHeightDip);
+  if (!main_window_) {
+    main_window_ = content::Shell::CreateNewWindow(
+        browser_context,
+        GURL(),
+        NULL,
+        MSG_ROUTING_NONE,
+        initial_size_);
+    WebContentsObserver::Observe(main_window_->web_contents());
+    send_configuration_to_next_host_ = true;
+    current_pid_ = base::kNullProcessId;
+    main_window_->LoadURL(test_url);
+  } else {
+#if (defined(OS_WIN) && !defined(USE_AURA)) || \
+    defined(TOOLKIT_GTK) || defined(OS_MACOSX)
+    // Shell::SizeTo is not implemented on all platforms.
+    main_window_->SizeTo(initial_size_.width(), initial_size_.height());
+#endif
+    main_window_->web_contents()->GetRenderViewHost()->GetView()
+        ->SetSize(initial_size_);
+    main_window_->web_contents()->GetRenderViewHost()->WasResized();
+    RenderViewHost* render_view_host =
+        main_window_->web_contents()->GetRenderViewHost();
+    WebPreferences prefs = render_view_host->GetWebkitPreferences();
+    OverrideWebkitPrefs(&prefs);
+    render_view_host->UpdateWebkitPreferences(prefs);
+    SendTestConfiguration();
+
+    NavigationController::LoadURLParams params(test_url);
+    params.transition_type = PageTransitionFromInt(
+        PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR);
+    params.should_clear_history_list = true;
+    main_window_->web_contents()->GetController().LoadURLWithParams(params);
+    main_window_->web_contents()->GetView()->Focus();
+  }
+  main_window_->web_contents()->GetRenderViewHost()->SetActive(true);
+  main_window_->web_contents()->GetRenderViewHost()->Focus();
+  return true;
+}
+
+bool WebKitTestController::ResetAfterLayoutTest() {
+  DCHECK(CalledOnValidThread());
+  printer_->PrintTextFooter();
+  printer_->PrintImageFooter();
+  send_configuration_to_next_host_ = false;
+  test_phase_ = BETWEEN_TESTS;
+  is_compositing_test_ = false;
+  enable_pixel_dumping_ = false;
+  expected_pixel_hash_.clear();
+  test_url_ = GURL();
+  prefs_ = WebPreferences();
+  should_override_prefs_ = false;
+  return true;
+}
+
+void WebKitTestController::SetTempPath(const base::FilePath& temp_path) {
+  temp_path_ = temp_path;
+}
+
+void WebKitTestController::RendererUnresponsive() {
+  DCHECK(CalledOnValidThread());
+  LOG(WARNING) << "renderer unresponsive";
+}
+
+void WebKitTestController::WorkerCrashed() {
+  DCHECK(CalledOnValidThread());
+  printer_->AddErrorMessage("#CRASHED - worker");
+  DiscardMainWindow();
+}
+
+void WebKitTestController::OverrideWebkitPrefs(WebPreferences* prefs) {
+  if (should_override_prefs_) {
+    *prefs = prefs_;
+  } else {
+    ApplyLayoutTestDefaultPreferences(prefs);
+    if (is_compositing_test_) {
+      CommandLine& command_line = *CommandLine::ForCurrentProcess();
+      if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing))
+        prefs->accelerated_2d_canvas_enabled = true;
+      prefs->accelerated_compositing_for_video_enabled = true;
+      prefs->mock_scrollbars_enabled = true;
+    }
+  }
+}
+
+void WebKitTestController::OpenURL(const GURL& url) {
+  if (test_phase_ != DURING_TEST)
+    return;
+
+  Shell::CreateNewWindow(main_window_->web_contents()->GetBrowserContext(),
+                         url,
+                         main_window_->web_contents()->GetSiteInstance(),
+                         MSG_ROUTING_NONE,
+                         gfx::Size());
+}
+
+void WebKitTestController::TestFinishedInSecondaryWindow() {
+  RenderViewHost* render_view_host =
+      main_window_->web_contents()->GetRenderViewHost();
+  render_view_host->Send(
+      new ShellViewMsg_NotifyDone(render_view_host->GetRoutingID()));
+}
+
+bool WebKitTestController::IsMainWindow(WebContents* web_contents) const {
+  return main_window_ && web_contents == main_window_->web_contents();
+}
+
+bool WebKitTestController::OnMessageReceived(const IPC::Message& message) {
+  DCHECK(CalledOnValidThread());
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage, OnPrintMessage)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump, OnAudioDump)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences,
+                        OnOverridePreferences)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished, OnTestFinished)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools, OnShowDevTools)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools, OnCloseDevTools)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset, OnGoToOffset)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload, OnReload)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame, OnLoadURLForFrame)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory,
+                        OnCaptureSessionHistory)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows,
+                        OnCloseRemainingWindows)
+    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone)
+    IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+
+  return handled;
+}
+
+void WebKitTestController::PluginCrashed(const base::FilePath& plugin_path,
+                                         base::ProcessId plugin_pid) {
+  DCHECK(CalledOnValidThread());
+  printer_->AddErrorMessage(
+      base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid));
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow),
+                 base::Unretained(this)));
+}
+
+void WebKitTestController::RenderViewCreated(RenderViewHost* render_view_host) {
+  DCHECK(CalledOnValidThread());
+  // Might be kNullProcessHandle, in which case we will receive a notification
+  // later when the RenderProcessHost was created.
+  if (render_view_host->GetProcess()->GetHandle() != base::kNullProcessHandle)
+    current_pid_ = base::GetProcId(render_view_host->GetProcess()->GetHandle());
+  if (!send_configuration_to_next_host_)
+    return;
+  send_configuration_to_next_host_ = false;
+  SendTestConfiguration();
+}
+
+void WebKitTestController::RenderProcessGone(base::TerminationStatus status) {
+  DCHECK(CalledOnValidThread());
+  if (current_pid_ != base::kNullProcessId) {
+    printer_->AddErrorMessage(std::string("#CRASHED - renderer (pid ") +
+                              base::IntToString(current_pid_) + ")");
+  } else {
+    printer_->AddErrorMessage("#CRASHED - renderer");
+  }
+  DiscardMainWindow();
+}
+
+void WebKitTestController::WebContentsDestroyed(WebContents* web_contents) {
+  DCHECK(CalledOnValidThread());
+  printer_->AddErrorMessage("FAIL: main window was destroyed");
+  DiscardMainWindow();
+}
+
+void WebKitTestController::Observe(int type,
+                                   const NotificationSource& source,
+                                   const NotificationDetails& details) {
+  DCHECK(CalledOnValidThread());
+  switch (type) {
+    case NOTIFICATION_RENDERER_PROCESS_CREATED: {
+      if (!main_window_)
+        return;
+      RenderViewHost* render_view_host =
+          main_window_->web_contents()->GetRenderViewHost();
+      if (!render_view_host)
+        return;
+      RenderProcessHost* render_process_host =
+          Source<RenderProcessHost>(source).ptr();
+      if (render_process_host != render_view_host->GetProcess())
+        return;
+      current_pid_ = base::GetProcId(render_process_host->GetHandle());
+      break;
+    }
+    default:
+      NOTREACHED();
+  }
+}
+
+void WebKitTestController::OnGpuProcessCrashed(
+    base::TerminationStatus exit_code) {
+  DCHECK(CalledOnValidThread());
+  printer_->AddErrorMessage("#CRASHED - gpu");
+  DiscardMainWindow();
+}
+
+void WebKitTestController::TimeoutHandler() {
+  DCHECK(CalledOnValidThread());
+  printer_->AddErrorMessage(
+      "FAIL: Timed out waiting for notifyDone to be called");
+  DiscardMainWindow();
+}
+
+void WebKitTestController::DiscardMainWindow() {
+  // If we're running a test, we need to close all windows and exit the message
+  // loop. Otherwise, we're already outside of the message loop, and we just
+  // discard the main window.
+  WebContentsObserver::Observe(NULL);
+  if (test_phase_ != BETWEEN_TESTS) {
+    Shell::CloseAllWindows();
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::MessageLoop::QuitClosure());
+    test_phase_ = CLEAN_UP;
+  } else if (main_window_) {
+    main_window_->Close();
+  }
+  main_window_ = NULL;
+  current_pid_ = base::kNullProcessId;
+}
+
+void WebKitTestController::SendTestConfiguration() {
+  RenderViewHost* render_view_host =
+      main_window_->web_contents()->GetRenderViewHost();
+  ShellTestConfiguration params;
+  params.current_working_directory = current_working_directory_;
+  params.temp_path = temp_path_;
+  params.test_url = test_url_;
+  params.enable_pixel_dumping = enable_pixel_dumping_;
+  params.allow_external_pages = CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kAllowExternalPages);
+  params.expected_pixel_hash = expected_pixel_hash_;
+  params.initial_size = initial_size_;
+  render_view_host->Send(new ShellViewMsg_SetTestConfiguration(
+      render_view_host->GetRoutingID(), params));
+}
+
+void WebKitTestController::OnTestFinished() {
+  test_phase_ = CLEAN_UP;
+  if (!printer_->output_finished())
+    printer_->PrintImageFooter();
+  RenderViewHost* render_view_host =
+      main_window_->web_contents()->GetRenderViewHost();
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(base::IgnoreResult(&WebKitTestController::Send),
+                 base::Unretained(this),
+                 new ShellViewMsg_Reset(render_view_host->GetRoutingID())));
+}
+
+void WebKitTestController::OnImageDump(
+    const std::string& actual_pixel_hash,
+    const SkBitmap& image) {
+  SkAutoLockPixels image_lock(image);
+
+  printer_->PrintImageHeader(actual_pixel_hash, expected_pixel_hash_);
+
+  // Only encode and dump the png if the hashes don't match. Encoding the
+  // image is really expensive.
+  if (actual_pixel_hash != expected_pixel_hash_) {
+    std::vector<unsigned char> png;
+
+    // Only the expected PNGs for Mac have a valid alpha channel.
+#if defined(OS_MACOSX)
+    bool discard_transparency = false;
+#else
+    bool discard_transparency = true;
+#endif
+
+    std::vector<gfx::PNGCodec::Comment> comments;
+    comments.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash));
+    bool success = gfx::PNGCodec::Encode(
+        static_cast<const unsigned char*>(image.getPixels()),
+        gfx::PNGCodec::FORMAT_BGRA,
+        gfx::Size(image.width(), image.height()),
+        static_cast<int>(image.rowBytes()),
+        discard_transparency,
+        comments,
+        &png);
+    if (success)
+      printer_->PrintImageBlock(png);
+  }
+  printer_->PrintImageFooter();
+}
+
+void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) {
+  printer_->PrintAudioHeader();
+  printer_->PrintAudioBlock(dump);
+  printer_->PrintAudioFooter();
+}
+
+void WebKitTestController::OnTextDump(const std::string& dump) {
+  printer_->PrintTextHeader();
+  printer_->PrintTextBlock(dump);
+  printer_->PrintTextFooter();
+}
+
+void WebKitTestController::OnPrintMessage(const std::string& message) {
+  printer_->AddMessageRaw(message);
+}
+
+void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) {
+  should_override_prefs_ = true;
+  prefs_ = prefs;
+}
+
+void WebKitTestController::OnShowDevTools() {
+  main_window_->ShowDevTools();
+}
+
+void WebKitTestController::OnCloseDevTools() {
+  main_window_->CloseDevTools();
+}
+
+void WebKitTestController::OnGoToOffset(int offset) {
+  main_window_->GoBackOrForward(offset);
+}
+
+void WebKitTestController::OnReload() {
+  main_window_->Reload();
+}
+
+void WebKitTestController::OnLoadURLForFrame(const GURL& url,
+                                             const std::string& frame_name) {
+  main_window_->LoadURLForFrame(url, frame_name);
+}
+
+void WebKitTestController::OnCaptureSessionHistory() {
+  std::vector<int> routing_ids;
+  std::vector<std::vector<PageState> > session_histories;
+  std::vector<unsigned> current_entry_indexes;
+
+  RenderViewHost* render_view_host =
+      main_window_->web_contents()->GetRenderViewHost();
+
+  for (std::vector<Shell*>::iterator window = Shell::windows().begin();
+       window != Shell::windows().end();
+       ++window) {
+    WebContents* web_contents = (*window)->web_contents();
+    // Only capture the history from windows in the same process as the main
+    // window. During layout tests, we only use two processes when an
+    // devtools window is open. This should not happen during history navigation
+    // tests.
+    if (render_view_host->GetProcess() !=
+        web_contents->GetRenderViewHost()->GetProcess()) {
+      NOTREACHED();
+      continue;
+    }
+    routing_ids.push_back(web_contents->GetRenderViewHost()->GetRoutingID());
+    current_entry_indexes.push_back(
+        web_contents->GetController().GetCurrentEntryIndex());
+    std::vector<PageState> history;
+    for (int entry = 0; entry < web_contents->GetController().GetEntryCount();
+         ++entry) {
+      PageState state = web_contents->GetController().GetEntryAtIndex(entry)->
+          GetPageState();
+      if (!state.IsValid()) {
+        state = PageState::CreateFromURL(
+            web_contents->GetController().GetEntryAtIndex(entry)->GetURL());
+      }
+      history.push_back(state);
+    }
+    session_histories.push_back(history);
+  }
+
+  Send(new ShellViewMsg_SessionHistory(render_view_host->GetRoutingID(),
+                                       routing_ids,
+                                       session_histories,
+                                       current_entry_indexes));
+}
+
+void WebKitTestController::OnCloseRemainingWindows() {
+  DevToolsManager::GetInstance()->CloseAllClientHosts();
+  std::vector<Shell*> open_windows(Shell::windows());
+  for (size_t i = 0; i < open_windows.size(); ++i) {
+    if (open_windows[i] != main_window_)
+      open_windows[i]->Close();
+  }
+  base::MessageLoop::current()->RunUntilIdle();
+}
+
+void WebKitTestController::OnResetDone() {
+  base::MessageLoop::current()->PostTask(FROM_HERE,
+                                         base::MessageLoop::QuitClosure());
+}
+
+}  // namespace content
diff --git a/content/shell/browser/webkit_test_controller.h b/content/shell/browser/webkit_test_controller.h
new file mode 100644
index 0000000..58d1fa9
--- /dev/null
+++ b/content/shell/browser/webkit_test_controller.h
@@ -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.
+
+#ifndef CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_
+#define CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_
+
+#include <ostream>
+#include <string>
+
+#include "base/cancelable_callback.h"
+#include "base/files/file_path.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/non_thread_safe.h"
+#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"
+
+#if defined(OS_ANDROID)
+#include "base/threading/thread_restrictions.h"
+#endif
+
+class SkBitmap;
+
+namespace content {
+
+class Shell;
+
+#if defined(OS_ANDROID)
+// Android uses a nested message loop for running layout tests because the
+// default message loop, provided by the system, does not offer a blocking
+// Run() method. The loop itself, implemented as NestedMessagePumpAndroid,
+// uses a base::WaitableEvent allowing it to sleep until more events arrive.
+class ScopedAllowWaitForAndroidLayoutTests {
+ private:
+  base::ThreadRestrictions::ScopedAllowWait wait;
+};
+#endif
+
+class WebKitTestResultPrinter {
+ public:
+  WebKitTestResultPrinter(std::ostream* output, std::ostream* error);
+  ~WebKitTestResultPrinter();
+
+  void reset() {
+    state_ = DURING_TEST;
+  }
+  bool output_finished() const { return state_ == AFTER_TEST; }
+  void set_capture_text_only(bool capture_text_only) {
+    capture_text_only_ = capture_text_only;
+  }
+
+  void set_encode_binary_data(bool encode_binary_data) {
+    encode_binary_data_ = encode_binary_data;
+  }
+
+  void PrintTextHeader();
+  void PrintTextBlock(const std::string& block);
+  void PrintTextFooter();
+
+  void PrintImageHeader(const std::string& actual_hash,
+                        const std::string& expected_hash);
+  void PrintImageBlock(const std::vector<unsigned char>& png_image);
+  void PrintImageFooter();
+
+  void PrintAudioHeader();
+  void PrintAudioBlock(const std::vector<unsigned char>& audio_data);
+  void PrintAudioFooter();
+
+  void AddMessage(const std::string& message);
+  void AddMessageRaw(const std::string& message);
+  void AddErrorMessage(const std::string& message);
+
+ private:
+  void PrintEncodedBinaryData(const std::vector<unsigned char>& data);
+
+  enum State {
+    DURING_TEST,
+    IN_TEXT_BLOCK,
+    IN_AUDIO_BLOCK,
+    IN_IMAGE_BLOCK,
+    AFTER_TEST
+  };
+  State state_;
+
+  bool capture_text_only_;
+  bool encode_binary_data_;
+
+  std::ostream* output_;
+  std::ostream* error_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebKitTestResultPrinter);
+};
+
+class WebKitTestController : public base::NonThreadSafe,
+                             public WebContentsObserver,
+                             public NotificationObserver,
+                             public GpuDataManagerObserver {
+ public:
+  static WebKitTestController* Get();
+
+  WebKitTestController();
+  virtual ~WebKitTestController();
+
+  // True if the controller is ready for testing.
+  bool PrepareForLayoutTest(const GURL& test_url,
+                            const base::FilePath& current_working_directory,
+                            bool enable_pixel_dumping,
+                            const std::string& expected_pixel_hash);
+  // True if the controller was reset successfully.
+  bool ResetAfterLayoutTest();
+
+  void SetTempPath(const base::FilePath& temp_path);
+  void RendererUnresponsive();
+  void WorkerCrashed();
+  void OverrideWebkitPrefs(WebPreferences* prefs);
+  void OpenURL(const GURL& url);
+  void TestFinishedInSecondaryWindow();
+  bool IsMainWindow(WebContents* web_contents) const;
+
+  WebKitTestResultPrinter* printer() { return printer_.get(); }
+  void set_printer(WebKitTestResultPrinter* printer) {
+    printer_.reset(printer);
+  }
+
+  // WebContentsObserver implementation.
+  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+  virtual void PluginCrashed(const base::FilePath& plugin_path,
+                             base::ProcessId plugin_pid) OVERRIDE;
+  virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
+  virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
+  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+
+  // NotificationObserver implementation.
+  virtual void Observe(int type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details) OVERRIDE;
+
+  // GpuDataManagerObserver implementation.
+  virtual void OnGpuProcessCrashed(base::TerminationStatus exit_code) OVERRIDE;
+
+ private:
+  enum TestPhase {
+    BETWEEN_TESTS,
+    DURING_TEST,
+    CLEAN_UP
+  };
+
+  static WebKitTestController* instance_;
+
+  void TimeoutHandler();
+  void DiscardMainWindow();
+  void SendTestConfiguration();
+
+  // Message handlers.
+  void OnAudioDump(const std::vector<unsigned char>& audio_dump);
+  void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image);
+  void OnTextDump(const std::string& dump);
+  void OnPrintMessage(const std::string& message);
+  void OnOverridePreferences(const WebPreferences& prefs);
+  void OnTestFinished();
+  void OnShowDevTools();
+  void OnCloseDevTools();
+  void OnGoToOffset(int offset);
+  void OnReload();
+  void OnLoadURLForFrame(const GURL& url, const std::string& frame_name);
+  void OnCaptureSessionHistory();
+  void OnCloseRemainingWindows();
+  void OnResetDone();
+
+  scoped_ptr<WebKitTestResultPrinter> printer_;
+
+  base::FilePath current_working_directory_;
+  base::FilePath temp_path_;
+
+  Shell* main_window_;
+
+  // The PID of the render process of the render view host of main_window_.
+  int current_pid_;
+
+  // True if we should set the test configuration to the next RenderViewHost
+  // created.
+  bool send_configuration_to_next_host_;
+
+  // What phase of running an individual test we are currently in.
+  TestPhase test_phase_;
+
+  // True if the currently running test is a compositing test.
+  bool is_compositing_test_;
+
+  // Per test config.
+  bool enable_pixel_dumping_;
+  std::string expected_pixel_hash_;
+  gfx::Size initial_size_;
+  GURL test_url_;
+
+  // True if the WebPreferences of newly created RenderViewHost should be
+  // overridden with prefs_.
+  bool should_override_prefs_;
+  WebPreferences prefs_;
+
+  NotificationRegistrar registrar_;
+
+#if defined(OS_ANDROID)
+  // Because of the nested message pump implementation, Android needs to allow
+  // waiting on the UI thread while layout tests are being ran.
+  ScopedAllowWaitForAndroidLayoutTests reduced_restrictions_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(WebKitTestController);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_
diff --git a/content/shell/common/shell_switches.cc b/content/shell/common/shell_switches.cc
index 81a4a68..a00af45 100644
--- a/content/shell/common/shell_switches.cc
+++ b/content/shell/common/shell_switches.cc
@@ -34,4 +34,10 @@
 // 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
+// http://dev.chromium.org/blink/runtime-enabled-features.
+const char kStableReleaseMode[] = "stable-release-mode";
+
 }  // namespace switches
diff --git a/content/shell/common/shell_switches.h b/content/shell/common/shell_switches.h
index 36474a7..d6b936a 100644
--- a/content/shell/common/shell_switches.h
+++ b/content/shell/common/shell_switches.h
@@ -18,6 +18,7 @@
 extern const char kEncodeBinary[];
 extern const char kExposeInternalsForTesting[];
 extern const char kOutputLayoutTestDifferences[];
+extern const char kStableReleaseMode[];
 
 }  // namespace switches
 
diff --git a/content/shell/geolocation/shell_access_token_store.cc b/content/shell/geolocation/shell_access_token_store.cc
index fa889bd..ceae3d6 100644
--- a/content/shell/geolocation/shell_access_token_store.cc
+++ b/content/shell/geolocation/shell_access_token_store.cc
@@ -8,7 +8,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/shell/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_context.h"
 
 namespace content {
 
diff --git a/content/shell/minimal_shell.cc b/content/shell/minimal_shell.cc
deleted file mode 100644
index 2e9079e..0000000
--- a/content/shell/minimal_shell.cc
+++ /dev/null
@@ -1,54 +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/shell/minimal_shell.h"
-
-#include "ui/aura/client/default_capture_client.h"
-#include "ui/aura/focus_manager.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/test_activation_client.h"
-#include "ui/views/corewm/compound_event_filter.h"
-#include "ui/views/corewm/input_method_event_filter.h"
-
-namespace content {
-
-MinimalShell::MinimalShell(const gfx::Size& default_window_size) {
-  root_window_.reset(new aura::RootWindow(
-      aura::RootWindow::CreateParams(
-          gfx::Rect(default_window_size))));
-  root_window_->Init();
-  aura::client::SetStackingClient(root_window_.get(), this);
-
-  focus_client_.reset(new aura::FocusManager);
-  aura::client::SetFocusClient(root_window_.get(), focus_client_.get());
-
-  root_window_event_filter_ = new views::corewm::CompoundEventFilter;
-  // Pass ownership of the filter to the root_window.
-  root_window_->SetEventFilter(root_window_event_filter_);
-
-  input_method_filter_.reset(new views::corewm::InputMethodEventFilter(
-      root_window_->GetAcceleratedWidget()));
-  input_method_filter_->SetInputMethodPropertyInRootWindow(
-      root_window_.get());
-  root_window_event_filter_->AddHandler(input_method_filter_.get());
-
-  test_activation_client_.reset(
-      new aura::test::TestActivationClient(root_window_.get()));
-
-  capture_client_.reset(
-      new aura::client::DefaultCaptureClient(root_window_.get()));
-}
-
-MinimalShell::~MinimalShell() {
-  root_window_event_filter_->RemoveHandler(input_method_filter_.get());
-}
-
-aura::Window* MinimalShell::GetDefaultParent(
-    aura::Window* context,
-    aura::Window* window,
-    const gfx::Rect& bounds) {
-  return root_window_.get();
-}
-
-}  // namespace content
diff --git a/content/shell/minimal_shell.h b/content/shell/minimal_shell.h
deleted file mode 100644
index b2ab9eb..0000000
--- a/content/shell/minimal_shell.h
+++ /dev/null
@@ -1,67 +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_SHELL_MINIMAL_SHELL_H_
-#define CONTENT_SHELL_MINIMAL_SHELL_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/aura/client/stacking_client.h"
-
-namespace aura {
-class RootWindow;
-class Window;
-namespace client {
-class DefaultCaptureClient;
-class FocusClient;
-}
-namespace test {
-class TestActivationClient;
-}
-}
-
-namespace gfx {
-class Rect;
-class Size;
-}
-
-namespace views {
-namespace corewm {
-class CompoundEventFilter;
-class InputMethodEventFilter;
-}
-}
-
-namespace content {
-
-// 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 {
- public:
-  explicit MinimalShell(const gfx::Size& default_window_size);
-  virtual ~MinimalShell();
-
-  // Overridden from client::StackingClient:
-  virtual aura::Window* GetDefaultParent(aura::Window* context,
-                                         aura::Window* window,
-                                         const gfx::Rect& bounds) OVERRIDE;
-
- private:
-  scoped_ptr<aura::RootWindow> root_window_;
-
-  // Owned by RootWindow
-  views::corewm::CompoundEventFilter* root_window_event_filter_;
-
-  scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
-  scoped_ptr<views::corewm::InputMethodEventFilter> input_method_filter_;
-  scoped_ptr<aura::test::TestActivationClient> test_activation_client_;
-  scoped_ptr<aura::client::FocusClient> focus_client_;
-
-  DISALLOW_COPY_AND_ASSIGN(MinimalShell);
-};
-
-}  // namespace content;
-
-#endif  // CONTENT_SHELL_MINIMAL_SHELL_H_
diff --git a/content/shell/notify_done_forwarder.cc b/content/shell/notify_done_forwarder.cc
deleted file mode 100644
index 522138e..0000000
--- a/content/shell/notify_done_forwarder.cc
+++ /dev/null
@@ -1,33 +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/shell/notify_done_forwarder.h"
-
-#include "content/shell/common/shell_messages.h"
-#include "content/shell/webkit_test_controller.h"
-
-namespace content {
-
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(NotifyDoneForwarder);
-
-NotifyDoneForwarder::NotifyDoneForwarder(WebContents* web_contents)
-    : WebContentsObserver(web_contents) {}
-
-NotifyDoneForwarder::~NotifyDoneForwarder() {}
-
-bool NotifyDoneForwarder::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(NotifyDoneForwarder, message)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinishedInSecondaryWindow,
-                        OnTestFinishedInSecondaryWindow)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void NotifyDoneForwarder::OnTestFinishedInSecondaryWindow() {
-  WebKitTestController::Get()->TestFinishedInSecondaryWindow();
-}
-
-}  // namespace content
diff --git a/content/shell/notify_done_forwarder.h b/content/shell/notify_done_forwarder.h
deleted file mode 100644
index 008371a..0000000
--- a/content/shell/notify_done_forwarder.h
+++ /dev/null
@@ -1,34 +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_SHELL_NOTIFY_DONE_FORWARDER_H_
-#define CONTENT_SHELL_NOTIFY_DONE_FORWARDER_H_
-
-#include "base/basictypes.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-
-namespace content {
-
-class NotifyDoneForwarder : public WebContentsObserver,
-                            public WebContentsUserData<NotifyDoneForwarder> {
- public:
-  virtual ~NotifyDoneForwarder();
-
-  // WebContentsObserver implementation.
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
- private:
-  friend class WebContentsUserData<NotifyDoneForwarder>;
-
-  explicit NotifyDoneForwarder(WebContents* web_contents);
-
-  void OnTestFinishedInSecondaryWindow();
-
-  DISALLOW_COPY_AND_ASSIGN(NotifyDoneForwarder);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_NOTIFY_DONE_FORWARDER_H_
diff --git a/content/shell/renderer/shell_render_process_observer.cc b/content/shell/renderer/shell_render_process_observer.cc
index 6c445fa..2694993 100644
--- a/content/shell/renderer/shell_render_process_observer.cc
+++ b/content/shell/renderer/shell_render_process_observer.cc
@@ -15,10 +15,12 @@
 #include "content/shell/renderer/shell_content_renderer_client.h"
 #include "content/shell/renderer/webkit_test_runner.h"
 #include "third_party/WebKit/public/testing/WebTestInterfaces.h"
+#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "webkit/glue/webkit_glue.h"
 
 using WebKit::WebFrame;
+using WebKit::WebRuntimeFeatures;
 using WebTestRunner::WebTestDelegate;
 using WebTestRunner::WebTestInterfaces;
 
@@ -68,6 +70,11 @@
   webkit_glue::SetJavaScriptFlags(" --expose-gc");
   RenderThread::Get()->RegisterExtension(extensions_v8::GCExtension::Get());
 
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+    switches::kStableReleaseMode)) {
+    WebRuntimeFeatures::enableTestOnlyFeatures(true);
+  }
+
   test_interfaces_.reset(new WebTestInterfaces);
   test_interfaces_->resetAll();
 }
diff --git a/content/shell/renderer/webkit_test_runner.cc b/content/shell/renderer/webkit_test_runner.cc
index a001300..7f11fb9 100644
--- a/content/shell/renderer/webkit_test_runner.cc
+++ b/content/shell/renderer/webkit_test_runner.cc
@@ -66,6 +66,7 @@
 using WebKit::WebContextMenuData;
 using WebKit::WebDevToolsAgent;
 using WebKit::WebDeviceMotionData;
+using WebKit::WebDeviceOrientationData;
 using WebKit::WebDeviceOrientation;
 using WebKit::WebElement;
 using WebKit::WebFrame;
@@ -217,6 +218,11 @@
   SetMockDeviceMotionData(data);
 }
 
+void WebKitTestRunner::setDeviceOrientationData(
+    const WebDeviceOrientationData& data) {
+  SetMockDeviceOrientationData(data);
+}
+
 void WebKitTestRunner::printMessage(const std::string& message) {
   Send(new ShellViewHostMsg_PrintMessage(routing_id(), message));
 }
diff --git a/content/shell/renderer/webkit_test_runner.h b/content/shell/renderer/webkit_test_runner.h
index 0d63e76..de8d48f 100644
--- a/content/shell/renderer/webkit_test_runner.h
+++ b/content/shell/renderer/webkit_test_runner.h
@@ -21,6 +21,7 @@
 
 namespace WebKit {
 class WebDeviceMotionData;
+class WebDeviceOrientationData;
 struct WebRect;
 }
 
@@ -53,6 +54,8 @@
                               const std::string& value);
   virtual void setGamepadData(const WebKit::WebGamepads& gamepads);
   virtual void setDeviceMotionData(const WebKit::WebDeviceMotionData& data);
+  virtual void setDeviceOrientationData(
+      const WebKit::WebDeviceOrientationData& data);
   virtual void printMessage(const std::string& message);
   virtual void postTask(::WebTestRunner::WebTask* task);
   virtual void postDelayedTask(::WebTestRunner::WebTask* task,
diff --git a/content/shell/shell.cc b/content/shell/shell.cc
deleted file mode 100644
index 0fadcf8..0000000
--- a/content/shell/shell.cc
+++ /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.
-
-#include "content/shell/shell.h"
-
-#include "base/auto_reset.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.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 "content/public/browser/devtools_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_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/renderer_preferences.h"
-#include "content/shell/common/shell_messages.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/notify_done_forwarder.h"
-#include "content/shell/shell_browser_main_parts.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_devtools_frontend.h"
-#include "content/shell/shell_javascript_dialog_manager.h"
-#include "content/shell/webkit_test_controller.h"
-
-namespace content {
-
-const int Shell::kDefaultTestWindowWidthDip = 800;
-const int Shell::kDefaultTestWindowHeightDip = 600;
-
-std::vector<Shell*> Shell::windows_;
-base::Callback<void(Shell*)> Shell::shell_created_callback_;
-
-bool Shell::quit_message_loop_ = true;
-
-class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
- public:
-  DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
-      : WebContentsObserver(web_contents),
-        shell_(shell) {
-  }
-
-  // WebContentsObserver
-  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
-    shell_->OnDevToolsWebContentsDestroyed();
-  }
-
- private:
-  Shell* shell_;
-
-  DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
-};
-
-Shell::Shell(WebContents* web_contents)
-    : devtools_frontend_(NULL),
-      is_fullscreen_(false),
-      window_(NULL),
-      url_edit_view_(NULL),
-#if defined(OS_WIN) && !defined(USE_AURA)
-      default_edit_wnd_proc_(0),
-#endif
-      headless_(false) {
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-  if (command_line.HasSwitch(switches::kDumpRenderTree))
-    headless_ = true;
-  registrar_.Add(this, NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
-      Source<WebContents>(web_contents));
-  windows_.push_back(this);
-
-  if (!shell_created_callback_.is_null()) {
-    shell_created_callback_.Run(this);
-    shell_created_callback_.Reset();
-  }
-}
-
-Shell::~Shell() {
-  PlatformCleanUp();
-
-  for (size_t i = 0; i < windows_.size(); ++i) {
-    if (windows_[i] == this) {
-      windows_.erase(windows_.begin() + i);
-      break;
-    }
-  }
-
-  if (windows_.empty() && quit_message_loop_)
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
-}
-
-Shell* Shell::CreateShell(WebContents* web_contents,
-                          const gfx::Size& initial_size) {
-  Shell* shell = new Shell(web_contents);
-  shell->PlatformCreateWindow(initial_size.width(), initial_size.height());
-
-  shell->web_contents_.reset(web_contents);
-  web_contents->SetDelegate(shell);
-
-  shell->PlatformSetContents();
-
-  shell->PlatformResizeSubViews();
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
-    web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
-    web_contents->GetRenderViewHost()->SyncRendererPrefs();
-  }
-
-  return shell;
-}
-
-void Shell::CloseAllWindows() {
-  base::AutoReset<bool> auto_reset(&quit_message_loop_, false);
-  DevToolsManager::GetInstance()->CloseAllClientHosts();
-  std::vector<Shell*> open_windows(windows_);
-  for (size_t i = 0; i < open_windows.size(); ++i)
-    open_windows[i]->Close();
-  base::MessageLoop::current()->RunUntilIdle();
-}
-
-void Shell::SetShellCreatedCallback(
-    base::Callback<void(Shell*)> shell_created_callback) {
-  DCHECK(shell_created_callback_.is_null());
-  shell_created_callback_ = shell_created_callback;
-}
-
-Shell* Shell::FromRenderViewHost(RenderViewHost* rvh) {
-  for (size_t i = 0; i < windows_.size(); ++i) {
-    if (windows_[i]->web_contents() &&
-        windows_[i]->web_contents()->GetRenderViewHost() == rvh) {
-      return windows_[i];
-    }
-  }
-  return NULL;
-}
-
-// static
-void Shell::Initialize() {
-  PlatformInitialize(
-      gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
-}
-
-Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
-                              const GURL& url,
-                              SiteInstance* site_instance,
-                              int routing_id,
-                              const gfx::Size& initial_size) {
-  WebContents::CreateParams create_params(browser_context, site_instance);
-  create_params.routing_id = routing_id;
-  if (!initial_size.IsEmpty())
-    create_params.initial_size = initial_size;
-  else
-    create_params.initial_size =
-        gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
-  WebContents* web_contents = WebContents::Create(create_params);
-  Shell* shell = CreateShell(web_contents, create_params.initial_size);
-  if (!url.is_empty())
-    shell->LoadURL(url);
-  return shell;
-}
-
-void Shell::LoadURL(const GURL& url) {
-  LoadURLForFrame(url, std::string());
-}
-
-void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) {
-  NavigationController::LoadURLParams params(url);
-  params.transition_type = PageTransitionFromInt(
-      PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR);
-  params.frame_name = frame_name;
-  web_contents_->GetController().LoadURLWithParams(params);
-  web_contents_->GetView()->Focus();
-}
-
-void Shell::GoBackOrForward(int offset) {
-  web_contents_->GetController().GoToOffset(offset);
-  web_contents_->GetView()->Focus();
-}
-
-void Shell::Reload() {
-  web_contents_->GetController().Reload(false);
-  web_contents_->GetView()->Focus();
-}
-
-void Shell::Stop() {
-  web_contents_->Stop();
-  web_contents_->GetView()->Focus();
-}
-
-void Shell::UpdateNavigationControls() {
-  int current_index = web_contents_->GetController().GetCurrentEntryIndex();
-  int max_index = web_contents_->GetController().GetEntryCount() - 1;
-
-  PlatformEnableUIControl(BACK_BUTTON, current_index > 0);
-  PlatformEnableUIControl(FORWARD_BUTTON, current_index < max_index);
-  PlatformEnableUIControl(STOP_BUTTON, web_contents_->IsLoading());
-}
-
-void Shell::ShowDevTools() {
-  if (devtools_frontend_) {
-    devtools_frontend_->Focus();
-    return;
-  }
-  devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
-  devtools_observer_.reset(new DevToolsWebContentsObserver(
-      this, devtools_frontend_->frontend_shell()->web_contents()));
-}
-
-void Shell::CloseDevTools() {
-  if (!devtools_frontend_)
-    return;
-  devtools_observer_.reset();
-  devtools_frontend_->Close();
-  devtools_frontend_ = NULL;
-}
-
-gfx::NativeView Shell::GetContentView() {
-  if (!web_contents_)
-    return NULL;
-  return web_contents_->GetView()->GetNativeView();
-}
-
-WebContents* Shell::OpenURLFromTab(WebContents* source,
-                                   const OpenURLParams& params) {
-  // The only one we implement for now.
-  DCHECK(params.disposition == CURRENT_TAB);
-  NavigationController::LoadURLParams load_url_params(params.url);
-  load_url_params.referrer = params.referrer;
-  load_url_params.transition_type = params.transition;
-  load_url_params.extra_headers = params.extra_headers;
-  load_url_params.should_replace_current_entry =
-      params.should_replace_current_entry;
-
-  if (params.transferred_global_request_id != GlobalRequestID()) {
-    load_url_params.is_renderer_initiated = params.is_renderer_initiated;
-    load_url_params.transferred_global_request_id =
-        params.transferred_global_request_id;
-  } else if (params.is_renderer_initiated) {
-    load_url_params.is_renderer_initiated = true;
-  }
-
-  source->GetController().LoadURLWithParams(load_url_params);
-  return source;
-}
-
-void Shell::LoadingStateChanged(WebContents* source) {
-  UpdateNavigationControls();
-  PlatformSetIsLoading(source->IsLoading());
-}
-
-void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
-                                       bool enter_fullscreen) {
-#if defined(OS_ANDROID)
-  PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
-#endif
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-  if (is_fullscreen_ != enter_fullscreen) {
-    is_fullscreen_ = enter_fullscreen;
-    web_contents->GetRenderViewHost()->WasResized();
-  }
-}
-
-bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
-#if defined(OS_ANDROID)
-  return PlatformIsFullscreenForTabOrPending(web_contents);
-#else
-  return is_fullscreen_;
-#endif
-}
-
-void Shell::RequestToLockMouse(WebContents* web_contents,
-                               bool user_gesture,
-                               bool last_unlocked_by_target) {
-  web_contents->GotResponseToLockMouseRequest(true);
-}
-
-void Shell::CloseContents(WebContents* source) {
-  Close();
-}
-
-bool Shell::CanOverscrollContent() const {
-#if defined(USE_AURA)
-  return true;
-#else
-  return false;
-#endif
-}
-
-void Shell::WebContentsCreated(WebContents* source_contents,
-                               int64 source_frame_id,
-                               const string16& frame_name,
-                               const GURL& target_url,
-                               WebContents* new_contents) {
-  CreateShell(new_contents, source_contents->GetView()->GetContainerSize());
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    NotifyDoneForwarder::CreateForWebContents(new_contents);
-}
-
-void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
-  PlatformSetAddressBarURL(web_contents->GetURL());
-}
-
-JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
-  if (!dialog_manager_)
-    dialog_manager_.reset(new ShellJavaScriptDialogManager());
-  return dialog_manager_.get();
-}
-
-bool Shell::AddMessageToConsole(WebContents* source,
-                                int32 level,
-                                const string16& message,
-                                int32 line_no,
-                                const string16& source_id) {
-  return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
-}
-
-void Shell::RendererUnresponsive(WebContents* source) {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-  WebKitTestController::Get()->RendererUnresponsive();
-}
-
-void Shell::ActivateContents(WebContents* contents) {
-  contents->GetRenderViewHost()->Focus();
-}
-
-void Shell::DeactivateContents(WebContents* contents) {
-  contents->GetRenderViewHost()->Blur();
-}
-
-void Shell::WorkerCrashed(WebContents* source) {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-  WebKitTestController::Get()->WorkerCrashed();
-}
-
-void Shell::Observe(int type,
-                    const NotificationSource& source,
-                    const NotificationDetails& details) {
-  if (type == NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
-    std::pair<NavigationEntry*, bool>* title =
-        Details<std::pair<NavigationEntry*, bool> >(details).ptr();
-
-    if (title->first) {
-      string16 text = title->first->GetTitle();
-      PlatformSetTitle(text);
-    }
-  } else {
-    NOTREACHED();
-  }
-}
-
-void Shell::OnDevToolsWebContentsDestroyed() {
-  devtools_observer_.reset();
-  devtools_frontend_ = NULL;
-}
-
-}  // namespace content
diff --git a/content/shell/shell.h b/content/shell/shell.h
deleted file mode 100644
index 8666aec..0000000
--- a/content/shell/shell.h
+++ /dev/null
@@ -1,286 +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_SHELL_SHELL_H_
-#define CONTENT_SHELL_SHELL_H_
-
-
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback_forward.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_piece.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/web_contents_delegate.h"
-#include "ipc/ipc_channel.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/size.h"
-
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#include "ui/base/gtk/gtk_signal.h"
-
-typedef struct _GtkToolItem GtkToolItem;
-#elif defined(OS_ANDROID)
-#include "base/android/scoped_java_ref.h"
-#elif defined(USE_AURA)
-#if defined(OS_CHROMEOS)
-namespace content {
-class MinimalShell;
-}
-#endif
-namespace views {
-class Widget;
-class ViewsDelegate;
-}
-#endif
-
-class GURL;
-namespace content {
-
-class BrowserContext;
-class ShellDevToolsFrontend;
-class ShellJavaScriptDialogManager;
-class SiteInstance;
-class WebContents;
-
-// This represents one window of the Content Shell, i.e. all the UI including
-// buttons and url bar, as well as the web content area.
-class Shell : public WebContentsDelegate,
-              public NotificationObserver {
- public:
-  static const int kDefaultTestWindowWidthDip;
-  static const int kDefaultTestWindowHeightDip;
-
-  virtual ~Shell();
-
-  void LoadURL(const GURL& url);
-  void LoadURLForFrame(const GURL& url, const std::string& frame_name);
-  void GoBackOrForward(int offset);
-  void Reload();
-  void Stop();
-  void UpdateNavigationControls();
-  void Close();
-  void ShowDevTools();
-  void CloseDevTools();
-#if (defined(OS_WIN) && !defined(USE_AURA)) || \
-    defined(TOOLKIT_GTK) || defined(OS_MACOSX)
-  // Resizes the main window to the given dimensions.
-  void SizeTo(int width, int height);
-#endif
-
-  // Do one time initialization at application startup.
-  static void Initialize();
-
-  static Shell* CreateNewWindow(BrowserContext* browser_context,
-                                const GURL& url,
-                                SiteInstance* site_instance,
-                                int routing_id,
-                                const gfx::Size& initial_size);
-
-  // Returns the Shell object corresponding to the given RenderViewHost.
-  static Shell* FromRenderViewHost(RenderViewHost* rvh);
-
-  // Returns the currently open windows.
-  static std::vector<Shell*>& windows() { return windows_; }
-
-  // Closes all windows and returns. This runs a message loop.
-  static void CloseAllWindows();
-
-  // Closes all windows and exits.
-  static void PlatformExit();
-
-  // Used for content_browsertests. Called once.
-  static void SetShellCreatedCallback(
-      base::Callback<void(Shell*)> shell_created_callback);
-
-  WebContents* web_contents() const { return web_contents_.get(); }
-  gfx::NativeWindow window() { return window_; }
-
-#if defined(OS_MACOSX)
-  // Public to be called by an ObjC bridge object.
-  void ActionPerformed(int control);
-  void URLEntered(std::string url_string);
-#elif defined(OS_ANDROID)
-  // Registers the Android Java to native methods.
-  static bool Register(JNIEnv* env);
-#endif
-
-  // WebContentsDelegate
-  virtual WebContents* OpenURLFromTab(WebContents* source,
-                                      const OpenURLParams& params) OVERRIDE;
-  virtual void LoadingStateChanged(WebContents* source) OVERRIDE;
-#if defined(OS_ANDROID)
-  virtual void LoadProgressChanged(WebContents* source,
-                                   double progress) OVERRIDE;
-#endif
-  virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
-                                          bool enter_fullscreen) OVERRIDE;
-  virtual bool IsFullscreenForTabOrPending(
-      const WebContents* web_contents) const OVERRIDE;
-  virtual void RequestToLockMouse(WebContents* web_contents,
-                                  bool user_gesture,
-                                  bool last_unlocked_by_target) OVERRIDE;
-  virtual void CloseContents(WebContents* source) OVERRIDE;
-  virtual bool CanOverscrollContent() const OVERRIDE;
-  virtual void WebContentsCreated(WebContents* source_contents,
-                                  int64 source_frame_id,
-                                  const string16& frame_name,
-                                  const GURL& target_url,
-                                  WebContents* new_contents) OVERRIDE;
-  virtual void DidNavigateMainFramePostCommit(
-      WebContents* web_contents) OVERRIDE;
-  virtual JavaScriptDialogManager* GetJavaScriptDialogManager() OVERRIDE;
-#if defined(OS_MACOSX)
-  virtual void HandleKeyboardEvent(
-      WebContents* source,
-      const NativeWebKeyboardEvent& event) OVERRIDE;
-#endif
-  virtual bool AddMessageToConsole(WebContents* source,
-                                   int32 level,
-                                   const string16& message,
-                                   int32 line_no,
-                                   const string16& source_id) OVERRIDE;
-  virtual void RendererUnresponsive(WebContents* source) OVERRIDE;
-  virtual void ActivateContents(WebContents* contents) OVERRIDE;
-  virtual void DeactivateContents(WebContents* contents) OVERRIDE;
-  virtual void WorkerCrashed(WebContents* source) OVERRIDE;
-
- private:
-  enum UIControl {
-    BACK_BUTTON,
-    FORWARD_BUTTON,
-    STOP_BUTTON
-  };
-
-  class DevToolsWebContentsObserver;
-
-  explicit Shell(WebContents* web_contents);
-
-  // Helper to create a new Shell given a newly created WebContents.
-  static Shell* CreateShell(WebContents* web_contents,
-                            const gfx::Size& initial_size);
-
-  // Helper for one time initialization of application
-  static void PlatformInitialize(const gfx::Size& default_window_size);
-
-  // All the methods that begin with Platform need to be implemented by the
-  // platform specific Shell implementation.
-  // Called from the destructor to let each platform do any necessary cleanup.
-  void PlatformCleanUp();
-  // Creates the main window GUI.
-  void PlatformCreateWindow(int width, int height);
-  // Links the WebContents into the newly created window.
-  void PlatformSetContents();
-  // Resize the content area and GUI.
-  void PlatformResizeSubViews();
-  // Enable/disable a button.
-  void PlatformEnableUIControl(UIControl control, bool is_enabled);
-  // Updates the url in the url bar.
-  void PlatformSetAddressBarURL(const GURL& url);
-  // Sets whether the spinner is spinning.
-  void PlatformSetIsLoading(bool loading);
-  // Set the title of shell window
-  void PlatformSetTitle(const string16& title);
-#if defined(OS_ANDROID)
-  void PlatformToggleFullscreenModeForTab(WebContents* web_contents,
-                                          bool enter_fullscreen);
-  bool PlatformIsFullscreenForTabOrPending(
-      const WebContents* web_contents) const;
-#endif
-
-  gfx::NativeView GetContentView();
-
-  // NotificationObserver
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details) OVERRIDE;
-
-  void OnDevToolsWebContentsDestroyed();
-
-#if defined(OS_WIN) && !defined(USE_AURA)
-  static ATOM RegisterWindowClass();
-  static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
-  static LRESULT CALLBACK EditWndProc(HWND, UINT, WPARAM, LPARAM);
-#elif defined(TOOLKIT_GTK)
-  CHROMEGTK_CALLBACK_0(Shell, void, OnBackButtonClicked);
-  CHROMEGTK_CALLBACK_0(Shell, void, OnForwardButtonClicked);
-  CHROMEGTK_CALLBACK_0(Shell, void, OnReloadButtonClicked);
-  CHROMEGTK_CALLBACK_0(Shell, void, OnStopButtonClicked);
-  CHROMEGTK_CALLBACK_0(Shell, void, OnURLEntryActivate);
-  CHROMEGTK_CALLBACK_0(Shell, gboolean, OnWindowDestroyed);
-
-  CHROMEG_CALLBACK_3(Shell, gboolean, OnCloseWindowKeyPressed, GtkAccelGroup*,
-                     GObject*, guint, GdkModifierType);
-  CHROMEG_CALLBACK_3(Shell, gboolean, OnNewWindowKeyPressed, GtkAccelGroup*,
-                     GObject*, guint, GdkModifierType);
-  CHROMEG_CALLBACK_3(Shell, gboolean, OnHighlightURLView, GtkAccelGroup*,
-                     GObject*, guint, GdkModifierType);
-  CHROMEG_CALLBACK_3(Shell, gboolean, OnReloadKeyPressed, GtkAccelGroup*,
-                     GObject*, guint, GdkModifierType);
-#endif
-
-  scoped_ptr<ShellJavaScriptDialogManager> dialog_manager_;
-
-  scoped_ptr<WebContents> web_contents_;
-
-  scoped_ptr<DevToolsWebContentsObserver> devtools_observer_;
-  ShellDevToolsFrontend* devtools_frontend_;
-
-  bool is_fullscreen_;
-
-  gfx::NativeWindow window_;
-  gfx::NativeEditView url_edit_view_;
-
-  // Notification manager
-  NotificationRegistrar registrar_;
-
-#if defined(OS_WIN) && !defined(USE_AURA)
-  WNDPROC default_edit_wnd_proc_;
-  static HINSTANCE instance_handle_;
-#elif defined(TOOLKIT_GTK)
-  GtkWidget* vbox_;
-
-  GtkToolItem* back_button_;
-  GtkToolItem* forward_button_;
-  GtkToolItem* reload_button_;
-  GtkToolItem* stop_button_;
-
-  GtkWidget* spinner_;
-  GtkToolItem* spinner_item_;
-
-  int content_width_;
-  int content_height_;
-  int ui_elements_height_; // height of menubar, toolbar, etc.
-#elif defined(OS_ANDROID)
-  base::android::ScopedJavaGlobalRef<jobject> java_object_;
-#elif defined(USE_AURA)
-#if defined(OS_CHROMEOS)
-  static content::MinimalShell* minimal_shell_;
-#endif
-  static views::ViewsDelegate* views_delegate_;
-
-  views::Widget* window_widget_;
-#elif defined(OS_MACOSX)
-  int content_width_;
-  int content_height_;
-#endif
-
-  bool headless_;
-
-  // A container of all the open windows. We use a vector so we can keep track
-  // of ordering.
-  static std::vector<Shell*> windows_;
-
-  static base::Callback<void(Shell*)> shell_created_callback_;
-
-  // True if the destructur of Shell should post a quit closure on the current
-  // message loop if the destructed Shell object was the last one.
-  static bool quit_message_loop_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_H_
diff --git a/content/shell/shell_android.cc b/content/shell/shell_android.cc
deleted file mode 100644
index d12d0d7..0000000
--- a/content/shell/shell_android.cc
+++ /dev/null
@@ -1,93 +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/shell/shell.h"
-
-#include <jni.h>
-
-#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/strings/string_piece.h"
-#include "content/public/common/content_switches.h"
-#include "content/shell/android/shell_manager.h"
-#include "jni/Shell_jni.h"
-
-using base::android::AttachCurrentThread;
-using base::android::ConvertUTF8ToJavaString;
-
-namespace content {
-
-void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  DCHECK(command_line->HasSwitch(switches::kForceCompositingMode));
-  DCHECK(command_line->HasSwitch(switches::kEnableThreadedCompositing));
-}
-
-void Shell::PlatformCleanUp() {
-}
-
-void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
-}
-
-void Shell::PlatformSetAddressBarURL(const GURL& url) {
-  JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
-  Java_Shell_onUpdateUrl(env, java_object_.obj(), j_url.obj());
-}
-
-void Shell::PlatformSetIsLoading(bool loading) {
-  JNIEnv* env = AttachCurrentThread();
-  Java_Shell_setIsLoading(env, java_object_.obj(), loading);
-}
-
-void Shell::PlatformCreateWindow(int width, int height) {
-  java_object_.Reset(AttachCurrentThread(), CreateShellView(this));
-}
-
-void Shell::PlatformSetContents() {
-  JNIEnv* env = AttachCurrentThread();
-  Java_Shell_initFromNativeTabContents(
-      env, java_object_.obj(), reinterpret_cast<jint>(web_contents()));
-}
-
-void Shell::PlatformResizeSubViews() {
-  // Not needed; subviews are bound.
-}
-
-void Shell::PlatformSetTitle(const string16& title) {
-  NOTIMPLEMENTED();
-}
-
-void Shell::LoadProgressChanged(WebContents* source, double progress) {
-  JNIEnv* env = AttachCurrentThread();
-  Java_Shell_onLoadProgressChanged(env, java_object_.obj(), progress);
-}
-
-void Shell::PlatformToggleFullscreenModeForTab(WebContents* web_contents,
-                                               bool enter_fullscreen) {
-  JNIEnv* env = AttachCurrentThread();
-  Java_Shell_toggleFullscreenModeForTab(
-      env, java_object_.obj(), enter_fullscreen);
-}
-
-bool Shell::PlatformIsFullscreenForTabOrPending(
-    const WebContents* web_contents) const {
-  JNIEnv* env = AttachCurrentThread();
-  return Java_Shell_isFullscreenForTabOrPending(env, java_object_.obj());
-}
-
-void Shell::Close() {
-  CloseShellView(java_object_.obj());
-  java_object_.Reset();
-  delete this;
-}
-
-// static
-bool Shell::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-}  // namespace content
diff --git a/content/shell/shell_application_mac.h b/content/shell/shell_application_mac.h
deleted file mode 100644
index 26718ac..0000000
--- a/content/shell/shell_application_mac.h
+++ /dev/null
@@ -1,27 +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_SHELL_SHELL_APPLICATION_MAC_H_
-#define CONTENT_SHELL_SHELL_APPLICATION_MAC_H_
-
-#include "base/mac/scoped_sending_event.h"
-#include "base/message_loop/message_pump_mac.h"
-
-@interface ShellCrApplication : NSApplication<CrAppProtocol,
-                                              CrAppControlProtocol> {
- @private
-  BOOL handlingSendEvent_;
-}
-
-// CrAppProtocol:
-- (BOOL)isHandlingSendEvent;
-
-// CrAppControlProtocol:
-- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
-
-- (IBAction)newDocument:(id)sender;
-
-@end
-
-#endif  // CONTENT_SHELL_SHELL_APPLICATION_MAC_H_
diff --git a/content/shell/shell_application_mac.mm b/content/shell/shell_application_mac.mm
deleted file mode 100644
index 8300ebf..0000000
--- a/content/shell/shell_application_mac.mm
+++ /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.
-
-#include "content/shell/shell_application_mac.h"
-
-#include "base/auto_reset.h"
-#include "content/public/common/url_constants.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "url/gurl.h"
-
-@implementation ShellCrApplication
-
-- (BOOL)isHandlingSendEvent {
-  return handlingSendEvent_;
-}
-
-- (void)sendEvent:(NSEvent*)event {
-  base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
-  [super sendEvent:event];
-}
-
-- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
-  handlingSendEvent_ = handlingSendEvent;
-}
-
-- (IBAction)newDocument:(id)sender {
-  content::ShellBrowserContext* browserContext =
-      content::ShellContentBrowserClient::Get()->browser_context();
-  content::Shell::CreateNewWindow(browserContext,
-                                  GURL(content::kAboutBlankURL),
-                                  NULL,
-                                  MSG_ROUTING_NONE,
-                                  gfx::Size());
-}
-
-@end
diff --git a/content/shell/shell_aura.cc b/content/shell/shell_aura.cc
deleted file mode 100644
index b7bf5d0..0000000
--- a/content/shell/shell_aura.cc
+++ /dev/null
@@ -1,374 +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/shell/shell.h"
-
-#include "base/command_line.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "ui/aura/env.h"
-#include "ui/aura/root_window.h"
-#include "ui/aura/window.h"
-#include "ui/base/accessibility/accessibility_types.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/events/event.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/screen.h"
-#include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/textfield/textfield.h"
-#include "ui/views/controls/textfield/textfield_controller.h"
-#include "ui/views/controls/webview/webview.h"
-#include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/grid_layout.h"
-#include "ui/views/test/desktop_test_views_delegate.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/desktop_aura/desktop_screen.h"
-#include "ui/views/widget/widget.h"
-#include "ui/views/widget/widget_delegate.h"
-
-#if defined(OS_CHROMEOS)
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "content/shell/minimal_shell.h"
-#include "ui/aura/test/test_screen.h"
-#endif
-
-namespace content {
-
-namespace {
-// ViewDelegate implementation for aura content shell
-class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate {
- public:
-  ShellViewsDelegateAura() : use_transparent_windows_(false) {
-  }
-
-  virtual ~ShellViewsDelegateAura() {
-  }
-
-  void SetUseTransparentWindows(bool transparent) {
-    use_transparent_windows_ = transparent;
-  }
-
-  // Overridden from views::TestViewsDelegate:
-  virtual bool UseTransparentWindows() const OVERRIDE {
-    return use_transparent_windows_;
-  }
-
- private:
-  bool use_transparent_windows_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura);
-};
-
-// Maintain the UI controls and web view for content shell
-class ShellWindowDelegateView : public views::WidgetDelegateView,
-                                public views::TextfieldController,
-                                public views::ButtonListener {
- public:
-  enum UIControl {
-    BACK_BUTTON,
-    FORWARD_BUTTON,
-    STOP_BUTTON
-  };
-
-  ShellWindowDelegateView(Shell* shell)
-    : shell_(shell),
-      toolbar_view_(new View),
-      contents_view_(new View) {
-  }
-  virtual ~ShellWindowDelegateView() {}
-
-  // Update the state of UI controls
-  void SetAddressBarURL(const GURL& url) {
-    url_entry_->SetText(ASCIIToUTF16(url.spec()));
-  }
-  void SetWebContents(WebContents* web_contents) {
-    contents_view_->SetLayoutManager(new views::FillLayout());
-    web_view_ = new views::WebView(web_contents->GetBrowserContext());
-    web_view_->SetWebContents(web_contents);
-    web_contents->GetView()->Focus();
-    contents_view_->AddChildView(web_view_);
-    Layout();
-  }
-  void SetWindowTitle(const string16& title) { title_ = title; }
-  void EnableUIControl(UIControl control, bool is_enabled) {
-    if (control == BACK_BUTTON) {
-      back_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
-          : views::CustomButton::STATE_DISABLED);
-    } else if (control == FORWARD_BUTTON) {
-      forward_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
-          : views::CustomButton::STATE_DISABLED);
-    } else if (control == STOP_BUTTON) {
-      stop_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
-          : views::CustomButton::STATE_DISABLED);
-    }
-  }
-
- private:
-  // Initialize the UI control contained in shell window
-  void InitShellWindow() {
-    set_background(views::Background::CreateStandardPanelBackground());
-
-    views::GridLayout* layout = new views::GridLayout(this);
-    SetLayoutManager(layout);
-
-    views::ColumnSet* column_set = layout->AddColumnSet(0);
-    column_set->AddPaddingColumn(0, 2);
-    column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
-                          views::GridLayout::USE_PREF, 0, 0);
-    column_set->AddPaddingColumn(0, 2);
-
-    layout->AddPaddingRow(0, 2);
-
-    // Add toolbar buttons and URL text field
-    {
-      layout->StartRow(0, 0);
-      views::GridLayout* toolbar_layout = new views::GridLayout(toolbar_view_);
-      toolbar_view_->SetLayoutManager(toolbar_layout);
-
-      views::ColumnSet* toolbar_column_set =
-          toolbar_layout->AddColumnSet(0);
-      // Back button
-      back_button_ = new views::LabelButton(this, ASCIIToUTF16("Back"));
-      back_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
-      gfx::Size back_button_size = back_button_->GetPreferredSize();
-      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
-                                    views::GridLayout::CENTER, 0,
-                                    views::GridLayout::FIXED,
-                                    back_button_size.width(),
-                                    back_button_size.width() / 2);
-      // Forward button
-      forward_button_ = new views::LabelButton(this, ASCIIToUTF16("Forward"));
-      forward_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
-      gfx::Size forward_button_size = forward_button_->GetPreferredSize();
-      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
-                                    views::GridLayout::CENTER, 0,
-                                    views::GridLayout::FIXED,
-                                    forward_button_size.width(),
-                                    forward_button_size.width() / 2);
-      // Refresh button
-      refresh_button_ = new views::LabelButton(this, ASCIIToUTF16("Refresh"));
-      refresh_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
-      gfx::Size refresh_button_size = refresh_button_->GetPreferredSize();
-      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
-                                    views::GridLayout::CENTER, 0,
-                                    views::GridLayout::FIXED,
-                                    refresh_button_size.width(),
-                                    refresh_button_size.width() / 2);
-      // Stop button
-      stop_button_ = new views::LabelButton(this, ASCIIToUTF16("Stop"));
-      stop_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
-      gfx::Size stop_button_size = stop_button_->GetPreferredSize();
-      toolbar_column_set->AddColumn(views::GridLayout::CENTER,
-                                    views::GridLayout::CENTER, 0,
-                                    views::GridLayout::FIXED,
-                                    stop_button_size.width(),
-                                    stop_button_size.width() / 2);
-      toolbar_column_set->AddPaddingColumn(0, 2);
-      // URL entry
-      url_entry_ = new views::Textfield();
-      url_entry_->SetController(this);
-      toolbar_column_set->AddColumn(views::GridLayout::FILL,
-                                    views::GridLayout::FILL, 1,
-                                    views::GridLayout::USE_PREF, 0, 0);
-
-      // Fill up the first row
-      toolbar_layout->StartRow(0, 0);
-      toolbar_layout->AddView(back_button_);
-      toolbar_layout->AddView(forward_button_);
-      toolbar_layout->AddView(refresh_button_);
-      toolbar_layout->AddView(stop_button_);
-      toolbar_layout->AddView(url_entry_);
-
-      layout->AddView(toolbar_view_);
-    }
-
-    layout->AddPaddingRow(0, 5);
-
-    // Add web contents view as the second row
-    {
-      layout->StartRow(1, 0);
-      layout->AddView(contents_view_);
-    }
-
-    layout->AddPaddingRow(0, 5);
-  }
-  // Overridden from TextfieldController
-  virtual void ContentsChanged(views::Textfield* sender,
-                               const string16& new_contents) OVERRIDE {
-  }
-  virtual bool HandleKeyEvent(views::Textfield* sender,
-                              const ui::KeyEvent& key_event) OVERRIDE {
-   if (sender == url_entry_ && key_event.key_code() == ui::VKEY_RETURN) {
-     std::string text = UTF16ToUTF8(url_entry_->text());
-     GURL url(text);
-     if (!url.has_scheme()) {
-       url = GURL(std::string("http://") + std::string(text));
-       url_entry_->SetText(ASCIIToUTF16(url.spec()));
-     }
-     shell_->LoadURL(url);
-     return true;
-   }
-   return false;
-  }
-
-  // Overridden from ButtonListener
-  virtual void ButtonPressed(views::Button* sender,
-                             const ui::Event& event) OVERRIDE {
-    if (sender == back_button_)
-      shell_->GoBackOrForward(-1);
-    else if (sender == forward_button_)
-      shell_->GoBackOrForward(1);
-    else if (sender == refresh_button_)
-      shell_->Reload();
-    else if (sender == stop_button_)
-      shell_->Stop();
-  }
-
-  // Overridden from WidgetDelegateView
-  virtual bool CanResize() const OVERRIDE { return true; }
-  virtual bool CanMaximize() const OVERRIDE { return true; }
-  virtual string16 GetWindowTitle() const OVERRIDE {
-    return title_;
-  }
-  virtual void WindowClosing() OVERRIDE {
-    if (shell_) {
-      delete shell_;
-      shell_ = NULL;
-    }
-  }
-  virtual View* GetContentsView() OVERRIDE { return this; }
-
-  // Overridden from View
-  virtual void ViewHierarchyChanged(
-      const ViewHierarchyChangedDetails& details) OVERRIDE {
-    if (details.is_add && details.child == this) {
-      InitShellWindow();
-    }
-  }
-
- private:
-  // Hold a reference of Shell for deleting it when the window is closing
-  Shell* shell_;
-
-  // Window title
-  string16 title_;
-
-  // Toolbar view contains forward/backward/reload button and URL entry
-  View* toolbar_view_;
-  views::LabelButton* back_button_;
-  views::LabelButton* forward_button_;
-  views::LabelButton* refresh_button_;
-  views::LabelButton* stop_button_;
-  views::Textfield* url_entry_;
-
-  // Contents view contains the web contents view
-  View* contents_view_;
-  views::WebView* web_view_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView);
-};
-
-}  // namespace
-
-#if defined(OS_CHROMEOS)
-MinimalShell* Shell::minimal_shell_ = NULL;
-#endif
-views::ViewsDelegate* Shell::views_delegate_ = NULL;
-
-// static
-void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
-#if defined(OS_CHROMEOS)
-  chromeos::DBusThreadManager::Initialize();
-  gfx::Screen::SetScreenInstance(
-      gfx::SCREEN_TYPE_NATIVE, aura::TestScreen::Create());
-  minimal_shell_ = new content::MinimalShell(default_window_size);
-#else
-  gfx::Screen::SetScreenInstance(
-      gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
-#endif
-  views_delegate_ = new ShellViewsDelegateAura();
-}
-
-void Shell::PlatformExit() {
-#if defined(OS_CHROMEOS)
-  if (minimal_shell_)
-    delete minimal_shell_;
-#endif
-  if (views_delegate_)
-    delete views_delegate_;
-#if defined(OS_CHROMEOS)
-  chromeos::DBusThreadManager::Shutdown();
-#endif
-  aura::Env::DeleteInstance();
-}
-
-void Shell::PlatformCleanUp() {
-}
-
-void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
-  ShellWindowDelegateView* delegate_view =
-    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
-  if (control == BACK_BUTTON) {
-    delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON,
-        is_enabled);
-  } else if (control == FORWARD_BUTTON) {
-    delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON,
-        is_enabled);
-  } else if (control == STOP_BUTTON) {
-    delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON,
-        is_enabled);
-  }
-}
-
-void Shell::PlatformSetAddressBarURL(const GURL& url) {
-  ShellWindowDelegateView* delegate_view =
-    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
-  delegate_view->SetAddressBarURL(url);
-}
-
-void Shell::PlatformSetIsLoading(bool loading) {
-}
-
-void Shell::PlatformCreateWindow(int width, int height) {
-#if defined(OS_CHROMEOS)
-  window_widget_ =
-      views::Widget::CreateWindowWithContextAndBounds(
-          new ShellWindowDelegateView(this),
-          minimal_shell_->GetDefaultParent(NULL, NULL, gfx::Rect()),
-          gfx::Rect(0, 0, width, height));
-#else
-  window_widget_ =
-      views::Widget::CreateWindowWithBounds(new ShellWindowDelegateView(this),
-               gfx::Rect(0, 0, width, height));
-#endif
-
-  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_widget_->Show();
-}
-
-void Shell::PlatformSetContents() {
-  ShellWindowDelegateView* delegate_view =
-    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
-  delegate_view->SetWebContents(web_contents_.get());
-}
-
-void Shell::PlatformResizeSubViews() {
-}
-
-void Shell::Close() {
-  window_widget_->Close();
-}
-
-void Shell::PlatformSetTitle(const string16& title) {
-  ShellWindowDelegateView* delegate_view =
-    static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
-  delegate_view->SetWindowTitle(title);
-  window_widget_->UpdateWindowTitle();
-}
-
-}  // namespace content
diff --git a/content/shell/shell_browser_context.cc b/content/shell/shell_browser_context.cc
deleted file mode 100644
index 1c89355..0000000
--- a/content/shell/shell_browser_context.cc
+++ /dev/null
@@ -1,215 +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/shell/shell_browser_context.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/environment.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/threading/thread.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_context.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/common/content_switches.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell_download_manager_delegate.h"
-#include "content/shell/shell_url_request_context_getter.h"
-
-#if defined(OS_WIN)
-#include "base/base_paths_win.h"
-#elif defined(OS_LINUX)
-#include "base/nix/xdg_util.h"
-#elif defined(OS_MACOSX)
-#include "base/base_paths_mac.h"
-#endif
-
-namespace content {
-
-class ShellBrowserContext::ShellResourceContext : public ResourceContext {
- public:
-  ShellResourceContext() : getter_(NULL) {}
-  virtual ~ShellResourceContext() {}
-
-  // ResourceContext implementation:
-  virtual net::HostResolver* GetHostResolver() OVERRIDE {
-    CHECK(getter_);
-    return getter_->host_resolver();
-  }
-  virtual net::URLRequestContext* GetRequestContext() OVERRIDE {
-    CHECK(getter_);
-    return getter_->GetURLRequestContext();
-  }
-  virtual bool AllowMicAccess(const GURL& origin) OVERRIDE {
-    return false;
-  }
-  virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE {
-    return false;
-  }
-
-  void set_url_request_context_getter(ShellURLRequestContextGetter* getter) {
-    getter_ = getter;
-  }
-
- private:
-  ShellURLRequestContextGetter* getter_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellResourceContext);
-};
-
-ShellBrowserContext::ShellBrowserContext(bool off_the_record,
-                                         net::NetLog* net_log)
-    : off_the_record_(off_the_record),
-      net_log_(net_log),
-      ignore_certificate_errors_(false),
-      resource_context_(new ShellResourceContext) {
-  InitWhileIOAllowed();
-}
-
-ShellBrowserContext::~ShellBrowserContext() {
-  if (resource_context_) {
-    BrowserThread::DeleteSoon(
-      BrowserThread::IO, FROM_HERE, resource_context_.release());
-  }
-}
-
-void ShellBrowserContext::InitWhileIOAllowed() {
-  CommandLine* cmd_line = CommandLine::ForCurrentProcess();
-  if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors) ||
-      cmd_line->HasSwitch(switches::kDumpRenderTree)) {
-    ignore_certificate_errors_ = true;
-  }
-  if (cmd_line->HasSwitch(switches::kContentShellDataPath)) {
-    path_ = cmd_line->GetSwitchValuePath(switches::kContentShellDataPath);
-    return;
-  }
-#if defined(OS_WIN)
-  CHECK(PathService::Get(base::DIR_LOCAL_APP_DATA, &path_));
-  path_ = path_.Append(std::wstring(L"content_shell"));
-#elif defined(OS_LINUX)
-  scoped_ptr<base::Environment> env(base::Environment::Create());
-  base::FilePath config_dir(
-      base::nix::GetXDGDirectory(env.get(),
-                                 base::nix::kXdgConfigHomeEnvVar,
-                                 base::nix::kDotConfigDir));
-  path_ = config_dir.Append("content_shell");
-#elif defined(OS_MACOSX)
-  CHECK(PathService::Get(base::DIR_APP_DATA, &path_));
-  path_ = path_.Append("Chromium Content Shell");
-#elif defined(OS_ANDROID)
-  CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &path_));
-  path_ = path_.Append(FILE_PATH_LITERAL("content_shell"));
-#else
-  NOTIMPLEMENTED();
-#endif
-
-  if (!base::PathExists(path_))
-    file_util::CreateDirectory(path_);
-}
-
-base::FilePath ShellBrowserContext::GetPath() const {
-  return path_;
-}
-
-bool ShellBrowserContext::IsOffTheRecord() const {
-  return off_the_record_;
-}
-
-DownloadManagerDelegate* ShellBrowserContext::GetDownloadManagerDelegate()  {
-  DownloadManager* manager = BrowserContext::GetDownloadManager(this);
-
-  if (!download_manager_delegate_.get()) {
-    download_manager_delegate_ = new ShellDownloadManagerDelegate();
-    download_manager_delegate_->SetDownloadManager(manager);
-    CommandLine* cmd_line = CommandLine::ForCurrentProcess();
-    if (cmd_line->HasSwitch(switches::kDumpRenderTree)) {
-      download_manager_delegate_->SetDownloadBehaviorForTesting(
-          path_.Append(FILE_PATH_LITERAL("downloads")));
-    }
-  }
-
-  return download_manager_delegate_.get();
-}
-
-net::URLRequestContextGetter* ShellBrowserContext::GetRequestContext()  {
-  return GetDefaultStoragePartition(this)->GetURLRequestContext();
-}
-
-net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext(
-    ProtocolHandlerMap* protocol_handlers) {
-  DCHECK(!url_request_getter_.get());
-  url_request_getter_ = new ShellURLRequestContextGetter(
-      ignore_certificate_errors_,
-      GetPath(),
-      BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO),
-      BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE),
-      protocol_handlers,
-      net_log_);
-  resource_context_->set_url_request_context_getter(url_request_getter_.get());
-  return url_request_getter_.get();
-}
-
-net::URLRequestContextGetter*
-    ShellBrowserContext::GetRequestContextForRenderProcess(
-        int renderer_child_id)  {
-  return GetRequestContext();
-}
-
-net::URLRequestContextGetter*
-    ShellBrowserContext::GetMediaRequestContext()  {
-  return GetRequestContext();
-}
-
-net::URLRequestContextGetter*
-    ShellBrowserContext::GetMediaRequestContextForRenderProcess(
-        int renderer_child_id)  {
-  return GetRequestContext();
-}
-
-net::URLRequestContextGetter*
-    ShellBrowserContext::GetMediaRequestContextForStoragePartition(
-        const base::FilePath& partition_path,
-        bool in_memory) {
-  return GetRequestContext();
-}
-
-void ShellBrowserContext::RequestMIDISysExPermission(
-      int render_process_id,
-      int render_view_id,
-      const GURL& requesting_frame,
-      const MIDISysExPermissionCallback& callback) {
-  // Always reject requests for LayoutTests for now.
-  // TODO(toyoshim): Make it programmable to improve test coverage.
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
-    callback.Run(false);
-    return;
-  }
-  // TODO(toyoshim): Implement. http://crbug.com/257618 .
-  callback.Run(false);
-}
-
-net::URLRequestContextGetter*
-    ShellBrowserContext::CreateRequestContextForStoragePartition(
-        const base::FilePath& partition_path,
-        bool in_memory,
-        ProtocolHandlerMap* protocol_handlers) {
-  return NULL;
-}
-
-ResourceContext* ShellBrowserContext::GetResourceContext()  {
-  return resource_context_.get();
-}
-
-GeolocationPermissionContext*
-    ShellBrowserContext::GetGeolocationPermissionContext()  {
-  return NULL;
-}
-
-quota::SpecialStoragePolicy* ShellBrowserContext::GetSpecialStoragePolicy() {
-  return NULL;
-}
-
-}  // namespace content
diff --git a/content/shell/shell_browser_context.h b/content/shell/shell_browser_context.h
deleted file mode 100644
index 640f237..0000000
--- a/content/shell/shell_browser_context.h
+++ /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.
-
-#ifndef CONTENT_SHELL_SHELL_BROWSER_CONTEXT_H_
-#define CONTENT_SHELL_SHELL_BROWSER_CONTEXT_H_
-
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/content_browser_client.h"
-#include "net/url_request/url_request_job_factory.h"
-
-namespace net {
-class NetLog;
-}
-
-namespace content {
-
-class DownloadManagerDelegate;
-class ResourceContext;
-class ShellDownloadManagerDelegate;
-class ShellURLRequestContextGetter;
-
-class ShellBrowserContext : public BrowserContext {
- public:
-  ShellBrowserContext(bool off_the_record, net::NetLog* net_log);
-  virtual ~ShellBrowserContext();
-
-  // BrowserContext implementation.
-  virtual base::FilePath GetPath() const OVERRIDE;
-  virtual bool IsOffTheRecord() const OVERRIDE;
-  virtual DownloadManagerDelegate* GetDownloadManagerDelegate() OVERRIDE;
-  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
-  virtual net::URLRequestContextGetter* GetRequestContextForRenderProcess(
-      int renderer_child_id) OVERRIDE;
-  virtual net::URLRequestContextGetter* GetMediaRequestContext() OVERRIDE;
-  virtual net::URLRequestContextGetter* GetMediaRequestContextForRenderProcess(
-      int renderer_child_id) OVERRIDE;
-  virtual net::URLRequestContextGetter*
-      GetMediaRequestContextForStoragePartition(
-          const base::FilePath& partition_path,
-          bool in_memory) OVERRIDE;
-  virtual void RequestMIDISysExPermission(
-      int render_process_id,
-      int render_view_id,
-      const GURL& requesting_frame,
-      const MIDISysExPermissionCallback& callback) OVERRIDE;
-  virtual ResourceContext* GetResourceContext() OVERRIDE;
-  virtual GeolocationPermissionContext*
-      GetGeolocationPermissionContext() OVERRIDE;
-  virtual quota::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE;
-
-  net::URLRequestContextGetter* CreateRequestContext(
-      ProtocolHandlerMap* protocol_handlers);
-  net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
-      const base::FilePath& partition_path,
-      bool in_memory,
-      ProtocolHandlerMap* protocol_handlers);
-
- private:
-  class ShellResourceContext;
-
-  // Performs initialization of the ShellBrowserContext while IO is still
-  // allowed on the current thread.
-  void InitWhileIOAllowed();
-
-  bool off_the_record_;
-  net::NetLog* net_log_;
-  bool ignore_certificate_errors_;
-  base::FilePath path_;
-  scoped_ptr<ShellResourceContext> resource_context_;
-  scoped_refptr<ShellDownloadManagerDelegate> download_manager_delegate_;
-  scoped_refptr<ShellURLRequestContextGetter> url_request_getter_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellBrowserContext);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_BROWSER_CONTEXT_H_
diff --git a/content/shell/shell_browser_main.cc b/content/shell/shell_browser_main.cc
deleted file mode 100644
index d4d65a3..0000000
--- a/content/shell/shell_browser_main.cc
+++ /dev/null
@@ -1,214 +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/shell/shell_browser_main.h"
-
-#include <iostream>
-
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/files/file_path.h"
-#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/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_restrictions.h"
-#include "content/public/browser/browser_main_runner.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/common/webkit_test_helpers.h"
-#include "content/shell/shell.h"
-#include "content/shell/webkit_test_controller.h"
-#include "net/base/net_util.h"
-#include "webkit/support/webkit_support.h"
-
-#if defined(OS_ANDROID)
-#include "base/run_loop.h"
-#include "content/shell/shell_layout_tests_android.h"
-#endif
-
-namespace {
-
-GURL GetURLForLayoutTest(const std::string& test_name,
-                         base::FilePath* current_working_directory,
-                         bool* enable_pixel_dumping,
-                         std::string* expected_pixel_hash) {
-  // A test name is formated like file:///path/to/test'--pixel-test'pixelhash
-  std::string path_or_url = test_name;
-  std::string pixel_switch;
-  std::string pixel_hash;
-  std::string::size_type separator_position = path_or_url.find('\'');
-  if (separator_position != std::string::npos) {
-    pixel_switch = path_or_url.substr(separator_position + 1);
-    path_or_url.erase(separator_position);
-  }
-  separator_position = pixel_switch.find('\'');
-  if (separator_position != std::string::npos) {
-    pixel_hash = pixel_switch.substr(separator_position + 1);
-    pixel_switch.erase(separator_position);
-  }
-  if (enable_pixel_dumping) {
-    *enable_pixel_dumping =
-        (pixel_switch == "--pixel-test" || pixel_switch == "-p");
-  }
-  if (expected_pixel_hash)
-    *expected_pixel_hash = pixel_hash;
-
-  GURL test_url;
-#if defined(OS_ANDROID)
-  if (content::GetTestUrlForAndroid(path_or_url, &test_url))
-    return test_url;
-#endif
-
-  test_url = GURL(path_or_url);
-  if (!(test_url.is_valid() && test_url.has_scheme())) {
-    // We're outside of the message loop here, and this is a test.
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
-#if defined(OS_WIN)
-    std::wstring wide_path_or_url =
-        base::SysNativeMBToWide(path_or_url);
-    base::FilePath local_file(wide_path_or_url);
-#else
-    base::FilePath local_file(path_or_url);
-#endif
-    if (!base::PathExists(local_file)) {
-      local_file = content::GetWebKitRootDirFilePath()
-          .Append(FILE_PATH_LITERAL("LayoutTests")).Append(local_file);
-    }
-    test_url = net::FilePathToFileURL(base::MakeAbsoluteFilePath(local_file));
-  }
-  base::FilePath local_path;
-  if (current_working_directory) {
-    // We're outside of the message loop here, and this is a test.
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
-    if (net::FileURLToFilePath(test_url, &local_path))
-      *current_working_directory = local_path.DirName();
-    else
-      file_util::GetCurrentDirectory(current_working_directory);
-  }
-  return test_url;
-}
-
-bool GetNextTest(const CommandLine::StringVector& args,
-                 size_t* position,
-                 std::string* test) {
-  if (*position >= args.size())
-    return false;
-  if (args[*position] == FILE_PATH_LITERAL("-"))
-    return !!std::getline(std::cin, *test, '\n');
-#if defined(OS_WIN)
-  *test = WideToUTF8(args[(*position)++]);
-#else
-  *test = args[(*position)++];
-#endif
-  return true;
-}
-
-}  // namespace
-
-// Main routine for running as the Browser process.
-int ShellBrowserMain(
-    const content::MainFunctionParams& parameters,
-    const scoped_ptr<content::BrowserMainRunner>& main_runner) {
-  bool layout_test_mode =
-      CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
-  base::ScopedTempDir browser_context_path_for_layout_tests;
-
-  if (layout_test_mode) {
-    CHECK(browser_context_path_for_layout_tests.CreateUniqueTempDir());
-    CHECK(!browser_context_path_for_layout_tests.path().MaybeAsASCII().empty());
-    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kContentShellDataPath,
-        browser_context_path_for_layout_tests.path().MaybeAsASCII());
-
-#if defined(OS_ANDROID)
-    content::EnsureInitializeForAndroidLayoutTests();
-#endif
-  }
-
-  int exit_code = main_runner->Initialize(parameters);
-  DCHECK_LT(exit_code, 0)
-      << "BrowserMainRunner::Initialize failed in ShellBrowserMain";
-
-  if (exit_code >= 0)
-    return exit_code;
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-        switches::kCheckLayoutTestSysDeps)) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
-    main_runner->Run();
-    content::Shell::CloseAllWindows();
-    main_runner->Shutdown();
-    return 0;
-  }
-
-  if (layout_test_mode) {
-    content::WebKitTestController test_controller;
-    {
-      // We're outside of the message loop here, and this is a test.
-      base::ThreadRestrictions::ScopedAllowIO allow_io;
-      base::FilePath temp_path;
-      file_util::GetTempDir(&temp_path);
-      test_controller.SetTempPath(temp_path);
-    }
-    std::string test_string;
-    CommandLine::StringVector args =
-        CommandLine::ForCurrentProcess()->GetArgs();
-    size_t command_line_position = 0;
-    bool ran_at_least_once = false;
-
-#if defined(OS_ANDROID)
-    std::cout << "#READY\n";
-    std::cout.flush();
-#endif
-
-    while (GetNextTest(args, &command_line_position, &test_string)) {
-      if (test_string.empty())
-        continue;
-      if (test_string == "QUIT")
-        break;
-
-      bool enable_pixel_dumps;
-      std::string pixel_hash;
-      base::FilePath cwd;
-      GURL test_url = GetURLForLayoutTest(
-          test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
-      if (!content::WebKitTestController::Get()->PrepareForLayoutTest(
-              test_url, cwd, enable_pixel_dumps, pixel_hash)) {
-        break;
-      }
-
-      ran_at_least_once = true;
-#if defined(OS_ANDROID)
-      // The message loop on Android is provided by the system, and does not
-      // offer a blocking Run() method. For layout tests, use a nested loop
-      // together with a base::RunLoop so it can block until a QuitClosure.
-      base::RunLoop run_loop;
-      run_loop.Run();
-#else
-      main_runner->Run();
-#endif
-
-      if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())
-        break;
-    }
-    if (!ran_at_least_once) {
-      base::MessageLoop::current()->PostTask(FROM_HERE,
-                                             base::MessageLoop::QuitClosure());
-      main_runner->Run();
-    }
-    exit_code = 0;
-  }
-
-#if !defined(OS_ANDROID)
-  if (!layout_test_mode)
-    exit_code = main_runner->Run();
-
-  main_runner->Shutdown();
-#endif
-
-  return exit_code;
-}
diff --git a/content/shell/shell_browser_main.h b/content/shell/shell_browser_main.h
deleted file mode 100644
index 7fe5908..0000000
--- a/content/shell/shell_browser_main.h
+++ /dev/null
@@ -1,19 +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_SHELL_SHELL_BROWSER_MAIN_H_
-#define CONTENT_SHELL_SHELL_BROWSER_MAIN_H_
-
-#include "base/memory/scoped_ptr.h"
-
-namespace content {
-class BrowserMainRunner;
-struct MainFunctionParams;
-}
-
-int ShellBrowserMain(
-    const content::MainFunctionParams& parameters,
-    const scoped_ptr<content::BrowserMainRunner>& main_runner);
-
-#endif  // CONTENT_SHELL_SHELL_BROWSER_MAIN_H_
diff --git a/content/shell/shell_browser_main_parts.cc b/content/shell/shell_browser_main_parts.cc
deleted file mode 100644
index bf7233a..0000000
--- a/content/shell/shell_browser_main_parts.cc
+++ /dev/null
@@ -1,175 +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/shell/shell_browser_main_parts.h"
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "cc/base/switches.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/main_function_params.h"
-#include "content/public/common/url_constants.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_devtools_delegate.h"
-#include "content/shell/shell_net_log.h"
-#include "grit/net_resources.h"
-#include "net/base/net_module.h"
-#include "net/base/net_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "url/gurl.h"
-#include "webkit/browser/quota/quota_manager.h"
-
-#if defined(ENABLE_PLUGINS)
-#include "content/public/browser/plugin_service.h"
-#include "content/shell/shell_plugin_service_filter.h"
-#endif
-
-#if defined(OS_ANDROID)
-#include "net/android/network_change_notifier_factory_android.h"
-#include "net/base/network_change_notifier.h"
-#endif
-
-#if defined(USE_AURA) && defined(USE_X11)
-#include "ui/base/touch/touch_factory_x11.h"
-#endif
-
-namespace content {
-
-namespace {
-
-// Default quota for each origin is 5MB.
-const int kDefaultLayoutTestQuotaBytes = 5 * 1024 * 1024;
-
-GURL GetStartupURL() {
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kContentBrowserTest))
-    return GURL();
-  const CommandLine::StringVector& args = command_line->GetArgs();
-
-#if defined(OS_ANDROID)
-  // Delay renderer creation on Android until surface is ready.
-  return GURL();
-#endif
-
-  if (args.empty())
-    return GURL("http://www.google.com/");
-
-  GURL url(args[0]);
-  if (url.is_valid() && url.has_scheme())
-    return url;
-
-  return net::FilePathToFileURL(base::FilePath(args[0]));
-}
-
-base::StringPiece PlatformResourceProvider(int key) {
-  if (key == IDR_DIR_HEADER_HTML) {
-    base::StringPiece html_data =
-        ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
-            IDR_DIR_HEADER_HTML);
-    return html_data;
-  }
-  return base::StringPiece();
-}
-
-}  // namespace
-
-ShellBrowserMainParts::ShellBrowserMainParts(
-    const MainFunctionParams& parameters)
-    : BrowserMainParts(), parameters_(parameters), run_message_loop_(true) {}
-
-ShellBrowserMainParts::~ShellBrowserMainParts() {
-}
-
-#if !defined(OS_MACOSX)
-void ShellBrowserMainParts::PreMainMessageLoopStart() {
-#if defined(USE_AURA) && defined(USE_X11)
-  ui::TouchFactory::SetTouchDeviceListFromCommandLine();
-#endif
-}
-#endif
-
-void ShellBrowserMainParts::PostMainMessageLoopStart() {
-#if defined(OS_ANDROID)
-  base::MessageLoopForUI::current()->Start();
-#endif
-}
-
-void ShellBrowserMainParts::PreEarlyInitialization() {
-#if defined(OS_ANDROID)
-  net::NetworkChangeNotifier::SetFactory(
-      new net::NetworkChangeNotifierFactoryAndroid());
-
-  CommandLine::ForCurrentProcess()->AppendSwitch(
-      cc::switches::kCompositeToMailbox);
-#endif
-}
-
-void ShellBrowserMainParts::PreMainMessageLoopRun() {
-  net_log_.reset(new ShellNetLog());
-  browser_context_.reset(new ShellBrowserContext(false, net_log_.get()));
-  off_the_record_browser_context_.reset(
-      new ShellBrowserContext(true, net_log_.get()));
-
-  Shell::Initialize();
-  net::NetModule::SetResourceProvider(PlatformResourceProvider);
-
-  devtools_delegate_.reset(new ShellDevToolsDelegate(browser_context_.get()));
-
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
-    Shell::CreateNewWindow(browser_context_.get(),
-                           GetStartupURL(),
-                           NULL,
-                           MSG_ROUTING_NONE,
-                           gfx::Size());
-  }
-
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
-    quota::QuotaManager* quota_manager =
-        BrowserContext::GetDefaultStoragePartition(browser_context())
-            ->GetQuotaManager();
-    BrowserThread::PostTask(
-        BrowserThread::IO,
-        FROM_HERE,
-        base::Bind(&quota::QuotaManager::SetTemporaryGlobalOverrideQuota,
-                   quota_manager,
-                   kDefaultLayoutTestQuotaBytes *
-                       quota::QuotaManager::kPerHostTemporaryPortion,
-                   quota::QuotaCallback()));
-#if defined(ENABLE_PLUGINS)
-    PluginService* plugin_service = PluginService::GetInstance();
-    plugin_service_filter_.reset(new ShellPluginServiceFilter);
-    plugin_service->SetFilter(plugin_service_filter_.get());
-#endif
-  }
-
-  if (parameters_.ui_task) {
-    parameters_.ui_task->Run();
-    delete parameters_.ui_task;
-    run_message_loop_ = false;
-  }
-}
-
-bool ShellBrowserMainParts::MainMessageLoopRun(int* result_code)  {
-  return !run_message_loop_;
-}
-
-void ShellBrowserMainParts::PostMainMessageLoopRun() {
-#if defined(USE_AURA)
-  Shell::PlatformExit();
-#endif
-  if (devtools_delegate_)
-    devtools_delegate_->Stop();
-  browser_context_.reset();
-  off_the_record_browser_context_.reset();
-}
-
-}  // namespace
diff --git a/content/shell/shell_browser_main_parts.h b/content/shell/shell_browser_main_parts.h
deleted file mode 100644
index 25a4449..0000000
--- a/content/shell/shell_browser_main_parts.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 CONTENT_SHELL_SHELL_BROWSER_MAIN_PARTS_H_
-#define CONTENT_SHELL_SHELL_BROWSER_MAIN_PARTS_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/browser_main_parts.h"
-#include "content/public/common/main_function_params.h"
-
-namespace base {
-class Thread;
-}
-
-namespace net {
-class NetLog;
-}
-
-namespace content {
-
-class ShellBrowserContext;
-class ShellDevToolsDelegate;
-class ShellPluginServiceFilter;
-
-class ShellBrowserMainParts : public BrowserMainParts {
- public:
-  explicit ShellBrowserMainParts(const MainFunctionParams& parameters);
-  virtual ~ShellBrowserMainParts();
-
-  // BrowserMainParts overrides.
-  virtual void PreEarlyInitialization() OVERRIDE;
-  virtual void PreMainMessageLoopStart() OVERRIDE;
-  virtual void PostMainMessageLoopStart() OVERRIDE;
-  virtual void PreMainMessageLoopRun() OVERRIDE;
-  virtual bool MainMessageLoopRun(int* result_code) OVERRIDE;
-  virtual void PostMainMessageLoopRun() OVERRIDE;
-
-  ShellDevToolsDelegate* devtools_delegate() {
-    return devtools_delegate_.get();
-  }
-
-  ShellBrowserContext* browser_context() { return browser_context_.get(); }
-  ShellBrowserContext* off_the_record_browser_context() {
-    return off_the_record_browser_context_.get();
-  }
-
-  net::NetLog* net_log() { return net_log_.get(); }
-
- private:
-  scoped_ptr<net::NetLog> net_log_;
-  scoped_ptr<ShellBrowserContext> browser_context_;
-  scoped_ptr<ShellBrowserContext> off_the_record_browser_context_;
-
-  // For running content_browsertests.
-  const MainFunctionParams parameters_;
-  bool run_message_loop_;
-
-  scoped_ptr<ShellDevToolsDelegate> devtools_delegate_;
-#if defined(ENABLE_PLUGINS)
-  scoped_ptr<ShellPluginServiceFilter> plugin_service_filter_;
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(ShellBrowserMainParts);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_BROWSER_MAIN_PARTS_H_
diff --git a/content/shell/shell_browser_main_parts_mac.mm b/content/shell/shell_browser_main_parts_mac.mm
deleted file mode 100644
index b2b84b7..0000000
--- a/content/shell/shell_browser_main_parts_mac.mm
+++ /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.
-
-#include "content/shell/shell_browser_main_parts.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/bundle_locations.h"
-#include "base/mac/scoped_nsobject.h"
-#include "content/shell/shell_application_mac.h"
-
-namespace content {
-
-void ShellBrowserMainParts::PreMainMessageLoopStart() {
-  // Force the NSApplication subclass to be used.
-  [ShellCrApplication sharedApplication];
-
-  base::scoped_nsobject<NSNib> nib(
-      [[NSNib alloc] initWithNibNamed:@"MainMenu"
-                               bundle:base::mac::FrameworkBundle()]);
-  [nib instantiateNibWithOwner:NSApp topLevelObjects:nil];
-}
-
-}  // namespace content
diff --git a/content/shell/shell_content_browser_client.cc b/content/shell/shell_content_browser_client.cc
deleted file mode 100644
index ac37954..0000000
--- a/content/shell/shell_content_browser_client.cc
+++ /dev/null
@@ -1,275 +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/shell/shell_content_browser_client.h"
-
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/path_service.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/resource_dispatcher_host.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/url_constants.h"
-#include "content/shell/common/shell_messages.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/common/webkit_test_helpers.h"
-#include "content/shell/geolocation/shell_access_token_store.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_browser_main_parts.h"
-#include "content/shell/shell_devtools_delegate.h"
-#include "content/shell/shell_message_filter.h"
-#include "content/shell/shell_net_log.h"
-#include "content/shell/shell_quota_permission_context.h"
-#include "content/shell/shell_resource_dispatcher_host_delegate.h"
-#include "content/shell/shell_web_contents_view_delegate_creator.h"
-#include "content/shell/webkit_test_controller.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "url/gurl.h"
-#include "webkit/common/webpreferences.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/path_utils.h"
-#include "base/path_service.h"
-#include "base/platform_file.h"
-#include "content/shell/android/shell_descriptors.h"
-#endif
-
-namespace content {
-
-namespace {
-
-ShellContentBrowserClient* g_browser_client;
-bool g_swap_processes_for_redirect = false;
-
-}  // namespace
-
-ShellContentBrowserClient* ShellContentBrowserClient::Get() {
-  return g_browser_client;
-}
-
-void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
-  g_swap_processes_for_redirect = swap;
-}
-
-ShellContentBrowserClient::ShellContentBrowserClient()
-    : shell_browser_main_parts_(NULL) {
-  DCHECK(!g_browser_client);
-  g_browser_client = this;
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-  webkit_source_dir_ = GetWebKitRootDirFilePath();
-}
-
-ShellContentBrowserClient::~ShellContentBrowserClient() {
-  g_browser_client = NULL;
-}
-
-BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
-    const MainFunctionParams& parameters) {
-  shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
-  return shell_browser_main_parts_;
-}
-
-void ShellContentBrowserClient::RenderProcessHostCreated(
-    RenderProcessHost* host) {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-  host->GetChannel()->AddFilter(new ShellMessageFilter(
-      host->GetID(),
-      BrowserContext::GetDefaultStoragePartition(browser_context())
-          ->GetDatabaseTracker(),
-      BrowserContext::GetDefaultStoragePartition(browser_context())
-          ->GetQuotaManager(),
-      BrowserContext::GetDefaultStoragePartition(browser_context())
-          ->GetURLRequestContext()));
-  host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_));
-  registrar_.Add(this,
-                 NOTIFICATION_RENDERER_PROCESS_CREATED,
-                 Source<RenderProcessHost>(host));
-  registrar_.Add(this,
-                 NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-                 Source<RenderProcessHost>(host));
-}
-
-net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
-    BrowserContext* content_browser_context,
-    ProtocolHandlerMap* protocol_handlers) {
-  ShellBrowserContext* shell_browser_context =
-      ShellBrowserContextForBrowserContext(content_browser_context);
-  return shell_browser_context->CreateRequestContext(protocol_handlers);
-}
-
-net::URLRequestContextGetter*
-ShellContentBrowserClient::CreateRequestContextForStoragePartition(
-    BrowserContext* content_browser_context,
-    const base::FilePath& partition_path,
-    bool in_memory,
-    ProtocolHandlerMap* protocol_handlers) {
-  ShellBrowserContext* shell_browser_context =
-      ShellBrowserContextForBrowserContext(content_browser_context);
-  return shell_browser_context->CreateRequestContextForStoragePartition(
-      partition_path, in_memory, protocol_handlers);
-}
-
-bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
-  if (!url.is_valid())
-    return false;
-  DCHECK_EQ(url.scheme(), StringToLowerASCII(url.scheme()));
-  // Keep in sync with ProtocolHandlers added by
-  // ShellURLRequestContextGetter::GetURLRequestContext().
-  static const char* const kProtocolList[] = {
-      chrome::kBlobScheme,
-      chrome::kFileSystemScheme,
-      chrome::kChromeUIScheme,
-      chrome::kChromeDevToolsScheme,
-      chrome::kDataScheme,
-      chrome::kFileScheme,
-  };
-  for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
-    if (url.scheme() == kProtocolList[i])
-      return true;
-  }
-  return false;
-}
-
-void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
-    CommandLine* command_line, int child_process_id) {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    command_line->AppendSwitch(switches::kDumpRenderTree);
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kExposeInternalsForTesting))
-    command_line->AppendSwitch(switches::kExposeInternalsForTesting);
-}
-
-void ShellContentBrowserClient::OverrideWebkitPrefs(
-    RenderViewHost* render_view_host,
-    const GURL& url,
-    WebPreferences* prefs) {
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-  WebKitTestController::Get()->OverrideWebkitPrefs(prefs);
-}
-
-void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
-  resource_dispatcher_host_delegate_.reset(
-      new ShellResourceDispatcherHostDelegate());
-  ResourceDispatcherHost::Get()->SetDelegate(
-      resource_dispatcher_host_delegate_.get());
-}
-
-std::string ShellContentBrowserClient::GetDefaultDownloadName() {
-  return "download";
-}
-
-bool ShellContentBrowserClient::SupportsBrowserPlugin(
-    content::BrowserContext* browser_context, const GURL& url) {
-  return CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kEnableBrowserPluginForAllViewTypes);
-}
-
-WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate(
-    WebContents* web_contents) {
-#if !defined(USE_AURA)
-  return CreateShellWebContentsViewDelegate(web_contents);
-#else
-  return NULL;
-#endif
-}
-
-QuotaPermissionContext*
-ShellContentBrowserClient::CreateQuotaPermissionContext() {
-  return new ShellQuotaPermissionContext();
-}
-
-net::NetLog* ShellContentBrowserClient::GetNetLog() {
-  return shell_browser_main_parts_->net_log();
-}
-
-bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
-    ResourceContext* resource_context,
-    const GURL& current_url,
-    const GURL& new_url) {
-  return g_swap_processes_for_redirect;
-}
-
-#if defined(OS_ANDROID)
-void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
-    const CommandLine& command_line,
-    int child_process_id,
-    std::vector<content::FileDescriptorInfo>* mappings) {
-  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);
-  CHECK(r);
-  pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
-  pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
-
-  base::PlatformFile f =
-      base::CreatePlatformFile(pak_file, flags, NULL, NULL);
-  if (f == base::kInvalidPlatformFileValue) {
-    NOTREACHED() << "Failed to open file when creating renderer process: "
-                 << "content_shell.pak";
-  }
-  mappings->push_back(
-      content::FileDescriptorInfo(kShellPakDescriptor,
-                                  base::FileDescriptor(f, true)));
-}
-#endif
-
-void ShellContentBrowserClient::Observe(int type,
-                                        const NotificationSource& source,
-                                        const NotificationDetails& details) {
-  switch (type) {
-    case NOTIFICATION_RENDERER_PROCESS_CREATED: {
-      registrar_.Remove(this,
-                        NOTIFICATION_RENDERER_PROCESS_CREATED,
-                        source);
-      registrar_.Remove(this,
-                        NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-                        source);
-      break;
-    }
-
-    case NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
-      registrar_.Remove(this,
-                        NOTIFICATION_RENDERER_PROCESS_CREATED,
-                        source);
-      registrar_.Remove(this,
-                        NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-                        source);
-      break;
-    }
-
-    default:
-      NOTREACHED();
-  }
-}
-
-ShellBrowserContext* ShellContentBrowserClient::browser_context() {
-  return shell_browser_main_parts_->browser_context();
-}
-
-ShellBrowserContext*
-    ShellContentBrowserClient::off_the_record_browser_context() {
-  return shell_browser_main_parts_->off_the_record_browser_context();
-}
-
-AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
-  return new ShellAccessTokenStore(browser_context());
-}
-
-ShellBrowserContext*
-ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
-    BrowserContext* content_browser_context) {
-  if (content_browser_context == browser_context())
-    return browser_context();
-  DCHECK_EQ(content_browser_context, off_the_record_browser_context());
-  return off_the_record_browser_context();
-}
-
-}  // namespace content
diff --git a/content/shell/shell_content_browser_client.h b/content/shell/shell_content_browser_client.h
deleted file mode 100644
index 917a955..0000000
--- a/content/shell/shell_content_browser_client.h
+++ /dev/null
@@ -1,103 +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_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_
-#define CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/platform_file.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-
-namespace content {
-
-class ShellBrowserContext;
-class ShellBrowserMainParts;
-class ShellResourceDispatcherHostDelegate;
-
-class ShellContentBrowserClient : public ContentBrowserClient,
-                                  public NotificationObserver {
- public:
-  // Gets the current instance.
-  static ShellContentBrowserClient* Get();
-
-  static void SetSwapProcessesForRedirect(bool swap);
-
-  ShellContentBrowserClient();
-  virtual ~ShellContentBrowserClient();
-
-  // ContentBrowserClient overrides.
-  virtual BrowserMainParts* CreateBrowserMainParts(
-      const MainFunctionParams& parameters) OVERRIDE;
-  virtual void RenderProcessHostCreated(RenderProcessHost* host) OVERRIDE;
-  virtual net::URLRequestContextGetter* CreateRequestContext(
-      BrowserContext* browser_context,
-      ProtocolHandlerMap* protocol_handlers) OVERRIDE;
-  virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
-      BrowserContext* browser_context,
-      const base::FilePath& partition_path,
-      bool in_memory,
-      ProtocolHandlerMap* protocol_handlers) OVERRIDE;
-  virtual bool IsHandledURL(const GURL& url) OVERRIDE;
-  virtual void AppendExtraCommandLineSwitches(CommandLine* command_line,
-                                              int child_process_id) OVERRIDE;
-  virtual void OverrideWebkitPrefs(RenderViewHost* render_view_host,
-                                   const GURL& url,
-                                   WebPreferences* prefs) OVERRIDE;
-  virtual void ResourceDispatcherHostCreated() OVERRIDE;
-  virtual AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
-  virtual std::string GetDefaultDownloadName() OVERRIDE;
-  virtual bool SupportsBrowserPlugin(content::BrowserContext* browser_context,
-                                     const GURL& url) OVERRIDE;
-  virtual WebContentsViewDelegate* GetWebContentsViewDelegate(
-      WebContents* web_contents) OVERRIDE;
-  virtual QuotaPermissionContext* CreateQuotaPermissionContext() OVERRIDE;
-  virtual net::NetLog* GetNetLog() OVERRIDE;
-  virtual bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context,
-                                              const GURL& current_url,
-                                              const GURL& new_url) OVERRIDE;
-
-#if defined(OS_ANDROID)
-  virtual void GetAdditionalMappedFilesForChildProcess(
-      const CommandLine& command_line,
-      int child_process_id,
-      std::vector<content::FileDescriptorInfo>* mappings) OVERRIDE;
-#endif
-
-  // NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details) OVERRIDE;
-
-  ShellBrowserContext* browser_context();
-  ShellBrowserContext* off_the_record_browser_context();
-  ShellResourceDispatcherHostDelegate* resource_dispatcher_host_delegate() {
-    return resource_dispatcher_host_delegate_.get();
-  }
-  ShellBrowserMainParts* shell_browser_main_parts() {
-    return shell_browser_main_parts_;
-  }
-
- private:
-  ShellBrowserContext* ShellBrowserContextForBrowserContext(
-      BrowserContext* content_browser_context);
-
-  scoped_ptr<ShellResourceDispatcherHostDelegate>
-      resource_dispatcher_host_delegate_;
-
-  base::FilePath webkit_source_dir_;
-
-  ShellBrowserMainParts* shell_browser_main_parts_;
-
-  NotificationRegistrar registrar_;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_
diff --git a/content/shell/shell_devtools_delegate.cc b/content/shell/shell_devtools_delegate.cc
deleted file mode 100644
index d6fe39c..0000000
--- a/content/shell/shell_devtools_delegate.cc
+++ /dev/null
@@ -1,119 +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/shell/shell_devtools_delegate.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/strings/string_number_conversions.h"
-#include "content/public/browser/devtools_http_handler.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/url_constants.h"
-#include "content/shell/shell.h"
-#include "grit/shell_resources.h"
-#include "net/socket/tcp_listen_socket.h"
-#include "ui/base/resource/resource_bundle.h"
-
-#if defined(OS_ANDROID)
-#include "content/public/browser/android/devtools_auth.h"
-#include "net/socket/unix_domain_socket_posix.h"
-#endif
-
-namespace {
-
-net::StreamListenSocketFactory* CreateSocketFactory() {
-  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-#if defined(OS_ANDROID)
-  std::string socket_name = "content_shell_devtools_remote";
-  if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
-    socket_name = command_line.GetSwitchValueASCII(
-        switches::kRemoteDebuggingSocketName);
-  }
-  return new net::UnixDomainSocketWithAbstractNamespaceFactory(
-      socket_name, "", base::Bind(&content::CanUserConnectToDevTools));
-#else
-  // See if the user specified a port on the command line (useful for
-  // automation). If not, use an ephemeral port by specifying 0.
-  int port = 0;
-  if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
-    int temp_port;
-    std::string port_str =
-        command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
-    if (base::StringToInt(port_str, &temp_port) &&
-        temp_port > 0 && temp_port < 65535) {
-      port = temp_port;
-    } else {
-      DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
-    }
-  }
-  return new net::TCPListenSocketFactory("127.0.0.1", port);
-#endif
-}
-}  // namespace
-
-namespace content {
-
-ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext* browser_context)
-    : browser_context_(browser_context) {
-  // Note that Content Shell always used bundled DevTools frontend,
-  // even on Android, because the shell is used for running layout tests.
-  devtools_http_handler_ =
-      DevToolsHttpHandler::Start(CreateSocketFactory(), std::string(), this);
-}
-
-ShellDevToolsDelegate::~ShellDevToolsDelegate() {
-}
-
-void ShellDevToolsDelegate::Stop() {
-  // The call below destroys this.
-  devtools_http_handler_->Stop();
-}
-
-std::string ShellDevToolsDelegate::GetDiscoveryPageHTML() {
-  return ResourceBundle::GetSharedInstance().GetRawDataResource(
-      IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE).as_string();
-}
-
-bool ShellDevToolsDelegate::BundlesFrontendResources() {
-  return true;
-}
-
-base::FilePath ShellDevToolsDelegate::GetDebugFrontendDir() {
-  return base::FilePath();
-}
-
-std::string ShellDevToolsDelegate::GetPageThumbnailData(const GURL& url) {
-  return std::string();
-}
-
-RenderViewHost* ShellDevToolsDelegate::CreateNewTarget() {
-  Shell* shell = Shell::CreateNewWindow(browser_context_,
-                                        GURL(kAboutBlankURL),
-                                        NULL,
-                                        MSG_ROUTING_NONE,
-                                        gfx::Size());
-  return shell->web_contents()->GetRenderViewHost();
-}
-
-DevToolsHttpHandlerDelegate::TargetType
-ShellDevToolsDelegate::GetTargetType(RenderViewHost*) {
-  return kTargetTypeTab;
-}
-
-std::string ShellDevToolsDelegate::GetViewDescription(
-    content::RenderViewHost*) {
-  return std::string();
-}
-
-scoped_refptr<net::StreamListenSocket>
-ShellDevToolsDelegate::CreateSocketForTethering(
-    net::StreamListenSocket::Delegate* delegate,
-    std::string* name) {
-  return NULL;
-}
-
-}  // namespace content
diff --git a/content/shell/shell_devtools_delegate.h b/content/shell/shell_devtools_delegate.h
deleted file mode 100644
index dd4e762..0000000
--- a/content/shell/shell_devtools_delegate.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 CONTENT_SHELL_SHELL_DEVTOOLS_DELEGATE_H_
-#define CONTENT_SHELL_SHELL_DEVTOOLS_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/public/browser/devtools_http_handler_delegate.h"
-
-namespace content {
-
-class BrowserContext;
-class DevToolsHttpHandler;
-
-class ShellDevToolsDelegate : public DevToolsHttpHandlerDelegate {
- public:
-  explicit ShellDevToolsDelegate(BrowserContext* browser_context);
-  virtual ~ShellDevToolsDelegate();
-
-  // Stops http server.
-  void Stop();
-
-  // DevToolsHttpProtocolHandler::Delegate overrides.
-  virtual std::string GetDiscoveryPageHTML() OVERRIDE;
-  virtual bool BundlesFrontendResources() OVERRIDE;
-  virtual base::FilePath GetDebugFrontendDir() OVERRIDE;
-  virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE;
-  virtual RenderViewHost* CreateNewTarget() OVERRIDE;
-  virtual TargetType GetTargetType(RenderViewHost*) OVERRIDE;
-  virtual std::string GetViewDescription(content::RenderViewHost*) OVERRIDE;
-  virtual scoped_refptr<net::StreamListenSocket> CreateSocketForTethering(
-      net::StreamListenSocket::Delegate* delegate,
-      std::string* name) OVERRIDE;
-
-  DevToolsHttpHandler* devtools_http_handler() {
-    return devtools_http_handler_;
-  }
-
- private:
-  BrowserContext* browser_context_;
-  DevToolsHttpHandler* devtools_http_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellDevToolsDelegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_DEVTOOLS_DELEGATE_H_
diff --git a/content/shell/shell_devtools_frontend.cc b/content/shell/shell_devtools_frontend.cc
deleted file mode 100644
index d102eaa..0000000
--- a/content/shell/shell_devtools_frontend.cc
+++ /dev/null
@@ -1,107 +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/shell/shell_devtools_frontend.h"
-
-#include "base/command_line.h"
-#include "base/path_service.h"
-#include "content/public/browser/devtools_http_handler.h"
-#include "content/public/browser/devtools_manager.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/content_client.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_browser_main_parts.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_devtools_delegate.h"
-#include "net/base/net_util.h"
-
-namespace content {
-
-namespace {
-
-// DevTools frontend path for inspector LayoutTests.
-GURL GetDevToolsPathAsURL() {
-  base::FilePath dir_exe;
-  if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
-    NOTREACHED();
-    return GURL();
-  }
-#if defined(OS_MACOSX)
-  // On Mac, the executable is in
-  // out/Release/Content Shell.app/Contents/MacOS/Content Shell.
-  // We need to go up 3 directories to get to out/Release.
-  dir_exe = dir_exe.AppendASCII("../../..");
-#endif
-  base::FilePath dev_tools_path = dir_exe.AppendASCII(
-      "resources/inspector/devtools.html");
-  return net::FilePathToFileURL(dev_tools_path);
-}
-
-}  // namespace
-
-// static
-ShellDevToolsFrontend* ShellDevToolsFrontend::Show(
-    WebContents* inspected_contents) {
-  Shell* shell = Shell::CreateNewWindow(inspected_contents->GetBrowserContext(),
-                                        GURL(),
-                                        NULL,
-                                        MSG_ROUTING_NONE,
-                                        gfx::Size());
-  ShellDevToolsFrontend* devtools_frontend = new ShellDevToolsFrontend(
-      shell,
-      DevToolsAgentHost::GetOrCreateFor(inspected_contents->GetRenderViewHost())
-          .get());
-
-  ShellDevToolsDelegate* delegate = ShellContentBrowserClient::Get()->
-      shell_browser_main_parts()->devtools_delegate();
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    shell->LoadURL(GetDevToolsPathAsURL());
-  else
-    shell->LoadURL(delegate->devtools_http_handler()->GetFrontendURL(NULL));
-
-  return devtools_frontend;
-}
-
-void ShellDevToolsFrontend::Focus() {
-  web_contents()->GetView()->Focus();
-}
-
-void ShellDevToolsFrontend::Close() {
-  frontend_shell_->Close();
-}
-
-ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell,
-                                             DevToolsAgentHost* agent_host)
-    : WebContentsObserver(frontend_shell->web_contents()),
-      frontend_shell_(frontend_shell),
-      agent_host_(agent_host) {
-  frontend_host_.reset(
-      DevToolsClientHost::CreateDevToolsFrontendHost(web_contents(), this));
-}
-
-ShellDevToolsFrontend::~ShellDevToolsFrontend() {
-}
-
-void ShellDevToolsFrontend::RenderViewCreated(
-    RenderViewHost* render_view_host) {
-  DevToolsClientHost::SetupDevToolsFrontendClient(
-      web_contents()->GetRenderViewHost());
-  DevToolsManager* manager = DevToolsManager::GetInstance();
-  manager->RegisterDevToolsClientHostFor(agent_host_.get(),
-                                         frontend_host_.get());
-}
-
-void ShellDevToolsFrontend::WebContentsDestroyed(WebContents* web_contents) {
-  DevToolsManager::GetInstance()->ClientHostClosing(frontend_host_.get());
-  delete this;
-}
-
-void ShellDevToolsFrontend::InspectedContentsClosing() {
-  frontend_shell_->Close();
-}
-
-}  // namespace content
diff --git a/content/shell/shell_devtools_frontend.h b/content/shell/shell_devtools_frontend.h
deleted file mode 100644
index a76cbc3..0000000
--- a/content/shell/shell_devtools_frontend.h
+++ /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.
-
-#ifndef CONTENT_SHELL_SHELL_DEVTOOLS_FRONTEND_H_
-#define CONTENT_SHELL_SHELL_DEVTOOLS_FRONTEND_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/devtools_agent_host.h"
-#include "content/public/browser/devtools_client_host.h"
-#include "content/public/browser/devtools_frontend_host_delegate.h"
-#include "content/public/browser/web_contents_observer.h"
-
-namespace content {
-
-class RenderViewHost;
-class Shell;
-class WebContents;
-
-class ShellDevToolsFrontend : public WebContentsObserver,
-                              public DevToolsFrontendHostDelegate {
- public:
-  static ShellDevToolsFrontend* Show(WebContents* inspected_contents);
-  void Focus();
-  void Close();
-
-  Shell* frontend_shell() const { return frontend_shell_; }
-
- private:
-  ShellDevToolsFrontend(Shell* frontend_shell, DevToolsAgentHost* agent_host);
-  virtual ~ShellDevToolsFrontend();
-
-  // WebContentsObserver overrides
-  virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
-  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
-
-  // DevToolsFrontendHostDelegate implementation
-  virtual void ActivateWindow() OVERRIDE {}
-  virtual void ChangeAttachedWindowHeight(unsigned height) OVERRIDE {}
-  virtual void CloseWindow() OVERRIDE {}
-  virtual void MoveWindow(int x, int y) OVERRIDE {}
-  virtual void SetDockSide(const std::string& side) OVERRIDE {}
-  virtual void OpenInNewTab(const std::string& url) OVERRIDE {}
-  virtual void SaveToFile(const std::string& url,
-                          const std::string& content,
-                          bool save_as) OVERRIDE {}
-  virtual void AppendToFile(const std::string& url,
-                            const std::string& content) OVERRIDE {}
-  virtual void RequestFileSystems() OVERRIDE {}
-  virtual void AddFileSystem() OVERRIDE {}
-  virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE {}
-  virtual void IndexPath(int request_id,
-                         const std::string& file_system_path) OVERRIDE {}
-  virtual void StopIndexing(int request_id) OVERRIDE {}
-  virtual void SearchInPath(int request_id,
-                            const std::string& file_system_path,
-                            const std::string& query) OVERRIDE {}
-
-  virtual void InspectedContentsClosing() OVERRIDE;
-
-  Shell* frontend_shell_;
-  scoped_refptr<DevToolsAgentHost> agent_host_;
-  scoped_ptr<DevToolsClientHost> frontend_host_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellDevToolsFrontend);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_DEVTOOLS_FRONTEND_H_
diff --git a/content/shell/shell_download_manager_delegate.cc b/content/shell/shell_download_manager_delegate.cc
deleted file mode 100644
index 624ece5..0000000
--- a/content/shell/shell_download_manager_delegate.cc
+++ /dev/null
@@ -1,211 +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/shell/shell_download_manager_delegate.h"
-
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#endif
-
-#if defined(OS_WIN)
-#include <windows.h>
-#include <commdlg.h>
-#endif
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/download_manager.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/webkit_test_controller.h"
-#include "net/base/net_util.h"
-
-namespace content {
-
-ShellDownloadManagerDelegate::ShellDownloadManagerDelegate()
-    : download_manager_(NULL),
-      suppress_prompting_(false) {
-  // Balanced in Shutdown();
-  AddRef();
-}
-
-ShellDownloadManagerDelegate::~ShellDownloadManagerDelegate(){
-}
-
-
-void ShellDownloadManagerDelegate::SetDownloadManager(
-    DownloadManager* download_manager) {
-  download_manager_ = download_manager;
-}
-
-void ShellDownloadManagerDelegate::Shutdown() {
-  Release();
-}
-
-bool ShellDownloadManagerDelegate::DetermineDownloadTarget(
-    DownloadItem* download,
-    const DownloadTargetCallback& callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  // This assignment needs to be here because even at the call to
-  // SetDownloadManager, the system is not fully initialized.
-  if (default_download_path_.empty()) {
-    default_download_path_ = download_manager_->GetBrowserContext()->GetPath().
-        Append(FILE_PATH_LITERAL("Downloads"));
-  }
-
-  if (!download->GetForcedFilePath().empty()) {
-    callback.Run(download->GetForcedFilePath(),
-                 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
-                 DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
-                 download->GetForcedFilePath());
-    return true;
-  }
-
-  base::FilePath generated_name = net::GenerateFileName(
-      download->GetURL(),
-      download->GetContentDisposition(),
-      EmptyString(),
-      download->GetSuggestedFilename(),
-      download->GetMimeType(),
-      "download");
-
-  BrowserThread::PostTask(
-      BrowserThread::FILE,
-      FROM_HERE,
-      base::Bind(
-          &ShellDownloadManagerDelegate::GenerateFilename,
-          this, download->GetId(), callback, generated_name,
-          default_download_path_));
-  return true;
-}
-
-bool ShellDownloadManagerDelegate::ShouldOpenDownload(
-      DownloadItem* item,
-      const DownloadOpenDelayedCallback& callback) {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree) &&
-      WebKitTestController::Get()->IsMainWindow(item->GetWebContents()) &&
-      item->GetMimeType() == "text/html") {
-    WebKitTestController::Get()->OpenURL(
-        net::FilePathToFileURL(item->GetFullPath()));
-  }
-  return true;
-}
-
-void ShellDownloadManagerDelegate::GetNextId(
-    const DownloadIdCallback& callback) {
-  static uint32 next_id = DownloadItem::kInvalidId + 1;
-  callback.Run(next_id++);
-}
-
-void ShellDownloadManagerDelegate::GenerateFilename(
-    uint32 download_id,
-    const DownloadTargetCallback& callback,
-    const base::FilePath& generated_name,
-    const base::FilePath& suggested_directory) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  if (!base::PathExists(suggested_directory))
-    file_util::CreateDirectory(suggested_directory);
-
-  base::FilePath suggested_path(suggested_directory.Append(generated_name));
-  BrowserThread::PostTask(
-      BrowserThread::UI,
-      FROM_HERE,
-      base::Bind(
-          &ShellDownloadManagerDelegate::OnDownloadPathGenerated,
-          this, download_id, callback, suggested_path));
-}
-
-void ShellDownloadManagerDelegate::OnDownloadPathGenerated(
-    uint32 download_id,
-    const DownloadTargetCallback& callback,
-    const base::FilePath& suggested_path) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  if (suppress_prompting_) {
-    // Testing exit.
-    callback.Run(suggested_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
-                 DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
-                 suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")));
-    return;
-  }
-
-  ChooseDownloadPath(download_id, callback, suggested_path);
-}
-
-void ShellDownloadManagerDelegate::ChooseDownloadPath(
-    uint32 download_id,
-    const DownloadTargetCallback& callback,
-    const base::FilePath& suggested_path) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  DownloadItem* item = download_manager_->GetDownload(download_id);
-  if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
-    return;
-
-  base::FilePath result;
-#if defined(OS_WIN) && !defined(USE_AURA)
-  std::wstring file_part = base::FilePath(suggested_path).BaseName().value();
-  wchar_t file_name[MAX_PATH];
-  base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
-  OPENFILENAME save_as;
-  ZeroMemory(&save_as, sizeof(save_as));
-  save_as.lStructSize = sizeof(OPENFILENAME);
-  save_as.hwndOwner = item->GetWebContents()->GetView()->GetNativeView();
-  save_as.lpstrFile = file_name;
-  save_as.nMaxFile = arraysize(file_name);
-
-  std::wstring directory;
-  if (!suggested_path.empty())
-    directory = suggested_path.DirName().value();
-
-  save_as.lpstrInitialDir = directory.c_str();
-  save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
-                  OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
-
-  if (GetSaveFileName(&save_as))
-    result = base::FilePath(std::wstring(save_as.lpstrFile));
-#elif defined(TOOLKIT_GTK)
-  GtkWidget *dialog;
-  gfx::NativeWindow parent_window;
-  std::string base_name = base::FilePath(suggested_path).BaseName().value();
-
-  parent_window = item->GetWebContents()->GetView()->GetTopLevelNativeWindow();
-  dialog = gtk_file_chooser_dialog_new("Save File",
-                                       parent_window,
-                                       GTK_FILE_CHOOSER_ACTION_SAVE,
-                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                       GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
-                                       NULL);
-  gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
-                                                 TRUE);
-  gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
-                                    base_name.c_str());
-
-  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
-    char *filename;
-    filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
-    result = base::FilePath(filename);
-    g_free(filename);
-  }
-  gtk_widget_destroy(dialog);
-#else
-  NOTIMPLEMENTED();
-#endif
-
-  callback.Run(result, DownloadItem::TARGET_DISPOSITION_PROMPT,
-               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result);
-}
-
-void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting(
-    const base::FilePath& default_download_path) {
-  default_download_path_ = default_download_path;
-  suppress_prompting_ = true;
-}
-
-}  // namespace content
diff --git a/content/shell/shell_download_manager_delegate.h b/content/shell/shell_download_manager_delegate.h
deleted file mode 100644
index 3c699c5..0000000
--- a/content/shell/shell_download_manager_delegate.h
+++ /dev/null
@@ -1,65 +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_SHELL_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
-#define CONTENT_SHELL_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "content/public/browser/download_manager_delegate.h"
-
-namespace content {
-
-class DownloadManager;
-
-class ShellDownloadManagerDelegate
-    : public DownloadManagerDelegate,
-      public base::RefCountedThreadSafe<ShellDownloadManagerDelegate> {
- public:
-  ShellDownloadManagerDelegate();
-
-  void SetDownloadManager(DownloadManager* manager);
-
-  virtual void Shutdown() OVERRIDE;
-  virtual bool DetermineDownloadTarget(
-      DownloadItem* download,
-      const DownloadTargetCallback& callback) OVERRIDE;
-  virtual bool ShouldOpenDownload(
-      DownloadItem* item,
-      const DownloadOpenDelayedCallback& callback) OVERRIDE;
-  virtual void GetNextId(const DownloadIdCallback& callback) OVERRIDE;
-
-  // Inhibits prompting and sets the default download path.
-  void SetDownloadBehaviorForTesting(
-      const base::FilePath& default_download_path);
-
- protected:
-  // To allow subclasses for testing.
-  virtual ~ShellDownloadManagerDelegate();
-
- private:
-  friend class base::RefCountedThreadSafe<ShellDownloadManagerDelegate>;
-
-
-  void GenerateFilename(uint32 download_id,
-                        const DownloadTargetCallback& callback,
-                        const base::FilePath& generated_name,
-                        const base::FilePath& suggested_directory);
-  void OnDownloadPathGenerated(uint32 download_id,
-                               const DownloadTargetCallback& callback,
-                               const base::FilePath& suggested_path);
-  void ChooseDownloadPath(uint32 download_id,
-                          const DownloadTargetCallback& callback,
-                          const base::FilePath& suggested_path);
-
-  DownloadManager* download_manager_;
-  base::FilePath default_download_path_;
-  bool suppress_prompting_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellDownloadManagerDelegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
diff --git a/content/shell/shell_gtk.cc b/content/shell/shell_gtk.cc
deleted file mode 100644
index ee77473..0000000
--- a/content/shell/shell_gtk.cc
+++ /dev/null
@@ -1,339 +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/shell/shell.h"
-
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/native_web_keyboard_event.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/renderer_preferences.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_content_browser_client.h"
-
-namespace content {
-
-namespace {
-
-// Callback for Debug > Show web inspector... menu item.
-gboolean ShowWebInspectorActivated(GtkWidget* widget, Shell* shell) {
-  shell->ShowDevTools();
-  return FALSE;  // Don't stop this message.
-}
-
-GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text,
-                        GCallback callback, Shell* shell) {
-  GtkWidget* entry = gtk_menu_item_new_with_label(text);
-  g_signal_connect(entry, "activate", callback, shell);
-  gtk_menu_shell_append(GTK_MENU_SHELL(menu_widget), entry);
-  return entry;
-}
-
-GtkWidget* CreateMenu(GtkWidget* menu_bar, const char* text) {
-  GtkWidget* menu_widget = gtk_menu_new();
-  GtkWidget* menu_header = gtk_menu_item_new_with_label(text);
-  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_header), menu_widget);
-  gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_header);
-  return menu_widget;
-}
-
-GtkWidget* CreateMenuBar(Shell* shell) {
-  GtkWidget* menu_bar = gtk_menu_bar_new();
-  GtkWidget* debug_menu = CreateMenu(menu_bar, "Debug");
-  AddMenuEntry(debug_menu, "Show web inspector...",
-               G_CALLBACK(ShowWebInspectorActivated), shell);
-  return menu_bar;
-}
-
-}  // namespace
-
-void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
-}
-
-void Shell::PlatformCleanUp() {
-  // Nothing to clean up; GTK will clean up the widgets shortly after.
-}
-
-void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
-  if (headless_)
-    return;
-
-  GtkToolItem* item = NULL;
-  switch (control) {
-    case BACK_BUTTON:
-      item = back_button_;
-      break;
-    case FORWARD_BUTTON:
-      item = forward_button_;
-      break;
-    case STOP_BUTTON:
-      item = stop_button_;
-      break;
-    default:
-      NOTREACHED() << "Unknown UI control";
-      return;
-  }
-  gtk_widget_set_sensitive(GTK_WIDGET(item), is_enabled);
-}
-
-void Shell::PlatformSetAddressBarURL(const GURL& url) {
-  if (headless_)
-    return;
-
-  gtk_entry_set_text(GTK_ENTRY(url_edit_view_), url.spec().c_str());
-}
-
-void Shell::PlatformSetIsLoading(bool loading) {
-  if (headless_)
-    return;
-
-  if (loading)
-    gtk_spinner_start(GTK_SPINNER(spinner_));
-  else
-    gtk_spinner_stop(GTK_SPINNER(spinner_));
-}
-
-void Shell::PlatformCreateWindow(int width, int height) {
-  ui_elements_height_ = 0;
-  if (headless_) {
-    SizeTo(width, height);
-    return;
-  }
-
-  window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
-  gtk_window_set_title(window_, "Content Shell");
-  g_signal_connect(G_OBJECT(window_), "destroy",
-                   G_CALLBACK(OnWindowDestroyedThunk), this);
-
-  vbox_ = gtk_vbox_new(FALSE, 0);
-
-  // Create the menu bar.
-  GtkWidget* menu_bar = CreateMenuBar(this);
-  gtk_box_pack_start(GTK_BOX(vbox_), menu_bar, FALSE, FALSE, 0);
-
-  // Create the object that mediates accelerators.
-  GtkAccelGroup* accel_group = gtk_accel_group_new();
-  gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group);
-
-  // Set global window handling accelerators:
-  gtk_accel_group_connect(
-      accel_group, GDK_w, GDK_CONTROL_MASK,
-      GTK_ACCEL_VISIBLE,
-      g_cclosure_new(G_CALLBACK(OnCloseWindowKeyPressedThunk),
-                     this, NULL));
-
-  gtk_accel_group_connect(
-      accel_group, GDK_n, GDK_CONTROL_MASK,
-      GTK_ACCEL_VISIBLE,
-      g_cclosure_new(G_CALLBACK(OnNewWindowKeyPressedThunk),
-                    this, NULL));
-
-  gtk_accel_group_connect(
-    accel_group, GDK_F5, (GdkModifierType)0,
-      GTK_ACCEL_VISIBLE,
-      g_cclosure_new(G_CALLBACK(OnReloadKeyPressedThunk),
-                    this, NULL));
-
-  GtkWidget* toolbar = gtk_toolbar_new();
-  // Turn off the labels on the toolbar buttons.
-  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
-
-  back_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
-  g_signal_connect(back_button_, "clicked",
-                   G_CALLBACK(&OnBackButtonClickedThunk), this);
-  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), back_button_, -1 /* append */);
-  gtk_widget_add_accelerator(GTK_WIDGET(back_button_), "clicked", accel_group,
-                             GDK_Left, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
-
-  forward_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
-  g_signal_connect(forward_button_, "clicked",
-                   G_CALLBACK(&OnForwardButtonClickedThunk), this);
-  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), forward_button_, -1 /* append */);
-  gtk_widget_add_accelerator(GTK_WIDGET(forward_button_), "clicked",
-                             accel_group,
-                             GDK_Right, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
-
-  reload_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH);
-  g_signal_connect(reload_button_, "clicked",
-                   G_CALLBACK(&OnReloadButtonClickedThunk), this);
-  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), reload_button_, -1 /* append */);
-  gtk_widget_add_accelerator(GTK_WIDGET(reload_button_), "clicked",
-                             accel_group,
-                             GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
-
-  stop_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_STOP);
-  g_signal_connect(stop_button_, "clicked",
-                   G_CALLBACK(&OnStopButtonClickedThunk), this);
-  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), stop_button_, -1 /* append */);
-
-  url_edit_view_ = gtk_entry_new();
-  g_signal_connect(G_OBJECT(url_edit_view_), "activate",
-                   G_CALLBACK(&OnURLEntryActivateThunk), this);
-
-  gtk_accel_group_connect(
-      accel_group, GDK_l, GDK_CONTROL_MASK,
-      GTK_ACCEL_VISIBLE,
-      g_cclosure_new(G_CALLBACK(OnHighlightURLViewThunk),
-                     this, NULL));
-
-  GtkToolItem* tool_item = gtk_tool_item_new();
-  gtk_container_add(GTK_CONTAINER(tool_item), url_edit_view_);
-  gtk_tool_item_set_expand(tool_item, TRUE);
-  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1 /* append */);
-
-  // Center a 20x20 spinner in a 26x24 area.
-  GtkWidget* spinner_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
-  gtk_alignment_set_padding(GTK_ALIGNMENT(spinner_alignment), 2, 2, 4, 4);
-  spinner_ = gtk_spinner_new();
-  gtk_widget_set_size_request(spinner_, 20, 20);
-  gtk_container_add(GTK_CONTAINER(spinner_alignment), spinner_);
-
-  spinner_item_ = gtk_tool_item_new();
-  gtk_container_add(GTK_CONTAINER(spinner_item_), spinner_alignment);
-  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), spinner_item_, -1 /* append */);
-
-  gtk_box_pack_start(GTK_BOX(vbox_), toolbar, FALSE, FALSE, 0);
-
-  gtk_container_add(GTK_CONTAINER(window_), vbox_);
-
-  // Trigger layout of the UI elements, so that we can measure their
-  // heights. The width and height passed to this method are meant for the web
-  // contents view, not the top-level window. Since Gtk only seems to provide a
-  // suitable resizing function for top-level windows, we need to know how to
-  // convert from web contents view size to top-level window size.
-  gtk_widget_show_all(GTK_WIDGET(vbox_));
-
-  // Measure the heights of the UI elements, now that they have been laid out.
-  GtkRequisition elm_size;
-  gtk_widget_size_request(menu_bar, &elm_size);
-  ui_elements_height_ += elm_size.height;
-  gtk_widget_size_request(toolbar, &elm_size);
-  ui_elements_height_ += elm_size.height;
-
-  // We're ready to set an initial window size.
-  SizeTo(width, height);
-
-  // Finally, show the window.
-  gtk_widget_show_all(GTK_WIDGET(window_));
-}
-
-void Shell::PlatformSetContents() {
-  if (headless_)
-    return;
-
-  WebContentsView* content_view = web_contents_->GetView();
-  gtk_container_add(GTK_CONTAINER(vbox_), content_view->GetNativeView());
-}
-
-void Shell::SizeTo(int width, int height) {
-  content_width_ = width;
-  content_height_ = height;
-
-  // Prefer setting the top level window's size (if we have one), rather than
-  // setting the inner widget's minimum size (so that the user can shrink the
-  // window if she wants).
-  if (window_) {
-    gtk_window_resize(window_, width, height + ui_elements_height_);
-  } else if (web_contents_) {
-    gtk_widget_set_size_request(web_contents_->GetView()->GetNativeView(),
-                                width, height);
-  }
-}
-
-void Shell::PlatformResizeSubViews() {
-  SizeTo(content_width_, content_height_);
-}
-
-void Shell::Close() {
-  if (headless_) {
-    delete this;
-    return;
-  }
-
-  gtk_widget_destroy(GTK_WIDGET(window_));
-}
-
-void Shell::OnBackButtonClicked(GtkWidget* widget) {
-  GoBackOrForward(-1);
-}
-
-void Shell::OnForwardButtonClicked(GtkWidget* widget) {
-  GoBackOrForward(1);
-}
-
-void Shell::OnReloadButtonClicked(GtkWidget* widget) {
-  Reload();
-}
-
-void Shell::OnStopButtonClicked(GtkWidget* widget) {
-  Stop();
-}
-
-void Shell::OnURLEntryActivate(GtkWidget* entry) {
-  const gchar* str = gtk_entry_get_text(GTK_ENTRY(entry));
-  GURL url(str);
-  if (!url.has_scheme())
-    url = GURL(std::string("http://") + std::string(str));
-  LoadURL(GURL(url));
-}
-
-// Callback for when the main window is destroyed.
-gboolean Shell::OnWindowDestroyed(GtkWidget* window) {
-  delete this;
-  return FALSE;  // Don't stop this message.
-}
-
-gboolean Shell::OnCloseWindowKeyPressed(GtkAccelGroup* accel_group,
-                                        GObject* acceleratable,
-                                        guint keyval,
-                                        GdkModifierType modifier) {
-  gtk_widget_destroy(GTK_WIDGET(window_));
-  return TRUE;
-}
-
-gboolean Shell::OnNewWindowKeyPressed(GtkAccelGroup* accel_group,
-                                      GObject* acceleratable,
-                                      guint keyval,
-                                      GdkModifierType modifier) {
-  ShellBrowserContext* browser_context =
-      ShellContentBrowserClient::Get()->browser_context();
-  Shell::CreateNewWindow(browser_context,
-                         GURL(),
-                         NULL,
-                         MSG_ROUTING_NONE,
-                         gfx::Size());
-  return TRUE;
-}
-
-gboolean Shell::OnHighlightURLView(GtkAccelGroup* accel_group,
-                                   GObject* acceleratable,
-                                   guint keyval,
-                                   GdkModifierType modifier) {
-  gtk_widget_grab_focus(GTK_WIDGET(url_edit_view_));
-  return TRUE;
-}
-
-gboolean Shell::OnReloadKeyPressed(GtkAccelGroup* accel_group,
-                                   GObject* acceleratable,
-                                   guint keyval,
-                                   GdkModifierType modifier) {
-  Reload();
-  return TRUE;
-}
-
-void Shell::PlatformSetTitle(const string16& title) {
-  if (headless_)
-    return;
-
-  std::string title_utf8 = UTF16ToUTF8(title);
-  gtk_window_set_title(GTK_WINDOW(window_), title_utf8.c_str());
-}
-
-}  // namespace content
diff --git a/content/shell/shell_javascript_dialog.h b/content/shell/shell_javascript_dialog.h
deleted file mode 100644
index b819f3b..0000000
--- a/content/shell/shell_javascript_dialog.h
+++ /dev/null
@@ -1,64 +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_SHELL_SHELL_JAVASCRIPT_DIALOG_H_
-#define CONTENT_SHELL_SHELL_JAVASCRIPT_DIALOG_H_
-
-#include "content/public/browser/javascript_dialog_manager.h"
-
-#if defined(TOOLKIT_GTK)
-#include "ui/base/gtk/gtk_signal.h"
-#endif
-
-#if defined(OS_MACOSX)
-#if __OBJC__
-@class ShellJavaScriptDialogHelper;
-#else
-class ShellJavaScriptDialogHelper;
-#endif  // __OBJC__
-#endif  // defined(OS_MACOSX)
-
-namespace content {
-
-class ShellJavaScriptDialogManager;
-
-class ShellJavaScriptDialog {
- public:
-  ShellJavaScriptDialog(
-      ShellJavaScriptDialogManager* manager,
-      gfx::NativeWindow parent_window,
-      JavaScriptMessageType message_type,
-      const string16& message_text,
-      const string16& default_prompt_text,
-      const JavaScriptDialogManager::DialogClosedCallback& callback);
-  ~ShellJavaScriptDialog();
-
-  // Called to cancel a dialog mid-flight.
-  void Cancel();
-
- private:
-  ShellJavaScriptDialogManager* manager_;
-  JavaScriptDialogManager::DialogClosedCallback callback_;
-
-#if defined(OS_MACOSX)
-  ShellJavaScriptDialogHelper* helper_;  // owned
-#elif defined(OS_WIN)
-  JavaScriptMessageType message_type_;
-  HWND dialog_win_;
-  string16 message_text_;
-  string16 default_prompt_text_;
-  static INT_PTR CALLBACK DialogProc(HWND dialog, UINT message, WPARAM wparam,
-                                     LPARAM lparam);
-#elif defined(TOOLKIT_GTK)
-  GtkWidget* gtk_dialog_;
-  gfx::NativeWindow parent_window_;
-  CHROMEGTK_CALLBACK_1(ShellJavaScriptDialog, void, OnResponse, int);
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(ShellJavaScriptDialog);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_JAVASCRIPT_DIALOG_H_
diff --git a/content/shell/shell_javascript_dialog_gtk.cc b/content/shell/shell_javascript_dialog_gtk.cc
deleted file mode 100644
index 9ba05fc..0000000
--- a/content/shell/shell_javascript_dialog_gtk.cc
+++ /dev/null
@@ -1,127 +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/shell/shell_javascript_dialog.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/shell/app/resource.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_javascript_dialog_manager.h"
-
-namespace {
-
-const char kPromptTextId[] = "content_shell_prompt_text";
-
-// If there's a text entry in the dialog, get the text from the first one and
-// return it.
-string16 GetPromptText(GtkDialog* dialog) {
-  GtkWidget* widget = static_cast<GtkWidget*>(
-      g_object_get_data(G_OBJECT(dialog), kPromptTextId));
-  if (widget)
-    return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(widget)));
-  return string16();
-}
-
-}  // namespace
-
-
-namespace content {
-
-ShellJavaScriptDialog::ShellJavaScriptDialog(
-    ShellJavaScriptDialogManager* manager,
-    gfx::NativeWindow parent_window,
-    JavaScriptMessageType message_type,
-    const string16& message_text,
-    const string16& default_prompt_text,
-    const JavaScriptDialogManager::DialogClosedCallback& callback)
-    : manager_(manager),
-      callback_(callback),
-      parent_window_(parent_window) {
-  GtkButtonsType buttons = GTK_BUTTONS_NONE;
-  GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER;
-
-  switch (message_type) {
-    case content::JAVASCRIPT_MESSAGE_TYPE_ALERT:
-      buttons = GTK_BUTTONS_NONE;
-      gtk_message_type = GTK_MESSAGE_WARNING;
-      break;
-
-    case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
-      buttons = GTK_BUTTONS_CANCEL;
-      gtk_message_type = GTK_MESSAGE_QUESTION;
-      break;
-
-    case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT:
-      buttons = GTK_BUTTONS_CANCEL;
-      gtk_message_type = GTK_MESSAGE_QUESTION;
-      break;
-
-    default:
-      NOTREACHED();
-  }
-
-  gtk_dialog_ = gtk_message_dialog_new(parent_window_,
-                                       GTK_DIALOG_MODAL,
-                                       gtk_message_type,
-                                       buttons,
-                                       "%s",
-                                       UTF16ToUTF8(message_text).c_str());
-  g_signal_connect(gtk_dialog_,
-                   "delete-event",
-                   G_CALLBACK(gtk_widget_hide_on_delete),
-                   NULL);
-  gtk_window_set_title(GTK_WINDOW(gtk_dialog_), "JavaScript");
-
-  GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_),
-                                               GTK_STOCK_OK,
-                                               GTK_RESPONSE_OK);
-
-  if (message_type != content::JAVASCRIPT_MESSAGE_TYPE_PROMPT)
-    gtk_widget_grab_focus(ok_button);
-
-  if (message_type == content::JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
-    GtkWidget* content_area =
-        gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_));
-    GtkWidget* text_box = gtk_entry_new();
-    gtk_entry_set_text(GTK_ENTRY(text_box),
-                       UTF16ToUTF8(default_prompt_text).c_str());
-    gtk_box_pack_start(GTK_BOX(content_area), text_box, TRUE, TRUE, 0);
-    g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box);
-    gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE);
-  }
-
-  gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
-  g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnResponseThunk), this);
-  gtk_widget_show_all(GTK_WIDGET(gtk_dialog_));
-}
-
-ShellJavaScriptDialog::~ShellJavaScriptDialog() {
-}
-
-void ShellJavaScriptDialog::Cancel() {
-}
-
-void ShellJavaScriptDialog::OnResponse(GtkWidget* dialog, int response_id) {
-  switch (response_id) {
-    case GTK_RESPONSE_OK:
-      callback_.Run(true, GetPromptText(GTK_DIALOG(dialog)));
-      break;
-    case GTK_RESPONSE_CANCEL:
-    case GTK_RESPONSE_DELETE_EVENT:
-      callback_.Run(false, string16());
-      break;
-    default:
-      NOTREACHED();
-  }
-
-  gtk_widget_destroy(dialog);
-
-  manager_->DialogClosed(this);
-}
-
-}  // namespace content
diff --git a/content/shell/shell_javascript_dialog_mac.mm b/content/shell/shell_javascript_dialog_mac.mm
deleted file mode 100644
index 0a89a89..0000000
--- a/content/shell/shell_javascript_dialog_mac.mm
+++ /dev/null
@@ -1,138 +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/shell/shell_javascript_dialog.h"
-
-#import <Cocoa/Cocoa.h>
-
-#import "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "content/shell/shell_javascript_dialog_manager.h"
-
-// Helper object that receives the notification that the dialog/sheet is
-// going away. Is responsible for cleaning itself up.
-@interface ShellJavaScriptDialogHelper : NSObject<NSAlertDelegate> {
- @private
-  base::scoped_nsobject<NSAlert> alert_;
-  NSTextField* textField_;  // WEAK; owned by alert_
-
-  // Copies of the fields in ShellJavaScriptDialog because they're private.
-  content::ShellJavaScriptDialogManager* manager_;
-  content::JavaScriptDialogManager::DialogClosedCallback callback_;
-}
-
-- (id)initHelperWithManager:(content::ShellJavaScriptDialogManager*)manager
-   andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback;
-- (NSAlert*)alert;
-- (NSTextField*)textField;
-- (void)alertDidEnd:(NSAlert*)alert
-         returnCode:(int)returnCode
-        contextInfo:(void*)contextInfo;
-- (void)cancel;
-
-@end
-
-@implementation ShellJavaScriptDialogHelper
-
-- (id)initHelperWithManager:(content::ShellJavaScriptDialogManager*)manager
-  andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback {
-  if (self = [super init]) {
-    manager_ = manager;
-    callback_ = callback;
-  }
-
-  return self;
-}
-
-- (NSAlert*)alert {
-  alert_.reset([[NSAlert alloc] init]);
-  return alert_;
-}
-
-- (NSTextField*)textField {
-  textField_ = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)];
-  [[textField_ cell] setLineBreakMode:NSLineBreakByTruncatingTail];
-  [alert_ setAccessoryView:textField_];
-  [textField_ release];
-
-  return textField_;
-}
-
-- (void)alertDidEnd:(NSAlert*)alert
-         returnCode:(int)returnCode
-        contextInfo:(void*)contextInfo {
-  if (returnCode == NSRunStoppedResponse)
-    return;
-
-  bool success = returnCode == NSAlertFirstButtonReturn;
-  string16 input;
-  if (textField_)
-    input = base::SysNSStringToUTF16([textField_ stringValue]);
-
-  content::ShellJavaScriptDialog* native_dialog =
-      reinterpret_cast<content::ShellJavaScriptDialog*>(contextInfo);
-  callback_.Run(success, input);
-  manager_->DialogClosed(native_dialog);
-}
-
-- (void)cancel {
-  [NSApp endSheet:[alert_ window]];
-  alert_.reset();
-}
-
-@end
-
-namespace content {
-
-ShellJavaScriptDialog::ShellJavaScriptDialog(
-    ShellJavaScriptDialogManager* manager,
-    gfx::NativeWindow parent_window,
-    JavaScriptMessageType message_type,
-    const string16& message_text,
-    const string16& default_prompt_text,
-    const JavaScriptDialogManager::DialogClosedCallback& callback)
-    : manager_(manager),
-      callback_(callback) {
-  bool text_field = message_type == JAVASCRIPT_MESSAGE_TYPE_PROMPT;
-  bool one_button = message_type == JAVASCRIPT_MESSAGE_TYPE_ALERT;
-
-  helper_ =
-      [[ShellJavaScriptDialogHelper alloc] initHelperWithManager:manager
-                                                     andCallback:callback];
-
-  // Show the modal dialog.
-  NSAlert* alert = [helper_ alert];
-  NSTextField* field = nil;
-  if (text_field) {
-    field = [helper_ textField];
-    [field setStringValue:base::SysUTF16ToNSString(default_prompt_text)];
-  }
-  [alert setDelegate:helper_];
-  [alert setInformativeText:base::SysUTF16ToNSString(message_text)];
-  [alert setMessageText:@"Javascript alert"];
-  [alert addButtonWithTitle:@"OK"];
-  if (!one_button) {
-    NSButton* other = [alert addButtonWithTitle:@"Cancel"];
-    [other setKeyEquivalent:@"\e"];
-  }
-
-  [alert
-      beginSheetModalForWindow:nil  // nil here makes it app-modal
-                 modalDelegate:helper_
-                didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
-                   contextInfo:this];
-
-  if ([alert accessoryView])
-    [[alert window] makeFirstResponder:[alert accessoryView]];
-}
-
-ShellJavaScriptDialog::~ShellJavaScriptDialog() {
-  [helper_ release];
-}
-
-void ShellJavaScriptDialog::Cancel() {
-  [helper_ cancel];
-}
-
-}  // namespace content
diff --git a/content/shell/shell_javascript_dialog_manager.cc b/content/shell/shell_javascript_dialog_manager.cc
deleted file mode 100644
index 9248483..0000000
--- a/content/shell/shell_javascript_dialog_manager.cc
+++ /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.
-
-#include "content/shell/shell_javascript_dialog_manager.h"
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell_javascript_dialog.h"
-#include "content/shell/webkit_test_controller.h"
-#include "net/base/net_util.h"
-
-namespace content {
-
-ShellJavaScriptDialogManager::ShellJavaScriptDialogManager() {
-}
-
-ShellJavaScriptDialogManager::~ShellJavaScriptDialogManager() {
-}
-
-void ShellJavaScriptDialogManager::RunJavaScriptDialog(
-    WebContents* web_contents,
-    const GURL& origin_url,
-    const std::string& accept_lang,
-    JavaScriptMessageType javascript_message_type,
-    const string16& message_text,
-    const string16& default_prompt_text,
-    const DialogClosedCallback& callback,
-    bool* did_suppress_message) {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
-    callback.Run(true, string16());
-    return;
-  }
-
-  if (!dialog_request_callback_.is_null()) {
-    dialog_request_callback_.Run();
-    callback.Run(true, string16());
-    dialog_request_callback_.Reset();
-    return;
-  }
-
-#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
-  *did_suppress_message = false;
-
-  if (dialog_) {
-    // One dialog at a time, please.
-    *did_suppress_message = true;
-    return;
-  }
-
-  string16 new_message_text = net::FormatUrl(origin_url, accept_lang) +
-                              ASCIIToUTF16("\n\n") +
-                              message_text;
-  gfx::NativeWindow parent_window =
-      web_contents->GetView()->GetTopLevelNativeWindow();
-
-  dialog_.reset(new ShellJavaScriptDialog(this,
-                                          parent_window,
-                                          javascript_message_type,
-                                          new_message_text,
-                                          default_prompt_text,
-                                          callback));
-#else
-  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
-  *did_suppress_message = true;
-  return;
-#endif
-}
-
-void ShellJavaScriptDialogManager::RunBeforeUnloadDialog(
-    WebContents* web_contents,
-    const string16& message_text,
-    bool is_reload,
-    const DialogClosedCallback& callback) {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
-    callback.Run(true, string16());
-    return;
-  }
-
-  if (!dialog_request_callback_.is_null()) {
-    dialog_request_callback_.Run();
-    callback.Run(true, string16());
-    dialog_request_callback_.Reset();
-    return;
-  }
-
-#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
-  if (dialog_) {
-    // Seriously!?
-    callback.Run(true, string16());
-    return;
-  }
-
-  string16 new_message_text =
-      message_text +
-      ASCIIToUTF16("\n\nIs it OK to leave/reload this page?");
-
-  gfx::NativeWindow parent_window =
-      web_contents->GetView()->GetTopLevelNativeWindow();
-
-  dialog_.reset(new ShellJavaScriptDialog(this,
-                                          parent_window,
-                                          JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
-                                          new_message_text,
-                                          string16(),  // default_prompt_text
-                                          callback));
-#else
-  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
-  callback.Run(true, string16());
-  return;
-#endif
-}
-
-void ShellJavaScriptDialogManager::CancelActiveAndPendingDialogs(
-    WebContents* web_contents) {
-#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
-  if (dialog_) {
-    dialog_->Cancel();
-    dialog_.reset();
-  }
-#else
-  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
-#endif
-}
-
-void ShellJavaScriptDialogManager::WebContentsDestroyed(
-    WebContents* web_contents) {
-}
-
-void ShellJavaScriptDialogManager::DialogClosed(ShellJavaScriptDialog* dialog) {
-#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
-  DCHECK_EQ(dialog, dialog_.get());
-  dialog_.reset();
-#else
-  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
-#endif
-}
-
-}  // namespace content
diff --git a/content/shell/shell_javascript_dialog_manager.h b/content/shell/shell_javascript_dialog_manager.h
deleted file mode 100644
index 1327ab7..0000000
--- a/content/shell/shell_javascript_dialog_manager.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_SHELL_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
-#define CONTENT_SHELL_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
-
-#include "base/callback_forward.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/javascript_dialog_manager.h"
-
-namespace content {
-
-class ShellJavaScriptDialog;
-
-class ShellJavaScriptDialogManager : public JavaScriptDialogManager {
- public:
-  ShellJavaScriptDialogManager();
-  virtual ~ShellJavaScriptDialogManager();
-
-  // JavaScriptDialogManager:
-  virtual void RunJavaScriptDialog(
-      WebContents* web_contents,
-      const GURL& origin_url,
-      const std::string& accept_lang,
-      JavaScriptMessageType javascript_message_type,
-      const string16& message_text,
-      const string16& default_prompt_text,
-      const DialogClosedCallback& callback,
-      bool* did_suppress_message) OVERRIDE;
-
-  virtual void RunBeforeUnloadDialog(
-      WebContents* web_contents,
-      const string16& message_text,
-      bool is_reload,
-      const DialogClosedCallback& callback) OVERRIDE;
-
-  virtual void CancelActiveAndPendingDialogs(
-      WebContents* web_contents) OVERRIDE;
-
-  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
-
-  // Called by the ShellJavaScriptDialog when it closes.
-  void DialogClosed(ShellJavaScriptDialog* dialog);
-
-  // Used for content_browsertests.
-  void set_dialog_request_callback(const base::Closure& callback) {
-    dialog_request_callback_ = callback;
-  }
-
- private:
-#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
-  // The dialog being shown. No queueing.
-  scoped_ptr<ShellJavaScriptDialog> dialog_;
-#else
-  // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
-#endif
-
-  base::Closure dialog_request_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellJavaScriptDialogManager);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
diff --git a/content/shell/shell_javascript_dialog_win.cc b/content/shell/shell_javascript_dialog_win.cc
deleted file mode 100644
index c39b2d7..0000000
--- a/content/shell/shell_javascript_dialog_win.cc
+++ /dev/null
@@ -1,113 +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/shell/shell_javascript_dialog.h"
-
-#include "base/strings/string_util.h"
-#include "content/shell/app/resource.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_javascript_dialog_manager.h"
-
-namespace content {
-
-class ShellJavaScriptDialog;
-
-INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog,
-                                                   UINT message,
-                                                   WPARAM wparam,
-                                                   LPARAM lparam) {
-  switch (message) {
-    case WM_INITDIALOG: {
-      SetWindowLongPtr(dialog, DWLP_USER, static_cast<LONG_PTR>(lparam));
-      ShellJavaScriptDialog* owner =
-          reinterpret_cast<ShellJavaScriptDialog*>(lparam);
-      owner->dialog_win_ = dialog;
-      SetDlgItemText(dialog, IDC_DIALOGTEXT, owner->message_text_.c_str());
-      if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT)
-        SetDlgItemText(dialog, IDC_PROMPTEDIT,
-                       owner->default_prompt_text_.c_str());
-      break;
-    }
-    case WM_DESTROY: {
-      ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
-          GetWindowLongPtr(dialog, DWLP_USER));
-      if (owner->dialog_win_) {
-        owner->dialog_win_ = 0;
-        owner->callback_.Run(false, string16());
-        owner->manager_->DialogClosed(owner);
-      }
-      break;
-    }
-    case WM_COMMAND: {
-      ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
-          GetWindowLongPtr(dialog, DWLP_USER));
-      string16 user_input;
-      bool finish = false;
-      bool result;
-      switch (LOWORD(wparam)) {
-        case IDOK:
-          finish = true;
-          result = true;
-          if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
-            int length =
-                GetWindowTextLength(GetDlgItem(dialog, IDC_PROMPTEDIT)) + 1;
-            GetDlgItemText(dialog, IDC_PROMPTEDIT,
-                           WriteInto(&user_input, length), length);
-          }
-          break;
-        case IDCANCEL:
-          finish = true;
-          result = false;
-          break;
-      }
-      if (finish) {
-        owner->dialog_win_ = 0;
-        owner->callback_.Run(result, user_input);
-        DestroyWindow(dialog);
-        owner->manager_->DialogClosed(owner);
-      }
-      break;
-    }
-    default:
-      return DefWindowProc(dialog, message, wparam, lparam);
-  }
-  return 0;
-}
-
-ShellJavaScriptDialog::ShellJavaScriptDialog(
-    ShellJavaScriptDialogManager* manager,
-    gfx::NativeWindow parent_window,
-    JavaScriptMessageType message_type,
-    const string16& message_text,
-    const string16& default_prompt_text,
-    const JavaScriptDialogManager::DialogClosedCallback& callback)
-    : manager_(manager),
-      callback_(callback),
-      message_text_(message_text),
-      default_prompt_text_(default_prompt_text),
-      message_type_(message_type) {
-  int dialog_type;
-  if (message_type == JAVASCRIPT_MESSAGE_TYPE_ALERT)
-    dialog_type = IDD_ALERT;
-  else if (message_type == JAVASCRIPT_MESSAGE_TYPE_CONFIRM)
-    dialog_type = IDD_CONFIRM;
-  else // JAVASCRIPT_MESSAGE_TYPE_PROMPT
-    dialog_type = IDD_PROMPT;
-
-  dialog_win_ = CreateDialogParam(GetModuleHandle(0),
-                                  MAKEINTRESOURCE(dialog_type), 0, DialogProc,
-                                  reinterpret_cast<LPARAM>(this));
-  ShowWindow(dialog_win_, SW_SHOWNORMAL);
-}
-
-ShellJavaScriptDialog::~ShellJavaScriptDialog() {
-  Cancel();
-}
-
-void ShellJavaScriptDialog::Cancel() {
-  if (dialog_win_)
-    DestroyWindow(dialog_win_);
-}
-
-}  // namespace content
diff --git a/content/shell/shell_layout_tests_android.cc b/content/shell/shell_layout_tests_android.cc
deleted file mode 100644
index 68e8001..0000000
--- a/content/shell/shell_layout_tests_android.cc
+++ /dev/null
@@ -1,93 +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/shell/shell_layout_tests_android.h"
-
-#include "base/android/fifo_utils.h"
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/message_loop/message_loop.h"
-#include "content/public/test/nested_message_pump_android.h"
-#include "content/shell/common/shell_switches.h"
-#include "jni/ShellLayoutTestUtils_jni.h"
-#include "url/gurl.h"
-
-namespace {
-
-// Path to search for when translating a layout test path to an URL.
-const char kAndroidLayoutTestPath[] =
-    "/data/local/tmp/third_party/WebKit/LayoutTests/";
-
-// The base URL from which layout tests are being served on Android.
-const char kAndroidLayoutTestBase[] = "http://127.0.0.1:8000/all-tests/";
-
-base::FilePath GetTestFilesDirectory(JNIEnv* env) {
-  ScopedJavaLocalRef<jstring> directory =
-      content::Java_ShellLayoutTestUtils_getApplicationFilesDirectory(
-          env, base::android::GetApplicationContext());
-  return base::FilePath(ConvertJavaStringToUTF8(directory));
-}
-
-void EnsureCreateFIFO(const base::FilePath& path) {
-  unlink(path.value().c_str());
-  CHECK(base::android::CreateFIFO(path, 0666))
-    << "Unable to create the Android's FIFO: " << path.value().c_str();
-}
-
-base::MessagePump* CreateMessagePumpForUI() {
-  return new content::NestedMessagePumpAndroid();
-}
-
-}  // namespace
-
-namespace content {
-
-bool GetTestUrlForAndroid(std::string& path_or_url, GURL* url) {
-  if (path_or_url.find(kAndroidLayoutTestPath) == std::string::npos)
-    return false;
-
-  std::string test_location(kAndroidLayoutTestBase);
-  test_location.append(path_or_url.substr(strlen(kAndroidLayoutTestPath)));
-
-  *url = GURL(test_location);
-  return true;
-}
-
-void EnsureInitializeForAndroidLayoutTests() {
-  CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree));
-
-  JNIEnv* env = base::android::AttachCurrentThread();
-  content::NestedMessagePumpAndroid::RegisterJni(env);
-  content::RegisterNativesImpl(env);
-
-  bool success = base::MessageLoop::InitMessagePumpForUIFactory(
-      &CreateMessagePumpForUI);
-  CHECK(success) << "Unable to initialize the message pump for Android.";
-
-  // Android will need three FIFOs to communicate with the Blink test runner,
-  // one for each of [stdout, stderr, stdin].
-  base::FilePath files_dir(GetTestFilesDirectory(env));
-
-  base::FilePath stdout_fifo(files_dir.Append(FILE_PATH_LITERAL("test.fifo")));
-  EnsureCreateFIFO(stdout_fifo);
-
-  base::FilePath stderr_fifo(
-      files_dir.Append(FILE_PATH_LITERAL("stderr.fifo")));
-  EnsureCreateFIFO(stderr_fifo);
-
-  base::FilePath stdin_fifo(files_dir.Append(FILE_PATH_LITERAL("stdin.fifo")));
-  EnsureCreateFIFO(stdin_fifo);
-
-  // Redirecting stdout needs to happen before redirecting stdin, which needs
-  // to happen before redirecting stderr.
-  success = base::android::RedirectStream(stdout, stdout_fifo, "w") &&
-            base::android::RedirectStream(stdin, stdin_fifo, "r") &&
-            base::android::RedirectStream(stderr, stderr_fifo, "w");
-
-  CHECK(success) << "Unable to initialize the Android FIFOs.";
-}
-
-}  // namespace content
diff --git a/content/shell/shell_layout_tests_android.h b/content/shell/shell_layout_tests_android.h
deleted file mode 100644
index 9a3c423..0000000
--- a/content/shell/shell_layout_tests_android.h
+++ /dev/null
@@ -1,25 +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_SHELL_SHELL_LAYOUT_TESTS_ANDROID_H_
-#define CONTENT_SHELL_SHELL_LAYOUT_TESTS_ANDROID_H_
-
-#include <string>
-
-class GURL;
-
-namespace content {
-
-// On Android, all passed tests will be paths to a local temporary directory.
-// However, because we can't transfer all test files to the device, translate
-// those paths to a local, forwarded URL so the host can serve them.
-bool GetTestUrlForAndroid(std::string& path_or_url, GURL* url);
-
-// Initialize the nested message loop and FIFOs for Android, and verify that
-// all has been set up using a few appropriate CHECK()s.
-void EnsureInitializeForAndroidLayoutTests();
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_LAYOUT_TESTS_ANDROID_H_
diff --git a/content/shell/shell_login_dialog.cc b/content/shell/shell_login_dialog.cc
deleted file mode 100644
index f32c427..0000000
--- a/content/shell/shell_login_dialog.cc
+++ /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.
-
-#include "content/shell/shell_login_dialog.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_dispatcher_host.h"
-#include "net/base/auth.h"
-#include "net/url_request/url_request.h"
-#include "ui/base/text/text_elider.h"
-
-namespace content {
-
-ShellLoginDialog::ShellLoginDialog(
-    net::AuthChallengeInfo* auth_info,
-    net::URLRequest* request) : auth_info_(auth_info),
-                                request_(request) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&ShellLoginDialog::PrepDialog, this,
-                 ASCIIToUTF16(auth_info->challenger.ToString()),
-                 UTF8ToUTF16(auth_info->realm)));
-}
-
-void ShellLoginDialog::OnRequestCancelled() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&ShellLoginDialog::PlatformRequestCancelled, this));
-}
-
-void ShellLoginDialog::UserAcceptedAuth(const string16& username,
-                                        const string16& password) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&ShellLoginDialog::SendAuthToRequester, this,
-                 true, username, password));
-}
-
-void ShellLoginDialog::UserCancelledAuth() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&ShellLoginDialog::SendAuthToRequester, this,
-                 false, string16(), string16()));
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&ShellLoginDialog::PlatformCleanUp, this));
-}
-
-ShellLoginDialog::~ShellLoginDialog() {
-  // Cannot post any tasks here; this object is going away and cannot be
-  // referenced/dereferenced.
-}
-
-#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK)
-// Bogus implementations for linking. They are never called because
-// ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL.
-// TODO: implement ShellLoginDialog for other platforms, drop this #if
-void ShellLoginDialog::PlatformCreateDialog(const string16& message) {}
-void ShellLoginDialog::PlatformCleanUp() {}
-void ShellLoginDialog::PlatformRequestCancelled() {}
-#endif
-
-void ShellLoginDialog::PrepDialog(const string16& host,
-                                  const string16& realm) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  // The realm is controlled by the remote server, so there is no reason to
-  // believe it is of a reasonable length.
-  string16 elided_realm;
-  ui::ElideString(realm, 120, &elided_realm);
-
-  string16 explanation =
-      ASCIIToUTF16("The server ") + host +
-      ASCIIToUTF16(" requires a username and password.");
-
-  if (!elided_realm.empty()) {
-    explanation += ASCIIToUTF16(" The server says: ");
-    explanation += elided_realm;
-    explanation += ASCIIToUTF16(".");
-  }
-
-  PlatformCreateDialog(explanation);
-}
-
-void ShellLoginDialog::SendAuthToRequester(bool success,
-                                           const string16& username,
-                                           const string16& password) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  if (success)
-    request_->SetAuth(net::AuthCredentials(username, password));
-  else
-    request_->CancelAuth();
-  ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_);
-
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&ShellLoginDialog::PlatformCleanUp, this));
-}
-
-}  // namespace content
diff --git a/content/shell/shell_login_dialog.h b/content/shell/shell_login_dialog.h
deleted file mode 100644
index 22abab4..0000000
--- a/content/shell/shell_login_dialog.h
+++ /dev/null
@@ -1,97 +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_SHELL_SHELL_LOGIN_DIALOG_H_
-#define CONTENT_SHELL_SHELL_LOGIN_DIALOG_H_
-
-#include "base/compiler_specific.h"
-#include "base/strings/string16.h"
-#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
-
-#if defined(TOOLKIT_GTK)
-#include "ui/base/gtk/gtk_signal.h"
-#endif
-
-#if defined(OS_MACOSX)
-#if __OBJC__
-@class ShellLoginDialogHelper;
-#else
-class ShellLoginDialogHelper;
-#endif  // __OBJC__
-#endif  // defined(OS_MACOSX)
-
-namespace net {
-class AuthChallengeInfo;
-class URLRequest;
-}
-
-namespace content {
-
-// This class provides a dialog box to ask the user for credentials. Useful in
-// ResourceDispatcherHostDelegate::CreateLoginDelegate.
-class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate {
- public:
-  // Threading: IO thread.
-  ShellLoginDialog(net::AuthChallengeInfo* auth_info, net::URLRequest* request);
-
-  // ResourceDispatcherHostLoginDelegate implementation:
-  // Threading: IO thread.
-  virtual void OnRequestCancelled() OVERRIDE;
-
-  // Called by the platform specific code when the user responds. Public because
-  // the aforementioned platform specific code may not have access to private
-  // members. Not to be called from client code.
-  // Threading: UI thread.
-  void UserAcceptedAuth(const string16& username, const string16& password);
-  void UserCancelledAuth();
-
- protected:
-  // Threading: any
-  virtual ~ShellLoginDialog();
-
- private:
-  // All the methods that begin with Platform need to be implemented by the
-  // platform specific LoginDialog implementation.
-  // Creates the dialog.
-  // Threading: UI thread.
-  void PlatformCreateDialog(const string16& message);
-  // Called from the destructor to let each platform do any necessary cleanup.
-  // Threading: UI thread.
-  void PlatformCleanUp();
-  // Called from OnRequestCancelled if the request was cancelled.
-  // Threading: UI thread.
-  void PlatformRequestCancelled();
-
-  // Sets up dialog creation.
-  // Threading: UI thread.
-  void PrepDialog(const string16& host, const string16& realm);
-
-  // Sends the authentication to the requester.
-  // Threading: IO thread.
-  void SendAuthToRequester(bool success,
-                           const string16& username,
-                           const string16& password);
-
-  // Who/where/what asked for the authentication.
-  // Threading: IO thread.
-  scoped_refptr<net::AuthChallengeInfo> auth_info_;
-
-  // The request that wants login data.
-  // Threading: IO thread.
-  net::URLRequest* request_;
-
-#if defined(OS_MACOSX)
-  // Threading: UI thread.
-  ShellLoginDialogHelper* helper_;  // owned
-#elif defined(TOOLKIT_GTK)
-  GtkWidget* username_entry_;
-  GtkWidget* password_entry_;
-  GtkWidget* root_;
-  CHROMEGTK_CALLBACK_1(ShellLoginDialog, void, OnResponse, int);
-#endif
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_LOGIN_DIALOG_H_
diff --git a/content/shell/shell_login_dialog_gtk.cc b/content/shell/shell_login_dialog_gtk.cc
deleted file mode 100644
index 1be48d3..0000000
--- a/content/shell/shell_login_dialog_gtk.cc
+++ /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.
-
-#include "content/shell/shell_login_dialog.h"
-
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_dispatcher_host.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "ui/base/gtk/gtk_hig_constants.h"
-
-namespace content {
-
-void ShellLoginDialog::PlatformCreateDialog(const string16& message) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  int render_process_id;
-  int render_view_id;
-  if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderView(
-          &render_process_id,  &render_view_id)) {
-    NOTREACHED();
-  }
-
-  WebContents* web_contents = NULL;
-  RenderViewHost* render_view_host =
-      RenderViewHost::FromID(render_process_id, render_view_id);
-  if (render_view_host)
-    web_contents = WebContents::FromRenderViewHost(render_view_host);
-  DCHECK(web_contents);
-
-  gfx::NativeWindow parent_window =
-      web_contents->GetView()->GetTopLevelNativeWindow();
-
-  root_ = gtk_message_dialog_new(parent_window,
-                                 GTK_DIALOG_MODAL,
-                                 GTK_MESSAGE_INFO,
-                                 GTK_BUTTONS_OK_CANCEL,
-                                 "Please log in.");
-
-  GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(root_));
-  GtkWidget* label = gtk_label_new(UTF16ToUTF8(message).c_str());
-  gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
-  gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0);
-
-  username_entry_ = gtk_entry_new();
-  gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);
-
-  password_entry_ = gtk_entry_new();
-  gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
-  gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
-
-  GtkWidget* table = gtk_table_new(2, 2, FALSE);
-  gtk_table_set_col_spacing(GTK_TABLE(table), 0, ui::kLabelSpacing);
-  gtk_table_set_row_spacings(GTK_TABLE(table), ui::kControlSpacing);
-
-  GtkWidget* username_label = gtk_label_new("Username:");
-  gtk_misc_set_alignment(GTK_MISC(username_label), 0, 0.5);
-
-  gtk_table_attach(GTK_TABLE(table), username_label, 0, 1, 0, 1, GTK_FILL,
-                   GTK_FILL, 0, 0);
-  gtk_table_attach_defaults(GTK_TABLE(table), username_entry_, 1, 2, 0, 1);
-
-  GtkWidget* password_label = gtk_label_new("Password:");
-  gtk_misc_set_alignment(GTK_MISC(password_label), 0, 0.5);
-
-  gtk_table_attach(GTK_TABLE(table), password_label, 0, 1, 1, 2, GTK_FILL,
-                   GTK_FILL, 0, 0);
-  gtk_table_attach_defaults(GTK_TABLE(table), password_entry_, 1, 2, 1, 2);
-
-  gtk_box_pack_start(GTK_BOX(content_area), table, FALSE, FALSE, 0);
-
-  g_signal_connect(root_, "response", G_CALLBACK(OnResponseThunk), this);
-  gtk_widget_grab_focus(username_entry_);
-  gtk_widget_show_all(GTK_WIDGET(root_));
-}
-
-void ShellLoginDialog::PlatformCleanUp() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-void ShellLoginDialog::PlatformRequestCancelled() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-void ShellLoginDialog::OnResponse(GtkWidget* sender, int response_id) {
-  switch (response_id) {
-    case GTK_RESPONSE_OK:
-      UserAcceptedAuth(
-          UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
-          UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
-      break;
-    case GTK_RESPONSE_CANCEL:
-    case GTK_RESPONSE_DELETE_EVENT:
-      UserCancelledAuth();
-      break;
-    default:
-      NOTREACHED();
-  }
-
-  gtk_widget_destroy(root_);
-}
-
-}  // namespace content
diff --git a/content/shell/shell_login_dialog_mac.mm b/content/shell/shell_login_dialog_mac.mm
deleted file mode 100644
index b7d6947..0000000
--- a/content/shell/shell_login_dialog_mac.mm
+++ /dev/null
@@ -1,122 +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/shell/shell_login_dialog.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/logging.h"
-#include "base/mac/bundle_locations.h"
-#import "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
-#include "content/public/browser/browser_thread.h"
-#import "ui/base/cocoa/nib_loading.h"
-
-namespace {
-
-const int kUsernameFieldTag = 1;
-const int kPasswordFieldTag = 2;
-
-}  // namespace
-
-// Helper object that receives the notification that the dialog/sheet is
-// going away.
-@interface ShellLoginDialogHelper : NSObject<NSAlertDelegate> {
- @private
-  base::scoped_nsobject<NSAlert> alert_;
-  NSTextField* usernameField_;  // WEAK; owned by alert_
-  NSSecureTextField* passwordField_;  // WEAK; owned by alert_
-}
-
-- (NSAlert*)alert;
-- (NSView*)accessoryView;
-- (void)focus;
-- (void)alertDidEnd:(NSAlert*)alert
-         returnCode:(int)returnCode
-        contextInfo:(void*)contextInfo;
-- (void)cancel;
-
-@end
-
-@implementation ShellLoginDialogHelper
-
-- (NSAlert*)alert {
-  alert_.reset([[NSAlert alloc] init]);
-  [alert_ setAccessoryView:[self accessoryView]];
-  return alert_;
-}
-
-- (NSView*)accessoryView {
-  NSView* accessory_view = ui::GetViewFromNib(@"HttpAuth");
-  if (!accessory_view)
-    return nil;
-
-  usernameField_ = [accessory_view viewWithTag:kUsernameFieldTag];
-  passwordField_ = [accessory_view viewWithTag:kPasswordFieldTag];
-  return accessory_view;
-}
-
-- (void)focus {
-  [[alert_ window] makeFirstResponder:usernameField_];
-}
-
-- (void)alertDidEnd:(NSAlert*)alert
-         returnCode:(int)returnCode
-        contextInfo:(void*)contextInfo {
-  if (returnCode == NSRunStoppedResponse)
-    return;
-
-  content::ShellLoginDialog* this_dialog =
-      reinterpret_cast<content::ShellLoginDialog*>(contextInfo);
-  if (returnCode == NSAlertFirstButtonReturn) {
-    this_dialog->UserAcceptedAuth(
-        base::SysNSStringToUTF16([usernameField_ stringValue]),
-        base::SysNSStringToUTF16([passwordField_ stringValue]));
-  } else {
-    this_dialog->UserCancelledAuth();
-  }
-}
-
-- (void)cancel {
-  [NSApp endSheet:[alert_ window]];
-  alert_.reset();
-}
-
-@end
-
-namespace content {
-
-void ShellLoginDialog::PlatformCreateDialog(const string16& message) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  helper_ = [[ShellLoginDialogHelper alloc] init];
-
-  // Show the modal dialog.
-  NSAlert* alert = [helper_ alert];
-  [alert setDelegate:helper_];
-  [alert setInformativeText:base::SysUTF16ToNSString(message)];
-  [alert setMessageText:@"Please log in."];
-  [alert addButtonWithTitle:@"OK"];
-  NSButton* other = [alert addButtonWithTitle:@"Cancel"];
-  [other setKeyEquivalent:@"\e"];
-  [alert
-      beginSheetModalForWindow:nil  // nil here makes it app-modal
-                 modalDelegate:helper_
-                didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
-                   contextInfo:this];
-
-  [helper_ focus];
-}
-
-void ShellLoginDialog::PlatformCleanUp() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  [helper_ release];
-  helper_ = nil;
-}
-
-void ShellLoginDialog::PlatformRequestCancelled() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  [helper_ cancel];
-}
-
-}  // namespace content
diff --git a/content/shell/shell_mac.mm b/content/shell/shell_mac.mm
deleted file mode 100644
index 370a64d..0000000
--- a/content/shell/shell_mac.mm
+++ /dev/null
@@ -1,334 +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/shell/shell.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#import "base/mac/scoped_nsobject.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/sys_string_conversions.h"
-#include "content/public/browser/native_web_keyboard_event.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/shell/app/resource.h"
-#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
-#include "url/gurl.h"
-
-#if !defined(MAC_OS_X_VERSION_10_7) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
-
-enum {
-  NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
-  NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8
-};
-
-#endif // MAC_OS_X_VERSION_10_7
-
-// Receives notification that the window is closing so that it can start the
-// tear-down process. Is responsible for deleting itself when done.
-@interface ContentShellWindowDelegate : NSObject<NSWindowDelegate> {
- @private
-  content::Shell* shell_;
-}
-- (id)initWithShell:(content::Shell*)shell;
-@end
-
-@implementation ContentShellWindowDelegate
-
-- (id)initWithShell:(content::Shell*)shell {
-  if ((self = [super init])) {
-    shell_ = shell;
-  }
-  return self;
-}
-
-// Called when the window is about to close. Perform the self-destruction
-// sequence by getting rid of the shell and removing it and the window from
-// the various global lists. By returning YES, we allow the window to be
-// removed from the screen.
-- (BOOL)windowShouldClose:(id)window {
-  [window autorelease];
-  delete shell_;
-  [self release];
-
-  return YES;
-}
-
-- (void)performAction:(id)sender {
-  shell_->ActionPerformed([sender tag]);
-}
-
-- (void)takeURLStringValueFrom:(id)sender {
-  shell_->URLEntered(base::SysNSStringToUTF8([sender stringValue]));
-}
-
-@end
-
-@interface CrShellWindow : UnderlayOpenGLHostingWindow {
- @private
-  content::Shell* shell_;
-}
-- (void)setShell:(content::Shell*)shell;
-- (void)showDevTools:(id)sender;
-@end
-
-@implementation CrShellWindow
-
-- (void)setShell:(content::Shell*)shell {
-  shell_ = shell;
-}
-
-- (void)showDevTools:(id)sender {
-  shell_->ShowDevTools();
-}
-
-@end
-
-namespace {
-
-NSString* kWindowTitle = @"Content Shell";
-
-// Layout constants (in view coordinates)
-const CGFloat kButtonWidth = 72;
-const CGFloat kURLBarHeight = 24;
-
-// The minimum size of the window's content (in view coordinates)
-const CGFloat kMinimumWindowWidth = 400;
-const CGFloat kMinimumWindowHeight = 300;
-
-void MakeShellButton(NSRect* rect,
-                     NSString* title,
-                     NSView* parent,
-                     int control,
-                     NSView* target,
-                     NSString* key,
-                     NSUInteger modifier) {
-  base::scoped_nsobject<NSButton> button(
-      [[NSButton alloc] initWithFrame:*rect]);
-  [button setTitle:title];
-  [button setBezelStyle:NSSmallSquareBezelStyle];
-  [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
-  [button setTarget:target];
-  [button setAction:@selector(performAction:)];
-  [button setTag:control];
-  [button setKeyEquivalent:key];
-  [button setKeyEquivalentModifierMask:modifier];
-  [parent addSubview:button];
-  rect->origin.x += kButtonWidth;
-}
-
-}  // namespace
-
-namespace content {
-
-void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
-}
-
-void Shell::PlatformCleanUp() {
-}
-
-void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
-  if (headless_)
-    return;
-
-  int id;
-  switch (control) {
-    case BACK_BUTTON:
-      id = IDC_NAV_BACK;
-      break;
-    case FORWARD_BUTTON:
-      id = IDC_NAV_FORWARD;
-      break;
-    case STOP_BUTTON:
-      id = IDC_NAV_STOP;
-      break;
-    default:
-      NOTREACHED() << "Unknown UI control";
-      return;
-  }
-  [[[window_ contentView] viewWithTag:id] setEnabled:is_enabled];
-}
-
-void Shell::PlatformSetAddressBarURL(const GURL& url) {
-  if (headless_)
-    return;
-
-  NSString* url_string = base::SysUTF8ToNSString(url.spec());
-  [url_edit_view_ setStringValue:url_string];
-}
-
-void Shell::PlatformSetIsLoading(bool loading) {
-}
-
-void Shell::PlatformCreateWindow(int width, int height) {
-  if (headless_) {
-    content_width_ = width;
-    content_height_ = height;
-    return;
-  }
-
-  NSRect initial_window_bounds =
-      NSMakeRect(0, 0, width, height + kURLBarHeight);
-  NSRect content_rect = initial_window_bounds;
-  NSUInteger style_mask = NSTitledWindowMask |
-                          NSClosableWindowMask |
-                          NSMiniaturizableWindowMask |
-                          NSResizableWindowMask;
-  CrShellWindow* window =
-      [[CrShellWindow alloc] initWithContentRect:content_rect
-                                       styleMask:style_mask
-                                         backing:NSBackingStoreBuffered
-                                           defer:NO];
-  window_ = window;
-  [window setShell:this];
-  [window_ setTitle:kWindowTitle];
-  NSView* content = [window_ contentView];
-
-  // If the window is allowed to get too small, it will wreck the view bindings.
-  NSSize min_size = NSMakeSize(kMinimumWindowWidth, kMinimumWindowHeight);
-  min_size = [content convertSize:min_size toView:nil];
-  // Note that this takes window coordinates.
-  [window_ setContentMinSize:min_size];
-
-  // Set the shell window to participate in Lion Fullscreen mode. Set
-  // Setting this flag has no effect on Snow Leopard or earlier.
-  NSUInteger collectionBehavior = [window_ collectionBehavior];
-  collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
-  [window_ setCollectionBehavior:collectionBehavior];
-
-  // Rely on the window delegate to clean us up rather than immediately
-  // releasing when the window gets closed. We use the delegate to do
-  // everything from the autorelease pool so the shell isn't on the stack
-  // during cleanup (ie, a window close from javascript).
-  [window_ setReleasedWhenClosed:NO];
-
-  // Create a window delegate to watch for when it's asked to go away. It will
-  // clean itself up so we don't need to hold a reference.
-  ContentShellWindowDelegate* delegate =
-      [[ContentShellWindowDelegate alloc] initWithShell:this];
-  [window_ setDelegate:delegate];
-
-  NSRect button_frame =
-      NSMakeRect(0, NSMaxY(initial_window_bounds) - kURLBarHeight,
-                 kButtonWidth, kURLBarHeight);
-
-  MakeShellButton(&button_frame, @"Back", content, IDC_NAV_BACK,
-                  (NSView*)delegate, @"[", NSCommandKeyMask);
-  MakeShellButton(&button_frame, @"Forward", content, IDC_NAV_FORWARD,
-                  (NSView*)delegate, @"]", NSCommandKeyMask);
-  MakeShellButton(&button_frame, @"Reload", content, IDC_NAV_RELOAD,
-                  (NSView*)delegate, @"r", NSCommandKeyMask);
-  MakeShellButton(&button_frame, @"Stop", content, IDC_NAV_STOP,
-                  (NSView*)delegate, @".", NSCommandKeyMask);
-
-  button_frame.size.width =
-      NSWidth(initial_window_bounds) - NSMinX(button_frame);
-  base::scoped_nsobject<NSTextField> url_edit_view(
-      [[NSTextField alloc] initWithFrame:button_frame]);
-  [content addSubview:url_edit_view];
-  [url_edit_view setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
-  [url_edit_view setTarget:delegate];
-  [url_edit_view setAction:@selector(takeURLStringValueFrom:)];
-  [[url_edit_view cell] setWraps:NO];
-  [[url_edit_view cell] setScrollable:YES];
-  url_edit_view_ = url_edit_view.get();
-
-  // show the window
-  [window_ makeKeyAndOrderFront:nil];
-}
-
-void Shell::PlatformSetContents() {
-  NSView* web_view = web_contents_->GetView()->GetNativeView();
-  [web_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
-
-  if (headless_) {
-    SizeTo(content_width_, content_height_);
-    return;
-  }
-
-  NSView* content = [window_ contentView];
-  [content addSubview:web_view];
-
-  NSRect frame = [content bounds];
-  frame.size.height -= kURLBarHeight;
-  [web_view setFrame:frame];
-  [web_view setNeedsDisplay:YES];
-}
-
-void Shell::SizeTo(int width, int height) {
-  if (!headless_) {
-    NOTREACHED();
-    return;
-  }
-  NSView* web_view = web_contents_->GetView()->GetNativeView();
-  NSRect frame = NSMakeRect(0, 0, width, height);
-  [web_view setFrame:frame];
-}
-
-void Shell::PlatformResizeSubViews() {
-  // Not needed; subviews are bound.
-}
-
-void Shell::PlatformSetTitle(const string16& title) {
-  if (headless_)
-    return;
-
-  NSString* title_string = base::SysUTF16ToNSString(title);
-  [window_ setTitle:title_string];
-}
-
-void Shell::Close() {
-  if (headless_)
-    delete this;
-  else
-    [window_ performClose:nil];
-}
-
-void Shell::ActionPerformed(int control) {
-  switch (control) {
-    case IDC_NAV_BACK:
-      GoBackOrForward(-1);
-      break;
-    case IDC_NAV_FORWARD:
-      GoBackOrForward(1);
-      break;
-    case IDC_NAV_RELOAD:
-      Reload();
-      break;
-    case IDC_NAV_STOP:
-      Stop();
-      break;
-  }
-}
-
-void Shell::URLEntered(std::string url_string) {
-  if (!url_string.empty()) {
-    GURL url(url_string);
-    if (!url.has_scheme())
-      url = GURL("http://" + url_string);
-    LoadURL(url);
-  }
-}
-
-void Shell::HandleKeyboardEvent(WebContents* source,
-                                const NativeWebKeyboardEvent& event) {
-  if (event.skip_in_browser)
-    return;
-
-  // The event handling to get this strictly right is a tangle; cheat here a bit
-  // by just letting the menus have a chance at it.
-  if ([event.os_event type] == NSKeyDown) {
-    if (([event.os_event modifierFlags] & NSCommandKeyMask) &&
-        [[event.os_event characters] isEqual:@"l"]) {
-      [window_ makeFirstResponder:url_edit_view_];
-      return;
-    }
-
-    [[NSApp mainMenu] performKeyEquivalent:event.os_event];
-  }
-}
-
-}  // namespace content
diff --git a/content/shell/shell_message_filter.cc b/content/shell/shell_message_filter.cc
deleted file mode 100644
index 7bfe826..0000000
--- a/content/shell/shell_message_filter.cc
+++ /dev/null
@@ -1,105 +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/shell/shell_message_filter.h"
-
-#include "base/file_util.h"
-#include "base/threading/thread_restrictions.h"
-#include "content/public/browser/child_process_security_policy.h"
-#include "content/shell/common/shell_messages.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_network_delegate.h"
-#include "net/base/net_errors.h"
-#include "net/cookies/cookie_monster.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "webkit/browser/database/database_tracker.h"
-#include "webkit/browser/fileapi/isolated_context.h"
-#include "webkit/browser/quota/quota_manager.h"
-
-namespace content {
-
-ShellMessageFilter::ShellMessageFilter(
-    int render_process_id,
-    webkit_database::DatabaseTracker* database_tracker,
-    quota::QuotaManager* quota_manager,
-    net::URLRequestContextGetter* request_context_getter)
-    : render_process_id_(render_process_id),
-      database_tracker_(database_tracker),
-      quota_manager_(quota_manager),
-      request_context_getter_(request_context_getter) {
-}
-
-ShellMessageFilter::~ShellMessageFilter() {
-}
-
-void ShellMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
-                                                  BrowserThread::ID* thread) {
-  if (message.type() == ShellViewHostMsg_ClearAllDatabases::ID)
-    *thread = BrowserThread::FILE;
-}
-
-bool ShellMessageFilter::OnMessageReceived(const IPC::Message& message,
-                                           bool* message_was_ok) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP_EX(ShellMessageFilter, message, *message_was_ok)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ReadFileToString, OnReadFileToString)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_RegisterIsolatedFileSystem,
-                        OnRegisterIsolatedFileSystem)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ClearAllDatabases, OnClearAllDatabases)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_SetDatabaseQuota, OnSetDatabaseQuota)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_AcceptAllCookies, OnAcceptAllCookies)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_DeleteAllCookies, OnDeleteAllCookies)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-void ShellMessageFilter::OnReadFileToString(const base::FilePath& local_file,
-                                            std::string* contents) {
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
-  file_util::ReadFileToString(local_file, contents);
-}
-
-void ShellMessageFilter::OnRegisterIsolatedFileSystem(
-    const std::vector<base::FilePath>& absolute_filenames,
-    std::string* filesystem_id) {
-  fileapi::IsolatedContext::FileInfoSet files;
-  ChildProcessSecurityPolicy* policy =
-      ChildProcessSecurityPolicy::GetInstance();
-  for (size_t i = 0; i < absolute_filenames.size(); ++i) {
-    files.AddPath(absolute_filenames[i], NULL);
-    if (!policy->CanReadFile(render_process_id_, absolute_filenames[i]))
-      policy->GrantReadFile(render_process_id_, absolute_filenames[i]);
-  }
-  *filesystem_id =
-      fileapi::IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files);
-  policy->GrantReadFileSystem(render_process_id_, *filesystem_id);
-}
-
-void ShellMessageFilter::OnClearAllDatabases() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-  database_tracker_->DeleteDataModifiedSince(
-      base::Time(), net::CompletionCallback());
-}
-
-void ShellMessageFilter::OnSetDatabaseQuota(int quota) {
-  quota_manager_->SetTemporaryGlobalOverrideQuota(
-      quota * quota::QuotaManager::kPerHostTemporaryPortion,
-      quota::QuotaCallback());
-}
-
-void ShellMessageFilter::OnAcceptAllCookies(bool accept) {
-  ShellNetworkDelegate::SetAcceptAllCookies(accept);
-}
-
-void ShellMessageFilter::OnDeleteAllCookies() {
-  request_context_getter_->GetURLRequestContext()->cookie_store()
-      ->GetCookieMonster()
-      ->DeleteAllAsync(net::CookieMonster::DeleteCallback());
-}
-
-}  // namespace content
diff --git a/content/shell/shell_message_filter.h b/content/shell/shell_message_filter.h
deleted file mode 100644
index b53908e..0000000
--- a/content/shell/shell_message_filter.h
+++ /dev/null
@@ -1,66 +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_SHELL_SHELL_MESSAGE_FILTER_H_
-#define CONTENT_SHELL_SHELL_MESSAGE_FILTER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "content/public/browser/browser_message_filter.h"
-
-namespace net {
-class URLRequestContextGetter;
-}
-
-namespace quota {
-class QuotaManager;
-}
-
-namespace webkit_database {
-class DatabaseTracker;
-}
-
-namespace content {
-
-class ShellMessageFilter : public BrowserMessageFilter {
- public:
-  ShellMessageFilter(int render_process_id,
-                     webkit_database::DatabaseTracker* database_tracker,
-                     quota::QuotaManager* quota_manager,
-                     net::URLRequestContextGetter* request_context_getter);
-
- private:
-  virtual ~ShellMessageFilter();
-
-  // BrowserMessageFilter implementation.
-  virtual void OverrideThreadForMessage(const IPC::Message& message,
-                                        BrowserThread::ID* thread) OVERRIDE;
-  virtual bool OnMessageReceived(const IPC::Message& message,
-                                 bool* message_was_ok) OVERRIDE;
-
-  void OnReadFileToString(const base::FilePath& local_file,
-                          std::string* contents);
-  void OnRegisterIsolatedFileSystem(
-      const std::vector<base::FilePath>& absolute_filenames,
-      std::string* filesystem_id);
-  void OnClearAllDatabases();
-  void OnSetDatabaseQuota(int quota);
-  void OnAcceptAllCookies(bool accept);
-  void OnDeleteAllCookies();
-
-  int render_process_id_;
-
-  webkit_database::DatabaseTracker* database_tracker_;
-  quota::QuotaManager* quota_manager_;
-  net::URLRequestContextGetter* request_context_getter_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellMessageFilter);
-};
-
-}  // namespace content
-
-#endif // CONTENT_SHELL_SHELL_MESSAGE_FILTER_H_
diff --git a/content/shell/shell_net_log.cc b/content/shell/shell_net_log.cc
deleted file mode 100644
index 03443d2..0000000
--- a/content/shell/shell_net_log.cc
+++ /dev/null
@@ -1,72 +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/shell/shell_net_log.h"
-
-#include <stdio.h>
-
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/values.h"
-#include "content/public/common/content_switches.h"
-#include "net/base/net_log_logger.h"
-
-namespace content {
-
-namespace {
-
-base::DictionaryValue* GetShellConstants() {
-  base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
-
-  // Add a dictionary with client information
-  base::DictionaryValue* dict = new DictionaryValue();
-
-  dict->SetString("name", "content_shell");
-  dict->SetString("command_line",
-                  CommandLine::ForCurrentProcess()->GetCommandLineString());
-
-  constants_dict->Set("clientInfo", dict);
-
-  return constants_dict;
-}
-
-}  // namespace
-
-ShellNetLog::ShellNetLog() {
-  const CommandLine* command_line = CommandLine::ForCurrentProcess();
-
-  if (command_line->HasSwitch(switches::kLogNetLog)) {
-    base::FilePath log_path =
-        command_line->GetSwitchValuePath(switches::kLogNetLog);
-    // Much like logging.h, bypass threading restrictions by using fopen
-    // directly.  Have to write on a thread that's shutdown to handle events on
-    // shutdown properly, and posting events to another thread as they occur
-    // would result in an unbounded buffer size, so not much can be gained by
-    // doing this on another thread.  It's only used when debugging, so
-    // performance is not a big concern.
-    FILE* file = NULL;
-#if defined(OS_WIN)
-    file = _wfopen(log_path.value().c_str(), L"w");
-#elif defined(OS_POSIX)
-    file = fopen(log_path.value().c_str(), "w");
-#endif
-
-    if (file == NULL) {
-      LOG(ERROR) << "Could not open file " << log_path.value()
-                 << " for net logging";
-    } else {
-      scoped_ptr<base::Value> constants(GetShellConstants());
-      net_log_logger_.reset(new net::NetLogLogger(file, *constants));
-      net_log_logger_->StartObserving(this);
-    }
-  }
-}
-
-ShellNetLog::~ShellNetLog() {
-  // Remove the observer we own before we're destroyed.
-  if (net_log_logger_)
-    RemoveThreadSafeObserver(net_log_logger_.get());
-}
-
-}  // namespace content
diff --git a/content/shell/shell_net_log.h b/content/shell/shell_net_log.h
deleted file mode 100644
index ead9108..0000000
--- a/content/shell/shell_net_log.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 CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_
-#define CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_
-
-#include <string>
-
-#include "base/memory/scoped_ptr.h"
-#include "net/base/net_log_logger.h"
-
-namespace content {
-
-class ShellNetLog : public net::NetLog {
- public:
-  ShellNetLog();
-  virtual ~ShellNetLog();
-
- private:
-  scoped_ptr<net::NetLogLogger> net_log_logger_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellNetLog);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_CONTENT_BROWSER_CLIENT_H_
diff --git a/content/shell/shell_network_delegate.cc b/content/shell/shell_network_delegate.cc
deleted file mode 100644
index e633686..0000000
--- a/content/shell/shell_network_delegate.cc
+++ /dev/null
@@ -1,127 +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/shell/shell_network_delegate.h"
-
-#include "net/base/net_errors.h"
-#include "net/base/static_cookie_policy.h"
-#include "net/url_request/url_request.h"
-
-namespace content {
-
-namespace {
-bool g_accept_all_cookies = true;
-}
-
-ShellNetworkDelegate::ShellNetworkDelegate() {
-}
-
-ShellNetworkDelegate::~ShellNetworkDelegate() {
-}
-
-void ShellNetworkDelegate::SetAcceptAllCookies(bool accept) {
-  g_accept_all_cookies = accept;
-}
-
-int ShellNetworkDelegate::OnBeforeURLRequest(
-    net::URLRequest* request,
-    const net::CompletionCallback& callback,
-    GURL* new_url) {
-  return net::OK;
-}
-
-int ShellNetworkDelegate::OnBeforeSendHeaders(
-    net::URLRequest* request,
-    const net::CompletionCallback& callback,
-    net::HttpRequestHeaders* headers) {
-  return net::OK;
-}
-
-void ShellNetworkDelegate::OnSendHeaders(
-    net::URLRequest* request,
-    const net::HttpRequestHeaders& headers) {
-}
-
-int ShellNetworkDelegate::OnHeadersReceived(
-    net::URLRequest* request,
-    const net::CompletionCallback& callback,
-    const net::HttpResponseHeaders* original_response_headers,
-    scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
-  return net::OK;
-}
-
-void ShellNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
-                                            const GURL& new_location) {
-}
-
-void ShellNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
-}
-
-void ShellNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
-                                          int bytes_read) {
-}
-
-void ShellNetworkDelegate::OnCompleted(net::URLRequest* request, bool started) {
-}
-
-void ShellNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {
-}
-
-void ShellNetworkDelegate::OnPACScriptError(int line_number,
-                                            const string16& error) {
-}
-
-ShellNetworkDelegate::AuthRequiredResponse ShellNetworkDelegate::OnAuthRequired(
-    net::URLRequest* request,
-    const net::AuthChallengeInfo& auth_info,
-    const AuthCallback& callback,
-    net::AuthCredentials* credentials) {
-  return AUTH_REQUIRED_RESPONSE_NO_ACTION;
-}
-
-bool ShellNetworkDelegate::OnCanGetCookies(const net::URLRequest& request,
-                                           const net::CookieList& cookie_list) {
-  net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
-      net::StaticCookiePolicy::ALLOW_ALL_COOKIES :
-      net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
-  net::StaticCookiePolicy policy(policy_type);
-  int rv = policy.CanGetCookies(
-      request.url(), request.first_party_for_cookies());
-  return rv == net::OK;
-}
-
-bool ShellNetworkDelegate::OnCanSetCookie(const net::URLRequest& request,
-                                          const std::string& cookie_line,
-                                          net::CookieOptions* options) {
-  net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
-      net::StaticCookiePolicy::ALLOW_ALL_COOKIES :
-      net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
-  net::StaticCookiePolicy policy(policy_type);
-  int rv = policy.CanSetCookie(
-      request.url(), request.first_party_for_cookies());
-  return rv == net::OK;
-}
-
-bool ShellNetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
-                                           const base::FilePath& path) const {
-  return true;
-}
-
-bool ShellNetworkDelegate::OnCanThrottleRequest(
-    const net::URLRequest& request) const {
-  return false;
-}
-
-int ShellNetworkDelegate::OnBeforeSocketStreamConnect(
-    net::SocketStream* socket,
-    const net::CompletionCallback& callback) {
-  return net::OK;
-}
-
-void ShellNetworkDelegate::OnRequestWaitStateChange(
-    const net::URLRequest& request,
-    RequestWaitState waiting) {
-}
-
-}  // namespace content
diff --git a/content/shell/shell_network_delegate.h b/content/shell/shell_network_delegate.h
deleted file mode 100644
index c2f5e8e..0000000
--- a/content/shell/shell_network_delegate.h
+++ /dev/null
@@ -1,71 +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_SHELL_SHELL_NETWORK_DELEGATE_H_
-#define CONTENT_SHELL_SHELL_NETWORK_DELEGATE_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "net/base/network_delegate.h"
-
-namespace content {
-
-class ShellNetworkDelegate : public net::NetworkDelegate {
- public:
-  ShellNetworkDelegate();
-  virtual ~ShellNetworkDelegate();
-
-  static void SetAcceptAllCookies(bool accept);
-
- private:
-  // net::NetworkDelegate implementation.
-  virtual int OnBeforeURLRequest(net::URLRequest* request,
-                                 const net::CompletionCallback& callback,
-                                 GURL* new_url) OVERRIDE;
-  virtual int OnBeforeSendHeaders(net::URLRequest* request,
-                                  const net::CompletionCallback& callback,
-                                  net::HttpRequestHeaders* headers) OVERRIDE;
-  virtual void OnSendHeaders(net::URLRequest* request,
-                             const net::HttpRequestHeaders& headers) OVERRIDE;
-  virtual int OnHeadersReceived(
-      net::URLRequest* request,
-      const net::CompletionCallback& callback,
-      const net::HttpResponseHeaders* original_response_headers,
-      scoped_refptr<net::HttpResponseHeaders>*
-          override_response_headers) OVERRIDE;
-  virtual void OnBeforeRedirect(net::URLRequest* request,
-                                const GURL& new_location) OVERRIDE;
-  virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
-  virtual void OnRawBytesRead(const net::URLRequest& request,
-                              int bytes_read) OVERRIDE;
-  virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE;
-  virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE;
-  virtual void OnPACScriptError(int line_number,
-                                const string16& error) OVERRIDE;
-  virtual AuthRequiredResponse OnAuthRequired(
-      net::URLRequest* request,
-      const net::AuthChallengeInfo& auth_info,
-      const AuthCallback& callback,
-      net::AuthCredentials* credentials) OVERRIDE;
-  virtual bool OnCanGetCookies(const net::URLRequest& request,
-                               const net::CookieList& cookie_list) OVERRIDE;
-  virtual bool OnCanSetCookie(const net::URLRequest& request,
-                              const std::string& cookie_line,
-                              net::CookieOptions* options) OVERRIDE;
-  virtual bool OnCanAccessFile(const net::URLRequest& request,
-                               const base::FilePath& path) const OVERRIDE;
-  virtual bool OnCanThrottleRequest(
-      const net::URLRequest& request) const OVERRIDE;
-  virtual int OnBeforeSocketStreamConnect(
-      net::SocketStream* stream,
-      const net::CompletionCallback& callback) OVERRIDE;
-  virtual void OnRequestWaitStateChange(const net::URLRequest& request,
-                                        RequestWaitState state) OVERRIDE;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_NETWORK_DELEGATE_H_
diff --git a/content/shell/shell_plugin_service_filter.cc b/content/shell/shell_plugin_service_filter.cc
deleted file mode 100644
index f164637..0000000
--- a/content/shell/shell_plugin_service_filter.cc
+++ /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.
-
-#include "content/shell/shell_plugin_service_filter.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "content/public/common/webplugininfo.h"
-
-namespace content {
-
-ShellPluginServiceFilter::ShellPluginServiceFilter() {}
-
-ShellPluginServiceFilter::~ShellPluginServiceFilter() {}
-
-bool ShellPluginServiceFilter::IsPluginAvailable(
-    int render_process_id,
-    int render_view_id,
-    const void* context,
-    const GURL& url,
-    const GURL& policy_url,
-    WebPluginInfo* plugin) {
-  return plugin->name == ASCIIToUTF16("WebKit Test PlugIn");
-}
-
-bool ShellPluginServiceFilter::CanLoadPlugin(int render_process_id,
-                                             const base::FilePath& path) {
-  return true;
-}
-
-}  // namespace content
diff --git a/content/shell/shell_plugin_service_filter.h b/content/shell/shell_plugin_service_filter.h
deleted file mode 100644
index a489aff..0000000
--- a/content/shell/shell_plugin_service_filter.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 CONTENT_SHELL_SHELL_PLUGIN_SERVICE_FILTER_H_
-#define CONTENT_SHELL_SHELL_PLUGIN_SERVICE_FILTER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/public/browser/plugin_service_filter.h"
-
-namespace content {
-
-class ShellPluginServiceFilter : public PluginServiceFilter {
- public:
-  ShellPluginServiceFilter();
-  virtual ~ShellPluginServiceFilter();
-
-  // PluginServiceFilter implementation.
-  virtual bool IsPluginAvailable(int render_process_id,
-                                 int render_view_id,
-                                 const void* context,
-                                 const GURL& url,
-                                 const GURL& policy_url,
-                                 WebPluginInfo* plugin) OVERRIDE;
-
-  virtual bool CanLoadPlugin(int render_process_id,
-                             const base::FilePath& path) OVERRIDE;
-
- private:
-
-  DISALLOW_COPY_AND_ASSIGN(ShellPluginServiceFilter);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_PLUGIN_SERVICE_FILTER_H_
diff --git a/content/shell/shell_quota_permission_context.cc b/content/shell/shell_quota_permission_context.cc
deleted file mode 100644
index fe0df90..0000000
--- a/content/shell/shell_quota_permission_context.cc
+++ /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.
-
-#include "content/shell/shell_quota_permission_context.h"
-
-#include "webkit/common/quota/quota_types.h"
-
-namespace content {
-
-ShellQuotaPermissionContext::ShellQuotaPermissionContext() {}
-
-void ShellQuotaPermissionContext::RequestQuotaPermission(
-    const GURL& origin_url,
-    quota::StorageType type,
-    int64 requested_quota,
-    int render_process_id,
-    int render_view_id,
-    const PermissionCallback& callback) {
-  if (type != quota::kStorageTypePersistent) {
-    // For now we only support requesting quota with this interface
-    // for Persistent storage type.
-    callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
-    return;
-  }
-
-  callback.Run(QUOTA_PERMISSION_RESPONSE_ALLOW);
-}
-
-ShellQuotaPermissionContext::~ShellQuotaPermissionContext() {}
-
-}  // namespace content
diff --git a/content/shell/shell_quota_permission_context.h b/content/shell/shell_quota_permission_context.h
deleted file mode 100644
index af7f62f..0000000
--- a/content/shell/shell_quota_permission_context.h
+++ /dev/null
@@ -1,34 +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_SHELL_SHELL_QUOTA_PERMISSION_CONTEXT_H_
-#define CONTENT_SHELL_SHELL_QUOTA_PERMISSION_CONTEXT_H_
-
-#include "base/compiler_specific.h"
-#include "content/public/browser/quota_permission_context.h"
-
-namespace content {
-
-class ShellQuotaPermissionContext : public QuotaPermissionContext {
- public:
-  ShellQuotaPermissionContext();
-
-  // The callback will be dispatched on the IO thread.
-  virtual void RequestQuotaPermission(
-      const GURL& origin_url,
-      quota::StorageType type,
-      int64 new_quota,
-      int render_process_id,
-      int render_view_id,
-      const PermissionCallback& callback) OVERRIDE;
-
- private:
-  virtual ~ShellQuotaPermissionContext();
-
-  DISALLOW_COPY_AND_ASSIGN(ShellQuotaPermissionContext);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_QUOTA_PERMISSION_CONTEXT_H_
diff --git a/content/shell/shell_resource_dispatcher_host_delegate.cc b/content/shell/shell_resource_dispatcher_host_delegate.cc
deleted file mode 100644
index 1637edd..0000000
--- a/content/shell/shell_resource_dispatcher_host_delegate.cc
+++ /dev/null
@@ -1,44 +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/shell/shell_resource_dispatcher_host_delegate.h"
-
-#include "base/command_line.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell_login_dialog.h"
-
-namespace content {
-
-ShellResourceDispatcherHostDelegate::ShellResourceDispatcherHostDelegate() {
-}
-
-ShellResourceDispatcherHostDelegate::~ShellResourceDispatcherHostDelegate() {
-}
-
-bool ShellResourceDispatcherHostDelegate::AcceptAuthRequest(
-    net::URLRequest* request,
-    net::AuthChallengeInfo* auth_info) {
-  bool accept_auth_request =
-      !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
-  return accept_auth_request;
-}
-
-ResourceDispatcherHostLoginDelegate*
-ShellResourceDispatcherHostDelegate::CreateLoginDelegate(
-    net::AuthChallengeInfo* auth_info, net::URLRequest* request) {
-  if (!login_request_callback_.is_null()) {
-    login_request_callback_.Run();
-    login_request_callback_.Reset();
-    return NULL;
-  }
-
-#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK)
-// TODO: implement ShellLoginDialog for other platforms, drop this #if
-  return NULL;
-#else
-  return new ShellLoginDialog(auth_info, request);
-#endif
-}
-
-}  // namespace content
diff --git a/content/shell/shell_resource_dispatcher_host_delegate.h b/content/shell/shell_resource_dispatcher_host_delegate.h
deleted file mode 100644
index ff78e48..0000000
--- a/content/shell/shell_resource_dispatcher_host_delegate.h
+++ /dev/null
@@ -1,40 +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_SHELL_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
-#define CONTENT_SHELL_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
-
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "content/public/browser/resource_dispatcher_host_delegate.h"
-
-namespace content {
-
-class ShellResourceDispatcherHostDelegate
-    : public ResourceDispatcherHostDelegate {
- public:
-  ShellResourceDispatcherHostDelegate();
-  virtual ~ShellResourceDispatcherHostDelegate();
-
-  // ResourceDispatcherHostDelegate implementation.
-  virtual bool AcceptAuthRequest(net::URLRequest* request,
-                                 net::AuthChallengeInfo* auth_info) OVERRIDE;
-  virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
-      net::AuthChallengeInfo* auth_info, net::URLRequest* request) OVERRIDE;
-
-  // Used for content_browsertests.
-  void set_login_request_callback(
-      base::Callback<void()> login_request_callback) {
-    login_request_callback_ = login_request_callback;
-  }
-
- private:
-  base::Callback<void()> login_request_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellResourceDispatcherHostDelegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
diff --git a/content/shell/shell_url_request_context_getter.cc b/content/shell/shell_url_request_context_getter.cc
deleted file mode 100644
index dd74b9f..0000000
--- a/content/shell/shell_url_request_context_getter.cc
+++ /dev/null
@@ -1,227 +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/shell/shell_url_request_context_getter.h"
-
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/threading/worker_pool.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/common/url_constants.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell_network_delegate.h"
-#include "net/base/cache_type.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cookies/cookie_monster.h"
-#include "net/dns/host_resolver.h"
-#include "net/dns/mapped_host_resolver.h"
-#include "net/http/http_auth_handler_factory.h"
-#include "net/http/http_cache.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/http/transport_security_state.h"
-#include "net/proxy/proxy_service.h"
-#include "net/ssl/default_server_bound_cert_store.h"
-#include "net/ssl/server_bound_cert_service.h"
-#include "net/ssl/ssl_config_service_defaults.h"
-#include "net/url_request/data_protocol_handler.h"
-#include "net/url_request/file_protocol_handler.h"
-#include "net/url_request/protocol_intercept_job_factory.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_context_storage.h"
-#include "net/url_request/url_request_job_factory_impl.h"
-
-namespace content {
-
-namespace {
-
-void InstallProtocolHandlers(net::URLRequestJobFactoryImpl* job_factory,
-                             ProtocolHandlerMap* protocol_handlers) {
-  for (ProtocolHandlerMap::iterator it =
-           protocol_handlers->begin();
-       it != protocol_handlers->end();
-       ++it) {
-    bool set_protocol = job_factory->SetProtocolHandler(
-        it->first, it->second.release());
-    DCHECK(set_protocol);
-  }
-  protocol_handlers->clear();
-}
-
-}  // namespace
-
-ShellURLRequestContextGetter::ShellURLRequestContextGetter(
-    bool ignore_certificate_errors,
-    const base::FilePath& base_path,
-    base::MessageLoop* io_loop,
-    base::MessageLoop* file_loop,
-    ProtocolHandlerMap* protocol_handlers,
-    net::NetLog* net_log)
-    : ignore_certificate_errors_(ignore_certificate_errors),
-      base_path_(base_path),
-      io_loop_(io_loop),
-      file_loop_(file_loop),
-      net_log_(net_log) {
-  // Must first be created on the UI thread.
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  std::swap(protocol_handlers_, *protocol_handlers);
-
-  // We must create the proxy config service on the UI loop on Linux because it
-  // must synchronously run on the glib message loop. This will be passed to
-  // the URLRequestContextStorage on the IO thread in GetURLRequestContext().
-  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
-    proxy_config_service_.reset(
-        net::ProxyService::CreateSystemProxyConfigService(
-            io_loop_->message_loop_proxy().get(), file_loop_));
-  }
-}
-
-ShellURLRequestContextGetter::~ShellURLRequestContextGetter() {
-}
-
-net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-
-  if (!url_request_context_) {
-    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
-    url_request_context_.reset(new net::URLRequestContext());
-    url_request_context_->set_net_log(net_log_);
-    network_delegate_.reset(new ShellNetworkDelegate);
-    if (command_line.HasSwitch(switches::kDumpRenderTree))
-      ShellNetworkDelegate::SetAcceptAllCookies(false);
-    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_server_bound_cert_service(new net::ServerBoundCertService(
-        new net::DefaultServerBoundCertStore(NULL),
-        base::WorkerPool::GetTaskRunner(true)));
-    storage_->set_http_user_agent_settings(
-        new net::StaticHttpUserAgentSettings("en-us,en", EmptyString()));
-
-    scoped_ptr<net::HostResolver> host_resolver(
-        net::HostResolver::CreateDefaultResolver(
-            url_request_context_->net_log()));
-
-    storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
-    storage_->set_transport_security_state(new net::TransportSecurityState);
-    if (command_line.HasSwitch(switches::kDumpRenderTree)) {
-      storage_->set_proxy_service(net::ProxyService::CreateDirect());
-    } else {
-      // TODO(jam): use v8 if possible, look at chrome code.
-      storage_->set_proxy_service(
-          net::ProxyService::CreateUsingSystemProxyResolver(
-          proxy_config_service_.release(),
-          0,
-          url_request_context_->net_log()));
-    }
-    storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
-    storage_->set_http_auth_handler_factory(
-        net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
-    storage_->set_http_server_properties(
-        scoped_ptr<net::HttpServerProperties>(
-            new net::HttpServerPropertiesImpl()));
-
-    base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
-    net::HttpCache::DefaultBackend* main_backend =
-        new net::HttpCache::DefaultBackend(
-            net::DISK_CACHE,
-#if defined(OS_ANDROID)
-            // TODO(rdsmith): Remove when default backend for Android is
-            // changed to simple cache.
-            net::CACHE_BACKEND_SIMPLE,
-#else
-            net::CACHE_BACKEND_DEFAULT,
-#endif
-            cache_path,
-            0,
-            BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)
-                .get());
-
-    net::HttpNetworkSession::Params network_session_params;
-    network_session_params.cert_verifier =
-        url_request_context_->cert_verifier();
-    network_session_params.transport_security_state =
-        url_request_context_->transport_security_state();
-    network_session_params.server_bound_cert_service =
-        url_request_context_->server_bound_cert_service();
-    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_auth_handler_factory =
-        url_request_context_->http_auth_handler_factory();
-    network_session_params.network_delegate =
-        network_delegate_.get();
-    network_session_params.http_server_properties =
-        url_request_context_->http_server_properties();
-    network_session_params.net_log =
-        url_request_context_->net_log();
-    network_session_params.ignore_certificate_errors =
-        ignore_certificate_errors_;
-    if (command_line.HasSwitch(switches::kTestingFixedHttpPort)) {
-      int value;
-      base::StringToInt(command_line.GetSwitchValueASCII(
-          switches::kTestingFixedHttpPort), &value);
-      network_session_params.testing_fixed_http_port = value;
-    }
-    if (command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
-      int value;
-      base::StringToInt(command_line.GetSwitchValueASCII(
-          switches::kTestingFixedHttpsPort), &value);
-      network_session_params.testing_fixed_https_port = value;
-    }
-    if (command_line.HasSwitch(switches::kHostResolverRules)) {
-      scoped_ptr<net::MappedHostResolver> mapped_host_resolver(
-          new net::MappedHostResolver(host_resolver.Pass()));
-      mapped_host_resolver->SetRulesFromString(
-          command_line.GetSwitchValueASCII(switches::kHostResolverRules));
-      host_resolver = mapped_host_resolver.Pass();
-    }
-
-    // Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
-    storage_->set_host_resolver(host_resolver.Pass());
-    network_session_params.host_resolver =
-        url_request_context_->host_resolver();
-
-    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());
-    // Keep ProtocolHandlers added in sync with
-    // ShellContentBrowserClient::IsHandledURL().
-    InstallProtocolHandlers(job_factory.get(), &protocol_handlers_);
-    bool set_protocol = job_factory->SetProtocolHandler(
-        chrome::kDataScheme,
-        new net::DataProtocolHandler);
-    DCHECK(set_protocol);
-    set_protocol = job_factory->SetProtocolHandler(
-        chrome::kFileScheme,
-        new net::FileProtocolHandler);
-    DCHECK(set_protocol);
-    storage_->set_job_factory(job_factory.release());
-  }
-
-  return url_request_context_.get();
-}
-
-scoped_refptr<base::SingleThreadTaskRunner>
-    ShellURLRequestContextGetter::GetNetworkTaskRunner() const {
-  return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
-}
-
-net::HostResolver* ShellURLRequestContextGetter::host_resolver() {
-  return url_request_context_->host_resolver();
-}
-
-}  // namespace content
diff --git a/content/shell/shell_url_request_context_getter.h b/content/shell/shell_url_request_context_getter.h
deleted file mode 100644
index d1afb6f..0000000
--- a/content/shell/shell_url_request_context_getter.h
+++ /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.
-
-#ifndef CONTENT_SHELL_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
-#define CONTENT_SHELL_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
-
-#include "base/compiler_specific.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/content_browser_client.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_job_factory.h"
-
-namespace base {
-class MessageLoop;
-}
-
-namespace net {
-class HostResolver;
-class MappedHostResolver;
-class NetworkDelegate;
-class NetLog;
-class ProxyConfigService;
-class URLRequestContextStorage;
-}
-
-namespace content {
-
-class ShellURLRequestContextGetter : public net::URLRequestContextGetter {
- public:
-  ShellURLRequestContextGetter(
-      bool ignore_certificate_errors,
-      const base::FilePath& base_path,
-      base::MessageLoop* io_loop,
-      base::MessageLoop* file_loop,
-      ProtocolHandlerMap* protocol_handlers,
-      net::NetLog* net_log);
-
-  // net::URLRequestContextGetter implementation.
-  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
-  virtual scoped_refptr<base::SingleThreadTaskRunner>
-      GetNetworkTaskRunner() const OVERRIDE;
-
-  net::HostResolver* host_resolver();
-
- protected:
-  virtual ~ShellURLRequestContextGetter();
-
- private:
-  bool ignore_certificate_errors_;
-  base::FilePath base_path_;
-  base::MessageLoop* io_loop_;
-  base::MessageLoop* file_loop_;
-  net::NetLog* net_log_;
-
-  scoped_ptr<net::ProxyConfigService> proxy_config_service_;
-  scoped_ptr<net::NetworkDelegate> network_delegate_;
-  scoped_ptr<net::URLRequestContextStorage> storage_;
-  scoped_ptr<net::URLRequestContext> url_request_context_;
-  ProtocolHandlerMap protocol_handlers_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellURLRequestContextGetter);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/content/shell/shell_web_contents_view_delegate.h b/content/shell/shell_web_contents_view_delegate.h
deleted file mode 100644
index f9292a8..0000000
--- a/content/shell/shell_web_contents_view_delegate.h
+++ /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.
-
-#ifndef CONTENT_SHELL_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
-#define CONTENT_SHELL_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
-
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view_delegate.h"
-#include "content/public/common/context_menu_params.h"
-
-#if defined(TOOLKIT_GTK)
-#include "ui/base/gtk/gtk_signal.h"
-#include "ui/base/gtk/owned_widget_gtk.h"
-#endif
-
-namespace content {
-
-class ShellWebContentsViewDelegate : public WebContentsViewDelegate {
- public:
-  explicit ShellWebContentsViewDelegate(WebContents* web_contents);
-  virtual ~ShellWebContentsViewDelegate();
-
-  // Overridden from WebContentsViewDelegate:
-  virtual void ShowContextMenu(const ContextMenuParams& params) OVERRIDE;
-  virtual WebDragDestDelegate* GetDragDestDelegate() OVERRIDE;
-
-#if defined(TOOLKIT_GTK)
-  virtual void Initialize(GtkWidget* expanded_container,
-                          ui::FocusStoreGtk* focus_store) OVERRIDE;
-  virtual gfx::NativeView GetNativeView() const OVERRIDE;
-  virtual void Focus() OVERRIDE;
-  virtual gboolean OnNativeViewFocusEvent(GtkWidget* widget,
-                                          GtkDirectionType type,
-                                          gboolean* return_value) OVERRIDE;
-#elif defined(OS_MACOSX)
-  virtual NSObject<RenderWidgetHostViewMacDelegate>*
-      CreateRenderWidgetHostViewDelegate(
-          RenderWidgetHost* render_widget_host) OVERRIDE;
-  void ActionPerformed(int id);
-#elif defined(OS_WIN)
-  virtual void StoreFocus() OVERRIDE;
-  virtual void RestoreFocus() OVERRIDE;
-  virtual bool Focus() OVERRIDE;
-  virtual void TakeFocus(bool reverse) OVERRIDE;
-  virtual void SizeChanged(const gfx::Size& size) OVERRIDE;
-  void MenuItemSelected(int selection);
-#endif
-
- private:
-  WebContents* web_contents_;
-  ContextMenuParams params_;
-
-#if defined(TOOLKIT_GTK)
-  ui::OwnedWidgetGtk floating_;
-  GtkWidget* expanded_container_;
-
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnBackMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnForwardMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnReloadMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnOpenURLMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnCutMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnCopyMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnPasteMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnDeleteMenuActivated);
-  CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
-                       OnInspectMenuActivated);
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(ShellWebContentsViewDelegate);
-};
-
-}  // namespace content
-
-#endif // CONTENT_SHELL_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
diff --git a/content/shell/shell_web_contents_view_delegate_android.cc b/content/shell/shell_web_contents_view_delegate_android.cc
deleted file mode 100644
index a5b4c82..0000000
--- a/content/shell/shell_web_contents_view_delegate_android.cc
+++ /dev/null
@@ -1,46 +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/shell/shell_web_contents_view_delegate.h"
-
-#include "base/command_line.h"
-#include "content/public/browser/android/content_view_core.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/context_menu_params.h"
-#include "content/shell/shell_web_contents_view_delegate_creator.h"
-
-namespace content {
-
-WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
-    WebContents* web_contents) {
-  return new ShellWebContentsViewDelegate(web_contents);
-}
-
-
-ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
-    WebContents* web_contents)
-    : web_contents_(web_contents) {
-}
-
-ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
-}
-
-void ShellWebContentsViewDelegate::ShowContextMenu(
-    const ContextMenuParams& params) {
-  if (params.is_editable && params.selection_text.empty()) {
-    content::ContentViewCore* content_view_core =
-        ContentViewCore::FromWebContents(web_contents_);
-    if (content_view_core) {
-      content_view_core->ShowPastePopup(params.selection_start.x(),
-                                        params.selection_start.y());
-    }
-  }
-}
-
-WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
-  return NULL;
-}
-
-}  // namespace content
diff --git a/content/shell/shell_web_contents_view_delegate_creator.h b/content/shell/shell_web_contents_view_delegate_creator.h
deleted file mode 100644
index 707bbd9..0000000
--- a/content/shell/shell_web_contents_view_delegate_creator.h
+++ /dev/null
@@ -1,18 +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_SHELL_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
-#define CONTENT_SHELL_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
-
-namespace content {
-
-class WebContents;
-class WebContentsViewDelegate;
-
-WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
-    WebContents* web_contents);
-
-}  // namespace content
-
-#endif //CONTENT_SHELL_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
diff --git a/content/shell/shell_web_contents_view_delegate_gtk.cc b/content/shell/shell_web_contents_view_delegate_gtk.cc
deleted file mode 100644
index 9f1318b..0000000
--- a/content/shell/shell_web_contents_view_delegate_gtk.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 "content/shell/shell_web_contents_view_delegate.h"
-
-#include "base/command_line.h"
-#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/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/context_menu_params.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_browser_main_parts.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_devtools_frontend.h"
-#include "content/shell/shell_web_contents_view_delegate_creator.h"
-#include "third_party/WebKit/public/web/WebContextMenuData.h"
-#include "ui/base/gtk/focus_store_gtk.h"
-#include "ui/base/gtk/gtk_floating_container.h"
-
-using WebKit::WebContextMenuData;
-
-namespace content {
-
-WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
-    WebContents* web_contents) {
-  return new ShellWebContentsViewDelegate(web_contents);
-}
-
-ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
-    WebContents* web_contents)
-    : web_contents_(web_contents),
-      floating_(gtk_floating_container_new()) {
-}
-
-ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
-  floating_.Destroy();
-}
-
-void ShellWebContentsViewDelegate::ShowContextMenu(
-    const ContextMenuParams& params) {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-
-  GtkWidget* menu = gtk_menu_new();
-
-  params_ = params;
-  bool has_link = !params_.unfiltered_link_url.is_empty();
-  bool has_selection = !params_.selection_text.empty();
-
-  if (params_.media_type == WebContextMenuData::MediaTypeNone &&
-      !has_link &&
-      !has_selection &&
-      !params_.is_editable) {
-    GtkWidget* back_menu = gtk_menu_item_new_with_label("Back");
-    gtk_menu_append(GTK_MENU(menu), back_menu);
-    g_signal_connect(back_menu,
-                     "activate",
-                     G_CALLBACK(OnBackMenuActivatedThunk),
-                     this);
-    gtk_widget_set_sensitive(back_menu,
-                             web_contents_->GetController().CanGoBack());
-
-    GtkWidget* forward_menu = gtk_menu_item_new_with_label("Forward");
-    gtk_menu_append(GTK_MENU(menu), forward_menu);
-    g_signal_connect(forward_menu,
-                     "activate",
-                     G_CALLBACK(OnForwardMenuActivatedThunk),
-                     this);
-    gtk_widget_set_sensitive(forward_menu,
-                             web_contents_->GetController().CanGoForward());
-
-    GtkWidget* reload_menu = gtk_menu_item_new_with_label("Reload");
-    gtk_menu_append(GTK_MENU(menu), reload_menu);
-    g_signal_connect(reload_menu,
-                     "activate",
-                     G_CALLBACK(OnReloadMenuActivatedThunk),
-                     this);
-
-    GtkWidget* navigate_separator = gtk_separator_menu_item_new();
-    gtk_menu_append(GTK_MENU(menu), navigate_separator);
-  }
-
-  if (has_link) {
-    GtkWidget* open_menu = gtk_menu_item_new_with_label("Open in New Window");
-    gtk_menu_append(GTK_MENU(menu), open_menu);
-    g_signal_connect(open_menu,
-                     "activate",
-                     G_CALLBACK(OnOpenURLMenuActivatedThunk),
-                     this);
-
-    GtkWidget* link_separator = gtk_separator_menu_item_new();
-    gtk_menu_append(GTK_MENU(menu), link_separator);
-  }
-
-  if (params_.is_editable) {
-    GtkWidget* cut_menu = gtk_menu_item_new_with_label("Cut");
-    gtk_menu_append(GTK_MENU(menu), cut_menu);
-    g_signal_connect(cut_menu,
-                     "activate",
-                     G_CALLBACK(OnCutMenuActivatedThunk),
-                     this);
-    gtk_widget_set_sensitive(
-        cut_menu,
-        params_.edit_flags & WebContextMenuData::CanCut);
-
-    GtkWidget* copy_menu = gtk_menu_item_new_with_label("Copy");
-    gtk_menu_append(GTK_MENU(menu), copy_menu);
-    g_signal_connect(copy_menu,
-                     "activate",
-                     G_CALLBACK(OnCopyMenuActivatedThunk),
-                     this);
-    gtk_widget_set_sensitive(
-        copy_menu,
-        params_.edit_flags & WebContextMenuData::CanCopy);
-
-    GtkWidget* paste_menu = gtk_menu_item_new_with_label("Paste");
-    gtk_menu_append(GTK_MENU(menu), paste_menu);
-    g_signal_connect(paste_menu,
-                     "activate",
-                     G_CALLBACK(OnPasteMenuActivatedThunk),
-                     this);
-    gtk_widget_set_sensitive(
-        paste_menu,
-        params_.edit_flags & WebContextMenuData::CanPaste);
-
-    GtkWidget* delete_menu = gtk_menu_item_new_with_label("Delete");
-    gtk_menu_append(GTK_MENU(menu), delete_menu);
-    g_signal_connect(delete_menu,
-                     "activate",
-                     G_CALLBACK(OnDeleteMenuActivatedThunk),
-                     this);
-    gtk_widget_set_sensitive(
-        delete_menu,
-        params_.edit_flags & WebContextMenuData::CanDelete);
-
-    GtkWidget* edit_separator = gtk_separator_menu_item_new();
-    gtk_menu_append(GTK_MENU(menu), edit_separator);
-  } else if (has_selection) {
-    GtkWidget* copy_menu = gtk_menu_item_new_with_label("Copy");
-    gtk_menu_append(GTK_MENU(menu), copy_menu);
-    g_signal_connect(copy_menu,
-                     "activate",
-                     G_CALLBACK(OnCopyMenuActivatedThunk),
-                     this);
-
-    GtkWidget* copy_separator = gtk_separator_menu_item_new();
-    gtk_menu_append(GTK_MENU(menu), copy_separator);
-  }
-
-  GtkWidget* inspect_menu = gtk_menu_item_new_with_label("Inspect...");
-  gtk_menu_append(GTK_MENU(menu), inspect_menu);
-  g_signal_connect(inspect_menu,
-                   "activate",
-                   G_CALLBACK(OnInspectMenuActivatedThunk),
-                   this);
-
-  gtk_widget_show_all(menu);
-
-  gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, GDK_CURRENT_TIME);
-}
-
-WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
-  return NULL;
-}
-
-void ShellWebContentsViewDelegate::Initialize(GtkWidget* expanded_container,
-                                              ui::FocusStoreGtk* focus_store) {
-  expanded_container_ = expanded_container;
-
-  gtk_container_add(GTK_CONTAINER(floating_.get()), expanded_container_);
-  gtk_widget_show(floating_.get());
-}
-
-gfx::NativeView ShellWebContentsViewDelegate::GetNativeView() const {
-  return floating_.get();
-}
-
-void ShellWebContentsViewDelegate::Focus() {
-  GtkWidget* widget = web_contents_->GetView()->GetContentNativeView();
-  if (widget)
-    gtk_widget_grab_focus(widget);
-}
-
-gboolean ShellWebContentsViewDelegate::OnNativeViewFocusEvent(
-    GtkWidget* widget,
-    GtkDirectionType type,
-    gboolean* return_value) {
-  return false;
-}
-
-void ShellWebContentsViewDelegate::OnBackMenuActivated(GtkWidget* widget) {
-  web_contents_->GetController().GoToOffset(-1);
-  web_contents_->GetView()->Focus();
-}
-
-void ShellWebContentsViewDelegate::OnForwardMenuActivated(GtkWidget* widget) {
-  web_contents_->GetController().GoToOffset(1);
-  web_contents_->GetView()->Focus();
-}
-
-void ShellWebContentsViewDelegate::OnReloadMenuActivated(GtkWidget* widget) {
-  web_contents_->GetController().Reload(false);
-  web_contents_->GetView()->Focus();
-}
-
-void ShellWebContentsViewDelegate::OnOpenURLMenuActivated(GtkWidget* widget) {
-  ShellBrowserContext* browser_context =
-      ShellContentBrowserClient::Get()->browser_context();
-  Shell::CreateNewWindow(browser_context,
-                         params_.link_url,
-                         NULL,
-                         MSG_ROUTING_NONE,
-                         gfx::Size());
-}
-
-void ShellWebContentsViewDelegate::OnCutMenuActivated(GtkWidget* widget) {
-  web_contents_->GetRenderViewHost()->Cut();
-}
-
-void ShellWebContentsViewDelegate::OnCopyMenuActivated(GtkWidget* widget) {
-  web_contents_->GetRenderViewHost()->Copy();
-}
-
-void ShellWebContentsViewDelegate::OnPasteMenuActivated(GtkWidget* widget) {
-  web_contents_->GetRenderViewHost()->Paste();
-}
-
-void ShellWebContentsViewDelegate::OnDeleteMenuActivated(GtkWidget* widget) {
-  web_contents_->GetRenderViewHost()->Delete();
-}
-
-void ShellWebContentsViewDelegate::OnInspectMenuActivated(GtkWidget* widget) {
-  ShellDevToolsFrontend::Show(web_contents_);
-}
-
-}  // namespace content
diff --git a/content/shell/shell_web_contents_view_delegate_mac.mm b/content/shell/shell_web_contents_view_delegate_mac.mm
deleted file mode 100644
index 606a826..0000000
--- a/content/shell/shell_web_contents_view_delegate_mac.mm
+++ /dev/null
@@ -1,277 +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/shell/shell_web_contents_view_delegate.h"
-
-#import  <Cocoa/Cocoa.h>
-
-#include "base/command_line.h"
-#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/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/context_menu_params.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_browser_main_parts.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_devtools_frontend.h"
-#include "content/shell/shell_web_contents_view_delegate_creator.h"
-#include "third_party/WebKit/public/web/WebContextMenuData.h"
-
-using WebKit::WebContextMenuData;
-
-enum {
-  ShellContextMenuItemCutTag = 0,
-  ShellContextMenuItemCopyTag,
-  ShellContextMenuItemPasteTag,
-  ShellContextMenuItemDeleteTag,
-  ShellContextMenuItemOpenLinkTag,
-  ShellContextMenuItemBackTag,
-  ShellContextMenuItemForwardTag,
-  ShellContextMenuItemReloadTag,
-  ShellContextMenuItemInspectTag
-};
-
-@interface ShellContextMenuDelegate : NSObject<NSMenuDelegate> {
- @private
-  content::ShellWebContentsViewDelegate* delegate_;
-}
-@end
-
-@implementation ShellContextMenuDelegate
-- (id)initWithDelegate:(content::ShellWebContentsViewDelegate*) delegate {
-  if ((self = [super init])) {
-    delegate_ = delegate;
-  }
-  return self;
-}
-
-- (void)itemSelected:(id)sender {
-  NSInteger tag = [sender tag];
-  delegate_->ActionPerformed(tag);
-}
-@end
-
-namespace {
-
-NSMenuItem* MakeContextMenuItem(NSString* title,
-                                NSInteger tag,
-                                NSMenu* menu,
-                                BOOL enabled,
-                                ShellContextMenuDelegate* delegate) {
-  NSMenuItem* menu_item =
-      [[NSMenuItem alloc] initWithTitle:title
-                                 action:@selector(itemSelected:)
-                          keyEquivalent:@""];
-  [menu_item setTarget:delegate];
-  [menu_item setTag:tag];
-  [menu_item setEnabled:enabled];
-  [menu addItem:menu_item];
-
-  return menu_item;
-}
-
-}  // namespace
-
-namespace content {
-
-WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
-  WebContents* web_contents) {
-  return new ShellWebContentsViewDelegate(web_contents);
-}
-
-ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
-    WebContents* web_contents)
-    : web_contents_(web_contents) {
-}
-
-ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
-}
-
-void ShellWebContentsViewDelegate::ShowContextMenu(
-    const ContextMenuParams& params) {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-
-  params_ = params;
-  bool has_link = !params_.unfiltered_link_url.is_empty();
-  bool has_selection = ! params_.selection_text.empty();
-
-  NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
-  ShellContextMenuDelegate* delegate =
-      [[ShellContextMenuDelegate alloc] initWithDelegate:this];
-  [menu setDelegate:delegate];
-  [menu setAutoenablesItems:NO];
-
-  if (params.media_type == WebContextMenuData::MediaTypeNone &&
-      !has_link &&
-      !has_selection &&
-      !params_.is_editable) {
-    BOOL back_menu_enabled =
-        web_contents_->GetController().CanGoBack() ? YES : NO;
-    MakeContextMenuItem(@"Back",
-                        ShellContextMenuItemBackTag,
-                        menu,
-                        back_menu_enabled,
-                        delegate);
-
-    BOOL forward_menu_enabled =
-        web_contents_->GetController().CanGoForward() ? YES : NO;
-    MakeContextMenuItem(@"Forward",
-                        ShellContextMenuItemForwardTag,
-                        menu,
-                        forward_menu_enabled,
-                        delegate);
-
-    MakeContextMenuItem(@"Reload",
-                        ShellContextMenuItemReloadTag,
-                        menu,
-                        YES,
-                        delegate);
-
-    NSMenuItem* separator = [NSMenuItem separatorItem];
-    [menu addItem:separator];
-  }
-
-  if (has_link) {
-    MakeContextMenuItem(@"Open In New Window",
-                        ShellContextMenuItemOpenLinkTag,
-                        menu,
-                        YES,
-                        delegate);
-
-    NSMenuItem* separator = [NSMenuItem separatorItem];
-    [menu addItem:separator];
-  }
-
-  if (params_.is_editable) {
-    BOOL cut_menu_enabled =
-        (params_.edit_flags & WebContextMenuData::CanCut) ? YES : NO;
-    MakeContextMenuItem(@"Cut",
-                        ShellContextMenuItemCutTag,
-                        menu,
-                        cut_menu_enabled,
-                        delegate);
-
-    BOOL copy_menu_enabled =
-        (params_.edit_flags & WebContextMenuData::CanCopy) ? YES : NO;
-    MakeContextMenuItem(@"Copy",
-                        ShellContextMenuItemCopyTag,
-                        menu,
-                        copy_menu_enabled,
-                        delegate);
-
-    BOOL paste_menu_enabled =
-        (params_.edit_flags & WebContextMenuData::CanPaste) ? YES : NO;
-    MakeContextMenuItem(@"Paste",
-                        ShellContextMenuItemPasteTag,
-                        menu,
-                        paste_menu_enabled,
-                        delegate);
-
-    BOOL delete_menu_enabled =
-        (params_.edit_flags & WebContextMenuData::CanDelete) ? YES : NO;
-    MakeContextMenuItem(@"Delete",
-                        ShellContextMenuItemDeleteTag,
-                        menu,
-                        delete_menu_enabled,
-                        delegate);
-
-    NSMenuItem* separator = [NSMenuItem separatorItem];
-    [menu addItem:separator];
-  } else if (has_selection) {
-    MakeContextMenuItem(@"Copy",
-                        ShellContextMenuItemCopyTag,
-                        menu,
-                        YES,
-                        delegate);
-
-    NSMenuItem* separator = [NSMenuItem separatorItem];
-    [menu addItem:separator];
-  }
-
-  MakeContextMenuItem(@"Inspect",
-                      ShellContextMenuItemInspectTag,
-                      menu,
-                      YES,
-                      delegate);
-
-  NSView* parent_view = web_contents_->GetView()->GetContentNativeView();
-  NSEvent* currentEvent = [NSApp currentEvent];
-  NSWindow* window = [parent_view window];
-  NSPoint position = [window mouseLocationOutsideOfEventStream];
-  NSTimeInterval eventTime = [currentEvent timestamp];
-  NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
-                                           location:position
-                                      modifierFlags:NSRightMouseDownMask
-                                          timestamp:eventTime
-                                       windowNumber:[window windowNumber]
-                                            context:nil
-                                        eventNumber:0
-                                         clickCount:1
-                                           pressure:1.0];
-
-  [NSMenu popUpContextMenu:menu
-                 withEvent:clickEvent
-                   forView:parent_view];
-}
-
-void ShellWebContentsViewDelegate::ActionPerformed(int tag) {
-  switch (tag) {
-    case ShellContextMenuItemCutTag:
-      web_contents_->GetRenderViewHost()->Cut();
-      break;
-    case ShellContextMenuItemCopyTag:
-      web_contents_->GetRenderViewHost()->Copy();
-      break;
-    case ShellContextMenuItemPasteTag:
-      web_contents_->GetRenderViewHost()->Paste();
-      break;
-    case ShellContextMenuItemDeleteTag:
-      web_contents_->GetRenderViewHost()->Delete();
-      break;
-    case ShellContextMenuItemOpenLinkTag: {
-      ShellBrowserContext* browser_context =
-          ShellContentBrowserClient::Get()->browser_context();
-      Shell::CreateNewWindow(browser_context,
-                             params_.link_url,
-                             NULL,
-                             MSG_ROUTING_NONE,
-                             gfx::Size());
-      break;
-    }
-    case ShellContextMenuItemBackTag:
-      web_contents_->GetController().GoToOffset(-1);
-      web_contents_->GetView()->Focus();
-      break;
-    case ShellContextMenuItemForwardTag:
-      web_contents_->GetController().GoToOffset(1);
-      web_contents_->GetView()->Focus();
-      break;
-    case ShellContextMenuItemReloadTag: {
-      web_contents_->GetController().Reload(false);
-      web_contents_->GetView()->Focus();
-      break;
-    }
-    case ShellContextMenuItemInspectTag: {
-      ShellDevToolsFrontend::Show(web_contents_);
-      break;
-    }
-  }
-}
-
-WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
-  return NULL;
-}
-
-NSObject<RenderWidgetHostViewMacDelegate>*
-ShellWebContentsViewDelegate::CreateRenderWidgetHostViewDelegate(
-    content::RenderWidgetHost* render_widget_host) {
-  return NULL;
-}
-
-}  // namespace content
diff --git a/content/shell/shell_web_contents_view_delegate_win.cc b/content/shell/shell_web_contents_view_delegate_win.cc
deleted file mode 100644
index a062dea..0000000
--- a/content/shell/shell_web_contents_view_delegate_win.cc
+++ /dev/null
@@ -1,254 +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/shell/shell_web_contents_view_delegate.h"
-
-#include "base/command_line.h"
-#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/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/public/common/context_menu_params.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_browser_main_parts.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "content/shell/shell_devtools_frontend.h"
-#include "content/shell/shell_web_contents_view_delegate_creator.h"
-#include "third_party/WebKit/public/web/WebContextMenuData.h"
-
-using WebKit::WebContextMenuData;
-
-namespace {
-
-enum {
-  ShellContextMenuItemCutId = 10001,
-  ShellContextMenuItemCopyId,
-  ShellContextMenuItemPasteId,
-  ShellContextMenuItemDeleteId,
-  ShellContextMenuItemOpenLinkId,
-  ShellContextMenuItemBackId,
-  ShellContextMenuItemForwardId,
-  ShellContextMenuItemReloadId,
-  ShellContextMenuItemInspectId
-};
-
-void MakeContextMenuItem(HMENU menu,
-                         int menu_index,
-                         LPTSTR text,
-                         UINT id,
-                         bool enabled) {
-  MENUITEMINFO mii = {0};
-  mii.cbSize = sizeof(mii);
-  mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA | MIIM_STRING | MIIM_STATE;
-  mii.fState = enabled ? MFS_ENABLED : (MF_DISABLED | MFS_GRAYED);
-  mii.fType = MFT_STRING;
-  mii.wID = id;
-  mii.dwTypeData = text;
-
-  InsertMenuItem(menu, menu_index, TRUE, &mii);
-}
-
-}  // namespace
-
-namespace content {
-
-WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
-    WebContents* web_contents) {
-  return new ShellWebContentsViewDelegate(web_contents);
-}
-
-ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
-    WebContents* web_contents)
-    : web_contents_(web_contents) {
-}
-
-ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
-}
-
-void ShellWebContentsViewDelegate::ShowContextMenu(
-    const ContextMenuParams& params) {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
-    return;
-
-  params_ = params;
-  bool has_link = !params_.unfiltered_link_url.is_empty();
-  bool has_selection = !params_.selection_text.empty();
-
-  HMENU menu = CreateMenu();
-  HMENU sub_menu = CreatePopupMenu();
-  AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)sub_menu, L"");
-
-  int index = 0;
-  if (params_.media_type == WebContextMenuData::MediaTypeNone &&
-      !has_link &&
-      !has_selection &&
-      !params_.is_editable) {
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Back",
-                        ShellContextMenuItemBackId,
-                        web_contents_->GetController().CanGoBack());
-
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Forward",
-                        ShellContextMenuItemForwardId,
-                        web_contents_->GetController().CanGoForward());
-
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Reload",
-                        ShellContextMenuItemReloadId,
-                        true);
-
-    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
-    index++;
-  }
-
-  if (has_link) {
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Open in New Window",
-                        ShellContextMenuItemOpenLinkId,
-                        true);
-    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
-    index++;
-  }
-
-  if (params_.is_editable) {
-    bool cut_enabled = ((params_.edit_flags & WebContextMenuData::CanCut) != 0);
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Cut",
-                        ShellContextMenuItemCutId,
-                        cut_enabled);
-
-    bool copy_enabled =
-        ((params_.edit_flags & WebContextMenuData::CanCopy) != 0);
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Copy",
-                        ShellContextMenuItemCopyId,
-                        copy_enabled);
-
-    bool paste_enabled =
-        ((params_.edit_flags & WebContextMenuData::CanPaste) != 0);
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Paste",
-                        ShellContextMenuItemPasteId,
-                        paste_enabled);
-    bool delete_enabled =
-        ((params_.edit_flags & WebContextMenuData::CanDelete) != 0);
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Delete",
-                        ShellContextMenuItemDeleteId,
-                        delete_enabled);
-
-    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
-    index++;
-  } else if (has_selection) {
-    MakeContextMenuItem(sub_menu,
-                        index++,
-                        L"Copy",
-                        ShellContextMenuItemCopyId,
-                        true);
-
-    AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
-    index++;
-  }
-
-  MakeContextMenuItem(sub_menu,
-                      index++,
-                      L"Inspect...",
-                      ShellContextMenuItemInspectId,
-                      true);
-#if defined(USE_AURA)
-  NOTIMPLEMENTED();
-#else
-  gfx::Point screen_point(params.x, params.y);
-  POINT point = screen_point.ToPOINT();
-  ClientToScreen(web_contents_->GetView()->GetNativeView(), &point);
-
-  int selection =
-      TrackPopupMenu(sub_menu,
-                     TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
-                     point.x, point.y,
-                     0,
-                     web_contents_->GetView()->GetContentNativeView(),
-                     NULL);
-
-  MenuItemSelected(selection);
-#endif
-  DestroyMenu(menu);
-}
-
-void ShellWebContentsViewDelegate::MenuItemSelected(int selection) {
-  switch (selection) {
-    case ShellContextMenuItemCutId:
-      web_contents_->GetRenderViewHost()->Cut();
-      break;
-    case ShellContextMenuItemCopyId:
-      web_contents_->GetRenderViewHost()->Copy();
-      break;
-    case ShellContextMenuItemPasteId:
-      web_contents_->GetRenderViewHost()->Paste();
-      break;
-    case ShellContextMenuItemDeleteId:
-      web_contents_->GetRenderViewHost()->Delete();
-      break;
-    case ShellContextMenuItemOpenLinkId: {
-      ShellBrowserContext* browser_context =
-          ShellContentBrowserClient::Get()->browser_context();
-      Shell::CreateNewWindow(browser_context,
-                             params_.link_url,
-                             NULL,
-                             MSG_ROUTING_NONE,
-                             gfx::Size());
-      break;
-    }
-    case ShellContextMenuItemBackId:
-      web_contents_->GetController().GoToOffset(-1);
-      web_contents_->GetView()->Focus();
-      break;
-    case ShellContextMenuItemForwardId:
-      web_contents_->GetController().GoToOffset(1);
-      web_contents_->GetView()->Focus();
-      break;
-    case ShellContextMenuItemReloadId:
-      web_contents_->GetController().Reload(false);
-      web_contents_->GetView()->Focus();
-      break;
-    case ShellContextMenuItemInspectId: {
-      ShellDevToolsFrontend::Show(web_contents_);
-      break;
-    }
-  }
-}
-
-WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
-  return NULL;
-}
-
-void ShellWebContentsViewDelegate::StoreFocus() {
-}
-
-void ShellWebContentsViewDelegate::RestoreFocus() {
-}
-
-bool ShellWebContentsViewDelegate::Focus() {
-  return false;
-}
-
-void ShellWebContentsViewDelegate::TakeFocus(bool reverse) {
-}
-
-void ShellWebContentsViewDelegate::SizeChanged(const gfx::Size& size) {
-}
-
-}  // namespace content
diff --git a/content/shell/shell_win.cc b/content/shell/shell_win.cc
deleted file mode 100644
index d6d9497..0000000
--- a/content/shell/shell_win.cc
+++ /dev/null
@@ -1,285 +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/shell/shell.h"
-
-#include <commctrl.h>
-#include <fcntl.h>
-#include <io.h>
-#include <windows.h>
-
-#include "base/strings/utf_string_conversions.h"
-#include "base/win/wrapped_window_proc.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_view.h"
-#include "content/shell/app/resource.h"
-#include "ui/base/win/hwnd_util.h"
-
-namespace {
-
-const wchar_t kWindowTitle[] = L"Content Shell";
-const wchar_t kWindowClass[] = L"CONTENT_SHELL";
-
-const int kButtonWidth = 72;
-const int kURLBarHeight = 24;
-
-const int kMaxURLLength = 1024;
-
-}  // namespace
-
-namespace content {
-
-HINSTANCE Shell::instance_handle_;
-
-void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
-  _setmode(_fileno(stdout), _O_BINARY);
-  _setmode(_fileno(stderr), _O_BINARY);
-  INITCOMMONCONTROLSEX InitCtrlEx;
-  InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
-  InitCtrlEx.dwICC  = ICC_STANDARD_CLASSES;
-  InitCommonControlsEx(&InitCtrlEx);
-  RegisterWindowClass();
-}
-
-void Shell::PlatformExit() {
-  std::vector<Shell*> windows = windows_;
-  for (std::vector<Shell*>::iterator it = windows.begin();
-       it != windows.end(); ++it)
-    DestroyWindow((*it)->window_);
-}
-
-void Shell::PlatformCleanUp() {
-  // When the window is destroyed, tell the Edit field to forget about us,
-  // otherwise we will crash.
-  ui::SetWindowProc(url_edit_view_, default_edit_wnd_proc_);
-  ui::SetWindowUserData(url_edit_view_, NULL);
-}
-
-void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
-  int id;
-  switch (control) {
-    case BACK_BUTTON:
-      id = IDC_NAV_BACK;
-      break;
-    case FORWARD_BUTTON:
-      id = IDC_NAV_FORWARD;
-      break;
-    case STOP_BUTTON:
-      id = IDC_NAV_STOP;
-      break;
-    default:
-      NOTREACHED() << "Unknown UI control";
-      return;
-  }
-  EnableWindow(GetDlgItem(window_, id), is_enabled);
-}
-
-void Shell::PlatformSetAddressBarURL(const GURL& url) {
-  std::wstring url_string = UTF8ToWide(url.spec());
-  SendMessage(url_edit_view_, WM_SETTEXT, 0,
-              reinterpret_cast<LPARAM>(url_string.c_str()));
-}
-
-void Shell::PlatformSetIsLoading(bool loading) {
-}
-
-void Shell::PlatformCreateWindow(int width, int height) {
-  window_ = CreateWindow(kWindowClass, kWindowTitle,
-                         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
-                         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
-                         NULL, NULL, instance_handle_, NULL);
-  ui::SetWindowUserData(window_, this);
-
-  HWND hwnd;
-  int x = 0;
-
-  hwnd = CreateWindow(L"BUTTON", L"Back",
-                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
-                      x, 0, kButtonWidth, kURLBarHeight,
-                      window_, (HMENU) IDC_NAV_BACK, instance_handle_, 0);
-  x += kButtonWidth;
-
-  hwnd = CreateWindow(L"BUTTON", L"Forward",
-                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
-                      x, 0, kButtonWidth, kURLBarHeight,
-                      window_, (HMENU) IDC_NAV_FORWARD, instance_handle_, 0);
-  x += kButtonWidth;
-
-  hwnd = CreateWindow(L"BUTTON", L"Reload",
-                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
-                      x, 0, kButtonWidth, kURLBarHeight,
-                      window_, (HMENU) IDC_NAV_RELOAD, instance_handle_, 0);
-  x += kButtonWidth;
-
-  hwnd = CreateWindow(L"BUTTON", L"Stop",
-                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
-                      x, 0, kButtonWidth, kURLBarHeight,
-                      window_, (HMENU) IDC_NAV_STOP, instance_handle_, 0);
-  x += kButtonWidth;
-
-  // This control is positioned by PlatformResizeSubViews.
-  url_edit_view_ = CreateWindow(L"EDIT", 0,
-                                WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT |
-                                ES_AUTOVSCROLL | ES_AUTOHSCROLL,
-                                x, 0, 0, 0, window_, 0, instance_handle_, 0);
-
-  default_edit_wnd_proc_ = ui::SetWindowProc(url_edit_view_,
-                                             Shell::EditWndProc);
-  ui::SetWindowUserData(url_edit_view_, this);
-
-  ShowWindow(window_, SW_SHOW);
-
-  SizeTo(width, height);
-}
-
-void Shell::PlatformSetContents() {
-  SetParent(web_contents_->GetView()->GetNativeView(), window_);
-}
-
-void Shell::SizeTo(int width, int height) {
-  RECT rc, rw;
-  GetClientRect(window_, &rc);
-  GetWindowRect(window_, &rw);
-
-  int client_width = rc.right - rc.left;
-  int window_width = rw.right - rw.left;
-  window_width = (window_width - client_width) + width;
-
-  int client_height = rc.bottom - rc.top;
-  int window_height = rw.bottom - rw.top;
-  window_height = (window_height - client_height) + height;
-
-  // Add space for the url bar.
-  window_height += kURLBarHeight;
-
-  SetWindowPos(window_, NULL, 0, 0, window_width, window_height,
-               SWP_NOMOVE | SWP_NOZORDER);
-}
-
-void Shell::PlatformResizeSubViews() {
-  RECT rc;
-  GetClientRect(window_, &rc);
-
-  int x = kButtonWidth * 4;
-  MoveWindow(url_edit_view_, x, 0, rc.right - x, kURLBarHeight, TRUE);
-
-  MoveWindow(GetContentView(), 0, kURLBarHeight, rc.right,
-             rc.bottom - kURLBarHeight, TRUE);
-}
-
-void Shell::Close() {
-  DestroyWindow(window_);
-}
-
-ATOM Shell::RegisterWindowClass() {
-  WNDCLASSEX window_class;
-  base::win::InitializeWindowClass(
-      kWindowClass,
-      &Shell::WndProc,
-      CS_HREDRAW | CS_VREDRAW,
-      0,
-      0,
-      LoadCursor(NULL, IDC_ARROW),
-      NULL,
-      MAKEINTRESOURCE(IDC_CONTENTSHELL),
-      NULL,
-      NULL,
-      &window_class);
-  instance_handle_ = window_class.hInstance;
-  return RegisterClassEx(&window_class);
-}
-
-LRESULT CALLBACK Shell::WndProc(HWND hwnd, UINT message, WPARAM wParam,
-                                LPARAM lParam) {
-  Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
-
-  switch (message) {
-    case WM_COMMAND: {
-      int id = LOWORD(wParam);
-      switch (id) {
-        case IDM_NEW_WINDOW:
-          CreateNewWindow(
-              shell->web_contents()->GetBrowserContext(),
-              GURL(), NULL, MSG_ROUTING_NONE, gfx::Size());
-          break;
-        case IDM_CLOSE_WINDOW:
-          DestroyWindow(hwnd);
-          break;
-        case IDM_EXIT:
-          PlatformExit();
-          break;
-        case IDM_SHOW_DEVELOPER_TOOLS:
-          shell->ShowDevTools();
-          break;
-        case IDC_NAV_BACK:
-          shell->GoBackOrForward(-1);
-          break;
-        case IDC_NAV_FORWARD:
-          shell->GoBackOrForward(1);
-          break;
-        case IDC_NAV_RELOAD:
-          shell->Reload();
-          break;
-        case IDC_NAV_STOP:
-          shell->Stop();
-          break;
-      }
-      break;
-    }
-    case WM_DESTROY: {
-      delete shell;
-      return 0;
-    }
-
-    case WM_SIZE: {
-      if (shell->GetContentView())
-        shell->PlatformResizeSubViews();
-      return 0;
-    }
-
-    case WM_WINDOWPOSCHANGED: {
-      // Notify the content view that the window position of its parent window
-      // has been changed by sending window message
-      gfx::NativeView native_view = shell->GetContentView();
-      if (native_view) {
-        SendMessage(native_view, message, wParam, lParam);
-      }
-      break;
-   }
-  }
-
-  return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-LRESULT CALLBACK Shell::EditWndProc(HWND hwnd, UINT message,
-                                    WPARAM wParam, LPARAM lParam) {
-  Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
-
-  switch (message) {
-    case WM_CHAR:
-      if (wParam == VK_RETURN) {
-        wchar_t str[kMaxURLLength + 1];  // Leave room for adding a NULL;
-        *(str) = kMaxURLLength;
-        LRESULT str_len = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)str);
-        if (str_len > 0) {
-          str[str_len] = 0;  // EM_GETLINE doesn't NULL terminate.
-          GURL url(str);
-          if (!url.has_scheme())
-            url = GURL(std::wstring(L"http://") + std::wstring(str));
-          shell->LoadURL(url);
-        }
-
-        return 0;
-      }
-  }
-
-  return CallWindowProc(shell->default_edit_wnd_proc_, hwnd, message, wParam,
-                        lParam);
-}
-
-void Shell::PlatformSetTitle(const string16& text) {
-  ::SetWindowText(window_, text.c_str());
-}
-
-}  // namespace content
diff --git a/content/shell/webkit_test_controller.cc b/content/shell/webkit_test_controller.cc
deleted file mode 100644
index 147367e..0000000
--- a/content/shell/webkit_test_controller.cc
+++ /dev/null
@@ -1,632 +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/shell/webkit_test_controller.h"
-
-#include <iostream>
-
-#include "base/base64.h"
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "content/public/browser/devtools_manager.h"
-#include "content/public/browser/gpu_data_manager.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.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/render_view_host.h"
-#include "content/public/browser/render_widget_host_view.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/common/shell_messages.h"
-#include "content/shell/common/shell_switches.h"
-#include "content/shell/common/webkit_test_helpers.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_content_browser_client.h"
-#include "ui/gfx/codec/png_codec.h"
-
-namespace content {
-
-const int kTestSVGWindowWidthDip = 480;
-const int kTestSVGWindowHeightDip = 360;
-
-// WebKitTestResultPrinter ----------------------------------------------------
-
-WebKitTestResultPrinter::WebKitTestResultPrinter(
-    std::ostream* output, std::ostream* error)
-    : state_(DURING_TEST),
-      capture_text_only_(false),
-      encode_binary_data_(false),
-      output_(output),
-      error_(error) {
-}
-
-WebKitTestResultPrinter::~WebKitTestResultPrinter() {
-}
-
-void WebKitTestResultPrinter::PrintTextHeader() {
-  if (state_ != DURING_TEST)
-    return;
-  if (!capture_text_only_)
-    *output_ << "Content-Type: text/plain\n";
-  state_ = IN_TEXT_BLOCK;
-}
-
-void WebKitTestResultPrinter::PrintTextBlock(const std::string& block) {
-  if (state_ != IN_TEXT_BLOCK)
-    return;
-  *output_ << block;
-}
-
-void WebKitTestResultPrinter::PrintTextFooter() {
-  if (state_ != IN_TEXT_BLOCK)
-    return;
-  if (!capture_text_only_) {
-    *output_ << "#EOF\n";
-    output_->flush();
-  }
-  state_ = IN_IMAGE_BLOCK;
-}
-
-void WebKitTestResultPrinter::PrintImageHeader(
-    const std::string& actual_hash,
-    const std::string& expected_hash) {
-  if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
-    return;
-  *output_ << "\nActualHash: " << actual_hash << "\n";
-  if (!expected_hash.empty())
-    *output_ << "\nExpectedHash: " << expected_hash << "\n";
-}
-
-void WebKitTestResultPrinter::PrintImageBlock(
-    const std::vector<unsigned char>& png_image) {
-  if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
-    return;
-  *output_ << "Content-Type: image/png\n";
-  if (encode_binary_data_) {
-    PrintEncodedBinaryData(png_image);
-    return;
-  }
-
-  *output_ << "Content-Length: " << png_image.size() << "\n";
-  output_->write(
-      reinterpret_cast<const char*>(&png_image[0]), png_image.size());
-}
-
-void WebKitTestResultPrinter::PrintImageFooter() {
-  if (state_ != IN_IMAGE_BLOCK)
-    return;
-  if (!capture_text_only_) {
-    *output_ << "#EOF\n";
-    *error_ << "#EOF\n";
-    output_->flush();
-    error_->flush();
-  }
-  state_ = AFTER_TEST;
-}
-
-void WebKitTestResultPrinter::PrintAudioHeader() {
-  DCHECK_EQ(state_, DURING_TEST);
-  if (!capture_text_only_)
-    *output_ << "Content-Type: audio/wav\n";
-  state_ = IN_AUDIO_BLOCK;
-}
-
-void WebKitTestResultPrinter::PrintAudioBlock(
-    const std::vector<unsigned char>& audio_data) {
-  if (state_ != IN_AUDIO_BLOCK || capture_text_only_)
-    return;
-  if (encode_binary_data_) {
-    PrintEncodedBinaryData(audio_data);
-    return;
-  }
-
-  *output_ << "Content-Length: " << audio_data.size() << "\n";
-  output_->write(
-      reinterpret_cast<const char*>(&audio_data[0]), audio_data.size());
-}
-
-void WebKitTestResultPrinter::PrintAudioFooter() {
-  if (state_ != IN_AUDIO_BLOCK)
-    return;
-  if (!capture_text_only_) {
-    *output_ << "#EOF\n";
-    *error_ << "#EOF\n";
-    output_->flush();
-    error_->flush();
-  }
-  state_ = IN_IMAGE_BLOCK;
-}
-
-void WebKitTestResultPrinter::AddMessage(const std::string& message) {
-  AddMessageRaw(message + "\n");
-}
-
-void WebKitTestResultPrinter::AddMessageRaw(const std::string& message) {
-  if (state_ != DURING_TEST)
-    return;
-  *output_ << message;
-}
-
-void WebKitTestResultPrinter::AddErrorMessage(const std::string& message) {
-  if (!capture_text_only_)
-    *error_ << message << "\n";
-  if (state_ != DURING_TEST)
-    return;
-  PrintTextHeader();
-  *output_ << message << "\n";
-  PrintTextFooter();
-  PrintImageFooter();
-}
-
-void WebKitTestResultPrinter::PrintEncodedBinaryData(
-    const std::vector<unsigned char>& data) {
-  *output_ << "Content-Transfer-Encoding: base64\n";
-
-  std::string data_base64;
-  const bool success = base::Base64Encode(
-      base::StringPiece(reinterpret_cast<const char*>(&data[0]), data.size()),
-      &data_base64);
-  DCHECK(success);
-
-  *output_ << "Content-Length: " << data_base64.length() << "\n";
-  output_->write(data_base64.c_str(), data_base64.length());
-}
-
-
-// WebKitTestController -------------------------------------------------------
-
-WebKitTestController* WebKitTestController::instance_ = NULL;
-
-// static
-WebKitTestController* WebKitTestController::Get() {
-  DCHECK(instance_);
-  return instance_;
-}
-
-WebKitTestController::WebKitTestController()
-    : main_window_(NULL),
-      test_phase_(BETWEEN_TESTS) {
-  CHECK(!instance_);
-  instance_ = this;
-  printer_.reset(new WebKitTestResultPrinter(&std::cout, &std::cerr));
-  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEncodeBinary))
-    printer_->set_encode_binary_data(true);
-  registrar_.Add(this,
-                 NOTIFICATION_RENDERER_PROCESS_CREATED,
-                 NotificationService::AllSources());
-  GpuDataManager::GetInstance()->AddObserver(this);
-  ResetAfterLayoutTest();
-}
-
-WebKitTestController::~WebKitTestController() {
-  DCHECK(CalledOnValidThread());
-  CHECK(instance_ == this);
-  CHECK(test_phase_ == BETWEEN_TESTS);
-  GpuDataManager::GetInstance()->RemoveObserver(this);
-  DiscardMainWindow();
-  instance_ = NULL;
-}
-
-bool WebKitTestController::PrepareForLayoutTest(
-    const GURL& test_url,
-    const base::FilePath& current_working_directory,
-    bool enable_pixel_dumping,
-    const std::string& expected_pixel_hash) {
-  DCHECK(CalledOnValidThread());
-  test_phase_ = DURING_TEST;
-  current_working_directory_ = current_working_directory;
-  enable_pixel_dumping_ = enable_pixel_dumping;
-  expected_pixel_hash_ = expected_pixel_hash;
-  test_url_ = test_url;
-  printer_->reset();
-  ShellBrowserContext* browser_context =
-      ShellContentBrowserClient::Get()->browser_context();
-  if (test_url.spec().find("compositing/") != std::string::npos)
-    is_compositing_test_ = true;
-  initial_size_ = gfx::Size(
-      Shell::kDefaultTestWindowWidthDip, Shell::kDefaultTestWindowHeightDip);
-  // The W3C SVG layout tests use a different size than the other layout tests.
-  if (test_url.spec().find("W3C-SVG-1.1") != std::string::npos)
-    initial_size_ = gfx::Size(kTestSVGWindowWidthDip, kTestSVGWindowHeightDip);
-  if (!main_window_) {
-    main_window_ = content::Shell::CreateNewWindow(
-        browser_context,
-        GURL(),
-        NULL,
-        MSG_ROUTING_NONE,
-        initial_size_);
-    WebContentsObserver::Observe(main_window_->web_contents());
-    send_configuration_to_next_host_ = true;
-    current_pid_ = base::kNullProcessId;
-    main_window_->LoadURL(test_url);
-  } else {
-#if (defined(OS_WIN) && !defined(USE_AURA)) || \
-    defined(TOOLKIT_GTK) || defined(OS_MACOSX)
-    // Shell::SizeTo is not implemented on all platforms.
-    main_window_->SizeTo(initial_size_.width(), initial_size_.height());
-#endif
-    main_window_->web_contents()->GetRenderViewHost()->GetView()
-        ->SetSize(initial_size_);
-    main_window_->web_contents()->GetRenderViewHost()->WasResized();
-    RenderViewHost* render_view_host =
-        main_window_->web_contents()->GetRenderViewHost();
-    WebPreferences prefs = render_view_host->GetWebkitPreferences();
-    OverrideWebkitPrefs(&prefs);
-    render_view_host->UpdateWebkitPreferences(prefs);
-    SendTestConfiguration();
-
-    NavigationController::LoadURLParams params(test_url);
-    params.transition_type = PageTransitionFromInt(
-        PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR);
-    params.should_clear_history_list = true;
-    main_window_->web_contents()->GetController().LoadURLWithParams(params);
-    main_window_->web_contents()->GetView()->Focus();
-  }
-  main_window_->web_contents()->GetRenderViewHost()->SetActive(true);
-  main_window_->web_contents()->GetRenderViewHost()->Focus();
-  return true;
-}
-
-bool WebKitTestController::ResetAfterLayoutTest() {
-  DCHECK(CalledOnValidThread());
-  printer_->PrintTextFooter();
-  printer_->PrintImageFooter();
-  send_configuration_to_next_host_ = false;
-  test_phase_ = BETWEEN_TESTS;
-  is_compositing_test_ = false;
-  enable_pixel_dumping_ = false;
-  expected_pixel_hash_.clear();
-  test_url_ = GURL();
-  prefs_ = WebPreferences();
-  should_override_prefs_ = false;
-  return true;
-}
-
-void WebKitTestController::SetTempPath(const base::FilePath& temp_path) {
-  temp_path_ = temp_path;
-}
-
-void WebKitTestController::RendererUnresponsive() {
-  DCHECK(CalledOnValidThread());
-  LOG(WARNING) << "renderer unresponsive";
-}
-
-void WebKitTestController::WorkerCrashed() {
-  DCHECK(CalledOnValidThread());
-  printer_->AddErrorMessage("#CRASHED - worker");
-  DiscardMainWindow();
-}
-
-void WebKitTestController::OverrideWebkitPrefs(WebPreferences* prefs) {
-  if (should_override_prefs_) {
-    *prefs = prefs_;
-  } else {
-    ApplyLayoutTestDefaultPreferences(prefs);
-    if (is_compositing_test_) {
-      CommandLine& command_line = *CommandLine::ForCurrentProcess();
-      if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing))
-        prefs->accelerated_2d_canvas_enabled = true;
-      prefs->accelerated_compositing_for_video_enabled = true;
-      prefs->mock_scrollbars_enabled = true;
-    }
-  }
-}
-
-void WebKitTestController::OpenURL(const GURL& url) {
-  if (test_phase_ != DURING_TEST)
-    return;
-
-  Shell::CreateNewWindow(main_window_->web_contents()->GetBrowserContext(),
-                         url,
-                         main_window_->web_contents()->GetSiteInstance(),
-                         MSG_ROUTING_NONE,
-                         gfx::Size());
-}
-
-void WebKitTestController::TestFinishedInSecondaryWindow() {
-  RenderViewHost* render_view_host =
-      main_window_->web_contents()->GetRenderViewHost();
-  render_view_host->Send(
-      new ShellViewMsg_NotifyDone(render_view_host->GetRoutingID()));
-}
-
-bool WebKitTestController::IsMainWindow(WebContents* web_contents) const {
-  return main_window_ && web_contents == main_window_->web_contents();
-}
-
-bool WebKitTestController::OnMessageReceived(const IPC::Message& message) {
-  DCHECK(CalledOnValidThread());
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage, OnPrintMessage)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump, OnAudioDump)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences,
-                        OnOverridePreferences)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished, OnTestFinished)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools, OnShowDevTools)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools, OnCloseDevTools)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset, OnGoToOffset)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload, OnReload)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame, OnLoadURLForFrame)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory,
-                        OnCaptureSessionHistory)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows,
-                        OnCloseRemainingWindows)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-void WebKitTestController::PluginCrashed(const base::FilePath& plugin_path,
-                                         base::ProcessId plugin_pid) {
-  DCHECK(CalledOnValidThread());
-  printer_->AddErrorMessage(
-      base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid));
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow),
-                 base::Unretained(this)));
-}
-
-void WebKitTestController::RenderViewCreated(RenderViewHost* render_view_host) {
-  DCHECK(CalledOnValidThread());
-  // Might be kNullProcessHandle, in which case we will receive a notification
-  // later when the RenderProcessHost was created.
-  if (render_view_host->GetProcess()->GetHandle() != base::kNullProcessHandle)
-    current_pid_ = base::GetProcId(render_view_host->GetProcess()->GetHandle());
-  if (!send_configuration_to_next_host_)
-    return;
-  send_configuration_to_next_host_ = false;
-  SendTestConfiguration();
-}
-
-void WebKitTestController::RenderProcessGone(base::TerminationStatus status) {
-  DCHECK(CalledOnValidThread());
-  if (current_pid_ != base::kNullProcessId) {
-    printer_->AddErrorMessage(std::string("#CRASHED - renderer (pid ") +
-                              base::IntToString(current_pid_) + ")");
-  } else {
-    printer_->AddErrorMessage("#CRASHED - renderer");
-  }
-  DiscardMainWindow();
-}
-
-void WebKitTestController::WebContentsDestroyed(WebContents* web_contents) {
-  DCHECK(CalledOnValidThread());
-  printer_->AddErrorMessage("FAIL: main window was destroyed");
-  DiscardMainWindow();
-}
-
-void WebKitTestController::Observe(int type,
-                                   const NotificationSource& source,
-                                   const NotificationDetails& details) {
-  DCHECK(CalledOnValidThread());
-  switch (type) {
-    case NOTIFICATION_RENDERER_PROCESS_CREATED: {
-      if (!main_window_)
-        return;
-      RenderViewHost* render_view_host =
-          main_window_->web_contents()->GetRenderViewHost();
-      if (!render_view_host)
-        return;
-      RenderProcessHost* render_process_host =
-          Source<RenderProcessHost>(source).ptr();
-      if (render_process_host != render_view_host->GetProcess())
-        return;
-      current_pid_ = base::GetProcId(render_process_host->GetHandle());
-      break;
-    }
-    default:
-      NOTREACHED();
-  }
-}
-
-void WebKitTestController::OnGpuProcessCrashed(
-    base::TerminationStatus exit_code) {
-  DCHECK(CalledOnValidThread());
-  printer_->AddErrorMessage("#CRASHED - gpu");
-  DiscardMainWindow();
-}
-
-void WebKitTestController::TimeoutHandler() {
-  DCHECK(CalledOnValidThread());
-  printer_->AddErrorMessage(
-      "FAIL: Timed out waiting for notifyDone to be called");
-  DiscardMainWindow();
-}
-
-void WebKitTestController::DiscardMainWindow() {
-  // If we're running a test, we need to close all windows and exit the message
-  // loop. Otherwise, we're already outside of the message loop, and we just
-  // discard the main window.
-  WebContentsObserver::Observe(NULL);
-  if (test_phase_ != BETWEEN_TESTS) {
-    Shell::CloseAllWindows();
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
-    test_phase_ = CLEAN_UP;
-  } else if (main_window_) {
-    main_window_->Close();
-  }
-  main_window_ = NULL;
-  current_pid_ = base::kNullProcessId;
-}
-
-void WebKitTestController::SendTestConfiguration() {
-  RenderViewHost* render_view_host =
-      main_window_->web_contents()->GetRenderViewHost();
-  ShellTestConfiguration params;
-  params.current_working_directory = current_working_directory_;
-  params.temp_path = temp_path_;
-  params.test_url = test_url_;
-  params.enable_pixel_dumping = enable_pixel_dumping_;
-  params.allow_external_pages = CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kAllowExternalPages);
-  params.expected_pixel_hash = expected_pixel_hash_;
-  params.initial_size = initial_size_;
-  render_view_host->Send(new ShellViewMsg_SetTestConfiguration(
-      render_view_host->GetRoutingID(), params));
-}
-
-void WebKitTestController::OnTestFinished() {
-  test_phase_ = CLEAN_UP;
-  if (!printer_->output_finished())
-    printer_->PrintImageFooter();
-  RenderViewHost* render_view_host =
-      main_window_->web_contents()->GetRenderViewHost();
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(base::IgnoreResult(&WebKitTestController::Send),
-                 base::Unretained(this),
-                 new ShellViewMsg_Reset(render_view_host->GetRoutingID())));
-}
-
-void WebKitTestController::OnImageDump(
-    const std::string& actual_pixel_hash,
-    const SkBitmap& image) {
-  SkAutoLockPixels image_lock(image);
-
-  printer_->PrintImageHeader(actual_pixel_hash, expected_pixel_hash_);
-
-  // Only encode and dump the png if the hashes don't match. Encoding the
-  // image is really expensive.
-  if (actual_pixel_hash != expected_pixel_hash_) {
-    std::vector<unsigned char> png;
-
-    // Only the expected PNGs for Mac have a valid alpha channel.
-#if defined(OS_MACOSX)
-    bool discard_transparency = false;
-#else
-    bool discard_transparency = true;
-#endif
-
-    std::vector<gfx::PNGCodec::Comment> comments;
-    comments.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash));
-    bool success = gfx::PNGCodec::Encode(
-        static_cast<const unsigned char*>(image.getPixels()),
-        gfx::PNGCodec::FORMAT_BGRA,
-        gfx::Size(image.width(), image.height()),
-        static_cast<int>(image.rowBytes()),
-        discard_transparency,
-        comments,
-        &png);
-    if (success)
-      printer_->PrintImageBlock(png);
-  }
-  printer_->PrintImageFooter();
-}
-
-void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) {
-  printer_->PrintAudioHeader();
-  printer_->PrintAudioBlock(dump);
-  printer_->PrintAudioFooter();
-}
-
-void WebKitTestController::OnTextDump(const std::string& dump) {
-  printer_->PrintTextHeader();
-  printer_->PrintTextBlock(dump);
-  printer_->PrintTextFooter();
-}
-
-void WebKitTestController::OnPrintMessage(const std::string& message) {
-  printer_->AddMessageRaw(message);
-}
-
-void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) {
-  should_override_prefs_ = true;
-  prefs_ = prefs;
-}
-
-void WebKitTestController::OnShowDevTools() {
-  main_window_->ShowDevTools();
-}
-
-void WebKitTestController::OnCloseDevTools() {
-  main_window_->CloseDevTools();
-}
-
-void WebKitTestController::OnGoToOffset(int offset) {
-  main_window_->GoBackOrForward(offset);
-}
-
-void WebKitTestController::OnReload() {
-  main_window_->Reload();
-}
-
-void WebKitTestController::OnLoadURLForFrame(const GURL& url,
-                                             const std::string& frame_name) {
-  main_window_->LoadURLForFrame(url, frame_name);
-}
-
-void WebKitTestController::OnCaptureSessionHistory() {
-  std::vector<int> routing_ids;
-  std::vector<std::vector<PageState> > session_histories;
-  std::vector<unsigned> current_entry_indexes;
-
-  RenderViewHost* render_view_host =
-      main_window_->web_contents()->GetRenderViewHost();
-
-  for (std::vector<Shell*>::iterator window = Shell::windows().begin();
-       window != Shell::windows().end();
-       ++window) {
-    WebContents* web_contents = (*window)->web_contents();
-    // Only capture the history from windows in the same process as the main
-    // window. During layout tests, we only use two processes when an
-    // devtools window is open. This should not happen during history navigation
-    // tests.
-    if (render_view_host->GetProcess() !=
-        web_contents->GetRenderViewHost()->GetProcess()) {
-      NOTREACHED();
-      continue;
-    }
-    routing_ids.push_back(web_contents->GetRenderViewHost()->GetRoutingID());
-    current_entry_indexes.push_back(
-        web_contents->GetController().GetCurrentEntryIndex());
-    std::vector<PageState> history;
-    for (int entry = 0; entry < web_contents->GetController().GetEntryCount();
-         ++entry) {
-      PageState state = web_contents->GetController().GetEntryAtIndex(entry)->
-          GetPageState();
-      if (!state.IsValid()) {
-        state = PageState::CreateFromURL(
-            web_contents->GetController().GetEntryAtIndex(entry)->GetURL());
-      }
-      history.push_back(state);
-    }
-    session_histories.push_back(history);
-  }
-
-  Send(new ShellViewMsg_SessionHistory(render_view_host->GetRoutingID(),
-                                       routing_ids,
-                                       session_histories,
-                                       current_entry_indexes));
-}
-
-void WebKitTestController::OnCloseRemainingWindows() {
-  DevToolsManager::GetInstance()->CloseAllClientHosts();
-  std::vector<Shell*> open_windows(Shell::windows());
-  for (size_t i = 0; i < open_windows.size(); ++i) {
-    if (open_windows[i] != main_window_)
-      open_windows[i]->Close();
-  }
-  base::MessageLoop::current()->RunUntilIdle();
-}
-
-void WebKitTestController::OnResetDone() {
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::MessageLoop::QuitClosure());
-}
-
-}  // namespace content
diff --git a/content/shell/webkit_test_controller.h b/content/shell/webkit_test_controller.h
deleted file mode 100644
index aa181df..0000000
--- a/content/shell/webkit_test_controller.h
+++ /dev/null
@@ -1,219 +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_SHELL_WEBKIT_TEST_CONTROLLER_H_
-#define CONTENT_SHELL_WEBKIT_TEST_CONTROLLER_H_
-
-#include <ostream>
-#include <string>
-
-#include "base/cancelable_callback.h"
-#include "base/files/file_path.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/non_thread_safe.h"
-#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"
-
-#if defined(OS_ANDROID)
-#include "base/threading/thread_restrictions.h"
-#endif
-
-class SkBitmap;
-
-namespace content {
-
-class Shell;
-
-#if defined(OS_ANDROID)
-// Android uses a nested message loop for running layout tests because the
-// default message loop, provided by the system, does not offer a blocking
-// Run() method. The loop itself, implemented as NestedMessagePumpAndroid,
-// uses a base::WaitableEvent allowing it to sleep until more events arrive.
-class ScopedAllowWaitForAndroidLayoutTests {
- private:
-  base::ThreadRestrictions::ScopedAllowWait wait;
-};
-#endif
-
-class WebKitTestResultPrinter {
- public:
-  WebKitTestResultPrinter(std::ostream* output, std::ostream* error);
-  ~WebKitTestResultPrinter();
-
-  void reset() {
-    state_ = DURING_TEST;
-  }
-  bool output_finished() const { return state_ == AFTER_TEST; }
-  void set_capture_text_only(bool capture_text_only) {
-    capture_text_only_ = capture_text_only;
-  }
-
-  void set_encode_binary_data(bool encode_binary_data) {
-    encode_binary_data_ = encode_binary_data;
-  }
-
-  void PrintTextHeader();
-  void PrintTextBlock(const std::string& block);
-  void PrintTextFooter();
-
-  void PrintImageHeader(const std::string& actual_hash,
-                        const std::string& expected_hash);
-  void PrintImageBlock(const std::vector<unsigned char>& png_image);
-  void PrintImageFooter();
-
-  void PrintAudioHeader();
-  void PrintAudioBlock(const std::vector<unsigned char>& audio_data);
-  void PrintAudioFooter();
-
-  void AddMessage(const std::string& message);
-  void AddMessageRaw(const std::string& message);
-  void AddErrorMessage(const std::string& message);
-
- private:
-  void PrintEncodedBinaryData(const std::vector<unsigned char>& data);
-
-  enum State {
-    DURING_TEST,
-    IN_TEXT_BLOCK,
-    IN_AUDIO_BLOCK,
-    IN_IMAGE_BLOCK,
-    AFTER_TEST
-  };
-  State state_;
-
-  bool capture_text_only_;
-  bool encode_binary_data_;
-
-  std::ostream* output_;
-  std::ostream* error_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebKitTestResultPrinter);
-};
-
-class WebKitTestController : public base::NonThreadSafe,
-                             public WebContentsObserver,
-                             public NotificationObserver,
-                             public GpuDataManagerObserver {
- public:
-  static WebKitTestController* Get();
-
-  WebKitTestController();
-  virtual ~WebKitTestController();
-
-  // True if the controller is ready for testing.
-  bool PrepareForLayoutTest(const GURL& test_url,
-                            const base::FilePath& current_working_directory,
-                            bool enable_pixel_dumping,
-                            const std::string& expected_pixel_hash);
-  // True if the controller was reset successfully.
-  bool ResetAfterLayoutTest();
-
-  void SetTempPath(const base::FilePath& temp_path);
-  void RendererUnresponsive();
-  void WorkerCrashed();
-  void OverrideWebkitPrefs(WebPreferences* prefs);
-  void OpenURL(const GURL& url);
-  void TestFinishedInSecondaryWindow();
-  bool IsMainWindow(WebContents* web_contents) const;
-
-  WebKitTestResultPrinter* printer() { return printer_.get(); }
-  void set_printer(WebKitTestResultPrinter* printer) {
-    printer_.reset(printer);
-  }
-
-  // WebContentsObserver implementation.
-  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-  virtual void PluginCrashed(const base::FilePath& plugin_path,
-                             base::ProcessId plugin_pid) OVERRIDE;
-  virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
-  virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
-  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
-
-  // NotificationObserver implementation.
-  virtual void Observe(int type,
-                       const NotificationSource& source,
-                       const NotificationDetails& details) OVERRIDE;
-
-  // GpuDataManagerObserver implementation.
-  virtual void OnGpuProcessCrashed(base::TerminationStatus exit_code) OVERRIDE;
-
- private:
-  enum TestPhase {
-    BETWEEN_TESTS,
-    DURING_TEST,
-    CLEAN_UP
-  };
-
-  static WebKitTestController* instance_;
-
-  void TimeoutHandler();
-  void DiscardMainWindow();
-  void SendTestConfiguration();
-
-  // Message handlers.
-  void OnAudioDump(const std::vector<unsigned char>& audio_dump);
-  void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image);
-  void OnTextDump(const std::string& dump);
-  void OnPrintMessage(const std::string& message);
-  void OnOverridePreferences(const WebPreferences& prefs);
-  void OnTestFinished();
-  void OnShowDevTools();
-  void OnCloseDevTools();
-  void OnGoToOffset(int offset);
-  void OnReload();
-  void OnLoadURLForFrame(const GURL& url, const std::string& frame_name);
-  void OnCaptureSessionHistory();
-  void OnCloseRemainingWindows();
-  void OnResetDone();
-
-  scoped_ptr<WebKitTestResultPrinter> printer_;
-
-  base::FilePath current_working_directory_;
-  base::FilePath temp_path_;
-
-  Shell* main_window_;
-
-  // The PID of the render process of the render view host of main_window_.
-  int current_pid_;
-
-  // True if we should set the test configuration to the next RenderViewHost
-  // created.
-  bool send_configuration_to_next_host_;
-
-  // What phase of running an individual test we are currently in.
-  TestPhase test_phase_;
-
-  // True if the currently running test is a compositing test.
-  bool is_compositing_test_;
-
-  // Per test config.
-  bool enable_pixel_dumping_;
-  std::string expected_pixel_hash_;
-  gfx::Size initial_size_;
-  GURL test_url_;
-
-  // True if the WebPreferences of newly created RenderViewHost should be
-  // overridden with prefs_.
-  bool should_override_prefs_;
-  WebPreferences prefs_;
-
-  NotificationRegistrar registrar_;
-
-#if defined(OS_ANDROID)
-  // Because of the nested message pump implementation, Android needs to allow
-  // waiting on the UI thread while layout tests are being ran.
-  ScopedAllowWaitForAndroidLayoutTests reduced_restrictions_;
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(WebKitTestController);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_WEBKIT_TEST_CONTROLLER_H_
diff --git a/content/test/accessibility_browser_test_utils.cc b/content/test/accessibility_browser_test_utils.cc
index 5ca6b12..67d159c 100644
--- a/content/test/accessibility_browser_test_utils.cc
+++ b/content/test/accessibility_browser_test_utils.cc
@@ -13,7 +13,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 
 namespace content {
 
@@ -57,13 +57,11 @@
   // to avoid a possible race condition between the test beginning
   // listening for accessibility events and "about:blank" loading.
   const AccessibilityNodeDataTreeNode& root = GetAccessibilityNodeDataTree();
-  typedef AccessibilityNodeData::StringAttribute StringAttribute;
-  std::map<StringAttribute, string16>::const_iterator iter;
-  iter = root.string_attributes.find(AccessibilityNodeData::ATTR_DOC_URL);
-  if (iter != root.string_attributes.end()) {
-    string16 doc_url = iter->second;
-    if (doc_url == ASCIIToUTF16(kAboutBlankURL))
-      return true;
+  for (size_t i = 0; i < root.string_attributes.size(); ++i) {
+    if (root.string_attributes[i].first != AccessibilityNodeData::ATTR_DOC_URL)
+      continue;
+    const std::string& doc_url = root.string_attributes[i].second;
+    return doc_url == kAboutBlankURL;
   }
   return false;
 }
diff --git a/content/test/content_browser_test.cc b/content/test/content_browser_test.cc
index fb0cb6d..2155cb3 100644
--- a/content/test/content_browser_test.cc
+++ b/content/test/content_browser_test.cc
@@ -14,11 +14,11 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/shell/app/shell_main_delegate.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/common/shell_switches.h"
 #include "content/shell/renderer/shell_content_renderer_client.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/shell_content_browser_client.h"
 #include "content/test/test_content_client.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
diff --git a/content/test/content_browser_test_test.cc b/content/test/content_browser_test_test.cc
index 9ecd4f6..5681140 100644
--- a/content/test/content_browser_test_test.cc
+++ b/content/test/content_browser_test_test.cc
@@ -8,7 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
-#include "content/shell/shell.h"
+#include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/content/test/content_browser_test_utils.cc b/content/test/content_browser_test_utils.cc
index aec5661..6c38718 100644
--- a/content/test/content_browser_test_utils.cc
+++ b/content/test/content_browser_test_utils.cc
@@ -15,8 +15,8 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
-#include "content/shell/shell.h"
-#include "content/shell/shell_javascript_dialog_manager.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
 #include "net/base/net_util.h"
 
 namespace content {
diff --git a/content/test/content_test_launcher.cc b/content/test/content_test_launcher.cc
index c4ed185..9a229a9 100644
--- a/content/test/content_test_launcher.cc
+++ b/content/test/content_test_launcher.cc
@@ -12,9 +12,9 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/content_test_suite_base.h"
 #include "content/shell/app/shell_main_delegate.h"
+#include "content/shell/browser/shell_content_browser_client.h"
 #include "content/shell/common/shell_content_client.h"
 #include "content/shell/common/shell_switches.h"
-#include "content/shell/shell_content_browser_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(OS_ANDROID)
diff --git a/content/test/data/browser_plugin_embedder.html b/content/test/data/browser_plugin_embedder.html
index 73ce463..b48ecdd 100644
--- a/content/test/data/browser_plugin_embedder.html
+++ b/content/test/data/browser_plugin_embedder.html
@@ -1,9 +1,4 @@
 <script type="text/javascript">
-function sizeChanged(evt) {
-  var data = JSON.parse(evt.detail);
-  document.title = "AutoSize(" + data.newWidth + ", " + data.newHeight + ")";
-}
-
 function SetSrc(src) {
   var plugin = document.getElementById('plugin');
   plugin.src = src;
@@ -57,7 +52,6 @@
 
 var plugin = document.getElementById('plugin');
 window.addEventListener('message', receiveMessage, false);
-plugin.addEventListener('-internal-sizechanged', sizeChanged);
 plugin.addEventListener('-internal-instanceid-allocated', function(e) {
   plugin['-internal-attach']({});
 });
diff --git a/content/test/data/media/getusermedia.html b/content/test/data/media/getusermedia.html
index 429dd66..14ce8d5 100644
--- a/content/test/data/media/getusermedia.html
+++ b/content/test/data/media/getusermedia.html
@@ -19,7 +19,12 @@
     navigator.webkitGetUserMedia(constraints, displayAndWaitForVideo,
         failedCallback);
   }
-  
+
+  function getUserMediaWithAnalysis(constraints) {
+    navigator.webkitGetUserMedia(
+        constraints, displayAndWaitForAndAnalyzeVideo, failedCallback);
+  }
+
   // This test that a MediaStream can be cloned and that the clone can 
   // be rendered.
   function getUserMediaAndClone() {
@@ -37,7 +42,14 @@
     $('local-view').src = localStreamUrl;
     waitForVideo('local-view');   
   }
-  
+
+  function displayAndWaitForAndAnalyzeVideo(stream) {
+    gLocalStream = stream;
+    var localStreamUrl = webkitURL.createObjectURL(stream);
+    $('local-view').src = localStreamUrl;
+    analyzeVideo();
+  }
+
   function createAndRenderClone(stream) {
     gLocalStream = stream;
     // TODO(perkj):  --use-fake-device-for-media-stream do not currently
@@ -56,7 +68,16 @@
     $('local-view').src = newStreamUrl;  
     waitForVideo('local-view');
   }
-  
+
+  function analyzeVideo() {
+    document.title = 'Waiting for video...';
+    addExpectedEvent();
+    detectAspectRatio(function(aspectRatio) {
+      document.title = aspectRatio;
+      eventOccured();
+    });
+  }
+
   </script>  
 </head>
 <body>
diff --git a/content/test/data/media/webrtc_test_utilities.js b/content/test/data/media/webrtc_test_utilities.js
index 61472d1..ba894cd 100644
--- a/content/test/data/media/webrtc_test_utilities.js
+++ b/content/test/data/media/webrtc_test_utilities.js
@@ -6,6 +6,9 @@
 const VIDEO_TAG_WIDTH = 320;
 const VIDEO_TAG_HEIGHT = 240;
 
+// Fake video capture background green is of value 135.
+const COLOR_BACKGROUND_GREEN = 135;
+
 // Number of test events to occur before the test pass. When the test pass,
 // the function gAllEventsOccured is called.
 var gNumberOfExpectedEvents = 0;
@@ -87,4 +90,91 @@
     document.title = s;
     throw s;
   }
-}
\ No newline at end of file
+}
+
+// This function tries to calculate the aspect ratio shown by the fake capture
+// device in the video tag. For this, we count the amount of light green pixels
+// along |aperture| pixels on the positive X and Y axis starting from the
+// center of the image. In this very center there should be a time-varying
+// pacman; the algorithm counts for a couple of iterations and keeps the
+// maximum amount of light green pixels on both directions. From this data
+// the aspect ratio is calculated relative to a 320x240 window, so 4:3 would
+// show as a 1. Furthermore, since an original non-4:3 might be letterboxed or
+// cropped, the actual X and Y pixel amounts are compared with the fake video
+// capture expected pacman radius (see further below).
+function detectAspectRatio(callback) {
+  var width = VIDEO_TAG_WIDTH;
+  var height = VIDEO_TAG_HEIGHT;
+  var videoElement = $('local-view');
+  var canvas = $('local-view-canvas');
+
+  var maxLightGreenPixelsX = 0;
+  var maxLightGreenPixelsY = 0;
+
+  var aperture = Math.min(width, height) / 2;
+  var iterations = 0;
+  var maxIterations = 10;
+
+  var waitVideo = setInterval(function() {
+    var context = canvas.getContext('2d');
+    context.drawImage(videoElement, 0, 0, width, height);
+
+    // We are interested in a window starting from the center of the image
+    // where we expect the circle from the fake video capture to be rolling.
+    var pixels =
+        context.getImageData(width / 2, height / 2, aperture, aperture);
+
+    var lightGreenPixelsX = 0;
+    var lightGreenPixelsY = 0;
+
+    // Walk horizontally counting light green pixels.
+    for (var x = 0; x < aperture; ++x) {
+      if (pixels.data[4 * x + 1] != COLOR_BACKGROUND_GREEN)
+        lightGreenPixelsX++;
+    }
+    // Walk vertically counting light green pixels.
+    for (var y = 0; y < aperture; ++y) {
+      if (pixels.data[4 * y * aperture + 1] != 135)
+        lightGreenPixelsY++;
+    }
+    if (lightGreenPixelsX > maxLightGreenPixelsX &&
+        lightGreenPixelsX < aperture)
+      maxLightGreenPixelsX = lightGreenPixelsX;
+    if (lightGreenPixelsY > maxLightGreenPixelsY &&
+        lightGreenPixelsY < aperture)
+      maxLightGreenPixelsY = lightGreenPixelsY;
+
+    var detectedAspectRatioString = "";
+    if (++iterations > maxIterations) {
+      clearInterval(waitVideo);
+      observedAspectRatio = maxLightGreenPixelsY / maxLightGreenPixelsX;
+      // At this point the observed aspect ratio is either 1, for undistorted
+      // 4:3, or some other aspect ratio that is seen as distorted.
+      if (Math.abs(observedAspectRatio - 1.333) < 0.1)
+        detectedAspectRatioString = "16:9";
+      else if (Math.abs(observedAspectRatio - 1.20) < 0.1)
+        detectedAspectRatioString = "16:10";
+      else if (Math.abs(observedAspectRatio - 1.0) < 0.1)
+        detectedAspectRatioString = "4:3";
+      else
+        detectedAspectRatioString = "UNKNOWN aspect ratio";
+      console.log(detectedAspectRatioString + " observed aspect ratio (" +
+                  observedAspectRatio + ")");
+
+      // The FakeVideoCapture calculates the circle radius as
+      // std::min(capture_format_.width, capture_format_.height) / 4;
+      // we do the same and see if both dimensions are scaled, meaning
+      // we started from a cropped or stretched image.
+      var nonDistortedRadius = Math.min(width, height) / 4;
+      if ((maxLightGreenPixelsX != nonDistortedRadius) &&
+          (maxLightGreenPixelsY != nonDistortedRadius)) {
+        detectedAspectRatioString += " cropped";
+      } else
+        detectedAspectRatioString += " letterbox";
+
+      console.log("Original image is: " + detectedAspectRatioString);
+      callback(detectedAspectRatioString);
+    }
+  },
+                              50);
+}
diff --git a/content/test/data/media/webui/integration_test.html b/content/test/data/media/webui/integration_test.html
new file mode 100644
index 0000000..2d25ede
--- /dev/null
+++ b/content/test/data/media/webui/integration_test.html
@@ -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.
+-->
+<!DOCTYPE html>
+<html>
+  <body>
+    <script>
+      window.setUp = function() {
+        var doNothing = function() {};
+        var mockClientRenderer = {
+          playerUpdated: doNothing,
+          playerRemoved: doNothing,
+          playerAdded: doNothing
+        };
+
+        var manager = new PlayerManager(mockClientRenderer);
+        media.initialize(manager);
+
+        window.playerManager = manager;
+      };
+
+      // The renderer and player ids are completely arbitrarily.
+      var TEST_RENDERER = 12;
+      var TEST_PLAYER = 4;
+      var TEST_NAME = TEST_RENDERER + ':' + TEST_PLAYER;
+
+      // Correctly use the information from a media event.
+      window.testOnMediaEvent = function() {
+        var event = {
+          ticksMillis: 132,
+          renderer: TEST_RENDERER,
+          player: TEST_PLAYER,
+          params: {
+            fps: 60,
+            other: 'hi'
+          }
+        };
+
+        window.media.onMediaEvent(event);
+        var info = window.playerManager.players_[TEST_NAME];
+
+        assertEquals(event.ticksMillis, info.firstTimestamp_);
+        assertEquals(TEST_NAME, info.id);
+        assertEquals(event.params.fps, info.properties.fps);
+      };
+
+      // Remove a player.
+      window.testOnRenderTerminated = function() {
+        window.testOnMediaEvent();
+
+        window.media.onRendererTerminated(TEST_RENDERER);
+        assertEquals(undefined, window.playerManager.players_[TEST_NAME]);
+      };
+
+      // Audio Streams are weird, they are handled separately
+      window.testAddAudioStream = function() {
+        var event = {
+          id: 'ID',
+          status: 'created',
+          playing: true
+        };
+
+        window.media.addAudioStream(event);
+
+        var player = window.playerManager.players_[event.id];
+        assertTrue(undefined !== player);
+        assertEquals(event.playing, player.properties['playing']);
+      };
+    </script>
+  </body>
+</html>
diff --git a/content/test/data/media/webui/player_info_test.html b/content/test/data/media/webui/player_info_test.html
new file mode 100644
index 0000000..02a36b4
--- /dev/null
+++ b/content/test/data/media/webui/player_info_test.html
@@ -0,0 +1,140 @@
+<!--
+Copyright 2013 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<!DOCTYPE html>
+<html>
+  <body>
+    <script>
+      window.setUp = function() {
+        window.pi = new PlayerInfo('example_id');
+      };
+
+      window.tearDown = function() {
+        window.pi = null;
+      };
+
+      // Test that an ID is set correctly.
+      window.testConstructorStringID = function() {
+        assertEquals('example_id', window.pi.id);
+      };
+
+      // Test that numerical IDs are valid.
+      window.testConstructorNumberId = function() {
+        var pi = new PlayerInfo(5);
+        assertEquals(5, pi.id);
+      };
+
+      // Make sure that a new PlayerInfo has no events.
+      window.testEmptyEvents = function() {
+        assertEquals(0, window.pi.allEvents.length);
+      };
+
+      // Check that the most recent property gets updated.
+      window.testAddProperty = function() {
+        var key = 'key',
+          value = 'value',
+          value2 = 'value2';
+
+        window.pi.addProperty(0, key, value);
+        assertEquals(value, window.pi.properties[key]);
+
+        window.pi.addProperty(0, key, value2);
+        assertEquals(value2, window.pi.properties[key]);
+
+      };
+
+      // Make sure that the first timestamp that gets sent
+      // is recorded as the base timestamp.
+      window.testFirstTimestamp = function() {
+        var pi = new PlayerInfo('example_ID');
+        var timestamp = 5000;
+        pi.addProperty(timestamp, 'key', 'value');
+
+        assertEquals(timestamp, pi.firstTimestamp_);
+      };
+
+      // Adding a property with a non-string key should
+      // throw an exception.
+      window.testWrongKeyType = function() {
+        var pi = new PlayerInfo('example_ID');
+        assertThrows(function() {
+          pi.addProperty(0, 5, 'some value');
+        });
+      };
+
+      // Subsequent events should have their log offset based
+      // on the first timestamp added.
+      window.testAddPropertyTimestampOffset = function() {
+        var firstTimestamp = 500,
+          secondTimestamp = 550,
+          deltaT = secondTimestamp - firstTimestamp,
+          key = 'key',
+          value = 'value';
+
+        var pi = new PlayerInfo('example_ID');
+        pi.addProperty(firstTimestamp, key, value);
+        pi.addProperty(secondTimestamp, key, value);
+
+        assertEquals(firstTimestamp, pi.firstTimestamp_);
+        assertEquals(0, pi.allEvents[0].time);
+        assertEquals(deltaT, pi.allEvents[1].time);
+
+        assertTrue(undefined !== pi.pastValues[key]);
+
+        console.log(pi.pastValues);
+
+        assertEquals(0, pi.pastValues[key][0].time);
+        assertEquals(deltaT, pi.pastValues[key][1].time);
+      };
+
+      // Check to make sure that properties are correctly
+      // added to the relevant pastValues array.
+      window.testAddPropertyPastValues = function() {
+        var pi = new PlayerInfo('example_ID'),
+          timestamp = 50,
+          key = 'key',
+          value = 'value';
+
+        pi.addProperty(timestamp, key, value);
+
+        assertEquals(value, pi.pastValues[key][0].value);
+        assertEquals(key, pi.pastValues[key][0].key);
+        assertEquals(0, pi.pastValues[key][0].time);
+      };
+
+      // The list of all events should be recorded in correctly.
+      window.testAllEvents = function() {
+        var pi = new PlayerInfo('example_ID'),
+          timestamp = 50,
+          key = 'key',
+          value = 'value',
+          key2 = 'key2',
+          value2 = 'value2';
+
+        pi.addProperty(timestamp, key, value);
+        assertEquals(value, pi.allEvents[0].value);
+        assertEquals(key, pi.allEvents[0].key);
+
+        pi.addProperty(timestamp, key2, value2);
+        assertEquals(value2, pi.allEvents[1].value);
+        assertEquals(key2, pi.allEvents[1].key);
+      };
+
+      // Using noRecord should make it not show up in allEvents,
+      // but it should still show up in pastValues[key].
+      window.testNoRecord = function() {
+        var pi = new PlayerInfo('example_ID'),
+          timestamp = 50,
+          key = 'key',
+          value = 'value';
+        pi.addPropertyNoRecord(timestamp, key, value);
+
+        assertEquals(value, pi.properties[key]);
+        assertEquals(0, pi.allEvents.length);
+        assertEquals(1, pi.pastValues[key].length);
+      };
+    </script>
+  </body>
+</html>
diff --git a/content/test/data/media/webui/player_manager_test.html b/content/test/data/media/webui/player_manager_test.html
new file mode 100644
index 0000000..290ee3f
--- /dev/null
+++ b/content/test/data/media/webui/player_manager_test.html
@@ -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.
+-->
+<!DOCTYPE html>
+<html>
+  <body>
+    <script>
+      var doNothing = function() {
+      };
+
+      var emptyClientRenderer = {
+        playerAdded: doNothing,
+        playerRemoved: doNothing,
+        playerUpdated: doNothing
+      };
+
+      window.setUp = function() {
+        window.pm = new PlayerManager(emptyClientRenderer);
+      };
+
+      window.tearDown = function() {
+        window.pm = null;
+      };
+
+      // Test a normal case of .addPlayer
+      window.testAddPlayer = function() {
+        window.pm.addPlayer('someid');
+        assertTrue(undefined !== window.pm.players_['someid']);
+      };
+
+      // On occasion, the backend will add an existing ID multiple times.
+      // make sure this doesn't break anything.
+      window.testAddPlayerAlreadyExisting = function() {
+        window.pm.addPlayer('someid');
+        window.pm.addPlayer('someid');
+        assertTrue(undefined !== window.pm.players_['someid']);
+      };
+
+      // If the removal is set, make sure that a player
+      // gets removed from the PlayerManager.
+      window.testRemovePlayer = function() {
+        window.pm.addPlayer('someid');
+        assertTrue(undefined !== window.pm.players_['someid']);
+        window.pm.removePlayer('someid');
+        assertTrue(undefined === window.pm.players_['someid']);
+      };
+
+      // Trying to select a non-existant player should throw
+      // an exception
+      window.testSelectNonExistant = function() {
+        assertThrows(function() {
+          window.pm.selectPlayer('someId');
+        });
+      };
+    </script>
+  </body>
+</html>
diff --git a/content/test/gpu/gpu_tests/pixel.py b/content/test/gpu/gpu_tests/pixel.py
index d2726c4..8545dd2 100644
--- a/content/test/gpu/gpu_tests/pixel.py
+++ b/content/test/gpu/gpu_tests/pixel.py
@@ -13,9 +13,6 @@
   def __init__(self):
     super(PixelValidator, self).__init__('ValidatePage')
 
-  def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArg('--enable-webgl')
-
   def ValidatePage(self, page, tab, results):
     # TODO(bajones): Grab screenshot, compare to reference.
     # page.reference_image
diff --git a/content/test/gpu/gpu_tests/webgl_conformance.py b/content/test/gpu/gpu_tests/webgl_conformance.py
index 1d49501..5e27d21 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance.py
@@ -59,7 +59,6 @@
       raise page_test.Failure(_WebGLTestMessages(tab))
 
   def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArg('--enable-webgl')
     options.AppendExtraBrowserArg(
         '--disable-gesture-requirement-for-media-playback')
 
@@ -85,7 +84,15 @@
       pages.append({
         'url': 'file:///' + test,
         'script_to_evaluate_on_commit': conformance_harness_script,
-        'wait_for_javascript_expression': 'webglTestHarness._finished'
+        'navigate_steps': [
+          {'action': 'navigate'},
+          {
+            'action': 'wait',
+            'condition': 'javascript',
+            'javascript': 'webglTestHarness._finished',
+            'timeout': 120
+          },
+        ]
       })
 
     return page_set.PageSet.FromDict(page_set_dict, conformance_path)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index a092c7e..af4a0b4 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -7,11 +7,15 @@
 # Valid expectation conditions are:
 # win xp vista win7
 # mac leopard snowleopard lion mountainlion
-# linux chromeos
+# linux chromeos android
 # nvidia amd intel
+# Specific gpu's can be listed as a tuple with vendor name and device ID.
+# Example: ('nvidia', 0x1234)
+# Device ID's must be paired with a gpu vendor.
 
 class WebGLConformanceExpectations(test_expectations.TestExpectations):
   def SetExpectations(self):
     # Sample Usage:
-    # self.Fail("gl-enable-vertex-attrib.html", ["mac", "win"], bug=1234)
+    # self.Fail("gl-enable-vertex-attrib.html",
+    #     ['mac', 'amd', ('nvidia', 0x1234)], bug=123)
     pass
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 3f1a0f6..12448b5 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -13,6 +13,7 @@
 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
 #include "content/test/test_media_stream_client.h"
 #include "third_party/WebKit/public/platform/WebDeviceMotionData.h"
+#include "third_party/WebKit/public/platform/WebDeviceOrientationData.h"
 #include "third_party/WebKit/public/platform/WebGamepads.h"
 #include "third_party/WebKit/public/testing/WebFrameTestProxy.h"
 #include "third_party/WebKit/public/testing/WebTestProxy.h"
@@ -26,6 +27,7 @@
 #endif
 
 using WebKit::WebDeviceMotionData;
+using WebKit::WebDeviceOrientationData;
 using WebKit::WebGamepads;
 using WebKit::WebRect;
 using WebKit::WebSize;
@@ -84,6 +86,11 @@
   RendererWebKitPlatformSupportImpl::SetMockDeviceMotionDataForTesting(data);
 }
 
+void SetMockDeviceOrientationData(const WebDeviceOrientationData& data) {
+  RendererWebKitPlatformSupportImpl::
+      SetMockDeviceOrientationDataForTesting(data);
+}
+
 void EnableRendererLayoutTestMode() {
   RenderThreadImpl::current()->set_layout_test_mode(true);
 }
diff --git a/content/test/net/url_request_mock_http_job.cc b/content/test/net/url_request_mock_http_job.cc
index a864ed0..9927960 100644
--- a/content/test/net/url_request_mock_http_job.cc
+++ b/content/test/net/url_request_mock_http_job.cc
@@ -8,7 +8,9 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
@@ -109,10 +111,13 @@
 }
 
 URLRequestMockHTTPJob::URLRequestMockHTTPJob(
-    net::URLRequest* request,
-    net::NetworkDelegate* network_delegate,
+    net::URLRequest* request, net::NetworkDelegate* network_delegate,
     const base::FilePath& file_path)
-    : net::URLRequestFileJob(request, network_delegate, file_path) { }
+    : net::URLRequestFileJob(
+          request, network_delegate, file_path,
+          content::BrowserThread::GetBlockingPool()->
+              GetTaskRunnerWithShutdownBehavior(
+                  base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {}
 
 URLRequestMockHTTPJob::~URLRequestMockHTTPJob() { }
 
diff --git a/content/test/net/url_request_prepackaged_interceptor.cc b/content/test/net/url_request_prepackaged_interceptor.cc
index 75d2ffc..484f260 100644
--- a/content/test/net/url_request_prepackaged_interceptor.cc
+++ b/content/test/net/url_request_prepackaged_interceptor.cc
@@ -5,6 +5,7 @@
 #include "content/test/net/url_request_prepackaged_interceptor.h"
 
 #include "base/file_util.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/url_request/url_request.h"
@@ -23,7 +24,11 @@
   URLRequestPrepackagedJob(net::URLRequest* request,
                            net::NetworkDelegate* network_delegate,
                            const base::FilePath& file_path)
-      : net::URLRequestFileJob(request, network_delegate, file_path) {}
+      : net::URLRequestFileJob(
+            request, network_delegate, file_path,
+            content::BrowserThread::GetBlockingPool()->
+                GetTaskRunnerWithShutdownBehavior(
+                    base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {}
 
   virtual int GetResponseCode() const OVERRIDE { return 200; }
 
diff --git a/content/test/plugin/plugin_window_size_test.cc b/content/test/plugin/plugin_window_size_test.cc
index 701b58a..06cecf7 100644
--- a/content/test/plugin/plugin_window_size_test.cc
+++ b/content/test/plugin/plugin_window_size_test.cc
@@ -17,7 +17,7 @@
     return NPERR_NO_ERROR;
 
   HWND window = reinterpret_cast<HWND>(pNPWindow->window);
-  if (!pNPWindow || !::IsWindow(window)) {
+  if (!::IsWindow(window)) {
     SetError("Invalid arguments passed in");
     return NPERR_INVALID_PARAM;
   }
diff --git a/content/test/plugin/plugin_windowed_test.cc b/content/test/plugin/plugin_windowed_test.cc
index 150d256..a795857 100644
--- a/content/test/plugin/plugin_windowed_test.cc
+++ b/content/test/plugin/plugin_windowed_test.cc
@@ -32,7 +32,7 @@
     return NPERR_NO_ERROR;
 
   HWND parent = reinterpret_cast<HWND>(pNPWindow->window);
-  if (!pNPWindow || !::IsWindow(parent)) {
+  if (!::IsWindow(parent)) {
     SetError("Invalid arguments passed in");
     return NPERR_INVALID_PARAM;
   }
diff --git a/content/test/ppapi_unittest.cc b/content/test/ppapi_unittest.cc
new file mode 100644
index 0000000..8714550
--- /dev/null
+++ b/content/test/ppapi_unittest.cc
@@ -0,0 +1,118 @@
+// 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/test/ppapi_unittest.h"
+
+#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/gfx_conversion.h"
+#include "content/renderer/pepper/host_globals.h"
+#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/plugin_module.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/pp_var.h"
+#include "ppapi/c/ppp_instance.h"
+#include "ppapi/shared_impl/ppapi_globals.h"
+#include "ppapi/shared_impl/ppapi_permissions.h"
+
+namespace content {
+
+namespace {
+
+PpapiUnittest* current_unittest = NULL;
+
+const void* MockGetInterface(const char* interface_name) {
+  return current_unittest->GetMockInterface(interface_name);
+}
+
+int MockInitializeModule(PP_Module, PPB_GetInterface) {
+  return PP_OK;
+}
+
+// PPP_Instance implementation ------------------------------------------------
+
+PP_Bool Instance_DidCreate(PP_Instance pp_instance,
+                           uint32_t argc,
+                           const char* argn[],
+                           const char* argv[]) {
+  return PP_TRUE;
+}
+
+void Instance_DidDestroy(PP_Instance instance) {
+}
+
+void Instance_DidChangeView(PP_Instance pp_instance, PP_Resource view) {
+}
+
+void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
+}
+
+PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
+                                    PP_Resource pp_url_loader) {
+  return PP_FALSE;
+}
+
+static PPP_Instance mock_instance_interface = {
+  &Instance_DidCreate,
+  &Instance_DidDestroy,
+  &Instance_DidChangeView,
+  &Instance_DidChangeFocus,
+  &Instance_HandleDocumentLoad
+};
+
+}  // namespace
+
+// PpapiUnittest --------------------------------------------------------------
+
+PpapiUnittest::PpapiUnittest() {
+  DCHECK(!current_unittest);
+  current_unittest = this;
+}
+
+PpapiUnittest::~PpapiUnittest() {
+  DCHECK(current_unittest == this);
+  current_unittest = NULL;
+}
+
+void PpapiUnittest::SetUp() {
+  message_loop_.reset(new base::MessageLoop());
+
+  // Initialize the mock module.
+  module_ = new PluginModule("Mock plugin", base::FilePath(),
+                             ppapi::PpapiPermissions());
+  ppapi::PpapiGlobals::Get()->ResetMainThreadMessageLoopForTesting();
+  PepperPluginInfo::EntryPoints entry_points;
+  entry_points.get_interface = &MockGetInterface;
+  entry_points.initialize_module = &MockInitializeModule;
+  ASSERT_TRUE(module_->InitAsInternalPlugin(entry_points));
+
+  // Initialize the mock instance.
+  instance_ = PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL());
+}
+
+void PpapiUnittest::TearDown() {
+  instance_ = NULL;
+  module_ = NULL;
+  message_loop_.reset();
+  PluginModule::ResetHostGlobalsForTest();
+}
+
+const void* PpapiUnittest::GetMockInterface(const char* interface_name) const {
+  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE_1_0) == 0)
+    return &mock_instance_interface;
+  return NULL;
+}
+
+void PpapiUnittest::ShutdownModule() {
+  DCHECK(instance_->HasOneRef());
+  instance_ = NULL;
+  DCHECK(module_->HasOneRef());
+  module_ = NULL;
+}
+
+void PpapiUnittest::SetViewSize(int width, int height) const {
+  instance_->view_data_.rect = PP_FromGfxRect(gfx::Rect(0, 0, width, height));
+  instance_->view_data_.clip_rect = instance_->view_data_.rect;
+}
+
+}  // namespace content
diff --git a/content/test/ppapi_unittest.h b/content/test/ppapi_unittest.h
new file mode 100644
index 0000000..eb4f3b9
--- /dev/null
+++ b/content/test/ppapi_unittest.h
@@ -0,0 +1,55 @@
+// 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 CONTENT_TEST_PPAPI_UNITTEST_H_
+#define CONTENT_TEST_PPAPI_UNITTEST_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace content {
+
+class PepperPluginInstanceImpl;
+class PluginModule;
+
+class PpapiUnittest : public testing::Test {
+ public:
+  PpapiUnittest();
+  virtual ~PpapiUnittest();
+
+  virtual void SetUp();
+  virtual void TearDown();
+
+  PluginModule* module() const { return module_.get(); }
+  PepperPluginInstanceImpl* instance() const { return instance_.get(); }
+
+  // Provides access to the interfaces implemented by the test. The default one
+  // implements PPP_INSTANCE.
+  virtual const void* GetMockInterface(const char* interface_name) const;
+
+  // Deletes the instance and module to simulate module shutdown.
+  void ShutdownModule();
+
+  // Sets the view size of the plugin instance.
+  void SetViewSize(int width, int height) const;
+
+ private:
+  // Note: module must be declared first since we want it to get destroyed last.
+  scoped_refptr<PluginModule> module_;
+  scoped_refptr<PepperPluginInstanceImpl> instance_;
+
+  scoped_ptr<base::MessageLoop> message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(PpapiUnittest);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_TEST_PPAPI_UNITTEST_H_
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index d801f6b..ff77335 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -17,7 +17,6 @@
 #include "content/public/browser/notification_types.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/page_transition_types.h"
-#include "content/public/common/password_form.h"
 #include "content/public/test/mock_render_process_host.h"
 
 namespace content {
@@ -78,7 +77,6 @@
   params.should_update_history = false;
   params.searchable_form_url = GURL();
   params.searchable_form_encoding = std::string();
-  params.password_form = PasswordForm();
   params.security_info = std::string();
   params.gesture = NavigationGestureUser;
   params.was_within_same_page = false;
diff --git a/content/test/webrtc_audio_device_test.cc b/content/test/webrtc_audio_device_test.cc
index c258caf..eb2f1c7 100644
--- a/content/test/webrtc_audio_device_test.cc
+++ b/content/test/webrtc_audio_device_test.cc
@@ -252,9 +252,11 @@
       media_internals_.get(), media_stream_manager_.get());
   audio_render_host_->OnChannelConnected(base::GetCurrentProcId());
 
-  audio_input_renderer_host_ = new AudioInputRendererHost(
-      audio_manager_.get(), media_stream_manager_.get(),
-      mirroring_manager_.get());
+  audio_input_renderer_host_ =
+      new AudioInputRendererHost(audio_manager_.get(),
+                                 media_stream_manager_.get(),
+                                 mirroring_manager_.get(),
+                                 NULL);
   audio_input_renderer_host_->OnChannelConnected(base::GetCurrentProcId());
 
   channel_.reset(new IPC::Channel(name, IPC::Channel::MODE_SERVER, this));
diff --git a/content/test/webui_resource_browsertest.cc b/content/test/webui_resource_browsertest.cc
new file mode 100644
index 0000000..317d519
--- /dev/null
+++ b/content/test/webui_resource_browsertest.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 "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/test/browser_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 "grit/content_resources.h"
+#include "net/base/net_util.h"
+
+namespace content {
+
+class WebUIResourceBrowserTest : public ContentBrowserTest {
+ public:
+  WebUIResourceBrowserTest() {}
+  virtual ~WebUIResourceBrowserTest() {}
+
+  // Runs all test functions in |file|, waiting for them to complete.
+  void RunTest(const base::FilePath& file) {
+    ASSERT_TRUE(PathExists(file));
+    NavigateToURL(shell(), net::FilePathToFileURL(file));
+
+    RenderViewHost* rvh = shell()->web_contents()->GetRenderViewHost();
+    ASSERT_TRUE(rvh);
+    EXPECT_TRUE(ExecuteWebUIResourceTest(rvh, include_libraries_));
+  }
+
+  void RunMediaInternalsTest(const base::FilePath::CharType* file) {
+    AddLibrary(IDR_MEDIA_INTERNALS_NEW_JS);
+
+    base::FilePath path;
+    PathService::Get(DIR_TEST_DATA, &path);
+    RunTest(path.Append(FILE_PATH_LITERAL("media"))
+        .Append(FILE_PATH_LITERAL("webui"))
+        .Append(file));
+  }
+
+  // Queues the library corresponding to |resource_id| for injection into the
+  // test. The code injection is performed post-load, so any common test
+  // initialization that depends on the library should be placed in a setUp
+  // function.
+  void AddLibrary(int resource_id) {
+    include_libraries_.push_back(resource_id);
+  }
+
+ private:
+  // Resource IDs for internal javascript libraries to inject into the test.
+  std::vector<int> include_libraries_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebUIResourceBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MediaInternals_Integration) {
+  RunMediaInternalsTest(FILE_PATH_LITERAL("integration_test.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MediaInternals_PlayerInfo) {
+  RunMediaInternalsTest(FILE_PATH_LITERAL("player_info_test.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MediaInternals_PlayerManager) {
+  RunMediaInternalsTest(FILE_PATH_LITERAL("player_manager_test.html"));
+}
+
+}  // namespace content
diff --git a/content/utility/utility_main_thread.cc b/content/utility/utility_main_thread.cc
new file mode 100644
index 0000000..7d97399
--- /dev/null
+++ b/content/utility/utility_main_thread.cc
@@ -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.
+
+#include "content/utility/utility_main_thread.h"
+
+#include "content/child/child_process.h"
+#include "content/utility/utility_thread_impl.h"
+
+namespace content {
+
+// We want to ensure there's only one utility thread running at a time, as there
+// are many globals used in the utility process.
+static base::LazyInstance<base::Lock> g_one_utility_thread_lock;
+
+UtilityMainThread::UtilityMainThread(const std::string& channel_id)
+    : Thread("Chrome_InProcUtilityThread"), channel_id_(channel_id) {
+}
+
+UtilityMainThread::~UtilityMainThread() {
+  Stop();
+}
+
+void UtilityMainThread::Init() {
+  // We need to return right away or else the main thread that started us will
+  // hang.
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&UtilityMainThread::InitInternal, base::Unretained(this)));
+}
+
+void UtilityMainThread::CleanUp() {
+  child_process_.reset();
+
+  // See comment in RendererMainThread.
+  SetThreadWasQuitProperly(true);
+  g_one_utility_thread_lock.Get().Release();
+}
+
+void UtilityMainThread::InitInternal() {
+  g_one_utility_thread_lock.Get().Acquire();
+  child_process_.reset(new ChildProcess());
+  child_process_->set_main_thread(new UtilityThreadImpl(channel_id_));
+}
+
+base::Thread* CreateUtilityMainThread(const std::string& channel_id) {
+  return new UtilityMainThread(channel_id);
+}
+
+}  // namespace content
diff --git a/content/utility/utility_main_thread.h b/content/utility/utility_main_thread.h
new file mode 100644
index 0000000..43e22b7
--- /dev/null
+++ b/content/utility/utility_main_thread.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_UTILITY_UTILITY_MAIN_THREAD_H_
+#define CONTENT_UTILITY_UTILITY_MAIN_THREAD_H_
+
+#include <string>
+
+#include "base/threading/thread.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class ChildProcess;
+
+class UtilityMainThread : public base::Thread {
+ public:
+  UtilityMainThread(const std::string& channel_id);
+  virtual ~UtilityMainThread();
+ private:
+
+  // base::Thread implementation:
+  virtual void Init() OVERRIDE;
+  virtual void CleanUp() OVERRIDE;
+
+  void InitInternal();
+
+  std::string channel_id_;
+  scoped_ptr<ChildProcess> child_process_;
+
+  DISALLOW_COPY_AND_ASSIGN(UtilityMainThread);
+};
+
+CONTENT_EXPORT base::Thread* CreateUtilityMainThread(
+    const std::string& channel_id);
+
+}  // namespace content
+
+#endif  // CONTENT_UTILITY_UTILITY_MAIN_THREAD_H_
diff --git a/content/worker/websharedworkerclient_proxy.cc b/content/worker/websharedworkerclient_proxy.cc
index a2c8c4f..ec2e264 100644
--- a/content/worker/websharedworkerclient_proxy.cc
+++ b/content/worker/websharedworkerclient_proxy.cc
@@ -7,9 +7,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
-#include "content/child/fileapi/file_system_dispatcher.h"
-#include "content/child/fileapi/webfilesystem_callback_adapters.h"
-#include "content/child/quota_dispatcher.h"
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/worker_messages.h"
 #include "content/public/common/content_switches.h"
@@ -21,7 +18,6 @@
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebFileSystemCallbacks.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 
@@ -161,18 +157,6 @@
   return result;
 }
 
-void WebSharedWorkerClientProxy::openFileSystem(
-    WebKit::WebFileSystemType type,
-    long long size,
-    bool create,
-    WebKit::WebFileSystemCallbacks* callbacks) {
-  ChildThread::current()->file_system_dispatcher()->OpenFileSystem(
-      stub_->url().GetOrigin(), static_cast<fileapi::FileSystemType>(type),
-      size, create,
-      base::Bind(&OpenFileSystemCallbackAdapter, callbacks),
-      base::Bind(&FileStatusCallbackAdapter, callbacks));
-}
-
 bool WebSharedWorkerClientProxy::allowIndexedDB(const WebKit::WebString& name) {
   bool result = false;
   Send(new WorkerProcessHostMsg_AllowIndexedDB(
@@ -180,14 +164,6 @@
   return result;
 }
 
-void WebSharedWorkerClientProxy::queryUsageAndQuota(
-    WebKit::WebStorageQuotaType type,
-    WebKit::WebStorageQuotaCallbacks* callbacks) {
-  ChildThread::current()->quota_dispatcher()->QueryStorageUsageAndQuota(
-      stub_->url().GetOrigin(), static_cast<quota::StorageType>(type),
-      QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
-}
-
 void WebSharedWorkerClientProxy::dispatchDevToolsMessage(
     const WebString& message) {
   if (devtools_agent_)
diff --git a/content/worker/websharedworkerclient_proxy.h b/content/worker/websharedworkerclient_proxy.h
index 9035c97..39d1203 100644
--- a/content/worker/websharedworkerclient_proxy.h
+++ b/content/worker/websharedworkerclient_proxy.h
@@ -8,11 +8,7 @@
 #include "base/basictypes.h"
 #include "base/memory/weak_ptr.h"
 #include "ipc/ipc_channel.h"
-#include "third_party/WebKit/public/platform/WebFileSystem.h"
-#include "third_party/WebKit/public/platform/WebFileSystemType.h"
 #include "third_party/WebKit/public/web/WebSharedWorkerClient.h"
-#include "third_party/WebKit/public/web/WebStorageQuotaCallbacks.h"
-#include "third_party/WebKit/public/web/WebStorageQuotaType.h"
 
 namespace WebKit {
 class WebApplicationCacheHost;
@@ -77,14 +73,7 @@
                              const WebKit::WebString& display_name,
                              unsigned long estimated_size);
   virtual bool allowFileSystem();
-  virtual void openFileSystem(
-                              WebKit::WebFileSystemType type,
-                              long long size,
-                              bool create,
-                              WebKit::WebFileSystemCallbacks* callbacks);
   virtual bool allowIndexedDB(const WebKit::WebString&);
-  virtual void queryUsageAndQuota(WebKit::WebStorageQuotaType,
-                                  WebKit::WebStorageQuotaCallbacks*);
   virtual void dispatchDevToolsMessage(const WebKit::WebString&);
   virtual void saveDevToolsAgentState(const WebKit::WebString&);
 
diff --git a/content/worker/worker_webkitplatformsupport_impl.cc b/content/worker/worker_webkitplatformsupport_impl.cc
index 144db95..3cc4c81 100644
--- a/content/worker/worker_webkitplatformsupport_impl.cc
+++ b/content/worker/worker_webkitplatformsupport_impl.cc
@@ -86,6 +86,7 @@
 }
 
 WorkerWebKitPlatformSupportImpl::~WorkerWebKitPlatformSupportImpl() {
+  WebFileSystemImpl::DeleteThreadSpecificInstance();
 }
 
 WebClipboard* WorkerWebKitPlatformSupportImpl::clipboard() {
@@ -98,9 +99,7 @@
 }
 
 WebFileSystem* WorkerWebKitPlatformSupportImpl::fileSystem() {
-  if (!web_file_system_)
-    web_file_system_.reset(new WebFileSystemImpl(child_thread_loop_.get()));
-  return web_file_system_.get();
+  return WebFileSystemImpl::ThreadSpecificInstance(child_thread_loop_.get());
 }
 
 WebFileUtilities* WorkerWebKitPlatformSupportImpl::fileUtilities() {
@@ -282,15 +281,6 @@
   return ASCIIToUTF16(mime_type);
 }
 
-WebString WorkerWebKitPlatformSupportImpl::preferredExtensionForMIMEType(
-    const WebString& mime_type) {
-  base::FilePath::StringType file_extension;
-  thread_safe_sender_->Send(
-      new MimeRegistryMsg_GetPreferredExtensionForMimeType(
-          UTF16ToASCII(mime_type), &file_extension));
-  return base::FilePath(file_extension).AsUTF16Unsafe();
-}
-
 WebBlobRegistry* WorkerWebKitPlatformSupportImpl::blobRegistry() {
   if (!blob_registry_.get() && thread_safe_sender_.get())
     blob_registry_.reset(new WebBlobRegistryImpl(thread_safe_sender_.get()));
diff --git a/content/worker/worker_webkitplatformsupport_impl.h b/content/worker/worker_webkitplatformsupport_impl.h
index a85d574..d429822 100644
--- a/content/worker/worker_webkitplatformsupport_impl.h
+++ b/content/worker/worker_webkitplatformsupport_impl.h
@@ -98,8 +98,6 @@
   virtual WebKit::WebString wellKnownMimeTypeForExtension(
       const WebKit::WebString&);
   virtual WebKit::WebString mimeTypeFromFile(const WebKit::WebString&);
-  virtual WebKit::WebString preferredExtensionForMIMEType(
-      const WebKit::WebString&);
   virtual void queryStorageUsageAndQuota(
       const WebKit::WebURL& storage_partition,
       WebKit::WebStorageQuotaType,
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc
index abb52ae..4b83444 100644
--- a/content/zygote/zygote_linux.cc
+++ b/content/zygote/zygote_linux.cc
@@ -99,6 +99,17 @@
   }
 }
 
+bool Zygote::GetProcessInfo(base::ProcessHandle pid,
+                            ZygoteProcessInfo* process_info) {
+  DCHECK(process_info);
+  const ZygoteProcessMap::const_iterator it = process_info_map_.find(pid);
+  if (it == process_info_map_.end()) {
+    return false;
+  }
+  *process_info = it->second;
+  return true;
+}
+
 bool Zygote::UsingSUIDSandbox() const {
   return sandbox_flags_ & kSandboxLinuxSUID;
 }
@@ -155,47 +166,63 @@
   return false;
 }
 
+// TODO(jln): remove callers to this broken API. See crbug.com/274855.
 void Zygote::HandleReapRequest(int fd,
                                const Pickle& pickle,
                                PickleIterator iter) {
   base::ProcessId child;
-  base::ProcessId actual_child;
 
   if (!pickle.ReadInt(&iter, &child)) {
     LOG(WARNING) << "Error parsing reap request from browser";
     return;
   }
 
-  if (UsingSUIDSandbox()) {
-    actual_child = real_pids_to_sandbox_pids[child];
-    if (!actual_child)
-      return;
-    real_pids_to_sandbox_pids.erase(child);
-  } else {
-    actual_child = child;
-  }
-
-  base::EnsureProcessTerminated(actual_child);
-}
-
-void Zygote::HandleGetTerminationStatus(int fd,
-                                        const Pickle& pickle,
-                                        PickleIterator iter) {
-  bool known_dead;
-  base::ProcessHandle child;
-
-  if (!pickle.ReadBool(&iter, &known_dead) ||
-      !pickle.ReadInt(&iter, &child)) {
-    LOG(WARNING) << "Error parsing GetTerminationStatus request "
-                 << "from browser";
+  ZygoteProcessInfo child_info;
+  if (!GetProcessInfo(child, &child_info)) {
+    LOG(ERROR) << "Child not found!";
+    NOTREACHED();
     return;
   }
 
-  base::TerminationStatus status;
-  int exit_code;
-  if (UsingSUIDSandbox())
-    child = real_pids_to_sandbox_pids[child];
-  if (child) {
+  if (!child_info.started_from_helper) {
+    // TODO(jln): this old code is completely broken. See crbug.com/274855.
+    base::EnsureProcessTerminated(child_info.internal_pid);
+  } else {
+    // For processes from the helper, send a GetTerminationStatus request
+    // with known_dead set to true.
+    // This is not perfect, as the process may be killed instantly, but is
+    // better than ignoring the request.
+    base::TerminationStatus status;
+    int exit_code;
+    bool got_termination_status =
+        GetTerminationStatus(child, true /* known_dead */, &status, &exit_code);
+    DCHECK(got_termination_status);
+  }
+  process_info_map_.erase(child);
+}
+
+bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid,
+                                  bool known_dead,
+                                  base::TerminationStatus* status,
+                                  int* exit_code) {
+
+  ZygoteProcessInfo child_info;
+  if (!GetProcessInfo(real_pid, &child_info)) {
+    LOG(ERROR) << "Zygote::GetTerminationStatus for unknown PID "
+               << real_pid;
+    NOTREACHED();
+    return false;
+  }
+  // We know about |real_pid|.
+  const base::ProcessHandle child = child_info.internal_pid;
+  if (child_info.started_from_helper) {
+    // Let the helper handle the request.
+    DCHECK(helper_);
+    if (!helper_->GetTerminationStatus(child, known_dead, status, exit_code)) {
+      return false;
+    }
+  } else {
+    // Handle the request directly.
     if (known_dead) {
       // If we know that the process is already dead and the kernel is cleaning
       // it up, we do want to wait until it becomes a zombie and not risk
@@ -206,13 +233,43 @@
       if (kill(child, SIGKILL)) {
         PLOG(ERROR) << "kill (" << child << ")";
       }
-      status = base::WaitForTerminationStatus(child, &exit_code);
+      *status = base::WaitForTerminationStatus(child, exit_code);
     } else {
-      status = base::GetTerminationStatus(child, &exit_code);
+      // We don't know if the process is dying, so get its status but don't
+      // wait.
+      *status = base::GetTerminationStatus(child, exit_code);
     }
-  } else {
+  }
+  // Successfully got a status for |real_pid|.
+  if (*status != base::TERMINATION_STATUS_STILL_RUNNING) {
+    // Time to forget about this process.
+    process_info_map_.erase(real_pid);
+  }
+  return true;
+}
+
+void Zygote::HandleGetTerminationStatus(int fd,
+                                        const Pickle& pickle,
+                                        PickleIterator iter) {
+  bool known_dead;
+  base::ProcessHandle child_requested;
+
+  if (!pickle.ReadBool(&iter, &known_dead) ||
+      !pickle.ReadInt(&iter, &child_requested)) {
+    LOG(WARNING) << "Error parsing GetTerminationStatus request "
+                 << "from browser";
+    return;
+  }
+
+  base::TerminationStatus status;
+  int exit_code;
+
+  bool got_termination_status =
+      GetTerminationStatus(child_requested, known_dead, &status, &exit_code);
+  if (!got_termination_status) {
     // Assume that if we can't find the child in the sandbox, then
     // it terminated normally.
+    NOTREACHED();
     status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
     exit_code = RESULT_CODE_NORMAL_EXIT;
   }
@@ -236,10 +293,6 @@
                                                        uma_name,
                                                        uma_sample,
                                                        uma_boundary_value));
-  if (!(use_helper || UsingSUIDSandbox())) {
-    return fork();
-  }
-
   int dummy_fd;
   ino_t dummy_inode;
   int pipe_fds[2] = { -1, -1 };
@@ -326,10 +379,21 @@
         LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed";
         goto error;
       }
-      real_pids_to_sandbox_pids[real_pid] = pid;
-    }
-    if (use_helper) {
+    } else {
+      // If no SUID sandbox is involved then no pid translation is
+      // necessary.
       real_pid = pid;
+    }
+
+    // Now set-up this process to be tracked by the Zygote.
+    if (process_info_map_.find(real_pid) != process_info_map_.end()) {
+      LOG(ERROR) << "Already tracking PID " << real_pid;
+      NOTREACHED();
+    }
+    process_info_map_[real_pid].internal_pid = pid;
+    process_info_map_[real_pid].started_from_helper = use_helper;
+
+    if (use_helper) {
       if (!helper_->AckChild(pipe_fds[1], channel_switch)) {
         LOG(ERROR) << "Failed to synchronise with zygote fork helper";
         goto error;
diff --git a/content/zygote/zygote_linux.h b/content/zygote/zygote_linux.h
index 3b175ac..c39bfd0 100644
--- a/content/zygote/zygote_linux.h
+++ b/content/zygote/zygote_linux.h
@@ -8,7 +8,8 @@
 #include <string>
 #include <vector>
 
-#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+#include "base/process/kill.h"
 #include "base/process/process.h"
 
 class Pickle;
@@ -33,6 +34,22 @@
   static const int kMagicSandboxIPCDescriptor = 5;
 
  private:
+  struct ZygoteProcessInfo {
+    // Pid from inside the Zygote's PID namespace.
+    base::ProcessHandle internal_pid;
+    // Keeps track of whether or not a process was started from a fork
+    // delegate helper.
+    bool started_from_helper;
+  };
+  typedef base::SmallMap< std::map<base::ProcessHandle, ZygoteProcessInfo> >
+      ZygoteProcessMap;
+
+  // Retrieve a ZygoteProcessInfo from the process_info_map_.
+  // Returns true and write to process_info if |pid| can be found, return
+  // false otherwise.
+  bool GetProcessInfo(base::ProcessHandle pid,
+                      ZygoteProcessInfo* process_info);
+
   // Returns true if the SUID sandbox is active.
   bool UsingSUIDSandbox() const;
 
@@ -45,6 +62,14 @@
 
   void HandleReapRequest(int fd, const Pickle& pickle, PickleIterator iter);
 
+  // Get the termination status of |real_pid|. |real_pid| is the PID as it
+  // appears outside of the sandbox.
+  // Return true if it managed to get the termination status and return the
+  // status in |status| and the exit code in |exit_code|.
+  bool GetTerminationStatus(base::ProcessHandle real_pid, bool known_dead,
+                            base::TerminationStatus* status,
+                            int* exit_code);
+
   void HandleGetTerminationStatus(int fd,
                                   const Pickle& pickle,
                                   PickleIterator iter);
@@ -84,11 +109,11 @@
                               const Pickle& pickle,
                               PickleIterator iter);
 
-  // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs
-  // fork() returns are not the real PIDs, so we need to map the Real PIDS
-  // into the sandbox PID namespace.
-  typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap;
-  ProcessMap real_pids_to_sandbox_pids;
+  // The Zygote needs to keep some information about each process. Most
+  // notably what the PID of the process is inside the PID namespace of
+  // the Zygote and whether or not a process was started by the
+  // ZygoteForkDelegate helper.
+  ZygoteProcessMap process_info_map_;
 
   const int sandbox_flags_;
   ZygoteForkDelegate* helper_;
diff --git a/courgette/analyze_mem_test b/courgette/analyze_mem_test
new file mode 100755
index 0000000..9470fa2
--- /dev/null
+++ b/courgette/analyze_mem_test
@@ -0,0 +1,96 @@
+#!/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.
+
+# Produce memory metrics for run_apply_test
+
+error() {
+  echo "error: ${@}" >&2
+}
+
+compute_percentiles() {
+  if [ -z "${1}" ]; then
+    return;
+  fi
+  local pctls=".5 .9 1"
+  local lines=$(cat ${1} | wc -l)
+  for p in $pctls; do
+    local count="$(echo "${lines} * $p" | bc -lq | cut -d. -f1)"
+    local bytes=$(cat ${1} \
+      | cut -d' ' -f2 \
+      | sort -n \
+      | head -n$count \
+      | tail -n1)
+    echo -n "$((bytes / 1000000))MB "
+  done
+}
+
+main() {
+  if [ $# -lt 1 ]; then
+    cat <<EOF
+
+USAGE: $(basename ${0}) dir
+
+Produce memory metrics for run_apply_test.  This shows the percentiles
+of the max heap size across all files.
+
+EOF
+    exit 1
+  fi
+
+  local dir="${1}"
+  if [ ! -d "${dir}" ]; then
+    error "\"${dir}\" not found" exit 1
+  fi
+
+  local metrics_dir="${dir}/metrics"
+  local metrics="${dir}/mem_per_file.txt"
+
+  if [ ! -f "${metrics}" ]; then
+    local metrics_tmp="${metrics}.tmp"
+    echo "computing usage percentiles for courgette.  this may take a while..."
+    find "${metrics_dir}" \
+      | grep "\.apply_mem$" \
+      | while read i; do
+      local apply_mem="${i}"
+      local unbz2_mem="${apply_mem%.apply_mem}.unbz2_mem"
+      local unxz_mem="${apply_mem%.apply_mem}.unxz_mem"
+      echo -n "$apply_mem "
+      cat "${apply_mem}" "${unbz2_mem}" "${unxz_mem}" \
+        | grep "mem_heap_B" \
+        | cut -d= -f2 \
+        | sort -nr \
+        | head -n1
+    done | sort -k2 -n > "${metrics_tmp}"
+    mv "${metrics_tmp}" "${metrics}"
+  fi
+
+  echo "$(compute_percentiles ${metrics})max heap per file for Courgette" \
+    "(50th 90th 100th)"
+
+  local metrics_bsdiff="${dir}/mem_per_file_bsdiff.txt"
+
+  if [ ! -f "${metrics_bsdiff}" ]; then
+    local metrics_bsdiff_tmp="${metrics_bsdiff}.tmp"
+    echo "computing usage percentiles for bsdiff.  this may take a while..."
+    find "${metrics_dir}" \
+      | grep "\.bsdiff_mem$" \
+      | while read i; do
+      local bsdiff_mem="${i}"
+      echo -n "$bsdiff_mem "
+      cat $bsdiff_mem \
+        | grep "mem_heap_B" \
+        | cut -d= -f2 \
+        | sort -nr \
+        | head -n1
+    done | sort -k2 -n > "${metrics_bsdiff_tmp}"
+    mv "${metrics_bsdiff_tmp}" "${metrics_bsdiff}"
+  fi
+
+  echo "$(compute_percentiles ${metrics_bsdiff})max heap per file for bsdiff" \
+    "(50th 90th 100th)"
+}
+
+main "${@}"
diff --git a/courgette/analyze_stress_test b/courgette/analyze_stress_test
index 6aff656..338eb6e 100755
--- a/courgette/analyze_stress_test
+++ b/courgette/analyze_stress_test
@@ -22,6 +22,24 @@
   fi
 }
 
+# Given a token, search for and compute the percentiles from logfile.
+compute_percentiles() {
+  if [ ! -z "${1}" ]; then
+    local pctls=".5 .9 1"
+    local lines=$(count_result ${1})
+    for p in $pctls; do
+      local count="$(echo "${lines} * $p" | bc -lq | cut -d. -f1)"
+      echo -n $(cat ${log} \
+        | grep ${1} \
+        | cut -d' ' -f2 \
+        | sort -n \
+        | head -n$count \
+        | tail -n1)
+      echo -n "s "
+    done
+  fi
+}
+
 main() {
   if [ $# -lt 1 ]; then
     cat <<EOF
@@ -46,9 +64,12 @@
 $(count_result "FAIL_DISASSEMBLE") failed to disassemble/assemble
 $(count_result "PASS_BSDIFF") succesful bsdiff patches
 $(count_result "FAIL_BSDIFF") failed bsdiff patches
-$(count_result "BEST_COURGETTE") patch(es) where courgette is smaller
-$(count_result "BEST_BSDIFF") patch(es) where bsdiff is smaller
-$(count_result "BEST_TIE") patch(es) where both are the same size
+$(count_result "BEST_COURGETTE") patch(es) where courgette is smaller (bz2)
+$(count_result "BEST_BSDIFF") patch(es) where bsdiff is smaller (xz)
+$(count_result "BEST_TIE") patch(es) where both are the same size (bz2)
+$(count_result "XZBEST_COURGETTE") patch(es) where courgette (xz) is smaller
+$(count_result "XZBEST_BSDIFF") patch(es) where bsdiff is smaller (xz)
+$(count_result "XZBEST_TIE") patch(es) where both are the same size (xz)
 EOF
 
   # Log file has the format "^SIZE courgette=... bsdiff=..."
@@ -56,7 +77,13 @@
     | grep "^SIZE " \
     | cut -d' ' -f2 \
     | awk -F= 'BEGIN{sum=0} {sum += $2} END{print sum}')"
-  echo "${courgette_total} bytes for a courgette payload"
+  echo "${courgette_total} bytes for a courgette payload (bz2)"
+
+  local courgette_total_xz="$(cat "${log}" \
+    | grep "^SIZE " \
+    | cut -d' ' -f4 \
+    | awk -F= 'BEGIN{sum=0} {sum += $2} END{print sum}')"
+  echo "${courgette_total_xz} bytes for a courgette payload (xz)"
 
   local bsdiff_total="$(cat "${log}" \
     | grep "^SIZE " \
@@ -67,20 +94,43 @@
   local best_total="$(cat "${log}" \
     | grep "^BEST_" \
     | awk 'BEGIN{sum=0} {sum += $2} END{print sum}')"
-    echo "${best_total} bytes for a best-choice payload"
+    echo "${best_total} bytes for a best-choice payload (bz2)"
+
+  local best_total_xz="$(cat "${log}" \
+    | grep "^XZBEST_" \
+    | awk 'BEGIN{sum=0} {sum += $2} END{print sum}')"
+    echo "${best_total_xz} bytes for a best-choice payload (xz)"
 
   local pct="$(echo "100*${best_total}/${bsdiff_total}" \
     | bc -lq \
     | awk '{printf "%.2f\n", $0}')"
-    echo "${pct}% of a bsdiff-only payload"
+    echo "${pct}% of a bsdiff-only payload (bz2)"
+
+  local pct="$(echo "100*${best_total_xz}/${bsdiff_total}" \
+    | bc -lq \
+    | awk '{printf "%.2f\n", $0}')"
+    echo "${pct}% of a bsdiff-only payload (xz)"
 
   local savings="$((bsdiff_total - best_total))"
-  echo "${savings} bytes saved by courgette"
+  echo "${savings} bytes saved by courgette (bz2)"
+
+  local savings_xz="$((bsdiff_total - best_total_xz))"
+  echo "${savings} bytes saved by courgette (xz)"
 
   local pct_savings="$(echo "100*${savings}/${bsdiff_total}" \
     | bc -lq \
     | awk '{printf "%.2f\n", $0}')"
-  echo "${pct_savings}% savings"
+  echo "${pct_savings}% savings (bz2)"
+
+  local pct_savings="$(echo "100*${savings_xz}/${bsdiff_total}" \
+    | bc -lq \
+    | awk '{printf "%.2f\n", $0}')"
+  echo "${pct_savings}% savings (xz)"
+
+  echo "$(compute_percentiles "TIME_GEN")to generate a patch (50th 90th 100th)"
+  echo "$(compute_percentiles "TIME_APPLY")to apply a patch (50th 90th 100th)"
+  echo "$(compute_percentiles "TIME_BSDIFF")for bsdiff (50th 90th 100th)"
+  echo "$(compute_percentiles "TIME_BSPATCH")for bspatch (50th 90th 100th)"
 }
 
 main "${@}"
diff --git a/courgette/courgette.gyp b/courgette/courgette.gyp
index d6d4c15..5bed905 100644
--- a/courgette/courgette.gyp
+++ b/courgette/courgette.gyp
@@ -203,5 +203,32 @@
         },
       ],
     }],
+    # The build infrastructure needs courgette to be named courgette64.
+    ['OS=="win" and target_arch=="x64"', {
+      'targets': [
+        {
+          'target_name': 'courgette64',
+          'type': 'none',
+          'dependencies': [
+            'courgette',
+          ],
+          'actions': [{
+            'action_name': 'courgette64',
+            'inputs': [
+              '<(PRODUCT_DIR)/courgette.exe',
+            ],
+            'outputs': [
+              '<(PRODUCT_DIR)/courgette64.exe',
+            ],
+            'action': [
+              'python',
+              '../build/cp.py',
+              '<@(_inputs)',
+              '<@(_outputs)'
+            ],
+          }],
+        },
+      ],
+    }],
   ],
 }
diff --git a/courgette/run_mem_test b/courgette/run_mem_test
new file mode 100755
index 0000000..07a8e5b
--- /dev/null
+++ b/courgette/run_mem_test
@@ -0,0 +1,69 @@
+#!/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.
+
+# Collect memory usage on the patches from run_stress_test
+
+error() {
+  echo "error: ${@}" >&2
+}
+
+main() {
+  if [ $# -lt 1 ]; then
+    cat <<EOF
+
+USAGE: $(basename ${0}) dir
+
+Collect memory usage on the patches from run_stress_test
+
+EOF
+    exit 1
+  fi
+
+  local dir="${1}"
+  if [ ! -d "${dir}" ]; then
+    error "\"${dir}\" not found"
+    exit 1
+  fi
+
+  local patches_dir="${dir}/patches"
+
+  find "${patches_dir}" \
+    | grep "\.patch$" \
+    | while read i; do
+    local patch="${i}"
+    local subdir_filename="${patch:$((${#patches_dir} + 1))}"
+    local out_base="${dir}/metrics/${subdir_filename}"
+    mkdir -p "$(dirname ${out_base})"
+
+    local original="${subdir_filename%.patch}"
+    local applied="${out_base}.applied"
+    local apply_mem="${out_base}.apply_mem"
+    valgrind --tool=massif --massif-out-file="${apply_mem}" courgette -apply \
+      "${original}" "${patch}" "${applied}" &
+
+    local bz2_patch="${i}.bz2"
+    local unbz2="${out_base}.unbz2"
+    local unbz2_mem="${out_base}.unbz2_mem"
+    valgrind --tool=massif --massif-out-file="${unbz2_mem}" bunzip2 -c \
+      "${bz2_patch}" > "${unbz2}" &
+
+    local xz_patch="${i}.xz"
+    local unxz="${out_base}.unxz"
+    local unxz_mem="${out_base}.unxz_mem"
+    valgrind --tool=massif --massif-out-file="${unxz_mem}" unxz -c \
+      "${xz_patch}" > "${unxz}" &
+
+    local bsdiff_patch="${patch%.patch}.bsdiff_patch"
+    local applied_bsdiff="${out_base}.applied_bsdiff"
+    local bsdiff_mem="${out_base}.bsdiff_mem"
+    valgrind --tool=massif --massif-out-file="${bsdiff_mem}" bspatch \
+      "${original}" "${applied_bsdiff}" "${bsdiff_patch}" &
+
+    wait
+  done
+}
+
+main "${@}"
diff --git a/courgette/run_stress_test b/courgette/run_stress_test
index 1110e59..442ad3d 100755
--- a/courgette/run_stress_test
+++ b/courgette/run_stress_test
@@ -11,6 +11,7 @@
 }
 
 outdir_prefix="stress_test_"
+time="/usr/bin/time"
 
 if [ $# -lt 2 ]; then
   cat <<EOF
@@ -90,8 +91,12 @@
     fi
     mkdir -p "$(dirname "${patch}")"
     mkdir -p "$(dirname "${apply}")"
-    courgette -gen "${file1}" "${file2}" "${patch}"
-    courgette -apply "${file1}" "${patch}" "${apply}"
+    echo "courgette -gen"
+    ${time} -f "TIME_GEN %e ${file1}" courgette -gen "${file1}" "${file2}" \
+      "${patch}"
+    echo "courgette -apply"
+    ${time} -f "TIME_APPLY %e ${file1}" courgette -apply "${file1}" "${patch}" \
+      "${apply}"
     cmp -s "${file2}" "${apply}"
     if [ "${?}" -ne 0 ]; then
       echo "FAIL_COURGETTE ${file1}"
@@ -99,17 +104,26 @@
       echo "PASS_COURGETTE ${file1}"
       local bsdiff_patch="${patches_dir}/${file1}.bsdiff_patch"
       local bsdiff_apply="${applied_dir}/${file2}.bsdiff_applied"
-      bsdiff "${file1}" "${file2}" "${bsdiff_patch}"
-      bspatch "${file1}" "${bsdiff_apply}" "${bsdiff_patch}"
+      echo "RUN bsdiff"
+      ${time} -f "TIME_BSDIFF %e ${file1}" bsdiff "${file1}" "${file2}" \
+        "${bsdiff_patch}"
+      echo "RUN bspatch"
+      ${time} -f "TIME_BSPATCH %e ${file1}" bspatch "${file1}" \
+        "${bsdiff_apply}" "${bsdiff_patch}"
       cmp -s "${file2}" "${bsdiff_apply}"
       if [ "${?}" -ne 0 ]; then
         echo "FAIL_BSDIFF ${file1}"
       else
         echo "PASS_BSDIFF ${file1}"
-        bzip2 -k -9 "${patch}"
-        local patch_size="$(du -b "${patch}.bz2" | cut -f1)"
+        local bz2_patch="${patch}.bz2"
+        local xz_patch="${patch}.xz"
+        bzip2 -9 -c "${patch}" > "${bz2_patch}"
+        xz -9 -c "${patch}" > "${xz_patch}"
+        local patch_size="$(du -b "${bz2_patch}" | cut -f1)"
         local bsdiff_patch_size="$(du -b "${bsdiff_patch}" | cut -f1)"
-        echo "SIZE courgette=${patch_size} bsdiff=${bsdiff_patch_size} ${file1}"
+        local xz_patch_size="$(du -b "${xz_patch}" | cut -f1)"
+        echo "SIZE courgette=${patch_size} bsdiff=${bsdiff_patch_size}" \
+          "courgette_xz=${xz_patch_size} ${file1}"
         if [ "${patch_size}" -eq "${bsdiff_patch_size}" ]; then
           echo "BEST_TIE ${patch_size} ${file1}"
         elif [ "${patch_size}" -lt "${bsdiff_patch_size}" ]; then
@@ -117,6 +131,13 @@
         elif [ "${patch_size}" -gt "${bsdiff_patch_size}" ]; then
           echo "BEST_BSDIFF ${bsdiff_patch_size} ${file1}"
         fi
+        if [ "${xz_patch_size}" -eq "${bsdiff_patch_size}" ]; then
+          echo "XZBEST_TIE ${xz_patch_size} ${file1}"
+        elif [ "${xz_patch_size}" -lt "${bsdiff_patch_size}" ]; then
+          echo "XZBEST_COURGETTE ${xz_patch_size} ${file1}"
+        elif [ "${xz_patch_size}" -gt "${bsdiff_patch_size}" ]; then
+          echo "XZBEST_BSDIFF ${bsdiff_patch_size} ${file1}"
+        fi
       fi
     fi
   fi
@@ -158,7 +179,10 @@
 for "^FAIL_DISASSEMBLE")
 $(count_result "PASS_BSDIFF") succesful bsdiff patches
 $(count_result "FAIL_BSDIFF") failed bsdiff patches
-$(count_result "BEST_COURGETTE") patch(es) where courgette is smaller
-$(count_result "BEST_BSDIFF") patch(es) where bsdiff is smaller
-$(count_result "BEST_TIE") patch(es) where both are the same size
+$(count_result "BEST_COURGETTE") patch(es) where courgette (bz2) is smaller
+$(count_result "BEST_BSDIFF") patch(es) where bsdiff is smaller (bz2)
+$(count_result "BEST_TIE") patch(es) where both are the same size (bz2)
+$(count_result "XZBEST_COURGETTE") patch(es) where courgette (xz) is smaller
+$(count_result "XZBEST_BSDIFF") patch(es) where bsdiff is smaller (xz)
+$(count_result "XZBEST_TIE") patch(es) where both are the same size (xz)
 EOF
diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc
index 95aab89..ea76fd7 100644
--- a/dbus/object_proxy.cc
+++ b/dbus/object_proxy.cc
@@ -612,8 +612,12 @@
 
 void ObjectProxy::UpdateNameOwnerAndBlock() {
   bus_->AssertOnDBusThread();
+  // Errors should be suppressed here, as the service may not be yet running
+  // when connecting to signals of the service, which is just fine.
+  // The ObjectProxy will be notified when the service is launched via
+  // NameOwnerChanged signal. See also comments in ConnectToSignalInternal().
   service_name_owner_ =
-      bus_->GetServiceOwnerAndBlock(service_name_, Bus::REPORT_ERRORS);
+      bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
 }
 
 DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
diff --git a/extensions/common/features/feature.cc b/extensions/common/features/feature.cc
new file mode 100644
index 0000000..705f3e5
--- /dev/null
+++ b/extensions/common/features/feature.cc
@@ -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.
+
+#include "extensions/common/features/feature.h"
+
+#include <map>
+
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace extensions {
+
+// static
+Feature::Platform Feature::GetCurrentPlatform() {
+#if defined(OS_CHROMEOS)
+  return CHROMEOS_PLATFORM;
+#else
+  return UNSPECIFIED_PLATFORM;
+#endif
+}
+
+// static
+Feature::Location Feature::ConvertLocation(Manifest::Location location) {
+  if (location == Manifest::COMPONENT)
+    return COMPONENT_LOCATION;
+  else
+    return UNSPECIFIED_LOCATION;
+}
+
+// static
+Feature::Availability Feature::CreateAvailability(AvailabilityResult result,
+                                                  const std::string& message) {
+  return Availability(result, message);
+}
+
+Feature::Feature() : no_parent_(false) {}
+
+Feature::~Feature() {}
+
+}  // namespace extensions
diff --git a/extensions/common/features/feature.h b/extensions/common/features/feature.h
new file mode 100644
index 0000000..036fc72
--- /dev/null
+++ b/extensions/common/features/feature.h
@@ -0,0 +1,155 @@
+// Copyright 2013 The Chromium Authors. 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_FEATURES_FEATURE_H_
+#define EXTENSIONS_COMMON_FEATURES_FEATURE_H_
+
+#include <set>
+#include <string>
+
+#include "base/values.h"
+#include "extensions/common/manifest.h"
+
+class GURL;
+
+namespace extensions {
+
+class Extension;
+
+// Represents a single feature accessible to an extension developer, such as a
+// top-level manifest key, a permission, or a programmatic API. A feature can
+// express requirements for where it can be accessed, and supports testing
+// support for those requirements.
+class Feature {
+ public:
+  // The JavaScript contexts the feature is supported in.
+  enum Context {
+    UNSPECIFIED_CONTEXT,
+
+    // A context in a privileged extension process.
+    BLESSED_EXTENSION_CONTEXT,
+
+    // A context in an unprivileged extension process.
+    UNBLESSED_EXTENSION_CONTEXT,
+
+    // A context from a content script.
+    CONTENT_SCRIPT_CONTEXT,
+
+    // A normal web page. This should have an associated URL matching pattern.
+    WEB_PAGE_CONTEXT,
+  };
+
+  // The location required of extensions the feature is supported in.
+  enum Location {
+    UNSPECIFIED_LOCATION,
+    COMPONENT_LOCATION
+  };
+
+  // The platforms the feature is supported in.
+  enum Platform {
+    UNSPECIFIED_PLATFORM,
+    CHROMEOS_PLATFORM
+  };
+
+  // Whether a feature is available in a given situation or not, and if not,
+  // why not.
+  enum AvailabilityResult {
+    IS_AVAILABLE,
+    NOT_FOUND_IN_WHITELIST,
+    INVALID_URL,
+    INVALID_TYPE,
+    INVALID_CONTEXT,
+    INVALID_LOCATION,
+    INVALID_PLATFORM,
+    INVALID_MIN_MANIFEST_VERSION,
+    INVALID_MAX_MANIFEST_VERSION,
+    NOT_PRESENT,
+    UNSUPPORTED_CHANNEL,
+  };
+
+  // Container for AvailabiltyResult that also exposes a user-visible error
+  // message in cases where the feature is not available.
+  class Availability {
+   public:
+    AvailabilityResult result() const { return result_; }
+    bool is_available() const { return result_ == IS_AVAILABLE; }
+    const std::string& message() const { return message_; }
+
+   private:
+    friend class SimpleFeature;
+    friend class Feature;
+
+    // Instances should be created via Feature::CreateAvailability.
+    Availability(AvailabilityResult result, const std::string& message)
+        : result_(result), message_(message) { }
+
+    const AvailabilityResult result_;
+    const std::string message_;
+  };
+
+  Feature();
+  virtual ~Feature();
+
+  // Used by ChromeV8Context until the feature system is fully functional.
+  static Availability CreateAvailability(AvailabilityResult result,
+                                         const std::string& message);
+
+  const std::string& name() const { return name_; }
+  void set_name(const std::string& name) { name_ = name; }
+  const std::set<std::string>& dependencies() { return dependencies_; }
+  bool no_parent() const { return no_parent_; }
+
+  // Gets the platform the code is currently running on.
+  static Platform GetCurrentPlatform();
+
+  // Gets the Feature::Location value for the specified Manifest::Location.
+  static Location ConvertLocation(Manifest::Location extension_location);
+
+  virtual std::set<Context>* GetContexts() = 0;
+
+  // Tests whether this is an internal API or not.
+  virtual bool IsInternal() const = 0;
+
+  // Returns true if the feature is available to be parsed into a new extension
+  // manifest.
+  Availability IsAvailableToManifest(const std::string& extension_id,
+                                     Manifest::Type type,
+                                     Location location,
+                                     int manifest_version) const {
+    return IsAvailableToManifest(extension_id, type, location, manifest_version,
+                                 GetCurrentPlatform());
+  }
+  virtual Availability IsAvailableToManifest(const std::string& extension_id,
+                                             Manifest::Type type,
+                                             Location location,
+                                             int manifest_version,
+                                             Platform platform) const = 0;
+
+  // Returns true if the feature is available to be used in the specified
+  // extension and context.
+  Availability IsAvailableToContext(const Extension* extension,
+                                    Context context,
+                                    const GURL& url) const {
+    return IsAvailableToContext(extension, context, url, GetCurrentPlatform());
+  }
+  virtual Availability IsAvailableToContext(const Extension* extension,
+                                            Context context,
+                                            const GURL& url,
+                                            Platform platform) const = 0;
+
+  virtual std::string GetAvailabilityMessage(AvailabilityResult result,
+                                             Manifest::Type type,
+                                             const GURL& url) const = 0;
+
+  virtual bool IsIdInWhitelist(const std::string& extension_id) const = 0;
+
+ protected:
+  std::string name_;
+  std::set<std::string> dependencies_;
+  bool no_parent_;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_COMMON_FEATURES_FEATURE_H_
diff --git a/extensions/common/install_warning.cc b/extensions/common/install_warning.cc
index c632a71..3db5a5b 100644
--- a/extensions/common/install_warning.cc
+++ b/extensions/common/install_warning.cc
@@ -6,19 +6,27 @@
 
 namespace extensions {
 
+InstallWarning::InstallWarning(const std::string& message) : message(message) {
+}
+
+InstallWarning::InstallWarning(const std::string& message,
+                               const std::string& key)
+    : message(message), key(key) {
+}
+
+InstallWarning::InstallWarning(const std::string& message,
+                               const std::string& key,
+                               const std::string& specific)
+    : message(message), key(key), specific(specific) {
+}
+
+InstallWarning::~InstallWarning() {
+}
+
 void PrintTo(const InstallWarning& warning, ::std::ostream* os) {
-  *os << "InstallWarning(";
-  switch (warning.format) {
-    case InstallWarning::FORMAT_TEXT:
-      *os << "FORMAT_TEXT, \"";
-      break;
-    case InstallWarning::FORMAT_HTML:
-      *os << "FORMAT_HTML, \"";
-      break;
-  }
   // This is just for test error messages, so no need to escape '"'
   // characters inside the message.
-  *os << warning.message << "\")";
+  *os << "InstallWarning(\"" << warning.message << "\")";
 }
 
 }  // namespace extensions
diff --git a/extensions/common/install_warning.h b/extensions/common/install_warning.h
index fb3fccb..88dd0a1 100644
--- a/extensions/common/install_warning.h
+++ b/extensions/common/install_warning.h
@@ -10,24 +10,34 @@
 
 namespace extensions {
 
+// A struct to describe a non-fatal issue discovered in the installation of an
+// extension.
 struct InstallWarning {
-  enum Format {
-    // IMPORTANT: Do not build HTML strings from user or developer-supplied
-    // input.
-    FORMAT_TEXT,
-    FORMAT_HTML,
-  };
-  static InstallWarning Text(const std::string& message) {
-    return InstallWarning(FORMAT_TEXT, message);
-  }
-  InstallWarning(Format format, const std::string& message)
-      : format(format), message(message) {
-  }
+  InstallWarning(const std::string& message);
+  InstallWarning(const std::string& message,
+                 const std::string& key);
+  InstallWarning(const std::string& message,
+                 const std::string& key,
+                 const std::string& specific);
+  ~InstallWarning();
+
   bool operator==(const InstallWarning& other) const {
-    return format == other.format && message == other.message;
+    // We don't have to look at |key| or |specific| here, because they are each
+    // used in the the message itself.
+    // For example, a full message would be "Permission 'foo' is unknown or URL
+    // pattern is malformed." |key| here is "permissions", and |specific| is
+    // "foo", but these are redundant with the message.
+    return message == other.message;
   }
-  Format format;
+
+  // The warning's message (human-friendly).
   std::string message;
+  // Optional - for specifying the incorrect key in the manifest (e.g.,
+  // "permissions").
+  std::string key;
+  // Optional - for specifying the incorrect portion of a key in the manifest
+  // (e.g., an unrecognized permission "foo" in "permissions").
+  std::string specific;
 };
 
 // Let gtest print InstallWarnings.
diff --git a/extensions/common/manifest.cc b/extensions/common/manifest.cc
new file mode 100644
index 0000000..eaaaf76
--- /dev/null
+++ b/extensions/common/manifest.cc
@@ -0,0 +1,257 @@
+// Copyright 2013 The Chromium Authors. 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/manifest.h"
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/features/feature_provider.h"
+#include "extensions/common/install_warning.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+
+namespace {
+
+// Rank extension locations in a way that allows
+// Manifest::GetHigherPriorityLocation() to compare locations.
+// An extension installed from two locations will have the location
+// with the higher rank, as returned by this function. The actual
+// integer values may change, and should never be persisted.
+int GetLocationRank(Manifest::Location location) {
+  const int kInvalidRank = -1;
+  int rank = kInvalidRank;  // Will CHECK that rank is not kInvalidRank.
+
+  switch (location) {
+    // Component extensions can not be overriden by any other type.
+    case Manifest::COMPONENT:
+      rank = 7;
+      break;
+
+    // Policy controlled extensions may not be overridden by any type
+    // that is not part of chrome.
+    case Manifest::EXTERNAL_POLICY_DOWNLOAD:
+      rank = 6;
+      break;
+
+    // A developer-loaded extension should override any installed type
+    // that a user can disable. Anything specified on the command-line should
+    // override one loaded via the extensions UI.
+    case Manifest::COMMAND_LINE:
+      rank = 5;
+      break;
+
+    case Manifest::UNPACKED:
+      rank = 4;
+      break;
+
+    // The relative priority of various external sources is not important,
+    // but having some order ensures deterministic behavior.
+    case Manifest::EXTERNAL_REGISTRY:
+      rank = 3;
+      break;
+
+    case Manifest::EXTERNAL_PREF:
+      rank = 2;
+      break;
+
+    case Manifest::EXTERNAL_PREF_DOWNLOAD:
+      rank = 1;
+      break;
+
+    // User installed extensions are overridden by any external type.
+    case Manifest::INTERNAL:
+      rank = 0;
+      break;
+
+    default:
+      NOTREACHED() << "Need to add new extension location " << location;
+  }
+
+  CHECK(rank != kInvalidRank);
+  return rank;
+}
+
+}  // namespace
+
+// static
+Manifest::Location Manifest::GetHigherPriorityLocation(
+    Location loc1, Location loc2) {
+  if (loc1 == loc2)
+    return loc1;
+
+  int loc1_rank = GetLocationRank(loc1);
+  int loc2_rank = GetLocationRank(loc2);
+
+  // If two different locations have the same rank, then we can not
+  // deterministicly choose a location.
+  CHECK(loc1_rank != loc2_rank);
+
+  // Highest rank has highest priority.
+  return (loc1_rank > loc2_rank ? loc1 : loc2 );
+}
+
+Manifest::Manifest(Location location, scoped_ptr<base::DictionaryValue> value)
+    : location_(location),
+      value_(value.Pass()),
+      type_(TYPE_UNKNOWN) {
+  if (value_->HasKey(keys::kTheme)) {
+    type_ = TYPE_THEME;
+  } else if (value_->HasKey(keys::kExport)) {
+    type_ = TYPE_SHARED_MODULE;
+  } else if (value_->HasKey(keys::kApp)) {
+    if (value_->Get(keys::kWebURLs, NULL) ||
+        value_->Get(keys::kLaunchWebURL, NULL)) {
+      type_ = TYPE_HOSTED_APP;
+    } else if (value_->Get(keys::kPlatformAppBackground, NULL)) {
+      type_ = TYPE_PLATFORM_APP;
+    } else {
+      type_ = TYPE_LEGACY_PACKAGED_APP;
+    }
+  } else {
+    type_ = TYPE_EXTENSION;
+  }
+  CHECK_NE(type_, TYPE_UNKNOWN);
+}
+
+Manifest::~Manifest() {
+}
+
+bool Manifest::ValidateManifest(
+    std::string* error,
+    std::vector<InstallWarning>* warnings) const {
+  *error = "";
+
+  // Check every feature to see if its in the manifest. Note that this means
+  // we will ignore keys that are not features; we do this for forward
+  // compatibility.
+  // TODO(aa): Consider having an error here in the case of strict error
+  // checking to let developers know when they screw up.
+
+  FeatureProvider* provider = FeatureProvider::GetByName("manifest");
+  const std::vector<std::string>& feature_names =
+      provider->GetAllFeatureNames();
+  for (std::vector<std::string>::const_iterator feature_name =
+           feature_names.begin();
+       feature_name != feature_names.end(); ++feature_name) {
+    // Use Get instead of HasKey because the former uses path expansion.
+    if (!value_->Get(*feature_name, NULL))
+      continue;
+
+    Feature* feature = provider->GetFeature(*feature_name);
+    Feature::Availability result = feature->IsAvailableToManifest(
+        extension_id_, type_, Feature::ConvertLocation(location_),
+        GetManifestVersion());
+    if (!result.is_available())
+      warnings->push_back(InstallWarning(result.message(), *feature_name));
+  }
+
+  // Also generate warnings for keys that are not features.
+  for (base::DictionaryValue::Iterator it(*value_); !it.IsAtEnd();
+       it.Advance()) {
+    if (!provider->GetFeature(it.key())) {
+      warnings->push_back(InstallWarning(
+          base::StringPrintf("Unrecognized manifest key '%s'.",
+                             it.key().c_str()),
+          it.key()));
+    }
+  }
+  return true;
+}
+
+bool Manifest::HasKey(const std::string& key) const {
+  return CanAccessKey(key) && value_->HasKey(key);
+}
+
+bool Manifest::HasPath(const std::string& path) const {
+  base::Value* ignored = NULL;
+  return CanAccessPath(path) && value_->Get(path, &ignored);
+}
+
+bool Manifest::Get(
+    const std::string& path, const base::Value** out_value) const {
+  return CanAccessPath(path) && value_->Get(path, out_value);
+}
+
+bool Manifest::GetBoolean(
+    const std::string& path, bool* out_value) const {
+  return CanAccessPath(path) && value_->GetBoolean(path, out_value);
+}
+
+bool Manifest::GetInteger(
+    const std::string& path, int* out_value) const {
+  return CanAccessPath(path) && value_->GetInteger(path, out_value);
+}
+
+bool Manifest::GetString(
+    const std::string& path, std::string* out_value) const {
+  return CanAccessPath(path) && value_->GetString(path, out_value);
+}
+
+bool Manifest::GetString(
+    const std::string& path, string16* out_value) const {
+  return CanAccessPath(path) && value_->GetString(path, out_value);
+}
+
+bool Manifest::GetDictionary(
+    const std::string& path, const base::DictionaryValue** out_value) const {
+  return CanAccessPath(path) && value_->GetDictionary(path, out_value);
+}
+
+bool Manifest::GetList(
+    const std::string& path, const base::ListValue** out_value) const {
+  return CanAccessPath(path) && value_->GetList(path, out_value);
+}
+
+Manifest* Manifest::DeepCopy() const {
+  Manifest* manifest = new Manifest(
+      location_, scoped_ptr<base::DictionaryValue>(value_->DeepCopy()));
+  manifest->set_extension_id(extension_id_);
+  return manifest;
+}
+
+bool Manifest::Equals(const Manifest* other) const {
+  return other && value_->Equals(other->value());
+}
+
+int Manifest::GetManifestVersion() const {
+  // Platform apps were launched after manifest version 2 was the preferred
+  // version, so they default to that.
+  int manifest_version = type_ == TYPE_PLATFORM_APP ? 2 : 1;
+  value_->GetInteger(keys::kManifestVersion, &manifest_version);
+  return manifest_version;
+}
+
+bool Manifest::CanAccessPath(const std::string& path) const {
+  std::vector<std::string> components;
+  base::SplitString(path, '.', &components);
+  std::string key;
+  for (size_t i = 0; i < components.size(); ++i) {
+    key += components[i];
+    if (!CanAccessKey(key))
+      return false;
+    key += '.';
+  }
+  return true;
+}
+
+bool Manifest::CanAccessKey(const std::string& key) const {
+  Feature* feature = FeatureProvider::GetByName("manifest")->GetFeature(key);
+  if (!feature)
+    return true;
+
+  return feature->IsAvailableToManifest(
+      extension_id_, type_, Feature::ConvertLocation(location_),
+      GetManifestVersion()).is_available();
+}
+
+}  // namespace extensions
diff --git a/extensions/common/manifest.h b/extensions/common/manifest.h
new file mode 100644
index 0000000..c4ceb38
--- /dev/null
+++ b/extensions/common/manifest.h
@@ -0,0 +1,177 @@
+// Copyright 2013 The Chromium Authors. 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_MANIFEST_H_
+#define EXTENSIONS_COMMON_MANIFEST_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/values.h"
+
+namespace extensions {
+struct InstallWarning;
+
+// Wraps the DictionaryValue form of extension's manifest. Enforces access to
+// properties of the manifest using ManifestFeatureProvider.
+class Manifest {
+ public:
+  // What an extension was loaded from.
+  // NOTE: These values are stored as integers in the preferences and used
+  // in histograms so don't remove or reorder existing items.  Just append
+  // to the end.
+  enum Location {
+    INVALID_LOCATION,
+    INTERNAL,           // A crx file from the internal Extensions directory.
+    EXTERNAL_PREF,      // A crx file from an external directory (via prefs).
+    EXTERNAL_REGISTRY,  // A crx file from an external directory (via eg the
+                        // registry on Windows).
+    UNPACKED,           // From loading an unpacked extension from the
+                        // extensions settings page.
+    COMPONENT,          // An integral component of Chrome itself, which
+                        // happens to be implemented as an extension. We don't
+                        // show these in the management UI.
+    EXTERNAL_PREF_DOWNLOAD,    // A crx file from an external directory (via
+                               // prefs), installed from an update URL.
+    EXTERNAL_POLICY_DOWNLOAD,  // A crx file from an external directory (via
+                               // admin policies), installed from an update URL.
+    COMMAND_LINE,       // --load-extension.
+
+    NUM_LOCATIONS
+  };
+
+  // Do not change the order of entries or remove entries in this list
+  // as this is used in UMA_HISTOGRAM_ENUMERATIONs about extensions.
+  enum Type {
+    TYPE_UNKNOWN = 0,
+    TYPE_EXTENSION,
+    TYPE_THEME,
+    TYPE_USER_SCRIPT,
+    TYPE_HOSTED_APP,
+    // This is marked legacy because platform apps are preferred. For
+    // backwards compatibility, we can't remove support for packaged apps
+    TYPE_LEGACY_PACKAGED_APP,
+    TYPE_PLATFORM_APP,
+    TYPE_SHARED_MODULE
+  };
+
+  // Given two install sources, return the one which should take priority
+  // over the other. If an extension is installed from two sources A and B,
+  // its install source should be set to GetHigherPriorityLocation(A, B).
+  static Location GetHigherPriorityLocation(Location loc1, Location loc2);
+
+  // Whether the |location| is external or not.
+  static inline bool IsExternalLocation(Location location) {
+    return location == EXTERNAL_PREF ||
+           location == EXTERNAL_REGISTRY ||
+           location == EXTERNAL_PREF_DOWNLOAD ||
+           location == EXTERNAL_POLICY_DOWNLOAD;
+  }
+
+  // Whether the |location| is unpacked (no CRX) or not.
+  static inline bool IsUnpackedLocation(Location location) {
+    return location == UNPACKED || location == COMMAND_LINE;
+  }
+
+  // Whether extensions with |location| are auto-updatable or not.
+  static inline bool IsAutoUpdateableLocation(Location location) {
+    // Only internal and external extensions can be autoupdated.
+    return location == INTERNAL ||
+           IsExternalLocation(location);
+  }
+
+  // Unpacked extensions start off with file access since they are a developer
+  // feature.
+  static inline bool ShouldAlwaysAllowFileAccess(Location location) {
+    return IsUnpackedLocation(location);
+  }
+
+  Manifest(Location location, scoped_ptr<base::DictionaryValue> value);
+  virtual ~Manifest();
+
+  const std::string& extension_id() const { return extension_id_; }
+  void set_extension_id(const std::string& id) { extension_id_ = id; }
+
+  Location location() const { return location_; }
+
+  // Returns false and |error| will be non-empty if the manifest is malformed.
+  // |warnings| will be populated if there are keys in the manifest that cannot
+  // be specified by the extension type.
+  bool ValidateManifest(std::string* error,
+                        std::vector<InstallWarning>* warnings) const;
+
+  // The version of this extension's manifest. We increase the manifest
+  // version when making breaking changes to the extension system. If the
+  // manifest contains no explicit manifest version, this returns the current
+  // system default.
+  int GetManifestVersion() const;
+
+  // Returns the manifest type.
+  Type type() const { return type_; }
+
+  bool is_theme() const { return type_ == TYPE_THEME; }
+  bool is_app() const {
+    return is_legacy_packaged_app() || is_hosted_app() || is_platform_app();
+  }
+  bool is_platform_app() const { return type_ == TYPE_PLATFORM_APP; }
+  bool is_hosted_app() const { return type_ == TYPE_HOSTED_APP; }
+  bool is_legacy_packaged_app() const {
+    return type_ == TYPE_LEGACY_PACKAGED_APP;
+  }
+  bool is_extension() const { return type_ == TYPE_EXTENSION; }
+  bool is_shared_module() const { return type_ == TYPE_SHARED_MODULE; }
+
+  // These access the wrapped manifest value, returning false when the property
+  // does not exist or if the manifest type can't access it.
+  bool HasKey(const std::string& key) const;
+  bool HasPath(const std::string& path) const;
+  bool Get(const std::string& path, const base::Value** out_value) const;
+  bool GetBoolean(const std::string& path, bool* out_value) const;
+  bool GetInteger(const std::string& path, int* out_value) const;
+  bool GetString(const std::string& path, std::string* out_value) const;
+  bool GetString(const std::string& path, string16* out_value) const;
+  bool GetDictionary(const std::string& path,
+                     const base::DictionaryValue** out_value) const;
+  bool GetList(const std::string& path,
+               const base::ListValue** out_value) const;
+
+  // Returns a new Manifest equal to this one, passing ownership to
+  // the caller.
+  Manifest* DeepCopy() const;
+
+  // Returns true if this equals the |other| manifest.
+  bool Equals(const Manifest* other) const;
+
+  // Gets the underlying DictionaryValue representing the manifest.
+  // Note: only use this when you KNOW you don't need the validation.
+  const base::DictionaryValue* value() const { return value_.get(); }
+
+ private:
+  // Returns true if the extension can specify the given |path|.
+  bool CanAccessPath(const std::string& path) const;
+  bool CanAccessKey(const std::string& key) const;
+
+  // A persistent, globally unique ID. An extension's ID is used in things
+  // like directory structures and URLs, and is expected to not change across
+  // versions. It is generated as a SHA-256 hash of the extension's public
+  // key, or as a hash of the path in the case of unpacked extensions.
+  std::string extension_id_;
+
+  // The location the extension was loaded from.
+  Location location_;
+
+  // The underlying dictionary representation of the manifest.
+  scoped_ptr<base::DictionaryValue> value_;
+
+  Type type_;
+
+  DISALLOW_COPY_AND_ASSIGN(Manifest);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_COMMON_MANIFEST_H_
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
new file mode 100644
index 0000000..fcdf6e9
--- /dev/null
+++ b/extensions/common/manifest_constants.cc
@@ -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.
+
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace manifest_keys {
+
+const char kAllFrames[] = "all_frames";
+const char kAltKey[] = "altKey";
+const char kApp[] = "app";
+const char kAudio[] = "audio";
+const char kBackgroundAllowJsAccess[] = "background.allow_js_access";
+const char kBackgroundPage[] = "background.page";
+const char kBackgroundPageLegacy[] = "background_page";
+const char kBackgroundPersistent[] = "background.persistent";
+const char kBackgroundScripts[] = "background.scripts";
+const char kBrowserAction[] = "browser_action";
+const char kChromeURLOverrides[] = "chrome_url_overrides";
+const char kCommands[] = "commands";
+const char kContentPack[] = "content_pack";
+const char kContentPackSites[] = "sites";
+const char kContentScripts[] = "content_scripts";
+const char kContentSecurityPolicy[] = "content_security_policy";
+const char kConvertedFromUserScript[] = "converted_from_user_script";
+const char kCss[] = "css";
+const char kCtrlKey[] = "ctrlKey";
+const char kCurrentLocale[] = "current_locale";
+const char kDefaultLocale[] = "default_locale";
+const char kDescription[] = "description";
+const char kDevToolsPage[] = "devtools_page";
+const char kDisplayInLauncher[] = "display_in_launcher";
+const char kDisplayInNewTabPage[] = "display_in_new_tab_page";
+const char kEventName[] = "event_name";
+const char kExcludeGlobs[] = "exclude_globs";
+const char kExcludeMatches[] = "exclude_matches";
+const char kExport[] = "export";
+const char kExternallyConnectable[] = "externally_connectable";
+const char kFileAccessList[] = "file_access";
+const char kFileFilters[] = "file_filters";
+const char kFileBrowserHandlers[] = "file_browser_handlers";
+const char kMediaGalleriesHandlers[] = "media_galleries_handlers";
+const char kFileHandlers[] = "file_handlers";
+const char kFileHandlerExtensions[] = "extensions";
+const char kFileHandlerTitle[] = "title";
+const char kFileHandlerTypes[] = "types";
+const char kHomepageURL[] = "homepage_url";
+const char kIcons[] = "icons";
+const char kId[] = "id";
+const char kImport[] = "import";
+const char kIncognito[] = "incognito";
+const char kIncludeGlobs[] = "include_globs";
+const char kInputComponents[] = "input_components";
+const char kIsolation[] = "app.isolation";
+const char kJs[] = "js";
+const char kKey[] = "key";
+const char kKeycode[] = "keyCode";
+const char kKioskEnabled[] = "kiosk_enabled";
+const char kLanguage[] = "language";
+const char kLaunch[] = "app.launch";
+const char kLaunchContainer[] = "app.launch.container";
+const char kLaunchHeight[] = "app.launch.height";
+const char kLaunchLocalPath[] = "app.launch.local_path";
+const char kLaunchWebURL[] = "app.launch.web_url";
+const char kLaunchWidth[] = "app.launch.width";
+const char kLayouts[] = "layouts";
+const char kManifestVersion[] = "manifest_version";
+const char kMatches[] = "matches";
+const char kMinimumChromeVersion[] = "minimum_chrome_version";
+const char kMinimumVersion[] = "minimum_version";
+const char kMIMETypes[] = "mime_types";
+const char kMimeTypesHandler[] = "mime_types_handler";
+const char kName[] = "name";
+const char kNaClModules[] = "nacl_modules";
+const char kNaClModulesMIMEType[] = "mime_type";
+const char kNaClModulesPath[] = "path";
+const char kOAuth2[] = "oauth2";
+const char kOAuth2AutoApprove[] = "oauth2.auto_approve";
+const char kOAuth2ClientId[] = "oauth2.client_id";
+const char kOAuth2Scopes[] = "oauth2.scopes";
+const char kOfflineEnabled[] = "offline_enabled";
+const char kOmnibox[] = "omnibox";
+const char kOmniboxKeyword[] = "omnibox.keyword";
+const char kOptionalPermissions[] = "optional_permissions";
+const char kOptionsPage[] = "options_page";
+const char kPageAction[] = "page_action";
+const char kPageActionDefaultIcon[] = "default_icon";
+const char kPageActionDefaultPopup[] = "default_popup";
+const char kPageActionDefaultTitle[] = "default_title";
+const char kPageActionIcons[] = "icons";
+const char kPageActionId[] = "id";
+const char kPageActionPopup[] = "popup";
+const char kPageActionPopupPath[] = "path";
+const char kPageActions[] = "page_actions";
+const char kPermissions[] = "permissions";
+const char kPlatformAppBackground[] = "app.background";
+const char kPlatformAppBackgroundPage[] = "app.background.page";
+const char kPlatformAppBackgroundScripts[] = "app.background.scripts";
+const char kPlatformAppContentSecurityPolicy[] = "app.content_security_policy";
+const char kPlugins[] = "plugins";
+const char kPluginsPath[] = "path";
+const char kPluginsPublic[] = "public";
+const char kPublicKey[] = "key";
+const char kResources[] = "resources";
+const char kRequirements[] = "requirements";
+const char kRunAt[] = "run_at";
+const char kSandboxedPages[] = "sandbox.pages";
+const char kSandboxedPagesCSP[] = "sandbox.content_security_policy";
+const char kScriptBadge[] = "script_badge";
+const char kShiftKey[] = "shiftKey";
+const char kShortcutKey[] = "shortcutKey";
+const char kSignature[] = "signature";
+const char kSpellcheck[] = "spellcheck";
+const char kSpellcheckDictionaryFormat[] = "dictionary_format";
+const char kSpellcheckDictionaryLanguage[] = "dictionary_language";
+const char kSpellcheckDictionaryLocale[] = "dictionary_locale";
+const char kSpellcheckDictionaryPath[] = "dictionary_path";
+const char kStorageManagedSchema[] = "storage.managed_schema";
+const char kSuggestedKey[] = "suggested_key";
+const char kSystemIndicator[] = "system_indicator";
+const char kSystemInfoDisplay[] = "systemInfo.display";
+const char kTheme[] = "theme";
+const char kThemeColors[] = "colors";
+const char kThemeDisplayProperties[] = "properties";
+const char kThemeImages[] = "images";
+const char kThemeTints[] = "tints";
+const char kTtsEngine[] = "tts_engine";
+const char kTtsGenderFemale[] = "female";
+const char kTtsGenderMale[] = "male";
+const char kTtsVoices[] = "voices";
+const char kTtsVoicesEventTypeEnd[] = "end";
+const char kTtsVoicesEventTypeError[] = "error";
+const char kTtsVoicesEventTypeMarker[] = "marker";
+const char kTtsVoicesEventTypeSentence[] = "sentence";
+const char kTtsVoicesEventTypeStart[] = "start";
+const char kTtsVoicesEventTypeWord[] = "word";
+const char kTtsVoicesEventTypes[] = "event_types";
+const char kTtsVoicesGender[] = "gender";
+const char kTtsVoicesLang[] = "lang";
+const char kTtsVoicesVoiceName[] = "voice_name";
+const char kType[] = "type";
+const char kUpdateURL[] = "update_url";
+const char kVersion[] = "version";
+const char kWebAccessibleResources[] = "web_accessible_resources";
+const char kWebURLs[] = "app.urls";
+
+}  // namespace manifest_keys
+
+}  // namespace extensions
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
new file mode 100644
index 0000000..ce31f7c
--- /dev/null
+++ b/extensions/common/manifest_constants.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 EXTENSIONS_COMMON_MANIFEST_CONSTANTS_H_
+#define EXTENSIONS_COMMON_MANIFEST_CONSTANTS_H_
+
+// Keys used in JSON representation of extensions.
+namespace extensions {
+namespace manifest_keys {
+  extern const char kAllFrames[];
+  extern const char kAltKey[];
+  extern const char kApp[];
+  extern const char kBackgroundAllowJsAccess[];
+  extern const char kBackgroundPage[];
+  extern const char kBackgroundPageLegacy[];
+  extern const char kBackgroundPersistent[];
+  extern const char kBackgroundScripts[];
+  extern const char kBrowserAction[];
+  extern const char kBrowseURLs[];
+  extern const char kChromeURLOverrides[];
+  extern const char kCommands[];
+  extern const char kContentPack[];
+  extern const char kContentPackSites[];
+  extern const char kContentScripts[];
+  extern const char kContentSecurityPolicy[];
+  extern const char kConvertedFromUserScript[];
+  extern const char kCss[];
+  extern const char kCtrlKey[];
+  extern const char kCurrentLocale[];
+  extern const char kDefaultLocale[];
+  extern const char kDescription[];
+  extern const char kDevToolsPage[];
+  extern const char kDisplayInLauncher[];
+  extern const char kDisplayInNewTabPage[];
+  extern const char kEventName[];
+  extern const char kExcludeGlobs[];
+  extern const char kExcludeMatches[];
+  extern const char kExport[];
+  extern const char kExternallyConnectable[];
+  extern const char kFileAccessList[];
+  extern const char kFileHandlers[];
+  extern const char kFileHandlerExtensions[];
+  extern const char kFileHandlerTitle[];
+  extern const char kFileHandlerTypes[];
+  extern const char kFileFilters[];
+  extern const char kFileBrowserHandlers[];
+  extern const char kMediaGalleriesHandlers[];
+  extern const char kHomepageURL[];
+  extern const char kIcons[];
+  extern const char kId[];
+  extern const char kImport[];
+  extern const char kIncognito[];
+  extern const char kIncludeGlobs[];
+  extern const char kInputComponents[];
+  extern const char kIntentDisposition[];
+  extern const char kIntentHref[];
+  extern const char kIntentPath[];
+  extern const char kIntents[];
+  extern const char kIntentTitle[];
+  extern const char kIntentType[];
+  extern const char kIsolation[];
+  extern const char kJs[];
+  extern const char kKey[];
+  extern const char kKeycode[];
+  extern const char kKioskEnabled[];
+  extern const char kLanguage[];
+  extern const char kLaunch[];
+  extern const char kLaunchContainer[];
+  extern const char kLaunchHeight[];
+  extern const char kLaunchLocalPath[];
+  extern const char kLaunchWebURL[];
+  extern const char kLaunchWidth[];
+  extern const char kLayouts[];
+  extern const char kManifestVersion[];
+  extern const char kMatches[];
+  extern const char kMIMETypes[];
+  extern const char kMimeTypesHandler[];
+  extern const char kMinimumChromeVersion[];
+  extern const char kMinimumVersion[];
+  extern const char kNaClModules[];
+  extern const char kNaClModulesMIMEType[];
+  extern const char kNaClModulesPath[];
+  extern const char kName[];
+  extern const char kOAuth2[];
+  extern const char kOAuth2AutoApprove[];
+  extern const char kOAuth2ClientId[];
+  extern const char kOAuth2Scopes[];
+  extern const char kOfflineEnabled[];
+  extern const char kOmnibox[];
+  extern const char kOmniboxKeyword[];
+  extern const char kOptionalPermissions[];
+  extern const char kOptionsPage[];
+  extern const char kPageAction[];
+  extern const char kPageActionDefaultIcon[];
+  extern const char kPageActionDefaultPopup[];
+  extern const char kPageActionDefaultTitle[];
+  extern const char kPageActionIcons[];
+  extern const char kPageActionId[];
+  extern const char kPageActionPopup[];
+  extern const char kPageActionPopupPath[];
+  extern const char kPageActions[];
+  extern const char kPermissions[];
+  extern const char kPlatformAppBackground[];
+  extern const char kPlatformAppBackgroundPage[];
+  extern const char kPlatformAppBackgroundScripts[];
+  extern const char kPlatformAppContentSecurityPolicy[];
+  extern const char kPlugins[];
+  extern const char kPluginsPath[];
+  extern const char kPluginsPublic[];
+  extern const char kPublicKey[];
+  extern const char kResources[];
+  extern const char kRequirements[];
+  extern const char kRunAt[];
+  extern const char kSandboxedPages[];
+  extern const char kSandboxedPagesCSP[];
+  extern const char kScriptBadge[];
+  extern const char kShiftKey[];
+  extern const char kShortcutKey[];
+  extern const char kSignature[];
+  extern const char kSpellcheck[];
+  extern const char kSpellcheckDictionaryFormat[];
+  extern const char kSpellcheckDictionaryLanguage[];
+  extern const char kSpellcheckDictionaryLocale[];
+  extern const char kSpellcheckDictionaryPath[];
+  extern const char kStorageManagedSchema[];
+  extern const char kSuggestedKey[];
+  extern const char kSystemIndicator[];
+  extern const char kTheme[];
+  extern const char kThemeColors[];
+  extern const char kThemeDisplayProperties[];
+  extern const char kThemeImages[];
+  extern const char kThemeTints[];
+  extern const char kTtsEngine[];
+  extern const char kTtsGenderFemale[];
+  extern const char kTtsGenderMale[];
+  extern const char kTtsVoices[];
+  extern const char kTtsVoicesEventTypeEnd[];
+  extern const char kTtsVoicesEventTypeError[];
+  extern const char kTtsVoicesEventTypeMarker[];
+  extern const char kTtsVoicesEventTypeSentence[];
+  extern const char kTtsVoicesEventTypeStart[];
+  extern const char kTtsVoicesEventTypeWord[];
+  extern const char kTtsVoicesEventTypes[];
+  extern const char kTtsVoicesGender[];
+  extern const char kTtsVoicesLang[];
+  extern const char kTtsVoicesVoiceName[];
+  extern const char kType[];
+  extern const char kUpdateURL[];
+  extern const char kVersion[];
+  extern const char kWebAccessibleResources[];
+  extern const char kWebURLs[];
+}  // namespace manifest_keys
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_COMMON_MANIFEST_CONSTANTS_H_
diff --git a/extensions/common/matcher/regex_set_matcher.cc b/extensions/common/matcher/regex_set_matcher.cc
index af8027c..24d99ef 100644
--- a/extensions/common/matcher/regex_set_matcher.cc
+++ b/extensions/common/matcher/regex_set_matcher.cc
@@ -53,7 +53,6 @@
   std::vector<RE2ID> re2_ids;
   filtered_re2_->AllMatches(text, atoms, &re2_ids);
 
-  std::set<StringPattern::ID> matched_ids;
   for (size_t i = 0; i < re2_ids.size(); ++i) {
     StringPattern::ID id = re2_id_map_[re2_ids[i]];
     matches->insert(id);
diff --git a/extensions/common/matcher/url_matcher.cc b/extensions/common/matcher/url_matcher.cc
index be3057a..5a1d876 100644
--- a/extensions/common/matcher/url_matcher.cc
+++ b/extensions/common/matcher/url_matcher.cc
@@ -752,19 +752,15 @@
                           : registered_url_component_patterns_;
 
   // Add all patterns that are in new_patterns but not in registered_patterns.
-  std::vector<const StringPattern*> patterns_to_register;
-  std::set_difference(
-      new_patterns.begin(), new_patterns.end(),
-      registered_patterns.begin(), registered_patterns.end(),
-      std::back_inserter(patterns_to_register));
+  std::vector<const StringPattern*> patterns_to_register =
+      base::STLSetDifference<std::vector<const StringPattern*> >(
+          new_patterns, registered_patterns);
 
   // Remove all patterns that are in registered_patterns but not in
   // new_patterns.
-  std::vector<const StringPattern*> patterns_to_unregister;
-  std::set_difference(
-      registered_patterns.begin(), registered_patterns.end(),
-      new_patterns.begin(), new_patterns.end(),
-      std::back_inserter(patterns_to_unregister));
+  std::vector<const StringPattern*> patterns_to_unregister =
+      base::STLSetDifference<std::vector<const StringPattern*> >(
+           registered_patterns, new_patterns);
 
   // Update the SubstringSetMatcher.
   SubstringSetMatcher& url_matcher =
diff --git a/google_apis/gaia/gaia_constants.cc b/google_apis/gaia/gaia_constants.cc
index d1d932f..1b1581d 100644
--- a/google_apis/gaia/gaia_constants.cc
+++ b/google_apis/gaia/gaia_constants.cc
@@ -40,9 +40,6 @@
 const char kGoogleTalkOAuth2Scope[] =
     "https://www.googleapis.com/auth/googletalk";
 
-// Service for LSO endpoint of Google that exposes OAuth APIs.
-const char kLSOService[] = "lso";
-
 // Used to mint uber auth tokens when needed.
 const char kGaiaSid[] = "sid";
 const char kGaiaLsid[] = "lsid";
diff --git a/google_apis/gaia/gaia_constants.h b/google_apis/gaia/gaia_constants.h
index 72cae74..3b45eee 100644
--- a/google_apis/gaia/gaia_constants.h
+++ b/google_apis/gaia/gaia_constants.h
@@ -23,7 +23,6 @@
 extern const char kChromeSyncOAuth2Scope[];
 extern const char kChromeSyncManagedOAuth2Scope[];
 extern const char kGoogleTalkOAuth2Scope[];
-extern const char kLSOService[];
 
 // Used with uber auth tokens when needed.
 extern const char kGaiaSid[];
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc
index fc4b547..0baf00d 100644
--- a/google_apis/google_api_keys.cc
+++ b/google_apis/google_api_keys.cc
@@ -49,6 +49,14 @@
 #define GOOGLE_CLIENT_SECRET_REMOTING DUMMY_API_TOKEN
 #endif
 
+#if !defined(GOOGLE_CLIENT_ID_REMOTING_HOST)
+#define GOOGLE_CLIENT_ID_REMOTING_HOST DUMMY_API_TOKEN
+#endif
+
+#if !defined(GOOGLE_CLIENT_SECRET_REMOTING_HOST)
+#define GOOGLE_CLIENT_SECRET_REMOTING_HOST DUMMY_API_TOKEN
+#endif
+
 // These are used as shortcuts for developers and users providing
 // OAuth credentials via preprocessor defines or environment
 // variables.  If set, they will be used to replace any of the client
@@ -152,6 +160,21 @@
         default_client_secret,
         environment.get(),
         command_line);
+
+    client_ids_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
+        GOOGLE_CLIENT_ID_REMOTING_HOST,
+        STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_ID_REMOTING_HOST),
+        NULL,
+        default_client_id,
+        environment.get(),
+        command_line);
+    client_secrets_[CLIENT_REMOTING_HOST] = CalculateKeyValue(
+        GOOGLE_CLIENT_SECRET_REMOTING_HOST,
+        STRINGIZE_NO_EXPANSION(GOOGLE_CLIENT_SECRET_REMOTING_HOST),
+        NULL,
+        default_client_secret,
+        environment.get(),
+        command_line);
   }
 
   std::string api_key() const { return api_key_; }
diff --git a/google_apis/google_api_keys.h b/google_apis/google_api_keys.h
index 28421e8..8f4bc7e 100644
--- a/google_apis/google_api_keys.h
+++ b/google_apis/google_api_keys.h
@@ -71,6 +71,7 @@
   CLIENT_MAIN,         // Several different features use this.
   CLIENT_CLOUD_PRINT,
   CLIENT_REMOTING,
+  CLIENT_REMOTING_HOST,
 
   CLIENT_NUM_ITEMS     // Must be last item.
 };
diff --git a/google_apis/google_api_keys.py b/google_apis/google_api_keys.py
index 6776aae..94170ea 100755
--- a/google_apis/google_api_keys.py
+++ b/google_apis/google_api_keys.py
@@ -88,3 +88,8 @@
   print 'GOOGLE_CLIENT_SECRET_CLOUD_PRINT=%s' % GetClientSecret('CLOUD_PRINT')
   print 'GOOGLE_CLIENT_ID_REMOTING=%s' % GetClientID('REMOTING')
   print 'GOOGLE_CLIENT_SECRET_REMOTING=%s' % GetClientSecret('REMOTING')
+  print 'GOOGLE_CLIENT_ID_REMOTING_HOST=%s' % GetClientID('REMOTING_HOST')
+  print 'GOOGLE_CLIENT_SECRET_REMOTING_HOST=%s' % GetClientSecret(
+      'REMOTING_HOST')
+  print 'GOOGLE_CLIENT_ID_REMOTING_IDENTITY_API=%s' %GetClientID(
+      'REMOTING_IDENTITY_API')
diff --git a/google_apis/google_api_keys_unittest.cc b/google_apis/google_api_keys_unittest.cc
index 4d338f5..7432f93 100644
--- a/google_apis/google_api_keys_unittest.cc
+++ b/google_apis/google_api_keys_unittest.cc
@@ -59,8 +59,10 @@
     env_cache_[4].variable_name = "GOOGLE_CLIENT_SECRET_CLOUD_PRINT";
     env_cache_[5].variable_name = "GOOGLE_CLIENT_ID_REMOTING";
     env_cache_[6].variable_name = "GOOGLE_CLIENT_SECRET_REMOTING";
-    env_cache_[7].variable_name = "GOOGLE_DEFAULT_CLIENT_ID";
-    env_cache_[8].variable_name = "GOOGLE_DEFAULT_CLIENT_SECRET";
+    env_cache_[7].variable_name = "GOOGLE_CLIENT_ID_REMOTING_HOST";
+    env_cache_[8].variable_name = "GOOGLE_CLIENT_SECRET_REMOTING_HOST";
+    env_cache_[9].variable_name = "GOOGLE_DEFAULT_CLIENT_ID";
+    env_cache_[10].variable_name = "GOOGLE_DEFAULT_CLIENT_SECRET";
   }
 
   virtual void SetUp() {
@@ -114,6 +116,8 @@
 #undef GOOGLE_CLIENT_SECRET_CLOUD_PRINT
 #undef GOOGLE_CLIENT_ID_REMOTING
 #undef GOOGLE_CLIENT_SECRET_REMOTING
+#undef GOOGLE_CLIENT_ID_REMOTING_HOST
+#undef GOOGLE_CLIENT_SECRET_REMOTING_HOST
 #undef GOOGLE_DEFAULT_CLIENT_ID
 #undef GOOGLE_DEFAULT_CLIENT_SECRET
 
@@ -150,6 +154,11 @@
   std::string secret_remoting =
       testcase::g_api_key_cache.Get().GetClientSecret(
           testcase::CLIENT_REMOTING);
+  std::string id_remoting_host = testcase::g_api_key_cache.Get().GetClientID(
+      testcase::CLIENT_REMOTING_HOST);
+  std::string secret_remoting_host =
+      testcase::g_api_key_cache.Get().GetClientSecret(
+          testcase::CLIENT_REMOTING_HOST);
 
   EXPECT_NE(0u, api_key.size());
   EXPECT_NE(DUMMY_API_TOKEN, api_key);
@@ -180,6 +189,14 @@
   EXPECT_NE(0u, secret_remoting.size());
   EXPECT_NE(DUMMY_API_TOKEN, secret_remoting);
   EXPECT_NE(kDummyToken, secret_remoting);
+
+  EXPECT_NE(0u, id_remoting_host.size());
+  EXPECT_NE(DUMMY_API_TOKEN, id_remoting_host);
+  EXPECT_NE(kDummyToken, id_remoting_host);
+
+  EXPECT_NE(0u, secret_remoting_host.size());
+  EXPECT_NE(DUMMY_API_TOKEN, secret_remoting_host);
+  EXPECT_NE(kDummyToken, secret_remoting_host);
 }
 #endif  // defined(GOOGLE_CHROME_BUILD) || defined(USE_OFFICIAL_GOOGLE_API_KEYS)
 
@@ -201,6 +218,8 @@
 #undef GOOGLE_CLIENT_SECRET_CLOUD_PRINT
 #undef GOOGLE_CLIENT_ID_REMOTING
 #undef GOOGLE_CLIENT_SECRET_REMOTING
+#undef GOOGLE_CLIENT_ID_REMOTING_HOST
+#undef GOOGLE_CLIENT_SECRET_REMOTING_HOST
 #undef GOOGLE_DEFAULT_CLIENT_ID
 #undef GOOGLE_DEFAULT_CLIENT_SECRET
 
@@ -232,6 +251,11 @@
   std::string secret_remoting =
       testcase::g_api_key_cache.Get().GetClientSecret(
           testcase::CLIENT_REMOTING);
+  std::string id_remoting_host = testcase::g_api_key_cache.Get().GetClientID(
+      testcase::CLIENT_REMOTING_HOST);
+  std::string secret_remoting_host =
+      testcase::g_api_key_cache.Get().GetClientSecret(
+          testcase::CLIENT_REMOTING_HOST);
 
   EXPECT_EQ(kDummyToken, api_key);
   EXPECT_EQ(kDummyToken, id_main);
@@ -240,6 +264,8 @@
   EXPECT_EQ(kDummyToken, secret_cloud_print);
   EXPECT_EQ(kDummyToken, id_remoting);
   EXPECT_EQ(kDummyToken, secret_remoting);
+  EXPECT_EQ(kDummyToken, id_remoting_host);
+  EXPECT_EQ(kDummyToken, secret_remoting_host);
 }
 
 // Override a couple of keys, leave the rest default.
@@ -255,6 +281,8 @@
 #undef GOOGLE_CLIENT_SECRET_CLOUD_PRINT
 #undef GOOGLE_CLIENT_ID_REMOTING
 #undef GOOGLE_CLIENT_SECRET_REMOTING
+#undef GOOGLE_CLIENT_ID_REMOTING_HOST
+#undef GOOGLE_CLIENT_SECRET_REMOTING_HOST
 #undef GOOGLE_DEFAULT_CLIENT_ID
 #undef GOOGLE_DEFAULT_CLIENT_SECRET
 
@@ -289,6 +317,11 @@
   std::string secret_remoting =
       testcase::g_api_key_cache.Get().GetClientSecret(
           testcase::CLIENT_REMOTING);
+  std::string id_remoting_host = testcase::g_api_key_cache.Get().GetClientID(
+      testcase::CLIENT_REMOTING_HOST);
+  std::string secret_remoting_host =
+      testcase::g_api_key_cache.Get().GetClientSecret(
+          testcase::CLIENT_REMOTING_HOST);
 
   EXPECT_EQ("API_KEY override", api_key);
   EXPECT_EQ(kDummyToken, id_main);
@@ -297,6 +330,8 @@
   EXPECT_EQ(kDummyToken, secret_cloud_print);
   EXPECT_EQ("CLIENT_ID_REMOTING override", id_remoting);
   EXPECT_EQ(kDummyToken, secret_remoting);
+  EXPECT_EQ(kDummyToken, id_remoting_host);
+  EXPECT_EQ(kDummyToken, secret_remoting_host);
 }
 
 // Override all keys.
@@ -312,6 +347,8 @@
 #undef GOOGLE_CLIENT_SECRET_CLOUD_PRINT
 #undef GOOGLE_CLIENT_ID_REMOTING
 #undef GOOGLE_CLIENT_SECRET_REMOTING
+#undef GOOGLE_CLIENT_ID_REMOTING_HOST
+#undef GOOGLE_CLIENT_SECRET_REMOTING_HOST
 #undef GOOGLE_DEFAULT_CLIENT_ID
 #undef GOOGLE_DEFAULT_CLIENT_SECRET
 
@@ -322,6 +359,8 @@
 #define GOOGLE_CLIENT_SECRET_CLOUD_PRINT "SECRET_CLOUD_PRINT"
 #define GOOGLE_CLIENT_ID_REMOTING "ID_REMOTING"
 #define GOOGLE_CLIENT_SECRET_REMOTING "SECRET_REMOTING"
+#define GOOGLE_CLIENT_ID_REMOTING_HOST "ID_REMOTING_HOST"
+#define GOOGLE_CLIENT_SECRET_REMOTING_HOST "SECRET_REMOTING_HOST"
 
 // Undef include guard so things get defined again, within this namespace.
 #undef GOOGLE_APIS_GOOGLE_API_KEYS_H_
@@ -351,6 +390,11 @@
   std::string secret_remoting =
       testcase::g_api_key_cache.Get().GetClientSecret(
           testcase::CLIENT_REMOTING);
+  std::string id_remoting_host = testcase::g_api_key_cache.Get().GetClientID(
+      testcase::CLIENT_REMOTING_HOST);
+  std::string secret_remoting_host =
+      testcase::g_api_key_cache.Get().GetClientSecret(
+          testcase::CLIENT_REMOTING_HOST);
 
   EXPECT_EQ("API_KEY", api_key);
   EXPECT_EQ("ID_MAIN", id_main);
@@ -359,6 +403,8 @@
   EXPECT_EQ("SECRET_CLOUD_PRINT", secret_cloud_print);
   EXPECT_EQ("ID_REMOTING", id_remoting);
   EXPECT_EQ("SECRET_REMOTING", secret_remoting);
+  EXPECT_EQ("ID_REMOTING_HOST", id_remoting_host);
+  EXPECT_EQ("SECRET_REMOTING_HOST", secret_remoting_host);
 }
 
 // Override all keys using both preprocessor defines and environment
@@ -375,6 +421,8 @@
 #undef GOOGLE_CLIENT_SECRET_CLOUD_PRINT
 #undef GOOGLE_CLIENT_ID_REMOTING
 #undef GOOGLE_CLIENT_SECRET_REMOTING
+#undef GOOGLE_CLIENT_ID_REMOTING_HOST
+#undef GOOGLE_CLIENT_SECRET_REMOTING_HOST
 #undef GOOGLE_DEFAULT_CLIENT_ID
 #undef GOOGLE_DEFAULT_CLIENT_SECRET
 
@@ -385,6 +433,8 @@
 #define GOOGLE_CLIENT_SECRET_CLOUD_PRINT "SECRET_CLOUD_PRINT"
 #define GOOGLE_CLIENT_ID_REMOTING "ID_REMOTING"
 #define GOOGLE_CLIENT_SECRET_REMOTING "SECRET_REMOTING"
+#define GOOGLE_CLIENT_ID_REMOTING_HOST "ID_REMOTING_HOST"
+#define GOOGLE_CLIENT_SECRET_REMOTING_HOST "SECRET_REMOTING_HOST"
 
 // Undef include guard so things get defined again, within this namespace.
 #undef GOOGLE_APIS_GOOGLE_API_KEYS_H_
@@ -401,9 +451,11 @@
   env->SetVar("GOOGLE_CLIENT_ID_MAIN", "env-ID_MAIN");
   env->SetVar("GOOGLE_CLIENT_ID_CLOUD_PRINT", "env-ID_CLOUD_PRINT");
   env->SetVar("GOOGLE_CLIENT_ID_REMOTING", "env-ID_REMOTING");
+  env->SetVar("GOOGLE_CLIENT_ID_REMOTING_HOST", "env-ID_REMOTING_HOST");
   env->SetVar("GOOGLE_CLIENT_SECRET_MAIN", "env-SECRET_MAIN");
   env->SetVar("GOOGLE_CLIENT_SECRET_CLOUD_PRINT", "env-SECRET_CLOUD_PRINT");
   env->SetVar("GOOGLE_CLIENT_SECRET_REMOTING", "env-SECRET_REMOTING");
+  env->SetVar("GOOGLE_CLIENT_SECRET_REMOTING_HOST", "env-SECRET_REMOTING_HOST");
 
   EXPECT_TRUE(testcase::HasKeysConfigured());
 
@@ -425,6 +477,11 @@
   std::string secret_remoting =
       testcase::g_api_key_cache.Get().GetClientSecret(
           testcase::CLIENT_REMOTING);
+  std::string id_remoting_host = testcase::g_api_key_cache.Get().GetClientID(
+      testcase::CLIENT_REMOTING_HOST);
+  std::string secret_remoting_host =
+      testcase::g_api_key_cache.Get().GetClientSecret(
+          testcase::CLIENT_REMOTING_HOST);
 
   EXPECT_EQ("env-API_KEY", api_key);
   EXPECT_EQ("env-ID_MAIN", id_main);
@@ -433,6 +490,8 @@
   EXPECT_EQ("env-SECRET_CLOUD_PRINT", secret_cloud_print);
   EXPECT_EQ("env-ID_REMOTING", id_remoting);
   EXPECT_EQ("env-SECRET_REMOTING", secret_remoting);
+  EXPECT_EQ("env-ID_REMOTING_HOST", id_remoting_host);
+  EXPECT_EQ("env-SECRET_REMOTING_HOST", secret_remoting_host);
 }
 
 #endif  // defined(OS_LINUX) || defined(OS_MACOSX)
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 6555da2..a6f13c1 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -62,13 +62,15 @@
 _CAPABILITY_FLAGS = [
   {'name': 'blend'},
   {'name': 'cull_face'},
-  {'name': 'depth_test', 'state_flag': 'clear_state_dirty_'},
+  {'name': 'depth_test', 'state_flag': 'framebuffer_state_.clear_state_dirty'},
   {'name': 'dither', 'default': True},
   {'name': 'polygon_offset_fill'},
   {'name': 'sample_alpha_to_coverage'},
   {'name': 'sample_coverage'},
-  {'name': 'scissor_test', 'state_flag': 'clear_state_dirty_'},
-  {'name': 'stencil_test', 'state_flag': 'clear_state_dirty_'},
+  {'name': 'scissor_test',
+   'state_flag': 'framebuffer_state_.clear_state_dirty'},
+  {'name': 'stencil_test',
+   'state_flag': 'framebuffer_state_.clear_state_dirty'},
 ]
 
 _STATES = {
@@ -101,7 +103,7 @@
       {'name': 'color_mask_blue', 'type': 'GLboolean', 'default': 'true'},
       {'name': 'color_mask_alpha', 'type': 'GLboolean', 'default': 'true'},
     ],
-    'state_flag': 'clear_state_dirty_',
+    'state_flag': 'framebuffer_state_.clear_state_dirty',
   },
   'ClearStencil': {
     'type': 'Normal',
@@ -242,7 +244,7 @@
   'StencilMask': {
     'type': 'FrontBack',
     'func': 'StencilMaskSeparate',
-    'state_flag': 'clear_state_dirty_',
+    'state_flag': 'framebuffer_state_.clear_state_dirty',
     'states': [
       {
         'name': 'stencil_front_writemask',
@@ -400,7 +402,7 @@
     'states': [
       {'name': 'depth_mask', 'type': 'GLboolean', 'default': 'true'},
     ],
-    'state_flag': 'clear_state_dirty_',
+    'state_flag': 'framebuffer_state_.clear_state_dirty',
   },
   'Scissor': {
     'type': 'Normal',
diff --git a/gpu/command_buffer/client/buffer_tracker_unittest.cc b/gpu/command_buffer/client/buffer_tracker_unittest.cc
index 86b69f0..51f4f94 100644
--- a/gpu/command_buffer/client/buffer_tracker_unittest.cc
+++ b/gpu/command_buffer/client/buffer_tracker_unittest.cc
@@ -51,7 +51,8 @@
     command_buffer_.reset(new MockClientCommandBufferImpl());
     helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
     helper_->Initialize(kCommandBufferSizeBytes);
-    mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+    mapped_memory_.reset(new MappedMemoryManager(
+        helper_.get(), MappedMemoryManager::kNoLimit));
     buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
   }
 
diff --git a/gpu/command_buffer/client/client_test_helper.cc b/gpu/command_buffer/client/client_test_helper.cc
index cccfa3b..31a91b2 100644
--- a/gpu/command_buffer/client/client_test_helper.cc
+++ b/gpu/command_buffer/client/client_test_helper.cc
@@ -151,6 +151,12 @@
           this, &MockCommandBufferBase::FlushHelper));
 }
 
+MockClientGpuControl::MockClientGpuControl() {
+}
+
+MockClientGpuControl::~MockClientGpuControl() {
+}
+
 }  // namespace gpu
 
 
diff --git a/gpu/command_buffer/client/client_test_helper.h b/gpu/command_buffer/client/client_test_helper.h
index 7010704..e9d6c36 100644
--- a/gpu/command_buffer/client/client_test_helper.h
+++ b/gpu/command_buffer/client/client_test_helper.h
@@ -11,6 +11,7 @@
 #include "gpu/command_buffer/common/cmd_buffer_common.h"
 #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 "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -81,6 +82,22 @@
   void DelegateToFake();
 };
 
+class MockClientGpuControl : public GpuControl {
+ public:
+  MockClientGpuControl();
+  virtual ~MockClientGpuControl();
+
+  MOCK_METHOD4(CreateGpuMemoryBuffer,
+               gfx::GpuMemoryBuffer*(size_t width,
+                                     size_t height,
+                                     unsigned internalformat,
+                                     int32* id));
+  MOCK_METHOD1(DestroyGpuMemoryBuffer, void(int32 id));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockClientGpuControl);
+};
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_
diff --git a/gpu/command_buffer/client/fenced_allocator.cc b/gpu/command_buffer/client/fenced_allocator.cc
index 6eb9ab3..02e891f 100644
--- a/gpu/command_buffer/client/fenced_allocator.cc
+++ b/gpu/command_buffer/client/fenced_allocator.cc
@@ -5,7 +5,9 @@
 // This file contains the implementation of the FencedAllocator class.
 
 #include "gpu/command_buffer/client/fenced_allocator.h"
+
 #include <algorithm>
+
 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
 
 namespace gpu {
@@ -33,7 +35,8 @@
 
 FencedAllocator::FencedAllocator(unsigned int size,
                                  CommandBufferHelper *helper)
-    : helper_(helper) {
+    : helper_(helper),
+      bytes_in_use_(0) {
   Block block = { FREE, 0, RoundDown(size), kUnusedToken };
   blocks_.push_back(block);
 }
@@ -90,7 +93,12 @@
 void FencedAllocator::Free(FencedAllocator::Offset offset) {
   BlockIndex index = GetBlockByOffset(offset);
   GPU_DCHECK_NE(blocks_[index].state, FREE);
-  blocks_[index].state = FREE;
+  Block &block = blocks_[index];
+
+  if (block.state == IN_USE)
+    bytes_in_use_ -= block.size;
+
+  block.state = FREE;
   CollapseFreeBlock(index);
 }
 
@@ -99,6 +107,8 @@
     FencedAllocator::Offset offset, int32 token) {
   BlockIndex index = GetBlockByOffset(offset);
   Block &block = blocks_[index];
+  if (block.state == IN_USE)
+    bytes_in_use_ -= block.size;
   block.state = FREE_PENDING_TOKEN;
   block.token = token;
 }
@@ -153,6 +163,8 @@
   return true;
 }
 
+// Returns false if all blocks are actually FREE, in which
+// case they would be coalesced into one block, true otherwise.
 bool FencedAllocator::InUse() {
   return blocks_.size() != 1 || blocks_[0].state != FREE;
 }
@@ -211,6 +223,7 @@
   GPU_DCHECK_GE(block.size, size);
   GPU_DCHECK_EQ(block.state, FREE);
   Offset offset = block.offset;
+  bytes_in_use_ += size;
   if (block.size == size) {
     block.state = IN_USE;
     return offset;
diff --git a/gpu/command_buffer/client/fenced_allocator.h b/gpu/command_buffer/client/fenced_allocator.h
index 90288d9..71e6178 100644
--- a/gpu/command_buffer/client/fenced_allocator.h
+++ b/gpu/command_buffer/client/fenced_allocator.h
@@ -83,6 +83,9 @@
   // True if any memory is allocated.
   bool InUse();
 
+  // Return bytes of memory that is IN_USE
+  size_t bytes_in_use() const { return bytes_in_use_; }
+
  private:
   // Status of a block of memory, for book-keeping.
   enum State {
@@ -134,6 +137,7 @@
 
   CommandBufferHelper *helper_;
   Container blocks_;
+  size_t bytes_in_use_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator);
 };
@@ -243,6 +247,8 @@
 
   FencedAllocator &allocator() { return allocator_; }
 
+  size_t bytes_in_use() const { return allocator_.bytes_in_use(); }
+
  private:
   FencedAllocator allocator_;
   void* base_;
diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc
index cdbfc9f..984214d 100644
--- a/gpu/command_buffer/client/gl_in_process_context.cc
+++ b/gpu/command_buffer/client/gl_in_process_context.cc
@@ -23,8 +23,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
-#include "gpu/command_buffer/client/image_factory.h"
 #include "gpu/command_buffer/client/transfer_buffer.h"
 #include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/command_buffer/common/constants.h"
@@ -32,6 +30,10 @@
 #include "ui/gfx/size.h"
 #include "ui/gl/gl_image.h"
 
+#if defined(OS_ANDROID)
+#include "ui/gl/android/surface_texture_bridge.h"
+#endif
+
 namespace gpu {
 
 namespace {
@@ -43,11 +45,8 @@
 const size_t kMinTransferBufferSize = 1 * 256 * 1024;
 const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
 
-static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
-
 class GLInProcessContextImpl
     : public GLInProcessContext,
-      public gles2::ImageFactory,
       public base::SupportsWeakPtr<GLInProcessContextImpl> {
  public:
   explicit GLInProcessContextImpl();
@@ -70,11 +69,10 @@
       OVERRIDE;
   virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE;
 
-  // ImageFactory implementation:
-  virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      int width, int height, GLenum internalformat,
-      unsigned* image_id) OVERRIDE;
-  virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE;
+#if defined(OS_ANDROID)
+  virtual scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture(
+      uint32 stream_id) OVERRIDE;
+#endif
 
  private:
   void Destroy();
@@ -108,24 +106,6 @@
   return g_all_shared_contexts.Get().size();
 }
 
-scoped_ptr<gfx::GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer(
-    int width, int height, GLenum internalformat, unsigned int* image_id) {
-  scoped_ptr<gfx::GpuMemoryBuffer> buffer(
-      g_gpu_memory_buffer_factory->CreateGpuMemoryBuffer(width,
-                                                         height,
-                                                         internalformat));
-  if (!buffer)
-    return scoped_ptr<gfx::GpuMemoryBuffer>();
-
-  *image_id = command_buffer_->CreateImageForGpuMemoryBuffer(
-      buffer->GetHandle(), gfx::Size(width, height));
-  return buffer.Pass();
-}
-
-void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) {
-  command_buffer_->RemoveImage(image_id);
-}
-
 GLInProcessContextImpl::GLInProcessContextImpl()
     : share_group_id_(0), context_lost_(false) {}
 
@@ -279,7 +259,7 @@
       share_group,
       transfer_buffer_.get(),
       false,
-      this));
+      command_buffer_.get()));
 
   if (share_resources) {
     g_all_shared_contexts.Get().insert(this);
@@ -289,7 +269,8 @@
   if (!gles2_implementation_->Initialize(
       kStartTransferBufferSize,
       kMinTransferBufferSize,
-      kMaxTransferBufferSize)) {
+      kMaxTransferBufferSize,
+      gles2::GLES2Implementation::kNoLimit)) {
     return false;
   }
 
@@ -361,6 +342,13 @@
   }
 }
 
+#if defined(OS_ANDROID)
+scoped_refptr<gfx::SurfaceTextureBridge>
+GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id) {
+  return command_buffer_->GetSurfaceTexture(stream_id);
+}
+#endif
+
 }  // anonymous namespace
 
 GLInProcessContextAttribs::GLInProcessContextAttribs()
@@ -421,11 +409,4 @@
   return context.release();
 }
 
-// static
-void GLInProcessContext::SetGpuMemoryBufferFactory(
-    GpuMemoryBufferFactory* factory) {
-  DCHECK_EQ(0u, SharedContextCount());
-  g_gpu_memory_buffer_factory = factory;
-}
-
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/gl_in_process_context.h b/gpu/command_buffer/client/gl_in_process_context.h
index 09f8140..ec7bdc5 100644
--- a/gpu/command_buffer/client/gl_in_process_context.h
+++ b/gpu/command_buffer/client/gl_in_process_context.h
@@ -16,14 +16,18 @@
 class Size;
 }
 
+#if defined(OS_ANDROID)
+namespace gfx {
+class SurfaceTextureBridge;
+}
+#endif
+
 namespace gpu {
 
 namespace gles2 {
 class GLES2Implementation;
 }
 
-class GpuMemoryBufferFactory;
-
 // The default uninitialized value is -1.
 struct GLES2_IMPL_EXPORT GLInProcessContextAttribs {
   GLInProcessContextAttribs();
@@ -42,9 +46,6 @@
  public:
   virtual ~GLInProcessContext() {}
 
-  // Must be called before any GLInProcessContext instances are created.
-  static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory);
-
   // Create a GLInProcessContext, if |is_offscreen| is true, renders to an
   // offscreen context. |attrib_list| must be NULL or a NONE-terminated list
   // of attribute/value pairs.
@@ -78,6 +79,11 @@
   // Allows direct access to the GLES2 implementation so a GLInProcessContext
   // can be used without making it current.
   virtual gles2::GLES2Implementation* GetImplementation() = 0;
+
+#if defined(OS_ANDROID)
+  virtual scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture(
+      uint32 stream_id) = 0;
+#endif
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 9285b6d..0fde7d8 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -17,7 +17,6 @@
 #include <GLES2/gl2extchromium.h>
 #include "gpu/command_buffer/client/buffer_tracker.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
-#include "gpu/command_buffer/client/mapped_memory.h"
 #include "gpu/command_buffer/client/program_info_manager.h"
 #include "gpu/command_buffer/client/query_tracker.h"
 #include "gpu/command_buffer/client/transfer_buffer.h"
@@ -86,7 +85,7 @@
       ShareGroup* share_group,
       TransferBufferInterface* transfer_buffer,
       bool bind_generates_resource,
-      ImageFactory* image_factory)
+      GpuControl* gpu_control)
     : helper_(helper),
       transfer_buffer_(transfer_buffer),
       angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
@@ -111,7 +110,7 @@
       use_count_(0),
       current_query_(NULL),
       error_message_callback_(NULL),
-      image_factory_(image_factory) {
+      gpu_control_(gpu_control) {
   GPU_DCHECK(helper);
   GPU_DCHECK(transfer_buffer);
 
@@ -133,7 +132,8 @@
 bool GLES2Implementation::Initialize(
     unsigned int starting_transfer_buffer_size,
     unsigned int min_transfer_buffer_size,
-    unsigned int max_transfer_buffer_size) {
+    unsigned int max_transfer_buffer_size,
+    unsigned int mapped_memory_limit) {
   GPU_DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
   GPU_DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
   GPU_DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
@@ -148,8 +148,8 @@
     return false;
   }
 
-  mapped_memory_.reset(new MappedMemoryManager(helper_));
-  SetSharedMemoryChunkSizeMultiple(1024 * 1024 * 2);
+  mapped_memory_.reset(new MappedMemoryManager(helper_, mapped_memory_limit));
+  mapped_memory_->set_chunk_size_multiple(2 * 1024 * 1024);
 
   if (!QueryAndCacheStaticState())
     return false;
@@ -165,7 +165,7 @@
 
   query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
   buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
-  gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(image_factory_));
+  gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(gpu_control_));
 
 #if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
   GetIdHandler(id_namespaces::kBuffers)->MakeIds(
@@ -289,11 +289,6 @@
   return transfer_buffer_->GetResultOffset();
 }
 
-void GLES2Implementation::SetSharedMemoryChunkSizeMultiple(
-    unsigned int multiple) {
-  mapped_memory_->set_chunk_size_multiple(multiple);
-}
-
 void GLES2Implementation::FreeUnusedSharedMemory() {
   mapped_memory_->FreeUnused();
 }
@@ -2089,7 +2084,7 @@
             "GL_CHROMIUM_map_sub "
             "GL_CHROMIUM_shallow_flush "
             "GL_EXT_unpack_subimage";
-        if (image_factory_ != NULL) {
+        if (gpu_control_ != NULL) {
           // The first space character is intentional.
           str += " GL_CHROMIUM_map_image";
         }
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index c2bf49f..9f8a7a2 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -20,7 +20,7 @@
 #include "gpu/command_buffer/client/gles2_cmd_helper.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
-#include "gpu/command_buffer/client/image_factory.h"
+#include "gpu/command_buffer/client/mapped_memory.h"
 #include "gpu/command_buffer/client/query_tracker.h"
 #include "gpu/command_buffer/client/ref_counted.h"
 #include "gpu/command_buffer/client/ring_buffer.h"
@@ -98,7 +98,7 @@
 
 namespace gpu {
 
-class MappedMemoryManager;
+class GpuControl;
 class ScopedTransferBufferPtr;
 class TransferBufferInterface;
 
@@ -115,6 +115,9 @@
 // shared memory and synchronization issues.
 class GLES2_IMPL_EXPORT GLES2Implementation : public GLES2Interface {
  public:
+  enum MappedMemoryLimit {
+    kNoLimit = MappedMemoryManager::kNoLimit,
+  };
   class ErrorMessageCallback {
    public:
     virtual ~ErrorMessageCallback() { }
@@ -177,14 +180,15 @@
       ShareGroup* share_group,
       TransferBufferInterface* transfer_buffer,
       bool bind_generates_resource,
-      ImageFactory* image_factory);
+      GpuControl* gpu_control);
 
   virtual ~GLES2Implementation();
 
   bool Initialize(
       unsigned int starting_transfer_buffer_size,
       unsigned int min_transfer_buffer_size,
-      unsigned int max_transfer_buffer_size);
+      unsigned int max_transfer_buffer_size,
+      unsigned int mapped_memory_limit);
 
   // The GLES2CmdHelper being used by this GLES2Implementation. You can use
   // this to issue cmds at a lower level for certain kinds of optimization.
@@ -215,7 +219,6 @@
       GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
       GLint* size, GLenum* type, char* name);
 
-  void SetSharedMemoryChunkSizeMultiple(unsigned int multiple);
 
   void FreeUnusedSharedMemory();
   void FreeEverything();
@@ -668,7 +671,7 @@
 
   scoped_ptr<std::string> current_trace_name_;
 
-  ImageFactory* image_factory_;
+  GpuControl* gpu_control_;
 
   DISALLOW_COPY_AND_ASSIGN(GLES2Implementation);
 };
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index e58907c..84fa749 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -366,6 +366,8 @@
     helper_.reset(new GLES2CmdHelper(command_buffer()));
     helper_->Initialize(kCommandBufferSizeBytes);
 
+    gpu_control_.reset(new StrictMock<MockClientGpuControl>());
+
     GLES2Implementation::GLStaticState state;
     GLES2Implementation::GLStaticState::IntState& int_state = state.int_state;
     int_state.max_combined_texture_image_units = kMaxCombinedTextureImageUnits;
@@ -401,11 +403,12 @@
           NULL,
           transfer_buffer_.get(),
           bind_generates_resource,
-          NULL));
+          gpu_control_.get()));
       ASSERT_TRUE(gl_->Initialize(
           kTransferBufferSize,
           kTransferBufferSize,
-          kTransferBufferSize));
+          kTransferBufferSize,
+          GLES2Implementation::kNoLimit));
     }
 
     EXPECT_CALL(*command_buffer(), OnFlush())
@@ -473,6 +476,7 @@
 
   Sequence sequence_;
   scoped_ptr<MockClientCommandBuffer> command_buffer_;
+  scoped_ptr<MockClientGpuControl> gpu_control_;
   scoped_ptr<GLES2CmdHelper> helper_;
   scoped_ptr<MockTransferBuffer> transfer_buffer_;
   scoped_ptr<GLES2Implementation> gl_;
@@ -2476,7 +2480,8 @@
       "GL_CHROMIUM_flipy "
       "GL_CHROMIUM_map_sub "
       "GL_CHROMIUM_shallow_flush "
-      "GL_EXT_unpack_subimage";
+      "GL_EXT_unpack_subimage "
+      "GL_CHROMIUM_map_image";
   const char kBad = 0x12;
   struct Cmds {
     cmd::SetBucketSize set_bucket_size1;
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc b/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
index c1c9b4d..a957cc4 100644
--- a/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
+++ b/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
@@ -6,15 +6,13 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/image_factory.h"
-#include "ui/gfx/gpu_memory_buffer.h"
+#include "gpu/command_buffer/common/gpu_control.h"
 
 namespace gpu {
 namespace gles2 {
 
-GpuMemoryBufferTracker::GpuMemoryBufferTracker(ImageFactory* factory)
-    : buffers_(),
-      factory_(factory) {
+GpuMemoryBufferTracker::GpuMemoryBufferTracker(GpuControl* gpu_control)
+    : gpu_control_(gpu_control) {
 }
 
 GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
@@ -23,37 +21,33 @@
   }
 }
 
-GLuint GpuMemoryBufferTracker::CreateBuffer(
-    GLsizei width, GLsizei height, GLenum internalformat) {
-  GLuint image_id = 0;
-  DCHECK(factory_);
-  scoped_ptr<gfx::GpuMemoryBuffer> buffer =
-      factory_->CreateGpuMemoryBuffer(width, height, internalformat, &image_id);
-
-  if (buffer.get() == NULL)
+int32 GpuMemoryBufferTracker::CreateBuffer(
+    size_t width, size_t height, int32 internalformat) {
+  int32 image_id = 0;
+  DCHECK(gpu_control_);
+  gfx::GpuMemoryBuffer* buffer = gpu_control_->CreateGpuMemoryBuffer(
+      width, height, internalformat, &image_id);
+  if (!buffer)
     return 0;
 
   std::pair<BufferMap::iterator, bool> result =
-      buffers_.insert(std::make_pair(image_id, buffer.release()));
+      buffers_.insert(std::make_pair(image_id, buffer));
   GPU_DCHECK(result.second);
 
   return image_id;
 }
 
-gfx::GpuMemoryBuffer* GpuMemoryBufferTracker::GetBuffer(GLuint image_id) {
+gfx::GpuMemoryBuffer* GpuMemoryBufferTracker::GetBuffer(int32 image_id) {
   BufferMap::iterator it = buffers_.find(image_id);
   return (it != buffers_.end()) ? it->second : NULL;
 }
 
-void GpuMemoryBufferTracker::RemoveBuffer(GLuint image_id) {
+void GpuMemoryBufferTracker::RemoveBuffer(int32 image_id) {
   BufferMap::iterator buffer_it = buffers_.find(image_id);
-  if (buffer_it != buffers_.end()) {
-    gfx::GpuMemoryBuffer* buffer = buffer_it->second;
+  if (buffer_it != buffers_.end())
     buffers_.erase(buffer_it);
-    delete buffer;
-  }
-  DCHECK(factory_);
-  factory_->DeleteGpuMemoryBuffer(image_id);
+  DCHECK(gpu_control_);
+  gpu_control_->DestroyGpuMemoryBuffer(image_id);
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_tracker.h b/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
index 1192b17..0b07dd0 100644
--- a/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
+++ b/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
@@ -5,8 +5,6 @@
 #ifndef GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
 #define GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
 
-#include <GLES2/gl2.h>
-
 #include "base/basictypes.h"
 #include "gles2_impl_export.h"
 #include "gpu/command_buffer/client/hash_tables.h"
@@ -16,25 +14,24 @@
 }
 
 namespace gpu {
+class GpuControl;
+
 namespace gles2 {
-class ImageFactory;
 
 // Tracks GPU memory buffer objects on the client side.
 class GLES2_IMPL_EXPORT GpuMemoryBufferTracker {
  public:
-  // Ownership of |factory| remains with caller.
-  explicit GpuMemoryBufferTracker(ImageFactory* factory);
+  explicit GpuMemoryBufferTracker(GpuControl* gpu_control);
   virtual ~GpuMemoryBufferTracker();
 
-  GLuint CreateBuffer(
-      GLsizei width, GLsizei height, GLenum internalformat);
-  gfx::GpuMemoryBuffer* GetBuffer(GLuint image_id);
-  void RemoveBuffer(GLuint image_id);
+  int32 CreateBuffer(size_t width, size_t height, int32 internalformat);
+  gfx::GpuMemoryBuffer* GetBuffer(int32 image_id);
+  void RemoveBuffer(int32 image_id);
 
  private:
-  typedef gpu::hash_map<GLuint, gfx::GpuMemoryBuffer*> BufferMap;
+  typedef gpu::hash_map<int32, gfx::GpuMemoryBuffer*> BufferMap;
   BufferMap buffers_;
-  ImageFactory* factory_;
+  GpuControl* gpu_control_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferTracker);
 };
diff --git a/gpu/command_buffer/client/image_factory.h b/gpu/command_buffer/client/image_factory.h
deleted file mode 100644
index 449c8a4..0000000
--- a/gpu/command_buffer/client/image_factory.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 GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
-#define GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
-
-#include <GLES2/gl2.h>
-
-#include "base/memory/scoped_ptr.h"
-#include "gles2_impl_export.h"
-
-namespace gfx {
-class GpuMemoryBuffer;
-}
-
-namespace gpu {
-namespace gles2 {
-
-class GLES2_IMPL_EXPORT ImageFactory {
-
- public:
-  virtual ~ImageFactory() {}
-
-  // Create a GpuMemoryBuffer and makes it available to the
-  // service side by inserting it to the ImageManager.
-  virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      int width, int height, GLenum internalformat, unsigned* image_id) = 0;
-  virtual void DeleteGpuMemoryBuffer(unsigned image_id) = 0;
-};
-
-}  // namespace gles2
-}  // namespace gpu
-
-#endif  // GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index 82829d4..c367e69 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <functional>
 
+#include "base/debug/trace_event.h"
 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
 
 namespace gpu {
@@ -18,9 +19,12 @@
       allocator_(shm.size, helper, shm.ptr) {
 }
 
-MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper)
+MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper,
+                                         size_t unused_memory_reclaim_limit)
     : chunk_size_multiple_(1),
-      helper_(helper) {
+      helper_(helper),
+      allocated_memory_(0),
+      max_free_bytes_(unused_memory_reclaim_limit) {
 }
 
 MappedMemoryManager::~MappedMemoryManager() {
@@ -36,16 +40,38 @@
     unsigned int size, int32* shm_id, unsigned int* shm_offset) {
   GPU_DCHECK(shm_id);
   GPU_DCHECK(shm_offset);
-  // See if any of the chucks can satisfy this request.
-  for (size_t ii = 0; ii < chunks_.size(); ++ii) {
-    MemoryChunk* chunk = chunks_[ii];
-    chunk->FreeUnused();
-    if (chunk->GetLargestFreeSizeWithoutWaiting() >= size) {
-      void* mem = chunk->Alloc(size);
-      GPU_DCHECK(mem);
-      *shm_id = chunk->shm_id();
-      *shm_offset = chunk->GetOffset(mem);
-      return mem;
+  if (size <= allocated_memory_) {
+    size_t total_bytes_in_use = 0;
+    // See if any of the chunks can satisfy this request.
+    for (size_t ii = 0; ii < chunks_.size(); ++ii) {
+      MemoryChunk* chunk = chunks_[ii];
+      chunk->FreeUnused();
+      total_bytes_in_use += chunk->bytes_in_use();
+      if (chunk->GetLargestFreeSizeWithoutWaiting() >= size) {
+        void* mem = chunk->Alloc(size);
+        GPU_DCHECK(mem);
+        *shm_id = chunk->shm_id();
+        *shm_offset = chunk->GetOffset(mem);
+        return mem;
+      }
+    }
+
+    // If there is a memory limit being enforced and total free
+    // memory (allocated_memory_ - total_bytes_in_use) is larger than
+    // the limit try waiting.
+    if (max_free_bytes_ != kNoLimit &&
+        (allocated_memory_ - total_bytes_in_use) >= max_free_bytes_) {
+      TRACE_EVENT0("gpu", "MappedMemoryManager::Alloc::wait");
+      for (size_t ii = 0; ii < chunks_.size(); ++ii) {
+        MemoryChunk* chunk = chunks_[ii];
+        if (chunk->GetLargestFreeSizeWithWaiting() >= size) {
+          void* mem = chunk->Alloc(size);
+          GPU_DCHECK(mem);
+          *shm_id = chunk->shm_id();
+          *shm_offset = chunk->GetOffset(mem);
+          return mem;
+        }
+      }
     }
   }
 
@@ -59,6 +85,7 @@
   if (id  < 0)
     return NULL;
   MemoryChunk* mc = new MemoryChunk(id, shm, helper_);
+  allocated_memory_ += mc->GetSize();
   chunks_.push_back(mc);
   void* mem = mc->Alloc(size);
   GPU_DCHECK(mem);
@@ -97,6 +124,7 @@
     chunk->FreeUnused();
     if (!chunk->InUse()) {
       cmd_buf->DestroyTransferBuffer(chunk->shm_id());
+      allocated_memory_ -= chunk->GetSize();
       iter = chunks_.erase(iter);
     } else {
       ++iter;
@@ -105,6 +133,3 @@
 }
 
 }  // namespace gpu
-
-
-
diff --git a/gpu/command_buffer/client/mapped_memory.h b/gpu/command_buffer/client/mapped_memory.h
index ec70c43..db73ca7 100644
--- a/gpu/command_buffer/client/mapped_memory.h
+++ b/gpu/command_buffer/client/mapped_memory.h
@@ -79,7 +79,7 @@
     allocator_.FreePendingToken(pointer, token);
   }
 
-  // Frees any blocks who's tokens have passed.
+  // Frees any blocks whose tokens have passed.
   void FreeUnused() {
     allocator_.FreeUnused();
   }
@@ -90,11 +90,15 @@
            pointer < reinterpret_cast<const int8*>(shm_.ptr) + shm_.size;
   }
 
-  // Returns true of any memory in this chuck is in use.
+  // Returns true of any memory in this chunk is in use.
   bool InUse() {
     return allocator_.InUse();
   }
 
+  size_t bytes_in_use() const {
+    return allocator_.bytes_in_use();
+  }
+
  private:
   int32 shm_id_;
   gpu::Buffer shm_;
@@ -103,10 +107,17 @@
   DISALLOW_COPY_AND_ASSIGN(MemoryChunk);
 };
 
-// Manages MemoryChucks.
+// Manages MemoryChunks.
 class GPU_EXPORT MappedMemoryManager {
  public:
-  explicit MappedMemoryManager(CommandBufferHelper* helper);
+  enum MemoryLimit {
+    kNoLimit = 0,
+  };
+
+  // |unused_memory_reclaim_limit|: When exceeded this causes pending memory
+  // to be reclaimed before allocating more memory.
+  MappedMemoryManager(CommandBufferHelper* helper,
+                      size_t unused_memory_reclaim_limit);
 
   ~MappedMemoryManager();
 
@@ -146,10 +157,15 @@
   void FreeUnused();
 
   // Used for testing
-  size_t num_chunks() {
+  size_t num_chunks() const {
     return chunks_.size();
   }
 
+  // Used for testing
+  size_t allocated_memory() const {
+    return allocated_memory_;
+  }
+
  private:
   typedef ScopedVector<MemoryChunk> MemoryChunkVector;
 
@@ -157,6 +173,8 @@
   unsigned int chunk_size_multiple_;
   CommandBufferHelper* helper_;
   MemoryChunkVector chunks_;
+  size_t allocated_memory_;
+  size_t max_free_bytes_;
 
   DISALLOW_COPY_AND_ASSIGN(MappedMemoryManager);
 };
diff --git a/gpu/command_buffer/client/mapped_memory_unittest.cc b/gpu/command_buffer/client/mapped_memory_unittest.cc
index 99e6e8d..90d1ce7 100644
--- a/gpu/command_buffer/client/mapped_memory_unittest.cc
+++ b/gpu/command_buffer/client/mapped_memory_unittest.cc
@@ -149,7 +149,8 @@
  protected:
   virtual void SetUp() {
     MappedMemoryTestBase::SetUp();
-    manager_.reset(new MappedMemoryManager(helper_.get()));
+    manager_.reset(new MappedMemoryManager(
+        helper_.get(), MappedMemoryManager::kNoLimit));
   }
 
   virtual void TearDown() {
@@ -306,4 +307,81 @@
   EXPECT_EQ(0u, offset3);
 }
 
+TEST_F(MappedMemoryManagerTest, UnusedMemoryLimit) {
+  const unsigned int kChunkSize = 2048;
+  // Reset the manager with a memory limit.
+  manager_.reset(new MappedMemoryManager(helper_.get(), kChunkSize));
+  manager_->set_chunk_size_multiple(kChunkSize);
+
+  // Allocate one chunk worth of memory.
+  int32 id1 = -1;
+  unsigned int offset1 = 0xFFFFFFFFU;
+  void* mem1 = manager_->Alloc(kChunkSize, &id1, &offset1);
+  ASSERT_TRUE(mem1);
+  EXPECT_NE(-1, id1);
+  EXPECT_EQ(0u, offset1);
+
+  // Allocate half a chunk worth of memory again.
+  // The same chunk will be used.
+  int32 id2 = -1;
+  unsigned int offset2 = 0xFFFFFFFFU;
+  void* mem2 = manager_->Alloc(kChunkSize, &id2, &offset2);
+  ASSERT_TRUE(mem2);
+  EXPECT_NE(-1, id2);
+  EXPECT_EQ(0u, offset2);
+
+  // Expect two chunks to be allocated, exceeding the limit,
+  // since all memory is in use.
+  EXPECT_EQ(2 * kChunkSize, manager_->allocated_memory());
+}
+
+TEST_F(MappedMemoryManagerTest, MemoryLimitWithReuse) {
+  const unsigned int kSize = 1024;
+  // Reset the manager with a memory limit.
+  manager_.reset(new MappedMemoryManager(helper_.get(), kSize));
+  const unsigned int kChunkSize = 2 * 1024;
+  manager_->set_chunk_size_multiple(kChunkSize);
+
+  // Allocate half a chunk worth of memory.
+  int32 id1 = -1;
+  unsigned int offset1 = 0xFFFFFFFFU;
+  void* mem1 = manager_->Alloc(kSize, &id1, &offset1);
+  ASSERT_TRUE(mem1);
+  EXPECT_NE(-1, id1);
+  EXPECT_EQ(0u, offset1);
+
+  // Allocate half a chunk worth of memory again.
+  // The same chunk will be used.
+  int32 id2 = -1;
+  unsigned int offset2 = 0xFFFFFFFFU;
+  void* mem2 = manager_->Alloc(kSize, &id2, &offset2);
+  ASSERT_TRUE(mem2);
+  EXPECT_NE(-1, id2);
+  EXPECT_EQ(kSize, offset2);
+
+  // Free one successful allocation, pending fence.
+  int32 token = helper_.get()->InsertToken();
+  manager_->FreePendingToken(mem2, token);
+
+  // The way we hooked up the helper and engine, it won't process commands
+  // until it has to wait for something. Which means the token shouldn't have
+  // passed yet at this point.
+  EXPECT_GT(token, GetToken());
+
+  // Since we didn't call helper_.finish() the token did not pass.
+  // We won't be able to claim the free memory without waiting and
+  // as we've already met the memory limit we'll have to wait
+  // on the token.
+  int32 id3 = -1;
+  unsigned int offset3 = 0xFFFFFFFFU;
+  void* mem3 = manager_->Alloc(kSize, &id3, &offset3);
+  ASSERT_TRUE(mem3);
+  EXPECT_NE(-1, id3);
+  // It will reuse the space from the second allocation just freed.
+  EXPECT_EQ(kSize, offset3);
+
+  // Expect one chunk to be allocated
+  EXPECT_EQ(1 * kChunkSize, manager_->allocated_memory());
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/query_tracker_unittest.cc b/gpu/command_buffer/client/query_tracker_unittest.cc
index 2dad335..800c479 100644
--- a/gpu/command_buffer/client/query_tracker_unittest.cc
+++ b/gpu/command_buffer/client/query_tracker_unittest.cc
@@ -28,7 +28,8 @@
     command_buffer_.reset(new MockClientCommandBuffer());
     helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
     helper_->Initialize(kCommandBufferSizeBytes);
-    mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+    mapped_memory_.reset(new MappedMemoryManager(
+        helper_.get(), MappedMemoryManager::kNoLimit));
     sync_manager_.reset(new QuerySyncManager(mapped_memory_.get()));
   }
 
@@ -81,7 +82,8 @@
     command_buffer_.reset(new MockClientCommandBuffer());
     helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
     helper_->Initialize(kCommandBufferSizeBytes);
-    mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+    mapped_memory_.reset(new MappedMemoryManager(
+        helper_.get(), MappedMemoryManager::kNoLimit));
     query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
   }
 
diff --git a/gpu/command_buffer/command_buffer_untrusted.gyp b/gpu/command_buffer/command_buffer_untrusted.gyp
index 8f27a0b..0667fd8 100644
--- a/gpu/command_buffer/command_buffer_untrusted.gyp
+++ b/gpu/command_buffer/command_buffer_untrusted.gyp
@@ -21,7 +21,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libgles2_utils_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'dependencies': [
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 37c7a53..76bb3fe 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -56,7 +56,6 @@
   kTextures,
   kQueries,
   kVertexArrays,
-  kImages,
   kNumIdNamespaces
 };
 
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 25eafcd..301ef4a 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -715,7 +715,29 @@
   return true;
 }
 
-ContextCreationAttribParser::ContextCreationAttribParser()
+namespace {
+
+// From <EGL/egl.h>.
+const int32 kAlphaSize       = 0x3021;  // EGL_ALPHA_SIZE
+const int32 kBlueSize        = 0x3022;  // EGL_BLUE_SIZE
+const int32 kGreenSize       = 0x3023;  // EGL_GREEN_SIZE
+const int32 kRedSize         = 0x3024;  // EGL_RED_SIZE
+const int32 kDepthSize       = 0x3025;  // EGL_DEPTH_SIZE
+const int32 kStencilSize     = 0x3026;  // EGL_STENCIL_SIZE
+const int32 kSamples         = 0x3031;  // EGL_SAMPLES
+const int32 kSampleBuffers   = 0x3032;  // EGL_SAMPLE_BUFFERS
+const int32 kNone            = 0x3038;  // EGL_NONE
+const int32 kSwapBehavior    = 0x3093;  // EGL_SWAP_BEHAVIOR
+const int32 kBufferPreserved = 0x3094;  // EGL_BUFFER_PRESERVED
+const int32 kBufferDestroyed = 0x3095;  // EGL_BUFFER_DESTROYED
+
+// Chromium only.
+const int32 kShareResources        = 0x10000;
+const int32 kBindGeneratesResource = 0x10001;
+
+}  // namespace
+
+ContextCreationAttribHelper::ContextCreationAttribHelper()
   : alpha_size_(-1),
     blue_size_(-1),
     green_size_(-1),
@@ -729,28 +751,53 @@
     bind_generates_resource_(true) {
 }
 
-bool ContextCreationAttribParser::Parse(const std::vector<int32>& attribs) {
-  // From <EGL/egl.h>.
-  const int32 EGL_ALPHA_SIZE = 0x3021;
-  const int32 EGL_BLUE_SIZE = 0x3022;
-  const int32 EGL_GREEN_SIZE = 0x3023;
-  const int32 EGL_RED_SIZE = 0x3024;
-  const int32 EGL_DEPTH_SIZE = 0x3025;
-  const int32 EGL_STENCIL_SIZE = 0x3026;
-  const int32 EGL_SAMPLES = 0x3031;
-  const int32 EGL_SAMPLE_BUFFERS = 0x3032;
-  const int32 EGL_NONE = 0x3038;
-  const int32 EGL_SWAP_BEHAVIOR = 0x3093;
-  const int32 EGL_BUFFER_PRESERVED = 0x3094;
+void ContextCreationAttribHelper::Serialize(std::vector<int32>* attribs) {
+  if (alpha_size_ != -1) {
+    attribs->push_back(kAlphaSize);
+    attribs->push_back(alpha_size_);
+  }
+  if (blue_size_ != -1) {
+    attribs->push_back(kBlueSize);
+    attribs->push_back(blue_size_);
+  }
+  if (green_size_ != -1) {
+    attribs->push_back(kGreenSize);
+    attribs->push_back(green_size_);
+  }
+  if (red_size_ != -1) {
+    attribs->push_back(kRedSize);
+    attribs->push_back(red_size_);
+  }
+  if (depth_size_ != -1) {
+    attribs->push_back(kDepthSize);
+    attribs->push_back(depth_size_);
+  }
+  if (stencil_size_ != -1) {
+    attribs->push_back(kStencilSize);
+    attribs->push_back(stencil_size_);
+  }
+  if (samples_ != -1) {
+    attribs->push_back(kSamples);
+    attribs->push_back(samples_);
+  }
+  if (sample_buffers_ != -1) {
+    attribs->push_back(kSampleBuffers);
+    attribs->push_back(sample_buffers_);
+  }
+  attribs->push_back(kSwapBehavior);
+  attribs->push_back(buffer_preserved_ ? kBufferPreserved : kBufferDestroyed);
+  attribs->push_back(kShareResources);
+  attribs->push_back(share_resources_ ? 1 : 0);
+  attribs->push_back(kBindGeneratesResource);
+  attribs->push_back(bind_generates_resource_ ? 1 : 0);
+  attribs->push_back(kNone);
+}
 
-  // Chromium only.
-  const int32 SHARE_RESOURCES           = 0x10000;
-  const int32 BIND_GENERATES_RESOURCES  = 0x10001;
-
+bool ContextCreationAttribHelper::Parse(const std::vector<int32>& attribs) {
   for (size_t i = 0; i < attribs.size(); i += 2) {
     const int32 attrib = attribs[i];
     if (i + 1 >= attribs.size()) {
-      if (attrib == EGL_NONE) {
+      if (attrib == kNone) {
         return true;
       }
 
@@ -761,40 +808,40 @@
 
     const int32 value = attribs[i+1];
     switch (attrib) {
-      case EGL_ALPHA_SIZE:
+      case kAlphaSize:
         alpha_size_ = value;
         break;
-      case EGL_BLUE_SIZE:
+      case kBlueSize:
         blue_size_ = value;
         break;
-      case EGL_GREEN_SIZE:
+      case kGreenSize:
         green_size_ = value;
         break;
-      case EGL_RED_SIZE:
+      case kRedSize:
         red_size_ = value;
         break;
-      case EGL_DEPTH_SIZE:
+      case kDepthSize:
         depth_size_ = value;
         break;
-      case EGL_STENCIL_SIZE:
+      case kStencilSize:
         stencil_size_ = value;
         break;
-      case EGL_SAMPLES:
+      case kSamples:
         samples_ = value;
         break;
-      case EGL_SAMPLE_BUFFERS:
+      case kSampleBuffers:
         sample_buffers_ = value;
         break;
-      case EGL_SWAP_BEHAVIOR:
-        buffer_preserved_ = value == EGL_BUFFER_PRESERVED;
+      case kSwapBehavior:
+        buffer_preserved_ = value == kBufferPreserved;
         break;
-      case SHARE_RESOURCES:
+      case kShareResources:
         share_resources_ = value != 0;
         break;
-      case BIND_GENERATES_RESOURCES:
+      case kBindGeneratesResource:
         bind_generates_resource_ = value != 0;
         break;
-      case EGL_NONE:
+      case kNone:
         // Terminate list, even if more attributes.
         return true;
       default:
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 4bc4b1b..b8619e6 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -174,9 +174,11 @@
   int num_shader_binary_formats_;
 };
 
-class GLES2_UTILS_EXPORT ContextCreationAttribParser {
+class GLES2_UTILS_EXPORT ContextCreationAttribHelper {
  public:
-  ContextCreationAttribParser();
+  ContextCreationAttribHelper();
+
+  void Serialize(std::vector<int32>* attribs);
   bool Parse(const std::vector<int32>& attribs);
 
   // -1 if invalid or unspecified.
diff --git a/gpu/command_buffer/common/gpu_control.h b/gpu/command_buffer/common/gpu_control.h
new file mode 100644
index 0000000..5534ca7
--- /dev/null
+++ b/gpu/command_buffer/common/gpu_control.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 GPU_COMMAND_BUFFER_COMMON_GPU_CONTROL_H_
+#define GPU_COMMAND_BUFFER_COMMON_GPU_CONTROL_H_
+
+#include "gpu/gpu_export.h"
+
+namespace gfx {
+class GpuMemoryBuffer;
+}
+
+namespace gpu {
+
+// Common interface for GpuControl implementations.
+class GPU_EXPORT GpuControl {
+ public:
+  GpuControl() {}
+  virtual ~GpuControl() {}
+
+  // Create a gpu memory buffer of the given dimensions and format. Returns
+  // its ID or -1 on error.
+  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat,
+      int32* id) = 0;
+
+  // Destroy a gpu memory buffer. The ID must be positive.
+  virtual void DestroyGpuMemoryBuffer(int32 id) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GpuControl);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_COMMON_GPU_CONTROL_H_
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 0cf991a..90932fb 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -67,7 +67,6 @@
   id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator);
   id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator);
   id_namespaces_[id_namespaces::kVertexArrays].reset(new IdAllocator);
-  id_namespaces_[id_namespaces::kImages].reset(new IdAllocator);
 }
 
 static void GetIntegerv(GLenum pname, uint32* var) {
diff --git a/gpu/command_buffer/service/disk_cache_proto.proto b/gpu/command_buffer/service/disk_cache_proto.proto
index c165443..2c504aa 100644
--- a/gpu/command_buffer/service/disk_cache_proto.proto
+++ b/gpu/command_buffer/service/disk_cache_proto.proto
@@ -5,12 +5,14 @@
   optional int32 size = 2;
   optional string name = 3;
   optional string key = 4;
+  optional int32 precision = 5;
 }
 
 message ShaderProto {
   optional bytes sha = 1;
   repeated ShaderInfoProto attribs = 2;
   repeated ShaderInfoProto uniforms = 3;
+  repeated ShaderInfoProto varyings = 4;
 }
 
 message GpuProgramProto {
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index b468262..b4c6b09 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -203,6 +203,13 @@
     uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
         attachment_type, max_color_attachments);
     uint32 have = GLES2Util::GetChannelsForFormat(internal_format);
+
+    // Workaround for NVIDIA drivers that incorrectly expose these formats as
+    // renderable:
+    if (internal_format == GL_LUMINANCE || internal_format == GL_ALPHA ||
+        internal_format == GL_LUMINANCE_ALPHA) {
+      return false;
+    }
     return (need & have) != 0;
   }
 
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index 176e3e2..aa11118 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -180,6 +180,15 @@
   DISALLOW_COPY_AND_ASSIGN(Framebuffer);
 };
 
+struct DecoderFramebufferState {
+  DecoderFramebufferState():
+      clear_state_dirty(true) {}
+
+  // State saved for clearing so we can clear render buffers and then
+  // restore to these values.
+  bool clear_state_dirty;
+};
+
 // This class keeps track of the frambebuffers and their attached renderbuffers
 // so we can correctly clear them.
 class GPU_EXPORT FramebufferManager {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index a9b1f1e..77a6b8a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -349,18 +349,6 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedResolvedFrameBufferBinder);
 };
 
-// This class records texture upload time when in scope.
-class ScopedTextureUploadTimer {
- public:
-  explicit ScopedTextureUploadTimer(GLES2DecoderImpl* decoder);
-  ~ScopedTextureUploadTimer();
-
- private:
-  GLES2DecoderImpl* decoder_;
-  base::TimeTicks begin_time_;
-  DISALLOW_COPY_AND_ASSIGN(ScopedTextureUploadTimer);
-};
-
 // Encapsulates an OpenGL texture.
 class BackTexture {
  public:
@@ -651,7 +639,6 @@
   friend class ScopedFrameBufferBinder;
   friend class ScopedGLErrorSuppressor;
   friend class ScopedResolvedFrameBufferBinder;
-  friend class ScopedTextureUploadTimer;
   friend class BackTexture;
   friend class BackRenderbuffer;
   friend class BackFramebuffer;
@@ -813,33 +800,6 @@
       GLsizei width,
       GLsizei height);
 
-  // Validation for TexImage2D commands.
-  bool ValidateTexImage2D(
-      const char* function_name,
-      GLenum target,
-      GLint level,
-      GLenum internal_format,
-      GLsizei width,
-      GLsizei height,
-      GLint border,
-      GLenum format,
-      GLenum type,
-      const void* pixels,
-      uint32 pixels_size);
-
-  // Wrapper for TexImage2D commands.
-  void DoTexImage2D(
-      GLenum target,
-      GLint level,
-      GLenum internal_format,
-      GLsizei width,
-      GLsizei height,
-      GLint border,
-      GLenum format,
-      GLenum type,
-      const void* pixels,
-      uint32 pixels_size);
-
   // Validation for TexSubImage2D.
   bool ValidateTexSubImage2D(
       error::Error* error,
@@ -1427,46 +1387,6 @@
       bool instanced, GLenum mode, GLsizei count, GLenum type,
       int32 offset, GLsizei primcount);
 
-  // Gets the texture id for a given target.
-  TextureRef* GetTextureInfoForTarget(GLenum target) {
-    TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
-    TextureRef* texture = NULL;
-    switch (target) {
-      case GL_TEXTURE_2D:
-        texture = unit.bound_texture_2d.get();
-        break;
-      case GL_TEXTURE_CUBE_MAP:
-      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-        texture = unit.bound_texture_cube_map.get();
-        break;
-      case GL_TEXTURE_EXTERNAL_OES:
-        texture = unit.bound_texture_external_oes.get();
-        break;
-      case GL_TEXTURE_RECTANGLE_ARB:
-        texture = unit.bound_texture_rectangle_arb.get();
-        break;
-      default:
-        NOTREACHED();
-        return NULL;
-    }
-    return texture;
-  }
-
-  TextureRef* GetTextureInfoForTargetUnlessDefault(
-      GLenum target) {
-    TextureRef* texture = GetTextureInfoForTarget(target);
-    if (!texture)
-      return NULL;
-    if (texture == texture_manager()->GetDefaultTextureInfo(target))
-      return NULL;
-    return texture;
-  }
-
   GLenum GetBindTargetForSamplerType(GLenum type) {
     DCHECK(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE ||
            type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_2D_RECT_ARB);
@@ -1642,10 +1562,6 @@
   // The size of fiixed attrib buffer.
   GLsizei fixed_attrib_buffer_size_;
 
-  // state saved for clearing so we can clear render buffers and then
-  // restore to these values.
-  bool clear_state_dirty_;
-
   // The offscreen frame buffer that the client renders to. With EGL, the
   // depth and stencil buffers are separate. With regular GL there is a single
   // packed depth stencil buffer in offscreen_target_depth_render_buffer_.
@@ -1692,8 +1608,6 @@
   // Backbuffer attachments that are currently undefined.
   uint32 backbuffer_needs_clear_bits_;
 
-  bool teximage2d_faster_than_texsubimage2d_;
-
   // The current decoder error.
   error::Error current_decoder_error_;
 
@@ -1707,10 +1621,6 @@
   const Validators* validators_;
   scoped_refptr<FeatureInfo> feature_info_;
 
-  // This indicates all the following texSubImage2D calls that are part of the
-  // failed texImage2D call should be ignored.
-  bool tex_image_2d_failed_;
-
   int frame_number_;
 
   bool has_robustness_extension_;
@@ -1744,10 +1654,12 @@
   GLsizei viewport_max_height_;
 
   // Command buffer stats.
-  int texture_upload_count_;
-  base::TimeDelta total_texture_upload_time_;
   base::TimeDelta total_processing_commands_time_;
 
+  // States related to each manager.
+  DecoderTextureState texture_state_;
+  DecoderFramebufferState framebuffer_state_;
+
   scoped_ptr<GPUTracer> gpu_tracer_;
 
   std::queue<linked_ptr<FenceCallback> > pending_readpixel_fences_;
@@ -1881,17 +1793,6 @@
   }
 }
 
-ScopedTextureUploadTimer::ScopedTextureUploadTimer(GLES2DecoderImpl* decoder)
-    : decoder_(decoder),
-      begin_time_(base::TimeTicks::HighResNow()) {
-}
-
-ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
-  decoder_->texture_upload_count_++;
-  decoder_->total_texture_upload_time_ +=
-      base::TimeTicks::HighResNow() - begin_time_;
-}
-
 BackTexture::BackTexture(GLES2DecoderImpl* decoder)
     : decoder_(decoder),
       memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged),
@@ -2156,7 +2057,6 @@
       attrib_0_size_(0),
       fixed_attrib_buffer_id_(0),
       fixed_attrib_buffer_size_(0),
-      clear_state_dirty_(true),
       offscreen_target_color_format_(0),
       offscreen_target_depth_format_(0),
       offscreen_target_stencil_format_(0),
@@ -2167,12 +2067,10 @@
       back_buffer_has_depth_(false),
       back_buffer_has_stencil_(false),
       backbuffer_needs_clear_bits_(0),
-      teximage2d_faster_than_texsubimage2d_(true),
       current_decoder_error_(error::kNoError),
       use_shader_translator_(true),
       validators_(group_->feature_info()->validators()),
       feature_info_(group_->feature_info()),
-      tex_image_2d_failed_(false),
       frame_number_(0),
       has_robustness_extension_(false),
       reset_status_(GL_NO_ERROR),
@@ -2185,8 +2083,7 @@
       service_logging_(CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableGPUServiceLoggingGPU)),
       viewport_max_width_(0),
-      viewport_max_height_(0),
-      texture_upload_count_(0) {
+      viewport_max_height_(0) {
   DCHECK(group);
 
   attrib_0_value_.v[0] = 0.0f;
@@ -2207,7 +2104,7 @@
 
   // TODO(gman): Consider setting this based on GPU and/or driver.
   if (IsAngle()) {
-    teximage2d_faster_than_texsubimage2d_ = false;
+    texture_state_.teximage2d_faster_than_texsubimage2d = false;
   }
 }
 
@@ -2310,7 +2207,7 @@
   glActiveTexture(GL_TEXTURE0);
   CHECK_GL_ERROR();
 
-  ContextCreationAttribParser attrib_parser;
+  ContextCreationAttribHelper attrib_parser;
   if (!attrib_parser.Parse(attribs))
     return false;
 
@@ -2717,7 +2614,7 @@
     if (framebuffer && !framebuffer->IsDeleted()) {
       if (framebuffer == state_.bound_draw_framebuffer.get()) {
         state_.bound_draw_framebuffer = NULL;
-        clear_state_dirty_ = true;
+        framebuffer_state_.clear_state_dirty = true;
         GLenum target = supports_separate_framebuffer_binds ?
             GL_DRAW_FRAMEBUFFER_EXT : GL_FRAMEBUFFER;
         glBindFramebufferEXT(target, GetBackbufferServiceId());
@@ -2761,7 +2658,7 @@
               ->UnbindRenderbuffer(GL_FRAMEBUFFER, renderbuffer);
         }
       }
-      clear_state_dirty_ = true;
+      framebuffer_state_.clear_state_dirty = true;
       RemoveRenderbuffer(client_ids[ii]);
     }
   }
@@ -2776,7 +2673,7 @@
     if (texture_ref) {
       Texture* texture = texture_ref->texture();
       if (texture->IsAttachedToFramebuffer()) {
-        clear_state_dirty_ = true;
+        framebuffer_state_.clear_state_dirty = true;
       }
       // Unbind texture_ref from texture_ref units.
       for (size_t jj = 0; jj < state_.texture_units.size(); ++jj) {
@@ -2835,7 +2732,7 @@
   if (workarounds().unbind_fbo_on_context_switch)
     RestoreFramebufferBindings();
 
-  clear_state_dirty_ = true;
+  framebuffer_state_.clear_state_dirty = true;
 
   return true;
 }
@@ -2879,7 +2776,7 @@
 }
 
 void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() {
-  clear_state_dirty_ = true;
+  framebuffer_state_.clear_state_dirty = true;
 
   if (!features().chromium_framebuffer_multisample) {
     RebindCurrentFramebuffer(
@@ -3075,7 +2972,8 @@
       offscreen_saved_color_texture_info_.get(),
       GL_TEXTURE_WRAP_T,
       GL_CLAMP_TO_EDGE);
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   glBindTexture(target, texture_ref ? texture_ref->service_id() : 0);
 }
 
@@ -3127,12 +3025,12 @@
 }
 
 uint32 GLES2DecoderImpl::GetTextureUploadCount() {
-  return texture_upload_count_ +
+  return texture_state_.texture_upload_count +
          async_pixel_transfer_manager_->GetTextureUploadCount();
 }
 
 base::TimeDelta GLES2DecoderImpl::GetTotalTextureUploadTime() {
-  return total_texture_upload_time_ +
+  return texture_state_.total_texture_upload_time +
          async_pixel_transfer_manager_->GetTotalTextureUploadTime();
 }
 
@@ -3678,7 +3576,7 @@
 }
 
 void GLES2DecoderImpl::ApplyDirtyState() {
-  if (clear_state_dirty_) {
+  if (framebuffer_state_.clear_state_dirty) {
     glColorMask(
         state_.color_mask_red, state_.color_mask_green, state_.color_mask_blue,
         state_.color_mask_alpha &&
@@ -3696,7 +3594,7 @@
     EnableDisable(GL_CULL_FACE, state_.enable_flags.cull_face);
     EnableDisable(GL_SCISSOR_TEST, state_.enable_flags.scissor_test);
     EnableDisable(GL_BLEND, state_.enable_flags.blend);
-    clear_state_dirty_ = false;
+    framebuffer_state_.clear_state_dirty = false;
   }
 }
 
@@ -3804,7 +3702,7 @@
     state_.bound_read_framebuffer = framebuffer;
   }
 
-  clear_state_dirty_ = true;
+  framebuffer_state_.clear_state_dirty = true;
 
   // If we are rendering to the backbuffer get the FBO id for any simulated
   // backbuffer.
@@ -3982,7 +3880,8 @@
 }
 
 void GLES2DecoderImpl::DoGenerateMipmap(GLenum target) {
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref ||
       !texture_manager()->CanGenerateMipmaps(texture_ref)) {
     LOCAL_SET_GL_ERROR(
@@ -4758,7 +4657,7 @@
     framebuffer->AttachRenderbuffer(attachment, renderbuffer);
   }
   if (framebuffer == state_.bound_draw_framebuffer.get()) {
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
   OnFboChanged();
 }
@@ -4842,7 +4741,7 @@
 }
 
 void GLES2DecoderImpl::RestoreClearState() {
-  clear_state_dirty_ = true;
+  framebuffer_state_.clear_state_dirty = true;
   glClearColor(
       state_.color_clear_red, state_.color_clear_green, state_.color_clear_blue,
       state_.color_clear_alpha);
@@ -4942,7 +4841,7 @@
          samples);
   }
   if (framebuffer == state_.bound_draw_framebuffer.get()) {
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
   OnFboChanged();
 }
@@ -5181,7 +5080,8 @@
 
 void GLES2DecoderImpl::DoTexParameterf(
     GLenum target, GLenum pname, GLfloat param) {
-  TextureRef* texture = GetTextureInfoForTarget(target);
+  TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture) {
     LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameterf", "unknown texture");
     return;
@@ -5194,7 +5094,8 @@
 
 void GLES2DecoderImpl::DoTexParameteri(
     GLenum target, GLenum pname, GLint param) {
-  TextureRef* texture = GetTextureInfoForTarget(target);
+  TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture) {
     LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameteri", "unknown texture");
     return;
@@ -5206,7 +5107,8 @@
 
 void GLES2DecoderImpl::DoTexParameterfv(
     GLenum target, GLenum pname, const GLfloat* params) {
-  TextureRef* texture = GetTextureInfoForTarget(target);
+  TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture) {
     LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameterfv", "unknown texture");
     return;
@@ -5219,7 +5121,8 @@
 
 void GLES2DecoderImpl::DoTexParameteriv(
   GLenum target, GLenum pname, const GLint* params) {
-  TextureRef* texture = GetTextureInfoForTarget(target);
+  TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_VALUE, "glTexParameteriv", "unknown texture");
@@ -7420,7 +7323,8 @@
     }
     y += tile_height;
   }
-  TextureRef* texture = GetTextureInfoForTarget(bind_target);
+  TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+      &state_, bind_target);
   glBindTexture(bind_target, texture ? texture->service_id() : 0);
   return true;
 }
@@ -7595,7 +7499,8 @@
         "glCompressedTexImage2D", "dimensions out of range");
     return error::kNoError;
   }
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_VALUE,
@@ -7624,7 +7529,7 @@
   }
 
   if (texture->IsAttachedToFramebuffer()) {
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
 
   scoped_ptr<int8[]> zero;
@@ -7759,176 +7664,16 @@
   return error::kNoError;
 }
 
-bool GLES2DecoderImpl::ValidateTextureParameters(
-    const char* function_name,
-    GLenum target, GLenum format, GLenum type, GLint level) {
-  if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
-      LOCAL_SET_GL_ERROR(
-          GL_INVALID_OPERATION, function_name,
-          (std::string("invalid type ") +
-           GLES2Util::GetStringEnum(type) + " for format " +
-           GLES2Util::GetStringEnum(format)).c_str());
-      return false;
-  }
-
-  uint32 channels = GLES2Util::GetChannelsForFormat(format);
-  if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, function_name,
-        (std::string("invalid type ") +
-         GLES2Util::GetStringEnum(type) + " for format " +
-         GLES2Util::GetStringEnum(format)).c_str());
-    return false;
-  }
-  return true;
-}
-
-bool GLES2DecoderImpl::ValidateTexImage2D(
-    const char* function_name,
-    GLenum target,
-    GLint level,
-    GLenum internal_format,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    const void* pixels,
-    uint32 pixels_size) {
-  if (!validators_->texture_target.IsValid(target)) {
-    LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target");
-    return false;
-  }
-  if (!validators_->texture_format.IsValid(internal_format)) {
-    LOCAL_SET_GL_ERROR_INVALID_ENUM(
-        function_name, internal_format, "internal_format");
-    return false;
-  }
-  if (!validators_->texture_format.IsValid(format)) {
-    LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, format, "format");
-    return false;
-  }
-  if (!validators_->pixel_type.IsValid(type)) {
-    LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, type, "type");
-    return false;
-  }
-  if (format != internal_format) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, function_name, "format != internalFormat");
-    return false;
-  }
-  if (!ValidateTextureParameters(function_name, target, format, type, level)) {
-    return false;
-  }
-  if (!texture_manager()->ValidForTarget(target, level, width, height, 1) ||
-      border != 0) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, function_name, "dimensions out of range");
-    return false;
-  }
-  if ((GLES2Util::GetChannelsForFormat(format) &
-       (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && pixels) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION,
-        function_name, "can not supply data for depth or stencil textures");
-    return false;
-  }
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
-  if (!texture_ref) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, function_name, "unknown texture for target");
-    return false;
-  }
-  if (texture_ref->texture()->IsImmutable()) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, function_name, "texture is immutable");
-    return false;
-  }
-  return true;
-}
-
-void GLES2DecoderImpl::DoTexImage2D(
-    GLenum target,
-    GLint level,
-    GLenum internal_format,
-    GLsizei width,
-    GLsizei height,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    const void* pixels,
-    uint32 pixels_size) {
-  if (!ValidateTexImage2D("glTexImage2D", target, level, internal_format,
-      width, height, border, format, type, pixels, pixels_size)) {
-    return;
-  }
-
-  if (!EnsureGPUMemoryAvailable(pixels_size)) {
-    LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory");
-    return;
-  }
-
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
-  Texture* texture = texture_ref->texture();
-  GLsizei tex_width = 0;
-  GLsizei tex_height = 0;
-  GLenum tex_type = 0;
-  GLenum tex_format = 0;
-  bool level_is_same =
-      texture->GetLevelSize(target, level, &tex_width, &tex_height) &&
-      texture->GetLevelType(target, level, &tex_type, &tex_format) &&
-      width == tex_width && height == tex_height &&
-      type == tex_type && format == tex_format;
-
-  if (level_is_same && !pixels) {
-    // Just set the level texture but mark the texture as uncleared.
-    texture_manager()->SetLevelInfo(
-        texture_ref,
-        target, level, internal_format, width, height, 1, border, format, type,
-        false);
-    tex_image_2d_failed_ = false;
-    return;
-  }
-
-  if (texture->IsAttachedToFramebuffer()) {
-    clear_state_dirty_ = true;
-  }
-
-  if (!teximage2d_faster_than_texsubimage2d_ && level_is_same && pixels) {
-    {
-      ScopedTextureUploadTimer timer(this);
-      glTexSubImage2D(target, level, 0, 0, width, height, format, type, pixels);
-    }
-    texture_manager()->SetLevelCleared(texture_ref, target, level, true);
-    tex_image_2d_failed_ = false;
-    return;
-  }
-
-  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glTexImage2D");
-  {
-    ScopedTextureUploadTimer timer(this);
-    glTexImage2D(
-        target, level, internal_format, width, height, border, format, type,
-        pixels);
-  }
-  GLenum error = LOCAL_PEEK_GL_ERROR("glTexImage2D");
-  if (error == GL_NO_ERROR) {
-    texture_manager()->SetLevelInfo(
-        texture_ref,
-        target, level, internal_format, width, height, 1, border, format, type,
-        pixels != NULL);
-    tex_image_2d_failed_ = false;
-  }
-  return;
-}
-
 error::Error GLES2DecoderImpl::HandleTexImage2D(
     uint32 immediate_data_size, const cmds::TexImage2D& c) {
   TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleTexImage2D");
-  tex_image_2d_failed_ = true;
+  // Set as failed for now, but if it successed, this will be set to not failed.
+  texture_state_.tex_image_2d_failed = true;
   GLenum target = static_cast<GLenum>(c.target);
   GLint level = static_cast<GLint>(c.level);
-  GLint internal_format = static_cast<GLint>(c.internalformat);
+  // TODO(kloveless): Change TexImage2D command to use unsigned integer
+  // for internalformat.
+  GLenum internal_format = static_cast<GLenum>(c.internalformat);
   GLsizei width = static_cast<GLsizei>(c.width);
   GLsizei height = static_cast<GLsizei>(c.height);
   GLint border = static_cast<GLint>(c.border);
@@ -7951,9 +7696,11 @@
     }
   }
 
-  DoTexImage2D(
-      target, level, internal_format, width, height, border, format, type,
-      pixels, pixels_size);
+  TextureManager::DoTextImage2DArguments args = {
+    target, level, internal_format, width, height, border, format, type,
+    pixels, pixels_size};
+  texture_manager()->ValidateAndDoTexImage2D(
+      &texture_state_, &state_, &framebuffer_state_, args);
   return error::kNoError;
 }
 
@@ -7961,7 +7708,9 @@
     uint32 immediate_data_size, const cmds::TexImage2DImmediate& c) {
   GLenum target = static_cast<GLenum>(c.target);
   GLint level = static_cast<GLint>(c.level);
-  GLint internal_format = static_cast<GLint>(c.internalformat);
+  // TODO(kloveless): Change TexImage2DImmediate command to use unsigned
+  // integer for internalformat.
+  GLenum internal_format = static_cast<GLenum>(c.internalformat);
   GLsizei width = static_cast<GLsizei>(c.width);
   GLsizei height = static_cast<GLsizei>(c.height);
   GLint border = static_cast<GLint>(c.border);
@@ -7978,9 +7727,12 @@
   if (!pixels) {
     return error::kOutOfBounds;
   }
-  DoTexImage2D(
-      target, level, internal_format, width, height, border, format, type,
-      pixels, size);
+
+  TextureManager::DoTextImage2DArguments args = {
+    target, level, internal_format, width, height, border, format, type,
+    pixels, size};
+  texture_manager()->ValidateAndDoTexImage2D(
+      &texture_state_, &state_, &framebuffer_state_, args);
   return error::kNoError;
 }
 
@@ -7994,7 +7746,8 @@
   GLenum format,
   GLsizei image_size,
   const void * data) {
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -8067,7 +7820,8 @@
     GLsizei height,
     GLint border) {
   DCHECK(!ShouldDeferReads());
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -8085,8 +7839,9 @@
         GL_INVALID_VALUE, "glCopyTexImage2D", "dimensions out of range");
     return;
   }
-  if (!ValidateTextureParameters(
-      "glCopyTexImage2D", target, internal_format, GL_UNSIGNED_BYTE, level)) {
+  if (!texture_manager()->ValidateTextureParameters(
+      state_.GetErrorState(), "glCopyTexImage2D", target, internal_format,
+      GL_UNSIGNED_BYTE, level)) {
     return;
   }
 
@@ -8131,7 +7886,7 @@
   gfx::Size size = GetBoundReadFrameBufferSize();
 
   if (texture->IsAttachedToFramebuffer()) {
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
 
   // Clip to size to source dimensions
@@ -8186,7 +7941,8 @@
     GLsizei width,
     GLsizei height) {
   DCHECK(!ShouldDeferReads());
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -8312,7 +8068,8 @@
     LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, type, "type");
     return false;
   }
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -8379,7 +8136,8 @@
       xoffset, yoffset, width, height, format, type, data)) {
     return error;
   }
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   Texture* texture = texture_ref->texture();
   GLsizei tex_width = 0;
   GLsizei tex_height = 0;
@@ -8393,20 +8151,21 @@
           GL_OUT_OF_MEMORY, "glTexSubImage2D", "dimensions too big");
       return error::kNoError;
     }
-    ScopedTextureUploadTimer timer(this);
+    ScopedTextureUploadTimer timer(&texture_state_);
     glTexSubImage2D(
         target, level, xoffset, yoffset, width, height, format, type, data);
     return error::kNoError;
   }
 
-  if (teximage2d_faster_than_texsubimage2d_ && !texture->IsImmutable()) {
-    ScopedTextureUploadTimer timer(this);
+  if (texture_state_.teximage2d_faster_than_texsubimage2d &&
+      !texture->IsImmutable()) {
+    ScopedTextureUploadTimer timer(&texture_state_);
     // NOTE: In OpenGL ES 2.0 border is always zero and format is always the
     // same as internal_foramt. If that changes we'll need to look them up.
     glTexImage2D(
         target, level, format, width, height, 0, format, type, data);
   } else {
-    ScopedTextureUploadTimer timer(this);
+    ScopedTextureUploadTimer timer(&texture_state_);
     glTexSubImage2D(
         target, level, xoffset, yoffset, width, height, format, type, data);
   }
@@ -8418,7 +8177,7 @@
     uint32 immediate_data_size, const cmds::TexSubImage2D& c) {
   TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleTexSubImage2D");
   GLboolean internal = static_cast<GLboolean>(c.internal);
-  if (internal == GL_TRUE && tex_image_2d_failed_)
+  if (internal == GL_TRUE && texture_state_.tex_image_2d_failed)
     return error::kNoError;
 
   GLenum target = static_cast<GLenum>(c.target);
@@ -8444,7 +8203,7 @@
 error::Error GLES2DecoderImpl::HandleTexSubImage2DImmediate(
     uint32 immediate_data_size, const cmds::TexSubImage2DImmediate& c) {
   GLboolean internal = static_cast<GLboolean>(c.internal);
-  if (internal == GL_TRUE && tex_image_2d_failed_)
+  if (internal == GL_TRUE && texture_state_.tex_image_2d_failed)
     return error::kNoError;
 
   GLenum target = static_cast<GLenum>(c.target);
@@ -9564,7 +9323,8 @@
 
   // Default target might be conceptually valid, but disallow it to avoid
   // accidents.
-  TextureRef* texture_ref = GetTextureInfoForTargetUnlessDefault(target);
+  TextureRef* texture_ref =
+      texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -9879,7 +9639,8 @@
         GL_INVALID_VALUE, "glTexStorage2DEXT", "dimensions out of range");
     return;
   }
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -9888,7 +9649,7 @@
   }
   Texture* texture = texture_ref->texture();
   if (texture->IsAttachedToFramebuffer()) {
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
   if (texture->IsImmutable()) {
     LOCAL_SET_GL_ERROR(
@@ -9960,7 +9721,8 @@
       "context", logger_.GetLogPrefix(),
       "mailbox[0]", static_cast<unsigned char>(mailbox[0]));
 
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -9994,7 +9756,7 @@
       "mailbox[0]", static_cast<unsigned char>(mailbox[0]));
 
   scoped_refptr<TextureRef> texture_ref =
-      GetTextureInfoForTargetUnlessDefault(target);
+      texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
   if (!texture_ref.get()) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
                        "glConsumeTextureCHROMIUM",
@@ -10085,7 +9847,8 @@
 
   // Default target might be conceptually valid, but disallow it to avoid
   // accidents.
-  TextureRef* texture_ref = GetTextureInfoForTargetUnlessDefault(target);
+  TextureRef* texture_ref =
+      texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -10132,7 +9895,8 @@
 
   // Default target might be conceptually valid, but disallow it to avoid
   // accidents.
-  TextureRef* texture_ref = GetTextureInfoForTargetUnlessDefault(target);
+  TextureRef* texture_ref =
+      texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
   if (!texture_ref) {
     LOCAL_SET_GL_ERROR(
         GL_INVALID_OPERATION,
@@ -10273,7 +10037,9 @@
   TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM");
   GLenum target = static_cast<GLenum>(c.target);
   GLint level = static_cast<GLint>(c.level);
-  GLint internal_format = static_cast<GLint>(c.internalformat);
+  // TODO(kloveless): Change HandleAsyncTexImage2DCHROMIUM command to use
+  // unsigned integer for internalformat.
+  GLenum internal_format = static_cast<GLenum>(c.internalformat);
   GLsizei width = static_cast<GLsizei>(c.width);
   GLsizei height = static_cast<GLsizei>(c.height);
   GLint border = static_cast<GLint>(c.border);
@@ -10299,15 +10065,17 @@
     }
   }
 
+  TextureManager::DoTextImage2DArguments args = {
+    target, level, internal_format, width, height, border, format, type,
+    pixels, pixels_size};
+  TextureRef* texture_ref;
   // All the normal glTexSubImage2D validation.
-  if (!ValidateTexImage2D(
-      "glAsyncTexImage2DCHROMIUM", target, level, internal_format,
-      width, height, border, format, type, pixels, pixels_size)) {
+  if (!texture_manager()->ValidateTexImage2D(
+      &state_, "glAsyncTexImage2DCHROMIUM", args, &texture_ref)) {
     return error::kNoError;
   }
 
   // Extra async validation.
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
   Texture* texture = texture_ref->texture();
   if (!ValidateAsyncTransfer(
       "glAsyncTexImage2DCHROMIUM", texture_ref, target, level, pixels))
@@ -10394,7 +10162,8 @@
   }
 
   // Extra async validation.
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   Texture* texture = texture_ref->texture();
   if (!ValidateAsyncTransfer(
          "glAsyncTexSubImage2DCHROMIUM", texture_ref, target, level, pixels))
@@ -10462,7 +10231,8 @@
         GL_INVALID_ENUM, "glWaitAsyncTexImage2DCHROMIUM", "target");
     return error::kNoError;
   }
-  TextureRef* texture_ref = GetTextureInfoForTarget(target);
+  TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+      &state_, target);
   if (!texture_ref) {
       LOCAL_SET_GL_ERROR(
           GL_INVALID_OPERATION,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index a992e34..393c902 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -319,7 +319,7 @@
     state_.color_mask_green = green;
     state_.color_mask_blue = blue;
     state_.color_mask_alpha = alpha;
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
   return error::kNoError;
 }
@@ -678,7 +678,7 @@
   GLboolean flag = static_cast<GLboolean>(c.flag);
   if (state_.depth_mask != flag) {
     state_.depth_mask = flag;
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
   return error::kNoError;
 }
@@ -1698,7 +1698,7 @@
       state_.stencil_back_writemask != mask) {
     state_.stencil_front_writemask = mask;
     state_.stencil_back_writemask = mask;
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
   return error::kNoError;
 }
@@ -1725,7 +1725,7 @@
     if (face == GL_BACK || face == GL_FRONT_AND_BACK) {
       state_.stencil_back_writemask = mask;
     }
-    clear_state_dirty_ = true;
+    framebuffer_state_.clear_state_dirty = true;
   }
   return error::kNoError;
 }
@@ -3332,7 +3332,7 @@
     case GL_DEPTH_TEST:
       if (state_.enable_flags.depth_test != enabled) {
         state_.enable_flags.depth_test = enabled;
-        clear_state_dirty_ = true;
+        framebuffer_state_.clear_state_dirty = true;
       }
       return false;
     case GL_DITHER:
@@ -3350,13 +3350,13 @@
     case GL_SCISSOR_TEST:
       if (state_.enable_flags.scissor_test != enabled) {
         state_.enable_flags.scissor_test = enabled;
-        clear_state_dirty_ = true;
+        framebuffer_state_.clear_state_dirty = true;
       }
       return false;
     case GL_STENCIL_TEST:
       if (state_.enable_flags.stencil_test != enabled) {
         state_.enable_flags.stencil_test = enabled;
-        clear_state_dirty_ = true;
+        framebuffer_state_.clear_state_dirty = true;
       }
       return false;
     default:
diff --git a/gpu/command_buffer/service/gpu_control_service.cc b/gpu/command_buffer/service/gpu_control_service.cc
new file mode 100644
index 0000000..d368ff9
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_control_service.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 "gpu/command_buffer/service/gpu_control_service.h"
+
+#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/gpu_memory_buffer_manager.h"
+
+namespace gpu {
+
+GpuControlService::GpuControlService(
+    GpuMemoryBufferManagerInterface* gpu_memory_buffer_manager,
+    GpuMemoryBufferFactory* gpu_memory_buffer_factory)
+    : gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+      gpu_memory_buffer_factory_(gpu_memory_buffer_factory) {
+}
+
+GpuControlService::~GpuControlService() {
+}
+
+gfx::GpuMemoryBuffer* GpuControlService::CreateGpuMemoryBuffer(
+    size_t width,
+    size_t height,
+    unsigned internalformat,
+    int32* id) {
+  *id = -1;
+
+  CHECK(gpu_memory_buffer_factory_) << "No GPU memory buffer factory provided";
+  linked_ptr<gfx::GpuMemoryBuffer> buffer = make_linked_ptr(
+      gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(width,
+                                                        height,
+                                                        internalformat));
+  if (!buffer.get())
+    return NULL;
+
+  static int32 next_id = 1;
+  *id = next_id++;
+
+  if (!RegisterGpuMemoryBuffer(*id,
+                               buffer->GetHandle(),
+                               width,
+                               height,
+                               internalformat)) {
+    *id = -1;
+    return NULL;
+  }
+
+  gpu_memory_buffers_[*id] = buffer;
+  return buffer.get();
+}
+
+void GpuControlService::DestroyGpuMemoryBuffer(int32 id) {
+  GpuMemoryBufferMap::iterator it = gpu_memory_buffers_.find(id);
+  if (it != gpu_memory_buffers_.end())
+    gpu_memory_buffers_.erase(it);
+
+  gpu_memory_buffer_manager_->DestroyGpuMemoryBuffer(id);
+}
+
+bool GpuControlService::RegisterGpuMemoryBuffer(
+    int32 id,
+    gfx::GpuMemoryBufferHandle buffer,
+    size_t width,
+    size_t height,
+    unsigned internalformat) {
+  return gpu_memory_buffer_manager_->RegisterGpuMemoryBuffer(id,
+                                                             buffer,
+                                                             width,
+                                                             height,
+                                                             internalformat);
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_control_service.h b/gpu/command_buffer/service/gpu_control_service.h
new file mode 100644
index 0000000..a12fee4
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_control_service.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 GPU_COMMAND_BUFFER_SERVICE_GPU_CONTROL_SERVICE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_CONTROL_SERVICE_H_
+
+#include <map>
+
+#include "base/memory/linked_ptr.h"
+#include "gpu/command_buffer/common/gpu_control.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace gpu {
+class GpuMemoryBufferFactory;
+class GpuMemoryBufferManagerInterface;
+
+class GPU_EXPORT GpuControlService : public GpuControl {
+ public:
+  GpuControlService(GpuMemoryBufferManagerInterface* gpu_memory_buffer_manager,
+                    GpuMemoryBufferFactory* gpu_memory_buffer_factory);
+  virtual ~GpuControlService();
+
+  // Overridden from GpuControl:
+  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat,
+      int32* id) OVERRIDE;
+  virtual void DestroyGpuMemoryBuffer(int32 id) OVERRIDE;
+
+  // Register an existing gpu memory buffer and get an ID that can be used
+  // to identify it in the command buffer.
+  bool RegisterGpuMemoryBuffer(int32 id,
+                               gfx::GpuMemoryBufferHandle buffer,
+                               size_t width,
+                               size_t height,
+                               unsigned internalformat);
+
+ private:
+  GpuMemoryBufferManagerInterface* gpu_memory_buffer_manager_;
+  GpuMemoryBufferFactory* gpu_memory_buffer_factory_;
+  typedef std::map<int32, linked_ptr<gfx::GpuMemoryBuffer> > GpuMemoryBufferMap;
+  GpuMemoryBufferMap gpu_memory_buffers_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuControlService);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GPU_CONTROL_SERVICE_H_
diff --git a/gpu/command_buffer/service/gpu_memory_buffer_manager.h b/gpu/command_buffer/service/gpu_memory_buffer_manager.h
new file mode 100644
index 0000000..fb44ede
--- /dev/null
+++ b/gpu/command_buffer/service/gpu_memory_buffer_manager.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 GPU_COMMAND_BUFFER_SERVICE_GPU_MEMORY_BUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_MEMORY_BUFFER_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "gpu/gpu_export.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace gpu {
+
+class GPU_EXPORT GpuMemoryBufferManagerInterface {
+ public:
+  virtual ~GpuMemoryBufferManagerInterface() {}
+
+  virtual bool RegisterGpuMemoryBuffer(int32 id,
+                                       gfx::GpuMemoryBufferHandle buffer,
+                                       size_t width,
+                                       size_t height,
+                                       unsigned internalformat) = 0;
+  virtual void DestroyGpuMemoryBuffer(int32 id) = 0;
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GPU_MEMORY_BUFFER_MANAGER_H_
diff --git a/gpu/command_buffer/service/image_manager.cc b/gpu/command_buffer/service/image_manager.cc
index 6be4e66..a09af15 100644
--- a/gpu/command_buffer/service/image_manager.cc
+++ b/gpu/command_buffer/service/image_manager.cc
@@ -15,6 +15,36 @@
 ImageManager::~ImageManager() {
 }
 
+bool ImageManager::RegisterGpuMemoryBuffer(int32 id,
+                                           gfx::GpuMemoryBufferHandle buffer,
+                                           size_t width,
+                                           size_t height,
+                                           unsigned internalformat) {
+  if (id <= 0) {
+    DVLOG(0) << "Cannot register GPU memory buffer with non-positive ID.";
+    return false;
+  }
+
+  if (LookupImage(id)) {
+    DVLOG(0) << "GPU memory buffer ID already in use.";
+    return false;
+  }
+
+  scoped_refptr<gfx::GLImage> gl_image =
+      gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer,
+                                                    gfx::Size(width, height),
+                                                    internalformat);
+  if (!gl_image)
+    return false;
+
+  AddImage(gl_image.get(), id);
+  return true;
+}
+
+void ImageManager::DestroyGpuMemoryBuffer(int32 id) {
+  RemoveImage(id);
+}
+
 void ImageManager::AddImage(gfx::GLImage* image, int32 service_id) {
   gl_images_[service_id] = image;
 }
diff --git a/gpu/command_buffer/service/image_manager.h b/gpu/command_buffer/service/image_manager.h
index 1b42146..a125ae8 100644
--- a/gpu/command_buffer/service/image_manager.h
+++ b/gpu/command_buffer/service/image_manager.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/containers/hash_tables.h"
 #include "base/memory/ref_counted.h"
+#include "gpu/command_buffer/service/gpu_memory_buffer_manager.h"
 #include "gpu/gpu_export.h"
 
 namespace gfx {
@@ -18,10 +19,20 @@
 namespace gles2 {
 
 // Interface used by the cmd decoder to lookup images.
-class GPU_EXPORT ImageManager : public base::RefCounted<ImageManager> {
+class GPU_EXPORT ImageManager
+    : public GpuMemoryBufferManagerInterface,
+      public base::RefCounted<ImageManager> {
  public:
   ImageManager();
 
+  // Overridden from GpuMemoryBufferManagerInterface:
+  virtual bool RegisterGpuMemoryBuffer(int32 id,
+                                       gfx::GpuMemoryBufferHandle buffer,
+                                       size_t width,
+                                       size_t height,
+                                       unsigned internalformat) OVERRIDE;
+  virtual void DestroyGpuMemoryBuffer(int32 id) OVERRIDE;
+
   void AddImage(gfx::GLImage* gl_image, int32 service_id);
   void RemoveImage(int32 service_id);
   gfx::GLImage* LookupImage(int32 service_id);
@@ -29,7 +40,7 @@
  private:
   friend class base::RefCounted<ImageManager>;
 
-  ~ImageManager();
+  virtual ~ImageManager();
 
   typedef base::hash_map<uint32, scoped_refptr<gfx::GLImage> > GLImageMap;
   GLImageMap gl_images_;
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index ccbfb32..6b9fe8a 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -22,10 +22,10 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/sequence_checker.h"
 #include "base/threading/thread.h"
-#include "gpu/command_buffer/common/id_allocator.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gl_context_virtual.h"
+#include "gpu/command_buffer/service/gpu_control_service.h"
 #include "gpu/command_buffer/service/gpu_scheduler.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
@@ -34,6 +34,11 @@
 #include "ui/gl/gl_image.h"
 #include "ui/gl/gl_share_group.h"
 
+#if defined(OS_ANDROID)
+#include "gpu/command_buffer/service/stream_texture_manager_in_process_android.h"
+#include "ui/gl/android/surface_texture_bridge.h"
+#endif
+
 namespace gpu {
 
 namespace {
@@ -43,6 +48,7 @@
 
 static bool g_use_virtualized_gl_context = false;
 static bool g_uses_explicit_scheduling = false;
+static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
 
 template <typename T>
 static void RunTaskWithResult(base::Callback<T(void)> task,
@@ -378,11 +384,21 @@
       share_group = new gfx::GLShareGroup;
   }
 
+  StreamTextureManager* stream_texture_manager = NULL;
+#if defined(OS_ANDROID)
+  stream_texture_manager = stream_texture_manager_ =
+      context_group ? context_group->stream_texture_manager_.get()
+                    : new StreamTextureManagerInProcess;
+#endif
+
   bool bind_generates_resource = false;
   decoder_.reset(gles2::GLES2Decoder::Create(
       context_group ? context_group->decoder_->GetContextGroup()
-                    : new gles2::ContextGroup(
-                          NULL, NULL, NULL, NULL, bind_generates_resource)));
+                    : new gles2::ContextGroup(NULL,
+                                              NULL,
+                                              NULL,
+                                              stream_texture_manager,
+                                              bind_generates_resource)));
 
   gpu_scheduler_.reset(
       new GpuScheduler(command_buffer.get(), decoder_.get(), decoder_.get()));
@@ -390,6 +406,10 @@
       &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
   command_buffer_ = command_buffer.Pass();
 
+  gpu_control_.reset(
+      new GpuControlService(decoder_->GetContextGroup()->image_manager(),
+                            g_gpu_memory_buffer_factory));
+
   decoder_->set_engine(gpu_scheduler_.get());
 
   if (!surface_) {
@@ -496,55 +516,6 @@
          sequence_checker_->CalledOnValidSequencedThread());
 }
 
-unsigned int InProcessCommandBuffer::CreateImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer,
-    gfx::Size size) {
-  CheckSequencedThread();
-  unsigned int image_id;
-  {
-    // TODO: ID allocation should go through CommandBuffer
-    base::AutoLock lock(command_buffer_lock_);
-    gles2::ContextGroup* group = decoder_->GetContextGroup();
-    image_id =
-        group->GetIdAllocator(gles2::id_namespaces::kImages)->AllocateID();
-  }
-  base::Closure image_task =
-      base::Bind(&InProcessCommandBuffer::CreateImageOnGpuThread,
-                 base::Unretained(this), buffer, size, image_id);
-  QueueTask(image_task);
-  return image_id;
-}
-
-void InProcessCommandBuffer::CreateImageOnGpuThread(
-    gfx::GpuMemoryBufferHandle buffer,
-    gfx::Size size,
-    unsigned int image_id) {
-  CheckSequencedThread();
-  scoped_refptr<gfx::GLImage> gl_image =
-      gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer, size);
-   decoder_->GetContextGroup()->image_manager()->AddImage(gl_image, image_id);
-}
-
-void InProcessCommandBuffer::RemoveImage(unsigned int image_id) {
-  CheckSequencedThread();
-  {
-    // TODO: ID allocation should go through CommandBuffer
-    base::AutoLock lock(command_buffer_lock_);
-    gles2::ContextGroup* group = decoder_->GetContextGroup();
-    group->GetIdAllocator(gles2::id_namespaces::kImages)->FreeID(image_id);
-  }
-  base::Closure image_manager_task =
-      base::Bind(&InProcessCommandBuffer::RemoveImageOnGpuThread,
-                 base::Unretained(this),
-                 image_id);
-  QueueTask(image_manager_task);
-}
-
-void InProcessCommandBuffer::RemoveImageOnGpuThread(unsigned int image_id) {
-  CheckSequencedThread();
-  decoder_->GetContextGroup()->image_manager()->RemoveImage(image_id);
-}
-
 void InProcessCommandBuffer::OnContextLost() {
   CheckSequencedThread();
   if (!context_lost_callback_.is_null()) {
@@ -680,6 +651,28 @@
   QueueTask(WrapCallback(callback));
 }
 
+gfx::GpuMemoryBuffer* InProcessCommandBuffer::CreateGpuMemoryBuffer(
+    size_t width,
+    size_t height,
+    unsigned internalformat,
+    int32* id) {
+  CheckSequencedThread();
+  base::AutoLock lock(command_buffer_lock_);
+  return gpu_control_->CreateGpuMemoryBuffer(width,
+                                             height,
+                                             internalformat,
+                                             id);
+}
+
+void InProcessCommandBuffer::DestroyGpuMemoryBuffer(int32 id) {
+  CheckSequencedThread();
+  base::Closure task = base::Bind(&GpuControl::DestroyGpuMemoryBuffer,
+                                  base::Unretained(gpu_control_.get()),
+                                  id);
+
+  QueueTask(task);
+}
+
 gpu::error::Error InProcessCommandBuffer::GetLastError() {
   CheckSequencedThread();
   return last_state_.error;
@@ -734,6 +727,14 @@
   return wrapped_callback;
 }
 
+#if defined(OS_ANDROID)
+scoped_refptr<gfx::SurfaceTextureBridge>
+InProcessCommandBuffer::GetSurfaceTexture(uint32 stream_id) {
+  DCHECK(stream_texture_manager_);
+  return stream_texture_manager_->GetSurfaceTexture(stream_id);
+}
+#endif
+
 // static
 void InProcessCommandBuffer::EnableVirtualizedContext() {
   g_use_virtualized_gl_context = true;
@@ -753,4 +754,10 @@
   g_gpu_queue.Get().RunTasks();
 }
 
+// static
+void InProcessCommandBuffer::SetGpuMemoryBufferFactory(
+    GpuMemoryBufferFactory* factory) {
+  g_gpu_memory_buffer_factory = factory;
+}
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index 9bdbd49..3caf4aa 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -14,6 +14,7 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/gpu_control.h"
 #include "gpu/gpu_export.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
@@ -26,17 +27,26 @@
 
 namespace gfx {
 class GLContext;
-class GLImage;
 class GLSurface;
 class Size;
 }
 
+#if defined(OS_ANDROID)
+namespace gfx {
+class SurfaceTextureBridge;
+}
+namespace gpu {
+class StreamTextureManagerInProcess;
+}
+#endif
+
 namespace gpu {
 
 namespace gles2 {
 class GLES2Decoder;
 }
 
+class GpuMemoryBufferFactory;
 class GpuScheduler;
 class TransferBufferManagerInterface;
 
@@ -44,7 +54,8 @@
 // example GPU thread) when being run in single process mode.
 // However, the behavior for accessing one context (i.e. one instance of this
 // class) from different client threads is undefined.
-class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer {
+class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer,
+                                          public GpuControl {
  public:
   InProcessCommandBuffer();
   virtual ~InProcessCommandBuffer();
@@ -61,6 +72,7 @@
   static void ProcessGpuWorkOnCurrentThread();
 
   static void EnableVirtualizedContext();
+  static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory);
 
   // If |surface| is not NULL, use it directly; in this case, the command
   // buffer gpu thread must be the same as the client thread. Otherwise create
@@ -78,10 +90,6 @@
   void Destroy();
   void SignalSyncPoint(unsigned sync_point,
                        const base::Closure& callback);
-  unsigned int CreateImageForGpuMemoryBuffer(
-      gfx::GpuMemoryBufferHandle buffer,
-      gfx::Size size);
-  void RemoveImage(unsigned int image_id);
 
   // CommandBuffer implementation:
   virtual bool Initialize() OVERRIDE;
@@ -102,6 +110,14 @@
   virtual uint32 InsertSyncPoint() OVERRIDE;
   virtual gpu::error::Error GetLastError() OVERRIDE;
 
+  // GpuControl implementation:
+  virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(
+      size_t width,
+      size_t height,
+      unsigned internalformat,
+      int32* id) OVERRIDE;
+  virtual void DestroyGpuMemoryBuffer(int32 id) OVERRIDE;
+
   // The serializer interface to the GPU service (i.e. thread).
   class SchedulerClient {
    public:
@@ -109,6 +125,11 @@
      virtual void QueueTask(const base::Closure& task) = 0;
   };
 
+#if defined(OS_ANDROID)
+  scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture(
+      uint32 stream_id);
+#endif
+
  private:
   bool InitializeOnGpuThread(bool is_offscreen,
                              gfx::AcceleratedWidget window,
@@ -118,10 +139,6 @@
                              gfx::GpuPreference gpu_preference);
   bool DestroyOnGpuThread();
   void FlushOnGpuThread(int32 put_offset);
-  void CreateImageOnGpuThread(gfx::GpuMemoryBufferHandle buffer,
-                              gfx::Size size,
-                              unsigned int image_id);
-  void RemoveImageOnGpuThread(unsigned int image_id);
   bool MakeCurrent();
   bool IsContextLost();
   base::Closure WrapCallback(const base::Closure& callback);
@@ -158,6 +175,11 @@
   scoped_ptr<SchedulerClient> queue_;
   State state_after_last_flush_;
   base::Lock state_after_last_flush_lock_;
+  scoped_ptr<GpuControl> gpu_control_;
+
+#if defined(OS_ANDROID)
+  scoped_refptr<StreamTextureManagerInProcess> stream_texture_manager_;
+#endif
 
   // Only used with explicit scheduling and the gpu thread is the same as
   // the client thread.
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index e09d132..3bff3dc 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -15,6 +15,7 @@
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 #include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/shader_translator.h"
 #include "ui/gl/gl_bindings.h"
 
 namespace {
@@ -40,31 +41,40 @@
 
 enum ShaderMapType {
   ATTRIB_MAP = 0,
-  UNIFORM_MAP
+  UNIFORM_MAP,
+  VARYING_MAP
 };
 
 void StoreShaderInfo(ShaderMapType type, ShaderProto *proto,
                      const ShaderTranslator::VariableMap& map) {
   ShaderTranslator::VariableMap::const_iterator iter;
-  for (iter = map.begin(); iter != map.end(); iter++) {
-    ShaderInfoProto* info;
-    if (type == UNIFORM_MAP) {
-      info = proto->add_uniforms();
-    } else {
-      info = proto->add_attribs();
+  for (iter = map.begin(); iter != map.end(); ++iter) {
+    ShaderInfoProto* info = NULL;
+    switch (type) {
+      case UNIFORM_MAP:
+        info = proto->add_uniforms();
+        break;
+      case ATTRIB_MAP:
+        info = proto->add_attribs();
+        break;
+      case VARYING_MAP:
+        info = proto->add_varyings();
+        break;
+      default: NOTREACHED();
     }
 
     info->set_key(iter->first);
     info->set_type(iter->second.type);
     info->set_size(iter->second.size);
+    info->set_precision(iter->second.precision);
     info->set_name(iter->second.name);
   }
 }
 
 void RetrieveShaderInfo(const ShaderInfoProto& proto,
                         ShaderTranslator::VariableMap* map) {
-  ShaderTranslator::VariableInfo info(proto.type(), proto.size(),
-                                      proto.name());
+  ShaderTranslator::VariableInfo info(
+      proto.type(), proto.size(), proto.precision(), proto.name());
   (*map)[proto.key()] = info;
 }
 
@@ -73,6 +83,7 @@
   proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength);
   StoreShaderInfo(ATTRIB_MAP, proto, shader->attrib_map());
   StoreShaderInfo(UNIFORM_MAP, proto, shader->uniform_map());
+  StoreShaderInfo(VARYING_MAP, proto, shader->varying_map());
 }
 
 void RunShaderCallback(const ShaderCacheCallback& callback,
@@ -147,8 +158,10 @@
   }
   shader_a->set_attrib_map(value->attrib_map_0());
   shader_a->set_uniform_map(value->uniform_map_0());
+  shader_a->set_varying_map(value->varying_map_0());
   shader_b->set_attrib_map(value->attrib_map_1());
   shader_b->set_uniform_map(value->uniform_map_1());
+  shader_b->set_varying_map(value->varying_map_1());
 
   if (!shader_callback.is_null() &&
       !CommandLine::ForCurrentProcess()->HasSwitch(
@@ -241,9 +254,11 @@
                                    a_sha,
                                    shader_a->attrib_map(),
                                    shader_a->uniform_map(),
+                                   shader_a->varying_map(),
                                    b_sha,
                                    shader_b->attrib_map(),
                                    shader_b->uniform_map(),
+                                   shader_b->varying_map(),
                                    this));
 
   UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
@@ -255,6 +270,7 @@
   if (proto->ParseFromString(program)) {
     ShaderTranslator::VariableMap vertex_attribs;
     ShaderTranslator::VariableMap vertex_uniforms;
+    ShaderTranslator::VariableMap vertex_varyings;
 
     for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
       RetrieveShaderInfo(proto->vertex_shader().attribs(i), &vertex_attribs);
@@ -264,8 +280,13 @@
       RetrieveShaderInfo(proto->vertex_shader().uniforms(i), &vertex_uniforms);
     }
 
+    for (int i = 0; i < proto->vertex_shader().varyings_size(); i++) {
+      RetrieveShaderInfo(proto->vertex_shader().varyings(i), &vertex_varyings);
+    }
+
     ShaderTranslator::VariableMap fragment_attribs;
     ShaderTranslator::VariableMap fragment_uniforms;
+    ShaderTranslator::VariableMap fragment_varyings;
 
     for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
       RetrieveShaderInfo(proto->fragment_shader().attribs(i),
@@ -277,6 +298,11 @@
                          &fragment_uniforms);
     }
 
+    for (int i = 0; i < proto->fragment_shader().varyings_size(); i++) {
+      RetrieveShaderInfo(proto->fragment_shader().varyings(i),
+                         &fragment_varyings);
+    }
+
     scoped_ptr<char[]> binary(new char[proto->program().length()]);
     memcpy(binary.get(), proto->program().c_str(), proto->program().length());
 
@@ -288,9 +314,11 @@
                                      proto->vertex_shader().sha().c_str(),
                                      vertex_attribs,
                                      vertex_uniforms,
+                                     vertex_varyings,
                                      proto->fragment_shader().sha().c_str(),
                                      fragment_attribs,
                                      fragment_uniforms,
+                                     fragment_varyings,
                                      this));
 
     UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
@@ -308,9 +336,11 @@
     const char* shader_0_hash,
     const ShaderTranslator::VariableMap& attrib_map_0,
     const ShaderTranslator::VariableMap& uniform_map_0,
+    const ShaderTranslator::VariableMap& varying_map_0,
     const char* shader_1_hash,
     const ShaderTranslator::VariableMap& attrib_map_1,
     const ShaderTranslator::VariableMap& uniform_map_1,
+    const ShaderTranslator::VariableMap& varying_map_1,
     MemoryProgramCache* program_cache)
     : length_(length),
       format_(format),
@@ -319,9 +349,11 @@
       shader_0_hash_(shader_0_hash, kHashLength),
       attrib_map_0_(attrib_map_0),
       uniform_map_0_(uniform_map_0),
+      varying_map_0_(varying_map_0),
       shader_1_hash_(shader_1_hash, kHashLength),
       attrib_map_1_(attrib_map_1),
       uniform_map_1_(uniform_map_1),
+      varying_map_1_(varying_map_1),
       program_cache_(program_cache) {
   program_cache_->curr_size_bytes_ += length_;
   program_cache_->LinkedProgramCacheSuccess(program_hash);
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index b2f23e6..e72f9f5 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -57,9 +57,11 @@
                       const char* shader_0_hash,
                       const ShaderTranslator::VariableMap& attrib_map_0,
                       const ShaderTranslator::VariableMap& uniform_map_0,
+                      const ShaderTranslator::VariableMap& varying_map_0,
                       const char* shader_1_hash,
                       const ShaderTranslator::VariableMap& attrib_map_1,
                       const ShaderTranslator::VariableMap& uniform_map_1,
+                      const ShaderTranslator::VariableMap& varying_map_1,
                       MemoryProgramCache* program_cache);
 
     GLsizei length() const {
@@ -86,6 +88,10 @@
       return uniform_map_0_;
     }
 
+    const ShaderTranslator::VariableMap& varying_map_0() const {
+      return varying_map_0_;
+    }
+
     const std::string& shader_1_hash() const {
       return shader_1_hash_;
     }
@@ -98,6 +104,10 @@
       return uniform_map_1_;
     }
 
+    const ShaderTranslator::VariableMap& varying_map_1() const {
+      return varying_map_1_;
+    }
+
    private:
     friend class base::RefCounted<ProgramCacheValue>;
 
@@ -110,9 +120,11 @@
     const std::string shader_0_hash_;
     const ShaderTranslator::VariableMap attrib_map_0_;
     const ShaderTranslator::VariableMap uniform_map_0_;
+    const ShaderTranslator::VariableMap varying_map_0_;
     const std::string shader_1_hash_;
     const ShaderTranslator::VariableMap attrib_map_1_;
     const ShaderTranslator::VariableMap uniform_map_1_;
+    const ShaderTranslator::VariableMap varying_map_1_;
     MemoryProgramCache* const program_cache_;
 
     DISALLOW_COPY_AND_ASSIGN(ProgramCacheValue);
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index 83fc12a..36291c4 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -108,19 +108,27 @@
     typedef ShaderTranslator::VariableMap VariableMap;
     VariableMap vertex_attrib_map;
     VariableMap vertex_uniform_map;
+    VariableMap vertex_varying_map;
     VariableMap fragment_attrib_map;
     VariableMap fragment_uniform_map;
+    VariableMap fragment_varying_map;
 
-    vertex_attrib_map["a"] = VariableInfo(1, 34, "a");
-    vertex_uniform_map["a"] = VariableInfo(0, 10, "a");
-    vertex_uniform_map["b"] = VariableInfo(2, 3114, "b");
-    fragment_attrib_map["jjjbb"] = VariableInfo(463, 1114, "jjjbb");
-    fragment_uniform_map["k"] = VariableInfo(10, 34413, "k");
+    vertex_attrib_map["a"] = VariableInfo(1, 34, SH_PRECISION_LOWP, "a");
+    vertex_uniform_map["a"] = VariableInfo(0, 10, SH_PRECISION_MEDIUMP,  "a");
+    vertex_uniform_map["b"] = VariableInfo(2, 3114, SH_PRECISION_HIGHP, "b");
+    vertex_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, "c");
+    fragment_attrib_map["jjjbb"] =
+        VariableInfo(463, 1114, SH_PRECISION_MEDIUMP, "jjjbb");
+    fragment_uniform_map["k"] =
+        VariableInfo(10, 34413, SH_PRECISION_MEDIUMP, "k");
+    fragment_varying_map["c"] = VariableInfo(3, 2, SH_PRECISION_HIGHP, "c");
 
     vertex_shader_->set_attrib_map(vertex_attrib_map);
     vertex_shader_->set_uniform_map(vertex_uniform_map);
+    vertex_shader_->set_varying_map(vertex_varying_map);
     fragment_shader_->set_attrib_map(vertex_attrib_map);
     fragment_shader_->set_uniform_map(vertex_uniform_map);
+    fragment_shader_->set_varying_map(vertex_varying_map);
 
     vertex_shader_->UpdateSource("bbbalsldkdkdkd");
     fragment_shader_->UpdateSource("bbbal   sldkdkdkas 134 ad");
@@ -262,13 +270,17 @@
 
   VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
   VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
+  VariableMap vertex_varying_map = vertex_shader_->varying_map();
   VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
   VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
+  VariableMap fragment_varying_map = fragment_shader_->varying_map();
 
   vertex_shader_->set_attrib_map(VariableMap());
   vertex_shader_->set_uniform_map(VariableMap());
+  vertex_shader_->set_varying_map(VariableMap());
   fragment_shader_->set_attrib_map(VariableMap());
   fragment_shader_->set_uniform_map(VariableMap());
+  fragment_shader_->set_varying_map(VariableMap());
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
@@ -286,9 +298,11 @@
   // equality operator
 #if !defined(OS_ANDROID)
   EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, vertex_shader_->uniform_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
+  EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
+  EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
+  EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
 #endif
 }
 
@@ -311,13 +325,17 @@
 
   VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
   VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
+  VariableMap vertex_varying_map = vertex_shader_->varying_map();
   VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
   VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
+  VariableMap fragment_varying_map = fragment_shader_->varying_map();
 
   vertex_shader_->set_attrib_map(VariableMap());
   vertex_shader_->set_uniform_map(VariableMap());
+  vertex_shader_->set_varying_map(VariableMap());
   fragment_shader_->set_attrib_map(VariableMap());
   fragment_shader_->set_uniform_map(VariableMap());
+  fragment_shader_->set_varying_map(VariableMap());
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
@@ -338,9 +356,11 @@
   // equality operator
 #if !defined(OS_ANDROID)
   EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, vertex_shader_->uniform_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->attrib_map());
-  EXPECT_EQ(vertex_attrib_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map());
+  EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map());
+  EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map());
+  EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map());
+  EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map());
 #endif
 }
 
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h
index fda8722..d05ba39 100644
--- a/gpu/command_buffer/service/mocks.h
+++ b/gpu/command_buffer/service/mocks.h
@@ -90,6 +90,7 @@
   MOCK_CONST_METHOD0(info_log, const char*());
   MOCK_CONST_METHOD0(attrib_map, const VariableMap&());
   MOCK_CONST_METHOD0(uniform_map, const VariableMap&());
+  MOCK_CONST_METHOD0(varying_map, const VariableMap&());
   MOCK_CONST_METHOD0(name_map, const NameMap&());
   MOCK_CONST_METHOD0(
       GetStringForOptionsThatWouldEffectCompilation, std::string());
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 8b1eede..19f05cc 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -34,6 +34,28 @@
 
 namespace {
 
+struct UniformType {
+  explicit UniformType(const ShaderTranslator::VariableInfo uniform)
+      : type(uniform.type),
+        size(uniform.size),
+        precision(uniform.precision) { }
+
+  UniformType()
+      : type(0),
+        size(0),
+        precision(SH_PRECISION_MEDIUMP) { }
+
+  bool operator==(const UniformType& other) const {
+    return type == other.type &&
+        size == other.size &&
+        precision == other.precision;
+  }
+
+  int type;
+  int size;
+  int precision;
+};
+
 int ShaderTypeToIndex(GLenum shader_type) {
   switch (shader_type) {
     case GL_VERTEX_SHADER:
@@ -512,6 +534,10 @@
     set_log_info("glBindAttribLocation() conflicts");
     return false;
   }
+  if (DetectUniformsMismatch()) {
+    set_log_info("Uniforms with the same name but different type/precision");
+    return false;
+  }
 
   TimeTicks before_time = TimeTicks::HighResNow();
   bool link = true;
@@ -963,6 +989,32 @@
   return false;
 }
 
+bool Program::DetectUniformsMismatch() const {
+  typedef std::map<std::string, UniformType> UniformMap;
+  UniformMap uniform_map;
+  for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+    const ShaderTranslator::VariableMap& shader_uniforms =
+        attached_shaders_[ii]->uniform_map();
+    for (ShaderTranslator::VariableMap::const_iterator iter =
+             shader_uniforms.begin();
+         iter != shader_uniforms.end(); ++iter) {
+      const std::string& name = iter->first;
+      UniformType type(iter->second);
+      UniformMap::iterator map_entry = uniform_map.find(name);
+      if (map_entry == uniform_map.end()) {
+        uniform_map[name] = type;
+      } else {
+        // If a uniform is already in the map, i.e., it has already been
+        // declared by other shader, then the type and precision must match.
+        if (map_entry->second == type)
+          continue;
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 static uint32 ComputeOffset(const void* start, const void* position) {
   return static_cast<const uint8*>(position) -
          static_cast<const uint8*>(start);
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index dca232b..05014ba 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -186,6 +186,11 @@
   // We only consider the declared attributes in the program.
   bool DetectAttribLocationBindingConflicts() const;
 
+  // Detects if there are uniforms of the same name but different type
+  // or precision in vertex/fragment shaders.
+  // Return true if such cases are detected.
+  bool DetectUniformsMismatch() const;
+
   // Visible for testing
   const LocationMap& bind_attrib_location_map() const {
     return bind_attrib_location_map_;
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 90ce0af..da16c85 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -162,6 +162,9 @@
   static const GLint kAttrib1Size = 1;
   static const GLint kAttrib2Size = 1;
   static const GLint kAttrib3Size = 1;
+  static const int kAttrib1Precision = SH_PRECISION_MEDIUMP;
+  static const int kAttrib2Precision = SH_PRECISION_HIGHP;
+  static const int kAttrib3Precision = SH_PRECISION_LOWP;
   static const GLint kAttrib1Location = 0;
   static const GLint kAttrib2Location = 1;
   static const GLint kAttrib3Location = 2;
@@ -178,6 +181,9 @@
   static const GLint kUniform1Size = 1;
   static const GLint kUniform2Size = 3;
   static const GLint kUniform3Size = 2;
+  static const int kUniform1Precision = SH_PRECISION_LOWP;
+  static const int kUniform2Precision = SH_PRECISION_MEDIUMP;
+  static const int kUniform3Precision = SH_PRECISION_HIGHP;
   static const GLint kUniform1FakeLocation = 0;  // These are hard coded
   static const GLint kUniform2FakeLocation = 1;  // to match
   static const GLint kUniform3FakeLocation = 2;  // ProgramManager.
@@ -670,22 +676,25 @@
   MockShaderTranslator shader_translator;
   ShaderTranslator::VariableMap attrib_map;
   ShaderTranslator::VariableMap uniform_map;
+  ShaderTranslator::VariableMap varying_map;
   attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib1Type, kAttrib1Size, kAttrib1Name);
+      kAttrib1Type, kAttrib1Size, kAttrib1Precision, kAttrib1Name);
   attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib2GoodType, kAttrib2Size, kAttrib2Name);
+      kAttrib2GoodType, kAttrib2Size, kAttrib2Precision, kAttrib2Name);
   attrib_map[kAttrib3Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib3Type, kAttrib3Size, kAttrib3Name);
+      kAttrib3Type, kAttrib3Size, kAttrib3Precision, kAttrib3Name);
   uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform1Type, kUniform1Size, kUniform1Name);
+      kUniform1Type, kUniform1Size, kUniform1Precision, kUniform1Name);
   uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform2GoodType, kUniform2Size, kUniform2Name);
+      kUniform2GoodType, kUniform2Size, kUniform2Precision, kUniform2Name);
   uniform_map[kUniform3GoodName] = ShaderTranslatorInterface::VariableInfo(
-      kUniform3Type, kUniform3Size, kUniform3GoodName);
+      kUniform3Type, kUniform3Size, kUniform3Precision, kUniform3GoodName);
   EXPECT_CALL(shader_translator, attrib_map())
       .WillRepeatedly(ReturnRef(attrib_map));
   EXPECT_CALL(shader_translator, uniform_map())
       .WillRepeatedly(ReturnRef(uniform_map));
+  EXPECT_CALL(shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(varying_map));
   ShaderTranslator::NameMap name_map;
   EXPECT_CALL(shader_translator, name_map())
       .WillRepeatedly(ReturnRef(name_map));
@@ -937,13 +946,19 @@
   ShaderTranslator::VariableMap attrib_map;
   for (uint32 ii = 0; ii < kNumAttribs; ++ii) {
     attrib_map[kAttribs[ii].name] = ShaderTranslatorInterface::VariableInfo(
-        kAttribs[ii].type, kAttribs[ii].size, kAttribs[ii].name);
+        kAttribs[ii].type,
+        kAttribs[ii].size,
+        SH_PRECISION_MEDIUMP,
+        kAttribs[ii].name);
   }
   ShaderTranslator::VariableMap uniform_map;
+  ShaderTranslator::VariableMap varying_map;
   EXPECT_CALL(shader_translator, attrib_map())
       .WillRepeatedly(ReturnRef(attrib_map));
   EXPECT_CALL(shader_translator, uniform_map())
       .WillRepeatedly(ReturnRef(uniform_map));
+  EXPECT_CALL(shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(varying_map));
   ShaderTranslator::NameMap name_map;
   EXPECT_CALL(shader_translator, name_map())
       .WillRepeatedly(ReturnRef(name_map));
@@ -964,6 +979,7 @@
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
     EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.precision, variable_info->precision);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
   fshader->SetStatus(true, "", NULL);
@@ -997,6 +1013,69 @@
   EXPECT_TRUE(LinkAsExpected(program, false));
 }
 
+TEST_F(ProgramManagerWithShaderTest, UniformsPrecisionMismatch) {
+  // Set up shader
+  const GLuint kVShaderClientId = 1;
+  const GLuint kVShaderServiceId = 11;
+  const GLuint kFShaderClientId = 2;
+  const GLuint kFShaderServiceId = 12;
+
+  MockShaderTranslator vertex_shader_translator;
+  ShaderTranslator::VariableMap vertex_attrib_map;
+  ShaderTranslator::VariableMap vertex_uniform_map;
+  vertex_uniform_map["a"] = ShaderTranslator::VariableInfo(
+      1, 3, SH_PRECISION_MEDIUMP, "a");
+  ShaderTranslator::VariableMap vertex_varying_map;
+  ShaderTranslator::NameMap vertex_name_map;
+  EXPECT_CALL(vertex_shader_translator, attrib_map())
+      .WillRepeatedly(ReturnRef(vertex_attrib_map));
+  EXPECT_CALL(vertex_shader_translator, uniform_map())
+      .WillRepeatedly(ReturnRef(vertex_uniform_map));
+  EXPECT_CALL(vertex_shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(vertex_varying_map));
+  EXPECT_CALL(vertex_shader_translator, name_map())
+    .WillRepeatedly(ReturnRef(vertex_name_map));
+
+  MockShaderTranslator frag_shader_translator;
+  ShaderTranslator::VariableMap frag_attrib_map;
+  ShaderTranslator::VariableMap frag_uniform_map;
+  frag_uniform_map["a"] = ShaderTranslator::VariableInfo(
+      1, 3, SH_PRECISION_LOWP, "a");
+  ShaderTranslator::VariableMap frag_varying_map;
+  ShaderTranslator::NameMap frag_name_map;
+  EXPECT_CALL(frag_shader_translator, attrib_map())
+      .WillRepeatedly(ReturnRef(frag_attrib_map));
+  EXPECT_CALL(frag_shader_translator, uniform_map())
+      .WillRepeatedly(ReturnRef(frag_uniform_map));
+  EXPECT_CALL(frag_shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(frag_varying_map));
+  EXPECT_CALL(frag_shader_translator, name_map())
+    .WillRepeatedly(ReturnRef(frag_name_map));
+
+  // Check we can create shader.
+  Shader* vshader = shader_manager_.CreateShader(
+      kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+  Shader* fshader = shader_manager_.CreateShader(
+      kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+  // Check shader got created.
+  ASSERT_TRUE(vshader != NULL && fshader != NULL);
+  // Set Status
+  vshader->SetStatus(true, "", &vertex_shader_translator);
+  fshader->SetStatus(true, "", &frag_shader_translator);
+
+  // Set up program
+  const GLuint kClientProgramId = 6666;
+  const GLuint kServiceProgramId = 8888;
+  Program* program =
+      manager_.CreateProgram(kClientProgramId, kServiceProgramId);
+  ASSERT_TRUE(program != NULL);
+  EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+  EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+
+  EXPECT_TRUE(program->DetectUniformsMismatch());
+  EXPECT_TRUE(LinkAsExpected(program, false));
+}
+
 TEST_F(ProgramManagerWithShaderTest, ClearWithSamplerTypes) {
   const GLuint kVShaderClientId = 2001;
   const GLuint kFShaderClientId = 2002;
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index a95b04c..89f21f9 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -43,10 +43,12 @@
   if (translator && valid) {
     attrib_map_ = translator->attrib_map();
     uniform_map_ = translator->uniform_map();
+    varying_map_ = translator->varying_map();
     name_map_ = translator->name_map();
   } else {
     attrib_map_.clear();
     uniform_map_.clear();
+    varying_map_.clear();
     name_map_.clear();
   }
   if (valid && source_.get()) {
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index bc68868..1324238 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -98,6 +98,11 @@
   }
 
   // Used by program cache.
+  const ShaderTranslator::VariableMap& varying_map() const {
+    return varying_map_;
+  }
+
+  // Used by program cache.
   void set_attrib_map(const ShaderTranslator::VariableMap& attrib_map) {
     // copied because cache might be cleared
     attrib_map_ = ShaderTranslator::VariableMap(attrib_map);
@@ -109,6 +114,12 @@
     uniform_map_ = ShaderTranslator::VariableMap(uniform_map);
   }
 
+  // Used by program cache.
+  void set_varying_map(const ShaderTranslator::VariableMap& varying_map) {
+    // copied because cache might be cleared
+    varying_map_ = ShaderTranslator::VariableMap(varying_map);
+  }
+
  private:
   typedef ShaderTranslator::VariableMap VariableMap;
   typedef ShaderTranslator::NameMap NameMap;
@@ -148,6 +159,7 @@
   // The type info when the shader was last compiled.
   VariableMap attrib_map_;
   VariableMap uniform_map_;
+  VariableMap varying_map_;
 
   // The name hashing info when the shader was last compiled.
   NameMap name_map_;
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index a225a3c..642b121 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -134,31 +134,39 @@
   const GLenum kShader1Type = GL_VERTEX_SHADER;
   const GLenum kAttrib1Type = GL_FLOAT_VEC2;
   const GLsizei kAttrib1Size = 2;
+  const int kAttrib1Precision = SH_PRECISION_MEDIUMP;
   const char* kAttrib1Name = "attr1";
   const GLenum kAttrib2Type = GL_FLOAT_VEC3;
   const GLsizei kAttrib2Size = 4;
+  const int kAttrib2Precision = SH_PRECISION_HIGHP;
   const char* kAttrib2Name = "attr2";
   const GLenum kUniform1Type = GL_FLOAT_MAT2;
   const GLsizei kUniform1Size = 3;
+  const int kUniform1Precision = SH_PRECISION_LOWP;
   const char* kUniform1Name = "uni1";
   const GLenum kUniform2Type = GL_FLOAT_MAT3;
   const GLsizei kUniform2Size = 5;
+  const int kUniform2Precision = SH_PRECISION_MEDIUMP;
   const char* kUniform2Name = "uni2";
+
   MockShaderTranslator shader_translator;
   ShaderTranslator::VariableMap attrib_map;
   attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib1Type, kAttrib1Size, kAttrib1Name);
+      kAttrib1Type, kAttrib1Size, kAttrib1Precision, kAttrib1Name);
   attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
-      kAttrib2Type, kAttrib2Size, kAttrib2Name);
+      kAttrib2Type, kAttrib2Size, kAttrib2Precision, kAttrib2Name);
   ShaderTranslator::VariableMap uniform_map;
   uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform1Type, kUniform1Size, kUniform1Name);
+      kUniform1Type, kUniform1Size, kUniform1Precision, kUniform1Name);
   uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
-      kUniform2Type, kUniform2Size, kUniform2Name);
+      kUniform2Type, kUniform2Size, kUniform2Precision, kUniform2Name);
   EXPECT_CALL(shader_translator, attrib_map())
       .WillRepeatedly(ReturnRef(attrib_map));
   EXPECT_CALL(shader_translator, uniform_map())
       .WillRepeatedly(ReturnRef(uniform_map));
+  ShaderTranslator::VariableMap varying_map;
+  EXPECT_CALL(shader_translator, varying_map())
+      .WillRepeatedly(ReturnRef(varying_map));
   ShaderTranslator::NameMap name_map;
   EXPECT_CALL(shader_translator, name_map())
       .WillRepeatedly(ReturnRef(name_map));
@@ -177,6 +185,7 @@
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
     EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.precision, variable_info->precision);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
   for (ShaderTranslator::VariableMap::const_iterator it = uniform_map.begin();
@@ -186,6 +195,7 @@
     ASSERT_TRUE(variable_info != NULL);
     EXPECT_EQ(it->second.type, variable_info->type);
     EXPECT_EQ(it->second.size, variable_info->size);
+    EXPECT_EQ(it->second.precision, variable_info->precision);
     EXPECT_EQ(it->second.name, variable_info->name);
   }
   // Check attrib and uniform get cleared.
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc
index 5129bfc..f05c450 100644
--- a/gpu/command_buffer/service/shader_translator.cc
+++ b/gpu/command_buffer/service/shader_translator.cc
@@ -48,6 +48,9 @@
     case SH_ACTIVE_UNIFORMS:
       ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len);
       break;
+    case SH_VARYINGS:
+      ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len);
+      break;
     default: NOTREACHED();
   }
   ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len);
@@ -61,18 +64,11 @@
     ANGLEGetInfoType len = 0;
     int size = 0;
     ShDataType type = SH_NONE;
+    ShPrecisionType precision = SH_PRECISION_MEDIUMP;
 
-    switch (var_type) {
-      case SH_ACTIVE_ATTRIBUTES:
-        ShGetActiveAttrib(
-            compiler, i, &len, &size, &type, name.get(), mapped_name.get());
-        break;
-      case SH_ACTIVE_UNIFORMS:
-        ShGetActiveUniform(
-            compiler, i, &len, &size, &type, name.get(), mapped_name.get());
-        break;
-      default: NOTREACHED();
-    }
+    ShGetVariableInfo(compiler, var_type, i,
+                      &len, &size, &type, &precision,
+                      name.get(), mapped_name.get());
 
     // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
     // to handle long struct field name mapping before we can do this.
@@ -81,7 +77,7 @@
     std::string name_string(name.get(), std::min(len, name_len - 1));
     mapped_name.get()[mapped_name_len - 1] = '\0';
 
-    ShaderTranslator::VariableInfo info(type, size, name_string);
+    ShaderTranslator::VariableInfo info(type, size, precision, name_string);
     (*var_map)[mapped_name.get()] = info;
   }
 }
@@ -156,7 +152,7 @@
 
 int ShaderTranslator::GetCompileOptions() const {
   int compile_options =
-      SH_OBJECT_CODE | SH_ATTRIBUTES_UNIFORMS |
+      SH_OBJECT_CODE | SH_VARIABLES |
       SH_MAP_LONG_VARIABLE_NAMES | SH_ENFORCE_PACKING_RESTRICTIONS |
       SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH;
 
@@ -190,6 +186,7 @@
     // Get info for attribs and uniforms.
     GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_);
     GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_);
+    GetVariableInfo(compiler_, SH_VARYINGS, &varying_map_);
     // Get info for name hashing.
     GetNameHashingInfo(compiler_, &name_map_);
   }
@@ -281,6 +278,11 @@
   return uniform_map_;
 }
 
+const ShaderTranslatorInterface::VariableMap&
+ShaderTranslator::varying_map() const {
+  return varying_map_;
+}
+
 const ShaderTranslatorInterface::NameMap&
 ShaderTranslator::name_map() const {
   return name_map_;
@@ -310,6 +312,7 @@
   info_log_.reset();
   attrib_map_.clear();
   uniform_map_.clear();
+  varying_map_.clear();
   name_map_.clear();
 }
 
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h
index 957f721..d4524d0 100644
--- a/gpu/command_buffer/service/shader_translator.h
+++ b/gpu/command_buffer/service/shader_translator.h
@@ -35,23 +35,27 @@
   struct VariableInfo {
     VariableInfo()
         : type(0),
-          size(0) {
+          size(0),
+          precision(SH_PRECISION_MEDIUMP) {
     }
 
-    VariableInfo(int _type, int _size, std::string _name)
+    VariableInfo(int _type, int _size, int _precision, std::string _name)
         : type(_type),
           size(_size),
+          precision(_precision),
           name(_name) {
     }
     bool operator==(
         const ShaderTranslatorInterface::VariableInfo& other) const {
       return type == other.type &&
           size == other.size &&
+          precision == other.precision &&
           strcmp(name.c_str(), other.name.c_str()) == 0;
     }
 
     int type;
     int size;
+    int precision;
     std::string name;  // name in the original shader source.
   };
 
@@ -82,6 +86,7 @@
 
   virtual const VariableMap& attrib_map() const = 0;
   virtual const VariableMap& uniform_map() const = 0;
+  virtual const VariableMap& varying_map() const = 0;
   virtual const NameMap& name_map() const = 0;
 
   // Return a string that is unique for a specfic set of options that would
@@ -128,6 +133,7 @@
   // Overridden from ShaderTranslatorInterface.
   virtual const VariableMap& attrib_map() const OVERRIDE;
   virtual const VariableMap& uniform_map() const OVERRIDE;
+  virtual const VariableMap& varying_map() const OVERRIDE;
   virtual const NameMap& name_map() const OVERRIDE;
 
   virtual std::string GetStringForOptionsThatWouldEffectCompilation() const
@@ -149,6 +155,7 @@
   scoped_ptr<char[]> info_log_;
   VariableMap attrib_map_;
   VariableMap uniform_map_;
+  VariableMap varying_map_;
   NameMap name_map_;
   bool implementation_is_glsl_es_;
   bool needs_built_in_function_emulation_;
diff --git a/gpu/command_buffer/service/stream_texture_manager.h b/gpu/command_buffer/service/stream_texture_manager.h
index b4f0a53..51119fa 100644
--- a/gpu/command_buffer/service/stream_texture_manager.h
+++ b/gpu/command_buffer/service/stream_texture_manager.h
@@ -6,7 +6,6 @@
 #define GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MANAGER_H_
 
 #include "base/basictypes.h"
-#include "gpu/command_buffer/service/gl_utils.h"
 
 namespace gpu {
 
@@ -22,8 +21,7 @@
   }
 
   // Returns an identifier for the object, or NULL if not successful.
-  virtual GLuint CreateStreamTexture(uint32 service_id,
-                                     uint32 client_id) = 0;
+  virtual uint32 CreateStreamTexture(uint32 service_id, uint32 client_id) = 0;
 
   virtual void DestroyStreamTexture(uint32 service_id) = 0;
 
diff --git a/gpu/command_buffer/service/stream_texture_manager_in_process_android.cc b/gpu/command_buffer/service/stream_texture_manager_in_process_android.cc
new file mode 100644
index 0000000..0a6c4c9
--- /dev/null
+++ b/gpu/command_buffer/service/stream_texture_manager_in_process_android.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 "gpu/command_buffer/service/stream_texture_manager_in_process_android.h"
+
+#include "base/bind.h"
+#include "ui/gfx/size.h"
+#include "ui/gl/android/surface_texture_bridge.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gpu {
+
+StreamTextureManagerInProcess::StreamTextureImpl::StreamTextureImpl(
+    uint32 service_id,
+    uint32 stream_id)
+    : surface_texture_bridge_(new gfx::SurfaceTextureBridge(service_id)),
+      stream_id_(stream_id) {}
+
+StreamTextureManagerInProcess::StreamTextureImpl::~StreamTextureImpl() {}
+
+void StreamTextureManagerInProcess::StreamTextureImpl::Update() {
+  GLint texture_id = 0;
+  glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id);
+  surface_texture_bridge_->UpdateTexImage();
+  glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
+}
+
+gfx::Size StreamTextureManagerInProcess::StreamTextureImpl::GetSize() {
+  return size_;
+}
+
+void StreamTextureManagerInProcess::StreamTextureImpl::SetSize(gfx::Size size) {
+  size_ = size;
+}
+
+scoped_refptr<gfx::SurfaceTextureBridge>
+StreamTextureManagerInProcess::StreamTextureImpl::GetSurfaceTexture() {
+  return surface_texture_bridge_;
+}
+
+StreamTextureManagerInProcess::StreamTextureManagerInProcess() : next_id_(1) {}
+
+StreamTextureManagerInProcess::~StreamTextureManagerInProcess() {
+  if (!textures_.empty()) {
+    LOG(WARNING) << "Undestroyed surface textures while tearing down "
+                    "StreamTextureManager.";
+  }
+}
+
+GLuint StreamTextureManagerInProcess::CreateStreamTexture(uint32 service_id,
+                                                          uint32 client_id) {
+  base::AutoLock lock(map_lock_);
+  uint32 stream_id = next_id_++;
+  linked_ptr<StreamTextureImpl> texture(
+      new StreamTextureImpl(service_id, stream_id));
+  textures_[service_id] = texture;
+
+  if (next_id_ == 0)
+    next_id_++;
+
+  return stream_id;
+}
+
+void StreamTextureManagerInProcess::DestroyStreamTexture(uint32 service_id) {
+  base::AutoLock lock(map_lock_);
+  textures_.erase(service_id);
+}
+
+gpu::StreamTexture* StreamTextureManagerInProcess::LookupStreamTexture(
+    uint32 service_id) {
+  base::AutoLock lock(map_lock_);
+  TextureMap::const_iterator it = textures_.find(service_id);
+  if (it != textures_.end())
+    return it->second.get();
+
+  return NULL;
+}
+
+scoped_refptr<gfx::SurfaceTextureBridge>
+StreamTextureManagerInProcess::GetSurfaceTexture(uint32 stream_id) {
+  base::AutoLock lock(map_lock_);
+  for (TextureMap::iterator it = textures_.begin(); it != textures_.end();
+       it++) {
+    if (it->second->stream_id() == stream_id)
+      return it->second->GetSurfaceTexture();
+  }
+
+  return NULL;
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/stream_texture_manager_in_process_android.h b/gpu/command_buffer/service/stream_texture_manager_in_process_android.h
new file mode 100644
index 0000000..70ec024
--- /dev/null
+++ b/gpu/command_buffer/service/stream_texture_manager_in_process_android.h
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. 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_STREAM_TEXTURE_MANAGER_IN_PROCESS_ANDROID_H_
+#define GPU_STREAM_TEXTURE_MANAGER_IN_PROCESS_ANDROID_H_
+
+#include <map>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "gpu/command_buffer/service/stream_texture.h"
+#include "gpu/command_buffer/service/stream_texture_manager.h"
+
+namespace gfx {
+class Size;
+class SurfaceTextureBridge;
+}
+
+namespace gpu {
+
+class StreamTextureManagerInProcess
+    : public gpu::StreamTextureManager,
+      public base::RefCountedThreadSafe<StreamTextureManagerInProcess> {
+ public:
+  StreamTextureManagerInProcess();
+
+  // implement gpu::StreamTextureManager:
+  virtual uint32 CreateStreamTexture(uint32 service_id,
+                                     uint32 client_id) OVERRIDE;
+  virtual void DestroyStreamTexture(uint32 service_id) OVERRIDE;
+  virtual gpu::StreamTexture* LookupStreamTexture(uint32 service_id) OVERRIDE;
+
+  scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture(uint32 stream_id);
+
+ private:
+  class StreamTextureImpl : public gpu::StreamTexture {
+   public:
+    StreamTextureImpl(uint32 service_id, uint32 stream_id);
+    virtual ~StreamTextureImpl();
+
+    // implement gpu::StreamTexture
+    virtual void Update() OVERRIDE;
+    virtual gfx::Size GetSize() OVERRIDE;
+
+    void SetSize(gfx::Size size);
+
+    scoped_refptr<gfx::SurfaceTextureBridge> GetSurfaceTexture();
+    uint32 stream_id() { return stream_id_; }
+
+   private:
+    scoped_refptr<gfx::SurfaceTextureBridge> surface_texture_bridge_;
+    uint32 stream_id_;
+    gfx::Size size_;
+
+    DISALLOW_COPY_AND_ASSIGN(StreamTextureImpl);
+  };
+
+  friend class base::RefCountedThreadSafe<StreamTextureManagerInProcess>;
+  virtual ~StreamTextureManagerInProcess();
+
+  typedef std::map<uint32, linked_ptr<StreamTextureImpl> > TextureMap;
+  TextureMap textures_;
+
+  uint32 next_id_;
+
+  base::Lock map_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(StreamTextureManagerInProcess);
+};
+
+}  // gpu
+
+#endif  // GPU_STREAM_TEXTURE_MANAGER_IN_PROCESS_ANDROID_H_
diff --git a/gpu/command_buffer/service/stream_texture_manager_mock.h b/gpu/command_buffer/service/stream_texture_manager_mock.h
index ac145ec..4b744f2 100644
--- a/gpu/command_buffer/service/stream_texture_manager_mock.h
+++ b/gpu/command_buffer/service/stream_texture_manager_mock.h
@@ -18,8 +18,8 @@
   MockStreamTextureManager();
   virtual ~MockStreamTextureManager();
 
-  MOCK_METHOD2(CreateStreamTexture, GLuint(uint32 service_id,
-                                           uint32 client_id));
+  MOCK_METHOD2(CreateStreamTexture,
+               uint32(uint32 service_id, uint32 client_id));
   MOCK_METHOD1(DestroyStreamTexture, void(uint32 service_id));
   MOCK_METHOD1(LookupStreamTexture, StreamTexture*(uint32 service_id));
 
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 486bdac..deb8c8e 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -6,6 +6,7 @@
 #include "base/bits.h"
 #include "base/strings/stringprintf.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/context_state.h"
 #include "gpu/command_buffer/service/error_state.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
@@ -1236,5 +1237,238 @@
 
 }
 
+bool TextureManager::ValidateTextureParameters(
+    ErrorState* error_state, const char* function_name,
+    GLenum target, GLenum format, GLenum type, GLint level) {
+  if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
+      ERRORSTATE_SET_GL_ERROR(
+          error_state, GL_INVALID_OPERATION, function_name,
+          (std::string("invalid type ") +
+           GLES2Util::GetStringEnum(type) + " for format " +
+           GLES2Util::GetStringEnum(format)).c_str());
+      return false;
+  }
+
+  uint32 channels = GLES2Util::GetChannelsForFormat(format);
+  if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
+    ERRORSTATE_SET_GL_ERROR(
+        error_state, GL_INVALID_OPERATION, function_name,
+        (std::string("invalid type ") +
+         GLES2Util::GetStringEnum(type) + " for format " +
+         GLES2Util::GetStringEnum(format)).c_str());
+    return false;
+  }
+  return true;
+}
+
+// Gets the texture id for a given target.
+TextureRef* TextureManager::GetTextureInfoForTarget(
+    ContextState* state, GLenum target) {
+  TextureUnit& unit = state->texture_units[state->active_texture_unit];
+  TextureRef* texture = NULL;
+  switch (target) {
+    case GL_TEXTURE_2D:
+      texture = unit.bound_texture_2d.get();
+      break;
+    case GL_TEXTURE_CUBE_MAP:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+    case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+    case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+      texture = unit.bound_texture_cube_map.get();
+      break;
+    case GL_TEXTURE_EXTERNAL_OES:
+      texture = unit.bound_texture_external_oes.get();
+      break;
+    case GL_TEXTURE_RECTANGLE_ARB:
+      texture = unit.bound_texture_rectangle_arb.get();
+      break;
+    default:
+      NOTREACHED();
+      return NULL;
+  }
+  return texture;
+}
+
+TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
+    ContextState* state, GLenum target) {
+  TextureRef* texture = GetTextureInfoForTarget(state, target);
+  if (!texture)
+    return NULL;
+  if (texture == GetDefaultTextureInfo(target))
+    return NULL;
+  return texture;
+}
+
+bool TextureManager::ValidateTexImage2D(
+    ContextState* state,
+    const char* function_name,
+    const DoTextImage2DArguments& args,
+    TextureRef** texture_ref) {
+  ErrorState* error_state = state->GetErrorState();
+  const Validators* validators = feature_info_->validators();
+  if (!validators->texture_target.IsValid(args.target)) {
+    ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+        error_state, function_name, args.target, "target");
+    return false;
+  }
+  if (!validators->texture_format.IsValid(args.internal_format)) {
+    ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+        error_state, function_name, args.internal_format,
+        "internal_format");
+    return false;
+  }
+  if (!validators->texture_format.IsValid(args.format)) {
+    ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+        error_state, function_name, args.format, "format");
+    return false;
+  }
+  if (!validators->pixel_type.IsValid(args.type)) {
+    ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+        error_state, function_name, args.type, "type");
+    return false;
+  }
+  if (args.format != args.internal_format) {
+    ERRORSTATE_SET_GL_ERROR(
+        error_state, GL_INVALID_OPERATION, function_name,
+        "format != internalFormat");
+    return false;
+  }
+  if (!ValidateTextureParameters(
+      error_state, function_name, args.target, args.format, args.type,
+      args.level)) {
+    return false;
+  }
+  if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
+      args.border != 0) {
+    ERRORSTATE_SET_GL_ERROR(
+        error_state, GL_INVALID_VALUE, function_name,
+        "dimensions out of range");
+    return false;
+  }
+  if ((GLES2Util::GetChannelsForFormat(args.format) &
+       (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
+    ERRORSTATE_SET_GL_ERROR(
+        error_state, GL_INVALID_OPERATION,
+        function_name, "can not supply data for depth or stencil textures");
+    return false;
+  }
+
+  TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
+  if (!local_texture_ref) {
+    ERRORSTATE_SET_GL_ERROR(
+        error_state, GL_INVALID_OPERATION, function_name,
+        "unknown texture for target");
+    return false;
+  }
+  if (local_texture_ref->texture()->IsImmutable()) {
+    ERRORSTATE_SET_GL_ERROR(
+        error_state, GL_INVALID_OPERATION, function_name,
+        "texture is immutable");
+    return false;
+  }
+
+  // TODO - verify that using the managed vs unmanaged does not matter.
+  // They both use the same MemoryTracker, and this call just re-routes
+  // to it.
+  if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
+    ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, "glTexImage2D",
+                            "out of memory");
+    return false;
+  }
+
+  // Write the TextureReference since this is valid.
+  *texture_ref = local_texture_ref;
+  return true;
+}
+
+void TextureManager::ValidateAndDoTexImage2D(
+    DecoderTextureState* texture_state,
+    ContextState* state,
+    DecoderFramebufferState* framebuffer_state,
+    const DoTextImage2DArguments& args) {
+  TextureRef* texture_ref;
+  if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
+    return;
+  }
+
+  DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
+               texture_ref, args);
+}
+
+void TextureManager::DoTexImage2D(
+    DecoderTextureState* texture_state,
+    ErrorState* error_state,
+    DecoderFramebufferState* framebuffer_state,
+    TextureRef* texture_ref,
+    const DoTextImage2DArguments& args) {
+  Texture* texture = texture_ref->texture();
+  GLsizei tex_width = 0;
+  GLsizei tex_height = 0;
+  GLenum tex_type = 0;
+  GLenum tex_format = 0;
+  bool level_is_same =
+      texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) &&
+      texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
+      args.width == tex_width && args.height == tex_height &&
+      args.type == tex_type && args.format == tex_format;
+
+  if (level_is_same && !args.pixels) {
+    // Just set the level texture but mark the texture as uncleared.
+    SetLevelInfo(
+        texture_ref,
+        args.target, args.level, args.internal_format, args.width, args.height,
+        1, args.border, args.format, args.type, false);
+    texture_state->tex_image_2d_failed = false;
+    return;
+  }
+
+  if (texture->IsAttachedToFramebuffer()) {
+    framebuffer_state->clear_state_dirty = true;
+  }
+
+  if (!texture_state->teximage2d_faster_than_texsubimage2d &&
+      level_is_same && args.pixels) {
+    {
+      ScopedTextureUploadTimer timer(texture_state);
+      glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
+                      args.format, args.type, args.pixels);
+    }
+    SetLevelCleared(texture_ref, args.target, args.level, true);
+    texture_state->tex_image_2d_failed = false;
+    return;
+  }
+
+  ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
+  {
+    ScopedTextureUploadTimer timer(texture_state);
+    glTexImage2D(
+        args.target, args.level, args.internal_format, args.width, args.height,
+        args.border, args.format, args.type, args.pixels);
+  }
+  GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
+  if (error == GL_NO_ERROR) {
+    SetLevelInfo(
+        texture_ref,
+        args.target, args.level, args.internal_format, args.width, args.height,
+        1, args.border, args.format, args.type, args.pixels != NULL);
+    texture_state->tex_image_2d_failed = false;
+  }
+}
+
+ScopedTextureUploadTimer::ScopedTextureUploadTimer(
+    DecoderTextureState* texture_state)
+    : texture_state_(texture_state),
+      begin_time_(base::TimeTicks::HighResNow()) {
+}
+
+ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
+  texture_state_->texture_upload_count++;
+  texture_state_->total_texture_upload_time +=
+      base::TimeTicks::HighResNow() - begin_time_;
+}
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index cbc659c..db47004 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -27,6 +27,8 @@
 namespace gles2 {
 
 class GLES2Decoder;
+struct ContextState;
+struct DecoderFramebufferState;
 class Display;
 class ErrorState;
 class FeatureInfo;
@@ -429,6 +431,29 @@
   DISALLOW_COPY_AND_ASSIGN(TextureRef);
 };
 
+// Holds data that is per gles2_cmd_decoder, but is related to to the
+// TextureManager.
+struct DecoderTextureState {
+  // total_texture_upload_time automatically initialized to 0 in default
+  // constructor.
+  DecoderTextureState():
+      tex_image_2d_failed(false),
+      texture_upload_count(0),
+      teximage2d_faster_than_texsubimage2d(true) {}
+
+  // This indicates all the following texSubImage2D calls that are part of the
+  // failed texImage2D call should be ignored.
+  bool tex_image_2d_failed;
+
+  // Command buffer stats.
+  int texture_upload_count;
+  base::TimeDelta total_texture_upload_time;
+
+  // This is really not per-decoder, but the logic to decide this value is in
+  // the decoder for now, so it is simpler to leave it there.
+  bool teximage2d_faster_than_texsubimage2d;
+};
+
 // This class keeps track of the textures and their sizes so we can do NPOT and
 // texture complete checking.
 //
@@ -671,6 +696,43 @@
     destruction_observers_.RemoveObserver(observer);
   }
 
+  struct DoTextImage2DArguments {
+    GLenum target;
+    GLint level;
+    GLenum internal_format;
+    GLsizei width;
+    GLsizei height;
+    GLint border;
+    GLenum format;
+    GLenum type;
+    const void* pixels;
+    uint32 pixels_size;
+  };
+
+  bool ValidateTexImage2D(
+    ContextState* state,
+    const char* function_name,
+    const DoTextImage2DArguments& args,
+    // Pointer to TextureRef filled in if validation successful.
+    // Presumes the pointer is valid.
+    TextureRef** texture_ref);
+
+  void ValidateAndDoTexImage2D(
+    DecoderTextureState* texture_state,
+    ContextState* state,
+    DecoderFramebufferState* framebuffer_state,
+    const DoTextImage2DArguments& args);
+
+  // TODO(kloveless): Make GetTexture* private once this is no longer called
+  // from gles2_cmd_decoder.
+  TextureRef* GetTextureInfoForTarget(ContextState* state, GLenum target);
+  TextureRef* GetTextureInfoForTargetUnlessDefault(
+      ContextState* state, GLenum target);
+
+  bool ValidateTextureParameters(
+    ErrorState* error_state, const char* function_name,
+    GLenum target, GLenum format, GLenum type, GLint level);
+
  private:
   friend class Texture;
   friend class TextureRef;
@@ -680,6 +742,13 @@
       GLenum target,
       GLuint* black_texture);
 
+  void DoTexImage2D(
+    DecoderTextureState* texture_state,
+    ErrorState* error_state,
+    DecoderFramebufferState* framebuffer_state,
+    TextureRef* texture_ref,
+    const DoTextImage2DArguments& args);
+
   void StartTracking(TextureRef* texture);
   void StopTracking(TextureRef* texture);
 
@@ -730,6 +799,18 @@
   DISALLOW_COPY_AND_ASSIGN(TextureManager);
 };
 
+// This class records texture upload time when in scope.
+class ScopedTextureUploadTimer {
+ public:
+  explicit ScopedTextureUploadTimer(DecoderTextureState* texture_state);
+  ~ScopedTextureUploadTimer();
+
+ private:
+  DecoderTextureState* texture_state_;
+  base::TimeTicks begin_time_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedTextureUploadTimer);
+};
+
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/tests/gl_depth_texture_unittest.cc b/gpu/command_buffer/tests/gl_depth_texture_unittest.cc
index e97863c..83bb84c 100644
--- a/gpu/command_buffer/tests/gl_depth_texture_unittest.cc
+++ b/gpu/command_buffer/tests/gl_depth_texture_unittest.cc
@@ -60,15 +60,7 @@
 
 }  // anonymous namespace
 
-// crbug.com/135229
-// Fails on all Windows platforms and on Linux Intel.
-#if defined(OS_WIN) || (defined(OS_LINUX) && defined(NDEBUG))
-#define MAYBE_RenderTo DISABLED_RenderTo
-#else
-#define MAYBE_RenderTo RenderTo
-#endif
-
-TEST_F(DepthTextureTest, MAYBE_RenderTo) {
+TEST_F(DepthTextureTest, RenderTo) {
   if (!GLTestHelper::HasExtension("GL_CHROMIUM_depth_texture")) {
     return;
   }
@@ -200,9 +192,11 @@
       continue;
     }
 
-    // Check that each pixel's RGB are the same and that it's value is less
-    // than the previous pixel in either direction. Basically verify we have a
-    // gradient.
+    // Check that each pixel's red value is less than the previous pixel in
+    // either direction. Basically verify we have a gradient. No assumption is
+    // made about the other channels green, blue and alpha since, according to
+    // the GL_CHROMIUM_depth_texture spec, they have undefined values for
+    // depth textures.
     int bad_count = 0;  // used to not spam the log with too many messages.
     for (GLint yy = 0; bad_count < 16 && yy < kResolution; ++yy) {
       for (GLint xx = 0; bad_count < 16 && xx < kResolution; ++xx) {
@@ -210,10 +204,6 @@
         const uint8* left = actual - 4;
         const uint8* down = actual - kResolution * 4;
 
-        EXPECT_EQ(actual[0], actual[1]) << "pixel at " << xx << ", " << yy;
-        EXPECT_EQ(actual[1], actual[2]) << "pixel at " << xx << ", " << yy;
-        bad_count += (actual[0] == actual[1] ? 0 : 1);
-
         // NOTE: Qualcomm on Nexus 4 the right most column has the same
         // values as the next to right most column. (bad interpolator?)
         if (xx > 0 && xx < kResolution - 1) {
@@ -230,10 +220,6 @@
           EXPECT_GT(actual[0], down[0]) << "pixel at " << xx << ", " << yy;
           bad_count += (actual[0] > down[0] ? 0 : 1);
         }
-
-        EXPECT_TRUE(actual[3] == actual[0] || actual[3] == 0xFF)
-            << "pixel at " << xx << ", " << yy;
-        bad_count += ((actual[3] == actual[0] || actual[3] == 0xFF) ? 0 : 1);
       }
     }
 
diff --git a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc
index 9c9d5ab..91fbc6a 100644
--- a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc
+++ b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittests.cc
@@ -11,6 +11,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/process/process_handle.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/tests/gl_manager.h"
 #include "gpu/command_buffer/tests/gl_test_utils.h"
@@ -51,24 +53,16 @@
   DISALLOW_COPY_AND_ASSIGN(MockGpuMemoryBuffer);
 };
 
-class MockImageFactory : public ImageFactory {
+class MockGpuMemoryBufferFactory : public GpuMemoryBufferFactory {
  public:
-  MockImageFactory(ImageManager* image_manager) {}
-  virtual ~MockImageFactory() {}
+  MockGpuMemoryBufferFactory() {}
+  virtual ~MockGpuMemoryBufferFactory() {}
 
-  MOCK_METHOD4(CreateGpuMemoryBufferMock, gfx::GpuMemoryBuffer*(
-      int width, int height, GLenum internalformat, unsigned* image_id));
-  MOCK_METHOD1(DeleteGpuMemoryBuffer, void(unsigned));
-  // Workaround for mocking methods that return scoped_ptrs
-  virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
-      int width, int height, GLenum internalformat,
-      unsigned* image_id) OVERRIDE {
-    return scoped_ptr<gfx::GpuMemoryBuffer>(CreateGpuMemoryBufferMock(
-        width, height, internalformat, image_id));
-  }
+  MOCK_METHOD3(CreateGpuMemoryBuffer,
+               gfx::GpuMemoryBuffer*(size_t, size_t, unsigned));
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(MockImageFactory);
+  DISALLOW_COPY_AND_ASSIGN(MockGpuMemoryBufferFactory);
 };
 
 class MockGpuMemoryBufferTest : public testing::Test {
@@ -76,10 +70,9 @@
   virtual void SetUp() {
     GLManager::Options options;
     image_manager_ = new ImageManager;
-    image_factory_.reset(
-        new StrictMock<MockImageFactory>(image_manager_.get()));
+    gpu_memory_buffer_factory_.reset(new MockGpuMemoryBufferFactory);
     options.image_manager = image_manager_.get();
-    options.image_factory = image_factory_.get();
+    options.gpu_memory_buffer_factory = gpu_memory_buffer_factory_.get();
 
     gl_.Initialize(options);
     gl_.MakeCurrent();
@@ -108,8 +101,8 @@
     gl_.Destroy();
   }
 
-  scoped_ptr<StrictMock<MockImageFactory> > image_factory_;
   scoped_refptr<ImageManager> image_manager_;
+  scoped_ptr<MockGpuMemoryBufferFactory> gpu_memory_buffer_factory_;
   GLManager gl_;
   GLuint texture_ids_[2];
   GLuint framebuffer_id_;
@@ -133,29 +126,21 @@
   handle.type = gfx::SHARED_MEMORY_BUFFER;
   handle.handle = duped_shared_memory_handle;
 
-  const GLuint kImageId = 345u;
-
-  EXPECT_CALL(*image_factory_.get(), CreateGpuMemoryBufferMock(
-      kImageWidth, kImageHeight, GL_RGBA8_OES, _))
+  EXPECT_CALL(*gpu_memory_buffer_factory_.get(), CreateGpuMemoryBuffer(
+      kImageWidth, kImageHeight, GL_RGBA8_OES))
       .Times(1)
-      .WillOnce(DoAll(SetArgPointee<3>(kImageId), Return(gpu_memory_buffer)))
+      .WillOnce(Return(gpu_memory_buffer))
       .RetiresOnSaturation();
-
-  // Create the GLImage and insert it into the ImageManager, which
-  // would be done within CreateGpuMemoryBufferMock if it weren't a mock.
-  GLuint image_id = glCreateImageCHROMIUM(
-      kImageWidth, kImageHeight, GL_RGBA8_OES);
-  EXPECT_EQ(kImageId, image_id);
-
   EXPECT_CALL(*gpu_memory_buffer, GetHandle())
+      .Times(1)
       .WillOnce(Return(handle))
       .RetiresOnSaturation();
 
-  gfx::Size size(kImageWidth, kImageHeight);
-  scoped_refptr<gfx::GLImage> gl_image(
-      gfx::GLImage::CreateGLImageForGpuMemoryBuffer(
-          gpu_memory_buffer->GetHandle(), size));
-  image_manager_->AddImage(gl_image.get(), image_id);
+  // Create the image. This should add the image ID to the ImageManager.
+  GLuint image_id = glCreateImageCHROMIUM(
+      kImageWidth, kImageHeight, GL_RGBA8_OES);
+  EXPECT_NE(0u, image_id);
+  EXPECT_TRUE(image_manager_->LookupImage(image_id) != NULL);
 
   EXPECT_CALL(*gpu_memory_buffer, IsMapped())
       .WillOnce(Return(false))
@@ -217,11 +202,6 @@
   EXPECT_CALL(*gpu_memory_buffer, Die())
       .Times(1)
       .RetiresOnSaturation();
-
-  EXPECT_CALL(*image_factory_.get(), DeleteGpuMemoryBuffer(image_id))
-      .Times(1)
-      .RetiresOnSaturation();
-
   glDestroyImageCHROMIUM(image_id);
 }
 
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index c4b84a2..82a01f0 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -12,10 +12,12 @@
 #include "gpu/command_buffer/client/gles2_lib.h"
 #include "gpu/command_buffer/client/transfer_buffer.h"
 #include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_control_service.h"
 #include "gpu/command_buffer/service/gpu_scheduler.h"
 #include "gpu/command_buffer/service/image_manager.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
@@ -38,8 +40,7 @@
       virtual_manager(NULL),
       bind_generates_resource(false),
       context_lost_allowed(false),
-      image_manager(NULL),
-      image_factory(NULL) {
+      image_manager(NULL) {
 }
 
 GLManager::GLManager()
@@ -100,14 +101,6 @@
     real_gl_context = options.virtual_manager->context();
   }
 
-  // From <EGL/egl.h>.
-  const int32 EGL_ALPHA_SIZE = 0x3021;
-  const int32 EGL_BLUE_SIZE = 0x3022;
-  const int32 EGL_GREEN_SIZE = 0x3023;
-  const int32 EGL_RED_SIZE = 0x3024;
-  const int32 EGL_DEPTH_SIZE = 0x3025;
-  const int32 EGL_NONE = 0x3038;
-
   mailbox_manager_ =
       mailbox_manager ? mailbox_manager : new gles2::MailboxManager;
   share_group_ =
@@ -116,17 +109,13 @@
   gfx::GpuPreference gpu_preference(gfx::PreferDiscreteGpu);
   const char* allowed_extensions = "*";
   std::vector<int32> attribs;
-  attribs.push_back(EGL_RED_SIZE);
-  attribs.push_back(8);
-  attribs.push_back(EGL_GREEN_SIZE);
-  attribs.push_back(8);
-  attribs.push_back(EGL_BLUE_SIZE);
-  attribs.push_back(8);
-  attribs.push_back(EGL_ALPHA_SIZE);
-  attribs.push_back(8);
-  attribs.push_back(EGL_DEPTH_SIZE);
-  attribs.push_back(16);
-  attribs.push_back(EGL_NONE);
+  gles2::ContextCreationAttribHelper attrib_helper;
+  attrib_helper.red_size_ = 8;
+  attrib_helper.green_size_ = 8;
+  attrib_helper.blue_size_ = 8;
+  attrib_helper.alpha_size_ = 8;
+  attrib_helper.depth_size_ = 16;
+  attrib_helper.Serialize(&attribs);
 
   if (!context_group) {
     context_group = new gles2::ContextGroup(mailbox_manager_.get(),
@@ -143,6 +132,10 @@
   ASSERT_TRUE(command_buffer_->Initialize())
       << "could not create command buffer service";
 
+  gpu_control_.reset(
+      new GpuControlService(decoder_->GetContextGroup()->image_manager(),
+                            options.gpu_memory_buffer_factory));
+
   gpu_scheduler_.reset(new GpuScheduler(command_buffer_.get(),
                                         decoder_.get(),
                                         decoder_.get()));
@@ -200,12 +193,14 @@
       client_share_group,
       transfer_buffer_.get(),
       options.bind_generates_resource,
-      options.image_factory));
+      gpu_control_.get()));
 
   ASSERT_TRUE(gles2_implementation_->Initialize(
       kStartTransferBufferSize,
       kMinTransferBufferSize,
-      kMaxTransferBufferSize)) << "Could not init GLES2Implementation";
+      kMaxTransferBufferSize,
+      gpu::gles2::GLES2Implementation::kNoLimit))
+          << "Could not init GLES2Implementation";
 
   MakeCurrent();
 }
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index a53aa40..8a811fd 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -21,8 +21,10 @@
 namespace gpu {
 
 class CommandBufferService;
-class TransferBuffer;
+class GpuControlService;
+class GpuMemoryBufferFactory;
 class GpuScheduler;
+class TransferBuffer;
 
 namespace gles2 {
 
@@ -55,8 +57,8 @@
     bool context_lost_allowed;
     // Image manager to be used.
     gles2::ImageManager* image_manager;
-    // Image factory to be used.
-    gles2::ImageFactory* image_factory;
+    // GpuMemoryBuffer factory to be used.
+    GpuMemoryBufferFactory* gpu_memory_buffer_factory;
   };
   GLManager();
   ~GLManager();
@@ -98,6 +100,7 @@
   scoped_refptr<gles2::MailboxManager> mailbox_manager_;
   scoped_refptr<gfx::GLShareGroup> share_group_;
   scoped_ptr<CommandBufferService> command_buffer_;
+  scoped_ptr<GpuControlService> gpu_control_;
   scoped_ptr<gles2::GLES2Decoder> decoder_;
   scoped_ptr<GpuScheduler> gpu_scheduler_;
   scoped_refptr<gfx::GLSurface> surface_;
diff --git a/gpu/command_buffer_common.gypi b/gpu/command_buffer_common.gypi
index 85431e4..55e825e 100644
--- a/gpu/command_buffer_common.gypi
+++ b/gpu/command_buffer_common.gypi
@@ -21,6 +21,7 @@
     'command_buffer/common/gles2_cmd_format_autogen.h',
     'command_buffer/common/gles2_cmd_format.cc',
     'command_buffer/common/gles2_cmd_format.h',
+    'command_buffer/common/gpu_control.h',
     'command_buffer/common/id_allocator.cc',
     'command_buffer/common/id_allocator.h',
     'command_buffer/common/mailbox.cc',
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index f8e94c1..9c9c3f7 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -75,13 +75,16 @@
     'command_buffer/service/gl_state_restorer_impl.cc',
     'command_buffer/service/gl_state_restorer_impl.h',
     'command_buffer/service/gl_utils.h',
-    'command_buffer/service/gpu_scheduler.h',
+    'command_buffer/service/gpu_control_service.cc',
+    'command_buffer/service/gpu_control_service.h',
+    'command_buffer/service/gpu_memory_buffer_manager.h',
     'command_buffer/service/gpu_scheduler.cc',
+    'command_buffer/service/gpu_scheduler.h',
     'command_buffer/service/gpu_scheduler_mock.h',
-    'command_buffer/service/gpu_switches.h',
     'command_buffer/service/gpu_switches.cc',
-    'command_buffer/service/gpu_tracer.h',
+    'command_buffer/service/gpu_switches.h',
     'command_buffer/service/gpu_tracer.cc',
+    'command_buffer/service/gpu_tracer.h',
     'command_buffer/service/id_manager.h',
     'command_buffer/service/id_manager.cc',
     'command_buffer/service/image_manager.cc',
@@ -113,6 +116,8 @@
     'command_buffer/service/shader_translator_cache.cc',
     'command_buffer/service/stream_texture.h',
     'command_buffer/service/stream_texture_manager.h',
+    'command_buffer/service/stream_texture_manager_in_process_android.h',
+    'command_buffer/service/stream_texture_manager_in_process_android.cc',
     'command_buffer/service/texture_manager.h',
     'command_buffer/service/texture_manager.cc',
     'command_buffer/service/transfer_buffer_manager.cc',
diff --git a/gpu/command_buffer_service.target.darwin-arm.mk b/gpu/command_buffer_service.target.darwin-arm.mk
index 9755e0e..19278fc 100644
--- a/gpu/command_buffer_service.target.darwin-arm.mk
+++ b/gpu/command_buffer_service.target.darwin-arm.mk
@@ -48,6 +48,7 @@
 	gpu/command_buffer/service/gles2_cmd_validation.cc \
 	gpu/command_buffer/service/gl_context_virtual.cc \
 	gpu/command_buffer/service/gl_state_restorer_impl.cc \
+	gpu/command_buffer/service/gpu_control_service.cc \
 	gpu/command_buffer/service/gpu_scheduler.cc \
 	gpu/command_buffer/service/gpu_switches.cc \
 	gpu/command_buffer/service/gpu_tracer.cc \
@@ -65,6 +66,7 @@
 	gpu/command_buffer/service/shader_manager.cc \
 	gpu/command_buffer/service/shader_translator.cc \
 	gpu/command_buffer/service/shader_translator_cache.cc \
+	gpu/command_buffer/service/stream_texture_manager_in_process_android.cc \
 	gpu/command_buffer/service/texture_manager.cc \
 	gpu/command_buffer/service/transfer_buffer_manager.cc \
 	gpu/command_buffer/service/vertex_array_manager.cc \
diff --git a/gpu/command_buffer_service.target.darwin-mips.mk b/gpu/command_buffer_service.target.darwin-mips.mk
index 59049b6..86fe44b 100644
--- a/gpu/command_buffer_service.target.darwin-mips.mk
+++ b/gpu/command_buffer_service.target.darwin-mips.mk
@@ -48,6 +48,7 @@
 	gpu/command_buffer/service/gles2_cmd_validation.cc \
 	gpu/command_buffer/service/gl_context_virtual.cc \
 	gpu/command_buffer/service/gl_state_restorer_impl.cc \
+	gpu/command_buffer/service/gpu_control_service.cc \
 	gpu/command_buffer/service/gpu_scheduler.cc \
 	gpu/command_buffer/service/gpu_switches.cc \
 	gpu/command_buffer/service/gpu_tracer.cc \
@@ -65,6 +66,7 @@
 	gpu/command_buffer/service/shader_manager.cc \
 	gpu/command_buffer/service/shader_translator.cc \
 	gpu/command_buffer/service/shader_translator_cache.cc \
+	gpu/command_buffer/service/stream_texture_manager_in_process_android.cc \
 	gpu/command_buffer/service/texture_manager.cc \
 	gpu/command_buffer/service/transfer_buffer_manager.cc \
 	gpu/command_buffer/service/vertex_array_manager.cc \
diff --git a/gpu/command_buffer_service.target.darwin-x86.mk b/gpu/command_buffer_service.target.darwin-x86.mk
index 5bc2dff..86c33bd 100644
--- a/gpu/command_buffer_service.target.darwin-x86.mk
+++ b/gpu/command_buffer_service.target.darwin-x86.mk
@@ -48,6 +48,7 @@
 	gpu/command_buffer/service/gles2_cmd_validation.cc \
 	gpu/command_buffer/service/gl_context_virtual.cc \
 	gpu/command_buffer/service/gl_state_restorer_impl.cc \
+	gpu/command_buffer/service/gpu_control_service.cc \
 	gpu/command_buffer/service/gpu_scheduler.cc \
 	gpu/command_buffer/service/gpu_switches.cc \
 	gpu/command_buffer/service/gpu_tracer.cc \
@@ -65,6 +66,7 @@
 	gpu/command_buffer/service/shader_manager.cc \
 	gpu/command_buffer/service/shader_translator.cc \
 	gpu/command_buffer/service/shader_translator_cache.cc \
+	gpu/command_buffer/service/stream_texture_manager_in_process_android.cc \
 	gpu/command_buffer/service/texture_manager.cc \
 	gpu/command_buffer/service/transfer_buffer_manager.cc \
 	gpu/command_buffer/service/vertex_array_manager.cc \
diff --git a/gpu/command_buffer_service.target.linux-arm.mk b/gpu/command_buffer_service.target.linux-arm.mk
index 9755e0e..19278fc 100644
--- a/gpu/command_buffer_service.target.linux-arm.mk
+++ b/gpu/command_buffer_service.target.linux-arm.mk
@@ -48,6 +48,7 @@
 	gpu/command_buffer/service/gles2_cmd_validation.cc \
 	gpu/command_buffer/service/gl_context_virtual.cc \
 	gpu/command_buffer/service/gl_state_restorer_impl.cc \
+	gpu/command_buffer/service/gpu_control_service.cc \
 	gpu/command_buffer/service/gpu_scheduler.cc \
 	gpu/command_buffer/service/gpu_switches.cc \
 	gpu/command_buffer/service/gpu_tracer.cc \
@@ -65,6 +66,7 @@
 	gpu/command_buffer/service/shader_manager.cc \
 	gpu/command_buffer/service/shader_translator.cc \
 	gpu/command_buffer/service/shader_translator_cache.cc \
+	gpu/command_buffer/service/stream_texture_manager_in_process_android.cc \
 	gpu/command_buffer/service/texture_manager.cc \
 	gpu/command_buffer/service/transfer_buffer_manager.cc \
 	gpu/command_buffer/service/vertex_array_manager.cc \
diff --git a/gpu/command_buffer_service.target.linux-mips.mk b/gpu/command_buffer_service.target.linux-mips.mk
index 59049b6..86fe44b 100644
--- a/gpu/command_buffer_service.target.linux-mips.mk
+++ b/gpu/command_buffer_service.target.linux-mips.mk
@@ -48,6 +48,7 @@
 	gpu/command_buffer/service/gles2_cmd_validation.cc \
 	gpu/command_buffer/service/gl_context_virtual.cc \
 	gpu/command_buffer/service/gl_state_restorer_impl.cc \
+	gpu/command_buffer/service/gpu_control_service.cc \
 	gpu/command_buffer/service/gpu_scheduler.cc \
 	gpu/command_buffer/service/gpu_switches.cc \
 	gpu/command_buffer/service/gpu_tracer.cc \
@@ -65,6 +66,7 @@
 	gpu/command_buffer/service/shader_manager.cc \
 	gpu/command_buffer/service/shader_translator.cc \
 	gpu/command_buffer/service/shader_translator_cache.cc \
+	gpu/command_buffer/service/stream_texture_manager_in_process_android.cc \
 	gpu/command_buffer/service/texture_manager.cc \
 	gpu/command_buffer/service/transfer_buffer_manager.cc \
 	gpu/command_buffer/service/vertex_array_manager.cc \
diff --git a/gpu/command_buffer_service.target.linux-x86.mk b/gpu/command_buffer_service.target.linux-x86.mk
index 5bc2dff..86c33bd 100644
--- a/gpu/command_buffer_service.target.linux-x86.mk
+++ b/gpu/command_buffer_service.target.linux-x86.mk
@@ -48,6 +48,7 @@
 	gpu/command_buffer/service/gles2_cmd_validation.cc \
 	gpu/command_buffer/service/gl_context_virtual.cc \
 	gpu/command_buffer/service/gl_state_restorer_impl.cc \
+	gpu/command_buffer/service/gpu_control_service.cc \
 	gpu/command_buffer/service/gpu_scheduler.cc \
 	gpu/command_buffer/service/gpu_switches.cc \
 	gpu/command_buffer/service/gpu_tracer.cc \
@@ -65,6 +66,7 @@
 	gpu/command_buffer/service/shader_manager.cc \
 	gpu/command_buffer/service/shader_translator.cc \
 	gpu/command_buffer/service/shader_translator_cache.cc \
+	gpu/command_buffer/service/stream_texture_manager_in_process_android.cc \
 	gpu/command_buffer/service/texture_manager.cc \
 	gpu/command_buffer/service/transfer_buffer_manager.cc \
 	gpu/command_buffer/service/vertex_array_manager.cc \
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index 827c76c..c3dc16f 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -4,6 +4,20 @@
 
 #include "gpu/config/gpu_info.h"
 
+namespace {
+
+void EnumerateGPUDevice(gpu::GPUInfo::Enumerator* enumerator,
+                        const gpu::GPUInfo::GPUDevice& device) {
+  enumerator->BeginGPUDevice();
+  enumerator->AddInt("vendorId", device.vendor_id);
+  enumerator->AddInt("deviceId", device.device_id);
+  enumerator->AddString("vendorString", device.vendor_string);
+  enumerator->AddString("deviceString", device.device_string);
+  enumerator->EndGPUDevice();
+}
+
+}  // namespace
+
 namespace gpu {
 
 GPUInfo::GPUDevice::GPUDevice()
@@ -27,4 +41,89 @@
 
 GPUInfo::~GPUInfo() { }
 
+void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
+  struct GPUInfoKnownFields {
+    bool finalized;
+    base::TimeDelta initialization_time;
+    bool optimus;
+    bool amd_switchable;
+    bool lenovo_dcute;
+    Version display_link_version;
+    GPUDevice gpu;
+    std::vector<GPUDevice> secondary_gpus;
+    uint64 adapter_luid;
+    std::string driver_vendor;
+    std::string driver_version;
+    std::string driver_date;
+    std::string pixel_shader_version;
+    std::string vertex_shader_version;
+    std::string machine_model;
+    std::string gl_version;
+    std::string gl_version_string;
+    std::string gl_vendor;
+    std::string gl_renderer;
+    std::string gl_extensions;
+    std::string gl_ws_vendor;
+    std::string gl_ws_version;
+    std::string gl_ws_extensions;
+    uint32 gl_reset_notification_strategy;
+    bool can_lose_context;
+    GpuPerformanceStats performance_stats;
+    bool software_rendering;
+    bool sandboxed;
+#if defined(OS_WIN)
+    DxDiagNode dx_diagnostics;
+#endif
+  };
+
+  // If this assert fails then most likely something below needs to be updated.
+  // Note that this assert is only approximate. If a new field is added to
+  // GPUInfo which fits within the current padding then it will not be caught.
+  COMPILE_ASSERT(
+      sizeof(GPUInfo) == sizeof(GPUInfoKnownFields),
+      Fields_Have_Changed_In_GPUInfo_So_Update_Below);
+
+  // Required fields (according to DevTools protocol) first.
+  enumerator->AddString("machineModel", machine_model);
+  EnumerateGPUDevice(enumerator, gpu);
+  for (size_t ii = 0; ii < secondary_gpus.size(); ++ii) {
+    EnumerateGPUDevice(enumerator, secondary_gpus[ii]);
+  }
+
+  enumerator->BeginAuxAttributes();
+  enumerator->AddBool("finalized", finalized);
+  enumerator->AddTimeDeltaInSecondsF("initializationTime",
+                                     initialization_time);
+  enumerator->AddBool("optimus", optimus);
+  enumerator->AddBool("amdSwitchable", amd_switchable);
+  enumerator->AddBool("lenovoDcute", lenovo_dcute);
+  if (display_link_version.IsValid()) {
+    enumerator->AddString("displayLinkVersion",
+                          display_link_version.GetString());
+  }
+  enumerator->AddInt64("adapterLuid", adapter_luid);
+  enumerator->AddString("driverVendor", driver_vendor);
+  enumerator->AddString("driverVersion", driver_version);
+  enumerator->AddString("driverDate", driver_date);
+  enumerator->AddString("pixelShaderVersion", pixel_shader_version);
+  enumerator->AddString("vertexShaderVersion", vertex_shader_version);
+  enumerator->AddString("glVersion", gl_version);
+  enumerator->AddString("glVersionString", gl_version_string);
+  enumerator->AddString("glVendor", gl_vendor);
+  enumerator->AddString("glRenderer", gl_renderer);
+  enumerator->AddString("glExtensions", gl_extensions);
+  enumerator->AddString("glWsVendor", gl_ws_vendor);
+  enumerator->AddString("glWsVersion", gl_ws_version);
+  enumerator->AddString("glWsExtensions", gl_ws_extensions);
+  enumerator->AddInt(
+      "glResetNotificationStrategy",
+      static_cast<int>(gl_reset_notification_strategy));
+  enumerator->AddBool("can_lose_context", can_lose_context);
+  // TODO(kbr): add performance_stats.
+  enumerator->AddBool("softwareRendering", software_rendering);
+  enumerator->AddBool("sandboxed", sandboxed);
+  // TODO(kbr): add dx_diagnostics on Windows.
+  enumerator->EndAuxAttributes();
+}
+
 }  // namespace gpu
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 98ab80c..456f4e9 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -140,6 +140,41 @@
   // The information returned by the DirectX Diagnostics Tool.
   DxDiagNode dx_diagnostics;
 #endif
+  // Note: when adding new members, please remember to update EnumerateFields
+  // in gpu_info.cc.
+
+  // In conjunction with EnumerateFields, this allows the embedder to
+  // enumerate the values in this structure without having to embed
+  // references to its specific member variables. This simplifies the
+  // addition of new fields to this type.
+  class Enumerator {
+   public:
+    // The following methods apply to the "current" object. Initially this
+    // is the root object, but calls to BeginGPUDevice/EndGPUDevice and
+    // BeginAuxAttributes/EndAuxAttributes change the object to which these
+    // calls should apply.
+    virtual void AddInt64(const char* name, int64 value) = 0;
+    virtual void AddInt(const char* name, int value) = 0;
+    virtual void AddString(const char* name, const std::string& value) = 0;
+    virtual void AddBool(const char* name, bool value) = 0;
+    virtual void AddTimeDeltaInSecondsF(const char* name,
+                                        const base::TimeDelta& value) = 0;
+
+    // Markers indicating that a GPUDevice is being described.
+    virtual void BeginGPUDevice() = 0;
+    virtual void EndGPUDevice() = 0;
+
+    // Markers indicating that "auxiliary" attributes of the GPUInfo
+    // (according to the DevTools protocol) are being described.
+    virtual void BeginAuxAttributes() = 0;
+    virtual void EndAuxAttributes() = 0;
+
+   protected:
+    virtual ~Enumerator() {}
+  };
+
+  // Outputs the fields in this structure to the provided enumerator.
+  void EnumerateFields(Enumerator* enumerator) const;
 };
 
 }  // namespace gpu
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc
index 66934bb..7de9e36 100644
--- a/gpu/gles2_conform_support/egl/display.cc
+++ b/gpu/gles2_conform_support/egl/display.cc
@@ -234,7 +234,8 @@
   if (!context_->Initialize(
       kTransferBufferSize,
       kTransferBufferSize / 2,
-      kTransferBufferSize * 2)) {
+      kTransferBufferSize * 2,
+      gpu::gles2::GLES2Implementation::kNoLimit)) {
     return EGL_NO_CONTEXT;
   }
 
diff --git a/gpu/gpu_common.gypi b/gpu/gpu_common.gypi
index da2be68..015d9c6 100644
--- a/gpu/gpu_common.gypi
+++ b/gpu/gpu_common.gypi
@@ -39,7 +39,6 @@
       'command_buffer/client/gpu_memory_buffer_factory.h',
       'command_buffer/client/gpu_memory_buffer_tracker.cc',
       'command_buffer/client/gpu_memory_buffer_tracker.h',
-      'command_buffer/client/image_factory.h',
       'command_buffer/client/program_info_manager.cc',
       'command_buffer/client/program_info_manager.h',
       'command_buffer/client/query_tracker.cc',
diff --git a/gpu/gpu_untrusted.gyp b/gpu/gpu_untrusted.gyp
index a1f755c..7974d12 100644
--- a/gpu/gpu_untrusted.gyp
+++ b/gpu/gpu_untrusted.gyp
@@ -22,7 +22,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libgles2_implementation_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'defines': [
@@ -46,7 +46,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libcommand_buffer_common_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'includes': [
@@ -65,7 +65,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libgles2_cmd_helper_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'includes': [
@@ -84,7 +84,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libcommand_buffer_client_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'includes': [
@@ -103,7 +103,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libgpu_ipc_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'includes': [
diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc
index 2fb9097..cf3a65e 100644
--- a/ipc/ipc_message.cc
+++ b/ipc/ipc_message.cc
@@ -27,7 +27,7 @@
   // Process ID. With the current trace event buffer cap, the 14-bit count did
   // not appear to wrap during a trace. Note that it is not a big deal if
   // collisions occur, as this is only used for debugging and trace analysis.
-  return ((pid << 22) | (count & 0x3fff)) << 8;
+  return ((pid << 14) | (count & 0x3fff)) << 8;
 }
 
 }  // namespace
diff --git a/ipc/ipc_untrusted.gyp b/ipc/ipc_untrusted.gyp
index a502548..7b0c548 100644
--- a/ipc/ipc_untrusted.gyp
+++ b/ipc/ipc_untrusted.gyp
@@ -21,7 +21,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libipc_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'dependencies': [
diff --git a/jingle/glue/chrome_async_socket.cc b/jingle/glue/chrome_async_socket.cc
index 39085e1..c14fb99 100644
--- a/jingle/glue/chrome_async_socket.cc
+++ b/jingle/glue/chrome_async_socket.cc
@@ -106,9 +106,9 @@
 
   net::HostPortPair dest_host_port_pair(address.hostname(), address.port());
 
-  transport_socket_.reset(
+  transport_socket_ =
       resolving_client_socket_factory_->CreateTransportClientSocket(
-          dest_host_port_pair));
+          dest_host_port_pair);
   int status = transport_socket_->Connect(
       base::Bind(&ChromeAsyncSocket::ProcessConnectDone,
                  weak_ptr_factory_.GetWeakPtr()));
@@ -404,10 +404,10 @@
   DCHECK(transport_socket_.get());
   scoped_ptr<net::ClientSocketHandle> socket_handle(
       new net::ClientSocketHandle());
-  socket_handle->set_socket(transport_socket_.release());
-  transport_socket_.reset(
+  socket_handle->SetSocket(transport_socket_.Pass());
+  transport_socket_ =
       resolving_client_socket_factory_->CreateSSLClientSocket(
-          socket_handle.release(), net::HostPortPair(domain_name, 443)));
+          socket_handle.Pass(), net::HostPortPair(domain_name, 443));
   int status = transport_socket_->Connect(
       base::Bind(&ChromeAsyncSocket::ProcessSSLConnectDone,
                  weak_ptr_factory_.GetWeakPtr()));
diff --git a/jingle/glue/chrome_async_socket_unittest.cc b/jingle/glue/chrome_async_socket_unittest.cc
index ebb69a2..db3d2b0 100644
--- a/jingle/glue/chrome_async_socket_unittest.cc
+++ b/jingle/glue/chrome_async_socket_unittest.cc
@@ -113,20 +113,20 @@
   }
 
   // ResolvingClientSocketFactory implementation.
-  virtual net::StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<net::StreamSocket> CreateTransportClientSocket(
       const net::HostPortPair& host_and_port) OVERRIDE {
     return mock_client_socket_factory_->CreateTransportClientSocket(
         address_list_, NULL, net::NetLog::Source());
   }
 
-  virtual net::SSLClientSocket* CreateSSLClientSocket(
-      net::ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<net::SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<net::ClientSocketHandle> transport_socket,
       const net::HostPortPair& host_and_port) OVERRIDE {
     net::SSLClientSocketContext context;
     context.cert_verifier = cert_verifier_.get();
     context.transport_security_state = transport_security_state_.get();
     return mock_client_socket_factory_->CreateSSLClientSocket(
-        transport_socket, host_and_port, ssl_config_, context);
+        transport_socket.Pass(), host_and_port, ssl_config_, context);
   }
 
  private:
diff --git a/jingle/glue/fake_ssl_client_socket.cc b/jingle/glue/fake_ssl_client_socket.cc
index bf6d12a..9d722c7 100644
--- a/jingle/glue/fake_ssl_client_socket.cc
+++ b/jingle/glue/fake_ssl_client_socket.cc
@@ -77,8 +77,8 @@
 }
 
 FakeSSLClientSocket::FakeSSLClientSocket(
-    net::StreamSocket* transport_socket)
-    : transport_socket_(transport_socket),
+    scoped_ptr<net::StreamSocket> transport_socket)
+    : transport_socket_(transport_socket.Pass()),
       next_handshake_state_(STATE_NONE),
       handshake_completed_(false),
       write_buf_(NewDrainableIOBufferWithSize(arraysize(kSslClientHello))),
diff --git a/jingle/glue/fake_ssl_client_socket.h b/jingle/glue/fake_ssl_client_socket.h
index 5bc4547..54a9e2f 100644
--- a/jingle/glue/fake_ssl_client_socket.h
+++ b/jingle/glue/fake_ssl_client_socket.h
@@ -36,8 +36,7 @@
 
 class FakeSSLClientSocket : public net::StreamSocket {
  public:
-  // Takes ownership of |transport_socket|.
-  explicit FakeSSLClientSocket(net::StreamSocket* transport_socket);
+  explicit FakeSSLClientSocket(scoped_ptr<net::StreamSocket> transport_socket);
 
   virtual ~FakeSSLClientSocket();
 
diff --git a/jingle/glue/fake_ssl_client_socket_unittest.cc b/jingle/glue/fake_ssl_client_socket_unittest.cc
index 5c061f3..f6d8fea 100644
--- a/jingle/glue/fake_ssl_client_socket_unittest.cc
+++ b/jingle/glue/fake_ssl_client_socket_unittest.cc
@@ -91,7 +91,7 @@
 
   virtual ~FakeSSLClientSocketTest() {}
 
-  net::StreamSocket* MakeClientSocket() {
+  scoped_ptr<net::StreamSocket> MakeClientSocket() {
     return mock_client_socket_factory_.CreateTransportClientSocket(
         net::AddressList(), NULL, net::NetLog::Source());
   }
@@ -269,7 +269,7 @@
 };
 
 TEST_F(FakeSSLClientSocketTest, PassThroughMethods) {
-  MockClientSocket* mock_client_socket = new MockClientSocket();
+  scoped_ptr<MockClientSocket> mock_client_socket(new MockClientSocket());
   const int kReceiveBufferSize = 10;
   const int kSendBufferSize = 20;
   net::IPEndPoint ip_endpoint(net::IPAddressNumber(net::kIPv4AddressSize), 80);
@@ -284,7 +284,8 @@
   EXPECT_CALL(*mock_client_socket, SetOmniboxSpeculation());
 
   // Takes ownership of |mock_client_socket|.
-  FakeSSLClientSocket fake_ssl_client_socket(mock_client_socket);
+  FakeSSLClientSocket fake_ssl_client_socket(
+      mock_client_socket.PassAs<net::StreamSocket>());
   fake_ssl_client_socket.SetReceiveBufferSize(kReceiveBufferSize);
   fake_ssl_client_socket.SetSendBufferSize(kSendBufferSize);
   EXPECT_EQ(kPeerAddress,
diff --git a/jingle/glue/resolving_client_socket_factory.h b/jingle/glue/resolving_client_socket_factory.h
index 5be8bc8..d1b9fc1 100644
--- a/jingle/glue/resolving_client_socket_factory.h
+++ b/jingle/glue/resolving_client_socket_factory.h
@@ -5,6 +5,7 @@
 #ifndef JINGLE_GLUE_RESOLVING_CLIENT_SOCKET_FACTORY_H_
 #define JINGLE_GLUE_RESOLVING_CLIENT_SOCKET_FACTORY_H_
 
+#include "base/memory/scoped_ptr.h"
 
 namespace net {
 class ClientSocketHandle;
@@ -23,11 +24,11 @@
  public:
   virtual ~ResolvingClientSocketFactory() { }
   // Method to create a transport socket using a HostPortPair.
-  virtual net::StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<net::StreamSocket> CreateTransportClientSocket(
       const net::HostPortPair& host_and_port) = 0;
 
-  virtual net::SSLClientSocket* CreateSSLClientSocket(
-      net::ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<net::SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<net::ClientSocketHandle> transport_socket,
       const net::HostPortPair& host_and_port) = 0;
 };
 
diff --git a/jingle/glue/xmpp_client_socket_factory.cc b/jingle/glue/xmpp_client_socket_factory.cc
index b9e040d..4823ee5 100644
--- a/jingle/glue/xmpp_client_socket_factory.cc
+++ b/jingle/glue/xmpp_client_socket_factory.cc
@@ -8,6 +8,7 @@
 #include "jingle/glue/fake_ssl_client_socket.h"
 #include "jingle/glue/proxy_resolving_client_socket.h"
 #include "net/socket/client_socket_factory.h"
+#include "net/socket/client_socket_handle.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -28,20 +29,25 @@
 
 XmppClientSocketFactory::~XmppClientSocketFactory() {}
 
-net::StreamSocket* XmppClientSocketFactory::CreateTransportClientSocket(
+scoped_ptr<net::StreamSocket>
+XmppClientSocketFactory::CreateTransportClientSocket(
     const net::HostPortPair& host_and_port) {
   // TODO(akalin): Use socket pools.
-  net::StreamSocket* transport_socket = new ProxyResolvingClientSocket(
-      NULL,
-      request_context_getter_,
-      ssl_config_,
-      host_and_port);
+  scoped_ptr<net::StreamSocket> transport_socket(
+      new ProxyResolvingClientSocket(
+          NULL,
+          request_context_getter_,
+          ssl_config_,
+          host_and_port));
   return (use_fake_ssl_client_socket_ ?
-          new FakeSSLClientSocket(transport_socket) : transport_socket);
+          scoped_ptr<net::StreamSocket>(
+              new FakeSSLClientSocket(transport_socket.Pass())) :
+          transport_socket.Pass());
 }
 
-net::SSLClientSocket* XmppClientSocketFactory::CreateSSLClientSocket(
-    net::ClientSocketHandle* transport_socket,
+scoped_ptr<net::SSLClientSocket>
+XmppClientSocketFactory::CreateSSLClientSocket(
+    scoped_ptr<net::ClientSocketHandle> transport_socket,
     const net::HostPortPair& host_and_port) {
   net::SSLClientSocketContext context;
   context.cert_verifier =
@@ -52,7 +58,7 @@
   // TODO(rkn): context.server_bound_cert_service is NULL because the
   // ServerBoundCertService class is not thread safe.
   return client_socket_factory_->CreateSSLClientSocket(
-      transport_socket, host_and_port, ssl_config_, context);
+      transport_socket.Pass(), host_and_port, ssl_config_, context);
 }
 
 
diff --git a/jingle/glue/xmpp_client_socket_factory.h b/jingle/glue/xmpp_client_socket_factory.h
index c2a0d6a..4204c19 100644
--- a/jingle/glue/xmpp_client_socket_factory.h
+++ b/jingle/glue/xmpp_client_socket_factory.h
@@ -35,11 +35,11 @@
   virtual ~XmppClientSocketFactory();
 
   // ResolvingClientSocketFactory implementation.
-  virtual net::StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<net::StreamSocket> CreateTransportClientSocket(
       const net::HostPortPair& host_and_port) OVERRIDE;
 
-  virtual net::SSLClientSocket* CreateSSLClientSocket(
-      net::ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<net::SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<net::ClientSocketHandle> transport_socket,
       const net::HostPortPair& host_and_port) OVERRIDE;
 
  private:
diff --git a/jingle/notifier/listener/push_notifications_subscribe_task.cc b/jingle/notifier/listener/push_notifications_subscribe_task.cc
index 33f9949..b069c9e 100644
--- a/jingle/notifier/listener/push_notifications_subscribe_task.cc
+++ b/jingle/notifier/listener/push_notifications_subscribe_task.cc
@@ -43,7 +43,6 @@
   scoped_ptr<buzz::XmlElement> iq_stanza(
       MakeSubscriptionMessage(subscriptions_, GetClient()->jid(),
                               task_id()));
-  std::string stanza_str = XmlElementToString(*iq_stanza.get());
   DVLOG(1) << "Push notifications: Subscription stanza: "
           << XmlElementToString(*iq_stanza.get());
 
@@ -61,10 +60,9 @@
   if (stanza == NULL) {
     return STATE_BLOCKED;
   }
-  std::string stanza_str = XmlElementToString(*stanza);
   DVLOG(1) << "Push notifications: Subscription response: "
            << XmlElementToString(*stanza);
-  // We've receieved a response to our subscription request.
+  // We've received a response to our subscription request.
   if (stanza->HasAttr(buzz::QN_TYPE) &&
     stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT) {
     if (delegate_)
diff --git a/media/DEPS b/media/DEPS
index 9c27aba..495c804 100644
--- a/media/DEPS
+++ b/media/DEPS
@@ -5,6 +5,7 @@
   "+third_party/libvpx",
   "+third_party/opus",
   "+third_party/skia",
+  "+ui/base",
   "+ui/gfx",
   "+ui/gl",
 ]
diff --git a/media/audio/async_socket_io_handler.h b/media/audio/async_socket_io_handler.h
deleted file mode 100644
index cc7185e..0000000
--- a/media/audio/async_socket_io_handler.h
+++ /dev/null
@@ -1,113 +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_ASYNC_SOCKET_IO_HANDLER_H_
-#define MEDIA_AUDIO_ASYNC_SOCKET_IO_HANDLER_H_
-
-#include "base/message_loop/message_loop.h"
-#include "base/sync_socket.h"
-#include "base/threading/non_thread_safe.h"
-#include "media/base/media_export.h"
-
-namespace media {
-
-// The message loop callback interface is different based on platforms.
-#if defined(OS_WIN)
-typedef base::MessageLoopForIO::IOHandler MessageLoopIOHandler;
-#elif defined(OS_POSIX)
-typedef base::MessageLoopForIO::Watcher MessageLoopIOHandler;
-#endif
-
-// Extends the CancelableSyncSocket class to allow reading from a socket
-// asynchronously on a TYPE_IO message loop thread.  This makes it easy to share
-// a thread that uses a message loop (e.g. for IPC and other things) and not
-// require a separate thread to read from the socket.
-//
-// Example usage (also see the unit tests):
-//
-// class SocketReader {
-//  public:
-//   SocketReader(base::CancelableSyncSocket* socket)
-//       : socket_(socket), buffer_() {
-//     io_handler.Initialize(socket_->handle(),
-//                           base::Bind(&SocketReader::OnDataAvailable,
-//                                      base::Unretained(this));
-//   }
-//
-//   void AsyncRead() {
-//     CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
-//   }
-//
-//  private:
-//   void OnDataAvailable(int bytes_read) {
-//     if (ProcessData(&buffer_[0], bytes_read)) {
-//       // Issue another read.
-//       CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
-//     }
-//   }
-//
-//   media::AsyncSocketIoHandler io_handler;
-//   base::CancelableSyncSocket* socket_;
-//   char buffer_[kBufferSize];
-// };
-//
-class MEDIA_EXPORT AsyncSocketIoHandler
-    : public NON_EXPORTED_BASE(base::NonThreadSafe),
-      public NON_EXPORTED_BASE(MessageLoopIOHandler) {
- public:
-  AsyncSocketIoHandler();
-  virtual ~AsyncSocketIoHandler();
-
-  // Type definition for the callback. The parameter tells how many
-  // bytes were read and is 0 if an error occurred.
-  typedef base::Callback<void(int)> ReadCompleteCallback;
-
-  // Initializes the AsyncSocketIoHandler by hooking it up to the current
-  // thread's message loop (must be TYPE_IO), to do async reads from the socket
-  // on the current thread.  The |callback| will be invoked whenever a Read()
-  // has completed.
-  bool Initialize(base::SyncSocket::Handle socket,
-                  const ReadCompleteCallback& callback);
-
-  // Attempts to read from the socket.  The return value will be |false|
-  // if an error occurred and |true| if data was read or a pending read
-  // was issued.  Regardless of async or sync operation, the
-  // ReadCompleteCallback (see above) will be called when data is available.
-  bool Read(char* buffer, int buffer_len);
-
- private:
-#if defined(OS_WIN)
-  // Implementation of IOHandler on Windows.
-  virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
-                             DWORD bytes_transfered,
-                             DWORD error) OVERRIDE;
-#elif defined(OS_POSIX)
-  // Implementation of base::MessageLoopForIO::Watcher.
-  virtual void OnFileCanWriteWithoutBlocking(int socket) OVERRIDE {}
-  virtual void OnFileCanReadWithoutBlocking(int socket) OVERRIDE;
-
-  void EnsureWatchingSocket();
-#endif
-
-  base::SyncSocket::Handle socket_;
-#if defined(OS_WIN)
-  base::MessageLoopForIO::IOContext* context_;
-  bool is_pending_;
-#elif defined(OS_POSIX)
-  base::MessageLoopForIO::FileDescriptorWatcher socket_watcher_;
-  // |pending_buffer_| and |pending_buffer_len_| are valid only between
-  // Read() and OnFileCanReadWithoutBlocking().
-  char* pending_buffer_;
-  int pending_buffer_len_;
-  // |true| iff the message loop is watching the socket for IO events.
-  bool is_watching_;
-#endif
-  ReadCompleteCallback read_complete_;
-
-  DISALLOW_COPY_AND_ASSIGN(AsyncSocketIoHandler);
-};
-
-}  // namespace media.
-
-#endif  // MEDIA_AUDIO_ASYNC_SOCKET_IO_HANDLER_H_
diff --git a/media/audio/async_socket_io_handler_posix.cc b/media/audio/async_socket_io_handler_posix.cc
deleted file mode 100644
index be8f370..0000000
--- a/media/audio/async_socket_io_handler_posix.cc
+++ /dev/null
@@ -1,98 +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/async_socket_io_handler.h"
-
-#include <fcntl.h>
-
-#include "base/posix/eintr_wrapper.h"
-
-namespace media {
-
-AsyncSocketIoHandler::AsyncSocketIoHandler()
-    : socket_(base::SyncSocket::kInvalidHandle),
-      pending_buffer_(NULL),
-      pending_buffer_len_(0),
-      is_watching_(false) {
-}
-
-AsyncSocketIoHandler::~AsyncSocketIoHandler() {
-  DCHECK(CalledOnValidThread());
-}
-
-void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
-  DCHECK(CalledOnValidThread());
-  DCHECK_EQ(socket, socket_);
-  DCHECK(!read_complete_.is_null());
-
-  if (pending_buffer_) {
-    int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
-                                       pending_buffer_len_));
-    DCHECK_GE(bytes_read, 0);
-    pending_buffer_ = NULL;
-    pending_buffer_len_ = 0;
-    read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
-  } else {
-    // We're getting notifications that we can read from the socket while
-    // we're not waiting for data.  In order to not starve the message loop,
-    // let's stop watching the fd and restart the watch when Read() is called.
-    is_watching_ = false;
-    socket_watcher_.StopWatchingFileDescriptor();
-  }
-}
-
-bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(!read_complete_.is_null());
-  DCHECK(!pending_buffer_);
-
-  EnsureWatchingSocket();
-
-  int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
-  if (bytes_read < 0) {
-    if (errno == EAGAIN) {
-      pending_buffer_ = buffer;
-      pending_buffer_len_ = buffer_len;
-    } else {
-      NOTREACHED() << "read(): " << errno;
-      return false;
-    }
-  } else {
-    read_complete_.Run(bytes_read);
-  }
-  return true;
-}
-
-bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
-                                      const ReadCompleteCallback& callback) {
-  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
-
-  DetachFromThread();
-
-  socket_ = socket;
-  read_complete_ = callback;
-
-  // SyncSocket is blocking by default, so let's convert it to non-blocking.
-  int value = fcntl(socket, F_GETFL);
-  if (!(value & O_NONBLOCK)) {
-    // Set the socket to be non-blocking so we can do async reads.
-    if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
-      NOTREACHED();
-      return false;
-    }
-  }
-
-  return true;
-}
-
-void AsyncSocketIoHandler::EnsureWatchingSocket() {
-  DCHECK(CalledOnValidThread());
-  if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
-    is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
-        socket_, true, base::MessageLoopForIO::WATCH_READ,
-        &socket_watcher_, this);
-  }
-}
-
-}  // namespace media.
diff --git a/media/audio/async_socket_io_handler_unittest.cc b/media/audio/async_socket_io_handler_unittest.cc
deleted file mode 100644
index ae97146..0000000
--- a/media/audio/async_socket_io_handler_unittest.cc
+++ /dev/null
@@ -1,168 +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/async_socket_io_handler.h"
-
-#include "base/bind.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-const char kAsyncSocketIoTestString[] = "Hello, AsyncSocketIoHandler";
-const size_t kAsyncSocketIoTestStringLength =
-    arraysize(kAsyncSocketIoTestString);
-
-class TestSocketReader {
- public:
-  // Set |number_of_reads_before_quit| to >0 when you expect a specific number
-  // of Read operations to complete.  Once that number is reached, the current
-  // message loop will be Quit().  Set |number_of_reads_before_quit| to -1 if
-  // callbacks should not be counted.
-  TestSocketReader(base::CancelableSyncSocket* socket,
-                   int number_of_reads_before_quit,
-                   bool issue_reads_from_callback,
-                   bool expect_eof)
-      : socket_(socket), buffer_(),
-        number_of_reads_before_quit_(number_of_reads_before_quit),
-        callbacks_received_(0),
-        issue_reads_from_callback_(issue_reads_from_callback),
-        expect_eof_(expect_eof) {
-    io_handler.Initialize(socket_->handle(),
-                          base::Bind(&TestSocketReader::OnRead,
-                                     base::Unretained(this)));
-  }
-  ~TestSocketReader() {}
-
-  bool IssueRead() {
-    return io_handler.Read(&buffer_[0], sizeof(buffer_));
-  }
-
-  const char* buffer() const { return &buffer_[0]; }
-
-  int callbacks_received() const { return callbacks_received_; }
-
- private:
-  void OnRead(int bytes_read) {
-    if (!expect_eof_) {
-      EXPECT_GT(bytes_read, 0);
-    } else {
-      EXPECT_GE(bytes_read, 0);
-    }
-    ++callbacks_received_;
-    if (number_of_reads_before_quit_ == callbacks_received_) {
-      base::MessageLoop::current()->Quit();
-    } else if (issue_reads_from_callback_) {
-      IssueRead();
-    }
-  }
-
-  media::AsyncSocketIoHandler io_handler;
-  base::CancelableSyncSocket* socket_;  // Ownership lies outside the class.
-  char buffer_[kAsyncSocketIoTestStringLength];
-  int number_of_reads_before_quit_;
-  int callbacks_received_;
-  bool issue_reads_from_callback_;
-  bool expect_eof_;
-};
-
-// Workaround to be able to use a base::Closure for sending data.
-// Send() returns int but a closure must return void.
-void SendData(base::CancelableSyncSocket* socket,
-              const void* buffer,
-              size_t length) {
-  socket->Send(buffer, length);
-}
-
-}  // end namespace.
-
-// Tests doing a pending read from a socket and use an IO handler to get
-// notified of data.
-TEST(AsyncSocketIoHandlerTest, AsynchronousReadWithMessageLoop) {
-  base::MessageLoopForIO loop;
-
-  base::CancelableSyncSocket pair[2];
-  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
-  TestSocketReader reader(&pair[0], 1, false, false);
-  EXPECT_TRUE(reader.IssueRead());
-
-  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
-  base::MessageLoop::current()->Run();
-  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
-  EXPECT_EQ(1, reader.callbacks_received());
-}
-
-// Tests doing a read from a socket when we know that there is data in the
-// socket.  Here we want to make sure that any async 'can read' notifications
-// won't trip us off and that the synchronous case works as well.
-TEST(AsyncSocketIoHandlerTest, SynchronousReadWithMessageLoop) {
-  base::MessageLoopForIO loop;
-
-  base::CancelableSyncSocket pair[2];
-  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
-  TestSocketReader reader(&pair[0], -1, false, false);
-
-  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      base::TimeDelta::FromMilliseconds(100));
-  base::MessageLoop::current()->Run();
-
-  EXPECT_TRUE(reader.IssueRead());
-  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
-  // We've now verified that the read happened synchronously, but it's not
-  // guaranteed that the callback has been issued since the callback will be
-  // called asynchronously even though the read may have been done.
-  // So we call RunUntilIdle() to allow any event notifications or APC's on
-  // Windows, to execute before checking the count of how many callbacks we've
-  // received.
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(1, reader.callbacks_received());
-}
-
-// Calls Read() from within a callback to test that simple read "loops" work.
-TEST(AsyncSocketIoHandlerTest, ReadFromCallback) {
-  base::MessageLoopForIO loop;
-
-  base::CancelableSyncSocket pair[2];
-  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
-  const int kReadOperationCount = 10;
-  TestSocketReader reader(&pair[0], kReadOperationCount, true, false);
-  EXPECT_TRUE(reader.IssueRead());
-
-  // Issue sends on an interval to satisfy the Read() requirements.
-  int64 milliseconds = 0;
-  for (int i = 0; i < kReadOperationCount; ++i) {
-    base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-        base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
-            kAsyncSocketIoTestStringLength),
-        base::TimeDelta::FromMilliseconds(milliseconds));
-    milliseconds += 10;
-  }
-
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::MessageLoop::QuitClosure(),
-      base::TimeDelta::FromMilliseconds(100 + milliseconds));
-
-  base::MessageLoop::current()->Run();
-  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
-}
-
-// Calls Read() then close other end, check that a correct callback is received.
-TEST(AsyncSocketIoHandlerTest, ReadThenClose) {
-  base::MessageLoopForIO loop;
-
-  base::CancelableSyncSocket pair[2];
-  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
-
-  const int kReadOperationCount = 1;
-  TestSocketReader reader(&pair[0], kReadOperationCount, false, true);
-  EXPECT_TRUE(reader.IssueRead());
-
-  pair[1].Close();
-
-  base::MessageLoop::current()->Run();
-  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
-}
diff --git a/media/audio/async_socket_io_handler_win.cc b/media/audio/async_socket_io_handler_win.cc
deleted file mode 100644
index ea6bd4a..0000000
--- a/media/audio/async_socket_io_handler_win.cc
+++ /dev/null
@@ -1,77 +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/async_socket_io_handler.h"
-
-namespace media {
-
-AsyncSocketIoHandler::AsyncSocketIoHandler()
-    : socket_(base::SyncSocket::kInvalidHandle),
-      context_(NULL),
-      is_pending_(false) {}
-
-AsyncSocketIoHandler::~AsyncSocketIoHandler() {
-  // We need to be deleted on the correct thread to avoid racing with the
-  // message loop thread.
-  DCHECK(CalledOnValidThread());
-
-  if (context_) {
-    if (is_pending_) {
-      // Make the context be deleted by the message pump when done.
-      context_->handler = NULL;
-    } else {
-      delete context_;
-    }
-  }
-}
-
-// Implementation of IOHandler on Windows.
-void AsyncSocketIoHandler::OnIOCompleted(
-    base::MessageLoopForIO::IOContext* context,
-    DWORD bytes_transfered,
-    DWORD error) {
-  DCHECK(CalledOnValidThread());
-  DCHECK_EQ(context_, context);
-  DCHECK(!read_complete_.is_null());
-  is_pending_ = false;
-  read_complete_.Run(error == ERROR_SUCCESS ? bytes_transfered : 0);
-}
-
-bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(!read_complete_.is_null());
-  DCHECK(!is_pending_);
-  DCHECK_NE(socket_, base::SyncSocket::kInvalidHandle);
-
-  DWORD bytes_read = 0;
-  BOOL ok = ::ReadFile(socket_, buffer, buffer_len, &bytes_read,
-                       &context_->overlapped);
-  // The completion port will be signaled regardless of completing the read
-  // straight away or asynchronously (ERROR_IO_PENDING). OnIOCompleted() will
-  // be called regardless and we don't need to explicitly run the callback
-  // in the case where ok is FALSE and GLE==ERROR_IO_PENDING.
-  is_pending_ = !ok && (GetLastError() == ERROR_IO_PENDING);
-  return ok || is_pending_;
-}
-
-bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
-                                      const ReadCompleteCallback& callback) {
-  DCHECK(!context_);
-  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
-
-  DetachFromThread();
-
-  socket_ = socket;
-  read_complete_ = callback;
-
-  base::MessageLoopForIO::current()->RegisterIOHandler(socket, this);
-
-  context_ = new base::MessageLoopForIO::IOContext();
-  context_->handler = this;
-  memset(&context_->overlapped, 0, sizeof(context_->overlapped));
-
-  return true;
-}
-
-}  // namespace media.
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc
index 31e137e..f7747b9 100644
--- a/media/audio/audio_input_controller.cc
+++ b/media/audio/audio_input_controller.cc
@@ -36,14 +36,17 @@
 AudioInputController::Factory* AudioInputController::factory_ = NULL;
 
 AudioInputController::AudioInputController(EventHandler* handler,
-                                           SyncWriter* sync_writer)
+                                           SyncWriter* sync_writer,
+                                           UserInputMonitor* user_input_monitor)
     : creator_loop_(base::MessageLoopProxy::current()),
       handler_(handler),
       stream_(NULL),
       data_is_active_(false),
       state_(kEmpty),
       sync_writer_(sync_writer),
-      max_volume_(0.0) {
+      max_volume_(0.0),
+      user_input_monitor_(user_input_monitor),
+      key_pressed_(false) {
   DCHECK(creator_loop_.get());
 }
 
@@ -56,17 +59,19 @@
     AudioManager* audio_manager,
     EventHandler* event_handler,
     const AudioParameters& params,
-    const std::string& device_id) {
+    const std::string& device_id,
+    UserInputMonitor* user_input_monitor) {
   DCHECK(audio_manager);
 
   if (!params.IsValid() || (params.channels() > kMaxInputChannels))
     return NULL;
 
-  if (factory_)
-    return factory_->Create(audio_manager, event_handler, params);
-
-  scoped_refptr<AudioInputController> controller(new AudioInputController(
-      event_handler, NULL));
+  if (factory_) {
+    return factory_->Create(
+        audio_manager, event_handler, params, user_input_monitor);
+  }
+  scoped_refptr<AudioInputController> controller(
+      new AudioInputController(event_handler, NULL, user_input_monitor));
 
   controller->message_loop_ = audio_manager->GetMessageLoop();
 
@@ -87,7 +92,8 @@
     EventHandler* event_handler,
     const AudioParameters& params,
     const std::string& device_id,
-    SyncWriter* sync_writer) {
+    SyncWriter* sync_writer,
+    UserInputMonitor* user_input_monitor) {
   DCHECK(audio_manager);
   DCHECK(sync_writer);
 
@@ -96,8 +102,8 @@
 
   // Create the AudioInputController object and ensure that it runs on
   // the audio-manager thread.
-  scoped_refptr<AudioInputController> controller(new AudioInputController(
-      event_handler, sync_writer));
+  scoped_refptr<AudioInputController> controller(
+      new AudioInputController(event_handler, sync_writer, user_input_monitor));
   controller->message_loop_ = audio_manager->GetMessageLoop();
 
   // Create and open a new audio input stream from the existing
@@ -116,14 +122,15 @@
     const scoped_refptr<base::MessageLoopProxy>& message_loop,
     EventHandler* event_handler,
     AudioInputStream* stream,
-    SyncWriter* sync_writer) {
+    SyncWriter* sync_writer,
+    UserInputMonitor* user_input_monitor) {
   DCHECK(sync_writer);
   DCHECK(stream);
 
   // Create the AudioInputController object and ensure that it runs on
   // the audio-manager thread.
-  scoped_refptr<AudioInputController> controller(new AudioInputController(
-      event_handler, sync_writer));
+  scoped_refptr<AudioInputController> controller(
+      new AudioInputController(event_handler, sync_writer, user_input_monitor));
   controller->message_loop_ = message_loop;
 
   // TODO(miu): See TODO at top of file.  Until that's resolved, we need to
@@ -233,6 +240,9 @@
 
   stream_->Start(this);
   handler_->OnRecording(this);
+
+  if (user_input_monitor_)
+    user_input_monitor_->AddKeyStrokeListener(this);
 }
 
 void AudioInputController::DoClose() {
@@ -251,6 +261,9 @@
     }
 
     state_ = kClosed;
+
+    if (user_input_monitor_)
+      user_input_monitor_->RemoveKeyStrokeListener(this);
   }
 }
 
@@ -320,10 +333,13 @@
 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
                                   uint32 size, uint32 hardware_delay_bytes,
                                   double volume) {
+  bool key_pressed = false;
   {
     base::AutoLock auto_lock(lock_);
     if (state_ != kRecording)
       return;
+
+    std::swap(key_pressed, key_pressed_);
   }
 
   // Mark data as active to ensure that the periodic calls to
@@ -332,7 +348,7 @@
 
   // Use SyncSocket if we are in a low-latency mode.
   if (LowLatencyMode()) {
-    sync_writer_->Write(data, size, volume);
+    sync_writer_->Write(data, size, volume, key_pressed);
     sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
     return;
   }
@@ -353,8 +369,13 @@
       &AudioInputController::DoReportError, this));
 }
 
+void AudioInputController::OnKeyStroke() {
+  base::AutoLock auto_lock(lock_);
+  key_pressed_ = true;
+}
+
 void AudioInputController::DoStopCloseAndClearStream(
-    base::WaitableEvent *done) {
+    base::WaitableEvent* done) {
   DCHECK(message_loop_->BelongsToCurrentThread());
 
   // Allow calling unconditionally and bail if we don't have a stream to close.
diff --git a/media/audio/audio_input_controller.h b/media/audio/audio_input_controller.h
index 586d477..6be4821 100644
--- a/media/audio/audio_input_controller.h
+++ b/media/audio/audio_input_controller.h
@@ -16,6 +16,7 @@
 #include "base/timer/timer.h"
 #include "media/audio/audio_io.h"
 #include "media/audio/audio_manager_base.h"
+#include "media/base/user_input_monitor.h"
 
 // An AudioInputController controls an AudioInputStream and records data
 // from this input stream. The two main methods are Record() and Close() and
@@ -74,7 +75,8 @@
 
 class MEDIA_EXPORT AudioInputController
     : public base::RefCountedThreadSafe<AudioInputController>,
-      public AudioInputStream::AudioInputCallback {
+      public AudioInputStream::AudioInputCallback,
+      public UserInputMonitor::KeyStrokeListener {
  public:
   // An event handler that receives events from the AudioInputController. The
   // following methods are all called on the audio thread.
@@ -102,7 +104,10 @@
 
     // Write certain amount of data from |data|. This method returns
     // number of written bytes.
-    virtual uint32 Write(const void* data, uint32 size, double volume) = 0;
+    virtual uint32 Write(const void* data,
+                         uint32 size,
+                         double volume,
+                         bool key_pressed) = 0;
 
     // Close this synchronous writer.
     virtual void Close() = 0;
@@ -110,11 +115,15 @@
 
   // AudioInputController::Create() can use the currently registered Factory
   // to create the AudioInputController. Factory is intended for testing only.
+  // |user_input_monitor| is used for typing detection and can be NULL.
   class Factory {
    public:
-    virtual AudioInputController* Create(AudioManager* audio_manager,
-                                         EventHandler* event_handler,
-                                         AudioParameters params) = 0;
+    virtual AudioInputController* Create(
+        AudioManager* audio_manager,
+        EventHandler* event_handler,
+        AudioParameters params,
+        UserInputMonitor* user_input_monitor) = 0;
+
    protected:
     virtual ~Factory() {}
   };
@@ -123,11 +132,13 @@
   // The audio device will be created on the audio thread, and when that is
   // done, the event handler will receive an OnCreated() call from that same
   // thread. |device_id| is the unique ID of the audio device to be opened.
+  // |user_input_monitor| is used for typing detection and can be NULL.
   static scoped_refptr<AudioInputController> Create(
       AudioManager* audio_manager,
       EventHandler* event_handler,
       const AudioParameters& params,
-      const std::string& device_id);
+      const std::string& device_id,
+      UserInputMonitor* user_input_monitor);
 
   // Sets the factory used by the static method Create(). AudioInputController
   // does not take ownership of |factory|. A value of NULL results in an
@@ -138,25 +149,28 @@
   // Factory method for creating an AudioInputController for low-latency mode.
   // The audio device will be created on the audio thread, and when that is
   // done, the event handler will receive an OnCreated() call from that same
-  // thread.
+  // thread. |user_input_monitor| is used for typing detection and can be NULL.
   static scoped_refptr<AudioInputController> CreateLowLatency(
       AudioManager* audio_manager,
       EventHandler* event_handler,
       const AudioParameters& params,
       const std::string& device_id,
       // External synchronous writer for audio controller.
-      SyncWriter* sync_writer);
+      SyncWriter* sync_writer,
+      UserInputMonitor* user_input_monitor);
 
   // Factory method for creating an AudioInputController for low-latency mode,
   // taking ownership of |stream|.  The stream will be opened on the audio
   // thread, and when that is done, the event handler will receive an
-  // OnCreated() call from that same thread.
+  // OnCreated() call from that same thread. |user_input_monitor| is used for
+  // typing detection and can be NULL.
   static scoped_refptr<AudioInputController> CreateForStream(
       const scoped_refptr<base::MessageLoopProxy>& message_loop,
       EventHandler* event_handler,
       AudioInputStream* stream,
       // External synchronous writer for audio controller.
-      SyncWriter* sync_writer);
+      SyncWriter* sync_writer,
+      UserInputMonitor* user_input_monitor);
 
   // Starts recording using the created audio input stream.
   // This method is called on the creator thread.
@@ -189,6 +203,9 @@
 
   bool LowLatencyMode() const { return sync_writer_ != NULL; }
 
+  // Impl of KeyStrokeListener.
+  virtual void OnKeyStroke() OVERRIDE;
+
  protected:
   friend class base::RefCountedThreadSafe<AudioInputController>;
 
@@ -201,7 +218,9 @@
     kError
   };
 
-  AudioInputController(EventHandler* handler, SyncWriter* sync_writer);
+  AudioInputController(EventHandler* handler,
+                       SyncWriter* sync_writer,
+                       UserInputMonitor* user_input_monitor);
   virtual ~AudioInputController();
 
   // Methods called on the audio thread (owned by the AudioManager).
@@ -266,6 +285,11 @@
 
   double max_volume_;
 
+  UserInputMonitor* user_input_monitor_;
+
+  // True if any key has been pressed after the last OnData call.
+  bool key_pressed_;
+
   DISALLOW_COPY_AND_ASSIGN(AudioInputController);
 };
 
diff --git a/media/audio/audio_input_controller_unittest.cc b/media/audio/audio_input_controller_unittest.cc
index b96ef3a..6388cbf 100644
--- a/media/audio/audio_input_controller_unittest.cc
+++ b/media/audio/audio_input_controller_unittest.cc
@@ -83,9 +83,13 @@
   scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
   AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
                          kSampleRate, kBitsPerSample, kSamplesPerPacket);
+
   scoped_refptr<AudioInputController> controller =
-      AudioInputController::Create(audio_manager.get(), &event_handler, params,
-                                   AudioManagerBase::kDefaultDeviceId);
+      AudioInputController::Create(audio_manager.get(),
+                                   &event_handler,
+                                   params,
+                                   AudioManagerBase::kDefaultDeviceId,
+                                   NULL);
   ASSERT_TRUE(controller.get());
 
   // Wait for OnCreated() to fire.
@@ -120,8 +124,11 @@
 
   // Creating the AudioInputController should render an OnCreated() call.
   scoped_refptr<AudioInputController> controller =
-      AudioInputController::Create(audio_manager.get(), &event_handler, params,
-                                   AudioManagerBase::kDefaultDeviceId);
+      AudioInputController::Create(audio_manager.get(),
+                                   &event_handler,
+                                   params,
+                                   AudioManagerBase::kDefaultDeviceId,
+                                   NULL);
   ASSERT_TRUE(controller.get());
 
   // Start recording and trigger one OnRecording() call.
@@ -167,8 +174,11 @@
 
   // Creating the AudioInputController should render an OnCreated() call.
   scoped_refptr<AudioInputController> controller =
-      AudioInputController::Create(audio_manager.get(), &event_handler, params,
-                                   AudioManagerBase::kDefaultDeviceId);
+      AudioInputController::Create(audio_manager.get(),
+                                   &event_handler,
+                                   params,
+                                   AudioManagerBase::kDefaultDeviceId,
+                                   NULL);
   ASSERT_TRUE(controller.get());
 
   // Start recording and trigger one OnRecording() call.
@@ -196,11 +206,17 @@
     .Times(Exactly(0));
 
   scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
-  AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
-                         kSampleRate, kBitsPerSample, kSamplesPerPacket * 1000);
+  AudioParameters params(AudioParameters::AUDIO_FAKE,
+                         kChannelLayout,
+                         kSampleRate,
+                         kBitsPerSample,
+                         kSamplesPerPacket * 1000);
   scoped_refptr<AudioInputController> controller =
-      AudioInputController::Create(audio_manager.get(), &event_handler, params,
-                                   AudioManagerBase::kDefaultDeviceId);
+      AudioInputController::Create(audio_manager.get(),
+                                   &event_handler,
+                                   params,
+                                   AudioManagerBase::kDefaultDeviceId,
+                                   NULL);
   ASSERT_FALSE(controller.get());
 }
 
@@ -216,11 +232,17 @@
       .Times(Exactly(1));
 
   scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
-  AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
-                         kSampleRate, kBitsPerSample, kSamplesPerPacket);
+  AudioParameters params(AudioParameters::AUDIO_FAKE,
+                         kChannelLayout,
+                         kSampleRate,
+                         kBitsPerSample,
+                         kSamplesPerPacket);
   scoped_refptr<AudioInputController> controller =
-      AudioInputController::Create(audio_manager.get(), &event_handler, params,
-                                   AudioManagerBase::kDefaultDeviceId);
+      AudioInputController::Create(audio_manager.get(),
+                                   &event_handler,
+                                   params,
+                                   AudioManagerBase::kDefaultDeviceId,
+                                   NULL);
   ASSERT_TRUE(controller.get());
 
   controller->Record();
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index 87fd571..5477be6 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -294,6 +294,7 @@
   DCHECK_EQ(buffer->params.size,
             segment_length_ - sizeof(AudioInputBufferParameters));
   double volume = buffer->params.volume;
+  bool key_pressed = buffer->params.key_pressed;
 
   int audio_delay_milliseconds = pending_data / bytes_per_ms_;
   int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]);
@@ -308,8 +309,8 @@
 
   // Deliver captured data to the client in floating point format
   // and update the audio-delay measurement.
-  capture_callback_->Capture(audio_bus_.get(),
-                             audio_delay_milliseconds, volume);
+  capture_callback_->Capture(
+      audio_bus_.get(), audio_delay_milliseconds, volume, key_pressed);
 }
 
 }  // namespace media
diff --git a/media/audio/audio_parameters.h b/media/audio/audio_parameters.h
index 02a6f96..bc629a7 100644
--- a/media/audio/audio_parameters.h
+++ b/media/audio/audio_parameters.h
@@ -14,6 +14,7 @@
 struct MEDIA_EXPORT AudioInputBufferParameters {
   double volume;
   uint32 size;
+  bool key_pressed;
 };
 
 // Use a struct-in-struct approach to ensure that we can calculate the required
@@ -82,6 +83,7 @@
   // Comparison with other AudioParams.
   bool operator==(const AudioParameters& other) const {
     return format_ == other.format() &&
+           sample_rate_ == other.sample_rate() &&
            channel_layout_ == other.channel_layout() &&
            channels_ == other.channels() &&
            input_channels_ == other.input_channels() &&
diff --git a/media/audio/clockless_audio_sink.cc b/media/audio/clockless_audio_sink.cc
new file mode 100644
index 0000000..ff809d0
--- /dev/null
+++ b/media/audio/clockless_audio_sink.cc
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. 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/clockless_audio_sink.h"
+
+#include "base/threading/simple_thread.h"
+#include "base/time/time.h"
+#include "media/base/audio_renderer_sink.h"
+
+namespace media {
+
+// Internal to ClocklessAudioSink. Class is used to call Render() on a seperate
+// thread, running as fast as it can read the data.
+class ClocklessAudioSinkThread : public base::DelegateSimpleThread::Delegate {
+ public:
+  explicit ClocklessAudioSinkThread(const AudioParameters& params,
+                                    AudioRendererSink::RenderCallback* callback)
+      : callback_(callback),
+        audio_bus_(AudioBus::Create(params)),
+        stop_event_(new base::WaitableEvent(false, false)) {}
+
+  void Start() {
+    stop_event_->Reset();
+    thread_.reset(new base::DelegateSimpleThread(this, "ClocklessAudioSink"));
+    thread_->Start();
+  }
+
+  // Generate a signal to stop calling Render().
+  base::TimeDelta Stop() {
+    stop_event_->Signal();
+    thread_->Join();
+    return playback_time_;
+  }
+
+ private:
+   // Call Render() repeatedly, keeping track of the rendering time.
+   virtual void Run() OVERRIDE {
+     base::TimeTicks start;
+     while (!stop_event_->IsSignaled()) {
+       int frames_received = callback_->Render(audio_bus_.get(), 0);
+       if (frames_received <= 0) {
+         // No data received, so let other threads run to provide data.
+         base::PlatformThread::YieldCurrentThread();
+       } else if (start.is_null()) {
+         // First time we processed some audio, so record the starting time.
+         start = base::TimeTicks::HighResNow();
+       } else {
+         // Keep track of the last time data was rendered.
+         playback_time_ = base::TimeTicks::HighResNow() - start;
+       }
+     }
+   }
+
+  AudioRendererSink::RenderCallback* callback_;
+  scoped_ptr<AudioBus> audio_bus_;
+  scoped_ptr<base::WaitableEvent> stop_event_;
+  scoped_ptr<base::DelegateSimpleThread> thread_;
+  base::TimeDelta playback_time_;
+};
+
+ClocklessAudioSink::ClocklessAudioSink()
+    : initialized_(false),
+      playing_(false) {}
+
+ClocklessAudioSink::~ClocklessAudioSink() {}
+
+void ClocklessAudioSink::Initialize(const AudioParameters& params,
+                                    RenderCallback* callback) {
+  DCHECK(!initialized_);
+  thread_.reset(new ClocklessAudioSinkThread(params, callback));
+  initialized_ = true;
+}
+
+void ClocklessAudioSink::Start() {
+  DCHECK(!playing_);
+}
+
+void ClocklessAudioSink::Stop() {
+  DCHECK(initialized_);
+
+  if (!playing_)
+    return;
+
+  playback_time_ = thread_->Stop();
+}
+
+void ClocklessAudioSink::Play() {
+  DCHECK(initialized_);
+
+  if (playing_)
+    return;
+
+  playing_ = true;
+  thread_->Start();
+}
+
+void ClocklessAudioSink::Pause() {
+  Stop();
+}
+
+bool ClocklessAudioSink::SetVolume(double volume) {
+  // Audio is always muted.
+  return volume == 0.0;
+}
+
+}  // namespace media
diff --git a/media/audio/clockless_audio_sink.h b/media/audio/clockless_audio_sink.h
new file mode 100644
index 0000000..9e73b1a
--- /dev/null
+++ b/media/audio/clockless_audio_sink.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 MEDIA_AUDIO_CLOCKLESS_AUDIO_SINK_H_
+#define MEDIA_AUDIO_CLOCKLESS_AUDIO_SINK_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "media/base/audio_renderer_sink.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace media {
+class AudioBus;
+class ClocklessAudioSinkThread;
+
+// Implementation of an AudioRendererSink that consumes the audio as fast as
+// possible. This class does not support multiple Play()/Pause() events.
+class MEDIA_EXPORT ClocklessAudioSink
+    : NON_EXPORTED_BASE(public AudioRendererSink) {
+ public:
+  ClocklessAudioSink();
+
+  // AudioRendererSink implementation.
+  virtual void Initialize(const AudioParameters& params,
+                          RenderCallback* callback) OVERRIDE;
+  virtual void Start() OVERRIDE;
+  virtual void Stop() OVERRIDE;
+  virtual void Pause() OVERRIDE;
+  virtual void Play() OVERRIDE;
+  virtual bool SetVolume(double volume) OVERRIDE;
+
+  // Returns the time taken to consume all the audio.
+  base::TimeDelta render_time() { return playback_time_; }
+
+ protected:
+  virtual ~ClocklessAudioSink();
+
+ private:
+  scoped_ptr<ClocklessAudioSinkThread> thread_;
+  bool initialized_;
+  bool playing_;
+
+  // Time taken in last set of Render() calls.
+  base::TimeDelta playback_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClocklessAudioSink);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_AUDIO_CLOCKLESS_AUDIO_SINK_H_
diff --git a/media/audio/test_audio_input_controller_factory.cc b/media/audio/test_audio_input_controller_factory.cc
index 64bfb9f..d146231 100644
--- a/media/audio/test_audio_input_controller_factory.cc
+++ b/media/audio/test_audio_input_controller_factory.cc
@@ -12,8 +12,9 @@
     AudioManager* audio_manager,
     const AudioParameters& audio_parameters,
     EventHandler* event_handler,
-    SyncWriter* sync_writer)
-    : AudioInputController(event_handler, sync_writer),
+    SyncWriter* sync_writer,
+    UserInputMonitor* user_input_monitor)
+    : AudioInputController(event_handler, sync_writer, user_input_monitor),
       audio_parameters_(audio_parameters),
       factory_(factory),
       event_handler_(event_handler) {
@@ -48,10 +49,11 @@
 AudioInputController* TestAudioInputControllerFactory::Create(
     AudioManager* audio_manager,
     AudioInputController::EventHandler* event_handler,
-    AudioParameters params) {
+    AudioParameters params,
+    UserInputMonitor* user_input_monitor) {
   DCHECK(!controller_);  // Only one test instance managed at a time.
-  controller_ = new TestAudioInputController(this, audio_manager, params,
-      event_handler, NULL);
+  controller_ = new TestAudioInputController(
+      this, audio_manager, params, event_handler, NULL, user_input_monitor);
   return controller_;
 }
 
diff --git a/media/audio/test_audio_input_controller_factory.h b/media/audio/test_audio_input_controller_factory.h
index 0a17947..4968c01 100644
--- a/media/audio/test_audio_input_controller_factory.h
+++ b/media/audio/test_audio_input_controller_factory.h
@@ -10,6 +10,7 @@
 
 namespace media {
 
+class UserInputMonitor;
 class TestAudioInputControllerFactory;
 
 // TestAudioInputController and TestAudioInputControllerFactory are used for
@@ -56,7 +57,8 @@
                            AudioManager* audio_manager,
                            const AudioParameters& audio_parameters,
                            EventHandler* event_handler,
-                           SyncWriter* sync_writer);
+                           SyncWriter* sync_writer,
+                           UserInputMonitor* user_input_monitor);
 
   // Returns the event handler installed on the AudioInputController.
   EventHandler* event_handler() const { return event_handler_; }
@@ -94,7 +96,8 @@
   virtual AudioInputController* Create(
       AudioManager* audio_manager,
       AudioInputController::EventHandler* event_handler,
-      AudioParameters params) OVERRIDE;
+      AudioParameters params,
+      UserInputMonitor* user_input_monitor) OVERRIDE;
 
   void SetDelegateForTests(TestAudioInputControllerDelegate* delegate);
 
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index 82dd4d4..a753e55 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -389,7 +389,8 @@
   }
 
   if (input_params.IsValid()) {
-    if (CoreAudioUtil::IsSupported()) {
+    if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) &&
+        CoreAudioUtil::IsSupported()) {
       // Check if it is possible to open up at the specified input channel
       // layout but avoid checking if the specified layout is the same as the
       // hardware (preferred) layout. We do this extra check to avoid the
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc
index 392184b..73d7b11 100644
--- a/media/audio/win/core_audio_util_win.cc
+++ b/media/audio/win/core_audio_util_win.cc
@@ -4,8 +4,9 @@
 
 #include "media/audio/win/core_audio_util_win.h"
 
-#include <Audioclient.h>
-#include <Functiondiscoverykeys_devpkey.h>
+#include <audioclient.h>
+#include <devicetopology.h>
+#include <functiondiscoverykeys_devpkey.h>
 
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -317,6 +318,53 @@
   return hr;
 }
 
+std::string CoreAudioUtil::GetAudioControllerID(IMMDevice* device,
+    IMMDeviceEnumerator* enumerator) {
+  DCHECK(IsSupported());
+
+  // Fetching the controller device id could be as simple as fetching the value
+  // of the "{B3F8FA53-0004-438E-9003-51A46E139BFC},2" property in the property
+  // store of the |device|, but that key isn't defined in any header and
+  // according to MS should not be relied upon.
+  // So, instead, we go deeper, look at the device topology and fetch the
+  // PKEY_Device_InstanceId of the associated physical audio device.
+  ScopedComPtr<IDeviceTopology> topology;
+  ScopedComPtr<IConnector> connector;
+  ScopedCoMem<WCHAR> filter_id;
+  if (FAILED(device->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL,
+             topology.ReceiveVoid()) ||
+      // For our purposes checking the first connected device should be enough
+      // and if there are cases where there are more than one device connected
+      // we're not sure how to handle that anyway. So we pass 0.
+      FAILED(topology->GetConnector(0, connector.Receive())) ||
+      FAILED(connector->GetDeviceIdConnectedTo(&filter_id)))) {
+    DLOG(ERROR) << "Failed to get the device identifier of the audio device";
+    return std::string();
+  }
+
+  // Now look at the properties of the connected device node and fetch the
+  // instance id (PKEY_Device_InstanceId) of the device node that uniquely
+  // identifies the controller.
+  ScopedComPtr<IMMDevice> device_node;
+  ScopedComPtr<IPropertyStore> properties;
+  base::win::ScopedPropVariant instance_id;
+  if (FAILED(enumerator->GetDevice(filter_id, device_node.Receive())) ||
+      FAILED(device_node->OpenPropertyStore(STGM_READ, properties.Receive())) ||
+      FAILED(properties->GetValue(PKEY_Device_InstanceId,
+                                  instance_id.Receive())) ||
+      instance_id.get().vt != VT_LPWSTR) {
+    DLOG(ERROR) << "Failed to get instance id of the audio device node";
+    return std::string();
+  }
+
+  std::string controller_id;
+  WideToUTF8(instance_id.get().pwszVal,
+             wcslen(instance_id.get().pwszVal),
+             &controller_id);
+
+  return controller_id;
+}
+
 std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) {
   DCHECK(IsSupported());
   ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id);
diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h
index 3b27345..154a33a 100644
--- a/media/audio/win/core_audio_util_win.h
+++ b/media/audio/win/core_audio_util_win.h
@@ -68,6 +68,18 @@
   //          "Microphone (Realtek High Definition Audio)".
   static HRESULT GetDeviceName(IMMDevice* device, AudioDeviceName* name);
 
+  // Returns the device ID/path of the controller (a.k.a. physical device that
+  // |device| is connected to.  This ID will be the same for all devices from
+  // the same controller so it is useful for doing things like determining
+  // whether a set of output and input devices belong to the same controller.
+  // The device enumerator is required as well as the device itself since
+  // looking at the device topology is required and we need to open up
+  // associated devices to determine the controller id.
+  // If the ID could not be determined for some reason, an empty string is
+  // returned.
+  static std::string GetAudioControllerID(IMMDevice* device,
+      IMMDeviceEnumerator* enumerator);
+
   // Gets the user-friendly name of the endpoint device which is represented
   // by a unique id in |device_id|.
   static std::string GetFriendlyName(const std::string& device_id);
diff --git a/media/audio/win/core_audio_util_win_unittest.cc b/media/audio/win/core_audio_util_win_unittest.cc
index 6d3e1fc..f18c611 100644
--- a/media/audio/win/core_audio_util_win_unittest.cc
+++ b/media/audio/win/core_audio_util_win_unittest.cc
@@ -140,6 +140,33 @@
   }
 }
 
+TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) {
+  if (!CanRunAudioTest())
+    return;
+
+  ScopedComPtr<IMMDeviceEnumerator> enumerator(
+      CoreAudioUtil::CreateDeviceEnumerator());
+  ASSERT_TRUE(enumerator);
+
+  // Enumerate all active input and output devices and fetch the ID of
+  // the associated device.
+  EDataFlow flows[] = { eRender , eCapture };
+  for (int i = 0; i < arraysize(flows); ++i) {
+    ScopedComPtr<IMMDeviceCollection> collection;
+    ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(flows[i],
+        DEVICE_STATE_ACTIVE, collection.Receive())));
+    UINT count = 0;
+    collection->GetCount(&count);
+    for (UINT j = 0; j < count; ++j) {
+      ScopedComPtr<IMMDevice> device;
+      collection->Item(j, device.Receive());
+      std::string controller_id(CoreAudioUtil::GetAudioControllerID(
+          device, enumerator));
+      EXPECT_FALSE(controller_id.empty());
+    }
+  }
+}
+
 TEST_F(CoreAudioUtilWinTest, GetFriendlyName) {
   if (!CanRunAudioTest())
     return;
diff --git a/media/base/android/audio_decoder_job.cc b/media/base/android/audio_decoder_job.cc
new file mode 100644
index 0000000..5c6842a
--- /dev/null
+++ b/media/base/android/audio_decoder_job.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 "media/base/android/audio_decoder_job.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/threading/thread.h"
+#include "media/base/android/media_codec_bridge.h"
+
+namespace media {
+
+class AudioDecoderThread : public base::Thread {
+ public:
+  AudioDecoderThread() : base::Thread("MediaSource_AudioDecoderThread") {
+    Start();
+  }
+};
+
+// TODO(qinmin): Check if it is tolerable to use worker pool to handle all the
+// decoding tasks so that we don't need a global thread here.
+// http://crbug.com/245750
+base::LazyInstance<AudioDecoderThread>::Leaky
+    g_audio_decoder_thread = LAZY_INSTANCE_INITIALIZER;
+
+AudioDecoderJob* AudioDecoderJob::Create(
+    const AudioCodec audio_codec,
+    int sample_rate,
+    int channel_count,
+    const uint8* extra_data,
+    size_t extra_data_size,
+    jobject media_crypto) {
+  scoped_ptr<AudioCodecBridge> codec(AudioCodecBridge::Create(audio_codec));
+  if (codec && codec->Start(audio_codec, sample_rate, channel_count, extra_data,
+                            extra_data_size, true, media_crypto)) {
+    return new AudioDecoderJob(codec.Pass());
+  }
+  return NULL;
+}
+
+AudioDecoderJob::AudioDecoderJob(
+    scoped_ptr<AudioCodecBridge> audio_codec_bridge)
+    : MediaDecoderJob(g_audio_decoder_thread.Pointer()->message_loop_proxy(),
+                      audio_codec_bridge.get()),
+      audio_codec_bridge_(audio_codec_bridge.Pass()) {
+}
+
+AudioDecoderJob::~AudioDecoderJob() {
+}
+
+void AudioDecoderJob::SetVolume(double volume) {
+  audio_codec_bridge_->SetVolume(volume);
+}
+
+void AudioDecoderJob::ReleaseOutputBuffer(
+    int outputBufferIndex, size_t size,
+    const base::TimeDelta& presentation_timestamp,
+    const MediaDecoderJob::DecoderCallback& callback,
+    DecodeStatus status) {
+  audio_codec_bridge_->PlayOutputBuffer(outputBufferIndex, size);
+
+  if (status != DECODE_OUTPUT_END_OF_STREAM || size != 0u)
+    audio_codec_bridge_->ReleaseOutputBuffer(outputBufferIndex, false);
+
+  callback.Run(status, presentation_timestamp, size);
+}
+
+bool AudioDecoderJob::ComputeTimeToRender() const {
+  return false;
+}
+
+}  // namespace media
diff --git a/media/base/android/audio_decoder_job.h b/media/base/android/audio_decoder_job.h
new file mode 100644
index 0000000..171dc4e
--- /dev/null
+++ b/media/base/android/audio_decoder_job.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 MEDIA_BASE_ANDROID_AUDIO_DECODER_JOB_H_
+#define MEDIA_BASE_ANDROID_AUDIO_DECODER_JOB_H_
+
+#include <jni.h>
+
+#include "media/base/android/media_decoder_job.h"
+
+namespace media {
+
+class AudioCodecBridge;
+
+// Class for managing audio decoding jobs.
+class AudioDecoderJob : public MediaDecoderJob {
+ public:
+  virtual ~AudioDecoderJob();
+
+  // Creates a new AudioDecoderJob instance for decoding audio.
+  // |audio_codec| - The audio format the object needs to decode.
+  // |sample_rate| - The sample rate of the decoded output.
+  // |channel_count| - The number of channels in the decoded output.
+  // |extra_data|, |extra_data_size| - Extra data buffer needed for initializing
+  // the decoder.
+  // |media_crypto| - Handle to a Java object that handles the encryption for
+  // the audio data.
+  static AudioDecoderJob* Create(
+      const AudioCodec audio_codec, int sample_rate, int channel_count,
+      const uint8* extra_data, size_t extra_data_size, jobject media_crypto);
+
+  void SetVolume(double volume);
+
+ private:
+  AudioDecoderJob(scoped_ptr<AudioCodecBridge> audio_decoder_bridge);
+
+  // MediaDecoderJob implementation.
+  virtual void ReleaseOutputBuffer(
+      int outputBufferIndex, size_t size,
+      const base::TimeDelta& presentation_timestamp,
+      const MediaDecoderJob::DecoderCallback& callback,
+      DecodeStatus status) OVERRIDE;
+
+  virtual bool ComputeTimeToRender() const OVERRIDE;
+
+  scoped_ptr<AudioCodecBridge> audio_codec_bridge_;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_ANDROID_AUDIO_DECODER_JOB_H_
diff --git a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
index a7afdae..3bb7f9e 100644
--- a/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
+++ b/media/base/android/java/src/org/chromium/media/AudioManagerAndroid.java
@@ -41,9 +41,6 @@
     public void setMode(int mode) {
         try {
             mAudioManager.setMode(mode);
-            if (mode == AudioManager.MODE_IN_COMMUNICATION) {
-                mAudioManager.setSpeakerphoneOn(true);
-            }
         } catch (SecurityException e) {
             Log.e(TAG, "setMode exception: " + e.getMessage());
             logDeviceInfo();
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 ed5d947..b1580d1 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -13,6 +13,7 @@
 import android.view.Surface;
 import android.util.Log;
 
+import java.io.IOException;
 import java.nio.ByteBuffer;
 
 import org.chromium.base.CalledByNative;
@@ -79,7 +80,7 @@
         private int numBytes() { return mNumBytes; }
     }
 
-    private MediaCodecBridge(String mime) {
+    private MediaCodecBridge(String mime) throws IOException {
         mMediaCodec = MediaCodec.createDecoderByType(mime);
         mLastPresentationTimeUs = 0;
         mFlushed = true;
@@ -87,7 +88,14 @@
 
     @CalledByNative
     private static MediaCodecBridge create(String mime) {
-        return new MediaCodecBridge(mime);
+        MediaCodecBridge mediaCodecBridge = null;
+        try {
+            mediaCodecBridge = new MediaCodecBridge(mime);
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to create MediaCodecBridge " + e.toString());
+        }
+
+        return mediaCodecBridge;
     }
 
     @CalledByNative
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
new file mode 100644
index 0000000..5f824fc
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -0,0 +1,338 @@
+// Copyright 2013 The Chromium 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.media;
+
+import android.media.MediaCrypto;
+import android.media.MediaDrm;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.util.Log;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.UUID;
+
+/**
+ * A wrapper of the android MediaDrm class. Each MediaDrmBridge manages multiple
+ * sessions for a single MediaSourcePlayer.
+ */
+@JNINamespace("media")
+class MediaDrmBridge {
+
+    private static final String TAG = "MediaDrmBridge";
+    private MediaDrm mMediaDrm;
+    private UUID mSchemeUUID;
+    private int mNativeMediaDrmBridge;
+    // TODO(qinmin): we currently only support one session per DRM bridge.
+    // Change this to a HashMap if we start to support multiple sessions.
+    private String mSessionId;
+    private MediaCrypto mMediaCrypto;
+    private String mMimeType;
+    private Handler mhandler;
+
+    private static UUID getUUIDFromBytes(byte[] data) {
+        if (data.length != 16) {
+            return null;
+        }
+        long mostSigBits = 0;
+        long leastSigBits = 0;
+        for (int i = 0; i < 8; i++) {
+            mostSigBits = (mostSigBits << 8) | (data[i] & 0xff);
+        }
+        for (int i = 8; i < 16; i++) {
+            leastSigBits = (leastSigBits << 8) | (data[i] & 0xff);
+        }
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    private MediaDrmBridge(UUID schemeUUID, int nativeMediaDrmBridge) {
+        try {
+            mSchemeUUID = schemeUUID;
+            mMediaDrm = new MediaDrm(schemeUUID);
+            mNativeMediaDrmBridge = nativeMediaDrmBridge;
+            mMediaDrm.setOnEventListener(new MediaDrmListener());
+            mSessionId = openSession();
+            mhandler = new Handler();
+        } catch (android.media.UnsupportedSchemeException e) {
+            Log.e(TAG, "Unsupported DRM scheme " + e.toString());
+        }
+    }
+
+    /**
+     * Open a new session and return the sessionId.
+     *
+     * @return ID of the session.
+     */
+    private String openSession() {
+        String session = null;
+        try {
+            final byte[] sessionId = mMediaDrm.openSession();
+            session = new String(sessionId, "UTF-8");
+        } catch (android.media.NotProvisionedException e) {
+            Log.e(TAG, "Cannot open a new session " + e.toString());
+        } catch (java.io.UnsupportedEncodingException e) {
+            Log.e(TAG, "Cannot open a new session " + e.toString());
+        }
+        return session;
+    }
+
+    /**
+     * Create a new MediaDrmBridge from the crypto scheme UUID.
+     *
+     * @param schemeUUID Crypto scheme UUID.
+     * @param nativeMediaDrmBridge Native object of this class.
+     */
+    @CalledByNative
+    private static MediaDrmBridge create(byte[] schemeUUID, int nativeMediaDrmBridge) {
+        UUID cryptoScheme = getUUIDFromBytes(schemeUUID);
+        if (cryptoScheme != null && MediaDrm.isCryptoSchemeSupported(cryptoScheme)) {
+            return new MediaDrmBridge(cryptoScheme, nativeMediaDrmBridge);
+        }
+        return null;
+    }
+
+    /**
+     * Create a new MediaCrypto object from the session Id.
+     *
+     * @param sessionId Crypto session Id.
+     */
+    @CalledByNative
+    private MediaCrypto getMediaCrypto() {
+        if (mMediaCrypto != null) {
+            return mMediaCrypto;
+        }
+        try {
+            final byte[] session = mSessionId.getBytes("UTF-8");
+            if (MediaCrypto.isCryptoSchemeSupported(mSchemeUUID)) {
+                mMediaCrypto = new MediaCrypto(mSchemeUUID, session);
+            }
+        } catch (android.media.MediaCryptoException e) {
+            Log.e(TAG, "Cannot create MediaCrypto " + e.toString());
+        } catch (java.io.UnsupportedEncodingException e) {
+            Log.e(TAG, "Cannot create MediaCrypto " + e.toString());
+        }
+        return mMediaCrypto;
+    }
+
+    /**
+     * Release the MediaDrmBridge object.
+     */
+    @CalledByNative
+    private void release() {
+        if (mMediaCrypto != null) {
+            mMediaCrypto.release();
+        }
+        if (mSessionId != null) {
+            try {
+                final byte[] session = mSessionId.getBytes("UTF-8");
+                mMediaDrm.closeSession(session);
+            } catch (java.io.UnsupportedEncodingException e) {
+                Log.e(TAG, "Failed to close session " + e.toString());
+            }
+        }
+        mMediaDrm.release();
+    }
+
+    /**
+     * Generate a key request and post an asynchronous task to the native side
+     * with the response message.
+     *
+     * @param initData Data needed to generate the key request.
+     * @param mime Mime type.
+     */
+    @CalledByNative
+    private void generateKeyRequest(byte[] initData, String mime) {
+        if (mSessionId == null) {
+            return;
+        }
+        try {
+            final byte[] session = mSessionId.getBytes("UTF-8");
+            mMimeType = mime;
+            HashMap<String, String> optionalParameters = new HashMap<String, String>();
+            final MediaDrm.KeyRequest request = mMediaDrm.getKeyRequest(
+                    session, initData, mime, MediaDrm.KEY_TYPE_STREAMING, optionalParameters);
+            mhandler.post(new Runnable(){
+                public void run() {
+                    nativeOnKeyMessage(mNativeMediaDrmBridge, mSessionId,
+                            request.getData(), request.getDefaultUrl());
+                }
+            });
+            return;
+        } catch (android.media.NotProvisionedException e) {
+            Log.e(TAG, "Cannot get key request " + e.toString());
+        } catch (java.io.UnsupportedEncodingException e) {
+            Log.e(TAG, "Cannot get key request " + e.toString());
+        }
+        onKeyError();
+    }
+
+    /**
+     * Cancel a key request for a session Id.
+     *
+     * @param sessionId Crypto session Id.
+     */
+    @CalledByNative
+    private void cancelKeyRequest(String sessionId) {
+        if (mSessionId == null || !mSessionId.equals(sessionId)) {
+            return;
+        }
+        try {
+            final byte[] session = sessionId.getBytes("UTF-8");
+            mMediaDrm.removeKeys(session);
+        } catch (java.io.UnsupportedEncodingException e) {
+            Log.e(TAG, "Cannot cancel key request " + e.toString());
+        }
+    }
+
+    /**
+     * Add a key for a session Id.
+     *
+     * @param sessionId Crypto session Id.
+     * @param key Response data from the server.
+     */
+    @CalledByNative
+    private void addKey(String sessionId, byte[] key) {
+        if (mSessionId == null || !mSessionId.equals(sessionId)) {
+            return;
+        }
+        try {
+            final byte[] session = sessionId.getBytes("UTF-8");
+            mMediaDrm.provideKeyResponse(session, key);
+            mhandler.post(new Runnable() {
+                public void run() {
+                    nativeOnKeyAdded(mNativeMediaDrmBridge, mSessionId);
+                }
+            });
+            return;
+        } catch (android.media.NotProvisionedException e) {
+            Log.e(TAG, "failed to provide key response " + e.toString());
+        } catch (android.media.DeniedByServerException e) {
+            Log.e(TAG, "failed to provide key response " + e.toString());
+        } catch (java.io.UnsupportedEncodingException e) {
+            Log.e(TAG, "failed to provide key response " + e.toString());
+        }
+        onKeyError();
+    }
+
+    /**
+     * Called when the provision response is received.
+     *
+     * @param response Response data from the provision server.
+     */
+    private void onProvisionResponse(byte[] response) {
+        try {
+            mMediaDrm.provideProvisionResponse(response);
+        } catch (android.media.DeniedByServerException e) {
+            Log.e(TAG, "failed to provide key response " + e.toString());
+        }
+    }
+
+    private void onKeyError() {
+        // TODO(qinmin): pass the error code to native.
+        mhandler.post(new Runnable() {
+            public void run() {
+                nativeOnKeyError(mNativeMediaDrmBridge, mSessionId);
+            }
+        });
+    }
+
+    private class MediaDrmListener implements MediaDrm.OnEventListener {
+        @Override
+        public void onEvent(MediaDrm mediaDrm, byte[] sessionId, int event, int extra,
+                byte[] data) {
+            switch(event) {
+                case MediaDrm.EVENT_PROVISION_REQUIRED:
+                    MediaDrm.ProvisionRequest request = mMediaDrm.getProvisionRequest();
+                    PostRequestTask postTask = new PostRequestTask(request.getData());
+                    postTask.execute(request.getDefaultUrl());
+                    break;
+                case MediaDrm.EVENT_KEY_REQUIRED:
+                    generateKeyRequest(data, mMimeType);
+                    break;
+                case MediaDrm.EVENT_KEY_EXPIRED:
+                    onKeyError();
+                    break;
+                case MediaDrm.EVENT_VENDOR_DEFINED:
+                    assert(false);
+                    break;
+                default:
+                    Log.e(TAG, "Invalid DRM event " + (int)event);
+                    return;
+            }
+        }
+    }
+
+    private class PostRequestTask extends AsyncTask<String, Void, Void> {
+        private static final String TAG = "PostRequestTask";
+
+        private byte[] mDrmRequest;
+        private byte[] mResponseBody;
+
+        public PostRequestTask(byte[] drmRequest) {
+            mDrmRequest = drmRequest;
+        }
+
+        @Override
+        protected Void doInBackground(String... urls) {
+            mResponseBody = postRequest(urls[0], mDrmRequest);
+            if (mResponseBody != null) {
+                Log.d(TAG, "response length=" + mResponseBody.length);
+            }
+            return null;
+        }
+
+        private byte[] postRequest(String url, byte[] drmRequest) {
+            HttpClient httpClient = new DefaultHttpClient();
+            HttpPost httpPost = new HttpPost(url + "&signedRequest=" + new String(drmRequest));
+
+            Log.d(TAG, "PostRequest:" + httpPost.getRequestLine());
+            try {
+                // Add data
+                httpPost.setHeader("Accept", "*/*");
+                httpPost.setHeader("User-Agent", "Widevine CDM v1.0");
+                httpPost.setHeader("Content-Type", "application/json");
+
+                // Execute HTTP Post Request
+                HttpResponse response = httpClient.execute(httpPost);
+
+                byte[] responseBody;
+                int responseCode = response.getStatusLine().getStatusCode();
+                if (responseCode == 200) {
+                    responseBody = EntityUtils.toByteArray(response.getEntity());
+                } else {
+                    Log.d(TAG, "Server returned HTTP error code " + responseCode);
+                    return null;
+                }
+                return responseBody;
+            } catch (ClientProtocolException e) {
+                e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(Void v) {
+            onProvisionResponse(mResponseBody);
+        }
+    }
+
+    private native void nativeOnKeyMessage(int nativeMediaDrmBridge, String sessionId,
+                                           byte[] message, String destinationUrl);
+
+    private native void nativeOnKeyAdded(int nativeMediaDrmBridge, String sessionId);
+
+    private native void nativeOnKeyError(int nativeMediaDrmBridge, String sessionId);
+}
diff --git a/media/base/android/java/src/org/chromium/media/VideoCapture.java b/media/base/android/java/src/org/chromium/media/VideoCapture.java
index f055f35..5099c0a 100644
--- a/media/base/android/java/src/org/chromium/media/VideoCapture.java
+++ b/media/base/android/java/src/org/chromium/media/VideoCapture.java
@@ -100,6 +100,12 @@
               ", height=" + height + ", frameRate=" + frameRate);
         try {
             mCamera = Camera.open(mId);
+        } catch (RuntimeException ex) {
+            Log.e(TAG, "allocate:Camera.open: " + ex);
+            return false;
+        }
+
+        try {
             Camera.CameraInfo camera_info = new Camera.CameraInfo();
             Camera.getCameraInfo(mId, camera_info);
             mCameraOrientation = camera_info.orientation;
diff --git a/media/base/android/media_codec_bridge.cc b/media/base/android/media_codec_bridge.cc
index ab54936..bb5ddcc 100644
--- a/media/base/android/media_codec_bridge.cc
+++ b/media/base/android/media_codec_bridge.cc
@@ -85,7 +85,8 @@
 MediaCodecBridge::~MediaCodecBridge() {
   JNIEnv* env = AttachCurrentThread();
   CHECK(env);
-  Java_MediaCodecBridge_release(env, j_media_codec_.obj());
+  if (j_media_codec_.obj())
+    Java_MediaCodecBridge_release(env, j_media_codec_.obj());
 }
 
 void MediaCodecBridge::StartInternal() {
@@ -237,6 +238,9 @@
   JNIEnv* env = AttachCurrentThread();
   DCHECK(AudioCodecToMimeType(codec));
 
+  if (!media_codec())
+    return false;
+
   ScopedJavaLocalRef<jstring> j_mime =
       ConvertUTF8ToJavaString(env, AudioCodecToMimeType(codec));
   ScopedJavaLocalRef<jobject> j_format(
@@ -388,6 +392,9 @@
   JNIEnv* env = AttachCurrentThread();
   DCHECK(VideoCodecToMimeType(codec));
 
+  if (!media_codec())
+    return false;
+
   ScopedJavaLocalRef<jstring> j_mime =
       ConvertUTF8ToJavaString(env, VideoCodecToMimeType(codec));
   ScopedJavaLocalRef<jobject> j_format(
@@ -417,4 +424,3 @@
 }
 
 }  // namespace media
-
diff --git a/media/base/android/media_decoder_job.cc b/media/base/android/media_decoder_job.cc
new file mode 100644
index 0000000..c29eaf9
--- /dev/null
+++ b/media/base/android/media_decoder_job.cc
@@ -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.
+
+#include "media/base/android/media_decoder_job.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "media/base/android/media_codec_bridge.h"
+#include "media/base/bind_to_loop.h"
+
+namespace media {
+
+// Timeout value for media codec operations. Because the first
+// DequeInputBuffer() can take about 150 milliseconds, use 250 milliseconds
+// here. See http://b/9357571.
+static const int kMediaCodecTimeoutInMilliseconds = 250;
+
+MediaDecoderJob::MediaDecoderJob(
+    const scoped_refptr<base::MessageLoopProxy>& decoder_loop,
+    MediaCodecBridge* media_codec_bridge)
+    : ui_loop_(base::MessageLoopProxy::current()),
+      decoder_loop_(decoder_loop),
+      media_codec_bridge_(media_codec_bridge),
+      needs_flush_(false),
+      input_eos_encountered_(false),
+      weak_this_(this),
+      is_decoding_(false) {
+}
+
+MediaDecoderJob::~MediaDecoderJob() {}
+
+void MediaDecoderJob::Decode(
+    const AccessUnit& unit,
+    const base::TimeTicks& start_time_ticks,
+    const base::TimeDelta& start_presentation_timestamp,
+    const MediaDecoderJob::DecoderCallback& callback) {
+  DCHECK(!is_decoding_);
+  DCHECK(ui_loop_->BelongsToCurrentThread());
+  is_decoding_ = true;
+  decoder_loop_->PostTask(FROM_HERE, base::Bind(
+      &MediaDecoderJob::DecodeInternal, base::Unretained(this), unit,
+      start_time_ticks, start_presentation_timestamp, needs_flush_,
+      media::BindToLoop(ui_loop_, callback)));
+  needs_flush_ = false;
+}
+
+MediaDecoderJob::DecodeStatus MediaDecoderJob::QueueInputBuffer(
+    const AccessUnit& unit) {
+  base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
+      kMediaCodecTimeoutInMilliseconds);
+  int input_buf_index = media_codec_bridge_->DequeueInputBuffer(timeout);
+  if (input_buf_index == MediaCodecBridge::INFO_MEDIA_CODEC_ERROR)
+    return DECODE_FAILED;
+  if (input_buf_index == MediaCodecBridge::INFO_TRY_AGAIN_LATER)
+    return DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER;
+
+  // TODO(qinmin): skip frames if video is falling far behind.
+  DCHECK(input_buf_index >= 0);
+  if (unit.end_of_stream || unit.data.empty()) {
+    media_codec_bridge_->QueueEOS(input_buf_index);
+    return DECODE_INPUT_END_OF_STREAM;
+  }
+  if (unit.key_id.empty()) {
+    media_codec_bridge_->QueueInputBuffer(
+        input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
+  } else {
+    if (unit.iv.empty() || unit.subsamples.empty()) {
+      LOG(ERROR) << "The access unit doesn't have iv or subsamples while it "
+                 << "has key IDs!";
+      return DECODE_FAILED;
+    }
+    media_codec_bridge_->QueueSecureInputBuffer(
+        input_buf_index, &unit.data[0], unit.data.size(),
+        reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
+        reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
+        &unit.subsamples[0], unit.subsamples.size(), unit.timestamp);
+  }
+
+  return DECODE_SUCCEEDED;
+}
+
+void MediaDecoderJob::DecodeInternal(
+    const AccessUnit& unit,
+    const base::TimeTicks& start_time_ticks,
+    const base::TimeDelta& start_presentation_timestamp,
+    bool needs_flush,
+    const MediaDecoderJob::DecoderCallback& callback) {
+  if (needs_flush) {
+    DVLOG(1) << "DecodeInternal needs flush.";
+    input_eos_encountered_ = false;
+    media_codec_bridge_->Reset();
+  }
+
+  DecodeStatus decode_status = DECODE_INPUT_END_OF_STREAM;
+  if (!input_eos_encountered_) {
+    decode_status = QueueInputBuffer(unit);
+    if (decode_status == DECODE_INPUT_END_OF_STREAM) {
+      input_eos_encountered_ = true;
+    } else if (decode_status != DECODE_SUCCEEDED) {
+      callback.Run(decode_status, start_presentation_timestamp, 0);
+      return;
+    }
+  }
+
+  size_t offset = 0;
+  size_t size = 0;
+  base::TimeDelta presentation_timestamp;
+  bool end_of_stream = false;
+
+  base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
+      kMediaCodecTimeoutInMilliseconds);
+  int output_buffer_index = media_codec_bridge_->DequeueOutputBuffer(
+      timeout, &offset, &size, &presentation_timestamp, &end_of_stream);
+
+  if (end_of_stream)
+    decode_status = DECODE_OUTPUT_END_OF_STREAM;
+
+  if (output_buffer_index < 0) {
+    MediaCodecBridge::DequeueBufferInfo buffer_info =
+        static_cast<MediaCodecBridge::DequeueBufferInfo>(output_buffer_index);
+    switch (buffer_info) {
+      case MediaCodecBridge::INFO_OUTPUT_BUFFERS_CHANGED:
+        DCHECK_NE(decode_status, DECODE_INPUT_END_OF_STREAM);
+        media_codec_bridge_->GetOutputBuffers();
+        break;
+      case MediaCodecBridge::INFO_OUTPUT_FORMAT_CHANGED:
+        DCHECK_NE(decode_status, DECODE_INPUT_END_OF_STREAM);
+        // TODO(qinmin): figure out what we should do if format changes.
+        decode_status = DECODE_FORMAT_CHANGED;
+        break;
+      case MediaCodecBridge::INFO_TRY_AGAIN_LATER:
+        decode_status = DECODE_TRY_DEQUEUE_OUTPUT_AGAIN_LATER;
+        break;
+      case MediaCodecBridge::INFO_MEDIA_CODEC_ERROR:
+        decode_status = DECODE_FAILED;
+        break;
+    }
+  } else {
+      base::TimeDelta time_to_render;
+      DCHECK(!start_time_ticks.is_null());
+      if (ComputeTimeToRender()) {
+        time_to_render = presentation_timestamp - (base::TimeTicks::Now() -
+            start_time_ticks + start_presentation_timestamp);
+      }
+
+      // TODO(acolwell): Change to > since the else will never run for audio.
+      if (time_to_render >= base::TimeDelta()) {
+        base::MessageLoop::current()->PostDelayedTask(
+            FROM_HERE,
+            base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
+                       weak_this_.GetWeakPtr(), output_buffer_index, size,
+                       presentation_timestamp, callback, decode_status),
+            time_to_render);
+      } else {
+        // TODO(qinmin): The codec is lagging behind, need to recalculate the
+        // |start_presentation_timestamp_| and |start_time_ticks_|.
+        DVLOG(1) << "codec is lagging behind :"
+                 << time_to_render.InMicroseconds();
+        ReleaseOutputBuffer(output_buffer_index, size, presentation_timestamp,
+                            callback, decode_status);
+      }
+
+      return;
+  }
+  callback.Run(decode_status, start_presentation_timestamp, 0);
+}
+
+void MediaDecoderJob::OnDecodeCompleted() {
+  DCHECK(ui_loop_->BelongsToCurrentThread());
+  is_decoding_ = false;
+}
+
+void MediaDecoderJob::Flush() {
+  // Do nothing, flush when the next Decode() happens.
+  needs_flush_ = true;
+}
+
+void MediaDecoderJob::Release() {
+  // If |decoding_| is false, there is nothing running on the decoder thread.
+  // So it is safe to delete the MediaDecoderJob on the UI thread. However,
+  // if we post a task to the decoder thread to delete object, then we cannot
+  // immediately pass the surface to a new MediaDecoderJob instance because
+  // the java surface is still owned by the old object. New decoder creation
+  // will be blocked on the UI thread until the previous decoder gets deleted.
+  // This introduces extra latency during config changes, and makes the logic in
+  // MediaSourcePlayer more complicated.
+  //
+  // TODO(qinmin): Figure out the logic to passing the surface to a new
+  // MediaDecoderJob instance after the previous one gets deleted on the decoder
+  // thread.
+  if (is_decoding_ && !decoder_loop_->BelongsToCurrentThread()) {
+    DCHECK(ui_loop_->BelongsToCurrentThread());
+    decoder_loop_->DeleteSoon(FROM_HERE, this);
+    return;
+  }
+
+  delete this;
+}
+
+}  // namespace media
diff --git a/media/base/android/media_decoder_job.h b/media/base/android/media_decoder_job.h
new file mode 100644
index 0000000..4a3bd87
--- /dev/null
+++ b/media/base/android/media_decoder_job.h
@@ -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.
+
+#ifndef MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_
+#define MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "media/base/android/demuxer_stream_player_params.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace media {
+
+class MediaCodecBridge;
+
+// Class for managing all the decoding tasks. Each decoding task will be posted
+// onto the same thread. The thread will be stopped once Stop() is called.
+class MediaDecoderJob {
+ public:
+  enum DecodeStatus {
+    DECODE_SUCCEEDED,
+    DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER,
+    DECODE_TRY_DEQUEUE_OUTPUT_AGAIN_LATER,
+    DECODE_FORMAT_CHANGED,
+    DECODE_INPUT_END_OF_STREAM,
+    DECODE_OUTPUT_END_OF_STREAM,
+    DECODE_FAILED,
+  };
+
+  struct Deleter {
+    inline void operator()(MediaDecoderJob* ptr) const { ptr->Release(); }
+  };
+
+  virtual ~MediaDecoderJob();
+
+  // Callback when a decoder job finishes its work. Args: whether decode
+  // finished successfully, presentation time, audio output bytes.
+  typedef base::Callback<void(DecodeStatus, const base::TimeDelta&,
+                              size_t)> DecoderCallback;
+
+  // Called by MediaSourcePlayer to decode some data.
+  void Decode(const AccessUnit& unit,
+              const base::TimeTicks& start_time_ticks,
+              const base::TimeDelta& start_presentation_timestamp,
+              const MediaDecoderJob::DecoderCallback& callback);
+
+  // Flush the decoder.
+  void Flush();
+
+  // Called on the UI thread to indicate that one decode cycle has completed.
+  void OnDecodeCompleted();
+
+  bool is_decoding() const { return is_decoding_; }
+
+ protected:
+  MediaDecoderJob(const scoped_refptr<base::MessageLoopProxy>& decoder_loop,
+                  MediaCodecBridge* media_codec_bridge);
+
+  // Release the output buffer and render it.
+  virtual void ReleaseOutputBuffer(
+      int outputBufferIndex, size_t size,
+      const base::TimeDelta& presentation_timestamp,
+      const MediaDecoderJob::DecoderCallback& callback,
+      DecodeStatus status) = 0;
+
+  // Returns true if the "time to render" needs to be computed for frames in
+  // this decoder job.
+  virtual bool ComputeTimeToRender() const = 0;
+
+ private:
+  // Causes this instance to be deleted on the thread it is bound to.
+  void Release();
+
+  DecodeStatus QueueInputBuffer(const AccessUnit& unit);
+
+  // Helper function to decoder data on |thread_|. |unit| contains all the data
+  // to be decoded. |start_time_ticks| and |start_presentation_timestamp|
+  // represent the system time and the presentation timestamp when the first
+  // frame is rendered. We use these information to estimate when the current
+  // frame should be rendered. If |needs_flush| is true, codec needs to be
+  // flushed at the beginning of this call.
+  void DecodeInternal(const AccessUnit& unit,
+                      const base::TimeTicks& start_time_ticks,
+                      const base::TimeDelta& start_presentation_timestamp,
+                      bool needs_flush,
+                      const MediaDecoderJob::DecoderCallback& callback);
+
+  // The UI message loop where callbacks should be dispatched.
+  scoped_refptr<base::MessageLoopProxy> ui_loop_;
+
+  // The message loop that decoder job runs on.
+  scoped_refptr<base::MessageLoopProxy> decoder_loop_;
+
+  // The media codec bridge used for decoding. Owned by derived class.
+  // NOTE: This MUST NOT be accessed in the destructor.
+  MediaCodecBridge* media_codec_bridge_;
+
+  // Whether the decoder needs to be flushed.
+  bool needs_flush_;
+
+  // Whether input EOS is encountered.
+  bool input_eos_encountered_;
+
+  // Weak pointer passed to media decoder jobs for callbacks. It is bounded to
+  // the decoder thread.
+  base::WeakPtrFactory<MediaDecoderJob> weak_this_;
+
+  // Whether the decoder is actively decoding data.
+  bool is_decoding_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MediaDecoderJob);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_ANDROID_MEDIA_DECODER_JOB_H_
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index ee4fbbd..9ac62ca 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -4,11 +4,15 @@
 
 #include "media/base/android/media_drm_bridge.h"
 
+#include "base/android/build_info.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/logging.h"
+#include "jni/MediaDrmBridge_jni.h"
 #include "media/base/android/media_player_manager.h"
 
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::JavaByteArrayToByteVector;
 using base::android::ScopedJavaLocalRef;
@@ -135,53 +139,83 @@
 }
 
 // static
-bool MediaDrmBridge::IsAvailable() {
-  return false;
-}
-
 MediaDrmBridge* MediaDrmBridge::Create(int media_keys_id,
-                                       const std::vector<uint8>& uuid,
+                                       const std::vector<uint8>& scheme_uuid,
                                        MediaPlayerManager* manager) {
-  if (!IsAvailable())
+  if (!IsAvailable() || scheme_uuid.empty())
     return NULL;
 
   // TODO(qinmin): check whether the uuid is valid.
-  return new MediaDrmBridge(media_keys_id, uuid, manager);
+  return new MediaDrmBridge(media_keys_id, scheme_uuid, manager);
+}
+
+bool MediaDrmBridge::IsAvailable() {
+  return base::android::BuildInfo::GetInstance()->sdk_int() >= 18;
+}
+
+bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) {
+  return RegisterNativesImpl(env);
 }
 
 MediaDrmBridge::MediaDrmBridge(int media_keys_id,
-                               const std::vector<uint8>& uuid,
+                               const std::vector<uint8>& scheme_uuid,
                                MediaPlayerManager* manager)
-    : media_keys_id_(media_keys_id), uuid_(uuid), manager_(manager) {
-  // TODO(qinmin): pass the uuid to DRM engine.
+    : media_keys_id_(media_keys_id),
+      scheme_uuid_(scheme_uuid),
+      manager_(manager) {
+  JNIEnv* env = AttachCurrentThread();
+  CHECK(env);
+
+  ScopedJavaLocalRef<jbyteArray> j_scheme_uuid =
+      base::android::ToJavaByteArray(env, &scheme_uuid[0], scheme_uuid.size());
+  j_media_drm_.Reset(Java_MediaDrmBridge_create(
+      env, j_scheme_uuid.obj(), reinterpret_cast<intptr_t>(this)));
 }
 
-MediaDrmBridge::~MediaDrmBridge() {}
+MediaDrmBridge::~MediaDrmBridge() {
+  JNIEnv* env = AttachCurrentThread();
+  Java_MediaDrmBridge_release(env, j_media_drm_.obj());
+}
 
 bool MediaDrmBridge::GenerateKeyRequest(const std::string& type,
                                         const uint8* init_data,
                                         int init_data_length) {
   std::vector<uint8> pssh_data;
-  if (!GetPsshData(init_data, init_data_length, uuid_, &pssh_data))
+  if (!GetPsshData(init_data, init_data_length, scheme_uuid_, &pssh_data))
     return false;
 
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void MediaDrmBridge::CancelKeyRequest(const std::string& session_id) {
-  NOTIMPLEMENTED();
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> j_pssh_data =
+      base::android::ToJavaByteArray(env, &pssh_data[0], pssh_data.size());
+  ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, type);
+  Java_MediaDrmBridge_generateKeyRequest(
+      env, j_media_drm_.obj(), j_pssh_data.obj(), j_mime.obj());
+  return true;
 }
 
 void MediaDrmBridge::AddKey(const uint8* key, int key_length,
                             const uint8* init_data, int init_data_length,
                             const std::string& session_id) {
-  NOTIMPLEMENTED();
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> j_key_data =
+      base::android::ToJavaByteArray(env, key, key_length);
+  ScopedJavaLocalRef<jstring> j_session_id =
+      ConvertUTF8ToJavaString(env, session_id);
+  Java_MediaDrmBridge_addKey(
+      env, j_media_drm_.obj(), j_session_id.obj(), j_key_data.obj());
 }
 
 ScopedJavaLocalRef<jobject> MediaDrmBridge::GetMediaCrypto() {
-  NOTIMPLEMENTED();
-  return ScopedJavaLocalRef<jobject>();
+  JNIEnv* env = AttachCurrentThread();
+  return Java_MediaDrmBridge_getMediaCrypto(env, j_media_drm_.obj());
+}
+
+void MediaDrmBridge::CancelKeyRequest(const std::string& session_id) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_session_id =
+      ConvertUTF8ToJavaString(env, session_id);
+  Java_MediaDrmBridge_cancelKeyRequest(
+      env, j_media_drm_.obj(), j_session_id.obj());
 }
 
 void MediaDrmBridge::OnKeyMessage(JNIEnv* env,
@@ -197,13 +231,14 @@
   manager_->OnKeyMessage(media_keys_id_, session_id, message, destination_url);
 }
 
-void MediaDrmBridge::OnDrmEvent(JNIEnv* env,
-                                jobject j_media_drm,
-                                jstring session_id,
-                                jint event,
-                                jint extra,
-                                jstring data) {
-  NOTIMPLEMENTED();
+void MediaDrmBridge::OnKeyAdded(JNIEnv* env, jobject, jstring j_session_id) {
+  std::string session_id = ConvertJavaStringToUTF8(env, j_session_id);
+  manager_->OnKeyAdded(media_keys_id_, session_id);
+}
+
+void MediaDrmBridge::OnKeyError(JNIEnv* env, jobject, jstring j_session_id) {
+  std::string session_id = ConvertJavaStringToUTF8(env, j_session_id);
+  manager_->OnKeyError(media_keys_id_, session_id, MediaKeys::kUnknownError, 0);
 }
 
 }  // namespace media
diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h
index 42b6790..26e6437 100644
--- a/media/base/android/media_drm_bridge.h
+++ b/media/base/android/media_drm_bridge.h
@@ -23,15 +23,17 @@
  public:
   virtual ~MediaDrmBridge();
 
-  // Returns a MediaDrmBridge instance if |uuid| is supported, or a NULL
+  // Returns a MediaDrmBridge instance if |scheme_uuid| is supported, or a NULL
   // pointer otherwise.
   static MediaDrmBridge* Create(int media_keys_id,
-                                const std::vector<uint8>& uuid,
+                                const std::vector<uint8>& scheme_uuid,
                                 MediaPlayerManager* manager);
 
-  // Checks whether DRM is available.
+  // Checks whether MediaDRM is available.
   static bool IsAvailable();
 
+  static bool RegisterMediaDrmBridge(JNIEnv* env);
+
   // MediaKeys implementations.
   virtual bool GenerateKeyRequest(const std::string& type,
                                   const uint8* init_data,
@@ -41,14 +43,16 @@
                       const std::string& session_id) OVERRIDE;
   virtual void CancelKeyRequest(const std::string& session_id) OVERRIDE;
 
-  // Drm related message was received.
-  void OnDrmEvent(JNIEnv* env, jobject, jstring session_id,
-                  jint event, jint extra, jstring data);
-
   // Called after we got the response for GenerateKeyRequest().
-  void OnKeyMessage(JNIEnv* env, jobject, jstring session_id,
+  void OnKeyMessage(JNIEnv* env, jobject, jstring j_session_id,
                     jbyteArray message, jstring destination_url);
 
+  // Called when key is added.
+  void OnKeyAdded(JNIEnv* env, jobject, jstring j_session_id);
+
+  // Called when error happens.
+  void OnKeyError(JNIEnv* env, jobject, jstring j_session_id);
+
   // Methods to create and release a MediaCrypto object.
   base::android::ScopedJavaLocalRef<jobject> GetMediaCrypto();
 
@@ -56,14 +60,17 @@
 
  private:
   MediaDrmBridge(int media_keys_id,
-                 const std::vector<uint8>& uuid,
+                 const std::vector<uint8>& scheme_uuid,
                  MediaPlayerManager* manager);
 
-  // Id of the MediaKeys object.
+  // ID of the MediaKeys object.
   int media_keys_id_;
 
   // UUID of the key system.
-  std::vector<uint8> uuid_;
+  std::vector<uint8> scheme_uuid_;
+
+  // Java MediaDrm instance.
+  base::android::ScopedJavaGlobalRef<jobject> j_media_drm_;
 
   // Non-owned pointer.
   MediaPlayerManager* manager_;
diff --git a/media/base/android/media_jni_registrar.cc b/media/base/android/media_jni_registrar.cc
index 93a46c3..b7d48ca 100644
--- a/media/base/android/media_jni_registrar.cc
+++ b/media/base/android/media_jni_registrar.cc
@@ -10,6 +10,7 @@
 
 #include "media/audio/android/audio_manager_android.h"
 #include "media/base/android/media_codec_bridge.h"
+#include "media/base/android/media_drm_bridge.h"
 #include "media/base/android/media_player_bridge.h"
 #include "media/base/android/media_player_listener.h"
 #include "media/base/android/webaudio_media_codec_bridge.h"
@@ -22,6 +23,8 @@
     AudioManagerAndroid::RegisterAudioManager },
   { "MediaCodecBridge",
     MediaCodecBridge::RegisterMediaCodecBridge },
+  { "MediaDrmBridge",
+    MediaDrmBridge::RegisterMediaDrmBridge },
   { "MediaPlayerBridge",
     MediaPlayerBridge::RegisterMediaPlayerBridge },
   { "MediaPlayerListener",
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc
index 979d1cc..e0fd9c7 100644
--- a/media/base/android/media_source_player.cc
+++ b/media/base/android/media_source_player.cc
@@ -8,317 +8,22 @@
 #include "base/android/jni_string.h"
 #include "base/basictypes.h"
 #include "base/bind.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread.h"
-#include "media/base/android/media_codec_bridge.h"
+#include "media/base/android/audio_decoder_job.h"
 #include "media/base/android/media_drm_bridge.h"
 #include "media/base/android/media_player_manager.h"
+#include "media/base/android/video_decoder_job.h"
 #include "media/base/audio_timestamp_helper.h"
 
 namespace {
 
-// Timeout value for media codec operations. Because the first
-// DequeInputBuffer() can take about 150 milliseconds, use 250 milliseconds
-// here. See b/9357571.
-const int kMediaCodecTimeoutInMilliseconds = 250;
-
 // Use 16bit PCM for audio output. Keep this value in sync with the output
 // format we passed to AudioTrack in MediaCodecBridge.
 const int kBytesPerAudioOutputSample = 2;
-
-class DecoderThread : public base::Thread {
- public:
-  virtual ~DecoderThread() {}
- protected:
-  DecoderThread(const char* name) : base::Thread(name) { Start(); }
-};
-
-class AudioDecoderThread : public DecoderThread {
- public:
-  AudioDecoderThread() : DecoderThread("MediaSource_AudioDecoderThread") {}
-};
-
-class VideoDecoderThread : public DecoderThread {
- public:
-  VideoDecoderThread() : DecoderThread("MediaSource_VideoDecoderThread") {}
-};
-
-// TODO(qinmin): Check if it is tolerable to use worker pool to handle all the
-// decoding tasks so that we don't need the global threads here.
-// http://crbug.com/245750
-base::LazyInstance<AudioDecoderThread>::Leaky
-    g_audio_decoder_thread = LAZY_INSTANCE_INITIALIZER;
-
-base::LazyInstance<VideoDecoderThread>::Leaky
-    g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER;
-
 }
 
 namespace media {
 
-MediaDecoderJob::MediaDecoderJob(
-    const scoped_refptr<base::MessageLoopProxy>& decoder_loop,
-    MediaCodecBridge* media_codec_bridge,
-    bool is_audio)
-    : ui_loop_(base::MessageLoopProxy::current()),
-      decoder_loop_(decoder_loop),
-      media_codec_bridge_(media_codec_bridge),
-      needs_flush_(false),
-      is_audio_(is_audio),
-      input_eos_encountered_(false),
-      weak_this_(this),
-      is_decoding_(false) {
-}
-
-MediaDecoderJob::~MediaDecoderJob() {}
-
-// Class for managing audio decoding jobs.
-class AudioDecoderJob : public MediaDecoderJob {
- public:
-  virtual ~AudioDecoderJob() {}
-
-  static AudioDecoderJob* Create(
-      const AudioCodec audio_codec, int sample_rate, int channel_count,
-      const uint8* extra_data, size_t extra_data_size, jobject media_crypto);
-
-  void SetVolume(double volume);
-
- private:
-  AudioDecoderJob(MediaCodecBridge* media_codec_bridge);
-};
-
-// Class for managing video decoding jobs.
-class VideoDecoderJob : public MediaDecoderJob {
- public:
-  virtual ~VideoDecoderJob() {}
-
-  static VideoDecoderJob* Create(
-      const VideoCodec video_codec, const gfx::Size& size, jobject surface,
-      jobject media_crypto);
-
- private:
-  VideoDecoderJob(MediaCodecBridge* media_codec_bridge);
-};
-
-void MediaDecoderJob::Decode(
-    const AccessUnit& unit,
-    const base::TimeTicks& start_time_ticks,
-    const base::TimeDelta& start_presentation_timestamp,
-    const MediaDecoderJob::DecoderCallback& callback) {
-  DCHECK(!is_decoding_);
-  DCHECK(ui_loop_->BelongsToCurrentThread());
-  is_decoding_ = true;
-  decoder_loop_->PostTask(FROM_HERE, base::Bind(
-      &MediaDecoderJob::DecodeInternal, base::Unretained(this), unit,
-      start_time_ticks, start_presentation_timestamp, needs_flush_,
-      callback));
-  needs_flush_ = false;
-}
-
-MediaDecoderJob::DecodeStatus MediaDecoderJob::QueueInputBuffer(
-    const AccessUnit& unit) {
-  base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
-      kMediaCodecTimeoutInMilliseconds);
-  int input_buf_index = media_codec_bridge_->DequeueInputBuffer(timeout);
-  if (input_buf_index == MediaCodecBridge::INFO_MEDIA_CODEC_ERROR)
-    return DECODE_FAILED;
-  if (input_buf_index == MediaCodecBridge::INFO_TRY_AGAIN_LATER)
-    return DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER;
-
-  // TODO(qinmin): skip frames if video is falling far behind.
-  DCHECK(input_buf_index >= 0);
-  if (unit.end_of_stream || unit.data.empty()) {
-    media_codec_bridge_->QueueEOS(input_buf_index);
-    return DECODE_INPUT_END_OF_STREAM;
-  }
-  if (unit.key_id.empty()) {
-    media_codec_bridge_->QueueInputBuffer(
-        input_buf_index, &unit.data[0], unit.data.size(), unit.timestamp);
-  } else {
-    if (unit.iv.empty() || unit.subsamples.empty()) {
-      LOG(ERROR) << "The access unit doesn't have iv or subsamples while it "
-                 << "has key IDs!";
-      return DECODE_FAILED;
-    }
-    media_codec_bridge_->QueueSecureInputBuffer(
-        input_buf_index, &unit.data[0], unit.data.size(),
-        reinterpret_cast<const uint8*>(&unit.key_id[0]), unit.key_id.size(),
-        reinterpret_cast<const uint8*>(&unit.iv[0]), unit.iv.size(),
-        &unit.subsamples[0], unit.subsamples.size(), unit.timestamp);
-  }
-
-  return DECODE_SUCCEEDED;
-}
-
-void MediaDecoderJob::DecodeInternal(
-    const AccessUnit& unit,
-    const base::TimeTicks& start_time_ticks,
-    const base::TimeDelta& start_presentation_timestamp,
-    bool needs_flush,
-    const MediaDecoderJob::DecoderCallback& callback) {
-  if (needs_flush) {
-    DVLOG(1) << "DecodeInternal needs flush.";
-    input_eos_encountered_ = false;
-    media_codec_bridge_->Reset();
-  }
-
-  DecodeStatus decode_status = DECODE_INPUT_END_OF_STREAM;
-  if (!input_eos_encountered_) {
-    decode_status = QueueInputBuffer(unit);
-    if (decode_status == DECODE_INPUT_END_OF_STREAM) {
-      input_eos_encountered_ = true;
-    } else if (decode_status != DECODE_SUCCEEDED) {
-      ui_loop_->PostTask(FROM_HERE,
-                         base::Bind(callback, decode_status,
-                                    start_presentation_timestamp, 0));
-      return;
-    }
-  }
-
-  size_t offset = 0;
-  size_t size = 0;
-  base::TimeDelta presentation_timestamp;
-  bool end_of_stream = false;
-
-  base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
-      kMediaCodecTimeoutInMilliseconds);
-  int outputBufferIndex = media_codec_bridge_->DequeueOutputBuffer(
-      timeout, &offset, &size, &presentation_timestamp, &end_of_stream);
-
-  if (end_of_stream)
-    decode_status = DECODE_OUTPUT_END_OF_STREAM;
-  switch (outputBufferIndex) {
-    case MediaCodecBridge::INFO_OUTPUT_BUFFERS_CHANGED:
-      DCHECK(decode_status != DECODE_INPUT_END_OF_STREAM);
-      media_codec_bridge_->GetOutputBuffers();
-      break;
-    case MediaCodecBridge::INFO_OUTPUT_FORMAT_CHANGED:
-      DCHECK(decode_status != DECODE_INPUT_END_OF_STREAM);
-      // TODO(qinmin): figure out what we should do if format changes.
-      decode_status = DECODE_FORMAT_CHANGED;
-      break;
-    case MediaCodecBridge::INFO_TRY_AGAIN_LATER:
-      decode_status = DECODE_TRY_DEQUEUE_OUTPUT_AGAIN_LATER;
-      break;
-    case MediaCodecBridge::INFO_MEDIA_CODEC_ERROR:
-      decode_status = DECODE_FAILED;
-      break;
-    default:
-      DCHECK_LE(0, outputBufferIndex);
-      base::TimeDelta time_to_render;
-      DCHECK(!start_time_ticks.is_null());
-      if (!is_audio_) {
-        time_to_render = presentation_timestamp - (base::TimeTicks::Now() -
-            start_time_ticks + start_presentation_timestamp);
-      }
-      if (time_to_render >= base::TimeDelta()) {
-        base::MessageLoop::current()->PostDelayedTask(
-            FROM_HERE,
-            base::Bind(&MediaDecoderJob::ReleaseOutputBuffer,
-                       weak_this_.GetWeakPtr(), outputBufferIndex, size,
-                       presentation_timestamp, callback, decode_status),
-            time_to_render);
-      } else {
-        // TODO(qinmin): The codec is lagging behind, need to recalculate the
-        // |start_presentation_timestamp_| and |start_time_ticks_|.
-        DVLOG(1) << (is_audio_ ? "audio " : "video ")
-            << "codec is lagging behind :" << time_to_render.InMicroseconds();
-        ReleaseOutputBuffer(outputBufferIndex, size, presentation_timestamp,
-                            callback, decode_status);
-      }
-      return;
-  }
-  ui_loop_->PostTask(FROM_HERE, base::Bind(
-      callback, decode_status, start_presentation_timestamp, 0));
-}
-
-void MediaDecoderJob::ReleaseOutputBuffer(
-    int outputBufferIndex, size_t size,
-    const base::TimeDelta& presentation_timestamp,
-    const MediaDecoderJob::DecoderCallback& callback, DecodeStatus status) {
-  // TODO(qinmin): Refactor this function. Maybe AudioDecoderJob should provide
-  // its own ReleaseOutputBuffer().
-  if (is_audio_) {
-    static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->PlayOutputBuffer(
-        outputBufferIndex, size);
-  }
-  if (status != DECODE_OUTPUT_END_OF_STREAM || size != 0u)
-    media_codec_bridge_->ReleaseOutputBuffer(outputBufferIndex, !is_audio_);
-  ui_loop_->PostTask(FROM_HERE, base::Bind(
-      callback, status, presentation_timestamp, is_audio_ ? size : 0));
-}
-
-void MediaDecoderJob::OnDecodeCompleted() {
-  DCHECK(ui_loop_->BelongsToCurrentThread());
-  is_decoding_ = false;
-}
-
-void MediaDecoderJob::Flush() {
-  // Do nothing, flush when the next Decode() happens.
-  needs_flush_ = true;
-}
-
-void MediaDecoderJob::Release() {
-  // If |decoding_| is false, there is nothing running on the decoder thread.
-  // So it is safe to delete the MediaDecoderJob on the UI thread. However,
-  // if we post a task to the decoder thread to delete object, then we cannot
-  // immediately pass the surface to a new MediaDecoderJob instance because
-  // the java surface is still owned by the old object. New decoder creation
-  // will be blocked on the UI thread until the previous decoder gets deleted.
-  // This introduces extra latency during config changes, and makes the logic in
-  // MediaSourcePlayer more complicated.
-  //
-  // TODO(qinmin): Figure out the logic to passing the surface to a new
-  // MediaDecoderJob instance after the previous one gets deleted on the decoder
-  // thread.
-  if (is_decoding_ && !decoder_loop_->BelongsToCurrentThread()) {
-    DCHECK(ui_loop_->BelongsToCurrentThread());
-    decoder_loop_->DeleteSoon(FROM_HERE, this);
-  } else {
-    delete this;
-  }
-}
-
-VideoDecoderJob* VideoDecoderJob::Create(
-    const VideoCodec video_codec, const gfx::Size& size, jobject surface,
-    jobject media_crypto) {
-  scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec));
-  if (codec && codec->Start(video_codec, size, surface, media_crypto))
-    return new VideoDecoderJob(codec.release());
-  return NULL;
-}
-
-VideoDecoderJob::VideoDecoderJob(MediaCodecBridge* media_codec_bridge)
-    : MediaDecoderJob(g_video_decoder_thread.Pointer()->message_loop_proxy(),
-                      media_codec_bridge,
-                      false) {}
-
-AudioDecoderJob* AudioDecoderJob::Create(
-    const AudioCodec audio_codec,
-    int sample_rate,
-    int channel_count,
-    const uint8* extra_data,
-    size_t extra_data_size,
-    jobject media_crypto) {
-  scoped_ptr<AudioCodecBridge> codec(AudioCodecBridge::Create(audio_codec));
-  if (codec && codec->Start(audio_codec, sample_rate, channel_count, extra_data,
-                            extra_data_size, true, media_crypto)) {
-    return new AudioDecoderJob(codec.release());
-  }
-  return NULL;
-}
-
-AudioDecoderJob::AudioDecoderJob(MediaCodecBridge* media_codec_bridge)
-    : MediaDecoderJob(g_audio_decoder_thread.Pointer()->message_loop_proxy(),
-                      media_codec_bridge,
-                      true) {}
-
-void AudioDecoderJob::SetVolume(double volume) {
-  static_cast<AudioCodecBridge*>(media_codec_bridge_.get())->SetVolume(volume);
-}
-
 MediaSourcePlayer::MediaSourcePlayer(
     int player_id,
     MediaPlayerManager* manager)
@@ -847,11 +552,11 @@
   if (video_decoder_job_ && !reconfig_video_decoder_)
     return;
 
-  base::android::ScopedJavaLocalRef<jobject> media_codec;
+  base::android::ScopedJavaLocalRef<jobject> media_crypto;
   if (is_video_encrypted_) {
     if (drm_bridge_) {
-      media_codec = drm_bridge_->GetMediaCrypto();
-      DCHECK(!media_codec.is_null());
+      media_crypto = drm_bridge_->GetMediaCrypto();
+      DCHECK(!media_crypto.is_null());
     } else {
       LOG(INFO) << "MediaDrmBridge is not available when creating decoder "
                 << "for encrypted video stream.";
@@ -865,7 +570,7 @@
   // Create the new VideoDecoderJob.
   video_decoder_job_.reset(VideoDecoderJob::Create(
       video_codec_, gfx::Size(width_, height_), surface_.j_surface().obj(),
-      media_codec.obj()));
+      media_crypto.obj()));
   if (video_decoder_job_)
     reconfig_video_decoder_ = false;
 
diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h
index 05fd224..c475762 100644
--- a/media/base/android/media_source_player.h
+++ b/media/base/android/media_source_player.h
@@ -18,115 +18,18 @@
 #include "base/threading/thread.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
-#include "media/base/android/demuxer_stream_player_params.h"
 #include "media/base/android/media_codec_bridge.h"
+#include "media/base/android/media_decoder_job.h"
 #include "media/base/android/media_player_android.h"
 #include "media/base/clock.h"
 #include "media/base/media_export.h"
 
-namespace base {
-class MessageLoopProxy;
-}
-
 namespace media {
 
 class AudioDecoderJob;
 class AudioTimestampHelper;
 class VideoDecoderJob;
 
-// Class for managing all the decoding tasks. Each decoding task will be posted
-// onto the same thread. The thread will be stopped once Stop() is called.
-class MediaDecoderJob {
- public:
-  enum DecodeStatus {
-    DECODE_SUCCEEDED,
-    DECODE_TRY_ENQUEUE_INPUT_AGAIN_LATER,
-    DECODE_TRY_DEQUEUE_OUTPUT_AGAIN_LATER,
-    DECODE_FORMAT_CHANGED,
-    DECODE_INPUT_END_OF_STREAM,
-    DECODE_OUTPUT_END_OF_STREAM,
-    DECODE_FAILED,
-  };
-
-  virtual ~MediaDecoderJob();
-
-  // Callback when a decoder job finishes its work. Args: whether decode
-  // finished successfully, presentation time, audio output bytes.
-  typedef base::Callback<void(DecodeStatus, const base::TimeDelta&,
-                              size_t)> DecoderCallback;
-
-  // Called by MediaSourcePlayer to decode some data.
-  void Decode(const AccessUnit& unit,
-              const base::TimeTicks& start_time_ticks,
-              const base::TimeDelta& start_presentation_timestamp,
-              const MediaDecoderJob::DecoderCallback& callback);
-
-  // Flush the decoder.
-  void Flush();
-
-  // Causes this instance to be deleted on the thread it is bound to.
-  void Release();
-
-  // Called on the UI thread to indicate that one decode cycle has completed.
-  void OnDecodeCompleted();
-
-  bool is_decoding() const { return is_decoding_; }
-
- protected:
-  MediaDecoderJob(const scoped_refptr<base::MessageLoopProxy>& decoder_loop,
-                  MediaCodecBridge* media_codec_bridge,
-                  bool is_audio);
-
-  // Release the output buffer and render it.
-  void ReleaseOutputBuffer(
-      int outputBufferIndex, size_t size,
-      const base::TimeDelta& presentation_timestamp,
-      const MediaDecoderJob::DecoderCallback& callback, DecodeStatus status);
-
-  DecodeStatus QueueInputBuffer(const AccessUnit& unit);
-
-  // Helper function to decoder data on |thread_|. |unit| contains all the data
-  // to be decoded. |start_time_ticks| and |start_presentation_timestamp|
-  // represent the system time and the presentation timestamp when the first
-  // frame is rendered. We use these information to estimate when the current
-  // frame should be rendered. If |needs_flush| is true, codec needs to be
-  // flushed at the beginning of this call.
-  void DecodeInternal(const AccessUnit& unit,
-                      const base::TimeTicks& start_time_ticks,
-                      const base::TimeDelta& start_presentation_timestamp,
-                      bool needs_flush,
-                      const MediaDecoderJob::DecoderCallback& callback);
-
-  // The UI message loop where callbacks should be dispatched.
-  scoped_refptr<base::MessageLoopProxy> ui_loop_;
-
-  // The message loop that decoder job runs on.
-  scoped_refptr<base::MessageLoopProxy> decoder_loop_;
-
-  // The media codec bridge used for decoding.
-  scoped_ptr<MediaCodecBridge> media_codec_bridge_;
-
-  // Whether the decoder needs to be flushed.
-  bool needs_flush_;
-
-  // Whether this is an audio decoder.
-  bool is_audio_;
-
-  // Whether input EOS is encountered.
-  bool input_eos_encountered_;
-
-  // Weak pointer passed to media decoder jobs for callbacks. It is bounded to
-  // the decoder thread.
-  base::WeakPtrFactory<MediaDecoderJob> weak_this_;
-
-  // Whether the decoder is actively decoding data.
-  bool is_decoding_;
-};
-
-struct DecoderJobDeleter {
-  inline void operator()(MediaDecoderJob* ptr) const { ptr->Release(); }
-};
-
 // This class handles media source extensions on Android. It uses Android
 // MediaCodec to decode audio and video streams in two separate threads.
 // IPC is being used to send data from the render process to this object.
@@ -271,9 +174,9 @@
   // The surface object currently owned by the player.
   gfx::ScopedJavaSurface surface_;
 
-  // Decoder jobs
-  scoped_ptr<AudioDecoderJob, DecoderJobDeleter> audio_decoder_job_;
-  scoped_ptr<VideoDecoderJob, DecoderJobDeleter> video_decoder_job_;
+  // Decoder jobs.
+  scoped_ptr<AudioDecoderJob, MediaDecoderJob::Deleter> audio_decoder_job_;
+  scoped_ptr<VideoDecoderJob, MediaDecoderJob::Deleter> video_decoder_job_;
 
   bool reconfig_audio_decoder_;
   bool reconfig_video_decoder_;
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index 40d28e4..02ded2d 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
 #include "media/base/android/media_codec_bridge.h"
 #include "media/base/android/media_player_manager.h"
 #include "media/base/android/media_source_player.h"
@@ -136,12 +137,13 @@
   }
 
   MediaPlayerHostMsg_ReadFromDemuxerAck_Params
-      CreateReadFromDemuxerAckForAudio() {
+      CreateReadFromDemuxerAckForAudio(int packet_id) {
     MediaPlayerHostMsg_ReadFromDemuxerAck_Params ack_params;
     ack_params.type = DemuxerStream::AUDIO;
     ack_params.access_units.resize(1);
     ack_params.access_units[0].status = DemuxerStream::kOk;
-    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vorbis-packet-0");
+    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(
+        base::StringPrintf("vorbis-packet-%d", packet_id));
     ack_params.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
@@ -165,6 +167,15 @@
     return ack_params;
   }
 
+  MediaPlayerHostMsg_ReadFromDemuxerAck_Params CreateEOSAck(bool is_audio) {
+      MediaPlayerHostMsg_ReadFromDemuxerAck_Params ack_params;
+      ack_params.type = is_audio ? DemuxerStream::AUDIO : DemuxerStream::VIDEO;
+      ack_params.access_units.resize(1);
+      ack_params.access_units[0].status = DemuxerStream::kOk;
+      ack_params.access_units[0].end_of_stream = true;
+      return ack_params;
+    }
+
   base::TimeTicks StartTimeTicks() {
     return player_->start_time_ticks_;
   }
@@ -334,7 +345,7 @@
   EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding());
 
   // Sending data to player.
-  player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio());
+  player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio(0));
   EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
 
   // Decoder job will not immediately stop after Pause() since it is
@@ -394,15 +405,12 @@
   EXPECT_FALSE(video_decoder_job->is_decoding());
 
   // Sending video data to player, both decoders should start now.
-  player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio());
+  player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio(0));
   EXPECT_TRUE(audio_decoder_job->is_decoding());
   EXPECT_TRUE(video_decoder_job->is_decoding());
 }
 
-// Disabled due to http://crbug.com/266041.
-// TODO(xhwang/qinmin): Fix this test and reenable it.
-TEST_F(MediaSourcePlayerTest,
-       DISABLED_StartTimeTicksResetAfterDecoderUnderruns) {
+TEST_F(MediaSourcePlayerTest, StartTimeTicksResetAfterDecoderUnderruns) {
   if (!MediaCodecBridge::IsAvailable())
     return;
 
@@ -410,12 +418,17 @@
   StartAudioDecoderJob();
   EXPECT_TRUE(NULL != GetMediaDecoderJob(true));
   EXPECT_EQ(1, manager_->num_requests());
-  player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio());
-  EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+  // For the first couple chunks, the decoder job may return
+  // DECODE_FORMAT_CHANGED status instead of DECODE_SUCCEEDED status. Decode
+  // more frames to guarantee that DECODE_SUCCEEDED will be returned.
+  for (int i = 0; i < 4; ++i) {
+    player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio(i));
+    EXPECT_TRUE(GetMediaDecoderJob(true)->is_decoding());
+    manager_->message_loop()->Run();
+  }
 
-  manager_->message_loop()->Run();
   // The decoder job should finish and a new request will be sent.
-  EXPECT_EQ(2, manager_->num_requests());
+  EXPECT_EQ(5, manager_->num_requests());
   EXPECT_FALSE(GetMediaDecoderJob(true)->is_decoding());
   base::TimeTicks previous = StartTimeTicks();
 
@@ -424,7 +437,7 @@
   manager_->message_loop()->RunUntilIdle();
 
   // Send new data to the decoder. This should reset the start time ticks.
-  player_->ReadFromDemuxerAck(CreateReadFromDemuxerAckForAudio());
+  player_->ReadFromDemuxerAck(CreateEOSAck(true));
   base::TimeTicks current = StartTimeTicks();
   EXPECT_LE(100.0, (current - previous).InMillisecondsF());
 }
@@ -448,12 +461,7 @@
   EXPECT_EQ(2, manager_->num_requests());
 
   // Send EOS.
-  MediaPlayerHostMsg_ReadFromDemuxerAck_Params ack_params;
-  ack_params.type = DemuxerStream::VIDEO;
-  ack_params.access_units.resize(1);
-  ack_params.access_units[0].status = DemuxerStream::kOk;
-  ack_params.access_units[0].end_of_stream = true;
-  player_->ReadFromDemuxerAck(ack_params);
+  player_->ReadFromDemuxerAck(CreateEOSAck(false));
   manager_->message_loop()->Run();
   // No more request for data should be made.
   EXPECT_EQ(2, manager_->num_requests());
diff --git a/media/base/android/video_decoder_job.cc b/media/base/android/video_decoder_job.cc
new file mode 100644
index 0000000..0cd7386
--- /dev/null
+++ b/media/base/android/video_decoder_job.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 "media/base/android/video_decoder_job.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/threading/thread.h"
+#include "media/base/android/media_codec_bridge.h"
+
+namespace media {
+
+class VideoDecoderThread : public base::Thread {
+ public:
+  VideoDecoderThread() : base::Thread("MediaSource_VideoDecoderThread") {
+    Start();
+  }
+};
+
+// TODO(qinmin): Check if it is tolerable to use worker pool to handle all the
+// decoding tasks so that we don't need a global thread here.
+// http://crbug.com/245750
+base::LazyInstance<VideoDecoderThread>::Leaky
+    g_video_decoder_thread = LAZY_INSTANCE_INITIALIZER;
+
+
+VideoDecoderJob* VideoDecoderJob::Create(
+    const VideoCodec video_codec, const gfx::Size& size, jobject surface,
+    jobject media_crypto) {
+  scoped_ptr<VideoCodecBridge> codec(VideoCodecBridge::Create(video_codec));
+  if (codec && codec->Start(video_codec, size, surface, media_crypto))
+    return new VideoDecoderJob(codec.Pass());
+  return NULL;
+}
+
+VideoDecoderJob::VideoDecoderJob(
+    scoped_ptr<VideoCodecBridge> video_codec_bridge)
+    : MediaDecoderJob(g_video_decoder_thread.Pointer()->message_loop_proxy(),
+                      video_codec_bridge.get()),
+      video_codec_bridge_(video_codec_bridge.Pass()) {
+}
+
+VideoDecoderJob::~VideoDecoderJob() {
+}
+
+void VideoDecoderJob::ReleaseOutputBuffer(
+    int outputBufferIndex, size_t size,
+    const base::TimeDelta& presentation_timestamp,
+    const MediaDecoderJob::DecoderCallback& callback,
+    DecodeStatus status) {
+
+  if (status != DECODE_OUTPUT_END_OF_STREAM || size != 0u)
+    video_codec_bridge_->ReleaseOutputBuffer(outputBufferIndex, true);
+
+  callback.Run(status, presentation_timestamp, 0);
+}
+
+bool VideoDecoderJob::ComputeTimeToRender() const {
+  return true;
+}
+
+}  // namespace media
diff --git a/media/base/android/video_decoder_job.h b/media/base/android/video_decoder_job.h
new file mode 100644
index 0000000..16f3229
--- /dev/null
+++ b/media/base/android/video_decoder_job.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 MEDIA_BASE_ANDROID_VIDEO_DECODER_JOB_H_
+#define MEDIA_BASE_ANDROID_VIDEO_DECODER_JOB_H_
+
+#include <jni.h>
+
+#include "media/base/android/media_decoder_job.h"
+
+namespace media {
+
+class VideoCodecBridge;
+
+// Class for managing video decoding jobs.
+class VideoDecoderJob : public MediaDecoderJob {
+ public:
+  virtual ~VideoDecoderJob();
+
+  // Create a new VideoDecoderJob instance.
+  // |video_codec| - The video format the object needs to decode.
+  // |size| -  The natrual size of the output frames.
+  // |surface| - The surface to render the frames to.
+  // |media_crypto| - Handle to a Java object responsible for decrypting the
+  // video data.
+  static VideoDecoderJob* Create(
+      const VideoCodec video_codec, const gfx::Size& size, jobject surface,
+      jobject media_crypto);
+
+ private:
+  VideoDecoderJob(scoped_ptr<VideoCodecBridge> video_codec_bridge);
+
+  // MediaDecoderJob implementation.
+  virtual void ReleaseOutputBuffer(
+      int outputBufferIndex, size_t size,
+      const base::TimeDelta& presentation_timestamp,
+      const MediaDecoderJob::DecoderCallback& callback,
+      DecodeStatus status) OVERRIDE;
+
+  virtual bool ComputeTimeToRender() const OVERRIDE;
+
+  scoped_ptr<VideoCodecBridge> video_codec_bridge_;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_ANDROID_VIDEO_DECODER_JOB_H_
diff --git a/media/base/audio_buffer.cc b/media/base/audio_buffer.cc
index b2cdd8c..0bf3720 100644
--- a/media/base/audio_buffer.cc
+++ b/media/base/audio_buffer.cc
@@ -11,11 +11,6 @@
 
 namespace media {
 
-// Alignment of each channel's data; this must match what ffmpeg expects
-// (which may be 0, 16, or 32, depending on the processor). Selecting 32 in
-// order to work on all processors.
-enum { kChannelAlignment = 32 };
-
 AudioBuffer::AudioBuffer(SampleFormat sample_format,
                          int channel_count,
                          int frame_count,
@@ -73,6 +68,8 @@
   data_size *= channel_count;
   data_.reset(
       static_cast<uint8*>(base::AlignedAlloc(data_size, kChannelAlignment)));
+  channel_data_.reserve(1);
+  channel_data_.push_back(data_.get());
   if (data)
     memcpy(data_.get(), data[0], data_size);
 }
diff --git a/media/base/audio_buffer.h b/media/base/audio_buffer.h
index e52355a..c3bcf4d 100644
--- a/media/base/audio_buffer.h
+++ b/media/base/audio_buffer.h
@@ -23,6 +23,11 @@
 class MEDIA_EXPORT AudioBuffer
     : public base::RefCountedThreadSafe<AudioBuffer> {
  public:
+  // Alignment of each channel's data; this must match what ffmpeg expects
+  // (which may be 0, 16, or 32, depending on the processor). Selecting 32 in
+  // order to work on all processors.
+  enum { kChannelAlignment = 32 };
+
   // Create an AudioBuffer whose channel data is copied from |data|. For
   // interleaved data, only the first buffer is used. For planar data, the
   // number of buffers must be equal to |channel_count|. |frame_count| is the
@@ -95,8 +100,8 @@
   bool end_of_stream() const { return end_of_stream_; }
 
   // Access to the raw buffer for ffmpeg to write directly to. Data for planar
-  // data is grouped by channel.
-  uint8* writable_data() { return data_.get(); }
+  // data is grouped by channel. There is only 1 entry for interleaved formats.
+  const std::vector<uint8*>& channel_data() const { return channel_data_; }
 
  private:
   friend class base::RefCountedThreadSafe<AudioBuffer>;
diff --git a/media/base/audio_capturer_source.h b/media/base/audio_capturer_source.h
index deae5e2..b584f8a 100644
--- a/media/base/audio_capturer_source.h
+++ b/media/base/audio_capturer_source.h
@@ -26,7 +26,8 @@
     // Callback to deliver the captured data from the OS.
     virtual void Capture(AudioBus* audio_source,
                          int audio_delay_milliseconds,
-                         double volume) = 0;
+                         double volume,
+                         bool key_pressed) = 0;
 
     // Signals an error has occurred.
     virtual void OnCaptureError() = 0;
diff --git a/media/base/channel_layout.cc b/media/base/channel_layout.cc
index e895ddc..958430a 100644
--- a/media/base/channel_layout.cc
+++ b/media/base/channel_layout.cc
@@ -184,4 +184,73 @@
   return kChannelOrderings[layout][channel];
 }
 
+const char* ChannelLayoutToString(ChannelLayout layout) {
+  switch (layout) {
+    case CHANNEL_LAYOUT_NONE:
+      return "NONE";
+    case CHANNEL_LAYOUT_UNSUPPORTED:
+      return "UNSUPPORTED";
+    case CHANNEL_LAYOUT_MONO:
+      return "MONO";
+    case CHANNEL_LAYOUT_STEREO:
+      return "STEREO";
+    case CHANNEL_LAYOUT_2_1:
+      return "2.1";
+    case CHANNEL_LAYOUT_SURROUND:
+      return "SURROUND";
+    case CHANNEL_LAYOUT_4_0:
+      return "4.0";
+    case CHANNEL_LAYOUT_2_2:
+      return "2.2";
+    case CHANNEL_LAYOUT_QUAD:
+      return "QUAD";
+    case CHANNEL_LAYOUT_5_0:
+      return "5.0";
+    case CHANNEL_LAYOUT_5_1:
+      return "5.1";
+    case CHANNEL_LAYOUT_5_0_BACK:
+      return "5.0_BACK";
+    case CHANNEL_LAYOUT_5_1_BACK:
+      return "5.1_BACK";
+    case CHANNEL_LAYOUT_7_0:
+      return "7.0";
+    case CHANNEL_LAYOUT_7_1:
+      return "7.1";
+    case CHANNEL_LAYOUT_7_1_WIDE:
+      return "7.1_WIDE";
+    case CHANNEL_LAYOUT_STEREO_DOWNMIX:
+      return "STEREO_DOWNMIX";
+    case CHANNEL_LAYOUT_2POINT1:
+      return "2POINT1";
+    case CHANNEL_LAYOUT_3_1:
+      return "3.1";
+    case CHANNEL_LAYOUT_4_1:
+      return "4.1";
+    case CHANNEL_LAYOUT_6_0:
+      return "6.0";
+    case CHANNEL_LAYOUT_6_0_FRONT:
+      return "6.0_FRONT";
+    case CHANNEL_LAYOUT_HEXAGONAL:
+      return "HEXAGONAL";
+    case CHANNEL_LAYOUT_6_1:
+      return "6.1";
+    case CHANNEL_LAYOUT_6_1_BACK:
+      return "6.1_BACK";
+    case CHANNEL_LAYOUT_6_1_FRONT:
+      return "6.1_FRONT";
+    case CHANNEL_LAYOUT_7_0_FRONT:
+      return "7.0_FRONT";
+    case CHANNEL_LAYOUT_7_1_WIDE_BACK:
+      return "7.1_WIDE_BACK";
+    case CHANNEL_LAYOUT_OCTAGONAL:
+      return "OCTAGONAL";
+    case CHANNEL_LAYOUT_DISCRETE:
+      return "DISCRETE";
+    case CHANNEL_LAYOUT_MAX:
+      break;
+  }
+  NOTREACHED() << "Invalid channel layout provided: " << layout;
+  return "";
+}
+
 }  // namespace media
diff --git a/media/base/channel_layout.h b/media/base/channel_layout.h
index 4c96ca5..9354eee 100644
--- a/media/base/channel_layout.h
+++ b/media/base/channel_layout.h
@@ -130,6 +130,9 @@
 // or return CHANNEL_LAYOUT_UNSUPPORTED if there is no good match.
 MEDIA_EXPORT ChannelLayout GuessChannelLayout(int channels);
 
+// Returns a string representation of the channel layout.
+MEDIA_EXPORT const char* ChannelLayoutToString(ChannelLayout layout);
+
 }  // namespace media
 
 #endif  // MEDIA_BASE_CHANNEL_LAYOUT_H_
diff --git a/media/base/demuxer.h b/media/base/demuxer.h
index 6a91aab..81ac33b 100644
--- a/media/base/demuxer.h
+++ b/media/base/demuxer.h
@@ -47,8 +47,10 @@
   // callback upon completion.
   virtual void Seek(base::TimeDelta time, const PipelineStatusCB& status_cb);
 
-  // The pipeline is being stopped either as a result of an error or because
-  // the client called Stop().
+  // Starts stopping this demuxer, executing the callback upon completion.
+  //
+  // After the callback completes the demuxer may be destroyed. It is illegal to
+  // call any method (including Stop()) after a demuxer has stopped.
   virtual void Stop(const base::Closure& callback);
 
   // This method is called from the pipeline when the audio renderer
diff --git a/media/base/media_file_checker_unittest.cc b/media/base/media_file_checker_unittest.cc
index f43c846..ec61edf 100644
--- a/media/base/media_file_checker_unittest.cc
+++ b/media/base/media_file_checker_unittest.cc
@@ -39,7 +39,7 @@
   RunMediaFileChecker("sfx.ogg", true);
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 TEST(MediaFileCheckerTest, MP3) {
   RunMediaFileChecker("sfx.mp3", true);
 }
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 3c1dc16..2ebf5df 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -66,6 +66,13 @@
 // Use Windows WaveOut/In audio API even if Core Audio is supported.
 const char kForceWaveAudio[] = "force-wave-audio";
 
+// Instead of always using the hardware channel layout, check if a driver
+// supports the source channel layout.  Avoids outputting empty channels and
+// permits drivers to enable stereo to multichannel expansion.  Kept behind a
+// flag since some drivers lie about supported layouts and hang when used.  See
+// http://crbug.com/259165 for more details.
+const char kTrySupportedChannelLayouts[] = "try-supported-channel-layouts";
+
 // Number of buffers to use for WaveOut.
 const char kWaveOutBuffers[] = "waveout-buffers";
 #endif
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 885839d..e6c1de0 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -41,6 +41,7 @@
 MEDIA_EXPORT extern const char kEnableExclusiveAudio[];
 MEDIA_EXPORT extern const char kForceDirectShowVideoCapture[];
 MEDIA_EXPORT extern const char kForceWaveAudio[];
+MEDIA_EXPORT extern const char kTrySupportedChannelLayouts[];
 MEDIA_EXPORT extern const char kWaveOutBuffers[];
 #endif
 
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc
index ccac819..9790c61 100644
--- a/media/base/pipeline.cc
+++ b/media/base/pipeline.cc
@@ -723,10 +723,14 @@
     return;
   }
 
-  SetState(kStopping);
-  pending_callbacks_.reset();
   stop_cb_ = stop_cb;
 
+  // We may already be stopping due to a runtime error.
+  if (state_ == kStopping)
+    return;
+
+  SetState(kStopping);
+  pending_callbacks_.reset();
   DoStop(base::Bind(&Pipeline::OnStopCompleted, base::Unretained(this)));
 }
 
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc
index 90c616f..360f233 100644
--- a/media/base/pipeline_unittest.cc
+++ b/media/base/pipeline_unittest.cc
@@ -5,6 +5,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/callback_helpers.h"
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "base/test/simple_test_tick_clock.h"
@@ -871,6 +872,7 @@
   enum StopOrError {
     kStop,
     kError,
+    kErrorAndStop,
   };
 
   PipelineTeardownTest() {}
@@ -1132,17 +1134,42 @@
   void DoStopOrError(StopOrError stop_or_error) {
     InSequence s;
 
-    EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
+    // Save the callback and run it after the error teardown path has started
+    // running.
+    //
+    // TODO(scherkus): Remove after https://codereview.chromium.org/22850009
+    // lands.
+    base::Closure stop_cb;
+    if (stop_or_error == kErrorAndStop) {
+      EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(SaveArg<0>(&stop_cb));
+    } else {
+      EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
+    }
+
     EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
     EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
 
-    if (stop_or_error == kStop) {
-      EXPECT_CALL(callbacks_, OnStop());
-      pipeline_->Stop(base::Bind(
-          &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
-    } else {
-      EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
-      pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
+    switch (stop_or_error) {
+      case kStop:
+        EXPECT_CALL(callbacks_, OnStop());
+        pipeline_->Stop(base::Bind(
+            &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+        break;
+
+      case kError:
+        EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
+        pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
+        break;
+
+      case kErrorAndStop:
+        pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
+        message_loop_.RunUntilIdle();
+        base::ResetAndReturn(&stop_cb).Run();
+
+        EXPECT_CALL(callbacks_, OnStop());
+        pipeline_->Stop(base::Bind(
+            &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+        break;
     }
 
     message_loop_.RunUntilIdle();
@@ -1176,4 +1203,6 @@
 INSTANTIATE_TEARDOWN_TEST(Error, Starting);
 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
 
+INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
+
 }  // namespace media
diff --git a/media/base/serial_runner.h b/media/base/serial_runner.h
index a59c775..ef4b5d7 100644
--- a/media/base/serial_runner.h
+++ b/media/base/serial_runner.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
 
 namespace base {
@@ -22,13 +23,13 @@
 // Runs a series of bound functions accepting Closures or PipelineStatusCB.
 // SerialRunner doesn't use regular Closure/PipelineStatusCBs as it late binds
 // the completion callback as the series progresses.
-class SerialRunner {
+class MEDIA_EXPORT SerialRunner {
  public:
   typedef base::Callback<void(const base::Closure&)> BoundClosure;
   typedef base::Callback<void(const PipelineStatusCB&)> BoundPipelineStatusCB;
 
   // Serial queue of bound functions to run.
-  class Queue {
+  class MEDIA_EXPORT Queue {
    public:
     Queue();
     ~Queue();
diff --git a/media/base/serial_runner_unittest.cc b/media/base/serial_runner_unittest.cc
new file mode 100644
index 0000000..8df28be
--- /dev/null
+++ b/media/base/serial_runner_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright 2013 The Chromium Authors. 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/debug/stack_trace.h"
+#include "base/message_loop/message_loop.h"
+#include "media/base/pipeline_status.h"
+#include "media/base/serial_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class SerialRunnerTest : public ::testing::Test {
+ public:
+  SerialRunnerTest()
+      : inside_start_(false), done_called_(false), done_status_(PIPELINE_OK) {}
+  virtual ~SerialRunnerTest() {}
+
+  void RunSerialRunner() {
+    message_loop_.PostTask(FROM_HERE, base::Bind(
+        &SerialRunnerTest::StartRunnerInternal, base::Unretained(this),
+        bound_fns_));
+    message_loop_.RunUntilIdle();
+  }
+
+  // Pushes a bound function to the queue that will run its callback with
+  // |status|. called(i) returns whether the i'th bound function pushed to the
+  // queue was called while running the SerialRunner.
+  void PushBoundFunction(PipelineStatus status) {
+    bound_fns_.Push(base::Bind(&SerialRunnerTest::RunBoundFunction,
+                               base::Unretained(this),
+                               status,
+                               called_.size()));
+    called_.push_back(false);
+  }
+
+  // Push a bound function to the queue that will delete the SerialRunner,
+  // which should cancel all remaining queued work.
+  void PushCancellation() {
+    bound_fns_.Push(base::Bind(&SerialRunnerTest::CancelSerialRunner,
+                               base::Unretained(this)));
+  }
+
+  // Queries final status of pushed functions and done callback. Valid only
+  // after calling RunSerialRunner().
+  bool called(size_t index) { return called_[index]; }
+  bool done_called() { return done_called_; }
+  PipelineStatus done_status() { return done_status_; }
+
+ private:
+  void RunBoundFunction(PipelineStatus status,
+                        size_t index,
+                        const PipelineStatusCB& status_cb) {
+    EXPECT_FALSE(inside_start_)
+        << "Bound functions should not run on same stack as "
+        << "SerialRunner::Run()\n" << base::debug::StackTrace().ToString();
+
+    called_[index] = true;
+    status_cb.Run(status);
+  }
+
+  void StartRunnerInternal(const SerialRunner::Queue& bound_fns) {
+    inside_start_ = true;
+    runner_ = SerialRunner::Run(bound_fns_, base::Bind(
+        &SerialRunnerTest::DoneCallback, base::Unretained(this)));
+    inside_start_ = false;
+  }
+
+  void DoneCallback(PipelineStatus status) {
+    EXPECT_FALSE(inside_start_)
+        << "Done callback should not run on same stack as SerialRunner::Run()\n"
+        << base::debug::StackTrace().ToString();
+
+    done_called_ = true;
+    done_status_ = status;
+    message_loop_.QuitWhenIdle();
+  }
+
+  void CancelSerialRunner(const PipelineStatusCB& status_cb) {
+    // Tasks run by |runner_| shouldn't reset it, hence we post a task to do so.
+    message_loop_.PostTask(FROM_HERE, base::Bind(
+        &SerialRunnerTest::ResetSerialRunner, base::Unretained(this)));
+    status_cb.Run(PIPELINE_OK);
+  }
+
+  void ResetSerialRunner() {
+    runner_.reset();
+  }
+
+  base::MessageLoop message_loop_;
+  SerialRunner::Queue bound_fns_;
+  scoped_ptr<SerialRunner> runner_;
+
+  // Used to enforce calling stack guarantees of the API.
+  bool inside_start_;
+
+  // Tracks whether the i'th bound function was called.
+  std::vector<bool> called_;
+
+  // Tracks whether the final done callback was called + resulting status.
+  bool done_called_;
+  PipelineStatus done_status_;
+
+  DISALLOW_COPY_AND_ASSIGN(SerialRunnerTest);
+};
+
+TEST_F(SerialRunnerTest, Empty) {
+  RunSerialRunner();
+
+  EXPECT_TRUE(done_called());
+  EXPECT_EQ(PIPELINE_OK, done_status());
+}
+
+TEST_F(SerialRunnerTest, Single) {
+  PushBoundFunction(PIPELINE_OK);
+  RunSerialRunner();
+
+  EXPECT_TRUE(called(0));
+  EXPECT_TRUE(done_called());
+  EXPECT_EQ(PIPELINE_OK, done_status());
+}
+
+TEST_F(SerialRunnerTest, Single_Error) {
+  PushBoundFunction(PIPELINE_ERROR_ABORT);
+  RunSerialRunner();
+
+  EXPECT_TRUE(called(0));
+  EXPECT_TRUE(done_called());
+  EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status());
+}
+
+TEST_F(SerialRunnerTest, Single_Cancel) {
+  PushBoundFunction(PIPELINE_OK);
+  PushCancellation();
+  RunSerialRunner();
+
+  EXPECT_TRUE(called(0));
+  EXPECT_FALSE(done_called());
+}
+
+TEST_F(SerialRunnerTest, Multiple) {
+  PushBoundFunction(PIPELINE_OK);
+  PushBoundFunction(PIPELINE_OK);
+  RunSerialRunner();
+
+  EXPECT_TRUE(called(0));
+  EXPECT_TRUE(called(1));
+  EXPECT_TRUE(done_called());
+  EXPECT_EQ(PIPELINE_OK, done_status());
+}
+
+TEST_F(SerialRunnerTest, Multiple_Error) {
+  PushBoundFunction(PIPELINE_ERROR_ABORT);
+  PushBoundFunction(PIPELINE_OK);
+  RunSerialRunner();
+
+  EXPECT_TRUE(called(0));
+  EXPECT_FALSE(called(1));  // A bad status cancels remaining work.
+  EXPECT_TRUE(done_called());
+  EXPECT_EQ(PIPELINE_ERROR_ABORT, done_status());
+}
+
+TEST_F(SerialRunnerTest, Multiple_Cancel) {
+  PushBoundFunction(PIPELINE_OK);
+  PushCancellation();
+  PushBoundFunction(PIPELINE_OK);
+  RunSerialRunner();
+
+  EXPECT_TRUE(called(0));
+  EXPECT_FALSE(called(1));
+  EXPECT_FALSE(done_called());
+}
+
+}  // namespace media
diff --git a/media/base/user_input_monitor.cc b/media/base/user_input_monitor.cc
new file mode 100644
index 0000000..18b4c80
--- /dev/null
+++ b/media/base/user_input_monitor.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 "media/base/user_input_monitor.h"
+
+#include "third_party/skia/include/core/SkPoint.h"
+
+namespace media {
+
+#ifdef DISABLE_USER_INPUT_MONITOR
+scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
+    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
+  return scoped_ptr<UserInputMonitor>();
+}
+#endif  // DISABLE_USER_INPUT_MONITOR
+
+UserInputMonitor::~UserInputMonitor() {
+  DCHECK(!monitoring_mouse_);
+  DCHECK(!monitoring_keyboard_);
+}
+
+void UserInputMonitor::AddMouseListener(MouseEventListener* listener) {
+  base::AutoLock auto_lock(lock_);
+  mouse_listeners_.AddObserver(listener);
+  if (!monitoring_mouse_) {
+    StartMouseMonitoring();
+    monitoring_mouse_ = true;
+    DVLOG(2) << "Started mouse monitoring.";
+  }
+}
+void UserInputMonitor::RemoveMouseListener(MouseEventListener* listener) {
+  base::AutoLock auto_lock(lock_);
+  mouse_listeners_.RemoveObserver(listener);
+  if (mouse_listeners_.size() == 0) {
+    StopMouseMonitoring();
+    monitoring_mouse_ = false;
+    DVLOG(2) << "Stopped mouse monitoring.";
+  }
+}
+void UserInputMonitor::AddKeyStrokeListener(KeyStrokeListener* listener) {
+  base::AutoLock auto_lock(lock_);
+  key_stroke_listeners_.AddObserver(listener);
+  if (!monitoring_keyboard_) {
+    StartKeyboardMonitoring();
+    monitoring_keyboard_ = true;
+    DVLOG(2) << "Started keyboard monitoring.";
+  }
+}
+void UserInputMonitor::RemoveKeyStrokeListener(KeyStrokeListener* listener) {
+  base::AutoLock auto_lock(lock_);
+  key_stroke_listeners_.RemoveObserver(listener);
+  if (key_stroke_listeners_.size() == 0) {
+    StopKeyboardMonitoring();
+    monitoring_keyboard_ = false;
+    DVLOG(2) << "Stopped keyboard monitoring.";
+  }
+}
+
+UserInputMonitor::UserInputMonitor()
+    : monitoring_mouse_(false), monitoring_keyboard_(false) {}
+
+void UserInputMonitor::OnMouseEvent(const SkIPoint& position) {
+  base::AutoLock auto_lock(lock_);
+  FOR_EACH_OBSERVER(
+      MouseEventListener, mouse_listeners_, OnMouseMoved(position));
+}
+
+void UserInputMonitor::OnKeyboardEvent(ui::EventType event,
+                                       ui::KeyboardCode key_code) {
+  base::AutoLock auto_lock(lock_);
+  // Updates the pressed keys and maybe notifies the key_stroke_listeners_.
+  if (event == ui::ET_KEY_PRESSED) {
+    if (pressed_keys_.find(key_code) != pressed_keys_.end())
+      return;
+    pressed_keys_.insert(key_code);
+    DVLOG(6) << "Key stroke detected.";
+    FOR_EACH_OBSERVER(KeyStrokeListener, key_stroke_listeners_, OnKeyStroke());
+  } else {
+    DCHECK_EQ(ui::ET_KEY_RELEASED, event);
+    DCHECK(pressed_keys_.find(key_code) != pressed_keys_.end());
+    pressed_keys_.erase(key_code);
+  }
+}
+
+}  // namespace media
diff --git a/media/base/user_input_monitor.h b/media/base/user_input_monitor.h
new file mode 100644
index 0000000..9eb82f3
--- /dev/null
+++ b/media/base/user_input_monitor.h
@@ -0,0 +1,99 @@
+// Copyright 2013 The Chromium Authors. 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_BASE_USER_INPUT_MONITOR_H_
+#define MEDIA_BASE_USER_INPUT_MONITOR_H_
+
+#include <set>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/synchronization/lock.h"
+#include "media/base/media_export.h"
+#include "ui/base/events/event_constants.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+
+struct SkIPoint;
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace media {
+
+// Monitors and notifies about mouse movements and keyboard events.
+// Thread safe. The thread on which the listenters are called is not guaranteed.
+// The callers should not perform expensive/blocking tasks in the callback since
+// it might be called on the browser UI/IO threads.
+class MEDIA_EXPORT UserInputMonitor {
+ public:
+  // The interface to receive mouse movement events.
+  class MEDIA_EXPORT MouseEventListener {
+   public:
+    // |position| is the new mouse position.
+    virtual void OnMouseMoved(const SkIPoint& position) = 0;
+
+   protected:
+    virtual ~MouseEventListener() {}
+  };
+  // The interface to receive key stroke events.
+  class MEDIA_EXPORT KeyStrokeListener {
+   public:
+    // Called when any key is pressed. Called only once until the key is
+    // released, i.e. holding down a key for a long period will generate one
+    // callback just when the key is pressed down.
+    virtual void OnKeyStroke() = 0;
+
+   protected:
+    virtual ~KeyStrokeListener() {}
+  };
+
+  virtual ~UserInputMonitor();
+
+  // Creates a platform-specific instance of UserInputMonitor.
+  // |io_task_runner| is the task runner for an IO thread.
+  // |ui_task_runner| is the task runner for a UI thread.
+  static scoped_ptr<UserInputMonitor> Create(
+      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+      const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner);
+
+  // The same |listener| should only be added once.
+  // The clients should make sure to call Remove*Listener before |listener| is
+  // destroyed.
+  void AddMouseListener(MouseEventListener* listener);
+  void RemoveMouseListener(MouseEventListener* listener);
+  void AddKeyStrokeListener(KeyStrokeListener* listener);
+  void RemoveKeyStrokeListener(KeyStrokeListener* listener);
+
+ protected:
+  UserInputMonitor();
+
+  // Called by the platform-specific sub-classes to propagate the events to the
+  // listeners.
+  void OnMouseEvent(const SkIPoint& position);
+  void OnKeyboardEvent(ui::EventType event, ui::KeyboardCode key_code);
+
+ private:
+  virtual void StartMouseMonitoring() = 0;
+  virtual void StopMouseMonitoring() = 0;
+  virtual void StartKeyboardMonitoring() = 0;
+  virtual void StopKeyboardMonitoring() = 0;
+
+  base::Lock lock_;
+  ObserverList<MouseEventListener, true> mouse_listeners_;
+  ObserverList<KeyStrokeListener, true> key_stroke_listeners_;
+  bool monitoring_mouse_;
+  bool monitoring_keyboard_;
+  // The set of keys currently held down. Used for convering raw keyboard events
+  // into KeyStrokeListener callbacks.
+  std::set<ui::KeyboardCode> pressed_keys_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserInputMonitor);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_USER_INPUT_MONITOR_H_
diff --git a/media/base/user_input_monitor_linux.cc b/media/base/user_input_monitor_linux.cc
new file mode 100644
index 0000000..ee1b774
--- /dev/null
+++ b/media/base/user_input_monitor_linux.cc
@@ -0,0 +1,338 @@
+// Copyright 2013 The Chromium Authors. 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/base/user_input_monitor.h"
+
+#include <sys/select.h>
+#include <unistd.h>
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_libevent.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/non_thread_safe.h"
+#include "third_party/skia/include/core/SkPoint.h"
+#include "ui/base/keycodes/keyboard_code_conversion_x.h"
+
+// These includes need to be later than dictated by the style guide due to
+// Xlib header pollution, specifically the min, max, and Status macros.
+#include <X11/XKBlib.h>
+#include <X11/Xlibint.h>
+#include <X11/extensions/record.h>
+
+namespace media {
+
+namespace {
+
+class UserInputMonitorLinux : public base::NonThreadSafe,
+                              public UserInputMonitor {
+ public:
+  UserInputMonitorLinux(
+      const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
+  virtual ~UserInputMonitorLinux();
+
+ private:
+  enum EventType {
+    MOUSE_EVENT,
+    KEYBOARD_EVENT
+  };
+
+  // The actual implementation resides in UserInputMonitorLinux::Core class.
+  // Must be called on the io_task_runner thread.
+  class Core : public base::RefCountedThreadSafe<Core>,
+               public base::MessagePumpLibevent::Watcher {
+   public:
+    typedef const base::Callback<void(const SkIPoint&)> MouseCallback;
+    typedef base::Callback<void(ui::EventType event, ui::KeyboardCode key_code)>
+        KeyboardCallback;
+    Core(const MouseCallback& mouse_callback,
+         const KeyboardCallback& keyboard_callback);
+
+    void StartMonitor(EventType type);
+    void StopMonitor(EventType type);
+
+   private:
+    friend class base::RefCountedThreadSafe<Core>;
+    virtual ~Core();
+
+    // base::MessagePumpLibevent::Watcher interface.
+    virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
+    virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
+
+    // Processes key and mouse events.
+    void ProcessXEvent(xEvent* event);
+    static void ProcessReply(XPointer self, XRecordInterceptData* data);
+
+    // Used to receive base::MessagePumpLibevent::Watcher events.
+    base::MessagePumpLibevent::FileDescriptorWatcher controller_;
+
+    Display* display_;
+    Display* x_record_display_;
+    XRecordRange* x_record_range_[2];
+    XRecordContext x_record_context_;
+    base::Callback<void(const SkIPoint&)> mouse_callback_;
+    base::Callback<void(ui::EventType event, ui::KeyboardCode key_code)>
+        keyboard_callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(Core);
+  };
+
+  virtual void StartMouseMonitoring() OVERRIDE;
+  virtual void StopMouseMonitoring() OVERRIDE;
+  virtual void StartKeyboardMonitoring() OVERRIDE;
+  virtual void StopKeyboardMonitoring() OVERRIDE;
+
+  void OnMouseEvent(const SkIPoint& position);
+  void OnKeyboardEvent(ui::EventType event, ui::KeyboardCode key_code);
+
+  // Task runner on which X Window events are received.
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+  scoped_refptr<Core> core_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserInputMonitorLinux);
+};
+
+UserInputMonitorLinux::UserInputMonitorLinux(
+    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
+    : io_task_runner_(io_task_runner),
+      core_(new Core(base::Bind(&UserInputMonitorLinux::OnMouseEvent,
+                                base::Unretained(this)),
+                     base::Bind(&UserInputMonitorLinux::OnKeyboardEvent,
+                                base::Unretained(this)))) {}
+
+UserInputMonitorLinux::~UserInputMonitorLinux() {}
+
+void UserInputMonitorLinux::StartMouseMonitoring() {
+  io_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Core::StartMonitor, core_.get(), MOUSE_EVENT));
+}
+
+void UserInputMonitorLinux::StopMouseMonitoring() {
+  io_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Core::StopMonitor, core_.get(), MOUSE_EVENT));
+}
+
+void UserInputMonitorLinux::StartKeyboardMonitoring() {
+  io_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Core::StartMonitor, core_.get(), KEYBOARD_EVENT));
+}
+
+void UserInputMonitorLinux::StopKeyboardMonitoring() {
+  io_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&Core::StopMonitor, core_.get(), KEYBOARD_EVENT));
+}
+
+void UserInputMonitorLinux::OnMouseEvent(const SkIPoint& position) {
+  UserInputMonitor::OnMouseEvent(position);
+}
+
+void UserInputMonitorLinux::OnKeyboardEvent(ui::EventType event,
+                                            ui::KeyboardCode key_code) {
+  UserInputMonitor::OnKeyboardEvent(event, key_code);
+}
+
+UserInputMonitorLinux::Core::Core(const MouseCallback& mouse_callback,
+                                  const KeyboardCallback& keyboard_callback)
+    : display_(NULL),
+      x_record_display_(NULL),
+      x_record_context_(0),
+      mouse_callback_(mouse_callback),
+      keyboard_callback_(keyboard_callback) {
+  x_record_range_[0] = NULL;
+  x_record_range_[1] = NULL;
+}
+
+UserInputMonitorLinux::Core::~Core() {
+  DCHECK(!display_);
+  DCHECK(!x_record_display_);
+  DCHECK(!x_record_range_[0]);
+  DCHECK(!x_record_range_[1]);
+  DCHECK(!x_record_context_);
+}
+
+void UserInputMonitorLinux::Core::StartMonitor(EventType type) {
+  DCHECK(base::MessageLoopForIO::current());
+  // TODO(jamiewalch): We should pass the display in. At that point, since
+  // XRecord needs a private connection to the X Server for its data channel
+  // and both channels are used from a separate thread, we'll need to duplicate
+  // them with something like the following:
+  //   XOpenDisplay(DisplayString(display));
+  if (!display_)
+    display_ = XOpenDisplay(NULL);
+
+  if (!x_record_display_)
+    x_record_display_ = XOpenDisplay(NULL);
+
+  if (!display_ || !x_record_display_) {
+    LOG(ERROR) << "Couldn't open X display";
+    return;
+  }
+
+  int xr_opcode, xr_event, xr_error;
+  if (!XQueryExtension(display_, "RECORD", &xr_opcode, &xr_event, &xr_error)) {
+    LOG(ERROR) << "X Record extension not available.";
+    return;
+  }
+
+  if (!x_record_range_[type])
+    x_record_range_[type] = XRecordAllocRange();
+
+  if (!x_record_range_[type]) {
+    LOG(ERROR) << "XRecordAllocRange failed.";
+    return;
+  }
+
+  if (type == MOUSE_EVENT) {
+    x_record_range_[type]->device_events.first = MotionNotify;
+    x_record_range_[type]->device_events.last = MotionNotify;
+  } else {
+    DCHECK_EQ(KEYBOARD_EVENT, type);
+    x_record_range_[type]->device_events.first = KeyPress;
+    x_record_range_[type]->device_events.last = KeyRelease;
+  }
+
+  if (x_record_context_) {
+    XRecordDisableContext(display_, x_record_context_);
+    XFlush(display_);
+    XRecordFreeContext(x_record_display_, x_record_context_);
+    x_record_context_ = 0;
+  }
+  XRecordRange** record_range_to_use =
+      (x_record_range_[0] && x_record_range_[1]) ? x_record_range_
+                                                 : &x_record_range_[type];
+  int number_of_ranges = (x_record_range_[0] && x_record_range_[1]) ? 2 : 1;
+
+  XRecordClientSpec client_spec = XRecordAllClients;
+  x_record_context_ = XRecordCreateContext(x_record_display_,
+                                           0,
+                                           &client_spec,
+                                           1,
+                                           record_range_to_use,
+                                           number_of_ranges);
+  if (!x_record_context_) {
+    LOG(ERROR) << "XRecordCreateContext failed.";
+    return;
+  }
+
+  if (!XRecordEnableContextAsync(x_record_display_,
+                                 x_record_context_,
+                                 &Core::ProcessReply,
+                                 reinterpret_cast<XPointer>(this))) {
+    LOG(ERROR) << "XRecordEnableContextAsync failed.";
+    return;
+  }
+
+  if (!x_record_range_[0] || !x_record_range_[1]) {
+    // Register OnFileCanReadWithoutBlocking() to be called every time there is
+    // something to read from |x_record_display_|.
+    base::MessageLoopForIO* message_loop = base::MessageLoopForIO::current();
+    int result =
+        message_loop->WatchFileDescriptor(ConnectionNumber(x_record_display_),
+                                          true,
+                                          base::MessageLoopForIO::WATCH_READ,
+                                          &controller_,
+                                          this);
+    if (!result) {
+      LOG(ERROR) << "Failed to create X record task.";
+      return;
+    }
+  }
+
+  // Fetch pending events if any.
+  OnFileCanReadWithoutBlocking(ConnectionNumber(x_record_display_));
+}
+
+void UserInputMonitorLinux::Core::StopMonitor(EventType type) {
+  DCHECK(base::MessageLoopForIO::current());
+
+  if (x_record_range_[type]) {
+    XFree(x_record_range_[type]);
+    x_record_range_[type] = NULL;
+  }
+  if (x_record_range_[0] || x_record_range_[1])
+    return;
+
+  // Context must be disabled via the control channel because we can't send
+  // any X protocol traffic over the data channel while it's recording.
+  if (x_record_context_) {
+    XRecordDisableContext(display_, x_record_context_);
+    XFlush(display_);
+    XRecordFreeContext(x_record_display_, x_record_context_);
+    x_record_context_ = 0;
+
+    controller_.StopWatchingFileDescriptor();
+    if (x_record_display_) {
+      XCloseDisplay(x_record_display_);
+      x_record_display_ = NULL;
+    }
+    if (display_) {
+      XCloseDisplay(display_);
+      display_ = NULL;
+    }
+  }
+}
+
+void UserInputMonitorLinux::Core::OnFileCanReadWithoutBlocking(int fd) {
+  DCHECK(base::MessageLoopForIO::current());
+  XEvent event;
+  // Fetch pending events if any.
+  while (XPending(x_record_display_)) {
+    XNextEvent(x_record_display_, &event);
+  }
+}
+
+void UserInputMonitorLinux::Core::OnFileCanWriteWithoutBlocking(int fd) {
+  NOTREACHED();
+}
+
+void UserInputMonitorLinux::Core::ProcessXEvent(xEvent* event) {
+  if (event->u.u.type == MotionNotify) {
+    SkIPoint position(SkIPoint::Make(event->u.keyButtonPointer.rootX,
+                                     event->u.keyButtonPointer.rootY));
+    mouse_callback_.Run(position);
+  } else {
+    ui::EventType type;
+    if (event->u.u.type == KeyPress) {
+      type = ui::ET_KEY_PRESSED;
+    } else if (event->u.u.type == KeyRelease) {
+      type = ui::ET_KEY_RELEASED;
+    } else {
+      NOTREACHED();
+    }
+
+    KeySym key_sym = XkbKeycodeToKeysym(display_, event->u.u.detail, 0, 0);
+    ui::KeyboardCode key_code = ui::KeyboardCodeFromXKeysym(key_sym);
+    keyboard_callback_.Run(type, key_code);
+  }
+}
+
+// static
+void UserInputMonitorLinux::Core::ProcessReply(XPointer self,
+                                               XRecordInterceptData* data) {
+  if (data->category == XRecordFromServer) {
+    xEvent* event = reinterpret_cast<xEvent*>(data->data);
+    reinterpret_cast<Core*>(self)->ProcessXEvent(event);
+  }
+  XRecordFreeData(data);
+}
+
+}  // namespace
+
+scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
+    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
+    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
+  return scoped_ptr<UserInputMonitor>(
+      new UserInputMonitorLinux(io_task_runner));
+}
+
+}  // namespace media
diff --git a/media/base/user_input_monitor_mac.mm b/media/base/user_input_monitor_mac.mm
new file mode 100644
index 0000000..4ffad42
--- /dev/null
+++ b/media/base/user_input_monitor_mac.mm
@@ -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 "media/base/user_input_monitor.h"
+
+namespace media {
+
+// TODO(jiayl): add the implementation.
+scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
+    const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner,
+    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
+  return scoped_ptr<UserInputMonitor>();
+}
+
+}  // namespace media
diff --git a/media/base/user_input_monitor_win.cc b/media/base/user_input_monitor_win.cc
new file mode 100644
index 0000000..4ffad42
--- /dev/null
+++ b/media/base/user_input_monitor_win.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 "media/base/user_input_monitor.h"
+
+namespace media {
+
+// TODO(jiayl): add the implementation.
+scoped_ptr<UserInputMonitor> UserInputMonitor::Create(
+    const scoped_refptr<base::SingleThreadTaskRunner>& input_task_runner,
+    const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
+  return scoped_ptr<UserInputMonitor>();
+}
+
+}  // namespace media
diff --git a/media/cast/DEPS b/media/cast/DEPS
new file mode 100644
index 0000000..e566fc7
--- /dev/null
+++ b/media/cast/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/webrtc",
+]
diff --git a/media/cast/OWNERS b/media/cast/OWNERS
new file mode 100644
index 0000000..c7233bd
--- /dev/null
+++ b/media/cast/OWNERS
@@ -0,0 +1 @@
+hclam@chromium.org
diff --git a/media/cast/README b/media/cast/README
new file mode 100644
index 0000000..4878967
--- /dev/null
+++ b/media/cast/README
@@ -0,0 +1,64 @@
+This directory contains a RTP/RTCP library used for the Cast mirroring
+protocol. This library is specifically built for low latency purposes and
+enables Chrome to send real-time video and audio streams. 
+
+CONTENTS
+
+cast/
+    Build rules and top level source files and headers.
+
+cast/audio_receiver/
+    Module for receiving and decodes audio RTP stream.
+
+cast/audio_sender/
+    Module for encoding and sending audio RTP stream.
+
+cast/congestion_control/
+    Bandwidth estimation and network congestion handling.
+
+cast/pacing/
+    Module for rate limiting data outflow.
+
+cast/rtcp/
+    Module for handling RTCP messages.
+
+cast/rtp_common/
+    Module for common code used for RTP messages.
+
+cast/rtp_receiver/
+    Module for reciving RTP messages.
+
+cast/rtp_sender/
+    Module for sending RTP messages.
+
+cast/test/
+    Module for test applications.
+
+cast/video_receiver/
+    Module for receiving and decodes video RTP stream.
+
+cast/video_sender/
+    Module for encoding and sending video RTP stream.
+
+DEPENDENCIES
+
+Content of this directory should only depend on:
+
+base/
+    Provides base libraries and platform independent layer.
+
+net/
+    Provides network capabilities.
+
+third_party/libvpx
+    Provides video encoder.
+
+third_party/opus
+    Provides audio encoder.
+
+third_party/webrtc
+    Provides audio signal processing.
+
+OWNERS
+
+See OWNERS for ownership.
diff --git a/media/cast/cast.gyp b/media/cast/cast.gyp
new file mode 100644
index 0000000..229a833
--- /dev/null
+++ b/media/cast/cast.gyp
@@ -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.
+
+{
+  'variables': {
+    'include_tests%': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'cast_config',
+      'type': 'static_library',
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [
+        'cast_config.h',
+        'cast_config.cc',
+      ], # source
+    },
+    {
+      'target_name': 'cast_sender',
+      'type': 'static_library',
+      'dependencies': [
+        'cast_config',
+        'cast_sender.gyp:cast_sender_impl',
+      ],
+    },
+    {
+      'target_name': 'cast_receiver',
+      'type': 'static_library',
+      'dependencies': [
+        'cast_config',
+        'cast_receiver.gyp:cast_receiver_impl',
+      ],
+    },
+  ],  # targets,
+  'conditions': [
+    ['include_tests==1', {
+      'targets': [
+        {
+          'target_name': 'cast_unittest',
+          'type': '<(gtest_target_type)',
+          'dependencies': [
+            'cast_sender',
+            'cast_receiver',
+            '../../base/base.gyp:run_all_unittests',
+            '<(DEPTH)/testing/gmock.gyp:gmock',
+            '<(DEPTH)/testing/gtest.gyp:gtest',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'congestion_control/congestion_control_unittest.cc',
+          ], # source
+        },
+      ],  # targets
+    }], # include_tests
+  ],
+}
diff --git a/media/cast/cast_config.cc b/media/cast/cast_config.cc
new file mode 100644
index 0000000..97c7073
--- /dev/null
+++ b/media/cast/cast_config.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 "media/cast/cast_config.h"
+
+namespace media {
+namespace cast {
+
+VideoSenderConfig::VideoSenderConfig()
+    : rtcp_interval(kDefaultRtcpIntervalMs),
+      rtcp_mode(kRtcpReducedSize),
+      rtp_history_ms(kDefaultRtpHistoryMs),
+      rtp_max_delay_ms(kDefaultRtpMaxDelayMs),
+      congestion_control_back_off(kDefaultCongestionControlBackOff),
+      max_qp(kDefaultMaxQp),
+      min_qp(kDefaultMinQp),
+      max_frame_rate(kDefaultMaxFrameRate),
+      max_number_of_video_buffers_used(kDefaultNumberOfVideoBuffers) {}
+
+AudioSenderConfig::AudioSenderConfig()
+    : rtcp_interval(kDefaultRtcpIntervalMs),
+      rtcp_mode(kRtcpReducedSize),
+      rtp_history_ms(kDefaultRtpHistoryMs),
+      rtp_max_delay_ms(kDefaultRtpMaxDelayMs) {}
+
+AudioReceiverConfig::AudioReceiverConfig()
+    : rtcp_interval(kDefaultRtcpIntervalMs),
+      rtcp_mode(kRtcpReducedSize),
+      rtp_max_delay_ms(kDefaultRtpMaxDelayMs) {}
+
+VideoReceiverConfig::VideoReceiverConfig()
+    : rtcp_interval(kDefaultRtcpIntervalMs),
+      rtcp_mode(kRtcpReducedSize),
+      rtp_max_delay_ms(kDefaultRtpMaxDelayMs),
+      max_frame_rate(kDefaultMaxFrameRate),
+      decoder_faster_than_max_frame_rate(true) {}
+
+EncodedVideoFrame::EncodedVideoFrame() {}
+EncodedVideoFrame::~EncodedVideoFrame() {}
+
+EncodedAudioFrame::EncodedAudioFrame() {}
+EncodedAudioFrame::~EncodedAudioFrame() {}
+
+PcmAudioFrame::PcmAudioFrame() {}
+PcmAudioFrame::~PcmAudioFrame() {}
+
+}  // namespace cast
+}  // namespace media
diff --git a/media/cast/cast_config.h b/media/cast/cast_config.h
new file mode 100644
index 0000000..e1280cd
--- /dev/null
+++ b/media/cast/cast_config.h
@@ -0,0 +1,217 @@
+// Copyright 2013 The Chromium Authors. 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_CAST_CONFIG_H_
+#define MEDIA_CAST_CAST_CONFIG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "media/cast/cast_defines.h"
+
+namespace media {
+namespace cast {
+
+enum RtcpMode {
+  kRtcpCompound,  // Compound RTCP mode is described by RFC 4585.
+  kRtcpReducedSize,  // Reduced-size RTCP mode is described by RFC 5506.
+};
+
+enum VideoCodec {
+  kVp8,
+  kH264,
+  kExternalVideo,
+};
+
+enum AudioCodec {
+  kOpus,
+  kPcm16,
+  kExternalAudio,
+};
+
+struct AudioSenderConfig {
+  AudioSenderConfig();
+
+  uint32 sender_ssrc;
+  uint32 incoming_feedback_ssrc;
+
+  int rtcp_interval;
+  std::string rtcp_c_name;
+  RtcpMode rtcp_mode;
+
+  int rtp_history_ms;  // The time RTP packets are stored for retransmissions.
+  int rtp_max_delay_ms;
+  int rtp_payload_type;
+
+  bool use_external_encoder;
+  int frequency;
+  int channels;
+  int bitrate;
+  AudioCodec codec;
+};
+
+struct VideoSenderConfig {
+  VideoSenderConfig();
+
+  uint32 sender_ssrc;
+  uint32 incoming_feedback_ssrc;
+
+  int rtcp_interval;
+  std::string rtcp_c_name;
+  RtcpMode rtcp_mode;
+
+  int rtp_history_ms;  // The time RTP packets are stored for retransmissions.
+  int rtp_max_delay_ms;
+  int rtp_payload_type;
+
+  bool use_external_encoder;
+  int width;  // Incoming frames will be scaled to this size.
+  int height;
+
+  float congestion_control_back_off;
+  int max_bitrate;
+  int min_bitrate;
+  int start_bitrate;
+  int max_qp;
+  int min_qp;
+  int max_frame_rate;
+  int max_number_of_video_buffers_used;  // Max value depend on codec.
+  VideoCodec codec;
+  int number_of_cores;
+};
+
+struct AudioReceiverConfig {
+  AudioReceiverConfig();
+
+  uint32 feedback_ssrc;
+  uint32 incoming_ssrc;
+
+  int rtcp_interval;
+  std::string rtcp_c_name;
+  RtcpMode rtcp_mode;
+
+  // The time the receiver is prepared to wait for retransmissions.
+  int rtp_max_delay_ms;
+  int rtp_payload_type;
+
+  bool use_external_decoder;
+  int frequency;
+  int channels;
+  AudioCodec codec;
+};
+
+struct VideoReceiverConfig {
+  VideoReceiverConfig();
+
+  uint32 feedback_ssrc;
+  uint32 incoming_ssrc;
+
+  int rtcp_interval;
+  std::string rtcp_c_name;
+  RtcpMode rtcp_mode;
+
+  // The time the receiver is prepared to wait for retransmissions.
+  int rtp_max_delay_ms;
+  int rtp_payload_type;
+
+  bool use_external_decoder;
+  int max_frame_rate;
+
+  // Some HW decoders can not run faster than the frame rate, preventing it
+  // from catching up after a glitch.
+  bool decoder_faster_than_max_frame_rate;
+  VideoCodec codec;
+};
+
+struct I420VideoPlane {
+  int stride;
+  int length;
+  uint8* data;
+};
+
+struct I420VideoFrame {
+  int width;
+  int height;
+  I420VideoPlane y_plane;
+  I420VideoPlane u_plane;
+  I420VideoPlane v_plane;
+};
+
+struct EncodedVideoFrame {
+  EncodedVideoFrame();
+  ~EncodedVideoFrame();
+
+  VideoCodec codec;
+  bool key_frame;
+  uint8 frame_id;
+  uint8 last_referenced_frame_id;
+  std::vector<uint8> data;
+};
+
+struct PcmAudioFrame {
+  PcmAudioFrame();
+  ~PcmAudioFrame();
+
+  int channels;  // Samples in interleaved stereo format. L0, R0, L1 ,R1 ,...
+  int frequency;
+  std::vector<int16> samples;
+};
+
+struct EncodedAudioFrame {
+  EncodedAudioFrame();
+  ~EncodedAudioFrame();
+
+  AudioCodec codec;
+  uint8 frame_id;  // Needed to release the frame. Not used send side.
+  int samples;  // Needed send side to advance the RTP timestamp.
+                // Not used receive side.
+  std::vector<uint8> data;
+};
+
+class PacketSender {
+ public:
+  // All packets to be sent to the network will be delivered via this function.
+  virtual bool SendPacket(const uint8* packet, int length) = 0;
+
+ protected:
+  virtual ~PacketSender() {}
+};
+
+class PacketReceiver {
+ public:
+  // All packets received from the network should be delivered via this
+  // function.
+  virtual void ReceivedPacket(const uint8* packet, int length) = 0;
+
+ protected:
+  virtual ~PacketReceiver() {}
+};
+
+class VideoEncoderController {
+ public:
+  // Inform the encoder about the new target bit rate.
+  virtual void SetBitRate(int new_bit_rate) = 0;
+
+  // Inform the encoder to not encode the next frame.
+  // Note: this setting is sticky and should last until called with false.
+  virtual void SkipNextFrame(bool skip_next_frame) = 0;
+
+  // Inform the encoder to encode the next frame as a key frame.
+  virtual void GenerateKeyFrame() = 0;
+
+  // Inform the encoder to only reference frames older or equal to frame_id;
+  virtual void LatestFrameIdToReference(uint8 frame_id) = 0;
+
+  // Query the codec about how many frames it has skipped due to slow ACK.
+  virtual int NumberOfSkippedFrames() const = 0;
+
+ protected:
+  virtual ~VideoEncoderController() {}
+};
+
+}  // namespace cast
+}  // namespace media
+
+#endif  // MEDIA_CAST_CAST_CONFIG_H_
diff --git a/media/cast/cast_defines.h b/media/cast/cast_defines.h
new file mode 100644
index 0000000..7239148
--- /dev/null
+++ b/media/cast/cast_defines.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 MEDIA_CAST_CAST_DEFINES_H_
+#define MEDIA_CAST_CAST_DEFINES_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/time/time.h"
+
+namespace media {
+namespace cast {
+
+const int64 kDontShowTimeoutMs = 33;
+const float kDefaultCongestionControlBackOff = 0.875f;
+const uint8 kStartFrameId = 255;
+const uint32 kVideoFrequency = 90000;
+const int64 kSkippedFramesCheckPeriodkMs = 10000;
+
+// Number of skipped frames threshold in fps (as configured) per period above.
+const int kSkippedFramesThreshold = 3;
+const size_t kIpPacketSize = 1500;
+const int kStartRttMs = 20;
+const int64 kCastMessageUpdateIntervalMs = 33;
+const int64 kNackRepeatIntervalMs = 30;
+
+enum DefaultSettings {
+  kDefaultMaxQp = 56,
+  kDefaultMinQp = 4,
+  kDefaultMaxFrameRate = 30,
+  kDefaultNumberOfVideoBuffers = 1,
+  kDefaultRtcpIntervalMs = 500,
+  kDefaultRtpHistoryMs = 1000,
+  kDefaultRtpMaxDelayMs = 100,
+};
+
+}  // namespace cast
+}  // namespace media
+
+#endif  // MEDIA_CAST_CAST_DEFINES_H_
diff --git a/media/cast/cast_receiver.gyp b/media/cast/cast_receiver.gyp
new file mode 100644
index 0000000..576f2d8
--- /dev/null
+++ b/media/cast/cast_receiver.gyp
@@ -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.
+
+{
+  'includes': [
+#    'audio_receiver/audio_receiver.gypi',
+#    'video_receiver/video_receiver.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'cast_receiver_impl',
+      'type': 'static_library',
+      'sources': [
+        'cast_receiver.h',
+#        'cast_receiver_impl.cc',
+#        'cast_receiver_impl.h',
+      ], # source
+      'dependencies': [
+#        'audio_receiver',
+#        'video_receiver',
+#        '<(DEPTH)/cast/pacing/paced_sender.gyp:*',
+      ],
+    },
+  ],
+}
diff --git a/media/cast/cast_receiver.h b/media/cast/cast_receiver.h
new file mode 100644
index 0000000..3dafbe5
--- /dev/null
+++ b/media/cast/cast_receiver.h
@@ -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.
+
+#ifndef MEDIA_CAST_CAST_RECEIVER_H_
+#define MEDIA_CAST_CAST_RECEIVER_H_
+
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "media/cast/cast_config.h"
+
+namespace media {
+namespace cast {
+
+class FrameReceiver {
+ public:
+  virtual bool GetRawVideoFrame(I420VideoFrame* video_frame,
+                                base::TimeTicks* render_time) = 0;
+
+  virtual bool GetEncodedVideoFrame(EncodedVideoFrame* video_frame,
+                                    base::TimeTicks* render_time) = 0;
+
+  virtual void ReleaseEncodedVideoFrame(uint8 frame_id) = 0;
+
+  virtual bool GetRawAudioFrame(int number_of_10ms_blocks,
+                                int desired_frequency,
+                                PcmAudioFrame* audio_frame,
+                                base::TimeTicks* playout_time) = 0;
+
+  virtual bool GetCodedAudioFrame(EncodedAudioFrame* audio_frame,
+                                  base::TimeTicks* playout_time) = 0;
+
+  virtual void ReleaseCodedAudioFrame(uint8 frame_id) = 0;
+
+protected:
+  virtual ~FrameReceiver() {}
+};
+
+class CastReceiver {
+ public:
+  static CastReceiver* CreateCastReceiver(
+      const AudioReceiverConfig& audio_config,
+      const VideoReceiverConfig& video_config,
+      PacketSender* const packet_sender);
+
+  // All received RTP and RTCP packets for the call should be inserted to this
+  // PacketReceiver. The PacketReceiver pointer is valid as long as the
+  // CastReceiver instance exists.
+  virtual PacketReceiver* packet_receiver() = 0;
+
+  // Polling interface to get audio and video frames from the CastReceiver.
+  virtual FrameReceiver* frame_receiver() = 0;
+
+  virtual ~CastReceiver() {};
+};
+
+}  // namespace cast
+}  // namespace media
+
+#endif  // MEDIA_CAST_CAST_RECEIVER_H_
diff --git a/media/cast/cast_sender.gyp b/media/cast/cast_sender.gyp
new file mode 100644
index 0000000..9bb37fe
--- /dev/null
+++ b/media/cast/cast_sender.gyp
@@ -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.
+
+{
+  'includes': [
+#    'audio_sender/audio_sender.gypi',
+    'congestion_control/congestion_control.gypi',
+#    'video_sender/video_sender.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'cast_sender_impl',
+      'type': 'static_library',
+      'sources': [
+        'cast_sender.h',
+#        'cast_sender_impl.cc',
+#        'cast_sender_impl.h',
+      ], # source
+      'dependencies': [
+#        '<(DEPTH)/media/cast/pacing/paced_sender.gyp:*',
+#        'audio_sender',
+        'congestion_control',
+#        'video_sender',
+      ], # dependencies
+    },
+  ],
+}
diff --git a/media/cast/cast_sender.h b/media/cast/cast_sender.h
new file mode 100644
index 0000000..b5a3bcb
--- /dev/null
+++ b/media/cast/cast_sender.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 MEDIA_CAST_CAST_SENDER_H_
+#define MEDIA_CAST_CAST_SENDER_H_
+
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "media/cast/cast_config.h"
+
+namespace media {
+namespace cast {
+
+class FrameInput {
+ public:
+  virtual void InsertRawVideoFrame(const I420VideoFrame& video_frame,
+                                   base::TimeTicks capture_time) = 0;
+
+  virtual void InsertCodedVideoFrame(const EncodedVideoFrame& video_frame,
+                                     base::TimeTicks capture_time) = 0;
+
+  virtual void InsertRawAudioFrame(const PcmAudioFrame& audio_frame,
+                                   base::TimeTicks recorded_time) = 0;
+
+  virtual void InsertCodedAudioFrame(const EncodedAudioFrame& audio_frame,
+                                     base::TimeTicks recorded_time) = 0;
+
+ protected:
+  virtual ~FrameInput() {}
+};
+
+class CastSender {
+ public:
+  static CastSender* CreateCastSender(
+      const AudioSenderConfig& audio_config,
+      const VideoSenderConfig& video_config,
+      VideoEncoderController* const video_encoder_controller,
+      PacketSender* const packet_sender);
+
+  virtual ~CastSender() {};
+
+  virtual FrameInput* frame_input() = 0;
+
+  // All RTCP packets for the call should be inserted to this
+  // PacketReceiver. The PacketReceiver pointer is valid as long as the
+  // CastSender instance exists.
+  virtual PacketReceiver* packet_receiver() = 0;
+};
+
+}  // namespace cast
+}  // namespace media
+
+#endif  // MEDIA_CAST_CAST_SENDER_H_
diff --git a/media/cast/congestion_control/congestion_control.cc b/media/cast/congestion_control/congestion_control.cc
new file mode 100644
index 0000000..68ba3b2
--- /dev/null
+++ b/media/cast/congestion_control/congestion_control.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/congestion_control/congestion_control.h"
+
+#include "base/logging.h"
+#include "media/cast/cast_config.h"
+#include "media/cast/cast_defines.h"
+
+namespace media {
+namespace cast {
+
+static const int64 kCongestionControlMinChangeIntervalMs = 10;
+static const int64 kCongestionControlMaxChangeIntervalMs = 100;
+
+// At 10 ms RTT TCP Reno would ramp 1500 * 8 * 100  = 1200 Kbit/s.
+// NACK is sent after a maximum of 10 ms.
+static const int kCongestionControlMaxBitrateIncreasePerMillisecond = 1200;
+
+static const int64 kMaxElapsedTimeMs = kCongestionControlMaxChangeIntervalMs;
+
+CongestionControl::CongestionControl(float congestion_control_back_off,
+                                     uint32 max_bitrate_configured,
+                                     uint32 min_bitrate_configured,
+                                     uint32 start_bitrate)
+    : congestion_control_back_off_(congestion_control_back_off),
+      max_bitrate_configured_(max_bitrate_configured),
+      min_bitrate_configured_(min_bitrate_configured),
+      bitrate_(start_bitrate),
+      testing_clock_(NULL) {
+  DCHECK_GT(congestion_control_back_off, 0.0f) << "Invalid config";
+  DCHECK_LT(congestion_control_back_off, 1.0f) << "Invalid config";
+  DCHECK_GE(max_bitrate_configured, min_bitrate_configured) << "Invalid config";
+  DCHECK_GE(max_bitrate_configured, start_bitrate) << "Invalid config";
+  DCHECK_GE(start_bitrate, min_bitrate_configured) << "Invalid config";
+}
+
+bool CongestionControl::OnAck(base::TimeDelta rtt, uint32* new_bitrate) {
+  base::TimeTicks now = testing_clock_ ?
+      testing_clock_->NowTicks() : base::TimeTicks::Now();
+
+  // First feedback?
+  if (time_last_increase_.is_null()) {
+    time_last_increase_ = now;
+    time_last_decrease_ = now;
+    return false;
+  }
+  // Are we at the max bitrate?
+  if (max_bitrate_configured_ == bitrate_)  return false;
+
+  // Make sure RTT is never less than 1 ms.
+  rtt = std::max(rtt, base::TimeDelta::FromMilliseconds(1));
+
+  base::TimeDelta elapsed_time = std::min(now - time_last_increase_,
+      base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs));
+  base::TimeDelta change_interval = std::max(rtt,
+      base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs));
+  change_interval = std::min(change_interval,
+      base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs));
+
+  // Have enough time have passed?
+  if (elapsed_time < change_interval)  return false;
+
+  time_last_increase_ = now;
+
+  // One packet per RTT multiplied by the elapsed time fraction.
+  // 1500 * 8 * (1000 / rtt_ms) * (elapsed_time_ms / 1000) =>
+  // 1500 * 8 * elapsed_time_ms / rtt_ms.
+  uint32 bitrate_increase = (1500 * 8 * elapsed_time.InMilliseconds()) /
+     rtt.InMilliseconds();
+  uint32 max_bitrate_increase =
+      kCongestionControlMaxBitrateIncreasePerMillisecond *
+          elapsed_time.InMilliseconds();
+  bitrate_increase = std::min(max_bitrate_increase, bitrate_increase);
+  *new_bitrate = std::min(bitrate_increase + bitrate_, max_bitrate_configured_);
+  bitrate_ = *new_bitrate;
+  return true;
+}
+
+bool CongestionControl::OnNack(base::TimeDelta rtt, uint32* new_bitrate) {
+  base::TimeTicks now = testing_clock_ ?
+      testing_clock_->NowTicks() : base::TimeTicks::Now();
+
+  // First feedback?
+  if (time_last_decrease_.is_null()) {
+    time_last_increase_ = now;
+    time_last_decrease_ = now;
+    return false;
+  }
+  base::TimeDelta elapsed_time = std::min(now - time_last_decrease_,
+      base::TimeDelta::FromMilliseconds(kMaxElapsedTimeMs));
+  base::TimeDelta change_interval = std::max(rtt,
+      base::TimeDelta::FromMilliseconds(kCongestionControlMinChangeIntervalMs));
+  change_interval = std::min(change_interval,
+      base::TimeDelta::FromMilliseconds(kCongestionControlMaxChangeIntervalMs));
+
+  // Have enough time have passed?
+  if (elapsed_time < change_interval)  return false;
+
+  time_last_decrease_ = now;
+  time_last_increase_ = now;
+
+  *new_bitrate = std::max(
+      static_cast<uint32>(bitrate_ * congestion_control_back_off_),
+      min_bitrate_configured_);
+
+  bitrate_ = *new_bitrate;
+  return true;
+}
+
+}  // namespace cast
+}  // namespace media
diff --git a/media/cast/congestion_control/congestion_control.gypi b/media/cast/congestion_control/congestion_control.gypi
new file mode 100644
index 0000000..d429623
--- /dev/null
+++ b/media/cast/congestion_control/congestion_control.gypi
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'congestion_control',
+      'type': 'static_library',
+      'include_dirs': [
+        '../../../',
+      ],
+      'sources': [
+        'congestion_control.h',
+        'congestion_control.cc',
+      ], # source
+      'dependencies': [
+        '../../base/base.gyp:base',
+        '../../base/base.gyp:test_support_base',
+      ],
+  },
+  ],
+}
+
diff --git a/media/cast/congestion_control/congestion_control.h b/media/cast/congestion_control/congestion_control.h
new file mode 100644
index 0000000..41c04fb
--- /dev/null
+++ b/media/cast/congestion_control/congestion_control.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 MEDIA_CAST_CONGESTION_CONTROL_CONGESTION_CONTROL_H_
+#define MEDIA_CAST_CONGESTION_CONTROL_CONGESTION_CONTROL_H_
+
+#include "base/basictypes.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
+
+namespace media {
+namespace cast {
+
+class CongestionControl {
+ public:
+  CongestionControl(float congestion_control_back_off,
+                    uint32 max_bitrate_configured,
+                    uint32 min_bitrate_configured,
+                    uint32 start_bitrate);
+
+  virtual ~CongestionControl() {}
+
+  // Don't call OnAck if the same message contain a NACK.
+  // Returns true if the bitrate have changed.
+  bool OnAck(base::TimeDelta rtt_ms, uint32* new_bitrate);
+
+  // Returns true if the bitrate have changed.
+  bool OnNack(base::TimeDelta rtt_ms, uint32* new_bitrate);
+
+  void set_testing_clock(base::SimpleTestTickClock* clock) {
+    testing_clock_ = clock;
+  }
+
+ private:
+  const float congestion_control_back_off_;
+  const uint32 max_bitrate_configured_;
+  const uint32 min_bitrate_configured_;
+  uint32 bitrate_;
+  base::TimeTicks time_last_increase_;
+  base::TimeTicks time_last_decrease_;
+
+  // Used only for helping test. Not owned and can be NULL.
+  base::SimpleTestTickClock* testing_clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(CongestionControl);
+};
+
+}  // namespace cast
+}  // namespace media
+
+#endif // MEDIA_CAST_CONGESTION_CONTROL_CONGESTION_CONTROL_H_
diff --git a/media/cast/congestion_control/congestion_control_unittest.cc b/media/cast/congestion_control/congestion_control_unittest.cc
new file mode 100644
index 0000000..f55a39a
--- /dev/null
+++ b/media/cast/congestion_control/congestion_control_unittest.cc
@@ -0,0 +1,139 @@
+// Copyright 2013 The Chromium Authors. 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/test/simple_test_tick_clock.h"
+#include "media/cast/cast_defines.h"
+#include "media/cast/congestion_control/congestion_control.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+namespace cast {
+
+static const uint32 kMaxBitrateConfigured = 5000000;
+static const uint32 kMinBitrateConfigured = 500000;
+static const uint32 kStartBitrate = 2000000;
+static const int64 kStartMillisecond = 123456789;
+static const int64 kRttMs = 20;
+static const int64 kAckRateMs = 33;
+static const int64 kNackRateMs = 10;
+
+class CongestionControlTest : public ::testing::Test {
+ protected:
+  CongestionControlTest()
+      : congestion_control_(kDefaultCongestionControlBackOff,
+                            kMaxBitrateConfigured,
+                            kMinBitrateConfigured,
+                            kStartBitrate) {
+    testing_clock_.Advance(
+        base::TimeDelta::FromMilliseconds(kStartMillisecond));
+    congestion_control_.set_testing_clock(&testing_clock_);
+  }
+
+  base::SimpleTestTickClock testing_clock_;
+  CongestionControl congestion_control_;
+};
+
+TEST_F(CongestionControlTest, Max) {
+  uint32 new_bitrate = 0;
+  base::TimeDelta rtt = base::TimeDelta::FromMilliseconds(kRttMs);
+  base::TimeDelta ack_rate = base::TimeDelta::FromMilliseconds(kAckRateMs);
+  EXPECT_FALSE(congestion_control_.OnAck(rtt, &new_bitrate));
+
+  uint32 expected_increase_bitrate = 0;
+
+  // Expected time is 5 seconds. 500000 - 2000000 = 5 * 1500 * 8 * (1000 / 20).
+  for (int i = 0; i < 151; ++i) {
+    testing_clock_.Advance(ack_rate);
+    EXPECT_TRUE(congestion_control_.OnAck(rtt, &new_bitrate));
+    expected_increase_bitrate += 1500 * 8 * kAckRateMs / kRttMs;
+    EXPECT_EQ(kStartBitrate + expected_increase_bitrate, new_bitrate);
+  }
+  testing_clock_.Advance(ack_rate);
+  EXPECT_TRUE(congestion_control_.OnAck(rtt, &new_bitrate));
+  EXPECT_EQ(kMaxBitrateConfigured, new_bitrate);
+}
+
+TEST_F(CongestionControlTest, Min) {
+  uint32 new_bitrate = 0;
+  base::TimeDelta rtt = base::TimeDelta::FromMilliseconds(kRttMs);
+  base::TimeDelta ack_rate = base::TimeDelta::FromMilliseconds(kAckRateMs);
+  EXPECT_FALSE(congestion_control_.OnNack(rtt, &new_bitrate));
+
+  uint32 expected_decrease_bitrate = kStartBitrate;
+
+  // Expected number is 10. 2000 * 0.875^10 <= 500.
+  for (int i = 0; i < 10; ++i) {
+    testing_clock_.Advance(ack_rate);
+     EXPECT_TRUE(congestion_control_.OnNack(rtt, &new_bitrate));
+     expected_decrease_bitrate = static_cast<uint32>(
+         expected_decrease_bitrate * kDefaultCongestionControlBackOff);
+     EXPECT_EQ(expected_decrease_bitrate, new_bitrate);
+   }
+   testing_clock_.Advance(ack_rate);
+   EXPECT_TRUE(congestion_control_.OnNack(rtt, &new_bitrate));
+   EXPECT_EQ(kMinBitrateConfigured, new_bitrate);
+}
+
+TEST_F(CongestionControlTest, Timing) {
+  base::TimeDelta rtt = base::TimeDelta::FromMilliseconds(kRttMs);
+  base::TimeDelta ack_rate = base::TimeDelta::FromMilliseconds(kAckRateMs);
+  uint32 new_bitrate = 0;
+  uint32 expected_bitrate = kStartBitrate;
+
+  EXPECT_FALSE(congestion_control_.OnAck(rtt, &new_bitrate));
+
+  testing_clock_.Advance(ack_rate);
+  EXPECT_TRUE(congestion_control_.OnAck(rtt, &new_bitrate));
+  expected_bitrate += 1500 * 8 * kAckRateMs / kRttMs;
+  EXPECT_EQ(expected_bitrate, new_bitrate);
+
+  // We should back immediately.
+  EXPECT_TRUE(congestion_control_.OnNack(rtt, &new_bitrate));
+  expected_bitrate = static_cast<uint32>(
+      expected_bitrate * kDefaultCongestionControlBackOff);
+  EXPECT_EQ(expected_bitrate, new_bitrate);
+
+  // Less than one RTT have passed don't back again.
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_FALSE(congestion_control_.OnNack(rtt, &new_bitrate));
+
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_TRUE(congestion_control_.OnNack(rtt, &new_bitrate));
+  expected_bitrate = static_cast<uint32>(
+      expected_bitrate * kDefaultCongestionControlBackOff);
+  EXPECT_EQ(expected_bitrate, new_bitrate);
+
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_FALSE(congestion_control_.OnAck(rtt, &new_bitrate));
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_TRUE(congestion_control_.OnAck(rtt, &new_bitrate));
+  expected_bitrate += 1500 * 8 * 20 / kRttMs;
+  EXPECT_EQ(expected_bitrate, new_bitrate);
+
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_FALSE(congestion_control_.OnAck(rtt, &new_bitrate));
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
+  EXPECT_TRUE(congestion_control_.OnAck(rtt, &new_bitrate));
+  expected_bitrate += 1500 * 8 * 20 / kRttMs;
+  EXPECT_EQ(expected_bitrate, new_bitrate);
+
+  // Test long elapsed time (300 ms).
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(300));
+  EXPECT_TRUE(congestion_control_.OnAck(rtt, &new_bitrate));
+  expected_bitrate += 1500 * 8 * 100 / kRttMs;
+  EXPECT_EQ(expected_bitrate, new_bitrate);
+
+  // Test many short elapsed time (1 ms).
+  for (int i = 0; i < 19; ++i) {
+    testing_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
+    EXPECT_FALSE(congestion_control_.OnAck(rtt, &new_bitrate));
+  }
+  testing_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
+  EXPECT_TRUE(congestion_control_.OnAck(rtt, &new_bitrate));
+  expected_bitrate += 1500 * 8 * 20 / kRttMs;
+  EXPECT_EQ(expected_bitrate, new_bitrate);
+}
+
+}  // namespace cast
+}  // namespace media
diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h
index 99e1cc2..ccd2aa5 100644
--- a/media/ffmpeg/ffmpeg_common.h
+++ b/media/ffmpeg/ffmpeg_common.h
@@ -95,7 +95,8 @@
                                                  int channels);
 
 // Converts FFmpeg's audio sample format to Chrome's SampleFormat.
-SampleFormat AVSampleFormatToSampleFormat(AVSampleFormat sample_format);
+MEDIA_EXPORT SampleFormat
+    AVSampleFormatToSampleFormat(AVSampleFormat sample_format);
 
 // Converts FFmpeg's pixel formats to its corresponding supported video format.
 VideoFrame::Format PixelFormatToVideoFormat(PixelFormat pixel_format);
diff --git a/media/ffmpeg/ffmpeg_common_unittest.cc b/media/ffmpeg/ffmpeg_common_unittest.cc
index 33ad46e..2fa61ac 100644
--- a/media/ffmpeg/ffmpeg_common_unittest.cc
+++ b/media/ffmpeg/ffmpeg_common_unittest.cc
@@ -79,4 +79,22 @@
   }
 }
 
+TEST_F(FFmpegCommonTest, VerifyFormatSizes) {
+  for (AVSampleFormat format = AV_SAMPLE_FMT_NONE;
+       format < AV_SAMPLE_FMT_NB;
+       format = static_cast<AVSampleFormat>(format + 1)) {
+    SampleFormat sample_format = AVSampleFormatToSampleFormat(format);
+    if (sample_format == kUnknownSampleFormat) {
+      // This format not supported, so skip it.
+      continue;
+    }
+
+    // Have FFMpeg compute the size of a buffer of 1 channel / 1 frame
+    // with 1 byte alignment to make sure the sizes match.
+    int single_buffer_size = av_samples_get_buffer_size(NULL, 1, 1, format, 1);
+    int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format);
+    EXPECT_EQ(bytes_per_channel, single_buffer_size);
+  }
+}
+
 }  // namespace media
diff --git a/media/ffmpeg/ffmpeg_regression_tests.cc b/media/ffmpeg/ffmpeg_regression_tests.cc
index 19f00f8..0b68fd0 100644
--- a/media/ffmpeg/ffmpeg_regression_tests.cc
+++ b/media/ffmpeg/ffmpeg_regression_tests.cc
@@ -152,6 +152,11 @@
 FFMPEG_TEST_CASE(Cr242786, "security/242786.webm", PIPELINE_OK,
                  PIPELINE_OK, kNullVideoHash,
                  "-1.72,-0.83,0.84,1.70,1.23,-0.53,");
+// Test for out-of-bounds access with slightly corrupt file (detection logic
+// thinks it's a MONO file, but actually contains STEREO audio).
+FFMPEG_TEST_CASE(Cr275590, "security/275590.m4a",
+                 DECODER_ERROR_NOT_SUPPORTED, DEMUXER_ERROR_COULD_NOT_OPEN,
+                 kNullVideoHash, kNullAudioHash);
 
 // General MP4 test cases.
 FFMPEG_TEST_CASE(MP4_0, "security/aac.10419.mp4", DEMUXER_ERROR_COULD_NOT_OPEN,
@@ -359,7 +364,7 @@
 TEST_P(FFmpegRegressionTest, BasicPlayback) {
   if (GetParam().init_status == PIPELINE_OK) {
     ASSERT_TRUE(Start(GetTestDataFilePath(GetParam().filename),
-                      GetParam().init_status, true));
+                      GetParam().init_status, kHashed));
     Play();
     ASSERT_EQ(WaitUntilEndedOrError(), GetParam().end_status);
     EXPECT_EQ(GetParam().video_md5, GetVideoHash());
@@ -374,7 +379,7 @@
     }
   } else {
     ASSERT_FALSE(Start(GetTestDataFilePath(GetParam().filename),
-                       GetParam().init_status, true));
+                       GetParam().init_status, kHashed));
     EXPECT_EQ(GetParam().video_md5, GetVideoHash());
     EXPECT_EQ(GetParam().audio_md5, GetAudioHash());
   }
diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc
index 7ce37ff..bf4acd1 100644
--- a/media/filters/audio_file_reader_unittest.cc
+++ b/media/filters/audio_file_reader_unittest.cc
@@ -110,7 +110,7 @@
           base::TimeDelta::FromMicroseconds(288414), 12719, 12719);
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 TEST_F(AudioFileReaderTest, MP3) {
   RunTest("sfx.mp3", "3.05,2.87,3.00,3.32,3.58,4.08,", 1, 44100,
           base::TimeDelta::FromMicroseconds(313470), 13824, 12719);
diff --git a/media/filters/blocking_url_protocol.cc b/media/filters/blocking_url_protocol.cc
index 68e883c..e50b677 100644
--- a/media/filters/blocking_url_protocol.cc
+++ b/media/filters/blocking_url_protocol.cc
@@ -67,7 +67,7 @@
 
 bool BlockingUrlProtocol::SetPosition(int64 position) {
   int64 file_size;
-  if ((data_source_->GetSize(&file_size) && position >= file_size) ||
+  if ((data_source_->GetSize(&file_size) && position > file_size) ||
       position < 0) {
     return false;
   }
diff --git a/media/filters/blocking_url_protocol_unittest.cc b/media/filters/blocking_url_protocol_unittest.cc
index 4886ba7..d8d1dfc 100644
--- a/media/filters/blocking_url_protocol_unittest.cc
+++ b/media/filters/blocking_url_protocol_unittest.cc
@@ -90,11 +90,14 @@
   EXPECT_TRUE(url_protocol_.GetPosition(&position));
 
   EXPECT_TRUE(url_protocol_.SetPosition(512));
-  EXPECT_FALSE(url_protocol_.SetPosition(size));
   EXPECT_FALSE(url_protocol_.SetPosition(size + 1));
   EXPECT_FALSE(url_protocol_.SetPosition(-1));
   EXPECT_TRUE(url_protocol_.GetPosition(&position));
   EXPECT_EQ(512, position);
+
+  EXPECT_TRUE(url_protocol_.SetPosition(size));
+  EXPECT_TRUE(url_protocol_.GetPosition(&position));
+  EXPECT_EQ(size, position);
 }
 
 TEST_F(BlockingUrlProtocolTest, GetSize) {
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index e3a84e6..7f88a61 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -2014,7 +2014,7 @@
 TEST_F(ChunkDemuxerTest, CodecPrefixMatching) {
   ChunkDemuxer::Status expected = ChunkDemuxer::kNotSupported;
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   expected = ChunkDemuxer::kOk;
 #endif
 
@@ -2029,7 +2029,7 @@
 TEST_F(ChunkDemuxerTest, CodecIDsThatAreNotRFC6381Compliant) {
   ChunkDemuxer::Status expected = ChunkDemuxer::kNotSupported;
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   expected = ChunkDemuxer::kOk;
 #endif
   const char* codec_ids[] = {
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index 34fc793..cce22b7 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -176,24 +176,38 @@
     return AVERROR(EINVAL);
 
   // Determine how big the buffer should be and allocate it. FFmpeg may adjust
-  // how big each channel data is in order to meet it's alignment policy, so
+  // how big each channel data is in order to meet the alignment policy, so
   // we need to take this into consideration.
   int buffer_size_in_bytes =
-      av_samples_get_buffer_size(NULL, channels, frame->nb_samples, format, 1);
+      av_samples_get_buffer_size(&frame->linesize[0],
+                                 channels,
+                                 frame->nb_samples,
+                                 format,
+                                 AudioBuffer::kChannelAlignment);
   int frames_required = buffer_size_in_bytes / bytes_per_channel / channels;
   DCHECK_GE(frames_required, frame->nb_samples);
   scoped_refptr<AudioBuffer> buffer =
       AudioBuffer::CreateBuffer(sample_format, channels, frames_required);
 
-  // Initialize the data[], linesize[], and extended_data[] fields.
-  int ret = avcodec_fill_audio_frame(frame,
-                                     channels,
-                                     format,
-                                     buffer->writable_data(),
-                                     buffer_size_in_bytes,
-                                     1);
-  if (ret < 0)
-    return ret;
+  // Initialize the data[] and extended_data[] fields to point into the memory
+  // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved
+  // audio and equal to |channels| for planar audio.
+  int number_of_planes = buffer->channel_data().size();
+  if (number_of_planes <= AV_NUM_DATA_POINTERS) {
+    DCHECK_EQ(frame->extended_data, frame->data);
+    for (int i = 0; i < number_of_planes; ++i)
+      frame->data[i] = buffer->channel_data()[i];
+  } else {
+    // There are more channels than can fit into data[], so allocate
+    // extended_data[] and fill appropriately.
+    frame->extended_data = static_cast<uint8**>(
+        av_malloc(number_of_planes * sizeof(*frame->extended_data)));
+    int i = 0;
+    for (; i < AV_NUM_DATA_POINTERS; ++i)
+      frame->extended_data[i] = frame->data[i] = buffer->channel_data()[i];
+    for (; i < number_of_planes; ++i)
+      frame->extended_data[i] = buffer->channel_data()[i];
+  }
 
   // Now create an AVBufferRef for the data just allocated. It will own the
   // reference to the AudioBuffer object.
@@ -360,6 +374,13 @@
 
   // Store initial values to guard against midstream configuration changes.
   channels_ = codec_context_->channels;
+  if (channels_ != ChannelLayoutToChannelCount(channel_layout_)) {
+    DLOG(ERROR) << "Audio configuration specified "
+                << ChannelLayoutToChannelCount(channel_layout_)
+                << " channels, but FFmpeg thinks the file contains "
+                << channels_ << " channels";
+    return false;
+  }
   av_sample_format_ = codec_context_->sample_fmt;
   sample_format_ = AVSampleFormatToSampleFormat(
       static_cast<AVSampleFormat>(av_sample_format_));
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 14b1fff..e95dcef 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -316,12 +316,7 @@
   data_source_->Stop(BindToCurrentLoop(base::Bind(
       &FFmpegDemuxer::OnDataSourceStopped, weak_this_,
       BindToCurrentLoop(callback))));
-
-  // TODO(scherkus): Reenable after figuring why Stop() gets called multiple
-  // times, see http://crbug.com/235933
-#if 0
   data_source_ = NULL;
-#endif
 }
 
 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
@@ -476,7 +471,7 @@
 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
                                          int result) {
   DCHECK(message_loop_->BelongsToCurrentThread());
-  if (!blocking_thread_.IsRunning()) {
+  if (!blocking_thread_.IsRunning() || !data_source_) {
     status_cb.Run(PIPELINE_ERROR_ABORT);
     return;
   }
@@ -595,8 +590,11 @@
 
     media_log_->SetStringProperty("audio_sample_format", sample_name);
 
-    media_log_->SetStringProperty("audio_codec_name",
-                                  audio_codec->codec_name);
+    AVCodec* codec = avcodec_find_decoder(audio_codec->codec_id);
+    if (codec) {
+      media_log_->SetStringProperty("audio_codec_name", codec->name);
+    }
+
     media_log_->SetIntegerProperty("audio_sample_rate",
                                    audio_codec->sample_rate);
     media_log_->SetIntegerProperty("audio_channels_count",
@@ -611,7 +609,12 @@
   if (video_stream) {
     AVCodecContext* video_codec = video_stream->codec;
     media_log_->SetBooleanProperty("found_video_stream", true);
-    media_log_->SetStringProperty("video_codec_name", video_codec->codec_name);
+
+    AVCodec* codec = avcodec_find_decoder(video_codec->codec_id);
+    if (codec) {
+      media_log_->SetStringProperty("video_codec_name", codec->name);
+    }
+
     media_log_->SetIntegerProperty("width", video_codec->width);
     media_log_->SetIntegerProperty("height", video_codec->height);
     media_log_->SetIntegerProperty("coded_width",
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index c1da0cc..4fa2ab2 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -433,7 +433,9 @@
   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
   ASSERT_TRUE(audio);
 
-  demuxer_->Stop(NewExpectedClosure());
+  WaitableMessageLoopEvent event;
+  demuxer_->Stop(event.GetClosure());
+  event.RunAndWait();
 
   // Reads after being stopped are all EOS buffers.
   StrictMock<MockReadCB> callback;
@@ -442,6 +444,9 @@
   // Attempt the read...
   audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback)));
   message_loop_.RunUntilIdle();
+
+  // Don't let the test call Stop() again.
+  demuxer_.reset();
 }
 
 TEST_F(FFmpegDemuxerTest, DisableAudioStream) {
diff --git a/media/filters/gpu_video_accelerator_factories.cc b/media/filters/gpu_video_accelerator_factories.cc
new file mode 100644
index 0000000..f9f5660
--- /dev/null
+++ b/media/filters/gpu_video_accelerator_factories.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 "media/filters/gpu_video_accelerator_factories.h"
+
+namespace media {
+
+GpuVideoAcceleratorFactories::~GpuVideoAcceleratorFactories() {}
+
+}  // namespace media
diff --git a/media/filters/gpu_video_accelerator_factories.h b/media/filters/gpu_video_accelerator_factories.h
new file mode 100644
index 0000000..3ee79ac
--- /dev/null
+++ b/media/filters/gpu_video_accelerator_factories.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 MEDIA_FILTERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
+#define MEDIA_FILTERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "media/video/video_decode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
+
+namespace base {
+class MessageLoopProxy;
+class SharedMemory;
+}
+
+class SkBitmap;
+
+namespace media {
+
+// Helper interface for specifying factories needed to instantiate a hardware
+// video accelerator.
+class MEDIA_EXPORT GpuVideoAcceleratorFactories
+    : public base::RefCountedThreadSafe<GpuVideoAcceleratorFactories> {
+ public:
+  // Caller owns returned pointer.
+  virtual scoped_ptr<VideoDecodeAccelerator> CreateVideoDecodeAccelerator(
+      VideoCodecProfile profile,
+      VideoDecodeAccelerator::Client* client) = 0;
+
+  // Caller owns returned pointer.
+  virtual scoped_ptr<VideoEncodeAccelerator> CreateVideoEncodeAccelerator(
+      VideoEncodeAccelerator::Client* client) = 0;
+
+  // Allocate & delete native textures.
+  virtual uint32 CreateTextures(int32 count,
+                                const gfx::Size& size,
+                                std::vector<uint32>* texture_ids,
+                                std::vector<gpu::Mailbox>* texture_mailboxes,
+                                uint32 texture_target) = 0;
+  virtual void DeleteTexture(uint32 texture_id) = 0;
+
+  virtual void WaitSyncPoint(uint32 sync_point) = 0;
+
+  // Read pixels from a native texture and store into |pixels| as RGBA.
+  virtual void ReadPixels(uint32 texture_id,
+                          uint32 texture_target,
+                          const gfx::Size& size,
+                          const SkBitmap& pixels) = 0;
+
+  // Allocate & return a shared memory segment.  Caller is responsible for
+  // Close()ing the returned pointer.
+  virtual base::SharedMemory* CreateSharedMemory(size_t size) = 0;
+
+  // Returns the message loop the video accelerator runs on.
+  virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() = 0;
+
+  // Abort any outstanding factory operations and error any future
+  // attempts at factory operations
+  virtual void Abort() = 0;
+
+  // Returns true if Abort() has been called.
+  virtual bool IsAborted() = 0;
+
+ protected:
+  friend class base::RefCountedThreadSafe<GpuVideoAcceleratorFactories>;
+  virtual ~GpuVideoAcceleratorFactories();
+};
+
+}  // namespace media
+
+#endif  // MEDIA_FILTERS_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 30c6dfa..273542e 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -14,10 +14,11 @@
 #include "base/task_runner_util.h"
 #include "media/base/bind_to_loop.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_log.h"
 #include "media/base/pipeline.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/video_decoder_config.h"
-#include "media/filters/gpu_video_decoder_factories.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
 
 namespace media {
 
@@ -52,12 +53,14 @@
 GpuVideoDecoder::BufferData::~BufferData() {}
 
 GpuVideoDecoder::GpuVideoDecoder(
-    const scoped_refptr<GpuVideoDecoderFactories>& factories)
+    const scoped_refptr<GpuVideoAcceleratorFactories>& factories,
+    const scoped_refptr<MediaLog>& media_log)
     : needs_bitstream_conversion_(false),
       gvd_loop_proxy_(factories->GetMessageLoop()),
       weak_factory_(this),
       factories_(factories),
       state_(kNormal),
+      media_log_(media_log),
       decoder_texture_target_(0),
       next_picture_buffer_id_(0),
       next_bitstream_buffer_id_(0),
@@ -137,7 +140,7 @@
       BindToCurrentLoop(orig_status_cb));
 
   bool previously_initialized = config_.IsValidConfig();
-#if !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_WIN)
   if (previously_initialized) {
     // TODO(xhwang): Make GpuVideoDecoder reinitializable.
     // See http://crbug.com/233608
@@ -173,13 +176,15 @@
     return;
   }
 
-  vda_.reset(factories_->CreateVideoDecodeAccelerator(config.profile(), this));
+  vda_ =
+      factories_->CreateVideoDecodeAccelerator(config.profile(), this).Pass();
   if (!vda_) {
     status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
     return;
   }
 
   DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded.";
+  media_log_->SetStringProperty("video_decoder", "gpu");
   status_cb.Run(PIPELINE_OK);
 }
 
@@ -245,6 +250,11 @@
     if (state_ == kNormal) {
       state_ = kDrainingDecoder;
       vda_->Flush();
+      // If we have ready frames, go ahead and process them to ensure that the
+      // Flush operation does not block in the VDA due to lack of picture
+      // buffers.
+      if (!ready_video_frames_.empty())
+        EnqueueFrameAndTriggerFrameDelivery(NULL);
     }
     return;
   }
@@ -435,7 +445,7 @@
       visible_rect,
       natural_size,
       timestamp,
-      base::Bind(&GpuVideoDecoderFactories::ReadPixels,
+      base::Bind(&GpuVideoAcceleratorFactories::ReadPixels,
                  factories_,
                  pb.texture_id(),
                  decoder_texture_target_,
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h
index 29c330d..f7fff52 100644
--- a/media/filters/gpu_video_decoder.h
+++ b/media/filters/gpu_video_decoder.h
@@ -26,7 +26,8 @@
 namespace media {
 
 class DecoderBuffer;
-class GpuVideoDecoderFactories;
+class GpuVideoAcceleratorFactories;
+class MediaLog;
 
 // GPU-accelerated video decoder implementation.  Relies on
 // AcceleratedVideoDecoderMsg_Decode and friends.
@@ -36,7 +37,8 @@
  public:
   // The message loop of |factories| will be saved to |gvd_loop_proxy_|.
   explicit GpuVideoDecoder(
-      const scoped_refptr<GpuVideoDecoderFactories>& factories);
+      const scoped_refptr<GpuVideoAcceleratorFactories>& factories,
+      const scoped_refptr<MediaLog>& media_log);
 
   // VideoDecoder implementation.
   virtual void Initialize(const VideoDecoderConfig& config,
@@ -117,7 +119,7 @@
   base::WeakPtrFactory<GpuVideoDecoder> weak_factory_;
   base::WeakPtr<GpuVideoDecoder> weak_this_;
 
-  scoped_refptr<GpuVideoDecoderFactories> factories_;
+  scoped_refptr<GpuVideoAcceleratorFactories> factories_;
 
   // Populated during Initialize() (on success) and unchanged until an error
   // occurs.
@@ -137,6 +139,8 @@
   // steady-state of the decoder.
   std::vector<SHMBuffer*> available_shm_segments_;
 
+  scoped_refptr<MediaLog> media_log_;
+
   // Book-keeping variables.
   struct BufferPair {
     BufferPair(SHMBuffer* s, const scoped_refptr<DecoderBuffer>& b);
diff --git a/media/filters/gpu_video_decoder_factories.cc b/media/filters/gpu_video_decoder_factories.cc
deleted file mode 100644
index 67d24ce..0000000
--- a/media/filters/gpu_video_decoder_factories.cc
+++ /dev/null
@@ -1,11 +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 "media/filters/gpu_video_decoder_factories.h"
-
-namespace media {
-
-GpuVideoDecoderFactories::~GpuVideoDecoderFactories() {}
-
-}  // namespace media
diff --git a/media/filters/gpu_video_decoder_factories.h b/media/filters/gpu_video_decoder_factories.h
deleted file mode 100644
index 107e2de..0000000
--- a/media/filters/gpu_video_decoder_factories.h
+++ /dev/null
@@ -1,67 +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 MEDIA_FILTERS_GPU_VIDEO_DECODER_FACTORIES_H_
-#define MEDIA_FILTERS_GPU_VIDEO_DECODER_FACTORIES_H_
-
-#include "base/memory/ref_counted.h"
-#include "media/video/video_decode_accelerator.h"
-
-namespace base {
-class MessageLoopProxy;
-class SharedMemory;
-}
-
-class SkBitmap;
-
-namespace media {
-
-// Helper interface for specifying factories needed to instantiate a hardware
-// video decoder.
-class MEDIA_EXPORT GpuVideoDecoderFactories
-    : public base::RefCountedThreadSafe<GpuVideoDecoderFactories> {
- public:
-  // Caller owns returned pointer.
-  virtual VideoDecodeAccelerator* CreateVideoDecodeAccelerator(
-      VideoCodecProfile profile,
-      VideoDecodeAccelerator::Client* client) = 0;
-
-  // Allocate & delete native textures.
-  virtual uint32 CreateTextures(int32 count,
-                                const gfx::Size& size,
-                                std::vector<uint32>* texture_ids,
-                                std::vector<gpu::Mailbox>* texture_mailboxes,
-                                uint32 texture_target) = 0;
-  virtual void DeleteTexture(uint32 texture_id) = 0;
-
-  virtual void WaitSyncPoint(uint32 sync_point) = 0;
-
-  // Read pixels from a native texture and store into |pixels| as RGBA.
-  virtual void ReadPixels(uint32 texture_id,
-                          uint32 texture_target,
-                          const gfx::Size& size,
-                          const SkBitmap& pixels) = 0;
-
-  // Allocate & return a shared memory segment.  Caller is responsible for
-  // Close()ing the returned pointer.
-  virtual base::SharedMemory* CreateSharedMemory(size_t size) = 0;
-
-  // Returns the message loop the VideoDecodeAccelerator runs on.
-  virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() = 0;
-
-  // Abort any outstanding factory operations and error any future
-  // attempts at factory operations
-  virtual void Abort() = 0;
-
-  // Returns true if Abort() has been called.
-  virtual bool IsAborted() = 0;
-
- protected:
-  friend class base::RefCountedThreadSafe<GpuVideoDecoderFactories>;
-  virtual ~GpuVideoDecoderFactories();
-};
-
-}  // namespace media
-
-#endif  // MEDIA_FILTERS_GPU_VIDEO_DECODER_FACTORIES_H_
diff --git a/media/filters/in_memory_url_protocol.cc b/media/filters/in_memory_url_protocol.cc
index c55438c..85fa290 100644
--- a/media/filters/in_memory_url_protocol.cc
+++ b/media/filters/in_memory_url_protocol.cc
@@ -35,7 +35,7 @@
 }
 
 bool InMemoryUrlProtocol::SetPosition(int64 position) {
-  if (position < 0 || position >= size_)
+  if (position < 0 || position > size_)
     return false;
   position_ = position;
   return true;
diff --git a/media/filters/mock_gpu_video_accelerator_factories.cc b/media/filters/mock_gpu_video_accelerator_factories.cc
new file mode 100644
index 0000000..f4f3997
--- /dev/null
+++ b/media/filters/mock_gpu_video_accelerator_factories.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 "media/filters/mock_gpu_video_accelerator_factories.h"
+
+namespace media {
+
+MockGpuVideoAcceleratorFactories::MockGpuVideoAcceleratorFactories() {}
+
+MockGpuVideoAcceleratorFactories::~MockGpuVideoAcceleratorFactories() {}
+
+scoped_ptr<VideoDecodeAccelerator>
+MockGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator(
+    VideoCodecProfile profile,
+    VideoDecodeAccelerator::Client* client) {
+  return scoped_ptr<VideoDecodeAccelerator>(
+      DoCreateVideoDecodeAccelerator(profile, client));
+}
+
+scoped_ptr<VideoEncodeAccelerator>
+MockGpuVideoAcceleratorFactories::CreateVideoEncodeAccelerator(
+    VideoEncodeAccelerator::Client* client) {
+  return scoped_ptr<VideoEncodeAccelerator>(
+      DoCreateVideoEncodeAccelerator(client));
+}
+
+}  // namespace media
diff --git a/media/filters/mock_gpu_video_accelerator_factories.h b/media/filters/mock_gpu_video_accelerator_factories.h
new file mode 100644
index 0000000..8aa432d
--- /dev/null
+++ b/media/filters/mock_gpu_video_accelerator_factories.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 MEDIA_FILTERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
+#define MEDIA_FILTERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "media/filters/gpu_video_accelerator_factories.h"
+#include "media/video/video_decode_accelerator.h"
+#include "media/video/video_encode_accelerator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+template <class T>
+class scoped_refptr;
+
+namespace base {
+class SharedMemory;
+}
+
+namespace media {
+
+class MockGpuVideoAcceleratorFactories : public GpuVideoAcceleratorFactories {
+ public:
+  MockGpuVideoAcceleratorFactories();
+
+  // CreateVideo{Decode,Encode}Accelerator returns scoped_ptr, which the mocking
+  // framework does not want.  Trampoline them.
+  MOCK_METHOD2(DoCreateVideoDecodeAccelerator,
+               VideoDecodeAccelerator*(VideoCodecProfile,
+                                       VideoDecodeAccelerator::Client*));
+  MOCK_METHOD1(DoCreateVideoEncodeAccelerator,
+               VideoEncodeAccelerator*(VideoEncodeAccelerator::Client*));
+
+  MOCK_METHOD5(CreateTextures,
+               uint32(int32 count,
+                      const gfx::Size& size,
+                      std::vector<uint32>* texture_ids,
+                      std::vector<gpu::Mailbox>* texture_mailboxes,
+                      uint32 texture_target));
+  MOCK_METHOD1(DeleteTexture, void(uint32 texture_id));
+  MOCK_METHOD1(WaitSyncPoint, void(uint32 sync_point));
+  MOCK_METHOD4(ReadPixels,
+               void(uint32 texture_id,
+                    uint32 texture_target,
+                    const gfx::Size& size,
+                    const SkBitmap& pixels));
+  MOCK_METHOD1(CreateSharedMemory, base::SharedMemory*(size_t size));
+  MOCK_METHOD0(GetMessageLoop, scoped_refptr<base::MessageLoopProxy>());
+  MOCK_METHOD0(Abort, void());
+  MOCK_METHOD0(IsAborted, bool());
+
+  virtual scoped_ptr<VideoDecodeAccelerator> CreateVideoDecodeAccelerator(
+      VideoCodecProfile profile,
+      VideoDecodeAccelerator::Client* client) OVERRIDE;
+
+  virtual scoped_ptr<VideoEncodeAccelerator> CreateVideoEncodeAccelerator(
+      VideoEncodeAccelerator::Client* client) OVERRIDE;
+
+ private:
+  virtual ~MockGpuVideoAcceleratorFactories();
+
+  DISALLOW_COPY_AND_ASSIGN(MockGpuVideoAcceleratorFactories);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_FILTERS_MOCK_GPU_VIDEO_ACCELERATOR_FACTORIES_H_
diff --git a/media/filters/mock_gpu_video_decoder_factories.cc b/media/filters/mock_gpu_video_decoder_factories.cc
deleted file mode 100644
index 9a16a80..0000000
--- a/media/filters/mock_gpu_video_decoder_factories.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 "media/filters/mock_gpu_video_decoder_factories.h"
-
-namespace media {
-
-MockGpuVideoDecoderFactories::MockGpuVideoDecoderFactories() {}
-
-MockGpuVideoDecoderFactories::~MockGpuVideoDecoderFactories() {}
-
-}  // namespace media
diff --git a/media/filters/mock_gpu_video_decoder_factories.h b/media/filters/mock_gpu_video_decoder_factories.h
deleted file mode 100644
index e0ad274..0000000
--- a/media/filters/mock_gpu_video_decoder_factories.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 MEDIA_FILTERS_MOCK_GPU_VIDEO_DECODER_FACTORIES_H_
-#define MEDIA_FILTERS_MOCK_GPU_VIDEO_DECODER_FACTORIES_H_
-
-#include "base/message_loop/message_loop_proxy.h"
-#include "media/filters/gpu_video_decoder_factories.h"
-#include "media/video/video_decode_accelerator.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-template <class T>
-class scoped_refptr;
-
-namespace base {
-class SharedMemory;
-}
-
-namespace media {
-
-class MockGpuVideoDecoderFactories : public GpuVideoDecoderFactories {
- public:
-  MockGpuVideoDecoderFactories();
-  MOCK_METHOD2(CreateVideoDecodeAccelerator,
-               VideoDecodeAccelerator*(VideoCodecProfile,
-                                       VideoDecodeAccelerator::Client*));
-  MOCK_METHOD5(CreateTextures,
-               uint32(int32 count,
-                      const gfx::Size& size,
-                      std::vector<uint32>* texture_ids,
-                      std::vector<gpu::Mailbox>* texture_mailboxes,
-                      uint32 texture_target));
-  MOCK_METHOD1(DeleteTexture, void(uint32 texture_id));
-  MOCK_METHOD1(WaitSyncPoint, void(uint32 sync_point));
-  MOCK_METHOD4(ReadPixels,
-               void(uint32 texture_id,
-                    uint32 texture_target,
-                    const gfx::Size& size,
-                    const SkBitmap& pixels));
-  MOCK_METHOD1(CreateSharedMemory, base::SharedMemory*(size_t size));
-  MOCK_METHOD0(GetMessageLoop, scoped_refptr<base::MessageLoopProxy>());
-  MOCK_METHOD0(Abort, void());
-  MOCK_METHOD0(IsAborted, bool());
-
- private:
-  virtual ~MockGpuVideoDecoderFactories();
-
-  DISALLOW_COPY_AND_ASSIGN(MockGpuVideoDecoderFactories);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_FILTERS_MOCK_GPU_VIDEO_DECODER_FACTORIES_H_
diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc
index 26f65b9..fe5ab5c 100644
--- a/media/filters/pipeline_integration_test.cc
+++ b/media/filters/pipeline_integration_test.cc
@@ -5,6 +5,7 @@
 #include "media/filters/pipeline_integration_test_base.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
@@ -58,6 +59,9 @@
 static const int kVP9WebMFileDurationMs = 2735;
 static const int kVP8AWebMFileDurationMs = 2700;
 
+// Command line switch for runtime adjustment of audio file to be benchmarked.
+static const char kBenchmarkAudioFile[] = "benchmark-audio-file";
+
 // Note: Tests using this class only exercise the DecryptingDemuxerStream path.
 // They do not exercise the Decrypting{Audio|Video}Decoder path.
 class FakeEncryptedMedia {
@@ -403,8 +407,8 @@
 }
 
 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {
-  ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"),
-                    PIPELINE_OK, true));
+  ASSERT_TRUE(Start(
+      GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK, kHashed));
 
   Play();
 
@@ -414,8 +418,31 @@
   EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
 }
 
+TEST_F(PipelineIntegrationTest, AudioPlaybackBenchmark) {
+  // Audio-only files are all that is allowed for clockless playback.
+  // Audio file can be specified on the command line
+  // (--benchmark-audio-file=id3_png_test.mp3), so check for it.
+  std::string filename(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+      kBenchmarkAudioFile));
+  if (filename.empty())
+    filename = "sfx_f32le.wav";
+
+  ASSERT_TRUE(Start(GetTestDataFilePath(filename), PIPELINE_OK, kClockless));
+
+  Play();
+
+  ASSERT_TRUE(WaitUntilOnEnded());
+
+  // Call Stop() to ensure that the rendering is complete.
+  Stop();
+  printf("Clockless playback of %s took %.2f ms.\n",
+         filename.c_str(),
+         GetAudioTime().InMillisecondsF());
+}
+
 TEST_F(PipelineIntegrationTest, F32PlaybackHashed) {
-  ASSERT_TRUE(Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK, true));
+  ASSERT_TRUE(
+      Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK, kHashed));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
   EXPECT_EQ(std::string(kNullVideoHash), GetVideoHash());
@@ -601,7 +628,7 @@
   source.Abort();
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) {
   MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile);
   StartPipelineWithMediaSource(&source);
@@ -777,7 +804,7 @@
   Stop();
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_VideoOnly) {
   MockMediaSource source("bear-1280x720-v_frag-cenc.mp4",
                          kMP4Video, kAppendWholeFile);
diff --git a/media/filters/pipeline_integration_test_base.cc b/media/filters/pipeline_integration_test_base.cc
index e2567ad..31ae8ad 100644
--- a/media/filters/pipeline_integration_test_base.cc
+++ b/media/filters/pipeline_integration_test_base.cc
@@ -26,6 +26,7 @@
 
 PipelineIntegrationTestBase::PipelineIntegrationTestBase()
     : hashing_enabled_(false),
+      clockless_playback_(false),
       pipeline_(new Pipeline(message_loop_.message_loop_proxy(),
                              new MediaLog())),
       ended_(false),
@@ -120,8 +121,9 @@
 
 bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path,
                                         PipelineStatus expected_status,
-                                        bool hashing_enabled) {
-  hashing_enabled_ = hashing_enabled;
+                                        kTestType test_type) {
+  hashing_enabled_ = test_type == kHashed;
+  clockless_playback_ = test_type == kClockless;
   return Start(file_path, expected_status);
 }
 
@@ -229,26 +231,32 @@
   scoped_ptr<FilterCollection> collection(new FilterCollection());
   collection->SetDemuxer(demuxer_.get());
 
-  ScopedVector<VideoDecoder> video_decoders;
-  video_decoders.push_back(
-      new VpxVideoDecoder(message_loop_.message_loop_proxy()));
-  video_decoders.push_back(
-      new FFmpegVideoDecoder(message_loop_.message_loop_proxy()));
+  if (!clockless_playback_) {
+    ScopedVector<VideoDecoder> video_decoders;
+    video_decoders.push_back(
+        new VpxVideoDecoder(message_loop_.message_loop_proxy()));
+    video_decoders.push_back(
+        new FFmpegVideoDecoder(message_loop_.message_loop_proxy()));
 
-  // Disable frame dropping if hashing is enabled.
-  scoped_ptr<VideoRenderer> renderer(new VideoRendererBase(
-      message_loop_.message_loop_proxy(),
-      video_decoders.Pass(),
-      base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
-                 base::Unretained(this), decryptor),
-      base::Bind(&PipelineIntegrationTestBase::OnVideoRendererPaint,
-                 base::Unretained(this)),
-      base::Bind(&PipelineIntegrationTestBase::OnSetOpaque,
-                 base::Unretained(this)),
-      !hashing_enabled_));
-  collection->SetVideoRenderer(renderer.Pass());
+    // Disable frame dropping if hashing is enabled.
+    scoped_ptr<VideoRenderer> renderer(new VideoRendererBase(
+        message_loop_.message_loop_proxy(),
+        video_decoders.Pass(),
+        base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
+                   base::Unretained(this),
+                   decryptor),
+        base::Bind(&PipelineIntegrationTestBase::OnVideoRendererPaint,
+                   base::Unretained(this)),
+        base::Bind(&PipelineIntegrationTestBase::OnSetOpaque,
+                   base::Unretained(this)),
+        !hashing_enabled_));
+    collection->SetVideoRenderer(renderer.Pass());
 
-  audio_sink_ = new NullAudioSink(message_loop_.message_loop_proxy());
+    audio_sink_ = new NullAudioSink(message_loop_.message_loop_proxy());
+  } else {
+    // audio only for clockless_playback_
+    clockless_audio_sink_ = new ClocklessAudioSink();
+  }
 
   ScopedVector<AudioDecoder> audio_decoders;
   audio_decoders.push_back(
@@ -258,7 +266,9 @@
 
   AudioRendererImpl* audio_renderer_impl = new AudioRendererImpl(
       message_loop_.message_loop_proxy(),
-      audio_sink_.get(),
+      (clockless_playback_)
+          ? static_cast<AudioRendererSink*>(clockless_audio_sink_.get())
+          : audio_sink_.get(),
       audio_decoders.Pass(),
       base::Bind(&PipelineIntegrationTestBase::SetDecryptor,
                  base::Unretained(this),
@@ -301,4 +311,9 @@
   return audio_sink_->GetAudioHashForTesting();
 }
 
+base::TimeDelta PipelineIntegrationTestBase::GetAudioTime() {
+  DCHECK(clockless_playback_);
+  return clockless_audio_sink_->render_time();
+}
+
 }  // namespace media
diff --git a/media/filters/pipeline_integration_test_base.h b/media/filters/pipeline_integration_test_base.h
index e9dc0aa..f91d8c4 100644
--- a/media/filters/pipeline_integration_test_base.h
+++ b/media/filters/pipeline_integration_test_base.h
@@ -7,6 +7,7 @@
 
 #include "base/md5.h"
 #include "base/message_loop/message_loop.h"
+#include "media/audio/clockless_audio_sink.h"
 #include "media/audio/null_audio_sink.h"
 #include "media/base/filter_collection.h"
 #include "media/base/media_keys.h"
@@ -47,10 +48,13 @@
   bool WaitUntilOnEnded();
   PipelineStatus WaitUntilEndedOrError();
   bool Start(const base::FilePath& file_path, PipelineStatus expected_status);
-  // Enable playback with audio and video hashing enabled.  Frame dropping and
-  // audio underflow will be disabled to ensure consistent hashes.
-  bool Start(const base::FilePath& file_path, PipelineStatus expected_status,
-             bool hashing_enabled);
+  // Enable playback with audio and video hashing enabled, or clockless
+  // playback (audio only). Frame dropping and audio underflow will be disabled
+  // if hashing enabled to ensure consistent hashes.
+  enum kTestType { kHashed, kClockless };
+  bool Start(const base::FilePath& file_path,
+             PipelineStatus expected_status,
+             kTestType test_type);
   // Initialize the pipeline and ignore any status updates.  Useful for testing
   // invalid audio/video clips which don't have deterministic results.
   bool Start(const base::FilePath& file_path);
@@ -75,14 +79,20 @@
   // enabled.
   std::string GetAudioHash();
 
+  // Returns the time taken to render the complete audio file.
+  // Pipeline must have been started with clockless playback enabled.
+  base::TimeDelta GetAudioTime();
+
  protected:
   base::MessageLoop message_loop_;
   base::MD5Context md5_context_;
   bool hashing_enabled_;
+  bool clockless_playback_;
   scoped_ptr<Demuxer> demuxer_;
   scoped_ptr<DataSource> data_source_;
   scoped_ptr<Pipeline> pipeline_;
   scoped_refptr<NullAudioSink> audio_sink_;
+  scoped_refptr<ClocklessAudioSink> clockless_audio_sink_;
   bool ended_;
   PipelineStatus pipeline_status_;
   NeedKeyCB need_key_cb_;
@@ -103,6 +113,7 @@
   void QuitAfterCurrentTimeTask(const base::TimeDelta& quit_time);
   scoped_ptr<FilterCollection> CreateFilterCollection(
       scoped_ptr<Demuxer> demuxer, Decryptor* decryptor);
+
   void SetDecryptor(Decryptor* decryptor,
                     const DecryptorReadyCB& decryptor_ready_cb);
   void OnVideoRendererPaint(const scoped_refptr<VideoFrame>& frame);
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc
index c883f96..25db8f0 100644
--- a/media/filters/stream_parser_factory.cc
+++ b/media/filters/stream_parser_factory.cc
@@ -12,7 +12,7 @@
 #include "media/base/media_switches.h"
 #include "media/webm/webm_stream_parser.h"
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 #include "media/mp4/es_descriptor.h"
 #include "media/mp4/mp4_stream_parser.h"
 #endif
@@ -81,7 +81,7 @@
   return new media::WebMStreamParser();
 }
 
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
 // AAC Object Type IDs that Chrome supports.
 static const int kAACLCObjectType = 2;
 static const int kAACSBRObjectType = 5;
@@ -181,7 +181,7 @@
 static const SupportedTypeInfo kSupportedTypeInfo[] = {
   { "video/webm", &BuildWebMParser, kVideoWebMCodecs },
   { "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
   { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
 #endif
diff --git a/media/media.gyp b/media/media.gyp
index c685090..6408f4b 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -60,9 +60,6 @@
         'audio/android/opensles_input.h',
         'audio/android/opensles_output.cc',
         'audio/android/opensles_output.h',
-        'audio/async_socket_io_handler.h',
-        'audio/async_socket_io_handler_posix.cc',
-        'audio/async_socket_io_handler_win.cc',
         'audio/audio_buffers_state.cc',
         'audio/audio_buffers_state.h',
         'audio/audio_device_name.cc',
@@ -99,6 +96,8 @@
         'audio/audio_source_diverter.h',
         'audio/audio_util.cc',
         'audio/audio_util.h',
+        'audio/clockless_audio_sink.cc',
+        'audio/clockless_audio_sink.h',
         'audio/cras/audio_manager_cras.cc',
         'audio/cras/audio_manager_cras.h',
         'audio/cras/cras_input.cc',
@@ -153,10 +152,10 @@
         'audio/openbsd/audio_manager_openbsd.h',
         'audio/pulse/audio_manager_pulse.cc',
         'audio/pulse/audio_manager_pulse.h',
-        'audio/pulse/pulse_output.cc',
-        'audio/pulse/pulse_output.h',
         'audio/pulse/pulse_input.cc',
         'audio/pulse/pulse_input.h',
+        'audio/pulse/pulse_output.cc',
+        'audio/pulse/pulse_output.h',
         'audio/pulse/pulse_unified.cc',
         'audio/pulse/pulse_unified.h',
         'audio/pulse/pulse_util.cc',
@@ -183,10 +182,10 @@
         'audio/win/audio_unified_win.h',
         'audio/win/avrt_wrapper_win.cc',
         'audio/win/avrt_wrapper_win.h',
-        'audio/win/device_enumeration_win.cc',
-        'audio/win/device_enumeration_win.h',
         'audio/win/core_audio_util_win.cc',
         'audio/win/core_audio_util_win.h',
+        'audio/win/device_enumeration_win.cc',
+        'audio/win/device_enumeration_win.h',
         'audio/win/wavein_input_win.cc',
         'audio/win/wavein_input_win.h',
         'audio/win/waveout_output_win.cc',
@@ -217,19 +216,19 @@
         'base/audio_pull_fifo.h',
         'base/audio_renderer.cc',
         'base/audio_renderer.h',
-        'base/audio_renderer_sink.h',
         'base/audio_renderer_mixer.cc',
         'base/audio_renderer_mixer.h',
         'base/audio_renderer_mixer_input.cc',
         'base/audio_renderer_mixer_input.h',
+        'base/audio_renderer_sink.h',
         'base/audio_splicer.cc',
         'base/audio_splicer.h',
         'base/audio_timestamp_helper.cc',
         'base/audio_timestamp_helper.h',
         'base/bind_to_loop.h',
-        'base/bitstream_buffer.h',
         'base/bit_reader.cc',
         'base/bit_reader.h',
+        'base/bitstream_buffer.h',
         'base/buffers.h',
         'base/byte_queue.cc',
         'base/byte_queue.h',
@@ -247,10 +246,10 @@
         'base/decoder_buffer.h',
         'base/decoder_buffer_queue.cc',
         'base/decoder_buffer_queue.h',
-        'base/decryptor.cc',
-        'base/decryptor.h',
         'base/decrypt_config.cc',
         'base/decrypt_config.h',
+        'base/decryptor.cc',
+        'base/decryptor.h',
         'base/demuxer.cc',
         'base/demuxer.h',
         'base/demuxer_stream.cc',
@@ -302,6 +301,11 @@
         'base/stream_parser_buffer.cc',
         'base/stream_parser_buffer.h',
         'base/text_track.h',
+        'base/user_input_monitor.cc',
+        'base/user_input_monitor.h',
+        'base/user_input_monitor_linux.cc',
+        'base/user_input_monitor_mac.mm',
+        'base/user_input_monitor_win.cc',
         'base/video_decoder.cc',
         'base/video_decoder.h',
         'base/video_decoder_config.cc',
@@ -348,10 +352,10 @@
         'filters/ffmpeg_video_decoder.h',
         'filters/file_data_source.cc',
         'filters/file_data_source.h',
+        'filters/gpu_video_accelerator_factories.cc',
+        'filters/gpu_video_accelerator_factories.h',
         'filters/gpu_video_decoder.cc',
         'filters/gpu_video_decoder.h',
-        'filters/gpu_video_decoder_factories.cc',
-        'filters/gpu_video_decoder_factories.h',
         'filters/h264_to_annex_b_bitstream_converter.cc',
         'filters/h264_to_annex_b_bitstream_converter.h',
         'filters/in_memory_url_protocol.cc',
@@ -372,12 +376,12 @@
         'filters/video_renderer_base.h',
         'filters/vpx_video_decoder.cc',
         'filters/vpx_video_decoder.h',
-        'midi/midi_manager.h',
         'midi/midi_manager.cc',
-        'midi/midi_manager_mac.h',
+        'midi/midi_manager.h',
         'midi/midi_manager_mac.cc',
-        'midi/midi_port_info.h',
+        'midi/midi_manager_mac.h',
         'midi/midi_port_info.cc',
+        'midi/midi_port_info.h',
         'video/capture/android/video_capture_device_android.cc',
         'video/capture/android/video_capture_device_android.h',
         'video/capture/fake_video_capture_device.cc',
@@ -416,6 +420,8 @@
         'video/picture.h',
         'video/video_decode_accelerator.cc',
         'video/video_decode_accelerator.h',
+        'video/video_encode_accelerator.cc',
+        'video/video_encode_accelerator.h',
         'webm/webm_audio_client.cc',
         'webm/webm_audio_client.h',
         'webm/webm_cluster_parser.cc',
@@ -537,6 +543,7 @@
             ['include', '^base/media\\.cc$'],
             ['include', '^base/media_stub\\.cc$'],
             ['include', '^base/media_switches\\.'],
+            ['include', '^base/user_input_monitor\\.'],
             ['include', '^base/vector_math\\.'],
           ],
           'link_settings': {
@@ -547,6 +554,9 @@
               '$(SDKROOT)/System/Library/Frameworks/CoreMIDI.framework',
             ],
           },
+          'defines': [
+            'DISABLE_USER_INPUT_MONITOR',
+          ],
         }],
         ['OS=="android"', {
           'link_settings': {
@@ -574,6 +584,9 @@
               ],
             }],
           ],
+          'defines': [
+            'DISABLE_USER_INPUT_MONITOR',
+          ],
         }],
         # A simple WebM encoder for animated avatars on ChromeOS.
         ['chromeos==1', {
@@ -587,6 +600,15 @@
             'webm/chromeos/webm_encoder.cc',
             'webm/chromeos/webm_encoder.h',
           ],
+          'defines': [
+            # TODO(jiayl): figure out why MediaStreamInfoBarTest.
+            # DenyingCameraDoesNotCauseStickyDenyForMics fails on ChromeOS and
+            # remove this.
+            'DISABLE_USER_INPUT_MONITOR',
+          ],
+          'sources!': [
+            'base/user_input_monitor_linux.cc',
+          ],
         }],
         ['use_alsa==1', {
           'link_settings': {
@@ -622,8 +644,16 @@
                   '-lXdamage',
                   '-lXext',
                   '-lXfixes',
+                  '-lXtst',
                 ],
               },
+            }, {  # else: use_x11==0
+              'sources!': [
+                'base/user_input_monitor_linux.cc',
+              ],
+              'defines': [
+                'DISABLE_USER_INPUT_MONITOR',
+              ],
             }],
             ['use_cras==1', {
               'cflags': [
@@ -877,7 +907,6 @@
         '../ui/ui.gyp:ui',
       ],
       'sources': [
-        'audio/async_socket_io_handler_unittest.cc',
         'audio/audio_input_controller_unittest.cc',
         'audio/audio_input_device_unittest.cc',
         'audio/audio_input_unittest.cc',
@@ -936,6 +965,7 @@
         'base/ranges_unittest.cc',
         'base/run_all_unittests.cc',
         'base/scoped_histogram_timer_unittest.cc',
+        'base/serial_runner_unittest.cc',
         'base/seekable_buffer_unittest.cc',
         'base/sinc_resampler_unittest.cc',
         'base/test_data_util.cc',
@@ -1125,8 +1155,8 @@
         'base/mock_filters.h',
         'base/test_helpers.cc',
         'base/test_helpers.h',
-        'filters/mock_gpu_video_decoder_factories.cc',
-        'filters/mock_gpu_video_decoder_factories.h',
+        'filters/mock_gpu_video_accelerator_factories.cc',
+        'filters/mock_gpu_video_accelerator_factories.h',
         'video/mock_video_decode_accelerator.cc',
         'video/mock_video_decode_accelerator.h',
       ],
@@ -1232,13 +1262,8 @@
           'include_dirs': [
             '..',
           ],
-          'conditions': [
-            # TODO(jschuh): Get MMX enabled on Win64. crbug.com/179657
-            ['OS!="win" or target_arch=="ia32"', {
-              'sources': [
-                'base/simd/filter_yuv_mmx.cc',
-              ],
-            }],
+          'sources': [
+            'base/simd/filter_yuv_mmx.cc',
           ],
         },
         {
@@ -1479,6 +1504,7 @@
           'sources': [
             'base/android/java/src/org/chromium/media/AudioManagerAndroid.java',
             'base/android/java/src/org/chromium/media/MediaCodecBridge.java',
+            'base/android/java/src/org/chromium/media/MediaDrmBridge.java',
             'base/android/java/src/org/chromium/media/MediaPlayerBridge.java',
             'base/android/java/src/org/chromium/media/MediaPlayerListener.java',
             'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java',
@@ -1503,8 +1529,12 @@
           'target_name': 'player_android',
           'type': 'static_library',
           'sources': [
+            'base/android/audio_decoder_job.cc',
+            'base/android/audio_decoder_job.h',
             'base/android/media_codec_bridge.cc',
             'base/android/media_codec_bridge.h',
+            'base/android/media_decoder_job.cc',
+            'base/android/media_decoder_job.h',
             'base/android/media_drm_bridge.cc',
             'base/android/media_drm_bridge.h',
             'base/android/media_jni_registrar.cc',
@@ -1517,6 +1547,8 @@
             'base/android/media_player_listener.h',
             'base/android/media_source_player.cc',
             'base/android/media_source_player.h',
+            'base/android/video_decoder_job.cc',
+            'base/android/video_decoder_job.h',
             'base/android/webaudio_media_codec_bridge.cc',
             'base/android/webaudio_media_codec_bridge.h',
             'base/android/webaudio_media_codec_info.h',
diff --git a/media/media.target.darwin-arm.mk b/media/media.target.darwin-arm.mk
index fca98f8..b909eae 100644
--- a/media/media.target.darwin-arm.mk
+++ b/media/media.target.darwin-arm.mk
@@ -31,7 +31,6 @@
 	media/audio/android/audio_manager_android.cc \
 	media/audio/android/opensles_input.cc \
 	media/audio/android/opensles_output.cc \
-	media/audio/async_socket_io_handler_posix.cc \
 	media/audio/audio_buffers_state.cc \
 	media/audio/audio_device_name.cc \
 	media/audio/audio_device_thread.cc \
@@ -49,6 +48,7 @@
 	media/audio/audio_output_resampler.cc \
 	media/audio/audio_power_monitor.cc \
 	media/audio/audio_util.cc \
+	media/audio/clockless_audio_sink.cc \
 	media/audio/cross_process_notification.cc \
 	media/audio/cross_process_notification_posix.cc \
 	media/audio/fake_audio_consumer.cc \
@@ -84,8 +84,8 @@
 	media/base/data_source.cc \
 	media/base/decoder_buffer.cc \
 	media/base/decoder_buffer_queue.cc \
-	media/base/decryptor.cc \
 	media/base/decrypt_config.cc \
+	media/base/decryptor.cc \
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
@@ -108,6 +108,7 @@
 	media/base/sinc_resampler.cc \
 	media/base/stream_parser.cc \
 	media/base/stream_parser_buffer.cc \
+	media/base/user_input_monitor.cc \
 	media/base/video_decoder.cc \
 	media/base/video_decoder_config.cc \
 	media/base/video_frame.cc \
@@ -123,8 +124,8 @@
 	media/filters/decrypting_demuxer_stream.cc \
 	media/filters/decrypting_video_decoder.cc \
 	media/filters/file_data_source.cc \
+	media/filters/gpu_video_accelerator_factories.cc \
 	media/filters/gpu_video_decoder.cc \
-	media/filters/gpu_video_decoder_factories.cc \
 	media/filters/h264_to_annex_b_bitstream_converter.cc \
 	media/filters/in_memory_url_protocol.cc \
 	media/filters/opus_audio_decoder.cc \
@@ -142,6 +143,7 @@
 	media/video/capture/video_capture_proxy.cc \
 	media/video/picture.cc \
 	media/video/video_decode_accelerator.cc \
+	media/video/video_encode_accelerator.cc \
 	media/webm/webm_audio_client.cc \
 	media/webm/webm_cluster_parser.cc \
 	media/webm/webm_constants.cc \
@@ -214,6 +216,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
@@ -325,6 +328,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
diff --git a/media/media.target.darwin-mips.mk b/media/media.target.darwin-mips.mk
index cf784c1..40dcf70 100644
--- a/media/media.target.darwin-mips.mk
+++ b/media/media.target.darwin-mips.mk
@@ -31,7 +31,6 @@
 	media/audio/android/audio_manager_android.cc \
 	media/audio/android/opensles_input.cc \
 	media/audio/android/opensles_output.cc \
-	media/audio/async_socket_io_handler_posix.cc \
 	media/audio/audio_buffers_state.cc \
 	media/audio/audio_device_name.cc \
 	media/audio/audio_device_thread.cc \
@@ -49,6 +48,7 @@
 	media/audio/audio_output_resampler.cc \
 	media/audio/audio_power_monitor.cc \
 	media/audio/audio_util.cc \
+	media/audio/clockless_audio_sink.cc \
 	media/audio/cross_process_notification.cc \
 	media/audio/cross_process_notification_posix.cc \
 	media/audio/fake_audio_consumer.cc \
@@ -84,8 +84,8 @@
 	media/base/data_source.cc \
 	media/base/decoder_buffer.cc \
 	media/base/decoder_buffer_queue.cc \
-	media/base/decryptor.cc \
 	media/base/decrypt_config.cc \
+	media/base/decryptor.cc \
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
@@ -108,6 +108,7 @@
 	media/base/sinc_resampler.cc \
 	media/base/stream_parser.cc \
 	media/base/stream_parser_buffer.cc \
+	media/base/user_input_monitor.cc \
 	media/base/video_decoder.cc \
 	media/base/video_decoder_config.cc \
 	media/base/video_frame.cc \
@@ -123,8 +124,8 @@
 	media/filters/decrypting_demuxer_stream.cc \
 	media/filters/decrypting_video_decoder.cc \
 	media/filters/file_data_source.cc \
+	media/filters/gpu_video_accelerator_factories.cc \
 	media/filters/gpu_video_decoder.cc \
-	media/filters/gpu_video_decoder_factories.cc \
 	media/filters/h264_to_annex_b_bitstream_converter.cc \
 	media/filters/in_memory_url_protocol.cc \
 	media/filters/opus_audio_decoder.cc \
@@ -142,6 +143,7 @@
 	media/video/capture/video_capture_proxy.cc \
 	media/video/picture.cc \
 	media/video/video_decode_accelerator.cc \
+	media/video/video_encode_accelerator.cc \
 	media/webm/webm_audio_client.cc \
 	media/webm/webm_cluster_parser.cc \
 	media/webm/webm_constants.cc \
@@ -213,6 +215,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
@@ -323,6 +326,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
diff --git a/media/media.target.darwin-x86.mk b/media/media.target.darwin-x86.mk
index e1ec667..c6eafe0 100644
--- a/media/media.target.darwin-x86.mk
+++ b/media/media.target.darwin-x86.mk
@@ -31,7 +31,6 @@
 	media/audio/android/audio_manager_android.cc \
 	media/audio/android/opensles_input.cc \
 	media/audio/android/opensles_output.cc \
-	media/audio/async_socket_io_handler_posix.cc \
 	media/audio/audio_buffers_state.cc \
 	media/audio/audio_device_name.cc \
 	media/audio/audio_device_thread.cc \
@@ -49,6 +48,7 @@
 	media/audio/audio_output_resampler.cc \
 	media/audio/audio_power_monitor.cc \
 	media/audio/audio_util.cc \
+	media/audio/clockless_audio_sink.cc \
 	media/audio/cross_process_notification.cc \
 	media/audio/cross_process_notification_posix.cc \
 	media/audio/fake_audio_consumer.cc \
@@ -84,8 +84,8 @@
 	media/base/data_source.cc \
 	media/base/decoder_buffer.cc \
 	media/base/decoder_buffer_queue.cc \
-	media/base/decryptor.cc \
 	media/base/decrypt_config.cc \
+	media/base/decryptor.cc \
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
@@ -108,6 +108,7 @@
 	media/base/sinc_resampler.cc \
 	media/base/stream_parser.cc \
 	media/base/stream_parser_buffer.cc \
+	media/base/user_input_monitor.cc \
 	media/base/video_decoder.cc \
 	media/base/video_decoder_config.cc \
 	media/base/video_frame.cc \
@@ -123,8 +124,8 @@
 	media/filters/decrypting_demuxer_stream.cc \
 	media/filters/decrypting_video_decoder.cc \
 	media/filters/file_data_source.cc \
+	media/filters/gpu_video_accelerator_factories.cc \
 	media/filters/gpu_video_decoder.cc \
-	media/filters/gpu_video_decoder_factories.cc \
 	media/filters/h264_to_annex_b_bitstream_converter.cc \
 	media/filters/in_memory_url_protocol.cc \
 	media/filters/opus_audio_decoder.cc \
@@ -142,6 +143,7 @@
 	media/video/capture/video_capture_proxy.cc \
 	media/video/picture.cc \
 	media/video/video_decode_accelerator.cc \
+	media/video/video_encode_accelerator.cc \
 	media/webm/webm_audio_client.cc \
 	media/webm/webm_cluster_parser.cc \
 	media/webm/webm_constants.cc \
@@ -217,6 +219,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
@@ -330,6 +333,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
diff --git a/media/media.target.linux-arm.mk b/media/media.target.linux-arm.mk
index fca98f8..b909eae 100644
--- a/media/media.target.linux-arm.mk
+++ b/media/media.target.linux-arm.mk
@@ -31,7 +31,6 @@
 	media/audio/android/audio_manager_android.cc \
 	media/audio/android/opensles_input.cc \
 	media/audio/android/opensles_output.cc \
-	media/audio/async_socket_io_handler_posix.cc \
 	media/audio/audio_buffers_state.cc \
 	media/audio/audio_device_name.cc \
 	media/audio/audio_device_thread.cc \
@@ -49,6 +48,7 @@
 	media/audio/audio_output_resampler.cc \
 	media/audio/audio_power_monitor.cc \
 	media/audio/audio_util.cc \
+	media/audio/clockless_audio_sink.cc \
 	media/audio/cross_process_notification.cc \
 	media/audio/cross_process_notification_posix.cc \
 	media/audio/fake_audio_consumer.cc \
@@ -84,8 +84,8 @@
 	media/base/data_source.cc \
 	media/base/decoder_buffer.cc \
 	media/base/decoder_buffer_queue.cc \
-	media/base/decryptor.cc \
 	media/base/decrypt_config.cc \
+	media/base/decryptor.cc \
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
@@ -108,6 +108,7 @@
 	media/base/sinc_resampler.cc \
 	media/base/stream_parser.cc \
 	media/base/stream_parser_buffer.cc \
+	media/base/user_input_monitor.cc \
 	media/base/video_decoder.cc \
 	media/base/video_decoder_config.cc \
 	media/base/video_frame.cc \
@@ -123,8 +124,8 @@
 	media/filters/decrypting_demuxer_stream.cc \
 	media/filters/decrypting_video_decoder.cc \
 	media/filters/file_data_source.cc \
+	media/filters/gpu_video_accelerator_factories.cc \
 	media/filters/gpu_video_decoder.cc \
-	media/filters/gpu_video_decoder_factories.cc \
 	media/filters/h264_to_annex_b_bitstream_converter.cc \
 	media/filters/in_memory_url_protocol.cc \
 	media/filters/opus_audio_decoder.cc \
@@ -142,6 +143,7 @@
 	media/video/capture/video_capture_proxy.cc \
 	media/video/picture.cc \
 	media/video/video_decode_accelerator.cc \
+	media/video/video_encode_accelerator.cc \
 	media/webm/webm_audio_client.cc \
 	media/webm/webm_cluster_parser.cc \
 	media/webm/webm_constants.cc \
@@ -214,6 +216,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
@@ -325,6 +328,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
diff --git a/media/media.target.linux-mips.mk b/media/media.target.linux-mips.mk
index cf784c1..40dcf70 100644
--- a/media/media.target.linux-mips.mk
+++ b/media/media.target.linux-mips.mk
@@ -31,7 +31,6 @@
 	media/audio/android/audio_manager_android.cc \
 	media/audio/android/opensles_input.cc \
 	media/audio/android/opensles_output.cc \
-	media/audio/async_socket_io_handler_posix.cc \
 	media/audio/audio_buffers_state.cc \
 	media/audio/audio_device_name.cc \
 	media/audio/audio_device_thread.cc \
@@ -49,6 +48,7 @@
 	media/audio/audio_output_resampler.cc \
 	media/audio/audio_power_monitor.cc \
 	media/audio/audio_util.cc \
+	media/audio/clockless_audio_sink.cc \
 	media/audio/cross_process_notification.cc \
 	media/audio/cross_process_notification_posix.cc \
 	media/audio/fake_audio_consumer.cc \
@@ -84,8 +84,8 @@
 	media/base/data_source.cc \
 	media/base/decoder_buffer.cc \
 	media/base/decoder_buffer_queue.cc \
-	media/base/decryptor.cc \
 	media/base/decrypt_config.cc \
+	media/base/decryptor.cc \
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
@@ -108,6 +108,7 @@
 	media/base/sinc_resampler.cc \
 	media/base/stream_parser.cc \
 	media/base/stream_parser_buffer.cc \
+	media/base/user_input_monitor.cc \
 	media/base/video_decoder.cc \
 	media/base/video_decoder_config.cc \
 	media/base/video_frame.cc \
@@ -123,8 +124,8 @@
 	media/filters/decrypting_demuxer_stream.cc \
 	media/filters/decrypting_video_decoder.cc \
 	media/filters/file_data_source.cc \
+	media/filters/gpu_video_accelerator_factories.cc \
 	media/filters/gpu_video_decoder.cc \
-	media/filters/gpu_video_decoder_factories.cc \
 	media/filters/h264_to_annex_b_bitstream_converter.cc \
 	media/filters/in_memory_url_protocol.cc \
 	media/filters/opus_audio_decoder.cc \
@@ -142,6 +143,7 @@
 	media/video/capture/video_capture_proxy.cc \
 	media/video/picture.cc \
 	media/video/video_decode_accelerator.cc \
+	media/video/video_encode_accelerator.cc \
 	media/webm/webm_audio_client.cc \
 	media/webm/webm_cluster_parser.cc \
 	media/webm/webm_constants.cc \
@@ -213,6 +215,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
@@ -323,6 +326,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
diff --git a/media/media.target.linux-x86.mk b/media/media.target.linux-x86.mk
index e1ec667..c6eafe0 100644
--- a/media/media.target.linux-x86.mk
+++ b/media/media.target.linux-x86.mk
@@ -31,7 +31,6 @@
 	media/audio/android/audio_manager_android.cc \
 	media/audio/android/opensles_input.cc \
 	media/audio/android/opensles_output.cc \
-	media/audio/async_socket_io_handler_posix.cc \
 	media/audio/audio_buffers_state.cc \
 	media/audio/audio_device_name.cc \
 	media/audio/audio_device_thread.cc \
@@ -49,6 +48,7 @@
 	media/audio/audio_output_resampler.cc \
 	media/audio/audio_power_monitor.cc \
 	media/audio/audio_util.cc \
+	media/audio/clockless_audio_sink.cc \
 	media/audio/cross_process_notification.cc \
 	media/audio/cross_process_notification_posix.cc \
 	media/audio/fake_audio_consumer.cc \
@@ -84,8 +84,8 @@
 	media/base/data_source.cc \
 	media/base/decoder_buffer.cc \
 	media/base/decoder_buffer_queue.cc \
-	media/base/decryptor.cc \
 	media/base/decrypt_config.cc \
+	media/base/decryptor.cc \
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
@@ -108,6 +108,7 @@
 	media/base/sinc_resampler.cc \
 	media/base/stream_parser.cc \
 	media/base/stream_parser_buffer.cc \
+	media/base/user_input_monitor.cc \
 	media/base/video_decoder.cc \
 	media/base/video_decoder_config.cc \
 	media/base/video_frame.cc \
@@ -123,8 +124,8 @@
 	media/filters/decrypting_demuxer_stream.cc \
 	media/filters/decrypting_video_decoder.cc \
 	media/filters/file_data_source.cc \
+	media/filters/gpu_video_accelerator_factories.cc \
 	media/filters/gpu_video_decoder.cc \
-	media/filters/gpu_video_decoder_factories.cc \
 	media/filters/h264_to_annex_b_bitstream_converter.cc \
 	media/filters/in_memory_url_protocol.cc \
 	media/filters/opus_audio_decoder.cc \
@@ -142,6 +143,7 @@
 	media/video/capture/video_capture_proxy.cc \
 	media/video/picture.cc \
 	media/video/video_decode_accelerator.cc \
+	media/video/video_encode_accelerator.cc \
 	media/webm/webm_audio_client.cc \
 	media/webm/webm_cluster_parser.cc \
 	media/webm/webm_constants.cc \
@@ -217,6 +219,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
@@ -330,6 +333,7 @@
 	'-DUSE_OPENSSL=1' \
 	'-DENABLE_EGLIMAGE=1' \
 	'-DMEDIA_IMPLEMENTATION' \
+	'-DDISABLE_USER_INPUT_MONITOR' \
 	'-DSK_ENABLE_INST_COUNT=0' \
 	'-DSK_SUPPORT_GPU=1' \
 	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
diff --git a/media/media_android_jni_headers.target.darwin-arm.mk b/media/media_android_jni_headers.target.darwin-arm.mk
index 35313e8..3c9132c 100644
--- a/media/media_android_jni_headers.target.darwin-arm.mk
+++ b/media/media_android_jni_headers.target.darwin-arm.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "media_media_gyp_media_android_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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaDrmBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -36,6 +36,16 @@
 .PHONY: media_media_android_jni_headers_gyp_rule_trigger
 media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h
 
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: $(LOCAL_PATH)/media/base/android/java/src/org/chromium/media/MediaDrmBridge.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)/media/jni; cd $(gyp_local_path)/media; ../base/android/jni_generator/jni_generator.py --input_file base/android/java/src/org/chromium/media/MediaDrmBridge.java --output_dir "$(gyp_shared_intermediate_dir)/media/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: media_media_android_jni_headers_gyp_rule_trigger
+media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h
+
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -71,6 +81,7 @@
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h
@@ -81,6 +92,7 @@
 LOCAL_GENERATED_SOURCES := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h \
diff --git a/media/media_android_jni_headers.target.darwin-mips.mk b/media/media_android_jni_headers.target.darwin-mips.mk
index 78e558a..8d8aa4b 100644
--- a/media/media_android_jni_headers.target.darwin-mips.mk
+++ b/media/media_android_jni_headers.target.darwin-mips.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "media_media_gyp_media_android_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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaDrmBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -36,6 +36,16 @@
 .PHONY: media_media_android_jni_headers_gyp_rule_trigger
 media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h
 
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: $(LOCAL_PATH)/media/base/android/java/src/org/chromium/media/MediaDrmBridge.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)/media/jni; cd $(gyp_local_path)/media; ../base/android/jni_generator/jni_generator.py --input_file base/android/java/src/org/chromium/media/MediaDrmBridge.java --output_dir "$(gyp_shared_intermediate_dir)/media/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: media_media_android_jni_headers_gyp_rule_trigger
+media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h
+
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -71,6 +81,7 @@
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h
@@ -81,6 +92,7 @@
 LOCAL_GENERATED_SOURCES := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h \
diff --git a/media/media_android_jni_headers.target.darwin-x86.mk b/media/media_android_jni_headers.target.darwin-x86.mk
index a31e14e..5f14b4b 100644
--- a/media/media_android_jni_headers.target.darwin-x86.mk
+++ b/media/media_android_jni_headers.target.darwin-x86.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "media_media_gyp_media_android_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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaDrmBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -36,6 +36,16 @@
 .PHONY: media_media_android_jni_headers_gyp_rule_trigger
 media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h
 
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: $(LOCAL_PATH)/media/base/android/java/src/org/chromium/media/MediaDrmBridge.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)/media/jni; cd $(gyp_local_path)/media; ../base/android/jni_generator/jni_generator.py --input_file base/android/java/src/org/chromium/media/MediaDrmBridge.java --output_dir "$(gyp_shared_intermediate_dir)/media/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: media_media_android_jni_headers_gyp_rule_trigger
+media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h
+
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -71,6 +81,7 @@
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h
@@ -81,6 +92,7 @@
 LOCAL_GENERATED_SOURCES := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h \
diff --git a/media/media_android_jni_headers.target.linux-arm.mk b/media/media_android_jni_headers.target.linux-arm.mk
index 35313e8..3c9132c 100644
--- a/media/media_android_jni_headers.target.linux-arm.mk
+++ b/media/media_android_jni_headers.target.linux-arm.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "media_media_gyp_media_android_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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaDrmBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -36,6 +36,16 @@
 .PHONY: media_media_android_jni_headers_gyp_rule_trigger
 media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h
 
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: $(LOCAL_PATH)/media/base/android/java/src/org/chromium/media/MediaDrmBridge.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)/media/jni; cd $(gyp_local_path)/media; ../base/android/jni_generator/jni_generator.py --input_file base/android/java/src/org/chromium/media/MediaDrmBridge.java --output_dir "$(gyp_shared_intermediate_dir)/media/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: media_media_android_jni_headers_gyp_rule_trigger
+media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h
+
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -71,6 +81,7 @@
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h
@@ -81,6 +92,7 @@
 LOCAL_GENERATED_SOURCES := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h \
diff --git a/media/media_android_jni_headers.target.linux-mips.mk b/media/media_android_jni_headers.target.linux-mips.mk
index 78e558a..8d8aa4b 100644
--- a/media/media_android_jni_headers.target.linux-mips.mk
+++ b/media/media_android_jni_headers.target.linux-mips.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "media_media_gyp_media_android_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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaDrmBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -36,6 +36,16 @@
 .PHONY: media_media_android_jni_headers_gyp_rule_trigger
 media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h
 
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: $(LOCAL_PATH)/media/base/android/java/src/org/chromium/media/MediaDrmBridge.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)/media/jni; cd $(gyp_local_path)/media; ../base/android/jni_generator/jni_generator.py --input_file base/android/java/src/org/chromium/media/MediaDrmBridge.java --output_dir "$(gyp_shared_intermediate_dir)/media/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: media_media_android_jni_headers_gyp_rule_trigger
+media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h
+
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -71,6 +81,7 @@
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h
@@ -81,6 +92,7 @@
 LOCAL_GENERATED_SOURCES := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h \
diff --git a/media/media_android_jni_headers.target.linux-x86.mk b/media/media_android_jni_headers.target.linux-x86.mk
index a31e14e..5f14b4b 100644
--- a/media/media_android_jni_headers.target.linux-x86.mk
+++ b/media/media_android_jni_headers.target.linux-x86.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "media_media_gyp_media_android_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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/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)/media/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['base/android/java/src/org/chromium/media/AudioManagerAndroid.java', 'base/android/java/src/org/chromium/media/MediaCodecBridge.java', 'base/android/java/src/org/chromium/media/MediaDrmBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerBridge.java', 'base/android/java/src/org/chromium/media/MediaPlayerListener.java', 'base/android/java/src/org/chromium/media/WebAudioMediaCodecBridge.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/media/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -36,6 +36,16 @@
 .PHONY: media_media_android_jni_headers_gyp_rule_trigger
 media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h
 
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h: $(LOCAL_PATH)/media/base/android/java/src/org/chromium/media/MediaDrmBridge.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)/media/jni; cd $(gyp_local_path)/media; ../base/android/jni_generator/jni_generator.py --input_file base/android/java/src/org/chromium/media/MediaDrmBridge.java --output_dir "$(gyp_shared_intermediate_dir)/media/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: media_media_android_jni_headers_gyp_rule_trigger
+media_media_android_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h
+
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -71,6 +81,7 @@
 GYP_GENERATED_OUTPUTS := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h
@@ -81,6 +92,7 @@
 LOCAL_GENERATED_SOURCES := \
 	$(gyp_shared_intermediate_dir)/media/jni/AudioManagerAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaCodecBridge_jni.h \
+	$(gyp_shared_intermediate_dir)/media/jni/MediaDrmBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerBridge_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/MediaPlayerListener_jni.h \
 	$(gyp_shared_intermediate_dir)/media/jni/WebAudioMediaCodecBridge_jni.h \
diff --git a/media/media_untrusted.gyp b/media/media_untrusted.gyp
index dade625..638d401 100644
--- a/media/media_untrusted.gyp
+++ b/media/media_untrusted.gyp
@@ -19,7 +19,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libshared_memory_support_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'dependencies': [
diff --git a/media/midi/midi_manager_mac.cc b/media/midi/midi_manager_mac.cc
index d766bdb..7bc8f23 100644
--- a/media/midi/midi_manager_mac.cc
+++ b/media/midi/midi_manager_mac.cc
@@ -68,7 +68,7 @@
     return false;
 
   int destination_count = MIDIGetNumberOfDestinations();
-  destinations_.reserve(destination_count);
+  destinations_.resize(destination_count);
 
   for (int i = 0; i < destination_count ; i++) {
     MIDIEndpointRef destination = MIDIGetDestination(i);
diff --git a/media/player_android.target.darwin-arm.mk b/media/player_android.target.darwin-arm.mk
index 3874555..3f86418 100644
--- a/media/player_android.target.darwin-arm.mk
+++ b/media/player_android.target.darwin-arm.mk
@@ -25,13 +25,16 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	media/base/android/audio_decoder_job.cc \
 	media/base/android/media_codec_bridge.cc \
+	media/base/android/media_decoder_job.cc \
 	media/base/android/media_drm_bridge.cc \
 	media/base/android/media_jni_registrar.cc \
 	media/base/android/media_player_android.cc \
 	media/base/android/media_player_bridge.cc \
 	media/base/android/media_player_listener.cc \
 	media/base/android/media_source_player.cc \
+	media/base/android/video_decoder_job.cc \
 	media/base/android/webaudio_media_codec_bridge.cc
 
 
diff --git a/media/player_android.target.darwin-mips.mk b/media/player_android.target.darwin-mips.mk
index 3f7eb22..472e70f 100644
--- a/media/player_android.target.darwin-mips.mk
+++ b/media/player_android.target.darwin-mips.mk
@@ -25,13 +25,16 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	media/base/android/audio_decoder_job.cc \
 	media/base/android/media_codec_bridge.cc \
+	media/base/android/media_decoder_job.cc \
 	media/base/android/media_drm_bridge.cc \
 	media/base/android/media_jni_registrar.cc \
 	media/base/android/media_player_android.cc \
 	media/base/android/media_player_bridge.cc \
 	media/base/android/media_player_listener.cc \
 	media/base/android/media_source_player.cc \
+	media/base/android/video_decoder_job.cc \
 	media/base/android/webaudio_media_codec_bridge.cc
 
 
diff --git a/media/player_android.target.darwin-x86.mk b/media/player_android.target.darwin-x86.mk
index 36124fe..b530e7c 100644
--- a/media/player_android.target.darwin-x86.mk
+++ b/media/player_android.target.darwin-x86.mk
@@ -25,13 +25,16 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	media/base/android/audio_decoder_job.cc \
 	media/base/android/media_codec_bridge.cc \
+	media/base/android/media_decoder_job.cc \
 	media/base/android/media_drm_bridge.cc \
 	media/base/android/media_jni_registrar.cc \
 	media/base/android/media_player_android.cc \
 	media/base/android/media_player_bridge.cc \
 	media/base/android/media_player_listener.cc \
 	media/base/android/media_source_player.cc \
+	media/base/android/video_decoder_job.cc \
 	media/base/android/webaudio_media_codec_bridge.cc
 
 
diff --git a/media/player_android.target.linux-arm.mk b/media/player_android.target.linux-arm.mk
index 3874555..3f86418 100644
--- a/media/player_android.target.linux-arm.mk
+++ b/media/player_android.target.linux-arm.mk
@@ -25,13 +25,16 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	media/base/android/audio_decoder_job.cc \
 	media/base/android/media_codec_bridge.cc \
+	media/base/android/media_decoder_job.cc \
 	media/base/android/media_drm_bridge.cc \
 	media/base/android/media_jni_registrar.cc \
 	media/base/android/media_player_android.cc \
 	media/base/android/media_player_bridge.cc \
 	media/base/android/media_player_listener.cc \
 	media/base/android/media_source_player.cc \
+	media/base/android/video_decoder_job.cc \
 	media/base/android/webaudio_media_codec_bridge.cc
 
 
diff --git a/media/player_android.target.linux-mips.mk b/media/player_android.target.linux-mips.mk
index 3f7eb22..472e70f 100644
--- a/media/player_android.target.linux-mips.mk
+++ b/media/player_android.target.linux-mips.mk
@@ -25,13 +25,16 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	media/base/android/audio_decoder_job.cc \
 	media/base/android/media_codec_bridge.cc \
+	media/base/android/media_decoder_job.cc \
 	media/base/android/media_drm_bridge.cc \
 	media/base/android/media_jni_registrar.cc \
 	media/base/android/media_player_android.cc \
 	media/base/android/media_player_bridge.cc \
 	media/base/android/media_player_listener.cc \
 	media/base/android/media_source_player.cc \
+	media/base/android/video_decoder_job.cc \
 	media/base/android/webaudio_media_codec_bridge.cc
 
 
diff --git a/media/player_android.target.linux-x86.mk b/media/player_android.target.linux-x86.mk
index 36124fe..b530e7c 100644
--- a/media/player_android.target.linux-x86.mk
+++ b/media/player_android.target.linux-x86.mk
@@ -25,13 +25,16 @@
 GYP_COPIED_SOURCE_ORIGIN_DIRS :=
 
 LOCAL_SRC_FILES := \
+	media/base/android/audio_decoder_job.cc \
 	media/base/android/media_codec_bridge.cc \
+	media/base/android/media_decoder_job.cc \
 	media/base/android/media_drm_bridge.cc \
 	media/base/android/media_jni_registrar.cc \
 	media/base/android/media_player_android.cc \
 	media/base/android/media_player_bridge.cc \
 	media/base/android/media_player_listener.cc \
 	media/base/android/media_source_player.cc \
+	media/base/android/video_decoder_job.cc \
 	media/base/android/webaudio_media_codec_bridge.cc
 
 
diff --git a/media/tools/shader_bench/shader_bench.cc b/media/tools/shader_bench/shader_bench.cc
index b26733c..0b4236f 100644
--- a/media/tools/shader_bench/shader_bench.cc
+++ b/media/tools/shader_bench/shader_bench.cc
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
+#include "media/base/media.h"
 #include "media/base/video_frame.h"
 #include "media/tools/shader_bench/cpu_color_painter.h"
 #include "media/tools/shader_bench/gpu_color_painter.h"
@@ -127,18 +128,19 @@
 
   // Initialize window and graphics context.
   base::AtExitManager at_exit_manager;
+  media::InitializeMediaLibraryForTesting();
   gfx::GLSurface::InitializeOneOff();
   scoped_ptr<media::Window> window(new media::Window(width, height));
-  gfx::GLSurface* surface =
-      gfx::GLSurface::CreateViewGLSurface(window->PluginWindow()).get();
-  gfx::GLContext* context = gfx::GLContext::CreateGLContext(
-      NULL, surface, gfx::PreferDiscreteGpu).get();
-  context->MakeCurrent(surface);
+  scoped_refptr<gfx::GLSurface> surface =
+      gfx::GLSurface::CreateViewGLSurface(window->PluginWindow());
+  scoped_refptr<gfx::GLContext> context = gfx::GLContext::CreateGLContext(
+      NULL, surface.get(), gfx::PreferDiscreteGpu);
+  context->MakeCurrent(surface.get());
   // This sets D3DPRESENT_INTERVAL_IMMEDIATE on Windows.
   context->SetSwapInterval(0);
 
   // Initialize and name GPU painters.
-  static const struct {
+  const struct {
     const char* name;
     GPUPainter* painter;
   } painters[] = {
diff --git a/media/video/capture/mac/video_capture_device_mac.h b/media/video/capture/mac/video_capture_device_mac.h
index 6ca24f3..dc0935f 100644
--- a/media/video/capture/mac/video_capture_device_mac.h
+++ b/media/video/capture/mac/video_capture_device_mac.h
@@ -10,6 +10,9 @@
 #include <string>
 
 #include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "media/video/capture/video_capture_device.h"
 #include "media/video/capture/video_capture_types.h"
 
@@ -38,6 +41,8 @@
   void ReceiveFrame(const uint8* video_frame, int video_frame_length,
                     const VideoCaptureCapability& frame_info);
 
+  void ReceiveError(const std::string& reason);
+
  private:
   void SetErrorState(const std::string& reason);
 
@@ -52,8 +57,16 @@
 
   Name device_name_;
   VideoCaptureDevice::EventHandler* observer_;
+
+  // Only read and write state_ from inside this loop.
+  const scoped_refptr<base::MessageLoopProxy> loop_proxy_;
   InternalState state_;
 
+  // Used with Bind and PostTask to ensure that methods aren't called
+  // after the VideoCaptureDeviceMac is destroyed.
+  base::WeakPtrFactory<VideoCaptureDeviceMac> weak_factory_;
+  base::WeakPtr<VideoCaptureDeviceMac> weak_this_;
+
   VideoCaptureDeviceQTKit* 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 1891217..957486e 100644
--- a/media/video/capture/mac/video_capture_device_mac.mm
+++ b/media/video/capture/mac/video_capture_device_mac.mm
@@ -6,6 +6,8 @@
 
 #import <QTKit/QTKit.h>
 
+#include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/time/time.h"
 #include "media/video/capture/mac/video_capture_device_qtkit_mac.h"
@@ -94,17 +96,22 @@
 VideoCaptureDeviceMac::VideoCaptureDeviceMac(const Name& device_name)
     : device_name_(device_name),
       observer_(NULL),
+      loop_proxy_(base::MessageLoopProxy::current()),
       state_(kNotInitialized),
+      weak_factory_(this),
+      weak_this_(weak_factory_.GetWeakPtr()),
       capture_device_(nil) {
 }
 
 VideoCaptureDeviceMac::~VideoCaptureDeviceMac() {
+  DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
   [capture_device_ release];
 }
 
 void VideoCaptureDeviceMac::Allocate(
     const VideoCaptureCapability& capture_format,
     EventHandler* observer) {
+  DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
   if (state_ != kIdle) {
     return;
   }
@@ -153,6 +160,7 @@
 }
 
 void VideoCaptureDeviceMac::Start() {
+  DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
   DCHECK_EQ(state_, kAllocated);
   if (![capture_device_ startCapture]) {
     SetErrorState("Could not start capture device.");
@@ -162,12 +170,14 @@
 }
 
 void VideoCaptureDeviceMac::Stop() {
-  DCHECK_EQ(state_, kCapturing);
+  DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
+  DCHECK(state_ == kCapturing || state_ == kError) << state_;
   [capture_device_ stopCapture];
   state_ = kAllocated;
 }
 
 void VideoCaptureDeviceMac::DeAllocate() {
+  DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
   if (state_ != kAllocated && state_ != kCapturing) {
     return;
   }
@@ -185,6 +195,7 @@
 }
 
 bool VideoCaptureDeviceMac::Init() {
+  DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
   DCHECK_EQ(state_, kNotInitialized);
 
   Names device_names;
@@ -206,11 +217,20 @@
     const uint8* video_frame,
     int video_frame_length,
     const VideoCaptureCapability& frame_info) {
+  // This method is safe to call from a device capture thread,
+  // i.e. any thread controlled by QTKit.
   observer_->OnIncomingCapturedFrame(
       video_frame, video_frame_length, base::Time::Now(), 0, false, false);
 }
 
+void VideoCaptureDeviceMac::ReceiveError(const std::string& reason) {
+  loop_proxy_->PostTask(FROM_HERE,
+      base::Bind(&VideoCaptureDeviceMac::SetErrorState, weak_this_,
+          reason));
+}
+
 void VideoCaptureDeviceMac::SetErrorState(const std::string& reason) {
+  DCHECK_EQ(loop_proxy_, base::MessageLoopProxy::current());
   DLOG(ERROR) << reason;
   state_ = kError;
   observer_->OnError();
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 3c9a3db..a2d6f26 100644
--- a/media/video/capture/mac/video_capture_device_qtkit_mac.h
+++ b/media/video/capture/mac/video_capture_device_qtkit_mac.h
@@ -60,6 +60,9 @@
 // Stops video capturing.
 - (void)stopCapture;
 
+// Handle any QTCaptureSessionRuntimeErrorNotifications.
+- (void)handleNotification:(NSNotification *)errorNotification;
+
 @end
 
 #endif  // MEDIA_VIDEO_CAPTURE_MAC_VIDEO_CAPTURE_DEVICE_MAC_QTKIT_H_
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 fa2d7c3..b7e407a 100644
--- a/media/video/capture/mac/video_capture_device_qtkit_mac.mm
+++ b/media/video/capture/mac/video_capture_device_qtkit_mac.mm
@@ -121,6 +121,7 @@
     }
     if ([[captureSession_ outputs] count] > 0) {
       // Only one output is set for |captureSession_|.
+      DCHECK_EQ([[captureSession_ outputs] count], 1u);
       id output = [[captureSession_ outputs] objectAtIndex:0];
       [output setDelegate:nil];
 
@@ -194,6 +195,12 @@
                   << [[error localizedDescription] UTF8String];
       return NO;
     }
+    NSNotificationCenter * notificationCenter =
+        [NSNotificationCenter defaultCenter];
+    [notificationCenter addObserver:self
+                           selector:@selector(handleNotification:)
+                               name:QTCaptureSessionRuntimeErrorNotification
+                             object:captureSession_];
     [captureSession_ startRunning];
   }
   return YES;
@@ -204,6 +211,8 @@
     [captureSession_ removeInput:captureDeviceInput_];
     [captureSession_ stopRunning];
   }
+
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
 }
 
 // |captureOutput| is called by the capture device to deliver a new frame.
@@ -269,4 +278,10 @@
   [lock_ unlock];
 }
 
+- (void)handleNotification:(NSNotification *)errorNotification {
+  NSError * error = (NSError *)[[errorNotification userInfo]
+      objectForKey:QTCaptureSessionErrorKey];
+  frameReceiver_->ReceiveError([[error localizedDescription] UTF8String]);
+}
+
 @end
diff --git a/media/video/capture/video_capture_device.h b/media/video/capture/video_capture_device.h
index 4480116..8ef43e7 100644
--- a/media/video/capture/video_capture_device.h
+++ b/media/video/capture/video_capture_device.h
@@ -72,7 +72,7 @@
     // In the shared build, all methods from the STL container will be exported
     // so even though they're not used, they're still depended upon.
     bool operator==(const Name& other) const {
-      return other.id() == unique_id_ && other.name() == device_name_;
+      return other.id() == unique_id_;
     }
     bool operator<(const Name& other) const {
       return unique_id_ < other.id();
diff --git a/media/video/capture/win/filter_base_win.cc b/media/video/capture/win/filter_base_win.cc
index 89309df..ddc68d6 100644
--- a/media/video/capture/win/filter_base_win.cc
+++ b/media/video/capture/win/filter_base_win.cc
@@ -72,8 +72,6 @@
 
   STDMETHOD(Clone)(IEnumPins** clone) {
     PinEnumerator* pin_enum = new PinEnumerator(filter_);
-    if (!pin_enum)
-      return E_OUTOFMEMORY;
     pin_enum->AddRef();
     pin_enum->index_ = index_;
     *clone = pin_enum;
diff --git a/media/video/capture/win/pin_base_win.cc b/media/video/capture/win/pin_base_win.cc
index 7e2f7b0..3a5139e 100644
--- a/media/video/capture/win/pin_base_win.cc
+++ b/media/video/capture/win/pin_base_win.cc
@@ -93,8 +93,6 @@
 
   STDMETHOD(Clone)(IEnumMediaTypes** clone) {
     TypeEnumerator* type_enum = new TypeEnumerator(pin_);
-    if (!type_enum)
-      return E_OUTOFMEMORY;
     type_enum->AddRef();
     type_enum->index_ = index_;
     *clone = type_enum;
@@ -248,8 +246,18 @@
 STDMETHODIMP PinBase::ReceiveMultiple(IMediaSample** samples,
                                       long sample_count,
                                       long* processed) {
-  NOTREACHED();
-  return VFW_E_INVALIDMEDIATYPE;
+  DCHECK(samples);
+
+  HRESULT hr = S_OK;
+  *processed = 0;
+  while (sample_count--) {
+    hr = Receive(samples[*processed]);
+    // S_FALSE means don't send any more.
+    if (hr != S_OK)
+      break;
+    ++(*processed);
+  }
+  return hr;
 }
 
 STDMETHODIMP PinBase::ReceiveCanBlock() {
diff --git a/media/video/capture/win/video_capture_device_win.cc b/media/video/capture/win/video_capture_device_win.cc
index 1a7c3b7..3aaef04 100644
--- a/media/video/capture/win/video_capture_device_win.cc
+++ b/media/video/capture/win/video_capture_device_win.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/strings/string_util.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/win/metro.h"
 #include "base/win/scoped_variant.h"
 #include "media/base/media_switches.h"
 #include "media/video/capture/win/video_capture_device_mf_win.h"
@@ -150,22 +151,15 @@
 
 // static
 void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
-  Names::iterator it;
-
   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
-  if (VideoCaptureDeviceMFWin::PlatformSupported() &&
+  // Use Media Foundation for Metro processes (after and including Win8)
+  // and DirectShow for any other platforms.
+  if (base::win::IsMetroProcess() &&
       !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) {
     VideoCaptureDeviceMFWin::GetDeviceNames(device_names);
+  } else {
+    VideoCaptureDeviceWin::GetDeviceNames(device_names);
   }
-  // Retrieve the devices with DirectShow (DS) interface. They might (partially)
-  // overlap with the MediaFoundation (MF), so the list has to be consolidated.
-  Names temp_names;
-  VideoCaptureDeviceWin::GetDeviceNames(&temp_names);
-
-  // Merge the DS devices into the MF device list, and next remove
-  // the duplicates, giving priority to the MF "versions".
-  device_names->merge(temp_names);
-  device_names->unique();
 }
 
 // static
diff --git a/media/video/video_encode_accelerator.cc b/media/video/video_encode_accelerator.cc
new file mode 100644
index 0000000..6309180
--- /dev/null
+++ b/media/video/video_encode_accelerator.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 "media/video/video_encode_accelerator.h"
+
+namespace media {
+
+VideoEncodeAccelerator::~VideoEncodeAccelerator() {}
+
+}  // namespace media
diff --git a/media/video/video_encode_accelerator.h b/media/video/video_encode_accelerator.h
new file mode 100644
index 0000000..8d4f565
--- /dev/null
+++ b/media/video/video_encode_accelerator.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 MEDIA_VIDEO_VIDEO_ENCODE_ACCELERATOR_H_
+#define MEDIA_VIDEO_VIDEO_ENCODE_ACCELERATOR_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "media/base/bitstream_buffer.h"
+#include "media/base/media_export.h"
+#include "media/base/video_decoder_config.h"
+#include "media/base/video_frame.h"
+
+namespace media {
+
+class BitstreamBuffer;
+class VideoFrame;
+
+// Video encoder interface.
+class MEDIA_EXPORT VideoEncodeAccelerator {
+ public:
+  virtual ~VideoEncodeAccelerator();
+
+  // Specification of an encoding profile supported by an encoder.
+  struct SupportedProfile {
+    VideoCodecProfile profile;
+    gfx::Size max_resolution;
+    struct {
+      uint32 numerator;
+      uint32 denominator;
+    } max_framerate;
+  };
+
+  // Enumeration of potential errors generated by the API.
+  enum Error {
+    // An operation was attempted during an incompatible encoder state.
+    kIllegalStateError,
+    // Invalid argument was passed to an API method.
+    kInvalidArgumentError,
+    // A failure occurred at the GPU process or one of its dependencies.
+    // Examples of such failures include GPU hardware failures, GPU driver
+    // failures, GPU library failures, GPU process programming errors, and so
+    // on.
+    kPlatformFailureError,
+  };
+
+  // Interface for clients that use VideoEncodeAccelerator.
+  class MEDIA_EXPORT Client {
+   public:
+    // Callback to notify client that encoder has been successfully initialized.
+    virtual void NotifyInitializeDone() = 0;
+
+    // Callback to tell the client what size of frames and buffers to provide
+    // for input and output.  The VEA disclaims use or ownership of all
+    // previously provided buffers once this callback is made.
+    // Parameters:
+    //  |input_count| is the number of input VideoFrames required for encoding.
+    //  The client should be prepared to feed at least this many frames into the
+    //  encoder before being returned any input frames, since the encoder may
+    //  need to hold onto some subset of inputs as reference pictures.
+    //  |input_coded_size| is the logical size of the input frames (as reported
+    //  by VideoFrame::coded_size()) to encode, in pixels.  The encoder may have
+    //  hardware alignment requirements that make this different from
+    //  |input_visible_size|, as requested in Initialize(), in which case the
+    //  input VideoFrame to Encode() should be padded appropriately.
+    //  |output_buffer_size| is the required size of output buffers for this
+    //  encoder in bytes.
+    virtual void RequireBitstreamBuffers(unsigned int input_count,
+                                         const gfx::Size& input_coded_size,
+                                         size_t output_buffer_size) = 0;
+
+    // Callback to deliver encoded bitstream buffers.  Ownership of the buffer
+    // is transferred back to the VEA::Client once this callback is made.
+    // Parameters:
+    //  |bitstream_buffer_id| is the id of the buffer that is ready.
+    //  |payload_size| is the byte size of the used portion of the buffer.
+    //  |key_frame| is true if this delivered frame is a keyframe.
+    virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
+                                      size_t payload_size,
+                                      bool key_frame) = 0;
+
+    // Error notification callback.
+    virtual void NotifyError(Error error) = 0;
+
+   protected:
+    // Clients are not owned by VEA instances and should not be deleted through
+    // these pointers.
+    virtual ~Client() {}
+  };
+
+  // Video encoder functions.
+
+  // Initialize the video encoder with a specific configuration.  Called once
+  // per encoder construction.
+  // Parameters:
+  //  |input_format| is the frame format of the input stream (as would be
+  //  reported by VideoFrame::format() for frames passed to Encode()).
+  //  |input_visible_size| is the resolution of the input stream (as would be
+  //  reported by VideoFrame::visible_rect().size() for frames passed to
+  //  Encode()).
+  //  |output_profile| is the codec profile of the encoded output stream.
+  //  |initial_bitrate| is the initial bitrate of the encoded output stream,
+  //  in bits per second.
+  // TODO(sheu): handle resolution changes.  http://crbug.com/249944
+  virtual void Initialize(media::VideoFrame::Format input_format,
+                          const gfx::Size& input_visible_size,
+                          VideoCodecProfile output_profile,
+                          uint32 initial_bitrate) = 0;
+
+  // Encodes the given frame.
+  // Parameters:
+  //  |frame| is the VideoFrame that is to be encoded.
+  //  |force_keyframe| forces the encoding of a keyframe for this frame.
+  virtual void Encode(const scoped_refptr<VideoFrame>& frame,
+                      bool force_keyframe) = 0;
+
+  // Send a bitstream buffer to the encoder to be used for storing future
+  // encoded output.  Each call here with a given |buffer| will cause the buffer
+  // to be filled once, then returned with BitstreamBufferReady().
+  // Parameters:
+  //  |buffer| is the bitstream buffer to use for output.
+  virtual void UseOutputBitstreamBuffer(const BitstreamBuffer& buffer) = 0;
+
+  // Request a change to the encoding parameters.  This is only a request,
+  // fulfilled on a best-effort basis.
+  // Parameters:
+  //  |bitrate| is the requested new bitrate, in bits per second.
+  //  |framerate| is the requested new framerate, in frames per second.
+  virtual void RequestEncodingParametersChange(uint32 bitrate,
+                                               uint32 framerate) = 0;
+
+  // Destroys the encoder: all pending inputs and outputs are dropped
+  // immediately and the component is freed.  This call may asynchronously free
+  // system resources, but its client-visible effects are synchronous.  After
+  // this method returns no more callbacks will be made on the client.  Deletes
+  // |this| unconditionally, so make sure to drop all pointers to it!
+  virtual void Destroy() = 0;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_VIDEO_VIDEO_ENCODE_ACCELERATOR_H_
diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc
index f83a365..9991d6b 100644
--- a/media/webm/webm_cluster_parser.cc
+++ b/media/webm/webm_cluster_parser.cc
@@ -214,7 +214,7 @@
 
   // Sign extend negative timecode offsets.
   if (timecode & 0x8000)
-    timecode |= (-1 << 16);
+    timecode |= ~0xffff;
 
   const uint8* frame_data = buf + 4;
   int frame_size = size - (frame_data - buf);
@@ -277,6 +277,8 @@
     return false;
   }
 
+  // TODO(acolwell): Should relative negative timecode offsets be rejected?  Or
+  // only when the absolute timecode is negative?  See http://crbug.com/271794
   if (timecode < 0) {
     MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset "
                        << timecode;
diff --git a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
index 9d415c9..c002b98 100644
--- a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
+++ b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
@@ -35,16 +35,6 @@
     },
     {
       "archives": [],
-      "description": "Chrome 24 bundle, revision xxxxx",
-      "name": "pepper_24",
-      "recommended": "no",
-      "repath": "pepper_24",
-      "revision": 0,
-      "stability": "post_stable",
-      "version": 24
-    },
-    {
-      "archives": [],
       "description": "Chrome 25 bundle, revision xxxxx",
       "name": "pepper_25",
       "recommended": "no",
@@ -67,20 +57,20 @@
       "archives": [],
       "description": "Chrome 27 bundle, revision xxxxx",
       "name": "pepper_27",
-      "recommended": "yes",
+      "recommended": "no",
       "repath": "pepper_27",
       "revision": 0,
-      "stability": "stable",
+      "stability": "post_stable",
       "version": 27
     },
     {
       "archives": [],
       "description": "Chrome 28 bundle, revision xxxxx",
       "name": "pepper_28",
-      "recommended": "no",
+      "recommended": "yes",
       "repath": "pepper_28",
       "revision": 0,
-      "stability": "beta",
+      "stability": "stable",
       "version": 28
     },
     {
@@ -90,11 +80,21 @@
       "recommended": "no",
       "repath": "pepper_29",
       "revision": 0,
-      "stability": "dev",
+      "stability": "beta",
       "version": 29
     },
     {
       "archives": [],
+      "description": "Chrome 30 bundle, revision xxxxx",
+      "name": "pepper_30",
+      "recommended": "no",
+      "repath": "pepper_30",
+      "revision": 0,
+      "stability": "dev",
+      "version": 30
+    },
+    {
+      "archives": [],
       "description": "Chrome Canary",
       "name": "pepper_canary",
       "recommended": "no",
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index a210f4a..96fb7f4 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -1,622 +1,85 @@
 AUTHORS
 COPYING
-examples/api/audio/audio.cc
-examples/api/audio/background.js
-examples/api/audio/common.js
-examples/api/audio/example.js
-examples/api/audio/icon128.png
-examples/api/audio/index.html
-[win]examples/api/audio/make.bat
-examples/api/audio/Makefile
-examples/api/audio/manifest.json
-examples/api/core/background.js
-examples/api/core/common.js
-examples/api/core/core.cc
-examples/api/core/example.js
-examples/api/core/icon128.png
-examples/api/core/index.html
-[win]examples/api/core/make.bat
-examples/api/core/Makefile
-examples/api/core/manifest.json
-examples/api/file_io/background.js
-examples/api/file_io/common.js
-examples/api/file_io/example.js
-examples/api/file_io/file_io.cc
-examples/api/file_io/icon128.png
-examples/api/file_io/index.html
-[win]examples/api/file_io/make.bat
-examples/api/file_io/Makefile
-examples/api/file_io/manifest.json
-examples/api/gamepad/background.js
-examples/api/gamepad/common.js
-examples/api/gamepad/gamepad.cc
-examples/api/gamepad/icon128.png
-examples/api/gamepad/index.html
-[win]examples/api/gamepad/make.bat
-examples/api/gamepad/Makefile
-examples/api/gamepad/manifest.json
-examples/api/graphics_3d/background.js
-examples/api/graphics_3d/common.js
-examples/api/graphics_3d/fragment_shader_es2.frag
-examples/api/graphics_3d/graphics_3d.cc
-examples/api/graphics_3d/hello.raw
-examples/api/graphics_3d/icon128.png
-examples/api/graphics_3d/index.html
-[win]examples/api/graphics_3d/make.bat
-examples/api/graphics_3d/Makefile
-examples/api/graphics_3d/manifest.json
-examples/api/graphics_3d/matrix.cc
-examples/api/graphics_3d/matrix.h
-examples/api/graphics_3d/vertex_shader_es2.vert
-examples/api/input_event/background.js
-examples/api/input_event/common.js
-examples/api/input_event/custom_events.cc
-examples/api/input_event/custom_events.h
-examples/api/input_event/example.js
-examples/api/input_event/icon128.png
-examples/api/input_event/index.html
-examples/api/input_event/input_event.cc
-[win]examples/api/input_event/make.bat
-examples/api/input_event/Makefile
-examples/api/input_event/manifest.json
-examples/api/input_event/shared_queue.h
+examples/api/audio/*
+examples/api/core/*
+examples/api/file_io/*
+examples/api/gamepad/*
+examples/api/graphics_3d/*
+examples/api/input_event/*
 [win]examples/api/make.bat
 examples/api/Makefile
-examples/api/mouse_lock/background.js
-examples/api/mouse_lock/common.js
-examples/api/mouse_lock/icon128.png
-examples/api/mouse_lock/index.html
-[win]examples/api/mouse_lock/make.bat
-examples/api/mouse_lock/Makefile
-examples/api/mouse_lock/manifest.json
-examples/api/mouse_lock/mouse_lock.cc
-examples/api/mouse_lock/mouse_lock.h
-examples/api/socket/background.js
-examples/api/socket/common.js
-examples/api/socket/example.js
-examples/api/socket/icon128.png
-examples/api/socket/index.html
-[win]examples/api/socket/make.bat
-examples/api/socket/Makefile
-examples/api/socket/manifest.json
-examples/api/socket/socket.cc
-examples/api/url_loader/background.js
-examples/api/url_loader/common.js
-examples/api/url_loader/example.js
-examples/api/url_loader/icon128.png
-examples/api/url_loader/index.html
-[win]examples/api/url_loader/make.bat
-examples/api/url_loader/Makefile
-examples/api/url_loader/manifest.json
-examples/api/url_loader/url_loader.cc
-examples/api/url_loader/url_loader_handler.cc
-examples/api/url_loader/url_loader_handler.h
-examples/api/url_loader/url_loader_success.html
-examples/api/var_array_buffer/background.js
-examples/api/var_array_buffer/common.js
-examples/api/var_array_buffer/example.js
-examples/api/var_array_buffer/icon128.png
-examples/api/var_array_buffer/index.html
-[win]examples/api/var_array_buffer/make.bat
-examples/api/var_array_buffer/Makefile
-examples/api/var_array_buffer/manifest.json
-examples/api/var_array_buffer/var_array_buffer.cc
-examples/api/websocket/background.js
-examples/api/websocket/common.js
-examples/api/websocket/example.js
-examples/api/websocket/icon128.png
-examples/api/websocket/index.html
-[win]examples/api/websocket/make.bat
-examples/api/websocket/Makefile
-examples/api/websocket/manifest.json
-examples/api/websocket/websocket.cc
+examples/api/mouse_lock/*
+examples/api/socket/*
+examples/api/url_loader/*
+examples/api/var_array_buffer/*
+examples/api/websocket/*
 examples/button_close.png
 examples/button_close_hover.png
-examples/demo/drive/background.js
-examples/demo/drive/common.js
-examples/demo/drive/drive.cc
-examples/demo/drive/example.js
-examples/demo/drive/icon128.png
-examples/demo/drive/index.html
-[win]examples/demo/drive/make.bat
-examples/demo/drive/Makefile
-examples/demo/drive/manifest.json
-examples/demo/earth/background.js
-examples/demo/earth/common.js
-examples/demo/earth/earth.cc
-examples/demo/earth/earth.jpg
-examples/demo/earth/earthnight.jpg
-examples/demo/earth/example.js
-examples/demo/earth/icon128.png
-examples/demo/earth/index.html
-[win]examples/demo/earth/make.bat
-examples/demo/earth/Makefile
-examples/demo/earth/manifest.json
-examples/demo/flock/background.js
-examples/demo/flock/common.js
-examples/demo/flock/flock.cc
-examples/demo/flock/goose.cc
-examples/demo/flock/goose.h
-examples/demo/flock/icon128.png
-examples/demo/flock/images/flock_green.raw
-examples/demo/flock/index.html
-[win]examples/demo/flock/make.bat
-examples/demo/flock/Makefile
-examples/demo/flock/manifest.json
-examples/demo/flock/sprite.cc
-examples/demo/flock/sprite.h
-examples/demo/flock/vector2.h
-examples/demo/life/background.js
-examples/demo/life/common.js
-examples/demo/life/icon128.png
-examples/demo/life/index.html
-examples/demo/life/life.c
-[win]examples/demo/life/make.bat
-examples/demo/life/Makefile
-examples/demo/life/manifest.json
+examples/demo/drive/*
+examples/demo/earth/*
+examples/demo/flock/*
+examples/demo/life/*
 [win]examples/demo/make.bat
 examples/demo/Makefile
-examples/demo/nacl_io/background.js
-examples/demo/nacl_io/common.js
-examples/demo/nacl_io/example.js
-examples/demo/nacl_io/handlers.c
-examples/demo/nacl_io/handlers.h
-examples/demo/nacl_io/icon128.png
-examples/demo/nacl_io/index.html
-[win]examples/demo/nacl_io/make.bat
-examples/demo/nacl_io/Makefile
-examples/demo/nacl_io/manifest.json
-examples/demo/nacl_io/nacl_io_demo.c
-examples/demo/nacl_io/nacl_io_demo.h
-examples/demo/nacl_io/queue.c
-examples/demo/nacl_io/queue.h
-examples/demo/pi_generator/background.js
-examples/demo/pi_generator/common.js
-examples/demo/pi_generator/example.js
-examples/demo/pi_generator/icon128.png
-examples/demo/pi_generator/index.html
-[win]examples/demo/pi_generator/make.bat
-examples/demo/pi_generator/Makefile
-examples/demo/pi_generator/manifest.json
-examples/demo/pi_generator/pi_generator.cc
-examples/demo/voronoi/background.js
-examples/demo/voronoi/common.js
-examples/demo/voronoi/example.js
-examples/demo/voronoi/icon128.png
-examples/demo/voronoi/index.html
-[win]examples/demo/voronoi/make.bat
-examples/demo/voronoi/Makefile
-examples/demo/voronoi/manifest.json
-examples/demo/voronoi/voronoi.cc
+examples/demo/nacl_io/*
+examples/demo/pi_generator/*
+examples/demo/voronoi/*
 examples/favicon.ico
-examples/getting_started/hello_world/background.js
-examples/getting_started/hello_world/common.js
-examples/getting_started/hello_world/example.js
-examples/getting_started/hello_world/hello_world.c
-examples/getting_started/hello_world/icon128.png
-examples/getting_started/hello_world/index.html
-[win]examples/getting_started/hello_world/make.bat
-examples/getting_started/hello_world/Makefile
-examples/getting_started/hello_world/manifest.json
+examples/getting_started/hello_world/*
 [win]examples/getting_started/make.bat
 examples/getting_started/Makefile
-examples/getting_started/simple_hello_world/background.js
-examples/getting_started/simple_hello_world/common.js
-examples/getting_started/simple_hello_world/example.js
-examples/getting_started/simple_hello_world/hello_world.c
-examples/getting_started/simple_hello_world/icon128.png
-examples/getting_started/simple_hello_world/index.html
-[win]examples/getting_started/simple_hello_world/make.bat
-examples/getting_started/simple_hello_world/Makefile
-examples/getting_started/simple_hello_world/manifest.json
+examples/getting_started/simple_hello_world/*
 examples/httpd.cmd
 examples/index.css
 examples/index.html
 examples/index.js
 [win]examples/make.bat
 examples/Makefile
-examples/tutorial/debugging/background.js
-examples/tutorial/debugging/common.js
-examples/tutorial/debugging/debugging.c
-examples/tutorial/debugging/example.js
-examples/tutorial/debugging/icon128.png
-examples/tutorial/debugging/index.html
-[win]examples/tutorial/debugging/make.bat
-examples/tutorial/debugging/Makefile
-examples/tutorial/debugging/manifest.json
-examples/tutorial/dlopen/background.js
-examples/tutorial/dlopen/common.js
-examples/tutorial/dlopen/dlopen.cc
-examples/tutorial/dlopen/eightball.cc
-examples/tutorial/dlopen/eightball.h
-examples/tutorial/dlopen/example.js
-examples/tutorial/dlopen/icon128.png
-examples/tutorial/dlopen/index.html
-[win]examples/tutorial/dlopen/make.bat
-examples/tutorial/dlopen/Makefile
-examples/tutorial/dlopen/manifest.json
-examples/tutorial/dlopen/reverse.cc
-examples/tutorial/dlopen/reverse.h
-examples/tutorial/load_progress/background.js
-examples/tutorial/load_progress/common.js
-examples/tutorial/load_progress/example.js
-examples/tutorial/load_progress/icon128.png
-examples/tutorial/load_progress/index.html
-examples/tutorial/load_progress/load_progress.cc
-[win]examples/tutorial/load_progress/make.bat
-examples/tutorial/load_progress/Makefile
-examples/tutorial/load_progress/manifest.json
+examples/tutorial/debugging/*
+examples/tutorial/dlopen/*
+examples/tutorial/load_progress/*
 [win]examples/tutorial/make.bat
 examples/tutorial/Makefile
-examples/tutorial/testing/background.js
-examples/tutorial/testing/common.js
-examples/tutorial/testing/example.js
-examples/tutorial/testing/icon128.png
-examples/tutorial/testing/index.html
-[win]examples/tutorial/testing/make.bat
-examples/tutorial/testing/Makefile
-examples/tutorial/testing/manifest.json
-examples/tutorial/testing/testing.cc
-include/error_handling/error_handling.h
-include/error_handling/string_stream.h
-include/GLES2/gl2.h
-include/GLES2/gl2ext.h
-include/GLES2/gl2platform.h
-include/gmock/gmock-actions.h
-include/gmock/gmock-cardinalities.h
-include/gmock/gmock-generated-actions.h
-include/gmock/gmock-generated-actions.h.pump
-include/gmock/gmock-generated-function-mockers.h
-include/gmock/gmock-generated-function-mockers.h.pump
-include/gmock/gmock-generated-matchers.h
-include/gmock/gmock-generated-matchers.h.pump
-include/gmock/gmock-generated-nice-strict.h
-include/gmock/gmock-generated-nice-strict.h.pump
-include/gmock/gmock-matchers.h
-include/gmock/gmock-more-actions.h
-include/gmock/gmock-spec-builders.h
-include/gmock/gmock.h
-include/gmock/internal/gmock-generated-internal-utils.h
-include/gmock/internal/gmock-generated-internal-utils.h.pump
-include/gmock/internal/gmock-internal-utils.h
-include/gmock/internal/gmock-port.h
-include/gtest/gtest-death-test.h
-include/gtest/gtest-message.h
-include/gtest/gtest-param-test.h
-include/gtest/gtest-printers.h
-include/gtest/gtest-spi.h
-include/gtest/gtest-test-part.h
-include/gtest/gtest-typed-test.h
-include/gtest/gtest.h
-include/gtest/gtest_pred_impl.h
-include/gtest/gtest_prod.h
-include/gtest/internal/gtest-death-test-internal.h
-include/gtest/internal/gtest-filepath.h
-include/gtest/internal/gtest-internal.h
-include/gtest/internal/gtest-linked_ptr.h
-include/gtest/internal/gtest-param-util-generated.h
-include/gtest/internal/gtest-param-util.h
-include/gtest/internal/gtest-port.h
-include/gtest/internal/gtest-string.h
-include/gtest/internal/gtest-tuple.h
-include/gtest/internal/gtest-type-util.h
-include/gtest/internal/src/gtest-internal-inl.h
-include/json/assertions.h
-include/json/autolink.h
-include/json/config.h
-include/json/features.h
-include/json/forwards.h
-include/json/json.h
-include/json/reader.h
-include/json/value.h
-include/json/writer.h
-include/KHR/khrplatform.h
-include/nacl_io/error.h
-include/nacl_io/event_emitter.h
-include/nacl_io/event_listener.h
-include/nacl_io/host_resolver.h
-include/nacl_io/inode_pool.h
-include/nacl_io/ioctl.h
-include/nacl_io/kernel_handle.h
-include/nacl_io/kernel_intercept.h
-include/nacl_io/kernel_object.h
-include/nacl_io/kernel_proxy.h
-include/nacl_io/kernel_wrap.h
-include/nacl_io/kernel_wrap_real.h
-include/nacl_io/mount.h
-include/nacl_io/mount_dev.h
-include/nacl_io/mount_factory.h
-include/nacl_io/mount_html5fs.h
-include/nacl_io/mount_http.h
-include/nacl_io/mount_mem.h
-include/nacl_io/mount_node.h
-include/nacl_io/mount_node_char.h
-include/nacl_io/mount_node_dir.h
-include/nacl_io/mount_node_html5fs.h
-include/nacl_io/mount_node_http.h
-include/nacl_io/mount_node_mem.h
-include/nacl_io/mount_node_tty.h
-include/nacl_io/mount_passthrough.h
-include/nacl_io/nacl_io.h
-include/nacl_io/osdirent.h
-include/nacl_io/osinttypes.h
-include/nacl_io/osmman.h
-include/nacl_io/ossocket.h
-include/nacl_io/osstat.h
-include/nacl_io/ostermios.h
-include/nacl_io/ostime.h
-include/nacl_io/ostypes.h
-include/nacl_io/osunistd.h
-include/nacl_io/osutime.h
-include/nacl_io/path.h
-include/nacl_io/pepper/all_interfaces.h
-include/nacl_io/pepper/define_empty_macros.h
-include/nacl_io/pepper/undef_macros.h
-include/nacl_io/pepper_interface.h
-include/nacl_io/real_pepper_interface.h
-include/nacl_io/typed_mount_factory.h
-include/newlib/arpa/inet.h
-include/newlib/netdb.h
-include/newlib/netinet/in.h
-include/newlib/netinet/tcp.h
-include/newlib/netinet6/in6.h
-include/newlib/poll.h
-include/newlib/sys/mount.h
-include/newlib/sys/select.h
-include/newlib/sys/socket.h
-include/newlib/sys/termios.h
-include/newlib/sys/utsname.h
-include/pnacl/arpa/inet.h
-include/pnacl/netdb.h
-include/pnacl/netinet/in.h
-include/pnacl/netinet/tcp.h
-include/pnacl/netinet6/in6.h
-include/pnacl/poll.h
-include/pnacl/sys/mount.h
-include/pnacl/sys/select.h
-include/pnacl/sys/socket.h
-include/pnacl/sys/termios.h
-include/pnacl/sys/utsname.h
-include/ppapi/c/dev/deprecated_bool.h
-include/ppapi/c/dev/pp_cursor_type_dev.h
-include/ppapi/c/dev/pp_print_settings_dev.h
-include/ppapi/c/dev/pp_video_capture_dev.h
-include/ppapi/c/dev/pp_video_dev.h
-include/ppapi/c/dev/ppb_audio_input_dev.h
-include/ppapi/c/dev/ppb_buffer_dev.h
-include/ppapi/c/dev/ppb_char_set_dev.h
-include/ppapi/c/dev/ppb_crypto_dev.h
-include/ppapi/c/dev/ppb_cursor_control_dev.h
-include/ppapi/c/dev/ppb_device_ref_dev.h
-include/ppapi/c/dev/ppb_file_chooser_dev.h
-include/ppapi/c/dev/ppb_find_dev.h
-include/ppapi/c/dev/ppb_font_dev.h
-include/ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h
-include/ppapi/c/dev/ppb_graphics_2d_dev.h
-include/ppapi/c/dev/ppb_ime_input_event_dev.h
-include/ppapi/c/dev/ppb_keyboard_input_event_dev.h
-include/ppapi/c/dev/ppb_memory_dev.h
-include/ppapi/c/dev/ppb_opengles2ext_dev.h
-include/ppapi/c/dev/ppb_printing_dev.h
-include/ppapi/c/dev/ppb_resource_array_dev.h
-include/ppapi/c/dev/ppb_scrollbar_dev.h
-include/ppapi/c/dev/ppb_testing_dev.h
-include/ppapi/c/dev/ppb_text_input_dev.h
-include/ppapi/c/dev/ppb_trace_event_dev.h
-include/ppapi/c/dev/ppb_truetype_font_dev.h
-include/ppapi/c/dev/ppb_url_util_dev.h
-include/ppapi/c/dev/ppb_var_deprecated.h
-include/ppapi/c/dev/ppb_video_capture_dev.h
-include/ppapi/c/dev/ppb_video_decoder_dev.h
-include/ppapi/c/dev/ppb_view_dev.h
-include/ppapi/c/dev/ppb_widget_dev.h
-include/ppapi/c/dev/ppb_zoom_dev.h
-include/ppapi/c/dev/ppp_class_deprecated.h
-include/ppapi/c/dev/ppp_find_dev.h
-include/ppapi/c/dev/ppp_network_state_dev.h
-include/ppapi/c/dev/ppp_printing_dev.h
-include/ppapi/c/dev/ppp_scrollbar_dev.h
-include/ppapi/c/dev/ppp_selection_dev.h
-include/ppapi/c/dev/ppp_text_input_dev.h
-include/ppapi/c/dev/ppp_video_capture_dev.h
-include/ppapi/c/dev/ppp_video_decoder_dev.h
-include/ppapi/c/dev/ppp_widget_dev.h
-include/ppapi/c/dev/ppp_zoom_dev.h
-include/ppapi/c/extensions/dev/ppb_ext_alarms_dev.h
-include/ppapi/c/extensions/dev/ppb_ext_events_dev.h
-include/ppapi/c/extensions/dev/ppb_ext_socket_dev.h
-include/ppapi/c/pp_array_output.h
-include/ppapi/c/pp_bool.h
-include/ppapi/c/pp_completion_callback.h
-include/ppapi/c/pp_directory_entry.h
-include/ppapi/c/pp_errors.h
-include/ppapi/c/pp_file_info.h
-include/ppapi/c/pp_graphics_3d.h
-include/ppapi/c/pp_input_event.h
-include/ppapi/c/pp_instance.h
-include/ppapi/c/pp_macros.h
-include/ppapi/c/pp_module.h
-include/ppapi/c/pp_point.h
-include/ppapi/c/pp_rect.h
-include/ppapi/c/pp_resource.h
-include/ppapi/c/pp_size.h
-include/ppapi/c/pp_stdint.h
-include/ppapi/c/pp_time.h
-include/ppapi/c/pp_touch_point.h
-include/ppapi/c/pp_var.h
-include/ppapi/c/ppb.h
-include/ppapi/c/ppb_audio.h
-include/ppapi/c/ppb_audio_config.h
-include/ppapi/c/ppb_console.h
-include/ppapi/c/ppb_core.h
-include/ppapi/c/ppb_file_io.h
-include/ppapi/c/ppb_file_ref.h
-include/ppapi/c/ppb_file_system.h
-include/ppapi/c/ppb_fullscreen.h
-include/ppapi/c/ppb_gamepad.h
-include/ppapi/c/ppb_graphics_2d.h
-include/ppapi/c/ppb_graphics_3d.h
-include/ppapi/c/ppb_host_resolver.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_message_loop.h
-include/ppapi/c/ppb_messaging.h
-include/ppapi/c/ppb_mouse_cursor.h
-include/ppapi/c/ppb_mouse_lock.h
-include/ppapi/c/ppb_net_address.h
-include/ppapi/c/ppb_network_proxy.h
-include/ppapi/c/ppb_opengles2.h
-include/ppapi/c/ppb_tcp_socket.h
-include/ppapi/c/ppb_text_input_controller.h
-include/ppapi/c/ppb_udp_socket.h
-include/ppapi/c/ppb_url_loader.h
-include/ppapi/c/ppb_url_request_info.h
-include/ppapi/c/ppb_url_response_info.h
-include/ppapi/c/ppb_var.h
-include/ppapi/c/ppb_var_array.h
-include/ppapi/c/ppb_var_array_buffer.h
-include/ppapi/c/ppb_var_dictionary.h
-include/ppapi/c/ppb_view.h
-include/ppapi/c/ppb_websocket.h
-include/ppapi/c/ppp.h
-include/ppapi/c/ppp_graphics_3d.h
-include/ppapi/c/ppp_input_event.h
-include/ppapi/c/ppp_instance.h
-include/ppapi/c/ppp_messaging.h
-include/ppapi/c/ppp_mouse_lock.h
-include/ppapi/c/private/pp_file_handle.h
-include/ppapi/c/private/ppb_ext_crx_file_system_private.h
-include/ppapi/c/private/ppb_file_io_private.h
-include/ppapi/c/private/ppb_file_ref_private.h
-include/ppapi/c/private/ppb_host_resolver_private.h
-include/ppapi/c/private/ppb_net_address_private.h
-include/ppapi/c/private/ppb_tcp_server_socket_private.h
-include/ppapi/c/private/ppb_tcp_socket_private.h
-include/ppapi/c/private/ppb_udp_socket_private.h
-include/ppapi/c/private/ppb_x509_certificate_private.h
-include/ppapi/cpp/array_output.h
-include/ppapi/cpp/audio.h
-include/ppapi/cpp/audio_config.h
-include/ppapi/cpp/completion_callback.h
-include/ppapi/cpp/core.h
-include/ppapi/cpp/dev/audio_input_dev.h
-include/ppapi/cpp/dev/buffer_dev.h
-include/ppapi/cpp/dev/crypto_dev.h
-include/ppapi/cpp/dev/cursor_control_dev.h
-include/ppapi/cpp/dev/device_ref_dev.h
-include/ppapi/cpp/dev/file_chooser_dev.h
-include/ppapi/cpp/dev/find_dev.h
-include/ppapi/cpp/dev/font_dev.h
-include/ppapi/cpp/dev/graphics_2d_dev.h
-include/ppapi/cpp/dev/ime_input_event_dev.h
-include/ppapi/cpp/dev/memory_dev.h
-include/ppapi/cpp/dev/printing_dev.h
-include/ppapi/cpp/dev/resource_array_dev.h
-include/ppapi/cpp/dev/scriptable_object_deprecated.h
-include/ppapi/cpp/dev/scrollbar_dev.h
-include/ppapi/cpp/dev/selection_dev.h
-include/ppapi/cpp/dev/text_input_dev.h
-include/ppapi/cpp/dev/truetype_font_dev.h
-include/ppapi/cpp/dev/url_util_dev.h
-include/ppapi/cpp/dev/video_capture_client_dev.h
-include/ppapi/cpp/dev/video_capture_dev.h
-include/ppapi/cpp/dev/video_decoder_client_dev.h
-include/ppapi/cpp/dev/video_decoder_dev.h
-include/ppapi/cpp/dev/view_dev.h
-include/ppapi/cpp/dev/widget_client_dev.h
-include/ppapi/cpp/dev/widget_dev.h
-include/ppapi/cpp/dev/zoom_dev.h
-include/ppapi/cpp/directory_entry.h
-include/ppapi/cpp/extensions/dev/alarms_dev.h
-include/ppapi/cpp/extensions/dev/events_dev.h
-include/ppapi/cpp/extensions/dev/socket_dev.h
-include/ppapi/cpp/extensions/dict_field.h
-include/ppapi/cpp/extensions/event_base.h
-include/ppapi/cpp/extensions/ext_output_traits.h
-include/ppapi/cpp/extensions/from_var_converter.h
-include/ppapi/cpp/extensions/optional.h
-include/ppapi/cpp/extensions/to_var_converter.h
-include/ppapi/cpp/file_io.h
-include/ppapi/cpp/file_ref.h
-include/ppapi/cpp/file_system.h
-include/ppapi/cpp/fullscreen.h
-include/ppapi/cpp/graphics_2d.h
-include/ppapi/cpp/graphics_3d.h
-include/ppapi/cpp/graphics_3d_client.h
-include/ppapi/cpp/host_resolver.h
-include/ppapi/cpp/image_data.h
-include/ppapi/cpp/input_event.h
-include/ppapi/cpp/instance.h
-include/ppapi/cpp/instance_handle.h
-include/ppapi/cpp/logging.h
-include/ppapi/cpp/message_loop.h
-include/ppapi/cpp/module.h
-include/ppapi/cpp/module_embedder.h
-include/ppapi/cpp/module_impl.h
-include/ppapi/cpp/mouse_cursor.h
-include/ppapi/cpp/mouse_lock.h
-include/ppapi/cpp/net_address.h
-include/ppapi/cpp/network_proxy.h
-include/ppapi/cpp/output_traits.h
-include/ppapi/cpp/pass_ref.h
-include/ppapi/cpp/point.h
-include/ppapi/cpp/private/ext_crx_file_system_private.h
-include/ppapi/cpp/private/file_io_private.h
-include/ppapi/cpp/private/host_resolver_private.h
-include/ppapi/cpp/private/net_address_private.h
-include/ppapi/cpp/private/pass_file_handle.h
-include/ppapi/cpp/private/tcp_server_socket_private.h
-include/ppapi/cpp/private/tcp_socket_private.h
-include/ppapi/cpp/private/udp_socket_private.h
-include/ppapi/cpp/private/x509_certificate_private.h
-include/ppapi/cpp/rect.h
-include/ppapi/cpp/resource.h
-include/ppapi/cpp/size.h
-include/ppapi/cpp/tcp_socket.h
-include/ppapi/cpp/text_input_controller.h
-include/ppapi/cpp/touch_point.h
-include/ppapi/cpp/udp_socket.h
-include/ppapi/cpp/url_loader.h
-include/ppapi/cpp/url_request_info.h
-include/ppapi/cpp/url_response_info.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/ppapi/cpp/view.h
-include/ppapi/cpp/websocket.h
-include/ppapi/gles2/gl2ext_ppapi.h
-include/ppapi/lib/gl/gles2/gl2ext_ppapi.h
-include/ppapi/utility/completion_callback_factory.h
-include/ppapi/utility/completion_callback_factory_thread_traits.h
-include/ppapi/utility/graphics/paint_aggregator.h
-include/ppapi/utility/graphics/paint_manager.h
-include/ppapi/utility/threading/lock.h
-include/ppapi/utility/threading/simple_thread.h
-include/ppapi/utility/websocket/websocket_api.h
-include/ppapi_simple/ps.h
-include/ppapi_simple/ps_context_2d.h
-include/ppapi_simple/ps_event.h
-include/ppapi_simple/ps_instance.h
-include/ppapi_simple/ps_interface.h
-include/ppapi_simple/ps_main.h
-include/sdk_util/atomicops.h
-include/sdk_util/auto_lock.h
-include/sdk_util/macros.h
-include/sdk_util/ref_object.h
-include/sdk_util/scoped_ref.h
-include/sdk_util/simple_lock.h
-include/sdk_util/thread_pool.h
-include/sdk_util/thread_safe_queue.h
-[win]include/win/config.h
-[win]include/win/context.h
-[win]include/win/implement.h
-[win]include/win/need_errno.h
+examples/tutorial/testing/*
+include/error_handling/*
+include/GLES2/*
+include/gmock/*
+include/gmock/internal/*
+include/gtest/*
+include/gtest/internal/*
+include/gtest/internal/src/*
+include/json/*
+include/KHR/*
+include/nacl_io/*
+include/nacl_io/pepper/*
+include/newlib/*
+include/newlib/arpa/*
+include/newlib/netinet/*
+include/newlib/netinet6/*
+include/newlib/sys/*
+include/pnacl/*
+include/pnacl/arpa/*
+include/pnacl/netinet/*
+include/pnacl/netinet6/*
+include/pnacl/sys/*
+include/ppapi/c/*
+include/ppapi/c/dev/*
+include/ppapi/c/extensions/dev/*
+include/ppapi/c/private/*
+include/ppapi/cpp/*
+include/ppapi/cpp/dev/*
+include/ppapi/cpp/extensions/*
+include/ppapi/cpp/private/*
+include/ppapi/gles2/*
+include/ppapi/lib/gl/gles2/*
+include/ppapi/utility/*
+include/ppapi/utility/graphics/*
+include/ppapi/utility/threading/*
+include/ppapi/utility/websocket/*
+include/ppapi_simple/*
+include/sdk_util/*
+[win]include/win/*
 include/win/poll.h
-[win]include/win/pthread.h
-[win]include/win/sched.h
-[win]include/win/semaphore.h
 [linux]lib/${PLATFORM}_host/Debug/libgmock.a
 [linux]lib/${PLATFORM}_host/Debug/libgtest.a
 [linux]lib/${PLATFORM}_host/Debug/libjsoncpp.a
@@ -803,373 +266,23 @@
 NOTICE
 README
 README.Makefiles
-src/error_handling/error_handling.c
-[win]src/error_handling/make.bat
-src/error_handling/Makefile
-src/error_handling/string_stream.c
-src/gmock/gmock-cardinalities.cc
-src/gmock/gmock-internal-utils.cc
-src/gmock/gmock-matchers.cc
-src/gmock/gmock-spec-builders.cc
-src/gmock/gmock.cc
-[win]src/gmock/make.bat
-src/gmock/Makefile
-src/gtest/gtest-death-test.cc
-src/gtest/gtest-filepath.cc
-src/gtest/gtest-port.cc
-src/gtest/gtest-printers.cc
-src/gtest/gtest-test-part.cc
-src/gtest/gtest-typed-test.cc
-src/gtest/gtest.cc
-src/gtest/gtest_main.cc
-[win]src/gtest/make.bat
-src/gtest/Makefile
-src/gtest/nacl_gtest_dummy_sys.cc
-src/jsoncpp/json_batchallocator.h
-src/jsoncpp/json_internalarray.inl
-src/jsoncpp/json_internalmap.inl
-src/jsoncpp/json_reader.cpp
-src/jsoncpp/json_tool.h
-src/jsoncpp/json_value.cpp
-src/jsoncpp/json_valueiterator.inl
-src/jsoncpp/json_writer.cpp
-src/jsoncpp/LICENSE
-[win]src/jsoncpp/make.bat
-src/jsoncpp/Makefile
-src/jsoncpp/README.chromium
+src/error_handling/*
+src/gmock/*
+src/gtest/*
+src/jsoncpp/*
 [win]src/make.bat
 src/Makefile
-src/nacl_io/event_emitter.cc
-src/nacl_io/event_listener.cc
-src/nacl_io/h_errno.cc
-src/nacl_io/host_resolver.cc
-src/nacl_io/kernel_handle.cc
-src/nacl_io/kernel_intercept.cc
-src/nacl_io/kernel_object.cc
-src/nacl_io/kernel_proxy.cc
-src/nacl_io/kernel_wrap_glibc.cc
-src/nacl_io/kernel_wrap_newlib.cc
-src/nacl_io/kernel_wrap_win.cc
-[win]src/nacl_io/make.bat
-src/nacl_io/Makefile
-src/nacl_io/mount.cc
-src/nacl_io/mount_dev.cc
-src/nacl_io/mount_html5fs.cc
-src/nacl_io/mount_http.cc
-src/nacl_io/mount_mem.cc
-src/nacl_io/mount_node.cc
-src/nacl_io/mount_node_dir.cc
-src/nacl_io/mount_node_html5fs.cc
-src/nacl_io/mount_node_http.cc
-src/nacl_io/mount_node_mem.cc
-src/nacl_io/mount_node_tty.cc
-src/nacl_io/mount_passthrough.cc
-src/nacl_io/nacl_io.cc
-src/nacl_io/path.cc
-src/nacl_io/pepper_interface.cc
-src/nacl_io/real_pepper_interface.cc
-src/nacl_io/syscalls/accept.c
-src/nacl_io/syscalls/access.c
-src/nacl_io/syscalls/bind.c
-src/nacl_io/syscalls/chdir.c
-src/nacl_io/syscalls/chmod.c
-src/nacl_io/syscalls/chown.c
-src/nacl_io/syscalls/connect.c
-src/nacl_io/syscalls/fchown.c
-src/nacl_io/syscalls/fsync.c
-src/nacl_io/syscalls/ftruncate.c
-src/nacl_io/syscalls/getcwd.c
-src/nacl_io/syscalls/getdents.c
-src/nacl_io/syscalls/gethostbyname.c
-src/nacl_io/syscalls/getpeername.c
-src/nacl_io/syscalls/getsockname.c
-src/nacl_io/syscalls/getsockopt.c
-src/nacl_io/syscalls/getwd.c
-src/nacl_io/syscalls/herror.c
-src/nacl_io/syscalls/hstrerror.cc
-src/nacl_io/syscalls/htonl.c
-src/nacl_io/syscalls/htons.c
-src/nacl_io/syscalls/inet_ntoa.cc
-src/nacl_io/syscalls/inet_ntop.cc
-src/nacl_io/syscalls/ioctl.c
-src/nacl_io/syscalls/isatty.c
-src/nacl_io/syscalls/lchown.c
-src/nacl_io/syscalls/link.c
-src/nacl_io/syscalls/listen.c
-src/nacl_io/syscalls/mkdir.c
-src/nacl_io/syscalls/mount.c
-src/nacl_io/syscalls/ntohl.c
-src/nacl_io/syscalls/ntohs.c
-src/nacl_io/syscalls/poll.c
-src/nacl_io/syscalls/recv.c
-src/nacl_io/syscalls/recvfrom.c
-src/nacl_io/syscalls/recvmsg.c
-src/nacl_io/syscalls/remove.c
-src/nacl_io/syscalls/rmdir.c
-src/nacl_io/syscalls/select.c
-src/nacl_io/syscalls/send.c
-src/nacl_io/syscalls/sendmsg.c
-src/nacl_io/syscalls/sendto.c
-src/nacl_io/syscalls/setsockopt.c
-src/nacl_io/syscalls/shutdown.c
-src/nacl_io/syscalls/socket.c
-src/nacl_io/syscalls/socketpair.c
-src/nacl_io/syscalls/tcflush.c
-src/nacl_io/syscalls/tcgetattr.c
-src/nacl_io/syscalls/tcsetattr.c
-src/nacl_io/syscalls/umount.c
-src/nacl_io/syscalls/uname.c
-src/nacl_io/syscalls/unlink.c
-src/nacl_io/syscalls/utime.c
+src/nacl_io/*
+src/ppapi/*
 [win]src/ppapi/make.bat
 src/ppapi/Makefile
-src/ppapi/ppapi_externs.c
-src/ppapi_cpp/alarms_dev.cc
-src/ppapi_cpp/array_output.cc
-src/ppapi_cpp/audio.cc
-src/ppapi_cpp/audio_config.cc
-src/ppapi_cpp/audio_input_dev.cc
-src/ppapi_cpp/buffer_dev.cc
-src/ppapi_cpp/core.cc
-src/ppapi_cpp/crypto_dev.cc
-src/ppapi_cpp/cursor_control_dev.cc
-src/ppapi_cpp/device_ref_dev.cc
-src/ppapi_cpp/directory_entry.cc
-src/ppapi_cpp/event_base.cc
-src/ppapi_cpp/events_dev.cc
-src/ppapi_cpp/file_chooser_dev.cc
-src/ppapi_cpp/file_io.cc
-src/ppapi_cpp/file_ref.cc
-src/ppapi_cpp/file_system.cc
-src/ppapi_cpp/find_dev.cc
-src/ppapi_cpp/font_dev.cc
-src/ppapi_cpp/fullscreen.cc
-src/ppapi_cpp/graphics_2d.cc
-src/ppapi_cpp/graphics_2d_dev.cc
-src/ppapi_cpp/graphics_3d.cc
-src/ppapi_cpp/graphics_3d_client.cc
-src/ppapi_cpp/host_resolver.cc
-src/ppapi_cpp/image_data.cc
-src/ppapi_cpp/ime_input_event_dev.cc
-src/ppapi_cpp/input_event.cc
-src/ppapi_cpp/instance.cc
-src/ppapi_cpp/instance_handle.cc
-src/ppapi_cpp/lock.cc
-[win]src/ppapi_cpp/make.bat
-src/ppapi_cpp/Makefile
-src/ppapi_cpp/memory_dev.cc
-src/ppapi_cpp/message_loop.cc
-src/ppapi_cpp/module.cc
-src/ppapi_cpp/mouse_cursor.cc
-src/ppapi_cpp/mouse_lock.cc
-src/ppapi_cpp/net_address.cc
-src/ppapi_cpp/network_proxy.cc
-src/ppapi_cpp/paint_aggregator.cc
-src/ppapi_cpp/paint_manager.cc
-src/ppapi_cpp/ppp_entrypoints.cc
-src/ppapi_cpp/printing_dev.cc
-src/ppapi_cpp/rect.cc
-src/ppapi_cpp/resource.cc
-src/ppapi_cpp/resource_array_dev.cc
-src/ppapi_cpp/scriptable_object_deprecated.cc
-src/ppapi_cpp/scrollbar_dev.cc
-src/ppapi_cpp/selection_dev.cc
-src/ppapi_cpp/simple_thread.cc
-src/ppapi_cpp/socket_dev.cc
-src/ppapi_cpp/tcp_socket.cc
-src/ppapi_cpp/text_input_controller.cc
-src/ppapi_cpp/text_input_dev.cc
-src/ppapi_cpp/truetype_font_dev.cc
-src/ppapi_cpp/udp_socket.cc
-src/ppapi_cpp/url_loader.cc
-src/ppapi_cpp/url_request_info.cc
-src/ppapi_cpp/url_response_info.cc
-src/ppapi_cpp/url_util_dev.cc
-src/ppapi_cpp/var.cc
-src/ppapi_cpp/var_array.cc
-src/ppapi_cpp/var_array_buffer.cc
-src/ppapi_cpp/var_dictionary.cc
-src/ppapi_cpp/video_capture_client_dev.cc
-src/ppapi_cpp/video_capture_dev.cc
-src/ppapi_cpp/video_decoder_client_dev.cc
-src/ppapi_cpp/video_decoder_dev.cc
-src/ppapi_cpp/view.cc
-src/ppapi_cpp/view_dev.cc
-src/ppapi_cpp/websocket.cc
-src/ppapi_cpp/websocket_api.cc
-src/ppapi_cpp/widget_client_dev.cc
-src/ppapi_cpp/widget_dev.cc
-src/ppapi_cpp/zoom_dev.cc
-src/ppapi_cpp_private/ext_crx_file_system_private.cc
-src/ppapi_cpp_private/file_io_private.cc
-src/ppapi_cpp_private/host_resolver_private.cc
-[win]src/ppapi_cpp_private/make.bat
-src/ppapi_cpp_private/Makefile
-src/ppapi_cpp_private/net_address_private.cc
-src/ppapi_cpp_private/pass_file_handle.cc
-src/ppapi_cpp_private/tcp_server_socket_private.cc
-src/ppapi_cpp_private/tcp_socket_private.cc
-src/ppapi_cpp_private/udp_socket_private.cc
-src/ppapi_cpp_private/x509_certificate_private.cc
-src/ppapi_gles2/gl2ext_ppapi.c
-src/ppapi_gles2/gles2.c
-[win]src/ppapi_gles2/make.bat
-src/ppapi_gles2/Makefile
-[win]src/ppapi_simple/make.bat
-src/ppapi_simple/Makefile
-src/ppapi_simple/ps.cc
-src/ppapi_simple/ps_context_2d.cc
-src/ppapi_simple/ps_event.cc
-src/ppapi_simple/ps_instance.cc
-src/ppapi_simple/ps_interface.cc
-src/ppapi_simple/ps_main.cc
-[win]src/pthread/autostatic.c
-[win]src/pthread/cleanup.c
-[win]src/pthread/CONTRIBUTORS
-[win]src/pthread/COPYING
-[win]src/pthread/COPYING.LIB
-[win]src/pthread/create.c
-[win]src/pthread/errno.c
-[win]src/pthread/fork.c
-[win]src/pthread/global.c
-[win]src/pthread/MAINTAINERS
-[win]src/pthread/make.bat
-[win]src/pthread/Makefile
-[win]src/pthread/pthread_attr_destroy.c
-[win]src/pthread/pthread_attr_getdetachstate.c
-[win]src/pthread/pthread_attr_getinheritsched.c
-[win]src/pthread/pthread_attr_getschedparam.c
-[win]src/pthread/pthread_attr_getschedpolicy.c
-[win]src/pthread/pthread_attr_getscope.c
-[win]src/pthread/pthread_attr_getstackaddr.c
-[win]src/pthread/pthread_attr_getstacksize.c
-[win]src/pthread/pthread_attr_init.c
-[win]src/pthread/pthread_attr_setdetachstate.c
-[win]src/pthread/pthread_attr_setinheritsched.c
-[win]src/pthread/pthread_attr_setschedparam.c
-[win]src/pthread/pthread_attr_setschedpolicy.c
-[win]src/pthread/pthread_attr_setscope.c
-[win]src/pthread/pthread_attr_setstackaddr.c
-[win]src/pthread/pthread_attr_setstacksize.c
-[win]src/pthread/pthread_barrier_destroy.c
-[win]src/pthread/pthread_barrier_init.c
-[win]src/pthread/pthread_barrier_wait.c
-[win]src/pthread/pthread_barrierattr_destroy.c
-[win]src/pthread/pthread_barrierattr_getpshared.c
-[win]src/pthread/pthread_barrierattr_init.c
-[win]src/pthread/pthread_barrierattr_setpshared.c
-[win]src/pthread/pthread_cancel.c
-[win]src/pthread/pthread_cond_destroy.c
-[win]src/pthread/pthread_cond_init.c
-[win]src/pthread/pthread_cond_signal.c
-[win]src/pthread/pthread_cond_wait.c
-[win]src/pthread/pthread_condattr_destroy.c
-[win]src/pthread/pthread_condattr_getpshared.c
-[win]src/pthread/pthread_condattr_init.c
-[win]src/pthread/pthread_condattr_setpshared.c
-[win]src/pthread/pthread_delay_np.c
-[win]src/pthread/pthread_detach.c
-[win]src/pthread/pthread_equal.c
-[win]src/pthread/pthread_exit.c
-[win]src/pthread/pthread_getconcurrency.c
-[win]src/pthread/pthread_getschedparam.c
-[win]src/pthread/pthread_getspecific.c
-[win]src/pthread/pthread_getunique_np.c
-[win]src/pthread/pthread_getw32threadhandle_np.c
-[win]src/pthread/pthread_join.c
-[win]src/pthread/pthread_key_create.c
-[win]src/pthread/pthread_key_delete.c
-[win]src/pthread/pthread_kill.c
-[win]src/pthread/pthread_mutex_consistent.c
-[win]src/pthread/pthread_mutex_destroy.c
-[win]src/pthread/pthread_mutex_init.c
-[win]src/pthread/pthread_mutex_lock.c
-[win]src/pthread/pthread_mutex_timedlock.c
-[win]src/pthread/pthread_mutex_trylock.c
-[win]src/pthread/pthread_mutex_unlock.c
-[win]src/pthread/pthread_mutexattr_destroy.c
-[win]src/pthread/pthread_mutexattr_getkind_np.c
-[win]src/pthread/pthread_mutexattr_getpshared.c
-[win]src/pthread/pthread_mutexattr_getrobust.c
-[win]src/pthread/pthread_mutexattr_gettype.c
-[win]src/pthread/pthread_mutexattr_init.c
-[win]src/pthread/pthread_mutexattr_setkind_np.c
-[win]src/pthread/pthread_mutexattr_setpshared.c
-[win]src/pthread/pthread_mutexattr_setrobust.c
-[win]src/pthread/pthread_mutexattr_settype.c
-[win]src/pthread/pthread_num_processors_np.c
-[win]src/pthread/pthread_once.c
-[win]src/pthread/pthread_rwlock_destroy.c
-[win]src/pthread/pthread_rwlock_init.c
-[win]src/pthread/pthread_rwlock_rdlock.c
-[win]src/pthread/pthread_rwlock_timedrdlock.c
-[win]src/pthread/pthread_rwlock_timedwrlock.c
-[win]src/pthread/pthread_rwlock_tryrdlock.c
-[win]src/pthread/pthread_rwlock_trywrlock.c
-[win]src/pthread/pthread_rwlock_unlock.c
-[win]src/pthread/pthread_rwlock_wrlock.c
-[win]src/pthread/pthread_rwlockattr_destroy.c
-[win]src/pthread/pthread_rwlockattr_getpshared.c
-[win]src/pthread/pthread_rwlockattr_init.c
-[win]src/pthread/pthread_rwlockattr_setpshared.c
-[win]src/pthread/pthread_self.c
-[win]src/pthread/pthread_setcancelstate.c
-[win]src/pthread/pthread_setcanceltype.c
-[win]src/pthread/pthread_setconcurrency.c
-[win]src/pthread/pthread_setschedparam.c
-[win]src/pthread/pthread_setspecific.c
-[win]src/pthread/pthread_spin_destroy.c
-[win]src/pthread/pthread_spin_init.c
-[win]src/pthread/pthread_spin_lock.c
-[win]src/pthread/pthread_spin_trylock.c
-[win]src/pthread/pthread_spin_unlock.c
-[win]src/pthread/pthread_testcancel.c
-[win]src/pthread/pthread_timechange_handler_np.c
-[win]src/pthread/pthread_win32_attach_detach_np.c
-[win]src/pthread/ptw32_calloc.c
-[win]src/pthread/ptw32_callUserDestroyRoutines.c
-[win]src/pthread/ptw32_cond_check_need_init.c
-[win]src/pthread/ptw32_getprocessors.c
-[win]src/pthread/ptw32_is_attr.c
-[win]src/pthread/ptw32_MCS_lock.c
-[win]src/pthread/ptw32_mutex_check_need_init.c
-[win]src/pthread/ptw32_new.c
-[win]src/pthread/ptw32_processInitialize.c
-[win]src/pthread/ptw32_processTerminate.c
-[win]src/pthread/ptw32_relmillisecs.c
-[win]src/pthread/ptw32_reuse.c
-[win]src/pthread/ptw32_rwlock_cancelwrwait.c
-[win]src/pthread/ptw32_rwlock_check_need_init.c
-[win]src/pthread/ptw32_semwait.c
-[win]src/pthread/ptw32_spinlock_check_need_init.c
-[win]src/pthread/ptw32_threadDestroy.c
-[win]src/pthread/ptw32_threadStart.c
-[win]src/pthread/ptw32_throw.c
-[win]src/pthread/ptw32_timespec.c
-[win]src/pthread/ptw32_tkAssocCreate.c
-[win]src/pthread/ptw32_tkAssocDestroy.c
+src/ppapi_cpp/*
+src/ppapi_cpp_private/*
+src/ppapi_gles2/*
+src/ppapi_simple/*
+[win]src/pthread/*
 [win]src/pthread/README
-[win]src/pthread/sched_get_priority_max.c
-[win]src/pthread/sched_get_priority_min.c
-[win]src/pthread/sched_getscheduler.c
-[win]src/pthread/sched_setscheduler.c
-[win]src/pthread/sched_yield.c
-[win]src/pthread/sem_close.c
-[win]src/pthread/sem_destroy.c
-[win]src/pthread/sem_getvalue.c
-[win]src/pthread/sem_init.c
-[win]src/pthread/sem_open.c
-[win]src/pthread/sem_post.c
-[win]src/pthread/sem_post_multiple.c
-[win]src/pthread/sem_timedwait.c
-[win]src/pthread/sem_trywait.c
-[win]src/pthread/sem_unlink.c
-[win]src/pthread/sem_wait.c
-[win]src/pthread/signal.c
-[win]src/pthread/w32_CancelableWait.c
-[win]src/sdk_util/make.bat
-src/sdk_util/Makefile
-src/sdk_util/thread_pool.cc
+src/sdk_util/*
 toolchain/${PLATFORM}_arm_newlib/*
 toolchain/${PLATFORM}_arm_newlib/arm-nacl/include/irt.h
 toolchain/${PLATFORM}_arm_newlib/arm-nacl/include/irt_ppapi.h
diff --git a/native_client_sdk/src/build_tools/test.js b/native_client_sdk/src/build_tools/test.js
new file mode 100644
index 0000000..d6ba6d8
--- /dev/null
+++ b/native_client_sdk/src/build_tools/test.js
@@ -0,0 +1,6 @@
+// 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 is a dummy JavaScript file that will be loaded by browser_tester if no
+// example-specific test.js is found.
diff --git a/native_client_sdk/src/build_tools/test_projects.py b/native_client_sdk/src/build_tools/test_projects.py
index a742923..04fe73d 100755
--- a/native_client_sdk/src/build_tools/test_projects.py
+++ b/native_client_sdk/src/build_tools/test_projects.py
@@ -13,7 +13,7 @@
 import build_version
 import parse_dsc
 
-from build_paths import OUT_DIR, SRC_DIR, SDK_SRC_DIR
+from build_paths import OUT_DIR, SRC_DIR, SDK_SRC_DIR, SCRIPT_DIR
 
 sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
 import getos
@@ -61,9 +61,6 @@
     {'name': 'graphics_3d', 'platform': ('win', 'linux')},
 ]
 
-DEFAULT_RETRY_ON_FAILURE_TIMES = 3
-
-
 def ValidateToolchains(toolchains):
   invalid_toolchains = set(toolchains) - set(ALL_TOOLCHAINS)
   if invalid_toolchains:
@@ -77,6 +74,12 @@
   return os.path.join(path, desc['NAME'])
 
 
+def GetRepoServingDirForProject(desc):
+  # This differs from GetServingDirForProject, because it returns the location
+  # within the Chrome repository of the project, not the "pepperdir".
+  return os.path.dirname(desc['FILEPATH'])
+
+
 def GetExecutableDirForProject(desc, toolchain, config):
   return os.path.join(GetServingDirForProject(desc), toolchain, config)
 
@@ -89,15 +92,17 @@
     '--timeout', '30.0',  # seconds
     # Prevent the infobar that shows up when requesting filesystem quota.
     '--browser_flag', '--unlimited-storage',
-    # Some samples need the use the socket API.  Enabling this for all
-    # tests should be harmless.
-    '--browser_flag', '--allow-nacl-socket-api=localhost',
+    '--enable_sockets',
   ]
 
   args.extend(['--serving_dir', GetServingDirForProject(desc)])
-  exe_dir = GetExecutableDirForProject(desc, toolchain, config)
+  # Fall back on the example directory in the Chromium repo, to find test.js.
+  args.extend(['--serving_dir', GetRepoServingDirForProject(desc)])
+  # If it is not found there, fall back on the dummy one (in this directory.)
+  args.extend(['--serving_dir', SCRIPT_DIR])
 
   if toolchain == platform:
+    exe_dir = GetExecutableDirForProject(desc, toolchain, config)
     ppapi_plugin = os.path.join(exe_dir, desc['NAME'])
     if platform == 'win':
       ppapi_plugin += '.dll'
@@ -181,10 +186,17 @@
 
 def IsTestDisabled(desc, toolchain, config):
   def AsList(value):
-    if type(value) in (list, tuple):
-      return (value,)
+    if type(value) not in (list, tuple):
+      return [value]
     return value
 
+  def TestMatchesDisabled(test_values, disabled_test):
+    for key in test_values:
+      if key in disabled_test:
+        if test_values[key] not in AsList(disabled_test[key]):
+          return False
+    return True
+
   test_values = {
       'name': desc['NAME'],
       'toolchain': toolchain,
@@ -193,10 +205,8 @@
   }
 
   for disabled_test in DISABLED_TESTS:
-    for key in test_values:
-      if key in disabled_test:
-        if test_values[key] in AsList(disabled_test[key]):
-          return True
+    if TestMatchesDisabled(test_values, disabled_test):
+      return True
   return False
 
 
@@ -265,7 +275,7 @@
 
 def main(args):
   parser = optparse.OptionParser()
-  parser.add_option('--config',
+  parser.add_option('-c', '--config',
       help='Choose configuration to run (Debug or Release).  Runs both '
            'by default', action='append')
   parser.add_option('-x', '--experimental',
@@ -281,7 +291,7 @@
       action='append')
   parser.add_option('--retry-times',
       help='Number of types to retry on failure (Default: %default)',
-          type='int', default=DEFAULT_RETRY_ON_FAILURE_TIMES)
+          type='int', default=1)
 
   options, args = parser.parse_args(args[1:])
   if args:
diff --git a/native_client_sdk/src/build_tools/test_sdk.py b/native_client_sdk/src/build_tools/test_sdk.py
index 6e7360b..bd5a00b 100755
--- a/native_client_sdk/src/build_tools/test_sdk.py
+++ b/native_client_sdk/src/build_tools/test_sdk.py
@@ -101,6 +101,7 @@
   args = [
     sys.executable,
     os.path.join(SCRIPT_DIR, 'test_projects.py'),
+    '--retry-times=3',
   ]
 
   if experimental:
diff --git a/native_client_sdk/src/build_tools/tests/verify_filelist_test.py b/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
index a1da591..2e01da1 100755
--- a/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
+++ b/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
@@ -122,6 +122,19 @@
       dirlist = ['foo/bar/baz\\foo']
       Verify('linux', rules, dirlist)
 
+  def testNestedGlobs(self):
+    rules = """\
+foo/*
+foo/bar/*"""
+    dirlist = ['foo/file', 'foo/bar/file']
+    Verify('linux', rules, dirlist)
+
+    rules = """\
+foo/bar/*
+foo/*"""
+    dirlist = ['foo/file', 'foo/bar/file']
+    Verify('linux', rules, dirlist)
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/native_client_sdk/src/build_tools/verify_filelist.py b/native_client_sdk/src/build_tools/verify_filelist.py
index 95526bf..e6ccbb0 100755
--- a/native_client_sdk/src/build_tools/verify_filelist.py
+++ b/native_client_sdk/src/build_tools/verify_filelist.py
@@ -90,6 +90,14 @@
       # Remove the *
       pattern = pattern[:-1]
       self.glob_prefixes.append(pattern)
+      # Sort by longest prefix first; otherwise the rules:
+      #
+      # foo/*
+      # foo/bar/*
+      #
+      # Won't work properly. A file "foo/bar/baz" will match the first rule,
+      # not the second.
+      self.glob_prefixes.sort(cmp=lambda x, y: cmp(len(y), len(x)))
     else:
       self.exact_filenames.add(pattern)
 
diff --git a/native_client_sdk/src/examples/common.js b/native_client_sdk/src/examples/common.js
index 51adb54..79687d5 100644
--- a/native_client_sdk/src/examples/common.js
+++ b/native_client_sdk/src/examples/common.js
@@ -64,6 +64,56 @@
   }
 
   /**
+   * Inject a script into the DOM, and call a callback when it is loaded.
+   *
+   * @param {string} url The url of the script to load.
+   * @param {Function} onload The callback to call when the script is loaded.
+   * @param {Function} onerror The callback to call if the script fails to load.
+   */
+  function injectScript(url, onload, onerror) {
+    var scriptEl = document.createElement('script');
+    scriptEl.type = 'text/javascript';
+    scriptEl.src = url;
+    scriptEl.onload = onload;
+    if (onerror) {
+      scriptEl.addEventListener('error', onerror, false);
+    }
+    document.head.appendChild(scriptEl);
+  }
+
+  /**
+   * Run all tests for this example.
+   *
+   * @param {bool} waitForModule True if the tests should wait for the module
+   *     to load. This is not necessary for trusted plugins (i.e. host plugins).
+   * @param {Object} moduleEl The module DOM element.
+   */
+  function runTests(waitForModule, moduleEl) {
+    console.log('runTests()');
+    common.tester = new Tester();
+
+    // All NaCl SDK examples are OK if the example exits cleanly; (i.e. the
+    // NaCl module returns 0 or calls exit(0)).
+    //
+    // Without this exception, the browser_tester thinks that the module
+    // has crashed.
+    common.tester.exitCleanlyIsOK();
+
+    common.tester.addAsyncTest('loaded', function(test) {
+      test.pass();
+    });
+
+    if (typeof window.addTests !== 'undefined') {
+      window.addTests();
+    }
+
+    if (waitForModule) {
+      common.tester.waitFor(moduleEl);
+    }
+    common.tester.run();
+  }
+
+  /**
    * Create the Native Client <embed> element as a child of the DOM element
    * named "listener".
    *
@@ -86,7 +136,7 @@
     // Add any optional arguments
     if (attrs) {
       for (var key in attrs) {
-        moduleEl.setAttribute(key, attrs[key])
+        moduleEl.setAttribute(key, attrs[key]);
       }
     }
 
@@ -113,34 +163,16 @@
 
     // This is code that is only used to test the SDK.
     if (isTest) {
-      var scriptEl = document.createElement('script');
-      scriptEl.type = 'text/javascript';
-      scriptEl.src = 'nacltest.js';
-      document.head.appendChild(scriptEl);
-
-      scriptEl.onload = function() {
-        common.tester = new Tester();
-
-        // All NaCl SDK examples are OK if the example exits cleanly; (i.e. the
-        // NaCl module returns 0 or calls exit(0)).
-        //
-        // Without this exception, the browser_tester thinks that the module
-        // has crashed.
-        common.tester.exitCleanlyIsOK();
-
-        common.tester.addAsyncTest('loaded', function(test) {
-          test.pass();
+      var loadNaClTest = function() {
+        injectScript('nacltest.js', function() {
+          var waitForModule = !isHost;
+          runTests(waitForModule, moduleEl);
         });
-
-        if (typeof window.addTests !== 'undefined') {
-          window.addTests();
-        }
-
-        if (!isHost) {
-          common.tester.waitFor(moduleEl);
-        }
-        common.tester.run();
       };
+
+      // Try to load test.js for the example. Whether or not it exists, load
+      // nacltest.js.
+      injectScript('test.js', loadNaClTest, loadNaClTest);
     }
   }
 
@@ -171,9 +203,9 @@
    */
   function handleCrash(event) {
     if (common.naclModule.exitStatus == -1) {
-      updateStatus('CRASHED')
+      updateStatus('CRASHED');
     } else {
-      updateStatus('EXITED [' + common.naclModule.exitStatus + ']')
+      updateStatus('EXITED [' + common.naclModule.exitStatus + ']');
     }
     if (typeof window.handleCrash !== 'undefined') {
       window.handleCrash(common.naclModule.lastError);
@@ -276,7 +308,7 @@
       return;
     }
 
-    logMessage('Unhandled message: ' + message_event.data)
+    logMessage('Unhandled message: ' + message_event.data);
   }
 
   /**
diff --git a/native_client_sdk/src/examples/demo/earth/earth.cc b/native_client_sdk/src/examples/demo/earth/earth.cc
index 2a1c958..559cc79 100644
--- a/native_client_sdk/src/examples/demo/earth/earth.cc
+++ b/native_client_sdk/src/examples/demo/earth/earth.cc
@@ -60,7 +60,7 @@
   return 0.0;
 }
 
-// RGBA helper functions.
+// RGBA helper functions, used for extracting color from RGBA source image.
 inline float ExtractR(uint32_t c) {
   return static_cast<float>(c & 0xFF) * kOneOver255;
 }
@@ -73,7 +73,8 @@
   return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255;
 }
 
-inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+// 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));
 }
 
@@ -353,7 +354,7 @@
   // By default, render from the dispatch thread.
   workers_ = new ThreadPool(num_threads_);
   PSEventSetFilter(PSE_ALL);
-  ps_context_ = PSContext2DAllocate();
+  ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
 }
 
 Planet::~Planet() {
@@ -382,7 +383,7 @@
 void Planet::wRenderPixelSpan(int x0, int x1, int y) {
   if (!base_tex_ || !night_tex_)
     return;
-  const int kColorBlack = MakeRGBA(0, 0, 0, 0xFF);
+  const int kColorBlack = MakeBGRA(0, 0, 0, 0xFF);
   float width = ps_context_->width;
   float height = ps_context_->height;
   float min_dim = width < height ? width : height;
@@ -495,7 +496,7 @@
     unsigned int ig = Clamp255(pg * tg + ng * ipg);
     unsigned int ib = Clamp255(pb * tb + nb * ipb);
 
-    unsigned int color = MakeRGBA(ir, ig, ib, 0xFF);
+    unsigned int color = MakeBGRA(ib, ig, ir, 0xFF);
 
     *pixels = color;
     ++pixels;
diff --git a/native_client_sdk/src/examples/demo/flock/flock.cc b/native_client_sdk/src/examples/demo/flock/flock.cc
index 94707a0..9e1a639 100644
--- a/native_client_sdk/src/examples/demo/flock/flock.cc
+++ b/native_client_sdk/src/examples/demo/flock/flock.cc
@@ -116,7 +116,7 @@
 
   g_goose_sprite = new Sprite(buffer, pp::Size(fmt.width, fmt.height), 0);
 
-  PSContext2D_t* ctx = PSContext2DAllocate();
+  PSContext2D_t* ctx = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
   ResetFlock(ctx, 50);
   while (1) {
     PSEvent* event;
diff --git a/native_client_sdk/src/examples/demo/life/life.c b/native_client_sdk/src/examples/demo/life/life.c
index ef107be..06b020d 100644
--- a/native_client_sdk/src/examples/demo/life/life.c
+++ b/native_client_sdk/src/examples/demo/life/life.c
@@ -42,7 +42,8 @@
 
 const unsigned int kInitialRandSeed = 0xC0DE533D;
 
-#define MakeRGBA(r, g, b, a)  \
+/* BGRA helper macro, for constructing a pixel for a BGRA buffer. */
+#define MakeBGRA(b, g, r, a)  \
   (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
 
 
@@ -53,24 +54,24 @@
  * a binary alive or dead.
  */
 const uint32_t kNeighborColors[] = {
-    MakeRGBA(0x00, 0x00, 0x00, 0xff),
-    MakeRGBA(0x00, 0x40, 0x00, 0xff),
-    MakeRGBA(0x00, 0x60, 0x00, 0xff),
-    MakeRGBA(0x00, 0x80, 0x00, 0xff),
-    MakeRGBA(0x00, 0xA0, 0x00, 0xff),
-    MakeRGBA(0x00, 0xC0, 0x00, 0xff),
-    MakeRGBA(0x00, 0xE0, 0x00, 0xff),
-    MakeRGBA(0x00, 0x00, 0x00, 0xff),
-    MakeRGBA(0x00, 0x40, 0x00, 0xff),
-    MakeRGBA(0x00, 0x60, 0x00, 0xff),
-    MakeRGBA(0x00, 0x80, 0x00, 0xff),
-    MakeRGBA(0x00, 0xA0, 0x00, 0xff),
-    MakeRGBA(0x00, 0xC0, 0x00, 0xff),
-    MakeRGBA(0x00, 0xE0, 0x00, 0xff),
-    MakeRGBA(0x00, 0xFF, 0x00, 0xff),
-    MakeRGBA(0x00, 0xFF, 0x00, 0xff),
-    MakeRGBA(0x00, 0xFF, 0x00, 0xff),
-    MakeRGBA(0x00, 0xFF, 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, 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),
 };
 
 /*
diff --git a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
index 9b1f472..59ae061 100644
--- a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
+++ b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
@@ -75,7 +75,7 @@
 
   PSEventSetFilter(PSE_ALL);
 
-  PSContext2D_t* ctx = PSContext2DAllocate();
+  PSContext2D_t* ctx = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
   bool running = true;
   while (running) {
     PSEvent* event;
diff --git a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
index 7cadb1a..99c2cbb 100644
--- a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
+++ b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
@@ -73,7 +73,8 @@
   return 0.0;
 }
 
-inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+// 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
@@ -162,7 +163,7 @@
     const float v = (frand() * 2.0f - 1.0f) * speed;
     velocities_[i].Set(u, v);
     // 'unique' color (well... unique enough for our purposes)
-    colors_[i] = MakeRGBA(rand255(), rand255(), rand255(), 255);
+    colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255);
   }
 }
 
@@ -173,7 +174,7 @@
   // By default, render from the dispatch thread.
   workers_ = new ThreadPool(num_threads_);
   PSEventSetFilter(PSE_ALL);
-  ps_context_ = PSContext2DAllocate();
+  ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
 }
 
 Voronoi::~Voronoi() {
@@ -243,7 +244,7 @@
 // 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 = MakeRGBA(128, 128, 128, 255);
+    const uint32_t gray = MakeBGRA(128, 128, 128, 255);
     color = gray;
   }
   for (int i = 0; i < width; i += 4) {
@@ -394,8 +395,8 @@
 
 // Superimposes dots on the positions.
 void Voronoi::SuperimposePositions() {
-  const uint32_t white = MakeRGBA(255, 255, 255, 255);
-  const uint32_t gray = MakeRGBA(192, 192, 192, 255);
+  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);
diff --git a/native_client_sdk/src/examples/tutorial/load_progress/example.js b/native_client_sdk/src/examples/tutorial/load_progress/example.js
index faceef5..3f45f6a 100644
--- a/native_client_sdk/src/examples/tutorial/load_progress/example.js
+++ b/native_client_sdk/src/examples/tutorial/load_progress/example.js
@@ -39,13 +39,12 @@
   if (event.lengthComputable && event.total > 0) {
     loadPercent = event.loaded / event.total * 100.0;
     loadPercentString = loadPercent + '%';
+    common.logMessage('progress: ' + event.url + ' ' + loadPercentString +
+                     ' (' + event.loaded + ' of ' + event.total + ' bytes)');
   } else {
     // The total length is not yet known.
-    loadPercent = -1.0;
-    loadPercentString = 'Computing...';
+    common.logMessage('progress: Computing...');
   }
-  common.logMessage('progress: ' + loadPercentString +
-                   ' (' + event.loaded + ' of ' + event.total + ' bytes)');
 }
 
 // Handler that gets called if an error occurred while loading the NaCl
diff --git a/native_client_sdk/src/libraries/nacl_io/dbgprint.c b/native_client_sdk/src/libraries/nacl_io/dbgprint.c
new file mode 100644
index 0000000..b8a5bdf
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/dbgprint.c
@@ -0,0 +1,36 @@
+/* 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 "nacl_io/dbgprint.h"
+
+#include "nacl_io/kernel_wrap_real.h"
+
+#include <alloca.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+void dbgprintf(const char* format, ...) {
+  va_list args;
+  size_t wrote;
+  char* output;
+
+#ifdef _MSC_VER
+  /* TODO(sbc): vsnprintf on win32 does not return the
+   * size of the buffer needed.  This can be implemented
+   * on win32 in terms of _vscprintf; */
+#error "not implemented for win32"
+#endif
+
+  va_start(args, format);
+  int len = vsnprintf(NULL, 0, format, args);
+  va_end(args);
+  output = alloca(len + 1);
+
+  va_start(args, format);
+  vsnprintf(output, len + 1, format, args);
+  va_end(args);
+
+  _real_write(2, output, strlen(output), &wrote);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/dbgprint.h b/native_client_sdk/src/libraries/nacl_io/dbgprint.h
new file mode 100644
index 0000000..305fea5
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/dbgprint.h
@@ -0,0 +1,16 @@
+/* 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_DBGPRINT_H_
+#define LIBRARIES_NACL_IO_DBGPRINT_H_
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+void dbgprintf(const char* format, ...);
+
+EXTERN_C_END
+
+#endif  /* LIBRARIES_NACL_IO_DBGPRINT_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/event_listener.cc b/native_client_sdk/src/libraries/nacl_io/event_listener.cc
index d8b293d..11297b6 100644
--- a/native_client_sdk/src/libraries/nacl_io/event_listener.cc
+++ b/native_client_sdk/src/libraries/nacl_io/event_listener.cc
@@ -175,14 +175,14 @@
 }
 
 Error EventListener::Track(int id,
-                          const ScopedEventEmitter& emitter,
-                          uint32_t filter,
-                          uint64_t user_data) {
+                           const ScopedEventEmitter& emitter,
+                           uint32_t filter,
+                           uint64_t user_data) {
   AUTO_LOCK(info_lock_);
   EventInfoMap_t::iterator it = event_info_map_.find(id);
 
   // If it's not a streaming type, then it can not be added.
-  if ((emitter->GetType() & (S_IFIFO | S_IFSOCK)) == 0)
+  if ((emitter->GetType() & (S_IFIFO | S_IFSOCK | S_IFCHR)) == 0)
     return EPERM;
 
   if (it != event_info_map_.end())
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/ioctl.h b/native_client_sdk/src/libraries/nacl_io/include/sys/ioctl.h
new file mode 100644
index 0000000..aa3774c
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/ioctl.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 LIBRARIES_NACL_IO_INCLUDE_SYS_IOCTL_H_
+#define LIBRARIES_NACL_IO_INCLUDE_SYS_IOCTL_H_
+
+#include <sys/cdefs.h>
+
+#define TIOCGWINSZ 0x5413
+#define TIOCSWINSZ 0x5414
+
+struct winsize {
+  unsigned short ws_row;
+  unsigned short ws_col;
+  unsigned short ws_xpixel;
+  unsigned short ws_ypixel;
+};
+
+__BEGIN_DECLS
+
+int ioctl(int fd, unsigned long request, ...);
+
+__END_DECLS
+
+#endif  /* LIBRARIES_NACL_IO_INCLUDE_SYS_IOCTL_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h b/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
index a817565..7a4af07 100644
--- a/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
@@ -99,6 +99,11 @@
 #define TCSADRAIN 1
 #define TCSAFLUSH 2
 
+#define TCOOFF    0
+#define TCOON     1
+#define TCIOFF    2
+#define TCION     3
+
 typedef unsigned char cc_t;
 typedef unsigned short tcflag_t;
 typedef char speed_t;
@@ -120,8 +125,17 @@
 
 __BEGIN_DECLS
 
+speed_t cfgetispeed(const struct termios *termios_p);
+speed_t cfgetospeed(const struct termios *termios_p);
+int cfsetispeed(struct termios *termios_p, speed_t speed);
+int cfsetospeed(struct termios *termios_p, speed_t speed);
+int cfsetspeed(struct termios *termios_p, speed_t speed);
+
+int tcdrain(int fd);
+int tcflow(int fd, int action);
 int tcflush(int fd, int queue_selector);
 int tcgetattr(int fd, struct termios *termios_p);
+int tcsendbreak(int fd, int duration);
 int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
 
 __END_DECLS
diff --git a/native_client_sdk/src/libraries/nacl_io/ioctl.h b/native_client_sdk/src/libraries/nacl_io/ioctl.h
index 1d27c61..80c2c4f 100644
--- a/native_client_sdk/src/libraries/nacl_io/ioctl.h
+++ b/native_client_sdk/src/libraries/nacl_io/ioctl.h
@@ -5,21 +5,40 @@
 #ifndef LIBRARIES_NACL_IO_IOCTL_H_
 #define LIBRARIES_NACL_IO_IOCTL_H_
 
-/* ioctl to tell a tty mount to prefix every message with a particular
- * null-terminated string. Accepts a pointer to a C string which will
- * be the prefix.
- */
-#define TIOCNACLPREFIX 0xadcd01
+#include <sys/types.h>
 
-/* ioctl to feed input to a tty mount. Accepts a pointer to the following
+/*
+ * ioctl to feed input to a tty node. Accepts a pointer to the following
  * struct (tioc_nacl_input_string), which contains a pointer to an array
  * of characters.
  */
 #define TIOCNACLINPUT  0xadcd02
 
+/*
+ * ioctl to register an output handler with the tty node.  Will fail
+ * with EALREADY if a handler is already registered.  Expects an
+ * argument of type tioc_nacl_output.  The handler will be called during
+ * calls to write() on the thread that calls write(), or, for echoed input
+ * during the TIOCNACLINPUT ioctl() on the thread calling ioctl(). The
+ * handler should return the number of bytes written/handled, or -errno
+ * if an error occured.
+ */
+#define TIOCNACLOUTPUT 0xadcd03
+
 struct tioc_nacl_input_string {
   size_t length;
   const char* buffer;
 };
 
+
+typedef ssize_t (*tioc_nacl_output_handler_t)(const char* buf,
+                                              size_t count,
+                                              void* user_data);
+
+struct tioc_nacl_output {
+  tioc_nacl_output_handler_t handler;
+  void* user_data;
+};
+
+
 #endif  /* LIBRARIES_NACL_IO_NACL_IO_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
index d93c05b..37d3fa4 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
@@ -29,6 +29,13 @@
   mount_.reset(NULL);
 }
 
+// Returns the MountNodeSocket* if this node is a socket.
+MountNodeSocket*  KernelHandle::socket_node() {
+  if (node_.get() && node_->IsaSock())
+    return reinterpret_cast<MountNodeSocket*>(node_.get());
+  return NULL;
+}
+
 Error KernelHandle::Init(int open_mode) {
   if (open_mode & O_APPEND) {
     Error error = node_->GetSize(&offs_);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
index ad2b900..fd76dde 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
@@ -19,6 +19,9 @@
 
 namespace nacl_io {
 
+class MountNode;
+class MountNodeSocket;
+
 // KernelHandle provides a reference counted container for the open
 // file information, such as it's mount, node, access type and offset.
 // KernelHandle can only be referenced when the KernelProxy lock is held.
@@ -41,6 +44,10 @@
   const ScopedMountNode& node() { return node_; }
   const ScopedMount& mount() { return mount_; }
 
+  // Returns the MountNodeSocket* if this node is a socket otherwise returns
+  // NULL.
+  MountNodeSocket* socket_node();
+
 private:
   ScopedMount mount_;
   ScopedMountNode node_;
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
index d1bad01..b378e86 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -22,6 +22,7 @@
   }
 
 static KernelProxy* s_kp;
+static bool s_kp_owned;
 
 void ki_init(void* kp) {
   ki_init_ppapi(kp, 0, NULL);
@@ -32,8 +33,14 @@
                    PPB_GetInterface get_browser_interface) {
   kernel_wrap_init();
 
-  if (kp == NULL) kp = new KernelProxy();
-  s_kp = static_cast<KernelProxy*>(kp);
+  if (kp == NULL) {
+    s_kp = new KernelProxy();
+    s_kp_owned = true;
+  } else {
+    s_kp = static_cast<KernelProxy*>(kp);
+    s_kp_owned = false;
+  }
+
 
   PepperInterface* ppapi = NULL;
   if (instance && get_browser_interface)
@@ -48,10 +55,11 @@
 
 void ki_uninit() {
   kernel_wrap_uninit();
+  if (s_kp_owned)
+    delete s_kp;
   s_kp = NULL;
 }
 
-
 int ki_chdir(const char* path) {
   ON_NOSYS_RETURN(-1);
   return s_kp->chdir(path);
@@ -258,6 +266,21 @@
   return s_kp->tcsetattr(fd, optional_actions, termios_p);
 }
 
+int ki_kill(pid_t pid, int sig) {
+  ON_NOSYS_RETURN(-1);
+  return s_kp->kill(pid, sig);
+}
+
+sighandler_t ki_signal(int signum, sighandler_t handler) {
+  ON_NOSYS_RETURN(SIG_ERR);
+  return s_kp->sigset(signum, handler);
+}
+
+sighandler_t ki_sigset(int signum, sighandler_t handler) {
+  ON_NOSYS_RETURN(SIG_ERR);
+  return s_kp->sigset(signum, handler);
+}
+
 #ifdef PROVIDES_SOCKET_API
 // Socket Functions
 int ki_accept(int fd, struct sockaddr* addr, socklen_t* len) {
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
index 6ef44b3..c17b61c 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -8,6 +8,7 @@
 #include <ppapi/c/ppb.h>
 #include <ppapi/c/pp_instance.h>
 
+#include "nacl_io/ossignal.h"
 #include "nacl_io/ossocket.h"
 #include "nacl_io/osstat.h"
 #include "nacl_io/ostermios.h"
@@ -75,6 +76,9 @@
 int ki_tcgetattr(int fd, struct termios* termios_p);
 int ki_tcsetattr(int fd, int optional_actions,
                  const struct termios *termios_p);
+int ki_kill(pid_t pid, int sig);
+sighandler_t ki_signal(int signum, sighandler_t handler);
+sighandler_t ki_sigset(int signum, sighandler_t handler);
 
 #ifdef PROVIDES_SOCKET_API
 // Socket Functions
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 292f91e..84e531e 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -14,10 +14,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
+#include <unistd.h>
 
 #include <iterator>
 #include <string>
 
+#include "nacl_io/dbgprint.h"
 #include "nacl_io/host_resolver.h"
 #include "nacl_io/kernel_handle.h"
 #include "nacl_io/kernel_wrap_real.h"
@@ -27,6 +29,8 @@
 #include "nacl_io/mount_http.h"
 #include "nacl_io/mount_mem.h"
 #include "nacl_io/mount_node.h"
+#include "nacl_io/mount_node_tcp.h"
+#include "nacl_io/mount_node_udp.h"
 #include "nacl_io/mount_passthrough.h"
 #include "nacl_io/osmman.h"
 #include "nacl_io/ossocket.h"
@@ -43,7 +47,31 @@
 
 namespace nacl_io {
 
-KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) {
+class SignalEmitter : public EventEmitter {
+ public:
+  // From EventEmitter.  The SignalEmitter exists in order
+  // to inturrupt anything waiting in select()/poll() when kill()
+  // is called.  It is an edge trigger only and therefore has no
+  // persistent readable/wriable/error state.
+  uint32_t GetEventStatus() {
+     return 0;
+  }
+
+  int GetType() {
+    // For lack of a better type, report socket to signify it can be in an
+    // used to signal.
+    return S_IFSOCK;
+  }
+
+  void SignalOccurred() {
+    RaiseEvent(POLLERR);
+  }
+};
+
+KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL),
+                             sigwinch_handler_(SIG_IGN),
+                             signal_emitter_(new SignalEmitter) {
+
 }
 
 KernelProxy::~KernelProxy() {
@@ -82,6 +110,10 @@
 #ifdef PROVIDES_SOCKET_API
   host_resolver_.Init(ppapi_);
 #endif
+
+  StringMap_t args;
+  socket_mount_.reset(new MountSocket());
+  socket_mount_->Init(0, args, ppapi);
 }
 
 int KernelProxy::open_resource(const char* path) {
@@ -704,11 +736,77 @@
   return 0;
 }
 
+int KernelProxy::kill(pid_t pid, int sig) {
+  // Currently we don't even pretend that other processes exist
+  // so we can only send a signal to outselves.  For kill(2)
+  // pid 0 means the current process group and -1 means all the
+  // processes we have permission to send signals to.
+  if (pid != getpid() && pid != -1 && pid != 0) {
+    errno = ESRCH;
+    return -1;
+  }
+
+  // Raise an event so that select/poll get interrupted.
+  signal_emitter_->SignalOccurred();
+  switch (sig) {
+    case SIGWINCH:
+      if (sigwinch_handler_ != SIG_IGN)
+        sigwinch_handler_(SIGWINCH);
+      break;
+
+    case SIGUSR1:
+    case SIGUSR2:
+      break;
+
+    default:
+      errno = EINVAL;
+      return -1;
+  }
+
+  return 0;
+}
+
+sighandler_t KernelProxy::sigset(int signum, sighandler_t handler) {
+  switch (signum) {
+    // Handled signals.
+    case SIGWINCH: {
+      sighandler_t old_value = sigwinch_handler_;
+      if (handler == SIG_DFL)
+        handler = SIG_IGN;
+      sigwinch_handler_ = handler;
+      return old_value;
+    }
+
+    // Known signals
+    case SIGHUP:
+    case SIGINT:
+    case SIGKILL:
+    case SIGPIPE:
+    case SIGPOLL:
+    case SIGPROF:
+    case SIGTERM:
+    case SIGCHLD:
+    case SIGURG:
+    case SIGFPE:
+    case SIGILL:
+    case SIGQUIT:
+    case SIGSEGV:
+    case SIGTRAP:
+      if (handler == SIG_DFL)
+        return SIG_DFL;
+      break;
+  }
+
+  errno = EINVAL;
+  return SIG_ERR;
+}
+
 #ifdef PROVIDES_SOCKET_API
 
 int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
                         fd_set* exceptfds, struct timeval* timeout) {
   ScopedEventListener listener(new EventListener);
+
   std::vector<struct pollfd> fds;
 
   fd_set readout, writeout, exceptout;
@@ -785,7 +883,7 @@
 
       // If the timeout is invalid or too long (larger than signed 32 bit).
       if ((timeout->tv_sec < 0) || (timeout->tv_sec >= (INT_MAX / 1000)) ||
-          (timeout->tv_usec < 0) || (timeout->tv_usec >= 1000) ||
+          (timeout->tv_usec < 0) || (timeout->tv_usec >= 1000000) ||
           (ms < 0) || (ms >= INT_MAX)) {
         errno = EINVAL;
         return -1;
@@ -794,9 +892,24 @@
       ms_timeout = static_cast<int>(ms);
     }
 
+    // Add a special node to listen for events
+    // coming from the KernelProxy itself (kill will
+    // generated a SIGERR event).
+    listener->Track(-1, signal_emitter_, POLLERR, -1);
+    event_track += 1;
+
     events.resize(event_track);
+
+    bool interrupted = false;
     listener->Wait(events.data(), event_track, ms_timeout, &ready_cnt);
     for (fd = 0; static_cast<int>(fd) < ready_cnt; fd++) {
+      if (events[fd].user_data == static_cast<uint64_t>(-1)) {
+        if (events[fd].events & POLLERR) {
+          interrupted = true;
+        }
+        continue;
+      }
+
       if (events[fd].events & POLLIN) {
         FD_SET(events[fd].user_data, &readout);
         event_cnt++;
@@ -812,6 +925,11 @@
         event_cnt++;
       }
     }
+
+    if (0 == event_cnt && interrupted) {
+      errno = EINTR;
+      return -1;
+    }
   }
 
   // Copy out the results
@@ -829,10 +947,11 @@
 
 int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) {
   ScopedEventListener listener(new EventListener);
+  listener->Track(-1, signal_emitter_, POLLERR, 0);
 
   int index;
   size_t event_cnt = 0;
-  size_t event_track = 0;
+  size_t event_track = 1;
   for (index = 0; static_cast<nfds_t>(index) < nfds; index++) {
     ScopedKernelHandle handle;
     struct pollfd* info = &fds[index];
@@ -867,14 +986,23 @@
     std::vector<EventData> events;
     int ready_cnt;
 
+    bool interrupted = false;
     events.resize(event_track);
     listener->Wait(events.data(), event_track, timeout, &ready_cnt);
     for (index = 0; index < ready_cnt; index++) {
       struct pollfd* info = &fds[events[index].user_data];
+      if (!info) {
+        interrupted = true;
+        continue;
+      }
 
       info->revents = events[index].events;
       event_cnt++;
     }
+    if (0 == event_cnt && interrupted) {
+      errno = EINTR;
+      return -1;
+    }
   }
 
   return event_cnt;
@@ -907,8 +1035,13 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  Error err = handle->socket_node()->Bind(addr, len);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return 0;
 }
 
 int KernelProxy::connect(int fd, const struct sockaddr* addr, socklen_t len) {
@@ -921,8 +1054,13 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EACCES;
-  return -1;
+  Error err = handle->socket_node()->Connect(addr, len);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return 0;
 }
 
 struct hostent* KernelProxy::gethostbyname(const char* name) {
@@ -939,8 +1077,13 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  Error err = handle->socket_node()->GetPeerName(addr, len);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return 0;
 }
 
 int KernelProxy::getsockname(int fd, struct sockaddr* addr, socklen_t* len) {
@@ -953,8 +1096,13 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  Error err = handle->socket_node()->GetSockName(addr, len);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return 0;
 }
 
 int KernelProxy::getsockopt(int fd,
@@ -997,8 +1145,14 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  int out_len = 0;
+  Error err = handle->socket_node()->Recv(buf, len, flags, &out_len);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return static_cast<ssize_t>(out_len);
 }
 
 ssize_t KernelProxy::recvfrom(int fd,
@@ -1021,8 +1175,19 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  int out_len = 0;
+  Error err = handle->socket_node()->RecvFrom(buf,
+                                              len,
+                                              flags,
+                                              addr,
+                                              addrlen,
+                                              &out_len);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return static_cast<ssize_t>(out_len);
 }
 
 ssize_t KernelProxy::recvmsg(int fd, struct msghdr* msg, int flags) {
@@ -1049,8 +1214,14 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  int out_len = 0;
+  Error err = handle->socket_node()->Send(buf, len, flags, &out_len);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return static_cast<ssize_t>(out_len);
 }
 
 ssize_t KernelProxy::sendto(int fd,
@@ -1073,8 +1244,16 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  int out_len = 0;
+  Error err =
+      handle->socket_node()->SendTo(buf, len, flags, addr, addrlen, &out_len);
+
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return static_cast<ssize_t>(out_len);
 }
 
 ssize_t KernelProxy::sendmsg(int fd, const struct msghdr* msg, int flags) {
@@ -1114,8 +1293,13 @@
   if (AcquireSocketHandle(fd, &handle) == -1)
     return -1;
 
-  errno = EINVAL;
-  return -1;
+  Error err = handle->socket_node()->Shutdown(how);
+  if (err != 0) {
+    errno = err;
+    return -1;
+  }
+
+  return 0;
 }
 
 int KernelProxy::socket(int domain, int type, int protocol) {
@@ -1124,13 +1308,29 @@
     return -1;
   }
 
-  if (SOCK_STREAM != type && SOCK_DGRAM != type) {
-    errno = EPROTONOSUPPORT;
-    return -1;
+  MountNodeSocket* sock = NULL;
+  switch (type) {
+    case SOCK_DGRAM:
+      sock = new MountNodeUDP(socket_mount_.get());
+      break;
+
+    case SOCK_STREAM:
+      sock = new MountNodeTCP(socket_mount_.get());
+      break;
+
+    default:
+      errno = EPROTONOSUPPORT;
+      return -1;
   }
 
-  errno = EACCES;
-  return -1;
+  ScopedMountNode node(sock);
+  if (sock->Init(S_IREAD | S_IWRITE) == 0) {
+    ScopedKernelHandle handle(new KernelHandle(socket_mount_, node));
+    return AllocateFD(handle);
+  }
+
+  // If we failed to init, assume we don't have access.
+  return EACCES;
 }
 
 int KernelProxy::socketpair(int domain, int type, int protocol, int* sv) {
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
index fc0191f..b8ca04e 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -11,6 +11,8 @@
 #include "nacl_io/host_resolver.h"
 #include "nacl_io/kernel_object.h"
 #include "nacl_io/mount_factory.h"
+#include "nacl_io/mount_socket.h"
+#include "nacl_io/ossignal.h"
 #include "nacl_io/ossocket.h"
 #include "nacl_io/ostypes.h"
 #include "nacl_io/osutime.h"
@@ -20,6 +22,9 @@
 namespace nacl_io {
 
 class PepperInterface;
+class SignalEmitter;
+
+typedef sdk_util::ScopedRef<SignalEmitter> ScopedSignalEmitter;
 
 // KernelProxy provide one-to-one mapping for libc kernel calls.  Calls to the
 // proxy will result in IO access to the provided Mount and MountNode objects.
@@ -124,6 +129,9 @@
   virtual int tcsetattr(int fd, int optional_actions,
                            const struct termios *termios_p);
 
+  virtual int kill(pid_t pid, int sig);
+  virtual sighandler_t sigset(int signum, sighandler_t handler);
+
 #ifdef PROVIDES_SOCKET_API
   virtual int select(int nfds, fd_set* readfds, fd_set* writefds,
                     fd_set* exceptfds, struct timeval* timeout);
@@ -174,9 +182,11 @@
 
  protected:
   MountFactoryMap_t factories_;
+  sdk_util::ScopedRef<MountSocket> socket_mount_;
   int dev_;
   PepperInterface* ppapi_;
   static KernelProxy *s_instance_;
+  sighandler_t sigwinch_handler_;
 #ifdef PROVIDES_SOCKET_API
   HostResolver host_resolver_;
 #endif
@@ -185,6 +195,7 @@
   virtual int AcquireSocketHandle(int fd, ScopedKernelHandle* handle);
 #endif
 
+  ScopedSignalEmitter signal_emitter_;
   DISALLOW_COPY_AND_ASSIGN(KernelProxy);
 };
 
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
index 33a4c2d..c7f8ce1 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
@@ -5,9 +5,11 @@
 #ifndef LIBRARIES_NACL_IO_KERNEL_WRAP_H_
 #define LIBRARIES_NACL_IO_KERNEL_WRAP_H_
 
-#include <sys/types.h>
+#include <signal.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
 
 #include "nacl_io/ossocket.h"
 #include "nacl_io/ostypes.h"
@@ -62,7 +64,6 @@
 char* NAME(getcwd)(char* buf, getcwd_size_t size) NOTHROW;
 char* getwd(char* buf) NOTHROW;
 int getdents(int fd, void* buf, unsigned int count) NOTHROW;
-int ioctl(int d, int request, char* argp) NOTHROW;
 int NAME(isatty)(int fd) NOTHROW;
 int lchown(const char* path, uid_t owner, gid_t group) NOTHROW;
 int link(const char* oldpath, const char* newpath) NOTHROW;
@@ -81,6 +82,7 @@
 read_ssize_t NAME(read)(int fd, void* buf, size_t nbyte);
 int remove(const char* path) NOTHROW;
 int NAME(rmdir)(const char* path) NOTHROW;
+sighandler_t sigset(int sig, sighandler_t disp);
 #if defined(WIN32)
 int setenv(const char* name, const char* value, int overwrite);
 int _stat32(const char* path, struct _stat32* buf);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
index c2a9e1f..8c270b1 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -22,6 +22,7 @@
 #include <sys/time.h>
 
 #include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap_real.h"
 #include "nacl_io/osmman.h"
 
 
@@ -243,9 +244,6 @@
 }
 
 int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
-  if (!ki_is_initialized())
-    return REAL(read)(fd, buf, count, nread);
-
   ssize_t signed_nread = ki_read(fd, buf, count);
   *nread = static_cast<size_t>(signed_nread);
   return (signed_nread < 0) ? errno : 0;
@@ -277,22 +275,33 @@
 }
 
 int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) {
-  if (!ki_is_initialized())
-    return REAL(write)(fd, buf, count, nwrote);
-
   ssize_t signed_nwrote = ki_write(fd, buf, count);
   *nwrote = static_cast<size_t>(signed_nwrote);
   return (signed_nwrote < 0) ? errno : 0;
 }
 
+static void assign_real_pointers() {
+  static bool assigned = false;
+  if (!assigned) {
+    EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
+    assigned = true;
+  }
+}
+
+#define CHECK_REAL(func) \
+  if (!REAL(func)) \
+    assign_real_pointers();
+
 // "real" functions, i.e. the unwrapped original functions.
 
 int _real_close(int fd) {
+  CHECK_REAL(close);
   return REAL(close)(fd);
 }
 
 int _real_fstat(int fd, struct stat* buf) {
   struct nacl_abi_stat st;
+  CHECK_REAL(fstat);
   int err = REAL(fstat)(fd, &st);
   if (err) {
     errno = err;
@@ -310,6 +319,7 @@
   size_t offset = 0;
   size_t nacl_offset = 0;
   size_t nacl_nread;
+  CHECK_REAL(getdents);
   int err = REAL(getdents)(fd, (dirent*)nacl_buf, count, &nacl_nread);
   if (err)
     return err;
@@ -333,39 +343,48 @@
 }
 
 int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
+  CHECK_REAL(seek);
   return REAL(seek)(fd, offset, whence, new_offset);
 }
 
 int _real_mkdir(const char* pathname, mode_t mode) {
+  CHECK_REAL(mkdir);
   return REAL(mkdir)(pathname, mode);
 }
 
 int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
                off_t offset) {
+  CHECK_REAL(mmap);
   return REAL(mmap)(addr, length, prot, flags, fd, offset);
 }
 
 int _real_munmap(void* addr, size_t length) {
+  CHECK_REAL(munmap);
   return REAL(munmap)(addr, length);
 }
 
 int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
+  CHECK_REAL(open);
   return REAL(open)(pathname, oflag, cmode, newfd);
 }
 
 int _real_open_resource(const char* file, int* fd) {
+  CHECK_REAL(open_resource);
   return REAL(open_resource)(file, fd);
 }
 
 int _real_read(int fd, void *buf, size_t count, size_t *nread) {
+  CHECK_REAL(read);
   return REAL(read)(fd, buf, count, nread);
 }
 
 int _real_rmdir(const char* pathname) {
+  CHECK_REAL(rmdir);
   return REAL(rmdir)(pathname);
 }
 
 int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
+  CHECK_REAL(write);
   return REAL(write)(fd, buf, count, nwrote);
 }
 
@@ -376,13 +395,9 @@
 }
 
 static bool s_wrapped = false;
-static bool s_assigned = false;
 void kernel_wrap_init() {
   if (!s_wrapped) {
-    if (!s_assigned) {
-      EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
-      s_assigned = true;
-    }
+    assign_real_pointers();
     EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP)
     s_wrapped = true;
   }
@@ -397,6 +412,4 @@
 
 EXTERN_C_END
 
-
 #endif  // defined(__native_client__) && defined(__GLIBC__)
-
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
index 34ab407..dcb3117 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
@@ -9,6 +9,7 @@
 #if defined(__native_client__) && !defined(__GLIBC__)
 
 #include "nacl_io/kernel_wrap.h"
+
 #include <assert.h>
 #include <dirent.h>
 #include <errno.h>
@@ -16,7 +17,9 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+
 #include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap_real.h"
 
 EXTERN_C_BEGIN
 
@@ -86,7 +89,11 @@
 }
 
 int WRAP(getdents)(int fd, dirent* buf, size_t count, size_t* nread) {
-  return (ki_getdents(fd, buf, count) < 0) ? errno : 0;
+  int rtn = ki_getdents(fd, buf, count);
+  if (rtn < 0)
+    return errno;
+  *nread = rtn;
+  return 0;
 }
 
 int WRAP(mmap)(void** addr, size_t length, int prot, int flags, int fd,
@@ -111,9 +118,6 @@
 }
 
 int WRAP(read)(int fd, void* buf, size_t count, size_t* nread) {
-  if (!ki_is_initialized())
-    return REAL(read)(fd, buf, count, nread);
-
   ssize_t signed_nread = ki_read(fd, buf, count);
   *nread = static_cast<size_t>(signed_nread);
   return (signed_nread < 0) ? errno : 0;
@@ -129,29 +133,43 @@
 }
 
 int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) {
-  if (!ki_is_initialized())
-    return REAL(write)(fd, buf, count, nwrote);
-
   ssize_t signed_nwrote = ki_write(fd, buf, count);
   *nwrote = static_cast<size_t>(signed_nwrote);
   return (signed_nwrote < 0) ? errno : 0;
 }
 
+static void assign_real_pointers() {
+  static bool assigned = false;
+  if (!assigned) {
+    __libnacl_irt_filename_init();
+    EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
+    assigned = true;
+  }
+}
+
+#define CHECK_REAL(func) \
+  if (!REAL(func)) \
+    assign_real_pointers();
+
 // "real" functions, i.e. the unwrapped original functions.
 
 int _real_close(int fd) {
+  CHECK_REAL(close);
   return REAL(close)(fd);
 }
 
 int _real_fstat(int fd, struct stat* buf) {
+  CHECK_REAL(fstat);
   return REAL(fstat)(fd, buf);
 }
 
-int _real_getdents(int fd, dirent* nacl_buf, size_t nacl_count, size_t* nread) {
-  return REAL(getdents)(fd, nacl_buf, nacl_count, nread);
+int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t* nread) {
+  CHECK_REAL(getdents);
+  return REAL(getdents)(fd, static_cast<dirent*>(nacl_buf), nacl_count, nread);
 }
 
 int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
+  CHECK_REAL(seek);
   return REAL(seek)(fd, offset, whence, new_offset);
 }
 
@@ -161,14 +179,17 @@
 
 int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
                off_t offset) {
+  CHECK_REAL(mmap);
   return REAL(mmap)(addr, length, prot, flags, fd, offset);
 }
 
 int _real_munmap(void* addr, size_t length) {
+  CHECK_REAL(munmap);
   return REAL(munmap)(addr, length);
 }
 
 int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
+  CHECK_REAL(open);
   return REAL(open)(pathname, oflag, cmode, newfd);
 }
 
@@ -177,6 +198,7 @@
 }
 
 int _real_read(int fd, void* buf, size_t count, size_t* nread) {
+  CHECK_REAL(read);
   return REAL(read)(fd, buf, count, nread);
 }
 
@@ -185,6 +207,7 @@
 }
 
 int _real_write(int fd, const void* buf, size_t count, size_t* nwrote) {
+  CHECK_REAL(write);
   return REAL(write)(fd, buf, count, nwrote);
 }
 
@@ -195,14 +218,10 @@
 }
 
 static bool s_wrapped = false;
-static bool s_assigned = false;
+
 void kernel_wrap_init() {
   if (!s_wrapped) {
-    if (!s_assigned) {
-      __libnacl_irt_filename_init();
-      EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
-      s_assigned = true;
-    }
+    assign_real_pointers();
     EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP)
     s_wrapped = true;
   }
@@ -217,6 +236,4 @@
 
 EXTERN_C_END
 
-
 #endif  // defined(__native_client__) && !defined(__GLIBC__)
-
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 4d75b2c..533bcf4 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -11,6 +11,7 @@
       'NAME' : 'nacl_io',
       'TYPE' : 'lib',
       'SOURCES' : [
+        'dbgprint.c',
         "event_emitter.cc",
         "event_listener.cc",
         "h_errno.cc",
@@ -32,15 +33,25 @@
         "mount_node_html5fs.cc",
         "mount_node_http.cc",
         "mount_node_mem.cc",
+        "mount_node_socket.cc",
+        "mount_node_tcp.cc",
         "mount_node_tty.cc",
+        "mount_node_udp.cc",
         "mount_passthrough.cc",
+        "mount_socket.cc",
         "nacl_io.cc",
         "path.cc",
         "pepper_interface.cc",
+        "pepper_interface_delegate.cc",
         "real_pepper_interface.cc",
         "syscalls/accept.c",
         "syscalls/access.c",
         "syscalls/bind.c",
+        "syscalls/cfgetispeed.c",
+        "syscalls/cfgetospeed.c",
+        "syscalls/cfsetspeed.c",
+        "syscalls/cfsetispeed.c",
+        "syscalls/cfsetospeed.c",
         "syscalls/chdir.c",
         "syscalls/chmod.c",
         "syscalls/chown.c",
@@ -49,7 +60,6 @@
         "syscalls/fsync.c",
         "syscalls/ftruncate.c",
         "syscalls/getcwd.c",
-        "syscalls/getdents.c",
         "syscalls/gethostbyname.c",
         "syscalls/getpeername.c",
         "syscalls/getsockname.c",
@@ -63,6 +73,7 @@
         "syscalls/inet_ntop.cc",
         "syscalls/ioctl.c",
         "syscalls/isatty.c",
+        "syscalls/kill.c",
         "syscalls/lchown.c",
         "syscalls/link.c",
         "syscalls/listen.c",
@@ -76,8 +87,11 @@
         "syscalls/recvfrom.c",
         "syscalls/recvmsg.c",
         "syscalls/remove.c",
+        "syscalls/tcdrain.c",
+        "syscalls/tcflow.c",
         "syscalls/tcflush.c",
         "syscalls/tcgetattr.c",
+        "syscalls/tcsendbreak.c",
         "syscalls/tcsetattr.c",
         "syscalls/select.c",
         "syscalls/send.c",
@@ -85,6 +99,8 @@
         "syscalls/sendto.c",
         "syscalls/setsockopt.c",
         "syscalls/shutdown.c",
+        "syscalls/signal.c",
+        "syscalls/sigset.c",
         "syscalls/socket.c",
         "syscalls/socketpair.c",
         "syscalls/unlink.c",
@@ -97,9 +113,10 @@
   'HEADERS': [
     {
       'FILES': [
+        "dbgprint.h",
+        "error.h",
         "event_emitter.h",
         "event_listener.h",
-        "error.h",
         "host_resolver.h",
         "inode_pool.h",
         "ioctl.h",
@@ -109,9 +126,9 @@
         "kernel_proxy.h",
         "kernel_wrap.h",
         "kernel_wrap_real.h",
-        "mount.h",
         "mount_dev.h",
         "mount_factory.h",
+        "mount.h",
         "mount_html5fs.h",
         "mount_http.h",
         "mount_mem.h",
@@ -121,12 +138,17 @@
         "mount_node_html5fs.h",
         "mount_node_http.h",
         "mount_node_mem.h",
+        "mount_node_socket.h",
+        "mount_node_tcp.h",
         "mount_node_tty.h",
+        "mount_node_udp.h",
         "mount_passthrough.h",
+        "mount_socket.h",
         "nacl_io.h",
         "osdirent.h",
         "osinttypes.h",
         "osmman.h",
+        "ossignal.h",
         "ossocket.h",
         "osstat.h",
         "ostime.h",
@@ -135,6 +157,8 @@
         "osutime.h",
         "ostermios.h",
         "path.h",
+        "pepper_interface_delegate.h",
+        "pepper_interface_dummy.h",
         "pepper_interface.h",
         "real_pepper_interface.h",
         "typed_mount_factory.h",
@@ -149,8 +173,10 @@
         "netinet/tcp.h",
         "netinet6/in6.h",
         "poll.h",
+        "sys/ioctl.h",
         "sys/mount.h",
         "sys/select.h",
+        "sys/signal.h",
         "sys/socket.h",
         "sys/termios.h",
         "sys/utsname.h",
@@ -165,8 +191,10 @@
         "netinet/tcp.h",
         "netinet6/in6.h",
         "poll.h",
+        "sys/ioctl.h",
         "sys/mount.h",
         "sys/select.h",
+        "sys/signal.h",
         "sys/socket.h",
         "sys/termios.h",
         "sys/utsname.h",
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
index 0394aff..9d364d7 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
@@ -61,6 +61,11 @@
   if (error)
     return error;
 
+  // FileRef returns PP_ERROR_NOACCESS which is translated to EACCES if you
+  // try to create the root directory. EEXIST is a better errno here.
+  if (path.Top())
+    return EEXIST;
+
   ScopedResource fileref_resource(
       ppapi(),
       ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
@@ -138,7 +143,7 @@
   // We can't block the main thread, so make an asynchronous call if on main
   // thread. If we are off-main-thread, then don't make an asynchronous call;
   // otherwise we require a message loop.
-  bool main_thread = ppapi->IsMainThread();
+  bool main_thread = ppapi->GetCoreInterface()->IsMainThread();
   PP_CompletionCallback cc =
       main_thread ? PP_MakeCompletionCallback(
                         &MountHtml5Fs::FilesystemOpenCallbackThunk, this)
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.cc b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
index 0116745..4a0c065 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -153,6 +153,8 @@
 
 bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
 
+bool MountNode::IsaSock() { return (stat_.st_mode & S_IFSOCK) != 0; }
+
 bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
 
 Error MountNode::AddChild(const std::string& name,
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.h b/native_client_sdk/src/libraries/nacl_io/mount_node.h
index 2afc88b..661a194 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.h
@@ -37,8 +37,8 @@
   virtual void Destroy();
 
  public:
-   // Declared in EventEmitter. defaults to signalled.
-   virtual uint32_t GetEventStatus();
+  // Declared in EventEmitter. defaults to signalled.
+  virtual uint32_t GetEventStatus();
 
   // Normal OS operations on a node (file), can be called by the kernel
   // directly so it must lock and unlock appropriately.  These functions
@@ -82,6 +82,7 @@
   virtual Error GetSize(size_t* out_size);
   virtual bool IsaDir();
   virtual bool IsaFile();
+  virtual bool IsaSock();
   virtual bool IsaTTY();
 
 
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_char.h b/native_client_sdk/src/libraries/nacl_io/mount_node_char.h
index 48ad86f..ebb8616 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_char.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_char.h
@@ -14,6 +14,10 @@
   explicit MountNodeCharDevice(Mount* mount) : MountNode(mount) {
     stat_.st_mode = S_IFCHR;
   }
+
+  virtual uint32_t GetEventStatus() {
+    return 0;
+  }
 };
 
 }
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
index 09d957a..4d5b283 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
@@ -70,7 +70,7 @@
 
 Error MountNodeHtml5Fs::FSync() {
   // Cannot call Flush on a directory; simply do nothing.
-  if (IsDirectory())
+  if (IsaDir())
     return 0;
 
   int32_t result = mount_->ppapi()->GetFileIoInterface()
@@ -95,7 +95,7 @@
     return EINVAL;
 
   // If this is not a directory, fail
-  if (!IsDirectory())
+  if (!IsaDir())
     return ENOTDIR;
 
   OutputBuffer output_buf = {NULL, 0};
@@ -121,20 +121,22 @@
     uint32_t file_name_length;
     const char* file_name = mount_->ppapi()->GetVarInterface()
         ->VarToUtf8(file_name_var, &file_name_length);
-    if (!file_name)
-      continue;
 
-    file_name_length = std::min(
-        static_cast<size_t>(file_name_length),
-        sizeof(static_cast<struct dirent*>(0)->d_name) - 1);  // -1 for NULL.
+    if (file_name) {
+      file_name_length = std::min(
+          static_cast<size_t>(file_name_length),
+          sizeof(static_cast<struct dirent*>(0)->d_name) - 1);  // -1 for NULL.
 
-    dirents.push_back(dirent());
-    struct dirent& direntry = dirents.back();
-    direntry.d_ino = 1;  // Must be > 0.
-    direntry.d_off = sizeof(struct dirent);
-    direntry.d_reclen = sizeof(struct dirent);
-    strncpy(direntry.d_name, file_name, file_name_length);
-    direntry.d_name[file_name_length] = 0;
+      dirents.push_back(dirent());
+      struct dirent& direntry = dirents.back();
+      direntry.d_ino = 1;  // Must be > 0.
+      direntry.d_off = sizeof(struct dirent);
+      direntry.d_reclen = sizeof(struct dirent);
+      strncpy(direntry.d_name, file_name, file_name_length);
+      direntry.d_name[file_name_length] = 0;
+    }
+
+    mount_->ppapi()->GetVarInterface()->Release(file_name_var);
   }
 
   // Release the output buffer.
@@ -193,7 +195,7 @@
                              int* out_bytes) {
   *out_bytes = 0;
 
-  if (IsDirectory())
+  if (IsaDir())
     return EISDIR;
 
   int32_t result =
@@ -210,7 +212,7 @@
 }
 
 Error MountNodeHtml5Fs::FTruncate(off_t size) {
-  if (IsDirectory())
+  if (IsaDir())
     return EISDIR;
 
   int32_t result = mount_->ppapi()->GetFileIoInterface()
@@ -226,7 +228,7 @@
                               int* out_bytes) {
   *out_bytes = 0;
 
-  if (IsDirectory())
+  if (IsaDir())
     return EISDIR;
 
   int32_t result = mount_->ppapi()->GetFileIoInterface()
@@ -242,9 +244,16 @@
   return 0;
 }
 
+int MountNodeHtml5Fs::GetType() {
+  return fileio_resource_ ? S_IFREG : S_IFDIR;
+}
+
 Error MountNodeHtml5Fs::GetSize(size_t* out_size) {
   *out_size = 0;
 
+  if (IsaDir())
+    return 0;
+
   AUTO_LOCK(node_lock_);
 
   PP_FileInfo info;
@@ -257,6 +266,14 @@
   return 0;
 }
 
+bool MountNodeHtml5Fs::IsaDir() {
+  return !fileio_resource_;
+}
+
+bool MountNodeHtml5Fs::IsaFile() {
+  return fileio_resource_;
+}
+
 MountNodeHtml5Fs::MountNodeHtml5Fs(Mount* mount, PP_Resource fileref_resource)
     : MountNode(mount),
       fileref_resource_(fileref_resource),
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
index 57bc791..6a4c0f5 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
@@ -30,7 +30,10 @@
                       size_t count,
                       int* out_bytes);
 
+  virtual int GetType();
   virtual Error GetSize(size_t *out_size);
+  virtual bool IsaDir();
+  virtual bool IsaFile();
 
  protected:
   MountNodeHtml5Fs(Mount* mount, PP_Resource fileref);
@@ -43,11 +46,6 @@
   PP_Resource fileref_resource_;
   PP_Resource fileio_resource_;  // 0 if the file is a directory.
 
-  // Returns true if this node is a directory.
-  bool IsDirectory() const {
-    return !fileio_resource_;
-  }
-
   friend class MountHtml5Fs;
 };
 
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
new file mode 100644
index 0000000..be524d5
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
@@ -0,0 +1,263 @@
+// 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 "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+#include <string.h>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/pepper_interface.h"
+
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/ppb_net_address.h"
+
+namespace nacl_io {
+
+MountNodeSocket::MountNodeSocket(Mount* mount)
+    : MountNode(mount),
+      socket_resource_(0),
+      local_addr_(0),
+      remote_addr_(0) {
+  stat_.st_mode |= S_IFSOCK;
+}
+
+void MountNodeSocket::Destroy() {
+  if (socket_resource_)
+    mount_->ppapi()->ReleaseResource(socket_resource_);
+  if (local_addr_)
+    mount_->ppapi()->ReleaseResource(local_addr_);
+  if (remote_addr_)
+    mount_->ppapi()->ReleaseResource(remote_addr_);
+}
+
+// Default to always signaled, until socket select support is added.
+uint32_t MountNodeSocket::GetEventStatus() {
+  return POLLIN | POLLOUT;
+}
+
+// Assume that |addr| and |out_addr| are non-NULL.
+Error MountNodeSocket::MMap(void* addr,
+                            size_t length,
+                            int prot,
+                            int flags,
+                            size_t offset,
+                            void** out_addr) {
+  return EACCES;
+}
+
+// Normal read/write operations on a file
+Error MountNodeSocket::Read(size_t offs,
+                            void* buf,
+                            size_t count,
+                            int* out_bytes) {
+  return Recv(buf, count, 0, out_bytes);
+}
+
+Error MountNodeSocket::Write(size_t offs,
+                      const void* buf,
+                      size_t count,
+                      int* out_bytes) {
+  if (0 == remote_addr_)
+    return EDESTADDRREQ;
+
+  return Send(buf, count, 0, out_bytes);
+}
+
+NetAddressInterface* MountNodeSocket::NetAddress() {
+  return mount_->ppapi()->GetNetAddressInterface();
+}
+
+PP_Resource MountNodeSocket::SockAddrToResource(const struct sockaddr* addr,
+                                                socklen_t len) {
+  if (AF_INET == addr->sa_family) {
+    PP_NetAddress_IPv4 addr4;
+    const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(addr);
+
+    if (len != sizeof(sockaddr_in))
+      return 0;
+
+    memset(&addr4, 0, sizeof(addr4));
+
+    addr4.port = sin->sin_port;
+    memcpy(addr4.addr, &sin->sin_addr, sizeof(addr4.addr));
+    return mount_->ppapi()->GetNetAddressInterface()->CreateFromIPv4Address(
+        mount_->ppapi()->GetInstance(), &addr4);
+  }
+
+  if (AF_INET6 == addr->sa_family) {
+    PP_NetAddress_IPv6 addr6;
+    const sockaddr_in6* sin = reinterpret_cast<const sockaddr_in6*>(addr);
+
+    if (len != sizeof(sockaddr_in6))
+      return 0;
+
+    memset(&addr6, 0, sizeof(addr6));
+
+    addr6.port = sin->sin6_port;
+    memcpy(addr6.addr, &sin->sin6_addr, sizeof(addr6.addr));
+    return mount_->ppapi()->GetNetAddressInterface()->CreateFromIPv6Address(
+        mount_->ppapi()->GetInstance(), &addr6);
+  }
+  return 0;
+}
+
+
+socklen_t MountNodeSocket::ResourceToSockAddr(PP_Resource addr,
+                                              socklen_t len,
+                                              struct sockaddr* out_addr) {
+  if (0 == addr)
+    return 0;
+
+  PP_NetAddress_IPv4 ipv4;
+  PP_NetAddress_IPv6 ipv6;
+
+  if (PP_TRUE == NetAddress()->DescribeAsIPv4Address(addr, &ipv4)) {
+    sockaddr_in addr4;
+    addr4.sin_family = AF_INET;
+    addr4.sin_port = ipv4.port;
+    memcpy(&addr4.sin_addr, ipv4.addr, sizeof(ipv4.addr));
+    memcpy(out_addr, &addr4, len);
+
+    // Returns required size not copied size like getpeername/getsockname.
+    return sizeof(sockaddr_in);
+  }
+
+  if (PP_TRUE == NetAddress()->DescribeAsIPv6Address(addr, &ipv6)) {
+    sockaddr_in6 addr6;
+    addr6.sin6_family = AF_INET6;
+    addr6.sin6_port = ipv6.port;
+    memcpy(&addr6.sin6_addr, ipv6.addr, sizeof(ipv6.addr));
+    memcpy(out_addr, &addr6, len);
+
+    // Returns required size not copied size like getpeername/getsockname.
+    return sizeof(sockaddr_in6);
+  }
+
+  return 0;
+}
+
+bool MountNodeSocket::IsEquivalentAddress(PP_Resource addr1,
+                                          PP_Resource addr2) {
+  if (addr1 == addr2)
+    return true;
+
+  char data1[sizeof(sockaddr_in6)];
+  char data2[sizeof(sockaddr_in6)];
+
+  sockaddr* saddr1 = reinterpret_cast<sockaddr*>(data1);
+  sockaddr* saddr2 = reinterpret_cast<sockaddr*>(data2);
+
+  socklen_t len1 = ResourceToSockAddr(addr1, sizeof(data1), saddr1);
+  socklen_t len2 = ResourceToSockAddr(addr2, sizeof(data2), saddr2);
+
+  if (len1 != len2)
+    return false;
+
+  return memcmp(saddr1, saddr2, len1) == 0;
+}
+
+
+Error MountNodeSocket::Accept(const struct sockaddr* addr, socklen_t len) {
+  return ENOSYS;
+}
+
+Error MountNodeSocket::Connect(const struct sockaddr* addr, socklen_t len) {
+  if (len < 1)
+    return EINVAL;
+
+  if (NULL == addr)
+    return EFAULT;
+
+  return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::Listen(int backlog) {
+  return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::GetSockOpt(int lvl,
+                                  int optname,
+                                  void* optval,
+                                  socklen_t* len) {
+  return EINVAL;
+}
+
+Error MountNodeSocket::SetSockOpt(int lvl,
+                                  int optname,
+                                  const void* optval,
+                                  socklen_t len) {
+  return EINVAL;
+}
+
+Error MountNodeSocket::Bind(const struct sockaddr* addr, socklen_t len) {
+  return EINVAL;
+}
+
+Error MountNodeSocket::Recv(void* buf, size_t len, int flags, int* out_len) {
+  return EINVAL;
+}
+
+Error MountNodeSocket::RecvFrom(void* buf,
+                                size_t len,
+                                int flags,
+                                struct sockaddr* src_addr,
+                                socklen_t* addrlen,
+                                int* out_len) {
+  return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::Send(const void* buf,
+                            size_t len,
+                            int flags,
+                            int* out_len) {
+  return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::SendTo(const void* buf,
+                              size_t len,
+                              int flags,
+                              const struct sockaddr* dest_addr,
+                              socklen_t addrlen,
+                              int* out_len) {
+  return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::Shutdown(int how) {
+  return EOPNOTSUPP;
+}
+
+
+Error MountNodeSocket::GetPeerName(struct sockaddr* addr, socklen_t* len) {
+  if (NULL == addr || NULL == len)
+    return EFAULT;
+
+  AUTO_LOCK(node_lock_);
+  if (remote_addr_ != 0) {
+    *len = ResourceToSockAddr(remote_addr_, *len, addr);
+    return 0;
+  }
+
+  return ENOTCONN;
+}
+
+Error MountNodeSocket::GetSockName(struct sockaddr* addr, socklen_t* len) {
+  if (NULL == addr || NULL == len)
+    return EFAULT;
+
+  AUTO_LOCK(node_lock_);
+  if (local_addr_ != 0) {
+    *len = ResourceToSockAddr(local_addr_, *len, addr);
+    return 0;
+  }
+
+  return ENOTCONN;
+}
+
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
\ No newline at end of file
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
new file mode 100644
index 0000000..a133c19
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
@@ -0,0 +1,105 @@
+// 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_MOUNT_NODE_SOCKET_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_SOCKET_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <ppapi/c/pp_errors.h>
+#include <ppapi/c/pp_resource.h>
+#include <ppapi/c/ppb_net_address.h>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/pepper_interface.h"
+
+namespace nacl_io {
+
+/* Only allow single maximum transfers of 64K or less. Socket users
+ * should be looping on Send/Recv size. */
+static const size_t MAX_SOCK_TRANSFER = 65536;
+
+class MountSocket;
+
+class MountNodeSocket : public MountNode {
+ public:
+  explicit MountNodeSocket(Mount* mount);
+
+ protected:
+  virtual void Destroy();
+  virtual Error Init(int flags) = 0;
+
+ public:
+  virtual uint32_t GetEventStatus();
+
+  // Normal read/write operations on a file (recv/send).
+  virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+  virtual Error Write(size_t offs,
+                      const void* buf,
+                      size_t count,
+                      int* out_bytes);
+
+  // Unsuported Functions
+  virtual Error Accept(const struct sockaddr* addr, socklen_t len);
+  virtual Error Listen(int backlog);
+  virtual Error GetSockOpt(int lvl, int optname, void* optval, socklen_t* len);
+  virtual Error SetSockOpt(int lvl,
+                           int optname,
+                           const void* optval,
+                           socklen_t len);
+  virtual Error Shutdown(int how);
+  virtual Error MMap(void* addr,
+                     size_t length,
+                     int prot,
+                     int flags,
+                     size_t offset,
+                     void** out_addr);
+
+  // Normal Functions.
+  virtual Error Bind(const struct sockaddr* addr, socklen_t len);
+  virtual Error Connect(const struct sockaddr* addr, socklen_t len);
+  virtual Error Recv(void* buf, size_t len, int flags, int* out_len);
+  virtual Error RecvFrom(void* buf,
+                         size_t len,
+                         int flags,
+                         struct sockaddr* src_addr,
+                         socklen_t* addrlen,
+                         int* out_len);
+
+  virtual Error Send(const void* buf, size_t len, int flags, int* out_len);
+  virtual Error SendTo(const void* buf,
+                       size_t len,
+                       int flags,
+                       const struct sockaddr* dest_addr,
+                       socklen_t addrlen,
+                       int* out_len);
+
+  virtual Error GetPeerName(struct sockaddr* addr, socklen_t* len);
+  virtual Error GetSockName(struct sockaddr* addr, socklen_t* len);
+
+ protected:
+  NetAddressInterface* NetAddress();
+  PP_Resource SockAddrToResource(const struct sockaddr* addr, socklen_t len);
+  socklen_t ResourceToSockAddr(PP_Resource addr,
+                               socklen_t len,
+                               struct sockaddr* out_addr);
+
+  bool IsEquivalentAddress(PP_Resource addr1, PP_Resource addr2);
+
+ protected:
+  PP_Resource socket_resource_;
+  PP_Resource local_addr_;
+  PP_Resource remote_addr_;
+
+  friend class KernelProxy;
+  friend class MountSocket;
+};
+
+
+}  // namespace nacl_io
+
+
+#endif  // PROVIDES_SOCKET_API
+#endif  // LIBRARIES_NACL_IO_MOUNT_NODE_SOCKET_H_
\ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc
new file mode 100644
index 0000000..5a5f9f1
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc
@@ -0,0 +1,146 @@
+// 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 "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+#include <string.h>
+#include <algorithm>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/mount_node_tcp.h"
+#include "nacl_io/pepper_interface.h"
+
+namespace nacl_io {
+
+MountNodeTCP::MountNodeTCP(Mount* mount) : MountNodeSocket(mount) {}
+
+
+TCPSocketInterface* MountNodeTCP::TCPSocket() {
+  if (mount_->ppapi() == NULL)
+    return NULL;
+
+  return mount_->ppapi()->GetTCPSocketInterface();
+}
+
+Error MountNodeTCP::Init(int flags) {
+  if (TCPSocket() == NULL)
+    return EACCES;
+
+  socket_resource_ = TCPSocket()->Create(mount_->ppapi()->GetInstance());
+  if (0 == socket_resource_)
+    return EACCES;
+
+  return 0;
+}
+
+Error MountNodeTCP::Bind(const struct sockaddr* addr, socklen_t len) {
+  AUTO_LOCK(node_lock_);
+
+  if (0 == socket_resource_)
+    return EBADF;
+
+  /* Only bind once. */
+  if (local_addr_ != 0)
+    return EINVAL;
+
+  /* Lie, we won't know until we connect. */
+  return 0;
+}
+
+Error MountNodeTCP::Connect(const struct sockaddr* addr, socklen_t len) {
+  AUTO_LOCK(node_lock_);
+
+  if (0 == socket_resource_)
+    return EBADF;
+
+  if (remote_addr_ != 0)
+    return EISCONN;
+
+  remote_addr_ = SockAddrToResource(addr, len);
+  if (0 == remote_addr_)
+    return EINVAL;
+
+  int err = TCPSocket()->Connect(socket_resource_,
+                                 remote_addr_,
+                                 PP_BlockUntilComplete());
+
+  // If we fail, release the dest addr resource
+  if (err != PP_OK) {
+    mount_->ppapi()->ReleaseResource(remote_addr_);
+    remote_addr_ = 0;
+    return PPErrorToErrno(err);
+  }
+
+  local_addr_ = TCPSocket()->GetLocalAddress(socket_resource_);
+  mount_->ppapi()->AddRefResource(local_addr_);
+  return 0;
+}
+
+Error MountNodeTCP::Recv(void* buf, size_t len, int flags, int* out_len) {
+  AUTO_LOCK(node_lock_);
+  if (0 == socket_resource_)
+    return EBADF;
+
+  int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+  int err = TCPSocket()->Read(socket_resource_,
+                              static_cast<char*>(buf),
+                              capped_len,
+                              PP_BlockUntilComplete());
+  if (err < 0)
+    return PPErrorToErrno(err);
+
+  *out_len = err;
+  return 0;
+}
+
+Error MountNodeTCP::RecvFrom(void* buf,
+                             size_t len,
+                             int flags,
+                             struct sockaddr* src_addr,
+                             socklen_t* addrlen,
+                             int* out_len) {
+  Error err = Recv(buf, len, flags, out_len);
+  if (err == 0)
+    GetPeerName(src_addr, addrlen);
+  return err;
+}
+
+
+Error MountNodeTCP::Send(const void* buf, size_t len, int flags, int* out_len) {
+  AUTO_LOCK(node_lock_);
+
+  if (0 == socket_resource_)
+    return EBADF;
+
+  if (0 == remote_addr_)
+    return ENOTCONN;
+
+  int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+  int err = TCPSocket()->Write(socket_resource_,
+                               static_cast<const char*>(buf),
+                               capped_len,
+                               PP_BlockUntilComplete());
+  if (err < 0)
+    return PPErrorToErrno(err);
+
+  *out_len = err;
+  return 0;
+}
+
+Error MountNodeTCP::SendTo(const void* buf,
+                           size_t len,
+                           int flags,
+                           const struct sockaddr* dest_addr,
+                           socklen_t addrlen,
+                           int* out_len) {
+  return Send(buf, len, flags, out_len);
+}
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
\ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h
new file mode 100644
index 0000000..860e93b
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h
@@ -0,0 +1,52 @@
+// 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_MOUNT_NODE_TCP_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_TCP_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <ppapi/c/pp_resource.h>
+#include <ppapi/c/ppb_tcp_socket.h>
+
+#include "nacl_io/mount_node.h"
+#include "nacl_io/mount_node_socket.h"
+
+namespace nacl_io {
+
+class MountNodeTCP : public MountNodeSocket {
+ public:
+  explicit MountNodeTCP(Mount* mount);
+
+  virtual Error Init(int flags);
+
+  virtual Error Bind(const struct sockaddr* addr, socklen_t len);
+  virtual Error Connect(const struct sockaddr* addr, socklen_t len);
+
+  virtual Error Recv(void* buf, size_t len, int flags, int* out_len);
+  virtual Error RecvFrom(void* buf,
+                         size_t len,
+                         int flags,
+                         struct sockaddr* src_addr,
+                         socklen_t* addrlen,
+                         int* out_len);
+
+  virtual Error Send(const void* buf, size_t len, int flags, int* out_len);
+  virtual Error SendTo(const void* buf,
+                       size_t len,
+                       int flags,
+                       const struct sockaddr* dest_addr,
+                       socklen_t addrlen,
+                       int* out_len);
+
+ protected:
+  TCPSocketInterface* TCPSocket();
+};
+
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
+#endif  // LIBRARIES_NACL_IO_MOUNT_NODE_TCP_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
index 7b9fb79..534e53a 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
@@ -6,8 +6,11 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <signal.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
 #include <algorithm>
 
@@ -24,10 +27,17 @@
 #define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL)
 #define IS_ICANON CHECK_LFLAG(termios_, ICANON)
 
+#define DEFAULT_TTY_COLS 80
+#define DEFAULT_TTY_ROWS 30
+
 namespace nacl_io {
 
 MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount),
-                                           is_readable_(false) {
+                                           is_readable_(false),
+                                           did_resize_(false),
+                                           rows_(DEFAULT_TTY_ROWS),
+                                           cols_(DEFAULT_TTY_COLS) {
+  output_handler_.handler = NULL;
   pthread_cond_init(&is_readable_cond_, NULL);
   InitTermios();
 }
@@ -68,49 +78,37 @@
                      const void* buf,
                      size_t count,
                      int* out_bytes) {
-  return Write(offs, buf, count, out_bytes, false);
-}
-
-Error MountNodeTty::Write(size_t offs,
-                     const void* buf,
-                     size_t count,
-                     int* out_bytes,
-                     bool locked) {
+  AUTO_LOCK(output_lock_);
   *out_bytes = 0;
 
-  if (!mount_->ppapi())
-    return ENOSYS;
+  // No handler registered.
+  if (output_handler_.handler == NULL)
+    return EIO;
 
-  MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface();
-  VarInterface* var_intr = mount_->ppapi()->GetVarInterface();
+  int rtn = output_handler_.handler(static_cast<const char*>(buf),
+                                    count,
+                                    output_handler_.user_data);
 
-  if (!(var_intr && msg_intr))
-    return ENOSYS;
+  // Negative return value means an error occured and the return
+  // value is a negated errno value.
+  if (rtn < 0)
+    return -rtn;
 
-  // We append the prefix_ to the data in buf, then package it up
-  // and post it as a message.
-  const char* data = static_cast<const char*>(buf);
-  std::string message;
-  if (locked) {
-    message = prefix_;
-  } else {
-    AUTO_LOCK(node_lock_);
-    message = prefix_;
-  }
-
-  message.append(data, count);
-  uint32_t len = static_cast<uint32_t>(message.size());
-  struct PP_Var val = var_intr->VarFromUtf8(message.data(), len);
-  msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
-  var_intr->Release(val);
-  *out_bytes = count;
+  *out_bytes = rtn;
   return 0;
 }
 
 Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
   AUTO_LOCK(node_lock_);
+  did_resize_ = false;
   while (!is_readable_) {
     pthread_cond_wait(&is_readable_cond_, node_lock_.mutex());
+    if (!is_readable_ && did_resize_) {
+      // If an async resize event occured then return the failure and
+      // set EINTR.
+      *out_bytes = 0;
+      return EINTR;
+    }
   }
 
   size_t bytes_to_copy = std::min(count, input_buffer_.size());
@@ -151,7 +149,7 @@
 
 Error MountNodeTty::Echo(const char* string, int count) {
   int wrote;
-  Error error = Write(0, string, count, &wrote, true);
+  Error error = Write(0, string, count, &wrote);
   if (error != 0 || wrote != count) {
     // TOOD(sbc): Do something more useful in response to a
     // failure to echo.
@@ -163,15 +161,11 @@
 
 Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
   AUTO_LOCK(node_lock_);
-  if (message->length < prefix_.size() ||
-      strncmp(message->buffer, prefix_.data(), prefix_.size()) != 0) {
-    return ENOTTY;
-  }
 
-  const char* buffer = message->buffer + prefix_.size();
-  int num_bytes = message->length - prefix_.size();
+  const char* buffer = message->buffer;
+  size_t num_bytes = message->length;
 
-  for (int i = 0; i < num_bytes; i++) {
+  for (size_t i = 0; i < num_bytes; i++) {
     char c = buffer[i];
     // Transform characters according to input flags.
     if (c == '\r') {
@@ -229,30 +223,60 @@
       is_readable_ = true;
   }
 
-  if (is_readable_)
+  if (is_readable_) {
+    RaiseEvent(POLLIN);
     pthread_cond_broadcast(&is_readable_cond_);
+  }
+
   return 0;
 }
 
 Error MountNodeTty::Ioctl(int request, char* arg) {
-  if (request == TIOCNACLPREFIX) {
-    // This ioctl is used to change the prefix for this tty node.
-    // The prefix is used to distinguish messages intended for this
-    // tty node from all the other messages cluttering up the
-    // javascript postMessage() channel.
-    AUTO_LOCK(node_lock_);
-    prefix_ = arg;
-    return 0;
-  } else if (request == TIOCNACLINPUT) {
-    // This ioctl is used to deliver data from the user to this tty node's
-    // input buffer. We check if the prefix in the input data matches the
-    // prefix for this node, and only deliver the data if so.
-    struct tioc_nacl_input_string* message =
-      reinterpret_cast<struct tioc_nacl_input_string*>(arg);
-    return ProcessInput(message);
-  } else {
-    return EINVAL;
+  switch (request) {
+    case TIOCNACLOUTPUT: {
+      AUTO_LOCK(output_lock_);
+      if (arg == NULL) {
+        output_handler_.handler = NULL;
+        return 0;
+      }
+      if (output_handler_.handler != NULL)
+        return EALREADY;
+      output_handler_ = *reinterpret_cast<tioc_nacl_output*>(arg);
+      return 0;
+    }
+    case TIOCNACLINPUT: {
+      // This ioctl is used to deliver data from the user to this tty node's
+      // input buffer.
+      struct tioc_nacl_input_string* message =
+        reinterpret_cast<struct tioc_nacl_input_string*>(arg);
+      return ProcessInput(message);
+    }
+    case TIOCSWINSZ: {
+      struct winsize* size = reinterpret_cast<struct winsize*>(arg);
+      {
+        AUTO_LOCK(node_lock_);
+        rows_ = size->ws_row;
+        cols_ = size->ws_col;
+      }
+      kill(getpid(), SIGWINCH);
+
+      // Wake up any thread waiting on Read
+      {
+        AUTO_LOCK(node_lock_);
+        did_resize_ = true;
+        pthread_cond_broadcast(&is_readable_cond_);
+      }
+      return 0;
+    }
+    case TIOCGWINSZ: {
+      struct winsize* size = reinterpret_cast<struct winsize*>(arg);
+      size->ws_row = rows_;
+      size->ws_col = cols_;
+      return 0;
+    }
   }
+
+  return EINVAL;
 }
 
 Error MountNodeTty::Tcgetattr(struct termios* termios_p) {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h
index 0707420..8bf5b17 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h
@@ -5,6 +5,7 @@
 #ifndef LIBRARIES_NACL_IO_MOUNT_NODE_TTY_H_
 #define LIBRARIES_NACL_IO_MOUNT_NODE_TTY_H_
 
+#include <poll.h>
 #include <pthread.h>
 
 #include <deque>
@@ -38,21 +39,34 @@
   virtual Error Tcsetattr(int optional_actions,
                           const struct termios *termios_p);
 
+  virtual uint32_t GetEventStatus() {
+    uint32_t status = POLLOUT;
+    if (is_readable_)
+      status |= POLLIN;
+    return status;
+  }
+
  private:
-  virtual Error Write(size_t offs,
-                      const void* buf,
-                      size_t count,
-                      int* out_bytes,
-                      bool locked);
   Error ProcessInput(struct tioc_nacl_input_string* message);
   Error Echo(const char* string, int count);
   void InitTermios();
 
   std::deque<char> input_buffer_;
   bool is_readable_;
+  bool did_resize_;
   pthread_cond_t is_readable_cond_;
-  std::string prefix_;
   struct termios termios_;
+
+  /// Current height of terminal in rows.  Set via ioctl(2).
+  int rows_;
+  /// Current width of terminal in columns.  Set via ioctl(2).
+  int cols_;
+
+  // Output handler for TTY.  This is set via ioctl(2).
+  struct tioc_nacl_output output_handler_;
+  // Lock to protect output_handler_.  This lock gets aquired whenever
+  // output_handler_ is used or set.
+  sdk_util::SimpleLock output_lock_;
 };
 
 }
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_udp.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.cc
new file mode 100644
index 0000000..310a2bd
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.cc
@@ -0,0 +1,188 @@
+// 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 "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+#include <string.h>
+#include <algorithm>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/mount_node_udp.h"
+#include "nacl_io/pepper_interface.h"
+
+namespace nacl_io {
+
+MountNodeUDP::MountNodeUDP(Mount* mount) : MountNodeSocket(mount) {}
+
+
+UDPSocketInterface* MountNodeUDP::UDPSocket() {
+  if (mount_->ppapi() == NULL)
+    return NULL;
+
+  return mount_->ppapi()->GetUDPSocketInterface();
+}
+
+Error MountNodeUDP::Init(int flags) {
+  if (UDPSocket() == NULL)
+    return EACCES;
+
+  socket_resource_ = UDPSocket()->Create(mount_->ppapi()->GetInstance());
+  if (0 == socket_resource_)
+    return EACCES;
+
+  return 0;
+}
+
+Error MountNodeUDP::Bind(const struct sockaddr* addr, socklen_t len) {
+  if (0 == socket_resource_)
+    return EBADF;
+
+  /* Only bind once. */
+  if (local_addr_ != 0)
+    return EINVAL;
+
+  PP_Resource out_addr = SockAddrToResource(addr, len);
+  if (0 == out_addr)
+    return EINVAL;
+
+  int err = UDPSocket()->Bind(socket_resource_,
+                              out_addr,
+                              PP_BlockUntilComplete());
+  if (err != 0) {
+    mount_->ppapi()->ReleaseResource(out_addr);
+    return PPErrorToErrno(err);
+  }
+
+  local_addr_ = out_addr;
+  return 0;
+}
+
+Error MountNodeUDP::Connect(const struct sockaddr* addr, socklen_t len) {
+  if (0 == socket_resource_)
+    return EBADF;
+
+  /* Connect for UDP is the default dest, it's legal to change it. */
+  if (remote_addr_ != 0) {
+    mount_->ppapi()->ReleaseResource(remote_addr_);
+    remote_addr_ = 0;
+  }
+
+  remote_addr_ = SockAddrToResource(addr, len);
+  if (0 == remote_addr_)
+    return EINVAL;
+
+  return 0;
+}
+
+Error MountNodeUDP::RecvFromHelper(void* buf,
+                                   size_t len,
+                                   int flags,
+                                   PP_Resource* out_addr,
+                                   int* out_len) {
+  if (0 == socket_resource_)
+    return EBADF;
+
+  int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+  int err =  UDPSocket()->RecvFrom(socket_resource_,
+                                   static_cast<char*>(buf),
+                                   capped_len,
+                                   out_addr,
+                                   PP_BlockUntilComplete());
+  if (err < 0)
+    return PPErrorToErrno(err);
+
+  *out_len = err;
+  return 0;
+}
+
+Error MountNodeUDP::Recv(void* buf, size_t len, int flags, int* out_len) {
+  while (1) {
+    int local_len = 0;
+    PP_Resource addr = 0;
+
+    int err = RecvFromHelper(buf, len, flags, &addr, &local_len);
+    if (err < 0)
+      return PPErrorToErrno(err);
+
+    /* If "connected" then only receive packets from the given remote. */
+    bool same = IsEquivalentAddress(addr, remote_addr_);
+    mount_->ppapi()->ReleaseResource(addr);
+
+    if (remote_addr_ != 0 && same)
+      continue;
+
+    *out_len = local_len;
+    return 0;
+  }
+}
+
+Error MountNodeUDP::RecvFrom(void* buf,
+                             size_t len,
+                             int flags,
+                             struct sockaddr* src_addr,
+                             socklen_t* addrlen,
+                             int* out_len) {
+  PP_Resource addr = 0;
+  int err = RecvFromHelper(buf, len, flags, &addr, out_len);
+  if (err < 0)
+    return PPErrorToErrno(err);
+
+  if (src_addr)
+    *addrlen = ResourceToSockAddr(addr, *addrlen, src_addr);
+
+  mount_->ppapi()->ReleaseResource(addr);
+  return 0;
+}
+
+
+Error MountNodeUDP::SendToHelper(const void* buf,
+                                 size_t len,
+                                 int flags,
+                                 PP_Resource addr,
+                                 int* out_len) {
+  if (0 == socket_resource_)
+    return EBADF;
+
+  if (0 == addr)
+    return ENOTCONN;
+
+  int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+  int err = UDPSocket()->SendTo(socket_resource_,
+                                static_cast<const char*>(buf),
+                                capped_len,
+                                addr,
+                                PP_BlockUntilComplete());
+  if (err < 0)
+    return PPErrorToErrno(err);
+
+  *out_len = err;
+  return 0;
+}
+
+Error MountNodeUDP::Send(const void* buf, size_t len, int flags, int* out_len) {
+  return SendToHelper(buf, len, flags, remote_addr_, out_len);
+}
+
+Error MountNodeUDP::SendTo(const void* buf,
+                           size_t len,
+                           int flags,
+                           const struct sockaddr* dest_addr,
+                           socklen_t addrlen,
+                           int* out_len) {
+  PP_Resource out_addr = SockAddrToResource(dest_addr, addrlen);
+  if (0 == out_addr)
+    return EINVAL;
+
+  Error err = SendToHelper(buf, len, flags, out_addr, out_len);
+  mount_->ppapi()->ReleaseResource(out_addr);
+  return err;
+}
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
\ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_udp.h b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.h
new file mode 100644
index 0000000..ac095f1
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.h
@@ -0,0 +1,64 @@
+// 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_MOUNT_NODE_UDP_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_UDP_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <ppapi/c/pp_resource.h>
+#include <ppapi/c/ppb_udp_socket.h>
+
+#include "nacl_io/mount_node.h"
+#include "nacl_io/mount_node_socket.h"
+
+namespace nacl_io {
+
+class MountNodeUDP : public MountNodeSocket {
+ public:
+  explicit MountNodeUDP(Mount* mount);
+
+  virtual Error Init(int flags);
+
+  virtual Error Bind(const struct sockaddr* addr, socklen_t len);
+  virtual Error Connect(const struct sockaddr* addr, socklen_t len);
+
+  virtual Error Recv(void* buf, size_t len, int flags, int* out_len);
+  virtual Error RecvFrom(void* buf,
+                         size_t len,
+                         int flags,
+                         struct sockaddr* src_addr,
+                         socklen_t* addrlen,
+                         int* out_len);
+
+  virtual Error Send(const void* buf, size_t len, int flags, int* out_len);
+  virtual Error SendTo(const void* buf,
+                       size_t len,
+                       int flags,
+                       const struct sockaddr* dest_addr,
+                       socklen_t addrlen,
+                       int* out_len);
+
+ protected:
+  UDPSocketInterface* UDPSocket();
+
+  Error RecvFromHelper(void* buf,
+                       size_t len,
+                       int flags,
+                       PP_Resource* addr,
+                       int* out_len);
+
+  Error SendToHelper(const void* buf,
+                     size_t len,
+                     int flags,
+                     PP_Resource dest_addr,
+                     int* out_len);
+};
+
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
+#endif  // LIBRARIES_NACL_IO_MOUNT_NODE_UDP_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_socket.cc b/native_client_sdk/src/libraries/nacl_io/mount_socket.cc
new file mode 100644
index 0000000..141c930
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_socket.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 "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/mount_socket.h"
+
+namespace nacl_io {
+
+MountSocket::MountSocket() {}
+
+Error MountSocket::Access(const Path& path, int a_mode) { return EACCES; }
+Error MountSocket::Open(const Path& path,
+                        int o_flags,
+                        ScopedMountNode* out_node) { return EACCES; }
+
+Error MountSocket::Unlink(const Path& path) { return EACCES; }
+Error MountSocket::Mkdir(const Path& path, int permissions) { return EACCES; }
+Error MountSocket::Rmdir(const Path& path) { return EACCES; }
+Error MountSocket::Remove(const Path& path) { return EACCES; }
+
+}  // namespace nacl_io
+#endif  // PROVIDES_SOCKET_API
\ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_socket.h b/native_client_sdk/src/libraries/nacl_io/mount_socket.h
new file mode 100644
index 0000000..f235232
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_socket.h
@@ -0,0 +1,37 @@
+// 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_MOUNT_SOCKET_H_
+#define LIBRARIES_NACL_IO_MOUNT_SOCKET_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include "nacl_io/mount.h"
+
+namespace nacl_io {
+
+class MountSocket : public Mount {
+ protected:
+  MountSocket();
+
+ private:
+  virtual Error Access(const Path& path, int a_mode);
+  virtual Error Open(const Path& path,
+                     int o_flags,
+                     ScopedMountNode* out_node);
+  virtual Error Unlink(const Path& path);
+  virtual Error Mkdir(const Path& path, int permissions);
+  virtual Error Rmdir(const Path& path);
+  virtual Error Remove(const Path& path);
+
+ private:
+  friend class KernelProxy;
+  DISALLOW_COPY_AND_ASSIGN(MountSocket);
+};
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
+#endif  // LIBRARIES_NACL_IO_MOUNT_SOCKET_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/nacl_io.h b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
index 058ba68..4522219 100644
--- a/native_client_sdk/src/libraries/nacl_io/nacl_io.h
+++ b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
@@ -89,7 +89,7 @@
  *             "foo/bar.txt" will attempt to read from the URL
  *             "http://example.com/path/foo/bar.txt".
  *     data: A string of parameters:
- *       "allow_cross_origin_request": If "true", then reads from this
+ *       "allow_cross_origin_requests": If "true", then reads from this
  *           filesystem will follow the CORS standard for cross-origin requests.
  *           See http://www.w3.org/TR/access-control.
  *       "allow_credentials": If "true", credentials are sent with cross-origin
diff --git a/native_client_sdk/src/libraries/nacl_io/ossignal.h b/native_client_sdk/src/libraries/nacl_io/ossignal.h
new file mode 100644
index 0000000..3ce0071
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/ossignal.h
@@ -0,0 +1,17 @@
+/* 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_OSSIGNAL_H_
+#define LIBRARIES_NACL_IO_OSSIGNAL_H_
+
+#ifdef __native_client__
+#include <signal.h>
+#ifdef __GLIBC__
+typedef __sighandler_t sighandler_t;
+#else
+typedef _sig_func_ptr sighandler_t;
+#endif
+#endif
+
+#endif
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
index 1f2e1bf..f1fae29 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
@@ -19,9 +19,15 @@
  */
 
 BEGIN_INTERFACE(ConsoleInterface, PPB_Console, PPB_CONSOLE_INTERFACE_1_0)
-  METHOD3(ConsoleInterface, void, Log, PP_Instance, PP_LogLevel, struct PP_Var)
+  METHOD3(ConsoleInterface, void, Log, PP_Instance, PP_LogLevel, PP_Var)
 END_INTERFACE(ConsoleInterface, PPB_Console)
 
+BEGIN_INTERFACE(CoreInterface, PPB_Core, PPB_CORE_INTERFACE_1_0)
+  METHOD1(CoreInterface, void, AddRefResource, PP_Resource)
+  METHOD1(CoreInterface, void, ReleaseResource, PP_Resource)
+  METHOD0(CoreInterface, PP_Bool, IsMainThread)
+END_INTERFACE(CoreInterface, PPB_Core)
+
 BEGIN_INTERFACE(FileIoInterface, PPB_FileIO, PPB_FILEIO_INTERFACE_1_0)
   METHOD1(FileIoInterface, void, Close, PP_Resource)
   METHOD1(FileIoInterface, PP_Resource, Create, PP_Resource)
@@ -60,12 +66,13 @@
 END_INTERFACE(FileSystemInterface, PPB_FileSystem)
 
 BEGIN_INTERFACE(MessagingInterface, PPB_Messaging, PPB_MESSAGING_INTERFACE_1_0)
-  METHOD2(MessagingInterface, void, PostMessage, PP_Instance, struct PP_Var)
+  METHOD2(MessagingInterface, void, PostMessage, PP_Instance, PP_Var)
 END_INTERFACE(MessagingInterface, PPB_Messaging)
 
 BEGIN_INTERFACE(VarInterface, PPB_Var, PPB_VAR_INTERFACE_1_1)
-  METHOD1(VarInterface, void, Release, struct PP_Var)
-  METHOD2(VarInterface, struct PP_Var, VarFromUtf8, const char *, uint32_t)
+  METHOD1(VarInterface, void, AddRef, PP_Var)
+  METHOD1(VarInterface, void, Release, PP_Var)
+  METHOD2(VarInterface, PP_Var, VarFromUtf8, const char *, uint32_t)
   METHOD2(VarInterface, const char*, VarToUtf8, PP_Var, uint32_t*)
 END_INTERFACE(VarInterface, PPB_Var)
 
@@ -83,6 +90,10 @@
 
 BEGIN_INTERFACE(NetAddressInterface, PPB_NetAddress,
                 PPB_NETADDRESS_INTERFACE_1_0)
+  METHOD2(NetAddressInterface, PP_Resource, CreateFromIPv4Address,
+          PP_Instance, PP_NetAddress_IPv4*)
+  METHOD2(NetAddressInterface, PP_Resource, CreateFromIPv6Address,
+          PP_Instance, PP_NetAddress_IPv6*)
   METHOD1(NetAddressInterface, PP_Bool, IsNetAddress, PP_Resource)
   METHOD1(NetAddressInterface, PP_NetAddress_Family, GetFamily, PP_Resource)
   METHOD2(NetAddressInterface, PP_Bool, DescribeAsIPv4Address, PP_Resource,
@@ -113,3 +124,36 @@
   METHOD2(URLResponseInfoInterface, PP_Var, GetProperty, PP_Resource,
           PP_URLResponseProperty)
 END_INTERFACE(URLResponseInfoInterface, PPB_URLResponseInfo)
+
+BEGIN_INTERFACE(TCPSocketInterface, PPB_TCPSocket,
+                PPB_TCPSOCKET_INTERFACE_1_0)
+  METHOD1(TCPSocketInterface, PP_Resource, Create, PP_Instance)
+  METHOD1(TCPSocketInterface, PP_Bool, IsTCPSocket, PP_Resource)
+  METHOD3(TCPSocketInterface, int32_t, Connect, PP_Resource, PP_Resource,
+          PP_CompletionCallback)
+  METHOD1(TCPSocketInterface, PP_Resource, GetLocalAddress, PP_Resource)
+  METHOD1(TCPSocketInterface, PP_Resource, GetRemoteAddress, PP_Resource)
+  METHOD4(TCPSocketInterface, int32_t, Read, PP_Resource, char*, int32_t,
+          PP_CompletionCallback)
+  METHOD4(TCPSocketInterface, int32_t, Write, PP_Resource, const char*,
+          int32_t, PP_CompletionCallback)
+  METHOD1(TCPSocketInterface, void, Close, PP_Resource)
+  METHOD4(TCPSocketInterface, int32_t, SetOption, PP_Resource,
+          PP_TCPSocket_Option, PP_Var, PP_CompletionCallback)
+END_INTERFACE(TCPSocketInterface, PPB_TCPSocket)
+
+BEGIN_INTERFACE(UDPSocketInterface, PPB_UDPSocket,
+                PPB_UDPSOCKET_INTERFACE_1_0)
+  METHOD1(UDPSocketInterface, PP_Resource, Create, PP_Instance)
+  METHOD1(UDPSocketInterface, PP_Bool, IsUDPSocket, PP_Resource)
+  METHOD3(UDPSocketInterface, int32_t, Bind, PP_Resource, PP_Resource,
+          PP_CompletionCallback)
+  METHOD1(UDPSocketInterface, PP_Resource, GetBoundAddress, PP_Resource)
+  METHOD5(UDPSocketInterface, int32_t, RecvFrom, PP_Resource, char*, int32_t,
+          PP_Resource*, PP_CompletionCallback)
+  METHOD5(UDPSocketInterface, int32_t, SendTo, PP_Resource, const char*,
+          int32_t, PP_Resource, PP_CompletionCallback)
+  METHOD1(UDPSocketInterface, void, Close, PP_Resource)
+  METHOD4(UDPSocketInterface, int32_t, SetOption, PP_Resource,
+          PP_UDPSocket_Option, PP_Var, PP_CompletionCallback)
+END_INTERFACE(UDPSocketInterface, PPB_UDPSocket)
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h b/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h
index 4fb479e..492730d 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h
@@ -4,6 +4,7 @@
 
 #define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString)
 #define END_INTERFACE(BaseClass, PPInterface)
+#define METHOD0(Class, ReturnType, MethodName)
 #define METHOD1(Class, ReturnType, MethodName, Type0)
 #define METHOD2(Class, ReturnType, MethodName, Type0, Type1)
 #define METHOD3(Class, ReturnType, MethodName, Type0, Type1, Type2)
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h b/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h
index d1b8f50..848d4b3 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h
@@ -4,6 +4,7 @@
 
 #undef BEGIN_INTERFACE
 #undef END_INTERFACE
+#undef METHOD0
 #undef METHOD1
 #undef METHOD2
 #undef METHOD3
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc b/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc
index e97c819..84e8305 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc
@@ -8,6 +8,14 @@
 
 namespace nacl_io {
 
+void PepperInterface::AddRefResource(PP_Resource resource) {
+  GetCoreInterface()->AddRefResource(resource);
+}
+
+void PepperInterface::ReleaseResource(PP_Resource resource) {
+  GetCoreInterface()->ReleaseResource(resource);
+}
+
 ScopedResource::ScopedResource(PepperInterface* ppapi, PP_Resource resource)
     : ppapi_(ppapi),
       resource_(resource) {
@@ -25,8 +33,11 @@
 }
 
 int PPErrorToErrno(int32_t err) {
+  // If not an error, then just return it.
+  if (err >= PP_OK)
+    return err;
+
   switch (err) {
-    case PP_OK: return 0;
     case PP_OK_COMPLETIONPENDING: return 0;
     case PP_ERROR_FAILED: return EPERM;
     case PP_ERROR_ABORTED: return EPERM;
@@ -50,6 +61,12 @@
     case PP_ERROR_CONTEXT_LOST: return EPERM;
     case PP_ERROR_NO_MESSAGE_LOOP: return EPERM;
     case PP_ERROR_WRONG_THREAD: return EPERM;
+    case PP_ERROR_CONNECTION_ABORTED: return ECONNABORTED;
+    case PP_ERROR_CONNECTION_REFUSED: return ECONNREFUSED;
+    case PP_ERROR_CONNECTION_FAILED: return ECONNREFUSED;
+    case PP_ERROR_CONNECTION_TIMEDOUT: return ETIMEDOUT;
+    case PP_ERROR_ADDRESS_UNREACHABLE: return ENETUNREACH;
+    case PP_ERROR_ADDRESS_IN_USE: return EADDRINUSE;
   }
 
   return EINVAL;
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
index 6ffe1e6..ac8f6ba 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
@@ -13,6 +13,7 @@
 #include <ppapi/c/pp_resource.h>
 #include <ppapi/c/pp_var.h>
 #include <ppapi/c/ppb_console.h>
+#include <ppapi/c/ppb_core.h>
 #include <ppapi/c/ppb_file_io.h>
 #include <ppapi/c/ppb_file_ref.h>
 #include <ppapi/c/ppb_file_system.h>
@@ -20,15 +21,36 @@
 #include <ppapi/c/ppb_messaging.h>
 #include <ppapi/c/ppb_messaging.h>
 #include <ppapi/c/ppb_net_address.h>
+#include <ppapi/c/ppb_tcp_socket.h>
 #include <ppapi/c/ppb_url_loader.h>
 #include <ppapi/c/ppb_url_request_info.h>
 #include <ppapi/c/ppb_url_response_info.h>
+#include <ppapi/c/ppb_udp_socket.h>
 #include <ppapi/c/ppb_var.h>
 
 #include <sdk_util/macros.h>
 
 namespace nacl_io {
 
+// This class is the base interface for Pepper used by nacl_io.
+//
+// We use #include and macro magic to simplify adding new interfaces. The
+// resulting PepperInterface basically looks like this:
+//
+// class PepperInterface {
+//  public:
+//   virtual ~PepperInterface() {}
+//   virtual PP_Instance GetInstance() = 0;
+//   ...
+//
+//   // Interface getters.
+//   ConsoleInterface* GetConsoleInterface() = 0;
+//   CoreInterface* GetCoreInterface() = 0;
+//   FileIoInterface* GetFileIoInterface() = 0;
+//   ... etc.
+// };
+//
+//
 // Note: To add a new interface:
 //
 // 1. Using one of the other interfaces as a template, add your interface to
@@ -51,11 +73,18 @@
  public:
   virtual ~PepperInterface() {}
   virtual PP_Instance GetInstance() = 0;
-  virtual void AddRefResource(PP_Resource) = 0;
-  virtual void ReleaseResource(PP_Resource) = 0;
-  virtual bool IsMainThread() = 0;
+
+  // Convenience functions. These forward to
+  // GetCoreInterface()->{AddRef,Release}Resource.
+  void AddRefResource(PP_Resource resource);
+  void ReleaseResource(PP_Resource resource);
 
 // Interface getters.
+//
+// These macros expand to definitions like:
+//
+//   CoreInterface* GetCoreInterface() = 0;
+//
 #include "nacl_io/pepper/undef_macros.h"
 #include "nacl_io/pepper/define_empty_macros.h"
 #undef BEGIN_INTERFACE
@@ -65,6 +94,17 @@
 };
 
 // Interface class definitions.
+//
+// Each class will be defined with all pure virtual methods, e.g:
+//
+//   class CoreInterface {
+//    public:
+//     virtual ~CoreInterface() {}
+//     virtual void AddRefResource() = 0;
+//     virtual void ReleaseResource() = 0;
+//     virtual PP_Bool IsMainThread() = 0;
+//   };
+//
 #include "nacl_io/pepper/undef_macros.h"
 #define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
     class BaseClass { \
@@ -72,6 +112,8 @@
       virtual ~BaseClass() {}
 #define END_INTERFACE(BaseClass, PPInterface) \
     };
+#define METHOD0(Class, ReturnType, MethodName) \
+    virtual ReturnType MethodName() = 0;
 #define METHOD1(Class, ReturnType, MethodName, Type0) \
     virtual ReturnType MethodName(Type0) = 0;
 #define METHOD2(Class, ReturnType, MethodName, Type0, Type1) \
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.cc b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.cc
new file mode 100644
index 0000000..384737e
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.cc
@@ -0,0 +1,46 @@
+// 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 "nacl_io/pepper_interface_delegate.h"
+
+namespace nacl_io {
+
+PepperInterfaceDelegate::PepperInterfaceDelegate(PP_Instance instance)
+    : instance_(instance) {
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+  BaseClass##delegate_ = NULL;
+#include "nacl_io/pepper/all_interfaces.h"
+}
+
+PepperInterfaceDelegate::~PepperInterfaceDelegate() {}
+
+PP_Instance PepperInterfaceDelegate::GetInstance() {
+  return instance_;
+}
+
+// Interface getters.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+BaseClass* PepperInterfaceDelegate::Get##BaseClass() { \
+  return BaseClass##delegate_; \
+}
+#include "nacl_io/pepper/all_interfaces.h"
+
+// Interface delegate setters.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+void PepperInterfaceDelegate::Set##BaseClass##Delegate( \
+    BaseClass* delegate) { \
+  BaseClass##delegate_ = delegate; \
+}
+#include "nacl_io/pepper/all_interfaces.h"
+
+}  // namespace nacl_io
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.h
new file mode 100644
index 0000000..d6945a4
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.h
@@ -0,0 +1,82 @@
+/* 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_PEPPER_INTERFACE_DELEGATE_H_
+#define LIBRARIES_NACL_IO_PEPPER_INTERFACE_DELEGATE_H_
+
+#include "nacl_io/pepper_interface.h"
+
+// This class allows you to delegate Interface requests to different
+// PepperInterface-derived classes.
+//
+// For example:
+//  class FooPepperInterface : public PepperInterface {
+//    ...
+//    CoreInterface* GetCoreInterface() { ... };
+//    ...
+//  };
+//
+//  class BarPepperInterface : public PepperInterface {
+//    ...
+//    VarInterface* GetVarInterface() { ... };
+//    ...
+//  };
+//
+//  void SomeFunction() {
+//    FooPepperInterface foo;
+//    BarPepperInterface bar;
+//    PepperInterfaceDelegate delegate(pp_instance);
+//    delegate.SetCoreInterface(foo.GetCoreInterface());
+//    delegate.SetVarInterface(bar.GetVarInterface());
+//    ...
+//  }
+
+namespace nacl_io {
+
+class PepperInterfaceDelegate : public PepperInterface {
+ public:
+  explicit PepperInterfaceDelegate(PP_Instance instance);
+  virtual ~PepperInterfaceDelegate();
+  virtual PP_Instance GetInstance();
+
+// Interface getters.
+//
+// These declarations look like:
+//
+//   CoreInterface* GetCoreInterface();
+//
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+    virtual BaseClass* Get##BaseClass();
+#include "nacl_io/pepper/all_interfaces.h"
+
+// Interface delegate setters.
+//
+// These declarations look like:
+//
+//   void SetCoreInterface(CoreInterface* delegate);
+//
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+    void Set##BaseClass##Delegate(BaseClass* delegate);
+#include "nacl_io/pepper/all_interfaces.h"
+
+ private:
+  PP_Instance instance_;
+// Interface delegate pointers.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+    BaseClass* BaseClass##delegate_;
+#include "nacl_io/pepper/all_interfaces.h"
+};
+
+}  // namespace nacl_io
+
+#endif  // LIBRARIES_NACL_IO_PEPPER_INTERFACE_DELEGATE_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface_dummy.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface_dummy.h
new file mode 100644
index 0000000..5c2271e
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface_dummy.h
@@ -0,0 +1,43 @@
+/* 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_PEPPER_INTERFACE_DUMMY_H_
+#define LIBRARIES_NACL_IO_PEPPER_INTERFACE_DUMMY_H_
+
+#include "nacl_io/pepper_interface.h"
+
+// This class simplifies implementing a PepperInterface-derived class where you
+// don't care about certain interfaces. All interface-getters return NULL by
+// default.
+//
+// For example:
+//
+// class FooPepperInterface : public PepperInterfaceDummy {
+//  public:
+//   CoreInterface* GetCoreInterface() { ... };
+// };
+//
+// // FooPepperInterface is not abstract -- all pure virtual functions have
+// been defined to return NULL.
+
+namespace nacl_io {
+
+class PepperInterfaceDummy : public PepperInterface {
+ public:
+  PepperInterfaceDummy() {}
+  virtual ~PepperInterfaceDummy() {}
+  virtual PP_Instance GetInstance() { return 0; }
+
+// Interface getters.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+    virtual BaseClass* Get##BaseClass() { return NULL; }
+#include "nacl_io/pepper/all_interfaces.h"
+};
+
+}  // namespace nacl_io
+
+#endif  // LIBRARIES_NACL_IO_PEPPER_INTERFACE_DUMMY_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
index f7743b6..53a8a0f 100644
--- a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
+++ b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
@@ -19,6 +19,8 @@
      private: \
       const PPInterface* interface_; \
     };
+#define METHOD0(Class, ReturnType, MethodName) \
+    virtual ReturnType MethodName();
 #define METHOD1(Class, ReturnType, MethodName, Type0) \
     virtual ReturnType MethodName(Type0);
 #define METHOD2(Class, ReturnType, MethodName, Type0, Type1) \
@@ -40,6 +42,10 @@
 
 #define END_INTERFACE(BaseClass, PPInterface)
 
+#define METHOD0(BaseClass, ReturnType, MethodName) \
+    ReturnType Real##BaseClass::MethodName() { \
+      return interface_->MethodName(); \
+    }
 #define METHOD1(BaseClass, ReturnType, MethodName, Type0) \
     ReturnType Real##BaseClass::MethodName(Type0 arg0) { \
       return interface_->MethodName(arg0); \
@@ -69,17 +75,7 @@
 
 RealPepperInterface::RealPepperInterface(PP_Instance instance,
                                          PPB_GetInterface get_browser_interface)
-    : instance_(instance),
-      core_interface_(NULL),
-      message_loop_interface_(NULL) {
-
-  core_interface_ = static_cast<const PPB_Core*>(
-      get_browser_interface(PPB_CORE_INTERFACE));
-  message_loop_interface_ = static_cast<const PPB_MessageLoop*>(
-      get_browser_interface(PPB_MESSAGELOOP_INTERFACE));
-  assert(core_interface_);
-  assert(message_loop_interface_);
-
+    : instance_(instance) {
 #include "nacl_io/pepper/undef_macros.h"
 #include "nacl_io/pepper/define_empty_macros.h"
 #undef BEGIN_INTERFACE
@@ -94,20 +90,6 @@
   return instance_;
 }
 
-void RealPepperInterface::AddRefResource(PP_Resource resource) {
-  if (resource)
-    core_interface_->AddRefResource(resource);
-}
-
-void RealPepperInterface::ReleaseResource(PP_Resource resource) {
-  if (resource)
-    core_interface_->ReleaseResource(resource);
-}
-
-bool RealPepperInterface::IsMainThread() {
-  return core_interface_->IsMainThread();
-}
-
 // Define getter function.
 #include "nacl_io/pepper/undef_macros.h"
 #include "nacl_io/pepper/define_empty_macros.h"
@@ -118,24 +100,5 @@
     }
 #include "nacl_io/pepper/all_interfaces.h"
 
-
-int32_t RealPepperInterface::InitializeMessageLoop() {
-  int32_t result;
-  PP_Resource message_loop = 0;
-  if (core_interface_->IsMainThread()) {
-    // TODO(binji): Spin up the main thread's ppapi work thread.
-    assert(0);
-  } else {
-    message_loop = message_loop_interface_->GetCurrent();
-    if (!message_loop) {
-      message_loop = message_loop_interface_->Create(instance_);
-      result = message_loop_interface_->AttachToCurrentThread(message_loop);
-      assert(result == PP_OK);
-    }
-  }
-
-  return PP_OK;
-}
-
 }  // namespace nacl_io
 
diff --git a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h
index 0bddee1..c6b0a18 100644
--- a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h
+++ b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h
@@ -26,9 +26,6 @@
                       PPB_GetInterface get_browser_interface);
 
   virtual PP_Instance GetInstance();
-  virtual void AddRefResource(PP_Resource);
-  virtual void ReleaseResource(PP_Resource);
-  virtual bool IsMainThread();
 
 // Interface getters.
 #include "nacl_io/pepper/undef_macros.h"
@@ -38,12 +35,8 @@
     virtual BaseClass* Get##BaseClass();
 #include "nacl_io/pepper/all_interfaces.h"
 
-  int32_t InitializeMessageLoop();
-
  private:
   PP_Instance instance_;
-  const PPB_Core* core_interface_;
-  const PPB_MessageLoop* message_loop_interface_;
 
 // Interface pointers.
 #include "nacl_io/pepper/undef_macros.h"
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetispeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetispeed.c
new file mode 100644
index 0000000..747e234
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetispeed.c
@@ -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. */
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+speed_t cfgetispeed(const struct termios *termios_p) {
+  return termios_p->c_ispeed;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetospeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetospeed.c
new file mode 100644
index 0000000..1e6ccb7
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetospeed.c
@@ -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. */
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+speed_t cfgetospeed(const struct termios *termios_p) {
+  return termios_p->c_ospeed;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetispeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetispeed.c
new file mode 100644
index 0000000..7ae776c
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetispeed.c
@@ -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 "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int cfsetispeed(struct termios *termios_p, speed_t speed) {
+  termios_p->c_ispeed = speed;
+  return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetospeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetospeed.c
new file mode 100644
index 0000000..7e13b1a
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetospeed.c
@@ -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 "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int cfsetospeed(struct termios *termios_p, speed_t speed) {
+  termios_p->c_ospeed = speed;
+  return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetspeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetspeed.c
new file mode 100644
index 0000000..3d618e3
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetspeed.c
@@ -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. */
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int cfsetspeed(struct termios *termios_p, speed_t speed) {
+  termios_p->c_ispeed = speed;
+  termios_p->c_ospeed = speed;
+  return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/getdents.c b/native_client_sdk/src/libraries/nacl_io/syscalls/getdents.c
deleted file mode 100644
index 649fea6..0000000
--- a/native_client_sdk/src/libraries/nacl_io/syscalls/getdents.c
+++ /dev/null
@@ -1,10 +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 "nacl_io/kernel_intercept.h"
-#include "nacl_io/kernel_wrap.h"
-
-int getdents(int fd, void* buf, unsigned int count) {
-  return ki_getdents(fd, buf, count);
-}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c b/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c
index dd23530..c1cd7d0 100644
--- a/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c
@@ -2,9 +2,15 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+#include <stdarg.h>
+
 #include "nacl_io/kernel_intercept.h"
 #include "nacl_io/kernel_wrap.h"
 
-int ioctl(int d, int request, char* argp) {
-  return ki_ioctl(d, request, argp);
+int ioctl(int fd, unsigned long request, ...) {
+  va_list ap;
+  va_start(ap, request);
+  char* arg = va_arg(ap, char*);
+  va_end(ap);
+  return ki_ioctl(fd, request, arg);
 }
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/kill.c b/native_client_sdk/src/libraries/nacl_io/syscalls/kill.c
new file mode 100644
index 0000000..9631516
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/kill.c
@@ -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. */
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int kill(pid_t pid, int sig) {
+  return ki_kill(pid, sig);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/signal.c b/native_client_sdk/src/libraries/nacl_io/syscalls/signal.c
new file mode 100644
index 0000000..a111add
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/signal.c
@@ -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. */
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+sighandler_t signal(int signum, sighandler_t handler) {
+  return ki_signal(signum, handler);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/sigset.c b/native_client_sdk/src/libraries/nacl_io/syscalls/sigset.c
new file mode 100644
index 0000000..258c495
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/sigset.c
@@ -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. */
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+sighandler_t sigset(int signum, sighandler_t handler) {
+  return ki_sigset(signum, handler);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcdrain.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcdrain.c
new file mode 100644
index 0000000..49c078b
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcdrain.c
@@ -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 <errno.h>
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int tcdrain(int fd) {
+  errno = ENOSYS;
+  return -1;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcflow.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcflow.c
new file mode 100644
index 0000000..a299153
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcflow.c
@@ -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 <errno.h>
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int tcflow(int fd, int action) {
+  errno = ENOSYS;
+  return -1;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcsendbreak.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcsendbreak.c
new file mode 100644
index 0000000..9674467
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcsendbreak.c
@@ -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 <errno.h>
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int tcsendbreak(int fd, int duration) {
+  errno = ENOSYS;
+  return -1;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/event_test.cc b/native_client_sdk/src/libraries/nacl_io_test/event_test.cc
deleted file mode 100644
index c342799..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/event_test.cc
+++ /dev/null
@@ -1,480 +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 <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#include "gtest/gtest.h"
-
-#include "nacl_io/event_emitter.h"
-#include "nacl_io/event_listener.h"
-#include "nacl_io/kernel_intercept.h"
-#include "nacl_io/kernel_proxy.h"
-#include "nacl_io/kernel_wrap.h"
-
-
-using namespace nacl_io;
-using namespace sdk_util;
-
-class EventEmitterTester : public MountNode {
- public:
-  EventEmitterTester() : MountNode(NULL), event_status_(0), event_cnt_(0) {}
-
-  void SetEventStatus(uint32_t bits) { event_status_ = bits; }
-  uint32_t GetEventStatus() { return event_status_; }
-
-  Error Ioctl(int request, char* arg) {
-    event_status_ = static_cast<uint32_t>(request);
-    return 0;
-  }
-
-  int GetType() { return S_IFSOCK; }
-  int NumEvents() { return event_cnt_; }
-
- public:
-  // Make this function public for testing
-  void RaiseEvent(uint32_t events) {
-    EventEmitter::RaiseEvent(events);
-  }
-
-    // Called after registering locally, but while lock is still held.
-  void ChainRegisterEventInfo(const ScopedEventInfo& event) {
-    event_cnt_++;
-  }
-
-  // Called before unregistering locally, but while lock is still held.
-  void ChainUnregisterEventInfo(const ScopedEventInfo& event) {
-    event_cnt_--;
-  }
-
- protected:
-  uint32_t event_status_;
-  uint32_t event_cnt_;
-};
-
-
-const int MAX_EVENTS = 8;
-
-// IDs for Emitters
-const int ID_EMITTER = 5;
-const int ID_LISTENER = 6;
-const int ID_EMITTER_DUP = 7;
-
-// Kernel Event values
-const uint32_t KE_EXPECTED = 4;
-const uint32_t KE_FILTERED = 2;
-const uint32_t KE_NONE = 0;
-
-// User Data values
-const uint64_t USER_DATA_A = 1;
-const uint64_t USER_DATA_B = 5;
-
-// Timeout durations
-const int TIMEOUT_IMMEDIATE = 0;
-const int TIMEOUT_SHORT= 100;
-const int TIMEOUT_LONG = 500;
-const int TIMEOUT_NEVER = -1;
-const int TIMEOUT_VERY_LONG = 1000;
-
-// We subtract TIMEOUT_SLOP from the expected minimum timed due to rounding
-// and clock drift converting between absolute and relative time.  This should
-// only be 1 for Less Than, and 1 for rounding, but we use 10 since we don't
-// care about real precision, aren't testing of the underlying
-// implementations and don't want flakiness.
-const int TIMEOUT_SLOP = 10;
-
-TEST(EventTest, EmitterBasic) {
-  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
-  ScopedRef<EventEmitter> null_emitter;
-
-  ScopedEventListener listener(new EventListener);
-
-  // Verify construction
-  EXPECT_EQ(0, emitter->NumEvents());
-  EXPECT_EQ(0, emitter->GetEventStatus());
-
-  // Verify status
-  emitter->SetEventStatus(KE_EXPECTED);
-  EXPECT_EQ(KE_EXPECTED, emitter->GetEventStatus());
-
-  // Fail to update or free an ID not in the set
-  EXPECT_EQ(ENOENT, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
-  EXPECT_EQ(ENOENT, listener->Free(ID_EMITTER));
-
-  // Fail to Track self
-  EXPECT_EQ(EINVAL, listener->Track(ID_LISTENER,
-                                    listener,
-                                    KE_EXPECTED,
-                                    USER_DATA_A));
-
-  // Set the emitter filter and data
-  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
-  EXPECT_EQ(1, emitter->NumEvents());
-
-  // Fail to add the same ID
-  EXPECT_EQ(EEXIST,
-            listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
-  EXPECT_EQ(1, emitter->NumEvents());
-
-  int event_cnt = 0;
-  EventData ev[MAX_EVENTS];
-
-  // Do not allow a wait with a zero events count.
-  EXPECT_EQ(EINVAL, listener->Wait(ev, 0, TIMEOUT_IMMEDIATE, &event_cnt));
-
-  // Do not allow a wait with a negative events count.
-  EXPECT_EQ(EINVAL, listener->Wait(ev, -1, TIMEOUT_IMMEDIATE, &event_cnt));
-
-  // Do not allow a wait with a NULL EventData pointer
-  EXPECT_EQ(EFAULT,
-            listener->Wait(NULL, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
-
-  // Return with no events if the Emitter has no signals set.
-  memset(ev, 0, sizeof(ev));
-  event_cnt = 100;
-  emitter->SetEventStatus(KE_NONE);
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
-  EXPECT_EQ(0, event_cnt);
-
-  // Return with no events if the Emitter has a filtered signals set.
-  memset(ev, 0, sizeof(ev));
-  event_cnt = 100;
-  emitter->SetEventStatus(KE_FILTERED);
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
-  EXPECT_EQ(0, event_cnt);
-
-  // Return with one event if the Emitter has the expected signal set.
-  memset(ev, 0, sizeof(ev));
-  event_cnt = 100;
-  emitter->SetEventStatus(KE_EXPECTED);
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
-  EXPECT_EQ(1, event_cnt);
-  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-
-  // Return with one event containing only the expected signal.
-  memset(ev, 0, sizeof(ev));
-  event_cnt = 100;
-  emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
-  EXPECT_EQ(1, event_cnt);
-  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-
-  // Change the USER_DATA on an existing event
-  EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_B));
-
-  // Return with one event signaled with the alternate USER DATA
-  memset(ev, 0, sizeof(ev));
-  event_cnt = 100;
-  emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, 0, &event_cnt));
-  EXPECT_EQ(1, event_cnt);
-  EXPECT_EQ(USER_DATA_B, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-
-  // Reset the USER_DATA.
-  EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
-
-  // Support adding a DUP.
-  EXPECT_EQ(0, listener->Track(ID_EMITTER_DUP,
-                               emitter,
-                               KE_EXPECTED,
-                               USER_DATA_A));
-  EXPECT_EQ(2, emitter->NumEvents());
-
-  // Return unsignaled.
-  memset(ev, 0, sizeof(ev));
-  emitter->SetEventStatus(KE_NONE);
-  event_cnt = 100;
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
-  EXPECT_EQ(0, event_cnt);
-
-  // Return with two event signaled with expected data.
-  memset(ev, 0, sizeof(ev));
-  emitter->SetEventStatus(KE_EXPECTED);
-  event_cnt = 100;
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
-  EXPECT_EQ(2, event_cnt);
-  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-  EXPECT_EQ(USER_DATA_A, ev[1].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[1].events);
-}
-
-long Duration(struct timeval* start, struct timeval* end) {
-  if (start->tv_usec > end->tv_usec) {
-    end->tv_sec -= 1;
-    end->tv_usec += 1000000;
-  }
-  long cur_time = 1000 * (end->tv_sec - start->tv_sec);
-  cur_time += (end->tv_usec - start->tv_usec) / 1000;
-  return cur_time;
-}
-
-
-// Run a timed wait, and return the average of 8 iterations to reduce
-// chance of false negative on outlier.
-const int TRIES_TO_AVERAGE = 8;
-bool TimedListen(ScopedEventListener& listen,
-                 EventData* ev,
-                 int ev_max,
-                 int ev_expect,
-                 int ms_wait,
-                 long* duration) {
-
-  struct timeval start;
-  struct timeval end;
-  long total_time = 0;
-
-  for (int a=0; a < TRIES_TO_AVERAGE; a++) {
-    gettimeofday(&start, NULL);
-
-    int signaled;
-
-    EXPECT_EQ(0, listen->Wait(ev, ev_max, ms_wait, &signaled));
-    EXPECT_EQ(signaled, ev_expect);
-
-    if (signaled != ev_expect) {
-      return false;
-    }
-
-    gettimeofday(&end, NULL);
-
-    long cur_time = Duration(&start, &end);
-    total_time += cur_time;
-  }
-
-  *duration = total_time / TRIES_TO_AVERAGE;
-  return true;
-}
-
-
-// NOTE:  These timing tests are potentially flaky, the real test is
-// for the zero timeout should be, has the ConditionVariable been waited on?
-// Once we provide a debuggable SimpleCond and SimpleLock we can actually test
-// the correct thing.
-
-// Normal scheduling would expect us to see ~10ms accuracy, but we'll
-// use a much bigger number (yet smaller than the MAX_MS_TIMEOUT).
-const int SCHEDULING_GRANULARITY = 100;
-
-const int EXPECT_ONE_EVENT = 1;
-const int EXPECT_NO_EVENT = 0;
-
-TEST(EventTest, EmitterTimeout) {
-  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
-  ScopedEventListener listener(new EventListener());
-  long duration;
-
-  EventData ev[MAX_EVENTS];
-  memset(ev, 0, sizeof(ev));
-  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
-
-  // Return immediately when emitter is signaled, with no timeout
-  emitter->SetEventStatus(KE_EXPECTED);
-  memset(ev, 0, sizeof(ev));
-  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
-                          TIMEOUT_IMMEDIATE, &duration));
-  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-  EXPECT_EQ(0, duration);
-
-  // Return immediately when emitter is signaled, even with timeout
-  emitter->SetEventStatus(KE_EXPECTED);
-  memset(ev, 0, sizeof(ev));
-  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
-                          TIMEOUT_LONG, &duration));
-  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-  EXPECT_GT(SCHEDULING_GRANULARITY, duration);
-
-  // Return immediately if Emiiter is already signaled when blocking forever.
-  emitter->SetEventStatus(KE_EXPECTED);
-  memset(ev, 0, sizeof(ev));
-  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
-                          TIMEOUT_NEVER, &duration));
-  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-  EXPECT_GT(SCHEDULING_GRANULARITY, duration);
-
-  // Return immediately if Emitter is no signaled when not blocking.
-  emitter->SetEventStatus(KE_NONE);
-  memset(ev, 0, sizeof(ev));
-  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
-                          TIMEOUT_IMMEDIATE, &duration));
-  EXPECT_EQ(0, duration);
-
-  // Wait TIMEOUT_LONG if the emitter is not in a signaled state.
-  emitter->SetEventStatus(KE_NONE);
-  memset(ev, 0, sizeof(ev));
-  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
-                          TIMEOUT_LONG, &duration));
-  EXPECT_LT(TIMEOUT_LONG - TIMEOUT_SLOP, duration);
-  EXPECT_GT(TIMEOUT_LONG + SCHEDULING_GRANULARITY, duration);
-}
-
-struct SignalInfo {
-  EventEmitterTester* em;
-  unsigned int ms_wait;
-  uint32_t events;
-};
-
-void *SignalEmitter(void *ptr) {
-  SignalInfo* info = (SignalInfo*) ptr;
-  struct timespec ts;
-  ts.tv_sec = 0;
-  ts.tv_nsec = info->ms_wait * 1000000;
-
-  nanosleep(&ts, NULL);
-
-  info->em->RaiseEvent(info->events);
-  return NULL;
-}
-
-TEST(EventTest, EmitterSignalling) {
-  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
-  ScopedEventListener listener(new EventListener);
-
-  SignalInfo siginfo;
-  struct timeval start;
-  struct timeval end;
-  long duration;
-
-  EventData ev[MAX_EVENTS];
-  memset(ev, 0, sizeof(ev));
-  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
-
-  // Setup another thread to wait 1/4 of the max time, and signal both
-  // an expected, and unexpected value.
-  siginfo.em = emitter.get();
-  siginfo.ms_wait = TIMEOUT_SHORT;
-  siginfo.events = KE_EXPECTED | KE_FILTERED;
-  pthread_t tid;
-  pthread_create(&tid, NULL, SignalEmitter, &siginfo);
-
-  // Wait for the signal from the other thread and time it.
-  gettimeofday(&start, NULL);
-  int cnt = 0;
-  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_VERY_LONG, &cnt));
-  EXPECT_EQ(1, cnt);
-  gettimeofday(&end, NULL);
-
-  // Verify the wait duration, and that we only recieved the expected signal.
-  duration = Duration(&start, &end);
-  EXPECT_GT(TIMEOUT_SHORT + SCHEDULING_GRANULARITY, duration);
-  EXPECT_LT(TIMEOUT_SHORT - TIMEOUT_SLOP, duration);
-  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
-  EXPECT_EQ(KE_EXPECTED, ev[0].events);
-}
-
-
-namespace {
-
-class KernelProxyPolling : public KernelProxy {
- public:
-  virtual int socket(int domain, int type, int protocol) {
-    ScopedMount mnt;
-    ScopedMountNode node(new EventEmitterTester());
-    ScopedKernelHandle handle(new KernelHandle(mnt, node));
-
-    Error error = handle->Init(0);
-    if (error) {
-      errno = error;
-      return -1;
-    }
-
-    return AllocateFD(handle);
-  }
-};
-
-class KernelProxyPollingTest : public ::testing::Test {
- public:
-  KernelProxyPollingTest() : kp_(new KernelProxyPolling) {
-    ki_init(kp_);
-  }
-
-  ~KernelProxyPollingTest() {
-    ki_uninit();
-    delete kp_;
-  }
-
-  KernelProxyPolling* kp_;
-};
-
-}  // namespace
-
-
-#define SOCKET_CNT 4
-void SetFDs(fd_set* set, int* fds) {
-  FD_ZERO(set);
-
-  FD_SET(0, set);
-  FD_SET(1, set);
-  FD_SET(2, set);
-
-  for (int index = 0; index < SOCKET_CNT; index++)
-    FD_SET(fds[index], set);
-}
-
-TEST_F(KernelProxyPollingTest, Select) {
-  int fds[SOCKET_CNT];
-
-  fd_set rd_set;
-  fd_set wr_set;
-
-  FD_ZERO(&rd_set);
-  FD_ZERO(&wr_set);
-
-  FD_SET(0, &rd_set);
-  FD_SET(1, &rd_set);
-  FD_SET(2, &rd_set);
-
-  FD_SET(0, &wr_set);
-  FD_SET(1, &wr_set);
-  FD_SET(2, &wr_set);
-
-  // Expect normal files to select as read, write, and error
-  int cnt = select(4, &rd_set, &rd_set, &rd_set, NULL);
-  EXPECT_EQ(3 * 3, cnt);
-  EXPECT_NE(0, FD_ISSET(0, &rd_set));
-  EXPECT_NE(0, FD_ISSET(1, &rd_set));
-  EXPECT_NE(0, FD_ISSET(2, &rd_set));
-
-  for (int index = 0 ; index < SOCKET_CNT; index++) {
-    fds[index] = socket(0, 0, 0);
-    EXPECT_NE(-1, fds[index]);
-  }
-
-  // Highest numbered fd
-  const int fdnum = fds[SOCKET_CNT - 1] + 1;
-
-  // Expect only the normal files to select
-  SetFDs(&rd_set, fds);
-  cnt = select(fds[SOCKET_CNT-1] + 1, &rd_set, NULL, NULL, NULL);
-  EXPECT_EQ(3, cnt);
-  EXPECT_NE(0, FD_ISSET(0, &rd_set));
-  EXPECT_NE(0, FD_ISSET(1, &rd_set));
-  EXPECT_NE(0, FD_ISSET(2, &rd_set));
-  for (int index = 0 ; index < SOCKET_CNT; index++) {
-    EXPECT_EQ(0, FD_ISSET(fds[index], &rd_set));
-  }
-
-  // Poke one of the pollable nodes to be READ ready
-  ioctl(fds[0], POLLIN, NULL);
-
-  // Expect normal files to be read/write and one pollable node to be read.
-  SetFDs(&rd_set, fds);
-  SetFDs(&wr_set, fds);
-  cnt = select(fdnum, &rd_set, &wr_set, NULL, NULL);
-  EXPECT_EQ(7, cnt);
-  EXPECT_NE(0, FD_ISSET(fds[0], &rd_set));
-  EXPECT_EQ(0, FD_ISSET(fds[0], &wr_set));
-}
-
-
diff --git a/native_client_sdk/src/libraries/nacl_io_test/example.dsc b/native_client_sdk/src/libraries/nacl_io_test/example.dsc
deleted file mode 100644
index 3c1226e..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/example.dsc
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-  'TOOLS': ['newlib', 'glibc', 'pnacl'],
-  'SEL_LDR': True,
-
-  # Need to add ../../examples for common.js
-  'SEARCH': ['.', '../../examples'],
-  'TARGETS': [
-    {
-      'NAME' : 'nacl_io_test',
-      'TYPE' : 'main',
-      'SOURCES' : [
-        'event_test.cc',
-        'kernel_object_test.cc',
-        'kernel_proxy_mock.cc',
-        'kernel_proxy_mock.h',
-        'kernel_proxy_test.cc',
-        'kernel_wrap_test.cc',
-        'main.cc',
-        'mock_util.h',
-        'mount_html5fs_test.cc',
-        'mount_http_test.cc',
-        'mount_mock.cc',
-        'mount_mock.h',
-        'mount_node_mock.cc',
-        'mount_node_mock.h',
-        'mount_node_test.cc',
-        'mount_test.cc',
-        'path_test.cc',
-        'pepper_interface_mock.cc',
-        'pepper_interface_mock.h',
-	'socket_test.cc',
-      ],
-      'DEPS': ['ppapi_simple', 'nacl_io'],
-      # Order matters here: gtest has a "main" function that will be used if
-      # referenced before ppapi.
-      'LIBS': ['gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
-      'INCLUDES': ['$(NACL_SDK_ROOT)/include/gtest/internal'],
-      'CXXFLAGS': ['-Wno-sign-compare', '-Wno-unused-private-field'],
-      'CFLAGS_GCC': ['-Wno-unused-local-typedefs'],
-    }
-  ],
-  'DATA': [
-    'example.js'
-  ],
-  'DEST': 'tests',
-  'NAME': 'nacl_io_test',
-  'TITLE': 'NaCl IO test',
-}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/example.js b/native_client_sdk/src/libraries/nacl_io_test/example.js
deleted file mode 100644
index bd17594..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/example.js
+++ /dev/null
@@ -1,85 +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.
-// Called by the common.js module.
-function moduleDidLoad() {
-  // The module is not hidden by default so we can easily see if the plugin
-  // failed to load.
-  common.hideModule();
-}
-
-var currentTestEl = null;
-
-function startCommand(testName) {
-  var testListEl = document.getElementById('tests');
-  var testEl = document.createElement('li');
-  var testRowEl = document.createElement('div');
-  var testNameEl = document.createElement('span');
-  var testResultEl = document.createElement('span');
-  testRowEl.classList.add('row');
-  testNameEl.classList.add('name');
-  testNameEl.textContent = testName;
-  testResultEl.classList.add('result');
-  testRowEl.appendChild(testNameEl);
-  testRowEl.appendChild(testResultEl);
-  testEl.appendChild(testRowEl);
-  testListEl.appendChild(testEl);
-
-  currentTestEl = testEl;
-}
-
-function failCommand(fileName, lineNumber, summary) {
-  var testMessageEl = document.createElement('pre');
-  testMessageEl.textContent += fileName + ':' + lineNumber + ': ' + summary;
-  currentTestEl.appendChild(testMessageEl);
-}
-
-function endCommand(testName, testResult) {
-  var testRowEl = currentTestEl.querySelector('.row');
-  var testResultEl = currentTestEl.querySelector('.result');
-  testRowEl.classList.add(testResult);
-  testResultEl.textContent = testResult;
-}
-
-function handleMessage(event) {
-  var msg = event.data;
-  var firstColon = msg.indexOf(':');
-  var cmd = msg.substr(0, firstColon);
-  var cmdFunctionName = cmd + 'Command';
-  var cmdFunction = window[cmdFunctionName];
-
-  if (typeof(cmdFunction) !== 'function') {
-    console.log('Unknown command: ' + cmd);
-    console.log('  message: ' + msg);
-    return;
-  }
-
-  var argCount = cmdFunction.length;
-
-  // Don't use split, because it will split all commas (for example any commas
-  // in the test failure summary).
-  var argList = msg.substr(firstColon + 1);
-  args = [];
-  for (var i = 0; i < argCount - 1; ++i) {
-    var arg;
-    var comma = argList.indexOf(',');
-    if (comma === -1) {
-      if (i !== argCount - 1) {
-        console.log('Bad arg count to command "' + cmd + '", expected ' +
-                    argCount);
-        console.log('  message: ' + msg);
-      } else {
-        arg = argList;
-      }
-    } else {
-      arg = argList.substr(0, comma);
-      argList = argList.substr(comma + 1);
-    }
-    args.push(arg);
-  }
-
-  // Last argument is the rest of the message.
-  args.push(argList);
-
-  cmdFunction.apply(null, args);
-}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
deleted file mode 100644
index 025402f..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
+++ /dev/null
@@ -1,192 +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 <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <sys/stat.h>
-
-#include <map>
-#include <string>
-
-#include "nacl_io/kernel_handle.h"
-#include "nacl_io/kernel_object.h"
-#include "nacl_io/mount.h"
-#include "nacl_io/path.h"
-
-#include "gtest/gtest.h"
-
-using namespace nacl_io;
-
-namespace {
-
-class MountNodeRefMock : public MountNode {
- public:
-  MountNodeRefMock(Mount* mnt) : MountNode(mnt) {}
-};
-
-class MountRefMock : public Mount {
- public:
-  MountRefMock() {}
-  ~MountRefMock() {}
-
- public:
-  Error Access(const Path& path, int a_mode) { return ENOSYS; }
-  Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
-    out_node->reset(NULL);
-    return ENOSYS;
-  }
-  Error Unlink(const Path& path) { return 0; }
-  Error Mkdir(const Path& path, int permissions) { return 0; }
-  Error Rmdir(const Path& path) { return 0; }
-  Error Remove(const Path& path) { return 0; }
-};
-
-class KernelHandleRefMock : public KernelHandle {
- public:
-  KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node)
-      : KernelHandle(mnt, node) {}
-
-  ~KernelHandleRefMock() {}
-};
-
-class KernelObjectTest : public ::testing::Test {
- public:
-  KernelObjectTest() {
-    proxy = new KernelObject;
-    mnt.reset(new MountRefMock());
-    node.reset(new MountNodeRefMock(mnt.get()));
-  }
-
-  ~KernelObjectTest() {
-    // mnt is ref-counted, it doesn't need to be explicitly deleted.
-    node.reset(NULL);
-    mnt.reset(NULL);
-    delete proxy;
-  }
-
-  KernelObject* proxy;
-  ScopedMount mnt;
-  ScopedMountNode node;
-};
-
-}  // namespace
-
-#include <nacl_io/mount_mem.h>
-#include <nacl_io/mount_http.h>
-
-TEST_F(KernelObjectTest, Referencing) {
-  // The mount and node should have 1 ref count at this point
-  EXPECT_EQ(1, mnt->RefCount());
-  EXPECT_EQ(1, node->RefCount());
-
-  // Pass the mount and node into a KernelHandle
-  KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
-  ScopedKernelHandle handle_a(raw_handle);
-
-  // The mount and node should have 1 ref count at this point
-  EXPECT_EQ(1, handle_a->RefCount());
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-
-  ScopedKernelHandle handle_b = handle_a;
-
-  // There should be two references to the KernelHandle, the mount and node
-  // should be unchanged.
-  EXPECT_EQ(2, handle_a->RefCount());
-  EXPECT_EQ(2, handle_b->RefCount());
-  EXPECT_EQ(handle_a.get(), handle_b.get());
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-
-  // Allocating an FD should cause the KernelProxy to ref the handle and
-  // the node and mount should be unchanged.
-  int fd1 = proxy->AllocateFD(handle_a);
-  EXPECT_EQ(3, handle_a->RefCount());
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-
-  // If we "dup" the handle, we should bump the ref count on the handle
-  int fd2 = proxy->AllocateFD(handle_b);
-  EXPECT_EQ(4, handle_a->RefCount());
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-
-  // Handles are expected to come out in order
-  EXPECT_EQ(0, fd1);
-  EXPECT_EQ(1, fd2);
-
-  // Now we "free" the handles, since the proxy should hold them.
-  handle_a.reset(NULL);
-  handle_b.reset(NULL);
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-
-  // We should find the handle by either fd
-  EXPECT_EQ(0, proxy->AcquireHandle(fd1, &handle_a));
-  EXPECT_EQ(0, proxy->AcquireHandle(fd2, &handle_b));
-  EXPECT_EQ(raw_handle, handle_a.get());
-  EXPECT_EQ(raw_handle, handle_b.get());
-
-  EXPECT_EQ(4, handle_a->RefCount());
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-
-  // A non existent fd should fail, and handleA should decrement as handleB
-  // is released by the call.
-  EXPECT_EQ(EBADF, proxy->AcquireHandle(-1, &handle_b));
-  EXPECT_EQ(NULL, handle_b.get());
-  EXPECT_EQ(3, handle_a->RefCount());
-
-  EXPECT_EQ(EBADF, proxy->AcquireHandle(100, &handle_b));
-  EXPECT_EQ(NULL, handle_b.get());
-
-  // Now only the KernelProxy should reference the KernelHandle in the
-  // FD to KernelHandle Map.
-  handle_a.reset();
-  handle_b.reset();
-
-  EXPECT_EQ(2, raw_handle->RefCount());
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-  proxy->FreeFD(fd2);
-  EXPECT_EQ(1, raw_handle->RefCount());
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-
-  proxy->FreeFD(fd1);
-  EXPECT_EQ(1, mnt->RefCount());
-  EXPECT_EQ(1, node->RefCount());
-}
-
-TEST_F(KernelObjectTest, FreeAndReassignFD) {
-  // The mount and node should have 1 ref count at this point
-  EXPECT_EQ(1, mnt->RefCount());
-  EXPECT_EQ(1, node->RefCount());
-
-  KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
-  ScopedKernelHandle handle(raw_handle);
-
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-  EXPECT_EQ(1, raw_handle->RefCount());
-
-  proxy->AllocateFD(handle);
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-  EXPECT_EQ(2, raw_handle->RefCount());
-
-  proxy->FreeAndReassignFD(5, handle);
-  EXPECT_EQ(2, mnt->RefCount());
-  EXPECT_EQ(2, node->RefCount());
-  EXPECT_EQ(3, raw_handle->RefCount());
-
-  handle.reset();
-  EXPECT_EQ(2, raw_handle->RefCount());
-
-  proxy->AcquireHandle(5, &handle);
-  EXPECT_EQ(3, raw_handle->RefCount());
-  EXPECT_EQ(raw_handle, handle.get());
-}
-
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
deleted file mode 100644
index 159e3cb..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
+++ /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.
-
-#ifndef LIBRARIES_NACL_IO_TEST_KERNEL_PROXY_MOCK_H_
-#define LIBRARIES_NACL_IO_TEST_KERNEL_PROXY_MOCK_H_
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "gmock/gmock.h"
-
-#include "nacl_io/kernel_proxy.h"
-#include "nacl_io/ossocket.h"
-#include "nacl_io/ostermios.h"
-
-class KernelProxyMock : public nacl_io::KernelProxy {
- public:
-  KernelProxyMock();
-  virtual ~KernelProxyMock();
-
-  MOCK_METHOD2(access, int(const char*, int));
-  MOCK_METHOD1(chdir, int(const char*));
-  MOCK_METHOD2(chmod, int(const char*, mode_t));
-  MOCK_METHOD3(chown, int(const char*, uid_t, gid_t));
-  MOCK_METHOD1(close, int(int));
-  MOCK_METHOD1(dup, int(int));
-  MOCK_METHOD2(dup2, int(int, int));
-  MOCK_METHOD3(fchown, int(int, uid_t, gid_t));
-  MOCK_METHOD2(ftruncate, int(int, off_t));
-  MOCK_METHOD2(fstat, int(int, struct stat*));
-  MOCK_METHOD1(fsync, int(int));
-  MOCK_METHOD2(getcwd, char*(char*, size_t));
-  MOCK_METHOD3(getdents, int(int, void*, unsigned int));
-  MOCK_METHOD1(getwd, char*(char*));
-  MOCK_METHOD3(ioctl, int(int, int, char*));
-  MOCK_METHOD1(isatty, int(int));
-  MOCK_METHOD3(lchown, int(const char*, uid_t, gid_t));
-  MOCK_METHOD3(lseek, off_t(int, off_t, int));
-  MOCK_METHOD2(mkdir, int(const char*, mode_t));
-  MOCK_METHOD5(mount, int(const char*, const char*, const char*, unsigned long,
-                          const void*));
-  MOCK_METHOD2(open, int(const char*, int));
-  MOCK_METHOD3(read, ssize_t(int, void*, size_t));
-  MOCK_METHOD1(remove, int(const char*));
-  MOCK_METHOD1(rmdir, int(const char*));
-  MOCK_METHOD2(stat, int(const char*, struct stat*));
-  MOCK_METHOD2(tcgetattr, int(int, struct termios*));
-  MOCK_METHOD3(tcsetattr, int(int, int, const struct termios*));
-  MOCK_METHOD1(umount, int(const char*));
-  MOCK_METHOD1(unlink, int(const char*));
-  MOCK_METHOD2(utime, int(const char*, const struct utimbuf*));
-  MOCK_METHOD3(write, ssize_t(int, const void*, size_t));
-  MOCK_METHOD2(link, int(const char*, const char*));
-  MOCK_METHOD2(symlink, int(const char*, const char*));
-  MOCK_METHOD6(mmap, void*(void*, size_t, int, int, int, size_t));
-  MOCK_METHOD1(open_resource, int(const char*));
-
-#ifdef PROVIDES_SOCKET_API
-  MOCK_METHOD3(poll, int(struct pollfd*, nfds_t, int));
-  MOCK_METHOD5(select, int(int, fd_set*, fd_set*, fd_set*, struct timeval*));
-
-  // Socket support functions
-  MOCK_METHOD3(accept, int(int, struct sockaddr*, socklen_t*));
-  MOCK_METHOD3(bind, int(int, const struct sockaddr*, socklen_t));
-  MOCK_METHOD3(connect, int(int, const struct sockaddr*, socklen_t));
-  MOCK_METHOD1(gethostbyname, struct hostent*(const char*));
-  MOCK_METHOD3(getpeername, int(int, struct sockaddr*, socklen_t*));
-  MOCK_METHOD3(getsockname, int(int, struct sockaddr*, socklen_t*));
-  MOCK_METHOD5(getsockopt, int(int, int, int, void*, socklen_t*));
-  MOCK_METHOD2(listen, int(int, int));
-  MOCK_METHOD4(recv, ssize_t(int, void*, size_t, int));
-  MOCK_METHOD6(recvfrom, ssize_t(int, void*, size_t, int,
-                                 struct sockaddr*, socklen_t*));
-  MOCK_METHOD3(recvmsg, ssize_t(int, struct msghdr*, int));
-  MOCK_METHOD4(send, ssize_t(int, const void*, size_t, int));
-  MOCK_METHOD6(sendto, ssize_t(int, const void*, size_t, int,
-                               const struct sockaddr*, socklen_t));
-  MOCK_METHOD3(sendmsg, ssize_t(int, const struct msghdr*, int));
-  MOCK_METHOD5(setsockopt, int(int, int, int, const void*, socklen_t));
-  MOCK_METHOD2(shutdown, int(int, int));
-  MOCK_METHOD3(socket, int(int, int, int));
-  MOCK_METHOD4(socketpair, int(int, int, int, int*));
-#endif // PROVIDES_SOCKET_API
-
-};
-
-#endif  // LIBRARIES_NACL_IO_TEST_KERNEL_PROXY_MOCK_H_
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
deleted file mode 100644
index 1eabdd0..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
+++ /dev/null
@@ -1,524 +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 <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <sys/stat.h>
-
-#include <map>
-#include <string>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "mount_mock.h"
-#include "mount_node_mock.h"
-
-#include "nacl_io/kernel_intercept.h"
-#include "nacl_io/kernel_proxy.h"
-#include "nacl_io/mount.h"
-#include "nacl_io/mount_mem.h"
-#include "nacl_io/osmman.h"
-#include "nacl_io/path.h"
-#include "nacl_io/typed_mount_factory.h"
-
-using namespace nacl_io;
-using namespace sdk_util;
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::SaveArg;
-using ::testing::SetArgPointee;
-using ::testing::StrEq;
-using ::testing::WithArgs;
-
-namespace {
-
-class KernelProxyFriend : public KernelProxy {
- public:
-  Mount* RootMount() {
-    ScopedMount mnt;
-    Path path;
-
-    AcquireMountAndRelPath("/", &mnt, &path);
-    return mnt.get();
-  }
-};
-
-class KernelProxyTest : public ::testing::Test {
- public:
-  KernelProxyTest() : kp_(new KernelProxyFriend) {
-    ki_init(kp_);
-    // Unmount the passthrough FS and mount a memfs.
-    EXPECT_EQ(0, kp_->umount("/"));
-    EXPECT_EQ(0, kp_->mount("", "/", "memfs", 0, NULL));
-  }
-
-  ~KernelProxyTest() {
-    ki_uninit();
-    delete kp_;
-  }
-
- protected:
-  KernelProxyFriend* kp_;
-};
-
-}  // namespace
-
-TEST_F(KernelProxyTest, FileLeak) {
-  const size_t buffer_size = 1024;
-  char filename[128];
-  int file_num;
-  int garbage[buffer_size];
-
-  MountMem* mount = (MountMem*)kp_->RootMount();
-  ScopedMountNode root;
-
-  EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
-  EXPECT_EQ(0, root->ChildCount());
-
-  for (file_num = 0; file_num < 4096; file_num++) {
-    sprintf(filename, "/foo%i.tmp", file_num++);
-    FILE* f = fopen(filename, "w");
-    EXPECT_NE((FILE*)0, f);
-    EXPECT_EQ(1, root->ChildCount());
-    EXPECT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
-    fclose(f);
-    EXPECT_EQ(0, remove(filename));
-  }
-  EXPECT_EQ(0, root->ChildCount());
-}
-
-TEST_F(KernelProxyTest, WorkingDirectory) {
-  char text[1024];
-
-  text[0] = 0;
-  ki_getcwd(text, sizeof(text));
-  EXPECT_STREQ("/", text);
-
-  char* alloc = ki_getwd(NULL);
-  EXPECT_EQ((char*)NULL, alloc);
-  EXPECT_EQ(EFAULT, errno);
-
-  text[0] = 0;
-  alloc = ki_getwd(text);
-  EXPECT_STREQ("/", alloc);
-
-  EXPECT_EQ(-1, ki_chdir("/foo"));
-  EXPECT_EQ(ENOENT, errno);
-
-  EXPECT_EQ(0, ki_chdir("/"));
-
-  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
-  EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
-  EXPECT_EQ(EEXIST, errno);
-
-  memset(text, 0, sizeof(text));
-  EXPECT_EQ(0, ki_chdir("foo"));
-  EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
-  EXPECT_STREQ("/foo", text);
-
-  memset(text, 0, sizeof(text));
-  EXPECT_EQ(-1, ki_chdir("foo"));
-  EXPECT_EQ(ENOENT, errno);
-  EXPECT_EQ(0, ki_chdir(".."));
-  EXPECT_EQ(0, ki_chdir("/foo"));
-  EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
-  EXPECT_STREQ("/foo", text);
-}
-
-TEST_F(KernelProxyTest, MemMountIO) {
-  char text[1024];
-  int fd1, fd2, fd3;
-  int len;
-
-  // Fail to delete non existant "/foo"
-  EXPECT_EQ(-1, ki_rmdir("/foo"));
-  EXPECT_EQ(ENOENT, errno);
-
-  // Create "/foo"
-  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
-  EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
-  EXPECT_EQ(EEXIST, errno);
-
-  // Delete "/foo"
-  EXPECT_EQ(0, ki_rmdir("/foo"));
-
-  // Recreate "/foo"
-  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
-
-  // Fail to open "/foo/bar"
-  EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY));
-  EXPECT_EQ(ENOENT, errno);
-
-  // Create bar "/foo/bar"
-  fd1 = ki_open("/foo/bar", O_RDONLY | O_CREAT);
-  EXPECT_NE(-1, fd1);
-
-  // Open (optionally create) bar "/foo/bar"
-  fd2 = ki_open("/foo/bar", O_RDONLY | O_CREAT);
-  EXPECT_NE(-1, fd2);
-
-  // Fail to exclusively create bar "/foo/bar"
-  EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL));
-  EXPECT_EQ(EEXIST, errno);
-
-  // Write hello and world to same node with different descriptors
-  // so that we overwrite each other
-  EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
-  EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
-
-  fd3 = ki_open("/foo/bar", O_WRONLY);
-  EXPECT_NE(-1, fd3);
-
-  len = ki_read(fd3, text, sizeof(text));
-  if (len > 0)
-    text[len] = 0;
-  EXPECT_EQ(5, len);
-  EXPECT_STREQ("HELLO", text);
-  EXPECT_EQ(0, ki_close(fd1));
-  EXPECT_EQ(0, ki_close(fd2));
-
-  fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
-  EXPECT_NE(-1, fd1);
-  EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
-
-  len = ki_read(fd3, text, sizeof(text));
-  if (len >= 0)
-    text[len] = 0;
-
-  EXPECT_EQ(5, len);
-  EXPECT_STREQ("WORLD", text);
-
-  fd2 = ki_open("/foo/bar", O_RDONLY);
-  EXPECT_NE(-1, fd2);
-  len = ki_read(fd2, text, sizeof(text));
-  if (len > 0)
-    text[len] = 0;
-  EXPECT_EQ(10, len);
-  EXPECT_STREQ("HELLOWORLD", text);
-}
-
-TEST_F(KernelProxyTest, MemMountLseek) {
-  int fd = ki_open("/foo", O_CREAT | O_RDWR);
-  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
-
-  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
-  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END));
-  EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
-  EXPECT_EQ(EINVAL, errno);
-
-  // Seek past end of file.
-  EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
-  char buffer[4];
-  memset(&buffer[0], 0xfe, 4);
-  EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
-  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
-  EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
-  EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
-}
-
-TEST_F(KernelProxyTest, CloseTwice) {
-  int fd = ki_open("/foo", O_CREAT | O_RDWR);
-  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
-
-  int fd2 = ki_dup(fd);
-  EXPECT_NE(-1, fd2);
-
-  EXPECT_EQ(0, ki_close(fd));
-  EXPECT_EQ(0, ki_close(fd2));
-}
-
-TEST_F(KernelProxyTest, MemMountDup) {
-  int fd = ki_open("/foo", O_CREAT | O_RDWR);
-
-  int dup_fd = ki_dup(fd);
-  EXPECT_NE(-1, dup_fd);
-
-  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
-  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
-  EXPECT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
-
-  int dup2_fd = 123;
-  EXPECT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
-  EXPECT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
-
-  int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
-
-  EXPECT_EQ(fd, ki_dup2(new_fd, fd));
-  // fd, new_fd -> "/bar"
-  // dup_fd, dup2_fd -> "/foo"
-
-  // We should still be able to write to dup_fd (i.e. it should not be closed).
-  EXPECT_EQ(4, ki_write(dup_fd, "more", 4));
-
-  EXPECT_EQ(0, ki_close(dup2_fd));
-  // fd, new_fd -> "/bar"
-  // dup_fd -> "/foo"
-
-  EXPECT_EQ(dup_fd, ki_dup2(fd, dup_fd));
-  // fd, new_fd, dup_fd -> "/bar"
-}
-
-namespace {
-
-StringMap_t g_StringMap;
-
-class MountMockInit : public MountMem {
- public:
-  virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
-    g_StringMap = args;
-    if (args.find("false") != args.end())
-      return EINVAL;
-    return 0;
-  }
-
-  friend class TypedMountFactory<MountMockInit>;
-};
-
-class KernelProxyMountMock : public KernelProxy {
-  virtual void Init(PepperInterface* ppapi) {
-    KernelProxy::Init(NULL);
-    factories_["initfs"] = new TypedMountFactory<MountMockInit>;
-  }
-};
-
-class KernelProxyMountTest : public ::testing::Test {
- public:
-  KernelProxyMountTest() : kp_(new KernelProxyMountMock) { ki_init(kp_); }
-
-  ~KernelProxyMountTest() {
-    ki_uninit();
-    delete kp_;
-  }
-
- private:
-  KernelProxy* kp_;
-};
-
-}  // namespace
-
-TEST_F(KernelProxyMountTest, MountInit) {
-  int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
-
-  EXPECT_EQ("bar", g_StringMap["foo"]);
-  EXPECT_EQ(-1, res1);
-  EXPECT_EQ(EINVAL, errno);
-
-  int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
-  EXPECT_NE(-1, res2);
-  EXPECT_EQ("y", g_StringMap["x"]);
-}
-
-namespace {
-
-int g_MMapCount = 0;
-
-class MountNodeMockMMap : public MountNode {
- public:
-  MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
-    EXPECT_EQ(0, Init(0));
-  }
-
-  virtual Error MMap(void* addr,
-                     size_t length,
-                     int prot,
-                     int flags,
-                     size_t offset,
-                     void** out_addr) {
-    node_mmap_count_++;
-    switch (g_MMapCount++) {
-      case 0:
-        *out_addr = reinterpret_cast<void*>(0x1000);
-        break;
-      case 1:
-        *out_addr = reinterpret_cast<void*>(0x2000);
-        break;
-      case 2:
-        *out_addr = reinterpret_cast<void*>(0x3000);
-        break;
-      default:
-        return EPERM;
-    }
-
-    return 0;
-  }
-
- private:
-  int node_mmap_count_;
-};
-
-class MountMockMMap : public Mount {
- public:
-  virtual Error Access(const Path& path, int a_mode) { return 0; }
-  virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
-    out_node->reset(new MountNodeMockMMap(this));
-    return 0;
-  }
-
-  virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
-    out_node->reset(NULL);
-    return ENOSYS;
-  }
-  virtual Error Unlink(const Path& path) { return ENOSYS; }
-  virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
-  virtual Error Rmdir(const Path& path) { return ENOSYS; }
-  virtual Error Remove(const Path& path) { return ENOSYS; }
-
-  friend class TypedMountFactory<MountMockMMap>;
-};
-
-class KernelProxyMockMMap : public KernelProxy {
-  virtual void Init(PepperInterface* ppapi) {
-    KernelProxy::Init(NULL);
-    factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
-  }
-};
-
-class KernelProxyMMapTest : public ::testing::Test {
- public:
-  KernelProxyMMapTest() : kp_(new KernelProxyMockMMap) { ki_init(kp_); }
-
-  ~KernelProxyMMapTest() {
-    ki_uninit();
-    delete kp_;
-  }
-
- private:
-  KernelProxy* kp_;
-};
-
-}  // namespace
-
-TEST_F(KernelProxyMMapTest, MMap) {
-  EXPECT_EQ(0, ki_umount("/"));
-  EXPECT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
-  int fd = ki_open("/file", O_RDWR | O_CREAT);
-  EXPECT_NE(-1, fd);
-
-  void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
-  EXPECT_EQ(reinterpret_cast<void*>(0x1000), addr1);
-  EXPECT_EQ(1, g_MMapCount);
-
-  void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
-  EXPECT_EQ(reinterpret_cast<void*>(0x2000), addr2);
-  EXPECT_EQ(2, g_MMapCount);
-
-  void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
-  EXPECT_EQ(reinterpret_cast<void*>(0x3000), addr3);
-  EXPECT_EQ(3, g_MMapCount);
-
-  ki_close(fd);
-
-  // We no longer track mmap'd regions, so munmap is a no-op.
-  EXPECT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
-  // We don't track regions, so the mmap count hasn't changed.
-  EXPECT_EQ(3, g_MMapCount);
-}
-
-namespace {
-
-class SingletonMountFactory : public MountFactory {
- public:
-  SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
-
-  virtual Error CreateMount(int dev,
-                            StringMap_t& args,
-                            PepperInterface* ppapi,
-                            ScopedMount* out_mount) {
-    *out_mount = mount_;
-    return 0;
-  }
-
- private:
-  ScopedMount mount_;
-};
-
-class KernelProxyError : public KernelProxy {
- public:
-  KernelProxyError() : mnt_(new MountMock) {}
-
-  virtual void Init(PepperInterface* ppapi) {
-    KernelProxy::Init(ppapi);
-    factories_["testfs"] = new SingletonMountFactory(mnt_);
-
-    EXPECT_CALL(*mnt_, Destroy()).Times(1);
-  }
-
-  ScopedRef<MountMock> mnt() { return mnt_; }
-
- private:
-  ScopedRef<MountMock> mnt_;
-};
-
-class KernelProxyErrorTest : public ::testing::Test {
- public:
-  KernelProxyErrorTest() : kp_(new KernelProxyError) {
-    ki_init(kp_);
-    // Unmount the passthrough FS and mount a testfs.
-    EXPECT_EQ(0, kp_->umount("/"));
-    EXPECT_EQ(0, kp_->mount("", "/", "testfs", 0, NULL));
-  }
-
-  ~KernelProxyErrorTest() {
-    ki_uninit();
-    delete kp_;
-  }
-
-  ScopedRef<MountMock> mnt() { return kp_->mnt(); }
-
- private:
-  KernelProxyError* kp_;
-};
-
-}  // namespace
-
-TEST_F(KernelProxyErrorTest, WriteError) {
-  ScopedRef<MountMock> mock_mnt(mnt());
-  ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
-  EXPECT_CALL(*mock_mnt, Open(_, _, _))
-      .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
-
-  EXPECT_CALL(*mock_node, Write(_, _, _, _))
-      .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
-                      Return(1234)));       // Returned error 1234.
-
-  EXPECT_CALL(*mock_node, Destroy()).Times(1);
-
-  int fd = ki_open("/dummy", O_WRONLY);
-  EXPECT_NE(0, fd);
-
-  char buf[20];
-  EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
-  // The Mount should be able to return whatever error it wants and have it
-  // propagate through.
-  EXPECT_EQ(1234, errno);
-}
-
-TEST_F(KernelProxyErrorTest, ReadError) {
-  ScopedRef<MountMock> mock_mnt(mnt());
-  ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
-  EXPECT_CALL(*mock_mnt, Open(_, _, _))
-      .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
-
-  EXPECT_CALL(*mock_node, Read(_, _, _, _))
-      .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
-                      Return(1234)));       // Returned error 1234.
-
-  EXPECT_CALL(*mock_node, Destroy()).Times(1);
-
-  int fd = ki_open("/dummy", O_RDONLY);
-  EXPECT_NE(0, fd);
-
-  char buf[20];
-  EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
-  // The Mount should be able to return whatever error it wants and have it
-  // propagate through.
-  EXPECT_EQ(1234, errno);
-}
-
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
deleted file mode 100644
index 34db64a..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
+++ /dev/null
@@ -1,405 +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 <string>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "kernel_proxy_mock.h"
-#include "nacl_io/kernel_intercept.h"
-#include "nacl_io/kernel_wrap.h"
-#include "nacl_io/ossocket.h"
-#include "nacl_io/ostermios.h"
-
-using namespace nacl_io;
-
-using ::testing::_;
-using ::testing::Return;
-using ::testing::StrEq;
-
-namespace {
-
-static const int DUMMY_FD = 5678;
-
-#define COMPARE_FIELD(f) \
-  if (arg->f != statbuf->f) { \
-    *result_listener << "mismatch of field \""#f"\". " \
-      "expected: " << statbuf->f << \
-      " actual: " << arg->f; \
-    return false; \
-  }
-
-MATCHER_P(IsEqualToStatbuf, statbuf, "") {
-  COMPARE_FIELD(st_dev);
-  COMPARE_FIELD(st_ino);
-  COMPARE_FIELD(st_mode);
-  COMPARE_FIELD(st_nlink);
-  COMPARE_FIELD(st_uid);
-  COMPARE_FIELD(st_gid);
-  COMPARE_FIELD(st_rdev);
-  COMPARE_FIELD(st_size);
-  COMPARE_FIELD(st_atime);
-  COMPARE_FIELD(st_mtime);
-  COMPARE_FIELD(st_ctime);
-  return true;
-}
-
-#undef COMPARE_FIELD
-
-ACTION_P(SetStat, statbuf) {
-  memset(arg1, 0, sizeof(struct stat));
-  arg1->st_dev = statbuf->st_dev;
-  arg1->st_ino = statbuf->st_ino;
-  arg1->st_mode = statbuf->st_mode;
-  arg1->st_nlink = statbuf->st_nlink;
-  arg1->st_uid = statbuf->st_uid;
-  arg1->st_gid = statbuf->st_gid;
-  arg1->st_rdev = statbuf->st_rdev;
-  arg1->st_size = statbuf->st_size;
-  arg1->st_atime = statbuf->st_atime;
-  arg1->st_mtime = statbuf->st_mtime;
-  arg1->st_ctime = statbuf->st_ctime;
-  return 0;
-}
-
-void MakeDummyStatbuf(struct stat* statbuf) {
-  memset(&statbuf[0], 0, sizeof(struct stat));
-  statbuf->st_dev = 1;
-  statbuf->st_ino = 2;
-  statbuf->st_mode = 3;
-  statbuf->st_nlink = 4;
-  statbuf->st_uid = 5;
-  statbuf->st_gid = 6;
-  statbuf->st_rdev = 7;
-  statbuf->st_size = 8;
-  statbuf->st_atime = 9;
-  statbuf->st_mtime = 10;
-  statbuf->st_ctime = 11;
-}
-
-const uid_t kDummyUid = 1001;
-const gid_t kDummyGid = 1002;
-
-class KernelWrapTest : public ::testing::Test {
- public:
-  KernelWrapTest() {
-    // Initializing the KernelProxy opens stdin/stdout/stderr.
-    EXPECT_CALL(mock, open(_, _))
-      .WillOnce(Return(0))
-      .WillOnce(Return(1))
-      .WillOnce(Return(2));
-    // And will call mount / and /dev.
-    EXPECT_CALL(mock, mount(_, _, _, _, _))
-      .WillOnce(Return(0))
-      .WillOnce(Return(0));
-
-    ki_init(&mock);
-  }
-
-  ~KernelWrapTest() {
-    ki_uninit();
-  }
-
-  KernelProxyMock mock;
-};
-
-}  // namespace
-
-
-TEST_F(KernelWrapTest, access) {
-  EXPECT_CALL(mock, access(StrEq("access"), 12)).Times(1);
-  access("access", 12);
-}
-
-TEST_F(KernelWrapTest, chdir) {
-  EXPECT_CALL(mock, chdir(StrEq("chdir"))).Times(1);
-  chdir("chdir");
-}
-
-TEST_F(KernelWrapTest, chmod) {
-  EXPECT_CALL(mock, chmod(StrEq("chmod"), 23)).Times(1);
-  chmod("chmod", 23);
-}
-
-TEST_F(KernelWrapTest, chown) {
-  uid_t uid = kDummyUid;
-  gid_t gid = kDummyGid;
-  EXPECT_CALL(mock, chown(StrEq("chown"), uid, gid)).Times(1);
-  chown("chown", uid, gid);
-}
-
-TEST_F(KernelWrapTest, close) {
-  EXPECT_CALL(mock, close(34)).Times(1);
-  close(34);
-}
-
-TEST_F(KernelWrapTest, dup) {
-  EXPECT_CALL(mock, dup(DUMMY_FD)).Times(1);
-  dup(DUMMY_FD);
-}
-
-TEST_F(KernelWrapTest, dup2) {
-  EXPECT_CALL(mock, dup2(DUMMY_FD, 234)).Times(1);
-  dup2(DUMMY_FD, 234);
-}
-
-TEST_F(KernelWrapTest, fchown) {
-  uid_t uid = kDummyUid;
-  gid_t gid = kDummyGid;
-  EXPECT_CALL(mock, fchown(DUMMY_FD, uid, gid)).Times(1);
-  fchown(DUMMY_FD, uid, gid);
-}
-
-TEST_F(KernelWrapTest, fstat) {
-  struct stat in_statbuf;
-  MakeDummyStatbuf(&in_statbuf);
-  EXPECT_CALL(mock, fstat(DUMMY_FD, _))
-      .Times(1)
-      .WillOnce(SetStat(&in_statbuf));
-  struct stat out_statbuf;
-  fstat(DUMMY_FD, &out_statbuf);
-  EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
-}
-
-TEST_F(KernelWrapTest, ftruncate) {
-  EXPECT_CALL(mock, ftruncate(456, 0)).Times(1);
-  ftruncate(456, 0);
-}
-
-TEST_F(KernelWrapTest, fsync) {
-  EXPECT_CALL(mock, fsync(345)).Times(1);
-  fsync(345);
-}
-
-TEST_F(KernelWrapTest, getcwd) {
-  EXPECT_CALL(mock, getcwd(StrEq("getcwd"), 1)).Times(1);
-  char buffer[] = "getcwd";
-  getcwd(buffer, 1);
-}
-
-TEST_F(KernelWrapTest, getdents) {
-  EXPECT_CALL(mock, getdents(456, NULL, 567)).Times(1);
-  getdents(456, NULL, 567);
-}
-
-// gcc gives error: getwd is deprecated.
-#if defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-TEST_F(KernelWrapTest, getwd) {
-  EXPECT_CALL(mock, getwd(StrEq("getwd"))).Times(1);
-  char buffer[] = "getwd";
-  getwd(buffer);
-}
-#if defined(__GNUC__)
-#pragma GCC diagnostic warning "-Wdeprecated-declarations"
-#endif
-
-TEST_F(KernelWrapTest, ioctl) {
-  char buffer[] = "ioctl";
-  EXPECT_CALL(mock, ioctl(012, 345, StrEq("ioctl"))).Times(1);
-  ioctl(012, 345, buffer);
-}
-
-TEST_F(KernelWrapTest, isatty) {
-  EXPECT_CALL(mock, isatty(678)).Times(1);
-  isatty(678);
-}
-
-TEST_F(KernelWrapTest, lchown) {
-  uid_t uid = kDummyUid;
-  gid_t gid = kDummyGid;
-  EXPECT_CALL(mock, lchown(StrEq("lchown"), uid, gid)).Times(1);
-  lchown("lchown", uid, gid);
-}
-
-TEST_F(KernelWrapTest, lseek) {
-  EXPECT_CALL(mock, lseek(789, 891, 912)).Times(1);
-  lseek(789, 891, 912);
-}
-
-TEST_F(KernelWrapTest, mkdir) {
-#if defined(WIN32)
-  EXPECT_CALL(mock, mkdir(StrEq("mkdir"), 0777)).Times(1);
-  mkdir("mkdir");
-#else
-  EXPECT_CALL(mock, mkdir(StrEq("mkdir"), 1234)).Times(1);
-  mkdir("mkdir", 1234);
-#endif
-}
-
-TEST_F(KernelWrapTest, mount) {
-  EXPECT_CALL(mock,
-      mount(StrEq("mount1"), StrEq("mount2"), StrEq("mount3"), 2345, NULL))
-      .Times(1);
-  mount("mount1", "mount2", "mount3", 2345, NULL);
-}
-
-TEST_F(KernelWrapTest, open) {
-  EXPECT_CALL(mock, open(StrEq("open"), 3456)).Times(1);
-  open("open", 3456);
-}
-
-TEST_F(KernelWrapTest, read) {
-  EXPECT_CALL(mock, read(4567, NULL, 5678)).Times(1);
-  read(4567, NULL, 5678);
-}
-
-TEST_F(KernelWrapTest, remove) {
-  EXPECT_CALL(mock, remove(StrEq("remove"))).Times(1);
-  remove("remove");
-}
-
-TEST_F(KernelWrapTest, rmdir) {
-  EXPECT_CALL(mock, rmdir(StrEq("rmdir"))).Times(1);
-  rmdir("rmdir");
-}
-
-TEST_F(KernelWrapTest, stat) {
-  struct stat in_statbuf;
-  MakeDummyStatbuf(&in_statbuf);
-  EXPECT_CALL(mock, stat(StrEq("stat"), _))
-      .Times(1)
-      .WillOnce(SetStat(&in_statbuf));
-  struct stat out_statbuf;
-  stat("stat", &out_statbuf);
-  EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
-}
-
-TEST_F(KernelWrapTest, tcgetattr) {
-  struct termios term;
-  EXPECT_CALL(mock, tcgetattr(DUMMY_FD, &term)).Times(1);
-  tcgetattr(DUMMY_FD, &term);
-}
-
-TEST_F(KernelWrapTest, tcsetattr) {
-  struct termios term;
-  EXPECT_CALL(mock, tcsetattr(DUMMY_FD, 0, &term)).Times(1);
-  tcsetattr(DUMMY_FD, 0, &term);
-}
-
-TEST_F(KernelWrapTest, umount) {
-  EXPECT_CALL(mock, umount(StrEq("umount"))).Times(1);
-  umount("umount");
-}
-
-TEST_F(KernelWrapTest, unlink) {
-  EXPECT_CALL(mock, unlink(StrEq("unlink"))).Times(1);
-  unlink("unlink");
-}
-
-TEST_F(KernelWrapTest, utime) {
-  const struct utimbuf* times = NULL;
-  EXPECT_CALL(mock, utime(StrEq("utime"), times));
-  utime("utime", times);
-}
-
-TEST_F(KernelWrapTest, write) {
-  EXPECT_CALL(mock, write(6789, NULL, 7891)).Times(1);
-  write(6789, NULL, 7891);
-}
-
-#ifdef PROVIDES_SOCKET_API
-TEST_F(KernelWrapTest, poll) {
-  EXPECT_CALL(mock, poll(NULL, 5, -1));
-  poll(NULL, 5, -1);
-}
-
-TEST_F(KernelWrapTest, select) {
-  EXPECT_CALL(mock, select(123, NULL, NULL, NULL, NULL));
-  select(123, NULL, NULL, NULL, NULL);
-}
-
-// Socket Functions
-TEST_F(KernelWrapTest, accept) {
-  EXPECT_CALL(mock, accept(DUMMY_FD, NULL, NULL)).Times(1);
-  accept(DUMMY_FD, NULL, NULL);
-}
-
-TEST_F(KernelWrapTest, bind) {
-  EXPECT_CALL(mock, bind(DUMMY_FD, NULL, 456)).Times(1);
-  bind(DUMMY_FD, NULL, 456);
-}
-
-TEST_F(KernelWrapTest, connect) {
-  EXPECT_CALL(mock, connect(DUMMY_FD, NULL, 456)).Times(1);
-  connect(DUMMY_FD, NULL, 456);
-}
-
-TEST_F(KernelWrapTest, gethostbyname) {
-  EXPECT_CALL(mock, gethostbyname(NULL)).Times(1);
-  gethostbyname(NULL);
-}
-
-TEST_F(KernelWrapTest, getpeername) {
-  EXPECT_CALL(mock, getpeername(DUMMY_FD, NULL, NULL)).Times(1);
-  getpeername(DUMMY_FD, NULL, NULL);
-}
-
-TEST_F(KernelWrapTest, getsockname) {
-  EXPECT_CALL(mock, getsockname(DUMMY_FD, NULL, NULL)).Times(1);
-  getsockname(DUMMY_FD, NULL, NULL);
-}
-
-TEST_F(KernelWrapTest, getsockopt) {
-  EXPECT_CALL(mock, getsockopt(DUMMY_FD, 456, 789, NULL, NULL)).Times(1);
-  getsockopt(DUMMY_FD, 456, 789, NULL, NULL);
-}
-
-TEST_F(KernelWrapTest, listen) {
-  EXPECT_CALL(mock, listen(DUMMY_FD, 456)).Times(1);
-  listen(DUMMY_FD, 456);
-}
-
-TEST_F(KernelWrapTest, recv) {
-  EXPECT_CALL(mock, recv(DUMMY_FD, NULL, 456, 789)).Times(1);
-  recv(DUMMY_FD, NULL, 456, 789);
-}
-
-TEST_F(KernelWrapTest, recvfrom) {
-  EXPECT_CALL(mock, recvfrom(DUMMY_FD, NULL, 456, 789, NULL, NULL)).Times(1);
-  recvfrom(DUMMY_FD, NULL, 456, 789, NULL, NULL);
-}
-
-TEST_F(KernelWrapTest, recvmsg) {
-  EXPECT_CALL(mock, recvmsg(DUMMY_FD, NULL, 456)).Times(1);
-  recvmsg(DUMMY_FD, NULL, 456);
-}
-
-TEST_F(KernelWrapTest, send) {
-  EXPECT_CALL(mock, send(DUMMY_FD, NULL, 456, 789)).Times(1);
-  send(DUMMY_FD, NULL, 456, 789);
-}
-
-TEST_F(KernelWrapTest, sendto) {
-  EXPECT_CALL(mock, sendto(DUMMY_FD, NULL, 456, 789, NULL, 314)).Times(1);
-  sendto(DUMMY_FD, NULL, 456, 789, NULL, 314);
-}
-
-TEST_F(KernelWrapTest, sendmsg) {
-  EXPECT_CALL(mock, sendmsg(DUMMY_FD, NULL, 456)).Times(1);
-  sendmsg(DUMMY_FD, NULL, 456);
-}
-
-TEST_F(KernelWrapTest, setsockopt) {
-  EXPECT_CALL(mock, setsockopt(DUMMY_FD, 456, 789, NULL, 314)).Times(1);
-  setsockopt(DUMMY_FD, 456, 789, NULL, 314);
-}
-
-TEST_F(KernelWrapTest, shutdown) {
-  EXPECT_CALL(mock, shutdown(DUMMY_FD, 456)).Times(1);
-  shutdown(DUMMY_FD, 456);
-}
-
-TEST_F(KernelWrapTest, socket) {
-  EXPECT_CALL(mock, socket(DUMMY_FD, 456, 789)).Times(1);
-  socket(DUMMY_FD, 456, 789);
-}
-
-TEST_F(KernelWrapTest, socketpair) {
-  EXPECT_CALL(mock, socketpair(DUMMY_FD, 456, 789, NULL)).Times(1);
-  socketpair(DUMMY_FD, 456, 789, NULL);
-}
-
-#endif // PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mock_util.h b/native_client_sdk/src/libraries/nacl_io_test/mock_util.h
deleted file mode 100644
index 290d6cd..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/mock_util.h
+++ /dev/null
@@ -1,55 +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_TEST_MOCK_UTIL_H_
-#define LIBRARIES_NACL_IO_TEST_MOCK_UTIL_H_
-
-#include <gmock/gmock.h>
-#include <ppapi/c/pp_completion_callback.h>
-#include <ppapi/c/pp_var.h>
-
-ACTION_TEMPLATE(CallCallback,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_1_VALUE_PARAMS(result)) {
-  PP_CompletionCallback callback = std::tr1::get<k>(args);
-  if (callback.func) {
-    (*callback.func)(callback.user_data, result);
-  }
-
-  // Dummy return value.
-  return 0;
-}
-
-MATCHER_P(IsEqualToVar, var, "") {
-  if (arg.type != var.type)
-    return false;
-
-  switch (arg.type) {
-    case PP_VARTYPE_BOOL:
-      return arg.value.as_bool == var.value.as_bool;
-
-    case PP_VARTYPE_INT32:
-      return arg.value.as_int == var.value.as_int;
-
-    case PP_VARTYPE_DOUBLE:
-      return arg.value.as_double == var.value.as_double;
-
-    case PP_VARTYPE_STRING:
-      return arg.value.as_id == var.value.as_id;
-
-    case PP_VARTYPE_UNDEFINED:
-    case PP_VARTYPE_NULL:
-      return true;
-
-    case PP_VARTYPE_ARRAY:
-    case PP_VARTYPE_ARRAY_BUFFER:
-    case PP_VARTYPE_DICTIONARY:
-    case PP_VARTYPE_OBJECT:
-    default:
-      // Not supported.
-      return false;
-  }
-}
-
-#endif  // LIBRARIES_NACL_IO_TEST_MOCK_UTIL_H_
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
deleted file mode 100644
index b64770d..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
+++ /dev/null
@@ -1,629 +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 <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <gmock/gmock.h>
-#include <ppapi/c/ppb_file_io.h>
-#include <ppapi/c/pp_directory_entry.h>
-#include <ppapi/c/pp_errors.h>
-#include <ppapi/c/pp_instance.h>
-#if defined(WIN32)
-#include <windows.h>  // For Sleep()
-#endif
-
-#include "mock_util.h"
-#include "nacl_io/mount_html5fs.h"
-#include "nacl_io/osdirent.h"
-#include "nacl_io/osunistd.h"
-#include "pepper_interface_mock.h"
-
-using namespace nacl_io;
-using namespace sdk_util;
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::SaveArg;
-using ::testing::SetArgPointee;
-using ::testing::StrEq;
-using ::testing::WithArgs;
-
-namespace {
-
-class MountHtml5FsMock : public MountHtml5Fs {
- public:
-  MountHtml5FsMock(StringMap_t map, PepperInterfaceMock* ppapi) {
-    Init(1, map, ppapi);
-  }
-
-  ~MountHtml5FsMock() {}
-};
-
-class MountHtml5FsTest : public ::testing::Test {
- public:
-  MountHtml5FsTest();
-  ~MountHtml5FsTest();
-  void SetUpFilesystemExpectations(PP_FileSystemType, int,
-                                   bool async_callback=false);
-
- protected:
-  PepperInterfaceMock* ppapi_;
-  PP_CompletionCallback open_filesystem_callback_;
-
-  static const PP_Instance instance_ = 123;
-  static const PP_Resource filesystem_resource_ = 234;
-};
-
-MountHtml5FsTest::MountHtml5FsTest()
-    : ppapi_(new PepperInterfaceMock(instance_)) {
-}
-
-MountHtml5FsTest::~MountHtml5FsTest() {
-  delete ppapi_;
-}
-
-void MountHtml5FsTest::SetUpFilesystemExpectations(
-    PP_FileSystemType fstype,
-    int expected_size,
-    bool async_callback) {
-  FileSystemInterfaceMock* filesystem = ppapi_->GetFileSystemInterface();
-  EXPECT_CALL(*filesystem, Create(instance_, fstype))
-      .Times(1)
-      .WillOnce(Return(filesystem_resource_));
-
-  if (async_callback) {
-    EXPECT_CALL(*filesystem, Open(filesystem_resource_, expected_size, _))
-        .WillOnce(DoAll(SaveArg<2>(&open_filesystem_callback_),
-                        Return(int32_t(PP_OK))));
-    EXPECT_CALL(*ppapi_, IsMainThread()).WillOnce(Return(PP_TRUE));
-  } else {
-    EXPECT_CALL(*filesystem, Open(filesystem_resource_, expected_size, _))
-        .WillOnce(CallCallback<2>(int32_t(PP_OK)));
-    EXPECT_CALL(*ppapi_, IsMainThread()).WillOnce(Return(PP_FALSE));
-  }
-
-  EXPECT_CALL(*ppapi_, ReleaseResource(filesystem_resource_));
-}
-
-class MountHtml5FsNodeTest : public MountHtml5FsTest {
- public:
-  MountHtml5FsNodeTest();
-  virtual void SetUp();
-  virtual void TearDown();
-
-  void SetUpNodeExpectations(PP_FileType file_type);
-  void InitFilesystem();
-  void InitNode();
-
- protected:
-  ScopedRef<MountHtml5FsMock> mnt_;
-  ScopedMountNode node_;
-
-  FileRefInterfaceMock* fileref_;
-  FileIoInterfaceMock* fileio_;
-
-  static const char path_[];
-  static const PP_Resource fileref_resource_ = 235;
-  static const PP_Resource fileio_resource_ = 236;
-};
-
-// static
-const char MountHtml5FsNodeTest::path_[] = "/foo";
-
-MountHtml5FsNodeTest::MountHtml5FsNodeTest()
-    : fileref_(NULL),
-      fileio_(NULL) {
-}
-
-void MountHtml5FsNodeTest::SetUp() {
-  fileref_ = ppapi_->GetFileRefInterface();
-  fileio_ = ppapi_->GetFileIoInterface();
-}
-
-void MountHtml5FsNodeTest::TearDown() {
-  node_.reset();
-  mnt_.reset();
-}
-
-void MountHtml5FsNodeTest::SetUpNodeExpectations(PP_FileType file_type) {
-  // Open.
-  EXPECT_CALL(*fileref_, Create(filesystem_resource_, StrEq(&path_[0])))
-      .WillOnce(Return(fileref_resource_));
-  PP_FileInfo info;
-  memset(&info, 0, sizeof(PP_FileInfo));
-  info.type = file_type;
-  EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
-      .WillOnce(DoAll(SetArgPointee<1>(info),
-                      Return(int32_t(PP_OK))));
-  if (file_type != PP_FILETYPE_DIRECTORY) {
-    EXPECT_CALL(*fileio_, Create(instance_)).WillOnce(Return(fileio_resource_));
-    int32_t open_flags = PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE |
-        PP_FILEOPENFLAG_CREATE;
-    EXPECT_CALL(*fileio_,
-                Open(fileio_resource_, fileref_resource_, open_flags, _))
-        .WillOnce(Return(int32_t(PP_OK)));
-
-    // Close.
-    EXPECT_CALL(*fileio_, Close(fileio_resource_));
-    EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource_));
-    EXPECT_CALL(*fileio_, Flush(fileio_resource_, _));
-  }
-
-  // Close.
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource_));
-}
-
-void MountHtml5FsNodeTest::InitFilesystem() {
-  StringMap_t map;
-  mnt_.reset(new MountHtml5FsMock(map, ppapi_));
-}
-
-void MountHtml5FsNodeTest::InitNode() {
-  ASSERT_EQ(0, mnt_->Open(Path(path_), O_CREAT | O_RDWR, &node_));
-  ASSERT_NE((MountNode*)NULL, node_.get());
-}
-
-// Node test where the filesystem is opened synchronously; that is, the
-// creation of the mount blocks until the filesystem is ready.
-class MountHtml5FsNodeSyncTest : public MountHtml5FsNodeTest {
- public:
-  void SetUpForFileType(PP_FileType file_type);
-
-  virtual void SetUp();
-};
-
-void MountHtml5FsNodeSyncTest::SetUpForFileType(PP_FileType file_type) {
-  MountHtml5FsNodeTest::SetUp();
-  SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-  InitFilesystem();
-  SetUpNodeExpectations(file_type);
-  InitNode();
-}
-
-void MountHtml5FsNodeSyncTest::SetUp() {
-  SetUpForFileType(PP_FILETYPE_REGULAR);
-}
-
-// Node test where the filesystem is opened synchronously, and the node is a
-// directory.
-class MountHtml5FsNodeSyncDirTest : public MountHtml5FsNodeSyncTest {
- public:
-  virtual void SetUp();
-};
-
-void MountHtml5FsNodeSyncDirTest::SetUp() {
-  SetUpForFileType(PP_FILETYPE_DIRECTORY);
-}
-
-void ReadDirectoryEntriesAction(const PP_ArrayOutput& output) {
-  const int fileref_resource_1 = 238;
-  const int fileref_resource_2 = 239;
-
-  std::vector<PP_DirectoryEntry> entries;
-  PP_DirectoryEntry entry1 = { fileref_resource_1, PP_FILETYPE_REGULAR };
-  PP_DirectoryEntry entry2 = { fileref_resource_2, PP_FILETYPE_REGULAR };
-  entries.push_back(entry1);
-  entries.push_back(entry2);
-
-  void* dest = output.GetDataBuffer(
-      output.user_data, 2, sizeof(PP_DirectoryEntry));
-  memcpy(dest, &entries[0], sizeof(PP_DirectoryEntry) * 2);
-}
-
-class MountHtml5FsNodeAsyncTest : public MountHtml5FsNodeTest {
- public:
-  virtual void SetUp();
-  virtual void TearDown();
-
- private:
-  static void* ThreadThunk(void* param);
-  void Thread();
-
-  enum {
-    STATE_INIT,
-    STATE_INIT_NODE,
-    STATE_INIT_NODE_FINISHED,
-  } state_;
-
-  pthread_t thread_;
-  pthread_cond_t cond_;
-  pthread_mutex_t mutex_;
-};
-
-void MountHtml5FsNodeAsyncTest::SetUp() {
-  MountHtml5FsNodeTest::SetUp();
-
-  state_ = STATE_INIT;
-
-  pthread_create(&thread_, NULL, &MountHtml5FsNodeAsyncTest::ThreadThunk, this);
-  pthread_mutex_init(&mutex_, NULL);
-  pthread_cond_init(&cond_, NULL);
-
-  // This test shows that even if the filesystem open callback happens after an
-  // attempt to open a node, it still works (opening the node blocks until the
-  // filesystem is ready).
-  // true => asynchronous filesystem open.
-  SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0, true);
-  InitFilesystem();
-  SetUpNodeExpectations(PP_FILETYPE_REGULAR);
-
-  // Signal the other thread to try opening a Node.
-  pthread_mutex_lock(&mutex_);
-  state_ = STATE_INIT_NODE;
-  pthread_cond_signal(&cond_);
-  pthread_mutex_unlock(&mutex_);
-
-  // Wait for a bit...
-  // TODO(binji): this will be flaky. How to test this better?
-#if defined(WIN32)
-  Sleep(500);  // milliseconds
-#else
-  usleep(500*1000);  // microseconds
-#endif
-
-  // Call the filesystem open callback.
-  (*open_filesystem_callback_.func)(open_filesystem_callback_.user_data, PP_OK);
-
-  // Wait for the other thread to unblock and signal us.
-  pthread_mutex_lock(&mutex_);
-  while (state_ != STATE_INIT_NODE_FINISHED)
-    pthread_cond_wait(&cond_, &mutex_);
-  pthread_mutex_unlock(&mutex_);
-}
-
-void MountHtml5FsNodeAsyncTest::TearDown() {
-  pthread_cond_destroy(&cond_);
-  pthread_mutex_destroy(&mutex_);
-
-  MountHtml5FsNodeTest::TearDown();
-}
-
-void* MountHtml5FsNodeAsyncTest::ThreadThunk(void* param) {
-  static_cast<MountHtml5FsNodeAsyncTest*>(param)->Thread();
-  return NULL;
-}
-
-void MountHtml5FsNodeAsyncTest::Thread() {
-  // Wait for the "main" thread to tell us to open the Node.
-  pthread_mutex_lock(&mutex_);
-  while (state_ != STATE_INIT_NODE)
-    pthread_cond_wait(&cond_, &mutex_);
-  pthread_mutex_unlock(&mutex_);
-
-  // Opening the node blocks until the filesystem is open...
-  InitNode();
-
-  // Signal the "main" thread to tell it we're unblocked.
-  pthread_mutex_lock(&mutex_);
-  state_ = STATE_INIT_NODE_FINISHED;
-  pthread_cond_signal(&cond_);
-  pthread_mutex_unlock(&mutex_);
-}
-
-}  // namespace
-
-
-TEST_F(MountHtml5FsTest, FilesystemType) {
-  SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 100);
-
-  StringMap_t map;
-  map["type"] = "PERSISTENT";
-  map["expected_size"] = "100";
-  ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-}
-
-TEST_F(MountHtml5FsTest, Access) {
-  const char path[] = "/foo";
-  const PP_Resource fileref_resource = 235;
-  const PP_Resource fileio_resource = 236;
-
-  // These are the default values.
-  SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
-  FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
-  FileIoInterfaceMock* fileio = ppapi_->GetFileIoInterface();
-
-  EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
-      .WillOnce(Return(fileref_resource));
-  PP_FileInfo info;
-  memset(&info, 0, sizeof(PP_FileInfo));
-  info.type = PP_FILETYPE_REGULAR;
-  EXPECT_CALL(*fileref, Query(fileref_resource, _, _))
-      .WillOnce(DoAll(SetArgPointee<1>(info),
-                      Return(int32_t(PP_OK))));
-  EXPECT_CALL(*fileio, Create(instance_)).WillOnce(Return(fileio_resource));
-  int32_t open_flags = PP_FILEOPENFLAG_READ;
-  EXPECT_CALL(*fileio,
-              Open(fileio_resource, fileref_resource, open_flags, _))
-      .WillOnce(Return(int32_t(PP_OK)));
-  EXPECT_CALL(*fileio, Close(fileio_resource));
-  EXPECT_CALL(*fileio, Flush(fileio_resource, _));
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource));
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
-  StringMap_t map;
-  ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
-  ASSERT_EQ(0, mnt->Access(Path(path), R_OK | W_OK | X_OK));
-}
-
-TEST_F(MountHtml5FsTest, AccessFileNotFound) {
-  const char path[] = "/foo";
-  const PP_Resource fileref_resource = 235;
-  const PP_Resource fileio_resource = 236;
-
-  // These are the default values.
-  SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
-  FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
-  FileIoInterfaceMock* fileio = ppapi_->GetFileIoInterface();
-
-  // Report the file as missing.
-  EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
-      .WillOnce(Return(fileref_resource));
-  PP_FileInfo info;
-  memset(&info, 0, sizeof(PP_FileInfo));
-  info.type = PP_FILETYPE_REGULAR;
-  EXPECT_CALL(*fileref, Query(fileref_resource, _, _))
-      .WillOnce(DoAll(SetArgPointee<1>(info),
-                      Return(int32_t(PP_ERROR_FILENOTFOUND))));
-  EXPECT_CALL(*fileio, Create(instance_)).WillOnce(Return(fileio_resource));
-  int32_t open_flags = PP_FILEOPENFLAG_READ;
-  EXPECT_CALL(*fileio,
-              Open(fileio_resource, fileref_resource, open_flags, _))
-      .WillOnce(Return(int32_t(PP_ERROR_FILENOTFOUND)));
-  EXPECT_CALL(*fileio, Close(fileio_resource));
-  EXPECT_CALL(*fileio, Flush(fileio_resource, _));
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource));
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
-  StringMap_t map;
-  ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
-  ASSERT_EQ(ENOENT, mnt->Access(Path(path), F_OK));
-}
-
-TEST_F(MountHtml5FsTest, Mkdir) {
-  const char path[] = "/foo";
-  const PP_Resource fileref_resource = 235;
-
-  // These are the default values.
-  SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
-  FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
-
-  EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
-      .WillOnce(Return(fileref_resource));
-  EXPECT_CALL(*fileref, MakeDirectory(fileref_resource, _, _))
-      .WillOnce(Return(int32_t(PP_OK)));
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
-  StringMap_t map;
-  ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
-  const int permissions = 0;  // unused.
-  int32_t result = mnt->Mkdir(Path(path), permissions);
-  ASSERT_EQ(0, result);
-}
-
-TEST_F(MountHtml5FsTest, Remove) {
-  const char path[] = "/foo";
-  const PP_Resource fileref_resource = 235;
-
-  // These are the default values.
-  SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
-  FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
-
-  EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
-      .WillOnce(Return(fileref_resource));
-  EXPECT_CALL(*fileref, Delete(fileref_resource, _))
-      .WillOnce(Return(int32_t(PP_OK)));
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
-  StringMap_t map;
-  ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
-  int32_t result = mnt->Remove(Path(path));
-  ASSERT_EQ(0, result);
-}
-
-TEST_F(MountHtml5FsNodeAsyncTest, AsyncFilesystemOpen) {
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, OpenAndClose) {
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, Write) {
-  const int offset = 10;
-  const int count = 20;
-  const char buffer[30] = {0};
-
-  EXPECT_CALL(*fileio_, Write(fileio_resource_, offset, &buffer[0], count, _))
-      .WillOnce(Return(count));
-
-  int result = 0;
-  EXPECT_EQ(0, node_->Write(offset, &buffer, count, &result));
-  EXPECT_EQ(count, result);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, Read) {
-  const int offset = 10;
-  const int count = 20;
-  char buffer[30] = {0};
-
-  EXPECT_CALL(*fileio_, Read(fileio_resource_, offset, &buffer[0], count, _))
-      .WillOnce(Return(count));
-
-  int result = 0;
-  EXPECT_EQ(0, node_->Read(offset, &buffer, count, &result));
-  EXPECT_EQ(count, result);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, GetStat) {
-  const int size = 123;
-  const int creation_time = 1000;
-  const int access_time = 2000;
-  const int modified_time = 3000;
-
-  PP_FileInfo info;
-  info.size = size;
-  info.type = PP_FILETYPE_REGULAR;
-  info.system_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
-  info.creation_time = creation_time;
-  info.last_access_time = access_time;
-  info.last_modified_time = modified_time;
-
-  EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
-      .WillOnce(DoAll(SetArgPointee<1>(info),
-                      Return(int32_t(PP_OK))));
-
-  struct stat statbuf;
-  int result = node_->GetStat(&statbuf);
-
-  EXPECT_EQ(0, result);
-  EXPECT_EQ(S_IFREG | S_IWRITE | S_IREAD, statbuf.st_mode);
-  EXPECT_EQ(size, statbuf.st_size);
-  EXPECT_EQ(access_time, statbuf.st_atime);
-  EXPECT_EQ(modified_time, statbuf.st_mtime);
-  EXPECT_EQ(creation_time, statbuf.st_ctime);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, FTruncate) {
-  const int size = 123;
-  EXPECT_CALL(*fileio_, SetLength(fileio_resource_, size, _))
-      .WillOnce(Return(int32_t(PP_OK)));
-
-  int result = node_->FTruncate(size);
-  EXPECT_EQ(0, result);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, GetDents) {
-  struct dirent dirents[2];
-  memset(&dirents[0], 0, sizeof(dirents));
-
-  // Should fail for regular files.
-  int result_bytes = 0;
-  EXPECT_EQ(ENOTDIR, node_->GetDents(0, &dirents[0], sizeof(dirent) * 2,
-        &result_bytes));
-  ASSERT_EQ(0, result_bytes);
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, OpenAndClose) {
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, Write) {
-  const int offset = 10;
-  const int count = 20;
-  const char buffer[30] = {0};
-
-  // Should fail for directories.
-  int result_bytes = 0;
-  EXPECT_EQ(EISDIR, node_->Write(offset, &buffer, count, &result_bytes));
-  ASSERT_EQ(0, result_bytes);
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, Read) {
-  const int offset = 10;
-  const int count = 20;
-  char buffer[30] = {0};
-
-  // Should fail for directories.
-  int result_bytes = 0;
-  EXPECT_EQ(EISDIR, node_->Read(offset, &buffer, count, &result_bytes));
-  ASSERT_EQ(0, result_bytes);
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, GetStat) {
-  const int creation_time = 1000;
-  const int access_time = 2000;
-  const int modified_time = 3000;
-
-  PP_FileInfo info;
-  info.size = 0;
-  info.type = PP_FILETYPE_DIRECTORY;
-  info.system_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
-  info.creation_time = creation_time;
-  info.last_access_time = access_time;
-  info.last_modified_time = modified_time;
-
-  EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
-      .WillOnce(DoAll(SetArgPointee<1>(info),
-                      Return(int32_t(PP_OK))));
-
-  struct stat statbuf;
-  int result = node_->GetStat(&statbuf);
-
-  EXPECT_EQ(0, result);
-  EXPECT_EQ(S_IFDIR | S_IWRITE | S_IREAD, statbuf.st_mode);
-  EXPECT_EQ(0, statbuf.st_size);
-  EXPECT_EQ(access_time, statbuf.st_atime);
-  EXPECT_EQ(modified_time, statbuf.st_mtime);
-  EXPECT_EQ(creation_time, statbuf.st_ctime);
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, FTruncate) {
-  const int size = 123;
-  // Should fail for directories.
-  EXPECT_EQ(EISDIR, node_->FTruncate(size));
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, GetDents) {
-  const int fileref_resource_1 = 238;
-  const int fileref_resource_2 = 239;
-
-  const int fileref_name_id_1 = 240;
-  const char fileref_name_cstr_1[] = "bar";
-  PP_Var fileref_name_1;
-  fileref_name_1.type = PP_VARTYPE_STRING;
-  fileref_name_1.value.as_id = fileref_name_id_1;
-
-  const int fileref_name_id_2 = 241;
-  const char fileref_name_cstr_2[] = "quux";
-  PP_Var fileref_name_2;
-  fileref_name_2.type = PP_VARTYPE_STRING;
-  fileref_name_2.value.as_id = fileref_name_id_2;
-
-  VarInterfaceMock* var = ppapi_->GetVarInterface();
-
-  EXPECT_CALL(*fileref_, ReadDirectoryEntries(fileref_resource_, _, _))
-      .WillOnce(DoAll(WithArgs<1>(Invoke(ReadDirectoryEntriesAction)),
-                      Return(int32_t(PP_OK))));
-
-  EXPECT_CALL(*fileref_, GetName(fileref_resource_1))
-      .WillOnce(Return(fileref_name_1));
-  EXPECT_CALL(*fileref_, GetName(fileref_resource_2))
-      .WillOnce(Return(fileref_name_2));
-
-  EXPECT_CALL(*var, VarToUtf8(IsEqualToVar(fileref_name_1), _))
-      .WillOnce(Return(fileref_name_cstr_1));
-  EXPECT_CALL(*var, VarToUtf8(IsEqualToVar(fileref_name_2), _))
-      .WillOnce(Return(fileref_name_cstr_2));
-
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource_1));
-  EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource_2));
-
-  struct dirent dirents[2];
-  memset(&dirents[0], 0, sizeof(dirents));
-  // +2 to test a size that is not a multiple of sizeof(dirent).
-  // Expect it to round down.
-  int result_bytes = 0;
-  EXPECT_EQ(
-      0,
-      node_->GetDents(0, &dirents[0], sizeof(dirent) * 2 + 2, &result_bytes));
-
-  ASSERT_EQ(sizeof(dirent) * 2, result_bytes);
-  EXPECT_LT(0, dirents[0].d_ino);  // 0 is an invalid inode number.
-  EXPECT_EQ(sizeof(dirent), dirents[0].d_off);
-  EXPECT_EQ(sizeof(dirent), dirents[0].d_reclen);
-  EXPECT_STREQ(fileref_name_cstr_1, dirents[0].d_name);
-  EXPECT_LT(0, dirents[1].d_ino);  // 0 is an invalid inode number.
-  EXPECT_EQ(sizeof(dirent), dirents[1].d_off);
-  EXPECT_EQ(sizeof(dirent), dirents[1].d_reclen);
-  EXPECT_STREQ(fileref_name_cstr_2, dirents[1].d_name);
-}
-
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
deleted file mode 100644
index 926fe28..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
+++ /dev/null
@@ -1,610 +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 <fcntl.h>
-#include <gmock/gmock.h>
-#include <ppapi/c/ppb_file_io.h>
-#include <ppapi/c/pp_errors.h>
-#include <ppapi/c/pp_instance.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "mock_util.h"
-#include "nacl_io/kernel_intercept.h"
-#include "nacl_io/mount_http.h"
-#include "nacl_io/mount_node_dir.h"
-#include "nacl_io/osdirent.h"
-#include "nacl_io/osunistd.h"
-#include "pepper_interface_mock.h"
-
-using namespace nacl_io;
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Mock;
-using ::testing::Return;
-using ::testing::SetArgPointee;
-using ::testing::StrEq;
-
-
-class MountHttpMock : public MountHttp {
- public:
-  MountHttpMock(StringMap_t map, PepperInterfaceMock* ppapi) {
-    EXPECT_EQ(0, Init(1, map, ppapi));
-  }
-
-  ~MountHttpMock() {
-    Destroy();
-  }
-
-  NodeMap_t& GetMap() { return node_cache_; }
-
-  using MountHttp::ParseManifest;
-  using MountHttp::FindOrCreateDir;
-};
-
-class MountHttpTest : public ::testing::Test {
- public:
-  MountHttpTest();
-  ~MountHttpTest();
-
- protected:
-  PepperInterfaceMock ppapi_;
-  MountHttpMock* mnt_;
-
-  static const PP_Instance instance_ = 123;
-};
-
-MountHttpTest::MountHttpTest()
-    : ppapi_(instance_),
-      mnt_(NULL) {
-}
-
-MountHttpTest::~MountHttpTest() {
-  delete mnt_;
-}
-
-
-TEST_F(MountHttpTest, MountEmpty) {
-  StringMap_t args;
-  mnt_ = new MountHttpMock(args, &ppapi_);
-}
-
-TEST_F(MountHttpTest, Mkdir) {
-  StringMap_t args;
-  mnt_ = new MountHttpMock(args, &ppapi_);
-  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
-  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
-  // mkdir of existing directories should give "File exists".
-  EXPECT_EQ(EEXIST, mnt_->Mkdir(Path("/"), 0));
-  EXPECT_EQ(EEXIST, mnt_->Mkdir(Path("/mydir"), 0));
-  // mkdir of non-existent directories should give "Permission denied".
-  EXPECT_EQ(EACCES, mnt_->Mkdir(Path("/non_existent"), 0));
-}
-
-TEST_F(MountHttpTest, Rmdir) {
-  StringMap_t args;
-  mnt_ = new MountHttpMock(args, &ppapi_);
-  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
-  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
-  // Rmdir on existing dirs should give "Permission Denied"
-  EXPECT_EQ(EACCES, mnt_->Rmdir(Path("/")));
-  EXPECT_EQ(EACCES, mnt_->Rmdir(Path("/mydir")));
-  // Rmdir on existing files should give "Not a direcotory"
-  EXPECT_EQ(ENOTDIR, mnt_->Rmdir(Path("/mydir/foo")));
-  // Rmdir on non-existent files should give "No such file or directory"
-  EXPECT_EQ(ENOENT, mnt_->Rmdir(Path("/non_existent")));
-}
-
-TEST_F(MountHttpTest, Unlink) {
-  StringMap_t args;
-  mnt_ = new MountHttpMock(args, &ppapi_);
-  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
-  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
-  // Unlink of existing files should give "Permission Denied"
-  EXPECT_EQ(EACCES, mnt_->Unlink(Path("/mydir/foo")));
-  // Unlink of existing directory should give "Is a directory"
-  EXPECT_EQ(EISDIR, mnt_->Unlink(Path("/mydir")));
-  // Unlink of non-existent files should give "No such file or directory"
-  EXPECT_EQ(ENOENT, mnt_->Unlink(Path("/non_existent")));
-}
-
-TEST_F(MountHttpTest, Remove) {
-  StringMap_t args;
-  mnt_ = new MountHttpMock(args, &ppapi_);
-  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
-  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
-  // Remove of existing files should give "Permission Denied"
-  EXPECT_EQ(EACCES, mnt_->Remove(Path("/mydir/foo")));
-  // Remove of existing directory should give "Permission Denied"
-  EXPECT_EQ(EACCES, mnt_->Remove(Path("/mydir")));
-  // Unlink of non-existent files should give "No such file or directory"
-  EXPECT_EQ(ENOENT, mnt_->Remove(Path("/non_existent")));
-}
-
-TEST_F(MountHttpTest, ParseManifest) {
-  StringMap_t args;
-  size_t result_size = 0;
-
-  mnt_ = new MountHttpMock(args, &ppapi_);
-
-  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
-  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
-
-  ScopedMountNode root;
-  EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/"), &root));
-  ASSERT_NE((MountNode*)NULL, root.get());
-  EXPECT_EQ(2, root->ChildCount());
-
-  ScopedMountNode dir;
-  EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/mydir"), &dir));
-  ASSERT_NE((MountNode*)NULL, dir.get());
-  EXPECT_EQ(1, dir->ChildCount());
-
-  MountNode* node = mnt_->GetMap()["/mydir/foo"].get();
-  EXPECT_NE((MountNode*)NULL, node);
-  EXPECT_EQ(0, node->GetSize(&result_size));
-  EXPECT_EQ(123, result_size);
-
-  // Since these files are cached thanks to the manifest, we can open them
-  // without accessing the PPAPI URL API.
-  ScopedMountNode foo;
-  EXPECT_EQ(0, mnt_->Open(Path("/mydir/foo"), O_RDONLY, &foo));
-
-  ScopedMountNode bar;
-  EXPECT_EQ(0, mnt_->Open(Path("/thatdir/bar"), O_RDWR, &bar));
-
-  struct stat sfoo;
-  struct stat sbar;
-
-  EXPECT_FALSE(foo->GetStat(&sfoo));
-  EXPECT_FALSE(bar->GetStat(&sbar));
-
-  EXPECT_EQ(123, sfoo.st_size);
-  EXPECT_EQ(S_IFREG | S_IREAD, sfoo.st_mode);
-
-  EXPECT_EQ(234, sbar.st_size);
-  EXPECT_EQ(S_IFREG | S_IREAD | S_IWRITE, sbar.st_mode);
-}
-
-
-class MountHttpNodeTest : public MountHttpTest {
- public:
-  MountHttpNodeTest();
-  virtual void TearDown();
-
-  void SetMountArgs(const StringMap_t& args);
-  void ExpectOpen(const char* method);
-  void ExpectHeaders(const char* headers);
-  void OpenNode();
-  void SetResponse(int status_code, const char* headers);
-  // Set a response code, but expect the request to fail. Certain function calls
-  // expected by SetResponse are not expected here.
-  void SetResponseExpectFail(int status_code, const char* headers);
-  void SetResponseBody(const char* body);
-  void ResetMocks();
-
- protected:
-  MountHttpMock* mnt_;
-  ScopedMountNode node_;
-
-  VarInterfaceMock* var_;
-  URLLoaderInterfaceMock* loader_;
-  URLRequestInfoInterfaceMock* request_;
-  URLResponseInfoInterfaceMock* response_;
-  size_t response_body_offset_;
-
-  static const char path_[];
-  static const char rel_path_[];
-  static const PP_Resource loader_resource_ = 235;
-  static const PP_Resource request_resource_ = 236;
-  static const PP_Resource response_resource_ = 237;
-};
-
-// static
-const char MountHttpNodeTest::path_[] = "/foo";
-// static
-const char MountHttpNodeTest::rel_path_[] = "foo";
-
-MountHttpNodeTest::MountHttpNodeTest()
-    : mnt_(NULL),
-      node_(NULL) {
-}
-
-static PP_Var MakeString(PP_Resource resource) {
-  PP_Var result = { PP_VARTYPE_STRING, 0, {PP_FALSE} };
-  result.value.as_id = resource;
-  return result;
-}
-
-void MountHttpNodeTest::SetMountArgs(const StringMap_t& args) {
-  mnt_ = new MountHttpMock(args, &ppapi_);
-}
-
-void MountHttpNodeTest::ExpectOpen(const char* method) {
-  loader_ = ppapi_.GetURLLoaderInterface();
-  request_ = ppapi_.GetURLRequestInfoInterface();
-  response_ = ppapi_.GetURLResponseInfoInterface();
-  var_ = ppapi_.GetVarInterface();
-
-  ON_CALL(*request_, SetProperty(request_resource_, _, _))
-      .WillByDefault(Return(PP_TRUE));
-  ON_CALL(*var_, VarFromUtf8(_, _)).WillByDefault(Return(PP_MakeUndefined()));
-
-  EXPECT_CALL(*loader_, Create(instance_)).WillOnce(Return(loader_resource_));
-  EXPECT_CALL(*request_, Create(instance_)).WillOnce(Return(request_resource_));
-
-  PP_Var var_head = MakeString(345);
-  PP_Var var_url = MakeString(346);
-  EXPECT_CALL(*var_, VarFromUtf8(StrEq(method), _)).WillOnce(Return(var_head));
-  EXPECT_CALL(*var_, VarFromUtf8(StrEq(rel_path_), _))
-      .WillOnce(Return(var_url));
-
-#define EXPECT_SET_PROPERTY(NAME, VAR) \
-  EXPECT_CALL(*request_, SetProperty(request_resource_, NAME, VAR))
-
-  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_URL, IsEqualToVar(var_url));
-  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_METHOD, IsEqualToVar(var_head));
-  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, _);
-  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS, _);
-
-#undef EXPECT_SET_PROPERTY
-
-  EXPECT_CALL(*loader_, Open(loader_resource_, request_resource_, _))
-      .WillOnce(CallCallback<2>(int32_t(PP_OK)));
-  EXPECT_CALL(*loader_, GetResponseInfo(loader_resource_))
-      .WillOnce(Return(response_resource_));
-
-  EXPECT_CALL(ppapi_, ReleaseResource(loader_resource_));
-  EXPECT_CALL(ppapi_, ReleaseResource(request_resource_));
-  EXPECT_CALL(ppapi_, ReleaseResource(response_resource_));
-}
-
-void MountHttpNodeTest::ExpectHeaders(const char* headers) {
-  PP_Var var_headers = MakeString(347);
-  var_ = ppapi_.GetVarInterface();
-  EXPECT_CALL(*var_, VarFromUtf8(StrEq(headers), _))
-      .WillOnce(Return(var_headers));
-
-  EXPECT_CALL(*request_, SetProperty(request_resource_,
-                                     PP_URLREQUESTPROPERTY_HEADERS,
-                                     IsEqualToVar(var_headers))).Times(1);
-}
-
-void MountHttpNodeTest::SetResponse(int status_code, const char* headers) {
-  ON_CALL(*response_, GetProperty(response_resource_, _))
-      .WillByDefault(Return(PP_MakeUndefined()));
-
-  PP_Var var_headers = MakeString(348);
-  EXPECT_CALL(*response_,
-              GetProperty(response_resource_,
-                          PP_URLRESPONSEPROPERTY_STATUSCODE))
-      .WillOnce(Return(PP_MakeInt32(status_code)));
-  EXPECT_CALL(*response_,
-              GetProperty(response_resource_, PP_URLRESPONSEPROPERTY_HEADERS))
-      .WillOnce(Return(var_headers));
-  EXPECT_CALL(*var_, VarToUtf8(IsEqualToVar(var_headers), _))
-      .WillOnce(DoAll(SetArgPointee<1>(strlen(headers)),
-                      Return(headers)));
-}
-
-void MountHttpNodeTest::SetResponseExpectFail(int status_code,
-                                              const char* headers) {
-  ON_CALL(*response_, GetProperty(response_resource_, _))
-      .WillByDefault(Return(PP_MakeUndefined()));
-
-  EXPECT_CALL(*response_,
-              GetProperty(response_resource_,
-                          PP_URLRESPONSEPROPERTY_STATUSCODE))
-      .WillOnce(Return(PP_MakeInt32(status_code)));
-}
-
-ACTION_P3(ReadResponseBodyAction, offset, body, body_length) {
-  char* buf = static_cast<char*>(arg1);
-  size_t read_length = arg2;
-  PP_CompletionCallback callback = arg3;
-  if (*offset >= body_length)
-    return 0;
-
-  read_length = std::min(read_length, body_length - *offset);
-  memcpy(buf, body + *offset, read_length);
-  *offset += read_length;
-
-  // Also call the callback.
-  if (callback.func)
-    (*callback.func)(callback.user_data, PP_OK);
-
-  return read_length;
-}
-
-void MountHttpNodeTest::SetResponseBody(const char* body) {
-  response_body_offset_ = 0;
-  EXPECT_CALL(*loader_, ReadResponseBody(loader_resource_, _, _, _))
-      .WillRepeatedly(ReadResponseBodyAction(
-            &response_body_offset_, body, strlen(body)));
-}
-
-void MountHttpNodeTest::OpenNode() {
-  ASSERT_EQ(0, mnt_->Open(Path(path_), O_RDONLY, &node_));
-  ASSERT_NE((MountNode*)NULL, node_.get());
-}
-
-void MountHttpNodeTest::ResetMocks() {
-  Mock::VerifyAndClearExpectations(&ppapi_);
-  Mock::VerifyAndClearExpectations(loader_);
-  Mock::VerifyAndClearExpectations(request_);
-  Mock::VerifyAndClearExpectations(response_);
-  Mock::VerifyAndClearExpectations(var_);
-}
-
-void MountHttpNodeTest::TearDown() {
-  node_.reset();
-  delete mnt_;
-}
-
-TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseNoCache) {
-  StringMap_t smap;
-  smap["cache_content"] = "false";
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "");
-  OpenNode();
-}
-
-TEST_F(MountHttpNodeTest, OpenAndCloseNotFound) {
-  StringMap_t smap;
-  smap["cache_content"] = "false";
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponseExpectFail(404, "");
-  ASSERT_EQ(ENOENT, mnt_->Open(Path(path_), O_RDONLY, &node_));
-}
-
-TEST_F(MountHttpNodeTest, OpenAndCloseServerError) {
-  StringMap_t smap;
-  smap["cache_content"] = "false";
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponseExpectFail(500, "");
-  ASSERT_EQ(EIO, mnt_->Open(Path(path_), O_RDONLY, &node_));
-}
-
-TEST_F(MountHttpNodeTest, GetStat) {
-  StringMap_t smap;
-  smap["cache_content"] = "false";
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "Content-Length: 42\n");
-  OpenNode();
-
-  struct stat stat;
-  EXPECT_EQ(0, node_->GetStat(&stat));
-  EXPECT_EQ(42, stat.st_size);
-}
-
-TEST_F(MountHttpNodeTest, DISABLED_Access) {
-  StringMap_t smap;
-  smap["cache_content"] = "false";
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "");
-  ASSERT_EQ(0, mnt_->Access(Path(path_), R_OK));
-}
-
-TEST_F(MountHttpNodeTest, DISABLED_AccessWrite) {
-  StringMap_t smap;
-  smap["cache_content"] = "false";
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "");
-  ASSERT_EQ(EACCES, mnt_->Access(Path(path_), W_OK));
-}
-
-TEST_F(MountHttpNodeTest, AccessNotFound) {
-  StringMap_t smap;
-  smap["cache_content"] = "false";
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponseExpectFail(404, "");
-  ASSERT_EQ(ENOENT, mnt_->Access(Path(path_), R_OK));
-}
-
-TEST_F(MountHttpNodeTest, ReadCached) {
-  size_t result_size = 0;
-  int result_bytes = 0;
-
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "Content-Length: 42\n");
-  OpenNode();
-  ResetMocks();
-
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(42, result_size);
-
-  char buf[10];
-  memset(&buf[0], 0, sizeof(buf));
-
-  ExpectOpen("GET");
-  ExpectHeaders("");
-  SetResponse(200, "Content-Length: 42\n");
-  SetResponseBody("Here is some response text. And some more.");
-  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_STREQ("Here is s", &buf[0]);
-  ResetMocks();
-
-  // Further reads should be cached.
-  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_STREQ("Here is s", &buf[0]);
-  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_STREQ("me respon", &buf[0]);
-
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(42, result_size);
-}
-
-TEST_F(MountHttpNodeTest, DISABLED_ReadCachedNoContentLength) {
-  size_t result_size = 0;
-  int result_bytes = 0;
-
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "");
-  OpenNode();
-  ResetMocks();
-
-  ExpectOpen("GET");
-  ExpectHeaders("");
-  SetResponse(200, "");  // No Content-Length response here.
-  SetResponseBody("Here is some response text. And some more.");
-
-  // GetSize will Read() because it didn't get the content length from the HEAD
-  // request.
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(42, result_size);
-
-  char buf[10];
-  memset(&buf[0], 0, sizeof(buf));
-
-  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_STREQ("Here is s", &buf[0]);
-  ResetMocks();
-
-  // Further reads should be cached.
-  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_STREQ("Here is s", &buf[0]);
-  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_STREQ("me respon", &buf[0]);
-
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(42, result_size);
-}
-
-TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
-  size_t result_size = 0;
-  int result_bytes = 0;
-
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "Content-Length: 100\n");
-  OpenNode();
-  ResetMocks();
-
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(100, result_size);
-
-  char buf[10];
-  memset(&buf[0], 0, sizeof(buf));
-
-  ExpectOpen("GET");
-  ExpectHeaders("");
-  SetResponse(200, "Content-Length: 100\n");
-  SetResponseBody("abcdefghijklmnopqrstuvwxyz");
-  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
-  EXPECT_STREQ("abcdefghi", &buf[0]);
-  ResetMocks();
-
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(26, result_size);
-}
-
-TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
-  size_t result_size = 0;
-  int result_bytes = 0;
-
-  SetMountArgs(StringMap_t());
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "Content-Length: 15\n");
-  OpenNode();
-  ResetMocks();
-
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(15, result_size);
-
-  char buf[10];
-  memset(&buf[0], 0, sizeof(buf));
-
-  ExpectOpen("GET");
-  ExpectHeaders("");
-  SetResponse(200, "Content-Length: 15\n");
-  SetResponseBody("01234567890123456789");
-  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_EQ(5, result_bytes);
-  EXPECT_STREQ("01234", &buf[0]);
-  ResetMocks();
-
-  EXPECT_EQ(0, node_->GetSize(&result_size));
-  EXPECT_EQ(15, result_size);
-}
-
-TEST_F(MountHttpNodeTest, ReadPartial) {
-  int result_bytes = 0;
-
-  StringMap_t args;
-  args["cache_content"] = "false";
-  SetMountArgs(args);
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "");
-  OpenNode();
-  ResetMocks();
-
-  char buf[10];
-  memset(&buf[0], 0, sizeof(buf));
-
-  ExpectOpen("GET");
-  ExpectHeaders("Range: bytes=0-8\n");
-  SetResponse(206, "Content-Length: 9\nContent-Range: bytes=0-8\n");
-  SetResponseBody("012345678");
-  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
-  EXPECT_STREQ("012345678", &buf[0]);
-  ResetMocks();
-
-  // Another read is another request.
-  ExpectOpen("GET");
-  ExpectHeaders("Range: bytes=10-18\n");
-  SetResponse(206, "Content-Length: 9\nContent-Range: bytes=10-18\n");
-  SetResponseBody("abcdefghi");
-  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
-  EXPECT_STREQ("abcdefghi", &buf[0]);
-}
-
-TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) {
-  int result_bytes = 0;
-
-  StringMap_t args;
-  args["cache_content"] = "false";
-  SetMountArgs(args);
-  ExpectOpen("HEAD");
-  ExpectHeaders("");
-  SetResponse(200, "");
-  OpenNode();
-  ResetMocks();
-
-  char buf[10];
-  memset(&buf[0], 0, sizeof(buf));
-
-  ExpectOpen("GET");
-  ExpectHeaders("Range: bytes=10-18\n");
-  SetResponse(200, "Content-Length: 20\n");
-  SetResponseBody("0123456789abcdefghij");
-  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
-  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
-  EXPECT_STREQ("abcdefghi", &buf[0]);
-}
-
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
deleted file mode 100644
index 875122a..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
+++ /dev/null
@@ -1,197 +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 <errno.h>
-#include <fcntl.h>
-
-#include "nacl_io/error.h"
-#include "nacl_io/ioctl.h"
-#include "nacl_io/kernel_proxy.h"
-#include "nacl_io/mount_dev.h"
-#include "nacl_io/mount_node.h"
-#include "nacl_io/mount_node_dir.h"
-#include "nacl_io/mount_node_mem.h"
-#include "nacl_io/osdirent.h"
-
-#include "gtest/gtest.h"
-
-#define NULL_NODE ((MountNode*) NULL)
-
-using namespace nacl_io;
-
-static int s_AllocNum = 0;
-
-class MockMemory : public MountNodeMem {
- public:
-  MockMemory() : MountNodeMem(NULL) { s_AllocNum++; }
-
-  ~MockMemory() { s_AllocNum--; }
-
-  Error Init(int mode) { return MountNodeMem::Init(mode); }
-  Error AddChild(const std::string& name, const ScopedMountNode& node) {
-    return MountNodeMem::AddChild(name, node);
-  }
-  Error RemoveChild(const std::string& name) {
-    return MountNodeMem::RemoveChild(name);
-  }
-  Error FindChild(const std::string& name, ScopedMountNode* out_node) {
-    return MountNodeMem::FindChild(name, out_node);
-  }
-  void Link() { MountNodeMem::Link(); }
-  void Unlink() { MountNodeMem::Unlink(); }
-
- protected:
-  using MountNodeMem::Init;
-};
-
-class MockDir : public MountNodeDir {
- public:
-  MockDir() : MountNodeDir(NULL) { s_AllocNum++; }
-
-  ~MockDir() { s_AllocNum--; }
-
-  Error Init(int mode) { return MountNodeDir::Init(mode); }
-  Error AddChild(const std::string& name, const ScopedMountNode& node) {
-    return MountNodeDir::AddChild(name, node);
-  }
-  Error RemoveChild(const std::string& name) {
-    return MountNodeDir::RemoveChild(name);
-  }
-  Error FindChild(const std::string& name, ScopedMountNode* out_node) {
-    return MountNodeDir::FindChild(name, out_node);
-  }
-  void Link() { MountNodeDir::Link(); }
-  void Unlink() { MountNodeDir::Unlink(); }
-
- protected:
-  using MountNodeDir::Init;
-};
-
-TEST(MountNodeTest, File) {
-  MockMemory* file = new MockMemory;
-  ScopedMountNode result_node;
-  size_t result_size = 0;
-  int result_bytes = 0;
-
-  EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
-
-  // Test properties
-  EXPECT_EQ(0, file->GetLinks());
-  EXPECT_EQ(S_IREAD | S_IWRITE, file->GetMode());
-  EXPECT_EQ(S_IFREG, file->GetType());
-  EXPECT_FALSE(file->IsaDir());
-  EXPECT_TRUE(file->IsaFile());
-  EXPECT_FALSE(file->IsaTTY());
-  EXPECT_EQ(0, file->RefCount());
-
-  // Test IO
-  char buf1[1024];
-  char buf2[1024 * 2];
-  for (size_t a = 0; a < sizeof(buf1); a++)
-    buf1[a] = a;
-  memset(buf2, 0, sizeof(buf2));
-
-  EXPECT_EQ(0, file->GetSize(&result_size));
-  EXPECT_EQ(0, result_size);
-  EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
-  EXPECT_EQ(0, result_bytes);
-  EXPECT_EQ(0, file->GetSize(&result_size));
-  EXPECT_EQ(0, result_size);
-  EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
-  EXPECT_EQ(sizeof(buf1), result_bytes);
-  EXPECT_EQ(0, file->GetSize(&result_size));
-  EXPECT_EQ(sizeof(buf1), result_size);
-  EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
-  EXPECT_EQ(sizeof(buf1), result_bytes);
-  EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
-
-  struct stat s;
-  EXPECT_EQ(0, file->GetStat(&s));
-  EXPECT_LT(0, s.st_ino);  // 0 is an invalid inode number.
-  EXPECT_EQ(sizeof(buf1), s.st_size);
-
-  // Directory operations should fail
-  struct dirent d;
-  EXPECT_EQ(ENOTDIR, file->GetDents(0, &d, sizeof(d), &result_bytes));
-  EXPECT_EQ(ENOTDIR, file->AddChild("", result_node));
-  EXPECT_EQ(ENOTDIR, file->RemoveChild(""));
-  EXPECT_EQ(ENOTDIR, file->FindChild("", &result_node));
-  EXPECT_EQ(NULL_NODE, result_node.get());
-
-  delete file;
-}
-
-TEST(MountNodeTest, Directory) {
-  MockDir* root = new MockDir();
-  ScopedMountNode result_node;
-  size_t result_size = 0;
-  int result_bytes = 0;
-
-  root->Init(S_IREAD | S_IWRITE);
-
-  // Test properties
-  EXPECT_EQ(0, root->GetLinks());
-  EXPECT_EQ(S_IREAD | S_IWRITE, root->GetMode());
-  EXPECT_EQ(S_IFDIR, root->GetType());
-  EXPECT_TRUE(root->IsaDir());
-  EXPECT_FALSE(root->IsaFile());
-  EXPECT_FALSE(root->IsaTTY());
-  EXPECT_EQ(0, root->RefCount());
-
-  // IO operations should fail
-  char buf1[1024];
-  EXPECT_EQ(0, root->GetSize(&result_size));
-  EXPECT_EQ(0, result_size);
-  EXPECT_EQ(EISDIR, root->Read(0, buf1, sizeof(buf1), &result_bytes));
-  EXPECT_EQ(EISDIR, root->Write(0, buf1, sizeof(buf1), &result_bytes));
-
-  // Test directory operations
-  MockMemory* raw_file = new MockMemory;
-  EXPECT_EQ(0, raw_file->Init(S_IREAD | S_IWRITE));
-  ScopedMountNode file(raw_file);
-
-  EXPECT_EQ(0, root->RefCount());
-  EXPECT_EQ(1, file->RefCount());
-  EXPECT_EQ(0, root->AddChild("F1", file));
-  EXPECT_EQ(1, file->GetLinks());
-  EXPECT_EQ(2, file->RefCount());
-
-  // Test that the directory is there
-  struct dirent d;
-  EXPECT_EQ(0, root->GetDents(0, &d, sizeof(d), &result_bytes));
-  EXPECT_EQ(sizeof(d), result_bytes);
-  EXPECT_LT(0, d.d_ino);  // 0 is an invalid inode number.
-  EXPECT_EQ(sizeof(d), d.d_off);
-  EXPECT_EQ(sizeof(d), d.d_reclen);
-  EXPECT_EQ(0, strcmp("F1", d.d_name));
-  EXPECT_EQ(0, root->GetDents(sizeof(d), &d, sizeof(d), &result_bytes));
-  EXPECT_EQ(0, result_bytes);
-
-  EXPECT_EQ(0, root->AddChild("F2", file));
-  EXPECT_EQ(2, file->GetLinks());
-  EXPECT_EQ(3, file->RefCount());
-  EXPECT_EQ(EEXIST, root->AddChild("F1", file));
-  EXPECT_EQ(2, file->GetLinks());
-  EXPECT_EQ(3, file->RefCount());
-
-  EXPECT_EQ(2, s_AllocNum);
-  EXPECT_EQ(0, root->FindChild("F1", &result_node));
-  EXPECT_NE(NULL_NODE, result_node.get());
-  EXPECT_EQ(0, root->FindChild("F2", &result_node));
-  EXPECT_NE(NULL_NODE, result_node.get());
-  EXPECT_EQ(ENOENT, root->FindChild("F3", &result_node));
-  EXPECT_EQ(NULL_NODE, result_node.get());
-
-  EXPECT_EQ(2, s_AllocNum);
-  EXPECT_EQ(0, root->RemoveChild("F1"));
-  EXPECT_EQ(1, file->GetLinks());
-  EXPECT_EQ(2, file->RefCount());
-  EXPECT_EQ(0, root->RemoveChild("F2"));
-  EXPECT_EQ(0, file->GetLinks());
-  EXPECT_EQ(1, file->RefCount());
-  EXPECT_EQ(2, s_AllocNum);
-
-  file.reset();
-  EXPECT_EQ(1, s_AllocNum);
-}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
deleted file mode 100644
index 4829ccf..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
+++ /dev/null
@@ -1,368 +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 <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <string>
-
-#include "gtest/gtest.h"
-#include "nacl_io/ioctl.h"
-#include "nacl_io/mount.h"
-#include "nacl_io/mount_dev.h"
-#include "nacl_io/mount_mem.h"
-#include "nacl_io/osdirent.h"
-#include "nacl_io/osunistd.h"
-
-using namespace nacl_io;
-
-namespace {
-
-class MountMemMock : public MountMem {
- public:
-  MountMemMock() {
-    StringMap_t map;
-    EXPECT_EQ(0, Init(1, map, NULL));
-  }
-
-  int num_nodes() { return (int) inode_pool_.size(); }
-};
-
-class MountDevMock : public MountDev {
- public:
-  MountDevMock() {
-    StringMap_t map;
-    Init(1, map, NULL);
-  }
-  int num_nodes() { return (int) inode_pool_.size(); }
-};
-
-}  // namespace
-
-#define NULL_NODE ((MountNode*) NULL)
-
-TEST(MountTest, Sanity) {
-  MountMemMock* mnt = new MountMemMock();
-
-  ScopedMountNode file;
-  ScopedMountNode root;
-  ScopedMountNode result_node;
-
-  size_t result_size = 0;
-  int result_bytes = 0;
-  char buf1[1024];
-
-  // A memory mount starts with one directory node: the root.
-  EXPECT_EQ(1, mnt->num_nodes());
-
-  // Fail to open non existent file
-  EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), R_OK | W_OK));
-  EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &result_node));
-  EXPECT_EQ(NULL, result_node.get());
-  EXPECT_EQ(1, mnt->num_nodes());
-
-  // Create a file
-  EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &file));
-  EXPECT_NE(NULL_NODE, file.get());
-  if (file == NULL)
-    return;
-
-  // We now have a directory and a file.  The file has a two references
-  // one returned to the test, one for the name->inode map.
-  EXPECT_EQ(2, mnt->num_nodes());
-  EXPECT_EQ(2, file->RefCount());
-  EXPECT_EQ(0, mnt->Access(Path("/foo"), R_OK | W_OK));
-  EXPECT_EQ(EACCES, mnt->Access(Path("/foo"), X_OK));
-
-  // Write access should be allowed on the root directory.
-  EXPECT_EQ(0, mnt->Access(Path("/"), R_OK | W_OK));
-  EXPECT_EQ(EACCES, mnt->Access(Path("/"), X_OK));
-  // Open the root directory for write should fail.
-  EXPECT_EQ(EISDIR, mnt->Open(Path("/"), O_RDWR, &root));
-  EXPECT_EQ(2, mnt->num_nodes());
-
-  // Open the root directory, should not create a new file
-  EXPECT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
-  EXPECT_EQ(2, mnt->num_nodes());
-  EXPECT_NE(NULL_NODE, root.get());
-  if (NULL != root) {
-    struct dirent dirs[2];
-    int len;
-    EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
-    EXPECT_EQ(sizeof(struct dirent), len);
-  }
-
-  // Fail to re-create the same file
-  EXPECT_EQ(EEXIST,
-            mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
-  EXPECT_EQ(NULL_NODE, result_node.get());
-  EXPECT_EQ(2, mnt->num_nodes());
-
-  // Fail to create a directory with the same name
-  EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/foo"), O_RDWR));
-  EXPECT_EQ(2, mnt->num_nodes());
-
-  // Attempt to READ/WRITE
-  EXPECT_EQ(0, file->GetSize(&result_size));
-  EXPECT_EQ(0, result_size);
-  EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
-  EXPECT_EQ(sizeof(buf1), result_bytes);
-  EXPECT_EQ(0, file->GetSize(&result_size));
-  EXPECT_EQ(sizeof(buf1), result_size);
-  EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes));
-  EXPECT_EQ(sizeof(buf1), result_bytes);
-  EXPECT_EQ(2, mnt->num_nodes());
-  EXPECT_EQ(2, file->RefCount());
-
-  // Attempt to open the same file, create another ref to it, but does not
-  // create a new file.
-  EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
-  EXPECT_EQ(3, file->RefCount());
-  EXPECT_EQ(2, mnt->num_nodes());
-  EXPECT_EQ(file.get(), result_node.get());
-  EXPECT_EQ(0, file->GetSize(&result_size));
-  EXPECT_EQ(sizeof(buf1), result_size);
-
-  // Remove our references so that only the Mount holds it
-  file.reset();
-  result_node.reset();
-  EXPECT_EQ(2, mnt->num_nodes());
-
-  // This should have deleted the object
-  EXPECT_EQ(0, mnt->Unlink(Path("/foo")));
-  EXPECT_EQ(1, mnt->num_nodes());
-
-  // We should fail to find it
-  EXPECT_EQ(ENOENT, mnt->Unlink(Path("/foo")));
-  EXPECT_EQ(1, mnt->num_nodes());
-
-  // Recreate foo as a directory
-  EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR));
-  EXPECT_EQ(2, mnt->num_nodes());
-
-  // Create a file (exclusively)
-  EXPECT_EQ(0, mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
-  EXPECT_NE(NULL_NODE, file.get());
-  if (NULL == file)
-    return;
-  EXPECT_EQ(2, file->RefCount());
-  EXPECT_EQ(3, mnt->num_nodes());
-
-  // Attempt to delete the directory and fail
-  EXPECT_EQ(ENOTEMPTY, mnt->Rmdir(Path("/foo")));
-  EXPECT_EQ(2, root->RefCount());
-  EXPECT_EQ(2, file->RefCount());
-  EXPECT_EQ(3, mnt->num_nodes());
-
-  // Unlink the file, we should have the only file ref at this point.
-  EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar")));
-  EXPECT_EQ(2, root->RefCount());
-  EXPECT_EQ(1, file->RefCount());
-  EXPECT_EQ(3, mnt->num_nodes());
-
-
-  // Deref the file, to make it go away
-  file.reset();
-  EXPECT_EQ(2, mnt->num_nodes());
-
-  // Deref the directory
-  EXPECT_EQ(0, mnt->Rmdir(Path("/foo")));
-  EXPECT_EQ(1, mnt->num_nodes());
-
-  // Verify the directory is gone
-  EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
-  EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &file));
-  EXPECT_EQ(NULL_NODE, file.get());
-}
-
-TEST(MountTest, MemMountRemove) {
-  MountMemMock* mnt = new MountMemMock();
-  ScopedMountNode file;
-  ScopedMountNode result_node;
-
-  EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
-  EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
-  EXPECT_NE(NULL_NODE, file.get());
-  EXPECT_EQ(3, mnt->num_nodes());
-  file.reset();
-
-  EXPECT_EQ(0, mnt->Remove(Path("/dir")));
-  EXPECT_EQ(2, mnt->num_nodes());
-  EXPECT_EQ(0, mnt->Remove(Path("/file")));
-  EXPECT_EQ(1, mnt->num_nodes());
-
-  EXPECT_EQ(ENOENT,
-            mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
-  EXPECT_EQ(NULL_NODE, result_node.get());
-  EXPECT_EQ(ENOENT, mnt->Open(Path("/file"), O_RDONLY, &result_node));
-  EXPECT_EQ(NULL_NODE, result_node.get());
-}
-
-TEST(MountTest, DevAccess) {
-  // Should not be able to open non-existent file.
-  MountDevMock* mnt = new MountDevMock();
-  ASSERT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
-}
-
-TEST(MountTest, DevNull) {
-  MountDevMock* mnt = new MountDevMock();
-  ScopedMountNode dev_null;
-  int result_bytes = 0;
-
-  ASSERT_EQ(0, mnt->Access(Path("/null"), R_OK | W_OK));
-  ASSERT_EQ(EACCES, mnt->Access(Path("/null"), X_OK));
-  ASSERT_EQ(0, mnt->Open(Path("/null"), O_RDWR, &dev_null));
-  ASSERT_NE(NULL_NODE, dev_null.get());
-
-  // Writing to /dev/null should write everything.
-  const char msg[] = "Dummy test message.";
-  EXPECT_EQ(0, dev_null->Write(0, &msg[0], strlen(msg), &result_bytes));
-  EXPECT_EQ(strlen(msg), result_bytes);
-
-  // Reading from /dev/null should read nothing.
-  const int kBufferLength = 100;
-  char buffer[kBufferLength];
-  EXPECT_EQ(0, dev_null->Read(0, &buffer[0], kBufferLength, &result_bytes));
-  EXPECT_EQ(0, result_bytes);
-}
-
-TEST(MountTest, DevZero) {
-  MountDevMock* mnt = new MountDevMock();
-  ScopedMountNode dev_zero;
-  int result_bytes = 0;
-
-  ASSERT_EQ(0, mnt->Access(Path("/zero"), R_OK | W_OK));
-  ASSERT_EQ(EACCES, mnt->Access(Path("/zero"), X_OK));
-  ASSERT_EQ(0, mnt->Open(Path("/zero"), O_RDWR, &dev_zero));
-  ASSERT_NE(NULL_NODE, dev_zero.get());
-
-  // Writing to /dev/zero should write everything.
-  const char msg[] = "Dummy test message.";
-  EXPECT_EQ(0, dev_zero->Write(0, &msg[0], strlen(msg), &result_bytes));
-  EXPECT_EQ(strlen(msg), result_bytes);
-
-  // Reading from /dev/zero should read all zeroes.
-  const int kBufferLength = 100;
-  char buffer[kBufferLength];
-  // First fill with all 1s.
-  memset(&buffer[0], 0x1, kBufferLength);
-  EXPECT_EQ(0, dev_zero->Read(0, &buffer[0], kBufferLength, &result_bytes));
-  EXPECT_EQ(kBufferLength, result_bytes);
-
-  char zero_buffer[kBufferLength];
-  memset(&zero_buffer[0], 0, kBufferLength);
-  EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
-}
-
-// Disabled due to intermittent failures on linux: http://crbug.com/257257
-TEST(MountTest, DISABLED_DevUrandom) {
-  MountDevMock* mnt = new MountDevMock();
-  ScopedMountNode dev_urandom;
-  int result_bytes = 0;
-
-  ASSERT_EQ(0, mnt->Access(Path("/urandom"), R_OK | W_OK));
-  ASSERT_EQ(EACCES, mnt->Access(Path("/urandom"), X_OK));
-  ASSERT_EQ(0, mnt->Open(Path("/urandom"), O_RDWR, &dev_urandom));
-  ASSERT_NE(NULL_NODE, dev_urandom.get());
-
-  // Writing to /dev/urandom should write everything.
-  const char msg[] = "Dummy test message.";
-  EXPECT_EQ(0, dev_urandom->Write(0, &msg[0], strlen(msg), &result_bytes));
-  EXPECT_EQ(strlen(msg), result_bytes);
-
-  // Reading from /dev/urandom should read random bytes.
-  const int kSampleBatches = 1000;
-  const int kSampleBatchSize = 1000;
-  const int kTotalSamples = kSampleBatches * kSampleBatchSize;
-
-  int byte_count[256] = {0};
-
-  unsigned char buffer[kSampleBatchSize];
-  for (int batch = 0; batch < kSampleBatches; ++batch) {
-    int bytes_read = 0;
-    EXPECT_EQ(0,
-              dev_urandom->Read(0, &buffer[0], kSampleBatchSize, &bytes_read));
-    EXPECT_EQ(kSampleBatchSize, bytes_read);
-
-    for (int i = 0; i < bytes_read; ++i) {
-      byte_count[buffer[i]]++;
-    }
-  }
-
-  double expected_count = kTotalSamples / 256.;
-  double chi_squared = 0;
-  for (int i = 0; i < 256; ++i) {
-    double difference = byte_count[i] - expected_count;
-    chi_squared += difference * difference / expected_count;
-  }
-
-  // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
-  EXPECT_LE(chi_squared, 293.24);
-}
-
-
-TEST(MountTest, DevTty) {
-  MountDevMock* mnt = new MountDevMock();
-  ScopedMountNode dev_tty;
-
-  ASSERT_EQ(0, mnt->Access(Path("/tty"), R_OK | W_OK));
-  ASSERT_EQ(EACCES, mnt->Access(Path("/tty"), X_OK));
-  ASSERT_EQ(0, mnt->Open(Path("/tty"), O_RDWR, &dev_tty));
-  ASSERT_NE(NULL_NODE, dev_tty.get());
-
-  // 123 is not a valid ioctl request.
-  EXPECT_EQ(EINVAL, dev_tty->Ioctl(123, NULL));
-
-  // TIOCNACLPREFIX is, it should set the prefix.
-  std::string prefix("__my_awesome_prefix__");
-  EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLPREFIX,
-                              const_cast<char*>(prefix.c_str())));
-
-  // Now let's try sending some data over.
-  // First we create the message.
-  std::string content("hello, how are you?\n");
-  std::string message = prefix.append(content);
-  struct tioc_nacl_input_string packaged_message;
-  packaged_message.length = message.size();
-  packaged_message.buffer = message.data();
-
-  // Now we make buffer we'll read into.
-  // We fill the buffer and a backup buffer with arbitrary data
-  // and compare them after reading to make sure read doesn't
-  // clobber parts of the buffer it shouldn't.
-  int bytes_read;
-  char buffer[100];
-  char backup_buffer[100];
-  memset(buffer, 'a', 100);
-  memset(backup_buffer, 'a', 100);
-
-  // Now we actually send the data
-  EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLINPUT,
-                              reinterpret_cast<char*>(&packaged_message)));
-
-  // We read a small chunk first to ensure it doesn't give us
-  // more than we ask for.
-  EXPECT_EQ(0, dev_tty->Read(0, buffer, 5, &bytes_read));
-  EXPECT_EQ(bytes_read, 5);
-  EXPECT_EQ(0, memcmp(content.data(), buffer, 5));
-  EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
-
-  // Now we ask for more data than is left in the tty, to ensure
-  // it doesn't give us more than is there.
-  EXPECT_EQ(0, dev_tty->Read(0, buffer + 5, 95, &bytes_read));
-  EXPECT_EQ(bytes_read, content.size() - 5);
-  EXPECT_EQ(0, memcmp(content.data(), buffer, content.size()));
-  EXPECT_EQ(0, memcmp(buffer + content.size(),
-                      backup_buffer + content.size(),
-                       100 - content.size()));
-
-  // Now we try to send something with an invalid prefix
-  std::string bogus_message("Woah there, this message has no valid prefix");
-  struct tioc_nacl_input_string bogus_pack;
-  bogus_pack.length = bogus_message.size();
-  bogus_pack.buffer = bogus_message.data();
-  EXPECT_EQ(ENOTTY, dev_tty->Ioctl(TIOCNACLINPUT,
-                                   reinterpret_cast<char*>(&bogus_pack)));
-}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/path_test.cc b/native_client_sdk/src/libraries/nacl_io_test/path_test.cc
deleted file mode 100644
index ab12f39..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/path_test.cc
+++ /dev/null
@@ -1,260 +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 <fcntl.h>
-#include "nacl_io/kernel_proxy.h"
-#include "nacl_io/path.h"
-
-#include "gtest/gtest.h"
-
-using namespace nacl_io;
-
-TEST(PathTest, SanityChecks) {
-  // can we construct and delete?
-  Path ph1(".");
-  Path *ph2 = new Path(".");
-  delete ph2;
-
-  Path p1(".");
-  EXPECT_FALSE(p1.IsAbsolute());
-  EXPECT_EQ(".", p1.Join());
-  Path p2("/");
-  EXPECT_TRUE(p2.IsAbsolute());
-  EXPECT_EQ("/", p2.Join());
-}
-
-TEST(PathTest, Assignment) {
-  Path empty;
-  Path dot(".");
-  Path root("/");
-  Path abs_str("/abs/from/string");
-  Path rel_str("rel/from/string");
-  Path self_str("./rel/from/string");
-
-  EXPECT_EQ(0, empty.Size());
-  EXPECT_FALSE(empty.IsAbsolute());
-  EXPECT_EQ(std::string(""), empty.Join());
-
-  EXPECT_EQ(1, dot.Size());
-  EXPECT_FALSE(dot.IsAbsolute());
-  EXPECT_EQ(std::string("."), dot.Join());
-
-  EXPECT_EQ(1, root.Size());
-  EXPECT_TRUE(root.IsAbsolute());
-  EXPECT_EQ(std::string("/"), root.Join());
-
-  EXPECT_EQ(4, abs_str.Size());
-  EXPECT_TRUE(abs_str.IsAbsolute());
-  EXPECT_EQ(std::string("/abs/from/string"), abs_str.Join());
-
-  EXPECT_EQ(3, rel_str.Size());
-  EXPECT_FALSE(rel_str.IsAbsolute());
-  EXPECT_EQ(std::string("rel/from/string"), rel_str.Join());
-
-  EXPECT_EQ(3, self_str.Size());
-  EXPECT_FALSE(self_str.IsAbsolute());
-  EXPECT_EQ(std::string("rel/from/string"), self_str.Join());
-
-  empty = "";
-  dot = ".";
-  root = "/";
-  abs_str = "/abs/from/assign";
-  rel_str = "rel/from/assign";
-  self_str = "./rel/from/assign";
-
-  EXPECT_EQ(1, empty.Size());
-  EXPECT_FALSE(empty.IsAbsolute());
-  EXPECT_EQ(std::string("."), empty.Join());
-
-  EXPECT_EQ(1, dot.Size());
-  EXPECT_FALSE(dot.IsAbsolute());
-  EXPECT_EQ(std::string("."), dot.Join());
-
-  EXPECT_EQ(1, root.Size());
-  EXPECT_TRUE(root.IsAbsolute());
-  EXPECT_EQ(std::string("/"), root.Join());
-
-  EXPECT_EQ(4, abs_str.Size());
-  EXPECT_TRUE(abs_str.IsAbsolute());
-  EXPECT_EQ(std::string("/abs/from/assign"), abs_str.Join());
-
-  EXPECT_EQ(3, rel_str.Size());
-  EXPECT_FALSE(rel_str.IsAbsolute());
-  EXPECT_EQ(std::string("rel/from/assign"), rel_str.Join());
-
-  EXPECT_EQ(3, self_str.Size());
-  EXPECT_FALSE(self_str.IsAbsolute());
-  EXPECT_EQ(std::string("rel/from/assign"), self_str.Join());
-
-  Path cpy_str;
-  cpy_str = empty;
-  EXPECT_EQ(1, cpy_str.Size());
-  EXPECT_FALSE(cpy_str.IsAbsolute());
-  EXPECT_EQ(std::string("."), cpy_str.Join());
-
-  cpy_str = dot;
-  EXPECT_EQ(1, cpy_str.Size());
-  EXPECT_FALSE(cpy_str.IsAbsolute());
-  EXPECT_EQ(std::string("."), cpy_str.Join());
-
-  cpy_str = root;
-  EXPECT_EQ(1, cpy_str.Size());
-  EXPECT_TRUE(cpy_str.IsAbsolute());
-  EXPECT_EQ(std::string("/"), cpy_str.Join());
-
-  cpy_str = abs_str;
-  EXPECT_EQ(4, cpy_str.Size());
-  EXPECT_TRUE(cpy_str.IsAbsolute());
-  EXPECT_EQ(std::string("/abs/from/assign"), cpy_str.Join());
-
-  cpy_str = rel_str;
-  EXPECT_EQ(3, cpy_str.Size());
-  EXPECT_FALSE(cpy_str.IsAbsolute());
-  EXPECT_EQ(std::string("rel/from/assign"), cpy_str.Join());
-
-  cpy_str = self_str;
-  EXPECT_EQ(3, cpy_str.Size());
-  EXPECT_FALSE(cpy_str.IsAbsolute());
-  EXPECT_EQ(std::string("rel/from/assign"), cpy_str.Join());
-}
-
-
-TEST(PathTest, Collapse) {
-  StringArray_t path_components;
-
-  Path p1("/simple/splitter/test");
-  path_components = p1.Split();
-  EXPECT_EQ("/", path_components[0]);
-  EXPECT_EQ("/", p1.Part(0));
-
-  EXPECT_EQ("simple", path_components[1]);
-  EXPECT_EQ("simple", p1.Part(1));
-
-  EXPECT_EQ("splitter",path_components[2]);
-  EXPECT_EQ("splitter",p1.Part(2));
-
-  EXPECT_EQ("test", path_components[3]);
-  EXPECT_EQ("test", p1.Part(3));
-
-  Path p2("///simple//splitter///test/");
-  path_components = p2.Split();
-  EXPECT_EQ(4, static_cast<int>(path_components.size()));
-  EXPECT_EQ(4, static_cast<int>(p2.Size()));
-  EXPECT_EQ("/", path_components[0]);
-  EXPECT_EQ("simple", path_components[1]);
-  EXPECT_EQ("splitter", path_components[2]);
-  EXPECT_EQ("test", path_components[3]);
-
-  Path p3("sim/ple//spli/tter/te/st/");
-  path_components = p3.Split();
-  EXPECT_EQ(6, static_cast<int>(path_components.size()));
-  EXPECT_FALSE(p3.IsAbsolute());
-  EXPECT_EQ("sim", path_components[0]);
-  EXPECT_EQ("ple", path_components[1]);
-  EXPECT_EQ("spli", path_components[2]);
-  EXPECT_EQ("tter", path_components[3]);
-  EXPECT_EQ("te", path_components[4]);
-  EXPECT_EQ("st", path_components[5]);
-
-  Path p4("");
-  path_components = p4.Split();
-  EXPECT_EQ(1, static_cast<int>(path_components.size()));
-
-  Path p5("/");
-  path_components = p5.Split();
-  EXPECT_EQ(1, static_cast<int>(path_components.size()));
-}
-
-TEST(PathTest, AppendAndJoin) {
-  Path ph1("/usr/local/hi/there");
-
-  EXPECT_EQ("/usr/local/hi/there", ph1.Join());
-  ph1 = ph1.Append("..");
-  EXPECT_EQ("/usr/local/hi", ph1.Join());
-  ph1 = ph1.Append(".././././hi/there/../.././././");
-  EXPECT_EQ("/usr/local", ph1.Join());
-  ph1 = ph1.Append("../../../../../../../../././../");
-  EXPECT_EQ("/", ph1.Join());
-  ph1 = ph1.Append("usr/lib/../bin/.././etc/../local/../share");
-  EXPECT_EQ("/usr/share", ph1.Join());
-
-  Path ph2("./");
-  EXPECT_EQ(".", ph2.Join());
-
-  Path ph3("/");
-  EXPECT_EQ("/", ph3.Join());
-  ph3 = ph3.Append("");
-  EXPECT_EQ("/", ph3.Join());
-  ph3 = ph3.Append("USR/local/SHARE");
-  EXPECT_EQ("/USR/local/SHARE", ph3.Join());
-  ph3 = ph3.Append("///////////////////////////////");
-  EXPECT_EQ("/USR/local/SHARE", ph3.Join());
-
-  Path ph4("..");
-  EXPECT_EQ("..", ph4.Join());
-  ph4 = ph4.Append("/node1/node3/../../node1/./");
-  EXPECT_EQ("../node1", ph4.Join());
-  ph4 = ph4.Append("node4/../../node1/./node5");
-  EXPECT_EQ("../node1/node5", ph4.Join());
-}
-
-
-TEST(PathTest, Invalid) {
-  Path rooted("/usr/local");
-  Path current("./usr/local");
-  Path relative("usr/local");
-
-  Path test;
-
-  test = rooted;
-  test.Append("../..");
-  EXPECT_EQ("/", test.Join());
-
-  test = rooted;
-  test.Append("../../..");
-  EXPECT_EQ("/", test.Join());
-
-  test = rooted;
-  test.Append("../../../foo");
-  EXPECT_EQ("/foo", test.Join());
-
-  test = current;
-  test.Append("../..");
-  EXPECT_EQ(".", test.Join());
-
-  test = current;
-  test.Append("../../..");
-  EXPECT_EQ("..", test.Join());
-
-  test = current;
-  test.Append("../../../foo");
-  EXPECT_EQ("../foo", test.Join());
-
-  test = relative;
-  test.Append("../..");
-  EXPECT_EQ(".", test.Join());
-
-  test = relative;
-  test.Append("../../..");
-  EXPECT_EQ("..", test.Join());
-
-  test = relative;
-  test.Append("../../../foo");
-  EXPECT_EQ("../foo", test.Join());
-}
-
-TEST(PathTest, Range) {
-  Path p("/an/absolute/path");
-
-  // p's parts should be ["/", "an", "absolute", "path"].
-  EXPECT_EQ("/an/absolute/path", p.Range(0, 4));
-  EXPECT_EQ("an/absolute/path", p.Range(1, 4));
-  EXPECT_EQ("absolute/path", p.Range(2, 4));
-  EXPECT_EQ("path", p.Range(3, 4));
-
-  EXPECT_EQ("/an/absolute", p.Range(0, 3));
-  EXPECT_EQ("an/absolute", p.Range(1, 3));
-  EXPECT_EQ("absolute", p.Range(2, 3));
-}
-
diff --git a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.h b/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.h
deleted file mode 100644
index ae4b579..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.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 LIBRARIES_NACL_IO_TEST_PEPPER_INTERFACE_MOCK_H_
-#define LIBRARIES_NACL_IO_TEST_PEPPER_INTERFACE_MOCK_H_
-
-#include "gmock/gmock.h"
-#include "nacl_io/pepper_interface.h"
-
-// Mock interface class definitions.
-#include "nacl_io/pepper/undef_macros.h"
-#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
-    class BaseClass##Mock : public nacl_io::BaseClass { \
-     public: \
-      BaseClass##Mock(); \
-      virtual ~BaseClass##Mock();
-#define END_INTERFACE(BaseClass, PPInterface) \
-    };
-#define METHOD1(Class, ReturnType, MethodName, Type0) \
-    MOCK_METHOD1(MethodName, ReturnType(Type0));
-#define METHOD2(Class, ReturnType, MethodName, Type0, Type1) \
-    MOCK_METHOD2(MethodName, ReturnType(Type0, Type1));
-#define METHOD3(Class, ReturnType, MethodName, Type0, Type1, Type2) \
-    MOCK_METHOD3(MethodName, ReturnType(Type0, Type1, Type2));
-#define METHOD4(Class, ReturnType, MethodName, Type0, Type1, Type2, Type3) \
-    MOCK_METHOD4(MethodName, ReturnType(Type0, Type1, Type2, Type3));
-#define METHOD5(Class, ReturnType, MethodName, Type0, Type1, Type2, Type3, \
-                Type4) \
-    MOCK_METHOD5(MethodName, ReturnType(Type0, Type1, Type2, Type3, Type4));
-#include "nacl_io/pepper/all_interfaces.h"
-
-
-class PepperInterfaceMock : public nacl_io::PepperInterface {
- public:
-  explicit PepperInterfaceMock(PP_Instance instance);
-  ~PepperInterfaceMock();
-
-  virtual PP_Instance GetInstance();
-  MOCK_METHOD1(AddRefResource, void(PP_Resource));
-  MOCK_METHOD1(ReleaseResource, void(PP_Resource));
-  MOCK_METHOD0(IsMainThread, bool());
-
-// Interface getters.
-#include "nacl_io/pepper/undef_macros.h"
-#include "nacl_io/pepper/define_empty_macros.h"
-#undef BEGIN_INTERFACE
-#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
-    virtual BaseClass##Mock* Get##BaseClass();
-#include "nacl_io/pepper/all_interfaces.h"
-
- private:
-  PP_Instance instance_;
-
-// Interface pointers.
-#include "nacl_io/pepper/undef_macros.h"
-#include "nacl_io/pepper/define_empty_macros.h"
-#undef BEGIN_INTERFACE
-#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
-    BaseClass##Mock* BaseClass##interface_;
-#include "nacl_io/pepper/all_interfaces.h"
-
-  int dummy_;
-};
-
-
-#endif  // LIBRARIES_NACL_IO_TEST_PEPPER_INTERFACE_MOCK_H_
diff --git a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc b/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
deleted file mode 100644
index e98aa7a..0000000
--- a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
+++ /dev/null
@@ -1,414 +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 <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <sys/stat.h>
-
-#include <map>
-#include <string>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "nacl_io/kernel_intercept.h"
-#include "nacl_io/kernel_proxy.h"
-#include "nacl_io/ossocket.h"
-#include "nacl_io/ostypes.h"
-
-#ifdef PROVIDES_SOCKET_API
-
-using namespace nacl_io;
-using namespace sdk_util;
-
-namespace {
-class SocketTest : public ::testing::Test {
- public:
-  SocketTest() : kp_(new KernelProxy) {
-    ki_init(kp_);
-  }
-
-  ~SocketTest() {
-    ki_uninit();
-    delete kp_;
-  }
-
- protected:
-  KernelProxy* kp_;
-};
-
-}  // namespace
-
-TEST_F(SocketTest, Accept) {
-  struct sockaddr addr = {};
-  socklen_t len = 0;
-
-  EXPECT_LT(ki_accept(123, NULL, &len), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_accept(123, &addr, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_accept(123, NULL, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_accept(-1, &addr, &len), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_accept(0, &addr, &len), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Bind) {
-  const struct sockaddr const_addr = {};
-  socklen_t len = 0;
-
-  EXPECT_LT(ki_bind(123, NULL, len), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_bind(-1, &const_addr, len), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_bind(0, &const_addr, len), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Connect) {
-  const struct sockaddr const_addr = {};
-  socklen_t len = 0;
-
-  EXPECT_LT(ki_connect(123, NULL, len), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_connect(-1, &const_addr, len), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_connect(0, &const_addr, len), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Getpeername) {
-  struct sockaddr addr = {};
-  socklen_t len = 0;
-
-  EXPECT_LT(ki_getpeername(123, NULL, &len), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getpeername(123, &addr, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getpeername(123, NULL, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getpeername(-1, &addr, &len), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_getpeername(0, &addr, &len), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Getsockname) {
-  struct sockaddr addr = {};
-  socklen_t len = 0;
-
-  EXPECT_LT(ki_getsockname(123, NULL, &len), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getsockname(123, &addr, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getsockname(123, NULL, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getsockname(-1, &addr, &len), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_getsockname(0, &addr, &len), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Getsockopt) {
-  socklen_t len = 10;
-  char optval[len];
-
-  EXPECT_LT(ki_getsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, optval, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, NULL, &len), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, NULL, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_getsockopt(-1, SOL_SOCKET, SO_ACCEPTCONN, optval, &len), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_getsockopt(0, SOL_SOCKET, SO_ACCEPTCONN, optval, &len), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Listen) {
-  EXPECT_LT(ki_listen(-1, 123), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_listen(0, 123), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Recv) {
-  size_t len = 10;
-  char buf[len];
-
-  EXPECT_LT(ki_recv(123, NULL, len, 0), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_recv(-1, buf, len, 0), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_recv(0, buf, len, 0), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Recvfrom) {
-  size_t len = 10;
-  char buf[len];
-  struct sockaddr addr = {};
-  socklen_t addrlen = 4;
-
-  EXPECT_LT(ki_recvfrom(123, NULL, len, 0, &addr, &addrlen), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_recvfrom(123, buf, len, 0, &addr, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_recvfrom(-1, buf, len, 0, &addr, &addrlen), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_recvfrom(0, buf, len, 0, &addr, &addrlen), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Recvmsg) {
-  struct msghdr msg = {};
-
-  EXPECT_LT(ki_recvmsg(123, NULL, 0), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_recvmsg(-1, &msg, 0), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_recvmsg(0, &msg, 0), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Send) {
-  size_t len = 10;
-  char buf[len];
-
-  EXPECT_LT(ki_send(123, NULL, len, 0), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_send(-1, buf, len, 0), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_send(0, buf, len, 0), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Sendto) {
-  size_t len = 10;
-  char buf[len];
-  struct sockaddr addr = {};
-  socklen_t addrlen = 4;
-
-  EXPECT_LT(ki_sendto(123, NULL, len, 0, &addr, addrlen), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_sendto(-1, buf, len, 0, &addr, addrlen), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_sendto(0, buf, len, 0, &addr, addrlen), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Sendmsg) {
-  struct msghdr msg = {};
-
-  EXPECT_LT(ki_sendmsg(123, NULL, 0), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_sendmsg(-1, &msg, 0), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_sendmsg(0, &msg, 0), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Setsockopt) {
-  socklen_t len = 10;
-  char optval[len];
-
-  EXPECT_LT(ki_setsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, NULL, len), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_setsockopt(-1, SOL_SOCKET, SO_ACCEPTCONN, optval, len), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_setsockopt(0, SOL_SOCKET, SO_ACCEPTCONN, optval, len), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Shutdown) {
-  EXPECT_LT(ki_shutdown(-1, SHUT_RDWR), 0);
-  EXPECT_EQ(errno, EBADF);
-  EXPECT_LT(ki_shutdown(0, SHUT_RDWR), 0);
-  EXPECT_EQ(errno, ENOTSOCK);
-}
-
-TEST_F(SocketTest, Socket) {
-  EXPECT_LT(ki_socket(AF_UNIX, SOCK_STREAM, 0), 0);
-  EXPECT_EQ(errno, EAFNOSUPPORT);
-  EXPECT_LT(ki_socket(AF_INET, SOCK_RAW, 0), 0);
-  EXPECT_EQ(errno, EPROTONOSUPPORT);
-
-  // These four af/protocol combinations should be supported.
-  EXPECT_LT(ki_socket(AF_INET, SOCK_STREAM, 0), 0);
-  EXPECT_EQ(errno, EACCES);
-  EXPECT_LT(ki_socket(AF_INET, SOCK_DGRAM, 0), 0);
-  EXPECT_EQ(errno, EACCES);
-  EXPECT_LT(ki_socket(AF_INET6, SOCK_STREAM, 0), 0);
-  EXPECT_EQ(errno, EACCES);
-  EXPECT_LT(ki_socket(AF_INET6, SOCK_DGRAM, 0), 0);
-  EXPECT_EQ(errno, EACCES);
-}
-
-TEST_F(SocketTest, Socketpair) {
-  int sv[2];
-  EXPECT_LT(ki_socketpair(AF_INET, SOCK_STREAM, 0, NULL), 0);
-  EXPECT_EQ(errno, EFAULT);
-  EXPECT_LT(ki_socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
-  EXPECT_EQ(errno, EAFNOSUPPORT);
-  EXPECT_LT(ki_socketpair(AF_INET, SOCK_STREAM, 0, sv), 0);
-  EXPECT_EQ(errno, EPROTONOSUPPORT);
-  EXPECT_LT(ki_socketpair(AF_INET6, SOCK_STREAM, 0, sv), 0);
-  EXPECT_EQ(errno, EPROTONOSUPPORT);
-}
-
-// These utility functions are only used for newlib (glibc provides its own
-// implementations of these functions).
-#if !defined(__GLIBC__)
-
-TEST(SocketUtilityFunctions, Hstrerror) {
-  EXPECT_STREQ(hstrerror(2718),
-               "Unknown error in gethostbyname: 2718.");
-}
-
-TEST(SocketUtilityFunctions, Htonl) {
-  uint32_t host_long = 0x44332211;
-  uint32_t network_long = htonl(host_long);
-  uint8_t network_bytes[4];
-  memcpy(network_bytes, &network_long, 4);
-  EXPECT_EQ(network_bytes[0], 0x44);
-  EXPECT_EQ(network_bytes[1], 0x33);
-  EXPECT_EQ(network_bytes[2], 0x22);
-  EXPECT_EQ(network_bytes[3], 0x11);
-}
-
-TEST(SocketUtilityFunctions, Htons) {
-  uint16_t host_short = 0x2211;
-  uint16_t network_short = htons(host_short);
-  uint8_t network_bytes[2];
-  memcpy(network_bytes, &network_short, 2);
-  EXPECT_EQ(network_bytes[0], 0x22);
-  EXPECT_EQ(network_bytes[1], 0x11);
-}
-
-static struct in_addr generate_ipv4_addr(int tuple1, int tuple2,
-                                         int tuple3, int tuple4) {
-  unsigned char addr[4];
-  addr[0] = static_cast<unsigned char>(tuple1);
-  addr[1] = static_cast<unsigned char>(tuple2);
-  addr[2] = static_cast<unsigned char>(tuple3);
-  addr[3] = static_cast<unsigned char>(tuple4);
-  struct in_addr real_addr;
-  memcpy(&real_addr, addr, 4);
-  return real_addr;
-}
-
-static struct in6_addr generate_ipv6_addr(int* tuples) {
-  unsigned char addr[16];
-  for (int i = 0; i < 8; i++) {
-    addr[2*i] = (tuples[i] >> 8) & 0xFF;
-    addr[2*i+1] = tuples[i] & 0xFF;
-  }
-  struct in6_addr real_addr;
-  memcpy(&real_addr, addr, 16);
-  return real_addr;
-}
-
-TEST(SocketUtilityFunctions, Inet_ntoa) {
-  char* stringified_addr = inet_ntoa(generate_ipv4_addr(0,0,0,0));
-  ASSERT_TRUE(NULL != stringified_addr);
-  EXPECT_STREQ("0.0.0.0", stringified_addr);
-
-  stringified_addr = inet_ntoa(generate_ipv4_addr(127,0,0,1));
-  ASSERT_TRUE(NULL != stringified_addr);
-  EXPECT_STREQ("127.0.0.1", stringified_addr);
-
-  stringified_addr = inet_ntoa(generate_ipv4_addr(255,255,255,255));
-  ASSERT_TRUE(NULL != stringified_addr);
-  EXPECT_STREQ("255.255.255.255", stringified_addr);
-}
-
-TEST(SocketUtilityFunctions, Inet_ntop_ipv4) {
-  char stringified_addr[INET_ADDRSTRLEN];
-
-  struct in_addr real_addr = generate_ipv4_addr(0,0,0,0);
-  EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
-                                stringified_addr, INET_ADDRSTRLEN));
-  EXPECT_STREQ("0.0.0.0", stringified_addr);
-
-  real_addr = generate_ipv4_addr(127,0,0,1);
-  EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
-                                stringified_addr, INET_ADDRSTRLEN));
-  EXPECT_STREQ("127.0.0.1", stringified_addr);
-
-  real_addr = generate_ipv4_addr(255,255,255,255);
-  EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
-                                stringified_addr, INET_ADDRSTRLEN));
-  EXPECT_STREQ("255.255.255.255", stringified_addr);
-}
-
-TEST(SocketUtilityFunctions, Inet_ntop_ipv6) {
-  char stringified_addr[INET6_ADDRSTRLEN];
-
-  {
-    int addr_tuples[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-    struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
-    EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
-                                  stringified_addr, INET6_ADDRSTRLEN));
-    EXPECT_STREQ("0:0:0:0:0:0:0:0", stringified_addr);
-  }
-
-  {
-    int addr_tuples[8] = { 0x1234, 0xa, 0x12, 0x0000,
-                                0x5678, 0x9abc, 0xdef, 0xffff };
-    struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
-    EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
-                                  stringified_addr, INET6_ADDRSTRLEN));
-    EXPECT_STREQ("1234:a:12:0:5678:9abc:def:ffff", stringified_addr);
-  }
-
-  {
-    int addr_tuples[8] = { 0xffff, 0xffff, 0xffff, 0xffff,
-                                0xffff, 0xffff, 0xffff, 0xffff };
-    struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
-    EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
-                                  stringified_addr, INET6_ADDRSTRLEN));
-    EXPECT_STREQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", stringified_addr);
-  }
-}
-
-TEST(SocketUtilityFunctions, Inet_ntop_failure) {
-  char addr_name[INET6_ADDRSTRLEN];
-  int addr_tuples[8] = { 0xffff, 0xffff, 0xffff, 0xffff,
-                              0xffff, 0xffff, 0xffff, 0xffff };
-  struct in6_addr ipv6_addr = generate_ipv6_addr(addr_tuples);
-  struct in_addr ipv4_addr = generate_ipv4_addr(255,255,255,255);
-
-  EXPECT_TRUE(NULL == inet_ntop(AF_UNIX, &ipv6_addr,
-                                addr_name, INET6_ADDRSTRLEN));
-  EXPECT_EQ(errno, EAFNOSUPPORT);
-
-  EXPECT_TRUE(NULL == inet_ntop(AF_INET, &ipv4_addr,
-                                addr_name, INET_ADDRSTRLEN - 1));
-  EXPECT_EQ(errno, ENOSPC);
-
-  EXPECT_TRUE(NULL == inet_ntop(AF_INET6, &ipv6_addr,
-                                addr_name, INET6_ADDRSTRLEN - 1));
-  EXPECT_EQ(errno, ENOSPC);
-}
-
-TEST(SocketUtilityFunctions, Ntohs) {
-  uint8_t network_bytes[2] = { 0x22, 0x11 };
-  uint16_t network_short;
-  memcpy(&network_short, network_bytes, 2);
-  uint16_t host_short = ntohs(network_short);
-  EXPECT_EQ(host_short, 0x2211);
-}
-
-TEST(SocketUtilityFunctions, Ntohl) {
-  uint8_t network_bytes[4] = { 0x44, 0x33, 0x22, 0x11 };
-  uint32_t network_long;
-  memcpy(&network_long, network_bytes, 4);
-  uint32_t host_long = ntohl(network_long);
-  EXPECT_EQ(host_long, 0x44332211);
-}
-
-#endif  // !defined(__GLIBC__)
-#endif  // PROVIDES_SOCKETPAIR_API
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
index 743dabe..d422cf7 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
@@ -1,6 +1,6 @@
 // Copyright 2013 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.auto
+// found in the LICENSE file.
 
 #include <stdlib.h>
 #include <string.h>
@@ -21,11 +21,11 @@
 #include "ppapi_simple/ps_instance.h"
 #include "ppapi_simple/ps_interface.h"
 
-PSContext2D_t* PSContext2DAllocate() {
+PSContext2D_t* PSContext2DAllocate(PP_ImageDataFormat format) {
   PSContext2D_t* ctx = (PSContext2D_t*) malloc(sizeof(PSContext2D_t));
   memset(ctx, 0, sizeof(PSContext2D_t));
 
-  ctx->format = PSInterfaceImageData()->GetNativeImageDataFormat();
+  ctx->format = format;
   return ctx;
 }
 
@@ -41,6 +41,10 @@
   free(ctx);
 }
 
+PP_ImageDataFormat PSContext2DGetNativeImageDataFormat() {
+  return PSInterfaceImageData()->GetNativeImageDataFormat();
+}
+
 // Update the 2D context if the message is appropriate, returning non-zero
 // if the event was consumed.
 int PSContext2DHandleEvent(PSContext2D_t* ctx, PSEvent* event) {
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
index 30d0cf9..74541ec 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
@@ -34,10 +34,17 @@
  * various PPAPI operations on the developer's behalf, such as processing view
  * change events, swapping buffers, etc...
  */
-PSContext2D_t* PSContext2DAllocate();
+PSContext2D_t* PSContext2DAllocate(PP_ImageDataFormat format);
 void PSContext2DFree(PSContext2D_t* ctx);
 
 /*
+ * PSContext2DGetNativeFormat
+ *
+ * Query the native system image format.
+ */
+PP_ImageDataFormat PSContext2DGetNativeImageDataFormat();
+
+/*
  * PSContext2DHandleEvent
  *
  * Updates the context such as allocating, freeing, or sizing graphics and
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
index 2c073f0..8aa50b9 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
@@ -7,6 +7,7 @@
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -96,7 +97,8 @@
       main_loop_(NULL),
       events_enabled_(PSE_NONE),
       verbosity_(PSV_WARN),
-      fd_tty_(-1) {
+      tty_fd_(-1),
+      tty_prefix_(NULL) {
   // Set the single Instance object
   s_InstanceObject = this;
 
@@ -207,11 +209,19 @@
   int fd2 = open(getenv("PS_STDERR"), O_WRONLY);
   dup2(fd2, 2);
 
-  const char* tty_prefix = getenv("PS_TTY_PREFIX");
-  if (tty_prefix) {
-    fd_tty_ = open("/dev/tty", O_WRONLY);
-    if (fd_tty_ >= 0) {
-      ioctl(fd_tty_, TIOCNACLPREFIX, const_cast<char*>(tty_prefix));
+  tty_prefix_ = getenv("PS_TTY_PREFIX");
+  if (tty_prefix_) {
+    tty_fd_ = open("/dev/tty", O_WRONLY);
+    if (tty_fd_ >= 0) {
+      RegisterMessageHandler(tty_prefix_, MessageHandlerInputStatic, this);
+      const char* tty_resize = getenv("PS_TTY_RESIZE");
+      if (tty_resize)
+        RegisterMessageHandler(tty_resize, MessageHandlerResizeStatic, this);
+
+      tioc_nacl_output handler;
+      handler.handler = TtyOutputHandlerStatic;
+      handler.user_data = this;
+      ioctl(tty_fd_, TIOCNACLOUTPUT, reinterpret_cast<char*>(&handler));
     } else {
       Error("Failed to open /dev/tty.\n");
     }
@@ -310,31 +320,113 @@
   event_queue_.Enqueue(env);
 }
 
+ssize_t PSInstance::TtyOutputHandler(const char* buf, size_t count) {
+  // We prepend the prefix_ to the data in buf, then package it up
+  // and post it as a message to javascript.
+  const char* data = static_cast<const char*>(buf);
+  std::string message = tty_prefix_;
+  message.append(data, count);
+  PostMessage(pp::Var(message));
+  return count;
+}
+
+void PSInstance::MessageHandlerInput(const pp::Var& message) {
+  // Since our message may contain null characters, we can't send it as a
+  // naked C string, so we package it up in this struct before sending it
+  // to the ioctl.
+  assert(message.is_string());
+  std::string buffer = message.AsString();
+
+  struct tioc_nacl_input_string ioctl_message;
+  ioctl_message.length = buffer.size();
+  ioctl_message.buffer = buffer.c_str();
+  int ret =
+    ioctl(tty_fd_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message));
+  if (ret != 0 && errno != ENOTTY) {
+    Error("ioctl returned unexpected error: %d.\n", ret);
+  }
+}
+
+void PSInstance::MessageHandlerResize(const pp::Var& message) {
+  assert(message.is_array());
+  pp::VarArray array(message);
+  assert(array.GetLength() == 2);
+
+  struct winsize size;
+  memset(&size, 0, sizeof(size));
+  size.ws_col = array.Get(0).AsInt();
+  size.ws_row = array.Get(1).AsInt();
+  ioctl(tty_fd_, TIOCSWINSZ, reinterpret_cast<char*>(&size));
+}
+
+ssize_t PSInstance::TtyOutputHandlerStatic(const char* buf,
+                                           size_t count,
+                                           void* user_data) {
+  PSInstance* instance = reinterpret_cast<PSInstance*>(user_data);
+  return instance->TtyOutputHandler(buf, count);
+}
+
+void PSInstance::MessageHandlerInputStatic(const pp::Var& key,
+                                           const pp::Var& value,
+                                           void* user_data) {
+  PSInstance* instance = reinterpret_cast<PSInstance*>(user_data);
+  instance->MessageHandlerInput(value);
+}
+
+void PSInstance::MessageHandlerResizeStatic(const pp::Var& key,
+                                            const pp::Var& value,
+                                            void* user_data) {
+  PSInstance* instance = reinterpret_cast<PSInstance*>(user_data);
+  instance->MessageHandlerResize(value);
+}
+
+void PSInstance::RegisterMessageHandler(std::string message_name,
+                                        MessageHandler_t handler,
+                                        void* user_data) {
+  if (handler == NULL) {
+    message_handlers_.erase(message_name);
+    return;
+  }
+
+  MessageHandler message_handler = { handler, user_data };
+  message_handlers_[message_name] = message_handler;
+}
+
 void PSInstance::PostEvent(PSEventType type, const PP_Var& var) {
   assert(PSE_INSTANCE_HANDLEMESSAGE == type);
 
-  // If the user has specified a tty_prefix_ (using ioctl), then we'll give the
-  // tty node a chance to vacuum up any messages beginning with that prefix. If
-  // the message does not start with the prefix, the ioctl call will return
-  // ENOENT and we'll pass the message through to the event queue.
-  if (fd_tty_ >= 0 && var.type == PP_VARTYPE_STRING) {
-    uint32_t message_len;
-    const char* message = PSInterfaceVar()->VarToUtf8(var, &message_len);
-    std::string message_str(message, message + message_len);
-
-    // Since our message may contain null characters, we can't send it as a
-    // naked C string, so we package it up in this struct before sending it
-    // to the ioctl.
-    struct tioc_nacl_input_string ioctl_message;
-    ioctl_message.length = message_len;
-    ioctl_message.buffer = message_str.data();
-    int ret =
-      ioctl(fd_tty_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message));
-    if (ret != 0 && errno != ENOTTY) {
-      Error("ioctl returned unexpected error: %d.\n", ret);
+  // If the user has specified a tty_prefix_, then filter out the
+  // matching message here and pass them to the tty node via
+  // ioctl() rather then adding them to the event queue.
+  pp::Var event(var);
+  if (tty_fd_ >= 0 && event.is_string()) {
+    std::string message = event.AsString();
+    size_t prefix_len = strlen(tty_prefix_);
+    if (message.size() > prefix_len) {
+      if (!strncmp(message.c_str(), tty_prefix_, prefix_len)) {
+        MessageHandlerInput(pp::Var(message.substr(prefix_len)));
+        return;
+      }
     }
+  }
 
-    return;
+  // If the message is a dictionary then see if it matches one
+  // of the specific handlers, then call that handler rather than
+  // queuing an event.
+  if (tty_fd_ >= 0 && event.is_dictionary()) {
+    pp::VarDictionary dictionary(var);
+    pp::VarArray keys = dictionary.GetKeys();
+    if (keys.GetLength() == 1) {
+      pp::Var key = keys.Get(0);
+      MessageHandlerMap::iterator iter =
+          message_handlers_.find(key.AsString());
+      if (iter != message_handlers_.end()) {
+        MessageHandler_t handler = iter->second.handler;
+        void* user_data = iter->second.user_data;
+        handler(key, dictionary.Get(key), user_data);
+        return;
+      }
+    }
   }
 
   PSInterfaceVar()->AddRef(var);
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
index 2df1550..1829bee 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
@@ -26,6 +26,14 @@
 
 #include "sdk_util/thread_safe_queue.h"
 
+typedef void (*MessageHandler_t)(const pp::Var& key,
+                                 const pp::Var& value,
+                                 void* user_data);
+
+struct MessageHandler {
+  MessageHandler_t handler;
+  void* user_data;
+};
 
 // The basic instance class which also inherits the MouseLock and
 // Graphics3DClient interfaces.
@@ -73,7 +81,37 @@
   PSEvent* WaitAcquireEvent();
   void ReleaseEvent(PSEvent* event);
 
+  // Register a message handler for messages that arrive
+  // from JavaScript with a give names.  Messages are of the
+  // form:  { message_name : <value> }.
+  //
+  // PSInstance will then not generate events but instead
+  // cause the handler to be called upon message arrival.
+  // If handler is NULL then the current handler will be
+  // removed. Example usage:
+  //
+  // JavaScript:
+  //   nacl_module.postMessage({'foo': 123});
+  //
+  // C++:
+  //   void MyMessageHandler(const pp::Var& key,
+  //                         const pp::Var& value,
+  //                         void* user_data) {
+  //     assert(key.is_string());
+  //     assert(key.AsString() == "foo");
+  //     assert(value.is_int());
+  //     assert(value.AsInt() == 123);
+  //   }
+  //   ...
+  //   instance_->RegisterMessageHandler("foo", &MyMessageHandler, NULL);
+  //
+  void RegisterMessageHandler(std::string message_name,
+                              MessageHandler_t handler,
+                              void* user_data);
+
  protected:
+  typedef std::map<std::string, MessageHandler> MessageHandlerMap;
+
   // Callback functions triggered by Pepper
   //
   // These functions are called on the main pepper thread, so they must
@@ -113,6 +151,26 @@
 
  private:
   static void* MainThreadThunk(void *start_info);
+  ssize_t TtyOutputHandler(const char* buf, size_t count);
+  void MessageHandlerInput(const pp::Var& message);
+  void MessageHandlerResize(const pp::Var& message);
+
+  static ssize_t TtyOutputHandlerStatic(const char* buf, size_t count,
+                                        void* user_data);
+
+  /// Handle input message from JavaScript.  The value is
+  /// expected to be of type string.
+  static void MessageHandlerInputStatic(const pp::Var& key,
+                                        const pp::Var& value,
+                                        void* user_data);
+
+
+  /// Handle resizs message from JavaScript.  The value is
+  /// expected to be an array of 2 integers representing the
+  /// number of columns and rows in the TTY.
+  static void MessageHandlerResizeStatic(const pp::Var& key,
+                                         const pp::Var& value,
+                                         void* user_data);
 
  protected:
   pp::MessageLoop* main_loop_;
@@ -120,7 +178,11 @@
   sdk_util::ThreadSafeQueue<PSEvent> event_queue_;
   uint32_t events_enabled_;
   Verbosity verbosity_;
-  int fd_tty_;
+
+  // TTY handling
+  int tty_fd_;
+  const char* tty_prefix_;
+  MessageHandlerMap message_handlers_;
 
   PSMainFunc_t main_cb_;
 
diff --git a/native_client_sdk/src/libraries/sdk_util/auto_lock.h b/native_client_sdk/src/libraries/sdk_util/auto_lock.h
index b489269..b969416 100644
--- a/native_client_sdk/src/libraries/sdk_util/auto_lock.h
+++ b/native_client_sdk/src/libraries/sdk_util/auto_lock.h
@@ -24,7 +24,7 @@
   }
 
   ~AutoLock() {
-    if (lock_) pthread_mutex_unlock(lock_);
+    Unlock();
   }
 
   void Unlock() {
diff --git a/native_client_sdk/src/libraries/third_party/newlib-extras/sys/signal.h b/native_client_sdk/src/libraries/third_party/newlib-extras/sys/signal.h
new file mode 100644
index 0000000..36093b6
--- /dev/null
+++ b/native_client_sdk/src/libraries/third_party/newlib-extras/sys/signal.h
@@ -0,0 +1,311 @@
+/* sys/signal.h */
+
+#ifndef _SYS_SIGNAL_H
+#define _SYS_SIGNAL_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "_ansi.h"
+#include <sys/features.h>
+#include <sys/types.h>
+
+/* #ifndef __STRICT_ANSI__*/
+
+typedef unsigned long sigset_t;
+
+#if defined(__rtems__)
+
+#if defined(_POSIX_REALTIME_SIGNALS)
+
+/* sigev_notify values
+   NOTE: P1003.1c/D10, p. 34 adds SIGEV_THREAD.  */
+
+#define SIGEV_NONE   1  /* No asynchronous notification shall be delivered */
+                        /*   when the event of interest occurs. */
+#define SIGEV_SIGNAL 2  /* A queued signal, with an application defined */
+                        /*  value, shall be delivered when the event of */
+                        /*  interest occurs. */
+#define SIGEV_THREAD 3  /* A notification function shall be called to */
+                        /*   perform notification. */
+
+/*  Signal Generation and Delivery, P1003.1b-1993, p. 63
+    NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and
+          sigev_notify_attributes to the sigevent structure.  */
+
+union sigval {
+  int    sival_int;    /* Integer signal value */
+  void  *sival_ptr;    /* Pointer signal value */
+};
+
+struct sigevent {
+  int              sigev_notify;               /* Notification type */
+  int              sigev_signo;                /* Signal number */
+  union sigval     sigev_value;                /* Signal value */
+
+#if defined(_POSIX_THREADS)
+  void           (*sigev_notify_function)( union sigval );
+                                               /* Notification function */
+  pthread_attr_t  *sigev_notify_attributes;    /* Notification Attributes */
+#endif
+};
+
+/* Signal Actions, P1003.1b-1993, p. 64 */
+/* si_code values, p. 66 */
+
+#define SI_USER    1    /* Sent by a user. kill(), abort(), etc */
+#define SI_QUEUE   2    /* Sent by sigqueue() */
+#define SI_TIMER   3    /* Sent by expiration of a timer_settime() timer */
+#define SI_ASYNCIO 4    /* Indicates completion of asycnhronous IO */
+#define SI_MESGQ   5    /* Indicates arrival of a message at an empty queue */
+
+typedef struct {
+  int          si_signo;    /* Signal number */
+  int          si_code;     /* Cause of the signal */
+  union sigval si_value;    /* Signal value */
+} siginfo_t;
+#endif
+
+/*  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 */
+
+#define SA_NOCLDSTOP 1   /* Do not generate SIGCHLD when children stop */
+#define SA_SIGINFO   2   /* Invoke the signal catching function with */
+                         /*   three arguments instead of one. */
+
+/* struct sigaction notes from POSIX:
+ *
+ *  (1) Routines stored in sa_handler should take a single int as
+ *      their argument although the POSIX standard does not require this.
+ *      This is not longer true since at least POSIX.1-2008
+ *  (2) The fields sa_handler and sa_sigaction may overlap, and a conforming
+ *      application should not use both simultaneously.
+ */
+
+typedef void (*_sig_func_ptr)(int);
+
+struct sigaction {
+  int         sa_flags;       /* Special flags to affect behavior of signal */
+  sigset_t    sa_mask;        /* Additional set of signals to be blocked */
+                              /*   during execution of signal-catching */
+                              /*   function. */
+  union {
+    _sig_func_ptr _handler;  /* SIG_DFL, SIG_IGN, or pointer to a function */
+#if defined(_POSIX_REALTIME_SIGNALS)
+    void      (*_sigaction)( int, siginfo_t *, void * );
+#endif
+  } _signal_handlers;
+};
+
+#define sa_handler    _signal_handlers._handler
+#if defined(_POSIX_REALTIME_SIGNALS)
+#define sa_sigaction  _signal_handlers._sigaction
+#endif
+
+#elif defined(__CYGWIN__)
+#include <cygwin/signal.h>
+#else
+#define SA_NOCLDSTOP 1  /* only value supported now for sa_flags */
+
+typedef void (*_sig_func_ptr)(int);
+
+struct sigaction 
+{
+	_sig_func_ptr sa_handler;
+	sigset_t sa_mask;
+	int sa_flags;
+};
+#endif /* defined(__rtems__) */
+
+#define SIG_SETMASK 0	/* set mask with sigprocmask() */
+#define SIG_BLOCK 1	/* set of signals to block */
+#define SIG_UNBLOCK 2	/* set of signals to, well, unblock */
+
+/* These depend upon the type of sigset_t, which right now 
+   is always a long.. They're in the POSIX namespace, but
+   are not ANSI. */
+#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0)
+#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0)
+#define sigemptyset(what)   (*(what) = 0, 0)
+#define sigfillset(what)    (*(what) = ~(0), 0)
+#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0)
+
+int _EXFUN(sigprocmask, (int how, const sigset_t *set, sigset_t *oset));
+
+#if defined(_POSIX_THREADS)
+int _EXFUN(pthread_sigmask, (int how, const sigset_t *set, sigset_t *oset));
+#endif
+
+/* protos for functions found in winsup sources for CYGWIN */
+#if defined(__CYGWIN__) || defined(__rtems__) || defined (__native_client__)
+#undef sigaddset
+#undef sigdelset
+#undef sigemptyset
+#undef sigfillset
+#undef sigismember
+
+int _EXFUN(kill, (pid_t, int));
+int _EXFUN(killpg, (pid_t, int));
+int _EXFUN(sigaction, (int, const struct sigaction *, struct sigaction *));
+int _EXFUN(sigaddset, (sigset_t *, const int));
+int _EXFUN(sigdelset, (sigset_t *, const int));
+int _EXFUN(sigismember, (const sigset_t *, int));
+int _EXFUN(sigfillset, (sigset_t *));
+int _EXFUN(sigemptyset, (sigset_t *));
+int _EXFUN(sigpending, (sigset_t *));
+int _EXFUN(sigsuspend, (const sigset_t *));
+int _EXFUN(sigpause, (int));
+
+#if defined(_POSIX_THREADS)
+#ifdef __CYGWIN__
+#  ifndef _CYGWIN_TYPES_H
+#    error You need the winsup sources or a cygwin installation to compile the cygwin version of newlib.
+#  endif
+#endif
+int _EXFUN(pthread_kill, (pthread_t thread, int sig));
+#endif
+
+#if defined(_POSIX_REALTIME_SIGNALS)
+
+/*  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
+    NOTE: P1003.1c/D10, p. 39 adds sigwait().  */
+
+int _EXFUN(sigwaitinfo, (const sigset_t *set, siginfo_t *info));
+int _EXFUN(sigtimedwait,
+  (const sigset_t *set, siginfo_t *info, const struct timespec  *timeout)
+);
+int _EXFUN(sigwait, (const sigset_t *set, int *sig));
+
+/*  3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78 */
+int _EXFUN(sigqueue, (pid_t pid, int signo, const union sigval value));
+
+#endif /* defined(_POSIX_REALTIME_SIGNALS) */
+
+#endif /* defined(__CYGWIN__) || defined(__rtems__) */
+
+/* #endif __STRICT_ANSI__ */
+
+#if defined(___AM29K__)
+/* These all need to be defined for ANSI C, but I don't think they are
+   meaningful.  */
+#define SIGABRT 1
+#define SIGFPE 1
+#define SIGILL 1
+#define SIGINT 1
+#define SIGSEGV 1
+#define SIGTERM 1
+/* These need to be defined for POSIX, and some others do too.  */
+#define SIGHUP 1
+#define SIGQUIT 1
+#define NSIG 2
+#elif defined(__GO32__)
+#define SIGINT  1
+#define SIGKILL 2
+#define SIGPIPE 3
+#define SIGFPE  4
+#define SIGHUP  5
+#define SIGTERM 6
+#define SIGSEGV 7
+#define SIGTSTP 8
+#define SIGQUIT 9
+#define SIGTRAP 10
+#define SIGILL  11
+#define SIGEMT  12
+#define SIGALRM 13
+#define SIGBUS  14
+#define SIGLOST 15
+#define SIGSTOP 16
+#define SIGABRT 17
+#define SIGUSR1	18
+#define SIGUSR2	19
+#define NSIG    20
+#elif !defined(SIGTRAP)
+#define	SIGHUP	1	/* hangup */
+#define	SIGINT	2	/* interrupt */
+#define	SIGQUIT	3	/* quit */
+#define	SIGILL	4	/* illegal instruction (not reset when caught) */
+#define	SIGTRAP	5	/* trace trap (not reset when caught) */
+#define	SIGIOT	6	/* IOT instruction */
+#define	SIGABRT 6	/* used by abort, replace SIGIOT in the future */
+#define	SIGEMT	7	/* EMT instruction */
+#define	SIGFPE	8	/* floating point exception */
+#define	SIGKILL	9	/* kill (cannot be caught or ignored) */
+#define	SIGBUS	10	/* bus error */
+#define	SIGSEGV	11	/* segmentation violation */
+#define	SIGSYS	12	/* bad argument to system call */
+#define	SIGPIPE	13	/* write on a pipe with no one to read it */
+#define	SIGALRM	14	/* alarm clock */
+#define	SIGTERM	15	/* software termination signal from kill */
+
+#if defined(__rtems__)
+#define	SIGURG	16	/* urgent condition on IO channel */
+#define	SIGSTOP	17	/* sendable stop signal not from tty */
+#define	SIGTSTP	18	/* stop signal from tty */
+#define	SIGCONT	19	/* continue a stopped process */
+#define	SIGCHLD	20	/* to parent on child stop or exit */
+#define	SIGCLD	20	/* System V name for SIGCHLD */
+#define	SIGTTIN	21	/* to readers pgrp upon background tty read */
+#define	SIGTTOU	22	/* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define	SIGIO	23	/* input/output possible signal */
+#define	SIGPOLL	SIGIO	/* System V name for SIGIO */
+#define	SIGWINCH 24	/* window changed */
+#define	SIGUSR1 25	/* user defined signal 1 */
+#define	SIGUSR2 26	/* user defined signal 2 */
+
+/* Real-Time Signals Range, P1003.1b-1993, p. 61
+   NOTE: By P1003.1b-1993, this should be at least RTSIG_MAX
+         (which is a minimum of 8) signals.
+ */
+#define SIGRTMIN 27
+#define SIGRTMAX 31
+#define __SIGFIRSTNOTRT SIGHUP
+#define __SIGLASTNOTRT  SIGUSR2
+
+#define NSIG	32      /* signal 0 implied */
+
+#elif defined(__svr4__)
+/* svr4 specifics. different signals above 15, and sigaction. */
+#define	SIGUSR1	16
+#define SIGUSR2	17
+#define SIGCLD	18
+#define	SIGPWR	19
+#define SIGWINCH 20
+#define	SIGPOLL	22	/* 20 for x.out binaries!!!! */
+#define	SIGSTOP	23	/* sendable stop signal not from tty */
+#define	SIGTSTP	24	/* stop signal from tty */
+#define	SIGCONT	25	/* continue a stopped process */
+#define	SIGTTIN	26	/* to readers pgrp upon background tty read */
+#define	SIGTTOU	27	/* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define NSIG	28	
+#else
+#define	SIGURG	16	/* urgent condition on IO channel */
+#define	SIGSTOP	17	/* sendable stop signal not from tty */
+#define	SIGTSTP	18	/* stop signal from tty */
+#define	SIGCONT	19	/* continue a stopped process */
+#define	SIGCHLD	20	/* to parent on child stop or exit */
+#define	SIGCLD	20	/* System V name for SIGCHLD */
+#define	SIGTTIN	21	/* to readers pgrp upon background tty read */
+#define	SIGTTOU	22	/* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define	SIGIO	23	/* input/output possible signal */
+#define	SIGPOLL	SIGIO	/* System V name for SIGIO */
+#define	SIGXCPU	24	/* exceeded CPU time limit */
+#define	SIGXFSZ	25	/* exceeded file size limit */
+#define	SIGVTALRM 26	/* virtual time alarm */
+#define	SIGPROF	27	/* profiling time alarm */
+#define	SIGWINCH 28	/* window changed */
+#define	SIGLOST 29	/* resource lost (eg, record-lock lost) */
+#define	SIGUSR1 30	/* user defined signal 1 */
+#define	SIGUSR2 31	/* user defined signal 2 */
+#define NSIG	32      /* signal 0 implied */
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef _SIGNAL_H_
+/* Some applications take advantage of the fact that <sys/signal.h>
+ * and <signal.h> are equivalent in glibc.  Allow for that here.  */
+#include <signal.h>
+#endif
+#endif /* _SYS_SIGNAL_H */
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/event_test.cc b/native_client_sdk/src/tests/nacl_io_socket_test/event_test.cc
new file mode 100644
index 0000000..7a854d7
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/event_test.cc
@@ -0,0 +1,480 @@
+/* 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "gtest/gtest.h"
+
+#include "nacl_io/event_emitter.h"
+#include "nacl_io/event_listener.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/kernel_wrap.h"
+
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+class EventEmitterTester : public MountNode {
+ public:
+  EventEmitterTester() : MountNode(NULL), event_status_(0), event_cnt_(0) {}
+
+  void SetEventStatus(uint32_t bits) { event_status_ = bits; }
+  uint32_t GetEventStatus() { return event_status_; }
+
+  Error Ioctl(int request, char* arg) {
+    event_status_ = static_cast<uint32_t>(request);
+    return 0;
+  }
+
+  int GetType() { return S_IFSOCK; }
+  int NumEvents() { return event_cnt_; }
+
+ public:
+  // Make this function public for testing
+  void RaiseEvent(uint32_t events) {
+    EventEmitter::RaiseEvent(events);
+  }
+
+    // Called after registering locally, but while lock is still held.
+  void ChainRegisterEventInfo(const ScopedEventInfo& event) {
+    event_cnt_++;
+  }
+
+  // Called before unregistering locally, but while lock is still held.
+  void ChainUnregisterEventInfo(const ScopedEventInfo& event) {
+    event_cnt_--;
+  }
+
+ protected:
+  uint32_t event_status_;
+  uint32_t event_cnt_;
+};
+
+
+const int MAX_EVENTS = 8;
+
+// IDs for Emitters
+const int ID_EMITTER = 5;
+const int ID_LISTENER = 6;
+const int ID_EMITTER_DUP = 7;
+
+// Kernel Event values
+const uint32_t KE_EXPECTED = 4;
+const uint32_t KE_FILTERED = 2;
+const uint32_t KE_NONE = 0;
+
+// User Data values
+const uint64_t USER_DATA_A = 1;
+const uint64_t USER_DATA_B = 5;
+
+// Timeout durations
+const int TIMEOUT_IMMEDIATE = 0;
+const int TIMEOUT_SHORT= 100;
+const int TIMEOUT_LONG = 500;
+const int TIMEOUT_NEVER = -1;
+const int TIMEOUT_VERY_LONG = 1000;
+
+// We subtract TIMEOUT_SLOP from the expected minimum timed due to rounding
+// and clock drift converting between absolute and relative time.  This should
+// only be 1 for Less Than, and 1 for rounding, but we use 10 since we don't
+// care about real precision, aren't testing of the underlying
+// implementations and don't want flakiness.
+const int TIMEOUT_SLOP = 10;
+
+TEST(EventTest, EmitterBasic) {
+  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+  ScopedRef<EventEmitter> null_emitter;
+
+  ScopedEventListener listener(new EventListener);
+
+  // Verify construction
+  EXPECT_EQ(0, emitter->NumEvents());
+  EXPECT_EQ(0, emitter->GetEventStatus());
+
+  // Verify status
+  emitter->SetEventStatus(KE_EXPECTED);
+  EXPECT_EQ(KE_EXPECTED, emitter->GetEventStatus());
+
+  // Fail to update or free an ID not in the set
+  EXPECT_EQ(ENOENT, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
+  EXPECT_EQ(ENOENT, listener->Free(ID_EMITTER));
+
+  // Fail to Track self
+  EXPECT_EQ(EINVAL, listener->Track(ID_LISTENER,
+                                    listener,
+                                    KE_EXPECTED,
+                                    USER_DATA_A));
+
+  // Set the emitter filter and data
+  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+  EXPECT_EQ(1, emitter->NumEvents());
+
+  // Fail to add the same ID
+  EXPECT_EQ(EEXIST,
+            listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+  EXPECT_EQ(1, emitter->NumEvents());
+
+  int event_cnt = 0;
+  EventData ev[MAX_EVENTS];
+
+  // Do not allow a wait with a zero events count.
+  EXPECT_EQ(EINVAL, listener->Wait(ev, 0, TIMEOUT_IMMEDIATE, &event_cnt));
+
+  // Do not allow a wait with a negative events count.
+  EXPECT_EQ(EINVAL, listener->Wait(ev, -1, TIMEOUT_IMMEDIATE, &event_cnt));
+
+  // Do not allow a wait with a NULL EventData pointer
+  EXPECT_EQ(EFAULT,
+            listener->Wait(NULL, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+
+  // Return with no events if the Emitter has no signals set.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_NONE);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(0, event_cnt);
+
+  // Return with no events if the Emitter has a filtered signals set.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_FILTERED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(0, event_cnt);
+
+  // Return with one event if the Emitter has the expected signal set.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_EXPECTED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(1, event_cnt);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+  // Return with one event containing only the expected signal.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(1, event_cnt);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+  // Change the USER_DATA on an existing event
+  EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_B));
+
+  // Return with one event signaled with the alternate USER DATA
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, 0, &event_cnt));
+  EXPECT_EQ(1, event_cnt);
+  EXPECT_EQ(USER_DATA_B, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+  // Reset the USER_DATA.
+  EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
+
+  // Support adding a DUP.
+  EXPECT_EQ(0, listener->Track(ID_EMITTER_DUP,
+                               emitter,
+                               KE_EXPECTED,
+                               USER_DATA_A));
+  EXPECT_EQ(2, emitter->NumEvents());
+
+  // Return unsignaled.
+  memset(ev, 0, sizeof(ev));
+  emitter->SetEventStatus(KE_NONE);
+  event_cnt = 100;
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(0, event_cnt);
+
+  // Return with two event signaled with expected data.
+  memset(ev, 0, sizeof(ev));
+  emitter->SetEventStatus(KE_EXPECTED);
+  event_cnt = 100;
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(2, event_cnt);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_EQ(USER_DATA_A, ev[1].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[1].events);
+}
+
+long Duration(struct timeval* start, struct timeval* end) {
+  if (start->tv_usec > end->tv_usec) {
+    end->tv_sec -= 1;
+    end->tv_usec += 1000000;
+  }
+  long cur_time = 1000 * (end->tv_sec - start->tv_sec);
+  cur_time += (end->tv_usec - start->tv_usec) / 1000;
+  return cur_time;
+}
+
+
+// Run a timed wait, and return the average of 8 iterations to reduce
+// chance of false negative on outlier.
+const int TRIES_TO_AVERAGE = 8;
+bool TimedListen(ScopedEventListener& listen,
+                 EventData* ev,
+                 int ev_max,
+                 int ev_expect,
+                 int ms_wait,
+                 long* duration) {
+
+  struct timeval start;
+  struct timeval end;
+  long total_time = 0;
+
+  for (int a=0; a < TRIES_TO_AVERAGE; a++) {
+    gettimeofday(&start, NULL);
+
+    int signaled;
+
+    EXPECT_EQ(0, listen->Wait(ev, ev_max, ms_wait, &signaled));
+    EXPECT_EQ(signaled, ev_expect);
+
+    if (signaled != ev_expect) {
+      return false;
+    }
+
+    gettimeofday(&end, NULL);
+
+    long cur_time = Duration(&start, &end);
+    total_time += cur_time;
+  }
+
+  *duration = total_time / TRIES_TO_AVERAGE;
+  return true;
+}
+
+
+// NOTE:  These timing tests are potentially flaky, the real test is
+// for the zero timeout should be, has the ConditionVariable been waited on?
+// Once we provide a debuggable SimpleCond and SimpleLock we can actually test
+// the correct thing.
+
+// Normal scheduling would expect us to see ~10ms accuracy, but we'll
+// use a much bigger number (yet smaller than the MAX_MS_TIMEOUT).
+const int SCHEDULING_GRANULARITY = 100;
+
+const int EXPECT_ONE_EVENT = 1;
+const int EXPECT_NO_EVENT = 0;
+
+TEST(EventTest, EmitterTimeout) {
+  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+  ScopedEventListener listener(new EventListener());
+  long duration;
+
+  EventData ev[MAX_EVENTS];
+  memset(ev, 0, sizeof(ev));
+  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+
+  // Return immediately when emitter is signaled, with no timeout
+  emitter->SetEventStatus(KE_EXPECTED);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+                          TIMEOUT_IMMEDIATE, &duration));
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_EQ(0, duration);
+
+  // Return immediately when emitter is signaled, even with timeout
+  emitter->SetEventStatus(KE_EXPECTED);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+                          TIMEOUT_LONG, &duration));
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_GT(SCHEDULING_GRANULARITY, duration);
+
+  // Return immediately if Emiiter is already signaled when blocking forever.
+  emitter->SetEventStatus(KE_EXPECTED);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+                          TIMEOUT_NEVER, &duration));
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_GT(SCHEDULING_GRANULARITY, duration);
+
+  // Return immediately if Emitter is no signaled when not blocking.
+  emitter->SetEventStatus(KE_NONE);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
+                          TIMEOUT_IMMEDIATE, &duration));
+  EXPECT_EQ(0, duration);
+
+  // Wait TIMEOUT_LONG if the emitter is not in a signaled state.
+  emitter->SetEventStatus(KE_NONE);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
+                          TIMEOUT_LONG, &duration));
+  EXPECT_LT(TIMEOUT_LONG - TIMEOUT_SLOP, duration);
+  EXPECT_GT(TIMEOUT_LONG + SCHEDULING_GRANULARITY, duration);
+}
+
+struct SignalInfo {
+  EventEmitterTester* em;
+  unsigned int ms_wait;
+  uint32_t events;
+};
+
+static void *SignalEmitterThread(void *ptr) {
+  SignalInfo* info = (SignalInfo*) ptr;
+  struct timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = info->ms_wait * 1000000;
+
+  nanosleep(&ts, NULL);
+
+  info->em->RaiseEvent(info->events);
+  return NULL;
+}
+
+TEST(EventTest, EmitterSignalling) {
+  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+  ScopedEventListener listener(new EventListener);
+
+  SignalInfo siginfo;
+  struct timeval start;
+  struct timeval end;
+  long duration;
+
+  EventData ev[MAX_EVENTS];
+  memset(ev, 0, sizeof(ev));
+  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+
+  // Setup another thread to wait 1/4 of the max time, and signal both
+  // an expected, and unexpected value.
+  siginfo.em = emitter.get();
+  siginfo.ms_wait = TIMEOUT_SHORT;
+  siginfo.events = KE_EXPECTED | KE_FILTERED;
+  pthread_t tid;
+  pthread_create(&tid, NULL, SignalEmitterThread, &siginfo);
+
+  // Wait for the signal from the other thread and time it.
+  gettimeofday(&start, NULL);
+  int cnt = 0;
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_VERY_LONG, &cnt));
+  EXPECT_EQ(1, cnt);
+  gettimeofday(&end, NULL);
+
+  // Verify the wait duration, and that we only recieved the expected signal.
+  duration = Duration(&start, &end);
+  EXPECT_GT(TIMEOUT_SHORT + SCHEDULING_GRANULARITY, duration);
+  EXPECT_LT(TIMEOUT_SHORT - TIMEOUT_SLOP, duration);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+}
+
+
+namespace {
+
+class KernelProxyPolling : public KernelProxy {
+ public:
+  virtual int socket(int domain, int type, int protocol) {
+    ScopedMount mnt;
+    ScopedMountNode node(new EventEmitterTester());
+    ScopedKernelHandle handle(new KernelHandle(mnt, node));
+
+    Error error = handle->Init(0);
+    if (error) {
+      errno = error;
+      return -1;
+    }
+
+    return AllocateFD(handle);
+  }
+};
+
+class KernelProxyPollingTest : public ::testing::Test {
+ public:
+  KernelProxyPollingTest() : kp_(new KernelProxyPolling) {
+    ki_init(kp_);
+  }
+
+  ~KernelProxyPollingTest() {
+    ki_uninit();
+    delete kp_;
+  }
+
+  KernelProxyPolling* kp_;
+};
+
+}  // namespace
+
+
+#define SOCKET_CNT 4
+void SetFDs(fd_set* set, int* fds) {
+  FD_ZERO(set);
+
+  FD_SET(0, set);
+  FD_SET(1, set);
+  FD_SET(2, set);
+
+  for (int index = 0; index < SOCKET_CNT; index++)
+    FD_SET(fds[index], set);
+}
+
+TEST_F(KernelProxyPollingTest, Select) {
+  int fds[SOCKET_CNT];
+
+  fd_set rd_set;
+  fd_set wr_set;
+
+  FD_ZERO(&rd_set);
+  FD_ZERO(&wr_set);
+
+  FD_SET(0, &rd_set);
+  FD_SET(1, &rd_set);
+  FD_SET(2, &rd_set);
+
+  FD_SET(0, &wr_set);
+  FD_SET(1, &wr_set);
+  FD_SET(2, &wr_set);
+
+  // Expect normal files to select as read, write, and error
+  int cnt = select(4, &rd_set, &rd_set, &rd_set, NULL);
+  EXPECT_EQ(3 * 3, cnt);
+  EXPECT_NE(0, FD_ISSET(0, &rd_set));
+  EXPECT_NE(0, FD_ISSET(1, &rd_set));
+  EXPECT_NE(0, FD_ISSET(2, &rd_set));
+
+  for (int index = 0 ; index < SOCKET_CNT; index++) {
+    fds[index] = socket(0, 0, 0);
+    EXPECT_NE(-1, fds[index]);
+  }
+
+  // Highest numbered fd
+  const int fdnum = fds[SOCKET_CNT - 1] + 1;
+
+  // Expect only the normal files to select
+  SetFDs(&rd_set, fds);
+  cnt = select(fds[SOCKET_CNT-1] + 1, &rd_set, NULL, NULL, NULL);
+  EXPECT_EQ(3, cnt);
+  EXPECT_NE(0, FD_ISSET(0, &rd_set));
+  EXPECT_NE(0, FD_ISSET(1, &rd_set));
+  EXPECT_NE(0, FD_ISSET(2, &rd_set));
+  for (int index = 0 ; index < SOCKET_CNT; index++) {
+    EXPECT_EQ(0, FD_ISSET(fds[index], &rd_set));
+  }
+
+  // Poke one of the pollable nodes to be READ ready
+  ioctl(fds[0], POLLIN, NULL);
+
+  // Expect normal files to be read/write and one pollable node to be read.
+  SetFDs(&rd_set, fds);
+  SetFDs(&wr_set, fds);
+  cnt = select(fdnum, &rd_set, &wr_set, NULL, NULL);
+  EXPECT_EQ(7, cnt);
+  EXPECT_NE(0, FD_ISSET(fds[0], &rd_set));
+  EXPECT_EQ(0, FD_ISSET(fds[0], &wr_set));
+}
+
+
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc b/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc
new file mode 100644
index 0000000..6340d66
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc
@@ -0,0 +1,37 @@
+{
+  'TOOLS': ['newlib', 'glibc', 'pnacl'],
+
+  # Need to add ../../examples for common.js
+  'SEARCH': ['.', '../../examples'],
+  'TARGETS': [
+    {
+      'NAME' : 'nacl_io_socket_test',
+      'TYPE' : 'main',
+      'SOURCES' : [
+        'main.cc',
+        'socket_test.cc',
+      ],
+      'DEPS': ['ppapi_simple', 'nacl_io'],
+      # Order matters here: gtest has a "main" function that will be used if
+      # referenced before ppapi.
+      'LIBS': ['gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
+      'INCLUDES': ['$(NACL_SDK_ROOT)/include/gtest/internal'],
+      'CXXFLAGS': ['-Wno-sign-compare', '-Wno-unused-private-field'],
+      'CFLAGS_GCC': ['-Wno-unused-local-typedefs'],
+    }
+  ],
+  'DATA': [
+    'example.js'
+  ],
+  'DEST': 'tests',
+  'NAME': 'nacl_io_socket_test',
+  'TITLE': 'NaCl IO Socket test',
+  'PRE': '''\nCHROME_ARGS = --allow-nacl-socket-api=localhost\n''',
+  'SOCKET_PERMISSIONS': [
+    "tcp-listen:*:*",
+    "tcp-connect",
+    "resolve-host",
+    "udp-bind:*:*",
+    "udp-send-to:*:*"
+  ]
+}
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/example.js b/native_client_sdk/src/tests/nacl_io_socket_test/example.js
new file mode 100644
index 0000000..1a6a8bf
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/example.js
@@ -0,0 +1,126 @@
+// 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.
+// Called by the common.js module.
+
+function runTCPEchoServer(port) {
+  console.log("Starting server on TCP port: " + port);
+  chrome.socket.create("tcp", {}, function(createInfo) {
+    var listeningSocket = createInfo.socketId;
+    chrome.socket.listen(listeningSocket,
+                         '127.0.0.1',
+                         port,
+                         10,
+                         function(result) {
+      if (result !== 0) {
+        console.log("Listen failed: " + result);
+        return;
+      }
+
+      chrome.socket.accept(listeningSocket, function(acceptInfo) {
+        if (result !== 0) {
+          console.log("Accept failed: " + result);
+          return;
+        }
+
+        var newSock = acceptInfo.socketId;
+
+        var readCallback = function(readInfo) {
+          if (readInfo.resultCode < 0) {
+            console.log("Read failed: " + readInfo.resultCode);
+            chrome.socket.destroy(newSock);
+            return;
+          }
+
+          chrome.socket.write(newSock, readInfo.data, function(writeInfo) {})
+          chrome.socket.read(newSock, readCallback);
+        }
+
+        chrome.socket.read(newSock, readCallback);
+      })
+    })
+  })
+}
+
+function moduleDidLoad() {
+  // The module is not hidden by default so we can easily see if the plugin
+  // failed to load.
+  common.hideModule();
+  runTCPEchoServer(4006);
+}
+
+var currentTestEl = null;
+
+function startCommand(testName) {
+  var testListEl = document.getElementById('tests');
+  var testEl = document.createElement('li');
+  var testRowEl = document.createElement('div');
+  var testNameEl = document.createElement('span');
+  var testResultEl = document.createElement('span');
+  testRowEl.classList.add('row');
+  testNameEl.classList.add('name');
+  testNameEl.textContent = testName;
+  testResultEl.classList.add('result');
+  testRowEl.appendChild(testNameEl);
+  testRowEl.appendChild(testResultEl);
+  testEl.appendChild(testRowEl);
+  testListEl.appendChild(testEl);
+
+  currentTestEl = testEl;
+}
+
+function failCommand(fileName, lineNumber, summary) {
+  var testMessageEl = document.createElement('pre');
+  testMessageEl.textContent += fileName + ':' + lineNumber + ': ' + summary;
+  currentTestEl.appendChild(testMessageEl);
+}
+
+function endCommand(testName, testResult) {
+  var testRowEl = currentTestEl.querySelector('.row');
+  var testResultEl = currentTestEl.querySelector('.result');
+  testRowEl.classList.add(testResult);
+  testResultEl.textContent = testResult;
+}
+
+function handleMessage(event) {
+  var msg = event.data;
+  var firstColon = msg.indexOf(':');
+  var cmd = msg.substr(0, firstColon);
+  var cmdFunctionName = cmd + 'Command';
+  var cmdFunction = window[cmdFunctionName];
+
+  if (typeof(cmdFunction) !== 'function') {
+    console.log('Unknown command: ' + cmd);
+    console.log('  message: ' + msg);
+    return;
+  }
+
+  var argCount = cmdFunction.length;
+
+  // Don't use split, because it will split all commas (for example any commas
+  // in the test failure summary).
+  var argList = msg.substr(firstColon + 1);
+  args = [];
+  for (var i = 0; i < argCount - 1; ++i) {
+    var arg;
+    var comma = argList.indexOf(',');
+    if (comma === -1) {
+      if (i !== argCount - 1) {
+        console.log('Bad arg count to command "' + cmd + '", expected ' +
+                    argCount);
+        console.log('  message: ' + msg);
+      } else {
+        arg = argList;
+      }
+    } else {
+      arg = argList.substr(0, comma);
+      argList = argList.substr(comma + 1);
+    }
+    args.push(arg);
+  }
+
+  // Last argument is the rest of the message.
+  args.push(argList);
+
+  cmdFunction.apply(null, args);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/index.html b/native_client_sdk/src/tests/nacl_io_socket_test/index.html
similarity index 100%
copy from native_client_sdk/src/libraries/nacl_io_test/index.html
copy to native_client_sdk/src/tests/nacl_io_socket_test/index.html
diff --git a/native_client_sdk/src/libraries/nacl_io_test/main.cc b/native_client_sdk/src/tests/nacl_io_socket_test/main.cc
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/main.cc
rename to native_client_sdk/src/tests/nacl_io_socket_test/main.cc
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
new file mode 100644
index 0000000..fe22ae1
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.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 <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <map>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/ossocket.h"
+#include "nacl_io/ostypes.h"
+
+#ifdef PROVIDES_SOCKET_API
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+// No error expected
+#define ENONE 0
+#define LOCAL_HOST 0x7F000001
+#define PORT1 4006
+#define PORT2 4007
+#define ANY_PORT 0
+
+
+namespace {
+class SocketTest : public ::testing::Test {
+ public:
+  SocketTest() : sock1(0), sock2(0) {}
+
+  ~SocketTest() {
+    EXPECT_EQ(0, close(sock1));
+    EXPECT_EQ(0, close(sock2));
+  }
+
+  void IP4ToSockAddr(uint32_t ip, uint16_t port, struct sockaddr_in* addr) {
+    memset(addr, 0, sizeof(*addr));
+
+    addr->sin_family = AF_INET;
+    addr->sin_port = htons(port);
+    addr->sin_addr.s_addr = htonl(ip);
+  }
+
+  int Bind(int fd, uint32_t ip, uint16_t port) {
+    sockaddr_in addr;
+    socklen_t addrlen = sizeof(addr);
+
+    IP4ToSockAddr(ip, port, &addr);
+    int err = bind(fd, (sockaddr*) &addr, addrlen);
+
+    if (err == -1)
+      return errno;
+    return 0;
+  }
+
+  void SetupPorts() {
+    EXPECT_EQ(Bind(sock1, LOCAL_HOST, 0), ENONE);
+    EXPECT_EQ(Bind(sock2, LOCAL_HOST, 0), ENONE);
+  }
+
+ public:
+  int sock1;
+  int sock2;
+};
+
+class SocketTestUDP : public SocketTest {
+ public:
+  SocketTestUDP() {
+    sock1 = socket(AF_INET, SOCK_DGRAM, 0);
+    sock2 = socket(AF_INET, SOCK_DGRAM, 0);
+
+    EXPECT_LT(-1, sock1);
+    EXPECT_LT(-1, sock2);
+  }
+};
+
+class SocketTestTCP : public SocketTest {
+ public:
+  SocketTestTCP() {
+    sock1 = socket(AF_INET, SOCK_STREAM, 0);
+    sock2 = socket(AF_INET, SOCK_STREAM, 0);
+
+    EXPECT_LT(-1, sock1);
+    EXPECT_LT(-1, sock2);
+  }
+};
+
+}  // namespace
+
+TEST(SocketTestSimple, Socket) {
+  EXPECT_EQ(-1, socket(AF_UNIX, SOCK_STREAM, 0));
+  EXPECT_EQ(errno, EAFNOSUPPORT);
+  EXPECT_EQ(-1, socket(AF_INET, SOCK_RAW, 0));
+  EXPECT_EQ(errno, EPROTONOSUPPORT);
+
+  int sock1 = socket(AF_INET, SOCK_DGRAM, 0);
+  EXPECT_NE(-1, sock1);
+
+  int sock2 = socket(AF_INET6, SOCK_DGRAM, 0);
+  EXPECT_NE(-1, sock2);
+
+  int sock3 = socket(AF_INET, SOCK_STREAM, 0);
+  EXPECT_NE(-1, sock3);
+
+  int sock4 = socket(AF_INET6, SOCK_STREAM, 0);
+  EXPECT_NE(-1, sock4);
+
+  close(sock1);
+  close(sock2);
+  close(sock3);
+  close(sock4);
+}
+
+TEST_F(SocketTestUDP, Bind) {
+  // Bind away.
+  EXPECT_EQ(Bind(sock1, LOCAL_HOST, PORT1), ENONE);
+
+  // Invalid to rebind a socket.
+  EXPECT_EQ(Bind(sock1, LOCAL_HOST, PORT1), EINVAL);
+
+  // Addr in use.
+  EXPECT_EQ(Bind(sock2, LOCAL_HOST, PORT1), EADDRINUSE);
+
+  // Bind with a wildcard.
+  EXPECT_EQ(Bind(sock2, LOCAL_HOST, ANY_PORT), ENONE);
+
+  // Invalid to rebind after wildcard
+  EXPECT_EQ(Bind(sock2, LOCAL_HOST, PORT1), EINVAL);
+
+}
+
+TEST_F(SocketTestUDP, SendRcv) {
+  char outbuf[256];
+  char inbuf[512];
+
+  memset(outbuf, 1, sizeof(outbuf));
+  memset(inbuf, 0, sizeof(inbuf));
+
+  EXPECT_EQ(Bind(sock1, LOCAL_HOST, PORT1), ENONE);
+  EXPECT_EQ(Bind(sock2, LOCAL_HOST, PORT2), ENONE);
+
+  sockaddr_in addr;
+  socklen_t addrlen = sizeof(addr);
+  IP4ToSockAddr(LOCAL_HOST, PORT2, &addr);
+
+  int len1 =
+     sendto(sock1, outbuf, sizeof(outbuf), 0, (sockaddr *) &addr, addrlen);
+  EXPECT_EQ(sizeof(outbuf), len1);
+
+  // Ensure the buffers are different
+  EXPECT_NE(0, memcmp(outbuf, inbuf, sizeof(outbuf)));
+  memset(&addr, 0, sizeof(addr));
+
+  // Try to receive the previously sent packet
+  int len2 =
+    recvfrom(sock2, inbuf, sizeof(inbuf), 0, (sockaddr *) &addr, &addrlen);
+  EXPECT_EQ(sizeof(outbuf), len2);
+  EXPECT_EQ(sizeof(sockaddr_in), addrlen);
+  EXPECT_EQ(PORT1, htons(addr.sin_port));
+
+  // Now they should be the same
+  EXPECT_EQ(0, memcmp(outbuf, inbuf, sizeof(outbuf)));
+}
+
+#if 0
+TEST_F(SocketTestTCP, Connect) {
+  int sock = socket(AF_INET, SOCK_STREAM, 0);
+  EXPECT_NE(-1, sock);
+
+  sockaddr_in addr;
+  socklen_t addrlen = sizeof(addr);
+
+  IP4ToSockAddr(LOCAL_HOST, PORT1, &addr);
+  int err = connect(sock, (sockaddr*) &addr, addrlen);
+  EXPECT_EQ(ENONE, err) << "Failed with errno: " << errno << "\n";
+}
+#endif
+
+#endif  // PROVIDES_SOCKETPAIR_API
diff --git a/native_client_sdk/src/tests/nacl_io_test/event_test.cc b/native_client_sdk/src/tests/nacl_io_test/event_test.cc
new file mode 100644
index 0000000..11326bf
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/event_test.cc
@@ -0,0 +1,481 @@
+/* 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "gtest/gtest.h"
+
+#include "nacl_io/event_emitter.h"
+#include "nacl_io/event_listener.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/kernel_wrap.h"
+
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+class EventEmitterTester : public MountNode {
+ public:
+  EventEmitterTester() : MountNode(NULL), event_status_(0), event_cnt_(0) {}
+
+  void SetEventStatus(uint32_t bits) { event_status_ = bits; }
+  uint32_t GetEventStatus() { return event_status_; }
+
+  Error Ioctl(int request, char* arg) {
+    event_status_ = static_cast<uint32_t>(request);
+    return 0;
+  }
+
+  int GetType() { return S_IFSOCK; }
+  int NumEvents() { return event_cnt_; }
+
+ public:
+  // Make this function public for testing
+  void RaiseEvent(uint32_t events) {
+    EventEmitter::RaiseEvent(events);
+  }
+
+    // Called after registering locally, but while lock is still held.
+  void ChainRegisterEventInfo(const ScopedEventInfo& event) {
+    event_cnt_++;
+  }
+
+  // Called before unregistering locally, but while lock is still held.
+  void ChainUnregisterEventInfo(const ScopedEventInfo& event) {
+    event_cnt_--;
+  }
+
+ protected:
+  uint32_t event_status_;
+  uint32_t event_cnt_;
+};
+
+
+const int MAX_EVENTS = 8;
+
+// IDs for Emitters
+const int ID_EMITTER = 5;
+const int ID_LISTENER = 6;
+const int ID_EMITTER_DUP = 7;
+
+// Kernel Event values
+const uint32_t KE_EXPECTED = 4;
+const uint32_t KE_FILTERED = 2;
+const uint32_t KE_NONE = 0;
+
+// User Data values
+const uint64_t USER_DATA_A = 1;
+const uint64_t USER_DATA_B = 5;
+
+// Timeout durations
+const int TIMEOUT_IMMEDIATE = 0;
+const int TIMEOUT_SHORT= 100;
+const int TIMEOUT_LONG = 500;
+const int TIMEOUT_NEVER = -1;
+const int TIMEOUT_VERY_LONG = 1000;
+
+// We subtract TIMEOUT_SLOP from the expected minimum timed due to rounding
+// and clock drift converting between absolute and relative time.  This should
+// only be 1 for Less Than, and 1 for rounding, but we use 10 since we don't
+// care about real precision, aren't testing of the underlying
+// implementations and don't want flakiness.
+const int TIMEOUT_SLOP = 10;
+
+TEST(EventTest, EmitterBasic) {
+  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+  ScopedRef<EventEmitter> null_emitter;
+
+  ScopedEventListener listener(new EventListener);
+
+  // Verify construction
+  EXPECT_EQ(0, emitter->NumEvents());
+  EXPECT_EQ(0, emitter->GetEventStatus());
+
+  // Verify status
+  emitter->SetEventStatus(KE_EXPECTED);
+  EXPECT_EQ(KE_EXPECTED, emitter->GetEventStatus());
+
+  // Fail to update or free an ID not in the set
+  EXPECT_EQ(ENOENT, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
+  EXPECT_EQ(ENOENT, listener->Free(ID_EMITTER));
+
+  // Fail to Track self
+  EXPECT_EQ(EINVAL, listener->Track(ID_LISTENER,
+                                    listener,
+                                    KE_EXPECTED,
+                                    USER_DATA_A));
+
+  // Set the emitter filter and data
+  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+  EXPECT_EQ(1, emitter->NumEvents());
+
+  // Fail to add the same ID
+  EXPECT_EQ(EEXIST,
+            listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+  EXPECT_EQ(1, emitter->NumEvents());
+
+  int event_cnt = 0;
+  EventData ev[MAX_EVENTS];
+
+  // Do not allow a wait with a zero events count.
+  EXPECT_EQ(EINVAL, listener->Wait(ev, 0, TIMEOUT_IMMEDIATE, &event_cnt));
+
+  // Do not allow a wait with a negative events count.
+  EXPECT_EQ(EINVAL, listener->Wait(ev, -1, TIMEOUT_IMMEDIATE, &event_cnt));
+
+  // Do not allow a wait with a NULL EventData pointer
+  EXPECT_EQ(EFAULT,
+            listener->Wait(NULL, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+
+  // Return with no events if the Emitter has no signals set.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_NONE);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(0, event_cnt);
+
+  // Return with no events if the Emitter has a filtered signals set.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_FILTERED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(0, event_cnt);
+
+  // Return with one event if the Emitter has the expected signal set.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_EXPECTED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(1, event_cnt);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+  // Return with one event containing only the expected signal.
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(1, event_cnt);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+  // Change the USER_DATA on an existing event
+  EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_B));
+
+  // Return with one event signaled with the alternate USER DATA
+  memset(ev, 0, sizeof(ev));
+  event_cnt = 100;
+  emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, 0, &event_cnt));
+  EXPECT_EQ(1, event_cnt);
+  EXPECT_EQ(USER_DATA_B, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+  // Reset the USER_DATA.
+  EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
+
+  // Support adding a DUP.
+  EXPECT_EQ(0, listener->Track(ID_EMITTER_DUP,
+                               emitter,
+                               KE_EXPECTED,
+                               USER_DATA_A));
+  EXPECT_EQ(2, emitter->NumEvents());
+
+  // Return unsignaled.
+  memset(ev, 0, sizeof(ev));
+  emitter->SetEventStatus(KE_NONE);
+  event_cnt = 100;
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(0, event_cnt);
+
+  // Return with two event signaled with expected data.
+  memset(ev, 0, sizeof(ev));
+  emitter->SetEventStatus(KE_EXPECTED);
+  event_cnt = 100;
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+  EXPECT_EQ(2, event_cnt);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_EQ(USER_DATA_A, ev[1].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[1].events);
+}
+
+long Duration(struct timeval* start, struct timeval* end) {
+  if (start->tv_usec > end->tv_usec) {
+    end->tv_sec -= 1;
+    end->tv_usec += 1000000;
+  }
+  long cur_time = 1000 * (end->tv_sec - start->tv_sec);
+  cur_time += (end->tv_usec - start->tv_usec) / 1000;
+  return cur_time;
+}
+
+
+// Run a timed wait, and return the average of 8 iterations to reduce
+// chance of false negative on outlier.
+const int TRIES_TO_AVERAGE = 8;
+bool TimedListen(ScopedEventListener& listen,
+                 EventData* ev,
+                 int ev_max,
+                 int ev_expect,
+                 int ms_wait,
+                 long* duration) {
+
+  struct timeval start;
+  struct timeval end;
+  long total_time = 0;
+
+  for (int a=0; a < TRIES_TO_AVERAGE; a++) {
+    gettimeofday(&start, NULL);
+
+    int signaled;
+
+    EXPECT_EQ(0, listen->Wait(ev, ev_max, ms_wait, &signaled));
+    EXPECT_EQ(signaled, ev_expect);
+
+    if (signaled != ev_expect) {
+      return false;
+    }
+
+    gettimeofday(&end, NULL);
+
+    long cur_time = Duration(&start, &end);
+    total_time += cur_time;
+  }
+
+  *duration = total_time / TRIES_TO_AVERAGE;
+  return true;
+}
+
+
+// NOTE:  These timing tests are potentially flaky, the real test is
+// for the zero timeout should be, has the ConditionVariable been waited on?
+// Once we provide a debuggable SimpleCond and SimpleLock we can actually test
+// the correct thing.
+
+// Normal scheduling would expect us to see ~10ms accuracy, but we'll
+// use a much bigger number (yet smaller than the MAX_MS_TIMEOUT).
+const int SCHEDULING_GRANULARITY = 100;
+
+const int EXPECT_ONE_EVENT = 1;
+const int EXPECT_NO_EVENT = 0;
+
+TEST(EventTest, EmitterTimeout) {
+  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+  ScopedEventListener listener(new EventListener());
+  long duration;
+
+  EventData ev[MAX_EVENTS];
+  memset(ev, 0, sizeof(ev));
+  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+
+  // Return immediately when emitter is signaled, with no timeout
+  emitter->SetEventStatus(KE_EXPECTED);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+                          TIMEOUT_IMMEDIATE, &duration));
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_EQ(0, duration);
+
+  // Return immediately when emitter is signaled, even with timeout
+  emitter->SetEventStatus(KE_EXPECTED);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+                          TIMEOUT_LONG, &duration));
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_GT(SCHEDULING_GRANULARITY, duration);
+
+  // Return immediately if Emiiter is already signaled when blocking forever.
+  emitter->SetEventStatus(KE_EXPECTED);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+                          TIMEOUT_NEVER, &duration));
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+  EXPECT_GT(SCHEDULING_GRANULARITY, duration);
+
+  // Return immediately if Emitter is no signaled when not blocking.
+  emitter->SetEventStatus(KE_NONE);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
+                          TIMEOUT_IMMEDIATE, &duration));
+  EXPECT_EQ(0, duration);
+
+  // Wait TIMEOUT_LONG if the emitter is not in a signaled state.
+  emitter->SetEventStatus(KE_NONE);
+  memset(ev, 0, sizeof(ev));
+  EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
+                          TIMEOUT_LONG, &duration));
+  EXPECT_LT(TIMEOUT_LONG - TIMEOUT_SLOP, duration);
+  EXPECT_GT(TIMEOUT_LONG + SCHEDULING_GRANULARITY, duration);
+}
+
+struct SignalInfo {
+  EventEmitterTester* em;
+  unsigned int ms_wait;
+  uint32_t events;
+};
+
+static void *SignalEmitterThread(void *ptr) {
+  SignalInfo* info = (SignalInfo*) ptr;
+  struct timespec ts;
+  ts.tv_sec = 0;
+  ts.tv_nsec = info->ms_wait * 1000000;
+
+  nanosleep(&ts, NULL);
+
+  info->em->RaiseEvent(info->events);
+  return NULL;
+}
+
+TEST(EventTest, EmitterSignalling) {
+  ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+  ScopedEventListener listener(new EventListener);
+
+  SignalInfo siginfo;
+  struct timeval start;
+  struct timeval end;
+  long duration;
+
+  EventData ev[MAX_EVENTS];
+  memset(ev, 0, sizeof(ev));
+  EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+
+  // Setup another thread to wait 1/4 of the max time, and signal both
+  // an expected, and unexpected value.
+  siginfo.em = emitter.get();
+  siginfo.ms_wait = TIMEOUT_SHORT;
+  siginfo.events = KE_EXPECTED | KE_FILTERED;
+  pthread_t tid;
+  pthread_create(&tid, NULL, SignalEmitterThread, &siginfo);
+
+  // Wait for the signal from the other thread and time it.
+  gettimeofday(&start, NULL);
+  int cnt = 0;
+  EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_VERY_LONG, &cnt));
+  EXPECT_EQ(1, cnt);
+  gettimeofday(&end, NULL);
+
+  // Verify the wait duration, and that we only recieved the expected signal.
+  duration = Duration(&start, &end);
+  EXPECT_GT(TIMEOUT_SHORT + SCHEDULING_GRANULARITY, duration);
+  EXPECT_LT(TIMEOUT_SHORT - TIMEOUT_SLOP, duration);
+  EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+  EXPECT_EQ(KE_EXPECTED, ev[0].events);
+}
+
+
+namespace {
+
+class KernelProxyPolling : public KernelProxy {
+ public:
+  virtual int socket(int domain, int type, int protocol) {
+    ScopedMount mnt;
+    ScopedMountNode node(new EventEmitterTester());
+    ScopedKernelHandle handle(new KernelHandle(mnt, node));
+
+    Error error = handle->Init(0);
+    if (error) {
+      errno = error;
+      return -1;
+    }
+
+    return AllocateFD(handle);
+  }
+};
+
+class KernelProxyPollingTest : public ::testing::Test {
+ public:
+  void SetUp() {
+    ki_init(&kp_);
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+ protected:
+  KernelProxyPolling kp_;
+};
+
+}  // namespace
+
+
+#define SOCKET_CNT 4
+void SetFDs(fd_set* set, int* fds) {
+  FD_ZERO(set);
+
+  FD_SET(0, set);
+  FD_SET(1, set);
+  FD_SET(2, set);
+
+  for (int index = 0; index < SOCKET_CNT; index++)
+    FD_SET(fds[index], set);
+}
+
+TEST_F(KernelProxyPollingTest, Select) {
+  int fds[SOCKET_CNT];
+
+  fd_set rd_set;
+  fd_set wr_set;
+
+  FD_ZERO(&rd_set);
+  FD_ZERO(&wr_set);
+
+  FD_SET(0, &rd_set);
+  FD_SET(1, &rd_set);
+  FD_SET(2, &rd_set);
+
+  FD_SET(0, &wr_set);
+  FD_SET(1, &wr_set);
+  FD_SET(2, &wr_set);
+
+  // Expect normal files to select as read, write, and error
+  int cnt = select(4, &rd_set, &rd_set, &rd_set, NULL);
+  EXPECT_EQ(3 * 3, cnt);
+  EXPECT_NE(0, FD_ISSET(0, &rd_set));
+  EXPECT_NE(0, FD_ISSET(1, &rd_set));
+  EXPECT_NE(0, FD_ISSET(2, &rd_set));
+
+  for (int index = 0 ; index < SOCKET_CNT; index++) {
+    fds[index] = socket(0, 0, 0);
+    EXPECT_NE(-1, fds[index]);
+  }
+
+  // Highest numbered fd
+  const int fdnum = fds[SOCKET_CNT - 1] + 1;
+
+  // Expect only the normal files to select
+  SetFDs(&rd_set, fds);
+  cnt = select(fds[SOCKET_CNT-1] + 1, &rd_set, NULL, NULL, NULL);
+  EXPECT_EQ(3, cnt);
+  EXPECT_NE(0, FD_ISSET(0, &rd_set));
+  EXPECT_NE(0, FD_ISSET(1, &rd_set));
+  EXPECT_NE(0, FD_ISSET(2, &rd_set));
+  for (int index = 0 ; index < SOCKET_CNT; index++) {
+    EXPECT_EQ(0, FD_ISSET(fds[index], &rd_set));
+  }
+
+  // Poke one of the pollable nodes to be READ ready
+  ioctl(fds[0], POLLIN, NULL);
+
+  // Expect normal files to be read/write and one pollable node to be read.
+  SetFDs(&rd_set, fds);
+  SetFDs(&wr_set, fds);
+  cnt = select(fdnum, &rd_set, &wr_set, NULL, NULL);
+  EXPECT_EQ(7, cnt);
+  EXPECT_NE(0, FD_ISSET(fds[0], &rd_set));
+  EXPECT_EQ(0, FD_ISSET(fds[0], &wr_set));
+}
+
+
diff --git a/native_client_sdk/src/tests/nacl_io_test/example.dsc b/native_client_sdk/src/tests/nacl_io_test/example.dsc
new file mode 100644
index 0000000..1afb68a
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/example.dsc
@@ -0,0 +1,59 @@
+{
+  'TOOLS': ['newlib', 'glibc', 'pnacl'],
+  'SEL_LDR': True,
+
+  # Need to add ../../examples for common.js
+  'SEARCH': ['.', '../../examples'],
+  'TARGETS': [
+    {
+      'NAME' : 'nacl_io_test',
+      'TYPE' : 'main',
+      'SOURCES' : [
+        'event_test.cc',
+        'fake_core_interface.cc',
+        'fake_core_interface.h',
+        'fake_pepper_interface_html5fs.cc',
+        'fake_pepper_interface_html5fs.h',
+        'fake_resource_manager.cc',
+        'fake_resource_manager.h',
+        'fake_var_interface.cc',
+        'fake_var_interface.h',
+        'kernel_object_test.cc',
+        'kernel_proxy_mock.cc',
+        'kernel_proxy_mock.h',
+        'kernel_proxy_test.cc',
+        'kernel_wrap_test.cc',
+        'main.cc',
+        'mock_util.h',
+        'mount_dev_mock.h',
+        'mount_html5fs_test.cc',
+        'mount_http_test.cc',
+        'mount_mock.cc',
+        'mount_mock.h',
+        'mount_node_mock.cc',
+        'mount_node_mock.h',
+        'mount_node_test.cc',
+        'mount_node_tty_test.cc',
+        'mount_test.cc',
+        'path_test.cc',
+        'pepper_interface_mock.cc',
+        'pepper_interface_mock.h',
+        'socket_test.cc',
+        'syscalls_test.cc',
+      ],
+      'DEPS': ['ppapi_simple', 'nacl_io'],
+      # Order matters here: gtest has a "main" function that will be used if
+      # referenced before ppapi.
+      'LIBS': ['gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
+      'INCLUDES': ['$(NACL_SDK_ROOT)/include/gtest/internal'],
+      'CXXFLAGS': ['-Wno-sign-compare', '-Wno-unused-private-field'],
+      'CFLAGS_GCC': ['-Wno-unused-local-typedefs'],
+    }
+  ],
+  'DATA': [
+    'example.js'
+  ],
+  'DEST': 'tests',
+  'NAME': 'nacl_io_test',
+  'TITLE': 'NaCl IO test',
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/example.js b/native_client_sdk/src/tests/nacl_io_test/example.js
new file mode 100644
index 0000000..3a65c89
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/example.js
@@ -0,0 +1,92 @@
+// 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.
+// Called by the common.js module.
+function moduleDidLoad() {
+  // The module is not hidden by default so we can easily see if the plugin
+  // failed to load.
+  common.hideModule();
+}
+
+var currentTestEl = null;
+var failedTests = 0;
+var testsFinished = false;
+
+function startCommand(testName) {
+  var testListEl = document.getElementById('tests');
+  var testEl = document.createElement('li');
+  var testRowEl = document.createElement('div');
+  var testNameEl = document.createElement('span');
+  var testResultEl = document.createElement('span');
+  testRowEl.classList.add('row');
+  testNameEl.classList.add('name');
+  testNameEl.textContent = testName;
+  testResultEl.classList.add('result');
+  testRowEl.appendChild(testNameEl);
+  testRowEl.appendChild(testResultEl);
+  testEl.appendChild(testRowEl);
+  testListEl.appendChild(testEl);
+
+  currentTestEl = testEl;
+}
+
+function failCommand(fileName, lineNumber, summary) {
+  var testMessageEl = document.createElement('pre');
+  testMessageEl.textContent += fileName + ':' + lineNumber + ': ' + summary;
+  currentTestEl.appendChild(testMessageEl);
+  failedTests++;
+}
+
+function endCommand(testName, testResult) {
+  var testRowEl = currentTestEl.querySelector('.row');
+  var testResultEl = currentTestEl.querySelector('.result');
+  testRowEl.classList.add(testResult);
+  testResultEl.textContent = testResult;
+}
+
+function testendCommand() {
+  testsFinished = true;
+}
+
+function handleMessage(event) {
+  var msg = event.data;
+  var firstColon = msg.indexOf(':');
+  var cmd = firstColon !== -1 ? msg.substr(0, firstColon) : msg;
+  var cmdFunctionName = cmd + 'Command';
+  var cmdFunction = window[cmdFunctionName];
+
+  if (typeof(cmdFunction) !== 'function') {
+    console.log('Unknown command: ' + cmd);
+    console.log('  message: ' + msg);
+    return;
+  }
+
+  var argCount = cmdFunction.length;
+
+  // Don't use split, because it will split all commas (for example any commas
+  // in the test failure summary).
+  var argList = msg.substr(firstColon + 1);
+  args = [];
+  for (var i = 0; i < argCount - 1; ++i) {
+    var arg;
+    var comma = argList.indexOf(',');
+    if (comma === -1) {
+      if (i !== argCount - 1) {
+        console.log('Bad arg count to command "' + cmd + '", expected ' +
+                    argCount);
+        console.log('  message: ' + msg);
+      } else {
+        arg = argList;
+      }
+    } else {
+      arg = argList.substr(0, comma);
+      argList = argList.substr(comma + 1);
+    }
+    args.push(arg);
+  }
+
+  // Last argument is the rest of the message.
+  args.push(argList);
+
+  cmdFunction.apply(null, args);
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.cc b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.cc
new file mode 100644
index 0000000..85759c4
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.cc
@@ -0,0 +1,15 @@
+// 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 "fake_core_interface.h"
+
+FakeCoreInterface::FakeCoreInterface() {}
+
+void FakeCoreInterface::AddRefResource(PP_Resource handle) {
+  return resource_manager_.AddRef(handle);
+}
+
+void FakeCoreInterface::ReleaseResource(PP_Resource handle) {
+  return resource_manager_.Release(handle);
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.h b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.h
new file mode 100644
index 0000000..cae326f
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.h
@@ -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.
+
+#ifndef LIBRARIES_NACL_IO_TEST_FAKE_CORE_INTERFACE_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_CORE_INTERFACE_H_
+
+#include "fake_resource_manager.h"
+#include "nacl_io/pepper_interface.h"
+#include "sdk_util/macros.h"
+
+class FakeCoreInterface : public nacl_io::CoreInterface {
+ public:
+  FakeCoreInterface();
+
+  virtual void AddRefResource(PP_Resource handle);
+  virtual void ReleaseResource(PP_Resource handle);
+  virtual PP_Bool IsMainThread() { return PP_FALSE; }
+
+  FakeResourceManager* resource_manager() { return &resource_manager_; }
+
+ private:
+  FakeResourceManager resource_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeCoreInterface);
+};
+
+#endif  // LIBRARIES_NACL_IO_TEST_FAKE_CORE_INTERFACE_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.cc b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.cc
new file mode 100644
index 0000000..3bc3989
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.cc
@@ -0,0 +1,707 @@
+// 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 "fake_pepper_interface_html5fs.h"
+
+#include <string.h>
+
+#include <algorithm>
+
+#include <ppapi/c/pp_completion_callback.h>
+#include <ppapi/c/pp_errors.h>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+class FakeInstanceResource : public FakeResource {
+ public:
+  FakeInstanceResource() : filesystem_template(NULL) {}
+  static const char* classname() { return "FakeInstanceResource"; }
+
+  FakeHtml5FsFilesystem* filesystem_template;  // Weak reference.
+};
+
+class FakeFileSystemResource : public FakeResource {
+ public:
+  FakeFileSystemResource() : filesystem(NULL), opened(false) {}
+  ~FakeFileSystemResource() { delete filesystem; }
+  static const char* classname() { return "FakeFileSystemResource"; }
+
+  FakeHtml5FsFilesystem* filesystem;  // Owned.
+  bool opened;
+};
+
+class FakeFileRefResource : public FakeResource {
+ public:
+  FakeFileRefResource() : filesystem(NULL) {}
+  static const char* classname() { return "FakeFileRefResource"; }
+
+  FakeHtml5FsFilesystem* filesystem;  // Weak reference.
+  FakeHtml5FsFilesystem::Path path;
+};
+
+class FakeFileIoResource : public FakeResource {
+ public:
+  FakeFileIoResource() : node(NULL), open_flags(0) {}
+  static const char* classname() { return "FakeFileIoResource"; }
+
+  FakeHtml5FsNode* node;  // Weak reference.
+  int32_t open_flags;
+};
+
+// Helper function to call the completion callback if it is defined (an
+// asynchronous call), or return the result directly if it isn't (a synchronous
+// call).
+//
+// Use like this:
+//   if (<some error condition>)
+//     return RunCompletionCallback(callback, PP_ERROR_FUBAR);
+//
+//   /* Everything worked OK */
+//   return RunCompletionCallback(callback, PP_OK);
+int32_t RunCompletionCallback(PP_CompletionCallback* callback, int32_t result) {
+  if (callback->func) {
+    PP_RunCompletionCallback(callback, result);
+    return PP_OK_COMPLETIONPENDING;
+  }
+  return result;
+}
+
+}  // namespace
+
+FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info) : info_(info) {}
+
+FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
+                                 const std::vector<uint8_t>& contents)
+    : info_(info), contents_(contents) {}
+
+FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
+                                 const std::string& contents)
+    : info_(info) {
+  std::copy(contents.begin(), contents.end(), std::back_inserter(contents_));
+}
+
+int32_t FakeHtml5FsNode::Read(int64_t offset,
+                              char* buffer,
+                              int32_t bytes_to_read) {
+  if (offset < 0)
+    return PP_ERROR_FAILED;
+
+  bytes_to_read =
+      std::max(0, std::min<int32_t>(bytes_to_read, contents_.size() - offset));
+  memcpy(buffer, contents_.data() + offset, bytes_to_read);
+  return bytes_to_read;
+}
+
+int32_t FakeHtml5FsNode::Write(int64_t offset,
+                               const char* buffer,
+                               int32_t bytes_to_write) {
+  if (offset < 0)
+    return PP_ERROR_FAILED;
+
+  size_t new_size = offset + bytes_to_write;
+  if (new_size > contents_.size())
+    contents_.resize(new_size);
+
+  memcpy(contents_.data() + offset, buffer, bytes_to_write);
+  info_.size = new_size;
+  return bytes_to_write;
+}
+
+int32_t FakeHtml5FsNode::Append(const char* buffer, int32_t bytes_to_write) {
+  return Write(contents_.size(), buffer, bytes_to_write);
+}
+
+int32_t FakeHtml5FsNode::SetLength(int64_t length) {
+  contents_.resize(length);
+  info_.size = length;
+  return PP_OK;
+}
+
+void FakeHtml5FsNode::GetInfo(PP_FileInfo* out_info) { *out_info = info_; }
+
+bool FakeHtml5FsNode::IsRegular() const {
+  return info_.type == PP_FILETYPE_REGULAR;
+}
+
+bool FakeHtml5FsNode::IsDirectory() const {
+  return info_.type == PP_FILETYPE_DIRECTORY;
+}
+
+FakeHtml5FsFilesystem::FakeHtml5FsFilesystem()
+    : filesystem_type_(PP_FILESYSTEMTYPE_INVALID) {
+  Clear();
+}
+
+FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(PP_FileSystemType type)
+    : filesystem_type_(type) {
+  Clear();
+}
+
+FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(
+    const FakeHtml5FsFilesystem& filesystem,
+    PP_FileSystemType type)
+    : node_map_(filesystem.node_map_), filesystem_type_(type) {}
+
+void FakeHtml5FsFilesystem::Clear() {
+  node_map_.clear();
+  // Always have a root node.
+  AddDirectory("/", NULL);
+}
+
+bool FakeHtml5FsFilesystem::AddEmptyFile(const Path& path,
+                                         FakeHtml5FsNode** out_node) {
+  return AddFile(path, std::vector<uint8_t>(), out_node);
+}
+
+bool FakeHtml5FsFilesystem::AddFile(const Path& path,
+                                    const std::string& contents,
+                                    FakeHtml5FsNode** out_node) {
+  std::vector<uint8_t> data;
+  std::copy(contents.begin(), contents.end(), std::back_inserter(data));
+  return AddFile(path, data, out_node);
+}
+
+bool FakeHtml5FsFilesystem::AddFile(const Path& path,
+                                    const std::vector<uint8_t>& contents,
+                                    FakeHtml5FsNode** out_node) {
+  NodeMap::iterator iter = node_map_.find(path);
+  if (iter != node_map_.end()) {
+    if (out_node)
+      *out_node = NULL;
+    return false;
+  }
+
+  PP_FileInfo info;
+  info.size = contents.size();
+  info.type = PP_FILETYPE_REGULAR;
+  info.system_type = filesystem_type_;
+  info.creation_time = 0;
+  info.last_access_time = 0;
+  info.last_modified_time = 0;
+
+  FakeHtml5FsNode node(info, contents);
+  std::pair<NodeMap::iterator, bool> result =
+      node_map_.insert(NodeMap::value_type(path, node));
+
+  EXPECT_EQ(true, result.second);
+  if (out_node)
+    *out_node = &result.first->second;
+  return true;
+}
+
+bool FakeHtml5FsFilesystem::AddDirectory(const Path& path,
+                                         FakeHtml5FsNode** out_node) {
+  NodeMap::iterator iter = node_map_.find(path);
+  if (iter != node_map_.end()) {
+    if (out_node)
+      *out_node = NULL;
+    return false;
+  }
+
+  PP_FileInfo info;
+  info.size = 0;
+  info.type = PP_FILETYPE_DIRECTORY;
+  info.system_type = filesystem_type_;
+  info.creation_time = 0;
+  info.last_access_time = 0;
+  info.last_modified_time = 0;
+
+  FakeHtml5FsNode node(info);
+  std::pair<NodeMap::iterator, bool> result =
+      node_map_.insert(NodeMap::value_type(path, node));
+
+  EXPECT_EQ(true, result.second);
+  if (out_node)
+    *out_node = &result.first->second;
+  return true;
+}
+
+bool FakeHtml5FsFilesystem::RemoveNode(const Path& path) {
+  return node_map_.erase(path) >= 1;
+}
+
+FakeHtml5FsNode* FakeHtml5FsFilesystem::GetNode(const Path& path) {
+  NodeMap::iterator iter = node_map_.find(path);
+  if (iter == node_map_.end())
+    return NULL;
+  return &iter->second;
+}
+
+bool FakeHtml5FsFilesystem::GetDirectoryEntries(
+    const Path& path,
+    DirectoryEntries* out_dir_entries) const {
+  out_dir_entries->clear();
+
+  NodeMap::const_iterator iter = node_map_.find(path);
+  if (iter == node_map_.end())
+    return false;
+
+  const FakeHtml5FsNode& dir_node = iter->second;
+  if (!dir_node.IsDirectory())
+    return false;
+
+  for (NodeMap::const_iterator iter = node_map_.begin();
+       iter != node_map_.end();
+       ++iter) {
+    const Path& node_path = iter->first;
+    if (node_path.find(path) == std::string::npos)
+      continue;
+
+    // A node is not a child of itself.
+    if (&iter->second == &dir_node)
+      continue;
+
+    // Only consider children, not descendants. If we find a forward slash, then
+    // the node must be in a subdirectory.
+    if (node_path.find('/', path.size() + 1) != std::string::npos)
+      continue;
+
+    // The directory entry names do not include the path.
+    Path entry_path = node_path;
+    size_t last_slash = node_path.rfind('/');
+    if (last_slash != std::string::npos)
+      entry_path.erase(0, last_slash + 1);
+
+    DirectoryEntry entry;
+    entry.path = entry_path;
+    entry.node = &iter->second;
+    out_dir_entries->push_back(entry);
+  }
+
+  return true;
+}
+
+// static
+FakeHtml5FsFilesystem::Path FakeHtml5FsFilesystem::GetParentPath(
+    const Path& path) {
+  size_t last_slash = path.rfind('/');
+  if (last_slash == 0)
+    return "/";
+
+  EXPECT_EQ(std::string::npos, last_slash);
+  return path.substr(0, last_slash);
+}
+
+FakeFileIoInterface::FakeFileIoInterface(FakeCoreInterface* core_interface)
+    : core_interface_(core_interface) {}
+
+PP_Resource FakeFileIoInterface::Create(PP_Resource) {
+  return CREATE_RESOURCE(core_interface_->resource_manager(),
+                         FakeFileIoResource,
+                         new FakeFileIoResource);
+}
+
+int32_t FakeFileIoInterface::Open(PP_Resource file_io,
+                                  PP_Resource file_ref,
+                                  int32_t open_flags,
+                                  PP_CompletionCallback callback) {
+  FakeFileIoResource* file_io_resource =
+      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+  if (file_io_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  bool flag_write = !!(open_flags & PP_FILEOPENFLAG_WRITE);
+  bool flag_create = !!(open_flags & PP_FILEOPENFLAG_CREATE);
+  bool flag_truncate = !!(open_flags & PP_FILEOPENFLAG_TRUNCATE);
+  bool flag_exclusive = !!(open_flags & PP_FILEOPENFLAG_EXCLUSIVE);
+  bool flag_append = !!(open_flags & PP_FILEOPENFLAG_APPEND);
+
+  if ((flag_append && flag_write) || (flag_truncate && !flag_write))
+    return PP_ERROR_BADARGUMENT;
+
+  FakeFileRefResource* file_ref_resource =
+      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+  if (file_ref_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  const FakeHtml5FsFilesystem::Path& path = file_ref_resource->path;
+  FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
+  FakeHtml5FsNode* node = filesystem->GetNode(path);
+  bool node_exists = node != NULL;
+
+  if (!node_exists) {
+    if (!flag_create)
+      return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+    bool result = filesystem->AddEmptyFile(path, &node);
+    EXPECT_EQ(true, result);
+  } else {
+    if (flag_create && flag_exclusive)
+      return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);
+  }
+
+  file_io_resource->node = node;
+  file_io_resource->open_flags = open_flags;
+
+  if (flag_truncate)
+    return RunCompletionCallback(&callback, node->SetLength(0));
+
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileIoInterface::Query(PP_Resource file_io,
+                                   PP_FileInfo* info,
+                                   PP_CompletionCallback callback) {
+  FakeFileIoResource* file_io_resource =
+      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+  if (file_io_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  if (!file_io_resource->node)
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  file_io_resource->node->GetInfo(info);
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileIoInterface::Read(PP_Resource file_io,
+                                  int64_t offset,
+                                  char* buffer,
+                                  int32_t bytes_to_read,
+                                  PP_CompletionCallback callback) {
+  FakeFileIoResource* file_io_resource =
+      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+  if (file_io_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  if (bytes_to_read < 0)
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_READ) !=
+      PP_FILEOPENFLAG_READ) {
+    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+  }
+
+  if (!file_io_resource->node)
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  int32_t result = file_io_resource->node->Read(offset, buffer, bytes_to_read);
+  return RunCompletionCallback(&callback, result);
+}
+
+int32_t FakeFileIoInterface::Write(PP_Resource file_io,
+                                   int64_t offset,
+                                   const char* buffer,
+                                   int32_t bytes_to_write,
+                                   PP_CompletionCallback callback) {
+  FakeFileIoResource* file_io_resource =
+      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+  if (file_io_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
+      PP_FILEOPENFLAG_WRITE) {
+    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+  }
+
+  if (!file_io_resource->node)
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  int32_t result;
+  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_APPEND) ==
+      PP_FILEOPENFLAG_APPEND) {
+    result = file_io_resource->node->Append(buffer, bytes_to_write);
+  } else {
+    result = file_io_resource->node->Write(offset, buffer, bytes_to_write);
+  }
+
+  return RunCompletionCallback(&callback, result);
+}
+
+int32_t FakeFileIoInterface::SetLength(PP_Resource file_io,
+                                       int64_t length,
+                                       PP_CompletionCallback callback) {
+  FakeFileIoResource* file_io_resource =
+      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+  if (file_io_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
+      PP_FILEOPENFLAG_WRITE) {
+    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+  }
+
+  if (!file_io_resource->node)
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  int32_t result = file_io_resource->node->SetLength(length);
+  return RunCompletionCallback(&callback, result);
+}
+
+int32_t FakeFileIoInterface::Flush(PP_Resource file_io,
+                                   PP_CompletionCallback callback) {
+  FakeFileIoResource* file_io_resource =
+      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+  if (file_io_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  if (!file_io_resource->node)
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+void FakeFileIoInterface::Close(PP_Resource file_io) {
+  FakeFileIoResource* file_io_resource =
+      core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+  if (file_io_resource == NULL)
+    return;
+
+  file_io_resource->node = NULL;
+  file_io_resource->open_flags = 0;
+}
+
+FakeFileRefInterface::FakeFileRefInterface(FakeCoreInterface* core_interface,
+                                           FakeVarInterface* var_interface)
+    : core_interface_(core_interface), var_interface_(var_interface) {}
+
+PP_Resource FakeFileRefInterface::Create(PP_Resource file_system,
+                                         const char* path) {
+  FakeFileSystemResource* file_system_resource =
+      core_interface_->resource_manager()->Get<FakeFileSystemResource>(
+          file_system);
+  if (file_system_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  if (!file_system_resource->opened)
+    return PP_ERROR_FAILED;
+
+  if (path == NULL)
+    return PP_ERROR_FAILED;
+
+  size_t path_len = strlen(path);
+  if (path_len == 0)
+    return PP_ERROR_FAILED;
+
+  FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
+  file_ref_resource->filesystem = file_system_resource->filesystem;
+  file_ref_resource->path = path;
+
+  // Remove a trailing slash from the path, unless it is the root path.
+  if (path_len > 1 && file_ref_resource->path[path_len - 1] == '/')
+    file_ref_resource->path.erase(path_len - 1);
+
+  return CREATE_RESOURCE(core_interface_->resource_manager(),
+                         FakeFileRefResource,
+                         file_ref_resource);
+}
+
+PP_Var FakeFileRefInterface::GetName(PP_Resource file_ref) {
+  FakeFileRefResource* file_ref_resource =
+      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+  if (file_ref_resource == NULL)
+    return PP_MakeUndefined();
+
+  return var_interface_->VarFromUtf8(file_ref_resource->path.c_str(),
+                                     file_ref_resource->path.size());
+}
+
+int32_t FakeFileRefInterface::MakeDirectory(PP_Resource directory_ref,
+                                            PP_Bool make_ancestors,
+                                            PP_CompletionCallback callback) {
+  FakeFileRefResource* directory_ref_resource =
+      core_interface_->resource_manager()->Get<FakeFileRefResource>(
+          directory_ref);
+  if (directory_ref_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  // TODO(binji): We don't currently use make_ancestors==PP_TRUE in nacl_io, so
+  // I won't bother implementing it.
+  if (make_ancestors == PP_TRUE)
+    return PP_ERROR_FAILED;
+
+  FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
+  FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;
+
+  // Pepper returns PP_ERROR_NOACCESS when trying to create the root directory,
+  // not PP_ERROR_FILEEXISTS, as you might expect.
+  if (path == "/")
+    return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+
+  FakeHtml5FsNode* node = filesystem->GetNode(path);
+  if (node != NULL)
+    return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);
+
+  FakeHtml5FsFilesystem::Path parent_path = filesystem->GetParentPath(path);
+  FakeHtml5FsNode* parent_node = filesystem->GetNode(parent_path);
+  if (parent_node == NULL)
+    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+  if (!parent_node->IsDirectory())
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  bool result = filesystem->AddDirectory(directory_ref_resource->path, NULL);
+  EXPECT_EQ(true, result);
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileRefInterface::Delete(PP_Resource file_ref,
+                                     PP_CompletionCallback callback) {
+  FakeFileRefResource* file_ref_resource =
+      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+  if (file_ref_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
+  FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
+  FakeHtml5FsNode* node = filesystem->GetNode(path);
+  if (node == NULL)
+    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+  filesystem->RemoveNode(path);
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileRefInterface::Query(PP_Resource file_ref,
+                                    PP_FileInfo* info,
+                                    PP_CompletionCallback callback) {
+  FakeFileRefResource* file_ref_resource =
+      core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+  if (file_ref_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
+  FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
+  FakeHtml5FsNode* node = filesystem->GetNode(path);
+  if (node == NULL)
+    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+  node->GetInfo(info);
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileRefInterface::ReadDirectoryEntries(
+    PP_Resource directory_ref,
+    const PP_ArrayOutput& output,
+    PP_CompletionCallback callback) {
+  FakeFileRefResource* directory_ref_resource =
+      core_interface_->resource_manager()->Get<FakeFileRefResource>(
+          directory_ref);
+  if (directory_ref_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
+  FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;
+  FakeHtml5FsNode* node = filesystem->GetNode(path);
+  if (node == NULL)
+    return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+  if (!node->IsDirectory())
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  FakeHtml5FsFilesystem::DirectoryEntries fake_dir_entries;
+  filesystem->GetDirectoryEntries(path, &fake_dir_entries);
+
+  uint32_t element_count = fake_dir_entries.size();
+  uint32_t element_size = sizeof(fake_dir_entries[0]);
+  void* data_buffer =
+      (*output.GetDataBuffer)(output.user_data, element_count, element_size);
+
+  if (data_buffer == NULL)
+    return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+  PP_DirectoryEntry* dir_entries = static_cast<PP_DirectoryEntry*>(data_buffer);
+  for (uint32_t i = 0; i < element_count; ++i) {
+    const FakeHtml5FsFilesystem::DirectoryEntry& fake_dir_entry =
+        fake_dir_entries[i];
+
+    FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
+    file_ref_resource->filesystem = directory_ref_resource->filesystem;
+    file_ref_resource->path = fake_dir_entry.path;
+    PP_Resource file_ref = CREATE_RESOURCE(core_interface_->resource_manager(),
+                                           FakeFileRefResource,
+                                           file_ref_resource);
+
+    dir_entries[i].file_ref = file_ref;
+    dir_entries[i].file_type = fake_dir_entry.node->file_type();
+  }
+
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+FakeFileSystemInterface::FakeFileSystemInterface(
+    FakeCoreInterface* core_interface)
+    : core_interface_(core_interface) {}
+
+PP_Resource FakeFileSystemInterface::Create(PP_Instance instance,
+                                            PP_FileSystemType filesystem_type) {
+  FakeInstanceResource* instance_resource =
+      core_interface_->resource_manager()->Get<FakeInstanceResource>(instance);
+  if (instance_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  FakeFileSystemResource* file_system_resource = new FakeFileSystemResource;
+  file_system_resource->filesystem = new FakeHtml5FsFilesystem(
+      *instance_resource->filesystem_template, filesystem_type);
+
+  return CREATE_RESOURCE(core_interface_->resource_manager(),
+                         FakeFileSystemResource,
+                         file_system_resource);
+}
+
+int32_t FakeFileSystemInterface::Open(PP_Resource file_system,
+                                      int64_t expected_size,
+                                      PP_CompletionCallback callback) {
+  FakeFileSystemResource* file_system_resource =
+      core_interface_->resource_manager()->Get<FakeFileSystemResource>(
+          file_system);
+  if (file_system_resource == NULL)
+    return PP_ERROR_BADRESOURCE;
+
+  file_system_resource->opened = true;
+  return RunCompletionCallback(&callback, PP_OK);
+}
+
+FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs()
+    : file_system_interface_(&core_interface_),
+      file_ref_interface_(&core_interface_, &var_interface_),
+      file_io_interface_(&core_interface_) {
+  Init();
+}
+
+FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs(
+    const FakeHtml5FsFilesystem& filesystem)
+    : filesystem_template_(filesystem),
+      file_system_interface_(&core_interface_),
+      file_ref_interface_(&core_interface_, &var_interface_),
+      file_io_interface_(&core_interface_),
+      instance_(0) {
+  Init();
+}
+
+void FakePepperInterfaceHtml5Fs::Init() {
+  FakeInstanceResource* instance_resource = new FakeInstanceResource;
+  instance_resource->filesystem_template = &filesystem_template_;
+
+  instance_ = CREATE_RESOURCE(core_interface_.resource_manager(),
+                              FakeInstanceResource,
+                              instance_resource);
+}
+
+FakePepperInterfaceHtml5Fs::~FakePepperInterfaceHtml5Fs() {
+  core_interface_.ReleaseResource(instance_);
+}
+
+nacl_io::CoreInterface* FakePepperInterfaceHtml5Fs::GetCoreInterface() {
+  return &core_interface_;
+}
+
+nacl_io::FileSystemInterface*
+FakePepperInterfaceHtml5Fs::GetFileSystemInterface() {
+  return &file_system_interface_;
+}
+
+nacl_io::FileRefInterface* FakePepperInterfaceHtml5Fs::GetFileRefInterface() {
+  return &file_ref_interface_;
+}
+
+nacl_io::FileIoInterface* FakePepperInterfaceHtml5Fs::GetFileIoInterface() {
+  return &file_io_interface_;
+}
+
+nacl_io::VarInterface* FakePepperInterfaceHtml5Fs::GetVarInterface() {
+  return &var_interface_;
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.h b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.h
new file mode 100644
index 0000000..6e10844
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.h
@@ -0,0 +1,200 @@
+// 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_TEST_FAKE_PEPPER_INTERFACE_HTML5FS_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_PEPPER_INTERFACE_HTML5FS_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <ppapi/c/pp_directory_entry.h>
+
+#include "fake_core_interface.h"
+#include "fake_var_interface.h"
+#include "nacl_io/pepper_interface_dummy.h"
+#include "sdk_util/macros.h"
+
+// This class is a fake implementation of the interfaces necessary to access
+// the HTML5 Filesystem from NaCl.
+//
+// Example:
+//   FakePepperInterfaceHtml5Fs ppapi_html5fs;
+//   ...
+//   PP_Resource ref_resource = ppapi_html5fs.GetFileRefInterface()->Create(
+//       ppapi_html5fs.GetInstance(),
+//       "/some/path");
+//   ...
+//
+// NOTE: This pepper interface creates an instance resource that can only be
+// used with FakePepperInterfaceHtml5Fs, not other fake pepper implementations.
+
+class FakeHtml5FsNode {
+ public:
+  FakeHtml5FsNode(const PP_FileInfo& info);
+  FakeHtml5FsNode(const PP_FileInfo& info,
+                  const std::vector<uint8_t>& contents);
+  FakeHtml5FsNode(const PP_FileInfo& info, const std::string& contents);
+
+  int32_t Read(int64_t offset, char* buffer, int32_t bytes_to_read);
+  int32_t Write(int64_t offset, const char* buffer, int32_t bytes_to_write);
+  int32_t Append(const char* buffer, int32_t bytes_to_write);
+  int32_t SetLength(int64_t length);
+  void GetInfo(PP_FileInfo* out_info);
+  bool IsRegular() const;
+  bool IsDirectory() const;
+  PP_FileType file_type() const { return info_.type; }
+
+  // These times are not modified by the fake implementation.
+  void set_creation_time(PP_Time time) { info_.creation_time = time; }
+  void set_last_access_time(PP_Time time) { info_.last_access_time = time; }
+  void set_last_modified_time(PP_Time time) { info_.last_modified_time = time; }
+
+ private:
+  PP_FileInfo info_;
+  std::vector<uint8_t> contents_;
+};
+
+class FakeHtml5FsFilesystem {
+ public:
+  typedef std::string Path;
+
+  struct DirectoryEntry {
+    Path path;
+    const FakeHtml5FsNode* node;
+  };
+  typedef std::vector<DirectoryEntry> DirectoryEntries;
+
+  FakeHtml5FsFilesystem();
+  explicit FakeHtml5FsFilesystem(PP_FileSystemType type);
+  FakeHtml5FsFilesystem(const FakeHtml5FsFilesystem& filesystem,
+                        PP_FileSystemType type);
+
+  void Clear();
+  bool AddEmptyFile(const Path& path, FakeHtml5FsNode** out_node);
+  bool AddFile(const Path& path,
+               const std::string& contents,
+               FakeHtml5FsNode** out_node);
+  bool AddFile(const Path& path,
+               const std::vector<uint8_t>& contents,
+               FakeHtml5FsNode** out_node);
+  bool AddDirectory(const Path& path, FakeHtml5FsNode** out_node);
+  bool RemoveNode(const Path& path);
+
+  FakeHtml5FsNode* GetNode(const Path& path);
+  bool GetDirectoryEntries(const Path& path,
+                           DirectoryEntries* out_dir_entries) const;
+  PP_FileSystemType filesystem_type() const { return filesystem_type_; }
+  static Path GetParentPath(const Path& path);
+
+ private:
+  typedef std::map<Path, FakeHtml5FsNode> NodeMap;
+  NodeMap node_map_;
+  PP_FileSystemType filesystem_type_;
+};
+
+class FakeFileIoInterface : public nacl_io::FileIoInterface {
+ public:
+  explicit FakeFileIoInterface(FakeCoreInterface* core_interface);
+
+  PP_Resource Create(PP_Resource instance);
+  int32_t Open(PP_Resource file_io,
+               PP_Resource file_ref,
+               int32_t open_flags,
+               PP_CompletionCallback callback);
+  int32_t Query(PP_Resource file_io,
+                PP_FileInfo* info,
+                PP_CompletionCallback callback);
+  int32_t Read(PP_Resource file_io,
+               int64_t offset,
+               char* buffer,
+               int32_t bytes_to_read,
+               PP_CompletionCallback callback);
+  int32_t Write(PP_Resource file_io,
+                int64_t offset,
+                const char* buffer,
+                int32_t bytes_to_write,
+                PP_CompletionCallback callback);
+  int32_t SetLength(PP_Resource file_io,
+                    int64_t length,
+                    PP_CompletionCallback callback);
+  int32_t Flush(PP_Resource file_io, PP_CompletionCallback callback);
+  void Close(PP_Resource file_io);
+
+ private:
+  FakeCoreInterface* core_interface_;  // Weak reference.
+
+  DISALLOW_COPY_AND_ASSIGN(FakeFileIoInterface);
+};
+
+class FakeFileRefInterface : public nacl_io::FileRefInterface {
+ public:
+  FakeFileRefInterface(FakeCoreInterface* core_interface,
+                       FakeVarInterface* var_interface);
+
+  PP_Resource Create(PP_Resource file_system, const char* path);
+  PP_Var GetName(PP_Resource file_ref);
+  int32_t MakeDirectory(PP_Resource directory_ref,
+                        PP_Bool make_ancestors,
+                        PP_CompletionCallback callback);
+  int32_t Delete(PP_Resource file_ref, PP_CompletionCallback callback);
+  int32_t Query(PP_Resource file_ref,
+                PP_FileInfo* info,
+                PP_CompletionCallback callback);
+  int32_t ReadDirectoryEntries(PP_Resource file_ref,
+                               const PP_ArrayOutput& output,
+                               PP_CompletionCallback callback);
+
+ private:
+  FakeCoreInterface* core_interface_;  // Weak reference.
+  FakeVarInterface* var_interface_;    // Weak reference.
+
+  DISALLOW_COPY_AND_ASSIGN(FakeFileRefInterface);
+};
+
+class FakeFileSystemInterface : public nacl_io::FileSystemInterface {
+ public:
+  FakeFileSystemInterface(FakeCoreInterface* core_interface);
+
+  PP_Resource Create(PP_Instance instance, PP_FileSystemType type);
+  int32_t Open(PP_Resource file_system,
+               int64_t expected_size,
+               PP_CompletionCallback callback);
+
+ private:
+  FakeCoreInterface* core_interface_;  // Weak reference.
+
+  DISALLOW_COPY_AND_ASSIGN(FakeFileSystemInterface);
+};
+
+class FakePepperInterfaceHtml5Fs : public nacl_io::PepperInterfaceDummy {
+ public:
+  FakePepperInterfaceHtml5Fs();
+  explicit FakePepperInterfaceHtml5Fs(const FakeHtml5FsFilesystem& filesystem);
+  ~FakePepperInterfaceHtml5Fs();
+
+  virtual PP_Instance GetInstance() { return instance_; }
+  virtual nacl_io::CoreInterface* GetCoreInterface();
+  virtual nacl_io::FileSystemInterface* GetFileSystemInterface();
+  virtual nacl_io::FileRefInterface* GetFileRefInterface();
+  virtual nacl_io::FileIoInterface* GetFileIoInterface();
+  virtual nacl_io::VarInterface* GetVarInterface();
+
+  FakeHtml5FsFilesystem* filesystem_template() { return &filesystem_template_; }
+
+ private:
+  void Init();
+
+  FakeCoreInterface core_interface_;
+  FakeVarInterface var_interface_;
+  FakeHtml5FsFilesystem filesystem_template_;
+  FakeFileSystemInterface file_system_interface_;
+  FakeFileRefInterface file_ref_interface_;
+  FakeFileIoInterface file_io_interface_;
+  PP_Instance instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakePepperInterfaceHtml5Fs);
+};
+
+#endif  // LIBRARIES_NACL_IO_TEST_FAKE_PEPPER_INTERFACE_HTML5FS_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.cc b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.cc
new file mode 100644
index 0000000..f9c3ab2
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.cc
@@ -0,0 +1,116 @@
+// 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 "fake_resource_manager.h"
+#include "gtest/gtest.h"
+#include "sdk_util/auto_lock.h"
+
+FakeResourceManager::FakeResourceManager() : next_handle_(1) {}
+
+FakeResourceManager::~FakeResourceManager() {
+  // The ref counts for all resources should be zero.
+  for (ResourceMap::iterator iter = resource_map_.begin();
+       iter != resource_map_.end();
+       ++iter) {
+    const FakeResourceTracker* resource_tracker = iter->second;
+    EXPECT_EQ(0, resource_tracker->ref_count()) << "Leaked resource "
+                                                << resource_tracker->classname()
+                                                << "(" << iter->first
+                                                << "), created at "
+                                                << resource_tracker->file()
+                                                << ":"
+                                                << resource_tracker->line();
+  }
+}
+
+PP_Resource FakeResourceManager::Create(FakeResource* resource,
+                                        const char* classname,
+                                        const char* file,
+                                        int line) {
+  AUTO_LOCK(lock_);
+  PP_Resource handle = next_handle_++;
+  FakeResourceTracker* resource_tracker =
+      new FakeResourceTracker(resource, classname, file, line);
+  std::pair<ResourceMap::iterator, bool> result =
+      resource_map_.insert(ResourceMap::value_type(handle, resource_tracker));
+  EXPECT_TRUE(result.second);
+  result.first->second->AddRef();
+  return handle;
+}
+
+void FakeResourceManager::AddRef(PP_Resource handle) {
+  AUTO_LOCK(lock_);
+  ResourceMap::iterator iter = resource_map_.find(handle);
+  ASSERT_NE(resource_map_.end(), iter) << "AddRefing unknown resource "
+                                       << handle;
+
+  FakeResourceTracker* resource_tracker = iter->second;
+  EXPECT_LT(0, resource_tracker->ref_count()) << "AddRefing freed resource "
+                                              << resource_tracker->classname()
+                                              << "(" << handle
+                                              << "), created at "
+                                              << resource_tracker->file() << ":"
+                                              << resource_tracker->line();
+  resource_tracker->AddRef();
+}
+
+void FakeResourceManager::Release(PP_Resource handle) {
+  AUTO_LOCK(lock_);
+  ResourceMap::iterator iter = resource_map_.find(handle);
+  ASSERT_NE(resource_map_.end(), iter) << "Releasing unknown resource "
+                                       << handle;
+
+  FakeResourceTracker* resource_tracker = iter->second;
+  EXPECT_LT(0, resource_tracker->ref_count()) << "Releasing freed resource "
+                                              << resource_tracker->classname()
+                                              << "(" << handle
+                                              << "), created at "
+                                              << resource_tracker->file() << ":"
+                                              << resource_tracker->line();
+  resource_tracker->Release();
+}
+
+FakeResourceTracker* FakeResourceManager::Get(PP_Resource handle) {
+  AUTO_LOCK(lock_);
+  ResourceMap::iterator iter = resource_map_.find(handle);
+  if (iter == resource_map_.end()) {
+    // Can't use FAIL() because it tries to return void.
+    EXPECT_TRUE(false) << "Trying to get resource " << handle
+                       << " that doesn't exist!";
+    return NULL;
+  }
+
+  FakeResourceTracker* resource_tracker = iter->second;
+  EXPECT_LT(0, resource_tracker->ref_count()) << "Accessing freed resource "
+                                              << resource_tracker->classname()
+                                              << "(" << handle
+                                              << "), created at "
+                                              << resource_tracker->file() << ":"
+                                              << resource_tracker->line();
+
+  return iter->second;
+}
+
+FakeResourceTracker::FakeResourceTracker(FakeResource* resource,
+                                         const char* classname,
+                                         const char* file,
+                                         int line)
+    : resource_(resource),
+      classname_(classname),
+      file_(file),
+      line_(line),
+      ref_count_(0) {}
+
+FakeResourceTracker::~FakeResourceTracker() { delete resource_; }
+
+bool FakeResourceTracker::CheckType(const char* other_classname) const {
+  if (strcmp(other_classname, classname_) != 0) {
+    // Repeat the expectation, just to print out a nice error message before we
+    // crash. :)
+    EXPECT_STREQ(classname_, other_classname);
+    return false;
+  }
+
+  return true;
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.h b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.h
new file mode 100644
index 0000000..f545e91
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.h
@@ -0,0 +1,99 @@
+// 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_TEST_FAKE_RESOURCE_MANAGER_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_RESOURCE_MANAGER_H_
+
+#include <map>
+
+#include <ppapi/c/pp_resource.h>
+
+#include "sdk_util/atomicops.h"
+#include "sdk_util/macros.h"
+#include "sdk_util/simple_lock.h"
+
+class FakeResource;
+class FakeResourceTracker;
+
+class FakeResourceManager {
+ public:
+  FakeResourceManager();
+  ~FakeResourceManager();
+
+  PP_Resource Create(FakeResource* resource,
+                     const char* classname,
+                     const char* file,
+                     int line);
+  void AddRef(PP_Resource handle);
+  void Release(PP_Resource handle);
+  template <typename T>
+  T* Get(PP_Resource handle);
+
+ private:
+  FakeResourceTracker* Get(PP_Resource handle);
+
+  typedef std::map<PP_Resource, FakeResourceTracker*> ResourceMap;
+  PP_Resource next_handle_;
+  ResourceMap resource_map_;
+  sdk_util::SimpleLock lock_;  // Protects next_handle_ and resource_map_.
+
+  DISALLOW_COPY_AND_ASSIGN(FakeResourceManager);
+};
+
+// FakeResourceTracker wraps a FakeResource to keep metadata about the
+// resource, including its refcount, the type of resource, etc.
+class FakeResourceTracker {
+ public:
+  FakeResourceTracker(FakeResource* resource,
+                      const char* classname,
+                      const char* file,
+                      int line);
+  ~FakeResourceTracker();
+
+  void AddRef() { sdk_util::AtomicAddFetch(&ref_count_, 1); }
+  void Release() { sdk_util::AtomicAddFetch(&ref_count_, -1); }
+  int32_t ref_count() const { return ref_count_; }
+
+  template <typename T>
+  T* resource() {
+    if (!CheckType(T::classname()))
+      return NULL;
+
+    return static_cast<T*>(resource_);
+  }
+
+  const char* classname() const { return classname_; }
+  const char* file() const { return file_; }
+  int line() const { return line_; }
+
+ private:
+  bool CheckType(const char* classname) const;
+
+  FakeResource* resource_;  // Owned.
+  const char* classname_;   // Weak reference.
+  const char* file_;        // Weak reference.
+  int line_;
+  int32_t ref_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeResourceTracker);
+};
+
+class FakeResource {
+ public:
+  FakeResource() {}
+  virtual ~FakeResource() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeResource);
+};
+
+template <typename T>
+inline T* FakeResourceManager::Get(PP_Resource handle) {
+  return Get(handle)->resource<T>();
+}
+
+#define CREATE_RESOURCE(MANAGER, TYPE, RESOURCE) \
+  (MANAGER)->Create(RESOURCE, #TYPE, __FILE__, __LINE__)
+
+#endif  // LIBRARIES_NACL_IO_TEST_FAKE_RESOURCE_MANAGER_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.cc b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.cc
new file mode 100644
index 0000000..f67a0de
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.cc
@@ -0,0 +1,93 @@
+// 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 "fake_var_interface.h"
+#include "gtest/gtest.h"
+
+FakeVarInterface::FakeVarInterface() : next_id_(1) {}
+
+FakeVarInterface::~FakeVarInterface() {
+  // The ref counts for all vars should be zero.
+  for (VarMap::const_iterator iter = var_map_.begin(); iter != var_map_.end();
+       ++iter) {
+    const FakeStringVar& string_var = iter->second;
+    EXPECT_EQ(0, string_var.ref_count) << "Non-zero refcount on string var "
+                                       << iter->first << " with value \""
+                                       << string_var.value << "\"";
+  }
+}
+
+void FakeVarInterface::AddRef(PP_Var var) {
+  // From ppb_var.h:
+  //   AddRef() adds a reference to the given var. If this is not a refcounted
+  //   object, this function will do nothing so you can always call it no matter
+  //   what the type.
+  if (var.type != PP_VARTYPE_STRING)
+    return;
+
+  VarMap::iterator iter = var_map_.find(var.value.as_id);
+  if (iter == var_map_.end())
+    return;
+
+  FakeStringVar& string_var = iter->second;
+  EXPECT_LT(0, string_var.ref_count) << "AddRefing freed string var "
+                                     << var.value.as_id << " with value \""
+                                     << string_var.value << "\"";
+  string_var.ref_count++;
+}
+
+void FakeVarInterface::Release(PP_Var var) {
+  // From ppb_var.h:
+  //   Release() removes a reference to given var, deleting it if the internal
+  //   reference count becomes 0. If the given var is not a refcounted object,
+  //   this function will do nothing so you can always call it no matter what
+  //   the type.
+  if (var.type != PP_VARTYPE_STRING)
+    return;
+
+  VarMap::iterator iter = var_map_.find(var.value.as_id);
+  if (iter == var_map_.end())
+    return;
+
+  FakeStringVar& string_var = iter->second;
+  EXPECT_LT(0, string_var.ref_count) << "Releasing freed string var "
+                                     << var.value.as_id << " with value \""
+                                     << string_var.value << "\"";
+  string_var.ref_count--;
+}
+
+PP_Var FakeVarInterface::VarFromUtf8(const char* data, uint32_t len) {
+  Id id = next_id_++;
+
+  FakeStringVar string_var;
+  string_var.value.assign(data, len);
+  string_var.ref_count = 1;
+
+  var_map_[id] = string_var;
+
+  struct PP_Var result = {PP_VARTYPE_STRING, 0, {PP_FALSE}};
+  result.value.as_id = id;
+  return result;
+}
+
+const char* FakeVarInterface::VarToUtf8(PP_Var var, uint32_t* out_len) {
+  if (var.type != PP_VARTYPE_STRING) {
+    *out_len = 0;
+    return NULL;
+  }
+
+  VarMap::const_iterator iter = var_map_.find(var.value.as_id);
+  if (iter == var_map_.end()) {
+    *out_len = 0;
+    return NULL;
+  }
+
+  const FakeStringVar& string_var = iter->second;
+  EXPECT_LT(0, string_var.ref_count) << "VarToUtf8 on freed string var "
+                                     << var.value.as_id << " with value \""
+                                     << string_var.value << "\"";
+
+  *out_len = string_var.value.length();
+  return string_var.value.c_str();
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.h b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.h
new file mode 100644
index 0000000..0d59ac6
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.h
@@ -0,0 +1,41 @@
+// 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_TEST_FAKE_VAR_INTERFACE_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_VAR_INTERFACE_H_
+
+#include <map>
+#include <string>
+
+#include <ppapi/c/pp_var.h>
+
+#include "nacl_io/pepper_interface.h"
+#include "sdk_util/macros.h"
+
+class FakeVarInterface : public nacl_io::VarInterface {
+ public:
+  FakeVarInterface();
+  ~FakeVarInterface();
+
+  virtual void AddRef(PP_Var var);
+  virtual void Release(PP_Var var);
+  virtual PP_Var VarFromUtf8(const char* data, uint32_t len);
+  virtual const char* VarToUtf8(PP_Var var, uint32_t* out_len);
+
+ private:
+  typedef uint64_t Id;
+
+  struct FakeStringVar {
+    std::string value;
+    int32_t ref_count;
+  };
+
+  typedef std::map<Id, FakeStringVar> VarMap;
+  Id next_id_;
+  VarMap var_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeVarInterface);
+};
+
+#endif  // LIBRARIES_NACL_IO_TEST_FAKE_VAR_INTERFACE_H_
diff --git a/native_client_sdk/src/libraries/nacl_io_test/index.html b/native_client_sdk/src/tests/nacl_io_test/index.html
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/index.html
rename to native_client_sdk/src/tests/nacl_io_test/index.html
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc
new file mode 100644
index 0000000..4ec3136
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc
@@ -0,0 +1,187 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/stat.h>
+
+#include <map>
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_handle.h"
+#include "nacl_io/kernel_object.h"
+#include "nacl_io/mount.h"
+#include "nacl_io/path.h"
+
+using namespace nacl_io;
+
+namespace {
+
+class MountNodeRefMock : public MountNode {
+ public:
+  MountNodeRefMock(Mount* mnt) : MountNode(mnt) {}
+};
+
+class MountRefMock : public Mount {
+ public:
+  MountRefMock() {}
+
+ public:
+  Error Access(const Path& path, int a_mode) { return ENOSYS; }
+  Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
+    out_node->reset(NULL);
+    return ENOSYS;
+  }
+  Error Unlink(const Path& path) { return 0; }
+  Error Mkdir(const Path& path, int permissions) { return 0; }
+  Error Rmdir(const Path& path) { return 0; }
+  Error Remove(const Path& path) { return 0; }
+};
+
+class KernelHandleRefMock : public KernelHandle {
+ public:
+  KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node)
+      : KernelHandle(mnt, node) {}
+};
+
+class KernelObjectTest : public ::testing::Test {
+ public:
+  void SetUp() {
+    mnt.reset(new MountRefMock());
+    node.reset(new MountNodeRefMock(mnt.get()));
+  }
+
+  void TearDown() {
+    // mnt is ref-counted, it doesn't need to be explicitly deleted.
+    node.reset(NULL);
+    mnt.reset(NULL);
+  }
+
+  KernelObject proxy;
+  ScopedMount mnt;
+  ScopedMountNode node;
+};
+
+}  // namespace
+
+#include <nacl_io/mount_mem.h>
+#include <nacl_io/mount_http.h>
+
+TEST_F(KernelObjectTest, Referencing) {
+  // The mount and node should have 1 ref count at this point
+  EXPECT_EQ(1, mnt->RefCount());
+  EXPECT_EQ(1, node->RefCount());
+
+  // Pass the mount and node into a KernelHandle
+  KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
+  ScopedKernelHandle handle_a(raw_handle);
+
+  // The mount and node should have 1 ref count at this point
+  EXPECT_EQ(1, handle_a->RefCount());
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+
+  ScopedKernelHandle handle_b = handle_a;
+
+  // There should be two references to the KernelHandle, the mount and node
+  // should be unchanged.
+  EXPECT_EQ(2, handle_a->RefCount());
+  EXPECT_EQ(2, handle_b->RefCount());
+  EXPECT_EQ(handle_a.get(), handle_b.get());
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+
+  // Allocating an FD should cause the KernelProxy to ref the handle and
+  // the node and mount should be unchanged.
+  int fd1 = proxy.AllocateFD(handle_a);
+  EXPECT_EQ(3, handle_a->RefCount());
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+
+  // If we "dup" the handle, we should bump the ref count on the handle
+  int fd2 = proxy.AllocateFD(handle_b);
+  EXPECT_EQ(4, handle_a->RefCount());
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+
+  // Handles are expected to come out in order
+  EXPECT_EQ(0, fd1);
+  EXPECT_EQ(1, fd2);
+
+  // Now we "free" the handles, since the proxy should hold them.
+  handle_a.reset(NULL);
+  handle_b.reset(NULL);
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+
+  // We should find the handle by either fd
+  EXPECT_EQ(0, proxy.AcquireHandle(fd1, &handle_a));
+  EXPECT_EQ(0, proxy.AcquireHandle(fd2, &handle_b));
+  EXPECT_EQ(raw_handle, handle_a.get());
+  EXPECT_EQ(raw_handle, handle_b.get());
+
+  EXPECT_EQ(4, handle_a->RefCount());
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+
+  // A non existent fd should fail, and handleA should decrement as handleB
+  // is released by the call.
+  EXPECT_EQ(EBADF, proxy.AcquireHandle(-1, &handle_b));
+  EXPECT_EQ(NULL, handle_b.get());
+  EXPECT_EQ(3, handle_a->RefCount());
+
+  EXPECT_EQ(EBADF, proxy.AcquireHandle(100, &handle_b));
+  EXPECT_EQ(NULL, handle_b.get());
+
+  // Now only the KernelProxy should reference the KernelHandle in the
+  // FD to KernelHandle Map.
+  handle_a.reset();
+  handle_b.reset();
+
+  EXPECT_EQ(2, raw_handle->RefCount());
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+  proxy.FreeFD(fd2);
+  EXPECT_EQ(1, raw_handle->RefCount());
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+
+  proxy.FreeFD(fd1);
+  EXPECT_EQ(1, mnt->RefCount());
+  EXPECT_EQ(1, node->RefCount());
+}
+
+TEST_F(KernelObjectTest, FreeAndReassignFD) {
+  // The mount and node should have 1 ref count at this point
+  EXPECT_EQ(1, mnt->RefCount());
+  EXPECT_EQ(1, node->RefCount());
+
+  KernelHandle* raw_handle = new KernelHandleRefMock(mnt, node);
+  ScopedKernelHandle handle(raw_handle);
+
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+  EXPECT_EQ(1, raw_handle->RefCount());
+
+  proxy.AllocateFD(handle);
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+  EXPECT_EQ(2, raw_handle->RefCount());
+
+  proxy.FreeAndReassignFD(5, handle);
+  EXPECT_EQ(2, mnt->RefCount());
+  EXPECT_EQ(2, node->RefCount());
+  EXPECT_EQ(3, raw_handle->RefCount());
+
+  handle.reset();
+  EXPECT_EQ(2, raw_handle->RefCount());
+
+  proxy.AcquireHandle(5, &handle);
+  EXPECT_EQ(3, raw_handle->RefCount());
+  EXPECT_EQ(raw_handle, handle.get());
+}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.cc
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc
rename to native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.cc
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.h b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.h
new file mode 100644
index 0000000..8a301ac
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.h
@@ -0,0 +1,91 @@
+// 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 LIBRARIES_NACL_IO_TEST_KERNEL_PROXY_MOCK_H_
+#define LIBRARIES_NACL_IO_TEST_KERNEL_PROXY_MOCK_H_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "gmock/gmock.h"
+
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/ossignal.h"
+#include "nacl_io/ossocket.h"
+#include "nacl_io/ostermios.h"
+
+class KernelProxyMock : public nacl_io::KernelProxy {
+ public:
+  KernelProxyMock();
+  virtual ~KernelProxyMock();
+
+  MOCK_METHOD2(access, int(const char*, int));
+  MOCK_METHOD1(chdir, int(const char*));
+  MOCK_METHOD2(chmod, int(const char*, mode_t));
+  MOCK_METHOD3(chown, int(const char*, uid_t, gid_t));
+  MOCK_METHOD1(close, int(int));
+  MOCK_METHOD1(dup, int(int));
+  MOCK_METHOD2(dup2, int(int, int));
+  MOCK_METHOD3(fchown, int(int, uid_t, gid_t));
+  MOCK_METHOD2(ftruncate, int(int, off_t));
+  MOCK_METHOD2(fstat, int(int, struct stat*));
+  MOCK_METHOD1(fsync, int(int));
+  MOCK_METHOD2(getcwd, char*(char*, size_t));
+  MOCK_METHOD3(getdents, int(int, void*, unsigned int));
+  MOCK_METHOD1(getwd, char*(char*));
+  MOCK_METHOD3(ioctl, int(int, int, char*));
+  MOCK_METHOD1(isatty, int(int));
+  MOCK_METHOD2(kill, int(int, int));
+  MOCK_METHOD3(lchown, int(const char*, uid_t, gid_t));
+  MOCK_METHOD2(link, int(const char*, const char*));
+  MOCK_METHOD3(lseek, off_t(int, off_t, int));
+  MOCK_METHOD2(mkdir, int(const char*, mode_t));
+  MOCK_METHOD6(mmap, void*(void*, size_t, int, int, int, size_t));
+  MOCK_METHOD5(mount, int(const char*, const char*, const char*, unsigned long,
+                          const void*));
+  MOCK_METHOD2(open, int(const char*, int));
+  MOCK_METHOD3(read, ssize_t(int, void*, size_t));
+  MOCK_METHOD1(remove, int(const char*));
+  MOCK_METHOD1(rmdir, int(const char*));
+  MOCK_METHOD2(signal, sighandler_t(int, sighandler_t));
+  MOCK_METHOD2(sigset, sighandler_t(int, sighandler_t));
+  MOCK_METHOD2(stat, int(const char*, struct stat*));
+  MOCK_METHOD2(symlink, int(const char*, const char*));
+  MOCK_METHOD2(tcgetattr, int(int, struct termios*));
+  MOCK_METHOD3(tcsetattr, int(int, int, const struct termios*));
+  MOCK_METHOD1(umount, int(const char*));
+  MOCK_METHOD1(unlink, int(const char*));
+  MOCK_METHOD2(utime, int(const char*, const struct utimbuf*));
+  MOCK_METHOD3(write, ssize_t(int, const void*, size_t));
+  MOCK_METHOD1(open_resource, int(const char*));
+
+#ifdef PROVIDES_SOCKET_API
+  MOCK_METHOD3(poll, int(struct pollfd*, nfds_t, int));
+  MOCK_METHOD5(select, int(int, fd_set*, fd_set*, fd_set*, struct timeval*));
+
+  // Socket support functions
+  MOCK_METHOD3(accept, int(int, struct sockaddr*, socklen_t*));
+  MOCK_METHOD3(bind, int(int, const struct sockaddr*, socklen_t));
+  MOCK_METHOD3(connect, int(int, const struct sockaddr*, socklen_t));
+  MOCK_METHOD1(gethostbyname, struct hostent*(const char*));
+  MOCK_METHOD3(getpeername, int(int, struct sockaddr*, socklen_t*));
+  MOCK_METHOD3(getsockname, int(int, struct sockaddr*, socklen_t*));
+  MOCK_METHOD5(getsockopt, int(int, int, int, void*, socklen_t*));
+  MOCK_METHOD2(listen, int(int, int));
+  MOCK_METHOD4(recv, ssize_t(int, void*, size_t, int));
+  MOCK_METHOD6(recvfrom, ssize_t(int, void*, size_t, int,
+                                 struct sockaddr*, socklen_t*));
+  MOCK_METHOD3(recvmsg, ssize_t(int, struct msghdr*, int));
+  MOCK_METHOD4(send, ssize_t(int, const void*, size_t, int));
+  MOCK_METHOD6(sendto, ssize_t(int, const void*, size_t, int,
+                               const struct sockaddr*, socklen_t));
+  MOCK_METHOD3(sendmsg, ssize_t(int, const struct msghdr*, int));
+  MOCK_METHOD5(setsockopt, int(int, int, int, const void*, socklen_t));
+  MOCK_METHOD2(shutdown, int(int, int));
+  MOCK_METHOD3(socket, int(int, int, int));
+  MOCK_METHOD4(socketpair, int(int, int, int, int*));
+#endif // PROVIDES_SOCKET_API
+
+};
+
+#endif  // LIBRARIES_NACL_IO_TEST_KERNEL_PROXY_MOCK_H_
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
new file mode 100644
index 0000000..18cc6a9
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
@@ -0,0 +1,532 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <map>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "mount_mock.h"
+#include "mount_node_mock.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_mem.h"
+#include "nacl_io/osmman.h"
+#include "nacl_io/path.h"
+#include "nacl_io/typed_mount_factory.h"
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+using ::testing::StrEq;
+using ::testing::WithArgs;
+
+namespace {
+
+class KernelProxyFriend : public KernelProxy {
+ public:
+  Mount* RootMount() {
+    ScopedMount mnt;
+    Path path;
+
+    AcquireMountAndRelPath("/", &mnt, &path);
+    return mnt.get();
+  }
+};
+
+class KernelProxyTest : public ::testing::Test {
+ public:
+  KernelProxyTest() {}
+
+  void SetUp() {
+    ki_init(&kp_);
+    // Unmount the passthrough FS and mount a memfs.
+    EXPECT_EQ(0, kp_.umount("/"));
+    EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+ protected:
+  KernelProxyFriend kp_;
+};
+
+}  // namespace
+
+TEST_F(KernelProxyTest, FileLeak) {
+  const size_t buffer_size = 1024;
+  char filename[128];
+  int file_num;
+  int garbage[buffer_size];
+
+  MountMem* mount = (MountMem*)kp_.RootMount();
+  ScopedMountNode root;
+
+  EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
+  EXPECT_EQ(0, root->ChildCount());
+
+  for (file_num = 0; file_num < 4096; file_num++) {
+    sprintf(filename, "/foo%i.tmp", file_num++);
+    FILE* f = fopen(filename, "w");
+    EXPECT_NE((FILE*)0, f);
+    EXPECT_EQ(1, root->ChildCount());
+    EXPECT_EQ(buffer_size, fwrite(garbage, 1, buffer_size, f));
+    fclose(f);
+    EXPECT_EQ(0, remove(filename));
+  }
+  EXPECT_EQ(0, root->ChildCount());
+}
+
+TEST_F(KernelProxyTest, WorkingDirectory) {
+  char text[1024];
+
+  text[0] = 0;
+  ki_getcwd(text, sizeof(text));
+  EXPECT_STREQ("/", text);
+
+  char* alloc = ki_getwd(NULL);
+  EXPECT_EQ((char*)NULL, alloc);
+  EXPECT_EQ(EFAULT, errno);
+
+  text[0] = 0;
+  alloc = ki_getwd(text);
+  EXPECT_STREQ("/", alloc);
+
+  EXPECT_EQ(-1, ki_chdir("/foo"));
+  EXPECT_EQ(ENOENT, errno);
+
+  EXPECT_EQ(0, ki_chdir("/"));
+
+  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
+  EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
+  EXPECT_EQ(EEXIST, errno);
+
+  memset(text, 0, sizeof(text));
+  EXPECT_EQ(0, ki_chdir("foo"));
+  EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
+  EXPECT_STREQ("/foo", text);
+
+  memset(text, 0, sizeof(text));
+  EXPECT_EQ(-1, ki_chdir("foo"));
+  EXPECT_EQ(ENOENT, errno);
+  EXPECT_EQ(0, ki_chdir(".."));
+  EXPECT_EQ(0, ki_chdir("/foo"));
+  EXPECT_EQ(text, ki_getcwd(text, sizeof(text)));
+  EXPECT_STREQ("/foo", text);
+}
+
+TEST_F(KernelProxyTest, MemMountIO) {
+  char text[1024];
+  int fd1, fd2, fd3;
+  int len;
+
+  // Fail to delete non existant "/foo"
+  EXPECT_EQ(-1, ki_rmdir("/foo"));
+  EXPECT_EQ(ENOENT, errno);
+
+  // Create "/foo"
+  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
+  EXPECT_EQ(-1, ki_mkdir("/foo", S_IREAD | S_IWRITE));
+  EXPECT_EQ(EEXIST, errno);
+
+  // Delete "/foo"
+  EXPECT_EQ(0, ki_rmdir("/foo"));
+
+  // Recreate "/foo"
+  EXPECT_EQ(0, ki_mkdir("/foo", S_IREAD | S_IWRITE));
+
+  // Fail to open "/foo/bar"
+  EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY));
+  EXPECT_EQ(ENOENT, errno);
+
+  // Create bar "/foo/bar"
+  fd1 = ki_open("/foo/bar", O_RDONLY | O_CREAT);
+  EXPECT_NE(-1, fd1);
+
+  // Open (optionally create) bar "/foo/bar"
+  fd2 = ki_open("/foo/bar", O_RDONLY | O_CREAT);
+  EXPECT_NE(-1, fd2);
+
+  // Fail to exclusively create bar "/foo/bar"
+  EXPECT_EQ(-1, ki_open("/foo/bar", O_RDONLY | O_CREAT | O_EXCL));
+  EXPECT_EQ(EEXIST, errno);
+
+  // Write hello and world to same node with different descriptors
+  // so that we overwrite each other
+  EXPECT_EQ(5, ki_write(fd2, "WORLD", 5));
+  EXPECT_EQ(5, ki_write(fd1, "HELLO", 5));
+
+  fd3 = ki_open("/foo/bar", O_WRONLY);
+  EXPECT_NE(-1, fd3);
+
+  len = ki_read(fd3, text, sizeof(text));
+  if (len > 0)
+    text[len] = 0;
+  EXPECT_EQ(5, len);
+  EXPECT_STREQ("HELLO", text);
+  EXPECT_EQ(0, ki_close(fd1));
+  EXPECT_EQ(0, ki_close(fd2));
+
+  fd1 = ki_open("/foo/bar", O_WRONLY | O_APPEND);
+  EXPECT_NE(-1, fd1);
+  EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
+
+  len = ki_read(fd3, text, sizeof(text));
+  if (len >= 0)
+    text[len] = 0;
+
+  EXPECT_EQ(5, len);
+  EXPECT_STREQ("WORLD", text);
+
+  fd2 = ki_open("/foo/bar", O_RDONLY);
+  EXPECT_NE(-1, fd2);
+  len = ki_read(fd2, text, sizeof(text));
+  if (len > 0)
+    text[len] = 0;
+  EXPECT_EQ(10, len);
+  EXPECT_STREQ("HELLOWORLD", text);
+}
+
+TEST_F(KernelProxyTest, MemMountLseek) {
+  int fd = ki_open("/foo", O_CREAT | O_RDWR);
+  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
+
+  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
+  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_END));
+  EXPECT_EQ(-1, ki_lseek(fd, -1, SEEK_SET));
+  EXPECT_EQ(EINVAL, errno);
+
+  // Seek past end of file.
+  EXPECT_EQ(13, ki_lseek(fd, 13, SEEK_SET));
+  char buffer[4];
+  memset(&buffer[0], 0xfe, 4);
+  EXPECT_EQ(9, ki_lseek(fd, -4, SEEK_END));
+  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
+  EXPECT_EQ(4, ki_read(fd, &buffer[0], 4));
+  EXPECT_EQ(0, memcmp("\0\0\0\0", buffer, 4));
+}
+
+TEST_F(KernelProxyTest, CloseTwice) {
+  int fd = ki_open("/foo", O_CREAT | O_RDWR);
+  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
+
+  int fd2 = ki_dup(fd);
+  EXPECT_NE(-1, fd2);
+
+  EXPECT_EQ(0, ki_close(fd));
+  EXPECT_EQ(0, ki_close(fd2));
+}
+
+TEST_F(KernelProxyTest, MemMountDup) {
+  int fd = ki_open("/foo", O_CREAT | O_RDWR);
+
+  int dup_fd = ki_dup(fd);
+  EXPECT_NE(-1, dup_fd);
+
+  EXPECT_EQ(9, ki_write(fd, "Some text", 9));
+  EXPECT_EQ(9, ki_lseek(fd, 0, SEEK_CUR));
+  EXPECT_EQ(9, ki_lseek(dup_fd, 0, SEEK_CUR));
+
+  int dup2_fd = 123;
+  EXPECT_EQ(dup2_fd, ki_dup2(fd, dup2_fd));
+  EXPECT_EQ(9, ki_lseek(dup2_fd, 0, SEEK_CUR));
+
+  int new_fd = ki_open("/bar", O_CREAT | O_RDWR);
+
+  EXPECT_EQ(fd, ki_dup2(new_fd, fd));
+  // fd, new_fd -> "/bar"
+  // dup_fd, dup2_fd -> "/foo"
+
+  // We should still be able to write to dup_fd (i.e. it should not be closed).
+  EXPECT_EQ(4, ki_write(dup_fd, "more", 4));
+
+  EXPECT_EQ(0, ki_close(dup2_fd));
+  // fd, new_fd -> "/bar"
+  // dup_fd -> "/foo"
+
+  EXPECT_EQ(dup_fd, ki_dup2(fd, dup_fd));
+  // fd, new_fd, dup_fd -> "/bar"
+}
+
+namespace {
+
+StringMap_t g_StringMap;
+
+class MountMockInit : public MountMem {
+ public:
+  virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+    g_StringMap = args;
+    if (args.find("false") != args.end())
+      return EINVAL;
+    return 0;
+  }
+
+  friend class TypedMountFactory<MountMockInit>;
+};
+
+class KernelProxyMountMock : public KernelProxy {
+  virtual void Init(PepperInterface* ppapi) {
+    KernelProxy::Init(NULL);
+    factories_["initfs"] = new TypedMountFactory<MountMockInit>;
+  }
+};
+
+class KernelProxyMountTest : public ::testing::Test {
+ public:
+  KernelProxyMountTest() {}
+
+  void SetUp() {
+    ki_init(&kp_);
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+ private:
+  KernelProxyMountMock kp_;
+};
+
+}  // namespace
+
+TEST_F(KernelProxyMountTest, MountInit) {
+  int res1 = ki_mount("/", "/mnt1", "initfs", 0, "false,foo=bar");
+
+  EXPECT_EQ("bar", g_StringMap["foo"]);
+  EXPECT_EQ(-1, res1);
+  EXPECT_EQ(EINVAL, errno);
+
+  int res2 = ki_mount("/", "/mnt2", "initfs", 0, "true,bar=foo,x=y");
+  EXPECT_NE(-1, res2);
+  EXPECT_EQ("y", g_StringMap["x"]);
+}
+
+namespace {
+
+int g_MMapCount = 0;
+
+class MountNodeMockMMap : public MountNode {
+ public:
+  MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
+    EXPECT_EQ(0, Init(0));
+  }
+
+  virtual Error MMap(void* addr,
+                     size_t length,
+                     int prot,
+                     int flags,
+                     size_t offset,
+                     void** out_addr) {
+    node_mmap_count_++;
+    switch (g_MMapCount++) {
+      case 0:
+        *out_addr = reinterpret_cast<void*>(0x1000);
+        break;
+      case 1:
+        *out_addr = reinterpret_cast<void*>(0x2000);
+        break;
+      case 2:
+        *out_addr = reinterpret_cast<void*>(0x3000);
+        break;
+      default:
+        return EPERM;
+    }
+
+    return 0;
+  }
+
+ private:
+  int node_mmap_count_;
+};
+
+class MountMockMMap : public Mount {
+ public:
+  virtual Error Access(const Path& path, int a_mode) { return 0; }
+  virtual Error Open(const Path& path, int mode, ScopedMountNode* out_node) {
+    out_node->reset(new MountNodeMockMMap(this));
+    return 0;
+  }
+
+  virtual Error OpenResource(const Path& path, ScopedMountNode* out_node) {
+    out_node->reset(NULL);
+    return ENOSYS;
+  }
+  virtual Error Unlink(const Path& path) { return ENOSYS; }
+  virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
+  virtual Error Rmdir(const Path& path) { return ENOSYS; }
+  virtual Error Remove(const Path& path) { return ENOSYS; }
+
+  friend class TypedMountFactory<MountMockMMap>;
+};
+
+class KernelProxyMockMMap : public KernelProxy {
+  virtual void Init(PepperInterface* ppapi) {
+    KernelProxy::Init(NULL);
+    factories_["mmapfs"] = new TypedMountFactory<MountMockMMap>;
+  }
+};
+
+class KernelProxyMMapTest : public ::testing::Test {
+ public:
+  KernelProxyMMapTest() {}
+
+  void SetUp() {
+    ki_init(&kp_);
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+ private:
+  KernelProxyMockMMap kp_;
+};
+
+}  // namespace
+
+TEST_F(KernelProxyMMapTest, MMap) {
+  EXPECT_EQ(0, ki_umount("/"));
+  EXPECT_EQ(0, ki_mount("", "/", "mmapfs", 0, NULL));
+  int fd = ki_open("/file", O_RDWR | O_CREAT);
+  EXPECT_NE(-1, fd);
+
+  void* addr1 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
+  EXPECT_EQ(reinterpret_cast<void*>(0x1000), addr1);
+  EXPECT_EQ(1, g_MMapCount);
+
+  void* addr2 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
+  EXPECT_EQ(reinterpret_cast<void*>(0x2000), addr2);
+  EXPECT_EQ(2, g_MMapCount);
+
+  void* addr3 = ki_mmap(NULL, 0x800, PROT_READ, MAP_PRIVATE, fd, 0);
+  EXPECT_EQ(reinterpret_cast<void*>(0x3000), addr3);
+  EXPECT_EQ(3, g_MMapCount);
+
+  ki_close(fd);
+
+  // We no longer track mmap'd regions, so munmap is a no-op.
+  EXPECT_EQ(0, ki_munmap(reinterpret_cast<void*>(0x1000), 0x2800));
+  // We don't track regions, so the mmap count hasn't changed.
+  EXPECT_EQ(3, g_MMapCount);
+}
+
+namespace {
+
+class SingletonMountFactory : public MountFactory {
+ public:
+  SingletonMountFactory(const ScopedMount& mount) : mount_(mount) {}
+
+  virtual Error CreateMount(int dev,
+                            StringMap_t& args,
+                            PepperInterface* ppapi,
+                            ScopedMount* out_mount) {
+    *out_mount = mount_;
+    return 0;
+  }
+
+ private:
+  ScopedMount mount_;
+};
+
+class KernelProxyError : public KernelProxy {
+ public:
+  KernelProxyError() : mnt_(new MountMock) {}
+
+  virtual void Init(PepperInterface* ppapi) {
+    KernelProxy::Init(ppapi);
+    factories_["testfs"] = new SingletonMountFactory(mnt_);
+
+    EXPECT_CALL(*mnt_, Destroy()).Times(1);
+  }
+
+  ScopedRef<MountMock> mnt() { return mnt_; }
+
+ private:
+  ScopedRef<MountMock> mnt_;
+};
+
+class KernelProxyErrorTest : public ::testing::Test {
+ public:
+  KernelProxyErrorTest() {}
+
+  void SetUp() {
+    ki_init(&kp_);
+    // Unmount the passthrough FS and mount a testfs.
+    EXPECT_EQ(0, kp_.umount("/"));
+    EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+  ScopedRef<MountMock> mnt() { return kp_.mnt(); }
+
+ private:
+  KernelProxyError kp_;
+};
+
+}  // namespace
+
+TEST_F(KernelProxyErrorTest, WriteError) {
+  ScopedRef<MountMock> mock_mnt(mnt());
+  ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
+  EXPECT_CALL(*mock_mnt, Open(_, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
+
+  EXPECT_CALL(*mock_node, Write(_, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<3>(0),  // Wrote 0 bytes.
+                      Return(1234)));       // Returned error 1234.
+
+  EXPECT_CALL(*mock_node, Destroy()).Times(1);
+
+  int fd = ki_open("/dummy", O_WRONLY);
+  EXPECT_NE(0, fd);
+
+  char buf[20];
+  EXPECT_EQ(-1, ki_write(fd, &buf[0], 20));
+  // The Mount should be able to return whatever error it wants and have it
+  // propagate through.
+  EXPECT_EQ(1234, errno);
+}
+
+TEST_F(KernelProxyErrorTest, ReadError) {
+  ScopedRef<MountMock> mock_mnt(mnt());
+  ScopedRef<MountNodeMock> mock_node(new MountNodeMock(&*mock_mnt));
+  EXPECT_CALL(*mock_mnt, Open(_, _, _))
+      .WillOnce(DoAll(SetArgPointee<2>(mock_node), Return(0)));
+
+  EXPECT_CALL(*mock_node, Read(_, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<3>(0),  // Read 0 bytes.
+                      Return(1234)));       // Returned error 1234.
+
+  EXPECT_CALL(*mock_node, Destroy()).Times(1);
+
+  int fd = ki_open("/dummy", O_RDONLY);
+  EXPECT_NE(0, fd);
+
+  char buf[20];
+  EXPECT_EQ(-1, ki_read(fd, &buf[0], 20));
+  // The Mount should be able to return whatever error it wants and have it
+  // propagate through.
+  EXPECT_EQ(1234, errno);
+}
+
diff --git a/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc
new file mode 100644
index 0000000..4472d8c
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc
@@ -0,0 +1,429 @@
+// 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 <string>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "kernel_proxy_mock.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+#include "nacl_io/ossocket.h"
+#include "nacl_io/ostermios.h"
+
+using namespace nacl_io;
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StrEq;
+
+namespace {
+
+static const int DUMMY_FD = 5678;
+
+#define COMPARE_FIELD(f) \
+  if (arg->f != statbuf->f) { \
+    *result_listener << "mismatch of field \""#f"\". " \
+      "expected: " << statbuf->f << \
+      " actual: " << arg->f; \
+    return false; \
+  }
+
+MATCHER_P(IsEqualToStatbuf, statbuf, "") {
+  COMPARE_FIELD(st_dev);
+  COMPARE_FIELD(st_ino);
+  COMPARE_FIELD(st_mode);
+  COMPARE_FIELD(st_nlink);
+  COMPARE_FIELD(st_uid);
+  COMPARE_FIELD(st_gid);
+  COMPARE_FIELD(st_rdev);
+  COMPARE_FIELD(st_size);
+  COMPARE_FIELD(st_atime);
+  COMPARE_FIELD(st_mtime);
+  COMPARE_FIELD(st_ctime);
+  return true;
+}
+
+#undef COMPARE_FIELD
+
+ACTION_P(SetStat, statbuf) {
+  memset(arg1, 0, sizeof(struct stat));
+  arg1->st_dev = statbuf->st_dev;
+  arg1->st_ino = statbuf->st_ino;
+  arg1->st_mode = statbuf->st_mode;
+  arg1->st_nlink = statbuf->st_nlink;
+  arg1->st_uid = statbuf->st_uid;
+  arg1->st_gid = statbuf->st_gid;
+  arg1->st_rdev = statbuf->st_rdev;
+  arg1->st_size = statbuf->st_size;
+  arg1->st_atime = statbuf->st_atime;
+  arg1->st_mtime = statbuf->st_mtime;
+  arg1->st_ctime = statbuf->st_ctime;
+  return 0;
+}
+
+void MakeDummyStatbuf(struct stat* statbuf) {
+  memset(&statbuf[0], 0, sizeof(struct stat));
+  statbuf->st_dev = 1;
+  statbuf->st_ino = 2;
+  statbuf->st_mode = 3;
+  statbuf->st_nlink = 4;
+  statbuf->st_uid = 5;
+  statbuf->st_gid = 6;
+  statbuf->st_rdev = 7;
+  statbuf->st_size = 8;
+  statbuf->st_atime = 9;
+  statbuf->st_mtime = 10;
+  statbuf->st_ctime = 11;
+}
+
+const uid_t kDummyUid = 1001;
+const gid_t kDummyGid = 1002;
+
+class KernelWrapTest : public ::testing::Test {
+ public:
+  KernelWrapTest() {
+    // Initializing the KernelProxy opens stdin/stdout/stderr.
+    EXPECT_CALL(mock, open(_, _))
+      .WillOnce(Return(0))
+      .WillOnce(Return(1))
+      .WillOnce(Return(2));
+    // And will call mount / and /dev.
+    EXPECT_CALL(mock, mount(_, _, _, _, _))
+      .WillOnce(Return(0))
+      .WillOnce(Return(0));
+
+    ki_init(&mock);
+  }
+
+  ~KernelWrapTest() {
+    ki_uninit();
+  }
+
+  KernelProxyMock mock;
+};
+
+}  // namespace
+
+
+TEST_F(KernelWrapTest, access) {
+  EXPECT_CALL(mock, access(StrEq("access"), 12)).Times(1);
+  access("access", 12);
+}
+
+TEST_F(KernelWrapTest, chdir) {
+  EXPECT_CALL(mock, chdir(StrEq("chdir"))).Times(1);
+  chdir("chdir");
+}
+
+TEST_F(KernelWrapTest, chmod) {
+  EXPECT_CALL(mock, chmod(StrEq("chmod"), 23)).Times(1);
+  chmod("chmod", 23);
+}
+
+TEST_F(KernelWrapTest, chown) {
+  uid_t uid = kDummyUid;
+  gid_t gid = kDummyGid;
+  EXPECT_CALL(mock, chown(StrEq("chown"), uid, gid)).Times(1);
+  chown("chown", uid, gid);
+}
+
+TEST_F(KernelWrapTest, close) {
+  EXPECT_CALL(mock, close(34)).Times(1);
+  close(34);
+}
+
+TEST_F(KernelWrapTest, dup) {
+  EXPECT_CALL(mock, dup(DUMMY_FD)).Times(1);
+  dup(DUMMY_FD);
+}
+
+TEST_F(KernelWrapTest, dup2) {
+  EXPECT_CALL(mock, dup2(DUMMY_FD, 234)).Times(1);
+  dup2(DUMMY_FD, 234);
+}
+
+TEST_F(KernelWrapTest, fchown) {
+  uid_t uid = kDummyUid;
+  gid_t gid = kDummyGid;
+  EXPECT_CALL(mock, fchown(DUMMY_FD, uid, gid)).Times(1);
+  fchown(DUMMY_FD, uid, gid);
+}
+
+TEST_F(KernelWrapTest, fstat) {
+  struct stat in_statbuf;
+  MakeDummyStatbuf(&in_statbuf);
+  EXPECT_CALL(mock, fstat(DUMMY_FD, _))
+      .Times(1)
+      .WillOnce(SetStat(&in_statbuf));
+  struct stat out_statbuf;
+  fstat(DUMMY_FD, &out_statbuf);
+  EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
+}
+
+TEST_F(KernelWrapTest, ftruncate) {
+  EXPECT_CALL(mock, ftruncate(456, 0)).Times(1);
+  ftruncate(456, 0);
+}
+
+TEST_F(KernelWrapTest, fsync) {
+  EXPECT_CALL(mock, fsync(345)).Times(1);
+  fsync(345);
+}
+
+TEST_F(KernelWrapTest, getcwd) {
+  EXPECT_CALL(mock, getcwd(StrEq("getcwd"), 1)).Times(1);
+  char buffer[] = "getcwd";
+  getcwd(buffer, 1);
+}
+
+TEST_F(KernelWrapTest, getdents) {
+#ifndef __GLIBC__
+  // TODO(sbc): Find a way to test the getdents wrapper under glibc.
+  // It looks like the only way to excerside it is to call readdir(2).
+  // There is an internal glibc function __getdents that will call the
+  // IRT but that cannot be accessed from here as glibc does not export it.
+  EXPECT_CALL(mock, getdents(456, NULL, 567)).WillOnce(Return(678));
+  EXPECT_EQ(getdents(456, NULL, 567), 678);
+#endif
+}
+
+// gcc gives error: getwd is deprecated.
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+TEST_F(KernelWrapTest, getwd) {
+  EXPECT_CALL(mock, getwd(StrEq("getwd"))).Times(1);
+  char buffer[] = "getwd";
+  getwd(buffer);
+}
+#if defined(__GNUC__)
+#pragma GCC diagnostic warning "-Wdeprecated-declarations"
+#endif
+
+TEST_F(KernelWrapTest, ioctl) {
+  char buffer[] = "ioctl";
+  EXPECT_CALL(mock, ioctl(012, 345, StrEq("ioctl"))).Times(1);
+  ioctl(012, 345, buffer);
+}
+
+TEST_F(KernelWrapTest, isatty) {
+  EXPECT_CALL(mock, isatty(678)).Times(1);
+  isatty(678);
+}
+
+TEST_F(KernelWrapTest, kill) {
+  EXPECT_CALL(mock, kill(22, 33)).Times(1);
+  kill(22, 33);
+}
+
+TEST_F(KernelWrapTest, lchown) {
+  uid_t uid = kDummyUid;
+  gid_t gid = kDummyGid;
+  EXPECT_CALL(mock, lchown(StrEq("lchown"), uid, gid)).Times(1);
+  lchown("lchown", uid, gid);
+}
+
+TEST_F(KernelWrapTest, lseek) {
+  EXPECT_CALL(mock, lseek(789, 891, 912)).Times(1);
+  lseek(789, 891, 912);
+}
+
+TEST_F(KernelWrapTest, mkdir) {
+#if defined(WIN32)
+  EXPECT_CALL(mock, mkdir(StrEq("mkdir"), 0777)).Times(1);
+  mkdir("mkdir");
+#else
+  EXPECT_CALL(mock, mkdir(StrEq("mkdir"), 1234)).Times(1);
+  mkdir("mkdir", 1234);
+#endif
+}
+
+TEST_F(KernelWrapTest, mount) {
+  EXPECT_CALL(mock,
+      mount(StrEq("mount1"), StrEq("mount2"), StrEq("mount3"), 2345, NULL))
+      .Times(1);
+  mount("mount1", "mount2", "mount3", 2345, NULL);
+}
+
+TEST_F(KernelWrapTest, open) {
+  EXPECT_CALL(mock, open(StrEq("open"), 3456)).Times(1);
+  open("open", 3456);
+}
+
+TEST_F(KernelWrapTest, read) {
+  EXPECT_CALL(mock, read(4567, NULL, 5678)).Times(1);
+  read(4567, NULL, 5678);
+}
+
+TEST_F(KernelWrapTest, remove) {
+  EXPECT_CALL(mock, remove(StrEq("remove"))).Times(1);
+  remove("remove");
+}
+
+TEST_F(KernelWrapTest, rmdir) {
+  EXPECT_CALL(mock, rmdir(StrEq("rmdir"))).Times(1);
+  rmdir("rmdir");
+}
+
+static void handler(int) {
+}
+
+TEST_F(KernelWrapTest, sigset) {
+  EXPECT_CALL(mock, sigset(22, handler)).Times(1);
+  sigset(22, handler);
+}
+
+TEST_F(KernelWrapTest, signal) {
+  EXPECT_CALL(mock, sigset(22, handler)).Times(1);
+  signal(22, handler);
+}
+
+TEST_F(KernelWrapTest, stat) {
+  struct stat in_statbuf;
+  MakeDummyStatbuf(&in_statbuf);
+  EXPECT_CALL(mock, stat(StrEq("stat"), _))
+      .Times(1)
+      .WillOnce(SetStat(&in_statbuf));
+  struct stat out_statbuf;
+  stat("stat", &out_statbuf);
+  EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
+}
+
+TEST_F(KernelWrapTest, tcgetattr) {
+  struct termios term;
+  EXPECT_CALL(mock, tcgetattr(DUMMY_FD, &term)).Times(1);
+  tcgetattr(DUMMY_FD, &term);
+}
+
+TEST_F(KernelWrapTest, tcsetattr) {
+  struct termios term;
+  EXPECT_CALL(mock, tcsetattr(DUMMY_FD, 0, &term)).Times(1);
+  tcsetattr(DUMMY_FD, 0, &term);
+}
+
+TEST_F(KernelWrapTest, umount) {
+  EXPECT_CALL(mock, umount(StrEq("umount"))).Times(1);
+  umount("umount");
+}
+
+TEST_F(KernelWrapTest, unlink) {
+  EXPECT_CALL(mock, unlink(StrEq("unlink"))).Times(1);
+  unlink("unlink");
+}
+
+TEST_F(KernelWrapTest, utime) {
+  const struct utimbuf* times = NULL;
+  EXPECT_CALL(mock, utime(StrEq("utime"), times));
+  utime("utime", times);
+}
+
+TEST_F(KernelWrapTest, write) {
+  EXPECT_CALL(mock, write(6789, NULL, 7891)).Times(1);
+  write(6789, NULL, 7891);
+}
+
+#ifdef PROVIDES_SOCKET_API
+TEST_F(KernelWrapTest, poll) {
+  EXPECT_CALL(mock, poll(NULL, 5, -1));
+  poll(NULL, 5, -1);
+}
+
+TEST_F(KernelWrapTest, select) {
+  EXPECT_CALL(mock, select(123, NULL, NULL, NULL, NULL));
+  select(123, NULL, NULL, NULL, NULL);
+}
+
+// Socket Functions
+TEST_F(KernelWrapTest, accept) {
+  EXPECT_CALL(mock, accept(DUMMY_FD, NULL, NULL)).Times(1);
+  accept(DUMMY_FD, NULL, NULL);
+}
+
+TEST_F(KernelWrapTest, bind) {
+  EXPECT_CALL(mock, bind(DUMMY_FD, NULL, 456)).Times(1);
+  bind(DUMMY_FD, NULL, 456);
+}
+
+TEST_F(KernelWrapTest, connect) {
+  EXPECT_CALL(mock, connect(DUMMY_FD, NULL, 456)).Times(1);
+  connect(DUMMY_FD, NULL, 456);
+}
+
+TEST_F(KernelWrapTest, gethostbyname) {
+  EXPECT_CALL(mock, gethostbyname(NULL)).Times(1);
+  gethostbyname(NULL);
+}
+
+TEST_F(KernelWrapTest, getpeername) {
+  EXPECT_CALL(mock, getpeername(DUMMY_FD, NULL, NULL)).Times(1);
+  getpeername(DUMMY_FD, NULL, NULL);
+}
+
+TEST_F(KernelWrapTest, getsockname) {
+  EXPECT_CALL(mock, getsockname(DUMMY_FD, NULL, NULL)).Times(1);
+  getsockname(DUMMY_FD, NULL, NULL);
+}
+
+TEST_F(KernelWrapTest, getsockopt) {
+  EXPECT_CALL(mock, getsockopt(DUMMY_FD, 456, 789, NULL, NULL)).Times(1);
+  getsockopt(DUMMY_FD, 456, 789, NULL, NULL);
+}
+
+TEST_F(KernelWrapTest, listen) {
+  EXPECT_CALL(mock, listen(DUMMY_FD, 456)).Times(1);
+  listen(DUMMY_FD, 456);
+}
+
+TEST_F(KernelWrapTest, recv) {
+  EXPECT_CALL(mock, recv(DUMMY_FD, NULL, 456, 789)).Times(1);
+  recv(DUMMY_FD, NULL, 456, 789);
+}
+
+TEST_F(KernelWrapTest, recvfrom) {
+  EXPECT_CALL(mock, recvfrom(DUMMY_FD, NULL, 456, 789, NULL, NULL)).Times(1);
+  recvfrom(DUMMY_FD, NULL, 456, 789, NULL, NULL);
+}
+
+TEST_F(KernelWrapTest, recvmsg) {
+  EXPECT_CALL(mock, recvmsg(DUMMY_FD, NULL, 456)).Times(1);
+  recvmsg(DUMMY_FD, NULL, 456);
+}
+
+TEST_F(KernelWrapTest, send) {
+  EXPECT_CALL(mock, send(DUMMY_FD, NULL, 456, 789)).Times(1);
+  send(DUMMY_FD, NULL, 456, 789);
+}
+
+TEST_F(KernelWrapTest, sendto) {
+  EXPECT_CALL(mock, sendto(DUMMY_FD, NULL, 456, 789, NULL, 314)).Times(1);
+  sendto(DUMMY_FD, NULL, 456, 789, NULL, 314);
+}
+
+TEST_F(KernelWrapTest, sendmsg) {
+  EXPECT_CALL(mock, sendmsg(DUMMY_FD, NULL, 456)).Times(1);
+  sendmsg(DUMMY_FD, NULL, 456);
+}
+
+TEST_F(KernelWrapTest, setsockopt) {
+  EXPECT_CALL(mock, setsockopt(DUMMY_FD, 456, 789, NULL, 314)).Times(1);
+  setsockopt(DUMMY_FD, 456, 789, NULL, 314);
+}
+
+TEST_F(KernelWrapTest, shutdown) {
+  EXPECT_CALL(mock, shutdown(DUMMY_FD, 456)).Times(1);
+  shutdown(DUMMY_FD, 456);
+}
+
+TEST_F(KernelWrapTest, socket) {
+  EXPECT_CALL(mock, socket(DUMMY_FD, 456, 789)).Times(1);
+  socket(DUMMY_FD, 456, 789);
+}
+
+TEST_F(KernelWrapTest, socketpair) {
+  EXPECT_CALL(mock, socketpair(DUMMY_FD, 456, 789, NULL)).Times(1);
+  socketpair(DUMMY_FD, 456, 789, NULL);
+}
+
+#endif // PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/tests/nacl_io_test/main.cc b/native_client_sdk/src/tests/nacl_io_test/main.cc
new file mode 100644
index 0000000..9df6d4b
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/main.cc
@@ -0,0 +1,70 @@
+// 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 <string>
+
+#include "gtest/gtest.h"
+
+#if defined(SEL_LDR)
+
+int main(int argc, char* argv[]) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+
+#else
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi_simple/ps_main.h"
+
+#if defined(WIN32)
+#include <Windows.h>
+#undef PostMessage
+#endif
+
+class GTestEventListener : public ::testing::EmptyTestEventListener {
+ public:
+  // TestEventListener overrides.
+  virtual void OnTestStart(const ::testing::TestInfo& test_info) {
+    std::stringstream msg;
+    msg << "start:" << test_info.test_case_name() << "." << test_info.name();
+    pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+  }
+
+  virtual void OnTestPartResult(
+      const ::testing::TestPartResult& test_part_result) {
+    if (test_part_result.failed()) {
+      std::stringstream msg;
+      msg << "fail:" << test_part_result.file_name() << ","
+          << test_part_result.line_number() << ","
+          << test_part_result.summary();
+      pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+    }
+  }
+
+  virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
+    std::stringstream msg;
+    msg << "end:" << test_info.test_case_name() << "." << test_info.name()
+        << "," << (test_info.result()->Failed() ? "failed" : "ok");
+    pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+  }
+
+  virtual void OnTestProgramEnd(const ::testing::UnitTest&) {
+    pp::Instance(PSGetInstanceId()).PostMessage("testend");
+  }
+};
+
+int example_main(int argc, char* argv[]) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ::testing::UnitTest::GetInstance()->listeners()
+      .Append(new GTestEventListener());
+  return RUN_ALL_TESTS();
+}
+
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
+
+#endif
diff --git a/native_client_sdk/src/tests/nacl_io_test/mock_util.h b/native_client_sdk/src/tests/nacl_io_test/mock_util.h
new file mode 100644
index 0000000..7f29f0f
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mock_util.h
@@ -0,0 +1,52 @@
+// 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_TEST_MOCK_UTIL_H_
+#define LIBRARIES_NACL_IO_TEST_MOCK_UTIL_H_
+
+#include <gmock/gmock.h>
+#include <ppapi/c/pp_completion_callback.h>
+#include <ppapi/c/pp_var.h>
+
+ACTION_TEMPLATE(CallCallback,
+                HAS_1_TEMPLATE_PARAMS(int, k),
+                AND_1_VALUE_PARAMS(result)) {
+  PP_CompletionCallback callback = std::tr1::get<k>(args);
+  if (callback.func) {
+    (*callback.func)(callback.user_data, result);
+  }
+}
+
+MATCHER_P(IsEqualToVar, var, "") {
+  if (arg.type != var.type)
+    return false;
+
+  switch (arg.type) {
+    case PP_VARTYPE_BOOL:
+      return arg.value.as_bool == var.value.as_bool;
+
+    case PP_VARTYPE_INT32:
+      return arg.value.as_int == var.value.as_int;
+
+    case PP_VARTYPE_DOUBLE:
+      return arg.value.as_double == var.value.as_double;
+
+    case PP_VARTYPE_STRING:
+      return arg.value.as_id == var.value.as_id;
+
+    case PP_VARTYPE_UNDEFINED:
+    case PP_VARTYPE_NULL:
+      return true;
+
+    case PP_VARTYPE_ARRAY:
+    case PP_VARTYPE_ARRAY_BUFFER:
+    case PP_VARTYPE_DICTIONARY:
+    case PP_VARTYPE_OBJECT:
+    default:
+      // Not supported.
+      return false;
+  }
+}
+
+#endif  // LIBRARIES_NACL_IO_TEST_MOCK_UTIL_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_dev_mock.h b/native_client_sdk/src/tests/nacl_io_test/mount_dev_mock.h
new file mode 100644
index 0000000..10ee830
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_dev_mock.h
@@ -0,0 +1,24 @@
+// 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_TEST_MOUNT_NODE_MOCK_H_
+#define LIBRARIES_NACL_IO_TEST_MOUNT_NODE_MOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_dev.h"
+
+#define NULL_NODE ((MountNode*) NULL)
+
+class MountDevMock : public nacl_io::MountDev {
+ public:
+  MountDevMock() {
+    nacl_io::StringMap_t map;
+    Init(1, map, NULL);
+  }
+  int num_nodes() { return (int) inode_pool_.size(); }
+};
+
+#endif  // LIBRARIES_NACL_IO_TEST_MOUNT_NODE_MOCK_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_html5fs_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_html5fs_test.cc
new file mode 100644
index 0000000..73cd749
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_html5fs_test.cc
@@ -0,0 +1,448 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <gmock/gmock.h>
+#include <ppapi/c/ppb_file_io.h>
+#include <ppapi/c/pp_directory_entry.h>
+#include <ppapi/c/pp_errors.h>
+#include <ppapi/c/pp_instance.h>
+#if defined(WIN32)
+#include <windows.h>  // For Sleep()
+#endif
+
+#include "nacl_io/mount_html5fs.h"
+#include "nacl_io/osdirent.h"
+#include "nacl_io/osunistd.h"
+#include "nacl_io/pepper_interface_delegate.h"
+#include "sdk_util/scoped_ref.h"
+#include "fake_pepper_interface_html5fs.h"
+#include "mock_util.h"
+#include "pepper_interface_mock.h"
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::Return;
+
+namespace {
+
+class MountHtml5FsForTesting : public MountHtml5Fs {
+ public:
+  MountHtml5FsForTesting(StringMap_t& args, PepperInterface* ppapi) {
+    Error error = Init(1, args, ppapi);
+    EXPECT_EQ(0, error);
+  }
+};
+
+class MountHtml5FsTest : public ::testing::Test {
+ public:
+  MountHtml5FsTest();
+
+ protected:
+  FakePepperInterfaceHtml5Fs ppapi_html5_;
+  PepperInterfaceMock ppapi_mock_;
+  PepperInterfaceDelegate ppapi_;
+};
+
+MountHtml5FsTest::MountHtml5FsTest()
+    : ppapi_mock_(ppapi_html5_.GetInstance()),
+      ppapi_(ppapi_html5_.GetInstance()) {
+  // Default delegation to the html5 pepper interface.
+  ppapi_.SetCoreInterfaceDelegate(ppapi_html5_.GetCoreInterface());
+  ppapi_.SetFileSystemInterfaceDelegate(ppapi_html5_.GetFileSystemInterface());
+  ppapi_.SetFileRefInterfaceDelegate(ppapi_html5_.GetFileRefInterface());
+  ppapi_.SetFileIoInterfaceDelegate(ppapi_html5_.GetFileIoInterface());
+  ppapi_.SetVarInterfaceDelegate(ppapi_html5_.GetVarInterface());
+}
+
+}  // namespace
+
+TEST_F(MountHtml5FsTest, FilesystemType) {
+  const char* filesystem_type_strings[] = {"", "PERSISTENT", "TEMPORARY", NULL};
+  PP_FileSystemType filesystem_type_values[] = {
+      PP_FILESYSTEMTYPE_LOCALPERSISTENT,  // Default to persistent.
+      PP_FILESYSTEMTYPE_LOCALPERSISTENT, PP_FILESYSTEMTYPE_LOCALTEMPORARY};
+
+  const char* expected_size_strings[] = {"100", "12345", NULL};
+  const int expected_size_values[] = {100, 12345};
+
+  FileSystemInterfaceMock* filesystem_mock =
+      ppapi_mock_.GetFileSystemInterface();
+
+  FakeFileSystemInterface* filesystem_fake =
+      static_cast<FakeFileSystemInterface*>(
+          ppapi_html5_.GetFileSystemInterface());
+
+  for (int i = 0; filesystem_type_strings[i] != NULL; ++i) {
+    const char* filesystem_type_string = filesystem_type_strings[i];
+    PP_FileSystemType expected_filesystem_type = filesystem_type_values[i];
+
+    for (int j = 0; expected_size_strings[j] != NULL; ++j) {
+      const char* expected_size_string = expected_size_strings[j];
+      int64_t expected_expected_size = expected_size_values[j];
+
+      ppapi_.SetFileSystemInterfaceDelegate(filesystem_mock);
+
+      ON_CALL(*filesystem_mock, Create(_, _)).WillByDefault(
+          Invoke(filesystem_fake, &FakeFileSystemInterface::Create));
+
+      EXPECT_CALL(*filesystem_mock,
+                  Create(ppapi_.GetInstance(), expected_filesystem_type));
+
+      EXPECT_CALL(*filesystem_mock, Open(_, expected_expected_size, _))
+          .WillOnce(DoAll(CallCallback<2>(int32_t(PP_OK)),
+                          Return(int32_t(PP_OK_COMPLETIONPENDING))));
+
+      StringMap_t map;
+      map["type"] = filesystem_type_string;
+      map["expected_size"] = expected_size_string;
+      ScopedRef<MountHtml5FsForTesting> mnt(
+          new MountHtml5FsForTesting(map, &ppapi_));
+
+      Mock::VerifyAndClearExpectations(&filesystem_mock);
+    }
+  }
+}
+
+TEST_F(MountHtml5FsTest, Access) {
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/foo", NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ASSERT_EQ(0, mnt->Access(Path("/foo"), R_OK | W_OK | X_OK));
+  ASSERT_EQ(ENOENT, mnt->Access(Path("/bar"), F_OK));
+}
+
+TEST_F(MountHtml5FsTest, Mkdir) {
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  // mkdir at the root should return EEXIST, not EACCES.
+  EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/"), 0644));
+
+  Path path("/foo");
+  ASSERT_EQ(ENOENT, mnt->Access(path, F_OK));
+  ASSERT_EQ(0, mnt->Mkdir(path, 0644));
+
+  struct stat stat;
+  ScopedMountNode node;
+  ASSERT_EQ(0, mnt->Open(path, O_RDONLY, &node));
+  EXPECT_EQ(0, node->GetStat(&stat));
+  EXPECT_EQ(S_IFDIR, stat.st_mode & S_IFDIR);
+}
+
+TEST_F(MountHtml5FsTest, Remove) {
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/foo", NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  Path path("/foo");
+  ASSERT_EQ(0, mnt->Access(path, F_OK));
+  ASSERT_EQ(0, mnt->Remove(path));
+  EXPECT_EQ(ENOENT, mnt->Access(path, F_OK));
+}
+
+// Unlink + Rmdir forward to Remove unconditionally, which will not fail if the
+// file type is wrong.
+TEST_F(MountHtml5FsTest, DISABLED_Unlink) {
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/file", NULL));
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ASSERT_EQ(EISDIR, mnt->Unlink(Path("/dir")));
+  EXPECT_EQ(0, mnt->Unlink(Path("/file")));
+  EXPECT_EQ(ENOENT, mnt->Access(Path("/file"), F_OK));
+  EXPECT_EQ(0, mnt->Access(Path("/dir"), F_OK));
+}
+
+// Unlink + Rmdir forward to Remove unconditionally, which will not fail if the
+// file type is wrong.
+TEST_F(MountHtml5FsTest, DISABLED_Rmdir) {
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/file", NULL));
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ASSERT_EQ(ENOTDIR, mnt->Rmdir(Path("/file")));
+  EXPECT_EQ(0, mnt->Rmdir(Path("/dir")));
+  EXPECT_EQ(ENOENT, mnt->Access(Path("/dir"), F_OK));
+  EXPECT_EQ(0, mnt->Access(Path("/file"), F_OK));
+}
+
+TEST_F(MountHtml5FsTest, OpenForCreate) {
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  Path path("/foo");
+  EXPECT_EQ(ENOENT, mnt->Access(path, F_OK));
+
+  ScopedMountNode node;
+  EXPECT_EQ(0, mnt->Open(path, O_CREAT | O_RDWR, &node));
+
+  // Write some data.
+  char contents[] = "contents";
+  int bytes_written = 0;
+  EXPECT_EQ(0, node->Write(0, &contents[0], strlen(contents), &bytes_written));
+  EXPECT_EQ(strlen(contents), bytes_written);
+
+  // Create again.
+  ASSERT_EQ(0, mnt->Open(path, O_CREAT, &node));
+
+  // Check that the file still has data.
+  size_t size;
+  EXPECT_EQ(0, node->GetSize(&size));
+  EXPECT_EQ(strlen(contents), size);
+
+  // Open exclusively.
+  EXPECT_EQ(EEXIST, mnt->Open(path, O_CREAT | O_EXCL, &node));
+
+  // Try to truncate without write access.
+  EXPECT_EQ(EINVAL, mnt->Open(path, O_CREAT | O_TRUNC, &node));
+
+  // Open and truncate.
+  ASSERT_EQ(0, mnt->Open(path, O_CREAT | O_TRUNC | O_WRONLY, &node));
+
+  // File should be empty.
+  EXPECT_EQ(0, node->GetSize(&size));
+  EXPECT_EQ(0, size);
+}
+
+TEST_F(MountHtml5FsTest, Read) {
+  const char contents[] = "contents";
+  EXPECT_TRUE(
+      ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ScopedMountNode node;
+  EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDONLY, &node));
+
+  char buffer[10] = {0};
+  int bytes_read = 0;
+  EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+  EXPECT_EQ(strlen(contents), bytes_read);
+  EXPECT_STREQ(contents, buffer);
+
+  // Read nothing past the end of the file.
+  EXPECT_EQ(0, node->Read(100, &buffer[0], sizeof(buffer), &bytes_read));
+  EXPECT_EQ(0, bytes_read);
+
+  // Read part of the data.
+  EXPECT_EQ(0, node->Read(4, &buffer[0], sizeof(buffer), &bytes_read));
+  ASSERT_EQ(strlen(contents) - 4, bytes_read);
+  buffer[bytes_read] = 0;
+  EXPECT_STREQ("ents", buffer);
+
+  // Writing should fail.
+  int bytes_written = 1;  // Set to a non-zero value.
+  EXPECT_EQ(EACCES, node->Write(0, &buffer[0], sizeof(buffer), &bytes_written));
+  EXPECT_EQ(0, bytes_written);
+
+  // Reading from a directory should fail.
+  EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDONLY, &node));
+  EXPECT_EQ(EISDIR, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+}
+
+TEST_F(MountHtml5FsTest, Write) {
+  const char contents[] = "contents";
+  EXPECT_TRUE(
+      ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ScopedMountNode node;
+  ASSERT_EQ(0, mnt->Open(Path("/file"), O_WRONLY, &node));
+
+  // Reading should fail.
+  char buffer[10];
+  int bytes_read = 1;  // Set to a non-zero value.
+  EXPECT_EQ(EACCES, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+  EXPECT_EQ(0, bytes_read);
+
+  // Reopen as read-write.
+  ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDWR, &node));
+
+  int bytes_written = 1;  // Set to a non-zero value.
+  EXPECT_EQ(0, node->Write(3, "struct", 6, &bytes_written));
+  EXPECT_EQ(6, bytes_written);
+
+  EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+  EXPECT_EQ(9, bytes_read);
+  buffer[bytes_read] = 0;
+  EXPECT_STREQ("construct", buffer);
+
+  // Writing to a directory should fail.
+  EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDWR, &node));
+  EXPECT_EQ(EISDIR, node->Write(0, &buffer[0], sizeof(buffer), &bytes_read));
+}
+
+TEST_F(MountHtml5FsTest, GetStat) {
+  const int creation_time = 1000;
+  const int access_time = 2000;
+  const int modified_time = 3000;
+  const char contents[] = "contents";
+
+  // Create fake file.
+  FakeHtml5FsNode* fake_node;
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddFile(
+      "/file", contents, &fake_node));
+  fake_node->set_creation_time(creation_time);
+  fake_node->set_last_access_time(access_time);
+  fake_node->set_last_modified_time(modified_time);
+
+  // Create fake directory.
+  EXPECT_TRUE(
+      ppapi_html5_.filesystem_template()->AddDirectory("/dir", &fake_node));
+  fake_node->set_creation_time(creation_time);
+  fake_node->set_last_access_time(access_time);
+  fake_node->set_last_modified_time(modified_time);
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ScopedMountNode node;
+  ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDONLY, &node));
+
+  struct stat statbuf;
+  EXPECT_EQ(0, node->GetStat(&statbuf));
+  EXPECT_EQ(S_IFREG | S_IWRITE | S_IREAD, statbuf.st_mode);
+  EXPECT_EQ(strlen(contents), statbuf.st_size);
+  EXPECT_EQ(access_time, statbuf.st_atime);
+  EXPECT_EQ(creation_time, statbuf.st_ctime);
+  EXPECT_EQ(modified_time, statbuf.st_mtime);
+
+  // Test Get* and Isa* methods.
+  size_t size;
+  EXPECT_EQ(0, node->GetSize(&size));
+  EXPECT_EQ(strlen(contents), size);
+  EXPECT_FALSE(node->IsaDir());
+  EXPECT_TRUE(node->IsaFile());
+  EXPECT_FALSE(node->IsaTTY());
+
+  // GetStat on a directory...
+  EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDONLY, &node));
+  EXPECT_EQ(0, node->GetStat(&statbuf));
+  EXPECT_EQ(S_IFDIR | S_IWRITE | S_IREAD, statbuf.st_mode);
+  EXPECT_EQ(0, statbuf.st_size);
+  EXPECT_EQ(access_time, statbuf.st_atime);
+  EXPECT_EQ(creation_time, statbuf.st_ctime);
+  EXPECT_EQ(modified_time, statbuf.st_mtime);
+
+  // Test Get* and Isa* methods.
+  EXPECT_EQ(0, node->GetSize(&size));
+  EXPECT_EQ(0, size);
+  EXPECT_TRUE(node->IsaDir());
+  EXPECT_FALSE(node->IsaFile());
+  EXPECT_FALSE(node->IsaTTY());
+}
+
+TEST_F(MountHtml5FsTest, FTruncate) {
+  const char contents[] = "contents";
+  EXPECT_TRUE(
+      ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+  EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ScopedMountNode node;
+  ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDWR, &node));
+
+  char buffer[10] = {0};
+  int bytes_read = 0;
+
+  // First make the file shorter...
+  EXPECT_EQ(0, node->FTruncate(4));
+  EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+  EXPECT_EQ(4, bytes_read);
+  buffer[bytes_read] = 0;
+  EXPECT_STREQ("cont", buffer);
+
+  // Now make the file longer...
+  EXPECT_EQ(0, node->FTruncate(8));
+  EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+  EXPECT_EQ(8, bytes_read);
+  buffer[bytes_read] = 0;
+  EXPECT_STREQ("cont\0\0\0\0", buffer);
+
+  // Ftruncate should fail for a directory.
+  EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDONLY, &node));
+  EXPECT_EQ(EISDIR, node->FTruncate(4));
+}
+
+TEST_F(MountHtml5FsTest, GetDents) {
+  const char contents[] = "contents";
+  EXPECT_TRUE(
+      ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+
+  StringMap_t map;
+  ScopedRef<MountHtml5FsForTesting> mnt(
+      new MountHtml5FsForTesting(map, &ppapi_));
+
+  ScopedMountNode root;
+  ASSERT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
+
+  ScopedMountNode node;
+  ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDWR, &node));
+
+  // Should fail for regular files.
+  struct dirent dirents[3];
+  int bytes_read = 1;  // Set to a non-zero value.
+
+  memset(&dirents[0], 0, sizeof(dirents));
+  EXPECT_EQ(ENOTDIR,
+            node->GetDents(0, &dirents[0], sizeof(dirents), &bytes_read));
+  EXPECT_EQ(0, bytes_read);
+
+  // Should work with root directory.
+  // +2 to test a size that is not a multiple of sizeof(dirent).
+  // Expect it to round down.
+  memset(&dirents[0], 0, sizeof(dirents));
+  EXPECT_EQ(0, root->GetDents(0, &dirents[0], sizeof(dirent) + 2, &bytes_read));
+  EXPECT_EQ(sizeof(dirent), bytes_read);
+  EXPECT_EQ(sizeof(dirent), dirents[0].d_off);
+  EXPECT_EQ(sizeof(dirent), dirents[0].d_reclen);
+  EXPECT_STREQ("file", dirents[0].d_name);
+
+  // Add another file...
+  ASSERT_EQ(0, mnt->Open(Path("/file2"), O_CREAT, &node));
+
+  // Read the root directory again.
+  memset(&dirents[0], 0, sizeof(dirents));
+  EXPECT_EQ(0, root->GetDents(0, &dirents[0], sizeof(dirents), &bytes_read));
+  EXPECT_EQ(sizeof(dirent) * 2, bytes_read);
+
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_LT(0, dirents[i].d_ino);  // 0 is an invalid ino.
+    EXPECT_EQ(sizeof(dirent), dirents[i].d_off);
+    EXPECT_EQ(sizeof(dirent), dirents[i].d_reclen);
+    // Could be "file" or "file2".
+    EXPECT_TRUE(strncmp("file", dirents[i].d_name, 4) == 0);
+  }
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_http_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_http_test.cc
new file mode 100644
index 0000000..25c907f
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_http_test.cc
@@ -0,0 +1,615 @@
+// 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 <fcntl.h>
+#include <gmock/gmock.h>
+#include <ppapi/c/ppb_file_io.h>
+#include <ppapi/c/pp_errors.h>
+#include <ppapi/c/pp_instance.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "mock_util.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/mount_http.h"
+#include "nacl_io/mount_node_dir.h"
+#include "nacl_io/osdirent.h"
+#include "nacl_io/osunistd.h"
+#include "pepper_interface_mock.h"
+
+using namespace nacl_io;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrEq;
+
+
+class MountHttpMock : public MountHttp {
+ public:
+  MountHttpMock(StringMap_t map, PepperInterfaceMock* ppapi) {
+    EXPECT_EQ(0, Init(1, map, ppapi));
+  }
+
+  ~MountHttpMock() {
+    Destroy();
+  }
+
+  NodeMap_t& GetMap() { return node_cache_; }
+
+  using MountHttp::ParseManifest;
+  using MountHttp::FindOrCreateDir;
+};
+
+class MountHttpTest : public ::testing::Test {
+ public:
+  MountHttpTest();
+  ~MountHttpTest();
+
+ protected:
+  PepperInterfaceMock ppapi_;
+  MountHttpMock* mnt_;
+
+  static const PP_Instance instance_ = 123;
+};
+
+MountHttpTest::MountHttpTest()
+    : ppapi_(instance_),
+      mnt_(NULL) {
+}
+
+MountHttpTest::~MountHttpTest() {
+  delete mnt_;
+}
+
+
+TEST_F(MountHttpTest, MountEmpty) {
+  StringMap_t args;
+  mnt_ = new MountHttpMock(args, &ppapi_);
+}
+
+TEST_F(MountHttpTest, Mkdir) {
+  StringMap_t args;
+  mnt_ = new MountHttpMock(args, &ppapi_);
+  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
+  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
+  // mkdir of existing directories should give "File exists".
+  EXPECT_EQ(EEXIST, mnt_->Mkdir(Path("/"), 0));
+  EXPECT_EQ(EEXIST, mnt_->Mkdir(Path("/mydir"), 0));
+  // mkdir of non-existent directories should give "Permission denied".
+  EXPECT_EQ(EACCES, mnt_->Mkdir(Path("/non_existent"), 0));
+}
+
+TEST_F(MountHttpTest, Rmdir) {
+  StringMap_t args;
+  mnt_ = new MountHttpMock(args, &ppapi_);
+  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
+  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
+  // Rmdir on existing dirs should give "Permission Denied"
+  EXPECT_EQ(EACCES, mnt_->Rmdir(Path("/")));
+  EXPECT_EQ(EACCES, mnt_->Rmdir(Path("/mydir")));
+  // Rmdir on existing files should give "Not a direcotory"
+  EXPECT_EQ(ENOTDIR, mnt_->Rmdir(Path("/mydir/foo")));
+  // Rmdir on non-existent files should give "No such file or directory"
+  EXPECT_EQ(ENOENT, mnt_->Rmdir(Path("/non_existent")));
+}
+
+TEST_F(MountHttpTest, Unlink) {
+  StringMap_t args;
+  mnt_ = new MountHttpMock(args, &ppapi_);
+  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
+  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
+  // Unlink of existing files should give "Permission Denied"
+  EXPECT_EQ(EACCES, mnt_->Unlink(Path("/mydir/foo")));
+  // Unlink of existing directory should give "Is a directory"
+  EXPECT_EQ(EISDIR, mnt_->Unlink(Path("/mydir")));
+  // Unlink of non-existent files should give "No such file or directory"
+  EXPECT_EQ(ENOENT, mnt_->Unlink(Path("/non_existent")));
+}
+
+TEST_F(MountHttpTest, Remove) {
+  StringMap_t args;
+  mnt_ = new MountHttpMock(args, &ppapi_);
+  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
+  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
+  // Remove of existing files should give "Permission Denied"
+  EXPECT_EQ(EACCES, mnt_->Remove(Path("/mydir/foo")));
+  // Remove of existing directory should give "Permission Denied"
+  EXPECT_EQ(EACCES, mnt_->Remove(Path("/mydir")));
+  // Unlink of non-existent files should give "No such file or directory"
+  EXPECT_EQ(ENOENT, mnt_->Remove(Path("/non_existent")));
+}
+
+TEST_F(MountHttpTest, ParseManifest) {
+  StringMap_t args;
+  size_t result_size = 0;
+
+  mnt_ = new MountHttpMock(args, &ppapi_);
+
+  char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
+  EXPECT_EQ(0, mnt_->ParseManifest(manifest));
+
+  ScopedMountNode root;
+  EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/"), &root));
+  ASSERT_NE((MountNode*)NULL, root.get());
+  EXPECT_EQ(2, root->ChildCount());
+
+  ScopedMountNode dir;
+  EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/mydir"), &dir));
+  ASSERT_NE((MountNode*)NULL, dir.get());
+  EXPECT_EQ(1, dir->ChildCount());
+
+  MountNode* node = mnt_->GetMap()["/mydir/foo"].get();
+  EXPECT_NE((MountNode*)NULL, node);
+  EXPECT_EQ(0, node->GetSize(&result_size));
+  EXPECT_EQ(123, result_size);
+
+  // Since these files are cached thanks to the manifest, we can open them
+  // without accessing the PPAPI URL API.
+  ScopedMountNode foo;
+  EXPECT_EQ(0, mnt_->Open(Path("/mydir/foo"), O_RDONLY, &foo));
+
+  ScopedMountNode bar;
+  EXPECT_EQ(0, mnt_->Open(Path("/thatdir/bar"), O_RDWR, &bar));
+
+  struct stat sfoo;
+  struct stat sbar;
+
+  EXPECT_FALSE(foo->GetStat(&sfoo));
+  EXPECT_FALSE(bar->GetStat(&sbar));
+
+  EXPECT_EQ(123, sfoo.st_size);
+  EXPECT_EQ(S_IFREG | S_IREAD, sfoo.st_mode);
+
+  EXPECT_EQ(234, sbar.st_size);
+  EXPECT_EQ(S_IFREG | S_IREAD | S_IWRITE, sbar.st_mode);
+}
+
+
+class MountHttpNodeTest : public MountHttpTest {
+ public:
+  MountHttpNodeTest();
+  virtual void TearDown();
+
+  void SetMountArgs(const StringMap_t& args);
+  void ExpectOpen(const char* method);
+  void ExpectHeaders(const char* headers);
+  void OpenNode();
+  void SetResponse(int status_code, const char* headers);
+  // Set a response code, but expect the request to fail. Certain function calls
+  // expected by SetResponse are not expected here.
+  void SetResponseExpectFail(int status_code, const char* headers);
+  void SetResponseBody(const char* body);
+  void ResetMocks();
+
+ protected:
+  MountHttpMock* mnt_;
+  ScopedMountNode node_;
+
+  CoreInterfaceMock* core_;
+  VarInterfaceMock* var_;
+  URLLoaderInterfaceMock* loader_;
+  URLRequestInfoInterfaceMock* request_;
+  URLResponseInfoInterfaceMock* response_;
+  size_t response_body_offset_;
+
+  static const char path_[];
+  static const char rel_path_[];
+  static const PP_Resource loader_resource_ = 235;
+  static const PP_Resource request_resource_ = 236;
+  static const PP_Resource response_resource_ = 237;
+};
+
+// static
+const char MountHttpNodeTest::path_[] = "/foo";
+// static
+const char MountHttpNodeTest::rel_path_[] = "foo";
+
+MountHttpNodeTest::MountHttpNodeTest()
+    : mnt_(NULL),
+      node_(NULL) {
+}
+
+static PP_Var MakeString(PP_Resource resource) {
+  PP_Var result = { PP_VARTYPE_STRING, 0, {PP_FALSE} };
+  result.value.as_id = resource;
+  return result;
+}
+
+void MountHttpNodeTest::SetMountArgs(const StringMap_t& args) {
+  mnt_ = new MountHttpMock(args, &ppapi_);
+}
+
+void MountHttpNodeTest::ExpectOpen(const char* method) {
+  core_ = ppapi_.GetCoreInterface();
+  loader_ = ppapi_.GetURLLoaderInterface();
+  request_ = ppapi_.GetURLRequestInfoInterface();
+  response_ = ppapi_.GetURLResponseInfoInterface();
+  var_ = ppapi_.GetVarInterface();
+
+  ON_CALL(*request_, SetProperty(request_resource_, _, _))
+      .WillByDefault(Return(PP_TRUE));
+  ON_CALL(*var_, VarFromUtf8(_, _)).WillByDefault(Return(PP_MakeUndefined()));
+
+  EXPECT_CALL(*loader_, Create(instance_)).WillOnce(Return(loader_resource_));
+  EXPECT_CALL(*request_, Create(instance_)).WillOnce(Return(request_resource_));
+
+  PP_Var var_head = MakeString(345);
+  PP_Var var_url = MakeString(346);
+  EXPECT_CALL(*var_, VarFromUtf8(StrEq(method), _)).WillOnce(Return(var_head));
+  EXPECT_CALL(*var_, VarFromUtf8(StrEq(rel_path_), _))
+      .WillOnce(Return(var_url));
+
+#define EXPECT_SET_PROPERTY(NAME, VAR) \
+  EXPECT_CALL(*request_, SetProperty(request_resource_, NAME, VAR))
+
+  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_URL, IsEqualToVar(var_url));
+  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_METHOD, IsEqualToVar(var_head));
+  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, _);
+  EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS, _);
+
+#undef EXPECT_SET_PROPERTY
+
+  EXPECT_CALL(*loader_, Open(loader_resource_, request_resource_, _))
+      .WillOnce(DoAll(CallCallback<2>(int32_t(PP_OK)),
+                      Return(int32_t(PP_OK_COMPLETIONPENDING))));
+  EXPECT_CALL(*loader_, GetResponseInfo(loader_resource_))
+      .WillOnce(Return(response_resource_));
+
+  EXPECT_CALL(*core_, ReleaseResource(loader_resource_));
+  EXPECT_CALL(*core_, ReleaseResource(request_resource_));
+  EXPECT_CALL(*core_, ReleaseResource(response_resource_));
+}
+
+void MountHttpNodeTest::ExpectHeaders(const char* headers) {
+  PP_Var var_headers = MakeString(347);
+  var_ = ppapi_.GetVarInterface();
+  EXPECT_CALL(*var_, VarFromUtf8(StrEq(headers), _))
+      .WillOnce(Return(var_headers));
+
+  EXPECT_CALL(*request_, SetProperty(request_resource_,
+                                     PP_URLREQUESTPROPERTY_HEADERS,
+                                     IsEqualToVar(var_headers))).Times(1);
+}
+
+void MountHttpNodeTest::SetResponse(int status_code, const char* headers) {
+  ON_CALL(*response_, GetProperty(response_resource_, _))
+      .WillByDefault(Return(PP_MakeUndefined()));
+
+  PP_Var var_headers = MakeString(348);
+  EXPECT_CALL(*response_,
+              GetProperty(response_resource_,
+                          PP_URLRESPONSEPROPERTY_STATUSCODE))
+      .WillOnce(Return(PP_MakeInt32(status_code)));
+  EXPECT_CALL(*response_,
+              GetProperty(response_resource_, PP_URLRESPONSEPROPERTY_HEADERS))
+      .WillOnce(Return(var_headers));
+  EXPECT_CALL(*var_, VarToUtf8(IsEqualToVar(var_headers), _))
+      .WillOnce(DoAll(SetArgPointee<1>(strlen(headers)),
+                      Return(headers)));
+}
+
+void MountHttpNodeTest::SetResponseExpectFail(int status_code,
+                                              const char* headers) {
+  ON_CALL(*response_, GetProperty(response_resource_, _))
+      .WillByDefault(Return(PP_MakeUndefined()));
+
+  EXPECT_CALL(*response_,
+              GetProperty(response_resource_,
+                          PP_URLRESPONSEPROPERTY_STATUSCODE))
+      .WillOnce(Return(PP_MakeInt32(status_code)));
+}
+
+ACTION_P3(ReadResponseBodyAction, offset, body, body_length) {
+  char* buf = static_cast<char*>(arg1);
+  size_t read_length = arg2;
+  PP_CompletionCallback callback = arg3;
+  if (*offset >= body_length)
+    return 0;
+
+  read_length = std::min(read_length, body_length - *offset);
+  memcpy(buf, body + *offset, read_length);
+  *offset += read_length;
+
+  // Also call the callback.
+  if (callback.func)
+    (*callback.func)(callback.user_data, PP_OK);
+
+  return read_length;
+}
+
+void MountHttpNodeTest::SetResponseBody(const char* body) {
+  response_body_offset_ = 0;
+  EXPECT_CALL(*loader_, ReadResponseBody(loader_resource_, _, _, _))
+      .WillRepeatedly(ReadResponseBodyAction(
+            &response_body_offset_, body, strlen(body)));
+}
+
+void MountHttpNodeTest::OpenNode() {
+  ASSERT_EQ(0, mnt_->Open(Path(path_), O_RDONLY, &node_));
+  ASSERT_NE((MountNode*)NULL, node_.get());
+}
+
+void MountHttpNodeTest::ResetMocks() {
+  Mock::VerifyAndClearExpectations(&ppapi_);
+  Mock::VerifyAndClearExpectations(loader_);
+  Mock::VerifyAndClearExpectations(request_);
+  Mock::VerifyAndClearExpectations(response_);
+  Mock::VerifyAndClearExpectations(var_);
+}
+
+void MountHttpNodeTest::TearDown() {
+  node_.reset();
+  delete mnt_;
+}
+
+// TODO(binji): These tests are all broken now. In another CL, I'll reimplement
+// these tests using an HTTP fake.
+TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseNoCache) {
+  StringMap_t smap;
+  smap["cache_content"] = "false";
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "");
+  OpenNode();
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseNotFound) {
+  StringMap_t smap;
+  smap["cache_content"] = "false";
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponseExpectFail(404, "");
+  ASSERT_EQ(ENOENT, mnt_->Open(Path(path_), O_RDONLY, &node_));
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseServerError) {
+  StringMap_t smap;
+  smap["cache_content"] = "false";
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponseExpectFail(500, "");
+  ASSERT_EQ(EIO, mnt_->Open(Path(path_), O_RDONLY, &node_));
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_GetStat) {
+  StringMap_t smap;
+  smap["cache_content"] = "false";
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "Content-Length: 42\n");
+  OpenNode();
+
+  struct stat stat;
+  EXPECT_EQ(0, node_->GetStat(&stat));
+  EXPECT_EQ(42, stat.st_size);
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_Access) {
+  StringMap_t smap;
+  smap["cache_content"] = "false";
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "");
+  ASSERT_EQ(0, mnt_->Access(Path(path_), R_OK));
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_AccessWrite) {
+  StringMap_t smap;
+  smap["cache_content"] = "false";
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "");
+  ASSERT_EQ(EACCES, mnt_->Access(Path(path_), W_OK));
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_AccessNotFound) {
+  StringMap_t smap;
+  smap["cache_content"] = "false";
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponseExpectFail(404, "");
+  ASSERT_EQ(ENOENT, mnt_->Access(Path(path_), R_OK));
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_ReadCached) {
+  size_t result_size = 0;
+  int result_bytes = 0;
+
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "Content-Length: 42\n");
+  OpenNode();
+  ResetMocks();
+
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(42, result_size);
+
+  char buf[10];
+  memset(&buf[0], 0, sizeof(buf));
+
+  ExpectOpen("GET");
+  ExpectHeaders("");
+  SetResponse(200, "Content-Length: 42\n");
+  SetResponseBody("Here is some response text. And some more.");
+  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_STREQ("Here is s", &buf[0]);
+  ResetMocks();
+
+  // Further reads should be cached.
+  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_STREQ("Here is s", &buf[0]);
+  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_STREQ("me respon", &buf[0]);
+
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(42, result_size);
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_ReadCachedNoContentLength) {
+  size_t result_size = 0;
+  int result_bytes = 0;
+
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "");
+  OpenNode();
+  ResetMocks();
+
+  ExpectOpen("GET");
+  ExpectHeaders("");
+  SetResponse(200, "");  // No Content-Length response here.
+  SetResponseBody("Here is some response text. And some more.");
+
+  // GetSize will Read() because it didn't get the content length from the HEAD
+  // request.
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(42, result_size);
+
+  char buf[10];
+  memset(&buf[0], 0, sizeof(buf));
+
+  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_STREQ("Here is s", &buf[0]);
+  ResetMocks();
+
+  // Further reads should be cached.
+  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_STREQ("Here is s", &buf[0]);
+  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_STREQ("me respon", &buf[0]);
+
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(42, result_size);
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_ReadCachedUnderrun) {
+  size_t result_size = 0;
+  int result_bytes = 0;
+
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "Content-Length: 100\n");
+  OpenNode();
+  ResetMocks();
+
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(100, result_size);
+
+  char buf[10];
+  memset(&buf[0], 0, sizeof(buf));
+
+  ExpectOpen("GET");
+  ExpectHeaders("");
+  SetResponse(200, "Content-Length: 100\n");
+  SetResponseBody("abcdefghijklmnopqrstuvwxyz");
+  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
+  EXPECT_STREQ("abcdefghi", &buf[0]);
+  ResetMocks();
+
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(26, result_size);
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_ReadCachedOverrun) {
+  size_t result_size = 0;
+  int result_bytes = 0;
+
+  SetMountArgs(StringMap_t());
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "Content-Length: 15\n");
+  OpenNode();
+  ResetMocks();
+
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(15, result_size);
+
+  char buf[10];
+  memset(&buf[0], 0, sizeof(buf));
+
+  ExpectOpen("GET");
+  ExpectHeaders("");
+  SetResponse(200, "Content-Length: 15\n");
+  SetResponseBody("01234567890123456789");
+  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_EQ(5, result_bytes);
+  EXPECT_STREQ("01234", &buf[0]);
+  ResetMocks();
+
+  EXPECT_EQ(0, node_->GetSize(&result_size));
+  EXPECT_EQ(15, result_size);
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_ReadPartial) {
+  int result_bytes = 0;
+
+  StringMap_t args;
+  args["cache_content"] = "false";
+  SetMountArgs(args);
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "");
+  OpenNode();
+  ResetMocks();
+
+  char buf[10];
+  memset(&buf[0], 0, sizeof(buf));
+
+  ExpectOpen("GET");
+  ExpectHeaders("Range: bytes=0-8\n");
+  SetResponse(206, "Content-Length: 9\nContent-Range: bytes=0-8\n");
+  SetResponseBody("012345678");
+  EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
+  EXPECT_STREQ("012345678", &buf[0]);
+  ResetMocks();
+
+  // Another read is another request.
+  ExpectOpen("GET");
+  ExpectHeaders("Range: bytes=10-18\n");
+  SetResponse(206, "Content-Length: 9\nContent-Range: bytes=10-18\n");
+  SetResponseBody("abcdefghi");
+  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
+  EXPECT_STREQ("abcdefghi", &buf[0]);
+}
+
+TEST_F(MountHttpNodeTest, DISABLED_ReadPartialNoServerSupport) {
+  int result_bytes = 0;
+
+  StringMap_t args;
+  args["cache_content"] = "false";
+  SetMountArgs(args);
+  ExpectOpen("HEAD");
+  ExpectHeaders("");
+  SetResponse(200, "");
+  OpenNode();
+  ResetMocks();
+
+  char buf[10];
+  memset(&buf[0], 0, sizeof(buf));
+
+  ExpectOpen("GET");
+  ExpectHeaders("Range: bytes=10-18\n");
+  SetResponse(200, "Content-Length: 20\n");
+  SetResponseBody("0123456789abcdefghij");
+  EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+  EXPECT_EQ(sizeof(buf) - 1, result_bytes);
+  EXPECT_STREQ("abcdefghi", &buf[0]);
+}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc b/native_client_sdk/src/tests/nacl_io_test/mount_mock.cc
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc
rename to native_client_sdk/src/tests/nacl_io_test/mount_mock.cc
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.h b/native_client_sdk/src/tests/nacl_io_test/mount_mock.h
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/mount_mock.h
rename to native_client_sdk/src/tests/nacl_io_test/mount_mock.h
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_mock.cc
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc
rename to native_client_sdk/src/tests/nacl_io_test/mount_node_mock.cc
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h b/native_client_sdk/src/tests/nacl_io_test/mount_node_mock.h
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h
rename to native_client_sdk/src/tests/nacl_io_test/mount_node_mock.h
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
new file mode 100644
index 0000000..962c3d0
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
@@ -0,0 +1,174 @@
+// 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 <errno.h>
+#include <fcntl.h>
+
+#include "gtest/gtest.h"
+
+#include "nacl_io/error.h"
+#include "nacl_io/ioctl.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/mount_dev.h"
+#include "nacl_io/mount_node.h"
+#include "nacl_io/mount_node_dir.h"
+#include "nacl_io/mount_node_mem.h"
+#include "nacl_io/osdirent.h"
+
+#define NULL_NODE ((MountNode*) NULL)
+
+using namespace nacl_io;
+
+static int s_AllocNum = 0;
+
+class MockMemory : public MountNodeMem {
+ public:
+  MockMemory() : MountNodeMem(NULL) { s_AllocNum++; }
+
+  ~MockMemory() { s_AllocNum--; }
+
+  using MountNodeMem::Init;
+  using MountNodeMem::AddChild;
+  using MountNodeMem::RemoveChild;
+  using MountNodeMem::FindChild;
+};
+
+class MockDir : public MountNodeDir {
+ public:
+  MockDir() : MountNodeDir(NULL) { s_AllocNum++; }
+
+  ~MockDir() { s_AllocNum--; }
+
+  using MountNodeDir::Init;
+  using MountNodeDir::AddChild;
+  using MountNodeDir::RemoveChild;
+  using MountNodeDir::FindChild;
+};
+
+TEST(MountNodeTest, File) {
+  MockMemory file;
+  ScopedMountNode result_node;
+  size_t result_size = 0;
+  int result_bytes = 0;
+
+  EXPECT_EQ(0, file.Init(S_IREAD | S_IWRITE));
+
+  // Test properties
+  EXPECT_EQ(0, file.GetLinks());
+  EXPECT_EQ(S_IREAD | S_IWRITE, file.GetMode());
+  EXPECT_EQ(S_IFREG, file.GetType());
+  EXPECT_FALSE(file.IsaDir());
+  EXPECT_TRUE(file.IsaFile());
+  EXPECT_FALSE(file.IsaTTY());
+  EXPECT_EQ(0, file.RefCount());
+
+  // Test IO
+  char buf1[1024];
+  char buf2[1024 * 2];
+  for (size_t a = 0; a < sizeof(buf1); a++)
+    buf1[a] = a;
+  memset(buf2, 0, sizeof(buf2));
+
+  EXPECT_EQ(0, file.GetSize(&result_size));
+  EXPECT_EQ(0, result_size);
+  EXPECT_EQ(0, file.Read(0, buf2, sizeof(buf2), &result_bytes));
+  EXPECT_EQ(0, result_bytes);
+  EXPECT_EQ(0, file.GetSize(&result_size));
+  EXPECT_EQ(0, result_size);
+  EXPECT_EQ(0, file.Write(0, buf1, sizeof(buf1), &result_bytes));
+  EXPECT_EQ(sizeof(buf1), result_bytes);
+  EXPECT_EQ(0, file.GetSize(&result_size));
+  EXPECT_EQ(sizeof(buf1), result_size);
+  EXPECT_EQ(0, file.Read(0, buf2, sizeof(buf2), &result_bytes));
+  EXPECT_EQ(sizeof(buf1), result_bytes);
+  EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
+
+  struct stat s;
+  EXPECT_EQ(0, file.GetStat(&s));
+  EXPECT_LT(0, s.st_ino);  // 0 is an invalid inode number.
+  EXPECT_EQ(sizeof(buf1), s.st_size);
+
+  // Directory operations should fail
+  struct dirent d;
+  EXPECT_EQ(ENOTDIR, file.GetDents(0, &d, sizeof(d), &result_bytes));
+  EXPECT_EQ(ENOTDIR, file.AddChild("", result_node));
+  EXPECT_EQ(ENOTDIR, file.RemoveChild(""));
+  EXPECT_EQ(ENOTDIR, file.FindChild("", &result_node));
+  EXPECT_EQ(NULL_NODE, result_node.get());
+}
+
+TEST(MountNodeTest, Directory) {
+  s_AllocNum = 0;
+  MockDir root;
+  ScopedMountNode result_node;
+  size_t result_size = 0;
+  int result_bytes = 0;
+
+  root.Init(S_IREAD | S_IWRITE);
+
+  // Test properties
+  EXPECT_EQ(0, root.GetLinks());
+  EXPECT_EQ(S_IREAD | S_IWRITE, root.GetMode());
+  EXPECT_EQ(S_IFDIR, root.GetType());
+  EXPECT_TRUE(root.IsaDir());
+  EXPECT_FALSE(root.IsaFile());
+  EXPECT_FALSE(root.IsaTTY());
+  EXPECT_EQ(0, root.RefCount());
+
+  // IO operations should fail
+  char buf1[1024];
+  EXPECT_EQ(0, root.GetSize(&result_size));
+  EXPECT_EQ(0, result_size);
+  EXPECT_EQ(EISDIR, root.Read(0, buf1, sizeof(buf1), &result_bytes));
+  EXPECT_EQ(EISDIR, root.Write(0, buf1, sizeof(buf1), &result_bytes));
+
+  // Test directory operations
+  MockMemory* raw_file = new MockMemory;
+  EXPECT_EQ(0, raw_file->Init(S_IREAD | S_IWRITE));
+  ScopedMountNode file(raw_file);
+
+  EXPECT_EQ(0, root.RefCount());
+  EXPECT_EQ(1, file->RefCount());
+  EXPECT_EQ(0, root.AddChild("F1", file));
+  EXPECT_EQ(1, file->GetLinks());
+  EXPECT_EQ(2, file->RefCount());
+
+  // Test that the directory is there
+  struct dirent d;
+  EXPECT_EQ(0, root.GetDents(0, &d, sizeof(d), &result_bytes));
+  EXPECT_EQ(sizeof(d), result_bytes);
+  EXPECT_LT(0, d.d_ino);  // 0 is an invalid inode number.
+  EXPECT_EQ(sizeof(d), d.d_off);
+  EXPECT_EQ(sizeof(d), d.d_reclen);
+  EXPECT_EQ(0, strcmp("F1", d.d_name));
+  EXPECT_EQ(0, root.GetDents(sizeof(d), &d, sizeof(d), &result_bytes));
+  EXPECT_EQ(0, result_bytes);
+
+  EXPECT_EQ(0, root.AddChild("F2", file));
+  EXPECT_EQ(2, file->GetLinks());
+  EXPECT_EQ(3, file->RefCount());
+  EXPECT_EQ(EEXIST, root.AddChild("F1", file));
+  EXPECT_EQ(2, file->GetLinks());
+  EXPECT_EQ(3, file->RefCount());
+
+  EXPECT_EQ(2, s_AllocNum);
+  EXPECT_EQ(0, root.FindChild("F1", &result_node));
+  EXPECT_NE(NULL_NODE, result_node.get());
+  EXPECT_EQ(0, root.FindChild("F2", &result_node));
+  EXPECT_NE(NULL_NODE, result_node.get());
+  EXPECT_EQ(ENOENT, root.FindChild("F3", &result_node));
+  EXPECT_EQ(NULL_NODE, result_node.get());
+
+  EXPECT_EQ(2, s_AllocNum);
+  EXPECT_EQ(0, root.RemoveChild("F1"));
+  EXPECT_EQ(1, file->GetLinks());
+  EXPECT_EQ(2, file->RefCount());
+  EXPECT_EQ(0, root.RemoveChild("F2"));
+  EXPECT_EQ(0, file->GetLinks());
+  EXPECT_EQ(1, file->RefCount());
+  EXPECT_EQ(2, s_AllocNum);
+
+  file.reset();
+  EXPECT_EQ(1, s_AllocNum);
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc
new file mode 100644
index 0000000..c9a67cd
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc
@@ -0,0 +1,249 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "mount_dev_mock.h"
+#include "nacl_io/ioctl.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_dev.h"
+#include "nacl_io/mount_mem.h"
+#include "nacl_io/osdirent.h"
+
+using namespace nacl_io;
+
+namespace {
+
+class TtyTest : public ::testing::Test {
+ public:
+  void SetUp() {
+    ki_init(&kp_);
+    ASSERT_EQ(0, mnt_.Access(Path("/tty"), R_OK | W_OK));
+    ASSERT_EQ(EACCES, mnt_.Access(Path("/tty"), X_OK));
+    ASSERT_EQ(0, mnt_.Open(Path("/tty"), O_RDWR, &dev_tty_));
+    ASSERT_NE(NULL_NODE, dev_tty_.get());
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+ protected:
+  KernelProxy kp_;
+  MountDevMock mnt_;
+  ScopedMountNode dev_tty_;
+};
+
+TEST_F(TtyTest, InvalidIoctl) {
+  // 123 is not a valid ioctl request.
+  EXPECT_EQ(EINVAL, dev_tty_->Ioctl(123, NULL));
+}
+
+TEST_F(TtyTest, TtyInput) {
+  // Now let's try sending some data over.
+  // First we create the message.
+  std::string message("hello, how are you?\n");
+  struct tioc_nacl_input_string packaged_message;
+  packaged_message.length = message.size();
+  packaged_message.buffer = message.data();
+
+  // Now we make buffer we'll read into.
+  // We fill the buffer and a backup buffer with arbitrary data
+  // and compare them after reading to make sure read doesn't
+  // clobber parts of the buffer it shouldn't.
+  int bytes_read;
+  char buffer[100];
+  char backup_buffer[100];
+  memset(buffer, 'a', 100);
+  memset(backup_buffer, 'a', 100);
+
+  // Now we actually send the data
+  EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLINPUT,
+                               reinterpret_cast<char*>(&packaged_message)));
+
+  // We read a small chunk first to ensure it doesn't give us
+  // more than we ask for.
+  EXPECT_EQ(0, dev_tty_->Read(0, buffer, 5, &bytes_read));
+  EXPECT_EQ(bytes_read, 5);
+  EXPECT_EQ(0, memcmp(message.data(), buffer, 5));
+  EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
+
+  // Now we ask for more data than is left in the tty, to ensure
+  // it doesn't give us more than is there.
+  EXPECT_EQ(0, dev_tty_->Read(0, buffer + 5, 95, &bytes_read));
+  EXPECT_EQ(bytes_read, message.size() - 5);
+  EXPECT_EQ(0, memcmp(message.data(), buffer, message.size()));
+  EXPECT_EQ(0, memcmp(buffer + message.size(),
+                      backup_buffer + message.size(),
+                      100 - message.size()));
+}
+
+struct user_data_t {
+  const char* output_buf;
+  size_t output_count;
+};
+
+static ssize_t output_handler(const char* buf, size_t count, void* data) {
+  user_data_t* user_data = static_cast<user_data_t*>(data);
+  user_data->output_buf = buf;
+  user_data->output_count = count;
+  return count;
+}
+
+TEST_F(TtyTest, TtyOutput) {
+  // When no handler is registered then all writes should return EIO
+  int bytes_written = 10;
+  const char* message = "hello\n";
+  int message_len = strlen(message);
+  EXPECT_EQ(EIO, dev_tty_->Write(0, message, message_len, &bytes_written));
+
+  // Setup output handler with user_data to record calls.
+  user_data_t user_data;
+  user_data.output_buf = NULL;
+  user_data.output_count = 0;
+
+  tioc_nacl_output handler;
+  handler.handler = output_handler;
+  handler.user_data = &user_data;
+
+  EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLOUTPUT,
+                               reinterpret_cast<char*>(&handler)));
+
+  EXPECT_EQ(0, dev_tty_->Write(0, message, message_len, &bytes_written));
+  EXPECT_EQ(message_len, bytes_written);
+  EXPECT_EQ(message_len, user_data.output_count);
+  EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len));
+}
+
+// Returns:
+//   0 -> Not readable
+//   1 -> Readable
+//  -1 -> Error occured
+static int IsReadable(int fd) {
+  struct timeval timeout = { 0, 0 };
+  fd_set readfds;
+  fd_set errorfds;
+  FD_ZERO(&readfds);
+  FD_ZERO(&errorfds);
+  FD_SET(fd, &readfds);
+  FD_SET(fd, &errorfds);
+  int rtn = ki_select(fd + 1, &readfds, NULL, &errorfds, &timeout);
+  if (rtn == 0)
+    return 0; // not readable
+  if (rtn != 1)
+    return -1; // error
+  if (FD_ISSET(fd, &errorfds))
+    return -1; // error
+  if (!FD_ISSET(fd, &readfds))
+    return -1; // error
+  return 1; // readable
+}
+
+TEST_F(TtyTest, TtySelect) {
+  struct timeval timeout;
+  fd_set readfds;
+  fd_set writefds;
+  fd_set errorfds;
+
+  int tty_fd = ki_open("/dev/tty", O_RDONLY);
+  ASSERT_TRUE(tty_fd >= 0) << "tty open failed: " << errno;
+
+  FD_ZERO(&readfds);
+  FD_ZERO(&errorfds);
+  FD_SET(tty_fd, &readfds);
+  FD_SET(tty_fd, &errorfds);
+  // 10 millisecond timeout
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 10 * 1000;
+  // Should timeout when no input is available.
+  int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
+  ASSERT_EQ(rtn, 0) << "select failed: " << rtn << " err=" << strerror(errno);
+  ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
+  ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
+
+  FD_ZERO(&readfds);
+  FD_ZERO(&writefds);
+  FD_ZERO(&errorfds);
+  FD_SET(tty_fd, &readfds);
+  FD_SET(tty_fd, &writefds);
+  FD_SET(tty_fd, &errorfds);
+  // TTY should be writable on startup.
+  rtn = ki_select(tty_fd + 1, &readfds, &writefds, &errorfds, NULL);
+  ASSERT_EQ(rtn, 1);
+  ASSERT_TRUE(FD_ISSET(tty_fd, &writefds));
+  ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
+  ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
+
+  // Send 4 bytes to TTY input
+  struct tioc_nacl_input_string input;
+  input.buffer = "input:test";
+  input.length = strlen(input.buffer);
+  char* ioctl_arg = reinterpret_cast<char*>(&input);
+  ASSERT_EQ(0, ki_ioctl(tty_fd, TIOCNACLINPUT, ioctl_arg));
+
+  // TTY should not be readable until newline in written
+  ASSERT_EQ(IsReadable(tty_fd), 0);
+
+  input.buffer = "input:\n";
+  input.length = strlen(input.buffer);
+  ASSERT_EQ(0, ki_ioctl(tty_fd, TIOCNACLINPUT, ioctl_arg));
+
+  // TTY should now be readable
+  ASSERT_EQ(IsReadable(tty_fd), 1);
+
+  ki_close(tty_fd);
+}
+
+int g_recieved_signal = 0;
+
+void sighandler(int sig) {
+  g_recieved_signal = sig;
+}
+
+TEST_F(TtyTest, WindowSize) {
+  // Get current window size
+  struct winsize old_winsize = { 0 };
+  ASSERT_EQ(0, dev_tty_->Ioctl(TIOCGWINSZ,
+                               reinterpret_cast<char*>(&old_winsize)));
+
+  // Install signal handler
+  sighandler_t new_handler = sighandler;
+  sighandler_t old_handler = ki_signal(SIGWINCH, new_handler);
+  ASSERT_NE(old_handler, SIG_ERR) << "signal return error: " << errno;
+
+  // Set a new windows size
+  struct winsize winsize;
+  winsize.ws_col = 100;
+  winsize.ws_row = 200;
+  EXPECT_EQ(0, dev_tty_->Ioctl(TIOCSWINSZ,
+                               reinterpret_cast<char*>(&winsize)));
+  EXPECT_EQ(g_recieved_signal, SIGWINCH);
+
+  // Restore old signal handler
+  EXPECT_EQ(new_handler, ki_signal(SIGWINCH, old_handler));
+
+  // Verify new window size can be queried correctly.
+  winsize.ws_col = 0;
+  winsize.ws_row = 0;
+  EXPECT_EQ(0, dev_tty_->Ioctl(TIOCGWINSZ,
+                               reinterpret_cast<char*>(&winsize)));
+  EXPECT_EQ(winsize.ws_col, 100);
+  EXPECT_EQ(winsize.ws_row, 200);
+
+  // Restore original windows size.
+  EXPECT_EQ(0, dev_tty_->Ioctl(TIOCSWINSZ,
+                               reinterpret_cast<char*>(&old_winsize)));
+}
+
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_test.cc
new file mode 100644
index 0000000..ce3475e
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_test.cc
@@ -0,0 +1,293 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "mount_dev_mock.h"
+#include "nacl_io/ioctl.h"
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_mem.h"
+#include "nacl_io/osdirent.h"
+#include "nacl_io/osunistd.h"
+
+using namespace nacl_io;
+
+namespace {
+
+class MountMemMock : public MountMem {
+ public:
+  MountMemMock() {
+    StringMap_t map;
+    EXPECT_EQ(0, Init(1, map, NULL));
+  }
+
+  int num_nodes() { return (int) inode_pool_.size(); }
+};
+
+}  // namespace
+
+TEST(MountTest, Sanity) {
+  MountMemMock mnt;
+
+  ScopedMountNode file;
+  ScopedMountNode root;
+  ScopedMountNode result_node;
+
+  size_t result_size = 0;
+  int result_bytes = 0;
+  char buf1[1024];
+
+  // A memory mount starts with one directory node: the root.
+  EXPECT_EQ(1, mnt.num_nodes());
+
+  // Fail to open non existent file
+  EXPECT_EQ(ENOENT, mnt.Access(Path("/foo"), R_OK | W_OK));
+  EXPECT_EQ(ENOENT, mnt.Open(Path("/foo"), O_RDWR, &result_node));
+  EXPECT_EQ(NULL, result_node.get());
+  EXPECT_EQ(1, mnt.num_nodes());
+
+  // Create a file
+  EXPECT_EQ(0, mnt.Open(Path("/foo"), O_RDWR | O_CREAT, &file));
+  EXPECT_NE(NULL_NODE, file.get());
+  if (file == NULL)
+    return;
+
+  // We now have a directory and a file.  The file has a two references
+  // one returned to the test, one for the name->inode map.
+  EXPECT_EQ(2, mnt.num_nodes());
+  EXPECT_EQ(2, file->RefCount());
+  EXPECT_EQ(0, mnt.Access(Path("/foo"), R_OK | W_OK));
+  EXPECT_EQ(EACCES, mnt.Access(Path("/foo"), X_OK));
+
+  // Write access should be allowed on the root directory.
+  EXPECT_EQ(0, mnt.Access(Path("/"), R_OK | W_OK));
+  EXPECT_EQ(EACCES, mnt.Access(Path("/"), X_OK));
+  // Open the root directory for write should fail.
+  EXPECT_EQ(EISDIR, mnt.Open(Path("/"), O_RDWR, &root));
+  EXPECT_EQ(2, mnt.num_nodes());
+
+  // Open the root directory, should not create a new file
+  EXPECT_EQ(0, mnt.Open(Path("/"), O_RDONLY, &root));
+  EXPECT_EQ(2, mnt.num_nodes());
+  EXPECT_NE(NULL_NODE, root.get());
+  if (NULL != root) {
+    struct dirent dirs[2];
+    int len;
+    EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
+    EXPECT_EQ(sizeof(struct dirent), len);
+  }
+
+  // Fail to re-create the same file
+  EXPECT_EQ(EEXIST,
+            mnt.Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
+  EXPECT_EQ(NULL_NODE, result_node.get());
+  EXPECT_EQ(2, mnt.num_nodes());
+
+  // Fail to create a directory with the same name
+  EXPECT_EQ(EEXIST, mnt.Mkdir(Path("/foo"), O_RDWR));
+  EXPECT_EQ(2, mnt.num_nodes());
+
+  // Attempt to READ/WRITE
+  EXPECT_EQ(0, file->GetSize(&result_size));
+  EXPECT_EQ(0, result_size);
+  EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
+  EXPECT_EQ(sizeof(buf1), result_bytes);
+  EXPECT_EQ(0, file->GetSize(&result_size));
+  EXPECT_EQ(sizeof(buf1), result_size);
+  EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes));
+  EXPECT_EQ(sizeof(buf1), result_bytes);
+  EXPECT_EQ(2, mnt.num_nodes());
+  EXPECT_EQ(2, file->RefCount());
+
+  // Attempt to open the same file, create another ref to it, but does not
+  // create a new file.
+  EXPECT_EQ(0, mnt.Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
+  EXPECT_EQ(3, file->RefCount());
+  EXPECT_EQ(2, mnt.num_nodes());
+  EXPECT_EQ(file.get(), result_node.get());
+  EXPECT_EQ(0, file->GetSize(&result_size));
+  EXPECT_EQ(sizeof(buf1), result_size);
+
+  // Remove our references so that only the Mount holds it
+  file.reset();
+  result_node.reset();
+  EXPECT_EQ(2, mnt.num_nodes());
+
+  // This should have deleted the object
+  EXPECT_EQ(0, mnt.Unlink(Path("/foo")));
+  EXPECT_EQ(1, mnt.num_nodes());
+
+  // We should fail to find it
+  EXPECT_EQ(ENOENT, mnt.Unlink(Path("/foo")));
+  EXPECT_EQ(1, mnt.num_nodes());
+
+  // Recreate foo as a directory
+  EXPECT_EQ(0, mnt.Mkdir(Path("/foo"), O_RDWR));
+  EXPECT_EQ(2, mnt.num_nodes());
+
+  // Create a file (exclusively)
+  EXPECT_EQ(0, mnt.Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
+  EXPECT_NE(NULL_NODE, file.get());
+  if (NULL == file)
+    return;
+  EXPECT_EQ(2, file->RefCount());
+  EXPECT_EQ(3, mnt.num_nodes());
+
+  // Attempt to delete the directory and fail
+  EXPECT_EQ(ENOTEMPTY, mnt.Rmdir(Path("/foo")));
+  EXPECT_EQ(2, root->RefCount());
+  EXPECT_EQ(2, file->RefCount());
+  EXPECT_EQ(3, mnt.num_nodes());
+
+  // Unlink the file, we should have the only file ref at this point.
+  EXPECT_EQ(0, mnt.Unlink(Path("/foo/bar")));
+  EXPECT_EQ(2, root->RefCount());
+  EXPECT_EQ(1, file->RefCount());
+  EXPECT_EQ(3, mnt.num_nodes());
+
+
+  // Deref the file, to make it go away
+  file.reset();
+  EXPECT_EQ(2, mnt.num_nodes());
+
+  // Deref the directory
+  EXPECT_EQ(0, mnt.Rmdir(Path("/foo")));
+  EXPECT_EQ(1, mnt.num_nodes());
+
+  // Verify the directory is gone
+  EXPECT_EQ(ENOENT, mnt.Access(Path("/foo"), F_OK));
+  EXPECT_EQ(ENOENT, mnt.Open(Path("/foo"), O_RDWR, &file));
+  EXPECT_EQ(NULL_NODE, file.get());
+}
+
+TEST(MountTest, MemMountRemove) {
+  MountMemMock mnt;
+  ScopedMountNode file;
+  ScopedMountNode result_node;
+
+  EXPECT_EQ(0, mnt.Mkdir(Path("/dir"), O_RDWR));
+  EXPECT_EQ(0, mnt.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
+  EXPECT_NE(NULL_NODE, file.get());
+  EXPECT_EQ(3, mnt.num_nodes());
+  file.reset();
+
+  EXPECT_EQ(0, mnt.Remove(Path("/dir")));
+  EXPECT_EQ(2, mnt.num_nodes());
+  EXPECT_EQ(0, mnt.Remove(Path("/file")));
+  EXPECT_EQ(1, mnt.num_nodes());
+
+  EXPECT_EQ(ENOENT,
+            mnt.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
+  EXPECT_EQ(NULL_NODE, result_node.get());
+  EXPECT_EQ(ENOENT, mnt.Open(Path("/file"), O_RDONLY, &result_node));
+  EXPECT_EQ(NULL_NODE, result_node.get());
+}
+
+TEST(MountTest, DevAccess) {
+  // Should not be able to open non-existent file.
+  MountDevMock mnt;
+  ASSERT_EQ(ENOENT, mnt.Access(Path("/foo"), F_OK));
+}
+
+TEST(MountTest, DevNull) {
+  MountDevMock mnt;
+  ScopedMountNode dev_null;
+  int result_bytes = 0;
+
+  ASSERT_EQ(0, mnt.Access(Path("/null"), R_OK | W_OK));
+  ASSERT_EQ(EACCES, mnt.Access(Path("/null"), X_OK));
+  ASSERT_EQ(0, mnt.Open(Path("/null"), O_RDWR, &dev_null));
+  ASSERT_NE(NULL_NODE, dev_null.get());
+
+  // Writing to /dev/null should write everything.
+  const char msg[] = "Dummy test message.";
+  EXPECT_EQ(0, dev_null->Write(0, &msg[0], strlen(msg), &result_bytes));
+  EXPECT_EQ(strlen(msg), result_bytes);
+
+  // Reading from /dev/null should read nothing.
+  const int kBufferLength = 100;
+  char buffer[kBufferLength];
+  EXPECT_EQ(0, dev_null->Read(0, &buffer[0], kBufferLength, &result_bytes));
+  EXPECT_EQ(0, result_bytes);
+}
+
+TEST(MountTest, DevZero) {
+  MountDevMock mnt;
+  ScopedMountNode dev_zero;
+  int result_bytes = 0;
+
+  ASSERT_EQ(0, mnt.Access(Path("/zero"), R_OK | W_OK));
+  ASSERT_EQ(EACCES, mnt.Access(Path("/zero"), X_OK));
+  ASSERT_EQ(0, mnt.Open(Path("/zero"), O_RDWR, &dev_zero));
+  ASSERT_NE(NULL_NODE, dev_zero.get());
+
+  // Writing to /dev/zero should write everything.
+  const char msg[] = "Dummy test message.";
+  EXPECT_EQ(0, dev_zero->Write(0, &msg[0], strlen(msg), &result_bytes));
+  EXPECT_EQ(strlen(msg), result_bytes);
+
+  // Reading from /dev/zero should read all zeroes.
+  const int kBufferLength = 100;
+  char buffer[kBufferLength];
+  // First fill with all 1s.
+  memset(&buffer[0], 0x1, kBufferLength);
+  EXPECT_EQ(0, dev_zero->Read(0, &buffer[0], kBufferLength, &result_bytes));
+  EXPECT_EQ(kBufferLength, result_bytes);
+
+  char zero_buffer[kBufferLength];
+  memset(&zero_buffer[0], 0, kBufferLength);
+  EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
+}
+
+// Disabled due to intermittent failures on linux: http://crbug.com/257257
+TEST(MountTest, DISABLED_DevUrandom) {
+  MountDevMock mnt;
+  ScopedMountNode dev_urandom;
+  int result_bytes = 0;
+
+  ASSERT_EQ(0, mnt.Access(Path("/urandom"), R_OK | W_OK));
+  ASSERT_EQ(EACCES, mnt.Access(Path("/urandom"), X_OK));
+  ASSERT_EQ(0, mnt.Open(Path("/urandom"), O_RDWR, &dev_urandom));
+  ASSERT_NE(NULL_NODE, dev_urandom.get());
+
+  // Writing to /dev/urandom should write everything.
+  const char msg[] = "Dummy test message.";
+  EXPECT_EQ(0, dev_urandom->Write(0, &msg[0], strlen(msg), &result_bytes));
+  EXPECT_EQ(strlen(msg), result_bytes);
+
+  // Reading from /dev/urandom should read random bytes.
+  const int kSampleBatches = 1000;
+  const int kSampleBatchSize = 1000;
+  const int kTotalSamples = kSampleBatches * kSampleBatchSize;
+
+  int byte_count[256] = {0};
+
+  unsigned char buffer[kSampleBatchSize];
+  for (int batch = 0; batch < kSampleBatches; ++batch) {
+    int bytes_read = 0;
+    EXPECT_EQ(0,
+              dev_urandom->Read(0, &buffer[0], kSampleBatchSize, &bytes_read));
+    EXPECT_EQ(kSampleBatchSize, bytes_read);
+
+    for (int i = 0; i < bytes_read; ++i) {
+      byte_count[buffer[i]]++;
+    }
+  }
+
+  double expected_count = kTotalSamples / 256.;
+  double chi_squared = 0;
+  for (int i = 0; i < 256; ++i) {
+    double difference = byte_count[i] - expected_count;
+    chi_squared += difference * difference / expected_count;
+  }
+
+  // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
+  EXPECT_LE(chi_squared, 293.24);
+}
+
diff --git a/native_client_sdk/src/tests/nacl_io_test/path_test.cc b/native_client_sdk/src/tests/nacl_io_test/path_test.cc
new file mode 100644
index 0000000..29dce11
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/path_test.cc
@@ -0,0 +1,261 @@
+// 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 <fcntl.h>
+
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/path.h"
+
+using namespace nacl_io;
+
+TEST(PathTest, SanityChecks) {
+  // can we construct and delete?
+  Path ph1(".");
+  Path *ph2 = new Path(".");
+  delete ph2;
+
+  Path p1(".");
+  EXPECT_FALSE(p1.IsAbsolute());
+  EXPECT_EQ(".", p1.Join());
+  Path p2("/");
+  EXPECT_TRUE(p2.IsAbsolute());
+  EXPECT_EQ("/", p2.Join());
+}
+
+TEST(PathTest, Assignment) {
+  Path empty;
+  Path dot(".");
+  Path root("/");
+  Path abs_str("/abs/from/string");
+  Path rel_str("rel/from/string");
+  Path self_str("./rel/from/string");
+
+  EXPECT_EQ(0, empty.Size());
+  EXPECT_FALSE(empty.IsAbsolute());
+  EXPECT_EQ(std::string(""), empty.Join());
+
+  EXPECT_EQ(1, dot.Size());
+  EXPECT_FALSE(dot.IsAbsolute());
+  EXPECT_EQ(std::string("."), dot.Join());
+
+  EXPECT_EQ(1, root.Size());
+  EXPECT_TRUE(root.IsAbsolute());
+  EXPECT_EQ(std::string("/"), root.Join());
+
+  EXPECT_EQ(4, abs_str.Size());
+  EXPECT_TRUE(abs_str.IsAbsolute());
+  EXPECT_EQ(std::string("/abs/from/string"), abs_str.Join());
+
+  EXPECT_EQ(3, rel_str.Size());
+  EXPECT_FALSE(rel_str.IsAbsolute());
+  EXPECT_EQ(std::string("rel/from/string"), rel_str.Join());
+
+  EXPECT_EQ(3, self_str.Size());
+  EXPECT_FALSE(self_str.IsAbsolute());
+  EXPECT_EQ(std::string("rel/from/string"), self_str.Join());
+
+  empty = "";
+  dot = ".";
+  root = "/";
+  abs_str = "/abs/from/assign";
+  rel_str = "rel/from/assign";
+  self_str = "./rel/from/assign";
+
+  EXPECT_EQ(1, empty.Size());
+  EXPECT_FALSE(empty.IsAbsolute());
+  EXPECT_EQ(std::string("."), empty.Join());
+
+  EXPECT_EQ(1, dot.Size());
+  EXPECT_FALSE(dot.IsAbsolute());
+  EXPECT_EQ(std::string("."), dot.Join());
+
+  EXPECT_EQ(1, root.Size());
+  EXPECT_TRUE(root.IsAbsolute());
+  EXPECT_EQ(std::string("/"), root.Join());
+
+  EXPECT_EQ(4, abs_str.Size());
+  EXPECT_TRUE(abs_str.IsAbsolute());
+  EXPECT_EQ(std::string("/abs/from/assign"), abs_str.Join());
+
+  EXPECT_EQ(3, rel_str.Size());
+  EXPECT_FALSE(rel_str.IsAbsolute());
+  EXPECT_EQ(std::string("rel/from/assign"), rel_str.Join());
+
+  EXPECT_EQ(3, self_str.Size());
+  EXPECT_FALSE(self_str.IsAbsolute());
+  EXPECT_EQ(std::string("rel/from/assign"), self_str.Join());
+
+  Path cpy_str;
+  cpy_str = empty;
+  EXPECT_EQ(1, cpy_str.Size());
+  EXPECT_FALSE(cpy_str.IsAbsolute());
+  EXPECT_EQ(std::string("."), cpy_str.Join());
+
+  cpy_str = dot;
+  EXPECT_EQ(1, cpy_str.Size());
+  EXPECT_FALSE(cpy_str.IsAbsolute());
+  EXPECT_EQ(std::string("."), cpy_str.Join());
+
+  cpy_str = root;
+  EXPECT_EQ(1, cpy_str.Size());
+  EXPECT_TRUE(cpy_str.IsAbsolute());
+  EXPECT_EQ(std::string("/"), cpy_str.Join());
+
+  cpy_str = abs_str;
+  EXPECT_EQ(4, cpy_str.Size());
+  EXPECT_TRUE(cpy_str.IsAbsolute());
+  EXPECT_EQ(std::string("/abs/from/assign"), cpy_str.Join());
+
+  cpy_str = rel_str;
+  EXPECT_EQ(3, cpy_str.Size());
+  EXPECT_FALSE(cpy_str.IsAbsolute());
+  EXPECT_EQ(std::string("rel/from/assign"), cpy_str.Join());
+
+  cpy_str = self_str;
+  EXPECT_EQ(3, cpy_str.Size());
+  EXPECT_FALSE(cpy_str.IsAbsolute());
+  EXPECT_EQ(std::string("rel/from/assign"), cpy_str.Join());
+}
+
+
+TEST(PathTest, Collapse) {
+  StringArray_t path_components;
+
+  Path p1("/simple/splitter/test");
+  path_components = p1.Split();
+  EXPECT_EQ("/", path_components[0]);
+  EXPECT_EQ("/", p1.Part(0));
+
+  EXPECT_EQ("simple", path_components[1]);
+  EXPECT_EQ("simple", p1.Part(1));
+
+  EXPECT_EQ("splitter",path_components[2]);
+  EXPECT_EQ("splitter",p1.Part(2));
+
+  EXPECT_EQ("test", path_components[3]);
+  EXPECT_EQ("test", p1.Part(3));
+
+  Path p2("///simple//splitter///test/");
+  path_components = p2.Split();
+  EXPECT_EQ(4, static_cast<int>(path_components.size()));
+  EXPECT_EQ(4, static_cast<int>(p2.Size()));
+  EXPECT_EQ("/", path_components[0]);
+  EXPECT_EQ("simple", path_components[1]);
+  EXPECT_EQ("splitter", path_components[2]);
+  EXPECT_EQ("test", path_components[3]);
+
+  Path p3("sim/ple//spli/tter/te/st/");
+  path_components = p3.Split();
+  EXPECT_EQ(6, static_cast<int>(path_components.size()));
+  EXPECT_FALSE(p3.IsAbsolute());
+  EXPECT_EQ("sim", path_components[0]);
+  EXPECT_EQ("ple", path_components[1]);
+  EXPECT_EQ("spli", path_components[2]);
+  EXPECT_EQ("tter", path_components[3]);
+  EXPECT_EQ("te", path_components[4]);
+  EXPECT_EQ("st", path_components[5]);
+
+  Path p4("");
+  path_components = p4.Split();
+  EXPECT_EQ(1, static_cast<int>(path_components.size()));
+
+  Path p5("/");
+  path_components = p5.Split();
+  EXPECT_EQ(1, static_cast<int>(path_components.size()));
+}
+
+TEST(PathTest, AppendAndJoin) {
+  Path ph1("/usr/local/hi/there");
+
+  EXPECT_EQ("/usr/local/hi/there", ph1.Join());
+  ph1 = ph1.Append("..");
+  EXPECT_EQ("/usr/local/hi", ph1.Join());
+  ph1 = ph1.Append(".././././hi/there/../.././././");
+  EXPECT_EQ("/usr/local", ph1.Join());
+  ph1 = ph1.Append("../../../../../../../../././../");
+  EXPECT_EQ("/", ph1.Join());
+  ph1 = ph1.Append("usr/lib/../bin/.././etc/../local/../share");
+  EXPECT_EQ("/usr/share", ph1.Join());
+
+  Path ph2("./");
+  EXPECT_EQ(".", ph2.Join());
+
+  Path ph3("/");
+  EXPECT_EQ("/", ph3.Join());
+  ph3 = ph3.Append("");
+  EXPECT_EQ("/", ph3.Join());
+  ph3 = ph3.Append("USR/local/SHARE");
+  EXPECT_EQ("/USR/local/SHARE", ph3.Join());
+  ph3 = ph3.Append("///////////////////////////////");
+  EXPECT_EQ("/USR/local/SHARE", ph3.Join());
+
+  Path ph4("..");
+  EXPECT_EQ("..", ph4.Join());
+  ph4 = ph4.Append("/node1/node3/../../node1/./");
+  EXPECT_EQ("../node1", ph4.Join());
+  ph4 = ph4.Append("node4/../../node1/./node5");
+  EXPECT_EQ("../node1/node5", ph4.Join());
+}
+
+
+TEST(PathTest, Invalid) {
+  Path rooted("/usr/local");
+  Path current("./usr/local");
+  Path relative("usr/local");
+
+  Path test;
+
+  test = rooted;
+  test.Append("../..");
+  EXPECT_EQ("/", test.Join());
+
+  test = rooted;
+  test.Append("../../..");
+  EXPECT_EQ("/", test.Join());
+
+  test = rooted;
+  test.Append("../../../foo");
+  EXPECT_EQ("/foo", test.Join());
+
+  test = current;
+  test.Append("../..");
+  EXPECT_EQ(".", test.Join());
+
+  test = current;
+  test.Append("../../..");
+  EXPECT_EQ("..", test.Join());
+
+  test = current;
+  test.Append("../../../foo");
+  EXPECT_EQ("../foo", test.Join());
+
+  test = relative;
+  test.Append("../..");
+  EXPECT_EQ(".", test.Join());
+
+  test = relative;
+  test.Append("../../..");
+  EXPECT_EQ("..", test.Join());
+
+  test = relative;
+  test.Append("../../../foo");
+  EXPECT_EQ("../foo", test.Join());
+}
+
+TEST(PathTest, Range) {
+  Path p("/an/absolute/path");
+
+  // p's parts should be ["/", "an", "absolute", "path"].
+  EXPECT_EQ("/an/absolute/path", p.Range(0, 4));
+  EXPECT_EQ("an/absolute/path", p.Range(1, 4));
+  EXPECT_EQ("absolute/path", p.Range(2, 4));
+  EXPECT_EQ("path", p.Range(3, 4));
+
+  EXPECT_EQ("/an/absolute", p.Range(0, 3));
+  EXPECT_EQ("an/absolute", p.Range(1, 3));
+  EXPECT_EQ("absolute", p.Range(2, 3));
+}
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc b/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.cc
similarity index 100%
rename from native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc
rename to native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.cc
diff --git a/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.h b/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.h
new file mode 100644
index 0000000..9e610bd
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.h
@@ -0,0 +1,66 @@
+// 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 LIBRARIES_NACL_IO_TEST_PEPPER_INTERFACE_MOCK_H_
+#define LIBRARIES_NACL_IO_TEST_PEPPER_INTERFACE_MOCK_H_
+
+#include "gmock/gmock.h"
+#include "nacl_io/pepper_interface.h"
+
+// Mock interface class definitions.
+#include "nacl_io/pepper/undef_macros.h"
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+    class BaseClass##Mock : public nacl_io::BaseClass { \
+     public: \
+      BaseClass##Mock(); \
+      virtual ~BaseClass##Mock();
+#define END_INTERFACE(BaseClass, PPInterface) \
+    };
+#define METHOD0(Class, ReturnType, MethodName) \
+    MOCK_METHOD0(MethodName, ReturnType());
+#define METHOD1(Class, ReturnType, MethodName, Type0) \
+    MOCK_METHOD1(MethodName, ReturnType(Type0));
+#define METHOD2(Class, ReturnType, MethodName, Type0, Type1) \
+    MOCK_METHOD2(MethodName, ReturnType(Type0, Type1));
+#define METHOD3(Class, ReturnType, MethodName, Type0, Type1, Type2) \
+    MOCK_METHOD3(MethodName, ReturnType(Type0, Type1, Type2));
+#define METHOD4(Class, ReturnType, MethodName, Type0, Type1, Type2, Type3) \
+    MOCK_METHOD4(MethodName, ReturnType(Type0, Type1, Type2, Type3));
+#define METHOD5(Class, ReturnType, MethodName, Type0, Type1, Type2, Type3, \
+                Type4) \
+    MOCK_METHOD5(MethodName, ReturnType(Type0, Type1, Type2, Type3, Type4));
+#include "nacl_io/pepper/all_interfaces.h"
+
+
+class PepperInterfaceMock : public nacl_io::PepperInterface {
+ public:
+  explicit PepperInterfaceMock(PP_Instance instance);
+  ~PepperInterfaceMock();
+
+  virtual PP_Instance GetInstance();
+
+// Interface getters.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+    virtual BaseClass##Mock* Get##BaseClass();
+#include "nacl_io/pepper/all_interfaces.h"
+
+ private:
+  PP_Instance instance_;
+
+// Interface pointers.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+    BaseClass##Mock* BaseClass##interface_;
+#include "nacl_io/pepper/all_interfaces.h"
+
+  int dummy_;
+};
+
+
+#endif  // LIBRARIES_NACL_IO_TEST_PEPPER_INTERFACE_MOCK_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/signal_test.cc b/native_client_sdk/src/tests/nacl_io_test/signal_test.cc
new file mode 100644
index 0000000..856e250
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/signal_test.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 <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+
+TEST(Signal, KillSignals) {
+  EXPECT_LT(ki_kill(123, NULL, &len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_EQ(errno, 0x2211);
+}
+
+TEST(Siganl, Ntohl) {
+  uint8_t network_bytes[4] = { 0x44, 0x33, 0x22, 0x11 };
+  uint32_t network_long;
+  memcpy(&network_long, network_bytes, 4);
+  uint32_t host_long = ntohl(network_long);
+  EXPECT_EQ(host_long, 0x44332211);
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc
new file mode 100644
index 0000000..90c59dd
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc
@@ -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.
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <map>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/ossocket.h"
+#include "nacl_io/ostypes.h"
+
+#ifdef PROVIDES_SOCKET_API
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+namespace {
+class SocketTest : public ::testing::Test {
+ public:
+  SocketTest() {}
+
+  void SetUp() {
+    ki_init(&kp_);
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+ protected:
+  KernelProxy kp_;
+};
+
+}  // namespace
+
+TEST_F(SocketTest, Accept) {
+  struct sockaddr addr = {};
+  socklen_t len = 0;
+
+  EXPECT_LT(ki_accept(123, NULL, &len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_accept(123, &addr, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_accept(123, NULL, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_accept(-1, &addr, &len), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_accept(0, &addr, &len), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Bind) {
+  const struct sockaddr const_addr = {};
+  socklen_t len = 0;
+
+  EXPECT_LT(ki_bind(123, NULL, len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_bind(-1, &const_addr, len), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_bind(0, &const_addr, len), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Connect) {
+  const struct sockaddr const_addr = {};
+  socklen_t len = 0;
+
+  EXPECT_LT(ki_connect(123, NULL, len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_connect(-1, &const_addr, len), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_connect(0, &const_addr, len), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Getpeername) {
+  struct sockaddr addr = {};
+  socklen_t len = 0;
+
+  EXPECT_LT(ki_getpeername(123, NULL, &len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getpeername(123, &addr, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getpeername(123, NULL, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getpeername(-1, &addr, &len), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_getpeername(0, &addr, &len), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Getsockname) {
+  struct sockaddr addr = {};
+  socklen_t len = 0;
+
+  EXPECT_LT(ki_getsockname(123, NULL, &len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getsockname(123, &addr, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getsockname(123, NULL, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getsockname(-1, &addr, &len), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_getsockname(0, &addr, &len), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Getsockopt) {
+  socklen_t len = 10;
+  char optval[len];
+
+  EXPECT_LT(ki_getsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, optval, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, NULL, &len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, NULL, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_getsockopt(-1, SOL_SOCKET, SO_ACCEPTCONN, optval, &len), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_getsockopt(0, SOL_SOCKET, SO_ACCEPTCONN, optval, &len), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Listen) {
+  EXPECT_LT(ki_listen(-1, 123), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_listen(0, 123), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Recv) {
+  size_t len = 10;
+  char buf[len];
+
+  EXPECT_LT(ki_recv(123, NULL, len, 0), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_recv(-1, buf, len, 0), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_recv(0, buf, len, 0), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Recvfrom) {
+  size_t len = 10;
+  char buf[len];
+  struct sockaddr addr = {};
+  socklen_t addrlen = 4;
+
+  EXPECT_LT(ki_recvfrom(123, NULL, len, 0, &addr, &addrlen), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_recvfrom(123, buf, len, 0, &addr, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_recvfrom(-1, buf, len, 0, &addr, &addrlen), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_recvfrom(0, buf, len, 0, &addr, &addrlen), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Recvmsg) {
+  struct msghdr msg = {};
+
+  EXPECT_LT(ki_recvmsg(123, NULL, 0), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_recvmsg(-1, &msg, 0), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_recvmsg(0, &msg, 0), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Send) {
+  size_t len = 10;
+  char buf[len];
+
+  EXPECT_LT(ki_send(123, NULL, len, 0), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_send(-1, buf, len, 0), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_send(0, buf, len, 0), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Sendto) {
+  size_t len = 10;
+  char buf[len];
+  struct sockaddr addr = {};
+  socklen_t addrlen = 4;
+
+  EXPECT_LT(ki_sendto(123, NULL, len, 0, &addr, addrlen), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_sendto(-1, buf, len, 0, &addr, addrlen), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_sendto(0, buf, len, 0, &addr, addrlen), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Sendmsg) {
+  struct msghdr msg = {};
+
+  EXPECT_LT(ki_sendmsg(123, NULL, 0), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_sendmsg(-1, &msg, 0), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_sendmsg(0, &msg, 0), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Setsockopt) {
+  socklen_t len = 10;
+  char optval[len];
+
+  EXPECT_LT(ki_setsockopt(123, SOL_SOCKET, SO_ACCEPTCONN, NULL, len), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_setsockopt(-1, SOL_SOCKET, SO_ACCEPTCONN, optval, len), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_setsockopt(0, SOL_SOCKET, SO_ACCEPTCONN, optval, len), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Shutdown) {
+  EXPECT_LT(ki_shutdown(-1, SHUT_RDWR), 0);
+  EXPECT_EQ(errno, EBADF);
+  EXPECT_LT(ki_shutdown(0, SHUT_RDWR), 0);
+  EXPECT_EQ(errno, ENOTSOCK);
+}
+
+TEST_F(SocketTest, Socket) {
+  EXPECT_LT(ki_socket(AF_UNIX, SOCK_STREAM, 0), 0);
+  EXPECT_EQ(errno, EAFNOSUPPORT);
+  EXPECT_LT(ki_socket(AF_INET, SOCK_RAW, 0), 0);
+  EXPECT_EQ(errno, EPROTONOSUPPORT);
+}
+
+TEST_F(SocketTest, Socketpair) {
+  int sv[2];
+  EXPECT_LT(ki_socketpair(AF_INET, SOCK_STREAM, 0, NULL), 0);
+  EXPECT_EQ(errno, EFAULT);
+  EXPECT_LT(ki_socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
+  EXPECT_EQ(errno, EAFNOSUPPORT);
+  EXPECT_LT(ki_socketpair(AF_INET, SOCK_STREAM, 0, sv), 0);
+  EXPECT_EQ(errno, EPROTONOSUPPORT);
+  EXPECT_LT(ki_socketpair(AF_INET6, SOCK_STREAM, 0, sv), 0);
+  EXPECT_EQ(errno, EPROTONOSUPPORT);
+}
+
+// These utility functions are only used for newlib (glibc provides its own
+// implementations of these functions).
+#if !defined(__GLIBC__)
+
+TEST(SocketUtilityFunctions, Hstrerror) {
+  EXPECT_STREQ(hstrerror(2718),
+               "Unknown error in gethostbyname: 2718.");
+}
+
+TEST(SocketUtilityFunctions, Htonl) {
+  uint32_t host_long = 0x44332211;
+  uint32_t network_long = htonl(host_long);
+  uint8_t network_bytes[4];
+  memcpy(network_bytes, &network_long, 4);
+  EXPECT_EQ(network_bytes[0], 0x44);
+  EXPECT_EQ(network_bytes[1], 0x33);
+  EXPECT_EQ(network_bytes[2], 0x22);
+  EXPECT_EQ(network_bytes[3], 0x11);
+}
+
+TEST(SocketUtilityFunctions, Htons) {
+  uint16_t host_short = 0x2211;
+  uint16_t network_short = htons(host_short);
+  uint8_t network_bytes[2];
+  memcpy(network_bytes, &network_short, 2);
+  EXPECT_EQ(network_bytes[0], 0x22);
+  EXPECT_EQ(network_bytes[1], 0x11);
+}
+
+static struct in_addr generate_ipv4_addr(int tuple1, int tuple2,
+                                         int tuple3, int tuple4) {
+  unsigned char addr[4];
+  addr[0] = static_cast<unsigned char>(tuple1);
+  addr[1] = static_cast<unsigned char>(tuple2);
+  addr[2] = static_cast<unsigned char>(tuple3);
+  addr[3] = static_cast<unsigned char>(tuple4);
+  struct in_addr real_addr;
+  memcpy(&real_addr, addr, 4);
+  return real_addr;
+}
+
+static struct in6_addr generate_ipv6_addr(int* tuples) {
+  unsigned char addr[16];
+  for (int i = 0; i < 8; i++) {
+    addr[2*i] = (tuples[i] >> 8) & 0xFF;
+    addr[2*i+1] = tuples[i] & 0xFF;
+  }
+  struct in6_addr real_addr;
+  memcpy(&real_addr, addr, 16);
+  return real_addr;
+}
+
+TEST(SocketUtilityFunctions, Inet_ntoa) {
+  char* stringified_addr = inet_ntoa(generate_ipv4_addr(0,0,0,0));
+  ASSERT_TRUE(NULL != stringified_addr);
+  EXPECT_STREQ("0.0.0.0", stringified_addr);
+
+  stringified_addr = inet_ntoa(generate_ipv4_addr(127,0,0,1));
+  ASSERT_TRUE(NULL != stringified_addr);
+  EXPECT_STREQ("127.0.0.1", stringified_addr);
+
+  stringified_addr = inet_ntoa(generate_ipv4_addr(255,255,255,255));
+  ASSERT_TRUE(NULL != stringified_addr);
+  EXPECT_STREQ("255.255.255.255", stringified_addr);
+}
+
+TEST(SocketUtilityFunctions, Inet_ntop_ipv4) {
+  char stringified_addr[INET_ADDRSTRLEN];
+
+  struct in_addr real_addr = generate_ipv4_addr(0,0,0,0);
+  EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
+                                stringified_addr, INET_ADDRSTRLEN));
+  EXPECT_STREQ("0.0.0.0", stringified_addr);
+
+  real_addr = generate_ipv4_addr(127,0,0,1);
+  EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
+                                stringified_addr, INET_ADDRSTRLEN));
+  EXPECT_STREQ("127.0.0.1", stringified_addr);
+
+  real_addr = generate_ipv4_addr(255,255,255,255);
+  EXPECT_TRUE(NULL != inet_ntop(AF_INET, &real_addr,
+                                stringified_addr, INET_ADDRSTRLEN));
+  EXPECT_STREQ("255.255.255.255", stringified_addr);
+}
+
+TEST(SocketUtilityFunctions, Inet_ntop_ipv6) {
+  char stringified_addr[INET6_ADDRSTRLEN];
+
+  {
+    int addr_tuples[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+    struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
+    EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
+                                  stringified_addr, INET6_ADDRSTRLEN));
+    EXPECT_STREQ("0:0:0:0:0:0:0:0", stringified_addr);
+  }
+
+  {
+    int addr_tuples[8] = { 0x1234, 0xa, 0x12, 0x0000,
+                                0x5678, 0x9abc, 0xdef, 0xffff };
+    struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
+    EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
+                                  stringified_addr, INET6_ADDRSTRLEN));
+    EXPECT_STREQ("1234:a:12:0:5678:9abc:def:ffff", stringified_addr);
+  }
+
+  {
+    int addr_tuples[8] = { 0xffff, 0xffff, 0xffff, 0xffff,
+                                0xffff, 0xffff, 0xffff, 0xffff };
+    struct in6_addr real_addr = generate_ipv6_addr(addr_tuples);
+    EXPECT_TRUE(NULL != inet_ntop(AF_INET6, &real_addr,
+                                  stringified_addr, INET6_ADDRSTRLEN));
+    EXPECT_STREQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", stringified_addr);
+  }
+}
+
+TEST(SocketUtilityFunctions, Inet_ntop_failure) {
+  char addr_name[INET6_ADDRSTRLEN];
+  int addr_tuples[8] = { 0xffff, 0xffff, 0xffff, 0xffff,
+                              0xffff, 0xffff, 0xffff, 0xffff };
+  struct in6_addr ipv6_addr = generate_ipv6_addr(addr_tuples);
+  struct in_addr ipv4_addr = generate_ipv4_addr(255,255,255,255);
+
+  EXPECT_TRUE(NULL == inet_ntop(AF_UNIX, &ipv6_addr,
+                                addr_name, INET6_ADDRSTRLEN));
+  EXPECT_EQ(errno, EAFNOSUPPORT);
+
+  EXPECT_TRUE(NULL == inet_ntop(AF_INET, &ipv4_addr,
+                                addr_name, INET_ADDRSTRLEN - 1));
+  EXPECT_EQ(errno, ENOSPC);
+
+  EXPECT_TRUE(NULL == inet_ntop(AF_INET6, &ipv6_addr,
+                                addr_name, INET6_ADDRSTRLEN - 1));
+  EXPECT_EQ(errno, ENOSPC);
+}
+
+TEST(SocketUtilityFunctions, Ntohs) {
+  uint8_t network_bytes[2] = { 0x22, 0x11 };
+  uint16_t network_short;
+  memcpy(&network_short, network_bytes, 2);
+  uint16_t host_short = ntohs(network_short);
+  EXPECT_EQ(host_short, 0x2211);
+}
+
+TEST(SocketUtilityFunctions, Ntohl) {
+  uint8_t network_bytes[4] = { 0x44, 0x33, 0x22, 0x11 };
+  uint32_t network_long;
+  memcpy(&network_long, network_bytes, 4);
+  uint32_t host_long = ntohl(network_long);
+  EXPECT_EQ(host_long, 0x44332211);
+}
+
+#endif  // !defined(__GLIBC__)
+#endif  // PROVIDES_SOCKETPAIR_API
diff --git a/native_client_sdk/src/tests/nacl_io_test/syscalls_test.cc b/native_client_sdk/src/tests/nacl_io_test/syscalls_test.cc
new file mode 100644
index 0000000..76eea7f
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/syscalls_test.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 <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+namespace {
+class TestsWithKI : public ::testing::Test {
+ public:
+  TestsWithKI() {}
+
+  void SetUp() {
+    ki_init(&kp_);
+  }
+
+  void TearDown() {
+    ki_uninit();
+  }
+
+ protected:
+  KernelProxy kp_;
+};
+
+class SyscallsKill : public TestsWithKI {
+};
+
+class SyscallsSignal : public TestsWithKI {
+};
+
+TEST_F(SyscallsKill, KillSignals) {
+  // SIGSEGV can't be sent via kill(2)
+  ASSERT_EQ(-1, kill(0, SIGSEGV)) << "kill(SEGV) failed to return an error";
+  ASSERT_EQ(EINVAL, errno) << "kill(SEGV) failedd to set errno to EINVAL";
+
+  // Our implemenation should understand SIGWINCH
+  ASSERT_EQ(0, kill(0, SIGWINCH)) << "kill(SIGWINCH) failed: " << errno;
+
+  // And USR1/USR2
+  ASSERT_EQ(0, kill(0, SIGUSR1)) << "kill(SIGUSR1) failed: " << errno;
+  ASSERT_EQ(0, kill(0, SIGUSR2)) << "kill(SIGUSR2) failed: " << errno;
+}
+
+TEST_F(SyscallsKill, KillPIDValues) {
+  // Any PID other than 0, -1 and getpid() should yield ESRCH
+  // since there is only one valid process under NaCl
+  int mypid = getpid();
+  ASSERT_EQ(0, kill(0, SIGWINCH));
+  ASSERT_EQ(0, kill(-1, SIGWINCH));
+  ASSERT_EQ(0, kill(mypid, SIGWINCH));
+
+  // Don't use mypid + 1 since getpid() actually returns -1
+  // when the IRT interface is missing (e.g. within chrome),
+  // and 0 is always a valid PID when calling kill().
+  int invalid_pid = mypid + 10;
+  ASSERT_EQ(-1, kill(invalid_pid, SIGWINCH));
+  ASSERT_EQ(ESRCH, errno);
+}
+
+static bool g_handler_called = false;
+void sighandler(int) {
+  g_handler_called = true;
+}
+
+TEST_F(SyscallsSignal, SignalValues) {
+  ASSERT_EQ(signal(SIGSEGV, sighandler), SIG_ERR)
+      << "registering SEGV handler didn't fail";
+  ASSERT_EQ(errno, EINVAL) << "signal(SEGV) failed to set errno to EINVAL";
+
+  ASSERT_EQ(signal(-1, sighandler), SIG_ERR)
+      << "registering handler for invalid signal didn't fail";
+  ASSERT_EQ(errno, EINVAL) << "signal(-1) failed to set errno to EINVAL";
+}
+
+TEST_F(SyscallsSignal, HandlerValues) {
+  // Unsupported signal.
+  ASSERT_NE(SIG_ERR, signal(SIGSEGV, SIG_DFL));
+  ASSERT_EQ(SIG_ERR, signal(SIGSEGV, SIG_IGN));
+  ASSERT_EQ(SIG_ERR, signal(SIGSEGV, sighandler));
+
+  // Supported signal.
+  ASSERT_NE(SIG_ERR, signal(SIGWINCH, SIG_DFL));
+  ASSERT_NE(SIG_ERR, signal(SIGWINCH, SIG_IGN));
+  ASSERT_NE(SIG_ERR, signal(SIGWINCH, sighandler));
+}
+
+TEST_F(SyscallsSignal, Sigwinch) {
+  g_handler_called = false;
+
+  // Register WINCH handler
+  sighandler_t newsig = sighandler;
+  sighandler_t oldsig = signal(SIGWINCH, newsig);
+  ASSERT_NE(oldsig, SIG_ERR);
+
+  // Send signal.
+  kill(0, SIGWINCH);
+
+  // Verify that handler was called
+  EXPECT_TRUE(g_handler_called);
+
+  // Restore existing handler
+  oldsig = signal(SIGWINCH, oldsig);
+
+  // Verify the our newsig was returned as previous handler
+  ASSERT_EQ(oldsig, newsig);
+}
+
+}  // namespace
diff --git a/native_client_sdk/src/tests/nacl_io_test/test.js b/native_client_sdk/src/tests/nacl_io_test/test.js
new file mode 100644
index 0000000..d0c376c
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/test.js
@@ -0,0 +1,18 @@
+// 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 addTests() {
+  common.tester.addAsyncTest('nacl_io_test', function (test) {
+    var intervalId = window.setInterval(function () {
+      if (!testsFinished)
+        return;
+
+      window.clearInterval(intervalId);
+      if (failedTests > 0)
+        test.fail('tests failed');
+      else
+        test.pass();
+    }, 100);
+  });
+}
diff --git a/native_client_sdk/src/tests/sdk_util_test/example.dsc b/native_client_sdk/src/tests/sdk_util_test/example.dsc
new file mode 100644
index 0000000..8c7ee19
--- /dev/null
+++ b/native_client_sdk/src/tests/sdk_util_test/example.dsc
@@ -0,0 +1,29 @@
+{
+  'TOOLS': ['newlib', 'glibc', 'pnacl'],
+  'SEL_LDR': True,
+
+  # Need to add ../../examples for common.js
+  'SEARCH': ['.', '../../examples'],
+  'TARGETS': [
+    {
+      'NAME' : 'sdk_util_test',
+      'TYPE' : 'main',
+      'SOURCES' : [
+        'main.cc',
+      ],
+      'DEPS': ['ppapi_simple', 'sdk_util', 'nacl_io'],
+      # Order matters here: gtest has a "main" function that will be used if
+      # referenced before ppapi.
+      'LIBS': ['gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
+      'INCLUDES': ['$(NACL_SDK_ROOT)/include/gtest/internal'],
+      'CXXFLAGS': ['-Wno-sign-compare', '-Wno-unused-private-field'],
+      'CFLAGS_GCC': ['-Wno-unused-local-typedefs'],
+    }
+  ],
+  'DATA': [
+    'example.js'
+  ],
+  'DEST': 'tests',
+  'NAME': 'sdk_util_test',
+  'TITLE': 'SDK Util test',
+}
diff --git a/native_client_sdk/src/tests/sdk_util_test/example.js b/native_client_sdk/src/tests/sdk_util_test/example.js
new file mode 100644
index 0000000..d004ac4
--- /dev/null
+++ b/native_client_sdk/src/tests/sdk_util_test/example.js
@@ -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.
+// Called by the common.js module.
+function moduleDidLoad() {
+  // The module is not hidden by default so we can easily see if the plugin
+  // failed to load.
+  common.hideModule();
+}
+
+var currentTestEl = null;
+
+function startCommand(testName) {
+  var testListEl = document.getElementById('tests');
+  var testEl = document.createElement('li');
+  var testRowEl = document.createElement('div');
+  var testNameEl = document.createElement('span');
+  var testResultEl = document.createElement('span');
+  testRowEl.classList.add('row');
+  testNameEl.classList.add('name');
+  testNameEl.textContent = testName;
+  testResultEl.classList.add('result');
+  testRowEl.appendChild(testNameEl);
+  testRowEl.appendChild(testResultEl);
+  testEl.appendChild(testRowEl);
+  testListEl.appendChild(testEl);
+
+  currentTestEl = testEl;
+}
+
+function failCommand(fileName, lineNumber, summary) {
+  var testMessageEl = document.createElement('pre');
+  testMessageEl.textContent += fileName + ':' + lineNumber + ': ' + summary;
+  currentTestEl.appendChild(testMessageEl);
+}
+
+function endCommand(testName, testResult) {
+  var testRowEl = currentTestEl.querySelector('.row');
+  var testResultEl = currentTestEl.querySelector('.result');
+  testRowEl.classList.add(testResult);
+  testResultEl.textContent = testResult;
+}
+
+function handleMessage(event) {
+  var msg = event.data;
+  var firstColon = msg.indexOf(':');
+  var cmd = msg.substr(0, firstColon);
+  var cmdFunctionName = cmd + 'Command';
+  var cmdFunction = window[cmdFunctionName];
+
+  if (typeof(cmdFunction) !== 'function') {
+    console.log('Unknown command: ' + cmd);
+    console.log('  message: ' + msg);
+    return;
+  }
+
+  var argCount = cmdFunction.length;
+
+  // Don't use split, because it will split all commas (for example any commas
+  // in the test failure summary).
+  var argList = msg.substr(firstColon + 1);
+  args = [];
+  for (var i = 0; i < argCount - 1; ++i) {
+    var arg;
+    var comma = argList.indexOf(',');
+    if (comma === -1) {
+      if (i !== argCount - 1) {
+        console.log('Bad arg count to command "' + cmd + '", expected ' +
+                    argCount);
+        console.log('  message: ' + msg);
+      } else {
+        arg = argList;
+      }
+    } else {
+      arg = argList.substr(0, comma);
+      argList = argList.substr(comma + 1);
+    }
+    args.push(arg);
+  }
+
+  // Last argument is the rest of the message.
+  args.push(argList);
+
+  cmdFunction.apply(null, args);
+}
diff --git a/native_client_sdk/src/tests/sdk_util_test/index.html b/native_client_sdk/src/tests/sdk_util_test/index.html
new file mode 100644
index 0000000..20b24b5
--- /dev/null
+++ b/native_client_sdk/src/tests/sdk_util_test/index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<!--
+Copyright 2013 The Chromium 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 http-equiv="Pragma" content="no-cache">
+  <meta http-equiv="Expires" content="-1">
+  <title>{{title}}</title>
+  <script type="text/javascript" src="common.js"></script>
+  <script type="text/javascript" src="example.js"></script>
+  <style>
+    .result { padding-left: 10px; }
+    .ok { background-color: #0f0; }
+    .failed { background-color: #f00; }
+  </style>
+</head>
+<body {{attrs}}>
+  <h1>{{title}}</h1>
+  <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+  <!-- The NaCl plugin will be embedded inside the element with id "listener".
+      See common.js.-->
+  <div id="listener"></div>
+  <ul id="tests" style="list-style:none;"></ul>
+</body>
+</html>
diff --git a/native_client_sdk/src/tests/sdk_util_test/main.cc b/native_client_sdk/src/tests/sdk_util_test/main.cc
new file mode 100644
index 0000000..7dedcc6
--- /dev/null
+++ b/native_client_sdk/src/tests/sdk_util_test/main.cc
@@ -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.
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#if defined(SEL_LDR)
+
+int main(int argc, char* argv[]) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+
+#else
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi_simple/ps_main.h"
+
+#if defined(WIN32)
+#include <Windows.h>
+#undef PostMessage
+#endif
+
+class GTestEventListener : public ::testing::EmptyTestEventListener {
+ public:
+  // TestEventListener overrides.
+  virtual void OnTestStart(const ::testing::TestInfo& test_info) {
+    std::stringstream msg;
+    msg << "start:" << test_info.test_case_name() << "." << test_info.name();
+    pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+  }
+
+  virtual void OnTestPartResult(
+      const ::testing::TestPartResult& test_part_result) {
+    if (test_part_result.failed()) {
+      std::stringstream msg;
+      msg << "fail:" << test_part_result.file_name() << ","
+          << test_part_result.line_number() << ","
+          << test_part_result.summary();
+      pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+    }
+  }
+
+  virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
+    std::stringstream msg;
+    msg << "end:" << test_info.test_case_name() << "." << test_info.name()
+        << "," << (test_info.result()->Failed() ? "failed" : "ok");
+    pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+  }
+};
+
+int example_main(int argc, char* argv[]) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ::testing::UnitTest::GetInstance()->listeners()
+      .Append(new GTestEventListener());
+  return RUN_ALL_TESTS();
+}
+
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
+
+#endif
diff --git a/native_client_sdk/src/tools/common.mk b/native_client_sdk/src/tools/common.mk
index 3082072..4fc67e6 100644
--- a/native_client_sdk/src/tools/common.mk
+++ b/native_client_sdk/src/tools/common.mk
@@ -455,13 +455,13 @@
 ifndef NACL_ARCH
 	$(error Cannot run in sel_ldr unless $$NACL_ARCH is set)
 endif
-	$(SEL_LDR_PATH) $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
+	$(SEL_LDR_PATH) $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe -- $(NEXE_ARGS)
 
 debug: all
 ifndef NACL_ARCH
 	$(error Cannot run in sel_ldr unless $$NACL_ARCH is set)
 endif
-	$(SEL_LDR_PATH) -d $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
+	$(SEL_LDR_PATH) -d $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe -- $(NEXE_ARGS)
 else
 PAGE ?= index.html
 PAGE_TC_CONFIG ?= "$(PAGE)?tc=$(TOOLCHAIN)&config=$(CONFIG)"
diff --git a/net/OWNERS b/net/OWNERS
index 18f1462..87e11fa 100644
--- a/net/OWNERS
+++ b/net/OWNERS
@@ -1,4 +1,5 @@
 agl@chromium.org
+akalin@chromium.org
 asanka@chromium.org
 cbentzel@chromium.org
 eroman@chromium.org
diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc
index cc83c7c..06034cb 100644
--- a/net/base/mime_sniffer.cc
+++ b/net/base/mime_sniffer.cc
@@ -804,8 +804,7 @@
         UMASnifferHistogramGet("mime_sniffer.ShouldSniffMimeType2", 3);
   }
   bool sniffable_scheme = url.is_empty() ||
-                          url.SchemeIs("http") ||
-                          url.SchemeIs("https") ||
+                          url.SchemeIsHTTPOrHTTPS() ||
                           url.SchemeIs("ftp") ||
 #if defined(OS_ANDROID)
                           url.SchemeIs("content") ||
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index da3a4c9..ddb9b66 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -447,7 +447,7 @@
     non_image_map_.insert(supported_javascript_types[i]);
   for (size_t i = 0; i < arraysize(common_media_types); ++i)
     non_image_map_.insert(common_media_types[i]);
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
     non_image_map_.insert(proprietary_media_types[i]);
 #endif
@@ -455,7 +455,7 @@
   // Initialize the supported media types.
   for (size_t i = 0; i < arraysize(common_media_types); ++i)
     media_map_.insert(common_media_types[i]);
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
     media_map_.insert(proprietary_media_types[i]);
 #endif
@@ -465,7 +465,7 @@
 
   for (size_t i = 0; i < arraysize(common_media_codecs); ++i)
     codecs_map_.insert(common_media_codecs[i]);
-#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
+#if defined(USE_PROPRIETARY_CODECS)
   for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
     codecs_map_.insert(proprietary_media_codecs[i]);
 #endif
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 01d9bf1..4c4371c 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -50,6 +50,11 @@
 //
 //   {
 //     "host": <Hostname associated with the request>,
+//     "address_family": <The address family to restrict results to>
+//     "allow_cached_response": <Whether it is ok to return a result from
+//                               the host cache>
+//     "is_speculative": <Whether this request was started by the DNS
+//                        prefetcher>
 //     "source_dependency": <Source id, if any, of what created the request>,
 //   }
 //
@@ -1296,6 +1301,15 @@
 //                                as a base-10 string.>,
 //     "size": <The size of the packet in bytes>
 //   }
+EVENT_TYPE(QUIC_SESSION_PACKET_RETRANSMITTED)
+
+// Session retransmitted a QUIC packet.
+//   {
+//     "old_packet_sequence_number": <The old packet's full 64-bit sequence
+//                                    number, as a base-10 string.>,
+//     "new_packet_sequence_number": <The new packet's full 64-bit sequence
+//                                    number, as a base-10 string.>,
+//   }
 EVENT_TYPE(QUIC_SESSION_PACKET_SENT)
 
 // Session received a QUIC packet header for a valid packet.
@@ -1435,6 +1449,49 @@
 //   }
 EVENT_TYPE(QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT)
 
+// Session received a public reset packet.
+//   {
+//   }
+EVENT_TYPE(QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED)
+
+// Session received a version negotiation packet.
+//   {
+//     "versions": <List of QUIC versions supported by the server>,
+//   }
+EVENT_TYPE(QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED)
+
+// Session revived a QUIC packet packet via FEC.
+//   {
+//     "guid": <The 64-bit GUID for this connection, as a base-10 string>,
+//     "public_flags": <The public flags set for this packet>,
+//     "packet_sequence_number": <The packet's full 64-bit sequence number,
+//                                as a base-10 string.>,
+//     "private_flags": <The private flags set for this packet>,
+//     "fec_group": <The FEC group of this packet>,
+//   }
+EVENT_TYPE(QUIC_SESSION_PACKET_HEADER_REVIVED)
+
+// Session received a crypto handshake message.
+//   {
+//     "quic_crypto_handshake_message": <The human readable dump of the message
+//                                       contents>
+//   }
+EVENT_TYPE(QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED)
+
+// Session sent a crypto handshake message.
+//   {
+//     "quic_crypto_handshake_message": <The human readable dump of the message
+//                                       contents>
+//   }
+EVENT_TYPE(QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT)
+
+// Session was closed, either remotely or by the peer.
+//   {
+//     "quic_error": <QuicErrorCode which caused the connection to be closed>,
+//     "from_peer":  <True if the peer closed the connection>
+//   }
+EVENT_TYPE(QUIC_SESSION_CLOSED)
+
 // ------------------------------------------------------------------------
 // QuicHttpStream
 // ------------------------------------------------------------------------
@@ -1575,6 +1632,7 @@
 //   {
 //     "nameservers":                <List of name server IPs>,
 //     "search":                     <List of domain suffixes>,
+//     "unhandled_options":          <See DnsConfig>,
 //     "append_to_multi_label_name": <See DnsConfig>,
 //     "ndots":                      <See DnsConfig>,
 //     "timeout":                    <See DnsConfig>,
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 958e3c3..c995c08 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -899,6 +899,28 @@
 #endif
 }
 
+bool IPNumberPrefixCheck(const IPAddressNumber& ip_number,
+                         const unsigned char* ip_prefix,
+                         size_t prefix_length_in_bits) {
+  // Compare all the bytes that fall entirely within the prefix.
+  int num_entire_bytes_in_prefix = prefix_length_in_bits / 8;
+  for (int i = 0; i < num_entire_bytes_in_prefix; ++i) {
+    if (ip_number[i] != ip_prefix[i])
+      return false;
+  }
+
+  // In case the prefix was not a multiple of 8, there will be 1 byte
+  // which is only partially masked.
+  int remaining_bits = prefix_length_in_bits % 8;
+  if (remaining_bits != 0) {
+    unsigned char mask = 0xFF << (8 - remaining_bits);
+    int i = num_entire_bytes_in_prefix;
+    if ((ip_number[i] & mask) != (ip_prefix[i] & mask))
+      return false;
+  }
+  return true;
+}
+
 }  // namespace
 
 const FormatUrlType kFormatUrlOmitNothing                     = 0;
@@ -1391,7 +1413,6 @@
   return url.host();
 }
 
-// static
 bool IsHostnameNonUnique(const std::string& hostname) {
   // CanonicalizeHost requires surrounding brackets to parse an IPv6 address.
   const std::string host_or_ip = hostname.find(':') != std::string::npos ?
@@ -1404,11 +1425,24 @@
   if (canonical_name.empty())
     return false;
 
-  // If |hostname| is an IP address, presume it's unique.
-  // TODO(rsleevi): In the future, this should also reject IP addresses in
-  // IANA-reserved ranges.
-  if (host_info.IsIPAddress())
-    return false;
+  // If |hostname| is an IP address, check to see if it's in an IANA-reserved
+  // range.
+  if (host_info.IsIPAddress()) {
+    IPAddressNumber host_addr;
+    if (!ParseIPLiteralToNumber(hostname.substr(host_info.out_host.begin,
+                                                host_info.out_host.len),
+                                &host_addr)) {
+      return false;
+    }
+    switch (host_info.family) {
+      case url_canon::CanonHostInfo::IPV4:
+      case url_canon::CanonHostInfo::IPV6:
+        return IsIPAddressReserved(host_addr);
+      case url_canon::CanonHostInfo::NEUTRAL:
+      case url_canon::CanonHostInfo::BROKEN:
+        return false;
+    }
+  }
 
   // Check for a registry controlled portion of |hostname|, ignoring private
   // registries, as they already chain to ICANN-administered registries,
@@ -1425,6 +1459,57 @@
                   registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
 }
 
+// Don't compare IPv4 and IPv6 addresses (they have different range
+// reservations). Keep separate reservation arrays for each IP type, and
+// consolidate adjacent reserved ranges within a reservation array when
+// possible.
+// Sources for info:
+// www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml
+// www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
+// They're formatted here with the prefix as the last element. For example:
+// 10.0.0.0/8 becomes 10,0,0,0,8 and fec0::/10 becomes 0xfe,0xc0,0,0,0...,10.
+bool IsIPAddressReserved(const IPAddressNumber& host_addr) {
+  static const unsigned char kReservedIPv4[][5] = {
+      { 0,0,0,0,8 }, { 10,0,0,0,8 }, { 100,64,0,0,10 }, { 127,0,0,0,8 },
+      { 169,254,0,0,16 }, { 172,16,0,0,12 }, { 192,0,2,0,24 },
+      { 192,88,99,0,24 }, { 192,168,0,0,16 }, { 198,18,0,0,15 },
+      { 198,51,100,0,24 }, { 203,0,113,0,24 }, { 224,0,0,0,3 }
+  };
+  static const unsigned char kReservedIPv6[][17] = {
+      { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8 },
+      { 0x40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2 },
+      { 0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2 },
+      { 0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3 },
+      { 0xe0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 },
+      { 0xf0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5 },
+      { 0xf8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6 },
+      { 0xfc,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7 },
+      { 0xfe,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9 },
+      { 0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10 },
+      { 0xfe,0xc0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10 },
+  };
+  size_t array_size = 0;
+  const unsigned char* array = NULL;
+  switch (host_addr.size()) {
+    case kIPv4AddressSize:
+      array_size = arraysize(kReservedIPv4);
+      array = kReservedIPv4[0];
+      break;
+    case kIPv6AddressSize:
+      array_size = arraysize(kReservedIPv6);
+      array = kReservedIPv6[0];
+      break;
+  }
+  if (!array)
+    return false;
+  size_t width = host_addr.size() + 1;
+  for (size_t i = 0; i < array_size; ++i, array += width) {
+    if (IPNumberPrefixCheck(host_addr, array, array[width-1]))
+      return true;
+  }
+  return false;
+}
+
 // Extracts the address and port portions of a sockaddr.
 bool GetIPAddressFromSockAddr(const struct sockaddr* sock_addr,
                               socklen_t sock_addr_len,
@@ -1996,25 +2081,7 @@
                                  96 + prefix_length_in_bits);
   }
 
-  // Otherwise we are comparing two IPv4 addresses, or two IPv6 addresses.
-  // Compare all the bytes that fall entirely within the prefix.
-  int num_entire_bytes_in_prefix = prefix_length_in_bits / 8;
-  for (int i = 0; i < num_entire_bytes_in_prefix; ++i) {
-    if (ip_number[i] != ip_prefix[i])
-      return false;
-  }
-
-  // In case the prefix was not a multiple of 8, there will be 1 byte
-  // which is only partially masked.
-  int remaining_bits = prefix_length_in_bits % 8;
-  if (remaining_bits != 0) {
-    unsigned char mask = 0xFF << (8 - remaining_bits);
-    int i = num_entire_bytes_in_prefix;
-    if ((ip_number[i] & mask) != (ip_prefix[i] & mask))
-      return false;
-  }
-
-  return true;
+  return IPNumberPrefixCheck(ip_number, &ip_prefix[0], prefix_length_in_bits);
 }
 
 const uint16* GetPortFieldFromSockaddr(const struct sockaddr* address,
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 839735e..0b8dfc3 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -112,12 +112,15 @@
 NET_EXPORT_PRIVATE std::string GetHostAndOptionalPort(const GURL& url);
 
 // Returns true if |hostname| contains a non-registerable or non-assignable
-// domain name (eg: a gTLD that has not been assigned by IANA)
-//
-// TODO(rsleevi): http://crbug.com/119212 - Also match internal IP
-// address ranges.
+// domain name (eg: a gTLD that has not been assigned by IANA) or an IP address
+// that falls in an IANA-reserved range.
 NET_EXPORT bool IsHostnameNonUnique(const std::string& hostname);
 
+// Returns true if an IP address hostname is in a range reserved by the IANA.
+// Works with both IPv4 and IPv6 addresses, and only compares against a given
+// protocols's reserved ranges.
+NET_EXPORT bool IsIPAddressReserved(const IPAddressNumber& address);
+
 // Convenience struct for when you need a |struct sockaddr|.
 struct SockaddrStorage {
   SockaddrStorage() : addr_len(sizeof(addr_storage)),
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index 7c6bb57..22bcba1 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -3517,15 +3517,27 @@
     // Domains under private registries.
     { true, "appspot.com" },
     { true, "test.appspot.com" },
-    // IPv4 addresses (in various forms).
+    // Unreserved IPv4 addresses (in various forms).
     { true, "8.8.8.8" },
-    { true, "1.2.3" },
-    { true, "14.15" },
-    { true, "676768" },
-    // IPv6 addresses.
-    { true, "FEDC:ba98:7654:3210:FEDC:BA98:7654:3210" },
-    { true, "::192.9.5.5" },
-    { true, "FEED::BEEF" },
+    { true, "99.64.0.0" },
+    { true, "212.15.0.0" },
+    { true, "212.15" },
+    { true, "212.15.0" },
+    { true, "3557752832" },
+    // Reserved IPv4 addresses (in various forms).
+    { false, "192.168.0.0" },
+    { false, "192.168.0.6" },
+    { false, "10.0.0.5" },
+    { false, "10.0" },
+    { false, "10.0.0" },
+    { false, "3232235526" },
+    // Unreserved IPv6 addresses.
+    { true, "FFC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
+    { true, "2000:ba98:7654:2301:EFCD:BA98:7654:3210" },
+    // Reserved IPv6 addresses.
+    { false, "::192.9.5.5" },
+    { false, "FEED::BEEF" },
+    { false, "FEC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
     // 'internal'/non-IANA assigned domains.
     { false, "intranet" },
     { false, "intranet." },
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc
index a6335d0..fad9440 100644
--- a/net/base/network_change_notifier.cc
+++ b/net/base/network_change_notifier.cc
@@ -249,7 +249,7 @@
   // from the network thread.
   void NotifyDataReceived(const URLRequest& request, int bytes_read) {
     if (IsLocalhost(request.url().host()) ||
-        !(request.url().SchemeIs("http") || request.url().SchemeIs("https"))) {
+        !request.url().SchemeIsHTTPOrHTTPS()) {
       return;
     }
 
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
index ec1ef68..3988de3 100644
--- a/net/cert/cert_verify_proc.cc
+++ b/net/cert/cert_verify_proc.cc
@@ -242,16 +242,19 @@
       rv = MapCertStatusToNetError(verify_result->cert_status);
   }
 
+#if !defined(OS_ANDROID)
   // Flag certificates from publicly-trusted CAs that are issued to intranet
   // hosts. While the CA/Browser Forum Baseline Requirements (v1.1) permit
   // these to be issued until 1 November 2015, they represent a real risk for
   // the deployment of gTLDs and are being phased out ahead of the hard
   // deadline.
-  // TODO(rsleevi): http://crbug.com/119212 - Also match internal IP address
-  // ranges.
+  //
+  // TODO(ppi): is_issued_by_known_root is incorrect on Android. Once this is
+  // fixed, re-enable this check for Android. crbug.com/116838
   if (verify_result->is_issued_by_known_root && IsHostnameNonUnique(hostname)) {
     verify_result->cert_status |= CERT_STATUS_NON_UNIQUE_NAME;
   }
+#endif
 
   return rv;
 }
diff --git a/net/cert/cert_verify_proc_nss.cc b/net/cert/cert_verify_proc_nss.cc
index f63297e..0a0743c 100644
--- a/net/cert/cert_verify_proc_nss.cc
+++ b/net/cert/cert_verify_proc_nss.cc
@@ -764,8 +764,7 @@
 #endif  // defined(OS_IOS)
 
   // Make sure that the hostname matches with the common name of the cert.
-  SECStatus status = CERT_VerifyCertName(cert_handle, hostname.c_str());
-  if (status != SECSuccess)
+  if (!cert->VerifyNameMatch(hostname))
     verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
 
   // Make sure that the cert is valid now.
@@ -805,9 +804,9 @@
         CertificateListToCERTCertList(additional_trust_anchors));
   }
 
-  status = PKIXVerifyCert(cert_handle, check_revocation, false,
-                          cert_io_enabled, NULL, 0, trust_anchors.get(),
-                          cvout);
+  SECStatus status = PKIXVerifyCert(cert_handle, check_revocation, false,
+                                    cert_io_enabled, NULL, 0,
+                                    trust_anchors.get(), cvout);
 
   if (status == SECSuccess &&
       (flags & CertVerifier::VERIFY_REV_CHECKING_REQUIRED_LOCAL_ANCHORS) &&
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index a53d10a..8890e3b 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -245,7 +245,6 @@
   EXPECT_EQ(0u, verify_result.cert_status);
 }
 
-
 // Test for bug 58437.
 // This certificate will expire on 2011-12-21. The test will still
 // pass if error == ERR_CERT_DATE_INVALID.
@@ -692,11 +691,19 @@
                                             certs[2]->os_cert_handle()));
 }
 
+#if defined(OS_ANDROID)
+// TODO(ppi): Disabled because is_issued_by_known_root is incorrect on Android.
+// Once this is fixed, re-enable this check for android. crbug.com/116838
+#define MAYBE_IntranetHostsRejected DISABLED_IntranetHostsRejected
+#else
+#define MAYBE_IntranetHostsRejected IntranetHostsRejected
+#endif
+
 // Test that certificates issued for 'intranet' names (that is, containing no
 // known public registry controlled domain information) issued by well-known
 // CAs are flagged appropriately, while certificates that are issued by
 // internal CAs are not flagged.
-TEST_F(CertVerifyProcTest, IntranetHostsRejected) {
+TEST_F(CertVerifyProcTest, MAYBE_IntranetHostsRejected) {
   CertificateList cert_list = CreateCertificateListFromFile(
       GetTestCertsDirectory(), "ok_cert.pem",
       X509Certificate::FORMAT_AUTO);
@@ -1356,4 +1363,69 @@
     CertVerifyProcWeakDigestTest,
     testing::ValuesIn(kVerifyMixedTestData));
 
+// For the list of valid hostnames, see
+// net/cert/data/ssl/certificates/subjectAltName_sanity_check.pem
+static const struct CertVerifyProcNameData {
+  const char* hostname;
+  bool valid;  // Whether or not |hostname| matches a subjectAltName.
+} kVerifyNameData[] = {
+  { "127.0.0.1", false },  // Don't match the common name
+  { "127.0.0.2", true },  // Matches the iPAddress SAN (IPv4)
+  { "FE80:0:0:0:0:0:0:1", true },  // Matches the iPAddress SAN (IPv6)
+  { "[FE80:0:0:0:0:0:0:1]", false },  // Should not match the iPAddress SAN
+  { "FE80::1", true },  // Compressed form matches the iPAddress SAN (IPv6)
+  { "::127.0.0.2", false },  // IPv6 mapped form should NOT match iPAddress SAN
+  { "test.example", true },  // Matches the dNSName SAN
+  { "test.example.", true },  // Matches the dNSName SAN (trailing . ignored)
+  { "www.test.example", false },  // Should not match the dNSName SAN
+  { "test..example", false },  // Should not match the dNSName SAN
+  { "test.example..", false },  // Should not match the dNSName SAN
+  { ".test.example.", false },  // Should not match the dNSName SAN
+  { ".test.example", false },  // Should not match the dNSName SAN
+};
+
+// GTest 'magic' pretty-printer, so that if/when a test fails, it knows how
+// to output the parameter that was passed. Without this, it will simply
+// attempt to print out the first twenty bytes of the object, which depending
+// on platform and alignment, may result in an invalid read.
+void PrintTo(const CertVerifyProcNameData& data, std::ostream* os) {
+  *os << "Hostname: " << data.hostname << "; valid=" << data.valid;
+}
+
+class CertVerifyProcNameTest
+    : public CertVerifyProcTest,
+      public testing::WithParamInterface<CertVerifyProcNameData> {
+ public:
+  CertVerifyProcNameTest() {}
+  virtual ~CertVerifyProcNameTest() {}
+};
+
+TEST_P(CertVerifyProcNameTest, VerifyCertName) {
+  CertVerifyProcNameData data = GetParam();
+
+  CertificateList cert_list = CreateCertificateListFromFile(
+      GetTestCertsDirectory(), "subjectAltName_sanity_check.pem",
+      X509Certificate::FORMAT_AUTO);
+  ASSERT_EQ(1U, cert_list.size());
+  scoped_refptr<X509Certificate> cert(cert_list[0]);
+
+  ScopedTestRoot scoped_root(cert.get());
+
+  CertVerifyResult verify_result;
+  int error = Verify(cert.get(), data.hostname, 0, NULL, empty_cert_list_,
+                     &verify_result);
+  if (data.valid) {
+    EXPECT_EQ(OK, error);
+    EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_COMMON_NAME_INVALID);
+  } else {
+    EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, error);
+    EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_COMMON_NAME_INVALID);
+  }
+}
+
+WRAPPED_INSTANTIATE_TEST_CASE_P(
+    VerifyName,
+    CertVerifyProcNameTest,
+    testing::ValuesIn(kVerifyNameData));
+
 }  // namespace net
diff --git a/net/cert/cert_verify_proc_win.cc b/net/cert/cert_verify_proc_win.cc
index 7e94246..d3e8b62 100644
--- a/net/cert/cert_verify_proc_win.cc
+++ b/net/cert/cert_verify_proc_win.cc
@@ -727,7 +727,10 @@
   memset(&extra_policy_para, 0, sizeof(extra_policy_para));
   extra_policy_para.cbSize = sizeof(extra_policy_para);
   extra_policy_para.dwAuthType = AUTHTYPE_SERVER;
-  extra_policy_para.fdwChecks = 0;
+  // Certificate name validation happens separately, later, using an internal
+  // routine that has better support for RFC 6125 name matching.
+  extra_policy_para.fdwChecks =
+      0x00001000;  // SECURITY_FLAG_IGNORE_CERT_CN_INVALID
   extra_policy_para.pwszServerName =
       const_cast<wchar_t*>(wstr_hostname.c_str());
 
@@ -752,57 +755,17 @@
   if (policy_status.dwError) {
     verify_result->cert_status |= MapNetErrorToCertStatus(
         MapSecurityError(policy_status.dwError));
-
-    // CertVerifyCertificateChainPolicy reports only one error (in
-    // policy_status.dwError) if the certificate has multiple errors.
-    // CertGetCertificateChain doesn't report certificate name mismatch, so
-    // CertVerifyCertificateChainPolicy is the only function that can report
-    // certificate name mismatch.
-    //
-    // To prevent a potential certificate name mismatch from being hidden by
-    // some other certificate error, if we get any other certificate error,
-    // we call CertVerifyCertificateChainPolicy again, ignoring all other
-    // certificate errors.  Both extra_policy_para.fdwChecks and
-    // policy_para.dwFlags allow us to ignore certificate errors, so we set
-    // them both.
-    if (policy_status.dwError != CERT_E_CN_NO_MATCH) {
-      const DWORD extra_ignore_flags =
-          0x00000080 |  // SECURITY_FLAG_IGNORE_REVOCATION
-          0x00000100 |  // SECURITY_FLAG_IGNORE_UNKNOWN_CA
-          0x00002000 |  // SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
-          0x00000200;   // SECURITY_FLAG_IGNORE_WRONG_USAGE
-      extra_policy_para.fdwChecks = extra_ignore_flags;
-      const DWORD ignore_flags =
-          CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS |
-          CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG |
-          CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG |
-          CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG |
-          CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG |
-          CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG |
-          CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS |
-          CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG |
-          CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG |
-          CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG |
-          CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG;
-      policy_para.dwFlags = ignore_flags;
-      if (!CertVerifyCertificateChainPolicy(
-               CERT_CHAIN_POLICY_SSL,
-               chain_context,
-               &policy_para,
-               &policy_status)) {
-        return MapSecurityError(GetLastError());
-      }
-      if (policy_status.dwError) {
-        verify_result->cert_status |= MapNetErrorToCertStatus(
-            MapSecurityError(policy_status.dwError));
-      }
-    }
   }
 
   // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be
   // compatible with WinHTTP, which doesn't report this error (bug 3004).
   verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM;
 
+  // Perform hostname verification independent of
+  // CertVerifyCertificateChainPolicy.
+  if (!cert->VerifyNameMatch(hostname))
+    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
     // CERT_UNABLE_TO_CHECK_REVOCATION unless it had cached OCSP or CRL
diff --git a/net/cert/x509_cert_types.h b/net/cert/x509_cert_types.h
index b6adb51..f74c82e 100644
--- a/net/cert/x509_cert_types.h
+++ b/net/cert/x509_cert_types.h
@@ -42,7 +42,7 @@
   bool ParseDistinguishedName(const void* ber_name_data, size_t length);
 #endif
 
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
   // Compare this CertPrincipal with |against|, returning true if they're
   // equal enough to be a possible match. This should NOT be used for any
   // security relevant decisions.
@@ -136,9 +136,9 @@
 // |format|, and writes the result into |*time|. If an invalid date is
 // specified, or if parsing fails, returns false, and |*time| will not be
 // updated.
-bool ParseCertificateDate(const base::StringPiece& raw_date,
-                          CertDateFormat format,
-                          base::Time* time);
+NET_EXPORT_PRIVATE bool ParseCertificateDate(const base::StringPiece& raw_date,
+                                             CertDateFormat format,
+                                             base::Time* time);
 }  // namespace net
 
 #endif  // NET_CERT_X509_CERT_TYPES_H_
diff --git a/net/cert/x509_cert_types_unittest.cc b/net/cert/x509_cert_types_unittest.cc
index e0bcc70..38fd3e9 100644
--- a/net/cert/x509_cert_types_unittest.cc
+++ b/net/cert/x509_cert_types_unittest.cc
@@ -2,14 +2,19 @@
 // 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 "net/cert/x509_cert_types.h"
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
 #include "net/test/test_certificate_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
 
-#if defined(OS_MACOSX)
+namespace {
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
 TEST(X509TypesTest, Matching) {
   CertPrincipal spamco;
   spamco.common_name = "SpamCo Dept. Of Certificization";
@@ -48,6 +53,7 @@
 }
 #endif
 
+#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
 TEST(X509TypesTest, ParseDNVerisign) {
   CertPrincipal verisign;
   EXPECT_TRUE(verisign.ParseDistinguishedName(VerisignDN, sizeof(VerisignDN)));
@@ -135,5 +141,103 @@
   EXPECT_EQ("(c) 1999 Entrust.net Limited",
             entrust.organization_unit_names[1]);
 }
+#endif
+
+const struct CertDateTestData {
+  CertDateFormat format;
+  const char* date_string;
+  bool is_valid;
+  base::Time::Exploded expected_result;
+} kCertDateTimeData[] = {
+  { CERT_DATE_FORMAT_UTC_TIME,
+    "120101000000Z",
+    true,
+    { 2012, 1, 0, 1, 0, 0, 0 } },
+  { CERT_DATE_FORMAT_GENERALIZED_TIME,
+    "20120101000000Z",
+    true,
+    { 2012, 1, 0, 1, 0, 0, 0 } },
+  { CERT_DATE_FORMAT_UTC_TIME,
+    "490101000000Z",
+    true,
+    { 2049, 1, 0, 1, 0, 0, 0 } },
+  { CERT_DATE_FORMAT_UTC_TIME,
+    "500101000000Z",
+    true,
+    { 1950, 1, 0, 1, 0, 0, 0 } },
+  { CERT_DATE_FORMAT_GENERALIZED_TIME,
+    "19500101000000Z",
+    true,
+    { 1950, 1, 0, 1, 0, 0, 0 } },
+  { CERT_DATE_FORMAT_UTC_TIME,
+    "AB0101000000Z",
+    false,
+    { 0 } },
+  { CERT_DATE_FORMAT_GENERALIZED_TIME,
+    "19AB0101000000Z",
+    false,
+    { 0 } },
+  { CERT_DATE_FORMAT_UTC_TIME,
+    "",
+    false,
+    { 0 } },
+  { CERT_DATE_FORMAT_UTC_TIME,
+    "A",
+    false,
+    { 0 } },
+ { CERT_DATE_FORMAT_GENERALIZED_TIME,
+    "20121301000000Z",
+    false,
+    { 0 } },
+ { CERT_DATE_FORMAT_GENERALIZED_TIME,
+    "20120101123000Z",
+    true,
+    { 2012, 1, 0, 1, 12, 30, 0 } },
+};
+
+// GTest pretty printer.
+void PrintTo(const CertDateTestData& data, std::ostream* os) {
+  *os << " format: " << data.format
+      << "; date string: " << base::StringPiece(data.date_string)
+      << "; valid: " << data.is_valid
+      << "; expected date: "
+      << (data.is_valid ?
+              base::Time::FromUTCExploded(data.expected_result)
+                  .ToInternalValue() :
+              0U);
+}
+
+class X509CertTypesDateTest : public testing::TestWithParam<CertDateTestData> {
+  public:
+    virtual ~X509CertTypesDateTest() {}
+    virtual void SetUp() {
+      test_data_ = GetParam();
+    }
+
+  protected:
+    CertDateTestData test_data_;
+};
+
+TEST_P(X509CertTypesDateTest, Parse) {
+  base::Time parsed_date;
+  bool parsed = ParseCertificateDate(
+      test_data_.date_string, test_data_.format, &parsed_date);
+  EXPECT_EQ(test_data_.is_valid, parsed);
+  if (!test_data_.is_valid)
+    return;
+  // Convert the expected value to a base::Time(). This ensures that systems
+  // systems that only support 32-bit times will pass the tests, by ensuring at
+  // least that the times have the same truncating behaviour.
+  // Note: Compared as internal values so that mismatches can be cleanly
+  // printed by GTest (eg: without PrintTo overrides).
+  EXPECT_EQ(base::Time::FromUTCExploded(test_data_.expected_result)
+                .ToInternalValue(),
+            parsed_date.ToInternalValue());
+}
+INSTANTIATE_TEST_CASE_P(,
+                        X509CertTypesDateTest,
+                        testing::ValuesIn(kCertDateTimeData));
+
+}  // namespace
 
 }  // namespace net
diff --git a/net/cert/x509_certificate_openssl.cc b/net/cert/x509_certificate_openssl.cc
index bdf2bf2..71d558d 100644
--- a/net/cert/x509_certificate_openssl.cc
+++ b/net/cert/x509_certificate_openssl.cc
@@ -456,7 +456,7 @@
       break;
     case EVP_PKEY_EC:
       *type = kPublicKeyTypeECDSA;
-      *size_bits = EVP_PKEY_size(key);
+      *size_bits = EVP_PKEY_bits(key);
       break;
     case EVP_PKEY_DH:
       *type = kPublicKeyTypeDH;
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index 75ba827..04dbadd 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -23,6 +23,10 @@
 #include <cert.h>
 #endif
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 using base::HexEncode;
 using base::Time;
 
@@ -84,75 +88,6 @@
 // Dec 18 23:59:59 2011 GMT
 const double kGoogleParseValidTo = 1324252799;
 
-struct CertificateFormatTestData {
-  const char* file_name;
-  X509Certificate::Format format;
-  uint8* chain_fingerprints[3];
-};
-
-const CertificateFormatTestData FormatTestData[] = {
-  // DER Parsing - single certificate, DER encoded
-  { "google.single.der", X509Certificate::FORMAT_SINGLE_CERTIFICATE,
-    { google_parse_fingerprint,
-      NULL, } },
-  // DER parsing - single certificate, PEM encoded
-  { "google.single.pem", X509Certificate::FORMAT_SINGLE_CERTIFICATE,
-    { google_parse_fingerprint,
-      NULL, } },
-  // PEM parsing - single certificate, PEM encoded with a PEB of
-  // "CERTIFICATE"
-  { "google.single.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE,
-    { google_parse_fingerprint,
-      NULL, } },
-  // PEM parsing - sequence of certificates, PEM encoded with a PEB of
-  // "CERTIFICATE"
-  { "google.chain.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-  // PKCS#7 parsing - "degenerate" SignedData collection of certificates, DER
-  // encoding
-  { "google.binary.p7b", X509Certificate::FORMAT_PKCS7,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-  // PKCS#7 parsing - "degenerate" SignedData collection of certificates, PEM
-  // encoded with a PEM PEB of "CERTIFICATE"
-  { "google.pem_cert.p7b", X509Certificate::FORMAT_PKCS7,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-  // PKCS#7 parsing - "degenerate" SignedData collection of certificates, PEM
-  // encoded with a PEM PEB of "PKCS7"
-  { "google.pem_pkcs7.p7b", X509Certificate::FORMAT_PKCS7,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-  // All of the above, this time using auto-detection
-  { "google.single.der", X509Certificate::FORMAT_AUTO,
-    { google_parse_fingerprint,
-      NULL, } },
-  { "google.single.pem", X509Certificate::FORMAT_AUTO,
-    { google_parse_fingerprint,
-      NULL, } },
-  { "google.chain.pem", X509Certificate::FORMAT_AUTO,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-  { "google.binary.p7b", X509Certificate::FORMAT_AUTO,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-  { "google.pem_cert.p7b", X509Certificate::FORMAT_AUTO,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-  { "google.pem_pkcs7.p7b", X509Certificate::FORMAT_AUTO,
-    { google_parse_fingerprint,
-      thawte_parse_fingerprint,
-      NULL, } },
-};
-
 void CheckGoogleCert(const scoped_refptr<X509Certificate>& google_cert,
                      uint8* expected_fingerprint,
                      double valid_from, double valid_to) {
@@ -869,6 +804,73 @@
 }
 #endif
 
+const struct CertificateFormatTestData {
+  const char* file_name;
+  X509Certificate::Format format;
+  uint8* chain_fingerprints[3];
+} kFormatTestData[] = {
+  // DER Parsing - single certificate, DER encoded
+  { "google.single.der", X509Certificate::FORMAT_SINGLE_CERTIFICATE,
+    { google_parse_fingerprint,
+      NULL, } },
+  // DER parsing - single certificate, PEM encoded
+  { "google.single.pem", X509Certificate::FORMAT_SINGLE_CERTIFICATE,
+    { google_parse_fingerprint,
+      NULL, } },
+  // PEM parsing - single certificate, PEM encoded with a PEB of
+  // "CERTIFICATE"
+  { "google.single.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE,
+    { google_parse_fingerprint,
+      NULL, } },
+  // PEM parsing - sequence of certificates, PEM encoded with a PEB of
+  // "CERTIFICATE"
+  { "google.chain.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+  // PKCS#7 parsing - "degenerate" SignedData collection of certificates, DER
+  // encoding
+  { "google.binary.p7b", X509Certificate::FORMAT_PKCS7,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+  // PKCS#7 parsing - "degenerate" SignedData collection of certificates, PEM
+  // encoded with a PEM PEB of "CERTIFICATE"
+  { "google.pem_cert.p7b", X509Certificate::FORMAT_PKCS7,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+  // PKCS#7 parsing - "degenerate" SignedData collection of certificates, PEM
+  // encoded with a PEM PEB of "PKCS7"
+  { "google.pem_pkcs7.p7b", X509Certificate::FORMAT_PKCS7,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+  // All of the above, this time using auto-detection
+  { "google.single.der", X509Certificate::FORMAT_AUTO,
+    { google_parse_fingerprint,
+      NULL, } },
+  { "google.single.pem", X509Certificate::FORMAT_AUTO,
+    { google_parse_fingerprint,
+      NULL, } },
+  { "google.chain.pem", X509Certificate::FORMAT_AUTO,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+  { "google.binary.p7b", X509Certificate::FORMAT_AUTO,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+  { "google.pem_cert.p7b", X509Certificate::FORMAT_AUTO,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+  { "google.pem_pkcs7.p7b", X509Certificate::FORMAT_AUTO,
+    { google_parse_fingerprint,
+      thawte_parse_fingerprint,
+      NULL, } },
+};
+
 class X509CertificateParseTest
     : public testing::TestWithParam<CertificateFormatTestData> {
  public:
@@ -915,7 +917,7 @@
 }
 
 INSTANTIATE_TEST_CASE_P(, X509CertificateParseTest,
-                        testing::ValuesIn(FormatTestData));
+                        testing::ValuesIn(kFormatTestData));
 
 struct CertificateNameVerifyTestData {
   // true iff we expect hostname to match an entry in cert_names.
@@ -1144,4 +1146,50 @@
 INSTANTIATE_TEST_CASE_P(, X509CertificateNameVerifyTest,
                         testing::ValuesIn(kNameVerifyTestData));
 
+const struct PublicKeyInfoTestData {
+  const char* cert_file;
+  size_t expected_bits;
+  X509Certificate::PublicKeyType expected_type;
+} kPublicKeyInfoTestData[] = {
+  { "768-rsa-ee-by-768-rsa-intermediate.pem", 768,
+    X509Certificate::kPublicKeyTypeRSA },
+  { "1024-rsa-ee-by-768-rsa-intermediate.pem", 1024,
+    X509Certificate::kPublicKeyTypeRSA },
+  { "prime256v1-ecdsa-ee-by-1024-rsa-intermediate.pem", 256,
+    X509Certificate::kPublicKeyTypeECDSA },
+};
+
+class X509CertificatePublicKeyInfoTest
+    : public testing::TestWithParam<PublicKeyInfoTestData> {
+};
+
+TEST_P(X509CertificatePublicKeyInfoTest, GetPublicKeyInfo) {
+  PublicKeyInfoTestData data = GetParam();
+
+#if defined(OS_WIN)
+  if (base::win::GetVersion() < base::win::VERSION_VISTA &&
+      data.expected_type == X509Certificate::kPublicKeyTypeECDSA) {
+    // ECC is only supported on Vista+. Skip the test.
+    return;
+  }
+#endif
+
+  scoped_refptr<X509Certificate> cert(
+      ImportCertFromFile(GetTestCertsDirectory(), data.cert_file));
+  ASSERT_TRUE(cert.get());
+
+  size_t actual_bits = 0;
+  X509Certificate::PublicKeyType actual_type =
+      X509Certificate::kPublicKeyTypeUnknown;
+
+  X509Certificate::GetPublicKeyInfo(cert->os_cert_handle(), &actual_bits,
+                                    &actual_type);
+
+  EXPECT_EQ(data.expected_bits, actual_bits);
+  EXPECT_EQ(data.expected_type, actual_type);
+}
+
+INSTANTIATE_TEST_CASE_P(, X509CertificatePublicKeyInfoTest,
+                        testing::ValuesIn(kPublicKeyInfoTestData));
+
 }  // namespace net
diff --git a/net/data/ssl/certificates/subjectAltName_sanity_check.pem b/net/data/ssl/certificates/subjectAltName_sanity_check.pem
index 46cf58d..bb7f31b 100644
--- a/net/data/ssl/certificates/subjectAltName_sanity_check.pem
+++ b/net/data/ssl/certificates/subjectAltName_sanity_check.pem
@@ -1,54 +1,55 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number:
-            f2:f1:e7:8b:cf:09:30:f1
-        Signature Algorithm: sha1WithRSAEncryption
+        Serial Number: 17778064637999560130 (0xf6b85f9895e5b5c2)
+    Signature Algorithm: sha1WithRSAEncryption
         Issuer: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1
         Validity
-            Not Before: Apr  3 00:46:54 2012 GMT
-            Not After : Apr  1 00:46:54 2022 GMT
+            Not Before: Aug 16 02:31:34 2013 GMT
+            Not After : Aug 14 02:31:34 2023 GMT
         Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
-            RSA Public Key: (1024 bit)
-                Modulus (1024 bit):
-                    00:c8:0e:13:bb:da:d5:5a:d4:68:a2:11:90:ae:c3:
-                    b3:f9:72:52:7d:e9:73:5c:49:60:ef:d3:49:05:9a:
-                    c7:4e:01:4f:b0:c8:4c:18:34:2f:7b:84:27:ad:94:
-                    12:9b:e7:3d:38:6b:49:15:55:f6:c7:3a:8d:03:ec:
-                    3e:59:90:5c:b9:a6:41:af:f0:12:b8:87:b9:54:4d:
-                    1e:18:ba:41:96:d0:f3:bb:a0:d6:80:8e:29:10:72:
-                    eb:3c:4c:c0:e2:f7:d8:61:2f:d8:63:c7:a7:79:f5:
-                    74:e0:2a:f0:5d:3e:eb:a2:36:09:4b:5d:35:31:56:
-                    1c:86:0e:8a:22:ad:1b:3f:27
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:bf:11:d3:18:37:84:53:8b:07:d3:7d:0a:dc:f7:
+                    fc:ed:ce:8d:72:3a:29:af:17:e2:2b:d0:99:5f:3c:
+                    7b:29:a9:a8:3d:02:42:19:82:0b:df:5d:95:ac:60:
+                    d9:08:69:ed:90:36:42:57:39:87:4c:cc:1e:8a:1d:
+                    7e:92:bb:7e:02:df:02:80:48:3f:38:21:cc:e9:d1:
+                    b5:34:01:8f:92:17:ed:97:1d:11:2b:dd:df:fc:74:
+                    f4:d6:66:9f:e3:e5:10:ea:ea:53:b2:a7:78:4b:96:
+                    31:06:38:0b:fa:0f:d8:58:9b:ff:2a:1f:2d:8c:ae:
+                    6c:42:73:4c:d2:cf:1b:b7:d1
                 Exponent: 65537 (0x10001)
         X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
             X509v3 Subject Alternative Name: 
                 IP Address:127.0.0.2, IP Address:FE80:0:0:0:0:0:0:1, DNS:test.example, email:test@test.example, othername:<unsupported>, DirName:/CN=127.0.0.3
     Signature Algorithm: sha1WithRSAEncryption
-        32:46:49:70:be:e4:db:05:0e:7e:7a:e4:ea:5c:90:c6:4c:65:
-        2d:03:ac:fb:d1:de:e4:26:e5:83:dc:5a:c8:4f:ff:b5:10:4e:
-        39:21:7f:c8:37:f3:c6:7a:de:96:b3:30:e7:c7:87:6d:75:1e:
-        14:30:17:6b:d2:76:0b:b8:43:39:c4:63:4c:50:8e:e1:0f:09:
-        ff:6c:7d:ab:c8:97:46:e8:04:70:9d:f5:e5:8c:b6:8c:b7:3d:
-        8e:0f:59:1f:6a:fd:03:c2:be:a1:40:b7:9b:38:ca:55:f5:18:
-        c3:0d:35:01:12:a0:8d:ba:1b:41:a3:6e:68:8c:cf:52:f9:96:
-        90:64
+         ad:99:a8:25:29:15:1f:b8:c7:27:f0:c8:d7:2a:2a:66:54:07:
+         2b:2c:b4:1e:fe:27:07:29:da:22:3d:7a:d8:4d:81:72:78:3e:
+         96:5d:4c:42:ce:8c:c5:d1:d9:b3:ac:92:99:19:e5:2a:32:8a:
+         bc:ce:fb:58:a0:b9:e7:4b:44:d8:0c:2c:30:2f:fa:6c:48:7e:
+         23:77:4f:67:e9:72:83:39:22:6f:2b:4d:25:16:3d:98:be:01:
+         31:a0:55:0a:85:78:b8:b9:9c:66:e6:cb:7b:81:1c:fc:84:d1:
+         79:1b:41:12:21:f8:c9:5b:fd:3c:a6:e4:6d:36:5b:0a:4c:aa:
+         bb:2b
 -----BEGIN CERTIFICATE-----
-MIICsDCCAhmgAwIBAgIJAPLx54vPCTDxMA0GCSqGSIb3DQEBBQUAMGAxCzAJBgNV
+MIICwzCCAiygAwIBAgIJAPa4X5iV5bXCMA0GCSqGSIb3DQEBBQUAMGAxCzAJBgNV
 BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
-aWV3MRAwDgYDVQQKDAdUZXN0IENBMRIwEAYDVQQDDAkxMjcuMC4wLjEwHhcNMTIw
-NDAzMDA0NjU0WhcNMjIwNDAxMDA0NjU0WjBgMQswCQYDVQQGEwJVUzETMBEGA1UE
+aWV3MRAwDgYDVQQKDAdUZXN0IENBMRIwEAYDVQQDDAkxMjcuMC4wLjEwHhcNMTMw
+ODE2MDIzMTM0WhcNMjMwODE0MDIzMTM0WjBgMQswCQYDVQQGEwJVUzETMBEGA1UE
 CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwH
 VGVzdCBDQTESMBAGA1UEAwwJMTI3LjAuMC4xMIGfMA0GCSqGSIb3DQEBAQUAA4GN
-ADCBiQKBgQDIDhO72tVa1GiiEZCuw7P5clJ96XNcSWDv00kFmsdOAU+wyEwYNC97
-hCetlBKb5z04a0kVVfbHOo0D7D5ZkFy5pkGv8BK4h7lUTR4YukGW0PO7oNaAjikQ
-cus8TMDi99hhL9hjx6d59XTgKvBdPuuiNglLXTUxVhyGDooirRs/JwIDAQABo3Iw
-cDBuBgNVHREEZzBlhwR/AAAChxD+gAAAAAAAAAAAAAAAAAABggx0ZXN0LmV4YW1w
-bGWBEXRlc3RAdGVzdC5leGFtcGxloBIGAyoDBKALDAlpZ25vcmUgbWWkFjAUMRIw
-EAYDVQQDDAkxMjcuMC4wLjMwDQYJKoZIhvcNAQEFBQADgYEAMkZJcL7k2wUOfnrk
-6lyQxkxlLQOs+9He5Cblg9xayE//tRBOOSF/yDfzxnrelrMw58eHbXUeFDAXa9J2
-C7hDOcRjTFCO4Q8J/2x9q8iXRugEcJ315Yy2jLc9jg9ZH2r9A8K+oUC3mzjKVfUY
-ww01ARKgjbobQaNuaIzPUvmWkGQ=
+ADCBiQKBgQC/EdMYN4RTiwfTfQrc9/ztzo1yOimvF+Ir0JlfPHspqag9AkIZggvf
+XZWsYNkIae2QNkJXOYdMzB6KHX6Su34C3wKASD84Iczp0bU0AY+SF+2XHREr3d/8
+dPTWZp/j5RDq6lOyp3hLljEGOAv6D9hYm/8qHy2MrmxCc0zSzxu30QIDAQABo4GE
+MIGBMA8GA1UdEwEB/wQFMAMBAf8wbgYDVR0RBGcwZYcEfwAAAocQ/oAAAAAAAAAA
+AAAAAAAAAYIMdGVzdC5leGFtcGxlgRF0ZXN0QHRlc3QuZXhhbXBsZaASBgMqAwSg
+CwwJaWdub3JlIG1lpBYwFDESMBAGA1UEAwwJMTI3LjAuMC4zMA0GCSqGSIb3DQEB
+BQUAA4GBAK2ZqCUpFR+4xyfwyNcqKmZUBysstB7+Jwcp2iI9ethNgXJ4PpZdTELO
+jMXR2bOskpkZ5SoyirzO+1iguedLRNgMLDAv+mxIfiN3T2fpcoM5Im8rTSUWPZi+
+ATGgVQqFeLi5nGbmy3uBHPyE0XkbQRIh+Mlb/Tym5G02WwpMqrsr
 -----END CERTIFICATE-----
diff --git a/net/data/ssl/scripts/ee.cnf b/net/data/ssl/scripts/ee.cnf
index ad786c8..5214f9e 100644
--- a/net/data/ssl/scripts/ee.cnf
+++ b/net/data/ssl/scripts/ee.cnf
@@ -29,7 +29,8 @@
 subjectAltName = IP:127.0.0.1
 
 [req_san_sanity]
-subjectAltName = @san_sanity
+basicConstraints = critical, CA:true
+subjectAltName   = @san_sanity
 
 [san_sanity]
 IP.1  = 127.0.0.2
diff --git a/net/data/url_request_unittest/redirect-to-data.html b/net/data/url_request_unittest/redirect-to-data.html
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/net/data/url_request_unittest/redirect-to-data.html
@@ -0,0 +1 @@
+hello
diff --git a/net/data/url_request_unittest/redirect-to-data.html.mock-http-headers b/net/data/url_request_unittest/redirect-to-data.html.mock-http-headers
new file mode 100644
index 0000000..f049471
--- /dev/null
+++ b/net/data/url_request_unittest/redirect-to-data.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 302 Here I Am
+Location: data:text/html,goodbye
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index bc48a2e..7eeeee1 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -313,7 +313,7 @@
   scoped_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(
       cache_path_, cache_thread.message_loop_proxy().get(), NULL));
   int rv = cache->Init(cb.callback());
-  ASSERT_EQ(net::ERR_FAILED, cb.GetResult(rv));
+  EXPECT_EQ(net::ERR_FAILED, cb.GetResult(rv));
   base::ThreadRestrictions::SetIOAllowed(prev);
 
   cache.reset();
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 857e07f..7addc85 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -392,7 +392,6 @@
   EXPECT_EQ(
       25000,
       entry->ReadData(1, 0, buffer2.get(), kSize2, net::CompletionCallback()));
-  EXPECT_EQ(0, memcmp(buffer2->data(), buffer2->data(), 10000));
   EXPECT_EQ(5000,
             entry->ReadData(
                 1, 30000, buffer2.get(), kSize2, net::CompletionCallback()));
diff --git a/net/disk_cache/simple/simple_backend_impl.cc b/net/disk_cache/simple/simple_backend_impl.cc
index 2877c01..4aed36c 100644
--- a/net/disk_cache/simple/simple_backend_impl.cc
+++ b/net/disk_cache/simple/simple_backend_impl.cc
@@ -380,7 +380,7 @@
 }
 
 void SimpleBackendImpl::OnExternalCacheHit(const std::string& key) {
-  index_->UseIfExists(key);
+  index_->UseIfExists(simple_util::GetEntryHashKey(key));
 }
 
 void SimpleBackendImpl::InitializeIndex(const CompletionCallback& callback,
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index 3c3ec7d..72d6d4c 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -246,7 +246,7 @@
   // have the entry in the index but we don't have the created files yet, this
   // way we never leak files. CreationOperationComplete will remove the entry
   // from the index if the creation fails.
-  backend_->index()->Insert(key_);
+  backend_->index()->Insert(entry_hash_);
 
   RunNextOperationIfNeeded();
   return ret_value;
@@ -536,7 +536,7 @@
 void SimpleEntryImpl::MarkAsDoomed() {
   if (!backend_.get())
     return;
-  backend_->index()->Remove(key_);
+  backend_->index()->Remove(entry_hash_);
   RemoveSelfFromBackend();
 }
 
@@ -780,7 +780,7 @@
 
   state_ = STATE_IO_PENDING;
   if (backend_.get())
-    backend_->index()->UseIfExists(key_);
+    backend_->index()->UseIfExists(entry_hash_);
 
   scoped_ptr<uint32> read_crc32(new uint32());
   scoped_ptr<int> result(new int());
@@ -840,7 +840,7 @@
   DCHECK_EQ(STATE_READY, state_);
   state_ = STATE_IO_PENDING;
   if (backend_.get())
-    backend_->index()->UseIfExists(key_);
+    backend_->index()->UseIfExists(entry_hash_);
   // It is easy to incrementally compute the CRC from [0 .. |offset + buf_len|)
   // if |offset == 0| or we have already computed the CRC for [0 .. offset).
   // We rely on most write operations being sequential, start to end to compute
@@ -1120,7 +1120,7 @@
     data_size_[i] = entry_stat.data_size[i];
   }
   if (backend_.get())
-    backend_->index()->UpdateEntrySize(key_, GetDiskUsage());
+    backend_->index()->UpdateEntrySize(entry_hash_, GetDiskUsage());
 }
 
 int64 SimpleEntryImpl::GetDiskUsage() const {
@@ -1136,13 +1136,30 @@
     const SimpleEntryOperation& operation) const {
   if (!executing_operation_)
     return;
-  // TODO(clamy): The values of this histogram should be changed to something
-  // more useful.
-  bool parallelizable_read =
-      !operation.alone_in_queue() &&
-      executing_operation_->type() == SimpleEntryOperation::TYPE_READ;
-  UMA_HISTOGRAM_BOOLEAN("SimpleCache.ReadIsParallelizable",
-                        parallelizable_read);
+  // Used in histograms, please only add entries at the end.
+  enum ReadDependencyType {
+    // READ_STANDALONE = 0, Deprecated.
+    READ_FOLLOWS_READ = 1,
+    READ_FOLLOWS_CONFLICTING_WRITE = 2,
+    READ_FOLLOWS_NON_CONFLICTING_WRITE = 3,
+    READ_FOLLOWS_OTHER = 4,
+    READ_ALONE_IN_QUEUE = 5,
+    READ_DEPENDENCY_TYPE_MAX = 6,
+  };
+
+  ReadDependencyType type = READ_FOLLOWS_OTHER;
+  if (operation.alone_in_queue()) {
+    type = READ_ALONE_IN_QUEUE;
+  } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ) {
+    type = READ_FOLLOWS_READ;
+  } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_WRITE) {
+    if (executing_operation_->ConflictsWith(operation))
+      type = READ_FOLLOWS_CONFLICTING_WRITE ;
+    else
+      type = READ_FOLLOWS_NON_CONFLICTING_WRITE;
+  }
+  UMA_HISTOGRAM_ENUMERATION(
+      "SimpleCache.ReadIsParallelizable", type, READ_DEPENDENCY_TYPE_MAX);
 }
 
 void SimpleEntryImpl::RecordWriteDependencyType(
diff --git a/net/disk_cache/simple/simple_index.cc b/net/disk_cache/simple/simple_index.cc
index 78ce87e..e17ada7 100644
--- a/net/disk_cache/simple/simple_index.cc
+++ b/net/disk_cache/simple/simple_index.cc
@@ -148,8 +148,10 @@
   }
 
 #if defined(OS_ANDROID)
-  activity_status_listener_.reset(new base::android::ActivityStatus::Listener(
-      base::Bind(&SimpleIndex::OnActivityStateChange, AsWeakPtr())));
+  if (base::android::IsVMInitialized()) {
+    activity_status_listener_.reset(new base::android::ActivityStatus::Listener(
+        base::Bind(&SimpleIndex::OnActivityStateChange, AsWeakPtr())));
+  }
 #endif
 
   SimpleIndexLoadResult* load_result = new SimpleIndexLoadResult();
@@ -199,30 +201,28 @@
   return entries_set_.size();
 }
 
-void SimpleIndex::Insert(const std::string& key) {
+void SimpleIndex::Insert(uint64 entry_hash) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
   // Upon insert we don't know yet the size of the entry.
   // It will be updated later when the SimpleEntryImpl finishes opening or
   // creating the new entry, and then UpdateEntrySize will be called.
-  const uint64 hash_key = simple_util::GetEntryHashKey(key);
   InsertInEntrySet(
-      hash_key, EntryMetadata(base::Time::Now(), 0), &entries_set_);
+      entry_hash, EntryMetadata(base::Time::Now(), 0), &entries_set_);
   if (!initialized_)
-    removed_entries_.erase(hash_key);
+    removed_entries_.erase(entry_hash);
   PostponeWritingToDisk();
 }
 
-void SimpleIndex::Remove(const std::string& key) {
+void SimpleIndex::Remove(uint64 entry_hash) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
-  const uint64 hash_key = simple_util::GetEntryHashKey(key);
-  EntrySet::iterator it = entries_set_.find(hash_key);
+  EntrySet::iterator it = entries_set_.find(entry_hash);
   if (it != entries_set_.end()) {
     UpdateEntryIteratorSize(&it, 0);
     entries_set_.erase(it);
   }
 
   if (!initialized_)
-    removed_entries_.insert(hash_key);
+    removed_entries_.insert(entry_hash);
   PostponeWritingToDisk();
 }
 
@@ -232,11 +232,11 @@
   return !initialized_ || entries_set_.count(hash) > 0;
 }
 
-bool SimpleIndex::UseIfExists(const std::string& key) {
+bool SimpleIndex::UseIfExists(uint64 entry_hash) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
   // Always update the last used time, even if it is during initialization.
   // It will be merged later.
-  EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key));
+  EntrySet::iterator it = entries_set_.find(entry_hash);
   if (it == entries_set_.end())
     // If not initialized, always return true, forcing it to go to the disk.
     return !initialized_;
@@ -292,9 +292,9 @@
       base::Bind(&SimpleIndex::EvictionDone, AsWeakPtr()));
 }
 
-bool SimpleIndex::UpdateEntrySize(const std::string& key, uint64 entry_size) {
+bool SimpleIndex::UpdateEntrySize(uint64 entry_hash, uint64 entry_size) {
   DCHECK(io_thread_checker_.CalledOnValidThread());
-  EntrySet::iterator it = entries_set_.find(simple_util::GetEntryHashKey(key));
+  EntrySet::iterator it = entries_set_.find(entry_hash);
   if (it == entries_set_.end())
     return false;
 
@@ -318,11 +318,11 @@
 
 // static
 void SimpleIndex::InsertInEntrySet(
-    uint64 hash_key,
+    uint64 entry_hash,
     const disk_cache::EntryMetadata& entry_metadata,
     EntrySet* entry_set) {
   DCHECK(entry_set);
-  entry_set->insert(std::make_pair(hash_key, entry_metadata));
+  entry_set->insert(std::make_pair(entry_hash, entry_metadata));
 }
 
 void SimpleIndex::PostponeWritingToDisk() {
diff --git a/net/disk_cache/simple/simple_index.h b/net/disk_cache/simple/simple_index.h
index 788ffb2..9890e29 100644
--- a/net/disk_cache/simple/simple_index.h
+++ b/net/disk_cache/simple/simple_index.h
@@ -6,7 +6,6 @@
 #define NET_DISK_CACHE_SIMPLE_SIMPLE_INDEX_H_
 
 #include <list>
-#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -83,26 +82,26 @@
   bool SetMaxSize(int max_bytes);
   int max_size() const { return max_size_; }
 
-  void Insert(const std::string& key);
-  void Remove(const std::string& key);
+  void Insert(uint64 entry_hash);
+  void Remove(uint64 entry_hash);
 
   // Check whether the index has the entry given the hash of its key.
-  bool Has(uint64 hash) const;
+  bool Has(uint64 entry_hash) const;
 
   // Update the last used time of the entry with the given key and return true
   // iff the entry exist in the index.
-  bool UseIfExists(const std::string& key);
+  bool UseIfExists(uint64 entry_hash);
 
   void WriteToDisk();
 
   // Update the size (in bytes) of an entry, in the metadata stored in the
   // index. This should be the total disk-file size including all streams of the
   // entry.
-  bool UpdateEntrySize(const std::string& key, uint64 entry_size);
+  bool UpdateEntrySize(uint64 entry_hash, uint64 entry_size);
 
   typedef base::hash_map<uint64, EntryMetadata> EntrySet;
 
-  static void InsertInEntrySet(uint64 hash_key,
+  static void InsertInEntrySet(uint64 entry_hash,
                                const EntryMetadata& entry_metadata,
                                EntrySet* entry_set);
 
@@ -161,7 +160,7 @@
   bool eviction_in_progress_;
   base::TimeTicks eviction_start_time_;
 
-  // This stores all the hash_key of entries that are removed during
+  // This stores all the entry_hash of entries that are removed during
   // initialization.
   base::hash_set<uint64> removed_entries_;
   bool initialized_;
diff --git a/net/disk_cache/simple/simple_index_file.cc b/net/disk_cache/simple/simple_index_file.cc
index 7bcea7c..0136be1 100644
--- a/net/disk_cache/simple/simple_index_file.cc
+++ b/net/disk_cache/simple/simple_index_file.cc
@@ -7,7 +7,6 @@
 #include <vector>
 
 #include "base/file_util.h"
-#include "base/files/file_enumerator.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/hash.h"
 #include "base/logging.h"
@@ -22,11 +21,17 @@
 #include "net/disk_cache/simple/simple_util.h"
 #include "third_party/zlib/zlib.h"
 
-
+namespace disk_cache {
 namespace {
 
+const int kEntryFilesHashLength = 16;
+const int kEntryFilesSuffixLength = 2;
+
 const uint64 kMaxEntiresInIndex = 100000000;
 
+const char kIndexFileName[] = "the-real-index";
+const char kTempIndexFileName[] = "temp-index";
+
 uint32 CalculatePickleCRC(const Pickle& pickle) {
   return crc32(crc32(0, Z_NULL, 0),
                reinterpret_cast<const Bytef*>(pickle.payload()),
@@ -67,9 +72,54 @@
   }
 }
 
-}  // namespace
+// Called for each cache directory traversal iteration.
+void ProcessEntryFile(SimpleIndex::EntrySet* entries,
+                      const base::FilePath& file_path) {
+  static const size_t kEntryFilesLength =
+      kEntryFilesHashLength + kEntryFilesSuffixLength;
+  // Converting to std::string is OK since we never use UTF8 wide chars in our
+  // file names.
+  const base::FilePath::StringType base_name = file_path.BaseName().value();
+  const std::string file_name(base_name.begin(), base_name.end());
+  if (file_name.size() != kEntryFilesLength)
+    return;
+  const base::StringPiece hash_string(
+      file_name.begin(), file_name.begin() + kEntryFilesHashLength);
+  uint64 hash_key = 0;
+  if (!simple_util::GetEntryHashKeyFromHexString(hash_string, &hash_key)) {
+    LOG(WARNING) << "Invalid entry hash key filename while restoring index from"
+                 << " disk: " << file_name;
+    return;
+  }
 
-namespace disk_cache {
+  base::PlatformFileInfo file_info;
+  if (!file_util::GetFileInfo(file_path, &file_info)) {
+    LOG(ERROR) << "Could not get file info for " << file_path.value();
+    return;
+  }
+  base::Time last_used_time;
+#if defined(OS_POSIX)
+  // For POSIX systems, a last access time is available. However, it's not
+  // guaranteed to be more accurate than mtime. It is no worse though.
+  last_used_time = file_info.last_accessed;
+#endif
+  if (last_used_time.is_null())
+    last_used_time = file_info.last_modified;
+
+  int64 file_size = file_info.size;
+  SimpleIndex::EntrySet::iterator it = entries->find(hash_key);
+  if (it == entries->end()) {
+    SimpleIndex::InsertInEntrySet(
+        hash_key,
+        EntryMetadata(last_used_time, file_size),
+        entries);
+  } else {
+    // Summing up the total size of the entry through all the *_[0-2] files
+    it->second.SetEntrySize(it->second.GetEntrySize() + file_size);
+  }
+}
+
+}  // namespace
 
 SimpleIndexLoadResult::SimpleIndexLoadResult() : did_load(false),
                                                  flush_required(false) {
@@ -84,11 +134,6 @@
   entries.clear();
 }
 
-// static
-const char SimpleIndexFile::kIndexFileName[] = "the-real-index";
-// static
-const char SimpleIndexFile::kTempIndexFileName[] = "temp-index";
-
 SimpleIndexFile::IndexMetadata::IndexMetadata() :
     magic_number_(kSimpleIndexMagicNumber),
     version_(kSimpleVersion),
@@ -350,7 +395,6 @@
     const base::FilePath& index_file_path,
     SimpleIndexLoadResult* out_result) {
   LOG(INFO) << "Simple Cache Index is being restored from disk.";
-
   base::DeleteFile(index_file_path, /* recursive = */ false);
   out_result->Reset();
   SimpleIndex::EntrySet* entries = &out_result->entries;
@@ -359,53 +403,13 @@
   COMPILE_ASSERT(kSimpleEntryFileCount == 3,
                  file_pattern_must_match_file_count);
 
-  const int kFileSuffixLength = sizeof("_0") - 1;
-  const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*_[0-2]");
-  base::FileEnumerator enumerator(cache_directory,
-                                  false /* recursive */,
-                                  base::FileEnumerator::FILES,
-                                  file_pattern);
-  for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
-       file_path = enumerator.Next()) {
-    const base::FilePath::StringType base_name = file_path.BaseName().value();
-    // Converting to std::string is OK since we never use UTF8 wide chars in our
-    // file names.
-    const std::string hash_key_string(base_name.begin(),
-                                      base_name.end() - kFileSuffixLength);
-    uint64 hash_key = 0;
-    if (!simple_util::GetEntryHashKeyFromHexString(
-            hash_key_string, &hash_key)) {
-      LOG(WARNING) << "Invalid Entry Hash Key filename while restoring "
-                   << "Simple Index from disk: " << base_name;
-      // TODO(felipeg): Should we delete the invalid file here ?
-      continue;
-    }
-
-    base::FileEnumerator::FileInfo info = enumerator.GetInfo();
-    base::Time last_used_time;
-#if defined(OS_POSIX)
-    // For POSIX systems, a last access time is available. However, it's not
-    // guaranteed to be more accurate than mtime. It is no worse though.
-    last_used_time = base::Time::FromTimeT(info.stat().st_atime);
-#endif
-    if (last_used_time.is_null())
-      last_used_time = info.GetLastModifiedTime();
-
-    int64 file_size = info.GetSize();
-    SimpleIndex::EntrySet::iterator it = entries->find(hash_key);
-    if (it == entries->end()) {
-      SimpleIndex::InsertInEntrySet(
-          hash_key,
-          EntryMetadata(last_used_time, file_size),
-          entries);
-    } else {
-      // Summing up the total size of the entry through all the *_[0-2] files
-      it->second.SetEntrySize(it->second.GetEntrySize() + file_size);
-    }
+  const bool did_succeed = TraverseCacheDirectory(
+      cache_directory, base::Bind(&ProcessEntryFile, entries));
+  if (!did_succeed) {
+    LOG(ERROR) << "Could not reconstruct index from disk";
+    return;
   }
-
   out_result->did_load = true;
-
   // When we restore from disk we write the merged index file to disk right
   // away, this might save us from having to restore again next time.
   out_result->flush_required = true;
diff --git a/net/disk_cache/simple/simple_index_file.h b/net/disk_cache/simple/simple_index_file.h
index b536df9..e5fc85d 100644
--- a/net/disk_cache/simple/simple_index_file.h
+++ b/net/disk_cache/simple/simple_index_file.h
@@ -97,6 +97,9 @@
  private:
   friend class WrappedSimpleIndexFile;
 
+  // Used for cache directory traversal.
+  typedef base::Callback<void (const base::FilePath&)> EntryFileCallback;
+
   // When loading the entries from disk, add this many extra hash buckets to
   // prevent reallocation on the IO thread when merging in new live entries.
   static const int kExtraSizeForMerge = 512;
@@ -123,6 +126,15 @@
   static void Deserialize(const char* data, int data_len,
                           SimpleIndexLoadResult* out_result);
 
+  // Implemented either in simple_index_file_posix.cc or
+  // simple_index_file_win.cc. base::FileEnumerator turned out to be very
+  // expensive in terms of memory usage therefore it's used only on non-POSIX
+  // environments for convenience (for now). Returns whether the traversal
+  // succeeded.
+  static bool TraverseCacheDirectory(
+      const base::FilePath& cache_path,
+      const EntryFileCallback& entry_file_callback);
+
   // Scan the index directory for entries, returning an EntrySet of all entries
   // found.
   static void SyncRestoreFromDisk(const base::FilePath& cache_directory,
@@ -144,9 +156,6 @@
   const base::FilePath index_file_;
   const base::FilePath temp_index_file_;
 
-  static const char kIndexFileName[];
-  static const char kTempIndexFileName[];
-
   DISALLOW_COPY_AND_ASSIGN(SimpleIndexFile);
 };
 
diff --git a/net/disk_cache/simple/simple_index_file_posix.cc b/net/disk_cache/simple/simple_index_file_posix.cc
new file mode 100644
index 0000000..586699d
--- /dev/null
+++ b/net/disk_cache/simple/simple_index_file_posix.cc
@@ -0,0 +1,52 @@
+// 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/disk_cache/simple/simple_index_file.h"
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace disk_cache {
+namespace {
+
+struct DirCloser {
+  void operator()(DIR* dir) { closedir(dir); }
+};
+
+typedef scoped_ptr<DIR, DirCloser> ScopedDir;
+
+}  // namespace
+
+// static
+bool SimpleIndexFile::TraverseCacheDirectory(
+    const base::FilePath& cache_path,
+    const EntryFileCallback& entry_file_callback) {
+  const ScopedDir dir(opendir(cache_path.value().c_str()));
+  if (!dir) {
+    PLOG(ERROR) << "opendir " << cache_path.value();
+    return false;
+  }
+  dirent entry, *result;
+  while (readdir_r(dir.get(), &entry, &result) == 0) {
+    if (!result)
+      return true;  // The traversal completed successfully.
+    const std::string file_name(result->d_name);
+    if (file_name == "." || file_name == "..")
+      continue;
+    const base::FilePath file_path = cache_path.Append(
+        base::FilePath(file_name));
+    entry_file_callback.Run(file_path);
+  }
+  PLOG(ERROR) << "readdir_r " << cache_path.value();
+  return false;
+}
+
+}  // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_index_file_win.cc b/net/disk_cache/simple/simple_index_file_win.cc
new file mode 100644
index 0000000..051d12d
--- /dev/null
+++ b/net/disk_cache/simple/simple_index_file_win.cc
@@ -0,0 +1,33 @@
+// 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/disk_cache/simple/simple_index_file.h"
+
+#include <string>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+
+namespace disk_cache {
+
+// static
+bool SimpleIndexFile::TraverseCacheDirectory(
+    const base::FilePath& cache_path,
+    const EntryFileCallback& entry_file_callback) {
+  const base::FilePath current_directory(FILE_PATH_LITERAL("."));
+  const base::FilePath parent_directory(FILE_PATH_LITERAL(".."));
+  const base::FilePath::StringType file_pattern = FILE_PATH_LITERAL("*");
+  base::FileEnumerator enumerator(
+      cache_path, false /* recursive */, base::FileEnumerator::FILES,
+      file_pattern);
+  for (base::FilePath file_path = enumerator.Next(); !file_path.empty();
+       file_path = enumerator.Next()) {
+    if (file_path == current_directory || file_path == parent_directory)
+      continue;
+    entry_file_callback.Run(file_path);
+  }
+  return true;
+}
+
+}  // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_index_unittest.cc b/net/disk_cache/simple/simple_index_unittest.cc
index 0c845b2..a2c9016 100644
--- a/net/disk_cache/simple/simple_index_unittest.cc
+++ b/net/disk_cache/simple/simple_index_unittest.cc
@@ -14,22 +14,20 @@
 #include "base/time/time.h"
 #include "net/disk_cache/simple/simple_index.h"
 #include "net/disk_cache/simple/simple_index_file.h"
+#include "net/disk_cache/simple/simple_test_util.h"
 #include "net/disk_cache/simple/simple_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace disk_cache {
 namespace {
 
 const int64 kTestLastUsedTimeInternal = 12345;
 const base::Time kTestLastUsedTime =
     base::Time::FromInternalValue(kTestLastUsedTimeInternal);
 const uint64 kTestEntrySize = 789;
-const uint64 kKey1Hash = disk_cache::simple_util::GetEntryHashKey("key1");
-const uint64 kKey2Hash = disk_cache::simple_util::GetEntryHashKey("key2");
-const uint64 kKey3Hash = disk_cache::simple_util::GetEntryHashKey("key3");
 
 }  // namespace
 
-namespace disk_cache {
 
 class EntryMetadataTest  : public testing::Test {
  public:
@@ -103,7 +101,14 @@
 };
 
 class SimpleIndexTest  : public testing::Test {
- public:
+ protected:
+  SimpleIndexTest() : hashes_(base::Bind(&HashesInitializer)) {}
+
+  static uint64 HashesInitializer(size_t hash_index) {
+    return disk_cache::simple_util::GetEntryHashKey(
+        base::StringPrintf("key%d", static_cast<int>(hash_index)));
+  }
+
   virtual void SetUp() OVERRIDE {
     scoped_ptr<MockSimpleIndexFile> index_file(new MockSimpleIndexFile());
     index_file_ = index_file->AsWeakPtr();
@@ -122,19 +127,17 @@
   }
 
   // Redirect to allow single "friend" declaration in base class.
-  bool GetEntryForTesting(const std::string& key, EntryMetadata* metadata) {
-    const uint64 hash_key = simple_util::GetEntryHashKey(key);
-    SimpleIndex::EntrySet::iterator it = index_->entries_set_.find(hash_key);
+  bool GetEntryForTesting(uint64 key, EntryMetadata* metadata) {
+    SimpleIndex::EntrySet::iterator it = index_->entries_set_.find(key);
     if (index_->entries_set_.end() == it)
       return false;
     *metadata = it->second;
     return true;
   }
 
-  void InsertIntoIndexFileReturn(const std::string& key,
+  void InsertIntoIndexFileReturn(uint64 hash_key,
                                  base::Time last_used_time,
                                  uint64 entry_size) {
-    uint64 hash_key(simple_util::GetEntryHashKey(key));
     index_file_->load_result()->entries.insert(std::make_pair(
         hash_key, EntryMetadata(last_used_time, entry_size)));
   }
@@ -148,7 +151,7 @@
   SimpleIndex* index() { return index_.get(); }
   const MockSimpleIndexFile* index_file() const { return index_file_.get(); }
 
- protected:
+  const simple_util::ImmutableArray<uint64, 16> hashes_;
   scoped_ptr<SimpleIndex> index_;
   base::WeakPtr<MockSimpleIndexFile> index_file_;
 };
@@ -181,31 +184,31 @@
 TEST_F(SimpleIndexTest, IndexSizeCorrectOnMerge) {
   typedef disk_cache::SimpleIndex::EntrySet EntrySet;
   index()->SetMaxSize(100);
-  index()->Insert("two");
-  index()->UpdateEntrySize("two", 2);
-  index()->Insert("five");
-  index()->UpdateEntrySize("five", 5);
-  index()->Insert("seven");
-  index()->UpdateEntrySize("seven", 7);
-  EXPECT_EQ(14U, index()->cache_size_);
+  index()->Insert(hashes_.at<2>());
+  index()->UpdateEntrySize(hashes_.at<2>(), 2);
+  index()->Insert(hashes_.at<3>());
+  index()->UpdateEntrySize(hashes_.at<3>(), 3);
+  index()->Insert(hashes_.at<4>());
+  index()->UpdateEntrySize(hashes_.at<4>(), 4);
+  EXPECT_EQ(9U, index()->cache_size_);
   {
     scoped_ptr<SimpleIndexLoadResult> result(new SimpleIndexLoadResult());
     result->did_load = true;
     index()->MergeInitializingSet(result.Pass());
   }
-  EXPECT_EQ(14U, index()->cache_size_);
+  EXPECT_EQ(9U, index()->cache_size_);
   {
     scoped_ptr<SimpleIndexLoadResult> result(new SimpleIndexLoadResult());
     result->did_load = true;
-    const uint64 new_hash_key = simple_util::GetEntryHashKey("eleven");
+    const uint64 new_hash_key = hashes_.at<11>();
     result->entries.insert(
         std::make_pair(new_hash_key, EntryMetadata(base::Time::Now(), 11)));
-    const uint64 redundant_hash_key = simple_util::GetEntryHashKey("seven");
+    const uint64 redundant_hash_key = hashes_.at<4>();
     result->entries.insert(std::make_pair(redundant_hash_key,
-                                          EntryMetadata(base::Time::Now(), 7)));
+                                          EntryMetadata(base::Time::Now(), 4)));
     index()->MergeInitializingSet(result.Pass());
   }
-  EXPECT_EQ(2U + 5U + 7U + 11U, index()->cache_size_);
+  EXPECT_EQ(2U + 3U + 4U + 11U, index()->cache_size_);
 }
 
 // State of index changes as expected with an insert and a remove.
@@ -216,8 +219,8 @@
   EXPECT_EQ(0ul, metadata.GetEntrySize());
 
   // Confirm state after insert.
-  index()->Insert("key1");
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata));
+  index()->Insert(hashes_.at<1>());
+  ASSERT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
   base::Time now(base::Time::Now());
   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
@@ -225,8 +228,8 @@
 
   // Confirm state after remove.
   metadata = EntryMetadata();
-  index()->Remove("key1");
-  EXPECT_FALSE(GetEntryForTesting("key1", &metadata));
+  index()->Remove(hashes_.at<1>());
+  EXPECT_FALSE(GetEntryForTesting(hashes_.at<1>(), &metadata));
   EXPECT_EQ(base::Time(), metadata.GetLastUsedTime());
   EXPECT_EQ(0ul, metadata.GetEntrySize());
 }
@@ -237,20 +240,21 @@
   EXPECT_EQ(1, index_file_->load_index_entries_calls());
 
   // Confirm "Has()" always returns true before the callback is called.
-  EXPECT_TRUE(index()->Has(kKey1Hash));
-  index()->Insert("key1");
-  EXPECT_TRUE(index()->Has(kKey1Hash));
-  index()->Remove("key1");
+  const uint64 kHash1 = hashes_.at<1>();
+  EXPECT_TRUE(index()->Has(kHash1));
+  index()->Insert(kHash1);
+  EXPECT_TRUE(index()->Has(kHash1));
+  index()->Remove(kHash1);
   // TODO(rdsmith): Maybe return false on explicitly removed entries?
-  EXPECT_TRUE(index()->Has(kKey1Hash));
+  EXPECT_TRUE(index()->Has(kHash1));
 
   ReturnIndexFile();
 
   // Confirm "Has() returns conditionally now.
-  EXPECT_FALSE(index()->Has(kKey1Hash));
-  index()->Insert("key1");
-  EXPECT_TRUE(index()->Has(kKey1Hash));
-  index()->Remove("key1");
+  EXPECT_FALSE(index()->Has(kHash1));
+  index()->Insert(kHash1);
+  EXPECT_TRUE(index()->Has(kHash1));
+  index()->Remove(kHash1);
 }
 
 TEST_F(SimpleIndexTest, UseIfExists) {
@@ -260,37 +264,38 @@
 
   // Confirm "UseIfExists()" always returns true before the callback is called
   // and updates mod time if the entry was really there.
+  const uint64 kHash1 = hashes_.at<1>();
   EntryMetadata metadata1, metadata2;
-  EXPECT_TRUE(index()->UseIfExists("key1"));
-  EXPECT_FALSE(GetEntryForTesting("key1", &metadata1));
-  index()->Insert("key1");
-  EXPECT_TRUE(index()->UseIfExists("key1"));
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata1));
+  EXPECT_TRUE(index()->UseIfExists(kHash1));
+  EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
+  index()->Insert(kHash1);
+  EXPECT_TRUE(index()->UseIfExists(kHash1));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
   WaitForTimeChange();
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata2));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
   EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
-  EXPECT_TRUE(index()->UseIfExists("key1"));
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata2));
+  EXPECT_TRUE(index()->UseIfExists(kHash1));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
   EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
-  index()->Remove("key1");
-  EXPECT_TRUE(index()->UseIfExists("key1"));
+  index()->Remove(kHash1);
+  EXPECT_TRUE(index()->UseIfExists(kHash1));
 
   ReturnIndexFile();
 
   // Confirm "UseIfExists() returns conditionally now
-  EXPECT_FALSE(index()->UseIfExists("key1"));
-  EXPECT_FALSE(GetEntryForTesting("key1", &metadata1));
-  index()->Insert("key1");
-  EXPECT_TRUE(index()->UseIfExists("key1"));
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata1));
+  EXPECT_FALSE(index()->UseIfExists(kHash1));
+  EXPECT_FALSE(GetEntryForTesting(kHash1, &metadata1));
+  index()->Insert(kHash1);
+  EXPECT_TRUE(index()->UseIfExists(kHash1));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata1));
   WaitForTimeChange();
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata2));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
   EXPECT_EQ(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
-  EXPECT_TRUE(index()->UseIfExists("key1"));
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata2));
+  EXPECT_TRUE(index()->UseIfExists(kHash1));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata2));
   EXPECT_LT(metadata1.GetLastUsedTime(), metadata2.GetLastUsedTime());
-  index()->Remove("key1");
-  EXPECT_FALSE(index()->UseIfExists("key1"));
+  index()->Remove(kHash1);
+  EXPECT_FALSE(index()->UseIfExists(kHash1));
 }
 
 TEST_F(SimpleIndexTest, UpdateEntrySize) {
@@ -298,43 +303,42 @@
 
   index()->SetMaxSize(1000);
 
-  InsertIntoIndexFileReturn("key1",
-                            now - base::TimeDelta::FromDays(2),
-                            475u);
+  const uint64 kHash1 = hashes_.at<1>();
+  InsertIntoIndexFileReturn(kHash1, now - base::TimeDelta::FromDays(2), 475u);
   ReturnIndexFile();
 
   EntryMetadata metadata;
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
   EXPECT_EQ(now - base::TimeDelta::FromDays(2), metadata.GetLastUsedTime());
   EXPECT_EQ(475u, metadata.GetEntrySize());
 
-  index()->UpdateEntrySize("key1", 600u);
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata));
+  index()->UpdateEntrySize(kHash1, 600u);
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
   EXPECT_EQ(600u, metadata.GetEntrySize());
   EXPECT_EQ(1, index()->GetEntryCount());
 }
 
 TEST_F(SimpleIndexTest, GetEntryCount) {
   EXPECT_EQ(0, index()->GetEntryCount());
-  index()->Insert("key1");
+  index()->Insert(hashes_.at<1>());
   EXPECT_EQ(1, index()->GetEntryCount());
-  index()->Insert("key2");
+  index()->Insert(hashes_.at<2>());
   EXPECT_EQ(2, index()->GetEntryCount());
-  index()->Insert("key3");
+  index()->Insert(hashes_.at<3>());
   EXPECT_EQ(3, index()->GetEntryCount());
-  index()->Insert("key3");
+  index()->Insert(hashes_.at<3>());
   EXPECT_EQ(3, index()->GetEntryCount());
-  index()->Remove("key2");
+  index()->Remove(hashes_.at<2>());
   EXPECT_EQ(2, index()->GetEntryCount());
-  index()->Insert("key4");
+  index()->Insert(hashes_.at<4>());
   EXPECT_EQ(3, index()->GetEntryCount());
-  index()->Remove("key3");
+  index()->Remove(hashes_.at<3>());
   EXPECT_EQ(2, index()->GetEntryCount());
-  index()->Remove("key3");
+  index()->Remove(hashes_.at<3>());
   EXPECT_EQ(2, index()->GetEntryCount());
-  index()->Remove("key1");
+  index()->Remove(hashes_.at<1>());
   EXPECT_EQ(1, index()->GetEntryCount());
-  index()->Remove("key4");
+  index()->Remove(hashes_.at<4>());
   EXPECT_EQ(0, index()->GetEntryCount());
 }
 
@@ -342,48 +346,50 @@
 TEST_F(SimpleIndexTest, BasicInit) {
   base::Time now(base::Time::Now());
 
-  InsertIntoIndexFileReturn("key1",
+  InsertIntoIndexFileReturn(hashes_.at<1>(),
                             now - base::TimeDelta::FromDays(2),
                             10u);
-  InsertIntoIndexFileReturn("key2",
+  InsertIntoIndexFileReturn(hashes_.at<2>(),
                             now - base::TimeDelta::FromDays(3),
                             100u);
 
   ReturnIndexFile();
 
   EntryMetadata metadata;
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(hashes_.at<1>(), &metadata));
   EXPECT_EQ(now - base::TimeDelta::FromDays(2), metadata.GetLastUsedTime());
   EXPECT_EQ(10ul, metadata.GetEntrySize());
-  EXPECT_TRUE(GetEntryForTesting("key2", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
   EXPECT_EQ(now - base::TimeDelta::FromDays(3), metadata.GetLastUsedTime());
   EXPECT_EQ(100ul, metadata.GetEntrySize());
 }
 
 // Remove something that's going to come in from the loaded index.
 TEST_F(SimpleIndexTest, RemoveBeforeInit) {
-  index()->Remove("key1");
+  const uint64 kHash1 = hashes_.at<1>();
+  index()->Remove(kHash1);
 
-  InsertIntoIndexFileReturn("key1",
+  InsertIntoIndexFileReturn(kHash1,
                             base::Time::Now() - base::TimeDelta::FromDays(2),
                             10u);
   ReturnIndexFile();
 
-  EXPECT_FALSE(index()->Has(kKey1Hash));
+  EXPECT_FALSE(index()->Has(kHash1));
 }
 
 // Insert something that's going to come in from the loaded index; correct
 // result?
 TEST_F(SimpleIndexTest, InsertBeforeInit) {
-  index()->Insert("key1");
+  const uint64 kHash1 = hashes_.at<1>();
+  index()->Insert(kHash1);
 
-  InsertIntoIndexFileReturn("key1",
+  InsertIntoIndexFileReturn(kHash1,
                             base::Time::Now() - base::TimeDelta::FromDays(2),
                             10u);
   ReturnIndexFile();
 
   EntryMetadata metadata;
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
   base::Time now(base::Time::Now());
   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
@@ -392,29 +398,31 @@
 
 // Insert and Remove something that's going to come in from the loaded index.
 TEST_F(SimpleIndexTest, InsertRemoveBeforeInit) {
-  index()->Insert("key1");
-  index()->Remove("key1");
+  const uint64 kHash1 = hashes_.at<1>();
+  index()->Insert(kHash1);
+  index()->Remove(kHash1);
 
-  InsertIntoIndexFileReturn("key1",
+  InsertIntoIndexFileReturn(kHash1,
                             base::Time::Now() - base::TimeDelta::FromDays(2),
                             10u);
   ReturnIndexFile();
 
-  EXPECT_FALSE(index()->Has(kKey1Hash));
+  EXPECT_FALSE(index()->Has(kHash1));
 }
 
 // Insert and Remove something that's going to come in from the loaded index.
 TEST_F(SimpleIndexTest, RemoveInsertBeforeInit) {
-  index()->Remove("key1");
-  index()->Insert("key1");
+  const uint64 kHash1 = hashes_.at<1>();
+  index()->Remove(kHash1);
+  index()->Insert(kHash1);
 
-  InsertIntoIndexFileReturn("key1",
+  InsertIntoIndexFileReturn(kHash1,
                             base::Time::Now() - base::TimeDelta::FromDays(2),
                             10u);
   ReturnIndexFile();
 
   EntryMetadata metadata;
-  EXPECT_TRUE(GetEntryForTesting("key1", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(kHash1, &metadata));
   base::Time now(base::Time::Now());
   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
@@ -426,46 +434,46 @@
 TEST_F(SimpleIndexTest, AllInitConflicts) {
   base::Time now(base::Time::Now());
 
-  index()->Remove("key1");
-  InsertIntoIndexFileReturn("key1",
+  index()->Remove(hashes_.at<1>());
+  InsertIntoIndexFileReturn(hashes_.at<1>(),
                             now - base::TimeDelta::FromDays(2),
                             10u);
-  index()->Insert("key2");
-  InsertIntoIndexFileReturn("key2",
+  index()->Insert(hashes_.at<2>());
+  InsertIntoIndexFileReturn(hashes_.at<2>(),
                             now - base::TimeDelta::FromDays(3),
                             100u);
-  index()->Insert("key3");
-  index()->Remove("key3");
-  InsertIntoIndexFileReturn("key3",
+  index()->Insert(hashes_.at<3>());
+  index()->Remove(hashes_.at<3>());
+  InsertIntoIndexFileReturn(hashes_.at<3>(),
                             now - base::TimeDelta::FromDays(4),
                             1000u);
-  index()->Remove("key4");
-  index()->Insert("key4");
-  InsertIntoIndexFileReturn("key4",
+  index()->Remove(hashes_.at<4>());
+  index()->Insert(hashes_.at<4>());
+  InsertIntoIndexFileReturn(hashes_.at<4>(),
                             now - base::TimeDelta::FromDays(5),
                             10000u);
-  InsertIntoIndexFileReturn("key5",
+  InsertIntoIndexFileReturn(hashes_.at<5>(),
                             now - base::TimeDelta::FromDays(6),
                             100000u);
 
   ReturnIndexFile();
 
-  EXPECT_FALSE(index()->Has(kKey1Hash));
+  EXPECT_FALSE(index()->Has(hashes_.at<1>()));
 
   EntryMetadata metadata;
-  EXPECT_TRUE(GetEntryForTesting("key2", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(hashes_.at<2>(), &metadata));
   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
   EXPECT_EQ(0ul, metadata.GetEntrySize());
 
-  EXPECT_FALSE(index()->Has(kKey3Hash));
+  EXPECT_FALSE(index()->Has(hashes_.at<3>()));
 
-  EXPECT_TRUE(GetEntryForTesting("key4", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(hashes_.at<4>(), &metadata));
   EXPECT_LT(now - base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
   EXPECT_GT(now + base::TimeDelta::FromMinutes(1), metadata.GetLastUsedTime());
   EXPECT_EQ(0ul, metadata.GetEntrySize());
 
-  EXPECT_TRUE(GetEntryForTesting("key5", &metadata));
+  EXPECT_TRUE(GetEntryForTesting(hashes_.at<5>(), &metadata));
   EXPECT_EQ(now - base::TimeDelta::FromDays(6), metadata.GetLastUsedTime());
   EXPECT_EQ(100000u, metadata.GetEntrySize());
 }
@@ -473,33 +481,33 @@
 TEST_F(SimpleIndexTest, BasicEviction) {
   base::Time now(base::Time::Now());
   index()->SetMaxSize(1000);
-  InsertIntoIndexFileReturn("key1",
+  InsertIntoIndexFileReturn(hashes_.at<1>(),
                             now - base::TimeDelta::FromDays(2),
                             475u);
-  index()->Insert("key2");
-  index()->UpdateEntrySize("key2", 475);
+  index()->Insert(hashes_.at<2>());
+  index()->UpdateEntrySize(hashes_.at<2>(), 475);
   ReturnIndexFile();
 
   WaitForTimeChange();
 
-  index()->Insert("key3");
+  index()->Insert(hashes_.at<3>());
   // Confirm index is as expected: No eviction, everything there.
   EXPECT_EQ(3, index()->GetEntryCount());
   EXPECT_EQ(0, index_file()->doom_entry_set_calls());
-  EXPECT_TRUE(index()->Has(kKey1Hash));
-  EXPECT_TRUE(index()->Has(kKey2Hash));
-  EXPECT_TRUE(index()->Has(kKey3Hash));
+  EXPECT_TRUE(index()->Has(hashes_.at<1>()));
+  EXPECT_TRUE(index()->Has(hashes_.at<2>()));
+  EXPECT_TRUE(index()->Has(hashes_.at<3>()));
 
   // Trigger an eviction, and make sure the right things are tossed.
   // TODO(rdsmith): This is dependent on the innards of the implementation
   // as to at exactly what point we trigger eviction.  Not sure how to fix
   // that.
-  index()->UpdateEntrySize("key3", 475);
+  index()->UpdateEntrySize(hashes_.at<3>(), 475);
   EXPECT_EQ(1, index_file()->doom_entry_set_calls());
   EXPECT_EQ(1, index()->GetEntryCount());
-  EXPECT_FALSE(index()->Has(kKey1Hash));
-  EXPECT_FALSE(index()->Has(kKey2Hash));
-  EXPECT_TRUE(index()->Has(kKey3Hash));
+  EXPECT_FALSE(index()->Has(hashes_.at<1>()));
+  EXPECT_FALSE(index()->Has(hashes_.at<2>()));
+  EXPECT_TRUE(index()->Has(hashes_.at<3>()));
   ASSERT_EQ(2u, index_file_->last_doom_entry_hashes().size());
 }
 
@@ -511,20 +519,21 @@
 
   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
 
-  index()->Insert("key1");
+  const uint64 kHash1 = hashes_.at<1>();
+  index()->Insert(kHash1);
   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
   index()->write_to_disk_timer_.Stop();
   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
 
-  index()->UseIfExists("key1");
+  index()->UseIfExists(kHash1);
   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
   index()->write_to_disk_timer_.Stop();
 
-  index()->UpdateEntrySize("key1", 20);
+  index()->UpdateEntrySize(kHash1, 20);
   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
   index()->write_to_disk_timer_.Stop();
 
-  index()->Remove("key1");
+  index()->Remove(kHash1);
   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
   index()->write_to_disk_timer_.Stop();
 }
@@ -535,8 +544,9 @@
 
   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
 
-  index()->Insert("key1");
-  index()->UpdateEntrySize("key1", 20);
+  const uint64 kHash1 = hashes_.at<1>();
+  index()->Insert(kHash1);
+  index()->UpdateEntrySize(kHash1, 20);
   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
   base::Closure user_task(index()->write_to_disk_timer_.user_task());
   index()->write_to_disk_timer_.Stop();
@@ -547,7 +557,7 @@
   SimpleIndex::EntrySet entry_set;
   index_file_->GetAndResetDiskWriteEntrySet(&entry_set);
 
-  uint64 hash_key(simple_util::GetEntryHashKey("key1"));
+  uint64 hash_key = kHash1;
   base::Time now(base::Time::Now());
   ASSERT_EQ(1u, entry_set.size());
   EXPECT_EQ(hash_key, entry_set.begin()->first);
@@ -563,16 +573,16 @@
 
   EXPECT_FALSE(index()->write_to_disk_timer_.IsRunning());
 
-  index()->Insert("key1");
-  index()->UpdateEntrySize("key1", 20);
+  index()->Insert(hashes_.at<1>());
+  index()->UpdateEntrySize(hashes_.at<1>(), 20);
   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
   base::TimeTicks expected_trigger(
       index()->write_to_disk_timer_.desired_run_time());
 
   WaitForTimeChange();
   EXPECT_EQ(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
-  index()->Insert("key2");
-  index()->UpdateEntrySize("key2", 40);
+  index()->Insert(hashes_.at<2>());
+  index()->UpdateEntrySize(hashes_.at<2>(), 40);
   EXPECT_TRUE(index()->write_to_disk_timer_.IsRunning());
   EXPECT_LT(expected_trigger, index()->write_to_disk_timer_.desired_run_time());
   index()->write_to_disk_timer_.Stop();
diff --git a/net/disk_cache/simple/simple_synchronous_entry.cc b/net/disk_cache/simple/simple_synchronous_entry.cc
index e6f1eaa..5452624 100644
--- a/net/disk_cache/simple/simple_synchronous_entry.cc
+++ b/net/disk_cache/simple/simple_synchronous_entry.cc
@@ -514,6 +514,11 @@
       else
         out_entry_stat->last_modified = file_info.last_modified;
 
+      base::TimeDelta entry_age =
+          base::Time::Now() - out_entry_stat->last_modified;
+      UMA_HISTOGRAM_CUSTOM_COUNTS(
+          "SimpleCache.SyncOpenEntryAge", entry_age.InHours(), 1, 1000, 50);
+
       // Keep the file size in |data size_| briefly until the key is initialized
       // properly.
       out_entry_stat->data_size[i] = file_info.size;
diff --git a/net/disk_cache/simple/simple_test_util.cc b/net/disk_cache/simple/simple_test_util.cc
index 483cbec..9f09974 100644
--- a/net/disk_cache/simple/simple_test_util.cc
+++ b/net/disk_cache/simple/simple_test_util.cc
@@ -8,7 +8,6 @@
 #include "net/disk_cache/simple/simple_util.h"
 
 namespace disk_cache {
-
 namespace simple_util {
 
 bool CreateCorruptFileForTests(const std::string& key,
@@ -30,5 +29,4 @@
 }
 
 }  // namespace simple_backend
-
 }  // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_test_util.h b/net/disk_cache/simple/simple_test_util.h
index 98c140b..82eebbe 100644
--- a/net/disk_cache/simple/simple_test_util.h
+++ b/net/disk_cache/simple/simple_test_util.h
@@ -8,22 +8,41 @@
 #include <string>
 
 #include "base/basictypes.h"
-#include "net/base/net_export.h"
+#include "base/callback.h"
 
 namespace base {
 class FilePath;
 }
 
 namespace disk_cache {
-
 namespace simple_util {
 
+// Immutable array with compile-time bound-checking.
+template <typename T, size_t Size>
+class ImmutableArray {
+ public:
+  static const size_t size = Size;
+
+  ImmutableArray(const base::Callback<T (size_t index)>& initializer) {
+    for (size_t i = 0; i < size; ++i)
+      data_[i] = initializer.Run(i);
+  }
+
+  template <size_t Index>
+  const T& at() const {
+    COMPILE_ASSERT(Index < size, array_out_of_bounds);
+    return data_[Index];
+  }
+
+ private:
+  T data_[size];
+};
+
 // Creates a corrupt file to be used in tests.
 bool CreateCorruptFileForTests(const std::string& key,
                                const base::FilePath& cache_path);
 
 }  // namespace simple_backend
-
 }  // namespace disk_cache
 
 #endif  // NET_DISK_CACHE_SIMPLE_SIMPLE_TEST_UTIL_H_
diff --git a/net/disk_cache/simple/simple_util.cc b/net/disk_cache/simple/simple_util.cc
index 72a4612..e9ec067 100644
--- a/net/disk_cache/simple/simple_util.cc
+++ b/net/disk_cache/simple/simple_util.cc
@@ -40,7 +40,7 @@
   return hash_key_str;
 }
 
-bool GetEntryHashKeyFromHexString(const std::string& hash_key,
+bool GetEntryHashKeyFromHexString(const base::StringPiece& hash_key,
                                   uint64* hash_key_out) {
   if (hash_key.size() != kEntryHashKeyAsHexStringSize) {
     return false;
diff --git a/net/disk_cache/simple/simple_util.h b/net/disk_cache/simple/simple_util.h
index 2e92b4a..3bb80b9 100644
--- a/net/disk_cache/simple/simple_util.h
+++ b/net/disk_cache/simple/simple_util.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/strings/string_piece.h"
 #include "net/base/net_export.h"
 
 namespace base {
@@ -33,7 +34,7 @@
 // Parses the |hash_key| string into a uint64 buffer.
 // |hash_key| string must be of the form: FFFFFFFFFFFFFFFF .
 NET_EXPORT_PRIVATE bool GetEntryHashKeyFromHexString(
-    const std::string& hash_key,
+    const base::StringPiece& hash_key,
     uint64* hash_key_out);
 
 // Given a |key| for a (potential) entry in the simple backend and the |index|
diff --git a/net/dns/address_sorter_posix_unittest.cc b/net/dns/address_sorter_posix_unittest.cc
index 96cbfc6..c451737 100644
--- a/net/dns/address_sorter_posix_unittest.cc
+++ b/net/dns/address_sorter_posix_unittest.cc
@@ -10,6 +10,8 @@
 #include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/socket/client_socket_factory.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/stream_socket.h"
 #include "net/udp/datagram_client_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -90,27 +92,27 @@
   TestSocketFactory() {}
   virtual ~TestSocketFactory() {}
 
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType,
       const RandIntCallback&,
       NetLog*,
       const NetLog::Source&) OVERRIDE {
-    return new TestUDPClientSocket(&mapping_);
+    return scoped_ptr<DatagramClientSocket>(new TestUDPClientSocket(&mapping_));
   }
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList&,
       NetLog*,
       const NetLog::Source&) OVERRIDE {
     NOTIMPLEMENTED();
-    return NULL;
+    return scoped_ptr<StreamSocket>();
   }
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle*,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle>,
       const HostPortPair&,
       const SSLConfig&,
       const SSLClientSocketContext&) OVERRIDE {
     NOTIMPLEMENTED();
-    return NULL;
+    return scoped_ptr<SSLClientSocket>();
   }
   virtual void ClearSSLSessionCache() OVERRIDE {
     NOTIMPLEMENTED();
diff --git a/net/dns/dns_client.cc b/net/dns/dns_client.cc
index 976f153..9e29ca4 100644
--- a/net/dns/dns_client.cc
+++ b/net/dns/dns_client.cc
@@ -27,7 +27,7 @@
   virtual void SetConfig(const DnsConfig& config) OVERRIDE {
     factory_.reset();
     session_ = NULL;
-    if (config.IsValid()) {
+    if (config.IsValid() && !config.unhandled_options) {
       ClientSocketFactory* factory = ClientSocketFactory::GetDefaultFactory();
       scoped_ptr<DnsSocketPool> socket_pool(
           config.randomize_ports ? DnsSocketPool::CreateDefault(factory)
diff --git a/net/dns/dns_client.h b/net/dns/dns_client.h
index 650c7d0..0484d44 100644
--- a/net/dns/dns_client.h
+++ b/net/dns/dns_client.h
@@ -22,7 +22,8 @@
  public:
   virtual ~DnsClient() {}
 
-  // Creates a new DnsTransactionFactory according to the new |config|.
+  // Destroys the current DnsTransactionFactory and creates a new one
+  // according to |config|, unless it is invalid or has |unhandled_options|.
   virtual void SetConfig(const DnsConfig& config) = 0;
 
   // Returns NULL if the current config is not valid.
diff --git a/net/dns/dns_config_service.cc b/net/dns/dns_config_service.cc
index ea8a342..d7af988 100644
--- a/net/dns/dns_config_service.cc
+++ b/net/dns/dns_config_service.cc
@@ -14,7 +14,8 @@
 // Default values are taken from glibc resolv.h except timeout which is set to
 // |kDnsTimeoutSeconds|.
 DnsConfig::DnsConfig()
-    : append_to_multi_label_name(true),
+    : unhandled_options(false),
+      append_to_multi_label_name(true),
       randomize_ports(false),
       ndots(1),
       timeout(base::TimeDelta::FromSeconds(kDnsTimeoutSeconds)),
@@ -31,6 +32,7 @@
 bool DnsConfig::EqualsIgnoreHosts(const DnsConfig& d) const {
   return (nameservers == d.nameservers) &&
          (search == d.search) &&
+         (unhandled_options == d.unhandled_options) &&
          (append_to_multi_label_name == d.append_to_multi_label_name) &&
          (ndots == d.ndots) &&
          (timeout == d.timeout) &&
@@ -42,6 +44,7 @@
 void DnsConfig::CopyIgnoreHosts(const DnsConfig& d) {
   nameservers = d.nameservers;
   search = d.search;
+  unhandled_options = d.unhandled_options;
   append_to_multi_label_name = d.append_to_multi_label_name;
   ndots = d.ndots;
   timeout = d.timeout;
@@ -63,6 +66,7 @@
     list->Append(new base::StringValue(search[i]));
   dict->Set("search", list);
 
+  dict->SetBoolean("unhandled_options", unhandled_options);
   dict->SetBoolean("append_to_multi_label_name", append_to_multi_label_name);
   dict->SetInteger("ndots", ndots);
   dict->SetDouble("timeout", timeout.InSecondsF());
diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h
index 4babb9e..d14a2cd 100644
--- a/net/dns/dns_config_service.h
+++ b/net/dns/dns_config_service.h
@@ -59,6 +59,10 @@
 
   DnsHosts hosts;
 
+  // True if there are options set in the system configuration that are not yet
+  // supported by DnsClient.
+  bool unhandled_options;
+
   // AppendToMultiLabelName: is suffix search performed for multi-label names?
   // True, except on Windows where it can be configured.
   bool append_to_multi_label_name;
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index ff2295e..baf9172 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
+#include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
@@ -20,6 +21,69 @@
 #include "net/dns/notify_watcher_mac.h"
 #include "net/dns/serial_worker.h"
 
+#if defined(OS_MACOSX)
+#include <dlfcn.h>
+
+#include "third_party/apple_apsl/dnsinfo.h"
+
+namespace {
+
+// dnsinfo symbols are available via libSystem.dylib, but can also be present in
+// SystemConfiguration.framework. To avoid confusion, load them explicitly from
+// libSystem.dylib.
+class DnsInfoApi {
+ public:
+  typedef const char* (*dns_configuration_notify_key_t)();
+  typedef dns_config_t* (*dns_configuration_copy_t)();
+  typedef void (*dns_configuration_free_t)(dns_config_t*);
+
+  DnsInfoApi()
+      : dns_configuration_notify_key(NULL),
+        dns_configuration_copy(NULL),
+        dns_configuration_free(NULL) {
+    handle_ = dlopen("/usr/lib/libSystem.dylib",
+                     RTLD_LAZY | RTLD_NOLOAD);
+    if (!handle_)
+      return;
+    dns_configuration_notify_key =
+        reinterpret_cast<dns_configuration_notify_key_t>(
+            dlsym(handle_, "dns_configuration_notify_key"));
+    dns_configuration_copy =
+        reinterpret_cast<dns_configuration_copy_t>(
+            dlsym(handle_, "dns_configuration_copy"));
+    dns_configuration_free =
+        reinterpret_cast<dns_configuration_free_t>(
+            dlsym(handle_, "dns_configuration_free"));
+  }
+
+  ~DnsInfoApi() {
+    if (handle_)
+      dlclose(handle_);
+  }
+
+  dns_configuration_notify_key_t dns_configuration_notify_key;
+  dns_configuration_copy_t dns_configuration_copy;
+  dns_configuration_free_t dns_configuration_free;
+
+ private:
+  void* handle_;
+};
+
+const DnsInfoApi& GetDnsInfoApi() {
+  static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER;
+  return api.Get();
+}
+
+struct DnsConfigTDeleter {
+  inline void operator()(dns_config_t* ptr) const {
+    if (GetDnsInfoApi().dns_configuration_free)
+      GetDnsInfoApi().dns_configuration_free(ptr);
+  }
+};
+
+}  // namespace
+#endif  // defined(OS_MACOSX)
+
 namespace net {
 
 #if !defined(OS_ANDROID)
@@ -31,14 +95,13 @@
     FILE_PATH_LITERAL("/etc/hosts");
 
 #if defined(OS_MACOSX)
-// From 10.7.3 configd-395.10/dnsinfo/dnsinfo.h
-static const char* kDnsNotifyKey =
-    "com.apple.system.SystemConfiguration.dns_configuration";
-
 class ConfigWatcher {
  public:
   bool Watch(const base::Callback<void(bool succeeded)>& callback) {
-    return watcher_.Watch(kDnsNotifyKey, callback);
+    if (!GetDnsInfoApi().dns_configuration_notify_key)
+      return false;
+    return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(),
+                          callback);
   }
 
  private:
@@ -76,6 +139,7 @@
 
 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) {
   ConfigParsePosixResult result;
+  config->unhandled_options = false;
 #if defined(OS_OPENBSD)
   // Note: res_ninit in glibc always returns 0 and sets RES_INIT.
   // res_init behaves the same way.
@@ -100,6 +164,32 @@
   res_nclose(&res);
 #endif
 #endif
+
+#if defined(OS_MACOSX)
+  if (!GetDnsInfoApi().dns_configuration_copy)
+    return CONFIG_PARSE_POSIX_NO_DNSINFO;
+  scoped_ptr<dns_config_t, DnsConfigTDeleter> dns_config(
+      GetDnsInfoApi().dns_configuration_copy());
+  if (!dns_config)
+    return CONFIG_PARSE_POSIX_NO_DNSINFO;
+
+  // TODO(szym): Parse dns_config_t for resolvers rather than res_state.
+  // DnsClient can't handle domain-specific unscoped resolvers.
+  unsigned num_resolvers = 0;
+  for (int i = 0; i < dns_config->n_resolver; ++i) {
+    dns_resolver_t* resolver = dns_config->resolver[i];
+    if (!resolver->n_nameserver)
+      continue;
+    if (resolver->options && !strcmp(resolver->options, "mdns"))
+      continue;
+    ++num_resolvers;
+  }
+  if (num_resolvers > 1) {
+    LOG(WARNING) << "dns_config has unhandled options!";
+    config->unhandled_options = true;
+    return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
+  }
+#endif  // defined(OS_MACOSX)
   // Override timeout value to match default setting on Windows.
   config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds);
   return result;
@@ -172,7 +262,18 @@
   virtual void DoWork() OVERRIDE {
     base::TimeTicks start_time = base::TimeTicks::Now();
     ConfigParsePosixResult result = ReadDnsConfig(&dns_config_);
-    success_ = (result == CONFIG_PARSE_POSIX_OK);
+    switch (result) {
+      case CONFIG_PARSE_POSIX_MISSING_OPTIONS:
+      case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS:
+        DCHECK(dns_config_.unhandled_options);
+        // Fall through.
+      case CONFIG_PARSE_POSIX_OK:
+        success_ = true;
+        break;
+      default:
+        success_ = false;
+        break;
+    }
     UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix",
                               result, CONFIG_PARSE_POSIX_MAX);
     UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_);
@@ -358,12 +459,16 @@
   // The current implementation assumes these options are set. They normally
   // cannot be overwritten by /etc/resolv.conf
   unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
-  if ((res.options & kRequiredOptions) != kRequiredOptions)
+  if ((res.options & kRequiredOptions) != kRequiredOptions) {
+    dns_config->unhandled_options = true;
     return CONFIG_PARSE_POSIX_MISSING_OPTIONS;
+  }
 
   unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC;
-  if (res.options & kUnhandledOptions)
+  if (res.options & kUnhandledOptions) {
+    dns_config->unhandled_options = true;
     return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
+  }
 
   if (dns_config->nameservers.empty())
     return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
diff --git a/net/dns/dns_config_service_posix.h b/net/dns/dns_config_service_posix.h
index 95a4377..be19ab9 100644
--- a/net/dns/dns_config_service_posix.h
+++ b/net/dns/dns_config_service_posix.h
@@ -53,6 +53,7 @@
   CONFIG_PARSE_POSIX_NO_NAMESERVERS,
   CONFIG_PARSE_POSIX_MISSING_OPTIONS,
   CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS,
+  CONFIG_PARSE_POSIX_NO_DNSINFO,
   CONFIG_PARSE_POSIX_MAX  // Bounding values for enumeration.
 };
 
diff --git a/net/dns/dns_session_unittest.cc b/net/dns/dns_session_unittest.cc
index 4662706..ed726f2 100644
--- a/net/dns/dns_session_unittest.cc
+++ b/net/dns/dns_session_unittest.cc
@@ -14,6 +14,8 @@
 #include "net/dns/dns_protocol.h"
 #include "net/dns/dns_socket_pool.h"
 #include "net/socket/socket_test_util.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/stream_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
@@ -24,26 +26,26 @@
  public:
   virtual ~TestClientSocketFactory();
 
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       net::NetLog* net_log,
       const net::NetLog::Source& source) OVERRIDE;
 
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList& addresses,
       NetLog*, const NetLog::Source&) OVERRIDE {
     NOTIMPLEMENTED();
-    return NULL;
+    return scoped_ptr<StreamSocket>();
   }
 
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       const SSLClientSocketContext& context) OVERRIDE {
     NOTIMPLEMENTED();
-    return NULL;
+    return scoped_ptr<SSLClientSocket>();
   }
 
   virtual void ClearSSLSessionCache() OVERRIDE {
@@ -179,7 +181,8 @@
   return true;
 }
 
-DatagramClientSocket* TestClientSocketFactory::CreateDatagramClientSocket(
+scoped_ptr<DatagramClientSocket>
+TestClientSocketFactory::CreateDatagramClientSocket(
     DatagramSocket::BindType bind_type,
     const RandIntCallback& rand_int_cb,
     net::NetLog* net_log,
@@ -188,9 +191,10 @@
   // simplest SocketDataProvider with no data supplied.
   SocketDataProvider* data_provider = new StaticSocketDataProvider();
   data_providers_.push_back(data_provider);
-  MockUDPClientSocket* socket = new MockUDPClientSocket(data_provider, net_log);
-  data_provider->set_socket(socket);
-  return socket;
+  scoped_ptr<MockUDPClientSocket> socket(
+      new MockUDPClientSocket(data_provider, net_log));
+  data_provider->set_socket(socket.get());
+  return socket.PassAs<DatagramClientSocket>();
 }
 
 TestClientSocketFactory::~TestClientSocketFactory() {
diff --git a/net/dns/dns_socket_pool.cc b/net/dns/dns_socket_pool.cc
index 64570fc..7a7ecd6 100644
--- a/net/dns/dns_socket_pool.cc
+++ b/net/dns/dns_socket_pool.cc
@@ -76,8 +76,8 @@
   scoped_ptr<DatagramClientSocket> socket;
 
   NetLog::Source no_source;
-  socket.reset(socket_factory_->CreateDatagramClientSocket(
-      kBindType, base::Bind(&base::RandInt), net_log_, no_source));
+  socket = socket_factory_->CreateDatagramClientSocket(
+      kBindType, base::Bind(&base::RandInt), net_log_, no_source);
 
   if (socket.get()) {
     int rv = socket->Connect((*nameservers_)[server_index]);
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index f9667ee..7040e44 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -180,21 +180,21 @@
   TestSocketFactory() : fail_next_socket_(false) {}
   virtual ~TestSocketFactory() {}
 
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       net::NetLog* net_log,
       const net::NetLog::Source& source) OVERRIDE {
     if (fail_next_socket_) {
       fail_next_socket_ = false;
-      return new FailingUDPClientSocket(&empty_data_, net_log);
+      return scoped_ptr<DatagramClientSocket>(
+          new FailingUDPClientSocket(&empty_data_, net_log));
     }
     SocketDataProvider* data_provider = mock_data().GetNext();
-    TestUDPClientSocket* socket = new TestUDPClientSocket(this,
-                                                          data_provider,
-                                                          net_log);
-    data_provider->set_socket(socket);
-    return socket;
+    scoped_ptr<TestUDPClientSocket> socket(
+        new TestUDPClientSocket(this, data_provider, net_log));
+    data_provider->set_socket(socket.get());
+    return socket.PassAs<DatagramClientSocket>();
   }
 
   void OnConnect(const IPEndPoint& endpoint) {
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc
index d74be91..9b1e331 100644
--- a/net/dns/host_resolver.cc
+++ b/net/dns/host_resolver.cc
@@ -98,9 +98,7 @@
       address_family_(ADDRESS_FAMILY_UNSPECIFIED),
       host_resolver_flags_(0),
       allow_cached_response_(true),
-      is_speculative_(false),
-      priority_(MEDIUM) {
-}
+      is_speculative_(false) {}
 
 HostResolver::~HostResolver() {
 }
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h
index 558a1dd..2964fe6 100644
--- a/net/dns/host_resolver.h
+++ b/net/dns/host_resolver.h
@@ -53,8 +53,8 @@
     bool enable_caching;
   };
 
-  // The parameters for doing a Resolve(). A hostname and port are required,
-  // the rest are optional (and have reasonable defaults).
+  // The parameters for doing a Resolve(). A hostname and port are
+  // required; the rest are optional (and have reasonable defaults).
   class NET_EXPORT RequestInfo {
    public:
     explicit RequestInfo(const HostPortPair& host_port_pair);
@@ -85,9 +85,6 @@
     bool is_speculative() const { return is_speculative_; }
     void set_is_speculative(bool b) { is_speculative_ = b; }
 
-    RequestPriority priority() const { return priority_; }
-    void set_priority(RequestPriority priority) { priority_ = priority; }
-
    private:
     // The hostname to resolve, and the port to use in resulting sockaddrs.
     HostPortPair host_port_pair_;
@@ -103,9 +100,6 @@
 
     // Whether this request was started by the DNS prefetcher.
     bool is_speculative_;
-
-    // The priority for the request.
-    RequestPriority priority_;
   };
 
   // Opaque type used to cancel a request.
@@ -144,6 +138,7 @@
   //
   // Profiling information for the request is saved to |net_log| if non-NULL.
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 1063177..d10949f 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -343,7 +343,6 @@
                    static_cast<int>(info->address_family()));
   dict->SetBoolean("allow_cached_response", info->allow_cached_response());
   dict->SetBoolean("is_speculative", info->is_speculative());
-  dict->SetInteger("priority", info->priority());
   return dict;
 }
 
@@ -465,16 +464,17 @@
   Request(const BoundNetLog& source_net_log,
           const BoundNetLog& request_net_log,
           const RequestInfo& info,
+          RequestPriority priority,
           const CompletionCallback& callback,
           AddressList* addresses)
       : source_net_log_(source_net_log),
         request_net_log_(request_net_log),
         info_(info),
+        priority_(priority),
         job_(NULL),
         callback_(callback),
         addresses_(addresses),
-        request_time_(base::TimeTicks::Now()) {
-  }
+        request_time_(base::TimeTicks::Now()) {}
 
   // Mark the request as canceled.
   void MarkAsCanceled() {
@@ -521,16 +521,19 @@
     return info_;
   }
 
-  base::TimeTicks request_time() const {
-    return request_time_;
-  }
+  RequestPriority priority() const { return priority_; }
+
+  base::TimeTicks request_time() const { return request_time_; }
 
  private:
   BoundNetLog source_net_log_;
   BoundNetLog request_net_log_;
 
   // The request info that started the request.
-  RequestInfo info_;
+  const RequestInfo info_;
+
+  // TODO(akalin): Support reprioritization.
+  const RequestPriority priority_;
 
   // The resolve job that this request is dependent on.
   Job* job_;
@@ -1210,7 +1213,7 @@
     DCHECK_EQ(key_.hostname, req->info().hostname());
 
     req->set_job(this);
-    priority_tracker_.Add(req->info().priority());
+    priority_tracker_.Add(req->priority());
 
     req->request_net_log().AddEvent(
         NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
@@ -1245,12 +1248,11 @@
     LogCancelRequest(req->source_net_log(), req->request_net_log(),
                      req->info());
 
-    priority_tracker_.Remove(req->info().priority());
-    net_log_.AddEvent(
-        NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
-        base::Bind(&NetLogJobAttachCallback,
-                   req->request_net_log().source(),
-                   priority()));
+    priority_tracker_.Remove(req->priority());
+    net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
+                      base::Bind(&NetLogJobAttachCallback,
+                                 req->request_net_log().source(),
+                                 priority()));
 
     if (num_active_requests() > 0) {
       UpdatePriority();
@@ -1732,6 +1734,7 @@
 }
 
 int HostResolverImpl::Resolve(const RequestInfo& info,
+                              RequestPriority priority,
                               AddressList* addresses,
                               const CompletionCallback& callback,
                               RequestHandle* out_req,
@@ -1768,8 +1771,8 @@
   JobMap::iterator jobit = jobs_.find(key);
   Job* job;
   if (jobit == jobs_.end()) {
-    job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(),
-                  request_net_log);
+    job =
+        new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log);
     job->Schedule();
 
     // Check for queue overflow.
@@ -1789,11 +1792,8 @@
   }
 
   // Can't complete synchronously. Create and attach request.
-  scoped_ptr<Request> req(new Request(source_net_log,
-                                      request_net_log,
-                                      info,
-                                      callback,
-                                      addresses));
+  scoped_ptr<Request> req(new Request(
+      source_net_log, request_net_log, info, priority, callback, addresses));
   if (out_req)
     *out_req = reinterpret_cast<RequestHandle>(req.get());
 
@@ -2133,7 +2133,7 @@
   // the newly started jobs use the new config.
   if (dns_client_.get()) {
     dns_client_->SetConfig(dns_config);
-    if (dns_config.IsValid())
+    if (dns_client_->GetConfig())
       UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
   }
 
@@ -2199,7 +2199,7 @@
   NetworkChangeNotifier::GetDnsConfig(&dns_config);
   dns_client_->SetConfig(dns_config);
   num_dns_failures_ = 0;
-  if (dns_config.IsValid())
+  if (dns_client_->GetConfig())
     UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
 }
 
diff --git a/net/dns/host_resolver_impl.h b/net/dns/host_resolver_impl.h
index 928d07a..aa6421c 100644
--- a/net/dns/host_resolver_impl.h
+++ b/net/dns/host_resolver_impl.h
@@ -131,6 +131,7 @@
 
   // HostResolver methods:
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index f6b7f69..d604b64 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -197,10 +197,12 @@
   };
 
   Request(const HostResolver::RequestInfo& info,
+          RequestPriority priority,
           size_t index,
           HostResolver* resolver,
           Handler* handler)
       : info_(info),
+        priority_(priority),
         index_(index),
         resolver_(resolver),
         handler_(handler),
@@ -213,8 +215,12 @@
     DCHECK(!handle_);
     list_ = AddressList();
     result_ = resolver_->Resolve(
-        info_, &list_, base::Bind(&Request::OnComplete, base::Unretained(this)),
-        &handle_, BoundNetLog());
+        info_,
+        priority_,
+        &list_,
+        base::Bind(&Request::OnComplete, base::Unretained(this)),
+        &handle_,
+        BoundNetLog());
     if (!list_.empty())
       EXPECT_EQ(OK, result_);
     return result_;
@@ -291,6 +297,7 @@
   }
 
   HostResolver::RequestInfo info_;
+  RequestPriority priority_;
   size_t index_;
   HostResolver* resolver_;
   Handler* handler_;
@@ -419,8 +426,9 @@
     virtual ~Handler() {}
 
     // Proxy functions so that classes derived from Handler can access them.
-    Request* CreateRequest(const HostResolver::RequestInfo& info) {
-      return test->CreateRequest(info);
+    Request* CreateRequest(const HostResolver::RequestInfo& info,
+                           RequestPriority priority) {
+      return test->CreateRequest(info, priority);
     }
     Request* CreateRequest(const std::string& hostname, int port) {
       return test->CreateRequest(hostname, port);
@@ -457,9 +465,10 @@
 
   // The Request will not be made until a call to |Resolve()|, and the Job will
   // not start until released by |proc_->SignalXXX|.
-  Request* CreateRequest(const HostResolver::RequestInfo& info) {
-    Request* req = new Request(info, requests_.size(), resolver_.get(),
-                               handler_.get());
+  Request* CreateRequest(const HostResolver::RequestInfo& info,
+                         RequestPriority priority) {
+    Request* req = new Request(
+        info, priority, requests_.size(), resolver_.get(), handler_.get());
     requests_.push_back(req);
     return req;
   }
@@ -469,9 +478,8 @@
                          RequestPriority priority,
                          AddressFamily family) {
     HostResolver::RequestInfo info(HostPortPair(hostname, port));
-    info.set_priority(priority);
     info.set_address_family(family);
-    return CreateRequest(info);
+    return CreateRequest(info, priority);
   }
 
   Request* CreateRequest(const std::string& hostname,
@@ -817,7 +825,8 @@
         // longer service the request synchronously.
         HostResolver::RequestInfo info(HostPortPair(hostname, 71));
         info.set_allow_cached_response(false);
-        EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info)->Resolve());
+        EXPECT_EQ(ERR_IO_PENDING,
+                  CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
       } else if (71 == req->info().port()) {
         // Test is done.
         base::MessageLoop::current()->Quit();
@@ -1189,14 +1198,15 @@
   HostResolver::RequestInfo info(HostPortPair("just.testing", 80));
 
   // First hit will miss the cache.
-  EXPECT_EQ(ERR_DNS_CACHE_MISS, CreateRequest(info)->ResolveFromCache());
+  EXPECT_EQ(ERR_DNS_CACHE_MISS,
+            CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
 
   // This time, we fetch normally.
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
   EXPECT_EQ(OK, requests_[1]->WaitForResult());
 
   // Now we should be able to fetch from the cache.
-  EXPECT_EQ(OK, CreateRequest(info)->ResolveFromCache());
+  EXPECT_EQ(OK, CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
   EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.1.42", 80));
 }
 
@@ -1228,7 +1238,7 @@
 
   // Resolve "host1".
   HostResolver::RequestInfo info(HostPortPair("host1", 70));
-  Request* req = CreateRequest(info);
+  Request* req = CreateRequest(info, DEFAULT_PRIORITY);
   EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
 
   // Resolve returns -4 to indicate that 3rd attempt has resolved the host.
@@ -1609,7 +1619,7 @@
 
   // Try without DnsClient.
   ChangeDnsConfig(DnsConfig());
-  Request* req = CreateRequest(info);
+  Request* req = CreateRequest(info, DEFAULT_PRIORITY);
   // It is resolved via getaddrinfo, so expect asynchronous result.
   EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
   EXPECT_EQ(OK, req->WaitForResult());
@@ -1630,7 +1640,7 @@
   config.hosts = hosts;
 
   ChangeDnsConfig(config);
-  req = CreateRequest(info);
+  req = CreateRequest(info, DEFAULT_PRIORITY);
   // Expect synchronous resolution from DnsHosts.
   EXPECT_EQ(OK, req->Resolve());
 
diff --git a/net/dns/mapped_host_resolver.cc b/net/dns/mapped_host_resolver.cc
index 4db7bc9..7b18207 100644
--- a/net/dns/mapped_host_resolver.cc
+++ b/net/dns/mapped_host_resolver.cc
@@ -19,6 +19,7 @@
 }
 
 int MappedHostResolver::Resolve(const RequestInfo& original_info,
+                                RequestPriority priority,
                                 AddressList* addresses,
                                 const CompletionCallback& callback,
                                 RequestHandle* out_req,
@@ -28,7 +29,7 @@
   if (rv != OK)
     return rv;
 
-  return impl_->Resolve(info, addresses, callback, out_req, net_log);
+  return impl_->Resolve(info, priority, addresses, callback, out_req, net_log);
 }
 
 int MappedHostResolver::ResolveFromCache(const RequestInfo& original_info,
diff --git a/net/dns/mapped_host_resolver.h b/net/dns/mapped_host_resolver.h
index 50062a9..a121d4e 100644
--- a/net/dns/mapped_host_resolver.h
+++ b/net/dns/mapped_host_resolver.h
@@ -46,6 +46,7 @@
 
   // HostResolver methods:
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
diff --git a/net/dns/mapped_host_resolver_unittest.cc b/net/dns/mapped_host_resolver_unittest.cc
index d859466..fbbfde8 100644
--- a/net/dns/mapped_host_resolver_unittest.cc
+++ b/net/dns/mapped_host_resolver_unittest.cc
@@ -40,10 +40,13 @@
   // Try resolving "www.google.com:80". There are no mappings yet, so this
   // hits |resolver_impl| and fails.
   TestCompletionCallback callback;
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("www.google.com", 80)),
-                         &address_list, callback.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
@@ -52,10 +55,13 @@
   EXPECT_TRUE(resolver->AddRuleFromString("map *.google.com baz.com"));
 
   // Try resolving "www.google.com:80". Should be remapped to "baz.com:80".
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("www.google.com", 80)),
-                         &address_list, callback.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -64,7 +70,10 @@
   // Try resolving "foo.com:77". This will NOT be remapped, so result
   // is "foo.com:77".
   rv = resolver->Resolve(HostResolver::RequestInfo(HostPortPair("foo.com", 77)),
-                         &address_list, callback.callback(), NULL,
+                         DEFAULT_PRIORITY,
+                         &address_list,
+                         callback.callback(),
+                         NULL,
                          BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
@@ -75,10 +84,13 @@
   EXPECT_TRUE(resolver->AddRuleFromString("Map *.org proxy:99"));
 
   // Try resolving "chromium.org:61". Should be remapped to "proxy:99".
-  rv = resolver->Resolve(HostResolver::RequestInfo
-                             (HostPortPair("chromium.org", 61)),
-                         &address_list, callback.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("chromium.org", 61)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -107,20 +119,26 @@
   EXPECT_TRUE(resolver->AddRuleFromString("EXCLUDE *.google.com"));
 
   // Try resolving "www.google.com". Should not be remapped due to exclusion).
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("www.google.com", 80)),
-                         &address_list, callback.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
   EXPECT_EQ("192.168.1.3:80", FirstAddress(address_list));
 
   // Try resolving "chrome.com:80". Should be remapped to "baz:80".
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("chrome.com", 80)),
-                         &address_list, callback.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("chrome.com", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -145,20 +163,26 @@
   resolver->SetRulesFromString("map *.com baz , map *.net bar:60");
 
   // Try resolving "www.google.com". Should be remapped to "baz".
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("www.google.com", 80)),
-                         &address_list, callback.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
   EXPECT_EQ("192.168.1.7:80", FirstAddress(address_list));
 
   // Try resolving "chrome.net:80". Should be remapped to "bar:60".
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("chrome.net", 80)),
-                         &address_list, callback.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("chrome.net", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -196,18 +220,24 @@
 
   // Try resolving www.google.com --> Should give an error.
   TestCompletionCallback callback1;
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("www.google.com", 80)),
-                         &address_list, callback1.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback1.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
 
   // Try resolving www.foo.com --> Should succeed.
   TestCompletionCallback callback2;
-  rv = resolver->Resolve(HostResolver::RequestInfo(
-                             HostPortPair("www.foo.com", 80)),
-                         &address_list, callback2.callback(), NULL,
-                         BoundNetLog());
+  rv = resolver->Resolve(
+      HostResolver::RequestInfo(HostPortPair("www.foo.com", 80)),
+      DEFAULT_PRIORITY,
+      &address_list,
+      callback2.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback2.WaitForResult();
   EXPECT_EQ(OK, rv);
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index 0ddb8cf..a1d46d0 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -67,11 +67,13 @@
 }
 
 int MockHostResolverBase::Resolve(const RequestInfo& info,
+                                  RequestPriority priority,
                                   AddressList* addresses,
                                   const CompletionCallback& callback,
                                   RequestHandle* handle,
                                   const BoundNetLog& net_log) {
   DCHECK(CalledOnValidThread());
+  last_request_priority_ = priority;
   num_resolve_++;
   size_t id = next_request_id_++;
   int rv = ResolveFromIPLiteralOrCache(info, addresses);
@@ -135,7 +137,8 @@
 
 // start id from 1 to distinguish from NULL RequestHandle
 MockHostResolverBase::MockHostResolverBase(bool use_caching)
-    : synchronous_mode_(false),
+    : last_request_priority_(DEFAULT_PRIORITY),
+      synchronous_mode_(false),
       ondemand_mode_(false),
       next_request_id_(1),
       num_resolve_(0),
@@ -401,6 +404,7 @@
 //-----------------------------------------------------------------------------
 
 int HangingHostResolver::Resolve(const RequestInfo& info,
+                                 RequestPriority priority,
                                  AddressList* addresses,
                                  const CompletionCallback& callback,
                                  RequestHandle* out_req,
diff --git a/net/dns/mock_host_resolver.h b/net/dns/mock_host_resolver.h
index b73bd0a..3593fbd 100644
--- a/net/dns/mock_host_resolver.h
+++ b/net/dns/mock_host_resolver.h
@@ -75,6 +75,7 @@
 
   // HostResolver methods:
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
@@ -104,6 +105,12 @@
     return num_resolve_from_cache_;
   }
 
+  // Returns the RequestPriority of the last call to Resolve() (or
+  // DEFAULT_PRIORITY if Resolve() hasn't been called yet).
+  RequestPriority last_request_priority() const {
+    return last_request_priority_;
+  }
+
  protected:
   explicit MockHostResolverBase(bool use_caching);
 
@@ -120,6 +127,7 @@
   // Resolve request stored in |requests_|. Pass rv to callback.
   void ResolveNow(size_t id);
 
+  RequestPriority last_request_priority_;
   bool synchronous_mode_;
   bool ondemand_mode_;
   scoped_refptr<RuleBasedHostResolverProc> rules_;
@@ -216,6 +224,7 @@
 class HangingHostResolver : public HostResolver {
  public:
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
diff --git a/net/dns/single_request_host_resolver.cc b/net/dns/single_request_host_resolver.cc
index 31ef4c5..7974aba 100644
--- a/net/dns/single_request_host_resolver.cc
+++ b/net/dns/single_request_host_resolver.cc
@@ -25,9 +25,11 @@
   Cancel();
 }
 
-int SingleRequestHostResolver::Resolve(
-    const HostResolver::RequestInfo& info, AddressList* addresses,
-    const CompletionCallback& callback, const BoundNetLog& net_log) {
+int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info,
+                                       RequestPriority priority,
+                                       AddressList* addresses,
+                                       const CompletionCallback& callback,
+                                       const BoundNetLog& net_log) {
   DCHECK(addresses);
   DCHECK_EQ(false, callback.is_null());
   DCHECK(cur_request_callback_.is_null()) << "resolver already in use";
@@ -40,7 +42,7 @@
       callback.is_null() ? CompletionCallback() : callback_;
 
   int rv = resolver_->Resolve(
-      info, addresses, transient_callback, &request, net_log);
+      info, priority, addresses, transient_callback, &request, net_log);
 
   if (rv == ERR_IO_PENDING) {
     DCHECK_EQ(false, callback.is_null());
diff --git a/net/dns/single_request_host_resolver.h b/net/dns/single_request_host_resolver.h
index 52d0132..3c8ef02 100644
--- a/net/dns/single_request_host_resolver.h
+++ b/net/dns/single_request_host_resolver.h
@@ -5,10 +5,18 @@
 #ifndef NET_DNS_SINGLE_REQUEST_HOST_RESOLVER_H_
 #define NET_DNS_SINGLE_REQUEST_HOST_RESOLVER_H_
 
+#include "base/basictypes.h"
+
+#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
+#include "net/base/request_priority.h"
 #include "net/dns/host_resolver.h"
 
 namespace net {
 
+class AddressList;
+class BoundNetLog;
+
 // This class represents the task of resolving a hostname (or IP address
 // literal) to an AddressList object.  It wraps HostResolver to resolve only a
 // single hostname at a time and cancels this request when going out of scope.
@@ -25,6 +33,7 @@
   // Resolves the given hostname (or IP address literal), filling out the
   // |addresses| object upon success. See HostResolver::Resolve() for details.
   int Resolve(const HostResolver::RequestInfo& info,
+              RequestPriority priority,
               AddressList* addresses,
               const CompletionCallback& callback,
               const BoundNetLog& net_log);
diff --git a/net/dns/single_request_host_resolver_unittest.cc b/net/dns/single_request_host_resolver_unittest.cc
index 1b0198f..cc20bf3 100644
--- a/net/dns/single_request_host_resolver_unittest.cc
+++ b/net/dns/single_request_host_resolver_unittest.cc
@@ -31,6 +31,7 @@
   }
 
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
@@ -77,7 +78,7 @@
   TestCompletionCallback callback;
   HostResolver::RequestInfo request(HostPortPair("watsup", 90));
   int rv = single_request_resolver.Resolve(
-      request, &addrlist, callback.callback(), BoundNetLog());
+      request, DEFAULT_PRIORITY, &addrlist, callback.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -97,8 +98,11 @@
     AddressList addrlist;
     TestCompletionCallback callback;
     HostResolver::RequestInfo request(HostPortPair("watsup", 90));
-    int rv = single_request_resolver.Resolve(
-        request, &addrlist, callback.callback(), BoundNetLog());
+    int rv = single_request_resolver.Resolve(request,
+                                             DEFAULT_PRIORITY,
+                                             &addrlist,
+                                             callback.callback(),
+                                             BoundNetLog());
     EXPECT_EQ(ERR_IO_PENDING, rv);
     EXPECT_TRUE(resolver.has_outstanding_request());
   }
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index ccd6e2e..9d0cbe2 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -650,7 +650,9 @@
   HostResolver::RequestInfo info(HostPortPair::FromURL(request_->url));
   // No known referrer.
   return resolver_.Resolve(
-      info, &addresses_,
+      info,
+      DEFAULT_PRIORITY,
+      &addresses_,
       base::Bind(&FtpNetworkTransaction::OnIOComplete, base::Unretained(this)),
       net_log_);
 }
@@ -663,8 +665,8 @@
 
 int FtpNetworkTransaction::DoCtrlConnect() {
   next_state_ = STATE_CTRL_CONNECT_COMPLETE;
-  ctrl_socket_.reset(socket_factory_->CreateTransportClientSocket(
-        addresses_, net_log_.net_log(), net_log_.source()));
+  ctrl_socket_ = socket_factory_->CreateTransportClientSocket(
+      addresses_, net_log_.net_log(), net_log_.source());
   net_log_.AddEvent(
       NetLog::TYPE_FTP_CONTROL_CONNECTION,
       ctrl_socket_->NetLog().source().ToEventParametersCallback());
@@ -1249,8 +1251,8 @@
     return Stop(rv);
   data_address = AddressList::CreateFromIPAddress(
       ip_endpoint.address(), data_connection_port_);
-  data_socket_.reset(socket_factory_->CreateTransportClientSocket(
-        data_address, net_log_.net_log(), net_log_.source()));
+  data_socket_ = socket_factory_->CreateTransportClientSocket(
+        data_address, net_log_.net_log(), net_log_.source());
   net_log_.AddEvent(
       NetLog::TYPE_FTP_DATA_CONNECTION,
       data_socket_->NetLog().source().ToEventParametersCallback());
diff --git a/net/http/http_auth_cache.cc b/net/http/http_auth_cache.cc
index 79ea7fd..1c8c03f 100644
--- a/net/http/http_auth_cache.cc
+++ b/net/http/http_auth_cache.cc
@@ -43,8 +43,7 @@
 void CheckOriginIsValid(const GURL& origin) {
   DCHECK(origin.is_valid());
   // Note that the scheme may be FTP when we're using a HTTP proxy.
-  DCHECK(origin.SchemeIs("http") || origin.SchemeIs("https") ||
-         origin.SchemeIs("ftp"));
+  DCHECK(origin.SchemeIsHTTPOrHTTPS() || origin.SchemeIs("ftp"));
   DCHECK(origin.GetOrigin() == origin);
 }
 
diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc
index 21f5d65..13b1069 100644
--- a/net/http/http_auth_handler_negotiate.cc
+++ b/net/http/http_auth_handler_negotiate.cc
@@ -291,7 +291,9 @@
   info.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
   single_resolve_.reset(new SingleRequestHostResolver(resolver_));
   return single_resolve_->Resolve(
-      info, &address_list_,
+      info,
+      DEFAULT_PRIORITY,
+      &address_list_,
       base::Bind(&HttpAuthHandlerNegotiate::OnIOComplete,
                  base::Unretained(this)),
       net_log_);
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index d70ac02..c30e17d 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -127,4 +127,8 @@
   // |drainer| will delete itself.
 }
 
+void HttpBasicStream::SetPriority(RequestPriority priority) {
+  // TODO(akalin): Plumb this through to |connection_|.
+}
+
 }  // namespace net
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index 2d4bb65..2057837 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -81,6 +81,8 @@
 
   virtual void Drain(HttpNetworkSession* session) OVERRIDE;
 
+  virtual void SetPriority(RequestPriority priority) OVERRIDE;
+
  private:
   scoped_refptr<GrowableIOBuffer> read_buf_;
 
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 8d4a455..cd3be51 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -231,14 +231,6 @@
       cache_->RemovePendingTransaction(this);
     }
   }
-
-  // Cancel any outstanding callbacks before we drop our reference to the
-  // HttpCache.  This probably isn't strictly necessary, but might as well.
-  weak_factory_.InvalidateWeakPtrs();
-
-  // We could still have a cache read or write in progress, so we just null the
-  // cache_ pointer to signal that we are dead.  See DoCacheReadCompleted.
-  cache_.reset();
 }
 
 int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len,
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 3265962..346cbbc 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -107,6 +107,7 @@
                            params.client_socket_factory ?
                                params.client_socket_factory :
                                net::ClientSocketFactory::GetDefaultFactory(),
+                           params.http_server_properties,
                            params.quic_crypto_client_stream_factory,
                            params.quic_random ? params.quic_random :
                                QuicRandom::GetInstance(),
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 70292be..a63a2aa 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -419,8 +419,10 @@
 
 void HttpNetworkTransaction::SetPriority(RequestPriority priority) {
   priority_ = priority;
-  // TODO(akalin): Plumb this through to |stream_request_| and
-  // |stream_|.
+  if (stream_request_)
+    stream_request_->SetPriority(priority);
+  if (stream_)
+    stream_->SetPriority(priority);
 }
 
 void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config,
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 5f8dac2..504d5cd 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/files/file_path.h"
 #include "base/json/json_writer.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_file_util.h"
@@ -45,6 +46,7 @@
 #include "net/http/http_stream_factory.h"
 #include "net/http/http_transaction_unittest.h"
 #include "net/proxy/proxy_config_service_fixed.h"
+#include "net/proxy/proxy_info.h"
 #include "net/proxy/proxy_resolver.h"
 #include "net/proxy/proxy_service.h"
 #include "net/socket/client_socket_factory.h"
@@ -58,6 +60,7 @@
 #include "net/spdy/spdy_session_pool.h"
 #include "net/spdy/spdy_test_util_common.h"
 #include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_config_service.h"
 #include "net/ssl/ssl_config_service_defaults.h"
 #include "net/ssl/ssl_info.h"
 #include "net/test/cert_test_util.h"
@@ -92,6 +95,11 @@
       net::HttpNetworkSession::NORMAL_SOCKET_POOL)->IdleSocketCount();
 }
 
+bool IsTransportSocketPoolStalled(net::HttpNetworkSession* session) {
+  return session->GetTransportSocketPool(
+      net::HttpNetworkSession::NORMAL_SOCKET_POOL)->IsStalled();
+}
+
 // Takes in a Value created from a NetLogHttpResponseParameter, and returns
 // a JSONified list of headers as a single string.  Uses single quotes instead
 // of double quotes for easier comparison.  Returns false on failure.
@@ -449,7 +457,7 @@
   virtual void CancelRequest(const std::string& group_name,
                              ClientSocketHandle* handle) {}
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket,
+                             scoped_ptr<StreamSocket> socket,
                              int id) {}
   virtual void CloseIdleSockets() {}
   virtual int IdleSocketCount() const {
@@ -2792,7 +2800,8 @@
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
   // CONNECT to www.google.com:443 via SPDY
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                                LOWEST));
   // fetch https://www.google.com/ via HTTP
 
   const char get[] = "GET / HTTP/1.1\r\n"
@@ -2878,7 +2887,8 @@
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
   // CONNECT to www.google.com:443 via SPDY
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                                LOWEST));
   // fetch https://www.google.com/ via SPDY
   const char* const kMyUrl = "https://www.google.com/";
   scoped_ptr<SpdyFrame> get(
@@ -2966,7 +2976,8 @@
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
 
   // CONNECT to www.google.com:443 via SPDY
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                                LOWEST));
   scoped_ptr<SpdyFrame> get(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
 
@@ -3028,7 +3039,8 @@
   request2.load_flags = 0;
 
   // CONNECT to www.google.com:443 via SPDY.
-  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                                 LOWEST));
   scoped_ptr<SpdyFrame> conn_resp1(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
 
@@ -3186,7 +3198,8 @@
   request2.load_flags = 0;
 
   // CONNECT to www.google.com:443 via SPDY.
-  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> connect1(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                                 LOWEST));
   scoped_ptr<SpdyFrame> conn_resp1(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
 
@@ -5667,7 +5680,8 @@
   request.url = GURL("https://www.google.com/");
   request.load_flags = 0;
 
-  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                             LOWEST));
   scoped_ptr<SpdyFrame> goaway(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite data_writes[] = {
@@ -5775,7 +5789,8 @@
   request.url = GURL("https://www.google.com/");
   request.load_flags = 0;
 
-  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> conn(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                             LOWEST));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite data_writes[] = {
@@ -5841,7 +5856,8 @@
   scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
 
   // Since we have proxy, should try to establish tunnel.
-  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                            LOWEST));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
 
@@ -5851,7 +5867,7 @@
       "proxy-authorization", "Basic Zm9vOmJhcg==",
   };
   scoped_ptr<SpdyFrame> connect2(spdy_util_.ConstructSpdyConnect(
-      kAuthCredentials, arraysize(kAuthCredentials) / 2, 3));
+      kAuthCredentials, arraysize(kAuthCredentials) / 2, 3, LOWEST));
   // fetch https://www.google.com/ via HTTP
   const char get[] = "GET / HTTP/1.1\r\n"
     "Host: www.google.com\r\n"
@@ -7271,8 +7287,12 @@
   AddressList addrlist;
   TestCompletionCallback callback;
   int rv = session_deps_.host_resolver->Resolve(
-      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist,
-      callback.callback(), NULL, BoundNetLog());
+      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+      DEFAULT_PRIORITY,
+      &addrlist,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -7280,8 +7300,12 @@
   // Verify that it was added to host cache, by doing a subsequent async lookup
   // and confirming it completes synchronously.
   rv = session_deps_.host_resolver->Resolve(
-      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist,
-      callback.callback(), NULL, BoundNetLog());
+      HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+      DEFAULT_PRIORITY,
+      &addrlist,
+      callback.callback(),
+      NULL,
+      BoundNetLog());
   ASSERT_EQ(OK, rv);
 
   // Inject a failure the next time that "www.google.com" is resolved. This way
@@ -10476,9 +10500,12 @@
   HostPortPair host_port("www.gmail.com", 443);
   HostResolver::RequestInfo resolve_info(host_port);
   AddressList ignored;
-  rv = session_deps_.host_resolver->Resolve(resolve_info, &ignored,
-                                           callback.callback(), NULL,
-                                           BoundNetLog());
+  rv = session_deps_.host_resolver->Resolve(resolve_info,
+                                            DEFAULT_PRIORITY,
+                                            &ignored,
+                                            callback.callback(),
+                                            NULL,
+                                            BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -10602,12 +10629,13 @@
 
   // HostResolver methods:
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
                       const BoundNetLog& net_log) OVERRIDE {
     return host_resolver_.Resolve(
-        info, addresses, callback, out_req, net_log);
+        info, priority, addresses, callback, out_req, net_log);
   }
 
   virtual int ResolveFromCache(const RequestInfo& info,
@@ -10721,8 +10749,12 @@
   // Preload cache entries into HostCache.
   HostResolver::RequestInfo resolve_info(HostPortPair("www.gmail.com", 443));
   AddressList ignored;
-  rv = host_resolver.Resolve(resolve_info, &ignored, callback.callback(),
-                             NULL, BoundNetLog());
+  rv = host_resolver.Resolve(resolve_info,
+                             DEFAULT_PRIORITY,
+                             &ignored,
+                             callback.callback(),
+                             NULL,
+                             BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   EXPECT_EQ(OK, rv);
@@ -10881,7 +10913,8 @@
   const std::string http_url = "http://www.google.com:443/";
 
   // SPDY GET for HTTPS URL (through CONNECT tunnel)
-  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> connect(spdy_util_.ConstructSpdyConnect(NULL, 0, 1,
+                                                                LOWEST));
   scoped_ptr<SpdyFrame> req1(
       spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST));
 
@@ -11680,4 +11713,463 @@
   EXPECT_EQ("bar", foo);
 }
 
+namespace {
+
+// Fake HttpStreamBase that simply records calls to SetPriority().
+class FakeStream : public HttpStreamBase,
+                   public base::SupportsWeakPtr<FakeStream> {
+ public:
+  explicit FakeStream(RequestPriority priority) : priority_(priority) {}
+  virtual ~FakeStream() {}
+
+  RequestPriority priority() const { return priority_; }
+
+  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 {
+    ADD_FAILURE();
+    return ERR_UNEXPECTED;
+  }
+
+  virtual int ReadResponseHeaders(const CompletionCallback& callback) OVERRIDE {
+    ADD_FAILURE();
+    return ERR_UNEXPECTED;
+  }
+
+  virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE {
+    ADD_FAILURE();
+    return NULL;
+  }
+
+  virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
+                               const CompletionCallback& callback) OVERRIDE {
+    ADD_FAILURE();
+    return ERR_UNEXPECTED;
+  }
+
+  virtual void Close(bool not_reusable) OVERRIDE {}
+
+  virtual bool IsResponseBodyComplete() const OVERRIDE {
+    ADD_FAILURE();
+    return false;
+  }
+
+  virtual bool CanFindEndOfResponse() const OVERRIDE {
+    return false;
+  }
+
+  virtual bool IsConnectionReused() const OVERRIDE {
+    ADD_FAILURE();
+    return false;
+  }
+
+  virtual void SetConnectionReused() OVERRIDE {
+    ADD_FAILURE();
+  }
+
+  virtual bool IsConnectionReusable() const OVERRIDE {
+    ADD_FAILURE();
+    return false;
+  }
+
+  virtual bool GetLoadTimingInfo(
+      LoadTimingInfo* load_timing_info) const OVERRIDE {
+    ADD_FAILURE();
+    return false;
+  }
+
+  virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {
+    ADD_FAILURE();
+  }
+
+  virtual void GetSSLCertRequestInfo(
+      SSLCertRequestInfo* cert_request_info) OVERRIDE {
+    ADD_FAILURE();
+  }
+
+  virtual bool IsSpdyHttpStream() const OVERRIDE {
+    ADD_FAILURE();
+    return false;
+  }
+
+  virtual void Drain(HttpNetworkSession* session) OVERRIDE {
+    ADD_FAILURE();
+  }
+
+  virtual void SetPriority(RequestPriority priority) OVERRIDE {
+    priority_ = priority;
+  }
+
+ private:
+  RequestPriority priority_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeStream);
+};
+
+// Fake HttpStreamRequest that simply records calls to SetPriority()
+// and vends FakeStreams with its current priority.
+class FakeStreamRequest : public HttpStreamRequest,
+                          public base::SupportsWeakPtr<FakeStreamRequest> {
+ public:
+  FakeStreamRequest(RequestPriority priority,
+                    HttpStreamRequest::Delegate* delegate)
+      : priority_(priority),
+        delegate_(delegate) {}
+
+  virtual ~FakeStreamRequest() {}
+
+  RequestPriority priority() const { return priority_; }
+
+  // Create a new FakeStream and pass it to the request's
+  // delegate. Returns a weak pointer to the FakeStream.
+  base::WeakPtr<FakeStream> FinishStreamRequest() {
+    FakeStream* fake_stream = new FakeStream(priority_);
+    // Do this before calling OnStreamReady() as OnStreamReady() may
+    // immediately delete |fake_stream|.
+    base::WeakPtr<FakeStream> weak_stream = fake_stream->AsWeakPtr();
+    delegate_->OnStreamReady(SSLConfig(), ProxyInfo(), fake_stream);
+    return weak_stream;
+  }
+
+  virtual int RestartTunnelWithProxyAuth(
+      const AuthCredentials& credentials) OVERRIDE {
+    ADD_FAILURE();
+    return ERR_UNEXPECTED;
+  }
+
+  virtual LoadState GetLoadState() const OVERRIDE {
+    ADD_FAILURE();
+    return LoadState();
+  }
+
+  virtual void SetPriority(RequestPriority priority) OVERRIDE {
+    priority_ = priority;
+  }
+
+  virtual bool was_npn_negotiated() const OVERRIDE {
+    return false;
+  }
+
+  virtual NextProto protocol_negotiated() const OVERRIDE {
+    return kProtoUnknown;
+  }
+
+  virtual bool using_spdy() const OVERRIDE {
+    return false;
+  }
+
+ private:
+  RequestPriority priority_;
+  HttpStreamRequest::Delegate* const delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeStreamRequest);
+};
+
+// Fake HttpStreamFactory that vends FakeStreamRequests.
+class FakeStreamFactory : public HttpStreamFactory {
+ public:
+  FakeStreamFactory() {}
+  virtual ~FakeStreamFactory() {}
+
+  // Returns a WeakPtr<> to the last HttpStreamRequest returned by
+  // RequestStream() (which may be NULL if it was destroyed already).
+  base::WeakPtr<FakeStreamRequest> last_stream_request() {
+    return last_stream_request_;
+  }
+
+  virtual HttpStreamRequest* RequestStream(
+      const HttpRequestInfo& info,
+      RequestPriority priority,
+      const SSLConfig& server_ssl_config,
+      const SSLConfig& proxy_ssl_config,
+      HttpStreamRequest::Delegate* delegate,
+      const BoundNetLog& net_log) OVERRIDE {
+    FakeStreamRequest* fake_request = new FakeStreamRequest(priority, delegate);
+    last_stream_request_ = fake_request->AsWeakPtr();
+    return fake_request;
+  }
+
+  virtual HttpStreamRequest* RequestWebSocketStream(
+      const HttpRequestInfo& info,
+      RequestPriority priority,
+      const SSLConfig& server_ssl_config,
+      const SSLConfig& proxy_ssl_config,
+      HttpStreamRequest::Delegate* delegate,
+      WebSocketStreamBase::Factory* factory,
+      const BoundNetLog& net_log) OVERRIDE {
+    ADD_FAILURE();
+    return NULL;
+  }
+
+  virtual void PreconnectStreams(int num_streams,
+                                 const HttpRequestInfo& info,
+                                 RequestPriority priority,
+                                 const SSLConfig& server_ssl_config,
+                                 const SSLConfig& proxy_ssl_config) OVERRIDE {
+    ADD_FAILURE();
+  }
+
+  virtual base::Value* PipelineInfoToValue() const OVERRIDE {
+    ADD_FAILURE();
+    return NULL;
+  }
+
+  virtual const HostMappingRules* GetHostMappingRules() const OVERRIDE {
+    ADD_FAILURE();
+    return NULL;
+  }
+
+ private:
+  base::WeakPtr<FakeStreamRequest> last_stream_request_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeStreamFactory);
+};
+
+}  // namespace
+
+// Make sure that HttpNetworkTransaction passes on its priority to its
+// stream request on start.
+TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriorityOnStart) {
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  HttpNetworkSessionPeer peer(session);
+  FakeStreamFactory* fake_factory = new FakeStreamFactory();
+  peer.SetHttpStreamFactory(fake_factory);
+
+  HttpNetworkTransaction trans(LOW, session);
+
+  ASSERT_TRUE(fake_factory->last_stream_request() == NULL);
+
+  HttpRequestInfo request;
+  TestCompletionCallback callback;
+  EXPECT_EQ(ERR_IO_PENDING,
+            trans.Start(&request, callback.callback(), BoundNetLog()));
+
+  base::WeakPtr<FakeStreamRequest> fake_request =
+      fake_factory->last_stream_request();
+  ASSERT_TRUE(fake_request != NULL);
+  EXPECT_EQ(LOW, fake_request->priority());
+}
+
+// Make sure that HttpNetworkTransaction passes on its priority
+// updates to its stream request.
+TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriority) {
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  HttpNetworkSessionPeer peer(session);
+  FakeStreamFactory* fake_factory = new FakeStreamFactory();
+  peer.SetHttpStreamFactory(fake_factory);
+
+  HttpNetworkTransaction trans(LOW, session);
+
+  HttpRequestInfo request;
+  TestCompletionCallback callback;
+  EXPECT_EQ(ERR_IO_PENDING,
+            trans.Start(&request, callback.callback(), BoundNetLog()));
+
+  base::WeakPtr<FakeStreamRequest> fake_request =
+      fake_factory->last_stream_request();
+  ASSERT_TRUE(fake_request != NULL);
+  EXPECT_EQ(LOW, fake_request->priority());
+
+  trans.SetPriority(LOWEST);
+  ASSERT_TRUE(fake_request != NULL);
+  EXPECT_EQ(LOWEST, fake_request->priority());
+}
+
+// Make sure that HttpNetworkTransaction passes on its priority
+// updates to its stream.
+TEST_P(HttpNetworkTransactionTest, SetStreamPriority) {
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  HttpNetworkSessionPeer peer(session);
+  FakeStreamFactory* fake_factory = new FakeStreamFactory();
+  peer.SetHttpStreamFactory(fake_factory);
+
+  HttpNetworkTransaction trans(LOW, session);
+
+  HttpRequestInfo request;
+  TestCompletionCallback callback;
+  EXPECT_EQ(ERR_IO_PENDING,
+            trans.Start(&request, callback.callback(), BoundNetLog()));
+
+  base::WeakPtr<FakeStreamRequest> fake_request =
+      fake_factory->last_stream_request();
+  ASSERT_TRUE(fake_request != NULL);
+  base::WeakPtr<FakeStream> fake_stream = fake_request->FinishStreamRequest();
+  ASSERT_TRUE(fake_stream != NULL);
+  EXPECT_EQ(LOW, fake_stream->priority());
+
+  trans.SetPriority(LOWEST);
+  EXPECT_EQ(LOWEST, fake_stream->priority());
+}
+
+// Tests that when a used socket is returned to the SSL socket pool, it's closed
+// if the transport socket pool is stalled on the global socket limit.
+TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
+  ClientSocketPoolManager::set_max_sockets_per_group(
+      HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
+  ClientSocketPoolManager::set_max_sockets_per_pool(
+      HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
+
+  // Set up SSL request.
+
+  HttpRequestInfo ssl_request;
+  ssl_request.method = "GET";
+  ssl_request.url = GURL("https://www.google.com/");
+
+  MockWrite ssl_writes[] = {
+    MockWrite("GET / HTTP/1.1\r\n"
+              "Host: www.google.com\r\n"
+              "Connection: keep-alive\r\n\r\n"),
+  };
+  MockRead ssl_reads[] = {
+    MockRead("HTTP/1.1 200 OK\r\n"),
+    MockRead("Content-Length: 11\r\n\r\n"),
+    MockRead("hello world"),
+    MockRead(SYNCHRONOUS, OK),
+  };
+  StaticSocketDataProvider ssl_data(ssl_reads, arraysize(ssl_reads),
+                                    ssl_writes, arraysize(ssl_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&ssl_data);
+
+  SSLSocketDataProvider ssl(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+
+  // Set up HTTP request.
+
+  HttpRequestInfo http_request;
+  http_request.method = "GET";
+  http_request.url = GURL("http://www.google.com/");
+
+  MockWrite http_writes[] = {
+    MockWrite("GET / HTTP/1.1\r\n"
+              "Host: www.google.com\r\n"
+              "Connection: keep-alive\r\n\r\n"),
+  };
+  MockRead http_reads[] = {
+    MockRead("HTTP/1.1 200 OK\r\n"),
+    MockRead("Content-Length: 7\r\n\r\n"),
+    MockRead("falafel"),
+    MockRead(SYNCHRONOUS, OK),
+  };
+  StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
+                                     http_writes, arraysize(http_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&http_data);
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+  // Start the SSL request.
+  TestCompletionCallback ssl_callback;
+  scoped_ptr<HttpTransaction> ssl_trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+  ASSERT_EQ(ERR_IO_PENDING,
+            ssl_trans->Start(&ssl_request, ssl_callback.callback(),
+            BoundNetLog()));
+
+  // Start the HTTP request.  Pool should stall.
+  TestCompletionCallback http_callback;
+  scoped_ptr<HttpTransaction> http_trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+  ASSERT_EQ(ERR_IO_PENDING,
+            http_trans->Start(&http_request, http_callback.callback(),
+                              BoundNetLog()));
+  EXPECT_TRUE(IsTransportSocketPoolStalled(session));
+
+  // Wait for response from SSL request.
+  ASSERT_EQ(OK, ssl_callback.WaitForResult());
+  std::string response_data;
+  ASSERT_EQ(OK, ReadTransaction(ssl_trans.get(), &response_data));
+  EXPECT_EQ("hello world", response_data);
+
+  // The SSL socket should automatically be closed, so the HTTP request can
+  // start.
+  EXPECT_EQ(0, GetIdleSocketCountInSSLSocketPool(session));
+  ASSERT_FALSE(IsTransportSocketPoolStalled(session));
+
+  // The HTTP request can now complete.
+  ASSERT_EQ(OK, http_callback.WaitForResult());
+  ASSERT_EQ(OK, ReadTransaction(http_trans.get(), &response_data));
+  EXPECT_EQ("falafel", response_data);
+
+  EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session));
+}
+
+// Tests that when a SSL connection is established but there's no corresponding
+// request that needs it, the new socket is closed if the transport socket pool
+// is stalled on the global socket limit.
+TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest2) {
+  ClientSocketPoolManager::set_max_sockets_per_group(
+      HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
+  ClientSocketPoolManager::set_max_sockets_per_pool(
+      HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
+
+  // Set up an ssl request.
+
+  HttpRequestInfo ssl_request;
+  ssl_request.method = "GET";
+  ssl_request.url = GURL("https://www.foopy.com/");
+
+  // No data will be sent on the SSL socket.
+  StaticSocketDataProvider ssl_data;
+  session_deps_.socket_factory->AddSocketDataProvider(&ssl_data);
+
+  SSLSocketDataProvider ssl(ASYNC, OK);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+
+  // Set up HTTP request.
+
+  HttpRequestInfo http_request;
+  http_request.method = "GET";
+  http_request.url = GURL("http://www.google.com/");
+
+  MockWrite http_writes[] = {
+    MockWrite("GET / HTTP/1.1\r\n"
+              "Host: www.google.com\r\n"
+              "Connection: keep-alive\r\n\r\n"),
+  };
+  MockRead http_reads[] = {
+    MockRead("HTTP/1.1 200 OK\r\n"),
+    MockRead("Content-Length: 7\r\n\r\n"),
+    MockRead("falafel"),
+    MockRead(SYNCHRONOUS, OK),
+  };
+  StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
+                                     http_writes, arraysize(http_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&http_data);
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+  // Preconnect an SSL socket.  A preconnect is needed because connect jobs are
+  // cancelled when a normal transaction is cancelled.
+  net::HttpStreamFactory* http_stream_factory = session->http_stream_factory();
+  net::SSLConfig ssl_config;
+  session->ssl_config_service()->GetSSLConfig(&ssl_config);
+  http_stream_factory->PreconnectStreams(1, ssl_request, DEFAULT_PRIORITY,
+                                         ssl_config, ssl_config);
+  EXPECT_EQ(0, GetIdleSocketCountInSSLSocketPool(session));
+
+  // Start the HTTP request.  Pool should stall.
+  TestCompletionCallback http_callback;
+  scoped_ptr<HttpTransaction> http_trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+  ASSERT_EQ(ERR_IO_PENDING,
+            http_trans->Start(&http_request, http_callback.callback(),
+                              BoundNetLog()));
+  EXPECT_TRUE(IsTransportSocketPoolStalled(session));
+
+  // The SSL connection will automatically be closed once the connection is
+  // established, to let the HTTP request start.
+  ASSERT_EQ(OK, http_callback.WaitForResult());
+  std::string response_data;
+  ASSERT_EQ(OK, ReadTransaction(http_trans.get(), &response_data));
+  EXPECT_EQ("falafel", response_data);
+
+  EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session));
+}
+
 }  // namespace net
diff --git a/net/http/http_pipelined_connection_impl_unittest.cc b/net/http/http_pipelined_connection_impl_unittest.cc
index 1bf7597..296194e 100644
--- a/net/http/http_pipelined_connection_impl_unittest.cc
+++ b/net/http/http_pipelined_connection_impl_unittest.cc
@@ -28,15 +28,6 @@
 
 namespace net {
 
-class DummySocketParams : public base::RefCounted<DummySocketParams> {
- private:
-  friend class base::RefCounted<DummySocketParams>;
-  ~DummySocketParams() {}
-};
-
-REGISTER_SOCKET_PARAMS_FOR_POOL(MockTransportClientSocketPool,
-                                DummySocketParams);
-
 namespace {
 
 // Tests the load timing of a stream that's connected and is not the first
@@ -118,7 +109,7 @@
       data_->StopAfter(reads_count + writes_count);
     }
     factory_.AddSocketDataProvider(data_.get());
-    scoped_refptr<DummySocketParams> params;
+    scoped_refptr<MockTransportSocketParams> params;
     ClientSocketHandle* connection = new ClientSocketHandle;
     // Only give the connection a real NetLog to make sure that LoadTiming uses
     // the connection's ID, rather than the pipeline's.  Since pipelines are
diff --git a/net/http/http_pipelined_host_forced.cc b/net/http/http_pipelined_host_forced.cc
index 8179e86..8059d84 100644
--- a/net/http/http_pipelined_host_forced.cc
+++ b/net/http/http_pipelined_host_forced.cc
@@ -36,10 +36,9 @@
     bool was_npn_negotiated,
     NextProto protocol_negotiated) {
   CHECK(!pipeline_.get());
-  StreamSocket* wrapped_socket = connection->release_socket();
-  BufferedWriteStreamSocket* buffered_socket = new BufferedWriteStreamSocket(
-      wrapped_socket);
-  connection->set_socket(buffered_socket);
+  scoped_ptr<BufferedWriteStreamSocket> buffered_socket(
+      new BufferedWriteStreamSocket(connection->PassSocket()));
+  connection->SetSocket(buffered_socket.PassAs<StreamSocket>());
   pipeline_.reset(factory_->CreateNewPipeline(
       connection, this, key_.origin(), used_ssl_config, used_proxy_info,
       net_log, was_npn_negotiated, protocol_negotiated));
diff --git a/net/http/http_pipelined_stream.cc b/net/http/http_pipelined_stream.cc
index 951c2f9..df57435 100644
--- a/net/http/http_pipelined_stream.cc
+++ b/net/http/http_pipelined_stream.cc
@@ -121,6 +121,11 @@
   pipeline_->Drain(this, session);
 }
 
+void HttpPipelinedStream::SetPriority(RequestPriority priority) {
+  // TODO(akalin): Plumb this through to |pipeline_| and its
+  // underlying ClientSocketHandle.
+}
+
 const SSLConfig& HttpPipelinedStream::used_ssl_config() const {
   return pipeline_->used_ssl_config();
 }
diff --git a/net/http/http_pipelined_stream.h b/net/http/http_pipelined_stream.h
index 675d8f0..d3a7991 100644
--- a/net/http/http_pipelined_stream.h
+++ b/net/http/http_pipelined_stream.h
@@ -81,6 +81,8 @@
 
   virtual void Drain(HttpNetworkSession* session) OVERRIDE;
 
+  virtual void SetPriority(RequestPriority priority) OVERRIDE;
+
   // The SSLConfig used to establish this stream's pipeline.
   const SSLConfig& used_ssl_config() const;
 
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc
index b80df37..8d691b7 100644
--- a/net/http/http_proxy_client_socket_pool.cc
+++ b/net/http/http_proxy_client_socket_pool.cc
@@ -58,7 +58,7 @@
 
 const HostResolver::RequestInfo& HttpProxySocketParams::destination() const {
   if (transport_params_.get() == NULL) {
-    return ssl_params_->transport_params()->destination();
+    return ssl_params_->GetDirectConnectionParams()->destination();
   } else {
     return transport_params_->destination();
   }
@@ -77,6 +77,7 @@
 
 HttpProxyConnectJob::HttpProxyConnectJob(
     const std::string& group_name,
+    RequestPriority priority,
     const scoped_refptr<HttpProxySocketParams>& params,
     const base::TimeDelta& timeout_duration,
     TransportClientSocketPool* transport_pool,
@@ -84,7 +85,7 @@
     HostResolver* host_resolver,
     Delegate* delegate,
     NetLog* net_log)
-    : ConnectJob(group_name, timeout_duration, delegate,
+    : ConnectJob(group_name, timeout_duration, priority, delegate,
                  BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
       weak_ptr_factory_(this),
       params_(params),
@@ -179,10 +180,12 @@
 int HttpProxyConnectJob::DoTransportConnect() {
   next_state_ = STATE_TCP_CONNECT_COMPLETE;
   transport_socket_handle_.reset(new ClientSocketHandle());
-  return transport_socket_handle_->Init(
-      group_name(), params_->transport_params(),
-      params_->transport_params()->destination().priority(), callback_,
-      transport_pool_, net_log());
+  return transport_socket_handle_->Init(group_name(),
+                                        params_->transport_params(),
+                                        priority(),
+                                        callback_,
+                                        transport_pool_,
+                                        net_log());
 }
 
 int HttpProxyConnectJob::DoTransportConnectComplete(int result) {
@@ -213,9 +216,8 @@
   next_state_ = STATE_SSL_CONNECT_COMPLETE;
   transport_socket_handle_.reset(new ClientSocketHandle());
   return transport_socket_handle_->Init(
-      group_name(), params_->ssl_params(),
-      params_->ssl_params()->transport_params()->destination().priority(),
-      callback_, ssl_pool_, net_log());
+      group_name(), params_->ssl_params(), priority(), callback_,
+      ssl_pool_, net_log());
 }
 
 int HttpProxyConnectJob::DoSSLConnectComplete(int result) {
@@ -289,7 +291,7 @@
 int HttpProxyConnectJob::DoHttpProxyConnectComplete(int result) {
   if (result == OK || result == ERR_PROXY_AUTH_REQUESTED ||
       result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
-      set_socket(transport_socket_.release());
+    SetSocket(transport_socket_.PassAs<StreamSocket>());
   }
 
   return result;
@@ -321,9 +323,12 @@
   }
 
   next_state_ = STATE_SPDY_PROXY_CREATE_STREAM_COMPLETE;
-  return spdy_stream_request_.StartRequest(
-      SPDY_BIDIRECTIONAL_STREAM, spdy_session, params_->request_url(),
-      params_->destination().priority(), spdy_session->net_log(), callback_);
+  return spdy_stream_request_.StartRequest(SPDY_BIDIRECTIONAL_STREAM,
+                                           spdy_session,
+                                           params_->request_url(),
+                                           priority(),
+                                           spdy_session->net_log(),
+                                           callback_);
 }
 
 int HttpProxyConnectJob::DoSpdyProxyCreateStreamComplete(int result) {
@@ -380,19 +385,20 @@
 }
 
 
-ConnectJob*
+scoped_ptr<ConnectJob>
 HttpProxyClientSocketPool::HttpProxyConnectJobFactory::NewConnectJob(
     const std::string& group_name,
     const PoolBase::Request& request,
     ConnectJob::Delegate* delegate) const {
-  return new HttpProxyConnectJob(group_name,
-                                 request.params(),
-                                 ConnectionTimeout(),
-                                 transport_pool_,
-                                 ssl_pool_,
-                                 host_resolver_,
-                                 delegate,
-                                 net_log_);
+  return scoped_ptr<ConnectJob>(new HttpProxyConnectJob(group_name,
+                                                        request.priority(),
+                                                        request.params(),
+                                                        ConnectionTimeout(),
+                                                        transport_pool_,
+                                                        ssl_pool_,
+                                                        host_resolver_,
+                                                        delegate,
+                                                        net_log_));
 }
 
 base::TimeDelta
@@ -411,7 +417,7 @@
     NetLog* net_log)
     : transport_pool_(transport_pool),
       ssl_pool_(ssl_pool),
-      base_(max_sockets, max_sockets_per_group, histograms,
+      base_(this, max_sockets, max_sockets_per_group, histograms,
             ClientSocketPool::unused_idle_socket_timeout(),
             ClientSocketPool::used_idle_socket_timeout(),
             new HttpProxyConnectJobFactory(transport_pool,
@@ -420,17 +426,12 @@
                                            net_log)) {
   // We should always have a |transport_pool_| except in unit tests.
   if (transport_pool_)
-    transport_pool_->AddLayeredPool(this);
+    base_.AddLowerLayeredPool(transport_pool_);
   if (ssl_pool_)
-    ssl_pool_->AddLayeredPool(this);
+    base_.AddLowerLayeredPool(ssl_pool_);
 }
 
 HttpProxyClientSocketPool::~HttpProxyClientSocketPool() {
-  if (ssl_pool_)
-    ssl_pool_->RemoveLayeredPool(this);
-  // We should always have a |transport_pool_| except in unit tests.
-  if (transport_pool_)
-    transport_pool_->RemoveLayeredPool(this);
 }
 
 int HttpProxyClientSocketPool::RequestSocket(
@@ -462,20 +463,15 @@
 }
 
 void HttpProxyClientSocketPool::ReleaseSocket(const std::string& group_name,
-                                              StreamSocket* socket, int id) {
-  base_.ReleaseSocket(group_name, socket, id);
+                                              scoped_ptr<StreamSocket> socket,
+                                              int id) {
+  base_.ReleaseSocket(group_name, socket.Pass(), id);
 }
 
 void HttpProxyClientSocketPool::FlushWithError(int error) {
   base_.FlushWithError(error);
 }
 
-bool HttpProxyClientSocketPool::IsStalled() const {
-  return base_.IsStalled() ||
-      (transport_pool_ && transport_pool_->IsStalled()) ||
-      (ssl_pool_ && ssl_pool_->IsStalled());
-}
-
 void HttpProxyClientSocketPool::CloseIdleSockets() {
   base_.CloseIdleSockets();
 }
@@ -494,14 +490,6 @@
   return base_.GetLoadState(group_name, handle);
 }
 
-void HttpProxyClientSocketPool::AddLayeredPool(LayeredPool* layered_pool) {
-  base_.AddLayeredPool(layered_pool);
-}
-
-void HttpProxyClientSocketPool::RemoveLayeredPool(LayeredPool* layered_pool) {
-  base_.RemoveLayeredPool(layered_pool);
-}
-
 base::DictionaryValue* HttpProxyClientSocketPool::GetInfoAsValue(
     const std::string& name,
     const std::string& type,
@@ -532,10 +520,24 @@
   return base_.histograms();
 }
 
+bool HttpProxyClientSocketPool::IsStalled() const {
+  return base_.IsStalled();
+}
+
+void HttpProxyClientSocketPool::AddHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  base_.AddHigherLayeredPool(higher_pool);
+}
+
+void HttpProxyClientSocketPool::RemoveHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  base_.RemoveHigherLayeredPool(higher_pool);
+}
+
 bool HttpProxyClientSocketPool::CloseOneIdleConnection() {
   if (base_.CloseOneIdleSocket())
     return true;
-  return base_.CloseOneIdleConnectionInLayeredPool();
+  return base_.CloseOneIdleConnectionInHigherLayeredPool();
 }
 
 }  // namespace net
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h
index a15b8ca..a26c05f 100644
--- a/net/http/http_proxy_client_socket_pool.h
+++ b/net/http/http_proxy_client_socket_pool.h
@@ -96,6 +96,7 @@
 class HttpProxyConnectJob : public ConnectJob {
  public:
   HttpProxyConnectJob(const std::string& group_name,
+                      RequestPriority priority,
                       const scoped_refptr<HttpProxySocketParams>& params,
                       const base::TimeDelta& timeout_duration,
                       TransportClientSocketPool* transport_pool,
@@ -174,8 +175,10 @@
 
 class NET_EXPORT_PRIVATE HttpProxyClientSocketPool
     : public ClientSocketPool,
-      public LayeredPool {
+      public HigherLayeredPool {
  public:
+  typedef HttpProxySocketParams SocketParams;
+
   HttpProxyClientSocketPool(
       int max_sockets,
       int max_sockets_per_group,
@@ -204,13 +207,11 @@
                              ClientSocketHandle* handle) OVERRIDE;
 
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket,
+                             scoped_ptr<StreamSocket> socket,
                              int id) OVERRIDE;
 
   virtual void FlushWithError(int error) OVERRIDE;
 
-  virtual bool IsStalled() const OVERRIDE;
-
   virtual void CloseIdleSockets() OVERRIDE;
 
   virtual int IdleSocketCount() const OVERRIDE;
@@ -222,10 +223,6 @@
       const std::string& group_name,
       const ClientSocketHandle* handle) const OVERRIDE;
 
-  virtual void AddLayeredPool(LayeredPool* layered_pool) OVERRIDE;
-
-  virtual void RemoveLayeredPool(LayeredPool* layered_pool) OVERRIDE;
-
   virtual base::DictionaryValue* GetInfoAsValue(
       const std::string& name,
       const std::string& type,
@@ -235,7 +232,14 @@
 
   virtual ClientSocketPoolHistograms* histograms() const OVERRIDE;
 
-  // LayeredPool implementation.
+  // LowerLayeredPool implementation.
+  virtual bool IsStalled() const OVERRIDE;
+
+  virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+
+  virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+
+  // HigherLayeredPool implementation.
   virtual bool CloseOneIdleConnection() OVERRIDE;
 
  private:
@@ -250,7 +254,7 @@
         NetLog* net_log);
 
     // ClientSocketPoolBase::ConnectJobFactory methods.
-    virtual ConnectJob* NewConnectJob(
+    virtual scoped_ptr<ConnectJob> NewConnectJob(
         const std::string& group_name,
         const PoolBase::Request& request,
         ConnectJob::Delegate* delegate) const OVERRIDE;
@@ -274,9 +278,6 @@
   DISALLOW_COPY_AND_ASSIGN(HttpProxyClientSocketPool);
 };
 
-REGISTER_SOCKET_PARAMS_FOR_POOL(HttpProxyClientSocketPool,
-                                HttpProxySocketParams);
-
 }  // namespace net
 
 #endif  // NET_HTTP_HTTP_PROXY_CLIENT_SOCKET_POOL_H_
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 2274f25..a40c9da 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -55,31 +55,14 @@
 
 typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
 
-}  // namespace
+const char kHttpProxyHost[] = "httpproxy.example.com";
+const char kHttpsProxyHost[] = "httpsproxy.example.com";
 
 class HttpProxyClientSocketPoolTest
     : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
  protected:
   HttpProxyClientSocketPoolTest()
       : session_deps_(GetParam().protocol),
-        ssl_config_(),
-        ignored_transport_socket_params_(
-            new TransportSocketParams(HostPortPair("proxy", 80),
-                                      LOWEST,
-                                      false,
-                                      false,
-                                      OnHostResolutionCallback())),
-        ignored_ssl_socket_params_(
-            new SSLSocketParams(ignored_transport_socket_params_,
-                                NULL,
-                                NULL,
-                                ProxyServer::SCHEME_DIRECT,
-                                HostPortPair("www.google.com", 443),
-                                ssl_config_,
-                                kPrivacyModeDisabled,
-                                0,
-                                false,
-                                false)),
         tcp_histograms_("MockTCP"),
         transport_socket_pool_(
             kMaxSockets,
@@ -118,7 +101,9 @@
   void AddAuthToCache() {
     const base::string16 kFoo(ASCIIToUTF16("foo"));
     const base::string16 kBar(ASCIIToUTF16("bar"));
-    GURL proxy_url(GetParam().proxy_type == HTTP ? "http://proxy" : "https://proxy:80");
+    GURL proxy_url(GetParam().proxy_type == HTTP ?
+                   (std::string("http://") + kHttpProxyHost) :
+                   (std::string("https://") + kHttpsProxyHost));
     session_->http_auth_cache()->Add(proxy_url,
                                      "MyRealm1",
                                      HttpAuth::AUTH_SCHEME_BASIC,
@@ -127,24 +112,40 @@
                                      "/");
   }
 
-  scoped_refptr<TransportSocketParams> GetTcpParams() {
+  scoped_refptr<TransportSocketParams> CreateHttpProxyParams() const {
     if (GetParam().proxy_type != HTTP)
-      return scoped_refptr<TransportSocketParams>();
-    return ignored_transport_socket_params_;
+      return NULL;
+    return new TransportSocketParams(HostPortPair(kHttpProxyHost, 80),
+                                     false,
+                                     false,
+                                     OnHostResolutionCallback());
   }
 
-  scoped_refptr<SSLSocketParams> GetSslParams() {
+  scoped_refptr<SSLSocketParams> CreateHttpsProxyParams() const {
     if (GetParam().proxy_type == HTTP)
-      return scoped_refptr<SSLSocketParams>();
-    return ignored_ssl_socket_params_;
+      return NULL;
+    return new SSLSocketParams(
+        new TransportSocketParams(
+            HostPortPair(kHttpsProxyHost, 443),
+            false,
+            false,
+            OnHostResolutionCallback()),
+        NULL,
+        NULL,
+        HostPortPair(kHttpsProxyHost, 443),
+        SSLConfig(),
+        kPrivacyModeDisabled,
+        0,
+        false,
+        false);
   }
 
   // Returns the a correctly constructed HttpProxyParms
   // for the HTTP or HTTPS proxy.
-  scoped_refptr<HttpProxySocketParams> GetParams(bool tunnel) {
+  scoped_refptr<HttpProxySocketParams> CreateParams(bool tunnel) {
     return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams(
-        GetTcpParams(),
-        GetSslParams(),
+        CreateHttpProxyParams(),
+        CreateHttpsProxyParams(),
         GURL(tunnel ? "https://www.google.com/" : "http://www.google.com"),
         std::string(),
         HostPortPair("www.google.com", tunnel ? 443 : 80),
@@ -154,16 +155,16 @@
         tunnel));
   }
 
-  scoped_refptr<HttpProxySocketParams> GetTunnelParams() {
-    return GetParams(true);
+  scoped_refptr<HttpProxySocketParams> CreateTunnelParams() {
+    return CreateParams(true);
   }
 
-  scoped_refptr<HttpProxySocketParams> GetNoTunnelParams() {
-    return GetParams(false);
+  scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams() {
+    return CreateParams(false);
   }
 
-  DeterministicMockClientSocketFactory& socket_factory() {
-    return *session_deps_.deterministic_socket_factory.get();
+  DeterministicMockClientSocketFactory* socket_factory() {
+    return session_deps_.deterministic_socket_factory.get();
   }
 
   void Initialize(MockRead* reads, size_t reads_count,
@@ -181,14 +182,14 @@
     data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
     data_->StopAfter(2);  // Request / Response
 
-    socket_factory().AddSocketDataProvider(data_.get());
+    socket_factory()->AddSocketDataProvider(data_.get());
 
     if (GetParam().proxy_type != HTTP) {
       ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK));
       if (GetParam().proxy_type == SPDY) {
         InitializeSpdySsl();
       }
-      socket_factory().AddSSLSocketDataProvider(ssl_data_.get());
+      socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
     }
   }
 
@@ -201,12 +202,13 @@
         &session_deps_);
   }
 
+  RequestPriority GetLastTransportRequestPriority() const {
+    return transport_socket_pool_.last_request_priority();
+  }
+
  private:
   SpdySessionDependencies session_deps_;
-  SSLConfig ssl_config_;
 
-  scoped_refptr<TransportSocketParams> ignored_transport_socket_params_;
-  scoped_refptr<SSLSocketParams> ignored_ssl_socket_params_;
   ClientSocketPoolHistograms tcp_histograms_;
   MockTransportClientSocketPool transport_socket_pool_;
   ClientSocketPoolHistograms ssl_histograms_;
@@ -255,7 +257,7 @@
 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
   Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
 
-  int rv = handle_.Init("a", GetNoTunnelParams(), LOW, CompletionCallback(),
+  int rv = handle_.Init("a", CreateNoTunnelParams(), LOW, CompletionCallback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(OK, rv);
   EXPECT_TRUE(handle_.is_initialized());
@@ -265,6 +267,16 @@
   EXPECT_TRUE(tunnel_socket->IsConnected());
 }
 
+// Make sure that HttpProxyConnectJob passes on its priority to its
+// (non-SSL) socket request on Init.
+TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
+  Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
+  EXPECT_EQ(OK,
+            handle_.Init("a", CreateNoTunnelParams(), HIGHEST,
+                         CompletionCallback(), &pool_, BoundNetLog()));
+  EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority());
+}
+
 TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) {
   MockWrite writes[] = {
     MockWrite(ASYNC, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n"
@@ -279,7 +291,7 @@
     MockRead(ASYNC, 4, "0123456789"),
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(NULL, 0, 1));
+      spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOW));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite spdy_writes[] = {
@@ -296,7 +308,7 @@
                                            0,
                                            false,
                                            1,
-                                           LOWEST,
+                                           LOW,
                                            SYN_REPLY,
                                            CONTROL_FLAG_NONE,
                                            kAuthChallenge,
@@ -312,7 +324,7 @@
              arraysize(spdy_writes));
 
   data_->StopAfter(4);
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -331,7 +343,6 @@
   } else {
     EXPECT_FALSE(tunnel_socket->IsConnected());
     EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
-    EXPECT_FALSE(tunnel_socket->IsUsingSpdy());
   }
 }
 
@@ -355,7 +366,7 @@
              NULL, 0);
   AddAuthToCache();
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(OK, rv);
   EXPECT_TRUE(handle_.is_initialized());
@@ -377,7 +388,7 @@
   };
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
   MockWrite spdy_writes[] = {
     CreateMockWrite(*req, 0, ASYNC)
   };
@@ -392,7 +403,7 @@
              arraysize(spdy_writes));
   AddAuthToCache();
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -407,14 +418,47 @@
   EXPECT_TRUE(tunnel_socket->IsConnected());
 }
 
+// Make sure that HttpProxyConnectJob passes on its priority to its
+// SPDY session's socket request on Init (if applicable).
+TEST_P(HttpProxyClientSocketPoolTest,
+       SetSpdySessionSocketRequestPriorityOnInit) {
+  if (GetParam().proxy_type != SPDY)
+    return;
+
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize,
+                                      1, MEDIUM));
+  MockWrite spdy_writes[] = {
+    CreateMockWrite(*req, 0, ASYNC)
+  };
+  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  MockRead spdy_reads[] = {
+    CreateMockRead(*resp, 1, ASYNC),
+    MockRead(ASYNC, 0, 2)
+  };
+
+  Initialize(NULL, 0, NULL, 0,
+             spdy_reads, arraysize(spdy_reads),
+             spdy_writes, arraysize(spdy_writes));
+  AddAuthToCache();
+
+  EXPECT_EQ(ERR_IO_PENDING,
+            handle_.Init("a", CreateTunnelParams(), MEDIUM,
+                         callback_.callback(), &pool_, BoundNetLog()));
+  EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
+
+  data_->RunFor(2);
+  EXPECT_EQ(OK, callback_.WaitForResult());
+}
+
 TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
   if (GetParam().proxy_type == SPDY) return;
   data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
   data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
 
-  socket_factory().AddSocketDataProvider(data_.get());
+  socket_factory()->AddSocketDataProvider(data_.get());
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -430,16 +474,16 @@
   if (GetParam().proxy_type == HTTP) return;
   data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
   data_->set_connect_data(MockConnect(ASYNC, OK));
-  socket_factory().AddSocketDataProvider(data_.get());
+  socket_factory()->AddSocketDataProvider(data_.get());
 
   ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
                                             ERR_CERT_AUTHORITY_INVALID));
   if (GetParam().proxy_type == SPDY) {
     InitializeSpdySsl();
   }
-  socket_factory().AddSSLSocketDataProvider(ssl_data_.get());
+  socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -455,16 +499,16 @@
   if (GetParam().proxy_type == HTTP) return;
   data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
   data_->set_connect_data(MockConnect(ASYNC, OK));
-  socket_factory().AddSocketDataProvider(data_.get());
+  socket_factory()->AddSocketDataProvider(data_.get());
 
   ssl_data_.reset(new SSLSocketDataProvider(ASYNC,
                                             ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
   if (GetParam().proxy_type == SPDY) {
     InitializeSpdySsl();
   }
-  socket_factory().AddSSLSocketDataProvider(ssl_data_.get());
+  socket_factory()->AddSSLSocketDataProvider(ssl_data_.get());
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -489,7 +533,7 @@
     MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2),
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
   MockWrite spdy_writes[] = {
     CreateMockWrite(*req, 0, ASYNC)
   };
@@ -502,7 +546,7 @@
              arraysize(spdy_writes));
   AddAuthToCache();
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -532,7 +576,7 @@
     MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"),
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite spdy_writes[] = {
@@ -550,7 +594,7 @@
              arraysize(spdy_writes));
   AddAuthToCache();
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -583,7 +627,7 @@
     MockRead(ASYNC, 1, responseText.c_str()),
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1));
+      spdy_util_.ConstructSpdyConnect(kAuthHeaders, kAuthHeadersSize, 1, LOW));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
 
@@ -612,7 +656,7 @@
              arraysize(spdy_writes));
   AddAuthToCache();
 
-  int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(),
+  int rv = handle_.Init("a", CreateTunnelParams(), LOW, callback_.callback(),
                         &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
@@ -653,4 +697,6 @@
 
 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.
 
+}  // namespace
+
 }  // namespace net
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
index 5d9fcc4..70134cc 100644
--- a/net/http/http_response_body_drainer_unittest.cc
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -127,6 +127,8 @@
 
   virtual void Drain(HttpNetworkSession*) OVERRIDE {}
 
+  virtual void SetPriority(RequestPriority priority) OVERRIDE {}
+
   // Methods to tweak/observer mock behavior:
   void set_stall_reads_forever() { stall_reads_forever_ = true; }
 
diff --git a/net/http/http_stream_base.h b/net/http/http_stream_base.h
index 6dce6d2..596ed75 100644
--- a/net/http/http_stream_base.h
+++ b/net/http/http_stream_base.h
@@ -141,6 +141,9 @@
   // draining is complete.
   virtual void Drain(HttpNetworkSession* session) = 0;
 
+  // Called when the priority of the parent transaction changes.
+  virtual void SetPriority(RequestPriority priority) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HttpStreamBase);
 };
diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h
index 6db6905..0de3b65 100644
--- a/net/http/http_stream_factory.h
+++ b/net/http/http_stream_factory.h
@@ -157,6 +157,9 @@
   virtual int RestartTunnelWithProxyAuth(
       const AuthCredentials& credentials) = 0;
 
+  // Called when the priority of the parent transaction changes.
+  virtual void SetPriority(RequestPriority priority) = 0;
+
   // Returns the LoadState for the request.
   virtual LoadState GetLoadState() const = 0;
 
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h
index 3949f38..4339fd3 100644
--- a/net/http/http_stream_factory_impl.h
+++ b/net/http/http_stream_factory_impl.h
@@ -9,6 +9,7 @@
 #include <set>
 #include <vector>
 
+#include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_log.h"
@@ -66,8 +67,10 @@
   size_t num_orphaned_jobs() const { return orphaned_job_set_.size(); }
 
  private:
-  class Request;
-  class Job;
+  FRIEND_TEST_ALL_PREFIXES(HttpStreamFactoryImplRequestTest, SetPriority);
+
+  class NET_EXPORT_PRIVATE Request;
+  class NET_EXPORT_PRIVATE Job;
 
   typedef std::set<Request*> RequestSet;
   typedef std::vector<Request*> RequestVector;
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index b2eee3b..c0383f4 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -230,12 +230,17 @@
   }
 }
 
+void HttpStreamFactoryImpl::Job::SetPriority(RequestPriority priority) {
+  priority_ = priority;
+  // TODO(akalin): Propagate this to |connection_| and maybe the
+  // preconnect state.
+}
+
 bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const {
   return was_npn_negotiated_;
 }
 
-NextProto HttpStreamFactoryImpl::Job::protocol_negotiated()
-    const {
+NextProto HttpStreamFactoryImpl::Job::protocol_negotiated() const {
   return protocol_negotiated_;
 }
 
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index 2c2eb34..01a794a 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -74,6 +74,9 @@
   // Used to detach the Job from |request|.
   void Orphan(const Request* request);
 
+  void SetPriority(RequestPriority priority);
+
+  RequestPriority priority() const { return priority_; }
   bool was_npn_negotiated() const;
   NextProto protocol_negotiated() const;
   bool using_spdy() const;
diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc
index e73a897..57190ed 100644
--- a/net/http/http_stream_factory_impl_request.cc
+++ b/net/http/http_stream_factory_impl_request.cc
@@ -215,6 +215,15 @@
   return bound_job_->RestartTunnelWithProxyAuth(credentials);
 }
 
+void HttpStreamFactoryImpl::Request::SetPriority(RequestPriority priority) {
+  for (std::set<HttpStreamFactoryImpl::Job*>::const_iterator it = jobs_.begin();
+       it != jobs_.end(); ++it) {
+    (*it)->SetPriority(priority);
+  }
+  if (bound_job_)
+    bound_job_->SetPriority(priority);
+}
+
 LoadState HttpStreamFactoryImpl::Request::GetLoadState() const {
   if (bound_job_.get())
     return bound_job_->GetLoadState();
diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h
index 169e1f5..d6f9b02 100644
--- a/net/http/http_stream_factory_impl_request.h
+++ b/net/http/http_stream_factory_impl_request.h
@@ -105,6 +105,7 @@
 
   virtual int RestartTunnelWithProxyAuth(
       const AuthCredentials& credentials) OVERRIDE;
+  virtual void SetPriority(RequestPriority priority) OVERRIDE;
   virtual LoadState GetLoadState() const OVERRIDE;
   virtual bool was_npn_negotiated() const OVERRIDE;
   virtual NextProto protocol_negotiated() const OVERRIDE;
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc
new file mode 100644
index 0000000..1f38a2e
--- /dev/null
+++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -0,0 +1,98 @@
+// 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/http/http_stream_factory_impl_request.h"
+
+#include "net/http/http_stream_factory_impl_job.h"
+#include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_service.h"
+#include "net/spdy/spdy_test_util_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class HttpStreamFactoryImplRequestTest
+    : public ::testing::Test,
+      public ::testing::WithParamInterface<NextProto> {};
+
+INSTANTIATE_TEST_CASE_P(
+    NextProto,
+    HttpStreamFactoryImplRequestTest,
+    testing::Values(kProtoSPDY2, kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
+                    kProtoHTTP2Draft04));
+
+namespace {
+
+class DoNothingRequestDelegate : public HttpStreamRequest::Delegate {
+ public:
+  DoNothingRequestDelegate() {}
+
+  virtual ~DoNothingRequestDelegate() {}
+
+  // HttpStreamRequest::Delegate
+  virtual void OnStreamReady(
+      const SSLConfig& used_ssl_config,
+      const ProxyInfo& used_proxy_info,
+      HttpStreamBase* stream) OVERRIDE {}
+  virtual void OnWebSocketStreamReady(
+      const SSLConfig& used_ssl_config,
+      const ProxyInfo& used_proxy_info,
+      WebSocketStreamBase* stream) OVERRIDE {}
+  virtual void OnStreamFailed(
+      int status,
+      const SSLConfig& used_ssl_config) OVERRIDE {}
+  virtual void OnCertificateError(
+      int status,
+      const SSLConfig& used_ssl_config,
+      const SSLInfo& ssl_info) OVERRIDE {}
+  virtual void OnNeedsProxyAuth(const HttpResponseInfo& proxy_response,
+                                const SSLConfig& used_ssl_config,
+                                const ProxyInfo& used_proxy_info,
+                                HttpAuthController* auth_controller) OVERRIDE {}
+  virtual void OnNeedsClientAuth(const SSLConfig& used_ssl_config,
+                                 SSLCertRequestInfo* cert_info) OVERRIDE {}
+  virtual void OnHttpsProxyTunnelResponse(const HttpResponseInfo& response_info,
+                                          const SSLConfig& used_ssl_config,
+                                          const ProxyInfo& used_proxy_info,
+                                          HttpStreamBase* stream) OVERRIDE {}
+};
+
+}  // namespace
+
+// Make sure that Request passes on its priority updates to its jobs.
+TEST_P(HttpStreamFactoryImplRequestTest, SetPriority) {
+  SpdySessionDependencies session_deps(GetParam(),
+                                       ProxyService::CreateDirect());
+
+  scoped_refptr<HttpNetworkSession>
+      session(SpdySessionDependencies::SpdyCreateSession(&session_deps));
+  HttpStreamFactoryImpl* factory =
+      static_cast<HttpStreamFactoryImpl*>(session->http_stream_factory());
+
+  DoNothingRequestDelegate request_delegate;
+  HttpStreamFactoryImpl::Request request(
+      GURL(), factory, &request_delegate, NULL, BoundNetLog());
+
+  HttpStreamFactoryImpl::Job* job =
+      new HttpStreamFactoryImpl::Job(factory,
+                                     session,
+                                     HttpRequestInfo(),
+                                     DEFAULT_PRIORITY,
+                                     SSLConfig(),
+                                     SSLConfig(),
+                                     NULL);
+  request.AttachJob(job);
+  EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
+
+  request.SetPriority(MEDIUM);
+  EXPECT_EQ(MEDIUM, job->priority());
+
+  // Make |job| the bound job.
+  request.OnStreamFailed(job, ERR_FAILED, SSLConfig());
+
+  request.SetPriority(IDLE);
+  EXPECT_EQ(IDLE, job->priority());
+}
+
+}  // namespace net
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 14fbc03..f378c93 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -314,7 +314,7 @@
     ADD_FAILURE();
   }
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket,
+                             scoped_ptr<StreamSocket> socket,
                              int id) OVERRIDE {
     ADD_FAILURE();
   }
diff --git a/net/http/http_stream_parser_unittest.cc b/net/http/http_stream_parser_unittest.cc
index d530c2d..8477594 100644
--- a/net/http/http_stream_parser_unittest.cc
+++ b/net/http/http_stream_parser_unittest.cc
@@ -220,7 +220,7 @@
   ASSERT_EQ(OK, rv);
 
   scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
-  socket_handle->set_socket(transport.release());
+  socket_handle->SetSocket(transport.PassAs<StreamSocket>());
 
   HttpRequestInfo request_info;
   request_info.method = "GET";
@@ -375,7 +375,7 @@
       ASSERT_EQ(OK, rv);
 
       scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
-      socket_handle->set_socket(transport.release());
+      socket_handle->SetSocket(transport.PassAs<StreamSocket>());
 
       HttpRequestInfo request_info;
       request_info.method = "GET";
diff --git a/net/http/http_util_icu.cc b/net/http/http_util_icu.cc
index 64e7424..4f38f84 100644
--- a/net/http/http_util_icu.cc
+++ b/net/http/http_util_icu.cc
@@ -14,7 +14,7 @@
 
 // static
 std::string HttpUtil::PathForRequest(const GURL& url) {
-  DCHECK(url.is_valid() && (url.SchemeIs("http") || url.SchemeIs("https")));
+  DCHECK(url.is_valid() && url.SchemeIsHTTPOrHTTPS());
   if (url.has_query())
     return url.path() + "?" + url.query();
   return url.path();
@@ -23,8 +23,7 @@
 // static
 std::string HttpUtil::SpecForRequest(const GURL& url) {
   // We may get ftp scheme when fetching ftp resources through proxy.
-  DCHECK(url.is_valid() && (url.SchemeIs("http") ||
-                            url.SchemeIs("https") ||
+  DCHECK(url.is_valid() && (url.SchemeIsHTTPOrHTTPS() ||
                             url.SchemeIs("ftp")));
   return SimplifyUrlForRequest(url).spec();
 }
diff --git a/net/http/proxy_connect_redirect_http_stream.cc b/net/http/proxy_connect_redirect_http_stream.cc
index f30f33c..59bb014 100644
--- a/net/http/proxy_connect_redirect_http_stream.cc
+++ b/net/http/proxy_connect_redirect_http_stream.cc
@@ -109,6 +109,10 @@
   NOTREACHED();
 }
 
+void ProxyConnectRedirectHttpStream::SetPriority(RequestPriority priority) {
+  // Nothing to do.
+}
+
 UploadProgress ProxyConnectRedirectHttpStream::GetUploadProgress() const {
   NOTREACHED();
   return UploadProgress();
diff --git a/net/http/proxy_connect_redirect_http_stream.h b/net/http/proxy_connect_redirect_http_stream.h
index f39ec76..c335c21 100644
--- a/net/http/proxy_connect_redirect_http_stream.h
+++ b/net/http/proxy_connect_redirect_http_stream.h
@@ -59,6 +59,10 @@
       SSLCertRequestInfo* cert_request_info) OVERRIDE;
   virtual bool IsSpdyHttpStream() const OVERRIDE;
   virtual void Drain(HttpNetworkSession* session) OVERRIDE;
+
+  // This function may be called.
+  virtual void SetPriority(RequestPriority priority) OVERRIDE;
+
   virtual UploadProgress GetUploadProgress() const OVERRIDE;
   virtual HttpStream* RenewStreamForAuth() OVERRIDE;
 
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index 22b5cf9..f7ca89d 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -401,6 +401,7 @@
   {19, true, "\006script\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
   {20, true, "\007history\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
   {21, true, "\010security\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
+  {22, true, "\011translate\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
   {20, true, "\006market\007android\003com", true, kGooglePins, DOMAIN_ANDROID_COM },
   {26, true, "\003ssl\020google-analytics\003com", true, kGooglePins, DOMAIN_GOOGLE_ANALYTICS_COM },
   {18, true, "\005drive\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
@@ -419,6 +420,7 @@
   {23, true, "\021googleusercontent\003com", false, kGooglePins, DOMAIN_GOOGLEUSERCONTENT_COM },
   {13, true, "\007youtube\003com", false, kGooglePins, DOMAIN_YOUTUBE_COM },
   {16, true, "\012googleapis\003com", false, kGooglePins, DOMAIN_GOOGLEAPIS_COM },
+  {26, true, "\011translate\012googleapis\003com", true, kGooglePins, DOMAIN_GOOGLEAPIS_COM },
   {22, true, "\020googleadservices\003com", false, kGooglePins, DOMAIN_GOOGLEADSERVICES_COM },
   {13, true, "\007appspot\003com", false, kGooglePins, DOMAIN_APPSPOT_COM },
   {23, true, "\021googlesyndication\003com", false, kGooglePins, DOMAIN_GOOGLESYNDICATION_COM },
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 1106187..f2ea764 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -178,6 +178,7 @@
     { "name": "script.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
     { "name": "history.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
     { "name": "security.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "translate.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
 
     // Other Google-related domains that must use HTTPS.
     { "name": "market.android.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
@@ -193,6 +194,7 @@
     { "name": "code.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
     { "name": "googlecode.com", "include_subdomains": true, "pins": "google" },
     { "name": "dl.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "translate.googleapis.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
 
     // chart.apis.google.com is *not* HSTS because the certificate doesn't match
     // and there are lots of links out there that still use the name. The correct
diff --git a/net/net.gyp b/net/net.gyp
index cedc05b..4f99432 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -399,6 +399,8 @@
         'disk_cache/simple/simple_index.h',
         'disk_cache/simple/simple_index_file.cc',
         'disk_cache/simple/simple_index_file.h',
+        'disk_cache/simple/simple_index_file_posix.cc',
+        'disk_cache/simple/simple_index_file_win.cc',
         'disk_cache/simple/simple_net_log_parameters.cc',
         'disk_cache/simple/simple_net_log_parameters.h',
         'disk_cache/simple/simple_synchronous_entry.cc',
@@ -684,7 +686,6 @@
         'proxy/proxy_server_mac.cc',
         'proxy/proxy_service.cc',
         'proxy/proxy_service.h',
-        'quic/blocked_list.h',
         'quic/congestion_control/available_channel_estimator.cc',
         'quic/congestion_control/available_channel_estimator.h',
         'quic/congestion_control/channel_estimator.cc',
@@ -806,6 +807,8 @@
         'quic/quic_connection_helper.h',
         'quic/quic_connection_logger.cc',
         'quic/quic_connection_logger.h',
+        'quic/quic_connection_stats.cc',
+        'quic/quic_connection_stats.h',
         'quic/quic_data_reader.cc',
         'quic/quic_data_reader.h',
         'quic/quic_data_writer.cc',
@@ -834,8 +837,6 @@
         'quic/quic_spdy_compressor.h',
         'quic/quic_spdy_decompressor.cc',
         'quic/quic_spdy_decompressor.h',
-        'quic/quic_stats.cc',
-        'quic/quic_stats.h',
         'quic/quic_stream_factory.cc',
         'quic/quic_stream_factory.h',
         'quic/quic_stream_sequencer.cc',
@@ -963,6 +964,7 @@
         'spdy/spdy_websocket_stream.h',
         'spdy/spdy_write_queue.cc',
         'spdy/spdy_write_queue.h',
+        'spdy/write_blocked_list.h',
         'ssl/client_cert_store.h',
         'ssl/client_cert_store_impl.h',
         'ssl/client_cert_store_impl_mac.cc',
@@ -1631,6 +1633,7 @@
         'http/http_security_headers_unittest.cc',
         'http/http_server_properties_impl_unittest.cc',
         'http/http_status_code_unittest.cc',
+        'http/http_stream_factory_impl_request_unittest.cc',
         'http/http_stream_factory_impl_unittest.cc',
         'http/http_stream_parser_unittest.cc',
         'http/http_transaction_unittest.cc',
@@ -1666,7 +1669,6 @@
         'proxy/proxy_script_fetcher_impl_unittest.cc',
         'proxy/proxy_server_unittest.cc',
         'proxy/proxy_service_unittest.cc',
-        'quic/blocked_list_test.cc',
         'quic/congestion_control/available_channel_estimator_test.cc',
         'quic/congestion_control/channel_estimator_test.cc',
         'quic/congestion_control/cube_root_test.cc',
@@ -1818,6 +1820,7 @@
         'spdy/spdy_websocket_test_util.cc',
         'spdy/spdy_websocket_test_util.h',
         'spdy/spdy_write_queue_unittest.cc',
+        'spdy/write_blocked_list_test.cc',
         'ssl/client_cert_store_impl_unittest.cc',
         'ssl/default_server_bound_cert_store_unittest.cc',
         'ssl/openssl_client_key_store_unittest.cc',
@@ -1872,9 +1875,13 @@
           'sources': [
             'tools/flip_server/balsa_frame_test.cc',
             'tools/flip_server/balsa_headers_test.cc',
+            'tools/flip_server/flip_test_utils.cc',
+            'tools/flip_server/flip_test_utils.h',
+            'tools/flip_server/http_interface_test.cc',
             'tools/flip_server/mem_cache_test.cc',
             'tools/flip_server/simple_buffer.cc',
             'tools/flip_server/simple_buffer.h',
+            'tools/flip_server/spdy_interface_test.cc',
             'tools/quic/end_to_end_test.cc',
             'tools/quic/quic_client_session_test.cc',
             'tools/quic/quic_dispatcher_test.cc',
@@ -2133,11 +2140,6 @@
             '../testing/android/native_test.gyp:native_test_native_code',
           ]
         }],
-        [ 'OS != "win" and OS != "mac"', {
-          'sources!': [
-            'cert/x509_cert_types_unittest.cc',
-          ],
-        }],
       ],
     },
     {
diff --git a/net/net.target.darwin-arm.mk b/net/net.target.darwin-arm.mk
index 36ad05d..bce0d76 100644
--- a/net/net.target.darwin-arm.mk
+++ b/net/net.target.darwin-arm.mk
@@ -153,6 +153,7 @@
 	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
+	net/disk_cache/simple/simple_index_file_posix.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
 	net/disk_cache/simple/simple_synchronous_entry.cc \
 	net/disk_cache/simple/simple_util.cc \
@@ -319,6 +320,7 @@
 	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_data_reader.cc \
 	net/quic/quic_data_writer.cc \
 	net/quic/quic_fec_group.cc \
@@ -333,7 +335,6 @@
 	net/quic/quic_session.cc \
 	net/quic/quic_spdy_compressor.cc \
 	net/quic/quic_spdy_decompressor.cc \
-	net/quic/quic_stats.cc \
 	net/quic/quic_stream_factory.cc \
 	net/quic/quic_stream_sequencer.cc \
 	net/quic/quic_time.cc \
diff --git a/net/net.target.darwin-mips.mk b/net/net.target.darwin-mips.mk
index 203e38d..1425b90 100644
--- a/net/net.target.darwin-mips.mk
+++ b/net/net.target.darwin-mips.mk
@@ -153,6 +153,7 @@
 	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
+	net/disk_cache/simple/simple_index_file_posix.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
 	net/disk_cache/simple/simple_synchronous_entry.cc \
 	net/disk_cache/simple/simple_util.cc \
@@ -319,6 +320,7 @@
 	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_data_reader.cc \
 	net/quic/quic_data_writer.cc \
 	net/quic/quic_fec_group.cc \
@@ -333,7 +335,6 @@
 	net/quic/quic_session.cc \
 	net/quic/quic_spdy_compressor.cc \
 	net/quic/quic_spdy_decompressor.cc \
-	net/quic/quic_stats.cc \
 	net/quic/quic_stream_factory.cc \
 	net/quic/quic_stream_sequencer.cc \
 	net/quic/quic_time.cc \
diff --git a/net/net.target.darwin-x86.mk b/net/net.target.darwin-x86.mk
index e8410cd..28e8768 100644
--- a/net/net.target.darwin-x86.mk
+++ b/net/net.target.darwin-x86.mk
@@ -153,6 +153,7 @@
 	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
+	net/disk_cache/simple/simple_index_file_posix.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
 	net/disk_cache/simple/simple_synchronous_entry.cc \
 	net/disk_cache/simple/simple_util.cc \
@@ -319,6 +320,7 @@
 	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_data_reader.cc \
 	net/quic/quic_data_writer.cc \
 	net/quic/quic_fec_group.cc \
@@ -333,7 +335,6 @@
 	net/quic/quic_session.cc \
 	net/quic/quic_spdy_compressor.cc \
 	net/quic/quic_spdy_decompressor.cc \
-	net/quic/quic_stats.cc \
 	net/quic/quic_stream_factory.cc \
 	net/quic/quic_stream_sequencer.cc \
 	net/quic/quic_time.cc \
diff --git a/net/net.target.linux-arm.mk b/net/net.target.linux-arm.mk
index 36ad05d..bce0d76 100644
--- a/net/net.target.linux-arm.mk
+++ b/net/net.target.linux-arm.mk
@@ -153,6 +153,7 @@
 	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
+	net/disk_cache/simple/simple_index_file_posix.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
 	net/disk_cache/simple/simple_synchronous_entry.cc \
 	net/disk_cache/simple/simple_util.cc \
@@ -319,6 +320,7 @@
 	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_data_reader.cc \
 	net/quic/quic_data_writer.cc \
 	net/quic/quic_fec_group.cc \
@@ -333,7 +335,6 @@
 	net/quic/quic_session.cc \
 	net/quic/quic_spdy_compressor.cc \
 	net/quic/quic_spdy_decompressor.cc \
-	net/quic/quic_stats.cc \
 	net/quic/quic_stream_factory.cc \
 	net/quic/quic_stream_sequencer.cc \
 	net/quic/quic_time.cc \
diff --git a/net/net.target.linux-mips.mk b/net/net.target.linux-mips.mk
index 203e38d..1425b90 100644
--- a/net/net.target.linux-mips.mk
+++ b/net/net.target.linux-mips.mk
@@ -153,6 +153,7 @@
 	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
+	net/disk_cache/simple/simple_index_file_posix.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
 	net/disk_cache/simple/simple_synchronous_entry.cc \
 	net/disk_cache/simple/simple_util.cc \
@@ -319,6 +320,7 @@
 	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_data_reader.cc \
 	net/quic/quic_data_writer.cc \
 	net/quic/quic_fec_group.cc \
@@ -333,7 +335,6 @@
 	net/quic/quic_session.cc \
 	net/quic/quic_spdy_compressor.cc \
 	net/quic/quic_spdy_decompressor.cc \
-	net/quic/quic_stats.cc \
 	net/quic/quic_stream_factory.cc \
 	net/quic/quic_stream_sequencer.cc \
 	net/quic/quic_time.cc \
diff --git a/net/net.target.linux-x86.mk b/net/net.target.linux-x86.mk
index e8410cd..28e8768 100644
--- a/net/net.target.linux-x86.mk
+++ b/net/net.target.linux-x86.mk
@@ -153,6 +153,7 @@
 	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
+	net/disk_cache/simple/simple_index_file_posix.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
 	net/disk_cache/simple/simple_synchronous_entry.cc \
 	net/disk_cache/simple/simple_util.cc \
@@ -319,6 +320,7 @@
 	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_data_reader.cc \
 	net/quic/quic_data_writer.cc \
 	net/quic/quic_fec_group.cc \
@@ -333,7 +335,6 @@
 	net/quic/quic_session.cc \
 	net/quic/quic_spdy_compressor.cc \
 	net/quic/quic_spdy_decompressor.cc \
-	net/quic/quic_stats.cc \
 	net/quic/quic_stream_factory.cc \
 	net/quic/quic_stream_sequencer.cc \
 	net/quic/quic_time.cc \
diff --git a/net/net_unittests.isolate b/net/net_unittests.isolate
index 71a2dc0..9c88f77 100644
--- a/net/net_unittests.isolate
+++ b/net/net_unittests.isolate
@@ -34,14 +34,13 @@
       'variables': {
         'isolate_dependency_tracked': [
           '../testing/test_env.py',
-          '../tools/swarm_client/run_isolated.py',
-          '../tools/swarm_client/googletest/run_test_cases.py',
           '<(PRODUCT_DIR)/net_unittests<(EXECUTABLE_SUFFIX)',
         ],
         'isolate_dependency_untracked': [
           '../third_party/pyftpdlib/',
           '../third_party/pywebsocket/',
           '../third_party/tlslite/',
+          '../tools/swarm_client/',
           '<(PRODUCT_DIR)/pyproto/',
           'tools/testserver/',
         ],
diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc
index 4f6f5fc..dfea44a 100644
--- a/net/proxy/proxy_resolver_v8_tracing.cc
+++ b/net/proxy/proxy_resolver_v8_tracing.cc
@@ -849,6 +849,7 @@
   HostResolver::RequestHandle dns_request = NULL;
   int result = host_resolver()->Resolve(
       MakeDnsRequestInfo(pending_dns_host_, pending_dns_op_),
+      DEFAULT_PRIORITY,
       &pending_dns_addresses_,
       base::Bind(&Job::OnDnsOperationComplete, this),
       &dns_request,
diff --git a/net/proxy/proxy_resolver_v8_tracing_unittest.cc b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
index e597402..ff3ffd4 100644
--- a/net/proxy/proxy_resolver_v8_tracing_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_tracing_unittest.cc
@@ -764,6 +764,7 @@
       : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
 
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
diff --git a/net/proxy/proxy_script_fetcher_impl.cc b/net/proxy/proxy_script_fetcher_impl.cc
index 2bf9e66..f8925fa 100644
--- a/net/proxy/proxy_script_fetcher_impl.cc
+++ b/net/proxy/proxy_script_fetcher_impl.cc
@@ -211,7 +211,7 @@
   }
 
   // Require HTTP responses to have a success status code.
-  if (request->url().SchemeIs("http") || request->url().SchemeIs("https")) {
+  if (request->url().SchemeIsHTTPOrHTTPS()) {
     // NOTE about status codes: We are like Firefox 3 in this respect.
     // {IE 7, Safari 3, Opera 9.5} do not care about the status code.
     if (request->GetResponseCode() != 200) {
diff --git a/net/proxy/proxy_script_fetcher_impl_unittest.cc b/net/proxy/proxy_script_fetcher_impl_unittest.cc
index 8d42514..9c1ca98 100644
--- a/net/proxy/proxy_script_fetcher_impl_unittest.cc
+++ b/net/proxy/proxy_script_fetcher_impl_unittest.cc
@@ -71,7 +71,8 @@
     storage_.set_http_transaction_factory(new HttpCache(
         network_session.get(), HttpCache::DefaultBackend::InMemory(0)));
     URLRequestJobFactoryImpl* job_factory = new URLRequestJobFactoryImpl();
-    job_factory->SetProtocolHandler("file", new FileProtocolHandler());
+    job_factory->SetProtocolHandler(
+        "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
     storage_.set_job_factory(job_factory);
   }
 
diff --git a/net/quic/blocked_list.h b/net/quic/blocked_list.h
deleted file mode 100644
index 3a7f989..0000000
--- a/net/quic/blocked_list.h
+++ /dev/null
@@ -1,91 +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 combined list/hash set for read or write-blocked entities.
-
-#ifndef NET_QUIC_BLOCKED_LIST_H_
-#define NET_QUIC_BLOCKED_LIST_H_
-
-#include <list>
-
-#include "base/containers/hash_tables.h"
-#include "base/logging.h"
-
-namespace net {
-
-template <typename Object>
-class BlockedList {
- public:
-  // Called to add an object to the blocked list. This indicates
-  // the object should be notified when it can use the socket again.
-  //
-  // If this object is already on the list, it will not be added again.
-  void AddBlockedObject(Object object) {
-    // Only add the object to the list if we successfully add it to the set.
-    if (object_set_.insert(object).second) {
-      object_list_.push_back(object);
-    }
-  }
-
-  // Called to remove an object from a blocked list.  This should be
-  // called in the event the object is being deleted before the list is.
-  void RemoveBlockedObject(Object object) {
-    // Remove the object from the set.  We'll check the set before calling
-    // OnCanWrite on a object from the list.
-    //
-    // There is potentially ordering unfairness should a session be removed and
-    // then readded (as it keeps its position in the list) but it's not worth
-    // the overhead to walk the list and remove it.
-    object_set_.erase(object);
-  }
-
-  // Called when the socket is usable and some objects can access it.  Returns
-  // the first object and removes it from the list.
-  Object GetNextBlockedObject() {
-    DCHECK(!IsEmpty());
-
-    // Walk the list to find the first object which was not removed from the
-    // set.
-    while (!object_list_.empty()) {
-      Object object = *object_list_.begin();
-      object_list_.pop_front();
-      int removed = object_set_.erase(object);
-      if (removed > 0) {
-        return object;
-      }
-    }
-
-    // This is a bit of a hack: It's illegal to call GetNextBlockedObject() if
-    // the list is empty (see DCHECK above) but we must return something.  This
-    // compiles for ints (returns 0) and pointers in the case that someone has a
-    // bug in their call site.
-    return 0;
-  };
-
-  // Returns the number of objects in the blocked list.
-  int NumObjects() {
-    return object_set_.size();
-  };
-
-  // Returns true if there are no objects in the list, false otherwise.
-  bool IsEmpty() {
-    return object_set_.empty();
-  };
-
- private:
-  // A set tracking the objects. This is the authoritative container for
-  // determining if an object is blocked.   Objects in the list will always
-  // be in the set.
-  base::hash_set<Object> object_set_;
-  // A list tracking the order in which objects were added to the list.
-  // Objects are added to the back and pulled off the front, but only get
-  // resumption calls if they're still in the set.
-  // It's possible to be in the list twice, but only the first entry will get an
-  // OnCanWrite call.
-  std::list<Object> object_list_;
-};
-
-}  // namespace net
-
-#endif  // NET_QUIC_BLOCKED_LIST_H_
diff --git a/net/quic/blocked_list_test.cc b/net/quic/blocked_list_test.cc
deleted file mode 100644
index 074b6f5..0000000
--- a/net/quic/blocked_list_test.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 "net/quic/blocked_list.h"
-#include "net/quic/quic_connection.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(COMPILER_GCC)
-namespace BASE_HASH_NAMESPACE {
-template<>
-struct hash<const int*> {
-  std::size_t operator()(const int* ptr) const {
-    return hash<size_t>()(reinterpret_cast<size_t>(ptr));
-  }
-};
-}
-#endif
-
-namespace net {
-namespace test {
-namespace {
-
-class BlockedListTest : public ::testing::Test {
- protected:
-  BlockedListTest() :
-      item1_(0),
-      item2_(0),
-      item3_(0) {
-  }
-
-  BlockedList<const int*> list_;
-  const int item1_;
-  const int item2_;
-  const int item3_;
-};
-
-TEST_F(BlockedListTest, BasicAdd) {
-  list_.AddBlockedObject(&item1_);
-  list_.AddBlockedObject(&item3_);
-  list_.AddBlockedObject(&item2_);
-  ASSERT_EQ(3, list_.NumObjects());
-  ASSERT_FALSE(list_.IsEmpty());
-
-  EXPECT_EQ(&item1_, list_.GetNextBlockedObject());
-  EXPECT_EQ(&item3_, list_.GetNextBlockedObject());
-  EXPECT_EQ(&item2_, list_.GetNextBlockedObject());
-}
-
-TEST_F(BlockedListTest, AddAndRemove) {
-  list_.AddBlockedObject(&item1_);
-  list_.AddBlockedObject(&item3_);
-  list_.AddBlockedObject(&item2_);
-  ASSERT_EQ(3, list_.NumObjects());
-
-  list_.RemoveBlockedObject(&item3_);
-  ASSERT_EQ(2, list_.NumObjects());
-
-  EXPECT_EQ(&item1_, list_.GetNextBlockedObject());
-  EXPECT_EQ(&item2_, list_.GetNextBlockedObject());
-}
-
-TEST_F(BlockedListTest, DuplicateAdd) {
-  list_.AddBlockedObject(&item1_);
-  list_.AddBlockedObject(&item3_);
-  list_.AddBlockedObject(&item2_);
-
-  list_.AddBlockedObject(&item3_);
-  list_.AddBlockedObject(&item2_);
-  list_.AddBlockedObject(&item1_);
-
-  ASSERT_EQ(3, list_.NumObjects());
-  ASSERT_FALSE(list_.IsEmpty());
-
-  // Call in the original insert order.
-  EXPECT_EQ(&item1_, list_.GetNextBlockedObject());
-  EXPECT_EQ(&item3_, list_.GetNextBlockedObject());
-  EXPECT_EQ(&item2_, list_.GetNextBlockedObject());
-}
-
-}  // namespace
-}  // namespace test
-}  // namespace net
diff --git a/net/quic/congestion_control/fix_rate_sender.cc b/net/quic/congestion_control/fix_rate_sender.cc
index dff52cf..22f759f 100644
--- a/net/quic/congestion_control/fix_rate_sender.cc
+++ b/net/quic/congestion_control/fix_rate_sender.cc
@@ -80,7 +80,7 @@
     QuicTime now,
     Retransmission /*is_retransmission*/,
     HasRetransmittableData /*has_retransmittable_data*/,
-    IsHandshake /* handshake */) {
+    IsHandshake /*handshake*/) {
   if (CongestionWindow() > fix_rate_leaky_bucket_.BytesPending(now)) {
     if (CongestionWindow() <= data_in_flight_) {
       // We need an ack before we send more.
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index 8968dc9..eee96ad 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -104,9 +104,4 @@
   return false;
 }
 
-QuicTime::Delta HybridSlowStart::SmoothedRtt() {
-  // TODO(satyamshekhar): Calculate and return smooth average of rtt over time.
-  return current_rtt_;
-}
-
 }  // namespace net
diff --git a/net/quic/congestion_control/hybrid_slow_start.h b/net/quic/congestion_control/hybrid_slow_start.h
index b0e4248..cee9c73 100644
--- a/net/quic/congestion_control/hybrid_slow_start.h
+++ b/net/quic/congestion_control/hybrid_slow_start.h
@@ -46,8 +46,6 @@
 
   bool started() { return started_; }
 
-  QuicTime::Delta SmoothedRtt();
-
  private:
   const QuicClock* clock_;
   bool started_;
diff --git a/net/quic/congestion_control/inter_arrival_overuse_detector.cc b/net/quic/congestion_control/inter_arrival_overuse_detector.cc
index 73e005d..ea1c3af 100644
--- a/net/quic/congestion_control/inter_arrival_overuse_detector.cc
+++ b/net/quic/congestion_control/inter_arrival_overuse_detector.cc
@@ -16,10 +16,6 @@
 // Threshold for accumulated delta.
 static const int kThresholdAccumulatedDeltasUs = 1000;
 
-// The higher the beta parameter, the lower is the effect of the input and the
-// more damping of the noise. And the longer time for a detection.
-static const float kBeta = 0.98f;
-
 // Same as above, described as numerator and denominator.
 static const int kBetaNumerator = 49;
 static const int kBetaDenominator = 50;
diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc
index 1aa7ab9..3afa378 100644
--- a/net/quic/congestion_control/inter_arrival_sender.cc
+++ b/net/quic/congestion_control/inter_arrival_sender.cc
@@ -258,7 +258,7 @@
     QuicTime now,
     Retransmission /*retransmit*/,
     HasRetransmittableData has_retransmittable_data,
-    IsHandshake /* handshake */) {
+    IsHandshake /*handshake*/) {
   // TODO(pwestin): implement outer_congestion_window_ logic.
   QuicTime::Delta outer_window = QuicTime::Delta::Zero();
 
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 1e98c12..438dbe9 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -195,7 +195,7 @@
     }
     // congestion_window_cnt is the number of acks since last change of snd_cwnd
     if (congestion_window_ < max_tcp_congestion_window_) {
-      // TCP slow start, exponentail growth, increase by one for each ACK.
+      // TCP slow start, exponential growth, increase by one for each ACK.
       congestion_window_++;
     }
     DLOG(INFO) << "Slow start; congestion window:" << congestion_window_;
@@ -211,8 +211,9 @@
         }
         DLOG(INFO) << "Reno; congestion window:" << congestion_window_;
       } else {
-        congestion_window_ = cubic_.CongestionWindowAfterAck(congestion_window_,
-                                                             delay_min_);
+        congestion_window_ = std::min(
+            max_tcp_congestion_window_,
+            cubic_.CongestionWindowAfterAck(congestion_window_, delay_min_));
         DLOG(INFO) << "Cubic; congestion window:" << congestion_window_;
       }
     }
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index c22813a..8cea0aa 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// TCP cubic send side congestion algorithm, emulates the behaviour of
+// TCP cubic send side congestion algorithm, emulates the behavior of
 // TCP cubic.
 
 #ifndef NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_H_
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index e9f8893..fb67fcd 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -13,13 +13,15 @@
 namespace test {
 
 const uint32 kDefaultWindowTCP = 10 * kMaxPacketSize;
-const QuicByteCount kNoNBytesInFlight = 0;
+// TODO(ianswett): Remove 10000 once b/10075719 is fixed.
+const QuicTcpCongestionWindow kDefaultMaxCongestionWindowTCP = 10000;
 
 class TcpCubicSenderPeer : public TcpCubicSender {
  public:
-  // TODO(ianswett): Remove 10000 once b/10075719 is fixed.
-  TcpCubicSenderPeer(const QuicClock* clock, bool reno)
-      : TcpCubicSender(clock, reno, 10000) {
+  TcpCubicSenderPeer(const QuicClock* clock,
+                     bool reno,
+                     QuicTcpCongestionWindow max_tcp_congestion_window)
+      : TcpCubicSender(clock, reno, max_tcp_congestion_window) {
   }
   using TcpCubicSender::AvailableCongestionWindow;
   using TcpCubicSender::CongestionWindow;
@@ -29,12 +31,13 @@
 class TcpCubicSenderTest : public ::testing::Test {
  protected:
   TcpCubicSenderTest()
-     : rtt_(QuicTime::Delta::FromMilliseconds(60)),
-       one_ms_(QuicTime::Delta::FromMilliseconds(1)),
-       sender_(new TcpCubicSenderPeer(&clock_, true)),
-       receiver_(new TcpReceiver()),
-       sequence_number_(1),
-       acked_sequence_number_(0) {
+      : rtt_(QuicTime::Delta::FromMilliseconds(60)),
+        one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+        sender_(new TcpCubicSenderPeer(&clock_, true,
+                                       kDefaultMaxCongestionWindowTCP)),
+        receiver_(new TcpReceiver()),
+        sequence_number_(1),
+        acked_sequence_number_(0) {
   }
 
   void SendAvailableCongestionWindow() {
@@ -87,7 +90,7 @@
   // And that window is un-affected.
   EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableCongestionWindow());
 
-  // A retransmitt should always retun 0.
+  // A retransmit should always return 0.
   EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
       IS_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
 }
@@ -200,7 +203,7 @@
   EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
 
   // Testing Reno phase.
-  // We need to ack half of the pending packet before we can send agin.
+  // We need to ack half of the pending packet before we can send again.
   int number_of_packets_in_window = expected_congestion_window / kMaxPacketSize;
   AckNPackets(number_of_packets_in_window);
   EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
@@ -232,8 +235,8 @@
   sender_->AckAccounting(QuicTime::Delta::FromMilliseconds(kRttMs));
 
   // Initial value is to set the median deviation to half of the initial
-  // rtt, the median in then multiplied by a factor of 4 and finaly the
-  // smoothed rtt is added which is the inital rtt.
+  // rtt, the median in then multiplied by a factor of 4 and finally the
+  // smoothed rtt is added which is the initial rtt.
   QuicTime::Delta expected_delay =
       QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4);
   EXPECT_EQ(expected_delay, sender_->RetransmissionDelay());
@@ -252,5 +255,102 @@
               sender_->RetransmissionDelay().ToMilliseconds(),
               1);
 }
+
+TEST_F(TcpCubicSenderTest, SlowStartMaxCongestionWindow) {
+  const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50;
+  const int kNumberOfAck = 100;
+  sender_.reset(
+      new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP));
+
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+      NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
+  // Get default QuicCongestionFeedbackFrame from receiver.
+  ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
+  sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
+                                                 not_used_);
+  // Make sure we can send.
+  EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+      NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
+
+  for (int i = 0; i < kNumberOfAck; ++i) {
+    // Send our full congestion window.
+    SendAvailableCongestionWindow();
+    AckNPackets(2);
+  }
+  QuicByteCount expected_congestion_window =
+      kMaxCongestionWindowTCP * kMaxPacketSize;
+  EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
+}
+
+TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) {
+  const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50;
+  const int kNumberOfAck = 1000;
+  sender_.reset(
+      new TcpCubicSenderPeer(&clock_, true, kMaxCongestionWindowTCP));
+
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+      NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
+  // Get default QuicCongestionFeedbackFrame from receiver.
+  ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
+  sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
+                                                 not_used_);
+  // Make sure we can send.
+  EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+      NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
+
+  SendAvailableCongestionWindow();
+  AckNPackets(2);
+  // Make sure we fall out of slow start.
+  sender_->OnIncomingLoss(clock_.Now());
+
+  for (int i = 0; i < kNumberOfAck; ++i) {
+    // Send our full congestion window.
+    SendAvailableCongestionWindow();
+    AckNPackets(2);
+  }
+
+  QuicByteCount expected_congestion_window =
+      kMaxCongestionWindowTCP * kMaxPacketSize;
+  EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
+}
+
+TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) {
+  const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50;
+  const int kNumberOfAck = 1000;
+  sender_.reset(
+      new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP));
+
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+      NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
+  // Get default QuicCongestionFeedbackFrame from receiver.
+  ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
+  sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
+                                                 not_used_);
+  // Make sure we can send.
+  EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
+      NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
+
+  SendAvailableCongestionWindow();
+  AckNPackets(2);
+  // Make sure we fall out of slow start.
+  sender_->OnIncomingLoss(clock_.Now());
+
+  for (int i = 0; i < kNumberOfAck; ++i) {
+    // Send our full congestion window.
+    SendAvailableCongestionWindow();
+    AckNPackets(2);
+  }
+
+  QuicByteCount expected_congestion_window =
+      kMaxCongestionWindowTCP * kMaxPacketSize;
+  EXPECT_EQ(expected_congestion_window, sender_->CongestionWindow());
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h
index b070c66..ea69f3a 100644
--- a/net/quic/crypto/crypto_framer.h
+++ b/net/quic/crypto/crypto_framer.h
@@ -84,8 +84,6 @@
                           size_t pad_length,
                           uint32* end_offset);
 
-  void set_error(QuicErrorCode error) { error_ = error; }
-
   // Represents the current state of the parsing state machine.
   enum CryptoFramerState {
     STATE_READING_TAG,
diff --git a/net/quic/crypto/crypto_handshake.cc b/net/quic/crypto/crypto_handshake.cc
index d6a76f9..1a30f43 100644
--- a/net/quic/crypto/crypto_handshake.cc
+++ b/net/quic/crypto/crypto_handshake.cc
@@ -84,11 +84,6 @@
   serialized_.reset();
 }
 
-void CryptoHandshakeMessage::Insert(QuicTagValueMap::const_iterator begin,
-                                    QuicTagValueMap::const_iterator end) {
-  tag_value_map_.insert(begin, end);
-}
-
 void CryptoHandshakeMessage::SetTaglist(QuicTag tag, ...) {
   // Warning, if sizeof(QuicTag) > sizeof(int) then this function will break
   // because the terminating 0 will only be promoted to int.
@@ -326,8 +321,7 @@
 }
 
 QuicCryptoNegotiatedParameters::QuicCryptoNegotiatedParameters()
-    : version(0),
-      key_exchange(0),
+    : key_exchange(0),
       aead(0) {
 }
 
@@ -470,6 +464,12 @@
   server_config_sig_ = signature.as_string();
 }
 
+void QuicCryptoClientConfig::CachedState::ClearProof() {
+  SetProofInvalid();
+  certs_.clear();
+  server_config_sig_.clear();
+}
+
 void QuicCryptoClientConfig::CachedState::SetProofValid() {
   server_config_valid_ = true;
 }
@@ -822,8 +822,9 @@
   }
 
   StringPiece proof, cert_bytes;
-  if (rej.GetStringPiece(kPROF, &proof) &&
-      rej.GetStringPiece(kCertificateTag, &cert_bytes)) {
+  bool has_proof = rej.GetStringPiece(kPROF, &proof);
+  bool has_cert = rej.GetStringPiece(kCertificateTag, &cert_bytes);
+  if (has_proof && has_cert) {
     vector<string> certs;
     if (!CertCompressor::DecompressChain(cert_bytes, out_params->cached_certs,
                                          common_cert_sets, &certs)) {
@@ -832,6 +833,17 @@
     }
 
     cached->SetProof(certs, proof);
+  } else {
+    cached->ClearProof();
+    if (has_proof && !has_cert) {
+      *error_details = "Certificate missing";
+      return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+    }
+
+    if (!has_proof && has_cert) {
+      *error_details = "Proof missing";
+      return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+    }
   }
 
   return QUIC_NO_ERROR;
diff --git a/net/quic/crypto/crypto_handshake.h b/net/quic/crypto/crypto_handshake.h
index fdc92a0..e2fd38b 100644
--- a/net/quic/crypto/crypto_handshake.h
+++ b/net/quic/crypto/crypto_handshake.h
@@ -73,9 +73,6 @@
 
   const QuicTagValueMap& tag_value_map() const { return tag_value_map_; }
 
-  void Insert(QuicTagValueMap::const_iterator begin,
-              QuicTagValueMap::const_iterator end);
-
   // SetTaglist sets an element with the given tag to contain a list of tags,
   // passed as varargs. The argument list must be terminated with a 0 element.
   void SetTaglist(QuicTag tag, ...);
@@ -160,7 +157,6 @@
   QuicCryptoNegotiatedParameters();
   ~QuicCryptoNegotiatedParameters();
 
-  uint16 version;
   QuicTag key_exchange;
   QuicTag aead;
   std::string initial_premaster_secret;
@@ -266,6 +262,9 @@
     void SetProof(const std::vector<std::string>& certs,
                   base::StringPiece signature);
 
+    // Clears the certificate chain and signature and invalidates the proof.
+    void ClearProof();
+
     // SetProofValid records that the certificate chain and signature have been
     // validated and that it's safe to assume that the server is legitimate.
     // (Note: this does not check the chain or signature.)
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index 586569a..4580fce 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -59,7 +59,6 @@
 // Client hello tags
 const QuicTag kVERS = TAG('V', 'E', 'R', 'S');  // Version
 const QuicTag kNONC = TAG('N', 'O', 'N', 'C');  // The client's nonce
-const QuicTag kSSID = TAG('S', 'S', 'I', 'D');  // Session ID
 const QuicTag kKEXS = TAG('K', 'E', 'X', 'S');  // Key exchange methods
 const QuicTag kAEAD = TAG('A', 'E', 'A', 'D');  // Authenticated
                                                 // encryption algorithms
diff --git a/net/quic/crypto/strike_register.cc b/net/quic/crypto/strike_register.cc
index 97aca18..f45bfab 100644
--- a/net/quic/crypto/strike_register.cc
+++ b/net/quic/crypto/strike_register.cc
@@ -56,8 +56,8 @@
 };
 
 // kCreationTimeFromInternalEpoch contains the number of seconds between the
-// start of the internal epoch and |creation_time_external_|. This allows us
-// to consider times that are before |creation_time_external_|.
+// start of the internal epoch and the creation time. This allows us
+// to consider times that are before the creation time.
 static const uint32 kCreationTimeFromInternalEpoch = 63115200.0;  // 2 years.
 
 StrikeRegister::StrikeRegister(unsigned max_entries,
@@ -67,22 +67,17 @@
                                StartupType startup)
     : max_entries_(max_entries),
       window_secs_(window_secs),
+      internal_epoch_(current_time > kCreationTimeFromInternalEpoch
+                          ? current_time - kCreationTimeFromInternalEpoch
+                          : 0),
       // The horizon is initially set |window_secs| into the future because, if
       // we just crashed, then we may have accepted nonces in the span
       // [current_time...current_time+window_secs) and so we conservatively
       // reject the whole timespan unless |startup| tells us otherwise.
-      creation_time_external_(current_time),
-      internal_epoch_(current_time > kCreationTimeFromInternalEpoch
-                          ? current_time - kCreationTimeFromInternalEpoch
-                          : 0),
       horizon_(ExternalTimeToInternal(current_time) + window_secs),
       horizon_valid_(startup == DENY_REQUESTS_AT_STARTUP) {
   memcpy(orbit_, orbit, sizeof(orbit_));
 
-  // TODO(rtenneti): Remove the following check, Added the following to silence
-  // "is not used" error.
-  CHECK_GE(creation_time_external_, 0u);
-
   // We only have 23 bits of index available.
   CHECK_LT(max_entries, 1u << 23);
   CHECK_GT(max_entries, 1u);           // There must be at least two entries.
diff --git a/net/quic/crypto/strike_register.h b/net/quic/crypto/strike_register.h
index 98bc04c..fda62a8 100644
--- a/net/quic/crypto/strike_register.h
+++ b/net/quic/crypto/strike_register.h
@@ -129,7 +129,7 @@
   static uint32 TimeFromBytes(const uint8 d[4]);
 
   // ExternalTimeToInternal converts an external time value into an internal
-  // time value using |creation_time_external_|.
+  // time value using |internal_epoch_|.
   uint32 ExternalTimeToInternal(uint32 external_time);
 
   // BestMatch returns either kNil, or an external node index which could
@@ -164,10 +164,6 @@
 
   const uint32 max_entries_;
   const uint32 window_secs_;
-  // creation_time_external_ contains the uint32, external time when this
-  // object was created (i.e. the value passed to the constructor). This is
-  // used to translate external times to internal times.
-  const uint32 creation_time_external_;
   // internal_epoch_ contains the external time value of the start of internal
   // time.
   const uint32 internal_epoch_;
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index d7fb0d2..ac51eab 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -81,7 +81,7 @@
 
 QuicClientSession::QuicClientSession(
     QuicConnection* connection,
-    DatagramClientSocket* socket,
+    scoped_ptr<DatagramClientSocket> socket,
     QuicStreamFactory* stream_factory,
     QuicCryptoClientStreamFactory* crypto_client_stream_factory,
     const string& server_hostname,
@@ -89,14 +89,15 @@
     QuicCryptoClientConfig* crypto_config,
     NetLog* net_log)
     : QuicSession(connection, config, false),
-      weak_factory_(this),
+      require_confirmation_(false),
       stream_factory_(stream_factory),
-      socket_(socket),
+      socket_(socket.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_) {
+      logger_(net_log_),
+      weak_factory_(this) {
   crypto_stream_.reset(
       crypto_client_stream_factory ?
           crypto_client_stream_factory->CreateQuicCryptoClientStream(
@@ -209,7 +210,9 @@
   return crypto_stream_->GetSSLInfo(ssl_info);
 }
 
-int QuicClientSession::CryptoConnect(const CompletionCallback& callback) {
+int QuicClientSession::CryptoConnect(bool require_confirmation,
+                                     const CompletionCallback& callback) {
+  require_confirmation_ = require_confirmation;
   RecordHandshakeState(STATE_STARTED);
   if (!crypto_stream_->CryptoConnect()) {
     // TODO(wtc): change crypto_stream_.CryptoConnect() to return a
@@ -217,7 +220,9 @@
     return ERR_CONNECTION_FAILED;
   }
 
-  if (IsEncryptionEstablished()) {
+  bool can_notify = require_confirmation_ ?
+      IsCryptoHandshakeConfirmed() : IsEncryptionEstablished();
+  if (can_notify) {
     return OK;
   }
 
@@ -250,7 +255,8 @@
 }
 
 void QuicClientSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) {
-  if (!callback_.is_null()) {
+  if (!callback_.is_null() &&
+      (!require_confirmation_ || event == HANDSHAKE_CONFIRMED)) {
     // TODO(rtenneti): Currently for all CryptoHandshakeEvent events, callback_
     // could be called because there are no error events in CryptoHandshakeEvent
     // enum. If error events are added to CryptoHandshakeEvent, then the
@@ -260,9 +266,25 @@
   QuicSession::OnCryptoHandshakeEvent(event);
 }
 
+void QuicClientSession::OnCryptoHandshakeMessageSent(
+    const CryptoHandshakeMessage& message) {
+  logger_.OnCryptoHandshakeMessageSent(message);
+}
+
+void QuicClientSession::OnCryptoHandshakeMessageReceived(
+    const CryptoHandshakeMessage& message) {
+  logger_.OnCryptoHandshakeMessageReceived(message);
+}
+
 void QuicClientSession::ConnectionClose(QuicErrorCode error, bool from_peer) {
-  UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.ConnectionCloseErrorCode",
-                              error);
+  logger_.OnConnectionClose(error, from_peer);
+  if (from_peer) {
+    UMA_HISTOGRAM_SPARSE_SLOWLY(
+        "Net.QuicSession.ConnectionCloseErrorCodeServer", error);
+  } else {
+    UMA_HISTOGRAM_SPARSE_SLOWLY(
+        "Net.QuicSession.ConnectionCloseErrorCodeClient", error);
+  }
   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.QuicVersion",
                               connection()->version());
   if (!callback_.is_null()) {
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 339c40b..bdfaf2f 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -13,6 +13,7 @@
 #include <string>
 
 #include "base/containers/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
 #include "net/base/completion_callback.h"
 #include "net/quic/quic_connection_logger.h"
 #include "net/quic/quic_crypto_client_stream.h"
@@ -74,7 +75,7 @@
   // not |stream_factory|, which must outlive this session.
   // TODO(rch): decouple the factory from the session via a Delegate interface.
   QuicClientSession(QuicConnection* connection,
-                    DatagramClientSocket* socket,
+                    scoped_ptr<DatagramClientSocket> socket,
                     QuicStreamFactory* stream_factory,
                     QuicCryptoClientStreamFactory* crypto_client_stream_factory,
                     const std::string& server_hostname,
@@ -102,13 +103,18 @@
   virtual QuicCryptoClientStream* GetCryptoStream() OVERRIDE;
   virtual void CloseStream(QuicStreamId stream_id) OVERRIDE;
   virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) OVERRIDE;
+  virtual void OnCryptoHandshakeMessageSent(
+      const CryptoHandshakeMessage& message) OVERRIDE;
+  virtual void OnCryptoHandshakeMessageReceived(
+      const CryptoHandshakeMessage& message) OVERRIDE;
   virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE;
 
   // QuicConnectionVisitorInterface methods:
   virtual void ConnectionClose(QuicErrorCode error, bool from_peer) OVERRIDE;
 
   // Performs a crypto handshake with the server.
-  int CryptoConnect(const CompletionCallback& callback);
+  int CryptoConnect(bool require_confirmation,
+                    const CompletionCallback& callback);
 
   // Causes the QuicConnectionHelper to start reading from the socket
   // and passing the data along to the QuicConnection.
@@ -147,7 +153,7 @@
   // delete |this|.
   void NotifyFactoryOfSessionClose();
 
-  base::WeakPtrFactory<QuicClientSession> weak_factory_;
+  bool require_confirmation_;
   scoped_ptr<QuicCryptoClientStream> crypto_stream_;
   QuicStreamFactory* stream_factory_;
   scoped_ptr<DatagramClientSocket> socket_;
@@ -158,6 +164,7 @@
   size_t num_total_streams_;
   BoundNetLog net_log_;
   QuicConnectionLogger logger_;
+  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 6113f45..385be52 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -15,6 +15,7 @@
 #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"
+#include "net/udp/datagram_client_socket.h"
 
 using testing::_;
 
@@ -29,15 +30,16 @@
   QuicClientSessionTest()
       : guid_(1),
         connection_(new PacketSavingConnection(guid_, IPEndPoint(), false)),
-        session_(connection_, NULL, NULL, NULL, kServerHostname,
-                 DefaultQuicConfig(), &crypto_config_, &net_log_) {
+        session_(connection_, scoped_ptr<DatagramClientSocket>(), NULL,
+                 NULL, kServerHostname, DefaultQuicConfig(), &crypto_config_,
+                 &net_log_) {
     session_.config()->SetDefaults();
     crypto_config_.SetDefaults();
   }
 
   void CompleteCryptoHandshake() {
     ASSERT_EQ(ERR_IO_PENDING,
-              session_.CryptoConnect(callback_.callback()));
+              session_.CryptoConnect(false, callback_.callback()));
     CryptoTestUtils::HandshakeWithFakeServer(
         connection_, session_.GetCryptoStream());
     ASSERT_EQ(OK, callback_.WaitForResult());
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index fefeba9..0f3caf9 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -40,11 +40,6 @@
 // at least 3 sequence numbers larger arrives.
 const size_t kNumberOfNacksBeforeRetransmission = 3;
 
-// The maxiumum number of packets we'd like to queue.  We may end up queueing
-// more in the case of many control frames.
-// 6 is arbitrary.
-const int kMaxPacketsToSerializeAtOnce = 6;
-
 // Limit the number of packets we send per retransmission-alarm so we
 // eventually cede.  10 is arbitrary.
 const size_t kMaxPacketsPerRetransmissionAlarm = 10;
@@ -516,7 +511,7 @@
       incoming_ack.received_info.largest_observed) {
     DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
                 << *incoming_ack.received_info.missing_packets.rbegin()
-                << " greater than largest observed: "
+                << " which is greater than largest observed: "
                 << incoming_ack.received_info.largest_observed;
     return false;
   }
@@ -526,7 +521,7 @@
       received_packet_manager_.least_packet_awaited_by_peer()) {
     DLOG(ERROR) << ENDPOINT << "Peer sent missing packet: "
                 << *incoming_ack.received_info.missing_packets.begin()
-                << "smaller than least_packet_awaited_by_peer_: "
+                << " which is smaller than least_packet_awaited_by_peer_: "
                 << received_packet_manager_.least_packet_awaited_by_peer();
     return false;
   }
@@ -750,8 +745,21 @@
 
 void QuicConnection::MaybeSendInResponseToPacket(
     bool last_packet_should_instigate_ack) {
-  // TODO(ianswett): Better merge these two blocks to queue up an ack if
-  // necessary, then either only send the ack or bundle it with other data.
+  packet_generator_.StartBatchOperations();
+
+  if (last_packet_should_instigate_ack) {
+    if (send_ack_in_response_to_packet_) {
+      SendAck();
+    } else if (last_packet_should_instigate_ack) {
+      // Set the ack alarm for when any retransmittable frame is received.
+      if (!ack_alarm_->IsSet()) {
+        ack_alarm_->Set(clock_->ApproximateNow().Add(
+            congestion_manager_.DefaultRetransmissionTime()));
+      }
+    }
+    send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_;
+  }
+
   if (!last_ack_frames_.empty()) {
     // Now the we have received an ack, we might be able to send packets which
     // are queued locally, or drain streams which are blocked.
@@ -766,22 +774,7 @@
       send_alarm_->Set(time_of_last_received_packet_.Add(delay));
     }
   }
-
-  if (!last_packet_should_instigate_ack) {
-    return;
-  }
-
-  if (send_ack_in_response_to_packet_) {
-    SendAck();
-  } else if (!last_stream_frames_.empty()) {
-    // TODO(alyssar) this case should really be "if the packet contained any
-    // non-ack frame", rather than "if the packet contained a stream frame"
-    if (!ack_alarm_->IsSet()) {
-      ack_alarm_->Set(clock_->ApproximateNow().Add(
-          congestion_manager_.DefaultRetransmissionTime()));
-    }
-  }
-  send_ack_in_response_to_packet_ = !send_ack_in_response_to_packet_;
+  packet_generator_.FinishBatchOperations();
 }
 
 void QuicConnection::SendVersionNegotiationPacket() {
@@ -801,7 +794,22 @@
                                                 StringPiece data,
                                                 QuicStreamOffset offset,
                                                 bool fin) {
-  return packet_generator_.ConsumeData(id, data, offset, fin);
+  // To make reasoning about crypto frames easier, we don't combine them with
+  // any other frames in a single packet.
+  const bool crypto_frame_while_batch_mode =
+      id == kCryptoStreamId && packet_generator_.InBatchMode();
+
+  if (crypto_frame_while_batch_mode) {
+    // Flush pending frames to make room for a crypto frame.
+    packet_generator_.FinishBatchOperations();
+  }
+  QuicConsumedData consumed_data =
+      packet_generator_.ConsumeData(id, data, offset, fin);
+  if (crypto_frame_while_batch_mode) {
+    // Restore batch mode.
+    packet_generator_.StartBatchOperations();
+  }
+  return consumed_data;
 }
 
 void QuicConnection::SendRstStream(QuicStreamId id,
@@ -878,18 +886,35 @@
   DCHECK(!write_blocked_);
   WriteQueuedPackets();
 
+  // We are postulating if we are not yet forward secure, the visitor may have
+  // handshake messages to send.
+  // TODO(jar): add a new visitor_ method that returns whether it has handshake
+  // messages to send, and call it and pass the return value to each CanWrite
+  // call.
+  const IsHandshake maybe_handshake =
+      encryption_level_ == ENCRYPTION_FORWARD_SECURE ? NOT_HANDSHAKE
+                                                     : IS_HANDSHAKE;
+
   // Sending queued packets may have caused the socket to become write blocked,
   // or the congestion manager to prohibit sending.  If we've sent everything
   // we had queued and we're still not blocked, let the visitor know it can
   // write more.
   if (CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
-               NOT_HANDSHAKE)) {
-    packet_generator_.StartBatchOperations();
+               maybe_handshake)) {
+    const bool in_batch_mode = packet_generator_.InBatchMode();
+    if (!in_batch_mode) {
+      packet_generator_.StartBatchOperations();
+    }
     bool all_bytes_written = visitor_->OnCanWrite();
-    packet_generator_.FinishBatchOperations();
+    if (!in_batch_mode) {
+      packet_generator_.FinishBatchOperations();
+    }
 
     // After the visitor writes, it may have caused the socket to become write
     // blocked or the congestion manager to prohibit sending, so check again.
+    // TODO(jar): we need to pass NOT_HANDSHAKE instead of maybe_handshake to
+    // this CanWrite call to avoid getting into an infinite loop calling
+    // DoWrite.
     if (!write_blocked_ && !all_bytes_written &&
         CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
                  NOT_HANDSHAKE)) {
@@ -1019,9 +1044,15 @@
 
   // Re-packetize the frames with a new sequence number for retransmission.
   // Retransmitted data packets do not use FEC, even when it's enabled.
+  // Retransmitted packets use the same sequence number length as the original.
+  QuicSequenceNumberLength original_sequence_number_length =
+      retransmission_it->second.sequence_number_length;
   SerializedPacket serialized_packet =
-      packet_creator_.SerializeAllFrames(unacked->frames());
-  RetransmissionInfo retransmission_info(serialized_packet.sequence_number);
+      packet_creator_.ReserializeAllFrames(unacked->frames(),
+                                           original_sequence_number_length);
+  RetransmissionInfo retransmission_info(
+      serialized_packet.sequence_number,
+      serialized_packet.sequence_number_length);
   retransmission_info.number_retransmissions =
       retransmission_it->second.number_retransmissions + 1;
   // Remove info with old sequence number.
@@ -1035,6 +1066,10 @@
                                     unacked));
   retransmission_map_.insert(make_pair(serialized_packet.sequence_number,
                                        retransmission_info));
+  if (debug_visitor_) {
+    debug_visitor_->OnPacketRetransmitted(sequence_number,
+                                          serialized_packet.sequence_number);
+  }
   SendOrQueuePacket(unacked->encryption_level(),
                     serialized_packet.sequence_number,
                     serialized_packet.packet,
@@ -1163,6 +1198,10 @@
 
   Retransmission retransmission = IsRetransmission(sequence_number) ?
       IS_RETRANSMISSION : NOT_RETRANSMISSION;
+  // 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;
 
@@ -1221,6 +1260,11 @@
     SetupAbandonFecTimer(sequence_number);
   }
 
+  // TODO(ianswett): Change the sequence number length and other packet creator
+  // options by a more explicit API than setting a struct value directly.
+  packet_creator_.options()->send_sequence_number_length =
+      CalculateSequenceNumberLength(sequence_number);
+
   congestion_manager_.SentPacket(sequence_number, now, packet->length(),
                                  retransmission);
 
@@ -1250,6 +1294,31 @@
   return bytes_written;
 }
 
+QuicSequenceNumberLength QuicConnection::CalculateSequenceNumberLength(
+      QuicPacketSequenceNumber sequence_number) {
+  DCHECK_LE(received_packet_manager_.least_packet_awaited_by_peer(),
+            sequence_number);
+  // Since the packet creator will not change sequence number length mid FEC
+  // group, include the size of an FEC group to be safe.
+  const QuicPacketSequenceNumber current_delta =
+      packet_creator_.options()->max_packets_per_fec_group + sequence_number
+      - received_packet_manager_.least_packet_awaited_by_peer();
+  const uint64 congestion_window =
+      congestion_manager_.BandwidthEstimate().ToBytesPerPeriod(
+          congestion_manager_.SmoothedRtt()) /
+          packet_creator_.options()->max_packet_length;
+  const uint64 delta = max(current_delta, congestion_window);
+
+  if (delta < 1 << ((PACKET_1BYTE_SEQUENCE_NUMBER * 8) - 2)) {
+    return PACKET_1BYTE_SEQUENCE_NUMBER;
+  } else if (delta < 1 << ((PACKET_2BYTE_SEQUENCE_NUMBER * 8) - 2)) {
+    return PACKET_2BYTE_SEQUENCE_NUMBER;
+  } else if (delta < 1 << ((PACKET_4BYTE_SEQUENCE_NUMBER * 8) - 2)) {
+    return PACKET_4BYTE_SEQUENCE_NUMBER;
+  }
+  return PACKET_6BYTE_SEQUENCE_NUMBER;
+}
+
 bool QuicConnection::OnSerializedPacket(
     const SerializedPacket& serialized_packet) {
   if (serialized_packet.retransmittable_frames != NULL) {
@@ -1266,7 +1335,9 @@
     // All unacked packets might be retransmitted.
     retransmission_map_.insert(
         make_pair(serialized_packet.sequence_number,
-                  RetransmissionInfo(serialized_packet.sequence_number)));
+                  RetransmissionInfo(
+                      serialized_packet.sequence_number,
+                      serialized_packet.sequence_number_length)));
   } else if (serialized_packet.packet->is_fec_packet()) {
     unacked_fec_packets_.insert(make_pair(
         serialized_packet.sequence_number,
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 41172f7..ef90d23 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -29,13 +29,13 @@
 #include "net/quic/congestion_control/quic_congestion_manager.h"
 #include "net/quic/quic_alarm.h"
 #include "net/quic/quic_blocked_writer_interface.h"
+#include "net/quic/quic_connection_stats.h"
 #include "net/quic/quic_framer.h"
 #include "net/quic/quic_packet_creator.h"
 #include "net/quic/quic_packet_generator.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_received_packet_manager.h"
 #include "net/quic/quic_sent_entropy_manager.h"
-#include "net/quic/quic_stats.h"
 
 namespace net {
 
@@ -95,6 +95,12 @@
                             const QuicEncryptedPacket& packet,
                             int rv) = 0;
 
+  // Called when the contents of a packet have been retransmitted as
+  // a new packet.
+  virtual void OnPacketRetransmitted(
+      QuicPacketSequenceNumber old_sequence_number,
+      QuicPacketSequenceNumber new_sequence_number) = 0;
+
   // Called when a packet has been received, but before it is
   // validated or parsed.
   virtual void OnPacketReceived(const IPEndPoint& self_address,
@@ -198,8 +204,6 @@
                  QuicVersion version);
   virtual ~QuicConnection();
 
-  static void DeleteEnclosedFrame(QuicFrame* frame);
-
   // Send the data payload to the peer.
   // 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
@@ -449,13 +453,16 @@
   };
 
   struct RetransmissionInfo {
-    explicit RetransmissionInfo(QuicPacketSequenceNumber sequence_number)
+    RetransmissionInfo(QuicPacketSequenceNumber sequence_number,
+                       QuicSequenceNumberLength sequence_number_length)
         : sequence_number(sequence_number),
+          sequence_number_length(sequence_number_length),
           number_nacks(0),
           number_retransmissions(0) {
     }
 
     QuicPacketSequenceNumber sequence_number;
+    QuicSequenceNumberLength sequence_number_length;
     size_t number_nacks;
     size_t number_retransmissions;
   };
@@ -510,6 +517,12 @@
   // Returns false if the socket has become blocked.
   bool DoWrite();
 
+  // Calculates the smallest sequence number length that can also represent four
+  // times the maximum of the congestion window and the difference between the
+  // least_packet_awaited_by_peer_ and |sequence_number|.
+  QuicSequenceNumberLength CalculateSequenceNumberLength(
+      QuicPacketSequenceNumber sequence_number);
+
   // Drop packet corresponding to |sequence_number| by deleting entries from
   // |unacked_packets_| and |retransmission_map_|, if present. We need to drop
   // all packets with encryption level NONE after the default level has been set
diff --git a/net/quic/quic_connection_helper_test.cc b/net/quic/quic_connection_helper_test.cc
index 4822ea6..9f1bcac 100644
--- a/net/quic/quic_connection_helper_test.cc
+++ b/net/quic/quic_connection_helper_test.cc
@@ -121,6 +121,10 @@
     send_algorithm_ = new testing::StrictMock<MockSendAlgorithm>();
     EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _, _)).
         WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+    EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
+        testing::Return(QuicBandwidth::FromKBitsPerSecond(100)));
+    EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(
+        testing::Return(QuicTime::Delta::FromMilliseconds(100)));
     connection_.reset(new TestConnection(guid_, IPEndPoint(), helper_));
     connection_->set_visitor(&visitor_);
     connection_->SetSendAlgorithm(send_algorithm_);
@@ -199,6 +203,7 @@
     header_.public_header.guid = guid_;
     header_.public_header.reset_flag = false;
     header_.public_header.version_flag = true;
+    header_.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
     header_.packet_sequence_number = sequence_number;
     header_.entropy_flag = false;
     header_.fec_flag = false;
@@ -312,6 +317,7 @@
 
   EXPECT_CALL(*send_algorithm_, SentPacket(_, 1, _, NOT_RETRANSMISSION));
   EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _));
+
   // Send a packet.
   connection_->SendStreamData(1, kData, 0, false);
   EXPECT_CALL(*send_algorithm_, SentPacket(_, 2, _, IS_RETRANSMISSION));
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 3405cd0..b5dfcd6 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "net/base/net_log.h"
+#include "net/quic/crypto/crypto_handshake.h"
 
 namespace net {
 
@@ -43,6 +44,18 @@
   return dict;
 }
 
+base::Value* NetLogQuicPacketRetransmittedCallback(
+    QuicPacketSequenceNumber old_sequence_number,
+    QuicPacketSequenceNumber new_sequence_number,
+    NetLog::LogLevel /* log_level */) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetString("old_packet_sequence_number",
+                 base::Uint64ToString(old_sequence_number));
+ dict->SetString("new_packet_sequence_number",
+                 base::Uint64ToString(new_sequence_number));
+ return dict;
+}
+
 base::Value* NetLogQuicPacketHeaderCallback(const QuicPacketHeader* header,
                                             NetLog::LogLevel /* log_level */) {
   base::DictionaryValue* dict = new base::DictionaryValue();
@@ -86,7 +99,7 @@
       frame->received_info.missing_packets;
   for (SequenceNumberSet::const_iterator it = missing_packets.begin();
        it != missing_packets.end(); ++it) {
-    missing->Append(new base::StringValue(base::Uint64ToString(*it)));
+    missing->AppendString(base::Uint64ToString(*it));
   }
   return dict;
 }
@@ -107,7 +120,7 @@
            it != frame->inter_arrival.received_packet_times.end(); ++it) {
         std::string value = base::Uint64ToString(it->first) + "@" +
             base::Uint64ToString(it->second.ToDebuggingValue());
-        received->Append(new base::StringValue(value));
+        received->AppendString(value);
       }
       break;
     }
@@ -146,6 +159,37 @@
   return dict;
 }
 
+base::Value* NetLogQuicVersionNegotiationPacketCallback(
+    const QuicVersionNegotiationPacket* packet,
+    NetLog::LogLevel /* log_level */) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  base::ListValue* versions = new base::ListValue();
+  dict->Set("versions", versions);
+  for (QuicVersionVector::const_iterator it = packet->versions.begin();
+       it != packet->versions.end(); ++it) {
+    versions->AppendString(QuicVersionToString(*it));
+  }
+  return dict;
+}
+
+base::Value* NetLogQuicCryptoHandshakeMessageCallback(
+    const CryptoHandshakeMessage* message,
+    NetLog::LogLevel /* log_level */) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetString("quic_crypto_handshake_message", message->DebugString());
+  return dict;
+}
+
+base::Value* NetLogQuicConnectionClosedCallback(
+    QuicErrorCode error,
+    bool from_peer,
+    NetLog::LogLevel /* log_level */) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetInteger("quic_error", error);
+  dict->SetBoolean("from_peer", from_peer);
+  return dict;
+}
+
 void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets) {
   UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapSent",
                        num_consecutive_missing_packets);
@@ -216,6 +260,15 @@
                  packet.length(), rv));
 }
 
+void QuicConnectionLogger:: OnPacketRetransmitted(
+      QuicPacketSequenceNumber old_sequence_number,
+      QuicPacketSequenceNumber new_sequence_number) {
+  net_log_.AddEvent(
+      NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED,
+      base::Bind(&NetLogQuicPacketRetransmittedCallback,
+                 old_sequence_number, new_sequence_number));
+}
+
 void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address,
                                             const IPEndPoint& peer_address,
                                             const QuicEncryptedPacket& packet) {
@@ -321,15 +374,43 @@
 
 void QuicConnectionLogger::OnPublicResetPacket(
     const QuicPublicResetPacket& packet) {
+  net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED);
 }
 
 void QuicConnectionLogger::OnVersionNegotiationPacket(
     const QuicVersionNegotiationPacket& packet) {
+  net_log_.AddEvent(
+      NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED,
+      base::Bind(&NetLogQuicVersionNegotiationPacketCallback, &packet));
 }
 
 void QuicConnectionLogger::OnRevivedPacket(
     const QuicPacketHeader& revived_header,
     base::StringPiece payload) {
+  net_log_.AddEvent(
+      NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_REVIVED,
+      base::Bind(&NetLogQuicPacketHeaderCallback, &revived_header));
+}
+
+void QuicConnectionLogger::OnCryptoHandshakeMessageReceived(
+    const CryptoHandshakeMessage& message) {
+  net_log_.AddEvent(
+      NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED,
+      base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
+}
+
+void QuicConnectionLogger::OnCryptoHandshakeMessageSent(
+    const CryptoHandshakeMessage& message) {
+  net_log_.AddEvent(
+      NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT,
+      base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message));
+}
+
+void QuicConnectionLogger::OnConnectionClose(QuicErrorCode error,
+                                             bool from_peer) {
+  net_log_.AddEvent(
+      NetLog::TYPE_QUIC_SESSION_CLOSED,
+      base::Bind(&NetLogQuicConnectionClosedCallback, error, from_peer));
 }
 
 }  // namespace net
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 1d2bd2d..f9080d6 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -10,6 +10,7 @@
 namespace net {
 
 class BoundNetLog;
+class CryptoHandshakeMessage;
 
 // This class is a debug visitor of a QuicConnection which logs
 // events to |net_log|.
@@ -28,7 +29,9 @@
                             EncryptionLevel level,
                             const QuicEncryptedPacket& packet,
                             int rv) OVERRIDE;
-
+  virtual void OnPacketRetransmitted(
+      QuicPacketSequenceNumber old_sequence_number,
+      QuicPacketSequenceNumber new_sequence_number) OVERRIDE;
   virtual void OnPacketReceived(const IPEndPoint& self_address,
                                 const IPEndPoint& peer_address,
                                 const QuicEncryptedPacket& packet) OVERRIDE;
@@ -48,6 +51,12 @@
   virtual void OnRevivedPacket(const QuicPacketHeader& revived_header,
                                base::StringPiece payload) OVERRIDE;
 
+  void OnCryptoHandshakeMessageReceived(
+      const CryptoHandshakeMessage& message);
+  void OnCryptoHandshakeMessageSent(
+      const CryptoHandshakeMessage& message);
+  void OnConnectionClose(QuicErrorCode error, bool from_peer);
+
  private:
   BoundNetLog net_log_;
   // The last packet sequence number received.
diff --git a/net/quic/quic_connection_stats.cc b/net/quic/quic_connection_stats.cc
new file mode 100644
index 0000000..f66a5cb
--- /dev/null
+++ b/net/quic/quic_connection_stats.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/quic/quic_connection_stats.h"
+
+namespace net {
+
+QuicConnectionStats::QuicConnectionStats()
+    : bytes_sent(0),
+      packets_sent(0),
+      bytes_received(0),
+      packets_received(0),
+      bytes_retransmitted(0),
+      packets_retransmitted(0),
+      packets_revived(0),
+      packets_dropped(0),
+      rto_count(0),
+      rtt(0),
+      estimated_bandwidth(0) {
+}
+
+QuicConnectionStats::~QuicConnectionStats() {}
+
+}  // namespace net
diff --git a/net/quic/quic_connection_stats.h b/net/quic/quic_connection_stats.h
new file mode 100644
index 0000000..f933662
--- /dev/null
+++ b/net/quic/quic_connection_stats.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_CONNECTION_STATS_H_
+#define NET_QUIC_QUIC_CONNECTION_STATS_H_
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+
+namespace net {
+// TODO(satyamshekhar): Add more interesting stats:
+// 1. (C/S)HLO retransmission count.
+// 2. SHLO received to first stream packet processed time.
+// 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.
+
+// Structure to hold stats for a QuicConnection.
+struct NET_EXPORT_PRIVATE QuicConnectionStats {
+  QuicConnectionStats();
+  ~QuicConnectionStats();
+
+  uint64 bytes_sent;  // includes retransmissions, fec.
+  uint32 packets_sent;
+
+  uint64 bytes_received;  // includes duplicate data for a stream, fec.
+  uint32 packets_received;  // includes dropped packets
+
+  uint64 bytes_retransmitted;
+  uint32 packets_retransmitted;
+
+  uint32 packets_revived;
+  uint32 packets_dropped;  // duplicate or less than least unacked.
+  uint32 rto_count;
+
+  uint32 rtt;
+  uint64 estimated_bandwidth;
+  // TODO(satyamshekhar): Add window_size, mss and mtu.
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_QUIC_CONNECTION_STATS_H_
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index bd698c3..0eb37ce 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -29,14 +29,14 @@
 using std::vector;
 using testing::_;
 using testing::AnyNumber;
-using testing::Between;
 using testing::ContainerEq;
 using testing::DoAll;
 using testing::InSequence;
 using testing::InvokeWithoutArgs;
+using testing::Ref;
 using testing::Return;
-using testing::StrictMock;
 using testing::SaveArg;
+using testing::StrictMock;
 
 namespace net {
 namespace test {
@@ -50,6 +50,13 @@
 
 const QuicPacketEntropyHash kTestEntropyHash = 76;
 
+const int kDefaultRetransmissionTimeMs = 500;
+
+// Used by TestConnection::SendStreamData3.
+const QuicStreamId kStreamId3 = 3;
+// Used by TestConnection::SendStreamData5.
+const QuicStreamId kStreamId5 = 5;
+
 class TestReceiveAlgorithm : public ReceiveAlgorithmInterface {
  public:
   explicit TestReceiveAlgorithm(QuicCongestionFeedbackFrame* feedback)
@@ -382,12 +389,21 @@
     QuicConnectionPeer::SetSendAlgorithm(this, send_algorithm);
   }
 
-  QuicConsumedData SendStreamData1() {
-    return SendStreamData(1u, "food", 0, !kFin);
+  QuicConsumedData SendStreamData3() {
+    return SendStreamData(kStreamId3, "food", 0, !kFin);
   }
 
-  QuicConsumedData SendStreamData2() {
-    return SendStreamData(2u, "food2", 0, !kFin);
+  QuicConsumedData SendStreamData5() {
+    return SendStreamData(kStreamId5, "food2", 0, !kFin);
+  }
+
+  // The crypto stream has special semantics so that it is not blocked by a
+  // congestion window limitation, and also so that it gets put into a separate
+  // packet (so that it is easier to reason about a crypto frame not being
+  // split needlessly across packet boundaries).  As a result, we have separate
+  // tests for some cases for this stream.
+  QuicConsumedData SendCryptoStreamData() {
+    return SendStreamData(kCryptoStreamId, "chlo", 0, !kFin);
   }
 
   bool is_server() {
@@ -454,6 +470,10 @@
     EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(AnyNumber());
     EXPECT_CALL(*send_algorithm_, RetransmissionDelay()).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)));
   }
 
   QuicAckFrame* outgoing_ack() {
@@ -505,18 +525,6 @@
     return serialized_packet.entropy_hash;
   }
 
-  size_t ProcessFecProtectedPacket(QuicPacketSequenceNumber number,
-                                 bool expect_revival) {
-    if (expect_revival) {
-      EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).Times(2).WillRepeatedly(
-          Return(accept_packet_));
-    } else {
-      EXPECT_CALL(visitor_, OnPacket(_, _, _, _)).WillOnce(
-          Return(accept_packet_));
-    }
-    return ProcessDataPacket(number, 1, !kEntropyFlag);
-  }
-
   size_t ProcessDataPacket(QuicPacketSequenceNumber number,
                            QuicFecGroupNumber fec_group,
                            bool entropy_flag) {
@@ -689,6 +697,10 @@
     connection_.SetReceiveAlgorithm(receive_algorithm_);
   }
 
+  QuicTime::Delta DefaultRetransmissionTime() {
+    return QuicTime::Delta::FromMilliseconds(kDefaultRetransmissionTimeMs);
+  }
+
   QuicGuid guid_;
   QuicFramer framer_;
   QuicPacketCreator creator_;
@@ -699,7 +711,7 @@
   MockRandom random_generator_;
   TestConnectionHelper* helper_;
   TestConnection connection_;
-  testing::StrictMock<MockConnectionVisitor> visitor_;
+  StrictMock<MockConnectionVisitor> visitor_;
 
   QuicPacketHeader header_;
   QuicPacketHeader revived_header_;
@@ -813,20 +825,20 @@
   }
 
   QuicAckFrame frame(0, QuicTime::Zero(), 1);
-  frame.received_info.largest_observed = 192;
-  InsertMissingPacketsBetween(&frame.received_info, 1, 192);
+  frame.received_info.largest_observed = 193;
+  InsertMissingPacketsBetween(&frame.received_info, 1, 193);
   frame.received_info.entropy_hash =
-      QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^
-      QuicConnectionPeer::GetSentEntropyHash(&connection_, 191);
+      QuicConnectionPeer::GetSentEntropyHash(&connection_, 193) ^
+      QuicConnectionPeer::GetSentEntropyHash(&connection_, 192);
 
   ProcessAckPacket(&frame, true);
 
   EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
 
-  frame.received_info.missing_packets.erase(191);
+  frame.received_info.missing_packets.erase(192);
   frame.received_info.entropy_hash =
-      QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^
-      QuicConnectionPeer::GetSentEntropyHash(&connection_, 190);
+      QuicConnectionPeer::GetSentEntropyHash(&connection_, 193) ^
+      QuicConnectionPeer::GetSentEntropyHash(&connection_, 191);
 
   ProcessAckPacket(&frame, true);
   EXPECT_FALSE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
@@ -964,6 +976,106 @@
   ProcessAckPacket(&frame1, true);
 }
 
+TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsBandwidth) {
+  EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(Return(
+       QuicBandwidth::FromKBitsPerSecond(1000)));
+
+  QuicPacketSequenceNumber last_packet;
+  SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet);
+  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(Return(
+       QuicBandwidth::FromKBitsPerSecond(1000 * 256)));
+
+  SendStreamDataToPeer(1u, "bar", 3, !kFin, &last_packet);
+  EXPECT_EQ(2u, last_packet);
+  EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  // The 1 packet lag is due to the sequence number length being recalculated in
+  // QuicConnection after a packet is sent.
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(Return(
+       QuicBandwidth::FromKBitsPerSecond(1000 * 256 * 256)));
+
+  SendStreamDataToPeer(1, "foo", 6, !kFin, &last_packet);
+  EXPECT_EQ(3u, last_packet);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(Return(
+       QuicBandwidth::FromKBitsPerSecond(1000ll * 256 * 256 * 256)));
+
+  SendStreamDataToPeer(1u, "bar", 9, !kFin, &last_packet);
+  EXPECT_EQ(4u, last_packet);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillOnce(Return(
+      QuicBandwidth::FromKBitsPerSecond(1000ll * 256 * 256 * 256 * 256)));
+
+  SendStreamDataToPeer(1u, "foo", 12, !kFin, &last_packet);
+  EXPECT_EQ(5u, last_packet);
+  EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+}
+
+TEST_F(QuicConnectionTest, SendingDifferentSequenceNumberLengthsUnackedDelta) {
+  QuicPacketSequenceNumber last_packet;
+  SendStreamDataToPeer(1, "foo", 0, !kFin, &last_packet);
+  EXPECT_EQ(1u, last_packet);
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(100);
+
+  SendStreamDataToPeer(1u, "bar", 3, !kFin, &last_packet);
+  EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(
+      100 * 256);
+
+  SendStreamDataToPeer(1, "foo", 6, !kFin, &last_packet);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(
+      100 * 256 * 256);
+
+  SendStreamDataToPeer(1u, "bar", 9, !kFin, &last_packet);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+
+  QuicConnectionPeer::GetPacketCreator(&connection_)->set_sequence_number(
+      100 * 256 * 256 * 256);
+
+  SendStreamDataToPeer(1u, "foo", 12, !kFin, &last_packet);
+  EXPECT_EQ(PACKET_6BYTE_SEQUENCE_NUMBER,
+            connection_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            last_header()->public_header.sequence_number_length);
+}
+
 TEST_F(QuicConnectionTest, BasicSending) {
   EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(6);
   QuicPacketSequenceNumber last_packet;
@@ -1027,8 +1139,9 @@
   // All packets carry version info till version is negotiated.
   size_t payload_length;
   connection_.options()->max_packet_length =
-      GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
-                                  IN_FEC_GROUP, &payload_length);
+      GetPacketLengthForOneStream(
+          connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
+          IN_FEC_GROUP, &payload_length);
   // And send FEC every two packets.
   connection_.options()->max_packets_per_fec_group = 2;
 
@@ -1045,8 +1158,9 @@
   // All packets carry version info till version is negotiated.
   size_t payload_length;
   connection_.options()->max_packet_length =
-      GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
-                                  IN_FEC_GROUP, &payload_length);
+      GetPacketLengthForOneStream(
+          connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
+          IN_FEC_GROUP, &payload_length);
   // And send FEC every two packets.
   connection_.options()->max_packets_per_fec_group = 2;
 
@@ -1100,9 +1214,7 @@
 
   ProcessAckPacket(&ack_fec, true);
 
-  const QuicTime::Delta kDefaultRetransmissionTime =
-      QuicTime::Delta::FromMilliseconds(5000);
-  clock_.AdvanceTime(kDefaultRetransmissionTime);
+  clock_.AdvanceTime(DefaultRetransmissionTime());
 
   // Abandon only data packet, FEC has been acked.
   EXPECT_CALL(*send_algorithm_, AbandoningPacket(sequence_number, _)).Times(1);
@@ -1120,9 +1232,9 @@
   connection_.SendAck();
   EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
       IgnoreResult(InvokeWithoutArgs(&connection_,
-                                     &TestConnection::SendStreamData1)),
+                                     &TestConnection::SendStreamData3)),
       IgnoreResult(InvokeWithoutArgs(&connection_,
-                                     &TestConnection::SendStreamData2)),
+                                     &TestConnection::SendStreamData5)),
       Return(true)));
 
   // Unblock the connection.
@@ -1139,8 +1251,70 @@
   EXPECT_EQ(3u, helper_->frame_count());
   EXPECT_TRUE(helper_->ack());
   EXPECT_EQ(2u, helper_->stream_frames()->size());
-  EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
-  EXPECT_EQ(2u, (*helper_->stream_frames())[1].stream_id);
+  EXPECT_EQ(kStreamId3, (*helper_->stream_frames())[0].stream_id);
+  EXPECT_EQ(kStreamId5, (*helper_->stream_frames())[1].stream_id);
+}
+
+TEST_F(QuicConnectionTest, FramePackingNonCryptoThenCrypto) {
+  // Block the connection.
+  connection_.GetSendAlarm()->Set(
+      clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
+
+  // Send an ack and two stream frames (one non-crypto, then one crypto) in 2
+  // packets by queueing them.
+  connection_.SendAck();
+  EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
+      IgnoreResult(InvokeWithoutArgs(&connection_,
+                                     &TestConnection::SendStreamData3)),
+      IgnoreResult(InvokeWithoutArgs(&connection_,
+                                     &TestConnection::SendCryptoStreamData)),
+      Return(true)));
+
+  // Unblock the connection.
+  connection_.GetSendAlarm()->Cancel();
+  EXPECT_CALL(*send_algorithm_,
+              SentPacket(_, _, _, NOT_RETRANSMISSION))
+      .Times(2);
+  connection_.OnCanWrite();
+  EXPECT_EQ(0u, connection_.NumQueuedPackets());
+  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);
+}
+
+TEST_F(QuicConnectionTest, FramePackingCryptoThenNonCrypto) {
+  // Block the connection.
+  connection_.GetSendAlarm()->Set(
+      clock_.ApproximateNow().Add(QuicTime::Delta::FromSeconds(1)));
+
+  // Send an ack and two stream frames (one crypto, then one non-crypto) in 3
+  // packets by queueing them.
+  connection_.SendAck();
+  EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
+      IgnoreResult(InvokeWithoutArgs(&connection_,
+                                     &TestConnection::SendCryptoStreamData)),
+      IgnoreResult(InvokeWithoutArgs(&connection_,
+                                     &TestConnection::SendStreamData3)),
+      Return(true)));
+
+  // Unblock the connection.
+  connection_.GetSendAlarm()->Cancel();
+  EXPECT_CALL(*send_algorithm_,
+              SentPacket(_, _, _, NOT_RETRANSMISSION))
+      .Times(3);
+  connection_.OnCanWrite();
+  EXPECT_EQ(0u, connection_.NumQueuedPackets());
+  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);
 }
 
 TEST_F(QuicConnectionTest, FramePackingFEC) {
@@ -1154,9 +1328,9 @@
   connection_.SendAck();
   EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
       IgnoreResult(InvokeWithoutArgs(&connection_,
-                                     &TestConnection::SendStreamData1)),
+                                     &TestConnection::SendStreamData3)),
       IgnoreResult(InvokeWithoutArgs(&connection_,
-                                     &TestConnection::SendStreamData2)),
+                                     &TestConnection::SendStreamData5)),
       Return(true)));
 
   // Unblock the connection.
@@ -1176,9 +1350,9 @@
   // Visitor's OnCanWill send data, but will return false.
   EXPECT_CALL(visitor_, OnCanWrite()).WillOnce(DoAll(
       IgnoreResult(InvokeWithoutArgs(&connection_,
-                                     &TestConnection::SendStreamData1)),
+                                     &TestConnection::SendStreamData3)),
       IgnoreResult(InvokeWithoutArgs(&connection_,
-                                     &TestConnection::SendStreamData2)),
+                                     &TestConnection::SendStreamData5)),
       Return(false)));
 
   EXPECT_CALL(*send_algorithm_,
@@ -1191,8 +1365,8 @@
   // two different streams.
   EXPECT_EQ(2u, helper_->frame_count());
   EXPECT_EQ(2u, helper_->stream_frames()->size());
-  EXPECT_EQ(1u, (*helper_->stream_frames())[0].stream_id);
-  EXPECT_EQ(2u, (*helper_->stream_frames())[1].stream_id);
+  EXPECT_EQ(kStreamId3, (*helper_->stream_frames())[0].stream_id);
+  EXPECT_EQ(kStreamId5, (*helper_->stream_frames())[1].stream_id);
 }
 
 TEST_F(QuicConnectionTest, RetransmitOnNack) {
@@ -1269,12 +1443,11 @@
 
   // Make a truncated ack frame.
   QuicAckFrame frame(0, QuicTime::Zero(), 1);
-  frame.received_info.largest_observed = 192;
-  InsertMissingPacketsBetween(&frame.received_info, 1, 192);
+  frame.received_info.largest_observed = 193;
+  InsertMissingPacketsBetween(&frame.received_info, 1, 193);
   frame.received_info.entropy_hash =
-      QuicConnectionPeer::GetSentEntropyHash(&connection_, 192) ^
-      QuicConnectionPeer::GetSentEntropyHash(&connection_, 191);
-
+      QuicConnectionPeer::GetSentEntropyHash(&connection_, 193) ^
+      QuicConnectionPeer::GetSentEntropyHash(&connection_, 192);
 
   EXPECT_CALL(*send_algorithm_, OnIncomingAck(_, _, _)).Times(1);
   EXPECT_CALL(*send_algorithm_, OnIncomingLoss(_)).Times(1);
@@ -1283,20 +1456,18 @@
   EXPECT_TRUE(QuicConnectionPeer::GetReceivedTruncatedAck(&connection_));
 
   QuicConnectionPeer::SetMaxPacketsPerRetransmissionAlarm(&connection_, 200);
-  const QuicTime::Delta kDefaultRetransmissionTime =
-      QuicTime::Delta::FromMilliseconds(500);
-  clock_.AdvanceTime(kDefaultRetransmissionTime);
+  clock_.AdvanceTime(DefaultRetransmissionTime());
   // Only packets that are less than largest observed should be retransmitted.
-  EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(191);
-  EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(191);
+  EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(192);
+  EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(192);
   connection_.OnRetransmissionTimeout();
 
   clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
-      2 * kDefaultRetransmissionTime.ToMicroseconds()));
+      2 * DefaultRetransmissionTime().ToMicroseconds()));
   // Retransmit already retransmitted packets event though the sequence number
   // greater than the largest observed.
-  EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(191);
-  EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(191);
+  EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(192);
+  EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(192);
   connection_.OnRetransmissionTimeout();
 }
 
@@ -1458,11 +1629,8 @@
 }
 
 TEST_F(QuicConnectionTest, TestRetransmit) {
-  const QuicTime::Delta kDefaultRetransmissionTime =
-      QuicTime::Delta::FromMilliseconds(500);
-
   QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
-      kDefaultRetransmissionTime);
+      DefaultRetransmissionTime());
   SendStreamDataToPeer(1, "foo", 0, !kFin, NULL);
   EXPECT_EQ(1u, outgoing_ack()->sent_info.least_unacked);
 
@@ -1470,7 +1638,7 @@
   EXPECT_EQ(default_retransmission_time,
             connection_.GetRetransmissionAlarm()->deadline());
   // Simulate the retransimission alarm firing
-  clock_.AdvanceTime(kDefaultRetransmissionTime);
+  clock_.AdvanceTime(DefaultRetransmissionTime());
   EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
   EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, _)).Times(1);
   connection_.RetransmitPacket(1);
@@ -1479,11 +1647,8 @@
 }
 
 TEST_F(QuicConnectionTest, RetransmitWithSameEncryptionLevel) {
-  const QuicTime::Delta kDefaultRetransmissionTime =
-      QuicTime::Delta::FromMilliseconds(500);
-
   QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
-      kDefaultRetransmissionTime);
+      DefaultRetransmissionTime());
   use_tagging_decrypter();
 
   // A TaggingEncrypter puts kTagSize copies of the given byte (0x01 here) at
@@ -1500,7 +1665,7 @@
   EXPECT_EQ(default_retransmission_time,
             connection_.GetRetransmissionAlarm()->deadline());
   // Simulate the retransimission alarm firing
-  clock_.AdvanceTime(kDefaultRetransmissionTime);
+  clock_.AdvanceTime(DefaultRetransmissionTime());
   EXPECT_CALL(*send_algorithm_, AbandoningPacket(_, _)).Times(2);
 
   EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _));
@@ -1528,15 +1693,13 @@
   EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(0);
   EXPECT_CALL(*send_algorithm_, AbandoningPacket(sequence_number, _)).Times(1);
 
-  const QuicTime::Delta kDefaultRetransmissionTime =
-      QuicTime::Delta::FromMilliseconds(500);
   QuicTime default_retransmission_time = clock_.ApproximateNow().Add(
-      kDefaultRetransmissionTime);
+      DefaultRetransmissionTime());
 
   EXPECT_EQ(default_retransmission_time,
             connection_.GetRetransmissionAlarm()->deadline());
   // Simulate the retransimission alarm firing
-  clock_.AdvanceTime(kDefaultRetransmissionTime);
+  clock_.AdvanceTime(DefaultRetransmissionTime());
   connection_.OnRetransmissionTimeout();
 }
 
@@ -1966,8 +2129,9 @@
   // All packets carry version info till version is negotiated.
   size_t payload_length;
   connection_.options()->max_packet_length =
-      GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
-                                  NOT_IN_FEC_GROUP, &payload_length);
+      GetPacketLengthForOneStream(
+          connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
+          NOT_IN_FEC_GROUP, &payload_length);
 
   // Queue the first packet.
   EXPECT_CALL(*send_algorithm_,
@@ -1983,8 +2147,9 @@
   // All packets carry version info till version is negotiated.
   size_t payload_length;
   connection_.options()->max_packet_length =
-      GetPacketLengthForOneStream(connection_.version(), kIncludeVersion,
-                                  NOT_IN_FEC_GROUP, &payload_length);
+      GetPacketLengthForOneStream(
+          connection_.version(), kIncludeVersion, PACKET_1BYTE_SEQUENCE_NUMBER,
+          NOT_IN_FEC_GROUP, &payload_length);
 
   // Queue the first packet.
   EXPECT_CALL(*send_algorithm_, SentPacket(_, _, _, _)).Times(7);
@@ -2065,7 +2230,7 @@
   QuicPacketEntropyHash six_packet_entropy_hash = 0;
   if (ProcessAckPacket(&ack, true)) {
     six_packet_entropy_hash = 1 << 6;
-  };
+  }
 
   EXPECT_EQ((kRandomEntropyHash + (1 << 5) + six_packet_entropy_hash),
             outgoing_ack()->received_info.entropy_hash);
@@ -2440,6 +2605,68 @@
   EXPECT_EQ(1u, helper_->packets_write_attempts());
 }
 
+class MockQuicConnectionDebugVisitor
+    : public QuicConnectionDebugVisitorInterface {
+ public:
+  MOCK_METHOD1(OnFrameAddedToPacket,
+               void(const QuicFrame&));
+
+  MOCK_METHOD4(OnPacketSent,
+               void(QuicPacketSequenceNumber,
+                    EncryptionLevel,
+                    const QuicEncryptedPacket&,
+                    int));
+
+  MOCK_METHOD2(OnPacketRetransmitted,
+               void(QuicPacketSequenceNumber,
+                    QuicPacketSequenceNumber));
+
+  MOCK_METHOD3(OnPacketReceived,
+               void(const IPEndPoint&,
+                    const IPEndPoint&,
+                    const QuicEncryptedPacket&));
+
+  MOCK_METHOD1(OnProtocolVersionMismatch,
+               void(QuicVersion));
+
+  MOCK_METHOD1(OnPacketHeader,
+               void(const QuicPacketHeader& header));
+
+  MOCK_METHOD1(OnStreamFrame,
+               void(const QuicStreamFrame&));
+
+  MOCK_METHOD1(OnAckFrame,
+               void(const QuicAckFrame& frame));
+
+  MOCK_METHOD1(OnCongestionFeedbackFrame,
+               void(const QuicCongestionFeedbackFrame&));
+
+  MOCK_METHOD1(OnRstStreamFrame,
+               void(const QuicRstStreamFrame&));
+
+  MOCK_METHOD1(OnConnectionCloseFrame,
+               void(const QuicConnectionCloseFrame&));
+
+  MOCK_METHOD1(OnPublicResetPacket,
+               void(const QuicPublicResetPacket&));
+
+  MOCK_METHOD1(OnVersionNegotiationPacket,
+               void(const QuicVersionNegotiationPacket&));
+
+  MOCK_METHOD2(OnRevivedPacket,
+               void(const QuicPacketHeader&, StringPiece payload));
+};
+
+TEST_F(QuicConnectionTest, OnPacketHeaderDebugVisitor) {
+  QuicPacketHeader header;
+
+  scoped_ptr<MockQuicConnectionDebugVisitor>
+      debug_visitor(new StrictMock<MockQuicConnectionDebugVisitor>);
+  connection_.set_debug_visitor(debug_visitor.get());
+  EXPECT_CALL(*debug_visitor, OnPacketHeader(Ref(header))).Times(1);
+  connection_.OnPacketHeader(header);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index ab1d974..585b293 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -85,6 +85,8 @@
 
 void QuicCryptoClientStream::OnHandshakeMessage(
     const CryptoHandshakeMessage& message) {
+  QuicCryptoStream::OnHandshakeMessage(message);
+
   DoHandshakeLoop(&message);
 }
 
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 9f9e7f7..2ad9a3a 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -21,31 +21,6 @@
 
 const char kServerHostname[] = "example.com";
 
-class TestQuicVisitor : public NoOpFramerVisitor {
- public:
-  TestQuicVisitor()
-      : frame_valid_(false) {
-  }
-
-  // NoOpFramerVisitor
-  virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
-    frame_ = frame;
-    frame_valid_ = true;
-    return true;
-  }
-
-  bool frame_valid() const {
-    return frame_valid_;
-  }
-  QuicStreamFrame* frame() { return &frame_; }
-
- private:
-  QuicStreamFrame frame_;
-  bool frame_valid_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor);
-};
-
 class QuicCryptoClientStreamTest : public ::testing::Test {
  public:
   QuicCryptoClientStreamTest()
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index f7b67b7..a23a34d 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -27,6 +27,8 @@
 
 void QuicCryptoServerStream::OnHandshakeMessage(
     const CryptoHandshakeMessage& message) {
+  QuicCryptoStream::OnHandshakeMessage(message);
+
   // Do not process handshake messages after the handshake is confirmed.
   if (handshake_confirmed_) {
     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index f1e30cb..b4967d8 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -43,8 +43,6 @@
       CryptoHandshakeMessage* reply,
       std::string* error_details);
 
-  const QuicCryptoServerConfig* crypto_config() { return &crypto_config_; }
-
  private:
   friend class test::CryptoTestUtils;
 
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc
index 3bb2593..9e92b2b 100644
--- a/net/quic/quic_crypto_server_stream_test.cc
+++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -36,25 +36,6 @@
 namespace test {
 namespace {
 
-// TODO(agl): Use rch's utility class for parsing a message when committed.
-class TestQuicVisitor : public NoOpFramerVisitor {
- public:
-  TestQuicVisitor() {}
-
-  // NoOpFramerVisitor
-  virtual bool OnStreamFrame(const QuicStreamFrame& frame) OVERRIDE {
-    frame_ = frame;
-    return true;
-  }
-
-  QuicStreamFrame* frame() { return &frame_; }
-
- private:
-  QuicStreamFrame frame_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestQuicVisitor);
-};
-
 class QuicCryptoServerStreamTest : public ::testing::Test {
  public:
   QuicCryptoServerStreamTest()
diff --git a/net/quic/quic_crypto_stream.cc b/net/quic/quic_crypto_stream.cc
index 2f06e3b..569648f 100644
--- a/net/quic/quic_crypto_stream.cc
+++ b/net/quic/quic_crypto_stream.cc
@@ -27,6 +27,11 @@
   session()->ConnectionClose(framer->error(), false);
 }
 
+void QuicCryptoStream::OnHandshakeMessage(
+    const CryptoHandshakeMessage& message) {
+  session()->OnCryptoHandshakeMessageReceived(message);
+}
+
 uint32 QuicCryptoStream::ProcessData(const char* data,
                                      uint32 data_len) {
   // Do not process handshake messages after the handshake is confirmed.
@@ -52,6 +57,7 @@
 
 void QuicCryptoStream::SendHandshakeMessage(
     const CryptoHandshakeMessage& message) {
+  session()->OnCryptoHandshakeMessageSent(message);
   const QuicData& data = message.GetSerialized();
   // TODO(wtc): check the return value.
   WriteData(string(data.data(), data.length()), false);
diff --git a/net/quic/quic_crypto_stream.h b/net/quic/quic_crypto_stream.h
index bdae59e..c402b0d 100644
--- a/net/quic/quic_crypto_stream.h
+++ b/net/quic/quic_crypto_stream.h
@@ -34,7 +34,8 @@
 
   // CryptoFramerVisitorInterface implementation
   virtual void OnError(CryptoFramer* framer) OVERRIDE;
-  virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) = 0;
+  virtual void OnHandshakeMessage(
+      const CryptoHandshakeMessage& message) OVERRIDE;
 
   // ReliableQuicStream implementation
   virtual uint32 ProcessData(const char* data, uint32 data_len) OVERRIDE;
diff --git a/net/quic/quic_data_writer.cc b/net/quic/quic_data_writer.cc
index e52cd03..61e7292 100644
--- a/net/quic/quic_data_writer.cc
+++ b/net/quic/quic_data_writer.cc
@@ -56,10 +56,6 @@
   return WriteBytes(&value, sizeof(value));
 }
 
-bool QuicDataWriter::WriteUInt128(uint128 value) {
-  return WriteUInt64(Uint128Low64(value)) && WriteUInt64(Uint128High64(value));
-}
-
 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 f3408d1..b18121d 100644
--- a/net/quic/quic_data_writer.h
+++ b/net/quic/quic_data_writer.h
@@ -43,7 +43,6 @@
   bool WriteUInt32(uint32 value);
   bool WriteUInt48(uint64 value);
   bool WriteUInt64(uint64 value);
-  bool WriteUInt128(uint128 value);
   bool WriteStringPiece16(base::StringPiece val);
   bool WriteBytes(const void* data, size_t data_len);
   bool WriteRepeatedByte(uint8 byte, size_t count);
@@ -61,9 +60,6 @@
     return capacity_;
   }
 
- protected:
-  const char* end_of_payload() const { return buffer_ + length_; }
-
  private:
   // Returns the location that the data should be written at, or NULL if there
   // is not enough room. Call EndWrite with the returned offset and the given
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index 8796456..6004e3b 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -260,7 +260,8 @@
     const QuicFrames& frames,
     size_t packet_size) {
   QuicDataWriter writer(packet_size);
-  const SerializedPacket kNoPacket(0, NULL, 0, NULL);
+  const SerializedPacket kNoPacket(
+      0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL);
   if (!WritePacketHeader(header, &writer)) {
     return kNoPacket;
   }
@@ -331,7 +332,8 @@
                                              packet->FecProtectedData());
   }
 
-  return SerializedPacket(header.packet_sequence_number, packet,
+  return SerializedPacket(header.packet_sequence_number,
+                          header.public_header.sequence_number_length, packet,
                           GetPacketEntropyHash(header), NULL);
 }
 
@@ -343,7 +345,8 @@
   len += fec.redundancy.length();
 
   QuicDataWriter writer(len);
-  SerializedPacket kNoPacket = SerializedPacket(0, NULL, 0, NULL);
+  const SerializedPacket kNoPacket(
+      0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL);
   if (!WritePacketHeader(header, &writer)) {
     return kNoPacket;
   }
@@ -354,6 +357,7 @@
 
   return SerializedPacket(
       header.packet_sequence_number,
+      header.public_header.sequence_number_length,
       QuicPacket::NewFecPacket(writer.take(), len, true,
                                header.public_header.guid_length,
                                header.public_header.version_flag,
@@ -877,8 +881,8 @@
 
 bool QuicFramer::ProcessFrameData() {
   if (reader_->IsDoneReading()) {
-    set_detailed_error("Unable to read frame type.");
-    return RaiseError(QUIC_INVALID_FRAME_DATA);
+    set_detailed_error("Packet has no frames.");
+    return RaiseError(QUIC_MISSING_PAYLOAD);
   }
   while (!reader_->IsDoneReading()) {
     uint8 frame_type;
@@ -890,7 +894,7 @@
     if ((frame_type & kQuicFrameType0BitMask) == 0) {
       QuicStreamFrame frame;
       if (!ProcessStreamFrame(frame_type, &frame)) {
-        return RaiseError(QUIC_INVALID_FRAME_DATA);
+        return RaiseError(QUIC_INVALID_STREAM_DATA);
       }
       if (!visitor_->OnStreamFrame(frame)) {
         DLOG(INFO) << "Visitor asked to stop further processing.";
@@ -904,7 +908,7 @@
     if ((frame_type & kQuicFrameType0BitMask) == 0) {
       QuicAckFrame frame;
       if (!ProcessAckFrame(&frame)) {
-        return RaiseError(QUIC_INVALID_FRAME_DATA);
+        return RaiseError(QUIC_INVALID_ACK_DATA);
       }
       if (!visitor_->OnAckFrame(frame)) {
         DLOG(INFO) << "Visitor asked to stop further processing.";
@@ -918,7 +922,7 @@
     if ((frame_type & kQuicFrameType0BitMask) == 0) {
       QuicCongestionFeedbackFrame frame;
       if (!ProcessQuicCongestionFeedbackFrame(&frame)) {
-        return RaiseError(QUIC_INVALID_FRAME_DATA);
+        return RaiseError(QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
       }
       if (!visitor_->OnCongestionFeedbackFrame(frame)) {
         DLOG(INFO) << "Visitor asked to stop further processing.";
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc
index e4148fe..32d0fe7 100644
--- a/net/quic/quic_framer_test.cc
+++ b/net/quic/quic_framer_test.cc
@@ -36,8 +36,6 @@
 const QuicPacketSequenceNumber kEpoch = GG_UINT64_C(1) << 48;
 const QuicPacketSequenceNumber kMask = kEpoch - 1;
 
-// Index into the flags offset in the header.
-const size_t kPublicFlagsOffset = 0;
 // Index into the guid offset in the header.
 const size_t kGuidOffset = kPublicFlagsSize;
 // Index into the version string in the header. (if present).
@@ -390,11 +388,28 @@
     EXPECT_EQ(error_code, framer_.error()) << "len: " << len;
   }
 
-  void ValidateTruncatedAck(const QuicAckFrame* ack, size_t keys) {
-    for (size_t i = 1; i < keys; ++i) {
-      EXPECT_TRUE(ContainsKey(ack->received_info.missing_packets, i)) << i;
+  void CheckStreamFrameBoundaries(unsigned char* packet,
+                                  size_t stream_id_size,
+                                  bool include_version) {
+    // Now test framing boundaries
+    for (size_t i = kQuicFrameTypeSize;
+         i < GetMinStreamFrameSize(framer_.version()); ++i) {
+      string expected_error;
+      if (i < kQuicFrameTypeSize + stream_id_size) {
+        expected_error = "Unable to read stream_id.";
+      } else if (i < kQuicFrameTypeSize + stream_id_size +
+                 kQuicMaxStreamOffsetSize) {
+        expected_error = "Unable to read offset.";
+      } else {
+        expected_error = "Unable to read frame data.";
+      }
+      CheckProcessingFails(
+          packet,
+          i + GetPacketHeaderSize(PACKET_8BYTE_GUID, include_version,
+                                  PACKET_6BYTE_SEQUENCE_NUMBER,
+                                  NOT_IN_FEC_GROUP),
+          expected_error, QUIC_INVALID_STREAM_DATA);
     }
-    EXPECT_EQ(keys, ack->received_info.largest_observed);
   }
 
   void CheckCalculatePacketSequenceNumber(
@@ -580,7 +595,7 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
@@ -633,7 +648,7 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
@@ -688,7 +703,7 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
@@ -741,7 +756,7 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
@@ -778,9 +793,6 @@
 }
 
 TEST_P(QuicFramerTest, PacketHeaderWithVersionFlag) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (version)
     0x3D,
@@ -788,7 +800,7 @@
     0x10, 0x32, 0x54, 0x76,
     0x98, 0xBA, 0xDC, 0xFE,
     // version tag
-    'Q', '0', '0', '7',
+    'Q', '0', '0', (GetParam() == QUIC_VERSION_7 ? '7' : '8'),
     // packet sequence number
     0xBC, 0x9A, 0x78, 0x56,
     0x34, 0x12,
@@ -798,13 +810,13 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
   EXPECT_FALSE(visitor_.header_->public_header.reset_flag);
   EXPECT_TRUE(visitor_.header_->public_header.version_flag);
-  EXPECT_EQ(QUIC_VERSION_7, visitor_.header_->public_header.versions[0]);
+  EXPECT_EQ(GetParam(), visitor_.header_->public_header.versions[0]);
   EXPECT_FALSE(visitor_.header_->fec_flag);
   EXPECT_FALSE(visitor_.header_->entropy_flag);
   EXPECT_EQ(0, visitor_.header_->entropy_hash);
@@ -854,7 +866,7 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
@@ -909,7 +921,7 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
@@ -964,7 +976,7 @@
 
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_MISSING_PAYLOAD, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_EQ(GG_UINT64_C(0xFEDCBA9876543210),
             visitor_.header_->public_header.guid);
@@ -1039,9 +1051,6 @@
 };
 
 TEST_P(QuicFramerTest, InvalidPublicFlagWithMatchingVersions) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (8 byte guid and version flag and an unknown flag)
     0x4D,
@@ -1049,7 +1058,7 @@
     0x10, 0x32, 0x54, 0x76,
     0x98, 0xBA, 0xDC, 0xFE,
     // version tag
-    'Q', '0', '0', '7',
+    'Q', '0', '0', (GetParam() == QUIC_VERSION_7 ? '7' : '8'),
     // packet sequence number
     0xBC, 0x9A, 0x78, 0x56,
     0x34, 0x12,
@@ -1205,7 +1214,7 @@
       packet,
       GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
                           PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-      "Unable to read frame type.", QUIC_INVALID_FRAME_DATA);
+      "Packet has no frames.", QUIC_MISSING_PAYLOAD);
 }
 
 TEST_P(QuicFramerTest, StreamFrame) {
@@ -1253,26 +1262,7 @@
   EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
 
   // Now test framing boundaries
-  for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
-    string expected_error;
-    if (i < kQuicFrameTypeSize) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
-      expected_error = "Unable to read stream_id.";
-    } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
-      expected_error = "Unable to read fin.";
-    } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
-               kQuicMaxStreamOffsetSize) {
-      expected_error = "Unable to read offset.";
-    } else {
-      expected_error = "Unable to read frame data.";
-    }
-    CheckProcessingFails(
-        packet,
-        i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
-                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-        expected_error, QUIC_INVALID_FRAME_DATA);
-  }
+  CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, !kIncludeVersion);
 }
 
 TEST_P(QuicFramerTest, StreamFrame3ByteStreamId) {
@@ -1321,26 +1311,7 @@
 
   // Now test framing boundaries
   const size_t stream_id_size = 3;
-  for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
-    string expected_error;
-    if (i < kQuicFrameTypeSize) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size) {
-      expected_error = "Unable to read stream_id.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size - 1) {
-      expected_error = "Unable to read fin.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size +
-        kQuicMaxStreamOffsetSize) {
-      expected_error = "Unable to read offset.";
-    } else {
-      expected_error = "Unable to read frame data.";
-    }
-    CheckProcessingFails(
-        packet,
-        i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
-                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-                                expected_error, QUIC_INVALID_FRAME_DATA);
-  }
+  CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
 }
 
 TEST_P(QuicFramerTest, StreamFrame2ByteStreamId) {
@@ -1389,26 +1360,7 @@
 
   // Now test framing boundaries
   const size_t stream_id_size = 2;
-  for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
-    string expected_error;
-    if (i < kQuicFrameTypeSize) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size) {
-      expected_error = "Unable to read stream_id.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size - 1) {
-      expected_error = "Unable to read fin.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size +
-        kQuicMaxStreamOffsetSize) {
-      expected_error = "Unable to read offset.";
-    } else {
-      expected_error = "Unable to read frame data.";
-    }
-    CheckProcessingFails(
-        packet,
-        i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
-                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-                                expected_error, QUIC_INVALID_FRAME_DATA);
-  }
+  CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
 }
 
 TEST_P(QuicFramerTest, StreamFrame1ByteStreamId) {
@@ -1457,32 +1409,10 @@
 
   // Now test framing boundaries
   const size_t stream_id_size = 1;
-  for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
-    string expected_error;
-    if (i < kQuicFrameTypeSize) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size) {
-      expected_error = "Unable to read stream_id.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size - 1) {
-      expected_error = "Unable to read fin.";
-    } else if (i < kQuicFrameTypeSize + stream_id_size +
-        kQuicMaxStreamOffsetSize) {
-      expected_error = "Unable to read offset.";
-    } else {
-      expected_error = "Unable to read frame data.";
-    }
-    CheckProcessingFails(
-        packet,
-        i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
-                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-                                expected_error, QUIC_INVALID_FRAME_DATA);
-  }
+  CheckStreamFrameBoundaries(packet, stream_id_size, !kIncludeVersion);
 }
 
 TEST_P(QuicFramerTest, StreamFrameWithVersion) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (version, 8 byte guid)
     0x3D,
@@ -1490,7 +1420,7 @@
     0x10, 0x32, 0x54, 0x76,
     0x98, 0xBA, 0xDC, 0xFE,
     // version tag
-    'Q', '0', '0', '7',
+    'Q', '0', '0', (GetParam() == QUIC_VERSION_7 ? '7' : '8'),
     // packet sequence number
     0xBC, 0x9A, 0x78, 0x56,
     0x34, 0x12,
@@ -1518,7 +1448,7 @@
   EXPECT_EQ(QUIC_NO_ERROR, framer_.error());
   ASSERT_TRUE(visitor_.header_.get());
   EXPECT_TRUE(visitor_.header_.get()->public_header.version_flag);
-  EXPECT_EQ(QUIC_VERSION_7, visitor_.header_.get()->public_header.versions[0]);
+  EXPECT_EQ(GetParam(), visitor_.header_.get()->public_header.versions[0]);
   EXPECT_TRUE(CheckDecryption(encrypted, kIncludeVersion));
 
   ASSERT_EQ(1u, visitor_.stream_frames_.size());
@@ -1531,24 +1461,7 @@
   EXPECT_EQ("hello world!", visitor_.stream_frames_[0]->data);
 
   // Now test framing boundaries
-  for (size_t i = 0; i < GetMinStreamFrameSize(framer_.version()); ++i) {
-    string expected_error;
-    if (i < kQuicFrameTypeSize) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
-      expected_error = "Unable to read stream_id.";
-    } else if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize +
-               kQuicMaxStreamOffsetSize) {
-      expected_error = "Unable to read offset.";
-    } else {
-      expected_error = "Unable to read frame data.";
-    }
-    CheckProcessingFails(
-        packet,
-        i + GetPacketHeaderSize(PACKET_8BYTE_GUID, kIncludeVersion,
-                                PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-        expected_error, QUIC_INVALID_FRAME_DATA);
-  }
+  CheckStreamFrameBoundaries(packet, kQuicMaxStreamIdSize, kIncludeVersion);
 }
 
 TEST_P(QuicFramerTest, RejectPacket) {
@@ -1649,9 +1562,6 @@
 }
 
 TEST_P(QuicFramerTest, StreamFrameInFecGroup) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -1772,12 +1682,10 @@
       kNumberOfMissingPacketsSize;
   // Now test framing boundaries
   const size_t missing_packets_size = 1 * PACKET_6BYTE_SEQUENCE_NUMBER;
-  for (size_t i = 0;
+  for (size_t i = kQuicFrameTypeSize;
        i < QuicFramer::GetMinAckFrameSize() + missing_packets_size; ++i) {
     string expected_error;
-    if (i < kSentEntropyOffset) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < kLeastUnackedOffset) {
+    if (i < kLeastUnackedOffset) {
       expected_error = "Unable to read entropy hash for sent packets.";
     } else if (i < kReceivedEntropyOffset) {
       expected_error = "Unable to read least unacked.";
@@ -1796,7 +1704,7 @@
         packet,
         i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
                                 PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-        expected_error, QUIC_INVALID_FRAME_DATA);
+        expected_error, QUIC_INVALID_ACK_DATA);
   }
 }
 
@@ -1840,11 +1748,9 @@
   EXPECT_EQ(0x4030u, frame.tcp.receive_window);
 
   // Now test framing boundaries
-  for (size_t i = 0; i < 6; ++i) {
+  for (size_t i = kQuicFrameTypeSize; i < 6; ++i) {
     string expected_error;
-    if (i < 1) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < 2) {
+    if (i < 2) {
       expected_error = "Unable to read congestion feedback type.";
     } else if (i < 4) {
       expected_error = "Unable to read accumulated number of lost packets.";
@@ -1855,7 +1761,7 @@
         packet,
         i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
                                 PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-        expected_error, QUIC_INVALID_FRAME_DATA);
+        expected_error, QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
   }
 }
 
@@ -1926,11 +1832,9 @@
             iter->second.Subtract(start_).ToMicroseconds());
 
   // Now test framing boundaries
-  for (size_t i = 0; i < 31; ++i) {
+  for (size_t i = kQuicFrameTypeSize; i < 31; ++i) {
     string expected_error;
-    if (i < 1) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < 2) {
+    if (i < 2) {
       expected_error = "Unable to read congestion feedback type.";
     } else if (i < 4) {
       expected_error = "Unable to read accumulated number of lost packets.";
@@ -1953,7 +1857,7 @@
         packet,
         i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
                                 PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-        expected_error, QUIC_INVALID_FRAME_DATA);
+        expected_error, QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
   }
 }
 
@@ -1994,11 +1898,9 @@
             frame.fix_rate.bitrate.ToBytesPerSecond());
 
   // Now test framing boundaries
-  for (size_t i = 0; i < 6; ++i) {
+  for (size_t i = kQuicFrameTypeSize; i < 6; ++i) {
     string expected_error;
-    if (i < 1) {
-      expected_error = "Unable to read frame type.";
-    } else if (i < 2) {
+    if (i < 2) {
       expected_error = "Unable to read congestion feedback type.";
     } else if (i < 6) {
       expected_error = "Unable to read bitrate.";
@@ -2007,11 +1909,10 @@
         packet,
         i + GetPacketHeaderSize(PACKET_8BYTE_GUID, !kIncludeVersion,
                                 PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
-        expected_error, QUIC_INVALID_FRAME_DATA);
+        expected_error, QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
   }
 }
 
-
 TEST_P(QuicFramerTest, CongestionFeedbackFrameInvalidFeedback) {
   unsigned char packet[] = {
     // public flags (8 byte guid)
@@ -2034,7 +1935,7 @@
   QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false);
   EXPECT_FALSE(framer_.ProcessPacket(encrypted));
   EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion));
-  EXPECT_EQ(QUIC_INVALID_FRAME_DATA, framer_.error());
+  EXPECT_EQ(QUIC_INVALID_CONGESTION_FEEDBACK_DATA, framer_.error());
 }
 
 TEST_P(QuicFramerTest, RstStreamFrame) {
@@ -2078,7 +1979,7 @@
   EXPECT_EQ("because I can", visitor_.rst_stream_frame_.error_details);
 
   // Now test framing boundaries
-  for (size_t i = 2; i < 24; ++i) {
+  for (size_t i = kQuicFrameTypeSize; i < 24; ++i) {
     string expected_error;
     if (i < kQuicFrameTypeSize + kQuicMaxStreamIdSize) {
       expected_error = "Unable to read stream_id.";
@@ -2297,9 +2198,6 @@
 }
 
 TEST_P(QuicFramerTest, VersionNegotiationPacket) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (version, 8 byte guid)
     0x3D,
@@ -2307,7 +2205,7 @@
     0x10, 0x32, 0x54, 0x76,
     0x98, 0xBA, 0xDC, 0xFE,
     // version tag
-    'Q', '0', '0', '7',
+    'Q', '0', '0', (GetParam() == QUIC_VERSION_7 ? '7' : '8'),
     'Q', '2', '.', '0',
   };
 
@@ -2318,8 +2216,7 @@
   ASSERT_EQ(QUIC_NO_ERROR, framer_.error());
   ASSERT_TRUE(visitor_.version_negotiation_packet_.get());
   EXPECT_EQ(2u, visitor_.version_negotiation_packet_->versions.size());
-  EXPECT_EQ(QUIC_VERSION_7,
-            visitor_.version_negotiation_packet_->versions[0]);
+  EXPECT_EQ(GetParam(), visitor_.version_negotiation_packet_->versions[0]);
 
   for (size_t i = 0; i <= kPublicFlagsSize + PACKET_8BYTE_GUID; ++i) {
     string expected_error;
@@ -2554,9 +2451,6 @@
 }
 
 TEST_P(QuicFramerTest, BuildStreamFramePacket) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   QuicPacketHeader header;
   header.public_header.guid = GG_UINT64_C(0xFEDCBA9876543210);
   header.public_header.reset_flag = false;
@@ -2628,8 +2522,6 @@
   QuicFrames frames;
   frames.push_back(QuicFrame(&stream_frame));
 
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
   unsigned char packet[] = {
     // public flags (version, 8 byte guid)
     0x3D,
@@ -2637,7 +2529,7 @@
     0x10, 0x32, 0x54, 0x76,
     0x98, 0xBA, 0xDC, 0xFE,
     // version tag
-    'Q', '0', '0', '7',
+    'Q', '0', '0', (GetParam() == QUIC_VERSION_7 ? '7' : '8'),
     // packet sequence number
     0xBC, 0x9A, 0x78, 0x56,
     0x34, 0x12,
@@ -2680,11 +2572,11 @@
     0x10, 0x32, 0x54, 0x76,
     0x98, 0xBA, 0xDC, 0xFE,
     // version tag
-    'Q', '0', '0', '7',
+    'Q', '0', '0', (GetParam() == QUIC_VERSION_7 ? '7' : '8')
   };
 
   QuicVersionVector versions;
-  versions.push_back(QUIC_VERSION_7);
+  versions.push_back(GetParam());
   scoped_ptr<QuicEncryptedPacket> data(
       framer_.BuildVersionNegotiationPacket(header, versions));
 
@@ -3438,9 +3330,6 @@
 }
 
 TEST_P(QuicFramerTest, EntropyFlagTest) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -3476,9 +3365,6 @@
 };
 
 TEST_P(QuicFramerTest, FecEntropyTest) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
@@ -3516,9 +3402,6 @@
 };
 
 TEST_P(QuicFramerTest, StopPacketProcessing) {
-  // Set a specific version.
-  framer_.set_version(QUIC_VERSION_7);
-
   unsigned char packet[] = {
     // public flags (8 byte guid)
     0x3C,
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 94d1a2e..7358124 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -257,6 +257,10 @@
   delete this;
 }
 
+void QuicHttpStream::SetPriority(RequestPriority priority) {
+  // Nothing to do here (yet).
+}
+
 int QuicHttpStream::OnSendData() {
   // TODO(rch): Change QUIC IO to provide notifications to the streams.
   NOTREACHED();
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h
index 85dc553..cc2b973 100644
--- a/net/quic/quic_http_stream.h
+++ b/net/quic/quic_http_stream.h
@@ -54,6 +54,7 @@
       SSLCertRequestInfo* cert_request_info) OVERRIDE;
   virtual bool IsSpdyHttpStream() const OVERRIDE;
   virtual void Drain(HttpNetworkSession* session) OVERRIDE;
+  virtual void SetPriority(RequestPriority priority) OVERRIDE;
 
   // QuicReliableClientStream::Delegate implementation
   virtual int OnSendData() OVERRIDE;
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index b378416..7d107cb 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -172,6 +172,10 @@
         testing::Return(QuicTime::Delta::Zero()));
     EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _, _)).
         WillRepeatedly(testing::Return(QuicTime::Delta::Zero()));
+    EXPECT_CALL(*send_algorithm_, SmoothedRtt()).WillRepeatedly(
+        testing::Return(QuicTime::Delta::Zero()));
+    EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
+        testing::Return(QuicBandwidth::Zero()));
     helper_ = new QuicConnectionHelper(runner_.get(), &clock_,
                                        &random_generator_, socket);
     connection_ = new TestQuicConnection(guid_, peer_addr_, helper_);
@@ -179,10 +183,12 @@
     connection_->SetSendAlgorithm(send_algorithm_);
     connection_->SetReceiveAlgorithm(receive_algorithm_);
     crypto_config_.SetDefaults();
-    session_.reset(new QuicClientSession(connection_, socket, NULL,
-                                         &crypto_client_stream_factory_,
-                                         "www.google.com", DefaultQuicConfig(),
-                                         &crypto_config_, NULL));
+    session_.reset(
+        new QuicClientSession(connection_,
+                              scoped_ptr<DatagramClientSocket>(socket), NULL,
+                              &crypto_client_stream_factory_,
+                              "www.google.com", DefaultQuicConfig(),
+                              &crypto_config_, NULL));
     session_->GetCryptoStream()->CryptoConnect();
     EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
     stream_.reset(use_closing_stream_ ?
@@ -277,6 +283,7 @@
     header_.public_header.guid = guid_;
     header_.public_header.reset_flag = false;
     header_.public_header.version_flag = should_include_version;
+    header_.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
     header_.packet_sequence_number = sequence_number;
     header_.fec_group = 0;
     header_.entropy_flag = false;
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 0722b58..9d762cc 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -92,6 +92,7 @@
     header.public_header.guid = 0xDEADBEEF;
     header.public_header.reset_flag = false;
     header.public_header.version_flag = false;
+    header.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
     header.packet_sequence_number = num;
     header.entropy_flag = false;
     header.fec_flag = false;
@@ -108,6 +109,7 @@
     header.public_header.guid = 0xDEADBEEF;
     header.public_header.reset_flag = false;
     header.public_header.version_flag = false;
+    header.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
     header.packet_sequence_number = num;
     header.entropy_flag = false;
     header.fec_flag = false;
@@ -129,6 +131,7 @@
     header.public_header.guid = 0xDEADBEEF;
     header.public_header.reset_flag = false;
     header.public_header.version_flag = false;
+    header.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
     header.packet_sequence_number = 2;
     header.entropy_flag = false;
     header.fec_flag = false;
@@ -207,6 +210,7 @@
     header_.public_header.guid = random_generator_.RandUint64();
     header_.public_header.reset_flag = false;
     header_.public_header.version_flag = should_include_version;
+    header_.public_header.sequence_number_length = PACKET_1BYTE_SEQUENCE_NUMBER;
     header_.packet_sequence_number = sequence_number;
     header_.fec_group = 0;
     header_.entropy_flag = false;
@@ -232,6 +236,7 @@
     params_.http_server_properties = http_server_properties.GetWeakPtr();
 
     session_ = new HttpNetworkSession(params_);
+    session_->quic_stream_factory()->set_require_confirmation(false);
   }
 
   void CheckWasQuicResponse(const scoped_ptr<HttpNetworkTransaction>& trans) {
@@ -679,7 +684,11 @@
   host_resolver_.rules()->AddIPLiteralRule("www.google.com", "192.168.0.1", "");
   HostResolver::RequestInfo info(HostPortPair("www.google.com", 80));
   AddressList address;
-  host_resolver_.Resolve(info, &address, CompletionCallback(), NULL,
+  host_resolver_.Resolve(info,
+                         DEFAULT_PRIORITY,
+                         &address,
+                         CompletionCallback(),
+                         NULL,
                          net_log_.bound());
 
   CreateSession();
@@ -687,6 +696,65 @@
   SendRequestAndExpectQuicResponse("hello!");
 }
 
+TEST_F(QuicNetworkTransactionTest, ZeroRTTWithConfirmationRequired) {
+  HttpStreamFactory::EnableNpnSpdy();  // Enables QUIC too.
+
+  scoped_ptr<QuicEncryptedPacket> req(
+      ConstructDataPacket(1, 3, true, true, 0,
+                          GetRequestString("GET", "http", "/")));
+  scoped_ptr<QuicEncryptedPacket> ack(ConstructAckPacket(1, 0));
+
+  MockWrite quic_writes[] = {
+    MockWrite(SYNCHRONOUS, req->data(), req->length()),
+    MockWrite(SYNCHRONOUS, ack->data(), ack->length()),
+  };
+
+  scoped_ptr<QuicEncryptedPacket> resp(
+      ConstructDataPacket(
+          1, 3, false, true, 0, GetResponseString("200 OK", "hello!")));
+  MockRead quic_reads[] = {
+    MockRead(SYNCHRONOUS, resp->data(), resp->length()),
+    MockRead(ASYNC, OK),  // EOF
+  };
+
+  DelayedSocketData quic_data(
+      1,  // wait for one write to finish before reading.
+      quic_reads, arraysize(quic_reads),
+      quic_writes, arraysize(quic_writes));
+
+  socket_factory_.AddSocketDataProvider(&quic_data);
+
+  // The non-alternate protocol job needs to hang in order to guarantee that
+  // the alternate-protocol job will "win".
+  AddHangingNonAlternateProtocolSocketData();
+
+  // In order for a new QUIC session to be established via alternate-protocol
+  // without racing an HTTP connection, we need the host resolution to happen
+  // synchronously.  Of course, even though QUIC *could* perform a 0-RTT
+  // connection to the the server, in this test we require confirmation
+  // before encrypting so the HTTP job will still start.
+  host_resolver_.set_synchronous_mode(true);
+  host_resolver_.rules()->AddIPLiteralRule("www.google.com", "192.168.0.1", "");
+  HostResolver::RequestInfo info(HostPortPair("www.google.com", 80));
+  AddressList address;
+  host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address,
+                         CompletionCallback(), NULL, net_log_.bound());
+
+  CreateSession();
+  session_->quic_stream_factory()->set_require_confirmation(true);
+  AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+  scoped_ptr<HttpNetworkTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
+  TestCompletionCallback callback;
+  int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+
+  crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+      QuicSession::HANDSHAKE_CONFIRMED);
+  EXPECT_EQ(OK, callback.WaitForResult());
+}
+
 TEST_F(QuicNetworkTransactionTest, BrokenAlternateProtocol) {
   HttpStreamFactory::EnableNpnSpdy();  // Enables QUIC too.
 
@@ -748,5 +816,32 @@
   ExpectBrokenAlternateProtocolMapping();
 }
 
+TEST_F(QuicNetworkTransactionTest, FailedZeroRttBrokenAlternateProtocol) {
+  HttpStreamFactory::EnableNpnSpdy();  // Enables QUIC too.
+
+  // Alternate-protocol job
+  MockRead quic_reads[] = {
+    MockRead(ASYNC, ERR_SOCKET_NOT_CONNECTED),
+  };
+  StaticSocketDataProvider quic_data(quic_reads, arraysize(quic_reads),
+                                     NULL, 0);
+  socket_factory_.AddSocketDataProvider(&quic_data);
+
+  AddHangingNonAlternateProtocolSocketData();
+
+  CreateSession();
+
+  AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
+
+  scoped_ptr<HttpNetworkTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get()));
+  TestCompletionCallback callback;
+  int rv = trans->Start(&request_, callback.callback(), net_log_.bound());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+  EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult());
+
+  ExpectBrokenAlternateProtocolMapping();
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 6d69676..387cd37 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -28,10 +28,8 @@
       fec_group_number_(0),
       is_server_(is_server),
       send_version_in_packet_(!is_server),
-      packet_size_(GetPacketHeaderSize(options_.send_guid_length,
-                                       send_version_in_packet_,
-                                       options_.send_sequence_number_length,
-                                       NOT_IN_FEC_GROUP)) {
+      sequence_number_length_(options_.send_sequence_number_length),
+      packet_size_(0) {
   framer_->set_fec_builder(this);
 }
 
@@ -57,11 +55,6 @@
     // Set the fec group number to the sequence number of the next packet.
     fec_group_number_ = sequence_number() + 1;
     fec_group_.reset(new QuicFecGroup());
-    packet_size_ = GetPacketHeaderSize(options_.send_guid_length,
-                                       send_version_in_packet_,
-                                       options_.send_sequence_number_length,
-                                       IN_FEC_GROUP);
-    DCHECK_LE(packet_size_, options_.max_packet_length);
   }
 }
 
@@ -145,12 +138,33 @@
   return bytes_consumed;
 }
 
+SerializedPacket QuicPacketCreator::ReserializeAllFrames(
+    const QuicFrames& frames,
+    QuicSequenceNumberLength original_length) {
+  // Temporarily set the sequence number length and disable FEC.
+  const QuicSequenceNumberLength start_length = sequence_number_length_;
+  const QuicSequenceNumberLength start_options_length =
+      options_.send_sequence_number_length;
+  const QuicFecGroupNumber start_fec_group = fec_group_number_;
+  sequence_number_length_ = original_length;
+  options_.send_sequence_number_length = original_length;
+  fec_group_number_ = 0;
+  SerializedPacket serialized_packet = SerializeAllFrames(frames);
+  sequence_number_length_ = start_length;
+  options_.send_sequence_number_length = start_options_length;
+  fec_group_number_ = start_fec_group;
+  return serialized_packet;
+}
+
 SerializedPacket QuicPacketCreator::SerializeAllFrames(
     const QuicFrames& frames) {
   // TODO(satyamshekhar): Verify that this DCHECK won't fail. What about queued
   // frames from SendStreamData()[send_stream_should_flush_ == false &&
   // data.empty() == true] and retransmit due to RTO.
   DCHECK_EQ(0u, queued_frames_.size());
+  if (frames.empty()) {
+    LOG(DFATAL) << "Attempt to serialize empty packet";
+  }
   for (size_t i = 0; i < frames.size(); ++i) {
     bool success = AddFrame(frames[i], false);
     DCHECK(success);
@@ -167,10 +181,27 @@
 size_t QuicPacketCreator::BytesFree() const {
   const size_t max_plaintext_size =
       framer_->GetMaxPlaintextSize(options_.max_packet_length);
-  if (packet_size_ > max_plaintext_size) {
+  if (PacketSize() >= max_plaintext_size) {
     return 0;
   }
-  return max_plaintext_size - packet_size_;
+  return max_plaintext_size - PacketSize();
+}
+
+size_t QuicPacketCreator::PacketSize() const {
+  if (queued_frames_.empty()) {
+    // Only adjust the sequence number length when the FEC group is not open,
+    // to ensure no packets in a group are too large.
+    if (fec_group_.get() == NULL ||
+        fec_group_->NumReceivedPackets() == 0) {
+      sequence_number_length_ = options_.send_sequence_number_length;
+    }
+    packet_size_ = GetPacketHeaderSize(options_.send_guid_length,
+                                       send_version_in_packet_,
+                                       sequence_number_length_,
+                                       fec_group_number_ == 0 ?
+                                           NOT_IN_FEC_GROUP : IN_FEC_GROUP);
+  }
+  return packet_size_;
 }
 
 bool QuicPacketCreator::AddSavedFrame(const QuicFrame& frame) {
@@ -178,18 +209,16 @@
 }
 
 SerializedPacket QuicPacketCreator::SerializePacket() {
-  DCHECK_EQ(false, queued_frames_.empty());
+  if (queued_frames_.empty()) {
+    LOG(DFATAL) << "Attempt to serialize empty packet";
+  }
   QuicPacketHeader header;
   FillPacketHeader(fec_group_number_, false, false, &header);
 
   SerializedPacket serialized = framer_->BuildDataPacket(
-      header, queued_frames_, packet_size_);
+      header, queued_frames_, PacketSize());
+  packet_size_ = 0;
   queued_frames_.clear();
-  packet_size_ = GetPacketHeaderSize(options_.send_guid_length,
-                                     send_version_in_packet_,
-                                     options_.send_sequence_number_length,
-                                     fec_group_.get() != NULL ?
-                                         IN_FEC_GROUP : NOT_IN_FEC_GROUP);
   serialized.retransmittable_frames = queued_retransmittable_frames_.release();
   return serialized;
 }
@@ -206,11 +235,7 @@
   SerializedPacket serialized = framer_->BuildFecPacket(header, fec_data);
   fec_group_.reset(NULL);
   fec_group_number_ = 0;
-  // Reset packet_size_, since the next packet may not have an FEC group.
-  packet_size_ = GetPacketHeaderSize(options_.send_guid_length,
-                                     send_version_in_packet_,
-                                     options_.send_sequence_number_length,
-                                     NOT_IN_FEC_GROUP);
+  packet_size_ = 0;
   DCHECK(serialized.packet);
   DCHECK_GE(options_.max_packet_length, serialized.packet->length());
   return serialized;
@@ -247,6 +272,7 @@
   header->public_header.version_flag = send_version_in_packet_;
   header->fec_flag = fec_flag;
   header->packet_sequence_number = ++sequence_number_;
+  header->public_header.sequence_number_length = sequence_number_length_;
 
   bool entropy_flag;
   if (header->packet_sequence_number == 1) {
@@ -278,6 +304,7 @@
   if (frame_len == 0) {
     return false;
   }
+  DCHECK_LT(0u, packet_size_);
   packet_size_ += frame_len;
 
   if (save_retransmittable_frames && ShouldRetransmit(frame)) {
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index a1d74fa..e4fc2e7 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -34,7 +34,7 @@
           random_reorder(false),
           max_packets_per_fec_group(0),
           send_guid_length(PACKET_8BYTE_GUID),
-          send_sequence_number_length(PACKET_6BYTE_SEQUENCE_NUMBER) {
+          send_sequence_number_length(PACKET_1BYTE_SEQUENCE_NUMBER) {
     }
 
     size_t max_packet_length;
@@ -95,12 +95,20 @@
   // Never returns a RetransmittableFrames in SerializedPacket.
   SerializedPacket SerializeAllFrames(const QuicFrames& frames);
 
+  // Re-serializes frames with the original packet's sequence number length.
+  // Used for retransmitting packets to ensure they aren't too long.
+  SerializedPacket ReserializeAllFrames(
+      const QuicFrames& frames, QuicSequenceNumberLength original_length);
+
   // 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.
   size_t BytesFree() const;
 
+  // Returns the number of bytes in the current packet, including the header.
+  size_t PacketSize() const;
+
   // Adds |frame| to the packet creator's list of frames to be serialized.
   // Returns false if the frame doesn't fit into the current packet.
   bool AddSavedFrame(const QuicFrame& frame);
@@ -170,7 +178,13 @@
   // Controls whether protocol version should be included while serializing the
   // packet.
   bool send_version_in_packet_;
-  size_t packet_size_;
+  // The sequence number length for the current packet and the current FEC group
+  // if FEC is enabled.
+  // Mutable so PacketSize() can adjust it when the packet is empty.
+  mutable QuicSequenceNumberLength sequence_number_length_;
+  // packet_size_ is mutable because it's just a cache of the current size.
+  // packet_size should never be read directly, use PacketSize() instead.
+  mutable size_t packet_size_;
   QuicFrames queued_frames_;
   scoped_ptr<RetransmittableFrames> queued_retransmittable_frames_;
 
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 1d793d2..193bb88 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -32,7 +32,6 @@
   QuicPacketCreatorTest()
       : server_framer_(QuicVersionMax(), QuicTime::Zero(), true),
         client_framer_(QuicVersionMax(), QuicTime::Zero(), false),
-        id_(1),
         sequence_number_(0),
         guid_(2),
         data_("foo"),
@@ -64,7 +63,6 @@
   QuicFramer server_framer_;
   QuicFramer client_framer_;
   testing::StrictMock<MockFramerVisitor> framer_visitor_;
-  QuicStreamId id_;
   QuicPacketSequenceNumber sequence_number_;
   QuicGuid guid_;
   string data_;
@@ -133,6 +131,120 @@
   delete serialized.packet;
 }
 
+TEST_F(QuicPacketCreatorTest, SerializeChangingSequenceNumberLength) {
+  frames_.push_back(QuicFrame(new QuicAckFrame(0u, QuicTime::Zero(), 0u)));
+  creator_.AddSavedFrame(frames_[0]);
+  creator_.options()->send_sequence_number_length =
+      PACKET_4BYTE_SEQUENCE_NUMBER;
+  SerializedPacket serialized = creator_.SerializePacket();
+  // The sequence number length will not change mid-packet.
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+
+  {
+    InSequence s;
+    EXPECT_CALL(framer_visitor_, OnPacket());
+    EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+    EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+    EXPECT_CALL(framer_visitor_, OnPacketComplete());
+  }
+  ProcessPacket(serialized.packet);
+  delete serialized.packet;
+
+  creator_.AddSavedFrame(frames_[0]);
+  serialized = creator_.SerializePacket();
+  // Now the actual sequence number length should have changed.
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+  delete frames_[0].ack_frame;
+
+  {
+    InSequence s;
+    EXPECT_CALL(framer_visitor_, OnPacket());
+    EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+    EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+    EXPECT_CALL(framer_visitor_, OnPacketComplete());
+  }
+  ProcessPacket(serialized.packet);
+  delete serialized.packet;
+}
+
+TEST_F(QuicPacketCreatorTest, SerializeWithFECChangingSequenceNumberLength) {
+  creator_.options()->max_packets_per_fec_group = 6;
+  ASSERT_FALSE(creator_.ShouldSendFec(false));
+  creator_.MaybeStartFEC();
+
+  frames_.push_back(QuicFrame(new QuicAckFrame(0u, QuicTime::Zero(), 0u)));
+  creator_.AddSavedFrame(frames_[0]);
+  // Change the sequence number length mid-FEC group and it should not change.
+  creator_.options()->send_sequence_number_length =
+      PACKET_4BYTE_SEQUENCE_NUMBER;
+  SerializedPacket serialized = creator_.SerializePacket();
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+
+  {
+    InSequence s;
+    EXPECT_CALL(framer_visitor_, OnPacket());
+    EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+    EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_));
+    EXPECT_CALL(framer_visitor_, OnAckFrame(_));
+    EXPECT_CALL(framer_visitor_, OnPacketComplete());
+  }
+  ProcessPacket(serialized.packet);
+  delete serialized.packet;
+
+  ASSERT_FALSE(creator_.ShouldSendFec(false));
+  ASSERT_TRUE(creator_.ShouldSendFec(true));
+
+  serialized = creator_.SerializeFec();
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+  ASSERT_EQ(2u, serialized.sequence_number);
+
+  {
+    InSequence s;
+    EXPECT_CALL(framer_visitor_, OnPacket());
+    EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+    EXPECT_CALL(framer_visitor_, OnFecData(_));
+    EXPECT_CALL(framer_visitor_, OnPacketComplete());
+  }
+  ProcessPacket(serialized.packet);
+  delete serialized.packet;
+
+  // Ensure the next FEC group starts using the new sequence number length.
+  serialized = creator_.SerializeAllFrames(frames_);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+  delete frames_[0].stream_frame;
+  delete serialized.packet;
+}
+
+TEST_F(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) {
+  // If the original packet sequence number length, the current sequence number
+  // length, and the configured send sequence number length are different, the
+  // retransmit must sent with the original length and the others do not change.
+  creator_.options()->send_sequence_number_length =
+      PACKET_4BYTE_SEQUENCE_NUMBER;
+  QuicPacketCreatorPeer::SetSequenceNumberLength(&creator_,
+                                                 PACKET_2BYTE_SEQUENCE_NUMBER);
+  frames_.push_back(QuicFrame(new QuicStreamFrame(
+      0u, false, 0u, StringPiece(""))));
+  SerializedPacket serialized =
+      creator_.ReserializeAllFrames(frames_, PACKET_1BYTE_SEQUENCE_NUMBER);
+  EXPECT_EQ(PACKET_4BYTE_SEQUENCE_NUMBER,
+            creator_.options()->send_sequence_number_length);
+  EXPECT_EQ(PACKET_2BYTE_SEQUENCE_NUMBER,
+            QuicPacketCreatorPeer::GetSequenceNumberLength(&creator_));
+  EXPECT_EQ(PACKET_1BYTE_SEQUENCE_NUMBER, serialized.sequence_number_length);
+  delete frames_[0].stream_frame;
+
+  {
+    InSequence s;
+    EXPECT_CALL(framer_visitor_, OnPacket());
+    EXPECT_CALL(framer_visitor_, OnPacketHeader(_));
+    EXPECT_CALL(framer_visitor_, OnStreamFrame(_));
+    EXPECT_CALL(framer_visitor_, OnPacketComplete());
+  }
+  ProcessPacket(serialized.packet);
+  delete serialized.packet;
+}
+
 TEST_F(QuicPacketCreatorTest, SerializeConnectionClose) {
   QuicConnectionCloseFrame frame;
   frame.error_code = QUIC_NO_ERROR;
@@ -257,7 +369,7 @@
   creator_.options()->max_packet_length = GetPacketLengthForOneStream(
       client_framer_.version(),
       QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
-      NOT_IN_FEC_GROUP, &payload_length);
+      PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP, &payload_length);
   QuicFrame frame;
   const string too_long_payload(payload_length * 2, 'a');
   size_t consumed = creator_.CreateStreamFrame(
@@ -279,8 +391,7 @@
             GetPacketHeaderSize(
                 creator_.options()->send_guid_length,
                 QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
-                PACKET_6BYTE_SEQUENCE_NUMBER,
-                NOT_IN_FEC_GROUP),
+                PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP),
             creator_.BytesFree());
 
   // Add a variety of frame types and then a padding frame.
@@ -323,7 +434,7 @@
             GetPacketHeaderSize(
                 creator_.options()->send_guid_length,
                 QuicPacketCreatorPeer::SendVersionInPacket(&creator_),
-                PACKET_6BYTE_SEQUENCE_NUMBER,
+                PACKET_1BYTE_SEQUENCE_NUMBER,
                 NOT_IN_FEC_GROUP),
             creator_.BytesFree());
 }
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 7600010..c684cda 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -18,7 +18,7 @@
     : delegate_(delegate),
       debug_delegate_(debug_delegate),
       packet_creator_(creator),
-      should_flush_(true),
+      batch_mode_(false),
       should_send_ack_(false),
       should_send_feedback_(false) {
 }
@@ -70,13 +70,17 @@
                                                   StringPiece data,
                                                   QuicStreamOffset offset,
                                                   bool fin) {
+  IsHandshake handshake = id == kCryptoStreamId ? IS_HANDSHAKE : NOT_HANDSHAKE;
+  // The caller should have flushed pending frames before sending handshake
+  // messages.
+  DCHECK(handshake == NOT_HANDSHAKE || !HasPendingFrames());
   SendQueuedFrames();
 
   size_t total_bytes_consumed = 0;
   bool fin_consumed = false;
 
   while (delegate_->CanWrite(NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA,
-                             NOT_HANDSHAKE)) {
+                             handshake)) {
     QuicFrame frame;
     size_t bytes_consumed = packet_creator_->CreateStreamFrame(
         id, data, offset + total_bytes_consumed, fin, &frame);
@@ -89,7 +93,7 @@
     DCHECK(data.empty() || packet_creator_->BytesFree() == 0u);
 
     // TODO(ianswett): Restore packet reordering.
-    if (should_flush_ || !packet_creator_->HasRoomForStreamFrame(id, offset)) {
+    if (!InBatchMode() || !packet_creator_->HasRoomForStreamFrame(id, offset)) {
       SerializeAndSendPacket();
     }
 
@@ -101,15 +105,15 @@
     }
   }
 
-  // Ensure the FEC group is closed at the end of this method unless other
-  // writes are pending.
-  if (should_flush_ && packet_creator_->ShouldSendFec(true)) {
+  // Ensure the FEC group is closed at the end of this method if not in batch
+  // mode.
+  if (!InBatchMode() && packet_creator_->ShouldSendFec(true)) {
     SerializedPacket serialized_fec = packet_creator_->SerializeFec();
     DCHECK(serialized_fec.packet);
     delegate_->OnSerializedPacket(serialized_fec);
   }
 
-  DCHECK(!should_flush_ || !packet_creator_->HasPendingFrames());
+  DCHECK(InBatchMode() || !packet_creator_->HasPendingFrames());
   return QuicConsumedData(total_bytes_consumed, fin_consumed);
 }
 
@@ -135,7 +139,7 @@
     }
   }
 
-  if (should_flush_) {
+  if (!InBatchMode()) {
     if (packet_creator_->HasPendingFrames()) {
       SerializeAndSendPacket();
     }
@@ -151,12 +155,16 @@
   }
 }
 
+bool QuicPacketGenerator::InBatchMode() {
+  return batch_mode_;
+}
+
 void QuicPacketGenerator::StartBatchOperations() {
-  should_flush_ = false;
+  batch_mode_ = true;
 }
 
 void QuicPacketGenerator::FinishBatchOperations() {
-  should_flush_ = true;
+  batch_mode_ = false;
   SendQueuedFrames();
 }
 
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index e8b09e6..f61e6e4 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -95,6 +95,8 @@
                                QuicStreamOffset offset,
                                bool fin);
 
+  // Indicates whether batch mode is currently enabled.
+  bool InBatchMode();
   // Disables flushing.
   void StartBatchOperations();
   // Enables flushing and flushes queued data.
@@ -126,7 +128,10 @@
 
   QuicPacketCreator* packet_creator_;
   QuicFrames queued_control_frames_;
-  bool should_flush_;
+
+  // True if batch mode is currently enabled.
+  bool batch_mode_;
+
   // Flags to indicate the need for just-in-time construction of a frame.
   bool should_send_ack_;
   bool should_send_feedback_;
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 45556f1..8832042 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -21,6 +21,7 @@
 using testing::InSequence;
 using testing::Return;
 using testing::SaveArg;
+using testing::StrictMock;
 using testing::_;
 
 namespace net {
@@ -98,11 +99,11 @@
       : framer_(QuicVersionMax(), QuicTime::Zero(), false),
         creator_(42, &framer_, &random_, false),
         generator_(&delegate_, NULL, &creator_),
-        packet_(0, NULL, 0, NULL),
-        packet2_(0, NULL, 0, NULL),
-        packet3_(0, NULL, 0, NULL),
-        packet4_(0, NULL, 0, NULL),
-        packet5_(0, NULL, 0, NULL) {
+        packet_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
+        packet2_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
+        packet3_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
+        packet4_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL),
+        packet5_(0, PACKET_1BYTE_SEQUENCE_NUMBER, NULL, 0, NULL) {
   }
 
   ~QuicPacketGeneratorTest() {
@@ -198,7 +199,7 @@
   QuicFramer framer_;
   MockRandom random_;
   QuicPacketCreator creator_;
-  testing::StrictMock<MockDelegate> delegate_;
+  StrictMock<MockDelegate> delegate_;
   QuicPacketGenerator generator_;
   SimpleQuicFramer simple_framer_;
   SerializedPacket packet_;
@@ -211,6 +212,12 @@
   scoped_ptr<char[]> data_array_;
 };
 
+class MockDebugDelegate : public QuicPacketGenerator::DebugDelegateInterface {
+ public:
+  MOCK_METHOD1(OnFrameAddedToPacket,
+               void(const QuicFrame&));
+};
+
 TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) {
   delegate_.SetCanNotWrite();
 
@@ -219,10 +226,14 @@
 }
 
 TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) {
+  StrictMock<MockDebugDelegate> debug_delegate;
+
+  generator_.set_debug_delegate(&debug_delegate);
   delegate_.SetCanWriteOnlyNonRetransmittable();
   generator_.StartBatchOperations();
 
   EXPECT_CALL(delegate_, CreateAckFrame()).WillOnce(Return(CreateAckFrame()));
+  EXPECT_CALL(debug_delegate, OnFrameAddedToPacket(_)).Times(1);
 
   generator_.SetShouldSendAck(false);
   EXPECT_TRUE(generator_.HasQueuedFrames());
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 4c2e552..0a4b1b0 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -74,15 +74,6 @@
 
 QuicPacketPublicHeader::~QuicPacketPublicHeader() {}
 
-QuicPacketPublicHeader& QuicPacketPublicHeader::operator=(
-    const QuicPacketPublicHeader& other) {
-  guid = other.guid;
-  reset_flag = other.reset_flag;
-  version_flag = other.version_flag;
-  versions = other.versions;
-  return *this;
-}
-
 QuicPacketHeader::QuicPacketHeader()
     : fec_flag(false),
       entropy_flag(false),
@@ -184,6 +175,8 @@
 ostream& operator<<(ostream& os, const QuicPacketHeader& header) {
   os << "{ guid: " << header.public_header.guid
      << ", guid_length:" << header.public_header.guid_length
+     << ", sequence_number_length:"
+     << header.public_header.sequence_number_length
      << ", reset_flag: " << header.public_header.reset_flag
      << ", version_flag: " << header.public_header.version_flag;
   if (header.public_header.version_flag) {
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 737bb16..39105a3 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -278,110 +278,119 @@
   QUIC_STREAM_LAST_ERROR,
 };
 
+// These values must remain stable as they are uploaded to UMA histograms.
+// To add a new error code, use the current value of QUIC_LAST_ERROR and
+// increment QUIC_LAST_ERROR.
 enum QuicErrorCode {
   QUIC_NO_ERROR = 0,
 
   // Connection has reached an invalid state.
-  QUIC_INTERNAL_ERROR,
+  QUIC_INTERNAL_ERROR = 1,
   // There were data frames after the a fin or reset.
-  QUIC_STREAM_DATA_AFTER_TERMINATION,
+  QUIC_STREAM_DATA_AFTER_TERMINATION = 2,
   // Control frame is malformed.
-  QUIC_INVALID_PACKET_HEADER,
+  QUIC_INVALID_PACKET_HEADER = 3,
   // Frame data is malformed.
-  QUIC_INVALID_FRAME_DATA,
+  QUIC_INVALID_FRAME_DATA = 4,
+  // The packet contained no payload.
+  QUIC_MISSING_PAYLOAD = 48,
   // FEC data is malformed.
-  QUIC_INVALID_FEC_DATA,
-  // Stream rst data is malformed
-  QUIC_INVALID_RST_STREAM_DATA,
-  // Connection close data is malformed.
-  QUIC_INVALID_CONNECTION_CLOSE_DATA,
-  // GoAway data is malformed.
-  QUIC_INVALID_GOAWAY_DATA,
-  // Ack data is malformed.
-  QUIC_INVALID_ACK_DATA,
+  QUIC_INVALID_FEC_DATA = 5,
+  // STREAM frame data is malformed.
+  QUIC_INVALID_STREAM_DATA = 46,
+  // RST_STREAM frame data is malformed.
+  QUIC_INVALID_RST_STREAM_DATA = 6,
+  // CONNECTION_CLOSE frame data is malformed.
+  QUIC_INVALID_CONNECTION_CLOSE_DATA = 7,
+  // GOAWAY frame data is malformed.
+  QUIC_INVALID_GOAWAY_DATA = 8,
+  // ACK frame data is malformed.
+  QUIC_INVALID_ACK_DATA = 9,
+  // CONGESTION_FEEDBACK frame data is malformed.
+  QUIC_INVALID_CONGESTION_FEEDBACK_DATA = 47,
   // Version negotiation packet is malformed.
-  QUIC_INVALID_VERSION_NEGOTIATION_PACKET,
+  QUIC_INVALID_VERSION_NEGOTIATION_PACKET = 10,
   // Public RST packet is malformed.
-  QUIC_INVALID_PUBLIC_RST_PACKET,
+  QUIC_INVALID_PUBLIC_RST_PACKET = 11,
   // There was an error decrypting.
-  QUIC_DECRYPTION_FAILURE,
+  QUIC_DECRYPTION_FAILURE = 12,
   // There was an error encrypting.
-  QUIC_ENCRYPTION_FAILURE,
+  QUIC_ENCRYPTION_FAILURE = 13,
   // The packet exceeded kMaxPacketSize.
-  QUIC_PACKET_TOO_LARGE,
+  QUIC_PACKET_TOO_LARGE = 14,
   // Data was sent for a stream which did not exist.
-  QUIC_PACKET_FOR_NONEXISTENT_STREAM,
+  QUIC_PACKET_FOR_NONEXISTENT_STREAM = 15,
   // The peer is going away.  May be a client or server.
-  QUIC_PEER_GOING_AWAY,
+  QUIC_PEER_GOING_AWAY = 16,
   // A stream ID was invalid.
-  QUIC_INVALID_STREAM_ID,
+  QUIC_INVALID_STREAM_ID = 17,
   // Too many streams already open.
-  QUIC_TOO_MANY_OPEN_STREAMS,
+  QUIC_TOO_MANY_OPEN_STREAMS = 18,
   // Received public reset for this connection.
-  QUIC_PUBLIC_RESET,
+  QUIC_PUBLIC_RESET = 19,
   // Invalid protocol version.
-  QUIC_INVALID_VERSION,
+  QUIC_INVALID_VERSION = 20,
   // Stream reset before headers decompressed.
-  QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED,
+  QUIC_STREAM_RST_BEFORE_HEADERS_DECOMPRESSED = 21,
   // The Header ID for a stream was too far from the previous.
-  QUIC_INVALID_HEADER_ID,
+  QUIC_INVALID_HEADER_ID = 22,
   // Negotiable parameter received during handshake had invalid value.
-  QUIC_INVALID_NEGOTIATED_VALUE,
+  QUIC_INVALID_NEGOTIATED_VALUE = 23,
   // There was an error decompressing data.
-  QUIC_DECOMPRESSION_FAILURE,
+  QUIC_DECOMPRESSION_FAILURE = 24,
   // We hit our prenegotiated (or default) timeout
-  QUIC_CONNECTION_TIMED_OUT,
+  QUIC_CONNECTION_TIMED_OUT = 25,
   // There was an error encountered migrating addresses
-  QUIC_ERROR_MIGRATING_ADDRESS,
+  QUIC_ERROR_MIGRATING_ADDRESS = 26,
   // There was an error while writing the packet.
-  QUIC_PACKET_WRITE_ERROR,
+  QUIC_PACKET_WRITE_ERROR = 27,
 
 
   // Crypto errors.
 
   // Hanshake failed.
-  QUIC_HANDSHAKE_FAILED,
+  QUIC_HANDSHAKE_FAILED = 28,
   // Handshake message contained out of order tags.
-  QUIC_CRYPTO_TAGS_OUT_OF_ORDER,
+  QUIC_CRYPTO_TAGS_OUT_OF_ORDER = 29,
   // Handshake message contained too many entries.
-  QUIC_CRYPTO_TOO_MANY_ENTRIES,
+  QUIC_CRYPTO_TOO_MANY_ENTRIES = 30,
   // Handshake message contained an invalid value length.
-  QUIC_CRYPTO_INVALID_VALUE_LENGTH,
+  QUIC_CRYPTO_INVALID_VALUE_LENGTH = 31,
   // A crypto message was received after the handshake was complete.
-  QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE,
+  QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE = 32,
   // A crypto message was received with an illegal message tag.
-  QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
+  QUIC_INVALID_CRYPTO_MESSAGE_TYPE = 33,
   // A crypto message was received with an illegal parameter.
-  QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER,
+  QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER = 34,
   // A crypto message was received with a mandatory parameter missing.
-  QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
+  QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND = 35,
   // A crypto message was received with a parameter that has no overlap
   // with the local parameter.
-  QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP,
+  QUIC_CRYPTO_MESSAGE_PARAMETER_NO_OVERLAP = 36,
   // A crypto message was received that contained a parameter with too few
   // values.
-  QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND,
+  QUIC_CRYPTO_MESSAGE_INDEX_NOT_FOUND = 37,
   // An internal error occured in crypto processing.
-  QUIC_CRYPTO_INTERNAL_ERROR,
+  QUIC_CRYPTO_INTERNAL_ERROR = 38,
   // A crypto handshake message specified an unsupported version.
-  QUIC_CRYPTO_VERSION_NOT_SUPPORTED,
+  QUIC_CRYPTO_VERSION_NOT_SUPPORTED = 39,
   // There was no intersection between the crypto primitives supported by the
   // peer and ourselves.
-  QUIC_CRYPTO_NO_SUPPORT,
+  QUIC_CRYPTO_NO_SUPPORT = 40,
   // The server rejected our client hello messages too many times.
-  QUIC_CRYPTO_TOO_MANY_REJECTS,
+  QUIC_CRYPTO_TOO_MANY_REJECTS = 41,
   // The client rejected the server's certificate chain or signature.
-  QUIC_PROOF_INVALID,
+  QUIC_PROOF_INVALID = 42,
   // A crypto message was received with a duplicate tag.
-  QUIC_CRYPTO_DUPLICATE_TAG,
+  QUIC_CRYPTO_DUPLICATE_TAG = 43,
   // A crypto message was received with the wrong encryption level (i.e. it
   // should have been encrypted but was not.)
-  QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
+  QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT = 44,
   // The server config for a server has expired.
-  QUIC_CRYPTO_SERVER_CONFIG_EXPIRED,
+  QUIC_CRYPTO_SERVER_CONFIG_EXPIRED = 45,
 
   // No error. Used as bound while iterating.
-  QUIC_LAST_ERROR,
+  QUIC_LAST_ERROR = 49,
 };
 
 struct NET_EXPORT_PRIVATE QuicPacketPublicHeader {
@@ -389,8 +398,6 @@
   explicit QuicPacketPublicHeader(const QuicPacketPublicHeader& other);
   ~QuicPacketPublicHeader();
 
-  QuicPacketPublicHeader& operator=(const QuicPacketPublicHeader& other);
-
   // Universal header. All QuicPacket headers will have a guid and public flags.
   QuicGuid guid;
   QuicGuidLength guid_length;
@@ -675,10 +682,6 @@
   base::StringPiece redundancy;
 };
 
-struct NET_EXPORT_PRIVATE QuicPacketData {
-  std::string data;
-};
-
 class NET_EXPORT_PRIVATE QuicData {
  public:
   QuicData(const char* buffer, size_t length)
@@ -739,8 +742,6 @@
 
   bool is_fec_packet() const { return is_fec_packet_; }
 
-  bool includes_version() const { return includes_version_; }
-
   char* mutable_data() { return buffer_; }
 
  private:
@@ -815,15 +816,18 @@
 
 struct NET_EXPORT_PRIVATE SerializedPacket {
   SerializedPacket(QuicPacketSequenceNumber sequence_number,
+                   QuicSequenceNumberLength sequence_number_length,
                    QuicPacket* packet,
                    QuicPacketEntropyHash entropy_hash,
                    RetransmittableFrames* retransmittable_frames)
       : sequence_number(sequence_number),
+        sequence_number_length(sequence_number_length),
         packet(packet),
         entropy_hash(entropy_hash),
         retransmittable_frames(retransmittable_frames) {}
 
   QuicPacketSequenceNumber sequence_number;
+  QuicSequenceNumberLength sequence_number_length;
   QuicPacket* packet;
   QuicPacketEntropyHash entropy_hash;
   RetransmittableFrames* retransmittable_frames;
diff --git a/net/quic/quic_sent_entropy_manager.h b/net/quic/quic_sent_entropy_manager.h
index 4f684fc..a101e73 100644
--- a/net/quic/quic_sent_entropy_manager.h
+++ b/net/quic/quic_sent_entropy_manager.h
@@ -40,10 +40,6 @@
   // |sequence_number|.
   void ClearEntropyBefore(QuicPacketSequenceNumber sequence_number);
 
-  QuicPacketEntropyHash packets_entropy_hash() const {
-    return packets_entropy_hash_;
-  }
-
  private:
   typedef linked_hash_map<QuicPacketSequenceNumber,
                           std::pair<QuicPacketEntropyHash,
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index a07f413..aa83ab0 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -190,13 +190,16 @@
 bool QuicSession::OnCanWrite() {
   // We latch this here rather than doing a traditional loop, because streams
   // may be modifying the list as we loop.
-  int remaining_writes = write_blocked_streams_.NumObjects();
+  int remaining_writes = write_blocked_streams_.NumBlockedStreams();
 
   while (!connection_->HasQueuedData() &&
          remaining_writes > 0) {
-    DCHECK(!write_blocked_streams_.IsEmpty());
-    ReliableQuicStream* stream =
-        GetStream(write_blocked_streams_.GetNextBlockedObject());
+    DCHECK(write_blocked_streams_.HasWriteBlockedStreams());
+    ReliableQuicStream* stream = NULL;
+    int index = write_blocked_streams_.GetHighestPriorityWriteBlockedList();
+    if (index != -1) {
+      stream = GetStream(write_blocked_streams_.PopFront(index));
+    }
     if (stream != NULL) {
       // If the stream can't write all bytes, it'll re-add itself to the blocked
       // list.
@@ -205,7 +208,7 @@
     --remaining_writes;
   }
 
-  return write_blocked_streams_.IsEmpty();
+  return !write_blocked_streams_.HasWriteBlockedStreams();
 }
 
 QuicConsumedData QuicSession::WriteData(QuicStreamId id,
@@ -283,6 +286,14 @@
   }
 }
 
+void QuicSession::OnCryptoHandshakeMessageSent(
+    const CryptoHandshakeMessage& message) {
+}
+
+void QuicSession::OnCryptoHandshakeMessageReceived(
+    const CryptoHandshakeMessage& message) {
+}
+
 QuicConfig* QuicSession::config() {
   return &config_;
 }
@@ -385,7 +396,7 @@
 }
 
 void QuicSession::MarkWriteBlocked(QuicStreamId id) {
-  write_blocked_streams_.AddBlockedObject(id);
+  write_blocked_streams_.PushBack(id, 0);
 }
 
 void QuicSession::MarkDecompressionBlocked(QuicHeaderId header_id,
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 9f7aceb..75c3ea0 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -13,7 +13,6 @@
 #include "base/containers/hash_tables.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/linked_hash_map.h"
-#include "net/quic/blocked_list.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_crypto_stream.h"
 #include "net/quic/quic_packet_creator.h"
@@ -21,6 +20,7 @@
 #include "net/quic/quic_spdy_compressor.h"
 #include "net/quic/quic_spdy_decompressor.h"
 #include "net/quic/reliable_quic_stream.h"
+#include "net/spdy/write_blocked_list.h"
 
 namespace net {
 
@@ -106,6 +106,14 @@
   // Servers will simply call it once with HANDSHAKE_CONFIRMED.
   virtual void OnCryptoHandshakeEvent(CryptoHandshakeEvent event);
 
+  // Called by the QuicCryptoStream when a handshake message is sent.
+  virtual void OnCryptoHandshakeMessageSent(
+      const CryptoHandshakeMessage& message);
+
+  // Called by the QuicCryptoStream when a handshake message is received.
+  virtual void OnCryptoHandshakeMessageReceived(
+      const CryptoHandshakeMessage& message);
+
   // Returns mutable config for this session. Returned config is owned
   // by QuicSession.
   QuicConfig* config();
@@ -234,7 +242,7 @@
   base::hash_set<QuicStreamId> implicitly_created_streams_;
 
   // A list of streams which need to write more data.
-  BlockedList<QuicStreamId> write_blocked_streams_;
+  WriteBlockedList<QuicStreamId> write_blocked_streams_;
 
   // A map of headers waiting to be compressed, and the streams
   // they are associated with.
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index e417c43..4df7222 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -125,11 +125,13 @@
   QuicGuid guid_;
   MockConnection* connection_;
   TestSession session_;
-  QuicConnectionVisitorInterface* visitor_;
-  hash_map<QuicStreamId, ReliableQuicStream*>* streams_;
   set<QuicStreamId> closed_streams_;
 };
 
+TEST_F(QuicSessionTest, PeerAddress) {
+  EXPECT_EQ(IPEndPoint(), session_.peer_address());
+}
+
 TEST_F(QuicSessionTest, IsCryptoHandshakeConfirmed) {
   EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed());
   CryptoHandshakeMessage message;
diff --git a/net/quic/quic_stats.cc b/net/quic/quic_stats.cc
deleted file mode 100644
index 7404d92..0000000
--- a/net/quic/quic_stats.cc
+++ /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.
-
-#include "net/quic/quic_stats.h"
-
-namespace net {
-
-QuicConnectionStats::QuicConnectionStats()
-    : bytes_sent(0),
-      packets_sent(0),
-      bytes_received(0),
-      packets_received(0),
-      bytes_retransmitted(0),
-      packets_retransmitted(0),
-      packets_revived(0),
-      packets_dropped(0),
-      rto_count(0),
-      rtt(0),
-      estimated_bandwidth(0) {
-}
-
-QuicConnectionStats::~QuicConnectionStats() {}
-
-}  // namespace net
diff --git a/net/quic/quic_stats.h b/net/quic/quic_stats.h
deleted file mode 100644
index 252791e..0000000
--- a/net/quic/quic_stats.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 NET_QUIC_QUIC_STATS_H_
-#define NET_QUIC_QUIC_STATS_H_
-
-#include "base/basictypes.h"
-#include "net/base/net_export.h"
-
-namespace net {
-// TODO(satyamshekhar): Add more interesting stats:
-// 1. (C/S)HLO retransmission count.
-// 2. SHLO received to first stream packet processed time.
-// 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.
-
-// Structure to hold stats for a QuicConnection.
-struct NET_EXPORT_PRIVATE QuicConnectionStats {
-  QuicConnectionStats();
-  ~QuicConnectionStats();
-
-  uint64 bytes_sent;  // includes retransmissions, fec.
-  uint32 packets_sent;
-
-  uint64 bytes_received;  // includes duplicate data for a stream, fec.
-  uint32 packets_received;  // includes dropped packets
-
-  uint64 bytes_retransmitted;
-  uint32 packets_retransmitted;
-
-  uint32 packets_revived;
-  uint32 packets_dropped;  // duplicate or less than least unacked.
-  uint32 rto_count;
-
-  uint32 rtt;
-  uint64 estimated_bandwidth;
-  // TODO(satyamshekhar): Add window_size, mss and mtu.
-};
-
-}  // namespace net
-
-#endif  // NET_QUIC_QUIC_STATS_H_
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index fba7f0b..2986dd2 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -16,6 +16,7 @@
 #include "net/cert/cert_verifier.h"
 #include "net/dns/host_resolver.h"
 #include "net/dns/single_request_host_resolver.h"
+#include "net/http/http_server_properties.h"
 #include "net/quic/crypto/proof_verifier_chromium.h"
 #include "net/quic/crypto/quic_random.h"
 #include "net/quic/quic_client_session.h"
@@ -147,9 +148,10 @@
 int QuicStreamFactory::Job::DoResolveHost() {
   io_state_ = STATE_RESOLVE_HOST_COMPLETE;
   return host_resolver_.Resolve(
-      HostResolver::RequestInfo(host_port_proxy_pair_.first), &address_list_,
-      base::Bind(&QuicStreamFactory::Job::OnIOComplete,
-                 base::Unretained(this)),
+      HostResolver::RequestInfo(host_port_proxy_pair_.first),
+      DEFAULT_PRIORITY,
+      &address_list_,
+      base::Bind(&QuicStreamFactory::Job::OnIOComplete, base::Unretained(this)),
       net_log_);
 }
 
@@ -226,6 +228,7 @@
                                      cert_verifier_, address_list_, net_log_);
   session_->StartReading();
   int rv = session_->CryptoConnect(
+      factory_->require_confirmation(),
       base::Bind(&QuicStreamFactory::Job::OnIOComplete,
                  base::Unretained(this)));
   return rv;
@@ -244,11 +247,14 @@
 QuicStreamFactory::QuicStreamFactory(
     HostResolver* host_resolver,
     ClientSocketFactory* client_socket_factory,
+    base::WeakPtr<HttpServerProperties> http_server_properties,
     QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
     QuicRandom* random_generator,
     QuicClock* clock)
-    : host_resolver_(host_resolver),
+    : require_confirmation_(true),
+      host_resolver_(host_resolver),
       client_socket_factory_(client_socket_factory),
+      http_server_properties_(http_server_properties),
       quic_crypto_client_stream_factory_(quic_crypto_client_stream_factory),
       random_generator_(random_generator),
       clock_(clock),
@@ -301,6 +307,7 @@
 
 void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
   if (rv == OK) {
+    require_confirmation_ = false;
     // Create all the streams, but do not notify them yet.
     for (RequestSet::iterator it = job_requests_map_[job].begin();
          it != job_requests_map_[job].end() ; ++it) {
@@ -351,6 +358,13 @@
     DCHECK(active_sessions_.count(*it));
     DCHECK_EQ(session, active_sessions_[*it]);
     active_sessions_.erase(*it);
+    if (!session->IsCryptoHandshakeConfirmed() && http_server_properties_) {
+      // TODO(rch):  In the special case where the session has received no
+      // packets from the peer, we should consider blacklisting this
+      // differently so that we still race TCP but we don't consider the
+      // session connected until the handshake has been confirmed.
+      http_server_properties_->SetBrokenAlternateProtocol(it->first);
+    }
   }
   all_sessions_.erase(session);
   session_aliases_.erase(session);
@@ -393,6 +407,7 @@
 
 void QuicStreamFactory::OnIPAddressChanged() {
   CloseAllSessions(ERR_NETWORK_CHANGED);
+  require_confirmation_ = true;
 }
 
 bool QuicStreamFactory::HasActiveSession(
@@ -408,10 +423,10 @@
     const BoundNetLog& net_log) {
   QuicGuid guid = random_generator_->RandUint64();
   IPEndPoint addr = *address_list.begin();
-  DatagramClientSocket* socket =
+  scoped_ptr<DatagramClientSocket> socket(
       client_socket_factory_->CreateDatagramClientSocket(
           DatagramSocket::DEFAULT_BIND, base::Bind(&base::RandInt),
-          net_log.net_log(), net_log.source());
+          net_log.net_log(), net_log.source()));
   socket->Connect(addr);
 
   // We should adaptively set this buffer size, but for now, we'll use a size
@@ -437,7 +452,7 @@
       base::MessageLoop::current()->message_loop_proxy().get(),
       clock_.get(),
       random_generator_,
-      socket);
+      socket.get());
 
   QuicConnection* connection = new QuicConnection(guid, addr, helper, false,
                                                   QuicVersionMax());
@@ -447,7 +462,7 @@
   DCHECK(crypto_config);
 
   QuicClientSession* session =
-      new QuicClientSession(connection, socket, this,
+      new QuicClientSession(connection, socket.Pass(), this,
                             quic_crypto_client_stream_factory_,
                             host_port_proxy_pair.first.host(), config_,
                             crypto_config, net_log.net_log());
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 963a603..2319e72 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -25,6 +25,7 @@
 class CertVerifier;
 class ClientSocketFactory;
 class HostResolver;
+class HttpServerProperties;
 class QuicClock;
 class QuicClientSession;
 class QuicCryptoClientStreamFactory;
@@ -76,6 +77,7 @@
   QuicStreamFactory(
       HostResolver* host_resolver,
       ClientSocketFactory* client_socket_factory,
+      base::WeakPtr<HttpServerProperties> http_server_properties,
       QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory,
       QuicRandom* random_generator,
       QuicClock* clock);
@@ -120,6 +122,12 @@
   // IP address changes.
   virtual void OnIPAddressChanged() OVERRIDE;
 
+  bool require_confirmation() const { return require_confirmation_; }
+
+  void set_require_confirmation(bool require_confirmation) {
+    require_confirmation_ = require_confirmation;
+  }
+
  private:
   class Job;
 
@@ -148,8 +156,10 @@
   QuicCryptoClientConfig* GetOrCreateCryptoConfig(
       const HostPortProxyPair& host_port_proxy_pair);
 
+  bool require_confirmation_;
   HostResolver* host_resolver_;
   ClientSocketFactory* client_socket_factory_;
+  base::WeakPtr<HttpServerProperties> http_server_properties_;
   QuicCryptoClientStreamFactory* quic_crypto_client_stream_factory_;
   QuicRandom* random_generator_;
   scoped_ptr<QuicClock> clock_;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 2f46772..5c604ea 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -29,12 +29,14 @@
   QuicStreamFactoryTest()
       : clock_(new MockClock()),
         factory_(&host_resolver_, &socket_factory_,
+                 base::WeakPtr<HttpServerProperties>(),
                  &crypto_client_stream_factory_,
                  &random_generator_, clock_),
         host_port_proxy_pair_(HostPortPair("www.google.com", 443),
                               ProxyServer::Direct()),
         is_https_(false),
         cert_verifier_(CertVerifier::CreateDefault()) {
+    factory_.set_require_confirmation(false);
   }
 
   scoped_ptr<QuicEncryptedPacket> ConstructRstPacket(
@@ -342,6 +344,7 @@
   factory_.OnIPAddressChanged();
   EXPECT_EQ(ERR_NETWORK_CHANGED,
             stream->ReadResponseHeaders(callback_.callback()));
+  EXPECT_TRUE(factory_.require_confirmation());
 
   // Now attempting to request a stream to the same origin should create
   // a new session.
diff --git a/net/quic/quic_stream_sequencer.h b/net/quic/quic_stream_sequencer.h
index fe9fba5..a450bef 100644
--- a/net/quic/quic_stream_sequencer.h
+++ b/net/quic/quic_stream_sequencer.h
@@ -29,8 +29,6 @@
 // TOOD(alyssar) add some checks for overflow attempts [1, 256,] [2, 256]
 class NET_EXPORT_PRIVATE QuicStreamSequencer {
  public:
-  static size_t kMaxUdpPacketSize;
-
   explicit QuicStreamSequencer(ReliableQuicStream* quic_stream);
   QuicStreamSequencer(size_t max_frame_memory,
                       ReliableQuicStream* quic_stream);
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 0d40db9..878585b 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -58,11 +58,8 @@
   void SetMemoryLimit(size_t limit) {
     max_frame_memory_ = limit;
   }
-
-  const ReliableQuicStream* stream() const { return stream_; }
   uint64 num_bytes_consumed() const { return num_bytes_consumed_; }
   const FrameMap* frames() const { return &frames_; }
-  int32 max_frame_memory() const { return max_frame_memory_; }
   QuicStreamOffset close_offset() const { return close_offset_; }
 };
 
diff --git a/net/quic/quic_time_test.cc b/net/quic/quic_time_test.cc
index c4ea0e2..18b1de4 100644
--- a/net/quic/quic_time_test.cc
+++ b/net/quic/quic_time_test.cc
@@ -9,23 +9,19 @@
 namespace net {
 namespace test {
 
-class QuicTimeDeltaTest : public ::testing::Test {
- protected:
-};
-
-TEST_F(QuicTimeDeltaTest, Zero) {
+TEST(QuicTimeDeltaTest, Zero) {
   EXPECT_TRUE(QuicTime::Delta::Zero().IsZero());
   EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite());
   EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsZero());
 }
 
-TEST_F(QuicTimeDeltaTest, Infinite) {
+TEST(QuicTimeDeltaTest, Infinite) {
   EXPECT_TRUE(QuicTime::Delta::Infinite().IsInfinite());
   EXPECT_FALSE(QuicTime::Delta::Zero().IsInfinite());
   EXPECT_FALSE(QuicTime::Delta::FromMilliseconds(1).IsInfinite());
 }
 
-TEST_F(QuicTimeDeltaTest, FromTo) {
+TEST(QuicTimeDeltaTest, FromTo) {
   EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1),
             QuicTime::Delta::FromMicroseconds(1000));
   EXPECT_EQ(QuicTime::Delta::FromSeconds(1),
@@ -41,17 +37,24 @@
             QuicTime::Delta::FromSeconds(2).ToMicroseconds());
 }
 
-TEST_F(QuicTimeDeltaTest, Add) {
+TEST(QuicTimeDeltaTest, Add) {
   EXPECT_EQ(QuicTime::Delta::FromMicroseconds(2000),
             QuicTime::Delta::Zero().Add(QuicTime::Delta::FromMilliseconds(2)));
 }
 
-TEST_F(QuicTimeDeltaTest, Subtract) {
+TEST(QuicTimeDeltaTest, Subtract) {
   EXPECT_EQ(QuicTime::Delta::FromMicroseconds(1000),
             QuicTime::Delta::FromMilliseconds(2).Subtract(
                 QuicTime::Delta::FromMilliseconds(1)));
 }
 
+TEST(QuicTimeDeltaTest, NotEqual) {
+  EXPECT_TRUE(QuicTime::Delta::FromSeconds(0) !=
+              QuicTime::Delta::FromSeconds(1));
+  EXPECT_FALSE(QuicTime::Delta::FromSeconds(0) !=
+               QuicTime::Delta::FromSeconds(0));
+}
+
 class QuicTimeTest : public ::testing::Test {
  protected:
   MockClock clock_;
@@ -109,5 +112,14 @@
   EXPECT_EQ(now, time);
 }
 
+TEST_F(QuicTimeTest, LE) {
+  const QuicTime zero = QuicTime::Zero();
+  const QuicTime one  = zero.Add(QuicTime::Delta::FromSeconds(1));
+  EXPECT_TRUE(zero <= zero);
+  EXPECT_TRUE(zero <= one);
+  EXPECT_TRUE(one <= one);
+  EXPECT_FALSE(one <= zero);
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index 1795744..9c79a9b 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -111,14 +111,6 @@
   memcpy(out + sizeof(lo), &hi, sizeof(hi));
 }
 
-// static
-uint128 QuicUtils::ParseUint128(const uint8* in) {
-  uint64 lo, hi;
-  memcpy(&lo, in, sizeof(lo));
-  memcpy(&hi, in + sizeof(lo), sizeof(hi));
-  return uint128(hi, lo);
-}
-
 #define RETURN_STRING_LITERAL(x) \
 case x: \
 return #x;
@@ -148,11 +140,14 @@
     RETURN_STRING_LITERAL(QUIC_STREAM_DATA_AFTER_TERMINATION);
     RETURN_STRING_LITERAL(QUIC_INVALID_PACKET_HEADER);
     RETURN_STRING_LITERAL(QUIC_INVALID_FRAME_DATA);
+    RETURN_STRING_LITERAL(QUIC_MISSING_PAYLOAD);
     RETURN_STRING_LITERAL(QUIC_INVALID_FEC_DATA);
+    RETURN_STRING_LITERAL(QUIC_INVALID_STREAM_DATA);
     RETURN_STRING_LITERAL(QUIC_INVALID_RST_STREAM_DATA);
     RETURN_STRING_LITERAL(QUIC_INVALID_CONNECTION_CLOSE_DATA);
     RETURN_STRING_LITERAL(QUIC_INVALID_GOAWAY_DATA);
     RETURN_STRING_LITERAL(QUIC_INVALID_ACK_DATA);
+    RETURN_STRING_LITERAL(QUIC_INVALID_CONGESTION_FEEDBACK_DATA);
     RETURN_STRING_LITERAL(QUIC_INVALID_VERSION_NEGOTIATION_PACKET);
     RETURN_STRING_LITERAL(QUIC_INVALID_PUBLIC_RST_PACKET);
     RETURN_STRING_LITERAL(QUIC_DECRYPTION_FAILURE);
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h
index 6650dbf..37eb9d2 100644
--- a/net/quic/quic_utils.h
+++ b/net/quic/quic_utils.h
@@ -46,9 +46,6 @@
   // SerializeUint128 writes |v| in little-endian form to |out|.
   static void SerializeUint128(uint128 v, uint8* out);
 
-  // ParseUint128 parses a little-endian uint128 from |in| and returns it.
-  static uint128 ParseUint128(const uint8* in);
-
   // Returns the name of the QuicRstStreamErrorCode as a char*
   static const char* StreamErrorToString(QuicRstStreamErrorCode error);
 
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h
index 352325d..166ca61 100644
--- a/net/quic/reliable_quic_stream.h
+++ b/net/quic/reliable_quic_stream.h
@@ -108,7 +108,6 @@
 
   const IPEndPoint& GetPeerAddress() const;
 
-  Visitor* visitor() { return visitor_; }
   void set_visitor(Visitor* visitor) { visitor_ = visitor; }
 
   QuicSpdyCompressor* compressor();
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc
index 7167a22..e8ba52a 100644
--- a/net/quic/reliable_quic_stream_test.cc
+++ b/net/quic/reliable_quic_stream_test.cc
@@ -116,7 +116,7 @@
   scoped_ptr<QuicSpdyCompressor> compressor_;
   scoped_ptr<QuicSpdyDecompressor> decompressor_;
   SpdyHeaderBlock headers_;
-  BlockedList<QuicStreamId>* write_blocked_list_;
+  WriteBlockedList<QuicStreamId>* write_blocked_list_;
 };
 
 TEST_F(ReliableQuicStreamTest, WriteAllData) {
@@ -131,7 +131,7 @@
   EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
       Return(QuicConsumedData(kDataLen, true)));
   EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed);
-  EXPECT_TRUE(write_blocked_list_->IsEmpty());
+  EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
 }
 
 // TODO(rtenneti): Death tests crash on OS_ANDROID.
@@ -145,7 +145,7 @@
     EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
         Return(QuicConsumedData(0, false)));
     stream_->WriteData(StringPiece(), false);
-  EXPECT_TRUE(write_blocked_list_->IsEmpty());
+    EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
   }, "");
 }
 #endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) && !defined(OS_ANDROID)
@@ -158,7 +158,7 @@
   EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
       Return(QuicConsumedData(1, false)));
   stream_->WriteData(StringPiece(kData1, 2), false);
-  ASSERT_EQ(1, write_blocked_list_->NumObjects());
+  ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams());
 }
 
 
@@ -172,7 +172,7 @@
   EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
       Return(QuicConsumedData(2, false)));
   stream_->WriteData(StringPiece(kData1, 2), true);
-  ASSERT_EQ(1, write_blocked_list_->NumObjects());
+  ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams());
 }
 
 TEST_F(ReliableQuicStreamTest, BlockIfSoloFinNotConsumed) {
@@ -183,13 +183,13 @@
   EXPECT_CALL(*session_, WriteData(kStreamId, _, _, _)).WillOnce(
       Return(QuicConsumedData(0, false)));
   stream_->WriteData(StringPiece(), true);
-  ASSERT_EQ(1, write_blocked_list_->NumObjects());
+  ASSERT_EQ(1, write_blocked_list_->NumBlockedStreams());
 }
 
 TEST_F(ReliableQuicStreamTest, WriteData) {
   Initialize(kShouldProcessData);
 
-  EXPECT_TRUE(write_blocked_list_->IsEmpty());
+  EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
   connection_->options()->max_packet_length =
       1 + QuicPacketCreator::StreamFramePacketOverhead(
           connection_->version(), PACKET_8BYTE_GUID, !kIncludeVersion,
@@ -200,7 +200,7 @@
       Return(QuicConsumedData(kDataLen - 1, false)));
   // The return will be kDataLen, because the last byte gets buffered.
   EXPECT_EQ(kDataLen, stream_->WriteData(kData1, false).bytes_consumed);
-  EXPECT_FALSE(write_blocked_list_->IsEmpty());
+  EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
 
   // Queue a bytes_consumed write.
   EXPECT_EQ(kDataLen, stream_->WriteData(kData2, false).bytes_consumed);
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index 79c3353..bfeb06f 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -51,6 +51,16 @@
   return true;
 }
 
+void MockCryptoClientStream::SendOnCryptoHandshakeEvent(
+    QuicSession::CryptoHandshakeEvent event) {
+  encryption_established_ = true;
+  if (event == QuicSession::HANDSHAKE_CONFIRMED) {
+    handshake_confirmed_ = true;
+    SetConfigNegotiated();
+  }
+  session()->OnCryptoHandshakeEvent(event);
+}
+
 void MockCryptoClientStream::SetConfigNegotiated() {
   ASSERT_FALSE(session()->config()->negotiated());
   QuicTagVector cgst;
diff --git a/net/quic/test_tools/mock_crypto_client_stream.h b/net/quic/test_tools/mock_crypto_client_stream.h
index 2b73b8f..ada1b68 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.h
+++ b/net/quic/test_tools/mock_crypto_client_stream.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "net/quic/crypto/crypto_handshake.h"
+#include "net/quic/crypto/crypto_protocol.h"
 #include "net/quic/quic_crypto_client_stream.h"
 #include "net/quic/quic_session.h"
 
@@ -46,6 +47,10 @@
   // QuicCryptoClientStream implementation.
   virtual bool CryptoConnect() OVERRIDE;
 
+  // Invokes the sessions's CryptoHandshakeEvent method with the specified
+  // event.
+  void SendOnCryptoHandshakeEvent(QuicSession::CryptoHandshakeEvent event);
+
   HandshakeMode handshake_mode_;
 
  private:
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.cc b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
index 7578790..e54fb41 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.cc
@@ -12,7 +12,8 @@
 namespace net {
 
 MockCryptoClientStreamFactory::MockCryptoClientStreamFactory()
-  : handshake_mode_(MockCryptoClientStream::CONFIRM_HANDSHAKE) {
+    : handshake_mode_(MockCryptoClientStream::CONFIRM_HANDSHAKE),
+      last_stream_(NULL) {
 }
 
 QuicCryptoClientStream*
@@ -20,8 +21,9 @@
     const string& server_hostname,
     QuicSession* session,
     QuicCryptoClientConfig* crypto_config) {
-  return new MockCryptoClientStream(server_hostname, session, crypto_config,
-                                    handshake_mode_);
+  last_stream_ = new MockCryptoClientStream(server_hostname, session,
+                                            crypto_config, handshake_mode_);
+  return last_stream_;
 }
 
 }  // namespace net
diff --git a/net/quic/test_tools/mock_crypto_client_stream_factory.h b/net/quic/test_tools/mock_crypto_client_stream_factory.h
index e3f2a4a..9d056cb 100644
--- a/net/quic/test_tools/mock_crypto_client_stream_factory.h
+++ b/net/quic/test_tools/mock_crypto_client_stream_factory.h
@@ -9,7 +9,6 @@
 
 #include "net/quic/quic_crypto_client_stream.h"
 #include "net/quic/quic_crypto_client_stream_factory.h"
-#include "net/quic/quic_session.h"
 #include "net/quic/test_tools/mock_crypto_client_stream.h"
 
 namespace net {
@@ -30,8 +29,13 @@
     handshake_mode_ = handshake_mode;
   }
 
+  MockCryptoClientStream* last_stream() const {
+    return last_stream_;
+  }
+
  private:
   MockCryptoClientStream::HandshakeMode handshake_mode_;
+  MockCryptoClientStream* last_stream_;
 };
 
 }  // namespace net
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h
index 4438353..20dbc21 100644
--- a/net/quic/test_tools/quic_connection_peer.h
+++ b/net/quic/test_tools/quic_connection_peer.h
@@ -7,8 +7,8 @@
 
 #include "base/basictypes.h"
 #include "net/base/ip_endpoint.h"
+#include "net/quic/quic_connection_stats.h"
 #include "net/quic/quic_protocol.h"
-#include "net/quic/quic_stats.h"
 
 namespace net {
 
diff --git a/net/quic/test_tools/quic_framer_peer.cc b/net/quic/test_tools/quic_framer_peer.cc
index 5ec52dc..e8d43cd 100644
--- a/net/quic/test_tools/quic_framer_peer.cc
+++ b/net/quic/test_tools/quic_framer_peer.cc
@@ -34,9 +34,5 @@
   framer->is_server_ = is_server;
 }
 
-void QuicFramerPeer::SetVersion(QuicFramer* framer, QuicVersion version) {
-  framer->quic_version_ = version;
-}
-
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/quic_framer_peer.h b/net/quic/test_tools/quic_framer_peer.h
index 0508f5c..acb45ec 100644
--- a/net/quic/test_tools/quic_framer_peer.h
+++ b/net/quic/test_tools/quic_framer_peer.h
@@ -24,7 +24,6 @@
       QuicFramer* framer,
       QuicPacketSequenceNumber packet_sequence_number);
   static void SetIsServer(QuicFramer* framer, bool is_server);
-  static void SetVersion(QuicFramer* framer, QuicVersion version);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicFramerPeer);
diff --git a/net/quic/test_tools/quic_packet_creator_peer.cc b/net/quic/test_tools/quic_packet_creator_peer.cc
index 4451f02..1acdf24 100644
--- a/net/quic/test_tools/quic_packet_creator_peer.cc
+++ b/net/quic/test_tools/quic_packet_creator_peer.cc
@@ -21,6 +21,19 @@
 }
 
 // static
+void QuicPacketCreatorPeer::SetSequenceNumberLength(
+      QuicPacketCreator* creator,
+      QuicSequenceNumberLength sequence_number_length) {
+  creator->sequence_number_length_ = sequence_number_length;
+}
+
+// static
+QuicSequenceNumberLength QuicPacketCreatorPeer::GetSequenceNumberLength(
+    QuicPacketCreator* creator) {
+  return creator->sequence_number_length_;
+}
+
+// static
 void QuicPacketCreatorPeer::SetIsServer(QuicPacketCreator* creator,
                                         bool is_server) {
   creator->is_server_ = is_server;
diff --git a/net/quic/test_tools/quic_packet_creator_peer.h b/net/quic/test_tools/quic_packet_creator_peer.h
index 816afa9..12ae676 100644
--- a/net/quic/test_tools/quic_packet_creator_peer.h
+++ b/net/quic/test_tools/quic_packet_creator_peer.h
@@ -18,6 +18,11 @@
 
   static void SetSendVersionInPacket(QuicPacketCreator* creator,
                                      bool send_version_in_packet);
+  static void SetSequenceNumberLength(
+      QuicPacketCreator* creator,
+      QuicSequenceNumberLength sequence_number_length);
+  static QuicSequenceNumberLength GetSequenceNumberLength(
+      QuicPacketCreator* creator);
 
   static void SetIsServer(QuicPacketCreator* creator, bool is_server);
 
diff --git a/net/quic/test_tools/quic_session_peer.cc b/net/quic/test_tools/quic_session_peer.cc
index 66caa15..c25b42f 100644
--- a/net/quic/test_tools/quic_session_peer.cc
+++ b/net/quic/test_tools/quic_session_peer.cc
@@ -22,13 +22,7 @@
 }
 
 // static
-ReliableQuicStream* QuicSessionPeer::CreateIncomingReliableStream(
-    QuicSession* session, QuicStreamId id) {
-  return session->CreateIncomingReliableStream(id);
-}
-
-// static
-BlockedList<QuicStreamId>* QuicSessionPeer::GetWriteblockedStreams(
+WriteBlockedList<QuicStreamId>* QuicSessionPeer::GetWriteblockedStreams(
     QuicSession* session) {
   return &session->write_blocked_streams_;
 }
diff --git a/net/quic/test_tools/quic_session_peer.h b/net/quic/test_tools/quic_session_peer.h
index 6f9a8f3..fb4529c 100644
--- a/net/quic/test_tools/quic_session_peer.h
+++ b/net/quic/test_tools/quic_session_peer.h
@@ -5,8 +5,8 @@
 #ifndef NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
 #define NET_QUIC_TEST_TOOLS_QUIC_SESSION_PEER_H_
 
-#include "net/quic/blocked_list.h"
 #include "net/quic/quic_protocol.h"
+#include "net/spdy/write_blocked_list.h"
 
 namespace net {
 
@@ -19,9 +19,7 @@
  public:
   static void SetNextStreamId(QuicSession* session, QuicStreamId id);
   static void SetMaxOpenStreams(QuicSession* session, uint32 max_streams);
-  static ReliableQuicStream* CreateIncomingReliableStream(QuicSession* session,
-                                                          QuicStreamId id);
-  static BlockedList<QuicStreamId>* GetWriteblockedStreams(
+  static WriteBlockedList<QuicStreamId>* GetWriteblockedStreams(
       QuicSession* session);
 
  private:
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 2562b07..39571bc 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -356,16 +356,6 @@
       << HexDumpWithMarks(actual, actual_len, marks.get(), max_len);
 }
 
-void CompareQuicDataWithHexError(
-    const string& description,
-    QuicData* actual,
-    QuicData* expected) {
-  CompareCharArraysWithHexError(
-      description,
-      actual->data(), actual->length(),
-      expected->data(), expected->length());
-}
-
 static QuicPacket* ConstructPacketFromHandshakeMessage(
     QuicGuid guid,
     const CryptoHandshakeMessage& message,
@@ -399,20 +389,22 @@
   return ConstructPacketFromHandshakeMessage(guid, message, false);
 }
 
-size_t GetPacketLengthForOneStream(QuicVersion version,
-                                   bool include_version,
-                                   InFecGroup is_in_fec_group,
-                                   size_t* payload_length) {
+size_t GetPacketLengthForOneStream(
+    QuicVersion version,
+    bool include_version,
+    QuicSequenceNumberLength sequence_number_length,
+    InFecGroup is_in_fec_group,
+    size_t* payload_length) {
   *payload_length = 1;
   const size_t stream_length =
       NullEncrypter().GetCiphertextSize(*payload_length) +
       QuicPacketCreator::StreamFramePacketOverhead(
           version, PACKET_8BYTE_GUID, include_version,
-          PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
+          sequence_number_length, is_in_fec_group);
   const size_t ack_length = NullEncrypter().GetCiphertextSize(
       QuicFramer::GetMinAckFrameSize()) +
       GetPacketHeaderSize(PACKET_8BYTE_GUID, include_version,
-                          PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
+                          sequence_number_length, is_in_fec_group);
   if (stream_length < ack_length) {
     *payload_length = 1 + ack_length - stream_length;
   }
@@ -420,7 +412,7 @@
   return NullEncrypter().GetCiphertextSize(*payload_length) +
       QuicPacketCreator::StreamFramePacketOverhead(
           version, PACKET_8BYTE_GUID, include_version,
-          PACKET_6BYTE_SEQUENCE_NUMBER, is_in_fec_group);
+          sequence_number_length, is_in_fec_group);
 }
 
 // Size in bytes of the stream frame fields for an arbitrary StreamID and
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 65fba73..843e485 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -31,24 +31,20 @@
                                    const char* expected,
                                    const int expected_len);
 
-void CompareQuicDataWithHexError(const std::string& description,
-                                 QuicData* actual,
-                                 QuicData* expected);
-
 // Returns the length of a QuicPacket that is capable of holding either a
 // stream frame or a minimal ack frame.  Sets |*payload_length| to the number
 // of bytes of stream data that will fit in such a packet.
-size_t GetPacketLengthForOneStream(QuicVersion version,
-                                   bool include_version,
-                                   InFecGroup is_in_fec_group,
-                                   size_t* payload_length);
+size_t GetPacketLengthForOneStream(
+    QuicVersion version,
+    bool include_version,
+    QuicSequenceNumberLength sequence_number_length,
+    InFecGroup is_in_fec_group,
+    size_t* payload_length);
 
 // Size in bytes of the stream frame fields for an arbitrary StreamID and
 // offset and the last frame in a packet.
 size_t GetMinStreamFrameSize(QuicVersion version);
 
-string SerializeUncompressedHeaders(const SpdyHeaderBlock& headers);
-
 // Returns QuicConfig set to default values.
 QuicConfig DefaultQuicConfig();
 
diff --git a/net/socket/buffered_write_stream_socket.cc b/net/socket/buffered_write_stream_socket.cc
index 36b9df7..cf13c5e 100644
--- a/net/socket/buffered_write_stream_socket.cc
+++ b/net/socket/buffered_write_stream_socket.cc
@@ -23,8 +23,8 @@
 }  // anonymous namespace
 
 BufferedWriteStreamSocket::BufferedWriteStreamSocket(
-    StreamSocket* socket_to_wrap)
-    : wrapped_socket_(socket_to_wrap),
+    scoped_ptr<StreamSocket> socket_to_wrap)
+    : wrapped_socket_(socket_to_wrap.Pass()),
       io_buffer_(new GrowableIOBuffer()),
       backup_buffer_(new GrowableIOBuffer()),
       weak_factory_(this),
diff --git a/net/socket/buffered_write_stream_socket.h b/net/socket/buffered_write_stream_socket.h
index fcb33a8..aad5736 100644
--- a/net/socket/buffered_write_stream_socket.h
+++ b/net/socket/buffered_write_stream_socket.h
@@ -5,6 +5,8 @@
 #ifndef NET_SOCKET_BUFFERED_WRITE_STREAM_SOCKET_H_
 #define NET_SOCKET_BUFFERED_WRITE_STREAM_SOCKET_H_
 
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "net/base/net_log.h"
 #include "net/socket/stream_socket.h"
@@ -33,7 +35,7 @@
 // There are no bounds on the local buffer size. Use carefully.
 class NET_EXPORT_PRIVATE BufferedWriteStreamSocket : public StreamSocket {
  public:
-  BufferedWriteStreamSocket(StreamSocket* socket_to_wrap);
+  explicit BufferedWriteStreamSocket(scoped_ptr<StreamSocket> socket_to_wrap);
   virtual ~BufferedWriteStreamSocket();
 
   // Socket interface
@@ -71,6 +73,8 @@
   bool callback_pending_;
   bool wrapped_write_in_progress_;
   int error_;
+
+  DISALLOW_COPY_AND_ASSIGN(BufferedWriteStreamSocket);
 };
 
 }  // namespace net
diff --git a/net/socket/buffered_write_stream_socket_unittest.cc b/net/socket/buffered_write_stream_socket_unittest.cc
index e579a7f..485295f 100644
--- a/net/socket/buffered_write_stream_socket_unittest.cc
+++ b/net/socket/buffered_write_stream_socket_unittest.cc
@@ -30,10 +30,11 @@
     if (writes_count) {
       data_->StopAfter(writes_count);
     }
-    DeterministicMockTCPClientSocket* wrapped_socket =
-        new DeterministicMockTCPClientSocket(net_log_.net_log(), data_.get());
+    scoped_ptr<DeterministicMockTCPClientSocket> wrapped_socket(
+        new DeterministicMockTCPClientSocket(net_log_.net_log(), data_.get()));
     data_->set_delegate(wrapped_socket->AsWeakPtr());
-    socket_.reset(new BufferedWriteStreamSocket(wrapped_socket));
+    socket_.reset(new BufferedWriteStreamSocket(
+        wrapped_socket.PassAs<StreamSocket>()));
     socket_->Connect(callback_.callback());
   }
 
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
index 022988a..a86688e 100644
--- a/net/socket/client_socket_factory.cc
+++ b/net/socket/client_socket_factory.cc
@@ -67,23 +67,25 @@
     ClearSSLSessionCache();
   }
 
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE {
-    return new UDPClientSocket(bind_type, rand_int_cb, net_log, source);
+    return scoped_ptr<DatagramClientSocket>(
+        new UDPClientSocket(bind_type, rand_int_cb, net_log, source));
   }
 
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList& addresses,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE {
-    return new TCPClientSocket(addresses, net_log, source);
+    return scoped_ptr<StreamSocket>(
+        new TCPClientSocket(addresses, net_log, source));
   }
 
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       const SSLClientSocketContext& context) OVERRIDE {
@@ -102,17 +104,19 @@
       nss_task_runner = base::ThreadTaskRunnerHandle::Get();
 
 #if defined(USE_OPENSSL)
-    return new SSLClientSocketOpenSSL(transport_socket, host_and_port,
-                                      ssl_config, context);
+    return scoped_ptr<SSLClientSocket>(
+        new SSLClientSocketOpenSSL(transport_socket.Pass(), host_and_port,
+                                   ssl_config, context));
 #elif defined(USE_NSS) || defined(OS_MACOSX) || defined(OS_WIN)
-    return new SSLClientSocketNSS(nss_task_runner.get(),
-                                  transport_socket,
-                                  host_and_port,
-                                  ssl_config,
-                                  context);
+    return scoped_ptr<SSLClientSocket>(
+        new SSLClientSocketNSS(nss_task_runner.get(),
+                               transport_socket.Pass(),
+                               host_and_port,
+                               ssl_config,
+                               context));
 #else
     NOTIMPLEMENTED();
-    return NULL;
+    return scoped_ptr<SSLClientSocket>();
 #endif
   }
 
@@ -130,18 +134,6 @@
 
 }  // namespace
 
-// Deprecated function (http://crbug.com/37810) that takes a StreamSocket.
-SSLClientSocket* ClientSocketFactory::CreateSSLClientSocket(
-    StreamSocket* transport_socket,
-    const HostPortPair& host_and_port,
-    const SSLConfig& ssl_config,
-    const SSLClientSocketContext& context) {
-  ClientSocketHandle* socket_handle = new ClientSocketHandle();
-  socket_handle->set_socket(transport_socket);
-  return CreateSSLClientSocket(socket_handle, host_and_port, ssl_config,
-                               context);
-}
-
 // static
 ClientSocketFactory* ClientSocketFactory::GetDefaultFactory() {
   return g_default_client_socket_factory.Pointer();
diff --git a/net/socket/client_socket_factory.h b/net/socket/client_socket_factory.h
index 65022f2..6cb5949 100644
--- a/net/socket/client_socket_factory.h
+++ b/net/socket/client_socket_factory.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "net/base/net_export.h"
 #include "net/base/net_log.h"
 #include "net/base/rand_callback.h"
@@ -32,13 +33,13 @@
 
   // |source| is the NetLog::Source for the entity trying to create the socket,
   // if it has one.
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       NetLog* net_log,
       const NetLog::Source& source) = 0;
 
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList& addresses,
       NetLog* net_log,
       const NetLog::Source& source) = 0;
@@ -46,19 +47,12 @@
   // It is allowed to pass in a |transport_socket| that is not obtained from a
   // socket pool. The caller could create a ClientSocketHandle directly and call
   // set_socket() on it to set a valid StreamSocket instance.
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       const SSLClientSocketContext& context) = 0;
 
-  // Deprecated function (http://crbug.com/37810) that takes a StreamSocket.
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      StreamSocket* transport_socket,
-      const HostPortPair& host_and_port,
-      const SSLConfig& ssl_config,
-      const SSLClientSocketContext& context);
-
   // Clears cache used for SSL session resumption.
   virtual void ClearSSLSessionCache() = 0;
 
diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc
index 3894fa7..9687a5a 100644
--- a/net/socket/client_socket_handle.cc
+++ b/net/socket/client_socket_handle.cc
@@ -18,7 +18,7 @@
 ClientSocketHandle::ClientSocketHandle()
     : is_initialized_(false),
       pool_(NULL),
-      layered_pool_(NULL),
+      higher_pool_(NULL),
       is_reused_(false),
       callback_(base::Bind(&ClientSocketHandle::OnIOComplete,
                            base::Unretained(this))),
@@ -43,7 +43,7 @@
     if (pool_)
       // If we've still got a socket, release it back to the ClientSocketPool so
       // it can be deleted or reused.
-      pool_->ReleaseSocket(group_name_, release_socket(), pool_id_);
+      pool_->ReleaseSocket(group_name_, PassSocket(), pool_id_);
   } else if (cancel) {
     // If we did not get initialized yet, we've got a socket request pending.
     // Cancel it.
@@ -53,10 +53,8 @@
   group_name_.clear();
   is_reused_ = false;
   user_callback_.Reset();
-  if (layered_pool_) {
-    pool_->RemoveLayeredPool(layered_pool_);
-    layered_pool_ = NULL;
-  }
+  if (higher_pool_)
+    RemoveHigherLayeredPool(higher_pool_);
   pool_ = NULL;
   idle_time_ = base::TimeDelta();
   init_time_ = base::TimeTicks();
@@ -82,24 +80,30 @@
 }
 
 bool ClientSocketHandle::IsPoolStalled() const {
+  if (!pool_)
+    return false;
   return pool_->IsStalled();
 }
 
-void ClientSocketHandle::AddLayeredPool(LayeredPool* layered_pool) {
-  CHECK(layered_pool);
-  CHECK(!layered_pool_);
+void ClientSocketHandle::AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
+  CHECK(higher_pool);
+  CHECK(!higher_pool_);
+  // TODO(mmenke):  |pool_| should only be NULL in tests.  Maybe stop doing that
+  // so this be be made into a DCHECK, and the same can be done in
+  // RemoveHigherLayeredPool?
   if (pool_) {
-    pool_->AddLayeredPool(layered_pool);
-    layered_pool_ = layered_pool;
+    pool_->AddHigherLayeredPool(higher_pool);
+    higher_pool_ = higher_pool;
   }
 }
 
-void ClientSocketHandle::RemoveLayeredPool(LayeredPool* layered_pool) {
-  CHECK(layered_pool);
-  CHECK(layered_pool_);
+void ClientSocketHandle::RemoveHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  CHECK(higher_pool_);
+  CHECK_EQ(higher_pool_, higher_pool);
   if (pool_) {
-    pool_->RemoveLayeredPool(layered_pool);
-    layered_pool_ = NULL;
+    pool_->RemoveHigherLayeredPool(higher_pool);
+    higher_pool_ = NULL;
   }
 }
 
@@ -121,6 +125,10 @@
   return true;
 }
 
+void ClientSocketHandle::SetSocket(scoped_ptr<StreamSocket> s) {
+  socket_ = s.Pass();
+}
+
 void ClientSocketHandle::OnIOComplete(int result) {
   CompletionCallback callback = user_callback_;
   user_callback_.Reset();
@@ -128,6 +136,10 @@
   callback.Run(result);
 }
 
+scoped_ptr<StreamSocket> ClientSocketHandle::PassSocket() {
+  return socket_.Pass();
+}
+
 void ClientSocketHandle::HandleInitCompletion(int result) {
   CHECK_NE(ERR_IO_PENDING, result);
   ClientSocketPoolHistograms* histograms = pool_->histograms();
diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h
index 7d5588a..8f2d4ae 100644
--- a/net/socket/client_socket_handle.h
+++ b/net/socket/client_socket_handle.h
@@ -70,9 +70,9 @@
   //
   // Profiling information for the request is saved to |net_log| if non-NULL.
   //
-  template <typename SocketParams, typename PoolType>
+  template <typename PoolType>
   int Init(const std::string& group_name,
-           const scoped_refptr<SocketParams>& socket_params,
+           const scoped_refptr<typename PoolType::SocketParams>& socket_params,
            RequestPriority priority,
            const CompletionCallback& callback,
            PoolType* pool,
@@ -94,9 +94,15 @@
 
   bool IsPoolStalled() const;
 
-  void AddLayeredPool(LayeredPool* layered_pool);
+  // Adds a higher layered pool on top of the socket pool that |socket_| belongs
+  // to.  At most one higher layered pool can be added to a
+  // ClientSocketHandle at a time.  On destruction or reset, automatically
+  // removes the higher pool if RemoveHigherLayeredPool has not been called.
+  void AddHigherLayeredPool(HigherLayeredPool* higher_pool);
 
-  void RemoveLayeredPool(LayeredPool* layered_pool);
+  // Removes a higher layered pool from the socket pool that |socket_| belongs
+  // to.  |higher_pool| must have been added by the above function.
+  void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool);
 
   // Returns true when Init() has completed successfully.
   bool is_initialized() const { return is_initialized_; }
@@ -116,8 +122,8 @@
                          LoadTimingInfo* load_timing_info) const;
 
   // Used by ClientSocketPool to initialize the ClientSocketHandle.
+  void SetSocket(scoped_ptr<StreamSocket> s);
   void set_is_reused(bool is_reused) { is_reused_ = is_reused; }
-  void set_socket(StreamSocket* s) { socket_.reset(s); }
   void set_idle_time(base::TimeDelta idle_time) { idle_time_ = idle_time; }
   void set_pool_id(int id) { pool_id_ = id; }
   void set_is_ssl_error(bool is_ssl_error) { is_ssl_error_ = is_ssl_error; }
@@ -144,10 +150,10 @@
   }
 
   // These may only be used if is_initialized() is true.
+  scoped_ptr<StreamSocket> PassSocket();
+  StreamSocket* socket() { return socket_.get(); }
   const std::string& group_name() const { return group_name_; }
   int id() const { return pool_id_; }
-  StreamSocket* socket() { return socket_.get(); }
-  StreamSocket* release_socket() { return socket_.release(); }
   bool is_reused() const { return is_reused_; }
   base::TimeDelta idle_time() const { return idle_time_; }
   SocketReuseType reuse_type() const {
@@ -184,7 +190,7 @@
 
   bool is_initialized_;
   ClientSocketPool* pool_;
-  LayeredPool* layered_pool_;
+  HigherLayeredPool* higher_pool_;
   scoped_ptr<StreamSocket> socket_;
   std::string group_name_;
   bool is_reused_;
@@ -207,20 +213,17 @@
 };
 
 // Template function implementation:
-template <typename SocketParams, typename PoolType>
-int ClientSocketHandle::Init(const std::string& group_name,
-                             const scoped_refptr<SocketParams>& socket_params,
-                             RequestPriority priority,
-                             const CompletionCallback& callback,
-                             PoolType* pool,
-                             const BoundNetLog& net_log) {
+template <typename PoolType>
+int ClientSocketHandle::Init(
+    const std::string& group_name,
+    const scoped_refptr<typename PoolType::SocketParams>& socket_params,
+    RequestPriority priority,
+    const CompletionCallback& callback,
+    PoolType* pool,
+    const BoundNetLog& net_log) {
   requesting_source_ = net_log.source();
 
   CHECK(!group_name.empty());
-  // Note that this will result in a compile error if the SocketParams has not
-  // been registered for the PoolType via REGISTER_SOCKET_PARAMS_FOR_POOL
-  // (defined in client_socket_pool.h).
-  CheckIsValidSocketParamsForPool<PoolType, SocketParams>();
   ResetInternal(true);
   ResetErrorState();
   pool_ = pool;
diff --git a/net/socket/client_socket_pool.h b/net/socket/client_socket_pool.h
index 7cb9a7e..715cddb 100644
--- a/net/socket/client_socket_pool.h
+++ b/net/socket/client_socket_pool.h
@@ -10,6 +10,7 @@
 
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/template_util.h"
 #include "base/time/time.h"
 #include "net/base/completion_callback.h"
@@ -30,20 +31,43 @@
 
 // ClientSocketPools are layered. This defines an interface for lower level
 // socket pools to communicate with higher layer pools.
-class NET_EXPORT LayeredPool {
+class NET_EXPORT HigherLayeredPool {
  public:
-  virtual ~LayeredPool() {};
+  virtual ~HigherLayeredPool() {}
 
-  // Instructs the LayeredPool to close an idle connection. Return true if one
-  // was closed.
+  // Instructs the HigherLayeredPool to close an idle connection. Return true if
+  // one was closed.  Closing an idle connection will call into the lower layer
+  // pool it came from, so must be careful of re-entrancy when using this.
   virtual bool CloseOneIdleConnection() = 0;
 };
 
+// ClientSocketPools are layered. This defines an interface for higher level
+// socket pools to communicate with lower layer pools.
+class NET_EXPORT LowerLayeredPool {
+ public:
+  virtual ~LowerLayeredPool() {}
+
+  // Returns true if a there is currently a request blocked on the per-pool
+  // (not per-host) max socket limit, either in this pool, or one that it is
+  // layered on top of.
+  virtual bool IsStalled() const = 0;
+
+  // Called to add or remove a higher layer pool on top of |this|.  A higher
+  // layer pool may be added at most once to |this|, and must be removed prior
+  // to destruction of |this|.
+  virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
+  virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) = 0;
+};
+
 // A ClientSocketPool is used to restrict the number of sockets open at a time.
 // It also maintains a list of idle persistent sockets.
 //
-class NET_EXPORT ClientSocketPool {
+class NET_EXPORT ClientSocketPool : public LowerLayeredPool {
  public:
+  // Subclasses must also have an inner class SocketParams which is
+  // the type for the |params| argument in RequestSocket() and
+  // RequestSockets() below.
+
   // Requests a connected socket for a group_name.
   //
   // There are five possible results from calling this function:
@@ -111,7 +135,7 @@
   // change when it flushes, so it can use this |id| to discard sockets with
   // mismatched ids.
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket,
+                             scoped_ptr<StreamSocket> socket,
                              int id) = 0;
 
   // This flushes all state from the ClientSocketPool.  This means that all
@@ -121,10 +145,6 @@
   // Does not flush any pools wrapped by |this|.
   virtual void FlushWithError(int error) = 0;
 
-  // Returns true if a there is currently a request blocked on the
-  // per-pool (not per-host) max socket limit.
-  virtual bool IsStalled() const = 0;
-
   // Called to close any idle connections held by the connection manager.
   virtual void CloseIdleSockets() = 0;
 
@@ -138,12 +158,6 @@
   virtual LoadState GetLoadState(const std::string& group_name,
                                  const ClientSocketHandle* handle) const = 0;
 
-  // Adds a LayeredPool on top of |this|.
-  virtual void AddLayeredPool(LayeredPool* layered_pool) = 0;
-
-  // Removes a LayeredPool from |this|.
-  virtual void RemoveLayeredPool(LayeredPool* layered_pool) = 0;
-
   // Retrieves information on the current state of the pool as a
   // DictionaryValue.  Caller takes possession of the returned value.
   // If |include_nested_pools| is true, the states of any nested
@@ -177,41 +191,13 @@
   DISALLOW_COPY_AND_ASSIGN(ClientSocketPool);
 };
 
-// ClientSocketPool subclasses should indicate valid SocketParams via the
-// REGISTER_SOCKET_PARAMS_FOR_POOL macro below.  By default, any given
-// <PoolType,SocketParams> pair will have its SocketParamsTrait inherit from
-// base::false_type, but REGISTER_SOCKET_PARAMS_FOR_POOL will specialize that
-// pairing to inherit from base::true_type.  This provides compile time
-// verification that the correct SocketParams type is used with the appropriate
-// PoolType.
-template <typename PoolType, typename SocketParams>
-struct SocketParamTraits : public base::false_type {
-};
-
-template <typename PoolType, typename SocketParams>
-void CheckIsValidSocketParamsForPool() {
-  COMPILE_ASSERT(!base::is_pointer<scoped_refptr<SocketParams> >::value,
-                 socket_params_cannot_be_pointer);
-  COMPILE_ASSERT((SocketParamTraits<PoolType,
-                                    scoped_refptr<SocketParams> >::value),
-                 invalid_socket_params_for_pool);
-}
-
-// Provides an empty definition for CheckIsValidSocketParamsForPool() which
-// should be optimized out by the compiler.
-#define REGISTER_SOCKET_PARAMS_FOR_POOL(pool_type, socket_params)             \
-template<>                                                                    \
-struct SocketParamTraits<pool_type, scoped_refptr<socket_params> >            \
-    : public base::true_type {                                                \
-}
-
-template <typename PoolType, typename SocketParams>
-void RequestSocketsForPool(PoolType* pool,
-                           const std::string& group_name,
-                           const scoped_refptr<SocketParams>& params,
-                           int num_sockets,
-                           const BoundNetLog& net_log) {
-  CheckIsValidSocketParamsForPool<PoolType, SocketParams>();
+template <typename PoolType>
+void RequestSocketsForPool(
+    PoolType* pool,
+    const std::string& group_name,
+    const scoped_refptr<typename PoolType::SocketParams>& params,
+    int num_sockets,
+    const BoundNetLog& net_log) {
   pool->RequestSockets(group_name, &params, num_sockets, net_log);
 }
 
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 3332e04..cec7956 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -65,10 +65,12 @@
 
 ConnectJob::ConnectJob(const std::string& group_name,
                        base::TimeDelta timeout_duration,
+                       RequestPriority priority,
                        Delegate* delegate,
                        const BoundNetLog& net_log)
     : group_name_(group_name),
       timeout_duration_(timeout_duration),
+      priority_(priority),
       delegate_(delegate),
       net_log_(net_log),
       idle_(true) {
@@ -82,6 +84,10 @@
   net_log().EndEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB);
 }
 
+scoped_ptr<StreamSocket> ConnectJob::PassSocket() {
+  return socket_.Pass();
+}
+
 int ConnectJob::Connect() {
   if (timeout_duration_ != base::TimeDelta())
     timer_.Start(FROM_HERE, timeout_duration_, this, &ConnectJob::OnTimeout);
@@ -100,16 +106,16 @@
   return rv;
 }
 
-void ConnectJob::set_socket(StreamSocket* socket) {
+void ConnectJob::SetSocket(scoped_ptr<StreamSocket> socket) {
   if (socket) {
     net_log().AddEvent(NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
                        socket->NetLog().source().ToEventParametersCallback());
   }
-  socket_.reset(socket);
+  socket_ = socket.Pass();
 }
 
 void ConnectJob::NotifyDelegateOfCompletion(int rv) {
-  // The delegate will delete |this|.
+  // The delegate will own |this|.
   Delegate* delegate = delegate_;
   delegate_ = NULL;
 
@@ -135,7 +141,7 @@
 
 void ConnectJob::OnTimeout() {
   // Make sure the socket is NULL before calling into |delegate|.
-  set_socket(NULL);
+  SetSocket(scoped_ptr<StreamSocket>());
 
   net_log_.AddEvent(NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT);
 
@@ -161,6 +167,7 @@
 ClientSocketPoolBaseHelper::Request::~Request() {}
 
 ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
+    HigherLayeredPool* pool,
     int max_sockets,
     int max_sockets_per_group,
     base::TimeDelta unused_idle_socket_timeout,
@@ -177,6 +184,7 @@
       connect_job_factory_(connect_job_factory),
       connect_backup_jobs_enabled_(false),
       pool_generation_number_(0),
+      pool_(pool),
       weak_factory_(this) {
   DCHECK_LE(0, max_sockets_per_group);
   DCHECK_LE(max_sockets_per_group, max_sockets);
@@ -192,9 +200,16 @@
   DCHECK(group_map_.empty());
   DCHECK(pending_callback_map_.empty());
   DCHECK_EQ(0, connecting_socket_count_);
-  CHECK(higher_layer_pools_.empty());
+  CHECK(higher_pools_.empty());
 
   NetworkChangeNotifier::RemoveIPAddressObserver(this);
+
+  // Remove from lower layer pools.
+  for (std::set<LowerLayeredPool*>::iterator it = lower_pools_.begin();
+       it != lower_pools_.end();
+       ++it) {
+    (*it)->RemoveHigherLayeredPool(pool_);
+  }
 }
 
 ClientSocketPoolBaseHelper::CallbackResultPair::CallbackResultPair()
@@ -209,46 +224,59 @@
 
 ClientSocketPoolBaseHelper::CallbackResultPair::~CallbackResultPair() {}
 
-// static
-void ClientSocketPoolBaseHelper::InsertRequestIntoQueue(
-    const Request* r, RequestQueue* pending_requests) {
-  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;
+bool ClientSocketPoolBaseHelper::IsStalled() const {
+  // If a lower layer pool is stalled, consider |this| stalled as well.
+  for (std::set<LowerLayeredPool*>::const_iterator it = lower_pools_.begin();
+       it != lower_pools_.end();
+       ++it) {
+    if ((*it)->IsStalled())
+      return true;
   }
-  pending_requests->insert(it, r);
+
+  // If fewer than |max_sockets_| are in use, then clearly |this| is not
+  // stalled.
+  if ((handed_out_socket_count_ + connecting_socket_count_) < max_sockets_)
+    return false;
+  // So in order to be stalled, |this| must be using at least |max_sockets_| AND
+  // |this| must have a request that is actually stalled on the global socket
+  // limit.  To find such a request, look for a group that has more requests
+  // than jobs AND where the number of sockets is less than
+  // |max_sockets_per_group_|.  (If the number of sockets is equal to
+  // |max_sockets_per_group_|, then the request is stalled on the group limit,
+  // which does not count.)
+  for (GroupMap::const_iterator it = group_map_.begin();
+       it != group_map_.end(); ++it) {
+    if (it->second->IsStalledOnPoolMaxSockets(max_sockets_per_group_))
+      return true;
+  }
+  return false;
 }
 
-// static
-const ClientSocketPoolBaseHelper::Request*
-ClientSocketPoolBaseHelper::RemoveRequestFromQueue(
-    const RequestQueue::iterator& it, Group* group) {
-  const Request* req = *it;
-  group->mutable_pending_requests()->erase(it);
-  // If there are no more requests, we kill the backup timer.
-  if (group->pending_requests().empty())
-    group->CleanupBackupJob();
-  return req;
+void ClientSocketPoolBaseHelper::AddLowerLayeredPool(
+    LowerLayeredPool* lower_pool) {
+  DCHECK(pool_);
+  CHECK(!ContainsKey(lower_pools_, lower_pool));
+  lower_pools_.insert(lower_pool);
+  lower_pool->AddHigherLayeredPool(pool_);
 }
 
-void ClientSocketPoolBaseHelper::AddLayeredPool(LayeredPool* pool) {
-  CHECK(pool);
-  CHECK(!ContainsKey(higher_layer_pools_, pool));
-  higher_layer_pools_.insert(pool);
+void ClientSocketPoolBaseHelper::AddHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  CHECK(higher_pool);
+  CHECK(!ContainsKey(higher_pools_, higher_pool));
+  higher_pools_.insert(higher_pool);
 }
 
-void ClientSocketPoolBaseHelper::RemoveLayeredPool(LayeredPool* pool) {
-  CHECK(pool);
-  CHECK(ContainsKey(higher_layer_pools_, pool));
-  higher_layer_pools_.erase(pool);
+void ClientSocketPoolBaseHelper::RemoveHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  CHECK(higher_pool);
+  CHECK(ContainsKey(higher_pools_, higher_pool));
+  higher_pools_.erase(higher_pool);
 }
 
 int ClientSocketPoolBaseHelper::RequestSocket(
     const std::string& group_name,
-    const Request* request) {
+    scoped_ptr<const Request> request) {
   CHECK(!request->callback().is_null());
   CHECK(request->handle());
 
@@ -259,13 +287,13 @@
   request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL);
   Group* group = GetOrCreateGroup(group_name);
 
-  int rv = RequestSocketInternal(group_name, request);
+  int rv = RequestSocketInternal(group_name, *request);
   if (rv != ERR_IO_PENDING) {
     request->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, rv);
     CHECK(!request->handle()->is_initialized());
-    delete request;
+    request.reset();
   } else {
-    InsertRequestIntoQueue(request, group->mutable_pending_requests());
+    group->InsertPendingRequest(request.Pass());
     // Have to do this asynchronously, as closing sockets in higher level pools
     // call back in to |this|, which will cause all sorts of fun and exciting
     // re-entrancy issues if the socket pool is doing something else at the
@@ -309,7 +337,7 @@
   for (int num_iterations_left = num_sockets;
        group->NumActiveSocketSlots() < num_sockets &&
        num_iterations_left > 0 ; num_iterations_left--) {
-    rv = RequestSocketInternal(group_name, &request);
+    rv = RequestSocketInternal(group_name, request);
     if (rv < 0 && rv != ERR_IO_PENDING) {
       // We're encountering a synchronous error.  Give up.
       if (!ContainsKey(group_map_, group_name))
@@ -336,12 +364,12 @@
 
 int ClientSocketPoolBaseHelper::RequestSocketInternal(
     const std::string& group_name,
-    const Request* request) {
-  ClientSocketHandle* const handle = request->handle();
+    const Request& request) {
+  ClientSocketHandle* const handle = request.handle();
   const bool preconnecting = !handle;
   Group* group = GetOrCreateGroup(group_name);
 
-  if (!(request->flags() & NO_IDLE_SOCKETS)) {
+  if (!(request.flags() & NO_IDLE_SOCKETS)) {
     // Try to reuse a socket.
     if (AssignIdleSocketToRequest(request, group))
       return OK;
@@ -355,17 +383,17 @@
 
   // Can we make another active socket now?
   if (!group->HasAvailableSocketSlot(max_sockets_per_group_) &&
-      !request->ignore_limits()) {
+      !request.ignore_limits()) {
     // TODO(willchan): Consider whether or not we need to close a socket in a
     // higher layered group. I don't think this makes sense since we would just
     // reuse that socket then if we needed one and wouldn't make it down to this
     // layer.
-    request->net_log().AddEvent(
+    request.net_log().AddEvent(
         NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP);
     return ERR_IO_PENDING;
   }
 
-  if (ReachedMaxSocketsLimit() && !request->ignore_limits()) {
+  if (ReachedMaxSocketsLimit() && !request.ignore_limits()) {
     // NOTE(mmenke):  Wonder if we really need different code for each case
     // here.  Only reason for them now seems to be preconnects.
     if (idle_socket_count() > 0) {
@@ -378,7 +406,7 @@
     } else {
       // We could check if we really have a stalled group here, but it requires
       // a scan of all groups, so just flip a flag here, and do the check later.
-      request->net_log().AddEvent(NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS);
+      request.net_log().AddEvent(NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS);
       return ERR_IO_PENDING;
     }
   }
@@ -386,17 +414,17 @@
   // We couldn't find a socket to reuse, and there's space to allocate one,
   // so allocate and connect a new one.
   scoped_ptr<ConnectJob> connect_job(
-      connect_job_factory_->NewConnectJob(group_name, *request, this));
+      connect_job_factory_->NewConnectJob(group_name, request, this));
 
   int rv = connect_job->Connect();
   if (rv == OK) {
     LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
     if (!preconnecting) {
-      HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
+      HandOutSocket(connect_job->PassSocket(), false /* not reused */,
                     connect_job->connect_timing(), handle, base::TimeDelta(),
-                    group, request->net_log());
+                    group, request.net_log());
     } else {
-      AddIdleSocket(connect_job->ReleaseSocket(), group);
+      AddIdleSocket(connect_job->PassSocket(), group);
     }
   } else if (rv == ERR_IO_PENDING) {
     // If we don't have any sockets in this group, set a timer for potentially
@@ -409,19 +437,19 @@
 
     connecting_socket_count_++;
 
-    group->AddJob(connect_job.release(), preconnecting);
+    group->AddJob(connect_job.Pass(), preconnecting);
   } else {
     LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
-    StreamSocket* error_socket = NULL;
+    scoped_ptr<StreamSocket> error_socket;
     if (!preconnecting) {
       DCHECK(handle);
       connect_job->GetAdditionalErrorState(handle);
-      error_socket = connect_job->ReleaseSocket();
+      error_socket = connect_job->PassSocket();
     }
     if (error_socket) {
-      HandOutSocket(error_socket, false /* not reused */,
+      HandOutSocket(error_socket.Pass(), false /* not reused */,
                     connect_job->connect_timing(), handle, base::TimeDelta(),
-                    group, request->net_log());
+                    group, request.net_log());
     } else if (group->IsEmpty()) {
       RemoveGroup(group_name);
     }
@@ -431,7 +459,7 @@
 }
 
 bool ClientSocketPoolBaseHelper::AssignIdleSocketToRequest(
-    const Request* request, Group* group) {
+    const Request& request, Group* group) {
   std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
   std::list<IdleSocket>::iterator idle_socket_it = idle_sockets->end();
 
@@ -469,13 +497,13 @@
     IdleSocket idle_socket = *idle_socket_it;
     idle_sockets->erase(idle_socket_it);
     HandOutSocket(
-        idle_socket.socket,
+        scoped_ptr<StreamSocket>(idle_socket.socket),
         idle_socket.socket->WasEverUsed(),
         LoadTimingInfo::ConnectTiming(),
-        request->handle(),
+        request.handle(),
         idle_time,
         group,
-        request->net_log());
+        request.net_log());
     return true;
   }
 
@@ -484,9 +512,9 @@
 
 // static
 void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
-    const NetLog::Source& connect_job_source, const Request* request) {
-  request->net_log().AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
-                              connect_job_source.ToEventParametersCallback());
+    const NetLog::Source& connect_job_source, const Request& request) {
+  request.net_log().AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
+                             connect_job_source.ToEventParametersCallback());
 }
 
 void ClientSocketPoolBaseHelper::CancelRequest(
@@ -495,11 +523,11 @@
   if (callback_it != pending_callback_map_.end()) {
     int result = callback_it->second.result;
     pending_callback_map_.erase(callback_it);
-    StreamSocket* socket = handle->release_socket();
+    scoped_ptr<StreamSocket> socket = handle->PassSocket();
     if (socket) {
       if (result != OK)
         socket->Disconnect();
-      ReleaseSocket(handle->group_name(), socket, handle->id());
+      ReleaseSocket(handle->group_name(), socket.Pass(), handle->id());
     }
     return;
   }
@@ -509,21 +537,18 @@
   Group* group = GetOrCreateGroup(group_name);
 
   // Search pending_requests for matching handle.
-  RequestQueue::iterator it = group->mutable_pending_requests()->begin();
-  for (; it != group->pending_requests().end(); ++it) {
-    if ((*it)->handle() == handle) {
-      scoped_ptr<const Request> req(RemoveRequestFromQueue(it, group));
-      req->net_log().AddEvent(NetLog::TYPE_CANCELLED);
-      req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL);
+  scoped_ptr<const Request> request =
+      group->FindAndRemovePendingRequest(handle);
+  if (request) {
+    request->net_log().AddEvent(NetLog::TYPE_CANCELLED);
+    request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL);
 
-      // We let the job run, unless we're at the socket limit and there is
-      // not another request waiting on the job.
-      if (group->jobs().size() > group->pending_requests().size() &&
-          ReachedMaxSocketsLimit()) {
-        RemoveConnectJob(*group->jobs().begin(), group);
-        CheckForStalledSocketGroups();
-      }
-      break;
+    // We let the job run, unless we're at the socket limit and there is
+    // not another request waiting on the job.
+    if (group->jobs().size() > group->pending_request_count() &&
+        ReachedMaxSocketsLimit()) {
+      RemoveConnectJob(*group->jobs().begin(), group);
+      CheckForStalledSocketGroups();
     }
   }
 }
@@ -560,16 +585,7 @@
   // Can't use operator[] since it is non-const.
   const Group& group = *group_map_.find(group_name)->second;
 
-  // Search the first group.jobs().size() |pending_requests| for |handle|.
-  // If it's farther back in the deque than that, it doesn't have a
-  // corresponding ConnectJob.
-  size_t connect_jobs = group.jobs().size();
-  RequestQueue::const_iterator it = group.pending_requests().begin();
-  for (size_t i = 0; it != group.pending_requests().end() && i < connect_jobs;
-       ++it, ++i) {
-    if ((*it)->handle() != handle)
-      continue;
-
+  if (group.HasConnectJobForHandle(handle)) {
     // Just return the state  of the farthest along ConnectJob for the first
     // group.jobs().size() pending requests.
     LoadState max_state = LOAD_STATE_IDLE;
@@ -607,8 +623,8 @@
     base::DictionaryValue* group_dict = new base::DictionaryValue();
 
     group_dict->SetInteger("pending_request_count",
-                           group->pending_requests().size());
-    if (!group->pending_requests().empty()) {
+                           group->pending_request_count());
+    if (group->has_pending_requests()) {
       group_dict->SetInteger("top_pending_priority",
                              group->TopPendingPriority());
     }
@@ -756,7 +772,7 @@
 }
 
 void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
-                                               StreamSocket* socket,
+                                               scoped_ptr<StreamSocket> socket,
                                                int id) {
   GroupMap::iterator i = group_map_.find(group_name);
   CHECK(i != group_map_.end());
@@ -773,10 +789,10 @@
       id == pool_generation_number_;
   if (can_reuse) {
     // Add it to the idle list.
-    AddIdleSocket(socket, group);
+    AddIdleSocket(socket.Pass(), group);
     OnAvailableSocketSlot(group_name, group);
   } else {
-    delete socket;
+    socket.reset();
   }
 
   CheckForStalledSocketGroups();
@@ -786,8 +802,18 @@
   // If we have idle sockets, see if we can give one to the top-stalled group.
   std::string top_group_name;
   Group* top_group = NULL;
-  if (!FindTopStalledGroup(&top_group, &top_group_name))
+  if (!FindTopStalledGroup(&top_group, &top_group_name)) {
+    // There may still be a stalled group in a lower level pool.
+    for (std::set<LowerLayeredPool*>::iterator it = lower_pools_.begin();
+         it != lower_pools_.end();
+         ++it) {
+       if ((*it)->IsStalled()) {
+         CloseOneIdleSocket();
+         break;
+       }
+    }
     return;
+  }
 
   if (ReachedMaxSocketsLimit()) {
     if (idle_socket_count() > 0) {
@@ -820,8 +846,7 @@
   for (GroupMap::const_iterator i = group_map_.begin();
        i != group_map_.end(); ++i) {
     Group* curr_group = i->second;
-    const RequestQueue& queue = curr_group->pending_requests();
-    if (queue.empty())
+    if (!curr_group->has_pending_requests())
       continue;
     if (curr_group->IsStalledOnPoolMaxSockets(max_sockets_per_group_)) {
       if (!group)
@@ -854,27 +879,29 @@
   CHECK(group_it != group_map_.end());
   Group* group = group_it->second;
 
-  scoped_ptr<StreamSocket> socket(job->ReleaseSocket());
+  scoped_ptr<StreamSocket> socket = job->PassSocket();
 
   // Copies of these are needed because |job| may be deleted before they are
   // accessed.
   BoundNetLog job_log = job->net_log();
   LoadTimingInfo::ConnectTiming connect_timing = job->connect_timing();
 
+  // RemoveConnectJob(job, _) must be called by all branches below;
+  // otherwise, |job| will be leaked.
+
   if (result == OK) {
     DCHECK(socket.get());
     RemoveConnectJob(job, group);
-    if (!group->pending_requests().empty()) {
-      scoped_ptr<const Request> r(RemoveRequestFromQueue(
-          group->mutable_pending_requests()->begin(), group));
-      LogBoundConnectJobToRequest(job_log.source(), r.get());
+    scoped_ptr<const Request> request = group->PopNextPendingRequest();
+    if (request) {
+      LogBoundConnectJobToRequest(job_log.source(), *request);
       HandOutSocket(
-          socket.release(), false /* unused socket */, connect_timing,
-          r->handle(), base::TimeDelta(), group, r->net_log());
-      r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL);
-      InvokeUserCallbackLater(r->handle(), r->callback(), result);
+          socket.Pass(), false /* unused socket */, connect_timing,
+          request->handle(), base::TimeDelta(), group, request->net_log());
+      request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL);
+      InvokeUserCallbackLater(request->handle(), request->callback(), result);
     } else {
-      AddIdleSocket(socket.release(), group);
+      AddIdleSocket(socket.Pass(), group);
       OnAvailableSocketSlot(group_name, group);
       CheckForStalledSocketGroups();
     }
@@ -882,20 +909,20 @@
     // If we got a socket, it must contain error information so pass that
     // up so that the caller can retrieve it.
     bool handed_out_socket = false;
-    if (!group->pending_requests().empty()) {
-      scoped_ptr<const Request> r(RemoveRequestFromQueue(
-          group->mutable_pending_requests()->begin(), group));
-      LogBoundConnectJobToRequest(job_log.source(), r.get());
-      job->GetAdditionalErrorState(r->handle());
+    scoped_ptr<const Request> request = group->PopNextPendingRequest();
+    if (request) {
+      LogBoundConnectJobToRequest(job_log.source(), *request);
+      job->GetAdditionalErrorState(request->handle());
       RemoveConnectJob(job, group);
       if (socket.get()) {
         handed_out_socket = true;
-        HandOutSocket(socket.release(), false /* unused socket */,
-                      connect_timing, r->handle(), base::TimeDelta(), group,
-                      r->net_log());
+        HandOutSocket(socket.Pass(), false /* unused socket */,
+                      connect_timing, request->handle(), base::TimeDelta(),
+                      group, request->net_log());
       }
-      r->net_log().EndEventWithNetErrorCode(NetLog::TYPE_SOCKET_POOL, result);
-      InvokeUserCallbackLater(r->handle(), r->callback(), result);
+      request->net_log().EndEventWithNetErrorCode(
+          NetLog::TYPE_SOCKET_POOL, result);
+      InvokeUserCallbackLater(request->handle(), request->callback(), result);
     } else {
       RemoveConnectJob(job, group);
     }
@@ -917,59 +944,38 @@
   CancelAllRequestsWithError(error);
 }
 
-bool ClientSocketPoolBaseHelper::IsStalled() const {
-  // If we are not using |max_sockets_|, then clearly we are not stalled
-  if ((handed_out_socket_count_ + connecting_socket_count_) < max_sockets_)
-    return false;
-  // So in order to be stalled we need to be using |max_sockets_| AND
-  // we need to have a request that is actually stalled on the global
-  // socket limit.  To find such a request, we look for a group that
-  // a has more requests that jobs AND where the number of jobs is less
-  // than |max_sockets_per_group_|.  (If the number of jobs is equal to
-  // |max_sockets_per_group_|, then the request is stalled on the group,
-  // which does not count.)
-  for (GroupMap::const_iterator it = group_map_.begin();
-       it != group_map_.end(); ++it) {
-    if (it->second->IsStalledOnPoolMaxSockets(max_sockets_per_group_))
-      return true;
-  }
-  return false;
-}
-
 void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job,
                                                   Group* group) {
   CHECK_GT(connecting_socket_count_, 0);
   connecting_socket_count_--;
 
   DCHECK(group);
-  DCHECK(ContainsKey(group->jobs(), job));
   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();
-
-  DCHECK(job);
-  delete job;
 }
 
 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
     const std::string& group_name, Group* group) {
   DCHECK(ContainsKey(group_map_, group_name));
-  if (group->IsEmpty())
+  if (group->IsEmpty()) {
     RemoveGroup(group_name);
-  else if (!group->pending_requests().empty())
+  } else if (group->has_pending_requests()) {
     ProcessPendingRequest(group_name, group);
+  }
 }
 
 void ClientSocketPoolBaseHelper::ProcessPendingRequest(
     const std::string& group_name, Group* group) {
-  int rv = RequestSocketInternal(group_name,
-                                 *group->pending_requests().begin());
+  const Request* next_request = group->GetNextPendingRequest();
+  DCHECK(next_request);
+  int rv = RequestSocketInternal(group_name, *next_request);
   if (rv != ERR_IO_PENDING) {
-    scoped_ptr<const Request> request(RemoveRequestFromQueue(
-          group->mutable_pending_requests()->begin(), group));
+    scoped_ptr<const Request> request = group->PopNextPendingRequest();
+    DCHECK(request);
     if (group->IsEmpty())
       RemoveGroup(group_name);
 
@@ -979,7 +985,7 @@
 }
 
 void ClientSocketPoolBaseHelper::HandOutSocket(
-    StreamSocket* socket,
+    scoped_ptr<StreamSocket> socket,
     bool reused,
     const LoadTimingInfo::ConnectTiming& connect_timing,
     ClientSocketHandle* handle,
@@ -987,7 +993,7 @@
     Group* group,
     const BoundNetLog& net_log) {
   DCHECK(socket);
-  handle->set_socket(socket);
+  handle->SetSocket(socket.Pass());
   handle->set_is_reused(reused);
   handle->set_idle_time(idle_time);
   handle->set_pool_id(pool_generation_number_);
@@ -1000,18 +1006,20 @@
             "idle_ms", static_cast<int>(idle_time.InMilliseconds())));
   }
 
-  net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
-                   socket->NetLog().source().ToEventParametersCallback());
+  net_log.AddEvent(
+      NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
+      handle->socket()->NetLog().source().ToEventParametersCallback());
 
   handed_out_socket_count_++;
   group->IncrementActiveSocketCount();
 }
 
 void ClientSocketPoolBaseHelper::AddIdleSocket(
-    StreamSocket* socket, Group* group) {
+    scoped_ptr<StreamSocket> socket,
+    Group* group) {
   DCHECK(socket);
   IdleSocket idle_socket;
-  idle_socket.socket = socket;
+  idle_socket.socket = socket.release();
   idle_socket.start_time = base::TimeTicks::Now();
 
   group->mutable_idle_sockets()->push_back(idle_socket);
@@ -1041,13 +1049,11 @@
   for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
     Group* group = i->second;
 
-    RequestQueue pending_requests;
-    pending_requests.swap(*group->mutable_pending_requests());
-    for (RequestQueue::iterator it2 = pending_requests.begin();
-         it2 != pending_requests.end(); ++it2) {
-      scoped_ptr<const Request> request(*it2);
-      InvokeUserCallbackLater(
-          request->handle(), request->callback(), error);
+    while (true) {
+      scoped_ptr<const Request> request = group->PopNextPendingRequest();
+      if (!request)
+        break;
+      InvokeUserCallbackLater(request->handle(), request->callback(), error);
     }
 
     // Delete group if no longer needed.
@@ -1103,12 +1109,12 @@
   return false;
 }
 
-bool ClientSocketPoolBaseHelper::CloseOneIdleConnectionInLayeredPool() {
+bool ClientSocketPoolBaseHelper::CloseOneIdleConnectionInHigherLayeredPool() {
   // This pool doesn't have any idle sockets. It's possible that a pool at a
   // higher layer is holding one of this sockets active, but it's actually idle.
   // Query the higher layers.
-  for (std::set<LayeredPool*>::const_iterator it = higher_layer_pools_.begin();
-       it != higher_layer_pools_.end(); ++it) {
+  for (std::set<HigherLayeredPool*>::const_iterator it = higher_pools_.begin();
+       it != higher_pools_.end(); ++it) {
     if ((*it)->CloseOneIdleConnection())
       return true;
   }
@@ -1144,7 +1150,7 @@
   while (IsStalled()) {
     // Closing a socket will result in calling back into |this| to use the freed
     // socket slot, so nothing else is needed.
-    if (!CloseOneIdleConnectionInLayeredPool())
+    if (!CloseOneIdleConnectionInHigherLayeredPool())
       return;
   }
 }
@@ -1182,19 +1188,25 @@
   return true;
 }
 
-void ClientSocketPoolBaseHelper::Group::AddJob(ConnectJob* job,
+void ClientSocketPoolBaseHelper::Group::AddJob(scoped_ptr<ConnectJob> job,
                                                bool is_preconnect) {
   SanityCheck();
 
   if (is_preconnect)
     ++unassigned_job_count_;
-  jobs_.insert(job);
+  jobs_.insert(job.release());
 }
 
 void ClientSocketPoolBaseHelper::Group::RemoveJob(ConnectJob* job) {
+  scoped_ptr<ConnectJob> owned_job(job);
   SanityCheck();
 
-  jobs_.erase(job);
+  std::set<ConnectJob*>::iterator it = jobs_.find(job);
+  if (it != jobs_.end()) {
+    jobs_.erase(it);
+  } else {
+    NOTREACHED();
+  }
   size_t job_count = jobs_.size();
   if (job_count < unassigned_job_count_)
     unassigned_job_count_ = job_count;
@@ -1222,15 +1234,17 @@
   if (pending_requests_.empty())
     return;
 
-  ConnectJob* backup_job = pool->connect_job_factory_->NewConnectJob(
-      group_name, **pending_requests_.begin(), pool);
+  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);
   SIMPLE_STATS_COUNTER("socket.backup_created");
   int rv = backup_job->Connect();
   pool->connecting_socket_count_++;
-  AddJob(backup_job, false);
+  ConnectJob* raw_backup_job = backup_job.get();
+  AddJob(backup_job.Pass(), false);
   if (rv != ERR_IO_PENDING)
-    pool->OnConnectJobComplete(rv, backup_job);
+    pool->OnConnectJobComplete(rv, raw_backup_job);
 }
 
 void ClientSocketPoolBaseHelper::Group::SanityCheck() {
@@ -1248,6 +1262,68 @@
   weak_factory_.InvalidateWeakPtrs();
 }
 
+const ClientSocketPoolBaseHelper::Request*
+ClientSocketPoolBaseHelper::Group::GetNextPendingRequest() const {
+  return pending_requests_.empty() ? NULL : *pending_requests_.begin();
+}
+
+bool ClientSocketPoolBaseHelper::Group::HasConnectJobForHandle(
+    const ClientSocketHandle* handle) const {
+  // Search the first |jobs_.size()| pending requests for |handle|.
+  // 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)
+      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 ClientSocketPoolBaseHelper::Request>
+ClientSocketPoolBaseHelper::Group::PopNextPendingRequest() {
+  if (pending_requests_.empty())
+    return scoped_ptr<const ClientSocketPoolBaseHelper::Request>();
+  return RemovePendingRequest(pending_requests_.begin());
+}
+
+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);
+      return request.Pass();
+    }
+  }
+  return scoped_ptr<const ClientSocketPoolBaseHelper::Request>();
+}
+
+scoped_ptr<const ClientSocketPoolBaseHelper::Request>
+ClientSocketPoolBaseHelper::Group::RemovePendingRequest(
+    const RequestQueue::iterator& it) {
+  scoped_ptr<const Request> request(*it);
+  pending_requests_.erase(it);
+  // If there are no more requests, kill the backup timer.
+  if (pending_requests_.empty())
+    CleanupBackupJob();
+  return request.Pass();
+}
+
 }  // namespace internal
 
 }  // namespace net
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index 4bf95d7..31ec9bf 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -61,8 +61,11 @@
     Delegate() {}
     virtual ~Delegate() {}
 
-    // Alerts the delegate that the connection completed.
-    virtual void OnConnectJobComplete(int result, ConnectJob* job) = 0;
+    // Alerts the delegate that the connection completed. |job| must
+    // be destroyed by the delegate. A scoped_ptr<> isn't used because
+    // the caller of this function doesn't own |job|.
+    virtual void OnConnectJobComplete(int result,
+                                      ConnectJob* job) = 0;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(Delegate);
@@ -71,6 +74,7 @@
   // A |timeout_duration| of 0 corresponds to no timeout.
   ConnectJob(const std::string& group_name,
              base::TimeDelta timeout_duration,
+             RequestPriority priority,
              Delegate* delegate,
              const BoundNetLog& net_log);
   virtual ~ConnectJob();
@@ -79,9 +83,10 @@
   const std::string& group_name() const { return group_name_; }
   const BoundNetLog& net_log() { return net_log_; }
 
-  // Releases |socket_| to the client.  On connection error, this should return
-  // NULL.
-  StreamSocket* ReleaseSocket() { return socket_.release(); }
+  // Releases ownership of the underlying socket to the caller.
+  // Returns the released socket, or NULL if there was a connection
+  // error.
+  scoped_ptr<StreamSocket> PassSocket();
 
   // Begins connecting the socket.  Returns OK on success, ERR_IO_PENDING if it
   // cannot complete synchronously without blocking, or another net error code
@@ -105,7 +110,8 @@
   const BoundNetLog& net_log() const { return net_log_; }
 
  protected:
-  void set_socket(StreamSocket* socket);
+  RequestPriority priority() const { return priority_; }
+  void SetSocket(scoped_ptr<StreamSocket> socket);
   StreamSocket* socket() { return socket_.get(); }
   void NotifyDelegateOfCompletion(int rv);
   void ResetTimer(base::TimeDelta remainingTime);
@@ -124,6 +130,8 @@
 
   const std::string group_name_;
   const base::TimeDelta timeout_duration_;
+  // TODO(akalin): Support reprioritization.
+  const RequestPriority priority_;
   // Timer to abort jobs that take too long.
   base::OneShotTimer<ConnectJob> timer_;
   Delegate* delegate_;
@@ -175,6 +183,7 @@
    private:
     ClientSocketHandle* const handle_;
     CompletionCallback callback_;
+    // TODO(akalin): Support reprioritization.
     const RequestPriority priority_;
     bool ignore_limits_;
     const Flags flags_;
@@ -188,7 +197,7 @@
     ConnectJobFactory() {}
     virtual ~ConnectJobFactory() {}
 
-    virtual ConnectJob* NewConnectJob(
+    virtual scoped_ptr<ConnectJob> NewConnectJob(
         const std::string& group_name,
         const Request& request,
         ConnectJob::Delegate* delegate) const = 0;
@@ -200,6 +209,7 @@
   };
 
   ClientSocketPoolBaseHelper(
+      HigherLayeredPool* pool,
       int max_sockets,
       int max_sockets_per_group,
       base::TimeDelta unused_idle_socket_timeout,
@@ -208,15 +218,21 @@
 
   virtual ~ClientSocketPoolBaseHelper();
 
-  // Adds/Removes layered pools. It is expected in the destructor that no
-  // layered pools remain.
-  void AddLayeredPool(LayeredPool* pool);
-  void RemoveLayeredPool(LayeredPool* pool);
+  // Adds a lower layered pool to |this|, and adds |this| as a higher layered
+  // pool on top of |lower_pool|.
+  void AddLowerLayeredPool(LowerLayeredPool* lower_pool);
+
+  // See LowerLayeredPool::IsStalled for documentation on this function.
+  bool IsStalled() const;
+
+  // See LowerLayeredPool for documentation on these functions. It is expected
+  // in the destructor that no higher layer pools remain.
+  void AddHigherLayeredPool(HigherLayeredPool* higher_pool);
+  void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool);
 
   // See ClientSocketPool::RequestSocket for documentation on this function.
-  // ClientSocketPoolBaseHelper takes ownership of |request|, which must be
-  // heap allocated.
-  int RequestSocket(const std::string& group_name, const Request* request);
+  int RequestSocket(const std::string& group_name,
+                    scoped_ptr<const Request> request);
 
   // See ClientSocketPool::RequestSocket for documentation on this function.
   void RequestSockets(const std::string& group_name,
@@ -229,15 +245,12 @@
 
   // See ClientSocketPool::ReleaseSocket for documentation on this function.
   void ReleaseSocket(const std::string& group_name,
-                     StreamSocket* socket,
+                     scoped_ptr<StreamSocket> socket,
                      int id);
 
   // See ClientSocketPool::FlushWithError for documentation on this function.
   void FlushWithError(int error);
 
-  // See ClientSocketPool::IsStalled for documentation on this function.
-  bool IsStalled() const;
-
   // See ClientSocketPool::CloseIdleSockets for documentation on this function.
   void CloseIdleSockets();
 
@@ -294,8 +307,8 @@
   // I'm not sure if we hit this situation often.
   bool CloseOneIdleSocket();
 
-  // Checks layered pools to see if they can close an idle connection.
-  bool CloseOneIdleConnectionInLayeredPool();
+  // Checks higher layered pools to see if they can close an idle connection.
+  bool CloseOneIdleConnectionInHigherLayeredPool();
 
   // See ClientSocketPool::GetInfoAsValue for documentation on this function.
   base::DictionaryValue* GetInfoAsValue(const std::string& name,
@@ -386,22 +399,55 @@
     // Otherwise, returns false.
     bool TryToUseUnassignedConnectJob();
 
-    void AddJob(ConnectJob* job, bool is_preconnect);
+    void AddJob(scoped_ptr<ConnectJob> job, bool is_preconnect);
+    // Remove |job| from this group, which must already own |job|.
     void RemoveJob(ConnectJob* job);
     void RemoveAllJobs();
 
+    bool has_pending_requests() const {
+      return !pending_requests_.empty();
+    }
+
+    size_t pending_request_count() const {
+      return pending_requests_.size();
+    }
+
+    // Gets (but does not remove) the next pending request. Returns
+    // NULL if there are no pending requests.
+    const Request* GetNextPendingRequest() const;
+
+    // Returns true if there is a connect job for |handle|.
+    bool HasConnectJobForHandle(const ClientSocketHandle* handle) const;
+
+    // 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);
+
+    // Gets and removes the next pending request. Returns NULL if
+    // there are no pending requests.
+    scoped_ptr<const Request> PopNextPendingRequest();
+
+    // Finds the pending request for |handle| and removes it. Returns
+    // the removed pending request, or NULL if there was none.
+    scoped_ptr<const Request> FindAndRemovePendingRequest(
+        ClientSocketHandle* handle);
+
     void IncrementActiveSocketCount() { active_socket_count_++; }
     void DecrementActiveSocketCount() { active_socket_count_--; }
 
     int unassigned_job_count() const { return unassigned_job_count_; }
     const std::set<ConnectJob*>& jobs() const { return jobs_; }
     const std::list<IdleSocket>& idle_sockets() const { return idle_sockets_; }
-    const RequestQueue& pending_requests() const { return pending_requests_; }
     int active_socket_count() const { return active_socket_count_; }
-    RequestQueue* mutable_pending_requests() { return &pending_requests_; }
     std::list<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; }
 
    private:
+    // Returns the iterator's pending request after removing it from
+    // the queue.
+    scoped_ptr<const Request> RemovePendingRequest(
+        const RequestQueue::iterator& it);
+
     // Called when the backup socket timer fires.
     void OnBackupSocketTimerFired(
         std::string group_name,
@@ -443,15 +489,6 @@
   typedef std::map<const ClientSocketHandle*, CallbackResultPair>
       PendingCallbackMap;
 
-  // Inserts the request into the queue based on order they will receive
-  // sockets. Sockets which ignore the socket pool limits are first. Then
-  // requests are sorted by priority, with higher priorities closer to the
-  // front. Older requests are prioritized over requests of equal priority.
-  static void InsertRequestIntoQueue(const Request* r,
-                                     RequestQueue* pending_requests);
-  static const Request* RemoveRequestFromQueue(const RequestQueue::iterator& it,
-                                               Group* group);
-
   Group* GetOrCreateGroup(const std::string& group_name);
   void RemoveGroup(const std::string& group_name);
   void RemoveGroup(GroupMap::iterator it);
@@ -475,7 +512,7 @@
     CleanupIdleSockets(false);
   }
 
-  // Removes |job| from |connect_job_set_|.  Also updates |group| if non-NULL.
+  // Removes |job| from |group|, which must already own |job|.
   void RemoveConnectJob(ConnectJob* job, Group* group);
 
   // Tries to see if we can handle any more requests for |group|.
@@ -485,7 +522,7 @@
   void ProcessPendingRequest(const std::string& group_name, Group* group);
 
   // Assigns |socket| to |handle| and updates |group|'s counters appropriately.
-  void HandOutSocket(StreamSocket* socket,
+  void HandOutSocket(scoped_ptr<StreamSocket> socket,
                      bool reused,
                      const LoadTimingInfo::ConnectTiming& connect_timing,
                      ClientSocketHandle* handle,
@@ -494,7 +531,7 @@
                      const BoundNetLog& net_log);
 
   // Adds |socket| to the list of idle sockets for |group|.
-  void AddIdleSocket(StreamSocket* socket, Group* group);
+  void AddIdleSocket(scoped_ptr<StreamSocket> socket, Group* group);
 
   // Iterates through |group_map_|, canceling all ConnectJobs and deleting
   // groups if they are no longer needed.
@@ -511,14 +548,14 @@
   // it does not handle logging into NetLog of the queueing status of
   // |request|.
   int RequestSocketInternal(const std::string& group_name,
-                            const Request* request);
+                            const Request& request);
 
   // Assigns an idle socket for the group to the request.
   // Returns |true| if an idle socket is available, false otherwise.
-  bool AssignIdleSocketToRequest(const Request* request, Group* group);
+  bool AssignIdleSocketToRequest(const Request& request, Group* group);
 
   static void LogBoundConnectJobToRequest(
-      const NetLog::Source& connect_job_source, const Request* request);
+      const NetLog::Source& connect_job_source, const Request& request);
 
   // Same as CloseOneIdleSocket() except it won't close an idle socket in
   // |group|.  If |group| is NULL, it is ignored.  Returns true if it closed a
@@ -588,7 +625,18 @@
   // to the pool, we can make sure that they are discarded rather than reused.
   int pool_generation_number_;
 
-  std::set<LayeredPool*> higher_layer_pools_;
+  // Used to add |this| as a higher layer pool on top of lower layer pools.  May
+  // be NULL if no lower layer pools will be added.
+  HigherLayeredPool* pool_;
+
+  // Pools that create connections through |this|.  |this| will try to close
+  // their idle sockets when it stalls.  Must be empty on destruction.
+  std::set<HigherLayeredPool*> higher_pools_;
+
+  // Pools that this goes through.  Typically there's only one, but not always.
+  // |this| will check if they're stalled when it has a new idle socket.  |this|
+  // will remove itself from all lower layered pools on destruction.
+  std::set<LowerLayeredPool*> lower_pools_;
 
   base::WeakPtrFactory<ClientSocketPoolBaseHelper> weak_factory_;
 
@@ -624,7 +672,7 @@
     ConnectJobFactory() {}
     virtual ~ConnectJobFactory() {}
 
-    virtual ConnectJob* NewConnectJob(
+    virtual scoped_ptr<ConnectJob> NewConnectJob(
         const std::string& group_name,
         const Request& request,
         ConnectJob::Delegate* delegate) const = 0;
@@ -642,6 +690,7 @@
   // |used_idle_socket_timeout| specifies how long to leave a previously used
   // idle socket open before closing it.
   ClientSocketPoolBase(
+      HigherLayeredPool* self,
       int max_sockets,
       int max_sockets_per_group,
       ClientSocketPoolHistograms* histograms,
@@ -649,19 +698,23 @@
       base::TimeDelta used_idle_socket_timeout,
       ConnectJobFactory* connect_job_factory)
       : histograms_(histograms),
-        helper_(max_sockets, max_sockets_per_group,
+        helper_(self, max_sockets, max_sockets_per_group,
                 unused_idle_socket_timeout, used_idle_socket_timeout,
                 new ConnectJobFactoryAdaptor(connect_job_factory)) {}
 
   virtual ~ClientSocketPoolBase() {}
 
   // These member functions simply forward to ClientSocketPoolBaseHelper.
-  void AddLayeredPool(LayeredPool* pool) {
-    helper_.AddLayeredPool(pool);
+  void AddLowerLayeredPool(LowerLayeredPool* lower_pool) {
+    helper_.AddLowerLayeredPool(lower_pool);
   }
 
-  void RemoveLayeredPool(LayeredPool* pool) {
-    helper_.RemoveLayeredPool(pool);
+  void AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
+    helper_.AddHigherLayeredPool(higher_pool);
+  }
+
+  void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) {
+    helper_.RemoveHigherLayeredPool(higher_pool);
   }
 
   // RequestSocket bundles up the parameters into a Request and then forwards to
@@ -672,12 +725,15 @@
                     ClientSocketHandle* handle,
                     const CompletionCallback& callback,
                     const BoundNetLog& net_log) {
-    Request* request =
+    scoped_ptr<const Request> request(
         new Request(handle, callback, priority,
                     internal::ClientSocketPoolBaseHelper::NORMAL,
                     params->ignore_limits(),
-                    params, net_log);
-    return helper_.RequestSocket(group_name, request);
+                    params, net_log));
+    return helper_.RequestSocket(
+        group_name,
+        request.template PassAs<
+            const internal::ClientSocketPoolBaseHelper::Request>());
   }
 
   // RequestSockets bundles up the parameters into a Request and then forwards
@@ -702,9 +758,10 @@
     return helper_.CancelRequest(group_name, handle);
   }
 
-  void ReleaseSocket(const std::string& group_name, StreamSocket* socket,
+  void ReleaseSocket(const std::string& group_name,
+                     scoped_ptr<StreamSocket> socket,
                      int id) {
-    return helper_.ReleaseSocket(group_name, socket, id);
+    return helper_.ReleaseSocket(group_name, socket.Pass(), id);
   }
 
   void FlushWithError(int error) { helper_.FlushWithError(error); }
@@ -765,8 +822,8 @@
 
   bool CloseOneIdleSocket() { return helper_.CloseOneIdleSocket(); }
 
-  bool CloseOneIdleConnectionInLayeredPool() {
-    return helper_.CloseOneIdleConnectionInLayeredPool();
+  bool CloseOneIdleConnectionInHigherLayeredPool() {
+    return helper_.CloseOneIdleConnectionInHigherLayeredPool();
   }
 
  private:
@@ -785,13 +842,13 @@
         : connect_job_factory_(connect_job_factory) {}
     virtual ~ConnectJobFactoryAdaptor() {}
 
-    virtual ConnectJob* NewConnectJob(
+    virtual scoped_ptr<ConnectJob> NewConnectJob(
         const std::string& group_name,
         const internal::ClientSocketPoolBaseHelper::Request& request,
-        ConnectJob::Delegate* delegate) const {
-      const Request* casted_request = static_cast<const Request*>(&request);
+        ConnectJob::Delegate* delegate) const OVERRIDE {
+      const Request& casted_request = static_cast<const Request&>(request);
       return connect_job_factory_->NewConnectJob(
-          group_name, *casted_request, delegate);
+          group_name, casted_request, delegate);
     }
 
     virtual base::TimeDelta ConnectionTimeout() const {
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 5eeda97..bbeca2f 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -30,7 +30,9 @@
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/client_socket_pool_histograms.h"
 #include "net/socket/socket_test_util.h"
+#include "net/socket/ssl_client_socket.h"
 #include "net/socket/stream_socket.h"
+#include "net/udp/datagram_client_socket.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -189,30 +191,30 @@
  public:
   MockClientSocketFactory() : allocation_count_(0) {}
 
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE {
     NOTREACHED();
-    return NULL;
+    return scoped_ptr<DatagramClientSocket>();
   }
 
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList& addresses,
       NetLog* /* net_log */,
       const NetLog::Source& /*source*/) OVERRIDE {
     allocation_count_++;
-    return NULL;
+    return scoped_ptr<StreamSocket>();
   }
 
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       const SSLClientSocketContext& context) OVERRIDE {
     NOTIMPLEMENTED();
-    return NULL;
+    return scoped_ptr<SSLClientSocket>();
   }
 
   virtual void ClearSSLSessionCache() OVERRIDE {
@@ -259,7 +261,7 @@
                  ConnectJob::Delegate* delegate,
                  MockClientSocketFactory* client_socket_factory,
                  NetLog* net_log)
-      : ConnectJob(group_name, timeout_duration, delegate,
+      : ConnectJob(group_name, timeout_duration, request.priority(), delegate,
                    BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
         job_type_(job_type),
         client_socket_factory_(client_socket_factory),
@@ -294,7 +296,8 @@
     AddressList ignored;
     client_socket_factory_->CreateTransportClientSocket(
         ignored, NULL, net::NetLog::Source());
-    set_socket(new MockClientSocket(net_log().net_log()));
+    SetSocket(
+        scoped_ptr<StreamSocket>(new MockClientSocket(net_log().net_log())));
     switch (job_type_) {
       case kMockJob:
         return DoConnect(true /* successful */, false /* sync */,
@@ -373,7 +376,7 @@
         return ERR_IO_PENDING;
       default:
         NOTREACHED();
-        set_socket(NULL);
+        SetSocket(scoped_ptr<StreamSocket>());
         return ERR_FAILED;
     }
   }
@@ -386,7 +389,7 @@
       result = ERR_PROXY_AUTH_REQUESTED;
     } else {
       result = ERR_CONNECTION_FAILED;
-      set_socket(NULL);
+      SetSocket(scoped_ptr<StreamSocket>());
     }
 
     if (was_async)
@@ -430,7 +433,7 @@
 
   // ConnectJobFactory implementation.
 
-  virtual ConnectJob* NewConnectJob(
+  virtual scoped_ptr<ConnectJob> NewConnectJob(
       const std::string& group_name,
       const TestClientSocketPoolBase::Request& request,
       ConnectJob::Delegate* delegate) const OVERRIDE {
@@ -440,13 +443,13 @@
       job_type = job_types_->front();
       job_types_->pop_front();
     }
-    return new TestConnectJob(job_type,
-                              group_name,
-                              request,
-                              timeout_duration_,
-                              delegate,
-                              client_socket_factory_,
-                              net_log_);
+    return scoped_ptr<ConnectJob>(new TestConnectJob(job_type,
+                                                     group_name,
+                                                     request,
+                                                     timeout_duration_,
+                                                     delegate,
+                                                     client_socket_factory_,
+                                                     net_log_));
   }
 
   virtual base::TimeDelta ConnectionTimeout() const OVERRIDE {
@@ -465,6 +468,8 @@
 
 class TestClientSocketPool : public ClientSocketPool {
  public:
+  typedef TestSocketParams SocketParams;
+
   TestClientSocketPool(
       int max_sockets,
       int max_sockets_per_group,
@@ -472,7 +477,7 @@
       base::TimeDelta unused_idle_socket_timeout,
       base::TimeDelta used_idle_socket_timeout,
       TestClientSocketPoolBase::ConnectJobFactory* connect_job_factory)
-      : base_(max_sockets, max_sockets_per_group, histograms,
+      : base_(NULL, max_sockets, max_sockets_per_group, histograms,
               unused_idle_socket_timeout, used_idle_socket_timeout,
               connect_job_factory) {}
 
@@ -509,9 +514,9 @@
 
   virtual void ReleaseSocket(
       const std::string& group_name,
-      StreamSocket* socket,
+      scoped_ptr<StreamSocket> socket,
       int id) OVERRIDE {
-    base_.ReleaseSocket(group_name, socket, id);
+    base_.ReleaseSocket(group_name, socket.Pass(), id);
   }
 
   virtual void FlushWithError(int error) OVERRIDE {
@@ -541,12 +546,13 @@
     return base_.GetLoadState(group_name, handle);
   }
 
-  virtual void AddLayeredPool(LayeredPool* pool) OVERRIDE {
-    base_.AddLayeredPool(pool);
+  virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE {
+    base_.AddHigherLayeredPool(higher_pool);
   }
 
-  virtual void RemoveLayeredPool(LayeredPool* pool) OVERRIDE {
-    base_.RemoveLayeredPool(pool);
+  virtual void RemoveHigherLayeredPool(
+      HigherLayeredPool* higher_pool) OVERRIDE {
+    base_.RemoveHigherLayeredPool(higher_pool);
   }
 
   virtual base::DictionaryValue* GetInfoAsValue(
@@ -586,8 +592,8 @@
 
   void EnableConnectBackupJobs() { base_.EnableConnectBackupJobs(); }
 
-  bool CloseOneIdleConnectionInLayeredPool() {
-    return base_.CloseOneIdleConnectionInLayeredPool();
+  bool CloseOneIdleConnectionInHigherLayeredPool() {
+    return base_.CloseOneIdleConnectionInHigherLayeredPool();
   }
 
  private:
@@ -598,8 +604,6 @@
 
 }  // namespace
 
-REGISTER_SOCKET_PARAMS_FOR_POOL(TestClientSocketPool, TestSocketParams);
-
 namespace {
 
 void MockClientSocketFactory::SignalJobs() {
@@ -630,10 +634,10 @@
 
   virtual void OnConnectJobComplete(int result, ConnectJob* job) OVERRIDE {
     result_ = result;
-    scoped_ptr<StreamSocket> socket(job->ReleaseSocket());
+    scoped_ptr<ConnectJob> owned_job(job);
+    scoped_ptr<StreamSocket> socket = owned_job->PassSocket();
     // socket.get() should be NULL iff result != OK
-    EXPECT_EQ(socket.get() == NULL, result != OK);
-    delete job;
+    EXPECT_EQ(socket == NULL, result != OK);
     have_result_ = true;
     if (waiting_for_result_)
       base::MessageLoop::current()->Quit();
@@ -702,9 +706,8 @@
       const std::string& group_name,
       RequestPriority priority,
       const scoped_refptr<TestSocketParams>& params) {
-    return test_base_.StartRequestUsingPool<
-        TestClientSocketPool, TestSocketParams>(
-            pool_.get(), group_name, priority, params);
+    return test_base_.StartRequestUsingPool(
+        pool_.get(), group_name, priority, params);
   }
 
   int StartRequest(const std::string& group_name, RequestPriority priority) {
@@ -3716,7 +3719,7 @@
   EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
 }
 
-class MockLayeredPool : public LayeredPool {
+class MockLayeredPool : public HigherLayeredPool {
  public:
   MockLayeredPool(TestClientSocketPool* pool,
                   const std::string& group_name)
@@ -3724,11 +3727,11 @@
         params_(new TestSocketParams),
         group_name_(group_name),
         can_release_connection_(true) {
-    pool_->AddLayeredPool(this);
+    pool_->AddHigherLayeredPool(this);
   }
 
   ~MockLayeredPool() {
-    pool_->RemoveLayeredPool(this);
+    pool_->RemoveHigherLayeredPool(this);
   }
 
   int RequestSocket(TestClientSocketPool* pool) {
@@ -3774,7 +3777,7 @@
   EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
   EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
       .WillOnce(Return(false));
-  EXPECT_FALSE(pool_->CloseOneIdleConnectionInLayeredPool());
+  EXPECT_FALSE(pool_->CloseOneIdleConnectionInHigherLayeredPool());
 }
 
 TEST_F(ClientSocketPoolBaseTest, ForciblyCloseIdleSocketsHeldByLayeredPool) {
@@ -3786,7 +3789,7 @@
   EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
       .WillOnce(Invoke(&mock_layered_pool,
                        &MockLayeredPool::ReleaseOneConnection));
-  EXPECT_TRUE(pool_->CloseOneIdleConnectionInLayeredPool());
+  EXPECT_TRUE(pool_->CloseOneIdleConnectionInHigherLayeredPool());
 }
 
 // Tests the basic case of closing an idle socket in a higher layered pool when
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index 71496d2..b37d2d1 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -158,7 +158,6 @@
   bool ignore_limits = (request_load_flags & LOAD_IGNORE_LIMITS) != 0;
   if (proxy_info.is_direct()) {
     tcp_params = new TransportSocketParams(origin_host_port,
-                                           request_priority,
                                            disable_resolver_cache,
                                            ignore_limits,
                                            resolution_callback);
@@ -167,7 +166,6 @@
     proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair()));
     scoped_refptr<TransportSocketParams> proxy_tcp_params(
         new TransportSocketParams(*proxy_host_port,
-                                  request_priority,
                                   disable_resolver_cache,
                                   ignore_limits,
                                   resolution_callback));
@@ -182,7 +180,6 @@
         ssl_params = new SSLSocketParams(proxy_tcp_params,
                                          NULL,
                                          NULL,
-                                         ProxyServer::SCHEME_DIRECT,
                                          *proxy_host_port.get(),
                                          ssl_config_for_proxy,
                                          kPrivacyModeDisabled,
@@ -214,8 +211,7 @@
 
       socks_params = new SOCKSSocketParams(proxy_tcp_params,
                                            socks_version == '5',
-                                           origin_host_port,
-                                           request_priority);
+                                           origin_host_port);
     }
   }
 
@@ -229,7 +225,6 @@
         new SSLSocketParams(tcp_params,
                             socks_params,
                             http_proxy_params,
-                            proxy_info.proxy_server().scheme(),
                             origin_host_port,
                             ssl_config_for_origin,
                             privacy_mode,
diff --git a/net/socket/deterministic_socket_data_unittest.cc b/net/socket/deterministic_socket_data_unittest.cc
index eba01b5..c51427e 100644
--- a/net/socket/deterministic_socket_data_unittest.cc
+++ b/net/socket/deterministic_socket_data_unittest.cc
@@ -72,7 +72,6 @@
       connect_data_(SYNCHRONOUS, OK),
       endpoint_("www.google.com", 443),
       tcp_params_(new TransportSocketParams(endpoint_,
-                                            LOWEST,
                                             false,
                                             false,
                                             OnHostResolutionCallback())),
diff --git a/net/socket/nss_ssl_util.cc b/net/socket/nss_ssl_util.cc
index be33ac5..ae037b1 100644
--- a/net/socket/nss_ssl_util.cc
+++ b/net/socket/nss_ssl_util.cc
@@ -58,12 +58,13 @@
           enabled = false;
 
         // Trim the list of cipher suites in order to keep the size of the
-        // ClientHello down. DSS, ECDH, CAMELLIA, SEED and ECC+3DES cipher
-        // suites are disabled.
+        // ClientHello down. DSS, ECDH, CAMELLIA, SEED, ECC+3DES, and
+        // HMAC-SHA256 cipher suites are disabled.
         if (info.symCipher == ssl_calg_camellia ||
             info.symCipher == ssl_calg_seed ||
             (info.symCipher == ssl_calg_3des && info.keaType != ssl_kea_rsa) ||
             info.authAlgorithm == ssl_auth_dsa ||
+            info.macAlgorithm == ssl_hmac_sha256 ||
             info.nonStandard ||
             strcmp(info.keaTypeName, "ECDH") == 0) {
           enabled = false;
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 8b2bdfc..78e9e7c 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -657,37 +657,39 @@
   mock_ssl_data_.ResetNextIndex();
 }
 
-DatagramClientSocket* MockClientSocketFactory::CreateDatagramClientSocket(
+scoped_ptr<DatagramClientSocket>
+MockClientSocketFactory::CreateDatagramClientSocket(
     DatagramSocket::BindType bind_type,
     const RandIntCallback& rand_int_cb,
     net::NetLog* net_log,
     const net::NetLog::Source& source) {
   SocketDataProvider* data_provider = mock_data_.GetNext();
-  MockUDPClientSocket* socket = new MockUDPClientSocket(data_provider, net_log);
-  data_provider->set_socket(socket);
-  return socket;
+  scoped_ptr<MockUDPClientSocket> socket(
+      new MockUDPClientSocket(data_provider, net_log));
+  data_provider->set_socket(socket.get());
+  return socket.PassAs<DatagramClientSocket>();
 }
 
-StreamSocket* MockClientSocketFactory::CreateTransportClientSocket(
+scoped_ptr<StreamSocket> MockClientSocketFactory::CreateTransportClientSocket(
     const AddressList& addresses,
     net::NetLog* net_log,
     const net::NetLog::Source& source) {
   SocketDataProvider* data_provider = mock_data_.GetNext();
-  MockTCPClientSocket* socket =
-      new MockTCPClientSocket(addresses, net_log, data_provider);
-  data_provider->set_socket(socket);
-  return socket;
+  scoped_ptr<MockTCPClientSocket> socket(
+      new MockTCPClientSocket(addresses, net_log, data_provider));
+  data_provider->set_socket(socket.get());
+  return socket.PassAs<StreamSocket>();
 }
 
-SSLClientSocket* MockClientSocketFactory::CreateSSLClientSocket(
-    ClientSocketHandle* transport_socket,
+scoped_ptr<SSLClientSocket> MockClientSocketFactory::CreateSSLClientSocket(
+    scoped_ptr<ClientSocketHandle> transport_socket,
     const HostPortPair& host_and_port,
     const SSLConfig& ssl_config,
     const SSLClientSocketContext& context) {
-  MockSSLClientSocket* socket =
-      new MockSSLClientSocket(transport_socket, host_and_port, ssl_config,
-                              mock_ssl_data_.GetNext());
-  return socket;
+  return scoped_ptr<SSLClientSocket>(
+      new MockSSLClientSocket(transport_socket.Pass(),
+                              host_and_port, ssl_config,
+                              mock_ssl_data_.GetNext()));
 }
 
 void MockClientSocketFactory::ClearSSLSessionCache() {
@@ -1278,7 +1280,7 @@
 
 // static
 void MockSSLClientSocket::ConnectCallback(
-    MockSSLClientSocket *ssl_client_socket,
+    MockSSLClientSocket* ssl_client_socket,
     const CompletionCallback& callback,
     int rv) {
   if (rv == OK)
@@ -1287,7 +1289,7 @@
 }
 
 MockSSLClientSocket::MockSSLClientSocket(
-    ClientSocketHandle* transport_socket,
+    scoped_ptr<ClientSocketHandle> transport_socket,
     const HostPortPair& host_port_pair,
     const SSLConfig& ssl_config,
     SSLSocketDataProvider* data)
@@ -1295,7 +1297,7 @@
          // Have to use the right BoundNetLog for LoadTimingInfo regression
          // tests.
          transport_socket->socket()->NetLog()),
-      transport_(transport_socket),
+      transport_(transport_socket.Pass()),
       data_(data),
       is_npn_state_set_(false),
       new_npn_value_(false),
@@ -1664,10 +1666,10 @@
 }
 
 MockTransportClientSocketPool::MockConnectJob::MockConnectJob(
-    StreamSocket* socket,
+    scoped_ptr<StreamSocket> socket,
     ClientSocketHandle* handle,
     const CompletionCallback& callback)
-    : socket_(socket),
+    : socket_(socket.Pass()),
       handle_(handle),
       user_callback_(callback) {
 }
@@ -1698,7 +1700,7 @@
   if (!socket_.get())
     return;
   if (rv == OK) {
-    handle_->set_socket(socket_.release());
+    handle_->SetSocket(socket_.Pass());
 
     // Needed for socket pool tests that layer other sockets on top of mock
     // sockets.
@@ -1730,6 +1732,7 @@
     : TransportClientSocketPool(max_sockets, max_sockets_per_group, histograms,
                                 NULL, NULL, NULL),
       client_socket_factory_(socket_factory),
+      last_request_priority_(DEFAULT_PRIORITY),
       release_count_(0),
       cancel_count_(0) {
 }
@@ -1740,9 +1743,11 @@
     const std::string& group_name, const void* socket_params,
     RequestPriority priority, ClientSocketHandle* handle,
     const CompletionCallback& callback, const BoundNetLog& net_log) {
-  StreamSocket* socket = client_socket_factory_->CreateTransportClientSocket(
-      AddressList(), net_log.net_log(), net::NetLog::Source());
-  MockConnectJob* job = new MockConnectJob(socket, handle, callback);
+  last_request_priority_ = priority;
+  scoped_ptr<StreamSocket> socket =
+      client_socket_factory_->CreateTransportClientSocket(
+          AddressList(), net_log.net_log(), net::NetLog::Source());
+  MockConnectJob* job = new MockConnectJob(socket.Pass(), handle, callback);
   job_list_.push_back(job);
   handle->set_pool_id(1);
   return job->Connect();
@@ -1759,11 +1764,12 @@
   }
 }
 
-void MockTransportClientSocketPool::ReleaseSocket(const std::string& group_name,
-                                            StreamSocket* socket, int id) {
+void MockTransportClientSocketPool::ReleaseSocket(
+    const std::string& group_name,
+    scoped_ptr<StreamSocket> socket,
+    int id) {
   EXPECT_EQ(1, id);
   release_count_++;
-  delete socket;
 }
 
 DeterministicMockClientSocketFactory::DeterministicMockClientSocketFactory() {}
@@ -1791,42 +1797,45 @@
   return ssl_client_sockets_[index];
 }
 
-DatagramClientSocket*
+scoped_ptr<DatagramClientSocket>
 DeterministicMockClientSocketFactory::CreateDatagramClientSocket(
     DatagramSocket::BindType bind_type,
     const RandIntCallback& rand_int_cb,
     net::NetLog* net_log,
     const NetLog::Source& source) {
   DeterministicSocketData* data_provider = mock_data().GetNext();
-  DeterministicMockUDPClientSocket* socket =
-      new DeterministicMockUDPClientSocket(net_log, data_provider);
+  scoped_ptr<DeterministicMockUDPClientSocket> socket(
+      new DeterministicMockUDPClientSocket(net_log, data_provider));
   data_provider->set_delegate(socket->AsWeakPtr());
-  udp_client_sockets().push_back(socket);
-  return socket;
+  udp_client_sockets().push_back(socket.get());
+  return socket.PassAs<DatagramClientSocket>();
 }
 
-StreamSocket* DeterministicMockClientSocketFactory::CreateTransportClientSocket(
+scoped_ptr<StreamSocket>
+DeterministicMockClientSocketFactory::CreateTransportClientSocket(
     const AddressList& addresses,
     net::NetLog* net_log,
     const net::NetLog::Source& source) {
   DeterministicSocketData* data_provider = mock_data().GetNext();
-  DeterministicMockTCPClientSocket* socket =
-      new DeterministicMockTCPClientSocket(net_log, data_provider);
+  scoped_ptr<DeterministicMockTCPClientSocket> socket(
+      new DeterministicMockTCPClientSocket(net_log, data_provider));
   data_provider->set_delegate(socket->AsWeakPtr());
-  tcp_client_sockets().push_back(socket);
-  return socket;
+  tcp_client_sockets().push_back(socket.get());
+  return socket.PassAs<StreamSocket>();
 }
 
-SSLClientSocket* DeterministicMockClientSocketFactory::CreateSSLClientSocket(
-    ClientSocketHandle* transport_socket,
+scoped_ptr<SSLClientSocket>
+DeterministicMockClientSocketFactory::CreateSSLClientSocket(
+    scoped_ptr<ClientSocketHandle> transport_socket,
     const HostPortPair& host_and_port,
     const SSLConfig& ssl_config,
     const SSLClientSocketContext& context) {
-  MockSSLClientSocket* socket =
-      new MockSSLClientSocket(transport_socket, host_and_port, ssl_config,
-                              mock_ssl_data_.GetNext());
-  ssl_client_sockets_.push_back(socket);
-  return socket;
+  scoped_ptr<MockSSLClientSocket> socket(
+      new MockSSLClientSocket(transport_socket.Pass(),
+                              host_and_port, ssl_config,
+                              mock_ssl_data_.GetNext()));
+  ssl_client_sockets_.push_back(socket.get());
+  return socket.PassAs<SSLClientSocket>();
 }
 
 void DeterministicMockClientSocketFactory::ClearSSLSessionCache() {
@@ -1859,8 +1868,9 @@
 }
 
 void MockSOCKSClientSocketPool::ReleaseSocket(const std::string& group_name,
-                                              StreamSocket* socket, int id) {
-  return transport_pool_->ReleaseSocket(group_name, socket, id);
+                                              scoped_ptr<StreamSocket> socket,
+                                              int id) {
+  return transport_pool_->ReleaseSocket(group_name, socket.Pass(), id);
 }
 
 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 };
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 6afe170..e4e5652 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -13,6 +13,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
@@ -592,17 +593,17 @@
   }
 
   // ClientSocketFactory
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE;
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList& addresses,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE;
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       const SSLClientSocketContext& context) OVERRIDE;
@@ -857,7 +858,7 @@
 class MockSSLClientSocket : public MockClientSocket, public AsyncSocket {
  public:
   MockSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       SSLSocketDataProvider* socket);
@@ -1001,11 +1002,12 @@
   ClientSocketPoolTest();
   ~ClientSocketPoolTest();
 
-  template <typename PoolType, typename SocketParams>
-  int StartRequestUsingPool(PoolType* socket_pool,
-                            const std::string& group_name,
-                            RequestPriority priority,
-                            const scoped_refptr<SocketParams>& socket_params) {
+  template <typename PoolType>
+  int StartRequestUsingPool(
+      PoolType* socket_pool,
+      const std::string& group_name,
+      RequestPriority priority,
+      const scoped_refptr<typename PoolType::SocketParams>& socket_params) {
     DCHECK(socket_pool);
     TestSocketRequest* request = new TestSocketRequest(&request_order_,
                                                        &completion_count_);
@@ -1045,11 +1047,20 @@
   size_t completion_count_;
 };
 
+class MockTransportSocketParams
+    : public base::RefCounted<MockTransportSocketParams> {
+ private:
+  friend class base::RefCounted<MockTransportSocketParams>;
+  ~MockTransportSocketParams() {}
+};
+
 class MockTransportClientSocketPool : public TransportClientSocketPool {
  public:
+  typedef MockTransportSocketParams SocketParams;
+
   class MockConnectJob {
    public:
-    MockConnectJob(StreamSocket* socket, ClientSocketHandle* handle,
+    MockConnectJob(scoped_ptr<StreamSocket> socket, ClientSocketHandle* handle,
                    const CompletionCallback& callback);
     ~MockConnectJob();
 
@@ -1074,6 +1085,9 @@
 
   virtual ~MockTransportClientSocketPool();
 
+  RequestPriority last_request_priority() const {
+    return last_request_priority_;
+  }
   int release_count() const { return release_count_; }
   int cancel_count() const { return cancel_count_; }
 
@@ -1088,11 +1102,13 @@
   virtual void CancelRequest(const std::string& group_name,
                              ClientSocketHandle* handle) OVERRIDE;
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket, int id) OVERRIDE;
+                             scoped_ptr<StreamSocket> socket,
+                             int id) OVERRIDE;
 
  private:
   ClientSocketFactory* client_socket_factory_;
   ScopedVector<MockConnectJob> job_list_;
+  RequestPriority last_request_priority_;
   int release_count_;
   int cancel_count_;
 
@@ -1123,17 +1139,17 @@
   }
 
   // ClientSocketFactory
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE;
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList& addresses,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE;
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       const SSLClientSocketContext& context) OVERRIDE;
@@ -1170,7 +1186,8 @@
   virtual void CancelRequest(const std::string& group_name,
                              ClientSocketHandle* handle) OVERRIDE;
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket, int id) OVERRIDE;
+                             scoped_ptr<StreamSocket> socket,
+                             int id) OVERRIDE;
 
  private:
   TransportClientSocketPool* const transport_pool_;
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index c9d25bc..537b584 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -28,34 +28,18 @@
 COMPILE_ASSERT(sizeof(struct in6_addr) == 16, incorrect_system_size_of_IPv6);
 
 SOCKS5ClientSocket::SOCKS5ClientSocket(
-    ClientSocketHandle* transport_socket,
+    scoped_ptr<ClientSocketHandle> transport_socket,
     const HostResolver::RequestInfo& req_info)
     : io_callback_(base::Bind(&SOCKS5ClientSocket::OnIOComplete,
                               base::Unretained(this))),
-      transport_(transport_socket),
+      transport_(transport_socket.Pass()),
       next_state_(STATE_NONE),
       completed_handshake_(false),
       bytes_sent_(0),
       bytes_received_(0),
       read_header_size(kReadHeaderSize),
       host_request_info_(req_info),
-      net_log_(transport_socket->socket()->NetLog()) {
-}
-
-SOCKS5ClientSocket::SOCKS5ClientSocket(
-    StreamSocket* transport_socket,
-    const HostResolver::RequestInfo& req_info)
-    : io_callback_(base::Bind(&SOCKS5ClientSocket::OnIOComplete,
-                              base::Unretained(this))),
-      transport_(new ClientSocketHandle()),
-      next_state_(STATE_NONE),
-      completed_handshake_(false),
-      bytes_sent_(0),
-      bytes_received_(0),
-      read_header_size(kReadHeaderSize),
-      host_request_info_(req_info),
-      net_log_(transport_socket->NetLog()) {
-  transport_->set_socket(transport_socket);
+      net_log_(transport_->socket()->NetLog()) {
 }
 
 SOCKS5ClientSocket::~SOCKS5ClientSocket() {
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index b955e8f..4521624 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -28,20 +28,13 @@
 // Currently no SOCKSv5 authentication is supported.
 class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket {
  public:
-  // Takes ownership of the |transport_socket|, which should already be
-  // connected by the time Connect() is called.
-  //
   // |req_info| contains the hostname and port to which the socket above will
   // communicate to via the SOCKS layer.
   //
   // Although SOCKS 5 supports 3 different modes of addressing, we will
   // always pass it a hostname. This means the DNS resolving is done
   // proxy side.
-  SOCKS5ClientSocket(ClientSocketHandle* transport_socket,
-                     const HostResolver::RequestInfo& req_info);
-
-  // Deprecated constructor (http://crbug.com/37810) that takes a StreamSocket.
-  SOCKS5ClientSocket(StreamSocket* transport_socket,
+  SOCKS5ClientSocket(scoped_ptr<ClientSocketHandle> transport_socket,
                      const HostResolver::RequestInfo& req_info);
 
   // On destruction Disconnect() is called.
diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc
index 717d858..78f2ac4 100644
--- a/net/socket/socks5_client_socket_unittest.cc
+++ b/net/socket/socks5_client_socket_unittest.cc
@@ -32,13 +32,13 @@
  public:
   SOCKS5ClientSocketTest();
   // Create a SOCKSClientSocket on top of a MockSocket.
-  SOCKS5ClientSocket* BuildMockSocket(MockRead reads[],
-                                      size_t reads_count,
-                                      MockWrite writes[],
-                                      size_t writes_count,
-                                      const std::string& hostname,
-                                      int port,
-                                      NetLog* net_log);
+  scoped_ptr<SOCKS5ClientSocket> BuildMockSocket(MockRead reads[],
+                                                 size_t reads_count,
+                                                 MockWrite writes[],
+                                                 size_t writes_count,
+                                                 const std::string& hostname,
+                                                 int port,
+                                                 NetLog* net_log);
 
   virtual void SetUp();
 
@@ -47,6 +47,8 @@
   CapturingNetLog net_log_;
   scoped_ptr<SOCKS5ClientSocket> user_sock_;
   AddressList address_list_;
+  // Filled in by BuildMockSocket() and owned by its return value
+  // (which |user_sock| is set to).
   StreamSocket* tcp_sock_;
   TestCompletionCallback callback_;
   scoped_ptr<MockHostResolver> host_resolver_;
@@ -68,14 +70,18 @@
   // Resolve the "localhost" AddressList used by the TCP connection to connect.
   HostResolver::RequestInfo info(HostPortPair("www.socks-proxy.com", 1080));
   TestCompletionCallback callback;
-  int rv = host_resolver_->Resolve(info, &address_list_, callback.callback(),
-                                   NULL, BoundNetLog());
+  int rv = host_resolver_->Resolve(info,
+                                   DEFAULT_PRIORITY,
+                                   &address_list_,
+                                   callback.callback(),
+                                   NULL,
+                                   BoundNetLog());
   ASSERT_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   ASSERT_EQ(OK, rv);
 }
 
-SOCKS5ClientSocket* SOCKS5ClientSocketTest::BuildMockSocket(
+scoped_ptr<SOCKS5ClientSocket> SOCKS5ClientSocketTest::BuildMockSocket(
     MockRead reads[],
     size_t reads_count,
     MockWrite writes[],
@@ -94,8 +100,13 @@
   EXPECT_EQ(OK, rv);
   EXPECT_TRUE(tcp_sock_->IsConnected());
 
-  return new SOCKS5ClientSocket(tcp_sock_,
-      HostResolver::RequestInfo(HostPortPair(hostname, port)));
+  scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+  // |connection| takes ownership of |tcp_sock_|, but keep a
+  // non-owning pointer to it.
+  connection->SetSocket(scoped_ptr<StreamSocket>(tcp_sock_));
+  return scoped_ptr<SOCKS5ClientSocket>(new SOCKS5ClientSocket(
+      connection.Pass(),
+      HostResolver::RequestInfo(HostPortPair(hostname, port))));
 }
 
 // Tests a complete SOCKS5 handshake and the disconnection.
@@ -123,9 +134,9 @@
       MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength),
       MockRead(ASYNC, payload_read.data(), payload_read.size()) };
 
-  user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                   data_writes, arraysize(data_writes),
-                                   "localhost", 80, &net_log_));
+  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                               data_writes, arraysize(data_writes),
+                               "localhost", 80, &net_log_);
 
   // At this state the TCP connection is completed but not the SOCKS handshake.
   EXPECT_TRUE(tcp_sock_->IsConnected());
@@ -195,9 +206,9 @@
         MockRead(SYNCHRONOUS, kSOCKS5OkResponse, kSOCKS5OkResponseLength)
     };
 
-    user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                     data_writes, arraysize(data_writes),
-                                     hostname, 80, NULL));
+    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                                 data_writes, arraysize(data_writes),
+                                 hostname, 80, NULL);
 
     int rv = user_sock_->Connect(callback_.callback());
     EXPECT_EQ(OK, rv);
@@ -217,9 +228,9 @@
   // Create a SOCKS socket, with mock transport socket.
   MockWrite data_writes[] = {MockWrite()};
   MockRead data_reads[] = {MockRead()};
-  user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                   data_writes, arraysize(data_writes),
-                                   large_host_name, 80, NULL));
+  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                               data_writes, arraysize(data_writes),
+                               large_host_name, 80, NULL);
 
   // Try to connect -- should fail (without having read/written anything to
   // the transport socket first) because the hostname is too long.
@@ -253,9 +264,9 @@
     MockRead data_reads[] = {
         MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
         MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
-    user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                     data_writes, arraysize(data_writes),
-                                     hostname, 80, &net_log_));
+    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                                 data_writes, arraysize(data_writes),
+                                 hostname, 80, &net_log_);
     int rv = user_sock_->Connect(callback_.callback());
     EXPECT_EQ(ERR_IO_PENDING, rv);
 
@@ -284,9 +295,9 @@
         MockRead(ASYNC, partial1, arraysize(partial1)),
         MockRead(ASYNC, partial2, arraysize(partial2)),
         MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
-    user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                     data_writes, arraysize(data_writes),
-                                     hostname, 80, &net_log_));
+    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                                 data_writes, arraysize(data_writes),
+                                 hostname, 80, &net_log_);
     int rv = user_sock_->Connect(callback_.callback());
     EXPECT_EQ(ERR_IO_PENDING, rv);
 
@@ -314,9 +325,9 @@
     MockRead data_reads[] = {
         MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
         MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
-    user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                     data_writes, arraysize(data_writes),
-                                     hostname, 80, &net_log_));
+    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                                 data_writes, arraysize(data_writes),
+                                 hostname, 80, &net_log_);
     int rv = user_sock_->Connect(callback_.callback());
     EXPECT_EQ(ERR_IO_PENDING, rv);
     CapturingNetLog::CapturedEntryList net_log_entries;
@@ -345,9 +356,9 @@
                  kSOCKS5OkResponseLength - kSplitPoint)
     };
 
-    user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                     data_writes, arraysize(data_writes),
-                                     hostname, 80, &net_log_));
+    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                                 data_writes, arraysize(data_writes),
+                                 hostname, 80, &net_log_);
     int rv = user_sock_->Connect(callback_.callback());
     EXPECT_EQ(ERR_IO_PENDING, rv);
     CapturingNetLog::CapturedEntryList net_log_entries;
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index c4bbd28..6708958 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -55,32 +55,20 @@
 COMPILE_ASSERT(sizeof(SOCKS4ServerResponse) == kReadHeaderSize,
                socks4_server_response_struct_wrong_size);
 
-SOCKSClientSocket::SOCKSClientSocket(ClientSocketHandle* transport_socket,
-                                     const HostResolver::RequestInfo& req_info,
-                                     HostResolver* host_resolver)
-    : transport_(transport_socket),
+SOCKSClientSocket::SOCKSClientSocket(
+    scoped_ptr<ClientSocketHandle> transport_socket,
+    const HostResolver::RequestInfo& req_info,
+    RequestPriority priority,
+    HostResolver* host_resolver)
+    : transport_(transport_socket.Pass()),
       next_state_(STATE_NONE),
       completed_handshake_(false),
       bytes_sent_(0),
       bytes_received_(0),
       host_resolver_(host_resolver),
       host_request_info_(req_info),
-      net_log_(transport_socket->socket()->NetLog()) {
-}
-
-SOCKSClientSocket::SOCKSClientSocket(StreamSocket* transport_socket,
-                                     const HostResolver::RequestInfo& req_info,
-                                     HostResolver* host_resolver)
-    : transport_(new ClientSocketHandle()),
-      next_state_(STATE_NONE),
-      completed_handshake_(false),
-      bytes_sent_(0),
-      bytes_received_(0),
-      host_resolver_(host_resolver),
-      host_request_info_(req_info),
-      net_log_(transport_socket->NetLog()) {
-  transport_->set_socket(transport_socket);
-}
+      priority_(priority),
+      net_log_(transport_->socket()->NetLog()) {}
 
 SOCKSClientSocket::~SOCKSClientSocket() {
   Disconnect();
@@ -283,7 +271,9 @@
   // addresses for the target host.
   host_request_info_.set_address_family(ADDRESS_FAMILY_IPV4);
   return host_resolver_.Resolve(
-      host_request_info_, &addresses_,
+      host_request_info_,
+      priority_,
+      &addresses_,
       base::Bind(&SOCKSClientSocket::OnIOComplete, base::Unretained(this)),
       net_log_);
 }
diff --git a/net/socket/socks_client_socket.h b/net/socket/socks_client_socket.h
index 3d4f9fc..d4f058a 100644
--- a/net/socket/socks_client_socket.h
+++ b/net/socket/socks_client_socket.h
@@ -27,18 +27,11 @@
 // The SOCKS client socket implementation
 class NET_EXPORT_PRIVATE SOCKSClientSocket : public StreamSocket {
  public:
-  // Takes ownership of the |transport_socket|, which should already be
-  // connected by the time Connect() is called.
-  //
   // |req_info| contains the hostname and port to which the socket above will
   // communicate to via the socks layer. For testing the referrer is optional.
-  SOCKSClientSocket(ClientSocketHandle* transport_socket,
+  SOCKSClientSocket(scoped_ptr<ClientSocketHandle> transport_socket,
                     const HostResolver::RequestInfo& req_info,
-                    HostResolver* host_resolver);
-
-  // Deprecated constructor (http://crbug.com/37810) that takes a StreamSocket.
-  SOCKSClientSocket(StreamSocket* transport_socket,
-                    const HostResolver::RequestInfo& req_info,
+                    RequestPriority priority,
                     HostResolver* host_resolver);
 
   // On destruction Disconnect() is called.
@@ -131,6 +124,7 @@
   SingleRequestHostResolver host_resolver_;
   AddressList addresses_;
   HostResolver::RequestInfo host_request_info_;
+  RequestPriority priority_;
 
   BoundNetLog net_log_;
 
diff --git a/net/socket/socks_client_socket_pool.cc b/net/socket/socks_client_socket_pool.cc
index d740e5b..e11b7a4 100644
--- a/net/socket/socks_client_socket_pool.cc
+++ b/net/socket/socks_client_socket_pool.cc
@@ -21,8 +21,7 @@
 SOCKSSocketParams::SOCKSSocketParams(
     const scoped_refptr<TransportSocketParams>& proxy_server,
     bool socks_v5,
-    const HostPortPair& host_port_pair,
-    RequestPriority priority)
+    const HostPortPair& host_port_pair)
     : transport_params_(proxy_server),
       destination_(host_port_pair),
       socks_v5_(socks_v5) {
@@ -30,7 +29,6 @@
     ignore_limits_ = transport_params_->ignore_limits();
   else
     ignore_limits_ = false;
-  destination_.set_priority(priority);
 }
 
 SOCKSSocketParams::~SOCKSSocketParams() {}
@@ -41,13 +39,14 @@
 
 SOCKSConnectJob::SOCKSConnectJob(
     const std::string& group_name,
+    RequestPriority priority,
     const scoped_refptr<SOCKSSocketParams>& socks_params,
     const base::TimeDelta& timeout_duration,
     TransportClientSocketPool* transport_pool,
     HostResolver* host_resolver,
     Delegate* delegate,
     NetLog* net_log)
-    : ConnectJob(group_name, timeout_duration, delegate,
+    : ConnectJob(group_name, timeout_duration, priority, delegate,
                  BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
       socks_params_(socks_params),
       transport_pool_(transport_pool),
@@ -117,10 +116,12 @@
 int SOCKSConnectJob::DoTransportConnect() {
   next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
   transport_socket_handle_.reset(new ClientSocketHandle());
-  return transport_socket_handle_->Init(
-      group_name(), socks_params_->transport_params(),
-      socks_params_->destination().priority(), callback_, transport_pool_,
-      net_log());
+  return transport_socket_handle_->Init(group_name(),
+                                        socks_params_->transport_params(),
+                                        priority(),
+                                        callback_,
+                                        transport_pool_,
+                                        net_log());
 }
 
 int SOCKSConnectJob::DoTransportConnectComplete(int result) {
@@ -140,11 +141,12 @@
 
   // Add a SOCKS connection on top of the tcp socket.
   if (socks_params_->is_socks_v5()) {
-    socket_.reset(new SOCKS5ClientSocket(transport_socket_handle_.release(),
+    socket_.reset(new SOCKS5ClientSocket(transport_socket_handle_.Pass(),
                                          socks_params_->destination()));
   } else {
-    socket_.reset(new SOCKSClientSocket(transport_socket_handle_.release(),
+    socket_.reset(new SOCKSClientSocket(transport_socket_handle_.Pass(),
                                         socks_params_->destination(),
+                                        priority(),
                                         resolver_));
   }
   return socket_->Connect(
@@ -157,7 +159,7 @@
     return result;
   }
 
-  set_socket(socket_.release());
+  SetSocket(socket_.Pass());
   return result;
 }
 
@@ -166,17 +168,19 @@
   return DoLoop(OK);
 }
 
-ConnectJob* SOCKSClientSocketPool::SOCKSConnectJobFactory::NewConnectJob(
+scoped_ptr<ConnectJob>
+SOCKSClientSocketPool::SOCKSConnectJobFactory::NewConnectJob(
     const std::string& group_name,
     const PoolBase::Request& request,
     ConnectJob::Delegate* delegate) const {
-  return new SOCKSConnectJob(group_name,
-                             request.params(),
-                             ConnectionTimeout(),
-                             transport_pool_,
-                             host_resolver_,
-                             delegate,
-                             net_log_);
+  return scoped_ptr<ConnectJob>(new SOCKSConnectJob(group_name,
+                                                    request.priority(),
+                                                    request.params(),
+                                                    ConnectionTimeout(),
+                                                    transport_pool_,
+                                                    host_resolver_,
+                                                    delegate,
+                                                    net_log_));
 }
 
 base::TimeDelta
@@ -193,7 +197,7 @@
     TransportClientSocketPool* transport_pool,
     NetLog* net_log)
     : transport_pool_(transport_pool),
-      base_(max_sockets, max_sockets_per_group, histograms,
+      base_(this, max_sockets, max_sockets_per_group, histograms,
             ClientSocketPool::unused_idle_socket_timeout(),
             ClientSocketPool::used_idle_socket_timeout(),
             new SOCKSConnectJobFactory(transport_pool,
@@ -201,13 +205,10 @@
                                        net_log)) {
   // We should always have a |transport_pool_| except in unit tests.
   if (transport_pool_)
-    transport_pool_->AddLayeredPool(this);
+    base_.AddLowerLayeredPool(transport_pool_);
 }
 
 SOCKSClientSocketPool::~SOCKSClientSocketPool() {
-  // We should always have a |transport_pool_| except in unit tests.
-  if (transport_pool_)
-    transport_pool_->RemoveLayeredPool(this);
 }
 
 int SOCKSClientSocketPool::RequestSocket(
@@ -238,18 +239,15 @@
 }
 
 void SOCKSClientSocketPool::ReleaseSocket(const std::string& group_name,
-                                          StreamSocket* socket, int id) {
-  base_.ReleaseSocket(group_name, socket, id);
+                                          scoped_ptr<StreamSocket> socket,
+                                          int id) {
+  base_.ReleaseSocket(group_name, socket.Pass(), id);
 }
 
 void SOCKSClientSocketPool::FlushWithError(int error) {
   base_.FlushWithError(error);
 }
 
-bool SOCKSClientSocketPool::IsStalled() const {
-  return base_.IsStalled() || transport_pool_->IsStalled();
-}
-
 void SOCKSClientSocketPool::CloseIdleSockets() {
   base_.CloseIdleSockets();
 }
@@ -268,14 +266,6 @@
   return base_.GetLoadState(group_name, handle);
 }
 
-void SOCKSClientSocketPool::AddLayeredPool(LayeredPool* layered_pool) {
-  base_.AddLayeredPool(layered_pool);
-}
-
-void SOCKSClientSocketPool::RemoveLayeredPool(LayeredPool* layered_pool) {
-  base_.RemoveLayeredPool(layered_pool);
-}
-
 base::DictionaryValue* SOCKSClientSocketPool::GetInfoAsValue(
     const std::string& name,
     const std::string& type,
@@ -299,10 +289,24 @@
   return base_.histograms();
 };
 
+bool SOCKSClientSocketPool::IsStalled() const {
+  return base_.IsStalled();
+}
+
+void SOCKSClientSocketPool::AddHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  base_.AddHigherLayeredPool(higher_pool);
+}
+
+void SOCKSClientSocketPool::RemoveHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  base_.RemoveHigherLayeredPool(higher_pool);
+}
+
 bool SOCKSClientSocketPool::CloseOneIdleConnection() {
   if (base_.CloseOneIdleSocket())
     return true;
-  return base_.CloseOneIdleConnectionInLayeredPool();
+  return base_.CloseOneIdleConnectionInHigherLayeredPool();
 }
 
 }  // namespace net
diff --git a/net/socket/socks_client_socket_pool.h b/net/socket/socks_client_socket_pool.h
index 86609a1..c6d5c8d 100644
--- a/net/socket/socks_client_socket_pool.h
+++ b/net/socket/socks_client_socket_pool.h
@@ -28,8 +28,7 @@
     : public base::RefCounted<SOCKSSocketParams> {
  public:
   SOCKSSocketParams(const scoped_refptr<TransportSocketParams>& proxy_server,
-                    bool socks_v5, const HostPortPair& host_port_pair,
-                    RequestPriority priority);
+                    bool socks_v5, const HostPortPair& host_port_pair);
 
   const scoped_refptr<TransportSocketParams>& transport_params() const {
     return transport_params_;
@@ -57,6 +56,7 @@
 class SOCKSConnectJob : public ConnectJob {
  public:
   SOCKSConnectJob(const std::string& group_name,
+                  RequestPriority priority,
                   const scoped_refptr<SOCKSSocketParams>& params,
                   const base::TimeDelta& timeout_duration,
                   TransportClientSocketPool* transport_pool,
@@ -105,8 +105,10 @@
 };
 
 class NET_EXPORT_PRIVATE SOCKSClientSocketPool
-    : public ClientSocketPool, public LayeredPool {
+    : public ClientSocketPool, public HigherLayeredPool {
  public:
+  typedef SOCKSSocketParams SocketParams;
+
   SOCKSClientSocketPool(
       int max_sockets,
       int max_sockets_per_group,
@@ -134,13 +136,11 @@
                              ClientSocketHandle* handle) OVERRIDE;
 
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket,
+                             scoped_ptr<StreamSocket> socket,
                              int id) OVERRIDE;
 
   virtual void FlushWithError(int error) OVERRIDE;
 
-  virtual bool IsStalled() const OVERRIDE;
-
   virtual void CloseIdleSockets() OVERRIDE;
 
   virtual int IdleSocketCount() const OVERRIDE;
@@ -152,10 +152,6 @@
       const std::string& group_name,
       const ClientSocketHandle* handle) const OVERRIDE;
 
-  virtual void AddLayeredPool(LayeredPool* layered_pool) OVERRIDE;
-
-  virtual void RemoveLayeredPool(LayeredPool* layered_pool) OVERRIDE;
-
   virtual base::DictionaryValue* GetInfoAsValue(
       const std::string& name,
       const std::string& type,
@@ -165,7 +161,14 @@
 
   virtual ClientSocketPoolHistograms* histograms() const OVERRIDE;
 
-  // LayeredPool implementation.
+  // LowerLayeredPool implementation.
+  virtual bool IsStalled() const OVERRIDE;
+
+  virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+
+  virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+
+  // HigherLayeredPool implementation.
   virtual bool CloseOneIdleConnection() OVERRIDE;
 
  private:
@@ -183,7 +186,7 @@
     virtual ~SOCKSConnectJobFactory() {}
 
     // ClientSocketPoolBase::ConnectJobFactory methods.
-    virtual ConnectJob* NewConnectJob(
+    virtual scoped_ptr<ConnectJob> NewConnectJob(
         const std::string& group_name,
         const PoolBase::Request& request,
         ConnectJob::Delegate* delegate) const OVERRIDE;
@@ -204,8 +207,6 @@
   DISALLOW_COPY_AND_ASSIGN(SOCKSClientSocketPool);
 };
 
-REGISTER_SOCKET_PARAMS_FOR_POOL(SOCKSClientSocketPool, SOCKSSocketParams);
-
 }  // namespace net
 
 #endif  // NET_SOCKET_SOCKS_CLIENT_SOCKET_POOL_H_
diff --git a/net/socket/socks_client_socket_pool_unittest.cc b/net/socket/socks_client_socket_pool_unittest.cc
index 77440d3..4463e17 100644
--- a/net/socket/socks_client_socket_pool_unittest.cc
+++ b/net/socket/socks_client_socket_pool_unittest.cc
@@ -41,6 +41,25 @@
   ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
 }
 
+
+scoped_refptr<TransportSocketParams> CreateProxyHostParams() {
+  return new TransportSocketParams(
+      HostPortPair("proxy", 80), false, false,
+      OnHostResolutionCallback());
+}
+
+scoped_refptr<SOCKSSocketParams> CreateSOCKSv4Params() {
+  return new SOCKSSocketParams(
+      CreateProxyHostParams(), false /* socks_v5 */,
+      HostPortPair("host", 80));
+}
+
+scoped_refptr<SOCKSSocketParams> CreateSOCKSv5Params() {
+  return new SOCKSSocketParams(
+      CreateProxyHostParams(), true /* socks_v5 */,
+      HostPortPair("host", 80));
+}
+
 class SOCKSClientSocketPoolTest : public testing::Test {
  protected:
   class SOCKS5MockData {
@@ -71,30 +90,24 @@
   };
 
   SOCKSClientSocketPoolTest()
-      : ignored_transport_socket_params_(new TransportSocketParams(
-          HostPortPair("proxy", 80), MEDIUM, false, false,
-          OnHostResolutionCallback())),
-        transport_histograms_("MockTCP"),
+      : transport_histograms_("MockTCP"),
         transport_socket_pool_(
             kMaxSockets, kMaxSocketsPerGroup,
             &transport_histograms_,
             &transport_client_socket_factory_),
-        ignored_socket_params_(new SOCKSSocketParams(
-            ignored_transport_socket_params_, true, HostPortPair("host", 80),
-            MEDIUM)),
         socks_histograms_("SOCKSUnitTest"),
         pool_(kMaxSockets, kMaxSocketsPerGroup,
               &socks_histograms_,
-              NULL,
+              &host_resolver_,
               &transport_socket_pool_,
               NULL) {
   }
 
   virtual ~SOCKSClientSocketPoolTest() {}
 
-  int StartRequest(const std::string& group_name, RequestPriority priority) {
+  int StartRequestV5(const std::string& group_name, RequestPriority priority) {
     return test_base_.StartRequestUsingPool(
-        &pool_, group_name, priority, ignored_socket_params_);
+        &pool_, group_name, priority, CreateSOCKSv5Params());
   }
 
   int GetOrderOfRequest(size_t index) const {
@@ -103,13 +116,12 @@
 
   ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
 
-  scoped_refptr<TransportSocketParams> ignored_transport_socket_params_;
   ClientSocketPoolHistograms transport_histograms_;
   MockClientSocketFactory transport_client_socket_factory_;
   MockTransportClientSocketPool transport_socket_pool_;
 
-  scoped_refptr<SOCKSSocketParams> ignored_socket_params_;
   ClientSocketPoolHistograms socks_histograms_;
+  MockHostResolver host_resolver_;
   SOCKSClientSocketPool pool_;
   ClientSocketPoolTest test_base_;
 };
@@ -120,7 +132,7 @@
   transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
 
   ClientSocketHandle handle;
-  int rv = handle.Init("a", ignored_socket_params_, LOW, CompletionCallback(),
+  int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, CompletionCallback(),
                        &pool_, BoundNetLog());
   EXPECT_EQ(OK, rv);
   EXPECT_TRUE(handle.is_initialized());
@@ -128,13 +140,52 @@
   TestLoadTimingInfo(handle);
 }
 
+// Make sure that SOCKSConnectJob passes on its priority to its
+// socket request on Init.
+TEST_F(SOCKSClientSocketPoolTest, SetSocketRequestPriorityOnInit) {
+  for (int i = MINIMUM_PRIORITY; i < NUM_PRIORITIES; ++i) {
+    RequestPriority priority = static_cast<RequestPriority>(i);
+    SOCKS5MockData data(SYNCHRONOUS);
+    data.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS, OK));
+    transport_client_socket_factory_.AddSocketDataProvider(
+        data.data_provider());
+
+    ClientSocketHandle handle;
+    EXPECT_EQ(OK,
+              handle.Init("a", CreateSOCKSv5Params(), priority,
+                          CompletionCallback(), &pool_, BoundNetLog()));
+    EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
+    handle.socket()->Disconnect();
+  }
+}
+
+// Make sure that SOCKSConnectJob passes on its priority to its
+// HostResolver request (for non-SOCKS5) on Init.
+TEST_F(SOCKSClientSocketPoolTest, SetResolvePriorityOnInit) {
+  for (int i = MINIMUM_PRIORITY; i < NUM_PRIORITIES; ++i) {
+    RequestPriority priority = static_cast<RequestPriority>(i);
+    SOCKS5MockData data(SYNCHRONOUS);
+    data.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS, OK));
+    transport_client_socket_factory_.AddSocketDataProvider(
+        data.data_provider());
+
+    ClientSocketHandle handle;
+    EXPECT_EQ(ERR_IO_PENDING,
+              handle.Init("a", CreateSOCKSv4Params(), priority,
+                          CompletionCallback(), &pool_, BoundNetLog()));
+    EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
+    EXPECT_EQ(priority, host_resolver_.last_request_priority());
+    EXPECT_TRUE(handle.socket() == NULL);
+  }
+}
+
 TEST_F(SOCKSClientSocketPoolTest, Async) {
   SOCKS5MockData data(ASYNC);
   transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", ignored_socket_params_, LOW, callback.callback(),
+  int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, callback.callback(),
                        &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -153,7 +204,7 @@
   transport_client_socket_factory_.AddSocketDataProvider(&socket_data);
 
   ClientSocketHandle handle;
-  int rv = handle.Init("a", ignored_socket_params_, LOW, CompletionCallback(),
+  int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, CompletionCallback(),
                        &pool_, BoundNetLog());
   EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -167,7 +218,7 @@
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", ignored_socket_params_, LOW, callback.callback(),
+  int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, callback.callback(),
                        &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -189,7 +240,7 @@
 
   ClientSocketHandle handle;
   EXPECT_EQ(0, transport_socket_pool_.release_count());
-  int rv = handle.Init("a", ignored_socket_params_, LOW, CompletionCallback(),
+  int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, CompletionCallback(),
                        &pool_, BoundNetLog());
   EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -209,7 +260,7 @@
   TestCompletionCallback callback;
   ClientSocketHandle handle;
   EXPECT_EQ(0, transport_socket_pool_.release_count());
-  int rv = handle.Init("a", ignored_socket_params_, LOW, callback.callback(),
+  int rv = handle.Init("a", CreateSOCKSv5Params(), LOW, callback.callback(),
                        &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -230,10 +281,10 @@
   transport_client_socket_factory_.AddSocketDataProvider(data2.data_provider());
 
   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
-  int rv = StartRequest("a", LOW);
+  int rv = StartRequestV5("a", LOW);
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
-  rv = StartRequest("a", LOW);
+  rv = StartRequestV5("a", LOW);
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   pool_.CancelRequest("a", (*requests())[0]->handle());
@@ -265,10 +316,10 @@
 
   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
   EXPECT_EQ(0, transport_socket_pool_.release_count());
-  int rv = StartRequest("a", LOW);
+  int rv = StartRequestV5("a", LOW);
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
-  rv = StartRequest("a", LOW);
+  rv = StartRequestV5("a", LOW);
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   pool_.CancelRequest("a", (*requests())[0]->handle());
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc
index 7a8faf6..f361244 100644
--- a/net/socket/socks_client_socket_unittest.cc
+++ b/net/socket/socks_client_socket_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "net/socket/socks_client_socket.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "net/base/address_list.h"
 #include "net/base/net_log.h"
 #include "net/base/net_log_unittest.h"
@@ -27,16 +28,19 @@
  public:
   SOCKSClientSocketTest();
   // Create a SOCKSClientSocket on top of a MockSocket.
-  SOCKSClientSocket* BuildMockSocket(MockRead reads[], size_t reads_count,
-                                     MockWrite writes[], size_t writes_count,
-                                     HostResolver* host_resolver,
-                                     const std::string& hostname, int port,
-                                     NetLog* net_log);
+  scoped_ptr<SOCKSClientSocket> BuildMockSocket(
+      MockRead reads[], size_t reads_count,
+      MockWrite writes[], size_t writes_count,
+      HostResolver* host_resolver,
+      const std::string& hostname, int port,
+      NetLog* net_log);
   virtual void SetUp();
 
  protected:
   scoped_ptr<SOCKSClientSocket> user_sock_;
   AddressList address_list_;
+  // Filled in by BuildMockSocket() and owned by its return value
+  // (which |user_sock| is set to).
   StreamSocket* tcp_sock_;
   TestCompletionCallback callback_;
   scoped_ptr<MockHostResolver> host_resolver_;
@@ -52,7 +56,7 @@
   PlatformTest::SetUp();
 }
 
-SOCKSClientSocket* SOCKSClientSocketTest::BuildMockSocket(
+scoped_ptr<SOCKSClientSocket> SOCKSClientSocketTest::BuildMockSocket(
     MockRead reads[],
     size_t reads_count,
     MockWrite writes[],
@@ -73,9 +77,15 @@
   EXPECT_EQ(OK, rv);
   EXPECT_TRUE(tcp_sock_->IsConnected());
 
-  return new SOCKSClientSocket(tcp_sock_,
+  scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+  // |connection| takes ownership of |tcp_sock_|, but keep a
+  // non-owning pointer to it.
+  connection->SetSocket(scoped_ptr<StreamSocket>(tcp_sock_));
+  return scoped_ptr<SOCKSClientSocket>(new SOCKSClientSocket(
+      connection.Pass(),
       HostResolver::RequestInfo(HostPortPair(hostname, port)),
-      host_resolver);
+      DEFAULT_PRIORITY,
+      host_resolver));
 }
 
 // Implementation of HostResolver that never completes its resolve request.
@@ -86,6 +96,7 @@
   HangingHostResolverWithCancel() : outstanding_request_(NULL) {}
 
   virtual int Resolve(const RequestInfo& info,
+                      RequestPriority priority,
                       AddressList* addresses,
                       const CompletionCallback& callback,
                       RequestHandle* out_req,
@@ -134,11 +145,11 @@
       MockRead(ASYNC, payload_read.data(), payload_read.size()) };
   CapturingNetLog log;
 
-  user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                   data_writes, arraysize(data_writes),
-                                   host_resolver_.get(),
-                                   "localhost", 80,
-                                   &log));
+  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                               data_writes, arraysize(data_writes),
+                               host_resolver_.get(),
+                               "localhost", 80,
+                               &log);
 
   // At this state the TCP connection is completed but not the SOCKS handshake.
   EXPECT_TRUE(tcp_sock_->IsConnected());
@@ -210,11 +221,11 @@
                  arraysize(tests[i].fail_reply)) };
     CapturingNetLog log;
 
-    user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                     data_writes, arraysize(data_writes),
-                                     host_resolver_.get(),
-                                     "localhost", 80,
-                                     &log));
+    user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                                 data_writes, arraysize(data_writes),
+                                 host_resolver_.get(),
+                                 "localhost", 80,
+                                 &log);
 
     int rv = user_sock_->Connect(callback_.callback());
     EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -247,11 +258,11 @@
       MockRead(ASYNC, kSOCKSPartialReply2, arraysize(kSOCKSPartialReply2)) };
   CapturingNetLog log;
 
-  user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                   data_writes, arraysize(data_writes),
-                                   host_resolver_.get(),
-                                   "localhost", 80,
-                                   &log));
+  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                               data_writes, arraysize(data_writes),
+                               host_resolver_.get(),
+                               "localhost", 80,
+                               &log);
 
   int rv = user_sock_->Connect(callback_.callback());
   EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -285,11 +296,11 @@
       MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply)) };
   CapturingNetLog log;
 
-  user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                   data_writes, arraysize(data_writes),
-                                   host_resolver_.get(),
-                                   "localhost", 80,
-                                   &log));
+  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                               data_writes, arraysize(data_writes),
+                               host_resolver_.get(),
+                               "localhost", 80,
+                               &log);
 
   int rv = user_sock_->Connect(callback_.callback());
   EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -317,11 +328,11 @@
       MockRead(SYNCHRONOUS, 0) };
   CapturingNetLog log;
 
-  user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                   data_writes, arraysize(data_writes),
-                                   host_resolver_.get(),
-                                   "localhost", 80,
-                                   &log));
+  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                               data_writes, arraysize(data_writes),
+                               host_resolver_.get(),
+                               "localhost", 80,
+                               &log);
 
   int rv = user_sock_->Connect(callback_.callback());
   EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -347,11 +358,11 @@
 
   CapturingNetLog log;
 
-  user_sock_.reset(BuildMockSocket(NULL, 0,
-                                   NULL, 0,
-                                   host_resolver_.get(),
-                                   hostname, 80,
-                                   &log));
+  user_sock_ = BuildMockSocket(NULL, 0,
+                               NULL, 0,
+                               host_resolver_.get(),
+                               hostname, 80,
+                               &log);
 
   int rv = user_sock_->Connect(callback_.callback());
   EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -378,11 +389,11 @@
   MockWrite data_writes[] = { MockWrite(SYNCHRONOUS, "", 0) };
   MockRead data_reads[] = { MockRead(SYNCHRONOUS, "", 0) };
 
-  user_sock_.reset(BuildMockSocket(data_reads, arraysize(data_reads),
-                                   data_writes, arraysize(data_writes),
-                                   hanging_resolver.get(),
-                                   "foo", 80,
-                                   NULL));
+  user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
+                               data_writes, arraysize(data_writes),
+                               hanging_resolver.get(),
+                               "foo", 80,
+                               NULL);
 
   // Start connecting (will get stuck waiting for the host to resolve).
   int rv = user_sock_->Connect(callback_.callback());
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 72154bb..acc1b0d 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -2598,7 +2598,7 @@
 
   weak_net_log_->BeginEvent(NetLog::TYPE_SSL_GET_DOMAIN_BOUND_CERT);
 
-  int rv = server_bound_cert_service_->GetDomainBoundCert(
+  int rv = server_bound_cert_service_->GetOrCreateDomainBoundCert(
       host,
       &domain_bound_private_key_,
       &domain_bound_cert_,
@@ -2751,12 +2751,12 @@
 
 SSLClientSocketNSS::SSLClientSocketNSS(
     base::SequencedTaskRunner* nss_task_runner,
-    ClientSocketHandle* transport_socket,
+    scoped_ptr<ClientSocketHandle> transport_socket,
     const HostPortPair& host_and_port,
     const SSLConfig& ssl_config,
     const SSLClientSocketContext& context)
     : nss_task_runner_(nss_task_runner),
-      transport_(transport_socket),
+      transport_(transport_socket.Pass()),
       host_and_port_(host_and_port),
       ssl_config_(ssl_config),
       cert_verifier_(context.cert_verifier),
@@ -2765,7 +2765,7 @@
       completed_handshake_(false),
       next_handshake_state_(STATE_NONE),
       nss_fd_(NULL),
-      net_log_(transport_socket->socket()->NetLog()),
+      net_log_(transport_->socket()->NetLog()),
       transport_security_state_(context.transport_security_state),
       valid_thread_id_(base::kInvalidThreadId) {
   EnterFunction("");
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index fed8ef7..b41d28d 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -59,7 +59,7 @@
   // behaviour is desired, for performance or compatibility, the current task
   // runner should be supplied instead.
   SSLClientSocketNSS(base::SequencedTaskRunner* nss_task_runner,
-                     ClientSocketHandle* transport_socket,
+                     scoped_ptr<ClientSocketHandle> transport_socket,
                      const HostPortPair& host_and_port,
                      const SSLConfig& ssl_config,
                      const SSLClientSocketContext& context);
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 1431bc6..416ab87 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -425,7 +425,7 @@
 }
 
 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL(
-    ClientSocketHandle* transport_socket,
+    scoped_ptr<ClientSocketHandle> transport_socket,
     const HostPortPair& host_and_port,
     const SSLConfig& ssl_config,
     const SSLClientSocketContext& context)
@@ -439,14 +439,14 @@
       cert_verifier_(context.cert_verifier),
       ssl_(NULL),
       transport_bio_(NULL),
-      transport_(transport_socket),
+      transport_(transport_socket.Pass()),
       host_and_port_(host_and_port),
       ssl_config_(ssl_config),
       ssl_session_cache_shard_(context.ssl_session_cache_shard),
       trying_cached_session_(false),
       next_handshake_state_(STATE_NONE),
       npn_status_(kNextProtoUnsupported),
-      net_log_(transport_socket->socket()->NetLog()) {
+      net_log_(transport_->socket()->NetLog()) {
 }
 
 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() {
@@ -532,9 +532,11 @@
   STACK_OF(SSL_CIPHER)* ciphers = SSL_get_ciphers(ssl_);
   DCHECK(ciphers);
   // See SSLConfig::disabled_cipher_suites for description of the suites
-  // disabled by default. Note that !SHA384 only removes HMAC-SHA384 cipher
-  // suites, not GCM cipher suites with SHA384 as the handshake hash.
-  std::string command("DEFAULT:!NULL:!aNULL:!IDEA:!FZA:!SRP:!SHA384:!aECDH");
+  // disabled by default. Note that !SHA256 and !SHA384 only remove HMAC-SHA256
+  // and HMAC-SHA384 cipher suites, not GCM cipher suites with SHA256 or SHA384
+  // as the handshake hash.
+  std::string command("DEFAULT:!NULL:!aNULL:!IDEA:!FZA:!SRP:!SHA256:!SHA384:"
+                      "!aECDH:!AESGCM+AES256");
   // Walk through all the installed ciphers, seeing if any need to be
   // appended to the cipher removal |command|.
   for (int i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) {
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h
index 520f432..f66d95c 100644
--- a/net/socket/ssl_client_socket_openssl.h
+++ b/net/socket/ssl_client_socket_openssl.h
@@ -41,7 +41,7 @@
   // The given hostname will be compared with the name(s) in the server's
   // certificate during the SSL handshake.  ssl_config specifies the SSL
   // settings.
-  SSLClientSocketOpenSSL(ClientSocketHandle* transport_socket,
+  SSLClientSocketOpenSSL(scoped_ptr<ClientSocketHandle> transport_socket,
                          const HostPortPair& host_and_port,
                          const SSLConfig& ssl_config,
                          const SSLClientSocketContext& context);
diff --git a/net/socket/ssl_client_socket_openssl_unittest.cc b/net/socket/ssl_client_socket_openssl_unittest.cc
index 7a37cdc..04f8999 100644
--- a/net/socket/ssl_client_socket_openssl_unittest.cc
+++ b/net/socket/ssl_client_socket_openssl_unittest.cc
@@ -107,11 +107,13 @@
   }
 
  protected:
-  SSLClientSocket* CreateSSLClientSocket(
-      StreamSocket* transport_socket,
+  scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<StreamSocket> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config) {
-    return socket_factory_->CreateSSLClientSocket(transport_socket,
+    scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+    connection->SetSocket(transport_socket.Pass());
+    return socket_factory_->CreateSSLClientSocket(connection.Pass(),
                                                   host_and_port,
                                                   ssl_config,
                                                   context_);
@@ -164,9 +166,9 @@
   // itself was a success.
   bool CreateAndConnectSSLClientSocket(SSLConfig& ssl_config,
                                        int* result) {
-    sock_.reset(CreateSSLClientSocket(transport_.release(),
-                                      test_server_->host_port_pair(),
-                                      ssl_config));
+    sock_ = CreateSSLClientSocket(transport_.Pass(),
+                                  test_server_->host_port_pair(),
+                                  ssl_config);
 
     if (sock_->IsConnected()) {
       LOG(ERROR) << "SSL Socket prematurely connected";
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index fed268d..5d574b7 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -26,20 +26,18 @@
 namespace net {
 
 SSLSocketParams::SSLSocketParams(
-    const scoped_refptr<TransportSocketParams>& transport_params,
-    const scoped_refptr<SOCKSSocketParams>& socks_params,
+    const scoped_refptr<TransportSocketParams>& direct_params,
+    const scoped_refptr<SOCKSSocketParams>& socks_proxy_params,
     const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
-    ProxyServer::Scheme proxy,
     const HostPortPair& host_and_port,
     const SSLConfig& ssl_config,
     PrivacyMode privacy_mode,
     int load_flags,
     bool force_spdy_over_ssl,
     bool want_spdy_over_npn)
-    : transport_params_(transport_params),
+    : direct_params_(direct_params),
+      socks_proxy_params_(socks_proxy_params),
       http_proxy_params_(http_proxy_params),
-      socks_params_(socks_params),
-      proxy_(proxy),
       host_and_port_(host_and_port),
       ssl_config_(ssl_config),
       privacy_mode_(privacy_mode),
@@ -47,39 +45,60 @@
       force_spdy_over_ssl_(force_spdy_over_ssl),
       want_spdy_over_npn_(want_spdy_over_npn),
       ignore_limits_(false) {
-  switch (proxy_) {
-    case ProxyServer::SCHEME_DIRECT:
-      DCHECK(transport_params_.get() != NULL);
-      DCHECK(http_proxy_params_.get() == NULL);
-      DCHECK(socks_params_.get() == NULL);
-      ignore_limits_ = transport_params_->ignore_limits();
-      break;
-    case ProxyServer::SCHEME_HTTP:
-    case ProxyServer::SCHEME_HTTPS:
-      DCHECK(transport_params_.get() == NULL);
-      DCHECK(http_proxy_params_.get() != NULL);
-      DCHECK(socks_params_.get() == NULL);
-      ignore_limits_ = http_proxy_params_->ignore_limits();
-      break;
-    case ProxyServer::SCHEME_SOCKS4:
-    case ProxyServer::SCHEME_SOCKS5:
-      DCHECK(transport_params_.get() == NULL);
-      DCHECK(http_proxy_params_.get() == NULL);
-      DCHECK(socks_params_.get() != NULL);
-      ignore_limits_ = socks_params_->ignore_limits();
-      break;
-    default:
-      LOG(DFATAL) << "unknown proxy type";
-      break;
+  if (direct_params_) {
+    DCHECK(!socks_proxy_params_);
+    DCHECK(!http_proxy_params_);
+    ignore_limits_ = direct_params_->ignore_limits();
+  } else if (socks_proxy_params_) {
+    DCHECK(!http_proxy_params_);
+    ignore_limits_ = socks_proxy_params_->ignore_limits();
+  } else {
+    DCHECK(http_proxy_params_);
+    ignore_limits_ = http_proxy_params_->ignore_limits();
   }
 }
 
 SSLSocketParams::~SSLSocketParams() {}
 
+SSLSocketParams::ConnectionType SSLSocketParams::GetConnectionType() const {
+  if (direct_params_) {
+    DCHECK(!socks_proxy_params_);
+    DCHECK(!http_proxy_params_);
+    return DIRECT;
+  }
+
+  if (socks_proxy_params_) {
+    DCHECK(!http_proxy_params_);
+    return SOCKS_PROXY;
+  }
+
+  DCHECK(http_proxy_params_);
+  return HTTP_PROXY;
+}
+
+const scoped_refptr<TransportSocketParams>&
+SSLSocketParams::GetDirectConnectionParams() const {
+  DCHECK_EQ(GetConnectionType(), DIRECT);
+  return direct_params_;
+}
+
+const scoped_refptr<SOCKSSocketParams>&
+SSLSocketParams::GetSocksProxyConnectionParams() const {
+  DCHECK_EQ(GetConnectionType(), SOCKS_PROXY);
+  return socks_proxy_params_;
+}
+
+const scoped_refptr<HttpProxySocketParams>&
+SSLSocketParams::GetHttpProxyConnectionParams() const {
+  DCHECK_EQ(GetConnectionType(), HTTP_PROXY);
+  return http_proxy_params_;
+}
+
 // Timeout for the SSL handshake portion of the connect.
 static const int kSSLHandshakeTimeoutInSeconds = 30;
 
 SSLConnectJob::SSLConnectJob(const std::string& group_name,
+                             RequestPriority priority,
                              const scoped_refptr<SSLSocketParams>& params,
                              const base::TimeDelta& timeout_duration,
                              TransportClientSocketPool* transport_pool,
@@ -92,6 +111,7 @@
                              NetLog* net_log)
     : ConnectJob(group_name,
                  timeout_duration,
+                 priority,
                  delegate,
                  BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
       params_(params),
@@ -201,12 +221,14 @@
 
   next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
   transport_socket_handle_.reset(new ClientSocketHandle());
-  scoped_refptr<TransportSocketParams> transport_params =
-      params_->transport_params();
-  return transport_socket_handle_->Init(
-      group_name(), transport_params,
-      transport_params->destination().priority(), callback_, transport_pool_,
-      net_log());
+  scoped_refptr<TransportSocketParams> direct_params =
+      params_->GetDirectConnectionParams();
+  return transport_socket_handle_->Init(group_name(),
+                                        direct_params,
+                                        priority(),
+                                        callback_,
+                                        transport_pool_,
+                                        net_log());
 }
 
 int SSLConnectJob::DoTransportConnectComplete(int result) {
@@ -220,10 +242,14 @@
   DCHECK(socks_pool_);
   next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
   transport_socket_handle_.reset(new ClientSocketHandle());
-  scoped_refptr<SOCKSSocketParams> socks_params = params_->socks_params();
-  return transport_socket_handle_->Init(
-      group_name(), socks_params, socks_params->destination().priority(),
-      callback_, socks_pool_, net_log());
+  scoped_refptr<SOCKSSocketParams> socks_proxy_params =
+      params_->GetSocksProxyConnectionParams();
+  return transport_socket_handle_->Init(group_name(),
+                                        socks_proxy_params,
+                                        priority(),
+                                        callback_,
+                                        socks_pool_,
+                                        net_log());
 }
 
 int SSLConnectJob::DoSOCKSConnectComplete(int result) {
@@ -239,11 +265,13 @@
 
   transport_socket_handle_.reset(new ClientSocketHandle());
   scoped_refptr<HttpProxySocketParams> http_proxy_params =
-      params_->http_proxy_params();
-  return transport_socket_handle_->Init(
-      group_name(), http_proxy_params,
-      http_proxy_params->destination().priority(), callback_, http_proxy_pool_,
-      net_log());
+      params_->GetHttpProxyConnectionParams();
+  return transport_socket_handle_->Init(group_name(),
+                                        http_proxy_params,
+                                        priority(),
+                                        callback_,
+                                        http_proxy_pool_,
+                                        net_log());
 }
 
 int SSLConnectJob::DoTunnelConnectComplete(int result) {
@@ -287,11 +315,11 @@
 
   connect_timing_.ssl_start = base::TimeTicks::Now();
 
-  ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket(
-      transport_socket_handle_.release(),
+  ssl_socket_ = client_socket_factory_->CreateSSLClientSocket(
+      transport_socket_handle_.Pass(),
       params_->host_and_port(),
       params_->ssl_config(),
-      context_));
+      context_);
   return ssl_socket_->Connect(callback_);
 }
 
@@ -410,7 +438,7 @@
   }
 
   if (result == OK || IsCertificateError(result)) {
-    set_socket(ssl_socket_.release());
+    SetSocket(ssl_socket_.PassAs<StreamSocket>());
   } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
     error_response_info_.cert_request_info = new SSLCertRequestInfo;
     ssl_socket_->GetSSLCertRequestInfo(
@@ -420,23 +448,22 @@
   return result;
 }
 
-int SSLConnectJob::ConnectInternal() {
-  switch (params_->proxy()) {
-    case ProxyServer::SCHEME_DIRECT:
-      next_state_ = STATE_TRANSPORT_CONNECT;
-      break;
-    case ProxyServer::SCHEME_HTTP:
-    case ProxyServer::SCHEME_HTTPS:
-      next_state_ = STATE_TUNNEL_CONNECT;
-      break;
-    case ProxyServer::SCHEME_SOCKS4:
-    case ProxyServer::SCHEME_SOCKS5:
-      next_state_ = STATE_SOCKS_CONNECT;
-      break;
-    default:
-      NOTREACHED() << "unknown proxy type";
-      break;
+SSLConnectJob::State SSLConnectJob::GetInitialState(
+    SSLSocketParams::ConnectionType connection_type) {
+  switch (connection_type) {
+    case SSLSocketParams::DIRECT:
+      return STATE_TRANSPORT_CONNECT;
+    case SSLSocketParams::HTTP_PROXY:
+      return STATE_TUNNEL_CONNECT;
+    case SSLSocketParams::SOCKS_PROXY:
+      return STATE_SOCKS_CONNECT;
   }
+  NOTREACHED();
+  return STATE_NONE;
+}
+
+int SSLConnectJob::ConnectInternal() {
+  next_state_ = GetInitialState(params_->GetConnectionType());
   return DoLoop(OK);
 }
 
@@ -491,7 +518,7 @@
     : transport_pool_(transport_pool),
       socks_pool_(socks_pool),
       http_proxy_pool_(http_proxy_pool),
-      base_(max_sockets, max_sockets_per_group, histograms,
+      base_(this, max_sockets, max_sockets_per_group, histograms,
             ClientSocketPool::unused_idle_socket_timeout(),
             ClientSocketPool::used_idle_socket_timeout(),
             new SSLConnectJobFactory(transport_pool,
@@ -509,32 +536,28 @@
   if (ssl_config_service_.get())
     ssl_config_service_->AddObserver(this);
   if (transport_pool_)
-    transport_pool_->AddLayeredPool(this);
+    base_.AddLowerLayeredPool(transport_pool_);
   if (socks_pool_)
-    socks_pool_->AddLayeredPool(this);
+    base_.AddLowerLayeredPool(socks_pool_);
   if (http_proxy_pool_)
-    http_proxy_pool_->AddLayeredPool(this);
+    base_.AddLowerLayeredPool(http_proxy_pool_);
 }
 
 SSLClientSocketPool::~SSLClientSocketPool() {
-  if (http_proxy_pool_)
-    http_proxy_pool_->RemoveLayeredPool(this);
-  if (socks_pool_)
-    socks_pool_->RemoveLayeredPool(this);
-  if (transport_pool_)
-    transport_pool_->RemoveLayeredPool(this);
   if (ssl_config_service_.get())
     ssl_config_service_->RemoveObserver(this);
 }
 
-ConnectJob* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob(
+scoped_ptr<ConnectJob>
+SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob(
     const std::string& group_name,
     const PoolBase::Request& request,
     ConnectJob::Delegate* delegate) const {
-  return new SSLConnectJob(group_name, request.params(), ConnectionTimeout(),
-                           transport_pool_, socks_pool_, http_proxy_pool_,
-                           client_socket_factory_, host_resolver_,
-                           context_, delegate, net_log_);
+  return scoped_ptr<ConnectJob>(
+      new SSLConnectJob(group_name, request.priority(), request.params(),
+                        ConnectionTimeout(), transport_pool_, socks_pool_,
+                        http_proxy_pool_, client_socket_factory_,
+                        host_resolver_, context_, delegate, net_log_));
 }
 
 base::TimeDelta
@@ -572,21 +595,15 @@
 }
 
 void SSLClientSocketPool::ReleaseSocket(const std::string& group_name,
-                                        StreamSocket* socket, int id) {
-  base_.ReleaseSocket(group_name, socket, id);
+                                        scoped_ptr<StreamSocket> socket,
+                                        int id) {
+  base_.ReleaseSocket(group_name, socket.Pass(), id);
 }
 
 void SSLClientSocketPool::FlushWithError(int error) {
   base_.FlushWithError(error);
 }
 
-bool SSLClientSocketPool::IsStalled() const {
-  return base_.IsStalled() ||
-      (transport_pool_ && transport_pool_->IsStalled()) ||
-      (socks_pool_ && socks_pool_->IsStalled()) ||
-      (http_proxy_pool_ && http_proxy_pool_->IsStalled());
-}
-
 void SSLClientSocketPool::CloseIdleSockets() {
   base_.CloseIdleSockets();
 }
@@ -605,14 +622,6 @@
   return base_.GetLoadState(group_name, handle);
 }
 
-void SSLClientSocketPool::AddLayeredPool(LayeredPool* layered_pool) {
-  base_.AddLayeredPool(layered_pool);
-}
-
-void SSLClientSocketPool::RemoveLayeredPool(LayeredPool* layered_pool) {
-  base_.RemoveLayeredPool(layered_pool);
-}
-
 base::DictionaryValue* SSLClientSocketPool::GetInfoAsValue(
     const std::string& name,
     const std::string& type,
@@ -648,14 +657,27 @@
   return base_.histograms();
 }
 
-void SSLClientSocketPool::OnSSLConfigChanged() {
-  FlushWithError(ERR_NETWORK_CHANGED);
+bool SSLClientSocketPool::IsStalled() const {
+  return base_.IsStalled();
+}
+
+void SSLClientSocketPool::AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
+  base_.AddHigherLayeredPool(higher_pool);
+}
+
+void SSLClientSocketPool::RemoveHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  base_.RemoveHigherLayeredPool(higher_pool);
 }
 
 bool SSLClientSocketPool::CloseOneIdleConnection() {
   if (base_.CloseOneIdleSocket())
     return true;
-  return base_.CloseOneIdleConnectionInLayeredPool();
+  return base_.CloseOneIdleConnectionInHigherLayeredPool();
+}
+
+void SSLClientSocketPool::OnSSLConfigChanged() {
+  FlushWithError(ERR_NETWORK_CHANGED);
 }
 
 }  // namespace net
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index bc54bc9..ec62eb0 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -13,7 +13,6 @@
 #include "net/base/privacy_mode.h"
 #include "net/dns/host_resolver.h"
 #include "net/http/http_response_info.h"
-#include "net/proxy/proxy_server.h"
 #include "net/socket/client_socket_pool.h"
 #include "net/socket/client_socket_pool_base.h"
 #include "net/socket/client_socket_pool_histograms.h"
@@ -35,32 +34,39 @@
 class TransportSecurityState;
 class TransportSocketParams;
 
-// SSLSocketParams only needs the socket params for the transport socket
-// that will be used (denoted by |proxy|).
 class NET_EXPORT_PRIVATE SSLSocketParams
     : public base::RefCounted<SSLSocketParams> {
  public:
-  SSLSocketParams(const scoped_refptr<TransportSocketParams>& transport_params,
-                  const scoped_refptr<SOCKSSocketParams>& socks_params,
-                  const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
-                  ProxyServer::Scheme proxy,
-                  const HostPortPair& host_and_port,
-                  const SSLConfig& ssl_config,
-                  PrivacyMode privacy_mode,
-                  int load_flags,
-                  bool force_spdy_over_ssl,
-                  bool want_spdy_over_npn);
+  enum ConnectionType { DIRECT, SOCKS_PROXY, HTTP_PROXY };
 
-  const scoped_refptr<TransportSocketParams>& transport_params() {
-      return transport_params_;
-  }
-  const scoped_refptr<HttpProxySocketParams>& http_proxy_params() {
-    return http_proxy_params_;
-  }
-  const scoped_refptr<SOCKSSocketParams>& socks_params() {
-    return socks_params_;
-  }
-  ProxyServer::Scheme proxy() const { return proxy_; }
+  // Exactly one of |direct_params|, |socks_proxy_params|, and
+  // |http_proxy_params| must be non-NULL.
+  SSLSocketParams(
+      const scoped_refptr<TransportSocketParams>& direct_params,
+      const scoped_refptr<SOCKSSocketParams>& socks_proxy_params,
+      const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
+      const HostPortPair& host_and_port,
+      const SSLConfig& ssl_config,
+      PrivacyMode privacy_mode,
+      int load_flags,
+      bool force_spdy_over_ssl,
+      bool want_spdy_over_npn);
+
+  // Returns the type of the underlying connection.
+  ConnectionType GetConnectionType() const;
+
+  // Must be called only when GetConnectionType() returns DIRECT.
+  const scoped_refptr<TransportSocketParams>&
+      GetDirectConnectionParams() const;
+
+  // Must be called only when GetConnectionType() returns SOCKS_PROXY.
+  const scoped_refptr<SOCKSSocketParams>&
+      GetSocksProxyConnectionParams() const;
+
+  // Must be called only when GetConnectionType() returns HTTP_PROXY.
+  const scoped_refptr<HttpProxySocketParams>&
+      GetHttpProxyConnectionParams() const;
+
   const HostPortPair& host_and_port() const { return host_and_port_; }
   const SSLConfig& ssl_config() const { return ssl_config_; }
   PrivacyMode privacy_mode() const { return privacy_mode_; }
@@ -73,10 +79,9 @@
   friend class base::RefCounted<SSLSocketParams>;
   ~SSLSocketParams();
 
-  const scoped_refptr<TransportSocketParams> transport_params_;
+  const scoped_refptr<TransportSocketParams> direct_params_;
+  const scoped_refptr<SOCKSSocketParams> socks_proxy_params_;
   const scoped_refptr<HttpProxySocketParams> http_proxy_params_;
-  const scoped_refptr<SOCKSSocketParams> socks_params_;
-  const ProxyServer::Scheme proxy_;
   const HostPortPair host_and_port_;
   const SSLConfig ssl_config_;
   const PrivacyMode privacy_mode_;
@@ -94,6 +99,7 @@
  public:
   SSLConnectJob(
       const std::string& group_name,
+      RequestPriority priority,
       const scoped_refptr<SSLSocketParams>& params,
       const base::TimeDelta& timeout_duration,
       TransportClientSocketPool* transport_pool,
@@ -138,6 +144,10 @@
   int DoSSLConnect();
   int DoSSLConnectComplete(int result);
 
+  // Returns the initial state for the state machine based on the
+  // |connection_type|.
+  static State GetInitialState(SSLSocketParams::ConnectionType connection_type);
+
   // Starts the SSL connection process.  Returns OK on success and
   // ERR_IO_PENDING if it cannot immediately service the request.
   // Otherwise, it returns a net error code.
@@ -164,9 +174,11 @@
 
 class NET_EXPORT_PRIVATE SSLClientSocketPool
     : public ClientSocketPool,
-      public LayeredPool,
+      public HigherLayeredPool,
       public SSLConfigService::Observer {
  public:
+  typedef SSLSocketParams SocketParams;
+
   // Only the pools that will be used are required. i.e. if you never
   // try to create an SSL over SOCKS socket, |socks_pool| may be NULL.
   SSLClientSocketPool(
@@ -204,13 +216,11 @@
                              ClientSocketHandle* handle) OVERRIDE;
 
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket,
+                             scoped_ptr<StreamSocket> socket,
                              int id) OVERRIDE;
 
   virtual void FlushWithError(int error) OVERRIDE;
 
-  virtual bool IsStalled() const OVERRIDE;
-
   virtual void CloseIdleSockets() OVERRIDE;
 
   virtual int IdleSocketCount() const OVERRIDE;
@@ -222,10 +232,6 @@
       const std::string& group_name,
       const ClientSocketHandle* handle) const OVERRIDE;
 
-  virtual void AddLayeredPool(LayeredPool* layered_pool) OVERRIDE;
-
-  virtual void RemoveLayeredPool(LayeredPool* layered_pool) OVERRIDE;
-
   virtual base::DictionaryValue* GetInfoAsValue(
       const std::string& name,
       const std::string& type,
@@ -235,7 +241,14 @@
 
   virtual ClientSocketPoolHistograms* histograms() const OVERRIDE;
 
-  // LayeredPool implementation.
+  // LowerLayeredPool implementation.
+  virtual bool IsStalled() const OVERRIDE;
+
+  virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+
+  virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+
+  // HigherLayeredPool implementation.
   virtual bool CloseOneIdleConnection() OVERRIDE;
 
  private:
@@ -261,7 +274,7 @@
     virtual ~SSLConnectJobFactory() {}
 
     // ClientSocketPoolBase::ConnectJobFactory methods.
-    virtual ConnectJob* NewConnectJob(
+    virtual scoped_ptr<ConnectJob> NewConnectJob(
         const std::string& group_name,
         const PoolBase::Request& request,
         ConnectJob::Delegate* delegate) const OVERRIDE;
@@ -290,8 +303,6 @@
   DISALLOW_COPY_AND_ASSIGN(SSLClientSocketPool);
 };
 
-REGISTER_SOCKET_PARAMS_FOR_POOL(SSLClientSocketPool, SSLSocketParams);
-
 }  // namespace net
 
 #endif  // NET_SOCKET_SSL_CLIENT_SOCKET_POOL_H_
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 280f6e7..8aecb98 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -85,7 +85,6 @@
         session_(CreateNetworkSession()),
         direct_transport_socket_params_(
             new TransportSocketParams(HostPortPair("host", 443),
-                                      MEDIUM,
                                       false,
                                       false,
                                       OnHostResolutionCallback())),
@@ -96,15 +95,13 @@
                                &socket_factory_),
         proxy_transport_socket_params_(
             new TransportSocketParams(HostPortPair("proxy", 443),
-                                      MEDIUM,
                                       false,
                                       false,
                                       OnHostResolutionCallback())),
         socks_socket_params_(
             new SOCKSSocketParams(proxy_transport_socket_params_,
                                   true,
-                                  HostPortPair("sockshost", 443),
-                                  MEDIUM)),
+                                  HostPortPair("sockshost", 443))),
         socks_histograms_("MockSOCKS"),
         socks_socket_pool_(kMaxSockets,
                            kMaxSocketsPerGroup,
@@ -159,7 +156,6 @@
                                             : NULL,
         proxy == ProxyServer::SCHEME_SOCKS5 ? socks_socket_params_ : NULL,
         proxy == ProxyServer::SCHEME_HTTP ? http_proxy_socket_params_ : NULL,
-        proxy,
         HostPortPair("host", 443),
         ssl_config_,
         kPrivacyModeDisabled,
@@ -294,6 +290,30 @@
   TestLoadTimingInfo(handle);
 }
 
+// Make sure that SSLConnectJob passes on its priority to its
+// socket request on Init (for the DIRECT case).
+TEST_P(SSLClientSocketPoolTest, SetSocketRequestPriorityOnInitDirect) {
+  CreatePool(true /* tcp pool */, false, false);
+  scoped_refptr<SSLSocketParams> params =
+      SSLParams(ProxyServer::SCHEME_DIRECT, false);
+
+  for (int i = MINIMUM_PRIORITY; i < NUM_PRIORITIES; ++i) {
+    RequestPriority priority = static_cast<RequestPriority>(i);
+    StaticSocketDataProvider data;
+    data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
+    socket_factory_.AddSocketDataProvider(&data);
+    SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+    socket_factory_.AddSSLSocketDataProvider(&ssl);
+
+    ClientSocketHandle handle;
+    TestCompletionCallback callback;
+    EXPECT_EQ(OK, handle.Init("a", params, priority, callback.callback(),
+                              pool_.get(), BoundNetLog()));
+    EXPECT_EQ(priority, transport_socket_pool_.last_request_priority());
+    handle.socket()->Disconnect();
+  }
+}
+
 TEST_P(SSLClientSocketPoolTest, BasicDirectAsync) {
   StaticSocketDataProvider data;
   socket_factory_.AddSocketDataProvider(&data);
@@ -547,6 +567,26 @@
   TestLoadTimingInfo(handle);
 }
 
+// Make sure that SSLConnectJob passes on its priority to its
+// transport socket on Init (for the SOCKS_PROXY case).
+TEST_P(SSLClientSocketPoolTest, SetTransportPriorityOnInitSOCKS) {
+  StaticSocketDataProvider data;
+  data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
+  socket_factory_.AddSocketDataProvider(&data);
+  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+  socket_factory_.AddSSLSocketDataProvider(&ssl);
+
+  CreatePool(false, true /* http proxy pool */, true /* socks pool */);
+  scoped_refptr<SSLSocketParams> params =
+      SSLParams(ProxyServer::SCHEME_SOCKS5, false);
+
+  ClientSocketHandle handle;
+  TestCompletionCallback callback;
+  EXPECT_EQ(OK, handle.Init("a", params, HIGHEST, callback.callback(),
+                            pool_.get(), BoundNetLog()));
+  EXPECT_EQ(HIGHEST, transport_socket_pool_.last_request_priority());
+}
+
 TEST_P(SSLClientSocketPoolTest, SOCKSBasicAsync) {
   StaticSocketDataProvider data;
   socket_factory_.AddSocketDataProvider(&data);
@@ -648,6 +688,38 @@
   TestLoadTimingInfoNoDns(handle);
 }
 
+// Make sure that SSLConnectJob passes on its priority to its
+// transport socket on Init (for the HTTP_PROXY case).
+TEST_P(SSLClientSocketPoolTest, SetTransportPriorityOnInitHTTP) {
+  MockWrite writes[] = {
+      MockWrite(SYNCHRONOUS,
+                "CONNECT host:80 HTTP/1.1\r\n"
+                "Host: host\r\n"
+                "Proxy-Connection: keep-alive\r\n"
+                "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+  };
+  MockRead reads[] = {
+      MockRead(SYNCHRONOUS, "HTTP/1.1 200 Connection Established\r\n\r\n"),
+  };
+  StaticSocketDataProvider data(reads, arraysize(reads), writes,
+                                arraysize(writes));
+  data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
+  socket_factory_.AddSocketDataProvider(&data);
+  AddAuthToCache();
+  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+  socket_factory_.AddSSLSocketDataProvider(&ssl);
+
+  CreatePool(false, true /* http proxy pool */, true /* socks pool */);
+  scoped_refptr<SSLSocketParams> params =
+      SSLParams(ProxyServer::SCHEME_HTTP, false);
+
+  ClientSocketHandle handle;
+  TestCompletionCallback callback;
+  EXPECT_EQ(OK, handle.Init("a", params, HIGHEST, callback.callback(),
+                            pool_.get(), BoundNetLog()));
+  EXPECT_EQ(HIGHEST, transport_socket_pool_.last_request_priority());
+}
+
 TEST_P(SSLClientSocketPoolTest, HttpProxyBasicAsync) {
   MockWrite writes[] = {
       MockWrite("CONNECT host:80 HTTP/1.1\r\n"
@@ -746,8 +818,12 @@
     // This test requires that the HostResolver cache be populated.  Normal
     // code would have done this already, but we do it manually.
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
-    host_resolver_.Resolve(info, &test_hosts[i].addresses, CompletionCallback(),
-                           NULL, BoundNetLog());
+    host_resolver_.Resolve(info,
+                           DEFAULT_PRIORITY,
+                           &test_hosts[i].addresses,
+                           CompletionCallback(),
+                           NULL,
+                           BoundNetLog());
 
     // Setup a SpdySessionKey
     test_hosts[i].key = SpdySessionKey(
@@ -802,8 +878,12 @@
     // This test requires that the HostResolver cache be populated.  Normal
     // code would have done this already, but we do it manually.
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
-    rv = host_resolver_.Resolve(info, &test_hosts[i].addresses,
-                                callback.callback(), NULL, BoundNetLog());
+    rv = host_resolver_.Resolve(info,
+                                DEFAULT_PRIORITY,
+                                &test_hosts[i].addresses,
+                                callback.callback(),
+                                NULL,
+                                BoundNetLog());
     EXPECT_EQ(OK, callback.GetResult(rv));
 
     // Setup a SpdySessionKey
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index f0e7120..f791928 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -30,9 +30,11 @@
 
 //-----------------------------------------------------------------------------
 
+namespace net {
+
 namespace {
 
-const net::SSLConfig kDefaultSSLConfig;
+const SSLConfig kDefaultSSLConfig;
 
 // WrappedStreamSocket is a base class that wraps an existing StreamSocket,
 // forwarding the Socket and StreamSocket interfaces to the underlying
@@ -40,33 +42,30 @@
 // This is to provide a common base class for subclasses to override specific
 // StreamSocket methods for testing, while still communicating with a 'real'
 // StreamSocket.
-class WrappedStreamSocket : public net::StreamSocket {
+class WrappedStreamSocket : public StreamSocket {
  public:
-  explicit WrappedStreamSocket(scoped_ptr<net::StreamSocket> transport)
-      : transport_(transport.Pass()) {
-  }
+  explicit WrappedStreamSocket(scoped_ptr<StreamSocket> transport)
+      : transport_(transport.Pass()) {}
   virtual ~WrappedStreamSocket() {}
 
   // StreamSocket implementation:
-  virtual int Connect(const net::CompletionCallback& callback) OVERRIDE {
+  virtual int Connect(const CompletionCallback& callback) OVERRIDE {
     return transport_->Connect(callback);
   }
-  virtual void Disconnect() OVERRIDE {
-    transport_->Disconnect();
-  }
+  virtual void Disconnect() OVERRIDE { transport_->Disconnect(); }
   virtual bool IsConnected() const OVERRIDE {
     return transport_->IsConnected();
   }
   virtual bool IsConnectedAndIdle() const OVERRIDE {
     return transport_->IsConnectedAndIdle();
   }
-  virtual int GetPeerAddress(net::IPEndPoint* address) const OVERRIDE {
+  virtual int GetPeerAddress(IPEndPoint* address) const OVERRIDE {
     return transport_->GetPeerAddress(address);
   }
-  virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE {
+  virtual int GetLocalAddress(IPEndPoint* address) const OVERRIDE {
     return transport_->GetLocalAddress(address);
   }
-  virtual const net::BoundNetLog& NetLog() const OVERRIDE {
+  virtual const BoundNetLog& NetLog() const OVERRIDE {
     return transport_->NetLog();
   }
   virtual void SetSubresourceSpeculation() OVERRIDE {
@@ -84,20 +83,22 @@
   virtual bool WasNpnNegotiated() const OVERRIDE {
     return transport_->WasNpnNegotiated();
   }
-  virtual net::NextProto GetNegotiatedProtocol() const OVERRIDE {
+  virtual NextProto GetNegotiatedProtocol() const OVERRIDE {
     return transport_->GetNegotiatedProtocol();
   }
-  virtual bool GetSSLInfo(net::SSLInfo* ssl_info) OVERRIDE {
+  virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {
     return transport_->GetSSLInfo(ssl_info);
   }
 
   // Socket implementation:
-  virtual int Read(net::IOBuffer* buf, int buf_len,
-                   const net::CompletionCallback& callback) OVERRIDE {
+  virtual int Read(IOBuffer* buf,
+                   int buf_len,
+                   const CompletionCallback& callback) OVERRIDE {
     return transport_->Read(buf, buf_len, callback);
   }
-  virtual int Write(net::IOBuffer* buf, int buf_len,
-                    const net::CompletionCallback& callback) OVERRIDE {
+  virtual int Write(IOBuffer* buf,
+                    int buf_len,
+                    const CompletionCallback& callback) OVERRIDE {
     return transport_->Write(buf, buf_len, callback);
   }
   virtual bool SetReceiveBufferSize(int32 size) OVERRIDE {
@@ -108,7 +109,7 @@
   }
 
  protected:
-  scoped_ptr<net::StreamSocket> transport_;
+  scoped_ptr<StreamSocket> transport_;
 };
 
 // ReadBufferingStreamSocket is a wrapper for an existing StreamSocket that
@@ -119,12 +120,13 @@
 // them from the TestServer.
 class ReadBufferingStreamSocket : public WrappedStreamSocket {
  public:
-  explicit ReadBufferingStreamSocket(scoped_ptr<net::StreamSocket> transport);
+  explicit ReadBufferingStreamSocket(scoped_ptr<StreamSocket> transport);
   virtual ~ReadBufferingStreamSocket() {}
 
   // Socket implementation:
-  virtual int Read(net::IOBuffer* buf, int buf_len,
-                   const net::CompletionCallback& callback) OVERRIDE;
+  virtual int Read(IOBuffer* buf,
+                   int buf_len,
+                   const CompletionCallback& callback) OVERRIDE;
 
   // Sets the internal buffer to |size|. This must not be greater than
   // the largest value supplied to Read() - that is, it does not handle
@@ -148,19 +150,18 @@
   void OnReadCompleted(int result);
 
   State state_;
-  scoped_refptr<net::GrowableIOBuffer> read_buffer_;
+  scoped_refptr<GrowableIOBuffer> read_buffer_;
   int buffer_size_;
 
-  scoped_refptr<net::IOBuffer> user_read_buf_;
-  net::CompletionCallback user_read_callback_;
+  scoped_refptr<IOBuffer> user_read_buf_;
+  CompletionCallback user_read_callback_;
 };
 
 ReadBufferingStreamSocket::ReadBufferingStreamSocket(
-    scoped_ptr<net::StreamSocket> transport)
+    scoped_ptr<StreamSocket> transport)
     : WrappedStreamSocket(transport.Pass()),
-      read_buffer_(new net::GrowableIOBuffer()),
-      buffer_size_(0) {
-}
+      read_buffer_(new GrowableIOBuffer()),
+      buffer_size_(0) {}
 
 void ReadBufferingStreamSocket::SetBufferSize(int size) {
   DCHECK(!user_read_buf_.get());
@@ -168,19 +169,19 @@
   read_buffer_->SetCapacity(size);
 }
 
-int ReadBufferingStreamSocket::Read(net::IOBuffer* buf,
+int ReadBufferingStreamSocket::Read(IOBuffer* buf,
                                     int buf_len,
-                                    const net::CompletionCallback& callback) {
+                                    const CompletionCallback& callback) {
   if (buffer_size_ == 0)
     return transport_->Read(buf, buf_len, callback);
 
   if (buf_len < buffer_size_)
-    return net::ERR_UNEXPECTED;
+    return ERR_UNEXPECTED;
 
   state_ = STATE_READ;
   user_read_buf_ = buf;
-  int result = DoLoop(net::OK);
-  if (result == net::ERR_IO_PENDING)
+  int result = DoLoop(OK);
+  if (result == ERR_IO_PENDING)
     user_read_callback_ = callback;
   else
     user_read_buf_ = NULL;
@@ -202,10 +203,10 @@
       case STATE_NONE:
       default:
         NOTREACHED() << "Unexpected state: " << current_state;
-        rv = net::ERR_UNEXPECTED;
+        rv = ERR_UNEXPECTED;
         break;
     }
-  } while (rv != net::ERR_IO_PENDING && state_ != STATE_NONE);
+  } while (rv != ERR_IO_PENDING && state_ != STATE_NONE);
   return rv;
 }
 
@@ -227,10 +228,11 @@
   read_buffer_->set_offset(read_buffer_->offset() + result);
   if (read_buffer_->RemainingCapacity() > 0) {
     state_ = STATE_READ;
-    return net::OK;
+    return OK;
   }
 
-  memcpy(user_read_buf_->data(), read_buffer_->StartOfBuffer(),
+  memcpy(user_read_buf_->data(),
+         read_buffer_->StartOfBuffer(),
          read_buffer_->capacity());
   read_buffer_->set_offset(0);
   return read_buffer_->capacity();
@@ -238,7 +240,7 @@
 
 void ReadBufferingStreamSocket::OnReadCompleted(int result) {
   result = DoLoop(result);
-  if (result == net::ERR_IO_PENDING)
+  if (result == ERR_IO_PENDING)
     return;
 
   user_read_buf_ = NULL;
@@ -252,16 +254,18 @@
   virtual ~SynchronousErrorStreamSocket() {}
 
   // Socket implementation:
-  virtual int Read(net::IOBuffer* buf, int buf_len,
-                   const net::CompletionCallback& callback) OVERRIDE;
-  virtual int Write(net::IOBuffer* buf, int buf_len,
-                    const net::CompletionCallback& callback) OVERRIDE;
+  virtual int Read(IOBuffer* buf,
+                   int buf_len,
+                   const CompletionCallback& callback) OVERRIDE;
+  virtual int Write(IOBuffer* buf,
+                    int buf_len,
+                    const CompletionCallback& callback) OVERRIDE;
 
   // Sets the next Read() call and all future calls to return |error|.
   // If there is already a pending asynchronous read, the configured error
   // will not be returned until that asynchronous read has completed and Read()
   // is called again.
-  void SetNextReadError(net::Error error) {
+  void SetNextReadError(Error error) {
     DCHECK_GE(0, error);
     have_read_error_ = true;
     pending_read_error_ = error;
@@ -271,7 +275,7 @@
   // If there is already a pending asynchronous write, the configured error
   // will not be returned until that asynchronous write has completed and
   // Write() is called again.
-  void SetNextWriteError(net::Error error) {
+  void SetNextWriteError(Error error) {
     DCHECK_GE(0, error);
     have_write_error_ = true;
     pending_write_error_ = error;
@@ -291,24 +295,21 @@
     scoped_ptr<StreamSocket> transport)
     : WrappedStreamSocket(transport.Pass()),
       have_read_error_(false),
-      pending_read_error_(net::OK),
+      pending_read_error_(OK),
       have_write_error_(false),
-      pending_write_error_(net::OK) {
-}
+      pending_write_error_(OK) {}
 
-int SynchronousErrorStreamSocket::Read(
-    net::IOBuffer* buf,
-    int buf_len,
-    const net::CompletionCallback& callback) {
+int SynchronousErrorStreamSocket::Read(IOBuffer* buf,
+                                       int buf_len,
+                                       const CompletionCallback& callback) {
   if (have_read_error_)
     return pending_read_error_;
   return transport_->Read(buf, buf_len, callback);
 }
 
-int SynchronousErrorStreamSocket::Write(
-    net::IOBuffer* buf,
-    int buf_len,
-    const net::CompletionCallback& callback) {
+int SynchronousErrorStreamSocket::Write(IOBuffer* buf,
+                                        int buf_len,
+                                        const CompletionCallback& callback) {
   if (have_write_error_)
     return pending_write_error_;
   return transport_->Write(buf, buf_len, callback);
@@ -324,12 +325,14 @@
   virtual ~FakeBlockingStreamSocket() {}
 
   // Socket implementation:
-  virtual int Read(net::IOBuffer* buf, int buf_len,
-                   const net::CompletionCallback& callback) OVERRIDE {
+  virtual int Read(IOBuffer* buf,
+                   int buf_len,
+                   const CompletionCallback& callback) OVERRIDE {
     return read_state_.RunWrappedFunction(buf, buf_len, callback);
   }
-  virtual int Write(net::IOBuffer* buf, int buf_len,
-                    const net::CompletionCallback& callback) OVERRIDE {
+  virtual int Write(IOBuffer* buf,
+                    int buf_len,
+                    const CompletionCallback& callback) OVERRIDE {
     return write_state_.RunWrappedFunction(buf, buf_len, callback);
   }
 
@@ -350,9 +353,8 @@
   class BlockingState {
    public:
     // Wrapper for the underlying Socket function to call (ie: Read/Write).
-    typedef base::Callback<
-        int(net::IOBuffer*, int,
-            const net::CompletionCallback&)> WrappedSocketFunction;
+    typedef base::Callback<int(IOBuffer*, int, const CompletionCallback&)>
+        WrappedSocketFunction;
 
     explicit BlockingState(const WrappedSocketFunction& function);
     ~BlockingState() {}
@@ -371,8 +373,9 @@
     // Performs the wrapped socket function on the underlying transport. If
     // configured to block via SetShouldBlock(), then |user_callback| will not
     // be invoked until Unblock() has been called.
-    int RunWrappedFunction(net::IOBuffer* buf, int len,
-                           const net::CompletionCallback& user_callback);
+    int RunWrappedFunction(IOBuffer* buf,
+                           int len,
+                           const CompletionCallback& user_callback);
 
    private:
     // Handles completion from the underlying wrapped socket function.
@@ -382,7 +385,7 @@
     bool should_block_;
     bool have_result_;
     int pending_result_;
-    net::CompletionCallback user_callback_;
+    CompletionCallback user_callback_;
   };
 
   BlockingState read_state_;
@@ -397,16 +400,14 @@
       read_state_(base::Bind(&Socket::Read,
                              base::Unretained(transport_.get()))),
       write_state_(base::Bind(&Socket::Write,
-                              base::Unretained(transport_.get()))) {
-}
+                              base::Unretained(transport_.get()))) {}
 
 FakeBlockingStreamSocket::BlockingState::BlockingState(
     const WrappedSocketFunction& function)
     : wrapped_function_(function),
       should_block_(false),
       have_result_(false),
-      pending_result_(net::OK) {
-}
+      pending_result_(OK) {}
 
 void FakeBlockingStreamSocket::BlockingState::SetShouldBlock() {
   DCHECK(!should_block_);
@@ -429,24 +430,24 @@
 }
 
 int FakeBlockingStreamSocket::BlockingState::RunWrappedFunction(
-    net::IOBuffer* buf,
+    IOBuffer* buf,
     int len,
-    const net::CompletionCallback& callback) {
+    const CompletionCallback& callback) {
 
   // The callback to be called by the underlying transport. Either forward
   // directly to the user's callback if not set to block, or intercept it with
   // OnCompleted so that the user's callback is not invoked until Unblock() is
   // called.
-  net::CompletionCallback transport_callback =
+  CompletionCallback transport_callback =
       !should_block_ ? callback : base::Bind(&BlockingState::OnCompleted,
                                              base::Unretained(this));
   int rv = wrapped_function_.Run(buf, len, transport_callback);
   if (should_block_) {
     user_callback_ = callback;
     // May have completed synchronously.
-    have_result_ = (rv != net::ERR_IO_PENDING);
+    have_result_ = (rv != ERR_IO_PENDING);
     pending_result_ = rv;
-    return net::ERR_IO_PENDING;
+    return ERR_IO_PENDING;
   }
 
   return rv;
@@ -466,64 +467,61 @@
   base::ResetAndReturn(&user_callback_).Run(result);
 }
 
-// CompletionCallback that will delete the associated net::StreamSocket when
+// CompletionCallback that will delete the associated StreamSocket when
 // the callback is invoked.
-class DeleteSocketCallback : public net::TestCompletionCallbackBase {
+class DeleteSocketCallback : public TestCompletionCallbackBase {
  public:
-  explicit DeleteSocketCallback(net::StreamSocket* socket)
+  explicit DeleteSocketCallback(StreamSocket* socket)
       : socket_(socket),
         callback_(base::Bind(&DeleteSocketCallback::OnComplete,
-                             base::Unretained(this))) {
-  }
+                             base::Unretained(this))) {}
   virtual ~DeleteSocketCallback() {}
 
-  const net::CompletionCallback& callback() const { return callback_; }
+  const CompletionCallback& callback() const { return callback_; }
 
  private:
   void OnComplete(int result) {
-   if (socket_) {
-     delete socket_;
-     socket_ = NULL;
-   } else {
-     ADD_FAILURE() << "Deleting socket twice";
-   }
-   SetResult(result);
+    if (socket_) {
+      delete socket_;
+      socket_ = NULL;
+    } else {
+      ADD_FAILURE() << "Deleting socket twice";
+    }
+    SetResult(result);
   }
 
-  net::StreamSocket* socket_;
-  net::CompletionCallback callback_;
+  StreamSocket* socket_;
+  CompletionCallback callback_;
 
   DISALLOW_COPY_AND_ASSIGN(DeleteSocketCallback);
 };
 
-}  // namespace
-
 class SSLClientSocketTest : public PlatformTest {
  public:
   SSLClientSocketTest()
-      : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()),
-        cert_verifier_(new net::MockCertVerifier),
-        transport_security_state_(new net::TransportSecurityState) {
-    cert_verifier_->set_default_result(net::OK);
+      : socket_factory_(ClientSocketFactory::GetDefaultFactory()),
+        cert_verifier_(new MockCertVerifier),
+        transport_security_state_(new TransportSecurityState) {
+    cert_verifier_->set_default_result(OK);
     context_.cert_verifier = cert_verifier_.get();
     context_.transport_security_state = transport_security_state_.get();
   }
 
  protected:
-  net::SSLClientSocket* CreateSSLClientSocket(
-      net::StreamSocket* transport_socket,
-      const net::HostPortPair& host_and_port,
-      const net::SSLConfig& ssl_config) {
-    return socket_factory_->CreateSSLClientSocket(transport_socket,
-                                                  host_and_port,
-                                                  ssl_config,
-                                                  context_);
+  scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<StreamSocket> transport_socket,
+      const HostPortPair& host_and_port,
+      const SSLConfig& ssl_config) {
+    scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
+    connection->SetSocket(transport_socket.Pass());
+    return socket_factory_->CreateSSLClientSocket(
+        connection.Pass(), host_and_port, ssl_config, context_);
   }
 
-  net::ClientSocketFactory* socket_factory_;
-  scoped_ptr<net::MockCertVerifier> cert_verifier_;
-  scoped_ptr<net::TransportSecurityState> transport_security_state_;
-  net::SSLClientSocketContext context_;
+  ClientSocketFactory* socket_factory_;
+  scoped_ptr<MockCertVerifier> cert_verifier_;
+  scoped_ptr<TransportSecurityState> transport_security_state_;
+  SSLClientSocketContext context_;
 };
 
 //-----------------------------------------------------------------------------
@@ -536,45 +534,45 @@
 // timeout. This means that an SSL connect end event may appear as a socket
 // write.
 static bool LogContainsSSLConnectEndEvent(
-    const net::CapturingNetLog::CapturedEntryList& log, int i) {
-  return net::LogContainsEndEvent(log, i, net::NetLog::TYPE_SSL_CONNECT) ||
-         net::LogContainsEvent(log, i, net::NetLog::TYPE_SOCKET_BYTES_SENT,
-                                net::NetLog::PHASE_NONE);
-};
+    const CapturingNetLog::CapturedEntryList& log,
+    int i) {
+  return LogContainsEndEvent(log, i, NetLog::TYPE_SSL_CONNECT) ||
+         LogContainsEvent(
+             log, i, NetLog::TYPE_SOCKET_BYTES_SENT, NetLog::PHASE_NONE);
+}
+;
 
 TEST_F(SSLClientSocketTest, Connect) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   EXPECT_FALSE(sock->IsConnected());
 
   rv = sock->Connect(callback.callback());
 
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
-  if (rv == net::ERR_IO_PENDING)
+  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
   log.GetEntries(&entries);
   EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
@@ -584,43 +582,40 @@
 }
 
 TEST_F(SSLClientSocketTest, ConnectExpired) {
-  net::SpawnedTestServer::SSLOptions ssl_options(
-      net::SpawnedTestServer::SSLOptions::CERT_EXPIRED);
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     ssl_options,
-                                     base::FilePath());
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_EXPIRED);
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  cert_verifier_->set_default_result(net::ERR_CERT_DATE_INVALID);
+  cert_verifier_->set_default_result(ERR_CERT_DATE_INVALID);
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   EXPECT_FALSE(sock->IsConnected());
 
   rv = sock->Connect(callback.callback());
 
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
-  if (rv == net::ERR_IO_PENDING)
+  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
 
-  EXPECT_EQ(net::ERR_CERT_DATE_INVALID, rv);
+  EXPECT_EQ(ERR_CERT_DATE_INVALID, rv);
 
   // Rather than testing whether or not the underlying socket is connected,
   // test that the handshake has finished. This is because it may be
@@ -631,43 +626,40 @@
 }
 
 TEST_F(SSLClientSocketTest, ConnectMismatched) {
-  net::SpawnedTestServer::SSLOptions ssl_options(
-      net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME);
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     ssl_options,
-                                     base::FilePath());
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME);
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  cert_verifier_->set_default_result(net::ERR_CERT_COMMON_NAME_INVALID);
+  cert_verifier_->set_default_result(ERR_CERT_COMMON_NAME_INVALID);
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   EXPECT_FALSE(sock->IsConnected());
 
   rv = sock->Connect(callback.callback());
 
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
-  if (rv == net::ERR_IO_PENDING)
+  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
 
-  EXPECT_EQ(net::ERR_CERT_COMMON_NAME_INVALID, rv);
+  EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, rv);
 
   // Rather than testing whether or not the underlying socket is connected,
   // test that the handshake has finished. This is because it may be
@@ -680,38 +672,35 @@
 // Attempt to connect to a page which requests a client certificate. It should
 // return an error code on connect.
 TEST_F(SSLClientSocketTest, ConnectClientAuthCertRequested) {
-  net::SpawnedTestServer::SSLOptions ssl_options;
+  SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     ssl_options,
-                                     base::FilePath());
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   EXPECT_FALSE(sock->IsConnected());
 
   rv = sock->Connect(callback.callback());
 
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
-  if (rv == net::ERR_IO_PENDING)
+  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
 
   log.GetEntries(&entries);
@@ -731,9 +720,9 @@
   // certificate. This test may still be useful as we'll want to close
   // the socket on a timeout if the user takes a long time to pick a
   // cert. Related bug: https://bugzilla.mozilla.org/show_bug.cgi?id=542832
-  net::ExpectLogContainsSomewhere(
-      entries, 0, net::NetLog::TYPE_SSL_CONNECT, net::NetLog::PHASE_END);
-  EXPECT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
+  ExpectLogContainsSomewhere(
+      entries, 0, NetLog::TYPE_SSL_CONNECT, NetLog::PHASE_END);
+  EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
   EXPECT_FALSE(sock->IsConnected());
 }
 
@@ -742,32 +731,30 @@
 //
 // TODO(davidben): Also test providing an actual certificate.
 TEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
-  net::SpawnedTestServer::SSLOptions ssl_options;
+  SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     ssl_options,
-                                     base::FilePath());
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  net::SSLConfig ssl_config = kDefaultSSLConfig;
+  SSLConfig ssl_config = kDefaultSSLConfig;
   ssl_config.send_client_cert = true;
   ssl_config.client_cert = NULL;
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            ssl_config));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), ssl_config));
 
   EXPECT_FALSE(sock->IsConnected());
 
@@ -775,14 +762,13 @@
   // TODO(davidben): Add a test which requires them and verify the error.
   rv = sock->Connect(callback.callback());
 
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
-  if (rv == net::ERR_IO_PENDING)
+  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
 
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
   log.GetEntries(&entries);
   EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
@@ -790,7 +776,7 @@
   // We responded to the server's certificate request with a Certificate
   // message with no client certificate in it.  ssl_info.client_cert_sent
   // should be false in this case.
-  net::SSLInfo ssl_info;
+  SSLInfo ssl_info;
   sock->GetSSLInfo(&ssl_info);
   EXPECT_FALSE(ssl_info.client_cert_sent);
 
@@ -804,51 +790,50 @@
 //   - Server sends data unexpectedly.
 
 TEST_F(SSLClientSocketTest, Read) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source());
+  TestCompletionCallback callback;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
 
   const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::IOBuffer(arraysize(request_text) - 1));
+  scoped_refptr<IOBuffer> request_buffer(
+      new IOBuffer(arraysize(request_text) - 1));
   memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
 
   rv = sock->Write(
       request_buffer.get(), arraysize(request_text) - 1, callback.callback());
-  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
   EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
 
-  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
+  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
   for (;;) {
     rv = sock->Read(buf.get(), 4096, callback.callback());
-    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+    EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-    if (rv == net::ERR_IO_PENDING)
+    if (rv == ERR_IO_PENDING)
       rv = callback.WaitForResult();
 
     EXPECT_GE(rv, 0);
@@ -862,39 +847,40 @@
 // the socket connection uncleanly.
 // This is a regression test for http://crbug.com/238536
 TEST_F(SSLClientSocketTest, Read_WithSynchronousError) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  scoped_ptr<net::StreamSocket> real_transport(new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source()));
-  SynchronousErrorStreamSocket* transport = new SynchronousErrorStreamSocket(
-      real_transport.Pass());
+  TestCompletionCallback callback;
+  scoped_ptr<StreamSocket> real_transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
+  scoped_ptr<SynchronousErrorStreamSocket> transport(
+      new SynchronousErrorStreamSocket(real_transport.Pass()));
   int rv = callback.GetResult(transport->Connect(callback.callback()));
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
   // Disable TLS False Start to avoid handshake non-determinism.
-  net::SSLConfig ssl_config;
+  SSLConfig ssl_config;
   ssl_config.false_start_enabled = false;
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
+  SynchronousErrorStreamSocket* raw_transport = transport.get();
+  scoped_ptr<SSLClientSocket> sock(
+      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
+                            test_server.host_port_pair(),
                             ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
 
   const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
   static const int kRequestTextSize =
       static_cast<int>(arraysize(request_text) - 1);
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::IOBuffer(kRequestTextSize));
+  scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize));
   memcpy(request_buffer->data(), request_text, kRequestTextSize);
 
   rv = callback.GetResult(
@@ -902,9 +888,9 @@
   EXPECT_EQ(kRequestTextSize, rv);
 
   // Simulate an unclean/forcible shutdown.
-  transport->SetNextReadError(net::ERR_CONNECTION_RESET);
+  raw_transport->SetNextReadError(ERR_CONNECTION_RESET);
 
-  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
+  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
 
   // Note: This test will hang if this bug has regressed. Simply checking that
   // rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate
@@ -913,7 +899,7 @@
 
 #if !defined(USE_OPENSSL)
   // SSLClientSocketNSS records the error exactly
-  EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
+  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
 #else
   // SSLClientSocketOpenSSL treats any errors as a simple EOF.
   EXPECT_EQ(0, rv);
@@ -925,49 +911,51 @@
 // intermediary terminates the socket connection uncleanly.
 // This is a regression test for http://crbug.com/249848
 TEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  scoped_ptr<net::StreamSocket> real_transport(new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source()));
-  // Note: |error_socket|'s ownership is handed to |transport|, but the pointer
+  TestCompletionCallback callback;
+  scoped_ptr<StreamSocket> real_transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
+  // Note: |error_socket|'s ownership is handed to |transport|, but a pointer
   // is retained in order to configure additional errors.
-  SynchronousErrorStreamSocket* error_socket = new SynchronousErrorStreamSocket(
-      real_transport.Pass());
-  FakeBlockingStreamSocket* transport = new FakeBlockingStreamSocket(
-      scoped_ptr<net::StreamSocket>(error_socket));
+  scoped_ptr<SynchronousErrorStreamSocket> error_socket(
+      new SynchronousErrorStreamSocket(real_transport.Pass()));
+  SynchronousErrorStreamSocket* raw_error_socket = error_socket.get();
+  scoped_ptr<FakeBlockingStreamSocket> transport(
+      new FakeBlockingStreamSocket(error_socket.PassAs<StreamSocket>()));
+  FakeBlockingStreamSocket* raw_transport = transport.get();
   int rv = callback.GetResult(transport->Connect(callback.callback()));
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
   // Disable TLS False Start to avoid handshake non-determinism.
-  net::SSLConfig ssl_config;
+  SSLConfig ssl_config;
   ssl_config.false_start_enabled = false;
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
+  scoped_ptr<SSLClientSocket> sock(
+      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
+                            test_server.host_port_pair(),
                             ssl_config));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
 
   const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
   static const int kRequestTextSize =
       static_cast<int>(arraysize(request_text) - 1);
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::IOBuffer(kRequestTextSize));
+  scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize));
   memcpy(request_buffer->data(), request_text, kRequestTextSize);
 
   // Simulate an unclean/forcible shutdown on the underlying socket.
   // However, simulate this error asynchronously.
-  error_socket->SetNextWriteError(net::ERR_CONNECTION_RESET);
-  transport->SetNextWriteShouldBlock();
+  raw_error_socket->SetNextWriteError(ERR_CONNECTION_RESET);
+  raw_transport->SetNextWriteShouldBlock();
 
   // This write should complete synchronously, because the TLS ciphertext
   // can be created and placed into the outgoing buffers independent of the
@@ -976,14 +964,14 @@
       sock->Write(request_buffer.get(), kRequestTextSize, callback.callback()));
   EXPECT_EQ(kRequestTextSize, rv);
 
-  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
+  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
 
   rv = sock->Read(buf.get(), 4096, callback.callback());
-  EXPECT_EQ(net::ERR_IO_PENDING, rv);
+  EXPECT_EQ(ERR_IO_PENDING, rv);
 
   // Now unblock the outgoing request, having it fail with the connection
   // being reset.
-  transport->UnblockWrite();
+  raw_transport->UnblockWrite();
 
   // Note: This will cause an inifite loop if this bug has regressed. Simply
   // checking that rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING
@@ -992,7 +980,7 @@
 
 #if !defined(USE_OPENSSL)
   // SSLClientSocketNSS records the error exactly
-  EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
+  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
 #else
   // SSLClientSocketOpenSSL treats any errors as a simple EOF.
   EXPECT_EQ(0, rv);
@@ -1002,38 +990,37 @@
 // Test the full duplex mode, with Read and Write pending at the same time.
 // This test also serves as a regression test for http://crbug.com/29815.
 TEST_F(SSLClientSocketTest, Read_FullDuplex) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;  // Used for everything except Write.
+  TestCompletionCallback callback;  // Used for everything except Write.
 
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source());
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
 
   // Issue a "hanging" Read first.
-  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
+  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
   rv = sock->Read(buf.get(), 4096, callback.callback());
   // We haven't written the request, so there should be no response yet.
-  ASSERT_EQ(net::ERR_IO_PENDING, rv);
+  ASSERT_EQ(ERR_IO_PENDING, rv);
 
   // Write the request.
   // The request is padded with a User-Agent header to a size that causes the
@@ -1043,15 +1030,14 @@
   for (int i = 0; i < 3770; ++i)
     request_text.push_back('*');
   request_text.append("\r\n\r\n");
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::StringIOBuffer(request_text));
+  scoped_refptr<IOBuffer> request_buffer(new StringIOBuffer(request_text));
 
-  net::TestCompletionCallback callback2;  // Used for Write only.
+  TestCompletionCallback callback2;  // Used for Write only.
   rv = sock->Write(
       request_buffer.get(), request_text.size(), callback2.callback());
-  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback2.WaitForResult();
   EXPECT_EQ(static_cast<int>(request_text.size()), rv);
 
@@ -1067,62 +1053,65 @@
 // callback, the Write() callback should not be invoked.
 // Regression test for http://crbug.com/232633
 TEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  scoped_ptr<net::StreamSocket> real_transport(new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source()));
-  // Note: |error_socket|'s ownership is handed to |transport|, but the pointer
+  TestCompletionCallback callback;
+  scoped_ptr<StreamSocket> real_transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
+  // Note: |error_socket|'s ownership is handed to |transport|, but a pointer
   // is retained in order to configure additional errors.
-  SynchronousErrorStreamSocket* error_socket = new SynchronousErrorStreamSocket(
-      real_transport.Pass());
-  FakeBlockingStreamSocket* transport = new FakeBlockingStreamSocket(
-      scoped_ptr<net::StreamSocket>(error_socket));
+  scoped_ptr<SynchronousErrorStreamSocket> error_socket(
+      new SynchronousErrorStreamSocket(real_transport.Pass()));
+  SynchronousErrorStreamSocket* raw_error_socket = error_socket.get();
+  scoped_ptr<FakeBlockingStreamSocket> transport(
+      new FakeBlockingStreamSocket(error_socket.PassAs<StreamSocket>()));
+  FakeBlockingStreamSocket* raw_transport = transport.get();
 
   int rv = callback.GetResult(transport->Connect(callback.callback()));
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
   // Disable TLS False Start to avoid handshake non-determinism.
-  net::SSLConfig ssl_config;
+  SSLConfig ssl_config;
   ssl_config.false_start_enabled = false;
 
-  net::SSLClientSocket* sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            ssl_config));
+  scoped_ptr<SSLClientSocket> sock =
+      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
+                            test_server.host_port_pair(),
+                            ssl_config);
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
 
   std::string request_text = "GET / HTTP/1.1\r\nUser-Agent: long browser name ";
   request_text.append(20 * 1024, '*');
   request_text.append("\r\n\r\n");
-  scoped_refptr<net::DrainableIOBuffer> request_buffer(
-      new net::DrainableIOBuffer(new net::StringIOBuffer(request_text),
-                                 request_text.size()));
+  scoped_refptr<DrainableIOBuffer> request_buffer(new DrainableIOBuffer(
+      new StringIOBuffer(request_text), request_text.size()));
 
   // Simulate errors being returned from the underlying Read() and Write() ...
-  error_socket->SetNextReadError(net::ERR_CONNECTION_RESET);
-  error_socket->SetNextWriteError(net::ERR_CONNECTION_RESET);
+  raw_error_socket->SetNextReadError(ERR_CONNECTION_RESET);
+  raw_error_socket->SetNextWriteError(ERR_CONNECTION_RESET);
   // ... but have those errors returned asynchronously. Because the Write() will
   // return first, this will trigger the error.
-  transport->SetNextReadShouldBlock();
-  transport->SetNextWriteShouldBlock();
+  raw_transport->SetNextReadShouldBlock();
+  raw_transport->SetNextWriteShouldBlock();
 
   // Enqueue a Read() before calling Write(), which should "hang" due to
   // the ERR_IO_PENDING caused by SetReadShouldBlock() and thus return.
-  DeleteSocketCallback read_callback(sock);
-  scoped_refptr<net::IOBuffer> read_buf(new net::IOBuffer(4096));
-  rv = sock->Read(read_buf.get(), 4096, read_callback.callback());
+  SSLClientSocket* raw_sock = sock.get();
+  DeleteSocketCallback read_callback(sock.release());
+  scoped_refptr<IOBuffer> read_buf(new IOBuffer(4096));
+  rv = raw_sock->Read(read_buf.get(), 4096, read_callback.callback());
 
   // Ensure things didn't complete synchronously, otherwise |sock| is invalid.
-  ASSERT_EQ(net::ERR_IO_PENDING, rv);
+  ASSERT_EQ(ERR_IO_PENDING, rv);
   ASSERT_FALSE(read_callback.have_result());
 
 #if !defined(USE_OPENSSL)
@@ -1142,9 +1131,9 @@
   // SSLClientSocketOpenSSL::Write() will not return until all of
   // |request_buffer| has been written to the underlying BIO (although not
   // necessarily the underlying transport).
-  rv = callback.GetResult(sock->Write(request_buffer.get(),
-                                      request_buffer->BytesRemaining(),
-                                      callback.callback()));
+  rv = callback.GetResult(raw_sock->Write(request_buffer.get(),
+                                          request_buffer->BytesRemaining(),
+                                          callback.callback()));
   ASSERT_LT(0, rv);
   request_buffer->DidConsume(rv);
 
@@ -1157,22 +1146,22 @@
   // Attempt to write the remaining data. NSS will not be able to consume the
   // application data because the internal buffers are full, while OpenSSL will
   // return that its blocked because the underlying transport is blocked.
-  rv = sock->Write(request_buffer.get(),
-                   request_buffer->BytesRemaining(),
-                   callback.callback());
-  ASSERT_EQ(net::ERR_IO_PENDING, rv);
+  rv = raw_sock->Write(request_buffer.get(),
+                       request_buffer->BytesRemaining(),
+                       callback.callback());
+  ASSERT_EQ(ERR_IO_PENDING, rv);
   ASSERT_FALSE(callback.have_result());
 
   // Now unblock Write(), which will invoke OnSendComplete and (eventually)
   // call the Read() callback, deleting the socket and thus aborting calling
   // the Write() callback.
-  transport->UnblockWrite();
+  raw_transport->UnblockWrite();
 
   rv = read_callback.WaitForResult();
 
 #if !defined(USE_OPENSSL)
   // NSS records the error exactly.
-  EXPECT_EQ(net::ERR_CONNECTION_RESET, rv);
+  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
 #else
   // OpenSSL treats any errors as a simple EOF.
   EXPECT_EQ(0, rv);
@@ -1183,50 +1172,49 @@
 }
 
 TEST_F(SSLClientSocketTest, Read_SmallChunks) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source());
+  TestCompletionCallback callback;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
   const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::IOBuffer(arraysize(request_text) - 1));
+  scoped_refptr<IOBuffer> request_buffer(
+      new IOBuffer(arraysize(request_text) - 1));
   memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
 
   rv = sock->Write(
       request_buffer.get(), arraysize(request_text) - 1, callback.callback());
-  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
   EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
 
-  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(1));
+  scoped_refptr<IOBuffer> buf(new IOBuffer(1));
   for (;;) {
     rv = sock->Read(buf.get(), 1, callback.callback());
-    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+    EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-    if (rv == net::ERR_IO_PENDING)
+    if (rv == ERR_IO_PENDING)
       rv = callback.WaitForResult();
 
     EXPECT_GE(rv, 0);
@@ -1236,34 +1224,36 @@
 }
 
 TEST_F(SSLClientSocketTest, Read_ManySmallRecords) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
+  TestCompletionCallback callback;
 
-  scoped_ptr<net::StreamSocket> real_transport(new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source()));
-  ReadBufferingStreamSocket* transport = new ReadBufferingStreamSocket(
-      real_transport.Pass());
+  scoped_ptr<StreamSocket> real_transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
+  scoped_ptr<ReadBufferingStreamSocket> transport(
+      new ReadBufferingStreamSocket(real_transport.Pass()));
+  ReadBufferingStreamSocket* raw_transport = transport.get();
   int rv = callback.GetResult(transport->Connect(callback.callback()));
-  ASSERT_EQ(net::OK, rv);
+  ASSERT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
+  scoped_ptr<SSLClientSocket> sock(
+      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
+                            test_server.host_port_pair(),
                             kDefaultSSLConfig));
 
   rv = callback.GetResult(sock->Connect(callback.callback()));
-  ASSERT_EQ(net::OK, rv);
+  ASSERT_EQ(OK, rv);
   ASSERT_TRUE(sock->IsConnected());
 
   const char request_text[] = "GET /ssl-many-small-records HTTP/1.0\r\n\r\n";
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::IOBuffer(arraysize(request_text) - 1));
+  scoped_refptr<IOBuffer> request_buffer(
+      new IOBuffer(arraysize(request_text) - 1));
   memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
 
   rv = callback.GetResult(sock->Write(
@@ -1280,117 +1270,114 @@
   // 15K was chosen because 15K is smaller than the 17K (max) read issued by
   // the SSLClientSocket implementation, and larger than the minimum amount
   // of ciphertext necessary to contain the 8K of plaintext requested below.
-  transport->SetBufferSize(15000);
+  raw_transport->SetBufferSize(15000);
 
-  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(8192));
+  scoped_refptr<IOBuffer> buffer(new IOBuffer(8192));
   rv = callback.GetResult(sock->Read(buffer.get(), 8192, callback.callback()));
   ASSERT_EQ(rv, 8192);
 }
 
 TEST_F(SSLClientSocketTest, Read_Interrupted) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source());
+  TestCompletionCallback callback;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
   const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::IOBuffer(arraysize(request_text) - 1));
+  scoped_refptr<IOBuffer> request_buffer(
+      new IOBuffer(arraysize(request_text) - 1));
   memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
 
   rv = sock->Write(
       request_buffer.get(), arraysize(request_text) - 1, callback.callback());
-  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
   EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
 
   // Do a partial read and then exit.  This test should not crash!
-  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(512));
+  scoped_refptr<IOBuffer> buf(new IOBuffer(512));
   rv = sock->Read(buf.get(), 512, callback.callback());
-  EXPECT_TRUE(rv > 0 || rv == net::ERR_IO_PENDING);
+  EXPECT_TRUE(rv > 0 || rv == ERR_IO_PENDING);
 
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
 
   EXPECT_GT(rv, 0);
 }
 
 TEST_F(SSLClientSocketTest, Read_FullLogging) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  log.SetLogLevel(net::NetLog::LOG_ALL);
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  log.SetLogLevel(NetLog::LOG_ALL);
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
 
   const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
-  scoped_refptr<net::IOBuffer> request_buffer(
-      new net::IOBuffer(arraysize(request_text) - 1));
+  scoped_refptr<IOBuffer> request_buffer(
+      new IOBuffer(arraysize(request_text) - 1));
   memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
 
   rv = sock->Write(
       request_buffer.get(), arraysize(request_text) - 1, callback.callback());
-  EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
   EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
 
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  size_t last_index = net::ExpectLogContainsSomewhereAfter(
-      entries, 5, net::NetLog::TYPE_SSL_SOCKET_BYTES_SENT,
-      net::NetLog::PHASE_NONE);
+  size_t last_index = ExpectLogContainsSomewhereAfter(
+      entries, 5, NetLog::TYPE_SSL_SOCKET_BYTES_SENT, NetLog::PHASE_NONE);
 
-  scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(4096));
+  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
   for (;;) {
     rv = sock->Read(buf.get(), 4096, callback.callback());
-    EXPECT_TRUE(rv >= 0 || rv == net::ERR_IO_PENDING);
+    EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
 
-    if (rv == net::ERR_IO_PENDING)
+    if (rv == ERR_IO_PENDING)
       rv = callback.WaitForResult();
 
     EXPECT_GE(rv, 0);
@@ -1398,61 +1385,59 @@
       break;
 
     log.GetEntries(&entries);
-    last_index = net::ExpectLogContainsSomewhereAfter(
-        entries, last_index + 1, net::NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED,
-        net::NetLog::PHASE_NONE);
+    last_index =
+        ExpectLogContainsSomewhereAfter(entries,
+                                        last_index + 1,
+                                        NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED,
+                                        NetLog::PHASE_NONE);
   }
 }
 
 // Regression test for http://crbug.com/42538
 TEST_F(SSLClientSocketTest, PrematureApplicationData) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
-  net::TestCompletionCallback callback;
+  AddressList addr;
+  TestCompletionCallback callback;
 
   static const unsigned char application_data[] = {
-    0x17, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x46, 0x03, 0x01, 0x4b,
-    0xc2, 0xf8, 0xb2, 0xc1, 0x56, 0x42, 0xb9, 0x57, 0x7f, 0xde, 0x87, 0x46,
-    0xf7, 0xa3, 0x52, 0x42, 0x21, 0xf0, 0x13, 0x1c, 0x9c, 0x83, 0x88, 0xd6,
-    0x93, 0x0c, 0xf6, 0x36, 0x30, 0x05, 0x7e, 0x20, 0xb5, 0xb5, 0x73, 0x36,
-    0x53, 0x83, 0x0a, 0xfc, 0x17, 0x63, 0xbf, 0xa0, 0xe4, 0x42, 0x90, 0x0d,
-    0x2f, 0x18, 0x6d, 0x20, 0xd8, 0x36, 0x3f, 0xfc, 0xe6, 0x01, 0xfa, 0x0f,
-    0xa5, 0x75, 0x7f, 0x09, 0x00, 0x04, 0x00, 0x16, 0x03, 0x01, 0x11, 0x57,
-    0x0b, 0x00, 0x11, 0x53, 0x00, 0x11, 0x50, 0x00, 0x06, 0x22, 0x30, 0x82,
-    0x06, 0x1e, 0x30, 0x82, 0x05, 0x06, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
-    0x0a
-  };
+      0x17, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x46, 0x03, 0x01, 0x4b,
+      0xc2, 0xf8, 0xb2, 0xc1, 0x56, 0x42, 0xb9, 0x57, 0x7f, 0xde, 0x87, 0x46,
+      0xf7, 0xa3, 0x52, 0x42, 0x21, 0xf0, 0x13, 0x1c, 0x9c, 0x83, 0x88, 0xd6,
+      0x93, 0x0c, 0xf6, 0x36, 0x30, 0x05, 0x7e, 0x20, 0xb5, 0xb5, 0x73, 0x36,
+      0x53, 0x83, 0x0a, 0xfc, 0x17, 0x63, 0xbf, 0xa0, 0xe4, 0x42, 0x90, 0x0d,
+      0x2f, 0x18, 0x6d, 0x20, 0xd8, 0x36, 0x3f, 0xfc, 0xe6, 0x01, 0xfa, 0x0f,
+      0xa5, 0x75, 0x7f, 0x09, 0x00, 0x04, 0x00, 0x16, 0x03, 0x01, 0x11, 0x57,
+      0x0b, 0x00, 0x11, 0x53, 0x00, 0x11, 0x50, 0x00, 0x06, 0x22, 0x30, 0x82,
+      0x06, 0x1e, 0x30, 0x82, 0x05, 0x06, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
+      0x0a};
 
   // All reads and writes complete synchronously (async=false).
-  net::MockRead data_reads[] = {
-    net::MockRead(net::SYNCHRONOUS,
-                  reinterpret_cast<const char*>(application_data),
-                  arraysize(application_data)),
-    net::MockRead(net::SYNCHRONOUS, net::OK),
-  };
+  MockRead data_reads[] = {
+      MockRead(SYNCHRONOUS,
+               reinterpret_cast<const char*>(application_data),
+               arraysize(application_data)),
+      MockRead(SYNCHRONOUS, OK), };
 
-  net::StaticSocketDataProvider data(data_reads, arraysize(data_reads),
-                                     NULL, 0);
+  StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
 
-  net::StreamSocket* transport =
-      new net::MockTCPClientSocket(addr, NULL, &data);
+  scoped_ptr<StreamSocket> transport(
+      new MockTCPClientSocket(addr, NULL, &data));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv);
+  EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
 }
 
 TEST_F(SSLClientSocketTest, CipherSuiteDisables) {
@@ -1460,46 +1445,41 @@
   // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml,
   // only disabling those cipher suites that the test server actually
   // implements.
-  const uint16 kCiphersToDisable[] = {
-    0x0005,  // TLS_RSA_WITH_RC4_128_SHA
+  const uint16 kCiphersToDisable[] = {0x0005,  // TLS_RSA_WITH_RC4_128_SHA
   };
 
-  net::SpawnedTestServer::SSLOptions ssl_options;
+  SpawnedTestServer::SSLOptions ssl_options;
   // Enable only RC4 on the test server.
-  ssl_options.bulk_ciphers =
-      net::SpawnedTestServer::SSLOptions::BULK_CIPHER_RC4;
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     ssl_options,
-                                     base::FilePath());
+  ssl_options.bulk_ciphers = SpawnedTestServer::SSLOptions::BULK_CIPHER_RC4;
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  net::SSLConfig ssl_config;
+  SSLConfig ssl_config;
   for (size_t i = 0; i < arraysize(kCiphersToDisable); ++i)
     ssl_config.disabled_cipher_suites.push_back(kCiphersToDisable[i]);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            ssl_config));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), ssl_config));
 
   EXPECT_FALSE(sock->IsConnected());
 
   rv = sock->Connect(callback.callback());
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
+  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
 
   // NSS has special handling that maps a handshake_failure alert received
   // immediately after a client_hello to be a mismatched cipher suite error,
@@ -1507,17 +1487,16 @@
   // Secure Transport (OS X), the handshake_failure is bubbled up without any
   // interpretation, leading to ERR_SSL_PROTOCOL_ERROR. Either way, a failure
   // indicates that no cipher suite was negotiated with the test server.
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_TRUE(rv == net::ERR_SSL_VERSION_OR_CIPHER_MISMATCH ||
-              rv == net::ERR_SSL_PROTOCOL_ERROR);
+  EXPECT_TRUE(rv == ERR_SSL_VERSION_OR_CIPHER_MISMATCH ||
+              rv == ERR_SSL_PROTOCOL_ERROR);
   // The exact ordering differs between SSLClientSocketNSS (which issues an
   // extra read) and SSLClientSocketMac (which does not). Just make sure the
   // error appears somewhere in the log.
   log.GetEntries(&entries);
-  net::ExpectLogContainsSomewhere(entries, 0,
-                                  net::NetLog::TYPE_SSL_HANDSHAKE_ERROR,
-                                  net::NetLog::PHASE_NONE);
+  ExpectLogContainsSomewhere(
+      entries, 0, NetLog::TYPE_SSL_HANDSHAKE_ERROR, NetLog::PHASE_NONE);
 
   // We cannot test sock->IsConnected(), as the NSS implementation disconnects
   // the socket when it encounters an error, whereas other implementations
@@ -1539,65 +1518,65 @@
 // Here we verify that such a simple ClientSocketHandle, not associated with any
 // client socket pool, can be destroyed safely.
 TEST_F(SSLClientSocketTest, ClientSocketHandleNotFromPool) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source());
+  TestCompletionCallback callback;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  net::ClientSocketHandle* socket_handle = new net::ClientSocketHandle();
-  socket_handle->set_socket(transport);
+  scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle());
+  socket_handle->SetSocket(transport.Pass());
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      socket_factory_->CreateSSLClientSocket(
-          socket_handle, test_server.host_port_pair(), kDefaultSSLConfig,
-          context_));
+  scoped_ptr<SSLClientSocket> sock(
+      socket_factory_->CreateSSLClientSocket(socket_handle.Pass(),
+                                             test_server.host_port_pair(),
+                                             kDefaultSSLConfig,
+                                             context_));
 
   EXPECT_FALSE(sock->IsConnected());
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 }
 
 // Verifies that SSLClientSocket::ExportKeyingMaterial return a success
 // code and different keying label results in different keying material.
 TEST_F(SSLClientSocketTest, ExportKeyingMaterial) {
-  net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                     net::SpawnedTestServer::kLocalhost,
-                                     base::FilePath());
+  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::kLocalhost,
+                                base::FilePath());
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
+  TestCompletionCallback callback;
 
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, NULL, net::NetLog::Source());
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, NULL, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
 
   rv = sock->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
 
   const int kKeyingMaterialSize = 32;
@@ -1605,23 +1584,23 @@
   const char* kKeyingContext = "";
   unsigned char client_out1[kKeyingMaterialSize];
   memset(client_out1, 0, sizeof(client_out1));
-  rv = sock->ExportKeyingMaterial(kKeyingLabel1, false, kKeyingContext,
-                                  client_out1, sizeof(client_out1));
-  EXPECT_EQ(rv, net::OK);
+  rv = sock->ExportKeyingMaterial(
+      kKeyingLabel1, false, kKeyingContext, client_out1, sizeof(client_out1));
+  EXPECT_EQ(rv, OK);
 
   const char* kKeyingLabel2 = "client-socket-test-2";
   unsigned char client_out2[kKeyingMaterialSize];
   memset(client_out2, 0, sizeof(client_out2));
-  rv = sock->ExportKeyingMaterial(kKeyingLabel2, false, kKeyingContext,
-                                  client_out2, sizeof(client_out2));
-  EXPECT_EQ(rv, net::OK);
+  rv = sock->ExportKeyingMaterial(
+      kKeyingLabel2, false, kKeyingContext, client_out2, sizeof(client_out2));
+  EXPECT_EQ(rv, OK);
   EXPECT_NE(memcmp(client_out1, client_out2, kKeyingMaterialSize), 0);
 }
 
 // Verifies that SSLClientSocket::ClearSessionCache can be called without
 // explicit NSS initialization.
 TEST(SSLClientSocket, ClearSessionCache) {
-  net::SSLClientSocket::ClearSessionCache();
+  SSLClientSocket::ClearSessionCache();
 }
 
 // This tests that SSLInfo contains a properly re-constructed certificate
@@ -1639,86 +1618,84 @@
 TEST_F(SSLClientSocketTest, VerifyReturnChainProperlyOrdered) {
   // By default, cause the CertVerifier to treat all certificates as
   // expired.
-  cert_verifier_->set_default_result(net::ERR_CERT_DATE_INVALID);
+  cert_verifier_->set_default_result(ERR_CERT_DATE_INVALID);
 
   // We will expect SSLInfo to ultimately contain this chain.
-  net::CertificateList certs = CreateCertificateListFromFile(
-      net::GetTestCertsDirectory(), "redundant-validated-chain.pem",
-      net::X509Certificate::FORMAT_AUTO);
+  CertificateList certs =
+      CreateCertificateListFromFile(GetTestCertsDirectory(),
+                                    "redundant-validated-chain.pem",
+                                    X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(3U, certs.size());
 
-  net::X509Certificate::OSCertHandles temp_intermediates;
+  X509Certificate::OSCertHandles temp_intermediates;
   temp_intermediates.push_back(certs[1]->os_cert_handle());
   temp_intermediates.push_back(certs[2]->os_cert_handle());
 
-  net::CertVerifyResult verify_result;
-  verify_result.verified_cert =
-      net::X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
-                                             temp_intermediates);
+  CertVerifyResult verify_result;
+  verify_result.verified_cert = X509Certificate::CreateFromHandle(
+      certs[0]->os_cert_handle(), temp_intermediates);
 
   // Add a rule that maps the server cert (A) to the chain of A->B->C2
   // rather than A->B->C.
-  cert_verifier_->AddResultForCert(certs[0].get(), verify_result, net::OK);
+  cert_verifier_->AddResultForCert(certs[0].get(), verify_result, OK);
 
   // Load and install the root for the validated chain.
-  scoped_refptr<net::X509Certificate> root_cert =
-    net::ImportCertFromFile(net::GetTestCertsDirectory(),
-                           "redundant-validated-chain-root.pem");
-  ASSERT_NE(static_cast<net::X509Certificate*>(NULL), root_cert);
-  net::ScopedTestRoot scoped_root(root_cert.get());
+  scoped_refptr<X509Certificate> root_cert = ImportCertFromFile(
+      GetTestCertsDirectory(), "redundant-validated-chain-root.pem");
+  ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
+  ScopedTestRoot scoped_root(root_cert.get());
 
   // Set up a test server with CERT_CHAIN_WRONG_ROOT.
-  net::SpawnedTestServer::SSLOptions ssl_options(
-      net::SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT);
-  net::SpawnedTestServer test_server(
-      net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT);
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS,
+      ssl_options,
       base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
   ASSERT_TRUE(test_server.Start());
 
-  net::AddressList addr;
+  AddressList addr;
   ASSERT_TRUE(test_server.GetAddressList(&addr));
 
-  net::TestCompletionCallback callback;
-  net::CapturingNetLog log;
-  net::StreamSocket* transport = new net::TCPClientSocket(
-      addr, &log, net::NetLog::Source());
+  TestCompletionCallback callback;
+  CapturingNetLog log;
+  scoped_ptr<StreamSocket> transport(
+      new TCPClientSocket(addr, &log, NetLog::Source()));
   int rv = transport->Connect(callback.callback());
-  if (rv == net::ERR_IO_PENDING)
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
 
-  scoped_ptr<net::SSLClientSocket> sock(
-      CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                            kDefaultSSLConfig));
+  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
   EXPECT_FALSE(sock->IsConnected());
   rv = sock->Connect(callback.callback());
 
-  net::CapturingNetLog::CapturedEntryList entries;
+  CapturingNetLog::CapturedEntryList entries;
   log.GetEntries(&entries);
-  EXPECT_TRUE(net::LogContainsBeginEvent(
-      entries, 5, net::NetLog::TYPE_SSL_CONNECT));
-  if (rv == net::ERR_IO_PENDING)
+  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
+  if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
 
-  EXPECT_EQ(net::OK, rv);
+  EXPECT_EQ(OK, rv);
   EXPECT_TRUE(sock->IsConnected());
   log.GetEntries(&entries);
   EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
 
-  net::SSLInfo ssl_info;
+  SSLInfo ssl_info;
   sock->GetSSLInfo(&ssl_info);
 
   // Verify that SSLInfo contains the corrected re-constructed chain A -> B
   // -> C2.
-  const net::X509Certificate::OSCertHandles& intermediates =
+  const X509Certificate::OSCertHandles& intermediates =
       ssl_info.cert->GetIntermediateCertificates();
   ASSERT_EQ(2U, intermediates.size());
-  EXPECT_TRUE(net::X509Certificate::IsSameOSCert(
-      ssl_info.cert->os_cert_handle(), certs[0]->os_cert_handle()));
-  EXPECT_TRUE(net::X509Certificate::IsSameOSCert(
-      intermediates[0], certs[1]->os_cert_handle()));
-  EXPECT_TRUE(net::X509Certificate::IsSameOSCert(
-      intermediates[1], certs[2]->os_cert_handle()));
+  EXPECT_TRUE(X509Certificate::IsSameOSCert(ssl_info.cert->os_cert_handle(),
+                                            certs[0]->os_cert_handle()));
+  EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[0],
+                                            certs[1]->os_cert_handle()));
+  EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[1],
+                                            certs[2]->os_cert_handle()));
 
   sock->Disconnect();
   EXPECT_FALSE(sock->IsConnected());
@@ -1729,37 +1706,34 @@
  protected:
   // Creates a test server with the given SSLOptions, connects to it and returns
   // the SSLCertRequestInfo reported by the socket.
-  scoped_refptr<net::SSLCertRequestInfo> GetCertRequest(
-      net::SpawnedTestServer::SSLOptions ssl_options) {
-    net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTPS,
-                                       ssl_options,
-                                       base::FilePath());
+  scoped_refptr<SSLCertRequestInfo> GetCertRequest(
+      SpawnedTestServer::SSLOptions ssl_options) {
+    SpawnedTestServer test_server(
+        SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
     if (!test_server.Start())
       return NULL;
 
-    net::AddressList addr;
+    AddressList addr;
     if (!test_server.GetAddressList(&addr))
       return NULL;
 
-    net::TestCompletionCallback callback;
-    net::CapturingNetLog log;
-    net::StreamSocket* transport = new net::TCPClientSocket(
-        addr, &log, net::NetLog::Source());
+    TestCompletionCallback callback;
+    CapturingNetLog log;
+    scoped_ptr<StreamSocket> transport(
+        new TCPClientSocket(addr, &log, NetLog::Source()));
     int rv = transport->Connect(callback.callback());
-    if (rv == net::ERR_IO_PENDING)
+    if (rv == ERR_IO_PENDING)
       rv = callback.WaitForResult();
-    EXPECT_EQ(net::OK, rv);
+    EXPECT_EQ(OK, rv);
 
-    scoped_ptr<net::SSLClientSocket> sock(
-        CreateSSLClientSocket(transport, test_server.host_port_pair(),
-                              kDefaultSSLConfig));
+    scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+        transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
     EXPECT_FALSE(sock->IsConnected());
 
     rv = sock->Connect(callback.callback());
-    if (rv == net::ERR_IO_PENDING)
+    if (rv == ERR_IO_PENDING)
       rv = callback.WaitForResult();
-    scoped_refptr<net::SSLCertRequestInfo> request_info =
-        new net::SSLCertRequestInfo();
+    scoped_refptr<SSLCertRequestInfo> request_info = new SSLCertRequestInfo();
     sock->GetSSLCertRequestInfo(request_info.get());
     sock->Disconnect();
     EXPECT_FALSE(sock->IsConnected());
@@ -1769,10 +1743,9 @@
 };
 
 TEST_F(SSLClientSocketCertRequestInfoTest, NoAuthorities) {
-  net::SpawnedTestServer::SSLOptions ssl_options;
+  SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
-  scoped_refptr<net::SSLCertRequestInfo> request_info =
-      GetCertRequest(ssl_options);
+  scoped_refptr<SSLCertRequestInfo> request_info = GetCertRequest(ssl_options);
   ASSERT_TRUE(request_info.get());
   EXPECT_EQ(0u, request_info->cert_authorities.size());
 }
@@ -1781,39 +1754,36 @@
   const base::FilePath::CharType kThawteFile[] =
       FILE_PATH_LITERAL("thawte.single.pem");
   const unsigned char kThawteDN[] = {
-    0x30, 0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-    0x02, 0x5a, 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
-    0x13, 0x1c, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e,
-    0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79,
-    0x29, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03,
-    0x55, 0x04, 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
-    0x53, 0x47, 0x43, 0x20, 0x43, 0x41
-  };
+      0x30, 0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+      0x02, 0x5a, 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
+      0x13, 0x1c, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e,
+      0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79,
+      0x29, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03,
+      0x55, 0x04, 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
+      0x53, 0x47, 0x43, 0x20, 0x43, 0x41};
   const size_t kThawteLen = sizeof(kThawteDN);
 
   const base::FilePath::CharType kDiginotarFile[] =
       FILE_PATH_LITERAL("diginotar_root_ca.pem");
   const unsigned char kDiginotarDN[] = {
-    0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-    0x02, 0x4e, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
-    0x13, 0x09, 0x44, 0x69, 0x67, 0x69, 0x4e, 0x6f, 0x74, 0x61, 0x72, 0x31,
-    0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x44, 0x69,
-    0x67, 0x69, 0x4e, 0x6f, 0x74, 0x61, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74,
-    0x20, 0x43, 0x41, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48,
-    0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x69, 0x6e, 0x66, 0x6f,
-    0x40, 0x64, 0x69, 0x67, 0x69, 0x6e, 0x6f, 0x74, 0x61, 0x72, 0x2e, 0x6e,
-    0x6c
-  };
+      0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+      0x02, 0x4e, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
+      0x13, 0x09, 0x44, 0x69, 0x67, 0x69, 0x4e, 0x6f, 0x74, 0x61, 0x72, 0x31,
+      0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x44, 0x69,
+      0x67, 0x69, 0x4e, 0x6f, 0x74, 0x61, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74,
+      0x20, 0x43, 0x41, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48,
+      0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x69, 0x6e, 0x66, 0x6f,
+      0x40, 0x64, 0x69, 0x67, 0x69, 0x6e, 0x6f, 0x74, 0x61, 0x72, 0x2e, 0x6e,
+      0x6c};
   const size_t kDiginotarLen = sizeof(kDiginotarDN);
 
-  net::SpawnedTestServer::SSLOptions ssl_options;
+  SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.request_client_certificate = true;
   ssl_options.client_authorities.push_back(
-      net::GetTestClientCertsDirectory().Append(kThawteFile));
+      GetTestClientCertsDirectory().Append(kThawteFile));
   ssl_options.client_authorities.push_back(
-      net::GetTestClientCertsDirectory().Append(kDiginotarFile));
-  scoped_refptr<net::SSLCertRequestInfo> request_info =
-      GetCertRequest(ssl_options);
+      GetTestClientCertsDirectory().Append(kDiginotarFile));
+  scoped_refptr<SSLCertRequestInfo> request_info = GetCertRequest(ssl_options);
   ASSERT_TRUE(request_info.get());
   ASSERT_EQ(2u, request_info->cert_authorities.size());
   EXPECT_EQ(std::string(reinterpret_cast<const char*>(kThawteDN), kThawteLen),
@@ -1822,3 +1792,7 @@
       std::string(reinterpret_cast<const char*>(kDiginotarDN), kDiginotarLen),
       request_info->cert_authorities[1]);
 }
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/socket/ssl_server_socket.h b/net/socket/ssl_server_socket.h
index 52d53cb..8b607bf 100644
--- a/net/socket/ssl_server_socket.h
+++ b/net/socket/ssl_server_socket.h
@@ -6,6 +6,7 @@
 #define NET_SOCKET_SSL_SERVER_SOCKET_H_
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_export.h"
 #include "net/socket/ssl_socket.h"
@@ -52,8 +53,8 @@
 //
 // The caller starts the SSL server handshake by calling Handshake on the
 // returned socket.
-NET_EXPORT SSLServerSocket* CreateSSLServerSocket(
-    StreamSocket* socket,
+NET_EXPORT scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
+    scoped_ptr<StreamSocket> socket,
     X509Certificate* certificate,
     crypto::RSAPrivateKey* key,
     const SSLConfig& ssl_config);
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
index c2681d3..7e5d701 100644
--- a/net/socket/ssl_server_socket_nss.cc
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -78,19 +78,20 @@
   g_nss_ssl_server_init_singleton.Get();
 }
 
-SSLServerSocket* CreateSSLServerSocket(
-    StreamSocket* socket,
+scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
+    scoped_ptr<StreamSocket> socket,
     X509Certificate* cert,
     crypto::RSAPrivateKey* key,
     const SSLConfig& ssl_config) {
   DCHECK(g_nss_server_sockets_init) << "EnableSSLServerSockets() has not been"
                                     << "called yet!";
 
-  return new SSLServerSocketNSS(socket, cert, key, ssl_config);
+  return scoped_ptr<SSLServerSocket>(
+      new SSLServerSocketNSS(socket.Pass(), cert, key, ssl_config));
 }
 
 SSLServerSocketNSS::SSLServerSocketNSS(
-    StreamSocket* transport_socket,
+    scoped_ptr<StreamSocket> transport_socket,
     scoped_refptr<X509Certificate> cert,
     crypto::RSAPrivateKey* key,
     const SSLConfig& ssl_config)
@@ -100,7 +101,7 @@
       user_write_buf_len_(0),
       nss_fd_(NULL),
       nss_bufs_(NULL),
-      transport_socket_(transport_socket),
+      transport_socket_(transport_socket.Pass()),
       ssl_config_(ssl_config),
       cert_(cert),
       next_handshake_state_(STATE_NONE),
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h
index 17a1fc3..8bbb0e3 100644
--- a/net/socket/ssl_server_socket_nss.h
+++ b/net/socket/ssl_server_socket_nss.h
@@ -24,7 +24,7 @@
  public:
   // See comments on CreateSSLServerSocket for details of how these
   // parameters are used.
-  SSLServerSocketNSS(StreamSocket* socket,
+  SSLServerSocketNSS(scoped_ptr<StreamSocket> socket,
                      scoped_refptr<X509Certificate> certificate,
                      crypto::RSAPrivateKey* key,
                      const SSLConfig& ssl_config);
diff --git a/net/socket/ssl_server_socket_openssl.cc b/net/socket/ssl_server_socket_openssl.cc
index e0cf8bc..c327f2c 100644
--- a/net/socket/ssl_server_socket_openssl.cc
+++ b/net/socket/ssl_server_socket_openssl.cc
@@ -16,13 +16,13 @@
   NOTIMPLEMENTED();
 }
 
-SSLServerSocket* CreateSSLServerSocket(StreamSocket* socket,
-                                       X509Certificate* certificate,
-                                       crypto::RSAPrivateKey* key,
-                                       const SSLConfig& ssl_config) {
+scoped_ptr<SSLServerSocket> CreateSSLServerSocket(
+    scoped_ptr<StreamSocket> socket,
+    X509Certificate* certificate,
+    crypto::RSAPrivateKey* key,
+    const SSLConfig& ssl_config) {
   NOTIMPLEMENTED();
-  delete socket;
-  return NULL;
+  return scoped_ptr<SSLServerSocket>();
 }
 
 }  // namespace net
diff --git a/net/socket/ssl_server_socket_unittest.cc b/net/socket/ssl_server_socket_unittest.cc
index f931e2c..64c8549 100644
--- a/net/socket/ssl_server_socket_unittest.cc
+++ b/net/socket/ssl_server_socket_unittest.cc
@@ -304,8 +304,11 @@
 
  protected:
   void Initialize() {
-    FakeSocket* fake_client_socket = new FakeSocket(&channel_1_, &channel_2_);
-    FakeSocket* fake_server_socket = new FakeSocket(&channel_2_, &channel_1_);
+    scoped_ptr<ClientSocketHandle> client_connection(new ClientSocketHandle);
+    client_connection->SetSocket(
+        scoped_ptr<StreamSocket>(new FakeSocket(&channel_1_, &channel_2_)));
+    scoped_ptr<StreamSocket> server_socket(
+        new FakeSocket(&channel_2_, &channel_1_));
 
     base::FilePath certs_dir(GetTestCertsDirectory());
 
@@ -344,11 +347,12 @@
     net::SSLClientSocketContext context;
     context.cert_verifier = cert_verifier_.get();
     context.transport_security_state = transport_security_state_.get();
-    client_socket_.reset(
+    client_socket_ =
         socket_factory_->CreateSSLClientSocket(
-            fake_client_socket, host_and_pair, ssl_config, context));
-    server_socket_.reset(net::CreateSSLServerSocket(
-        fake_server_socket, cert.get(), private_key.get(), net::SSLConfig()));
+            client_connection.Pass(), host_and_pair, ssl_config, context);
+    server_socket_ = net::CreateSSLServerSocket(
+        server_socket.Pass(),
+        cert.get(), private_key.get(), net::SSLConfig());
   }
 
   FakeDataChannel channel_1_;
diff --git a/net/socket/transport_client_socket_pool.cc b/net/socket/transport_client_socket_pool.cc
index 8255e98..88c7e23 100644
--- a/net/socket/transport_client_socket_pool.cc
+++ b/net/socket/transport_client_socket_pool.cc
@@ -48,25 +48,18 @@
 
 TransportSocketParams::TransportSocketParams(
     const HostPortPair& host_port_pair,
-    RequestPriority priority,
     bool disable_resolver_cache,
     bool ignore_limits,
     const OnHostResolutionCallback& host_resolution_callback)
     : destination_(host_port_pair),
       ignore_limits_(ignore_limits),
       host_resolution_callback_(host_resolution_callback) {
-  Initialize(priority, disable_resolver_cache);
-}
-
-TransportSocketParams::~TransportSocketParams() {}
-
-void TransportSocketParams::Initialize(RequestPriority priority,
-                                       bool disable_resolver_cache) {
-  destination_.set_priority(priority);
   if (disable_resolver_cache)
     destination_.set_allow_cached_response(false);
 }
 
+TransportSocketParams::~TransportSocketParams() {}
+
 // TransportConnectJobs will time out after this many seconds.  Note this is
 // the total time, including both host resolution and TCP connect() times.
 //
@@ -80,13 +73,14 @@
 
 TransportConnectJob::TransportConnectJob(
     const std::string& group_name,
+    RequestPriority priority,
     const scoped_refptr<TransportSocketParams>& params,
     base::TimeDelta timeout_duration,
     ClientSocketFactory* client_socket_factory,
     HostResolver* host_resolver,
     Delegate* delegate,
     NetLog* net_log)
-    : ConnectJob(group_name, timeout_duration, delegate,
+    : ConnectJob(group_name, timeout_duration, priority, delegate,
                  BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
       params_(params),
       client_socket_factory_(client_socket_factory),
@@ -166,7 +160,9 @@
   connect_timing_.dns_start = base::TimeTicks::Now();
 
   return resolver_.Resolve(
-      params_->destination(), &addresses_,
+      params_->destination(),
+      priority(),
+      &addresses_,
       base::Bind(&TransportConnectJob::OnIOComplete, base::Unretained(this)),
       net_log());
 }
@@ -190,8 +186,8 @@
 
 int TransportConnectJob::DoTransportConnect() {
   next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
-  transport_socket_.reset(client_socket_factory_->CreateTransportClientSocket(
-        addresses_, net_log().net_log(), net_log().source()));
+  transport_socket_ = client_socket_factory_->CreateTransportClientSocket(
+        addresses_, net_log().net_log(), net_log().source());
   int rv = transport_socket_->Connect(
       base::Bind(&TransportConnectJob::OnIOComplete, base::Unretained(this)));
   if (rv == ERR_IO_PENDING &&
@@ -246,7 +242,7 @@
                                    100);
       }
     }
-    set_socket(transport_socket_.release());
+    SetSocket(transport_socket_.Pass());
     fallback_timer_.Stop();
   } else {
     // Be a bit paranoid and kill off the fallback members to prevent reuse.
@@ -270,9 +266,9 @@
 
   fallback_addresses_.reset(new AddressList(addresses_));
   MakeAddressListStartWithIPv4(fallback_addresses_.get());
-  fallback_transport_socket_.reset(
+  fallback_transport_socket_ =
       client_socket_factory_->CreateTransportClientSocket(
-          *fallback_addresses_, net_log().net_log(), net_log().source()));
+          *fallback_addresses_, net_log().net_log(), net_log().source());
   fallback_connect_start_time_ = base::TimeTicks::Now();
   int rv = fallback_transport_socket_->Connect(
       base::Bind(
@@ -317,7 +313,7 @@
         base::TimeDelta::FromMilliseconds(1),
         base::TimeDelta::FromMinutes(10),
         100);
-    set_socket(fallback_transport_socket_.release());
+    SetSocket(fallback_transport_socket_.Pass());
     next_state_ = STATE_NONE;
     transport_socket_.reset();
   } else {
@@ -333,18 +329,20 @@
   return DoLoop(OK);
 }
 
-ConnectJob*
+scoped_ptr<ConnectJob>
     TransportClientSocketPool::TransportConnectJobFactory::NewConnectJob(
     const std::string& group_name,
     const PoolBase::Request& request,
     ConnectJob::Delegate* delegate) const {
-  return new TransportConnectJob(group_name,
-                                 request.params(),
-                                 ConnectionTimeout(),
-                                 client_socket_factory_,
-                                 host_resolver_,
-                                 delegate,
-                                 net_log_);
+  return scoped_ptr<ConnectJob>(
+      new TransportConnectJob(group_name,
+                              request.priority(),
+                              request.params(),
+                              ConnectionTimeout(),
+                              client_socket_factory_,
+                              host_resolver_,
+                              delegate,
+                              net_log_));
 }
 
 base::TimeDelta
@@ -360,11 +358,11 @@
     HostResolver* host_resolver,
     ClientSocketFactory* client_socket_factory,
     NetLog* net_log)
-    : base_(max_sockets, max_sockets_per_group, histograms,
+    : base_(NULL, max_sockets, max_sockets_per_group, histograms,
             ClientSocketPool::unused_idle_socket_timeout(),
             ClientSocketPool::used_idle_socket_timeout(),
             new TransportConnectJobFactory(client_socket_factory,
-                                     host_resolver, net_log)) {
+                                           host_resolver, net_log)) {
   base_.EnableConnectBackupJobs();
 }
 
@@ -419,19 +417,15 @@
 
 void TransportClientSocketPool::ReleaseSocket(
     const std::string& group_name,
-    StreamSocket* socket,
+    scoped_ptr<StreamSocket> socket,
     int id) {
-  base_.ReleaseSocket(group_name, socket, id);
+  base_.ReleaseSocket(group_name, socket.Pass(), id);
 }
 
 void TransportClientSocketPool::FlushWithError(int error) {
   base_.FlushWithError(error);
 }
 
-bool TransportClientSocketPool::IsStalled() const {
-  return base_.IsStalled();
-}
-
 void TransportClientSocketPool::CloseIdleSockets() {
   base_.CloseIdleSockets();
 }
@@ -450,14 +444,6 @@
   return base_.GetLoadState(group_name, handle);
 }
 
-void TransportClientSocketPool::AddLayeredPool(LayeredPool* layered_pool) {
-  base_.AddLayeredPool(layered_pool);
-}
-
-void TransportClientSocketPool::RemoveLayeredPool(LayeredPool* layered_pool) {
-  base_.RemoveLayeredPool(layered_pool);
-}
-
 base::DictionaryValue* TransportClientSocketPool::GetInfoAsValue(
     const std::string& name,
     const std::string& type,
@@ -473,4 +459,18 @@
   return base_.histograms();
 }
 
+bool TransportClientSocketPool::IsStalled() const {
+  return base_.IsStalled();
+}
+
+void TransportClientSocketPool::AddHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  base_.AddHigherLayeredPool(higher_pool);
+}
+
+void TransportClientSocketPool::RemoveHigherLayeredPool(
+    HigherLayeredPool* higher_pool) {
+  base_.RemoveHigherLayeredPool(higher_pool);
+}
+
 }  // namespace net
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index bb53b3d..16e421a 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -34,7 +34,6 @@
   // connection will be aborted with that value.
   TransportSocketParams(
       const HostPortPair& host_port_pair,
-      RequestPriority priority,
       bool disable_resolver_cache,
       bool ignore_limits,
       const OnHostResolutionCallback& host_resolution_callback);
@@ -49,8 +48,6 @@
   friend class base::RefCounted<TransportSocketParams>;
   ~TransportSocketParams();
 
-  void Initialize(RequestPriority priority, bool disable_resolver_cache);
-
   HostResolver::RequestInfo destination_;
   bool ignore_limits_;
   const OnHostResolutionCallback host_resolution_callback_;
@@ -69,6 +66,7 @@
 class NET_EXPORT_PRIVATE TransportConnectJob : public ConnectJob {
  public:
   TransportConnectJob(const std::string& group_name,
+                      RequestPriority priority,
                       const scoped_refptr<TransportSocketParams>& params,
                       base::TimeDelta timeout_duration,
                       ClientSocketFactory* client_socket_factory,
@@ -132,6 +130,8 @@
 
 class NET_EXPORT_PRIVATE TransportClientSocketPool : public ClientSocketPool {
  public:
+  typedef TransportSocketParams SocketParams;
+
   TransportClientSocketPool(
       int max_sockets,
       int max_sockets_per_group,
@@ -156,10 +156,9 @@
   virtual void CancelRequest(const std::string& group_name,
                              ClientSocketHandle* handle) OVERRIDE;
   virtual void ReleaseSocket(const std::string& group_name,
-                             StreamSocket* socket,
+                             scoped_ptr<StreamSocket> socket,
                              int id) OVERRIDE;
   virtual void FlushWithError(int error) OVERRIDE;
-  virtual bool IsStalled() const OVERRIDE;
   virtual void CloseIdleSockets() OVERRIDE;
   virtual int IdleSocketCount() const OVERRIDE;
   virtual int IdleSocketCountInGroup(
@@ -167,8 +166,6 @@
   virtual LoadState GetLoadState(
       const std::string& group_name,
       const ClientSocketHandle* handle) const OVERRIDE;
-  virtual void AddLayeredPool(LayeredPool* layered_pool) OVERRIDE;
-  virtual void RemoveLayeredPool(LayeredPool* layered_pool) OVERRIDE;
   virtual base::DictionaryValue* GetInfoAsValue(
       const std::string& name,
       const std::string& type,
@@ -176,6 +173,11 @@
   virtual base::TimeDelta ConnectionTimeout() const OVERRIDE;
   virtual ClientSocketPoolHistograms* histograms() const OVERRIDE;
 
+  // HigherLayeredPool implementation.
+  virtual bool IsStalled() const OVERRIDE;
+  virtual void AddHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+  virtual void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) OVERRIDE;
+
  private:
   typedef ClientSocketPoolBase<TransportSocketParams> PoolBase;
 
@@ -193,7 +195,7 @@
 
     // ClientSocketPoolBase::ConnectJobFactory methods.
 
-    virtual ConnectJob* NewConnectJob(
+    virtual scoped_ptr<ConnectJob> NewConnectJob(
         const std::string& group_name,
         const PoolBase::Request& request,
         ConnectJob::Delegate* delegate) const OVERRIDE;
@@ -213,9 +215,6 @@
   DISALLOW_COPY_AND_ASSIGN(TransportClientSocketPool);
 };
 
-REGISTER_SOCKET_PARAMS_FOR_POOL(TransportClientSocketPool,
-                                TransportSocketParams);
-
 }  // namespace net
 
 #endif  // NET_SOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index dfa1151..a984ea3 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -23,6 +23,7 @@
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/client_socket_pool_histograms.h"
 #include "net/socket/socket_test_util.h"
+#include "net/socket/ssl_client_socket.h"
 #include "net/socket/stream_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -340,16 +341,16 @@
         delay_(base::TimeDelta::FromMilliseconds(
             ClientSocketPool::kMaxConnectRetryIntervalMs)) {}
 
-  virtual DatagramClientSocket* CreateDatagramClientSocket(
+  virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
       DatagramSocket::BindType bind_type,
       const RandIntCallback& rand_int_cb,
       NetLog* net_log,
       const NetLog::Source& source) OVERRIDE {
     NOTREACHED();
-    return NULL;
+    return scoped_ptr<DatagramClientSocket>();
   }
 
-  virtual StreamSocket* CreateTransportClientSocket(
+  virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
       const AddressList& addresses,
       NetLog* /* net_log */,
       const NetLog::Source& /* source */) OVERRIDE {
@@ -363,34 +364,41 @@
 
     switch (type) {
       case MOCK_CLIENT_SOCKET:
-        return new MockClientSocket(addresses, net_log_);
+        return scoped_ptr<StreamSocket>(
+            new MockClientSocket(addresses, net_log_));
       case MOCK_FAILING_CLIENT_SOCKET:
-        return new MockFailingClientSocket(addresses, net_log_);
+        return scoped_ptr<StreamSocket>(
+            new MockFailingClientSocket(addresses, net_log_));
       case MOCK_PENDING_CLIENT_SOCKET:
-        return new MockPendingClientSocket(
-            addresses, true, false, base::TimeDelta(), net_log_);
+        return scoped_ptr<StreamSocket>(
+            new MockPendingClientSocket(
+                addresses, true, false, base::TimeDelta(), net_log_));
       case MOCK_PENDING_FAILING_CLIENT_SOCKET:
-        return new MockPendingClientSocket(
-            addresses, false, false, base::TimeDelta(), net_log_);
+        return scoped_ptr<StreamSocket>(
+            new MockPendingClientSocket(
+                addresses, false, false, base::TimeDelta(), net_log_));
       case MOCK_DELAYED_CLIENT_SOCKET:
-        return new MockPendingClientSocket(
-            addresses, true, false, delay_, net_log_);
+        return scoped_ptr<StreamSocket>(
+            new MockPendingClientSocket(
+                addresses, true, false, delay_, net_log_));
       case MOCK_STALLED_CLIENT_SOCKET:
-        return new MockPendingClientSocket(
-            addresses, true, true, base::TimeDelta(), net_log_);
+        return scoped_ptr<StreamSocket>(
+            new MockPendingClientSocket(
+                addresses, true, true, base::TimeDelta(), net_log_));
       default:
         NOTREACHED();
-        return new MockClientSocket(addresses, net_log_);
+        return scoped_ptr<StreamSocket>(
+            new MockClientSocket(addresses, net_log_));
     }
   }
 
-  virtual SSLClientSocket* CreateSSLClientSocket(
-      ClientSocketHandle* transport_socket,
+  virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+      scoped_ptr<ClientSocketHandle> transport_socket,
       const HostPortPair& host_and_port,
       const SSLConfig& ssl_config,
       const SSLClientSocketContext& context) OVERRIDE {
     NOTIMPLEMENTED();
-    return NULL;
+    return scoped_ptr<SSLClientSocket>();
   }
 
   virtual void ClearSSLSessionCache() OVERRIDE {
@@ -431,11 +439,7 @@
             ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(true)),
         params_(
             new TransportSocketParams(HostPortPair("www.google.com", 80),
-                                      kDefaultPriority, false, false,
-                                      OnHostResolutionCallback())),
-        low_params_(
-            new TransportSocketParams(HostPortPair("www.google.com", 80),
-                                      LOW, false, false,
+                                      false, false,
                                       OnHostResolutionCallback())),
         histograms_(new ClientSocketPoolHistograms("TCPUnitTest")),
         host_resolver_(new MockHostResolver),
@@ -455,7 +459,7 @@
 
   int StartRequest(const std::string& group_name, RequestPriority priority) {
     scoped_refptr<TransportSocketParams> params(new TransportSocketParams(
-        HostPortPair("www.google.com", 80), MEDIUM, false, false,
+        HostPortPair("www.google.com", 80), false, false,
         OnHostResolutionCallback()));
     return test_base_.StartRequestUsingPool(
         &pool_, group_name, priority, params);
@@ -479,7 +483,6 @@
   bool connect_backup_jobs_enabled_;
   CapturingNetLog net_log_;
   scoped_refptr<TransportSocketParams> params_;
-  scoped_refptr<TransportSocketParams> low_params_;
   scoped_ptr<ClientSocketPoolHistograms> histograms_;
   scoped_ptr<MockHostResolver> host_resolver_;
   MockClientSocketFactory client_socket_factory_;
@@ -561,7 +564,7 @@
 TEST_F(TransportClientSocketPoolTest, Basic) {
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool_,
+  int rv = handle.Init("a", params_, LOW, callback.callback(), &pool_,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -573,13 +576,27 @@
   TestLoadTimingInfoConnectedNotReused(handle);
 }
 
+// Make sure that TransportConnectJob passes on its priority to its
+// HostResolver request on Init.
+TEST_F(TransportClientSocketPoolTest, SetResolvePriorityOnInit) {
+  for (int i = MINIMUM_PRIORITY; i < NUM_PRIORITIES; ++i) {
+    RequestPriority priority = static_cast<RequestPriority>(i);
+    TestCompletionCallback callback;
+    ClientSocketHandle handle;
+    EXPECT_EQ(ERR_IO_PENDING,
+              handle.Init("a", params_, priority, callback.callback(), &pool_,
+                          BoundNetLog()));
+    EXPECT_EQ(priority, host_resolver_->last_request_priority());
+  }
+}
+
 TEST_F(TransportClientSocketPoolTest, InitHostResolutionFailure) {
   host_resolver_->rules()->AddSimulatedFailure("unresolvable.host.name");
   TestCompletionCallback callback;
   ClientSocketHandle handle;
   HostPortPair host_port_pair("unresolvable.host.name", 80);
   scoped_refptr<TransportSocketParams> dest(new TransportSocketParams(
-      host_port_pair, kDefaultPriority, false, false,
+      host_port_pair, false, false,
       OnHostResolutionCallback()));
   EXPECT_EQ(ERR_IO_PENDING,
             handle.Init("a", dest, kDefaultPriority, callback.callback(),
@@ -854,7 +871,7 @@
       }
       within_callback_ = true;
       scoped_refptr<TransportSocketParams> dest(new TransportSocketParams(
-          HostPortPair("www.google.com", 80), LOWEST, false, false,
+          HostPortPair("www.google.com", 80), false, false,
           OnHostResolutionCallback()));
       int rv = handle_->Init("a", dest, LOWEST, callback(), pool_,
                              BoundNetLog());
@@ -874,7 +891,7 @@
   ClientSocketHandle handle;
   RequestSocketCallback callback(&handle, &pool_);
   scoped_refptr<TransportSocketParams> dest(new TransportSocketParams(
-      HostPortPair("www.google.com", 80), LOWEST, false, false,
+      HostPortPair("www.google.com", 80), false, false,
       OnHostResolutionCallback()));
   int rv = handle.Init("a", dest, LOWEST, callback.callback(), &pool_,
                        BoundNetLog());
@@ -939,7 +956,7 @@
 TEST_F(TransportClientSocketPoolTest, IdleSocketLoadTiming) {
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool_,
+  int rv = handle.Init("a", params_, LOW, callback.callback(), &pool_,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -957,7 +974,7 @@
   // Now we should have 1 idle socket.
   EXPECT_EQ(1, pool_.IdleSocketCount());
 
-  rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool_,
+  rv = handle.Init("a", params_, LOW, callback.callback(), &pool_,
                    BoundNetLog());
   EXPECT_EQ(OK, rv);
   EXPECT_EQ(0, pool_.IdleSocketCount());
@@ -967,7 +984,7 @@
 TEST_F(TransportClientSocketPoolTest, ResetIdleSocketsOnIPAddressChange) {
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool_,
+  int rv = handle.Init("a", params_, LOW, callback.callback(), &pool_,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -1023,7 +1040,7 @@
 
     TestCompletionCallback callback;
     ClientSocketHandle handle;
-    int rv = handle.Init("b", low_params_, LOW, callback.callback(), &pool_,
+    int rv = handle.Init("b", params_, LOW, callback.callback(), &pool_,
                          BoundNetLog());
     EXPECT_EQ(ERR_IO_PENDING, rv);
     EXPECT_FALSE(handle.is_initialized());
@@ -1065,7 +1082,7 @@
 
     TestCompletionCallback callback;
     ClientSocketHandle handle;
-    int rv = handle.Init("c", low_params_, LOW, callback.callback(), &pool_,
+    int rv = handle.Init("c", params_, LOW, callback.callback(), &pool_,
                          BoundNetLog());
     EXPECT_EQ(ERR_IO_PENDING, rv);
     EXPECT_FALSE(handle.is_initialized());
@@ -1111,7 +1128,7 @@
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("b", low_params_, LOW, callback.callback(), &pool_,
+  int rv = handle.Init("b", params_, LOW, callback.callback(), &pool_,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -1159,7 +1176,7 @@
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("b", low_params_, LOW, callback.callback(), &pool_,
+  int rv = handle.Init("b", params_, LOW, callback.callback(), &pool_,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -1215,7 +1232,7 @@
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool,
+  int rv = handle.Init("a", params_, LOW, callback.callback(), &pool,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -1260,7 +1277,7 @@
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool,
+  int rv = handle.Init("a", params_, LOW, callback.callback(), &pool,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -1294,7 +1311,7 @@
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool,
+  int rv = handle.Init("a", params_, LOW, callback.callback(), &pool,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
@@ -1327,7 +1344,7 @@
 
   TestCompletionCallback callback;
   ClientSocketHandle handle;
-  int rv = handle.Init("a", low_params_, LOW, callback.callback(), &pool,
+  int rv = handle.Init("a", params_, LOW, callback.callback(), &pool,
                        BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle.is_initialized());
diff --git a/net/socket/transport_client_socket_unittest.cc b/net/socket/transport_client_socket_unittest.cc
index 2f75e74..9282c20 100644
--- a/net/socket/transport_client_socket_unittest.cc
+++ b/net/socket/transport_client_socket_unittest.cc
@@ -125,15 +125,15 @@
   scoped_ptr<HostResolver> resolver(new MockHostResolver());
   HostResolver::RequestInfo info(HostPortPair("localhost", listen_port_));
   TestCompletionCallback callback;
-  int rv = resolver->Resolve(info, &addr, callback.callback(), NULL,
-                             BoundNetLog());
+  int rv = resolver->Resolve(
+      info, DEFAULT_PRIORITY, &addr, callback.callback(), NULL, BoundNetLog());
   CHECK_EQ(ERR_IO_PENDING, rv);
   rv = callback.WaitForResult();
   CHECK_EQ(rv, OK);
-  sock_.reset(
+  sock_ =
       socket_factory_->CreateTransportClientSocket(addr,
                                                    &net_log_,
-                                                   NetLog::Source()));
+                                                   NetLog::Source());
 }
 
 int TransportClientSocketTest::DrainClientSocket(
diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc
index dca994c..699c820 100644
--- a/net/socket_stream/socket_stream.cc
+++ b/net/socket_stream/socket_stream.cc
@@ -33,6 +33,7 @@
 #include "net/http/http_transaction_factory.h"
 #include "net/http/http_util.h"
 #include "net/socket/client_socket_factory.h"
+#include "net/socket/client_socket_handle.h"
 #include "net/socket/socks5_client_socket.h"
 #include "net/socket/socks_client_socket.h"
 #include "net/socket/ssl_client_socket.h"
@@ -96,6 +97,7 @@
       proxy_mode_(kDirectConnection),
       proxy_url_(url),
       pac_request_(NULL),
+      connection_(new ClientSocketHandle),
       privacy_mode_(kPrivacyModeDisabled),
       // Unretained() is required; without it, Bind() creates a circular
       // dependency and the SocketStream object will not be freed.
@@ -205,8 +207,10 @@
       << "The current base::MessageLoop must be TYPE_IO";
   DCHECK_GT(len, 0);
 
-  if (!socket_.get() || !socket_->IsConnected() || next_state_ == STATE_NONE)
+  if (!connection_->socket() ||
+      !connection_->socket()->IsConnected() || next_state_ == STATE_NONE) {
     return false;
+  }
 
   int total_buffered_bytes = len;
   if (current_write_buf_.get()) {
@@ -264,7 +268,7 @@
   DCHECK_EQ(base::MessageLoop::TYPE_IO, base::MessageLoop::current()->type())
       << "The current base::MessageLoop must be TYPE_IO";
   DCHECK(proxy_auth_controller_.get());
-  if (!socket_.get()) {
+  if (!connection_->socket()) {
     DVLOG(1) << "Socket is closed before restarting with auth.";
     return;
   }
@@ -369,7 +373,7 @@
 }
 
 int SocketStream::DidEstablishConnection() {
-  if (!socket_.get() || !socket_->IsConnected()) {
+  if (!connection_->socket() || !connection_->socket()->IsConnected()) {
     next_state_ = STATE_CLOSE;
     return ERR_CONNECTION_FAILED;
   }
@@ -675,9 +679,11 @@
 
   DCHECK(context_->host_resolver());
   resolver_.reset(new SingleRequestHostResolver(context_->host_resolver()));
-  return resolver_->Resolve(
-      resolve_info, &addresses_, base::Bind(&SocketStream::OnIOCompleted, this),
-      net_log_);
+  return resolver_->Resolve(resolve_info,
+                            DEFAULT_PRIORITY,
+                            &addresses_,
+                            base::Bind(&SocketStream::OnIOCompleted, this),
+                            net_log_);
 }
 
 int SocketStream::DoResolveHostComplete(int result) {
@@ -730,11 +736,12 @@
   }
   next_state_ = STATE_TCP_CONNECT_COMPLETE;
   DCHECK(factory_);
-  socket_.reset(factory_->CreateTransportClientSocket(addresses_,
-                                                      net_log_.net_log(),
-                                                      net_log_.source()));
+  connection_->SetSocket(
+      factory_->CreateTransportClientSocket(addresses_,
+                                            net_log_.net_log(),
+                                            net_log_.source()));
   metrics_->OnStartConnection();
-  return socket_->Connect(io_callback_);
+  return connection_->socket()->Connect(io_callback_);
 }
 
 int SocketStream::DoTcpConnectComplete(int result) {
@@ -819,7 +826,8 @@
   int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() -
                                  tunnel_request_headers_bytes_sent_);
   DCHECK_GT(buf_len, 0);
-  return socket_->Write(tunnel_request_headers_.get(), buf_len, io_callback_);
+  return connection_->socket()->Write(
+      tunnel_request_headers_.get(), buf_len, io_callback_);
 }
 
 int SocketStream::DoWriteTunnelHeadersComplete(int result) {
@@ -862,7 +870,8 @@
   tunnel_response_headers_->SetDataOffset(tunnel_response_headers_len_);
   CHECK(tunnel_response_headers_->data());
 
-  return socket_->Read(tunnel_response_headers_.get(), buf_len, io_callback_);
+  return connection_->socket()->Read(
+      tunnel_response_headers_.get(), buf_len, io_callback_);
 }
 
 int SocketStream::DoReadTunnelHeadersComplete(int result) {
@@ -953,17 +962,22 @@
 
   next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
 
-  StreamSocket* s = socket_.release();
   HostResolver::RequestInfo req_info(HostPortPair::FromURL(url_));
 
   DCHECK(!proxy_info_.is_empty());
-  if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5)
-    s = new SOCKS5ClientSocket(s, req_info);
-  else
-    s = new SOCKSClientSocket(s, req_info, context_->host_resolver());
-  socket_.reset(s);
+  scoped_ptr<StreamSocket> s;
+  if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) {
+    s.reset(new SOCKS5ClientSocket(connection_.Pass(), req_info));
+  } else {
+    s.reset(new SOCKSClientSocket(connection_.Pass(),
+                                  req_info,
+                                  DEFAULT_PRIORITY,
+                                  context_->host_resolver()));
+  }
+  connection_.reset(new ClientSocketHandle);
+  connection_->SetSocket(s.Pass());
   metrics_->OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION);
-  return socket_->Connect(io_callback_);
+  return connection_->socket()->Connect(io_callback_);
 }
 
 int SocketStream::DoSOCKSConnectComplete(int result) {
@@ -986,14 +1000,16 @@
   ssl_context.cert_verifier = context_->cert_verifier();
   ssl_context.transport_security_state = context_->transport_security_state();
   ssl_context.server_bound_cert_service = context_->server_bound_cert_service();
-  socket_.reset(factory_->CreateSSLClientSocket(
-      socket_.release(),
+  scoped_ptr<StreamSocket> socket(factory_->CreateSSLClientSocket(
+      connection_.Pass(),
       proxy_info_.proxy_server().host_port_pair(),
       proxy_ssl_config_,
       ssl_context));
+  connection_.reset(new ClientSocketHandle);
+  connection_->SetSocket(socket.Pass());
   next_state_ = STATE_SECURE_PROXY_CONNECT_COMPLETE;
   metrics_->OnCountConnectionType(SocketStreamMetrics::SECURE_PROXY_CONNECTION);
-  return socket_->Connect(io_callback_);
+  return connection_->socket()->Connect(io_callback_);
 }
 
 int SocketStream::DoSecureProxyConnectComplete(int result) {
@@ -1025,7 +1041,7 @@
 int SocketStream::DoSecureProxyHandleCertErrorComplete(int result) {
   DCHECK_EQ(STATE_NONE, next_state_);
   if (result == OK) {
-    if (!socket_->IsConnectedAndIdle())
+    if (!connection_->socket()->IsConnectedAndIdle())
       return AllowCertErrorForReconnection(&proxy_ssl_config_);
     next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
   } else {
@@ -1040,13 +1056,16 @@
   ssl_context.cert_verifier = context_->cert_verifier();
   ssl_context.transport_security_state = context_->transport_security_state();
   ssl_context.server_bound_cert_service = context_->server_bound_cert_service();
-  socket_.reset(factory_->CreateSSLClientSocket(socket_.release(),
-                                                HostPortPair::FromURL(url_),
-                                                server_ssl_config_,
-                                                ssl_context));
+  scoped_ptr<StreamSocket> socket(
+      factory_->CreateSSLClientSocket(connection_.Pass(),
+                                      HostPortPair::FromURL(url_),
+                                      server_ssl_config_,
+                                      ssl_context));
+  connection_.reset(new ClientSocketHandle);
+  connection_->SetSocket(socket.Pass());
   next_state_ = STATE_SSL_CONNECT_COMPLETE;
   metrics_->OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION);
-  return socket_->Connect(io_callback_);
+  return connection_->socket()->Connect(io_callback_);
 }
 
 int SocketStream::DoSSLConnectComplete(int result) {
@@ -1082,7 +1101,7 @@
   // we should take care of TLS NPN extension here.
 
   if (result == OK) {
-    if (!socket_->IsConnectedAndIdle())
+    if (!connection_->socket()->IsConnectedAndIdle())
       return AllowCertErrorForReconnection(&server_ssl_config_);
     result = DidEstablishConnection();
   } else {
@@ -1096,7 +1115,7 @@
     next_state_ = STATE_CLOSE;
     return result;
   }
-  if (!socket_.get() || !socket_->IsConnected()) {
+  if (!connection_->socket() || !connection_->socket()->IsConnected()) {
     next_state_ = STATE_CLOSE;
     return ERR_CONNECTION_CLOSED;
   }
@@ -1105,7 +1124,7 @@
   // let's close the socket.
   // We don't care about receiving data after the socket is closed.
   if (closing_ && !current_write_buf_.get() && pending_write_bufs_.empty()) {
-    socket_->Disconnect();
+    connection_->socket()->Disconnect();
     next_state_ = STATE_CLOSE;
     return OK;
   }
@@ -1117,7 +1136,7 @@
     if (!read_buf_.get()) {
       // No read pending and server didn't close the socket.
       read_buf_ = new IOBuffer(kReadBufferSize);
-      result = socket_->Read(
+      result = connection_->socket()->Read(
           read_buf_.get(),
           kReadBufferSize,
           base::Bind(&SocketStream::OnReadCompleted, base::Unretained(this)));
@@ -1156,7 +1175,7 @@
     pending_write_bufs_.pop_front();
   }
 
-  result = socket_->Write(
+  result = connection_->socket()->Write(
       current_write_buf_.get(),
       current_write_buf_->BytesRemaining(),
       base::Bind(&SocketStream::OnWriteCompleted, base::Unretained(this)));
@@ -1188,10 +1207,10 @@
     return result;
   }
 
-  DCHECK(socket_.get());
+  DCHECK(connection_->socket());
   scoped_refptr<SSLCertRequestInfo> cert_request_info = new SSLCertRequestInfo;
   SSLClientSocket* ssl_socket =
-      static_cast<SSLClientSocket*>(socket_.get());
+      static_cast<SSLClientSocket*>(connection_->socket());
   ssl_socket->GetSSLCertRequestInfo(cert_request_info.get());
 
   HttpTransactionFactory* factory = context_->http_transaction_factory();
@@ -1237,7 +1256,8 @@
   // allowed bad certificates in |ssl_config|.
   // See also net/http/http_network_transaction.cc HandleCertificateError() and
   // RestartIgnoringLastError().
-  SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(socket_.get());
+  SSLClientSocket* ssl_socket =
+      static_cast<SSLClientSocket*>(connection_->socket());
   SSLInfo ssl_info;
   ssl_socket->GetSSLInfo(&ssl_info);
   if (ssl_info.cert.get() == NULL ||
@@ -1259,8 +1279,8 @@
   bad_cert.cert_status = ssl_info.cert_status;
   ssl_config->allowed_bad_certs.push_back(bad_cert);
   // Restart connection ignoring the bad certificate.
-  socket_->Disconnect();
-  socket_.reset();
+  connection_->socket()->Disconnect();
+  connection_->SetSocket(scoped_ptr<StreamSocket>());
   next_state_ = STATE_TCP_CONNECT;
   return OK;
 }
@@ -1286,7 +1306,8 @@
 
 int SocketStream::HandleCertificateError(int result) {
   DCHECK(IsCertificateError(result));
-  SSLClientSocket* ssl_socket = static_cast<SSLClientSocket*>(socket_.get());
+  SSLClientSocket* ssl_socket =
+      static_cast<SSLClientSocket*>(connection_->socket());
   DCHECK(ssl_socket);
 
   if (!context_)
diff --git a/net/socket_stream/socket_stream.h b/net/socket_stream/socket_stream.h
index 5004060..90aeb8c 100644
--- a/net/socket_stream/socket_stream.h
+++ b/net/socket_stream/socket_stream.h
@@ -28,13 +28,13 @@
 class AuthChallengeInfo;
 class CertVerifier;
 class ClientSocketFactory;
+class ClientSocketHandle;
 class CookieOptions;
 class HostResolver;
 class HttpAuthController;
 class SSLInfo;
 class ServerBoundCertService;
 class SingleRequestHostResolver;
-class StreamSocket;
 class SocketStreamMetrics;
 class TransportSecurityState;
 class URLRequestContext;
@@ -364,7 +364,7 @@
 
   scoped_ptr<SingleRequestHostResolver> resolver_;
   AddressList addresses_;
-  scoped_ptr<StreamSocket> socket_;
+  scoped_ptr<ClientSocketHandle> connection_;
 
   SSLConfig server_ssl_config_;
   SSLConfig proxy_ssl_config_;
diff --git a/net/spdy/spdy_credential_builder_unittest.cc b/net/spdy/spdy_credential_builder_unittest.cc
index bc67cc5..84aff7a 100644
--- a/net/spdy/spdy_credential_builder_unittest.cc
+++ b/net/spdy/spdy_credential_builder_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "net/spdy/spdy_credential_builder.h"
 
-#include "base/threading/sequenced_worker_pool.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"
@@ -23,21 +23,16 @@
 
 void CreateCertAndKey(std::string* cert, std::string* key) {
   // TODO(rch): Share this code with ServerBoundCertServiceTest.
-  scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
-      new base::SequencedWorkerPool(1, "CreateCertAndKey");
   scoped_ptr<ServerBoundCertService> server_bound_cert_service(
       new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
-                                 sequenced_worker_pool));
+                                 base::MessageLoopProxy::current()));
 
   TestCompletionCallback callback;
   ServerBoundCertService::RequestHandle request_handle;
-  int rv = server_bound_cert_service->GetDomainBoundCert(
-      "www.google.com", key, cert,
-      callback.callback(), &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());
-
-  sequenced_worker_pool->Shutdown();
 }
 
 }  // namespace
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 08e8b58..4d91175 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -524,4 +524,9 @@
   delete this;
 }
 
+void SpdyHttpStream::SetPriority(RequestPriority priority) {
+  // TODO(akalin): Plumb this through to |stream_request_| and
+  // |stream_|.
+}
+
 }  // namespace net
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h
index 65d9878..f6e39cd 100644
--- a/net/spdy/spdy_http_stream.h
+++ b/net/spdy/spdy_http_stream.h
@@ -73,6 +73,7 @@
       SSLCertRequestInfo* cert_request_info) OVERRIDE;
   virtual bool IsSpdyHttpStream() const OVERRIDE;
   virtual void Drain(HttpNetworkSession* session) OVERRIDE;
+  virtual void SetPriority(RequestPriority priority) OVERRIDE;
 
   // SpdyStream::Delegate implementation.
   virtual void OnRequestHeadersSent() OVERRIDE;
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 55387cf..7388dc0 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -7,8 +7,8 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/stl_util.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "crypto/ec_private_key.h"
 #include "crypto/ec_signature_creator.h"
 #include "crypto/signature_creator.h"
@@ -542,7 +542,7 @@
   TestCompletionCallback callback;
   std::string key;
   ServerBoundCertService::RequestHandle request_handle;
-  int rv = server_bound_cert_service->GetDomainBoundCert(
+  int rv = server_bound_cert_service->GetOrCreateDomainBoundCert(
       host, &key, cert, callback.callback(),
       &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -783,11 +783,9 @@
   if (GetParam() < kProtoSPDY3)
     return;
 
-  scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
-      new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
   scoped_ptr<ServerBoundCertService> server_bound_cert_service(
       new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
-                                 sequenced_worker_pool));
+                                 base::MessageLoopProxy::current()));
   std::string cert;
   std::string proof;
   GetECServerBoundCertAndProof("www.gmail.com",
@@ -795,19 +793,15 @@
                                &cert, &proof);
 
   TestSendCredentials(server_bound_cert_service.get(), cert, proof);
-
-  sequenced_worker_pool->Shutdown();
 }
 
 TEST_P(SpdyHttpStreamTest, DontSendCredentialsForHttpUrlsEC) {
   if (GetParam() < kProtoSPDY3)
     return;
 
-  scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
-      new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
   scoped_ptr<ServerBoundCertService> server_bound_cert_service(
       new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
-                                 sequenced_worker_pool));
+                                 base::MessageLoopProxy::current()));
   std::string cert;
   std::string proof;
   GetECServerBoundCertAndProof("proxy.google.com",
@@ -887,7 +881,6 @@
   ASSERT_TRUE(response.headers.get() != NULL);
   ASSERT_EQ(200, response.headers->response_code());
   deterministic_data_->RunFor(1);
-  sequenced_worker_pool->Shutdown();
 }
 
 #endif  // !defined(USE_OPENSSL)
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 98c4d13..f3f9f34 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_vector.h"
+#include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "net/base/auth.h"
 #include "net/base/net_log_unittest.h"
@@ -80,6 +81,13 @@
   SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) {
   }
 
+  virtual ~SpdyNetworkTransactionTest() {
+    // UploadDataStream posts deletion tasks back to the message loop on
+    // destruction.
+    upload_data_stream_.reset();
+    base::RunLoop().RunUntilIdle();
+  }
+
   virtual void SetUp() {
     google_get_request_initialized_ = false;
     google_post_request_initialized_ = false;
@@ -87,11 +95,6 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   }
 
-  virtual void TearDown() {
-    // Empty the current queue.
-    base::MessageLoop::current()->RunUntilIdle();
-  }
-
   struct TransactionHelperResult {
     int rv;
     std::string status_line;
@@ -519,7 +522,7 @@
         // reads until we complete our callback.
         while (!callback.have_result()) {
           data->CompleteRead();
-          base::MessageLoop::current()->RunUntilIdle();
+          base::RunLoop().RunUntilIdle();
         }
         rv = callback.WaitForResult();
       } else if (rv <= 0) {
@@ -573,7 +576,7 @@
     rv = trans2->Start(
         &CreateGetPushRequest(), callback.callback(), BoundNetLog());
     EXPECT_EQ(ERR_IO_PENDING, rv);
-    base::MessageLoop::current()->RunUntilIdle();
+    base::RunLoop().RunUntilIdle();
 
     // The data for the pushed path may be coming in more than 1 frame. Compile
     // the results into a single string.
@@ -1880,10 +1883,10 @@
   helper.AddData(&data);
   ASSERT_TRUE(helper.StartDefaultTest());
 
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   helper.request().upload_data_stream->AppendChunk(
       kUploadData, kUploadDataSize, false);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   helper.request().upload_data_stream->AppendChunk(
       kUploadData, kUploadDataSize, true);
 
@@ -2252,7 +2255,7 @@
 
   // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
   // MockClientSocketFactory) are still alive.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   helper.VerifyDataNotConsumed();
 }
 
@@ -2408,7 +2411,7 @@
   data.CompleteRead();
 
   // Finish running rest of tasks.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   helper.VerifyDataConsumed();
 }
 
@@ -2469,12 +2472,12 @@
 
     d.set_quit_on_redirect(true);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.received_redirect_count());
 
     r.FollowDeferredRedirect();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
     EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status());
@@ -2559,7 +2562,7 @@
         AddSocketDataProvider(&data);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, d.received_redirect_count());
     std::string contents("hello!");
@@ -2572,11 +2575,11 @@
 
     d2.set_quit_on_redirect(true);
     r2.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(1, d2.received_redirect_count());
 
     r2.FollowDeferredRedirect();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(1, d2.response_started_count());
     EXPECT_FALSE(d2.received_data_before_response());
     EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2.status().status());
@@ -3786,7 +3789,7 @@
 
   // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
   // MockClientSocketFactory) are still alive.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Verify that we consumed all test data.
   helper.VerifyDataConsumed();
@@ -3883,7 +3886,7 @@
 
   // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
   // MockClientSocketFactory) are still alive.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Verify that we consumed all test data.
   helper.VerifyDataConsumed();
@@ -3977,7 +3980,7 @@
 
   // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
   // MockClientSocketFactory) are still alive.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Verify that we consumed all test data.
   helper.VerifyDataConsumed();
@@ -4072,7 +4075,7 @@
 
   // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
   // MockClientSocketFactory) are still alive.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Verify that we consumed all test data.
   helper.VerifyDataConsumed();
@@ -4143,7 +4146,7 @@
 
   // Flush the MessageLoop; this will cause the buffered IO task
   // to run for the final time.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Verify that we consumed all test data.
   helper.VerifyDataConsumed();
@@ -4787,7 +4790,7 @@
         if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
           // Writes to the socket complete asynchronously on SPDY by running
           // through the message loop.  Complete the write here.
-          base::MessageLoop::current()->RunUntilIdle();
+          base::RunLoop().RunUntilIdle();
         }
 
         // Now schedule the ERR_CONNECTION_RESET.
@@ -5102,7 +5105,7 @@
       &CreateGetPushRequest(), callback.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   data.RunFor(3);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Read the server push body.
   std::string result2;
@@ -5238,7 +5241,7 @@
       &CreateGetPushRequest(), callback.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   data.RunFor(3);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Read the server push body.
   std::string result2;
@@ -5371,7 +5374,7 @@
       &CreateGetPushRequest(), callback.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   data.RunFor(2);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Read the server push body.
   std::string result2;
@@ -5726,7 +5729,7 @@
   // Run the message loop, but do not allow the write to complete.
   // This leaves the SpdySession with a write pending, which prevents
   // SpdySession from attempting subsequent writes until this write completes.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Now, start both new transactions
   HttpRequestInfo info2 = CreateGetRequest();
@@ -5735,7 +5738,7 @@
       new HttpNetworkTransaction(MEDIUM, helper.session().get()));
   rv = trans2->Start(&info2, callback2.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   HttpRequestInfo info3 = CreateGetRequest();
   TestCompletionCallback callback3;
@@ -5743,7 +5746,7 @@
       new HttpNetworkTransaction(HIGHEST, helper.session().get()));
   rv = trans3->Start(&info3, callback3.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // We now have two SYN_STREAM frames queued up which will be
   // dequeued only once the first write completes, which we
@@ -5955,7 +5958,7 @@
 
   // Force write of WINDOW_UPDATE which was scheduled during the above
   // read.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Read EOF.
   data.CompleteRead();
@@ -6139,7 +6142,7 @@
   int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
-  base::MessageLoop::current()->RunUntilIdle();  // Write as much as we can.
+  base::RunLoop().RunUntilIdle();  // Write as much as we can.
 
   SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
   ASSERT_TRUE(stream != NULL);
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index baef195..7f31cd5 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -205,13 +205,38 @@
   return dict;
 }
 
+// Helper function to return the total size of an array of objects
+// with .size() member functions.
+template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) {
+  size_t total_size = 0;
+  for (size_t i = 0; i < N; ++i) {
+    total_size += arr[i].size();
+  }
+  return total_size;
+}
+
+// Helper class for std:find_if on STL container containing
+// SpdyStreamRequest weak pointers.
+class RequestEquals {
+ public:
+  RequestEquals(const base::WeakPtr<SpdyStreamRequest>& request)
+      : request_(request) {}
+
+  bool operator()(const base::WeakPtr<SpdyStreamRequest>& request) const {
+    return request_.get() == request.get();
+  }
+
+ private:
+  const base::WeakPtr<SpdyStreamRequest> request_;
+};
+
 // The maximum number of concurrent streams we will ever create.  Even if
 // the server permits more, we will never exceed this limit.
 const size_t kMaxConcurrentStreamLimit = 256;
 
 }  // namespace
 
-SpdyStreamRequest::SpdyStreamRequest() {
+SpdyStreamRequest::SpdyStreamRequest() : weak_ptr_factory_(this) {
   Reset();
 }
 
@@ -226,9 +251,9 @@
     RequestPriority priority,
     const BoundNetLog& net_log,
     const CompletionCallback& callback) {
-  DCHECK(session.get());
-  DCHECK(!session_.get());
-  DCHECK(!stream_.get());
+  DCHECK(session);
+  DCHECK(!session_);
+  DCHECK(!stream_);
   DCHECK(callback_.is_null());
 
   type_ = type;
@@ -239,7 +264,7 @@
   callback_ = callback;
 
   base::WeakPtr<SpdyStream> stream;
-  int rv = session->TryCreateStream(this, &stream);
+  int rv = session->TryCreateStream(weak_ptr_factory_.GetWeakPtr(), &stream);
   if (rv == OK) {
     Reset();
     stream_ = stream;
@@ -248,34 +273,36 @@
 }
 
 void SpdyStreamRequest::CancelRequest() {
-  if (session_.get())
-    session_->CancelStreamRequest(this);
+  if (session_)
+    session_->CancelStreamRequest(weak_ptr_factory_.GetWeakPtr());
   Reset();
+  // Do this to cancel any pending CompleteStreamRequest() tasks.
+  weak_ptr_factory_.InvalidateWeakPtrs();
 }
 
 base::WeakPtr<SpdyStream> SpdyStreamRequest::ReleaseStream() {
-  DCHECK(!session_.get());
+  DCHECK(!session_);
   base::WeakPtr<SpdyStream> stream = stream_;
-  DCHECK(stream.get());
+  DCHECK(stream);
   Reset();
   return stream;
 }
 
 void SpdyStreamRequest::OnRequestCompleteSuccess(
-    base::WeakPtr<SpdyStream>* stream) {
-  DCHECK(session_.get());
-  DCHECK(!stream_.get());
+    const base::WeakPtr<SpdyStream>& stream) {
+  DCHECK(session_);
+  DCHECK(!stream_);
   DCHECK(!callback_.is_null());
   CompletionCallback callback = callback_;
   Reset();
-  DCHECK(*stream);
-  stream_ = *stream;
+  DCHECK(stream);
+  stream_ = stream;
   callback.Run(OK);
 }
 
 void SpdyStreamRequest::OnRequestCompleteFailure(int rv) {
-  DCHECK(session_.get());
-  DCHECK(!stream_.get());
+  DCHECK(session_);
+  DCHECK(!stream_);
   DCHECK(!callback_.is_null());
   CompletionCallback callback = callback_;
   Reset();
@@ -490,7 +517,7 @@
     error = OK;
   if (error == OK) {
     DCHECK_NE(availability_state_, STATE_CLOSED);
-    connection_->AddLayeredPool(this);
+    connection_->AddHigherLayeredPool(this);
     if (enable_sending_initial_data_)
       SendInitialData();
     pool_ = pool;
@@ -565,9 +592,10 @@
   return OK;
 }
 
-int SpdySession::TryCreateStream(SpdyStreamRequest* request,
-                                 base::WeakPtr<SpdyStream>* stream) {
-  CHECK(request);
+int SpdySession::TryCreateStream(
+    const base::WeakPtr<SpdyStreamRequest>& request,
+    base::WeakPtr<SpdyStream>* stream) {
+  DCHECK(request);
 
   if (availability_state_ == STATE_GOING_AWAY)
     return ERR_FAILED;
@@ -641,8 +669,9 @@
   return OK;
 }
 
-void SpdySession::CancelStreamRequest(SpdyStreamRequest* request) {
-  CHECK(request);
+void SpdySession::CancelStreamRequest(
+    const base::WeakPtr<SpdyStreamRequest>& request) {
+  DCHECK(request);
 
   if (DCHECK_IS_ON()) {
     // |request| should not be in a queue not matching its priority.
@@ -650,7 +679,9 @@
       if (request->priority() == i)
         continue;
       PendingStreamRequestQueue* queue = &pending_create_stream_queues_[i];
-      DCHECK(std::find(queue->begin(), queue->end(), request) == queue->end());
+      DCHECK(std::find_if(queue->begin(),
+                          queue->end(),
+                          RequestEquals(request)) == queue->end());
     }
   }
 
@@ -659,18 +690,30 @@
   // Remove |request| from |queue| while preserving the order of the
   // other elements.
   PendingStreamRequestQueue::iterator it =
-      std::find(queue->begin(), queue->end(), request);
+      std::find_if(queue->begin(), queue->end(), RequestEquals(request));
+  // The request may already be removed if there's a
+  // CompleteStreamRequest() in flight.
   if (it != queue->end()) {
     it = queue->erase(it);
     // |request| should be in the queue at most once, and if it is
     // present, should not be pending completion.
-    DCHECK(std::find(it, queue->end(), request) == queue->end());
-    DCHECK(!ContainsKey(pending_stream_request_completions_,
-                        request));
-    return;
+    DCHECK(std::find_if(it, queue->end(), RequestEquals(request)) ==
+           queue->end());
   }
+}
 
-  pending_stream_request_completions_.erase(request);
+base::WeakPtr<SpdyStreamRequest> SpdySession::GetNextPendingStreamRequest() {
+  for (int j = NUM_PRIORITIES - 1; j >= MINIMUM_PRIORITY; --j) {
+    if (pending_create_stream_queues_[j].empty())
+      continue;
+
+    base::WeakPtr<SpdyStreamRequest> pending_request =
+        pending_create_stream_queues_[j].front();
+    DCHECK(pending_request);
+    pending_create_stream_queues_[j].pop_front();
+    return pending_request;
+  }
+  return base::WeakPtr<SpdyStreamRequest>();
 }
 
 void SpdySession::ProcessPendingStreamRequests() {
@@ -684,27 +727,16 @@
   }
   for (size_t i = 0;
        max_requests_to_process == 0 || i < max_requests_to_process; ++i) {
-    bool processed_request = false;
-    for (int j = NUM_PRIORITIES - 1; j >= MINIMUM_PRIORITY; --j) {
-      if (pending_create_stream_queues_[j].empty())
-        continue;
+    base::WeakPtr<SpdyStreamRequest> pending_request =
+        GetNextPendingStreamRequest();
+    if (!pending_request)
+      break;
 
-      SpdyStreamRequest* pending_request =
-          pending_create_stream_queues_[j].front();
-      CHECK(pending_request);
-      pending_create_stream_queues_[j].pop_front();
-      processed_request = true;
-      DCHECK(!ContainsKey(pending_stream_request_completions_,
-                          pending_request));
-      pending_stream_request_completions_.insert(pending_request);
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&SpdySession::CompleteStreamRequest,
-                     weak_factory_.GetWeakPtr(), pending_request));
-      break;
-    }
-    if (!processed_request)
-      break;
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&SpdySession::CompleteStreamRequest,
+                   weak_factory_.GetWeakPtr(),
+                   pending_request));
   }
 }
 
@@ -1016,9 +1048,25 @@
   // push is hardly used. Write tests for this and fix this. (See
   // http://crbug.com/261712 .)
   if (owned_stream->type() == SPDY_PUSH_STREAM)
-      unclaimed_pushed_streams_.erase(owned_stream->url());
+    unclaimed_pushed_streams_.erase(owned_stream->url());
+
+  base::WeakPtr<SpdySession> weak_this = GetWeakPtr();
 
   DeleteStream(owned_stream.Pass(), status);
+
+  if (!weak_this)
+    return;
+
+  if (availability_state_ == STATE_CLOSED)
+    return;
+
+  // If there are no active streams and the socket pool is stalled, close the
+  // session to free up a socket slot.
+  if (active_streams_.empty() && connection_->IsPoolStalled()) {
+    CloseSessionResult result =
+        DoCloseSession(ERR_CONNECTION_CLOSED, "Closing idle connection.");
+    DCHECK_NE(result, SESSION_ALREADY_CLOSED);
+  }
 }
 
 void SpdySession::CloseCreatedStreamIterator(CreatedStreamSet::iterator it,
@@ -1377,7 +1425,6 @@
       DCHECK(pending_create_stream_queues_[i].empty());
     }
   }
-  DCHECK(pending_stream_request_completions_.empty());
   DCHECK(created_streams_.empty());
 }
 
@@ -1395,41 +1442,40 @@
   DCHECK_GE(availability_state_, STATE_GOING_AWAY);
 
   // The loops below are carefully written to avoid reentrancy problems.
-  //
-  // TODO(akalin): Any of the functions below can cause |this| to be
-  // deleted, so handle that below (and add tests for it).
 
-  for (int i = 0; i < NUM_PRIORITIES; ++i) {
-    PendingStreamRequestQueue queue;
-    queue.swap(pending_create_stream_queues_[i]);
-    for (PendingStreamRequestQueue::const_iterator it = queue.begin();
-         it != queue.end(); ++it) {
-      CHECK(*it);
-      (*it)->OnRequestCompleteFailure(ERR_ABORTED);
-    }
-  }
-
-  PendingStreamRequestCompletionSet pending_completions;
-  pending_completions.swap(pending_stream_request_completions_);
-  for (PendingStreamRequestCompletionSet::const_iterator it =
-           pending_completions.begin();
-       it != pending_completions.end(); ++it) {
-    (*it)->OnRequestCompleteFailure(ERR_ABORTED);
+  while (true) {
+    size_t old_size = GetTotalSize(pending_create_stream_queues_);
+    base::WeakPtr<SpdyStreamRequest> pending_request =
+        GetNextPendingStreamRequest();
+    if (!pending_request)
+      break;
+    // No new stream requests should be added while the session is
+    // going away.
+    DCHECK_GT(old_size, GetTotalSize(pending_create_stream_queues_));
+    pending_request->OnRequestCompleteFailure(ERR_ABORTED);
   }
 
   while (true) {
+    size_t old_size = active_streams_.size();
     ActiveStreamMap::iterator it =
         active_streams_.lower_bound(last_good_stream_id + 1);
     if (it == active_streams_.end())
       break;
     LogAbandonedActiveStream(it, status);
     CloseActiveStreamIterator(it, status);
+    // No new streams should be activated while the session is going
+    // away.
+    DCHECK_GT(old_size, active_streams_.size());
   }
 
   while (!created_streams_.empty()) {
+    size_t old_size = created_streams_.size();
     CreatedStreamSet::iterator it = created_streams_.begin();
     LogAbandonedStream(*it, status);
     CloseCreatedStreamIterator(it, status);
+    // No new streams should be created while the session is going
+    // away.
+    DCHECK_GT(old_size, created_streams_.size());
   }
 
   write_queue_.RemovePendingWritesForStreamsAfter(last_good_stream_id);
@@ -2677,25 +2723,20 @@
   }
 }
 
-void SpdySession::CompleteStreamRequest(SpdyStreamRequest* pending_request) {
-  CHECK(pending_request);
-
-  PendingStreamRequestCompletionSet::iterator it =
-      pending_stream_request_completions_.find(pending_request);
-
+void SpdySession::CompleteStreamRequest(
+    const base::WeakPtr<SpdyStreamRequest>& pending_request) {
   // Abort if the request has already been cancelled.
-  if (it == pending_stream_request_completions_.end())
+  if (!pending_request)
     return;
 
   base::WeakPtr<SpdyStream> stream;
   int rv = CreateStream(*pending_request, &stream);
-  pending_stream_request_completions_.erase(it);
 
   if (rv == OK) {
-    DCHECK(stream.get());
-    pending_request->OnRequestCompleteSuccess(&stream);
+    DCHECK(stream);
+    pending_request->OnRequestCompleteSuccess(stream);
   } else {
-    DCHECK(!stream.get());
+    DCHECK(!stream);
     pending_request->OnRequestCompleteFailure(rv);
   }
 }
@@ -2859,20 +2900,6 @@
   stream_send_unstall_queue_[stream.priority()].push_back(stream.stream_id());
 }
 
-namespace {
-
-// Helper function to return the total size of an array of objects
-// with .size() member functions.
-template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) {
-  size_t total_size = 0;
-  for (size_t i = 0; i < N; ++i) {
-    total_size += arr[i].size();
-  }
-  return total_size;
-}
-
-}  // namespace
-
 void SpdySession::ResumeSendStalledStreams() {
   DCHECK_EQ(flow_control_state_, FLOW_CONTROL_STREAM_AND_SESSION);
 
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 819db11..f9c0623 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -157,7 +157,7 @@
 
   // Called by |session_| when the stream attempt has finished
   // successfully.
-  void OnRequestCompleteSuccess(base::WeakPtr<SpdyStream>* stream);
+  void OnRequestCompleteSuccess(const base::WeakPtr<SpdyStream>& stream);
 
   // Called by |session_| when the stream attempt has finished with an
   // error. Also called with ERR_ABORTED if |session_| is destroyed
@@ -172,6 +172,7 @@
 
   void Reset();
 
+  base::WeakPtrFactory<SpdyStreamRequest> weak_ptr_factory_;
   SpdyStreamType type_;
   base::WeakPtr<SpdySession> session_;
   base::WeakPtr<SpdyStream> stream_;
@@ -185,7 +186,7 @@
 
 class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
                                public SpdyFramerDebugVisitorInterface,
-                               public LayeredPool {
+                               public HigherLayeredPool {
  public:
   // TODO(akalin): Use base::TickClock when it becomes available.
   typedef base::TimeTicks (*TimeFunc)(void);
@@ -479,7 +480,7 @@
   // Must be used only by |pool_|.
   base::WeakPtr<SpdySession> GetWeakPtr();
 
-  // LayeredPool implementation:
+  // HigherLayeredPool implementation:
   virtual bool CloseOneIdleConnection() OVERRIDE;
 
  private:
@@ -501,8 +502,8 @@
   FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlNoSendLeaks);
   FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlEndToEnd);
 
-  typedef std::deque<SpdyStreamRequest*> PendingStreamRequestQueue;
-  typedef std::set<SpdyStreamRequest*> PendingStreamRequestCompletionSet;
+  typedef std::deque<base::WeakPtr<SpdyStreamRequest> >
+      PendingStreamRequestQueue;
 
   struct ActiveStreamInfo {
     ActiveStreamInfo();
@@ -574,7 +575,7 @@
   // |request->OnRequestComplete{Success,Failure}()| will be called
   // when the stream is created (unless it is cancelled). Otherwise,
   // no stream is created and the error is returned.
-  int TryCreateStream(SpdyStreamRequest* request,
+  int TryCreateStream(const base::WeakPtr<SpdyStreamRequest>& request,
                       base::WeakPtr<SpdyStream>* stream);
 
   // Actually create a stream into |stream|. Returns OK if successful;
@@ -584,7 +585,11 @@
 
   // Called by SpdyStreamRequest to remove |request| from the stream
   // creation queue.
-  void CancelStreamRequest(SpdyStreamRequest* request);
+  void CancelStreamRequest(const base::WeakPtr<SpdyStreamRequest>& request);
+
+  // Returns the next pending stream request to process, or NULL if
+  // there is none.
+  base::WeakPtr<SpdyStreamRequest> GetNextPendingStreamRequest();
 
   // Called when there is room to create more streams (e.g., a stream
   // was closed). Processes as many pending stream requests as
@@ -783,7 +788,8 @@
 
   // Invokes a user callback for stream creation.  We provide this method so it
   // can be deferred to the MessageLoop, so we avoid re-entrancy problems.
-  void CompleteStreamRequest(SpdyStreamRequest* pending_request);
+  void CompleteStreamRequest(
+      const base::WeakPtr<SpdyStreamRequest>& pending_request);
 
   // Remove old unclaimed pushed streams.
   void DeleteExpiredPushedStreams();
@@ -960,12 +966,6 @@
   // not yet been satisfied.
   PendingStreamRequestQueue pending_create_stream_queues_[NUM_PRIORITIES];
 
-  // A set of requests that are waiting to be completed (i.e., for the
-  // stream to actually be created). This is necessary since we kick
-  // off the stream creation asynchronously, and so the request may be
-  // cancelled before the asynchronous task to create the stream runs.
-  PendingStreamRequestCompletionSet pending_stream_request_completions_;
-
   // Map from stream id to all active streams.  Streams are active in the sense
   // that they have a consumer (typically SpdyNetworkTransaction and regardless
   // of whether or not there is currently any ongoing IO [might be waiting for
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index 9d0679d..3368875 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -337,9 +337,12 @@
     // This test requires that the HostResolver cache be populated.  Normal
     // code would have done this already, but we do it manually.
     HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
-    session_deps_.host_resolver->Resolve(
-        info, &test_hosts[i].addresses, CompletionCallback(), NULL,
-        BoundNetLog());
+    session_deps_.host_resolver->Resolve(info,
+                                         DEFAULT_PRIORITY,
+                                         &test_hosts[i].addresses,
+                                         CompletionCallback(),
+                                         NULL,
+                                         BoundNetLog());
 
     // Setup a SpdySessionKey
     test_hosts[i].key = SpdySessionKey(
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index f0d448c..72dc574 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -193,6 +193,96 @@
       spdy_session_pool_, key_, ERR_FAILED);
 }
 
+namespace {
+
+// A helper class that vends a callback that, when fired, destroys a
+// given SpdyStreamRequest.
+class StreamRequestDestroyingCallback : public TestCompletionCallbackBase {
+ public:
+  StreamRequestDestroyingCallback() {}
+
+  virtual ~StreamRequestDestroyingCallback() {}
+
+  void SetRequestToDestroy(scoped_ptr<SpdyStreamRequest> request) {
+    request_ = request.Pass();
+  }
+
+  CompletionCallback MakeCallback() {
+    return base::Bind(&StreamRequestDestroyingCallback::OnComplete,
+                      base::Unretained(this));
+  }
+
+ private:
+  void OnComplete(int result) {
+    request_.reset();
+    SetResult(result);
+  }
+
+  scoped_ptr<SpdyStreamRequest> request_;
+};
+
+}  // namespace
+
+// Request kInitialMaxConcurrentStreams streams.  Request two more
+// streams, but have the callback for one destroy the second stream
+// request. Close the session. Nothing should blow up. This is a
+// regression test for http://crbug.com/250841 .
+TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
+  session_deps_.host_resolver->set_synchronous_mode(true);
+
+  MockRead reads[] = {MockRead(ASYNC, 0, 0), };
+
+  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
+  MockConnect connect_data(SYNCHRONOUS, OK);
+  data.set_connect_data(connect_data);
+  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+
+  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
+  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
+
+  CreateDeterministicNetworkSession();
+
+  base::WeakPtr<SpdySession> session =
+      CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
+
+  // Create the maximum number of concurrent streams.
+  for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
+    base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
+        SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, BoundNetLog());
+    ASSERT_TRUE(spdy_stream != NULL);
+  }
+
+  SpdyStreamRequest request1;
+  scoped_ptr<SpdyStreamRequest> request2(new SpdyStreamRequest);
+
+  StreamRequestDestroyingCallback callback1;
+  ASSERT_EQ(ERR_IO_PENDING,
+            request1.StartRequest(SPDY_BIDIRECTIONAL_STREAM,
+                                  session,
+                                  test_url_,
+                                  MEDIUM,
+                                  BoundNetLog(),
+                                  callback1.MakeCallback()));
+
+  // |callback2| is never called.
+  TestCompletionCallback callback2;
+  ASSERT_EQ(ERR_IO_PENDING,
+            request2->StartRequest(SPDY_BIDIRECTIONAL_STREAM,
+                                   session,
+                                   test_url_,
+                                   MEDIUM,
+                                   BoundNetLog(),
+                                   callback2.callback()));
+
+  callback1.SetRequestToDestroy(request2.Pass());
+
+  session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
+
+  EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult());
+
+  data.RunFor(1);
+}
+
 // A session receiving a GOAWAY frame with no active streams should
 // immediately close.
 TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
@@ -2669,7 +2759,7 @@
   TestCompletionCallback callback2;
   HostPortPair host_port2("2.com", 80);
   scoped_refptr<TransportSocketParams> params2(
-      new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false,
+      new TransportSocketParams(host_port2, false, false,
                                 OnHostResolutionCallback()));
   scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
   EXPECT_EQ(ERR_IO_PENDING,
@@ -2731,8 +2821,12 @@
   AddressList addresses;
   // Pre-populate the DNS cache, since a synchronous resolution is required in
   // order to create the alias.
-  session_deps_.host_resolver->Resolve(
-      info, &addresses, CompletionCallback(), NULL, BoundNetLog());
+  session_deps_.host_resolver->Resolve(info,
+                                       DEFAULT_PRIORITY,
+                                       &addresses,
+                                       CompletionCallback(),
+                                       NULL,
+                                       BoundNetLog());
   // Get a session for |key2|, which should return the session created earlier.
   base::WeakPtr<SpdySession> session2 =
       spdy_session_pool_->FindAvailableSession(key2, BoundNetLog());
@@ -2744,7 +2838,7 @@
   TestCompletionCallback callback3;
   HostPortPair host_port3("3.com", 80);
   scoped_refptr<TransportSocketParams> params3(
-      new TransportSocketParams(host_port3, DEFAULT_PRIORITY, false, false,
+      new TransportSocketParams(host_port3, false, false,
                                 OnHostResolutionCallback()));
   scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle);
   EXPECT_EQ(ERR_IO_PENDING,
@@ -2760,9 +2854,9 @@
   EXPECT_TRUE(session2 == NULL);
 }
 
-// Tests that a non-SPDY request can't close a SPDY session that's currently in
-// use.
-TEST_P(SpdySessionTest, CloseOneIdleConnectionFailsWhenSessionInUse) {
+// Tests that when a SPDY session becomes idle, it closes itself if there is
+// a lower layer pool stalled on the per-pool socket limit.
+TEST_P(SpdySessionTest, CloseSessionOnIdleWhenPoolStalled) {
   ClientSocketPoolManager::set_max_sockets_per_group(
       HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
   ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -2781,10 +2875,19 @@
     CreateMockWrite(*cancel1, 1),
   };
   StaticSocketDataProvider data(reads, arraysize(reads),
-                                     writes, arraysize(writes));
+                                writes, arraysize(writes));
   data.set_connect_data(connect_data);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
+  MockRead http_reads[] = {
+    MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
+  };
+  StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
+                                     NULL, 0);
+  http_data.set_connect_data(connect_data);
+  session_deps_.socket_factory->AddSocketDataProvider(&http_data);
+
+
   CreateNetworkSession();
 
   TransportClientSocketPool* pool =
@@ -2824,7 +2927,7 @@
   TestCompletionCallback callback2;
   HostPortPair host_port2("2.com", 80);
   scoped_refptr<TransportSocketParams> params2(
-      new TransportSocketParams(host_port2, DEFAULT_PRIORITY, false, false,
+      new TransportSocketParams(host_port2, false, false,
                                 OnHostResolutionCallback()));
   scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
   EXPECT_EQ(ERR_IO_PENDING,
@@ -2839,14 +2942,13 @@
   EXPECT_TRUE(pool->IsStalled());
   EXPECT_FALSE(callback2.have_result());
 
-  // Cancelling the request should still not release the session's socket,
-  // since the session is still kept alive by the SpdySessionPool.
+  // Cancelling the request should result in the session's socket being
+  // closed, since the pool is stalled.
   ASSERT_TRUE(spdy_stream1.get());
   spdy_stream1->Cancel();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(pool->IsStalled());
-  EXPECT_FALSE(callback2.have_result());
-  EXPECT_TRUE(session1 != NULL);
+  ASSERT_FALSE(pool->IsStalled());
+  EXPECT_EQ(OK, callback2.WaitForResult());
 }
 
 // Verify that SpdySessionKey and therefore SpdySession is different when
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 18d20e8..a603a6c 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -740,7 +740,7 @@
   io_state_ = STATE_GET_DOMAIN_BOUND_CERT_COMPLETE;
   ServerBoundCertService* sbc_service = session_->GetServerBoundCertService();
   DCHECK(sbc_service != NULL);
-  int rv = sbc_service->GetDomainBoundCert(
+  int rv = sbc_service->GetOrCreateDomainBoundCert(
       url.GetOrigin().host(),
       &domain_bound_private_key_,
       &domain_bound_cert_,
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index 4383db0..8fb085a 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -500,7 +500,7 @@
 
   scoped_refptr<TransportSocketParams> transport_params(
       new TransportSocketParams(
-          key.host_port_pair(), MEDIUM, false, false,
+          key.host_port_pair(), false, false,
           OnHostResolutionCallback()));
 
   scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
@@ -509,13 +509,10 @@
   int rv = ERR_UNEXPECTED;
   if (is_secure) {
     SSLConfig ssl_config;
-    scoped_refptr<SOCKSSocketParams> socks_params;
-    scoped_refptr<HttpProxySocketParams> http_proxy_params;
     scoped_refptr<SSLSocketParams> ssl_params(
         new SSLSocketParams(transport_params,
-                            socks_params,
-                            http_proxy_params,
-                            ProxyServer::SCHEME_DIRECT,
+                            NULL,
+                            NULL,
                             key.host_port_pair(),
                             ssl_config,
                             key.privacy_mode(),
@@ -649,8 +646,8 @@
   EXPECT_FALSE(HasSpdySession(pool, key));
   base::WeakPtr<SpdySession> spdy_session;
   scoped_ptr<ClientSocketHandle> handle(new ClientSocketHandle());
-  handle->set_socket(new FakeSpdySessionClientSocket(
-      expected_status == OK ? ERR_IO_PENDING : expected_status));
+  handle->SetSocket(scoped_ptr<StreamSocket>(new FakeSpdySessionClientSocket(
+      expected_status == OK ? ERR_IO_PENDING : expected_status)));
   EXPECT_EQ(
       expected_status,
       pool->CreateAvailableSessionFromSocket(
@@ -942,7 +939,8 @@
 SpdyFrame* SpdyTestUtil::ConstructSpdyConnect(
     const char* const extra_headers[],
     int extra_header_count,
-    int stream_id) const {
+    int stream_id,
+    RequestPriority priority) const {
   const char* const kConnectHeaders[] = {
     GetMethodKey(),  "CONNECT",
     GetPathKey(),    "www.google.com:443",
@@ -953,7 +951,7 @@
                                    extra_header_count,
                                    /*compressed*/ false,
                                    stream_id,
-                                   LOWEST,
+                                   priority,
                                    SYN_STREAM,
                                    CONTROL_FLAG_NONE,
                                    kConnectHeaders,
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index aa833ff..e9f453c 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -421,7 +421,8 @@
   // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
   SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
                                   int extra_header_count,
-                                  int stream_id) const;
+                                  int stream_id,
+                                  RequestPriority priority) const;
 
   // Constructs a standard SPDY push SYN frame.
   // |extra_headers| are the extra header-value pairs, which typically
diff --git a/net/spdy/write_blocked_list.h b/net/spdy/write_blocked_list.h
new file mode 100644
index 0000000..fe5668f
--- /dev/null
+++ b/net/spdy/write_blocked_list.h
@@ -0,0 +1,86 @@
+// Copyright 2013 The Chromium Authors. 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_WRITE_BLOCKED_LIST_H_
+#define NET_SPDY_WRITE_BLOCKED_LIST_H_
+
+#include <algorithm>
+#include <deque>
+
+#include "base/logging.h"
+
+namespace net {
+
+const int kHighestPriority = 0;
+const int kLowestPriority = 7;
+
+template <typename IdType>
+class WriteBlockedList {
+ public:
+  // 0(1) size lookup.  0(1) insert at front or back.
+  typedef std::deque<IdType> BlockedList;
+  typedef typename BlockedList::iterator iterator;
+
+  // Returns the priority of the highest priority list with sessions on it, or
+  // -1 if none of the lists have pending sessions.
+  int GetHighestPriorityWriteBlockedList() const {
+    for (int i = 0; i <= kLowestPriority; ++i) {
+      if (write_blocked_lists_[i].size() > 0)
+        return i;
+    }
+    return -1;
+  }
+
+  int PopFront(int priority) {
+    DCHECK(!write_blocked_lists_[priority].empty());
+    IdType stream_id = write_blocked_lists_[priority].front();
+    write_blocked_lists_[priority].pop_front();
+    return stream_id;
+  }
+
+  bool HasWriteBlockedStreamsGreaterThanPriority(int priority) const {
+    for (int i = kHighestPriority; i < priority; ++i) {
+      if (!write_blocked_lists_[i].empty()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool HasWriteBlockedStreams() const {
+    return HasWriteBlockedStreamsGreaterThanPriority(kLowestPriority + 1);
+  }
+
+  void PushBack(IdType stream_id, int priority) {
+    write_blocked_lists_[priority].push_back(stream_id);
+  }
+
+  void RemoveStreamFromWriteBlockedList(IdType stream_id, int priority) {
+    iterator it = std::find(write_blocked_lists_[priority].begin(),
+                            write_blocked_lists_[priority].end(),
+                            stream_id);
+    while (it != write_blocked_lists_[priority].end()) {
+      write_blocked_lists_[priority].erase(it);
+      it = std::find(write_blocked_lists_[priority].begin(),
+                     write_blocked_lists_[priority].end(),
+                     stream_id);
+    }
+  }
+
+  int NumBlockedStreams() {
+    int num_blocked_streams = 0;
+    for (int i = kHighestPriority; i <= kLowestPriority; ++i) {
+      num_blocked_streams += write_blocked_lists_[i].size();
+    }
+    return num_blocked_streams;
+  }
+
+ private:
+  // Priority ranges from 0 to 7
+  BlockedList write_blocked_lists_[8];
+};
+
+}  // namespace net
+
+#endif  // NET_SPDY_WRITE_BLOCKED_LIST_H_
diff --git a/net/spdy/write_blocked_list_test.cc b/net/spdy/write_blocked_list_test.cc
new file mode 100644
index 0000000..3bb49df
--- /dev/null
+++ b/net/spdy/write_blocked_list_test.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 "net/spdy/write_blocked_list.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace net {
+namespace test {
+namespace {
+
+typedef WriteBlockedList<int> IntWriteBlockedList;
+
+TEST(WriteBlockedListTest, GetHighestPriority) {
+  IntWriteBlockedList list;
+  EXPECT_EQ(-1, list.GetHighestPriorityWriteBlockedList());
+  list.PushBack(1, 1);
+  EXPECT_EQ(1, list.GetHighestPriorityWriteBlockedList());
+  list.PushBack(1, 0);
+  EXPECT_EQ(0, list.GetHighestPriorityWriteBlockedList());
+}
+
+TEST(WriteBlockedListTest, HasWriteBlockedStreamsOfGreaterThanPriority) {
+  IntWriteBlockedList list;
+  list.PushBack(1, 4);
+  EXPECT_TRUE(list.HasWriteBlockedStreamsGreaterThanPriority(5));
+  EXPECT_FALSE(list.HasWriteBlockedStreamsGreaterThanPriority(4));
+  list.PushBack(1, 2);
+  EXPECT_TRUE(list.HasWriteBlockedStreamsGreaterThanPriority(3));
+  EXPECT_FALSE(list.HasWriteBlockedStreamsGreaterThanPriority(2));
+}
+
+TEST(WriteBlockedListTest, RemoveStreamFromWriteBlockedList) {
+  IntWriteBlockedList list;
+
+  list.PushBack(1, 4);
+  EXPECT_TRUE(list.HasWriteBlockedStreams());
+
+  list.RemoveStreamFromWriteBlockedList(1, 5);
+  EXPECT_TRUE(list.HasWriteBlockedStreams());
+
+  list.PushBack(2, 4);
+  list.PushBack(1, 4);
+  list.RemoveStreamFromWriteBlockedList(1, 4);
+  list.RemoveStreamFromWriteBlockedList(2, 4);
+  EXPECT_FALSE(list.HasWriteBlockedStreams());
+
+  list.PushBack(1, 7);
+  EXPECT_TRUE(list.HasWriteBlockedStreams());
+}
+
+TEST(WriteBlockedListTest, PopFront) {
+  IntWriteBlockedList list;
+
+  list.PushBack(1, 4);
+  EXPECT_EQ(1, list.NumBlockedStreams());
+  list.PushBack(2, 4);
+  list.PushBack(1, 4);
+  list.PushBack(3, 4);
+  EXPECT_EQ(4, list.NumBlockedStreams());
+
+  EXPECT_EQ(1, list.PopFront(4));
+  EXPECT_EQ(2, list.PopFront(4));
+  EXPECT_EQ(1, list.PopFront(4));
+  EXPECT_EQ(1, list.NumBlockedStreams());
+  EXPECT_EQ(3, list.PopFront(4));
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace net
+
+
+
diff --git a/net/ssl/server_bound_cert_service.cc b/net/ssl/server_bound_cert_service.cc
index 4bc82ed..2bbcbc7 100644
--- a/net/ssl/server_bound_cert_service.cc
+++ b/net/ssl/server_bound_cert_service.cc
@@ -43,7 +43,8 @@
 const int kSystemTimeValidityBufferInDays = 90;
 
 // Used by the GetDomainBoundCertResult histogram to record the final
-// outcome of each GetDomainBoundCert call.  Do not re-use values.
+// outcome of each GetDomainBoundCert or GetOrCreateDomainBoundCert call.
+// Do not re-use values.
 enum GetCertResult {
   // Synchronously found and returned an existing domain bound cert.
   SYNC_SUCCESS = 0,
@@ -57,7 +58,8 @@
   ASYNC_FAILURE_CREATE_CERT = 4,
   ASYNC_FAILURE_EXPORT_KEY = 5,
   ASYNC_FAILURE_UNKNOWN = 6,
-  // GetDomainBoundCert was called with invalid arguments.
+  // GetDomainBoundCert or GetOrCreateDomainBoundCert was called with
+  // invalid arguments.
   INVALID_ARGUMENT = 7,
   // We don't support any of the cert types the server requested.
   UNSUPPORTED_TYPE = 8,
@@ -277,14 +279,18 @@
 // origin message loop.
 class ServerBoundCertServiceJob {
  public:
-  ServerBoundCertServiceJob() { }
+  ServerBoundCertServiceJob(bool create_if_missing)
+      : create_if_missing_(create_if_missing) {
+  }
 
   ~ServerBoundCertServiceJob() {
     if (!requests_.empty())
       DeleteAllCanceled();
   }
 
-  void AddRequest(ServerBoundCertServiceRequest* request) {
+  void AddRequest(ServerBoundCertServiceRequest* request,
+                  bool create_if_missing = false) {
+    create_if_missing_ |= create_if_missing;
     requests_.push_back(request);
   }
 
@@ -294,6 +300,8 @@
     PostAll(error, private_key, cert);
   }
 
+  bool CreateIfMissing() const { return create_if_missing_; }
+
  private:
   void PostAll(int error,
                const std::string& private_key,
@@ -320,6 +328,7 @@
   }
 
   std::vector<ServerBoundCertServiceRequest*> requests_;
+  bool create_if_missing_;
 };
 
 // static
@@ -388,6 +397,70 @@
   return domain;
 }
 
+int ServerBoundCertService::GetOrCreateDomainBoundCert(
+    const std::string& host,
+    std::string* private_key,
+    std::string* cert,
+    const CompletionCallback& callback,
+    RequestHandle* out_req) {
+  DVLOG(1) << __FUNCTION__ << " " << host;
+  DCHECK(CalledOnValidThread());
+  base::TimeTicks request_start = base::TimeTicks::Now();
+
+  if (callback.is_null() || !private_key || !cert || host.empty()) {
+    RecordGetDomainBoundCertResult(INVALID_ARGUMENT);
+    return ERR_INVALID_ARGUMENT;
+  }
+
+  std::string domain = GetDomainForHost(host);
+  if (domain.empty()) {
+    RecordGetDomainBoundCertResult(INVALID_ARGUMENT);
+    return ERR_INVALID_ARGUMENT;
+  }
+
+  requests_++;
+
+  // See if a request for the same domain is currently in flight.
+  bool create_if_missing = true;
+  if (JoinToInFlightRequest(request_start, domain, private_key, cert,
+                            create_if_missing, callback, out_req)) {
+    return ERR_IO_PENDING;
+  }
+
+  int err = LookupDomainBoundCert(request_start, domain, private_key, cert,
+                                  create_if_missing, callback, out_req);
+  if (err == ERR_FILE_NOT_FOUND) {
+    // Sync lookup did not find a valid cert.  Start generating a new one.
+    workers_created_++;
+    ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker(
+        domain,
+        base::Bind(&ServerBoundCertService::GeneratedServerBoundCert,
+                   weak_ptr_factory_.GetWeakPtr()));
+    if (!worker->Start(task_runner_)) {
+      // TODO(rkn): Log to the NetLog.
+      LOG(ERROR) << "ServerBoundCertServiceWorker couldn't be started.";
+      RecordGetDomainBoundCertResult(WORKER_FAILURE);
+      return ERR_INSUFFICIENT_RESOURCES;
+    }
+    // We are waiting for cert generation.  Create a job & request to track it.
+    ServerBoundCertServiceJob* job =
+        new ServerBoundCertServiceJob(create_if_missing);
+    inflight_[domain] = job;
+
+    ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
+        request_start,
+        base::Bind(&RequestHandle::OnRequestComplete,
+                   base::Unretained(out_req)),
+        private_key,
+        cert);
+    job->AddRequest(request);
+    out_req->RequestStarted(this, request, callback);
+    return ERR_IO_PENDING;
+  }
+
+  return err;
+}
+
 int ServerBoundCertService::GetDomainBoundCert(
     const std::string& host,
     std::string* private_key,
@@ -411,80 +484,15 @@
 
   requests_++;
 
-  // See if an identical request is currently in flight.
-  ServerBoundCertServiceJob* job = NULL;
-  std::map<std::string, ServerBoundCertServiceJob*>::const_iterator j;
-  j = inflight_.find(domain);
-  if (j != inflight_.end()) {
-    // An identical request is in flight already. We'll just attach our
-    // callback.
-    job = j->second;
-    inflight_joins_++;
-
-    ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
-        request_start,
-        base::Bind(&RequestHandle::OnRequestComplete,
-                   base::Unretained(out_req)),
-        private_key, cert);
-    job->AddRequest(request);
-    out_req->RequestStarted(this, request, callback);
+  // See if a request for the same domain currently in flight.
+  bool create_if_missing = false;
+  if (JoinToInFlightRequest(request_start, domain, private_key, cert,
+                            create_if_missing, callback, out_req)) {
     return ERR_IO_PENDING;
   }
 
-  // Check if a domain bound cert of an acceptable type already exists for this
-  // domain. Note that |expiration_time| is ignored, and expired certs are
-  // considered valid.
-  base::Time expiration_time;
-  int err = server_bound_cert_store_->GetServerBoundCert(
-      domain,
-      &expiration_time  /* ignored */,
-      private_key,
-      cert,
-      base::Bind(&ServerBoundCertService::GotServerBoundCert,
-                 weak_ptr_factory_.GetWeakPtr()));
-
-  if (err == OK) {
-    // Sync lookup found a valid cert.
-    DVLOG(1) << "Cert store had valid cert for " << domain;
-    cert_store_hits_++;
-    RecordGetDomainBoundCertResult(SYNC_SUCCESS);
-    base::TimeDelta request_time = base::TimeTicks::Now() - request_start;
-    UMA_HISTOGRAM_TIMES("DomainBoundCerts.GetCertTimeSync", request_time);
-    RecordGetCertTime(request_time);
-    return OK;
-  }
-
-  if (err == ERR_FILE_NOT_FOUND) {
-    // Sync lookup did not find a valid cert.  Start generating a new one.
-    workers_created_++;
-    ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker(
-        domain,
-        base::Bind(&ServerBoundCertService::GeneratedServerBoundCert,
-                   weak_ptr_factory_.GetWeakPtr()));
-    if (!worker->Start(task_runner_)) {
-      // TODO(rkn): Log to the NetLog.
-      LOG(ERROR) << "ServerBoundCertServiceWorker couldn't be started.";
-      RecordGetDomainBoundCertResult(WORKER_FAILURE);
-      return ERR_INSUFFICIENT_RESOURCES;
-    }
-  }
-
-  if (err == ERR_IO_PENDING || err == ERR_FILE_NOT_FOUND) {
-    // We are either waiting for async DB lookup, or waiting for cert
-    // generation.  Create a job & request to track it.
-    job = new ServerBoundCertServiceJob();
-    inflight_[domain] = job;
-
-    ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
-        request_start,
-        base::Bind(&RequestHandle::OnRequestComplete,
-                   base::Unretained(out_req)),
-        private_key, cert);
-    job->AddRequest(request);
-    out_req->RequestStarted(this, request, callback);
-    return ERR_IO_PENDING;
-  }
-
+  int err = LookupDomainBoundCert(request_start, domain, private_key, cert,
+                                  create_if_missing, callback, out_req);
   return err;
 }
 
@@ -511,7 +519,13 @@
     HandleResult(OK, server_identifier, key, cert);
     return;
   }
-  // Async lookup did not find a valid cert. Start generating a new one.
+  // Async lookup did not find a valid cert. If no request asked to create one,
+  // return the error directly.
+  if (!j->second->CreateIfMissing()) {
+    HandleResult(err, server_identifier, key, cert);
+    return;
+  }
+  // At least one request asked to create a cert => start generating a new one.
   workers_created_++;
   ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker(
       server_identifier,
@@ -524,7 +538,6 @@
                  server_identifier,
                  std::string(),
                  std::string());
-    return;
   }
 }
 
@@ -579,6 +592,86 @@
   delete job;
 }
 
+bool ServerBoundCertService::JoinToInFlightRequest(
+    const base::TimeTicks& request_start,
+    const std::string& domain,
+    std::string* private_key,
+    std::string* cert,
+    bool create_if_missing,
+    const CompletionCallback& callback,
+    RequestHandle* out_req) {
+  ServerBoundCertServiceJob* job = NULL;
+  std::map<std::string, ServerBoundCertServiceJob*>::const_iterator j =
+      inflight_.find(domain);
+  if (j != inflight_.end()) {
+    // A request for the same domain is in flight already. We'll attach our
+    // callback, but we'll also mark it as requiring a cert if one's mising.
+    job = j->second;
+    inflight_joins_++;
+
+    ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
+        request_start,
+        base::Bind(&RequestHandle::OnRequestComplete,
+                   base::Unretained(out_req)),
+        private_key,
+        cert);
+    job->AddRequest(request, create_if_missing);
+    out_req->RequestStarted(this, request, callback);
+    return true;
+  }
+  return false;
+}
+
+int ServerBoundCertService::LookupDomainBoundCert(
+    const base::TimeTicks& request_start,
+    const std::string& domain,
+    std::string* private_key,
+    std::string* cert,
+    bool create_if_missing,
+    const CompletionCallback& callback,
+    RequestHandle* out_req) {
+  // Check if a domain bound cert already exists for this domain. Note that
+  // |expiration_time| is ignored, and expired certs are considered valid.
+  base::Time expiration_time;
+  int err = server_bound_cert_store_->GetServerBoundCert(
+      domain,
+      &expiration_time  /* ignored */,
+      private_key,
+      cert,
+      base::Bind(&ServerBoundCertService::GotServerBoundCert,
+                 weak_ptr_factory_.GetWeakPtr()));
+
+  if (err == OK) {
+    // Sync lookup found a valid cert.
+    DVLOG(1) << "Cert store had valid cert for " << domain;
+    cert_store_hits_++;
+    RecordGetDomainBoundCertResult(SYNC_SUCCESS);
+    base::TimeDelta request_time = base::TimeTicks::Now() - request_start;
+    UMA_HISTOGRAM_TIMES("DomainBoundCerts.GetCertTimeSync", request_time);
+    RecordGetCertTime(request_time);
+    return OK;
+  }
+
+  if (err == ERR_IO_PENDING) {
+    // We are waiting for async DB lookup.  Create a job & request to track it.
+    ServerBoundCertServiceJob* job =
+        new ServerBoundCertServiceJob(create_if_missing);
+    inflight_[domain] = job;
+
+    ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
+        request_start,
+        base::Bind(&RequestHandle::OnRequestComplete,
+                   base::Unretained(out_req)),
+        private_key,
+        cert);
+    job->AddRequest(request);
+    out_req->RequestStarted(this, request, callback);
+    return ERR_IO_PENDING;
+  }
+
+  return err;
+}
+
 int ServerBoundCertService::cert_count() {
   return server_bound_cert_store_->GetCertCount();
 }
diff --git a/net/ssl/server_bound_cert_service.h b/net/ssl/server_bound_cert_service.h
index d931ec8..0dc7f4a 100644
--- a/net/ssl/server_bound_cert_service.h
+++ b/net/ssl/server_bound_cert_service.h
@@ -106,6 +106,31 @@
   // |*out_req| will be initialized with a handle to the async request. This
   // RequestHandle object must be cancelled or destroyed before the
   // ServerBoundCertService is destroyed.
+  int GetOrCreateDomainBoundCert(
+      const std::string& host,
+      std::string* private_key,
+      std::string* cert,
+      const CompletionCallback& callback,
+      RequestHandle* out_req);
+
+  // Fetches the domain bound cert for the specified host if one exists.
+  // Returns OK if successful, ERR_FILE_NOT_FOUND if none exists, or an error
+  // code upon failure.
+  //
+  // On successful completion, |private_key| stores a DER-encoded
+  // PrivateKeyInfo struct, and |cert| stores a DER-encoded certificate.
+  // The PrivateKeyInfo is always an ECDSA private key.
+  //
+  // |callback| must not be null. ERR_IO_PENDING is returned if the operation
+  // could not be completed immediately, in which case the result code will
+  // be passed to the callback when available. If an in-flight
+  // GetDomainBoundCert is pending, and a new GetOrCreateDomainBoundCert
+  // request arrives for the same domain, the GetDomainBoundCert request will
+  // not complete until a new cert is created.
+  //
+  // |*out_req| will be initialized with a handle to the async request. This
+  // RequestHandle object must be cancelled or destroyed before the
+  // ServerBoundCertService is destroyed.
   int GetDomainBoundCert(
       const std::string& host,
       std::string* private_key,
@@ -143,6 +168,29 @@
                     const std::string& private_key,
                     const std::string& cert);
 
+  // Searches for an in-flight request for the same domain. If found,
+  // attaches to the request and returns true. Returns false if no in-flight
+  // request is found.
+  bool JoinToInFlightRequest(const base::TimeTicks& request_start,
+                             const std::string& domain,
+                             std::string* private_key,
+                             std::string* cert,
+                             bool create_if_missing,
+                             const CompletionCallback& callback,
+                             RequestHandle* out_req);
+
+  // Looks for the domain bound cert for |domain| in this service's store.
+  // Returns OK if it can be found synchronously, ERR_IO_PENDING if the
+  // result cannot be obtained synchronously, or a network error code on
+  // failure (including failure to find a domain-bound cert of |domain|).
+  int LookupDomainBoundCert(const base::TimeTicks& request_start,
+                            const std::string& domain,
+                            std::string* private_key,
+                            std::string* cert,
+                            bool create_if_missing,
+                            const CompletionCallback& callback,
+                            RequestHandle* out_req);
+
   scoped_ptr<ServerBoundCertStore> server_bound_cert_store_;
   scoped_refptr<base::TaskRunner> task_runner_;
 
diff --git a/net/ssl/server_bound_cert_service_unittest.cc b/net/ssl/server_bound_cert_service_unittest.cc
index d7b8553..fc25b0b 100644
--- a/net/ssl/server_bound_cert_service_unittest.cc
+++ b/net/ssl/server_bound_cert_service_unittest.cc
@@ -10,8 +10,8 @@
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/task_runner.h"
-#include "base/threading/sequenced_worker_pool.h"
 #include "crypto/ec_private_key.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -28,23 +28,37 @@
   FAIL();
 }
 
+// Simple task runner that refuses to actually post any tasks. This simulates
+// a TaskRunner that has been shutdown, by returning false for any attempt to
+// add new tasks.
+class FailingTaskRunner : public base::TaskRunner {
+ public:
+  FailingTaskRunner() {}
+
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const base::Closure& task,
+                               base::TimeDelta delay) OVERRIDE {
+    return false;
+  }
+
+  virtual bool RunsTasksOnCurrentThread() const OVERRIDE { return true; }
+
+ protected:
+  virtual ~FailingTaskRunner() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FailingTaskRunner);
+};
+
 class ServerBoundCertServiceTest : public testing::Test {
  public:
   ServerBoundCertServiceTest()
-      : sequenced_worker_pool_(new base::SequencedWorkerPool(
-            3, "ServerBoundCertServiceTest")),
-        service_(new ServerBoundCertService(
+      : service_(new ServerBoundCertService(
             new DefaultServerBoundCertStore(NULL),
-            sequenced_worker_pool_)) {
-  }
-
-  virtual ~ServerBoundCertServiceTest() {
-    if (sequenced_worker_pool_.get())
-      sequenced_worker_pool_->Shutdown();
+            base::MessageLoopProxy::current())) {
   }
 
  protected:
-  scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool_;
   scoped_ptr<ServerBoundCertService> service_;
 };
 
@@ -136,6 +150,24 @@
 // See http://crbug.com/91512 - implement OpenSSL version of CreateSelfSigned.
 #if !defined(USE_OPENSSL)
 
+TEST_F(ServerBoundCertServiceTest, GetCacheMiss) {
+  std::string host("encrypted.google.com");
+
+  int error;
+  TestCompletionCallback callback;
+  ServerBoundCertService::RequestHandle request_handle;
+
+  // Synchronous completion, because the store is initialized.
+  std::string private_key, der_cert;
+  EXPECT_EQ(0, service_->cert_count());
+  error = service_->GetDomainBoundCert(
+      host, &private_key, &der_cert, callback.callback(), &request_handle);
+  EXPECT_EQ(ERR_FILE_NOT_FOUND, error);
+  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_EQ(0, service_->cert_count());
+  EXPECT_TRUE(der_cert.empty());
+}
+
 TEST_F(ServerBoundCertServiceTest, CacheHit) {
   std::string host("encrypted.google.com");
 
@@ -146,7 +178,7 @@
   // Asynchronous completion.
   std::string private_key_info1, der_cert1;
   EXPECT_EQ(0, service_->cert_count());
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host, &private_key_info1, &der_cert1,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
@@ -160,7 +192,7 @@
 
   // Synchronous completion.
   std::string private_key_info2, der_cert2;
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host, &private_key_info2, &der_cert2,
       callback.callback(), &request_handle);
   EXPECT_FALSE(request_handle.is_active());
@@ -169,8 +201,19 @@
   EXPECT_EQ(private_key_info1, private_key_info2);
   EXPECT_EQ(der_cert1, der_cert2);
 
-  EXPECT_EQ(2u, service_->requests());
-  EXPECT_EQ(1u, service_->cert_store_hits());
+  // Synchronous get.
+  std::string private_key_info3, der_cert3;
+  error = service_->GetDomainBoundCert(
+      host, &private_key_info3, &der_cert3, callback.callback(),
+      &request_handle);
+  EXPECT_FALSE(request_handle.is_active());
+  EXPECT_EQ(OK, error);
+  EXPECT_EQ(1, service_->cert_count());
+  EXPECT_EQ(der_cert1, der_cert3);
+  EXPECT_EQ(private_key_info1, private_key_info3);
+
+  EXPECT_EQ(3u, service_->requests());
+  EXPECT_EQ(2u, service_->cert_store_hits());
   EXPECT_EQ(0u, service_->inflight_joins());
 }
 
@@ -182,7 +225,7 @@
   std::string host1("encrypted.google.com");
   std::string private_key_info1, der_cert1;
   EXPECT_EQ(0, service_->cert_count());
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host1, &private_key_info1, &der_cert1,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
@@ -193,7 +236,7 @@
 
   std::string host2("www.verisign.com");
   std::string private_key_info2, der_cert2;
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host2, &private_key_info2, &der_cert2,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
@@ -204,7 +247,7 @@
 
   std::string host3("www.twitter.com");
   std::string private_key_info3, der_cert3;
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host3, &private_key_info3, &der_cert3,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
@@ -234,13 +277,13 @@
   TestCompletionCallback callback2;
   ServerBoundCertService::RequestHandle request_handle2;
 
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host, &private_key_info1, &der_cert1,
       callback1.callback(), &request_handle1);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle1.is_active());
   // Should join with the original request.
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host, &private_key_info2, &der_cert2,
       callback2.callback(), &request_handle2);
   EXPECT_EQ(ERR_IO_PENDING, error);
@@ -254,6 +297,45 @@
   EXPECT_EQ(2u, service_->requests());
   EXPECT_EQ(0u, service_->cert_store_hits());
   EXPECT_EQ(1u, service_->inflight_joins());
+  EXPECT_EQ(1u, service_->workers_created());
+}
+
+// Tests an inflight join of a Get request to a GetOrCreate request.
+TEST_F(ServerBoundCertServiceTest, InflightJoinGetOrCreateAndGet) {
+  std::string host("encrypted.google.com");
+  int error;
+
+  std::string private_key_info1, der_cert1;
+  TestCompletionCallback callback1;
+  ServerBoundCertService::RequestHandle request_handle1;
+
+  std::string private_key_info2;
+  std::string der_cert2;
+  TestCompletionCallback callback2;
+  ServerBoundCertService::RequestHandle request_handle2;
+
+  error = service_->GetOrCreateDomainBoundCert(
+      host, &private_key_info1, &der_cert1,
+      callback1.callback(), &request_handle1);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle1.is_active());
+  // Should join with the original request.
+  error = service_->GetDomainBoundCert(
+      host, &private_key_info2, &der_cert2, callback2.callback(),
+      &request_handle2);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle2.is_active());
+
+  error = callback1.WaitForResult();
+  EXPECT_EQ(OK, error);
+  error = callback2.WaitForResult();
+  EXPECT_EQ(OK, error);
+  EXPECT_EQ(der_cert1, der_cert2);
+
+  EXPECT_EQ(2u, service_->requests());
+  EXPECT_EQ(0u, service_->cert_store_hits());
+  EXPECT_EQ(1u, service_->inflight_joins());
+  EXPECT_EQ(1u, service_->workers_created());
 }
 
 TEST_F(ServerBoundCertServiceTest, ExtractValuesFromBytesEC) {
@@ -263,7 +345,7 @@
   TestCompletionCallback callback;
   ServerBoundCertService::RequestHandle request_handle;
 
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host, &private_key_info, &der_cert, callback.callback(),
       &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
@@ -297,18 +379,16 @@
   int error;
   ServerBoundCertService::RequestHandle request_handle;
 
-  error = service_->GetDomainBoundCert(host,
-                                      &private_key_info,
-                                      &der_cert,
-                                      base::Bind(&FailTest),
-                                      &request_handle);
+  error = service_->GetOrCreateDomainBoundCert(host,
+                                               &private_key_info,
+                                               &der_cert,
+                                               base::Bind(&FailTest),
+                                               &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
   request_handle.Cancel();
   EXPECT_FALSE(request_handle.is_active());
 
-  // Wait for generation to finish.
-  sequenced_worker_pool_->FlushForTesting();
   // Wait for reply from ServerBoundCertServiceWorker to be posted back to the
   // ServerBoundCertService.
   base::MessageLoop::current()->RunUntilIdle();
@@ -326,17 +406,15 @@
   {
     ServerBoundCertService::RequestHandle request_handle;
 
-    error = service_->GetDomainBoundCert(host,
-                                         &private_key_info,
-                                         &der_cert,
-                                         base::Bind(&FailTest),
-                                         &request_handle);
+    error = service_->GetOrCreateDomainBoundCert(host,
+                                                 &private_key_info,
+                                                 &der_cert,
+                                                 base::Bind(&FailTest),
+                                                 &request_handle);
     EXPECT_EQ(ERR_IO_PENDING, error);
     EXPECT_TRUE(request_handle.is_active());
   }
 
-  // Wait for generation to finish.
-  sequenced_worker_pool_->FlushForTesting();
   // Wait for reply from ServerBoundCertServiceWorker to be posted back to the
   // ServerBoundCertService.
   base::MessageLoop::current()->RunUntilIdle();
@@ -352,11 +430,11 @@
   int error;
   ServerBoundCertService::RequestHandle request_handle;
 
-  error = service_->GetDomainBoundCert(host,
-                                       &private_key_info,
-                                       &der_cert,
-                                       base::Bind(&FailTest),
-                                       &request_handle);
+  error = service_->GetOrCreateDomainBoundCert(host,
+                                               &private_key_info,
+                                               &der_cert,
+                                               base::Bind(&FailTest),
+                                               &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
 
@@ -364,10 +442,8 @@
   request_handle.Cancel();
   service_.reset();
 
-  // Wait for generation to finish.
-  sequenced_worker_pool_->FlushForTesting();
   // ServerBoundCertServiceWorker should not post anything back to the
-  // non-existant ServerBoundCertService, but run the loop just to be sure it
+  // non-existent ServerBoundCertService, but run the loop just to be sure it
   // doesn't.
   base::MessageLoop::current()->RunUntilIdle();
 
@@ -378,12 +454,9 @@
 // requests gracefully fails.
 // This is a regression test for http://crbug.com/236387
 TEST_F(ServerBoundCertServiceTest, RequestAfterPoolShutdown) {
-  // Shutdown the pool immediately.
-  sequenced_worker_pool_->Shutdown();
-  sequenced_worker_pool_ = NULL;
-
-  // Ensure any shutdown code is processed.
-  base::MessageLoop::current()->RunUntilIdle();
+  scoped_refptr<FailingTaskRunner> task_runner(new FailingTaskRunner);
+  service_.reset(new ServerBoundCertService(
+      new DefaultServerBoundCertStore(NULL), task_runner));
 
   // Make a request that will force synchronous completion.
   std::string host("encrypted.google.com");
@@ -391,11 +464,11 @@
   int error;
   ServerBoundCertService::RequestHandle request_handle;
 
-  error = service_->GetDomainBoundCert(host,
-                                       &private_key_info,
-                                       &der_cert,
-                                       base::Bind(&FailTest),
-                                       &request_handle);
+  error = service_->GetOrCreateDomainBoundCert(host,
+                                               &private_key_info,
+                                               &der_cert,
+                                               base::Bind(&FailTest),
+                                               &request_handle);
   // If we got here without crashing or a valgrind error, it worked.
   ASSERT_EQ(ERR_INSUFFICIENT_RESOURCES, error);
   EXPECT_FALSE(request_handle.is_active());
@@ -420,27 +493,27 @@
   TestCompletionCallback callback3;
   ServerBoundCertService::RequestHandle request_handle3;
 
-  error = service_->GetDomainBoundCert(host1,
-                                       &private_key_info1,
-                                       &der_cert1,
-                                       callback1.callback(),
-                                       &request_handle1);
+  error = service_->GetOrCreateDomainBoundCert(host1,
+                                               &private_key_info1,
+                                               &der_cert1,
+                                               callback1.callback(),
+                                               &request_handle1);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle1.is_active());
 
-  error = service_->GetDomainBoundCert(host2,
-                                       &private_key_info2,
-                                       &der_cert2,
-                                       callback2.callback(),
-                                       &request_handle2);
+  error = service_->GetOrCreateDomainBoundCert(host2,
+                                               &private_key_info2,
+                                               &der_cert2,
+                                               callback2.callback(),
+                                               &request_handle2);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle2.is_active());
 
-  error = service_->GetDomainBoundCert(host3,
-                                       &private_key_info3,
-                                       &der_cert3,
-                                       callback3.callback(),
-                                       &request_handle3);
+  error = service_->GetOrCreateDomainBoundCert(host3,
+                                               &private_key_info3,
+                                               &der_cert3,
+                                               callback3.callback(),
+                                               &request_handle3);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle3.is_active());
 
@@ -492,7 +565,7 @@
 
   // Cert is valid - synchronous completion.
   std::string private_key_info1, der_cert1;
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       "good", &private_key_info1, &der_cert1,
       callback.callback(), &request_handle);
   EXPECT_EQ(OK, error);
@@ -503,7 +576,7 @@
 
   // Expired cert is valid as well - synchronous completion.
   std::string private_key_info2, der_cert2;
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       "expired", &private_key_info2, &der_cert2,
       callback.callback(), &request_handle);
   EXPECT_EQ(OK, error);
@@ -513,11 +586,11 @@
   EXPECT_STREQ("d", der_cert2.c_str());
 }
 
-TEST_F(ServerBoundCertServiceTest, AsyncStoreGetNoCertsInStore) {
+TEST_F(ServerBoundCertServiceTest, AsyncStoreGetOrCreateNoCertsInStore) {
   MockServerBoundCertStoreWithAsyncGet* mock_store =
       new MockServerBoundCertStoreWithAsyncGet();
-  service_ = scoped_ptr<ServerBoundCertService>(
-      new ServerBoundCertService(mock_store, sequenced_worker_pool_));
+  service_ = scoped_ptr<ServerBoundCertService>(new ServerBoundCertService(
+      mock_store, base::MessageLoopProxy::current()));
 
   std::string host("encrypted.google.com");
 
@@ -528,7 +601,7 @@
   // Asynchronous completion with no certs in the store.
   std::string private_key_info, der_cert;
   EXPECT_EQ(0, service_->cert_count());
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host, &private_key_info, &der_cert, callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
@@ -544,11 +617,42 @@
   EXPECT_FALSE(request_handle.is_active());
 }
 
-TEST_F(ServerBoundCertServiceTest, AsyncStoreGetOneCertInStore) {
+TEST_F(ServerBoundCertServiceTest, AsyncStoreGetNoCertsInStore) {
   MockServerBoundCertStoreWithAsyncGet* mock_store =
       new MockServerBoundCertStoreWithAsyncGet();
-  service_ = scoped_ptr<ServerBoundCertService>(
-      new ServerBoundCertService(mock_store, sequenced_worker_pool_));
+  service_ = scoped_ptr<ServerBoundCertService>(new ServerBoundCertService(
+      mock_store, base::MessageLoopProxy::current()));
+
+  std::string host("encrypted.google.com");
+
+  int error;
+  TestCompletionCallback callback;
+  ServerBoundCertService::RequestHandle request_handle;
+
+  // Asynchronous completion with no certs in the store.
+  std::string private_key, der_cert;
+  EXPECT_EQ(0, service_->cert_count());
+  error = service_->GetDomainBoundCert(
+      host, &private_key, &der_cert, callback.callback(), &request_handle);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle.is_active());
+
+  mock_store->CallGetServerBoundCertCallbackWithResult(
+      ERR_FILE_NOT_FOUND, base::Time(), std::string(), std::string());
+
+  error = callback.WaitForResult();
+  EXPECT_EQ(ERR_FILE_NOT_FOUND, error);
+  EXPECT_EQ(0, service_->cert_count());
+  EXPECT_EQ(0u, service_->workers_created());
+  EXPECT_TRUE(der_cert.empty());
+  EXPECT_FALSE(request_handle.is_active());
+}
+
+TEST_F(ServerBoundCertServiceTest, AsyncStoreGetOrCreateOneCertInStore) {
+  MockServerBoundCertStoreWithAsyncGet* mock_store =
+      new MockServerBoundCertStoreWithAsyncGet();
+  service_ = scoped_ptr<ServerBoundCertService>(new ServerBoundCertService(
+      mock_store, base::MessageLoopProxy::current()));
 
   std::string host("encrypted.google.com");
 
@@ -559,7 +663,7 @@
   // Asynchronous completion with a cert in the store.
   std::string private_key_info, der_cert;
   EXPECT_EQ(0, service_->cert_count());
-  error = service_->GetDomainBoundCert(
+  error = service_->GetOrCreateDomainBoundCert(
       host, &private_key_info, &der_cert, callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
@@ -580,6 +684,94 @@
   EXPECT_FALSE(request_handle.is_active());
 }
 
+TEST_F(ServerBoundCertServiceTest, AsyncStoreGetOneCertInStore) {
+  MockServerBoundCertStoreWithAsyncGet* mock_store =
+      new MockServerBoundCertStoreWithAsyncGet();
+  service_ = scoped_ptr<ServerBoundCertService>(new ServerBoundCertService(
+      mock_store, base::MessageLoopProxy::current()));
+
+  std::string host("encrypted.google.com");
+
+  int error;
+  TestCompletionCallback callback;
+  ServerBoundCertService::RequestHandle request_handle;
+
+  // Asynchronous completion with a cert in the store.
+  std::string private_key, der_cert;
+  EXPECT_EQ(0, service_->cert_count());
+  error = service_->GetDomainBoundCert(
+      host, &private_key, &der_cert, callback.callback(), &request_handle);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle.is_active());
+
+  mock_store->CallGetServerBoundCertCallbackWithResult(
+      OK, base::Time(), "ab", "cd");
+
+  error = callback.WaitForResult();
+  EXPECT_EQ(OK, error);
+  EXPECT_EQ(1, service_->cert_count());
+  EXPECT_EQ(1u, service_->requests());
+  EXPECT_EQ(1u, service_->cert_store_hits());
+  // Because the cert was found in the store, no new workers should have been
+  // created.
+  EXPECT_EQ(0u, service_->workers_created());
+  EXPECT_STREQ("cd", der_cert.c_str());
+  EXPECT_FALSE(request_handle.is_active());
+}
+
+TEST_F(ServerBoundCertServiceTest, AsyncStoreGetThenCreateNoCertsInStore) {
+  MockServerBoundCertStoreWithAsyncGet* mock_store =
+      new MockServerBoundCertStoreWithAsyncGet();
+  service_ = scoped_ptr<ServerBoundCertService>(new ServerBoundCertService(
+      mock_store, base::MessageLoopProxy::current()));
+
+  std::string host("encrypted.google.com");
+
+  int error;
+
+  // Asynchronous get with no certs in the store.
+  TestCompletionCallback callback1;
+  ServerBoundCertService::RequestHandle request_handle1;
+  std::string private_key1, der_cert1;
+  EXPECT_EQ(0, service_->cert_count());
+  error = service_->GetDomainBoundCert(
+      host, &private_key1, &der_cert1, callback1.callback(), &request_handle1);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle1.is_active());
+
+  // Asynchronous get/create with no certs in the store.
+  TestCompletionCallback callback2;
+  ServerBoundCertService::RequestHandle request_handle2;
+  std::string private_key2, der_cert2;
+  EXPECT_EQ(0, service_->cert_count());
+  error = service_->GetOrCreateDomainBoundCert(
+      host, &private_key2, &der_cert2, callback2.callback(), &request_handle2);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle2.is_active());
+
+  mock_store->CallGetServerBoundCertCallbackWithResult(
+      ERR_FILE_NOT_FOUND, base::Time(), std::string(), std::string());
+
+  // Even though the first request didn't ask to create a cert, it gets joined
+  // by the second, which does, so both succeed.
+  error = callback1.WaitForResult();
+  EXPECT_EQ(OK, error);
+  error = callback2.WaitForResult();
+  EXPECT_EQ(OK, error);
+
+  // One cert is created, one request is joined.
+  EXPECT_EQ(2U, service_->requests());
+  EXPECT_EQ(1, service_->cert_count());
+  EXPECT_EQ(1u, service_->workers_created());
+  EXPECT_EQ(1u, service_->inflight_joins());
+  EXPECT_FALSE(der_cert1.empty());
+  EXPECT_EQ(der_cert1, der_cert2);
+  EXPECT_FALSE(private_key1.empty());
+  EXPECT_EQ(private_key1, private_key2);
+  EXPECT_FALSE(request_handle1.is_active());
+  EXPECT_FALSE(request_handle2.is_active());
+}
+
 #endif  // !defined(USE_OPENSSL)
 
 }  // namespace
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index c13745b..b8697d4 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -171,7 +171,11 @@
   scoped_ptr<HostResolver> resolver(HostResolver::CreateDefaultResolver(NULL));
   HostResolver::RequestInfo info(host_port_pair_);
   TestCompletionCallback callback;
-  int rv = resolver->Resolve(info, address_list, callback.callback(), NULL,
+  int rv = resolver->Resolve(info,
+                             DEFAULT_PRIORITY,
+                             address_list,
+                             callback.callback(),
+                             NULL,
                              BoundNetLog());
   if (rv == ERR_IO_PENDING)
     rv = callback.WaitForResult();
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium
index aad42b5..11a8510 100644
--- a/net/third_party/nss/README.chromium
+++ b/net/third_party/nss/README.chromium
@@ -74,6 +74,8 @@
     NSS that doesn't contain the CBC constant-time changes.
     patches/cbc.patch
     https://code.google.com/p/chromium/issues/detail?id=172658#c12
+    TODO(wtc): remove this patch now that NSS 3.14.3 is the minimum
+    compile-time and run-time version.
 
   * Change ssl3_SuiteBOnly to always return PR_TRUE. The softoken in NSS
     versions older than 3.15 report an EC key size range of 112 bits to 571
@@ -97,6 +99,14 @@
     https://bugzilla.mozilla.org/show_bug.cgi?id=903565
     patches/sslsock_903565.patch
 
+  * Implement the AES GCM cipher suites.
+    https://bugzilla.mozilla.org/show_bug.cgi?id=880543
+    patches/aesgcm.patch
+
+  * Add Chromium-specific code to detect AES GCM support in the system NSS
+    libraries at run time.
+    patches/aesgcmchromium.patch
+
 Apply the patches to NSS by running the patches/applypatches.sh script.  Read
 the comments at the top of patches/applypatches.sh for instructions.
 
diff --git a/net/third_party/nss/patches/aesgcm.patch b/net/third_party/nss/patches/aesgcm.patch
new file mode 100644
index 0000000..03fdf8e
--- /dev/null
+++ b/net/third_party/nss/patches/aesgcm.patch
@@ -0,0 +1,1363 @@
+Index: net/third_party/nss/ssl/sslinfo.c
+===================================================================
+--- net/third_party/nss/ssl/sslinfo.c	(revision 217715)
++++ net/third_party/nss/ssl/sslinfo.c	(working copy)
+@@ -109,7 +109,7 @@
+ #define K_ECDHE	"ECDHE", kt_ecdh
+ 
+ #define C_SEED 	"SEED", calg_seed
+-#define C_CAMELLIA	"CAMELLIA", calg_camellia
++#define C_CAMELLIA "CAMELLIA", calg_camellia
+ #define C_AES	"AES", calg_aes
+ #define C_RC4	"RC4", calg_rc4
+ #define C_RC2	"RC2", calg_rc2
+@@ -117,6 +117,7 @@
+ #define C_3DES	"3DES", calg_3des
+ #define C_NULL  "NULL", calg_null
+ #define C_SJ 	"SKIPJACK", calg_sj
++#define C_AESGCM "AES-GCM", calg_aes_gcm
+ 
+ #define B_256	256, 256, 256
+ #define B_128	128, 128, 128
+@@ -127,12 +128,16 @@
+ #define B_40    128,  40,  40
+ #define B_0  	  0,   0,   0
+ 
++#define M_AEAD_128 "AEAD", ssl_mac_aead, 128
+ #define M_SHA256 "SHA256", ssl_hmac_sha256, 256
+ #define M_SHA	"SHA1", ssl_mac_sha, 160
+ #define M_MD5	"MD5",  ssl_mac_md5, 128
++#define M_NULL	"NULL", ssl_mac_null,  0
+ 
+ static const SSLCipherSuiteInfo suiteInfo[] = {
+ /* <------ Cipher suite --------------------> <auth> <KEA>  <bulk cipher> <MAC> <FIPS> */
++{0,CS(TLS_RSA_WITH_AES_128_GCM_SHA256),       S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
++
+ {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
+ {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
+ {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0, },
+@@ -146,6 +151,7 @@
+ {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
+ {0,CS(TLS_DHE_DSS_WITH_RC4_128_SHA),          S_DSA, K_DHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
+ {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
++{0,CS(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256),   S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
+ {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA),      S_RSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
+ {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA),      S_DSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
+ {0,CS(TLS_RSA_WITH_SEED_CBC_SHA),             S_RSA, K_RSA, C_SEED,B_128, M_SHA, 1, 0, 0, },
+@@ -175,6 +181,9 @@
+ 
+ #ifdef NSS_ENABLE_ECC
+ /* ECC cipher suites */
++{0,CS(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
++{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
++
+ {0,CS(TLS_ECDH_ECDSA_WITH_NULL_SHA),          S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, },
+ {0,CS(TLS_ECDH_ECDSA_WITH_RC4_128_SHA),       S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, },
+ {0,CS(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA),  S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
+Index: net/third_party/nss/ssl/sslimpl.h
+===================================================================
+--- net/third_party/nss/ssl/sslimpl.h	(revision 217715)
++++ net/third_party/nss/ssl/sslimpl.h	(working copy)
+@@ -64,6 +64,7 @@
+ #define calg_aes	ssl_calg_aes
+ #define calg_camellia	ssl_calg_camellia
+ #define calg_seed	ssl_calg_seed
++#define calg_aes_gcm    ssl_calg_aes_gcm
+ 
+ #define mac_null	ssl_mac_null
+ #define mac_md5 	ssl_mac_md5
+@@ -71,6 +72,7 @@
+ #define hmac_md5	ssl_hmac_md5
+ #define hmac_sha	ssl_hmac_sha
+ #define hmac_sha256	ssl_hmac_sha256
++#define mac_aead	ssl_mac_aead
+ 
+ #define SET_ERROR_CODE		/* reminder */
+ #define SEND_ALERT		/* reminder */
+@@ -290,9 +292,9 @@
+ } ssl3CipherSuiteCfg;
+ 
+ #ifdef NSS_ENABLE_ECC
+-#define ssl_V3_SUITES_IMPLEMENTED 57
++#define ssl_V3_SUITES_IMPLEMENTED 61
+ #else
+-#define ssl_V3_SUITES_IMPLEMENTED 35
++#define ssl_V3_SUITES_IMPLEMENTED 37
+ #endif /* NSS_ENABLE_ECC */
+ 
+ #define MAX_DTLS_SRTP_CIPHER_SUITES 4
+@@ -440,20 +442,6 @@
+ #define GS_DATA		3
+ #define GS_PAD		4
+ 
+-typedef SECStatus (*SSLCipher)(void *               context, 
+-                               unsigned char *      out,
+-			       int *                outlen, 
+-			       int                  maxout, 
+-			       const unsigned char *in,
+-			       int                  inlen);
+-typedef SECStatus (*SSLCompressor)(void *               context,
+-                                   unsigned char *      out,
+-                                   int *                outlen,
+-                                   int                  maxout,
+-                                   const unsigned char *in,
+-                                   int                  inlen);
+-typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
+-
+ #if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_WIN32)
+ typedef PCERT_KEY_CONTEXT PlatformKey;
+ #elif defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_MACOSX)
+@@ -485,11 +473,12 @@
+     cipher_camellia_128,
+     cipher_camellia_256,
+     cipher_seed,
++    cipher_aes_128_gcm,
+     cipher_missing              /* reserved for no such supported cipher */
+     /* This enum must match ssl3_cipherName[] in ssl3con.c.  */
+ } SSL3BulkCipher;
+ 
+-typedef enum { type_stream, type_block } CipherType;
++typedef enum { type_stream, type_block, type_aead } CipherType;
+ 
+ #define MAX_IV_LENGTH 24
+ 
+@@ -531,6 +520,30 @@
+     PRUint64    cipher_context[MAX_CIPHER_CONTEXT_LLONGS];
+ } ssl3KeyMaterial;
+ 
++typedef SECStatus (*SSLCipher)(void *               context, 
++                               unsigned char *      out,
++			       int *                outlen, 
++			       int                  maxout, 
++			       const unsigned char *in,
++			       int                  inlen);
++typedef SECStatus (*SSLAEADCipher)(
++			       ssl3KeyMaterial *    keys,
++			       PRBool               doDecrypt,
++			       unsigned char *      out,
++			       int *                outlen,
++			       int                  maxout,
++			       const unsigned char *in,
++			       int                  inlen,
++			       const unsigned char *additionalData,
++			       int                  additionalDataLen);
++typedef SECStatus (*SSLCompressor)(void *               context,
++                                   unsigned char *      out,
++                                   int *                outlen,
++                                   int                  maxout,
++                                   const unsigned char *in,
++                                   int                  inlen);
++typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
++
+ /* The DTLS anti-replay window. Defined here because we need it in
+  * the cipher spec. Note that this is a ring buffer but left and
+  * right represent the true window, with modular arithmetic used to
+@@ -557,6 +570,7 @@
+     int                mac_size;
+     SSLCipher          encode;
+     SSLCipher          decode;
++    SSLAEADCipher      aead;
+     SSLDestroy         destroy;
+     void *             encodeContext;
+     void *             decodeContext;
+@@ -706,8 +720,6 @@
+     PRBool                   tls_keygen;
+ } ssl3KEADef;
+ 
+-typedef enum { kg_null, kg_strong, kg_export } SSL3KeyGenMode;
+-
+ /*
+ ** There are tables of these, all const.
+ */
+@@ -719,7 +731,8 @@
+     CipherType      type;
+     int             iv_size;
+     int             block_size;
+-    SSL3KeyGenMode  keygen_mode;
++    int             tag_size;  /* authentication tag size for AEAD ciphers. */
++    int             explicit_nonce_size;               /* for AEAD ciphers. */
+ };
+ 
+ /*
+Index: net/third_party/nss/ssl/ssl3ecc.c
+===================================================================
+--- net/third_party/nss/ssl/ssl3ecc.c	(revision 217715)
++++ net/third_party/nss/ssl/ssl3ecc.c	(working copy)
+@@ -911,6 +911,7 @@
+     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
++    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+     TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+@@ -921,6 +922,7 @@
+     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
++    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+     TLS_ECDHE_RSA_WITH_NULL_SHA,
+     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+@@ -932,12 +934,14 @@
+     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
++    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+     TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
++    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+     TLS_ECDHE_RSA_WITH_NULL_SHA,
+     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+Index: net/third_party/nss/ssl/sslsock.c
+===================================================================
+--- net/third_party/nss/ssl/sslsock.c	(revision 217715)
++++ net/third_party/nss/ssl/sslsock.c	(working copy)
+@@ -67,8 +67,10 @@
+  {  TLS_DHE_DSS_WITH_AES_128_CBC_SHA, 	    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_DHE_RSA_WITH_AES_128_CBC_SHA,       SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
++ {  TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_RSA_WITH_AES_128_CBC_SHA,     	    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_RSA_WITH_AES_128_CBC_SHA256,        SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
++ {  TLS_RSA_WITH_AES_128_GCM_SHA256,        SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_DHE_DSS_WITH_AES_256_CBC_SHA, 	    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_DHE_RSA_WITH_AES_256_CBC_SHA,       SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+@@ -94,6 +96,7 @@
+  {  TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,  SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,   SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
++ {  TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,   SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_ECDH_RSA_WITH_NULL_SHA,             SSL_ALLOWED,     SSL_ALLOWED },
+  {  TLS_ECDH_RSA_WITH_RC4_128_SHA,          SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+@@ -105,6 +108,7 @@
+  {  TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,     SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,  SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
++ {  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,  SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+  {  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,     SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ #endif /* NSS_ENABLE_ECC */
+  {  0,					    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }
+Index: net/third_party/nss/ssl/ssl3con.c
+===================================================================
+--- net/third_party/nss/ssl/ssl3con.c	(revision 217715)
++++ net/third_party/nss/ssl/ssl3con.c	(working copy)
+@@ -78,6 +78,13 @@
+ static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
+ 			     int maxOutputLen, const unsigned char *input,
+ 			     int inputLen);
++#ifndef NO_PKCS11_BYPASS
++static SECStatus ssl3_AESGCMBypass(ssl3KeyMaterial *keys, PRBool doDecrypt,
++				   unsigned char *out, int *outlen, int maxout,
++				   const unsigned char *in, int inlen,
++				   const unsigned char *additionalData,
++				   int additionalDataLen);
++#endif
+ 
+ #define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */
+ #define MIN_SEND_BUF_LENGTH  4000
+@@ -90,6 +97,13 @@
+ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
+    /*      cipher_suite                         policy      enabled is_present*/
+ #ifdef NSS_ENABLE_ECC
++ { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
++ { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,  SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
++#endif /* NSS_ENABLE_ECC */
++ { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,    SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
++ { TLS_RSA_WITH_AES_128_GCM_SHA256,        SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
++
++#ifdef NSS_ENABLE_ECC
+  { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,   SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+  { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,     SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ #endif /* NSS_ENABLE_ECC */
+@@ -233,23 +247,30 @@
+ 
+ /* indexed by SSL3BulkCipher */
+ static const ssl3BulkCipherDef bulk_cipher_defs[] = {
+-    /* cipher          calg        keySz secretSz  type  ivSz BlkSz keygen */
+-    {cipher_null,      calg_null,      0,  0, type_stream,  0, 0, kg_null},
+-    {cipher_rc4,       calg_rc4,      16, 16, type_stream,  0, 0, kg_strong},
+-    {cipher_rc4_40,    calg_rc4,      16,  5, type_stream,  0, 0, kg_export},
+-    {cipher_rc4_56,    calg_rc4,      16,  7, type_stream,  0, 0, kg_export},
+-    {cipher_rc2,       calg_rc2,      16, 16, type_block,   8, 8, kg_strong},
+-    {cipher_rc2_40,    calg_rc2,      16,  5, type_block,   8, 8, kg_export},
+-    {cipher_des,       calg_des,       8,  8, type_block,   8, 8, kg_strong},
+-    {cipher_3des,      calg_3des,     24, 24, type_block,   8, 8, kg_strong},
+-    {cipher_des40,     calg_des,       8,  5, type_block,   8, 8, kg_export},
+-    {cipher_idea,      calg_idea,     16, 16, type_block,   8, 8, kg_strong},
+-    {cipher_aes_128,   calg_aes,      16, 16, type_block,  16,16, kg_strong},
+-    {cipher_aes_256,   calg_aes,      32, 32, type_block,  16,16, kg_strong},
+-    {cipher_camellia_128, calg_camellia,16, 16, type_block,  16,16, kg_strong},
+-    {cipher_camellia_256, calg_camellia,32, 32, type_block,  16,16, kg_strong},
+-    {cipher_seed,      calg_seed,     16, 16, type_block,  16,16, kg_strong},
+-    {cipher_missing,   calg_null,      0,  0, type_stream,  0, 0, kg_null},
++    /*                                       |--------- Lengths --------| */
++    /* cipher             calg               k  s  type         i  b  t  n */
++    /*                                       e  e               v  l  a  o */
++    /*                                       y  c               |  o  g  n */
++    /*                                       |  r               |  c  |  c */
++    /*                                       |  e               |  k  |  e */
++    /*                                       |  t               |  |  |  | */
++    {cipher_null,         calg_null,         0, 0, type_stream, 0, 0, 0, 0},
++    {cipher_rc4,          calg_rc4,         16,16, type_stream, 0, 0, 0, 0},
++    {cipher_rc4_40,       calg_rc4,         16, 5, type_stream, 0, 0, 0, 0},
++    {cipher_rc4_56,       calg_rc4,         16, 7, type_stream, 0, 0, 0, 0},
++    {cipher_rc2,          calg_rc2,         16,16, type_block,  8, 8, 0, 0},
++    {cipher_rc2_40,       calg_rc2,         16, 5, type_block,  8, 8, 0, 0},
++    {cipher_des,          calg_des,          8, 8, type_block,  8, 8, 0, 0},
++    {cipher_3des,         calg_3des,        24,24, type_block,  8, 8, 0, 0},
++    {cipher_des40,        calg_des,          8, 5, type_block,  8, 8, 0, 0},
++    {cipher_idea,         calg_idea,        16,16, type_block,  8, 8, 0, 0},
++    {cipher_aes_128,      calg_aes,         16,16, type_block, 16,16, 0, 0},
++    {cipher_aes_256,      calg_aes,         32,32, type_block, 16,16, 0, 0},
++    {cipher_camellia_128, calg_camellia,    16,16, type_block, 16,16, 0, 0},
++    {cipher_camellia_256, calg_camellia,    32,32, type_block, 16,16, 0, 0},
++    {cipher_seed,         calg_seed,        16,16, type_block, 16,16, 0, 0},
++    {cipher_aes_128_gcm,  calg_aes_gcm,     16,16, type_aead,   4, 0,16, 8},
++    {cipher_missing,      calg_null,         0, 0, type_stream, 0, 0, 0, 0},
+ };
+ 
+ static const ssl3KEADef kea_defs[] = 
+@@ -371,6 +392,11 @@
+     {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips},
+     {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des,    mac_sha, kea_rsa_fips},
+ 
++    {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa},
++    {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa},
++    {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa},
++    {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa},
++
+ #ifdef NSS_ENABLE_ECC
+     {TLS_ECDH_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdh_ecdsa},
+     {TLS_ECDH_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdh_ecdsa},
+@@ -434,25 +460,29 @@
+     { calg_aes      , CKM_AES_CBC			},
+     { calg_camellia , CKM_CAMELLIA_CBC			},
+     { calg_seed     , CKM_SEED_CBC			},
++    { calg_aes_gcm  , CKM_AES_GCM			},
+ /*  { calg_init     , (CK_MECHANISM_TYPE)0x7fffffffL    }  */
+ };
+ 
+-#define mmech_null     (CK_MECHANISM_TYPE)0x80000000L
++#define mmech_invalid  (CK_MECHANISM_TYPE)0x80000000L
+ #define mmech_md5      CKM_SSL3_MD5_MAC
+ #define mmech_sha      CKM_SSL3_SHA1_MAC
+ #define mmech_md5_hmac CKM_MD5_HMAC
+ #define mmech_sha_hmac CKM_SHA_1_HMAC
+ #define mmech_sha256_hmac CKM_SHA256_HMAC
++#define mmech_sha384_hmac CKM_SHA384_HMAC
++#define mmech_sha512_hmac CKM_SHA512_HMAC
+ 
+ static const ssl3MACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */
+     /* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */
+     /* mac      mmech       pad_size  mac_size                       */
+-    { mac_null, mmech_null,       0,  0          },
++    { mac_null, mmech_invalid,    0,  0          },
+     { mac_md5,  mmech_md5,       48,  MD5_LENGTH },
+     { mac_sha,  mmech_sha,       40,  SHA1_LENGTH},
+     {hmac_md5,  mmech_md5_hmac,   0,  MD5_LENGTH },
+     {hmac_sha,  mmech_sha_hmac,   0,  SHA1_LENGTH},
+     {hmac_sha256, mmech_sha256_hmac, 0, SHA256_LENGTH},
++    { mac_aead, mmech_invalid,    0,  0          },
+ };
+ 
+ /* indexed by SSL3BulkCipher */
+@@ -472,6 +502,7 @@
+     "Camellia-128",
+     "Camellia-256",
+     "SEED-CBC",
++    "AES-128-GCM",
+     "missing"
+ };
+ 
+@@ -598,9 +629,13 @@
+     case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+     case TLS_RSA_WITH_AES_256_CBC_SHA256:
+     case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
++    case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+     case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
++    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+     case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
++    case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+     case TLS_RSA_WITH_AES_128_CBC_SHA256:
++    case TLS_RSA_WITH_AES_128_GCM_SHA256:
+     case TLS_RSA_WITH_NULL_SHA256:
+ 	return version >= SSL_LIBRARY_VERSION_TLS_1_2;
+     default:
+@@ -1360,7 +1395,7 @@
+     cipher = suite_def->bulk_cipher_alg;
+     kea    = suite_def->key_exchange_alg;
+     mac    = suite_def->mac_alg;
+-    if (mac <= ssl_mac_sha && isTLS)
++    if (mac <= ssl_mac_sha && mac != ssl_mac_null && isTLS)
+ 	mac += 2;
+ 
+     ss->ssl3.hs.suite_def = suite_def;
+@@ -1554,7 +1589,6 @@
+       unsigned int       optArg2  = 0;
+       PRBool             server_encrypts = ss->sec.isServer;
+       SSLCipherAlgorithm calg;
+-      SSLCompressionMethod compression_method;
+       SECStatus          rv;
+ 
+     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+@@ -1565,8 +1599,18 @@
+     cipher_def    = pwSpec->cipher_def;
+ 
+     calg = cipher_def->calg;
+-    compression_method = pwSpec->compression_method;
+ 
++    if (calg == calg_aes_gcm) {
++	pwSpec->encode = NULL;
++	pwSpec->decode = NULL;
++	pwSpec->destroy = NULL;
++	pwSpec->encodeContext = NULL;
++	pwSpec->decodeContext = NULL;
++	pwSpec->aead = ssl3_AESGCMBypass;
++	ssl3_InitCompressionContext(pwSpec);
++	return SECSuccess;
++    }
++
+     serverContext = pwSpec->server.cipher_context;
+     clientContext = pwSpec->client.cipher_context;
+ 
+@@ -1721,6 +1765,195 @@
+     return param;
+ }
+ 
++/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data
++ * which is included in the MAC or AEAD additional data) to |out| and returns
++ * its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the
++ * definition of the AEAD additional data.
++ *
++ * TLS pseudo-header includes the record's version field, SSL's doesn't. Which
++ * pseudo-header defintiion to use should be decided based on the version of
++ * the protocol that was negotiated when the cipher spec became current, NOT
++ * based on the version value in the record itself, and the decision is passed
++ * to this function as the |includesVersion| argument. But, the |version|
++ * argument should be the record's version value.
++ */
++static unsigned int
++ssl3_BuildRecordPseudoHeader(unsigned char *out,
++			     SSL3SequenceNumber seq_num,
++			     SSL3ContentType type,
++			     PRBool includesVersion,
++			     SSL3ProtocolVersion version,
++			     PRBool isDTLS,
++			     int length)
++{
++    out[0] = (unsigned char)(seq_num.high >> 24);
++    out[1] = (unsigned char)(seq_num.high >> 16);
++    out[2] = (unsigned char)(seq_num.high >>  8);
++    out[3] = (unsigned char)(seq_num.high >>  0);
++    out[4] = (unsigned char)(seq_num.low  >> 24);
++    out[5] = (unsigned char)(seq_num.low  >> 16);
++    out[6] = (unsigned char)(seq_num.low  >>  8);
++    out[7] = (unsigned char)(seq_num.low  >>  0);
++    out[8] = type;
++
++    /* SSL3 MAC doesn't include the record's version field. */
++    if (!includesVersion) {
++	out[9]  = MSB(length);
++	out[10] = LSB(length);
++	return 11;
++    }
++
++    /* TLS MAC and AEAD additional data include version. */
++    if (isDTLS) {
++	SSL3ProtocolVersion dtls_version;
++
++	dtls_version = dtls_TLSVersionToDTLSVersion(version);
++	out[9]  = MSB(dtls_version);
++	out[10] = LSB(dtls_version);
++    } else {
++	out[9]  = MSB(version);
++	out[10] = LSB(version);
++    }
++    out[11] = MSB(length);
++    out[12] = LSB(length);
++    return 13;
++}
++
++static SECStatus
++ssl3_AESGCM(ssl3KeyMaterial *keys,
++	    PRBool doDecrypt,
++	    unsigned char *out,
++	    int *outlen,
++	    int maxout,
++	    const unsigned char *in,
++	    int inlen,
++	    const unsigned char *additionalData,
++	    int additionalDataLen)
++{
++    SECItem            param;
++    SECStatus          rv = SECFailure;
++    unsigned char      nonce[12];
++    unsigned int       uOutLen;
++    CK_GCM_PARAMS      gcmParams;
++
++    static const int   tagSize = 16;
++    static const int   explicitNonceLen = 8;
++
++    /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
++     * nonce is formed. */
++    memcpy(nonce, keys->write_iv, 4);
++    if (doDecrypt) {
++	memcpy(nonce + 4, in, explicitNonceLen);
++	in += explicitNonceLen;
++	inlen -= explicitNonceLen;
++	*outlen = 0;
++    } else {
++	if (maxout < explicitNonceLen) {
++	    PORT_SetError(SEC_ERROR_INPUT_LEN);
++	    return SECFailure;
++        }
++	/* Use the 64-bit sequence number as the explicit nonce. */
++	memcpy(nonce + 4, additionalData, explicitNonceLen);
++	memcpy(out, additionalData, explicitNonceLen);
++	out += explicitNonceLen;
++	maxout -= explicitNonceLen;
++	*outlen = explicitNonceLen;
++    }
++
++    param.type = siBuffer;
++    param.data = (unsigned char *) &gcmParams;
++    param.len = sizeof(gcmParams);
++    gcmParams.pIv = nonce;
++    gcmParams.ulIvLen = sizeof(nonce);
++    gcmParams.pAAD = (unsigned char *)additionalData;  /* const cast */
++    gcmParams.ulAADLen = additionalDataLen;
++    gcmParams.ulTagBits = tagSize * 8;
++
++    if (doDecrypt) {
++	rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
++			  maxout, in, inlen);
++    } else {
++	rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
++			  maxout, in, inlen);
++    }
++    *outlen += (int) uOutLen;
++
++    return rv;
++}
++
++#ifndef NO_PKCS11_BYPASS
++static SECStatus
++ssl3_AESGCMBypass(ssl3KeyMaterial *keys,
++		  PRBool doDecrypt,
++		  unsigned char *out,
++		  int *outlen,
++		  int maxout,
++		  const unsigned char *in,
++		  int inlen,
++		  const unsigned char *additionalData,
++		  int additionalDataLen)
++{
++    SECStatus          rv = SECFailure;
++    unsigned char      nonce[12];
++    unsigned int       uOutLen;
++    AESContext        *cx;
++    CK_GCM_PARAMS      gcmParams;
++
++    static const int   tagSize = 16;
++    static const int   explicitNonceLen = 8;
++
++    /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
++     * nonce is formed. */
++    PORT_Assert(keys->write_iv_item.len == 4);
++    if (keys->write_iv_item.len != 4) {
++	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
++	return SECFailure;
++    }
++    memcpy(nonce, keys->write_iv_item.data, 4);
++    if (doDecrypt) {
++	memcpy(nonce + 4, in, explicitNonceLen);
++	in += explicitNonceLen;
++	inlen -= explicitNonceLen;
++	*outlen = 0;
++    } else {
++	if (maxout < explicitNonceLen) {
++	    PORT_SetError(SEC_ERROR_INPUT_LEN);
++	    return SECFailure;
++        }
++	/* Use the 64-bit sequence number as the explicit nonce. */
++	memcpy(nonce + 4, additionalData, explicitNonceLen);
++	memcpy(out, additionalData, explicitNonceLen);
++	out += explicitNonceLen;
++	maxout -= explicitNonceLen;
++	*outlen = explicitNonceLen;
++    }
++
++    gcmParams.pIv = nonce;
++    gcmParams.ulIvLen = sizeof(nonce);
++    gcmParams.pAAD = (unsigned char *)additionalData;  /* const cast */
++    gcmParams.ulAADLen = additionalDataLen;
++    gcmParams.ulTagBits = tagSize * 8;
++
++    cx = (AESContext *)keys->cipher_context;
++    rv = AES_InitContext(cx, keys->write_key_item.data,
++			 keys->write_key_item.len,
++			 (unsigned char *)&gcmParams, NSS_AES_GCM, !doDecrypt,
++			 AES_BLOCK_SIZE);
++    if (rv != SECSuccess) {
++	return rv;
++    }
++    if (doDecrypt) {
++	rv = AES_Decrypt(cx, out, &uOutLen, maxout, in, inlen);
++    } else {
++	rv = AES_Encrypt(cx, out, &uOutLen, maxout, in, inlen);
++    }
++    AES_DestroyContext(cx, PR_FALSE);
++    *outlen += (int) uOutLen;
++
++    return rv;
++}
++#endif
++
+ /* Initialize encryption and MAC contexts for pending spec.
+  * Master Secret already is derived.
+  * Caller holds Spec write lock.
+@@ -1748,14 +1981,27 @@
+     pwSpec        = ss->ssl3.pwSpec;
+     cipher_def    = pwSpec->cipher_def;
+     macLength     = pwSpec->mac_size;
++    calg          = cipher_def->calg;
++    PORT_Assert(alg2Mech[calg].calg == calg);
+ 
++    pwSpec->client.write_mac_context = NULL;
++    pwSpec->server.write_mac_context = NULL;
++
++    if (calg == calg_aes_gcm) {
++	pwSpec->encode = NULL;
++	pwSpec->decode = NULL;
++	pwSpec->destroy = NULL;
++	pwSpec->encodeContext = NULL;
++	pwSpec->decodeContext = NULL;
++	pwSpec->aead = ssl3_AESGCM;
++	return SECSuccess;
++    }
++
+     /* 
+     ** Now setup the MAC contexts, 
+     **   crypto contexts are setup below.
+     */
+ 
+-    pwSpec->client.write_mac_context = NULL;
+-    pwSpec->server.write_mac_context = NULL;
+     mac_mech       = pwSpec->mac_def->mmech;
+     mac_param.data = (unsigned char *)&macLength;
+     mac_param.len  = sizeof(macLength);
+@@ -1778,9 +2024,6 @@
+     ** Now setup the crypto contexts.
+     */
+ 
+-    calg = cipher_def->calg;
+-    PORT_Assert(alg2Mech[calg].calg == calg);
+-
+     if (calg == calg_null) {
+ 	pwSpec->encode  = Null_Cipher;
+ 	pwSpec->decode  = Null_Cipher;
+@@ -1988,10 +2231,8 @@
+ ssl3_ComputeRecordMAC(
+     ssl3CipherSpec *   spec,
+     PRBool             useServerMacKey,
+-    PRBool             isDTLS,
+-    SSL3ContentType    type,
+-    SSL3ProtocolVersion version,
+-    SSL3SequenceNumber seq_num,
++    const unsigned char *header,
++    unsigned int       headerLen,
+     const SSL3Opaque * input,
+     int                inputLength,
+     unsigned char *    outbuf,
+@@ -1999,56 +2240,8 @@
+ {
+     const ssl3MACDef * mac_def;
+     SECStatus          rv;
+-#ifndef NO_PKCS11_BYPASS
+-    PRBool             isTLS;
+-#endif
+-    unsigned int       tempLen;
+-    unsigned char      temp[MAX_MAC_LENGTH];
+ 
+-    temp[0] = (unsigned char)(seq_num.high >> 24);
+-    temp[1] = (unsigned char)(seq_num.high >> 16);
+-    temp[2] = (unsigned char)(seq_num.high >>  8);
+-    temp[3] = (unsigned char)(seq_num.high >>  0);
+-    temp[4] = (unsigned char)(seq_num.low  >> 24);
+-    temp[5] = (unsigned char)(seq_num.low  >> 16);
+-    temp[6] = (unsigned char)(seq_num.low  >>  8);
+-    temp[7] = (unsigned char)(seq_num.low  >>  0);
+-    temp[8] = type;
+-
+-    /* TLS MAC includes the record's version field, SSL's doesn't.
+-    ** We decide which MAC defintiion to use based on the version of 
+-    ** the protocol that was negotiated when the spec became current,
+-    ** NOT based on the version value in the record itself.
+-    ** But, we use the record'v version value in the computation.
+-    */
+-    if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
+-	temp[9]  = MSB(inputLength);
+-	temp[10] = LSB(inputLength);
+-	tempLen  = 11;
+-#ifndef NO_PKCS11_BYPASS
+-	isTLS    = PR_FALSE;
+-#endif
+-    } else {
+-    	/* New TLS hash includes version. */
+-	if (isDTLS) {
+-	    SSL3ProtocolVersion dtls_version;
+-
+-	    dtls_version = dtls_TLSVersionToDTLSVersion(version);
+-	    temp[9]  = MSB(dtls_version);
+-	    temp[10] = LSB(dtls_version);
+-        } else {
+-	    temp[9]  = MSB(version);
+-	    temp[10] = LSB(version);
+-        }
+-	temp[11] = MSB(inputLength);
+-	temp[12] = LSB(inputLength);
+-	tempLen  = 13;
+-#ifndef NO_PKCS11_BYPASS
+-	isTLS    = PR_TRUE;
+-#endif
+-    }
+-
+-    PRINT_BUF(95, (NULL, "frag hash1: temp", temp, tempLen));
++    PRINT_BUF(95, (NULL, "frag hash1: header", header, headerLen));
+     PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength));
+ 
+     mac_def = spec->mac_def;
+@@ -2093,7 +2286,10 @@
+ 	    return SECFailure;
+ 	}
+ 
+-	if (!isTLS) {
++	if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
++	    unsigned int tempLen;
++	    unsigned char temp[MAX_MAC_LENGTH];
++
+ 	    /* compute "inner" part of SSL3 MAC */
+ 	    hashObj->begin(write_mac_context);
+ 	    if (useServerMacKey)
+@@ -2105,7 +2301,7 @@
+ 				spec->client.write_mac_key_item.data,
+ 				spec->client.write_mac_key_item.len);
+ 	    hashObj->update(write_mac_context, mac_pad_1, pad_bytes);
+-	    hashObj->update(write_mac_context, temp,  tempLen);
++	    hashObj->update(write_mac_context, header, headerLen);
+ 	    hashObj->update(write_mac_context, input, inputLength);
+ 	    hashObj->end(write_mac_context,    temp, &tempLen, sizeof temp);
+ 
+@@ -2136,7 +2332,7 @@
+ 	    }
+ 	    if (rv == SECSuccess) {
+ 		HMAC_Begin(cx);
+-		HMAC_Update(cx, temp, tempLen);
++		HMAC_Update(cx, header, headerLen);
+ 		HMAC_Update(cx, input, inputLength);
+ 		rv = HMAC_Finish(cx, outbuf, outLength, spec->mac_size);
+ 		HMAC_Destroy(cx, PR_FALSE);
+@@ -2150,7 +2346,7 @@
+ 	    (useServerMacKey ? spec->server.write_mac_context
+ 	                     : spec->client.write_mac_context);
+ 	rv  = PK11_DigestBegin(mac_context);
+-	rv |= PK11_DigestOp(mac_context, temp, tempLen);
++	rv |= PK11_DigestOp(mac_context, header, headerLen);
+ 	rv |= PK11_DigestOp(mac_context, input, inputLength);
+ 	rv |= PK11_DigestFinal(mac_context, outbuf, outLength, spec->mac_size);
+     }
+@@ -2190,10 +2386,8 @@
+ ssl3_ComputeRecordMACConstantTime(
+     ssl3CipherSpec *   spec,
+     PRBool             useServerMacKey,
+-    PRBool             isDTLS,
+-    SSL3ContentType    type,
+-    SSL3ProtocolVersion version,
+-    SSL3SequenceNumber seq_num,
++    const unsigned char *header,
++    unsigned int       headerLen,
+     const SSL3Opaque * input,
+     int                inputLen,
+     int                originalLen,
+@@ -2205,9 +2399,7 @@
+     PK11Context *                mac_context;
+     SECItem                      param;
+     SECStatus                    rv;
+-    unsigned char                header[13];
+     PK11SymKey *                 key;
+-    int                          recordLength;
+ 
+     PORT_Assert(inputLen >= spec->mac_size);
+     PORT_Assert(originalLen >= inputLen);
+@@ -2223,42 +2415,15 @@
+ 	return SECSuccess;
+     }
+ 
+-    header[0] = (unsigned char)(seq_num.high >> 24);
+-    header[1] = (unsigned char)(seq_num.high >> 16);
+-    header[2] = (unsigned char)(seq_num.high >>  8);
+-    header[3] = (unsigned char)(seq_num.high >>  0);
+-    header[4] = (unsigned char)(seq_num.low  >> 24);
+-    header[5] = (unsigned char)(seq_num.low  >> 16);
+-    header[6] = (unsigned char)(seq_num.low  >>  8);
+-    header[7] = (unsigned char)(seq_num.low  >>  0);
+-    header[8] = type;
+-
+     macType = CKM_NSS_HMAC_CONSTANT_TIME;
+-    recordLength = inputLen - spec->mac_size;
+     if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
+ 	macType = CKM_NSS_SSL3_MAC_CONSTANT_TIME;
+-	header[9] = recordLength >> 8;
+-	header[10] = recordLength;
+-	params.ulHeaderLen = 11;
+-    } else {
+-	if (isDTLS) {
+-	    SSL3ProtocolVersion dtls_version;
+-
+-	    dtls_version = dtls_TLSVersionToDTLSVersion(version);
+-	    header[9] = dtls_version >> 8;
+-	    header[10] = dtls_version;
+-	} else {
+-	    header[9] = version >> 8;
+-	    header[10] = version;
+-	}
+-	header[11] = recordLength >> 8;
+-	header[12] = recordLength;
+-	params.ulHeaderLen = 13;
+     }
+ 
+     params.macAlg = spec->mac_def->mmech;
+     params.ulBodyTotalLen = originalLen;
+-    params.pHeader = header;
++    params.pHeader = (unsigned char *) header;  /* const cast */
++    params.ulHeaderLen = headerLen;
+ 
+     param.data = (unsigned char*) &params;
+     param.len = sizeof(params);
+@@ -2291,9 +2456,8 @@
+     /* ssl3_ComputeRecordMAC expects the MAC to have been removed from the
+      * length already. */
+     inputLen -= spec->mac_size;
+-    return ssl3_ComputeRecordMAC(spec, useServerMacKey, isDTLS, type,
+-				 version, seq_num, input, inputLen,
+-				 outbuf, outLen);
++    return ssl3_ComputeRecordMAC(spec, useServerMacKey, header, headerLen,
++				 input, inputLen, outbuf, outLen);
+ }
+ 
+ static PRBool
+@@ -2345,6 +2509,8 @@
+     PRUint16                  headerLen;
+     int                       ivLen = 0;
+     int                       cipherBytes = 0;
++    unsigned char             pseudoHeader[13];
++    unsigned int              pseudoHeaderLen;
+ 
+     cipher_def = cwSpec->cipher_def;
+     headerLen = isDTLS ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
+@@ -2390,86 +2556,117 @@
+ 	contentLen = outlen;
+     }
+ 
+-    /*
+-     * Add the MAC
+-     */
+-    rv = ssl3_ComputeRecordMAC( cwSpec, isServer, isDTLS,
+-	type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen,
+-	wrBuf->buf + headerLen + ivLen + contentLen, &macLen);
+-    if (rv != SECSuccess) {
+-	ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
+-	return SECFailure;
+-    }
+-    p1Len   = contentLen;
+-    p2Len   = macLen;
+-    fragLen = contentLen + macLen;	/* needs to be encrypted */
+-    PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
++    pseudoHeaderLen = ssl3_BuildRecordPseudoHeader(
++	pseudoHeader, cwSpec->write_seq_num, type,
++	cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->version,
++	isDTLS, contentLen);
++    PORT_Assert(pseudoHeaderLen <= sizeof(pseudoHeader));
++    if (cipher_def->type == type_aead) {
++	const int nonceLen = cipher_def->explicit_nonce_size;
++	const int tagLen = cipher_def->tag_size;
+ 
+-    /*
+-     * Pad the text (if we're doing a block cipher)
+-     * then Encrypt it
+-     */
+-    if (cipher_def->type == type_block) {
+-	unsigned char * pBuf;
+-	int             padding_length;
+-	int             i;
++	if (headerLen + nonceLen + contentLen + tagLen > wrBuf->space) {
++	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
++	    return SECFailure;
++	}
+ 
+-	oddLen = contentLen % cipher_def->block_size;
+-	/* Assume blockSize is a power of two */
+-	padding_length = cipher_def->block_size - 1 -
+-			((fragLen) & (cipher_def->block_size - 1));
+-	fragLen += padding_length + 1;
+-	PORT_Assert((fragLen % cipher_def->block_size) == 0);
+-
+-	/* Pad according to TLS rules (also acceptable to SSL3). */
+-	pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1];
+-	for (i = padding_length + 1; i > 0; --i) {
+-	    *pBuf-- = padding_length;
++	cipherBytes = contentLen;
++	rv = cwSpec->aead(
++		isServer ? &cwSpec->server : &cwSpec->client,
++		PR_FALSE,                                   /* do encrypt */
++		wrBuf->buf + headerLen,                     /* output  */
++		&cipherBytes,                               /* out len */
++		wrBuf->space - headerLen,                   /* max out */
++		pIn, contentLen,                            /* input   */
++		pseudoHeader, pseudoHeaderLen);
++	if (rv != SECSuccess) {
++	    PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
++	    return SECFailure;
+ 	}
+-	/* now, if contentLen is not a multiple of block size, fix it */
+-	p2Len = fragLen - p1Len;
+-    }
+-    if (p1Len < 256) {
+-	oddLen = p1Len;
+-	p1Len = 0;
+     } else {
+-	p1Len -= oddLen;
+-    }
+-    if (oddLen) {
+-	p2Len += oddLen;
+-	PORT_Assert( (cipher_def->block_size < 2) || \
+-		     (p2Len % cipher_def->block_size) == 0);
+-	memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len, oddLen);
+-    }
+-    if (p1Len > 0) {
+-	int cipherBytesPart1 = -1;
+-	rv = cwSpec->encode( cwSpec->encodeContext, 
+-	    wrBuf->buf + headerLen + ivLen,         /* output */
+-	    &cipherBytesPart1,                      /* actual outlen */
+-	    p1Len,                                  /* max outlen */
+-	    pIn, p1Len);                      /* input, and inputlen */
+-	PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len);
+-	if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) {
+-	    PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
++	/*
++	 * Add the MAC
++	 */
++	rv = ssl3_ComputeRecordMAC(cwSpec, isServer,
++	    pseudoHeader, pseudoHeaderLen, pIn, contentLen,
++	    wrBuf->buf + headerLen + ivLen + contentLen, &macLen);
++	if (rv != SECSuccess) {
++	    ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
+ 	    return SECFailure;
+ 	}
+-	cipherBytes += cipherBytesPart1;
++	p1Len   = contentLen;
++	p2Len   = macLen;
++	fragLen = contentLen + macLen;	/* needs to be encrypted */
++	PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
++
++	/*
++	 * Pad the text (if we're doing a block cipher)
++	 * then Encrypt it
++	 */
++	if (cipher_def->type == type_block) {
++	    unsigned char * pBuf;
++	    int             padding_length;
++	    int             i;
++
++	    oddLen = contentLen % cipher_def->block_size;
++	    /* Assume blockSize is a power of two */
++	    padding_length = cipher_def->block_size - 1 -
++			    ((fragLen) & (cipher_def->block_size - 1));
++	    fragLen += padding_length + 1;
++	    PORT_Assert((fragLen % cipher_def->block_size) == 0);
++
++	    /* Pad according to TLS rules (also acceptable to SSL3). */
++	    pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1];
++	    for (i = padding_length + 1; i > 0; --i) {
++		*pBuf-- = padding_length;
++	    }
++	    /* now, if contentLen is not a multiple of block size, fix it */
++	    p2Len = fragLen - p1Len;
++	}
++	if (p1Len < 256) {
++	    oddLen = p1Len;
++	    p1Len = 0;
++	} else {
++	    p1Len -= oddLen;
++	}
++	if (oddLen) {
++	    p2Len += oddLen;
++	    PORT_Assert( (cipher_def->block_size < 2) || \
++			 (p2Len % cipher_def->block_size) == 0);
++	    memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len,
++		    oddLen);
++	}
++	if (p1Len > 0) {
++	    int cipherBytesPart1 = -1;
++	    rv = cwSpec->encode( cwSpec->encodeContext, 
++		wrBuf->buf + headerLen + ivLen,         /* output */
++		&cipherBytesPart1,                      /* actual outlen */
++		p1Len,                                  /* max outlen */
++		pIn, p1Len);                      /* input, and inputlen */
++	    PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len);
++	    if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) {
++		PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
++		return SECFailure;
++	    }
++	    cipherBytes += cipherBytesPart1;
++	}
++	if (p2Len > 0) {
++	    int cipherBytesPart2 = -1;
++	    rv = cwSpec->encode( cwSpec->encodeContext, 
++		wrBuf->buf + headerLen + ivLen + p1Len,
++		&cipherBytesPart2,          /* output and actual outLen */
++		p2Len,                             /* max outlen */
++		wrBuf->buf + headerLen + ivLen + p1Len,
++		p2Len);                            /* input and inputLen*/
++	    PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len);
++	    if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) {
++		PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
++		return SECFailure;
++	    }
++	    cipherBytes += cipherBytesPart2;
++	}
+     }
+-    if (p2Len > 0) {
+-	int cipherBytesPart2 = -1;
+-	rv = cwSpec->encode( cwSpec->encodeContext, 
+-	    wrBuf->buf + headerLen + ivLen + p1Len,
+-	    &cipherBytesPart2,          /* output and actual outLen */
+-	    p2Len,                             /* max outlen */
+-	    wrBuf->buf + headerLen + ivLen + p1Len,
+-	    p2Len);                            /* input and inputLen*/
+-	PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len);
+-	if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) {
+-	    PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+-	    return SECFailure;
+-	}
+-	cipherBytes += cipherBytesPart2;
+-    }	
++
+     PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024);
+ 
+     wrBuf->len    = cipherBytes + headerLen;
+@@ -3012,9 +3209,6 @@
+ static SECStatus
+ ssl3_IllegalParameter(sslSocket *ss)
+ {
+-    PRBool isTLS;
+-
+-    isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+     (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+     PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
+                                    : SSL_ERROR_BAD_SERVER );
+@@ -3538,7 +3732,6 @@
+     }
+ 
+     key_material_params.bIsExport = (CK_BBOOL)(kea_def->is_limited);
+-    /* was:	(CK_BBOOL)(cipher_def->keygen_mode != kg_strong); */
+ 
+     key_material_params.RandomInfo.pClientRandom     = cr;
+     key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
+@@ -9946,7 +10139,6 @@
+ static void
+ ssl3_RecordKeyLog(sslSocket *ss)
+ {
+-    sslSessionID *sid;
+     SECStatus rv;
+     SECItem *keyData;
+     char buf[14 /* "CLIENT_RANDOM " */ +
+@@ -9958,8 +10150,6 @@
+ 
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ 
+-    sid = ss->sec.ci.sid;
+-
+     if (!ssl_keylog_iob)
+ 	return;
+ 
+@@ -11095,6 +11285,8 @@
+     unsigned int         originalLen = 0;
+     unsigned int         good;
+     unsigned int         minLength;
++    unsigned char        header[13];
++    unsigned int         headerLen;
+ 
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+ 
+@@ -11171,12 +11363,14 @@
+ 	    /* With >= TLS 1.1, CBC records have an explicit IV. */
+ 	    minLength += cipher_def->iv_size;
+ 	}
++    } else if (cipher_def->type == type_aead) {
++	minLength = cipher_def->explicit_nonce_size + cipher_def->tag_size;
+     }
+ 
+     /* We can perform this test in variable time because the record's total
+      * length and the ciphersuite are both public knowledge. */
+     if (cText->buf->len < minLength) {
+-        goto decrypt_loser;
++	goto decrypt_loser;
+     }
+ 
+     if (cipher_def->type == type_block &&
+@@ -11244,78 +11438,104 @@
+ 	return SECFailure;
+     }
+ 
+-    if (cipher_def->type == type_block &&
+-	((cText->buf->len - ivLen) % cipher_def->block_size) != 0) {
+-	goto decrypt_loser;
+-    }
++    rType = cText->type;
++    if (cipher_def->type == type_aead) {
++	/* XXX For many AEAD ciphers, the plaintext is shorter than the
++	 * ciphertext by a fixed byte count, but it is not true in general.
++	 * Each AEAD cipher should provide a function that returns the
++	 * plaintext length for a given ciphertext. */
++	unsigned int decryptedLen =
++	    cText->buf->len - cipher_def->explicit_nonce_size -
++	    cipher_def->tag_size;
++	headerLen = ssl3_BuildRecordPseudoHeader(
++	    header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
++	    rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen);
++	PORT_Assert(headerLen <= sizeof(header));
++	rv = crSpec->aead(
++		ss->sec.isServer ? &crSpec->client : &crSpec->server,
++		PR_TRUE,                          /* do decrypt */
++		plaintext->buf,                   /* out */
++		(int*) &plaintext->len,           /* outlen */
++		plaintext->space,                 /* maxout */
++		cText->buf->buf,                  /* in */
++		cText->buf->len,                  /* inlen */
++		header, headerLen);
++	if (rv != SECSuccess) {
++	    good = 0;
++	}
++    } else {
++	if (cipher_def->type == type_block &&
++	    ((cText->buf->len - ivLen) % cipher_def->block_size) != 0) {
++	    goto decrypt_loser;
++	}
+ 
+-    /* decrypt from cText buf to plaintext. */
+-    rv = crSpec->decode(
+-	crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len,
+-	plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
+-    if (rv != SECSuccess) {
+-	goto decrypt_loser;
+-    }
++	/* decrypt from cText buf to plaintext. */
++	rv = crSpec->decode(
++	    crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len,
++	    plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
++	if (rv != SECSuccess) {
++	    goto decrypt_loser;
++	}
+ 
+-    PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
++	PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
+ 
+-    originalLen = plaintext->len;
++	originalLen = plaintext->len;
+ 
+-    /* If it's a block cipher, check and strip the padding. */
+-    if (cipher_def->type == type_block) {
+-	const unsigned int blockSize = cipher_def->block_size;
+-	const unsigned int macSize = crSpec->mac_size;
++	/* If it's a block cipher, check and strip the padding. */
++	if (cipher_def->type == type_block) {
++	    const unsigned int blockSize = cipher_def->block_size;
++	    const unsigned int macSize = crSpec->mac_size;
+ 
+-	if (crSpec->version <= SSL_LIBRARY_VERSION_3_0) {
+-	    good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding(
+-			plaintext, blockSize, macSize));
+-	} else {
+-	    good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
+-			plaintext, macSize));
++	    if (!isTLS) {
++		good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding(
++			    plaintext, blockSize, macSize));
++	    } else {
++		good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
++			    plaintext, macSize));
++	    }
+ 	}
+-    }
+ 
+-    /* compute the MAC */
+-    rType = cText->type;
+-    if (cipher_def->type == type_block) {
+-	rv = ssl3_ComputeRecordMACConstantTime(
+-	    crSpec, (PRBool)(!ss->sec.isServer),
+-	    IS_DTLS(ss), rType, cText->version,
+-	    IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+-	    plaintext->buf, plaintext->len, originalLen,
+-	    hash, &hashBytes);
++	/* compute the MAC */
++	headerLen = ssl3_BuildRecordPseudoHeader(
++	    header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
++	    rType, isTLS, cText->version, IS_DTLS(ss),
++	    plaintext->len - crSpec->mac_size);
++	PORT_Assert(headerLen <= sizeof(header));
++	if (cipher_def->type == type_block) {
++	    rv = ssl3_ComputeRecordMACConstantTime(
++		crSpec, (PRBool)(!ss->sec.isServer), header, headerLen,
++		plaintext->buf, plaintext->len, originalLen,
++		hash, &hashBytes);
+ 
+-	ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf,
+-			  crSpec->mac_size);
+-	givenHash = givenHashBuf;
++	    ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf,
++			      crSpec->mac_size);
++	    givenHash = givenHashBuf;
+ 
+-	/* plaintext->len will always have enough space to remove the MAC
+-	 * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust
+-	 * plaintext->len if the result has enough space for the MAC and we
+-	 * tested the unadjusted size against minLength, above. */
+-	plaintext->len -= crSpec->mac_size;
+-    } else {
+-	/* This is safe because we checked the minLength above. */
+-	plaintext->len -= crSpec->mac_size;
++	    /* plaintext->len will always have enough space to remove the MAC
++	     * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust
++	     * plaintext->len if the result has enough space for the MAC and we
++	     * tested the unadjusted size against minLength, above. */
++	    plaintext->len -= crSpec->mac_size;
++	} else {
++	    /* This is safe because we checked the minLength above. */
++	    plaintext->len -= crSpec->mac_size;
+ 
+-	rv = ssl3_ComputeRecordMAC(
+-	    crSpec, (PRBool)(!ss->sec.isServer),
+-	    IS_DTLS(ss), rType, cText->version,
+-	    IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+-	    plaintext->buf, plaintext->len,
+-	    hash, &hashBytes);
++	    rv = ssl3_ComputeRecordMAC(
++		crSpec, (PRBool)(!ss->sec.isServer), header, headerLen,
++		plaintext->buf, plaintext->len, hash, &hashBytes);
+ 
+-	/* We can read the MAC directly from the record because its location is
+-	 * public when a stream cipher is used. */
+-	givenHash = plaintext->buf + plaintext->len;
+-    }
++	    /* We can read the MAC directly from the record because its location
++	     * is public when a stream cipher is used. */
++	    givenHash = plaintext->buf + plaintext->len;
++	}
+ 
+-    good &= SECStatusToMask(rv);
++	good &= SECStatusToMask(rv);
+ 
+-    if (hashBytes != (unsigned)crSpec->mac_size ||
+-	NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) {
+-	/* We're allowed to leak whether or not the MAC check was correct */
+-	good = 0;
++	if (hashBytes != (unsigned)crSpec->mac_size ||
++	    NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) {
++	    /* We're allowed to leak whether or not the MAC check was correct */
++	    good = 0;
++	}
+     }
+ 
+     if (good == 0) {
+Index: net/third_party/nss/ssl/sslenum.c
+===================================================================
+--- net/third_party/nss/ssl/sslenum.c	(revision 217715)
++++ net/third_party/nss/ssl/sslenum.c	(working copy)
+@@ -29,6 +29,14 @@
+  * Finally, update the ssl_V3_SUITES_IMPLEMENTED macro in sslimpl.h.
+  */
+ const PRUint16 SSL_ImplementedCiphers[] = {
++    /* AES-GCM */
++#ifdef NSS_ENABLE_ECC
++    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
++    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
++#endif /* NSS_ENABLE_ECC */
++    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
++    TLS_RSA_WITH_AES_128_GCM_SHA256,
++
+     /* 256-bit */
+ #ifdef NSS_ENABLE_ECC
+     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+Index: net/third_party/nss/ssl/sslproto.h
+===================================================================
+--- net/third_party/nss/ssl/sslproto.h	(revision 217715)
++++ net/third_party/nss/ssl/sslproto.h	(working copy)
+@@ -162,6 +162,10 @@
+ 
+ #define TLS_RSA_WITH_SEED_CBC_SHA		0x0096
+ 
++#define TLS_RSA_WITH_AES_128_GCM_SHA256         0x009C
++#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256     0x009E
++#define TLS_DHE_DSS_WITH_AES_128_GCM_SHA256     0x00A2
++
+ /* TLS "Signaling Cipher Suite Value" (SCSV). May be requested by client.
+  * Must NEVER be chosen by server.  SSL 3.0 server acknowledges by sending
+  * back an empty Renegotiation Info (RI) server hello extension.
+@@ -204,6 +208,11 @@
+ #define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
+ #define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256   0xC027
+ 
++#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
++#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256  0xC02D
++#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   0xC02F
++#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256    0xC031
++
+ /* Netscape "experimental" cipher suites. */
+ #define SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA	0xffe0
+ #define SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA	0xffe1
+Index: net/third_party/nss/ssl/sslt.h
+===================================================================
+--- net/third_party/nss/ssl/sslt.h	(revision 217715)
++++ net/third_party/nss/ssl/sslt.h	(working copy)
+@@ -91,9 +91,10 @@
+     ssl_calg_3des     = 4,
+     ssl_calg_idea     = 5,
+     ssl_calg_fortezza = 6,      /* deprecated, now unused */
+-    ssl_calg_aes      = 7,      /* coming soon */
++    ssl_calg_aes      = 7,
+     ssl_calg_camellia = 8,
+-    ssl_calg_seed     = 9
++    ssl_calg_seed     = 9,
++    ssl_calg_aes_gcm  = 10
+ } SSLCipherAlgorithm;
+ 
+ typedef enum { 
+@@ -102,7 +103,8 @@
+     ssl_mac_sha       = 2, 
+     ssl_hmac_md5      = 3, 	/* TLS HMAC version of mac_md5 */
+     ssl_hmac_sha      = 4, 	/* TLS HMAC version of mac_sha */
+-    ssl_hmac_sha256   = 5
++    ssl_hmac_sha256   = 5,
++    ssl_mac_aead      = 6
+ } SSLMACAlgorithm;
+ 
+ typedef enum {
+@@ -158,6 +160,9 @@
+     PRUint16             effectiveKeyBits;
+ 
+     /* MAC info */
++    /* AEAD ciphers don't have a MAC. For an AEAD cipher, macAlgorithmName
++     * is "AEAD", macAlgorithm is ssl_mac_aead, and macBits is the length in
++     * bits of the authentication tag. */
+     const char *         macAlgorithmName;
+     SSLMACAlgorithm      macAlgorithm;
+     PRUint16             macBits;
diff --git a/net/third_party/nss/patches/aesgcmchromium.patch b/net/third_party/nss/patches/aesgcmchromium.patch
new file mode 100644
index 0000000..f9ec6cb
--- /dev/null
+++ b/net/third_party/nss/patches/aesgcmchromium.patch
@@ -0,0 +1,117 @@
+--- net/third_party/nss/ssl/ssl3con.c.orig	2013-08-20 12:00:16.742760827 -0700
++++ net/third_party/nss/ssl/ssl3con.c	2013-08-20 11:59:56.782463207 -0700
+@@ -44,6 +44,9 @@
+ #ifdef NSS_ENABLE_ZLIB
+ #include "zlib.h"
+ #endif
++#ifdef LINUX
++#include <dlfcn.h>
++#endif
+ 
+ #ifndef PK11_SETATTRS
+ #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
+@@ -1819,6 +1822,69 @@ ssl3_BuildRecordPseudoHeader(unsigned ch
+     return 13;
+ }
+ 
++typedef SECStatus (*PK11CryptFcn)(
++    PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism, SECItem *param,
++    unsigned char *out, unsigned int *outLen, unsigned int maxLen,
++    const unsigned char *in, unsigned int inLen);
++
++static PK11CryptFcn pk11_encrypt = NULL;
++static PK11CryptFcn pk11_decrypt = NULL;
++
++static PRCallOnceType resolvePK11CryptOnce;
++
++static PRStatus
++ssl3_ResolvePK11CryptFunctions(void)
++{
++#ifdef LINUX
++    /* On Linux we use the system NSS libraries. Look up the PK11_Encrypt and
++     * PK11_Decrypt functions at run time. */
++    void *handle = dlopen(NULL, RTLD_LAZY);
++    if (!handle) {
++	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
++	return PR_FAILURE;
++    }
++    pk11_encrypt = (PK11CryptFcn)dlsym(handle, "PK11_Encrypt");
++    pk11_decrypt = (PK11CryptFcn)dlsym(handle, "PK11_Decrypt");
++    dlclose(handle);
++    return PR_SUCCESS;
++#else
++    /* On other platforms we use our own copy of NSS. PK11_Encrypt and
++     * PK11_Decrypt are known to be available. */
++    pk11_encrypt = PK11_Encrypt;
++    pk11_decrypt = PK11_Decrypt;
++    return PR_SUCCESS;
++#endif
++}
++
++/* 
++ * In NSS 3.15, PK11_Encrypt and PK11_Decrypt were added to provide access
++ * to the AES GCM implementation in the NSS softoken. So the presence of
++ * these two functions implies the NSS version supports AES GCM.
++ */
++static PRBool
++ssl3_HasGCMSupport(void)
++{
++    (void)PR_CallOnce(&resolvePK11CryptOnce, ssl3_ResolvePK11CryptFunctions);
++    return pk11_encrypt != NULL;
++}
++
++/* On this socket, disable the GCM cipher suites */
++SECStatus
++ssl3_DisableGCMSuites(sslSocket * ss)
++{
++    unsigned int i;
++
++    for (i = 0; i < PR_ARRAY_SIZE(cipher_suite_defs); i++) {
++	const ssl3CipherSuiteDef *cipher_def = &cipher_suite_defs[i];
++	if (cipher_def->bulk_cipher_alg == cipher_aes_128_gcm) {
++	    SECStatus rv = ssl3_CipherPrefSet(ss, cipher_def->cipher_suite,
++					      PR_FALSE);
++	    PORT_Assert(rv == SECSuccess); /* else is coding error */
++	}
++    }
++    return SECSuccess;
++}
++
+ static SECStatus
+ ssl3_AESGCM(ssl3KeyMaterial *keys,
+ 	    PRBool doDecrypt,
+@@ -1870,10 +1936,10 @@ ssl3_AESGCM(ssl3KeyMaterial *keys,
+     gcmParams.ulTagBits = tagSize * 8;
+ 
+     if (doDecrypt) {
+-	rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
++	rv = pk11_decrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+ 			  maxout, in, inlen);
+     } else {
+-	rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
++	rv = pk11_encrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+ 			  maxout, in, inlen);
+     }
+     *outlen += (int) uOutLen;
+@@ -5023,6 +5089,10 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
+ 	ssl3_DisableNonDTLSSuites(ss);
+     }
+ 
++    if (!ssl3_HasGCMSupport()) {
++	ssl3_DisableGCMSuites(ss);
++    }
++
+     /* how many suites are permitted by policy and user preference? */
+     num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE);
+     if (!num_suites)
+@@ -7728,6 +7798,10 @@ ssl3_HandleClientHello(sslSocket *ss, SS
+ 	ssl3_DisableNonDTLSSuites(ss);
+     }
+ 
++    if (!ssl3_HasGCMSupport()) {
++	ssl3_DisableGCMSuites(ss);
++    }
++
+ #ifdef PARANOID
+     /* Look for a matching cipher suite. */
+     j = ssl3_config_match_init(ss);
diff --git a/net/third_party/nss/patches/applypatches.sh b/net/third_party/nss/patches/applypatches.sh
index e768a64..14377ac 100755
--- a/net/third_party/nss/patches/applypatches.sh
+++ b/net/third_party/nss/patches/applypatches.sh
@@ -47,3 +47,7 @@
 patch -p4 < $patches_dir/alpn.patch
 
 patch -p5 < $patches_dir/sslsock_903565.patch
+
+patch -p4 < $patches_dir/aesgcm.patch
+
+patch -p4 < $patches_dir/aesgcmchromium.patch
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index 98e31d4..1ed0d90 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -44,6 +44,9 @@
 #ifdef NSS_ENABLE_ZLIB
 #include "zlib.h"
 #endif
+#ifdef LINUX
+#include <dlfcn.h>
+#endif
 
 #ifndef PK11_SETATTRS
 #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
@@ -78,6 +81,13 @@
 static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
 			     int maxOutputLen, const unsigned char *input,
 			     int inputLen);
+#ifndef NO_PKCS11_BYPASS
+static SECStatus ssl3_AESGCMBypass(ssl3KeyMaterial *keys, PRBool doDecrypt,
+				   unsigned char *out, int *outlen, int maxout,
+				   const unsigned char *in, int inlen,
+				   const unsigned char *additionalData,
+				   int additionalDataLen);
+#endif
 
 #define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */
 #define MIN_SEND_BUF_LENGTH  4000
@@ -90,6 +100,13 @@
 static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
    /*      cipher_suite                         policy      enabled is_present*/
 #ifdef NSS_ENABLE_ECC
+ { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,  SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
+#endif /* NSS_ENABLE_ECC */
+ { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,    SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+ { TLS_RSA_WITH_AES_128_GCM_SHA256,        SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE},
+
+#ifdef NSS_ENABLE_ECC
  { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,   SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,     SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE},
 #endif /* NSS_ENABLE_ECC */
@@ -233,23 +250,30 @@
 
 /* indexed by SSL3BulkCipher */
 static const ssl3BulkCipherDef bulk_cipher_defs[] = {
-    /* cipher          calg        keySz secretSz  type  ivSz BlkSz keygen */
-    {cipher_null,      calg_null,      0,  0, type_stream,  0, 0, kg_null},
-    {cipher_rc4,       calg_rc4,      16, 16, type_stream,  0, 0, kg_strong},
-    {cipher_rc4_40,    calg_rc4,      16,  5, type_stream,  0, 0, kg_export},
-    {cipher_rc4_56,    calg_rc4,      16,  7, type_stream,  0, 0, kg_export},
-    {cipher_rc2,       calg_rc2,      16, 16, type_block,   8, 8, kg_strong},
-    {cipher_rc2_40,    calg_rc2,      16,  5, type_block,   8, 8, kg_export},
-    {cipher_des,       calg_des,       8,  8, type_block,   8, 8, kg_strong},
-    {cipher_3des,      calg_3des,     24, 24, type_block,   8, 8, kg_strong},
-    {cipher_des40,     calg_des,       8,  5, type_block,   8, 8, kg_export},
-    {cipher_idea,      calg_idea,     16, 16, type_block,   8, 8, kg_strong},
-    {cipher_aes_128,   calg_aes,      16, 16, type_block,  16,16, kg_strong},
-    {cipher_aes_256,   calg_aes,      32, 32, type_block,  16,16, kg_strong},
-    {cipher_camellia_128, calg_camellia,16, 16, type_block,  16,16, kg_strong},
-    {cipher_camellia_256, calg_camellia,32, 32, type_block,  16,16, kg_strong},
-    {cipher_seed,      calg_seed,     16, 16, type_block,  16,16, kg_strong},
-    {cipher_missing,   calg_null,      0,  0, type_stream,  0, 0, kg_null},
+    /*                                       |--------- Lengths --------| */
+    /* cipher             calg               k  s  type         i  b  t  n */
+    /*                                       e  e               v  l  a  o */
+    /*                                       y  c               |  o  g  n */
+    /*                                       |  r               |  c  |  c */
+    /*                                       |  e               |  k  |  e */
+    /*                                       |  t               |  |  |  | */
+    {cipher_null,         calg_null,         0, 0, type_stream, 0, 0, 0, 0},
+    {cipher_rc4,          calg_rc4,         16,16, type_stream, 0, 0, 0, 0},
+    {cipher_rc4_40,       calg_rc4,         16, 5, type_stream, 0, 0, 0, 0},
+    {cipher_rc4_56,       calg_rc4,         16, 7, type_stream, 0, 0, 0, 0},
+    {cipher_rc2,          calg_rc2,         16,16, type_block,  8, 8, 0, 0},
+    {cipher_rc2_40,       calg_rc2,         16, 5, type_block,  8, 8, 0, 0},
+    {cipher_des,          calg_des,          8, 8, type_block,  8, 8, 0, 0},
+    {cipher_3des,         calg_3des,        24,24, type_block,  8, 8, 0, 0},
+    {cipher_des40,        calg_des,          8, 5, type_block,  8, 8, 0, 0},
+    {cipher_idea,         calg_idea,        16,16, type_block,  8, 8, 0, 0},
+    {cipher_aes_128,      calg_aes,         16,16, type_block, 16,16, 0, 0},
+    {cipher_aes_256,      calg_aes,         32,32, type_block, 16,16, 0, 0},
+    {cipher_camellia_128, calg_camellia,    16,16, type_block, 16,16, 0, 0},
+    {cipher_camellia_256, calg_camellia,    32,32, type_block, 16,16, 0, 0},
+    {cipher_seed,         calg_seed,        16,16, type_block, 16,16, 0, 0},
+    {cipher_aes_128_gcm,  calg_aes_gcm,     16,16, type_aead,   4, 0,16, 8},
+    {cipher_missing,      calg_null,         0, 0, type_stream, 0, 0, 0, 0},
 };
 
 static const ssl3KEADef kea_defs[] = 
@@ -371,6 +395,11 @@
     {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips},
     {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des,    mac_sha, kea_rsa_fips},
 
+    {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa},
+    {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa},
+    {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa},
+    {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa},
+
 #ifdef NSS_ENABLE_ECC
     {TLS_ECDH_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdh_ecdsa},
     {TLS_ECDH_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdh_ecdsa},
@@ -434,25 +463,29 @@
     { calg_aes      , CKM_AES_CBC			},
     { calg_camellia , CKM_CAMELLIA_CBC			},
     { calg_seed     , CKM_SEED_CBC			},
+    { calg_aes_gcm  , CKM_AES_GCM			},
 /*  { calg_init     , (CK_MECHANISM_TYPE)0x7fffffffL    }  */
 };
 
-#define mmech_null     (CK_MECHANISM_TYPE)0x80000000L
+#define mmech_invalid  (CK_MECHANISM_TYPE)0x80000000L
 #define mmech_md5      CKM_SSL3_MD5_MAC
 #define mmech_sha      CKM_SSL3_SHA1_MAC
 #define mmech_md5_hmac CKM_MD5_HMAC
 #define mmech_sha_hmac CKM_SHA_1_HMAC
 #define mmech_sha256_hmac CKM_SHA256_HMAC
+#define mmech_sha384_hmac CKM_SHA384_HMAC
+#define mmech_sha512_hmac CKM_SHA512_HMAC
 
 static const ssl3MACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */
     /* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */
     /* mac      mmech       pad_size  mac_size                       */
-    { mac_null, mmech_null,       0,  0          },
+    { mac_null, mmech_invalid,    0,  0          },
     { mac_md5,  mmech_md5,       48,  MD5_LENGTH },
     { mac_sha,  mmech_sha,       40,  SHA1_LENGTH},
     {hmac_md5,  mmech_md5_hmac,   0,  MD5_LENGTH },
     {hmac_sha,  mmech_sha_hmac,   0,  SHA1_LENGTH},
     {hmac_sha256, mmech_sha256_hmac, 0, SHA256_LENGTH},
+    { mac_aead, mmech_invalid,    0,  0          },
 };
 
 /* indexed by SSL3BulkCipher */
@@ -472,6 +505,7 @@
     "Camellia-128",
     "Camellia-256",
     "SEED-CBC",
+    "AES-128-GCM",
     "missing"
 };
 
@@ -598,9 +632,13 @@
     case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
     case TLS_RSA_WITH_AES_256_CBC_SHA256:
     case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+    case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
     case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
     case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+    case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
     case TLS_RSA_WITH_AES_128_CBC_SHA256:
+    case TLS_RSA_WITH_AES_128_GCM_SHA256:
     case TLS_RSA_WITH_NULL_SHA256:
 	return version >= SSL_LIBRARY_VERSION_TLS_1_2;
     default:
@@ -1360,7 +1398,7 @@
     cipher = suite_def->bulk_cipher_alg;
     kea    = suite_def->key_exchange_alg;
     mac    = suite_def->mac_alg;
-    if (mac <= ssl_mac_sha && isTLS)
+    if (mac <= ssl_mac_sha && mac != ssl_mac_null && isTLS)
 	mac += 2;
 
     ss->ssl3.hs.suite_def = suite_def;
@@ -1554,7 +1592,6 @@
       unsigned int       optArg2  = 0;
       PRBool             server_encrypts = ss->sec.isServer;
       SSLCipherAlgorithm calg;
-      SSLCompressionMethod compression_method;
       SECStatus          rv;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -1565,7 +1602,17 @@
     cipher_def    = pwSpec->cipher_def;
 
     calg = cipher_def->calg;
-    compression_method = pwSpec->compression_method;
+
+    if (calg == calg_aes_gcm) {
+	pwSpec->encode = NULL;
+	pwSpec->decode = NULL;
+	pwSpec->destroy = NULL;
+	pwSpec->encodeContext = NULL;
+	pwSpec->decodeContext = NULL;
+	pwSpec->aead = ssl3_AESGCMBypass;
+	ssl3_InitCompressionContext(pwSpec);
+	return SECSuccess;
+    }
 
     serverContext = pwSpec->server.cipher_context;
     clientContext = pwSpec->client.cipher_context;
@@ -1721,6 +1768,258 @@
     return param;
 }
 
+/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data
+ * which is included in the MAC or AEAD additional data) to |out| and returns
+ * its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the
+ * definition of the AEAD additional data.
+ *
+ * TLS pseudo-header includes the record's version field, SSL's doesn't. Which
+ * pseudo-header defintiion to use should be decided based on the version of
+ * the protocol that was negotiated when the cipher spec became current, NOT
+ * based on the version value in the record itself, and the decision is passed
+ * to this function as the |includesVersion| argument. But, the |version|
+ * argument should be the record's version value.
+ */
+static unsigned int
+ssl3_BuildRecordPseudoHeader(unsigned char *out,
+			     SSL3SequenceNumber seq_num,
+			     SSL3ContentType type,
+			     PRBool includesVersion,
+			     SSL3ProtocolVersion version,
+			     PRBool isDTLS,
+			     int length)
+{
+    out[0] = (unsigned char)(seq_num.high >> 24);
+    out[1] = (unsigned char)(seq_num.high >> 16);
+    out[2] = (unsigned char)(seq_num.high >>  8);
+    out[3] = (unsigned char)(seq_num.high >>  0);
+    out[4] = (unsigned char)(seq_num.low  >> 24);
+    out[5] = (unsigned char)(seq_num.low  >> 16);
+    out[6] = (unsigned char)(seq_num.low  >>  8);
+    out[7] = (unsigned char)(seq_num.low  >>  0);
+    out[8] = type;
+
+    /* SSL3 MAC doesn't include the record's version field. */
+    if (!includesVersion) {
+	out[9]  = MSB(length);
+	out[10] = LSB(length);
+	return 11;
+    }
+
+    /* TLS MAC and AEAD additional data include version. */
+    if (isDTLS) {
+	SSL3ProtocolVersion dtls_version;
+
+	dtls_version = dtls_TLSVersionToDTLSVersion(version);
+	out[9]  = MSB(dtls_version);
+	out[10] = LSB(dtls_version);
+    } else {
+	out[9]  = MSB(version);
+	out[10] = LSB(version);
+    }
+    out[11] = MSB(length);
+    out[12] = LSB(length);
+    return 13;
+}
+
+typedef SECStatus (*PK11CryptFcn)(
+    PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism, SECItem *param,
+    unsigned char *out, unsigned int *outLen, unsigned int maxLen,
+    const unsigned char *in, unsigned int inLen);
+
+static PK11CryptFcn pk11_encrypt = NULL;
+static PK11CryptFcn pk11_decrypt = NULL;
+
+static PRCallOnceType resolvePK11CryptOnce;
+
+static PRStatus
+ssl3_ResolvePK11CryptFunctions(void)
+{
+#ifdef LINUX
+    /* On Linux we use the system NSS libraries. Look up the PK11_Encrypt and
+     * PK11_Decrypt functions at run time. */
+    void *handle = dlopen(NULL, RTLD_LAZY);
+    if (!handle) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return PR_FAILURE;
+    }
+    pk11_encrypt = (PK11CryptFcn)dlsym(handle, "PK11_Encrypt");
+    pk11_decrypt = (PK11CryptFcn)dlsym(handle, "PK11_Decrypt");
+    dlclose(handle);
+    return PR_SUCCESS;
+#else
+    /* On other platforms we use our own copy of NSS. PK11_Encrypt and
+     * PK11_Decrypt are known to be available. */
+    pk11_encrypt = PK11_Encrypt;
+    pk11_decrypt = PK11_Decrypt;
+    return PR_SUCCESS;
+#endif
+}
+
+/* 
+ * In NSS 3.15, PK11_Encrypt and PK11_Decrypt were added to provide access
+ * to the AES GCM implementation in the NSS softoken. So the presence of
+ * these two functions implies the NSS version supports AES GCM.
+ */
+static PRBool
+ssl3_HasGCMSupport(void)
+{
+    (void)PR_CallOnce(&resolvePK11CryptOnce, ssl3_ResolvePK11CryptFunctions);
+    return pk11_encrypt != NULL;
+}
+
+/* On this socket, disable the GCM cipher suites */
+SECStatus
+ssl3_DisableGCMSuites(sslSocket * ss)
+{
+    unsigned int i;
+
+    for (i = 0; i < PR_ARRAY_SIZE(cipher_suite_defs); i++) {
+	const ssl3CipherSuiteDef *cipher_def = &cipher_suite_defs[i];
+	if (cipher_def->bulk_cipher_alg == cipher_aes_128_gcm) {
+	    SECStatus rv = ssl3_CipherPrefSet(ss, cipher_def->cipher_suite,
+					      PR_FALSE);
+	    PORT_Assert(rv == SECSuccess); /* else is coding error */
+	}
+    }
+    return SECSuccess;
+}
+
+static SECStatus
+ssl3_AESGCM(ssl3KeyMaterial *keys,
+	    PRBool doDecrypt,
+	    unsigned char *out,
+	    int *outlen,
+	    int maxout,
+	    const unsigned char *in,
+	    int inlen,
+	    const unsigned char *additionalData,
+	    int additionalDataLen)
+{
+    SECItem            param;
+    SECStatus          rv = SECFailure;
+    unsigned char      nonce[12];
+    unsigned int       uOutLen;
+    CK_GCM_PARAMS      gcmParams;
+
+    static const int   tagSize = 16;
+    static const int   explicitNonceLen = 8;
+
+    /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
+     * nonce is formed. */
+    memcpy(nonce, keys->write_iv, 4);
+    if (doDecrypt) {
+	memcpy(nonce + 4, in, explicitNonceLen);
+	in += explicitNonceLen;
+	inlen -= explicitNonceLen;
+	*outlen = 0;
+    } else {
+	if (maxout < explicitNonceLen) {
+	    PORT_SetError(SEC_ERROR_INPUT_LEN);
+	    return SECFailure;
+        }
+	/* Use the 64-bit sequence number as the explicit nonce. */
+	memcpy(nonce + 4, additionalData, explicitNonceLen);
+	memcpy(out, additionalData, explicitNonceLen);
+	out += explicitNonceLen;
+	maxout -= explicitNonceLen;
+	*outlen = explicitNonceLen;
+    }
+
+    param.type = siBuffer;
+    param.data = (unsigned char *) &gcmParams;
+    param.len = sizeof(gcmParams);
+    gcmParams.pIv = nonce;
+    gcmParams.ulIvLen = sizeof(nonce);
+    gcmParams.pAAD = (unsigned char *)additionalData;  /* const cast */
+    gcmParams.ulAADLen = additionalDataLen;
+    gcmParams.ulTagBits = tagSize * 8;
+
+    if (doDecrypt) {
+	rv = pk11_decrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+			  maxout, in, inlen);
+    } else {
+	rv = pk11_encrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
+			  maxout, in, inlen);
+    }
+    *outlen += (int) uOutLen;
+
+    return rv;
+}
+
+#ifndef NO_PKCS11_BYPASS
+static SECStatus
+ssl3_AESGCMBypass(ssl3KeyMaterial *keys,
+		  PRBool doDecrypt,
+		  unsigned char *out,
+		  int *outlen,
+		  int maxout,
+		  const unsigned char *in,
+		  int inlen,
+		  const unsigned char *additionalData,
+		  int additionalDataLen)
+{
+    SECStatus          rv = SECFailure;
+    unsigned char      nonce[12];
+    unsigned int       uOutLen;
+    AESContext        *cx;
+    CK_GCM_PARAMS      gcmParams;
+
+    static const int   tagSize = 16;
+    static const int   explicitNonceLen = 8;
+
+    /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
+     * nonce is formed. */
+    PORT_Assert(keys->write_iv_item.len == 4);
+    if (keys->write_iv_item.len != 4) {
+	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	return SECFailure;
+    }
+    memcpy(nonce, keys->write_iv_item.data, 4);
+    if (doDecrypt) {
+	memcpy(nonce + 4, in, explicitNonceLen);
+	in += explicitNonceLen;
+	inlen -= explicitNonceLen;
+	*outlen = 0;
+    } else {
+	if (maxout < explicitNonceLen) {
+	    PORT_SetError(SEC_ERROR_INPUT_LEN);
+	    return SECFailure;
+        }
+	/* Use the 64-bit sequence number as the explicit nonce. */
+	memcpy(nonce + 4, additionalData, explicitNonceLen);
+	memcpy(out, additionalData, explicitNonceLen);
+	out += explicitNonceLen;
+	maxout -= explicitNonceLen;
+	*outlen = explicitNonceLen;
+    }
+
+    gcmParams.pIv = nonce;
+    gcmParams.ulIvLen = sizeof(nonce);
+    gcmParams.pAAD = (unsigned char *)additionalData;  /* const cast */
+    gcmParams.ulAADLen = additionalDataLen;
+    gcmParams.ulTagBits = tagSize * 8;
+
+    cx = (AESContext *)keys->cipher_context;
+    rv = AES_InitContext(cx, keys->write_key_item.data,
+			 keys->write_key_item.len,
+			 (unsigned char *)&gcmParams, NSS_AES_GCM, !doDecrypt,
+			 AES_BLOCK_SIZE);
+    if (rv != SECSuccess) {
+	return rv;
+    }
+    if (doDecrypt) {
+	rv = AES_Decrypt(cx, out, &uOutLen, maxout, in, inlen);
+    } else {
+	rv = AES_Encrypt(cx, out, &uOutLen, maxout, in, inlen);
+    }
+    AES_DestroyContext(cx, PR_FALSE);
+    *outlen += (int) uOutLen;
+
+    return rv;
+}
+#endif
+
 /* Initialize encryption and MAC contexts for pending spec.
  * Master Secret already is derived.
  * Caller holds Spec write lock.
@@ -1748,14 +2047,27 @@
     pwSpec        = ss->ssl3.pwSpec;
     cipher_def    = pwSpec->cipher_def;
     macLength     = pwSpec->mac_size;
+    calg          = cipher_def->calg;
+    PORT_Assert(alg2Mech[calg].calg == calg);
+
+    pwSpec->client.write_mac_context = NULL;
+    pwSpec->server.write_mac_context = NULL;
+
+    if (calg == calg_aes_gcm) {
+	pwSpec->encode = NULL;
+	pwSpec->decode = NULL;
+	pwSpec->destroy = NULL;
+	pwSpec->encodeContext = NULL;
+	pwSpec->decodeContext = NULL;
+	pwSpec->aead = ssl3_AESGCM;
+	return SECSuccess;
+    }
 
     /* 
     ** Now setup the MAC contexts, 
     **   crypto contexts are setup below.
     */
 
-    pwSpec->client.write_mac_context = NULL;
-    pwSpec->server.write_mac_context = NULL;
     mac_mech       = pwSpec->mac_def->mmech;
     mac_param.data = (unsigned char *)&macLength;
     mac_param.len  = sizeof(macLength);
@@ -1778,9 +2090,6 @@
     ** Now setup the crypto contexts.
     */
 
-    calg = cipher_def->calg;
-    PORT_Assert(alg2Mech[calg].calg == calg);
-
     if (calg == calg_null) {
 	pwSpec->encode  = Null_Cipher;
 	pwSpec->decode  = Null_Cipher;
@@ -1988,10 +2297,8 @@
 ssl3_ComputeRecordMAC(
     ssl3CipherSpec *   spec,
     PRBool             useServerMacKey,
-    PRBool             isDTLS,
-    SSL3ContentType    type,
-    SSL3ProtocolVersion version,
-    SSL3SequenceNumber seq_num,
+    const unsigned char *header,
+    unsigned int       headerLen,
     const SSL3Opaque * input,
     int                inputLength,
     unsigned char *    outbuf,
@@ -1999,56 +2306,8 @@
 {
     const ssl3MACDef * mac_def;
     SECStatus          rv;
-#ifndef NO_PKCS11_BYPASS
-    PRBool             isTLS;
-#endif
-    unsigned int       tempLen;
-    unsigned char      temp[MAX_MAC_LENGTH];
 
-    temp[0] = (unsigned char)(seq_num.high >> 24);
-    temp[1] = (unsigned char)(seq_num.high >> 16);
-    temp[2] = (unsigned char)(seq_num.high >>  8);
-    temp[3] = (unsigned char)(seq_num.high >>  0);
-    temp[4] = (unsigned char)(seq_num.low  >> 24);
-    temp[5] = (unsigned char)(seq_num.low  >> 16);
-    temp[6] = (unsigned char)(seq_num.low  >>  8);
-    temp[7] = (unsigned char)(seq_num.low  >>  0);
-    temp[8] = type;
-
-    /* TLS MAC includes the record's version field, SSL's doesn't.
-    ** We decide which MAC defintiion to use based on the version of 
-    ** the protocol that was negotiated when the spec became current,
-    ** NOT based on the version value in the record itself.
-    ** But, we use the record'v version value in the computation.
-    */
-    if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
-	temp[9]  = MSB(inputLength);
-	temp[10] = LSB(inputLength);
-	tempLen  = 11;
-#ifndef NO_PKCS11_BYPASS
-	isTLS    = PR_FALSE;
-#endif
-    } else {
-    	/* New TLS hash includes version. */
-	if (isDTLS) {
-	    SSL3ProtocolVersion dtls_version;
-
-	    dtls_version = dtls_TLSVersionToDTLSVersion(version);
-	    temp[9]  = MSB(dtls_version);
-	    temp[10] = LSB(dtls_version);
-        } else {
-	    temp[9]  = MSB(version);
-	    temp[10] = LSB(version);
-        }
-	temp[11] = MSB(inputLength);
-	temp[12] = LSB(inputLength);
-	tempLen  = 13;
-#ifndef NO_PKCS11_BYPASS
-	isTLS    = PR_TRUE;
-#endif
-    }
-
-    PRINT_BUF(95, (NULL, "frag hash1: temp", temp, tempLen));
+    PRINT_BUF(95, (NULL, "frag hash1: header", header, headerLen));
     PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength));
 
     mac_def = spec->mac_def;
@@ -2093,7 +2352,10 @@
 	    return SECFailure;
 	}
 
-	if (!isTLS) {
+	if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
+	    unsigned int tempLen;
+	    unsigned char temp[MAX_MAC_LENGTH];
+
 	    /* compute "inner" part of SSL3 MAC */
 	    hashObj->begin(write_mac_context);
 	    if (useServerMacKey)
@@ -2105,7 +2367,7 @@
 				spec->client.write_mac_key_item.data,
 				spec->client.write_mac_key_item.len);
 	    hashObj->update(write_mac_context, mac_pad_1, pad_bytes);
-	    hashObj->update(write_mac_context, temp,  tempLen);
+	    hashObj->update(write_mac_context, header, headerLen);
 	    hashObj->update(write_mac_context, input, inputLength);
 	    hashObj->end(write_mac_context,    temp, &tempLen, sizeof temp);
 
@@ -2136,7 +2398,7 @@
 	    }
 	    if (rv == SECSuccess) {
 		HMAC_Begin(cx);
-		HMAC_Update(cx, temp, tempLen);
+		HMAC_Update(cx, header, headerLen);
 		HMAC_Update(cx, input, inputLength);
 		rv = HMAC_Finish(cx, outbuf, outLength, spec->mac_size);
 		HMAC_Destroy(cx, PR_FALSE);
@@ -2150,7 +2412,7 @@
 	    (useServerMacKey ? spec->server.write_mac_context
 	                     : spec->client.write_mac_context);
 	rv  = PK11_DigestBegin(mac_context);
-	rv |= PK11_DigestOp(mac_context, temp, tempLen);
+	rv |= PK11_DigestOp(mac_context, header, headerLen);
 	rv |= PK11_DigestOp(mac_context, input, inputLength);
 	rv |= PK11_DigestFinal(mac_context, outbuf, outLength, spec->mac_size);
     }
@@ -2190,10 +2452,8 @@
 ssl3_ComputeRecordMACConstantTime(
     ssl3CipherSpec *   spec,
     PRBool             useServerMacKey,
-    PRBool             isDTLS,
-    SSL3ContentType    type,
-    SSL3ProtocolVersion version,
-    SSL3SequenceNumber seq_num,
+    const unsigned char *header,
+    unsigned int       headerLen,
     const SSL3Opaque * input,
     int                inputLen,
     int                originalLen,
@@ -2205,9 +2465,7 @@
     PK11Context *                mac_context;
     SECItem                      param;
     SECStatus                    rv;
-    unsigned char                header[13];
     PK11SymKey *                 key;
-    int                          recordLength;
 
     PORT_Assert(inputLen >= spec->mac_size);
     PORT_Assert(originalLen >= inputLen);
@@ -2223,42 +2481,15 @@
 	return SECSuccess;
     }
 
-    header[0] = (unsigned char)(seq_num.high >> 24);
-    header[1] = (unsigned char)(seq_num.high >> 16);
-    header[2] = (unsigned char)(seq_num.high >>  8);
-    header[3] = (unsigned char)(seq_num.high >>  0);
-    header[4] = (unsigned char)(seq_num.low  >> 24);
-    header[5] = (unsigned char)(seq_num.low  >> 16);
-    header[6] = (unsigned char)(seq_num.low  >>  8);
-    header[7] = (unsigned char)(seq_num.low  >>  0);
-    header[8] = type;
-
     macType = CKM_NSS_HMAC_CONSTANT_TIME;
-    recordLength = inputLen - spec->mac_size;
     if (spec->version <= SSL_LIBRARY_VERSION_3_0) {
 	macType = CKM_NSS_SSL3_MAC_CONSTANT_TIME;
-	header[9] = recordLength >> 8;
-	header[10] = recordLength;
-	params.ulHeaderLen = 11;
-    } else {
-	if (isDTLS) {
-	    SSL3ProtocolVersion dtls_version;
-
-	    dtls_version = dtls_TLSVersionToDTLSVersion(version);
-	    header[9] = dtls_version >> 8;
-	    header[10] = dtls_version;
-	} else {
-	    header[9] = version >> 8;
-	    header[10] = version;
-	}
-	header[11] = recordLength >> 8;
-	header[12] = recordLength;
-	params.ulHeaderLen = 13;
     }
 
     params.macAlg = spec->mac_def->mmech;
     params.ulBodyTotalLen = originalLen;
-    params.pHeader = header;
+    params.pHeader = (unsigned char *) header;  /* const cast */
+    params.ulHeaderLen = headerLen;
 
     param.data = (unsigned char*) &params;
     param.len = sizeof(params);
@@ -2291,9 +2522,8 @@
     /* ssl3_ComputeRecordMAC expects the MAC to have been removed from the
      * length already. */
     inputLen -= spec->mac_size;
-    return ssl3_ComputeRecordMAC(spec, useServerMacKey, isDTLS, type,
-				 version, seq_num, input, inputLen,
-				 outbuf, outLen);
+    return ssl3_ComputeRecordMAC(spec, useServerMacKey, header, headerLen,
+				 input, inputLen, outbuf, outLen);
 }
 
 static PRBool
@@ -2345,6 +2575,8 @@
     PRUint16                  headerLen;
     int                       ivLen = 0;
     int                       cipherBytes = 0;
+    unsigned char             pseudoHeader[13];
+    unsigned int              pseudoHeaderLen;
 
     cipher_def = cwSpec->cipher_def;
     headerLen = isDTLS ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
@@ -2390,86 +2622,117 @@
 	contentLen = outlen;
     }
 
-    /*
-     * Add the MAC
-     */
-    rv = ssl3_ComputeRecordMAC( cwSpec, isServer, isDTLS,
-	type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen,
-	wrBuf->buf + headerLen + ivLen + contentLen, &macLen);
-    if (rv != SECSuccess) {
-	ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
-	return SECFailure;
-    }
-    p1Len   = contentLen;
-    p2Len   = macLen;
-    fragLen = contentLen + macLen;	/* needs to be encrypted */
-    PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
+    pseudoHeaderLen = ssl3_BuildRecordPseudoHeader(
+	pseudoHeader, cwSpec->write_seq_num, type,
+	cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->version,
+	isDTLS, contentLen);
+    PORT_Assert(pseudoHeaderLen <= sizeof(pseudoHeader));
+    if (cipher_def->type == type_aead) {
+	const int nonceLen = cipher_def->explicit_nonce_size;
+	const int tagLen = cipher_def->tag_size;
 
-    /*
-     * Pad the text (if we're doing a block cipher)
-     * then Encrypt it
-     */
-    if (cipher_def->type == type_block) {
-	unsigned char * pBuf;
-	int             padding_length;
-	int             i;
-
-	oddLen = contentLen % cipher_def->block_size;
-	/* Assume blockSize is a power of two */
-	padding_length = cipher_def->block_size - 1 -
-			((fragLen) & (cipher_def->block_size - 1));
-	fragLen += padding_length + 1;
-	PORT_Assert((fragLen % cipher_def->block_size) == 0);
-
-	/* Pad according to TLS rules (also acceptable to SSL3). */
-	pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1];
-	for (i = padding_length + 1; i > 0; --i) {
-	    *pBuf-- = padding_length;
+	if (headerLen + nonceLen + contentLen + tagLen > wrBuf->space) {
+	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+	    return SECFailure;
 	}
-	/* now, if contentLen is not a multiple of block size, fix it */
-	p2Len = fragLen - p1Len;
-    }
-    if (p1Len < 256) {
-	oddLen = p1Len;
-	p1Len = 0;
+
+	cipherBytes = contentLen;
+	rv = cwSpec->aead(
+		isServer ? &cwSpec->server : &cwSpec->client,
+		PR_FALSE,                                   /* do encrypt */
+		wrBuf->buf + headerLen,                     /* output  */
+		&cipherBytes,                               /* out len */
+		wrBuf->space - headerLen,                   /* max out */
+		pIn, contentLen,                            /* input   */
+		pseudoHeader, pseudoHeaderLen);
+	if (rv != SECSuccess) {
+	    PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+	    return SECFailure;
+	}
     } else {
-	p1Len -= oddLen;
-    }
-    if (oddLen) {
-	p2Len += oddLen;
-	PORT_Assert( (cipher_def->block_size < 2) || \
-		     (p2Len % cipher_def->block_size) == 0);
-	memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len, oddLen);
-    }
-    if (p1Len > 0) {
-	int cipherBytesPart1 = -1;
-	rv = cwSpec->encode( cwSpec->encodeContext, 
-	    wrBuf->buf + headerLen + ivLen,         /* output */
-	    &cipherBytesPart1,                      /* actual outlen */
-	    p1Len,                                  /* max outlen */
-	    pIn, p1Len);                      /* input, and inputlen */
-	PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len);
-	if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) {
-	    PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+	/*
+	 * Add the MAC
+	 */
+	rv = ssl3_ComputeRecordMAC(cwSpec, isServer,
+	    pseudoHeader, pseudoHeaderLen, pIn, contentLen,
+	    wrBuf->buf + headerLen + ivLen + contentLen, &macLen);
+	if (rv != SECSuccess) {
+	    ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
 	    return SECFailure;
 	}
-	cipherBytes += cipherBytesPart1;
-    }
-    if (p2Len > 0) {
-	int cipherBytesPart2 = -1;
-	rv = cwSpec->encode( cwSpec->encodeContext, 
-	    wrBuf->buf + headerLen + ivLen + p1Len,
-	    &cipherBytesPart2,          /* output and actual outLen */
-	    p2Len,                             /* max outlen */
-	    wrBuf->buf + headerLen + ivLen + p1Len,
-	    p2Len);                            /* input and inputLen*/
-	PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len);
-	if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) {
-	    PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
-	    return SECFailure;
+	p1Len   = contentLen;
+	p2Len   = macLen;
+	fragLen = contentLen + macLen;	/* needs to be encrypted */
+	PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
+
+	/*
+	 * Pad the text (if we're doing a block cipher)
+	 * then Encrypt it
+	 */
+	if (cipher_def->type == type_block) {
+	    unsigned char * pBuf;
+	    int             padding_length;
+	    int             i;
+
+	    oddLen = contentLen % cipher_def->block_size;
+	    /* Assume blockSize is a power of two */
+	    padding_length = cipher_def->block_size - 1 -
+			    ((fragLen) & (cipher_def->block_size - 1));
+	    fragLen += padding_length + 1;
+	    PORT_Assert((fragLen % cipher_def->block_size) == 0);
+
+	    /* Pad according to TLS rules (also acceptable to SSL3). */
+	    pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1];
+	    for (i = padding_length + 1; i > 0; --i) {
+		*pBuf-- = padding_length;
+	    }
+	    /* now, if contentLen is not a multiple of block size, fix it */
+	    p2Len = fragLen - p1Len;
 	}
-	cipherBytes += cipherBytesPart2;
-    }	
+	if (p1Len < 256) {
+	    oddLen = p1Len;
+	    p1Len = 0;
+	} else {
+	    p1Len -= oddLen;
+	}
+	if (oddLen) {
+	    p2Len += oddLen;
+	    PORT_Assert( (cipher_def->block_size < 2) || \
+			 (p2Len % cipher_def->block_size) == 0);
+	    memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len,
+		    oddLen);
+	}
+	if (p1Len > 0) {
+	    int cipherBytesPart1 = -1;
+	    rv = cwSpec->encode( cwSpec->encodeContext, 
+		wrBuf->buf + headerLen + ivLen,         /* output */
+		&cipherBytesPart1,                      /* actual outlen */
+		p1Len,                                  /* max outlen */
+		pIn, p1Len);                      /* input, and inputlen */
+	    PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len);
+	    if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) {
+		PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+		return SECFailure;
+	    }
+	    cipherBytes += cipherBytesPart1;
+	}
+	if (p2Len > 0) {
+	    int cipherBytesPart2 = -1;
+	    rv = cwSpec->encode( cwSpec->encodeContext, 
+		wrBuf->buf + headerLen + ivLen + p1Len,
+		&cipherBytesPart2,          /* output and actual outLen */
+		p2Len,                             /* max outlen */
+		wrBuf->buf + headerLen + ivLen + p1Len,
+		p2Len);                            /* input and inputLen*/
+	    PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len);
+	    if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) {
+		PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
+		return SECFailure;
+	    }
+	    cipherBytes += cipherBytesPart2;
+	}
+    }
+
     PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024);
 
     wrBuf->len    = cipherBytes + headerLen;
@@ -3012,9 +3275,6 @@
 static SECStatus
 ssl3_IllegalParameter(sslSocket *ss)
 {
-    PRBool isTLS;
-
-    isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
     PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
                                    : SSL_ERROR_BAD_SERVER );
@@ -3538,7 +3798,6 @@
     }
 
     key_material_params.bIsExport = (CK_BBOOL)(kea_def->is_limited);
-    /* was:	(CK_BBOOL)(cipher_def->keygen_mode != kg_strong); */
 
     key_material_params.RandomInfo.pClientRandom     = cr;
     key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
@@ -4830,6 +5089,10 @@
 	ssl3_DisableNonDTLSSuites(ss);
     }
 
+    if (!ssl3_HasGCMSupport()) {
+	ssl3_DisableGCMSuites(ss);
+    }
+
     /* how many suites are permitted by policy and user preference? */
     num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE);
     if (!num_suites)
@@ -7535,6 +7798,10 @@
 	ssl3_DisableNonDTLSSuites(ss);
     }
 
+    if (!ssl3_HasGCMSupport()) {
+	ssl3_DisableGCMSuites(ss);
+    }
+
 #ifdef PARANOID
     /* Look for a matching cipher suite. */
     j = ssl3_config_match_init(ss);
@@ -9946,7 +10213,6 @@
 static void
 ssl3_RecordKeyLog(sslSocket *ss)
 {
-    sslSessionID *sid;
     SECStatus rv;
     SECItem *keyData;
     char buf[14 /* "CLIENT_RANDOM " */ +
@@ -9958,8 +10224,6 @@
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
-    sid = ss->sec.ci.sid;
-
     if (!ssl_keylog_iob)
 	return;
 
@@ -11095,6 +11359,8 @@
     unsigned int         originalLen = 0;
     unsigned int         good;
     unsigned int         minLength;
+    unsigned char        header[13];
+    unsigned int         headerLen;
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
 
@@ -11171,12 +11437,14 @@
 	    /* With >= TLS 1.1, CBC records have an explicit IV. */
 	    minLength += cipher_def->iv_size;
 	}
+    } else if (cipher_def->type == type_aead) {
+	minLength = cipher_def->explicit_nonce_size + cipher_def->tag_size;
     }
 
     /* We can perform this test in variable time because the record's total
      * length and the ciphersuite are both public knowledge. */
     if (cText->buf->len < minLength) {
-        goto decrypt_loser;
+	goto decrypt_loser;
     }
 
     if (cipher_def->type == type_block &&
@@ -11244,78 +11512,104 @@
 	return SECFailure;
     }
 
-    if (cipher_def->type == type_block &&
-	((cText->buf->len - ivLen) % cipher_def->block_size) != 0) {
-	goto decrypt_loser;
-    }
-
-    /* decrypt from cText buf to plaintext. */
-    rv = crSpec->decode(
-	crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len,
-	plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
-    if (rv != SECSuccess) {
-	goto decrypt_loser;
-    }
-
-    PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
-
-    originalLen = plaintext->len;
-
-    /* If it's a block cipher, check and strip the padding. */
-    if (cipher_def->type == type_block) {
-	const unsigned int blockSize = cipher_def->block_size;
-	const unsigned int macSize = crSpec->mac_size;
-
-	if (crSpec->version <= SSL_LIBRARY_VERSION_3_0) {
-	    good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding(
-			plaintext, blockSize, macSize));
-	} else {
-	    good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
-			plaintext, macSize));
-	}
-    }
-
-    /* compute the MAC */
     rType = cText->type;
-    if (cipher_def->type == type_block) {
-	rv = ssl3_ComputeRecordMACConstantTime(
-	    crSpec, (PRBool)(!ss->sec.isServer),
-	    IS_DTLS(ss), rType, cText->version,
-	    IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
-	    plaintext->buf, plaintext->len, originalLen,
-	    hash, &hashBytes);
-
-	ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf,
-			  crSpec->mac_size);
-	givenHash = givenHashBuf;
-
-	/* plaintext->len will always have enough space to remove the MAC
-	 * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust
-	 * plaintext->len if the result has enough space for the MAC and we
-	 * tested the unadjusted size against minLength, above. */
-	plaintext->len -= crSpec->mac_size;
+    if (cipher_def->type == type_aead) {
+	/* XXX For many AEAD ciphers, the plaintext is shorter than the
+	 * ciphertext by a fixed byte count, but it is not true in general.
+	 * Each AEAD cipher should provide a function that returns the
+	 * plaintext length for a given ciphertext. */
+	unsigned int decryptedLen =
+	    cText->buf->len - cipher_def->explicit_nonce_size -
+	    cipher_def->tag_size;
+	headerLen = ssl3_BuildRecordPseudoHeader(
+	    header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+	    rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen);
+	PORT_Assert(headerLen <= sizeof(header));
+	rv = crSpec->aead(
+		ss->sec.isServer ? &crSpec->client : &crSpec->server,
+		PR_TRUE,                          /* do decrypt */
+		plaintext->buf,                   /* out */
+		(int*) &plaintext->len,           /* outlen */
+		plaintext->space,                 /* maxout */
+		cText->buf->buf,                  /* in */
+		cText->buf->len,                  /* inlen */
+		header, headerLen);
+	if (rv != SECSuccess) {
+	    good = 0;
+	}
     } else {
-	/* This is safe because we checked the minLength above. */
-	plaintext->len -= crSpec->mac_size;
+	if (cipher_def->type == type_block &&
+	    ((cText->buf->len - ivLen) % cipher_def->block_size) != 0) {
+	    goto decrypt_loser;
+	}
 
-	rv = ssl3_ComputeRecordMAC(
-	    crSpec, (PRBool)(!ss->sec.isServer),
-	    IS_DTLS(ss), rType, cText->version,
-	    IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
-	    plaintext->buf, plaintext->len,
-	    hash, &hashBytes);
+	/* decrypt from cText buf to plaintext. */
+	rv = crSpec->decode(
+	    crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len,
+	    plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
+	if (rv != SECSuccess) {
+	    goto decrypt_loser;
+	}
 
-	/* We can read the MAC directly from the record because its location is
-	 * public when a stream cipher is used. */
-	givenHash = plaintext->buf + plaintext->len;
-    }
+	PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
 
-    good &= SECStatusToMask(rv);
+	originalLen = plaintext->len;
 
-    if (hashBytes != (unsigned)crSpec->mac_size ||
-	NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) {
-	/* We're allowed to leak whether or not the MAC check was correct */
-	good = 0;
+	/* If it's a block cipher, check and strip the padding. */
+	if (cipher_def->type == type_block) {
+	    const unsigned int blockSize = cipher_def->block_size;
+	    const unsigned int macSize = crSpec->mac_size;
+
+	    if (!isTLS) {
+		good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding(
+			    plaintext, blockSize, macSize));
+	    } else {
+		good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
+			    plaintext, macSize));
+	    }
+	}
+
+	/* compute the MAC */
+	headerLen = ssl3_BuildRecordPseudoHeader(
+	    header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+	    rType, isTLS, cText->version, IS_DTLS(ss),
+	    plaintext->len - crSpec->mac_size);
+	PORT_Assert(headerLen <= sizeof(header));
+	if (cipher_def->type == type_block) {
+	    rv = ssl3_ComputeRecordMACConstantTime(
+		crSpec, (PRBool)(!ss->sec.isServer), header, headerLen,
+		plaintext->buf, plaintext->len, originalLen,
+		hash, &hashBytes);
+
+	    ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf,
+			      crSpec->mac_size);
+	    givenHash = givenHashBuf;
+
+	    /* plaintext->len will always have enough space to remove the MAC
+	     * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust
+	     * plaintext->len if the result has enough space for the MAC and we
+	     * tested the unadjusted size against minLength, above. */
+	    plaintext->len -= crSpec->mac_size;
+	} else {
+	    /* This is safe because we checked the minLength above. */
+	    plaintext->len -= crSpec->mac_size;
+
+	    rv = ssl3_ComputeRecordMAC(
+		crSpec, (PRBool)(!ss->sec.isServer), header, headerLen,
+		plaintext->buf, plaintext->len, hash, &hashBytes);
+
+	    /* We can read the MAC directly from the record because its location
+	     * is public when a stream cipher is used. */
+	    givenHash = plaintext->buf + plaintext->len;
+	}
+
+	good &= SECStatusToMask(rv);
+
+	if (hashBytes != (unsigned)crSpec->mac_size ||
+	    NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) {
+	    /* We're allowed to leak whether or not the MAC check was correct */
+	    good = 0;
+	}
     }
 
     if (good == 0) {
diff --git a/net/third_party/nss/ssl/ssl3ecc.c b/net/third_party/nss/ssl/ssl3ecc.c
index 74995f1..a3638e7 100644
--- a/net/third_party/nss/ssl/ssl3ecc.c
+++ b/net/third_party/nss/ssl/ssl3ecc.c
@@ -911,6 +911,7 @@
     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_NULL_SHA,
     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
@@ -921,6 +922,7 @@
     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
     TLS_ECDHE_RSA_WITH_NULL_SHA,
     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
@@ -932,12 +934,14 @@
     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_NULL_SHA,
     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
     TLS_ECDHE_RSA_WITH_NULL_SHA,
     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
diff --git a/net/third_party/nss/ssl/sslenum.c b/net/third_party/nss/ssl/sslenum.c
index b460f26..597ec07 100644
--- a/net/third_party/nss/ssl/sslenum.c
+++ b/net/third_party/nss/ssl/sslenum.c
@@ -29,6 +29,14 @@
  * Finally, update the ssl_V3_SUITES_IMPLEMENTED macro in sslimpl.h.
  */
 const PRUint16 SSL_ImplementedCiphers[] = {
+    /* AES-GCM */
+#ifdef NSS_ENABLE_ECC
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+#endif /* NSS_ENABLE_ECC */
+    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+    TLS_RSA_WITH_AES_128_GCM_SHA256,
+
     /* 256-bit */
 #ifdef NSS_ENABLE_ECC
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h
index e6792b3..1f08542 100644
--- a/net/third_party/nss/ssl/sslimpl.h
+++ b/net/third_party/nss/ssl/sslimpl.h
@@ -64,6 +64,7 @@
 #define calg_aes	ssl_calg_aes
 #define calg_camellia	ssl_calg_camellia
 #define calg_seed	ssl_calg_seed
+#define calg_aes_gcm    ssl_calg_aes_gcm
 
 #define mac_null	ssl_mac_null
 #define mac_md5 	ssl_mac_md5
@@ -71,6 +72,7 @@
 #define hmac_md5	ssl_hmac_md5
 #define hmac_sha	ssl_hmac_sha
 #define hmac_sha256	ssl_hmac_sha256
+#define mac_aead	ssl_mac_aead
 
 #define SET_ERROR_CODE		/* reminder */
 #define SEND_ALERT		/* reminder */
@@ -290,9 +292,9 @@
 } ssl3CipherSuiteCfg;
 
 #ifdef NSS_ENABLE_ECC
-#define ssl_V3_SUITES_IMPLEMENTED 57
+#define ssl_V3_SUITES_IMPLEMENTED 61
 #else
-#define ssl_V3_SUITES_IMPLEMENTED 35
+#define ssl_V3_SUITES_IMPLEMENTED 37
 #endif /* NSS_ENABLE_ECC */
 
 #define MAX_DTLS_SRTP_CIPHER_SUITES 4
@@ -440,20 +442,6 @@
 #define GS_DATA		3
 #define GS_PAD		4
 
-typedef SECStatus (*SSLCipher)(void *               context, 
-                               unsigned char *      out,
-			       int *                outlen, 
-			       int                  maxout, 
-			       const unsigned char *in,
-			       int                  inlen);
-typedef SECStatus (*SSLCompressor)(void *               context,
-                                   unsigned char *      out,
-                                   int *                outlen,
-                                   int                  maxout,
-                                   const unsigned char *in,
-                                   int                  inlen);
-typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
-
 #if defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_WIN32)
 typedef PCERT_KEY_CONTEXT PlatformKey;
 #elif defined(NSS_PLATFORM_CLIENT_AUTH) && defined(XP_MACOSX)
@@ -485,11 +473,12 @@
     cipher_camellia_128,
     cipher_camellia_256,
     cipher_seed,
+    cipher_aes_128_gcm,
     cipher_missing              /* reserved for no such supported cipher */
     /* This enum must match ssl3_cipherName[] in ssl3con.c.  */
 } SSL3BulkCipher;
 
-typedef enum { type_stream, type_block } CipherType;
+typedef enum { type_stream, type_block, type_aead } CipherType;
 
 #define MAX_IV_LENGTH 24
 
@@ -531,6 +520,30 @@
     PRUint64    cipher_context[MAX_CIPHER_CONTEXT_LLONGS];
 } ssl3KeyMaterial;
 
+typedef SECStatus (*SSLCipher)(void *               context, 
+                               unsigned char *      out,
+			       int *                outlen, 
+			       int                  maxout, 
+			       const unsigned char *in,
+			       int                  inlen);
+typedef SECStatus (*SSLAEADCipher)(
+			       ssl3KeyMaterial *    keys,
+			       PRBool               doDecrypt,
+			       unsigned char *      out,
+			       int *                outlen,
+			       int                  maxout,
+			       const unsigned char *in,
+			       int                  inlen,
+			       const unsigned char *additionalData,
+			       int                  additionalDataLen);
+typedef SECStatus (*SSLCompressor)(void *               context,
+                                   unsigned char *      out,
+                                   int *                outlen,
+                                   int                  maxout,
+                                   const unsigned char *in,
+                                   int                  inlen);
+typedef SECStatus (*SSLDestroy)(void *context, PRBool freeit);
+
 /* The DTLS anti-replay window. Defined here because we need it in
  * the cipher spec. Note that this is a ring buffer but left and
  * right represent the true window, with modular arithmetic used to
@@ -557,6 +570,7 @@
     int                mac_size;
     SSLCipher          encode;
     SSLCipher          decode;
+    SSLAEADCipher      aead;
     SSLDestroy         destroy;
     void *             encodeContext;
     void *             decodeContext;
@@ -706,8 +720,6 @@
     PRBool                   tls_keygen;
 } ssl3KEADef;
 
-typedef enum { kg_null, kg_strong, kg_export } SSL3KeyGenMode;
-
 /*
 ** There are tables of these, all const.
 */
@@ -719,7 +731,8 @@
     CipherType      type;
     int             iv_size;
     int             block_size;
-    SSL3KeyGenMode  keygen_mode;
+    int             tag_size;  /* authentication tag size for AEAD ciphers. */
+    int             explicit_nonce_size;               /* for AEAD ciphers. */
 };
 
 /*
diff --git a/net/third_party/nss/ssl/sslinfo.c b/net/third_party/nss/ssl/sslinfo.c
index d29fb0d..9597209 100644
--- a/net/third_party/nss/ssl/sslinfo.c
+++ b/net/third_party/nss/ssl/sslinfo.c
@@ -109,7 +109,7 @@
 #define K_ECDHE	"ECDHE", kt_ecdh
 
 #define C_SEED 	"SEED", calg_seed
-#define C_CAMELLIA	"CAMELLIA", calg_camellia
+#define C_CAMELLIA "CAMELLIA", calg_camellia
 #define C_AES	"AES", calg_aes
 #define C_RC4	"RC4", calg_rc4
 #define C_RC2	"RC2", calg_rc2
@@ -117,6 +117,7 @@
 #define C_3DES	"3DES", calg_3des
 #define C_NULL  "NULL", calg_null
 #define C_SJ 	"SKIPJACK", calg_sj
+#define C_AESGCM "AES-GCM", calg_aes_gcm
 
 #define B_256	256, 256, 256
 #define B_128	128, 128, 128
@@ -127,12 +128,16 @@
 #define B_40    128,  40,  40
 #define B_0  	  0,   0,   0
 
+#define M_AEAD_128 "AEAD", ssl_mac_aead, 128
 #define M_SHA256 "SHA256", ssl_hmac_sha256, 256
 #define M_SHA	"SHA1", ssl_mac_sha, 160
 #define M_MD5	"MD5",  ssl_mac_md5, 128
+#define M_NULL	"NULL", ssl_mac_null,  0
 
 static const SSLCipherSuiteInfo suiteInfo[] = {
 /* <------ Cipher suite --------------------> <auth> <KEA>  <bulk cipher> <MAC> <FIPS> */
+{0,CS(TLS_RSA_WITH_AES_128_GCM_SHA256),       S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
+
 {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
 {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0, },
 {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0, },
@@ -146,6 +151,7 @@
 {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, 0, 0, 0, },
 {0,CS(TLS_DHE_DSS_WITH_RC4_128_SHA),          S_DSA, K_DHE, C_RC4, B_128, M_SHA, 0, 0, 0, },
 {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_128, M_SHA256, 1, 0, 0, },
+{0,CS(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256),   S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
 {0,CS(TLS_DHE_RSA_WITH_AES_128_CBC_SHA),      S_RSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
 {0,CS(TLS_DHE_DSS_WITH_AES_128_CBC_SHA),      S_DSA, K_DHE, C_AES, B_128, M_SHA, 1, 0, 0, },
 {0,CS(TLS_RSA_WITH_SEED_CBC_SHA),             S_RSA, K_RSA, C_SEED,B_128, M_SHA, 1, 0, 0, },
@@ -175,6 +181,9 @@
 
 #ifdef NSS_ENABLE_ECC
 /* ECC cipher suites */
+{0,CS(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
+{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0, },
+
 {0,CS(TLS_ECDH_ECDSA_WITH_NULL_SHA),          S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, },
 {0,CS(TLS_ECDH_ECDSA_WITH_RC4_128_SHA),       S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, },
 {0,CS(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA),  S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0, },
diff --git a/net/third_party/nss/ssl/sslproto.h b/net/third_party/nss/ssl/sslproto.h
index b037887..53bba01 100644
--- a/net/third_party/nss/ssl/sslproto.h
+++ b/net/third_party/nss/ssl/sslproto.h
@@ -162,6 +162,10 @@
 
 #define TLS_RSA_WITH_SEED_CBC_SHA		0x0096
 
+#define TLS_RSA_WITH_AES_128_GCM_SHA256         0x009C
+#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256     0x009E
+#define TLS_DHE_DSS_WITH_AES_128_GCM_SHA256     0x00A2
+
 /* TLS "Signaling Cipher Suite Value" (SCSV). May be requested by client.
  * Must NEVER be chosen by server.  SSL 3.0 server acknowledges by sending
  * back an empty Renegotiation Info (RI) server hello extension.
@@ -204,6 +208,11 @@
 #define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
 #define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256   0xC027
 
+#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
+#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256  0xC02D
+#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   0xC02F
+#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256    0xC031
+
 /* Netscape "experimental" cipher suites. */
 #define SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA	0xffe0
 #define SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA	0xffe1
diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c
index db0da5f..c17c7a3 100644
--- a/net/third_party/nss/ssl/sslsock.c
+++ b/net/third_party/nss/ssl/sslsock.c
@@ -67,8 +67,10 @@
  {  TLS_DHE_DSS_WITH_AES_128_CBC_SHA, 	    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_DHE_RSA_WITH_AES_128_CBC_SHA,       SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ {  TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_RSA_WITH_AES_128_CBC_SHA,     	    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_RSA_WITH_AES_128_CBC_SHA256,        SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ {  TLS_RSA_WITH_AES_128_GCM_SHA256,        SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_DHE_DSS_WITH_AES_256_CBC_SHA, 	    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_DHE_RSA_WITH_AES_256_CBC_SHA,       SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
@@ -94,6 +96,7 @@
  {  TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,  SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,   SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ {  TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,   SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_ECDH_RSA_WITH_NULL_SHA,             SSL_ALLOWED,     SSL_ALLOWED },
  {  TLS_ECDH_RSA_WITH_RC4_128_SHA,          SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
@@ -105,6 +108,7 @@
  {  TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,     SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,  SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
+ {  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,  SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
  {  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,     SSL_NOT_ALLOWED, SSL_NOT_ALLOWED },
 #endif /* NSS_ENABLE_ECC */
  {  0,					    SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }
diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h
index 41d0113..b03422e 100644
--- a/net/third_party/nss/ssl/sslt.h
+++ b/net/third_party/nss/ssl/sslt.h
@@ -91,9 +91,10 @@
     ssl_calg_3des     = 4,
     ssl_calg_idea     = 5,
     ssl_calg_fortezza = 6,      /* deprecated, now unused */
-    ssl_calg_aes      = 7,      /* coming soon */
+    ssl_calg_aes      = 7,
     ssl_calg_camellia = 8,
-    ssl_calg_seed     = 9
+    ssl_calg_seed     = 9,
+    ssl_calg_aes_gcm  = 10
 } SSLCipherAlgorithm;
 
 typedef enum { 
@@ -102,7 +103,8 @@
     ssl_mac_sha       = 2, 
     ssl_hmac_md5      = 3, 	/* TLS HMAC version of mac_md5 */
     ssl_hmac_sha      = 4, 	/* TLS HMAC version of mac_sha */
-    ssl_hmac_sha256   = 5
+    ssl_hmac_sha256   = 5,
+    ssl_mac_aead      = 6
 } SSLMACAlgorithm;
 
 typedef enum {
@@ -158,6 +160,9 @@
     PRUint16             effectiveKeyBits;
 
     /* MAC info */
+    /* AEAD ciphers don't have a MAC. For an AEAD cipher, macAlgorithmName
+     * is "AEAD", macAlgorithm is ssl_mac_aead, and macBits is the length in
+     * bits of the authentication tag. */
     const char *         macAlgorithmName;
     SSLMACAlgorithm      macAlgorithm;
     PRUint16             macBits;
diff --git a/net/tools/flip_server/create_listener.cc b/net/tools/flip_server/create_listener.cc
index 4676912..21867a9 100644
--- a/net/tools/flip_server/create_listener.cc
+++ b/net/tools/flip_server/create_listener.cc
@@ -67,7 +67,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 // Sets an FD to be nonblocking.
-void SetNonBlocking(int fd) {
+void FlipSetNonBlocking(int fd) {
   DCHECK_GE(fd, 0);
 
   int fcntl_return = fcntl(fd, F_GETFL, 0);
@@ -270,7 +270,7 @@
     return -1;
   }
 
-  SetNonBlocking( sock );
+  FlipSetNonBlocking( sock );
 
   if (disable_nagle) {
     if (!SetDisableNagle(sock)) {
@@ -297,4 +297,3 @@
 }
 
 }  // namespace net
-
diff --git a/net/tools/flip_server/create_listener.h b/net/tools/flip_server/create_listener.h
index 4a4a6e1..a3f5a87 100644
--- a/net/tools/flip_server/create_listener.h
+++ b/net/tools/flip_server/create_listener.h
@@ -10,7 +10,7 @@
 
 namespace net {
 
-void SetNonBlocking(int fd);
+void FlipSetNonBlocking(int fd);
 
 // Summary:
 //   creates a socket for listening, and bind()s and listen()s it.
@@ -54,4 +54,3 @@
 }  // namespace net
 
 #endif  // NET_TOOLS_FLIP_SERVER_CREATE_LISTENER_H__
-
diff --git a/net/tools/flip_server/epoll_server.cc b/net/tools/flip_server/epoll_server.cc
index af09c14..0e09a6d 100644
--- a/net/tools/flip_server/epoll_server.cc
+++ b/net/tools/flip_server/epoll_server.cc
@@ -4,11 +4,10 @@
 
 #include "net/tools/flip_server/epoll_server.h"
 
+#include <unistd.h>  // For read, pipe, close and write.
 #include <stdlib.h>  // for abort
 #include <errno.h>    // for errno and strerror_r
 #include <algorithm>
-#include <ostream>
-#include <unistd.h>  // For read, pipe, close and write.
 #include <utility>
 #include <vector>
 
@@ -482,7 +481,7 @@
 }
 
 int EpollServer::NumFDsRegistered() const {
-  DCHECK(cb_map_.size() >= 1);
+  DCHECK_GE(cb_map_.size(), 1u);
   // Omit the internal FD (read_fd_)
   return cb_map_.size() - 1;
 }
@@ -490,7 +489,7 @@
 void EpollServer::Wake() {
   char data = 'd';  // 'd' is for data.  It's good enough for me.
   int rv = write(write_fd_, &data, 1);
-  DCHECK(rv == 1);
+  DCHECK_EQ(rv, 1);
 }
 
 int64 EpollServer::NowInUsec() const {
@@ -819,4 +818,3 @@
 }
 
 }  // namespace net
-
diff --git a/net/tools/flip_server/flip_config.cc b/net/tools/flip_server/flip_config.cc
index eb5c3ca..3de3028 100644
--- a/net/tools/flip_server/flip_config.cc
+++ b/net/tools/flip_server/flip_config.cc
@@ -72,7 +72,7 @@
     }
   }
 
-  SetNonBlocking(listen_fd_);
+  FlipSetNonBlocking(listen_fd_);
   VLOG(1) << "Listening on socket: ";
   if (flip_handler_type == FLIP_HANDLER_PROXY)
     VLOG(1) << "\tType         : Proxy";
diff --git a/net/tools/flip_server/flip_test_utils.cc b/net/tools/flip_server/flip_test_utils.cc
new file mode 100644
index 0000000..d9846cf
--- /dev/null
+++ b/net/tools/flip_server/flip_test_utils.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 "net/tools/flip_server/flip_test_utils.h"
+
+namespace net {
+
+MockSMInterface::MockSMInterface() {
+}
+
+MockSMInterface::~MockSMInterface() {
+}
+
+}  // namespace net
diff --git a/net/tools/flip_server/flip_test_utils.h b/net/tools/flip_server/flip_test_utils.h
new file mode 100644
index 0000000..8a10b95
--- /dev/null
+++ b/net/tools/flip_server/flip_test_utils.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 NET_TOOLS_FLIP_SERVER_FLIP_TEST_UTILS_H_
+#define NET_TOOLS_FLIP_SERVER_FLIP_TEST_UTILS_H_
+
+#include <string>
+
+#include "net/tools/flip_server/sm_interface.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class MockSMInterface : public SMInterface {
+ public:
+  MockSMInterface();
+  virtual ~MockSMInterface();
+
+  MOCK_METHOD2(InitSMInterface, void(SMInterface*, int32));
+  MOCK_METHOD8(InitSMConnection, void(SMConnectionPoolInterface*,
+                                      SMInterface*,
+                                      EpollServer*,
+                                      int,
+                                      std::string,
+                                      std::string,
+                                      std::string,
+                                      bool));
+  MOCK_METHOD2(ProcessReadInput, size_t(const char*, size_t));
+  MOCK_METHOD2(ProcessWriteInput, size_t(const char*, size_t));
+  MOCK_METHOD1(SetStreamID, void(uint32 stream_id));
+  MOCK_CONST_METHOD0(MessageFullyRead, bool());
+  MOCK_CONST_METHOD0(Error, bool());
+  MOCK_CONST_METHOD0(ErrorAsString, const char*());
+  MOCK_METHOD0(Reset, void());
+  MOCK_METHOD1(ResetForNewInterface, void(int32 server_idx));
+  MOCK_METHOD0(ResetForNewConnection, void());
+  MOCK_METHOD0(Cleanup, void());
+  MOCK_METHOD0(PostAcceptHook, int());
+  MOCK_METHOD3(NewStream, void(uint32, uint32, const std::string&));
+  MOCK_METHOD1(SendEOF, void(uint32 stream_id));
+  MOCK_METHOD1(SendErrorNotFound, void(uint32 stream_id));
+  MOCK_METHOD2(SendSynStream, size_t(uint32, const BalsaHeaders&));
+  MOCK_METHOD2(SendSynReply, size_t(uint32, const BalsaHeaders&));
+  MOCK_METHOD5(SendDataFrame, void(uint32, const char*, int64, uint32, bool));
+  MOCK_METHOD0(GetOutput, void());
+  MOCK_METHOD0(set_is_request, void());
+};
+
+}  // namespace net
+
+#endif  // NET_TOOLS_FLIP_SERVER_FLIP_TEST_UTILS_H_
diff --git a/net/tools/flip_server/http_interface.cc b/net/tools/flip_server/http_interface.cc
index 7a44c03..916ba51 100644
--- a/net/tools/flip_server/http_interface.cc
+++ b/net/tools/flip_server/http_interface.cc
@@ -14,11 +14,9 @@
 
 HttpSM::HttpSM(SMConnection* connection,
                SMInterface* sm_spdy_interface,
-               EpollServer* epoll_server,
                MemoryCache* memory_cache,
                FlipAcceptor* acceptor)
-    : seq_num_(0),
-      http_framer_(new BalsaFrame),
+    : http_framer_(new BalsaFrame),
       stream_id_(0),
       server_idx_(-1),
       connection_(connection),
@@ -37,7 +35,7 @@
   delete http_framer_;
 }
 
-void HttpSM::ProcessBodyData(const char *input, size_t size) {
+void HttpSM::ProcessBodyData(const char* input, size_t size) {
   if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
     VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process Body Data: stream "
             << stream_id_ << ": size " << size;
@@ -94,10 +92,6 @@
   output_ordering_.AddToOutputOrder(mci);
 }
 
-void HttpSM::SendOKResponse(uint32 stream_id, std::string* output) {
-  SendOKResponseImpl(stream_id, output);
-}
-
 void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface,
                              int32 server_idx) {
   sm_spdy_interface_ = sm_spdy_interface;
@@ -133,10 +127,10 @@
 size_t HttpSM::ProcessWriteInput(const char* data, size_t len) {
   VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process write input: size "
           << len << ": stream " << stream_id_;
-  char * dataPtr = new char[len];
+  char* dataPtr = new char[len];
   memcpy(dataPtr, data, len);
   DataFrame* data_frame = new DataFrame;
-  data_frame->data = (const char *)dataPtr;
+  data_frame->data = dataPtr;
   data_frame->size = len;
   data_frame->delete_when_done = true;
   connection_->EnqueueDataFrame(data_frame);
@@ -178,7 +172,6 @@
             << "Sending EOF to spdy.";
     sm_spdy_interface_->SendEOF(stream_id_);
   }
-  seq_num_ = 0;
   output_ordering_.Reset();
   http_framer_->Reset();
   if (sm_spdy_interface_) {
@@ -257,17 +250,6 @@
   output_ordering_.RemoveStreamId(stream_id);
 }
 
-void HttpSM::SendOKResponseImpl(uint32 stream_id, std::string* output) {
-  BalsaHeaders my_headers;
-  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
-  my_headers.RemoveAllOfHeader("content-length");
-  my_headers.AppendHeader("transfer-encoding", "chunked");
-  SendSynReplyImpl(stream_id, my_headers);
-  SendDataFrame(stream_id, output->c_str(), output->size(), 0, false);
-  SendEOFImpl(stream_id);
-  output_ordering_.RemoveStreamId(stream_id);
-}
-
 size_t HttpSM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) {
   SimpleBuffer sb;
   headers.WriteHeaderAndEndingToBuffer(&sb);
diff --git a/net/tools/flip_server/http_interface.h b/net/tools/flip_server/http_interface.h
index e311881..18e616d 100644
--- a/net/tools/flip_server/http_interface.h
+++ b/net/tools/flip_server/http_interface.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_
-#define NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_
+#ifndef NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_H_
+#define NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_H_
 
 #include <string>
 
@@ -27,7 +27,6 @@
  public:
   HttpSM(SMConnection* connection,
          SMInterface* sm_spdy_interface,
-         EpollServer* epoll_server,
          MemoryCache* memory_cache,
          FlipAcceptor* acceptor);
   virtual ~HttpSM();
@@ -69,9 +68,9 @@
 
  public:
   void AddToOutputOrder(const MemCacheIter& mci);
-  void SendOKResponse(uint32 stream_id, std::string* output);
   BalsaFrame* spdy_framer() { return http_framer_; }
   virtual void set_is_request() OVERRIDE {}
+  const OutputOrdering& output_ordering() const { return output_ordering_; }
 
   // SMInterface:
   virtual void InitSMInterface(SMInterface* sm_spdy_interface,
@@ -110,7 +109,7 @@
  private:
   void SendEOFImpl(uint32 stream_id);
   void SendErrorNotFoundImpl(uint32 stream_id);
-  void SendOKResponseImpl(uint32 stream_id, std::string* output);
+  void SendOKResponseImpl(uint32 stream_id, const std::string& output);
   size_t SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers);
   size_t SendSynStreamImpl(uint32 stream_id, const BalsaHeaders& headers);
   void SendDataFrameImpl(uint32 stream_id, const char* data, int64 len,
@@ -119,7 +118,6 @@
   virtual void GetOutput() OVERRIDE;
 
  private:
-  uint64 seq_num_;
   BalsaFrame* http_framer_;
   BalsaHeaders headers_;
   uint32 stream_id_;
@@ -133,7 +131,6 @@
   FlipAcceptor* acceptor_;
 };
 
-}  // namespace
+}  // namespace net
 
-#endif  // NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_
-
+#endif  // NET_TOOLS_FLIP_SERVER_HTTP_INTERFACE_H_
diff --git a/net/tools/flip_server/http_interface_test.cc b/net/tools/flip_server/http_interface_test.cc
new file mode 100644
index 0000000..ba9b3aa
--- /dev/null
+++ b/net/tools/flip_server/http_interface_test.cc
@@ -0,0 +1,487 @@
+// Copyright 2013 The Chromium Authors. 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/flip_server/http_interface.h"
+
+#include <list>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "net/tools/flip_server/balsa_enums.h"
+#include "net/tools/flip_server/balsa_frame.h"
+#include "net/tools/flip_server/balsa_headers.h"
+#include "net/tools/flip_server/flip_config.h"
+#include "net/tools/flip_server/flip_test_utils.h"
+#include "net/tools/flip_server/mem_cache.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+using ::base::StringPiece;
+using ::testing::_;
+using ::testing::InSequence;
+
+namespace {
+
+class MockSMConnection : public SMConnection {
+ public:
+  MockSMConnection(EpollServer* epoll_server,
+                   SSLState* ssl_state,
+                   MemoryCache* memory_cache,
+                   FlipAcceptor* acceptor,
+                   std::string log_prefix)
+      : SMConnection(epoll_server,
+                     ssl_state,
+                     memory_cache,
+                     acceptor,
+                     log_prefix) {}
+
+  MOCK_METHOD0(Cleanup, void());
+  MOCK_METHOD8(InitSMConnection, void(SMConnectionPoolInterface*,
+                                      SMInterface*,
+                                      EpollServer*,
+                                      int,
+                                      std::string,
+                                      std::string,
+                                      std::string,
+                                      bool));
+};
+
+class FlipHttpSMTest : public ::testing::Test {
+ public:
+  explicit FlipHttpSMTest(FlipHandlerType type = FLIP_HANDLER_PROXY) {
+    SSLState* ssl_state = NULL;
+    mock_another_interface_.reset(new MockSMInterface);
+    memory_cache_.reset(new MemoryCache);
+    acceptor_.reset(new FlipAcceptor(type,
+                                     "127.0.0.1",
+                                     "8941",
+                                     "ssl_cert_filename",
+                                     "ssl_key_filename",
+                                     "127.0.0.1",
+                                     "8942",
+                                     "127.0.0.1",
+                                     "8943",
+                                     1,
+                                     0,
+                                     true,
+                                     1,
+                                     false,
+                                     true,
+                                     NULL));
+    epoll_server_.reset(new EpollServer);
+    connection_.reset(new MockSMConnection(epoll_server_.get(),
+                                           ssl_state,
+                                           memory_cache_.get(),
+                                           acceptor_.get(),
+                                           "log_prefix"));
+
+    interface_.reset(new HttpSM(connection_.get(),
+                                mock_another_interface_.get(),
+                                memory_cache_.get(),
+                                acceptor_.get()));
+  }
+
+  virtual void TearDown() OVERRIDE {
+    if (acceptor_->listen_fd_ >= 0) {
+      epoll_server_->UnregisterFD(acceptor_->listen_fd_);
+      close(acceptor_->listen_fd_);
+      acceptor_->listen_fd_ = -1;
+    }
+    STLDeleteElements(connection_->output_list());
+  }
+
+  bool HasStream(uint32 stream_id) {
+    return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
+  }
+
+ protected:
+  scoped_ptr<MockSMInterface> mock_another_interface_;
+  scoped_ptr<MemoryCache> memory_cache_;
+  scoped_ptr<FlipAcceptor> acceptor_;
+  scoped_ptr<EpollServer> epoll_server_;
+  scoped_ptr<MockSMConnection> connection_;
+  scoped_ptr<HttpSM> interface_;
+};
+
+class FlipHttpSMProxyTest : public FlipHttpSMTest {
+ public:
+  FlipHttpSMProxyTest() : FlipHttpSMTest(FLIP_HANDLER_PROXY) {}
+  virtual ~FlipHttpSMProxyTest() {}
+};
+
+class FlipHttpSMHttpTest : public FlipHttpSMTest {
+ public:
+  FlipHttpSMHttpTest() : FlipHttpSMTest(FLIP_HANDLER_HTTP_SERVER) {}
+  virtual ~FlipHttpSMHttpTest() {}
+};
+
+class FlipHttpSMSpdyTest : public FlipHttpSMTest {
+ public:
+  FlipHttpSMSpdyTest() : FlipHttpSMTest(FLIP_HANDLER_SPDY_SERVER) {}
+  virtual ~FlipHttpSMSpdyTest() {}
+};
+
+TEST_F(FlipHttpSMTest, Construct) {
+  ASSERT_FALSE(interface_->spdy_framer()->is_request());
+}
+
+TEST_F(FlipHttpSMTest, AddToOutputOrder) {
+  uint32 stream_id = 13;
+  MemCacheIter mci;
+  mci.stream_id = stream_id;
+
+  {
+    BalsaHeaders headers;
+    std::string filename = "foobar";
+    memory_cache_->InsertFile(&headers, filename, "");
+    mci.file_data = memory_cache_->GetFileData(filename);
+  }
+
+  interface_->AddToOutputOrder(mci);
+  ASSERT_TRUE(HasStream(stream_id));
+}
+
+TEST_F(FlipHttpSMTest, InitSMInterface) {
+  scoped_ptr<MockSMInterface> mock(new MockSMInterface);
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendEOF(_));
+    EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
+    EXPECT_CALL(*mock, SendEOF(_));
+    EXPECT_CALL(*mock, ResetForNewInterface(_));
+  }
+
+  interface_->ResetForNewConnection();
+  interface_->InitSMInterface(mock.get(), 0);
+  interface_->ResetForNewConnection();
+}
+
+TEST_F(FlipHttpSMTest, InitSMConnection) {
+  EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
+
+  interface_->InitSMConnection(NULL, NULL, NULL, 0, "", "", "", false);
+}
+
+TEST_F(FlipHttpSMTest, ProcessReadInput) {
+  std::string data = "HTTP/1.1 200 OK\r\n"
+      "Content-Length: 14\r\n\r\n"
+      "hello, world\r\n";
+  testing::MockFunction<void(int)> checkpoint;
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _));
+    EXPECT_CALL(checkpoint, Call(0));
+    EXPECT_CALL(*mock_another_interface_, SendDataFrame(_, _, _, _, _));
+    EXPECT_CALL(*mock_another_interface_, SendEOF(_));
+  }
+
+  ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
+            interface_->spdy_framer()->ParseState());
+
+  size_t read = interface_->ProcessReadInput(data.data(), data.size());
+  ASSERT_EQ(39u, read);
+  checkpoint.Call(0);
+  read += interface_->ProcessReadInput(&data.data()[read], data.size() - read);
+  ASSERT_EQ(data.size(), read);
+  ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ,
+            interface_->spdy_framer()->ParseState());
+  ASSERT_TRUE(interface_->MessageFullyRead());
+}
+
+TEST_F(FlipHttpSMTest, ProcessWriteInput) {
+  std::string data = "hello, world";
+  interface_->ProcessWriteInput(data.data(), data.size());
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  ASSERT_EQ(data, StringPiece(df->data, df->size));
+  ASSERT_EQ(connection_->output_list()->end(), i);
+}
+
+TEST_F(FlipHttpSMTest, Reset) {
+  std::string data = "HTTP/1.1 200 OK\r\n\r\n";
+  testing::MockFunction<void(int)> checkpoint;
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _));
+    EXPECT_CALL(checkpoint, Call(0));
+  }
+
+  ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
+            interface_->spdy_framer()->ParseState());
+
+  interface_->ProcessReadInput(data.data(), data.size());
+  checkpoint.Call(0);
+  ASSERT_FALSE(interface_->MessageFullyRead());
+  ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE,
+            interface_->spdy_framer()->ParseState());
+
+  interface_->Reset();
+  ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
+            interface_->spdy_framer()->ParseState());
+}
+
+TEST_F(FlipHttpSMTest, ResetForNewConnection) {
+  std::string data = "HTTP/1.1 200 OK\r\n\r\n";
+  testing::MockFunction<void(int)> checkpoint;
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendSynReply(_, _));
+    EXPECT_CALL(checkpoint, Call(0));
+    EXPECT_CALL(*mock_another_interface_, SendEOF(_));
+    EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
+  }
+
+  ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
+            interface_->spdy_framer()->ParseState());
+
+  interface_->ProcessReadInput(data.data(), data.size());
+  checkpoint.Call(0);
+  ASSERT_FALSE(interface_->MessageFullyRead());
+  ASSERT_EQ(BalsaFrameEnums::READING_UNTIL_CLOSE,
+            interface_->spdy_framer()->ParseState());
+
+  interface_->ResetForNewConnection();
+  ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
+            interface_->spdy_framer()->ParseState());
+}
+
+TEST_F(FlipHttpSMTest, NewStream) {
+  uint32 stream_id = 4;
+  {
+    BalsaHeaders headers;
+    std::string filename = "foobar";
+    memory_cache_->InsertFile(&headers, filename, "");
+  }
+
+  interface_->NewStream(stream_id, 1, "foobar");
+  ASSERT_TRUE(HasStream(stream_id));
+}
+
+TEST_F(FlipHttpSMTest, NewStreamError) {
+  std::string syn_reply = "HTTP/1.1 404 Not Found\r\n"
+      "transfer-encoding: chunked\r\n\r\n";
+  std::string body = "e\r\npage not found\r\n";
+  uint32 stream_id = 4;
+
+  ASSERT_FALSE(HasStream(stream_id));
+  interface_->NewStream(stream_id, 1, "foobar");
+
+  ASSERT_EQ(3u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  ASSERT_EQ(syn_reply, StringPiece(df->data, df->size));
+  df = *i++;
+  ASSERT_EQ(body, StringPiece(df->data, df->size));
+  df = *i++;
+  ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
+  ASSERT_FALSE(HasStream(stream_id));
+}
+
+TEST_F(FlipHttpSMTest, SendErrorNotFound) {
+  std::string syn_reply = "HTTP/1.1 404 Not Found\r\n"
+      "transfer-encoding: chunked\r\n\r\n";
+  std::string body = "e\r\npage not found\r\n";
+  uint32 stream_id = 13;
+  MemCacheIter mci;
+  mci.stream_id = stream_id;
+
+  {
+    BalsaHeaders headers;
+    std::string filename = "foobar";
+    memory_cache_->InsertFile(&headers, filename, "");
+    mci.file_data = memory_cache_->GetFileData(filename);
+  }
+
+  interface_->AddToOutputOrder(mci);
+  ASSERT_TRUE(HasStream(stream_id));
+  interface_->SendErrorNotFound(stream_id);
+
+  ASSERT_EQ(3u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  ASSERT_EQ(syn_reply, StringPiece(df->data, df->size));
+  df = *i++;
+  ASSERT_EQ(body, StringPiece(df->data, df->size));
+  df = *i++;
+  ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
+  ASSERT_FALSE(HasStream(stream_id));
+}
+
+TEST_F(FlipHttpSMTest, SendSynStream) {
+  std::string expected = "GET / HTTP/1.0\r\n"
+      "key1: value1\r\n\r\n";
+  BalsaHeaders headers;
+  headers.SetResponseFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
+  headers.AppendHeader("key1", "value1");
+  interface_->SendSynStream(18, headers);
+
+  // TODO(yhirano): Is this behavior correct?
+  ASSERT_EQ(0u, connection_->output_list()->size());
+}
+
+TEST_F(FlipHttpSMTest, SendSynReply) {
+  std::string expected = "HTTP/1.1 200 OK\r\n"
+      "key1: value1\r\n\r\n";
+  BalsaHeaders headers;
+  headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
+  headers.AppendHeader("key1", "value1");
+  interface_->SendSynReply(18, headers);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  DataFrame* df = connection_->output_list()->front();
+  ASSERT_EQ(expected, StringPiece(df->data, df->size));
+}
+
+TEST_F(FlipHttpSMTest, SendDataFrame) {
+  std::string data = "foo bar baz";
+  interface_->SendDataFrame(12, data.data(), data.size(), 0, false);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  DataFrame* df = connection_->output_list()->front();
+  ASSERT_EQ("b\r\nfoo bar baz\r\n", StringPiece(df->data, df->size));
+}
+
+TEST_F(FlipHttpSMProxyTest, ProcessBodyData) {
+  BalsaVisitorInterface* visitor = interface_.get();
+  std::string data = "hello, world";
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_,
+                SendDataFrame(0, data.data(), data.size(), 0, false));
+  }
+  visitor->ProcessBodyData(data.data(), data.size());
+}
+
+// --
+// FlipHttpSMProxyTest
+
+TEST_F(FlipHttpSMProxyTest, ProcessHeaders) {
+  BalsaVisitorInterface* visitor = interface_.get();
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _));
+  }
+  BalsaHeaders headers;
+  visitor->ProcessHeaders(headers);
+}
+
+TEST_F(FlipHttpSMProxyTest, MessageDone) {
+  BalsaVisitorInterface* visitor = interface_.get();
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendEOF(0));
+  }
+  visitor->MessageDone();
+}
+
+TEST_F(FlipHttpSMProxyTest, Cleanup) {
+  EXPECT_CALL(*connection_, Cleanup()).Times(0);
+  interface_->Cleanup();
+}
+
+TEST_F(FlipHttpSMProxyTest, SendEOF) {
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_));
+  }
+  interface_->SendEOF(32);
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  DataFrame* df = connection_->output_list()->front();
+  ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
+}
+
+// --
+// FlipHttpSMHttpTest
+
+TEST_F(FlipHttpSMHttpTest, ProcessHeaders) {
+  BalsaVisitorInterface* visitor = interface_.get();
+  {
+    BalsaHeaders headers;
+    std::string filename = "GET_/path/file";
+    memory_cache_->InsertFile(&headers, filename, "");
+  }
+
+  BalsaHeaders headers;
+  headers.AppendHeader("Host", "example.com");
+  headers.SetRequestFirstlineFromStringPieces("GET",
+                                              "/path/file",
+                                              "HTTP/1.0");
+  uint32 stream_id = 133;
+  interface_->SetStreamID(stream_id);
+  ASSERT_FALSE(HasStream(stream_id));
+  visitor->ProcessHeaders(headers);
+  ASSERT_TRUE(HasStream(stream_id));
+}
+
+TEST_F(FlipHttpSMHttpTest, MessageDone) {
+  BalsaVisitorInterface* visitor = interface_.get();
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0);
+  }
+  visitor->MessageDone();
+}
+
+TEST_F(FlipHttpSMHttpTest, Cleanup) {
+  EXPECT_CALL(*connection_, Cleanup()).Times(0);
+  interface_->Cleanup();
+}
+
+TEST_F(FlipHttpSMHttpTest, SendEOF) {
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0);
+  }
+  interface_->SendEOF(32);
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  DataFrame* df = connection_->output_list()->front();
+  ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
+}
+
+// --
+// FlipHttpSMSpdyTest
+
+TEST_F(FlipHttpSMSpdyTest, ProcessHeaders) {
+  BalsaVisitorInterface* visitor = interface_.get();
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendSynReply(0, _));
+  }
+  BalsaHeaders headers;
+  visitor->ProcessHeaders(headers);
+}
+
+TEST_F(FlipHttpSMSpdyTest, MessageDone) {
+  BalsaVisitorInterface* visitor = interface_.get();
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, SendEOF(0)).Times(0);
+  }
+  visitor->MessageDone();
+}
+
+TEST_F(FlipHttpSMSpdyTest, Cleanup) {
+  EXPECT_CALL(*connection_, Cleanup()).Times(0);
+  interface_->Cleanup();
+}
+
+TEST_F(FlipHttpSMSpdyTest, SendEOF) {
+  {
+    InSequence s;
+    EXPECT_CALL(*mock_another_interface_, ResetForNewInterface(_)).Times(0);
+  }
+  interface_->SendEOF(32);
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  DataFrame* df = connection_->output_list()->front();
+  ASSERT_EQ("0\r\n\r\n", StringPiece(df->data, df->size));
+}
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/tools/flip_server/mem_cache.cc b/net/tools/flip_server/mem_cache.cc
index 9249208..d1e0e58 100644
--- a/net/tools/flip_server/mem_cache.cc
+++ b/net/tools/flip_server/mem_cache.cc
@@ -202,17 +202,9 @@
   if (slash_pos == std::string::npos) {
     slash_pos = filename_stripped.size();
   }
-  FileData* data =
-      new FileData(&visitor.headers,
-                   filename_stripped.substr(0, slash_pos),
-                   visitor.body);
-  Files::iterator it = files_.find(filename_stripped);
-  if (it != files_.end()) {
-    delete it->second;
-    it->second = data;
-  } else {
-    files_.insert(std::make_pair(filename_stripped, data));
-  }
+  InsertFile(&visitor.headers,
+             filename_stripped.substr(0, slash_pos),
+             visitor.body);
 }
 
 FileData* MemoryCache::GetFileData(const std::string& filename) {
@@ -239,6 +231,22 @@
   return true;
 }
 
+void MemoryCache::InsertFile(const BalsaHeaders* headers,
+                             const std::string& filename,
+                             const std::string& body) {
+  InsertFile(new FileData(headers, filename, body));
+}
+
+void MemoryCache::InsertFile(FileData* file_data) {
+  Files::iterator it = files_.find(file_data->filename());
+  if (it != files_.end()) {
+    delete it->second;
+    it->second = file_data;
+  } else {
+    files_.insert(std::make_pair(file_data->filename(), file_data));
+  }
+}
+
 void MemoryCache::ClearFiles() {
   for (Files::const_iterator i = files_.begin(); i != files_.end(); ++i) {
     delete i->second;
diff --git a/net/tools/flip_server/mem_cache.h b/net/tools/flip_server/mem_cache.h
index 806ae53..300c84a 100644
--- a/net/tools/flip_server/mem_cache.h
+++ b/net/tools/flip_server/mem_cache.h
@@ -135,7 +135,13 @@
 
   bool AssignFileData(const std::string& filename, MemCacheIter* mci);
 
+  // For unittests
+  void InsertFile(const BalsaHeaders* headers,
+                  const std::string& filename,
+                  const std::string& body);
+
  private:
+  void InsertFile(FileData* file_data);
   void ClearFiles();
 
   Files files_;
diff --git a/net/tools/flip_server/output_ordering.cc b/net/tools/flip_server/output_ordering.cc
index 22fd08a..6a42869 100644
--- a/net/tools/flip_server/output_ordering.cc
+++ b/net/tools/flip_server/output_ordering.cc
@@ -4,6 +4,8 @@
 
 #include "net/tools/flip_server/output_ordering.h"
 
+#include <utility>
+
 #include "net/tools/flip_server/flip_config.h"
 #include "net/tools/flip_server/sm_connection.h"
 
@@ -25,7 +27,9 @@
     epoll_server_ = connection->epoll_server();
 }
 
-OutputOrdering::~OutputOrdering() {}
+OutputOrdering::~OutputOrdering() {
+  Reset();
+}
 
 void OutputOrdering::Reset() {
   while (!stream_ids_.empty()) {
@@ -40,8 +44,8 @@
   first_data_senders_.clear();
 }
 
-bool OutputOrdering::ExistsInPriorityMaps(uint32 stream_id) {
-  StreamIdToPriorityMap::iterator sitpmi = stream_ids_.find(stream_id);
+bool OutputOrdering::ExistsInPriorityMaps(uint32 stream_id) const {
+  StreamIdToPriorityMap::const_iterator sitpmi = stream_ids_.find(stream_id);
   return sitpmi != stream_ids_.end();
 }
 
@@ -78,6 +82,7 @@
 
 void OutputOrdering::BeginOutputtingAlarm::OnUnregistration() {
   pmp_->alarm_enabled = false;
+  delete this;
 }
 
 void OutputOrdering::BeginOutputtingAlarm::OnShutdown(EpollServer* eps) {
diff --git a/net/tools/flip_server/output_ordering.h b/net/tools/flip_server/output_ordering.h
index 0558e3e..922d03f 100644
--- a/net/tools/flip_server/output_ordering.h
+++ b/net/tools/flip_server/output_ordering.h
@@ -45,7 +45,7 @@
   explicit OutputOrdering(SMConnectionInterface* connection);
   ~OutputOrdering();
   void Reset();
-  bool ExistsInPriorityMaps(uint32 stream_id);
+  bool ExistsInPriorityMaps(uint32 stream_id) const;
 
   struct BeginOutputtingAlarm : public EpollAlarmCallbackInterface {
    public:
diff --git a/net/tools/flip_server/sm_connection.cc b/net/tools/flip_server/sm_connection.cc
index 71e81a0..375bc2e 100644
--- a/net/tools/flip_server/sm_connection.cc
+++ b/net/tools/flip_server/sm_connection.cc
@@ -9,6 +9,7 @@
 #include <sys/socket.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <list>
 #include <string>
 
@@ -357,7 +358,6 @@
         if (!sm_http_interface_)
           sm_http_interface_ = new HttpSM(this,
                                           NULL,
-                                          epoll_server_,
                                           memory_cache_,
                                           acceptor_);
         sm_interface_ = sm_http_interface_;
diff --git a/net/tools/flip_server/sm_connection.h b/net/tools/flip_server/sm_connection.h
index e7f1e99..3e21772 100644
--- a/net/tools/flip_server/sm_connection.h
+++ b/net/tools/flip_server/sm_connection.h
@@ -65,14 +65,14 @@
   bool initialized() const { return initialized_; }
   std::string client_ip() const { return client_ip_; }
 
-  void InitSMConnection(SMConnectionPoolInterface* connection_pool,
-                        SMInterface* sm_interface,
-                        EpollServer* epoll_server,
-                        int fd,
-                        std::string server_ip,
-                        std::string server_port,
-                        std::string remote_ip,
-                        bool use_ssl);
+  virtual void InitSMConnection(SMConnectionPoolInterface* connection_pool,
+                                SMInterface* sm_interface,
+                                EpollServer* epoll_server,
+                                int fd,
+                                std::string server_ip,
+                                std::string server_port,
+                                std::string remote_ip,
+                                bool use_ssl);
 
   void CorkSocket();
   void UncorkSocket();
@@ -119,12 +119,12 @@
     return os;
   }
 
- private:
   SMConnection(EpollServer* epoll_server,
                SSLState* ssl_state,
                MemoryCache* memory_cache,
                FlipAcceptor* acceptor,
                std::string log_prefix);
+ private:
   int fd_;
   int events_;
 
diff --git a/net/tools/flip_server/spdy_interface.cc b/net/tools/flip_server/spdy_interface.cc
index b4e36be..359eab8 100644
--- a/net/tools/flip_server/spdy_interface.cc
+++ b/net/tools/flip_server/spdy_interface.cc
@@ -22,7 +22,7 @@
 
 class SpdyFrameDataFrame : public DataFrame {
  public:
-  SpdyFrameDataFrame(SpdyFrame* spdy_frame)
+  explicit SpdyFrameDataFrame(SpdyFrame* spdy_frame)
     : frame(spdy_frame) {
     data = spdy_frame->data();
     size = spdy_frame->size();
@@ -86,14 +86,14 @@
   VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: Creating new HTTP interface";
   SMInterface *sm_http_interface = new HttpSM(server_connection,
                                               this,
-                                              epoll_server_,
                                               memory_cache_,
                                               acceptor_);
   return sm_http_interface;
 }
 
 SMInterface* SpdySM::FindOrMakeNewSMConnectionInterface(
-    std::string server_ip, std::string server_port) {
+    const std::string& server_ip,
+    const std::string& server_port) {
   SMInterface *sm_http_interface;
   int32 server_idx;
   if (unused_server_interface_list.empty()) {
@@ -154,7 +154,7 @@
   // UrlUtilities::GetUrlPath will fail and always return a / breaking
   // the request. GetUrlPath assumes the absolute URL is being passed in.
   std::string uri;
-  if (url->second.compare(0,4,"http") == 0)
+  if (url->second.compare(0, 4, "http") == 0)
     uri = UrlUtilities::GetUrlPath(url->second);
   else
     uri = std::string(url->second);
@@ -323,6 +323,9 @@
   MemCacheIter mci;
   mci.stream_id = stream_id;
   mci.priority = priority;
+  // TODO(yhirano): The program will crash when
+  // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
+  // It should be fixed or an assertion should be placed.
   if (acceptor_->flip_handler_type_ == FLIP_HANDLER_SPDY_SERVER) {
     if (!memory_cache_->AssignFileData(filename, &mci)) {
       // error creating new stream.
@@ -348,10 +351,6 @@
   SendErrorNotFoundImpl(stream_id);
 }
 
-void SpdySM::SendOKResponse(uint32 stream_id, std::string* output) {
-  SendOKResponseImpl(stream_id, output);
-}
-
 size_t SpdySM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
   return SendSynStreamImpl(stream_id, headers);
 }
@@ -381,15 +380,6 @@
   client_output_ordering_.RemoveStreamId(stream_id);
 }
 
-void SpdySM::SendOKResponseImpl(uint32 stream_id, std::string* output) {
-  BalsaHeaders my_headers;
-  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
-  SendSynReplyImpl(stream_id, my_headers);
-  SendDataFrame(
-      stream_id, output->c_str(), output->size(), DATA_FLAG_FIN, false);
-  client_output_ordering_.RemoveStreamId(stream_id);
-}
-
 void SpdySM::KillStream(uint32 stream_id) {
   client_output_ordering_.RemoveStreamId(stream_id);
 }
@@ -426,15 +416,13 @@
                                  const BalsaHeaders& headers) {
   SpdyHeaderBlock block;
   block["method"] = headers.request_method().as_string();
-  if (!headers.HasHeader("status"))
-    block["status"] = headers.response_code().as_string();
   if (!headers.HasHeader("version"))
-    block["version"] =headers.response_version().as_string();
+    block["version"] =headers.request_version().as_string();
   if (headers.HasHeader("X-Original-Url")) {
     std::string original_url = headers.GetHeader("X-Original-Url").as_string();
-    block["path"] = UrlUtilities::GetUrlPath(original_url);
+    block["url"] = UrlUtilities::GetUrlPath(original_url);
   } else {
-    block["path"] = headers.request_uri().as_string();
+    block["url"] = headers.request_uri().as_string();
   }
   CopyHeaders(block, headers);
 
diff --git a/net/tools/flip_server/spdy_interface.h b/net/tools/flip_server/spdy_interface.h
index a83dab7..3ce1f3b 100644
--- a/net/tools/flip_server/spdy_interface.h
+++ b/net/tools/flip_server/spdy_interface.h
@@ -48,8 +48,10 @@
  private:
   virtual void set_is_request() OVERRIDE {}
   SMInterface* NewConnectionInterface();
-  SMInterface* FindOrMakeNewSMConnectionInterface(std::string server_ip,
-                                                  std::string server_port);
+  // virtual for tests
+  virtual SMInterface* FindOrMakeNewSMConnectionInterface(
+      const std::string& server_ip,
+      const std::string& server_port);
   int SpdyHandleNewStream(SpdyStreamId stream_id,
                           SpdyPriority priority,
                           const SpdyHeaderBlock& headers,
@@ -143,26 +145,26 @@
   void AddToOutputOrder(const MemCacheIter& mci);
   virtual void SendEOF(uint32 stream_id) OVERRIDE;
   virtual void SendErrorNotFound(uint32 stream_id) OVERRIDE;
-  void SendOKResponse(uint32 stream_id, std::string* output);
   virtual size_t SendSynStream(uint32 stream_id,
                                const BalsaHeaders& headers) OVERRIDE;
   virtual size_t SendSynReply(uint32 stream_id,
                               const BalsaHeaders& headers) OVERRIDE;
   virtual void SendDataFrame(uint32 stream_id, const char* data, int64 len,
                              uint32 flags, bool compress) OVERRIDE;
-  BufferedSpdyFramer* spdy_framer() {
-      return buffered_spdy_framer_;
+  BufferedSpdyFramer* spdy_framer() { return buffered_spdy_framer_; }
+
+  const OutputOrdering& output_ordering() const {
+    return client_output_ordering_;
   }
 
   static std::string forward_ip_header() { return forward_ip_header_; }
-  static void set_forward_ip_header(std::string value) {
+  static void set_forward_ip_header(const std::string& value) {
     forward_ip_header_ = value;
   }
 
  private:
   void SendEOFImpl(uint32 stream_id);
   void SendErrorNotFoundImpl(uint32 stream_id);
-  void SendOKResponseImpl(uint32 stream_id, std::string* output);
   void KillStream(uint32 stream_id);
   void CopyHeaders(SpdyHeaderBlock& dest, const BalsaHeaders& headers);
   size_t SendSynStreamImpl(uint32 stream_id, const BalsaHeaders& headers);
@@ -171,6 +173,7 @@
                          SpdyDataFlags flags, bool compress);
   void EnqueueDataFrame(DataFrame* df);
   virtual void GetOutput() OVERRIDE;
+
  private:
   BufferedSpdyFramer* buffered_spdy_framer_;
   bool valid_spdy_session_;  // True if we have seen valid data on this session.
diff --git a/net/tools/flip_server/spdy_interface_test.cc b/net/tools/flip_server/spdy_interface_test.cc
new file mode 100644
index 0000000..7a1c6e9
--- /dev/null
+++ b/net/tools/flip_server/spdy_interface_test.cc
@@ -0,0 +1,634 @@
+// Copyright 2013 The Chromium Authors. 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/flip_server/spdy_interface.h"
+
+#include <list>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "net/spdy/buffered_spdy_framer.h"
+#include "net/tools/flip_server/balsa_enums.h"
+#include "net/tools/flip_server/balsa_headers.h"
+#include "net/tools/flip_server/flip_config.h"
+#include "net/tools/flip_server/flip_test_utils.h"
+#include "net/tools/flip_server/mem_cache.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+using ::base::StringPiece;
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::InvokeWithoutArgs;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+namespace {
+
+struct StringSaver {
+ public:
+  StringSaver() : data(NULL), size(0) {}
+  void Save() {
+    string = std::string(data, size);
+  }
+
+  const char* data;
+  size_t size;
+  std::string string;
+};
+
+class SpdyFramerVisitor : public BufferedSpdyFramerVisitorInterface {
+ public:
+  virtual ~SpdyFramerVisitor() {}
+  MOCK_METHOD1(OnError, void(SpdyFramer::SpdyError));
+  MOCK_METHOD2(OnStreamError, void(SpdyStreamId, const std::string&));
+  MOCK_METHOD7(OnSynStream, void(SpdyStreamId,
+                                 SpdyStreamId,
+                                 SpdyPriority,
+                                 uint8,
+                                 bool,
+                                 bool,
+                                 const SpdyHeaderBlock&));
+  MOCK_METHOD3(OnSynStream, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
+  MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
+  MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
+  MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
+                                       const char*,
+                                       size_t,
+                                       bool));
+  MOCK_METHOD1(OnStreamFrameData, void(bool));
+  MOCK_METHOD1(OnSettings, void(bool));
+  MOCK_METHOD3(OnSetting, void(SpdySettingsIds, uint8, uint32));
+  MOCK_METHOD1(OnPing, void(uint32));
+  MOCK_METHOD2(OnRstStream, void(SpdyStreamId, SpdyRstStreamStatus));
+  MOCK_METHOD2(OnGoAway, void(SpdyStreamId, SpdyGoAwayStatus));
+  MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId, uint32));
+  MOCK_METHOD2(OnPushPromise, void(SpdyStreamId, SpdyStreamId));
+};
+
+class FakeSMConnection : public SMConnection {
+ public:
+  FakeSMConnection(EpollServer* epoll_server,
+                   SSLState* ssl_state,
+                   MemoryCache* memory_cache,
+                   FlipAcceptor* acceptor,
+                   std::string log_prefix)
+      : SMConnection(epoll_server,
+                     ssl_state,
+                     memory_cache,
+                     acceptor,
+                     log_prefix) {}
+
+  MOCK_METHOD0(Cleanup, void());
+  MOCK_METHOD8(InitSMConnection, void(SMConnectionPoolInterface*,
+                                      SMInterface*,
+                                      EpollServer*,
+                                      int,
+                                      std::string,
+                                      std::string,
+                                      std::string,
+                                      bool));
+};
+
+class SpdySMWithMockSMInterfaceFactory : public SpdySM {
+ public:
+  virtual ~SpdySMWithMockSMInterfaceFactory() {}
+  SpdySMWithMockSMInterfaceFactory(SMConnection* connection,
+                                   SMInterface* sm_http_interface,
+                                   EpollServer* epoll_server,
+                                   MemoryCache* memory_cache,
+                                   FlipAcceptor* acceptor)
+      : SpdySM(connection,
+               sm_http_interface,
+               epoll_server,
+               memory_cache,
+               acceptor) {}
+
+  MOCK_METHOD2(FindOrMakeNewSMConnectionInterface,
+               SMInterface*(const std::string&, const std::string&));
+};
+
+class FlipSpdySMTest : public ::testing::Test {
+ public:
+  FlipSpdySMTest(SpdyMajorVersion version = SPDY2,
+                 FlipHandlerType type = FLIP_HANDLER_PROXY)
+      : spdy_version_(version) {
+    SSLState* ssl_state = NULL;
+    mock_another_interface_.reset(new MockSMInterface);
+    memory_cache_.reset(new MemoryCache);
+    acceptor_.reset(new FlipAcceptor(type,
+                                     "127.0.0.1",
+                                     "8941",
+                                     "ssl_cert_filename",
+                                     "ssl_key_filename",
+                                     "127.0.0.1",
+                                     "8942",
+                                     "127.0.0.1",
+                                     "8943",
+                                     1,
+                                     0,
+                                     true,
+                                     1,
+                                     false,
+                                     true,
+                                     NULL));
+    epoll_server_.reset(new EpollServer);
+    connection_.reset(new FakeSMConnection(epoll_server_.get(),
+                                           ssl_state,
+                                           memory_cache_.get(),
+                                           acceptor_.get(),
+                                           "log_prefix"));
+
+    interface_.reset(new SpdySMWithMockSMInterfaceFactory(
+        connection_.get(),
+        mock_another_interface_.get(),
+        epoll_server_.get(),
+        memory_cache_.get(),
+        acceptor_.get()));
+
+    spdy_framer_.reset(new BufferedSpdyFramer(spdy_version_, true));
+    spdy_framer_visitor_.reset(new SpdyFramerVisitor);
+    spdy_framer_->set_visitor(spdy_framer_visitor_.get());
+  }
+
+  virtual void TearDown() OVERRIDE {
+    if (acceptor_->listen_fd_ >= 0) {
+      epoll_server_->UnregisterFD(acceptor_->listen_fd_);
+      close(acceptor_->listen_fd_);
+      acceptor_->listen_fd_ = -1;
+    }
+    OutputList& output_list = *connection_->output_list();
+    for (OutputList::const_iterator i = output_list.begin();
+         i != output_list.end();
+         ++i) {
+      delete *i;
+    }
+    output_list.clear();
+  }
+
+  bool HasStream(uint32 stream_id) {
+    return interface_->output_ordering().ExistsInPriorityMaps(stream_id);
+  }
+
+ protected:
+  SpdyMajorVersion spdy_version_;
+  scoped_ptr<MockSMInterface> mock_another_interface_;
+  scoped_ptr<MemoryCache> memory_cache_;
+  scoped_ptr<FlipAcceptor> acceptor_;
+  scoped_ptr<EpollServer> epoll_server_;
+  scoped_ptr<FakeSMConnection> connection_;
+  scoped_ptr<SpdySMWithMockSMInterfaceFactory> interface_;
+  scoped_ptr<BufferedSpdyFramer> spdy_framer_;
+  scoped_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
+};
+
+class FlipSpdy2SMTest : public FlipSpdySMTest {
+ public:
+  FlipSpdy2SMTest(): FlipSpdySMTest(SPDY2) {}
+  virtual ~FlipSpdy2SMTest() {}
+};
+
+class FlipSpdy2SMTestNonProxy : public FlipSpdySMTest {
+ public:
+  FlipSpdy2SMTestNonProxy(): FlipSpdySMTest(SPDY2, FLIP_HANDLER_SPDY_SERVER) {}
+  virtual ~FlipSpdy2SMTestNonProxy() {}
+};
+
+TEST_F(FlipSpdySMTest, InitSMConnection) {
+  {
+    InSequence s;
+    EXPECT_CALL(*connection_, InitSMConnection(_, _, _, _, _, _, _, _));
+  }
+  interface_->InitSMConnection(NULL,
+                               NULL,
+                               epoll_server_.get(),
+                               -1,
+                               "",
+                               "",
+                               "",
+                               false);
+}
+
+TEST_F(FlipSpdySMTest, OnSynStream) {
+  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
+  scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
+  uint32 stream_id = 92;
+  uint32 associated_id = 43;
+  std::string expected = "GET /path HTTP/1.0\r\n"
+      "method: GET\r\n"
+      "scheme: http\r\n"
+      "url: http://www.example.com/path\r\n"
+      "version: HTTP/1.0\r\n\r\n";
+  SpdyHeaderBlock block;
+  block["method"] = "GET";
+  block["url"] = "http://www.example.com/path";
+  block["scheme"] = "http";
+  block["version"] = "HTTP/1.0";
+  StringSaver saver;
+  {
+    InSequence s;
+    EXPECT_CALL(*interface_,
+                FindOrMakeNewSMConnectionInterface(_, _))
+        .WillOnce(Return(mock_interface.get()));
+    EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
+    EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
+        .WillOnce(DoAll(SaveArg<0>(&saver.data),
+                        SaveArg<1>(&saver.size),
+                        InvokeWithoutArgs(&saver, &StringSaver::Save),
+                        Return(0)));
+  }
+  visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+  ASSERT_EQ(expected, saver.string);
+}
+
+TEST_F(FlipSpdySMTest, OnStreamFrameData) {
+  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
+  scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
+  uint32 stream_id = 92;
+  uint32 associated_id = 43;
+  SpdyHeaderBlock block;
+  testing::MockFunction<void(int)> checkpoint;
+
+  scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12));
+  block["method"] = "GET";
+  block["url"] = "http://www.example.com/path";
+  block["scheme"] = "http";
+  block["version"] = "HTTP/1.0";
+  {
+    InSequence s;
+    EXPECT_CALL(*interface_,
+                FindOrMakeNewSMConnectionInterface(_, _))
+        .WillOnce(Return(mock_interface.get()));
+    EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
+    EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
+    EXPECT_CALL(checkpoint, Call(0));
+    EXPECT_CALL(*mock_interface,
+                ProcessWriteInput(frame->data(), frame->size())).Times(1);
+  }
+
+  visitor->OnSynStream(stream_id, associated_id, 0, 0, false, false, block);
+  checkpoint.Call(0);
+  visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
+}
+
+TEST_F(FlipSpdySMTest, OnRstStream) {
+  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
+  uint32 stream_id = 82;
+  MemCacheIter mci;
+  mci.stream_id = stream_id;
+
+  {
+    BalsaHeaders headers;
+    std::string filename = "foobar";
+    memory_cache_->InsertFile(&headers, filename, "");
+    mci.file_data = memory_cache_->GetFileData(filename);
+  }
+
+  interface_->AddToOutputOrder(mci);
+  ASSERT_TRUE(HasStream(stream_id));
+  visitor->OnRstStream(stream_id, RST_STREAM_INVALID);
+  ASSERT_FALSE(HasStream(stream_id));
+}
+
+TEST_F(FlipSpdySMTest, ProcessReadInput) {
+  ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
+  interface_->ProcessReadInput("", 1);
+  ASSERT_EQ(SpdyFramer::SPDY_READING_COMMON_HEADER,
+            interface_->spdy_framer()->state());
+}
+
+TEST_F(FlipSpdySMTest, ResetForNewConnection) {
+  uint32 stream_id = 13;
+  MemCacheIter mci;
+  mci.stream_id = stream_id;
+  // incomplete input
+  const char input[] = {'\0', '\0', '\0'};
+
+  {
+    BalsaHeaders headers;
+    std::string filename = "foobar";
+    memory_cache_->InsertFile(&headers, filename, "");
+    mci.file_data = memory_cache_->GetFileData(filename);
+  }
+
+  interface_->AddToOutputOrder(mci);
+  ASSERT_TRUE(HasStream(stream_id));
+  interface_->ProcessReadInput(input, sizeof(input));
+  ASSERT_NE(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
+
+  interface_->ResetForNewConnection();
+  ASSERT_FALSE(HasStream(stream_id));
+  ASSERT_EQ(SpdyFramer::SPDY_RESET, interface_->spdy_framer()->state());
+}
+
+TEST_F(FlipSpdySMTest, PostAcceptHook) {
+  interface_->PostAcceptHook();
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_, OnSettings(false));
+    EXPECT_CALL(*spdy_framer_visitor_, OnSetting(
+        SETTINGS_MAX_CONCURRENT_STREAMS, 0u, 100u));
+  }
+  spdy_framer_->ProcessInput(df->data, df->size);
+}
+
+TEST_F(FlipSpdySMTest, NewStream) {
+  // TODO(yhirano): SpdySM::NewStream leads to crash when
+  // acceptor_->flip_handler_type_ != FLIP_HANDLER_SPDY_SERVER.
+  // It should be fixed though I don't know the solution now.
+}
+
+TEST_F(FlipSpdySMTest, AddToOutputOrder) {
+  uint32 stream_id = 13;
+  MemCacheIter mci;
+  mci.stream_id = stream_id;
+
+  {
+    BalsaHeaders headers;
+    std::string filename = "foobar";
+    memory_cache_->InsertFile(&headers, filename, "");
+    mci.file_data = memory_cache_->GetFileData(filename);
+  }
+
+  interface_->AddToOutputOrder(mci);
+  ASSERT_TRUE(HasStream(stream_id));
+}
+
+TEST_F(FlipSpdySMTest, SendErrorNotFound) {
+  uint32 stream_id = 82;
+  SpdyHeaderBlock actual_header_block;
+  const char* actual_data;
+  size_t actual_size;
+  testing::MockFunction<void(int)> checkpoint;
+
+  interface_->SendErrorNotFound(stream_id);
+
+  ASSERT_EQ(2u, connection_->output_list()->size());
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnSynReply(stream_id, false, _))
+        .WillOnce(SaveArg<2>(&actual_header_block));
+    EXPECT_CALL(checkpoint, Call(0));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, _, _, false)).Times(1)
+        .WillOnce(DoAll(SaveArg<1>(&actual_data),
+                        SaveArg<2>(&actual_size)));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
+  }
+
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+  checkpoint.Call(0);
+  df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+
+  ASSERT_EQ(2, spdy_framer_->frames_received());
+  ASSERT_EQ(2u, actual_header_block.size());
+  ASSERT_EQ("404 Not Found", actual_header_block["status"]);
+  ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
+  ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
+}
+
+TEST_F(FlipSpdySMTest, SendSynStream) {
+  uint32 stream_id = 82;
+  BalsaHeaders headers;
+  SpdyHeaderBlock actual_header_block;
+  headers.AppendHeader("key1", "value1");
+  headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
+
+  interface_->SendSynStream(stream_id, headers);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnSynStream(stream_id, 0, _, _, false, false, _))
+        .WillOnce(SaveArg<6>(&actual_header_block));
+  }
+
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ(1, spdy_framer_->frames_received());
+  ASSERT_EQ(4u, actual_header_block.size());
+  ASSERT_EQ("GET", actual_header_block["method"]);
+  ASSERT_EQ("HTTP/1.0", actual_header_block["version"]);
+  ASSERT_EQ("/path", actual_header_block["url"]);
+  ASSERT_EQ("value1", actual_header_block["key1"]);
+}
+
+TEST_F(FlipSpdySMTest, SendSynReply) {
+  uint32 stream_id = 82;
+  BalsaHeaders headers;
+  SpdyHeaderBlock actual_header_block;
+  headers.AppendHeader("key1", "value1");
+  headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
+
+  interface_->SendSynReply(stream_id, headers);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
+        .WillOnce(SaveArg<2>(&actual_header_block));
+  }
+
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ(1, spdy_framer_->frames_received());
+  ASSERT_EQ(3u, actual_header_block.size());
+  ASSERT_EQ("200 OK", actual_header_block["status"]);
+  ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
+  ASSERT_EQ("value1", actual_header_block["key1"]);
+}
+
+TEST_F(FlipSpdySMTest, SendDataFrame) {
+  uint32 stream_id = 133;
+  SpdyDataFlags flags = DATA_FLAG_NONE;
+  const char* actual_data;
+  size_t actual_size;
+
+  interface_->SendDataFrame(stream_id, "hello", 5, flags, true);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, _, _, false))
+        .WillOnce(DoAll(SaveArg<1>(&actual_data),
+                        SaveArg<2>(&actual_size)));
+  }
+
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ(1, spdy_framer_->frames_received());
+  ASSERT_EQ("hello", StringPiece(actual_data, actual_size));
+}
+
+TEST_F(FlipSpdySMTest, SendLongDataFrame) {
+  uint32 stream_id = 133;
+  SpdyDataFlags flags = DATA_FLAG_NONE;
+  const char* actual_data;
+  size_t actual_size;
+
+  std::string data =
+      std::string(kSpdySegmentSize, 'a') +
+      std::string(kSpdySegmentSize, 'b') +
+      "c";
+  interface_->SendDataFrame(stream_id, data.data(), data.size(), flags, true);
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, _, _, false)).Times(3)
+        .WillRepeatedly(DoAll(SaveArg<1>(&actual_data),
+                        SaveArg<2>(&actual_size)));
+  }
+
+  ASSERT_EQ(3u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ(std::string(kSpdySegmentSize, 'a'),
+            StringPiece(actual_data, actual_size));
+
+  df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ(std::string(kSpdySegmentSize, 'b'),
+            StringPiece(actual_data, actual_size));
+
+  df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+  ASSERT_EQ("c", StringPiece(actual_data, actual_size));
+}
+
+TEST_F(FlipSpdy2SMTest, SendEOF) {
+  uint32 stream_id = 82;
+  // SPDY2 data frame
+  char empty_data_frame[] = {'\0', '\0', '\0', '\x52', '\x1', '\0', '\0', '\0'};
+  MemCacheIter mci;
+  mci.stream_id = stream_id;
+
+  {
+    BalsaHeaders headers;
+    std::string filename = "foobar";
+    memory_cache_->InsertFile(&headers, filename, "");
+    mci.file_data = memory_cache_->GetFileData(filename);
+  }
+
+  interface_->AddToOutputOrder(mci);
+  ASSERT_TRUE(HasStream(stream_id));
+  interface_->SendEOF(stream_id);
+  ASSERT_FALSE(HasStream(stream_id));
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  ASSERT_EQ(StringPiece(empty_data_frame, sizeof(empty_data_frame)),
+            StringPiece(df->data, df->size));
+}
+
+TEST_F(FlipSpdy2SMTest, SendEmptyDataFrame) {
+  uint32 stream_id = 133;
+  SpdyDataFlags flags = DATA_FLAG_NONE;
+  // SPDY2 data frame
+  char expected[] = {'\0', '\0', '\0', '\x85', '\0', '\0', '\0', '\0'};
+
+  interface_->SendDataFrame(stream_id, "hello", 0, flags, true);
+
+  ASSERT_EQ(1u, connection_->output_list()->size());
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+
+  ASSERT_EQ(StringPiece(expected, sizeof(expected)),
+            StringPiece(df->data, df->size));
+}
+
+TEST_F(FlipSpdy2SMTestNonProxy, OnSynStream) {
+  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
+  uint32 stream_id = 82;
+  SpdyHeaderBlock spdy_headers;
+  spdy_headers["url"] = "http://www.example.com/path";
+  spdy_headers["method"] = "GET";
+  spdy_headers["scheme"] = "http";
+
+  {
+    BalsaHeaders headers;
+    memory_cache_->InsertFile(&headers, "GET_/path", "");
+  }
+  visitor->OnSynStream(stream_id, 0, 0, 0, true, true, spdy_headers);
+  ASSERT_TRUE(HasStream(stream_id));
+}
+
+TEST_F(FlipSpdy2SMTestNonProxy, NewStream) {
+  uint32 stream_id = 13;
+  std::string filename = "foobar";
+
+  {
+    BalsaHeaders headers;
+    memory_cache_->InsertFile(&headers, filename, "");
+  }
+
+  interface_->NewStream(stream_id, 0, filename);
+  ASSERT_TRUE(HasStream(stream_id));
+}
+
+TEST_F(FlipSpdy2SMTestNonProxy, NewStreamError) {
+  uint32 stream_id = 82;
+  SpdyHeaderBlock actual_header_block;
+  const char* actual_data;
+  size_t actual_size;
+  testing::MockFunction<void(int)> checkpoint;
+
+  interface_->NewStream(stream_id, 0, "nonexistingfile");
+
+  ASSERT_EQ(2u, connection_->output_list()->size());
+
+  {
+    InSequence s;
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnSynReply(stream_id, false, _))
+        .WillOnce(SaveArg<2>(&actual_header_block));
+    EXPECT_CALL(checkpoint, Call(0));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, _, _, false)).Times(1)
+        .WillOnce(DoAll(SaveArg<1>(&actual_data),
+                        SaveArg<2>(&actual_size)));
+    EXPECT_CALL(*spdy_framer_visitor_,
+                OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
+  }
+
+  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
+  DataFrame* df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+  checkpoint.Call(0);
+  df = *i++;
+  spdy_framer_->ProcessInput(df->data, df->size);
+
+  ASSERT_EQ(2, spdy_framer_->frames_received());
+  ASSERT_EQ(2u, actual_header_block.size());
+  ASSERT_EQ("404 Not Found", actual_header_block["status"]);
+  ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
+  ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
+}
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/tools/gdig/gdig.cc b/net/tools/gdig/gdig.cc
index 0dec8d7..2764ee5 100644
--- a/net/tools/gdig/gdig.cc
+++ b/net/tools/gdig/gdig.cc
@@ -460,7 +460,11 @@
     ++active_resolves_;
     ++replay_log_index_;
     int ret = resolver_->Resolve(
-        info, addrlist, callback, NULL,
+        info,
+        DEFAULT_PRIORITY,
+        addrlist,
+        callback,
+        NULL,
         BoundNetLog::Make(log_.get(), net::NetLog::SOURCE_NONE));
     if (ret != ERR_IO_PENDING)
       callback.Run(ret);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 3903df9..facf72a 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -441,6 +441,39 @@
   EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
 }
 
+TEST_P(EndToEndTest, LargePostZeroRTTFailure) {
+  // Send a request and then disconnect. This prepares the client to attempt
+  // a 0-RTT handshake for the next request.
+  ASSERT_TRUE(Initialize());
+
+  string body;
+  GenerateBody(&body, 20480);
+
+  HTTPMessage request(HttpConstants::HTTP_1_1,
+                      HttpConstants::POST, "/foo");
+  request.AddBody(body, true);
+
+  EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+
+  client_->Disconnect();
+
+  // The 0-RTT handshake should succeed.
+  // TODO(wtc): figure out why this 0-RTT handshake takes 1 RTT.
+  client_->Connect();
+  ASSERT_TRUE(client_->client()->connected());
+  EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+
+  client_->Disconnect();
+
+  // Restart the server so that the 0-RTT handshake will take 1 RTT.
+  StopServer();
+  StartServer();
+
+  client_->Connect();
+  ASSERT_TRUE(client_->client()->connected());
+  EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
+}
+
 // TODO(ianswett): Enable once b/9295090 is fixed.
 TEST_P(EndToEndTest, DISABLED_LargePostFEC) {
   // FLAGS_fake_packet_loss_percentage = 30;
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index ca20a8d..5e89601 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -102,8 +102,6 @@
 
   bool connected() const;
 
-  int packets_dropped() { return packets_dropped_; }
-
   void set_bind_to_address(IPAddressNumber address) {
     bind_to_address_ = address;
   }
@@ -112,8 +110,6 @@
 
   void set_local_port(int local_port) { local_port_ = local_port; }
 
-  int local_port() { return local_port_; }
-
   const IPEndPoint& server_address() const { return server_address_; }
 
   const IPEndPoint& client_address() const { return client_address_; }
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 68691f7..5253764 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -59,7 +59,7 @@
                                 QuicBlockedWriterInterface* writer,
                                 int* error) {
   if (write_blocked_) {
-    write_blocked_list_.AddBlockedObject(writer);
+    write_blocked_list_.insert(make_pair(writer, true));
     *error = EAGAIN;
     return -1;
   }
@@ -68,7 +68,7 @@
                                         self_address, peer_address,
                                         error);
   if (rc == -1 && (*error == EWOULDBLOCK || *error == EAGAIN)) {
-    write_blocked_list_.AddBlockedObject(writer);
+    write_blocked_list_.insert(make_pair(writer, true));
     write_blocked_ = true;
   }
   return rc;
@@ -114,7 +114,7 @@
 
 void QuicDispatcher::CleanUpSession(SessionMap::iterator it) {
   QuicSession* session = it->second;
-  write_blocked_list_.RemoveBlockedObject(session->connection());
+  write_blocked_list_.erase(session->connection());
   time_wait_list_manager_->AddGuidToTimeWait(it->first,
                                              session->connection()->version());
   session_map_.erase(it);
@@ -129,13 +129,13 @@
   write_blocked_ = false;
 
   // Give each writer one attempt to write.
-  int num_writers = write_blocked_list_.NumObjects();
+  int num_writers = write_blocked_list_.size();
   for (int i = 0; i < num_writers; ++i) {
-    if (write_blocked_list_.IsEmpty()) {
+    if (write_blocked_list_.empty()) {
       break;
     }
-    QuicBlockedWriterInterface* writer =
-        write_blocked_list_.GetNextBlockedObject();
+    QuicBlockedWriterInterface* writer = write_blocked_list_.begin()->first;
+    write_blocked_list_.erase(write_blocked_list_.begin());
     bool can_write_more = writer->OnCanWrite();
     if (write_blocked_) {
       // We were unable to write.  Wait for the next EPOLLOUT.
@@ -146,12 +146,12 @@
     // The socket is not blocked but the writer has ceded work.  Add it to the
     // end of the list.
     if (can_write_more) {
-      write_blocked_list_.AddBlockedObject(writer);
+      write_blocked_list_.insert(make_pair(writer, true));
     }
   }
 
   // We're not write blocked.  Return true if there's more work to do.
-  return !write_blocked_list_.IsEmpty();
+  return !write_blocked_list_.empty();
 }
 
 void QuicDispatcher::Shutdown() {
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index bbf8d9b..aea76cb 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -12,7 +12,7 @@
 
 #include "base/containers/hash_tables.h"
 #include "net/base/ip_endpoint.h"
-#include "net/quic/blocked_list.h"
+#include "net/base/linked_hash_map.h"
 #include "net/quic/quic_blocked_writer_interface.h"
 #include "net/quic/quic_protocol.h"
 #include "net/tools/flip_server/epoll_server.h"
@@ -48,7 +48,8 @@
 class DeleteSessionsAlarm;
 class QuicDispatcher : public QuicPacketWriter, public QuicSessionOwner {
  public:
-  typedef BlockedList<QuicBlockedWriterInterface*> WriteBlockedList;
+  // 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.
@@ -82,7 +83,6 @@
   // Ensure that the closed connection is cleaned up asynchronously.
   virtual void OnConnectionClose(QuicGuid guid, QuicErrorCode error) OVERRIDE;
 
-  int fd() { return fd_; }
   void set_fd(int fd) { fd_ = fd; }
 
   typedef base::hash_map<QuicGuid, QuicSession*> SessionMap;
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index 059d833..2e2c309 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -22,6 +22,7 @@
 using net::EpollServer;
 using net::test::MockSession;
 using net::tools::test::MockConnection;
+using std::make_pair;
 using testing::_;
 using testing::DoAll;
 using testing::Invoke;
@@ -237,7 +238,7 @@
   ProcessPacket(addr, guid, "foo");
 }
 
-class WriteBlockedListTest : public QuicDispatcherTest {
+class QuicWriteBlockedListTest : public QuicDispatcherTest {
  public:
   virtual void SetUp() {
     IPEndPoint addr(Loopback4(), 1);
@@ -270,12 +271,12 @@
   QuicDispatcher::WriteBlockedList* blocked_list_;
 };
 
-TEST_F(WriteBlockedListTest, BasicOnCanWrite) {
+TEST_F(QuicWriteBlockedListTest, BasicOnCanWrite) {
   // No OnCanWrite calls because no connections are blocked.
   dispatcher_.OnCanWrite();
 
   // Register connection 1 for events, and make sure it's nofitied.
-  blocked_list_->AddBlockedObject(connection1());
+  blocked_list_->insert(make_pair(connection1(), true));
   EXPECT_CALL(*connection1(), OnCanWrite());
   dispatcher_.OnCanWrite();
 
@@ -284,67 +285,67 @@
   EXPECT_FALSE(dispatcher_.OnCanWrite());
 }
 
-TEST_F(WriteBlockedListTest, OnCanWriteOrder) {
+TEST_F(QuicWriteBlockedListTest, OnCanWriteOrder) {
   // Make sure we handle events in order.
   InSequence s;
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection2());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->insert(make_pair(connection2(), true));
   EXPECT_CALL(*connection1(), OnCanWrite());
   EXPECT_CALL(*connection2(), OnCanWrite());
   dispatcher_.OnCanWrite();
 
   // Check the other ordering.
-  blocked_list_->AddBlockedObject(connection2());
-  blocked_list_->AddBlockedObject(connection1());
+  blocked_list_->insert(make_pair(connection2(), true));
+  blocked_list_->insert(make_pair(connection1(), true));
   EXPECT_CALL(*connection2(), OnCanWrite());
   EXPECT_CALL(*connection1(), OnCanWrite());
   dispatcher_.OnCanWrite();
 }
 
-TEST_F(WriteBlockedListTest, OnCanWriteRemove) {
+TEST_F(QuicWriteBlockedListTest, OnCanWriteRemove) {
   // Add and remove one connction.
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->RemoveBlockedObject(connection1());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->erase(connection1());
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
   dispatcher_.OnCanWrite();
 
   // Add and remove one connction and make sure it doesn't affect others.
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection2());
-  blocked_list_->RemoveBlockedObject(connection1());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->insert(make_pair(connection2(), true));
+  blocked_list_->erase(connection1());
   EXPECT_CALL(*connection2(), OnCanWrite());
   dispatcher_.OnCanWrite();
 
   // Add it, remove it, and add it back and make sure things are OK.
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->RemoveBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection1());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->erase(connection1());
+  blocked_list_->insert(make_pair(connection1(), true));
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
   dispatcher_.OnCanWrite();
 }
 
-TEST_F(WriteBlockedListTest, DoubleAdd) {
+TEST_F(QuicWriteBlockedListTest, DoubleAdd) {
   // Make sure a double add does not necessitate a double remove.
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->RemoveBlockedObject(connection1());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->erase(connection1());
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
   dispatcher_.OnCanWrite();
 
   // Make sure a double add does not result in two OnCanWrite calls.
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection1());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->insert(make_pair(connection1(), true));
   EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
   dispatcher_.OnCanWrite();
 }
 
-TEST_F(WriteBlockedListTest, OnCanWriteHandleBlock) {
+TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) {
   // Finally make sure if we write block on a write call, we stop calling.
   InSequence s;
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection2());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->insert(make_pair(connection2(), true));
   EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
-      Invoke(this, &WriteBlockedListTest::SetBlocked));
+      Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
   EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
   dispatcher_.OnCanWrite();
 
@@ -353,12 +354,12 @@
   dispatcher_.OnCanWrite();
 }
 
-TEST_F(WriteBlockedListTest, LimitedWrites) {
+TEST_F(QuicWriteBlockedListTest, LimitedWrites) {
   // Make sure we call both writers.  The first will register for more writing
   // but should not be immediately called due to limits.
   InSequence s;
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection2());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->insert(make_pair(connection2(), true));
   EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(Return(true));
   EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(Return(false));
   dispatcher_.OnCanWrite();
@@ -368,13 +369,13 @@
   dispatcher_.OnCanWrite();
 }
 
-TEST_F(WriteBlockedListTest, TestWriteLimits) {
+TEST_F(QuicWriteBlockedListTest, TestWriteLimits) {
   // Finally make sure if we write block on a write call, we stop calling.
   InSequence s;
-  blocked_list_->AddBlockedObject(connection1());
-  blocked_list_->AddBlockedObject(connection2());
+  blocked_list_->insert(make_pair(connection1(), true));
+  blocked_list_->insert(make_pair(connection2(), true));
   EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
-      Invoke(this, &WriteBlockedListTest::SetBlocked));
+      Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
   EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
   dispatcher_.OnCanWrite();
 
diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc
index 0bfaee2..6d6ea13 100644
--- a/net/tools/quic/quic_epoll_connection_helper_test.cc
+++ b/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -15,7 +15,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using net::test::GetMinStreamFrameSize;
 using net::test::FramerVisitorCapturingFrames;
 using net::test::MockSendAlgorithm;
 using net::test::QuicConnectionPeer;
@@ -88,6 +87,10 @@
     epoll_server_.set_timeout_in_us(-1);
     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)));
   }
 
   QuicPacket* ConstructDataPacket(QuicPacketSequenceNumber number,
@@ -127,9 +130,11 @@
 
   const char buffer[] = "foo";
   const size_t packet_size =
-      GetPacketHeaderSize(PACKET_8BYTE_GUID, kIncludeVersion,
-                          PACKET_6BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP) +
-      GetMinStreamFrameSize(framer_.version()) + arraysize(buffer) - 1;
+      QuicPacketCreator::StreamFramePacketOverhead(
+          framer_.version(), PACKET_8BYTE_GUID, kIncludeVersion,
+          PACKET_1BYTE_SEQUENCE_NUMBER, NOT_IN_FEC_GROUP) +
+      arraysize(buffer) - 1;
+
   EXPECT_CALL(*send_algorithm_,
               SentPacket(_, 1, packet_size, NOT_RETRANSMISSION));
   EXPECT_CALL(*send_algorithm_, AbandoningPacket(1, packet_size));
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index d18525f..9eae4ab 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -36,6 +36,7 @@
 
 QuicServer::QuicServer()
     : port_(0),
+      fd_(-1),
       packets_dropped_(0),
       overflow_supported_(false),
       use_recvmmsg_(false),
@@ -47,6 +48,7 @@
 
 QuicServer::QuicServer(const QuicConfig& config)
     : port_(0),
+      fd_(-1),
       packets_dropped_(0),
       overflow_supported_(false),
       use_recvmmsg_(false),
@@ -154,6 +156,9 @@
   // Before we shut down the epoll server, give all active sessions a chance to
   // notify clients that they're closing.
   dispatcher_->Shutdown();
+
+  close(fd_);
+  fd_ = -1;
 }
 
 void QuicServer::OnEvent(int fd, EpollEvent* event) {
diff --git a/net/tools/quic/test_tools/http_message_test_utils.cc b/net/tools/quic/test_tools/http_message_test_utils.cc
index 7d6df7a..70eb592 100644
--- a/net/tools/quic/test_tools/http_message_test_utils.cc
+++ b/net/tools/quic/test_tools/http_message_test_utils.cc
@@ -54,7 +54,6 @@
 // - Neither Transfer-Encoding nor Content-Length is present and message
 //   is tagged as complete.
 bool IsCompleteMessage(const HTTPMessage& message) {
-  return true;
   const BalsaHeaders* headers = message.headers();
   StringPiece content_length = headers->GetHeader(kContentLength);
   if (!content_length.empty()) {
diff --git a/net/tools/quic/test_tools/quic_client_peer.cc b/net/tools/quic/test_tools/quic_client_peer.cc
index 8583594..25fdb7e 100644
--- a/net/tools/quic/test_tools/quic_client_peer.cc
+++ b/net/tools/quic/test_tools/quic_client_peer.cc
@@ -11,13 +11,6 @@
 namespace test {
 
 // static
-void QuicClientPeer::Reinitialize(QuicClient* client) {
-  client->initialized_ = false;
-  client->epoll_server_.UnregisterFD(client->fd_);
-  client->Initialize();
-}
-
-// static
 int QuicClientPeer::GetFd(QuicClient* client) {
   return client->fd_;
 }
diff --git a/net/tools/quic/test_tools/quic_client_peer.h b/net/tools/quic/test_tools/quic_client_peer.h
index 8eaa17e..016120a 100644
--- a/net/tools/quic/test_tools/quic_client_peer.h
+++ b/net/tools/quic/test_tools/quic_client_peer.h
@@ -14,7 +14,6 @@
 
 class QuicClientPeer {
  public:
-  static void Reinitialize(QuicClient* client);
   static int GetFd(QuicClient* client);
 };
 
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index 31ea181..d18556b 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -22,8 +22,6 @@
 namespace tools {
 namespace test {
 
-std::string SerializeUncompressedHeaders(const SpdyHeaderBlock& headers);
-
 class MockConnection : public QuicConnection {
  public:
   // Uses a QuicConnectionHelper created with fd and eps.
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 77a3142..d99c5ff 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -21,6 +21,7 @@
 import logging
 import minica
 import os
+import json
 import random
 import re
 import select
@@ -282,7 +283,8 @@
     post_handlers = [
       self.EchoTitleHandler,
       self.EchoHandler,
-      self.PostOnlyFileHandler] + get_handlers
+      self.PostOnlyFileHandler,
+      self.EchoMultipartPostHandler] + get_handlers
     put_handlers = [
       self.EchoTitleHandler,
       self.EchoHandler] + get_handlers
@@ -662,6 +664,37 @@
     self.wfile.write('</body></html>')
     return True
 
+  def EchoMultipartPostHandler(self):
+    """This handler echoes received multipart post data as json format."""
+
+    if not (self._ShouldHandleRequest("/echomultipartpost") or
+            self._ShouldHandleRequest("/searchbyimage")):
+      return False
+
+    content_type, parameters = cgi.parse_header(
+        self.headers.getheader('content-type'))
+    if content_type == 'multipart/form-data':
+      post_multipart = cgi.parse_multipart(self.rfile, parameters)
+    elif content_type == 'application/x-www-form-urlencoded':
+      raise Exception('POST by application/x-www-form-urlencoded is '
+                      'not implemented.')
+    else:
+      post_multipart = {}
+
+    # Since the data can be binary, we encode them by base64.
+    post_multipart_base64_encoded = {}
+    for field, values in post_multipart.items():
+      post_multipart_base64_encoded[field] = [base64.b64encode(value)
+                                              for value in values]
+
+    result = {'POST_multipart' : post_multipart_base64_encoded}
+
+    self.send_response(200)
+    self.send_header("Content-type", "text/plain")
+    self.end_headers()
+    self.wfile.write(json.dumps(result, indent=2, sort_keys=False))
+    return True
+
   def DownloadHandler(self):
     """This handler sends a downloadable file with or without reporting
     the size (6K)."""
diff --git a/net/tools/tld_cleanup/tld_cleanup.cc b/net/tools/tld_cleanup/tld_cleanup.cc
index 9d5337c..a4b127b 100644
--- a/net/tools/tld_cleanup/tld_cleanup.cc
+++ b/net/tools/tld_cleanup/tld_cleanup.cc
@@ -64,7 +64,7 @@
   settings.delete_old = logging::DELETE_OLD_LOG_FILE;
   logging::InitLogging(settings);
 
-  icu_util::Initialize();
+  base::i18n::InitializeICU();
 
   base::FilePath input_file;
   PathService::Get(base::DIR_SOURCE_ROOT, &input_file);
diff --git a/net/url_request/data_protocol_handler.cc b/net/url_request/data_protocol_handler.cc
index 3222f72..c6d9716 100644
--- a/net/url_request/data_protocol_handler.cc
+++ b/net/url_request/data_protocol_handler.cc
@@ -16,4 +16,8 @@
   return new URLRequestDataJob(request, network_delegate);
 }
 
+bool DataProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {
+  return false;
+}
+
 }  // namespace net
diff --git a/net/url_request/data_protocol_handler.h b/net/url_request/data_protocol_handler.h
index abb5abe..b7f7fef 100644
--- a/net/url_request/data_protocol_handler.h
+++ b/net/url_request/data_protocol_handler.h
@@ -20,6 +20,7 @@
   DataProtocolHandler();
   virtual URLRequestJob* MaybeCreateJob(
       URLRequest* request, NetworkDelegate* network_delegate) const OVERRIDE;
+  virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DataProtocolHandler);
diff --git a/net/url_request/file_protocol_handler.cc b/net/url_request/file_protocol_handler.cc
index dc5b16f..ef8096f 100644
--- a/net/url_request/file_protocol_handler.cc
+++ b/net/url_request/file_protocol_handler.cc
@@ -5,6 +5,7 @@
 #include "net/url_request/file_protocol_handler.h"
 
 #include "base/logging.h"
+#include "base/task_runner.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_request.h"
@@ -14,7 +15,11 @@
 
 namespace net {
 
-FileProtocolHandler::FileProtocolHandler() { }
+FileProtocolHandler::FileProtocolHandler(
+    const scoped_refptr<base::TaskRunner>& file_task_runner)
+    : file_task_runner_(file_task_runner) {}
+
+FileProtocolHandler::~FileProtocolHandler() {}
 
 URLRequestJob* FileProtocolHandler::MaybeCreateJob(
     URLRequest* request, NetworkDelegate* network_delegate) const {
@@ -41,7 +46,8 @@
 
   // Use a regular file request job for all non-directories (including invalid
   // file names).
-  return new URLRequestFileJob(request, network_delegate, file_path);
+  return new URLRequestFileJob(request, network_delegate, file_path,
+                               file_task_runner_);
 }
 
 bool FileProtocolHandler::IsSafeRedirectTarget(const GURL& location) const {
diff --git a/net/url_request/file_protocol_handler.h b/net/url_request/file_protocol_handler.h
index 8087a6e..78956a9 100644
--- a/net/url_request/file_protocol_handler.h
+++ b/net/url_request/file_protocol_handler.h
@@ -7,10 +7,15 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
 #include "net/url_request/url_request_job_factory.h"
 
 class GURL;
 
+namespace base {
+class TaskRunner;
+}
+
 namespace net {
 
 class NetworkDelegate;
@@ -21,12 +26,15 @@
 class NET_EXPORT FileProtocolHandler :
     public URLRequestJobFactory::ProtocolHandler {
  public:
-  FileProtocolHandler();
+  explicit FileProtocolHandler(
+      const scoped_refptr<base::TaskRunner>& file_task_runner);
+  virtual ~FileProtocolHandler();
   virtual URLRequestJob* MaybeCreateJob(
       URLRequest* request, NetworkDelegate* network_delegate) const OVERRIDE;
   virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE;
 
  private:
+  const scoped_refptr<base::TaskRunner> file_task_runner_;
   DISALLOW_COPY_AND_ASSIGN(FileProtocolHandler);
 };
 
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index 8f0e28d..f8d3773 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -566,8 +566,6 @@
       request_->set_method(
           request_type_ == URLFetcher::POST ? "POST" :
           request_type_ == URLFetcher::PUT ? "PUT" : "PATCH");
-      extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType,
-                                       upload_content_type_);
       if (!upload_content_type_.empty()) {
         extra_request_headers_.SetHeader(HttpRequestHeaders::kContentType,
                                          upload_content_type_);
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 540dfc1..dce8214 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -156,6 +156,11 @@
     return file_thread_.message_loop();
   }
 
+  scoped_refptr<base::MessageLoopProxy> file_message_loop_proxy() {
+    DCHECK(file_thread_.IsRunning());
+    return file_thread_.message_loop_proxy();
+  }
+
  protected:
   virtual ~BasicURLRequestContext() {}
 
@@ -190,7 +195,9 @@
 #if !defined(DISABLE_FTP_SUPPORT)
       ftp_enabled_(false),
 #endif
-      http_cache_enabled_(true) {}
+      http_cache_enabled_(true) {
+}
+
 URLRequestContextBuilder::~URLRequestContextBuilder() {}
 
 #if defined(OS_LINUX) || defined(OS_ANDROID)
@@ -301,7 +308,8 @@
   if (data_enabled_)
     job_factory->SetProtocolHandler("data", new DataProtocolHandler);
   if (file_enabled_)
-    job_factory->SetProtocolHandler("file", new FileProtocolHandler);
+    job_factory->SetProtocolHandler(
+        "file", new FileProtocolHandler(context->file_message_loop_proxy()));
 #if !defined(DISABLE_FTP_SUPPORT)
   if (ftp_enabled_) {
     ftp_transaction_factory_.reset(
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 437f962..053a22e 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -26,8 +26,8 @@
 #include "base/platform_file.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
+#include "base/task_runner.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/threading/worker_pool.h"
 #include "build/build_config.h"
 #include "net/base/file_stream.h"
 #include "net/base/io_buffer.h"
@@ -53,26 +53,27 @@
       is_directory(false) {
 }
 
-URLRequestFileJob::URLRequestFileJob(URLRequest* request,
-                                     NetworkDelegate* network_delegate,
-                                     const base::FilePath& file_path)
+URLRequestFileJob::URLRequestFileJob(
+    URLRequest* request,
+    NetworkDelegate* network_delegate,
+    const base::FilePath& file_path,
+    const scoped_refptr<base::TaskRunner>& file_task_runner)
     : URLRequestJob(request, network_delegate),
       file_path_(file_path),
-      stream_(new FileStream(NULL)),
+      stream_(new FileStream(NULL, file_task_runner)),
+      file_task_runner_(file_task_runner),
       remaining_bytes_(0),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
 void URLRequestFileJob::Start() {
   FileMetaInfo* meta_info = new FileMetaInfo();
-  base::WorkerPool::PostTaskAndReply(
+  file_task_runner_->PostTaskAndReply(
       FROM_HERE,
       base::Bind(&URLRequestFileJob::FetchMetaInfo, file_path_,
                  base::Unretained(meta_info)),
       base::Bind(&URLRequestFileJob::DidFetchMetaInfo,
                  weak_ptr_factory_.GetWeakPtr(),
-                 base::Owned(meta_info)),
-      true);
+                 base::Owned(meta_info)));
 }
 
 void URLRequestFileJob::Kill() {
diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h
index 6fc7fb9..7cd7df0 100644
--- a/net/url_request/url_request_file_job.h
+++ b/net/url_request/url_request_file_job.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "net/base/net_export.h"
 #include "net/http/http_byte_range.h"
@@ -17,6 +18,7 @@
 
 namespace base{
 struct PlatformFileInfo;
+class TaskRunner;
 }
 namespace file_util {
 struct FileInfo;
@@ -31,7 +33,8 @@
  public:
   URLRequestFileJob(URLRequest* request,
                     NetworkDelegate* network_delegate,
-                    const base::FilePath& file_path);
+                    const base::FilePath& file_path,
+                    const scoped_refptr<base::TaskRunner>& file_task_runner);
 
   // URLRequestJob:
   virtual void Start() OVERRIDE;
@@ -91,6 +94,7 @@
 
   scoped_ptr<FileStream> stream_;
   FileMetaInfo meta_info_;
+  const scoped_refptr<base::TaskRunner> file_task_runner_;
 
   HttpByteRange byte_range_;
   int64 remaining_bytes_;
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 64f5ac1..13462ff 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -19,7 +19,9 @@
 #include "base/format_macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
 #include "base/path_service.h"
+#include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -591,7 +593,8 @@
     default_context_.set_network_delegate(&default_network_delegate_);
     default_context_.set_net_log(&net_log_);
     job_factory_.SetProtocolHandler("data", new DataProtocolHandler);
-    job_factory_.SetProtocolHandler("file", new FileProtocolHandler);
+    job_factory_.SetProtocolHandler(
+        "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
     default_context_.set_job_factory(&job_factory_);
     default_context_.Init();
   }
@@ -620,7 +623,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(!r.is_pending());
     EXPECT_FALSE(d.received_data_before_response());
@@ -663,7 +666,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(!r.is_pending());
     EXPECT_FALSE(d.received_data_before_response());
@@ -688,7 +691,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = -1;
     EXPECT_TRUE(file_util::GetFileSize(app_path, &file_size));
@@ -720,7 +723,7 @@
   }
   // Async cancellation should be safe even when URLRequest has been already
   // destroyed.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_F(URLRequestTest, FileTestFullSpecifiedRange) {
@@ -755,7 +758,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_TRUE(!r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -798,7 +801,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_TRUE(!r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -834,7 +837,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_TRUE(d.request_failed());
   }
 
@@ -849,7 +852,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_TRUE(d.request_failed());
   }
 }
@@ -887,7 +890,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     WIN32_FILE_ATTRIBUTE_DATA data;
     GetFileAttributesEx(app_path.value().c_str(),
@@ -931,7 +934,7 @@
 
     d.set_cancel_in_received_data_pending(true);
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
   }
 
   // Take out mock resource provider.
@@ -952,7 +955,7 @@
   TestDelegate d;
   URLRequest req(FilePathToFileURL(path), &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   ASSERT_EQ(1, d.received_redirect_count());
   ASSERT_LT(0, d.bytes_received());
@@ -966,7 +969,7 @@
   TestDelegate d;
   URLRequest req(GURL("file:///"), &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   ASSERT_EQ(1, d.received_redirect_count());
   ASSERT_FALSE(req.status().is_success());
@@ -1194,7 +1197,7 @@
   req.SetUserData(&user_data2, user_data2);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Make sure we can retrieve our specific user data
   EXPECT_EQ(user_data0, req.GetUserData(NULL));
@@ -1229,7 +1232,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_intercept_main_);
@@ -1262,7 +1265,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_intercept_main_);
@@ -1291,7 +1294,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_simulate_error_main_);
@@ -1320,7 +1323,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_restart_main_);
@@ -1351,7 +1354,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_cancel_main_);
@@ -1382,7 +1385,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_intercept_main_);
@@ -1407,7 +1410,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_simulate_error_main_);
@@ -1433,7 +1436,7 @@
   URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
   req.set_method("GET");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check the interceptor got called as expected
   EXPECT_TRUE(interceptor.did_cancel_then_restart_main_);
@@ -1452,7 +1455,7 @@
   TestDelegate d;
   URLRequest req(GURL("http://test_intercept/foo"), &d, context);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   LoadTimingInfo resulting_load_timing;
   req.GetLoadTimingInfo(&resulting_load_timing);
@@ -1729,7 +1732,7 @@
   req.set_method("GET");
 
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // Check we see a failed request.
   EXPECT_FALSE(req.status().is_success());
@@ -1747,7 +1750,7 @@
   TestDelegate d;
   URLRequest req(GURL("data:,"), &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ("", d.data_received());
   EXPECT_EQ(1, default_network_delegate_.completed_requests());
 }
@@ -1841,7 +1844,7 @@
     URLRequest req(
         test_server.GetURL("set-cookie?CookieToNotSend=1"), &d, &context);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
     EXPECT_EQ(1, network_delegate.set_cookie_count());
@@ -1854,7 +1857,7 @@
     TestDelegate d;
     URLRequest req(test_server.GetURL("echoheader?Cookie"), &d, &context);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
                 != std::string::npos);
@@ -1876,7 +1879,7 @@
                    &d,
                    &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
   }
@@ -1889,7 +1892,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
                 != std::string::npos);
@@ -1906,7 +1909,7 @@
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.set_load_flags(LOAD_DO_NOT_SEND_COOKIES);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
                 == std::string::npos);
@@ -1930,7 +1933,7 @@
                    &d,
                    &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -1949,7 +1952,7 @@
     req.set_load_flags(LOAD_DO_NOT_SAVE_COOKIES);
     req.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     // LOAD_DO_NOT_SAVE_COOKIES does not trigger OnSetCookie.
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
@@ -1965,7 +1968,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
                 == std::string::npos);
@@ -1991,7 +1994,7 @@
                    &d,
                    &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2005,7 +2008,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
                 != std::string::npos);
@@ -2023,7 +2026,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
                 == std::string::npos);
@@ -2046,7 +2049,7 @@
                    &d,
                    &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2064,7 +2067,7 @@
         &default_context_);
     req.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(2, network_delegate.blocked_set_cookie_count());
@@ -2078,7 +2081,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
                 == std::string::npos);
@@ -2101,7 +2104,7 @@
     TestDelegate d;
     URLRequest req(test_server.GetURL("set-cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2122,7 +2125,7 @@
                    &d,
                    &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2136,7 +2139,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
                 != std::string::npos);
@@ -2154,7 +2157,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
                 == std::string::npos);
@@ -2177,7 +2180,7 @@
                    &d,
                    &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
@@ -2195,7 +2198,7 @@
         &default_context_);
     req.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
     EXPECT_EQ(2, network_delegate.blocked_set_cookie_count());
@@ -2209,7 +2212,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
                 == std::string::npos);
@@ -2278,7 +2281,7 @@
         &d,
         &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
   }
   // Verify that the cookie is not set.
   {
@@ -2288,7 +2291,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("StillGood=1") == std::string::npos);
   }
@@ -2302,7 +2305,7 @@
         &d,
         &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
   }
   // Verify that the cookie is set.
   {
@@ -2312,7 +2315,7 @@
     URLRequest req(
         test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("StillGood=1") != std::string::npos);
   }
@@ -2338,7 +2341,7 @@
     req.SetExtraRequestHeaders(headers);
 
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ("http://foo.com/", d.data_received());
   }
@@ -2356,7 +2359,7 @@
     req.set_load_flags(LOAD_VALIDATE_CACHE);
 
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ("None", d.data_received());
   }
@@ -2393,7 +2396,7 @@
       req.SetExtraRequestHeaders(headers);
     }
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(redirect_method, req.method());
     EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
     EXPECT_EQ(OK, req.status().error());
@@ -2436,7 +2439,7 @@
       r.Start();
       EXPECT_TRUE(r.is_pending());
 
-      base::MessageLoop::current()->Run();
+      base::RunLoop().Run();
 
       ASSERT_EQ(1, d.response_started_count())
           << "request failed: " << r.status().status()
@@ -2482,7 +2485,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     bool is_success = r.status().is_success();
 
@@ -2521,7 +2524,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
     EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r.status().error());
@@ -2547,7 +2550,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
     EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r.status().error());
@@ -2588,12 +2591,12 @@
 
     r.Start();
     for (size_t i = 0; i < blocking_stages_length; ++i) {
-      base::MessageLoop::current()->Run();
+      base::RunLoop().Run();
       EXPECT_EQ(blocking_stages[i],
                 network_delegate.stage_blocked_for_callback());
       network_delegate.DoCallback(OK);
     }
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(200, r.GetResponseCode());
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(1, network_delegate.created_requests());
@@ -2620,7 +2623,7 @@
     URLRequest r(test_server_.GetURL(std::string()), &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
     EXPECT_EQ(ERR_EMPTY_RESPONSE, r.status().error());
@@ -2650,7 +2653,7 @@
     URLRequest r(url, &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
     EXPECT_EQ(ERR_BLOCKED_BY_CLIENT, r.status().error());
@@ -2727,7 +2730,7 @@
     URLRequest r(original_url, &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -2760,7 +2763,7 @@
     URLRequest r(original_url, &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -2800,7 +2803,7 @@
                       base::UintToString(arraysize(kData) - 1));
     r.SetExtraRequestHeaders(headers);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -2837,7 +2840,7 @@
     URLRequest r(url, &d, &context);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -2874,7 +2877,7 @@
       EXPECT_FALSE(headers.HasHeader("Authorization"));
     }
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -2908,7 +2911,7 @@
     GURL url(test_server_.GetURL("auth-basic"));
     URLRequest r(url, &d, &context);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -2943,7 +2946,7 @@
     GURL url(test_server_.GetURL("auth-basic"));
     URLRequest r(url, &d, &context);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -2981,7 +2984,7 @@
     GURL url(test_server_.GetURL("auth-basic"));
     URLRequest r(url, &d, &context);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(OK, r.status().error());
@@ -3015,7 +3018,7 @@
     GURL url(test_server_.GetURL("auth-basic"));
     URLRequest r(url, &d, &context);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -3050,7 +3053,7 @@
     GURL url(test_server_.GetURL("auth-basic"));
     URLRequest r(url, &d, &context);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(0, r.status().error());
@@ -3083,7 +3086,7 @@
     GURL url(test_server_.GetURL("auth-basic"));
     URLRequest r(url, &d, &context);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
     EXPECT_EQ(OK, r.status().error());
@@ -3114,7 +3117,7 @@
     URLRequest r(test_server_.GetURL(std::string()), &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST,
               network_delegate.stage_blocked_for_callback());
     EXPECT_EQ(0, network_delegate.completed_requests());
@@ -3150,7 +3153,7 @@
     URLRequest r(test_server_.GetURL(std::string()), &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS,
               network_delegate.stage_blocked_for_callback());
     EXPECT_EQ(0, network_delegate.completed_requests());
@@ -3185,7 +3188,7 @@
     URLRequest r(test_server_.GetURL(std::string()), &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(BlockingNetworkDelegate::ON_HEADERS_RECEIVED,
               network_delegate.stage_blocked_for_callback());
     EXPECT_EQ(0, network_delegate.completed_requests());
@@ -3220,7 +3223,7 @@
     URLRequest r(test_server_.GetURL("auth-basic"), &d, &context);
 
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(BlockingNetworkDelegate::ON_AUTH_REQUIRED,
               network_delegate.stage_blocked_for_callback());
     EXPECT_EQ(0, network_delegate.completed_requests());
@@ -3254,7 +3257,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
     EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r.status().error());
@@ -3271,7 +3274,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -3337,7 +3340,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -3363,7 +3366,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -3388,7 +3391,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     LoadTimingInfo load_timing_info;
     r.GetLoadTimingInfo(&load_timing_info);
@@ -3437,7 +3440,7 @@
       r.Start();
       EXPECT_TRUE(r.is_pending());
 
-      base::MessageLoop::current()->Run();
+      base::RunLoop().Run();
 
       EXPECT_EQ(1, d.response_started_count());
       EXPECT_FALSE(d.received_data_before_response());
@@ -3473,7 +3476,7 @@
       "server-redirect?" + http_destination.spec()), &d, &default_context_);
   req.SetReferrer("https://www.referrer.com/");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, d.response_started_count());
   EXPECT_EQ(1, d.received_redirect_count());
@@ -3490,7 +3493,7 @@
   TestDelegate d;
   URLRequest req(original_url, &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, d.response_started_count());
   EXPECT_EQ(1, d.received_redirect_count());
@@ -3530,7 +3533,7 @@
   TestDelegate d;
   URLRequest req(original_url, &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, d.response_started_count());
   EXPECT_EQ(2, d.received_redirect_count());
@@ -3568,7 +3571,7 @@
   RedirectWithAdditionalHeadersDelegate d;
   URLRequest req(original_url, &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   std::string value;
   const HttpRequestHeaders& headers = req.extra_request_headers();
@@ -3605,7 +3608,7 @@
   URLRequest req(original_url, &d, &default_context_);
   req.SetExtraRequestHeaderByName(kExtraHeaderToRemove, "dummy", false);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   std::string value;
   const HttpRequestHeaders& headers = req.extra_request_headers();
@@ -3625,7 +3628,7 @@
 
     r.Cancel();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     // We expect to receive OnResponseStarted even though the request has been
     // cancelled.
@@ -3647,7 +3650,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_EQ(0, d.bytes_received());
@@ -3668,7 +3671,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     // There is no guarantee about how much data was received
@@ -3713,7 +3716,7 @@
     TestDelegate d;
     URLRequest r(test_server_.GetURL("cachetime"), &d, &default_context_);
     r.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
   }
 
@@ -3723,7 +3726,7 @@
     URLRequest r(test_server_.GetURL("cachetime"), &d, &default_context_);
     r.Start();
     r.Cancel();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(URLRequestStatus::CANCELED, r.status().status());
     EXPECT_EQ(1, d.response_started_count());
@@ -3753,7 +3756,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     ASSERT_EQ(1, d.response_started_count())
         << "request failed: " << r.status().status()
@@ -3804,7 +3807,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 size = 0;
     ASSERT_EQ(true, file_util::GetFileSize(path, &size));
@@ -3835,7 +3838,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     VerifyReceivedDataMatchesChunks(&r, &d);
   }
@@ -3852,7 +3855,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
     AddChunksToUpload(&r);
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     VerifyReceivedDataMatchesChunks(&r, &d);
   }
@@ -3869,9 +3872,9 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->RunUntilIdle();
+    base::RunLoop().RunUntilIdle();
     AddChunksToUpload(&r);
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     VerifyReceivedDataMatchesChunks(&r, &d);
   }
@@ -3884,7 +3887,7 @@
   URLRequest req(
       test_server_.GetURL("files/with-headers.html"), &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   const HttpResponseHeaders* headers = req.response_headers();
 
@@ -3920,7 +3923,7 @@
       &d,
       &default_context_);
   request.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
@@ -3964,7 +3967,7 @@
       &d,
       &default_context_);
   request.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
@@ -3995,7 +3998,7 @@
       &d,
       &default_context_);
   request.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // We should have set parameters from the first header, not the second.
   TransportSecurityState* security_state =
@@ -4024,7 +4027,7 @@
       &d,
       &default_context_);
   request.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   // We should have set parameters from the first header, not the second.
   TransportSecurityState* security_state =
@@ -4066,7 +4069,7 @@
       &d,
       &default_context_);
   request.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
@@ -4095,7 +4098,7 @@
   URLRequest req(test_server_.GetURL(
       "files/content-type-normalization.html"), &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   std::string mime_type;
   req.GetMimeType(&mime_type);
@@ -4111,23 +4114,36 @@
   // Test URLRequestJobFactory::ProtocolHandler::IsSafeRedirectTarget().
   GURL file_url("file:///foo.txt");
   GURL data_url("data:,foo");
-  FileProtocolHandler file_protocol_handler;
+  FileProtocolHandler file_protocol_handler(base::MessageLoopProxy::current());
   EXPECT_FALSE(file_protocol_handler.IsSafeRedirectTarget(file_url));
   DataProtocolHandler data_protocol_handler;
-  EXPECT_TRUE(data_protocol_handler.IsSafeRedirectTarget(data_url));
+  EXPECT_FALSE(data_protocol_handler.IsSafeRedirectTarget(data_url));
 
   // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
   EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(file_url));
-  EXPECT_TRUE(job_factory_.IsSafeRedirectTarget(data_url));
+  EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(data_url));
 }
 
-TEST_F(URLRequestTestHTTP, RestrictRedirects) {
+TEST_F(URLRequestTestHTTP, RestrictFileRedirects) {
   ASSERT_TRUE(test_server_.Start());
 
   TestDelegate d;
   URLRequest req(test_server_.GetURL(
       "files/redirect-to-file.html"), &d, &default_context_);
   req.Start();
+  base::RunLoop().Run();
+
+  EXPECT_EQ(URLRequestStatus::FAILED, req.status().status());
+  EXPECT_EQ(ERR_UNSAFE_REDIRECT, req.status().error());
+}
+
+TEST_F(URLRequestTestHTTP, RestrictDataRedirects) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  URLRequest req(test_server_.GetURL(
+      "files/redirect-to-data.html"), &d, &default_context_);
+  req.Start();
   base::MessageLoop::current()->Run();
 
   EXPECT_EQ(URLRequestStatus::FAILED, req.status().status());
@@ -4141,7 +4157,7 @@
   URLRequest req(test_server_.GetURL(
       "files/redirect-to-invalid-url.html"), &d, &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(URLRequestStatus::FAILED, req.status().status());
   EXPECT_EQ(ERR_INVALID_URL, req.status().error());
@@ -4155,7 +4171,7 @@
       test_server_.GetURL("echoheader?Referer"), &d, &default_context_);
   req.SetReferrer("http://user:pass@foo.com/");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(std::string("http://foo.com/"), d.data_received());
 }
@@ -4168,7 +4184,7 @@
       test_server_.GetURL("echoheader?Referer"), &d, &default_context_);
   req.SetReferrer("http://foo.com/test#fragment");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(std::string("http://foo.com/test"), d.data_received());
 }
@@ -4182,7 +4198,7 @@
   req.SetReferrer("http://foo.com/test#fragment");
   req.SetReferrer("");
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(std::string("None"), d.data_received());
 }
@@ -4196,7 +4212,7 @@
     URLRequest req(
         test_server_.GetURL("files/redirect-test.html"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_EQ(0, d.bytes_received());
@@ -4215,12 +4231,12 @@
     URLRequest req(test_url, &d, &default_context_);
 
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.received_redirect_count());
 
     req.FollowDeferredRedirect();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -4251,7 +4267,7 @@
     EXPECT_FALSE(d.have_full_request_headers());
 
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.received_redirect_count());
     EXPECT_TRUE(d.have_full_request_headers());
@@ -4259,7 +4275,7 @@
     d.ClearFullRequestHeaders();
 
     req.FollowDeferredRedirect();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     GURL target_url(test_server_.GetURL("files/with-headers.html"));
     EXPECT_EQ(1, d.response_started_count());
@@ -4290,12 +4306,12 @@
     URLRequest req(
         test_server_.GetURL("files/redirect-test.html"), &d, &default_context_);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.received_redirect_count());
 
     req.Cancel();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_EQ(0, d.bytes_received());
@@ -4316,7 +4332,7 @@
     headers.SetHeader("foo", "1");
     req.SetExtraRequestHeaders(headers);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     LoadTimingInfo load_timing_info;
     req.GetLoadTimingInfo(&load_timing_info);
@@ -4332,7 +4348,7 @@
     headers.SetHeader("foo", "1");
     req.SetExtraRequestHeaders(headers);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(req.was_cached());
 
@@ -4350,7 +4366,7 @@
     headers.SetHeader("foo", "2");
     req.SetExtraRequestHeaders(headers);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_FALSE(req.was_cached());
 
@@ -4371,7 +4387,7 @@
     URLRequest r(test_server_.GetURL("auth-basic"), &d, &default_context_);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("user/secret") != std::string::npos);
   }
@@ -4387,7 +4403,7 @@
     r.set_load_flags(LOAD_VALIDATE_CACHE);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("user/secret") != std::string::npos);
 
@@ -4418,7 +4434,7 @@
     URLRequest r(url_requiring_auth, &d, &context);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("user/secret") != std::string::npos);
 
@@ -4447,7 +4463,7 @@
     URLRequest r(url_with_identity, &d, &context);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("user2/secret") != std::string::npos);
 
@@ -4469,7 +4485,7 @@
     URLRequest r(test_server_.GetURL("auth-basic"), &d, &default_context_);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("user/secret") != std::string::npos);
 
@@ -4501,7 +4517,7 @@
     r.set_load_flags(LOAD_VALIDATE_CACHE);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_TRUE(d.data_received().find("user/secret") != std::string::npos);
 
@@ -4544,7 +4560,7 @@
     "Origin: http://localhost:1337/");
   req.SetExtraRequestHeaders(headers);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   std::string mime_type;
   req.GetMimeType(&mime_type);
@@ -4627,7 +4643,7 @@
   AddTestInterceptor()->set_main_intercept_job(job);
 
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ("GET", req.method());
 }
 
@@ -4651,7 +4667,7 @@
   AddTestInterceptor()->set_main_intercept_job(job);
 
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ("POST", req.method());
   EXPECT_EQ(kData, d.data_received());
 }
@@ -4671,7 +4687,7 @@
   URLRequest req(
       test_server_.GetURL("echoheader?Accept-Language"), &d, &context);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ("en", d.data_received());
 }
 
@@ -4692,7 +4708,7 @@
   URLRequest req(
       test_server_.GetURL("echoheader?Accept-Language"), &d, &context);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ("None", d.data_received());
 }
 
@@ -4709,7 +4725,7 @@
   headers.SetHeader(HttpRequestHeaders::kAcceptLanguage, "ru");
   req.SetExtraRequestHeaders(headers);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ(std::string("ru"), d.data_received());
 }
 
@@ -4724,7 +4740,7 @@
   HttpRequestHeaders headers;
   req.SetExtraRequestHeaders(headers);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_TRUE(ContainsString(d.data_received(), "gzip"));
 }
 
@@ -4741,7 +4757,7 @@
   headers.SetHeader(HttpRequestHeaders::kAcceptEncoding, "identity");
   req.SetExtraRequestHeaders(headers);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_FALSE(ContainsString(d.data_received(), "gzip"));
   EXPECT_TRUE(ContainsString(d.data_received(), "identity"));
 }
@@ -4758,7 +4774,7 @@
   headers.SetHeader(HttpRequestHeaders::kAcceptCharset, "koi-8r");
   req.SetExtraRequestHeaders(headers);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ(std::string("koi-8r"), d.data_received());
 }
 
@@ -4771,7 +4787,7 @@
                  &d,
                  &default_context_);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ(req.context()->GetUserAgent(req.url()), d.data_received());
 }
 
@@ -4788,7 +4804,7 @@
   headers.SetHeader(HttpRequestHeaders::kUserAgent, "Lynx (textmode)");
   req.SetExtraRequestHeaders(headers);
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   // If the net tests are being run with ChromeFrame then we need to allow for
   // the 'chromeframe' suffix which is added to the user agent before the
   // closing parentheses.
@@ -4820,7 +4836,7 @@
     TestDelegate d;
     URLRequest req(test_server_.GetURL(tests[i].request), &d, &context);
     req.Start();
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
     EXPECT_EQ(tests[i].expected_response, d.data_received())
         << " Request = \"" << tests[i].request << "\"";
   }
@@ -4850,7 +4866,7 @@
   AddTestInterceptor()->set_main_intercept_job(job.get());
 
   // Should trigger |job| to be started.
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
   EXPECT_EQ(LOW, job->priority());
 }
 
@@ -4880,7 +4896,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -4912,7 +4928,7 @@
       r.Start();
       EXPECT_TRUE(r.is_pending());
 
-      base::MessageLoop::current()->Run();
+      base::RunLoop().Run();
 
       EXPECT_EQ(1, d.response_started_count());
       EXPECT_FALSE(d.received_data_before_response());
@@ -4948,7 +4964,7 @@
       r.Start();
       EXPECT_TRUE(r.is_pending());
 
-      base::MessageLoop::current()->Run();
+      base::RunLoop().Run();
 
       EXPECT_EQ(1, d.response_started_count());
       EXPECT_FALSE(d.received_data_before_response());
@@ -4991,7 +5007,7 @@
   URLRequest r(test_server.GetURL(std::string()), &d, &context);
   r.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, d.response_started_count());
   EXPECT_NE(0, d.bytes_received());
@@ -5035,7 +5051,7 @@
   r.Start();
   EXPECT_TRUE(r.is_pending());
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, d.response_started_count());
   EXPECT_FALSE(d.received_data_before_response());
@@ -5083,7 +5099,7 @@
   r.Start();
   EXPECT_TRUE(r.is_pending());
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, d.response_started_count());
   EXPECT_FALSE(d.received_data_before_response());
@@ -5154,7 +5170,7 @@
   req.set_upload(make_scoped_ptr(CreateSimpleUploadData(kData)));
 
   req.Start();
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ("https", req.url().scheme());
   EXPECT_EQ("POST", req.method());
@@ -5184,7 +5200,7 @@
   URLRequest r(test_server.GetURL(std::string()), &d, &context);
   r.Start();
 
-  base::MessageLoop::current()->Run();
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, d.response_started_count());
   EXPECT_NE(0, d.bytes_received());
@@ -5235,7 +5251,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.on_certificate_requested_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -5246,7 +5262,7 @@
     // all platforms so we can test sending a cert as well.
     r.ContinueWithCertificate(NULL);
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
@@ -5275,7 +5291,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
   }
@@ -5291,7 +5307,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     // The response will look like;
     //   insert abc
@@ -5344,7 +5360,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
   }
@@ -5376,7 +5392,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     // The response will look like;
     //   insert abc
@@ -5492,7 +5508,7 @@
     URLRequest r(test_server.GetURL(std::string()), &d, &context_);
     r.Start();
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_EQ(1, d.response_started_count());
     *out_cert_status = r.ssl_info().cert_status;
@@ -5920,7 +5936,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
@@ -5938,7 +5954,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
@@ -5964,7 +5980,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -5996,7 +6012,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6034,7 +6050,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6067,7 +6083,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6097,7 +6113,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6130,7 +6146,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6162,7 +6178,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6180,7 +6196,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6214,7 +6230,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
@@ -6235,7 +6251,7 @@
     r.Start();
     EXPECT_TRUE(r.is_pending());
 
-    base::MessageLoop::current()->Run();
+    base::RunLoop().Run();
 
     int64 file_size = 0;
     file_util::GetFileSize(app_path, &file_size);
diff --git a/net/url_request/view_cache_helper_unittest.cc b/net/url_request/view_cache_helper_unittest.cc
index db26f70..0fdd193 100644
--- a/net/url_request/view_cache_helper_unittest.cc
+++ b/net/url_request/view_cache_helper_unittest.cc
@@ -34,7 +34,8 @@
   set_http_transaction_factory(&cache_);
 }
 
-void WriteHeaders(disk_cache::Entry* entry, int flags, const std::string data) {
+void WriteHeaders(disk_cache::Entry* entry, int flags,
+                  const std::string& data) {
   if (data.empty())
     return;
 
@@ -53,7 +54,7 @@
   ASSERT_EQ(len, cb.GetResult(rv));
 }
 
-void WriteData(disk_cache::Entry* entry, int index, const std::string data) {
+void WriteData(disk_cache::Entry* entry, int index, const std::string& data) {
   if (data.empty())
     return;
 
@@ -66,9 +67,9 @@
   ASSERT_EQ(len, cb.GetResult(rv));
 }
 
-void WriteToEntry(disk_cache::Backend* cache, const std::string key,
-                  const std::string data0, const std::string data1,
-                  const std::string data2) {
+void WriteToEntry(disk_cache::Backend* cache, const std::string& key,
+                  const std::string& data0, const std::string& data1,
+                  const std::string& data2) {
   net::TestCompletionCallback cb;
   disk_cache::Entry* entry;
   int rv = cache->CreateEntry(key, &entry, cb.callback());
diff --git a/ppapi/OWNERS b/ppapi/OWNERS
index a114912..c4871e2 100644
--- a/ppapi/OWNERS
+++ b/ppapi/OWNERS
@@ -1,3 +1,4 @@
+bbudge@chromium.org
 brettw@chromium.org
 dmichael@chromium.org
 raymes@chromium.org
diff --git a/ppapi/api/ppb_file_ref.idl b/ppapi/api/ppb_file_ref.idl
index 8e4b81d..d922647 100644
--- a/ppapi/api/ppb_file_ref.idl
+++ b/ppapi/api/ppb_file_ref.idl
@@ -25,7 +25,7 @@
    *
    * @param[in] resource A <code>PP_Resource</code> corresponding to a file
    * system.
-   * @param[in] path A path to the file.
+   * @param[in] path A path to the file. Must begin with a '/' character.
    *
    * @return A <code>PP_Resource</code> corresponding to a file reference if
    * successful or 0 if the path is malformed.
diff --git a/ppapi/api/private/ppb_gpu_blacklist_private.idl b/ppapi/api/private/ppb_gpu_blacklist_private.idl
deleted file mode 100644
index ef8e1b5..0000000
--- a/ppapi/api/private/ppb_gpu_blacklist_private.idl
+++ /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.
- */
-
-/* This file contains the <code>PPB_FileRefPrivate</code> interface. */
-label Chrome {
-  M24 = 0.2
-};
-
-/** PPB_GpuBlacklist_Private interface */
-interface PPB_GpuBlacklist_Private {
-  /**
-   * Returns true if the current system's GPU is blacklisted and 3D in Chrome
-   * will be emulated via software rendering.
-   *
-   * This is used internally by the SRPC NaCl proxy (not exposed to plugins) to
-   * determine if the 3D interfaces should be exposed to plugins. We don't
-   * expose the 3D interfaces if the 3D support is software-emulated. When the
-   * SRPC proxy is removed, this interface can also be removed.
-   */
-  PP_Bool IsGpuBlacklisted();
-};
diff --git a/ppapi/api/private/ppb_nacl_private.idl b/ppapi/api/private/ppb_nacl_private.idl
index bf2918b..9a67404 100644
--- a/ppapi/api/private/ppb_nacl_private.idl
+++ b/ppapi/api/private/ppb_nacl_private.idl
@@ -35,6 +35,9 @@
    * will be able to use dynamic code system calls (e.g., mmap with PROT_EXEC).
    * The |enable_exception_handling| flag indicates whether or not the nexe
    * will be able to use hardware exception handling.
+   * The |enable_crash_throttling| flag indicates whether or not crashes of
+   * the nexe contribute to crash throttling statisics and whether nexe starts
+   * are throttled by crash throttling.
    */
   PP_ExternalPluginResult LaunchSelLdr([in] PP_Instance instance,
                                        [in] str_t alleged_url,
@@ -43,6 +46,7 @@
                                        [in] PP_Bool enable_ppapi_dev,
                                        [in] PP_Bool enable_dyncode_syscalls,
                                        [in] PP_Bool enable_exception_handling,
+                                       [in] PP_Bool enable_crash_throttling,
                                        [out] mem_t imc_handle,
                                        [out] PP_Var error_message);
 
diff --git a/ppapi/c/ppb_file_ref.h b/ppapi/c/ppb_file_ref.h
index 0f35e2c..873ef18 100644
--- a/ppapi/c/ppb_file_ref.h
+++ b/ppapi/c/ppb_file_ref.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_file_ref.idl modified Wed May 22 15:08:49 2013. */
+/* From ppb_file_ref.idl modified Thu Aug 15 10:50:43 2013. */
 
 #ifndef PPAPI_C_PPB_FILE_REF_H_
 #define PPAPI_C_PPB_FILE_REF_H_
@@ -45,7 +45,7 @@
    *
    * @param[in] resource A <code>PP_Resource</code> corresponding to a file
    * system.
-   * @param[in] path A path to the file.
+   * @param[in] path A path to the file. Must begin with a '/' character.
    *
    * @return A <code>PP_Resource</code> corresponding to a file reference if
    * successful or 0 if the path is malformed.
diff --git a/ppapi/c/private/ppb_gpu_blacklist_private.h b/ppapi/c/private/ppb_gpu_blacklist_private.h
deleted file mode 100644
index f37106e..0000000
--- a/ppapi/c/private/ppb_gpu_blacklist_private.h
+++ /dev/null
@@ -1,49 +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 private/ppb_gpu_blacklist_private.idl,
- *   modified Wed Oct 24 14:41:20 2012.
- */
-
-#ifndef PPAPI_C_PRIVATE_PPB_GPU_BLACKLIST_PRIVATE_H_
-#define PPAPI_C_PRIVATE_PPB_GPU_BLACKLIST_PRIVATE_H_
-
-#include "ppapi/c/pp_bool.h"
-#include "ppapi/c/pp_macros.h"
-
-#define PPB_GPUBLACKLIST_PRIVATE_INTERFACE_0_2 "PPB_GpuBlacklist_Private;0.2"
-#define PPB_GPUBLACKLIST_PRIVATE_INTERFACE \
-    PPB_GPUBLACKLIST_PRIVATE_INTERFACE_0_2
-
-/**
- * @file
- * This file contains the <code>PPB_FileRefPrivate</code> interface. */
-
-
-/**
- * @addtogroup Interfaces
- * @{
- */
-/** PPB_GpuBlacklist_Private interface */
-struct PPB_GpuBlacklist_Private_0_2 {
-  /**
-   * Returns true if the current system's GPU is blacklisted and 3D in Chrome
-   * will be emulated via software rendering.
-   *
-   * This is used internally by the SRPC NaCl proxy (not exposed to plugins) to
-   * determine if the 3D interfaces should be exposed to plugins. We don't
-   * expose the 3D interfaces if the 3D support is software-emulated. When the
-   * SRPC proxy is removed, this interface can also be removed.
-   */
-  PP_Bool (*IsGpuBlacklisted)(void);
-};
-
-typedef struct PPB_GpuBlacklist_Private_0_2 PPB_GpuBlacklist_Private;
-/**
- * @}
- */
-
-#endif  /* PPAPI_C_PRIVATE_PPB_GPU_BLACKLIST_PRIVATE_H_ */
-
diff --git a/ppapi/c/private/ppb_nacl_private.h b/ppapi/c/private/ppb_nacl_private.h
index 8be2829..772998b 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 Tue Aug  6 11:51:26 2013. */
+/* From private/ppb_nacl_private.idl modified Mon Aug 19 14:06:38 2013. */
 
 #ifndef PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
 #define PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
@@ -63,6 +63,9 @@
    * will be able to use dynamic code system calls (e.g., mmap with PROT_EXEC).
    * The |enable_exception_handling| flag indicates whether or not the nexe
    * will be able to use hardware exception handling.
+   * The |enable_crash_throttling| flag indicates whether or not crashes of
+   * the nexe contribute to crash throttling statisics and whether nexe starts
+   * are throttled by crash throttling.
    */
   PP_ExternalPluginResult (*LaunchSelLdr)(PP_Instance instance,
                                           const char* alleged_url,
@@ -71,6 +74,7 @@
                                           PP_Bool enable_ppapi_dev,
                                           PP_Bool enable_dyncode_syscalls,
                                           PP_Bool enable_exception_handling,
+                                          PP_Bool enable_crash_throttling,
                                           void* imc_handle,
                                           struct PP_Var* error_message);
   /* This function starts the IPC proxy so the nexe can communicate with the
diff --git a/ppapi/cpp/file_ref.h b/ppapi/cpp/file_ref.h
index d229c5f..56828f7 100644
--- a/ppapi/cpp/file_ref.h
+++ b/ppapi/cpp/file_ref.h
@@ -48,7 +48,7 @@
   ///
   /// @param[in] file_system A <code>FileSystem</code> corresponding to a file
   /// system type.
-  /// @param[in] path A path to the file.
+  /// @param[in] path A path to the file. Must begin with a '/' character.
   FileRef(const FileSystem& file_system, const char* path);
 
   /// The copy constructor for <code>FileRef</code>.
diff --git a/ppapi/examples/ime/ime.cc b/ppapi/examples/ime/ime.cc
index e730786..2721519 100644
--- a/ppapi/examples/ime/ime.cc
+++ b/ppapi/examples/ime/ime.cc
@@ -128,7 +128,8 @@
         area_(x, y, width, height),
         font_size_(height - 2),
         caret_pos_(std::string::npos),
-        anchor_pos_(std::string::npos) {
+        anchor_pos_(std::string::npos),
+        target_segment_(0) {
     pp::FontDescription_Dev desc;
     desc.set_family(PP_FONTFAMILY_SANSSERIF);
     desc.set_size(font_size_);
diff --git a/ppapi/examples/video_decode/video_decode.cc b/ppapi/examples/video_decode/video_decode.cc
index e6bcff8..d1f7181 100644
--- a/ppapi/examples/video_decode/video_decode.cc
+++ b/ppapi/examples/video_decode/video_decode.cc
@@ -221,6 +221,7 @@
                                                  pp::Module* module)
     : pp::Instance(instance), pp::Graphics3DClient(this),
       pp::VideoDecoderClient_Dev(this),
+      is_painting_(false),
       num_frames_rendered_(0),
       first_frame_delivered_ticks_(-1),
       swap_ticks_(0),
diff --git a/ppapi/native_client/src/trusted/plugin/json_manifest.cc b/ppapi/native_client/src/trusted/plugin/json_manifest.cc
index 12d3c10..0928c05 100644
--- a/ppapi/native_client/src/trusted/plugin/json_manifest.cc
+++ b/ppapi/native_client/src/trusted/plugin/json_manifest.cc
@@ -173,6 +173,15 @@
     urlSpecPlusOptional = kPnaclUrlSpecPlusOptional;
     urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kPnaclUrlSpecPlusOptional);
   } else {
+    // URL specifications must not contain "pnacl-translate" keys.
+    // This prohibits NaCl clients from invoking PNaCl.
+    if (url_spec.isMember(kPnaclTranslateKey)) {
+      nacl::stringstream error_stream;
+      error_stream << "PNaCl-like NMF with application/x-nacl mimetype instead "
+                   << "of x-pnacl mimetype (has " << kPnaclTranslateKey << ").";
+      *error_string = error_stream.str();
+      return false;
+    }
     urlSpecPlusOptional = kManifestUrlSpecRequired;
     urlSpecPlusOptionalLength = NACL_ARRAY_SIZE(kManifestUrlSpecRequired);
   }
@@ -184,16 +193,6 @@
                          error_string)) {
     return false;
   }
-  // URL specifications must not contain "pnacl-translate" keys.
-  // This prohibits NaCl clients from invoking PNaCl.
-  Json::Value translate = url_spec[kPnaclTranslateKey];
-  if (!translate.empty()) {
-    nacl::stringstream error_stream;
-    error_stream << parent_key << " property '" << container_key <<
-        "' has '" << kPnaclTranslateKey << "' inside URL spec.";
-    *error_string = error_stream.str();
-    return false;
-  }
   // Verify the correct types of the fields if they exist.
   Json::Value url = url_spec[kUrlKey];
   if (!url.isString()) {
diff --git a/ppapi/native_client/src/trusted/plugin/module_ppapi.cc b/ppapi/native_client/src/trusted/plugin/module_ppapi.cc
index 4204ed4..f78bbf3 100644
--- a/ppapi/native_client/src/trusted/plugin/module_ppapi.cc
+++ b/ppapi/native_client/src/trusted/plugin/module_ppapi.cc
@@ -76,28 +76,6 @@
   return plugin;
 }
 
-const uint64_t kMaxCrashesPerInterval = 3;
-const uint64_t kCrashesIntervalInSeconds = 120;
-
-void ModulePpapi::RegisterPluginCrash() {
-  PLUGIN_PRINTF(("ModulePpapi::RegisterPluginCrash ()\n"));
-  if (crash_times_.size() == kMaxCrashesPerInterval) {
-    crash_times_.pop_front();
-  }
-  int64_t time = NaClGetTimeOfDayMicroseconds();
-  crash_times_.push_back(time);
-}
-
-bool ModulePpapi::IsPluginUnstable() {
-  PLUGIN_PRINTF(("ModulePpapi::IsPluginUnstable ()\n"));
-  if (crash_times_.size() != kMaxCrashesPerInterval) {
-    return false;
-  }
-  int64_t now = NaClGetTimeOfDayMicroseconds();
-  int64_t delta = now - crash_times_.front();
-  return delta / (1000.0 * 1000.0) <= kCrashesIntervalInSeconds;
-}
-
 }  // namespace plugin
 
 
diff --git a/ppapi/native_client/src/trusted/plugin/module_ppapi.h b/ppapi/native_client/src/trusted/plugin/module_ppapi.h
index b2e7564..ee7bd19 100644
--- a/ppapi/native_client/src/trusted/plugin/module_ppapi.h
+++ b/ppapi/native_client/src/trusted/plugin/module_ppapi.h
@@ -4,8 +4,6 @@
  * found in the LICENSE file.
  */
 
-#include <deque>
-
 #include "ppapi/c/private/ppb_nacl_private.h"
 #include "ppapi/cpp/module.h"
 
@@ -21,18 +19,9 @@
 
   virtual pp::Instance* CreateInstance(PP_Instance pp_instance);
 
-  // NaCl crash throttling.  If RegisterPluginCrash is called too many times
-  // within a time period, IsPluginUnstable reports true.  As long as
-  // IsPluginUnstable returns true, NaCl modules will fail to load.
-  void RegisterPluginCrash();
-  bool IsPluginUnstable();
-
  private:
   bool init_was_successful_;
   const PPB_NaCl_Private* private_interface_;
-
-  // Crash throttling support.
-  std::deque<int64_t> crash_times_;
 };
 
 }  // namespace plugin
diff --git a/ppapi/native_client/src/trusted/plugin/nacl_entry_points.h b/ppapi/native_client/src/trusted/plugin/nacl_entry_points.h
index 4fd620d..0d18208 100644
--- a/ppapi/native_client/src/trusted/plugin/nacl_entry_points.h
+++ b/ppapi/native_client/src/trusted/plugin/nacl_entry_points.h
@@ -24,6 +24,7 @@
     PP_Bool enable_ppapi_dev,
     PP_Bool enable_dyncode_syscalls,
     PP_Bool enable_exception_handling,
+    PP_Bool enable_crash_throttling,
     NaClHandle* result_socket,
     struct PP_Var* error_message);
 
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.cc b/ppapi/native_client/src/trusted/plugin/plugin.cc
index fe27aa2..2aa90be 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.cc
+++ b/ppapi/native_client/src/trusted/plugin/plugin.cc
@@ -55,7 +55,6 @@
 
 #include "ppapi/native_client/src/trusted/plugin/file_utils.h"
 #include "ppapi/native_client/src/trusted/plugin/json_manifest.h"
-#include "ppapi/native_client/src/trusted/plugin/module_ppapi.h"
 #include "ppapi/native_client/src/trusted/plugin/nacl_entry_points.h"
 #include "ppapi/native_client/src/trusted/plugin/nacl_subprocess.h"
 #include "ppapi/native_client/src/trusted/plugin/nexe_arch.h"
@@ -447,6 +446,7 @@
                             ErrorInfo* error_info,
                             bool enable_dyncode_syscalls,
                             bool enable_exception_handling,
+                            bool enable_crash_throttling,
                             const pp::CompletionCallback& init_done_cb,
                             const pp::CompletionCallback& crash_cb) {
   // Before forking a new sel_ldr process, ensure that we do not leak
@@ -460,7 +460,8 @@
                            true /* uses_ppapi */,
                            enable_dev_interfaces_,
                            enable_dyncode_syscalls,
-                           enable_exception_handling);
+                           enable_exception_handling,
+                           enable_crash_throttling);
   if (!LoadNaClModuleCommon(wrapper, &main_subprocess_, manifest_.get(),
                             true /* should_report_uma */,
                             params, init_done_cb, crash_cb)) {
@@ -532,7 +533,8 @@
                            false /* uses_ppapi */,
                            enable_dev_interfaces_,
                            false /* enable_dyncode_syscalls */,
-                           false /* enable_exception_handling */);
+                           false /* enable_exception_handling */,
+                           true /* enable_crash_throttling */);
   if (!LoadNaClModuleCommon(wrapper, nacl_subprocess.get(), manifest,
                             false /* should_report_uma */,
                             params,
@@ -907,6 +909,7 @@
       wrapper.get(), &error_info,
       true, /* enable_dyncode_syscalls */
       true, /* enable_exception_handling */
+      false, /* enable_crash_throttling */
       callback_factory_.NewCallback(&Plugin::NexeFileDidOpenContinuation),
       callback_factory_.NewCallback(&Plugin::NexeDidCrash));
 
@@ -1010,10 +1013,6 @@
   // invocation will just be a no-op, since all the crash log will
   // have been received and we'll just get an EOF indication.
   CopyCrashLogToJsConsole();
-
-  // Remember the nexe crash time, which helps determine the need to throttle.
-  ModulePpapi* module_ppapi = static_cast<ModulePpapi*>(pp::Module::Get());
-  module_ppapi->RegisterPluginCrash();
 }
 
 void Plugin::BitcodeDidTranslate(int32_t pp_error) {
@@ -1033,6 +1032,7 @@
       wrapper.get(), &error_info,
       false, /* enable_dyncode_syscalls */
       false, /* enable_exception_handling */
+      true, /* enable_crash_throttling */
       callback_factory_.NewCallback(&Plugin::BitcodeDidTranslateContinuation),
       callback_factory_.NewCallback(&Plugin::NexeDidCrash));
 
@@ -1208,31 +1208,16 @@
     // Inform JavaScript that we found a nexe URL to load.
     EnqueueProgressEvent(kProgressEventProgress);
     if (pnacl_options.translate()) {
-      if (this->nacl_interface()->IsPnaclEnabled()) {
-        // Check whether PNaCl has been crashing "frequently".  If so, report
-        // a load error.
-        ModulePpapi* module_ppapi =
-            static_cast<ModulePpapi*>(pp::Module::Get());
-        if (module_ppapi->IsPluginUnstable()) {
-          error_info.SetReport(ERROR_PNACL_CRASH_THROTTLED,
-                               "PNaCl has been temporarily disabled because too"
-                               " many crashes have been observed.");
-        } else {
-          pp::CompletionCallback translate_callback =
-              callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
-          // Will always call the callback on success or failure.
-          pnacl_coordinator_.reset(
-              PnaclCoordinator::BitcodeToNative(this,
-                                                program_url,
-                                                pnacl_options,
-                                                translate_callback));
-          return;
-        }
-      } else {
-        error_info.SetReport(ERROR_PNACL_NOT_ENABLED,
-                             "PNaCl has not been enabled (e.g., by setting "
-                             "the --enable-pnacl flag).");
-      }
+      CHECK(nacl_interface()->IsPnaclEnabled());
+      pp::CompletionCallback translate_callback =
+          callback_factory_.NewCallback(&Plugin::BitcodeDidTranslate);
+      // Will always call the callback on success or failure.
+      pnacl_coordinator_.reset(
+          PnaclCoordinator::BitcodeToNative(this,
+                                            program_url,
+                                            pnacl_options,
+                                            translate_callback));
+      return;
     } else {
       // Try the fast path first. This will only block if the file is installed.
       if (OpenURLFast(program_url, &nexe_downloader_)) {
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.h b/ppapi/native_client/src/trusted/plugin/plugin.h
index 1e9e780..416ab5b 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.h
+++ b/ppapi/native_client/src/trusted/plugin/plugin.h
@@ -106,6 +106,7 @@
   bool LoadNaClModule(nacl::DescWrapper* wrapper, ErrorInfo* error_info,
                       bool enable_dyncode_syscalls,
                       bool enable_exception_handling,
+                      bool enable_crash_throttling,
                       const pp::CompletionCallback& init_done_cb,
                       const pp::CompletionCallback& crash_cb);
 
diff --git a/ppapi/native_client/src/trusted/plugin/plugin_error.h b/ppapi/native_client/src/trusted/plugin/plugin_error.h
index cba1701..4ec0b51 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin_error.h
+++ b/ppapi/native_client/src/trusted/plugin/plugin_error.h
@@ -93,8 +93,8 @@
   ERROR_PNACL_LLC_INTERNAL = 65,
   ERROR_PNACL_LD_INTERNAL = 66,
   ERROR_PNACL_CREATE_TEMP = 67,
-  // Remove this next code when pnacl is no longer behind a flag (when we
-  // remove the --enable-pnacl flag).
+  // This entry is no longer used, but should not be removed, because UMA
+  // numbers need to be kept consistent.
   ERROR_PNACL_NOT_ENABLED = 68,
   ERROR_MANIFEST_NOACCESS_URL = 69,
   ERROR_NEXE_NOACCESS_URL = 70,
diff --git a/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.cc b/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.cc
index 2714eac..486696b 100644
--- a/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.cc
+++ b/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.cc
@@ -24,6 +24,7 @@
                                  bool enable_ppapi_dev,
                                  bool enable_dyncode_syscalls,
                                  bool enable_exception_handling,
+                                 bool enable_crash_throttling,
                                  nacl::string* error_message) {
   *error_message = "";
   if (!launch_nacl_process)
@@ -37,6 +38,7 @@
                           PP_FromBool(enable_ppapi_dev),
                           PP_FromBool(enable_dyncode_syscalls),
                           PP_FromBool(enable_exception_handling),
+                          PP_FromBool(enable_crash_throttling),
                           &channel_,
                           &var_error_message) != PP_EXTERNAL_PLUGIN_OK) {
     pp::Var var_error_message_cpp(pp::PASS_REF, var_error_message);
diff --git a/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h b/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h
index a64c66b..69c1716 100644
--- a/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h
+++ b/ppapi/native_client/src/trusted/plugin/sel_ldr_launcher_chrome.h
@@ -20,6 +20,7 @@
                      bool enable_ppapi_dev,
                      bool enable_dyncode_syscalls,
                      bool enable_exception_handling,
+                     bool enable_crash_throttling,
                      nacl::string* error_message);
 };
 
diff --git a/ppapi/native_client/src/trusted/plugin/service_runtime.cc b/ppapi/native_client/src/trusted/plugin/service_runtime.cc
index 2b43b2e..fd845a5 100644
--- a/ppapi/native_client/src/trusted/plugin/service_runtime.cc
+++ b/ppapi/native_client/src/trusted/plugin/service_runtime.cc
@@ -337,29 +337,19 @@
     NaClLog(4,
             "OpenManifestEntry_MainThreadContinuation: "
             "pulling down and translating.\n");
-    if (plugin_->nacl_interface()->IsPnaclEnabled()) {
-      pp::CompletionCallback translate_callback =
-          WeakRefNewCallback(
-              anchor_,
-              this,
-              &PluginReverseInterface::BitcodeTranslate_MainThreadContinuation,
-              open_cont);
-      // Will always call the callback on success or failure.
-      pnacl_coordinator_.reset(
-          PnaclCoordinator::BitcodeToNative(plugin_,
-                                            mapped_url,
-                                            pnacl_options,
-                                            translate_callback));
-    } else {
-      nacl::MutexLocker take(&mu_);
-      *p->op_complete_ptr = true;  // done...
-      p->file_info->desc = -1;  // but failed.
-      p->error_info->SetReport(ERROR_PNACL_NOT_ENABLED,
-                               "ServiceRuntime: GetPnaclFd failed -- pnacl not "
-                               "enabled with --enable-pnacl.");
-      NaClXCondVarBroadcast(&cv_);
-      return;
-    }
+    CHECK(plugin_->nacl_interface()->IsPnaclEnabled());
+    pp::CompletionCallback translate_callback =
+        WeakRefNewCallback(
+            anchor_,
+            this,
+            &PluginReverseInterface::BitcodeTranslate_MainThreadContinuation,
+            open_cont);
+    // Will always call the callback on success or failure.
+    pnacl_coordinator_.reset(
+        PnaclCoordinator::BitcodeToNative(plugin_,
+                                          mapped_url,
+                                          pnacl_options,
+                                          translate_callback));
   }
   // p is deleted automatically
 }
@@ -736,6 +726,7 @@
                                        params.enable_dev_interfaces,
                                        params.enable_dyncode_syscalls,
                                        params.enable_exception_handling,
+                                       params.enable_crash_throttling,
                                        &error_message);
   if (!started) {
     NaClLog(LOG_ERROR, "ServiceRuntime::Start (start failed)\n");
diff --git a/ppapi/native_client/src/trusted/plugin/service_runtime.h b/ppapi/native_client/src/trusted/plugin/service_runtime.h
index ee97710..e7ebbbc 100644
--- a/ppapi/native_client/src/trusted/plugin/service_runtime.h
+++ b/ppapi/native_client/src/trusted/plugin/service_runtime.h
@@ -56,14 +56,16 @@
                     bool uses_ppapi,
                     bool enable_dev_interfaces,
                     bool enable_dyncode_syscalls,
-                    bool enable_exception_handling)
+                    bool enable_exception_handling,
+                    bool enable_crash_throttling)
       : url(url),
         error_info(error_info),
         uses_irt(uses_irt),
         uses_ppapi(uses_ppapi),
         enable_dev_interfaces(enable_dev_interfaces),
         enable_dyncode_syscalls(enable_dyncode_syscalls),
-        enable_exception_handling(enable_exception_handling) {
+        enable_exception_handling(enable_exception_handling),
+        enable_crash_throttling(enable_crash_throttling) {
   }
   nacl::string url;
   ErrorInfo* error_info;
@@ -72,6 +74,7 @@
   bool enable_dev_interfaces;
   bool enable_dyncode_syscalls;
   bool enable_exception_handling;
+  bool enable_crash_throttling;
 };
 
 // Callback resources are essentially our continuation state.
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 8bb17f7..93ccb85 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
@@ -95,7 +95,6 @@
 #include "ppapi/c/private/ppb_flash_menu.h"
 #include "ppapi/c/private/ppb_flash_message_loop.h"
 #include "ppapi/c/private/ppb_flash_print.h"
-#include "ppapi/c/private/ppb_gpu_blacklist_private.h"
 #include "ppapi/c/private/ppb_host_resolver_private.h"
 #include "ppapi/c/private/ppb_instance_private.h"
 #include "ppapi/c/private/ppb_nacl_private.h"
@@ -2752,8 +2751,6 @@
 
 /* Not generating wrapper methods for PPB_Flash_Print_1_0 */
 
-/* Not generating wrapper methods for PPB_GpuBlacklist_Private_0_2 */
-
 /* Begin wrapper methods for PPB_HostResolver_Private_0_1 */
 
 static PP_Resource Pnacl_M19_PPB_HostResolver_Private_Create(PP_Instance instance) {
@@ -2809,9 +2806,9 @@
 
 /* Begin wrapper methods for PPB_NaCl_Private_1_0 */
 
-static PP_ExternalPluginResult Pnacl_M13_PPB_NaCl_Private_LaunchSelLdr(PP_Instance instance, const char* alleged_url, PP_Bool uses_irt, PP_Bool uses_ppapi, PP_Bool enable_ppapi_dev, PP_Bool enable_dyncode_syscalls, PP_Bool enable_exception_handling, void* imc_handle, struct PP_Var* error_message) {
+static PP_ExternalPluginResult Pnacl_M13_PPB_NaCl_Private_LaunchSelLdr(PP_Instance instance, const char* alleged_url, PP_Bool uses_irt, PP_Bool uses_ppapi, PP_Bool enable_ppapi_dev, PP_Bool enable_dyncode_syscalls, PP_Bool enable_exception_handling, PP_Bool enable_crash_throttling, void* imc_handle, struct PP_Var* error_message) {
   const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface;
-  return iface->LaunchSelLdr(instance, alleged_url, uses_irt, uses_ppapi, enable_ppapi_dev, enable_dyncode_syscalls, enable_exception_handling, imc_handle, error_message);
+  return iface->LaunchSelLdr(instance, alleged_url, uses_irt, uses_ppapi, enable_ppapi_dev, enable_dyncode_syscalls, enable_exception_handling, enable_crash_throttling, imc_handle, error_message);
 }
 
 static PP_ExternalPluginResult Pnacl_M13_PPB_NaCl_Private_StartPpapiProxy(PP_Instance instance) {
@@ -4637,8 +4634,6 @@
 
 /* Not generating wrapper interface for PPB_Flash_Print_1_0 */
 
-/* Not generating wrapper interface for PPB_GpuBlacklist_Private_0_2 */
-
 struct PPB_HostResolver_Private_0_1 Pnacl_Wrappers_PPB_HostResolver_Private_0_1 = {
     .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M19_PPB_HostResolver_Private_Create,
     .IsHostResolver = (PP_Bool (*)(PP_Resource resource))&Pnacl_M19_PPB_HostResolver_Private_IsHostResolver,
@@ -4655,7 +4650,7 @@
 };
 
 struct PPB_NaCl_Private_1_0 Pnacl_Wrappers_PPB_NaCl_Private_1_0 = {
-    .LaunchSelLdr = (PP_ExternalPluginResult (*)(PP_Instance instance, const char* alleged_url, PP_Bool uses_irt, PP_Bool uses_ppapi, PP_Bool enable_ppapi_dev, PP_Bool enable_dyncode_syscalls, PP_Bool enable_exception_handling, void* imc_handle, struct PP_Var* error_message))&Pnacl_M13_PPB_NaCl_Private_LaunchSelLdr,
+    .LaunchSelLdr = (PP_ExternalPluginResult (*)(PP_Instance instance, const char* alleged_url, PP_Bool uses_irt, PP_Bool uses_ppapi, PP_Bool enable_ppapi_dev, PP_Bool enable_dyncode_syscalls, PP_Bool enable_exception_handling, PP_Bool enable_crash_throttling, void* imc_handle, struct PP_Var* error_message))&Pnacl_M13_PPB_NaCl_Private_LaunchSelLdr,
     .StartPpapiProxy = (PP_ExternalPluginResult (*)(PP_Instance instance))&Pnacl_M13_PPB_NaCl_Private_StartPpapiProxy,
     .UrandomFD = (int32_t (*)(void))&Pnacl_M13_PPB_NaCl_Private_UrandomFD,
     .Are3DInterfacesDisabled = (PP_Bool (*)(void))&Pnacl_M13_PPB_NaCl_Private_Are3DInterfacesDisabled,
diff --git a/ppapi/native_client/tools/browser_tester/browser_tester.py b/ppapi/native_client/tools/browser_tester/browser_tester.py
index 513a091..ab24d0c 100755
--- a/ppapi/native_client/tools/browser_tester/browser_tester.py
+++ b/ppapi/native_client/tools/browser_tester/browser_tester.py
@@ -138,6 +138,10 @@
   parser.add_option('--enable_crash_reporter', dest='enable_crash_reporter',
                     action='store_true', default=False,
                     help='Force crash reporting on.')
+  parser.add_option('--enable_sockets', dest='enable_sockets',
+                    action='store_true', default=False,
+                    help='Pass --allow-nacl-socket-api=<host> to Chrome, where '
+                    '<host> is the name of the browser tester\'s web server.')
 
   return parser
 
@@ -242,7 +246,7 @@
   full_url = 'http://%s:%d/%s' % (host, port, url)
   if len(options.test_args) > 0:
     full_url += '?' + urllib.urlencode(options.test_args)
-  browser.Run(full_url, port)
+  browser.Run(full_url, host, port)
   server.TestingBegun(0.125)
 
   # In Python 2.5, server.handle_request may block indefinitely.  Serving pages
@@ -308,6 +312,13 @@
           DumpNetLog(browser.NetLogName())
     except Exception:
       listener.ever_failed = 1
+    # Try to let the browser clean itself up normally before killing it.
+    sys.stdout.write('##################### Terminating the browser\n')
+    browser.WaitForProcessDeath()
+    if browser.IsRunning():
+      sys.stdout.write('##################### TERM failed, KILLING\n')
+    # Always call Cleanup; it kills the process, but also removes the
+    # user-data-dir.
     browser.Cleanup()
     # We avoid calling server.server_close() here because it causes
     # the HTTP server thread to exit uncleanly with an EBADF error,
diff --git a/ppapi/native_client/tools/browser_tester/browsertester/browserlauncher.py b/ppapi/native_client/tools/browser_tester/browsertester/browserlauncher.py
index 256a1cb..5631690 100755
--- a/ppapi/native_client/tools/browser_tester/browsertester/browserlauncher.py
+++ b/ppapi/native_client/tools/browser_tester/browsertester/browserlauncher.py
@@ -9,6 +9,7 @@
 import sys
 import tempfile
 import time
+import urlparse
 
 import browserprocess
 
@@ -105,7 +106,7 @@
   def CreateProfile(self):
     raise NotImplementedError
 
-  def MakeCmd(self, url):
+  def MakeCmd(self, url, host, port):
     raise NotImplementedError
 
   def CreateToolLogDir(self):
@@ -205,12 +206,12 @@
   def GetReturnCode(self):
     return self.browser_process.GetReturnCode()
 
-  def Run(self, url, port):
+  def Run(self, url, host, port):
     self.binary = EscapeSpaces(self.FindBinary())
     self.profile = self.CreateProfile()
     if self.options.tool is not None:
       self.tool_log_dir = self.CreateToolLogDir()
-    cmd = self.MakeCmd(url, port)
+    cmd = self.MakeCmd(url, host, port)
     self.Launch(cmd, MakeEnv(self.options))
 
 
@@ -262,7 +263,7 @@
   def NetLogName(self):
     return os.path.join(self.profile, 'netlog.json')
 
-  def MakeCmd(self, url, port):
+  def MakeCmd(self, url, host, port):
     cmd = [self.binary,
             # Note that we do not use "--enable-logging" here because
             # it actually turns off logging to the Buildbot logs on
@@ -279,6 +280,7 @@
             '--no-default-browser-check',
             '--log-level=1',
             '--safebrowsing-disable-auto-update',
+            '--disable-default-apps',
             # Suppress metrics reporting.  This prevents misconfigured bots,
             # people testing at their desktop, etc from poisoning the UMA data.
             '--metrics-recording-only',
@@ -335,6 +337,8 @@
              '--log-file=%s/log.%%p' % (self.tool_log_dir,)] + cmd
     elif self.options.tool != None:
       raise LaunchFailure('Invalid tool name "%s"' % (self.options.tool,))
+    if self.options.enable_sockets:
+      cmd.append('--allow-nacl-socket-api=%s' % host)
     cmd.extend(self.options.browser_flags)
     cmd.append(url)
     return cmd
diff --git a/ppapi/native_client/tools/browser_tester/browsertester/browserprocess.py b/ppapi/native_client/tools/browser_tester/browsertester/browserprocess.py
index bca1734..e10e6b5 100755
--- a/ppapi/native_client/tools/browser_tester/browsertester/browserprocess.py
+++ b/ppapi/native_client/tools/browser_tester/browsertester/browserprocess.py
@@ -21,7 +21,13 @@
     return self.handle.poll() is None
 
   def Wait(self, wait_steps, sleep_time):
-    self.term()
+    try:
+      self.term()
+    except Exception:
+      # Terminating the handle can raise an exception. There is likely no point
+      # in waiting if the termination didn't succeed.
+      return
+
     i = 0
     # subprocess.wait() doesn't have a timeout, unfortunately.
     while self.IsRunning() and i < wait_steps:
diff --git a/ppapi/ppapi_ipc_untrusted.gyp b/ppapi/ppapi_ipc_untrusted.gyp
index 9b0b678..9e13867 100644
--- a/ppapi/ppapi_ipc_untrusted.gyp
+++ b/ppapi/ppapi_ipc_untrusted.gyp
@@ -22,7 +22,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libppapi_ipc_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'include_dirs': [
diff --git a/ppapi/ppapi_proxy_untrusted.gyp b/ppapi/ppapi_proxy_untrusted.gyp
index 727fbb5..35dff87 100644
--- a/ppapi/ppapi_proxy_untrusted.gyp
+++ b/ppapi/ppapi_proxy_untrusted.gyp
@@ -21,7 +21,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libppapi_proxy_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'include_dirs': [
diff --git a/ppapi/ppapi_shared_untrusted.gyp b/ppapi/ppapi_shared_untrusted.gyp
index 4043c3a..453e711 100644
--- a/ppapi/ppapi_shared_untrusted.gyp
+++ b/ppapi/ppapi_shared_untrusted.gyp
@@ -22,7 +22,7 @@
             'nacl_untrusted_build': 1,
             'nlib_target': 'libppapi_shared_untrusted.a',
             'build_glibc': 0,
-            'build_newlib': 1,
+            'build_newlib': 0,
             'build_irt': 1,
           },
           'include_dirs': [
diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi
index c6f7b01..209434e 100644
--- a/ppapi/ppapi_sources.gypi
+++ b/ppapi/ppapi_sources.gypi
@@ -110,7 +110,6 @@
       'c/private/ppb_flash_fullscreen.h',
       'c/private/ppb_flash_menu.h',
       'c/private/ppb_flash_message_loop.h',
-      'c/private/ppb_gpu_blacklist_private.h',
       'c/private/ppb_host_resolver_private.h',
       'c/private/ppb_instance_private.h',
       'c/private/ppb_nacl_private.h',
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index 3a1ac87..cf755c1 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -219,9 +219,6 @@
           ['os_posix==1 and OS!="mac"', {
             'cflags': ['-fvisibility=hidden'],
             'type': 'shared_library',
-            # -gstabs, used in the official builds, causes an ICE. Simply remove
-            # it.
-            'cflags!': ['-gstabs'],
           }],
           ['OS=="win"', {
             'type': 'shared_library',
diff --git a/ppapi/proxy/plugin_resource_tracker.cc b/ppapi/proxy/plugin_resource_tracker.cc
index 12e9d3f..86cbf7c 100644
--- a/ppapi/proxy/plugin_resource_tracker.cc
+++ b/ppapi/proxy/plugin_resource_tracker.cc
@@ -18,6 +18,7 @@
 namespace proxy {
 
 PluginResourceTracker::PluginResourceTracker() : ResourceTracker(THREAD_SAFE) {
+  UseOddResourceValueInDebugMode();
 }
 
 PluginResourceTracker::~PluginResourceTracker() {
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 3767f8f..a377193 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -1275,27 +1275,27 @@
     IPC::Message /* reply_msg */)
 
 // This message is sent from the renderer to the browser when it wants to create
-// a ResourceHost in the browser. It contains the process ID of the plugin and
+// ResourceHosts in the browser. It contains the process ID of the plugin and
 // the instance of the plugin for which to create the resource for. params
 // contains the sequence number for the message to track the response.
-// The nested message is a ResourceHost creation message.
+// The nested messages are ResourceHost creation messages.
 IPC_MESSAGE_CONTROL5(
-    PpapiHostMsg_CreateResourceHostFromHost,
+    PpapiHostMsg_CreateResourceHostsFromHost,
     int /* routing_id */,
     int /* child_process_id */,
     ppapi::proxy::ResourceMessageCallParams /* params */,
     PP_Instance /* instance */,
-    IPC::Message /* nested_msg */)
+    std::vector<IPC::Message> /* nested_msgs */)
 
-// This message is sent from the browser to the renderer when it has created a
-// ResourceHost for the renderer. It contains the sequence number that was sent
-// in the request and the ID of the pending ResourceHost which was created in
-// the browser. This ID is only useful for the plugin which can attach to the
-// ResourceHost in the browser.
+// This message is sent from the browser to the renderer when it has created
+// ResourceHosts for the renderer. It contains the sequence number that was sent
+// in the request and the IDs of the pending ResourceHosts which were created in
+// the browser. These IDs are only useful for the plugin which can attach to the
+// ResourceHosts in the browser.
 IPC_MESSAGE_ROUTED2(
-    PpapiHostMsg_CreateResourceHostFromHostReply,
+    PpapiHostMsg_CreateResourceHostsFromHostReply,
     int32_t /* sequence */,
-    int /* pending_host_id */)
+    std::vector<int> /* pending_host_ids */)
 
 //-----------------------------------------------------------------------------
 // Messages for resources using call/reply above.
diff --git a/ppapi/shared_impl/id_assignment.h b/ppapi/shared_impl/id_assignment.h
index 039e7fe..3bacac3 100644
--- a/ppapi/shared_impl/id_assignment.h
+++ b/ppapi/shared_impl/id_assignment.h
@@ -26,7 +26,7 @@
 
 extern const int32 kMaxPPId;
 
-// The most significant bits are the type, the rest are the value.
+// The least significant bits are the type, the rest are the value.
 template <typename T> inline T MakeTypedId(T value, PPIdType type) {
   return (value << kPPIdTypeBits) | static_cast<T>(type);
 }
diff --git a/ppapi/shared_impl/ppb_graphics_3d_shared.cc b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
index 948905d..e24a13c 100644
--- a/ppapi/shared_impl/ppb_graphics_3d_shared.cc
+++ b/ppapi/shared_impl/ppb_graphics_3d_shared.cc
@@ -135,7 +135,8 @@
   if (!gles2_impl_->Initialize(
       transfer_buffer_size,
       kMinTransferBufferSize,
-      std::max(kMaxTransferBufferSize, transfer_buffer_size))) {
+      std::max(kMaxTransferBufferSize, transfer_buffer_size),
+      gpu::gles2::GLES2Implementation::kNoLimit)) {
     return false;
   }
 
diff --git a/ppapi/shared_impl/ppb_image_data_shared.cc b/ppapi/shared_impl/ppb_image_data_shared.cc
index 4001d6f..50751a0 100644
--- a/ppapi/shared_impl/ppb_image_data_shared.cc
+++ b/ppapi/shared_impl/ppb_image_data_shared.cc
@@ -26,12 +26,7 @@
   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.
+  return PP_IMAGEDATAFORMAT_BGRA_PREMUL;
 #endif
 }
 
diff --git a/ppapi/shared_impl/resource_tracker.cc b/ppapi/shared_impl/resource_tracker.cc
index 5d7d01a..36aa2e1 100644
--- a/ppapi/shared_impl/resource_tracker.cc
+++ b/ppapi/shared_impl/resource_tracker.cc
@@ -44,6 +44,9 @@
   CheckThreadingPreconditions();
   DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
       << res << " is not a PP_Resource.";
+
+  DCHECK(CanOperateOnResource(res));
+
   ResourceMap::iterator i = live_resources_.find(res);
   if (i == live_resources_.end())
     return;
@@ -66,6 +69,9 @@
   CheckThreadingPreconditions();
   DLOG_IF(ERROR, !CheckIdType(res, PP_ID_TYPE_RESOURCE))
       << res << " is not a PP_Resource.";
+
+  DCHECK(CanOperateOnResource(res));
+
   ResourceMap::iterator i = live_resources_.find(res);
   if (i == live_resources_.end())
     return;
@@ -166,15 +172,23 @@
   return static_cast<int>(found->second->resources.size());
 }
 
+void ResourceTracker::UseOddResourceValueInDebugMode() {
+#if !defined(NDEBUG)
+  DCHECK_EQ(0, last_resource_value_);
+
+  ++last_resource_value_;
+#endif
+}
+
 PP_Resource ResourceTracker::AddResource(Resource* object) {
   CheckThreadingPreconditions();
   // If the plugin manages to create too many resources, don't do crazy stuff.
-  if (last_resource_value_ == kMaxPPId)
+  if (last_resource_value_ >= kMaxPPId)
     return 0;
 
   // Allocate an ID. Note there's a rare error condition below that means we
   // could end up not using |new_id|, but that's harmless.
-  PP_Resource new_id = MakeTypedId(++last_resource_value_, PP_ID_TYPE_RESOURCE);
+  PP_Resource new_id = MakeTypedId(GetNextResourceValue(), PP_ID_TYPE_RESOURCE);
 
   // Some objects have a 0 instance, meaning they aren't associated with any
   // instance, so they won't be in |instance_map_|. This is (as of this writing)
@@ -229,4 +243,31 @@
   object->NotifyLastPluginRefWasDeleted();
 }
 
+int32 ResourceTracker::GetNextResourceValue() {
+#if defined(NDEBUG)
+  return ++last_resource_value_;
+#else
+  // In debug mode, the least significant bit indicates which side (renderer
+  // or plugin process) created the resource. Increment by 2 so it's always the
+  // same.
+  last_resource_value_ += 2;
+  return last_resource_value_;
+#endif
+}
+
+bool ResourceTracker::CanOperateOnResource(PP_Resource res) {
+#if defined(NDEBUG)
+  return true;
+#else
+  // The invalid PP_Resource value could appear at both sides.
+  if (res == 0)
+    return true;
+
+  // Skipping the type bits, the least significant bit of |res| should be the
+  // same as that of |last_resource_value_|.
+  return ((res >> kPPIdTypeBits) & 1) == (last_resource_value_ & 1);
+#endif
+
+}
+
 }  // namespace ppapi
diff --git a/ppapi/shared_impl/resource_tracker.h b/ppapi/shared_impl/resource_tracker.h
index 2ba43b8..ee93376 100644
--- a/ppapi/shared_impl/resource_tracker.h
+++ b/ppapi/shared_impl/resource_tracker.h
@@ -36,7 +36,14 @@
   // count of the resource is unaffected.
   Resource* GetResource(PP_Resource res) const;
 
+  // Takes a reference on the given resource.
+  // Do not call this method on on the host side for resources backed by a
+  // ResourceHost.
   void AddRefResource(PP_Resource res);
+
+  // Releases a reference on the given resource.
+  // Do not call this method on on the host side for resources backed by a
+  // ResourceHost.
   void ReleaseResource(PP_Resource res);
 
   // Releases a reference on the given resource once the message loop returns.
@@ -63,6 +70,14 @@
   // plugin side, make sure we have the proxy lock.
   void CheckThreadingPreconditions() const;
 
+  // This method is called by PluginResourceTracker's constructor so that in
+  // debug mode PP_Resources from the plugin process always have odd values
+  // (ignoring the type bits), while PP_Resources from the renderer process have
+  // even values.
+  // This allows us to check that resource refs aren't added or released on the
+  // wrong side.
+  void UseOddResourceValueInDebugMode();
+
   // Adds the given resource to the tracker, associating it with the instance
   // stored in the resource object. The new resource ID is returned, and the
   // resource will have 0 plugin refcount. This is called by the resource
@@ -80,6 +95,11 @@
   // cancels pending callbacks for the resource.
   void LastPluginRefWasDeleted(Resource* object);
 
+  int32 GetNextResourceValue();
+
+  // In debug mode, checks whether |res| comes from the same resource tracker.
+  bool CanOperateOnResource(PP_Resource res);
+
   typedef std::set<PP_Resource> ResourceSet;
 
   struct InstanceData {
diff --git a/ppapi/tests/all_c_includes.h b/ppapi/tests/all_c_includes.h
index 5950c4e..54130c5 100644
--- a/ppapi/tests/all_c_includes.h
+++ b/ppapi/tests/all_c_includes.h
@@ -111,7 +111,6 @@
 #include "ppapi/c/private/ppb_flash_font_file.h"
 #include "ppapi/c/private/ppb_flash_menu.h"
 #include "ppapi/c/private/ppb_flash_message_loop.h"
-#include "ppapi/c/private/ppb_gpu_blacklist_private.h"
 #include "ppapi/c/private/ppb_host_resolver_private.h"
 #include "ppapi/c/private/ppb_instance_private.h"
 #include "ppapi/c/private/ppb_nacl_private.h"
diff --git a/ppapi/tests/test_case.cc b/ppapi/tests/test_case.cc
index 6f61fc5..9b565be 100644
--- a/ppapi/tests/test_case.cc
+++ b/ppapi/tests/test_case.cc
@@ -105,7 +105,6 @@
   // GYP_DEFINES='branding=Chrome buildtype=Official target_arch=x64'
   //     gclient runhooks
   // make -k -j4 BUILDTYPE=Release ppapi_tests
-  std::string s;
 
   std::ostringstream output;
   output << "Failure in " << file << "(" << line << "): " << cmd;
diff --git a/ppapi/tests/test_char_set.cc b/ppapi/tests/test_char_set.cc
index 5056c2c..de998d0 100644
--- a/ppapi/tests/test_char_set.cc
+++ b/ppapi/tests/test_char_set.cc
@@ -187,6 +187,7 @@
       &utf16[0], static_cast<uint32_t>(utf16.size()),
       "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE,
       &output_buffer[0], &utf8result_len);
+  ASSERT_TRUE(result == PP_TRUE);
   ASSERT_TRUE(utf8result_len == 3);
   output_buffer.resize(utf8result_len);
   ASSERT_TRUE(output_buffer == "h?i");
@@ -201,6 +202,7 @@
       &utf16[0], static_cast<uint32_t>(utf16.size()),
       "latin1", PP_CHARSET_TRUSTED_CONVERSIONERROR_SUBSTITUTE,
       &output_buffer[0], &utf8result_len);
+  ASSERT_TRUE(result == PP_TRUE);
   ASSERT_TRUE(utf8result_len == 2);
   ASSERT_TRUE(output_buffer[0] == '?' && output_buffer[1] == 'A');
 
diff --git a/ppapi/thunk/interfaces_legacy.h b/ppapi/thunk/interfaces_legacy.h
index 6e53ea4..6051824 100644
--- a/ppapi/thunk/interfaces_legacy.h
+++ b/ppapi/thunk/interfaces_legacy.h
@@ -10,8 +10,6 @@
 LEGACY_IFACE(PPB_INSTANCE_PRIVATE_INTERFACE_0_1,
              ::ppapi::thunk::GetPPB_Instance_Private_0_1_Thunk())
 LEGACY_IFACE(PPB_CORE_INTERFACE_1_0, &core_interface)
-LEGACY_IFACE(PPB_GPUBLACKLIST_PRIVATE_INTERFACE,
-             PPB_GpuBlacklist_Private_Impl::GetInterface())
 LEGACY_IFACE(PPB_OPENGLES2_INTERFACE,
              ::ppapi::PPB_OpenGLES2_Shared::GetInterface())
 LEGACY_IFACE(PPB_OPENGLES2_INSTANCEDARRAYS_INTERFACE,
diff --git a/printing/image_android.cc b/printing/image_android.cc
new file mode 100644
index 0000000..544cf07
--- /dev/null
+++ b/printing/image_android.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 "printing/image.h"
+
+namespace printing {
+
+bool Image::LoadMetafile(const Metafile& metafile) {
+  return false;
+}
+
+}  // namespace printing
diff --git a/printing/image_linux.cc b/printing/image_linux.cc
index 3968cfd..d89c4e9 100644
--- a/printing/image_linux.cc
+++ b/printing/image_linux.cc
@@ -4,8 +4,6 @@
 
 #include "printing/image.h"
 
-#include "base/logging.h"
-
 namespace printing {
 
 bool Image::LoadMetafile(const Metafile& metafile) {
diff --git a/printing/metafile.h b/printing/metafile.h
index ca0901b..e331069 100644
--- a/printing/metafile.h
+++ b/printing/metafile.h
@@ -29,7 +29,7 @@
 
 class SkDevice;
 
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 namespace base {
 struct FileDescriptor;
 }
@@ -155,12 +155,12 @@
                           gfx::NativeDrawingContext context,
                           const CGRect rect,
                           const MacRenderPageParams& params) const = 0;
-#elif defined(OS_CHROMEOS)
+#elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
   // Saves the underlying data to the file associated with fd. This function
   // should ONLY be called after the metafile is closed.
   // Returns true if writing succeeded.
   virtual bool SaveToFD(const base::FileDescriptor& fd) const = 0;
-#endif  // if defined(OS_CHROMEOS)
+#endif  // if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 };
 
 }  // namespace printing
diff --git a/printing/pdf_metafile_skia.cc b/printing/pdf_metafile_skia.cc
index 3326a1d..31c8c74 100644
--- a/printing/pdf_metafile_skia.cc
+++ b/printing/pdf_metafile_skia.cc
@@ -192,7 +192,7 @@
 }
 #endif
 
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 bool PdfMetafileSkia::SaveToFD(const base::FileDescriptor& fd) const {
   DCHECK_GT(data_->pdf_stream_.getOffset(), 0U);
 
diff --git a/printing/pdf_metafile_skia.h b/printing/pdf_metafile_skia.h
index 33be6d2..c6f1971 100644
--- a/printing/pdf_metafile_skia.h
+++ b/printing/pdf_metafile_skia.h
@@ -63,9 +63,9 @@
                           const MacRenderPageParams& params) const OVERRIDE;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
   virtual bool SaveToFD(const base::FileDescriptor& fd) const OVERRIDE;
-#endif  // if defined(OS_CHROMEOS)
+#endif  // if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 
   // Return a new metafile containing just the current page in draft mode.
   PdfMetafileSkia* GetMetafileForCurrentPage();
diff --git a/printing/print_settings_initializer.cc b/printing/print_settings_initializer.cc
index 80fa636..867f4dc 100644
--- a/printing/print_settings_initializer.cc
+++ b/printing/print_settings_initializer.cc
@@ -17,6 +17,7 @@
 #include "printing/print_settings.h"
 #include "printing/units.h"
 #include "ui/base/text/text_elider.h"
+#include "ui/gfx/font.h"
 #include "url/gurl.h"
 
 using base::DictionaryValue;
diff --git a/printing/printed_document.cc b/printing/printed_document.cc
index 6e912a1..59cc385 100644
--- a/printing/printed_document.cc
+++ b/printing/printed_document.cc
@@ -225,8 +225,8 @@
 PrintedDocument::Immutable::~Immutable() {
 }
 
-#if defined(OS_POSIX) && defined(USE_AURA)
-// This function is not used on aura linux/chromeos.
+#if (defined(OS_POSIX) && defined(USE_AURA)) || defined(OS_ANDROID)
+// This function is not used on aura linux/chromeos or android.
 void PrintedDocument::RenderPrintedPage(const PrintedPage& page,
                                         PrintingContext* context) const {
 }
diff --git a/printing/printing.gyp b/printing/printing.gyp
index b3bbf2b..890e5bf 100644
--- a/printing/printing.gyp
+++ b/printing/printing.gyp
@@ -37,6 +37,7 @@
         'emf_win.cc',
         'emf_win.h',
         'image.cc',
+        'image_android.cc',
         'image_linux.cc',
         'image_mac.cc',
         'image_win.cc',
@@ -228,6 +229,11 @@
             'printing_context_gtk.h',
           ],
         }],
+        ['OS=="android"', {
+          'sources': [
+            'printing_context_android.h',
+          ],
+        }],
       ],
     },
     {
diff --git a/printing/printing_context_android.h b/printing/printing_context_android.h
new file mode 100644
index 0000000..1803825
--- /dev/null
+++ b/printing/printing_context_android.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 PRINTING_PRINTING_CONTEXT_ANDROID_H_
+#define PRINTING_PRINTING_CONTEXT_ANDROID_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "printing/printing_context.h"
+
+namespace printing {
+
+// Android subclass of PrintingContext.  The implementation for this header file
+// resides in Chrome for Android repository.  This class communicates with the
+// Java side through JNI.
+class PRINTING_EXPORT PrintingContextAndroid : public PrintingContext {
+ public:
+  explicit PrintingContextAndroid(const std::string& app_locale);
+  virtual ~PrintingContextAndroid();
+
+  // Called when the page is successfully written to a PDF using the file
+  // descriptor specified, or when the printing operation failed.
+  static void PdfWritingDone(int fd, bool success);
+
+  // Called from Java, when printing settings from the user are ready or the
+  // printing operation is canceled.
+  void AskUserForSettingsReply(JNIEnv* env, jobject obj, jboolean success);
+
+  // PrintingContext implementation.
+  virtual void AskUserForSettings(
+      gfx::NativeView parent_view,
+      int max_pages,
+      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 InitWithSettings(const PrintSettings& settings) OVERRIDE;
+  virtual Result NewDocument(const string16& document_name) OVERRIDE;
+  virtual Result NewPage() OVERRIDE;
+  virtual Result PageDone() OVERRIDE;
+  virtual Result DocumentDone() OVERRIDE;
+  virtual void Cancel() OVERRIDE;
+  virtual void ReleaseContext() OVERRIDE;
+  virtual gfx::NativeDrawingContext context() const OVERRIDE;
+
+  // Registers JNI bindings for RegisterContext.
+  static bool RegisterPrintingContext(JNIEnv* env);
+
+ private:
+  base::android::ScopedJavaGlobalRef<jobject> j_printing_context_;
+
+  // The callback from AskUserForSettings to be called when the settings are
+  // ready on the Java side
+  PrintSettingsCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrintingContextAndroid);
+};
+
+}  // namespace printing
+
+#endif  // PRINTING_PRINTING_CONTEXT_ANDROID_H_
+
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 039bcb9..4508e58 100644
--- a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
@@ -186,7 +186,7 @@
     }
 
     /** Prompts the user to enter a PIN. */
-    private static void displayAuthenticationPrompt() {
+    private static void displayAuthenticationPrompt(boolean pairingSupported) {
         AlertDialog.Builder pinPrompt = new AlertDialog.Builder(sContext);
         pinPrompt.setTitle(sContext.getString(R.string.pin_entry_title));
         pinPrompt.setMessage(sContext.getString(R.string.pin_entry_message));
@@ -195,16 +195,21 @@
         final View pinEntry = sContext.getLayoutInflater().inflate(R.layout.pin_dialog, null);
         pinPrompt.setView(pinEntry);
 
+        final TextView pinTextView = (TextView)pinEntry.findViewById(R.id.pin_dialog_text);
+        final CheckBox pinCheckBox = (CheckBox)pinEntry.findViewById(R.id.pin_dialog_check);
+
+        if (!pairingSupported) {
+            pinCheckBox.setChecked(false);
+            pinCheckBox.setVisibility(View.GONE);
+        }
+
         pinPrompt.setPositiveButton(
                 R.string.pin_entry_connect, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         Log.i("jniiface", "User provided a PIN code");
-                        authenticationResponse(String.valueOf(
-                                ((TextView)
-                                        pinEntry.findViewById(R.id.pin_dialog_text)).getText()),
-                                ((CheckBox)
-                                        pinEntry.findViewById(R.id.pin_dialog_check)).isChecked());
+                        authenticationResponse(String.valueOf(pinTextView.getText()),
+                                               pinCheckBox.isChecked());
                     }
                 });
 
@@ -222,7 +227,7 @@
 
         final AlertDialog pinDialog = pinPrompt.create();
 
-        ((TextView)pinEntry.findViewById(R.id.pin_dialog_text)).setOnEditorActionListener(
+        pinTextView.setOnEditorActionListener(
                 new TextView.OnEditorActionListener() {
                     @Override
                     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
diff --git a/remoting/base/url_request_context.cc b/remoting/base/url_request_context.cc
index 470f153..4e80344 100644
--- a/remoting/base/url_request_context.cc
+++ b/remoting/base/url_request_context.cc
@@ -43,10 +43,7 @@
 };
 
 net::ProxyConfigService* CreateSystemProxyConfigService(
-    base::SingleThreadTaskRunner* ui_task_runner,
     base::SingleThreadTaskRunner* io_thread_task_runner) {
-  DCHECK(ui_task_runner->BelongsToCurrentThread());
-
 #if defined(OS_WIN)
   return new net::ProxyConfigServiceWin();
 #elif defined(OS_MACOSX)
@@ -115,11 +112,10 @@
 }
 
 URLRequestContextGetter::URLRequestContextGetter(
-    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
     : network_task_runner_(network_task_runner) {
   proxy_config_service_.reset(CreateSystemProxyConfigService(
-      ui_task_runner.get(), network_task_runner_.get()));
+      network_task_runner_.get()));
 }
 
 net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext() {
diff --git a/remoting/base/url_request_context.h b/remoting/base/url_request_context.h
index ecdb07a..6ce2d57 100644
--- a/remoting/base/url_request_context.h
+++ b/remoting/base/url_request_context.h
@@ -40,7 +40,6 @@
 class URLRequestContextGetter : public net::URLRequestContextGetter {
  public:
   URLRequestContextGetter(
-      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> network_task_runner);
 
   // Overridden from net::URLRequestContextGetter:
diff --git a/remoting/client/client_config.h b/remoting/client/client_config.h
index 7270abd..d56d0be 100644
--- a/remoting/client/client_config.h
+++ b/remoting/client/client_config.h
@@ -18,8 +18,6 @@
   ClientConfig();
   ~ClientConfig();
 
-  std::string local_jid;
-
   std::string host_jid;
   std::string host_public_key;
 
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc
index 067e954..7e45f7c 100644
--- a/remoting/client/jni/chromoting_jni_instance.cc
+++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "net/socket/client_socket_factory.h"
 #include "remoting/client/audio_player.h"
 #include "remoting/client/jni/android_keymap.h"
 #include "remoting/client/jni/chromoting_jni_runtime.h"
@@ -28,16 +29,37 @@
                                              const char* pairing_id,
                                              const char* pairing_secret)
     : jni_runtime_(jni_runtime),
-      username_(username),
-      auth_token_(auth_token),
-      host_jid_(host_jid),
       host_id_(host_id),
-      host_pubkey_(host_pubkey),
-      pairing_id_(pairing_id),
-      pairing_secret_(pairing_secret),
       create_pairing_(false) {
   DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
 
+  // Intialize XMPP config.
+  xmpp_config_.host = kXmppServer;
+  xmpp_config_.port = kXmppPort;
+  xmpp_config_.use_tls = kXmppUseTls;
+  xmpp_config_.username = username;
+  xmpp_config_.auth_token = auth_token;
+  xmpp_config_.auth_service = "oauth2";
+
+  // Initialize ClientConfig.
+  client_config_.host_jid = host_jid;
+  client_config_.host_public_key = host_pubkey;
+
+  client_config_.fetch_secret_callback =
+      base::Bind(&ChromotingJniInstance::FetchSecret, this);
+  client_config_.authentication_tag = host_id_;
+
+  client_config_.client_pairing_id = pairing_id;
+  client_config_.client_paired_secret = pairing_secret;
+
+  client_config_.authentication_methods.push_back(
+      protocol::AuthenticationMethod::FromString("spake2_pair"));
+  client_config_.authentication_methods.push_back(
+      protocol::AuthenticationMethod::FromString("spake2_hmac"));
+  client_config_.authentication_methods.push_back(
+      protocol::AuthenticationMethod::FromString("spake2_plain"));
+
+  // Post a task to start connection
   jni_runtime_->display_task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&ChromotingJniInstance::ConnectToHostOnDisplayThread,
@@ -89,19 +111,13 @@
 }
 
 void ChromotingJniInstance::PerformMouseAction(
-    int x,
-    int y,
+    int x, int y,
     protocol::MouseEvent_MouseButton button,
     bool button_down) {
   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
     jni_runtime_->network_task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&ChromotingJniInstance::PerformMouseAction,
-                   this,
-                   x,
-                   y,
-                   button,
-                   button_down));
+        FROM_HERE, base::Bind(&ChromotingJniInstance::PerformMouseAction,
+                              this, x, y, button, button_down));
     return;
   }
 
@@ -118,11 +134,8 @@
 void ChromotingJniInstance::PerformKeyboardAction(int key_code, bool key_down) {
   if (!jni_runtime_->network_task_runner()->BelongsToCurrentThread()) {
     jni_runtime_->network_task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&ChromotingJniInstance::PerformKeyboardAction,
-                   this,
-                   key_code,
-                   key_down));
+        FROM_HERE, base::Bind(&ChromotingJniInstance::PerformKeyboardAction,
+                              this, key_code, key_down));
     return;
   }
 
@@ -161,7 +174,9 @@
   // We ignore this message, since OnConnectoinState tells us the same thing.
 }
 
-void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {}
+void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {
+  NOTIMPLEMENTED();
+}
 
 void ChromotingJniInstance::SetPairingResponse(
     const protocol::PairingResponse& response) {
@@ -171,9 +186,7 @@
       FROM_HERE,
       base::Bind(&ChromotingJniRuntime::CommitPairingCredentials,
                  base::Unretained(jni_runtime_),
-                 host_id_,
-                 response.client_id(),
-                 response.shared_secret()));
+                 host_id_, response.client_id(), response.shared_secret()));
 }
 
 void ChromotingJniInstance::DeliverHostMessage(
@@ -223,52 +236,21 @@
 void ChromotingJniInstance::ConnectToHostOnNetworkThread() {
   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
 
-  client_config_.reset(new ClientConfig());
-  client_config_->host_jid = host_jid_;
-  client_config_->host_public_key = host_pubkey_;
-
-  client_config_->fetch_secret_callback = base::Bind(
-      &ChromotingJniInstance::FetchSecret,
-      this);
-  client_config_->authentication_tag = host_id_;
-
-  if (!pairing_id_.empty() && !pairing_secret_.empty()) {
-    client_config_->client_pairing_id = pairing_id_;
-    client_config_->client_paired_secret = pairing_secret_;
-    client_config_->authentication_methods.push_back(
-        protocol::AuthenticationMethod::FromString("spake2_pair"));
-  }
-
-  client_config_->authentication_methods.push_back(
-      protocol::AuthenticationMethod::FromString("spake2_hmac"));
-  client_config_->authentication_methods.push_back(
-      protocol::AuthenticationMethod::FromString("spake2_plain"));
-
   client_context_.reset(new ClientContext(
       jni_runtime_->network_task_runner().get()));
   client_context_->Start();
 
   connection_.reset(new protocol::ConnectionToHost(true));
 
-  client_.reset(new ChromotingClient(*client_config_,
-                                     client_context_.get(),
-                                     connection_.get(),
-                                     this,
-                                     frame_consumer_,
-                                     scoped_ptr<AudioPlayer>()));
+  client_.reset(new ChromotingClient(
+      client_config_, client_context_.get(), connection_.get(),
+      this, frame_consumer_, scoped_ptr<AudioPlayer>()));
 
   view_->set_frame_producer(client_->GetFrameProducer());
 
-  signaling_config_.reset(new XmppSignalStrategy::XmppServerConfig());
-  signaling_config_->host = kXmppServer;
-  signaling_config_->port = kXmppPort;
-  signaling_config_->use_tls = kXmppUseTls;
-
-  signaling_.reset(new XmppSignalStrategy(jni_runtime_->url_requester(),
-                                          username_,
-                                          auth_token_,
-                                          "oauth2",
-                                          *signaling_config_));
+  signaling_.reset(new XmppSignalStrategy(
+      net::ClientSocketFactory::GetDefaultFactory(),
+      jni_runtime_->url_requester(), xmpp_config_));
 
   network_settings_.reset(new NetworkSettings(
       NetworkSettings::NAT_TRAVERSAL_ENABLED));
@@ -283,11 +265,7 @@
 void ChromotingJniInstance::DisconnectFromHostOnNetworkThread() {
   DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
 
-  username_ = "";
-  auth_token_ = "";
-  host_jid_ = "";
-  host_id_ = "";
-  host_pubkey_ = "";
+  host_id_.clear();
 
   // |client_| must be torn down before |signaling_|.
   connection_.reset();
@@ -299,15 +277,12 @@
     const protocol::SecretFetchedCallback& callback) {
   if (!jni_runtime_->ui_task_runner()->BelongsToCurrentThread()) {
     jni_runtime_->ui_task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&ChromotingJniInstance::FetchSecret,
-                   this,
-                   pairable,
-                   callback));
+        FROM_HERE, base::Bind(&ChromotingJniInstance::FetchSecret,
+                              this, pairable, callback));
     return;
   }
 
-  if (!pairing_id_.empty() || !pairing_secret_.empty()) {
+  if (!client_config_.client_pairing_id.empty()) {
     // We attempted to connect using an existing pairing that was rejected.
     // Unless we forget about the stale credentials, we'll continue trying them.
     LOG(INFO) << "Deleting rejected pairing credentials";
@@ -315,7 +290,7 @@
   }
 
   pin_callback_ = callback;
-  jni_runtime_->DisplayAuthenticationPrompt();
+  jni_runtime_->DisplayAuthenticationPrompt(pairable);
 }
 
 }  // namespace remoting
diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h
index d066d6f..03b193d 100644
--- a/remoting/client/jni/chromoting_jni_instance.h
+++ b/remoting/client/jni/chromoting_jni_instance.h
@@ -24,9 +24,10 @@
 #include "remoting/protocol/cursor_shape_stub.h"
 
 namespace remoting {
+
 namespace protocol {
-  class ClipboardEvent;
-  class CursorShapeInfo;
+class ClipboardEvent;
+class CursorShapeInfo;
 }  // namespace protocol
 
 // ClientUserInterface that indirectly makes and receives JNI calls.
@@ -62,8 +63,7 @@
 
   // Moves the host's cursor to the specified coordinates, optionally with some
   // mouse button depressed. If |button| is BUTTON_UNDEFINED, no click is made.
-  void PerformMouseAction(int x,
-                          int y,
+  void PerformMouseAction(int x, int y,
                           protocol::MouseEvent_MouseButton button,
                           bool button_down);
 
@@ -109,17 +109,20 @@
   // Used to obtain task runner references and make calls to Java methods.
   ChromotingJniRuntime* jni_runtime_;
 
+  // ID of the host we are connecting to.
+  std::string host_id_;
+
   // This group of variables is to be used on the display thread.
   scoped_refptr<FrameConsumerProxy> frame_consumer_;
   scoped_ptr<JniFrameConsumer> view_;
   scoped_ptr<base::WeakPtrFactory<JniFrameConsumer> > view_weak_factory_;
 
   // This group of variables is to be used on the network thread.
-  scoped_ptr<ClientConfig> client_config_;
+  ClientConfig client_config_;
   scoped_ptr<ClientContext> client_context_;
   scoped_ptr<protocol::ConnectionToHost> connection_;
   scoped_ptr<ChromotingClient> client_;
-  scoped_ptr<XmppSignalStrategy::XmppServerConfig> signaling_config_;
+  XmppSignalStrategy::XmppServerConfig xmpp_config_;
   scoped_ptr<XmppSignalStrategy> signaling_;  // Must outlive client_
   scoped_ptr<NetworkSettings> network_settings_;
 
@@ -127,18 +130,6 @@
   // the UI thread, but must be posted to the network thread to call it.
   protocol::SecretFetchedCallback pin_callback_;
 
-  // These strings describe the current connection, and are not reused. They
-  // are initialized in ConnectionToHost(), but thereafter are only to be used
-  // on the network thread. (This is safe because ConnectionToHost()'s finishes
-  // using them on the UI thread before they are ever touched from network.)
-  std::string username_;
-  std::string auth_token_;
-  std::string host_jid_;
-  std::string host_id_;
-  std::string host_pubkey_;
-  std::string pairing_id_;
-  std::string pairing_secret_;
-
   // Indicates whether to establish a new pairing with this host. This is
   // modified in ProvideSecret(), but thereafter to be used only from the
   // network thread. (This is safe because ProvideSecret() is invoked at most
diff --git a/remoting/client/jni/chromoting_jni_runtime.cc b/remoting/client/jni/chromoting_jni_runtime.cc
index 8d51a83..059a4b2 100644
--- a/remoting/client/jni/chromoting_jni_runtime.cc
+++ b/remoting/client/jni/chromoting_jni_runtime.cc
@@ -50,8 +50,7 @@
   display_task_runner_ = AutoThread::Create("native_disp",
                                             ui_task_runner_);
 
-  url_requester_ = new URLRequestContextGetter(ui_task_runner_,
-                                               network_task_runner_);
+  url_requester_ = new URLRequestContextGetter(network_task_runner_);
 
   // Allows later decoding of video frames.
   media::InitializeCPUSpecificYUVConversions();
@@ -124,13 +123,14 @@
     error);
 }
 
-void ChromotingJniRuntime::DisplayAuthenticationPrompt() {
+void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) {
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
 
   JNIEnv* env = base::android::AttachCurrentThread();
   env->CallStaticVoidMethod(
       class_,
-      env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V"));
+      env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "(Z)V"),
+      pairing_supported);
 }
 
 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
diff --git a/remoting/client/jni/chromoting_jni_runtime.h b/remoting/client/jni/chromoting_jni_runtime.h
index 93f933f..f16d033 100644
--- a/remoting/client/jni/chromoting_jni_runtime.h
+++ b/remoting/client/jni/chromoting_jni_runtime.h
@@ -72,7 +72,7 @@
                               protocol::ErrorCode error);
 
   // Pops up a dialog box asking the user to enter a PIN. Call on UI thread.
-  void DisplayAuthenticationPrompt();
+  void DisplayAuthenticationPrompt(bool pairing_supported);
 
   // Saves new pairing credentials to permanent storage. Call on UI thread.
   void CommitPairingCredentials(const std::string& host,
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index e22452a..55e6954 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -31,10 +31,10 @@
 #include "remoting/client/chromoting_client.h"
 #include "remoting/client/client_config.h"
 #include "remoting/client/frame_consumer_proxy.h"
+#include "remoting/client/plugin/delegating_signal_strategy.h"
 #include "remoting/client/plugin/pepper_audio_player.h"
 #include "remoting/client/plugin/pepper_input_handler.h"
 #include "remoting/client/plugin/pepper_port_allocator.h"
-#include "remoting/client/plugin/pepper_signal_strategy.h"
 #include "remoting/client/plugin/pepper_token_fetcher.h"
 #include "remoting/client/plugin/pepper_view.h"
 #include "remoting/client/rectangle_update_decoder.h"
@@ -55,7 +55,7 @@
 // 32-bit BGRA is 4 bytes per pixel.
 const int kBytesPerPixel = 4;
 
-// Default DPI to assume for old clients that use notifyClientDimensions.
+// Default DPI to assume for old clients that use notifyClientResolution.
 const int kDefaultDPI = 96;
 
 // Interval at which to sample performance statistics.
@@ -143,8 +143,8 @@
 // String sent in the "hello" message to the webapp to describe features.
 const char ChromotingInstance::kApiFeatures[] =
     "highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey "
-    "notifyClientDimensions notifyClientResolution pauseVideo pauseAudio "
-    "asyncPin thirdPartyAuth pinlessAuth extensionMessage";
+    "notifyClientResolution pauseVideo pauseAudio asyncPin thirdPartyAuth "
+    "pinlessAuth extensionMessage";
 
 const char ChromotingInstance::kRequestedCapabilities[] = "";
 const char ChromotingInstance::kSupportedCapabilities[] = "desktopShape";
@@ -174,15 +174,9 @@
       plugin_task_runner_(new PluginThreadTaskRunner(&plugin_thread_delegate_)),
       context_(plugin_task_runner_.get()),
       input_tracker_(&mouse_input_filter_),
-#if defined(OS_MACOSX)
-      // On Mac we need an extra filter to inject missing keyup events.
-      // See remoting/client/plugin/mac_key_event_processor.h for more details.
-      mac_key_event_processor_(&input_tracker_),
-      key_mapper_(&mac_key_event_processor_),
-#else
       key_mapper_(&input_tracker_),
-#endif
-      input_handler_(&key_mapper_),
+      normalizing_input_filter_(CreateNormalizingInputFilter(&key_mapper_)),
+      input_handler_(normalizing_input_filter_.get()),
       use_async_pin_dialog_(false),
       weak_factory_(this) {
   RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
@@ -278,168 +272,37 @@
   }
 
   if (method == "connect") {
-    ClientConfig config;
-    std::string auth_methods;
-    if (!data->GetString("hostJid", &config.host_jid) ||
-        !data->GetString("hostPublicKey", &config.host_public_key) ||
-        !data->GetString("localJid", &config.local_jid) ||
-        !data->GetString("authenticationMethods", &auth_methods) ||
-        !ParseAuthMethods(auth_methods, &config) ||
-        !data->GetString("authenticationTag", &config.authentication_tag)) {
-      LOG(ERROR) << "Invalid connect() data.";
-      return;
-    }
-    data->GetString("clientPairingId", &config.client_pairing_id);
-    data->GetString("clientPairedSecret", &config.client_paired_secret);
-    if (use_async_pin_dialog_) {
-      config.fetch_secret_callback =
-          base::Bind(&ChromotingInstance::FetchSecretFromDialog,
-                     weak_factory_.GetWeakPtr());
-    } else {
-      std::string shared_secret;
-      if (!data->GetString("sharedSecret", &shared_secret)) {
-        LOG(ERROR) << "sharedSecret not specified in connect().";
-        return;
-      }
-      config.fetch_secret_callback =
-          base::Bind(&ChromotingInstance::FetchSecretFromString, shared_secret);
-    }
-
-    // Read the list of capabilities, if any.
-    if (data->HasKey("capabilities")) {
-      if (!data->GetString("capabilities", &config.capabilities)) {
-        LOG(ERROR) << "Invalid connect() data.";
-        return;
-      }
-    }
-
-    Connect(config);
+    HandleConnect(*data);
   } else if (method == "disconnect") {
-    Disconnect();
+    HandleDisconnect(*data);
   } else if (method == "incomingIq") {
-    std::string iq;
-    if (!data->GetString("iq", &iq)) {
-      LOG(ERROR) << "Invalid onIq() data.";
-      return;
-    }
-    OnIncomingIq(iq);
+    HandleOnIncomingIq(*data);
   } else if (method == "releaseAllKeys") {
-    ReleaseAllKeys();
+    HandleReleaseAllKeys(*data);
   } else if (method == "injectKeyEvent") {
-    int usb_keycode = 0;
-    bool is_pressed = false;
-    if (!data->GetInteger("usbKeycode", &usb_keycode) ||
-        !data->GetBoolean("pressed", &is_pressed)) {
-      LOG(ERROR) << "Invalid injectKeyEvent.";
-      return;
-    }
-
-    protocol::KeyEvent event;
-    event.set_usb_keycode(usb_keycode);
-    event.set_pressed(is_pressed);
-    InjectKeyEvent(event);
+    HandleInjectKeyEvent(*data);
   } else if (method == "remapKey") {
-    int from_keycode = 0;
-    int to_keycode = 0;
-    if (!data->GetInteger("fromKeycode", &from_keycode) ||
-        !data->GetInteger("toKeycode", &to_keycode)) {
-      LOG(ERROR) << "Invalid remapKey.";
-      return;
-    }
-
-    RemapKey(from_keycode, to_keycode);
+    HandleRemapKey(*data);
   } else if (method == "trapKey") {
-    int keycode = 0;
-    bool trap = false;
-    if (!data->GetInteger("keycode", &keycode) ||
-        !data->GetBoolean("trap", &trap)) {
-      LOG(ERROR) << "Invalid trapKey.";
-      return;
-    }
-
-    TrapKey(keycode, trap);
+    HandleTrapKey(*data);
   } else if (method == "sendClipboardItem") {
-    std::string mime_type;
-    std::string item;
-    if (!data->GetString("mimeType", &mime_type) ||
-        !data->GetString("item", &item)) {
-      LOG(ERROR) << "Invalid sendClipboardItem() data.";
-      return;
-    }
-    SendClipboardItem(mime_type, item);
-  } else if (method == "notifyClientDimensions" ||
-             method == "notifyClientResolution") {
-    // notifyClientResolution's width and height are in pixels,
-    // notifyClientDimension's in DIPs, but since for the latter
-    // we assume 96dpi, DIPs and pixels are equivalent.
-    int width = 0;
-    int height = 0;
-    if (!data->GetInteger("width", &width) ||
-        !data->GetInteger("height", &height) ||
-        width <= 0 || height <= 0) {
-      LOG(ERROR) << "Invalid " << method << ".";
-      return;
-    }
-
-    // notifyClientResolution requires that DPI be specified.
-    // For notifyClientDimensions we assume 96dpi.
-    int x_dpi = kDefaultDPI;
-    int y_dpi = kDefaultDPI;
-    if (method == "notifyClientResolution" &&
-        (!data->GetInteger("x_dpi", &x_dpi) ||
-         !data->GetInteger("y_dpi", &y_dpi) ||
-         x_dpi <= 0 || y_dpi <= 0)) {
-      LOG(ERROR) << "Invalid notifyClientResolution.";
-      return;
-    }
-
-    NotifyClientResolution(width, height, x_dpi, y_dpi);
+    HandleSendClipboardItem(*data);
+  } else if (method == "notifyClientResolution") {
+    HandleNotifyClientResolution(*data);
   } else if (method == "pauseVideo") {
-    bool pause = false;
-    if (!data->GetBoolean("pause", &pause)) {
-      LOG(ERROR) << "Invalid pauseVideo.";
-      return;
-    }
-    PauseVideo(pause);
+    HandlePauseVideo(*data);
   } else if (method == "pauseAudio") {
-    bool pause = false;
-    if (!data->GetBoolean("pause", &pause)) {
-      LOG(ERROR) << "Invalid pauseAudio.";
-      return;
-    }
-    PauseAudio(pause);
+    HandlePauseAudio(*data);
   } else if (method == "useAsyncPinDialog") {
     use_async_pin_dialog_ = true;
   } else if (method == "onPinFetched") {
-    std::string pin;
-    if (!data->GetString("pin", &pin)) {
-      LOG(ERROR) << "Invalid onPinFetched.";
-      return;
-    }
-    OnPinFetched(pin);
+    HandleOnPinFetched(*data);
   } else if (method == "onThirdPartyTokenFetched") {
-    std::string token;
-    std::string shared_secret;
-    if (!data->GetString("token", &token) ||
-        !data->GetString("sharedSecret", &shared_secret)) {
-      LOG(ERROR) << "Invalid onThirdPartyTokenFetched data.";
-      return;
-    }
-    OnThirdPartyTokenFetched(token, shared_secret);
+    HandleOnThirdPartyTokenFetched(*data);
   } else if (method == "requestPairing") {
-    std::string client_name;
-    if (!data->GetString("clientName", &client_name)) {
-      LOG(ERROR) << "Invalid requestPairing";
-      return;
-    }
-    RequestPairing(client_name);
+    HandleRequestPairing(*data);
   } else if (method == "extensionMessage") {
-    std::string type, message;
-    if (!data->GetString("type", &type) || !data->GetString("data", &message)) {
-      LOG(ERROR) << "Invalid extensionMessage.";
-      return;
-    }
-    SendClientMessage(type, message);
+    HandleExtensionMessage(*data);
   }
 }
 
@@ -684,7 +547,48 @@
   PostChromotingMessage("onFirstFrameReceived", data.Pass());
 }
 
-void ChromotingInstance::Connect(const ClientConfig& config) {
+void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) {
+  ClientConfig config;
+  std::string local_jid;
+  std::string auth_methods;
+  if (!data.GetString("hostJid", &config.host_jid) ||
+      !data.GetString("hostPublicKey", &config.host_public_key) ||
+      !data.GetString("localJid", &local_jid) ||
+      !data.GetString("authenticationMethods", &auth_methods) ||
+      !ParseAuthMethods(auth_methods, &config) ||
+      !data.GetString("authenticationTag", &config.authentication_tag)) {
+    LOG(ERROR) << "Invalid connect() data.";
+    return;
+  }
+  data.GetString("clientPairingId", &config.client_pairing_id);
+  data.GetString("clientPairedSecret", &config.client_paired_secret);
+  if (use_async_pin_dialog_) {
+    config.fetch_secret_callback =
+        base::Bind(&ChromotingInstance::FetchSecretFromDialog,
+                   weak_factory_.GetWeakPtr());
+  } else {
+    std::string shared_secret;
+    if (!data.GetString("sharedSecret", &shared_secret)) {
+      LOG(ERROR) << "sharedSecret not specified in connect().";
+      return;
+    }
+    config.fetch_secret_callback =
+        base::Bind(&ChromotingInstance::FetchSecretFromString, shared_secret);
+  }
+
+  // Read the list of capabilities, if any.
+  if (data.HasKey("capabilities")) {
+    if (!data.GetString("capabilities", &config.capabilities)) {
+      LOG(ERROR) << "Invalid connect() data.";
+      return;
+    }
+  }
+
+  ConnectWithConfig(config, local_jid);
+}
+
+void ChromotingInstance::ConnectWithConfig(const ClientConfig& config,
+                                           const std::string& local_jid) {
   DCHECK(plugin_task_runner_->BelongsToCurrentThread());
 
   jingle_glue::JingleThreadWrapper::EnsureForCurrentMessageLoop();
@@ -711,13 +615,12 @@
   mouse_input_filter_.set_input_size(view_->get_view_size_dips());
 
   LOG(INFO) << "Connecting to " << config.host_jid
-            << ". Local jid: " << config.local_jid << ".";
+            << ". Local jid: " << local_jid << ".";
 
-  // Setup the PepperSignalStrategy.
-  signal_strategy_.reset(new PepperSignalStrategy(
-      config.local_jid,
-      base::Bind(&ChromotingInstance::SendOutgoingIq,
-                 weak_factory_.GetWeakPtr())));
+  // Setup the signal strategy.
+  signal_strategy_.reset(new DelegatingSignalStrategy(
+      local_jid, base::Bind(&ChromotingInstance::SendOutgoingIq,
+                            weak_factory_.GetWeakPtr())));
 
   scoped_ptr<cricket::HttpPortAllocatorBase> port_allocator(
       PepperPortAllocator::Create(this));
@@ -734,7 +637,7 @@
       base::TimeDelta::FromMilliseconds(kPerfStatsIntervalMs));
 }
 
-void ChromotingInstance::Disconnect() {
+void ChromotingInstance::HandleDisconnect(const base::DictionaryValue& data) {
   DCHECK(plugin_task_runner_->BelongsToCurrentThread());
 
   // PepperView must be destroyed before the client.
@@ -749,35 +652,77 @@
   host_connection_.reset();
 }
 
-void ChromotingInstance::OnIncomingIq(const std::string& iq) {
+void ChromotingInstance::HandleOnIncomingIq(const base::DictionaryValue& data) {
+  std::string iq;
+  if (!data.GetString("iq", &iq)) {
+    LOG(ERROR) << "Invalid incomingIq() data.";
+    return;
+  }
+
   // Just ignore the message if it's received before Connect() is called. It's
   // likely to be a leftover from a previous session, so it's safe to ignore it.
   if (signal_strategy_)
     signal_strategy_->OnIncomingMessage(iq);
 }
 
-void ChromotingInstance::ReleaseAllKeys() {
+void ChromotingInstance::HandleReleaseAllKeys(
+    const base::DictionaryValue& data) {
   if (IsConnected())
     input_tracker_.ReleaseAll();
 }
 
-void ChromotingInstance::InjectKeyEvent(const protocol::KeyEvent& event) {
+void ChromotingInstance::HandleInjectKeyEvent(
+      const base::DictionaryValue& data) {
+  int usb_keycode = 0;
+  bool is_pressed = false;
+  if (!data.GetInteger("usbKeycode", &usb_keycode) ||
+      !data.GetBoolean("pressed", &is_pressed)) {
+    LOG(ERROR) << "Invalid injectKeyEvent.";
+    return;
+  }
+
+  protocol::KeyEvent event;
+  event.set_usb_keycode(usb_keycode);
+  event.set_pressed(is_pressed);
+
   // Inject after the KeyEventMapper, so the event won't get mapped or trapped.
   if (IsConnected())
     input_tracker_.InjectKeyEvent(event);
 }
 
-void ChromotingInstance::RemapKey(uint32 in_usb_keycode,
-                                  uint32 out_usb_keycode) {
-  key_mapper_.RemapKey(in_usb_keycode, out_usb_keycode);
+void ChromotingInstance::HandleRemapKey(const base::DictionaryValue& data) {
+  int from_keycode = 0;
+  int to_keycode = 0;
+  if (!data.GetInteger("fromKeycode", &from_keycode) ||
+      !data.GetInteger("toKeycode", &to_keycode)) {
+    LOG(ERROR) << "Invalid remapKey.";
+    return;
+  }
+
+  key_mapper_.RemapKey(from_keycode, to_keycode);
 }
 
-void ChromotingInstance::TrapKey(uint32 usb_keycode, bool trap) {
-  key_mapper_.TrapKey(usb_keycode, trap);
+void ChromotingInstance::HandleTrapKey(const base::DictionaryValue& data) {
+  int keycode = 0;
+  bool trap = false;
+  if (!data.GetInteger("keycode", &keycode) ||
+      !data.GetBoolean("trap", &trap)) {
+    LOG(ERROR) << "Invalid trapKey.";
+    return;
+  }
+
+  key_mapper_.TrapKey(keycode, trap);
 }
 
-void ChromotingInstance::SendClipboardItem(const std::string& mime_type,
-                                           const std::string& item) {
+void ChromotingInstance::HandleSendClipboardItem(
+    const base::DictionaryValue& data) {
+  std::string mime_type;
+  std::string item;
+  if (!data.GetString("mimeType", &mime_type) ||
+      !data.GetString("item", &item)) {
+    LOG(ERROR) << "Invalid sendClipboardItem data.";
+    return;
+  }
   if (!IsConnected()) {
     return;
   }
@@ -787,10 +732,22 @@
   host_connection_->clipboard_stub()->InjectClipboardEvent(event);
 }
 
-void ChromotingInstance::NotifyClientResolution(int width,
-                                                int height,
-                                                int x_dpi,
-                                                int y_dpi) {
+void ChromotingInstance::HandleNotifyClientResolution(
+    const base::DictionaryValue& data) {
+  int width = 0;
+  int height = 0;
+  int x_dpi = kDefaultDPI;
+  int y_dpi = kDefaultDPI;
+  if (!data.GetInteger("width", &width) ||
+      !data.GetInteger("height", &height) ||
+      !data.GetInteger("x_dpi", &x_dpi) ||
+      !data.GetInteger("y_dpi", &y_dpi) ||
+      width <= 0 || height <= 0 ||
+      x_dpi <= 0 || y_dpi <= 0) {
+    LOG(ERROR) << "Invalid notifyClientResolution.";
+    return;
+  }
+
   if (!IsConnected()) {
     return;
   }
@@ -808,7 +765,12 @@
   host_connection_->host_stub()->NotifyClientResolution(client_resolution);
 }
 
-void ChromotingInstance::PauseVideo(bool pause) {
+void ChromotingInstance::HandlePauseVideo(const base::DictionaryValue& data) {
+  bool pause = false;
+  if (!data.GetBoolean("pause", &pause)) {
+    LOG(ERROR) << "Invalid pauseVideo.";
+    return;
+  }
   if (!IsConnected()) {
     return;
   }
@@ -817,7 +779,12 @@
   host_connection_->host_stub()->ControlVideo(video_control);
 }
 
-void ChromotingInstance::PauseAudio(bool pause) {
+void ChromotingInstance::HandlePauseAudio(const base::DictionaryValue& data) {
+  bool pause = false;
+  if (!data.GetBoolean("pause", &pause)) {
+    LOG(ERROR) << "Invalid pauseAudio.";
+    return;
+  }
   if (!IsConnected()) {
     return;
   }
@@ -825,7 +792,12 @@
   audio_control.set_enable(!pause);
   host_connection_->host_stub()->ControlAudio(audio_control);
 }
-void ChromotingInstance::OnPinFetched(const std::string& pin) {
+void ChromotingInstance::HandleOnPinFetched(const base::DictionaryValue& data) {
+  std::string pin;
+  if (!data.GetString("pin", &pin)) {
+    LOG(ERROR) << "Invalid onPinFetched.";
+    return;
+  }
   if (!secret_fetched_callback_.is_null()) {
     secret_fetched_callback_.Run(pin);
     secret_fetched_callback_.Reset();
@@ -834,9 +806,15 @@
   }
 }
 
-void ChromotingInstance::OnThirdPartyTokenFetched(
-    const std::string& token,
-    const std::string& shared_secret) {
+void ChromotingInstance::HandleOnThirdPartyTokenFetched(
+    const base::DictionaryValue& data) {
+  std::string token;
+  std::string shared_secret;
+  if (!data.GetString("token", &token) ||
+      !data.GetString("sharedSecret", &shared_secret)) {
+    LOG(ERROR) << "Invalid onThirdPartyTokenFetched data.";
+    return;
+  }
   if (pepper_token_fetcher_.get()) {
     pepper_token_fetcher_->OnTokenFetched(token, shared_secret);
     pepper_token_fetcher_.reset();
@@ -845,7 +823,13 @@
   }
 }
 
-void ChromotingInstance::RequestPairing(const std::string& client_name) {
+void ChromotingInstance::HandleRequestPairing(
+    const base::DictionaryValue& data) {
+  std::string client_name;
+  if (!data.GetString("clientName", &client_name)) {
+    LOG(ERROR) << "Invalid requestPairing";
+    return;
+  }
   if (!IsConnected()) {
     return;
   }
@@ -854,14 +838,21 @@
   host_connection_->host_stub()->RequestPairing(pairing_request);
 }
 
-void ChromotingInstance::SendClientMessage(const std::string& type,
-                                           const std::string& data) {
+void ChromotingInstance::HandleExtensionMessage(
+    const base::DictionaryValue& data) {
+  std::string type;
+  std::string message_data;
+  if (!data.GetString("type", &type) ||
+      !data.GetString("data", &message_data)) {
+    LOG(ERROR) << "Invalid extensionMessage.";
+    return;
+  }
   if (!IsConnected()) {
     return;
   }
   protocol::ExtensionMessage message;
   message.set_type(type);
-  message.set_data(data);
+  message.set_data(message_data);
   host_connection_->host_stub()->DeliverClientMessage(message);
 }
 
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index 23c4c49..a97ca55 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -31,7 +31,7 @@
 #include "remoting/client/client_context.h"
 #include "remoting/client/client_user_interface.h"
 #include "remoting/client/key_event_mapper.h"
-#include "remoting/client/plugin/mac_key_event_processor.h"
+#include "remoting/client/plugin/normalizing_input_filter.h"
 #include "remoting/client/plugin/pepper_input_handler.h"
 #include "remoting/client/plugin/pepper_plugin_thread_delegate.h"
 #include "remoting/proto/event.pb.h"
@@ -58,12 +58,13 @@
 class ChromotingClient;
 class ChromotingStats;
 class ClientContext;
+class DelegatingSignalStrategy;
 class FrameConsumerProxy;
 class PepperAudioPlayer;
 class PepperTokenFetcher;
 class PepperView;
-class PepperSignalStrategy;
 class RectangleUpdateDecoder;
+class SignalStrategy;
 
 struct ClientConfig;
 
@@ -185,22 +186,25 @@
 
   // Message handlers for messages that come from JavaScript. Called
   // from HandleMessage().
-  void Connect(const ClientConfig& config);
-  void Disconnect();
-  void OnIncomingIq(const std::string& iq);
-  void ReleaseAllKeys();
-  void InjectKeyEvent(const protocol::KeyEvent& event);
-  void RemapKey(uint32 in_usb_keycode, uint32 out_usb_keycode);
-  void TrapKey(uint32 usb_keycode, bool trap);
-  void SendClipboardItem(const std::string& mime_type, const std::string& item);
-  void NotifyClientResolution(int width, int height, int x_dpi, int y_dpi);
-  void PauseVideo(bool pause);
-  void PauseAudio(bool pause);
-  void OnPinFetched(const std::string& pin);
-  void OnThirdPartyTokenFetched(const std::string& token,
-                                const std::string& shared_secret);
-  void RequestPairing(const std::string& client_name);
-  void SendClientMessage(const std::string& type, const std::string& data);
+  void HandleConnect(const base::DictionaryValue& data);
+  void HandleDisconnect(const base::DictionaryValue& data);
+  void HandleOnIncomingIq(const base::DictionaryValue& data);
+  void HandleReleaseAllKeys(const base::DictionaryValue& data);
+  void HandleInjectKeyEvent(const base::DictionaryValue& data);
+  void HandleRemapKey(const base::DictionaryValue& data);
+  void HandleTrapKey(const base::DictionaryValue& data);
+  void HandleSendClipboardItem(const base::DictionaryValue& data);
+  void HandleNotifyClientResolution(const base::DictionaryValue& data);
+  void HandlePauseVideo(const base::DictionaryValue& data);
+  void HandlePauseAudio(const base::DictionaryValue& data);
+  void HandleOnPinFetched(const base::DictionaryValue& data);
+  void HandleOnThirdPartyTokenFetched(const base::DictionaryValue& data);
+  void HandleRequestPairing(const base::DictionaryValue& data);
+  void HandleExtensionMessage(const base::DictionaryValue& data);
+
+  // Helper method called from Connect() to connect with parsed config.
+  void ConnectWithConfig(const ClientConfig& config,
+                         const std::string& local_jid);
 
   // Helper method to post messages to the webapp.
   void PostChromotingMessage(const std::string& method,
@@ -209,7 +213,7 @@
   // Posts trapped keys to the web-app to handle.
   void SendTrappedKey(uint32 usb_keycode, bool pressed);
 
-  // Callback for PepperSignalStrategy.
+  // Callback for DelegatingSignalStrategy.
   void SendOutgoingIq(const std::string& iq);
 
   void SendPerfStats();
@@ -240,7 +244,7 @@
   // Contains the most-recently-reported desktop shape, if any.
   scoped_ptr<SkRegion> desktop_shape_;
 
-  scoped_ptr<PepperSignalStrategy> signal_strategy_;
+  scoped_ptr<DelegatingSignalStrategy> signal_strategy_;
 
   scoped_ptr<protocol::ConnectionToHost> host_connection_;
   scoped_ptr<ChromotingClient> client_;
@@ -248,10 +252,8 @@
   // Input pipeline components, in reverse order of distance from input source.
   protocol::MouseInputFilter mouse_input_filter_;
   protocol::InputEventTracker input_tracker_;
-#if defined(OS_MACOSX)
-  MacKeyEventProcessor mac_key_event_processor_;
-#endif
   KeyEventMapper key_mapper_;
+  scoped_ptr<protocol::InputFilter> normalizing_input_filter_;
   PepperInputHandler input_handler_;
 
   // PIN Fetcher.
diff --git a/remoting/client/plugin/delegating_signal_strategy.cc b/remoting/client/plugin/delegating_signal_strategy.cc
new file mode 100644
index 0000000..7129341
--- /dev/null
+++ b/remoting/client/plugin/delegating_signal_strategy.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 "remoting/client/plugin/delegating_signal_strategy.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
+
+namespace remoting {
+
+DelegatingSignalStrategy::DelegatingSignalStrategy(
+    std::string local_jid,
+    const SendIqCallback& send_iq_callback)
+    : local_jid_(local_jid),
+      send_iq_callback_(send_iq_callback),
+      last_id_(0) {
+}
+
+DelegatingSignalStrategy::~DelegatingSignalStrategy() {
+}
+
+void DelegatingSignalStrategy::OnIncomingMessage(const std::string& message) {
+ scoped_ptr<buzz::XmlElement> stanza(buzz::XmlElement::ForStr(message));
+  if (!stanza.get()) {
+    LOG(WARNING) << "Malformed XMPP stanza received: " << message;
+    return;
+  }
+
+  ObserverListBase<Listener>::Iterator it(listeners_);
+  Listener* listener;
+  while ((listener = it.GetNext()) != NULL) {
+    if (listener->OnSignalStrategyIncomingStanza(stanza.get()))
+      break;
+  }
+}
+
+void DelegatingSignalStrategy::Connect() {
+}
+
+void DelegatingSignalStrategy::Disconnect() {
+}
+
+SignalStrategy::State DelegatingSignalStrategy::GetState() const {
+  return CONNECTED;
+}
+
+SignalStrategy::Error DelegatingSignalStrategy::GetError() const {
+  return OK;
+}
+
+std::string DelegatingSignalStrategy::GetLocalJid() const {
+  return local_jid_;
+}
+
+void DelegatingSignalStrategy::AddListener(Listener* listener) {
+  listeners_.AddObserver(listener);
+}
+
+void DelegatingSignalStrategy::RemoveListener(Listener* listener) {
+  listeners_.RemoveObserver(listener);
+}
+
+bool DelegatingSignalStrategy::SendStanza(scoped_ptr<buzz::XmlElement> stanza) {
+  send_iq_callback_.Run(stanza->Str());
+  return true;
+}
+
+std::string DelegatingSignalStrategy::GetNextId() {
+  ++last_id_;
+  return base::IntToString(last_id_);
+}
+
+}  // namespace remoting
diff --git a/remoting/client/plugin/delegating_signal_strategy.h b/remoting/client/plugin/delegating_signal_strategy.h
new file mode 100644
index 0000000..f22539a
--- /dev/null
+++ b/remoting/client/plugin/delegating_signal_strategy.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 REMOTING_CLIENT_PLUGIN_DELEGATING_SIGNAL_STRATEGY_H_
+#define REMOTING_CLIENT_PLUGIN_DELEGATING_SIGNAL_STRATEGY_H_
+
+#include "base/callback.h"
+#include "base/observer_list.h"
+#include "remoting/jingle_glue/signal_strategy.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace remoting {
+
+class DelegatingSignalStrategy : public SignalStrategy {
+ public:
+  typedef base::Callback<void(const std::string&)> SendIqCallback;
+
+  DelegatingSignalStrategy(std::string local_jid,
+                       const SendIqCallback& send_iq_callback);
+  virtual ~DelegatingSignalStrategy();
+
+  void OnIncomingMessage(const std::string& message);
+
+  // SignalStrategy interface.
+  virtual void Connect() OVERRIDE;
+  virtual void Disconnect() OVERRIDE;
+  virtual State GetState() const OVERRIDE;
+  virtual Error GetError() const OVERRIDE;
+  virtual std::string GetLocalJid() const OVERRIDE;
+  virtual void AddListener(Listener* listener) OVERRIDE;
+  virtual void RemoveListener(Listener* listener) OVERRIDE;
+  virtual bool SendStanza(scoped_ptr<buzz::XmlElement> stanza) OVERRIDE;
+  virtual std::string GetNextId() OVERRIDE;
+
+ private:
+  std::string local_jid_;
+  SendIqCallback send_iq_callback_;
+
+  ObserverList<Listener> listeners_;
+
+  int last_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(DelegatingSignalStrategy);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_CLIENT_PLUGIN_DELEGATING_SIGNAL_STRATEGY_H_
diff --git a/remoting/client/plugin/mac_key_event_processor.cc b/remoting/client/plugin/mac_key_event_processor.cc
deleted file mode 100644
index 175924bf..0000000
--- a/remoting/client/plugin/mac_key_event_processor.cc
+++ /dev/null
@@ -1,93 +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 "remoting/client/plugin/mac_key_event_processor.h"
-
-#include <vector>
-
-#include "base/logging.h"
-
-namespace remoting {
-
-namespace {
-
-const unsigned int kUsbCapsLock     = 0x070039;
-const unsigned int kUsbLeftControl  = 0x0700e0;
-const unsigned int kUsbLeftShift    = 0x0700e1;
-const unsigned int kUsbLeftOption   = 0x0700e2;
-const unsigned int kUsbLeftCmd      = 0x0700e3;
-const unsigned int kUsbRightControl = 0x0700e4;
-const unsigned int kUsbRightShift   = 0x0700e5;
-const unsigned int kUsbRightOption  = 0x0700e6;
-const unsigned int kUsbRightCmd     = 0x0700e7;
-const unsigned int kUsbTab          = 0x07002b;
-
-}  // namespace
-
-MacKeyEventProcessor::MacKeyEventProcessor(protocol::InputStub* input_stub)
-    : protocol::InputFilter(input_stub) {
-}
-
-MacKeyEventProcessor::~MacKeyEventProcessor() {
-}
-
-void MacKeyEventProcessor::InjectKeyEvent(const protocol::KeyEvent& event) {
-  DCHECK(event.has_usb_keycode());
-
-  bool is_special_key = event.usb_keycode() == kUsbLeftControl ||
-      event.usb_keycode() == kUsbLeftShift ||
-      event.usb_keycode() == kUsbLeftOption ||
-      event.usb_keycode() == kUsbRightControl ||
-      event.usb_keycode() == kUsbRightShift ||
-      event.usb_keycode() == kUsbRightOption ||
-      event.usb_keycode() == kUsbTab;
-
-  bool is_cmd_key = event.usb_keycode() == kUsbLeftCmd ||
-      event.usb_keycode() == kUsbRightCmd;
-
-  if (event.usb_keycode() == kUsbCapsLock) {
-    // Mac OS X generates keydown/keyup on lock-state transitions, rather than
-    // when the key is pressed & released, so fake keydown/keyup on each event.
-    protocol::KeyEvent newEvent(event);
-
-    newEvent.set_pressed(true);
-    InputFilter::InjectKeyEvent(newEvent);
-    newEvent.set_pressed(false);
-    InputFilter::InjectKeyEvent(newEvent);
-
-    return;
-  } else if (!is_cmd_key && !is_special_key) {
-    // Track keydown/keyup events for non-modifiers, so we can release them if
-    // necessary (see below).
-    if (event.pressed()) {
-      key_pressed_map_[event.usb_keycode()] = event;
-    } else {
-      key_pressed_map_.erase(event.usb_keycode());
-    }
-  }
-
-  if (is_cmd_key && !event.pressed()) {
-    // Mac OS X will not generate release events for keys pressed while Cmd is
-    // pressed, so release all pressed keys when Cmd is released.
-    GenerateKeyupEvents();
-  }
-
-  InputFilter::InjectKeyEvent(event);
-}
-
-void MacKeyEventProcessor::GenerateKeyupEvents() {
-  for (KeyPressedMap::iterator i = key_pressed_map_.begin();
-       i != key_pressed_map_.end(); ++i) {
-    // The generated key up event will have the same key code and lock states
-    // as the original key down event.
-    protocol::KeyEvent event = i->second;
-    event.set_pressed(false);
-    InputFilter::InjectKeyEvent(event);
-  }
-
-  // Clearing the map now that we have released all the pressed keys.
-  key_pressed_map_.clear();
-}
-
-}  // namespace remoting
diff --git a/remoting/client/plugin/mac_key_event_processor.h b/remoting/client/plugin/mac_key_event_processor.h
deleted file mode 100644
index 56bc974..0000000
--- a/remoting/client/plugin/mac_key_event_processor.h
+++ /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.
-
-// MacKeyEventProcessor is designed to solve the problem of missing keyup
-// events on Mac.
-//
-// PROBLEM
-//
-// On Mac if user presses CMD and then C key there is no keyup event generated
-// for C when user releases the C key before the CMD key.
-// The cause is that CMD + C triggers a system action and Chrome injects only a
-// keydown event for the C key. Safari shares the same behavior.
-//
-// SOLUTION
-//
-// When a keyup event for CMD key happens we will check all prior keydown
-// events received and inject corresponding keyup events artificially, with
-// the exception of:
-//
-// SHIFT, CONTROL, OPTION, LEFT CMD, RIGHT CMD and CAPS LOCK
-//
-// because they are reported by Chrome correctly.
-//
-// There are a couple cases that this solution doesn't work perfectly, one
-// of them leads to duplicated keyup events.
-//
-// User performs this sequence of actions:
-//
-// CMD DOWN, C DOWN, CMD UP, C UP
-//
-// In this case the algorithm will generate:
-//
-// CMD DOWN, C DOWN, C UP, CMD UP, C UP
-//
-// Because we artificially generate keyup events the C UP event is duplicated
-// as user releases the key after CMD key. This would not be a problem as the
-// receiver end will drop this duplicated keyup event.
-
-#ifndef REMOTING_CLIENT_PLUGIN_MAC_KEY_EVENT_PROCESSOR_H_
-#define REMOTING_CLIENT_PLUGIN_MAC_KEY_EVENT_PROCESSOR_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "remoting/proto/event.pb.h"
-#include "remoting/protocol/input_filter.h"
-
-namespace remoting {
-
-namespace protocol {
-class InputStub;
-}  // namespace protocol
-
-class MacKeyEventProcessor : public protocol::InputFilter {
- public:
-  explicit MacKeyEventProcessor(protocol::InputStub* input_stub);
-  virtual ~MacKeyEventProcessor();
-
-  // InputFilter overrides.
-  virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE;
-
- private:
-  // Generate keyup events for any keys pressed with CMD.
-  void GenerateKeyupEvents();
-
-  // A map that stores pressed keycodes and the corresponding key event.
-  typedef std::map<int, protocol::KeyEvent> KeyPressedMap;
-  KeyPressedMap key_pressed_map_;
-
-  DISALLOW_COPY_AND_ASSIGN(MacKeyEventProcessor);
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_CLIENT_PLUGIN_MAC_KEY_EVENT_PROCESSOR_H_
diff --git a/remoting/client/plugin/mac_key_event_processor_unittest.cc b/remoting/client/plugin/mac_key_event_processor_unittest.cc
deleted file mode 100644
index a2604d5..0000000
--- a/remoting/client/plugin/mac_key_event_processor_unittest.cc
+++ /dev/null
@@ -1,239 +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 "remoting/client/plugin/mac_key_event_processor.h"
-#include "remoting/proto/event.pb.h"
-#include "remoting/protocol/protocol_mock_objects.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::InSequence;
-using remoting::protocol::InputStub;
-using remoting::protocol::KeyEvent;
-using remoting::protocol::MockInputStub;
-using remoting::protocol::MouseEvent;
-
-namespace remoting {
-
-namespace {
-
-const unsigned int kUsbCapsLock   = 0x070039;
-const unsigned int kUsbLeftShift  = 0x0700e1;
-const unsigned int kUsbLeftOption = 0x0700e2;
-const unsigned int kUsbLeftCmd    = 0x0700e3;
-const unsigned int kUsbRightCmd   = 0x0700e7;
-
-// A hardcoded value used to verify |lock_states| is preserved.
-static const uint32 kTestLockStates = protocol::KeyEvent::LOCK_STATES_NUMLOCK;
-
-MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") {
-  return arg.usb_keycode() == static_cast<uint32>(usb_keycode) &&
-         arg.pressed() == pressed &&
-         arg.lock_states() == kTestLockStates;
-}
-
-KeyEvent MakeKeyEvent(uint32 keycode, bool pressed) {
-  KeyEvent event;
-  event.set_usb_keycode(keycode);
-  event.set_pressed(pressed);
-  event.set_lock_states(kTestLockStates);
-  return event;
-}
-
-}  // namespace
-
-// Test CapsLock press/release.
-TEST(MacKeyEventProcessorTest, CapsLock) {
-  MockInputStub stub;
-  MacKeyEventProcessor processor(&stub);
-
-  {
-    InSequence s;
-
-    // Verifies the generated CapsLock up/down events.
-    EXPECT_CALL(stub, InjectKeyEvent(EqualsUsbEvent(kUsbCapsLock, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(EqualsUsbEvent(kUsbCapsLock, false)));
-  }
-
-  // Injecting a CapsLock down event with NumLock on.
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbCapsLock, true));
-}
-
-// Test without pressing command key.
-TEST(MacKeyEventProcessorTest, NoInjection) {
-  MockInputStub stub;
-  MacKeyEventProcessor processor(&stub);
-
-  {
-    InSequence s;
-
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', false)));
-  }
-
-  // C Down and C Up.
-  processor.InjectKeyEvent(MakeKeyEvent('C', true));
-  processor.InjectKeyEvent(MakeKeyEvent('C', false));
-}
-
-// Test pressing command key and other normal keys.
-TEST(MacKeyEventProcessorTest, CmdKey) {
-  MockInputStub stub;
-  MacKeyEventProcessor processor(&stub);
-
-  {
-    InSequence s;
-
-    // Left command key.
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, false)));
-
-    // Right command key.
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbRightCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbRightCmd, false)));
-
-    // More than one keys after CMD.
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbRightCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('V', true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('V', false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbRightCmd, false)));
-  }
-
-  // Left command key.
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent('C', true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
-
-  // Right command key.
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent('C', true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
-
-  // More than one keys after CMD.
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent('C', true));
-  processor.InjectKeyEvent(MakeKeyEvent('V', true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
-}
-
-// Test pressing command and special keys.
-TEST(MacKeyEventProcessorTest, SpecialKeys) {
-  MockInputStub stub;
-  MacKeyEventProcessor processor(&stub);
-
-  {
-    InSequence s;
-
-    // Command + Shift.
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftShift, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftShift, false)));
-
-    // Command + Option.
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftOption, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftOption, false)));
-  }
-
-  // Command + Shift.
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftShift, true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftShift, false));
-
-  // Command + Option.
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftOption, true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftOption, false));
-}
-
-// Test pressing multiple command keys.
-TEST(MacKeyEventProcessorTest, MultipleCmdKeys) {
-  MockInputStub stub;
-  MacKeyEventProcessor processor(&stub);
-
-  {
-    InSequence s;
-
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbRightCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbLeftCmd, false)));
-  }
-
-  // Test multiple CMD keys at the same time.
-  // L CMD Down, C Down, R CMD Down, L CMD Up.
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent('C', true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
-}
-
-// Test press C key before command key.
-TEST(MacKeyEventProcessorTest, BeforeCmdKey) {
-  MockInputStub stub;
-  MacKeyEventProcessor processor(&stub);
-
-  {
-    InSequence s;
-
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbRightCmd, true)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent(kUsbRightCmd, false)));
-    EXPECT_CALL(stub, InjectKeyEvent(
-        EqualsUsbEvent('C', false)));
-  }
-
-  // Press C before command key.
-  processor.InjectKeyEvent(MakeKeyEvent('C', true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
-  processor.InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
-  processor.InjectKeyEvent(MakeKeyEvent('C', false));
-}
-
-}  // namespace remoting
diff --git a/remoting/client/plugin/normalizing_input_filter.cc b/remoting/client/plugin/normalizing_input_filter.cc
new file mode 100644
index 0000000..7206305
--- /dev/null
+++ b/remoting/client/plugin/normalizing_input_filter.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 "remoting/client/plugin/normalizing_input_filter.h"
+
+#include "remoting/protocol/input_filter.h"
+
+namespace remoting {
+
+using protocol::InputFilter;
+using protocol::InputStub;
+
+#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
+scoped_ptr<InputFilter> CreateNormalizingInputFilter(InputStub* input_stub) {
+  return scoped_ptr<InputFilter>(new InputFilter(input_stub));
+}
+#endif // !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
+
+}
diff --git a/remoting/client/plugin/normalizing_input_filter.h b/remoting/client/plugin/normalizing_input_filter.h
new file mode 100644
index 0000000..ebe49fe
--- /dev/null
+++ b/remoting/client/plugin/normalizing_input_filter.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 REMOTING_CLIENT_PLUGIN_NORMALIZING_INPUT_FILTER_H_
+#define REMOTING_CLIENT_PLUGIN_NORMALIZING_INPUT_FILTER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "remoting/protocol/input_filter.h"
+
+namespace remoting {
+
+// Returns an InputFilter which re-writes input events to work around
+// platform-specific behaviours. If no re-writing is required then a
+// pass-through InputFilter is returned.
+scoped_ptr<protocol::InputFilter> CreateNormalizingInputFilter(
+    protocol::InputStub* input_stub);
+
+}  // namespace remoting
+
+#endif  // REMOTING_CLIENT_PLUGIN_NORMALIZING_INPUT_FILTER_H_
diff --git a/remoting/client/plugin/normalizing_input_filter_cros.cc b/remoting/client/plugin/normalizing_input_filter_cros.cc
new file mode 100644
index 0000000..81cec8d
--- /dev/null
+++ b/remoting/client/plugin/normalizing_input_filter_cros.cc
@@ -0,0 +1,206 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// NormalizingInputFilterCros addresses the problems generated by key rewritings
+// such as Down->PageDown, 1->F1, etc, when keys are pressed in combination with
+// the OSKey (aka Search). Rewriting OSKey+Down, for example, causes us to
+// receive the following:
+//
+// keydown OSKey
+// keydown PageDown
+// keyup PageDown
+// keyup OSKey
+//
+// The host system will therefore behave as if OSKey+PageDown were pressed,
+// rather than PageDown alone.
+//
+// This file must be kept up-to-date with changes to
+// chrome/browser/ui/ash/event_rewriter.cc
+
+#include "remoting/client/plugin/normalizing_input_filter.h"
+
+#include "base/logging.h"
+#include "remoting/proto/event.pb.h"
+
+namespace remoting {
+
+namespace {
+
+// Returns true for OSKey codes.
+static bool IsOsKey(unsigned int code) {
+  const unsigned int kUsbLeftOsKey      = 0x0700e3;
+  const unsigned int kUsbRightOsKey     = 0x0700e7;
+  return code == kUsbLeftOsKey || code == kUsbRightOsKey;
+}
+
+// Returns true for codes generated by EventRewriter::RewriteFunctionKeys().
+static bool IsRewrittenFunctionKey(unsigned int code) {
+  const unsigned int kUsbFunctionKeyMin = 0x07003a;
+  const unsigned int kUsbFunctionKeyMax = 0x070045;
+  return code >= kUsbFunctionKeyMin && code <= kUsbFunctionKeyMax;
+}
+
+// Returns true for codes generated by EventRewriter::RewriteExtendedKeys().
+static bool IsRewrittenExtendedKey(unsigned int code) {
+  const unsigned int kUsbExtendedKeyMin = 0x070049;
+  const unsigned int kUsbExtendedKeyMax = 0x07004e;
+  return code >= kUsbExtendedKeyMin && code <= kUsbExtendedKeyMax;
+}
+
+// Returns true for codes generated by EventRewriter::Rewrite().
+static bool IsRewrittenKey(unsigned int code) {
+  return IsRewrittenExtendedKey(code) || IsRewrittenFunctionKey(code);
+}
+
+// The input filter tries to avoid sending keydown/keyup events for OSKey
+// (aka Search, WinKey, Cmd, Super) when it is used to rewrite other key events.
+// Rewriting via other combinations is not currently handled.
+//
+// OSKey events can be categorised as one of three kinds:
+// - Modifying - Holding the key down while executing other input modifies the
+//     effect of that input, e.g. OSKey+L causes the workstation to lock, e.g.
+//     OSKey + mouse-move performs an extended selection.
+// - Rewriting (ChromeOS only) - Holding the key down while pressing certain
+//     keys causes them to be treated as different keys, e.g. OSKey causes the
+//     Down key to behave as PageDown.
+// - Normal - Press & release of the key trigger an action, e.g. showing the
+//     Start menu.
+//
+// The input filter has four states:
+// 1. No OSKey has been pressed.
+//    - When an OSKey keydown is received, the event is deferred, and we move to
+//      State #2.
+// 2. An OSKey is pressed, but may be Normal, Rewriting or Modifying.
+//    - If the OSKey keyup is received, the key is Normal, both events are sent
+//      and we return to State #1.
+//    - If a Rewritten event is received we move to State #3.
+//    - If a Modified event is received the OSKey keydown is sent and we enter
+//      State #4.
+// 3. An OSKey is pressed, and is being used to Rewrite other key events.
+//    - If the OSKey keyup is received then it is suppressed, and we move to
+//      State #1.
+//    - If a Modified event is received the OSKey keydown is sent and we enter
+//      State #4.
+//    - If a Rewritten event is received then we stay in State #3.
+// 4. An OSKey is pressed, and is Modifying.
+//    - If the OSKey keyup is received then we send it and we move to State #1.
+//    - All other key event pass through the filter unchanged.
+
+class NormalizingInputFilterCros : public protocol::InputFilter {
+ public:
+  explicit NormalizingInputFilterCros(protocol::InputStub* input_stub)
+      : protocol::InputFilter(input_stub),
+        deferred_key_is_rewriting_(false),
+        modifying_key_(0) {
+  }
+  virtual ~NormalizingInputFilterCros() {}
+
+  // InputFilter overrides.
+  virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE {
+    DCHECK(event.has_usb_keycode());
+    DCHECK(event.has_pressed());
+
+    if (event.pressed())
+      ProcessKeyDown(event);
+    else
+      ProcessKeyUp(event);
+  }
+
+  virtual void InjectMouseEvent(const protocol::MouseEvent& event) OVERRIDE {
+    if (deferred_keydown_event_.has_usb_keycode())
+      SwitchRewritingKeyToModifying();
+    InputFilter::InjectMouseEvent(event);
+  }
+
+ private:
+  void ProcessKeyDown(const protocol::KeyEvent& event) {
+    // If |event| is |deferred_keydown_event_| auto-repeat then assume
+    // that the user is holding the key down rather than using it to Rewrite.
+    if (deferred_keydown_event_.has_usb_keycode() &&
+        deferred_keydown_event_.usb_keycode() == event.usb_keycode()) {
+      SwitchRewritingKeyToModifying();
+    }
+
+    // If |event| is a |modifying_key_| repeat then let it pass through.
+    if (modifying_key_ == event.usb_keycode()) {
+      InputFilter::InjectKeyEvent(event);
+      return;
+    }
+
+    // If |event| is for an OSKey and we don't know whether it's a Normal,
+    // Rewriting or Modifying use, then hold the keydown event.
+    if (IsOsKey(event.usb_keycode())) {
+      deferred_keydown_event_ = event;
+      deferred_key_is_rewriting_ = false;
+      return;
+    }
+
+    // If |event| is for a Rewritten key then set a flag to prevent any deferred
+    // OSKey keydown from being sent when keyup is received for it. Otherwise,
+    // inject the deferred OSKey keydown, if any, and switch that key into
+    // Modifying mode.
+    if (IsRewrittenKey(event.usb_keycode())) {
+      // Note that there may not be a deferred OSKey event if there is a full
+      // PC keyboard connected, which can generate e.g. PageDown without
+      // rewriting.
+      deferred_key_is_rewriting_ = true;
+    } else {
+      if (deferred_keydown_event_.has_usb_keycode())
+        SwitchRewritingKeyToModifying();
+    }
+
+    InputFilter::InjectKeyEvent(event);
+  }
+
+  void ProcessKeyUp(const protocol::KeyEvent& event) {
+    if (deferred_keydown_event_.has_usb_keycode() &&
+        deferred_keydown_event_.usb_keycode() == event.usb_keycode()) {
+      if (deferred_key_is_rewriting_) {
+        // If we never sent the keydown then don't send a keyup.
+        deferred_keydown_event_ = protocol::KeyEvent();
+        return;
+      }
+
+      // If the OSKey hasn't Rewritten anything then treat as Modifying.
+      SwitchRewritingKeyToModifying();
+    }
+
+    if (modifying_key_ == event.usb_keycode())
+      modifying_key_ = 0;
+
+    InputFilter::InjectKeyEvent(event);
+  }
+
+  void SwitchRewritingKeyToModifying() {
+    DCHECK(deferred_keydown_event_.has_usb_keycode());
+    modifying_key_ = deferred_keydown_event_.usb_keycode();
+    InputFilter::InjectKeyEvent(deferred_keydown_event_);
+    deferred_keydown_event_ = protocol::KeyEvent();
+  }
+
+  // Holds the keydown event for the most recent OSKey to have been pressed,
+  // while it is Rewriting, or we are not yet sure whether it is Normal,
+  // Rewriting or Modifying. The event is sent on if we switch to Modifying, or
+  // discarded if the OSKey is released while in Rewriting mode.
+  protocol::KeyEvent deferred_keydown_event_;
+
+  // True while the |rewrite_keydown_event_| key is Rewriting, i.e. was followed
+  // by one or more Rewritten key events, and not by any Modified events.
+  bool deferred_key_is_rewriting_;
+
+  // Stores the code of the OSKey while it is pressed for use as a Modifier.
+  uint32 modifying_key_;
+
+  DISALLOW_COPY_AND_ASSIGN(NormalizingInputFilterCros);
+};
+
+}  // namespace
+
+scoped_ptr<protocol::InputFilter> CreateNormalizingInputFilter(
+    protocol::InputStub* input_stub) {
+  return scoped_ptr<protocol::InputFilter>(
+      new NormalizingInputFilterCros(input_stub));
+}
+
+}  // namespace remoting
diff --git a/remoting/client/plugin/normalizing_input_filter_cros_unittest.cc b/remoting/client/plugin/normalizing_input_filter_cros_unittest.cc
new file mode 100644
index 0000000..cf46d16
--- /dev/null
+++ b/remoting/client/plugin/normalizing_input_filter_cros_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 "remoting/client/plugin/normalizing_input_filter.h"
+#include "remoting/proto/event.pb.h"
+#include "remoting/protocol/protocol_mock_objects.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InSequence;
+using remoting::protocol::InputStub;
+using remoting::protocol::KeyEvent;
+using remoting::protocol::MockInputStub;
+using remoting::protocol::MouseEvent;
+
+namespace remoting {
+
+namespace {
+
+const unsigned int kUsbLeftOsKey      = 0x0700e3;
+const unsigned int kUsbRightOsKey     = 0x0700e7;
+
+const unsigned int kUsbFunctionKey    = 0x07003a; // F1
+const unsigned int kUsbExtendedKey    = 0x070049; // Insert
+const unsigned int kUsbOtherKey       = 0x07002b; // Tab
+
+// A hardcoded value used to verify |lock_states| is preserved.
+static const uint32 kTestLockStates = protocol::KeyEvent::LOCK_STATES_NUMLOCK;
+
+MATCHER_P2(EqualsKeyEvent, usb_keycode, pressed, "") {
+  return arg.usb_keycode() == static_cast<uint32>(usb_keycode) &&
+         arg.pressed() == pressed &&
+         arg.lock_states() == kTestLockStates;
+}
+
+KeyEvent MakeKeyEvent(uint32 keycode, bool pressed) {
+  KeyEvent event;
+  event.set_usb_keycode(keycode);
+  event.set_pressed(pressed);
+  event.set_lock_states(kTestLockStates);
+  return event;
+}
+
+void PressAndReleaseKey(InputStub* input_stub, uint32 keycode) {
+  input_stub->InjectKeyEvent(MakeKeyEvent(keycode, true));
+  input_stub->InjectKeyEvent(MakeKeyEvent(keycode, false));
+}
+
+MATCHER_P2(EqualsMouseMoveEvent, x, y, "") {
+  return arg.x() == x && arg.y() == y;
+}
+
+static MouseEvent MakeMouseMoveEvent(int x, int y) {
+  MouseEvent event;
+  event.set_x(x);
+  event.set_y(y);
+  return event;
+}
+
+}  // namespace
+
+// Test OSKey press/release.
+TEST(NormalizingInputFilterCrosTest, PressReleaseOsKey) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false)));
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbRightOsKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbRightOsKey, false)));
+  }
+
+  // Inject press & release events for left & right OSKeys.
+  PressAndReleaseKey(processor.get(), kUsbLeftOsKey);
+  PressAndReleaseKey(processor.get(), kUsbRightOsKey);
+}
+
+// Test OSKey key repeat switches it to "modifying" mode.
+TEST(NormalizingInputFilterCrosTest, OSKeyRepeats) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true)));
+  }
+
+  // Inject a press and repeats for the left OSKey, but don't release it, and
+  // verify that the repeats result in press events.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+}
+
+// Test OSKey press followed by function key press and release results in
+// just the function key events.
+TEST(NormalizingInputFilterCrosTest, FunctionKey) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbFunctionKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbFunctionKey, false)));
+  }
+
+  // Hold the left OSKey while pressing & releasing the function key.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+  PressAndReleaseKey(processor.get(), kUsbFunctionKey);
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false));
+}
+
+// Test OSKey press followed by extended key press and release results in
+// just the function key events.
+TEST(NormalizingInputFilterCrosTest, ExtendedKey) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, false)));
+  }
+
+  // Hold the left OSKey while pressing & releasing the function key.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+  PressAndReleaseKey(processor.get(), kUsbExtendedKey);
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false));
+}
+
+// Test OSKey press followed by non-function, non-extended key press and release
+// results in normal-looking sequence.
+TEST(NormalizingInputFilterCrosTest, OtherKey) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, false)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false)));
+  }
+
+  // Hold the left OSKey while pressing & releasing the function key.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+  PressAndReleaseKey(processor.get(), kUsbOtherKey);
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false));
+}
+
+// Test OSKey press followed by extended key press, then normal key press
+// results in OSKey switching to modifying mode for the normal key.
+TEST(NormalizingInputFilterCrosTest, ExtendedThenOtherKey) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbExtendedKey, false)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbOtherKey, false)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false)));
+  }
+
+  // Hold the left OSKey while pressing & releasing the function key.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+  PressAndReleaseKey(processor.get(), kUsbExtendedKey);
+  PressAndReleaseKey(processor.get(), kUsbOtherKey);
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false));
+}
+
+// Test OSKey press followed by mouse event puts the OSKey into modifying mode.
+TEST(NormalizingInputFilterCrosTest, MouseEvent) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, true)));
+    EXPECT_CALL(stub, InjectMouseEvent(EqualsMouseMoveEvent(0, 0)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsKeyEvent(kUsbLeftOsKey, false)));
+  }
+
+  // Hold the left OSKey while pressing & releasing the function key.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, true));
+  processor->InjectMouseEvent(MakeMouseMoveEvent(0, 0));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOsKey, false));
+}
+
+}  // namespace remoting
diff --git a/remoting/client/plugin/normalizing_input_filter_mac.cc b/remoting/client/plugin/normalizing_input_filter_mac.cc
new file mode 100644
index 0000000..56b327e
--- /dev/null
+++ b/remoting/client/plugin/normalizing_input_filter_mac.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.
+
+// NormalizingInputFilterMac is designed to solve the problem of missing keyup
+// events on Mac.
+//
+// PROBLEM
+//
+// On Mac if user presses CMD and then C key there is no keyup event generated
+// for C when user releases the C key before the CMD key.
+// The cause is that CMD + C triggers a system action and Chrome injects only a
+// keydown event for the C key. Safari shares the same behavior.
+//
+// SOLUTION
+//
+// When a keyup event for CMD key happens we will check all prior keydown
+// events received and inject corresponding keyup events artificially, with
+// the exception of:
+//
+// SHIFT, CONTROL, OPTION, LEFT CMD, RIGHT CMD and CAPS LOCK
+//
+// because they are reported by Chrome correctly.
+//
+// There are a couple cases that this solution doesn't work perfectly, one
+// of them leads to duplicated keyup events.
+//
+// User performs this sequence of actions:
+//
+// CMD DOWN, C DOWN, CMD UP, C UP
+//
+// In this case the algorithm will generate:
+//
+// CMD DOWN, C DOWN, C UP, CMD UP, C UP
+//
+// Because we artificially generate keyup events the C UP event is duplicated
+// as user releases the key after CMD key. This would not be a problem as the
+// receiver end will drop this duplicated keyup event.
+
+#include "remoting/client/plugin/normalizing_input_filter.h"
+
+#include <map>
+#include <vector>
+
+#include "base/logging.h"
+#include "remoting/proto/event.pb.h"
+
+namespace remoting {
+
+namespace {
+
+const unsigned int kUsbCapsLock     = 0x070039;
+const unsigned int kUsbLeftControl  = 0x0700e0;
+const unsigned int kUsbLeftShift    = 0x0700e1;
+const unsigned int kUsbLeftOption   = 0x0700e2;
+const unsigned int kUsbLeftCmd      = 0x0700e3;
+const unsigned int kUsbRightControl = 0x0700e4;
+const unsigned int kUsbRightShift   = 0x0700e5;
+const unsigned int kUsbRightOption  = 0x0700e6;
+const unsigned int kUsbRightCmd     = 0x0700e7;
+const unsigned int kUsbTab          = 0x07002b;
+
+}  // namespace
+
+class NormalizingInputFilterMac : public protocol::InputFilter {
+ public:
+  explicit NormalizingInputFilterMac(protocol::InputStub* input_stub);
+  virtual ~NormalizingInputFilterMac() {}
+
+  // InputFilter overrides.
+  virtual void InjectKeyEvent(const protocol::KeyEvent& event) OVERRIDE;
+
+ private:
+  // Generate keyup events for any keys pressed with CMD.
+  void GenerateKeyupEvents();
+
+  // A map that stores pressed keycodes and the corresponding key event.
+  typedef std::map<int, protocol::KeyEvent> KeyPressedMap;
+  KeyPressedMap key_pressed_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(NormalizingInputFilterMac);
+};
+
+NormalizingInputFilterMac::NormalizingInputFilterMac(
+    protocol::InputStub* input_stub)
+    : protocol::InputFilter(input_stub) {
+}
+
+void NormalizingInputFilterMac::InjectKeyEvent(const protocol::KeyEvent& event)
+{
+  DCHECK(event.has_usb_keycode());
+
+  bool is_special_key = event.usb_keycode() == kUsbLeftControl ||
+      event.usb_keycode() == kUsbLeftShift ||
+      event.usb_keycode() == kUsbLeftOption ||
+      event.usb_keycode() == kUsbRightControl ||
+      event.usb_keycode() == kUsbRightShift ||
+      event.usb_keycode() == kUsbRightOption ||
+      event.usb_keycode() == kUsbTab;
+
+  bool is_cmd_key = event.usb_keycode() == kUsbLeftCmd ||
+      event.usb_keycode() == kUsbRightCmd;
+
+  if (event.usb_keycode() == kUsbCapsLock) {
+    // Mac OS X generates keydown/keyup on lock-state transitions, rather than
+    // when the key is pressed & released, so fake keydown/keyup on each event.
+    protocol::KeyEvent newEvent(event);
+
+    newEvent.set_pressed(true);
+    InputFilter::InjectKeyEvent(newEvent);
+    newEvent.set_pressed(false);
+    InputFilter::InjectKeyEvent(newEvent);
+
+    return;
+  } else if (!is_cmd_key && !is_special_key) {
+    // Track keydown/keyup events for non-modifiers, so we can release them if
+    // necessary (see below).
+    if (event.pressed()) {
+      key_pressed_map_[event.usb_keycode()] = event;
+    } else {
+      key_pressed_map_.erase(event.usb_keycode());
+    }
+  }
+
+  if (is_cmd_key && !event.pressed()) {
+    // Mac OS X will not generate release events for keys pressed while Cmd is
+    // pressed, so release all pressed keys when Cmd is released.
+    GenerateKeyupEvents();
+  }
+
+  InputFilter::InjectKeyEvent(event);
+}
+
+void NormalizingInputFilterMac::GenerateKeyupEvents() {
+  for (KeyPressedMap::iterator i = key_pressed_map_.begin();
+       i != key_pressed_map_.end(); ++i) {
+    // The generated key up event will have the same key code and lock states
+    // as the original key down event.
+    protocol::KeyEvent event = i->second;
+    event.set_pressed(false);
+    InputFilter::InjectKeyEvent(event);
+  }
+
+  // Clearing the map now that we have released all the pressed keys.
+  key_pressed_map_.clear();
+}
+
+scoped_ptr<protocol::InputFilter> CreateNormalizingInputFilter(
+    protocol::InputStub* input_stub) {
+  return scoped_ptr<protocol::InputFilter>(
+      new NormalizingInputFilterMac(input_stub));
+}
+
+}  // namespace remoting
diff --git a/remoting/client/plugin/normalizing_input_filter_mac_unittest.cc b/remoting/client/plugin/normalizing_input_filter_mac_unittest.cc
new file mode 100644
index 0000000..8221223
--- /dev/null
+++ b/remoting/client/plugin/normalizing_input_filter_mac_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright 2013 The Chromium Authors. 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/client/plugin/normalizing_input_filter.h"
+#include "remoting/proto/event.pb.h"
+#include "remoting/protocol/protocol_mock_objects.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InSequence;
+using remoting::protocol::InputStub;
+using remoting::protocol::KeyEvent;
+using remoting::protocol::MockInputStub;
+using remoting::protocol::MouseEvent;
+
+namespace remoting {
+
+namespace {
+
+const unsigned int kUsbCapsLock   = 0x070039;
+const unsigned int kUsbLeftShift  = 0x0700e1;
+const unsigned int kUsbLeftOption = 0x0700e2;
+const unsigned int kUsbLeftCmd    = 0x0700e3;
+const unsigned int kUsbRightCmd   = 0x0700e7;
+
+// A hardcoded value used to verify |lock_states| is preserved.
+static const uint32 kTestLockStates = protocol::KeyEvent::LOCK_STATES_NUMLOCK;
+
+MATCHER_P2(EqualsUsbEvent, usb_keycode, pressed, "") {
+  return arg.usb_keycode() == static_cast<uint32>(usb_keycode) &&
+         arg.pressed() == pressed &&
+         arg.lock_states() == kTestLockStates;
+}
+
+KeyEvent MakeKeyEvent(uint32 keycode, bool pressed) {
+  KeyEvent event;
+  event.set_usb_keycode(keycode);
+  event.set_pressed(pressed);
+  event.set_lock_states(kTestLockStates);
+  return event;
+}
+
+}  // namespace
+
+// Test CapsLock press/release.
+TEST(NormalizingInputFilterMacTest, CapsLock) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    // Verifies the generated CapsLock up/down events.
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsUsbEvent(kUsbCapsLock, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(EqualsUsbEvent(kUsbCapsLock, false)));
+  }
+
+  // Injecting a CapsLock down event with NumLock on.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbCapsLock, true));
+}
+
+// Test without pressing command key.
+TEST(NormalizingInputFilterMacTest, NoInjection) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', false)));
+  }
+
+  // C Down and C Up.
+  processor->InjectKeyEvent(MakeKeyEvent('C', true));
+  processor->InjectKeyEvent(MakeKeyEvent('C', false));
+}
+
+// Test pressing command key and other normal keys.
+TEST(NormalizingInputFilterMacTest, CmdKey) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    // Left command key.
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, false)));
+
+    // Right command key.
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbRightCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbRightCmd, false)));
+
+    // More than one keys after CMD.
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbRightCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('V', true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('V', false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbRightCmd, false)));
+  }
+
+  // Left command key.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent('C', true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
+
+  // Right command key.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent('C', true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
+
+  // More than one keys after CMD.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent('C', true));
+  processor->InjectKeyEvent(MakeKeyEvent('V', true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
+}
+
+// Test pressing command and special keys.
+TEST(NormalizingInputFilterMacTest, SpecialKeys) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    // Command + Shift.
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftShift, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftShift, false)));
+
+    // Command + Option.
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftOption, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftOption, false)));
+  }
+
+  // Command + Shift.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftShift, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftShift, false));
+
+  // Command + Option.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOption, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftOption, false));
+}
+
+// Test pressing multiple command keys.
+TEST(NormalizingInputFilterMacTest, MultipleCmdKeys) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbRightCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbLeftCmd, false)));
+  }
+
+  // Test multiple CMD keys at the same time.
+  // L CMD Down, C Down, R CMD Down, L CMD Up.
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent('C', true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbLeftCmd, false));
+}
+
+// Test press C key before command key.
+TEST(NormalizingInputFilterMacTest, BeforeCmdKey) {
+  MockInputStub stub;
+  scoped_ptr<protocol::InputFilter> processor =
+      CreateNormalizingInputFilter(&stub);
+
+  {
+    InSequence s;
+
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbRightCmd, true)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent(kUsbRightCmd, false)));
+    EXPECT_CALL(stub, InjectKeyEvent(
+        EqualsUsbEvent('C', false)));
+  }
+
+  // Press C before command key.
+  processor->InjectKeyEvent(MakeKeyEvent('C', true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, true));
+  processor->InjectKeyEvent(MakeKeyEvent(kUsbRightCmd, false));
+  processor->InjectKeyEvent(MakeKeyEvent('C', false));
+}
+
+}  // namespace remoting
diff --git a/remoting/client/plugin/pepper_entrypoints.cc b/remoting/client/plugin/pepper_entrypoints.cc
index 84ba6b8..c6923e3 100644
--- a/remoting/client/plugin/pepper_entrypoints.cc
+++ b/remoting/client/plugin/pepper_entrypoints.cc
@@ -36,16 +36,15 @@
 int32_t PPP_InitializeModule(PP_Module module_id,
                              PPB_GetInterface get_browser_interface) {
   ChromotingModule* module = new ChromotingModule();
-  if (!module)
-    return PP_ERROR_FAILED;
-
   if (!module->InternalInit(module_id, get_browser_interface)) {
     delete module;
     return PP_ERROR_FAILED;
   }
 
-  // Register a global log handler.
+#if !defined(NDEBUG)
+  // Register a global log handler, but only in Debug builds.
   ChromotingInstance::RegisterLogMessageHandler();
+#endif
 
   g_module_singleton = module;
   return PP_OK;
diff --git a/remoting/client/plugin/pepper_signal_strategy.cc b/remoting/client/plugin/pepper_signal_strategy.cc
deleted file mode 100644
index 3e8f675..0000000
--- a/remoting/client/plugin/pepper_signal_strategy.cc
+++ /dev/null
@@ -1,74 +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 "remoting/client/plugin/pepper_signal_strategy.h"
-
-#include "base/strings/string_number_conversions.h"
-#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
-
-namespace remoting {
-
-PepperSignalStrategy::PepperSignalStrategy(
-    std::string local_jid,
-    const SendIqCallback& send_iq_callback)
-    : local_jid_(local_jid),
-      send_iq_callback_(send_iq_callback),
-      last_id_(0) {
-}
-
-PepperSignalStrategy::~PepperSignalStrategy() {
-}
-
-void PepperSignalStrategy::OnIncomingMessage(const std::string& message) {
- scoped_ptr<buzz::XmlElement> stanza(buzz::XmlElement::ForStr(message));
-  if (!stanza.get()) {
-    LOG(WARNING) << "Malformed XMPP stanza received: " << message;
-    return;
-  }
-
-  ObserverListBase<Listener>::Iterator it(listeners_);
-  Listener* listener;
-  while ((listener = it.GetNext()) != NULL) {
-    if (listener->OnSignalStrategyIncomingStanza(stanza.get()))
-      break;
-  }
-}
-
-void PepperSignalStrategy::Connect() {
-}
-
-void PepperSignalStrategy::Disconnect() {
-}
-
-SignalStrategy::State PepperSignalStrategy::GetState() const {
-  return CONNECTED;
-}
-
-SignalStrategy::Error PepperSignalStrategy::GetError() const {
-  return OK;
-}
-
-std::string PepperSignalStrategy::GetLocalJid() const {
-  return local_jid_;
-}
-
-void PepperSignalStrategy::AddListener(Listener* listener) {
-  listeners_.AddObserver(listener);
-}
-
-void PepperSignalStrategy::RemoveListener(Listener* listener) {
-  listeners_.RemoveObserver(listener);
-}
-
-bool PepperSignalStrategy::SendStanza(scoped_ptr<buzz::XmlElement> stanza) {
-  send_iq_callback_.Run(stanza->Str());
-  return true;
-}
-
-std::string PepperSignalStrategy::GetNextId() {
-  ++last_id_;
-  return base::IntToString(last_id_);
-}
-
-}  // namespace remoting
diff --git a/remoting/client/plugin/pepper_signal_strategy.h b/remoting/client/plugin/pepper_signal_strategy.h
deleted file mode 100644
index f5fab46..0000000
--- a/remoting/client/plugin/pepper_signal_strategy.h
+++ /dev/null
@@ -1,52 +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 REMOTING_CLIENT_PLUGIN_PEPPER_XMPP_PROXY_H_
-#define REMOTING_CLIENT_PLUGIN_PEPPER_XMPP_PROXY_H_
-
-#include "base/callback.h"
-#include "base/observer_list.h"
-#include "remoting/jingle_glue/signal_strategy.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
-
-namespace remoting {
-
-class PepperSignalStrategy : public SignalStrategy {
- public:
-  typedef base::Callback<void(const std::string&)> SendIqCallback;
-
-  PepperSignalStrategy(std::string local_jid,
-                       const SendIqCallback& send_iq_callback);
-  virtual ~PepperSignalStrategy();
-
-  void OnIncomingMessage(const std::string& message);
-
-  // SignalStrategy interface.
-  virtual void Connect() OVERRIDE;
-  virtual void Disconnect() OVERRIDE;
-  virtual State GetState() const OVERRIDE;
-  virtual Error GetError() const OVERRIDE;
-  virtual std::string GetLocalJid() const OVERRIDE;
-  virtual void AddListener(Listener* listener) OVERRIDE;
-  virtual void RemoveListener(Listener* listener) OVERRIDE;
-  virtual bool SendStanza(scoped_ptr<buzz::XmlElement> stanza) OVERRIDE;
-  virtual std::string GetNextId() OVERRIDE;
-
- private:
-  std::string local_jid_;
-  SendIqCallback send_iq_callback_;
-
-  ObserverList<Listener> listeners_;
-
-  int last_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(PepperSignalStrategy);
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_CLIENT_PLUGIN_PEPPER_XMPP_PROXY_H_
diff --git a/remoting/codec/codec_test.cc b/remoting/codec/codec_test.cc
index 3d1d774..eff143d 100644
--- a/remoting/codec/codec_test.cc
+++ b/remoting/codec/codec_test.cc
@@ -140,7 +140,8 @@
       : screen_size_(screen_size),
         view_size_(view_size),
         strict_(false),
-        decoder_(decoder) {
+        decoder_(decoder),
+        frame_(NULL) {
     image_data_.reset(new uint8[
         view_size_.width() * view_size_.height() * kBytesPerPixel]);
     EXPECT_TRUE(image_data_.get());
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
index 82f0d6e..d7780f1 100644
--- a/remoting/host/chromoting_host.cc
+++ b/remoting/host/chromoting_host.cc
@@ -109,13 +109,13 @@
     FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnShutdown());
 }
 
-void ChromotingHost::Start(const std::string& xmpp_login) {
+void ChromotingHost::Start(const std::string& host_owner) {
   DCHECK(CalledOnValidThread());
   DCHECK(!started_);
 
   LOG(INFO) << "Starting host";
   started_ = true;
-  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(xmpp_login));
+  FOR_EACH_OBSERVER(HostStatusObserver, status_observers_, OnStart(host_owner));
 
   // Start the SessionManager, supplying this ChromotingHost as the listener.
   session_manager_->Init(signal_strategy_, this);
diff --git a/remoting/host/chromoting_host.h b/remoting/host/chromoting_host.h
index 614b466..ee4c587 100644
--- a/remoting/host/chromoting_host.h
+++ b/remoting/host/chromoting_host.h
@@ -86,7 +86,7 @@
   // network and start listening for incoming connections.
   //
   // This method can only be called once during the lifetime of this object.
-  void Start(const std::string& xmpp_login);
+  void Start(const std::string& host_owner);
 
   // HostStatusMonitor interface.
   virtual void AddStatusObserver(HostStatusObserver* observer) OVERRIDE;
diff --git a/remoting/host/chromoting_host_context.cc b/remoting/host/chromoting_host_context.cc
index aa3146c..350404b 100644
--- a/remoting/host/chromoting_host_context.cc
+++ b/remoting/host/chromoting_host_context.cc
@@ -40,7 +40,7 @@
       "ChromotingEncodeThread", ui_task_runner_);
 
   url_request_context_getter_ = new URLRequestContextGetter(
-      ui_task_runner_, network_task_runner_);
+      network_task_runner_);
 }
 
 ChromotingHostContext::~ChromotingHostContext() {
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index 933ded3..b001a39 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -177,7 +177,7 @@
 
 void ClientSession::RequestPairing(
     const protocol::PairingRequest& pairing_request) {
-  if (pairing_request.has_client_name()) {
+  if (pairing_registry_ && pairing_request.has_client_name()) {
     protocol::PairingRegistry::Pairing pairing =
         pairing_registry_->CreatePairing(pairing_request.client_name());
     protocol::PairingResponse pairing_response;
diff --git a/remoting/host/constants_mac.cc b/remoting/host/constants_mac.cc
index 9b79384..3b48ca0 100644
--- a/remoting/host/constants_mac.cc
+++ b/remoting/host/constants_mac.cc
@@ -36,6 +36,10 @@
 const char kLogFilePath[] = LOG_DIR SERVICE_NAME ".log";
 const char kLogFileConfigPath[] = LOG_CONFIG_DIR SERVICE_NAME ".conf";
 
+const char kNativeMessagingManifestPath[] =
+    "/Library/Google/Chrome/NativeMessagingHosts/"
+    "com.google.chrome.remote_desktop.json";
+
 const char kBrandedUninstallerPath[] = APPLICATIONS_DIR
     "Chrome Remote Desktop Host Uninstaller.app";
 const char kUnbrandedUninstallerPath[] = APPLICATIONS_DIR
diff --git a/remoting/host/constants_mac.h b/remoting/host/constants_mac.h
index ac288e5..5d131d2 100644
--- a/remoting/host/constants_mac.h
+++ b/remoting/host/constants_mac.h
@@ -52,6 +52,9 @@
 // Path to the log config file
 extern const char kLogFileConfigPath[];
 
+// Path to the native messaging host manifest
+extern const char kNativeMessagingManifestPath[];
+
 // The branded and unbranded names for the uninstaller.
 // This is the only file that changes names based on branding. We define both
 // because we want local dev builds to be able to clean up both files.
diff --git a/remoting/host/host_config.cc b/remoting/host/host_config.cc
index 94b5d49b..e812843 100644
--- a/remoting/host/host_config.cc
+++ b/remoting/host/host_config.cc
@@ -7,6 +7,7 @@
 namespace remoting {
 
 const char kHostEnabledConfigPath[] = "enabled";
+const char kHostOwnerConfigPath[] = "host_owner";
 const char kXmppLoginConfigPath[] = "xmpp_login";
 const char kXmppAuthTokenConfigPath[] = "xmpp_auth_token";
 const char kOAuthRefreshTokenConfigPath[] = "oauth_refresh_token";
diff --git a/remoting/host/host_config.h b/remoting/host/host_config.h
index a8233b5..5bd5c5c 100644
--- a/remoting/host/host_config.h
+++ b/remoting/host/host_config.h
@@ -19,6 +19,8 @@
 
 // Status of the host, whether it is enabled or disabled.
 extern const char kHostEnabledConfigPath[];
+// Google account of the owner of this host.
+extern const char kHostOwnerConfigPath[];
 // Login used to authenticate in XMPP network.
 extern const char kXmppLoginConfigPath[];
 // Auth token used to authenticate to XMPP network.
diff --git a/remoting/host/host_main.cc b/remoting/host/host_main.cc
index 25e01e6..bf3dc17 100644
--- a/remoting/host/host_main.cc
+++ b/remoting/host/host_main.cc
@@ -234,14 +234,15 @@
     // missing and the first argument looks like an origin that represents
     // an extension.
     CommandLine::StringVector args = command_line->GetArgs();
+    if (!args.empty()) {
 #if defined(OS_WIN)
-    std::string origin = UTF16ToUTF8(args[0]);
+      std::string origin = UTF16ToUTF8(args[0]);
 #else
-    std::string origin = args[0];
+      std::string origin = args[0];
 #endif
-    if (!args.empty() &&
-        StartsWithASCII(origin, kExtensionOriginPrefix, true)) {
-      process_type = kProcessTypeNativeMessagingHost;
+      if (StartsWithASCII(origin, kExtensionOriginPrefix, true)) {
+        process_type = kProcessTypeNativeMessagingHost;
+      }
     }
   }
 
diff --git a/remoting/host/installer/linux/Makefile b/remoting/host/installer/linux/Makefile
index 9fc36be..dd45d26 100644
--- a/remoting/host/installer/linux/Makefile
+++ b/remoting/host/installer/linux/Makefile
@@ -11,7 +11,6 @@
 
 INSTALL_DIR = $(DESTDIR)/opt/google/chrome-remote-desktop
 CHROME_MANIFEST_DIR = $(DESTDIR)/etc/opt/chrome/native-messaging-hosts
-MANIFEST = $(CHROME_MANIFEST_DIR)/com.google.chrome.remote_desktop.json
 
 ME2ME_PROGNAME = $(RELEASE)/remoting_me2me_host
 ME2ME_DEBUGFILE = $(ME2ME_PROGNAME).debug
@@ -30,8 +29,8 @@
 	  "$(INSTALL_DIR)/chrome-remote-desktop"
 	install "$(TOOLS)/is-remoting-session" "$(INSTALL_DIR)"
 
-	install -T "$(RELEASE)/remoting/native_messaging_manifest.json" \
-	  -m 0644 "$(MANIFEST)"
+	install "$(RELEASE)/remoting/com.google.chrome.remote_desktop.json" \
+	  -m 0644 "$(CHROME_MANIFEST_DIR)"
 
 	eu-strip -f "$(ME2ME_DEBUGFILE)" "$(ME2ME_PROGNAME)"
 	install "$(ME2ME_PROGNAME)" \
diff --git a/remoting/host/installer/mac/ChromotingHostService.pkgproj b/remoting/host/installer/mac/ChromotingHostService.pkgproj
index bc036f8..72ced50 100644
--- a/remoting/host/installer/mac/ChromotingHostService.pkgproj
+++ b/remoting/host/installer/mac/ChromotingHostService.pkgproj
@@ -164,6 +164,73 @@
 							</dict>
 							<dict>
 								<key>CHILDREN</key>
+								<array>
+									<dict>
+										<key>CHILDREN</key>
+										<array>
+											<dict>
+												<key>CHILDREN</key>
+												<array>
+													<dict>
+														<key>CHILDREN</key>
+														<array/>
+														<key>GID</key>
+														<integer>0</integer>
+														<key>PATH</key>
+														<string>Config/com.google.chrome.remote_desktop.json</string>
+														<key>PATH_TYPE</key>
+														<integer>1</integer>
+														<key>PERMISSIONS</key>
+														<integer>420</integer>
+														<key>TYPE</key>
+														<integer>3</integer>
+														<key>UID</key>
+														<integer>0</integer>
+													</dict>
+												</array>
+												<key>GID</key>
+												<integer>0</integer>
+												<key>PATH</key>
+												<string>NativeMessagingHosts</string>
+												<key>PATH_TYPE</key>
+												<integer>0</integer>
+												<key>PERMISSIONS</key>
+												<integer>493</integer>
+												<key>TYPE</key>
+												<integer>2</integer>
+												<key>UID</key>
+												<integer>0</integer>
+											</dict>
+										</array>
+										<key>GID</key>
+										<integer>0</integer>
+										<key>PATH</key>
+										<string>Chrome</string>
+										<key>PATH_TYPE</key>
+										<integer>0</integer>
+										<key>PERMISSIONS</key>
+										<integer>493</integer>
+										<key>TYPE</key>
+										<integer>2</integer>
+										<key>UID</key>
+										<integer>0</integer>
+									</dict>
+								</array>
+								<key>GID</key>
+								<integer>0</integer>
+								<key>PATH</key>
+								<string>Google</string>
+								<key>PATH_TYPE</key>
+								<integer>0</integer>
+								<key>PERMISSIONS</key>
+								<integer>493</integer>
+								<key>TYPE</key>
+								<integer>2</integer>
+								<key>UID</key>
+								<integer>0</integer>
+							</dict>
+							<dict>
+								<key>CHILDREN</key>
 								<array/>
 								<key>GID</key>
 								<integer>0</integer>
diff --git a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
index eb984d1..eec5e58 100644
--- a/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
+++ b/remoting/host/installer/mac/uninstaller/remoting_uninstaller.mm
@@ -143,6 +143,7 @@
   [self sudoDelete:remoting::kPrefPaneFilePath usingAuth:authRef];
   [self sudoDelete:remoting::kLogFilePath usingAuth:authRef];
   [self sudoDelete:remoting::kLogFileConfigPath usingAuth:authRef];
+  [self sudoDelete:remoting::kNativeMessagingManifestPath usingAuth:authRef];
   [self sudoDelete:remoting::kBrandedUninstallerPath usingAuth:authRef];
   [self sudoDelete:remoting::kUnbrandedUninstallerPath usingAuth:authRef];
 
diff --git a/remoting/host/keygen_main.cc b/remoting/host/keygen_main.cc
deleted file mode 100644
index 9102756..0000000
--- a/remoting/host/keygen_main.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.
-//
-// This is a tool used by register_host.py to generate RSA keypair. It just
-// generates new keys and prints them on stdout.
-//
-// This code will need to be integrated with the host registration UI.
-
-#include <stdio.h>
-
-#include <vector>
-
-#include "base/at_exit.h"
-#include "base/base64.h"
-#include "crypto/rsa_private_key.h"
-#include "base/memory/scoped_ptr.h"
-
-int main(int argc, char** argv) {
-  base::AtExitManager exit_manager;
-
-  scoped_ptr<crypto::RSAPrivateKey> key(crypto::RSAPrivateKey::Create(2048));
-
-  std::vector<uint8> private_key_buf;
-  key->ExportPrivateKey(&private_key_buf);
-  std::string private_key_str(private_key_buf.begin(), private_key_buf.end());
-  std::string private_key_base64;
-  base::Base64Encode(private_key_str, &private_key_base64);
-  printf("%s\n", private_key_base64.c_str());
-
-  std::vector<uint8> public_key_buf;
-  key->ExportPublicKey(&public_key_buf);
-  std::string public_key_str(public_key_buf.begin(), public_key_buf.end());
-  std::string public_key_base64;
-  base::Base64Encode(public_key_str, &public_key_base64);
-  printf("%s\n", public_key_base64.c_str());
-}
diff --git a/remoting/host/local_input_monitor_win.cc b/remoting/host/local_input_monitor_win.cc
index 2796bf0..2459c0f 100644
--- a/remoting/host/local_input_monitor_win.cc
+++ b/remoting/host/local_input_monitor_win.cc
@@ -148,7 +148,7 @@
     device.dwFlags = RIDEV_REMOVE;
     device.usUsagePage = kGenericDesktopPage;
     device.usUsage = kMouseUsage;
-    device.hwndTarget = window_->hwnd();
+    device.hwndTarget = NULL;
 
     // The error is harmless, ignore it.
     RegisterRawInputDevices(&device, 1, sizeof(device));
diff --git a/remoting/host/pairing_registry_delegate_win.cc b/remoting/host/pairing_registry_delegate_win.cc
index c7f11d9..20230d0 100644
--- a/remoting/host/pairing_registry_delegate_win.cc
+++ b/remoting/host/pairing_registry_delegate_win.cc
@@ -83,8 +83,7 @@
 
   // presubmit: allow wstring
   std::wstring value_json = UTF8ToWide(value_json_utf8);
-  LONG result = key.WriteValue(value_name,
-                               UTF8ToWide(value_json_utf8).c_str());
+  LONG result = key.WriteValue(value_name, value_json.c_str());
   if (result != ERROR_SUCCESS) {
     SetLastError(result);
     PLOG(ERROR) << "Cannot write value '" << value_name << "'";
diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc
index 1c8771d..b766cad 100644
--- a/remoting/host/plugin/host_script_object.cc
+++ b/remoting/host/plugin/host_script_object.cc
@@ -16,6 +16,7 @@
 #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"
@@ -107,9 +108,7 @@
   // Methods called by the script object, from the plugin thread.
 
   // Creates It2Me host structures and starts the host.
-  void Connect(const std::string& uid,
-               const std::string& auth_token,
-               const std::string& auth_service);
+  void Connect();
 
   // Disconnects the host, ready for tear-down.
   // Also called internally, from the network thread.
@@ -135,14 +134,10 @@
   bool IsConnected() const;
 
   // Called by Connect() to check for policies and start connection process.
-  void ReadPolicyAndConnect(const std::string& uid,
-                            const std::string& auth_token,
-                            const std::string& auth_service);
+  void ReadPolicyAndConnect();
 
   // Called by ReadPolicyAndConnect once policies have been read.
-  void FinishConnect(const std::string& uid,
-                     const std::string& auth_token,
-                     const std::string& auth_service);
+  void FinishConnect();
 
   // Called when the support host registration completes.
   void OnReceivedSupportID(bool success,
@@ -223,15 +218,11 @@
   DCHECK(plugin_task_runner_->BelongsToCurrentThread());
 }
 
-void HostNPScriptObject::It2MeImpl::Connect(
-    const std::string& uid,
-    const std::string& auth_token,
-    const std::string& auth_service) {
+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, uid, auth_token, auth_service));
+        FROM_HERE, base::Bind(&It2MeImpl::Connect, this));
     return;
   }
 
@@ -248,9 +239,7 @@
 
   // Switch to the network thread to start the actual connection.
   host_context_->network_task_runner()->PostTask(
-      FROM_HERE, base::Bind(
-          &It2MeImpl::ReadPolicyAndConnect, this,
-          uid, auth_token, auth_service));
+      FROM_HERE, base::Bind(&It2MeImpl::ReadPolicyAndConnect, this));
 }
 
 void HostNPScriptObject::It2MeImpl::Disconnect() {
@@ -305,10 +294,7 @@
     UpdateNatPolicy(nat_traversal_enabled_);
 }
 
-void HostNPScriptObject::It2MeImpl::ReadPolicyAndConnect(
-    const std::string& uid,
-    const std::string& auth_token,
-    const std::string& auth_service) {
+void HostNPScriptObject::It2MeImpl::ReadPolicyAndConnect() {
   DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
 
   SetState(kStarting);
@@ -316,19 +302,15 @@
   // Only proceed to FinishConnect() if at least one policy update has been
   // received.
   if (policy_received_) {
-    FinishConnect(uid, auth_token, auth_service);
+    FinishConnect();
   } else {
     // Otherwise, create the policy watcher, and thunk the connect.
     pending_connect_ =
-        base::Bind(&It2MeImpl::FinishConnect, this,
-                   uid, auth_token, auth_service);
+        base::Bind(&It2MeImpl::FinishConnect, this);
   }
 }
 
-void HostNPScriptObject::It2MeImpl::FinishConnect(
-    const std::string& uid,
-    const std::string& auth_token,
-    const std::string& auth_service) {
+void HostNPScriptObject::It2MeImpl::FinishConnect() {
   DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread());
 
   if (state_ != kStarting) {
@@ -338,7 +320,8 @@
 
   // Check the host domain policy.
   if (!required_host_domain_.empty() &&
-      !EndsWith(uid, std::string("@") + required_host_domain_, false)) {
+      !EndsWith(xmpp_server_config_.username,
+                std::string("@") + required_host_domain_, false)) {
     SetState(kInvalidDomainError);
     return;
   }
@@ -349,8 +332,8 @@
 
   // Create XMPP connection.
   scoped_ptr<SignalStrategy> signal_strategy(
-      new XmppSignalStrategy(host_context_->url_request_context_getter(),
-                             uid, auth_token, auth_service,
+      new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
+                             host_context_->url_request_context_getter(),
                              xmpp_server_config_));
 
   // Request registration of the host for support.
@@ -405,7 +388,7 @@
 
   // Connect signaling and start the host.
   signal_strategy_->Connect();
-  host_->Start(uid);
+  host_->Start(xmpp_server_config_.username);
 
   SetState(kRequestedAccessCode);
   return;
@@ -1015,7 +998,7 @@
   return true;
 }
 
-// string uid, string auth_token
+// string username, string auth_token
 bool HostNPScriptObject::Connect(const NPVariant* args,
                                  uint32_t arg_count,
                                  NPVariant* result) {
@@ -1033,18 +1016,18 @@
     return false;
   }
 
-  std::string uid = StringFromNPVariant(args[0]);
-  if (uid.empty()) {
-    SetException("connect: bad uid argument");
+  XmppSignalStrategy::XmppServerConfig xmpp_config = xmpp_server_config_;
+
+  xmpp_config.username = StringFromNPVariant(args[0]);
+  if (xmpp_config.username.empty()) {
+    SetException("connect: bad username argument");
     return false;
   }
 
   std::string auth_service_with_token = StringFromNPVariant(args[1]);
-  std::string auth_token;
-  std::string auth_service;
-  ParseAuthTokenWithService(auth_service_with_token, &auth_token,
-                            &auth_service);
-  if (auth_token.empty()) {
+  ParseAuthTokenWithService(auth_service_with_token, &xmpp_config.auth_token,
+                            &xmpp_config.auth_service);
+  if (xmpp_config.auth_token.empty()) {
     SetException("connect: auth_service_with_token argument has empty token");
     return false;
   }
@@ -1060,8 +1043,8 @@
   // Create the It2Me host implementation and start connecting.
   it2me_impl_ = new It2MeImpl(
       host_context.Pass(), plugin_task_runner_, weak_ptr_,
-      xmpp_server_config_, directory_bot_jid_);
-  it2me_impl_->Connect(uid, auth_token, auth_service);
+      xmpp_config, directory_bot_jid_);
+  it2me_impl_->Connect();
 
   return true;
 }
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 52b0fd3..9ed3383 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -29,6 +29,7 @@
 #include "ipc/ipc_listener.h"
 #include "media/base/media.h"
 #include "net/base/network_change_notifier.h"
+#include "net/socket/client_socket_factory.h"
 #include "net/socket/ssl_server_socket.h"
 #include "net/url_request/url_fetcher.h"
 #include "remoting/base/auto_thread_task_runner.h"
@@ -266,9 +267,8 @@
   scoped_refptr<RsaKeyPair> key_pair_;
   std::string oauth_refresh_token_;
   std::string serialized_config_;
-  std::string xmpp_login_;
-  std::string xmpp_auth_token_;
-  std::string xmpp_auth_service_;
+  std::string host_owner_;
+  bool use_service_account_;
   scoped_ptr<policy_hack::PolicyWatcher> policy_watcher_;
   bool allow_nat_traversal_;
   std::string talkgadget_prefix_;
@@ -303,6 +303,7 @@
                          int* exit_code_out)
     : context_(context.Pass()),
       state_(HOST_INITIALIZING),
+      use_service_account_(false),
       allow_nat_traversal_(true),
       allow_pairing_(true),
       curtain_required_(false),
@@ -520,7 +521,8 @@
 
   if (token_url_.is_empty() && token_validation_url_.is_empty()) {
     factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
-        local_certificate, key_pair_, host_secret_hash_, pairing_registry);
+        host_owner_, local_certificate, key_pair_, host_secret_hash_,
+        pairing_registry);
 
   } else if (token_url_.is_valid() && token_validation_url_.is_valid()) {
     scoped_ptr<protocol::ThirdPartyHostAuthenticator::TokenValidatorFactory>
@@ -528,7 +530,8 @@
             token_url_, token_validation_url_, key_pair_,
             context_->url_request_context_getter()));
     factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
-        local_certificate, key_pair_, token_validator_factory.Pass());
+        host_owner_, local_certificate, key_pair_,
+        token_validator_factory.Pass());
 
   } else {
     // TODO(rmsousa): If the policy is bad the host should not go online. It
@@ -709,8 +712,9 @@
   }
 
   // Use an XMPP connection to the Talk network for session signalling.
-  if (!config->GetString(kXmppLoginConfigPath, &xmpp_login_) ||
-      !(config->GetString(kXmppAuthTokenConfigPath, &xmpp_auth_token_) ||
+  if (!config->GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
+      !(config->GetString(kXmppAuthTokenConfigPath,
+                          &xmpp_server_config_.auth_token) ||
         config->GetString(kOAuthRefreshTokenConfigPath,
                           &oauth_refresh_token_))) {
     LOG(ERROR) << "XMPP credentials are not defined in the config.";
@@ -718,14 +722,24 @@
   }
 
   if (!oauth_refresh_token_.empty()) {
-    xmpp_auth_token_ = "";  // This will be set to the access token later.
-    xmpp_auth_service_ = "oauth2";
+    // SignalingConnector is responsible for getting OAuth token.
+    xmpp_server_config_.auth_token = "";
+    xmpp_server_config_.auth_service = "oauth2";
   } else if (!config->GetString(kXmppAuthServiceConfigPath,
-                                &xmpp_auth_service_)) {
+                                &xmpp_server_config_.auth_service)) {
     // For the me2me host, we default to ClientLogin token for chromiumsync
     // because earlier versions of the host had no HTTP stack with which to
     // request an OAuth2 access token.
-    xmpp_auth_service_ = kChromotingTokenDefaultServiceName;
+    xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
+  }
+
+  if (config->GetString(kHostOwnerConfigPath, &host_owner_)) {
+    // Service account configs have a host_owner, different from the xmpp_login.
+    use_service_account_ = true;
+  } else {
+    // User credential configs only have an xmpp_login, which is also the owner.
+    host_owner_ = xmpp_server_config_.username;
+    use_service_account_ = false;
   }
   return true;
 }
@@ -799,7 +813,7 @@
   LOG(INFO) << "Policy sets host domain: " << host_domain;
 
   if (!host_domain.empty() &&
-      !EndsWith(xmpp_login_, std::string("@") + host_domain, false)) {
+      !EndsWith(host_owner_, std::string("@") + host_domain, false)) {
     ShutdownHost(kInvalidHostDomainExitCode);
   }
   return false;
@@ -814,7 +828,7 @@
     LOG(INFO) << "Policy requires host username match.";
     std::string username = GetUsername();
     bool shutdown = username.empty() ||
-        !StartsWithASCII(xmpp_login_, username + std::string("@"),
+        !StartsWithASCII(host_owner_, username + std::string("@"),
                          false);
 
 #if defined(OS_MACOSX)
@@ -952,9 +966,9 @@
   state_ = HOST_STARTED;
 
   signal_strategy_.reset(
-      new XmppSignalStrategy(context_->url_request_context_getter(),
-                             xmpp_login_, xmpp_auth_token_,
-                             xmpp_auth_service_, xmpp_server_config_));
+      new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(),
+                             context_->url_request_context_getter(),
+                             xmpp_server_config_));
 
   scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(
       new DnsBlackholeChecker(context_->url_request_context_getter(),
@@ -972,7 +986,8 @@
   if (!oauth_refresh_token_.empty()) {
     scoped_ptr<SignalingConnector::OAuthCredentials> oauth_credentials(
         new SignalingConnector::OAuthCredentials(
-            xmpp_login_, oauth_refresh_token_));
+            xmpp_server_config_.username, oauth_refresh_token_,
+            use_service_account_));
     signaling_connector_->EnableOAuth(oauth_credentials.Pass());
   }
 
@@ -1026,7 +1041,7 @@
 #endif  // !defined(REMOTING_MULTI_PROCESS)
 
   host_->SetEnableCurtaining(curtain_required_);
-  host_->Start(xmpp_login_);
+  host_->Start(host_owner_);
 
   CreateAuthenticatorFactory();
 }
diff --git a/remoting/host/setup/daemon_controller_linux.cc b/remoting/host/setup/daemon_controller_linux.cc
index 1fb2598..e2d6566 100644
--- a/remoting/host/setup/daemon_controller_linux.cc
+++ b/remoting/host/setup/daemon_controller_linux.cc
@@ -36,8 +36,10 @@
 const char kDaemonScript[] =
     "/opt/google/chrome-remote-desktop/chrome-remote-desktop";
 
-// Timeout for running daemon script.
-const int64 kDaemonTimeoutMs = 5000;
+// Timeout for running daemon script. The script itself sets a timeout when
+// waiting for the host to come online, so the setting here should be at least
+// as long.
+const int64 kDaemonTimeoutMs = 60000;
 
 // Timeout for commands that require password prompt - 5 minutes.
 const int64 kSudoTimeoutSeconds = 5 * 60;
diff --git a/remoting/host/setup/host_starter.cc b/remoting/host/setup/host_starter.cc
index d16137b..3a0646b 100644
--- a/remoting/host/setup/host_starter.cc
+++ b/remoting/host/setup/host_starter.cc
@@ -95,30 +95,72 @@
   NOTREACHED();
 }
 
+// This function is called twice: once with the host owner credentials, and once
+// with the service account credentials.
 void HostStarter::OnGetUserEmailResponse(const std::string& user_email) {
   if (!main_task_runner_->BelongsToCurrentThread()) {
     main_task_runner_->PostTask(FROM_HERE, base::Bind(
         &HostStarter::OnGetUserEmailResponse, weak_ptr_, user_email));
     return;
   }
-  user_email_ = user_email;
-  // Register the host.
-  host_id_ = base::GenerateGUID();
-  key_pair_ = RsaKeyPair::Generate();
-  service_client_->RegisterHost(
-      host_id_, host_name_, key_pair_->GetPublicKey(), access_token_, this);
+
+  if (host_owner_.empty()) {
+    // This is the first callback, with the host owner credentials. Store the
+    // owner's email, and register the host.
+    host_owner_ = user_email;
+    host_id_ = base::GenerateGUID();
+    key_pair_ = RsaKeyPair::Generate();
+
+    std::string host_client_id;
+    host_client_id = google_apis::GetOAuth2ClientID(
+        google_apis::CLIENT_REMOTING_HOST);
+
+    service_client_->RegisterHost(
+        host_id_, host_name_, key_pair_->GetPublicKey(), host_client_id,
+        access_token_, this);
+  } else {
+    // This is the second callback, with the service account credentials.
+    // This email is the service account's email, used to login to XMPP.
+    xmpp_login_ = user_email;
+    StartHostProcess();
+  }
 }
 
-void HostStarter::OnHostRegistered() {
+void HostStarter::OnHostRegistered(const std::string& authorization_code) {
   if (!main_task_runner_->BelongsToCurrentThread()) {
     main_task_runner_->PostTask(FROM_HERE, base::Bind(
-        &HostStarter::OnHostRegistered, weak_ptr_));
+        &HostStarter::OnHostRegistered, weak_ptr_, authorization_code));
     return;
   }
+
+  if (authorization_code.empty()) {
+    // No service account code, start the host with the owner's credentials.
+    xmpp_login_ = host_owner_;
+    StartHostProcess();
+    return;
+  }
+
+  // Received a service account authorization code, update oauth_client_info_
+  // to use the service account client keys, and get service account tokens.
+  oauth_client_info_.client_id =
+      google_apis::GetOAuth2ClientID(
+          google_apis::CLIENT_REMOTING_HOST);
+  oauth_client_info_.client_secret =
+      google_apis::GetOAuth2ClientSecret(
+          google_apis::CLIENT_REMOTING_HOST);
+  oauth_client_info_.redirect_uri = "oob";
+  oauth_client_->GetTokensFromAuthCode(
+      oauth_client_info_, authorization_code, kMaxGetTokensRetries, this);
+}
+
+void HostStarter::StartHostProcess() {
   // Start the host.
   std::string host_secret_hash = remoting::MakeHostPinHash(host_id_, host_pin_);
   scoped_ptr<base::DictionaryValue> config(new base::DictionaryValue());
-  config->SetString("xmpp_login", user_email_);
+  if (host_owner_ != xmpp_login_) {
+    config->SetString("host_owner", host_owner_);
+  }
+  config->SetString("xmpp_login", xmpp_login_);
   config->SetString("oauth_refresh_token", refresh_token_);
   config->SetString("host_id", host_id_);
   config->SetString("host_name", host_name_);
diff --git a/remoting/host/setup/host_starter.h b/remoting/host/setup/host_starter.h
index a51f299..3bb2e3e 100644
--- a/remoting/host/setup/host_starter.h
+++ b/remoting/host/setup/host_starter.h
@@ -55,7 +55,7 @@
   virtual void OnGetUserEmailResponse(const std::string& user_email) OVERRIDE;
 
   // remoting::ServiceClient::Delegate
-  virtual void OnHostRegistered() OVERRIDE;
+  virtual void OnHostRegistered(const std::string& authorization_code) OVERRIDE;
   virtual void OnHostUnregistered() OVERRIDE;
 
   // TODO(sergeyu): Following methods are members of all three delegate
@@ -70,6 +70,8 @@
               scoped_ptr<remoting::ServiceClient> service_client,
               scoped_ptr<remoting::DaemonController> daemon_controller);
 
+  void StartHostProcess();
+
   void OnHostStarted(DaemonController::AsyncResult result);
 
   scoped_ptr<gaia::GaiaOAuthClient> oauth_client_;
@@ -83,9 +85,11 @@
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
   std::string refresh_token_;
   std::string access_token_;
-  std::string user_email_;
+  std::string host_owner_;
+  std::string xmpp_login_;
   scoped_refptr<remoting::RsaKeyPair> key_pair_;
   std::string host_id_;
+  bool use_service_account_;
 
   base::WeakPtrFactory<HostStarter> weak_ptr_factory_;
   base::WeakPtr<HostStarter> weak_ptr_;
diff --git a/remoting/host/setup/native_messaging_host.cc b/remoting/host/setup/native_messaging_host.cc
index 7bf6b7c..0492736 100644
--- a/remoting/host/setup/native_messaging_host.cc
+++ b/remoting/host/setup/native_messaging_host.cc
@@ -15,12 +15,16 @@
 #include "base/run_loop.h"
 #include "base/strings/stringize_macros.h"
 #include "base/values.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/google_api_keys.h"
 #include "net/base/net_util.h"
+#include "net/url_request/url_fetcher.h"
 #include "remoting/base/rsa_key_pair.h"
+#include "remoting/base/url_request_context.h"
 #include "remoting/host/host_exit_codes.h"
 #include "remoting/host/pairing_registry_delegate.h"
-#include "remoting/host/pairing_registry_delegate.h"
 #include "remoting/host/pin_hash.h"
+#include "remoting/host/setup/oauth_client.h"
 #include "remoting/protocol/pairing_registry.h"
 
 #if defined(OS_POSIX)
@@ -32,8 +36,13 @@
 // Features supported in addition to the base protocol.
 const char* kSupportedFeatures[] = {
   "pairingRegistry",
+  "oauthClient"
 };
 
+// redirect_uri to use when authenticating service accounts (service account
+// codes are obtained "out-of-band", i.e., not through an OAuth redirect).
+const char* kServiceAccountRedirectUri = "oob";
+
 // Helper to extract the "config" part of a message as a DictionaryValue.
 // Returns NULL on failure, and logs an error message.
 scoped_ptr<base::DictionaryValue> ConfigDictionaryFromMessage(
@@ -55,6 +64,7 @@
 NativeMessagingHost::NativeMessagingHost(
     scoped_ptr<DaemonController> daemon_controller,
     scoped_refptr<protocol::PairingRegistry> pairing_registry,
+    scoped_ptr<OAuthClient> oauth_client,
     base::PlatformFile input,
     base::PlatformFile output,
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
@@ -65,6 +75,7 @@
       native_messaging_writer_(output),
       daemon_controller_(daemon_controller.Pass()),
       pairing_registry_(pairing_registry),
+      oauth_client_(oauth_client.Pass()),
       weak_factory_(this) {
   weak_ptr_ = weak_factory_.GetWeakPtr();
 }
@@ -145,6 +156,11 @@
     success = ProcessStopDaemon(*message_dict, response_dict.Pass());
   } else if (type == "getDaemonState") {
     success = ProcessGetDaemonState(*message_dict, response_dict.Pass());
+  } else if (type == "getHostClientId") {
+    success = ProcessGetHostClientId(*message_dict, response_dict.Pass());
+  } else if (type == "getCredentialsFromAuthCode") {
+    success = ProcessGetCredentialsFromAuthCode(
+        *message_dict, response_dict.Pass());
   } else {
     LOG(ERROR) << "Unsupported request type: " << type;
   }
@@ -347,6 +363,38 @@
   return true;
 }
 
+bool NativeMessagingHost::ProcessGetHostClientId(
+    const base::DictionaryValue& message,
+    scoped_ptr<base::DictionaryValue> response) {
+  response->SetString("clientId", google_apis::GetOAuth2ClientID(
+      google_apis::CLIENT_REMOTING_HOST));
+  SendResponse(response.Pass());
+  return true;
+}
+
+bool NativeMessagingHost::ProcessGetCredentialsFromAuthCode(
+    const base::DictionaryValue& message,
+    scoped_ptr<base::DictionaryValue> response) {
+  std::string auth_code;
+  if (!message.GetString("authorizationCode", &auth_code)) {
+    LOG(ERROR) << "'authorizationCode' string not found.";
+    return false;
+  }
+
+  gaia::OAuthClientInfo oauth_client_info = {
+    google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING_HOST),
+    google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING_HOST),
+    kServiceAccountRedirectUri
+  };
+
+  oauth_client_->GetCredentialsFromAuthCode(
+      oauth_client_info, auth_code, base::Bind(
+          &NativeMessagingHost::SendCredentialsResponse, weak_ptr_,
+          base::Passed(&response)));
+
+  return true;
+}
+
 void NativeMessagingHost::SendResponse(
     scoped_ptr<base::DictionaryValue> response) {
   if (!caller_task_runner_->BelongsToCurrentThread()) {
@@ -415,6 +463,15 @@
   SendResponse(response.Pass());
 }
 
+void NativeMessagingHost::SendCredentialsResponse(
+    scoped_ptr<base::DictionaryValue> response,
+    const std::string& user_email,
+    const std::string& refresh_token) {
+  response->SetString("userEmail", user_email);
+  response->SetString("refreshToken", refresh_token);
+  SendResponse(response.Pass());
+}
+
 int NativeMessagingHostMain() {
 #if defined(OS_WIN)
   base::PlatformFile read_file = GetStdHandle(STD_INPUT_HANDLE);
@@ -428,10 +485,19 @@
 
   base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
   base::RunLoop run_loop;
+  // OAuth client (for credential requests).
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter(
+      new remoting::URLRequestContextGetter(message_loop.message_loop_proxy()));
+  scoped_ptr<remoting::OAuthClient> oauth_client(
+      new remoting::OAuthClient(url_request_context_getter));
+
+  net::URLFetcher::SetIgnoreCertificateRequests(true);
+
   scoped_refptr<protocol::PairingRegistry> pairing_registry =
       CreatePairingRegistry(message_loop.message_loop_proxy());
   remoting::NativeMessagingHost host(remoting::DaemonController::Create(),
                                      pairing_registry,
+                                     oauth_client.Pass(),
                                      read_file, write_file,
                                      message_loop.message_loop_proxy(),
                                      run_loop.QuitClosure());
diff --git a/remoting/host/setup/native_messaging_host.h b/remoting/host/setup/native_messaging_host.h
index 309d63c..6a00080 100644
--- a/remoting/host/setup/native_messaging_host.h
+++ b/remoting/host/setup/native_messaging_host.h
@@ -13,6 +13,7 @@
 #include "remoting/host/setup/daemon_controller.h"
 #include "remoting/host/setup/native_messaging_reader.h"
 #include "remoting/host/setup/native_messaging_writer.h"
+#include "remoting/host/setup/oauth_client.h"
 
 namespace base {
 class DictionaryValue;
@@ -21,6 +22,10 @@
 class Value;
 }  // namespace base
 
+namespace gaia {
+class GaiaOAuthClient;
+}  // namespace gaia
+
 namespace remoting {
 
 namespace protocol {
@@ -33,6 +38,7 @@
   NativeMessagingHost(
       scoped_ptr<DaemonController> daemon_controller,
       scoped_refptr<protocol::PairingRegistry> pairing_registry,
+      scoped_ptr<OAuthClient> oauth_client,
       base::PlatformFile input,
       base::PlatformFile output,
       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
@@ -79,6 +85,11 @@
                          scoped_ptr<base::DictionaryValue> response);
   bool ProcessGetDaemonState(const base::DictionaryValue& message,
                              scoped_ptr<base::DictionaryValue> response);
+  bool ProcessGetHostClientId(const base::DictionaryValue& message,
+                             scoped_ptr<base::DictionaryValue> response);
+  bool ProcessGetCredentialsFromAuthCode(
+      const base::DictionaryValue& message,
+      scoped_ptr<base::DictionaryValue> response);
 
   // Sends a response back to the client app. This can be called on either the
   // main message loop or the DaemonController's internal thread, so it
@@ -101,6 +112,9 @@
                        DaemonController::AsyncResult result);
   void SendBooleanResult(scoped_ptr<base::DictionaryValue> response,
                          bool result);
+  void SendCredentialsResponse(scoped_ptr<base::DictionaryValue> response,
+                               const std::string& user_email,
+                               const std::string& refresh_token);
 
   // Callbacks may be invoked by e.g. DaemonController during destruction,
   // which use |weak_ptr_|, so it's important that it be the last member to be
@@ -121,6 +135,9 @@
   // Used to load and update the paired clients for this host.
   scoped_refptr<protocol::PairingRegistry> pairing_registry_;
 
+  // Used to exchange the service account authorization code for credentials.
+  scoped_ptr<OAuthClient> oauth_client_;
+
   base::WeakPtrFactory<NativeMessagingHost> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NativeMessagingHost);
diff --git a/remoting/host/setup/native_messaging_host_unittest.cc b/remoting/host/setup/native_messaging_host_unittest.cc
index 09cf26e..209604a 100644
--- a/remoting/host/setup/native_messaging_host_unittest.cc
+++ b/remoting/host/setup/native_messaging_host_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/stl_util.h"
 #include "base/strings/stringize_macros.h"
 #include "base/values.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
 #include "net/base/file_stream.h"
 #include "net/base/net_util.h"
 #include "remoting/host/pin_hash.h"
@@ -273,6 +274,7 @@
 
   host_.reset(new NativeMessagingHost(daemon_controller.Pass(),
                                       pairing_registry,
+                                      scoped_ptr<remoting::OAuthClient>(),
                                       input_read_handle_, output_write_handle_,
                                       message_loop_.message_loop_proxy(),
                                       run_loop_.QuitClosure()));
diff --git a/remoting/host/setup/oauth_client.cc b/remoting/host/setup/oauth_client.cc
new file mode 100644
index 0000000..9de0723
--- /dev/null
+++ b/remoting/host/setup/oauth_client.cc
@@ -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.
+
+#include "remoting/host/setup/oauth_client.h"
+
+namespace {
+const int kMaxGaiaRetries = 3;
+}  // namespace
+
+namespace remoting {
+
+OAuthClient::OAuthClient(
+    scoped_refptr<net::URLRequestContextGetter> url_request_context_getter)
+    : gaia_oauth_client_(url_request_context_getter) {
+}
+
+OAuthClient::~OAuthClient() {
+}
+
+void OAuthClient::GetCredentialsFromAuthCode(
+    const gaia::OAuthClientInfo& oauth_client_info,
+    const std::string& auth_code,
+    CompletionCallback on_done) {
+
+  if (!on_done_.is_null()) {
+    pending_requests_.push(Request(oauth_client_info, auth_code, on_done));
+    return;
+  }
+
+  on_done_ = on_done;
+  // Map the authorization code to refresh and access tokens.
+  gaia_oauth_client_.GetTokensFromAuthCode(oauth_client_info, auth_code,
+                                           kMaxGaiaRetries, this);
+}
+
+void OAuthClient::OnGetTokensResponse(
+    const std::string& refresh_token,
+    const std::string& access_token,
+    int expires_in_seconds) {
+  refresh_token_ = refresh_token;
+  // Get the email corresponding to the access token.
+  gaia_oauth_client_.GetUserEmail(access_token, kMaxGaiaRetries, this);
+}
+
+void OAuthClient::OnRefreshTokenResponse(
+    const std::string& access_token,
+    int expires_in_seconds) {
+  // We never request a refresh token, so this call is not expected.
+  NOTREACHED();
+}
+
+void OAuthClient::SendResponse(const std::string& user_email,
+                               const std::string& refresh_token) {
+  CompletionCallback on_done = on_done_;
+  on_done_.Reset();
+  on_done.Run(user_email, refresh_token);
+
+  // Process the next request in the queue.
+  if (pending_requests_.size()) {
+    Request request = pending_requests_.front();
+    pending_requests_.pop();
+    // GetCredentialsFromAuthCode is asynchronous, so it's safe to call it here.
+    GetCredentialsFromAuthCode(
+        request.oauth_client_info, request.auth_code, request.on_done);
+  }
+}
+
+void OAuthClient::OnGetUserEmailResponse(const std::string& user_email) {
+  SendResponse(user_email, refresh_token_);
+}
+
+void OAuthClient::OnOAuthError() {
+  SendResponse("", "");
+}
+
+void OAuthClient::OnNetworkError(int response_code) {
+  SendResponse("", "");
+}
+
+OAuthClient::Request::Request(
+    const gaia::OAuthClientInfo& oauth_client_info,
+    const std::string& auth_code,
+    CompletionCallback on_done) {
+  this->oauth_client_info = oauth_client_info;
+  this->auth_code = auth_code;
+  this->on_done = on_done;
+}
+
+OAuthClient::Request::~Request() {
+}
+
+}  // namespace remoting
diff --git a/remoting/host/setup/oauth_client.h b/remoting/host/setup/oauth_client.h
new file mode 100644
index 0000000..2fdcbfe
--- /dev/null
+++ b/remoting/host/setup/oauth_client.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 REMOTING_HOST_SETUP_OAUTH_CLIENT
+#define REMOTING_HOST_SETUP_OAUTH_CLIENT
+
+#include <queue>
+#include <string>
+
+#include "base/callback.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "remoting/base/url_request_context.h"
+
+namespace remoting {
+
+// A wrapper around GaiaOAuthClient that provides a more convenient interface,
+// with queueing of requests and a callback rather than a delegate.
+class OAuthClient : public gaia::GaiaOAuthClient::Delegate {
+ public:
+  // Called when GetCredentialsFromAuthCode is completed, with the |user_email|
+  // and |refresh_token| that correspond to the given |auth_code|, or with empty
+  // strings on error.
+  typedef base::Callback<void(
+      const std::string& user_email,
+      const std::string& refresh_token)> CompletionCallback;
+
+  OAuthClient(
+      scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
+
+  virtual ~OAuthClient();
+
+  // Redeems |auth_code| using |oauth_client_info| to obtain |refresh_token| and
+  // |access_token|, then uses the userinfo endpoint to obtain |user_email|.
+  // Calls CompletionCallback with |user_email| and |refresh_token| when done,
+  // or with empty strings on error.
+  // If a request is received while another one is  being processed, it is
+  // enqueued and processed after the first one is finished.
+  void GetCredentialsFromAuthCode(
+      const gaia::OAuthClientInfo& oauth_client_info,
+      const std::string& auth_code,
+      CompletionCallback on_done);
+
+  // gaia::GaiaOAuthClient::Delegate
+  virtual void OnGetTokensResponse(const std::string& refresh_token,
+                                 const std::string& access_token,
+                                 int expires_in_seconds) OVERRIDE;
+  virtual void OnRefreshTokenResponse(const std::string& access_token,
+                                      int expires_in_seconds) OVERRIDE;
+  virtual void OnGetUserEmailResponse(const std::string& user_email) OVERRIDE;
+
+  virtual void OnOAuthError() OVERRIDE;
+  virtual void OnNetworkError(int response_code) OVERRIDE;
+
+ private:
+  struct Request {
+    Request(const gaia::OAuthClientInfo& oauth_client_info,
+            const std::string& auth_code,
+            CompletionCallback on_done);
+    virtual ~Request();
+    gaia::OAuthClientInfo oauth_client_info;
+    std::string auth_code;
+    CompletionCallback on_done;
+  };
+
+  void SendResponse(const std::string& user_email,
+                    const std::string& refresh_token);
+
+  std::queue<Request> pending_requests_;
+  gaia::GaiaOAuthClient gaia_oauth_client_;
+  std::string refresh_token_;
+  CompletionCallback on_done_;
+
+  DISALLOW_COPY_AND_ASSIGN(OAuthClient);
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_HOST_SETUP_OAUTH_CLIENT
diff --git a/remoting/host/setup/service_client.cc b/remoting/host/setup/service_client.cc
index c7bc22e..215b04e 100644
--- a/remoting/host/setup/service_client.cc
+++ b/remoting/host/setup/service_client.cc
@@ -4,6 +4,7 @@
 
 #include "remoting/host/setup/service_client.h"
 
+#include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
@@ -30,6 +31,7 @@
   void RegisterHost(const std::string& host_id,
                     const std::string& host_name,
                     const std::string& public_key,
+                    const std::string& host_client_id,
                     const std::string& oauth_access_token,
                     ServiceClient::Delegate* delegate);
 
@@ -50,7 +52,7 @@
     PENDING_REQUEST_UNREGISTER_HOST
   };
 
-  void MakeGaiaRequest(net::URLFetcher::RequestType request_type,
+  void MakeChromotingRequest(net::URLFetcher::RequestType request_type,
                        const std::string& post_body,
                        const std::string& url_suffix,
                        const std::string& oauth_access_token,
@@ -68,6 +70,7 @@
     const std::string& host_id,
     const std::string& host_name,
     const std::string& public_key,
+    const std::string& host_client_id,
     const std::string& oauth_access_token,
     Delegate* delegate) {
   DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
@@ -76,13 +79,16 @@
   post_body.SetString("data.hostId", host_id);
   post_body.SetString("data.hostName", host_name);
   post_body.SetString("data.publicKey", public_key);
+  std::string url_suffix;
+  if (!host_client_id.empty())
+    url_suffix = "?hostClientId=" + host_client_id;
   std::string post_body_str;
   base::JSONWriter::Write(&post_body, &post_body_str);
-  MakeGaiaRequest(net::URLFetcher::POST,
-                  std::string(),
-                  post_body_str,
-                  oauth_access_token,
-                  delegate);
+  MakeChromotingRequest(net::URLFetcher::POST,
+                        url_suffix,
+                        post_body_str,
+                        oauth_access_token,
+                        delegate);
 }
 
 void ServiceClient::Core::UnregisterHost(
@@ -91,14 +97,14 @@
     Delegate* delegate) {
   DCHECK(pending_request_type_ == PENDING_REQUEST_NONE);
   pending_request_type_ = PENDING_REQUEST_UNREGISTER_HOST;
-  MakeGaiaRequest(net::URLFetcher::DELETE_REQUEST,
-                  host_id,
-                  std::string(),
-                  oauth_access_token,
-                  delegate);
+  MakeChromotingRequest(net::URLFetcher::DELETE_REQUEST,
+                        host_id,
+                        std::string(),
+                        oauth_access_token,
+                        delegate);
 }
 
-void ServiceClient::Core::MakeGaiaRequest(
+void ServiceClient::Core::MakeChromotingRequest(
     net::URLFetcher::RequestType request_type,
     const std::string& url_suffix,
     const std::string& request_body,
@@ -133,7 +139,21 @@
       case PENDING_REQUEST_NONE:
         break;
       case PENDING_REQUEST_REGISTER_HOST:
-        delegate_->OnHostRegistered();
+        {
+          std::string data;
+          source->GetResponseAsString(&data);
+          scoped_ptr<Value> message_value(base::JSONReader::Read(data));
+          DictionaryValue *dict;
+          std::string code;
+          if (message_value.get() &&
+              message_value->IsType(Value::TYPE_DICTIONARY) &&
+              message_value->GetAsDictionary(&dict) &&
+              dict->GetString("data.authorizationCode", &code)) {
+            delegate_->OnHostRegistered(code);
+          } else {
+            delegate_->OnHostRegistered(std::string());
+          }
+        }
         break;
       case PENDING_REQUEST_UNREGISTER_HOST:
         delegate_->OnHostUnregistered();
@@ -156,10 +176,11 @@
     const std::string& host_id,
     const std::string& host_name,
     const std::string& public_key,
+    const std::string& host_client_id,
     const std::string& oauth_access_token,
     Delegate* delegate) {
-  return core_->RegisterHost(host_id, host_name, public_key, oauth_access_token,
-                             delegate);
+  return core_->RegisterHost(host_id, host_name, public_key, host_client_id,
+                             oauth_access_token, delegate);
 }
 
 void ServiceClient::UnregisterHost(
diff --git a/remoting/host/setup/service_client.h b/remoting/host/setup/service_client.h
index 5ae2144..eaa26ab 100644
--- a/remoting/host/setup/service_client.h
+++ b/remoting/host/setup/service_client.h
@@ -22,7 +22,7 @@
   class Delegate {
    public:
     // Invoked when a host has been registered.
-    virtual void OnHostRegistered() = 0;
+    virtual void OnHostRegistered(const std::string& authorization_code) = 0;
     // Invoked when a host has been unregistered.
     virtual void OnHostUnregistered() = 0;
     // Invoked when there is an OAuth error.
@@ -42,6 +42,7 @@
   void RegisterHost(const std::string& host_id,
                     const std::string& host_name,
                     const std::string& public_key,
+                    const std::string& host_client_id,
                     const std::string& oauth_access_token,
                     Delegate* delegate);
   // Unregister a host.
diff --git a/remoting/host/setup/start_host.cc b/remoting/host/setup/start_host.cc
index 024e9a3..ab5688d 100644
--- a/remoting/host/setup/start_host.cc
+++ b/remoting/host/setup/start_host.cc
@@ -149,9 +149,7 @@
   io_thread.StartWithOptions(io_thread_options);
 
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter(
-      new remoting::URLRequestContextGetter(
-          g_message_loop->message_loop_proxy(),
-          io_thread.message_loop_proxy()));
+      new remoting::URLRequestContextGetter(io_thread.message_loop_proxy()));
 
   net::URLFetcher::SetIgnoreCertificateRequests(true);
 
diff --git a/remoting/host/setup/win/host_configurer.cc b/remoting/host/setup/win/host_configurer.cc
index bf5b8a6..604c9e4 100644
--- a/remoting/host/setup/win/host_configurer.cc
+++ b/remoting/host/setup/win/host_configurer.cc
@@ -45,8 +45,7 @@
   io_thread.StartWithOptions(io_thread_options);
 
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_(
-      new remoting::URLRequestContextGetter(
-          message_loop.message_loop_proxy(), io_thread.message_loop_proxy()));
+      new remoting::URLRequestContextGetter(io_thread.message_loop_proxy()));
 
   OleInitialize(NULL);
 
diff --git a/remoting/host/signaling_connector.cc b/remoting/host/signaling_connector.cc
index 67c142f..ad9fbe5 100644
--- a/remoting/host/signaling_connector.cc
+++ b/remoting/host/signaling_connector.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/strings/string_util.h"
 #include "google_apis/google_api_keys.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -26,9 +27,11 @@
 
 SignalingConnector::OAuthCredentials::OAuthCredentials(
     const std::string& login_value,
-    const std::string& refresh_token_value)
+    const std::string& refresh_token_value,
+    bool is_service_account)
     : login(login_value),
-      refresh_token(refresh_token_value) {
+      refresh_token(refresh_token_value),
+      is_service_account(is_service_account) {
 }
 
 SignalingConnector::SignalingConnector(
@@ -228,12 +231,20 @@
   LOG(INFO) << "Refreshing OAuth token.";
   DCHECK(!refreshing_oauth_token_);
 
+  // Service accounts use different API keys, as they use the client app flow.
+  google_apis::OAuth2Client oauth2_client;
+  if (oauth_credentials_->is_service_account) {
+    oauth2_client = google_apis::CLIENT_REMOTING_HOST;
+  } else {
+    oauth2_client = google_apis::CLIENT_REMOTING;
+  }
+
   gaia::OAuthClientInfo client_info = {
-      google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING),
-      google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING),
-      // Redirect URL is only used when getting tokens from auth code. It
-      // is not required when getting access tokens.
-      ""
+    google_apis::GetOAuth2ClientID(oauth2_client),
+    google_apis::GetOAuth2ClientSecret(oauth2_client),
+    // Redirect URL is only used when getting tokens from auth code. It
+    // is not required when getting access tokens.
+    ""
   };
 
   refreshing_oauth_token_ = true;
diff --git a/remoting/host/signaling_connector.h b/remoting/host/signaling_connector.h
index 06265e7..77474cd 100644
--- a/remoting/host/signaling_connector.h
+++ b/remoting/host/signaling_connector.h
@@ -40,13 +40,17 @@
   // authentication to OAuth2.
   struct OAuthCredentials {
     OAuthCredentials(const std::string& login_value,
-                     const std::string& refresh_token_value);
+                     const std::string& refresh_token_value,
+                     bool is_service_account);
 
     // The user's account name (i.e. their email address).
     std::string login;
 
     // Token delegating authority to us to act as the user.
     std::string refresh_token;
+
+    // Whether these credentials belong to a service account.
+    bool is_service_account;
   };
 
   // The |auth_failed_callback| is called when authentication fails.
diff --git a/remoting/jingle_glue/xmpp_signal_strategy.cc b/remoting/jingle_glue/xmpp_signal_strategy.cc
index cf34d0a..ed27833 100644
--- a/remoting/jingle_glue/xmpp_signal_strategy.cc
+++ b/remoting/jingle_glue/xmpp_signal_strategy.cc
@@ -34,16 +34,15 @@
 
 namespace remoting {
 
+XmppSignalStrategy::XmppServerConfig::XmppServerConfig() {}
+XmppSignalStrategy::XmppServerConfig::~XmppServerConfig() {}
+
 XmppSignalStrategy::XmppSignalStrategy(
+    net::ClientSocketFactory* socket_factory,
     scoped_refptr<net::URLRequestContextGetter> request_context_getter,
-    const std::string& username,
-    const std::string& auth_token,
-    const std::string& auth_token_service,
     const XmppSignalStrategy::XmppServerConfig& xmpp_server_config)
-    : request_context_getter_(request_context_getter),
-      username_(username),
-      auth_token_(auth_token),
-      auth_token_service_(auth_token_service),
+    : socket_factory_(socket_factory),
+      request_context_getter_(request_context_getter),
       resource_name_(kDefaultResourceName),
       xmpp_client_(NULL),
       xmpp_server_config_(xmpp_server_config),
@@ -71,23 +70,23 @@
   Disconnect();
 
   buzz::XmppClientSettings settings;
-  buzz::Jid login_jid(username_);
+  buzz::Jid login_jid(xmpp_server_config_.username);
   settings.set_user(login_jid.node());
   settings.set_host(login_jid.domain());
   settings.set_resource(resource_name_);
-  settings.set_token_service(auth_token_service_);
-  settings.set_auth_token(buzz::AUTH_MECHANISM_GOOGLE_TOKEN, auth_token_);
+  settings.set_token_service(xmpp_server_config_.auth_service);
+  settings.set_auth_token(buzz::AUTH_MECHANISM_GOOGLE_TOKEN,
+                          xmpp_server_config_.auth_token);
   settings.set_server(talk_base::SocketAddress(
       xmpp_server_config_.host, xmpp_server_config_.port));
   settings.set_use_tls(
       xmpp_server_config_.use_tls ? buzz::TLS_ENABLED : buzz::TLS_DISABLED);
 
-  scoped_ptr<jingle_glue::XmppClientSocketFactory> socket_factory(
+  scoped_ptr<jingle_glue::XmppClientSocketFactory> xmpp_socket_factory(
       new jingle_glue::XmppClientSocketFactory(
-          net::ClientSocketFactory::GetDefaultFactory(),
-          net::SSLConfig(), request_context_getter_, false));
+          socket_factory_, net::SSLConfig(), request_context_getter_, false));
   buzz::AsyncSocket* socket = new jingle_glue::ChromeAsyncSocket(
-    socket_factory.release(), kReadBufferSize, kWriteBufferSize);
+    xmpp_socket_factory.release(), kReadBufferSize, kWriteBufferSize);
 
   task_runner_.reset(new jingle_glue::TaskPump());
   xmpp_client_ = new buzz::XmppClient(task_runner_.get());
@@ -175,11 +174,11 @@
 
 void XmppSignalStrategy::SetAuthInfo(const std::string& username,
                                      const std::string& auth_token,
-                                     const std::string& auth_token_service) {
+                                     const std::string& auth_service) {
   DCHECK(CalledOnValidThread());
-  username_ = username;
-  auth_token_ = auth_token;
-  auth_token_service_ = auth_token_service;
+  xmpp_server_config_.username = username;
+  xmpp_server_config_.auth_token = auth_token;
+  xmpp_server_config_.auth_service = auth_service;
 }
 
 void XmppSignalStrategy::SetResourceName(const std::string &resource_name) {
diff --git a/remoting/jingle_glue/xmpp_signal_strategy.h b/remoting/jingle_glue/xmpp_signal_strategy.h
index 5220710..4ef6b70 100644
--- a/remoting/jingle_glue/xmpp_signal_strategy.h
+++ b/remoting/jingle_glue/xmpp_signal_strategy.h
@@ -22,6 +22,7 @@
 #include "third_party/libjingle/source/talk/xmpp/xmppclient.h"
 
 namespace net {
+class ClientSocketFactory;
 class URLRequestContextGetter;
 }  // namespace net
 
@@ -40,16 +41,21 @@
  public:
   // XMPP Server configuration for XmppSignalStrategy.
   struct XmppServerConfig {
+    XmppServerConfig();
+    ~XmppServerConfig();
+
     std::string host;
     int port;
     bool use_tls;
+
+    std::string username;
+    std::string auth_token;
+    std::string auth_service;
   };
 
   XmppSignalStrategy(
+      net::ClientSocketFactory* socket_factory,
       scoped_refptr<net::URLRequestContextGetter> request_context_getter,
-      const std::string& username,
-      const std::string& auth_token,
-      const std::string& auth_token_service,
       const XmppServerConfig& xmpp_server_config);
   virtual ~XmppSignalStrategy();
 
@@ -72,7 +78,7 @@
   // CONNECTED state. It will be used on the next Connect() call.
   void SetAuthInfo(const std::string& username,
                    const std::string& auth_token,
-                   const std::string& auth_token_service);
+                   const std::string& auth_service);
 
   // Use this method to override the default resource name used (optional).
   // This will be used on the next Connect() call.
@@ -87,10 +93,8 @@
 
   void SendKeepAlive();
 
+  net::ClientSocketFactory* socket_factory_;
   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-  std::string username_;
-  std::string auth_token_;
-  std::string auth_token_service_;
   std::string resource_name_;
   scoped_ptr<talk_base::TaskRunner> task_runner_;
   buzz::XmppClient* xmpp_client_;
diff --git a/remoting/protocol/me2me_host_authenticator_factory.cc b/remoting/protocol/me2me_host_authenticator_factory.cc
index d0deff1..bd926da 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.cc
+++ b/remoting/protocol/me2me_host_authenticator_factory.cc
@@ -61,12 +61,14 @@
 // static
 scoped_ptr<AuthenticatorFactory>
 Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
+    const std::string& host_owner,
     const std::string& local_cert,
     scoped_refptr<RsaKeyPair> key_pair,
     const SharedSecretHash& shared_secret_hash,
     scoped_refptr<PairingRegistry> pairing_registry) {
   scoped_ptr<Me2MeHostAuthenticatorFactory> result(
       new Me2MeHostAuthenticatorFactory());
+  result->host_owner_ = host_owner;
   result->local_cert_ = local_cert;
   result->key_pair_ = key_pair;
   result->shared_secret_hash_ = shared_secret_hash;
@@ -78,12 +80,14 @@
 // static
 scoped_ptr<AuthenticatorFactory>
 Me2MeHostAuthenticatorFactory::CreateWithThirdPartyAuth(
+    const std::string& host_owner,
     const std::string& local_cert,
     scoped_refptr<RsaKeyPair> key_pair,
     scoped_ptr<ThirdPartyHostAuthenticator::TokenValidatorFactory>
         token_validator_factory) {
   scoped_ptr<Me2MeHostAuthenticatorFactory> result(
       new Me2MeHostAuthenticatorFactory());
+  result->host_owner_ = host_owner;
   result->local_cert_ = local_cert;
   result->key_pair_ = key_pair;
   result->token_validator_factory_ = token_validator_factory.Pass();
@@ -107,18 +111,12 @@
     const std::string& remote_jid,
     const buzz::XmlElement* first_message) {
 
-  size_t slash_pos = local_jid.find('/');
-  if (slash_pos == std::string::npos) {
-    LOG(DFATAL) << "Invalid local JID:" << local_jid;
-    return scoped_ptr<Authenticator>(new RejectingAuthenticator());
-  }
-
   // Verify that the client's jid is an ASCII string, and then check
   // that the client has the same bare jid as the host, i.e. client's
   // full JID starts with host's bare jid. Comparison is case
   // insensitive.
   if (!IsStringASCII(remote_jid) ||
-      !StartsWithASCII(remote_jid, local_jid.substr(0, slash_pos + 1), false)) {
+      !StartsWithASCII(remote_jid, host_owner_ + '/', false)) {
     LOG(ERROR) << "Rejecting incoming connection from " << remote_jid;
     return scoped_ptr<Authenticator>(new RejectingAuthenticator());
   }
diff --git a/remoting/protocol/me2me_host_authenticator_factory.h b/remoting/protocol/me2me_host_authenticator_factory.h
index cecb2b6..2563347 100644
--- a/remoting/protocol/me2me_host_authenticator_factory.h
+++ b/remoting/protocol/me2me_host_authenticator_factory.h
@@ -27,6 +27,7 @@
  public:
   // Create a factory that dispenses shared secret authenticators.
   static scoped_ptr<AuthenticatorFactory> CreateWithSharedSecret(
+      const std::string& host_owner,
       const std::string& local_cert,
       scoped_refptr<RsaKeyPair> key_pair,
       const SharedSecretHash& shared_secret_hash,
@@ -34,6 +35,7 @@
 
   // Create a factory that dispenses third party authenticators.
   static scoped_ptr<AuthenticatorFactory> CreateWithThirdPartyAuth(
+      const std::string& host_owner,
       const std::string& local_cert,
       scoped_refptr<RsaKeyPair> key_pair,
       scoped_ptr<ThirdPartyHostAuthenticator::TokenValidatorFactory>
@@ -54,6 +56,7 @@
 
  private:
   // Used for all host authenticators.
+  std::string host_owner_;
   std::string local_cert_;
   scoped_refptr<RsaKeyPair> key_pair_;
 
diff --git a/remoting/protocol/pairing_host_authenticator.cc b/remoting/protocol/pairing_host_authenticator.cc
index bd1f75d..d60b32e 100644
--- a/remoting/protocol/pairing_host_authenticator.cc
+++ b/remoting/protocol/pairing_host_authenticator.cc
@@ -63,7 +63,6 @@
     const base::Closure& resume_callback) {
   if (!v2_authenticator_) {
     std::string client_id;
-    std::string paired_secret;
 
     const buzz::XmlElement* pairing_tag = message->FirstNamed(kPairingInfoTag);
     if (pairing_tag) {
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator.cc b/remoting/protocol/ssl_hmac_channel_authenticator.cc
index 648e409..20bfc53 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator.cc
+++ b/remoting/protocol/ssl_hmac_channel_authenticator.cc
@@ -14,6 +14,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/http/transport_security_state.h"
 #include "net/socket/client_socket_factory.h"
+#include "net/socket/client_socket_handle.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/socket/ssl_server_socket.h"
 #include "net/ssl/ssl_config_service.h"
@@ -72,16 +73,16 @@
       return;
     }
 
-    net::SSLConfig ssl_config;
-    net::SSLServerSocket* server_socket =
-        net::CreateSSLServerSocket(socket.release(),
+    scoped_ptr<net::SSLServerSocket> server_socket =
+        net::CreateSSLServerSocket(socket.Pass(),
                                    cert.get(),
                                    local_key_pair_->private_key(),
-                                   ssl_config);
-    socket_.reset(server_socket);
-
-    result = server_socket->Handshake(base::Bind(
-        &SslHmacChannelAuthenticator::OnConnected, base::Unretained(this)));
+                                   net::SSLConfig());
+    net::SSLServerSocket* raw_server_socket = server_socket.get();
+    socket_ = server_socket.Pass();
+    result = raw_server_socket->Handshake(
+        base::Bind(&SslHmacChannelAuthenticator::OnConnected,
+                   base::Unretained(this)));
   } else {
     cert_verifier_.reset(net::CertVerifier::CreateDefault());
     transport_security_state_.reset(new net::TransportSecurityState);
@@ -103,9 +104,11 @@
     net::SSLClientSocketContext context;
     context.cert_verifier = cert_verifier_.get();
     context.transport_security_state = transport_security_state_.get();
-    socket_.reset(
+    scoped_ptr<net::ClientSocketHandle> connection(new net::ClientSocketHandle);
+    connection->SetSocket(socket.Pass());
+    socket_ =
         net::ClientSocketFactory::GetDefaultFactory()->CreateSSLClientSocket(
-            socket.release(), host_and_port, ssl_config, context));
+            connection.Pass(), host_and_port, ssl_config, context);
 
     result = socket_->Connect(
         base::Bind(&SslHmacChannelAuthenticator::OnConnected,
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index f81cfd3..89ad20d 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -82,17 +82,16 @@
       ['OS=="win"', {
         'host_plugin_extension': 'dll',
         'host_plugin_prefix': '',
-      }],
-      ['OS=="win"', {
         # Use auto-generated CLSIDs to make sure that the newly installed COM
         # classes will be used during/after upgrade even if there are old
         # instances running already.
-        # The parameter passed to uuidgen.py is ignored, but needed to make sure
-        # that the script will be invoked separately for each CLSID. Otherwise
-        # GYP will reuse the value returned by the first invocation of
-        # the script.
-        'daemon_controller_clsid': '<!(python tools/uuidgen.py 1)',
-        'rdp_desktop_session_clsid': '<!(python tools/uuidgen.py 2)',
+        # The parameter at the end is ignored, but needed to make sure that the
+        # script will be invoked separately for each CLSID. Otherwise GYP will
+        # reuse the value returned by the first invocation of the script.
+        'daemon_controller_clsid':
+            '<!(python -c "import uuid; print uuid.uuid4()" 1)',
+        'rdp_desktop_session_clsid':
+            '<!(python -c "import uuid; print uuid.uuid4()" 2)',
       }],
     ],
 
@@ -565,27 +564,6 @@
         },  # end of target 'remoting_me2me_host_static'
 
         {
-          'target_name': 'remoting_host_keygen',
-          'type': 'executable',
-          'dependencies': [
-            'remoting_base',
-            '../base/base.gyp:base',
-            '../base/base.gyp:base_i18n',
-            '../crypto/crypto.gyp:crypto',
-          ],
-          'sources': [
-            'host/keygen_main.cc',
-          ],
-          'conditions': [
-            ['OS=="linux" and linux_use_tcmalloc==1', {
-              'dependencies': [
-                '../base/allocator/allocator.gyp:allocator',
-              ],
-            }],
-          ],
-        },  # end of target 'remoting_host_keygen'
-
-        {
           'target_name': 'remoting_host_setup_base',
           'type': 'static_library',
           'variables': { 'enable_wexit_time_destructors': 1, },
@@ -612,6 +590,8 @@
             'host/setup/native_messaging_reader.h',
             'host/setup/native_messaging_writer.cc',
             'host/setup/native_messaging_writer.h',
+            'host/setup/oauth_client.cc',
+            'host/setup/oauth_client.h',
             'host/setup/oauth_helper.cc',
             'host/setup/oauth_helper.h',
             'host/setup/pin_validator.cc',
@@ -1149,6 +1129,7 @@
             'remoting_host_prefpane',
             'remoting_host_uninstaller',
             'remoting_me2me_host',
+            'remoting_native_messaging_host',
           ],
           'variables': {
             'host_name': '<!(python <(version_py_path) -f <(branding_path) -t "@HOST_PLUGIN_FILE_NAME@")',
@@ -1170,11 +1151,15 @@
                 '<(PRODUCT_DIR)/remoting_host_prefpane.prefPane',
                 '<(PRODUCT_DIR)/remoting_me2me_host.app',
                 '<(PRODUCT_DIR)/remoting_host_uninstaller.app',
+                '<(PRODUCT_DIR)/remoting_native_messaging_host',
+                '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_desktop.json',
               ],
               'generated_files_dst': [
                 'PreferencePanes/org.chromium.chromoting.prefPane',
                 'PrivilegedHelperTools/org.chromium.chromoting.me2me_host.app',
                 'Applications/<(host_uninstaller_name).app',
+                'PrivilegedHelperTools/org.chromium.chromoting.me2me_host.app/Contents/MacOS/native_messaging_host',
+		'Config/com.google.chrome.remote_desktop.json',
               ],
               'source_files': [
                 '<@(remoting_host_installer_mac_files)',
@@ -1747,7 +1732,7 @@
         },  # end of target 'remoting_host_messages'
 
         # Generates localized the version information resources for the Windows
-        # binaries. 
+        # binaries.
         # The substitution strings are taken from:
         #   - build/util/LASTCHANGE - the last source code revision.
         #   - chrome/VERSION - the major, build & patch versions.
@@ -1969,13 +1954,13 @@
           'generated_files': [
             '<@(_compiled_inputs)',
             '<(sas_dll_path)/sas.dll',
-            '<(PRODUCT_DIR)/remoting/native_messaging_manifest.json',
+            '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_desktop.json',
             'resources/chromoting.ico',
           ],
           'generated_files_dst': [
             '<@(_compiled_inputs_dst)',
             'files/sas.dll',
-            'files/native_messaging_manifest.json',
+            'files/com.google.chrome.remote_desktop.json',
             'files/chromoting.ico',
           ],
           'zip_path': '<(PRODUCT_DIR)/remoting-me2me-host-<(OS).zip',
@@ -2070,8 +2055,12 @@
       'sources': [
         'client/plugin/chromoting_instance.cc',
         'client/plugin/chromoting_instance.h',
-        'client/plugin/mac_key_event_processor.cc',
-        'client/plugin/mac_key_event_processor.h',
+        'client/plugin/normalizing_input_filter.cc',
+        'client/plugin/delegating_signal_strategy.cc',
+        'client/plugin/delegating_signal_strategy.h',
+        'client/plugin/normalizing_input_filter.h',
+        'client/plugin/normalizing_input_filter_cros.cc',
+        'client/plugin/normalizing_input_filter_mac.cc',
         'client/plugin/pepper_audio_player.cc',
         'client/plugin/pepper_audio_player.h',
         'client/plugin/pepper_entrypoints.cc',
@@ -2088,12 +2077,17 @@
         'client/plugin/pepper_port_allocator.h',
         'client/plugin/pepper_token_fetcher.cc',
         'client/plugin/pepper_token_fetcher.h',
-        'client/plugin/pepper_view.cc',
-        'client/plugin/pepper_view.h',
         'client/plugin/pepper_util.cc',
         'client/plugin/pepper_util.h',
-        'client/plugin/pepper_signal_strategy.cc',
-        'client/plugin/pepper_signal_strategy.h',
+        'client/plugin/pepper_view.cc',
+        'client/plugin/pepper_view.h',
+      ],
+      'conditions' : [
+        [ '(OS!="linux" or chromeos==0)', {
+          'sources!': [
+            'client/plugin/normalizing_input_filter_cros.cc',
+          ],
+        }],
       ],
     },  # end of target 'remoting_client_plugin'
 
@@ -2230,7 +2224,7 @@
       'target_conditions': [
         # We cannot currently build the appsv2 version of WebApp on Windows as
         # there isn't a version of the "patch" tool available on windows. We
-        # should remove this condition when we remove the reliance on the 'patch'.
+        # should remove this condition when we remove the reliance on patch.
 
         # We define this in a 'target_conditions' section because 'plugin_path'
         # is defined in a 'conditions' section so its value is not available
@@ -2295,42 +2289,55 @@
       ],
       'variables': {
         'input': 'host/setup/native_messaging_manifest.json',
-        'output': '<(PRODUCT_DIR)/remoting/native_messaging_manifest.json',
+        'output': '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_desktop.json',
       },
-      'conditions': [
-        [ 'OS=="win"', {
-          'variables': {
-            'native_messaging_host_path': 'remoting_host.exe',
-          },
-        }, {
-          'variables': {
-            'native_messaging_host_path': '/opt/google/chrome-remote-desktop/native-messaging-host',
-          },
-        }],
-      ],
-      'actions': [
-        {
-          'action_name': 'generate_manifest',
-          'inputs': [
-            '<(remoting_localize_path)',
-            '<(input)',
-          ],
-          'outputs': [
-            '<(output)',
-          ],
-          'action': [
-            'python',
-            '<(remoting_localize_path)',
-            '--define', 'NATIVE_MESSAGING_HOST_PATH=<(native_messaging_host_path)',
-            '--locale_dir', '<(webapp_locale_dir)',
-            '--template', '<(input)',
-            '--locale_output',
-            '<(output)',
-            '--encoding', 'utf-8',
-            'en',
-          ],
+      'target_conditions': [
+        ['OS == "win" or OS == "mac" or OS == "linux"', {
+          'conditions': [
+            [ 'OS == "win"', {
+              'variables': {
+                'native_messaging_host_path': 'remoting_host.exe',
+              },
+            }], [ 'OS == "mac"', {
+              'variables': {
+                'native_messaging_host_path': '/Library/PrivilegedHelperTools/org.chromium.chromoting.me2me_host.app/Contents/MacOS/native_messaging_host',
+              },
+            }], ['OS == "linux"', {
+              'variables': {
+                'native_messaging_host_path': '/opt/google/chrome-remote-desktop/native-messaging-host',
+              },
+            }], ['OS != "linux" and OS != "mac" and OS != "win"', {
+              'variables': {
+                'native_messaging_host_path': '/opt/google/chrome-remote-desktop/native-messaging-host',
+              },
+            }],
+          ],  # conditions
+          'actions': [
+            {
+              'action_name': 'generate_manifest',
+              'inputs': [
+                '<(remoting_localize_path)',
+                '<(input)',
+              ],
+              'outputs': [
+                '<(output)',
+              ],
+              'action': [
+                'python',
+                '<(remoting_localize_path)',
+                '--define', 'NATIVE_MESSAGING_HOST_PATH=<(native_messaging_host_path)',
+                '--locale_dir', '<(webapp_locale_dir)',
+                '--template', '<(input)',
+                '--locale_output',
+                '<(output)',
+                '--encoding', 'utf-8',
+                'en',
+              ],
+            },
+          ],  # actions
         },
-      ],
+       ],
+      ],  # target_conditions
     },  # end of target 'remoting_native_messaging_manifest'
     {
       'target_name': 'remoting_resources',
@@ -2762,7 +2769,8 @@
         'base/util_unittest.cc',
         'client/audio_player_unittest.cc',
         'client/key_event_mapper_unittest.cc',
-        'client/plugin/mac_key_event_processor_unittest.cc',
+        'client/plugin/normalizing_input_filter_cros_unittest.cc',
+        'client/plugin/normalizing_input_filter_mac_unittest.cc',
         'codec/audio_encoder_opus_unittest.cc',
         'codec/codec_test.cc',
         'codec/codec_test.h',
@@ -2875,7 +2883,7 @@
             ],
           },
         }],
-        ['OS=="mac" or (OS=="linux" and chromeos==0)', {
+        [ 'OS=="mac" or (OS=="linux" and chromeos==0)', {
           # Javascript unittests are disabled on CrOS because they cause
           # valgrind and test errors.
           #
@@ -2909,6 +2917,11 @@
             '<@(remoting_webapp_js_files)',
           ],
         }],
+        [ '(OS!="linux" or chromeos==0)', {
+          'sources!': [
+            'client/plugin/normalizing_input_filter_cros_unittest.cc',
+          ],
+        }],
         ['enable_remoting_host == 0', {
           'dependencies!': [
             'remoting_host',
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd
index f71fafd..41d6c53 100644
--- a/remoting/resources/remoting_strings.grd
+++ b/remoting/resources/remoting_strings.grd
@@ -530,9 +530,12 @@
       <message desc="Label for general-purpose OK buttons." name="IDR_OK">
         OK
       </message>
-      <message desc="Modified version of the host name shown for hosts that are not currently accessible." name="IDR_OFFLINE">
+      <message desc="Modified version of the host name shown for hosts that are not currently accessible, and for which no last-online status is available." name="IDR_OFFLINE">
         <ph name="HOSTNAME">$1<ex>My Linux desktop</ex></ph> (offline)
       </message>
+      <message desc="Modified version of the host name shown for hosts that are not currently accessible." name="IDR_LAST_ONLINE">
+        <ph name="HOSTNAME">$1<ex>My Linux desktop</ex></ph> (last online <ph name="DATE">$2<ex>1/6/13</ex></ph>)
+      </message>
       <message desc="Modified version of the host name shown for hosts that are running an out-of-date version of the Me2Me host software." name="IDR_UPDATE_REQUIRED">
         <ph name="HOSTNAME">$1<ex>My Linux desktop</ex></ph> (out-of-date)
       </message>
diff --git a/remoting/test/auth_browsertest.cc b/remoting/test/auth_browsertest.cc
new file mode 100644
index 0000000..fcb3987
--- /dev/null
+++ b/remoting/test/auth_browsertest.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 "remote_desktop_browsertest.h"
+
+namespace remoting {
+
+IN_PROC_BROWSER_TEST_F(RemoteDesktopBrowserTest, MANUAL_Auth) {
+  VerifyInternetAccess();
+
+  Install();
+
+  LaunchChromotingApp();
+
+  // Authorize, Authenticate, and Approve.
+  Auth();
+
+  Cleanup();
+}
+
+}  // namespace remoting
diff --git a/remoting/test/launch_browsertest.cc b/remoting/test/launch_browsertest.cc
new file mode 100644
index 0000000..4c9804e
--- /dev/null
+++ b/remoting/test/launch_browsertest.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 "remote_desktop_browsertest.h"
+
+namespace remoting {
+
+IN_PROC_BROWSER_TEST_F(RemoteDesktopBrowserTest, MANUAL_Launch) {
+  VerifyInternetAccess();
+
+  Install();
+
+  LaunchChromotingApp();
+
+  Cleanup();
+}
+
+}  // namespace remoting
diff --git a/remoting/test/remote_desktop_browsertest.cc b/remoting/test/remote_desktop_browsertest.cc
index 4242410..8d91a06 100644
--- a/remoting/test/remote_desktop_browsertest.cc
+++ b/remoting/test/remote_desktop_browsertest.cc
@@ -2,239 +2,38 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "remote_desktop_browsertest.h"
+
 #include "base/command_line.h"
-#include "base/path_service.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/unpacked_installer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.cc"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/manifest.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 "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "net/dns/mock_host_resolver.h"
 
 using extensions::Extension;
 
-namespace {
-// Command line arguments specific to the chromoting browser tests.
-const char kOverrideUserDataDir[] = "override-user-data-dir";
-const char kNoCleanup[] = "no-cleanup";
-const char kNoInstall[] = "no-install";
-const char kWebAppCrx[] = "webapp-crx";
-const char kUsername[] = "username";
-const char kkPassword[] = "password";
-
-// ASSERT_TRUE can only be used in void returning functions.
-void _ASSERT_TRUE(bool condition) {
-  ASSERT_TRUE(condition);
-  return;
-}
-
-}
-
 namespace remoting {
 
-class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
- public:
-  virtual void SetUp() OVERRIDE {
-    ParseCommandLine();
-    ExtensionBrowserTest::SetUp();
-  }
+RemoteDesktopBrowserTest::RemoteDesktopBrowserTest() {}
 
- protected:
-  // Override InProcessBrowserTest. Change behavior of the default host
-  // resolver to avoid DNS lookup errors, so we can make network calls.
-  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
-    // The resolver object lifetime is managed by sync_test_setup, not here.
-    EnableDNSLookupForThisTest(
-        new net::RuleBasedHostResolverProc(host_resolver()));
-  }
+RemoteDesktopBrowserTest::~RemoteDesktopBrowserTest() {}
 
-  // Override InProcessBrowserTest.
-  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
-    DisableDNSLookupForThisTest();
-  }
-
-  // Install the chromoting extension from a crx file.
-  void InstallChromotingApp();
-
-  // Uninstall the chromoting extension.
-  void UninstallChromotingApp();
-
-  // Test whether the chromoting extension is installed.
-  void VerifyChromotingLoaded(bool expected);
-
-  // Launch the chromoting app.
-  void LaunchChromotingApp();
-
-  // Verify the test has access to the internet (specifically google.com)
-  void VerifyInternetAccess();
-
-  void Authorize();
-
-  void Authenticate();
-
-  // Whether to perform the cleanup tasks (uninstalling chromoting, etc).
-  // This is useful for diagnostic purposes.
-  bool NoCleanup() { return no_cleanup_; }
-
-  // Whether to install the chromoting extension before running the test cases.
-  // This is useful for diagnostic purposes.
-  bool NoInstall() { return no_install_; }
-
- private:
-  void ParseCommandLine();
-
-  // Change behavior of the default host resolver to allow DNS lookup
-  // to proceed instead of being blocked by the test infrastructure.
-  void EnableDNSLookupForThisTest(
-    net::RuleBasedHostResolverProc* host_resolver);
-
-  // We need to reset the DNS lookup when we finish, or the test will fail.
-  void DisableDNSLookupForThisTest();
-
-  // Helper to get the path to the crx file of the webapp to be tested.
-  base::FilePath WebAppCrxPath() { return webapp_crx_; }
-
-  // Helper to get the extension ID of the installed chromoting webapp.
-  std::string ChromotingID() { return chromoting_id_; }
-
-  // Helper to retrieve the current URL of the active tab in the browser.
-  GURL GetCurrentURL() {
-    return browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
-  }
-
-  // Helper to execute a javascript code snippet on the current page.
-  void ExecuteScript(const std::string& script) {
-    ASSERT_TRUE(content::ExecuteScript(
-        browser()->tab_strip_model()->GetActiveWebContents(), script));
-  }
-
-  // Helper to execute a javascript code snippet on the current page and
-  // wait for page load to complete.
-  void ExecuteScriptAndWait(const std::string& script) {
-    content::WindowedNotificationObserver observer(
-        content::NOTIFICATION_LOAD_STOP,
-        content::Source<content::NavigationController>(
-            &browser()->tab_strip_model()->GetActiveWebContents()->
-                GetController()));
-
-    ExecuteScript(script);
-
-    observer.Wait();
-  }
-
-  // Helper to execute a javascript code snippet on the current page and
-  // extract the boolean result.
-  bool ExecuteScriptAndExtractBool(const std::string& script) {
-    bool result;
-    // Using a private assert function because ASSERT_TRUE can only be used in
-    // void returning functions.
-    _ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-        browser()->tab_strip_model()->GetActiveWebContents(),
-        "window.domAutomationController.send(" + script + ");",
-        &result));
-
-    return result;
-  }
-
-  // Helper to check whether a html element with the given name exists on
-  // the current page.
-  bool HtmlElementExists(const std::string& name) {
-    return ExecuteScriptAndExtractBool(
-        "document.getElementById(\"" + name + "\") != null");
-  }
-
-  // Helper to navigate to a given url.
-  void NavigateToURLAndWait(const GURL& url) {
-    content::WindowedNotificationObserver observer(
-        content::NOTIFICATION_LOAD_STOP,
-        content::Source<content::NavigationController>(
-            &browser()->tab_strip_model()->GetActiveWebContents()->
-                GetController()));
-
-    ui_test_utils::NavigateToURL(browser(), url);
-    observer.Wait();
-  }
-
-  // This test needs to make live DNS requests for access to
-  // GAIA and sync server URLs under google.com. We use a scoped version
-  // to override the default resolver while the test is active.
-  scoped_ptr<net::ScopedDefaultHostResolverProc> mock_host_resolver_override_;
-
-  bool no_cleanup_;
-  bool no_install_;
-  std::string chromoting_id_;
-  base::FilePath webapp_crx_;
-  std::string username_;
-  std::string password_;
-};
-
-void RemoteDesktopBrowserTest::ParseCommandLine() {
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-
-  // The test framework overrides any command line user-data-dir
-  // argument with a /tmp/.org.chromium.Chromium.XXXXXX directory.
-  // That happens in the ChromeTestLauncherDelegate, and affects
-  // all unit tests (no opt out available). It intentionally erases
-  // any --user-data-dir switch if present and appends a new one.
-  // Re-override the default data dir if override-user-data-dir
-  // is specified.
-  if (command_line->HasSwitch(kOverrideUserDataDir)) {
-    const base::FilePath& override_user_data_dir =
-        command_line->GetSwitchValuePath(kOverrideUserDataDir);
-
-    ASSERT_FALSE(override_user_data_dir.empty());
-
-    command_line->AppendSwitchPath(switches::kUserDataDir,
-                                   override_user_data_dir);
-  }
-
-  username_ = command_line->GetSwitchValueASCII(kUsername);
-  password_ = command_line->GetSwitchValueASCII(kkPassword);
-
-  no_cleanup_ = command_line->HasSwitch(kNoCleanup);
-  no_install_ = command_line->HasSwitch(kNoInstall);
-
-  if (!no_install_) {
-    webapp_crx_ = command_line->GetSwitchValuePath(kWebAppCrx);
-    ASSERT_FALSE(webapp_crx_.empty());
-  }
+void RemoteDesktopBrowserTest::SetUp() {
+  ParseCommandLine();
+  ExtensionBrowserTest::SetUp();
 }
 
-void RemoteDesktopBrowserTest::EnableDNSLookupForThisTest(
-    net::RuleBasedHostResolverProc* host_resolver) {
-  // mock_host_resolver_override_ takes ownership of the resolver.
-  scoped_refptr<net::RuleBasedHostResolverProc> resolver =
-      new net::RuleBasedHostResolverProc(host_resolver);
-  resolver->AllowDirectLookup("*.google.com");
-  // On Linux, we use Chromium's NSS implementation which uses the following
-  // hosts for certificate verification. Without these overrides, running the
-  // integration tests on Linux causes errors as we make external DNS lookups.
-  resolver->AllowDirectLookup("*.thawte.com");
-  resolver->AllowDirectLookup("*.geotrust.com");
-  resolver->AllowDirectLookup("*.gstatic.com");
-  resolver->AllowDirectLookup("*.googleapis.com");
-  mock_host_resolver_override_.reset(
-      new net::ScopedDefaultHostResolverProc(resolver.get()));
+// Change behavior of the default host resolver to avoid DNS lookup errors,
+// so we can make network calls.
+void RemoteDesktopBrowserTest::SetUpInProcessBrowserTestFixture() {
+  // The resolver object lifetime is managed by sync_test_setup, not here.
+  EnableDNSLookupForThisTest(
+      new net::RuleBasedHostResolverProc(host_resolver()));
 }
 
-void RemoteDesktopBrowserTest::DisableDNSLookupForThisTest() {
-  mock_host_resolver_override_.reset();
+void RemoteDesktopBrowserTest::TearDownInProcessBrowserTestFixture() {
+  DisableDNSLookupForThisTest();
 }
 
 void RemoteDesktopBrowserTest::VerifyInternetAccess() {
@@ -257,16 +56,6 @@
   chromoting_id_.clear();
 }
 
-void RemoteDesktopBrowserTest::LaunchChromotingApp() {
-  ASSERT_FALSE(ChromotingID().empty());
-
-  std::string url = "chrome-extension://" + ChromotingID() + "/main.html";
-  const GURL chromoting_main(url);
-  NavigateToURLAndWait(chromoting_main);
-
-  EXPECT_EQ(GetCurrentURL(), chromoting_main);
-}
-
 void RemoteDesktopBrowserTest::VerifyChromotingLoaded(bool expected) {
   const ExtensionSet* extensions = extension_service()->extensions();
   scoped_refptr<const extensions::Extension> extension;
@@ -296,14 +85,22 @@
   EXPECT_EQ(installed, expected);
 }
 
+void RemoteDesktopBrowserTest::LaunchChromotingApp() {
+  ASSERT_FALSE(ChromotingID().empty());
+
+  const GURL chromoting_main = Chromoting_Main_URL();
+  NavigateToURLAndWait(chromoting_main);
+
+  EXPECT_EQ(GetCurrentURL(), chromoting_main);
+}
+
 void RemoteDesktopBrowserTest::Authorize() {
   // The chromoting extension should be installed.
   ASSERT_FALSE(ChromotingID().empty());
 
   // The chromoting main page should be loaded in the current tab
   // and isAuthenticated() should be false (auth dialog visible).
-  std::string url = "chrome-extension://" + ChromotingID() + "/main.html";
-  ASSERT_EQ(GetCurrentURL().spec(), url);
+  ASSERT_EQ(GetCurrentURL(), Chromoting_Main_URL());
   ASSERT_FALSE(ExecuteScriptAndExtractBool(
       "remoting.OAuth2.prototype.isAuthenticated()"));
 
@@ -337,18 +134,40 @@
   EXPECT_TRUE(HtmlElementExists("submit_approve_access"));
 }
 
-IN_PROC_BROWSER_TEST_F(RemoteDesktopBrowserTest, MANUAL_Launch) {
-  VerifyInternetAccess();
+void RemoteDesktopBrowserTest::Approve() {
+  // The chromoting extension should be installed.
+  ASSERT_FALSE(ChromotingID().empty());
 
+  // The active tab should have the chromoting app loaded.
+  ASSERT_EQ(GetCurrentURL().host(), "accounts.google.com");
+
+  // Is there a better way to verify we are on the "Request for Permission"
+  // page?
+  ASSERT_TRUE(HtmlElementExists("submit_approve_access"));
+
+  const GURL chromoting_main = Chromoting_Main_URL();
+  ExecuteScriptAndWaitUntil(
+      "lso.approveButtonAction();"
+      "document.forms[\"connect-approve\"].submit();",
+      chromoting_main);
+
+  ASSERT_TRUE(GetCurrentURL() == chromoting_main);
+
+  EXPECT_TRUE(ExecuteScriptAndExtractBool(
+      "remoting.OAuth2.prototype.isAuthenticated()"));
+}
+
+void RemoteDesktopBrowserTest::Install() {
+  // TODO: add support for installing unpacked extension (the v2 app needs it).
   if (!NoInstall()) {
     VerifyChromotingLoaded(false);
     InstallChromotingApp();
   }
 
   VerifyChromotingLoaded(true);
+}
 
-  LaunchChromotingApp();
-
+void RemoteDesktopBrowserTest::Cleanup() {
   // TODO: Remove this hack by blocking on the appropriate notification.
   // The browser may still be loading images embedded in the webapp. If we
   // uinstall it now those load will fail. Navigating away to avoid the load
@@ -361,26 +180,128 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(RemoteDesktopBrowserTest, MANUAL_Auth) {
-  VerifyInternetAccess();
-
-  if (!NoInstall()) {
-    VerifyChromotingLoaded(false);
-    InstallChromotingApp();
-  }
-
-  VerifyChromotingLoaded(true);
-
-  LaunchChromotingApp();
-
+void RemoteDesktopBrowserTest::Auth() {
   Authorize();
-
   Authenticate();
+  Approve();
+}
 
-  if (!NoCleanup()) {
-    UninstallChromotingApp();
-    VerifyChromotingLoaded(false);
+void RemoteDesktopBrowserTest::EnableDNSLookupForThisTest(
+    net::RuleBasedHostResolverProc* host_resolver) {
+  // mock_host_resolver_override_ takes ownership of the resolver.
+  scoped_refptr<net::RuleBasedHostResolverProc> resolver =
+      new net::RuleBasedHostResolverProc(host_resolver);
+  resolver->AllowDirectLookup("*.google.com");
+  // On Linux, we use Chromium's NSS implementation which uses the following
+  // hosts for certificate verification. Without these overrides, running the
+  // integration tests on Linux causes errors as we make external DNS lookups.
+  resolver->AllowDirectLookup("*.thawte.com");
+  resolver->AllowDirectLookup("*.geotrust.com");
+  resolver->AllowDirectLookup("*.gstatic.com");
+  resolver->AllowDirectLookup("*.googleapis.com");
+  mock_host_resolver_override_.reset(
+      new net::ScopedDefaultHostResolverProc(resolver.get()));
+}
+
+void RemoteDesktopBrowserTest::DisableDNSLookupForThisTest() {
+  mock_host_resolver_override_.reset();
+}
+
+void RemoteDesktopBrowserTest::ParseCommandLine() {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+  // The test framework overrides any command line user-data-dir
+  // argument with a /tmp/.org.chromium.Chromium.XXXXXX directory.
+  // That happens in the ChromeTestLauncherDelegate, and affects
+  // all unit tests (no opt out available). It intentionally erases
+  // any --user-data-dir switch if present and appends a new one.
+  // Re-override the default data dir if override-user-data-dir
+  // is specified.
+  if (command_line->HasSwitch(kOverrideUserDataDir)) {
+    const base::FilePath& override_user_data_dir =
+        command_line->GetSwitchValuePath(kOverrideUserDataDir);
+
+    ASSERT_FALSE(override_user_data_dir.empty());
+
+    command_line->AppendSwitchPath(switches::kUserDataDir,
+                                   override_user_data_dir);
   }
+
+  username_ = command_line->GetSwitchValueASCII(kUsername);
+  password_ = command_line->GetSwitchValueASCII(kkPassword);
+
+  no_cleanup_ = command_line->HasSwitch(kNoCleanup);
+  no_install_ = command_line->HasSwitch(kNoInstall);
+
+  if (!no_install_) {
+    webapp_crx_ = command_line->GetSwitchValuePath(kWebAppCrx);
+    ASSERT_FALSE(webapp_crx_.empty());
+  }
+}
+
+void RemoteDesktopBrowserTest::ExecuteScript(const std::string& script) {
+  ASSERT_TRUE(content::ExecuteScript(
+      browser()->tab_strip_model()->GetActiveWebContents(), script));
+}
+
+void RemoteDesktopBrowserTest::ExecuteScriptAndWait(const std::string& script) {
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &browser()->tab_strip_model()->GetActiveWebContents()->
+              GetController()));
+
+  ExecuteScript(script);
+
+  observer.Wait();
+}
+
+void RemoteDesktopBrowserTest::ExecuteScriptAndWaitUntil(
+    const std::string& script,
+    const GURL& target) {
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &browser()->tab_strip_model()->GetActiveWebContents()->
+              GetController()));
+
+  ExecuteScript(script);
+
+  observer.Wait();
+
+  // TODO: is there a better way to wait for all the redirections to complete?
+  while (GetCurrentURL() != target) {
+    content::WindowedNotificationObserver(
+        content::NOTIFICATION_LOAD_STOP,
+        content::Source<content::NavigationController>(
+            &browser()->tab_strip_model()->GetActiveWebContents()->
+                GetController())).Wait();
+  }
+}
+
+bool RemoteDesktopBrowserTest::ExecuteScriptAndExtractBool(
+    const std::string& script) {
+  bool result;
+  // Using a private assert function because ASSERT_TRUE can only be used in
+  // void returning functions.
+  _ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "window.domAutomationController.send(" + script + ");",
+      &result));
+
+  return result;
+}
+
+// Helper to navigate to a given url.
+void RemoteDesktopBrowserTest::NavigateToURLAndWait(const GURL& url) {
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &browser()->tab_strip_model()->GetActiveWebContents()->
+              GetController()));
+
+  ui_test_utils::NavigateToURL(browser(), url);
+  observer.Wait();
 }
 
 }  // namespace remoting
diff --git a/remoting/test/remote_desktop_browsertest.h b/remoting/test/remote_desktop_browsertest.h
new file mode 100644
index 0000000..96a5b5e
--- /dev/null
+++ b/remoting/test/remote_desktop_browsertest.h
@@ -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.
+
+#ifndef REMOTE_DESKTOP_BROWSER_TEST_H_
+#define REMOTE_DESKTOP_BROWSER_TEST_H_
+
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+
+namespace {
+// Command line arguments specific to the chromoting browser tests.
+const char kOverrideUserDataDir[] = "override-user-data-dir";
+const char kNoCleanup[] = "no-cleanup";
+const char kNoInstall[] = "no-install";
+const char kWebAppCrx[] = "webapp-crx";
+const char kUsername[] = "username";
+const char kkPassword[] = "password";
+
+// ASSERT_TRUE can only be used in void returning functions.
+void _ASSERT_TRUE(bool condition) {
+  ASSERT_TRUE(condition);
+  return;
+}
+
+}
+
+namespace remoting {
+
+class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
+ public:
+  RemoteDesktopBrowserTest();
+  virtual ~RemoteDesktopBrowserTest();
+
+  // InProcessBrowserTest Overrides
+  virtual void SetUp() OVERRIDE;
+
+ protected:
+  // InProcessBrowserTest Overrides
+  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
+
+  // InProcessBrowserTest Overrides
+  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE;
+
+
+  /*                                                    */
+  /* The following helpers each perform a simple task.  */
+  /*                                                    */
+
+  // Verify the test has access to the internet (specifically google.com)
+  void VerifyInternetAccess();
+
+  // Install the chromoting extension from a crx file.
+  void InstallChromotingApp();
+
+  // Uninstall the chromoting extension.
+  void UninstallChromotingApp();
+
+  // Test whether the chromoting extension is installed.
+  void VerifyChromotingLoaded(bool expected);
+
+  // Launch the chromoting app.
+  void LaunchChromotingApp();
+
+  // Authorize: grant extended access permission to the user's computer.
+  void Authorize();
+
+  // Authenticate: sign in to google using the credentials provided.
+  void Authenticate();
+
+  // Approve: grant the chromoting app necessary permissions.
+  void Approve();
+
+
+  /*                                                      */
+  /* The following helpers each perform a composite task. */
+  /*                                                      */
+
+  // Install the chromoting extension
+  void Install();
+
+  // Clean up after the test.
+  void Cleanup();
+
+  // Perform all the auth steps: authorization, authenticattion, etc.
+  // It starts from the chromoting main page unauthenticated and ends up back
+  // on the chromoting main page authenticated and ready to go.
+  void Auth();
+
+ private:
+  // Change behavior of the default host resolver to allow DNS lookup
+  // to proceed instead of being blocked by the test infrastructure.
+  void EnableDNSLookupForThisTest(
+    net::RuleBasedHostResolverProc* host_resolver);
+
+  // We need to reset the DNS lookup when we finish, or the test will fail.
+  void DisableDNSLookupForThisTest();
+
+  void ParseCommandLine();
+
+
+  /*                    */
+  /* Accessor methods.  */
+  /*                    */
+
+  // Helper to get the path to the crx file of the webapp to be tested.
+  base::FilePath WebAppCrxPath() { return webapp_crx_; }
+
+  // Helper to get the extension ID of the installed chromoting webapp.
+  std::string ChromotingID() { return chromoting_id_; }
+
+  // Whether to perform the cleanup tasks (uninstalling chromoting, etc).
+  // This is useful for diagnostic purposes.
+  bool NoCleanup() { return no_cleanup_; }
+
+  // Whether to install the chromoting extension before running the test cases.
+  // This is useful for diagnostic purposes.
+  bool NoInstall() { return no_install_; }
+
+  // Helper to construct the starting URL of the installed chromoting webapp.
+  GURL Chromoting_Main_URL() {
+    return GURL("chrome-extension://" + ChromotingID() + "/main.html");
+  }
+
+  // Helper to retrieve the current URL of the active tab in the browser.
+  GURL GetCurrentURL() {
+    return browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
+  }
+
+
+  /*                                                    */
+  /* Helpers to execute javascript code on a web page.  */
+  /*                                                    */
+
+  // Helper to execute a javascript code snippet on the current page.
+  void ExecuteScript(const std::string& script);
+
+  // Helper to execute a javascript code snippet on the current page and
+  // wait for page load to complete.
+  void ExecuteScriptAndWait(const std::string& script);
+
+  // Helper to execute a javascript code snippet on the current page and
+  // wait until the target url is loaded. This is used when the target page
+  // is loaded after multiple redirections.
+  void ExecuteScriptAndWaitUntil(const std::string& script, const GURL& target);
+
+  // Helper to execute a javascript code snippet on the current page and
+  // extract the boolean result.
+  bool ExecuteScriptAndExtractBool(const std::string& script);
+
+  // Helper to navigate to a given url.
+  void NavigateToURLAndWait(const GURL& url);
+
+  // Helper to check whether a html element with the given name exists on
+  // the current page.
+  bool HtmlElementExists(const std::string& name) {
+    return ExecuteScriptAndExtractBool(
+        "document.getElementById(\"" + name + "\") != null");
+  }
+
+
+  /*        */
+  /* Fields */
+  /*        */
+
+  // This test needs to make live DNS requests for access to
+  // GAIA and sync server URLs under google.com. We use a scoped version
+  // to override the default resolver while the test is active.
+  scoped_ptr<net::ScopedDefaultHostResolverProc> mock_host_resolver_override_;
+
+  bool no_cleanup_;
+  bool no_install_;
+  std::string chromoting_id_;
+  base::FilePath webapp_crx_;
+  std::string username_;
+  std::string password_;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTE_DESKTOP_BROWSER_TEST_H_
diff --git a/remoting/tools/build_me2me_tarball.sh b/remoting/tools/build_me2me_tarball.sh
deleted file mode 100755
index 45588ac..0000000
--- a/remoting/tools/build_me2me_tarball.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/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.
-
-# Build a tarball distribution of the Virtual Me2Me host for Linux.
-# This script should be run from the top-level "src" directory - the output
-# tarball will be created in the parent directory (to avoid accidentally
-# committing it if "git commit -a" is typed).
-# To do a clean build, remove the out/Release directory before running this
-# script.
-
-set -eu
-
-MERGE_BASE="$(git merge-base HEAD origin/git-svn)"
-REVISION="$(git svn find-rev "$MERGE_BASE")"
-if [ -z "$REVISION" ]; then
-  echo "svn revision number not found"
-  REVISION_SUFFIX=""
-else
-  REVISION_SUFFIX="_r$REVISION"
-fi
-
-echo "Building..."
-make -j25 BUILDTYPE=Release remoting_host_keygen remoting_me2me_host
-
-FILES="\
-  remoting/tools/gaia_auth.py \
-  remoting/tools/keygen.py \
-  remoting/tools/me2me_virtual_host.py \
-  out/Release/remoting_host_keygen \
-  out/Release/remoting_me2me_host \
-"
-
-TEMP_DIR="$(mktemp -d)"
-trap 'rm -rf "$TEMP_DIR"' EXIT
-
-TARBALL_DIR="virtual_me2me"
-mkdir "$TEMP_DIR/$TARBALL_DIR"
-
-for file in $FILES; do
-  cp "$file" "$TEMP_DIR/$TARBALL_DIR"
-  strip "$TEMP_DIR/$TARBALL_DIR/$file" 2>/dev/null || true
-done
-
-TARBALL="../virtual_me2me$REVISION_SUFFIX.tgz"
-
-tar -zcf "$TARBALL" -C "$TEMP_DIR" "$TARBALL_DIR"
-
-echo "Tarball built: $TARBALL"
diff --git a/remoting/tools/gaia_auth.py b/remoting/tools/gaia_auth.py
deleted file mode 100644
index 392f2f3..0000000
--- a/remoting/tools/gaia_auth.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# 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.
-
-import getpass
-import os
-import urllib
-
-DEFAULT_GAIA_URL = "https://www.google.com:443/accounts/ClientLogin"
-
-class GaiaAuthenticator:
-  def __init__(self, service, url = DEFAULT_GAIA_URL):
-    self._service = service
-    self._url = url
-
-  ## Logins to gaia and returns auth token.
-  def authenticate(self, email, passwd):
-    params = urllib.urlencode({'Email': email, 'Passwd': passwd,
-                               'source': 'chromoting',
-                               'service': self._service,
-                               'PersistentCookie': 'true',
-                               'accountType': 'GOOGLE'})
-    f = urllib.urlopen(self._url, params);
-    result = f.read()
-    for line in result.splitlines():
-      if line.startswith('Auth='):
-        auth_string = line[5:]
-        return auth_string
-    raise Exception("Gaia didn't return auth token: " + result)
diff --git a/remoting/tools/gettoken.py b/remoting/tools/gettoken.py
deleted file mode 100755
index 4f867bf..0000000
--- a/remoting/tools/gettoken.py
+++ /dev/null
@@ -1,66 +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.
-
-"""Get auth token from Gaia.
-
-It asks username and password and then prints token on the screen.
-"""
-
-import getpass
-import os
-import urllib
-
-import gaia_auth
-
-
-def main():
-  basepath = os.path.expanduser('~')
-  chromoting_auth_filepath = os.path.join(basepath, '.chromotingAuthToken')
-  chromoting_dir_auth_filepath = os.path.join(
-      basepath, '.chromotingDirectoryAuthToken')
-
-  print "Email:",
-  email = raw_input()
-
-  passwd = getpass.getpass("Password: ")
-
-  chromoting_authenticator = gaia_auth.GaiaAuthenticator('chromiumsync');
-  chromoting_auth_token = chromoting_authenticator.authenticate(email, passwd)
-
-  chromoting_dir_authenticator = gaia_auth.GaiaAuthenticator('chromoting');
-  chromoting_dir_auth_token = chromoting_dir_authenticator.authenticate(
-      email, passwd)
-
-  # Set permission mask for created files.
-  os.umask(0066)
-
-  chromoting_auth_file = open(chromoting_auth_filepath, 'w')
-  chromoting_auth_file.write(email)
-  chromoting_auth_file.write('\n')
-  chromoting_auth_file.write(chromoting_auth_token)
-  chromoting_auth_file.close()
-
-  print
-  print 'Chromoting (sync) Auth Token:'
-  print
-  print chromoting_auth_token
-  print '...saved in', chromoting_auth_filepath
-
-  chromoting_dir_auth_file = open(chromoting_dir_auth_filepath, 'w')
-  chromoting_dir_auth_file.write(email)
-  chromoting_dir_auth_file.write('\n')
-  chromoting_dir_auth_file.write(chromoting_dir_auth_token)
-  chromoting_dir_auth_file.close()
-
-  print
-  print 'Chromoting Directory Auth Token:'
-  print
-  print chromoting_dir_auth_token
-  print '...saved in', chromoting_dir_auth_filepath
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/remoting/tools/hostdir.py b/remoting/tools/hostdir.py
deleted file mode 100755
index c9e01a1..0000000
--- a/remoting/tools/hostdir.py
+++ /dev/null
@@ -1,227 +0,0 @@
-#!/usr/bin/env python
-#
-# 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.
-
-# Chromoting Directory API client implementation. Used for testing/debugging
-# purposes. Requires Python 2.6: json module is not available in earlier
-# versions.
-
-import os
-import httplib
-import json
-import urllib
-import urllib2
-import random
-import sys
-
-DEFAULT_DIRECTORY_SERVER = 'www.googleapis.com'
-
-auth_filepath = os.path.join(os.path.expanduser('~'),
-                             '.chromotingDirectoryAuthToken')
-
-def random_uuid():
-  return ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x" %
-    tuple(map(lambda x: random.randrange(0,65536), range(8))))
-
-class Host:
-  def __init__(self, parameters=None):
-    if parameters != None:
-      self.host_id = parameters[u"hostId"]
-      self.host_name = parameters[u"hostName"]
-      self.public_key = parameters[u"publicKey"]
-      # Following fields may be missing, use get() for them.
-      self.jabber_id = parameters.get(u"jabberId")
-      self.created_time = parameters.get(u"createdTime")
-      self.updated_time = parameters.get(u"updatedTime")
-      self.status = parameters.get(u"status")
-    else:
-      self.host_id = random_uuid()
-      import socket
-      self.host_name = socket.gethostname()
-      self.public_key = None
-      self.jabber_id = None
-      self.created_time = None
-      self.updated_time = None
-      self.status = None
-
-class HostDirectoryError(Exception):
-  def __init__(self, message, response):
-    Exception.__init__(self, message)
-    print response
-    self._response = response
-
-class HostDirectory:
-  def __init__(self, username, auth_token, server=DEFAULT_DIRECTORY_SERVER):
-    self._username = username
-    self._auth_token = auth_token
-    self._base_url = '/chromoting/v1/@me/hosts'
-
-    self._http = httplib.HTTPSConnection(server)
-    self._headers = {"Authorization": "GoogleLogin auth=" + self._auth_token,
-                     "Content-Type": "application/json" }
-
-  def add_host(self, host):
-    host_json = { 'data':
-                    { 'hostId': host.host_id,
-                      'hostName': host.host_name,
-                      'publicKey': host.public_key,
-                      }
-                  }
-    if host.jabber_id:
-      host_json['data']['jabberId'] = host.jabber_id
-    post_data = json.dumps(host_json)
-    self._http.request("POST", self._base_url, post_data, self._headers)
-    response = self._http.getresponse()
-    if response.status != 200:
-      raise HostDirectoryError(response.reason, response.read())
-    data = response.read()
-
-  def get_hosts(self):
-    self._http.request("GET", self._base_url, headers=self._headers)
-    response = self._http.getresponse()
-    if response.status != 200:
-      raise HostDirectoryError(response.reason, response.read())
-    data = response.read()
-    data = json.loads(data)[u'data']
-    results = []
-    if data.has_key(u'items'):
-      for item in data[u'items']:
-        results.append(Host(item))
-    return results
-
-  def delete_host(self, host_id):
-    url = self._base_url + '/' + host_id
-    self._http.request("DELETE", url, headers=self._headers)
-    response = self._http.getresponse()
-    if response.status / 100 != 2: # Normally 204 is returned
-      raise HostDirectoryError(response.reason, response.read())
-    data = response.read()
-
-def usage():
-  sys.stderr.write(
-      ("Usage:\n" +
-       " Login: \t\t%(cmd)s login\n" +
-       " Register host: \t%(cmd)s insert --hostId=<hostId>" +
-       " --hostName=<hostName> \\\n" +
-       "\t\t\t    --publicKey=<publicKey>  --jabberId=<jabberId>\n" +
-       " List hosts: \t\t%(cmd)s list\n" +
-       " Delete a host: \t%(cmd)s delete <host_id>\n")
-                   % {"cmd" : sys.argv[0]})
-  return 1
-
-class CommandError(Exception):
-  def __init__(self, message):
-    Exception.__init__(self, message)
-
-def load_auth_token():
-  try:
-    lines = open(auth_filepath).readlines()
-  except IOError:
-    raise CommandError(("Can't open file (%s). Please run " +
-                        "'%s login' and try again.") %
-                       (auth_filepath, sys.argv[0]))
-  if len(lines) != 2:
-    raise CommandError(("Invalid auth file (%s). Please run " +
-                        "'%s login' and try again.") %
-                       (auth_filepath, sys.argv[0]))
-  return map(lambda x: x.strip(), lines)
-
-def login_cmd(args):
-  """login command"""
-  if len(args) != 0:
-    return usage()
-
-  import getpass
-  import gaia_auth
-
-  print "Email:",
-  email = raw_input()
-  passwd = getpass.getpass("Password: ")
-
-  authenticator = gaia_auth.GaiaAuthenticator('chromoting');
-  auth_token = authenticator.authenticate(email, passwd)
-
-  # Set permission mask for created file.
-  os.umask(0066)
-  auth_file = open(auth_filepath, 'w')
-  auth_file.write(email)
-  auth_file.write('\n')
-  auth_file.write(auth_token)
-  auth_file.close()
-
-  print 'Auth token: ', auth_token
-  print '...saved in', auth_filepath
-
-def list_cmd(args):
-  """list command"""
-  if len(args) != 0:
-    return usage()
-  (username, token) = load_auth_token()
-  client = HostDirectory(username, token)
-  print '%36s  %30s   %s' % ("HOST ID", "HOST NAME", "JABBER ID")
-  for host in client.get_hosts():
-    print '%36s  %30s   %s' % (host.host_id, host.host_name, host.jabber_id)
-  return 0
-
-def insert_cmd(args):
-  """insert command"""
-  (username, token) = load_auth_token()
-  client = HostDirectory(username, token)
-
-  host = Host()
-  for arg in args:
-    if arg.startswith("--hostId="):
-      host.host_id = arg[len("--hostId="):]
-    elif arg.startswith("--hostName="):
-      host.host_name = arg[len("--hostName="):]
-    elif arg.startswith("--publicKey="):
-      host.public_key = arg[len("--publicKey="):]
-    elif arg.startswith("--jabberId="):
-      host.jabber_id = arg[len("--jabberId="):]
-    else:
-      return usage()
-
-  client.add_host(host)
-  return 0
-
-def delete_cmd(args):
-  """delete command"""
-  if len(args) != 1:
-    return usage()
-  host_id = args[0]
-  (username, token) = load_auth_token()
-  client = HostDirectory(username, token)
-  client.delete_host(host_id)
-  return 0
-
-def main():
-  import sys
-  args = sys.argv[1:]
-  if len(args) == 0:
-    return usage()
-  command = args[0]
-
-  try:
-    if command == "help":
-      usage()
-    elif command == "login":
-      return login_cmd(args[1:])
-    elif command == "list":
-      return list_cmd(args[1:])
-    elif command == "insert":
-      return insert_cmd(args[1:])
-    elif command == "delete":
-      return delete_cmd(args[1:])
-    else:
-      raise CommandError("Unknown command: %s" % command);
-
-  except CommandError as e:
-    sys.stderr.write("%s\n" % e.args[0])
-    return 1
-
-  return 0
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/remoting/tools/json_to_grd.py b/remoting/tools/json_to_grd.py
deleted file mode 100755
index 36a26c9..0000000
--- a/remoting/tools/json_to_grd.py
+++ /dev/null
@@ -1,190 +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.
-#
-# This script can be used to convert messages.json to grd translations.
-
-import codecs
-import json
-import optparse
-import os
-import string
-import sys
-import xml.dom.minidom as dom
-
-import sys
-sys.path.append('../../tools/grit')
-sys.path.append('../../tools/grit/grit')
-import tclib
-
-def camelCase2ALL_CAPS(s):
-  for c in string.ascii_uppercase:
-    s = s.replace(c, '_' + c)
-  return s.upper()
-
-def load_messages(filename):
-  import collections
-  def create_ordered_dict(list):
-    return collections.OrderedDict(list)
-  messages = json.load(file(filename), object_pairs_hook=create_ordered_dict)
-  ids = messages.keys()
-
-  result = {}
-  for id in ids:
-    text = messages[id]['message']
-    placeholders = []
-    if messages[id].has_key('placeholders'):
-      for name, p in messages[id]['placeholders'].items():
-        index = p['content']
-        caps_name = camelCase2ALL_CAPS(name)
-        placeholders.append(tclib.Placeholder(caps_name, index, p['example']))
-        text = text.replace('$' + name + '$', caps_name)
-
-    msg = tclib.Message(text, placeholders,
-                        messages[id]['description'])
-    result[id] = msg
-
-  return ids, result
-
-def json_to_grd(input_dir, output_dir):
-  # load list of string IDs and placeholder names from the untranslated file
-  # because order of messages and placeholder names are not persisted in
-  # translations.
-  message_ids, messages = load_messages(
-      os.path.join(input_dir, '_locales/en', 'messages.json'))
-
-  grd_name = os.path.join(output_dir,
-                          'string_resources.grd')
-  grd_xml = dom.parse(grd_name)
-  grd_translations = grd_xml.getElementsByTagName('translations')[0]
-  grd_outputs = grd_xml.getElementsByTagName('outputs')[0]
-  grd_messages = grd_xml.getElementsByTagName('messages')[0]
-
-  for id in message_ids:
-    grit_id = 'IDR_' + id
-    message = grd_xml.createElement('message')
-    grd_messages.appendChild(grd_xml.createTextNode('  '))
-    grd_messages.appendChild(message)
-    grd_messages.appendChild(grd_xml.createTextNode('\n    '))
-    message.setAttribute('name', grit_id)
-    message.setAttribute('desc', messages[id].description)
-    message.appendChild(grd_xml.createTextNode('\n        '))
-    for part in messages[id].parts:
-      if isinstance(part, tclib.Placeholder):
-        ph = grd_xml.createElement('ph')
-        message.appendChild(ph)
-        ph.setAttribute('name', part.presentation)
-        ph.appendChild(grd_xml.createTextNode(part.original))
-        ex = grd_xml.createElement('ex')
-        ph.appendChild(ex)
-        ex.appendChild(grd_xml.createTextNode(part.example))
-      else:
-        message.appendChild(grd_xml.createTextNode(part))
-    message.appendChild(grd_xml.createTextNode('\n      '))
-
-  translations_dir = os.path.join(input_dir, '_locales.official')
-  lang_list = os.listdir(translations_dir)
-  lang_list.sort()
-  for lang in lang_list:
-    # Convert locale name representation to the Grit format.
-    grit_lang = lang.replace('_', '-') if lang != 'en' else 'en_US'
-
-    # Load translations
-    translations_file = file(
-        os.path.join(translations_dir, lang, 'messages.json'))
-    translations = json.load(translations_file)
-    translations_file.close()
-
-    # Uppercase all string name.
-    translations = dict(zip(map(lambda x: x.upper(), translations.iterkeys()),
-                        translations.values()))
-
-    doc = dom.Document()
-
-    bundle = doc.createElement('translationbundle')
-    doc.appendChild(bundle)
-    bundle.setAttribute('lang', grit_lang)
-    written_translations = {}
-    for id in message_ids:
-      bundle.appendChild(doc.createTextNode('\n'))
-
-      if not translations.has_key(id):
-        # Skip not translated messages.
-        continue
-      grit_id = 'IDR_' + id
-
-      placeholders = messages[id].placeholders
-      text = translations[id]['message']
-      for p in placeholders:
-        text = text.replace(p.original, p.presentation)
-
-      msg_id = messages[id].GetId()
-      if written_translations.has_key(msg_id):
-        # We've already written translation for this message.
-        continue
-      parsed_translation = tclib.Translation(text, msg_id, placeholders)
-      written_translations[msg_id] = 1
-
-      translation = doc.createElement('translation')
-      bundle.appendChild(translation)
-      translation.setAttribute('id', parsed_translation.GetId())
-      for part in parsed_translation.parts:
-        if isinstance(part, tclib.Placeholder):
-          ph = doc.createElement('ph')
-          translation.appendChild(ph)
-          ph.setAttribute('name', part.presentation)
-        else:
-          translation.appendChild(doc.createTextNode(part))
-    bundle.appendChild(doc.createTextNode('\n'))
-
-    out_name = os.path.join(output_dir,
-                            'string_resources_' + grit_lang + '.xtb')
-    out = codecs.open(out_name, mode='w', encoding = 'UTF-8')
-    out.write('<?xml version="1.0" ?>\n'
-              '<!DOCTYPE translationbundle>\n')
-    bundle.writexml(out)
-    out.close()
-
-    if grit_lang == 'en_US':
-      continue
-
-    t = grd_xml.createElement('file')
-    grd_translations.appendChild(grd_xml.createTextNode('  '))
-    grd_translations.appendChild(t)
-    grd_translations.appendChild(grd_xml.createTextNode('\n  '))
-    t.setAttribute('path', 'string_resources_' + grit_lang + '.xtb')
-    t.setAttribute('lang', grit_lang)
-
-    t = grd_xml.createElement('output')
-    grd_outputs.appendChild(grd_xml.createTextNode('  '))
-    grd_outputs.appendChild(t)
-    grd_outputs.appendChild(grd_xml.createTextNode('\n  '))
-    t.setAttribute('filename', 'remoting/resources/' + grit_lang + '.pak')
-    t.setAttribute('type', 'data_package')
-    t.setAttribute('lang', grit_lang)
-
-    t = grd_xml.createElement('output')
-    grd_outputs.appendChild(grd_xml.createTextNode('  '))
-    grd_outputs.appendChild(t)
-    grd_outputs.appendChild(grd_xml.createTextNode('\n  '))
-    t.setAttribute('filename',
-                   'remoting/webapp/_locales/' + lang + '/messages.json')
-    t.setAttribute('type', 'chrome_messages_json')
-    t.setAttribute('lang', grit_lang)
-
-  grd_out = codecs.open(grd_name + '_new', mode='w', encoding = 'UTF-8')
-  grd_xml.writexml(grd_out, encoding = 'UTF-8')
-  grd_out.close()
-
-def main():
-  usage = 'Usage: json_to_grd <input_dir> <output_dir>'
-  parser = optparse.OptionParser(usage=usage)
-  options, args = parser.parse_args()
-  if len(args) != 2:
-    parser.error('two positional arguments expected')
-
-  return json_to_grd(args[0], args[1])
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/remoting/tools/keygen.py b/remoting/tools/keygen.py
deleted file mode 100644
index d7e5d58..0000000
--- a/remoting/tools/keygen.py
+++ /dev/null
@@ -1,45 +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.
-
-import os
-import sys
-
-_SCRIPT_PATH = os.path.dirname(sys.argv[0])
-if _SCRIPT_PATH == "":
-  _SCRIPT_PATH = os.getcwd()
-
-_EXE_PATHS_TO_TRY = [
-  '.',
-  '..\\..\\build\\Debug',
-  '..\\..\\build\\Release',
-  '..\\Debug',
-  '..\\Release',
-  '../../xcodebuild/Debug',
-  '../../xcodebuild/Release',
-  '../../out/Debug',
-  '../../out/Release',
-  '/usr/lib/chrome-remote-desktop']
-
-
-def locate_executable(exe_name):
-  for path in _EXE_PATHS_TO_TRY:
-    exe_path = os.path.join(_SCRIPT_PATH, path, exe_name)
-    if os.path.exists(exe_path):
-      return exe_path
-    exe_path = exe_path + ".exe"
-    if os.path.exists(exe_path):
-      return exe_path
-
-  raise Exception("Could not locate executable '%s'" % exe_name)
-
-
-def generateRSAKeyPair():
-  """Returns (priv, pub) keypair where priv is a new private key and
-  pub is the corresponding public key.  Both keys are BASE64 encoded."""
-  keygen_path = locate_executable("remoting_host_keygen")
-  pipe = os.popen(keygen_path)
-  out = pipe.readlines()
-  if len(out) != 2:
-    raise Exception("remoting_host_keygen failed.")
-  return (out[0].strip(), out[1].strip())
diff --git a/remoting/tools/register_host.py b/remoting/tools/register_host.py
deleted file mode 100755
index 6aafa39..0000000
--- a/remoting/tools/register_host.py
+++ /dev/null
@@ -1,115 +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.
-
-"""Registers new hosts in chromoting directory.
-
-It asks for username/password and then writes these settings to config file.
-"""
-
-import base64
-import getpass
-import hashlib
-import hmac
-import json
-import os
-import random
-import socket
-import sys
-import urllib
-import urllib2
-
-import gaia_auth
-import keygen
-
-def random_uuid():
-  return ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x" %
-    tuple(map(lambda x: random.randrange(0,65536), range(8))))
-
-
-def main():
-  server = 'www.googleapis.com'
-  url = 'https://' + server + '/chromoting/v1/@me/hosts'
-
-  settings_filepath = os.path.join(os.path.expanduser('~'),
-                                  '.ChromotingConfig.json')
-
-  print "Email:",
-  email = raw_input()
-  password = getpass.getpass("Password: ")
-
-  chromoting_auth = gaia_auth.GaiaAuthenticator('chromoting')
-  auth_token = chromoting_auth.authenticate(email, password)
-
-  host_id = random_uuid()
-  print "HostId:", host_id
-  host_name = socket.gethostname()
-  print "HostName:", host_name
-
-  print "Generating RSA key pair...",
-  (private_key, public_key) = keygen.generateRSAKeyPair()
-  print "Done"
-
-  while 1:
-    pin = getpass.getpass("Host PIN: ")
-    if len(pin) < 4:
-      print "PIN must be at least 4 characters long."
-      continue
-    pin2 = getpass.getpass("Confirm host PIN: ")
-    if pin2 != pin:
-      print "PINs didn't match. Please try again."
-      continue
-    break
-  host_secret_hash = "hmac:" + base64.b64encode(
-      hmac.new(str(host_id), pin, hashlib.sha256).digest())
-
-  params = { "data": {
-      "hostId": host_id,
-      "hostName": host_name,
-      "publicKey": public_key,
-      } }
-  headers = {"Authorization": "GoogleLogin auth=" + auth_token,
-             "Content-Type": "application/json" }
-  request = urllib2.Request(url, json.dumps(params), headers)
-
-  opener = urllib2.OpenerDirector()
-  opener.add_handler(urllib2.HTTPDefaultErrorHandler())
-
-  print
-  print "Registering host with directory service..."
-  try:
-    res = urllib2.urlopen(request)
-    data = res.read()
-  except urllib2.HTTPError, err:
-    print >> sys.stderr, "Directory returned error:", err
-    print >> sys.stderr, err.fp.read()
-    return 1
-
-  print "Done"
-
-  # Get token that the host will use to athenticate in talk network.
-  authenticator = gaia_auth.GaiaAuthenticator('chromiumsync');
-  auth_token = authenticator.authenticate(email, password)
-
-  # Write settings file.
-  os.umask(0066) # Set permission mask for created file.
-  settings_file = open(settings_filepath, 'w')
-  config = {
-      "xmpp_login" : email,
-      "xmpp_auth_token" : auth_token,
-      "host_id" : host_id,
-      "host_name" : host_name,
-      "host_secret_hash": host_secret_hash,
-      "private_key" : private_key,
-      }
-
-  settings_file.write(json.dumps(config, indent=2))
-  settings_file.close()
-
-  print 'Configuration saved in', settings_filepath
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/remoting/tools/uuidgen.py b/remoting/tools/uuidgen.py
deleted file mode 100755
index ed1e415..0000000
--- a/remoting/tools/uuidgen.py
+++ /dev/null
@@ -1,18 +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.
-
-"""
-uuidgen.py -- UUID generation utility.
-"""
-
-import sys
-import uuid
-
-def main():
-  print uuid.uuid4()
-  return 0
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/remoting/webapp/appsv2.patch b/remoting/webapp/appsv2.patch
index f03a317..9deac20 100644
--- a/remoting/webapp/appsv2.patch
+++ b/remoting/webapp/appsv2.patch
@@ -42,8 +42,8 @@
      "clipboardWrite",
 -    "nativeMessaging"
 +    "nativeMessaging",
-+    "fullscreen"
-+    "identity",
++    "fullscreen",
++    "identity"
    ],
 -  "plugins": [
 -    { "path": "remoting_host_plugin.dll", "public": false },
@@ -52,7 +52,7 @@
 -    { "path": "remoting_host_plugin.plugin", "public": false }
 -  ],
 +  "oauth2": {
-+    "client_id": "45833509441-oqgdhgddn085c7cq9djknefjo0tedtua.apps.googleusercontent.com",
++    "client_id": "REMOTING_IDENTITY_API_CLIENT_ID",
 +    "scopes": [
 +      "https://www.googleapis.com/auth/chromoting https://www.googleapis.com/auth/googletalk https://www.googleapis.com/auth/userinfo#email"
 +    ]
diff --git a/remoting/webapp/build-webapp.py b/remoting/webapp/build-webapp.py
index 384aaf1..42e941c 100755
--- a/remoting/webapp/build-webapp.py
+++ b/remoting/webapp/build-webapp.py
@@ -279,6 +279,7 @@
   # For overriding the client ID/secret via env vars, see google_api_keys.py.
   apiClientId = google_api_keys.GetClientID('REMOTING')
   apiClientSecret = google_api_keys.GetClientSecret('REMOTING')
+  apiClientIdV2 = google_api_keys.GetClientID('REMOTING_IDENTITY_API')
 
   findAndReplace(os.path.join(destination, 'plugin_settings.js'),
                  "'API_CLIENT_ID'",
@@ -286,6 +287,9 @@
   findAndReplace(os.path.join(destination, 'plugin_settings.js'),
                  "'API_CLIENT_SECRET'",
                  "'" + apiClientSecret + "'")
+  findAndReplace(os.path.join(destination, 'manifest.json'),
+                 '"REMOTING_IDENTITY_API_CLIENT_ID"',
+                 '"' + apiClientIdV2 + '"')
 
   # Use a consistent extension id for unofficial builds.
   if buildtype != 'Official':
diff --git a/remoting/webapp/client_plugin.js b/remoting/webapp/client_plugin.js
index 247d068..8cd8f1c 100644
--- a/remoting/webapp/client_plugin.js
+++ b/remoting/webapp/client_plugin.js
@@ -58,7 +58,6 @@
  */
 remoting.ClientPlugin.Feature = {
   INJECT_KEY_EVENT: 'injectKeyEvent',
-  NOTIFY_CLIENT_DIMENSIONS: 'notifyClientDimensions',
   NOTIFY_CLIENT_RESOLUTION: 'notifyClientResolution',
   ASYNC_PIN: 'asyncPin',
   PAUSE_VIDEO: 'pauseVideo',
diff --git a/remoting/webapp/client_plugin_async.js b/remoting/webapp/client_plugin_async.js
index ac82c9f..b788f64 100644
--- a/remoting/webapp/client_plugin_async.js
+++ b/remoting/webapp/client_plugin_async.js
@@ -316,7 +316,7 @@
   } else if (message.method == 'extensionMessage') {
     // No messages currently supported.
     console.log('Unexpected message received: ' +
-                message.data.type + ': ' + message.data.data);
+                message.data['type'] + ': ' + message.data['data']);
   }
 };
 
@@ -520,11 +520,6 @@
           data: { width: width * device_scale,
                   height: height * device_scale,
                   x_dpi: dpi, y_dpi: dpi }}));
-  } else if (this.hasFeature(
-                 remoting.ClientPlugin.Feature.NOTIFY_CLIENT_DIMENSIONS)) {
-    this.plugin.postMessage(JSON.stringify(
-        { method: 'notifyClientDimensions',
-          data: { width: width, height: height }}));
   }
 };
 
diff --git a/remoting/webapp/client_screen.js b/remoting/webapp/client_screen.js
index 11f6d74..3368e52 100644
--- a/remoting/webapp/client_screen.js
+++ b/remoting/webapp/client_screen.js
@@ -70,7 +70,7 @@
   if (!remoting.clientSession) {
     return;
   }
-  if (remoting.clientSession.mode == remoting.ClientSession.Mode.IT2ME) {
+  if (remoting.clientSession.getMode() == remoting.ClientSession.Mode.IT2ME) {
     remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
   } else {
     remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
@@ -115,7 +115,8 @@
   switch (newState) {
     case remoting.ClientSession.State.CLOSED:
       console.log('Connection closed by host');
-      if (remoting.clientSession.mode == remoting.ClientSession.Mode.IT2ME) {
+      if (remoting.clientSession.getMode() ==
+          remoting.ClientSession.Mode.IT2ME) {
         remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_IT2ME);
       } else {
         remoting.setMode(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
@@ -155,7 +156,7 @@
   var errorDiv = document.getElementById('connect-error-message');
   l10n.localizeElementFromTag(errorDiv, /** @type {string} */ (errorTag));
   remoting.accessCode = '';
-  var mode = remoting.clientSession ? remoting.clientSession.mode
+  var mode = remoting.clientSession ? remoting.clientSession.getMode()
                                     : remoting.connector.getConnectionMode();
   if (mode == remoting.ClientSession.Mode.IT2ME) {
     remoting.setMode(remoting.AppMode.CLIENT_CONNECT_FAILED_IT2ME);
@@ -183,7 +184,8 @@
  */
 function updateStatistics_() {
   if (!remoting.clientSession ||
-      remoting.clientSession.state != remoting.ClientSession.State.CONNECTED) {
+      remoting.clientSession.getState() !=
+      remoting.ClientSession.State.CONNECTED) {
     return;
   }
   var perfstats = remoting.clientSession.getPerfStats();
@@ -336,7 +338,7 @@
   remoting.clientSession.setOnStateChange(onClientStateChange_);
   setConnectionInterruptedButtonsText_();
   var connectedTo = document.getElementById('connected-to');
-  connectedTo.innerText = clientSession.hostDisplayName;
+  connectedTo.innerText = remoting.connector.getHostDisplayName();
   document.getElementById('access-code-entry').value = '';
   remoting.setMode(remoting.AppMode.IN_SESSION);
   remoting.toolbar.center();
@@ -355,7 +357,7 @@
           sharedSecret: sharedSecret
         }
       };
-      remoting.HostSettings.save(clientSession.hostId, pairingInfo);
+      remoting.HostSettings.save(remoting.connector.getHostId(), pairingInfo);
       remoting.connector.updatePairingInfo(clientId, sharedSecret);
     };
     // Use the platform name as a proxy for the local computer name.
diff --git a/remoting/webapp/client_session.js b/remoting/webapp/client_session.js
index 2fa4b49..6587216 100644
--- a/remoting/webapp/client_session.js
+++ b/remoting/webapp/client_session.js
@@ -23,10 +23,7 @@
 var remoting = remoting || {};
 
 /**
- * @param {string} hostJid The jid of the host to connect to.
  * @param {string} clientJid The jid of the WCS client.
- * @param {string} hostPublicKey The base64 encoded version of the host's
- *     public key.
  * @param {string} accessCode The IT2Me access code. Blank for Me2Me.
  * @param {function(boolean, function(string): void): void} fetchPin
  *     Called by Me2Me connections when a PIN needs to be obtained
@@ -39,44 +36,54 @@
  *     authentication methods the client should attempt to use.
  * @param {string} hostId The host identifier for Me2Me, or empty for IT2Me.
  *     Mixed into authentication hashes for some authentication methods.
+ * @param {string} hostJid The jid of the host to connect to.
+ * @param {string} hostPublicKey The base64 encoded version of the host's
+ *     public key.
  * @param {remoting.ClientSession.Mode} mode The mode of this connection.
- * @param {string} hostDisplayName The name of the host for display purposes.
  * @param {string} clientPairingId For paired Me2Me connections, the
  *     pairing id for this client, as issued by the host.
  * @param {string} clientPairedSecret For paired Me2Me connections, the
  *     paired secret for this client, as issued by the host.
  * @constructor
  */
-remoting.ClientSession = function(hostJid, clientJid, hostPublicKey, accessCode,
-                                  fetchPin, fetchThirdPartyToken,
-                                  authenticationMethods, hostId,
-                                  mode, hostDisplayName,
+remoting.ClientSession = function(clientJid, accessCode, fetchPin,
+                                  fetchThirdPartyToken, authenticationMethods,
+                                  hostId, hostJid, hostPublicKey, mode,
                                   clientPairingId, clientPairedSecret) {
-  this.state = remoting.ClientSession.State.CREATED;
+  /** @private */
+  this.state_ = remoting.ClientSession.State.CREATED;
 
-  this.hostJid = hostJid;
-  this.clientJid = clientJid;
-  this.hostPublicKey = hostPublicKey;
+  /** @private */
+  this.clientJid_ = clientJid;
+
+  /** @private */
+  this.error_ = remoting.Error.NONE;
+
+  /** @private */
+  this.hostJid_ = hostJid;
+  /** @private */
+  this.hostPublicKey_ = hostPublicKey;
   /** @private */
   this.accessCode_ = accessCode;
   /** @private */
   this.fetchPin_ = fetchPin;
   /** @private */
   this.fetchThirdPartyToken_ = fetchThirdPartyToken;
-  this.authenticationMethods = authenticationMethods;
-  /** @type {string} */
-  this.hostId = hostId;
-  /** @type {string} */
-  this.hostDisplayName = hostDisplayName;
-  /** @type {remoting.ClientSession.Mode} */
-  this.mode = mode;
+  /** @private */
+  this.authenticationMethods_ = authenticationMethods;
+  /** @private */
+  this.hostId_ = hostId;
+  /** @private */
+  this.mode_ = mode;
   /** @private */
   this.clientPairingId_ = clientPairingId;
   /** @private */
-  this.clientPairedSecret_ = clientPairedSecret
-  this.sessionId = '';
-  /** @type {remoting.ClientPlugin} */
-  this.plugin = null;
+  this.clientPairedSecret_ = clientPairedSecret;
+  /** @private */
+  this.sessionId_ = '';
+  /** @type {remoting.ClientPlugin}
+    * @private */
+  this.plugin_ = null;
   /** @private */
   this.shrinkToFit_ = true;
   /** @private */
@@ -129,7 +136,7 @@
   /** @type {HTMLElement} @private */
   this.fullScreenButton_ = document.getElementById('toggle-full-screen');
 
-  if (this.mode == remoting.ClientSession.Mode.IT2ME) {
+  if (this.mode_ == remoting.ClientSession.Mode.IT2ME) {
     // Resize-to-client is not supported for IT2Me hosts.
     this.resizeToClientButton_.hidden = true;
   } else {
@@ -166,15 +173,15 @@
   if (!this.shrinkToFit_) {
     // Determine whether or not horizontal or vertical scrollbars are
     // required, taking into account their width.
-    needsVerticalScroll = window.innerHeight < this.plugin.desktopHeight;
-    needsHorizontalScroll = window.innerWidth < this.plugin.desktopWidth;
+    needsVerticalScroll = window.innerHeight < this.plugin_.desktopHeight;
+    needsHorizontalScroll = window.innerWidth < this.plugin_.desktopWidth;
     var kScrollBarWidth = 16;
     if (needsHorizontalScroll && !needsVerticalScroll) {
       needsVerticalScroll =
-          window.innerHeight - kScrollBarWidth < this.plugin.desktopHeight;
+          window.innerHeight - kScrollBarWidth < this.plugin_.desktopHeight;
     } else if (!needsHorizontalScroll && needsVerticalScroll) {
       needsHorizontalScroll =
-          window.innerWidth - kScrollBarWidth < this.plugin.desktopWidth;
+          window.innerWidth - kScrollBarWidth < this.plugin_.desktopWidth;
     }
   }
 
@@ -197,11 +204,9 @@
 // no corresponding plugin state transition.
 /** @enum {number} */
 remoting.ClientSession.State = {
-  CONNECTION_CANCELED: -5,  // Connection closed (gracefully) before connecting.
-  CONNECTION_DROPPED: -4,  // Succeeded, but subsequently closed with an error.
-  CREATED: -3,
-  BAD_PLUGIN_VERSION: -2,
-  UNKNOWN_PLUGIN_ERROR: -1,
+  CONNECTION_CANCELED: -3,  // Connection closed (gracefully) before connecting.
+  CONNECTION_DROPPED: -2,  // Succeeded, but subsequently closed with an error.
+  CREATED: -1,
   UNKNOWN: 0,
   CONNECTING: 1,
   INITIALIZING: 2,
@@ -263,20 +268,6 @@
 remoting.ClientSession.KEY_SHRINK_TO_FIT = 'shrinkToFit';
 
 /**
- * The current state of the session.
- * @type {remoting.ClientSession.State}
- */
-remoting.ClientSession.prototype.state = remoting.ClientSession.State.UNKNOWN;
-
-/**
- * The last connection error. Set when state is set to FAILED.
- * @type {remoting.ClientSession.ConnectionError}
- * @private
- */
-remoting.ClientSession.prototype.error_ =
-    remoting.ClientSession.ConnectionError.NONE;
-
-/**
  * The id of the client plugin
  *
  * @const
@@ -291,7 +282,7 @@
 remoting.ClientSession.Capability = {
   // When enabled this capability causes the client to send its screen
   // resolution to the host once connection has been established. See
-  // this.plugin.notifyClientResolution().
+  // this.plugin_.notifyClientResolution().
   SEND_INITIAL_RESOLUTION: 'sendInitialResolution',
   RATE_LIMIT_RESIZE_REQUESTS: 'rateLimitResizeRequests'
 };
@@ -349,12 +340,12 @@
  * Callback function called when the plugin element loses focus.
  */
 remoting.ClientSession.prototype.pluginLostFocus_ = function() {
-  if (this.plugin) {
+  if (this.plugin_) {
     // Release all keys to prevent them becoming 'stuck down' on the host.
-    this.plugin.releaseAllKeys();
-    if (this.plugin.element()) {
+    this.plugin_.releaseAllKeys();
+    if (this.plugin_.element()) {
       // Focus should stay on the element, not (for example) the toolbar.
-      this.plugin.element().focus();
+      this.plugin_.element().focus();
     }
   }
 };
@@ -366,8 +357,8 @@
  */
 remoting.ClientSession.prototype.createPluginAndConnect =
     function(container) {
-  this.plugin = this.createClientPlugin_(container, this.PLUGIN_ID);
-  remoting.HostSettings.load(this.hostId,
+  this.plugin_ = this.createClientPlugin_(container, this.PLUGIN_ID);
+  remoting.HostSettings.load(this.hostId_,
                              this.onHostSettingsLoaded_.bind(this));
 };
 
@@ -397,7 +388,7 @@
   }
 
   /** @param {boolean} result */
-  this.plugin.initialize(this.onPluginInitialized_.bind(this));
+  this.plugin_.initialize(this.onPluginInitialized_.bind(this));
 };
 
 /**
@@ -405,61 +396,68 @@
  * @private
  */
 remoting.ClientSession.prototype.setFocusHandlers_ = function() {
-  this.plugin.element().addEventListener(
+  this.plugin_.element().addEventListener(
       'focus', this.callPluginGotFocus_, false);
-  this.plugin.element().addEventListener(
+  this.plugin_.element().addEventListener(
       'blur', this.callPluginLostFocus_, false);
-  this.plugin.element().focus();
+  this.plugin_.element().focus();
 };
 
 /**
+ * @param {remoting.Error} error
+ */
+remoting.ClientSession.prototype.resetWithError_ = function(error) {
+  this.plugin_.cleanup();
+  delete this.plugin_;
+  this.error_ = error;
+  this.setState_(remoting.ClientSession.State.FAILED);
+}
+
+/**
  * @param {boolean} initialized
  */
 remoting.ClientSession.prototype.onPluginInitialized_ = function(initialized) {
   if (!initialized) {
     console.error('ERROR: remoting plugin not loaded');
-    this.plugin.cleanup();
-    delete this.plugin;
-    this.setState_(remoting.ClientSession.State.UNKNOWN_PLUGIN_ERROR);
+    this.resetWithError_(remoting.Error.MISSING_PLUGIN);
     return;
   }
 
-  if (!this.plugin.isSupportedVersion()) {
-    this.plugin.cleanup();
-    delete this.plugin;
-    this.setState_(remoting.ClientSession.State.BAD_PLUGIN_VERSION);
+  if (!this.plugin_.isSupportedVersion()) {
+    this.resetWithError_(remoting.Error.BAD_PLUGIN_VERSION);
     return;
   }
 
   // Show the Send Keys menu only if the plugin has the injectKeyEvent feature,
   // and the Ctrl-Alt-Del button only in Me2Me mode.
-  if (!this.plugin.hasFeature(remoting.ClientPlugin.Feature.INJECT_KEY_EVENT)) {
+  if (!this.plugin_.hasFeature(
+          remoting.ClientPlugin.Feature.INJECT_KEY_EVENT)) {
     var sendKeysElement = document.getElementById('send-keys-menu');
     sendKeysElement.hidden = true;
-  } else if (this.mode != remoting.ClientSession.Mode.ME2ME) {
+  } else if (this.mode_ != remoting.ClientSession.Mode.ME2ME) {
     var sendCadElement = document.getElementById('send-ctrl-alt-del');
     sendCadElement.hidden = true;
   }
 
   // Apply customized key remappings if the plugin supports remapKeys.
-  if (this.plugin.hasFeature(remoting.ClientPlugin.Feature.REMAP_KEY)) {
+  if (this.plugin_.hasFeature(remoting.ClientPlugin.Feature.REMAP_KEY)) {
     this.applyRemapKeys_(true);
   }
 
   /** @param {string} msg The IQ stanza to send. */
-  this.plugin.onOutgoingIqHandler = this.sendIq_.bind(this);
+  this.plugin_.onOutgoingIqHandler = this.sendIq_.bind(this);
   /** @param {string} msg The message to log. */
-  this.plugin.onDebugMessageHandler = function(msg) {
+  this.plugin_.onDebugMessageHandler = function(msg) {
     console.log('plugin: ' + msg);
   };
 
-  this.plugin.onConnectionStatusUpdateHandler =
+  this.plugin_.onConnectionStatusUpdateHandler =
       this.onConnectionStatusUpdate_.bind(this);
-  this.plugin.onConnectionReadyHandler =
+  this.plugin_.onConnectionReadyHandler =
       this.onConnectionReady_.bind(this);
-  this.plugin.onDesktopSizeUpdateHandler =
+  this.plugin_.onDesktopSizeUpdateHandler =
       this.onDesktopSizeChanged_.bind(this);
-  this.plugin.onSetCapabilitiesHandler =
+  this.plugin_.onSetCapabilitiesHandler =
       this.onSetCapabilities_.bind(this);
   this.connectPluginToWcs_();
 };
@@ -472,13 +470,13 @@
  * @return {void} Nothing.
  */
 remoting.ClientSession.prototype.removePlugin = function() {
-  if (this.plugin) {
-    this.plugin.element().removeEventListener(
+  if (this.plugin_) {
+    this.plugin_.element().removeEventListener(
         'focus', this.callPluginGotFocus_, false);
-    this.plugin.element().removeEventListener(
+    this.plugin_.element().removeEventListener(
         'blur', this.callPluginLostFocus_, false);
-    this.plugin.cleanup();
-    this.plugin = null;
+    this.plugin_.cleanup();
+    this.plugin_ = null;
   }
 
   // Delete event handlers that aren't relevent when not connected.
@@ -505,21 +503,19 @@
     // The plugin won't send a state change notification, so we explicitly log
     // the fact that the connection has closed.
     this.logToServer.logClientSessionStateChange(
-        remoting.ClientSession.State.CLOSED,
-        remoting.ClientSession.ConnectionError.NONE, this.mode);
+        remoting.ClientSession.State.CLOSED, remoting.Error.NONE, this.mode_);
   }
   remoting.wcsSandbox.setOnIq(null);
   this.sendIq_(
       '<cli:iq ' +
-          'to="' + this.hostJid + '" ' +
+          'to="' + this.hostJid_ + '" ' +
           'type="set" ' +
           'id="session-terminate" ' +
           'xmlns:cli="jabber:client">' +
         '<jingle ' +
             'xmlns="urn:xmpp:jingle:1" ' +
             'action="session-terminate" ' +
-            'initiator="' + this.clientJid + '" ' +
-            'sid="' + this.sessionId + '">' +
+            'sid="' + this.sessionId_ + '">' +
           '<reason><success/></reason>' +
         '</jingle>' +
       '</cli:iq>');
@@ -527,24 +523,24 @@
 };
 
 /**
- * @return {?remoting.Error} The current error code, or null if the connection
- *     is not in an error state.
+ * @return {remoting.ClientSession.Mode} The current state.
+ */
+remoting.ClientSession.prototype.getMode = function() {
+  return this.mode_;
+};
+
+/**
+ * @return {remoting.ClientSession.State} The current state.
+ */
+remoting.ClientSession.prototype.getState = function() {
+  return this.state_;
+};
+
+/**
+ * @return {remoting.Error} The current error code.
  */
 remoting.ClientSession.prototype.getError = function() {
-  switch (this.error_) {
-    case remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE:
-      return remoting.Error.HOST_IS_OFFLINE;
-    case remoting.ClientSession.ConnectionError.SESSION_REJECTED:
-      return remoting.Error.INVALID_ACCESS_CODE;
-    case remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL:
-      return remoting.Error.INCOMPATIBLE_PROTOCOL;
-    case remoting.ClientSession.ConnectionError.NETWORK_FAILURE:
-      return remoting.Error.P2P_FAILURE;
-    case remoting.ClientSession.ConnectionError.HOST_OVERLOAD:
-      return remoting.Error.HOST_OVERLOAD;
-    default:
-      return null;
-  }
+  return this.error_;
 };
 
 /**
@@ -557,10 +553,10 @@
  */
 remoting.ClientSession.prototype.sendKeyCombination_ = function(keys) {
   for (var i = 0; i < keys.length; i++) {
-    this.plugin.injectKeyEvent(keys[i], true);
+    this.plugin_.injectKeyEvent(keys[i], true);
   }
   for (var i = 0; i < keys.length; i++) {
-    this.plugin.injectKeyEvent(keys[i], false);
+    this.plugin_.injectKeyEvent(keys[i], false);
   }
 }
 
@@ -596,7 +592,7 @@
   // Save the new remapping setting.
   var options = {};
   options[remoting.ClientSession.KEY_REMAP_KEYS] = this.remapKeys_;
-  remoting.HostSettings.save(this.hostId, options);
+  remoting.HostSettings.save(this.hostId_, options);
 }
 
 /**
@@ -628,10 +624,10 @@
     if (apply) {
       console.log('remapKey 0x' + fromKey.toString(16) +
                   '>0x' + toKey.toString(16));
-      this.plugin.remapKey(fromKey, toKey);
+      this.plugin_.remapKey(fromKey, toKey);
     } else {
       console.log('cancel remapKey 0x' + fromKey.toString(16));
-      this.plugin.remapKey(fromKey, fromKey);
+      this.plugin_.remapKey(fromKey, fromKey);
     }
   }
 }
@@ -673,7 +669,7 @@
 remoting.ClientSession.prototype.setScreenMode_ =
     function(shrinkToFit, resizeToClient) {
   if (resizeToClient && !this.resizeToClient_) {
-    this.plugin.notifyClientResolution(window.innerWidth,
+    this.plugin_.notifyClientResolution(window.innerWidth,
                                        window.innerHeight,
                                        window.devicePixelRatio);
   }
@@ -685,11 +681,11 @@
   this.resizeToClient_ = resizeToClient;
   this.updateScrollbarVisibility();
 
-  if (this.hostId != '') {
+  if (this.hostId_ != '') {
     var options = {};
     options[remoting.ClientSession.KEY_SHRINK_TO_FIT] = this.shrinkToFit_;
     options[remoting.ClientSession.KEY_RESIZE_TO_CLIENT] = this.resizeToClient_;
-    remoting.HostSettings.save(this.hostId, options);
+    remoting.HostSettings.save(this.hostId_, options);
   }
 
   this.updateDimensions();
@@ -730,7 +726,7 @@
   if (jingleNode) {
     var action = jingleNode.getAttribute('action');
     if (jingleNode.nodeName == 'jingle' && action == 'session-initiate') {
-      this.sessionId = jingleNode.getAttribute('sid');
+      this.sessionId_ = jingleNode.getAttribute('sid');
     }
   }
 
@@ -758,10 +754,8 @@
  * @return {void} Nothing.
  */
 remoting.ClientSession.prototype.connectPluginToWcs_ = function() {
-  remoting.formatIq.setJids(this.clientJid, this.hostJid);
-  /** @type {remoting.ClientPlugin} */
-  var plugin = this.plugin;
-  var forwardIq = plugin.onIncomingIq.bind(plugin);
+  remoting.formatIq.setJids(this.clientJid_, this.hostJid_);
+  var forwardIq = this.plugin_.onIncomingIq.bind(this.plugin_);
   /** @param {string} stanza The IQ stanza received. */
   var onIncomingIq = function(stanza) {
     // HACK: Remove 'x' prefix added to the id in sendIq_().
@@ -786,27 +780,28 @@
 
   /** @type remoting.ClientSession */
   var that = this;
-  if (plugin.hasFeature(remoting.ClientPlugin.Feature.THIRD_PARTY_AUTH)) {
+  if (this.plugin_.hasFeature(remoting.ClientPlugin.Feature.THIRD_PARTY_AUTH)) {
     /** @type{function(string, string, string): void} */
     var fetchThirdPartyToken = function(tokenUrl, hostPublicKey, scope) {
       that.fetchThirdPartyToken_(
           tokenUrl, hostPublicKey, scope,
-          plugin.onThirdPartyTokenFetched.bind(plugin));
+          that.plugin_.onThirdPartyTokenFetched.bind(that.plugin_));
     };
-    plugin.fetchThirdPartyTokenHandler = fetchThirdPartyToken;
+    that.plugin_.fetchThirdPartyTokenHandler = fetchThirdPartyToken;
   }
   if (this.accessCode_) {
     // Shared secret was already supplied before connecting (It2Me case).
     this.connectToHost_(this.accessCode_);
-  } else if (plugin.hasFeature(
+  } else if (this.plugin_.hasFeature(
       remoting.ClientPlugin.Feature.ASYNC_PIN)) {
     // Plugin supports asynchronously asking for the PIN.
-    plugin.useAsyncPinDialog();
+    this.plugin_.useAsyncPinDialog();
     /** @param {boolean} pairingSupported */
     var fetchPin = function(pairingSupported) {
-      that.fetchPin_(pairingSupported, plugin.onPinFetched.bind(plugin));
+      that.fetchPin_(pairingSupported,
+                     that.plugin_.onPinFetched.bind(that.plugin_));
     };
-    plugin.fetchPinHandler = fetchPin;
+    this.plugin_.fetchPinHandler = fetchPin;
     this.connectToHost_('');
   } else {
     // Clients that don't support asking for a PIN asynchronously also don't
@@ -823,9 +818,9 @@
  * @private
  */
 remoting.ClientSession.prototype.connectToHost_ = function(sharedSecret) {
-  this.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid,
-                      sharedSecret, this.authenticationMethods, this.hostId,
-                      this.clientPairingId_, this.clientPairedSecret_);
+  this.plugin_.connect(this.hostJid_, this.hostPublicKey_, this.clientJid_,
+                       sharedSecret, this.authenticationMethods_, this.hostId_,
+                       this.clientPairingId_, this.clientPairedSecret_);
 };
 
 /**
@@ -842,12 +837,30 @@
     this.setFocusHandlers_();
     this.onDesktopSizeChanged_();
     if (this.resizeToClient_) {
-      this.plugin.notifyClientResolution(window.innerWidth,
+      this.plugin_.notifyClientResolution(window.innerWidth,
                                          window.innerHeight,
                                          window.devicePixelRatio);
     }
   } else if (status == remoting.ClientSession.State.FAILED) {
-    this.error_ = /** @type {remoting.ClientSession.ConnectionError} */ (error);
+    switch (error) {
+      case remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE:
+        this.error_ = remoting.Error.HOST_IS_OFFLINE;
+        break;
+      case remoting.ClientSession.ConnectionError.SESSION_REJECTED:
+        this.error_ = remoting.Error.INVALID_ACCESS_CODE;
+        break;
+      case remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL:
+        this.error_ = remoting.Error.INCOMPATIBLE_PROTOCOL;
+        break;
+      case remoting.ClientSession.ConnectionError.NETWORK_FAILURE:
+        this.error_ = remoting.Error.P2P_FAILURE;
+        break;
+      case remoting.ClientSession.ConnectionError.HOST_OVERLOAD:
+        this.error_ = remoting.Error.HOST_OVERLOAD;
+        break;
+      default:
+        this.error_ = remoting.Error.UNEXPECTED;
+    }
   }
   this.setState_(/** @type {remoting.ClientSession.State} */ (status));
 };
@@ -861,9 +874,9 @@
  */
 remoting.ClientSession.prototype.onConnectionReady_ = function(ready) {
   if (!ready) {
-    this.plugin.element().classList.add("session-client-inactive");
+    this.plugin_.element().classList.add("session-client-inactive");
   } else {
-    this.plugin.element().classList.remove("session-client-inactive");
+    this.plugin_.element().classList.remove("session-client-inactive");
   }
 };
 
@@ -884,7 +897,7 @@
   this.capabilities_ = capabilities;
   if (this.hasCapability_(
       remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION)) {
-    this.plugin.notifyClientResolution(window.innerWidth,
+    this.plugin_.notifyClientResolution(window.innerWidth,
                                        window.innerHeight,
                                        window.devicePixelRatio);
   }
@@ -896,14 +909,14 @@
  * @return {void} Nothing.
  */
 remoting.ClientSession.prototype.setState_ = function(newState) {
-  var oldState = this.state;
-  this.state = newState;
-  var state = this.state;
+  var oldState = this.state_;
+  this.state_ = newState;
+  var state = this.state_;
   if (oldState == remoting.ClientSession.State.CONNECTING) {
-    if (this.state == remoting.ClientSession.State.CLOSED) {
+    if (this.state_ == remoting.ClientSession.State.CLOSED) {
       state = remoting.ClientSession.State.CONNECTION_CANCELED;
-    } else if (this.state == remoting.ClientSession.State.FAILED &&
-        this.error_ == remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE &&
+    } else if (this.state_ == remoting.ClientSession.State.FAILED &&
+        this.error_ == remoting.Error.HOST_IS_OFFLINE &&
         !this.logHostOfflineErrors_) {
       // The application requested host-offline errors to be suppressed, for
       // example, because this connection attempt is using a cached host JID.
@@ -911,10 +924,10 @@
       state = remoting.ClientSession.State.CONNECTION_CANCELED;
     }
   } else if (oldState == remoting.ClientSession.State.CONNECTED &&
-             this.state == remoting.ClientSession.State.FAILED) {
+             this.state_ == remoting.ClientSession.State.FAILED) {
     state = remoting.ClientSession.State.CONNECTION_DROPPED;
   }
-  this.logToServer.logClientSessionStateChange(state, this.error_, this.mode);
+  this.logToServer.logClientSessionStateChange(state, this.error_, this.mode_);
   if (this.onStateChange_) {
     this.onStateChange_(oldState, newState);
   }
@@ -942,10 +955,10 @@
       kResizeRateLimitMs = 250;
     }
     this.notifyClientResolutionTimer_ = window.setTimeout(
-        this.plugin.notifyClientResolution.bind(this.plugin,
-                                                window.innerWidth,
-                                                window.innerHeight,
-                                                window.devicePixelRatio),
+        this.plugin_.notifyClientResolution.bind(this.plugin_,
+                                                 window.innerWidth,
+                                                 window.innerHeight,
+                                                 window.devicePixelRatio),
         kResizeRateLimitMs);
   }
 
@@ -963,8 +976,8 @@
  * @return {void} Nothing.
  */
 remoting.ClientSession.prototype.pauseVideo = function(pause) {
-  if (this.plugin) {
-    this.plugin.pauseVideo(pause)
+  if (this.plugin_) {
+    this.plugin_.pauseVideo(pause)
   }
 }
 
@@ -975,8 +988,8 @@
  * @return {void} Nothing.
  */
 remoting.ClientSession.prototype.pauseAudio = function(pause) {
-  if (this.plugin) {
-    this.plugin.pauseAudio(pause)
+  if (this.plugin_) {
+    this.plugin_.pauseAudio(pause)
   }
 }
 
@@ -989,10 +1002,10 @@
  */
 remoting.ClientSession.prototype.onDesktopSizeChanged_ = function() {
   console.log('desktop size changed: ' +
-              this.plugin.desktopWidth + 'x' +
-              this.plugin.desktopHeight +' @ ' +
-              this.plugin.desktopXDpi + 'x' +
-              this.plugin.desktopYDpi + ' DPI');
+              this.plugin_.desktopWidth + 'x' +
+              this.plugin_.desktopHeight +' @ ' +
+              this.plugin_.desktopXDpi + 'x' +
+              this.plugin_.desktopYDpi + ' DPI');
   this.updateDimensions();
   this.updateScrollbarVisibility();
 };
@@ -1004,15 +1017,15 @@
  * @return {void} Nothing.
  */
 remoting.ClientSession.prototype.updateDimensions = function() {
-  if (this.plugin.desktopWidth == 0 ||
-      this.plugin.desktopHeight == 0) {
+  if (this.plugin_.desktopWidth == 0 ||
+      this.plugin_.desktopHeight == 0) {
     return;
   }
 
   var windowWidth = window.innerWidth;
   var windowHeight = window.innerHeight;
-  var desktopWidth = this.plugin.desktopWidth;
-  var desktopHeight = this.plugin.desktopHeight;
+  var desktopWidth = this.plugin_.desktopWidth;
+  var desktopHeight = this.plugin_.desktopHeight;
 
   // When configured to display a host at its original size, we aim to display
   // it as close to its physical size as possible, without losing data:
@@ -1026,8 +1039,8 @@
   // an initial scale factor based on the client devicePixelRatio and host DPI.
 
   // Determine the effective device pixel ratio of the host, based on DPI.
-  var hostPixelRatioX = Math.ceil(this.plugin.desktopXDpi / 96);
-  var hostPixelRatioY = Math.ceil(this.plugin.desktopYDpi / 96);
+  var hostPixelRatioX = Math.ceil(this.plugin_.desktopXDpi / 96);
+  var hostPixelRatioY = Math.ceil(this.plugin_.desktopYDpi / 96);
   var hostPixelRatio = Math.min(hostPixelRatioX, hostPixelRatioY);
 
   // Down-scale by the smaller of the client and host ratios.
@@ -1064,14 +1077,14 @@
 
   // Resize the plugin if necessary.
   // TODO(wez): Handle high-DPI to high-DPI properly (crbug.com/135089).
-  this.plugin.element().width = pluginWidth;
-  this.plugin.element().height = pluginHeight;
+  this.plugin_.element().width = pluginWidth;
+  this.plugin_.element().height = pluginHeight;
 
   // Position the container.
   // Note that clientWidth/Height take into account scrollbars.
   var clientWidth = document.documentElement.clientWidth;
   var clientHeight = document.documentElement.clientHeight;
-  var parentNode = this.plugin.element().parentNode;
+  var parentNode = this.plugin_.element().parentNode;
 
   if (pluginWidth < clientWidth) {
     parentNode.style.left = (clientWidth - pluginWidth) / 2 + 'px';
@@ -1097,7 +1110,7 @@
  * @return {remoting.ClientSession.PerfStats} The connection statistics.
  */
 remoting.ClientSession.prototype.getPerfStats = function() {
-  return this.plugin.getPerfStats();
+  return this.plugin_.getPerfStats();
 };
 
 /**
@@ -1106,7 +1119,7 @@
  * @param {remoting.ClientSession.PerfStats} stats
  */
 remoting.ClientSession.prototype.logStatistics = function(stats) {
-  this.logToServer.logStatistics(stats, this.mode);
+  this.logToServer.logStatistics(stats, this.mode_);
 };
 
 /**
@@ -1129,8 +1142,8 @@
  *     client id and shared secret when they are available.
  */
 remoting.ClientSession.prototype.requestPairing = function(clientName, onDone) {
-  if (this.plugin) {
-    this.plugin.requestPairing(clientName, onDone);
+  if (this.plugin_) {
+    this.plugin_.requestPairing(clientName, onDone);
   }
 };
 
@@ -1179,7 +1192,7 @@
  * @private
  */
 remoting.ClientSession.prototype.scroll_ = function(dx, dy) {
-  var plugin = this.plugin.element();
+  var plugin = this.plugin_.element();
   var style = plugin.style;
 
   /**
@@ -1220,14 +1233,14 @@
   if (enable) {
     /** @type {null|function(Event):void} */
     this.onMouseMoveRef_ = this.onMouseMove_.bind(this);
-    this.plugin.element().addEventListener('mousemove', this.onMouseMoveRef_,
-                                           false);
+    this.plugin_.element().addEventListener(
+        'mousemove', this.onMouseMoveRef_, false);
   } else {
-    this.plugin.element().removeEventListener('mousemove', this.onMouseMoveRef_,
-                                              false);
+    this.plugin_.element().removeEventListener(
+        'mousemove', this.onMouseMoveRef_, false);
     this.onMouseMoveRef_ = null;
-    this.plugin.element().style.marginLeft = 0;
-    this.plugin.element().style.marginTop = 0;
+    this.plugin_.element().style.marginLeft = 0;
+    this.plugin_.element().style.marginTop = 0;
   }
 };
 
@@ -1288,3 +1301,16 @@
     repeatScroll(new Date().getTime());
   }
 };
+
+/**
+ * Sends a clipboard item to the host.
+ *
+ * @param {string} mimeType The MIME type of the clipboard item.
+ * @param {string} item The clipboard item.
+ */
+remoting.ClientSession.prototype.sendClipboardItem = function(mimeType, item) {
+  if (!this.plugin_)
+    return;
+  this.plugin_.sendClipboardItem(mimeType, item)
+};
+
diff --git a/remoting/webapp/clipboard.js b/remoting/webapp/clipboard.js
index 6a29dcd..98abce1 100644
--- a/remoting/webapp/clipboard.js
+++ b/remoting/webapp/clipboard.js
@@ -78,10 +78,9 @@
     console.log('Got invalid clipboardData.');
     return;
   }
-  if (!remoting.clientSession || !remoting.clientSession.plugin) {
+  if (!remoting.clientSession) {
     return;
   }
-  var plugin = remoting.clientSession.plugin;
   for (var i = 0; i < clipboardData.types.length; i++) {
     var type = clipboardData.types[i];
     var item = clipboardData.getData(type);
@@ -100,7 +99,8 @@
         if (!this.blockOneClipboardSend_) {
           // The plugin's JSON reader emits UTF-8.
           console.log('Sending clipboard to host.');
-          plugin.sendClipboardItem(this.ItemTypes.TEXT_UTF8_TYPE, item);
+          remoting.clientSession.sendClipboardItem(
+              this.ItemTypes.TEXT_UTF8_TYPE, item);
         }
         this.previousContent = item;
       }
diff --git a/remoting/webapp/error.js b/remoting/webapp/error.js
index 756e3e6..1b81a33 100644
--- a/remoting/webapp/error.js
+++ b/remoting/webapp/error.js
@@ -11,6 +11,8 @@
  * @enum {string} All error messages from messages.json
  */
 remoting.Error = {
+  NONE: '',
+
   // Used to signify that an operation was cancelled by the user. This should
   // not normally cause the error text to be shown to the user, so the
   // i18n-content prefix is not needed in this case.
diff --git a/remoting/webapp/host.js b/remoting/webapp/host.js
index 24634b6..5d24b7f 100644
--- a/remoting/webapp/host.js
+++ b/remoting/webapp/host.js
@@ -32,6 +32,8 @@
   this.hostVersion = '';
   /** @type {Array.<string>} */
   this.tokenUrlPatterns = [];
+  /** @type {string} */
+  this.updatedTime = '';
 };
 
 /**
diff --git a/remoting/webapp/host_controller.js b/remoting/webapp/host_controller.js
index 4323ff2..af05eab 100644
--- a/remoting/webapp/host_controller.js
+++ b/remoting/webapp/host_controller.js
@@ -16,7 +16,7 @@
     var container = document.getElementById('daemon-plugin-container');
     container.appendChild(plugin);
     return plugin;
-  }
+  };
 
   /** @type {remoting.HostDispatcher} @private */
   this.hostDispatcher_ = new remoting.HostDispatcher(createNpapiPlugin);
@@ -33,7 +33,7 @@
   this.hostDispatcher_.getDaemonVersion(printVersion, function() {
     console.log('Host version not available.');
   });
-}
+};
 
 // Note that the values in the enums below are copied from
 // daemon_controller.h and must be kept in sync.
@@ -63,7 +63,8 @@
  * @enum {string}
  */
 remoting.HostController.Feature = {
-  PAIRING_REGISTRY: 'pairingRegistry'
+  PAIRING_REGISTRY: 'pairingRegistry',
+  OAUTH_CLIENT: 'oauthClient'
 };
 
 /**
@@ -145,19 +146,24 @@
    * @param {string} hostName
    * @param {string} publicKey
    * @param {string} privateKey
-   * @param {XMLHttpRequest} xhr
+   * @param {string} xmppLogin
+   * @param {string} refreshToken
    * @param {string} hostSecretHash
    */
-  function startHostWithHash(hostName, publicKey, privateKey, xhr,
-                             hostSecretHash) {
+  function startHostWithHash(hostName, publicKey, privateKey,
+                             xmppLogin, refreshToken, hostSecretHash) {
     var hostConfig = {
-        xmpp_login: remoting.identity.getCachedEmail(),
-        oauth_refresh_token: remoting.oauth2.exportRefreshToken(),
-        host_id: newHostId,
-        host_name: hostName,
-        host_secret_hash: hostSecretHash,
-        private_key: privateKey
+      xmpp_login: xmppLogin,
+      oauth_refresh_token: refreshToken,
+      host_id: newHostId,
+      host_name: hostName,
+      host_secret_hash: hostSecretHash,
+      private_key: privateKey
     };
+    var hostOwner = remoting.identity.getCachedEmail();
+    if (hostOwner != xmppLogin) {
+      hostConfig['host_owner'] = hostOwner;
+    }
     that.hostDispatcher_.startDaemon(hostConfig, consent,
                                      onStarted.bind(null, hostName, publicKey),
                                      onStartError);
@@ -167,29 +173,61 @@
    * @param {string} hostName
    * @param {string} publicKey
    * @param {string} privateKey
+   * @param {string} email
+   * @param {string} refreshToken
+   */
+  function onServiceAccountCredentials(
+      hostName, publicKey, privateKey, email, refreshToken) {
+    that.hostDispatcher_.getPinHash(
+        newHostId, hostPin,
+        startHostWithHash.bind(
+            null, hostName, publicKey, privateKey, email, refreshToken),
+        onError);
+  }
+
+  /**
+   * @param {string} hostName
+   * @param {string} publicKey
+   * @param {string} privateKey
    * @param {XMLHttpRequest} xhr
    */
-  function onRegistered(hostName, publicKey, privateKey, xhr) {
+  function onRegistered(
+      hostName, publicKey, privateKey, xhr) {
     var success = (xhr.status == 200);
 
     if (success) {
-      that.hostDispatcher_.getPinHash(newHostId, hostPin,
-          startHostWithHash.bind(null, hostName, publicKey, privateKey, xhr),
+      var result = jsonParseSafe(xhr.responseText);
+      if ('data' in result && 'authorizationCode' in result['data']) {
+        that.hostDispatcher_.getCredentialsFromAuthCode(
+            result['data']['authorizationCode'],
+            onServiceAccountCredentials.bind(
+                null, hostName, publicKey, privateKey),
+            onError);
+      } else {
+        // No authorization code returned, use regular user credential flow.
+        that.hostDispatcher_.getPinHash(
+            newHostId, hostPin, startHostWithHash.bind(
+                null, hostName, publicKey, privateKey,
+                remoting.identity.getCachedEmail(),
+                remoting.oauth2.exportRefreshToken()),
           onError);
+      }
     } else {
       console.log('Failed to register the host. Status: ' + xhr.status +
                   ' response: ' + xhr.responseText);
       onError(remoting.Error.REGISTRATION_FAILED);
     }
-  };
+  }
 
   /**
    * @param {string} hostName
    * @param {string} privateKey
    * @param {string} publicKey
+   * @param {string} hostClientId
    * @param {string} oauthToken
    */
-  function doRegisterHost(hostName, privateKey, publicKey, oauthToken) {
+  function doRegisterHost(
+      hostName, privateKey, publicKey, hostClientId, oauthToken) {
     var headers = {
       'Authorization': 'OAuth ' + oauthToken,
       'Content-type' : 'application/json; charset=UTF-8'
@@ -200,12 +238,52 @@
        hostName: hostName,
        publicKey: publicKey
     } };
+
+    var registerHostUrl =
+        remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts';
+
+    if (hostClientId) {
+      registerHostUrl += '?' + remoting.xhr.urlencodeParamHash(
+          { hostClientId: hostClientId });
+    }
+
     remoting.xhr.post(
-        remoting.settings.DIRECTORY_API_BASE_URL + '/@me/hosts/',
+        registerHostUrl,
         onRegistered.bind(null, hostName, publicKey, privateKey),
         JSON.stringify(newHostDetails),
         headers);
-  };
+  }
+
+  /**
+   * @param {string} hostName
+   * @param {string} privateKey
+   * @param {string} publicKey
+   * @param {string} hostClientId
+   */
+  function onHostClientId(
+      hostName, privateKey, publicKey, hostClientId) {
+    remoting.identity.callWithToken(
+        doRegisterHost.bind(
+            null, hostName, privateKey, publicKey, hostClientId), onError);
+  }
+
+  /**
+   * @param {string} hostName
+   * @param {string} privateKey
+   * @param {string} publicKey
+   * @param {boolean} hasFeature
+   */
+  function onHasFeatureOAuthClient(
+      hostName, privateKey, publicKey, hasFeature) {
+    if (hasFeature) {
+      that.hostDispatcher_.getHostClientId(
+          onHostClientId.bind(null, hostName, privateKey, publicKey), onError);
+    } else {
+      remoting.identity.callWithToken(
+          doRegisterHost.bind(
+              null, hostName, privateKey, publicKey, null), onError);
+    }
+  }
 
   /**
    * @param {string} hostName
@@ -213,10 +291,10 @@
    * @param {string} publicKey
    */
   function onKeyGenerated(hostName, privateKey, publicKey) {
-    remoting.identity.callWithToken(
-        doRegisterHost.bind(null, hostName, privateKey, publicKey),
-        onError);
-  };
+    that.hasFeature(
+        remoting.HostController.Feature.OAUTH_CLIENT,
+        onHasFeatureOAuthClient.bind(null, hostName, privateKey, publicKey));
+  }
 
   /**
    * @param {string} hostName
@@ -247,7 +325,7 @@
       remoting.HostList.unregisterHostById(hostId);
     }
     onDone();
-  };
+  }
 
   /** @param {remoting.HostController.AsyncResult} result */
   function onStopped(result) {
diff --git a/remoting/webapp/host_dispatcher.js b/remoting/webapp/host_dispatcher.js
index 00296ac..ee33e41 100644
--- a/remoting/webapp/host_dispatcher.js
+++ b/remoting/webapp/host_dispatcher.js
@@ -479,3 +479,52 @@
       break;
   }
 };
+
+/**
+ * @param {function(string):void} onDone
+ * @param {function(remoting.Error):void} onError
+ * @return {void}
+ */
+remoting.HostDispatcher.prototype.getHostClientId =
+    function(onDone, onError) {
+  switch (this.state_) {
+    case remoting.HostDispatcher.State.UNKNOWN:
+      this.pendingRequests_.push(
+          this.getHostClientId.bind(this, onDone, onError));
+      break;
+    case remoting.HostDispatcher.State.NATIVE_MESSAGING:
+      this.nativeMessagingHost_.getHostClientId(onDone, onError);
+      break;
+    case remoting.HostDispatcher.State.NPAPI:
+      // The NPAPI plugin is packaged with the webapp, not the host, so it
+      // doesn't have access to the API keys baked into the installed host.
+      onError(remoting.Error.UNEXPECTED);
+      break;
+  }
+};
+
+/**
+ * @param {string} authorizationCode
+ * @param {function(string, string):void} onDone
+ * @param {function(remoting.Error):void} onError
+ * @return {void}
+ */
+remoting.HostDispatcher.prototype.getCredentialsFromAuthCode =
+    function(authorizationCode, onDone, onError) {
+  switch (this.state_) {
+    case remoting.HostDispatcher.State.UNKNOWN:
+      this.pendingRequests_.push(
+          this.getCredentialsFromAuthCode.bind(
+              this, authorizationCode, onDone, onError));
+      break;
+    case remoting.HostDispatcher.State.NATIVE_MESSAGING:
+      this.nativeMessagingHost_.getCredentialsFromAuthCode(
+          authorizationCode, onDone, onError);
+      break;
+    case remoting.HostDispatcher.State.NPAPI:
+      // The NPAPI plugin is packaged with the webapp, not the host, so it
+      // doesn't have access to the API keys baked into the installed host.
+      onError(remoting.Error.UNEXPECTED);
+      break;
+  }
+};
diff --git a/remoting/webapp/host_native_messaging.js b/remoting/webapp/host_native_messaging.js
index 9582926..8c76c42 100644
--- a/remoting/webapp/host_native_messaging.js
+++ b/remoting/webapp/host_native_messaging.js
@@ -344,6 +344,29 @@
       }
       break;
 
+    case 'getHostClientIdResponse':
+      /** @type {string} */
+      var clientId = message['clientId'];
+      if (checkType_('clientId', clientId, 'string')) {
+        onDone(clientId);
+      } else {
+        onError(remoting.Error.UNEXPECTED);
+      }
+      break;
+
+    case 'getCredentialsFromAuthCodeResponse':
+      /** @type {string} */
+      var userEmail = message['userEmail'];
+      /** @type {string} */
+      var refreshToken = message['refreshToken'];
+      if (checkType_('userEmail', userEmail, 'string') && userEmail &&
+          checkType_('refreshToken', refreshToken, 'string') && refreshToken) {
+        onDone(userEmail, refreshToken);
+      } else {
+        onError(remoting.Error.UNEXPECTED);
+      }
+      break;
+
     default:
       console.error('Unexpected native message: ', message);
       onError(remoting.Error.UNEXPECTED);
@@ -560,3 +583,32 @@
     clientId: client
   }, onDone, onError);
 }
+
+/**
+ * Gets the API keys to obtain/use service account credentials.
+ *
+ * @param {function(string):void} onDone Callback.
+ * @param {function(remoting.Error):void} onError The callback to be triggered
+ *     on error.
+ * @return {void} Nothing.
+ */
+remoting.HostNativeMessaging.prototype.getHostClientId =
+    function(onDone, onError) {
+  this.postMessage_({type: 'getHostClientId'}, onDone, onError);
+};
+
+/**
+ *
+ * @param {string} authorizationCode OAuth authorization code.
+ * @param {function(string, string):void} onDone Callback.
+ * @param {function(remoting.Error):void} onError The callback to be triggered
+ *     on error.
+ * @return {void} Nothing.
+ */
+remoting.HostNativeMessaging.prototype.getCredentialsFromAuthCode =
+    function(authorizationCode, onDone, onError) {
+  this.postMessage_({
+    type: 'getCredentialsFromAuthCode',
+    authorizationCode: authorizationCode
+  }, onDone, onError);
+};
diff --git a/remoting/webapp/host_table_entry.js b/remoting/webapp/host_table_entry.js
index 3ba5189..fe9970b 100644
--- a/remoting/webapp/host_table_entry.js
+++ b/remoting/webapp/host_table_entry.js
@@ -336,8 +336,23 @@
     };
     hostNameNode.addEventListener('keydown', onKeyDown, false);
   } else {
-    hostNameNode.innerText = chrome.i18n.getMessage(/*i18n-content*/'OFFLINE',
-                                                    this.host.hostName);
+    if (this.host.updatedTime) {
+      var lastOnline = new Date(this.host.updatedTime);
+      var now = new Date();
+      var displayString = '';
+      if (now.getFullYear() == lastOnline.getFullYear() &&
+          now.getMonth() == lastOnline.getMonth() &&
+          now.getDate() == lastOnline.getDate()) {
+        displayString = lastOnline.toLocaleTimeString();
+      } else {
+        displayString = lastOnline.toLocaleDateString();
+      }
+      hostNameNode.innerText = chrome.i18n.getMessage(
+          /*i18n-content*/'LAST_ONLINE', [this.host.hostName, displayString]);
+    } else {
+      hostNameNode.innerText = chrome.i18n.getMessage(
+          /*i18n-content*/'OFFLINE', this.host.hostName);
+    }
   }
   hostNameNode.classList.add('host-list-label');
   this.hostNameCell_.innerText = '';  // Remove previous contents (if any).
diff --git a/remoting/webapp/log_to_server.js b/remoting/webapp/log_to_server.js
index ad9b3c2..973bbf7 100644
--- a/remoting/webapp/log_to_server.js
+++ b/remoting/webapp/log_to_server.js
@@ -46,7 +46,7 @@
  * Logs a client session state change.
  *
  * @param {remoting.ClientSession.State} state
- * @param {remoting.ClientSession.ConnectionError} connectionError
+ * @param {remoting.Error} connectionError
  * @param {remoting.ClientSession.Mode} mode
  */
 remoting.LogToServer.prototype.logClientSessionStateChange =
diff --git a/remoting/webapp/main.html b/remoting/webapp/main.html
index 0013468..f4e4471 100644
--- a/remoting/webapp/main.html
+++ b/remoting/webapp/main.html
@@ -542,7 +542,7 @@
                          type="password"
                          autofocus="autofocus"
                          autocomplete="off"/>
-                  <button id="connect-button"
+                  <button id="pin-connect-button"
                           type="submit"
                           i18n-content="CONNECT_BUTTON">
                   </button>
diff --git a/remoting/webapp/remoting.js b/remoting/webapp/remoting.js
index 5be27ef..ec81c44 100644
--- a/remoting/webapp/remoting.js
+++ b/remoting/webapp/remoting.js
@@ -125,16 +125,18 @@
   }
   remoting.hostList.load(onLoad);
 
-  // Show the tab-type warnings if necessary.
-  /** @param {boolean} isWindowed */
-  var onIsWindowed = function(isWindowed) {
-    if (!isWindowed &&
-        navigator.platform.indexOf('Mac') == -1) {
-      document.getElementById('startup-mode-box-me2me').hidden = false;
-      document.getElementById('startup-mode-box-it2me').hidden = false;
-    }
-  };
-  isWindowed_(onIsWindowed);
+  // For Apps v1, check the tab type to warn the user if they are not getting
+  // the best keyboard experience.
+  if (!remoting.isAppsV2 && navigator.platform.indexOf('Mac') == -1) {
+    /** @param {boolean} isWindowed */
+    var onIsWindowed = function(isWindowed) {
+      if (!isWindowed) {
+        document.getElementById('startup-mode-box-me2me').hidden = false;
+        document.getElementById('startup-mode-box-it2me').hidden = false;
+      }
+    };
+    isWindowed_(onIsWindowed);
+  }
 };
 
 /**
@@ -262,7 +264,7 @@
  */
 remoting.promptClose = function() {
   if (!remoting.clientSession ||
-      remoting.clientSession.mode == remoting.ClientSession.Mode.ME2ME) {
+      remoting.clientSession.getMode() == remoting.ClientSession.Mode.ME2ME) {
     return null;
   }
   switch (remoting.currentMode) {
diff --git a/remoting/webapp/server_log_entry.js b/remoting/webapp/server_log_entry.js
index 2523518..cd758b9 100644
--- a/remoting/webapp/server_log_entry.js
+++ b/remoting/webapp/server_log_entry.js
@@ -48,10 +48,6 @@
       return 'unknown';
     case remoting.ClientSession.State.CREATED:
       return 'created';
-    case remoting.ClientSession.State.BAD_PLUGIN_VERSION:
-      return 'bad-plugin-version';
-    case remoting.ClientSession.State.UNKNOWN_PLUGIN_ERROR:
-      return 'unknown-plugin-error';
     case remoting.ClientSession.State.CONNECTING:
       return 'connecting';
     case remoting.ClientSession.State.INITIALIZING:
@@ -76,24 +72,34 @@
 
 /**
  * @private
- * @param {remoting.ClientSession.ConnectionError} connectionError
+ * @param {remoting.Error} connectionError
  * @return {string}
  */
-remoting.ServerLogEntry.getValueForConnectionError =
+remoting.ServerLogEntry.getValueForError =
     function(connectionError) {
   switch(connectionError) {
-    case remoting.ClientSession.ConnectionError.NONE:
+    case remoting.Error.NONE:
       return 'none';
-    case remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE:
+    case remoting.Error.INVALID_ACCESS_CODE:
+      return 'invalid-access-code';
+    case remoting.Error.MISSING_PLUGIN:
+      return 'missing_plugin';
+    case remoting.Error.AUTHENTICATION_FAILED:
+      return 'authentication-failed';
+    case remoting.Error.HOST_IS_OFFLINE:
       return 'host-is-offline';
-    case remoting.ClientSession.ConnectionError.SESSION_REJECTED:
-      return 'session-rejected';
-    case remoting.ClientSession.ConnectionError.INCOMPATIBLE_PROTOCOL:
+    case remoting.Error.INCOMPATIBLE_PROTOCOL:
       return 'incompatible-protocol';
-    case remoting.ClientSession.ConnectionError.NETWORK_FAILURE:
+    case remoting.Error.BAD_PLUGIN_VERSION:
+      return 'bad-plugin-version';
+    case remoting.Error.NETWORK_FAILURE:
       return 'network-failure';
-    case remoting.ClientSession.ConnectionError.UNKNOWN:
-      return 'unknown';
+    case remoting.Error.HOST_OVERLOAD:
+      return 'host-overload';
+    case remoting.Error.P2P_FAILURE:
+      return 'p2p-failure';
+    case remoting.Error.UNEXPECTED:
+      return 'unexpected';
     default:
       return 'unknown-' + connectionError;
   }
@@ -198,7 +204,7 @@
  * Makes a log entry for a change of client session state.
  *
  * @param {remoting.ClientSession.State} state
- * @param {remoting.ClientSession.ConnectionError} connectionError
+ * @param {remoting.Error} connectionError
  * @param {remoting.ClientSession.Mode} mode
  * @return {remoting.ServerLogEntry}
  */
@@ -211,10 +217,9 @@
             remoting.ServerLogEntry.VALUE_EVENT_NAME_SESSION_STATE_);
   entry.set(remoting.ServerLogEntry.KEY_SESSION_STATE_,
             remoting.ServerLogEntry.getValueForSessionState(state));
-  if (connectionError != remoting.ClientSession.ConnectionError.NONE) {
+  if (connectionError != remoting.Error.NONE) {
     entry.set(remoting.ServerLogEntry.KEY_CONNECTION_ERROR_,
-              remoting.ServerLogEntry.getValueForConnectionError(
-                  connectionError));
+              remoting.ServerLogEntry.getValueForError(connectionError));
   }
   entry.addModeField(mode);
   return entry;
diff --git a/remoting/webapp/session_connector.js b/remoting/webapp/session_connector.js
index 5febaab..1264e5c 100644
--- a/remoting/webapp/session_connector.js
+++ b/remoting/webapp/session_connector.js
@@ -315,6 +315,24 @@
 };
 
 /**
+ * Get host ID.
+ *
+ * @return {string}
+ */
+remoting.SessionConnector.prototype.getHostId = function() {
+  return this.hostId_;
+};
+
+/**
+ * Get host display name.
+ *
+ * @return {string}
+ */
+remoting.SessionConnector.prototype.getHostDisplayName = function() {
+  return this.hostDisplayName_;
+};
+
+/**
  * Continue an IT2Me connection once an access token has been obtained.
  *
  * @param {string} token An OAuth2 access token.
@@ -402,12 +420,13 @@
     this.clientSession_ = null;
   }
 
-  var securityTypes = 'third_party,spake2_pair,spake2_hmac,spake2_plain';
+  var authenticationMethods =
+     'third_party,spake2_pair,spake2_hmac,spake2_plain';
   this.clientSession_ = new remoting.ClientSession(
-      this.hostJid_, this.clientJid_, this.hostPublicKey_, this.passPhrase_,
-      this.fetchPin_, this.fetchThirdPartyToken_, securityTypes, this.hostId_,
-      this.connectionMode_, this.hostDisplayName_, this.clientPairingId_,
-      this.clientPairedSecret_);
+      this.clientJid_, this.passPhrase_, this.fetchPin_,
+      this.fetchThirdPartyToken_, authenticationMethods, this.hostId_,
+      this.hostJid_, this.hostPublicKey_, this.connectionMode_,
+      this.clientPairingId_, this.clientPairedSecret_);
   this.clientSession_.logHostOfflineErrors(!this.refreshHostJidIfOffline_);
   this.clientSession_.setOnStateChange(this.onStateChange_.bind(this));
   this.clientSession_.createPluginAndConnect(this.pluginParent_);
@@ -440,10 +459,6 @@
       console.log('Created plugin');
       break;
 
-    case remoting.ClientSession.State.BAD_PLUGIN_VERSION:
-      this.onError_(remoting.Error.BAD_PLUGIN_VERSION);
-      break;
-
     case remoting.ClientSession.State.CONNECTING:
       console.log('Connecting as ' + remoting.identity.getCachedEmail());
       break;
diff --git a/remoting/webapp/wcs_sandbox_container.js b/remoting/webapp/wcs_sandbox_container.js
index 6eaac66..04260a7 100644
--- a/remoting/webapp/wcs_sandbox_container.js
+++ b/remoting/webapp/wcs_sandbox_container.js
@@ -20,14 +20,19 @@
  * @constructor
  */
 remoting.WcsSandboxContainer = function(sandbox) {
+  /** @private */
   this.sandbox_ = sandbox;
-  /** @type {?function(string):void} */
+  /** @type {?function(string):void}
+    * @private */
   this.onLocalJid_ = null;
-  /** @type {?function(remoting.Error):void} */
-  this.onError_ = null;
-  /** @type {?function(string):void} */
+  /** @type {function(remoting.Error):void}
+    * @private */
+  this.onError_ = function(error) {};
+  /** @type {?function(string):void}
+    * @private */
   this.onIq_ = null;
-  /** @type {Object.<number, XMLHttpRequest>} */
+  /** @type {Object.<number, XMLHttpRequest>}
+    * @private */
   this.pendingXhrs_ = {};
 
   window.addEventListener('message', this.onMessage_.bind(this), false);
@@ -52,7 +57,7 @@
 };
 
 /**
- * @param {?function(remoting.Error):void} onError Callback invoked if the WCS
+ * @param {function(remoting.Error):void} onError Callback invoked if the WCS
  *     code cannot be loaded.
  * @return {void} Nothing.
  */
@@ -103,14 +108,13 @@
 
     case 'onLocalJid':
       /** @type {string} */
-      var clientJid = event.data['clientJid'];
-      if (clientJid === undefined) {
-        console.error('onReady: missing client JID');
+      var localJid = event.data['localJid'];
+      if (localJid === undefined) {
+        console.error('onReady: missing localJid');
         break;
       }
-      if (this.onLocalJid_) {
-        this.onLocalJid_(clientJid);
-      }
+      if (this.onLocalJid_)
+        this.onLocalJid_(localJid);
       break;
 
     case 'onError':
@@ -250,4 +254,4 @@
 }
 
 /** @type {remoting.WcsSandboxContainer} */
-remoting.wcsSandbox = null;
\ No newline at end of file
+remoting.wcsSandbox = null;
diff --git a/remoting/webapp/wcs_sandbox_content.js b/remoting/webapp/wcs_sandbox_content.js
index c3e346e..213d87a 100644
--- a/remoting/webapp/wcs_sandbox_content.js
+++ b/remoting/webapp/wcs_sandbox_content.js
@@ -125,14 +125,14 @@
  * Callback method to indicate that the WCS driver has loaded and provide the
  * full JID of the client.
  *
- * @param {string} clientJid The full JID of the WCS client.
+ * @param {string} localJid The full JID of the WCS client.
  * @private
  */
-remoting.WcsSandboxContent.prototype.onLocalJid_ = function(clientJid) {
+remoting.WcsSandboxContent.prototype.onLocalJid_ = function(localJid) {
   remoting.wcs.setOnIq(this.onIq_.bind(this));
   var message = {
     'command': 'onLocalJid',
-    'clientJid': clientJid
+    'localJid': localJid
   };
   this.parentWindow_.postMessage(message, '*');
 };
@@ -227,4 +227,4 @@
 window.addEventListener('load', onSandboxInit, false);
 
 /** @type {remoting.WcsSandboxContent} */
-remoting.sandboxContent = null;
\ No newline at end of file
+remoting.sandboxContent = null;
diff --git a/sandbox/win/sandbox_poc/pocdll/fs.cc b/sandbox/win/sandbox_poc/pocdll/fs.cc
index 5fab41b..9a5b2bc 100644
--- a/sandbox/win/sandbox_poc/pocdll/fs.cc
+++ b/sandbox/win/sandbox_poc/pocdll/fs.cc
@@ -14,7 +14,7 @@
   wchar_t path_expanded[MAX_PATH] = {0};
   DWORD size = ::ExpandEnvironmentStrings(path, path_expanded, MAX_PATH - 1);
   if (!size) {
-    fprintf(output, "[ERROR] Cannot expand \"%S\". Error %S.\r\n", path,
+    fprintf(output, "[ERROR] Cannot expand \"%S\". Error %d.\r\n", path,
             ::GetLastError());
   }
 
diff --git a/sandbox/win/src/handle_policy.cc b/sandbox/win/src/handle_policy.cc
index eeeea7b..718376e 100644
--- a/sandbox/win/src/handle_policy.cc
+++ b/sandbox/win/src/handle_policy.cc
@@ -79,7 +79,7 @@
   // If the policy didn't block us and we have no valid target, then the broker
   // (this process) is the valid target.
   HANDLE target_process = remote_target_process.IsValid() ?
-                          remote_target_process : ::GetCurrentProcess();
+                          remote_target_process.Get() : ::GetCurrentProcess();
   DWORD result = ERROR_SUCCESS;
   if (!::DuplicateHandle(client_info.process, source_handle, target_process,
                          target_handle, desired_access, FALSE,
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc
index a2d397c..d710fb6 100644
--- a/skia/ext/analysis_canvas.cc
+++ b/skia/ext/analysis_canvas.cc
@@ -212,7 +212,8 @@
                                     const SkBitmap& bitmap,
                                     const SkRect* src_or_null,
                                     const SkRect& dst,
-                                    const SkPaint& paint) {
+                                    const SkPaint& paint,
+                                    SkCanvas::DrawBitmapRectFlags flags) {
   // Call drawRect to determine transparency,
   // but reset solid color to false.
   drawRect(draw, dst, paint);
diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h
index 5db1540..b257b9f 100644
--- a/skia/ext/analysis_canvas.h
+++ b/skia/ext/analysis_canvas.h
@@ -102,7 +102,8 @@
                               const SkBitmap& bitmap,
                               const SkRect* src_or_null,
                               const SkRect& dst,
-                              const SkPaint& paint) OVERRIDE;
+                              const SkPaint& paint,
+                              SkCanvas::DrawBitmapRectFlags flags) OVERRIDE;
   virtual void drawText(const SkDraw& draw,
                         const void* text,
                         size_t len,
diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc
index d83252b..fbd2eb1 100644
--- a/skia/ext/benchmarking_canvas.cc
+++ b/skia/ext/benchmarking_canvas.cc
@@ -122,9 +122,10 @@
 
   virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
                                     const SkRect& dst,
-                                    const SkPaint* paint = NULL) OVERRIDE {
+                                    const SkPaint* paint,
+                                    DrawBitmapRectFlags flags) OVERRIDE {
     AutoStamper stamper(this);
-    SkProxyCanvas::drawBitmapRectToRect(bitmap, src, dst, paint);
+    SkProxyCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
   }
 
   virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
diff --git a/skia/ext/lazy_pixel_ref_utils.cc b/skia/ext/lazy_pixel_ref_utils.cc
index 67371c9..f0caef2 100644
--- a/skia/ext/lazy_pixel_ref_utils.cc
+++ b/skia/ext/lazy_pixel_ref_utils.cc
@@ -153,7 +153,8 @@
                               const SkBitmap& bitmap,
                               const SkRect* src_or_null,
                               const SkRect& dst,
-                              const SkPaint& paint) SK_OVERRIDE {
+                              const SkPaint& paint,
+                              SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
     SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
     SkMatrix matrix;
     matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
diff --git a/skia/ext/vector_platform_device_emf_win.cc b/skia/ext/vector_platform_device_emf_win.cc
index 958ff8f..16d0844 100644
--- a/skia/ext/vector_platform_device_emf_win.cc
+++ b/skia/ext/vector_platform_device_emf_win.cc
@@ -265,7 +265,8 @@
                                              const SkBitmap& bitmap,
                                              const SkRect* src,
                                              const SkRect& dst,
-                                             const SkPaint& paint) {
+                                             const SkPaint& paint,
+                                             SkCanvas::DrawBitmapRectFlags flags) {
     SkMatrix    matrix;
     SkRect      bitmapBounds, tmpSrc, tmpDst;
     SkBitmap    tmpBitmap;
diff --git a/skia/ext/vector_platform_device_emf_win.h b/skia/ext/vector_platform_device_emf_win.h
index c0deeec..9baee32 100644
--- a/skia/ext/vector_platform_device_emf_win.h
+++ b/skia/ext/vector_platform_device_emf_win.h
@@ -46,7 +46,8 @@
                         bool pathIsMutable = false) OVERRIDE;
   virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
                               const SkRect* src, const SkRect& dst,
-                              const SkPaint& paint) SK_OVERRIDE;
+                              const SkPaint& paint,
+                              SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE;
   virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
                           const SkMatrix& matrix,
                           const SkPaint& paint) OVERRIDE;
diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi
index ecd9b47..00a0f49 100644
--- a/skia/skia_chrome.gypi
+++ b/skia/skia_chrome.gypi
@@ -88,7 +88,7 @@
         'ext/SkThread_chrome.cc',
       ],
     }],
-    [ 'OS == "android"', {
+    [ 'OS == "android" and enable_printing == 0', {
       'sources!': [
         'ext/vector_platform_device_skia.cc',
       ],
diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi
index 2900553..23e5b7c 100644
--- a/skia/skia_library.gypi
+++ b/skia/skia_library.gypi
@@ -20,7 +20,7 @@
         }, {
           'skia_support_gpu': 1,
         }],
-        ['OS=="ios" or OS=="android"', {
+        ['OS=="ios" or enable_printing == 0', {
           'skia_support_pdf': 0,
         }, {
           'skia_support_pdf': 1,
@@ -41,14 +41,15 @@
       'SK_SUPPORT_GPU=<(skia_support_gpu)',
       'GR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"',
     ],
-    
+
     'default_font_cache_limit': '(20*1024*1024)',
 
     'conditions': [
       ['OS== "android"', {
         # Android devices are typically more memory constrained, so
-        # use a smaller glyph cache.
-        'default_font_cache_limit': '(8*1024*1024)',
+        # default to a smaller glyph cache (it may be overriden at runtime
+        # when the renderer starts up, depending on the actual device memory).
+        'default_font_cache_limit': '(1*1024*1024)',
         'skia_export_defines': [
           'SK_BUILD_FOR_ANDROID',
           'USE_CHROMIUM_SKIA',
@@ -117,6 +118,8 @@
     '../third_party/skia/src/ports/SkFontConfigParser_android.cpp',
     '../third_party/skia/src/ports/SkFontHost_mac.cpp',
     '../third_party/skia/src/ports/SkFontHost_win.cpp',
+    '../third_party/skia/src/ports/SkFontHost_win_dw.cpp',
+    '../third_party/skia/src/ports/SkFontMgr_default_gdi.cpp',
     '../third_party/skia/src/ports/SkGlobalInitialization_chromium.cpp',
     '../third_party/skia/src/ports/SkOSFile_posix.cpp',
     '../third_party/skia/src/ports/SkOSFile_stdio.cpp',
@@ -155,6 +158,11 @@
     '../third_party/skia/src/utils/SkProxyCanvas.cpp',
     '../third_party/skia/src/utils/SkRTConf.cpp',
     '../third_party/skia/include/utils/SkRTConf.h',
+    '../third_party/skia/src/utils/win/SkDWriteFontFileStream.cpp',
+    '../third_party/skia/src/utils/win/SkDWriteFontFileStream.h',
+    '../third_party/skia/src/utils/win/SkDWriteGeometrySink.cpp',
+    '../third_party/skia/src/utils/win/SkDWriteGeometrySink.h',
+    '../third_party/skia/src/utils/win/SkHRESULT.cpp',
     '../third_party/skia/include/pdf/SkPDFDevice.h',
     '../third_party/skia/include/pdf/SkPDFDocument.h',
 
@@ -355,7 +363,7 @@
       'sources/': [
         ['exclude', 'opts_check_SSE2\\.cpp$'],
       ],
-      
+
       # The main skia_opts target does not currently work on iOS because the
       # target architecture on iOS is determined at compile time rather than
       # gyp time (simulator builds are x86, device builds are arm).  As a
@@ -397,6 +405,24 @@
         '../third_party/skia/src/ports/SkTime_Unix.cpp',
         '../third_party/skia/src/ports/SkTLS_pthread.cpp',
       ],
+      'include_dirs': [
+        '../third_party/skia/include/utils/win',
+        '../third_party/skia/src/utils/win',
+      ],
+      'defines': [
+        'SK_FONTHOST_USES_FONTMGR',
+      ],
+    },{ # not 'OS == "win"'
+      'sources!': [
+        '../third_party/skia/src/ports/SkFontHost_win_dw.cpp',
+        '../third_party/skia/src/ports/SkFontMgr_default_gdi.cpp',
+
+        '../third_party/skia/src/utils/win/SkDWriteFontFileStream.cpp',
+        '../third_party/skia/src/utils/win/SkDWriteFontFileStream.h',
+        '../third_party/skia/src/utils/win/SkDWriteGeometrySink.cpp',
+        '../third_party/skia/src/utils/win/SkDWriteGeometrySink.h',
+        '../third_party/skia/src/utils/win/SkHRESULT.cpp',
+      ],
     }],
     # TODO(scottmg): http://crbug.com/177306
     ['clang==1', {
@@ -443,6 +469,7 @@
 
     'SKIA_IGNORE_GPU_MIPMAPS',
 
+    # this flag forces Skia not to use typographic metrics with GDI.
     'SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS',
 
     'SK_DEFAULT_FONT_CACHE_LIMIT=<(default_font_cache_limit)',
diff --git a/skia/skia_library.target.darwin-arm.mk b/skia/skia_library.target.darwin-arm.mk
index 3f0321b..bea158c 100644
--- a/skia/skia_library.target.darwin-arm.mk
+++ b/skia/skia_library.target.darwin-arm.mk
@@ -287,6 +287,7 @@
 	third_party/skia/src/gpu/GrAddPathRenderers_default.cpp \
 	third_party/skia/src/gpu/GrAllocPool.cpp \
 	third_party/skia/src/gpu/GrAtlas.cpp \
+	third_party/skia/src/gpu/GrBlend.cpp \
 	third_party/skia/src/gpu/GrBufferAllocPool.cpp \
 	third_party/skia/src/gpu/GrCacheID.cpp \
 	third_party/skia/src/gpu/GrClipData.cpp \
@@ -326,6 +327,7 @@
 	third_party/skia/src/gpu/GrTextureAccess.cpp \
 	third_party/skia/src/gpu/gr_unittests.cpp \
 	third_party/skia/src/gpu/effects/GrConfigConversionEffect.cpp \
+	third_party/skia/src/gpu/effects/GrBezierEffect.cpp \
 	third_party/skia/src/gpu/effects/GrConvolutionEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSimpleTextureEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSingleTextureEffect.cpp \
@@ -428,7 +430,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
@@ -550,7 +552,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
diff --git a/skia/skia_library.target.darwin-mips.mk b/skia/skia_library.target.darwin-mips.mk
index dbbd847..d64f1af 100644
--- a/skia/skia_library.target.darwin-mips.mk
+++ b/skia/skia_library.target.darwin-mips.mk
@@ -287,6 +287,7 @@
 	third_party/skia/src/gpu/GrAddPathRenderers_default.cpp \
 	third_party/skia/src/gpu/GrAllocPool.cpp \
 	third_party/skia/src/gpu/GrAtlas.cpp \
+	third_party/skia/src/gpu/GrBlend.cpp \
 	third_party/skia/src/gpu/GrBufferAllocPool.cpp \
 	third_party/skia/src/gpu/GrCacheID.cpp \
 	third_party/skia/src/gpu/GrClipData.cpp \
@@ -326,6 +327,7 @@
 	third_party/skia/src/gpu/GrTextureAccess.cpp \
 	third_party/skia/src/gpu/gr_unittests.cpp \
 	third_party/skia/src/gpu/effects/GrConfigConversionEffect.cpp \
+	third_party/skia/src/gpu/effects/GrBezierEffect.cpp \
 	third_party/skia/src/gpu/effects/GrConvolutionEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSimpleTextureEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSingleTextureEffect.cpp \
@@ -427,7 +429,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
@@ -548,7 +550,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
diff --git a/skia/skia_library.target.darwin-x86.mk b/skia/skia_library.target.darwin-x86.mk
index 8ce6ff2..1cc2f86 100644
--- a/skia/skia_library.target.darwin-x86.mk
+++ b/skia/skia_library.target.darwin-x86.mk
@@ -288,6 +288,7 @@
 	third_party/skia/src/gpu/GrAddPathRenderers_default.cpp \
 	third_party/skia/src/gpu/GrAllocPool.cpp \
 	third_party/skia/src/gpu/GrAtlas.cpp \
+	third_party/skia/src/gpu/GrBlend.cpp \
 	third_party/skia/src/gpu/GrBufferAllocPool.cpp \
 	third_party/skia/src/gpu/GrCacheID.cpp \
 	third_party/skia/src/gpu/GrClipData.cpp \
@@ -327,6 +328,7 @@
 	third_party/skia/src/gpu/GrTextureAccess.cpp \
 	third_party/skia/src/gpu/gr_unittests.cpp \
 	third_party/skia/src/gpu/effects/GrConfigConversionEffect.cpp \
+	third_party/skia/src/gpu/effects/GrBezierEffect.cpp \
 	third_party/skia/src/gpu/effects/GrConvolutionEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSimpleTextureEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSingleTextureEffect.cpp \
@@ -430,7 +432,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
@@ -554,7 +556,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
diff --git a/skia/skia_library.target.linux-arm.mk b/skia/skia_library.target.linux-arm.mk
index 3f0321b..bea158c 100644
--- a/skia/skia_library.target.linux-arm.mk
+++ b/skia/skia_library.target.linux-arm.mk
@@ -287,6 +287,7 @@
 	third_party/skia/src/gpu/GrAddPathRenderers_default.cpp \
 	third_party/skia/src/gpu/GrAllocPool.cpp \
 	third_party/skia/src/gpu/GrAtlas.cpp \
+	third_party/skia/src/gpu/GrBlend.cpp \
 	third_party/skia/src/gpu/GrBufferAllocPool.cpp \
 	third_party/skia/src/gpu/GrCacheID.cpp \
 	third_party/skia/src/gpu/GrClipData.cpp \
@@ -326,6 +327,7 @@
 	third_party/skia/src/gpu/GrTextureAccess.cpp \
 	third_party/skia/src/gpu/gr_unittests.cpp \
 	third_party/skia/src/gpu/effects/GrConfigConversionEffect.cpp \
+	third_party/skia/src/gpu/effects/GrBezierEffect.cpp \
 	third_party/skia/src/gpu/effects/GrConvolutionEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSimpleTextureEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSingleTextureEffect.cpp \
@@ -428,7 +430,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
@@ -550,7 +552,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
diff --git a/skia/skia_library.target.linux-mips.mk b/skia/skia_library.target.linux-mips.mk
index dbbd847..d64f1af 100644
--- a/skia/skia_library.target.linux-mips.mk
+++ b/skia/skia_library.target.linux-mips.mk
@@ -287,6 +287,7 @@
 	third_party/skia/src/gpu/GrAddPathRenderers_default.cpp \
 	third_party/skia/src/gpu/GrAllocPool.cpp \
 	third_party/skia/src/gpu/GrAtlas.cpp \
+	third_party/skia/src/gpu/GrBlend.cpp \
 	third_party/skia/src/gpu/GrBufferAllocPool.cpp \
 	third_party/skia/src/gpu/GrCacheID.cpp \
 	third_party/skia/src/gpu/GrClipData.cpp \
@@ -326,6 +327,7 @@
 	third_party/skia/src/gpu/GrTextureAccess.cpp \
 	third_party/skia/src/gpu/gr_unittests.cpp \
 	third_party/skia/src/gpu/effects/GrConfigConversionEffect.cpp \
+	third_party/skia/src/gpu/effects/GrBezierEffect.cpp \
 	third_party/skia/src/gpu/effects/GrConvolutionEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSimpleTextureEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSingleTextureEffect.cpp \
@@ -427,7 +429,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
@@ -548,7 +550,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
diff --git a/skia/skia_library.target.linux-x86.mk b/skia/skia_library.target.linux-x86.mk
index 8ce6ff2..1cc2f86 100644
--- a/skia/skia_library.target.linux-x86.mk
+++ b/skia/skia_library.target.linux-x86.mk
@@ -288,6 +288,7 @@
 	third_party/skia/src/gpu/GrAddPathRenderers_default.cpp \
 	third_party/skia/src/gpu/GrAllocPool.cpp \
 	third_party/skia/src/gpu/GrAtlas.cpp \
+	third_party/skia/src/gpu/GrBlend.cpp \
 	third_party/skia/src/gpu/GrBufferAllocPool.cpp \
 	third_party/skia/src/gpu/GrCacheID.cpp \
 	third_party/skia/src/gpu/GrClipData.cpp \
@@ -327,6 +328,7 @@
 	third_party/skia/src/gpu/GrTextureAccess.cpp \
 	third_party/skia/src/gpu/gr_unittests.cpp \
 	third_party/skia/src/gpu/effects/GrConfigConversionEffect.cpp \
+	third_party/skia/src/gpu/effects/GrBezierEffect.cpp \
 	third_party/skia/src/gpu/effects/GrConvolutionEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSimpleTextureEffect.cpp \
 	third_party/skia/src/gpu/effects/GrSingleTextureEffect.cpp \
@@ -430,7 +432,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
@@ -554,7 +556,7 @@
 	'-DIGNORE_ROT_AA_RECT_OPT' \
 	'-DSKIA_IGNORE_GPU_MIPMAPS' \
 	'-DSK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS' \
-	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(8*1024*1024)' \
+	'-DSK_DEFAULT_FONT_CACHE_LIMIT=(1*1024*1024)' \
 	'-DSK_GAMMA_APPLY_TO_A8' \
 	'-DSK_GAMMA_EXPONENT=1.4' \
 	'-DSK_GAMMA_CONTRAST=0.0' \
diff --git a/skia/skia_system.gypi b/skia/skia_system.gypi
index b05623c..a26bdc0 100644
--- a/skia/skia_system.gypi
+++ b/skia/skia_system.gypi
@@ -9,6 +9,13 @@
   'direct_dependent_settings': {
     # This makes the Android build system set the include path appropriately.
     'libraries': [ '-lskia' ],
+    # Some Chrome code uses non-public header files (http://crbug.com/274425),
+    # so we need to add this include path for now to make it build. The system
+    # version of skia is already required to be the same as the chromium version
+    # so using the bundled headers shouldn't break anything.
+    'include_dirs': [
+      '../third_party/skia/src/core',
+    ],
   },
   'link_settings': {
     # This actually causes the final binary to be linked against skia.
diff --git a/skia/skia_test_expectations.txt b/skia/skia_test_expectations.txt
index 83f6ac5..f4d8325 100644
--- a/skia/skia_test_expectations.txt
+++ b/skia/skia_test_expectations.txt
@@ -67,4 +67,9 @@
 crbug.com/266315 fast/repaint/shadow-multiple-strict-vertical.html [ ImageOnlyFailure ]
 crbug.com/266315 fast/repaint/shadow-multiple-vertical.html [ ImageOnlyFailure ]
 
+# With Skia r10769 the rendering of lines was slightly changed resulting in two
+# image layout differences
+crbug.com/275475 virtual/gpu/fast/canvas/canvas-transforms-during-path.html [ ImageOnlyFailure ]
+crbug.com/275475 virtual/gpu/fast/canvas/quadraticCurveTo.xml [ ImageOnlyFailure ]
+
 # END OVERRIDES HERE (this line ensures that the file is newline-terminated)
diff --git a/sql/connection.cc b/sql/connection.cc
index 3bc2545..097edd7 100644
--- a/sql/connection.cc
+++ b/sql/connection.cc
@@ -724,6 +724,29 @@
   return new StatementRef(NULL, stmt, true);
 }
 
+std::string Connection::GetSchema() const {
+  // The ORDER BY should not be necessary, but relying on organic
+  // order for something like this is questionable.
+  const char* kSql =
+      "SELECT type, name, tbl_name, sql "
+      "FROM sqlite_master ORDER BY 1, 2, 3, 4";
+  Statement statement(GetUntrackedStatement(kSql));
+
+  std::string schema;
+  while (statement.Step()) {
+    schema += statement.ColumnString(0);
+    schema += '|';
+    schema += statement.ColumnString(1);
+    schema += '|';
+    schema += statement.ColumnString(2);
+    schema += '|';
+    schema += statement.ColumnString(3);
+    schema += '\n';
+  }
+
+  return schema;
+}
+
 bool Connection::IsSQLValid(const char* sql) {
   AssertIOAllowed();
   if (!db_) {
diff --git a/sql/connection.h b/sql/connection.h
index 24f06de..7938606 100644
--- a/sql/connection.h
+++ b/sql/connection.h
@@ -389,6 +389,11 @@
   // last sqlite operation.
   const char* GetErrorMessage() const;
 
+  // Return a reproducible representation of the schema equivalent to
+  // running the following statement at a sqlite3 command-line:
+  //   SELECT type, name, tbl_name, sql FROM sqlite_master ORDER BY 1, 2, 3, 4;
+  std::string GetSchema() const;
+
  private:
   // For recovery module.
   friend class Recovery;
diff --git a/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java b/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java
index afec46c..6388588 100644
--- a/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java
+++ b/sync/android/java/src/org/chromium/sync/internal_api/pub/base/ModelType.java
@@ -7,11 +7,12 @@
 import android.util.Log;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Sets;
 import com.google.ipc.invalidation.external.client.types.ObjectId;
 import com.google.protos.ipc.invalidation.Types;
 
 import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -122,9 +123,9 @@
      */
     public static Set<ModelType> syncTypesToModelTypes(Collection<String> syncTypes) {
         if (syncTypes.contains(ALL_TYPES_TYPE)) {
-            return Sets.newHashSet(ModelType.values());
+            return EnumSet.allOf(ModelType.class);
         } else {
-            Set<ModelType> modelTypes = Sets.newHashSetWithExpectedSize(syncTypes.size());
+            Set<ModelType> modelTypes = new HashSet<ModelType>(syncTypes.size());
             for (String syncType : syncTypes) {
                 try {
                     modelTypes.add(valueOf(syncType));
@@ -152,7 +153,7 @@
      * This strips out any {@link ModelType} that is not an invalidation type.
      */
     public static Set<ObjectId> modelTypesToObjectIds(Set<ModelType> modelTypes) {
-        Set<ObjectId> objectIds = Sets.newHashSetWithExpectedSize(modelTypes.size());
+        Set<ObjectId> objectIds = new HashSet<ObjectId>(modelTypes.size());
         for (ModelType modelType : modelTypes) {
             if (!modelType.mNonInvalidationType) {
                 objectIds.add(modelType.toObjectId());
@@ -163,7 +164,7 @@
 
     /** Converts a set of {@link ModelType} to a set of string names. */
     public static Set<String> modelTypesToSyncTypes(Set<ModelType> modelTypes) {
-        Set<String> objectIds = Sets.newHashSetWithExpectedSize(modelTypes.size());
+        Set<String> objectIds = new HashSet<String>(modelTypes.size());
         for (ModelType modelType : modelTypes) {
             objectIds.add(modelType.toString());
         }
diff --git a/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java b/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java
index 03255d1..663ca00 100644
--- a/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java
+++ b/sync/android/java/src/org/chromium/sync/notifier/InvalidationController.java
@@ -10,9 +10,9 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
 
 import org.chromium.base.ActivityStatus;
+import org.chromium.base.CollectionUtil;
 import org.chromium.sync.internal_api.pub.base.ModelType;
 
 import java.util.Set;
@@ -66,7 +66,7 @@
                 }
             }
             registerIntent.putStringArrayListExtra(EXTRA_REGISTERED_TYPES,
-                    Lists.newArrayList(selectedTypesArray));
+                    CollectionUtil.newArrayList(selectedTypesArray));
             registerIntent.putExtra(EXTRA_ACCOUNT, account);
             return registerIntent;
         }
@@ -139,13 +139,6 @@
     }
 
     /**
-     * Returns the contract authority to use when requesting sync.
-     */
-    public String getContractAuthority() {
-        return mContext.getPackageName();
-    }
-
-    /**
      * Returns the instance that will use {@code context} to issue intents.
      *
      * Calling this method will create the instance if it does not yet exist.
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 963c417..7b0abd9 100644
--- a/sync/android/java/src/org/chromium/sync/notifier/InvalidationService.java
+++ b/sync/android/java/src/org/chromium/sync/notifier/InvalidationService.java
@@ -12,8 +12,6 @@
 import android.util.Log;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 import com.google.ipc.invalidation.external.client.InvalidationListener.RegistrationState;
 import com.google.ipc.invalidation.external.client.contrib.AndroidListener;
 import com.google.ipc.invalidation.external.client.types.ErrorInfo;
@@ -22,14 +20,15 @@
 import com.google.protos.ipc.invalidation.Types.ClientType;
 
 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.InvalidationPreferences.EditContext;
 import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.sync.signin.ChromeSigninController;
 
-import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Random;
 import java.util.Set;
@@ -96,7 +95,7 @@
             // If the intent requests a change in registrations, change them.
             List<String> regTypes =
                     intent.getStringArrayListExtra(IntentProtocol.EXTRA_REGISTERED_TYPES);
-            setRegisteredTypes(Sets.newHashSet(regTypes));
+            setRegisteredTypes(new HashSet<String>(regTypes));
         } else {
             // Otherwise, we don't recognize the intent. Pass it to the notification client service.
             super.onHandleIntent(intent);
@@ -131,7 +130,7 @@
         if (isTransient) {
           // Retry immediately on transient failures. The base AndroidListener will handle
           // exponential backoff if there are repeated failures.
-          List<ObjectId> objectIdAsList = Lists.newArrayList(objectId);
+          List<ObjectId> objectIdAsList = CollectionUtil.newArrayList(objectId);
           if (readRegistrationsFromPrefs().contains(objectId)) {
               register(clientId, objectIdAsList);
           } else {
@@ -144,7 +143,7 @@
     public void informRegistrationStatus(
             byte[] clientId, ObjectId objectId, RegistrationState regState) {
         Log.d(TAG, "Registration status for " + objectId + ": " + regState);
-        List<ObjectId> objectIdAsList = Lists.newArrayList(objectId);
+        List<ObjectId> objectIdAsList = CollectionUtil.newArrayList(objectId);
         boolean registrationisDesired = readRegistrationsFromPrefs().contains(objectId);
         if (regState == RegistrationState.REGISTERED) {
           if (!registrationisDesired) {
@@ -329,8 +328,8 @@
         // expansion of the ALL_TYPES_TYPE wildcard.
         // NOTE: syncTypes MUST NOT be used below this line, since it contains an unexpanded
         // wildcard.
-        List<ObjectId> unregistrations = Lists.newArrayList();
-        List<ObjectId> registrations = Lists.newArrayList();
+        Set<ObjectId> unregistrations = new HashSet<ObjectId>();
+        Set<ObjectId> registrations = new HashSet<ObjectId>();
         computeRegistrationOps(existingRegistrations,
                 ModelType.syncTypesToObjectIds(syncTypes),
                 registrations, unregistrations);
@@ -347,12 +346,15 @@
      */
     @VisibleForTesting
     static void computeRegistrationOps(Set<ObjectId> existingRegs, Set<ObjectId> desiredRegs,
-            Collection<ObjectId> regAccumulator, Collection<ObjectId> unregAccumulator) {
+            Set<ObjectId> regAccumulator, Set<ObjectId> unregAccumulator) {
+
         // Registrations to do are elements in the new set but not the old set.
-        regAccumulator.addAll(Sets.difference(desiredRegs, existingRegs));
+        regAccumulator.addAll(desiredRegs);
+        regAccumulator.removeAll(existingRegs);
 
         // Unregistrations to do are elements in the old set but not the new set.
-        unregAccumulator.addAll(Sets.difference(existingRegs, desiredRegs));
+        unregAccumulator.addAll(existingRegs);
+        unregAccumulator.removeAll(desiredRegs);
     }
 
     /**
@@ -379,7 +381,7 @@
             bundle.putString("payload", (payload == null) ? "" : payload);
         }
         Account account = ChromeSigninController.get(this).getSignedInUser();
-        String contractAuthority = InvalidationController.get(this).getContractAuthority();
+        String contractAuthority = SyncStatusHelper.get(this).getContractAuthority();
         requestSyncFromContentResolver(bundle, account, contractAuthority);
     }
 
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 9d82ab8..b315769 100644
--- a/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java
+++ b/sync/android/java/src/org/chromium/sync/notifier/SyncStatusHelper.java
@@ -86,8 +86,13 @@
         }
     }
 
+    @Deprecated
     public static final String AUTH_TOKEN_TYPE_SYNC = "chromiumsync";
 
+    // This should always have the same value as GaiaConstants::kChromeSyncOAuth2Scope.
+    public static final String CHROME_SYNC_OAUTH2_SCOPE =
+            "https://www.googleapis.com/auth/chromesync";
+
     public static final String TAG = "SyncStatusHelper";
 
     /**
@@ -126,8 +131,7 @@
             SyncContentResolverDelegate syncContentResolverWrapper) {
         mApplicationContext = context.getApplicationContext();
         mSyncContentResolverWrapper = syncContentResolverWrapper;
-        mContractAuthority =
-                InvalidationController.get(mApplicationContext).getContractAuthority();
+        mContractAuthority = getContractAuthority();
 
         updateMasterSyncAutomaticallySetting();
 
@@ -184,6 +188,13 @@
     }
 
     /**
+     * Returns the contract authority to use when requesting sync.
+     */
+    public String getContractAuthority() {
+        return mApplicationContext.getPackageName();
+    }
+
+    /**
      * Wrapper method for the ContentResolver.addStatusChangeListener(...) when we are only
      * interested in the settings type.
      */
diff --git a/sync/android/java/src/org/chromium/sync/signin/ChromeSigninController.java b/sync/android/java/src/org/chromium/sync/signin/ChromeSigninController.java
index a9a1b82..03805ec 100644
--- a/sync/android/java/src/org/chromium/sync/signin/ChromeSigninController.java
+++ b/sync/android/java/src/org/chromium/sync/signin/ChromeSigninController.java
@@ -6,10 +6,12 @@
 
 import android.accounts.Account;
 import android.content.Context;
+import android.os.AsyncTask;
 import android.preference.PreferenceManager;
 import android.util.Log;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener;
 
 import org.chromium.base.ObserverList;
 
@@ -34,6 +36,8 @@
 
     private final ObserverList<Listener> mListeners = new ObserverList<Listener>();
 
+    private boolean mGcmInitialized;
+
     private ChromeSigninController(Context context) {
         mApplicationContext = context.getApplicationContext();
     }
@@ -100,4 +104,29 @@
     public void removeListener(Listener listener) {
         mListeners.removeObserver(listener);
     }
+
+    /**
+     * Registers for Google Cloud Messaging (GCM) if there is no existing registration.
+     */
+    public void ensureGcmIsInitialized() {
+        if (mGcmInitialized) return;
+        mGcmInitialized = true;
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... arg0) {
+                try {
+                    String regId = MultiplexingGcmListener.initializeGcm(mApplicationContext);
+                    if (!regId.isEmpty())
+                        Log.d(TAG, "Already registered with GCM");
+                } catch (IllegalStateException exception) {
+                    Log.w(TAG, "Application manifest does not correctly configure GCM; "
+                            + "sync notifications will not work", exception);
+                } catch (UnsupportedOperationException exception) {
+                    Log.w(TAG, "Device does not support GCM; sync notifications will not work",
+                            exception);
+                }
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
 }
diff --git a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java
index 44f9eb4..215430b 100644
--- a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java
+++ b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationControllerTest.java
@@ -13,10 +13,8 @@
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
 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;
@@ -155,7 +153,7 @@
         InvalidationController controller = new InvalidationController(mContext);
         Account account = new Account("test@example.com", "bogus");
         controller.setRegisteredTypes(account, false,
-                Sets.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
+                CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
         assertEquals(1, mContext.getNumStartedIntents());
 
         // Validate destination.
@@ -168,9 +166,9 @@
         assertEquals(account, intentAccount);
 
         // Validate registered types.
-        Set<String> expectedTypes =
-                Sets.newHashSet(ModelType.BOOKMARK.name(), ModelType.SESSION.name());
-        Set<String> actualTypes = Sets.newHashSet();
+        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);
     }
@@ -180,7 +178,7 @@
     public void testRegisterForAllTypes() {
         Account account = new Account("test@example.com", "bogus");
         mController.setRegisteredTypes(account, true,
-                Sets.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
+                CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION));
         assertEquals(1, mContext.getNumStartedIntents());
 
         // Validate destination.
@@ -193,8 +191,8 @@
         assertEquals(account, intentAccount);
 
         // Validate registered types.
-        Set<String> expectedTypes = Sets.newHashSet(ModelType.ALL_TYPES_TYPE);
-        Set<String> actualTypes = Sets.newHashSet();
+        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);
     }
@@ -279,12 +277,6 @@
         assertEquals(true, resultAllTypes.get());
     }
 
-    @SmallTest
-    @Feature({"Sync"})
-    public void testGetContractAuthority() throws Exception {
-        assertEquals(mContext.getPackageName(), mController.getContractAuthority());
-    }
-
     /**
      * Asserts that {@code intent} is destined for the correct component.
      */
@@ -298,7 +290,7 @@
      * Mock context that saves all intents given to {@code startService}.
      */
     private static class IntentSavingContext extends AdvancedMockContext {
-        private final List<Intent> startedIntents = Lists.newArrayList();
+        private final List<Intent> startedIntents = new ArrayList<Intent>();
 
         IntentSavingContext(Context targetContext) {
             super(targetContext);
diff --git a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationPreferencesTest.java b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationPreferencesTest.java
index 4586513..2c5e841 100644
--- a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationPreferencesTest.java
+++ b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationPreferencesTest.java
@@ -9,14 +9,13 @@
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.google.common.collect.Sets;
-
+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.InvalidationPreferences;
 
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -41,9 +40,10 @@
          * Test plan: convert three strings to model types, one of which is invalid. Verify that
          * the two valid strings are properly converted and that the invalid string is dropped.
          */
-        HashSet<ModelType> expectedTypes = Sets.newHashSet(ModelType.BOOKMARK, ModelType.SESSION);
+        HashSet<ModelType> expectedTypes = CollectionUtil.newHashSet(
+                ModelType.BOOKMARK,ModelType.SESSION);
         Set<ModelType> actualTypes = ModelType.syncTypesToModelTypes(
-                Sets.newHashSet("BOOKMARK", "SESSION", "0!!!INVALID"));
+                CollectionUtil.newHashSet("BOOKMARK", "SESSION", "0!!!INVALID"));
         assertEquals(expectedTypes, actualTypes);
     }
 
@@ -54,9 +54,9 @@
          * Test plan: convert the special all-types type to model types. Verify that it is
          * properly expanded.
          */
-        HashSet<ModelType> expectedTypes = Sets.newHashSet(ModelType.values());
+        Set<ModelType> expectedTypes = EnumSet.allOf(ModelType.class);
         Set<ModelType> actualTypes = ModelType.syncTypesToModelTypes(
-                Sets.newHashSet(ModelType.ALL_TYPES_TYPE));
+                CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE));
         assertEquals(expectedTypes, actualTypes);
     }
 
@@ -84,7 +84,7 @@
 
         // We should never write both a real type and the all-types type in practice, but we test
         // with them here to ensure that preferences are not interpreting the written data.
-        Set<String> syncTypes = Sets.newHashSet("BOOKMARK", ModelType.ALL_TYPES_TYPE);
+        Set<String> syncTypes = CollectionUtil.newHashSet("BOOKMARK", ModelType.ALL_TYPES_TYPE);
         Account account = new Account("test@example.com", "bogus");
         byte[] internalClientState = new byte[]{100,101,102};
         invPreferences.setSyncTypes(editContext, syncTypes);
@@ -102,4 +102,4 @@
         assertTrue(Arrays.equals(
                 internalClientState, invPreferences.getInternalNotificationClientState()));
     }
-}
+}
\ No newline at end of file
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 db27879..18d6507 100644
--- a/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationServiceTest.java
+++ b/sync/android/javatests/src/org/chromium/sync/notifier/InvalidationServiceTest.java
@@ -11,15 +11,13 @@
 import android.test.ServiceTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 import com.google.ipc.invalidation.external.client.InvalidationListener.RegistrationState;
 import com.google.ipc.invalidation.external.client.contrib.AndroidListener;
 import com.google.ipc.invalidation.external.client.types.ErrorInfo;
 import com.google.ipc.invalidation.external.client.types.Invalidation;
 import com.google.ipc.invalidation.external.client.types.ObjectId;
 
+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;
@@ -27,7 +25,10 @@
 import org.chromium.sync.notifier.InvalidationPreferences.EditContext;
 import org.chromium.sync.signin.AccountManagerHelper;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -50,7 +51,7 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mStartServiceIntents = Lists.newArrayList();
+        mStartServiceIntents = new ArrayList<Intent>();
         setContext(new AdvancedMockContext(getContext()) {
             @Override
             public ComponentName startService(Intent intent) {
@@ -78,49 +79,52 @@
          * Test plan: compute the set of registration operations resulting from various combinations
          * of existing and desired registrations. Verifying that they are correct.
          */
-        List<ObjectId> regAccumulator = Lists.newArrayList();
-        List<ObjectId> unregAccumulator = Lists.newArrayList();
+        Set<ObjectId> regAccumulator = new HashSet<ObjectId>();
+        Set<ObjectId> unregAccumulator = new HashSet<ObjectId>();
 
         // Empty existing and desired registrations should yield empty operation sets.
         InvalidationService.computeRegistrationOps(
                 ModelType.modelTypesToObjectIds(
-                        Sets.newHashSet(ModelType.BOOKMARK, ModelType.SESSION)),
+                        CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION)),
                 ModelType.modelTypesToObjectIds(
-                        Sets.newHashSet(ModelType.BOOKMARK, ModelType.SESSION)),
+                        CollectionUtil.newHashSet(ModelType.BOOKMARK, ModelType.SESSION)),
                 regAccumulator, unregAccumulator);
         assertEquals(0, regAccumulator.size());
         assertEquals(0, unregAccumulator.size());
 
         // Equal existing and desired registrations should yield empty operation sets.
-        InvalidationService.computeRegistrationOps(Sets.<ObjectId>newHashSet(),
-                Sets.<ObjectId>newHashSet(), regAccumulator, unregAccumulator);
+        InvalidationService.computeRegistrationOps(new HashSet<ObjectId>(),
+                new HashSet<ObjectId>(), regAccumulator, unregAccumulator);
         assertEquals(0, regAccumulator.size());
         assertEquals(0, unregAccumulator.size());
 
         // Empty existing and non-empty desired registrations should yield desired registrations
         // as the registration operations to do and no unregistrations.
         Set<ObjectId> desiredTypes =
-                Sets.newHashSet(ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId());
+                CollectionUtil.newHashSet(
+                        ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId());
         InvalidationService.computeRegistrationOps(
-                Sets.<ObjectId>newHashSet(),
+                new HashSet<ObjectId>(),
                 desiredTypes,
                 regAccumulator, unregAccumulator);
         assertEquals(
-                Sets.newHashSet(ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId()),
-                Sets.newHashSet(regAccumulator));
+                CollectionUtil.newHashSet(
+                        ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId()),
+                new HashSet<ObjectId>(regAccumulator));
         assertEquals(0, unregAccumulator.size());
         regAccumulator.clear();
 
         // Unequal existing and desired registrations should yield both registrations and
         // unregistrations. We should unregister TYPED_URL and register BOOKMARK, keeping SESSION.
         InvalidationService.computeRegistrationOps(
-                Sets.<ObjectId>newHashSet(
+                CollectionUtil.newHashSet(
                         ModelType.SESSION.toObjectId(), ModelType.TYPED_URL.toObjectId()),
-                Sets.<ObjectId>newHashSet(
+                CollectionUtil.newHashSet(
                         ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId()),
                 regAccumulator, unregAccumulator);
-        assertEquals(Lists.newArrayList(ModelType.BOOKMARK.toObjectId()), regAccumulator);
-        assertEquals(Lists.newArrayList(ModelType.TYPED_URL.toObjectId()), unregAccumulator);
+        assertEquals(CollectionUtil.newHashSet(ModelType.BOOKMARK.toObjectId()), regAccumulator);
+        assertEquals(CollectionUtil.newHashSet(ModelType.TYPED_URL.toObjectId()),
+                unregAccumulator);
         regAccumulator.clear();
         unregAccumulator.clear();
     }
@@ -136,7 +140,7 @@
         // Persist some registrations.
         InvalidationPreferences invPrefs = new InvalidationPreferences(getContext());
         EditContext editContext = invPrefs.edit();
-        invPrefs.setSyncTypes(editContext, Lists.newArrayList("BOOKMARK", "SESSION"));
+        invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("BOOKMARK", "SESSION"));
         assertTrue(invPrefs.commit(editContext));
 
         // Issue ready.
@@ -147,9 +151,9 @@
         assertTrue(Arrays.equals(otherCid, InvalidationService.getClientIdForTest()));
 
         // Verify registrations issued.
-        assertEquals(
-                Sets.newHashSet(ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId()),
-                Sets.newHashSet(getService().mRegistrations.get(0)));
+        assertEquals(CollectionUtil.newHashSet(
+                ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId()),
+                new HashSet<ObjectId>(getService().mRegistrations.get(0)));
     }
 
     @SmallTest
@@ -169,15 +173,15 @@
         // Persist some registrations.
         InvalidationPreferences invPrefs = new InvalidationPreferences(getContext());
         EditContext editContext = invPrefs.edit();
-        invPrefs.setSyncTypes(editContext, Lists.newArrayList("BOOKMARK", "SESSION"));
+        invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("BOOKMARK", "SESSION"));
         assertTrue(invPrefs.commit(editContext));
 
         // Reissue registrations and verify that the appropriate registrations are issued.
         getService().reissueRegistrations(CLIENT_ID);
         assertEquals(1, getService().mRegistrations.size());
-        assertEquals(
-                Sets.newHashSet(ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId()),
-                Sets.newHashSet(getService().mRegistrations.get(0)));
+        assertEquals(CollectionUtil.newHashSet(
+                ModelType.BOOKMARK.toObjectId(), ModelType.SESSION.toObjectId()),
+                new HashSet<ObjectId>(getService().mRegistrations.get(0)));
     }
 
     @SmallTest
@@ -195,7 +199,7 @@
         // Initial test setup: persist a single registration into preferences.
         InvalidationPreferences invPrefs = new InvalidationPreferences(getContext());
         EditContext editContext = invPrefs.edit();
-        invPrefs.setSyncTypes(editContext, Lists.newArrayList("SESSION"));
+        invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("SESSION"));
         assertTrue(invPrefs.commit(editContext));
 
         // Cases 1 and 2: calls matching desired state cause no actions.
@@ -211,7 +215,7 @@
                 RegistrationState.REGISTERED);
         assertEquals(1, getService().mUnregistrations.size());
         assertEquals(0, getService().mRegistrations.size());
-        assertEquals(Lists.newArrayList(ModelType.BOOKMARK.toObjectId()),
+        assertEquals(CollectionUtil.newArrayList(ModelType.BOOKMARK.toObjectId()),
                 getService().mUnregistrations.get(0));
 
         // Case 4: unregistration of a desired object triggers a registration.
@@ -219,7 +223,7 @@
                 RegistrationState.UNREGISTERED);
         assertEquals(1, getService().mUnregistrations.size());
         assertEquals(1, getService().mRegistrations.size());
-        assertEquals(Lists.newArrayList(ModelType.SESSION.toObjectId()),
+        assertEquals(CollectionUtil.newArrayList(ModelType.SESSION.toObjectId()),
                 getService().mRegistrations.get(0));
     }
 
@@ -241,7 +245,7 @@
         // Initial test setup: persist a single registration into preferences.
         InvalidationPreferences invPrefs = new InvalidationPreferences(getContext());
         EditContext editContext = invPrefs.edit();
-        invPrefs.setSyncTypes(editContext, Lists.newArrayList("SESSION"));
+        invPrefs.setSyncTypes(editContext, CollectionUtil.newArrayList("SESSION"));
         assertTrue(invPrefs.commit(editContext));
 
         // Cases 2 and 4: permanent registration failures never cause calls to be made.
@@ -256,7 +260,7 @@
         getService().informRegistrationFailure(CLIENT_ID, ModelType.SESSION.toObjectId(), true, "");
         assertEquals(1, getService().mRegistrations.size());
         assertTrue(getService().mUnregistrations.isEmpty());
-        assertEquals(Lists.newArrayList(ModelType.SESSION.toObjectId()),
+        assertEquals(CollectionUtil.newArrayList(ModelType.SESSION.toObjectId()),
                 getService().mRegistrations.get(0));
 
         // Case 3: transient failure of an undesired registration results in unregistration.
@@ -264,7 +268,7 @@
                 "");
         assertEquals(1, getService().mRegistrations.size());
         assertEquals(1, getService().mUnregistrations.size());
-        assertEquals(Lists.newArrayList(ModelType.BOOKMARK.toObjectId()),
+        assertEquals(CollectionUtil.newArrayList(ModelType.BOOKMARK.toObjectId()),
                 getService().mUnregistrations.get(0));
     }
 
@@ -484,8 +488,8 @@
         getService().onCreate();
 
         // Send register Intent.
-        ImmutableSet<ModelType> desiredRegistrations =
-                ImmutableSet.of(ModelType.BOOKMARK, ModelType.SESSION);
+        Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet(
+                ModelType.BOOKMARK, ModelType.SESSION);
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
         Intent registrationIntent = IntentProtocol.createRegisterIntent(account, false,
                 desiredRegistrations);
@@ -504,7 +508,8 @@
         // verify that the on-disk state is updated and that no addition Intents are issued.
         getService().onHandleIntent(IntentProtocol.createRegisterIntent(account, true, null));
         assertEquals(account, invPrefs.getSavedSyncedAccount());
-        assertEquals(ImmutableSet.of(ModelType.ALL_TYPES_TYPE), invPrefs.getSavedSyncedTypes());
+        assertEquals(CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE),
+                invPrefs.getSavedSyncedTypes());
         assertEquals(1, mStartServiceIntents.size());
 
         // Finally, send one more registration-change intent, this time with a different account,
@@ -534,7 +539,8 @@
         assertTrue(InvalidationService.getIsClientStartedForTest());
         InvalidationPreferences invPrefs = new InvalidationPreferences(getContext());
         assertEquals(account, invPrefs.getSavedSyncedAccount());
-        assertEquals(ImmutableSet.of(ModelType.ALL_TYPES_TYPE), invPrefs.getSavedSyncedTypes());
+        assertEquals(CollectionUtil.newHashSet(ModelType.ALL_TYPES_TYPE),
+                invPrefs.getSavedSyncedTypes());
         assertEquals(1, mStartServiceIntents.size());
         assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0)));
 
@@ -544,8 +550,8 @@
 
         // Ensure registrations are correct.
         Set<ObjectId> expectedTypes =
-                ModelType.modelTypesToObjectIds(Sets.newHashSet(ModelType.values()));
-        assertEquals(expectedTypes, Sets.newHashSet(getService().mRegistrations.get(0)));
+                ModelType.modelTypesToObjectIds(EnumSet.allOf(ModelType.class));
+        assertEquals(expectedTypes, new HashSet<ObjectId>(getService().mRegistrations.get(0)));
     }
 
     @SmallTest
@@ -557,14 +563,14 @@
         // Send register Intent with no desired types.
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
         Intent registrationIntent =
-                IntentProtocol.createRegisterIntent(account, false, Sets.<ModelType>newHashSet());
+                IntentProtocol.createRegisterIntent(account, false, new HashSet<ModelType>());
         getService().onHandleIntent(registrationIntent);
 
         // Verify client started and state written.
         assertTrue(InvalidationService.getIsClientStartedForTest());
         InvalidationPreferences invPrefs = new InvalidationPreferences(getContext());
         assertEquals(account, invPrefs.getSavedSyncedAccount());
-        assertEquals(Sets.<String>newHashSet(), invPrefs.getSavedSyncedTypes());
+        assertEquals(new HashSet<String>(), invPrefs.getSavedSyncedTypes());
         assertEquals(1, mStartServiceIntents.size());
         assertTrue(isAndroidListenerStartIntent(mStartServiceIntents.get(0)));
 
@@ -579,8 +585,8 @@
         // Ensure registrations are correct.
         assertEquals(1, getService().mRegistrations.size());
         Set<ObjectId> expectedTypes =
-                ModelType.modelTypesToObjectIds(Sets.newHashSet(ModelType.values()));
-        assertEquals(expectedTypes, Sets.newHashSet(getService().mRegistrations.get(0)));
+                ModelType.modelTypesToObjectIds(EnumSet.allOf(ModelType.class));
+        assertEquals(expectedTypes, new HashSet<ObjectId>(getService().mRegistrations.get(0)));
     }
 
     @SmallTest
@@ -594,8 +600,8 @@
 
         // Send register Intent.
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
-        ImmutableSet<ModelType> desiredRegistrations =
-                ImmutableSet.of(ModelType.BOOKMARK, ModelType.SESSION);
+        Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet(
+                ModelType.BOOKMARK, ModelType.SESSION);
         Intent registrationIntent = IntentProtocol.createRegisterIntent(account, false,
                 desiredRegistrations);
         getService().onHandleIntent(registrationIntent);
@@ -622,8 +628,8 @@
 
         // Send register Intent. Verify client started but no registrations issued.
         Account account = AccountManagerHelper.createAccountFromName("test@example.com");
-        ImmutableSet<ModelType> desiredRegistrations =
-                ImmutableSet.of(ModelType.BOOKMARK, ModelType.SESSION);
+        Set<ModelType> desiredRegistrations = CollectionUtil.newHashSet(
+                ModelType.BOOKMARK, ModelType.SESSION);
         Set<ObjectId> desiredObjectIds = ModelType.modelTypesToObjectIds(desiredRegistrations);
 
         Intent registrationIntent = IntentProtocol.createRegisterIntent(account, false,
@@ -650,7 +656,7 @@
                 actualRegisterIntent.getExtras().keySet());
         assertEquals(
                 desiredObjectIds,
-                Sets.newHashSet(getService().mRegistrations.get(0)));
+                new HashSet<ObjectId>(getService().mRegistrations.get(0)));
     }
 
     @SmallTest
diff --git a/sync/android/javatests/src/org/chromium/sync/notifier/TestableInvalidationService.java b/sync/android/javatests/src/org/chromium/sync/notifier/TestableInvalidationService.java
index 9614a10..04eb6ba 100644
--- a/sync/android/javatests/src/org/chromium/sync/notifier/TestableInvalidationService.java
+++ b/sync/android/javatests/src/org/chromium/sync/notifier/TestableInvalidationService.java
@@ -4,15 +4,16 @@
 
 package org.chromium.sync.notifier;
 
-import com.google.common.collect.Lists;
-import com.google.ipc.invalidation.external.client.types.AckHandle;
-import com.google.ipc.invalidation.external.client.types.ObjectId;
-
 import android.accounts.Account;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Bundle;
 
+import com.google.ipc.invalidation.external.client.types.ObjectId;
+
+import org.chromium.base.CollectionUtil;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -23,18 +24,18 @@
  */
 public class TestableInvalidationService extends InvalidationService {
     /** Object ids given to {@link #register}, one list element per call. */
-    final List<List<ObjectId>> mRegistrations = Lists.newArrayList();
+    final List<List<ObjectId>> mRegistrations = new ArrayList<List<ObjectId>>();
 
     /** Object ids given to {@link #unregister}, one list element per call. */
-    final List<List<ObjectId>> mUnregistrations = Lists.newArrayList();
+    final List<List<ObjectId>> mUnregistrations = new ArrayList<List<ObjectId>>();
 
     /** Intents given to {@link #startService}. */
-    final List<Intent> mStartedServices = Lists.newArrayList();
+    final List<Intent> mStartedServices = new ArrayList<Intent>();
 
     /** Bundles given to {@link #requestSyncFromContentResolver}. */
-    final List<Bundle> mRequestedSyncs = Lists.newArrayList();
+    final List<Bundle> mRequestedSyncs = new ArrayList<Bundle>();
 
-    final List<byte[]> mAcknowledgements = Lists.newArrayList();
+    final List<byte[]> mAcknowledgements = new ArrayList<byte[]>();
 
     /** Whether Chrome is in the foreground. */
     private boolean mIsChromeInForeground = false;
@@ -52,13 +53,13 @@
 
     @Override
     public void register(byte[] clientId, Iterable<ObjectId> objectIds) {
-        mRegistrations.add(Lists.newArrayList(objectIds));
+        mRegistrations.add(CollectionUtil.newArrayList(objectIds));
         super.register(clientId, objectIds);
     }
 
     @Override
     public void unregister(byte[] clientId, Iterable<ObjectId> objectIds) {
-        mUnregistrations.add(Lists.newArrayList(objectIds));
+        mUnregistrations.add(CollectionUtil.newArrayList(objectIds));
         super.unregister(clientId, objectIds);
     }
 
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 a6d3dc7..a2e83bc 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
@@ -63,8 +63,8 @@
         ChromeSigninController.get(
                 getInstrumentation().getTargetContext()).setSignedInAccountName(
                         "account@example.com");
-        mAuthority = InvalidationController.get(
-                getInstrumentation().getTargetContext()).getContractAuthority();
+        mAuthority = SyncStatusHelper.get(getInstrumentation().getTargetContext())
+                .getContractAuthority();
         mTestAccount = new Account("account@example.com", "com.google");
         mAlternateTestAccount = new Account("alternateAccount@example.com", "com.google");
         super.setUp();
@@ -234,4 +234,12 @@
         assertEquals(getSyncAutomaticallyAcalls + 1,
                 mSyncContentResolverDelegate.mGetSyncAutomaticallyCalls);
     }
+
+    @SmallTest
+    @Feature({"Sync"})
+    public void testGetContractAuthority() throws Exception {
+        assertEquals("The contract authority should be the package name.",
+                getInstrumentation().getTargetContext().getPackageName(),
+                mHelper.getContractAuthority());
+    }
 }
diff --git a/sync/engine/build_commit_command.cc b/sync/engine/build_commit_command.cc
index 1bfac0f..0143370 100644
--- a/sync/engine/build_commit_command.cc
+++ b/sync/engine/build_commit_command.cc
@@ -118,14 +118,6 @@
   AddExtensionsActivityToMessage(session, commit_message);
   AddClientConfigParamsToMessage(session, commit_message);
 
-  // Cache previously computed position values.  Because |commit_ids|
-  // is already in sibling order, we should always hit this map after
-  // the first sibling in a consecutive run of commit items.  The
-  // entries in this map are (low, high) values describing the
-  // space of positions that are immediate successors of the item
-  // whose ID is the map's key.
-  std::map<Id, std::pair<int64, int64> > position_map;
-
   for (size_t i = 0; i < batch_commit_set_.Size(); i++) {
     Id id = batch_commit_set_.GetCommitIdAt(i);
     sync_pb::SyncEntity* sync_entry = commit_message->add_entries();
diff --git a/sync/engine/download.cc b/sync/engine/download.cc
index 74bc4e2..d511fc0 100644
--- a/sync/engine/download.cc
+++ b/sync/engine/download.cc
@@ -79,48 +79,20 @@
   return need_encryption_key;
 }
 
-SyncerError ExecuteDownloadUpdates(
+void AppendClientDebugInfoIfNeeded(
     SyncSession* session,
-    sync_pb::ClientToServerMessage* msg) {
-  sync_pb::ClientToServerResponse update_response;
-  StatusController* status = session->mutable_status_controller();
-  bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
-
-  SyncerError result = SyncerProtoUtil::PostClientToServerMessage(
-      msg,
-      &update_response,
-      session);
-
-  DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString(
-      update_response);
-
-  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));
+    DebugInfo* debug_info) {
+  // We want to send the debug info only once per sync cycle. Check if it has
+  // already been sent.
+  if (!session->status_controller().debug_info_sent()) {
+    DVLOG(1) << "Sending client debug info ...";
+    // Could be null in some unit tests.
+    if (session->context()->debug_info_getter()) {
+      session->context()->debug_info_getter()->GetAndClearDebugInfo(
+          debug_info);
     }
+    session->mutable_status_controller()->set_debug_info_sent();
   }
-
-  ProcessUpdatesCommand process_updates;
-  process_updates.Execute(session);
-
-  StoreTimestampsCommand store_timestamps;
-  store_timestamps.Execute(session);
-
-  return result;
 }
 
 void InitDownloadUpdatesRequest(
@@ -166,19 +138,19 @@
 
 }  // namespace
 
-SyncerError NormalDownloadUpdates(
+void BuildNormalDownloadUpdates(
     SyncSession* session,
     bool create_mobile_bookmarks_folder,
     ModelTypeSet request_types,
-    const sessions::NudgeTracker& nudge_tracker) {
-  sync_pb::ClientToServerMessage client_to_server_message;
+    const sessions::NudgeTracker& nudge_tracker,
+    sync_pb::ClientToServerMessage* client_to_server_message) {
   InitDownloadUpdatesRequest(
       session,
       create_mobile_bookmarks_folder,
-      &client_to_server_message,
+      client_to_server_message,
       request_types);
   sync_pb::GetUpdatesMessage* get_updates =
-      client_to_server_message.mutable_get_updates();
+      client_to_server_message->mutable_get_updates();
 
   // Request updates for all requested types.
   DVLOG(1) << "Getting updates for types "
@@ -207,23 +179,21 @@
         type,
         progress_marker->mutable_get_update_triggers());
   }
-
-  return ExecuteDownloadUpdates(session, &client_to_server_message);
 }
 
-SyncerError DownloadUpdatesForConfigure(
+void BuildDownloadUpdatesForConfigure(
     SyncSession* session,
     bool create_mobile_bookmarks_folder,
     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    ModelTypeSet request_types) {
-  sync_pb::ClientToServerMessage client_to_server_message;
+    ModelTypeSet request_types,
+    sync_pb::ClientToServerMessage* client_to_server_message) {
   InitDownloadUpdatesRequest(
       session,
       create_mobile_bookmarks_folder,
-      &client_to_server_message,
+      client_to_server_message,
       request_types);
   sync_pb::GetUpdatesMessage* get_updates =
-      client_to_server_message.mutable_get_updates();
+      client_to_server_message->mutable_get_updates();
 
   // Request updates for all enabled types.
   DVLOG(1) << "Initial download for types "
@@ -237,22 +207,20 @@
   sync_pb::SyncEnums::GetUpdatesOrigin origin =
       ConvertConfigureSourceToOrigin(source);
   get_updates->set_get_updates_origin(origin);
-
-  return ExecuteDownloadUpdates(session, &client_to_server_message);
 }
 
-SyncerError DownloadUpdatesForPoll(
+void BuildDownloadUpdatesForPoll(
     SyncSession* session,
     bool create_mobile_bookmarks_folder,
-    ModelTypeSet request_types) {
-  sync_pb::ClientToServerMessage client_to_server_message;
+    ModelTypeSet request_types,
+    sync_pb::ClientToServerMessage* client_to_server_message) {
   InitDownloadUpdatesRequest(
       session,
       create_mobile_bookmarks_folder,
-      &client_to_server_message,
+      client_to_server_message,
       request_types);
   sync_pb::GetUpdatesMessage* get_updates =
-      client_to_server_message.mutable_get_updates();
+      client_to_server_message->mutable_get_updates();
 
   DVLOG(1) << "Polling for types "
            << ModelTypeSetToString(request_types);
@@ -264,24 +232,50 @@
 
   // Set the new and improved version of source, too.
   get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC);
-
-  return ExecuteDownloadUpdates(session, &client_to_server_message);
 }
 
-void AppendClientDebugInfoIfNeeded(
+SyncerError ExecuteDownloadUpdates(
     SyncSession* session,
-    DebugInfo* debug_info) {
-  // We want to send the debug info only once per sync cycle. Check if it has
-  // already been sent.
-  if (!session->status_controller().debug_info_sent()) {
-    DVLOG(1) << "Sending client debug info ...";
-    // could be null in some unit tests.
-    if (session->context()->debug_info_getter()) {
-      session->context()->debug_info_getter()->GetAndClearDebugInfo(
-          debug_info);
+    sync_pb::ClientToServerMessage* msg) {
+  sync_pb::ClientToServerResponse update_response;
+  StatusController* status = session->mutable_status_controller();
+  bool need_encryption_key = ShouldRequestEncryptionKey(session->context());
+
+  SyncerError result = SyncerProtoUtil::PostClientToServerMessage(
+      msg,
+      &update_response,
+      session);
+
+  DVLOG(2) << SyncerProtoUtil::ClientToServerResponseDebugString(
+      update_response);
+
+  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));
     }
-    session->mutable_status_controller()->set_debug_info_sent();
   }
+
+  ProcessUpdatesCommand process_updates;
+  process_updates.Execute(session);
+
+  StoreTimestampsCommand store_timestamps;
+  store_timestamps.Execute(session);
+
+  return result;
 }
 
 }  // namespace syncer
diff --git a/sync/engine/download.h b/sync/engine/download.h
index 4ec4b5a..ddae79b 100644
--- a/sync/engine/download.h
+++ b/sync/engine/download.h
@@ -26,33 +26,37 @@
 // This function executes a single GetUpdate request and stores the response in
 // the session's StatusController.  It constructs the type of request used to
 // keep types in sync when in normal mode.
-SYNC_EXPORT_PRIVATE SyncerError NormalDownloadUpdates(
+SYNC_EXPORT_PRIVATE void BuildNormalDownloadUpdates(
     sessions::SyncSession* session,
     bool create_mobile_bookmarks_folder,
     ModelTypeSet request_types,
-    const sessions::NudgeTracker& nudge_tracker);
+    const sessions::NudgeTracker& nudge_tracker,
+    sync_pb::ClientToServerMessage* client_to_server_message);
 
 // This function executes a single GetUpdate request and stores the response in
 // the session's StatusController.  It constructs the type of request used to
 // initialize a type for the first time.
-SYNC_EXPORT_PRIVATE SyncerError DownloadUpdatesForConfigure(
+SYNC_EXPORT_PRIVATE void BuildDownloadUpdatesForConfigure(
     sessions::SyncSession* session,
     bool create_mobile_bookmarks_folder,
     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    ModelTypeSet request_types);
+    ModelTypeSet request_types,
+    sync_pb::ClientToServerMessage* client_to_server_message);
 
 // This function executes a single GetUpdate request and stores the response in
 // the session's status controller.  It constructs the type of request used for
 // periodic polling.
-SYNC_EXPORT_PRIVATE SyncerError DownloadUpdatesForPoll(
+SYNC_EXPORT_PRIVATE void BuildDownloadUpdatesForPoll(
     sessions::SyncSession* session,
     bool create_mobile_bookmarks_folder,
-    ModelTypeSet request_types);
+    ModelTypeSet request_types,
+    sync_pb::ClientToServerMessage* client_to_server_message);
 
-// A helper to set debug info.  Exposed only for testing.
-SYNC_EXPORT_PRIVATE void AppendClientDebugInfoIfNeeded(
-    sessions::SyncSession* session,
-    sync_pb::DebugInfo* debug_info);
+// 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,
+                           sync_pb::ClientToServerMessage* msg);
 
 }  // namespace syncer
 
diff --git a/sync/engine/download_unittest.cc b/sync/engine/download_unittest.cc
index 9990b7b..5ea5c14 100644
--- a/sync/engine/download_unittest.cc
+++ b/sync/engine/download_unittest.cc
@@ -8,8 +8,6 @@
 #include "sync/test/engine/fake_model_worker.h"
 #include "sync/test/engine/syncer_command_test.h"
 
-using ::testing::_;
-
 namespace syncer {
 
 // A test fixture for tests exercising download updates functions.
@@ -36,25 +34,48 @@
 };
 
 TEST_F(DownloadUpdatesTest, ExecuteNoStates) {
-  ConfigureMockServerConnection();
-
   sessions::NudgeTracker nudge_tracker;
   nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
 
-  mock_server()->ExpectGetUpdatesRequestTypes(
-      GetRoutingInfoTypes(routing_info()));
   scoped_ptr<sessions::SyncSession> session(
-      sessions::SyncSession::Build(context(),
-                                   delegate()));
-  NormalDownloadUpdates(session.get(),
-                        false,
-                        GetRoutingInfoTypes(routing_info()),
-                        nudge_tracker);
+      sessions::SyncSession::Build(context(), delegate()));
+  sync_pb::ClientToServerMessage msg;
+  BuildNormalDownloadUpdates(session.get(),
+                             false,
+                             GetRoutingInfoTypes(routing_info()),
+                             nudge_tracker,
+                             &msg);
+
+  const sync_pb::GetUpdatesMessage& gu_msg = msg.get_updates();
+  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
+            gu_msg.caller_info().source());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
+  for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
+    syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
+        gu_msg.from_progress_marker(i).data_type_id());
+    EXPECT_TRUE(GetRoutingInfoTypes(routing_info()).Has(type));
+
+    const sync_pb::DataTypeProgressMarker& progress_marker =
+        gu_msg.from_progress_marker(i);
+    const sync_pb::GetUpdateTriggers& gu_trigger =
+        progress_marker.get_update_triggers();
+
+    // We perform some basic tests of GU trigger and source fields here.  The
+    // more complicated scenarios are tested by the NudgeTracker tests.
+    if (type == BOOKMARKS) {
+      EXPECT_TRUE(progress_marker.has_notification_hint());
+      EXPECT_EQ("", progress_marker.notification_hint());
+      EXPECT_EQ(1, gu_trigger.local_modification_nudges());
+      EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
+    } else {
+      EXPECT_FALSE(progress_marker.has_notification_hint());
+      EXPECT_EQ(0, gu_trigger.local_modification_nudges());
+      EXPECT_EQ(0, gu_trigger.datatype_refresh_nudges());
+    }
+  }
 }
 
 TEST_F(DownloadUpdatesTest, ExecuteWithStates) {
-  ConfigureMockServerConnection();
-
   sessions::NudgeTracker nudge_tracker;
   nudge_tracker.RecordRemoteInvalidation(
       ModelTypeSetToInvalidationMap(ModelTypeSet(AUTOFILL),
@@ -65,40 +86,83 @@
   nudge_tracker.RecordRemoteInvalidation(
       ModelTypeSetToInvalidationMap(ModelTypeSet(PREFERENCES),
                                     "preferences_payload"));
+  ModelTypeSet notified_types;
+  notified_types.Put(AUTOFILL);
+  notified_types.Put(BOOKMARKS);
+  notified_types.Put(PREFERENCES);
 
-  ModelTypeInvalidationMap invalidation_map;
-  Invalidation i1;
-  i1.payload = "autofill_payload";
-  invalidation_map.insert(std::make_pair(AUTOFILL, i1));
-  Invalidation i2;
-  i2.payload = "bookmark_payload";
-  invalidation_map.insert(std::make_pair(BOOKMARKS, i2));
-  Invalidation i3;
-  i3.payload = "preferences_payload";
-  invalidation_map.insert(std::make_pair(PREFERENCES, i3));
-
-  mock_server()->ExpectGetUpdatesRequestTypes(
-      GetRoutingInfoTypes(routing_info()));
-  mock_server()->ExpectGetUpdatesRequestStates(
-      invalidation_map);
   scoped_ptr<sessions::SyncSession> session(
       sessions::SyncSession::Build(context(), delegate()));
-  NormalDownloadUpdates(session.get(),
-                        false,
-                        GetRoutingInfoTypes(routing_info()),
-                        nudge_tracker);
+  sync_pb::ClientToServerMessage msg;
+  BuildNormalDownloadUpdates(session.get(),
+                             false,
+                             GetRoutingInfoTypes(routing_info()),
+                             nudge_tracker,
+                             &msg);
+
+  const sync_pb::GetUpdatesMessage& gu_msg = msg.get_updates();
+  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
+            gu_msg.caller_info().source());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
+  for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
+    syncer::ModelType type = GetModelTypeFromSpecificsFieldNumber(
+        gu_msg.from_progress_marker(i).data_type_id());
+    EXPECT_TRUE(GetRoutingInfoTypes(routing_info()).Has(type));
+
+    const sync_pb::DataTypeProgressMarker& progress_marker =
+        gu_msg.from_progress_marker(i);
+    const sync_pb::GetUpdateTriggers& gu_trigger =
+        progress_marker.get_update_triggers();
+
+    // We perform some basic tests of GU trigger and source fields here.  The
+    // more complicated scenarios are tested by the NudgeTracker tests.
+    if (notified_types.Has(type)) {
+      EXPECT_TRUE(progress_marker.has_notification_hint());
+      EXPECT_FALSE(progress_marker.notification_hint().empty());
+      EXPECT_EQ(1, gu_trigger.notification_hint_size());
+    } else {
+      EXPECT_FALSE(progress_marker.has_notification_hint());
+      EXPECT_EQ(0, gu_trigger.notification_hint_size());
+    }
+  }
 }
 
+// Test that debug info is sent uploaded only once per sync session.
 TEST_F(DownloadUpdatesTest, VerifyAppendDebugInfo) {
-  sync_pb::DebugInfo debug_info;
-  EXPECT_CALL(*(mock_debug_info_getter()), GetAndClearDebugInfo(_))
-      .Times(1);
-  // The first of a set of repeated GUs will set it.
-  AppendClientDebugInfoIfNeeded(session(), &debug_info);
+  // Start by expecting that no events are uploaded.
+  sessions::NudgeTracker nudge_tracker;
+  nudge_tracker.RecordLocalChange(ModelTypeSet(BOOKMARKS));
 
-  // Subsequent GUs will not.
-  // Verify by checking that GetAndClearDebugInfo() is not called again.
-  AppendClientDebugInfoIfNeeded(session(), &debug_info);
+  sync_pb::ClientToServerMessage msg1;
+  scoped_ptr<sessions::SyncSession> session1(
+      sessions::SyncSession::Build(context(), delegate()));
+  BuildNormalDownloadUpdates(session1.get(),
+                             false,
+                             GetRoutingInfoTypes(routing_info()),
+                             nudge_tracker,
+                             &msg1);
+  EXPECT_EQ(0, msg1.debug_info().events_size());
+
+  // Create a new session, record an event, and try again.
+  scoped_ptr<sessions::SyncSession> session2(
+      sessions::SyncSession::Build(context(), delegate()));
+  debug_info_event_listener()->OnConfigureComplete();
+  sync_pb::ClientToServerMessage msg2;
+  BuildNormalDownloadUpdates(session2.get(),
+                             false,
+                             GetRoutingInfoTypes(routing_info()),
+                             nudge_tracker,
+                             &msg2);
+  EXPECT_EQ(1, msg2.debug_info().events_size());
+
+  // Events should never be sent up more than once per session.
+  sync_pb::ClientToServerMessage msg3;
+  BuildNormalDownloadUpdates(session2.get(),
+                             false,
+                             GetRoutingInfoTypes(routing_info()),
+                             nudge_tracker,
+                             &msg3);
+  EXPECT_EQ(0, msg3.debug_info().events_size());
 }
 
 }  // namespace syncer
diff --git a/sync/engine/net/server_connection_manager.cc b/sync/engine/net/server_connection_manager.cc
index a60e3a9..0076543 100644
--- a/sync/engine/net/server_connection_manager.cc
+++ b/sync/engine/net/server_connection_manager.cc
@@ -267,7 +267,11 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(watcher != NULL);
 
-  if (auth_token.empty()) {
+  // TODO(pavely): crbug.com/273096. Check for "credentials_lost" is added as
+  // workaround for M29 blocker to avoid sending RPC to sync with known invalid
+  // token but instead to trigger refreshing token in ProfileSyncService. Need
+  // to clean it.
+  if (auth_token.empty() || auth_token == "credentials_lost") {
     params->response.server_status = HttpResponse::SYNC_AUTH_ERROR;
     return false;
   }
diff --git a/sync/engine/syncer.cc b/sync/engine/syncer.cc
index 338c287..3d66ca3 100644
--- a/sync/engine/syncer.cc
+++ b/sync/engine/syncer.cc
@@ -68,12 +68,12 @@
       session->context()->ShouldFetchUpdatesBeforeCommit()) {
     if (!DownloadAndApplyUpdates(
             session,
-            base::Bind(&NormalDownloadUpdates,
+            base::Bind(&BuildNormalDownloadUpdates,
                        session,
                        kCreateMobileBookmarksFolder,
                        request_types,
                        base::ConstRef(nudge_tracker)))) {
-    return HandleCycleEnd(session, nudge_tracker.updates_source());
+      return HandleCycleEnd(session, nudge_tracker.updates_source());
     }
   }
 
@@ -92,7 +92,7 @@
   VLOG(1) << "Configuring types " << ModelTypeSetToString(request_types);
   DownloadAndApplyUpdates(
       session,
-      base::Bind(&DownloadUpdatesForConfigure,
+      base::Bind(&BuildDownloadUpdatesForConfigure,
                  session,
                  kCreateMobileBookmarksFolder,
                  source,
@@ -106,7 +106,7 @@
   VLOG(1) << "Polling types " << ModelTypeSetToString(request_types);
   DownloadAndApplyUpdates(
       session,
-      base::Bind(&DownloadUpdatesForPoll,
+      base::Bind(&BuildDownloadUpdatesForPoll,
                  session,
                  kCreateMobileBookmarksFolder,
                  request_types));
@@ -129,9 +129,12 @@
 
 bool Syncer::DownloadAndApplyUpdates(
     SyncSession* session,
-    base::Callback<SyncerError(void)> download_fn) {
+    base::Callback<void(sync_pb::ClientToServerMessage*)> build_fn) {
   while (!session->status_controller().ServerSaysNothingMoreToDownload()) {
-    SyncerError download_result = download_fn.Run();
+    TRACE_EVENT0("sync", "DownloadUpdates");
+    sync_pb::ClientToServerMessage msg;
+    build_fn.Run(&msg);
+    SyncerError download_result = ExecuteDownloadUpdates(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 8b5fc06..e1e5eac 100644
--- a/sync/engine/syncer.h
+++ b/sync/engine/syncer.h
@@ -72,7 +72,7 @@
   void ApplyUpdates(sessions::SyncSession* session);
   bool DownloadAndApplyUpdates(
       sessions::SyncSession* session,
-      base::Callback<SyncerError(void)> download_fn);
+      base::Callback<void(sync_pb::ClientToServerMessage*)> build_fn);
 
   void HandleCycleBegin(sessions::SyncSession* session);
   bool HandleCycleEnd(
diff --git a/sync/engine/syncer_proto_util.cc b/sync/engine/syncer_proto_util.cc
index 690a837..085bed4 100644
--- a/sync/engine/syncer_proto_util.cc
+++ b/sync/engine/syncer_proto_util.cc
@@ -199,6 +199,7 @@
   return sync_protocol_error;
 }
 
+// static
 bool SyncerProtoUtil::VerifyResponseBirthday(
     const ClientToServerResponse& response,
     syncable::Directory* dir) {
@@ -231,6 +232,13 @@
 }
 
 // static
+bool SyncerProtoUtil::IsSyncDisabledByAdmin(
+    const sync_pb::ClientToServerResponse& response) {
+  return (response.has_error_code() &&
+          response.error_code() == sync_pb::SyncEnums::DISABLED_BY_ADMIN);
+}
+
+// static
 void SyncerProtoUtil::AddRequestBirthday(syncable::Directory* dir,
                                          ClientToServerMessage* msg) {
   if (!dir->store_birthday().empty())
@@ -380,11 +388,14 @@
 
   SyncProtocolError sync_protocol_error;
 
-  // Birthday mismatch overrides any error that is sent by the server.
-  if (!VerifyResponseBirthday(*response, dir)) {
+  // The DISABLED_BY_ADMIN error overrides other errors sent by the server.
+  if (IsSyncDisabledByAdmin(*response)) {
+    sync_protocol_error.error_type = DISABLED_BY_ADMIN;
+    sync_protocol_error.action = STOP_SYNC_FOR_DISABLED_ACCOUNT;
+  } else if (!VerifyResponseBirthday(*response, dir)) {
+    // If sync isn't disabled, first check for a birthday mismatch error.
     sync_protocol_error.error_type = NOT_MY_BIRTHDAY;
-     sync_protocol_error.action =
-         DISABLE_SYNC_ON_CLIENT;
+    sync_protocol_error.action = DISABLE_SYNC_ON_CLIENT;
   } else if (response->has_error()) {
     // This is a new server. Just get the error from the protocol.
     sync_protocol_error = ConvertErrorPBToLocalType(response->error());
diff --git a/sync/engine/syncer_proto_util.h b/sync/engine/syncer_proto_util.h
index 4e627e0..d2468c0 100644
--- a/sync/engine/syncer_proto_util.h
+++ b/sync/engine/syncer_proto_util.h
@@ -129,6 +129,10 @@
       const sync_pb::ClientToServerResponse& response,
       syncable::Directory* dir);
 
+  // Returns true if sync is disabled by admin for a dasher account.
+  static bool IsSyncDisabledByAdmin(
+      const sync_pb::ClientToServerResponse& response);
+
   // Post the message using the scm, and do some processing on the returned
   // headers. Decode the server response.
   static bool PostAndProcessHeaders(ServerConnectionManager* scm,
@@ -142,6 +146,7 @@
   friend class SyncerProtoUtilTest;
   FRIEND_TEST_ALL_PREFIXES(SyncerProtoUtilTest, AddRequestBirthday);
   FRIEND_TEST_ALL_PREFIXES(SyncerProtoUtilTest, PostAndProcessHeaders);
+  FRIEND_TEST_ALL_PREFIXES(SyncerProtoUtilTest, VerifyDisabledByAdmin);
   FRIEND_TEST_ALL_PREFIXES(SyncerProtoUtilTest, VerifyResponseBirthday);
   FRIEND_TEST_ALL_PREFIXES(SyncerProtoUtilTest, HandleThrottlingNoDatatypes);
   FRIEND_TEST_ALL_PREFIXES(SyncerProtoUtilTest, HandleThrottlingWithDatatypes);
diff --git a/sync/engine/syncer_proto_util_unittest.cc b/sync/engine/syncer_proto_util_unittest.cc
index be49413..c288132 100644
--- a/sync/engine/syncer_proto_util_unittest.cc
+++ b/sync/engine/syncer_proto_util_unittest.cc
@@ -227,6 +227,20 @@
   EXPECT_FALSE(SyncerProtoUtil::VerifyResponseBirthday(response, directory()));
 }
 
+TEST_F(SyncerProtoUtilTest, VerifyDisabledByAdmin) {
+  // No error code
+  sync_pb::ClientToServerResponse response;
+  EXPECT_FALSE(SyncerProtoUtil::IsSyncDisabledByAdmin(response));
+
+  // Has error code, but not disabled
+  response.set_error_code(sync_pb::SyncEnums::NOT_MY_BIRTHDAY);
+  EXPECT_FALSE(SyncerProtoUtil::IsSyncDisabledByAdmin(response));
+
+  // Has error code, and is disabled by admin
+  response.set_error_code(sync_pb::SyncEnums::DISABLED_BY_ADMIN);
+  EXPECT_TRUE(SyncerProtoUtil::IsSyncDisabledByAdmin(response));
+}
+
 TEST_F(SyncerProtoUtilTest, AddRequestBirthday) {
   EXPECT_TRUE(directory()->store_birthday().empty());
   ClientToServerMessage msg;
diff --git a/sync/internal_api/public/engine/model_safe_worker.cc b/sync/internal_api/public/engine/model_safe_worker.cc
index 7179ed5..5c91715 100644
--- a/sync/internal_api/public/engine/model_safe_worker.cc
+++ b/sync/internal_api/public/engine/model_safe_worker.cc
@@ -134,11 +134,17 @@
         << " worker stops on destruction of its working thread.";
   }
 
+  {
+    base::AutoLock l(working_loop_lock_);
+    working_loop_ = NULL;
+  }
+
   if (observer_)
     observer_->OnWorkerLoopDestroyed(GetModelSafeGroup());
 }
 
 void ModelSafeWorker::SetWorkingLoopToCurrent() {
+  base::AutoLock l(working_loop_lock_);
   DCHECK(!working_loop_);
   working_loop_ = base::MessageLoop::current();
   working_loop_set_wait_.Signal();
@@ -150,19 +156,29 @@
   // loop.
   working_loop_set_wait_.Wait();
 
-  // Should be called on sync loop.
-  DCHECK_NE(base::MessageLoop::current(), working_loop_);
-  DCHECK(working_loop_);
-  working_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync,
-                 this, unregister_done_callback));
+  {
+    base::AutoLock l(working_loop_lock_);
+    if (working_loop_ != NULL) {
+      // Should be called on sync loop.
+      DCHECK_NE(base::MessageLoop::current(), working_loop_);
+      working_loop_->PostTask(
+          FROM_HERE,
+          base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync,
+                     this, unregister_done_callback));
+    }
+  }
 }
 
 void ModelSafeWorker::UnregisterForLoopDestructionAsync(
     base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
+  {
+    base::AutoLock l(working_loop_lock_);
+    if (!working_loop_)
+      return;
+    DCHECK_EQ(base::MessageLoop::current(), working_loop_);
+  }
+
   DCHECK(stopped_);
-  DCHECK_EQ(base::MessageLoop::current(), working_loop_);
   base::MessageLoop::current()->RemoveDestructionObserver(this);
   unregister_done_callback.Run(GetModelSafeGroup());
 }
diff --git a/sync/internal_api/public/engine/model_safe_worker.h b/sync/internal_api/public/engine/model_safe_worker.h
index f6b7ea6..0f41594 100644
--- a/sync/internal_api/public/engine/model_safe_worker.h
+++ b/sync/internal_api/public/engine/model_safe_worker.h
@@ -132,6 +132,7 @@
 
   // Remember working loop for posting task to unregister destruction
   // observation from sync thread when shutting down sync.
+  base::Lock working_loop_lock_;
   base::MessageLoop* working_loop_;
   base::WaitableEvent working_loop_set_wait_;
 };
diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc
index 21db7b2..f4fe44d 100644
--- a/sync/protocol/proto_value_conversions.cc
+++ b/sync/protocol/proto_value_conversions.cc
@@ -462,6 +462,7 @@
   SET_STR(id);
   SET_STR(name);
   SET_BOOL(acknowledged);
+  SET_STR(master_key);
   return value;
 }
 
@@ -549,6 +550,7 @@
   SET_STR(suggestions_url_post_params);
   SET_STR(instant_url_post_params);
   SET_STR(image_url_post_params);
+  SET_STR(new_tab_url);
   return value;
 }
 
diff --git a/sync/protocol/search_engine_specifics.proto b/sync/protocol/search_engine_specifics.proto
index 26c5bec..8db631c 100644
--- a/sync/protocol/search_engine_specifics.proto
+++ b/sync/protocol/search_engine_specifics.proto
@@ -75,5 +75,8 @@
   optional string suggestions_url_post_params = 23;
   optional string instant_url_post_params = 24;
   optional string image_url_post_params = 25;
+
+  // The parameterized URL for a search provider specified new tab page.
+  optional string new_tab_url = 26;
 }
 
diff --git a/sync/syncable/syncable_util.cc b/sync/syncable/syncable_util.cc
index c08f218..e57071b 100644
--- a/sync/syncable/syncable_util.cc
+++ b/sync/syncable/syncable_util.cc
@@ -106,8 +106,8 @@
 }
 
 std::string GenerateSyncableBookmarkHash(
-    const std::string originator_cache_guid,
-    const std::string originator_client_item_id) {
+    const std::string& originator_cache_guid,
+    const std::string& originator_client_item_id) {
   return syncable::GenerateSyncableHash(
       BOOKMARKS, originator_cache_guid + originator_client_item_id);
 }
diff --git a/sync/syncable/syncable_util.h b/sync/syncable/syncable_util.h
index 465324d..f7d351e 100644
--- a/sync/syncable/syncable_util.h
+++ b/sync/syncable/syncable_util.h
@@ -48,8 +48,8 @@
 // than one place, so we define the algorithm here to make sure the
 // implementation is consistent.
 SYNC_EXPORT_PRIVATE std::string GenerateSyncableBookmarkHash(
-    const std::string originator_cache_guid,
-    const std::string originator_client_item_id);
+    const std::string& originator_cache_guid,
+    const std::string& originator_client_item_id);
 
 }  // namespace syncable
 }  // namespace syncer
diff --git a/sync/test/android/javatests/src/org/chromium/sync/test/util/AccountHolder.java b/sync/test/android/javatests/src/org/chromium/sync/test/util/AccountHolder.java
index cff504c..c22ba42 100644
--- a/sync/test/android/javatests/src/org/chromium/sync/test/util/AccountHolder.java
+++ b/sync/test/android/javatests/src/org/chromium/sync/test/util/AccountHolder.java
@@ -4,8 +4,6 @@
 
 package org.chromium.sync.test.util;
 
-import com.google.common.collect.ImmutableMap;
-
 import android.accounts.Account;
 
 import java.util.HashMap;
@@ -56,10 +54,6 @@
         return mAuthTokens.get(authTokenType);
     }
 
-    public ImmutableMap<String, String> getAuthTokens() {
-        return ImmutableMap.copyOf(mAuthTokens);
-    }
-
     public boolean hasBeenAccepted(String authTokenType) {
         return mAlwaysAccept ||
                 mHasBeenAccepted.containsKey(authTokenType) && mHasBeenAccepted.get(authTokenType);
diff --git a/sync/test/engine/mock_connection_manager.cc b/sync/test/engine/mock_connection_manager.cc
index 65998e9..5bf2b4b 100644
--- a/sync/test/engine/mock_connection_manager.cc
+++ b/sync/test/engine/mock_connection_manager.cc
@@ -502,12 +502,6 @@
         GetProgressMarkerForType(gu.from_progress_marker(), model_type);
     EXPECT_EQ(expected_filter_.Has(model_type), (progress_marker != NULL))
         << "Syncer requested_types differs from test expectation.";
-    if (progress_marker) {
-      EXPECT_EQ((expected_states_.count(model_type) > 0 ?
-                 expected_states_[model_type].payload :
-                 std::string()),
-                progress_marker->notification_hint());
-    }
   }
 
   // Verify that the items we're about to send back to the client are of
diff --git a/sync/test/engine/mock_connection_manager.h b/sync/test/engine/mock_connection_manager.h
index 9f7cdb1..bab81ae 100644
--- a/sync/test/engine/mock_connection_manager.h
+++ b/sync/test/engine/mock_connection_manager.h
@@ -234,10 +234,6 @@
     expected_filter_ = expected_filter;
   }
 
-  void ExpectGetUpdatesRequestStates(const ModelTypeInvalidationMap& states) {
-    expected_states_ = states;
-  }
-
   void SetServerReachable();
 
   void SetServerNotReachable();
@@ -394,8 +390,6 @@
 
   ModelTypeSet expected_filter_;
 
-  ModelTypeInvalidationMap expected_states_;
-
   int num_get_updates_requests_;
 
   std::string next_token_;
diff --git a/sync/test/engine/syncer_command_test.cc b/sync/test/engine/syncer_command_test.cc
index 68edbbd..3baf2d1 100644
--- a/sync/test/engine/syncer_command_test.cc
+++ b/sync/test/engine/syncer_command_test.cc
@@ -9,6 +9,49 @@
 const unsigned int kMaxMessages = 10;
 const unsigned int kMaxMessageSize = 5 * 1024;
 
+void SyncerCommandTestBase::OnThrottled(
+    const base::TimeDelta& throttle_duration) {
+  FAIL() << "Should not get silenced.";
+}
+
+void SyncerCommandTestBase::OnTypesThrottled(
+    ModelTypeSet types,
+    const base::TimeDelta& throttle_duration) {
+  FAIL() << "Should not get silenced.";
+}
+
+bool SyncerCommandTestBase::IsCurrentlyThrottled() {
+  return false;
+}
+
+void SyncerCommandTestBase::OnReceivedLongPollIntervalUpdate(
+    const base::TimeDelta& new_interval) {
+  FAIL() << "Should not get poll interval update.";
+}
+
+void SyncerCommandTestBase::OnReceivedShortPollIntervalUpdate(
+    const base::TimeDelta& new_interval) {
+  FAIL() << "Should not get poll interval update.";
+}
+
+void SyncerCommandTestBase::OnReceivedSessionsCommitDelay(
+    const base::TimeDelta& new_delay) {
+  FAIL() << "Should not get sessions commit delay.";
+}
+
+void SyncerCommandTestBase::OnReceivedClientInvalidationHintBufferSize(
+    int size) {
+  FAIL() << "Should not get hint buffer size.";
+}
+
+void SyncerCommandTestBase::OnShouldStopSyncingPermanently() {
+  FAIL() << "Shouldn't be called.";
+}
+
+void SyncerCommandTestBase::OnSyncProtocolError(
+    const sessions::SyncSessionSnapshot& session) {
+  return;
+}
 SyncerCommandTestBase::SyncerCommandTestBase()
     : traffic_recorder_(kMaxMessages, kMaxMessageSize) {
 }
@@ -41,10 +84,4 @@
   dir_maker_.TearDown();
 }
 
-MockDebugInfoGetter::MockDebugInfoGetter() {
-}
-
-MockDebugInfoGetter::~MockDebugInfoGetter() {
-}
-
 }  // namespace syncer
diff --git a/sync/test/engine/syncer_command_test.h b/sync/test/engine/syncer_command_test.h
index f0904cc..6e1f672 100644
--- a/sync/test/engine/syncer_command_test.h
+++ b/sync/test/engine/syncer_command_test.h
@@ -14,6 +14,7 @@
 #include "base/message_loop/message_loop.h"
 #include "sync/engine/model_changing_syncer_command.h"
 #include "sync/engine/traffic_recorder.h"
+#include "sync/internal_api/debug_info_event_listener.h"
 #include "sync/internal_api/public/engine/model_safe_worker.h"
 #include "sync/sessions/debug_info_getter.h"
 #include "sync/sessions/sync_session.h"
@@ -26,17 +27,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using ::testing::NiceMock;
-
 namespace syncer {
 
-class MockDebugInfoGetter : public sessions::DebugInfoGetter {
- public:
-  MockDebugInfoGetter();
-  virtual ~MockDebugInfoGetter();
-  MOCK_METHOD1(GetAndClearDebugInfo, void(sync_pb::DebugInfo* debug_info));
-};
-
 // A test fixture that simplifies writing unit tests for individual
 // SyncerCommands, providing convenient access to a test directory
 // and a syncer session.
@@ -45,39 +37,21 @@
  public:
   // SyncSession::Delegate implementation.
   virtual void OnThrottled(
-      const base::TimeDelta& throttle_duration) OVERRIDE {
-    FAIL() << "Should not get silenced.";
-  }
+      const base::TimeDelta& throttle_duration) OVERRIDE;
   virtual void OnTypesThrottled(
       ModelTypeSet types,
-      const base::TimeDelta& throttle_duration) OVERRIDE {
-    FAIL() << "Should not get silenced.";
-  }
-  virtual bool IsCurrentlyThrottled() OVERRIDE {
-    return false;
-  }
+      const base::TimeDelta& throttle_duration) OVERRIDE;
+  virtual bool IsCurrentlyThrottled() OVERRIDE;
   virtual void OnReceivedLongPollIntervalUpdate(
-      const base::TimeDelta& new_interval) OVERRIDE {
-    FAIL() << "Should not get poll interval update.";
-  }
+      const base::TimeDelta& new_interval) OVERRIDE;
   virtual void OnReceivedShortPollIntervalUpdate(
-      const base::TimeDelta& new_interval) OVERRIDE {
-    FAIL() << "Should not get poll interval update.";
-  }
+      const base::TimeDelta& new_interval) OVERRIDE;
   virtual void OnReceivedSessionsCommitDelay(
-      const base::TimeDelta& new_delay) OVERRIDE {
-    FAIL() << "Should not get sessions commit delay.";
-  }
-  virtual void OnReceivedClientInvalidationHintBufferSize(int size) OVERRIDE {
-    FAIL() << "Should not get hint buffer size.";
-  }
-  virtual void OnShouldStopSyncingPermanently() OVERRIDE {
-    FAIL() << "Shouldn't be called.";
-  }
+      const base::TimeDelta& new_delay) OVERRIDE;
+  virtual void OnReceivedClientInvalidationHintBufferSize(int size) OVERRIDE;
+  virtual void OnShouldStopSyncingPermanently() OVERRIDE;
   virtual void OnSyncProtocolError(
-      const sessions::SyncSessionSnapshot& session) OVERRIDE {
-    return;
-  }
+      const sessions::SyncSessionSnapshot& session) OVERRIDE;
 
   std::vector<ModelSafeWorker*> GetWorkers() {
     std::vector<ModelSafeWorker*> workers;
@@ -117,7 +91,7 @@
             mock_server_.get(), directory(),
             GetWorkers(), extensions_activity_.get(),
             std::vector<SyncEngineEventListener*>(),
-            &mock_debug_info_getter_,
+            &debug_info_event_listener_,
             &traffic_recorder_,
             true,  // enable keystore encryption
             false,  // force enable pre-commit GU avoidance experiment
@@ -147,10 +121,9 @@
     return mock_server_.get();
   }
 
-  MockDebugInfoGetter* mock_debug_info_getter() {
-    return &mock_debug_info_getter_;
+  DebugInfoEventListener* debug_info_event_listener() {
+    return &debug_info_event_listener_;
   }
-
   // Helper functions to check command.GetGroupsToChange().
 
   void ExpectNoGroupsToChange(const ModelChangingSyncerCommand& command) {
@@ -193,7 +166,7 @@
   scoped_ptr<sessions::SyncSession> session_;
   std::vector<scoped_refptr<ModelSafeWorker> > workers_;
   ModelSafeRoutingInfo routing_info_;
-  NiceMock<MockDebugInfoGetter> mock_debug_info_getter_;
+  DebugInfoEventListener debug_info_event_listener_;
   scoped_refptr<ExtensionsActivity> extensions_activity_;
   TrafficRecorder traffic_recorder_;
   DISALLOW_COPY_AND_ASSIGN(SyncerCommandTestBase);
diff --git a/sync/util/nigori.cc b/sync/util/nigori.cc
index 5f8298a..b0158f3 100644
--- a/sync/util/nigori.cc
+++ b/sync/util/nigori.cc
@@ -227,7 +227,6 @@
   if (!encryptor.Init(encryption_key_.get(), Encryptor::CBC, iv))
     return false;
 
-  std::string plaintext;
   if (!encryptor.Decrypt(ciphertext, value))
     return false;
 
diff --git a/testing/android/native_test_launcher.cc b/testing/android/native_test_launcher.cc
index e39eb2b..300efc9 100644
--- a/testing/android/native_test_launcher.cc
+++ b/testing/android/native_test_launcher.cc
@@ -115,8 +115,6 @@
 
 }  // namespace
 
-// This method is called on a separate java thread so that we won't trigger
-// an ANR.
 static void RunTests(JNIEnv* env,
                      jobject obj,
                      jstring jfiles_dir,
diff --git a/third_party/cacheinvalidation/cacheinvalidation.gyp b/third_party/cacheinvalidation/cacheinvalidation.gyp
index 8566506..bd8586f 100644
--- a/third_party/cacheinvalidation/cacheinvalidation.gyp
+++ b/third_party/cacheinvalidation/cacheinvalidation.gyp
@@ -89,6 +89,7 @@
         'src/google/cacheinvalidation/impl/recurring-task.h',
         'src/google/cacheinvalidation/impl/registration-manager.cc',
         'src/google/cacheinvalidation/impl/registration-manager.h',
+        'src/google/cacheinvalidation/impl/repeated-field-namespace-fix.h',
         'src/google/cacheinvalidation/impl/run-state.h',
         'src/google/cacheinvalidation/impl/safe-storage.cc',
         'src/google/cacheinvalidation/impl/safe-storage.h',
diff --git a/third_party/flot/LICENSE.txt b/third_party/flot/LICENSE.txt
index 07d5b20..67f4625 100644
--- a/third_party/flot/LICENSE.txt
+++ b/third_party/flot/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2007-2009 IOLA and Ole Laursen
+Copyright (c) 2007-2013 IOLA and Ole Laursen
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
diff --git a/third_party/flot/README.chromium b/third_party/flot/README.chromium
index acee5bc..ff39b4b 100644
--- a/third_party/flot/README.chromium
+++ b/third_party/flot/README.chromium
@@ -1,9 +1,9 @@
 Name: Flot Javascript/JQuery library for creating graphs
 Short Name: Flot
 URL: code.google.com/p/flot and http://drupal.org/project/flot
-Version: 0.7
+Version: 0.8.1
 License: MIT
 License File: LICENSE.txt
 Security Critical: yes
-Description: Flot is used in the webui for performance monitor to draw charts of performance metrics.
+Description: Flot is used in the webui for performance monitor and the visualizer for Deep Memory Profiler to draw charts of performance metrics.
 Local Modifications: none
diff --git a/third_party/flot/excanvas.min.js b/third_party/flot/excanvas.min.js
new file mode 100644
index 0000000..fcf876c
--- /dev/null
+++ b/third_party/flot/excanvas.min.js
@@ -0,0 +1 @@
+if(!document.createElement("canvas").getContext){(function(){var ab=Math;var n=ab.round;var l=ab.sin;var A=ab.cos;var H=ab.abs;var N=ab.sqrt;var d=10;var f=d/2;var z=+navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];function y(){return this.context_||(this.context_=new D(this))}var t=Array.prototype.slice;function g(j,m,p){var i=t.call(arguments,2);return function(){return j.apply(m,i.concat(t.call(arguments)))}}function af(i){return String(i).replace(/&/g,"&amp;").replace(/"/g,"&quot;")}function Y(m,j,i){if(!m.namespaces[j]){m.namespaces.add(j,i,"#default#VML")}}function R(j){Y(j,"g_vml_","urn:schemas-microsoft-com:vml");Y(j,"g_o_","urn:schemas-microsoft-com:office:office");if(!j.styleSheets.ex_canvas_){var i=j.createStyleSheet();i.owningElement.id="ex_canvas_";i.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}R(document);var e={init:function(i){var j=i||document;j.createElement("canvas");j.attachEvent("onreadystatechange",g(this.init_,this,j))},init_:function(p){var m=p.getElementsByTagName("canvas");for(var j=0;j<m.length;j++){this.initElement(m[j])}},initElement:function(j){if(!j.getContext){j.getContext=y;R(j.ownerDocument);j.innerHTML="";j.attachEvent("onpropertychange",x);j.attachEvent("onresize",W);var i=j.attributes;if(i.width&&i.width.specified){j.style.width=i.width.nodeValue+"px"}else{j.width=j.clientWidth}if(i.height&&i.height.specified){j.style.height=i.height.nodeValue+"px"}else{j.height=j.clientHeight}}return j}};function x(j){var i=j.srcElement;switch(j.propertyName){case"width":i.getContext().clearRect();i.style.width=i.attributes.width.nodeValue+"px";i.firstChild.style.width=i.clientWidth+"px";break;case"height":i.getContext().clearRect();i.style.height=i.attributes.height.nodeValue+"px";i.firstChild.style.height=i.clientHeight+"px";break}}function W(j){var i=j.srcElement;if(i.firstChild){i.firstChild.style.width=i.clientWidth+"px";i.firstChild.style.height=i.clientHeight+"px"}}e.init();var k=[];for(var ae=0;ae<16;ae++){for(var ad=0;ad<16;ad++){k[ae*16+ad]=ae.toString(16)+ad.toString(16)}}function B(){return[[1,0,0],[0,1,0],[0,0,1]]}function J(p,m){var j=B();for(var i=0;i<3;i++){for(var ah=0;ah<3;ah++){var Z=0;for(var ag=0;ag<3;ag++){Z+=p[i][ag]*m[ag][ah]}j[i][ah]=Z}}return j}function v(j,i){i.fillStyle=j.fillStyle;i.lineCap=j.lineCap;i.lineJoin=j.lineJoin;i.lineWidth=j.lineWidth;i.miterLimit=j.miterLimit;i.shadowBlur=j.shadowBlur;i.shadowColor=j.shadowColor;i.shadowOffsetX=j.shadowOffsetX;i.shadowOffsetY=j.shadowOffsetY;i.strokeStyle=j.strokeStyle;i.globalAlpha=j.globalAlpha;i.font=j.font;i.textAlign=j.textAlign;i.textBaseline=j.textBaseline;i.arcScaleX_=j.arcScaleX_;i.arcScaleY_=j.arcScaleY_;i.lineScale_=j.lineScale_}var b={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",greenyellow:"#ADFF2F",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"};function M(j){var p=j.indexOf("(",3);var i=j.indexOf(")",p+1);var m=j.substring(p+1,i).split(",");if(m.length!=4||j.charAt(3)!="a"){m[3]=1}return m}function c(i){return parseFloat(i)/100}function r(j,m,i){return Math.min(i,Math.max(m,j))}function I(ag){var i,ai,aj,ah,ak,Z;ah=parseFloat(ag[0])/360%360;if(ah<0){ah++}ak=r(c(ag[1]),0,1);Z=r(c(ag[2]),0,1);if(ak==0){i=ai=aj=Z}else{var j=Z<0.5?Z*(1+ak):Z+ak-Z*ak;var m=2*Z-j;i=a(m,j,ah+1/3);ai=a(m,j,ah);aj=a(m,j,ah-1/3)}return"#"+k[Math.floor(i*255)]+k[Math.floor(ai*255)]+k[Math.floor(aj*255)]}function a(j,i,m){if(m<0){m++}if(m>1){m--}if(6*m<1){return j+(i-j)*6*m}else{if(2*m<1){return i}else{if(3*m<2){return j+(i-j)*(2/3-m)*6}else{return j}}}}var C={};function F(j){if(j in C){return C[j]}var ag,Z=1;j=String(j);if(j.charAt(0)=="#"){ag=j}else{if(/^rgb/.test(j)){var p=M(j);var ag="#",ah;for(var m=0;m<3;m++){if(p[m].indexOf("%")!=-1){ah=Math.floor(c(p[m])*255)}else{ah=+p[m]}ag+=k[r(ah,0,255)]}Z=+p[3]}else{if(/^hsl/.test(j)){var p=M(j);ag=I(p);Z=p[3]}else{ag=b[j]||j}}}return C[j]={color:ag,alpha:Z}}var o={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"};var L={};function E(i){if(L[i]){return L[i]}var p=document.createElement("div");var m=p.style;try{m.font=i}catch(j){}return L[i]={style:m.fontStyle||o.style,variant:m.fontVariant||o.variant,weight:m.fontWeight||o.weight,size:m.fontSize||o.size,family:m.fontFamily||o.family}}function u(m,j){var i={};for(var ah in m){i[ah]=m[ah]}var ag=parseFloat(j.currentStyle.fontSize),Z=parseFloat(m.size);if(typeof m.size=="number"){i.size=m.size}else{if(m.size.indexOf("px")!=-1){i.size=Z}else{if(m.size.indexOf("em")!=-1){i.size=ag*Z}else{if(m.size.indexOf("%")!=-1){i.size=(ag/100)*Z}else{if(m.size.indexOf("pt")!=-1){i.size=Z/0.75}else{i.size=ag}}}}}i.size*=0.981;return i}function ac(i){return i.style+" "+i.variant+" "+i.weight+" "+i.size+"px "+i.family}var s={butt:"flat",round:"round"};function S(i){return s[i]||"square"}function D(i){this.m_=B();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=d*1;this.globalAlpha=1;this.font="10px sans-serif";this.textAlign="left";this.textBaseline="alphabetic";this.canvas=i;var m="width:"+i.clientWidth+"px;height:"+i.clientHeight+"px;overflow:hidden;position:absolute";var j=i.ownerDocument.createElement("div");j.style.cssText=m;i.appendChild(j);var p=j.cloneNode(false);p.style.backgroundColor="red";p.style.filter="alpha(opacity=0)";i.appendChild(p);this.element_=j;this.arcScaleX_=1;this.arcScaleY_=1;this.lineScale_=1}var q=D.prototype;q.clearRect=function(){if(this.textMeasureEl_){this.textMeasureEl_.removeNode(true);this.textMeasureEl_=null}this.element_.innerHTML=""};q.beginPath=function(){this.currentPath_=[]};q.moveTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"moveTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.lineTo=function(j,i){var m=V(this,j,i);this.currentPath_.push({type:"lineTo",x:m.x,y:m.y});this.currentX_=m.x;this.currentY_=m.y};q.bezierCurveTo=function(m,j,ak,aj,ai,ag){var i=V(this,ai,ag);var ah=V(this,m,j);var Z=V(this,ak,aj);K(this,ah,Z,i)};function K(i,Z,m,j){i.currentPath_.push({type:"bezierCurveTo",cp1x:Z.x,cp1y:Z.y,cp2x:m.x,cp2y:m.y,x:j.x,y:j.y});i.currentX_=j.x;i.currentY_=j.y}q.quadraticCurveTo=function(ai,m,j,i){var ah=V(this,ai,m);var ag=V(this,j,i);var aj={x:this.currentX_+2/3*(ah.x-this.currentX_),y:this.currentY_+2/3*(ah.y-this.currentY_)};var Z={x:aj.x+(ag.x-this.currentX_)/3,y:aj.y+(ag.y-this.currentY_)/3};K(this,aj,Z,ag)};q.arc=function(al,aj,ak,ag,j,m){ak*=d;var ap=m?"at":"wa";var am=al+A(ag)*ak-f;var ao=aj+l(ag)*ak-f;var i=al+A(j)*ak-f;var an=aj+l(j)*ak-f;if(am==i&&!m){am+=0.125}var Z=V(this,al,aj);var ai=V(this,am,ao);var ah=V(this,i,an);this.currentPath_.push({type:ap,x:Z.x,y:Z.y,radius:ak,xStart:ai.x,yStart:ai.y,xEnd:ah.x,yEnd:ah.y})};q.rect=function(m,j,i,p){this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath()};q.strokeRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.stroke();this.currentPath_=Z};q.fillRect=function(m,j,i,p){var Z=this.currentPath_;this.beginPath();this.moveTo(m,j);this.lineTo(m+i,j);this.lineTo(m+i,j+p);this.lineTo(m,j+p);this.closePath();this.fill();this.currentPath_=Z};q.createLinearGradient=function(j,p,i,m){var Z=new U("gradient");Z.x0_=j;Z.y0_=p;Z.x1_=i;Z.y1_=m;return Z};q.createRadialGradient=function(p,ag,m,j,Z,i){var ah=new U("gradientradial");ah.x0_=p;ah.y0_=ag;ah.r0_=m;ah.x1_=j;ah.y1_=Z;ah.r1_=i;return ah};q.drawImage=function(aq,m){var aj,ah,al,ay,ao,am,at,aA;var ak=aq.runtimeStyle.width;var ap=aq.runtimeStyle.height;aq.runtimeStyle.width="auto";aq.runtimeStyle.height="auto";var ai=aq.width;var aw=aq.height;aq.runtimeStyle.width=ak;aq.runtimeStyle.height=ap;if(arguments.length==3){aj=arguments[1];ah=arguments[2];ao=am=0;at=al=ai;aA=ay=aw}else{if(arguments.length==5){aj=arguments[1];ah=arguments[2];al=arguments[3];ay=arguments[4];ao=am=0;at=ai;aA=aw}else{if(arguments.length==9){ao=arguments[1];am=arguments[2];at=arguments[3];aA=arguments[4];aj=arguments[5];ah=arguments[6];al=arguments[7];ay=arguments[8]}else{throw Error("Invalid number of arguments")}}}var az=V(this,aj,ah);var p=at/2;var j=aA/2;var ax=[];var i=10;var ag=10;ax.push(" <g_vml_:group",' coordsize="',d*i,",",d*ag,'"',' coordorigin="0,0"',' style="width:',i,"px;height:",ag,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]||this.m_[1][1]!=1||this.m_[1][0]){var Z=[];Z.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",n(az.x/d),",","Dy=",n(az.y/d),"");var av=az;var au=V(this,aj+al,ah);var ar=V(this,aj,ah+ay);var an=V(this,aj+al,ah+ay);av.x=ab.max(av.x,au.x,ar.x,an.x);av.y=ab.max(av.y,au.y,ar.y,an.y);ax.push("padding:0 ",n(av.x/d),"px ",n(av.y/d),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",Z.join(""),", sizingmethod='clip');")}else{ax.push("top:",n(az.y/d),"px;left:",n(az.x/d),"px;")}ax.push(' ">','<g_vml_:image src="',aq.src,'"',' style="width:',d*al,"px;"," height:",d*ay,'px"',' cropleft="',ao/ai,'"',' croptop="',am/aw,'"',' cropright="',(ai-ao-at)/ai,'"',' cropbottom="',(aw-am-aA)/aw,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",ax.join(""))};q.stroke=function(ao){var Z=10;var ap=10;var ag=5000;var ai={x:null,y:null};var an={x:null,y:null};for(var aj=0;aj<this.currentPath_.length;aj+=ag){var am=[];var ah=false;am.push("<g_vml_:shape",' filled="',!!ao,'"',' style="position:absolute;width:',Z,"px;height:",ap,'px;"',' coordorigin="0,0"',' coordsize="',d*Z,",",d*ap,'"',' stroked="',!ao,'"',' path="');var aq=false;for(var ak=aj;ak<Math.min(aj+ag,this.currentPath_.length);ak++){if(ak%ag==0&&ak>0){am.push(" m ",n(this.currentPath_[ak-1].x),",",n(this.currentPath_[ak-1].y))}var m=this.currentPath_[ak];var al;switch(m.type){case"moveTo":al=m;am.push(" m ",n(m.x),",",n(m.y));break;case"lineTo":am.push(" l ",n(m.x),",",n(m.y));break;case"close":am.push(" x ");m=null;break;case"bezierCurveTo":am.push(" c ",n(m.cp1x),",",n(m.cp1y),",",n(m.cp2x),",",n(m.cp2y),",",n(m.x),",",n(m.y));break;case"at":case"wa":am.push(" ",m.type," ",n(m.x-this.arcScaleX_*m.radius),",",n(m.y-this.arcScaleY_*m.radius)," ",n(m.x+this.arcScaleX_*m.radius),",",n(m.y+this.arcScaleY_*m.radius)," ",n(m.xStart),",",n(m.yStart)," ",n(m.xEnd),",",n(m.yEnd));break}if(m){if(ai.x==null||m.x<ai.x){ai.x=m.x}if(an.x==null||m.x>an.x){an.x=m.x}if(ai.y==null||m.y<ai.y){ai.y=m.y}if(an.y==null||m.y>an.y){an.y=m.y}}}am.push(' ">');if(!ao){w(this,am)}else{G(this,am,ai,an)}am.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",am.join(""))}};function w(m,ag){var j=F(m.strokeStyle);var p=j.color;var Z=j.alpha*m.globalAlpha;var i=m.lineScale_*m.lineWidth;if(i<1){Z*=i}ag.push("<g_vml_:stroke",' opacity="',Z,'"',' joinstyle="',m.lineJoin,'"',' miterlimit="',m.miterLimit,'"',' endcap="',S(m.lineCap),'"',' weight="',i,'px"',' color="',p,'" />')}function G(aq,ai,aK,ar){var aj=aq.fillStyle;var aB=aq.arcScaleX_;var aA=aq.arcScaleY_;var j=ar.x-aK.x;var p=ar.y-aK.y;if(aj instanceof U){var an=0;var aF={x:0,y:0};var ax=0;var am=1;if(aj.type_=="gradient"){var al=aj.x0_/aB;var m=aj.y0_/aA;var ak=aj.x1_/aB;var aM=aj.y1_/aA;var aJ=V(aq,al,m);var aI=V(aq,ak,aM);var ag=aI.x-aJ.x;var Z=aI.y-aJ.y;an=Math.atan2(ag,Z)*180/Math.PI;if(an<0){an+=360}if(an<0.000001){an=0}}else{var aJ=V(aq,aj.x0_,aj.y0_);aF={x:(aJ.x-aK.x)/j,y:(aJ.y-aK.y)/p};j/=aB*d;p/=aA*d;var aD=ab.max(j,p);ax=2*aj.r0_/aD;am=2*aj.r1_/aD-ax}var av=aj.colors_;av.sort(function(aN,i){return aN.offset-i.offset});var ap=av.length;var au=av[0].color;var at=av[ap-1].color;var az=av[0].alpha*aq.globalAlpha;var ay=av[ap-1].alpha*aq.globalAlpha;var aE=[];for(var aH=0;aH<ap;aH++){var ao=av[aH];aE.push(ao.offset*am+ax+" "+ao.color)}ai.push('<g_vml_:fill type="',aj.type_,'"',' method="none" focus="100%"',' color="',au,'"',' color2="',at,'"',' colors="',aE.join(","),'"',' opacity="',ay,'"',' g_o_:opacity2="',az,'"',' angle="',an,'"',' focusposition="',aF.x,",",aF.y,'" />')}else{if(aj instanceof T){if(j&&p){var ah=-aK.x;var aC=-aK.y;ai.push("<g_vml_:fill",' position="',ah/j*aB*aB,",",aC/p*aA*aA,'"',' type="tile"',' src="',aj.src_,'" />')}}else{var aL=F(aq.fillStyle);var aw=aL.color;var aG=aL.alpha*aq.globalAlpha;ai.push('<g_vml_:fill color="',aw,'" opacity="',aG,'" />')}}}q.fill=function(){this.stroke(true)};q.closePath=function(){this.currentPath_.push({type:"close"})};function V(j,Z,p){var i=j.m_;return{x:d*(Z*i[0][0]+p*i[1][0]+i[2][0])-f,y:d*(Z*i[0][1]+p*i[1][1]+i[2][1])-f}}q.save=function(){var i={};v(this,i);this.aStack_.push(i);this.mStack_.push(this.m_);this.m_=J(B(),this.m_)};q.restore=function(){if(this.aStack_.length){v(this.aStack_.pop(),this);this.m_=this.mStack_.pop()}};function h(i){return isFinite(i[0][0])&&isFinite(i[0][1])&&isFinite(i[1][0])&&isFinite(i[1][1])&&isFinite(i[2][0])&&isFinite(i[2][1])}function aa(j,i,p){if(!h(i)){return}j.m_=i;if(p){var Z=i[0][0]*i[1][1]-i[0][1]*i[1][0];j.lineScale_=N(H(Z))}}q.translate=function(m,j){var i=[[1,0,0],[0,1,0],[m,j,1]];aa(this,J(i,this.m_),false)};q.rotate=function(j){var p=A(j);var m=l(j);var i=[[p,m,0],[-m,p,0],[0,0,1]];aa(this,J(i,this.m_),false)};q.scale=function(m,j){this.arcScaleX_*=m;this.arcScaleY_*=j;var i=[[m,0,0],[0,j,0],[0,0,1]];aa(this,J(i,this.m_),true)};q.transform=function(Z,p,ah,ag,j,i){var m=[[Z,p,0],[ah,ag,0],[j,i,1]];aa(this,J(m,this.m_),true)};q.setTransform=function(ag,Z,ai,ah,p,j){var i=[[ag,Z,0],[ai,ah,0],[p,j,1]];aa(this,i,true)};q.drawText_=function(am,ak,aj,ap,ai){var ao=this.m_,at=1000,j=0,ar=at,ah={x:0,y:0},ag=[];var i=u(E(this.font),this.element_);var p=ac(i);var au=this.element_.currentStyle;var Z=this.textAlign.toLowerCase();switch(Z){case"left":case"center":case"right":break;case"end":Z=au.direction=="ltr"?"right":"left";break;case"start":Z=au.direction=="rtl"?"right":"left";break;default:Z="left"}switch(this.textBaseline){case"hanging":case"top":ah.y=i.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":ah.y=-i.size/2.25;break}switch(Z){case"right":j=at;ar=0.05;break;case"center":j=ar=at/2;break}var aq=V(this,ak+ah.x,aj+ah.y);ag.push('<g_vml_:line from="',-j,' 0" to="',ar,' 0.05" ',' coordsize="100 100" coordorigin="0 0"',' filled="',!ai,'" stroked="',!!ai,'" style="position:absolute;width:1px;height:1px;">');if(ai){w(this,ag)}else{G(this,ag,{x:-j,y:0},{x:ar,y:i.size})}var an=ao[0][0].toFixed(3)+","+ao[1][0].toFixed(3)+","+ao[0][1].toFixed(3)+","+ao[1][1].toFixed(3)+",0,0";var al=n(aq.x/d)+","+n(aq.y/d);ag.push('<g_vml_:skew on="t" matrix="',an,'" ',' offset="',al,'" origin="',j,' 0" />','<g_vml_:path textpathok="true" />','<g_vml_:textpath on="true" string="',af(am),'" style="v-text-align:',Z,";font:",af(p),'" /></g_vml_:line>');this.element_.insertAdjacentHTML("beforeEnd",ag.join(""))};q.fillText=function(m,i,p,j){this.drawText_(m,i,p,j,false)};q.strokeText=function(m,i,p,j){this.drawText_(m,i,p,j,true)};q.measureText=function(m){if(!this.textMeasureEl_){var i='<span style="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;"></span>';this.element_.insertAdjacentHTML("beforeEnd",i);this.textMeasureEl_=this.element_.lastChild}var j=this.element_.ownerDocument;this.textMeasureEl_.innerHTML="";this.textMeasureEl_.style.font=this.font;this.textMeasureEl_.appendChild(j.createTextNode(m));return{width:this.textMeasureEl_.offsetWidth}};q.clip=function(){};q.arcTo=function(){};q.createPattern=function(j,i){return new T(j,i)};function U(i){this.type_=i;this.x0_=0;this.y0_=0;this.r0_=0;this.x1_=0;this.y1_=0;this.r1_=0;this.colors_=[]}U.prototype.addColorStop=function(j,i){i=F(i);this.colors_.push({offset:j,color:i.color,alpha:i.alpha})};function T(j,i){Q(j);switch(i){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=i;break;default:O("SYNTAX_ERR")}this.src_=j.src;this.width_=j.width;this.height_=j.height}function O(i){throw new P(i)}function Q(i){if(!i||i.nodeType!=1||i.tagName!="IMG"){O("TYPE_MISMATCH_ERR")}if(i.readyState!="complete"){O("INVALID_STATE_ERR")}}function P(i){this.code=this[i];this.message=i+": DOM Exception "+this.code}var X=P.prototype=new Error;X.INDEX_SIZE_ERR=1;X.DOMSTRING_SIZE_ERR=2;X.HIERARCHY_REQUEST_ERR=3;X.WRONG_DOCUMENT_ERR=4;X.INVALID_CHARACTER_ERR=5;X.NO_DATA_ALLOWED_ERR=6;X.NO_MODIFICATION_ALLOWED_ERR=7;X.NOT_FOUND_ERR=8;X.NOT_SUPPORTED_ERR=9;X.INUSE_ATTRIBUTE_ERR=10;X.INVALID_STATE_ERR=11;X.SYNTAX_ERR=12;X.INVALID_MODIFICATION_ERR=13;X.NAMESPACE_ERR=14;X.INVALID_ACCESS_ERR=15;X.VALIDATION_ERR=16;X.TYPE_MISMATCH_ERR=17;G_vmlCanvasManager=e;CanvasRenderingContext2D=D;CanvasGradient=U;CanvasPattern=T;DOMException=P})()};
\ No newline at end of file
diff --git a/third_party/flot/jquery.colorhelpers.min.js b/third_party/flot/jquery.colorhelpers.min.js
index 7f44c57..844cef6 100644
--- a/third_party/flot/jquery.colorhelpers.min.js
+++ b/third_party/flot/jquery.colorhelpers.min.js
@@ -1 +1,21 @@
-(function(b){b.color={};b.color.make=function(f,e,c,d){var h={};h.r=f||0;h.g=e||0;h.b=c||0;h.a=d!=null?d:1;h.add=function(k,j){for(var g=0;g<k.length;++g){h[k.charAt(g)]+=j}return h.normalize()};h.scale=function(k,j){for(var g=0;g<k.length;++g){h[k.charAt(g)]*=j}return h.normalize()};h.toString=function(){if(h.a>=1){return"rgb("+[h.r,h.g,h.b].join(",")+")"}else{return"rgba("+[h.r,h.g,h.b,h.a].join(",")+")"}};h.normalize=function(){function g(j,k,i){return k<j?j:(k>i?i:k)}h.r=g(0,parseInt(h.r),255);h.g=g(0,parseInt(h.g),255);h.b=g(0,parseInt(h.b),255);h.a=g(0,h.a,1);return h};h.clone=function(){return b.color.make(h.r,h.b,h.g,h.a)};return h.normalize()};b.color.extract=function(e,d){var f;do{f=e.css(d).toLowerCase();if(f!=""&&f!="transparent"){break}e=e.parent()}while(!b.nodeName(e.get(0),"body"));if(f=="rgba(0, 0, 0, 0)"){f="transparent"}return b.color.parse(f)};b.color.parse=function(f){var e,c=b.color.make;if(e=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(f)){return c(parseInt(e[1],10),parseInt(e[2],10),parseInt(e[3],10))}if(e=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(f)){return c(parseInt(e[1],10),parseInt(e[2],10),parseInt(e[3],10),parseFloat(e[4]))}if(e=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(f)){return c(parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55)}if(e=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(f)){return c(parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55,parseFloat(e[4]))}if(e=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(f)){return c(parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16))}if(e=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(f)){return c(parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16))}var d=b.trim(f).toLowerCase();if(d=="transparent"){return c(255,255,255,0)}else{e=a[d]||[0,0,0];return c(e[0],e[1],e[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
\ No newline at end of file
+/* Plugin for jQuery for working with colors.
+ * 
+ * Version 1.1.
+ * 
+ * Inspiration from jQuery color animation plugin by John Resig.
+ *
+ * Released under the MIT license by Ole Laursen, October 2009.
+ *
+ * Examples:
+ *
+ *   $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
+ *   var c = $.color.extract($("#mydiv"), 'background-color');
+ *   console.log(c.r, c.g, c.b, c.a);
+ *   $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
+ *
+ * Note that .scale() and .add() return the same modified object
+ * instead of making a new one.
+ *
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
+ * produce a color rather than just crashing.
+ */(function(e){e.color={},e.color.make=function(t,n,r,i){var s={};return s.r=t||0,s.g=n||0,s.b=r||0,s.a=i!=null?i:1,s.add=function(e,t){for(var n=0;n<e.length;++n)s[e.charAt(n)]+=t;return s.normalize()},s.scale=function(e,t){for(var n=0;n<e.length;++n)s[e.charAt(n)]*=t;return s.normalize()},s.toString=function(){return s.a>=1?"rgb("+[s.r,s.g,s.b].join(",")+")":"rgba("+[s.r,s.g,s.b,s.a].join(",")+")"},s.normalize=function(){function e(e,t,n){return t<e?e:t>n?n:t}return s.r=e(0,parseInt(s.r),255),s.g=e(0,parseInt(s.g),255),s.b=e(0,parseInt(s.b),255),s.a=e(0,s.a,1),s},s.clone=function(){return e.color.make(s.r,s.b,s.g,s.a)},s.normalize()},e.color.extract=function(t,n){var r;do{r=t.css(n).toLowerCase();if(r!=""&&r!="transparent")break;t=t.parent()}while(!e.nodeName(t.get(0),"body"));return r=="rgba(0, 0, 0, 0)"&&(r="transparent"),e.color.parse(r)},e.color.parse=function(n){var r,i=e.color.make;if(r=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(n))return i(parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10));if(r=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(n))return i(parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10),parseFloat(r[4]));if(r=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(n))return i(parseFloat(r[1])*2.55,parseFloat(r[2])*2.55,parseFloat(r[3])*2.55);if(r=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(n))return i(parseFloat(r[1])*2.55,parseFloat(r[2])*2.55,parseFloat(r[3])*2.55,parseFloat(r[4]));if(r=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(n))return i(parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16));if(r=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(n))return i(parseInt(r[1]+r[1],16),parseInt(r[2]+r[2],16),parseInt(r[3]+r[3],16));var s=e.trim(n).toLowerCase();return s=="transparent"?i(255,255,255,0):(r=t[s]||[0,0,0],i(r[0],r[1],r[2]))};var t={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.canvas.min.js b/third_party/flot/jquery.flot.canvas.min.js
new file mode 100644
index 0000000..ac70b53
--- /dev/null
+++ b/third_party/flot/jquery.flot.canvas.min.js
@@ -0,0 +1,28 @@
+/* Flot plugin for drawing all elements of a plot on the canvas.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Flot normally produces certain elements, like axis labels and the legend, using
+HTML elements. This permits greater interactivity and customization, and often
+looks better, due to cross-browser canvas text inconsistencies and limitations.
+
+It can also be desirable to render the plot entirely in canvas, particularly
+if the goal is to save it as an image, or if Flot is being used in a context
+where the HTML DOM does not exist, as is the case within Node.js. This plugin
+switches out Flot's standard drawing operations for canvas-only replacements.
+
+Currently the plugin supports only axis labels, but it will eventually allow
+every element of the plot to be rendered directly to canvas.
+
+The plugin supports these options:
+
+{
+    canvas: boolean
+}
+
+The "canvas" option controls whether full canvas drawing is enabled, making it
+possible to toggle on and off. This is useful when a plot uses HTML text in the
+browser, but needs to redraw with canvas text when exporting as an image.
+
+*/(function(e){function o(t,o){var u=o.Canvas;n==null&&(r=u.prototype.getTextInfo,i=u.prototype.addText,n=u.prototype.render),u.prototype.render=function(){if(!t.getOptions().canvas)return n.call(this);var e=this.context,r=this._textCache;e.save(),e.textBaseline="middle";for(var i in r)if(s.call(r,i)){var o=r[i];for(var u in o)if(s.call(o,u)){var a=o[u],f=!0;for(var l in a)if(s.call(a,l)){var c=a[l],h=c.positions,p=c.lines;f&&(e.fillStyle=c.font.color,e.font=c.font.definition,f=!1);for(var d=0,v;v=h[d];d++)if(v.active)for(var m=0,g;g=v.lines[m];m++)e.fillText(p[m].text,g[0],g[1]);else h.splice(d--,1);h.length==0&&delete a[l]}}}e.restore()},u.prototype.getTextInfo=function(n,i,s,o,u){if(!t.getOptions().canvas)return r.call(this,n,i,s,o,u);var a,f,l,c;i=""+i,typeof s=="object"?a=s.style+" "+s.variant+" "+s.weight+" "+s.size+"px "+s.family:a=s,f=this._textCache[n],f==null&&(f=this._textCache[n]={}),l=f[a],l==null&&(l=f[a]={}),c=l[i];if(c==null){var h=this.context;if(typeof s!="object"){var p=e("<div>&nbsp;</div>").css("position","absolute").addClass(typeof s=="string"?s:null).appendTo(this.getTextLayer(n));s={lineHeight:p.height(),style:p.css("font-style"),variant:p.css("font-variant"),weight:p.css("font-weight"),family:p.css("font-family"),color:p.css("color")},s.size=p.css("line-height",1).height(),p.remove()}a=s.style+" "+s.variant+" "+s.weight+" "+s.size+"px "+s.family,c=l[i]={width:0,height:0,positions:[],lines:[],font:{definition:a,color:s.color}},h.save(),h.font=a;var d=(i+"").replace(/<br ?\/?>|\r\n|\r/g,"\n").split("\n");for(var v=0;v<d.length;++v){var m=d[v],g=h.measureText(m);c.width=Math.max(g.width,c.width),c.height+=s.lineHeight,c.lines.push({text:m,width:g.width,height:s.lineHeight})}h.restore()}return c},u.prototype.addText=function(e,n,r,s,o,u,a,f,l){if(!t.getOptions().canvas)return i.call(this,e,n,r,s,o,u,a,f,l);var c=this.getTextInfo(e,s,o,u,a),h=c.positions,p=c.lines;r+=c.height/p.length/2,l=="middle"?r=Math.round(r-c.height/2):l=="bottom"?r=Math.round(r-c.height):r=Math.round(r),!(window.opera&&window.opera.version().split(".")[0]<12)||(r-=2);for(var d=0,v;v=h[d];d++)if(v.x==n&&v.y==r){v.active=!0;return}v={active:!0,lines:[],x:n,y:r},h.push(v);for(var d=0,m;m=p[d];d++)f=="center"?v.lines.push([Math.round(n-m.width/2),r]):f=="right"?v.lines.push([Math.round(n-m.width),r]):v.lines.push([Math.round(n),r]),r+=m.height}}var t={canvas:!0},n,r,i,s=Object.prototype.hasOwnProperty;e.plot.plugins.push({init:o,options:t,name:"canvas",version:"1.0"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.categories.min.js b/third_party/flot/jquery.flot.categories.min.js
new file mode 100644
index 0000000..ca86594
--- /dev/null
+++ b/third_party/flot/jquery.flot.categories.min.js
@@ -0,0 +1,44 @@
+/* Flot plugin for plotting textual data or categories.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Consider a dataset like [["February", 34], ["March", 20], ...]. This plugin
+allows you to plot such a dataset directly.
+
+To enable it, you must specify mode: "categories" on the axis with the textual
+labels, e.g.
+
+	$.plot("#placeholder", data, { xaxis: { mode: "categories" } });
+
+By default, the labels are ordered as they are met in the data series. If you
+need a different ordering, you can specify "categories" on the axis options
+and list the categories there:
+
+	xaxis: {
+		mode: "categories",
+		categories: ["February", "March", "April"]
+	}
+
+If you need to customize the distances between the categories, you can specify
+"categories" as an object mapping labels to values
+
+	xaxis: {
+		mode: "categories",
+		categories: { "February": 1, "March": 3, "April": 4 }
+	}
+
+If you don't specify all categories, the remaining categories will be numbered
+from the max value plus 1 (with a spacing of 1 between each).
+
+Internally, the plugin works by transforming the input data through an auto-
+generated mapping where the first category becomes 0, the second 1, etc.
+Hence, a point like ["February", 34] becomes [0, 34] internally in Flot (this
+is visible in hover and click events that return numbers rather than the
+category labels). The plugin also overrides the tick generator to spit out the
+categories as ticks instead of the values.
+
+If you need to map a value back to its label, the mapping is always accessible
+as "categories" on the axis object, e.g. plot.getAxes().xaxis.categories.
+
+*/(function(e){function n(e,t,n,r){var i=t.xaxis.options.mode=="categories",s=t.yaxis.options.mode=="categories";if(!i&&!s)return;var o=r.format;if(!o){var u=t;o=[],o.push({x:!0,number:!0,required:!0}),o.push({y:!0,number:!0,required:!0});if(u.bars.show||u.lines.show&&u.lines.fill){var a=!!(u.bars.show&&u.bars.zero||u.lines.show&&u.lines.zero);o.push({y:!0,number:!0,required:!1,defaultValue:0,autoscale:a}),u.bars.horizontal&&(delete o[o.length-1].y,o[o.length-1].x=!0)}r.format=o}for(var f=0;f<o.length;++f)o[f].x&&i&&(o[f].number=!1),o[f].y&&s&&(o[f].number=!1)}function r(e){var t=-1;for(var n in e)e[n]>t&&(t=e[n]);return t+1}function i(e){var t=[];for(var n in e.categories){var r=e.categories[n];r>=e.min&&r<=e.max&&t.push([r,n])}return t.sort(function(e,t){return e[0]-t[0]}),t}function s(t,n,r){if(t[n].options.mode!="categories")return;if(!t[n].categories){var s={},u=t[n].options.categories||{};if(e.isArray(u))for(var a=0;a<u.length;++a)s[u[a]]=a;else for(var f in u)s[f]=u[f];t[n].categories=s}t[n].options.ticks||(t[n].options.ticks=i),o(r,n,t[n].categories)}function o(e,t,n){var i=e.points,s=e.pointsize,o=e.format,u=t.charAt(0),a=r(n);for(var f=0;f<i.length;f+=s){if(i[f]==null)continue;for(var l=0;l<s;++l){var c=i[f+l];if(c==null||!o[l][u])continue;c in n||(n[c]=a,++a),i[f+l]=n[c]}}}function u(e,t,n){s(t,"xaxis",n),s(t,"yaxis",n)}function a(e){e.hooks.processRawData.push(n),e.hooks.processDatapoints.push(u)}var t={xaxis:{categories:null},yaxis:{categories:null}};e.plot.plugins.push({init:a,options:t,name:"categories",version:"1.0"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.crosshair.min.js b/third_party/flot/jquery.flot.crosshair.min.js
index ccaf240..65bb990 100644
--- a/third_party/flot/jquery.flot.crosshair.min.js
+++ b/third_party/flot/jquery.flot.crosshair.min.js
@@ -1 +1,59 @@
-(function(b){var a={crosshair:{mode:null,color:"rgba(170, 0, 0, 0.80)",lineWidth:1}};function c(h){var j={x:-1,y:-1,locked:false};h.setCrosshair=function e(l){if(!l){j.x=-1}else{var k=h.p2c(l);j.x=Math.max(0,Math.min(k.left,h.width()));j.y=Math.max(0,Math.min(k.top,h.height()))}h.triggerRedrawOverlay()};h.clearCrosshair=h.setCrosshair;h.lockCrosshair=function f(k){if(k){h.setCrosshair(k)}j.locked=true};h.unlockCrosshair=function g(){j.locked=false};function d(k){if(j.locked){return}if(j.x!=-1){j.x=-1;h.triggerRedrawOverlay()}}function i(k){if(j.locked){return}if(h.getSelection&&h.getSelection()){j.x=-1;return}var l=h.offset();j.x=Math.max(0,Math.min(k.pageX-l.left,h.width()));j.y=Math.max(0,Math.min(k.pageY-l.top,h.height()));h.triggerRedrawOverlay()}h.hooks.bindEvents.push(function(l,k){if(!l.getOptions().crosshair.mode){return}k.mouseout(d);k.mousemove(i)});h.hooks.drawOverlay.push(function(m,k){var n=m.getOptions().crosshair;if(!n.mode){return}var l=m.getPlotOffset();k.save();k.translate(l.left,l.top);if(j.x!=-1){k.strokeStyle=n.color;k.lineWidth=n.lineWidth;k.lineJoin="round";k.beginPath();if(n.mode.indexOf("x")!=-1){k.moveTo(j.x,0);k.lineTo(j.x,m.height())}if(n.mode.indexOf("y")!=-1){k.moveTo(0,j.y);k.lineTo(m.width(),j.y)}k.stroke()}k.restore()});h.hooks.shutdown.push(function(l,k){k.unbind("mouseout",d);k.unbind("mousemove",i)})}b.plot.plugins.push({init:c,options:a,name:"crosshair",version:"1.0"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for showing crosshairs when the mouse hovers over the plot.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The plugin supports these options:
+
+	crosshair: {
+		mode: null or "x" or "y" or "xy"
+		color: color
+		lineWidth: number
+	}
+
+Set the mode to one of "x", "y" or "xy". The "x" mode enables a vertical
+crosshair that lets you trace the values on the x axis, "y" enables a
+horizontal crosshair and "xy" enables them both. "color" is the color of the
+crosshair (default is "rgba(170, 0, 0, 0.80)"), "lineWidth" is the width of
+the drawn lines (default is 1).
+
+The plugin also adds four public methods:
+
+  - setCrosshair( pos )
+
+    Set the position of the crosshair. Note that this is cleared if the user
+    moves the mouse. "pos" is in coordinates of the plot and should be on the
+    form { x: xpos, y: ypos } (you can use x2/x3/... if you're using multiple
+    axes), which is coincidentally the same format as what you get from a
+    "plothover" event. If "pos" is null, the crosshair is cleared.
+
+  - clearCrosshair()
+
+    Clear the crosshair.
+
+  - lockCrosshair(pos)
+
+    Cause the crosshair to lock to the current location, no longer updating if
+    the user moves the mouse. Optionally supply a position (passed on to
+    setCrosshair()) to move it to.
+
+    Example usage:
+
+	var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } };
+	$("#graph").bind( "plothover", function ( evt, position, item ) {
+		if ( item ) {
+			// Lock the crosshair to the data point being hovered
+			myFlot.lockCrosshair({
+				x: item.datapoint[ 0 ],
+				y: item.datapoint[ 1 ]
+			});
+		} else {
+			// Return normal crosshair operation
+			myFlot.unlockCrosshair();
+		}
+	});
+
+  - unlockCrosshair()
+
+    Free the crosshair to move again after locking it.
+*/(function(e){function n(e){function n(n){if(t.locked)return;t.x!=-1&&(t.x=-1,e.triggerRedrawOverlay())}function r(n){if(t.locked)return;if(e.getSelection&&e.getSelection()){t.x=-1;return}var r=e.offset();t.x=Math.max(0,Math.min(n.pageX-r.left,e.width())),t.y=Math.max(0,Math.min(n.pageY-r.top,e.height())),e.triggerRedrawOverlay()}var t={x:-1,y:-1,locked:!1};e.setCrosshair=function(r){if(!r)t.x=-1;else{var i=e.p2c(r);t.x=Math.max(0,Math.min(i.left,e.width())),t.y=Math.max(0,Math.min(i.top,e.height()))}e.triggerRedrawOverlay()},e.clearCrosshair=e.setCrosshair,e.lockCrosshair=function(r){r&&e.setCrosshair(r),t.locked=!0},e.unlockCrosshair=function(){t.locked=!1},e.hooks.bindEvents.push(function(e,t){if(!e.getOptions().crosshair.mode)return;t.mouseout(n),t.mousemove(r)}),e.hooks.drawOverlay.push(function(e,n){var r=e.getOptions().crosshair;if(!r.mode)return;var i=e.getPlotOffset();n.save(),n.translate(i.left,i.top);if(t.x!=-1){var s=e.getOptions().crosshair.lineWidth%2===0?0:.5;n.strokeStyle=r.color,n.lineWidth=r.lineWidth,n.lineJoin="round",n.beginPath();if(r.mode.indexOf("x")!=-1){var o=Math.round(t.x)+s;n.moveTo(o,0),n.lineTo(o,e.height())}if(r.mode.indexOf("y")!=-1){var u=Math.round(t.y)+s;n.moveTo(0,u),n.lineTo(e.width(),u)}n.stroke()}n.restore()}),e.hooks.shutdown.push(function(e,t){t.unbind("mouseout",n),t.unbind("mousemove",r)})}var t={crosshair:{mode:null,color:"rgba(170, 0, 0, 0.80)",lineWidth:1}};e.plot.plugins.push({init:n,options:t,name:"crosshair",version:"1.0"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.errorbars.min.js b/third_party/flot/jquery.flot.errorbars.min.js
new file mode 100644
index 0000000..72d7e3d
--- /dev/null
+++ b/third_party/flot/jquery.flot.errorbars.min.js
@@ -0,0 +1,63 @@
+/* Flot plugin for plotting error bars.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Error bars are used to show standard deviation and other statistical
+properties in a plot.
+
+* Created by Rui Pereira  -  rui (dot) pereira (at) gmail (dot) com
+
+This plugin allows you to plot error-bars over points. Set "errorbars" inside
+the points series to the axis name over which there will be error values in
+your data array (*even* if you do not intend to plot them later, by setting
+"show: null" on xerr/yerr).
+
+The plugin supports these options:
+
+	series: {
+		points: {
+			errorbars: "x" or "y" or "xy",
+			xerr: {
+				show: null/false or true,
+				asymmetric: null/false or true,
+				upperCap: null or "-" or function,
+				lowerCap: null or "-" or function,
+				color: null or color,
+				radius: null or number
+			},
+			yerr: { same options as xerr }
+		}
+	}
+
+Each data point array is expected to be of the type:
+
+	"x"  [ x, y, xerr ]
+	"y"  [ x, y, yerr ]
+	"xy" [ x, y, xerr, yerr ]
+
+Where xerr becomes xerr_lower,xerr_upper for the asymmetric error case, and
+equivalently for yerr. Eg., a datapoint for the "xy" case with symmetric
+error-bars on X and asymmetric on Y would be:
+
+	[ x, y, xerr, yerr_lower, yerr_upper ]
+
+By default no end caps are drawn. Setting upperCap and/or lowerCap to "-" will
+draw a small cap perpendicular to the error bar. They can also be set to a
+user-defined drawing function, with (ctx, x, y, radius) as parameters, as eg.
+
+	function drawSemiCircle( ctx, x, y, radius ) {
+		ctx.beginPath();
+		ctx.arc( x, y, radius, 0, Math.PI, false );
+		ctx.moveTo( x - radius, y );
+		ctx.lineTo( x + radius, y );
+		ctx.stroke();
+	}
+
+Color and radius both default to the same ones of the points series if not
+set. The independent radius parameter on xerr/yerr is useful for the case when
+we may want to add error-bars to a line, without showing the interconnecting
+points (with radius: 0), and still showing end caps on the error-bars.
+shadowSize and lineWidth are derived as well from the points series.
+
+*/(function(e){function n(e,t,n,r){if(!t.points.errorbars)return;var i=[{x:!0,number:!0,required:!0},{y:!0,number:!0,required:!0}],s=t.points.errorbars;if(s=="x"||s=="xy")t.points.xerr.asymmetric?(i.push({x:!0,number:!0,required:!0}),i.push({x:!0,number:!0,required:!0})):i.push({x:!0,number:!0,required:!0});if(s=="y"||s=="xy")t.points.yerr.asymmetric?(i.push({y:!0,number:!0,required:!0}),i.push({y:!0,number:!0,required:!0})):i.push({y:!0,number:!0,required:!0});r.format=i}function r(e,t){var n=e.datapoints.points,r=null,i=null,s=null,o=null,u=e.points.xerr,a=e.points.yerr,f=e.points.errorbars;f=="x"||f=="xy"?u.asymmetric?(r=n[t+2],i=n[t+3],f=="xy"&&(a.asymmetric?(s=n[t+4],o=n[t+5]):s=n[t+4])):(r=n[t+2],f=="xy"&&(a.asymmetric?(s=n[t+3],o=n[t+4]):s=n[t+3])):f=="y"&&(a.asymmetric?(s=n[t+2],o=n[t+3]):s=n[t+2]),i==null&&(i=r),o==null&&(o=s);var l=[r,i,s,o];return u.show||(l[0]=null,l[1]=null),a.show||(l[2]=null,l[3]=null),l}function i(e,t,n){var i=n.datapoints.points,o=n.datapoints.pointsize,u=[n.xaxis,n.yaxis],a=n.points.radius,f=[n.points.xerr,n.points.yerr],l=!1;if(u[0].p2c(u[0].max)<u[0].p2c(u[0].min)){l=!0;var c=f[0].lowerCap;f[0].lowerCap=f[0].upperCap,f[0].upperCap=c}var h=!1;if(u[1].p2c(u[1].min)<u[1].p2c(u[1].max)){h=!0;var c=f[1].lowerCap;f[1].lowerCap=f[1].upperCap,f[1].upperCap=c}for(var p=0;p<n.datapoints.points.length;p+=o){var d=r(n,p);for(var v=0;v<f.length;v++){var m=[u[v].min,u[v].max];if(d[v*f.length]){var g=i[p],y=i[p+1],b=[g,y][v]+d[v*f.length+1],w=[g,y][v]-d[v*f.length];if(f[v].err=="x")if(y>u[1].max||y<u[1].min||b<u[0].min||w>u[0].max)continue;if(f[v].err=="y")if(g>u[0].max||g<u[0].min||b<u[1].min||w>u[1].max)continue;var E=!0,S=!0;b>m[1]&&(E=!1,b=m[1]),w<m[0]&&(S=!1,w=m[0]);if(f[v].err=="x"&&l||f[v].err=="y"&&h){var c=w;w=b,b=c,c=S,S=E,E=c,c=m[0],m[0]=m[1],m[1]=c}g=u[0].p2c(g),y=u[1].p2c(y),b=u[v].p2c(b),w=u[v].p2c(w),m[0]=u[v].p2c(m[0]),m[1]=u[v].p2c(m[1]);var x=f[v].lineWidth?f[v].lineWidth:n.points.lineWidth,T=n.points.shadowSize!=null?n.points.shadowSize:n.shadowSize;if(x>0&&T>0){var N=T/2;t.lineWidth=N,t.strokeStyle="rgba(0,0,0,0.1)",s(t,f[v],g,y,b,w,E,S,a,N+N/2,m),t.strokeStyle="rgba(0,0,0,0.2)",s(t,f[v],g,y,b,w,E,S,a,N/2,m)}t.strokeStyle=f[v].color?f[v].color:n.color,t.lineWidth=x,s(t,f[v],g,y,b,w,E,S,a,0,m)}}}}function s(t,n,r,i,s,u,a,f,l,c,h){i+=c,s+=c,u+=c,n.err=="x"?(s>r+l?o(t,[[s,i],[Math.max(r+l,h[0]),i]]):a=!1,u<r-l?o(t,[[Math.min(r-l,h[1]),i],[u,i]]):f=!1):(s<i-l?o(t,[[r,s],[r,Math.min(i-l,h[0])]]):a=!1,u>i+l?o(t,[[r,Math.max(i+l,h[1])],[r,u]]):f=!1),l=n.radius!=null?n.radius:l,a&&(n.upperCap=="-"?n.err=="x"?o(t,[[s,i-l],[s,i+l]]):o(t,[[r-l,s],[r+l,s]]):e.isFunction(n.upperCap)&&(n.err=="x"?n.upperCap(t,s,i,l):n.upperCap(t,r,s,l))),f&&(n.lowerCap=="-"?n.err=="x"?o(t,[[u,i-l],[u,i+l]]):o(t,[[r-l,u],[r+l,u]]):e.isFunction(n.lowerCap)&&(n.err=="x"?n.lowerCap(t,u,i,l):n.lowerCap(t,r,u,l)))}function o(e,t){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(var n=1;n<t.length;n++)e.lineTo(t[n][0],t[n][1]);e.stroke()}function u(t,n){var r=t.getPlotOffset();n.save(),n.translate(r.left,r.top),e.each(t.getData(),function(e,r){r.points.errorbars&&(r.points.xerr.show||r.points.yerr.show)&&i(t,n,r)}),n.restore()}function a(e){e.hooks.processRawData.push(n),e.hooks.draw.push(u)}var t={series:{points:{errorbars:null,xerr:{err:"x",show:null,asymmetric:null,upperCap:null,lowerCap:null,color:null,radius:null},yerr:{err:"y",show:null,asymmetric:null,upperCap:null,lowerCap:null,color:null,radius:null}}}};e.plot.plugins.push({init:a,options:t,name:"errorbars",version:"1.0"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.fillbetween.min.js b/third_party/flot/jquery.flot.fillbetween.min.js
index 47f3dfb..e94efb7 100644
--- a/third_party/flot/jquery.flot.fillbetween.min.js
+++ b/third_party/flot/jquery.flot.fillbetween.min.js
@@ -1 +1,30 @@
-(function(b){var a={series:{fillBetween:null}};function c(f){function d(j,h){var g;for(g=0;g<h.length;++g){if(h[g].id==j.fillBetween){return h[g]}}if(typeof j.fillBetween=="number"){g=j.fillBetween;if(g<0||g>=h.length){return null}return h[g]}return null}function e(B,u,g){if(u.fillBetween==null){return}var p=d(u,B.getData());if(!p){return}var y=g.pointsize,E=g.points,h=p.datapoints.pointsize,x=p.datapoints.points,r=[],w,v,k,G,F,q,t=u.lines.show,o=y>2&&g.format[2].y,n=t&&u.lines.steps,D=true,C=0,A=0,z;while(true){if(C>=E.length){break}z=r.length;if(E[C]==null){for(m=0;m<y;++m){r.push(E[C+m])}C+=y}else{if(A>=x.length){if(!t){for(m=0;m<y;++m){r.push(E[C+m])}}C+=y}else{if(x[A]==null){for(m=0;m<y;++m){r.push(null)}D=true;A+=h}else{w=E[C];v=E[C+1];G=x[A];F=x[A+1];q=0;if(w==G){for(m=0;m<y;++m){r.push(E[C+m])}q=F;C+=y;A+=h}else{if(w>G){if(t&&C>0&&E[C-y]!=null){k=v+(E[C-y+1]-v)*(G-w)/(E[C-y]-w);r.push(G);r.push(k);for(m=2;m<y;++m){r.push(E[C+m])}q=F}A+=h}else{if(D&&t){C+=y;continue}for(m=0;m<y;++m){r.push(E[C+m])}if(t&&A>0&&x[A-h]!=null){q=F+(x[A-h+1]-F)*(w-G)/(x[A-h]-G)}C+=y}}D=false;if(z!=r.length&&o){r[z+2]=q}}}}if(n&&z!=r.length&&z>0&&r[z]!=null&&r[z]!=r[z-y]&&r[z+1]!=r[z-y+1]){for(m=0;m<y;++m){r[z+y+m]=r[z+m]}r[z+1]=r[z-y+1]}}g.points=r}f.hooks.processDatapoints.push(e)}b.plot.plugins.push({init:c,options:a,name:"fillbetween",version:"1.0"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for computing bottoms for filled line and bar charts.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The case: you've got two series that you want to fill the area between. In Flot
+terms, you need to use one as the fill bottom of the other. You can specify the
+bottom of each data point as the third coordinate manually, or you can use this
+plugin to compute it for you.
+
+In order to name the other series, you need to give it an id, like this:
+
+	var dataset = [
+		{ data: [ ... ], id: "foo" } ,         // use default bottom
+		{ data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom
+	];
+
+	$.plot($("#placeholder"), dataset, { lines: { show: true, fill: true }});
+
+As a convenience, if the id given is a number that doesn't appear as an id in
+the series, it is interpreted as the index in the array instead (so fillBetween:
+0 can also mean the first series).
+
+Internally, the plugin modifies the datapoints in each series. For line series,
+extra data points might be inserted through interpolation. Note that at points
+where the bottom line is not defined (due to a null point or start/end of line),
+the current line will show a gap too. The algorithm comes from the
+jquery.flot.stack.js plugin, possibly some code could be shared.
+
+*/(function(e){function n(e){function t(e,t){var n;for(n=0;n<t.length;++n)if(t[n].id===e.fillBetween)return t[n];return typeof e.fillBetween=="number"?e.fillBetween<0||e.fillBetween>=t.length?null:t[e.fillBetween]:null}function n(e,n,r){if(n.fillBetween==null)return;var i=t(n,e.getData());if(!i)return;var s=r.pointsize,o=r.points,u=i.datapoints.pointsize,a=i.datapoints.points,f=[],l,c,h,p,d,v,m=n.lines.show,g=s>2&&r.format[2].y,y=m&&n.lines.steps,b=!0,w=0,E=0,S,x;for(;;){if(w>=o.length)break;S=f.length;if(o[w]==null){for(x=0;x<s;++x)f.push(o[w+x]);w+=s}else if(E>=a.length){if(!m)for(x=0;x<s;++x)f.push(o[w+x]);w+=s}else if(a[E]==null){for(x=0;x<s;++x)f.push(null);b=!0,E+=u}else{l=o[w],c=o[w+1],p=a[E],d=a[E+1],v=0;if(l===p){for(x=0;x<s;++x)f.push(o[w+x]);v=d,w+=s,E+=u}else if(l>p){if(m&&w>0&&o[w-s]!=null){h=c+(o[w-s+1]-c)*(p-l)/(o[w-s]-l),f.push(p),f.push(h);for(x=2;x<s;++x)f.push(o[w+x]);v=d}E+=u}else{if(b&&m){w+=s;continue}for(x=0;x<s;++x)f.push(o[w+x]);m&&E>0&&a[E-u]!=null&&(v=d+(a[E-u+1]-d)*(l-p)/(a[E-u]-p)),w+=s}b=!1,S!==f.length&&g&&(f[S+2]=v)}if(y&&S!==f.length&&S>0&&f[S]!==null&&f[S]!==f[S-s]&&f[S+1]!==f[S-s+1]){for(x=0;x<s;++x)f[S+s+x]=f[S+x];f[S+1]=f[S-s+1]}}r.points=f}e.hooks.processDatapoints.push(n)}var t={series:{fillBetween:null}};e.plot.plugins.push({init:n,options:t,name:"fillbetween",version:"1.0"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.image.min.js b/third_party/flot/jquery.flot.image.min.js
index 9480c1e..b128d30 100644
--- a/third_party/flot/jquery.flot.image.min.js
+++ b/third_party/flot/jquery.flot.image.min.js
@@ -1 +1,53 @@
-(function(c){var a={series:{images:{show:false,alpha:1,anchor:"corner"}}};c.plot.image={};c.plot.image.loadDataImages=function(g,f,k){var j=[],h=[];var i=f.series.images.show;c.each(g,function(l,m){if(!(i||m.images.show)){return}if(m.data){m=m.data}c.each(m,function(n,o){if(typeof o[0]=="string"){j.push(o[0]);h.push(o)}})});c.plot.image.load(j,function(l){c.each(h,function(n,o){var m=o[0];if(l[m]){o[0]=l[m]}});k()})};c.plot.image.load=function(h,i){var g=h.length,f={};if(g==0){i({})}c.each(h,function(k,j){var l=function(){--g;f[j]=this;if(g==0){i(f)}};c("<img />").load(l).error(l).attr("src",j)})};function d(q,o,l){var m=q.getPlotOffset();if(!l.images||!l.images.show){return}var r=l.datapoints.points,n=l.datapoints.pointsize;for(var t=0;t<r.length;t+=n){var y=r[t],w=r[t+1],g=r[t+2],v=r[t+3],f=r[t+4],h=l.xaxis,u=l.yaxis,x;if(!y||y.width<=0||y.height<=0){continue}if(w>v){x=v;v=w;w=x}if(g>f){x=f;f=g;g=x}if(l.images.anchor=="center"){x=0.5*(v-w)/(y.width-1);w-=x;v+=x;x=0.5*(f-g)/(y.height-1);g-=x;f+=x}if(w==v||g==f||w>=h.max||v<=h.min||g>=u.max||f<=u.min){continue}var k=0,s=0,j=y.width,p=y.height;if(w<h.min){k+=(j-k)*(h.min-w)/(v-w);w=h.min}if(v>h.max){j+=(j-k)*(h.max-v)/(v-w);v=h.max}if(g<u.min){p+=(s-p)*(u.min-g)/(f-g);g=u.min}if(f>u.max){s+=(s-p)*(u.max-f)/(f-g);f=u.max}w=h.p2c(w);v=h.p2c(v);g=u.p2c(g);f=u.p2c(f);if(w>v){x=v;v=w;w=x}if(g>f){x=f;f=g;g=x}x=o.globalAlpha;o.globalAlpha*=l.images.alpha;o.drawImage(y,k,s,j-k,p-s,w+m.left,g+m.top,v-w,f-g);o.globalAlpha=x}}function b(i,f,g,h){if(!f.images.show){return}h.format=[{required:true},{x:true,number:true,required:true},{y:true,number:true,required:true},{x:true,number:true,required:true},{y:true,number:true,required:true}]}function e(f){f.hooks.processRawData.push(b);f.hooks.drawSeries.push(d)}c.plot.plugins.push({init:e,options:a,name:"image",version:"1.1"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for plotting images.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The data syntax is [ [ image, x1, y1, x2, y2 ], ... ] where (x1, y1) and
+(x2, y2) are where you intend the two opposite corners of the image to end up
+in the plot. Image must be a fully loaded Javascript image (you can make one
+with new Image()). If the image is not complete, it's skipped when plotting.
+
+There are two helpers included for retrieving images. The easiest work the way
+that you put in URLs instead of images in the data, like this:
+
+	[ "myimage.png", 0, 0, 10, 10 ]
+
+Then call $.plot.image.loadData( data, options, callback ) where data and
+options are the same as you pass in to $.plot. This loads the images, replaces
+the URLs in the data with the corresponding images and calls "callback" when
+all images are loaded (or failed loading). In the callback, you can then call
+$.plot with the data set. See the included example.
+
+A more low-level helper, $.plot.image.load(urls, callback) is also included.
+Given a list of URLs, it calls callback with an object mapping from URL to
+Image object when all images are loaded or have failed loading.
+
+The plugin supports these options:
+
+	series: {
+		images: {
+			show: boolean
+			anchor: "corner" or "center"
+			alpha: [ 0, 1 ]
+		}
+	}
+
+They can be specified for a specific series:
+
+	$.plot( $("#placeholder"), [{
+		data: [ ... ],
+		images: { ... }
+	])
+
+Note that because the data format is different from usual data points, you
+can't use images with anything else in a specific data series.
+
+Setting "anchor" to "center" causes the pixels in the image to be anchored at
+the corner pixel centers inside of at the pixel corners, effectively letting
+half a pixel stick out to each side in the plot.
+
+A possible future direction could be support for tiling for large images (like
+Google Maps).
+
+*/(function(e){function n(e,t,n){var r=e.getPlotOffset();if(!n.images||!n.images.show)return;var i=n.datapoints.points,s=n.datapoints.pointsize;for(var o=0;o<i.length;o+=s){var u=i[o],a=i[o+1],f=i[o+2],l=i[o+3],c=i[o+4],h=n.xaxis,p=n.yaxis,d;if(!u||u.width<=0||u.height<=0)continue;a>l&&(d=l,l=a,a=d),f>c&&(d=c,c=f,f=d),n.images.anchor=="center"&&(d=.5*(l-a)/(u.width-1),a-=d,l+=d,d=.5*(c-f)/(u.height-1),f-=d,c+=d);if(a==l||f==c||a>=h.max||l<=h.min||f>=p.max||c<=p.min)continue;var v=0,m=0,g=u.width,y=u.height;a<h.min&&(v+=(g-v)*(h.min-a)/(l-a),a=h.min),l>h.max&&(g+=(g-v)*(h.max-l)/(l-a),l=h.max),f<p.min&&(y+=(m-y)*(p.min-f)/(c-f),f=p.min),c>p.max&&(m+=(m-y)*(p.max-c)/(c-f),c=p.max),a=h.p2c(a),l=h.p2c(l),f=p.p2c(f),c=p.p2c(c),a>l&&(d=l,l=a,a=d),f>c&&(d=c,c=f,f=d),d=t.globalAlpha,t.globalAlpha*=n.images.alpha,t.drawImage(u,v,m,g-v,y-m,a+r.left,f+r.top,l-a,c-f),t.globalAlpha=d}}function r(e,t,n,r){if(!t.images.show)return;r.format=[{required:!0},{x:!0,number:!0,required:!0},{y:!0,number:!0,required:!0},{x:!0,number:!0,required:!0},{y:!0,number:!0,required:!0}]}function i(e){e.hooks.processRawData.push(r),e.hooks.drawSeries.push(n)}var t={series:{images:{show:!1,alpha:1,anchor:"corner"}}};e.plot.image={},e.plot.image.loadDataImages=function(t,n,r){var i=[],s=[],o=n.series.images.show;e.each(t,function(t,n){if(!o&&!n.images.show)return;n.data&&(n=n.data),e.each(n,function(e,t){typeof t[0]=="string"&&(i.push(t[0]),s.push(t))})}),e.plot.image.load(i,function(t){e.each(s,function(e,n){var r=n[0];t[r]&&(n[0]=t[r])}),r()})},e.plot.image.load=function(t,n){var r=t.length,i={};r==0&&n({}),e.each(t,function(t,s){var o=function(){--r,i[s]=this,r==0&&n(i)};e("<img />").load(o).error(o).attr("src",s)})},e.plot.plugins.push({init:i,options:t,name:"image",version:"1.1"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.min.js b/third_party/flot/jquery.flot.min.js
index 4467fc5..3706512 100644
--- a/third_party/flot/jquery.flot.min.js
+++ b/third_party/flot/jquery.flot.min.js
@@ -1,6 +1,29 @@
-/* Javascript plotting library for jQuery, v. 0.7.
+/* Javascript plotting library for jQuery, version 0.8.1.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/// first an inline dependency, jquery.colorhelpers.js, we inline it here
+// for convenience
+/* Plugin for jQuery for working with colors.
  *
- * Released under the MIT license by IOLA, December 2007.
+ * Version 1.1.
  *
- */
-(function(b){b.color={};b.color.make=function(d,e,g,f){var c={};c.r=d||0;c.g=e||0;c.b=g||0;c.a=f!=null?f:1;c.add=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]+=j}return c.normalize()};c.scale=function(h,j){for(var k=0;k<h.length;++k){c[h.charAt(k)]*=j}return c.normalize()};c.toString=function(){if(c.a>=1){return"rgb("+[c.r,c.g,c.b].join(",")+")"}else{return"rgba("+[c.r,c.g,c.b,c.a].join(",")+")"}};c.normalize=function(){function h(k,j,l){return j<k?k:(j>l?l:j)}c.r=h(0,parseInt(c.r),255);c.g=h(0,parseInt(c.g),255);c.b=h(0,parseInt(c.b),255);c.a=h(0,c.a,1);return c};c.clone=function(){return b.color.make(c.r,c.b,c.g,c.a)};return c.normalize()};b.color.extract=function(d,e){var c;do{c=d.css(e).toLowerCase();if(c!=""&&c!="transparent"){break}d=d.parent()}while(!b.nodeName(d.get(0),"body"));if(c=="rgba(0, 0, 0, 0)"){c="transparent"}return b.color.parse(c)};b.color.parse=function(c){var d,f=b.color.make;if(d=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10))}if(d=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10),parseFloat(d[4]))}if(d=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55)}if(d=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55,parseFloat(d[4]))}if(d=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c)){return f(parseInt(d[1],16),parseInt(d[2],16),parseInt(d[3],16))}if(d=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c)){return f(parseInt(d[1]+d[1],16),parseInt(d[2]+d[2],16),parseInt(d[3]+d[3],16))}var e=b.trim(c).toLowerCase();if(e=="transparent"){return f(255,255,255,0)}else{d=a[e]||[0,0,0];return f(d[0],d[1],d[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function(c){function b(av,ai,J,af){var Q=[],O={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{show:null,position:"bottom",mode:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null,monthNames:null,timeformat:null,twelveHourClock:false},yaxis:{autoscaleMargin:0.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false},shadowSize:3},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},hooks:{}},az=null,ad=null,y=null,H=null,A=null,p=[],aw=[],q={left:0,right:0,top:0,bottom:0},G=0,I=0,h=0,w=0,ak={processOptions:[],processRawData:[],processDatapoints:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},aq=this;aq.setData=aj;aq.setupGrid=t;aq.draw=W;aq.getPlaceholder=function(){return av};aq.getCanvas=function(){return az};aq.getPlotOffset=function(){return q};aq.width=function(){return h};aq.height=function(){return w};aq.offset=function(){var aB=y.offset();aB.left+=q.left;aB.top+=q.top;return aB};aq.getData=function(){return Q};aq.getAxes=function(){var aC={},aB;c.each(p.concat(aw),function(aD,aE){if(aE){aC[aE.direction+(aE.n!=1?aE.n:"")+"axis"]=aE}});return aC};aq.getXAxes=function(){return p};aq.getYAxes=function(){return aw};aq.c2p=C;aq.p2c=ar;aq.getOptions=function(){return O};aq.highlight=x;aq.unhighlight=T;aq.triggerRedrawOverlay=f;aq.pointOffset=function(aB){return{left:parseInt(p[aA(aB,"x")-1].p2c(+aB.x)+q.left),top:parseInt(aw[aA(aB,"y")-1].p2c(+aB.y)+q.top)}};aq.shutdown=ag;aq.resize=function(){B();g(az);g(ad)};aq.hooks=ak;F(aq);Z(J);X();aj(ai);t();W();ah();function an(aD,aB){aB=[aq].concat(aB);for(var aC=0;aC<aD.length;++aC){aD[aC].apply(this,aB)}}function F(){for(var aB=0;aB<af.length;++aB){var aC=af[aB];aC.init(aq);if(aC.options){c.extend(true,O,aC.options)}}}function Z(aC){var aB;c.extend(true,O,aC);if(O.xaxis.color==null){O.xaxis.color=O.grid.color}if(O.yaxis.color==null){O.yaxis.color=O.grid.color}if(O.xaxis.tickColor==null){O.xaxis.tickColor=O.grid.tickColor}if(O.yaxis.tickColor==null){O.yaxis.tickColor=O.grid.tickColor}if(O.grid.borderColor==null){O.grid.borderColor=O.grid.color}if(O.grid.tickColor==null){O.grid.tickColor=c.color.parse(O.grid.color).scale("a",0.22).toString()}for(aB=0;aB<Math.max(1,O.xaxes.length);++aB){O.xaxes[aB]=c.extend(true,{},O.xaxis,O.xaxes[aB])}for(aB=0;aB<Math.max(1,O.yaxes.length);++aB){O.yaxes[aB]=c.extend(true,{},O.yaxis,O.yaxes[aB])}if(O.xaxis.noTicks&&O.xaxis.ticks==null){O.xaxis.ticks=O.xaxis.noTicks}if(O.yaxis.noTicks&&O.yaxis.ticks==null){O.yaxis.ticks=O.yaxis.noTicks}if(O.x2axis){O.xaxes[1]=c.extend(true,{},O.xaxis,O.x2axis);O.xaxes[1].position="top"}if(O.y2axis){O.yaxes[1]=c.extend(true,{},O.yaxis,O.y2axis);O.yaxes[1].position="right"}if(O.grid.coloredAreas){O.grid.markings=O.grid.coloredAreas}if(O.grid.coloredAreasColor){O.grid.markingsColor=O.grid.coloredAreasColor}if(O.lines){c.extend(true,O.series.lines,O.lines)}if(O.points){c.extend(true,O.series.points,O.points)}if(O.bars){c.extend(true,O.series.bars,O.bars)}if(O.shadowSize!=null){O.series.shadowSize=O.shadowSize}for(aB=0;aB<O.xaxes.length;++aB){V(p,aB+1).options=O.xaxes[aB]}for(aB=0;aB<O.yaxes.length;++aB){V(aw,aB+1).options=O.yaxes[aB]}for(var aD in ak){if(O.hooks[aD]&&O.hooks[aD].length){ak[aD]=ak[aD].concat(O.hooks[aD])}}an(ak.processOptions,[O])}function aj(aB){Q=Y(aB);ax();z()}function Y(aE){var aC=[];for(var aB=0;aB<aE.length;++aB){var aD=c.extend(true,{},O.series);if(aE[aB].data!=null){aD.data=aE[aB].data;delete aE[aB].data;c.extend(true,aD,aE[aB]);aE[aB].data=aD.data}else{aD.data=aE[aB]}aC.push(aD)}return aC}function aA(aC,aD){var aB=aC[aD+"axis"];if(typeof aB=="object"){aB=aB.n}if(typeof aB!="number"){aB=1}return aB}function m(){return c.grep(p.concat(aw),function(aB){return aB})}function C(aE){var aC={},aB,aD;for(aB=0;aB<p.length;++aB){aD=p[aB];if(aD&&aD.used){aC["x"+aD.n]=aD.c2p(aE.left)}}for(aB=0;aB<aw.length;++aB){aD=aw[aB];if(aD&&aD.used){aC["y"+aD.n]=aD.c2p(aE.top)}}if(aC.x1!==undefined){aC.x=aC.x1}if(aC.y1!==undefined){aC.y=aC.y1}return aC}function ar(aF){var aD={},aC,aE,aB;for(aC=0;aC<p.length;++aC){aE=p[aC];if(aE&&aE.used){aB="x"+aE.n;if(aF[aB]==null&&aE.n==1){aB="x"}if(aF[aB]!=null){aD.left=aE.p2c(aF[aB]);break}}}for(aC=0;aC<aw.length;++aC){aE=aw[aC];if(aE&&aE.used){aB="y"+aE.n;if(aF[aB]==null&&aE.n==1){aB="y"}if(aF[aB]!=null){aD.top=aE.p2c(aF[aB]);break}}}return aD}function V(aC,aB){if(!aC[aB-1]){aC[aB-1]={n:aB,direction:aC==p?"x":"y",options:c.extend(true,{},aC==p?O.xaxis:O.yaxis)}}return aC[aB-1]}function ax(){var aG;var aM=Q.length,aB=[],aE=[];for(aG=0;aG<Q.length;++aG){var aJ=Q[aG].color;if(aJ!=null){--aM;if(typeof aJ=="number"){aE.push(aJ)}else{aB.push(c.color.parse(Q[aG].color))}}}for(aG=0;aG<aE.length;++aG){aM=Math.max(aM,aE[aG]+1)}var aC=[],aF=0;aG=0;while(aC.length<aM){var aI;if(O.colors.length==aG){aI=c.color.make(100,100,100)}else{aI=c.color.parse(O.colors[aG])}var aD=aF%2==1?-1:1;aI.scale("rgb",1+aD*Math.ceil(aF/2)*0.2);aC.push(aI);++aG;if(aG>=O.colors.length){aG=0;++aF}}var aH=0,aN;for(aG=0;aG<Q.length;++aG){aN=Q[aG];if(aN.color==null){aN.color=aC[aH].toString();++aH}else{if(typeof aN.color=="number"){aN.color=aC[aN.color].toString()}}if(aN.lines.show==null){var aL,aK=true;for(aL in aN){if(aN[aL]&&aN[aL].show){aK=false;break}}if(aK){aN.lines.show=true}}aN.xaxis=V(p,aA(aN,"x"));aN.yaxis=V(aw,aA(aN,"y"))}}function z(){var aO=Number.POSITIVE_INFINITY,aI=Number.NEGATIVE_INFINITY,aB=Number.MAX_VALUE,aU,aS,aR,aN,aD,aJ,aT,aP,aH,aG,aC,a0,aX,aL;function aF(a3,a2,a1){if(a2<a3.datamin&&a2!=-aB){a3.datamin=a2}if(a1>a3.datamax&&a1!=aB){a3.datamax=a1}}c.each(m(),function(a1,a2){a2.datamin=aO;a2.datamax=aI;a2.used=false});for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aJ.datapoints={points:[]};an(ak.processRawData,[aJ,aJ.data,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];var aZ=aJ.data,aW=aJ.datapoints.format;if(!aW){aW=[];aW.push({x:true,number:true,required:true});aW.push({y:true,number:true,required:true});if(aJ.bars.show||(aJ.lines.show&&aJ.lines.fill)){aW.push({y:true,number:true,required:false,defaultValue:0});if(aJ.bars.horizontal){delete aW[aW.length-1].y;aW[aW.length-1].x=true}}aJ.datapoints.format=aW}if(aJ.datapoints.pointsize!=null){continue}aJ.datapoints.pointsize=aW.length;aP=aJ.datapoints.pointsize;aT=aJ.datapoints.points;insertSteps=aJ.lines.show&&aJ.lines.steps;aJ.xaxis.used=aJ.yaxis.used=true;for(aS=aR=0;aS<aZ.length;++aS,aR+=aP){aL=aZ[aS];var aE=aL==null;if(!aE){for(aN=0;aN<aP;++aN){a0=aL[aN];aX=aW[aN];if(aX){if(aX.number&&a0!=null){a0=+a0;if(isNaN(a0)){a0=null}else{if(a0==Infinity){a0=aB}else{if(a0==-Infinity){a0=-aB}}}}if(a0==null){if(aX.required){aE=true}if(aX.defaultValue!=null){a0=aX.defaultValue}}}aT[aR+aN]=a0}}if(aE){for(aN=0;aN<aP;++aN){a0=aT[aR+aN];if(a0!=null){aX=aW[aN];if(aX.x){aF(aJ.xaxis,a0,a0)}if(aX.y){aF(aJ.yaxis,a0,a0)}}aT[aR+aN]=null}}else{if(insertSteps&&aR>0&&aT[aR-aP]!=null&&aT[aR-aP]!=aT[aR]&&aT[aR-aP+1]!=aT[aR+1]){for(aN=0;aN<aP;++aN){aT[aR+aP+aN]=aT[aR+aN]}aT[aR+1]=aT[aR-aP+1];aR+=aP}}}}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];an(ak.processDatapoints,[aJ,aJ.datapoints])}for(aU=0;aU<Q.length;++aU){aJ=Q[aU];aT=aJ.datapoints.points,aP=aJ.datapoints.pointsize;var aK=aO,aQ=aO,aM=aI,aV=aI;for(aS=0;aS<aT.length;aS+=aP){if(aT[aS]==null){continue}for(aN=0;aN<aP;++aN){a0=aT[aS+aN];aX=aW[aN];if(!aX||a0==aB||a0==-aB){continue}if(aX.x){if(a0<aK){aK=a0}if(a0>aM){aM=a0}}if(aX.y){if(a0<aQ){aQ=a0}if(a0>aV){aV=a0}}}}if(aJ.bars.show){var aY=aJ.bars.align=="left"?0:-aJ.bars.barWidth/2;if(aJ.bars.horizontal){aQ+=aY;aV+=aY+aJ.bars.barWidth}else{aK+=aY;aM+=aY+aJ.bars.barWidth}}aF(aJ.xaxis,aK,aM);aF(aJ.yaxis,aQ,aV)}c.each(m(),function(a1,a2){if(a2.datamin==aO){a2.datamin=null}if(a2.datamax==aI){a2.datamax=null}})}function j(aB,aC){var aD=document.createElement("canvas");aD.className=aC;aD.width=G;aD.height=I;if(!aB){c(aD).css({position:"absolute",left:0,top:0})}c(aD).appendTo(av);if(!aD.getContext){aD=window.G_vmlCanvasManager.initElement(aD)}aD.getContext("2d").save();return aD}function B(){G=av.width();I=av.height();if(G<=0||I<=0){throw"Invalid dimensions for plot, width = "+G+", height = "+I}}function g(aC){if(aC.width!=G){aC.width=G}if(aC.height!=I){aC.height=I}var aB=aC.getContext("2d");aB.restore();aB.save()}function X(){var aC,aB=av.children("canvas.base"),aD=av.children("canvas.overlay");if(aB.length==0||aD==0){av.html("");av.css({padding:0});if(av.css("position")=="static"){av.css("position","relative")}B();az=j(true,"base");ad=j(false,"overlay");aC=false}else{az=aB.get(0);ad=aD.get(0);aC=true}H=az.getContext("2d");A=ad.getContext("2d");y=c([ad,az]);if(aC){av.data("plot").shutdown();aq.resize();A.clearRect(0,0,G,I);y.unbind();av.children().not([az,ad]).remove()}av.data("plot",aq)}function ah(){if(O.grid.hoverable){y.mousemove(aa);y.mouseleave(l)}if(O.grid.clickable){y.click(R)}an(ak.bindEvents,[y])}function ag(){if(M){clearTimeout(M)}y.unbind("mousemove",aa);y.unbind("mouseleave",l);y.unbind("click",R);an(ak.shutdown,[y])}function r(aG){function aC(aH){return aH}var aF,aB,aD=aG.options.transform||aC,aE=aG.options.inverseTransform;if(aG.direction=="x"){aF=aG.scale=h/Math.abs(aD(aG.max)-aD(aG.min));aB=Math.min(aD(aG.max),aD(aG.min))}else{aF=aG.scale=w/Math.abs(aD(aG.max)-aD(aG.min));aF=-aF;aB=Math.max(aD(aG.max),aD(aG.min))}if(aD==aC){aG.p2c=function(aH){return(aH-aB)*aF}}else{aG.p2c=function(aH){return(aD(aH)-aB)*aF}}if(!aE){aG.c2p=function(aH){return aB+aH/aF}}else{aG.c2p=function(aH){return aE(aB+aH/aF)}}}function L(aD){var aB=aD.options,aF,aJ=aD.ticks||[],aI=[],aE,aK=aB.labelWidth,aG=aB.labelHeight,aC;function aH(aM,aL){return c('<div style="position:absolute;top:-10000px;'+aL+'font-size:smaller"><div class="'+aD.direction+"Axis "+aD.direction+aD.n+'Axis">'+aM.join("")+"</div></div>").appendTo(av)}if(aD.direction=="x"){if(aK==null){aK=Math.floor(G/(aJ.length>0?aJ.length:1))}if(aG==null){aI=[];for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel" style="float:left;width:'+aK+'px">'+aE+"</div>")}}if(aI.length>0){aI.push('<div style="clear:left"></div>');aC=aH(aI,"width:10000px;");aG=aC.height();aC.remove()}}}else{if(aK==null||aG==null){for(aF=0;aF<aJ.length;++aF){aE=aJ[aF].label;if(aE){aI.push('<div class="tickLabel">'+aE+"</div>")}}if(aI.length>0){aC=aH(aI,"");if(aK==null){aK=aC.children().width()}if(aG==null){aG=aC.find("div.tickLabel").height()}aC.remove()}}}if(aK==null){aK=0}if(aG==null){aG=0}aD.labelWidth=aK;aD.labelHeight=aG}function au(aD){var aC=aD.labelWidth,aL=aD.labelHeight,aH=aD.options.position,aF=aD.options.tickLength,aG=O.grid.axisMargin,aJ=O.grid.labelMargin,aK=aD.direction=="x"?p:aw,aE;var aB=c.grep(aK,function(aN){return aN&&aN.options.position==aH&&aN.reserveSpace});if(c.inArray(aD,aB)==aB.length-1){aG=0}if(aF==null){aF="full"}var aI=c.grep(aK,function(aN){return aN&&aN.reserveSpace});var aM=c.inArray(aD,aI)==0;if(!aM&&aF=="full"){aF=5}if(!isNaN(+aF)){aJ+=+aF}if(aD.direction=="x"){aL+=aJ;if(aH=="bottom"){q.bottom+=aL+aG;aD.box={top:I-q.bottom,height:aL}}else{aD.box={top:q.top+aG,height:aL};q.top+=aL+aG}}else{aC+=aJ;if(aH=="left"){aD.box={left:q.left+aG,width:aC};q.left+=aC+aG}else{q.right+=aC+aG;aD.box={left:G-q.right,width:aC}}}aD.position=aH;aD.tickLength=aF;aD.box.padding=aJ;aD.innermost=aM}function U(aB){if(aB.direction=="x"){aB.box.left=q.left;aB.box.width=h}else{aB.box.top=q.top;aB.box.height=w}}function t(){var aC,aE=m();c.each(aE,function(aF,aG){aG.show=aG.options.show;if(aG.show==null){aG.show=aG.used}aG.reserveSpace=aG.show||aG.options.reserveSpace;n(aG)});allocatedAxes=c.grep(aE,function(aF){return aF.reserveSpace});q.left=q.right=q.top=q.bottom=0;if(O.grid.show){c.each(allocatedAxes,function(aF,aG){S(aG);P(aG);ap(aG,aG.ticks);L(aG)});for(aC=allocatedAxes.length-1;aC>=0;--aC){au(allocatedAxes[aC])}var aD=O.grid.minBorderMargin;if(aD==null){aD=0;for(aC=0;aC<Q.length;++aC){aD=Math.max(aD,Q[aC].points.radius+Q[aC].points.lineWidth/2)}}for(var aB in q){q[aB]+=O.grid.borderWidth;q[aB]=Math.max(aD,q[aB])}}h=G-q.left-q.right;w=I-q.bottom-q.top;c.each(aE,function(aF,aG){r(aG)});if(O.grid.show){c.each(allocatedAxes,function(aF,aG){U(aG)});k()}o()}function n(aE){var aF=aE.options,aD=+(aF.min!=null?aF.min:aE.datamin),aB=+(aF.max!=null?aF.max:aE.datamax),aH=aB-aD;if(aH==0){var aC=aB==0?1:0.01;if(aF.min==null){aD-=aC}if(aF.max==null||aF.min!=null){aB+=aC}}else{var aG=aF.autoscaleMargin;if(aG!=null){if(aF.min==null){aD-=aH*aG;if(aD<0&&aE.datamin!=null&&aE.datamin>=0){aD=0}}if(aF.max==null){aB+=aH*aG;if(aB>0&&aE.datamax!=null&&aE.datamax<=0){aB=0}}}}aE.min=aD;aE.max=aB}function S(aG){var aM=aG.options;var aH;if(typeof aM.ticks=="number"&&aM.ticks>0){aH=aM.ticks}else{aH=0.3*Math.sqrt(aG.direction=="x"?G:I)}var aT=(aG.max-aG.min)/aH,aO,aB,aN,aR,aS,aQ,aI;if(aM.mode=="time"){var aJ={second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000};var aK=[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]];var aC=0;if(aM.minTickSize!=null){if(typeof aM.tickSize=="number"){aC=aM.tickSize}else{aC=aM.minTickSize[0]*aJ[aM.minTickSize[1]]}}for(var aS=0;aS<aK.length-1;++aS){if(aT<(aK[aS][0]*aJ[aK[aS][1]]+aK[aS+1][0]*aJ[aK[aS+1][1]])/2&&aK[aS][0]*aJ[aK[aS][1]]>=aC){break}}aO=aK[aS][0];aN=aK[aS][1];if(aN=="year"){aQ=Math.pow(10,Math.floor(Math.log(aT/aJ.year)/Math.LN10));aI=(aT/aJ.year)/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ}aG.tickSize=aM.tickSize||[aO,aN];aB=function(aX){var a2=[],a0=aX.tickSize[0],a3=aX.tickSize[1],a1=new Date(aX.min);var aW=a0*aJ[a3];if(a3=="second"){a1.setUTCSeconds(a(a1.getUTCSeconds(),a0))}if(a3=="minute"){a1.setUTCMinutes(a(a1.getUTCMinutes(),a0))}if(a3=="hour"){a1.setUTCHours(a(a1.getUTCHours(),a0))}if(a3=="month"){a1.setUTCMonth(a(a1.getUTCMonth(),a0))}if(a3=="year"){a1.setUTCFullYear(a(a1.getUTCFullYear(),a0))}a1.setUTCMilliseconds(0);if(aW>=aJ.minute){a1.setUTCSeconds(0)}if(aW>=aJ.hour){a1.setUTCMinutes(0)}if(aW>=aJ.day){a1.setUTCHours(0)}if(aW>=aJ.day*4){a1.setUTCDate(1)}if(aW>=aJ.year){a1.setUTCMonth(0)}var a5=0,a4=Number.NaN,aY;do{aY=a4;a4=a1.getTime();a2.push(a4);if(a3=="month"){if(a0<1){a1.setUTCDate(1);var aV=a1.getTime();a1.setUTCMonth(a1.getUTCMonth()+1);var aZ=a1.getTime();a1.setTime(a4+a5*aJ.hour+(aZ-aV)*a0);a5=a1.getUTCHours();a1.setUTCHours(0)}else{a1.setUTCMonth(a1.getUTCMonth()+a0)}}else{if(a3=="year"){a1.setUTCFullYear(a1.getUTCFullYear()+a0)}else{a1.setTime(a4+aW)}}}while(a4<aX.max&&a4!=aY);return a2};aR=function(aV,aY){var a0=new Date(aV);if(aM.timeformat!=null){return c.plot.formatDate(a0,aM.timeformat,aM.monthNames)}var aW=aY.tickSize[0]*aJ[aY.tickSize[1]];var aX=aY.max-aY.min;var aZ=(aM.twelveHourClock)?" %p":"";if(aW<aJ.minute){fmt="%h:%M:%S"+aZ}else{if(aW<aJ.day){if(aX<2*aJ.day){fmt="%h:%M"+aZ}else{fmt="%b %d %h:%M"+aZ}}else{if(aW<aJ.month){fmt="%b %d"}else{if(aW<aJ.year){if(aX<aJ.year){fmt="%b"}else{fmt="%b %y"}}else{fmt="%y"}}}}return c.plot.formatDate(a0,fmt,aM.monthNames)}}else{var aU=aM.tickDecimals;var aP=-Math.floor(Math.log(aT)/Math.LN10);if(aU!=null&&aP>aU){aP=aU}aQ=Math.pow(10,-aP);aI=aT/aQ;if(aI<1.5){aO=1}else{if(aI<3){aO=2;if(aI>2.25&&(aU==null||aP+1<=aU)){aO=2.5;++aP}}else{if(aI<7.5){aO=5}else{aO=10}}}aO*=aQ;if(aM.minTickSize!=null&&aO<aM.minTickSize){aO=aM.minTickSize}aG.tickDecimals=Math.max(0,aU!=null?aU:aP);aG.tickSize=aM.tickSize||aO;aB=function(aX){var aZ=[];var a0=a(aX.min,aX.tickSize),aW=0,aV=Number.NaN,aY;do{aY=aV;aV=a0+aW*aX.tickSize;aZ.push(aV);++aW}while(aV<aX.max&&aV!=aY);return aZ};aR=function(aV,aW){return aV.toFixed(aW.tickDecimals)}}if(aM.alignTicksWithAxis!=null){var aF=(aG.direction=="x"?p:aw)[aM.alignTicksWithAxis-1];if(aF&&aF.used&&aF!=aG){var aL=aB(aG);if(aL.length>0){if(aM.min==null){aG.min=Math.min(aG.min,aL[0])}if(aM.max==null&&aL.length>1){aG.max=Math.max(aG.max,aL[aL.length-1])}}aB=function(aX){var aY=[],aV,aW;for(aW=0;aW<aF.ticks.length;++aW){aV=(aF.ticks[aW].v-aF.min)/(aF.max-aF.min);aV=aX.min+aV*(aX.max-aX.min);aY.push(aV)}return aY};if(aG.mode!="time"&&aM.tickDecimals==null){var aE=Math.max(0,-Math.floor(Math.log(aT)/Math.LN10)+1),aD=aB(aG);if(!(aD.length>1&&/\..*0$/.test((aD[1]-aD[0]).toFixed(aE)))){aG.tickDecimals=aE}}}}aG.tickGenerator=aB;if(c.isFunction(aM.tickFormatter)){aG.tickFormatter=function(aV,aW){return""+aM.tickFormatter(aV,aW)}}else{aG.tickFormatter=aR}}function P(aF){var aH=aF.options.ticks,aG=[];if(aH==null||(typeof aH=="number"&&aH>0)){aG=aF.tickGenerator(aF)}else{if(aH){if(c.isFunction(aH)){aG=aH({min:aF.min,max:aF.max})}else{aG=aH}}}var aE,aB;aF.ticks=[];for(aE=0;aE<aG.length;++aE){var aC=null;var aD=aG[aE];if(typeof aD=="object"){aB=+aD[0];if(aD.length>1){aC=aD[1]}}else{aB=+aD}if(aC==null){aC=aF.tickFormatter(aB,aF)}if(!isNaN(aB)){aF.ticks.push({v:aB,label:aC})}}}function ap(aB,aC){if(aB.options.autoscaleMargin&&aC.length>0){if(aB.options.min==null){aB.min=Math.min(aB.min,aC[0].v)}if(aB.options.max==null&&aC.length>1){aB.max=Math.max(aB.max,aC[aC.length-1].v)}}}function W(){H.clearRect(0,0,G,I);var aC=O.grid;if(aC.show&&aC.backgroundColor){N()}if(aC.show&&!aC.aboveData){ac()}for(var aB=0;aB<Q.length;++aB){an(ak.drawSeries,[H,Q[aB]]);d(Q[aB])}an(ak.draw,[H]);if(aC.show&&aC.aboveData){ac()}}function D(aB,aI){var aE,aH,aG,aD,aF=m();for(i=0;i<aF.length;++i){aE=aF[i];if(aE.direction==aI){aD=aI+aE.n+"axis";if(!aB[aD]&&aE.n==1){aD=aI+"axis"}if(aB[aD]){aH=aB[aD].from;aG=aB[aD].to;break}}}if(!aB[aD]){aE=aI=="x"?p[0]:aw[0];aH=aB[aI+"1"];aG=aB[aI+"2"]}if(aH!=null&&aG!=null&&aH>aG){var aC=aH;aH=aG;aG=aC}return{from:aH,to:aG,axis:aE}}function N(){H.save();H.translate(q.left,q.top);H.fillStyle=am(O.grid.backgroundColor,w,0,"rgba(255, 255, 255, 0)");H.fillRect(0,0,h,w);H.restore()}function ac(){var aF;H.save();H.translate(q.left,q.top);var aH=O.grid.markings;if(aH){if(c.isFunction(aH)){var aK=aq.getAxes();aK.xmin=aK.xaxis.min;aK.xmax=aK.xaxis.max;aK.ymin=aK.yaxis.min;aK.ymax=aK.yaxis.max;aH=aH(aK)}for(aF=0;aF<aH.length;++aF){var aD=aH[aF],aC=D(aD,"x"),aI=D(aD,"y");if(aC.from==null){aC.from=aC.axis.min}if(aC.to==null){aC.to=aC.axis.max}if(aI.from==null){aI.from=aI.axis.min}if(aI.to==null){aI.to=aI.axis.max}if(aC.to<aC.axis.min||aC.from>aC.axis.max||aI.to<aI.axis.min||aI.from>aI.axis.max){continue}aC.from=Math.max(aC.from,aC.axis.min);aC.to=Math.min(aC.to,aC.axis.max);aI.from=Math.max(aI.from,aI.axis.min);aI.to=Math.min(aI.to,aI.axis.max);if(aC.from==aC.to&&aI.from==aI.to){continue}aC.from=aC.axis.p2c(aC.from);aC.to=aC.axis.p2c(aC.to);aI.from=aI.axis.p2c(aI.from);aI.to=aI.axis.p2c(aI.to);if(aC.from==aC.to||aI.from==aI.to){H.beginPath();H.strokeStyle=aD.color||O.grid.markingsColor;H.lineWidth=aD.lineWidth||O.grid.markingsLineWidth;H.moveTo(aC.from,aI.from);H.lineTo(aC.to,aI.to);H.stroke()}else{H.fillStyle=aD.color||O.grid.markingsColor;H.fillRect(aC.from,aI.to,aC.to-aC.from,aI.from-aI.to)}}}var aK=m(),aM=O.grid.borderWidth;for(var aE=0;aE<aK.length;++aE){var aB=aK[aE],aG=aB.box,aQ=aB.tickLength,aN,aL,aP,aJ;if(!aB.show||aB.ticks.length==0){continue}H.strokeStyle=aB.options.tickColor||c.color.parse(aB.options.color).scale("a",0.22).toString();H.lineWidth=1;if(aB.direction=="x"){aN=0;if(aQ=="full"){aL=(aB.position=="top"?0:w)}else{aL=aG.top-q.top+(aB.position=="top"?aG.height:0)}}else{aL=0;if(aQ=="full"){aN=(aB.position=="left"?0:h)}else{aN=aG.left-q.left+(aB.position=="left"?aG.width:0)}}if(!aB.innermost){H.beginPath();aP=aJ=0;if(aB.direction=="x"){aP=h}else{aJ=w}if(H.lineWidth==1){aN=Math.floor(aN)+0.5;aL=Math.floor(aL)+0.5}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ);H.stroke()}H.beginPath();for(aF=0;aF<aB.ticks.length;++aF){var aO=aB.ticks[aF].v;aP=aJ=0;if(aO<aB.min||aO>aB.max||(aQ=="full"&&aM>0&&(aO==aB.min||aO==aB.max))){continue}if(aB.direction=="x"){aN=aB.p2c(aO);aJ=aQ=="full"?-w:aQ;if(aB.position=="top"){aJ=-aJ}}else{aL=aB.p2c(aO);aP=aQ=="full"?-h:aQ;if(aB.position=="left"){aP=-aP}}if(H.lineWidth==1){if(aB.direction=="x"){aN=Math.floor(aN)+0.5}else{aL=Math.floor(aL)+0.5}}H.moveTo(aN,aL);H.lineTo(aN+aP,aL+aJ)}H.stroke()}if(aM){H.lineWidth=aM;H.strokeStyle=O.grid.borderColor;H.strokeRect(-aM/2,-aM/2,h+aM,w+aM)}H.restore()}function k(){av.find(".tickLabels").remove();var aG=['<div class="tickLabels" style="font-size:smaller">'];var aJ=m();for(var aD=0;aD<aJ.length;++aD){var aC=aJ[aD],aF=aC.box;if(!aC.show){continue}aG.push('<div class="'+aC.direction+"Axis "+aC.direction+aC.n+'Axis" style="color:'+aC.options.color+'">');for(var aE=0;aE<aC.ticks.length;++aE){var aH=aC.ticks[aE];if(!aH.label||aH.v<aC.min||aH.v>aC.max){continue}var aK={},aI;if(aC.direction=="x"){aI="center";aK.left=Math.round(q.left+aC.p2c(aH.v)-aC.labelWidth/2);if(aC.position=="bottom"){aK.top=aF.top+aF.padding}else{aK.bottom=I-(aF.top+aF.height-aF.padding)}}else{aK.top=Math.round(q.top+aC.p2c(aH.v)-aC.labelHeight/2);if(aC.position=="left"){aK.right=G-(aF.left+aF.width-aF.padding);aI="right"}else{aK.left=aF.left+aF.padding;aI="left"}}aK.width=aC.labelWidth;var aB=["position:absolute","text-align:"+aI];for(var aL in aK){aB.push(aL+":"+aK[aL]+"px")}aG.push('<div class="tickLabel" style="'+aB.join(";")+'">'+aH.label+"</div>")}aG.push("</div>")}aG.push("</div>");av.append(aG.join(""))}function d(aB){if(aB.lines.show){at(aB)}if(aB.bars.show){e(aB)}if(aB.points.show){ao(aB)}}function at(aE){function aD(aP,aQ,aI,aU,aT){var aV=aP.points,aJ=aP.pointsize,aN=null,aM=null;H.beginPath();for(var aO=aJ;aO<aV.length;aO+=aJ){var aL=aV[aO-aJ],aS=aV[aO-aJ+1],aK=aV[aO],aR=aV[aO+1];if(aL==null||aK==null){continue}if(aS<=aR&&aS<aT.min){if(aR<aT.min){continue}aL=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.min}else{if(aR<=aS&&aR<aT.min){if(aS<aT.min){continue}aK=(aT.min-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.min}}if(aS>=aR&&aS>aT.max){if(aR>aT.max){continue}aL=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aS=aT.max}else{if(aR>=aS&&aR>aT.max){if(aS>aT.max){continue}aK=(aT.max-aS)/(aR-aS)*(aK-aL)+aL;aR=aT.max}}if(aL<=aK&&aL<aU.min){if(aK<aU.min){continue}aS=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.min}else{if(aK<=aL&&aK<aU.min){if(aL<aU.min){continue}aR=(aU.min-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.min}}if(aL>=aK&&aL>aU.max){if(aK>aU.max){continue}aS=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aL=aU.max}else{if(aK>=aL&&aK>aU.max){if(aL>aU.max){continue}aR=(aU.max-aL)/(aK-aL)*(aR-aS)+aS;aK=aU.max}}if(aL!=aN||aS!=aM){H.moveTo(aU.p2c(aL)+aQ,aT.p2c(aS)+aI)}aN=aK;aM=aR;H.lineTo(aU.p2c(aK)+aQ,aT.p2c(aR)+aI)}H.stroke()}function aF(aI,aQ,aP){var aW=aI.points,aV=aI.pointsize,aN=Math.min(Math.max(0,aP.min),aP.max),aX=0,aU,aT=false,aM=1,aL=0,aR=0;while(true){if(aV>0&&aX>aW.length+aV){break}aX+=aV;var aZ=aW[aX-aV],aK=aW[aX-aV+aM],aY=aW[aX],aJ=aW[aX+aM];if(aT){if(aV>0&&aZ!=null&&aY==null){aR=aX;aV=-aV;aM=2;continue}if(aV<0&&aX==aL+aV){H.fill();aT=false;aV=-aV;aM=1;aX=aL=aR+aV;continue}}if(aZ==null||aY==null){continue}if(aZ<=aY&&aZ<aQ.min){if(aY<aQ.min){continue}aK=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.min}else{if(aY<=aZ&&aY<aQ.min){if(aZ<aQ.min){continue}aJ=(aQ.min-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.min}}if(aZ>=aY&&aZ>aQ.max){if(aY>aQ.max){continue}aK=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aZ=aQ.max}else{if(aY>=aZ&&aY>aQ.max){if(aZ>aQ.max){continue}aJ=(aQ.max-aZ)/(aY-aZ)*(aJ-aK)+aK;aY=aQ.max}}if(!aT){H.beginPath();H.moveTo(aQ.p2c(aZ),aP.p2c(aN));aT=true}if(aK>=aP.max&&aJ>=aP.max){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.max));H.lineTo(aQ.p2c(aY),aP.p2c(aP.max));continue}else{if(aK<=aP.min&&aJ<=aP.min){H.lineTo(aQ.p2c(aZ),aP.p2c(aP.min));H.lineTo(aQ.p2c(aY),aP.p2c(aP.min));continue}}var aO=aZ,aS=aY;if(aK<=aJ&&aK<aP.min&&aJ>=aP.min){aZ=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.min}else{if(aJ<=aK&&aJ<aP.min&&aK>=aP.min){aY=(aP.min-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.min}}if(aK>=aJ&&aK>aP.max&&aJ<=aP.max){aZ=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aK=aP.max}else{if(aJ>=aK&&aJ>aP.max&&aK<=aP.max){aY=(aP.max-aK)/(aJ-aK)*(aY-aZ)+aZ;aJ=aP.max}}if(aZ!=aO){H.lineTo(aQ.p2c(aO),aP.p2c(aK))}H.lineTo(aQ.p2c(aZ),aP.p2c(aK));H.lineTo(aQ.p2c(aY),aP.p2c(aJ));if(aY!=aS){H.lineTo(aQ.p2c(aY),aP.p2c(aJ));H.lineTo(aQ.p2c(aS),aP.p2c(aJ))}}}H.save();H.translate(q.left,q.top);H.lineJoin="round";var aG=aE.lines.lineWidth,aB=aE.shadowSize;if(aG>0&&aB>0){H.lineWidth=aB;H.strokeStyle="rgba(0,0,0,0.1)";var aH=Math.PI/18;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/2),Math.cos(aH)*(aG/2+aB/2),aE.xaxis,aE.yaxis);H.lineWidth=aB/2;aD(aE.datapoints,Math.sin(aH)*(aG/2+aB/4),Math.cos(aH)*(aG/2+aB/4),aE.xaxis,aE.yaxis)}H.lineWidth=aG;H.strokeStyle=aE.color;var aC=ae(aE.lines,aE.color,0,w);if(aC){H.fillStyle=aC;aF(aE.datapoints,aE.xaxis,aE.yaxis)}if(aG>0){aD(aE.datapoints,0,0,aE.xaxis,aE.yaxis)}H.restore()}function ao(aE){function aH(aN,aM,aU,aK,aS,aT,aQ,aJ){var aR=aN.points,aI=aN.pointsize;for(var aL=0;aL<aR.length;aL+=aI){var aP=aR[aL],aO=aR[aL+1];if(aP==null||aP<aT.min||aP>aT.max||aO<aQ.min||aO>aQ.max){continue}H.beginPath();aP=aT.p2c(aP);aO=aQ.p2c(aO)+aK;if(aJ=="circle"){H.arc(aP,aO,aM,0,aS?Math.PI:Math.PI*2,false)}else{aJ(H,aP,aO,aM,aS)}H.closePath();if(aU){H.fillStyle=aU;H.fill()}H.stroke()}}H.save();H.translate(q.left,q.top);var aG=aE.points.lineWidth,aC=aE.shadowSize,aB=aE.points.radius,aF=aE.points.symbol;if(aG>0&&aC>0){var aD=aC/2;H.lineWidth=aD;H.strokeStyle="rgba(0,0,0,0.1)";aH(aE.datapoints,aB,null,aD+aD/2,true,aE.xaxis,aE.yaxis,aF);H.strokeStyle="rgba(0,0,0,0.2)";aH(aE.datapoints,aB,null,aD/2,true,aE.xaxis,aE.yaxis,aF)}H.lineWidth=aG;H.strokeStyle=aE.color;aH(aE.datapoints,aB,ae(aE.points,aE.color),0,false,aE.xaxis,aE.yaxis,aF);H.restore()}function E(aN,aM,aV,aI,aQ,aF,aD,aL,aK,aU,aR,aC){var aE,aT,aJ,aP,aG,aB,aO,aH,aS;if(aR){aH=aB=aO=true;aG=false;aE=aV;aT=aN;aP=aM+aI;aJ=aM+aQ;if(aT<aE){aS=aT;aT=aE;aE=aS;aG=true;aB=false}}else{aG=aB=aO=true;aH=false;aE=aN+aI;aT=aN+aQ;aJ=aV;aP=aM;if(aP<aJ){aS=aP;aP=aJ;aJ=aS;aH=true;aO=false}}if(aT<aL.min||aE>aL.max||aP<aK.min||aJ>aK.max){return}if(aE<aL.min){aE=aL.min;aG=false}if(aT>aL.max){aT=aL.max;aB=false}if(aJ<aK.min){aJ=aK.min;aH=false}if(aP>aK.max){aP=aK.max;aO=false}aE=aL.p2c(aE);aJ=aK.p2c(aJ);aT=aL.p2c(aT);aP=aK.p2c(aP);if(aD){aU.beginPath();aU.moveTo(aE,aJ);aU.lineTo(aE,aP);aU.lineTo(aT,aP);aU.lineTo(aT,aJ);aU.fillStyle=aD(aJ,aP);aU.fill()}if(aC>0&&(aG||aB||aO||aH)){aU.beginPath();aU.moveTo(aE,aJ+aF);if(aG){aU.lineTo(aE,aP+aF)}else{aU.moveTo(aE,aP+aF)}if(aO){aU.lineTo(aT,aP+aF)}else{aU.moveTo(aT,aP+aF)}if(aB){aU.lineTo(aT,aJ+aF)}else{aU.moveTo(aT,aJ+aF)}if(aH){aU.lineTo(aE,aJ+aF)}else{aU.moveTo(aE,aJ+aF)}aU.stroke()}}function e(aD){function aC(aJ,aI,aL,aG,aK,aN,aM){var aO=aJ.points,aF=aJ.pointsize;for(var aH=0;aH<aO.length;aH+=aF){if(aO[aH]==null){continue}E(aO[aH],aO[aH+1],aO[aH+2],aI,aL,aG,aK,aN,aM,H,aD.bars.horizontal,aD.bars.lineWidth)}}H.save();H.translate(q.left,q.top);H.lineWidth=aD.bars.lineWidth;H.strokeStyle=aD.color;var aB=aD.bars.align=="left"?0:-aD.bars.barWidth/2;var aE=aD.bars.fill?function(aF,aG){return ae(aD.bars,aD.color,aF,aG)}:null;aC(aD.datapoints,aB,aB+aD.bars.barWidth,0,aE,aD.xaxis,aD.yaxis);H.restore()}function ae(aD,aB,aC,aF){var aE=aD.fill;if(!aE){return null}if(aD.fillColor){return am(aD.fillColor,aC,aF,aB)}var aG=c.color.parse(aB);aG.a=typeof aE=="number"?aE:0.4;aG.normalize();return aG.toString()}function o(){av.find(".legend").remove();if(!O.legend.show){return}var aH=[],aF=false,aN=O.legend.labelFormatter,aM,aJ;for(var aE=0;aE<Q.length;++aE){aM=Q[aE];aJ=aM.label;if(!aJ){continue}if(aE%O.legend.noColumns==0){if(aF){aH.push("</tr>")}aH.push("<tr>");aF=true}if(aN){aJ=aN(aJ,aM)}aH.push('<td class="legendColorBox"><div style="border:1px solid '+O.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+aM.color+';overflow:hidden"></div></div></td><td class="legendLabel">'+aJ+"</td>")}if(aF){aH.push("</tr>")}if(aH.length==0){return}var aL='<table style="font-size:smaller;color:'+O.grid.color+'">'+aH.join("")+"</table>";if(O.legend.container!=null){c(O.legend.container).html(aL)}else{var aI="",aC=O.legend.position,aD=O.legend.margin;if(aD[0]==null){aD=[aD,aD]}if(aC.charAt(0)=="n"){aI+="top:"+(aD[1]+q.top)+"px;"}else{if(aC.charAt(0)=="s"){aI+="bottom:"+(aD[1]+q.bottom)+"px;"}}if(aC.charAt(1)=="e"){aI+="right:"+(aD[0]+q.right)+"px;"}else{if(aC.charAt(1)=="w"){aI+="left:"+(aD[0]+q.left)+"px;"}}var aK=c('<div class="legend">'+aL.replace('style="','style="position:absolute;'+aI+";")+"</div>").appendTo(av);if(O.legend.backgroundOpacity!=0){var aG=O.legend.backgroundColor;if(aG==null){aG=O.grid.backgroundColor;if(aG&&typeof aG=="string"){aG=c.color.parse(aG)}else{aG=c.color.extract(aK,"background-color")}aG.a=1;aG=aG.toString()}var aB=aK.children();c('<div style="position:absolute;width:'+aB.width()+"px;height:"+aB.height()+"px;"+aI+"background-color:"+aG+';"> </div>').prependTo(aK).css("opacity",O.legend.backgroundOpacity)}}}var ab=[],M=null;function K(aI,aG,aD){var aO=O.grid.mouseActiveRadius,a0=aO*aO+1,aY=null,aR=false,aW,aU;for(aW=Q.length-1;aW>=0;--aW){if(!aD(Q[aW])){continue}var aP=Q[aW],aH=aP.xaxis,aF=aP.yaxis,aV=aP.datapoints.points,aT=aP.datapoints.pointsize,aQ=aH.c2p(aI),aN=aF.c2p(aG),aC=aO/aH.scale,aB=aO/aF.scale;if(aH.options.inverseTransform){aC=Number.MAX_VALUE}if(aF.options.inverseTransform){aB=Number.MAX_VALUE}if(aP.lines.show||aP.points.show){for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1];if(aK==null){continue}if(aK-aQ>aC||aK-aQ<-aC||aJ-aN>aB||aJ-aN<-aB){continue}var aM=Math.abs(aH.p2c(aK)-aI),aL=Math.abs(aF.p2c(aJ)-aG),aS=aM*aM+aL*aL;if(aS<a0){a0=aS;aY=[aW,aU/aT]}}}if(aP.bars.show&&!aY){var aE=aP.bars.align=="left"?0:-aP.bars.barWidth/2,aX=aE+aP.bars.barWidth;for(aU=0;aU<aV.length;aU+=aT){var aK=aV[aU],aJ=aV[aU+1],aZ=aV[aU+2];if(aK==null){continue}if(Q[aW].bars.horizontal?(aQ<=Math.max(aZ,aK)&&aQ>=Math.min(aZ,aK)&&aN>=aJ+aE&&aN<=aJ+aX):(aQ>=aK+aE&&aQ<=aK+aX&&aN>=Math.min(aZ,aJ)&&aN<=Math.max(aZ,aJ))){aY=[aW,aU/aT]}}}}if(aY){aW=aY[0];aU=aY[1];aT=Q[aW].datapoints.pointsize;return{datapoint:Q[aW].datapoints.points.slice(aU*aT,(aU+1)*aT),dataIndex:aU,series:Q[aW],seriesIndex:aW}}return null}function aa(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return aC.hoverable!=false})}}function l(aB){if(O.grid.hoverable){u("plothover",aB,function(aC){return false})}}function R(aB){u("plotclick",aB,function(aC){return aC.clickable!=false})}function u(aC,aB,aD){var aE=y.offset(),aH=aB.pageX-aE.left-q.left,aF=aB.pageY-aE.top-q.top,aJ=C({left:aH,top:aF});aJ.pageX=aB.pageX;aJ.pageY=aB.pageY;var aK=K(aH,aF,aD);if(aK){aK.pageX=parseInt(aK.series.xaxis.p2c(aK.datapoint[0])+aE.left+q.left);aK.pageY=parseInt(aK.series.yaxis.p2c(aK.datapoint[1])+aE.top+q.top)}if(O.grid.autoHighlight){for(var aG=0;aG<ab.length;++aG){var aI=ab[aG];if(aI.auto==aC&&!(aK&&aI.series==aK.series&&aI.point[0]==aK.datapoint[0]&&aI.point[1]==aK.datapoint[1])){T(aI.series,aI.point)}}if(aK){x(aK.series,aK.datapoint,aC)}}av.trigger(aC,[aJ,aK])}function f(){if(!M){M=setTimeout(s,30)}}function s(){M=null;A.save();A.clearRect(0,0,G,I);A.translate(q.left,q.top);var aC,aB;for(aC=0;aC<ab.length;++aC){aB=ab[aC];if(aB.series.bars.show){v(aB.series,aB.point)}else{ay(aB.series,aB.point)}}A.restore();an(ak.drawOverlay,[A])}function x(aD,aB,aF){if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){var aE=aD.datapoints.pointsize;aB=aD.datapoints.points.slice(aE*aB,aE*(aB+1))}var aC=al(aD,aB);if(aC==-1){ab.push({series:aD,point:aB,auto:aF});f()}else{if(!aF){ab[aC].auto=false}}}function T(aD,aB){if(aD==null&&aB==null){ab=[];f()}if(typeof aD=="number"){aD=Q[aD]}if(typeof aB=="number"){aB=aD.data[aB]}var aC=al(aD,aB);if(aC!=-1){ab.splice(aC,1);f()}}function al(aD,aE){for(var aB=0;aB<ab.length;++aB){var aC=ab[aB];if(aC.series==aD&&aC.point[0]==aE[0]&&aC.point[1]==aE[1]){return aB}}return -1}function ay(aE,aD){var aC=aD[0],aI=aD[1],aH=aE.xaxis,aG=aE.yaxis;if(aC<aH.min||aC>aH.max||aI<aG.min||aI>aG.max){return}var aF=aE.points.radius+aE.points.lineWidth/2;A.lineWidth=aF;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aB=1.5*aF,aC=aH.p2c(aC),aI=aG.p2c(aI);A.beginPath();if(aE.points.symbol=="circle"){A.arc(aC,aI,aB,0,2*Math.PI,false)}else{aE.points.symbol(A,aC,aI,aB,false)}A.closePath();A.stroke()}function v(aE,aB){A.lineWidth=aE.bars.lineWidth;A.strokeStyle=c.color.parse(aE.color).scale("a",0.5).toString();var aD=c.color.parse(aE.color).scale("a",0.5).toString();var aC=aE.bars.align=="left"?0:-aE.bars.barWidth/2;E(aB[0],aB[1],aB[2]||0,aC,aC+aE.bars.barWidth,0,function(){return aD},aE.xaxis,aE.yaxis,A,aE.bars.horizontal,aE.bars.lineWidth)}function am(aJ,aB,aH,aC){if(typeof aJ=="string"){return aJ}else{var aI=H.createLinearGradient(0,aH,0,aB);for(var aE=0,aD=aJ.colors.length;aE<aD;++aE){var aF=aJ.colors[aE];if(typeof aF!="string"){var aG=c.color.parse(aC);if(aF.brightness!=null){aG=aG.scale("rgb",aF.brightness)}if(aF.opacity!=null){aG.a*=aF.opacity}aF=aG.toString()}aI.addColorStop(aE/(aD-1),aF)}return aI}}}c.plot=function(g,e,d){var f=new b(c(g),e,d,c.plot.plugins);return f};c.plot.version="0.7";c.plot.plugins=[];c.plot.formatDate=function(l,f,h){var o=function(d){d=""+d;return d.length==1?"0"+d:d};var e=[];var p=false,j=false;var n=l.getUTCHours();var k=n<12;if(h==null){h=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}if(f.search(/%p|%P/)!=-1){if(n>12){n=n-12}else{if(n==0){n=12}}}for(var g=0;g<f.length;++g){var m=f.charAt(g);if(p){switch(m){case"h":m=""+n;break;case"H":m=o(n);break;case"M":m=o(l.getUTCMinutes());break;case"S":m=o(l.getUTCSeconds());break;case"d":m=""+l.getUTCDate();break;case"m":m=""+(l.getUTCMonth()+1);break;case"y":m=""+l.getUTCFullYear();break;case"b":m=""+h[l.getUTCMonth()];break;case"p":m=(k)?("am"):("pm");break;case"P":m=(k)?("AM"):("PM");break;case"0":m="";j=true;break}if(m&&j){m=o(m);j=false}e.push(m);if(!j){p=false}}else{if(m=="%"){p=true}else{e.push(m)}}}return e.join("")};function a(e,d){return d*Math.floor(e/d)}})(jQuery);
\ No newline at end of file
+ * Inspiration from jQuery color animation plugin by John Resig.
+ *
+ * Released under the MIT license by Ole Laursen, October 2009.
+ *
+ * Examples:
+ *
+ *   $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
+ *   var c = $.color.extract($("#mydiv"), 'background-color');
+ *   console.log(c.r, c.g, c.b, c.a);
+ *   $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
+ *
+ * Note that .scale() and .add() return the same modified object
+ * instead of making a new one.
+ *
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
+ * produce a color rather than just crashing.
+ */(function(e){e.color={},e.color.make=function(t,n,r,i){var s={};return s.r=t||0,s.g=n||0,s.b=r||0,s.a=i!=null?i:1,s.add=function(e,t){for(var n=0;n<e.length;++n)s[e.charAt(n)]+=t;return s.normalize()},s.scale=function(e,t){for(var n=0;n<e.length;++n)s[e.charAt(n)]*=t;return s.normalize()},s.toString=function(){return s.a>=1?"rgb("+[s.r,s.g,s.b].join(",")+")":"rgba("+[s.r,s.g,s.b,s.a].join(",")+")"},s.normalize=function(){function e(e,t,n){return t<e?e:t>n?n:t}return s.r=e(0,parseInt(s.r),255),s.g=e(0,parseInt(s.g),255),s.b=e(0,parseInt(s.b),255),s.a=e(0,s.a,1),s},s.clone=function(){return e.color.make(s.r,s.b,s.g,s.a)},s.normalize()},e.color.extract=function(t,n){var r;do{r=t.css(n).toLowerCase();if(r!=""&&r!="transparent")break;t=t.parent()}while(!e.nodeName(t.get(0),"body"));return r=="rgba(0, 0, 0, 0)"&&(r="transparent"),e.color.parse(r)},e.color.parse=function(n){var r,i=e.color.make;if(r=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(n))return i(parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10));if(r=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(n))return i(parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10),parseFloat(r[4]));if(r=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(n))return i(parseFloat(r[1])*2.55,parseFloat(r[2])*2.55,parseFloat(r[3])*2.55);if(r=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(n))return i(parseFloat(r[1])*2.55,parseFloat(r[2])*2.55,parseFloat(r[3])*2.55,parseFloat(r[4]));if(r=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(n))return i(parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16));if(r=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(n))return i(parseInt(r[1]+r[1],16),parseInt(r[2]+r[2],16),parseInt(r[3]+r[3],16));var s=e.trim(n).toLowerCase();return s=="transparent"?i(255,255,255,0):(r=t[s]||[0,0,0],i(r[0],r[1],r[2]))};var t={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery),function(e){function n(t,n){var r=n.children("."+t)[0];if(r==null){r=document.createElement("canvas"),r.className=t,e(r).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(n);if(!r.getContext){if(!window.G_vmlCanvasManager)throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.");r=window.G_vmlCanvasManager.initElement(r)}}this.element=r;var i=this.context=r.getContext("2d"),s=window.devicePixelRatio||1,o=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1;this.pixelRatio=s/o,this.resize(n.width(),n.height()),this.textContainer=null,this.text={},this._textCache={}}function r(t,r,s,o){function E(e,t){t=[w].concat(t);for(var n=0;n<e.length;++n)e[n].apply(this,t)}function S(){var t={Canvas:n};for(var r=0;r<o.length;++r){var i=o[r];i.init(w,t),i.options&&e.extend(!0,a,i.options)}}function x(n){e.extend(!0,a,n),n&&n.colors&&(a.colors=n.colors),a.xaxis.color==null&&(a.xaxis.color=e.color.parse(a.grid.color).scale("a",.22).toString()),a.yaxis.color==null&&(a.yaxis.color=e.color.parse(a.grid.color).scale("a",.22).toString()),a.xaxis.tickColor==null&&(a.xaxis.tickColor=a.grid.tickColor||a.xaxis.color),a.yaxis.tickColor==null&&(a.yaxis.tickColor=a.grid.tickColor||a.yaxis.color),a.grid.borderColor==null&&(a.grid.borderColor=a.grid.color),a.grid.tickColor==null&&(a.grid.tickColor=e.color.parse(a.grid.color).scale("a",.22).toString());var r,i,s,o={style:t.css("font-style"),size:Math.round(.8*(+t.css("font-size").replace("px","")||13)),variant:t.css("font-variant"),weight:t.css("font-weight"),family:t.css("font-family")};o.lineHeight=o.size*1.15,s=a.xaxes.length||1;for(r=0;r<s;++r)i=a.xaxes[r],i&&!i.tickColor&&(i.tickColor=i.color),i=e.extend(!0,{},a.xaxis,i),a.xaxes[r]=i,i.font&&(i.font=e.extend({},o,i.font),i.font.color||(i.font.color=i.color));s=a.yaxes.length||1;for(r=0;r<s;++r)i=a.yaxes[r],i&&!i.tickColor&&(i.tickColor=i.color),i=e.extend(!0,{},a.yaxis,i),a.yaxes[r]=i,i.font&&(i.font=e.extend({},o,i.font),i.font.color||(i.font.color=i.color));a.xaxis.noTicks&&a.xaxis.ticks==null&&(a.xaxis.ticks=a.xaxis.noTicks),a.yaxis.noTicks&&a.yaxis.ticks==null&&(a.yaxis.ticks=a.yaxis.noTicks),a.x2axis&&(a.xaxes[1]=e.extend(!0,{},a.xaxis,a.x2axis),a.xaxes[1].position="top"),a.y2axis&&(a.yaxes[1]=e.extend(!0,{},a.yaxis,a.y2axis),a.yaxes[1].position="right"),a.grid.coloredAreas&&(a.grid.markings=a.grid.coloredAreas),a.grid.coloredAreasColor&&(a.grid.markingsColor=a.grid.coloredAreasColor),a.lines&&e.extend(!0,a.series.lines,a.lines),a.points&&e.extend(!0,a.series.points,a.points),a.bars&&e.extend(!0,a.series.bars,a.bars),a.shadowSize!=null&&(a.series.shadowSize=a.shadowSize),a.highlightColor!=null&&(a.series.highlightColor=a.highlightColor);for(r=0;r<a.xaxes.length;++r)O(d,r+1).options=a.xaxes[r];for(r=0;r<a.yaxes.length;++r)O(v,r+1).options=a.yaxes[r];for(var u in b)a.hooks[u]&&a.hooks[u].length&&(b[u]=b[u].concat(a.hooks[u]));E(b.processOptions,[a])}function T(e){u=N(e),M(),_()}function N(t){var n=[];for(var r=0;r<t.length;++r){var i=e.extend(!0,{},a.series);t[r].data!=null?(i.data=t[r].data,delete t[r].data,e.extend(!0,i,t[r]),t[r].data=i.data):i.data=t[r],n.push(i)}return n}function C(e,t){var n=e[t+"axis"];return typeof n=="object"&&(n=n.n),typeof n!="number"&&(n=1),n}function k(){return e.grep(d.concat(v),function(e){return e})}function L(e){var t={},n,r;for(n=0;n<d.length;++n)r=d[n],r&&r.used&&(t["x"+r.n]=r.c2p(e.left));for(n=0;n<v.length;++n)r=v[n],r&&r.used&&(t["y"+r.n]=r.c2p(e.top));return t.x1!==undefined&&(t.x=t.x1),t.y1!==undefined&&(t.y=t.y1),t}function A(e){var t={},n,r,i;for(n=0;n<d.length;++n){r=d[n];if(r&&r.used){i="x"+r.n,e[i]==null&&r.n==1&&(i="x");if(e[i]!=null){t.left=r.p2c(e[i]);break}}}for(n=0;n<v.length;++n){r=v[n];if(r&&r.used){i="y"+r.n,e[i]==null&&r.n==1&&(i="y");if(e[i]!=null){t.top=r.p2c(e[i]);break}}}return t}function O(t,n){return t[n-1]||(t[n-1]={n:n,direction:t==d?"x":"y",options:e.extend(!0,{},t==d?a.xaxis:a.yaxis)}),t[n-1]}function M(){var t=u.length,n=-1,r;for(r=0;r<u.length;++r){var i=u[r].color;i!=null&&(t--,typeof i=="number"&&i>n&&(n=i))}t<=n&&(t=n+1);var s,o=[],f=a.colors,l=f.length,c=0;for(r=0;r<t;r++)s=e.color.parse(f[r%l]||"#666"),r%l==0&&r&&(c>=0?c<.5?c=-c-.2:c=0:c=-c),o[r]=s.scale("rgb",1+c);var h=0,p;for(r=0;r<u.length;++r){p=u[r],p.color==null?(p.color=o[h].toString(),++h):typeof p.color=="number"&&(p.color=o[p.color].toString());if(p.lines.show==null){var m,g=!0;for(m in p)if(p[m]&&p[m].show){g=!1;break}g&&(p.lines.show=!0)}p.lines.zero==null&&(p.lines.zero=!!p.lines.fill),p.xaxis=O(d,C(p,"x")),p.yaxis=O(v,C(p,"y"))}}function _(){function x(e,t,n){t<e.datamin&&t!=-r&&(e.datamin=t),n>e.datamax&&n!=r&&(e.datamax=n)}var t=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY,r=Number.MAX_VALUE,i,s,o,a,f,l,c,h,p,d,v,m,g,y,w,S;e.each(k(),function(e,r){r.datamin=t,r.datamax=n,r.used=!1});for(i=0;i<u.length;++i)l=u[i],l.datapoints={points:[]},E(b.processRawData,[l,l.data,l.datapoints]);for(i=0;i<u.length;++i){l=u[i],w=l.data,S=l.datapoints.format;if(!S){S=[],S.push({x:!0,number:!0,required:!0}),S.push({y:!0,number:!0,required:!0});if(l.bars.show||l.lines.show&&l.lines.fill){var T=!!(l.bars.show&&l.bars.zero||l.lines.show&&l.lines.zero);S.push({y:!0,number:!0,required:!1,defaultValue:0,autoscale:T}),l.bars.horizontal&&(delete S[S.length-1].y,S[S.length-1].x=!0)}l.datapoints.format=S}if(l.datapoints.pointsize!=null)continue;l.datapoints.pointsize=S.length,h=l.datapoints.pointsize,c=l.datapoints.points;var N=l.lines.show&&l.lines.steps;l.xaxis.used=l.yaxis.used=!0;for(s=o=0;s<w.length;++s,o+=h){y=w[s];var C=y==null;if(!C)for(a=0;a<h;++a)m=y[a],g=S[a],g&&(g.number&&m!=null&&(m=+m,isNaN(m)?m=null:m==Infinity?m=r:m==-Infinity&&(m=-r)),m==null&&(g.required&&(C=!0),g.defaultValue!=null&&(m=g.defaultValue))),c[o+a]=m;if(C)for(a=0;a<h;++a)m=c[o+a],m!=null&&(g=S[a],g.autoscale&&(g.x&&x(l.xaxis,m,m),g.y&&x(l.yaxis,m,m))),c[o+a]=null;else if(N&&o>0&&c[o-h]!=null&&c[o-h]!=c[o]&&c[o-h+1]!=c[o+1]){for(a=0;a<h;++a)c[o+h+a]=c[o+a];c[o+1]=c[o-h+1],o+=h}}}for(i=0;i<u.length;++i)l=u[i],E(b.processDatapoints,[l,l.datapoints]);for(i=0;i<u.length;++i){l=u[i],c=l.datapoints.points,h=l.datapoints.pointsize,S=l.datapoints.format;var L=t,A=t,O=n,M=n;for(s=0;s<c.length;s+=h){if(c[s]==null)continue;for(a=0;a<h;++a){m=c[s+a],g=S[a];if(!g||g.autoscale===!1||m==r||m==-r)continue;g.x&&(m<L&&(L=m),m>O&&(O=m)),g.y&&(m<A&&(A=m),m>M&&(M=m))}}if(l.bars.show){var _;switch(l.bars.align){case"left":_=0;break;case"right":_=-l.bars.barWidth;break;case"center":_=-l.bars.barWidth/2;break;default:throw new Error("Invalid bar alignment: "+l.bars.align)}l.bars.horizontal?(A+=_,M+=_+l.bars.barWidth):(L+=_,O+=_+l.bars.barWidth)}x(l.xaxis,L,O),x(l.yaxis,A,M)}e.each(k(),function(e,r){r.datamin==t&&(r.datamin=null),r.datamax==n&&(r.datamax=null)})}function D(){t.css("padding",0).children(":not(.flot-base,.flot-overlay)").remove(),t.css("position")=="static"&&t.css("position","relative"),f=new n("flot-base",t),l=new n("flot-overlay",t),h=f.context,p=l.context,c=e(l.element).unbind();var r=t.data("plot");r&&(r.shutdown(),l.clear()),t.data("plot",w)}function P(){a.grid.hoverable&&(c.mousemove(at),c.bind("mouseleave",ft)),a.grid.clickable&&c.click(lt),E(b.bindEvents,[c])}function H(){ot&&clearTimeout(ot),c.unbind("mousemove",at),c.unbind("mouseleave",ft),c.unbind("click",lt),E(b.shutdown,[c])}function B(e){function t(e){return e}var n,r,i=e.options.transform||t,s=e.options.inverseTransform;e.direction=="x"?(n=e.scale=g/Math.abs(i(e.max)-i(e.min)),r=Math.min(i(e.max),i(e.min))):(n=e.scale=y/Math.abs(i(e.max)-i(e.min)),n=-n,r=Math.max(i(e.max),i(e.min))),i==t?e.p2c=function(e){return(e-r)*n}:e.p2c=function(e){return(i(e)-r)*n},s?e.c2p=function(e){return s(r+e/n)}:e.c2p=function(e){return r+e/n}}function j(e){var t=e.options,n=e.ticks||[],r=t.labelWidth||0,i=t.labelHeight||0,s=r||e.direction=="x"?Math.floor(f.width/(n.length||1)):null;legacyStyles=e.direction+"Axis "+e.direction+e.n+"Axis",layer="flot-"+e.direction+"-axis flot-"+e.direction+e.n+"-axis "+legacyStyles,font=t.font||"flot-tick-label tickLabel";for(var o=0;o<n.length;++o){var u=n[o];if(!u.label)continue;var a=f.getTextInfo(layer,u.label,font,null,s);r=Math.max(r,a.width),i=Math.max(i,a.height)}e.labelWidth=t.labelWidth||r,e.labelHeight=t.labelHeight||i}function F(t){var n=t.labelWidth,r=t.labelHeight,i=t.options.position,s=t.options.tickLength,o=a.grid.axisMargin,u=a.grid.labelMargin,l=t.direction=="x"?d:v,c,h,p=e.grep(l,function(e){return e&&e.options.position==i&&e.reserveSpace});e.inArray(t,p)==p.length-1&&(o=0);if(s==null){var g=e.grep(l,function(e){return e&&e.reserveSpace});h=e.inArray(t,g)==0,h?s="full":s=5}isNaN(+s)||(u+=+s),t.direction=="x"?(r+=u,i=="bottom"?(m.bottom+=r+o,t.box={top:f.height-m.bottom,height:r}):(t.box={top:m.top+o,height:r},m.top+=r+o)):(n+=u,i=="left"?(t.box={left:m.left+o,width:n},m.left+=n+o):(m.right+=n+o,t.box={left:f.width-m.right,width:n})),t.position=i,t.tickLength=s,t.box.padding=u,t.innermost=h}function I(e){e.direction=="x"?(e.box.left=m.left-e.labelWidth/2,e.box.width=f.width-m.left-m.right+e.labelWidth):(e.box.top=m.top-e.labelHeight/2,e.box.height=f.height-m.bottom-m.top+e.labelHeight)}function q(){var t=a.grid.minBorderMargin,n={x:0,y:0},r,i;if(t==null){t=0;for(r=0;r<u.length;++r)t=Math.max(t,2*(u[r].points.radius+u[r].points.lineWidth/2))}n.x=n.y=Math.ceil(t),e.each(k(),function(e,t){var r=t.direction;t.reserveSpace&&(n[r]=Math.ceil(Math.max(n[r],(r=="x"?t.labelWidth:t.labelHeight)/2)))}),m.left=Math.max(n.x,m.left),m.right=Math.max(n.x,m.right),m.top=Math.max(n.y,m.top),m.bottom=Math.max(n.y,m.bottom)}function R(){var t,n=k(),r=a.grid.show;for(var i in m){var s=a.grid.margin||0;m[i]=typeof s=="number"?s:s[i]||0}E(b.processOffset,[m]);for(var i in m)typeof a.grid.borderWidth=="object"?m[i]+=r?a.grid.borderWidth[i]:0:m[i]+=r?a.grid.borderWidth:0;e.each(n,function(e,t){t.show=t.options.show,t.show==null&&(t.show=t.used),t.reserveSpace=t.show||t.options.reserveSpace,U(t)});if(r){var o=e.grep(n,function(e){return e.reserveSpace});e.each(o,function(e,t){z(t),W(t),X(t,t.ticks),j(t)});for(t=o.length-1;t>=0;--t)F(o[t]);q(),e.each(o,function(e,t){I(t)})}g=f.width-m.left-m.right,y=f.height-m.bottom-m.top,e.each(n,function(e,t){B(t)}),r&&G(),it()}function U(e){var t=e.options,n=+(t.min!=null?t.min:e.datamin),r=+(t.max!=null?t.max:e.datamax),i=r-n;if(i==0){var s=r==0?1:.01;t.min==null&&(n-=s);if(t.max==null||t.min!=null)r+=s}else{var o=t.autoscaleMargin;o!=null&&(t.min==null&&(n-=i*o,n<0&&e.datamin!=null&&e.datamin>=0&&(n=0)),t.max==null&&(r+=i*o,r>0&&e.datamax!=null&&e.datamax<=0&&(r=0)))}e.min=n,e.max=r}function z(t){var n=t.options,r;typeof n.ticks=="number"&&n.ticks>0?r=n.ticks:r=.3*Math.sqrt(t.direction=="x"?f.width:f.height);var s=(t.max-t.min)/r,o=-Math.floor(Math.log(s)/Math.LN10),u=n.tickDecimals;u!=null&&o>u&&(o=u);var a=Math.pow(10,-o),l=s/a,c;l<1.5?c=1:l<3?(c=2,l>2.25&&(u==null||o+1<=u)&&(c=2.5,++o)):l<7.5?c=5:c=10,c*=a,n.minTickSize!=null&&c<n.minTickSize&&(c=n.minTickSize),t.delta=s,t.tickDecimals=Math.max(0,u!=null?u:o),t.tickSize=n.tickSize||c;if(n.mode=="time"&&!t.tickGenerator)throw new Error("Time mode requires the flot.time plugin.");t.tickGenerator||(t.tickGenerator=function(e){var t=[],n=i(e.min,e.tickSize),r=0,s=Number.NaN,o;do o=s,s=n+r*e.tickSize,t.push(s),++r;while(s<e.max&&s!=o);return t},t.tickFormatter=function(e,t){var n=t.tickDecimals?Math.pow(10,t.tickDecimals):1,r=""+Math.round(e*n)/n;if(t.tickDecimals!=null){var i=r.indexOf("."),s=i==-1?0:r.length-i-1;if(s<t.tickDecimals)return(s?r:r+".")+(""+n).substr(1,t.tickDecimals-s)}return r}),e.isFunction(n.tickFormatter)&&(t.tickFormatter=function(e,t){return""+n.tickFormatter(e,t)});if(n.alignTicksWithAxis!=null){var h=(t.direction=="x"?d:v)[n.alignTicksWithAxis-1];if(h&&h.used&&h!=t){var p=t.tickGenerator(t);p.length>0&&(n.min==null&&(t.min=Math.min(t.min,p[0])),n.max==null&&p.length>1&&(t.max=Math.max(t.max,p[p.length-1]))),t.tickGenerator=function(e){var t=[],n,r;for(r=0;r<h.ticks.length;++r)n=(h.ticks[r].v-h.min)/(h.max-h.min),n=e.min+n*(e.max-e.min),t.push(n);return t};if(!t.mode&&n.tickDecimals==null){var m=Math.max(0,-Math.floor(Math.log(t.delta)/Math.LN10)+1),g=t.tickGenerator(t);g.length>1&&/\..*0$/.test((g[1]-g[0]).toFixed(m))||(t.tickDecimals=m)}}}}function W(t){var n=t.options.ticks,r=[];n==null||typeof n=="number"&&n>0?r=t.tickGenerator(t):n&&(e.isFunction(n)?r=n(t):r=n);var i,s;t.ticks=[];for(i=0;i<r.length;++i){var o=null,u=r[i];typeof u=="object"?(s=+u[0],u.length>1&&(o=u[1])):s=+u,o==null&&(o=t.tickFormatter(s,t)),isNaN(s)||t.ticks.push({v:s,label:o})}}function X(e,t){e.options.autoscaleMargin&&t.length>0&&(e.options.min==null&&(e.min=Math.min(e.min,t[0].v)),e.options.max==null&&t.length>1&&(e.max=Math.max(e.max,t[t.length-1].v)))}function V(){f.clear(),E(b.drawBackground,[h]);var e=a.grid;e.show&&e.backgroundColor&&K(),e.show&&!e.aboveData&&Q();for(var t=0;t<u.length;++t)E(b.drawSeries,[h,u[t]]),Y(u[t]);E(b.draw,[h]),e.show&&e.aboveData&&Q(),f.render(),ht()}function J(e,t){var n,r,i,s,o=k();for(var u=0;u<o.length;++u){n=o[u];if(n.direction==t){s=t+n.n+"axis",!e[s]&&n.n==1&&(s=t+"axis");if(e[s]){r=e[s].from,i=e[s].to;break}}}e[s]||(n=t=="x"?d[0]:v[0],r=e[t+"1"],i=e[t+"2"]);if(r!=null&&i!=null&&r>i){var a=r;r=i,i=a}return{from:r,to:i,axis:n}}function K(){h.save(),h.translate(m.left,m.top),h.fillStyle=bt(a.grid.backgroundColor,y,0,"rgba(255, 255, 255, 0)"),h.fillRect(0,0,g,y),h.restore()}function Q(){var t,n,r,i;h.save(),h.translate(m.left,m.top);var s=a.grid.markings;if(s){e.isFunction(s)&&(n=w.getAxes(),n.xmin=n.xaxis.min,n.xmax=n.xaxis.max,n.ymin=n.yaxis.min,n.ymax=n.yaxis.max,s=s(n));for(t=0;t<s.length;++t){var o=s[t],u=J(o,"x"),f=J(o,"y");u.from==null&&(u.from=u.axis.min),u.to==null&&(u.to=u.axis.max),f.from==null&&(f.from=f.axis.min),f.to==null&&(f.to=f.axis.max);if(u.to<u.axis.min||u.from>u.axis.max||f.to<f.axis.min||f.from>f.axis.max)continue;u.from=Math.max(u.from,u.axis.min),u.to=Math.min(u.to,u.axis.max),f.from=Math.max(f.from,f.axis.min),f.to=Math.min(f.to,f.axis.max);if(u.from==u.to&&f.from==f.to)continue;u.from=u.axis.p2c(u.from),u.to=u.axis.p2c(u.to),f.from=f.axis.p2c(f.from),f.to=f.axis.p2c(f.to),u.from==u.to||f.from==f.to?(h.beginPath(),h.strokeStyle=o.color||a.grid.markingsColor,h.lineWidth=o.lineWidth||a.grid.markingsLineWidth,h.moveTo(u.from,f.from),h.lineTo(u.to,f.to),h.stroke()):(h.fillStyle=o.color||a.grid.markingsColor,h.fillRect(u.from,f.to,u.to-u.from,f.from-f.to))}}n=k(),r=a.grid.borderWidth;for(var l=0;l<n.length;++l){var c=n[l],p=c.box,d=c.tickLength,v,b,E,S;if(!c.show||c.ticks.length==0)continue;h.lineWidth=1,c.direction=="x"?(v=0,d=="full"?b=c.position=="top"?0:y:b=p.top-m.top+(c.position=="top"?p.height:0)):(b=0,d=="full"?v=c.position=="left"?0:g:v=p.left-m.left+(c.position=="left"?p.width:0)),c.innermost||(h.strokeStyle=c.options.color,h.beginPath(),E=S=0,c.direction=="x"?E=g+1:S=y+1,h.lineWidth==1&&(c.direction=="x"?b=Math.floor(b)+.5:v=Math.floor(v)+.5),h.moveTo(v,b),h.lineTo(v+E,b+S),h.stroke()),h.strokeStyle=c.options.tickColor,h.beginPath();for(t=0;t<c.ticks.length;++t){var x=c.ticks[t].v;E=S=0;if(isNaN(x)||x<c.min||x>c.max||d=="full"&&(typeof r=="object"&&r[c.position]>0||r>0)&&(x==c.min||x==c.max))continue;c.direction=="x"?(v=c.p2c(x),S=d=="full"?-y:d,c.position=="top"&&(S=-S)):(b=c.p2c(x),E=d=="full"?-g:d,c.position=="left"&&(E=-E)),h.lineWidth==1&&(c.direction=="x"?v=Math.floor(v)+.5:b=Math.floor(b)+.5),h.moveTo(v,b),h.lineTo(v+E,b+S)}h.stroke()}r&&(i=a.grid.borderColor,typeof r=="object"||typeof i=="object"?(typeof r!="object"&&(r={top:r,right:r,bottom:r,left:r}),typeof i!="object"&&(i={top:i,right:i,bottom:i,left:i}),r.top>0&&(h.strokeStyle=i.top,h.lineWidth=r.top,h.beginPath(),h.moveTo(0-r.left,0-r.top/2),h.lineTo(g,0-r.top/2),h.stroke()),r.right>0&&(h.strokeStyle=i.right,h.lineWidth=r.right,h.beginPath(),h.moveTo(g+r.right/2,0-r.top),h.lineTo(g+r.right/2,y),h.stroke()),r.bottom>0&&(h.strokeStyle=i.bottom,h.lineWidth=r.bottom,h.beginPath(),h.moveTo(g+r.right,y+r.bottom/2),h.lineTo(0,y+r.bottom/2),h.stroke()),r.left>0&&(h.strokeStyle=i.left,h.lineWidth=r.left,h.beginPath(),h.moveTo(0-r.left/2,y+r.bottom),h.lineTo(0-r.left/2,0),h.stroke())):(h.lineWidth=r,h.strokeStyle=a.grid.borderColor,h.strokeRect(-r/2,-r/2,g+r,y+r))),h.restore()}function G(){e.each(k(),function(e,t){if(!t.show||t.ticks.length==0)return;var n=t.box,r=t.direction+"Axis "+t.direction+t.n+"Axis",i="flot-"+t.direction+"-axis flot-"+t.direction+t.n+"-axis "+r,s=t.options.font||"flot-tick-label tickLabel",o,u,a,l,c;f.removeText(i);for(var h=0;h<t.ticks.length;++h){o=t.ticks[h];if(!o.label||o.v<t.min||o.v>t.max)continue;t.direction=="x"?(l="center",u=m.left+t.p2c(o.v),t.position=="bottom"?a=n.top+n.padding:(a=n.top+n.height-n.padding,c="bottom")):(c="middle",a=m.top+t.p2c(o.v),t.position=="left"?(u=n.left+n.width-n.padding,l="right"):u=n.left+n.padding),f.addText(i,u,a,o.label,s,null,null,l,c)}})}function Y(e){e.lines.show&&Z(e),e.bars.show&&nt(e),e.points.show&&et(e)}function Z(e){function t(e,t,n,r,i){var s=e.points,o=e.pointsize,u=null,a=null;h.beginPath();for(var f=o;f<s.length;f+=o){var l=s[f-o],c=s[f-o+1],p=s[f],d=s[f+1];if(l==null||p==null)continue;if(c<=d&&c<i.min){if(d<i.min)continue;l=(i.min-c)/(d-c)*(p-l)+l,c=i.min}else if(d<=c&&d<i.min){if(c<i.min)continue;p=(i.min-c)/(d-c)*(p-l)+l,d=i.min}if(c>=d&&c>i.max){if(d>i.max)continue;l=(i.max-c)/(d-c)*(p-l)+l,c=i.max}else if(d>=c&&d>i.max){if(c>i.max)continue;p=(i.max-c)/(d-c)*(p-l)+l,d=i.max}if(l<=p&&l<r.min){if(p<r.min)continue;c=(r.min-l)/(p-l)*(d-c)+c,l=r.min}else if(p<=l&&p<r.min){if(l<r.min)continue;d=(r.min-l)/(p-l)*(d-c)+c,p=r.min}if(l>=p&&l>r.max){if(p>r.max)continue;c=(r.max-l)/(p-l)*(d-c)+c,l=r.max}else if(p>=l&&p>r.max){if(l>r.max)continue;d=(r.max-l)/(p-l)*(d-c)+c,p=r.max}(l!=u||c!=a)&&h.moveTo(r.p2c(l)+t,i.p2c(c)+n),u=p,a=d,h.lineTo(r.p2c(p)+t,i.p2c(d)+n)}h.stroke()}function n(e,t,n){var r=e.points,i=e.pointsize,s=Math.min(Math.max(0,n.min),n.max),o=0,u,a=!1,f=1,l=0,c=0;for(;;){if(i>0&&o>r.length+i)break;o+=i;var p=r[o-i],d=r[o-i+f],v=r[o],m=r[o+f];if(a){if(i>0&&p!=null&&v==null){c=o,i=-i,f=2;continue}if(i<0&&o==l+i){h.fill(),a=!1,i=-i,f=1,o=l=c+i;continue}}if(p==null||v==null)continue;if(p<=v&&p<t.min){if(v<t.min)continue;d=(t.min-p)/(v-p)*(m-d)+d,p=t.min}else if(v<=p&&v<t.min){if(p<t.min)continue;m=(t.min-p)/(v-p)*(m-d)+d,v=t.min}if(p>=v&&p>t.max){if(v>t.max)continue;d=(t.max-p)/(v-p)*(m-d)+d,p=t.max}else if(v>=p&&v>t.max){if(p>t.max)continue;m=(t.max-p)/(v-p)*(m-d)+d,v=t.max}a||(h.beginPath(),h.moveTo(t.p2c(p),n.p2c(s)),a=!0);if(d>=n.max&&m>=n.max){h.lineTo(t.p2c(p),n.p2c(n.max)),h.lineTo(t.p2c(v),n.p2c(n.max));continue}if(d<=n.min&&m<=n.min){h.lineTo(t.p2c(p),n.p2c(n.min)),h.lineTo(t.p2c(v),n.p2c(n.min));continue}var g=p,y=v;d<=m&&d<n.min&&m>=n.min?(p=(n.min-d)/(m-d)*(v-p)+p,d=n.min):m<=d&&m<n.min&&d>=n.min&&(v=(n.min-d)/(m-d)*(v-p)+p,m=n.min),d>=m&&d>n.max&&m<=n.max?(p=(n.max-d)/(m-d)*(v-p)+p,d=n.max):m>=d&&m>n.max&&d<=n.max&&(v=(n.max-d)/(m-d)*(v-p)+p,m=n.max),p!=g&&h.lineTo(t.p2c(g),n.p2c(d)),h.lineTo(t.p2c(p),n.p2c(d)),h.lineTo(t.p2c(v),n.p2c(m)),v!=y&&(h.lineTo(t.p2c(v),n.p2c(m)),h.lineTo(t.p2c(y),n.p2c(m)))}}h.save(),h.translate(m.left,m.top),h.lineJoin="round";var r=e.lines.lineWidth,i=e.shadowSize;if(r>0&&i>0){h.lineWidth=i,h.strokeStyle="rgba(0,0,0,0.1)";var s=Math.PI/18;t(e.datapoints,Math.sin(s)*(r/2+i/2),Math.cos(s)*(r/2+i/2),e.xaxis,e.yaxis),h.lineWidth=i/2,t(e.datapoints,Math.sin(s)*(r/2+i/4),Math.cos(s)*(r/2+i/4),e.xaxis,e.yaxis)}h.lineWidth=r,h.strokeStyle=e.color;var o=rt(e.lines,e.color,0,y);o&&(h.fillStyle=o,n(e.datapoints,e.xaxis,e.yaxis)),r>0&&t(e.datapoints,0,0,e.xaxis,e.yaxis),h.restore()}function et(e){function t(e,t,n,r,i,s,o,u){var a=e.points,f=e.pointsize;for(var l=0;l<a.length;l+=f){var c=a[l],p=a[l+1];if(c==null||c<s.min||c>s.max||p<o.min||p>o.max)continue;h.beginPath(),c=s.p2c(c),p=o.p2c(p)+r,u=="circle"?h.arc(c,p,t,0,i?Math.PI:Math.PI*2,!1):u(h,c,p,t,i),h.closePath(),n&&(h.fillStyle=n,h.fill()),h.stroke()}}h.save(),h.translate(m.left,m.top);var n=e.points.lineWidth,r=e.shadowSize,i=e.points.radius,s=e.points.symbol;n==0&&(n=1e-4);if(n>0&&r>0){var o=r/2;h.lineWidth=o,h.strokeStyle="rgba(0,0,0,0.1)",t(e.datapoints,i,null,o+o/2,!0,e.xaxis,e.yaxis,s),h.strokeStyle="rgba(0,0,0,0.2)",t(e.datapoints,i,null,o/2,!0,e.xaxis,e.yaxis,s)}h.lineWidth=n,h.strokeStyle=e.color,t(e.datapoints,i,rt(e.points,e.color),0,!1,e.xaxis,e.yaxis,s),h.restore()}function tt(e,t,n,r,i,s,o,u,a,f,l,c){var h,p,d,v,m,g,y,b,w;l?(b=g=y=!0,m=!1,h=n,p=e,v=t+r,d=t+i,p<h&&(w=p,p=h,h=w,m=!0,g=!1)):(m=g=y=!0,b=!1,h=e+r,p=e+i,d=n,v=t,v<d&&(w=v,v=d,d=w,b=!0,y=!1));if(p<u.min||h>u.max||v<a.min||d>a.max)return;h<u.min&&(h=u.min,m=!1),p>u.max&&(p=u.max,g=!1),d<a.min&&(d=a.min,b=!1),v>a.max&&(v=a.max,y=!1),h=u.p2c(h),d=a.p2c(d),p=u.p2c(p),v=a.p2c(v),o&&(f.beginPath(),f.moveTo(h,d),f.lineTo(h,v),f.lineTo(p,v),f.lineTo(p,d),f.fillStyle=o(d,v),f.fill()),c>0&&(m||g||y||b)&&(f.beginPath(),f.moveTo(h,d+s),m?f.lineTo(h,v+s):f.moveTo(h,v+s),y?f.lineTo(p,v+s):f.moveTo(p,v+s),g?f.lineTo(p,d+s):f.moveTo(p,d+s),b?f.lineTo(h,d+s):f.moveTo(h,d+s),f.stroke())}function nt(e){function t(t,n,r,i,s,o,u){var a=t.points,f=t.pointsize;for(var l=0;l<a.length;l+=f){if(a[l]==null)continue;tt(a[l],a[l+1],a[l+2],n,r,i,s,o,u,h,e.bars.horizontal,e.bars.lineWidth)}}h.save(),h.translate(m.left,m.top),h.lineWidth=e.bars.lineWidth,h.strokeStyle=e.color;var n;switch(e.bars.align){case"left":n=0;break;case"right":n=-e.bars.barWidth;break;case"center":n=-e.bars.barWidth/2;break;default:throw new Error("Invalid bar alignment: "+e.bars.align)}var r=e.bars.fill?function(t,n){return rt(e.bars,e.color,t,n)}:null;t(e.datapoints,n,n+e.bars.barWidth,0,r,e.xaxis,e.yaxis),h.restore()}function rt(t,n,r,i){var s=t.fill;if(!s)return null;if(t.fillColor)return bt(t.fillColor,r,i,n);var o=e.color.parse(n);return o.a=typeof s=="number"?s:.4,o.normalize(),o.toString()}function it(){t.find(".legend").remove();if(!a.legend.show)return;var n=[],r=[],i=!1,s=a.legend.labelFormatter,o,f;for(var l=0;l<u.length;++l)o=u[l],o.label&&(f=s?s(o.label,o):o.label,f&&r.push({label:f,color:o.color}));if(a.legend.sorted)if(e.isFunction(a.legend.sorted))r.sort(a.legend.sorted);else if(a.legend.sorted=="reverse")r.reverse();else{var c=a.legend.sorted!="descending";r.sort(function(e,t){return e.label==t.label?0:e.label<t.label!=c?1:-1})}for(var l=0;l<r.length;++l){var h=r[l];l%a.legend.noColumns==0&&(i&&n.push("</tr>"),n.push("<tr>"),i=!0),n.push('<td class="legendColorBox"><div style="border:1px solid '+a.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+h.color+';overflow:hidden"></div></div></td>'+'<td class="legendLabel">'+h.label+"</td>")}i&&n.push("</tr>");if(n.length==0)return;var p='<table style="font-size:smaller;color:'+a.grid.color+'">'+n.join("")+"</table>";if(a.legend.container!=null)e(a.legend.container).html(p);else{var d="",v=a.legend.position,g=a.legend.margin;g[0]==null&&(g=[g,g]),v.charAt(0)=="n"?d+="top:"+(g[1]+m.top)+"px;":v.charAt(0)=="s"&&(d+="bottom:"+(g[1]+m.bottom)+"px;"),v.charAt(1)=="e"?d+="right:"+(g[0]+m.right)+"px;":v.charAt(1)=="w"&&(d+="left:"+(g[0]+m.left)+"px;");var y=e('<div class="legend">'+p.replace('style="','style="position:absolute;'+d+";")+"</div>").appendTo(t);if(a.legend.backgroundOpacity!=0){var b=a.legend.backgroundColor;b==null&&(b=a.grid.backgroundColor,b&&typeof b=="string"?b=e.color.parse(b):b=e.color.extract(y,"background-color"),b.a=1,b=b.toString());var w=y.children();e('<div style="position:absolute;width:'+w.width()+"px;height:"+w.height()+"px;"+d+"background-color:"+b+';"> </div>').prependTo(y).css("opacity",a.legend.backgroundOpacity)}}}function ut(e,t,n){var r=a.grid.mouseActiveRadius,i=r*r+1,s=null,o=!1,f,l,c;for(f=u.length-1;f>=0;--f){if(!n(u[f]))continue;var h=u[f],p=h.xaxis,d=h.yaxis,v=h.datapoints.points,m=p.c2p(e),g=d.c2p(t),y=r/p.scale,b=r/d.scale;c=h.datapoints.pointsize,p.options.inverseTransform&&(y=Number.MAX_VALUE),d.options.inverseTransform&&(b=Number.MAX_VALUE);if(h.lines.show||h.points.show)for(l=0;l<v.length;l+=c){var w=v[l],E=v[l+1];if(w==null)continue;if(w-m>y||w-m<-y||E-g>b||E-g<-b)continue;var S=Math.abs(p.p2c(w)-e),x=Math.abs(d.p2c(E)-t),T=S*S+x*x;T<i&&(i=T,s=[f,l/c])}if(h.bars.show&&!s){var N=h.bars.align=="left"?0:-h.bars.barWidth/2,C=N+h.bars.barWidth;for(l=0;l<v.length;l+=c){var w=v[l],E=v[l+1],k=v[l+2];if(w==null)continue;if(u[f].bars.horizontal?m<=Math.max(k,w)&&m>=Math.min(k,w)&&g>=E+N&&g<=E+C:m>=w+N&&m<=w+C&&g>=Math.min(k,E)&&g<=Math.max(k,E))s=[f,l/c]}}}return s?(f=s[0],l=s[1],c=u[f].datapoints.pointsize,{datapoint:u[f].datapoints.points.slice(l*c,(l+1)*c),dataIndex:l,series:u[f],seriesIndex:f}):null}function at(e){a.grid.hoverable&&ct("plothover",e,function(e){return e["hoverable"]!=0})}function ft(e){a.grid.hoverable&&ct("plothover",e,function(e){return!1})}function lt(e){ct("plotclick",e,function(e){return e["clickable"]!=0})}function ct(e,n,r){var i=c.offset(),s=n.pageX-i.left-m.left,o=n.pageY-i.top-m.top,u=L({left:s,top:o});u.pageX=n.pageX,u.pageY=n.pageY;var f=ut(s,o,r);f&&(f.pageX=parseInt(f.series.xaxis.p2c(f.datapoint[0])+i.left+m.left,10),f.pageY=parseInt(f.series.yaxis.p2c(f.datapoint[1])+i.top+m.top,10));if(a.grid.autoHighlight){for(var l=0;l<st.length;++l){var h=st[l];h.auto==e&&(!f||h.series!=f.series||h.point[0]!=f.datapoint[0]||h.point[1]!=f.datapoint[1])&&vt(h.series,h.point)}f&&dt(f.series,f.datapoint,e)}t.trigger(e,[u,f])}function ht(){var e=a.interaction.redrawOverlayInterval;if(e==-1){pt();return}ot||(ot=setTimeout(pt,e))}function pt(){ot=null,p.save(),l.clear(),p.translate(m.left,m.top);var e,t;for(e=0;e<st.length;++e)t=st[e],t.series.bars.show?yt(t.series,t.point):gt(t.series,t.point);p.restore(),E(b.drawOverlay,[p])}function dt(e,t,n){typeof e=="number"&&(e=u[e]);if(typeof t=="number"){var r=e.datapoints.pointsize;t=e.datapoints.points.slice(r*t,r*(t+1))}var i=mt(e,t);i==-1?(st.push({series:e,point:t,auto:n}),ht()):n||(st[i].auto=!1)}function vt(e,t){if(e==null&&t==null){st=[],ht();return}typeof e=="number"&&(e=u[e]);if(typeof t=="number"){var n=e.datapoints.pointsize;t=e.datapoints.points.slice(n*t,n*(t+1))}var r=mt(e,t);r!=-1&&(st.splice(r,1),ht())}function mt(e,t){for(var n=0;n<st.length;++n){var r=st[n];if(r.series==e&&r.point[0]==t[0]&&r.point[1]==t[1])return n}return-1}function gt(t,n){var r=n[0],i=n[1],s=t.xaxis,o=t.yaxis,u=typeof t.highlightColor=="string"?t.highlightColor:e.color.parse(t.color).scale("a",.5).toString();if(r<s.min||r>s.max||i<o.min||i>o.max)return;var a=t.points.radius+t.points.lineWidth/2;p.lineWidth=a,p.strokeStyle=u;var f=1.5*a;r=s.p2c(r),i=o.p2c(i),p.beginPath(),t.points.symbol=="circle"?p.arc(r,i,f,0,2*Math.PI,!1):t.points.symbol(p,r,i,f,!1),p.closePath(),p.stroke()}function yt(t,n){var r=typeof t.highlightColor=="string"?t.highlightColor:e.color.parse(t.color).scale("a",.5).toString(),i=r,s=t.bars.align=="left"?0:-t.bars.barWidth/2;p.lineWidth=t.bars.lineWidth,p.strokeStyle=r,tt(n[0],n[1],n[2]||0,s,s+t.bars.barWidth,0,function(){return i},t.xaxis,t.yaxis,p,t.bars.horizontal,t.bars.lineWidth)}function bt(t,n,r,i){if(typeof t=="string")return t;var s=h.createLinearGradient(0,r,0,n);for(var o=0,u=t.colors.length;o<u;++o){var a=t.colors[o];if(typeof a!="string"){var f=e.color.parse(i);a.brightness!=null&&(f=f.scale("rgb",a.brightness)),a.opacity!=null&&(f.a*=a.opacity),a=f.toString()}s.addColorStop(o/(u-1),a)}return s}var u=[],a={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:!0,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null},yaxis:{autoscaleMargin:.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:!1,radius:3,lineWidth:2,fill:!0,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:!1,fillColor:null,steps:!1},bars:{show:!1,lineWidth:2,barWidth:1,fill:!0,fillColor:null,align:"left",horizontal:!1,zero:!0},shadowSize:3,highlightColor:null},grid:{show:!0,aboveData:!1,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:!1,hoverable:!1,autoHighlight:!0,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1e3/60},hooks:{}},f=null,l=null,c=null,h=null,p=null,d=[],v=[],m={left:0,right:0,top:0,bottom
+:0},g=0,y=0,b={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},w=this;w.setData=T,w.setupGrid=R,w.draw=V,w.getPlaceholder=function(){return t},w.getCanvas=function(){return f.element},w.getPlotOffset=function(){return m},w.width=function(){return g},w.height=function(){return y},w.offset=function(){var e=c.offset();return e.left+=m.left,e.top+=m.top,e},w.getData=function(){return u},w.getAxes=function(){var t={},n;return e.each(d.concat(v),function(e,n){n&&(t[n.direction+(n.n!=1?n.n:"")+"axis"]=n)}),t},w.getXAxes=function(){return d},w.getYAxes=function(){return v},w.c2p=L,w.p2c=A,w.getOptions=function(){return a},w.highlight=dt,w.unhighlight=vt,w.triggerRedrawOverlay=ht,w.pointOffset=function(e){return{left:parseInt(d[C(e,"x")-1].p2c(+e.x)+m.left,10),top:parseInt(v[C(e,"y")-1].p2c(+e.y)+m.top,10)}},w.shutdown=H,w.resize=function(){var e=t.width(),n=t.height();f.resize(e,n),l.resize(e,n)},w.hooks=b,S(w),x(s),D(),T(r),R(),V(),P();var st=[],ot=null}function i(e,t){return t*Math.floor(e/t)}var t=Object.prototype.hasOwnProperty;n.prototype.resize=function(e,t){if(e<=0||t<=0)throw new Error("Invalid dimensions for plot, width = "+e+", height = "+t);var n=this.element,r=this.context,i=this.pixelRatio;this.width!=e&&(n.width=e*i,n.style.width=e+"px",this.width=e),this.height!=t&&(n.height=t*i,n.style.height=t+"px",this.height=t),r.restore(),r.save(),r.scale(i,i)},n.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)},n.prototype.render=function(){var e=this._textCache;for(var n in e)if(t.call(e,n)){var r=this.getTextLayer(n),i=e[n];r.hide();for(var s in i)if(t.call(i,s)){var o=i[s];for(var u in o)if(t.call(o,u)){var a=o[u].positions;for(var f=0,l;l=a[f];f++)l.active?l.rendered||(r.append(l.element),l.rendered=!0):(a.splice(f--,1),l.rendered&&l.element.detach());a.length==0&&delete o[u]}}r.show()}},n.prototype.getTextLayer=function(t){var n=this.text[t];return n==null&&(this.textContainer==null&&(this.textContainer=e("<div class='flot-text'></div>").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)),n=this.text[t]=e("<div></div>").addClass(t).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)),n},n.prototype.getTextInfo=function(t,n,r,i,s){var o,u,a,f;n=""+n,typeof r=="object"?o=r.style+" "+r.variant+" "+r.weight+" "+r.size+"px/"+r.lineHeight+"px "+r.family:o=r,u=this._textCache[t],u==null&&(u=this._textCache[t]={}),a=u[o],a==null&&(a=u[o]={}),f=a[n];if(f==null){var l=e("<div></div>").html(n).css({position:"absolute","max-width":s,top:-9999}).appendTo(this.getTextLayer(t));typeof r=="object"?l.css({font:o,color:r.color}):typeof r=="string"&&l.addClass(r),f=a[n]={width:l.outerWidth(!0),height:l.outerHeight(!0),element:l,positions:[]},l.detach()}return f},n.prototype.addText=function(e,t,n,r,i,s,o,u,a){var f=this.getTextInfo(e,r,i,s,o),l=f.positions;u=="center"?t-=f.width/2:u=="right"&&(t-=f.width),a=="middle"?n-=f.height/2:a=="bottom"&&(n-=f.height);for(var c=0,h;h=l[c];c++)if(h.x==t&&h.y==n){h.active=!0;return}h={active:!0,rendered:!1,element:l.length?f.element.clone():f.element,x:t,y:n},l.push(h),h.element.css({top:Math.round(n),left:Math.round(t),"text-align":u})},n.prototype.removeText=function(e,n,r,i,s,o){if(i==null){var u=this._textCache[e];if(u!=null)for(var a in u)if(t.call(u,a)){var f=u[a];for(var l in f)if(t.call(f,l)){var c=f[l].positions;for(var h=0,p;p=c[h];h++)p.active=!1}}}else{var c=this.getTextInfo(e,i,s,o).positions;for(var h=0,p;p=c[h];h++)p.x==n&&p.y==r&&(p.active=!1)}},e.plot=function(t,n,i){var s=new r(e(t),n,i,e.plot.plugins);return s},e.plot.version="0.8.1",e.plot.plugins=[],e.fn.plot=function(t,n){return this.each(function(){e.plot(this,t,n)})}}(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.navigate.min.js b/third_party/flot/jquery.flot.navigate.min.js
index ecf63c9..0420f16 100644
--- a/third_party/flot/jquery.flot.navigate.min.js
+++ b/third_party/flot/jquery.flot.navigate.min.js
@@ -1 +1,86 @@
-(function(i){i.fn.drag=function(j,k,l){if(k){this.bind("dragstart",j)}if(l){this.bind("dragend",l)}return !j?this.trigger("drag"):this.bind("drag",k?k:j)};var d=i.event,c=d.special,h=c.drag={not:":input",distance:0,which:1,dragging:false,setup:function(j){j=i.extend({distance:h.distance,which:h.which,not:h.not},j||{});j.distance=e(j.distance);d.add(this,"mousedown",f,j);if(this.attachEvent){this.attachEvent("ondragstart",a)}},teardown:function(){d.remove(this,"mousedown",f);if(this===h.dragging){h.dragging=h.proxy=false}g(this,true);if(this.detachEvent){this.detachEvent("ondragstart",a)}}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}};function f(j){var k=this,l,m=j.data||{};if(m.elem){k=j.dragTarget=m.elem;j.dragProxy=h.proxy||k;j.cursorOffsetX=m.pageX-m.left;j.cursorOffsetY=m.pageY-m.top;j.offsetX=j.pageX-j.cursorOffsetX;j.offsetY=j.pageY-j.cursorOffsetY}else{if(h.dragging||(m.which>0&&j.which!=m.which)||i(j.target).is(m.not)){return}}switch(j.type){case"mousedown":i.extend(m,i(k).offset(),{elem:k,target:j.target,pageX:j.pageX,pageY:j.pageY});d.add(document,"mousemove mouseup",f,m);g(k,false);h.dragging=null;return false;case !h.dragging&&"mousemove":if(e(j.pageX-m.pageX)+e(j.pageY-m.pageY)<m.distance){break}j.target=m.target;l=b(j,"dragstart",k);if(l!==false){h.dragging=k;h.proxy=j.dragProxy=i(l||k)[0]}case"mousemove":if(h.dragging){l=b(j,"drag",k);if(c.drop){c.drop.allowed=(l!==false);c.drop.handler(j)}if(l!==false){break}j.type="mouseup"}case"mouseup":d.remove(document,"mousemove mouseup",f);if(h.dragging){if(c.drop){c.drop.handler(j)}b(j,"dragend",k)}g(k,true);h.dragging=h.proxy=m.elem=false;break}return true}function b(m,k,j){m.type=k;var l=i.event.handle.call(j,m);return l===false?false:l||m.result}function e(j){return Math.pow(j,2)}function a(){return(h.dragging===false)}function g(j,k){if(!j){return}j.unselectable=k?"off":"on";j.onselectstart=function(){return k};if(j.style){j.style.MozUserSelect=k?"":"none"}}})(jQuery);(function(f){var e=["DOMMouseScroll","mousewheel"];f.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var a=e.length;a;){this.addEventListener(e[--a],d,false)}}else{this.onmousewheel=d}},teardown:function(){if(this.removeEventListener){for(var a=e.length;a;){this.removeEventListener(e[--a],d,false)}}else{this.onmousewheel=null}}};f.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}});function d(b){var h=[].slice.call(arguments,1),a=0,c=true;b=f.event.fix(b||window.event);b.type="mousewheel";if(b.wheelDelta){a=b.wheelDelta/120}if(b.detail){a=-b.detail/3}h.unshift(b,a);return f.event.handle.apply(this,h)}})(jQuery);(function(b){var a={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false,cursor:"move",frameRate:20}};function c(o){function m(q,p){var r=o.offset();r.left=q.pageX-r.left;r.top=q.pageY-r.top;if(p){o.zoomOut({center:r})}else{o.zoom({center:r})}}function d(p,q){m(p,q<0);return false}var i="default",g=0,e=0,n=null;function f(p){if(p.which!=1){return false}var q=o.getPlaceholder().css("cursor");if(q){i=q}o.getPlaceholder().css("cursor",o.getOptions().pan.cursor);g=p.pageX;e=p.pageY}function j(q){var p=o.getOptions().pan.frameRate;if(n||!p){return}n=setTimeout(function(){o.pan({left:g-q.pageX,top:e-q.pageY});g=q.pageX;e=q.pageY;n=null},1/p*1000)}function h(p){if(n){clearTimeout(n);n=null}o.getPlaceholder().css("cursor",i);o.pan({left:g-p.pageX,top:e-p.pageY})}function l(q,p){var r=q.getOptions();if(r.zoom.interactive){p[r.zoom.trigger](m);p.mousewheel(d)}if(r.pan.interactive){p.bind("dragstart",{distance:10},f);p.bind("drag",j);p.bind("dragend",h)}}o.zoomOut=function(p){if(!p){p={}}if(!p.amount){p.amount=o.getOptions().zoom.amount}p.amount=1/p.amount;o.zoom(p)};o.zoom=function(q){if(!q){q={}}var x=q.center,r=q.amount||o.getOptions().zoom.amount,p=o.width(),t=o.height();if(!x){x={left:p/2,top:t/2}}var s=x.left/p,v=x.top/t,u={x:{min:x.left-s*p/r,max:x.left+(1-s)*p/r},y:{min:x.top-v*t/r,max:x.top+(1-v)*t/r}};b.each(o.getAxes(),function(z,C){var D=C.options,B=u[C.direction].min,w=u[C.direction].max,E=D.zoomRange;if(E===false){return}B=C.c2p(B);w=C.c2p(w);if(B>w){var A=B;B=w;w=A}var y=w-B;if(E&&((E[0]!=null&&y<E[0])||(E[1]!=null&&y>E[1]))){return}D.min=B;D.max=w});o.setupGrid();o.draw();if(!q.preventEvent){o.getPlaceholder().trigger("plotzoom",[o])}};o.pan=function(p){var q={x:+p.left,y:+p.top};if(isNaN(q.x)){q.x=0}if(isNaN(q.y)){q.y=0}b.each(o.getAxes(),function(s,u){var v=u.options,t,r,w=q[u.direction];t=u.c2p(u.p2c(u.min)+w),r=u.c2p(u.p2c(u.max)+w);var x=v.panRange;if(x===false){return}if(x){if(x[0]!=null&&x[0]>t){w=x[0]-t;t+=w;r+=w}if(x[1]!=null&&x[1]<r){w=x[1]-r;t+=w;r+=w}}v.min=t;v.max=r});o.setupGrid();o.draw();if(!p.preventEvent){o.getPlaceholder().trigger("plotpan",[o])}};function k(q,p){p.unbind(q.getOptions().zoom.trigger,m);p.unbind("mousewheel",d);p.unbind("dragstart",f);p.unbind("drag",j);p.unbind("dragend",h);if(n){clearTimeout(n)}}o.hooks.bindEvents.push(l);o.hooks.shutdown.push(k)}b.plot.plugins.push({init:c,options:a,name:"navigate",version:"1.3"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for adding the ability to pan and zoom the plot.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The default behaviour is double click and scrollwheel up/down to zoom in, drag
+to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and
+plot.pan( offset ) so you easily can add custom controls. It also fires
+"plotpan" and "plotzoom" events, useful for synchronizing plots.
+
+The plugin supports these options:
+
+	zoom: {
+		interactive: false
+		trigger: "dblclick" // or "click" for single click
+		amount: 1.5         // 2 = 200% (zoom in), 0.5 = 50% (zoom out)
+	}
+
+	pan: {
+		interactive: false
+		cursor: "move"      // CSS mouse cursor value used when dragging, e.g. "pointer"
+		frameRate: 20
+	}
+
+	xaxis, yaxis, x2axis, y2axis: {
+		zoomRange: null  // or [ number, number ] (min range, max range) or false
+		panRange: null   // or [ number, number ] (min, max) or false
+	}
+
+"interactive" enables the built-in drag/click behaviour. If you enable
+interactive for pan, then you'll have a basic plot that supports moving
+around; the same for zoom.
+
+"amount" specifies the default amount to zoom in (so 1.5 = 150%) relative to
+the current viewport.
+
+"cursor" is a standard CSS mouse cursor string used for visual feedback to the
+user when dragging.
+
+"frameRate" specifies the maximum number of times per second the plot will
+update itself while the user is panning around on it (set to null to disable
+intermediate pans, the plot will then not update until the mouse button is
+released).
+
+"zoomRange" is the interval in which zooming can happen, e.g. with zoomRange:
+[1, 100] the zoom will never scale the axis so that the difference between min
+and max is smaller than 1 or larger than 100. You can set either end to null
+to ignore, e.g. [1, null]. If you set zoomRange to false, zooming on that axis
+will be disabled.
+
+"panRange" confines the panning to stay within a range, e.g. with panRange:
+[-10, 20] panning stops at -10 in one end and at 20 in the other. Either can
+be null, e.g. [-10, null]. If you set panRange to false, panning on that axis
+will be disabled.
+
+Example API usage:
+
+	plot = $.plot(...);
+
+	// zoom default amount in on the pixel ( 10, 20 )
+	plot.zoom({ center: { left: 10, top: 20 } });
+
+	// zoom out again
+	plot.zoomOut({ center: { left: 10, top: 20 } });
+
+	// zoom 200% in on the pixel (10, 20)
+	plot.zoom({ amount: 2, center: { left: 10, top: 20 } });
+
+	// pan 100 pixels to the left and 20 down
+	plot.pan({ left: -100, top: 20 })
+
+Here, "center" specifies where the center of the zooming should happen. Note
+that this is defined in pixel space, not the space of the data points (you can
+use the p2c helpers on the axes in Flot to help you convert between these).
+
+"amount" is the amount to zoom the viewport relative to the current range, so
+1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You
+can set the default in the options.
+
+*/// First two dependencies, jquery.event.drag.js and
+// jquery.mousewheel.js, we put them inline here to save people the
+// effort of downloading them.
+/*
+jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
+Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
+*/(function(e){function t(i){var l,h=this,p=i.data||{};if(p.elem)h=i.dragTarget=p.elem,i.dragProxy=a.proxy||h,i.cursorOffsetX=p.pageX-p.left,i.cursorOffsetY=p.pageY-p.top,i.offsetX=i.pageX-i.cursorOffsetX,i.offsetY=i.pageY-i.cursorOffsetY;else if(a.dragging||p.which>0&&i.which!=p.which||e(i.target).is(p.not))return;switch(i.type){case"mousedown":return e.extend(p,e(h).offset(),{elem:h,target:i.target,pageX:i.pageX,pageY:i.pageY}),o.add(document,"mousemove mouseup",t,p),s(h,!1),a.dragging=null,!1;case!a.dragging&&"mousemove":if(r(i.pageX-p.pageX)+r(i.pageY-p.pageY)<p.distance)break;i.target=p.target,l=n(i,"dragstart",h),l!==!1&&(a.dragging=h,a.proxy=i.dragProxy=e(l||h)[0]);case"mousemove":if(a.dragging){if(l=n(i,"drag",h),u.drop&&(u.drop.allowed=l!==!1,u.drop.handler(i)),l!==!1)break;i.type="mouseup"};case"mouseup":o.remove(document,"mousemove mouseup",t),a.dragging&&(u.drop&&u.drop.handler(i),n(i,"dragend",h)),s(h,!0),a.dragging=a.proxy=p.elem=!1}return!0}function n(t,n,r){t.type=n;var i=e.event.dispatch.call(r,t);return i===!1?!1:i||t.result}function r(e){return Math.pow(e,2)}function i(){return a.dragging===!1}function s(e,t){e&&(e.unselectable=t?"off":"on",e.onselectstart=function(){return t},e.style&&(e.style.MozUserSelect=t?"":"none"))}e.fn.drag=function(e,t,n){return t&&this.bind("dragstart",e),n&&this.bind("dragend",n),e?this.bind("drag",t?t:e):this.trigger("drag")};var o=e.event,u=o.special,a=u.drag={not:":input",distance:0,which:1,dragging:!1,setup:function(n){n=e.extend({distance:a.distance,which:a.which,not:a.not},n||{}),n.distance=r(n.distance),o.add(this,"mousedown",t,n),this.attachEvent&&this.attachEvent("ondragstart",i)},teardown:function(){o.remove(this,"mousedown",t),this===a.dragging&&(a.dragging=a.proxy=!1),s(this,!0),this.detachEvent&&this.detachEvent("ondragstart",i)}};u.dragstart=u.dragend={setup:function(){},teardown:function(){}}})(jQuery),function(e){function t(t){var n=t||window.event,r=[].slice.call(arguments,1),i=0,s=0,o=0,t=e.event.fix(n);return t.type="mousewheel",n.wheelDelta&&(i=n.wheelDelta/120),n.detail&&(i=-n.detail/3),o=i,void 0!==n.axis&&n.axis===n.HORIZONTAL_AXIS&&(o=0,s=-1*i),void 0!==n.wheelDeltaY&&(o=n.wheelDeltaY/120),void 0!==n.wheelDeltaX&&(s=-1*n.wheelDeltaX/120),r.unshift(t,i,s,o),(e.event.dispatch||e.event.handle).apply(this,r)}var n=["DOMMouseScroll","mousewheel"];if(e.event.fixHooks)for(var r=n.length;r;)e.event.fixHooks[n[--r]]=e.event.mouseHooks;e.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var e=n.length;e;)this.addEventListener(n[--e],t,!1);else this.onmousewheel=t},teardown:function(){if(this.removeEventListener)for(var e=n.length;e;)this.removeEventListener(n[--e],t,!1);else this.onmousewheel=null}},e.fn.extend({mousewheel:function(e){return e?this.bind("mousewheel",e):this.trigger("mousewheel")},unmousewheel:function(e){return this.unbind("mousewheel",e)}})}(jQuery),function(e){function n(t){function n(e,n){var r=t.offset();r.left=e.pageX-r.left,r.top=e.pageY-r.top,n?t.zoomOut({center:r}):t.zoom({center:r})}function r(e,t){return e.preventDefault(),n(e,t<0),!1}function a(e){if(e.which!=1)return!1;var n=t.getPlaceholder().css("cursor");n&&(i=n),t.getPlaceholder().css("cursor",t.getOptions().pan.cursor),s=e.pageX,o=e.pageY}function f(e){var n=t.getOptions().pan.frameRate;if(u||!n)return;u=setTimeout(function(){t.pan({left:s-e.pageX,top:o-e.pageY}),s=e.pageX,o=e.pageY,u=null},1/n*1e3)}function l(e){u&&(clearTimeout(u),u=null),t.getPlaceholder().css("cursor",i),t.pan({left:s-e.pageX,top:o-e.pageY})}function c(e,t){var i=e.getOptions();i.zoom.interactive&&(t[i.zoom.trigger](n),t.mousewheel(r)),i.pan.interactive&&(t.bind("dragstart",{distance:10},a),t.bind("drag",f),t.bind("dragend",l))}function h(e,t){t.unbind(e.getOptions().zoom.trigger,n),t.unbind("mousewheel",r),t.unbind("dragstart",a),t.unbind("drag",f),t.unbind("dragend",l),u&&clearTimeout(u)}var i="default",s=0,o=0,u=null;t.zoomOut=function(e){e||(e={}),e.amount||(e.amount=t.getOptions().zoom.amount),e.amount=1/e.amount,t.zoom(e)},t.zoom=function(n){n||(n={});var r=n.center,i=n.amount||t.getOptions().zoom.amount,s=t.width(),o=t.height();r||(r={left:s/2,top:o/2});var u=r.left/s,a=r.top/o,f={x:{min:r.left-u*s/i,max:r.left+(1-u)*s/i},y:{min:r.top-a*o/i,max:r.top+(1-a)*o/i}};e.each(t.getAxes(),function(e,t){var n=t.options,r=f[t.direction].min,i=f[t.direction].max,s=n.zoomRange,o=n.panRange;if(s===!1)return;r=t.c2p(r),i=t.c2p(i);if(r>i){var u=r;r=i,i=u}o&&(o[0]!=null&&r<o[0]&&(r=o[0]),o[1]!=null&&i>o[1]&&(i=o[1]));var a=i-r;if(s&&(s[0]!=null&&a<s[0]||s[1]!=null&&a>s[1]))return;n.min=r,n.max=i}),t.setupGrid(),t.draw(),n.preventEvent||t.getPlaceholder().trigger("plotzoom",[t,n])},t.pan=function(n){var r={x:+n.left,y:+n.top};isNaN(r.x)&&(r.x=0),isNaN(r.y)&&(r.y=0),e.each(t.getAxes(),function(e,t){var n=t.options,i,s,o=r[t.direction];i=t.c2p(t.p2c(t.min)+o),s=t.c2p(t.p2c(t.max)+o);var u=n.panRange;if(u===!1)return;u&&(u[0]!=null&&u[0]>i&&(o=u[0]-i,i+=o,s+=o),u[1]!=null&&u[1]<s&&(o=u[1]-s,i+=o,s+=o)),n.min=i,n.max=s}),t.setupGrid(),t.draw(),n.preventEvent||t.getPlaceholder().trigger("plotpan",[t,n])},t.hooks.bindEvents.push(c),t.hooks.shutdown.push(h)}var t={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:!1,trigger:"dblclick",amount:1.5},pan:{interactive:!1,cursor:"move",frameRate:20}};e.plot.plugins.push({init:n,options:t,name:"navigate",version:"1.3"})}(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.pie.min.js b/third_party/flot/jquery.flot.pie.min.js
index b7bf870..3de8f44 100644
--- a/third_party/flot/jquery.flot.pie.min.js
+++ b/third_party/flot/jquery.flot.pie.min.js
@@ -1 +1,56 @@
-(function(b){function c(D){var h=null;var L=null;var n=null;var B=null;var p=null;var M=0;var F=true;var o=10;var w=0.95;var A=0;var d=false;var z=false;var j=[];D.hooks.processOptions.push(g);D.hooks.bindEvents.push(e);function g(O,N){if(N.series.pie.show){N.grid.show=false;if(N.series.pie.label.show=="auto"){if(N.legend.show){N.series.pie.label.show=false}else{N.series.pie.label.show=true}}if(N.series.pie.radius=="auto"){if(N.series.pie.label.show){N.series.pie.radius=3/4}else{N.series.pie.radius=1}}if(N.series.pie.tilt>1){N.series.pie.tilt=1}if(N.series.pie.tilt<0){N.series.pie.tilt=0}O.hooks.processDatapoints.push(E);O.hooks.drawOverlay.push(H);O.hooks.draw.push(r)}}function e(P,N){var O=P.getOptions();if(O.series.pie.show&&O.grid.hoverable){N.unbind("mousemove").mousemove(t)}if(O.series.pie.show&&O.grid.clickable){N.unbind("click").click(l)}}function G(O){var P="";function N(S,T){if(!T){T=0}for(var R=0;R<S.length;++R){for(var Q=0;Q<T;Q++){P+="\t"}if(typeof S[R]=="object"){P+=""+R+":\n";N(S[R],T+1)}else{P+=""+R+": "+S[R]+"\n"}}}N(O);alert(P)}function q(P){for(var N=0;N<P.length;++N){var O=parseFloat(P[N].data[0][1]);if(O){M+=O}}}function E(Q,N,O,P){if(!d){d=true;h=Q.getCanvas();L=b(h).parent();a=Q.getOptions();Q.setData(K(Q.getData()))}}function I(){A=L.children().filter(".legend").children().width();n=Math.min(h.width,(h.height/a.series.pie.tilt))/2;p=(h.height/2)+a.series.pie.offset.top;B=(h.width/2);if(a.series.pie.offset.left=="auto"){if(a.legend.position.match("w")){B+=A/2}else{B-=A/2}}else{B+=a.series.pie.offset.left}if(B<n){B=n}else{if(B>h.width-n){B=h.width-n}}}function v(O){for(var N=0;N<O.length;++N){if(typeof(O[N].data)=="number"){O[N].data=[[1,O[N].data]]}else{if(typeof(O[N].data)=="undefined"||typeof(O[N].data[0])=="undefined"){if(typeof(O[N].data)!="undefined"&&typeof(O[N].data.label)!="undefined"){O[N].label=O[N].data.label}O[N].data=[[1,0]]}}}return O}function K(Q){Q=v(Q);q(Q);var P=0;var S=0;var N=a.series.pie.combine.color;var R=[];for(var O=0;O<Q.length;++O){Q[O].data[0][1]=parseFloat(Q[O].data[0][1]);if(!Q[O].data[0][1]){Q[O].data[0][1]=0}if(Q[O].data[0][1]/M<=a.series.pie.combine.threshold){P+=Q[O].data[0][1];S++;if(!N){N=Q[O].color}}else{R.push({data:[[1,Q[O].data[0][1]]],color:Q[O].color,label:Q[O].label,angle:(Q[O].data[0][1]*(Math.PI*2))/M,percent:(Q[O].data[0][1]/M*100)})}}if(S>0){R.push({data:[[1,P]],color:N,label:a.series.pie.combine.label,angle:(P*(Math.PI*2))/M,percent:(P/M*100)})}return R}function r(S,Q){if(!L){return}ctx=Q;I();var T=S.getData();var P=0;while(F&&P<o){F=false;if(P>0){n*=w}P+=1;N();if(a.series.pie.tilt<=0.8){O()}R()}if(P>=o){N();L.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>')}if(S.setSeries&&S.insertLegend){S.setSeries(T);S.insertLegend()}function N(){ctx.clearRect(0,0,h.width,h.height);L.children().filter(".pieLabel, .pieLabelBackground").remove()}function O(){var Z=5;var Y=15;var W=10;var X=0.02;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}if(U>=(h.width/2)-Z||U*a.series.pie.tilt>=(h.height/2)-Y||U<=W){return}ctx.save();ctx.translate(Z,Y);ctx.globalAlpha=X;ctx.fillStyle="#000";ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);for(var V=1;V<=W;V++){ctx.beginPath();ctx.arc(0,0,U,0,Math.PI*2,false);ctx.fill();U-=V}ctx.restore()}function R(){startAngle=Math.PI*a.series.pie.startAngle;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}ctx.save();ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);ctx.save();var Y=startAngle;for(var W=0;W<T.length;++W){T[W].startAngle=Y;X(T[W].angle,T[W].color,true)}ctx.restore();ctx.save();ctx.lineWidth=a.series.pie.stroke.width;Y=startAngle;for(var W=0;W<T.length;++W){X(T[W].angle,a.series.pie.stroke.color,false)}ctx.restore();J(ctx);if(a.series.pie.label.show){V()}ctx.restore();function X(ab,Z,aa){if(ab<=0){return}if(aa){ctx.fillStyle=Z}else{ctx.strokeStyle=Z;ctx.lineJoin="round"}ctx.beginPath();if(Math.abs(ab-Math.PI*2)>1e-9){ctx.moveTo(0,0)}else{if(b.browser.msie){ab-=0.0001}}ctx.arc(0,0,U,Y,Y+ab,false);ctx.closePath();Y+=ab;if(aa){ctx.fill()}else{ctx.stroke()}}function V(){var ac=startAngle;if(a.series.pie.label.radius>1){var Z=a.series.pie.label.radius}else{var Z=n*a.series.pie.label.radius}for(var ab=0;ab<T.length;++ab){if(T[ab].percent>=a.series.pie.label.threshold*100){aa(T[ab],ac,ab)}ac+=T[ab].angle}function aa(ap,ai,ag){if(ap.data[0][1]==0){return}var ar=a.legend.labelFormatter,aq,ae=a.series.pie.label.formatter;if(ar){aq=ar(ap.label,ap)}else{aq=ap.label}if(ae){aq=ae(aq,ap)}var aj=((ai+ap.angle)+ai)/2;var ao=B+Math.round(Math.cos(aj)*Z);var am=p+Math.round(Math.sin(aj)*Z)*a.series.pie.tilt;var af='<span class="pieLabel" id="pieLabel'+ag+'" style="position:absolute;top:'+am+"px;left:"+ao+'px;">'+aq+"</span>";L.append(af);var an=L.children("#pieLabel"+ag);var ad=(am-an.height()/2);var ah=(ao-an.width()/2);an.css("top",ad);an.css("left",ah);if(0-ad>0||0-ah>0||h.height-(ad+an.height())<0||h.width-(ah+an.width())<0){F=true}if(a.series.pie.label.background.opacity!=0){var ak=a.series.pie.label.background.color;if(ak==null){ak=ap.color}var al="top:"+ad+"px;left:"+ah+"px;";b('<div class="pieLabelBackground" style="position:absolute;width:'+an.width()+"px;height:"+an.height()+"px;"+al+"background-color:"+ak+';"> </div>').insertBefore(an).css("opacity",a.series.pie.label.background.opacity)}}}}}function J(N){if(a.series.pie.innerRadius>0){N.save();innerRadius=a.series.pie.innerRadius>1?a.series.pie.innerRadius:n*a.series.pie.innerRadius;N.globalCompositeOperation="destination-out";N.beginPath();N.fillStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.fill();N.closePath();N.restore();N.save();N.beginPath();N.strokeStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.stroke();N.closePath();N.restore()}}function s(Q,R){for(var S=false,P=-1,N=Q.length,O=N-1;++P<N;O=P){((Q[P][1]<=R[1]&&R[1]<Q[O][1])||(Q[O][1]<=R[1]&&R[1]<Q[P][1]))&&(R[0]<(Q[O][0]-Q[P][0])*(R[1]-Q[P][1])/(Q[O][1]-Q[P][1])+Q[P][0])&&(S=!S)}return S}function u(R,P){var T=D.getData(),O=D.getOptions(),N=O.series.pie.radius>1?O.series.pie.radius:n*O.series.pie.radius;for(var Q=0;Q<T.length;++Q){var S=T[Q];if(S.pie.show){ctx.save();ctx.beginPath();ctx.moveTo(0,0);ctx.arc(0,0,N,S.startAngle,S.startAngle+S.angle,false);ctx.closePath();x=R-B;y=P-p;if(ctx.isPointInPath){if(ctx.isPointInPath(R-B,P-p)){ctx.restore();return{datapoint:[S.percent,S.data],dataIndex:0,series:S,seriesIndex:Q}}}else{p1X=(N*Math.cos(S.startAngle));p1Y=(N*Math.sin(S.startAngle));p2X=(N*Math.cos(S.startAngle+(S.angle/4)));p2Y=(N*Math.sin(S.startAngle+(S.angle/4)));p3X=(N*Math.cos(S.startAngle+(S.angle/2)));p3Y=(N*Math.sin(S.startAngle+(S.angle/2)));p4X=(N*Math.cos(S.startAngle+(S.angle/1.5)));p4Y=(N*Math.sin(S.startAngle+(S.angle/1.5)));p5X=(N*Math.cos(S.startAngle+S.angle));p5Y=(N*Math.sin(S.startAngle+S.angle));arrPoly=[[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];arrPoint=[x,y];if(s(arrPoly,arrPoint)){ctx.restore();return{datapoint:[S.percent,S.data],dataIndex:0,series:S,seriesIndex:Q}}}ctx.restore()}}return null}function t(N){m("plothover",N)}function l(N){m("plotclick",N)}function m(N,T){var O=D.offset(),R=parseInt(T.pageX-O.left),P=parseInt(T.pageY-O.top),V=u(R,P);if(a.grid.autoHighlight){for(var Q=0;Q<j.length;++Q){var S=j[Q];if(S.auto==N&&!(V&&S.series==V.series)){f(S.series)}}}if(V){k(V.series,N)}var U={pageX:T.pageX,pageY:T.pageY};L.trigger(N,[U,V])}function k(O,P){if(typeof O=="number"){O=series[O]}var N=C(O);if(N==-1){j.push({series:O,auto:P});D.triggerRedrawOverlay()}else{if(!P){j[N].auto=false}}}function f(O){if(O==null){j=[];D.triggerRedrawOverlay()}if(typeof O=="number"){O=series[O]}var N=C(O);if(N!=-1){j.splice(N,1);D.triggerRedrawOverlay()}}function C(P){for(var N=0;N<j.length;++N){var O=j[N];if(O.series==P){return N}}return -1}function H(Q,R){var P=Q.getOptions();var N=P.series.pie.radius>1?P.series.pie.radius:n*P.series.pie.radius;R.save();R.translate(B,p);R.scale(1,P.series.pie.tilt);for(i=0;i<j.length;++i){O(j[i].series)}J(R);R.restore();function O(S){if(S.angle<0){return}R.fillStyle="rgba(255, 255, 255, "+P.series.pie.highlight.opacity+")";R.beginPath();if(Math.abs(S.angle-Math.PI*2)>1e-9){R.moveTo(0,0)}R.arc(0,0,N,S.startAngle,S.startAngle+S.angle,false);R.closePath();R.fill()}}}var a={series:{pie:{show:false,radius:"auto",innerRadius:0,startAngle:3/2,tilt:1,offset:{top:0,left:"auto"},stroke:{color:"#FFF",width:1},label:{show:"auto",formatter:function(d,e){return'<div style="font-size:x-small;text-align:center;padding:2px;color:'+e.color+';">'+d+"<br/>"+Math.round(e.percent)+"%</div>"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:0.5}}}};b.plot.plugins.push({init:c,options:a,name:"pie",version:"1.0"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for rendering pie charts.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The plugin assumes that each series has a single data value, and that each
+value is a positive integer or zero.  Negative numbers don't make sense for a
+pie chart, and have unpredictable results.  The values do NOT need to be
+passed in as percentages; the plugin will calculate the total and per-slice
+percentages internally.
+
+* Created by Brian Medendorp
+
+* Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars
+
+The plugin supports these options:
+
+	series: {
+		pie: {
+			show: true/false
+			radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
+			innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
+			startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
+			tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
+			offset: {
+				top: integer value to move the pie up or down
+				left: integer value to move the pie left or right, or 'auto'
+			},
+			stroke: {
+				color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
+				width: integer pixel width of the stroke
+			},
+			label: {
+				show: true/false, or 'auto'
+				formatter:  a user-defined function that modifies the text/style of the label text
+				radius: 0-1 for percentage of fullsize, or a specified pixel length
+				background: {
+					color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
+					opacity: 0-1
+				},
+				threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
+			},
+			combine: {
+				threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
+				color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
+				label: any text value of what the combined slice should be labeled
+			}
+			highlight: {
+				opacity: 0-1
+			}
+		}
+	}
+
+More detail and specific examples can be found in the included HTML file.
+
+*/(function(e){function r(r){function p(t,n,r){l||(l=!0,s=t.getCanvas(),o=e(s).parent(),i=t.getOptions(),t.setData(d(t.getData())))}function d(t){var n=0,r=0,s=0,o=i.series.pie.combine.color,u=[];for(var a=0;a<t.length;++a){var f=t[a].data;e.isArray(f)&&f.length==1&&(f=f[0]),e.isArray(f)?!isNaN(parseFloat(f[1]))&&isFinite(f[1])?f[1]=+f[1]:f[1]=0:!isNaN(parseFloat(f))&&isFinite(f)?f=[1,+f]:f=[1,0],t[a].data=[f]}for(var a=0;a<t.length;++a)n+=t[a].data[0][1];for(var a=0;a<t.length;++a){var f=t[a].data[0][1];f/n<=i.series.pie.combine.threshold&&(r+=f,s++,o||(o=t[a].color))}for(var a=0;a<t.length;++a){var f=t[a].data[0][1];(s<2||f/n>i.series.pie.combine.threshold)&&u.push({data:[[1,f]],color:t[a].color,label:t[a].label,angle:f*Math.PI*2/n,percent:f/(n/100)})}return s>1&&u.push({data:[[1,r]],color:o,label:i.series.pie.combine.label,angle:r*Math.PI*2/n,percent:r/(n/100)}),u}function v(r,s){function y(){c.clearRect(0,0,h,p),o.children().filter(".pieLabel, .pieLabelBackground").remove()}function b(){var e=i.series.pie.shadow.left,t=i.series.pie.shadow.top,n=10,r=i.series.pie.shadow.alpha,s=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;if(s>=h/2-e||s*i.series.pie.tilt>=p/2-t||s<=n)return;c.save(),c.translate(e,t),c.globalAlpha=r,c.fillStyle="#000",c.translate(a,f),c.scale(1,i.series.pie.tilt);for(var o=1;o<=n;o++)c.beginPath(),c.arc(0,0,s,0,Math.PI*2,!1),c.fill(),s-=o;c.restore()}function w(){function l(e,t,i){if(e<=0||isNaN(e))return;i?c.fillStyle=t:(c.strokeStyle=t,c.lineJoin="round"),c.beginPath(),Math.abs(e-Math.PI*2)>1e-9&&c.moveTo(0,0),c.arc(0,0,n,r,r+e/2,!1),c.arc(0,0,n,r+e/2,r+e,!1),c.closePath(),r+=e,i?c.fill():c.stroke()}function d(){function l(t,n,s){if(t.data[0][1]==0)return!0;var u=i.legend.labelFormatter,l,c=i.series.pie.label.formatter;u?l=u(t.label,t):l=t.label,c&&(l=c(l,t));var d=(n+t.angle+n)/2,v=a+Math.round(Math.cos(d)*r),m=f+Math.round(Math.sin(d)*r)*i.series.pie.tilt,g="<span class='pieLabel' id='pieLabel"+s+"' style='position:absolute;top:"+m+"px;left:"+v+"px;'>"+l+"</span>";o.append(g);var y=o.children("#pieLabel"+s),b=m-y.height()/2,w=v-y.width()/2;y.css("top",b),y.css("left",w);if(0-b>0||0-w>0||p-(b+y.height())<0||h-(w+y.width())<0)return!1;if(i.series.pie.label.background.opacity!=0){var E=i.series.pie.label.background.color;E==null&&(E=t.color);var S="top:"+b+"px;left:"+w+"px;";e("<div class='pieLabelBackground' style='position:absolute;width:"+y.width()+"px;height:"+y.height()+"px;"+S+"background-color:"+E+";'></div>").css("opacity",i.series.pie.label.background.opacity).insertBefore(y)}return!0}var n=t,r=i.series.pie.label.radius>1?i.series.pie.label.radius:u*i.series.pie.label.radius;for(var s=0;s<v.length;++s){if(v[s].percent>=i.series.pie.label.threshold*100&&!l(v[s],n,s))return!1;n+=v[s].angle}return!0}var t=Math.PI*i.series.pie.startAngle,n=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;c.save(),c.translate(a,f),c.scale(1,i.series.pie.tilt),c.save();var r=t;for(var s=0;s<v.length;++s)v[s].startAngle=r,l(v[s].angle,v[s].color,!0);c.restore();if(i.series.pie.stroke.width>0){c.save(),c.lineWidth=i.series.pie.stroke.width,r=t;for(var s=0;s<v.length;++s)l(v[s].angle,i.series.pie.stroke.color,!1);c.restore()}return m(c),c.restore(),i.series.pie.label.show?d():!0}if(!o)return;var h=r.getPlaceholder().width(),p=r.getPlaceholder().height(),d=o.children().filter(".legend").children().width()||0;c=s,l=!1,u=Math.min(h,p/i.series.pie.tilt)/2,f=p/2+i.series.pie.offset.top,a=h/2,i.series.pie.offset.left=="auto"?i.legend.position.match("w")?a+=d/2:a-=d/2:a+=i.series.pie.offset.left,a<u?a=u:a>h-u&&(a=h-u);var v=r.getData(),g=0;do g>0&&(u*=n),g+=1,y(),i.series.pie.tilt<=.8&&b();while(!w()&&g<t);g>=t&&(y(),o.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>")),r.setSeries&&r.insertLegend&&(r.setSeries(v),r.insertLegend())}function m(e){if(i.series.pie.innerRadius>0){e.save();var t=i.series.pie.innerRadius>1?i.series.pie.innerRadius:u*i.series.pie.innerRadius;e.globalCompositeOperation="destination-out",e.beginPath(),e.fillStyle=i.series.pie.stroke.color,e.arc(0,0,t,0,Math.PI*2,!1),e.fill(),e.closePath(),e.restore(),e.save(),e.beginPath(),e.strokeStyle=i.series.pie.stroke.color,e.arc(0,0,t,0,Math.PI*2,!1),e.stroke(),e.closePath(),e.restore()}}function g(e,t){for(var n=!1,r=-1,i=e.length,s=i-1;++r<i;s=r)(e[r][1]<=t[1]&&t[1]<e[s][1]||e[s][1]<=t[1]&&t[1]<e[r][1])&&t[0]<(e[s][0]-e[r][0])*(t[1]-e[r][1])/(e[s][1]-e[r][1])+e[r][0]&&(n=!n);return n}function y(e,t){var n=r.getData(),i=r.getOptions(),s=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius,o,l;for(var h=0;h<n.length;++h){var p=n[h];if(p.pie.show){c.save(),c.beginPath(),c.moveTo(0,0),c.arc(0,0,s,p.startAngle,p.startAngle+p.angle/2,!1),c.arc(0,0,s,p.startAngle+p.angle/2,p.startAngle+p.angle,!1),c.closePath(),o=e-a,l=t-f;if(c.isPointInPath){if(c.isPointInPath(e-a,t-f))return c.restore(),{datapoint:[p.percent,p.data],dataIndex:0,series:p,seriesIndex:h}}else{var d=s*Math.cos(p.startAngle),v=s*Math.sin(p.startAngle),m=s*Math.cos(p.startAngle+p.angle/4),y=s*Math.sin(p.startAngle+p.angle/4),b=s*Math.cos(p.startAngle+p.angle/2),w=s*Math.sin(p.startAngle+p.angle/2),E=s*Math.cos(p.startAngle+p.angle/1.5),S=s*Math.sin(p.startAngle+p.angle/1.5),x=s*Math.cos(p.startAngle+p.angle),T=s*Math.sin(p.startAngle+p.angle),N=[[0,0],[d,v],[m,y],[b,w],[E,S],[x,T]],C=[o,l];if(g(N,C))return c.restore(),{datapoint:[p.percent,p.data],dataIndex:0,series:p,seriesIndex:h}}c.restore()}}return null}function b(e){E("plothover",e)}function w(e){E("plotclick",e)}function E(e,t){var n=r.offset(),s=parseInt(t.pageX-n.left),u=parseInt(t.pageY-n.top),a=y(s,u);if(i.grid.autoHighlight)for(var f=0;f<h.length;++f){var l=h[f];l.auto==e&&(!a||l.series!=a.series)&&x(l.series)}a&&S(a.series,e);var c={pageX:t.pageX,pageY:t.pageY};o.trigger(e,[c,a])}function S(e,t){var n=T(e);n==-1?(h.push({series:e,auto:t}),r.triggerRedrawOverlay()):t||(h[n].auto=!1)}function x(e){e==null&&(h=[],r.triggerRedrawOverlay());var t=T(e);t!=-1&&(h.splice(t,1),r.triggerRedrawOverlay())}function T(e){for(var t=0;t<h.length;++t){var n=h[t];if(n.series==e)return t}return-1}function N(e,t){function s(e){if(e.angle<=0||isNaN(e.angle))return;t.fillStyle="rgba(255, 255, 255, "+n.series.pie.highlight.opacity+")",t.beginPath(),Math.abs(e.angle-Math.PI*2)>1e-9&&t.moveTo(0,0),t.arc(0,0,r,e.startAngle,e.startAngle+e.angle/2,!1),t.arc(0,0,r,e.startAngle+e.angle/2,e.startAngle+e.angle,!1),t.closePath(),t.fill()}var n=e.getOptions(),r=n.series.pie.radius>1?n.series.pie.radius:u*n.series.pie.radius;t.save(),t.translate(a,f),t.scale(1,n.series.pie.tilt);for(var i=0;i<h.length;++i)s(h[i].series);m(t),t.restore()}var s=null,o=null,u=null,a=null,f=null,l=!1,c=null,h=[];r.hooks.processOptions.push(function(e,t){t.series.pie.show&&(t.grid.show=!1,t.series.pie.label.show=="auto"&&(t.legend.show?t.series.pie.label.show=!1:t.series.pie.label.show=!0),t.series.pie.radius=="auto"&&(t.series.pie.label.show?t.series.pie.radius=.75:t.series.pie.radius=1),t.series.pie.tilt>1?t.series.pie.tilt=1:t.series.pie.tilt<0&&(t.series.pie.tilt=0))}),r.hooks.bindEvents.push(function(e,t){var n=e.getOptions();n.series.pie.show&&(n.grid.hoverable&&t.unbind("mousemove").mousemove(b),n.grid.clickable&&t.unbind("click").click(w))}),r.hooks.processDatapoints.push(function(e,t,n,r){var i=e.getOptions();i.series.pie.show&&p(e,t,n,r)}),r.hooks.drawOverlay.push(function(e,t){var n=e.getOptions();n.series.pie.show&&N(e,t)}),r.hooks.draw.push(function(e,t){var n=e.getOptions();n.series.pie.show&&v(e,t)})}var t=10,n=.95,i={series:{pie:{show:!1,radius:"auto",innerRadius:0,startAngle:1.5,tilt:1,shadow:{left:5,top:15,alpha:.02},offset:{top:0,left:"auto"},stroke:{color:"#fff",width:1},label:{show:"auto",formatter:function(e,t){return"<div style='font-size:x-small;text-align:center;padding:2px;color:"+t.color+";'>"+e+"<br/>"+Math.round(t.percent)+"%</div>"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:.5}}}};e.plot.plugins.push({init:r,options:i,name:"pie",version:"1.1"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.resize.min.js b/third_party/flot/jquery.flot.resize.min.js
index 1fa0771..b2ddec1 100644
--- a/third_party/flot/jquery.flot.resize.min.js
+++ b/third_party/flot/jquery.flot.resize.min.js
@@ -1 +1,19 @@
-(function(n,p,u){var w=n([]),s=n.resize=n.extend(n.resize,{}),o,l="setTimeout",m="resize",t=m+"-special-event",v="delay",r="throttleWindow";s[v]=250;s[r]=true;n.event.special[m]={setup:function(){if(!s[r]&&this[l]){return false}var a=n(this);w=w.add(a);n.data(this,t,{w:a.width(),h:a.height()});if(w.length===1){q()}},teardown:function(){if(!s[r]&&this[l]){return false}var a=n(this);w=w.not(a);a.removeData(t);if(!w.length){clearTimeout(o)}},add:function(b){if(!s[r]&&this[l]){return false}var c;function a(d,h,g){var f=n(this),e=n.data(this,t);e.w=h!==u?h:f.width();e.h=g!==u?g:f.height();c.apply(this,arguments)}if(n.isFunction(b)){c=b;return a}else{c=b.handler;b.handler=a}}};function q(){o=p[l](function(){w.each(function(){var d=n(this),a=d.width(),b=d.height(),c=n.data(this,t);if(a!==c.w||b!==c.h){d.trigger(m,[c.w=a,c.h=b])}});q()},s[v])}})(jQuery,this);(function(b){var a={};function c(f){function e(){var h=f.getPlaceholder();if(h.width()==0||h.height()==0){return}f.resize();f.setupGrid();f.draw()}function g(i,h){i.getPlaceholder().resize(e)}function d(i,h){i.getPlaceholder().unbind("resize",e)}f.hooks.bindEvents.push(g);f.hooks.shutdown.push(d)}b.plot.plugins.push({init:c,options:a,name:"resize",version:"1.0"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for automatically redrawing plots as the placeholder resizes.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+It works by listening for changes on the placeholder div (through the jQuery
+resize event plugin) - if the size changes, it will redraw the plot.
+
+There are no options. If you need to disable the plugin for some plots, you
+can just fix the size of their placeholders.
+
+*//* Inline dependency:
+ * jQuery resize event - v1.1 - 3/14/2010
+ * http://benalman.com/projects/jquery-resize-plugin/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */(function(e,t,n){function c(){s=t[o](function(){r.each(function(){var t=e(this),n=t.width(),r=t.height(),i=e.data(this,a);(n!==i.w||r!==i.h)&&t.trigger(u,[i.w=n,i.h=r])}),c()},i[f])}var r=e([]),i=e.resize=e.extend(e.resize,{}),s,o="setTimeout",u="resize",a=u+"-special-event",f="delay",l="throttleWindow";i[f]=250,i[l]=!0,e.event.special[u]={setup:function(){if(!i[l]&&this[o])return!1;var t=e(this);r=r.add(t),e.data(this,a,{w:t.width(),h:t.height()}),r.length===1&&c()},teardown:function(){if(!i[l]&&this[o])return!1;var t=e(this);r=r.not(t),t.removeData(a),r.length||clearTimeout(s)},add:function(t){function s(t,i,s){var o=e(this),u=e.data(this,a);u.w=i!==n?i:o.width(),u.h=s!==n?s:o.height(),r.apply(this,arguments)}if(!i[l]&&this[o])return!1;var r;if(e.isFunction(t))return r=t,s;r=t.handler,t.handler=s}}})(jQuery,this),function(e){function n(e){function t(){var t=e.getPlaceholder();if(t.width()==0||t.height()==0)return;e.resize(),e.setupGrid(),e.draw()}function n(e,n){e.getPlaceholder().resize(t)}function r(e,n){e.getPlaceholder().unbind("resize",t)}e.hooks.bindEvents.push(n),e.hooks.shutdown.push(r)}var t={};e.plot.plugins.push({init:n,options:t,name:"resize",version:"1.0"})}(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.selection.min.js b/third_party/flot/jquery.flot.selection.min.js
index badc005..bbfb975 100644
--- a/third_party/flot/jquery.flot.selection.min.js
+++ b/third_party/flot/jquery.flot.selection.min.js
@@ -1 +1,79 @@
-(function(a){function b(k){var p={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var m={};var r=null;function e(s){if(p.active){l(s);k.getPlaceholder().trigger("plotselecting",[g()])}}function n(s){if(s.which!=1){return}document.body.focus();if(document.onselectstart!==undefined&&m.onselectstart==null){m.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&m.ondrag==null){m.ondrag=document.ondrag;document.ondrag=function(){return false}}d(p.first,s);p.active=true;r=function(t){j(t)};a(document).one("mouseup",r)}function j(s){r=null;if(document.onselectstart!==undefined){document.onselectstart=m.onselectstart}if(document.ondrag!==undefined){document.ondrag=m.ondrag}p.active=false;l(s);if(f()){i()}else{k.getPlaceholder().trigger("plotunselected",[]);k.getPlaceholder().trigger("plotselecting",[null])}return false}function g(){if(!f()){return null}var u={},t=p.first,s=p.second;a.each(k.getAxes(),function(v,w){if(w.used){var y=w.c2p(t[w.direction]),x=w.c2p(s[w.direction]);u[v]={from:Math.min(y,x),to:Math.max(y,x)}}});return u}function i(){var s=g();k.getPlaceholder().trigger("plotselected",[s]);if(s.xaxis&&s.yaxis){k.getPlaceholder().trigger("selected",[{x1:s.xaxis.from,y1:s.yaxis.from,x2:s.xaxis.to,y2:s.yaxis.to}])}}function h(t,u,s){return u<t?t:(u>s?s:u)}function d(w,t){var v=k.getOptions();var u=k.getPlaceholder().offset();var s=k.getPlotOffset();w.x=h(0,t.pageX-u.left-s.left,k.width());w.y=h(0,t.pageY-u.top-s.top,k.height());if(v.selection.mode=="y"){w.x=w==p.first?0:k.width()}if(v.selection.mode=="x"){w.y=w==p.first?0:k.height()}}function l(s){if(s.pageX==null){return}d(p.second,s);if(f()){p.show=true;k.triggerRedrawOverlay()}else{q(true)}}function q(s){if(p.show){p.show=false;k.triggerRedrawOverlay();if(!s){k.getPlaceholder().trigger("plotunselected",[])}}}function c(s,w){var t,y,z,A,x=k.getAxes();for(var u in x){t=x[u];if(t.direction==w){A=w+t.n+"axis";if(!s[A]&&t.n==1){A=w+"axis"}if(s[A]){y=s[A].from;z=s[A].to;break}}}if(!s[A]){t=w=="x"?k.getXAxes()[0]:k.getYAxes()[0];y=s[w+"1"];z=s[w+"2"]}if(y!=null&&z!=null&&y>z){var v=y;y=z;z=v}return{from:y,to:z,axis:t}}function o(t,s){var v,u,w=k.getOptions();if(w.selection.mode=="y"){p.first.x=0;p.second.x=k.width()}else{u=c(t,"x");p.first.x=u.axis.p2c(u.from);p.second.x=u.axis.p2c(u.to)}if(w.selection.mode=="x"){p.first.y=0;p.second.y=k.height()}else{u=c(t,"y");p.first.y=u.axis.p2c(u.from);p.second.y=u.axis.p2c(u.to)}p.show=true;k.triggerRedrawOverlay();if(!s&&f()){i()}}function f(){var s=5;return Math.abs(p.second.x-p.first.x)>=s&&Math.abs(p.second.y-p.first.y)>=s}k.clearSelection=q;k.setSelection=o;k.getSelection=g;k.hooks.bindEvents.push(function(t,s){var u=t.getOptions();if(u.selection.mode!=null){s.mousemove(e);s.mousedown(n)}});k.hooks.drawOverlay.push(function(v,D){if(p.show&&f()){var t=v.getPlotOffset();var s=v.getOptions();D.save();D.translate(t.left,t.top);var z=a.color.parse(s.selection.color);D.strokeStyle=z.scale("a",0.8).toString();D.lineWidth=1;D.lineJoin="round";D.fillStyle=z.scale("a",0.4).toString();var B=Math.min(p.first.x,p.second.x),A=Math.min(p.first.y,p.second.y),C=Math.abs(p.second.x-p.first.x),u=Math.abs(p.second.y-p.first.y);D.fillRect(B,A,C,u);D.strokeRect(B,A,C,u);D.restore()}});k.hooks.shutdown.push(function(t,s){s.unbind("mousemove",e);s.unbind("mousedown",n);if(r){a(document).unbind("mouseup",r)}})}a.plot.plugins.push({init:b,options:{selection:{mode:null,color:"#e8cfac"}},name:"selection",version:"1.1"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for selecting regions of a plot.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The plugin supports these options:
+
+selection: {
+	mode: null or "x" or "y" or "xy",
+	color: color,
+	shape: "round" or "miter" or "bevel",
+	minSize: number of pixels
+}
+
+Selection support is enabled by setting the mode to one of "x", "y" or "xy".
+In "x" mode, the user will only be able to specify the x range, similarly for
+"y" mode. For "xy", the selection becomes a rectangle where both ranges can be
+specified. "color" is color of the selection (if you need to change the color
+later on, you can get to it with plot.getOptions().selection.color). "shape"
+is the shape of the corners of the selection.
+
+"minSize" is the minimum size a selection can be in pixels. This value can
+be customized to determine the smallest size a selection can be and still
+have the selection rectangle be displayed. When customizing this value, the
+fact that it refers to pixels, not axis units must be taken into account.
+Thus, for example, if there is a bar graph in time mode with BarWidth set to 1
+minute, setting "minSize" to 1 will not make the minimum selection size 1
+minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent
+"plotunselected" events from being fired when the user clicks the mouse without
+dragging.
+
+When selection support is enabled, a "plotselected" event will be emitted on
+the DOM element you passed into the plot function. The event handler gets a
+parameter with the ranges selected on the axes, like this:
+
+	placeholder.bind( "plotselected", function( event, ranges ) {
+		alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
+		// similar for yaxis - with multiple axes, the extra ones are in
+		// x2axis, x3axis, ...
+	});
+
+The "plotselected" event is only fired when the user has finished making the
+selection. A "plotselecting" event is fired during the process with the same
+parameters as the "plotselected" event, in case you want to know what's
+happening while it's happening,
+
+A "plotunselected" event with no arguments is emitted when the user clicks the
+mouse to remove the selection. As stated above, setting "minSize" to 0 will
+destroy this behavior.
+
+The plugin allso adds the following methods to the plot object:
+
+- setSelection( ranges, preventEvent )
+
+  Set the selection rectangle. The passed in ranges is on the same form as
+  returned in the "plotselected" event. If the selection mode is "x", you
+  should put in either an xaxis range, if the mode is "y" you need to put in
+  an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
+  this:
+
+	setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
+
+  setSelection will trigger the "plotselected" event when called. If you don't
+  want that to happen, e.g. if you're inside a "plotselected" handler, pass
+  true as the second parameter. If you are using multiple axes, you can
+  specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of
+  xaxis, the plugin picks the first one it sees.
+
+- clearSelection( preventEvent )
+
+  Clear the selection rectangle. Pass in true to avoid getting a
+  "plotunselected" event.
+
+- getSelection()
+
+  Returns the current selection in the same format as the "plotselected"
+  event. If there's currently no selection, the function returns null.
+
+*/(function(e){function t(t){function s(e){n.active&&(h(e),t.getPlaceholder().trigger("plotselecting",[a()]))}function o(t){if(t.which!=1)return;document.body.focus(),document.onselectstart!==undefined&&r.onselectstart==null&&(r.onselectstart=document.onselectstart,document.onselectstart=function(){return!1}),document.ondrag!==undefined&&r.ondrag==null&&(r.ondrag=document.ondrag,document.ondrag=function(){return!1}),c(n.first,t),n.active=!0,i=function(e){u(e)},e(document).one("mouseup",i)}function u(e){return i=null,document.onselectstart!==undefined&&(document.onselectstart=r.onselectstart),document.ondrag!==undefined&&(document.ondrag=r.ondrag),n.active=!1,h(e),m()?f():(t.getPlaceholder().trigger("plotunselected",[]),t.getPlaceholder().trigger("plotselecting",[null])),!1}function a(){if(!m())return null;if(!n.show)return null;var r={},i=n.first,s=n.second;return e.each(t.getAxes(),function(e,t){if(t.used){var n=t.c2p(i[t.direction]),o=t.c2p(s[t.direction]);r[e]={from:Math.min(n,o),to:Math.max(n,o)}}}),r}function f(){var e=a();t.getPlaceholder().trigger("plotselected",[e]),e.xaxis&&e.yaxis&&t.getPlaceholder().trigger("selected",[{x1:e.xaxis.from,y1:e.yaxis.from,x2:e.xaxis.to,y2:e.yaxis.to}])}function l(e,t,n){return t<e?e:t>n?n:t}function c(e,r){var i=t.getOptions(),s=t.getPlaceholder().offset(),o=t.getPlotOffset();e.x=l(0,r.pageX-s.left-o.left,t.width()),e.y=l(0,r.pageY-s.top-o.top,t.height()),i.selection.mode=="y"&&(e.x=e==n.first?0:t.width()),i.selection.mode=="x"&&(e.y=e==n.first?0:t.height())}function h(e){if(e.pageX==null)return;c(n.second,e),m()?(n.show=!0,t.triggerRedrawOverlay()):p(!0)}function p(e){n.show&&(n.show=!1,t.triggerRedrawOverlay(),e||t.getPlaceholder().trigger("plotunselected",[]))}function d(e,n){var r,i,s,o,u=t.getAxes();for(var a in u){r=u[a];if(r.direction==n){o=n+r.n+"axis",!e[o]&&r.n==1&&(o=n+"axis");if(e[o]){i=e[o].from,s=e[o].to;break}}}e[o]||(r=n=="x"?t.getXAxes()[0]:t.getYAxes()[0],i=e[n+"1"],s=e[n+"2"]);if(i!=null&&s!=null&&i>s){var f=i;i=s,s=f}return{from:i,to:s,axis:r}}function v(e,r){var i,s,o=t.getOptions();o.selection.mode=="y"?(n.first.x=0,n.second.x=t.width()):(s=d(e,"x"),n.first.x=s.axis.p2c(s.from),n.second.x=s.axis.p2c(s.to)),o.selection.mode=="x"?(n.first.y=0,n.second.y=t.height()):(s=d(e,"y"),n.first.y=s.axis.p2c(s.from),n.second.y=s.axis.p2c(s.to)),n.show=!0,t.triggerRedrawOverlay(),!r&&m()&&f()}function m(){var e=t.getOptions().selection.minSize;return Math.abs(n.second.x-n.first.x)>=e&&Math.abs(n.second.y-n.first.y)>=e}var n={first:{x:-1,y:-1},second:{x:-1,y:-1},show:!1,active:!1},r={},i=null;t.clearSelection=p,t.setSelection=v,t.getSelection=a,t.hooks.bindEvents.push(function(e,t){var n=e.getOptions();n.selection.mode!=null&&(t.mousemove(s),t.mousedown(o))}),t.hooks.drawOverlay.push(function(t,r){if(n.show&&m()){var i=t.getPlotOffset(),s=t.getOptions();r.save(),r.translate(i.left,i.top);var o=e.color.parse(s.selection.color);r.strokeStyle=o.scale("a",.8).toString(),r.lineWidth=1,r.lineJoin=s.selection.shape,r.fillStyle=o.scale("a",.4).toString();var u=Math.min(n.first.x,n.second.x)+.5,a=Math.min(n.first.y,n.second.y)+.5,f=Math.abs(n.second.x-n.first.x)-1,l=Math.abs(n.second.y-n.first.y)-1;r.fillRect(u,a,f,l),r.strokeRect(u,a,f,l),r.restore()}}),t.hooks.shutdown.push(function(t,n){n.unbind("mousemove",s),n.unbind("mousedown",o),i&&e(document).unbind("mouseup",i)})}e.plot.plugins.push({init:t,options:{selection:{mode:null,color:"#e8cfac",shape:"round",minSize:5}},name:"selection",version:"1.1"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.stack.min.js b/third_party/flot/jquery.flot.stack.min.js
index bba2a0e..14e9931 100644
--- a/third_party/flot/jquery.flot.stack.min.js
+++ b/third_party/flot/jquery.flot.stack.min.js
@@ -1 +1,36 @@
-(function(b){var a={series:{stack:null}};function c(f){function d(k,j){var h=null;for(var g=0;g<j.length;++g){if(k==j[g]){break}if(j[g].stack==k.stack){h=j[g]}}return h}function e(C,v,g){if(v.stack==null){return}var p=d(v,C.getData());if(!p){return}var z=g.pointsize,F=g.points,h=p.datapoints.pointsize,y=p.datapoints.points,t=[],x,w,k,J,I,r,u=v.lines.show,G=v.bars.horizontal,o=z>2&&(G?g.format[2].x:g.format[2].y),n=u&&v.lines.steps,E=true,q=G?1:0,H=G?0:1,D=0,B=0,A;while(true){if(D>=F.length){break}A=t.length;if(F[D]==null){for(m=0;m<z;++m){t.push(F[D+m])}D+=z}else{if(B>=y.length){if(!u){for(m=0;m<z;++m){t.push(F[D+m])}}D+=z}else{if(y[B]==null){for(m=0;m<z;++m){t.push(null)}E=true;B+=h}else{x=F[D+q];w=F[D+H];J=y[B+q];I=y[B+H];r=0;if(x==J){for(m=0;m<z;++m){t.push(F[D+m])}t[A+H]+=I;r=I;D+=z;B+=h}else{if(x>J){if(u&&D>0&&F[D-z]!=null){k=w+(F[D-z+H]-w)*(J-x)/(F[D-z+q]-x);t.push(J);t.push(k+I);for(m=2;m<z;++m){t.push(F[D+m])}r=I}B+=h}else{if(E&&u){D+=z;continue}for(m=0;m<z;++m){t.push(F[D+m])}if(u&&B>0&&y[B-h]!=null){r=I+(y[B-h+H]-I)*(x-J)/(y[B-h+q]-J)}t[A+H]+=r;D+=z}}E=false;if(A!=t.length&&o){t[A+2]+=r}}}}if(n&&A!=t.length&&A>0&&t[A]!=null&&t[A]!=t[A-z]&&t[A+1]!=t[A-z+1]){for(m=0;m<z;++m){t[A+z+m]=t[A+m]}t[A+1]=t[A-z+1]}}g.points=t}f.hooks.processDatapoints.push(e)}b.plot.plugins.push({init:c,options:a,name:"stack",version:"1.2"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for stacking data sets rather than overlyaing them.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The plugin assumes the data is sorted on x (or y if stacking horizontally).
+For line charts, it is assumed that if a line has an undefined gap (from a
+null point), then the line above it should have the same gap - insert zeros
+instead of "null" if you want another behaviour. This also holds for the start
+and end of the chart. Note that stacking a mix of positive and negative values
+in most instances doesn't make sense (so it looks weird).
+
+Two or more series are stacked when their "stack" attribute is set to the same
+key (which can be any number or string or just "true"). To specify the default
+stack, you can set the stack option like this:
+
+	series: {
+		stack: null/false, true, or a key (number/string)
+	}
+
+You can also specify it for a single series, like this:
+
+	$.plot( $("#placeholder"), [{
+		data: [ ... ],
+		stack: true
+	}])
+
+The stacking order is determined by the order of the data series in the array
+(later series end up on top of the previous).
+
+Internally, the plugin modifies the datapoints in each series, adding an
+offset to the y value. For line series, extra data points are inserted through
+interpolation. If there's a second y value, it's also adjusted (e.g for bar
+charts or filled areas).
+
+*/(function(e){function n(e){function t(e,t){var n=null;for(var r=0;r<t.length;++r){if(e==t[r])break;t[r].stack==e.stack&&(n=t[r])}return n}function n(e,n,r){if(n.stack==null||n.stack===!1)return;var i=t(n,e.getData());if(!i)return;var s=r.pointsize,o=r.points,u=i.datapoints.pointsize,a=i.datapoints.points,f=[],l,c,h,p,d,v,m=n.lines.show,g=n.bars.horizontal,y=s>2&&(g?r.format[2].x:r.format[2].y),b=m&&n.lines.steps,w=!0,E=g?1:0,S=g?0:1,x=0,T=0,N,C;for(;;){if(x>=o.length)break;N=f.length;if(o[x]==null){for(C=0;C<s;++C)f.push(o[x+C]);x+=s}else if(T>=a.length){if(!m)for(C=0;C<s;++C)f.push(o[x+C]);x+=s}else if(a[T]==null){for(C=0;C<s;++C)f.push(null);w=!0,T+=u}else{l=o[x+E],c=o[x+S],p=a[T+E],d=a[T+S],v=0;if(l==p){for(C=0;C<s;++C)f.push(o[x+C]);f[N+S]+=d,v=d,x+=s,T+=u}else if(l>p){if(m&&x>0&&o[x-s]!=null){h=c+(o[x-s+S]-c)*(p-l)/(o[x-s+E]-l),f.push(p),f.push(h+d);for(C=2;C<s;++C)f.push(o[x+C]);v=d}T+=u}else{if(w&&m){x+=s;continue}for(C=0;C<s;++C)f.push(o[x+C]);m&&T>0&&a[T-u]!=null&&(v=d+(a[T-u+S]-d)*(l-p)/(a[T-u+E]-p)),f[N+S]+=v,x+=s}w=!1,N!=f.length&&y&&(f[N+2]+=v)}if(b&&N!=f.length&&N>0&&f[N]!=null&&f[N]!=f[N-s]&&f[N+1]!=f[N-s+1]){for(C=0;C<s;++C)f[N+s+C]=f[N+C];f[N+1]=f[N-s+1]}}r.points=f}e.hooks.processDatapoints.push(n)}var t={series:{stack:null}};e.plot.plugins.push({init:n,options:t,name:"stack",version:"1.2"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.symbol.min.js b/third_party/flot/jquery.flot.symbol.min.js
index 272e003..b78ea2e 100644
--- a/third_party/flot/jquery.flot.symbol.min.js
+++ b/third_party/flot/jquery.flot.symbol.min.js
@@ -1 +1,14 @@
-(function(b){function a(h,e,g){var d={square:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI)/2;k.rect(j-l,n-l,l+l,l+l)},diamond:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI/2);k.moveTo(j-l,n);k.lineTo(j,n-l);k.lineTo(j+l,n);k.lineTo(j,n+l);k.lineTo(j-l,n)},triangle:function(l,k,o,j,n){var m=j*Math.sqrt(2*Math.PI/Math.sin(Math.PI/3));var i=m*Math.sin(Math.PI/3);l.moveTo(k-m/2,o+i/2);l.lineTo(k+m/2,o+i/2);if(!n){l.lineTo(k,o-i/2);l.lineTo(k-m/2,o+i/2)}},cross:function(k,j,n,i,m){var l=i*Math.sqrt(Math.PI)/2;k.moveTo(j-l,n-l);k.lineTo(j+l,n+l);k.moveTo(j-l,n+l);k.lineTo(j+l,n-l)}};var f=e.points.symbol;if(d[f]){e.points.symbol=d[f]}}function c(d){d.hooks.processDatapoints.push(a)}b.plot.plugins.push({init:c,name:"symbols",version:"1.0"})})(jQuery);
\ No newline at end of file
+/* Flot plugin that adds some extra symbols for plotting points.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The symbols are accessed as strings through the standard symbol options:
+
+	series: {
+		points: {
+			symbol: "square" // or "diamond", "triangle", "cross"
+		}
+	}
+
+*/(function(e){function t(e,t,n){var r={square:function(e,t,n,r,i){var s=r*Math.sqrt(Math.PI)/2;e.rect(t-s,n-s,s+s,s+s)},diamond:function(e,t,n,r,i){var s=r*Math.sqrt(Math.PI/2);e.moveTo(t-s,n),e.lineTo(t,n-s),e.lineTo(t+s,n),e.lineTo(t,n+s),e.lineTo(t-s,n)},triangle:function(e,t,n,r,i){var s=r*Math.sqrt(2*Math.PI/Math.sin(Math.PI/3)),o=s*Math.sin(Math.PI/3);e.moveTo(t-s/2,n+o/2),e.lineTo(t+s/2,n+o/2),i||(e.lineTo(t,n-o/2),e.lineTo(t-s/2,n+o/2))},cross:function(e,t,n,r,i){var s=r*Math.sqrt(Math.PI)/2;e.moveTo(t-s,n-s),e.lineTo(t+s,n+s),e.moveTo(t-s,n+s),e.lineTo(t+s,n-s)}},i=t.points.symbol;r[i]&&(t.points.symbol=r[i])}function n(e){e.hooks.processDatapoints.push(t)}e.plot.plugins.push({init:n,name:"symbols",version:"1.0"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.threshold.min.js b/third_party/flot/jquery.flot.threshold.min.js
index d8b79df..1ca88a6 100644
--- a/third_party/flot/jquery.flot.threshold.min.js
+++ b/third_party/flot/jquery.flot.threshold.min.js
@@ -1 +1,43 @@
-(function(B){var A={series:{threshold:null}};function C(D){function E(L,S,M){if(!S.threshold){return }var F=M.pointsize,I,O,N,G,K,H=B.extend({},S);H.datapoints={points:[],pointsize:F};H.label=null;H.color=S.threshold.color;H.threshold=null;H.originSeries=S;H.data=[];var P=S.threshold.below,Q=M.points,R=S.lines.show;threspoints=[];newpoints=[];for(I=0;I<Q.length;I+=F){O=Q[I];N=Q[I+1];K=G;if(N<P){G=threspoints}else{G=newpoints}if(R&&K!=G&&O!=null&&I>0&&Q[I-F]!=null){var J=(O-Q[I-F])/(N-Q[I-F+1])*(P-N)+O;K.push(J);K.push(P);for(m=2;m<F;++m){K.push(Q[I+m])}G.push(null);G.push(null);for(m=2;m<F;++m){G.push(Q[I+m])}G.push(J);G.push(P);for(m=2;m<F;++m){G.push(Q[I+m])}}G.push(O);G.push(N)}M.points=newpoints;H.datapoints.points=threspoints;if(H.datapoints.points.length>0){L.getData().push(H)}}D.hooks.processDatapoints.push(E)}B.plot.plugins.push({init:C,options:A,name:"threshold",version:"1.0"})})(jQuery);
\ No newline at end of file
+/* Flot plugin for thresholding data.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The plugin supports these options:
+
+	series: {
+		threshold: {
+			below: number
+			color: colorspec
+		}
+	}
+
+It can also be applied to a single series, like this:
+
+	$.plot( $("#placeholder"), [{
+		data: [ ... ],
+		threshold: { ... }
+	}])
+
+An array can be passed for multiple thresholding, like this:
+
+	threshold: [{
+		below: number1
+		color: color1
+	},{
+		below: number2
+		color: color2
+	}]
+
+These multiple threshold objects can be passed in any order since they are
+sorted by the processing function.
+
+The data points below "below" are drawn with the specified color. This makes
+it easy to mark points below 0, e.g. for budget data.
+
+Internally, the plugin works by splitting the data into two series, above and
+below the threshold. The extra series below the threshold will have its label
+cleared and the special "originSeries" attribute set to the original series.
+You may need to check for this in hover events.
+
+*/(function(e){function n(t){function n(t,n,r,i,s){var o=r.pointsize,u,a,f,l,c,h=e.extend({},n);h.datapoints={points:[],pointsize:o,format:r.format},h.label=null,h.color=s,h.threshold=null,h.originSeries=n,h.data=[];var p=r.points,d=n.lines.show,v=[],m=[],g;for(u=0;u<p.length;u+=o){a=p[u],f=p[u+1],c=l,f<i?l=v:l=m;if(d&&c!=l&&a!=null&&u>0&&p[u-o]!=null){var y=a+(i-f)*(a-p[u-o])/(f-p[u-o+1]);c.push(y),c.push(i);for(g=2;g<o;++g)c.push(p[u+g]);l.push(null),l.push(null);for(g=2;g<o;++g)l.push(p[u+g]);l.push(y),l.push(i);for(g=2;g<o;++g)l.push(p[u+g])}l.push(a),l.push(f);for(g=2;g<o;++g)l.push(p[u+g])}r.points=m,h.datapoints.points=v;if(h.datapoints.points.length>0){var b=e.inArray(n,t.getData());t.getData().splice(b+1,0,h)}}function r(t,r,i){if(!r.threshold)return;r.threshold instanceof Array?(r.threshold.sort(function(e,t){return e.below-t.below}),e(r.threshold).each(function(e,o){n(t,r,i,o.below,o.color)})):n(t,r,i,r.threshold.below,r.threshold.color)}t.hooks.processDatapoints.push(r)}var t={series:{threshold:null}};e.plot.plugins.push({init:n,options:t,name:"threshold",version:"1.2"})})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.flot.time.min.js b/third_party/flot/jquery.flot.time.min.js
new file mode 100644
index 0000000..21d8477
--- /dev/null
+++ b/third_party/flot/jquery.flot.time.min.js
@@ -0,0 +1,9 @@
+/* Pretty handling of time axes.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+Set axis.mode to "time" to enable. See the section "Time series data" in
+API.txt for details.
+
+*/(function(e){function n(e,t){return t*Math.floor(e/t)}function r(e,t,n,r){if(typeof e.strftime=="function")return e.strftime(t);var i=function(e,t){return e=""+e,t=""+(t==null?"0":t),e.length==1?t+e:e},s=[],o=!1,u=e.getHours(),a=u<12;n==null&&(n=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]),r==null&&(r=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]);var f;u>12?f=u-12:u==0?f=12:f=u;for(var l=0;l<t.length;++l){var c=t.charAt(l);if(o){switch(c){case"a":c=""+r[e.getDay()];break;case"b":c=""+n[e.getMonth()];break;case"d":c=i(e.getDate());break;case"e":c=i(e.getDate()," ");break;case"h":case"H":c=i(u);break;case"I":c=i(f);break;case"l":c=i(f," ");break;case"m":c=i(e.getMonth()+1);break;case"M":c=i(e.getMinutes());break;case"q":c=""+(Math.floor(e.getMonth()/3)+1);break;case"S":c=i(e.getSeconds());break;case"y":c=i(e.getFullYear()%100);break;case"Y":c=""+e.getFullYear();break;case"p":c=a?"am":"pm";break;case"P":c=a?"AM":"PM";break;case"w":c=""+e.getDay()}s.push(c),o=!1}else c=="%"?o=!0:s.push(c)}return s.join("")}function i(e){function t(e,t,n,r){e[t]=function(){return n[r].apply(n,arguments)}}var n={date:e};e.strftime!=undefined&&t(n,"strftime",e,"strftime"),t(n,"getTime",e,"getTime"),t(n,"setTime",e,"setTime");var r=["Date","Day","FullYear","Hours","Milliseconds","Minutes","Month","Seconds"];for(var i=0;i<r.length;i++)t(n,"get"+r[i],e,"getUTC"+r[i]),t(n,"set"+r[i],e,"setUTC"+r[i]);return n}function s(e,t){if(t.timezone=="browser")return new Date(e);if(!t.timezone||t.timezone=="utc")return i(new Date(e));if(typeof timezoneJS!="undefined"&&typeof timezoneJS.Date!="undefined"){var n=new timezoneJS.Date;return n.setTimezone(t.timezone),n.setTime(e),n}return i(new Date(e))}function l(t){t.hooks.processOptions.push(function(t,i){e.each(t.getAxes(),function(e,t){var i=t.options;i.mode=="time"&&(t.tickGenerator=function(e){var t=[],r=s(e.min,i),u=0,l=i.tickSize&&i.tickSize[1]==="quarter"||i.minTickSize&&i.minTickSize[1]==="quarter"?f:a;i.minTickSize!=null&&(typeof i.tickSize=="number"?u=i.tickSize:u=i.minTickSize[0]*o[i.minTickSize[1]]);for(var c=0;c<l.length-1;++c)if(e.delta<(l[c][0]*o[l[c][1]]+l[c+1][0]*o[l[c+1][1]])/2&&l[c][0]*o[l[c][1]]>=u)break;var h=l[c][0],p=l[c][1];if(p=="year"){if(i.minTickSize!=null&&i.minTickSize[1]=="year")h=Math.floor(i.minTickSize[0]);else{var d=Math.pow(10,Math.floor(Math.log(e.delta/o.year)/Math.LN10)),v=e.delta/o.year/d;v<1.5?h=1:v<3?h=2:v<7.5?h=5:h=10,h*=d}h<1&&(h=1)}e.tickSize=i.tickSize||[h,p];var m=e.tickSize[0];p=e.tickSize[1];var g=m*o[p];p=="second"?r.setSeconds(n(r.getSeconds(),m)):p=="minute"?r.setMinutes(n(r.getMinutes(),m)):p=="hour"?r.setHours(n(r.getHours(),m)):p=="month"?r.setMonth(n(r.getMonth(),m)):p=="quarter"?r.setMonth(3*n(r.getMonth()/3,m)):p=="year"&&r.setFullYear(n(r.getFullYear(),m)),r.setMilliseconds(0),g>=o.minute&&r.setSeconds(0),g>=o.hour&&r.setMinutes(0),g>=o.day&&r.setHours(0),g>=o.day*4&&r.setDate(1),g>=o.month*2&&r.setMonth(n(r.getMonth(),3)),g>=o.quarter*2&&r.setMonth(n(r.getMonth(),6)),g>=o.year&&r.setMonth(0);var y=0,b=Number.NaN,w;do{w=b,b=r.getTime(),t.push(b);if(p=="month"||p=="quarter")if(m<1){r.setDate(1);var E=r.getTime();r.setMonth(r.getMonth()+(p=="quarter"?3:1));var S=r.getTime();r.setTime(b+y*o.hour+(S-E)*m),y=r.getHours(),r.setHours(0)}else r.setMonth(r.getMonth()+m*(p=="quarter"?3:1));else p=="year"?r.setFullYear(r.getFullYear()+m):r.setTime(b+g)}while(b<e.max&&b!=w);return t},t.tickFormatter=function(e,t){var n=s(e,t.options);if(i.timeformat!=null)return r(n,i.timeformat,i.monthNames,i.dayNames);var u=t.options.tickSize&&t.options.tickSize[1]=="quarter"||t.options.minTickSize&&t.options.minTickSize[1]=="quarter",a=t.tickSize[0]*o[t.tickSize[1]],f=t.max-t.min,l=i.twelveHourClock?" %p":"",c=i.twelveHourClock?"%I":"%H",h;a<o.minute?h=c+":%M:%S"+l:a<o.day?f<2*o.day?h=c+":%M"+l:h="%b %d "+c+":%M"+l:a<o.month?h="%b %d":u&&a<o.quarter||!u&&a<o.year?f<o.year?h="%b":h="%b %Y":u&&a<o.year?f<o.year?h="Q%q":h="Q%q %Y":h="%Y";var p=r(n,h,i.monthNames,i.dayNames);return p})})})}var t={xaxis:{timezone:null,timeformat:null,twelveHourClock:!1,monthNames:null}},o={second:1e3,minute:6e4,hour:36e5,day:864e5,month:2592e6,quarter:7776e6,year:525949.2*60*1e3},u=[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[.25,"month"],[.5,"month"],[1,"month"],[2,"month"]],a=u.concat([[3,"month"],[6,"month"],[1,"year"]]),f=u.concat([[1,"quarter"],[2,"quarter"],[1,"year"]]);e.plot.plugins.push({init:l,options:t,name:"time",version:"1.0"}),e.plot.formatDate=r})(jQuery);
\ No newline at end of file
diff --git a/third_party/flot/jquery.min.js b/third_party/flot/jquery.min.js
index 6422523..3883779 100644
--- a/third_party/flot/jquery.min.js
+++ b/third_party/flot/jquery.min.js
@@ -1,23 +1,2 @@
-/*
- * jQuery JavaScript Library v1.5.1
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Wed Feb 23 13:55:29 2011 -0500
- */
-(function(aY,H){var al=aY.document;var a=(function(){var bn=function(bI,bJ){return new bn.fn.init(bI,bJ,bl)},bD=aY.jQuery,bp=aY.$,bl,bH=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,bv=/\S/,br=/^\s+/,bm=/\s+$/,bq=/\d/,bj=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,bw=/^[\],:{}\s]*$/,bF=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,by=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,bs=/(?:^|:|,)(?:\s*\[)+/g,bh=/(webkit)[ \/]([\w.]+)/,bA=/(opera)(?:.*version)?[ \/]([\w.]+)/,bz=/(msie) ([\w.]+)/,bB=/(mozilla)(?:.*? rv:([\w.]+))?/,bG=navigator.userAgent,bE,bC=false,bk,e="then done fail isResolved isRejected promise".split(" "),bd,bu=Object.prototype.toString,bo=Object.prototype.hasOwnProperty,bi=Array.prototype.push,bt=Array.prototype.slice,bx=String.prototype.trim,be=Array.prototype.indexOf,bg={};bn.fn=bn.prototype={constructor:bn,init:function(bI,bM,bL){var bK,bN,bJ,bO;if(!bI){return this}if(bI.nodeType){this.context=this[0]=bI;this.length=1;return this}if(bI==="body"&&!bM&&al.body){this.context=al;this[0]=al.body;this.selector="body";this.length=1;return this}if(typeof bI==="string"){bK=bH.exec(bI);if(bK&&(bK[1]||!bM)){if(bK[1]){bM=bM instanceof bn?bM[0]:bM;bO=(bM?bM.ownerDocument||bM:al);bJ=bj.exec(bI);if(bJ){if(bn.isPlainObject(bM)){bI=[al.createElement(bJ[1])];bn.fn.attr.call(bI,bM,true)}else{bI=[bO.createElement(bJ[1])]}}else{bJ=bn.buildFragment([bK[1]],[bO]);bI=(bJ.cacheable?bn.clone(bJ.fragment):bJ.fragment).childNodes}return bn.merge(this,bI)}else{bN=al.getElementById(bK[2]);if(bN&&bN.parentNode){if(bN.id!==bK[2]){return bL.find(bI)}this.length=1;this[0]=bN}this.context=al;this.selector=bI;return this}}else{if(!bM||bM.jquery){return(bM||bL).find(bI)}else{return this.constructor(bM).find(bI)}}}else{if(bn.isFunction(bI)){return bL.ready(bI)}}if(bI.selector!==H){this.selector=bI.selector;this.context=bI.context}return bn.makeArray(bI,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return bt.call(this,0)},get:function(bI){return bI==null?this.toArray():(bI<0?this[this.length+bI]:this[bI])},pushStack:function(bJ,bL,bI){var bK=this.constructor();if(bn.isArray(bJ)){bi.apply(bK,bJ)}else{bn.merge(bK,bJ)}bK.prevObject=this;bK.context=this.context;if(bL==="find"){bK.selector=this.selector+(this.selector?" ":"")+bI}else{if(bL){bK.selector=this.selector+"."+bL+"("+bI+")"}}return bK},each:function(bJ,bI){return bn.each(this,bJ,bI)},ready:function(bI){bn.bindReady();bk.done(bI);return this},eq:function(bI){return bI===-1?this.slice(bI):this.slice(bI,+bI+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(bt.apply(this,arguments),"slice",bt.call(arguments).join(","))},map:function(bI){return this.pushStack(bn.map(this,function(bK,bJ){return bI.call(bK,bJ,bK)}))},end:function(){return this.prevObject||this.constructor(null)},push:bi,sort:[].sort,splice:[].splice};bn.fn.init.prototype=bn.fn;bn.extend=bn.fn.extend=function(){var bR,bK,bI,bJ,bO,bP,bN=arguments[0]||{},bM=1,bL=arguments.length,bQ=false;if(typeof bN==="boolean"){bQ=bN;bN=arguments[1]||{};bM=2}if(typeof bN!=="object"&&!bn.isFunction(bN)){bN={}}if(bL===bM){bN=this;--bM}for(;bM<bL;bM++){if((bR=arguments[bM])!=null){for(bK in bR){bI=bN[bK];bJ=bR[bK];if(bN===bJ){continue}if(bQ&&bJ&&(bn.isPlainObject(bJ)||(bO=bn.isArray(bJ)))){if(bO){bO=false;bP=bI&&bn.isArray(bI)?bI:[]}else{bP=bI&&bn.isPlainObject(bI)?bI:{}}bN[bK]=bn.extend(bQ,bP,bJ)}else{if(bJ!==H){bN[bK]=bJ}}}}}return bN};bn.extend({noConflict:function(bI){aY.$=bp;if(bI){aY.jQuery=bD}return bn},isReady:false,readyWait:1,ready:function(bI){if(bI===true){bn.readyWait--}if(!bn.readyWait||(bI!==true&&!bn.isReady)){if(!al.body){return setTimeout(bn.ready,1)}bn.isReady=true;if(bI!==true&&--bn.readyWait>0){return}bk.resolveWith(al,[bn]);if(bn.fn.trigger){bn(al).trigger("ready").unbind("ready")}}},bindReady:function(){if(bC){return}bC=true;if(al.readyState==="complete"){return setTimeout(bn.ready,1)}if(al.addEventListener){al.addEventListener("DOMContentLoaded",bd,false);aY.addEventListener("load",bn.ready,false)}else{if(al.attachEvent){al.attachEvent("onreadystatechange",bd);aY.attachEvent("onload",bn.ready);var bI=false;try{bI=aY.frameElement==null}catch(bJ){}if(al.documentElement.doScroll&&bI){bf()}}}},isFunction:function(bI){return bn.type(bI)==="function"},isArray:Array.isArray||function(bI){return bn.type(bI)==="array"},isWindow:function(bI){return bI&&typeof bI==="object"&&"setInterval" in bI},isNaN:function(bI){return bI==null||!bq.test(bI)||isNaN(bI)},type:function(bI){return bI==null?String(bI):bg[bu.call(bI)]||"object"},isPlainObject:function(bJ){if(!bJ||bn.type(bJ)!=="object"||bJ.nodeType||bn.isWindow(bJ)){return false}if(bJ.constructor&&!bo.call(bJ,"constructor")&&!bo.call(bJ.constructor.prototype,"isPrototypeOf")){return false}var bI;for(bI in bJ){}return bI===H||bo.call(bJ,bI)},isEmptyObject:function(bJ){for(var bI in bJ){return false}return true},error:function(bI){throw bI},parseJSON:function(bI){if(typeof bI!=="string"||!bI){return null}bI=bn.trim(bI);if(bw.test(bI.replace(bF,"@").replace(by,"]").replace(bs,""))){return aY.JSON&&aY.JSON.parse?aY.JSON.parse(bI):(new Function("return "+bI))()}else{bn.error("Invalid JSON: "+bI)}},parseXML:function(bK,bI,bJ){if(aY.DOMParser){bJ=new DOMParser();bI=bJ.parseFromString(bK,"text/xml")}else{bI=new ActiveXObject("Microsoft.XMLDOM");bI.async="false";bI.loadXML(bK)}bJ=bI.documentElement;if(!bJ||!bJ.nodeName||bJ.nodeName==="parsererror"){bn.error("Invalid XML: "+bK)}return bI},noop:function(){},globalEval:function(bK){if(bK&&bv.test(bK)){var bJ=al.head||al.getElementsByTagName("head")[0]||al.documentElement,bI=al.createElement("script");if(bn.support.scriptEval()){bI.appendChild(al.createTextNode(bK))}else{bI.text=bK}bJ.insertBefore(bI,bJ.firstChild);bJ.removeChild(bI)}},nodeName:function(bJ,bI){return bJ.nodeName&&bJ.nodeName.toUpperCase()===bI.toUpperCase()},each:function(bL,bP,bK){var bJ,bM=0,bN=bL.length,bI=bN===H||bn.isFunction(bL);if(bK){if(bI){for(bJ in bL){if(bP.apply(bL[bJ],bK)===false){break}}}else{for(;bM<bN;){if(bP.apply(bL[bM++],bK)===false){break}}}}else{if(bI){for(bJ in bL){if(bP.call(bL[bJ],bJ,bL[bJ])===false){break}}}else{for(var bO=bL[0];bM<bN&&bP.call(bO,bM,bO)!==false;bO=bL[++bM]){}}}return bL},trim:bx?function(bI){return bI==null?"":bx.call(bI)}:function(bI){return bI==null?"":bI.toString().replace(br,"").replace(bm,"")},makeArray:function(bL,bJ){var bI=bJ||[];if(bL!=null){var bK=bn.type(bL);if(bL.length==null||bK==="string"||bK==="function"||bK==="regexp"||bn.isWindow(bL)){bi.call(bI,bL)}else{bn.merge(bI,bL)}}return bI},inArray:function(bK,bL){if(bL.indexOf){return bL.indexOf(bK)}for(var bI=0,bJ=bL.length;bI<bJ;bI++){if(bL[bI]===bK){return bI}}return -1},merge:function(bM,bK){var bL=bM.length,bJ=0;if(typeof bK.length==="number"){for(var bI=bK.length;bJ<bI;bJ++){bM[bL++]=bK[bJ]}}else{while(bK[bJ]!==H){bM[bL++]=bK[bJ++]}}bM.length=bL;return bM},grep:function(bJ,bO,bI){var bK=[],bN;bI=!!bI;for(var bL=0,bM=bJ.length;bL<bM;bL++){bN=!!bO(bJ[bL],bL);if(bI!==bN){bK.push(bJ[bL])}}return bK},map:function(bJ,bO,bI){var bK=[],bN;for(var bL=0,bM=bJ.length;bL<bM;bL++){bN=bO(bJ[bL],bL,bI);if(bN!=null){bK[bK.length]=bN}}return bK.concat.apply([],bK)},guid:1,proxy:function(bK,bJ,bI){if(arguments.length===2){if(typeof bJ==="string"){bI=bK;bK=bI[bJ];bJ=H}else{if(bJ&&!bn.isFunction(bJ)){bI=bJ;bJ=H}}}if(!bJ&&bK){bJ=function(){return bK.apply(bI||this,arguments)}}if(bK){bJ.guid=bK.guid=bK.guid||bJ.guid||bn.guid++}return bJ},access:function(bI,bQ,bO,bK,bN,bP){var bJ=bI.length;if(typeof bQ==="object"){for(var bL in bQ){bn.access(bI,bL,bQ[bL],bK,bN,bO)}return bI}if(bO!==H){bK=!bP&&bK&&bn.isFunction(bO);for(var bM=0;bM<bJ;bM++){bN(bI[bM],bQ,bK?bO.call(bI[bM],bM,bN(bI[bM],bQ)):bO,bP)}return bI}return bJ?bN(bI[0],bQ):H},now:function(){return(new Date()).getTime()},_Deferred:function(){var bL=[],bM,bJ,bK,bI={done:function(){if(!bK){var bO=arguments,bP,bS,bR,bQ,bN;if(bM){bN=bM;bM=0}for(bP=0,bS=bO.length;bP<bS;bP++){bR=bO[bP];bQ=bn.type(bR);if(bQ==="array"){bI.done.apply(bI,bR)}else{if(bQ==="function"){bL.push(bR)}}}if(bN){bI.resolveWith(bN[0],bN[1])}}return this},resolveWith:function(bO,bN){if(!bK&&!bM&&!bJ){bJ=1;try{while(bL[0]){bL.shift().apply(bO,bN)}}catch(bP){throw bP}finally{bM=[bO,bN];bJ=0}}return this},resolve:function(){bI.resolveWith(bn.isFunction(this.promise)?this.promise():this,arguments);return this},isResolved:function(){return !!(bJ||bM)},cancel:function(){bK=1;bL=[];return this}};return bI},Deferred:function(bJ){var bI=bn._Deferred(),bL=bn._Deferred(),bK;bn.extend(bI,{then:function(bN,bM){bI.done(bN).fail(bM);return this},fail:bL.done,rejectWith:bL.resolveWith,reject:bL.resolve,isRejected:bL.isResolved,promise:function(bN){if(bN==null){if(bK){return bK}bK=bN={}}var bM=e.length;while(bM--){bN[e[bM]]=bI[e[bM]]}return bN}});bI.done(bL.cancel).fail(bI.cancel);delete bI.cancel;if(bJ){bJ.call(bI,bI)}return bI},when:function(bJ){var bO=arguments.length,bI=bO<=1&&bJ&&bn.isFunction(bJ.promise)?bJ:bn.Deferred(),bM=bI.promise();if(bO>1){var bN=bt.call(arguments,0),bL=bO,bK=function(bP){return function(bQ){bN[bP]=arguments.length>1?bt.call(arguments,0):bQ;if(!(--bL)){bI.resolveWith(bM,bN)}}};while((bO--)){bJ=bN[bO];if(bJ&&bn.isFunction(bJ.promise)){bJ.promise().then(bK(bO),bI.reject)}else{--bL}}if(!bL){bI.resolveWith(bM,bN)}}else{if(bI!==bJ){bI.resolve(bJ)}}return bM},uaMatch:function(bJ){bJ=bJ.toLowerCase();var bI=bh.exec(bJ)||bA.exec(bJ)||bz.exec(bJ)||bJ.indexOf("compatible")<0&&bB.exec(bJ)||[];return{browser:bI[1]||"",version:bI[2]||"0"}},sub:function(){function bJ(bL,bM){return new bJ.fn.init(bL,bM)}bn.extend(true,bJ,this);bJ.superclass=this;bJ.fn=bJ.prototype=this();bJ.fn.constructor=bJ;bJ.subclass=this.subclass;bJ.fn.init=function bK(bL,bM){if(bM&&bM instanceof bn&&!(bM instanceof bJ)){bM=bJ(bM)}return bn.fn.init.call(this,bL,bM,bI)};bJ.fn.init.prototype=bJ.fn;var bI=bJ(al);return bJ},browser:{}});bk=bn._Deferred();bn.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(bJ,bI){bg["[object "+bI+"]"]=bI.toLowerCase()});bE=bn.uaMatch(bG);if(bE.browser){bn.browser[bE.browser]=true;bn.browser.version=bE.version}if(bn.browser.webkit){bn.browser.safari=true}if(be){bn.inArray=function(bI,bJ){return be.call(bJ,bI)}}if(bv.test("\xA0")){br=/^[\s\xA0]+/;bm=/[\s\xA0]+$/}bl=bn(al);if(al.addEventListener){bd=function(){al.removeEventListener("DOMContentLoaded",bd,false);bn.ready()}}else{if(al.attachEvent){bd=function(){if(al.readyState==="complete"){al.detachEvent("onreadystatechange",bd);bn.ready()}}}}function bf(){if(bn.isReady){return}try{al.documentElement.doScroll("left")}catch(bI){setTimeout(bf,1);return}bn.ready()}return bn})();(function(){a.support={};var bd=al.createElement("div");bd.style.display="none";bd.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var bm=bd.getElementsByTagName("*"),bk=bd.getElementsByTagName("a")[0],bl=al.createElement("select"),be=bl.appendChild(al.createElement("option")),bj=bd.getElementsByTagName("input")[0];if(!bm||!bm.length||!bk){return}a.support={leadingWhitespace:bd.firstChild.nodeType===3,tbody:!bd.getElementsByTagName("tbody").length,htmlSerialize:!!bd.getElementsByTagName("link").length,style:/red/.test(bk.getAttribute("style")),hrefNormalized:bk.getAttribute("href")==="/a",opacity:/^0.55$/.test(bk.style.opacity),cssFloat:!!bk.style.cssFloat,checkOn:bj.value==="on",optSelected:be.selected,deleteExpando:true,optDisabled:false,checkClone:false,noCloneEvent:true,noCloneChecked:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};bj.checked=true;a.support.noCloneChecked=bj.cloneNode(true).checked;bl.disabled=true;a.support.optDisabled=!be.disabled;var bf=null;a.support.scriptEval=function(){if(bf===null){var bo=al.documentElement,bp=al.createElement("script"),br="script"+a.now();try{bp.appendChild(al.createTextNode("window."+br+"=1;"))}catch(bq){}bo.insertBefore(bp,bo.firstChild);if(aY[br]){bf=true;delete aY[br]}else{bf=false}bo.removeChild(bp);bo=bp=br=null}return bf};try{delete bd.test}catch(bh){a.support.deleteExpando=false}if(!bd.addEventListener&&bd.attachEvent&&bd.fireEvent){bd.attachEvent("onclick",function bn(){a.support.noCloneEvent=false;bd.detachEvent("onclick",bn)});bd.cloneNode(true).fireEvent("onclick")}bd=al.createElement("div");bd.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";var bg=al.createDocumentFragment();bg.appendChild(bd.firstChild);a.support.checkClone=bg.cloneNode(true).cloneNode(true).lastChild.checked;a(function(){var bp=al.createElement("div"),e=al.getElementsByTagName("body")[0];if(!e){return}bp.style.width=bp.style.paddingLeft="1px";e.appendChild(bp);a.boxModel=a.support.boxModel=bp.offsetWidth===2;if("zoom" in bp.style){bp.style.display="inline";bp.style.zoom=1;a.support.inlineBlockNeedsLayout=bp.offsetWidth===2;bp.style.display="";bp.innerHTML="<div style='width:4px;'></div>";a.support.shrinkWrapBlocks=bp.offsetWidth!==2}bp.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";var bo=bp.getElementsByTagName("td");a.support.reliableHiddenOffsets=bo[0].offsetHeight===0;bo[0].style.display="";bo[1].style.display="none";a.support.reliableHiddenOffsets=a.support.reliableHiddenOffsets&&bo[0].offsetHeight===0;bp.innerHTML="";e.removeChild(bp).style.display="none";bp=bo=null});var bi=function(e){var bp=al.createElement("div");e="on"+e;if(!bp.attachEvent){return true}var bo=(e in bp);if(!bo){bp.setAttribute(e,"return;");bo=typeof bp[e]==="function"}bp=null;return bo};a.support.submitBubbles=bi("submit");a.support.changeBubbles=bi("change");bd=bm=bk=null})();var aE=/^(?:\{.*\}|\[.*\])$/;a.extend({cache:{},uuid:0,expando:"jQuery"+(a.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},hasData:function(e){e=e.nodeType?a.cache[e[a.expando]]:e[a.expando];return !!e&&!P(e)},data:function(bf,bd,bh,bg){if(!a.acceptData(bf)){return}var bk=a.expando,bj=typeof bd==="string",bi,bl=bf.nodeType,e=bl?a.cache:bf,be=bl?bf[a.expando]:bf[a.expando]&&a.expando;if((!be||(bg&&be&&!e[be][bk]))&&bj&&bh===H){return}if(!be){if(bl){bf[a.expando]=be=++a.uuid}else{be=a.expando}}if(!e[be]){e[be]={};if(!bl){e[be].toJSON=a.noop}}if(typeof bd==="object"||typeof bd==="function"){if(bg){e[be][bk]=a.extend(e[be][bk],bd)}else{e[be]=a.extend(e[be],bd)}}bi=e[be];if(bg){if(!bi[bk]){bi[bk]={}}bi=bi[bk]}if(bh!==H){bi[bd]=bh}if(bd==="events"&&!bi[bd]){return bi[bk]&&bi[bk].events}return bj?bi[bd]:bi},removeData:function(bg,be,bh){if(!a.acceptData(bg)){return}var bj=a.expando,bk=bg.nodeType,bd=bk?a.cache:bg,bf=bk?bg[a.expando]:a.expando;if(!bd[bf]){return}if(be){var bi=bh?bd[bf][bj]:bd[bf];if(bi){delete bi[be];if(!P(bi)){return}}}if(bh){delete bd[bf][bj];if(!P(bd[bf])){return}}var e=bd[bf][bj];if(a.support.deleteExpando||bd!=aY){delete bd[bf]}else{bd[bf]=null}if(e){bd[bf]={};if(!bk){bd[bf].toJSON=a.noop}bd[bf][bj]=e}else{if(bk){if(a.support.deleteExpando){delete bg[a.expando]}else{if(bg.removeAttribute){bg.removeAttribute(a.expando)}else{bg[a.expando]=null}}}}},_data:function(bd,e,be){return a.data(bd,e,be,true)},acceptData:function(bd){if(bd.nodeName){var e=a.noData[bd.nodeName.toLowerCase()];if(e){return !(e===true||bd.getAttribute("classid")!==e)}}return true}});a.fn.extend({data:function(bg,bi){var bh=null;if(typeof bg==="undefined"){if(this.length){bh=a.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,be;for(var bf=0,bd=e.length;bf<bd;bf++){be=e[bf].name;if(be.indexOf("data-")===0){be=be.substr(5);aT(this[0],be,bh[be])}}}}return bh}else{if(typeof bg==="object"){return this.each(function(){a.data(this,bg)})}}var bj=bg.split(".");bj[1]=bj[1]?"."+bj[1]:"";if(bi===H){bh=this.triggerHandler("getData"+bj[1]+"!",[bj[0]]);if(bh===H&&this.length){bh=a.data(this[0],bg);bh=aT(this[0],bg,bh)}return bh===H&&bj[1]?this.data(bj[0]):bh}else{return this.each(function(){var bl=a(this),bk=[bj[0],bi];bl.triggerHandler("setData"+bj[1]+"!",bk);a.data(this,bg,bi);bl.triggerHandler("changeData"+bj[1]+"!",bk)})}},removeData:function(e){return this.each(function(){a.removeData(this,e)})}});function aT(be,bd,bf){if(bf===H&&be.nodeType===1){bf=be.getAttribute("data-"+bd);if(typeof bf==="string"){try{bf=bf==="true"?true:bf==="false"?false:bf==="null"?null:!a.isNaN(bf)?parseFloat(bf):aE.test(bf)?a.parseJSON(bf):bf}catch(bg){}a.data(be,bd,bf)}else{bf=H}}return bf}function P(bd){for(var e in bd){if(e!=="toJSON"){return false}}return true}a.extend({queue:function(bd,e,bf){if(!bd){return}e=(e||"fx")+"queue";var be=a._data(bd,e);if(!bf){return be||[]}if(!be||a.isArray(bf)){be=a._data(bd,e,a.makeArray(bf))}else{be.push(bf)}return be},dequeue:function(bf,be){be=be||"fx";var e=a.queue(bf,be),bd=e.shift();if(bd==="inprogress"){bd=e.shift()}if(bd){if(be==="fx"){e.unshift("inprogress")}bd.call(bf,function(){a.dequeue(bf,be)})}if(!e.length){a.removeData(bf,be+"queue",true)}}});a.fn.extend({queue:function(e,bd){if(typeof e!=="string"){bd=e;e="fx"}if(bd===H){return a.queue(this[0],e)}return this.each(function(bf){var be=a.queue(this,e,bd);if(e==="fx"&&be[0]!=="inprogress"){a.dequeue(this,e)}})},dequeue:function(e){return this.each(function(){a.dequeue(this,e)})},delay:function(bd,e){bd=a.fx?a.fx.speeds[bd]||bd:bd;e=e||"fx";return this.queue(e,function(){var be=this;setTimeout(function(){a.dequeue(be,e)},bd)})},clearQueue:function(e){return this.queue(e||"fx",[])}});var aC=/[\n\t\r]/g,a3=/\s+/,aG=/\r/g,a2=/^(?:href|src|style)$/,f=/^(?:button|input)$/i,C=/^(?:button|input|object|select|textarea)$/i,k=/^a(?:rea)?$/i,Q=/^(?:radio|checkbox)$/i;a.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};a.fn.extend({attr:function(e,bd){return a.access(this,e,bd,true,a.attr)},removeAttr:function(e,bd){return this.each(function(){a.attr(this,e,"");if(this.nodeType===1){this.removeAttribute(e)}})},addClass:function(bj){if(a.isFunction(bj)){return this.each(function(bm){var bl=a(this);bl.addClass(bj.call(this,bm,bl.attr("class")))})}if(bj&&typeof bj==="string"){var e=(bj||"").split(a3);for(var bf=0,be=this.length;bf<be;bf++){var bd=this[bf];if(bd.nodeType===1){if(!bd.className){bd.className=bj}else{var bg=" "+bd.className+" ",bi=bd.className;for(var bh=0,bk=e.length;bh<bk;bh++){if(bg.indexOf(" "+e[bh]+" ")<0){bi+=" "+e[bh]}}bd.className=a.trim(bi)}}}}return this},removeClass:function(bh){if(a.isFunction(bh)){return this.each(function(bl){var bk=a(this);bk.removeClass(bh.call(this,bl,bk.attr("class")))})}if((bh&&typeof bh==="string")||bh===H){var bi=(bh||"").split(a3);for(var be=0,bd=this.length;be<bd;be++){var bg=this[be];if(bg.nodeType===1&&bg.className){if(bh){var bf=(" "+bg.className+" ").replace(aC," ");for(var bj=0,e=bi.length;bj<e;bj++){bf=bf.replace(" "+bi[bj]+" "," ")}bg.className=a.trim(bf)}else{bg.className=""}}}}return this},toggleClass:function(bf,bd){var be=typeof bf,e=typeof bd==="boolean";if(a.isFunction(bf)){return this.each(function(bh){var bg=a(this);bg.toggleClass(bf.call(this,bh,bg.attr("class"),bd),bd)})}return this.each(function(){if(be==="string"){var bi,bh=0,bg=a(this),bj=bd,bk=bf.split(a3);while((bi=bk[bh++])){bj=e?bj:!bg.hasClass(bi);bg[bj?"addClass":"removeClass"](bi)}}else{if(be==="undefined"||be==="boolean"){if(this.className){a._data(this,"__className__",this.className)}this.className=this.className||bf===false?"":a._data(this,"__className__")||""}}})},hasClass:function(e){var bf=" "+e+" ";for(var be=0,bd=this.length;be<bd;be++){if((" "+this[be].className+" ").replace(aC," ").indexOf(bf)>-1){return true}}return false},val:function(bk){if(!arguments.length){var be=this[0];if(be){if(a.nodeName(be,"option")){var bd=be.attributes.value;return !bd||bd.specified?be.value:be.text}if(a.nodeName(be,"select")){var bi=be.selectedIndex,bl=[],bm=be.options,bh=be.type==="select-one";if(bi<0){return null}for(var bf=bh?bi:0,bj=bh?bi+1:bm.length;bf<bj;bf++){var bg=bm[bf];if(bg.selected&&(a.support.optDisabled?!bg.disabled:bg.getAttribute("disabled")===null)&&(!bg.parentNode.disabled||!a.nodeName(bg.parentNode,"optgroup"))){bk=a(bg).val();if(bh){return bk}bl.push(bk)}}if(bh&&!bl.length&&bm.length){return a(bm[bi]).val()}return bl}if(Q.test(be.type)&&!a.support.checkOn){return be.getAttribute("value")===null?"on":be.value}return(be.value||"").replace(aG,"")}return H}var e=a.isFunction(bk);return this.each(function(bp){var bo=a(this),bq=bk;if(this.nodeType!==1){return}if(e){bq=bk.call(this,bp,bo.val())}if(bq==null){bq=""}else{if(typeof bq==="number"){bq+=""}else{if(a.isArray(bq)){bq=a.map(bq,function(br){return br==null?"":br+""})}}}if(a.isArray(bq)&&Q.test(this.type)){this.checked=a.inArray(bo.val(),bq)>=0}else{if(a.nodeName(this,"select")){var bn=a.makeArray(bq);a("option",this).each(function(){this.selected=a.inArray(a(this).val(),bn)>=0});if(!bn.length){this.selectedIndex=-1}}else{this.value=bq}}})}});a.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(bd,e,bi,bl){if(!bd||bd.nodeType===3||bd.nodeType===8||bd.nodeType===2){return H}if(bl&&e in a.attrFn){return a(bd)[e](bi)}var be=bd.nodeType!==1||!a.isXMLDoc(bd),bh=bi!==H;e=be&&a.props[e]||e;if(bd.nodeType===1){var bg=a2.test(e);if(e==="selected"&&!a.support.optSelected){var bj=bd.parentNode;if(bj){bj.selectedIndex;if(bj.parentNode){bj.parentNode.selectedIndex}}}if((e in bd||bd[e]!==H)&&be&&!bg){if(bh){if(e==="type"&&f.test(bd.nodeName)&&bd.parentNode){a.error("type property can't be changed")}if(bi===null){if(bd.nodeType===1){bd.removeAttribute(e)}}else{bd[e]=bi}}if(a.nodeName(bd,"form")&&bd.getAttributeNode(e)){return bd.getAttributeNode(e).nodeValue}if(e==="tabIndex"){var bk=bd.getAttributeNode("tabIndex");return bk&&bk.specified?bk.value:C.test(bd.nodeName)||k.test(bd.nodeName)&&bd.href?0:H}return bd[e]}if(!a.support.style&&be&&e==="style"){if(bh){bd.style.cssText=""+bi}return bd.style.cssText}if(bh){bd.setAttribute(e,""+bi)}if(!bd.attributes[e]&&(bd.hasAttribute&&!bd.hasAttribute(e))){return H}var bf=!a.support.hrefNormalized&&be&&bg?bd.getAttribute(e,2):bd.getAttribute(e);return bf===null?H:bf}if(bh){bd[e]=bi}return bd[e]}});var aP=/\.(.*)$/,a0=/^(?:textarea|input|select)$/i,K=/\./g,aa=/ /g,aw=/[^\w\s.|`]/g,E=function(e){return e.replace(aw,"\\$&")};a.event={add:function(bg,bk,br,bi){if(bg.nodeType===3||bg.nodeType===8){return}try{if(a.isWindow(bg)&&(bg!==aY&&!bg.frameElement)){bg=aY}}catch(bl){}if(br===false){br=a5}else{if(!br){return}}var be,bp;if(br.handler){be=br;br=be.handler}if(!br.guid){br.guid=a.guid++}var bm=a._data(bg);if(!bm){return}var bq=bm.events,bj=bm.handle;if(!bq){bm.events=bq={}}if(!bj){bm.handle=bj=function(){return typeof a!=="undefined"&&!a.event.triggered?a.event.handle.apply(bj.elem,arguments):H}}bj.elem=bg;bk=bk.split(" ");var bo,bh=0,bd;while((bo=bk[bh++])){bp=be?a.extend({},be):{handler:br,data:bi};if(bo.indexOf(".")>-1){bd=bo.split(".");bo=bd.shift();bp.namespace=bd.slice(0).sort().join(".")}else{bd=[];bp.namespace=""}bp.type=bo;if(!bp.guid){bp.guid=br.guid}var bf=bq[bo],bn=a.event.special[bo]||{};if(!bf){bf=bq[bo]=[];if(!bn.setup||bn.setup.call(bg,bi,bd,bj)===false){if(bg.addEventListener){bg.addEventListener(bo,bj,false)}else{if(bg.attachEvent){bg.attachEvent("on"+bo,bj)}}}}if(bn.add){bn.add.call(bg,bp);if(!bp.handler.guid){bp.handler.guid=br.guid}}bf.push(bp);a.event.global[bo]=true}bg=null},global:{},remove:function(br,bm,be,bi){if(br.nodeType===3||br.nodeType===8){return}if(be===false){be=a5}var bu,bh,bj,bo,bp=0,bf,bk,bn,bg,bl,e,bt,bq=a.hasData(br)&&a._data(br),bd=bq&&bq.events;if(!bq||!bd){return}if(bm&&bm.type){be=bm.handler;bm=bm.type}if(!bm||typeof bm==="string"&&bm.charAt(0)==="."){bm=bm||"";for(bh in bd){a.event.remove(br,bh+bm)}return}bm=bm.split(" ");while((bh=bm[bp++])){bt=bh;e=null;bf=bh.indexOf(".")<0;bk=[];if(!bf){bk=bh.split(".");bh=bk.shift();bn=new RegExp("(^|\\.)"+a.map(bk.slice(0).sort(),E).join("\\.(?:.*\\.)?")+"(\\.|$)")}bl=bd[bh];if(!bl){continue}if(!be){for(bo=0;bo<bl.length;bo++){e=bl[bo];if(bf||bn.test(e.namespace)){a.event.remove(br,bt,e.handler,bo);bl.splice(bo--,1)}}continue}bg=a.event.special[bh]||{};for(bo=bi||0;bo<bl.length;bo++){e=bl[bo];if(be.guid===e.guid){if(bf||bn.test(e.namespace)){if(bi==null){bl.splice(bo--,1)}if(bg.remove){bg.remove.call(br,e)}}if(bi!=null){break}}}if(bl.length===0||bi!=null&&bl.length===1){if(!bg.teardown||bg.teardown.call(br,bk)===false){a.removeEvent(br,bh,bq.handle)}bu=null;delete bd[bh]}}if(a.isEmptyObject(bd)){var bs=bq.handle;if(bs){bs.elem=null}delete bq.events;delete bq.handle;if(a.isEmptyObject(bq)){a.removeData(br,H,true)}}},trigger:function(bd,bi,bf){var bm=bd.type||bd,bh=arguments[3];if(!bh){bd=typeof bd==="object"?bd[a.expando]?bd:a.extend(a.Event(bm),bd):a.Event(bm);if(bm.indexOf("!")>=0){bd.type=bm=bm.slice(0,-1);bd.exclusive=true}if(!bf){bd.stopPropagation();if(a.event.global[bm]){a.each(a.cache,function(){var br=a.expando,bq=this[br];if(bq&&bq.events&&bq.events[bm]){a.event.trigger(bd,bi,bq.handle.elem)}})}}if(!bf||bf.nodeType===3||bf.nodeType===8){return H}bd.result=H;bd.target=bf;bi=a.makeArray(bi);bi.unshift(bd)}bd.currentTarget=bf;var bj=a._data(bf,"handle");if(bj){bj.apply(bf,bi)}var bo=bf.parentNode||bf.ownerDocument;try{if(!(bf&&bf.nodeName&&a.noData[bf.nodeName.toLowerCase()])){if(bf["on"+bm]&&bf["on"+bm].apply(bf,bi)===false){bd.result=false;bd.preventDefault()}}}catch(bn){}if(!bd.isPropagationStopped()&&bo){a.event.trigger(bd,bi,bo,true)}else{if(!bd.isDefaultPrevented()){var be,bk=bd.target,e=bm.replace(aP,""),bp=a.nodeName(bk,"a")&&e==="click",bl=a.event.special[e]||{};if((!bl._default||bl._default.call(bf,bd)===false)&&!bp&&!(bk&&bk.nodeName&&a.noData[bk.nodeName.toLowerCase()])){try{if(bk[e]){be=bk["on"+e];if(be){bk["on"+e]=null}a.event.triggered=true;bk[e]()}}catch(bg){}if(be){bk["on"+e]=be}a.event.triggered=false}}}},handle:function(e){var bl,be,bd,bn,bm,bh=[],bj=a.makeArray(arguments);e=bj[0]=a.event.fix(e||aY.event);e.currentTarget=this;bl=e.type.indexOf(".")<0&&!e.exclusive;if(!bl){bd=e.type.split(".");e.type=bd.shift();bh=bd.slice(0).sort();bn=new RegExp("(^|\\.)"+bh.join("\\.(?:.*\\.)?")+"(\\.|$)")}e.namespace=e.namespace||bh.join(".");bm=a._data(this,"events");be=(bm||{})[e.type];if(bm&&be){be=be.slice(0);for(var bg=0,bf=be.length;bg<bf;bg++){var bk=be[bg];if(bl||bn.test(bk.namespace)){e.handler=bk.handler;e.data=bk.data;e.handleObj=bk;var bi=bk.handler.apply(this,bj);if(bi!==H){e.result=bi;if(bi===false){e.preventDefault();e.stopPropagation()}}if(e.isImmediatePropagationStopped()){break}}}}return e.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(bf){if(bf[a.expando]){return bf}var bd=bf;bf=a.Event(bd);for(var be=this.props.length,bh;be;){bh=this.props[--be];bf[bh]=bd[bh]}if(!bf.target){bf.target=bf.srcElement||al}if(bf.target.nodeType===3){bf.target=bf.target.parentNode}if(!bf.relatedTarget&&bf.fromElement){bf.relatedTarget=bf.fromElement===bf.target?bf.toElement:bf.fromElement}if(bf.pageX==null&&bf.clientX!=null){var bg=al.documentElement,e=al.body;bf.pageX=bf.clientX+(bg&&bg.scrollLeft||e&&e.scrollLeft||0)-(bg&&bg.clientLeft||e&&e.clientLeft||0);bf.pageY=bf.clientY+(bg&&bg.scrollTop||e&&e.scrollTop||0)-(bg&&bg.clientTop||e&&e.clientTop||0)}if(bf.which==null&&(bf.charCode!=null||bf.keyCode!=null)){bf.which=bf.charCode!=null?bf.charCode:bf.keyCode}if(!bf.metaKey&&bf.ctrlKey){bf.metaKey=bf.ctrlKey}if(!bf.which&&bf.button!==H){bf.which=(bf.button&1?1:(bf.button&2?3:(bf.button&4?2:0)))}return bf},guid:100000000,proxy:a.proxy,special:{ready:{setup:a.bindReady,teardown:a.noop},live:{add:function(e){a.event.add(this,n(e.origType,e.selector),a.extend({},e,{handler:af,guid:e.handler.guid}))},remove:function(e){a.event.remove(this,n(e.origType,e.selector),e)}},beforeunload:{setup:function(be,bd,e){if(a.isWindow(this)){this.onbeforeunload=e}},teardown:function(bd,e){if(this.onbeforeunload===e){this.onbeforeunload=null}}}}};a.removeEvent=al.removeEventListener?function(bd,e,be){if(bd.removeEventListener){bd.removeEventListener(e,be,false)}}:function(bd,e,be){if(bd.detachEvent){bd.detachEvent("on"+e,be)}};a.Event=function(e){if(!this.preventDefault){return new a.Event(e)}if(e&&e.type){this.originalEvent=e;this.type=e.type;this.isDefaultPrevented=(e.defaultPrevented||e.returnValue===false||e.getPreventDefault&&e.getPreventDefault())?h:a5}else{this.type=e}this.timeStamp=a.now();this[a.expando]=true};function a5(){return false}function h(){return true}a.Event.prototype={preventDefault:function(){this.isDefaultPrevented=h;var bd=this.originalEvent;if(!bd){return}if(bd.preventDefault){bd.preventDefault()}else{bd.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=h;var bd=this.originalEvent;if(!bd){return}if(bd.stopPropagation){bd.stopPropagation()}bd.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=h;this.stopPropagation()},isDefaultPrevented:a5,isPropagationStopped:a5,isImmediatePropagationStopped:a5};var Z=function(be){var bd=be.relatedTarget;try{if(bd!==al&&!bd.parentNode){return}while(bd&&bd!==this){bd=bd.parentNode}if(bd!==this){be.type=be.data;a.event.handle.apply(this,arguments)}}catch(bf){}},aK=function(e){e.type=e.data;a.event.handle.apply(this,arguments)};a.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(bd,e){a.event.special[bd]={setup:function(be){a.event.add(this,e,be&&be.selector?aK:Z,bd)},teardown:function(be){a.event.remove(this,e,be&&be.selector?aK:Z)}}});if(!a.support.submitBubbles){a.event.special.submit={setup:function(bd,e){if(this.nodeName&&this.nodeName.toLowerCase()!=="form"){a.event.add(this,"click.specialSubmit",function(bg){var bf=bg.target,be=bf.type;if((be==="submit"||be==="image")&&a(bf).closest("form").length){aN("submit",this,arguments)}});a.event.add(this,"keypress.specialSubmit",function(bg){var bf=bg.target,be=bf.type;if((be==="text"||be==="password")&&a(bf).closest("form").length&&bg.keyCode===13){aN("submit",this,arguments)}})}else{return false}},teardown:function(e){a.event.remove(this,".specialSubmit")}}}if(!a.support.changeBubbles){var a6,j=function(bd){var e=bd.type,be=bd.value;if(e==="radio"||e==="checkbox"){be=bd.checked}else{if(e==="select-multiple"){be=bd.selectedIndex>-1?a.map(bd.options,function(bf){return bf.selected}).join("-"):""}else{if(bd.nodeName.toLowerCase()==="select"){be=bd.selectedIndex}}}return be},X=function X(bf){var bd=bf.target,be,bg;if(!a0.test(bd.nodeName)||bd.readOnly){return}be=a._data(bd,"_change_data");bg=j(bd);if(bf.type!=="focusout"||bd.type!=="radio"){a._data(bd,"_change_data",bg)}if(be===H||bg===be){return}if(be!=null||bg){bf.type="change";bf.liveFired=H;a.event.trigger(bf,arguments[1],bd)}};a.event.special.change={filters:{focusout:X,beforedeactivate:X,click:function(bf){var be=bf.target,bd=be.type;if(bd==="radio"||bd==="checkbox"||be.nodeName.toLowerCase()==="select"){X.call(this,bf)}},keydown:function(bf){var be=bf.target,bd=be.type;if((bf.keyCode===13&&be.nodeName.toLowerCase()!=="textarea")||(bf.keyCode===32&&(bd==="checkbox"||bd==="radio"))||bd==="select-multiple"){X.call(this,bf)}},beforeactivate:function(be){var bd=be.target;a._data(bd,"_change_data",j(bd))}},setup:function(be,bd){if(this.type==="file"){return false}for(var e in a6){a.event.add(this,e+".specialChange",a6[e])}return a0.test(this.nodeName)},teardown:function(e){a.event.remove(this,".specialChange");return a0.test(this.nodeName)}};a6=a.event.special.change.filters;a6.focus=a6.beforeactivate}function aN(bd,bf,e){var be=a.extend({},e[0]);be.type=bd;be.originalEvent={};be.liveFired=H;a.event.handle.call(bf,be);if(be.isDefaultPrevented()){e[0].preventDefault()}}if(al.addEventListener){a.each({focus:"focusin",blur:"focusout"},function(be,e){a.event.special[e]={setup:function(){this.addEventListener(be,bd,true)},teardown:function(){this.removeEventListener(be,bd,true)}};function bd(bf){bf=a.event.fix(bf);bf.type=e;return a.event.handle.call(this,bf)}})}a.each(["bind","one"],function(bd,e){a.fn[e]=function(bj,bk,bi){if(typeof bj==="object"){for(var bg in bj){this[e](bg,bk,bj[bg],bi)}return this}if(a.isFunction(bk)||bk===false){bi=bk;bk=H}var bh=e==="one"?a.proxy(bi,function(bl){a(this).unbind(bl,bh);return bi.apply(this,arguments)}):bi;if(bj==="unload"&&e!=="one"){this.one(bj,bk,bi)}else{for(var bf=0,be=this.length;bf<be;bf++){a.event.add(this[bf],bj,bh,bk)}}return this}});a.fn.extend({unbind:function(bg,bf){if(typeof bg==="object"&&!bg.preventDefault){for(var be in bg){this.unbind(be,bg[be])}}else{for(var bd=0,e=this.length;bd<e;bd++){a.event.remove(this[bd],bg,bf)}}return this},delegate:function(e,bd,bf,be){return this.live(bd,bf,be,e)},undelegate:function(e,bd,be){if(arguments.length===0){return this.unbind("live")}else{return this.die(bd,null,be,e)}},trigger:function(e,bd){return this.each(function(){a.event.trigger(e,bd,this)})},triggerHandler:function(e,be){if(this[0]){var bd=a.Event(e);bd.preventDefault();bd.stopPropagation();a.event.trigger(bd,be,this[0]);return bd.result}},toggle:function(be){var e=arguments,bd=1;while(bd<e.length){a.proxy(be,e[bd++])}return this.click(a.proxy(be,function(bf){var bg=(a._data(this,"lastToggle"+be.guid)||0)%bd;a._data(this,"lastToggle"+be.guid,bg+1);bf.preventDefault();return e[bg].apply(this,arguments)||false}))},hover:function(e,bd){return this.mouseenter(e).mouseleave(bd||e)}});var aH={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};a.each(["live","die"],function(bd,e){a.fn[e]=function(bn,bk,bp,bg){var bo,bl=0,bm,bf,br,bi=bg||this.selector,be=bg?this:a(this.context);if(typeof bn==="object"&&!bn.preventDefault){for(var bq in bn){be[e](bq,bk,bn[bq],bi)}return this}if(a.isFunction(bk)){bp=bk;bk=H}bn=(bn||"").split(" ");while((bo=bn[bl++])!=null){bm=aP.exec(bo);bf="";if(bm){bf=bm[0];bo=bo.replace(aP,"")}if(bo==="hover"){bn.push("mouseenter"+bf,"mouseleave"+bf);continue}br=bo;if(bo==="focus"||bo==="blur"){bn.push(aH[bo]+bf);bo=bo+bf}else{bo=(aH[bo]||bo)+bf}if(e==="live"){for(var bj=0,bh=be.length;bj<bh;bj++){a.event.add(be[bj],"live."+n(bo,bi),{data:bk,selector:bi,handler:bp,origType:bo,origHandler:bp,preType:br})}}else{be.unbind("live."+n(bo,bi),bp)}}return this}});function af(bn){var bk,bf,bt,bh,e,bp,bm,bo,bl,bs,bj,bi,br,bq=[],bg=[],bd=a._data(this,"events");if(bn.liveFired===this||!bd||!bd.live||bn.target.disabled||bn.button&&bn.type==="click"){return}if(bn.namespace){bi=new RegExp("(^|\\.)"+bn.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")}bn.liveFired=this;var be=bd.live.slice(0);for(bm=0;bm<be.length;bm++){e=be[bm];if(e.origType.replace(aP,"")===bn.type){bg.push(e.selector)}else{be.splice(bm--,1)}}bh=a(bn.target).closest(bg,bn.currentTarget);for(bo=0,bl=bh.length;bo<bl;bo++){bj=bh[bo];for(bm=0;bm<be.length;bm++){e=be[bm];if(bj.selector===e.selector&&(!bi||bi.test(e.namespace))&&!bj.elem.disabled){bp=bj.elem;bt=null;if(e.preType==="mouseenter"||e.preType==="mouseleave"){bn.type=e.preType;bt=a(bn.relatedTarget).closest(e.selector)[0]}if(!bt||bt!==bp){bq.push({elem:bp,handleObj:e,level:bj.level})}}}}for(bo=0,bl=bq.length;bo<bl;bo++){bh=bq[bo];if(bf&&bh.level>bf){break}bn.currentTarget=bh.elem;bn.data=bh.handleObj.data;bn.handleObj=bh.handleObj;br=bh.handleObj.origHandler.apply(bh.elem,arguments);if(br===false||bn.isPropagationStopped()){bf=bh.level;if(br===false){bk=false}if(bn.isImmediatePropagationStopped()){break}}}return bk}function n(bd,e){return(bd&&bd!=="*"?bd+".":"")+e.replace(K,"`").replace(aa,"&")}a.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").split(" "),function(bd,e){a.fn[e]=function(bf,be){if(be==null){be=bf;bf=null}return arguments.length>0?this.bind(e,bf,be):this.trigger(e)};if(a.attrFn){a.attrFn[e]=true}});
-/*
- * Sizzle CSS Selector Engine
- *  Copyright 2011, The Dojo Foundation
- *  Released under the MIT, BSD, and GPL Licenses.
- *  More information: http://sizzlejs.com/
- */
-(function(){var bn=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,bo=0,br=Object.prototype.toString,bi=false,bh=true,bp=/\\/g,bv=/\W/;[0,0].sort(function(){bh=false;return 0});var bf=function(bA,e,bD,bE){bD=bD||[];e=e||al;var bG=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!bA||typeof bA!=="string"){return bD}var bx,bI,bL,bw,bH,bK,bJ,bC,bz=true,by=bf.isXML(e),bB=[],bF=bA;do{bn.exec("");bx=bn.exec(bF);if(bx){bF=bx[3];bB.push(bx[1]);if(bx[2]){bw=bx[3];break}}}while(bx);if(bB.length>1&&bj.exec(bA)){if(bB.length===2&&bk.relative[bB[0]]){bI=bs(bB[0]+bB[1],e)}else{bI=bk.relative[bB[0]]?[e]:bf(bB.shift(),e);while(bB.length){bA=bB.shift();if(bk.relative[bA]){bA+=bB.shift()}bI=bs(bA,bI)}}}else{if(!bE&&bB.length>1&&e.nodeType===9&&!by&&bk.match.ID.test(bB[0])&&!bk.match.ID.test(bB[bB.length-1])){bH=bf.find(bB.shift(),e,by);e=bH.expr?bf.filter(bH.expr,bH.set)[0]:bH.set[0]}if(e){bH=bE?{expr:bB.pop(),set:bl(bE)}:bf.find(bB.pop(),bB.length===1&&(bB[0]==="~"||bB[0]==="+")&&e.parentNode?e.parentNode:e,by);bI=bH.expr?bf.filter(bH.expr,bH.set):bH.set;if(bB.length>0){bL=bl(bI)}else{bz=false}while(bB.length){bK=bB.pop();bJ=bK;if(!bk.relative[bK]){bK=""}else{bJ=bB.pop()}if(bJ==null){bJ=e}bk.relative[bK](bL,bJ,by)}}else{bL=bB=[]}}if(!bL){bL=bI}if(!bL){bf.error(bK||bA)}if(br.call(bL)==="[object Array]"){if(!bz){bD.push.apply(bD,bL)}else{if(e&&e.nodeType===1){for(bC=0;bL[bC]!=null;bC++){if(bL[bC]&&(bL[bC]===true||bL[bC].nodeType===1&&bf.contains(e,bL[bC]))){bD.push(bI[bC])}}}else{for(bC=0;bL[bC]!=null;bC++){if(bL[bC]&&bL[bC].nodeType===1){bD.push(bI[bC])}}}}}else{bl(bL,bD)}if(bw){bf(bw,bG,bD,bE);bf.uniqueSort(bD)}return bD};bf.uniqueSort=function(bw){if(bq){bi=bh;bw.sort(bq);if(bi){for(var e=1;e<bw.length;e++){if(bw[e]===bw[e-1]){bw.splice(e--,1)}}}}return bw};bf.matches=function(e,bw){return bf(e,null,null,bw)};bf.matchesSelector=function(e,bw){return bf(bw,null,null,[e]).length>0};bf.find=function(bC,e,bD){var bB;if(!bC){return[]}for(var by=0,bx=bk.order.length;by<bx;by++){var bz,bA=bk.order[by];if((bz=bk.leftMatch[bA].exec(bC))){var bw=bz[1];bz.splice(1,1);if(bw.substr(bw.length-1)!=="\\"){bz[1]=(bz[1]||"").replace(bp,"");bB=bk.find[bA](bz,e,bD);if(bB!=null){bC=bC.replace(bk.match[bA],"");break}}}}if(!bB){bB=typeof e.getElementsByTagName!=="undefined"?e.getElementsByTagName("*"):[]}return{set:bB,expr:bC}};bf.filter=function(bG,bF,bJ,bz){var bB,e,bx=bG,bL=[],bD=bF,bC=bF&&bF[0]&&bf.isXML(bF[0]);while(bG&&bF.length){for(var bE in bk.filter){if((bB=bk.leftMatch[bE].exec(bG))!=null&&bB[2]){var bK,bI,bw=bk.filter[bE],by=bB[1];e=false;bB.splice(1,1);if(by.substr(by.length-1)==="\\"){continue}if(bD===bL){bL=[]}if(bk.preFilter[bE]){bB=bk.preFilter[bE](bB,bD,bJ,bL,bz,bC);if(!bB){e=bK=true}else{if(bB===true){continue}}}if(bB){for(var bA=0;(bI=bD[bA])!=null;bA++){if(bI){bK=bw(bI,bB,bA,bD);var bH=bz^!!bK;if(bJ&&bK!=null){if(bH){e=true}else{bD[bA]=false}}else{if(bH){bL.push(bI);e=true}}}}}if(bK!==H){if(!bJ){bD=bL}bG=bG.replace(bk.match[bE],"");if(!e){return[]}break}}}if(bG===bx){if(e==null){bf.error(bG)}else{break}}bx=bG}return bD};bf.error=function(e){throw"Syntax error, unrecognized expression: "+e};var bk=bf.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(e){return e.getAttribute("href")},type:function(e){return e.getAttribute("type")}},relative:{"+":function(bB,bw){var by=typeof bw==="string",bA=by&&!bv.test(bw),bC=by&&!bA;if(bA){bw=bw.toLowerCase()}for(var bx=0,e=bB.length,bz;bx<e;bx++){if((bz=bB[bx])){while((bz=bz.previousSibling)&&bz.nodeType!==1){}bB[bx]=bC||bz&&bz.nodeName.toLowerCase()===bw?bz||false:bz===bw}}if(bC){bf.filter(bw,bB,true)}},">":function(bB,bw){var bA,bz=typeof bw==="string",bx=0,e=bB.length;if(bz&&!bv.test(bw)){bw=bw.toLowerCase();for(;bx<e;bx++){bA=bB[bx];if(bA){var by=bA.parentNode;bB[bx]=by.nodeName.toLowerCase()===bw?by:false}}}else{for(;bx<e;bx++){bA=bB[bx];if(bA){bB[bx]=bz?bA.parentNode:bA.parentNode===bw}}if(bz){bf.filter(bw,bB,true)}}},"":function(by,bw,bA){var bz,bx=bo++,e=bt;if(typeof bw==="string"&&!bv.test(bw)){bw=bw.toLowerCase();bz=bw;e=bd}e("parentNode",bw,bx,by,bz,bA)},"~":function(by,bw,bA){var bz,bx=bo++,e=bt;if(typeof bw==="string"&&!bv.test(bw)){bw=bw.toLowerCase();bz=bw;e=bd}e("previousSibling",bw,bx,by,bz,bA)}},find:{ID:function(bw,bx,by){if(typeof bx.getElementById!=="undefined"&&!by){var e=bx.getElementById(bw[1]);return e&&e.parentNode?[e]:[]}},NAME:function(bx,bA){if(typeof bA.getElementsByName!=="undefined"){var bw=[],bz=bA.getElementsByName(bx[1]);for(var by=0,e=bz.length;by<e;by++){if(bz[by].getAttribute("name")===bx[1]){bw.push(bz[by])}}return bw.length===0?null:bw}},TAG:function(e,bw){if(typeof bw.getElementsByTagName!=="undefined"){return bw.getElementsByTagName(e[1])}}},preFilter:{CLASS:function(by,bw,bx,e,bB,bC){by=" "+by[1].replace(bp,"")+" ";if(bC){return by}for(var bz=0,bA;(bA=bw[bz])!=null;bz++){if(bA){if(bB^(bA.className&&(" "+bA.className+" ").replace(/[\t\n\r]/g," ").indexOf(by)>=0)){if(!bx){e.push(bA)}}else{if(bx){bw[bz]=false}}}}return false},ID:function(e){return e[1].replace(bp,"")},TAG:function(bw,e){return bw[1].replace(bp,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){bf.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var bw=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(bw[1]+(bw[2]||1))-0;e[3]=bw[3]-0}else{if(e[2]){bf.error(e[0])}}e[0]=bo++;return e},ATTR:function(bz,bw,bx,e,bA,bB){var by=bz[1]=bz[1].replace(bp,"");if(!bB&&bk.attrMap[by]){bz[1]=bk.attrMap[by]}bz[4]=(bz[4]||bz[5]||"").replace(bp,"");if(bz[2]==="~="){bz[4]=" "+bz[4]+" "}return bz},PSEUDO:function(bz,bw,bx,e,bA){if(bz[1]==="not"){if((bn.exec(bz[3])||"").length>1||/^\w/.test(bz[3])){bz[3]=bf(bz[3],null,null,bw)}else{var by=bf.filter(bz[3],bw,bx,true^bA);if(!bx){e.push.apply(e,by)}return false}}else{if(bk.match.POS.test(bz[0])||bk.match.CHILD.test(bz[0])){return true}}return bz},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(bx,bw,e){return !!bf(e[3],bx).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(e){return"text"===e.getAttribute("type")},radio:function(e){return"radio"===e.type},checkbox:function(e){return"checkbox"===e.type},file:function(e){return"file"===e.type},password:function(e){return"password"===e.type},submit:function(e){return"submit"===e.type},image:function(e){return"image"===e.type},reset:function(e){return"reset"===e.type},button:function(e){return"button"===e.type||e.nodeName.toLowerCase()==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)}},setFilters:{first:function(bw,e){return e===0},last:function(bx,bw,e,by){return bw===by.length-1},even:function(bw,e){return e%2===0},odd:function(bw,e){return e%2===1},lt:function(bx,bw,e){return bw<e[3]-0},gt:function(bx,bw,e){return bw>e[3]-0},nth:function(bx,bw,e){return e[3]-0===bw},eq:function(bx,bw,e){return e[3]-0===bw}},filter:{PSEUDO:function(bx,bC,bB,bD){var e=bC[1],bw=bk.filters[e];if(bw){return bw(bx,bB,bC,bD)}else{if(e==="contains"){return(bx.textContent||bx.innerText||bf.getText([bx])||"").indexOf(bC[3])>=0}else{if(e==="not"){var by=bC[3];for(var bA=0,bz=by.length;bA<bz;bA++){if(by[bA]===bx){return false}}return true}else{bf.error(e)}}}},CHILD:function(e,by){var bB=by[1],bw=e;switch(bB){case"only":case"first":while((bw=bw.previousSibling)){if(bw.nodeType===1){return false}}if(bB==="first"){return true}bw=e;case"last":while((bw=bw.nextSibling)){if(bw.nodeType===1){return false}}return true;case"nth":var bx=by[2],bE=by[3];if(bx===1&&bE===0){return true}var bA=by[0],bD=e.parentNode;if(bD&&(bD.sizcache!==bA||!e.nodeIndex)){var bz=0;for(bw=bD.firstChild;bw;bw=bw.nextSibling){if(bw.nodeType===1){bw.nodeIndex=++bz}}bD.sizcache=bA}var bC=e.nodeIndex-bE;if(bx===0){return bC===0}else{return(bC%bx===0&&bC/bx>=0)}}},ID:function(bw,e){return bw.nodeType===1&&bw.getAttribute("id")===e},TAG:function(bw,e){return(e==="*"&&bw.nodeType===1)||bw.nodeName.toLowerCase()===e},CLASS:function(bw,e){return(" "+(bw.className||bw.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(bA,by){var bx=by[1],e=bk.attrHandle[bx]?bk.attrHandle[bx](bA):bA[bx]!=null?bA[bx]:bA.getAttribute(bx),bB=e+"",bz=by[2],bw=by[4];return e==null?bz==="!=":bz==="="?bB===bw:bz==="*="?bB.indexOf(bw)>=0:bz==="~="?(" "+bB+" ").indexOf(bw)>=0:!bw?bB&&e!==false:bz==="!="?bB!==bw:bz==="^="?bB.indexOf(bw)===0:bz==="$="?bB.substr(bB.length-bw.length)===bw:bz==="|="?bB===bw||bB.substr(0,bw.length+1)===bw+"-":false},POS:function(bz,bw,bx,bA){var e=bw[2],by=bk.setFilters[e];if(by){return by(bz,bx,bw,bA)}}}};var bj=bk.match.POS,be=function(bw,e){return"\\"+(e-0+1)};for(var bg in bk.match){bk.match[bg]=new RegExp(bk.match[bg].source+(/(?![^\[]*\])(?![^\(]*\))/.source));bk.leftMatch[bg]=new RegExp(/(^(?:.|\r|\n)*?)/.source+bk.match[bg].source.replace(/\\(\d+)/g,be))}var bl=function(bw,e){bw=Array.prototype.slice.call(bw,0);if(e){e.push.apply(e,bw);return e}return bw};try{Array.prototype.slice.call(al.documentElement.childNodes,0)[0].nodeType}catch(bu){bl=function(bz,by){var bx=0,bw=by||[];if(br.call(bz)==="[object Array]"){Array.prototype.push.apply(bw,bz)}else{if(typeof bz.length==="number"){for(var e=bz.length;bx<e;bx++){bw.push(bz[bx])}}else{for(;bz[bx];bx++){bw.push(bz[bx])}}}return bw}}var bq,bm;if(al.documentElement.compareDocumentPosition){bq=function(bw,e){if(bw===e){bi=true;return 0}if(!bw.compareDocumentPosition||!e.compareDocumentPosition){return bw.compareDocumentPosition?-1:1}return bw.compareDocumentPosition(e)&4?-1:1}}else{bq=function(bD,bC){var bA,bw,bx=[],e=[],bz=bD.parentNode,bB=bC.parentNode,bE=bz;if(bD===bC){bi=true;return 0}else{if(bz===bB){return bm(bD,bC)}else{if(!bz){return -1}else{if(!bB){return 1}}}}while(bE){bx.unshift(bE);bE=bE.parentNode}bE=bB;while(bE){e.unshift(bE);bE=bE.parentNode}bA=bx.length;bw=e.length;for(var by=0;by<bA&&by<bw;by++){if(bx[by]!==e[by]){return bm(bx[by],e[by])}}return by===bA?bm(bD,e[by],-1):bm(bx[by],bC,1)};bm=function(bw,e,bx){if(bw===e){return bx}var by=bw.nextSibling;while(by){if(by===e){return -1}by=by.nextSibling}return 1}}bf.getText=function(e){var bw="",by;for(var bx=0;e[bx];bx++){by=e[bx];if(by.nodeType===3||by.nodeType===4){bw+=by.nodeValue}else{if(by.nodeType!==8){bw+=bf.getText(by.childNodes)}}}return bw};(function(){var bw=al.createElement("div"),bx="script"+(new Date()).getTime(),e=al.documentElement;bw.innerHTML="<a name='"+bx+"'/>";e.insertBefore(bw,e.firstChild);if(al.getElementById(bx)){bk.find.ID=function(bz,bA,bB){if(typeof bA.getElementById!=="undefined"&&!bB){var by=bA.getElementById(bz[1]);return by?by.id===bz[1]||typeof by.getAttributeNode!=="undefined"&&by.getAttributeNode("id").nodeValue===bz[1]?[by]:H:[]}};bk.filter.ID=function(bA,by){var bz=typeof bA.getAttributeNode!=="undefined"&&bA.getAttributeNode("id");return bA.nodeType===1&&bz&&bz.nodeValue===by}}e.removeChild(bw);e=bw=null})();(function(){var e=al.createElement("div");e.appendChild(al.createComment(""));if(e.getElementsByTagName("*").length>0){bk.find.TAG=function(bw,bA){var bz=bA.getElementsByTagName(bw[1]);if(bw[1]==="*"){var by=[];for(var bx=0;bz[bx];bx++){if(bz[bx].nodeType===1){by.push(bz[bx])}}bz=by}return bz}}e.innerHTML="<a href='#'></a>";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){bk.attrHandle.href=function(bw){return bw.getAttribute("href",2)}}e=null})();if(al.querySelectorAll){(function(){var e=bf,by=al.createElement("div"),bx="__sizzle__";by.innerHTML="<p class='TEST'></p>";if(by.querySelectorAll&&by.querySelectorAll(".TEST").length===0){return}bf=function(bJ,bA,bE,bI){bA=bA||al;if(!bI&&!bf.isXML(bA)){var bH=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(bJ);if(bH&&(bA.nodeType===1||bA.nodeType===9)){if(bH[1]){return bl(bA.getElementsByTagName(bJ),bE)}else{if(bH[2]&&bk.find.CLASS&&bA.getElementsByClassName){return bl(bA.getElementsByClassName(bH[2]),bE)}}}if(bA.nodeType===9){if(bJ==="body"&&bA.body){return bl([bA.body],bE)}else{if(bH&&bH[3]){var bD=bA.getElementById(bH[3]);if(bD&&bD.parentNode){if(bD.id===bH[3]){return bl([bD],bE)}}else{return bl([],bE)}}}try{return bl(bA.querySelectorAll(bJ),bE)}catch(bF){}}else{if(bA.nodeType===1&&bA.nodeName.toLowerCase()!=="object"){var bB=bA,bC=bA.getAttribute("id"),bz=bC||bx,bL=bA.parentNode,bK=/^\s*[+~]/.test(bJ);if(!bC){bA.setAttribute("id",bz)}else{bz=bz.replace(/'/g,"\\$&")}if(bK&&bL){bA=bA.parentNode}try{if(!bK||bL){return bl(bA.querySelectorAll("[id='"+bz+"'] "+bJ),bE)}}catch(bG){}finally{if(!bC){bB.removeAttribute("id")}}}}}return e(bJ,bA,bE,bI)};for(var bw in e){bf[bw]=e[bw]}by=null})()}(function(){var e=al.documentElement,bx=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector,bw=false;try{bx.call(al.documentElement,"[test!='']:sizzle")}catch(by){bw=true}if(bx){bf.matchesSelector=function(bz,bB){bB=bB.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!bf.isXML(bz)){try{if(bw||!bk.match.PSEUDO.test(bB)&&!/!=/.test(bB)){return bx.call(bz,bB)}}catch(bA){}}return bf(bB,null,null,[bz]).length>0}}})();(function(){var e=al.createElement("div");e.innerHTML="<div class='test e'></div><div class='test'></div>";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}bk.order.splice(1,0,"CLASS");bk.find.CLASS=function(bw,bx,by){if(typeof bx.getElementsByClassName!=="undefined"&&!by){return bx.getElementsByClassName(bw[1])}};e=null})();function bd(bw,bB,bA,bE,bC,bD){for(var by=0,bx=bE.length;by<bx;by++){var e=bE[by];if(e){var bz=false;e=e[bw];while(e){if(e.sizcache===bA){bz=bE[e.sizset];break}if(e.nodeType===1&&!bD){e.sizcache=bA;e.sizset=by}if(e.nodeName.toLowerCase()===bB){bz=e;break}e=e[bw]}bE[by]=bz}}}function bt(bw,bB,bA,bE,bC,bD){for(var by=0,bx=bE.length;by<bx;by++){var e=bE[by];if(e){var bz=false;e=e[bw];while(e){if(e.sizcache===bA){bz=bE[e.sizset];break}if(e.nodeType===1){if(!bD){e.sizcache=bA;e.sizset=by}if(typeof bB!=="string"){if(e===bB){bz=true;break}}else{if(bf.filter(bB,[e]).length>0){bz=e;break}}}e=e[bw]}bE[by]=bz}}}if(al.documentElement.contains){bf.contains=function(bw,e){return bw!==e&&(bw.contains?bw.contains(e):true)}}else{if(al.documentElement.compareDocumentPosition){bf.contains=function(bw,e){return !!(bw.compareDocumentPosition(e)&16)}}else{bf.contains=function(){return false}}}bf.isXML=function(e){var bw=(e?e.ownerDocument||e:0).documentElement;return bw?bw.nodeName!=="HTML":false};var bs=function(e,bC){var bA,by=[],bz="",bx=bC.nodeType?[bC]:bC;while((bA=bk.match.PSEUDO.exec(e))){bz+=bA[0];e=e.replace(bk.match.PSEUDO,"")}e=bk.relative[e]?e+"*":e;for(var bB=0,bw=bx.length;bB<bw;bB++){bf(e,bx[bB],by)}return bf.filter(bz,by)};a.find=bf;a.expr=bf.selectors;a.expr[":"]=a.expr.filters;a.unique=bf.uniqueSort;a.text=bf.getText;a.isXMLDoc=bf.isXML;a.contains=bf.contains})();var W=/Until$/,ai=/^(?:parents|prevUntil|prevAll)/,aW=/,/,a9=/^.[^:#\[\.,]*$/,M=Array.prototype.slice,F=a.expr.match.POS,ao={children:true,contents:true,next:true,prev:true};a.fn.extend({find:function(e){var be=this.pushStack("","find",e),bh=0;for(var bf=0,bd=this.length;bf<bd;bf++){bh=be.length;a.find(e,this[bf],be);if(bf>0){for(var bi=bh;bi<be.length;bi++){for(var bg=0;bg<bh;bg++){if(be[bg]===be[bi]){be.splice(bi--,1);break}}}}}return be},has:function(bd){var e=a(bd);return this.filter(function(){for(var bf=0,be=e.length;bf<be;bf++){if(a.contains(this,e[bf])){return true}}})},not:function(e){return this.pushStack(av(this,e,false),"not",e)},filter:function(e){return this.pushStack(av(this,e,true),"filter",e)},is:function(e){return !!e&&a.filter(e,this).length>0},closest:function(bm,bd){var bj=[],bg,be,bl=this[0];if(a.isArray(bm)){var bi,bf,bh={},e=1;if(bl&&bm.length){for(bg=0,be=bm.length;bg<be;bg++){bf=bm[bg];if(!bh[bf]){bh[bf]=a.expr.match.POS.test(bf)?a(bf,bd||this.context):bf}}while(bl&&bl.ownerDocument&&bl!==bd){for(bf in bh){bi=bh[bf];if(bi.jquery?bi.index(bl)>-1:a(bl).is(bi)){bj.push({selector:bf,elem:bl,level:e})}}bl=bl.parentNode;e++}}return bj}var bk=F.test(bm)?a(bm,bd||this.context):null;for(bg=0,be=this.length;bg<be;bg++){bl=this[bg];while(bl){if(bk?bk.index(bl)>-1:a.find.matchesSelector(bl,bm)){bj.push(bl);break}else{bl=bl.parentNode;if(!bl||!bl.ownerDocument||bl===bd){break}}}}bj=bj.length>1?a.unique(bj):bj;return this.pushStack(bj,"closest",bm)},index:function(e){if(!e||typeof e==="string"){return a.inArray(this[0],e?a(e):this.parent().children())}return a.inArray(e.jquery?e[0]:e,this)},add:function(e,bd){var bf=typeof e==="string"?a(e,bd):a.makeArray(e),be=a.merge(this.get(),bf);return this.pushStack(B(bf[0])||B(be[0])?be:a.unique(be))},andSelf:function(){return this.add(this.prevObject)}});function B(e){return !e||!e.parentNode||e.parentNode.nodeType===11}a.each({parent:function(bd){var e=bd.parentNode;return e&&e.nodeType!==11?e:null},parents:function(e){return a.dir(e,"parentNode")},parentsUntil:function(bd,e,be){return a.dir(bd,"parentNode",be)},next:function(e){return a.nth(e,2,"nextSibling")},prev:function(e){return a.nth(e,2,"previousSibling")},nextAll:function(e){return a.dir(e,"nextSibling")},prevAll:function(e){return a.dir(e,"previousSibling")},nextUntil:function(bd,e,be){return a.dir(bd,"nextSibling",be)},prevUntil:function(bd,e,be){return a.dir(bd,"previousSibling",be)},siblings:function(e){return a.sibling(e.parentNode.firstChild,e)},children:function(e){return a.sibling(e.firstChild)},contents:function(e){return a.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:a.makeArray(e.childNodes)}},function(e,bd){a.fn[e]=function(bh,be){var bg=a.map(this,bd,bh),bf=M.call(arguments);if(!W.test(e)){be=bh}if(be&&typeof be==="string"){bg=a.filter(be,bg)}bg=this.length>1&&!ao[e]?a.unique(bg):bg;if((this.length>1||aW.test(be))&&ai.test(e)){bg=bg.reverse()}return this.pushStack(bg,e,bf.join(","))}});a.extend({filter:function(be,e,bd){if(bd){be=":not("+be+")"}return e.length===1?a.find.matchesSelector(e[0],be)?[e[0]]:[]:a.find.matches(be,e)},dir:function(be,bd,bg){var e=[],bf=be[bd];while(bf&&bf.nodeType!==9&&(bg===H||bf.nodeType!==1||!a(bf).is(bg))){if(bf.nodeType===1){e.push(bf)}bf=bf[bd]}return e},nth:function(bg,e,be,bf){e=e||1;var bd=0;for(;bg;bg=bg[be]){if(bg.nodeType===1&&++bd===e){break}}return bg},sibling:function(be,bd){var e=[];for(;be;be=be.nextSibling){if(be.nodeType===1&&be!==bd){e.push(be)}}return e}});function av(bf,be,e){if(a.isFunction(be)){return a.grep(bf,function(bh,bg){var bi=!!be.call(bh,bg,bh);return bi===e})}else{if(be.nodeType){return a.grep(bf,function(bh,bg){return(bh===be)===e})}else{if(typeof be==="string"){var bd=a.grep(bf,function(bg){return bg.nodeType===1});if(a9.test(be)){return a.filter(be,bd,!e)}else{be=a.filter(be,bd)}}}}return a.grep(bf,function(bh,bg){return(a.inArray(bh,be)>=0)===e})}var ab=/ jQuery\d+="(?:\d+|null)"/g,aj=/^\s+/,O=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,c=/<([\w:]+)/,v=/<tbody/i,T=/<|&#?\w+;/,L=/<(?:script|object|embed|option|style)/i,m=/checked\s*(?:[^=]|=\s*.checked.)/i,an={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,"",""]};an.optgroup=an.option;an.tbody=an.tfoot=an.colgroup=an.caption=an.thead;an.th=an.td;if(!a.support.htmlSerialize){an._default=[1,"div<div>","</div>"]}a.fn.extend({text:function(e){if(a.isFunction(e)){return this.each(function(be){var bd=a(this);bd.text(e.call(this,be,bd.text()))})}if(typeof e!=="object"&&e!==H){return this.empty().append((this[0]&&this[0].ownerDocument||al).createTextNode(e))}return a.text(this)},wrapAll:function(e){if(a.isFunction(e)){return this.each(function(be){a(this).wrapAll(e.call(this,be))})}if(this[0]){var bd=a(e,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){bd.insertBefore(this[0])}bd.map(function(){var be=this;while(be.firstChild&&be.firstChild.nodeType===1){be=be.firstChild}return be}).append(this)}return this},wrapInner:function(e){if(a.isFunction(e)){return this.each(function(bd){a(this).wrapInner(e.call(this,bd))})}return this.each(function(){var bd=a(this),be=bd.contents();if(be.length){be.wrapAll(e)}else{bd.append(e)}})},wrap:function(e){return this.each(function(){a(this).wrapAll(e)})},unwrap:function(){return this.parent().each(function(){if(!a.nodeName(this,"body")){a(this).replaceWith(this.childNodes)}}).end()},append:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.appendChild(e)}})},prepend:function(){return this.domManip(arguments,true,function(e){if(this.nodeType===1){this.insertBefore(e,this.firstChild)}})},before:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bd){this.parentNode.insertBefore(bd,this)})}else{if(arguments.length){var e=a(arguments[0]);e.push.apply(e,this.toArray());return this.pushStack(e,"before",arguments)}}},after:function(){if(this[0]&&this[0].parentNode){return this.domManip(arguments,false,function(bd){this.parentNode.insertBefore(bd,this.nextSibling)})}else{if(arguments.length){var e=this.pushStack(this,"after",arguments);e.push.apply(e,a(arguments[0]).toArray());return e}}},remove:function(e,bf){for(var bd=0,be;(be=this[bd])!=null;bd++){if(!e||a.filter(e,[be]).length){if(!bf&&be.nodeType===1){a.cleanData(be.getElementsByTagName("*"));a.cleanData([be])}if(be.parentNode){be.parentNode.removeChild(be)}}}return this},empty:function(){for(var e=0,bd;(bd=this[e])!=null;e++){if(bd.nodeType===1){a.cleanData(bd.getElementsByTagName("*"))}while(bd.firstChild){bd.removeChild(bd.firstChild)}}return this},clone:function(bd,e){bd=bd==null?false:bd;e=e==null?bd:e;return this.map(function(){return a.clone(this,bd,e)})},html:function(bf){if(bf===H){return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(ab,""):null}else{if(typeof bf==="string"&&!L.test(bf)&&(a.support.leadingWhitespace||!aj.test(bf))&&!an[(c.exec(bf)||["",""])[1].toLowerCase()]){bf=bf.replace(O,"<$1></$2>");try{for(var be=0,bd=this.length;be<bd;be++){if(this[be].nodeType===1){a.cleanData(this[be].getElementsByTagName("*"));this[be].innerHTML=bf}}}catch(bg){this.empty().append(bf)}}else{if(a.isFunction(bf)){this.each(function(bh){var e=a(this);e.html(bf.call(this,bh,e.html()))})}else{this.empty().append(bf)}}}return this},replaceWith:function(e){if(this[0]&&this[0].parentNode){if(a.isFunction(e)){return this.each(function(bf){var be=a(this),bd=be.html();be.replaceWith(e.call(this,bf,bd))})}if(typeof e!=="string"){e=a(e).detach()}return this.each(function(){var be=this.nextSibling,bd=this.parentNode;a(this).remove();if(be){a(be).before(e)}else{a(bd).append(e)}})}else{return this.pushStack(a(a.isFunction(e)?e():e),"replaceWith",e)}},detach:function(e){return this.remove(e,true)},domManip:function(bj,bn,bm){var bf,bg,bi,bl,bk=bj[0],bd=[];if(!a.support.checkClone&&arguments.length===3&&typeof bk==="string"&&m.test(bk)){return this.each(function(){a(this).domManip(bj,bn,bm,true)})}if(a.isFunction(bk)){return this.each(function(bp){var bo=a(this);bj[0]=bk.call(this,bp,bn?bo.html():H);bo.domManip(bj,bn,bm)})}if(this[0]){bl=bk&&bk.parentNode;if(a.support.parentNode&&bl&&bl.nodeType===11&&bl.childNodes.length===this.length){bf={fragment:bl}}else{bf=a.buildFragment(bj,this,bd)}bi=bf.fragment;if(bi.childNodes.length===1){bg=bi=bi.firstChild}else{bg=bi.firstChild}if(bg){bn=bn&&a.nodeName(bg,"tr");for(var be=0,e=this.length,bh=e-1;be<e;be++){bm.call(bn?aX(this[be],bg):this[be],bf.cacheable||(e>1&&be<bh)?a.clone(bi,true,true):bi)}}if(bd.length){a.each(bd,a8)}}return this}});function aX(e,bd){return a.nodeName(e,"table")?(e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody"))):e}function s(e,bj){if(bj.nodeType!==1||!a.hasData(e)){return}var bi=a.expando,bf=a.data(e),bg=a.data(bj,bf);if((bf=bf[bi])){var bk=bf.events;bg=bg[bi]=a.extend({},bf);if(bk){delete bg.handle;bg.events={};for(var bh in bk){for(var be=0,bd=bk[bh].length;be<bd;be++){a.event.add(bj,bh+(bk[bh][be].namespace?".":"")+bk[bh][be].namespace,bk[bh][be],bk[bh][be].data)}}}}}function ac(bd,e){if(e.nodeType!==1){return}var be=e.nodeName.toLowerCase();e.clearAttributes();e.mergeAttributes(bd);if(be==="object"){e.outerHTML=bd.outerHTML}else{if(be==="input"&&(bd.type==="checkbox"||bd.type==="radio")){if(bd.checked){e.defaultChecked=e.checked=bd.checked}if(e.value!==bd.value){e.value=bd.value}}else{if(be==="option"){e.selected=bd.defaultSelected}else{if(be==="input"||be==="textarea"){e.defaultValue=bd.defaultValue}}}}e.removeAttribute(a.expando)}a.buildFragment=function(bh,bf,bd){var bg,e,be,bi=(bf&&bf[0]?bf[0].ownerDocument||bf[0]:al);if(bh.length===1&&typeof bh[0]==="string"&&bh[0].length<512&&bi===al&&bh[0].charAt(0)==="<"&&!L.test(bh[0])&&(a.support.checkClone||!m.test(bh[0]))){e=true;be=a.fragments[bh[0]];if(be){if(be!==1){bg=be}}}if(!bg){bg=bi.createDocumentFragment();a.clean(bh,bi,bg,bd)}if(e){a.fragments[bh[0]]=be?bg:1}return{fragment:bg,cacheable:e}};a.fragments={};a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,bd){a.fn[e]=function(be){var bh=[],bk=a(be),bj=this.length===1&&this[0].parentNode;if(bj&&bj.nodeType===11&&bj.childNodes.length===1&&bk.length===1){bk[bd](this[0]);return this}else{for(var bi=0,bf=bk.length;bi<bf;bi++){var bg=(bi>0?this.clone(true):this).get();a(bk[bi])[bd](bg);bh=bh.concat(bg)}return this.pushStack(bh,e,bk.selector)}}});function a1(e){if("getElementsByTagName" in e){return e.getElementsByTagName("*")}else{if("querySelectorAll" in e){return e.querySelectorAll("*")}else{return[]}}}a.extend({clone:function(bg,bi,be){var bh=bg.cloneNode(true),e,bd,bf;if((!a.support.noCloneEvent||!a.support.noCloneChecked)&&(bg.nodeType===1||bg.nodeType===11)&&!a.isXMLDoc(bg)){ac(bg,bh);e=a1(bg);bd=a1(bh);for(bf=0;e[bf];++bf){ac(e[bf],bd[bf])}}if(bi){s(bg,bh);if(be){e=a1(bg);bd=a1(bh);for(bf=0;e[bf];++bf){s(e[bf],bd[bf])}}}return bh},clean:function(be,bg,bn,bi){bg=bg||al;if(typeof bg.createElement==="undefined"){bg=bg.ownerDocument||bg[0]&&bg[0].ownerDocument||al}var bo=[];for(var bm=0,bh;(bh=be[bm])!=null;bm++){if(typeof bh==="number"){bh+=""}if(!bh){continue}if(typeof bh==="string"&&!T.test(bh)){bh=bg.createTextNode(bh)}else{if(typeof bh==="string"){bh=bh.replace(O,"<$1></$2>");var bp=(c.exec(bh)||["",""])[1].toLowerCase(),bf=an[bp]||an._default,bl=bf[0],bd=bg.createElement("div");bd.innerHTML=bf[1]+bh+bf[2];while(bl--){bd=bd.lastChild}if(!a.support.tbody){var e=v.test(bh),bk=bp==="table"&&!e?bd.firstChild&&bd.firstChild.childNodes:bf[1]==="<table>"&&!e?bd.childNodes:[];for(var bj=bk.length-1;bj>=0;--bj){if(a.nodeName(bk[bj],"tbody")&&!bk[bj].childNodes.length){bk[bj].parentNode.removeChild(bk[bj])}}}if(!a.support.leadingWhitespace&&aj.test(bh)){bd.insertBefore(bg.createTextNode(aj.exec(bh)[0]),bd.firstChild)}bh=bd.childNodes}}if(bh.nodeType){bo.push(bh)}else{bo=a.merge(bo,bh)}}if(bn){for(bm=0;bo[bm];bm++){if(bi&&a.nodeName(bo[bm],"script")&&(!bo[bm].type||bo[bm].type.toLowerCase()==="text/javascript")){bi.push(bo[bm].parentNode?bo[bm].parentNode.removeChild(bo[bm]):bo[bm])}else{if(bo[bm].nodeType===1){bo.splice.apply(bo,[bm+1,0].concat(a.makeArray(bo[bm].getElementsByTagName("script"))))}bn.appendChild(bo[bm])}}}return bo},cleanData:function(bd){var bg,be,e=a.cache,bl=a.expando,bj=a.event.special,bi=a.support.deleteExpando;for(var bh=0,bf;(bf=bd[bh])!=null;bh++){if(bf.nodeName&&a.noData[bf.nodeName.toLowerCase()]){continue}be=bf[a.expando];if(be){bg=e[be]&&e[be][bl];if(bg&&bg.events){for(var bk in bg.events){if(bj[bk]){a.event.remove(bf,bk)}else{a.removeEvent(bf,bk,bg.handle)}}if(bg.handle){bg.handle.elem=null}}if(bi){delete bf[a.expando]}else{if(bf.removeAttribute){bf.removeAttribute(a.expando)}}delete e[be]}}}});function a8(e,bd){if(bd.src){a.ajax({url:bd.src,async:false,dataType:"script"})}else{a.globalEval(bd.text||bd.textContent||bd.innerHTML||"")}if(bd.parentNode){bd.parentNode.removeChild(bd)}}var ae=/alpha\([^)]*\)/i,ak=/opacity=([^)]*)/,aM=/-([a-z])/ig,y=/([A-Z])/g,aZ=/^-?\d+(?:px)?$/i,a7=/^-?\d/,aV={position:"absolute",visibility:"hidden",display:"block"},ag=["Left","Right"],aR=["Top","Bottom"],U,ay,aL,l=function(e,bd){return bd.toUpperCase()};a.fn.css=function(e,bd){if(arguments.length===2&&bd===H){return this}return a.access(this,e,bd,true,function(bf,be,bg){return bg!==H?a.style(bf,be,bg):a.css(bf,be)})};a.extend({cssHooks:{opacity:{get:function(be,bd){if(bd){var e=U(be,"opacity","opacity");return e===""?"1":e}else{return be.style.opacity}}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,zoom:true,lineHeight:true},cssProps:{"float":a.support.cssFloat?"cssFloat":"styleFloat"},style:function(bf,be,bk,bg){if(!bf||bf.nodeType===3||bf.nodeType===8||!bf.style){return}var bj,bh=a.camelCase(be),bd=bf.style,bl=a.cssHooks[bh];be=a.cssProps[bh]||bh;if(bk!==H){if(typeof bk==="number"&&isNaN(bk)||bk==null){return}if(typeof bk==="number"&&!a.cssNumber[bh]){bk+="px"}if(!bl||!("set" in bl)||(bk=bl.set(bf,bk))!==H){try{bd[be]=bk}catch(bi){}}}else{if(bl&&"get" in bl&&(bj=bl.get(bf,false,bg))!==H){return bj}return bd[be]}},css:function(bh,bg,bd){var bf,be=a.camelCase(bg),e=a.cssHooks[be];bg=a.cssProps[be]||be;if(e&&"get" in e&&(bf=e.get(bh,true,bd))!==H){return bf}else{if(U){return U(bh,bg,be)}}},swap:function(bf,be,bg){var e={};for(var bd in be){e[bd]=bf.style[bd];bf.style[bd]=be[bd]}bg.call(bf);for(bd in be){bf.style[bd]=e[bd]}},camelCase:function(e){return e.replace(aM,l)}});a.curCSS=a.css;a.each(["height","width"],function(bd,e){a.cssHooks[e]={get:function(bg,bf,be){var bh;if(bf){if(bg.offsetWidth!==0){bh=o(bg,e,be)}else{a.swap(bg,aV,function(){bh=o(bg,e,be)})}if(bh<=0){bh=U(bg,e,e);if(bh==="0px"&&aL){bh=aL(bg,e,e)}if(bh!=null){return bh===""||bh==="auto"?"0px":bh}}if(bh<0||bh==null){bh=bg.style[e];return bh===""||bh==="auto"?"0px":bh}return typeof bh==="string"?bh:bh+"px"}},set:function(be,bf){if(aZ.test(bf)){bf=parseFloat(bf);if(bf>=0){return bf+"px"}}else{return bf}}}});if(!a.support.opacity){a.cssHooks.opacity={get:function(bd,e){return ak.test((e&&bd.currentStyle?bd.currentStyle.filter:bd.style.filter)||"")?(parseFloat(RegExp.$1)/100)+"":e?"1":""},set:function(bf,bg){var be=bf.style;be.zoom=1;var e=a.isNaN(bg)?"":"alpha(opacity="+bg*100+")",bd=be.filter||"";be.filter=ae.test(bd)?bd.replace(ae,e):be.filter+" "+e}}}if(al.defaultView&&al.defaultView.getComputedStyle){ay=function(bh,e,bf){var be,bg,bd;bf=bf.replace(y,"-$1").toLowerCase();if(!(bg=bh.ownerDocument.defaultView)){return H}if((bd=bg.getComputedStyle(bh,null))){be=bd.getPropertyValue(bf);if(be===""&&!a.contains(bh.ownerDocument.documentElement,bh)){be=a.style(bh,bf)}}return be}}if(al.documentElement.currentStyle){aL=function(bg,be){var bh,bd=bg.currentStyle&&bg.currentStyle[be],e=bg.runtimeStyle&&bg.runtimeStyle[be],bf=bg.style;if(!aZ.test(bd)&&a7.test(bd)){bh=bf.left;if(e){bg.runtimeStyle.left=bg.currentStyle.left}bf.left=be==="fontSize"?"1em":(bd||0);bd=bf.pixelLeft+"px";bf.left=bh;if(e){bg.runtimeStyle.left=e}}return bd===""?"auto":bd}}U=ay||aL;function o(be,bd,e){var bg=bd==="width"?ag:aR,bf=bd==="width"?be.offsetWidth:be.offsetHeight;if(e==="border"){return bf}a.each(bg,function(){if(!e){bf-=parseFloat(a.css(be,"padding"+this))||0}if(e==="margin"){bf+=parseFloat(a.css(be,"margin"+this))||0}else{bf-=parseFloat(a.css(be,"border"+this+"Width"))||0}});return bf}if(a.expr&&a.expr.filters){a.expr.filters.hidden=function(be){var bd=be.offsetWidth,e=be.offsetHeight;return(bd===0&&e===0)||(!a.support.reliableHiddenOffsets&&(be.style.display||a.css(be,"display"))==="none")};a.expr.filters.visible=function(e){return !a.expr.filters.hidden(e)}}var i=/%20/g,ah=/\[\]$/,bc=/\r?\n/g,ba=/#.*$/,ar=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,aO=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,aB=/(?:^file|^widget|\-extension):$/,aD=/^(?:GET|HEAD)$/,b=/^\/\//,I=/\?/,aU=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,p=/^(?:select|textarea)/i,g=/\s+/,bb=/([?&])_=[^&]*/,R=/(^|\-)([a-z])/g,aJ=function(bd,e,be){return e+be.toUpperCase()},G=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,z=a.fn.load,V={},q={},au,r;try{au=al.location.href}catch(am){au=al.createElement("a");au.href="";au=au.href}r=G.exec(au.toLowerCase());function d(e){return function(bg,bi){if(typeof bg!=="string"){bi=bg;bg="*"}if(a.isFunction(bi)){var bf=bg.toLowerCase().split(g),be=0,bh=bf.length,bd,bj,bk;for(;be<bh;be++){bd=bf[be];bk=/^\+/.test(bd);if(bk){bd=bd.substr(1)||"*"}bj=e[bd]=e[bd]||[];bj[bk?"unshift":"push"](bi)}}}}function aI(bd,bm,bh,bl,bj,bf){bj=bj||bm.dataTypes[0];bf=bf||{};bf[bj]=true;var bi=bd[bj],be=0,e=bi?bi.length:0,bg=(bd===V),bk;for(;be<e&&(bg||!bk);be++){bk=bi[be](bm,bh,bl);if(typeof bk==="string"){if(!bg||bf[bk]){bk=H}else{bm.dataTypes.unshift(bk);bk=aI(bd,bm,bh,bl,bk,bf)}}}if((bg||!bk)&&!bf["*"]){bk=aI(bd,bm,bh,bl,"*",bf)}return bk}a.fn.extend({load:function(be,bh,bi){if(typeof be!=="string"&&z){return z.apply(this,arguments)}else{if(!this.length){return this}}var bg=be.indexOf(" ");if(bg>=0){var e=be.slice(bg,be.length);be=be.slice(0,bg)}var bf="GET";if(bh){if(a.isFunction(bh)){bi=bh;bh=H}else{if(typeof bh==="object"){bh=a.param(bh,a.ajaxSettings.traditional);bf="POST"}}}var bd=this;a.ajax({url:be,type:bf,dataType:"html",data:bh,complete:function(bk,bj,bl){bl=bk.responseText;if(bk.isResolved()){bk.done(function(bm){bl=bm});bd.html(e?a("<div>").append(bl.replace(aU,"")).find(e):bl)}if(bi){bd.each(bi,[bl,bj,bk])}}});return this},serialize:function(){return a.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?a.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||p.test(this.nodeName)||aO.test(this.type))}).map(function(e,bd){var be=a(this).val();return be==null?null:a.isArray(be)?a.map(be,function(bg,bf){return{name:bd.name,value:bg.replace(bc,"\r\n")}}):{name:bd.name,value:be.replace(bc,"\r\n")}}).get()}});a.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,bd){a.fn[bd]=function(be){return this.bind(bd,be)}});a.each(["get","post"],function(e,bd){a[bd]=function(be,bg,bh,bf){if(a.isFunction(bg)){bf=bf||bh;bh=bg;bg=H}return a.ajax({type:bd,url:be,data:bg,success:bh,dataType:bf})}});a.extend({getScript:function(e,bd){return a.get(e,H,bd,"script")},getJSON:function(e,bd,be){return a.get(e,bd,be,"json")},ajaxSetup:function(be,e){if(!e){e=be;be=a.extend(true,a.ajaxSettings,e)}else{a.extend(true,be,a.ajaxSettings,e)}for(var bd in {context:1,url:1}){if(bd in e){be[bd]=e[bd]}else{if(bd in a.ajaxSettings){be[bd]=a.ajaxSettings[bd]}}}return be},ajaxSettings:{url:au,isLocal:aB.test(r[1]),global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":aY.String,"text html":true,"text json":a.parseJSON,"text xml":a.parseXML}},ajaxPrefilter:d(V),ajaxTransport:d(q),ajax:function(bh,bf){if(typeof bh==="object"){bf=bh;bh=H}bf=bf||{};var bl=a.ajaxSetup({},bf),bz=bl.context||bl,bo=bz!==bl&&(bz.nodeType||bz instanceof a)?a(bz):a.event,by=a.Deferred(),bv=a._Deferred(),bj=bl.statusCode||{},bk,bp={},bx,bg,bt,bm,bq,bi=0,be,bs,br={readyState:0,setRequestHeader:function(e,bA){if(!bi){bp[e.toLowerCase().replace(R,aJ)]=bA}return this},getAllResponseHeaders:function(){return bi===2?bx:null},getResponseHeader:function(bA){var e;if(bi===2){if(!bg){bg={};while((e=ar.exec(bx))){bg[e[1].toLowerCase()]=e[2]}}e=bg[bA.toLowerCase()]}return e===H?null:e},overrideMimeType:function(e){if(!bi){bl.mimeType=e}return this},abort:function(e){e=e||"abort";if(bt){bt.abort(e)}bn(0,e);return this}};function bn(bF,bD,bG,bC){if(bi===2){return}bi=2;if(bm){clearTimeout(bm)}bt=H;bx=bC||"";br.readyState=bF?4:0;var bA,bK,bJ,bE=bG?a4(bl,br,bG):H,bB,bI;if(bF>=200&&bF<300||bF===304){if(bl.ifModified){if((bB=br.getResponseHeader("Last-Modified"))){a.lastModified[bk]=bB}if((bI=br.getResponseHeader("Etag"))){a.etag[bk]=bI}}if(bF===304){bD="notmodified";bA=true}else{try{bK=D(bl,bE);bD="success";bA=true}catch(bH){bD="parsererror";bJ=bH}}}else{bJ=bD;if(!bD||bF){bD="error";if(bF<0){bF=0}}}br.status=bF;br.statusText=bD;if(bA){by.resolveWith(bz,[bK,bD,br])}else{by.rejectWith(bz,[br,bD,bJ])}br.statusCode(bj);bj=H;if(be){bo.trigger("ajax"+(bA?"Success":"Error"),[br,bl,bA?bK:bJ])}bv.resolveWith(bz,[br,bD]);if(be){bo.trigger("ajaxComplete",[br,bl]);if(!(--a.active)){a.event.trigger("ajaxStop")}}}by.promise(br);br.success=br.done;br.error=br.fail;br.complete=bv.done;br.statusCode=function(bA){if(bA){var e;if(bi<2){for(e in bA){bj[e]=[bj[e],bA[e]]}}else{e=bA[br.status];br.then(e,e)}}return this};bl.url=((bh||bl.url)+"").replace(ba,"").replace(b,r[1]+"//");bl.dataTypes=a.trim(bl.dataType||"*").toLowerCase().split(g);if(!bl.crossDomain){bq=G.exec(bl.url.toLowerCase());bl.crossDomain=!!(bq&&(bq[1]!=r[1]||bq[2]!=r[2]||(bq[3]||(bq[1]==="http:"?80:443))!=(r[3]||(r[1]==="http:"?80:443))))}if(bl.data&&bl.processData&&typeof bl.data!=="string"){bl.data=a.param(bl.data,bl.traditional)}aI(V,bl,bf,br);if(bi===2){return false}be=bl.global;bl.type=bl.type.toUpperCase();bl.hasContent=!aD.test(bl.type);if(be&&a.active++===0){a.event.trigger("ajaxStart")}if(!bl.hasContent){if(bl.data){bl.url+=(I.test(bl.url)?"&":"?")+bl.data}bk=bl.url;if(bl.cache===false){var bd=a.now(),bw=bl.url.replace(bb,"$1_="+bd);bl.url=bw+((bw===bl.url)?(I.test(bl.url)?"&":"?")+"_="+bd:"")}}if(bl.data&&bl.hasContent&&bl.contentType!==false||bf.contentType){bp["Content-Type"]=bl.contentType}if(bl.ifModified){bk=bk||bl.url;if(a.lastModified[bk]){bp["If-Modified-Since"]=a.lastModified[bk]}if(a.etag[bk]){bp["If-None-Match"]=a.etag[bk]}}bp.Accept=bl.dataTypes[0]&&bl.accepts[bl.dataTypes[0]]?bl.accepts[bl.dataTypes[0]]+(bl.dataTypes[0]!=="*"?", */*; q=0.01":""):bl.accepts["*"];for(bs in bl.headers){br.setRequestHeader(bs,bl.headers[bs])}if(bl.beforeSend&&(bl.beforeSend.call(bz,br,bl)===false||bi===2)){br.abort();return false}for(bs in {success:1,error:1,complete:1}){br[bs](bl[bs])}bt=aI(q,bl,bf,br);if(!bt){bn(-1,"No Transport")}else{br.readyState=1;if(be){bo.trigger("ajaxSend",[br,bl])}if(bl.async&&bl.timeout>0){bm=setTimeout(function(){br.abort("timeout")},bl.timeout)}try{bi=1;bt.send(bp,bn)}catch(bu){if(status<2){bn(-1,bu)}else{a.error(bu)}}}return br},param:function(e,be){var bd=[],bg=function(bh,bi){bi=a.isFunction(bi)?bi():bi;bd[bd.length]=encodeURIComponent(bh)+"="+encodeURIComponent(bi)};if(be===H){be=a.ajaxSettings.traditional}if(a.isArray(e)||(e.jquery&&!a.isPlainObject(e))){a.each(e,function(){bg(this.name,this.value)})}else{for(var bf in e){u(bf,e[bf],be,bg)}}return bd.join("&").replace(i,"+")}});function u(be,bg,bd,bf){if(a.isArray(bg)&&bg.length){a.each(bg,function(bi,bh){if(bd||ah.test(be)){bf(be,bh)}else{u(be+"["+(typeof bh==="object"||a.isArray(bh)?bi:"")+"]",bh,bd,bf)}})}else{if(!bd&&bg!=null&&typeof bg==="object"){if(a.isArray(bg)||a.isEmptyObject(bg)){bf(be,"")}else{for(var e in bg){u(be+"["+e+"]",bg[e],bd,bf)}}}else{bf(be,bg)}}}a.extend({active:0,lastModified:{},etag:{}});function a4(bl,bk,bh){var bd=bl.contents,bj=bl.dataTypes,be=bl.responseFields,bg,bi,bf,e;for(bi in be){if(bi in bh){bk[be[bi]]=bh[bi]}}while(bj[0]==="*"){bj.shift();if(bg===H){bg=bl.mimeType||bk.getResponseHeader("content-type")}}if(bg){for(bi in bd){if(bd[bi]&&bd[bi].test(bg)){bj.unshift(bi);break}}}if(bj[0] in bh){bf=bj[0]}else{for(bi in bh){if(!bj[0]||bl.converters[bi+" "+bj[0]]){bf=bi;break}if(!e){e=bi}}bf=bf||e}if(bf){if(bf!==bj[0]){bj.unshift(bf)}return bh[bf]}}function D(bp,bh){if(bp.dataFilter){bh=bp.dataFilter(bh,bp.dataType)}var bl=bp.dataTypes,bo={},bi,bm,be=bl.length,bj,bk=bl[0],bf,bg,bn,bd,e;for(bi=1;bi<be;bi++){if(bi===1){for(bm in bp.converters){if(typeof bm==="string"){bo[bm.toLowerCase()]=bp.converters[bm]}}}bf=bk;bk=bl[bi];if(bk==="*"){bk=bf}else{if(bf!=="*"&&bf!==bk){bg=bf+" "+bk;bn=bo[bg]||bo["* "+bk];if(!bn){e=H;for(bd in bo){bj=bd.split(" ");if(bj[0]===bf||bj[0]==="*"){e=bo[bj[1]+" "+bk];if(e){bd=bo[bd];if(bd===true){bn=e}else{if(e===true){bn=bd}}break}}}}if(!(bn||e)){a.error("No conversion from "+bg.replace(" "," to "))}if(bn!==true){bh=bn?bn(bh):e(bd(bh))}}}}return bh}var aq=a.now(),t=/(\=)\?(&|$)|()\?\?()/i;a.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return a.expando+"_"+(aq++)}});a.ajaxPrefilter("json jsonp",function(bm,bi,bl){var bk=(typeof bm.data==="string");if(bm.dataTypes[0]==="jsonp"||bi.jsonpCallback||bi.jsonp!=null||bm.jsonp!==false&&(t.test(bm.url)||bk&&t.test(bm.data))){var bj,be=bm.jsonpCallback=a.isFunction(bm.jsonpCallback)?bm.jsonpCallback():bm.jsonpCallback,bh=aY[be],e=bm.url,bg=bm.data,bd="$1"+be+"$2",bf=function(){aY[be]=bh;if(bj&&a.isFunction(bh)){aY[be](bj[0])}};if(bm.jsonp!==false){e=e.replace(t,bd);if(bm.url===e){if(bk){bg=bg.replace(t,bd)}if(bm.data===bg){e+=(/\?/.test(e)?"&":"?")+bm.jsonp+"="+be}}}bm.url=e;bm.data=bg;aY[be]=function(bn){bj=[bn]};bl.then(bf,bf);bm.converters["script json"]=function(){if(!bj){a.error(be+" was not called")}return bj[0]};bm.dataTypes[0]="json";return"script"}});a.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){a.globalEval(e);return e}}});a.ajaxPrefilter("script",function(e){if(e.cache===H){e.cache=false}if(e.crossDomain){e.type="GET";e.global=false}});a.ajaxTransport("script",function(be){if(be.crossDomain){var e,bd=al.head||al.getElementsByTagName("head")[0]||al.documentElement;return{send:function(bf,bg){e=al.createElement("script");e.async="async";if(be.scriptCharset){e.charset=be.scriptCharset}e.src=be.url;e.onload=e.onreadystatechange=function(bi,bh){if(!e.readyState||/loaded|complete/.test(e.readyState)){e.onload=e.onreadystatechange=null;if(bd&&e.parentNode){bd.removeChild(e)}e=H;if(!bh){bg(200,"success")}}};bd.insertBefore(e,bd.firstChild)},abort:function(){if(e){e.onload(0,1)}}}}});var x=a.now(),J,at;function A(){a(aY).unload(function(){for(var e in J){J[e](0,1)}})}function aA(){try{return new aY.XMLHttpRequest()}catch(bd){}}function ad(){try{return new aY.ActiveXObject("Microsoft.XMLHTTP")}catch(bd){}}a.ajaxSettings.xhr=aY.ActiveXObject?function(){return !this.isLocal&&aA()||ad()}:aA;at=a.ajaxSettings.xhr();a.support.ajax=!!at;a.support.cors=at&&("withCredentials" in at);at=H;if(a.support.ajax){a.ajaxTransport(function(e){if(!e.crossDomain||a.support.cors){var bd;return{send:function(bj,be){var bi=e.xhr(),bh,bg;if(e.username){bi.open(e.type,e.url,e.async,e.username,e.password)}else{bi.open(e.type,e.url,e.async)}if(e.xhrFields){for(bg in e.xhrFields){bi[bg]=e.xhrFields[bg]}}if(e.mimeType&&bi.overrideMimeType){bi.overrideMimeType(e.mimeType)}if(!(e.crossDomain&&!e.hasContent)&&!bj["X-Requested-With"]){bj["X-Requested-With"]="XMLHttpRequest"}try{for(bg in bj){bi.setRequestHeader(bg,bj[bg])}}catch(bf){}bi.send((e.hasContent&&e.data)||null);bd=function(bs,bm){var bn,bl,bk,bq,bp;try{if(bd&&(bm||bi.readyState===4)){bd=H;if(bh){bi.onreadystatechange=a.noop;delete J[bh]}if(bm){if(bi.readyState!==4){bi.abort()}}else{bn=bi.status;bk=bi.getAllResponseHeaders();bq={};bp=bi.responseXML;if(bp&&bp.documentElement){bq.xml=bp}bq.text=bi.responseText;try{bl=bi.statusText}catch(br){bl=""}if(!bn&&e.isLocal&&!e.crossDomain){bn=bq.text?200:404}else{if(bn===1223){bn=204}}}}}catch(bo){if(!bm){be(-1,bo)}}if(bq){be(bn,bl,bq,bk)}};if(!e.async||bi.readyState===4){bd()}else{if(!J){J={};A()}bh=x++;bi.onreadystatechange=J[bh]=bd}},abort:function(){if(bd){bd(0,1)}}}}})}var N={},ap=/^(?:toggle|show|hide)$/,aF=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,aS,ax=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];a.fn.extend({show:function(bf,bi,bh){var be,bg;if(bf||bf===0){return this.animate(aQ("show",3),bf,bi,bh)}else{for(var bd=0,e=this.length;bd<e;bd++){be=this[bd];bg=be.style.display;if(!a._data(be,"olddisplay")&&bg==="none"){bg=be.style.display=""}if(bg===""&&a.css(be,"display")==="none"){a._data(be,"olddisplay",w(be.nodeName))}}for(bd=0;bd<e;bd++){be=this[bd];bg=be.style.display;if(bg===""||bg==="none"){be.style.display=a._data(be,"olddisplay")||""}}return this}},hide:function(be,bh,bg){if(be||be===0){return this.animate(aQ("hide",3),be,bh,bg)}else{for(var bd=0,e=this.length;bd<e;bd++){var bf=a.css(this[bd],"display");if(bf!=="none"&&!a._data(this[bd],"olddisplay")){a._data(this[bd],"olddisplay",bf)}}for(bd=0;bd<e;bd++){this[bd].style.display="none"}return this}},_toggle:a.fn.toggle,toggle:function(be,bd,bf){var e=typeof be==="boolean";if(a.isFunction(be)&&a.isFunction(bd)){this._toggle.apply(this,arguments)}else{if(be==null||e){this.each(function(){var bg=e?be:a(this).is(":hidden");a(this)[bg?"show":"hide"]()})}else{this.animate(aQ("toggle",3),be,bd,bf)}}return this},fadeTo:function(e,bf,be,bd){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:bf},e,be,bd)},animate:function(bg,bd,bf,be){var e=a.speed(bd,bf,be);if(a.isEmptyObject(bg)){return this.each(e.complete)}return this[e.queue===false?"each":"queue"](function(){var bj=a.extend({},e),bn,bk=this.nodeType===1,bl=bk&&a(this).is(":hidden"),bh=this;for(bn in bg){var bi=a.camelCase(bn);if(bn!==bi){bg[bi]=bg[bn];delete bg[bn];bn=bi}if(bg[bn]==="hide"&&bl||bg[bn]==="show"&&!bl){return bj.complete.call(this)}if(bk&&(bn==="height"||bn==="width")){bj.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(a.css(this,"display")==="inline"&&a.css(this,"float")==="none"){if(!a.support.inlineBlockNeedsLayout){this.style.display="inline-block"}else{var bm=w(this.nodeName);if(bm==="inline"){this.style.display="inline-block"}else{this.style.display="inline";this.style.zoom=1}}}}if(a.isArray(bg[bn])){(bj.specialEasing=bj.specialEasing||{})[bn]=bg[bn][1];bg[bn]=bg[bn][0]}}if(bj.overflow!=null){this.style.overflow="hidden"}bj.curAnim=a.extend({},bg);a.each(bg,function(bp,bt){var bs=new a.fx(bh,bj,bp);if(ap.test(bt)){bs[bt==="toggle"?bl?"show":"hide":bt](bg)}else{var br=aF.exec(bt),bu=bs.cur();if(br){var bo=parseFloat(br[2]),bq=br[3]||(a.cssNumber[bp]?"":"px");if(bq!=="px"){a.style(bh,bp,(bo||1)+bq);bu=((bo||1)/bs.cur())*bu;a.style(bh,bp,bu+bq)}if(br[1]){bo=((br[1]==="-="?-1:1)*bo)+bu}bs.custom(bu,bo,bq)}else{bs.custom(bu,bt,"")}}});return true})},stop:function(bd,e){var be=a.timers;if(bd){this.queue([])}this.each(function(){for(var bf=be.length-1;bf>=0;bf--){if(be[bf].elem===this){if(e){be[bf](true)}be.splice(bf,1)}}});if(!e){this.dequeue()}return this}});function aQ(bd,e){var be={};a.each(ax.concat.apply([],ax.slice(0,e)),function(){be[this]=bd});return be}a.each({slideDown:aQ("show",1),slideUp:aQ("hide",1),slideToggle:aQ("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,bd){a.fn[e]=function(be,bg,bf){return this.animate(bd,be,bg,bf)}});a.extend({speed:function(be,bf,bd){var e=be&&typeof be==="object"?a.extend({},be):{complete:bd||!bd&&bf||a.isFunction(be)&&be,duration:be,easing:bd&&bf||bf&&!a.isFunction(bf)&&bf};e.duration=a.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in a.fx.speeds?a.fx.speeds[e.duration]:a.fx.speeds._default;e.old=e.complete;e.complete=function(){if(e.queue!==false){a(this).dequeue()}if(a.isFunction(e.old)){e.old.call(this)}};return e},easing:{linear:function(be,bf,e,bd){return e+bd*be},swing:function(be,bf,e,bd){return((-Math.cos(be*Math.PI)/2)+0.5)*bd+e}},timers:[],fx:function(bd,e,be){this.options=e;this.elem=bd;this.prop=be;if(!e.orig){e.orig={}}}});a.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(a.fx.step[this.prop]||a.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var e,bd=a.css(this.elem,this.prop);return isNaN(e=parseFloat(bd))?!bd||bd==="auto"?0:bd:e},custom:function(bh,bg,bf){var e=this,be=a.fx;this.startTime=a.now();this.start=bh;this.end=bg;this.unit=bf||this.unit||(a.cssNumber[this.prop]?"":"px");this.now=this.start;this.pos=this.state=0;function bd(bi){return e.step(bi)}bd.elem=this.elem;if(bd()&&a.timers.push(bd)&&!aS){aS=setInterval(be.tick,be.interval)}},show:function(){this.options.orig[this.prop]=a.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());a(this.elem).show()},hide:function(){this.options.orig[this.prop]=a.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(bf){var bk=a.now(),bg=true;if(bf||bk>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var bh in this.options.curAnim){if(this.options.curAnim[bh]!==true){bg=false}}if(bg){if(this.options.overflow!=null&&!a.support.shrinkWrapBlocks){var be=this.elem,bl=this.options;a.each(["","X","Y"],function(bm,bn){be.style["overflow"+bn]=bl.overflow[bm]})}if(this.options.hide){a(this.elem).hide()}if(this.options.hide||this.options.show){for(var e in this.options.curAnim){a.style(this.elem,e,this.options.orig[e])}}this.options.complete.call(this.elem)}return false}else{var bd=bk-this.startTime;this.state=bd/this.options.duration;var bi=this.options.specialEasing&&this.options.specialEasing[this.prop];var bj=this.options.easing||(a.easing.swing?"swing":"linear");this.pos=a.easing[bi||bj](this.state,bd,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};a.extend(a.fx,{tick:function(){var bd=a.timers;for(var e=0;e<bd.length;e++){if(!bd[e]()){bd.splice(e--,1)}}if(!bd.length){a.fx.stop()}},interval:13,stop:function(){clearInterval(aS);aS=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(e){a.style(e.elem,"opacity",e.now)},_default:function(e){if(e.elem.style&&e.elem.style[e.prop]!=null){e.elem.style[e.prop]=(e.prop==="width"||e.prop==="height"?Math.max(0,e.now):e.now)+e.unit}else{e.elem[e.prop]=e.now}}}});if(a.expr&&a.expr.filters){a.expr.filters.animated=function(e){return a.grep(a.timers,function(bd){return e===bd.elem}).length}}function w(be){if(!N[be]){var e=a("<"+be+">").appendTo("body"),bd=e.css("display");e.remove();if(bd==="none"||bd===""){bd="block"}N[be]=bd}return N[be]}var S=/^t(?:able|d|h)$/i,Y=/^(?:body|html)$/i;if("getBoundingClientRect" in al.documentElement){a.fn.offset=function(bq){var bg=this[0],bj;if(bq){return this.each(function(e){a.offset.setOffset(this,bq,e)})}if(!bg||!bg.ownerDocument){return null}if(bg===bg.ownerDocument.body){return a.offset.bodyOffset(bg)}try{bj=bg.getBoundingClientRect()}catch(bn){}var bp=bg.ownerDocument,be=bp.documentElement;if(!bj||!a.contains(be,bg)){return bj?{top:bj.top,left:bj.left}:{top:0,left:0}}var bk=bp.body,bl=az(bp),bi=be.clientTop||bk.clientTop||0,bm=be.clientLeft||bk.clientLeft||0,bd=(bl.pageYOffset||a.support.boxModel&&be.scrollTop||bk.scrollTop),bh=(bl.pageXOffset||a.support.boxModel&&be.scrollLeft||bk.scrollLeft),bo=bj.top+bd-bi,bf=bj.left+bh-bm;return{top:bo,left:bf}}}else{a.fn.offset=function(bn){var bh=this[0];if(bn){return this.each(function(bo){a.offset.setOffset(this,bn,bo)})}if(!bh||!bh.ownerDocument){return null}if(bh===bh.ownerDocument.body){return a.offset.bodyOffset(bh)}a.offset.initialize();var bk,be=bh.offsetParent,bd=bh,bm=bh.ownerDocument,bf=bm.documentElement,bi=bm.body,bj=bm.defaultView,e=bj?bj.getComputedStyle(bh,null):bh.currentStyle,bl=bh.offsetTop,bg=bh.offsetLeft;while((bh=bh.parentNode)&&bh!==bi&&bh!==bf){if(a.offset.supportsFixedPosition&&e.position==="fixed"){break}bk=bj?bj.getComputedStyle(bh,null):bh.currentStyle;bl-=bh.scrollTop;bg-=bh.scrollLeft;if(bh===be){bl+=bh.offsetTop;bg+=bh.offsetLeft;if(a.offset.doesNotAddBorder&&!(a.offset.doesAddBorderForTableAndCells&&S.test(bh.nodeName))){bl+=parseFloat(bk.borderTopWidth)||0;bg+=parseFloat(bk.borderLeftWidth)||0}bd=be;be=bh.offsetParent}if(a.offset.subtractsBorderForOverflowNotVisible&&bk.overflow!=="visible"){bl+=parseFloat(bk.borderTopWidth)||0;bg+=parseFloat(bk.borderLeftWidth)||0}e=bk}if(e.position==="relative"||e.position==="static"){bl+=bi.offsetTop;bg+=bi.offsetLeft}if(a.offset.supportsFixedPosition&&e.position==="fixed"){bl+=Math.max(bf.scrollTop,bi.scrollTop);bg+=Math.max(bf.scrollLeft,bi.scrollLeft)}return{top:bl,left:bg}}}a.offset={initialize:function(){var e=al.body,bd=al.createElement("div"),bg,bi,bh,bj,be=parseFloat(a.css(e,"marginTop"))||0,bf="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.extend(bd.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});bd.innerHTML=bf;e.insertBefore(bd,e.firstChild);bg=bd.firstChild;bi=bg.firstChild;bj=bg.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(bi.offsetTop!==5);this.doesAddBorderForTableAndCells=(bj.offsetTop===5);bi.style.position="fixed";bi.style.top="20px";this.supportsFixedPosition=(bi.offsetTop===20||bi.offsetTop===15);bi.style.position=bi.style.top="";bg.style.overflow="hidden";bg.style.position="relative";this.subtractsBorderForOverflowNotVisible=(bi.offsetTop===-5);this.doesNotIncludeMarginInBodyOffset=(e.offsetTop!==be);e.removeChild(bd);e=bd=bg=bi=bh=bj=null;a.offset.initialize=a.noop},bodyOffset:function(e){var be=e.offsetTop,bd=e.offsetLeft;a.offset.initialize();if(a.offset.doesNotIncludeMarginInBodyOffset){be+=parseFloat(a.css(e,"marginTop"))||0;bd+=parseFloat(a.css(e,"marginLeft"))||0}return{top:be,left:bd}},setOffset:function(bf,bo,bi){var bj=a.css(bf,"position");if(bj==="static"){bf.style.position="relative"}var bh=a(bf),bd=bh.offset(),e=a.css(bf,"top"),bm=a.css(bf,"left"),bn=(bj==="absolute"&&a.inArray("auto",[e,bm])>-1),bl={},bk={},be,bg;if(bn){bk=bh.position()}be=bn?bk.top:parseInt(e,10)||0;bg=bn?bk.left:parseInt(bm,10)||0;if(a.isFunction(bo)){bo=bo.call(bf,bi,bd)}if(bo.top!=null){bl.top=(bo.top-bd.top)+be}if(bo.left!=null){bl.left=(bo.left-bd.left)+bg}if("using" in bo){bo.using.call(bf,bl)}else{bh.css(bl)}}};a.fn.extend({position:function(){if(!this[0]){return null}var be=this[0],bd=this.offsetParent(),bf=this.offset(),e=Y.test(bd[0].nodeName)?{top:0,left:0}:bd.offset();bf.top-=parseFloat(a.css(be,"marginTop"))||0;bf.left-=parseFloat(a.css(be,"marginLeft"))||0;e.top+=parseFloat(a.css(bd[0],"borderTopWidth"))||0;e.left+=parseFloat(a.css(bd[0],"borderLeftWidth"))||0;return{top:bf.top-e.top,left:bf.left-e.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||al.body;while(e&&(!Y.test(e.nodeName)&&a.css(e,"position")==="static")){e=e.offsetParent}return e})}});a.each(["Left","Top"],function(bd,e){var be="scroll"+e;a.fn[be]=function(bh){var bf=this[0],bg;if(!bf){return null}if(bh!==H){return this.each(function(){bg=az(this);if(bg){bg.scrollTo(!bd?bh:a(bg).scrollLeft(),bd?bh:a(bg).scrollTop())}else{this[be]=bh}})}else{bg=az(bf);return bg?("pageXOffset" in bg)?bg[bd?"pageYOffset":"pageXOffset"]:a.support.boxModel&&bg.document.documentElement[be]||bg.document.body[be]:bf[be]}}});function az(e){return a.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}a.each(["Height","Width"],function(bd,e){var be=e.toLowerCase();a.fn["inner"+e]=function(){return this[0]?parseFloat(a.css(this[0],be,"padding")):null};a.fn["outer"+e]=function(bf){return this[0]?parseFloat(a.css(this[0],be,bf?"margin":"border")):null};a.fn[be]=function(bg){var bh=this[0];if(!bh){return bg==null?null:this}if(a.isFunction(bg)){return this.each(function(bl){var bk=a(this);bk[be](bg.call(this,bl,bk[be]()))})}if(a.isWindow(bh)){var bi=bh.document.documentElement["client"+e];return bh.document.compatMode==="CSS1Compat"&&bi||bh.document.body["client"+e]||bi}else{if(bh.nodeType===9){return Math.max(bh.documentElement["client"+e],bh.body["scroll"+e],bh.documentElement["scroll"+e],bh.body["offset"+e],bh.documentElement["offset"+e])}else{if(bg===H){var bj=a.css(bh,be),bf=parseFloat(bj);return a.isNaN(bf)?bj:bf}else{return this.css(be,typeof bg==="string"?bg:bg+"px")}}}}});aY.jQuery=aY.$=a})(window);
\ No newline at end of file
+/*! jQuery v1.8.3 jquery.com | jquery.org/license */
+(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.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%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},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(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.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(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.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(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={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,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[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","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window);
\ No newline at end of file
diff --git a/third_party/guava/guava.gyp b/third_party/guava/guava.gyp
index bfe2a30..e300460 100644
--- a/third_party/guava/guava.gyp
+++ b/third_party/guava/guava.gyp
@@ -9,6 +9,8 @@
       'type': 'none',
       'variables': {
         'java_in_dir': 'src/guava',
+        'proguard_preprocess': 1,
+        'proguard_config': 'proguard.flags',
       },
       'dependencies': [
         '../../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
diff --git a/third_party/guava/proguard.flags b/third_party/guava/proguard.flags
new file mode 100644
index 0000000..604059a
--- /dev/null
+++ b/third_party/guava/proguard.flags
@@ -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.
+
+-keep class com.google.common.base.** {
+  *;
+}
+
+-keep class com.google.common.annotations.** {
+  *;
+}
+
+-keepattributes Signature
+
+# Don't complain about usage of sun.misc.Unsafe. Guava imports this,
+# but does not use it unless it exists.
+# The gyp-target that uses this is guava.gyp:guava_javalib.
+-dontwarn sun.misc.Unsafe
+# Striped64 uses reflection to access some local fields.
+-dontnote com.google.common.cache.Striped64
+-dontnote com.google.common.cache.Striped64$Cell
+
+# Keep all enum values and valueOf methods. See
+# http://proguard.sourceforge.net/index.html#manual/examples.html
+# for the reason for this. Also, see http://crbug.com/248037.
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
diff --git a/third_party/lcov-1.9/CHANGES b/third_party/lcov-1.9/CHANGES
deleted file mode 100644
index 1ff8240..0000000
--- a/third_party/lcov-1.9/CHANGES
+++ /dev/null
@@ -1,419 +0,0 @@
-Version 1.9
-===========
-
-genhtml:
-- Improved wording for branch representation tooltip text
-- Fixed vertical alignment of HTML branch representation
-
-geninfo:
-- Improved warning message about --initial not generating branch coverage data
-- Debugging messages are now printed to STDERR instead of STDOUT
-- Fixed problem with some .gcno files. Reported by gui@futarque.com.
-  (file.gcno: reached unexpected end of file)
-- Fixed problem with relative build paths. Reported by zhanbiao2000@gmail.com.
-  (cannot find an entry for ^#src#test.c.gcov in .gcno file, skipping file!)
-- Fixed problem where coverage data is missing for some files. Reported by
-  weston_schmidt@open-roadster.com
-- Fixed problem where exclusion markers are ignored when gathering
-  initial coverage data. Reported by ahmed_osman@mentor.com.
-- Fixed large execution counts showing as negative numbers in HTML output.
-  Reported by kkyriako@yahoo.com.
-- Fixed problem that incorrectly associated branches outside of a block with
-  branches inside the first block
-
-lcov:
-- Fixed problem that made lcov ignore --kernel-directory parameters when
-  specifying --initial. Reported by hjia@redhat.com.
-- Added --list-full-path option to prevent lcov from truncating paths in list
-  output
-- Added lcov_list_width and lcov_list_truncate_max directives to the
-  lcov configuration file to allow for list output customization
-- Improved list output
-
-COPYING:
-- Added license text to better comply with GPL recommendations
-
-
-Version 1.8
-===========
-
-gendesc:
-- Fixed problem with single word descriptions
-
-genhtml:
-- Added support for branch coverage measurements
-- Added --demangle-cpp option to convert C++ function names to human readable
-  format. Based on a patch by slava.semushin@gmail.com.
-- Improved color legend: legend display takes up less space in HTML output
-- Improved coverage rate limits: all coverage types use the same limits
-  unless specified otherwise
-- Fixed CRLF line breaks in source code when generating html output. Based
-  on patch by michael.knigge@set-software.de.
-- Fixed warning when $HOME is not set
-- Fixed problem with --baseline-file option. Reported by sixarm@gmail.com.
-  (Undefined subroutine &main::add_fnccounts called at genhtml line 4560.)
-- Fixed problem with --baseline-file option and files without function
-  coverage data (Can't use an undefined value as a HASH reference at genhtml
-  line 4441.)
-- Fixed short-name option ambiguities
-- Fixed --highlight option not showing line data from converted test data
-- Fixed warnings about undefined value used. Reported by nikita@zhuk.fi.
-- Fixed error when processing tracefiles without function data. Reported
-  by richard.corden@gmail.com (Can't use an undefined value as a HASH
-  reference at genhtml line 1506.)
-
-geninfo:
-- Added support for branch coverage measurements
-- Added support for exclusion markers: Users can exclude lines of code from
-  coverage reports by adding keywords to the source code.
-- Added --derive-func-data option
-- Added --debug option to better debug problems with graph files
-- Fixed CRLF line breaks in source code when generating tracefiles. Based on
-  patch by michael.knigge@set-software.de.
-- Fixed problems with unnamed source files
-- Fixed warning when $HOME is not set. Reported by acalando@free.fr.
-- Fixed errors when processing unnamed source files
-- Fixed help text typo
-- Fixed errors when processing incomplete function names in .bb files
-- Fixed filename prefix detection
-- Fixed problem with matching filename
-- Fixed problem when LANG is set to non-english locale. Reported by
-  benoit_belbezet@yahoo.fr.
-- Fixed short-name option ambiguities
-
-genpng:
-- Fixed runtime-warning
-
-lcov:
-- Added support for branch coverage measurements
-- Added support for the linux-2.6.31 upstream gcov kernel support
-- Added --from-package and --to-package options
-- Added --derive-func-data option
-- Added overall coverage result output for more operations
-- Improved output of lcov --list
-- Improved gcov-kernel handling
-- Fixed minor problem with --diff
-- Fixed double-counting of function data
-- Fixed warning when $HOME is not set. Reported by acalando@free.fr.
-- Fixed error when combining tracefiles without function data. Reported by
-  richard.corden@gmail.com. (Can't use an undefined value as a HASH reference
-  at lcov line 1341.)
-- Fixed help text typo
-- Fixed filename prefix detection
-- Fixed lcov ignoring information about converted test data
-
-README: 
-- Added note to mention required -lgcov switch during linking
-
- 
-Version 1.7:
-============
-
-gendesc:
-- Updated error and warning messages
-- Updated man page
-
-genhtml:
-- Added function coverage data display patch by tomzo@nefkom.net (default is on)
-- Added --function-coverage to enable function coverage display
-- Added --no-function-coverage to disable function coverage display
-- Added sorting option in HTLM output (default is on)
-- Added --sort to enable sorting
-- Added --no-sort to disable sorting
-- Added --html-gzip to create gzip-compressed HTML output (patch by
-  dnozay@vmware.com)
-- Fixed problem when using --baseline-file on coverage data files that
-  contain data for files not found in the baseline file
-- Updated error and warning messages
-- Updated man page
-
-geninfo:
-- Added function coverage data collection patch by tomzo@nefkom.net
-- Added more verbose output when a "ERROR: reading string" error occurs
-  (patch by scott.heavner@philips.com)
-- Fixed geninfo not working with directory names containing spaces (reported
-  by jeffconnelly@users.sourceforge.net)
-- Fixed "ERROR: reading string" problem with gcc 4.1
-- Fixed problem with function names that contain non-alphanumerical characters
-- Fixed problem with gcc versions before 3.3
-- Updated error and warning messages
-- Updated man page
-
-genpng:
-- Updated error and warning messages
-- Updated man page
-
-lcov:
-- Added support for function coverage data for adding/diffing tracefiles
-- Added --no-recursion option to disable recursion into sub-directories
-  while scanning for gcov data files
-- Fixed lcov -z not working with directory names containing spaces (reported
-  by Jeff Connelly)
-- Updated error and warning messages
-- Updated man page
-
-lcov.spec:
-- Updated of description and title information
-
-lcovrc:
-- Added genhtml_function_hi_limit
-- Added genhtml_function_med_limit
-- Added genhtml_function_coverage
-- Added genhtml_sort
-- Updated man page
-
-Makefile:
-- Updated info text
-
-
-Version 1.6:
-============
-
-geninfo:
-- Added libtool compatibility patch by thomas@apestaart.org (default is on)
-- Added --compat-libtool option to enable libtool compatibility mode
-- Added --no-compat-libtool option to disable libtool compatibility mode
-- Changed default for line checksumming to off
-- Added --checksum option to enable line checksumming
-- Added --gcov-tool option
-- Added --ignore-errors option
-- Added --initial option to generate zero coverage from graph files
-- Removed automatic test name modification on s390
-- Added --checksum option
-- Updated man page
-
-lcov:
-- Added libtool compatibility patch by thomas@apestaart.org
-- Added --compat-libtool option to enable libtool compatibility mode
-- Added --no-compat-libtool option to disable libtool compatibility mode
-- Added --checksum option to enable line checksumming
-- Added --gcov-tool option
-- Added --ignore-errors option
-- Added --initial option to generate zero coverage from graph files
-- Updated help text
-- Updated man page
-- Fixed lcov not working when -k is specified more than once
-- Fixed lcov not deleting .gcda files when specifying -z and -d
-
-lcovrc:
-- Added geninfo_compat_libtool option
-- Added geninfo_checksum option
-- Removed geninfo_no_checksum option from example lcovrc
-- Updated man page
-
-README:
-- Added description of lcovrc file
-
-
-Version 1.5:
-============
-
-genhtml:
-- Added check for invalid characters in test names
-- Added --legend option
-- Added --html-prolog option
-- Added --html-epilog option
-- Added --html-extension option
-- Added warning when specifying --no-prefix and --prefix
-- Reworked help text to make it more readable
-
-geninfo:
-- Renamed 'sles9' compatibility mode to 'hammer' compatibility mode
-- Added support for mandrake gcc 3.3.2
-- Fixed bbg file reading in hammer compatibility mode
-- Added check for invalid characters in test names
-- Added --base-directory option
-
-lcov:
-- Added check for invalid characters in test names
-- Added --base-directory option
-
-
-Version 1.4:
-============
-
-All:
-- Added configuration file support
-
-genhtml:
-- Fixed help text message
-- Fixed handling of special characters in file- and directory names
-- Added description of --css-file option to man page
-
-geninfo:
-- Added support for GCOV file format as used by GCC 3.3.3 on SUSE SLES9
-- Fixed error text message
-- Added check to abort processing if no source code file is available
-- Added workaround for a problem where geninfo could not find source code
-  files for a C++ project
-- Fixed 'branch'-statement parsing for GCC>=3.3 .gcov files
-- Fixed exec count-statement parsing for GCC>=3.3 .gcov files
-- Fixed .gcno-file parser (some lines were not counted as being instrumented)
-
-lcov:
-- Modified path for temporary files from '.' to '/tmp'
-- Fixed comments
-- Removed unused function 'escape_shell'
-
-lcovrc:
-- Introduced sample configuration file
-
-Makefile:
-- Added rule to install configuration file
-- Fixed installation path for man pages
-
-
-Version 1.3:
-============
-
-All:
-- Added compatibility for gcc-3.4
-
-lcov:
-- Modified --diff function to better cope with ambiguous entries in patch files
-- Modified --capture option to use modprobe before insmod (needed for 2.6)
-- Added --path option required for --diff function
-
-
-Version 1.2:
-============
-
-All:
-- Added compatibility for gcc-3.3
-- Adjusted LCOV-URL (http://ltp.sourceforge.net/coverage/lcov.php)
-- Minor changes to whitespaces/line breaks/spelling
-- Modified call mechanism so that parameters for external commands are not
-  parsed by the shell mechanism anymore (no more problems with special
-  characters in paths/filenames)
-- Added checksumming mechanism: each tracefile now contains a checksum for
-  each instrumented line to detect incompatible data
-
-Makefile:
-- Added rule to build source RPM
-- Changed install path for executables (/usr/local/bin -> /usr/bin)
-
-lcov.spec:
-- Modified to support building source rpms
-
-updateversion.pl:
-- Modified to include update of release number in spec file
-
-genhtml:
-- Fixed bug which would not correctly associate data sets with an empty
-  test name (only necessary when using --show-details in genhtml)
-- Implemented new command line option '--nochecksum' to suppress generation
-  of checksums
-- Implemented new command line option '--highlight' which highlights lines of
-  code which were only covered in converted tracefiles (see '--diff' option of
-  lcov)
-
-geninfo:
-- Added workaround for a bug in gcov shipped with gcc-3.2 which aborts when
-  encountering empty .da files
-- Fixed geninfo so that it does not abort after encountering empty .bb files
-- Added function to collect branch coverage data
-- Added check for gcov tool
-- Added check for the '--preserve-paths' option of gcov; if available, this
-  will prevent losing .gcov files in some special cases (include files with
-  same name in different subdirectories)
-- Implemented new command line option '--follow' to control whether or not 
-  links should be followed while searching for .da files.
-- Implemented new command line option '--nochecksum' to suppress generation
-  of checksums
-
-lcov:
-- Fixed bug which would not correctly associate data sets with an empty
-  test name (only necessary when using --show-details in genhtml)
-- Cleaned up internal command line option check
-- Files are now processed in alphabetical order
-- Added message when reading tracefiles
-- Implemented new command line option '--nochecksum' to suppress generation
-  of checksums
-- Implemented new command line option '--diff' which allows converting
-  coverage data from an older source code version by using a diff file
-  to map line numbers
-- Implemented new command line option '--follow' to control whether or not 
-  links should be followed while searching for .da files.
-
-genpng:
-- Added support for the highlighting option of genhtml
-- Corrected tab to spaces conversion
-- Modified genpng to take number of spaces to use in place of tab as input
-  instead of replacement string
-  
-
-Version 1.1:
-============
-
-- Added CHANGES file
-- Added Makefile implementing the following targets:
-  * install    : install LCOV scripts and man pages
-  * uninstall  : revert previous installation
-  * dist       : create lcov.tar.gz file and lcov.rpm file
-  * clean      : clean up example directory, remove .tar and .rpm files
-- Added man pages for all scripts
-- Added example program to demonstrate the use of LCOV with a userspace
-  application
-- Implemented RPM build process
-- New directory structure:
-  * bin        : contains all executables
-  * example    : contains a userspace example for LCOV
-  * man        : contains man pages
-  * rpm        : contains files required for the RPM build process
-- LCOV-scripts are now in bin/
-- Removed .pl-extension from LCOV-script files
-- Renamed readme.txt to README
-
-README:
-- Adjusted mailing list address to ltp-coverage@lists.sourceforge.net
-- Fixed incorrect parameter '--output-filename' in example LCOV call
-- Removed tool descriptions and turned them into man pages
-- Installation instructions now refer to RPM and tarball
-
-descriptions.tests:
-- Fixed some spelling errors
-
-genhtml:
-- Fixed bug which resulted in an error when trying to combine .info files
-  containing data without a test name
-- Fixed bug which would not correctly handle data files in directories
-  with names containing some special characters ('+', etc.)
-- Added check for empty tracefiles to prevent division-by-zeros
-- Implemented new command line option --num-spaces / the number of spaces
-  which replace a tab in source code view is now user defined
-- Fixed tab expansion so that in source code view, a tab doesn't produce a
-  fixed number of spaces, but as many spaces as are needed to advance to the
-  next tab position
-- Output directory is now created if it doesn't exist
-- Renamed "overview page" to "directory view page"
-- HTML output pages are now titled "LCOV" instead of "GCOV"
-- Information messages are now printed to STDERR instead of STDOUT
-
-geninfo:
-- Fixed bug which would not allow .info files to be generated in directories
-  with names containing some special characters
-- Information messages are now printed to STDERR instead of STDOUT
-
-lcov:
-- Fixed bug which would cause lcov to fail when the tool is installed in
-  a path with a name containing some special characters
-- Implemented new command line option '--add-tracefile' which allows the
-  combination of data from several tracefiles
-- Implemented new command line option '--list' which lists the contents
-  of a tracefile
-- Implemented new command line option '--extract' which allows extracting
-  data for a particular set of files from a tracefile
-- Implemented new command line option '--remove' which allows removing
-  data for a particular set of files from a tracefile
-- Renamed '--reset' to '--zerocounters' to avoid a naming ambiguity with
-  '--remove'
-- Changed name of gcov kernel directory from /proc/gcov to a global constant
-  so that it may be changed easily when required in future versions
-- Information messages are now printed to STDERR instead of STDOUT
-
-
-Version 1.0 (2002-09-05):
-=========================
-
-- Initial version
-
diff --git a/third_party/lcov-1.9/Makefile b/third_party/lcov-1.9/Makefile
deleted file mode 100644
index 93fc419..0000000
--- a/third_party/lcov-1.9/Makefile
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# Makefile for LCOV
-#
-# Make targets:
-#   - install:   install LCOV tools and man pages on the system
-#   - uninstall: remove tools and man pages from the system
-#   - dist:      create files required for distribution, i.e. the lcov.tar.gz
-#                and the lcov.rpm file. Just make sure to adjust the VERSION
-#                and RELEASE variables below - both version and date strings
-#                will be updated in all necessary files.
-#   - clean:     remove all generated files
-#
-
-VERSION := 1.9
-RELEASE := 1
-
-CFG_DIR := $(PREFIX)/etc
-BIN_DIR := $(PREFIX)/usr/bin
-MAN_DIR := $(PREFIX)/usr/share/man
-TMP_DIR := /tmp/lcov-tmp.$(shell echo $$$$)
-FILES   := $(wildcard bin/*) $(wildcard man/*) README CHANGES Makefile \
-	   $(wildcard rpm/*) lcovrc
-
-.PHONY: all info clean install uninstall rpms
-
-all: info
-
-info:
-	@echo "Available make targets:"
-	@echo "  install   : install binaries and man pages in PREFIX (default /)"
-	@echo "  uninstall : delete binaries and man pages from PREFIX (default /)"
-	@echo "  dist      : create packages (RPM, tarball) ready for distribution"
-
-clean:
-	rm -f lcov-*.tar.gz
-	rm -f lcov-*.rpm
-	make -C example clean
-
-install:
-	bin/install.sh bin/lcov $(BIN_DIR)/lcov -m 755
-	bin/install.sh bin/genhtml $(BIN_DIR)/genhtml -m 755
-	bin/install.sh bin/geninfo $(BIN_DIR)/geninfo -m 755
-	bin/install.sh bin/genpng $(BIN_DIR)/genpng -m 755
-	bin/install.sh bin/gendesc $(BIN_DIR)/gendesc -m 755
-	bin/install.sh man/lcov.1 $(MAN_DIR)/man1/lcov.1 -m 644
-	bin/install.sh man/genhtml.1 $(MAN_DIR)/man1/genhtml.1 -m 644
-	bin/install.sh man/geninfo.1 $(MAN_DIR)/man1/geninfo.1 -m 644
-	bin/install.sh man/genpng.1 $(MAN_DIR)/man1/genpng.1 -m 644
-	bin/install.sh man/gendesc.1 $(MAN_DIR)/man1/gendesc.1 -m 644
-	bin/install.sh man/lcovrc.5 $(MAN_DIR)/man5/lcovrc.5 -m 644
-	bin/install.sh lcovrc $(CFG_DIR)/lcovrc -m 644
-
-uninstall:
-	bin/install.sh --uninstall bin/lcov $(BIN_DIR)/lcov
-	bin/install.sh --uninstall bin/genhtml $(BIN_DIR)/genhtml
-	bin/install.sh --uninstall bin/geninfo $(BIN_DIR)/geninfo
-	bin/install.sh --uninstall bin/genpng $(BIN_DIR)/genpng
-	bin/install.sh --uninstall bin/gendesc $(BIN_DIR)/gendesc
-	bin/install.sh --uninstall man/lcov.1 $(MAN_DIR)/man1/lcov.1
-	bin/install.sh --uninstall man/genhtml.1 $(MAN_DIR)/man1/genhtml.1
-	bin/install.sh --uninstall man/geninfo.1 $(MAN_DIR)/man1/geninfo.1
-	bin/install.sh --uninstall man/genpng.1 $(MAN_DIR)/man1/genpng.1
-	bin/install.sh --uninstall man/gendesc.1 $(MAN_DIR)/man1/gendesc.1
-	bin/install.sh --uninstall man/lcovrc.5 $(MAN_DIR)/man5/lcovrc.5
-	bin/install.sh --uninstall lcovrc $(CFG_DIR)/lcovrc
-
-dist: lcov-$(VERSION).tar.gz lcov-$(VERSION)-$(RELEASE).noarch.rpm \
-      lcov-$(VERSION)-$(RELEASE).src.rpm
-
-lcov-$(VERSION).tar.gz: $(FILES)
-	mkdir $(TMP_DIR)
-	mkdir $(TMP_DIR)/lcov-$(VERSION)
-	cp -r * $(TMP_DIR)/lcov-$(VERSION)
-	find $(TMP_DIR)/lcov-$(VERSION) -name CVS -type d | xargs rm -rf
-	make -C $(TMP_DIR)/lcov-$(VERSION) clean
-	bin/updateversion.pl $(TMP_DIR)/lcov-$(VERSION) $(VERSION) $(RELEASE)
-	cd $(TMP_DIR) ; \
-	tar cfz $(TMP_DIR)/lcov-$(VERSION).tar.gz lcov-$(VERSION)
-	mv $(TMP_DIR)/lcov-$(VERSION).tar.gz .
-	rm -rf $(TMP_DIR)
-
-lcov-$(VERSION)-$(RELEASE).noarch.rpm: rpms
-lcov-$(VERSION)-$(RELEASE).src.rpm: rpms
-
-rpms: lcov-$(VERSION).tar.gz
-	mkdir $(TMP_DIR)
-	mkdir $(TMP_DIR)/BUILD
-	mkdir $(TMP_DIR)/RPMS
-	mkdir $(TMP_DIR)/SOURCES
-	mkdir $(TMP_DIR)/SRPMS
-	cp lcov-$(VERSION).tar.gz $(TMP_DIR)/SOURCES
-	cd $(TMP_DIR)/BUILD ; \
-	tar xfz $(TMP_DIR)/SOURCES/lcov-$(VERSION).tar.gz \
-		lcov-$(VERSION)/rpm/lcov.spec
-	rpmbuild --define '_topdir $(TMP_DIR)' \
-		 -ba $(TMP_DIR)/BUILD/lcov-$(VERSION)/rpm/lcov.spec
-	mv $(TMP_DIR)/RPMS/noarch/lcov-$(VERSION)-$(RELEASE).noarch.rpm .
-	mv $(TMP_DIR)/SRPMS/lcov-$(VERSION)-$(RELEASE).src.rpm .
-	rm -rf $(TMP_DIR)
diff --git a/third_party/lcov-1.9/README b/third_party/lcov-1.9/README
deleted file mode 100644
index 6542162..0000000
--- a/third_party/lcov-1.9/README
+++ /dev/null
@@ -1,137 +0,0 @@
--------------------------------------------------
-- README file for the LTP GCOV extension (LCOV) -
-- Last changes: 2010-08-06                      -
--------------------------------------------------
-
-Description
------------
-  LCOV is an extension of GCOV, a GNU tool which provides information about
-  what parts of a program are actually executed (i.e. "covered") while running
-  a particular test case. The extension consists of a set of PERL scripts
-  which build on the textual GCOV output to implement the following enhanced
-  functionality:
-
-    * HTML based output: coverage rates are additionally indicated using bar
-      graphs and specific colors.
-
-    * Support for large projects: overview pages allow quick browsing of
-      coverage data by providing three levels of detail: directory view,
-      file view and source code view.
-
-  LCOV was initially designed to support Linux kernel coverage measurements,
-  but works as well for coverage measurements on standard user space
-  applications.
-
-
-Further README contents
------------------------
-  1. Included files
-  2. Installing LCOV
-  3. An example of how to access kernel coverage data
-  4. An example of how to access coverage data for a user space program
-  5. Questions and Comments
-
-
-
-1. Important files
-------------------
-  README             - This README file
-  CHANGES            - List of changes between releases
-  bin/lcov           - Tool for capturing LCOV coverage data
-  bin/genhtml        - Tool for creating HTML output from LCOV data
-  bin/gendesc        - Tool for creating description files as used by genhtml
-  bin/geninfo        - Internal tool (creates LCOV data files)
-  bin/genpng         - Internal tool (creates png overviews of source files)
-  bin/install.sh     - Internal tool (takes care of un-/installing)
-  descriptions.tests - Test descriptions for the LTP suite, use with gendesc
-  man                - Directory containing man pages for included tools
-  example            - Directory containing an example to demonstrate LCOV
-  lcovrc             - LCOV configuration file
-  Makefile           - Makefile providing 'install' and 'uninstall' targets
-
-
-2. Installing LCOV
-------------------
-The LCOV package is available as either RPM or tarball from:
-     
-  http://ltp.sourceforge.net/coverage/lcov.php
-
-To install the tarball, unpack it to a directory and run:
-
-  make install
-
-Use anonymous CVS for the most recent (but possibly unstable) version:
-
-  cvs -d:pserver:anonymous@ltp.cvs.sourceforge.net:/cvsroot/ltp login
-
-(simply press the ENTER key when asked for a password)
-
-  cvs -z3 -d:pserver:anonymous@ltp.cvs.sourceforge.net:/cvsroot/ltp export -D now utils
-
-Change to the utils/analysis/lcov directory and type:
-
-  make install
-
-
-3. An example of how to access kernel coverage data
----------------------------------------------------
-Requirements: get and install the gcov-kernel package from
-
-  http://sourceforge.net/projects/ltp
-
-Copy the resulting gcov kernel module file to either the system wide modules
-directory or the same directory as the PERL scripts. As root, do the following:
-
-  a) Resetting counters
-
-     lcov --zerocounters
-
-  b) Capturing the current coverage state to a file
-
-     lcov --capture --output-file kernel.info
-
-  c) Getting HTML output
-
-     genhtml kernel.info
-
-Point the web browser of your choice to the resulting index.html file.
-
-
-4. An example of how to access coverage data for a user space program
----------------------------------------------------------------------
-Requirements: compile the program in question using GCC with the options
--fprofile-arcs and -ftest-coverage. During linking, make sure to specify
--lgcov or -coverage.
-
-Assuming the compile directory is called "appdir", do the following:
-
-  a) Resetting counters
-
-     lcov --directory appdir --zerocounters
-
-  b) Capturing the current coverage state to a file (works only after the
-     application has been started and stopped at least once)
-
-     lcov --directory appdir --capture --output-file app.info
-
-  c) Getting HTML output
-
-     genhtml app.info
-
-Point the web browser of your choice to the resulting index.html file.
-
-Please note that independently of where the application is installed or
-from which directory it is run, the --directory statement needs to
-point to the directory in which the application was compiled.
-
-For further information on the gcc profiling mechanism, please also
-consult the gcov man page.
-
-
-5. Questions and comments
--------------------------
-See the included man pages for more information on how to use the LCOV tools.
-
-Please email further questions or comments regarding this tool to the
-LTP Mailing list at ltp-coverage@lists.sourceforge.net  
-
diff --git a/third_party/lcov-1.9/README.chromium b/third_party/lcov-1.9/README.chromium
deleted file mode 100644
index d0daef78..0000000
--- a/third_party/lcov-1.9/README.chromium
+++ /dev/null
@@ -1,14 +0,0 @@
-Name: LCOV - the LTP GCOV extension
-Short Name: lcov
-URL: http://ltp.sourceforge.net/coverage/lcov.php
-Version: 1.9
-License: GPLv2 or later
-License File: COPYING
-Security Critical: no
-Local Modifications: None
-Description:
-This directory contains a stock lcov-1.9. The existing lcov is v1.6 and need
-to stay here to prevent breakages of existing coverage schemes.
-
-N.B.: This code will not be shipped with Chrome.
-      It is only part of the build/test infrastructure.
diff --git a/third_party/lcov-1.9/bin/gendesc b/third_party/lcov-1.9/bin/gendesc
deleted file mode 100755
index 522ef69..0000000
--- a/third_party/lcov-1.9/bin/gendesc
+++ /dev/null
@@ -1,226 +0,0 @@
-#!/usr/bin/perl -w
-#
-#   Copyright (c) International Business Machines  Corp., 2002
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.                 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-#
-# gendesc
-#
-#   This script creates a description file as understood by genhtml.
-#   Input file format:
-#
-#   For each test case:
-#     <test name><optional whitespace>
-#     <at least one whitespace character (blank/tab)><test description>
-#   
-#   Actual description may consist of several lines. By default, output is
-#   written to stdout. Test names consist of alphanumeric characters
-#   including _ and -.
-#
-#
-# History:
-#   2002-09-02: created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-#
-
-use strict;
-use File::Basename; 
-use Getopt::Long;
-
-
-# Constants
-our $lcov_version	= 'LCOV version 1.9';
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
-our $tool_name		= basename($0);
-
-
-# Prototypes
-sub print_usage(*);
-sub gen_desc();
-sub warn_handler($);
-sub die_handler($);
-
-
-# Global variables
-our $help;
-our $version;
-our $output_filename;
-our $input_filename;
-
-
-#
-# Code entry point
-#
-
-$SIG{__WARN__} = \&warn_handler;
-$SIG{__DIE__} = \&die_handler;
-
-# Prettify version string
-$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
-
-# Parse command line options
-if (!GetOptions("output-filename=s" => \$output_filename,
-		"version" =>\$version,
-		"help|?" => \$help
-		))
-{
-	print(STDERR "Use $tool_name --help to get usage information\n");
-	exit(1);
-}
-
-$input_filename = $ARGV[0];
-
-# Check for help option
-if ($help)
-{
-	print_usage(*STDOUT);
-	exit(0);
-}
-
-# Check for version option
-if ($version)
-{
-	print("$tool_name: $lcov_version\n");
-	exit(0);
-}
-
-
-# Check for input filename
-if (!$input_filename)
-{
-	die("No input filename specified\n".
-	    "Use $tool_name --help to get usage information\n");
-}
-
-# Do something
-gen_desc();
-
-
-#
-# print_usage(handle)
-#
-# Write out command line usage information to given filehandle.
-#
-
-sub print_usage(*)
-{
-	local *HANDLE = $_[0];
-
-	print(HANDLE <<END_OF_USAGE)
-Usage: $tool_name [OPTIONS] INPUTFILE
-
-Convert a test case description file into a format as understood by genhtml.
-
-  -h, --help                        Print this help, then exit
-  -v, --version                     Print version number, then exit
-  -o, --output-filename FILENAME    Write description to FILENAME
-
-For more information see: $lcov_url
-END_OF_USAGE
-	;
-}
-
-
-#
-# gen_desc()
-#
-# Read text file INPUT_FILENAME and convert the contained description to a
-# format as understood by genhtml, i.e.
-#
-#    TN:<test name>
-#    TD:<test description>
-#
-# If defined, write output to OUTPUT_FILENAME, otherwise to stdout.
-#
-# Die on error.
-#
-
-sub gen_desc()
-{
-	local *INPUT_HANDLE;
-	local *OUTPUT_HANDLE;
-	my $empty_line = "ignore";
-
-	open(INPUT_HANDLE, $input_filename)
-		or die("ERROR: cannot open $input_filename!\n");
-
-	# Open output file for writing
-	if ($output_filename)
-	{
-		open(OUTPUT_HANDLE, ">$output_filename")
-			or die("ERROR: cannot create $output_filename!\n");
-	}
-	else
-	{
-		*OUTPUT_HANDLE = *STDOUT;
-	}
-
-	# Process all lines in input file
-	while (<INPUT_HANDLE>)
-	{
-		chomp($_);
-
-		if (/^(\w[\w-]*)(\s*)$/)
-		{
-			# Matched test name
-			# Name starts with alphanum or _, continues with
-			# alphanum, _ or -
-			print(OUTPUT_HANDLE "TN: $1\n");
-			$empty_line = "ignore";
-		}
-		elsif (/^(\s+)(\S.*?)\s*$/)
-		{
-			# Matched test description
-			if ($empty_line eq "insert")
-			{
-				# Write preserved empty line
-				print(OUTPUT_HANDLE "TD: \n");
-			}
-			print(OUTPUT_HANDLE "TD: $2\n");
-			$empty_line = "observe";
-		}
-		elsif (/^\s*$/)
-		{
-			# Matched empty line to preserve paragraph separation
-			# inside description text
-			if ($empty_line eq "observe")
-			{
-				$empty_line = "insert";
-			}
-		}
-	}
-
-	# Close output file if defined
-	if ($output_filename)
-	{
-		close(OUTPUT_HANDLE);
-	}
-
-	close(INPUT_HANDLE);
-}
-
-sub warn_handler($)
-{
-	my ($msg) = @_;
-
-	warn("$tool_name: $msg");
-}
-
-sub die_handler($)
-{
-	my ($msg) = @_;
-
-	die("$tool_name: $msg");
-}
diff --git a/third_party/lcov-1.9/bin/genhtml b/third_party/lcov-1.9/bin/genhtml
deleted file mode 100755
index d74063a..0000000
--- a/third_party/lcov-1.9/bin/genhtml
+++ /dev/null
@@ -1,5648 +0,0 @@
-#!/usr/bin/perl -w
-#
-#   Copyright (c) International Business Machines  Corp., 2002,2010
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details. 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-#
-# genhtml
-#
-#   This script generates HTML output from .info files as created by the
-#   geninfo script. Call it with --help and refer to the genhtml man page
-#   to get information on usage and available options.
-#
-#
-# History:
-#   2002-08-23 created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-#                         IBM Lab Boeblingen
-#        based on code by Manoj Iyer <manjo@mail.utexas.edu> and
-#                         Megan Bock <mbock@us.ibm.com>
-#                         IBM Austin
-#   2002-08-27 / Peter Oberparleiter: implemented frame view
-#   2002-08-29 / Peter Oberparleiter: implemented test description filtering
-#                so that by default only descriptions for test cases which
-#                actually hit some source lines are kept
-#   2002-09-05 / Peter Oberparleiter: implemented --no-sourceview
-#   2002-09-05 / Mike Kobler: One of my source file paths includes a "+" in
-#                the directory name.  I found that genhtml.pl died when it
-#                encountered it. I was able to fix the problem by modifying
-#                the string with the escape character before parsing it.
-#   2002-10-26 / Peter Oberparleiter: implemented --num-spaces
-#   2003-04-07 / Peter Oberparleiter: fixed bug which resulted in an error
-#                when trying to combine .info files containing data without
-#                a test name
-#   2003-04-10 / Peter Oberparleiter: extended fix by Mike to also cover
-#                other special characters
-#   2003-04-30 / Peter Oberparleiter: made info write to STDERR, not STDOUT
-#   2003-07-10 / Peter Oberparleiter: added line checksum support
-#   2004-08-09 / Peter Oberparleiter: added configuration file support
-#   2005-03-04 / Cal Pierog: added legend to HTML output, fixed coloring of
-#                "good coverage" background
-#   2006-03-18 / Marcus Boerger: added --custom-intro, --custom-outro and
-#                overwrite --no-prefix if --prefix is present
-#   2006-03-20 / Peter Oberparleiter: changes to custom_* function (rename
-#                to html_prolog/_epilog, minor modifications to implementation),
-#                changed prefix/noprefix handling to be consistent with current
-#                logic
-#   2006-03-20 / Peter Oberparleiter: added --html-extension option
-#   2008-07-14 / Tom Zoerner: added --function-coverage command line option;
-#                added function table to source file page
-#   2008-08-13 / Peter Oberparleiter: modified function coverage
-#                implementation (now enabled per default),
-#                introduced sorting option (enabled per default)
-#
-
-use strict;
-use File::Basename; 
-use Getopt::Long;
-use Digest::MD5 qw(md5_base64);
-
-
-# Global constants
-our $title		= "LCOV - code coverage report";
-our $lcov_version	= 'LCOV version 1.9';
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
-our $tool_name		= basename($0);
-
-# Specify coverage rate limits (in %) for classifying file entries
-# HI:   $hi_limit <= rate <= 100          graph color: green
-# MED: $med_limit <= rate <  $hi_limit    graph color: orange
-# LO:          0  <= rate <  $med_limit   graph color: red
-
-# For line coverage/all coverage types if not specified
-our $hi_limit = 90;
-our $med_limit = 75;
-
-# For function coverage
-our $fn_hi_limit;
-our $fn_med_limit;
-
-# For branch coverage
-our $br_hi_limit;
-our $br_med_limit;
-
-# Width of overview image
-our $overview_width = 80;
-
-# Resolution of overview navigation: this number specifies the maximum
-# difference in lines between the position a user selected from the overview
-# and the position the source code window is scrolled to.
-our $nav_resolution = 4;
-
-# Clicking a line in the overview image should show the source code view at
-# a position a bit further up so that the requested line is not the first
-# line in the window. This number specifies that offset in lines.
-our $nav_offset = 10;
-
-# Clicking on a function name should show the source code at a position a
-# few lines before the first line of code of that function. This number
-# specifies that offset in lines.
-our $func_offset = 2;
-
-our $overview_title = "top level";
-
-# Width for line coverage information in the source code view
-our $line_field_width = 12;
-
-# Width for branch coverage information in the source code view
-our $br_field_width = 16;
-
-# Internal Constants
-
-# Header types
-our $HDR_DIR		= 0;
-our $HDR_FILE		= 1;
-our $HDR_SOURCE		= 2;
-our $HDR_TESTDESC	= 3;
-our $HDR_FUNC		= 4;
-
-# Sort types
-our $SORT_FILE		= 0;
-our $SORT_LINE		= 1;
-our $SORT_FUNC		= 2;
-our $SORT_BRANCH	= 3;
-
-# Fileview heading types
-our $HEAD_NO_DETAIL	= 1;
-our $HEAD_DETAIL_HIDDEN	= 2;
-our $HEAD_DETAIL_SHOWN	= 3;
-
-# Offsets for storing branch coverage data in vectors
-our $BR_BLOCK		= 0;
-our $BR_BRANCH		= 1;
-our $BR_TAKEN		= 2;
-our $BR_VEC_ENTRIES	= 3;
-our $BR_VEC_WIDTH	= 32;
-
-# Additional offsets used when converting branch coverage data to HTML
-our $BR_LEN	= 3;
-our $BR_OPEN	= 4;
-our $BR_CLOSE	= 5;
-
-# Branch data combination types
-our $BR_SUB = 0;
-our $BR_ADD = 1;
-
-# Data related prototypes
-sub print_usage(*);
-sub gen_html();
-sub html_create($$);
-sub process_dir($);
-sub process_file($$$);
-sub info(@);
-sub read_info_file($);
-sub get_info_entry($);
-sub set_info_entry($$$$$$$$$;$$$$$$);
-sub get_prefix(@);
-sub shorten_prefix($);
-sub get_dir_list(@);
-sub get_relative_base_path($);
-sub read_testfile($);
-sub get_date_string();
-sub create_sub_dir($);
-sub subtract_counts($$);
-sub add_counts($$);
-sub apply_baseline($$);
-sub remove_unused_descriptions();
-sub get_found_and_hit($);
-sub get_affecting_tests($$$);
-sub combine_info_files($$);
-sub merge_checksums($$$);
-sub combine_info_entries($$$);
-sub apply_prefix($$);
-sub system_no_output($@);
-sub read_config($);
-sub apply_config($);
-sub get_html_prolog($);
-sub get_html_epilog($);
-sub write_dir_page($$$$$$$$$$$$$$$$$);
-sub classify_rate($$$$);
-sub br_taken_add($$);
-sub br_taken_sub($$);
-sub br_ivec_len($);
-sub br_ivec_get($$);
-sub br_ivec_push($$$$);
-sub combine_brcount($$$);
-sub get_br_found_and_hit($);
-sub warn_handler($);
-sub die_handler($);
-
-
-# HTML related prototypes
-sub escape_html($);
-sub get_bar_graph_code($$$);
-
-sub write_png_files();
-sub write_htaccess_file();
-sub write_css_file();
-sub write_description_file($$$$$$$);
-sub write_function_table(*$$$$$$$$$$);
-
-sub write_html(*$);
-sub write_html_prolog(*$$);
-sub write_html_epilog(*$;$);
-
-sub write_header(*$$$$$$$$$$);
-sub write_header_prolog(*$);
-sub write_header_line(*@);
-sub write_header_epilog(*$);
-
-sub write_file_table(*$$$$$$$);
-sub write_file_table_prolog(*$@);
-sub write_file_table_entry(*$$$@);
-sub write_file_table_detail_entry(*$@);
-sub write_file_table_epilog(*);
-
-sub write_test_table_prolog(*$);
-sub write_test_table_entry(*$$);
-sub write_test_table_epilog(*);
-
-sub write_source($$$$$$$);
-sub write_source_prolog(*);
-sub write_source_line(*$$$$$$);
-sub write_source_epilog(*);
-
-sub write_frameset(*$$$);
-sub write_overview_line(*$$$);
-sub write_overview(*$$$$);
-
-# External prototype (defined in genpng)
-sub gen_png($$$@);
-
-
-# Global variables & initialization
-our %info_data;		# Hash containing all data from .info file
-our $dir_prefix;	# Prefix to remove from all sub directories
-our %test_description;	# Hash containing test descriptions if available
-our $date = get_date_string();
-
-our @info_filenames;	# List of .info files to use as data source
-our $test_title;	# Title for output as written to each page header
-our $output_directory;	# Name of directory in which to store output
-our $base_filename;	# Optional name of file containing baseline data
-our $desc_filename;	# Name of file containing test descriptions
-our $css_filename;	# Optional name of external stylesheet file to use
-our $quiet;		# If set, suppress information messages
-our $help;		# Help option flag
-our $version;		# Version option flag
-our $show_details;	# If set, generate detailed directory view
-our $no_prefix;		# If set, do not remove filename prefix
-our $func_coverage = 1;	# If set, generate function coverage statistics
-our $no_func_coverage;	# Disable func_coverage
-our $br_coverage = 1;	# If set, generate branch coverage statistics
-our $no_br_coverage;	# Disable br_coverage
-our $sort = 1;		# If set, provide directory listings with sorted entries
-our $no_sort;		# Disable sort
-our $frames;		# If set, use frames for source code view
-our $keep_descriptions;	# If set, do not remove unused test case descriptions
-our $no_sourceview;	# If set, do not create a source code view for each file
-our $highlight;		# If set, highlight lines covered by converted data only
-our $legend;		# If set, include legend in output
-our $tab_size = 8;	# Number of spaces to use in place of tab
-our $config;		# Configuration file contents
-our $html_prolog_file;	# Custom HTML prolog file (up to and including <body>)
-our $html_epilog_file;	# Custom HTML epilog file (from </body> onwards)
-our $html_prolog;	# Actual HTML prolog
-our $html_epilog;	# Actual HTML epilog
-our $html_ext = "html";	# Extension for generated HTML files
-our $html_gzip = 0;	# Compress with gzip
-our $demangle_cpp = 0;	# Demangle C++ function names
-our @fileview_sortlist;
-our @fileview_sortname = ("", "-sort-l", "-sort-f", "-sort-b");
-our @funcview_sortlist;
-our @rate_name = ("Lo", "Med", "Hi");
-our @rate_png = ("ruby.png", "amber.png", "emerald.png");
-
-our $cwd = `pwd`;	# Current working directory
-chomp($cwd);
-our $tool_dir = dirname($0);	# Directory where genhtml tool is installed
-
-
-#
-# Code entry point
-#
-
-$SIG{__WARN__} = \&warn_handler;
-$SIG{__DIE__} = \&die_handler;
-
-# Prettify version string
-$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
-
-# Add current working directory if $tool_dir is not already an absolute path
-if (! ($tool_dir =~ /^\/(.*)$/))
-{
-	$tool_dir = "$cwd/$tool_dir";
-}
-
-# Read configuration file if available
-if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
-{
-	$config = read_config($ENV{"HOME"}."/.lcovrc");
-}
-elsif (-r "/etc/lcovrc")
-{
-	$config = read_config("/etc/lcovrc");
-}
-
-if ($config)
-{
-	# Copy configuration file values to variables
-	apply_config({
-		"genhtml_css_file"		=> \$css_filename,
-		"genhtml_hi_limit"		=> \$hi_limit,
-		"genhtml_med_limit"		=> \$med_limit,
-		"genhtml_line_field_width"	=> \$line_field_width,
-		"genhtml_overview_width"	=> \$overview_width,
-		"genhtml_nav_resolution"	=> \$nav_resolution,
-		"genhtml_nav_offset"		=> \$nav_offset,
-		"genhtml_keep_descriptions"	=> \$keep_descriptions,
-		"genhtml_no_prefix"		=> \$no_prefix,
-		"genhtml_no_source"		=> \$no_sourceview,
-		"genhtml_num_spaces"		=> \$tab_size,
-		"genhtml_highlight"		=> \$highlight,
-		"genhtml_legend"		=> \$legend,
-		"genhtml_html_prolog"		=> \$html_prolog_file,
-		"genhtml_html_epilog"		=> \$html_epilog_file,
-		"genhtml_html_extension"	=> \$html_ext,
-		"genhtml_html_gzip"		=> \$html_gzip,
-		"genhtml_function_hi_limit"	=> \$fn_hi_limit,
-		"genhtml_function_med_limit"	=> \$fn_med_limit,
-		"genhtml_function_coverage"	=> \$func_coverage,
-		"genhtml_branch_hi_limit"	=> \$br_hi_limit,
-		"genhtml_branch_med_limit"	=> \$br_med_limit,
-		"genhtml_branch_coverage"	=> \$br_coverage,
-		"genhtml_branch_field_width"	=> \$br_field_width,
-		"genhtml_sort"			=> \$sort,
-		});
-}
-
-# Copy limit values if not specified
-$fn_hi_limit	= $hi_limit if (!defined($fn_hi_limit));
-$fn_med_limit	= $med_limit if (!defined($fn_med_limit));
-$br_hi_limit	= $hi_limit if (!defined($br_hi_limit));
-$br_med_limit	= $med_limit if (!defined($br_med_limit));
-
-# Parse command line options
-if (!GetOptions("output-directory|o=s"	=> \$output_directory,
-		"title|t=s"		=> \$test_title,
-		"description-file|d=s"	=> \$desc_filename,
-		"keep-descriptions|k"	=> \$keep_descriptions,
-		"css-file|c=s"		=> \$css_filename,
-		"baseline-file|b=s"	=> \$base_filename,
-		"prefix|p=s"		=> \$dir_prefix,
-		"num-spaces=i"		=> \$tab_size,
-		"no-prefix"		=> \$no_prefix,
-		"no-sourceview"		=> \$no_sourceview,
-		"show-details|s"	=> \$show_details,
-		"frames|f"		=> \$frames,
-		"highlight"		=> \$highlight,
-		"legend"		=> \$legend,
-		"quiet|q"		=> \$quiet,
-		"help|h|?"		=> \$help,
-		"version|v"		=> \$version,
-		"html-prolog=s"		=> \$html_prolog_file,
-		"html-epilog=s"		=> \$html_epilog_file,
-		"html-extension=s"	=> \$html_ext,
-		"html-gzip"		=> \$html_gzip,
-		"function-coverage"	=> \$func_coverage,
-		"no-function-coverage"	=> \$no_func_coverage,
-		"branch-coverage"	=> \$br_coverage,
-		"no-branch-coverage"	=> \$no_br_coverage,
-		"sort"			=> \$sort,
-		"no-sort"		=> \$no_sort,
-		"demangle-cpp"		=> \$demangle_cpp,
-		))
-{
-	print(STDERR "Use $tool_name --help to get usage information\n");
-	exit(1);
-} else {
-	# Merge options
-	if ($no_func_coverage) {
-		$func_coverage = 0;
-	}
-	if ($no_br_coverage) {
-		$br_coverage = 0;
-	}
-
-	# Merge sort options
-	if ($no_sort) {
-		$sort = 0;
-	}
-}
-
-@info_filenames = @ARGV;
-
-# Check for help option
-if ($help)
-{
-	print_usage(*STDOUT);
-	exit(0);
-}
-
-# Check for version option
-if ($version)
-{
-	print("$tool_name: $lcov_version\n");
-	exit(0);
-}
-
-# Check for info filename
-if (!@info_filenames)
-{
-	die("No filename specified\n".
-	    "Use $tool_name --help to get usage information\n");
-}
-
-# Generate a title if none is specified
-if (!$test_title)
-{
-	if (scalar(@info_filenames) == 1)
-	{
-		# Only one filename specified, use it as title
-		$test_title = basename($info_filenames[0]);
-	}
-	else
-	{
-		# More than one filename specified, used default title
-		$test_title = "unnamed";
-	}
-}
-
-# Make sure css_filename is an absolute path (in case we're changing
-# directories)
-if ($css_filename)
-{
-	if (!($css_filename =~ /^\/(.*)$/))
-	{
-		$css_filename = $cwd."/".$css_filename;
-	}
-}
-
-# Make sure tab_size is within valid range
-if ($tab_size < 1)
-{
-	print(STDERR "ERROR: invalid number of spaces specified: ".
-		     "$tab_size!\n");
-	exit(1);
-}
-
-# Get HTML prolog and epilog
-$html_prolog = get_html_prolog($html_prolog_file);
-$html_epilog = get_html_epilog($html_epilog_file);
-
-# Issue a warning if --no-sourceview is enabled together with --frames
-if ($no_sourceview && defined($frames))
-{
-	warn("WARNING: option --frames disabled because --no-sourceview ".
-	     "was specified!\n");
-	$frames = undef;
-}
-
-# Issue a warning if --no-prefix is enabled together with --prefix
-if ($no_prefix && defined($dir_prefix))
-{
-	warn("WARNING: option --prefix disabled because --no-prefix was ".
-	     "specified!\n");
-	$dir_prefix = undef;
-}
-
-@fileview_sortlist = ($SORT_FILE);
-@funcview_sortlist = ($SORT_FILE);
-
-if ($sort) {
-	push(@fileview_sortlist, $SORT_LINE);
-	push(@fileview_sortlist, $SORT_FUNC) if ($func_coverage);
-	push(@fileview_sortlist, $SORT_BRANCH) if ($br_coverage);
-	push(@funcview_sortlist, $SORT_LINE);
-}
-
-if ($frames)
-{
-	# Include genpng code needed for overview image generation
-	do("$tool_dir/genpng");
-}
-
-# Ensure that the c++filt tool is available when using --demangle-cpp
-if ($demangle_cpp)
-{
-	if (system_no_output(3, "c++filt", "--version")) {
-		die("ERROR: could not find c++filt tool needed for ".
-		    "--demangle-cpp\n");
-	}
-}
-
-# Make sure output_directory exists, create it if necessary
-if ($output_directory)
-{
-	stat($output_directory);
-
-	if (! -e _)
-	{
-		create_sub_dir($output_directory);
-	}
-}
-
-# Do something
-gen_html();
-
-exit(0);
-
-
-
-#
-# print_usage(handle)
-#
-# Print usage information.
-#
-
-sub print_usage(*)
-{
-	local *HANDLE = $_[0];
-
-	print(HANDLE <<END_OF_USAGE);
-Usage: $tool_name [OPTIONS] INFOFILE(S)
-
-Create HTML output for coverage data found in INFOFILE. Note that INFOFILE
-may also be a list of filenames.
-
-Misc:
-  -h, --help                        Print this help, then exit
-  -v, --version                     Print version number, then exit
-  -q, --quiet                       Do not print progress messages
-
-Operation:
-  -o, --output-directory OUTDIR     Write HTML output to OUTDIR
-  -s, --show-details                Generate detailed directory view
-  -d, --description-file DESCFILE   Read test case descriptions from DESCFILE
-  -k, --keep-descriptions           Do not remove unused test descriptions
-  -b, --baseline-file BASEFILE      Use BASEFILE as baseline file
-  -p, --prefix PREFIX               Remove PREFIX from all directory names
-      --no-prefix                   Do not remove prefix from directory names
-      --(no-)function-coverage      Enable (disable) function coverage display
-      --(no-)branch-coverage        Enable (disable) branch coverage display
-
-HTML output:
-  -f, --frames                      Use HTML frames for source code view
-  -t, --title TITLE                 Display TITLE in header of all pages
-  -c, --css-file CSSFILE            Use external style sheet file CSSFILE
-      --no-source                   Do not create source code view
-      --num-spaces NUM              Replace tabs with NUM spaces in source view
-      --highlight                   Highlight lines with converted-only data
-      --legend                      Include color legend in HTML output
-      --html-prolog FILE            Use FILE as HTML prolog for generated pages
-      --html-epilog FILE            Use FILE as HTML epilog for generated pages
-      --html-extension EXT          Use EXT as filename extension for pages
-      --html-gzip                   Use gzip to compress HTML
-      --(no-)sort                   Enable (disable) sorted coverage views
-      --demangle-cpp                Demangle C++ function names
-
-For more information see: $lcov_url
-END_OF_USAGE
-	;
-}
-
-
-#
-# get_rate(found, hit)
-#
-# Return a relative value for the specified found&hit values
-# which is used for sorting the corresponding entries in a
-# file list.
-#
-
-sub get_rate($$)
-{
-	my ($found, $hit) = @_;
-
-	if ($found == 0) {
-		return 10000;
-	}
-	return int($hit * 1000 / $found) * 10 + 2 - (1 / $found);
-}
-
-
-#
-# get_overall_line(found, hit, name_singular, name_plural)
-#
-# Return a string containing overall information for the specified
-# found/hit data.
-#
-
-sub get_overall_line($$$$)
-{
-	my ($found, $hit, $name_sn, $name_pl) = @_;
-	my $name;
-
-	return "no data found" if (!defined($found) || $found == 0);
-	$name = ($found == 1) ? $name_sn : $name_pl;
-	return sprintf("%.1f%% (%d of %d %s)", $hit * 100 / $found, $hit,
-		       $found, $name);
-}
-
-
-#
-# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
-#                    br_found, br_hit)
-#
-# Print overall coverage rates for the specified coverage types.
-#
-
-sub print_overall_rate($$$$$$$$$)
-{
-	my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
-	    $br_do, $br_found, $br_hit) = @_;
-
-	info("Overall coverage rate:\n");
-	info("  lines......: %s\n",
-	     get_overall_line($ln_found, $ln_hit, "line", "lines"))
-		if ($ln_do);
-	info("  functions..: %s\n",
-	     get_overall_line($fn_found, $fn_hit, "function", "functions"))
-		if ($fn_do);
-	info("  branches...: %s\n",
-	     get_overall_line($br_found, $br_hit, "branch", "branches"))
-		if ($br_do);
-}
-
-
-#
-# gen_html()
-#
-# Generate a set of HTML pages from contents of .info file INFO_FILENAME.
-# Files will be written to the current directory. If provided, test case
-# descriptions will be read from .tests file TEST_FILENAME and included
-# in ouput.
-#
-# Die on error.
-#
-
-sub gen_html()
-{
-	local *HTML_HANDLE;
-	my %overview;
-	my %base_data;
-	my $lines_found;
-	my $lines_hit;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-	my $overall_found = 0;
-	my $overall_hit = 0;
-	my $total_fn_found = 0;
-	my $total_fn_hit = 0;
-	my $total_br_found = 0;
-	my $total_br_hit = 0;
-	my $dir_name;
-	my $link_name;
-	my @dir_list;
-	my %new_info;
-
-	# Read in all specified .info files
-	foreach (@info_filenames)
-	{
-		%new_info = %{read_info_file($_)};
-
-		# Combine %new_info with %info_data
-		%info_data = %{combine_info_files(\%info_data, \%new_info)};
-	}
-
-	info("Found %d entries.\n", scalar(keys(%info_data)));
-
-	# Read and apply baseline data if specified
-	if ($base_filename)
-	{
-		# Read baseline file
-		info("Reading baseline file $base_filename\n");
-		%base_data = %{read_info_file($base_filename)};
-		info("Found %d entries.\n", scalar(keys(%base_data)));
-
-		# Apply baseline
-		info("Subtracting baseline data.\n");
-		%info_data = %{apply_baseline(\%info_data, \%base_data)};
-	}
-
-	@dir_list = get_dir_list(keys(%info_data));
-
-	if ($no_prefix)
-	{
-		# User requested that we leave filenames alone
-		info("User asked not to remove filename prefix\n");
-	}
-	elsif (!defined($dir_prefix))
-	{
-		# Get prefix common to most directories in list
-		$dir_prefix = get_prefix(@dir_list);
-
-		if ($dir_prefix)
-		{
-			info("Found common filename prefix \"$dir_prefix\"\n");
-		}
-		else
-		{
-			info("No common filename prefix found!\n");
-			$no_prefix=1;
-		}
-	}
-	else
-	{
-		info("Using user-specified filename prefix \"".
-		     "$dir_prefix\"\n");
-	}
-
-	# Read in test description file if specified
-	if ($desc_filename)
-	{
-		info("Reading test description file $desc_filename\n");
-		%test_description = %{read_testfile($desc_filename)};
-
-		# Remove test descriptions which are not referenced
-		# from %info_data if user didn't tell us otherwise
-		if (!$keep_descriptions)
-		{
-			remove_unused_descriptions();
-		}
-	}
-
-	# Change to output directory if specified
-	if ($output_directory)
-	{
-		chdir($output_directory)
-			or die("ERROR: cannot change to directory ".
-			"$output_directory!\n");
-	}
-
-	info("Writing .css and .png files.\n");
-	write_css_file();
-	write_png_files();
-
-	if ($html_gzip)
-	{
-		info("Writing .htaccess file.\n");
-		write_htaccess_file();
-	}
-
-	info("Generating output.\n");
-
-	# Process each subdirectory and collect overview information
-	foreach $dir_name (@dir_list)
-	{
-		($lines_found, $lines_hit, $fn_found, $fn_hit,
-		 $br_found, $br_hit)
-			= process_dir($dir_name);
-
-		# Remove prefix if applicable
-		if (!$no_prefix && $dir_prefix)
-		{
-			# Match directory names beginning with $dir_prefix
-			$dir_name = apply_prefix($dir_name, $dir_prefix);
-		}
-
-		# Generate name for directory overview HTML page
-		if ($dir_name =~ /^\/(.*)$/)
-		{
-			$link_name = substr($dir_name, 1)."/index.$html_ext";
-		}
-		else
-		{
-			$link_name = $dir_name."/index.$html_ext";
-		}
-
-		$overview{$dir_name} = [$lines_found, $lines_hit, $fn_found,
-					$fn_hit, $br_found, $br_hit, $link_name,
-					get_rate($lines_found, $lines_hit),
-					get_rate($fn_found, $fn_hit),
-					get_rate($br_found, $br_hit)];
-		$overall_found	+= $lines_found;
-		$overall_hit	+= $lines_hit;
-		$total_fn_found	+= $fn_found;
-		$total_fn_hit	+= $fn_hit;
-		$total_br_found	+= $br_found;
-		$total_br_hit	+= $br_hit;
-	}
-
-	# Generate overview page
-	info("Writing directory view page.\n");
-
-	# Create sorted pages
-	foreach (@fileview_sortlist) {
-		write_dir_page($fileview_sortname[$_], ".", "", $test_title,
-			       undef, $overall_found, $overall_hit,
-			       $total_fn_found, $total_fn_hit, $total_br_found,
-			       $total_br_hit, \%overview, {}, {}, {}, 0, $_);
-	}
-
-	# Check if there are any test case descriptions to write out
-	if (%test_description)
-	{
-		info("Writing test case description file.\n");
-		write_description_file( \%test_description,
-					$overall_found, $overall_hit,
-					$total_fn_found, $total_fn_hit,
-					$total_br_found, $total_br_hit);
-	}
-
-	print_overall_rate(1, $overall_found, $overall_hit,
-			   $func_coverage, $total_fn_found, $total_fn_hit,
-			   $br_coverage, $total_br_found, $total_br_hit);
-
-	chdir($cwd);
-}
-
-#
-# html_create(handle, filename)
-#
-
-sub html_create($$)
-{
-	my $handle = $_[0];
-	my $filename = $_[1];
-
-	if ($html_gzip)
-	{
-		open($handle, "|gzip -c >$filename")
-			or die("ERROR: cannot open $filename for writing ".
-			       "(gzip)!\n");
-	}
-	else
-	{
-		open($handle, ">$filename")
-			or die("ERROR: cannot open $filename for writing!\n");
-	}
-}
-
-sub write_dir_page($$$$$$$$$$$$$$$$$)
-{
-	my ($name, $rel_dir, $base_dir, $title, $trunc_dir, $overall_found,
-	    $overall_hit, $total_fn_found, $total_fn_hit, $total_br_found,
-	    $total_br_hit, $overview, $testhash, $testfnchash, $testbrhash,
-	    $view_type, $sort_type) = @_;
-
-	# Generate directory overview page including details
-	html_create(*HTML_HANDLE, "$rel_dir/index$name.$html_ext");
-	if (!defined($trunc_dir)) {
-		$trunc_dir = "";
-	}
-	write_html_prolog(*HTML_HANDLE, $base_dir, "LCOV - $title$trunc_dir");
-	write_header(*HTML_HANDLE, $view_type, $trunc_dir, $rel_dir,
-		     $overall_found, $overall_hit, $total_fn_found,
-		     $total_fn_hit, $total_br_found, $total_br_hit, $sort_type);
-	write_file_table(*HTML_HANDLE, $base_dir, $overview, $testhash,
-			 $testfnchash, $testbrhash, $view_type, $sort_type);
-	write_html_epilog(*HTML_HANDLE, $base_dir);
-	close(*HTML_HANDLE);
-}
-
-
-#
-# process_dir(dir_name)
-#
-
-sub process_dir($)
-{
-	my $abs_dir = $_[0];
-	my $trunc_dir;
-	my $rel_dir = $abs_dir;
-	my $base_dir;
-	my $filename;
-	my %overview;
-	my $lines_found;
-	my $lines_hit;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-	my $overall_found=0;
-	my $overall_hit=0;
-	my $total_fn_found=0;
-	my $total_fn_hit=0;
-	my $total_br_found = 0;
-	my $total_br_hit = 0;
-	my $base_name;
-	my $extension;
-	my $testdata;
-	my %testhash;
-	my $testfncdata;
-	my %testfnchash;
-	my $testbrdata;
-	my %testbrhash;
-	my @sort_list;
-	local *HTML_HANDLE;
-
-	# Remove prefix if applicable
-	if (!$no_prefix)
-	{
-		# Match directory name beginning with $dir_prefix
-		$rel_dir = apply_prefix($rel_dir, $dir_prefix);
-	}
-
-	$trunc_dir = $rel_dir;
-
-	# Remove leading /
-	if ($rel_dir =~ /^\/(.*)$/)
-	{
-		$rel_dir = substr($rel_dir, 1);
-	}
-
-	$base_dir = get_relative_base_path($rel_dir);
-
-	create_sub_dir($rel_dir);
-
-	# Match filenames which specify files in this directory, not including
-	# sub-directories
-	foreach $filename (grep(/^\Q$abs_dir\E\/[^\/]*$/,keys(%info_data)))
-	{
-		my $page_link;
-		my $func_link;
-
-		($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
-		 $br_hit, $testdata, $testfncdata, $testbrdata) =
-			process_file($trunc_dir, $rel_dir, $filename);
-
-		$base_name = basename($filename);
-
-		if ($no_sourceview) {
-			$page_link = "";
-		} elsif ($frames) {
-			# Link to frameset page
-			$page_link = "$base_name.gcov.frameset.$html_ext";
-		} else {
-			# Link directory to source code view page
-			$page_link = "$base_name.gcov.$html_ext";
-		}
-		$overview{$base_name} = [$lines_found, $lines_hit, $fn_found,
-					 $fn_hit, $br_found, $br_hit,
-					 $page_link,
-					 get_rate($lines_found, $lines_hit),
-					 get_rate($fn_found, $fn_hit),
-					 get_rate($br_found, $br_hit)];
-
-		$testhash{$base_name} = $testdata;
-		$testfnchash{$base_name} = $testfncdata;
-		$testbrhash{$base_name} = $testbrdata;
-
-		$overall_found	+= $lines_found;
-		$overall_hit	+= $lines_hit;
-
-		$total_fn_found += $fn_found;
-		$total_fn_hit   += $fn_hit;
-
-		$total_br_found += $br_found;
-		$total_br_hit   += $br_hit;
-	}
-
-	# Create sorted pages
-	foreach (@fileview_sortlist) {
-		# Generate directory overview page (without details)	
-		write_dir_page($fileview_sortname[$_], $rel_dir, $base_dir,
-			       $test_title, $trunc_dir, $overall_found,
-			       $overall_hit, $total_fn_found, $total_fn_hit,
-			       $total_br_found, $total_br_hit, \%overview, {},
-			       {}, {}, 1, $_);
-		if (!$show_details) {
-			next;
-		}
-		# Generate directory overview page including details
-		write_dir_page("-detail".$fileview_sortname[$_], $rel_dir,
-			       $base_dir, $test_title, $trunc_dir,
-			       $overall_found, $overall_hit, $total_fn_found,
-			       $total_fn_hit, $total_br_found, $total_br_hit,
-			       \%overview, \%testhash, \%testfnchash,
-			       \%testbrhash, 1, $_);
-	}
-
-	# Calculate resulting line counts
-	return ($overall_found, $overall_hit, $total_fn_found, $total_fn_hit,
-		$total_br_found, $total_br_hit);
-}
-
-
-#
-# get_converted_lines(testdata)
-#
-# Return hash of line numbers of those lines which were only covered in
-# converted data sets.
-#
-
-sub get_converted_lines($)
-{
-	my $testdata = $_[0];
-	my $testcount;
-	my %converted;
-	my %nonconverted;
-	my $hash;
-	my $testcase;
-	my $line;
-	my %result;
-
-
-	# Get a hash containing line numbers with positive counts both for
-	# converted and original data sets
-	foreach $testcase (keys(%{$testdata}))
-	{
-		# Check to see if this is a converted data set
-		if ($testcase =~ /,diff$/)
-		{
-			$hash = \%converted;
-		}
-		else
-		{
-			$hash = \%nonconverted;
-		}
-
-		$testcount = $testdata->{$testcase};
-		# Add lines with a positive count to hash
-		foreach $line (keys%{$testcount})
-		{
-			if ($testcount->{$line} > 0)
-			{
-				$hash->{$line} = 1;
-			}
-		}
-	}
-
-	# Combine both hashes to resulting list
-	foreach $line (keys(%converted))
-	{
-		if (!defined($nonconverted{$line}))
-		{
-			$result{$line} = 1;
-		}
-	}
-
-	return \%result;
-}
-
-
-sub write_function_page($$$$$$$$$$$$$$$$$$)
-{
-	my ($base_dir, $rel_dir, $trunc_dir, $base_name, $title,
-	    $lines_found, $lines_hit, $fn_found, $fn_hit, $br_found, $br_hit,
-	    $sumcount, $funcdata, $sumfnccount, $testfncdata, $sumbrcount,
-	    $testbrdata, $sort_type) = @_;
-	my $pagetitle;
-	my $filename;
-
-	# Generate function table for this file
-	if ($sort_type == 0) {
-		$filename = "$rel_dir/$base_name.func.$html_ext";
-	} else {
-		$filename = "$rel_dir/$base_name.func-sort-c.$html_ext";
-	}
-	html_create(*HTML_HANDLE, $filename);
-	$pagetitle = "LCOV - $title - $trunc_dir/$base_name - functions";
-	write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
-	write_header(*HTML_HANDLE, 4, "$trunc_dir/$base_name",
-		     "$rel_dir/$base_name", $lines_found, $lines_hit,
-		     $fn_found, $fn_hit, $br_found, $br_hit, $sort_type);
-	write_function_table(*HTML_HANDLE, "$base_name.gcov.$html_ext",
-			     $sumcount, $funcdata,
-			     $sumfnccount, $testfncdata, $sumbrcount,
-			     $testbrdata, $base_name,
-			     $base_dir, $sort_type);
-	write_html_epilog(*HTML_HANDLE, $base_dir, 1);
-	close(*HTML_HANDLE);
-}
-
-
-#
-# process_file(trunc_dir, rel_dir, filename)
-#
-
-sub process_file($$$)
-{
-	info("Processing file ".apply_prefix($_[2], $dir_prefix)."\n");
-
-	my $trunc_dir = $_[0];
-	my $rel_dir = $_[1];
-	my $filename = $_[2];
-	my $base_name = basename($filename);
-	my $base_dir = get_relative_base_path($rel_dir);
-	my $testdata;
-	my $testcount;
-	my $sumcount;
-	my $funcdata;
-	my $checkdata;
-	my $testfncdata;
-	my $sumfnccount;
-	my $testbrdata;
-	my $sumbrcount;
-	my $lines_found;
-	my $lines_hit;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-	my $converted;
-	my @source;
-	my $pagetitle;
-	local *HTML_HANDLE;
-
-	($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
-	 $sumfnccount, $testbrdata, $sumbrcount, $lines_found, $lines_hit,
-	 $fn_found, $fn_hit, $br_found, $br_hit)
-		= get_info_entry($info_data{$filename});
-
-	# Return after this point in case user asked us not to generate
-	# source code view
-	if ($no_sourceview)
-	{
-		return ($lines_found, $lines_hit, $fn_found, $fn_hit,
-			$br_found, $br_hit, $testdata, $testfncdata,
-			$testbrdata);
-	}
-
-	$converted = get_converted_lines($testdata);
-	# Generate source code view for this file
-	html_create(*HTML_HANDLE, "$rel_dir/$base_name.gcov.$html_ext");
-	$pagetitle = "LCOV - $test_title - $trunc_dir/$base_name";
-	write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
-	write_header(*HTML_HANDLE, 2, "$trunc_dir/$base_name",
-		     "$rel_dir/$base_name", $lines_found, $lines_hit,
-		     $fn_found, $fn_hit, $br_found, $br_hit, 0);
-	@source = write_source(*HTML_HANDLE, $filename, $sumcount, $checkdata,
-			       $converted, $funcdata, $sumbrcount);
-
-	write_html_epilog(*HTML_HANDLE, $base_dir, 1);
-	close(*HTML_HANDLE);
-
-	if ($func_coverage) {
-		# Create function tables
-		foreach (@funcview_sortlist) {
-			write_function_page($base_dir, $rel_dir, $trunc_dir,
-					    $base_name, $test_title,
-					    $lines_found, $lines_hit,
-					    $fn_found, $fn_hit, $br_found,
-					    $br_hit, $sumcount,
-					    $funcdata, $sumfnccount,
-					    $testfncdata, $sumbrcount,
-					    $testbrdata, $_);
-		}
-	}
-
-	# Additional files are needed in case of frame output
-	if (!$frames)
-	{
-		return ($lines_found, $lines_hit, $fn_found, $fn_hit,
-			$br_found, $br_hit, $testdata, $testfncdata,
-			$testbrdata);
-	}
-
-	# Create overview png file
-	gen_png("$rel_dir/$base_name.gcov.png", $overview_width, $tab_size,
-		@source);
-
-	# Create frameset page
-	html_create(*HTML_HANDLE,
-		    "$rel_dir/$base_name.gcov.frameset.$html_ext");
-	write_frameset(*HTML_HANDLE, $base_dir, $base_name, $pagetitle);
-	close(*HTML_HANDLE);
-
-	# Write overview frame
-	html_create(*HTML_HANDLE,
-		    "$rel_dir/$base_name.gcov.overview.$html_ext");
-	write_overview(*HTML_HANDLE, $base_dir, $base_name, $pagetitle,
-		       scalar(@source));
-	close(*HTML_HANDLE);
-
-	return ($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
-		$br_hit, $testdata, $testfncdata, $testbrdata);
-}
-
-
-#
-# read_info_file(info_filename)
-#
-# Read in the contents of the .info file specified by INFO_FILENAME. Data will
-# be returned as a reference to a hash containing the following mappings:
-#
-# %result: for each filename found in file -> \%data
-#
-# %data: "test"  -> \%testdata
-#        "sum"   -> \%sumcount
-#        "func"  -> \%funcdata
-#        "found" -> $lines_found (number of instrumented lines found in file)
-#	 "hit"   -> $lines_hit (number of executed lines in file)
-#        "check" -> \%checkdata
-#        "testfnc" -> \%testfncdata
-#        "sumfnc"  -> \%sumfnccount
-#        "testbr"  -> \%testbrdata
-#        "sumbr"   -> \%sumbrcount
-#
-# %testdata   : name of test affecting this file -> \%testcount
-# %testfncdata: name of test affecting this file -> \%testfnccount
-# %testbrdata:  name of test affecting this file -> \%testbrcount
-#
-# %testcount   : line number   -> execution count for a single test
-# %testfnccount: function name -> execution count for a single test
-# %testbrcount : line number   -> branch coverage data for a single test
-# %sumcount    : line number   -> execution count for all tests
-# %sumfnccount : function name -> execution count for all tests
-# %sumbrcount  : line number   -> branch coverage data for all tests
-# %funcdata    : function name -> line number
-# %checkdata   : line number   -> checksum of source code line
-# $brdata      : vector of items: block, branch, taken
-# 
-# Note that .info file sections referring to the same file and test name
-# will automatically be combined by adding all execution counts.
-#
-# Note that if INFO_FILENAME ends with ".gz", it is assumed that the file
-# is compressed using GZIP. If available, GUNZIP will be used to decompress
-# this file.
-#
-# Die on error.
-#
-
-sub read_info_file($)
-{
-	my $tracefile = $_[0];		# Name of tracefile
-	my %result;			# Resulting hash: file -> data
-	my $data;			# Data handle for current entry
-	my $testdata;			#       "             "
-	my $testcount;			#       "             "
-	my $sumcount;			#       "             "
-	my $funcdata;			#       "             "
-	my $checkdata;			#       "             "
-	my $testfncdata;
-	my $testfnccount;
-	my $sumfnccount;
-	my $testbrdata;
-	my $testbrcount;
-	my $sumbrcount;
-	my $line;			# Current line read from .info file
-	my $testname;			# Current test name
-	my $filename;			# Current filename
-	my $hitcount;			# Count for lines hit
-	my $count;			# Execution count of current line
-	my $negative;			# If set, warn about negative counts
-	my $changed_testname;		# If set, warn about changed testname
-	my $line_checksum;		# Checksum of current line
-	my $br_found;
-	my $br_hit;
-	local *INFO_HANDLE;		# Filehandle for .info file
-
-	info("Reading data file $tracefile\n");
-
-	# Check if file exists and is readable
-	stat($_[0]);
-	if (!(-r _))
-	{
-		die("ERROR: cannot read file $_[0]!\n");
-	}
-
-	# Check if this is really a plain file
-	if (!(-f _))
-	{
-		die("ERROR: not a plain file: $_[0]!\n");
-	}
-
-	# Check for .gz extension
-	if ($_[0] =~ /\.gz$/)
-	{
-		# Check for availability of GZIP tool
-		system_no_output(1, "gunzip" ,"-h")
-			and die("ERROR: gunzip command not available!\n");
-
-		# Check integrity of compressed file
-		system_no_output(1, "gunzip", "-t", $_[0])
-			and die("ERROR: integrity check failed for ".
-				"compressed file $_[0]!\n");
-
-		# Open compressed file
-		open(INFO_HANDLE, "gunzip -c $_[0]|")
-			or die("ERROR: cannot start gunzip to decompress ".
-			       "file $_[0]!\n");
-	}
-	else
-	{
-		# Open decompressed file
-		open(INFO_HANDLE, $_[0])
-			or die("ERROR: cannot read file $_[0]!\n");
-	}
-
-	$testname = "";
-	while (<INFO_HANDLE>)
-	{
-		chomp($_);
-		$line = $_;
-
-		# Switch statement
-		foreach ($line)
-		{
-			/^TN:([^,]*)(,diff)?/ && do
-			{
-				# Test name information found
-				$testname = defined($1) ? $1 : "";
-				if ($testname =~ s/\W/_/g)
-				{
-					$changed_testname = 1;
-				}
-				$testname .= $2 if (defined($2));
-				last;
-			};
-
-			/^[SK]F:(.*)/ && do
-			{
-				# Filename information found
-				# Retrieve data for new entry
-				$filename = $1;
-
-				$data = $result{$filename};
-				($testdata, $sumcount, $funcdata, $checkdata,
-				 $testfncdata, $sumfnccount, $testbrdata,
-				 $sumbrcount) =
-					get_info_entry($data);
-
-				if (defined($testname))
-				{
-					$testcount = $testdata->{$testname};
-					$testfnccount = $testfncdata->{$testname};
-					$testbrcount = $testbrdata->{$testname};
-				}
-				else
-				{
-					$testcount = {};
-					$testfnccount = {};
-					$testbrcount = {};
-				}
-				last;
-			};
-
-			/^DA:(\d+),(-?\d+)(,[^,\s]+)?/ && do
-			{
-				# Fix negative counts
-				$count = $2 < 0 ? 0 : $2;
-				if ($2 < 0)
-				{
-					$negative = 1;
-				}
-				# Execution count found, add to structure
-				# Add summary counts
-				$sumcount->{$1} += $count;
-
-				# Add test-specific counts
-				if (defined($testname))
-				{
-					$testcount->{$1} += $count;
-				}
-
-				# Store line checksum if available
-				if (defined($3))
-				{
-					$line_checksum = substr($3, 1);
-
-					# Does it match a previous definition
-					if (defined($checkdata->{$1}) &&
-					    ($checkdata->{$1} ne
-					     $line_checksum))
-					{
-						die("ERROR: checksum mismatch ".
-						    "at $filename:$1\n");
-					}
-
-					$checkdata->{$1} = $line_checksum;
-				}
-				last;
-			};
-
-			/^FN:(\d+),([^,]+)/ && do
-			{
-				# Function data found, add to structure
-				$funcdata->{$2} = $1;
-
-				# Also initialize function call data
-				if (!defined($sumfnccount->{$2})) {
-					$sumfnccount->{$2} = 0;
-				}
-				if (defined($testname))
-				{
-					if (!defined($testfnccount->{$2})) {
-						$testfnccount->{$2} = 0;
-					}
-				}
-				last;
-			};
-
-			/^FNDA:(\d+),([^,]+)/ && do
-			{
-				# Function call count found, add to structure
-				# Add summary counts
-				$sumfnccount->{$2} += $1;
-
-				# Add test-specific counts
-				if (defined($testname))
-				{
-					$testfnccount->{$2} += $1;
-				}
-				last;
-			};
-
-			/^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
-				# Branch coverage data found
-				my ($line, $block, $branch, $taken) =
-				   ($1, $2, $3, $4);
-
-				$sumbrcount->{$line} =
-					br_ivec_push($sumbrcount->{$line},
-						     $block, $branch, $taken);
-
-				# Add test-specific counts
-				if (defined($testname)) {
-					$testbrcount->{$line} =
-						br_ivec_push(
-							$testbrcount->{$line},
-							$block, $branch,
-							$taken);
-				}
-				last;
-			};
-
-			/^end_of_record/ && do
-			{
-				# Found end of section marker
-				if ($filename)
-				{
-					# Store current section data
-					if (defined($testname))
-					{
-						$testdata->{$testname} =
-							$testcount;
-						$testfncdata->{$testname} =
-							$testfnccount;
-						$testbrdata->{$testname} =
-							$testbrcount;
-					}	
-
-					set_info_entry($data, $testdata,
-						       $sumcount, $funcdata,
-						       $checkdata, $testfncdata,
-						       $sumfnccount,
-						       $testbrdata,
-						       $sumbrcount);
-					$result{$filename} = $data;
-					last;
-				}
-			};
-
-			# default
-			last;
-		}
-	}
-	close(INFO_HANDLE);
-
-	# Calculate lines_found and lines_hit for each file
-	foreach $filename (keys(%result))
-	{
-		$data = $result{$filename};
-
-		($testdata, $sumcount, undef, undef, $testfncdata,
-		 $sumfnccount, $testbrdata, $sumbrcount) =
-			get_info_entry($data);
-
-		# Filter out empty files
-		if (scalar(keys(%{$sumcount})) == 0)
-		{
-			delete($result{$filename});
-			next;
-		}
-		# Filter out empty test cases
-		foreach $testname (keys(%{$testdata}))
-		{
-			if (!defined($testdata->{$testname}) ||
-			    scalar(keys(%{$testdata->{$testname}})) == 0)
-			{
-				delete($testdata->{$testname});
-				delete($testfncdata->{$testname});
-			}
-		}
-
-		$data->{"found"} = scalar(keys(%{$sumcount}));
-		$hitcount = 0;
-
-		foreach (keys(%{$sumcount}))
-		{
-			if ($sumcount->{$_} > 0) { $hitcount++; }
-		}
-
-		$data->{"hit"} = $hitcount;
-
-		# Get found/hit values for function call data
-		$data->{"f_found"} = scalar(keys(%{$sumfnccount}));
-		$hitcount = 0;
-
-		foreach (keys(%{$sumfnccount})) {
-			if ($sumfnccount->{$_} > 0) {
-				$hitcount++;
-			}
-		}
-		$data->{"f_hit"} = $hitcount;
-
-		# Get found/hit values for branch data
-		($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
-
-		$data->{"b_found"} = $br_found;
-		$data->{"b_hit"} = $br_hit;
-	}
-
-	if (scalar(keys(%result)) == 0)
-	{
-		die("ERROR: no valid records found in tracefile $tracefile\n");
-	}
-	if ($negative)
-	{
-		warn("WARNING: negative counts found in tracefile ".
-		     "$tracefile\n");
-	}
-	if ($changed_testname)
-	{
-		warn("WARNING: invalid characters removed from testname in ".
-		     "tracefile $tracefile\n");
-	}
-
-	return(\%result);
-}
-
-
-#
-# get_info_entry(hash_ref)
-#
-# Retrieve data from an entry of the structure generated by read_info_file().
-# Return a list of references to hashes:
-# (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash
-#  ref, testfncdata hash ref, sumfnccount hash ref, lines found, lines hit,
-#  functions found, functions hit)
-#
-
-sub get_info_entry($)
-{
-	my $testdata_ref = $_[0]->{"test"};
-	my $sumcount_ref = $_[0]->{"sum"};
-	my $funcdata_ref = $_[0]->{"func"};
-	my $checkdata_ref = $_[0]->{"check"};
-	my $testfncdata = $_[0]->{"testfnc"};
-	my $sumfnccount = $_[0]->{"sumfnc"};
-	my $testbrdata = $_[0]->{"testbr"};
-	my $sumbrcount = $_[0]->{"sumbr"};
-	my $lines_found = $_[0]->{"found"};
-	my $lines_hit = $_[0]->{"hit"};
-	my $fn_found = $_[0]->{"f_found"};
-	my $fn_hit = $_[0]->{"f_hit"};
-	my $br_found = $_[0]->{"b_found"};
-	my $br_hit = $_[0]->{"b_hit"};
-
-	return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
-		$testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
-		$lines_found, $lines_hit, $fn_found, $fn_hit,
-		$br_found, $br_hit);
-}
-
-
-#
-# set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
-#                checkdata_ref, testfncdata_ref, sumfcncount_ref,
-#                testbrdata_ref, sumbrcount_ref[,lines_found,
-#                lines_hit, f_found, f_hit, $b_found, $b_hit])
-#
-# Update the hash referenced by HASH_REF with the provided data references.
-#
-
-sub set_info_entry($$$$$$$$$;$$$$$$)
-{
-	my $data_ref = $_[0];
-
-	$data_ref->{"test"} = $_[1];
-	$data_ref->{"sum"} = $_[2];
-	$data_ref->{"func"} = $_[3];
-	$data_ref->{"check"} = $_[4];
-	$data_ref->{"testfnc"} = $_[5];
-	$data_ref->{"sumfnc"} = $_[6];
-	$data_ref->{"testbr"} = $_[7];
-	$data_ref->{"sumbr"} = $_[8];
-
-	if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
-	if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
-	if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
-	if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
-	if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
-	if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
-}
-
-
-#
-# add_counts(data1_ref, data2_ref)
-#
-# DATA1_REF and DATA2_REF are references to hashes containing a mapping
-#
-#   line number -> execution count
-#
-# Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF
-# is a reference to a hash containing the combined mapping in which
-# execution counts are added.
-#
-
-sub add_counts($$)
-{
-	my %data1 = %{$_[0]};	# Hash 1
-	my %data2 = %{$_[1]};	# Hash 2
-	my %result;		# Resulting hash
-	my $line;		# Current line iteration scalar
-	my $data1_count;	# Count of line in hash1
-	my $data2_count;	# Count of line in hash2
-	my $found = 0;		# Total number of lines found
-	my $hit = 0;		# Number of lines with a count > 0
-
-	foreach $line (keys(%data1))
-	{
-		$data1_count = $data1{$line};
-		$data2_count = $data2{$line};
-
-		# Add counts if present in both hashes
-		if (defined($data2_count)) { $data1_count += $data2_count; }
-
-		# Store sum in %result
-		$result{$line} = $data1_count;
-
-		$found++;
-		if ($data1_count > 0) { $hit++; }
-	}
-
-	# Add lines unique to data2
-	foreach $line (keys(%data2))
-	{
-		# Skip lines already in data1
-		if (defined($data1{$line})) { next; }
-
-		# Copy count from data2
-		$result{$line} = $data2{$line};
-
-		$found++;
-		if ($result{$line} > 0) { $hit++; }
-	}
-
-	return (\%result, $found, $hit);
-}
-
-
-#
-# merge_checksums(ref1, ref2, filename)
-#
-# REF1 and REF2 are references to hashes containing a mapping
-#
-#   line number -> checksum
-#
-# Merge checksum lists defined in REF1 and REF2 and return reference to
-# resulting hash. Die if a checksum for a line is defined in both hashes
-# but does not match.
-#
-
-sub merge_checksums($$$)
-{
-	my $ref1 = $_[0];
-	my $ref2 = $_[1];
-	my $filename = $_[2];
-	my %result;
-	my $line;
-
-	foreach $line (keys(%{$ref1}))
-	{
-		if (defined($ref2->{$line}) &&
-		    ($ref1->{$line} ne $ref2->{$line}))
-		{
-			die("ERROR: checksum mismatch at $filename:$line\n");
-		}
-		$result{$line} = $ref1->{$line};
-	}
-
-	foreach $line (keys(%{$ref2}))
-	{
-		$result{$line} = $ref2->{$line};
-	}
-
-	return \%result;
-}
-
-
-#
-# merge_func_data(funcdata1, funcdata2, filename)
-#
-
-sub merge_func_data($$$)
-{
-	my ($funcdata1, $funcdata2, $filename) = @_;
-	my %result;
-	my $func;
-
-	if (defined($funcdata1)) {
-		%result = %{$funcdata1};
-	}
-
-	foreach $func (keys(%{$funcdata2})) {
-		my $line1 = $result{$func};
-		my $line2 = $funcdata2->{$func};
-
-		if (defined($line1) && ($line1 != $line2)) {
-			warn("WARNING: function data mismatch at ".
-			     "$filename:$line2\n");
-			next;
-		}
-		$result{$func} = $line2;
-	}
-
-	return \%result;
-}
-
-
-#
-# add_fnccount(fnccount1, fnccount2)
-#
-# Add function call count data. Return list (fnccount_added, f_found, f_hit)
-#
-
-sub add_fnccount($$)
-{
-	my ($fnccount1, $fnccount2) = @_;
-	my %result;
-	my $fn_found;
-	my $fn_hit;
-	my $function;
-
-	if (defined($fnccount1)) {
-		%result = %{$fnccount1};
-	}
-	foreach $function (keys(%{$fnccount2})) {
-		$result{$function} += $fnccount2->{$function};
-	}
-	$fn_found = scalar(keys(%result));
-	$fn_hit = 0;
-	foreach $function (keys(%result)) {
-		if ($result{$function} > 0) {
-			$fn_hit++;
-		}
-	}
-
-	return (\%result, $fn_found, $fn_hit);
-}
-
-#
-# add_testfncdata(testfncdata1, testfncdata2)
-#
-# Add function call count data for several tests. Return reference to
-# added_testfncdata.
-#
-
-sub add_testfncdata($$)
-{
-	my ($testfncdata1, $testfncdata2) = @_;
-	my %result;
-	my $testname;
-
-	foreach $testname (keys(%{$testfncdata1})) {
-		if (defined($testfncdata2->{$testname})) {
-			my $fnccount;
-
-			# Function call count data for this testname exists
-			# in both data sets: add
-			($fnccount) = add_fnccount(
-				$testfncdata1->{$testname},
-				$testfncdata2->{$testname});
-			$result{$testname} = $fnccount;
-			next;
-		}
-		# Function call count data for this testname is unique to
-		# data set 1: copy
-		$result{$testname} = $testfncdata1->{$testname};
-	}
-
-	# Add count data for testnames unique to data set 2
-	foreach $testname (keys(%{$testfncdata2})) {
-		if (!defined($result{$testname})) {
-			$result{$testname} = $testfncdata2->{$testname};
-		}
-	}
-	return \%result;
-}
-
-
-#
-# brcount_to_db(brcount)
-#
-# Convert brcount data to the following format:
-#
-# db:          line number    -> block hash
-# block hash:  block number   -> branch hash
-# branch hash: branch number  -> taken value
-#
-
-sub brcount_to_db($)
-{
-	my ($brcount) = @_;
-	my $line;
-	my $db;
-
-	# Add branches from first count to database
-	foreach $line (keys(%{$brcount})) {
-		my $brdata = $brcount->{$line};
-		my $i;
-		my $num = br_ivec_len($brdata);
-
-		for ($i = 0; $i < $num; $i++) {
-			my ($block, $branch, $taken) = br_ivec_get($brdata, $i);
-
-			$db->{$line}->{$block}->{$branch} = $taken;
-		}
-	}
-
-	return $db;
-}
-
-
-#
-# db_to_brcount(db)
-#
-# Convert branch coverage data back to brcount format.
-#
-
-sub db_to_brcount($)
-{
-	my ($db) = @_;
-	my $line;
-	my $brcount = {};
-	my $br_found = 0;
-	my $br_hit = 0;
-
-	# Convert database back to brcount format
-	foreach $line (sort({$a <=> $b} keys(%{$db}))) {
-		my $ldata = $db->{$line};
-		my $brdata;
-		my $block;
-
-		foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
-			my $bdata = $ldata->{$block};
-			my $branch;
-
-			foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
-				my $taken = $bdata->{$branch};
-
-				$br_found++;
-				$br_hit++ if ($taken ne "-" && $taken > 0);
-				$brdata = br_ivec_push($brdata, $block,
-						       $branch, $taken);
-			}
-		}
-		$brcount->{$line} = $brdata;
-	}
-
-	return ($brcount, $br_found, $br_hit);
-}
-
-
-#
-# combine_brcount(brcount1, brcount2, type)
-#
-# If add is BR_ADD, add branch coverage data and return list (brcount_added,
-# br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2
-# from brcount1 and return (brcount_sub, br_found, br_hit).
-#
-
-sub combine_brcount($$$)
-{
-	my ($brcount1, $brcount2, $type) = @_;
-	my $line;
-	my $block;
-	my $branch;
-	my $taken;
-	my $db;
-	my $br_found = 0;
-	my $br_hit = 0;
-	my $result;
-
-	# Convert branches from first count to database
-	$db = brcount_to_db($brcount1);
-	# Combine values from database and second count
-	foreach $line (keys(%{$brcount2})) {
-		my $brdata = $brcount2->{$line};
-		my $num = br_ivec_len($brdata);
-		my $i;
-
-		for ($i = 0; $i < $num; $i++) {
-			($block, $branch, $taken) = br_ivec_get($brdata, $i);
-			my $new_taken = $db->{$line}->{$block}->{$branch};
-
-			if ($type == $BR_ADD) {
-				$new_taken = br_taken_add($new_taken, $taken);
-			} elsif ($type == $BR_SUB) {
-				$new_taken = br_taken_sub($new_taken, $taken);
-			}
-			$db->{$line}->{$block}->{$branch} = $new_taken
-				if (defined($new_taken));
-		}
-	}
-	# Convert database back to brcount format
-	($result, $br_found, $br_hit) = db_to_brcount($db);
-
-	return ($result, $br_found, $br_hit);
-}
-
-
-#
-# add_testbrdata(testbrdata1, testbrdata2)
-#
-# Add branch coverage data for several tests. Return reference to
-# added_testbrdata.
-#
-
-sub add_testbrdata($$)
-{
-	my ($testbrdata1, $testbrdata2) = @_;
-	my %result;
-	my $testname;
-
-	foreach $testname (keys(%{$testbrdata1})) {
-		if (defined($testbrdata2->{$testname})) {
-			my $brcount;
-
-			# Branch coverage data for this testname exists
-			# in both data sets: add
-			($brcount) = combine_brcount($testbrdata1->{$testname},
-					 $testbrdata2->{$testname}, $BR_ADD);
-			$result{$testname} = $brcount;
-			next;
-		}
-		# Branch coverage data for this testname is unique to
-		# data set 1: copy
-		$result{$testname} = $testbrdata1->{$testname};
-	}
-
-	# Add count data for testnames unique to data set 2
-	foreach $testname (keys(%{$testbrdata2})) {
-		if (!defined($result{$testname})) {
-			$result{$testname} = $testbrdata2->{$testname};
-		}
-	}
-	return \%result;
-}
-
-
-#
-# combine_info_entries(entry_ref1, entry_ref2, filename)
-#
-# Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2.
-# Return reference to resulting hash.
-#
-
-sub combine_info_entries($$$)
-{
-	my $entry1 = $_[0];	# Reference to hash containing first entry
-	my $testdata1;
-	my $sumcount1;
-	my $funcdata1;
-	my $checkdata1;
-	my $testfncdata1;
-	my $sumfnccount1;
-	my $testbrdata1;
-	my $sumbrcount1;
-
-	my $entry2 = $_[1];	# Reference to hash containing second entry
-	my $testdata2;
-	my $sumcount2;
-	my $funcdata2;
-	my $checkdata2;
-	my $testfncdata2;
-	my $sumfnccount2;
-	my $testbrdata2;
-	my $sumbrcount2;
-
-	my %result;		# Hash containing combined entry
-	my %result_testdata;
-	my $result_sumcount = {};
-	my $result_funcdata;
-	my $result_testfncdata;
-	my $result_sumfnccount;
-	my $result_testbrdata;
-	my $result_sumbrcount;
-	my $lines_found;
-	my $lines_hit;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-
-	my $testname;
-	my $filename = $_[2];
-
-	# Retrieve data
-	($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
-	 $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
-	($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
-	 $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
-
-	# Merge checksums
-	$checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
-
-	# Combine funcdata
-	$result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename);
-
-	# Combine function call count data
-	$result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2);
-	($result_sumfnccount, $fn_found, $fn_hit) =
-		add_fnccount($sumfnccount1, $sumfnccount2);
-	
-	# Combine branch coverage data
-	$result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
-	($result_sumbrcount, $br_found, $br_hit) =
-		combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
-
-	# Combine testdata
-	foreach $testname (keys(%{$testdata1}))
-	{
-		if (defined($testdata2->{$testname}))
-		{
-			# testname is present in both entries, requires
-			# combination
-			($result_testdata{$testname}) =
-				add_counts($testdata1->{$testname},
-					   $testdata2->{$testname});
-		}
-		else
-		{
-			# testname only present in entry1, add to result
-			$result_testdata{$testname} = $testdata1->{$testname};
-		}
-
-		# update sum count hash
-		($result_sumcount, $lines_found, $lines_hit) =
-			add_counts($result_sumcount,
-				   $result_testdata{$testname});
-	}
-
-	foreach $testname (keys(%{$testdata2}))
-	{
-		# Skip testnames already covered by previous iteration
-		if (defined($testdata1->{$testname})) { next; }
-
-		# testname only present in entry2, add to result hash
-		$result_testdata{$testname} = $testdata2->{$testname};
-
-		# update sum count hash
-		($result_sumcount, $lines_found, $lines_hit) =
-			add_counts($result_sumcount,
-				   $result_testdata{$testname});
-	}
-	
-	# Calculate resulting sumcount
-
-	# Store result
-	set_info_entry(\%result, \%result_testdata, $result_sumcount,
-		       $result_funcdata, $checkdata1, $result_testfncdata,
-		       $result_sumfnccount, $result_testbrdata,
-		       $result_sumbrcount, $lines_found, $lines_hit,
-		       $fn_found, $fn_hit, $br_found, $br_hit);
-
-	return(\%result);
-}
-
-
-#
-# combine_info_files(info_ref1, info_ref2)
-#
-# Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return
-# reference to resulting hash.
-#
-
-sub combine_info_files($$)
-{
-	my %hash1 = %{$_[0]};
-	my %hash2 = %{$_[1]};
-	my $filename;
-
-	foreach $filename (keys(%hash2))
-	{
-		if ($hash1{$filename})
-		{
-			# Entry already exists in hash1, combine them
-			$hash1{$filename} =
-				combine_info_entries($hash1{$filename},
-						     $hash2{$filename},
-						     $filename);
-		}
-		else
-		{
-			# Entry is unique in both hashes, simply add to
-			# resulting hash
-			$hash1{$filename} = $hash2{$filename};
-		}
-	}
-
-	return(\%hash1);
-}
-
-
-#
-# get_prefix(filename_list)
-#
-# Search FILENAME_LIST for a directory prefix which is common to as many
-# list entries as possible, so that removing this prefix will minimize the
-# sum of the lengths of all resulting shortened filenames.
-#
-
-sub get_prefix(@)
-{
-	my @filename_list = @_;		# provided list of filenames
-	my %prefix;			# mapping: prefix -> sum of lengths
-	my $current;			# Temporary iteration variable
-
-	# Find list of prefixes
-	foreach (@filename_list)
-	{
-		# Need explicit assignment to get a copy of $_ so that
-		# shortening the contained prefix does not affect the list
-		$current = shorten_prefix($_);
-		while ($current = shorten_prefix($current))
-		{
-			# Skip rest if the remaining prefix has already been
-			# added to hash
-			if ($prefix{$current}) { last; }
-
-			# Initialize with 0
-			$prefix{$current}="0";
-		}
-
-	}
-
-	# Calculate sum of lengths for all prefixes
-	foreach $current (keys(%prefix))
-	{
-		foreach (@filename_list)
-		{
-			# Add original length
-			$prefix{$current} += length($_);
-
-			# Check whether prefix matches
-			if (substr($_, 0, length($current)) eq $current)
-			{
-				# Subtract prefix length for this filename
-				$prefix{$current} -= length($current);
-			}
-		}
-	}
-
-	# Find and return prefix with minimal sum
-	$current = (keys(%prefix))[0];
-
-	foreach (keys(%prefix))
-	{
-		if ($prefix{$_} < $prefix{$current})
-		{
-			$current = $_;
-		}
-	}
-
-	return($current);
-}
-
-
-#
-# shorten_prefix(prefix)
-#
-# Return PREFIX shortened by last directory component.
-#
-
-sub shorten_prefix($)
-{
-	my @list = split("/", $_[0]);
-
-	pop(@list);
-	return join("/", @list);
-}
-
-
-
-#
-# get_dir_list(filename_list)
-#
-# Return sorted list of directories for each entry in given FILENAME_LIST.
-#
-
-sub get_dir_list(@)
-{
-	my %result;
-
-	foreach (@_)
-	{
-		$result{shorten_prefix($_)} = "";
-	}
-
-	return(sort(keys(%result)));
-}
-
-
-#
-# get_relative_base_path(subdirectory)
-#
-# Return a relative path string which references the base path when applied
-# in SUBDIRECTORY.
-#
-# Example: get_relative_base_path("fs/mm") -> "../../"
-#
-
-sub get_relative_base_path($)
-{
-	my $result = "";
-	my $index;
-
-	# Make an empty directory path a special case
-	if (!$_[0]) { return(""); }
-
-	# Count number of /s in path
-	$index = ($_[0] =~ s/\//\//g);
-
-	# Add a ../ to $result for each / in the directory path + 1
-	for (; $index>=0; $index--)
-	{
-		$result .= "../";
-	}
-
-	return $result;
-}
-
-
-#
-# read_testfile(test_filename)
-#
-# Read in file TEST_FILENAME which contains test descriptions in the format:
-#
-#   TN:<whitespace><test name>
-#   TD:<whitespace><test description>
-#
-# for each test case. Return a reference to a hash containing a mapping
-#
-#   test name -> test description.
-#
-# Die on error.
-#
-
-sub read_testfile($)
-{
-	my %result;
-	my $test_name;
-	my $changed_testname;
-	local *TEST_HANDLE;
-
-	open(TEST_HANDLE, "<".$_[0])
-		or die("ERROR: cannot open $_[0]!\n");
-
-	while (<TEST_HANDLE>)
-	{
-		chomp($_);
-
-		# Match lines beginning with TN:<whitespace(s)>
-		if (/^TN:\s+(.*?)\s*$/)
-		{
-			# Store name for later use
-			$test_name = $1;
-			if ($test_name =~ s/\W/_/g)
-			{
-				$changed_testname = 1;
-			}
-		}
-
-		# Match lines beginning with TD:<whitespace(s)>
-		if (/^TD:\s+(.*?)\s*$/)
-		{
-			# Check for empty line
-			if ($1)
-			{
-				# Add description to hash
-				$result{$test_name} .= " $1";
-			}
-			else
-			{
-				# Add empty line
-				$result{$test_name} .= "\n\n";
-			}
-		}
-	}
-
-	close(TEST_HANDLE);
-
-	if ($changed_testname)
-	{
-		warn("WARNING: invalid characters removed from testname in ".
-		     "descriptions file $_[0]\n");
-	}
-
-	return \%result;
-}
-
-
-#
-# escape_html(STRING)
-#
-# Return a copy of STRING in which all occurrences of HTML special characters
-# are escaped.
-#
-
-sub escape_html($)
-{
-	my $string = $_[0];
-
-	if (!$string) { return ""; }
-
-	$string =~ s/&/&amp;/g;		# & -> &amp;
-	$string =~ s/</&lt;/g;		# < -> &lt;
-	$string =~ s/>/&gt;/g;		# > -> &gt;
-	$string =~ s/\"/&quot;/g;	# " -> &quot;
-
-	while ($string =~ /^([^\t]*)(\t)/)
-	{
-		my $replacement = " "x($tab_size - (length($1) % $tab_size));
-		$string =~ s/^([^\t]*)(\t)/$1$replacement/;
-	}
-
-	$string =~ s/\n/<br>/g;		# \n -> <br>
-
-	return $string;
-}
-
-
-#
-# get_date_string()
-#
-# Return the current date in the form: yyyy-mm-dd
-#
-
-sub get_date_string()
-{
-	my $year;
-	my $month;
-	my $day;
-
-	($year, $month, $day) = (localtime())[5, 4, 3];
-
-	return sprintf("%d-%02d-%02d", $year+1900, $month+1, $day);
-}
-
-
-#
-# create_sub_dir(dir_name)
-#
-# Create subdirectory DIR_NAME if it does not already exist, including all its
-# parent directories.
-#
-# Die on error.
-#
-
-sub create_sub_dir($)
-{
-	my ($dir) = @_;
-
-	system("mkdir", "-p" ,$dir)
-		and die("ERROR: cannot create directory $dir!\n");
-}
-
-
-#
-# write_description_file(descriptions, overall_found, overall_hit,
-#                        total_fn_found, total_fn_hit, total_br_found,
-#                        total_br_hit)
-#
-# Write HTML file containing all test case descriptions. DESCRIPTIONS is a
-# reference to a hash containing a mapping
-#
-#   test case name -> test case description
-#
-# Die on error.
-#
-
-sub write_description_file($$$$$$$)
-{
-	my %description = %{$_[0]};
-	my $found = $_[1];
-	my $hit = $_[2];
-	my $fn_found = $_[3];
-	my $fn_hit = $_[4];
-	my $br_found = $_[5];
-	my $br_hit = $_[6];
-	my $test_name;
-	local *HTML_HANDLE;
-
-	html_create(*HTML_HANDLE,"descriptions.$html_ext");
-	write_html_prolog(*HTML_HANDLE, "", "LCOV - test case descriptions");
-	write_header(*HTML_HANDLE, 3, "", "", $found, $hit, $fn_found,
-		     $fn_hit, $br_found, $br_hit, 0);
-
-	write_test_table_prolog(*HTML_HANDLE,
-			 "Test case descriptions - alphabetical list");
-
-	foreach $test_name (sort(keys(%description)))
-	{
-		write_test_table_entry(*HTML_HANDLE, $test_name,
-				       escape_html($description{$test_name}));
-	}
-
-	write_test_table_epilog(*HTML_HANDLE);
-	write_html_epilog(*HTML_HANDLE, "");
-
-	close(*HTML_HANDLE);
-}
-
-
-
-#
-# write_png_files()
-#
-# Create all necessary .png files for the HTML-output in the current
-# directory. .png-files are used as bar graphs.
-#
-# Die on error.
-#
-
-sub write_png_files()
-{
-	my %data;
-	local *PNG_HANDLE;
-
-	$data{"ruby.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x18, 0x10, 0x5d, 0x57, 
-		 0x34, 0x6e, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x35, 0x2f, 
-		 0x00, 0x00, 0x00, 0xd0, 0x33, 0x9a, 0x9d, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
-	$data{"amber.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x28, 0x04, 0x98, 0xcb, 
-		 0xd6, 0xe0, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xe0, 0x50, 
-		 0x00, 0x00, 0x00, 0xa2, 0x7a, 0xda, 0x7e, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-	  	 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
-	$data{"emerald.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x22, 0x2b, 0xc9, 0xf5, 
-		 0x03, 0x33, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0xea, 0x59, 
-		 0x0a, 0x0a, 0x0a, 0x0f, 0xba, 0x50, 0x83, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
-	$data{"snow.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4d, 
-		 0x45, 0x07, 0xd2, 0x07, 0x11, 0x0f, 0x1e, 0x1d, 0x75, 0xbc, 
-		 0xef, 0x55, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 
-		 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 0xd2, 
-		 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 
-		 0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, 
-		 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x00, 
-		 0x00, 0x00, 0x02, 0x00, 0x01, 0xe5, 0x27, 0xde, 0xfc, 0x00, 
-		 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 
-		 0x82];
-	$data{"glass.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 
-		 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 
-		 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 
-		 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 
-		 0x00, 0x00, 0x06, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 
-		 0x00, 0x00, 0x00, 0x55, 0xc2, 0xd3, 0x7e, 0x00, 0x00, 0x00, 
-		 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 
-		 0x00, 0x00, 0x00, 0x01, 0x62, 0x4b, 0x47, 0x44, 0x00, 0x88, 
-		 0x05, 0x1d, 0x48, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 
-		 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12, 0x01, 
-		 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 
-		 0x4d, 0x45, 0x07, 0xd2, 0x07, 0x13, 0x0f, 0x08, 0x19, 0xc4, 
-		 0x40, 0x56, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 
-		 0x54, 0x78, 0x9c, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 
-		 0x01, 0x48, 0xaf, 0xa4, 0x71, 0x00, 0x00, 0x00, 0x00, 0x49, 
-		 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82];
-	$data{"updown.png"} =
-		[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 
-		 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0a, 
-		 0x00, 0x00, 0x00, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x00, 0x16, 
-		 0xa3, 0x8d, 0xab, 0x00, 0x00, 0x00, 0x3c, 0x49, 0x44, 0x41, 
-		 0x54, 0x28, 0xcf, 0x63, 0x60, 0x40, 0x03, 0xff, 0xa1, 0x00, 
-		 0x5d, 0x9c, 0x11, 0x5d, 0x11, 0x8a, 0x24, 0x23, 0x23, 0x23, 
-		 0x86, 0x42, 0x6c, 0xa6, 0x20, 0x2b, 0x66, 0xc4, 0xa7, 0x08, 
-		 0x59, 0x31, 0x23, 0x21, 0x45, 0x30, 0xc0, 0xc4, 0x30, 0x60, 
-		 0x80, 0xfa, 0x6e, 0x24, 0x3e, 0x78, 0x48, 0x0a, 0x70, 0x62, 
-		 0xa2, 0x90, 0x81, 0xd8, 0x44, 0x01, 0x00, 0xe9, 0x5c, 0x2f, 
-		 0xf5, 0xe2, 0x9d, 0x0f, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x49, 
-		 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] if ($sort);
-	foreach (keys(%data))
-	{
-		open(PNG_HANDLE, ">".$_)
-			or die("ERROR: cannot create $_!\n");
-		binmode(PNG_HANDLE);
-		print(PNG_HANDLE map(chr,@{$data{$_}}));
-		close(PNG_HANDLE);
-	}
-}
-
-
-#
-# write_htaccess_file()
-#
-
-sub write_htaccess_file()
-{
-	local *HTACCESS_HANDLE;
-	my $htaccess_data;
-
-	open(*HTACCESS_HANDLE, ">.htaccess")
-		or die("ERROR: cannot open .htaccess for writing!\n");
-
-	$htaccess_data = (<<"END_OF_HTACCESS")
-AddEncoding x-gzip .html
-END_OF_HTACCESS
-	;
-
-	print(HTACCESS_HANDLE $htaccess_data);
-	close(*HTACCESS_HANDLE);
-}
-
-
-#
-# write_css_file()
-#
-# Write the cascading style sheet file gcov.css to the current directory.
-# This file defines basic layout attributes of all generated HTML pages.
-#
-
-sub write_css_file()
-{
-	local *CSS_HANDLE;
-
-	# Check for a specified external style sheet file
-	if ($css_filename)
-	{
-		# Simply copy that file
-		system("cp", $css_filename, "gcov.css")
-			and die("ERROR: cannot copy file $css_filename!\n");
-		return;
-	}
-
-	open(CSS_HANDLE, ">gcov.css")
-		or die ("ERROR: cannot open gcov.css for writing!\n");
-
-
-	# *************************************************************
-
-	my $css_data = ($_=<<"END_OF_CSS")
-	/* All views: initial background and text color */
-	body
-	{
-	  color: #000000;
-	  background-color: #FFFFFF;
-	}
-	
-	/* All views: standard link format*/
-	a:link
-	{
-	  color: #284FA8;
-	  text-decoration: underline;
-	}
-	
-	/* All views: standard link - visited format */
-	a:visited
-	{
-	  color: #00CB40;
-	  text-decoration: underline;
-	}
-	
-	/* All views: standard link - activated format */
-	a:active
-	{
-	  color: #FF0040;
-	  text-decoration: underline;
-	}
-	
-	/* All views: main title format */
-	td.title
-	{
-	  text-align: center;
-	  padding-bottom: 10px;
-	  font-family: sans-serif;
-	  font-size: 20pt;
-	  font-style: italic;
-	  font-weight: bold;
-	}
-	
-	/* All views: header item format */
-	td.headerItem
-	{
-	  text-align: right;
-	  padding-right: 6px;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	  vertical-align: top;
-	  white-space: nowrap;
-	}
-	
-	/* All views: header item value format */
-	td.headerValue
-	{
-	  text-align: left;
-	  color: #284FA8;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	  white-space: nowrap;
-	}
-
-	/* All views: header item coverage table heading */
-	td.headerCovTableHead
-	{
-	  text-align: center;
-	  padding-right: 6px;
-	  padding-left: 6px;
-	  padding-bottom: 0px;
-	  font-family: sans-serif;
-	  font-size: 80%;
-	  white-space: nowrap;
-	}
-	
-	/* All views: header item coverage table entry */
-	td.headerCovTableEntry
-	{
-	  text-align: right;
-	  color: #284FA8;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	  white-space: nowrap;
-	  padding-left: 12px;
-	  padding-right: 4px;
-	  background-color: #DAE7FE;
-	}
-	
-	/* All views: header item coverage table entry for high coverage rate */
-	td.headerCovTableEntryHi
-	{
-	  text-align: right;
-	  color: #000000;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	  white-space: nowrap;
-	  padding-left: 12px;
-	  padding-right: 4px;
-	  background-color: #A7FC9D;
-	}
-	
-	/* All views: header item coverage table entry for medium coverage rate */
-	td.headerCovTableEntryMed
-	{
-	  text-align: right;
-	  color: #000000;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	  white-space: nowrap;
-	  padding-left: 12px;
-	  padding-right: 4px;
-	  background-color: #FFEA20;
-	}
-	
-	/* All views: header item coverage table entry for ow coverage rate */
-	td.headerCovTableEntryLo
-	{
-	  text-align: right;
-	  color: #000000;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	  white-space: nowrap;
-	  padding-left: 12px;
-	  padding-right: 4px;
-	  background-color: #FF0000;
-	}
-	
-	/* All views: header legend value for legend entry */
-	td.headerValueLeg
-	{
-	  text-align: left;
-	  color: #000000;
-	  font-family: sans-serif;
-	  font-size: 80%;
-	  white-space: nowrap;
-	  padding-top: 4px;
-	}
-	
-	/* All views: color of horizontal ruler */
-	td.ruler
-	{
-	  background-color: #6688D4;
-	}
-	
-	/* All views: version string format */
-	td.versionInfo
-	{
-	  text-align: center;
-	  padding-top: 2px;
-	  font-family: sans-serif;
-	  font-style: italic;
-	}
-	
-	/* Directory view/File view (all)/Test case descriptions:
-	   table headline format */
-	td.tableHead
-	{
-	  text-align: center;
-	  color: #FFFFFF;
-	  background-color: #6688D4;
-	  font-family: sans-serif;
-	  font-size: 120%;
-	  font-weight: bold;
-	  white-space: nowrap;
-	  padding-left: 4px;
-	  padding-right: 4px;
-	}
-
-	span.tableHeadSort
-	{
-	  padding-right: 4px;
-	}
-	
-	/* Directory view/File view (all): filename entry format */
-	td.coverFile
-	{
-	  text-align: left;
-	  padding-left: 10px;
-	  padding-right: 20px; 
-	  color: #284FA8;
-	  background-color: #DAE7FE;
-	  font-family: monospace;
-	}
-	
-	/* Directory view/File view (all): bar-graph entry format*/
-	td.coverBar
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #DAE7FE;
-	}
-	
-	/* Directory view/File view (all): bar-graph outline color */
-	td.coverBarOutline
-	{
-	  background-color: #000000;
-	}
-	
-	/* Directory view/File view (all): percentage entry for files with
-	   high coverage rate */
-	td.coverPerHi
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #A7FC9D;
-	  font-weight: bold;
-	  font-family: sans-serif;
-	}
-	
-	/* Directory view/File view (all): line count entry for files with
-	   high coverage rate */
-	td.coverNumHi
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #A7FC9D;
-	  white-space: nowrap;
-	  font-family: sans-serif;
-	}
-	
-	/* Directory view/File view (all): percentage entry for files with
-	   medium coverage rate */
-	td.coverPerMed
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #FFEA20;
-	  font-weight: bold;
-	  font-family: sans-serif;
-	}
-	
-	/* Directory view/File view (all): line count entry for files with
-	   medium coverage rate */
-	td.coverNumMed
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #FFEA20;
-	  white-space: nowrap;
-	  font-family: sans-serif;
-	}
-	
-	/* Directory view/File view (all): percentage entry for files with
-	   low coverage rate */
-	td.coverPerLo
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #FF0000;
-	  font-weight: bold;
-	  font-family: sans-serif;
-	}
-	
-	/* Directory view/File view (all): line count entry for files with
-	   low coverage rate */
-	td.coverNumLo
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #FF0000;
-	  white-space: nowrap;
-	  font-family: sans-serif;
-	}
-	
-	/* File view (all): "show/hide details" link format */
-	a.detail:link
-	{
-	  color: #B8D0FF;
-	  font-size:80%;
-	}
-	
-	/* File view (all): "show/hide details" link - visited format */
-	a.detail:visited
-	{
-	  color: #B8D0FF;
-	  font-size:80%;
-	}
-	
-	/* File view (all): "show/hide details" link - activated format */
-	a.detail:active
-	{
-	  color: #FFFFFF;
-	  font-size:80%;
-	}
-	
-	/* File view (detail): test name entry */
-	td.testName
-	{
-	  text-align: right;
-	  padding-right: 10px;
-	  background-color: #DAE7FE;
-	  font-family: sans-serif;
-	}
-	
-	/* File view (detail): test percentage entry */
-	td.testPer
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px; 
-	  background-color: #DAE7FE;
-	  font-family: sans-serif;
-	}
-	
-	/* File view (detail): test lines count entry */
-	td.testNum
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px; 
-	  background-color: #DAE7FE;
-	  font-family: sans-serif;
-	}
-	
-	/* Test case descriptions: test name format*/
-	dt
-	{
-	  font-family: sans-serif;
-	  font-weight: bold;
-	}
-	
-	/* Test case descriptions: description table body */
-	td.testDescription
-	{
-	  padding-top: 10px;
-	  padding-left: 30px;
-	  padding-bottom: 10px;
-	  padding-right: 30px;
-	  background-color: #DAE7FE;
-	}
-	
-	/* Source code view: function entry */
-	td.coverFn
-	{
-	  text-align: left;
-	  padding-left: 10px;
-	  padding-right: 20px; 
-	  color: #284FA8;
-	  background-color: #DAE7FE;
-	  font-family: monospace;
-	}
-
-	/* Source code view: function entry zero count*/
-	td.coverFnLo
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #FF0000;
-	  font-weight: bold;
-	  font-family: sans-serif;
-	}
-
-	/* Source code view: function entry nonzero count*/
-	td.coverFnHi
-	{
-	  text-align: right;
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  background-color: #DAE7FE;
-	  font-weight: bold;
-	  font-family: sans-serif;
-	}
-
-	/* Source code view: source code format */
-	pre.source
-	{
-	  font-family: monospace;
-	  white-space: pre;
-	  margin-top: 2px;
-	}
-	
-	/* Source code view: line number format */
-	span.lineNum
-	{
-	  background-color: #EFE383;
-	}
-	
-	/* Source code view: format for lines which were executed */
-	td.lineCov,
-	span.lineCov
-	{
-	  background-color: #CAD7FE;
-	}
-	
-	/* Source code view: format for Cov legend */
-	span.coverLegendCov
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-bottom: 2px;
-	  background-color: #CAD7FE;
-	}
-	
-	/* Source code view: format for lines which were not executed */
-	td.lineNoCov,
-	span.lineNoCov
-	{
-	  background-color: #FF6230;
-	}
-	
-	/* Source code view: format for NoCov legend */
-	span.coverLegendNoCov
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-bottom: 2px;
-	  background-color: #FF6230;
-	}
-	
-	/* Source code view (function table): standard link - visited format */
-	td.lineNoCov > a:visited,
-	td.lineCov > a:visited
-	{  
-	  color: black;
-	  text-decoration: underline;
-	}  
-	
-	/* Source code view: format for lines which were executed only in a
-	   previous version */
-	span.lineDiffCov
-	{
-	  background-color: #B5F7AF;
-	}
-	
-	/* Source code view: format for branches which were executed
-	 * and taken */
-	span.branchCov
-	{
-	  background-color: #CAD7FE;
-	}
-
-	/* Source code view: format for branches which were executed
-	 * but not taken */
-	span.branchNoCov
-	{
-	  background-color: #FF6230;
-	}
-
-	/* Source code view: format for branches which were not executed */
-	span.branchNoExec
-	{
-	  background-color: #FF6230;
-	}
-
-	/* Source code view: format for the source code heading line */
-	pre.sourceHeading
-	{
-	  white-space: pre;
-	  font-family: monospace;
-	  font-weight: bold;
-	  margin: 0px;
-	}
-
-	/* All views: header legend value for low rate */
-	td.headerValueLegL
-	{
-	  font-family: sans-serif;
-	  text-align: center;
-	  white-space: nowrap;
-	  padding-left: 4px;
-	  padding-right: 2px;
-	  background-color: #FF0000;
-	  font-size: 80%;
-	}
-
-	/* All views: header legend value for med rate */
-	td.headerValueLegM
-	{
-	  font-family: sans-serif;
-	  text-align: center;
-	  white-space: nowrap;
-	  padding-left: 2px;
-	  padding-right: 2px;
-	  background-color: #FFEA20;
-	  font-size: 80%;
-	}
-
-	/* All views: header legend value for hi rate */
-	td.headerValueLegH
-	{
-	  font-family: sans-serif;
-	  text-align: center;
-	  white-space: nowrap;
-	  padding-left: 2px;
-	  padding-right: 4px;
-	  background-color: #A7FC9D;
-	  font-size: 80%;
-	}
-
-	/* All views except source code view: legend format for low coverage */
-	span.coverLegendCovLo
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-top: 2px;
-	  background-color: #FF0000;
-	}
-
-	/* All views except source code view: legend format for med coverage */
-	span.coverLegendCovMed
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-top: 2px;
-	  background-color: #FFEA20;
-	}
-
-	/* All views except source code view: legend format for hi coverage */
-	span.coverLegendCovHi
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-top: 2px;
-	  background-color: #A7FC9D;
-	}
-END_OF_CSS
-	;
-
-	# *************************************************************
-
-
-	# Remove leading tab from all lines
-	$css_data =~ s/^\t//gm;
-
-	print(CSS_HANDLE $css_data);
-
-	close(CSS_HANDLE);
-}
-
-
-#
-# get_bar_graph_code(base_dir, cover_found, cover_hit)
-#
-# Return a string containing HTML code which implements a bar graph display
-# for a coverage rate of cover_hit * 100 / cover_found.
-#
-
-sub get_bar_graph_code($$$)
-{
-	my $rate;
-	my $alt;
-	my $width;
-	my $remainder;
-	my $png_name;
-	my $graph_code;
-
-	# Check number of instrumented lines
-	if ($_[1] == 0) { return ""; }
-
-	$rate		= $_[2] * 100 / $_[1];
-	$alt		= sprintf("%.1f", $rate)."%";
-	$width		= sprintf("%.0f", $rate);
-	$remainder	= sprintf("%d", 100-$width);
-
-	# Decide which .png file to use
-	$png_name = $rate_png[classify_rate($_[1], $_[2], $med_limit,
-					    $hi_limit)];
-
-	if ($width == 0)
-	{
-		# Zero coverage
-		$graph_code = (<<END_OF_HTML)
-	        <table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="$_[0]snow.png" width=100 height=10 alt="$alt"></td></tr></table>
-END_OF_HTML
-		;
-	}
-	elsif ($width == 100)
-	{
-		# Full coverage
-		$graph_code = (<<END_OF_HTML)
-		<table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="$_[0]$png_name" width=100 height=10 alt="$alt"></td></tr></table>
-END_OF_HTML
-		;
-	}
-	else
-	{
-		# Positive coverage
-		$graph_code = (<<END_OF_HTML)
-		<table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="$_[0]$png_name" width=$width height=10 alt="$alt"><img src="$_[0]snow.png" width=$remainder height=10 alt="$alt"></td></tr></table>
-END_OF_HTML
-		;
-	}
-
-	# Remove leading tabs from all lines
-	$graph_code =~ s/^\t+//gm;
-	chomp($graph_code);
-
-	return($graph_code);
-}
-
-#
-# sub classify_rate(found, hit, med_limit, high_limit)
-#
-# Return 0 for low rate, 1 for medium rate and 2 for hi rate.
-#
-
-sub classify_rate($$$$)
-{
-	my ($found, $hit, $med, $hi) = @_;
-	my $rate;
-
-	if ($found == 0) {
-		return 2;
-	}
-	$rate = $hit * 100 / $found;
-	if ($rate < $med) {
-		return 0;
-	} elsif ($rate < $hi) {
-		return 1;
-	}
-	return 2;
-}
-
-
-#
-# write_html(filehandle, html_code)
-#
-# Write out HTML_CODE to FILEHANDLE while removing a leading tabulator mark
-# in each line of HTML_CODE.
-#
-
-sub write_html(*$)
-{
-	local *HTML_HANDLE = $_[0];
-	my $html_code = $_[1];
-
-	# Remove leading tab from all lines
-	$html_code =~ s/^\t//gm;
-
-	print(HTML_HANDLE $html_code)
-		or die("ERROR: cannot write HTML data ($!)\n");
-}
-
-
-#
-# write_html_prolog(filehandle, base_dir, pagetitle)
-#
-# Write an HTML prolog common to all HTML files to FILEHANDLE. PAGETITLE will
-# be used as HTML page title. BASE_DIR contains a relative path which points
-# to the base directory.
-#
-
-sub write_html_prolog(*$$)
-{
-	my $basedir = $_[1];
-	my $pagetitle = $_[2];
-	my $prolog;
-
-	$prolog = $html_prolog;
-	$prolog =~ s/\@pagetitle\@/$pagetitle/g;
-	$prolog =~ s/\@basedir\@/$basedir/g;
-
-	write_html($_[0], $prolog);
-}
-
-
-#
-# write_header_prolog(filehandle, base_dir)
-#
-# Write beginning of page header HTML code.
-#
-
-sub write_header_prolog(*$)
-{
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	  <table width="100%" border=0 cellspacing=0 cellpadding=0>
-	    <tr><td class="title">$title</td></tr>
-	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
-
-	    <tr>
-	      <td width="100%">
-	        <table cellpadding=1 border=0 width="100%">
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_header_line(handle, content)
-#
-# Write a header line with the specified table contents.
-#
-
-sub write_header_line(*@)
-{
-	my ($handle, @content) = @_;
-	my $entry;
-
-	write_html($handle, "          <tr>\n");
-	foreach $entry (@content) {
-		my ($width, $class, $text, $colspan) = @{$entry};
-
-		if (defined($width)) {
-			$width = " width=\"$width\"";
-		} else {
-			$width = "";
-		}
-		if (defined($class)) {
-			$class = " class=\"$class\"";
-		} else {
-			$class = "";
-		}
-		if (defined($colspan)) {
-			$colspan = " colspan=\"$colspan\"";
-		} else {
-			$colspan = "";
-		}
-		$text = "" if (!defined($text));
-		write_html($handle,
-			   "            <td$width$class$colspan>$text</td>\n");
-	}
-	write_html($handle, "          </tr>\n");
-}
-
-
-#
-# write_header_epilog(filehandle, base_dir)
-#
-# Write end of page header HTML code.
-#
-
-sub write_header_epilog(*$)
-{
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	          <tr><td><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
-	        </table>
-	      </td>
-	    </tr>
-
-	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
-	  </table>
-
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_file_table_prolog(handle, file_heading, ([heading, num_cols], ...))
-#
-# Write heading for file table.
-#
-
-sub write_file_table_prolog(*$@)
-{
-	my ($handle, $file_heading, @columns) = @_;
-	my $num_columns = 0;
-	my $file_width;
-	my $col;
-	my $width;
-
-	$width = 20 if (scalar(@columns) == 1);
-	$width = 10 if (scalar(@columns) == 2);
-	$width = 8 if (scalar(@columns) > 2);
-
-	foreach $col (@columns) {
-		my ($heading, $cols) = @{$col};
-
-		$num_columns += $cols;
-	}
-	$file_width = 100 - $num_columns * $width;
-
-	# Table definition
-	write_html($handle, <<END_OF_HTML);
-	  <center>
-	  <table width="80%" cellpadding=1 cellspacing=1 border=0>
-
-	    <tr>
-	      <td width="$file_width%"><br></td>
-END_OF_HTML
-	# Empty first row
-	foreach $col (@columns) {
-		my ($heading, $cols) = @{$col};
-
-		while ($cols-- > 0) {
-			write_html($handle, <<END_OF_HTML);
-	      <td width="$width%"></td>
-END_OF_HTML
-		}
-	}
-	# Next row
-	write_html($handle, <<END_OF_HTML);
-	    </tr>
-
-	    <tr>
-	      <td class="tableHead">$file_heading</td>
-END_OF_HTML
-	# Heading row
-	foreach $col (@columns) {
-		my ($heading, $cols) = @{$col};
-		my $colspan = "";
-
-		$colspan = " colspan=$cols" if ($cols > 1);
-		write_html($handle, <<END_OF_HTML);
-	      <td class="tableHead"$colspan>$heading</td>
-END_OF_HTML
-	}
-	write_html($handle, <<END_OF_HTML);
-	    </tr>
-END_OF_HTML
-}
-
-
-# write_file_table_entry(handle, base_dir, filename, page_link,
-#			 ([ found, hit, med_limit, hi_limit, graph ], ..)
-#
-# Write an entry of the file table.
-#
-
-sub write_file_table_entry(*$$$@)
-{
-	my ($handle, $base_dir, $filename, $page_link, @entries) = @_;
-	my $file_code;
-	my $entry;
-
-	# Add link to source if provided
-	if (defined($page_link) && $page_link ne "") {
-		$file_code = "<a href=\"$page_link\">$filename</a>";
-	} else {
-		$file_code = $filename;
-	}
-
-	# First column: filename
-	write_html($handle, <<END_OF_HTML);
-	    <tr>
-	      <td class="coverFile">$file_code</td>
-END_OF_HTML
-	# Columns as defined
-	foreach $entry (@entries) {
-		my ($found, $hit, $med, $hi, $graph) = @{$entry};
-		my $bar_graph;
-		my $class;
-		my $rate;
-
-		# Generate bar graph if requested
-		if ($graph) {
-			$bar_graph = get_bar_graph_code($base_dir, $found,
-							$hit);
-			write_html($handle, <<END_OF_HTML);
-	      <td class="coverBar" align="center">
-	        $bar_graph
-	      </td>
-END_OF_HTML
-		}
-		# Get rate color and text
-		if ($found == 0) {
-			$rate = "-";
-			$class = "Hi";
-		} else {
-			$rate = sprintf("%.1f&nbsp;%%", $hit * 100 / $found);
-			$class = $rate_name[classify_rate($found, $hit,
-					    $med, $hi)];
-		}
-		write_html($handle, <<END_OF_HTML);
-	      <td class="coverPer$class">$rate</td>
-	      <td class="coverNum$class">$hit / $found</td>
-END_OF_HTML
-	}
-	# End of row
-        write_html($handle, <<END_OF_HTML);
-	    </tr>
-END_OF_HTML
-}
-
-
-#
-# write_file_table_detail_entry(filehandle, test_name, ([found, hit], ...))
-#
-# Write entry for detail section in file table.
-#
-
-sub write_file_table_detail_entry(*$@)
-{
-	my ($handle, $test, @entries) = @_;
-	my $entry;
-
-	if ($test eq "") {
-		$test = "<span style=\"font-style:italic\">&lt;unnamed&gt;</span>";
-	} elsif ($test =~ /^(.*),diff$/) {
-		$test = $1." (converted)";
-	}
-	# Testname
-	write_html($handle, <<END_OF_HTML);
-	    <tr>
-	      <td class="testName" colspan=2>$test</td>
-END_OF_HTML
-	# Test data
-	foreach $entry (@entries) {
-		my ($found, $hit) = @{$entry};
-		my $rate = "-";
-
-		if ($found > 0) {
-			$rate = sprintf("%.1f&nbsp;%%", $hit * 100 / $found);
-		}
-		write_html($handle, <<END_OF_HTML);
-	      <td class="testPer">$rate</td>
-	      <td class="testNum">$hit&nbsp;/&nbsp;$found</td>
-END_OF_HTML
-	}
-
-        write_html($handle, <<END_OF_HTML);
-	    </tr>
-
-END_OF_HTML
-
-	# *************************************************************
-}
-
-
-#
-# write_file_table_epilog(filehandle)
-#
-# Write end of file table HTML code.
-#
-
-sub write_file_table_epilog(*)
-{
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	  </table>
-	  </center>
-	  <br>
-
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_test_table_prolog(filehandle, table_heading)
-#
-# Write heading for test case description table.
-#
-
-sub write_test_table_prolog(*$)
-{
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	  <center>
-	  <table width="80%" cellpadding=2 cellspacing=1 border=0>
-
-	    <tr>
-	      <td><br></td>
-	    </tr>
-
-	    <tr>
-	      <td class="tableHead">$_[1]</td>
-	    </tr>
-
-	    <tr>
-	      <td class="testDescription">
-	        <dl>
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_test_table_entry(filehandle, test_name, test_description)
-#
-# Write entry for the test table.
-#
-
-sub write_test_table_entry(*$$)
-{
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-          <dt>$_[1]<a name="$_[1]">&nbsp;</a></dt>
-          <dd>$_[2]<br><br></dd>
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_test_table_epilog(filehandle)
-#
-# Write end of test description table HTML code.
-#
-
-sub write_test_table_epilog(*)
-{
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	        </dl>
-	      </td>
-	    </tr>
-	  </table>
-	  </center>
-	  <br>
-
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-sub fmt_centered($$)
-{
-	my ($width, $text) = @_;
-	my $w0 = length($text);
-	my $w1 = int(($width - $w0) / 2);
-	my $w2 = $width - $w0 - $w1;
-
-	return (" "x$w1).$text.(" "x$w2);
-}
-
-
-#
-# write_source_prolog(filehandle)
-#
-# Write start of source code table.
-#
-
-sub write_source_prolog(*)
-{
-	my $lineno_heading = "         ";
-	my $branch_heading = "";
-	my $line_heading = fmt_centered($line_field_width, "Line data");
-	my $source_heading = " Source code";
-
-	if ($br_coverage) {
-		$branch_heading = fmt_centered($br_field_width, "Branch data").
-				  " ";
-	}
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	  <table cellpadding=0 cellspacing=0 border=0>
-	    <tr>
-	      <td><br></td>
-	    </tr>
-	    <tr>
-	      <td>
-<pre class="sourceHeading">${lineno_heading}${branch_heading}${line_heading} ${source_heading}</pre>
-<pre class="source">
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# get_branch_blocks(brdata)
-#
-# Group branches that belong to the same basic block.
-#
-# Returns: [block1, block2, ...]
-# block:   [branch1, branch2, ...]
-# branch:  [block_num, branch_num, taken_count, text_length, open, close]
-#
-
-sub get_branch_blocks($)
-{
-	my ($brdata) = @_;
-	my $last_block_num;
-	my $block = [];
-	my @blocks;
-	my $i;
-	my $num = br_ivec_len($brdata);
-
-	# Group branches
-	for ($i = 0; $i < $num; $i++) {
-		my ($block_num, $branch, $taken) = br_ivec_get($brdata, $i);
-		my $br;
-
-		if (defined($last_block_num) && $block_num != $last_block_num) {
-			push(@blocks, $block);
-			$block = [];
-		}
-		$br = [$block_num, $branch, $taken, 3, 0, 0];
-		push(@{$block}, $br);
-		$last_block_num = $block_num;
-	}
-	push(@blocks, $block) if (scalar(@{$block}) > 0);
-
-	# Add braces to first and last branch in group
-	foreach $block (@blocks) {
-		$block->[0]->[$BR_OPEN] = 1;
-		$block->[0]->[$BR_LEN]++;
-		$block->[scalar(@{$block}) - 1]->[$BR_CLOSE] = 1;
-		$block->[scalar(@{$block}) - 1]->[$BR_LEN]++;
-	}
-
-	return @blocks;
-}
-
-#
-# get_block_len(block)
-#
-# Calculate total text length of all branches in a block of branches.
-#
-
-sub get_block_len($)
-{
-	my ($block) = @_;
-	my $len = 0;
-	my $branch;
-
-	foreach $branch (@{$block}) {
-		$len += $branch->[$BR_LEN];
-	}
-
-	return $len;
-}
-
-
-#
-# get_branch_html(brdata)
-#
-# Return a list of HTML lines which represent the specified branch coverage
-# data in source code view.
-#
-
-sub get_branch_html($)
-{
-	my ($brdata) = @_;
-	my @blocks = get_branch_blocks($brdata);
-	my $block;
-	my $branch;
-	my $line_len = 0;
-	my $line = [];	# [branch2|" ", branch|" ", ...]
-	my @lines;	# [line1, line2, ...]
-	my @result;
-
-	# Distribute blocks to lines
-	foreach $block (@blocks) {
-		my $block_len = get_block_len($block);
-
-		# Does this block fit into the current line?
-		if ($line_len + $block_len <= $br_field_width) {
-			# Add it
-			$line_len += $block_len;
-			push(@{$line}, @{$block});
-			next;
-		} elsif ($block_len <= $br_field_width) {
-			# It would fit if the line was empty - add it to new
-			# line
-			push(@lines, $line);
-			$line_len = $block_len;
-			$line = [ @{$block} ];
-			next;
-		}
-		# Split the block into several lines
-		foreach $branch (@{$block}) {
-			if ($line_len + $branch->[$BR_LEN] >= $br_field_width) {
-				# Start a new line
-				if (($line_len + 1 <= $br_field_width) &&
-				    scalar(@{$line}) > 0 &&
-				    !$line->[scalar(@$line) - 1]->[$BR_CLOSE]) {
-					# Try to align branch symbols to be in
-					# one # row
-					push(@{$line}, " ");
-				}
-				push(@lines, $line);
-				$line_len = 0;
-				$line = [];
-			}
-			push(@{$line}, $branch);
-			$line_len += $branch->[$BR_LEN];
-		}
-	}
-	push(@lines, $line);
-
-	# Convert to HTML
-	foreach $line (@lines) {
-		my $current = "";
-		my $current_len = 0;
-
-		foreach $branch (@$line) {
-			# Skip alignment space
-			if ($branch eq " ") {
-				$current .= " ";
-				$current_len++;
-				next;
-			}
-
-			my ($block_num, $br_num, $taken, $len, $open, $close) =
-			   @{$branch};
-			my $class;
-			my $title;
-			my $text;
-
-			if ($taken eq '-') {
-				$class	= "branchNoExec";
-				$text	= " # ";
-				$title	= "Branch $br_num was not executed";
-			} elsif ($taken == 0) {
-				$class	= "branchNoCov";
-				$text	= " - ";
-				$title	= "Branch $br_num was not taken";
-			} else {
-				$class	= "branchCov";
-				$text	= " + ";
-				$title	= "Branch $br_num was taken $taken ".
-					  "time";
-				$title .= "s" if ($taken > 1);
-			}
-			$current .= "[" if ($open);
-			$current .= "<span class=\"$class\" title=\"$title\">";
-			$current .= $text."</span>";
-			$current .= "]" if ($close);
-			$current_len += $len;
-		}
-
-		# Right-align result text
-		if ($current_len < $br_field_width) {
-			$current = (" "x($br_field_width - $current_len)).
-				   $current;
-		}
-		push(@result, $current);
-	}
-
-	return @result;
-}
-
-
-#
-# format_count(count, width)
-#
-# Return a right-aligned representation of count that fits in width characters.
-#
-
-sub format_count($$)
-{
-	my ($count, $width) = @_;
-	my $result;
-	my $exp;
-
-	$result = sprintf("%*.0f", $width, $count);
-	while (length($result) > $width) {
-		last if ($count < 10);
-		$exp++;
-		$count = int($count/10);
-		$result = sprintf("%*s", $width, ">$count*10^$exp");
-	}
-	return $result;
-}
-
-#
-# write_source_line(filehandle, line_num, source, hit_count, converted,
-#                   brdata, add_anchor)
-#
-# Write formatted source code line. Return a line in a format as needed
-# by gen_png()
-#
-
-sub write_source_line(*$$$$$$)
-{
-	my ($handle, $line, $source, $count, $converted, $brdata,
-	    $add_anchor) = @_;
-	my $source_format;
-	my $count_format;
-	my $result;
-	my $anchor_start = "";
-	my $anchor_end = "";
-	my $count_field_width = $line_field_width - 1;
-	my @br_html;
-	my $html;
-
-	# Get branch HTML data for this line
-	@br_html = get_branch_html($brdata) if ($br_coverage);
-
-	if (!defined($count)) {
-		$result		= "";
-		$source_format	= "";
-		$count_format	= " "x$count_field_width;
-	}
-	elsif ($count == 0) {
-		$result		= $count;
-		$source_format	= '<span class="lineNoCov">';
-		$count_format	= format_count($count, $count_field_width);
-	}
-	elsif ($converted && defined($highlight)) {
-		$result		= "*".$count;
-		$source_format	= '<span class="lineDiffCov">';
-		$count_format	= format_count($count, $count_field_width);
-	}
-	else {
-		$result		= $count;
-		$source_format	= '<span class="lineCov">';
-		$count_format	= format_count($count, $count_field_width);
-	}
-	$result .= ":".$source;
-
-	# Write out a line number navigation anchor every $nav_resolution
-	# lines if necessary
-	if ($add_anchor)
-	{
-		$anchor_start	= "<a name=\"$_[1]\">";
-		$anchor_end	= "</a>";
-	}
-
-
-	# *************************************************************
-
-	$html = $anchor_start;
-	$html .= "<span class=\"lineNum\">".sprintf("%8d", $line)." </span>";
-	$html .= shift(@br_html).":" if ($br_coverage);
-	$html .= "$source_format$count_format : ";
-	$html .= escape_html($source);
-	$html .= "</span>" if ($source_format);
-	$html .= $anchor_end."\n";
-
-	write_html($handle, $html);
-
-	if ($br_coverage) {
-		# Add lines for overlong branch information
-		foreach (@br_html) {
-			write_html($handle, "<span class=\"lineNum\">".
-				   "         </span>$_\n");
-		}
-	}
-	# *************************************************************
-
-	return($result);
-}
-
-
-#
-# write_source_epilog(filehandle)
-#
-# Write end of source code table.
-#
-
-sub write_source_epilog(*)
-{
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	</pre>
-	      </td>
-	    </tr>
-	  </table>
-	  <br>
-
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_html_epilog(filehandle, base_dir[, break_frames])
-#
-# Write HTML page footer to FILEHANDLE. BREAK_FRAMES should be set when
-# this page is embedded in a frameset, clicking the URL link will then
-# break this frameset.
-#
-
-sub write_html_epilog(*$;$)
-{
-	my $basedir = $_[1];
-	my $break_code = "";
-	my $epilog;
-
-	if (defined($_[2]))
-	{
-		$break_code = " target=\"_parent\"";
-	}
-
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	  <table width="100%" border=0 cellspacing=0 cellpadding=0>
-	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
-	    <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_code>$lcov_version</a></td></tr>
-	  </table>
-	  <br>
-END_OF_HTML
-	;
-
-	$epilog = $html_epilog;
-	$epilog =~ s/\@basedir\@/$basedir/g;
-
-	write_html($_[0], $epilog);
-}
-
-
-#
-# write_frameset(filehandle, basedir, basename, pagetitle)
-#
-#
-
-sub write_frameset(*$$$)
-{
-	my $frame_width = $overview_width + 40;
-
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">
-
-	<html lang="en">
-
-	<head>
-	  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-	  <title>$_[3]</title>
-	  <link rel="stylesheet" type="text/css" href="$_[1]gcov.css">
-	</head>
-
-	<frameset cols="$frame_width,*">
-	  <frame src="$_[2].gcov.overview.$html_ext" name="overview">
-	  <frame src="$_[2].gcov.$html_ext" name="source">
-	  <noframes>
-	    <center>Frames not supported by your browser!<br></center>
-	  </noframes>
-	</frameset>
-
-	</html>
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# sub write_overview_line(filehandle, basename, line, link)
-#
-#
-
-sub write_overview_line(*$$$)
-{
-	my $y1 = $_[2] - 1;
-	my $y2 = $y1 + $nav_resolution - 1;
-	my $x2 = $overview_width - 1;
-
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	    <area shape="rect" coords="0,$y1,$x2,$y2" href="$_[1].gcov.$html_ext#$_[3]" target="source" alt="overview">
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_overview(filehandle, basedir, basename, pagetitle, lines)
-#
-#
-
-sub write_overview(*$$$$)
-{
-	my $index;
-	my $max_line = $_[4] - 1;
-	my $offset;
-
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-
-	<html lang="en">
-
-	<head>
-	  <title>$_[3]</title>
-	  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-	  <link rel="stylesheet" type="text/css" href="$_[1]gcov.css">
-	</head>
-
-	<body>
-	  <map name="overview">
-END_OF_HTML
-	;
-
-	# *************************************************************
-
-	# Make $offset the next higher multiple of $nav_resolution
-	$offset = ($nav_offset + $nav_resolution - 1) / $nav_resolution;
-	$offset = sprintf("%d", $offset ) * $nav_resolution;
-
-	# Create image map for overview image
-	for ($index = 1; $index <= $_[4]; $index += $nav_resolution)
-	{
-		# Enforce nav_offset
-		if ($index < $offset + 1)
-		{
-			write_overview_line($_[0], $_[2], $index, 1);
-		}
-		else
-		{
-			write_overview_line($_[0], $_[2], $index, $index - $offset);
-		}
-	}
-
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
-	  </map>
-
-	  <center>
-	  <a href="$_[2].gcov.$html_ext#top" target="source">Top</a><br><br>
-	  <img src="$_[2].gcov.png" width=$overview_width height=$max_line alt="Overview" border=0 usemap="#overview">
-	  </center>
-	</body>
-	</html>
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-# format_rate(found, hit)
-#
-# Return formatted percent string for coverage rate.
-#
-
-sub format_rate($$)
-{	
-	return $_[0] == 0 ? "-" : sprintf("%.1f", $_[1] * 100 / $_[0])." %";
-}
-
-
-sub max($$)
-{
-	my ($a, $b) = @_;
-
-	return $a if ($a > $b);
-	return $b;
-}
-
-
-#
-# write_header(filehandle, type, trunc_file_name, rel_file_name, lines_found,
-# lines_hit, funcs_found, funcs_hit, sort_type)
-#
-# Write a complete standard page header. TYPE may be (0, 1, 2, 3, 4)
-# corresponding to (directory view header, file view header, source view
-# header, test case description header, function view header)
-#
-
-sub write_header(*$$$$$$$$$$)
-{
-	local *HTML_HANDLE = $_[0];
-	my $type = $_[1];
-	my $trunc_name = $_[2];
-	my $rel_filename = $_[3];
-	my $lines_found = $_[4];
-	my $lines_hit = $_[5];
-	my $fn_found = $_[6];
-	my $fn_hit = $_[7];
-	my $br_found = $_[8];
-	my $br_hit = $_[9];
-	my $sort_type = $_[10];
-	my $base_dir;
-	my $view;
-	my $test;
-	my $base_name;
-	my $style;
-	my $rate;
-	my @row_left;
-	my @row_right;
-	my $num_rows;
-	my $i;
-
-	$base_name = basename($rel_filename);
-
-	# Prepare text for "current view" field
-	if ($type == $HDR_DIR)
-	{
-		# Main overview
-		$base_dir = "";
-		$view = $overview_title;
-	}
-	elsif ($type == $HDR_FILE)
-	{
-		# Directory overview
-		$base_dir = get_relative_base_path($rel_filename);
-		$view = "<a href=\"$base_dir"."index.$html_ext\">".
-			"$overview_title</a> - $trunc_name";
-	}
-	elsif ($type == $HDR_SOURCE || $type == $HDR_FUNC)
-	{
-		# File view
-		my $dir_name = dirname($rel_filename);
-
-		$base_dir = get_relative_base_path($dir_name);
-		if ($frames)
-		{
-			# Need to break frameset when clicking any of these
-			# links
-			$view = "<a href=\"$base_dir"."index.$html_ext\" ".
-				"target=\"_parent\">$overview_title</a> - ".
-				"<a href=\"index.$html_ext\" target=\"_parent\">".
-				"$dir_name</a> - $base_name";
-		}
-		else
-		{
-			$view = "<a href=\"$base_dir"."index.$html_ext\">".
-				"$overview_title</a> - ".
-				"<a href=\"index.$html_ext\">".
-				"$dir_name</a> - $base_name";
-		}
-
-		# Add function suffix
-		if ($func_coverage) {
-			$view .= "<span style=\"font-size: 80%;\">";
-			if ($type == $HDR_SOURCE) {
-				$view .= " (source / <a href=\"$base_name.func.$html_ext\">functions</a>)";
-			} elsif ($type == $HDR_FUNC) {
-				$view .= " (<a href=\"$base_name.gcov.$html_ext\">source</a> / functions)";
-			}
-			$view .= "</span>";
-		}
-	}
-	elsif ($type == $HDR_TESTDESC)
-	{
-		# Test description header
-		$base_dir = "";
-		$view = "<a href=\"$base_dir"."index.$html_ext\">".
-			"$overview_title</a> - test case descriptions";
-	}
-
-	# Prepare text for "test" field
-	$test = escape_html($test_title);
-
-	# Append link to test description page if available
-	if (%test_description && ($type != $HDR_TESTDESC))
-	{
-		if ($frames && ($type == $HDR_SOURCE || $type == $HDR_FUNC))
-		{
-			# Need to break frameset when clicking this link
-			$test .= " ( <span style=\"font-size:80%;\">".
-				 "<a href=\"$base_dir".
-				 "descriptions.$html_ext\" target=\"_parent\">".
-				 "view descriptions</a></span> )";
-		}
-		else
-		{
-			$test .= " ( <span style=\"font-size:80%;\">".
-				 "<a href=\"$base_dir".
-				 "descriptions.$html_ext\">".
-				 "view descriptions</a></span> )";
-		}
-	}
-
-	# Write header
-	write_header_prolog(*HTML_HANDLE, $base_dir);
-
-	# Left row
-	push(@row_left, [[ "10%", "headerItem", "Current view:" ],
-			 [ "35%", "headerValue", $view ]]);
-	push(@row_left, [[undef, "headerItem", "Test:"],
-			 [undef, "headerValue", $test]]);
-	push(@row_left, [[undef, "headerItem", "Date:"],
-			 [undef, "headerValue", $date]]);
-
-	# Right row
-	if ($legend && ($type == $HDR_SOURCE || $type == $HDR_FUNC)) {
-		my $text = <<END_OF_HTML;
-            Lines:
-            <span class="coverLegendCov">hit</span>
-            <span class="coverLegendNoCov">not hit</span>
-END_OF_HTML
-		if ($br_coverage) {
-			$text .= <<END_OF_HTML;
-            | Branches:
-            <span class="coverLegendCov">+</span> taken
-            <span class="coverLegendNoCov">-</span> not taken
-            <span class="coverLegendNoCov">#</span> not executed
-END_OF_HTML
-		}
-		push(@row_left, [[undef, "headerItem", "Legend:"],
-				 [undef, "headerValueLeg", $text]]);
-	} elsif ($legend && ($type != $HDR_TESTDESC)) {
-		my $text = <<END_OF_HTML;
-	    Rating:
-            <span class="coverLegendCovLo" title="Coverage rates below $med_limit % are classified as low">low: &lt; $med_limit %</span>
-            <span class="coverLegendCovMed" title="Coverage rates between $med_limit % and $hi_limit % are classified as medium">medium: &gt;= $med_limit %</span>
-            <span class="coverLegendCovHi" title="Coverage rates of $hi_limit % and more are classified as high">high: &gt;= $hi_limit %</span>
-END_OF_HTML
-		push(@row_left, [[undef, "headerItem", "Legend:"],
-				 [undef, "headerValueLeg", $text]]);
-	}
-	if ($type == $HDR_TESTDESC) {
-		push(@row_right, [[ "55%" ]]);
-	} else {
-		push(@row_right, [["15%", undef, undef ],
-				  ["10%", "headerCovTableHead", "Hit" ],
-				  ["10%", "headerCovTableHead", "Total" ],
-				  ["15%", "headerCovTableHead", "Coverage"]]);
-	}
-	# Line coverage
-	$style = $rate_name[classify_rate($lines_found, $lines_hit,
-					  $med_limit, $hi_limit)];
-	$rate = format_rate($lines_found, $lines_hit);
-	push(@row_right, [[undef, "headerItem", "Lines:"],
-			  [undef, "headerCovTableEntry", $lines_hit],
-			  [undef, "headerCovTableEntry", $lines_found],
-			  [undef, "headerCovTableEntry$style", $rate]])
-			if ($type != $HDR_TESTDESC);
-	# Function coverage
-	if ($func_coverage) {
-		$style = $rate_name[classify_rate($fn_found, $fn_hit,
-						  $fn_med_limit, $fn_hi_limit)];
-		$rate = format_rate($fn_found, $fn_hit);
-		push(@row_right, [[undef, "headerItem", "Functions:"],
-				  [undef, "headerCovTableEntry", $fn_hit],
-				  [undef, "headerCovTableEntry", $fn_found],
-				  [undef, "headerCovTableEntry$style", $rate]])
-			if ($type != $HDR_TESTDESC);
-	}
-	# Branch coverage
-	if ($br_coverage) {
-		$style = $rate_name[classify_rate($br_found, $br_hit,
-						  $br_med_limit, $br_hi_limit)];
-		$rate = format_rate($br_found, $br_hit);
-		push(@row_right, [[undef, "headerItem", "Branches:"],
-				  [undef, "headerCovTableEntry", $br_hit],
-				  [undef, "headerCovTableEntry", $br_found],
-				  [undef, "headerCovTableEntry$style", $rate]])
-			if ($type != $HDR_TESTDESC);
-	}
-
-	# Print rows
-	$num_rows = max(scalar(@row_left), scalar(@row_right));
-	for ($i = 0; $i < $num_rows; $i++) {
-		my $left = $row_left[$i];
-		my $right = $row_right[$i];
-
-		if (!defined($left)) {
-			$left = [[undef, undef, undef], [undef, undef, undef]];
-		}
-		if (!defined($right)) {
-			$right = [];
-		}
-		write_header_line(*HTML_HANDLE, @{$left},
-				  [ $i == 0 ? "5%" : undef, undef, undef],
-				  @{$right});
-	}
-
-	# Fourth line
-	write_header_epilog(*HTML_HANDLE, $base_dir);
-}
-
-
-#
-# get_sorted_keys(hash_ref, sort_type)
-#
-
-sub get_sorted_keys($$)
-{
-	my ($hash, $type) = @_;
-
-	if ($type == $SORT_FILE) {
-		# Sort by name
-		return sort(keys(%{$hash}));
-	} elsif ($type == $SORT_LINE) {
-		# Sort by line coverage
-		return sort({$hash->{$a}[7] <=> $hash->{$b}[7]} keys(%{$hash}));
-	} elsif ($type == $SORT_FUNC) {
-		# Sort by function coverage;
-		return sort({$hash->{$a}[8] <=> $hash->{$b}[8]}	keys(%{$hash}));
-	} elsif ($type == $SORT_BRANCH) {
-		# Sort by br coverage;
-		return sort({$hash->{$a}[9] <=> $hash->{$b}[9]}	keys(%{$hash}));
-	}
-}
-
-sub get_sort_code($$$)
-{
-	my ($link, $alt, $base) = @_;
-	my $png;
-	my $link_start;
-	my $link_end;
-
-	if (!defined($link)) {
-		$png = "glass.png";
-		$link_start = "";
-		$link_end = "";
-	} else {
-		$png = "updown.png";
-		$link_start = '<a href="'.$link.'">';
-		$link_end = "</a>";
-	}
-
-	return ' <span class="tableHeadSort">'.$link_start.
-	       '<img src="'.$base.$png.'" width=10 height=14 '.
-	       'alt="'.$alt.'" title="'.$alt.'" border=0>'.$link_end.'</span>';
-}
-
-sub get_file_code($$$$)
-{
-	my ($type, $text, $sort_button, $base) = @_;
-	my $result = $text;
-	my $link;
-
-	if ($sort_button) {
-		if ($type == $HEAD_NO_DETAIL) {
-			$link = "index.$html_ext";
-		} else {
-			$link = "index-detail.$html_ext";
-		}
-	}
-	$result .= get_sort_code($link, "Sort by name", $base);
-
-	return $result;
-}
-
-sub get_line_code($$$$$)
-{
-	my ($type, $sort_type, $text, $sort_button, $base) = @_;
-	my $result = $text;
-	my $sort_link;
-
-	if ($type == $HEAD_NO_DETAIL) {
-		# Just text
-		if ($sort_button) {
-			$sort_link = "index-sort-l.$html_ext";
-		}
-	} elsif ($type == $HEAD_DETAIL_HIDDEN) {
-		# Text + link to detail view
-		$result .= ' ( <a class="detail" href="index-detail'.
-			   $fileview_sortname[$sort_type].'.'.$html_ext.
-			   '">show details</a> )';
-		if ($sort_button) {
-			$sort_link = "index-sort-l.$html_ext";
-		}
-	} else {
-		# Text + link to standard view
-		$result .= ' ( <a class="detail" href="index'.
-			   $fileview_sortname[$sort_type].'.'.$html_ext.
-			   '">hide details</a> )';
-		if ($sort_button) {
-			$sort_link = "index-detail-sort-l.$html_ext";
-		}
-	}
-	# Add sort button
-	$result .= get_sort_code($sort_link, "Sort by line coverage", $base);
-
-	return $result;
-}
-
-sub get_func_code($$$$)
-{
-	my ($type, $text, $sort_button, $base) = @_;
-	my $result = $text;
-	my $link;
-
-	if ($sort_button) {
-		if ($type == $HEAD_NO_DETAIL) {
-			$link = "index-sort-f.$html_ext";
-		} else {
-			$link = "index-detail-sort-f.$html_ext";
-		}
-	}
-	$result .= get_sort_code($link, "Sort by function coverage", $base);
-	return $result;
-}
-
-sub get_br_code($$$$)
-{
-	my ($type, $text, $sort_button, $base) = @_;
-	my $result = $text;
-	my $link;
-
-	if ($sort_button) {
-		if ($type == $HEAD_NO_DETAIL) {
-			$link = "index-sort-b.$html_ext";
-		} else {
-			$link = "index-detail-sort-b.$html_ext";
-		}
-	}
-	$result .= get_sort_code($link, "Sort by branch coverage", $base);
-	return $result;
-}
-
-#
-# write_file_table(filehandle, base_dir, overview, testhash, testfnchash,
-#                  testbrhash, fileview, sort_type)
-#
-# Write a complete file table. OVERVIEW is a reference to a hash containing
-# the following mapping:
-#
-#   filename -> "lines_found,lines_hit,funcs_found,funcs_hit,page_link,
-#		 func_link"
-#
-# TESTHASH is a reference to the following hash:
-#
-#   filename -> \%testdata
-#   %testdata: name of test affecting this file -> \%testcount
-#   %testcount: line number -> execution count for a single test
-#
-# Heading of first column is "Filename" if FILEVIEW is true, "Directory name"
-# otherwise.
-#
-
-sub write_file_table(*$$$$$$$)
-{
-	local *HTML_HANDLE = $_[0];
-	my $base_dir = $_[1];
-	my $overview = $_[2];
-	my $testhash = $_[3];
-	my $testfnchash = $_[4];
-	my $testbrhash = $_[5];
-	my $fileview = $_[6];
-	my $sort_type = $_[7];
-	my $filename;
-	my $bar_graph;
-	my $hit;
-	my $found;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-	my $page_link;
-	my $testname;
-	my $testdata;
-	my $testfncdata;
-	my $testbrdata;
-	my %affecting_tests;
-	my $line_code = "";
-	my $func_code;
-	my $br_code;
-	my $file_code;
-	my @head_columns;
-
-	# Determine HTML code for column headings
-	if (($base_dir ne "") && $show_details)
-	{
-		my $detailed = keys(%{$testhash});
-
-		$file_code = get_file_code($detailed ? $HEAD_DETAIL_HIDDEN :
-					$HEAD_NO_DETAIL,
-					$fileview ? "Filename" : "Directory",
-					$sort && $sort_type != $SORT_FILE,
-					$base_dir);
-		$line_code = get_line_code($detailed ? $HEAD_DETAIL_SHOWN :
-					$HEAD_DETAIL_HIDDEN,
-					$sort_type,
-					"Line Coverage",
-					$sort && $sort_type != $SORT_LINE,
-					$base_dir);
-		$func_code = get_func_code($detailed ? $HEAD_DETAIL_HIDDEN :
-					$HEAD_NO_DETAIL,
-					"Functions",
-					$sort && $sort_type != $SORT_FUNC,
-					$base_dir);
-		$br_code = get_br_code($detailed ? $HEAD_DETAIL_HIDDEN :
-					$HEAD_NO_DETAIL,
-					"Branches",
-					$sort && $sort_type != $SORT_BRANCH,
-					$base_dir);
-	} else {
-		$file_code = get_file_code($HEAD_NO_DETAIL,
-					$fileview ? "Filename" : "Directory",
-					$sort && $sort_type != $SORT_FILE,
-					$base_dir);
-		$line_code = get_line_code($HEAD_NO_DETAIL, $sort_type, "Line Coverage",
-					$sort && $sort_type != $SORT_LINE,
-					$base_dir);
-		$func_code = get_func_code($HEAD_NO_DETAIL, "Functions",
-					$sort && $sort_type != $SORT_FUNC,
-					$base_dir);
-		$br_code = get_br_code($HEAD_NO_DETAIL, "Branches",
-					$sort && $sort_type != $SORT_BRANCH,
-					$base_dir);
-	}
-	push(@head_columns, [ $line_code, 3 ]);
-	push(@head_columns, [ $func_code, 2]) if ($func_coverage);
-	push(@head_columns, [ $br_code, 2]) if ($br_coverage);
-
-	write_file_table_prolog(*HTML_HANDLE, $file_code, @head_columns);
-
-	foreach $filename (get_sorted_keys($overview, $sort_type))
-	{
-		my @columns;
-		($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit,
-		 $page_link) = @{$overview->{$filename}};
-
-		# Line coverage
-		push(@columns, [$found, $hit, $med_limit, $hi_limit, 1]);
-		# Function coverage
-		if ($func_coverage) {
-			push(@columns, [$fn_found, $fn_hit, $fn_med_limit,
-					$fn_hi_limit, 0]);
-		}
-		# Branch coverage
-		if ($br_coverage) {
-			push(@columns, [$br_found, $br_hit, $br_med_limit,
-					$br_hi_limit, 0]);
-		}
-		write_file_table_entry(*HTML_HANDLE, $base_dir, $filename,
-				       $page_link, @columns);
-
-		$testdata = $testhash->{$filename};
-		$testfncdata = $testfnchash->{$filename};
-		$testbrdata = $testbrhash->{$filename};
-
-		# Check whether we should write test specific coverage
-		# as well
-		if (!($show_details && $testdata)) { next; }
-
-		# Filter out those tests that actually affect this file
-		%affecting_tests = %{ get_affecting_tests($testdata,
-					$testfncdata, $testbrdata) };
-
-		# Does any of the tests affect this file at all?
-		if (!%affecting_tests) { next; }
-
-		foreach $testname (keys(%affecting_tests))
-		{
-			my @results;
-			($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
-				split(",", $affecting_tests{$testname});
-
-			# Insert link to description of available
-			if ($test_description{$testname})
-			{
-				$testname = "<a href=\"$base_dir".
-					    "descriptions.$html_ext#$testname\">".
-					    "$testname</a>";
-			}
-
-			push(@results, [$found, $hit]);
-			push(@results, [$fn_found, $fn_hit]) if ($func_coverage);
-			push(@results, [$br_found, $br_hit]) if ($br_coverage);
-			write_file_table_detail_entry(*HTML_HANDLE, $testname,
-				@results);
-		}
-	}
-
-	write_file_table_epilog(*HTML_HANDLE);
-}
-
-
-#
-# get_found_and_hit(hash)
-#
-# Return the count for entries (found) and entries with an execution count
-# greater than zero (hit) in a hash (linenumber -> execution count) as
-# a list (found, hit)
-#
-
-sub get_found_and_hit($)
-{
-	my %hash = %{$_[0]};
-	my $found = 0;
-	my $hit = 0;
-
-	# Calculate sum
-	$found = 0;
-	$hit = 0;
-			
-	foreach (keys(%hash))
-	{
-		$found++;
-		if ($hash{$_}>0) { $hit++; }
-	}
-
-	return ($found, $hit);
-}
-
-
-#
-# get_func_found_and_hit(sumfnccount)
-#
-# Return (f_found, f_hit) for sumfnccount
-#
-
-sub get_func_found_and_hit($)
-{
-	my ($sumfnccount) = @_;
-	my $function;
-	my $fn_found;
-	my $fn_hit;
-
-	$fn_found = scalar(keys(%{$sumfnccount}));
-	$fn_hit = 0;
-	foreach $function (keys(%{$sumfnccount})) {
-		if ($sumfnccount->{$function} > 0) {
-			$fn_hit++;
-		}
-	}
-	return ($fn_found, $fn_hit);
-}
-
-
-#
-# br_taken_to_num(taken)
-#
-# Convert a branch taken value .info format to number format.
-#
-
-sub br_taken_to_num($)
-{
-	my ($taken) = @_;
-
-	return 0 if ($taken eq '-');
-	return $taken + 1;
-}
-
-
-#
-# br_num_to_taken(taken)
-#
-# Convert a branch taken value in number format to .info format.
-#
-
-sub br_num_to_taken($)
-{
-	my ($taken) = @_;
-
-	return '-' if ($taken == 0);
-	return $taken - 1;
-}
-
-
-#
-# br_taken_add(taken1, taken2)
-#
-# Return the result of taken1 + taken2 for 'branch taken' values.
-#
-
-sub br_taken_add($$)
-{
-	my ($t1, $t2) = @_;
-
-	return $t1 if (!defined($t2));
-	return $t2 if (!defined($t1));
-	return $t1 if ($t2 eq '-');
-	return $t2 if ($t1 eq '-');
-	return $t1 + $t2;
-}
-
-
-#
-# br_taken_sub(taken1, taken2)
-#
-# Return the result of taken1 - taken2 for 'branch taken' values. Return 0
-# if the result would become negative.
-#
-
-sub br_taken_sub($$)
-{
-	my ($t1, $t2) = @_;
-
-	return $t1 if (!defined($t2));
-	return undef if (!defined($t1));
-	return $t1 if ($t1 eq '-');
-	return $t1 if ($t2 eq '-');
-	return 0 if $t2 > $t1;
-	return $t1 - $t2;
-}
-
-
-#
-# br_ivec_len(vector)
-#
-# Return the number of entries in the branch coverage vector.
-#
-
-sub br_ivec_len($)
-{
-	my ($vec) = @_;
-
-	return 0 if (!defined($vec));
-	return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
-}
-
-
-#
-# br_ivec_get(vector, number)
-#
-# Return an entry from the branch coverage vector.
-#
-
-sub br_ivec_get($$)
-{
-	my ($vec, $num) = @_;
-	my $block;
-	my $branch;
-	my $taken;
-	my $offset = $num * $BR_VEC_ENTRIES;
-
-	# Retrieve data from vector
-	$block	= vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
-	$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
-	$taken	= vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
-
-	# Decode taken value from an integer
-	$taken = br_num_to_taken($taken);
-
-	return ($block, $branch, $taken);
-}
-
-
-#
-# br_ivec_push(vector, block, branch, taken)
-#
-# Add an entry to the branch coverage vector. If an entry with the same
-# branch ID already exists, add the corresponding taken values.
-#
-
-sub br_ivec_push($$$$)
-{
-	my ($vec, $block, $branch, $taken) = @_;
-	my $offset;
-	my $num = br_ivec_len($vec);
-	my $i;
-
-	$vec = "" if (!defined($vec));
-
-	# Check if branch already exists in vector
-	for ($i = 0; $i < $num; $i++) {
-		my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
-
-		next if ($v_block != $block || $v_branch != $branch);
-
-		# Add taken counts
-		$taken = br_taken_add($taken, $v_taken);
-		last;
-	}
-
-	$offset = $i * $BR_VEC_ENTRIES;
-	$taken = br_taken_to_num($taken);
-
-	# Add to vector
-	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
-	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
-	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
-
-	return $vec;
-}
-
-
-#
-# get_br_found_and_hit(sumbrcount)
-#
-# Return (br_found, br_hit) for sumbrcount
-#
-
-sub get_br_found_and_hit($)
-{
-	my ($sumbrcount) = @_;
-	my $line;
-	my $br_found = 0;
-	my $br_hit = 0;
-
-	foreach $line (keys(%{$sumbrcount})) {
-		my $brdata = $sumbrcount->{$line};
-		my $i;
-		my $num = br_ivec_len($brdata);
-
-		for ($i = 0; $i < $num; $i++) {
-			my $taken;
-
-			(undef, undef, $taken) = br_ivec_get($brdata, $i);
-
-			$br_found++;
-			$br_hit++ if ($taken ne "-" && $taken > 0);
-		}
-	}
-
-	return ($br_found, $br_hit);
-}
-
-
-#
-# get_affecting_tests(testdata, testfncdata, testbrdata)
-#
-# HASHREF contains a mapping filename -> (linenumber -> exec count). Return
-# a hash containing mapping filename -> "lines found, lines hit" for each
-# filename which has a nonzero hit count.
-#
-
-sub get_affecting_tests($$$)
-{
-	my ($testdata, $testfncdata, $testbrdata) = @_;
-	my $testname;
-	my $testcount;
-	my $testfnccount;
-	my $testbrcount;
-	my %result;
-	my $found;
-	my $hit;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-
-	foreach $testname (keys(%{$testdata}))
-	{
-		# Get (line number -> count) hash for this test case
-		$testcount = $testdata->{$testname};
-		$testfnccount = $testfncdata->{$testname};
-		$testbrcount = $testbrdata->{$testname};
-
-		# Calculate sum
-		($found, $hit) = get_found_and_hit($testcount);
-		($fn_found, $fn_hit) = get_func_found_and_hit($testfnccount);
-		($br_found, $br_hit) = get_br_found_and_hit($testbrcount);
-
-		if ($hit>0)
-		{
-			$result{$testname} = "$found,$hit,$fn_found,$fn_hit,".
-					     "$br_found,$br_hit";
-		}
-	}
-
-	return(\%result);
-}
-
-
-sub get_hash_reverse($)
-{
-	my ($hash) = @_;
-	my %result;
-
-	foreach (keys(%{$hash})) {
-		$result{$hash->{$_}} = $_;
-	}
-
-	return \%result;
-}
-
-#
-# write_source(filehandle, source_filename, count_data, checksum_data,
-#              converted_data, func_data, sumbrcount)
-#
-# Write an HTML view of a source code file. Returns a list containing
-# data as needed by gen_png().
-#
-# Die on error.
-#
-
-sub write_source($$$$$$$)
-{
-	local *HTML_HANDLE = $_[0];
-	local *SOURCE_HANDLE;
-	my $source_filename = $_[1];
-	my %count_data;
-	my $line_number;
-	my @result;
-	my $checkdata = $_[3];
-	my $converted = $_[4];
-	my $funcdata  = $_[5];
-	my $sumbrcount = $_[6];
-	my $datafunc = get_hash_reverse($funcdata);
-	my $add_anchor;
-
-	if ($_[2])
-	{
-		%count_data = %{$_[2]};
-	}
-
-	open(SOURCE_HANDLE, "<".$source_filename)
-		or die("ERROR: cannot open $source_filename for reading!\n");
-	
-	write_source_prolog(*HTML_HANDLE);
-
-	for ($line_number = 1; <SOURCE_HANDLE> ; $line_number++)
-	{
-		chomp($_);
-
-		# Also remove CR from line-end
-		s/\015$//;
-
-		# Source code matches coverage data?
-		if (defined($checkdata->{$line_number}) &&
-		    ($checkdata->{$line_number} ne md5_base64($_)))
-		{
-			die("ERROR: checksum mismatch  at $source_filename:".
-			    "$line_number\n");
-		}
-
-		$add_anchor = 0;
-		if ($frames) {
-			if (($line_number - 1) % $nav_resolution == 0) {
-				$add_anchor = 1;
-			}
-		}
-		if ($func_coverage) {
-			if ($line_number == 1) {
-				$add_anchor = 1;
-			} elsif (defined($datafunc->{$line_number +
-						     $func_offset})) {
-				$add_anchor = 1;
-			}
-		}
-		push (@result,
-		      write_source_line(HTML_HANDLE, $line_number,
-					$_, $count_data{$line_number},
-					$converted->{$line_number},
-					$sumbrcount->{$line_number}, $add_anchor));
-	}
-
-	close(SOURCE_HANDLE);
-	write_source_epilog(*HTML_HANDLE);
-	return(@result);
-}
-
-
-sub funcview_get_func_code($$$)
-{
-	my ($name, $base, $type) = @_;
-	my $result;
-	my $link;
-
-	if ($sort && $type == 1) {
-		$link = "$name.func.$html_ext";
-	}
-	$result = "Function Name";
-	$result .= get_sort_code($link, "Sort by function name", $base);
-
-	return $result;
-}
-
-sub funcview_get_count_code($$$)
-{
-	my ($name, $base, $type) = @_;
-	my $result;
-	my $link;
-
-	if ($sort && $type == 0) {
-		$link = "$name.func-sort-c.$html_ext";
-	}
-	$result = "Hit count";
-	$result .= get_sort_code($link, "Sort by hit count", $base);
-
-	return $result;
-}
-
-#
-# funcview_get_sorted(funcdata, sumfncdata, sort_type)
-#
-# Depending on the value of sort_type, return a list of functions sorted
-# by name (type 0) or by the associated call count (type 1).
-#
-
-sub funcview_get_sorted($$$)
-{
-	my ($funcdata, $sumfncdata, $type) = @_;
-
-	if ($type == 0) {
-		return sort(keys(%{$funcdata}));
-	}
-	return sort({$sumfncdata->{$b} <=> $sumfncdata->{$a}}
-		    keys(%{$sumfncdata}));
-}
-
-#
-# write_function_table(filehandle, source_file, sumcount, funcdata,
-#		       sumfnccount, testfncdata, sumbrcount, testbrdata,
-#		       base_name, base_dir, sort_type)
-#
-# Write an HTML table listing all functions in a source file, including
-# also function call counts and line coverages inside of each function.
-#
-# Die on error.
-#
-
-sub write_function_table(*$$$$$$$$$$)
-{
-	local *HTML_HANDLE = $_[0];
-	my $source = $_[1];
-	my $sumcount = $_[2];
-	my $funcdata = $_[3];
-	my $sumfncdata = $_[4];
-	my $testfncdata = $_[5];
-	my $sumbrcount = $_[6];
-	my $testbrdata = $_[7];
-	my $name = $_[8];
-	my $base = $_[9];
-	my $type = $_[10];
-	my $func;
-	my $func_code;
-	my $count_code;
-
-	# Get HTML code for headings
-	$func_code = funcview_get_func_code($name, $base, $type);
-	$count_code = funcview_get_count_code($name, $base, $type);
-	write_html(*HTML_HANDLE, <<END_OF_HTML)
-	  <center>
-	  <table width="60%" cellpadding=1 cellspacing=1 border=0>
-	    <tr><td><br></td></tr>
-	    <tr>
-	      <td width="80%" class="tableHead">$func_code</td>
-	      <td width="20%" class="tableHead">$count_code</td>
-	    </tr>
-END_OF_HTML
-	;
-	
-	# Get a sorted table
-	foreach $func (funcview_get_sorted($funcdata, $sumfncdata, $type)) {
-		if (!defined($funcdata->{$func}))
-		{
-			next;
-		}
-
-		my $startline = $funcdata->{$func} - $func_offset;
-		my $name = $func;
-		my $count = $sumfncdata->{$name};
-		my $countstyle;
-
-		# Demangle C++ function names if requested
-		if ($demangle_cpp) {
-			$name = `c++filt "$name"`;
-			chomp($name);
-		}
-		# Escape any remaining special characters
-		$name = escape_html($name);
-		if ($startline < 1) {
-			$startline = 1;
-		}
-		if ($count == 0) {
-			$countstyle = "coverFnLo";
-		} else {
-			$countstyle = "coverFnHi";
-		}
-
-		write_html(*HTML_HANDLE, <<END_OF_HTML)
-	    <tr>
-              <td class="coverFn"><a href="$source#$startline">$name</a></td>
-              <td class="$countstyle">$count</td>
-            </tr>
-END_OF_HTML
-                ;
-	}
-	write_html(*HTML_HANDLE, <<END_OF_HTML)
-	  </table>
-	  <br>
-	  </center>
-END_OF_HTML
-	;
-}
-
-
-#
-# info(printf_parameter)
-#
-# Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag
-# is not set.
-#
-
-sub info(@)
-{
-	if (!$quiet)
-	{
-		# Print info string
-		printf(@_);
-	}
-}
-
-
-#
-# subtract_counts(data_ref, base_ref)
-#
-
-sub subtract_counts($$)
-{
-	my %data = %{$_[0]};
-	my %base = %{$_[1]};
-	my $line;
-	my $data_count;
-	my $base_count;
-	my $hit = 0;
-	my $found = 0;
-
-	foreach $line (keys(%data))
-	{
-		$found++;
-		$data_count = $data{$line};
-		$base_count = $base{$line};
-
-		if (defined($base_count))
-		{
-			$data_count -= $base_count;
-
-			# Make sure we don't get negative numbers
-			if ($data_count<0) { $data_count = 0; }
-		}
-
-		$data{$line} = $data_count;
-		if ($data_count > 0) { $hit++; }
-	}
-
-	return (\%data, $found, $hit);
-}
-
-
-#
-# subtract_fnccounts(data, base)
-#
-# Subtract function call counts found in base from those in data.
-# Return (data, f_found, f_hit).
-#
-
-sub subtract_fnccounts($$)
-{
-	my %data;
-	my %base;
-	my $func;
-	my $data_count;
-	my $base_count;
-	my $fn_hit = 0;
-	my $fn_found = 0;
-
-	%data = %{$_[0]} if (defined($_[0]));
-	%base = %{$_[1]} if (defined($_[1]));
-	foreach $func (keys(%data)) {
-		$fn_found++;
-		$data_count = $data{$func};
-		$base_count = $base{$func};
-
-		if (defined($base_count)) {
-			$data_count -= $base_count;
-
-			# Make sure we don't get negative numbers
-			if ($data_count < 0) {
-				$data_count = 0;
-			}
-		}
-
-		$data{$func} = $data_count;
-		if ($data_count > 0) {
-			$fn_hit++;
-		}
-	}
-
-	return (\%data, $fn_found, $fn_hit);
-}
-
-
-#
-# apply_baseline(data_ref, baseline_ref)
-#
-# Subtract the execution counts found in the baseline hash referenced by
-# BASELINE_REF from actual data in DATA_REF.
-#
-
-sub apply_baseline($$)
-{
-	my %data_hash = %{$_[0]};
-	my %base_hash = %{$_[1]};
-	my $filename;
-	my $testname;
-	my $data;
-	my $data_testdata;
-	my $data_funcdata;
-	my $data_checkdata;
-	my $data_testfncdata;
-	my $data_testbrdata;
-	my $data_count;
-	my $data_testfnccount;
-	my $data_testbrcount;
-	my $base;
-	my $base_checkdata;
-	my $base_sumfnccount;
-	my $base_sumbrcount;
-	my $base_count;
-	my $sumcount;
-	my $sumfnccount;
-	my $sumbrcount;
-	my $found;
-	my $hit;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-
-	foreach $filename (keys(%data_hash))
-	{
-		# Get data set for data and baseline
-		$data = $data_hash{$filename};
-		$base = $base_hash{$filename};
-
-		# Skip data entries for which no base entry exists
-		if (!defined($base))
-		{
-			next;
-		}
-
-		# Get set entries for data and baseline
-		($data_testdata, undef, $data_funcdata, $data_checkdata,
-		 $data_testfncdata, undef, $data_testbrdata) =
-			get_info_entry($data);
-		(undef, $base_count, undef, $base_checkdata, undef,
-		 $base_sumfnccount, undef, $base_sumbrcount) =
-			get_info_entry($base);
-
-		# Check for compatible checksums
-		merge_checksums($data_checkdata, $base_checkdata, $filename);
-
-		# sumcount has to be calculated anew
-		$sumcount = {};
-		$sumfnccount = {};
-		$sumbrcount = {};
-
-		# For each test case, subtract test specific counts
-		foreach $testname (keys(%{$data_testdata}))
-		{
-			# Get counts of both data and baseline
-			$data_count = $data_testdata->{$testname};
-			$data_testfnccount = $data_testfncdata->{$testname};
-			$data_testbrcount = $data_testbrdata->{$testname};
-
-			($data_count, undef, $hit) =
-				subtract_counts($data_count, $base_count);
-			($data_testfnccount) =
-				subtract_fnccounts($data_testfnccount,
-						   $base_sumfnccount);
-			($data_testbrcount) =
-				combine_brcount($data_testbrcount,
-						 $base_sumbrcount, $BR_SUB);
-
-
-			# Check whether this test case did hit any line at all
-			if ($hit > 0)
-			{
-				# Write back resulting hash
-				$data_testdata->{$testname} = $data_count;
-				$data_testfncdata->{$testname} =
-					$data_testfnccount;
-				$data_testbrdata->{$testname} =
-					$data_testbrcount;
-			}
-			else
-			{
-				# Delete test case which did not impact this
-				# file
-				delete($data_testdata->{$testname});
-				delete($data_testfncdata->{$testname});
-				delete($data_testbrdata->{$testname});
-			}
-
-			# Add counts to sum of counts
-			($sumcount, $found, $hit) =
-				add_counts($sumcount, $data_count);
-			($sumfnccount, $fn_found, $fn_hit) =
-				add_fnccount($sumfnccount, $data_testfnccount);
-			($sumbrcount, $br_found, $br_hit) =
-				combine_brcount($sumbrcount, $data_testbrcount,
-						$BR_ADD);
-		}
-
-		# Write back resulting entry
-		set_info_entry($data, $data_testdata, $sumcount, $data_funcdata,
-			       $data_checkdata, $data_testfncdata, $sumfnccount,
-			       $data_testbrdata, $sumbrcount, $found, $hit,
-			       $fn_found, $fn_hit, $br_found, $br_hit);
-
-		$data_hash{$filename} = $data;
-	}
-
-	return (\%data_hash);
-}
-
-
-#
-# remove_unused_descriptions()
-#
-# Removes all test descriptions from the global hash %test_description which
-# are not present in %info_data.
-#
-
-sub remove_unused_descriptions()
-{
-	my $filename;		# The current filename
-	my %test_list;		# Hash containing found test names
-	my $test_data;		# Reference to hash test_name -> count_data
-	my $before;		# Initial number of descriptions
-	my $after;		# Remaining number of descriptions
-	
-	$before = scalar(keys(%test_description));
-
-	foreach $filename (keys(%info_data))
-	{
-		($test_data) = get_info_entry($info_data{$filename});
-		foreach (keys(%{$test_data}))
-		{
-			$test_list{$_} = "";
-		}
-	}
-
-	# Remove descriptions for tests which are not in our list
-	foreach (keys(%test_description))
-	{
-		if (!defined($test_list{$_}))
-		{
-			delete($test_description{$_});
-		}
-	}
-
-	$after = scalar(keys(%test_description));
-	if ($after < $before)
-	{
-		info("Removed ".($before - $after).
-		     " unused descriptions, $after remaining.\n");
-	}
-}
-
-
-#
-# apply_prefix(filename, prefix)
-#
-# If FILENAME begins with PREFIX, remove PREFIX from FILENAME and return
-# resulting string, otherwise return FILENAME.
-#
-
-sub apply_prefix($$)
-{
-	my $filename = $_[0];
-	my $prefix = $_[1];
-
-	if (defined($prefix) && ($prefix ne ""))
-	{
-		if ($filename =~ /^\Q$prefix\E\/(.*)$/)
-		{
-			return substr($filename, length($prefix) + 1);
-		}
-	}
-
-	return $filename;
-}
-
-
-#
-# system_no_output(mode, parameters)
-#
-# Call an external program using PARAMETERS while suppressing depending on
-# the value of MODE:
-#
-#   MODE & 1: suppress STDOUT
-#   MODE & 2: suppress STDERR
-#
-# Return 0 on success, non-zero otherwise.
-#
-
-sub system_no_output($@)
-{
-	my $mode = shift;
-	my $result;
-	local *OLD_STDERR;
-	local *OLD_STDOUT;
-
-	# Save old stdout and stderr handles
-	($mode & 1) && open(OLD_STDOUT, ">>&STDOUT");
-	($mode & 2) && open(OLD_STDERR, ">>&STDERR");
-
-	# Redirect to /dev/null
-	($mode & 1) && open(STDOUT, ">/dev/null");
-	($mode & 2) && open(STDERR, ">/dev/null");
-
-	system(@_);
-	$result = $?;
-
-	# Close redirected handles
-	($mode & 1) && close(STDOUT);
-	($mode & 2) && close(STDERR);
-
-	# Restore old handles
-	($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
-	($mode & 2) && open(STDERR, ">>&OLD_STDERR");
-
-	return $result;
-}
-
-
-#
-# read_config(filename)
-#
-# Read configuration file FILENAME and return a reference to a hash containing
-# all valid key=value pairs found.
-#
-
-sub read_config($)
-{
-	my $filename = $_[0];
-	my %result;
-	my $key;
-	my $value;
-	local *HANDLE;
-
-	if (!open(HANDLE, "<$filename"))
-	{
-		warn("WARNING: cannot read configuration file $filename\n");
-		return undef;
-	}
-	while (<HANDLE>)
-	{
-		chomp;
-		# Skip comments
-		s/#.*//;
-		# Remove leading blanks
-		s/^\s+//;
-		# Remove trailing blanks
-		s/\s+$//;
-		next unless length;
-		($key, $value) = split(/\s*=\s*/, $_, 2);
-		if (defined($key) && defined($value))
-		{
-			$result{$key} = $value;
-		}
-		else
-		{
-			warn("WARNING: malformed statement in line $. ".
-			     "of configuration file $filename\n");
-		}
-	}
-	close(HANDLE);
-	return \%result;
-}
-
-
-#
-# apply_config(REF)
-#
-# REF is a reference to a hash containing the following mapping:
-#
-#   key_string => var_ref
-#
-# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
-# variable. If the global configuration hash CONFIG contains a value for
-# keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
-#
-
-sub apply_config($)
-{
-	my $ref = $_[0];
-
-	foreach (keys(%{$ref}))
-	{
-		if (defined($config->{$_}))
-		{
-			${$ref->{$_}} = $config->{$_};
-		}
-	}
-}
-
-
-#
-# get_html_prolog(FILENAME)
-#
-# If FILENAME is defined, return contents of file. Otherwise return default
-# HTML prolog. Die on error.
-#
-
-sub get_html_prolog($)
-{
-	my $filename = $_[0];
-	my $result = "";
-
-	if (defined($filename))
-	{
-		local *HANDLE;
-
-		open(HANDLE, "<".$filename)
-			or die("ERROR: cannot open html prolog $filename!\n");
-		while (<HANDLE>)
-		{
-			$result .= $_;
-		}
-		close(HANDLE);
-	}
-	else
-	{
-		$result = <<END_OF_HTML
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-
-<html lang="en">
-
-<head>
-  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-  <title>\@pagetitle\@</title>
-  <link rel="stylesheet" type="text/css" href="\@basedir\@gcov.css">
-</head>
-
-<body>
-
-END_OF_HTML
-		;
-	}
-
-	return $result;
-}
-
-
-#
-# get_html_epilog(FILENAME)
-#
-# If FILENAME is defined, return contents of file. Otherwise return default
-# HTML epilog. Die on error.
-#
-sub get_html_epilog($)
-{
-	my $filename = $_[0];
-	my $result = "";
-
-	if (defined($filename))
-	{
-		local *HANDLE;
-
-		open(HANDLE, "<".$filename)
-			or die("ERROR: cannot open html epilog $filename!\n");
-		while (<HANDLE>)
-		{
-			$result .= $_;
-		}
-		close(HANDLE);
-	}
-	else
-	{
-		$result = <<END_OF_HTML
-
-</body>
-</html>
-END_OF_HTML
-		;
-	}
-
-	return $result;
-
-}
-
-sub warn_handler($)
-{
-	my ($msg) = @_;
-
-	warn("$tool_name: $msg");
-}
-
-sub die_handler($)
-{
-	my ($msg) = @_;
-
-	die("$tool_name: $msg");
-}
diff --git a/third_party/lcov-1.9/bin/geninfo b/third_party/lcov-1.9/bin/geninfo
deleted file mode 100755
index dcb1a67..0000000
--- a/third_party/lcov-1.9/bin/geninfo
+++ /dev/null
@@ -1,3068 +0,0 @@
-#!/usr/bin/perl -w
-#
-#   Copyright (c) International Business Machines  Corp., 2002,2010
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.                 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-#
-# geninfo
-#
-#   This script generates .info files from data files as created by code
-#   instrumented with gcc's built-in profiling mechanism. Call it with
-#   --help and refer to the geninfo man page to get information on usage
-#   and available options.
-#
-#
-# Authors:
-#   2002-08-23 created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-#                         IBM Lab Boeblingen
-#        based on code by Manoj Iyer <manjo@mail.utexas.edu> and
-#                         Megan Bock <mbock@us.ibm.com>
-#                         IBM Austin
-#   2002-09-05 / Peter Oberparleiter: implemented option that allows file list
-#   2003-04-16 / Peter Oberparleiter: modified read_gcov so that it can also
-#                parse the new gcov format which is to be introduced in gcc 3.3
-#   2003-04-30 / Peter Oberparleiter: made info write to STDERR, not STDOUT
-#   2003-07-03 / Peter Oberparleiter: added line checksum support, added
-#                --no-checksum
-#   2003-09-18 / Nigel Hinds: capture branch coverage data from GCOV
-#   2003-12-11 / Laurent Deniel: added --follow option
-#                workaround gcov (<= 3.2.x) bug with empty .da files
-#   2004-01-03 / Laurent Deniel: Ignore empty .bb files
-#   2004-02-16 / Andreas Krebbel: Added support for .gcno/.gcda files and
-#                gcov versioning
-#   2004-08-09 / Peter Oberparleiter: added configuration file support
-#   2008-07-14 / Tom Zoerner: added --function-coverage command line option
-#   2008-08-13 / Peter Oberparleiter: modified function coverage
-#                implementation (now enabled per default)
-#
-
-use strict;
-use File::Basename; 
-use File::Spec::Functions qw /abs2rel catdir file_name_is_absolute splitdir
-			      splitpath/;
-use Getopt::Long;
-use Digest::MD5 qw(md5_base64);
-
-
-# Constants
-our $lcov_version	= 'LCOV version 1.9';
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
-our $gcov_tool		= "gcov";
-our $tool_name		= basename($0);
-
-our $GCOV_VERSION_3_4_0	= 0x30400;
-our $GCOV_VERSION_3_3_0	= 0x30300;
-our $GCNO_FUNCTION_TAG	= 0x01000000;
-our $GCNO_LINES_TAG	= 0x01450000;
-our $GCNO_FILE_MAGIC	= 0x67636e6f;
-our $BBG_FILE_MAGIC	= 0x67626267;
-
-our $COMPAT_HAMMER	= "hammer";
-
-our $ERROR_GCOV		= 0;
-our $ERROR_SOURCE	= 1;
-our $ERROR_GRAPH	= 2;
-
-our $EXCL_START = "LCOV_EXCL_START";
-our $EXCL_STOP = "LCOV_EXCL_STOP";
-our $EXCL_LINE = "LCOV_EXCL_LINE";
-
-our $BR_LINE		= 0;
-our $BR_BLOCK		= 1;
-our $BR_BRANCH		= 2;
-our $BR_TAKEN		= 3;
-our $BR_VEC_ENTRIES	= 4;
-our $BR_VEC_WIDTH	= 32;
-
-our $UNNAMED_BLOCK	= 9999;
-
-# Prototypes
-sub print_usage(*);
-sub gen_info($);
-sub process_dafile($$);
-sub match_filename($@);
-sub solve_ambiguous_match($$$);
-sub split_filename($);
-sub solve_relative_path($$);
-sub read_gcov_header($);
-sub read_gcov_file($);
-sub info(@);
-sub get_gcov_version();
-sub system_no_output($@);
-sub read_config($);
-sub apply_config($);
-sub get_exclusion_data($);
-sub apply_exclusion_data($$);
-sub process_graphfile($$);
-sub filter_fn_name($);
-sub warn_handler($);
-sub die_handler($);
-sub graph_error($$);
-sub graph_expect($);
-sub graph_read(*$;$);
-sub graph_skip(*$;$);
-sub sort_uniq(@);
-sub sort_uniq_lex(@);
-sub graph_cleanup($);
-sub graph_find_base($);
-sub graph_from_bb($$$);
-sub graph_add_order($$$);
-sub read_bb_word(*;$);
-sub read_bb_value(*;$);
-sub read_bb_string(*$);
-sub read_bb($$);
-sub read_bbg_word(*;$);
-sub read_bbg_value(*;$);
-sub read_bbg_string(*);
-sub read_bbg_lines_record(*$$$$$$);
-sub read_bbg($$);
-sub read_gcno_word(*;$);
-sub read_gcno_value(*$;$);
-sub read_gcno_string(*$);
-sub read_gcno_lines_record(*$$$$$$$);
-sub read_gcno_function_record(*$$$$);
-sub read_gcno($$);
-sub get_gcov_capabilities();
-sub get_overall_line($$$$);
-sub print_overall_rate($$$$$$$$$);
-sub br_gvec_len($);
-sub br_gvec_get($$);
-sub debug($);
-sub int_handler();
-
-
-# Global variables
-our $gcov_version;
-our $graph_file_extension;
-our $data_file_extension;
-our @data_directory;
-our $test_name = "";
-our $quiet;
-our $help;
-our $output_filename;
-our $base_directory;
-our $version;
-our $follow;
-our $checksum;
-our $no_checksum;
-our $compat_libtool;
-our $no_compat_libtool;
-our $adjust_testname;
-our $config;		# Configuration file contents
-our $compatibility;	# Compatibility version flag - used to indicate
-			# non-standard GCOV data format versions
-our @ignore_errors;	# List of errors to ignore (parameter)
-our @ignore;		# List of errors to ignore (array)
-our $initial;
-our $no_recursion = 0;
-our $maxdepth;
-our $no_markers = 0;
-our $opt_derive_func_data = 0;
-our $debug = 0;
-our $gcov_caps;
-our @gcov_options;
-
-our $cwd = `pwd`;
-chomp($cwd);
-
-
-#
-# Code entry point
-#
-
-# Register handler routine to be called when interrupted
-$SIG{"INT"} = \&int_handler;
-$SIG{__WARN__} = \&warn_handler;
-$SIG{__DIE__} = \&die_handler;
-
-# Prettify version string
-$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
-
-# Set LANG so that gcov output will be in a unified format
-$ENV{"LANG"} = "C";
-
-# Read configuration file if available
-if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
-{
-	$config = read_config($ENV{"HOME"}."/.lcovrc");
-}
-elsif (-r "/etc/lcovrc")
-{
-	$config = read_config("/etc/lcovrc");
-}
-
-if ($config)
-{
-	# Copy configuration file values to variables
-	apply_config({
-		"geninfo_gcov_tool"		=> \$gcov_tool,
-		"geninfo_adjust_testname"	=> \$adjust_testname,
-		"geninfo_checksum"		=> \$checksum,
-		"geninfo_no_checksum"		=> \$no_checksum, # deprecated
-		"geninfo_compat_libtool"	=> \$compat_libtool});
-
-	# Merge options
-	if (defined($no_checksum))
-	{
-		$checksum = ($no_checksum ? 0 : 1);
-		$no_checksum = undef;
-	}
-}
-
-# Parse command line options
-if (!GetOptions("test-name|t=s" => \$test_name,
-		"output-filename|o=s" => \$output_filename,
-		"checksum" => \$checksum,
-		"no-checksum" => \$no_checksum,
-		"base-directory|b=s" => \$base_directory,
-		"version|v" =>\$version,
-		"quiet|q" => \$quiet,
-		"help|h|?" => \$help,
-		"follow|f" => \$follow,
-		"compat-libtool" => \$compat_libtool,
-		"no-compat-libtool" => \$no_compat_libtool,
-		"gcov-tool=s" => \$gcov_tool,
-		"ignore-errors=s" => \@ignore_errors,
-		"initial|i" => \$initial,
-		"no-recursion" => \$no_recursion,
-		"no-markers" => \$no_markers,
-		"derive-func-data" => \$opt_derive_func_data,
-		"debug" => \$debug,
-		))
-{
-	print(STDERR "Use $tool_name --help to get usage information\n");
-	exit(1);
-}
-else
-{
-	# Merge options
-	if (defined($no_checksum))
-	{
-		$checksum = ($no_checksum ? 0 : 1);
-		$no_checksum = undef;
-	}
-
-	if (defined($no_compat_libtool))
-	{
-		$compat_libtool = ($no_compat_libtool ? 0 : 1);
-		$no_compat_libtool = undef;
-	}
-}
-
-@data_directory = @ARGV;
-
-# Check for help option
-if ($help)
-{
-	print_usage(*STDOUT);
-	exit(0);
-}
-
-# Check for version option
-if ($version)
-{
-	print("$tool_name: $lcov_version\n");
-	exit(0);
-}
-
-# Make sure test names only contain valid characters
-if ($test_name =~ s/\W/_/g)
-{
-	warn("WARNING: invalid characters removed from testname!\n");
-}
-
-# Adjust test name to include uname output if requested
-if ($adjust_testname)
-{
-	$test_name .= "__".`uname -a`;
-	$test_name =~ s/\W/_/g;
-}
-
-# Make sure base_directory contains an absolute path specification
-if ($base_directory)
-{
-	$base_directory = solve_relative_path($cwd, $base_directory);
-}
-
-# Check for follow option
-if ($follow)
-{
-	$follow = "-follow"
-}
-else
-{
-	$follow = "";
-}
-
-# Determine checksum mode
-if (defined($checksum))
-{
-	# Normalize to boolean
-	$checksum = ($checksum ? 1 : 0);
-}
-else
-{
-	# Default is off
-	$checksum = 0;
-}
-
-# Determine libtool compatibility mode
-if (defined($compat_libtool))
-{
-	$compat_libtool = ($compat_libtool? 1 : 0);
-}
-else
-{
-	# Default is on
-	$compat_libtool = 1;
-}
-
-# Determine max depth for recursion
-if ($no_recursion)
-{
-	$maxdepth = "-maxdepth 1";
-}
-else
-{
-	$maxdepth = "";
-}
-
-# Check for directory name
-if (!@data_directory)
-{
-	die("No directory specified\n".
-	    "Use $tool_name --help to get usage information\n");
-}
-else
-{
-	foreach (@data_directory)
-	{
-		stat($_);
-		if (!-r _)
-		{
-			die("ERROR: cannot read $_!\n");
-		}
-	}
-}
-
-if (@ignore_errors)
-{
-	my @expanded;
-	my $error;
-
-	# Expand comma-separated entries
-	foreach (@ignore_errors) {
-		if (/,/)
-		{
-			push(@expanded, split(",", $_));
-		}
-		else
-		{
-			push(@expanded, $_);
-		}
-	}
-
-	foreach (@expanded)
-	{
-		/^gcov$/ && do { $ignore[$ERROR_GCOV] = 1; next; } ;
-		/^source$/ && do { $ignore[$ERROR_SOURCE] = 1; next; };
-		/^graph$/ && do { $ignore[$ERROR_GRAPH] = 1; next; };
-		die("ERROR: unknown argument for --ignore-errors: $_\n");
-	}
-}
-
-if (system_no_output(3, $gcov_tool, "--help") == -1)
-{
-	die("ERROR: need tool $gcov_tool!\n");
-}
-
-$gcov_version = get_gcov_version();
-
-if ($gcov_version < $GCOV_VERSION_3_4_0)
-{
-	if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
-	{
-		$data_file_extension = ".da";
-		$graph_file_extension = ".bbg";
-	}
-	else
-	{
-		$data_file_extension = ".da";
-		$graph_file_extension = ".bb";
-	}
-}
-else
-{
-	$data_file_extension = ".gcda";
-	$graph_file_extension = ".gcno";
-}	
-
-# Determine gcov options
-$gcov_caps = get_gcov_capabilities();
-push(@gcov_options, "-b") if ($gcov_caps->{'branch-probabilities'});
-push(@gcov_options, "-c") if ($gcov_caps->{'branch-counts'});
-push(@gcov_options, "-a") if ($gcov_caps->{'all-blocks'});
-push(@gcov_options, "-p") if ($gcov_caps->{'preserve-paths'});
-
-# Check output filename
-if (defined($output_filename) && ($output_filename ne "-"))
-{
-	# Initially create output filename, data is appended
-	# for each data file processed
-	local *DUMMY_HANDLE;
-	open(DUMMY_HANDLE, ">$output_filename")
-		or die("ERROR: cannot create $output_filename!\n");
-	close(DUMMY_HANDLE);
-
-	# Make $output_filename an absolute path because we're going
-	# to change directories while processing files
-	if (!($output_filename =~ /^\/(.*)$/))
-	{
-		$output_filename = $cwd."/".$output_filename;
-	}
-}
-
-# Do something
-foreach my $entry (@data_directory) {
-	gen_info($entry);
-}
-
-if ($initial) {
-	warn("Note: --initial does not generate branch coverage ".
-	     "data\n");
-}
-info("Finished .info-file creation\n");
-
-exit(0);
-
-
-
-#
-# print_usage(handle)
-#
-# Print usage information.
-#
-
-sub print_usage(*)
-{
-	local *HANDLE = $_[0];
-
-	print(HANDLE <<END_OF_USAGE);
-Usage: $tool_name [OPTIONS] DIRECTORY
-
-Traverse DIRECTORY and create a .info file for each data file found. Note
-that you may specify more than one directory, all of which are then processed
-sequentially.
-
-  -h, --help                        Print this help, then exit
-  -v, --version                     Print version number, then exit
-  -q, --quiet                       Do not print progress messages
-  -i, --initial                     Capture initial zero coverage data
-  -t, --test-name NAME              Use test case name NAME for resulting data
-  -o, --output-filename OUTFILE     Write data only to OUTFILE
-  -f, --follow                      Follow links when searching .da/.gcda files
-  -b, --base-directory DIR          Use DIR as base directory for relative paths
-      --(no-)checksum               Enable (disable) line checksumming
-      --(no-)compat-libtool         Enable (disable) libtool compatibility mode
-      --gcov-tool TOOL              Specify gcov tool location
-      --ignore-errors ERROR         Continue after ERROR (gcov, source, graph)
-      --no-recursion                Exclude subdirectories from processing
-      --function-coverage           Capture function call counts
-      --no-markers                  Ignore exclusion markers in source code
-      --derive-func-data            Generate function data from line data
-
-For more information see: $lcov_url
-END_OF_USAGE
-	;
-}
-
-#
-# get_common_prefix(min_dir, filenames)
-#
-# Return the longest path prefix shared by all filenames. MIN_DIR specifies
-# the minimum number of directories that a filename may have after removing
-# the prefix.
-#
-
-sub get_common_prefix($@)
-{
-	my ($min_dir, @files) = @_;
-	my $file;
-	my @prefix;
-	my $i;
-
-	foreach $file (@files) {
-		my ($v, $d, $f) = splitpath($file);
-		my @comp = splitdir($d);
-
-		if (!@prefix) {
-			@prefix = @comp;
-			next;
-		}
-		for ($i = 0; $i < scalar(@comp) && $i < scalar(@prefix); $i++) {
-			if ($comp[$i] ne $prefix[$i] ||
-			    ((scalar(@comp) - ($i + 1)) <= $min_dir)) {
-				delete(@prefix[$i..scalar(@prefix)]);
-				last;
-			}
-		}
-	}
-
-	return catdir(@prefix);
-}
-
-#
-# gen_info(directory)
-#
-# Traverse DIRECTORY and create a .info file for each data file found.
-# The .info file contains TEST_NAME in the following format:
-#
-#   TN:<test name>
-#
-# For each source file name referenced in the data file, there is a section
-# containing source code and coverage data:
-#
-#   SF:<absolute path to the source file>
-#   FN:<line number of function start>,<function name> for each function
-#   DA:<line number>,<execution count> for each instrumented line
-#   LH:<number of lines with an execution count> greater than 0
-#   LF:<number of instrumented lines>
-#
-# Sections are separated by:
-#
-#   end_of_record
-#
-# In addition to the main source code file there are sections for each
-# #included file containing executable code. Note that the absolute path
-# of a source file is generated by interpreting the contents of the respective
-# graph file. Relative filenames are prefixed with the directory in which the
-# graph file is found. Note also that symbolic links to the graph file will be
-# resolved so that the actual file path is used instead of the path to a link.
-# This approach is necessary for the mechanism to work with the /proc/gcov
-# files.
-#
-# Die on error.
-#
-
-sub gen_info($)
-{
-	my $directory = $_[0];
-	my @file_list;
-	my $file;
-	my $prefix;
-	my $type;
-	my $ext;
-
-	if ($initial) {
-		$type = "graph";
-		$ext = $graph_file_extension;
-	} else {
-		$type = "data";
-		$ext = $data_file_extension;
-	}
-
-	if (-d $directory)
-	{
-		info("Scanning $directory for $ext files ...\n");
-
-		@file_list = `find "$directory" $maxdepth $follow -name \\*$ext -type f 2>/dev/null`;
-		chomp(@file_list);
-		@file_list or
-			die("ERROR: no $ext files found in $directory!\n");
-		$prefix = get_common_prefix(1, @file_list);
-		info("Found %d %s files in %s\n", $#file_list+1, $type,
-		     $directory);
-	}
-	else
-	{
-		@file_list = ($directory);
-		$prefix = "";
-	}
-
-	# Process all files in list
-	foreach $file (@file_list) {
-		# Process file
-		if ($initial) {
-			process_graphfile($file, $prefix);
-		} else {
-			process_dafile($file, $prefix);
-		}
-	}
-}
-
-
-sub derive_data($$$)
-{
-	my ($contentdata, $funcdata, $bbdata) = @_;
-	my @gcov_content = @{$contentdata};
-	my @gcov_functions = @{$funcdata};
-	my %fn_count;
-	my %ln_fn;
-	my $line;
-	my $maxline;
-	my %fn_name;
-	my $fn;
-	my $count;
-
-	if (!defined($bbdata)) {
-		return @gcov_functions;
-	}
-
-	# First add existing function data
-	while (@gcov_functions) {
-		$count = shift(@gcov_functions);
-		$fn = shift(@gcov_functions);
-
-		$fn_count{$fn} = $count;
-	}
-
-	# Convert line coverage data to function data
-	foreach $fn (keys(%{$bbdata})) {
-		my $line_data = $bbdata->{$fn};
-		my $line;
-
-		if ($fn eq "") {
-			next;
-		}
-		# Find the lowest line count for this function
-		$count = 0;
-		foreach $line (@$line_data) {
-			my $lcount = $gcov_content[ ( $line - 1 ) * 3 + 1 ];
-
-			if (($lcount > 0) &&
-			    (($count == 0) || ($lcount < $count))) {
-				$count = $lcount;
-			}
-		}
-		$fn_count{$fn} = $count;
-	}
-
-
-	# Check if we got data for all functions
-	foreach $fn (keys(%fn_name)) {
-		if ($fn eq "") {
-			next;
-		}
-		if (defined($fn_count{$fn})) {
-			next;
-		}
-		warn("WARNING: no derived data found for function $fn\n");
-	}
-
-	# Convert hash to list in @gcov_functions format
-	foreach $fn (sort(keys(%fn_count))) {
-		push(@gcov_functions, $fn_count{$fn}, $fn);
-	}
-
-	return @gcov_functions;
-}
-
-#
-# get_filenames(directory, pattern)
-#
-# Return a list of filenames found in directory which match the specified
-# pattern.
-#
-# Die on error.
-#
-
-sub get_filenames($$)
-{
-	my ($dirname, $pattern) = @_;
-	my @result;
-	my $directory;
-	local *DIR;
-
-	opendir(DIR, $dirname) or
-		die("ERROR: cannot read directory $dirname\n");
-	while ($directory = readdir(DIR)) {
-		push(@result, $directory) if ($directory =~ /$pattern/);
-	}
-	closedir(DIR);
-
-	return @result;
-}
-
-#
-# process_dafile(da_filename, dir)
-#
-# Create a .info file for a single data file.
-#
-# Die on error.
-#
-
-sub process_dafile($$)
-{
-	my ($file, $dir) = @_;
-	my $da_filename;	# Name of data file to process
-	my $da_dir;		# Directory of data file
-	my $source_dir;		# Directory of source file
-	my $da_basename;	# data filename without ".da/.gcda" extension
-	my $bb_filename;	# Name of respective graph file
-	my $bb_basename;	# Basename of the original graph file
-	my $graph;		# Contents of graph file
-	my $instr;		# Contents of graph file part 2
-	my $gcov_error;		# Error code of gcov tool
-	my $object_dir;		# Directory containing all object files
-	my $source_filename;	# Name of a source code file
-	my $gcov_file;		# Name of a .gcov file
-	my @gcov_content;	# Content of a .gcov file
-	my $gcov_branches;	# Branch content of a .gcov file
-	my @gcov_functions;	# Function calls of a .gcov file
-	my @gcov_list;		# List of generated .gcov files
-	my $line_number;	# Line number count
-	my $lines_hit;		# Number of instrumented lines hit
-	my $lines_found;	# Number of instrumented lines found
-	my $funcs_hit;		# Number of instrumented functions hit
-	my $funcs_found;	# Number of instrumented functions found
-	my $br_hit;
-	my $br_found;
-	my $source;		# gcov source header information
-	my $object;		# gcov object header information
-	my @matches;		# List of absolute paths matching filename
-	my @unprocessed;	# List of unprocessed source code files
-	my $base_dir;		# Base directory for current file
-	my @tmp_links;		# Temporary links to be cleaned up
-	my @result;
-	my $index;
-	my $da_renamed;		# If data file is to be renamed
-	local *INFO_HANDLE;
-
-	info("Processing %s\n", abs2rel($file, $dir));
-	# Get path to data file in absolute and normalized form (begins with /,
-	# contains no more ../ or ./)
-	$da_filename = solve_relative_path($cwd, $file);
-
-	# Get directory and basename of data file
-	($da_dir, $da_basename) = split_filename($da_filename);
-
-	# avoid files from .libs dirs 	 
-	if ($compat_libtool && $da_dir =~ m/(.*)\/\.libs$/) {
-		$source_dir = $1;
-	} else {
-		$source_dir = $da_dir;
-	}
-
-	if (-z $da_filename)
-	{
-		$da_renamed = 1;
-	}
-	else
-	{
-		$da_renamed = 0;
-	}
-
-	# Construct base_dir for current file
-	if ($base_directory)
-	{
-		$base_dir = $base_directory;
-	}
-	else
-	{
-		$base_dir = $source_dir;
-	}
-
-	# Check for writable $base_dir (gcov will try to write files there)
-	stat($base_dir);
-	if (!-w _)
-	{
-		die("ERROR: cannot write to directory $base_dir!\n");
-	}
-
-	# Construct name of graph file
-	$bb_basename = $da_basename.$graph_file_extension;
-	$bb_filename = "$da_dir/$bb_basename";
-
-	# Find out the real location of graph file in case we're just looking at
-	# a link
-	while (readlink($bb_filename))
-	{
-		my $last_dir = dirname($bb_filename);
-
-		$bb_filename = readlink($bb_filename);
-		$bb_filename = solve_relative_path($last_dir, $bb_filename);
-	}
-
-	# Ignore empty graph file (e.g. source file with no statement)
-	if (-z $bb_filename)
-	{
-		warn("WARNING: empty $bb_filename (skipped)\n");
-		return;
-	}
-
-	# Read contents of graph file into hash. We need it later to find out
-	# the absolute path to each .gcov file created as well as for
-	# information about functions and their source code positions.
-	if ($gcov_version < $GCOV_VERSION_3_4_0)
-	{
-		if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
-		{
-			($instr, $graph) = read_bbg($bb_filename, $base_dir);
-		}
-		else
-		{
-			($instr, $graph) = read_bb($bb_filename, $base_dir);
-		}
-	} 
-	else
-	{
-		($instr, $graph) = read_gcno($bb_filename, $base_dir);
-	} 
-
-	# Set $object_dir to real location of object files. This may differ
-	# from $da_dir if the graph file is just a link to the "real" object
-	# file location.
-	$object_dir = dirname($bb_filename);
-
-	# Is the data file in a different directory? (this happens e.g. with
-	# the gcov-kernel patch)
-	if ($object_dir ne $da_dir)
-	{
-		# Need to create link to data file in $object_dir
-		system("ln", "-s", $da_filename, 
-		       "$object_dir/$da_basename$data_file_extension")
-			and die ("ERROR: cannot create link $object_dir/".
-				 "$da_basename$data_file_extension!\n");
-		push(@tmp_links,
-		     "$object_dir/$da_basename$data_file_extension");
-		# Need to create link to graph file if basename of link
-		# and file are different (CONFIG_MODVERSION compat)
-		if ((basename($bb_filename) ne $bb_basename) &&
-		    (! -e "$object_dir/$bb_basename")) {
-			symlink($bb_filename, "$object_dir/$bb_basename") or
-				warn("WARNING: cannot create link ".
-				     "$object_dir/$bb_basename\n");
-			push(@tmp_links, "$object_dir/$bb_basename");
-		}
-	}
-
-	# Change to directory containing data files and apply GCOV
-        chdir($base_dir);
-
-	if ($da_renamed)
-	{
-		# Need to rename empty data file to workaround
-	        # gcov <= 3.2.x bug (Abort)
-		system_no_output(3, "mv", "$da_filename", "$da_filename.ori")
-			and die ("ERROR: cannot rename $da_filename\n");
-	}
-
-	# Execute gcov command and suppress standard output
-	$gcov_error = system_no_output(1, $gcov_tool, $da_filename,
-				       "-o", $object_dir, @gcov_options);
-
-	if ($da_renamed)
-	{
-		system_no_output(3, "mv", "$da_filename.ori", "$da_filename")
-			and die ("ERROR: cannot rename $da_filename.ori");
-	}
-
-	# Clean up temporary links
-	foreach (@tmp_links) {
-		unlink($_);
-	}
-
-	if ($gcov_error)
-	{
-		if ($ignore[$ERROR_GCOV])
-		{
-			warn("WARNING: GCOV failed for $da_filename!\n");
-			return;
-		}
-		die("ERROR: GCOV failed for $da_filename!\n");
-	}
-
-	# Collect data from resulting .gcov files and create .info file
-	@gcov_list = get_filenames('.', '\.gcov$');
-
-	# Check for files
-	if (!@gcov_list)
-	{
-		warn("WARNING: gcov did not create any files for ".
-		     "$da_filename!\n");
-	}
-
-	# Check whether we're writing to a single file
-	if ($output_filename)
-	{
-		if ($output_filename eq "-")
-		{
-			*INFO_HANDLE = *STDOUT;
-		}
-		else
-		{
-			# Append to output file
-			open(INFO_HANDLE, ">>$output_filename")
-				or die("ERROR: cannot write to ".
-				       "$output_filename!\n");
-		}
-	}
-	else
-	{
-		# Open .info file for output
-		open(INFO_HANDLE, ">$da_filename.info")
-			or die("ERROR: cannot create $da_filename.info!\n");
-	}
-
-	# Write test name
-	printf(INFO_HANDLE "TN:%s\n", $test_name);
-
-	# Traverse the list of generated .gcov files and combine them into a
-	# single .info file
-	@unprocessed = keys(%{$instr});
-	foreach $gcov_file (sort(@gcov_list))
-	{
-		my $i;
-		my $num;
-
-		($source, $object) = read_gcov_header($gcov_file);
-
-		if (defined($source))
-		{
-			$source = solve_relative_path($base_dir, $source);
-		}
-
-		# gcov will happily create output even if there's no source code
-		# available - this interferes with checksum creation so we need
-		# to pull the emergency brake here.
-		if (defined($source) && ! -r $source && $checksum)
-		{
-			if ($ignore[$ERROR_SOURCE])
-			{
-				warn("WARNING: could not read source file ".
-				     "$source\n");
-				next;
-			}
-			die("ERROR: could not read source file $source\n");
-		}
-
-		@matches = match_filename(defined($source) ? $source :
-					  $gcov_file, keys(%{$instr}));
-
-		# Skip files that are not mentioned in the graph file
-		if (!@matches)
-		{
-			warn("WARNING: cannot find an entry for ".$gcov_file.
-			     " in $graph_file_extension file, skipping ".
-			     "file!\n");
-			unlink($gcov_file);
-			next;
-		}
-
-		# Read in contents of gcov file
-		@result = read_gcov_file($gcov_file);
-		if (!defined($result[0])) {
-			warn("WARNING: skipping unreadable file ".
-			     $gcov_file."\n");
-			unlink($gcov_file);
-			next;
-		}
-		@gcov_content = @{$result[0]};
-		$gcov_branches = $result[1];
-		@gcov_functions = @{$result[2]};
-
-		# Skip empty files
-		if (!@gcov_content)
-		{
-			warn("WARNING: skipping empty file ".$gcov_file."\n");
-			unlink($gcov_file);
-			next;
-		}
-
-		if (scalar(@matches) == 1)
-		{
-			# Just one match
-			$source_filename = $matches[0];
-		}
-		else
-		{
-			# Try to solve the ambiguity
-			$source_filename = solve_ambiguous_match($gcov_file,
-						\@matches, \@gcov_content);
-		}
-
-		# Remove processed file from list
-		for ($index = scalar(@unprocessed) - 1; $index >= 0; $index--)
-		{
-			if ($unprocessed[$index] eq $source_filename)
-			{
-				splice(@unprocessed, $index, 1);
-				last;
-			}
-		}
-
-		# Write absolute path of source file
-		printf(INFO_HANDLE "SF:%s\n", $source_filename);
-
-		# If requested, derive function coverage data from
-		# line coverage data of the first line of a function
-		if ($opt_derive_func_data) {
-			@gcov_functions =
-				derive_data(\@gcov_content, \@gcov_functions,
-					    $graph->{$source_filename});
-		}
-
-		# Write function-related information
-		if (defined($graph->{$source_filename}))
-		{
-			my $fn_data = $graph->{$source_filename};
-			my $fn;
-
-			foreach $fn (sort
-				{$fn_data->{$a}->[0] <=> $fn_data->{$b}->[0]}
-				keys(%{$fn_data})) {
-				my $ln_data = $fn_data->{$fn};
-				my $line = $ln_data->[0];
-
-				# Skip empty function
-				if ($fn eq "") {
-					next;
-				}
-				# Remove excluded functions
-				if (!$no_markers) {
-					my $gfn;
-					my $found = 0;
-
-					foreach $gfn (@gcov_functions) {
-						if ($gfn eq $fn) {
-							$found = 1;
-							last;
-						}
-					}
-					if (!$found) {
-						next;
-					}
-				}
-
-				# Normalize function name
-				$fn = filter_fn_name($fn);
-
-				print(INFO_HANDLE "FN:$line,$fn\n");
-			}
-		}
-
-		#--
-		#-- FNDA: <call-count>, <function-name>
-		#-- FNF: overall count of functions
-		#-- FNH: overall count of functions with non-zero call count
-		#--
-		$funcs_found = 0;
-		$funcs_hit = 0;
-		while (@gcov_functions)
-		{
-			my $count = shift(@gcov_functions);
-			my $fn = shift(@gcov_functions);
-
-			$fn = filter_fn_name($fn);
-			printf(INFO_HANDLE "FNDA:$count,$fn\n");
-			$funcs_found++;
-			$funcs_hit++ if ($count > 0);
-		}
-		if ($funcs_found > 0) {
-			printf(INFO_HANDLE "FNF:%s\n", $funcs_found);
-			printf(INFO_HANDLE "FNH:%s\n", $funcs_hit);
-		}
-
-		# Write coverage information for each instrumented branch:
-		#
-		#   BRDA:<line number>,<block number>,<branch number>,<taken>
-		#
-		# where 'taken' is the number of times the branch was taken
-		# or '-' if the block to which the branch belongs was never
-		# executed
-		$br_found = 0;
-		$br_hit = 0;
-		$num = br_gvec_len($gcov_branches);
-		for ($i = 0; $i < $num; $i++) {
-			my ($line, $block, $branch, $taken) =
-				br_gvec_get($gcov_branches, $i);
-
-			print(INFO_HANDLE "BRDA:$line,$block,$branch,$taken\n");
-			$br_found++;
-			$br_hit++ if ($taken ne '-' && $taken > 0);
-		}
-		if ($br_found > 0) {
-			printf(INFO_HANDLE "BRF:%s\n", $br_found);
-			printf(INFO_HANDLE "BRH:%s\n", $br_hit);
-		}
-
-		# Reset line counters
-		$line_number = 0;
-		$lines_found = 0;
-		$lines_hit = 0;
-
-		# Write coverage information for each instrumented line
-		# Note: @gcov_content contains a list of (flag, count, source)
-		# tuple for each source code line
-		while (@gcov_content)
-		{
-			$line_number++;
-
-			# Check for instrumented line
-			if ($gcov_content[0])
-			{
-				$lines_found++;
-				printf(INFO_HANDLE "DA:".$line_number.",".
-				       $gcov_content[1].($checksum ?
-				       ",". md5_base64($gcov_content[2]) : "").
-				       "\n");
-
-				# Increase $lines_hit in case of an execution
-				# count>0
-				if ($gcov_content[1] > 0) { $lines_hit++; }
-			}
-
-			# Remove already processed data from array
-			splice(@gcov_content,0,3);
-		}
-
-		# Write line statistics and section separator
-		printf(INFO_HANDLE "LF:%s\n", $lines_found);
-		printf(INFO_HANDLE "LH:%s\n", $lines_hit);
-		print(INFO_HANDLE "end_of_record\n");
-
-		# Remove .gcov file after processing
-		unlink($gcov_file);
-	}
-
-	# Check for files which show up in the graph file but were never
-	# processed
-	if (@unprocessed && @gcov_list)
-	{
-		foreach (@unprocessed)
-		{
-			warn("WARNING: no data found for $_\n");
-		}
-	}
-
-	if (!($output_filename && ($output_filename eq "-")))
-	{
-		close(INFO_HANDLE);
-	}
-
-	# Change back to initial directory
-	chdir($cwd);
-}
-
-
-#
-# solve_relative_path(path, dir)
-#
-# Solve relative path components of DIR which, if not absolute, resides in PATH.
-#
-
-sub solve_relative_path($$)
-{
-	my $path = $_[0];
-	my $dir = $_[1];
-	my $result;
-
-	$result = $dir;
-	# Prepend path if not absolute
-	if ($dir =~ /^[^\/]/)
-	{
-		$result = "$path/$result";
-	}
-
-	# Remove //
-	$result =~ s/\/\//\//g;
-
-	# Remove .
-	$result =~ s/\/\.\//\//g;
-
-	# Solve ..
-	while ($result =~ s/\/[^\/]+\/\.\.\//\//)
-	{
-	}
-
-	# Remove preceding ..
-	$result =~ s/^\/\.\.\//\//g;
-
-	return $result;
-}
-
-
-#
-# match_filename(gcov_filename, list)
-#
-# Return a list of those entries of LIST which match the relative filename
-# GCOV_FILENAME.
-#
-
-sub match_filename($@)
-{
-	my ($filename, @list) = @_;
-	my ($vol, $dir, $file) = splitpath($filename);
-	my @comp = splitdir($dir);
-	my $comps = scalar(@comp);
-	my $entry;
-	my @result;
-
-entry:
-	foreach $entry (@list) {
-		my ($evol, $edir, $efile) = splitpath($entry);
-		my @ecomp;
-		my $ecomps;
-		my $i;
-
-		# Filename component must match
-		if ($efile ne $file) {
-			next;
-		}
-		# Check directory components last to first for match
-		@ecomp = splitdir($edir);
-		$ecomps = scalar(@ecomp);
-		if ($ecomps < $comps) {
-			next;
-		}
-		for ($i = 0; $i < $comps; $i++) {
-			if ($comp[$comps - $i - 1] ne
-			    $ecomp[$ecomps - $i - 1]) {
-				next entry;
-			}
-		}
-		push(@result, $entry),
-	}
-
-	return @result;
-}
-
-#
-# solve_ambiguous_match(rel_filename, matches_ref, gcov_content_ref)
-#
-# Try to solve ambiguous matches of mapping (gcov file) -> (source code) file
-# by comparing source code provided in the GCOV file with that of the files
-# in MATCHES. REL_FILENAME identifies the relative filename of the gcov
-# file.
-# 
-# Return the one real match or die if there is none.
-#
-
-sub solve_ambiguous_match($$$)
-{
-	my $rel_name = $_[0];
-	my $matches = $_[1];
-	my $content = $_[2];
-	my $filename;
-	my $index;
-	my $no_match;
-	local *SOURCE;
-
-	# Check the list of matches
-	foreach $filename (@$matches)
-	{
-
-		# Compare file contents
-		open(SOURCE, $filename)
-			or die("ERROR: cannot read $filename!\n");
-
-		$no_match = 0;
-		for ($index = 2; <SOURCE>; $index += 3)
-		{
-			chomp;
-
-			# Also remove CR from line-end
-			s/\015$//;
-
-			if ($_ ne @$content[$index])
-			{
-				$no_match = 1;
-				last;
-			}
-		}
-
-		close(SOURCE);
-
-		if (!$no_match)
-		{
-			info("Solved source file ambiguity for $rel_name\n");
-			return $filename;
-		}
-	}
-
-	die("ERROR: could not match gcov data for $rel_name!\n");
-}
-
-
-#
-# split_filename(filename)
-#
-# Return (path, filename, extension) for a given FILENAME.
-#
-
-sub split_filename($)
-{
-	my @path_components = split('/', $_[0]);
-	my @file_components = split('\.', pop(@path_components));
-	my $extension = pop(@file_components);
-
-	return (join("/",@path_components), join(".",@file_components),
-		$extension);
-}
-
-
-#
-# read_gcov_header(gcov_filename)
-#
-# Parse file GCOV_FILENAME and return a list containing the following
-# information:
-#
-#   (source, object)
-#
-# where:
-#
-# source: complete relative path of the source code file (gcc >= 3.3 only)
-# object: name of associated graph file
-#
-# Die on error.
-#
-
-sub read_gcov_header($)
-{
-	my $source;
-	my $object;
-	local *INPUT;
-
-	if (!open(INPUT, $_[0]))
-	{
-		if ($ignore_errors[$ERROR_GCOV])
-		{
-			warn("WARNING: cannot read $_[0]!\n");
-			return (undef,undef);
-		}
-		die("ERROR: cannot read $_[0]!\n");
-	}
-
-	while (<INPUT>)
-	{
-		chomp($_);
-
-		# Also remove CR from line-end
-		s/\015$//;
-
-		if (/^\s+-:\s+0:Source:(.*)$/)
-		{
-			# Source: header entry
-			$source = $1;
-		}
-		elsif (/^\s+-:\s+0:Object:(.*)$/)
-		{
-			# Object: header entry
-			$object = $1;
-		}
-		else
-		{
-			last;
-		}
-	}
-
-	close(INPUT);
-
-	return ($source, $object);
-}
-
-
-#
-# br_gvec_len(vector)
-#
-# Return the number of entries in the branch coverage vector.
-#
-
-sub br_gvec_len($)
-{
-	my ($vec) = @_;
-
-	return 0 if (!defined($vec));
-	return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
-}
-
-
-#
-# br_gvec_get(vector, number)
-#
-# Return an entry from the branch coverage vector.
-#
-
-sub br_gvec_get($$)
-{
-	my ($vec, $num) = @_;
-	my $line;
-	my $block;
-	my $branch;
-	my $taken;
-	my $offset = $num * $BR_VEC_ENTRIES;
-
-	# Retrieve data from vector
-	$line	= vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH);
-	$block	= vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
-	$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
-	$taken	= vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
-
-	# Decode taken value from an integer
-	if ($taken == 0) {
-		$taken = "-";
-	} else {
-		$taken--;
-	}
-
-	return ($line, $block, $branch, $taken);
-}
-
-
-#
-# br_gvec_push(vector, line, block, branch, taken)
-#
-# Add an entry to the branch coverage vector.
-#
-
-sub br_gvec_push($$$$$)
-{
-	my ($vec, $line, $block, $branch, $taken) = @_;
-	my $offset;
-
-	$vec = "" if (!defined($vec));
-	$offset = br_gvec_len($vec) * $BR_VEC_ENTRIES;
-
-	# Encode taken value into an integer
-	if ($taken eq "-") {
-		$taken = 0;
-	} else {
-		$taken++;
-	}
-
-	# Add to vector
-	vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH) = $line;
-	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
-	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
-	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
-
-	return $vec;
-}
-
-
-#
-# read_gcov_file(gcov_filename)
-#
-# Parse file GCOV_FILENAME (.gcov file format) and return the list:
-# (reference to gcov_content, reference to gcov_branch, reference to gcov_func)
-#
-# gcov_content is a list of 3 elements
-# (flag, count, source) for each source code line:
-#
-# $result[($line_number-1)*3+0] = instrumentation flag for line $line_number
-# $result[($line_number-1)*3+1] = execution count for line $line_number
-# $result[($line_number-1)*3+2] = source code text for line $line_number
-#
-# gcov_branch is a vector of 4 4-byte long elements for each branch:
-# line number, block number, branch number, count + 1 or 0
-#
-# gcov_func is a list of 2 elements
-# (number of calls, function name) for each function
-#
-# Die on error.
-#
-
-sub read_gcov_file($)
-{
-	my $filename = $_[0];
-	my @result = ();
-	my $branches = "";
-	my @functions = ();
-	my $number;
-	my $exclude_flag = 0;
-	my $exclude_line = 0;
-	my $last_block = $UNNAMED_BLOCK;
-	my $last_line = 0;
-	local *INPUT;
-
-	if (!open(INPUT, $filename)) {
-		if ($ignore_errors[$ERROR_GCOV])
-		{
-			warn("WARNING: cannot read $filename!\n");
-			return (undef, undef, undef);
-		}
-		die("ERROR: cannot read $filename!\n");
-	}
-
-	if ($gcov_version < $GCOV_VERSION_3_3_0)
-	{
-		# Expect gcov format as used in gcc < 3.3
-		while (<INPUT>)
-		{
-			chomp($_);
-
-			# Also remove CR from line-end
-			s/\015$//;
-
-			if (/^branch\s+(\d+)\s+taken\s+=\s+(\d+)/) {
-				next if ($exclude_line);
-				$branches = br_gvec_push($branches, $last_line,
-						$last_block, $1, $2);
-			} elsif (/^branch\s+(\d+)\s+never\s+executed/) {
-				next if ($exclude_line);
-				$branches = br_gvec_push($branches, $last_line,
-						$last_block, $1, '-');
-			}
-			elsif (/^call/ || /^function/)
-			{
-				# Function call return data
-			}
-			else
-			{
-				$last_line++;
-				# Check for exclusion markers
-				if (!$no_markers) {
-					if (/$EXCL_STOP/) {
-						$exclude_flag = 0;
-					} elsif (/$EXCL_START/) {
-						$exclude_flag = 1;
-					}
-					if (/$EXCL_LINE/ || $exclude_flag) {
-						$exclude_line = 1;
-					} else {
-						$exclude_line = 0;
-					}
-				}
-				# Source code execution data
-				if (/^\t\t(.*)$/)
-				{
-					# Uninstrumented line
-					push(@result, 0);
-					push(@result, 0);
-					push(@result, $1);
-					next;
-				}
-				$number = (split(" ",substr($_, 0, 16)))[0];
-
-				# Check for zero count which is indicated
-				# by ######
-				if ($number eq "######") { $number = 0;	}
-
-				if ($exclude_line) {
-					# Register uninstrumented line instead
-					push(@result, 0);
-					push(@result, 0);
-				} else {
-					push(@result, 1);
-					push(@result, $number);
-				}
-				push(@result, substr($_, 16));
-			}
-		}
-	}
-	else
-	{
-		# Expect gcov format as used in gcc >= 3.3
-		while (<INPUT>)
-		{
-			chomp($_);
-
-			# Also remove CR from line-end
-			s/\015$//;
-
-			if (/^\s*(\d+|\$+):\s*(\d+)-block\s+(\d+)\s*$/) {
-				# Block information - used to group related
-				# branches
-				$last_line = $2;
-				$last_block = $3;
-			} elsif (/^branch\s+(\d+)\s+taken\s+(\d+)/) {
-				next if ($exclude_line);
-				$branches = br_gvec_push($branches, $last_line,
-						$last_block, $1, $2);
-			} elsif (/^branch\s+(\d+)\s+never\s+executed/) {
-				next if ($exclude_line);
-				$branches = br_gvec_push($branches, $last_line,
-						$last_block, $1, '-');
-			}
-			elsif (/^function\s+(\S+)\s+called\s+(\d+)/)
-			{
-				if ($exclude_line) {
-					next;
-				}
-				push(@functions, $2, $1);
-			}
-			elsif (/^call/)
-			{
-				# Function call return data
-			}
-			elsif (/^\s*([^:]+):\s*([^:]+):(.*)$/)
-			{
-				my ($count, $line, $code) = ($1, $2, $3);
-
-				$last_line = $line;
-				$last_block = $UNNAMED_BLOCK;
-				# Check for exclusion markers
-				if (!$no_markers) {
-					if (/$EXCL_STOP/) {
-						$exclude_flag = 0;
-					} elsif (/$EXCL_START/) {
-						$exclude_flag = 1;
-					}
-					if (/$EXCL_LINE/ || $exclude_flag) {
-						$exclude_line = 1;
-					} else {
-						$exclude_line = 0;
-					}
-				}
-				# <exec count>:<line number>:<source code>
-				if ($line eq "0")
-				{
-					# Extra data
-				}
-				elsif ($count eq "-")
-				{
-					# Uninstrumented line
-					push(@result, 0);
-					push(@result, 0);
-					push(@result, $code);
-				}
-				else
-				{
-					if ($exclude_line) {
-						push(@result, 0);
-						push(@result, 0);
-					} else {
-						# Check for zero count
-						if ($count eq "#####") {
-							$count = 0;
-						}
-						push(@result, 1);
-						push(@result, $count);
-					}
-					push(@result, $code);
-				}
-			}
-		}
-	}
-
-	close(INPUT);
-	if ($exclude_flag) {
-		warn("WARNING: unterminated exclusion section in $filename\n");
-	}
-	return(\@result, $branches, \@functions);
-}
-
-
-#
-# Get the GCOV tool version. Return an integer number which represents the
-# GCOV version. Version numbers can be compared using standard integer
-# operations.
-#
-
-sub get_gcov_version()
-{
-	local *HANDLE;
-	my $version_string;
-	my $result;
-
-	open(GCOV_PIPE, "$gcov_tool -v |")
-		or die("ERROR: cannot retrieve gcov version!\n");
-	$version_string = <GCOV_PIPE>;
-	close(GCOV_PIPE);
-
-	$result = 0;
-	if ($version_string =~ /(\d+)\.(\d+)(\.(\d+))?/)
-	{
-		if (defined($4))
-		{
-			info("Found gcov version: $1.$2.$4\n");
-			$result = $1 << 16 | $2 << 8 | $4;
-		}
-		else
-		{
-			info("Found gcov version: $1.$2\n");
-			$result = $1 << 16 | $2 << 8;
-		}
-	}
-        if ($version_string =~ /suse/i && $result == 0x30303 ||
-            $version_string =~ /mandrake/i && $result == 0x30302)
-	{
-		info("Using compatibility mode for GCC 3.3 (hammer)\n");
-		$compatibility = $COMPAT_HAMMER;
-	}
-	return $result;
-}
-
-
-#
-# info(printf_parameter)
-#
-# Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag
-# is not set.
-#
-
-sub info(@)
-{
-	if (!$quiet)
-	{
-		# Print info string
-		if (defined($output_filename) && ($output_filename eq "-"))
-		{
-			# Don't interfere with the .info output to STDOUT
-			printf(STDERR @_);
-		}
-		else
-		{
-			printf(@_);
-		}
-	}
-}
-
-
-#
-# int_handler()
-#
-# Called when the script was interrupted by an INT signal (e.g. CTRl-C)
-#
-
-sub int_handler()
-{
-	if ($cwd) { chdir($cwd); }
-	info("Aborted.\n");
-	exit(1);
-}
-
-
-#
-# system_no_output(mode, parameters)
-#
-# Call an external program using PARAMETERS while suppressing depending on
-# the value of MODE:
-#
-#   MODE & 1: suppress STDOUT
-#   MODE & 2: suppress STDERR
-#
-# Return 0 on success, non-zero otherwise.
-#
-
-sub system_no_output($@)
-{
-	my $mode = shift;
-	my $result;
-	local *OLD_STDERR;
-	local *OLD_STDOUT;
-
-	# Save old stdout and stderr handles
-	($mode & 1) && open(OLD_STDOUT, ">>&STDOUT");
-	($mode & 2) && open(OLD_STDERR, ">>&STDERR");
-
-	# Redirect to /dev/null
-	($mode & 1) && open(STDOUT, ">/dev/null");
-	($mode & 2) && open(STDERR, ">/dev/null");
- 
-	system(@_);
-	$result = $?;
-
-	# Close redirected handles
-	($mode & 1) && close(STDOUT);
-	($mode & 2) && close(STDERR);
-
-	# Restore old handles
-	($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
-	($mode & 2) && open(STDERR, ">>&OLD_STDERR");
- 
-	return $result;
-}
-
-
-#
-# read_config(filename)
-#
-# Read configuration file FILENAME and return a reference to a hash containing
-# all valid key=value pairs found.
-#
-
-sub read_config($)
-{
-	my $filename = $_[0];
-	my %result;
-	my $key;
-	my $value;
-	local *HANDLE;
-
-	if (!open(HANDLE, "<$filename"))
-	{
-		warn("WARNING: cannot read configuration file $filename\n");
-		return undef;
-	}
-	while (<HANDLE>)
-	{
-		chomp;
-		# Skip comments
-		s/#.*//;
-		# Remove leading blanks
-		s/^\s+//;
-		# Remove trailing blanks
-		s/\s+$//;
-		next unless length;
-		($key, $value) = split(/\s*=\s*/, $_, 2);
-		if (defined($key) && defined($value))
-		{
-			$result{$key} = $value;
-		}
-		else
-		{
-			warn("WARNING: malformed statement in line $. ".
-			     "of configuration file $filename\n");
-		}
-	}
-	close(HANDLE);
-	return \%result;
-}
-
-
-#
-# apply_config(REF)
-#
-# REF is a reference to a hash containing the following mapping:
-#
-#   key_string => var_ref
-#
-# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
-# variable. If the global configuration hash CONFIG contains a value for
-# keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
-#
-
-sub apply_config($)
-{
-	my $ref = $_[0];
-
-	foreach (keys(%{$ref}))
-	{
-		if (defined($config->{$_}))
-		{
-			${$ref->{$_}} = $config->{$_};
-		}
-	}
-}
-
-
-#
-# get_exclusion_data(filename)
-#
-# Scan specified source code file for exclusion markers and return
-#   linenumber -> 1
-# for all lines which should be excluded.
-#
-
-sub get_exclusion_data($)
-{
-	my ($filename) = @_;
-	my %list;
-	my $flag = 0;
-	local *HANDLE;
-
-	if (!open(HANDLE, "<$filename")) {
-		warn("WARNING: could not open $filename\n");
-		return undef;
-	}
-	while (<HANDLE>) {
-		if (/$EXCL_STOP/) {
-			$flag = 0;
-		} elsif (/$EXCL_START/) {
-			$flag = 1;
-		}
-		if (/$EXCL_LINE/ || $flag) {
-			$list{$.} = 1;
-		}
-	}
-	close(HANDLE);
-
-	if ($flag) {
-		warn("WARNING: unterminated exclusion section in $filename\n");
-	}
-
-	return \%list;
-}
-
-
-#
-# apply_exclusion_data(instr, graph)
-#
-# Remove lines from instr and graph data structures which are marked
-# for exclusion in the source code file.
-#
-# Return adjusted (instr, graph).
-#
-# graph         : file name -> function data
-# function data : function name -> line data
-# line data     : [ line1, line2, ... ]
-#
-# instr     : filename -> line data
-# line data : [ line1, line2, ... ]
-#
-
-sub apply_exclusion_data($$)
-{
-	my ($instr, $graph) = @_;
-	my $filename;
-	my %excl_data;
-	my $excl_read_failed = 0;
-
-	# Collect exclusion marker data
-	foreach $filename (sort_uniq_lex(keys(%{$graph}), keys(%{$instr}))) {
-		my $excl = get_exclusion_data($filename);
-
-		# Skip and note if file could not be read
-		if (!defined($excl)) {
-			$excl_read_failed = 1;
-			next;
-		}
-
-		# Add to collection if there are markers
-		$excl_data{$filename} = $excl if (keys(%{$excl}) > 0);
-	}
-
-	# Warn if not all source files could be read
-	if ($excl_read_failed) {
-		warn("WARNING: some exclusion markers may be ignored\n");
-	}
-
-	# Skip if no markers were found
-	return ($instr, $graph) if (keys(%excl_data) == 0);
-
-	# Apply exclusion marker data to graph
-	foreach $filename (keys(%excl_data)) {
-		my $function_data = $graph->{$filename};
-		my $excl = $excl_data{$filename};
-		my $function;
-
-		next if (!defined($function_data));
-
-		foreach $function (keys(%{$function_data})) {
-			my $line_data = $function_data->{$function};
-			my $line;
-			my @new_data;
-
-			# To be consistent with exclusion parser in non-initial
-			# case we need to remove a function if the first line
-			# was excluded
-			if ($excl->{$line_data->[0]}) {
-				delete($function_data->{$function});
-				next;
-			}
-			# Copy only lines which are not excluded
-			foreach $line (@{$line_data}) {
-				push(@new_data, $line) if (!$excl->{$line});
-			}
-
-			# Store modified list
-			if (scalar(@new_data) > 0) {
-				$function_data->{$function} = \@new_data;
-			} else {
-				# All of this function was excluded
-				delete($function_data->{$function});
-			}
-		}
-
-		# Check if all functions of this file were excluded
-		if (keys(%{$function_data}) == 0) {
-			delete($graph->{$filename});
-		}
-	}
-
-	# Apply exclusion marker data to instr
-	foreach $filename (keys(%excl_data)) {
-		my $line_data = $instr->{$filename};
-		my $excl = $excl_data{$filename};
-		my $line;
-		my @new_data;
-
-		next if (!defined($line_data));
-
-		# Copy only lines which are not excluded
-		foreach $line (@{$line_data}) {
-			push(@new_data, $line) if (!$excl->{$line});
-		}
-
-		# Store modified list
-		if (scalar(@new_data) > 0) {
-			$instr->{$filename} = \@new_data;
-		} else {
-			# All of this file was excluded
-			delete($instr->{$filename});
-		}
-	}
-
-	return ($instr, $graph);
-}
-
-
-sub process_graphfile($$)
-{
-	my ($file, $dir) = @_;
-	my $graph_filename = $file;
-	my $graph_dir;
-	my $graph_basename;
-	my $source_dir;
-	my $base_dir;
-	my $graph;
-	my $instr;
-	my $filename;
-	local *INFO_HANDLE;
-
-	info("Processing %s\n", abs2rel($file, $dir));
-
-	# Get path to data file in absolute and normalized form (begins with /,
-	# contains no more ../ or ./)
-	$graph_filename = solve_relative_path($cwd, $graph_filename);
-
-	# Get directory and basename of data file
-	($graph_dir, $graph_basename) = split_filename($graph_filename);
-
-	# avoid files from .libs dirs 	 
-	if ($compat_libtool && $graph_dir =~ m/(.*)\/\.libs$/) {
-		$source_dir = $1;
-	} else {
-		$source_dir = $graph_dir;
-	}
-
-	# Construct base_dir for current file
-	if ($base_directory)
-	{
-		$base_dir = $base_directory;
-	}
-	else
-	{
-		$base_dir = $source_dir;
-	}
-
-	if ($gcov_version < $GCOV_VERSION_3_4_0)
-	{
-		if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
-		{
-			($instr, $graph) = read_bbg($graph_filename, $base_dir);
-		}
-		else
-		{
-			($instr, $graph) = read_bb($graph_filename, $base_dir);
-		}
-	} 
-	else
-	{
-		($instr, $graph) = read_gcno($graph_filename, $base_dir);
-	}
-
-	if (!$no_markers) {
-		# Apply exclusion marker data to graph file data
-		($instr, $graph) = apply_exclusion_data($instr, $graph);
-	}
-
-	# Check whether we're writing to a single file
-	if ($output_filename)
-	{
-		if ($output_filename eq "-")
-		{
-			*INFO_HANDLE = *STDOUT;
-		}
-		else
-		{
-			# Append to output file
-			open(INFO_HANDLE, ">>$output_filename")
-				or die("ERROR: cannot write to ".
-				       "$output_filename!\n");
-		}
-	}
-	else
-	{
-		# Open .info file for output
-		open(INFO_HANDLE, ">$graph_filename.info")
-			or die("ERROR: cannot create $graph_filename.info!\n");
-	}
-
-	# Write test name
-	printf(INFO_HANDLE "TN:%s\n", $test_name);
-	foreach $filename (sort(keys(%{$instr})))
-	{
-		my $funcdata = $graph->{$filename};
-		my $line;
-		my $linedata;
-
-		print(INFO_HANDLE "SF:$filename\n");
-
-		if (defined($funcdata)) {
-			my @functions = sort {$funcdata->{$a}->[0] <=>
-					      $funcdata->{$b}->[0]}
-					     keys(%{$funcdata});
-			my $func;
-
-			# Gather list of instrumented lines and functions
-			foreach $func (@functions) {
-				$linedata = $funcdata->{$func};
-
-				# Print function name and starting line
-				print(INFO_HANDLE "FN:".$linedata->[0].
-				      ",".filter_fn_name($func)."\n");
-			}
-			# Print zero function coverage data
-			foreach $func (@functions) {
-				print(INFO_HANDLE "FNDA:0,".
-				      filter_fn_name($func)."\n");
-			}
-			# Print function summary
-			print(INFO_HANDLE "FNF:".scalar(@functions)."\n");
-			print(INFO_HANDLE "FNH:0\n");
-		}
-		# Print zero line coverage data
-		foreach $line (@{$instr->{$filename}}) {
-			print(INFO_HANDLE "DA:$line,0\n");
-		}
-		# Print line summary
-		print(INFO_HANDLE "LF:".scalar(@{$instr->{$filename}})."\n");
-		print(INFO_HANDLE "LH:0\n");
-
-		print(INFO_HANDLE "end_of_record\n");
-	}
-	if (!($output_filename && ($output_filename eq "-")))
-	{
-		close(INFO_HANDLE);
-	}
-}
-
-sub filter_fn_name($)
-{
-	my ($fn) = @_;
-
-	# Remove characters used internally as function name delimiters
-	$fn =~ s/[,=]/_/g;
-
-	return $fn;
-}
-
-sub warn_handler($)
-{
-	my ($msg) = @_;
-
-	warn("$tool_name: $msg");
-}
-
-sub die_handler($)
-{
-	my ($msg) = @_;
-
-	die("$tool_name: $msg");
-}
-
-
-#
-# graph_error(filename, message)
-#
-# Print message about error in graph file. If ignore_graph_error is set, return.
-# Otherwise abort.
-#
-
-sub graph_error($$)
-{
-	my ($filename, $msg) = @_;
-
-	if ($ignore[$ERROR_GRAPH]) {
-		warn("WARNING: $filename: $msg - skipping\n");
-		return;
-	}
-	die("ERROR: $filename: $msg\n");
-}
-
-#
-# graph_expect(description)
-#
-# If debug is set to a non-zero value, print the specified description of what
-# is expected to be read next from the graph file.
-#
-
-sub graph_expect($)
-{
-	my ($msg) = @_;
-
-	if (!$debug || !defined($msg)) {
-		return;
-	}
-
-	print(STDERR "DEBUG: expecting $msg\n");
-}
-
-#
-# graph_read(handle, bytes[, description])
-#
-# Read and return the specified number of bytes from handle. Return undef
-# if the number of bytes could not be read.
-#
-
-sub graph_read(*$;$)
-{
-	my ($handle, $length, $desc) = @_;
-	my $data;
-	my $result;
-
-	graph_expect($desc);
-	$result = read($handle, $data, $length);
-	if ($debug) {
-		my $ascii = "";
-		my $hex = "";
-		my $i;
-
-		print(STDERR "DEBUG: read($length)=$result: ");
-		for ($i = 0; $i < length($data); $i++) {
-			my $c = substr($data, $i, 1);;
-			my $n = ord($c);
-
-			$hex .= sprintf("%02x ", $n);
-			if ($n >= 32 && $n <= 127) {
-				$ascii .= $c;
-			} else {
-				$ascii .= ".";
-			}
-		}
-		print(STDERR "$hex |$ascii|");
-		print(STDERR "\n");
-	}
-	if ($result != $length) {
-		return undef;
-	}
-	return $data;
-}
-
-#
-# graph_skip(handle, bytes[, description])
-#
-# Read and discard the specified number of bytes from handle. Return non-zero
-# if bytes could be read, zero otherwise.
-#
-
-sub graph_skip(*$;$)
-{
-	my ($handle, $length, $desc) = @_;
-
-	if (defined(graph_read($handle, $length, $desc))) {
-		return 1;
-	}
-	return 0;
-}
-
-#
-# sort_uniq(list)
-#
-# Return list in numerically ascending order and without duplicate entries.
-#
-
-sub sort_uniq(@)
-{
-	my (@list) = @_;
-	my %hash;
-
-	foreach (@list) {
-		$hash{$_} = 1;
-	}
-	return sort { $a <=> $b } keys(%hash);
-}
-
-#
-# sort_uniq_lex(list)
-#
-# Return list in lexically ascending order and without duplicate entries.
-#
-
-sub sort_uniq_lex(@)
-{
-	my (@list) = @_;
-	my %hash;
-
-	foreach (@list) {
-		$hash{$_} = 1;
-	}
-	return sort keys(%hash);
-}
-
-#
-# graph_cleanup(graph)
-#
-# Remove entries for functions with no lines. Remove duplicate line numbers.
-# Sort list of line numbers numerically ascending.
-#
-
-sub graph_cleanup($)
-{
-	my ($graph) = @_;
-	my $filename;
-
-	foreach $filename (keys(%{$graph})) {
-		my $per_file = $graph->{$filename};
-		my $function;
-
-		foreach $function (keys(%{$per_file})) {
-			my $lines = $per_file->{$function};
-
-			if (scalar(@$lines) == 0) {
-				# Remove empty function
-				delete($per_file->{$function});
-				next;
-			}
-			# Normalize list
-			$per_file->{$function} = [ sort_uniq(@$lines) ];
-		}
-		if (scalar(keys(%{$per_file})) == 0) {
-			# Remove empty file
-			delete($graph->{$filename});
-		}
-	}
-}
-
-#
-# graph_find_base(bb)
-#
-# Try to identify the filename which is the base source file for the
-# specified bb data.
-#
-
-sub graph_find_base($)
-{
-	my ($bb) = @_;
-	my %file_count;
-	my $basefile;
-	my $file;
-	my $func;
-	my $filedata;
-	my $count;
-	my $num;
-
-	# Identify base name for this bb data.
-	foreach $func (keys(%{$bb})) {
-		$filedata = $bb->{$func};
-
-		foreach $file (keys(%{$filedata})) {
-			$count = $file_count{$file};
-
-			# Count file occurrence
-			$file_count{$file} = defined($count) ? $count + 1 : 1;
-		}
-	}
-	$count = 0;
-	$num = 0;
-	foreach $file (keys(%file_count)) {
-		if ($file_count{$file} > $count) {
-			# The file that contains code for the most functions
-			# is likely the base file
-			$count = $file_count{$file};
-			$num = 1;
-			$basefile = $file;
-		} elsif ($file_count{$file} == $count) {
-			# If more than one file could be the basefile, we
-			# don't have a basefile
-			$basefile = undef;
-		}
-	}
-
-	return $basefile;
-}
-
-#
-# graph_from_bb(bb, fileorder, bb_filename)
-#
-# Convert data from bb to the graph format and list of instrumented lines.
-# Returns (instr, graph).
-#
-# bb         : function name -> file data
-#            : undef -> file order
-# file data  : filename -> line data
-# line data  : [ line1, line2, ... ]
-#
-# file order : function name -> [ filename1, filename2, ... ]
-#
-# graph         : file name -> function data
-# function data : function name -> line data
-# line data     : [ line1, line2, ... ]
-#
-# instr     : filename -> line data
-# line data : [ line1, line2, ... ]
-#
-
-sub graph_from_bb($$$)
-{
-	my ($bb, $fileorder, $bb_filename) = @_;
-	my $graph = {};
-	my $instr = {};
-	my $basefile;
-	my $file;
-	my $func;
-	my $filedata;
-	my $linedata;
-	my $order;
-
-	$basefile = graph_find_base($bb);
-	# Create graph structure
-	foreach $func (keys(%{$bb})) {
-		$filedata = $bb->{$func};
-		$order = $fileorder->{$func};
-
-		# Account for lines in functions
-		if (defined($basefile) && defined($filedata->{$basefile})) {
-			# If the basefile contributes to this function,
-			# account this function to the basefile.
-			$graph->{$basefile}->{$func} = $filedata->{$basefile};
-		} else {
-			# If the basefile does not contribute to this function,
-			# account this function to the first file contributing
-			# lines.
-			$graph->{$order->[0]}->{$func} =
-				$filedata->{$order->[0]};
-		}
-
-		foreach $file (keys(%{$filedata})) {
-			# Account for instrumented lines
-			$linedata = $filedata->{$file};
-			push(@{$instr->{$file}}, @$linedata);
-		}
-	}
-	# Clean up array of instrumented lines
-	foreach $file (keys(%{$instr})) {
-		$instr->{$file} = [ sort_uniq(@{$instr->{$file}}) ];
-	}
-
-	return ($instr, $graph);
-}
-
-#
-# graph_add_order(fileorder, function, filename)
-#
-# Add an entry for filename to the fileorder data set for function.
-#
-
-sub graph_add_order($$$)
-{
-	my ($fileorder, $function, $filename) = @_;
-	my $item;
-	my $list;
-
-	$list = $fileorder->{$function};
-	foreach $item (@$list) {
-		if ($item eq $filename) {
-			return;
-		}
-	}
-	push(@$list, $filename);
-	$fileorder->{$function} = $list;
-}
-#
-# read_bb_word(handle[, description])
-#
-# Read and return a word in .bb format from handle.
-#
-
-sub read_bb_word(*;$)
-{
-	my ($handle, $desc) = @_;
-
-	return graph_read($handle, 4, $desc);
-}
-
-#
-# read_bb_value(handle[, description])
-#
-# Read a word in .bb format from handle and return the word and its integer
-# value.
-#
-
-sub read_bb_value(*;$)
-{
-	my ($handle, $desc) = @_;
-	my $word;
-
-	$word = read_bb_word($handle, $desc);
-	return undef if (!defined($word));
-
-	return ($word, unpack("V", $word));
-}
-
-#
-# read_bb_string(handle, delimiter)
-#
-# Read and return a string in .bb format from handle up to the specified
-# delimiter value.
-#
-
-sub read_bb_string(*$)
-{
-	my ($handle, $delimiter) = @_;
-	my $word;
-	my $value;
-	my $string = "";
-
-	graph_expect("string");
-	do {
-		($word, $value) = read_bb_value($handle, "string or delimiter");
-		return undef if (!defined($value));
-		if ($value != $delimiter) {
-			$string .= $word;
-		}
-	} while ($value != $delimiter);
-	$string =~ s/\0//g;
-
-	return $string;
-}
-
-#
-# read_bb(filename, base_dir)
-#
-# Read the contents of the specified .bb file and return (instr, graph), where:
-#
-#   instr     : filename -> line data
-#   line data : [ line1, line2, ... ]
-#
-#   graph     :     filename -> file_data
-#   file_data : function name -> line_data
-#   line_data : [ line1, line2, ... ]
-#
-# Relative filenames are converted to absolute form using base_dir as
-# base directory. See the gcov info pages of gcc 2.95 for a description of
-# the .bb file format.
-#
-
-sub read_bb($$)
-{
-	my ($bb_filename, $base) = @_;
-	my $minus_one = 0x80000001;
-	my $minus_two = 0x80000002;
-	my $value;
-	my $filename;
-	my $function;
-	my $bb = {};
-	my $fileorder = {};
-	my $instr;
-	my $graph;
-	local *HANDLE;
-
-	open(HANDLE, "<$bb_filename") or goto open_error;
-	binmode(HANDLE);
-	while (!eof(HANDLE)) {
-		$value = read_bb_value(*HANDLE, "data word");
-		goto incomplete if (!defined($value));
-		if ($value == $minus_one) {
-			# Source file name
-			graph_expect("filename");
-			$filename = read_bb_string(*HANDLE, $minus_one);
-			goto incomplete if (!defined($filename));
-			if ($filename ne "") {
-				$filename = solve_relative_path($base,
-								$filename);
-			}
-		} elsif ($value == $minus_two) {
-			# Function name
-			graph_expect("function name");
-			$function = read_bb_string(*HANDLE, $minus_two);
-			goto incomplete if (!defined($function));
-		} elsif ($value > 0) {
-			# Line number
-			if (!defined($filename) || !defined($function)) {
-				warn("WARNING: unassigned line number ".
-				     "$value\n");
-				next;
-			}
-			push(@{$bb->{$function}->{$filename}}, $value);
-			graph_add_order($fileorder, $function, $filename);
-		}
-	}
-	close(HANDLE);
-	($instr, $graph) = graph_from_bb($bb, $fileorder, $bb_filename);
-	graph_cleanup($graph);
-
-	return ($instr, $graph);
-
-open_error:
-	graph_error($bb_filename, "could not open file");
-	return undef;
-incomplete:
-	graph_error($bb_filename, "reached unexpected end of file");
-	return undef;
-}
-
-#
-# read_bbg_word(handle[, description])
-#
-# Read and return a word in .bbg format.
-#
-
-sub read_bbg_word(*;$)
-{
-	my ($handle, $desc) = @_;
-
-	return graph_read($handle, 4, $desc);
-}
-
-#
-# read_bbg_value(handle[, description])
-#
-# Read a word in .bbg format from handle and return its integer value.
-#
-
-sub read_bbg_value(*;$)
-{
-	my ($handle, $desc) = @_;
-	my $word;
-
-	$word = read_bbg_word($handle, $desc);
-	return undef if (!defined($word));
-
-	return unpack("N", $word);
-}
-
-#
-# read_bbg_string(handle)
-#
-# Read and return a string in .bbg format.
-#
-
-sub read_bbg_string(*)
-{
-	my ($handle, $desc) = @_;
-	my $length;
-	my $string;
-
-	graph_expect("string");
-	# Read string length
-	$length = read_bbg_value($handle, "string length");
-	return undef if (!defined($length));
-	if ($length == 0) {
-		return "";
-	}
-	# Read string
-	$string = graph_read($handle, $length, "string");
-	return undef if (!defined($string));
-	# Skip padding
-	graph_skip($handle, 4 - $length % 4, "string padding") or return undef;
-
-	return $string;
-}
-
-#
-# read_bbg_lines_record(handle, bbg_filename, bb, fileorder, filename,
-#                       function, base)
-#
-# Read a bbg format lines record from handle and add the relevant data to
-# bb and fileorder. Return filename on success, undef on error.
-#
-
-sub read_bbg_lines_record(*$$$$$$)
-{
-	my ($handle, $bbg_filename, $bb, $fileorder, $filename, $function,
-	    $base) = @_;
-	my $string;
-	my $lineno;
-
-	graph_expect("lines record");
-	# Skip basic block index
-	graph_skip($handle, 4, "basic block index") or return undef;
-	while (1) {
-		# Read line number
-		$lineno = read_bbg_value($handle, "line number");
-		return undef if (!defined($lineno));
-		if ($lineno == 0) {
-			# Got a marker for a new filename
-			graph_expect("filename");
-			$string = read_bbg_string($handle);
-			return undef if (!defined($string));
-			# Check for end of record
-			if ($string eq "") {
-				return $filename;
-			}
-			$filename = solve_relative_path($base, $string);
-			next;
-		}
-		# Got an actual line number
-		if (!defined($filename)) {
-			warn("WARNING: unassigned line number in ".
-			     "$bbg_filename\n");
-			next;
-		}
-		push(@{$bb->{$function}->{$filename}}, $lineno);
-		graph_add_order($fileorder, $function, $filename);
-	}
-}
-
-#
-# read_bbg(filename, base_dir)
-#
-# Read the contents of the specified .bbg file and return the following mapping:
-#   graph:     filename -> file_data
-#   file_data: function name -> line_data
-#   line_data: [ line1, line2, ... ]
-#
-# Relative filenames are converted to absolute form using base_dir as
-# base directory. See the gcov-io.h file in the SLES 9 gcc 3.3.3 source code
-# for a description of the .bbg format.
-#
-
-sub read_bbg($$)
-{
-	my ($bbg_filename, $base) = @_;
-	my $file_magic = 0x67626267;
-	my $tag_function = 0x01000000;
-	my $tag_lines = 0x01450000;
-	my $word;
-	my $tag;
-	my $length;
-	my $function;
-	my $filename;
-	my $bb = {};
-	my $fileorder = {};
-	my $instr;
-	my $graph;
-	local *HANDLE;
-
-	open(HANDLE, "<$bbg_filename") or goto open_error;
-	binmode(HANDLE);
-	# Read magic
-	$word = read_bbg_value(*HANDLE, "file magic");
-	goto incomplete if (!defined($word));
-	# Check magic
-	if ($word != $file_magic) {
-		goto magic_error;
-	}
-	# Skip version
-	graph_skip(*HANDLE, 4, "version") or goto incomplete;
-	while (!eof(HANDLE)) {
-		# Read record tag
-		$tag = read_bbg_value(*HANDLE, "record tag");
-		goto incomplete if (!defined($tag));
-		# Read record length
-		$length = read_bbg_value(*HANDLE, "record length");
-		goto incomplete if (!defined($tag));
-		if ($tag == $tag_function) {
-			graph_expect("function record");
-			# Read function name
-			graph_expect("function name");
-			$function = read_bbg_string(*HANDLE);
-			goto incomplete if (!defined($function));
-			$filename = undef;
-			# Skip function checksum
-			graph_skip(*HANDLE, 4, "function checksum")
-				or goto incomplete;
-		} elsif ($tag == $tag_lines) {
-			# Read lines record
-			$filename = read_bbg_lines_record(HANDLE, $bbg_filename,
-					  $bb, $fileorder, $filename,
-					  $function, $base);
-			goto incomplete if (!defined($filename));
-		} else {
-			# Skip record contents
-			graph_skip(*HANDLE, $length, "unhandled record")
-				or goto incomplete;
-		}
-	}
-	close(HANDLE);
-	($instr, $graph) = graph_from_bb($bb, $fileorder, $bbg_filename);
-	graph_cleanup($graph);
-
-	return ($instr, $graph);
-
-open_error:
-	graph_error($bbg_filename, "could not open file");
-	return undef;
-incomplete:
-	graph_error($bbg_filename, "reached unexpected end of file");
-	return undef;
-magic_error:
-	graph_error($bbg_filename, "found unrecognized bbg file magic");
-	return undef;
-}
-
-#
-# read_gcno_word(handle[, description])
-#
-# Read and return a word in .gcno format.
-#
-
-sub read_gcno_word(*;$)
-{
-	my ($handle, $desc) = @_;
-
-	return graph_read($handle, 4, $desc);
-}
-
-#
-# read_gcno_value(handle, big_endian[, description])
-#
-# Read a word in .gcno format from handle and return its integer value
-# according to the specified endianness.
-#
-
-sub read_gcno_value(*$;$)
-{
-	my ($handle, $big_endian, $desc) = @_;
-	my $word;
-
-	$word = read_gcno_word($handle, $desc);
-	return undef if (!defined($word));
-	if ($big_endian) {
-		return unpack("N", $word);
-	} else {
-		return unpack("V", $word);
-	}
-}
-
-#
-# read_gcno_string(handle, big_endian)
-#
-# Read and return a string in .gcno format.
-#
-
-sub read_gcno_string(*$)
-{
-	my ($handle, $big_endian) = @_;
-	my $length;
-	my $string;
-
-	graph_expect("string");
-	# Read string length
-	$length = read_gcno_value($handle, $big_endian, "string length");
-	return undef if (!defined($length));
-	if ($length == 0) {
-		return "";
-	}
-	$length *= 4;
-	# Read string
-	$string = graph_read($handle, $length, "string and padding");
-	return undef if (!defined($string));
-	$string =~ s/\0//g;
-
-	return $string;
-}
-
-#
-# read_gcno_lines_record(handle, gcno_filename, bb, fileorder, filename,
-#                        function, base, big_endian)
-#
-# Read a gcno format lines record from handle and add the relevant data to
-# bb and fileorder. Return filename on success, undef on error.
-#
-
-sub read_gcno_lines_record(*$$$$$$$)
-{
-	my ($handle, $gcno_filename, $bb, $fileorder, $filename, $function,
-	    $base, $big_endian) = @_;
-	my $string;
-	my $lineno;
-
-	graph_expect("lines record");
-	# Skip basic block index
-	graph_skip($handle, 4, "basic block index") or return undef;
-	while (1) {
-		# Read line number
-		$lineno = read_gcno_value($handle, $big_endian, "line number");
-		return undef if (!defined($lineno));
-		if ($lineno == 0) {
-			# Got a marker for a new filename
-			graph_expect("filename");
-			$string = read_gcno_string($handle, $big_endian);
-			return undef if (!defined($string));
-			# Check for end of record
-			if ($string eq "") {
-				return $filename;
-			}
-			$filename = solve_relative_path($base, $string);
-			next;
-		}
-		# Got an actual line number
-		if (!defined($filename)) {
-			warn("WARNING: unassigned line number in ".
-			     "$gcno_filename\n");
-			next;
-		}
-		# Add to list
-		push(@{$bb->{$function}->{$filename}}, $lineno);
-		graph_add_order($fileorder, $function, $filename);
-	}
-}
-
-#
-# read_gcno_function_record(handle, graph, base, big_endian)
-#
-# Read a gcno format function record from handle and add the relevant data
-# to graph. Return (filename, function) on success, undef on error. 
-#
-
-sub read_gcno_function_record(*$$$$)
-{
-	my ($handle, $bb, $fileorder, $base, $big_endian) = @_;
-	my $filename;
-	my $function;
-	my $lineno;
-	my $lines;
-
-	graph_expect("function record");
-	# Skip ident and checksum
-	graph_skip($handle, 8, "function ident and checksum") or return undef;
-	# Read function name
-	graph_expect("function name");
-	$function = read_gcno_string($handle, $big_endian);
-	return undef if (!defined($function));
-	# Read filename
-	graph_expect("filename");
-	$filename = read_gcno_string($handle, $big_endian);
-	return undef if (!defined($filename));
-	$filename = solve_relative_path($base, $filename);
-	# Read first line number
-	$lineno = read_gcno_value($handle, $big_endian, "initial line number");
-	return undef if (!defined($lineno));
-	# Add to list
-	push(@{$bb->{$function}->{$filename}}, $lineno);
-	graph_add_order($fileorder, $function, $filename);
-
-	return ($filename, $function);
-}
-
-#
-# read_gcno(filename, base_dir)
-#
-# Read the contents of the specified .gcno file and return the following
-# mapping:
-#   graph:    filename -> file_data
-#   file_data: function name -> line_data
-#   line_data: [ line1, line2, ... ]
-#
-# Relative filenames are converted to absolute form using base_dir as
-# base directory. See the gcov-io.h file in the gcc 3.3 source code
-# for a description of the .gcno format.
-#
-
-sub read_gcno($$)
-{
-	my ($gcno_filename, $base) = @_;
-	my $file_magic = 0x67636e6f;
-	my $tag_function = 0x01000000;
-	my $tag_lines = 0x01450000;
-	my $big_endian;
-	my $word;
-	my $tag;
-	my $length;
-	my $filename;
-	my $function;
-	my $bb = {};
-	my $fileorder = {};
-	my $instr;
-	my $graph;
-	local *HANDLE;
-
-	open(HANDLE, "<$gcno_filename") or goto open_error;
-	binmode(HANDLE);
-	# Read magic
-	$word = read_gcno_word(*HANDLE, "file magic");
-	goto incomplete if (!defined($word));
-	# Determine file endianness
-	if (unpack("N", $word) == $file_magic) {
-		$big_endian = 1;
-	} elsif (unpack("V", $word) == $file_magic) {
-		$big_endian = 0;
-	} else {
-		goto magic_error;
-	}
-	# Skip version and stamp
-	graph_skip(*HANDLE, 8, "version and stamp") or goto incomplete;
-	while (!eof(HANDLE)) {
-		my $next_pos;
-		my $curr_pos;
-
-		# Read record tag
-		$tag = read_gcno_value(*HANDLE, $big_endian, "record tag");
-		goto incomplete if (!defined($tag));
-		# Read record length
-		$length = read_gcno_value(*HANDLE, $big_endian,
-					  "record length");
-		goto incomplete if (!defined($length));
-		# Convert length to bytes
-		$length *= 4;
-		# Calculate start of next record
-		$next_pos = tell(HANDLE);
-		goto tell_error if ($next_pos == -1);
-		$next_pos += $length;
-		# Process record
-		if ($tag == $tag_function) {
-			($filename, $function) = read_gcno_function_record(
-				*HANDLE, $bb, $fileorder, $base, $big_endian);
-			goto incomplete if (!defined($function));
-		} elsif ($tag == $tag_lines) {
-			# Read lines record
-			$filename = read_gcno_lines_record(*HANDLE,
-					$gcno_filename, $bb, $fileorder,
-					$filename, $function, $base,
-					$big_endian);
-			goto incomplete if (!defined($filename));
-		} else {
-			# Skip record contents
-			graph_skip(*HANDLE, $length, "unhandled record")
-				or goto incomplete;
-		}
-		# Ensure that we are at the start of the next record
-		$curr_pos = tell(HANDLE);
-		goto tell_error if ($curr_pos == -1);
-		next if ($curr_pos == $next_pos);
-		goto record_error if ($curr_pos > $next_pos);
-		graph_skip(*HANDLE, $next_pos - $curr_pos,
-			   "unhandled record content")
-			or goto incomplete;
-	}
-	close(HANDLE);
-	($instr, $graph) = graph_from_bb($bb, $fileorder, $gcno_filename);
-	graph_cleanup($graph);
-
-	return ($instr, $graph);
-
-open_error:
-	graph_error($gcno_filename, "could not open file");
-	return undef;
-incomplete:
-	graph_error($gcno_filename, "reached unexpected end of file");
-	return undef;
-magic_error:
-	graph_error($gcno_filename, "found unrecognized gcno file magic");
-	return undef;
-tell_error:
-	graph_error($gcno_filename, "could not determine file position");
-	return undef;
-record_error:
-	graph_error($gcno_filename, "found unrecognized record format");
-	return undef;
-}
-
-sub debug($)
-{
-	my ($msg) = @_;
-
-	return if (!$debug);
-	print(STDERR "DEBUG: $msg");
-}
-
-#
-# get_gcov_capabilities
-#
-# Determine the list of available gcov options.
-#
-
-sub get_gcov_capabilities()
-{
-	my $help = `$gcov_tool --help`;
-	my %capabilities;
-
-	foreach (split(/\n/, $help)) {
-		next if (!/--(\S+)/);
-		next if ($1 eq 'help');
-		next if ($1 eq 'version');
-		next if ($1 eq 'object-directory');
-
-		$capabilities{$1} = 1;
-		debug("gcov has capability '$1'\n");
-	}
-
-	return \%capabilities;
-}
diff --git a/third_party/lcov-1.9/bin/genpng b/third_party/lcov-1.9/bin/genpng
deleted file mode 100755
index 7fe9dfe..0000000
--- a/third_party/lcov-1.9/bin/genpng
+++ /dev/null
@@ -1,384 +0,0 @@
-#!/usr/bin/perl -w
-#
-#   Copyright (c) International Business Machines  Corp., 2002
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.                 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-#
-# genpng
-#
-#   This script creates an overview PNG image of a source code file by
-#   representing each source code character by a single pixel.
-#
-#   Note that the PERL module GD.pm is required for this script to work.
-#   It may be obtained from http://www.cpan.org
-#
-# History:
-#   2002-08-26: created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-#
-
-use strict;
-use File::Basename; 
-use Getopt::Long;
-
-
-# Constants
-our $lcov_version	= 'LCOV version 1.9';
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
-our $tool_name		= basename($0);
-
-
-# Prototypes
-sub gen_png($$$@);
-sub check_and_load_module($);
-sub genpng_print_usage(*);
-sub genpng_process_file($$$$);
-sub genpng_warn_handler($);
-sub genpng_die_handler($);
-
-
-#
-# Code entry point
-#
-
-# Prettify version string
-$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
-
-# Check whether required module GD.pm is installed
-if (check_and_load_module("GD"))
-{
-	# Note: cannot use die() to print this message because inserting this
-	# code into another script via do() would not fail as required!
-	print(STDERR <<END_OF_TEXT)
-ERROR: required module GD.pm not found on this system (see www.cpan.org).
-END_OF_TEXT
-	;
-	exit(2);
-}
-
-# Check whether we're called from the command line or from another script
-if (!caller)
-{
-	my $filename;
-	my $tab_size = 4;
-	my $width = 80;
-	my $out_filename;
-	my $help;
-	my $version;
-
-	$SIG{__WARN__} = \&genpng_warn_handler;
-	$SIG{__DIE__} = \&genpng_die_handler;
-
-	# Parse command line options
-	if (!GetOptions("tab-size=i" => \$tab_size,
-			"width=i" => \$width,
-			"output-filename=s" => \$out_filename,
-			"help" => \$help,
-			"version" => \$version))
-	{
-		print(STDERR "Use $tool_name --help to get usage ".
-		      "information\n");
-		exit(1);
-	}
-
-	$filename = $ARGV[0];
-
-	# Check for help flag
-	if ($help)
-	{
-		genpng_print_usage(*STDOUT);
-		exit(0);
-	}
-
-	# Check for version flag
-	if ($version)
-	{
-		print("$tool_name: $lcov_version\n");
-		exit(0);
-	}
-
-	# Check options
-	if (!$filename)
-	{
-		die("No filename specified\n");
-	}
-
-	# Check for output filename
-	if (!$out_filename)
-	{
-		$out_filename = "$filename.png";
-	}
-
-	genpng_process_file($filename, $out_filename, $width, $tab_size);
-	exit(0);
-}
-
-
-#
-# genpng_print_usage(handle)
-#
-# Write out command line usage information to given filehandle.
-#
-
-sub genpng_print_usage(*)
-{
-	local *HANDLE = $_[0];
-
-	print(HANDLE <<END_OF_USAGE)
-Usage: $tool_name [OPTIONS] SOURCEFILE
-
-Create an overview image for a given source code file of either plain text
-or .gcov file format.
-
-  -h, --help                        Print this help, then exit
-  -v, --version                     Print version number, then exit
-  -t, --tab-size TABSIZE            Use TABSIZE spaces in place of tab
-  -w, --width WIDTH                 Set width of output image to WIDTH pixel
-  -o, --output-filename FILENAME    Write image to FILENAME
-
-For more information see: $lcov_url
-END_OF_USAGE
-	;
-}
-
-
-#
-# check_and_load_module(module_name)
-#
-# Check whether a module by the given name is installed on this system
-# and make it known to the interpreter if available. Return undefined if it
-# is installed, an error message otherwise.
-#
-
-sub check_and_load_module($)
-{
-	eval("use $_[0];");
-	return $@;
-}
-
-
-#
-# genpng_process_file(filename, out_filename, width, tab_size)
-#
-
-sub genpng_process_file($$$$)
-{
-	my $filename		= $_[0];
-	my $out_filename	= $_[1];
-	my $width		= $_[2];
-	my $tab_size		= $_[3];
-	local *HANDLE;
-	my @source;
-
-	open(HANDLE, "<$filename")
-		or die("ERROR: cannot open $filename!\n");
-
-	# Check for .gcov filename extension
-	if ($filename =~ /^(.*).gcov$/)
-	{
-		# Assume gcov text format
-		while (<HANDLE>)
-		{
-			if (/^\t\t(.*)$/)
-			{
-				# Uninstrumented line
-				push(@source, ":$1");
-			}
-			elsif (/^      ######    (.*)$/)
-			{
-				# Line with zero execution count
-				push(@source, "0:$1");
-			}
-			elsif (/^( *)(\d*)    (.*)$/)
-			{
-				# Line with positive execution count
-				push(@source, "$2:$3");
-			}
-		}
-	}
-	else
-	{
-		# Plain text file
-		while (<HANDLE>) { push(@source, ":$_"); }
-	}
-	close(HANDLE);
-
-	gen_png($out_filename, $width, $tab_size, @source);
-}
-
-
-#
-# gen_png(filename, width, tab_size, source)
-#
-# Write an overview PNG file to FILENAME. Source code is defined by SOURCE
-# which is a list of lines <count>:<source code> per source code line.
-# The output image will be made up of one pixel per character of source,
-# coloring will be done according to execution counts. WIDTH defines the
-# image width. TAB_SIZE specifies the number of spaces to use as replacement
-# string for tabulator signs in source code text.
-#
-# Die on error.
-#
-
-sub gen_png($$$@)
-{
-	my $filename = shift(@_);	# Filename for PNG file
-	my $overview_width = shift(@_);	# Imagewidth for image
-	my $tab_size = shift(@_);	# Replacement string for tab signs
-	my @source = @_;	# Source code as passed via argument 2
-	my $height = scalar(@source);	# Height as define by source size
-	my $overview;		# Source code overview image data
-	my $col_plain_back;	# Color for overview background
-	my $col_plain_text;	# Color for uninstrumented text
-	my $col_cov_back;	# Color for background of covered lines
-	my $col_cov_text;	# Color for text of covered lines
-	my $col_nocov_back;	# Color for background of lines which
-				# were not covered (count == 0)
-	my $col_nocov_text;	# Color for test of lines which were not
-				# covered (count == 0)
-	my $col_hi_back;	# Color for background of highlighted lines
-	my $col_hi_text;	# Color for text of highlighted lines
-	my $line;		# Current line during iteration
-	my $row = 0;		# Current row number during iteration
-	my $column;		# Current column number during iteration
-	my $color_text;		# Current text color during iteration
-	my $color_back;		# Current background color during iteration
-	my $last_count;		# Count of last processed line
-	my $count;		# Count of current line
-	my $source;		# Source code of current line
-	my $replacement;	# Replacement string for tabulator chars
-	local *PNG_HANDLE;	# Handle for output PNG file
-
-	# Create image
-	$overview = new GD::Image($overview_width, $height)
-		or die("ERROR: cannot allocate overview image!\n");
-
-	# Define colors
-	$col_plain_back	= $overview->colorAllocate(0xff, 0xff, 0xff);
-	$col_plain_text	= $overview->colorAllocate(0xaa, 0xaa, 0xaa);
-	$col_cov_back	= $overview->colorAllocate(0xaa, 0xa7, 0xef);
-	$col_cov_text	= $overview->colorAllocate(0x5d, 0x5d, 0xea);
-	$col_nocov_back = $overview->colorAllocate(0xff, 0x00, 0x00);
-	$col_nocov_text = $overview->colorAllocate(0xaa, 0x00, 0x00);
-	$col_hi_back = $overview->colorAllocate(0x00, 0xff, 0x00);
-	$col_hi_text = $overview->colorAllocate(0x00, 0xaa, 0x00);
-
-	# Visualize each line
-	foreach $line (@source)
-	{
-		# Replace tabs with spaces to keep consistent with source
-		# code view
-		while ($line =~ /^([^\t]*)(\t)/)
-		{
-			$replacement = " "x($tab_size - ((length($1) - 1) %
-				       $tab_size));
-			$line =~ s/^([^\t]*)(\t)/$1$replacement/;
-		}
-
-		# Skip lines which do not follow the <count>:<line>
-		# specification, otherwise $1 = count, $2 = source code
-		if (!($line =~ /(\*?)(\d*):(.*)$/)) { next; }
-		$count = $2;
-		$source = $3;
-
-		# Decide which color pair to use
-
-		# If this line was not instrumented but the one before was,
-		# take the color of that line to widen color areas in
-		# resulting image
-		if (($count eq "") && defined($last_count) &&
-		    ($last_count ne ""))
-		{
-			$count = $last_count;
-		}
-
-		if ($count eq "")
-		{
-			# Line was not instrumented
-			$color_text = $col_plain_text;
-			$color_back = $col_plain_back;
-		}
-		elsif ($count == 0)
-		{
-			# Line was instrumented but not executed
-			$color_text = $col_nocov_text;
-			$color_back = $col_nocov_back;
-		}
-		elsif ($1 eq "*")
-		{
-			# Line was highlighted
-			$color_text = $col_hi_text;
-			$color_back = $col_hi_back;
-		}
-		else
-		{
-			# Line was instrumented and executed
-			$color_text = $col_cov_text;
-			$color_back = $col_cov_back;
-		}
-
-		# Write one pixel for each source character
-		$column = 0;
-		foreach (split("", $source))
-		{
-			# Check for width
-			if ($column >= $overview_width) { last; }
-
-			if ($_ eq " ")
-			{
-				# Space
-				$overview->setPixel($column++, $row,
-						    $color_back);
-			}
-			else
-			{
-				# Text
-				$overview->setPixel($column++, $row,
-						    $color_text);
-			}
-		}
-
-		# Fill rest of line		
-		while ($column < $overview_width)
-		{
-			$overview->setPixel($column++, $row, $color_back);
-		}
-
-		$last_count = $2;
-
-		$row++;
-	}
-
-	# Write PNG file
-	open (PNG_HANDLE, ">$filename")
-		or die("ERROR: cannot write png file $filename!\n");
-	binmode(*PNG_HANDLE);
-	print(PNG_HANDLE $overview->png());
-	close(PNG_HANDLE);
-}
-
-sub genpng_warn_handler($)
-{
-	my ($msg) = @_;
-
-	warn("$tool_name: $msg");
-}
-
-sub genpng_die_handler($)
-{
-	my ($msg) = @_;
-
-	die("$tool_name: $msg");
-}
diff --git a/third_party/lcov-1.9/bin/install.sh b/third_party/lcov-1.9/bin/install.sh
deleted file mode 100755
index 27140f9..0000000
--- a/third_party/lcov-1.9/bin/install.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/bash
-#
-# install.sh [--uninstall] sourcefile targetfile [install options]
-#
-
-
-# Check for uninstall option
-if test "x$1" == "x--uninstall" ; then
-  UNINSTALL=true
-  SOURCE=$2
-  TARGET=$3
-  shift 3
-else
-  UNINSTALL=false
-  SOURCE=$1
-  TARGET=$2
-  shift 2
-fi
-
-# Check usage
-if test -z "$SOURCE" || test -z "$TARGET" ; then
-  echo Usage: install.sh [--uninstall] source target [install options] >&2
-  exit 1
-fi
-
-
-#
-# do_install(SOURCE_FILE, TARGET_FILE)
-#
-
-do_install()
-{
-  local SOURCE=$1
-  local TARGET=$2
-  local PARAMS=$3
-
-  install -p -D $PARAMS $SOURCE $TARGET
-}
-
-
-#
-# do_uninstall(SOURCE_FILE, TARGET_FILE)
-#
-
-do_uninstall()
-{
-  local SOURCE=$1
-  local TARGET=$2
-
-  # Does target exist?
-  if test -r $TARGET ; then
-    # Is target of the same version as this package?
-    if diff $SOURCE $TARGET >/dev/null; then
-      rm -f $TARGET
-    else
-      echo WARNING: Skipping uninstall for $TARGET - versions differ! >&2
-    fi
-  else
-    echo WARNING: Skipping uninstall for $TARGET - not installed! >&2
-  fi
-}
-
-
-# Call sub routine
-if $UNINSTALL ; then
-  do_uninstall $SOURCE $TARGET
-else
-  do_install $SOURCE $TARGET "$*"
-fi
-
-exit 0
diff --git a/third_party/lcov-1.9/bin/lcov b/third_party/lcov-1.9/bin/lcov
deleted file mode 100755
index 4e392ff..0000000
--- a/third_party/lcov-1.9/bin/lcov
+++ /dev/null
@@ -1,4175 +0,0 @@
-#!/usr/bin/perl -w
-#
-#   Copyright (c) International Business Machines  Corp., 2002,2010
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.                 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-#
-# lcov
-#
-#   This is a wrapper script which provides a single interface for accessing
-#   LCOV coverage data.
-#
-#
-# History:
-#   2002-08-29 created by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-#                         IBM Lab Boeblingen
-#   2002-09-05 / Peter Oberparleiter: implemented --kernel-directory +
-#                multiple directories
-#   2002-10-16 / Peter Oberparleiter: implemented --add-tracefile option
-#   2002-10-17 / Peter Oberparleiter: implemented --extract option
-#   2002-11-04 / Peter Oberparleiter: implemented --list option
-#   2003-03-07 / Paul Larson: Changed to make it work with the latest gcov 
-#                kernel patch.  This will break it with older gcov-kernel
-#                patches unless you change the value of $gcovmod in this script
-#   2003-04-07 / Peter Oberparleiter: fixed bug which resulted in an error
-#                when trying to combine .info files containing data without
-#                a test name
-#   2003-04-10 / Peter Oberparleiter: extended Paul's change so that LCOV
-#                works both with the new and the old gcov-kernel patch
-#   2003-04-10 / Peter Oberparleiter: added $gcov_dir constant in anticipation
-#                of a possible move of the gcov kernel directory to another
-#                file system in a future version of the gcov-kernel patch
-#   2003-04-15 / Paul Larson: make info write to STDERR, not STDOUT
-#   2003-04-15 / Paul Larson: added --remove option
-#   2003-04-30 / Peter Oberparleiter: renamed --reset to --zerocounters
-#                to remove naming ambiguity with --remove
-#   2003-04-30 / Peter Oberparleiter: adjusted help text to include --remove
-#   2003-06-27 / Peter Oberparleiter: implemented --diff
-#   2003-07-03 / Peter Oberparleiter: added line checksum support, added
-#                --no-checksum
-#   2003-12-11 / Laurent Deniel: added --follow option
-#   2004-03-29 / Peter Oberparleiter: modified --diff option to better cope with
-#                ambiguous patch file entries, modified --capture option to use
-#                modprobe before insmod (needed for 2.6)
-#   2004-03-30 / Peter Oberparleiter: added --path option
-#   2004-08-09 / Peter Oberparleiter: added configuration file support
-#   2008-08-13 / Peter Oberparleiter: added function coverage support
-#
-
-use strict;
-use File::Basename;
-use File::Path;
-use File::Find;
-use File::Temp qw /tempdir/;
-use File::Spec::Functions qw /abs2rel canonpath catdir catfile catpath
-			      file_name_is_absolute rootdir splitdir splitpath/;
-use Getopt::Long;
-use Cwd qw /abs_path getcwd/;
-
-
-# Global constants
-our $lcov_version	= 'LCOV version 1.9';
-our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
-our $tool_name		= basename($0);
-
-# Directory containing gcov kernel files
-our $gcov_dir;
-
-# Where to create temporary directories
-our $tmp_dir;
-
-# Internal constants
-our $GKV_PROC = 0;	# gcov-kernel data in /proc via external patch
-our $GKV_SYS = 1;	# gcov-kernel data in /sys via vanilla 2.6.31+
-our @GKV_NAME = ( "external", "upstream" );
-our $pkg_gkv_file = ".gcov_kernel_version";
-our $pkg_build_file = ".build_directory";
-
-our $BR_BLOCK		= 0;
-our $BR_BRANCH		= 1;
-our $BR_TAKEN		= 2;
-our $BR_VEC_ENTRIES	= 3;
-our $BR_VEC_WIDTH	= 32;
-
-# Branch data combination types
-our $BR_SUB = 0;
-our $BR_ADD = 1;
-
-# Prototypes
-sub print_usage(*);
-sub check_options();
-sub userspace_reset();
-sub userspace_capture();
-sub kernel_reset();
-sub kernel_capture();
-sub kernel_capture_initial();
-sub package_capture();
-sub add_traces();
-sub read_info_file($);
-sub get_info_entry($);
-sub set_info_entry($$$$$$$$$;$$$$$$);
-sub add_counts($$);
-sub merge_checksums($$$);
-sub combine_info_entries($$$);
-sub combine_info_files($$);
-sub write_info_file(*$);
-sub extract();
-sub remove();
-sub list();
-sub get_common_filename($$);
-sub read_diff($);
-sub diff();
-sub system_no_output($@);
-sub read_config($);
-sub apply_config($);
-sub info(@);
-sub create_temp_dir();
-sub transform_pattern($);
-sub warn_handler($);
-sub die_handler($);
-sub abort_handler($);
-sub temp_cleanup();
-sub setup_gkv();
-sub get_overall_line($$$$);
-sub print_overall_rate($$$$$$$$$);
-sub lcov_geninfo(@);
-sub create_package($$$;$);
-sub get_func_found_and_hit($);
-sub br_ivec_get($$);
-
-# Global variables & initialization
-our @directory;		# Specifies where to get coverage data from
-our @kernel_directory;	# If set, captures only from specified kernel subdirs
-our @add_tracefile;	# If set, reads in and combines all files in list
-our $list;		# If set, list contents of tracefile
-our $extract;		# If set, extracts parts of tracefile
-our $remove;		# If set, removes parts of tracefile
-our $diff;		# If set, modifies tracefile according to diff
-our $reset;		# If set, reset all coverage data to zero
-our $capture;		# If set, capture data
-our $output_filename;	# Name for file to write coverage data to
-our $test_name = "";	# Test case name
-our $quiet = "";	# If set, suppress information messages
-our $help;		# Help option flag
-our $version;		# Version option flag
-our $convert_filenames;	# If set, convert filenames when applying diff
-our $strip;		# If set, strip leading directories when applying diff
-our $temp_dir_name;	# Name of temporary directory
-our $cwd = `pwd`;	# Current working directory
-our $to_file;		# If set, indicates that output is written to a file
-our $follow;		# If set, indicates that find shall follow links
-our $diff_path = "";	# Path removed from tracefile when applying diff
-our $base_directory;	# Base directory (cwd of gcc during compilation)
-our $checksum;		# If set, calculate a checksum for each line
-our $no_checksum;	# If set, don't calculate a checksum for each line
-our $compat_libtool;	# If set, indicates that libtool mode is to be enabled
-our $no_compat_libtool;	# If set, indicates that libtool mode is to be disabled
-our $gcov_tool;
-our $ignore_errors;
-our $initial;
-our $no_recursion = 0;
-our $to_package;
-our $from_package;
-our $maxdepth;
-our $no_markers;
-our $config;		# Configuration file contents
-chomp($cwd);
-our $tool_dir = dirname($0);	# Directory where genhtml tool is installed
-our @temp_dirs;
-our $gcov_gkv;		# gcov kernel support version found on machine
-our $opt_derive_func_data;
-our $opt_debug;
-our $opt_list_full_path;
-our $opt_no_list_full_path;
-our $opt_list_width = 80;
-our $opt_list_truncate_max = 20;
-our $ln_overall_found;
-our $ln_overall_hit;
-our $fn_overall_found;
-our $fn_overall_hit;
-our $br_overall_found;
-our $br_overall_hit;
-
-
-#
-# Code entry point
-#
-
-$SIG{__WARN__} = \&warn_handler;
-$SIG{__DIE__} = \&die_handler;
-$SIG{'INT'} = \&abort_handler;
-$SIG{'QUIT'} = \&abort_handler;
-
-# Prettify version string
-$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
-
-# Add current working directory if $tool_dir is not already an absolute path
-if (! ($tool_dir =~ /^\/(.*)$/))
-{
-	$tool_dir = "$cwd/$tool_dir";
-}
-
-# Read configuration file if available
-if (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
-{
-	$config = read_config($ENV{"HOME"}."/.lcovrc");
-}
-elsif (-r "/etc/lcovrc")
-{
-	$config = read_config("/etc/lcovrc");
-}
-
-if ($config)
-{
-	# Copy configuration file values to variables
-	apply_config({
-		"lcov_gcov_dir"		=> \$gcov_dir,
-		"lcov_tmp_dir"		=> \$tmp_dir,
-		"lcov_list_full_path"	=> \$opt_list_full_path,
-		"lcov_list_width"	=> \$opt_list_width,
-		"lcov_list_truncate_max"=> \$opt_list_truncate_max,
-	});
-}
-
-# Parse command line options
-if (!GetOptions("directory|d|di=s" => \@directory,
-		"add-tracefile|a=s" => \@add_tracefile,
-		"list|l=s" => \$list,
-		"kernel-directory|k=s" => \@kernel_directory,
-		"extract|e=s" => \$extract,
-		"remove|r=s" => \$remove,
-		"diff=s" => \$diff,
-		"convert-filenames" => \$convert_filenames,
-		"strip=i" => \$strip,
-		"capture|c" => \$capture,
-		"output-file|o=s" => \$output_filename,
-		"test-name|t=s" => \$test_name,
-		"zerocounters|z" => \$reset,
-		"quiet|q" => \$quiet,
-		"help|h|?" => \$help,
-		"version|v" => \$version,
-		"follow|f" => \$follow,
-		"path=s" => \$diff_path,
-		"base-directory|b=s" => \$base_directory,
-		"checksum" => \$checksum,
-		"no-checksum" => \$no_checksum,
-		"compat-libtool" => \$compat_libtool,
-		"no-compat-libtool" => \$no_compat_libtool,
-		"gcov-tool=s" => \$gcov_tool,
-		"ignore-errors=s" => \$ignore_errors,
-		"initial|i" => \$initial,
-		"no-recursion" => \$no_recursion,
-		"to-package=s" => \$to_package,
-		"from-package=s" => \$from_package,
-		"no-markers" => \$no_markers,
-		"derive-func-data" => \$opt_derive_func_data,
-		"debug" => \$opt_debug,
-		"list-full-path" => \$opt_list_full_path,
-		"no-list-full-path" => \$opt_no_list_full_path,
-		))
-{
-	print(STDERR "Use $tool_name --help to get usage information\n");
-	exit(1);
-}
-else
-{
-	# Merge options
-	if (defined($no_checksum))
-	{
-		$checksum = ($no_checksum ? 0 : 1);
-		$no_checksum = undef;
-	}
-
-	if (defined($no_compat_libtool))
-	{
-		$compat_libtool = ($no_compat_libtool ? 0 : 1);
-		$no_compat_libtool = undef;
-	}
-
-	if (defined($opt_no_list_full_path))
-	{
-		$opt_list_full_path = ($opt_no_list_full_path ? 0 : 1);
-		$opt_no_list_full_path = undef;
-	}
-}
-
-# Check for help option
-if ($help)
-{
-	print_usage(*STDOUT);
-	exit(0);
-}
-
-# Check for version option
-if ($version)
-{
-	print("$tool_name: $lcov_version\n");
-	exit(0);
-}
-
-# Check list width option
-if ($opt_list_width <= 40) {
-	die("ERROR: lcov_list_width parameter out of range (needs to be ".
-	    "larger than 40)\n");
-}
-
-# Normalize --path text
-$diff_path =~ s/\/$//;
-
-if ($follow)
-{
-	$follow = "-follow";
-}
-else
-{
-	$follow = "";
-}
-
-if ($no_recursion)
-{
-	$maxdepth = "-maxdepth 1";
-}
-else
-{
-	$maxdepth = "";
-}
-
-# Check for valid options
-check_options();
-
-# Only --extract, --remove and --diff allow unnamed parameters
-if (@ARGV && !($extract || $remove || $diff))
-{
-	die("Extra parameter found: '".join(" ", @ARGV)."'\n".
-	    "Use $tool_name --help to get usage information\n");
-}
-
-# Check for output filename
-$to_file = ($output_filename && ($output_filename ne "-"));
-
-if ($capture)
-{
-	if (!$to_file)
-	{
-		# Option that tells geninfo to write to stdout
-		$output_filename = "-";
-	}
-}
-
-# Determine kernel directory for gcov data
-if (!$from_package && !@directory && ($capture || $reset)) {
-	($gcov_gkv, $gcov_dir) = setup_gkv();
-}
-
-# Check for requested functionality
-if ($reset)
-{
-	# Differentiate between user space and kernel reset
-	if (@directory)
-	{
-		userspace_reset();
-	}
-	else
-	{
-		kernel_reset();
-	}
-}
-elsif ($capture)
-{
-	# Capture source can be user space, kernel or package
-	if ($from_package) {
-		package_capture();
-	} elsif (@directory) {
-		userspace_capture();
-	} else {
-		if ($initial) {
-			if (defined($to_package)) {
-				die("ERROR: --initial cannot be used together ".
-				    "with --to-package\n");
-			}
-			kernel_capture_initial();
-		} else {
-			kernel_capture();
-		}
-	}
-}
-elsif (@add_tracefile)
-{
-	($ln_overall_found, $ln_overall_hit,
-	 $fn_overall_found, $fn_overall_hit,
-	 $br_overall_found, $br_overall_hit) = add_traces();
-}
-elsif ($remove)
-{
-	($ln_overall_found, $ln_overall_hit,
-	 $fn_overall_found, $fn_overall_hit,
-	 $br_overall_found, $br_overall_hit) = remove();
-}
-elsif ($extract)
-{
-	($ln_overall_found, $ln_overall_hit,
-	 $fn_overall_found, $fn_overall_hit,
-	 $br_overall_found, $br_overall_hit) = extract();
-}
-elsif ($list)
-{
-	list();
-}
-elsif ($diff)
-{
-	if (scalar(@ARGV) != 1)
-	{
-		die("ERROR: option --diff requires one additional argument!\n".
-		    "Use $tool_name --help to get usage information\n");
-	}
-	($ln_overall_found, $ln_overall_hit,
-	 $fn_overall_found, $fn_overall_hit,
-	 $br_overall_found, $br_overall_hit) = diff();
-}
-
-temp_cleanup();
-
-if (defined($ln_overall_found)) {
-	print_overall_rate(1, $ln_overall_found, $ln_overall_hit,
-			   1, $fn_overall_found, $fn_overall_hit,
-			   1, $br_overall_found, $br_overall_hit);
-} else {
-	info("Done.\n") if (!$list && !$capture);
-}
-exit(0);
-
-#
-# print_usage(handle)
-#
-# Print usage information.
-#
-
-sub print_usage(*)
-{
-	local *HANDLE = $_[0];
-
-	print(HANDLE <<END_OF_USAGE);
-Usage: $tool_name [OPTIONS]
-
-Use lcov to collect coverage data from either the currently running Linux
-kernel or from a user space application. Specify the --directory option to
-get coverage data for a user space program.
-
-Misc:
-  -h, --help                      Print this help, then exit
-  -v, --version                   Print version number, then exit
-  -q, --quiet                     Do not print progress messages
-
-Operation:
-  -z, --zerocounters              Reset all execution counts to zero
-  -c, --capture                   Capture coverage data
-  -a, --add-tracefile FILE        Add contents of tracefiles
-  -e, --extract FILE PATTERN      Extract files matching PATTERN from FILE
-  -r, --remove FILE PATTERN       Remove files matching PATTERN from FILE
-  -l, --list FILE                 List contents of tracefile FILE
-      --diff FILE DIFF            Transform tracefile FILE according to DIFF
-
-Options:
-  -i, --initial                   Capture initial zero coverage data
-  -t, --test-name NAME            Specify test name to be stored with data
-  -o, --output-file FILENAME      Write data to FILENAME instead of stdout
-  -d, --directory DIR             Use .da files in DIR instead of kernel
-  -f, --follow                    Follow links when searching .da files
-  -k, --kernel-directory KDIR     Capture kernel coverage data only from KDIR
-  -b, --base-directory DIR        Use DIR as base directory for relative paths
-      --convert-filenames         Convert filenames when applying diff
-      --strip DEPTH               Strip initial DEPTH directory levels in diff
-      --path PATH                 Strip PATH from tracefile when applying diff
-      --(no-)checksum             Enable (disable) line checksumming
-      --(no-)compat-libtool       Enable (disable) libtool compatibility mode
-      --gcov-tool TOOL            Specify gcov tool location
-      --ignore-errors ERRORS      Continue after ERRORS (gcov, source, graph)
-      --no-recursion              Exclude subdirectories from processing
-      --to-package FILENAME       Store unprocessed coverage data in FILENAME
-      --from-package FILENAME     Capture from unprocessed data in FILENAME
-      --no-markers                Ignore exclusion markers in source code
-      --derive-func-data          Generate function data from line data
-      --list-full-path            Print full path during a list operation
-
-For more information see: $lcov_url
-END_OF_USAGE
-	;
-}
-
-
-#
-# check_options()
-#
-# Check for valid combination of command line options. Die on error.
-#
-
-sub check_options()
-{
-	my $i = 0;
-
-	# Count occurrence of mutually exclusive options
-	$reset && $i++;
-	$capture && $i++;
-	@add_tracefile && $i++;
-	$extract && $i++;
-	$remove && $i++;
-	$list && $i++;
-	$diff && $i++;
-	
-	if ($i == 0)
-	{
-		die("Need one of the options -z, -c, -a, -e, -r, -l or ".
-		    "--diff\n".
-		    "Use $tool_name --help to get usage information\n");
-	}
-	elsif ($i > 1)
-	{
-		die("ERROR: only one of -z, -c, -a, -e, -r, -l or ".
-		    "--diff allowed!\n".
-		    "Use $tool_name --help to get usage information\n");
-	}
-}
-
-
-#
-# userspace_reset()
-#
-# Reset coverage data found in DIRECTORY by deleting all contained .da files.
-#
-# Die on error.
-#
-
-sub userspace_reset()
-{
-	my $current_dir;
-	my @file_list;
-
-	foreach $current_dir (@directory)
-	{
-		info("Deleting all .da files in $current_dir".
-		     ($no_recursion?"\n":" and subdirectories\n"));
-		@file_list = `find "$current_dir" $maxdepth $follow -name \\*\\.da -o -name \\*\\.gcda -type f 2>/dev/null`;
-		chomp(@file_list);
-		foreach (@file_list)
-		{
-			unlink($_) or die("ERROR: cannot remove file $_!\n");
-		}
-	}
-}
-
-
-#
-# userspace_capture()
-#
-# Capture coverage data found in DIRECTORY and write it to a package (if
-# TO_PACKAGE specified) or to OUTPUT_FILENAME or STDOUT.
-#
-# Die on error.
-#
-
-sub userspace_capture()
-{
-	my $dir;
-	my $build;
-
-	if (!defined($to_package)) {
-		lcov_geninfo(@directory);
-		return;
-	}
-	if (scalar(@directory) != 1) {
-		die("ERROR: -d may be specified only once with --to-package\n");
-	}
-	$dir = $directory[0];
-	if (defined($base_directory)) {
-		$build = $base_directory;
-	} else {
-		$build = $dir;
-	}
-	create_package($to_package, $dir, $build);
-}
-
-
-#
-# kernel_reset()
-#
-# Reset kernel coverage.
-#
-# Die on error.
-#
-
-sub kernel_reset()
-{
-	local *HANDLE;
-	my $reset_file;
-
-	info("Resetting kernel execution counters\n");
-	if (-e "$gcov_dir/vmlinux") {
-		$reset_file = "$gcov_dir/vmlinux";
-	} elsif (-e "$gcov_dir/reset") {
-		$reset_file = "$gcov_dir/reset";
-	} else {
-		die("ERROR: no reset control found in $gcov_dir\n");
-	}
-	open(HANDLE, ">$reset_file") or
-		die("ERROR: cannot write to $reset_file!\n");
-	print(HANDLE "0");
-	close(HANDLE);
-}
-
-
-#
-# lcov_copy_single(from, to)
-# 
-# Copy single regular file FROM to TO without checking its size. This is
-# required to work with special files generated by the kernel
-# seq_file-interface.
-#
-#
-sub lcov_copy_single($$)
-{
-	my ($from, $to) = @_;
-	my $content;
-	local $/;
-	local *HANDLE;
-
-	open(HANDLE, "<$from") or die("ERROR: cannot read $from: $!\n");
-	$content = <HANDLE>;
-	close(HANDLE);
-	open(HANDLE, ">$to") or die("ERROR: cannot write $from: $!\n");
-	if (defined($content)) {
-		print(HANDLE $content);
-	}
-	close(HANDLE);
-}
-
-#
-# lcov_find(dir, function, data[, extension, ...)])
-#
-# Search DIR for files and directories whose name matches PATTERN and run
-# FUNCTION for each match. If not pattern is specified, match all names.
-#
-# FUNCTION has the following prototype:
-#   function(dir, relative_name, data)
-#
-# Where:
-#   dir: the base directory for this search
-#   relative_name: the name relative to the base directory of this entry
-#   data: the DATA variable passed to lcov_find
-#
-sub lcov_find($$$;@)
-{
-	my ($dir, $fn, $data, @pattern) = @_;
-	my $result;
-	my $_fn = sub {
-		my $filename = $File::Find::name;
-
-		if (defined($result)) {
-			return;
-		}		
-		$filename = abs2rel($filename, $dir);
-		foreach (@pattern) {
-			if ($filename =~ /$_/) {
-				goto ok;
-			}
-		}
-		return;
-	ok:
-		$result = &$fn($dir, $filename, $data);
-	};
-	if (scalar(@pattern) == 0) {
-		@pattern = ".*";
-	}
-	find( { wanted => $_fn, no_chdir => 1 }, $dir);
-
-	return $result;
-}
-
-#
-# lcov_copy_fn(from, rel, to)
-#
-# Copy directories, files and links from/rel to to/rel.
-#
-
-sub lcov_copy_fn($$$)
-{
-	my ($from, $rel, $to) = @_;
-	my $absfrom = canonpath(catfile($from, $rel));
-	my $absto = canonpath(catfile($to, $rel));
-
-	if (-d) {
-		if (! -d $absto) {
-			mkpath($absto) or
-				die("ERROR: cannot create directory $absto\n");
-			chmod(0700, $absto);
-		}
-	} elsif (-l) {
-		# Copy symbolic link
-		my $link = readlink($absfrom);
-
-		if (!defined($link)) {
-			die("ERROR: cannot read link $absfrom: $!\n");
-		}
-		symlink($link, $absto) or
-			die("ERROR: cannot create link $absto: $!\n");
-	} else {
-		lcov_copy_single($absfrom, $absto);
-		chmod(0600, $absto);
-	}
-	return undef;
-}
-
-#
-# lcov_copy(from, to, subdirs)
-# 
-# Copy all specified SUBDIRS and files from directory FROM to directory TO. For
-# regular files, copy file contents without checking its size. This is required
-# to work with seq_file-generated files.
-#
-
-sub lcov_copy($$;@)
-{
-	my ($from, $to, @subdirs) = @_;
-	my @pattern;
-
-	foreach (@subdirs) {
-		push(@pattern, "^$_");
-	}
-	lcov_find($from, \&lcov_copy_fn, $to, @pattern);
-}
-
-#
-# lcov_geninfo(directory)
-#
-# Call geninfo for the specified directory and with the parameters specified
-# at the command line.
-#
-
-sub lcov_geninfo(@)
-{
-	my (@dir) = @_;
-	my @param;
-
-	# Capture data
-	info("Capturing coverage data from ".join(" ", @dir)."\n");
-	@param = ("$tool_dir/geninfo", @dir);
-	if ($output_filename)
-	{
-		@param = (@param, "--output-filename", $output_filename);
-	}
-	if ($test_name)
-	{
-		@param = (@param, "--test-name", $test_name);
-	}
-	if ($follow)
-	{
-		@param = (@param, "--follow");
-	}
-	if ($quiet)
-	{
-		@param = (@param, "--quiet");
-	}
-	if (defined($checksum))
-	{
-		if ($checksum)
-		{
-			@param = (@param, "--checksum");
-		}
-		else
-		{
-			@param = (@param, "--no-checksum");
-		}
-	}
-	if ($base_directory)
-	{
-		@param = (@param, "--base-directory", $base_directory);
-	}
-	if ($no_compat_libtool)
-	{
-		@param = (@param, "--no-compat-libtool");
-	}
-	elsif ($compat_libtool)
-	{
-		@param = (@param, "--compat-libtool");
-	}
-	if ($gcov_tool)
-	{
-		@param = (@param, "--gcov-tool", $gcov_tool);
-	}
-	if ($ignore_errors)
-	{
-		@param = (@param, "--ignore-errors", $ignore_errors);
-	}
-	if ($initial)
-	{
-		@param = (@param, "--initial");
-	}
-	if ($no_markers)
-	{
-		@param = (@param, "--no-markers");
-	}
-	if ($opt_derive_func_data)
-	{
-		@param = (@param, "--derive-func-data");
-	}
-	if ($opt_debug)
-	{
-		@param = (@param, "--debug");
-	}
-	system(@param) and exit($? >> 8);
-}
-
-#
-# read_file(filename)
-#
-# Return the contents of the file defined by filename.
-#
-
-sub read_file($)
-{
-	my ($filename) = @_;
-	my $content;
-	local $\;
-	local *HANDLE;
-
-	open(HANDLE, "<$filename") || return undef;
-	$content = <HANDLE>;
-	close(HANDLE);
-
-	return $content;
-}
-
-#
-# get_package(package_file)
-#
-# Unpack unprocessed coverage data files from package_file to a temporary
-# directory and return directory name, build directory and gcov kernel version
-# as found in package.
-#
-
-sub get_package($)
-{
-	my ($file) = @_;
-	my $dir = create_temp_dir();
-	my $gkv;
-	my $build;
-	my $cwd = getcwd();
-	my $count;
-	local *HANDLE;
-
-	info("Reading package $file:\n");
-	info("  data directory .......: $dir\n");
-	$file = abs_path($file);
-	chdir($dir);
-	open(HANDLE, "tar xvfz $file 2>/dev/null|")
-		or die("ERROR: could not process package $file\n");
-	while (<HANDLE>) {
-		if (/\.da$/ || /\.gcda$/) {
-			$count++;
-		}
-	}
-	close(HANDLE);
-	$build = read_file("$dir/$pkg_build_file");
-	if (defined($build)) {
-		info("  build directory ......: $build\n");
-	}
-	$gkv = read_file("$dir/$pkg_gkv_file");
-	if (defined($gkv)) {
-		$gkv = int($gkv);
-		if ($gkv != $GKV_PROC && $gkv != $GKV_SYS) {
-			die("ERROR: unsupported gcov kernel version found ".
-			    "($gkv)\n");
-		}
-		info("  content type .........: kernel data\n");
-		info("  gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
-	} else {
-		info("  content type .........: application data\n");
-	}
-	info("  data files ...........: $count\n");
-	chdir($cwd);
-
-	return ($dir, $build, $gkv);
-}
-
-#
-# write_file(filename, $content)
-#
-# Create a file named filename and write the specified content to it.
-#
-
-sub write_file($$)
-{
-	my ($filename, $content) = @_;
-	local *HANDLE;
-
-	open(HANDLE, ">$filename") || return 0;
-	print(HANDLE $content);
-	close(HANDLE) || return 0;
-
-	return 1;
-}
-
-# count_package_data(filename)
-#
-# Count the number of coverage data files in the specified package file.
-#
-
-sub count_package_data($)
-{
-	my ($filename) = @_;
-	local *HANDLE;
-	my $count = 0;
-
-	open(HANDLE, "tar tfz $filename|") or return undef;
-	while (<HANDLE>) {
-		if (/\.da$/ || /\.gcda$/) {
-			$count++;
-		}
-	}
-	close(HANDLE);
-	return $count;
-}
-
-#
-# create_package(package_file, source_directory, build_directory[,
-# 		 kernel_gcov_version])
-#
-# Store unprocessed coverage data files from source_directory to package_file.
-#
-
-sub create_package($$$;$)
-{
-	my ($file, $dir, $build, $gkv) = @_;
-	my $cwd = getcwd();
-
-	# Print information about the package
-	info("Creating package $file:\n");
-	info("  data directory .......: $dir\n");
-
-	# Handle build directory
-	if (defined($build)) {
-		info("  build directory ......: $build\n");
-		write_file("$dir/$pkg_build_file", $build)
-			or die("ERROR: could not write to ".
-			       "$dir/$pkg_build_file\n");
-	}
-
-	# Handle gcov kernel version data
-	if (defined($gkv)) {
-		info("  content type .........: kernel data\n");
-		info("  gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
-		write_file("$dir/$pkg_gkv_file", $gkv)
-			or die("ERROR: could not write to ".
-			       "$dir/$pkg_gkv_file\n");
-	} else {
-		info("  content type .........: application data\n");
-	}
-
-	# Create package
-	$file = abs_path($file);
-	chdir($dir);
-	system("tar cfz $file .")
-		and die("ERROR: could not create package $file\n");
-
-	# Remove temporary files
-	unlink("$dir/$pkg_build_file");
-	unlink("$dir/$pkg_gkv_file");
-
-	# Show number of data files
-	if (!$quiet) {
-		my $count = count_package_data($file);
-
-		if (defined($count)) {
-			info("  data files ...........: $count\n");
-		}
-	}
-	chdir($cwd);
-}
-
-sub find_link_fn($$$)
-{
-	my ($from, $rel, $filename) = @_;
-	my $absfile = catfile($from, $rel, $filename);
-
-	if (-l $absfile) {
-		return $absfile;
-	}
-	return undef;
-}
-
-#
-# get_base(dir)
-#
-# Return (BASE, OBJ), where
-#  - BASE: is the path to the kernel base directory relative to dir
-#  - OBJ: is the absolute path to the kernel build directory
-#
-
-sub get_base($)
-{
-	my ($dir) = @_;
-	my $marker = "kernel/gcov/base.gcno";
-	my $markerfile;
-	my $sys;
-	my $obj;
-	my $link;
-
-	$markerfile = lcov_find($dir, \&find_link_fn, $marker);
-	if (!defined($markerfile)) {
-		return (undef, undef);
-	}
-
-	# sys base is parent of parent of markerfile.
-	$sys = abs2rel(dirname(dirname(dirname($markerfile))), $dir);
-
-	# obj base is parent of parent of markerfile link target.
-	$link = readlink($markerfile);
-	if (!defined($link)) {
-		die("ERROR: could not read $markerfile\n");
-	}
-	$obj = dirname(dirname(dirname($link)));
-
-	return ($sys, $obj);
-}
-
-#
-# apply_base_dir(data_dir, base_dir, build_dir, @directories)
-#
-# Make entries in @directories relative to data_dir.
-#
-
-sub apply_base_dir($$$@)
-{
-	my ($data, $base, $build, @dirs) = @_;
-	my $dir;
-	my @result;
-
-	foreach $dir (@dirs) {
-		# Is directory path relative to data directory?
-		if (-d catdir($data, $dir)) {
-			push(@result, $dir);
-			next;
-		}
-		# Relative to the auto-detected base-directory?
-		if (defined($base)) {
-			if (-d catdir($data, $base, $dir)) {
-				push(@result, catdir($base, $dir));
-				next;
-			}
-		}
-		# Relative to the specified base-directory?
-		if (defined($base_directory)) {
-			if (file_name_is_absolute($base_directory)) {
-				$base = abs2rel($base_directory, rootdir());
-			} else {
-				$base = $base_directory;
-			}
-			if (-d catdir($data, $base, $dir)) {
-				push(@result, catdir($base, $dir));
-				next;
-			}
-		}
-		# Relative to the build directory?
-		if (defined($build)) {
-			if (file_name_is_absolute($build)) {
-				$base = abs2rel($build, rootdir());
-			} else {
-				$base = $build;
-			}
-			if (-d catdir($data, $base, $dir)) {
-				push(@result, catdir($base, $dir));
-				next;
-			}
-		}
-		die("ERROR: subdirectory $dir not found\n".
-		    "Please use -b to specify the correct directory\n");
-	}
-	return @result;
-}
-
-#
-# copy_gcov_dir(dir, [@subdirectories])
-#
-# Create a temporary directory and copy all or, if specified, only some
-# subdirectories from dir to that directory. Return the name of the temporary
-# directory.
-#
-
-sub copy_gcov_dir($;@)
-{
-	my ($data, @dirs) = @_;
-	my $tempdir = create_temp_dir();
-
-	info("Copying data to temporary directory $tempdir\n");
-	lcov_copy($data, $tempdir, @dirs);
-
-	return $tempdir;
-}
-
-#
-# kernel_capture_initial
-#
-# Capture initial kernel coverage data, i.e. create a coverage data file from
-# static graph files which contains zero coverage data for all instrumented
-# lines.
-#
-
-sub kernel_capture_initial()
-{
-	my $build;
-	my $source;
-	my @params;
-
-	if (defined($base_directory)) {
-		$build = $base_directory;
-		$source = "specified";
-	} else {
-		(undef, $build) = get_base($gcov_dir);
-		if (!defined($build)) {
-			die("ERROR: could not auto-detect build directory.\n".
-			    "Please use -b to specify the build directory\n");
-		}
-		$source = "auto-detected";
-	}
-	info("Using $build as kernel build directory ($source)\n");
-	# Build directory needs to be passed to geninfo
-	$base_directory = $build;
-	if (@kernel_directory) {
-		foreach my $dir (@kernel_directory) {
-			push(@params, "$build/$dir");
-		}
-	} else {
-		push(@params, $build);
-	}
-	lcov_geninfo(@params);
-}
-
-#
-# kernel_capture_from_dir(directory, gcov_kernel_version, build)
-#
-# Perform the actual kernel coverage capturing from the specified directory
-# assuming that the data was copied from the specified gcov kernel version.
-#
-
-sub kernel_capture_from_dir($$$)
-{
-	my ($dir, $gkv, $build) = @_;
-
-	# Create package or coverage file
-	if (defined($to_package)) {
-		create_package($to_package, $dir, $build, $gkv);
-	} else {
-		# Build directory needs to be passed to geninfo
-		$base_directory = $build;
-		lcov_geninfo($dir);
-	}
-}
-
-#
-# adjust_kernel_dir(dir, build)
-#
-# Adjust directories specified with -k so that they point to the directory
-# relative to DIR. Return the build directory if specified or the auto-
-# detected build-directory.
-#
-
-sub adjust_kernel_dir($$)
-{
-	my ($dir, $build) = @_;
-	my ($sys_base, $build_auto) = get_base($dir);
-
-	if (!defined($build)) {
-		$build = $build_auto;
-	}
-	if (!defined($build)) {
-		die("ERROR: could not auto-detect build directory.\n".
-		    "Please use -b to specify the build directory\n");
-	}
-	# Make @kernel_directory relative to sysfs base
-	if (@kernel_directory) {
-		@kernel_directory = apply_base_dir($dir, $sys_base, $build,
-						   @kernel_directory);
-	}
-	return $build;
-}
-
-sub kernel_capture()
-{
-	my $data_dir;
-	my $build = $base_directory;
-
-	if ($gcov_gkv == $GKV_SYS) {
-		$build = adjust_kernel_dir($gcov_dir, $build);
-	}
-	$data_dir = copy_gcov_dir($gcov_dir, @kernel_directory);
-	kernel_capture_from_dir($data_dir, $gcov_gkv, $build);
-}
-
-#
-# package_capture()
-#
-# Capture coverage data from a package of unprocessed coverage data files
-# as generated by lcov --to-package.
-#
-
-sub package_capture()
-{
-	my $dir;
-	my $build;
-	my $gkv;
-
-	($dir, $build, $gkv) = get_package($from_package);
-
-	# Check for build directory
-	if (defined($base_directory)) {
-		if (defined($build)) {
-			info("Using build directory specified by -b.\n");
-		}
-		$build = $base_directory;
-	}
-
-	# Do the actual capture
-	if (defined($gkv)) {
-		if ($gkv == $GKV_SYS) {
-			$build = adjust_kernel_dir($dir, $build);
-		}
-		if (@kernel_directory) {
-			$dir = copy_gcov_dir($dir, @kernel_directory);	
-		}
-		kernel_capture_from_dir($dir, $gkv, $build);
-	} else {
-		# Build directory needs to be passed to geninfo
-		$base_directory = $build;
-		lcov_geninfo($dir);
-	}
-}
-
-
-#
-# info(printf_parameter)
-#
-# Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag
-# is not set.
-#
-
-sub info(@)
-{
-	if (!$quiet)
-	{
-		# Print info string
-		if ($to_file)
-		{
-			printf(@_)
-		}
-		else
-		{
-			# Don't interfere with the .info output to STDOUT
-			printf(STDERR @_);
-		}
-	}
-}
-
-
-#
-# create_temp_dir()
-#
-# Create a temporary directory and return its path.
-#
-# Die on error.
-#
-
-sub create_temp_dir()
-{
-	my $dir;
-
-	if (defined($tmp_dir)) {
-		$dir = tempdir(DIR => $tmp_dir, CLEANUP => 1);
-	} else {
-		$dir = tempdir(CLEANUP => 1);
-	}
-	if (!defined($dir)) {
-		die("ERROR: cannot create temporary directory\n");
-	}
-	push(@temp_dirs, $dir);
-
-	return $dir;
-}
-
-
-#
-# br_taken_to_num(taken)
-#
-# Convert a branch taken value .info format to number format.
-#
-
-sub br_taken_to_num($)
-{
-	my ($taken) = @_;
-
-	return 0 if ($taken eq '-');
-	return $taken + 1;
-}
-
-
-#
-# br_num_to_taken(taken)
-#
-# Convert a branch taken value in number format to .info format.
-#
-
-sub br_num_to_taken($)
-{
-	my ($taken) = @_;
-
-	return '-' if ($taken == 0);
-	return $taken - 1;
-}
-
-
-#
-# br_taken_add(taken1, taken2)
-#
-# Return the result of taken1 + taken2 for 'branch taken' values.
-#
-
-sub br_taken_add($$)
-{
-	my ($t1, $t2) = @_;
-
-	return $t1 if (!defined($t2));
-	return $t2 if (!defined($t1));
-	return $t1 if ($t2 eq '-');
-	return $t2 if ($t1 eq '-');
-	return $t1 + $t2;
-}
-
-
-#
-# br_taken_sub(taken1, taken2)
-#
-# Return the result of taken1 - taken2 for 'branch taken' values. Return 0
-# if the result would become negative.
-#
-
-sub br_taken_sub($$)
-{
-	my ($t1, $t2) = @_;
-
-	return $t1 if (!defined($t2));
-	return undef if (!defined($t1));
-	return $t1 if ($t1 eq '-');
-	return $t1 if ($t2 eq '-');
-	return 0 if $t2 > $t1;
-	return $t1 - $t2;
-}
-
-
-#
-#
-# br_ivec_len(vector)
-#
-# Return the number of entries in the branch coverage vector.
-#
-
-sub br_ivec_len($)
-{
-	my ($vec) = @_;
-
-	return 0 if (!defined($vec));
-	return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
-}
-
-
-#
-# br_ivec_push(vector, block, branch, taken)
-#
-# Add an entry to the branch coverage vector. If an entry with the same
-# branch ID already exists, add the corresponding taken values.
-#
-
-sub br_ivec_push($$$$)
-{
-	my ($vec, $block, $branch, $taken) = @_;
-	my $offset;
-	my $num = br_ivec_len($vec);
-	my $i;
-
-	$vec = "" if (!defined($vec));
-
-	# Check if branch already exists in vector
-	for ($i = 0; $i < $num; $i++) {
-		my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
-
-		next if ($v_block != $block || $v_branch != $branch);
-
-		# Add taken counts
-		$taken = br_taken_add($taken, $v_taken);
-		last;
-	}
-
-	$offset = $i * $BR_VEC_ENTRIES;
-	$taken = br_taken_to_num($taken);
-
-	# Add to vector
-	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
-	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
-	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
-
-	return $vec;
-}
-
-
-#
-# br_ivec_get(vector, number)
-#
-# Return an entry from the branch coverage vector.
-#
-
-sub br_ivec_get($$)
-{
-	my ($vec, $num) = @_;
-	my $block;
-	my $branch;
-	my $taken;
-	my $offset = $num * $BR_VEC_ENTRIES;
-
-	# Retrieve data from vector
-	$block	= vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
-	$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
-	$taken	= vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
-
-	# Decode taken value from an integer
-	$taken = br_num_to_taken($taken);
-
-	return ($block, $branch, $taken);
-}
-
-
-#
-# get_br_found_and_hit(brcount)
-#
-# Return (br_found, br_hit) for brcount
-#
-
-sub get_br_found_and_hit($)
-{
-	my ($brcount) = @_;
-	my $line;
-	my $br_found = 0;
-	my $br_hit = 0;
-
-	foreach $line (keys(%{$brcount})) {
-		my $brdata = $brcount->{$line};
-		my $i;
-		my $num = br_ivec_len($brdata);
-
-		for ($i = 0; $i < $num; $i++) {
-			my $taken;
-
-			(undef, undef, $taken) = br_ivec_get($brdata, $i);
-
-			$br_found++;
-			$br_hit++ if ($taken ne "-" && $taken > 0);
-		}
-	}
-
-	return ($br_found, $br_hit);
-}
-
-
-#
-# read_info_file(info_filename)
-#
-# Read in the contents of the .info file specified by INFO_FILENAME. Data will
-# be returned as a reference to a hash containing the following mappings:
-#
-# %result: for each filename found in file -> \%data
-#
-# %data: "test"  -> \%testdata
-#        "sum"   -> \%sumcount
-#        "func"  -> \%funcdata
-#        "found" -> $lines_found (number of instrumented lines found in file)
-#	 "hit"   -> $lines_hit (number of executed lines in file)
-#        "check" -> \%checkdata
-#        "testfnc" -> \%testfncdata
-#        "sumfnc"  -> \%sumfnccount
-#        "testbr"  -> \%testbrdata
-#        "sumbr"   -> \%sumbrcount
-#
-# %testdata   : name of test affecting this file -> \%testcount
-# %testfncdata: name of test affecting this file -> \%testfnccount
-# %testbrdata:  name of test affecting this file -> \%testbrcount
-#
-# %testcount   : line number   -> execution count for a single test
-# %testfnccount: function name -> execution count for a single test
-# %testbrcount : line number   -> branch coverage data for a single test
-# %sumcount    : line number   -> execution count for all tests
-# %sumfnccount : function name -> execution count for all tests
-# %sumbrcount  : line number   -> branch coverage data for all tests
-# %funcdata    : function name -> line number
-# %checkdata   : line number   -> checksum of source code line
-# $brdata      : vector of items: block, branch, taken
-# 
-# Note that .info file sections referring to the same file and test name
-# will automatically be combined by adding all execution counts.
-#
-# Note that if INFO_FILENAME ends with ".gz", it is assumed that the file
-# is compressed using GZIP. If available, GUNZIP will be used to decompress
-# this file.
-#
-# Die on error.
-#
-
-sub read_info_file($)
-{
-	my $tracefile = $_[0];		# Name of tracefile
-	my %result;			# Resulting hash: file -> data
-	my $data;			# Data handle for current entry
-	my $testdata;			#       "             "
-	my $testcount;			#       "             "
-	my $sumcount;			#       "             "
-	my $funcdata;			#       "             "
-	my $checkdata;			#       "             "
-	my $testfncdata;
-	my $testfnccount;
-	my $sumfnccount;
-	my $testbrdata;
-	my $testbrcount;
-	my $sumbrcount;
-	my $line;			# Current line read from .info file
-	my $testname;			# Current test name
-	my $filename;			# Current filename
-	my $hitcount;			# Count for lines hit
-	my $count;			# Execution count of current line
-	my $negative;			# If set, warn about negative counts
-	my $changed_testname;		# If set, warn about changed testname
-	my $line_checksum;		# Checksum of current line
-	local *INFO_HANDLE;		# Filehandle for .info file
-
-	info("Reading tracefile $tracefile\n");
-
-	# Check if file exists and is readable
-	stat($_[0]);
-	if (!(-r _))
-	{
-		die("ERROR: cannot read file $_[0]!\n");
-	}
-
-	# Check if this is really a plain file
-	if (!(-f _))
-	{
-		die("ERROR: not a plain file: $_[0]!\n");
-	}
-
-	# Check for .gz extension
-	if ($_[0] =~ /\.gz$/)
-	{
-		# Check for availability of GZIP tool
-		system_no_output(1, "gunzip" ,"-h")
-			and die("ERROR: gunzip command not available!\n");
-
-		# Check integrity of compressed file
-		system_no_output(1, "gunzip", "-t", $_[0])
-			and die("ERROR: integrity check failed for ".
-				"compressed file $_[0]!\n");
-
-		# Open compressed file
-		open(INFO_HANDLE, "gunzip -c $_[0]|")
-			or die("ERROR: cannot start gunzip to decompress ".
-			       "file $_[0]!\n");
-	}
-	else
-	{
-		# Open decompressed file
-		open(INFO_HANDLE, $_[0])
-			or die("ERROR: cannot read file $_[0]!\n");
-	}
-
-	$testname = "";
-	while (<INFO_HANDLE>)
-	{
-		chomp($_);
-		$line = $_;
-
-		# Switch statement
-		foreach ($line)
-		{
-			/^TN:([^,]*)(,diff)?/ && do
-			{
-				# Test name information found
-				$testname = defined($1) ? $1 : "";
-				if ($testname =~ s/\W/_/g)
-				{
-					$changed_testname = 1;
-				}
-				$testname .= $2 if (defined($2));
-				last;
-			};
-
-			/^[SK]F:(.*)/ && do
-			{
-				# Filename information found
-				# Retrieve data for new entry
-				$filename = $1;
-
-				$data = $result{$filename};
-				($testdata, $sumcount, $funcdata, $checkdata,
-				 $testfncdata, $sumfnccount, $testbrdata,
-				 $sumbrcount) =
-					get_info_entry($data);
-
-				if (defined($testname))
-				{
-					$testcount = $testdata->{$testname};
-					$testfnccount = $testfncdata->{$testname};
-					$testbrcount = $testbrdata->{$testname};
-				}
-				else
-				{
-					$testcount = {};
-					$testfnccount = {};
-					$testbrcount = {};
-				}
-				last;
-			};
-
-			/^DA:(\d+),(-?\d+)(,[^,\s]+)?/ && do
-			{
-				# Fix negative counts
-				$count = $2 < 0 ? 0 : $2;
-				if ($2 < 0)
-				{
-					$negative = 1;
-				}
-				# Execution count found, add to structure
-				# Add summary counts
-				$sumcount->{$1} += $count;
-
-				# Add test-specific counts
-				if (defined($testname))
-				{
-					$testcount->{$1} += $count;
-				}
-
-				# Store line checksum if available
-				if (defined($3))
-				{
-					$line_checksum = substr($3, 1);
-
-					# Does it match a previous definition
-					if (defined($checkdata->{$1}) &&
-					    ($checkdata->{$1} ne
-					     $line_checksum))
-					{
-						die("ERROR: checksum mismatch ".
-						    "at $filename:$1\n");
-					}
-
-					$checkdata->{$1} = $line_checksum;
-				}
-				last;
-			};
-
-			/^FN:(\d+),([^,]+)/ && do
-			{
-				# Function data found, add to structure
-				$funcdata->{$2} = $1;
-
-				# Also initialize function call data
-				if (!defined($sumfnccount->{$2})) {
-					$sumfnccount->{$2} = 0;
-				}
-				if (defined($testname))
-				{
-					if (!defined($testfnccount->{$2})) {
-						$testfnccount->{$2} = 0;
-					}
-				}
-				last;
-			};
-
-			/^FNDA:(\d+),([^,]+)/ && do
-			{
-				# Function call count found, add to structure
-				# Add summary counts
-				$sumfnccount->{$2} += $1;
-
-				# Add test-specific counts
-				if (defined($testname))
-				{
-					$testfnccount->{$2} += $1;
-				}
-				last;
-			};
-
-			/^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
-				# Branch coverage data found
-				my ($line, $block, $branch, $taken) =
-				   ($1, $2, $3, $4);
-
-				$sumbrcount->{$line} =
-					br_ivec_push($sumbrcount->{$line},
-						     $block, $branch, $taken);
-
-				# Add test-specific counts
-				if (defined($testname)) {
-					$testbrcount->{$line} =
-						br_ivec_push(
-							$testbrcount->{$line},
-							$block, $branch,
-							$taken);
-				}
-				last;
-			};
-
-			/^end_of_record/ && do
-			{
-				# Found end of section marker
-				if ($filename)
-				{
-					# Store current section data
-					if (defined($testname))
-					{
-						$testdata->{$testname} =
-							$testcount;
-						$testfncdata->{$testname} =
-							$testfnccount;
-						$testbrdata->{$testname} =
-							$testbrcount;
-					}	
-
-					set_info_entry($data, $testdata,
-						       $sumcount, $funcdata,
-						       $checkdata, $testfncdata,
-						       $sumfnccount,
-						       $testbrdata,
-						       $sumbrcount);
-					$result{$filename} = $data;
-					last;
-				}
-			};
-
-			# default
-			last;
-		}
-	}
-	close(INFO_HANDLE);
-
-	# Calculate hit and found values for lines and functions of each file
-	foreach $filename (keys(%result))
-	{
-		$data = $result{$filename};
-
-		($testdata, $sumcount, undef, undef, $testfncdata,
-		 $sumfnccount, $testbrdata, $sumbrcount) =
-			get_info_entry($data);
-
-		# Filter out empty files
-		if (scalar(keys(%{$sumcount})) == 0)
-		{
-			delete($result{$filename});
-			next;
-		}
-		# Filter out empty test cases
-		foreach $testname (keys(%{$testdata}))
-		{
-			if (!defined($testdata->{$testname}) ||
-			    scalar(keys(%{$testdata->{$testname}})) == 0)
-			{
-				delete($testdata->{$testname});
-				delete($testfncdata->{$testname});
-			}
-		}
-
-		$data->{"found"} = scalar(keys(%{$sumcount}));
-		$hitcount = 0;
-
-		foreach (keys(%{$sumcount}))
-		{
-			if ($sumcount->{$_} > 0) { $hitcount++; }
-		}
-
-		$data->{"hit"} = $hitcount;
-
-		# Get found/hit values for function call data
-		$data->{"f_found"} = scalar(keys(%{$sumfnccount}));
-		$hitcount = 0;
-
-		foreach (keys(%{$sumfnccount})) {
-			if ($sumfnccount->{$_} > 0) {
-				$hitcount++;
-			}
-		}
-		$data->{"f_hit"} = $hitcount;
-
-		# Get found/hit values for branch data
-		{
-			my ($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
-
-			$data->{"b_found"} = $br_found;
-			$data->{"b_hit"} = $br_hit;
-		}
-	}
-
-	if (scalar(keys(%result)) == 0)
-	{
-		die("ERROR: no valid records found in tracefile $tracefile\n");
-	}
-	if ($negative)
-	{
-		warn("WARNING: negative counts found in tracefile ".
-		     "$tracefile\n");
-	}
-	if ($changed_testname)
-	{
-		warn("WARNING: invalid characters removed from testname in ".
-		     "tracefile $tracefile\n");
-	}
-
-	return(\%result);
-}
-
-
-#
-# get_info_entry(hash_ref)
-#
-# Retrieve data from an entry of the structure generated by read_info_file().
-# Return a list of references to hashes:
-# (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash
-#  ref, testfncdata hash ref, sumfnccount hash ref, testbrdata hash ref,
-#  sumbrcount hash ref, lines found, lines hit, functions found,
-#  functions hit, branches found, branches hit)
-#
-
-sub get_info_entry($)
-{
-	my $testdata_ref = $_[0]->{"test"};
-	my $sumcount_ref = $_[0]->{"sum"};
-	my $funcdata_ref = $_[0]->{"func"};
-	my $checkdata_ref = $_[0]->{"check"};
-	my $testfncdata = $_[0]->{"testfnc"};
-	my $sumfnccount = $_[0]->{"sumfnc"};
-	my $testbrdata = $_[0]->{"testbr"};
-	my $sumbrcount = $_[0]->{"sumbr"};
-	my $lines_found = $_[0]->{"found"};
-	my $lines_hit = $_[0]->{"hit"};
-	my $f_found = $_[0]->{"f_found"};
-	my $f_hit = $_[0]->{"f_hit"};
-	my $br_found = $_[0]->{"b_found"};
-	my $br_hit = $_[0]->{"b_hit"};
-
-	return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
-		$testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
-		$lines_found, $lines_hit, $f_found, $f_hit,
-		$br_found, $br_hit);
-}
-
-
-#
-# set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
-#                checkdata_ref, testfncdata_ref, sumfcncount_ref,
-#                testbrdata_ref, sumbrcount_ref[,lines_found,
-#                lines_hit, f_found, f_hit, $b_found, $b_hit])
-#
-# Update the hash referenced by HASH_REF with the provided data references.
-#
-
-sub set_info_entry($$$$$$$$$;$$$$$$)
-{
-	my $data_ref = $_[0];
-
-	$data_ref->{"test"} = $_[1];
-	$data_ref->{"sum"} = $_[2];
-	$data_ref->{"func"} = $_[3];
-	$data_ref->{"check"} = $_[4];
-	$data_ref->{"testfnc"} = $_[5];
-	$data_ref->{"sumfnc"} = $_[6];
-	$data_ref->{"testbr"} = $_[7];
-	$data_ref->{"sumbr"} = $_[8];
-
-	if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
-	if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
-	if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
-	if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
-	if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
-	if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
-}
-
-
-#
-# add_counts(data1_ref, data2_ref)
-#
-# DATA1_REF and DATA2_REF are references to hashes containing a mapping
-#
-#   line number -> execution count
-#
-# Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF
-# is a reference to a hash containing the combined mapping in which
-# execution counts are added.
-#
-
-sub add_counts($$)
-{
-	my %data1 = %{$_[0]};	# Hash 1
-	my %data2 = %{$_[1]};	# Hash 2
-	my %result;		# Resulting hash
-	my $line;		# Current line iteration scalar
-	my $data1_count;	# Count of line in hash1
-	my $data2_count;	# Count of line in hash2
-	my $found = 0;		# Total number of lines found
-	my $hit = 0;		# Number of lines with a count > 0
-
-	foreach $line (keys(%data1))
-	{
-		$data1_count = $data1{$line};
-		$data2_count = $data2{$line};
-
-		# Add counts if present in both hashes
-		if (defined($data2_count)) { $data1_count += $data2_count; }
-
-		# Store sum in %result
-		$result{$line} = $data1_count;
-
-		$found++;
-		if ($data1_count > 0) { $hit++; }
-	}
-
-	# Add lines unique to data2
-	foreach $line (keys(%data2))
-	{
-		# Skip lines already in data1
-		if (defined($data1{$line})) { next; }
-
-		# Copy count from data2
-		$result{$line} = $data2{$line};
-
-		$found++;
-		if ($result{$line} > 0) { $hit++; }
-	}
-
-	return (\%result, $found, $hit);
-}
-
-
-#
-# merge_checksums(ref1, ref2, filename)
-#
-# REF1 and REF2 are references to hashes containing a mapping
-#
-#   line number -> checksum
-#
-# Merge checksum lists defined in REF1 and REF2 and return reference to
-# resulting hash. Die if a checksum for a line is defined in both hashes
-# but does not match.
-#
-
-sub merge_checksums($$$)
-{
-	my $ref1 = $_[0];
-	my $ref2 = $_[1];
-	my $filename = $_[2];
-	my %result;
-	my $line;
-
-	foreach $line (keys(%{$ref1}))
-	{
-		if (defined($ref2->{$line}) &&
-		    ($ref1->{$line} ne $ref2->{$line}))
-		{
-			die("ERROR: checksum mismatch at $filename:$line\n");
-		}
-		$result{$line} = $ref1->{$line};
-	}
-
-	foreach $line (keys(%{$ref2}))
-	{
-		$result{$line} = $ref2->{$line};
-	}
-
-	return \%result;
-}
-
-
-#
-# merge_func_data(funcdata1, funcdata2, filename)
-#
-
-sub merge_func_data($$$)
-{
-	my ($funcdata1, $funcdata2, $filename) = @_;
-	my %result;
-	my $func;
-
-	if (defined($funcdata1)) {
-		%result = %{$funcdata1};
-	}
-
-	foreach $func (keys(%{$funcdata2})) {
-		my $line1 = $result{$func};
-		my $line2 = $funcdata2->{$func};
-
-		if (defined($line1) && ($line1 != $line2)) {
-			warn("WARNING: function data mismatch at ".
-			     "$filename:$line2\n");
-			next;
-		}
-		$result{$func} = $line2;
-	}
-
-	return \%result;
-}
-
-
-#
-# add_fnccount(fnccount1, fnccount2)
-#
-# Add function call count data. Return list (fnccount_added, f_found, f_hit)
-#
-
-sub add_fnccount($$)
-{
-	my ($fnccount1, $fnccount2) = @_;
-	my %result;
-	my $f_found;
-	my $f_hit;
-	my $function;
-
-	if (defined($fnccount1)) {
-		%result = %{$fnccount1};
-	}
-	foreach $function (keys(%{$fnccount2})) {
-		$result{$function} += $fnccount2->{$function};
-	}
-	$f_found = scalar(keys(%result));
-	$f_hit = 0;
-	foreach $function (keys(%result)) {
-		if ($result{$function} > 0) {
-			$f_hit++;
-		}
-	}
-
-	return (\%result, $f_found, $f_hit);
-}
-
-#
-# add_testfncdata(testfncdata1, testfncdata2)
-#
-# Add function call count data for several tests. Return reference to
-# added_testfncdata.
-#
-
-sub add_testfncdata($$)
-{
-	my ($testfncdata1, $testfncdata2) = @_;
-	my %result;
-	my $testname;
-
-	foreach $testname (keys(%{$testfncdata1})) {
-		if (defined($testfncdata2->{$testname})) {
-			my $fnccount;
-
-			# Function call count data for this testname exists
-			# in both data sets: merge
-			($fnccount) = add_fnccount(
-				$testfncdata1->{$testname},
-				$testfncdata2->{$testname});
-			$result{$testname} = $fnccount;
-			next;
-		}
-		# Function call count data for this testname is unique to
-		# data set 1: copy
-		$result{$testname} = $testfncdata1->{$testname};
-	}
-
-	# Add count data for testnames unique to data set 2
-	foreach $testname (keys(%{$testfncdata2})) {
-		if (!defined($result{$testname})) {
-			$result{$testname} = $testfncdata2->{$testname};
-		}
-	}
-	return \%result;
-}
-
-
-#
-# brcount_to_db(brcount)
-#
-# Convert brcount data to the following format:
-#
-# db:          line number    -> block hash
-# block hash:  block number   -> branch hash
-# branch hash: branch number  -> taken value
-#
-
-sub brcount_to_db($)
-{
-	my ($brcount) = @_;
-	my $line;
-	my $db;
-
-	# Add branches from first count to database
-	foreach $line (keys(%{$brcount})) {
-		my $brdata = $brcount->{$line};
-		my $i;
-		my $num = br_ivec_len($brdata);
-
-		for ($i = 0; $i < $num; $i++) {
-			my ($block, $branch, $taken) = br_ivec_get($brdata, $i);
-
-			$db->{$line}->{$block}->{$branch} = $taken;
-		}
-	}
-
-	return $db;
-}
-
-
-#
-# db_to_brcount(db)
-#
-# Convert branch coverage data back to brcount format.
-#
-
-sub db_to_brcount($)
-{
-	my ($db) = @_;
-	my $line;
-	my $brcount = {};
-	my $br_found = 0;
-	my $br_hit = 0;
-
-	# Convert database back to brcount format
-	foreach $line (sort({$a <=> $b} keys(%{$db}))) {
-		my $ldata = $db->{$line};
-		my $brdata;
-		my $block;
-
-		foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
-			my $bdata = $ldata->{$block};
-			my $branch;
-
-			foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
-				my $taken = $bdata->{$branch};
-
-				$br_found++;
-				$br_hit++ if ($taken ne "-" && $taken > 0);
-				$brdata = br_ivec_push($brdata, $block,
-						       $branch, $taken);
-			}
-		}
-		$brcount->{$line} = $brdata;
-	}
-
-	return ($brcount, $br_found, $br_hit);
-}
-
-
-# combine_brcount(brcount1, brcount2, type)
-#
-# If add is BR_ADD, add branch coverage data and return list (brcount_added,
-# br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2
-# from brcount1 and return (brcount_sub, br_found, br_hit).
-#
-
-sub combine_brcount($$$)
-{
-	my ($brcount1, $brcount2, $type) = @_;
-	my $line;
-	my $block;
-	my $branch;
-	my $taken;
-	my $db;
-	my $br_found = 0;
-	my $br_hit = 0;
-	my $result;
-
-	# Convert branches from first count to database
-	$db = brcount_to_db($brcount1);
-	# Combine values from database and second count
-	foreach $line (keys(%{$brcount2})) {
-		my $brdata = $brcount2->{$line};
-		my $num = br_ivec_len($brdata);
-		my $i;
-
-		for ($i = 0; $i < $num; $i++) {
-			($block, $branch, $taken) = br_ivec_get($brdata, $i);
-			my $new_taken = $db->{$line}->{$block}->{$branch};
-
-			if ($type == $BR_ADD) {
-				$new_taken = br_taken_add($new_taken, $taken);
-			} elsif ($type == $BR_SUB) {
-				$new_taken = br_taken_sub($new_taken, $taken);
-			}
-			$db->{$line}->{$block}->{$branch} = $new_taken
-				if (defined($new_taken));
-		}
-	}
-	# Convert database back to brcount format
-	($result, $br_found, $br_hit) = db_to_brcount($db);
-
-	return ($result, $br_found, $br_hit);
-}
-
-
-#
-# add_testbrdata(testbrdata1, testbrdata2)
-#
-# Add branch coverage data for several tests. Return reference to
-# added_testbrdata.
-#
-
-sub add_testbrdata($$)
-{
-	my ($testbrdata1, $testbrdata2) = @_;
-	my %result;
-	my $testname;
-
-	foreach $testname (keys(%{$testbrdata1})) {
-		if (defined($testbrdata2->{$testname})) {
-			my $brcount;
-
-			# Branch coverage data for this testname exists
-			# in both data sets: add
-			($brcount) = combine_brcount(
-				$testbrdata1->{$testname},
-				$testbrdata2->{$testname}, $BR_ADD);
-			$result{$testname} = $brcount;
-			next;
-		}
-		# Branch coverage data for this testname is unique to
-		# data set 1: copy
-		$result{$testname} = $testbrdata1->{$testname};
-	}
-
-	# Add count data for testnames unique to data set 2
-	foreach $testname (keys(%{$testbrdata2})) {
-		if (!defined($result{$testname})) {
-			$result{$testname} = $testbrdata2->{$testname};
-		}
-	}
-	return \%result;
-}
-
-
-#
-# combine_info_entries(entry_ref1, entry_ref2, filename)
-#
-# Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2.
-# Return reference to resulting hash.
-#
-
-sub combine_info_entries($$$)
-{
-	my $entry1 = $_[0];	# Reference to hash containing first entry
-	my $testdata1;
-	my $sumcount1;
-	my $funcdata1;
-	my $checkdata1;
-	my $testfncdata1;
-	my $sumfnccount1;
-	my $testbrdata1;
-	my $sumbrcount1;
-
-	my $entry2 = $_[1];	# Reference to hash containing second entry
-	my $testdata2;
-	my $sumcount2;
-	my $funcdata2;
-	my $checkdata2;
-	my $testfncdata2;
-	my $sumfnccount2;
-	my $testbrdata2;
-	my $sumbrcount2;
-
-	my %result;		# Hash containing combined entry
-	my %result_testdata;
-	my $result_sumcount = {};
-	my $result_funcdata;
-	my $result_testfncdata;
-	my $result_sumfnccount;
-	my $result_testbrdata;
-	my $result_sumbrcount;
-	my $lines_found;
-	my $lines_hit;
-	my $f_found;
-	my $f_hit;
-	my $br_found;
-	my $br_hit;
-
-	my $testname;
-	my $filename = $_[2];
-
-	# Retrieve data
-	($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
-	 $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
-	($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
-	 $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
-
-	# Merge checksums
-	$checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
-
-	# Combine funcdata
-	$result_funcdata = merge_func_data($funcdata1, $funcdata2, $filename);
-
-	# Combine function call count data
-	$result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2);
-	($result_sumfnccount, $f_found, $f_hit) =
-		add_fnccount($sumfnccount1, $sumfnccount2);
-
-	# Combine branch coverage data
-	$result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
-	($result_sumbrcount, $br_found, $br_hit) =
-		combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
-
-	# Combine testdata
-	foreach $testname (keys(%{$testdata1}))
-	{
-		if (defined($testdata2->{$testname}))
-		{
-			# testname is present in both entries, requires
-			# combination
-			($result_testdata{$testname}) =
-				add_counts($testdata1->{$testname},
-					   $testdata2->{$testname});
-		}
-		else
-		{
-			# testname only present in entry1, add to result
-			$result_testdata{$testname} = $testdata1->{$testname};
-		}
-
-		# update sum count hash
-		($result_sumcount, $lines_found, $lines_hit) =
-			add_counts($result_sumcount,
-				   $result_testdata{$testname});
-	}
-
-	foreach $testname (keys(%{$testdata2}))
-	{
-		# Skip testnames already covered by previous iteration
-		if (defined($testdata1->{$testname})) { next; }
-
-		# testname only present in entry2, add to result hash
-		$result_testdata{$testname} = $testdata2->{$testname};
-
-		# update sum count hash
-		($result_sumcount, $lines_found, $lines_hit) =
-			add_counts($result_sumcount,
-				   $result_testdata{$testname});
-	}
-	
-	# Calculate resulting sumcount
-
-	# Store result
-	set_info_entry(\%result, \%result_testdata, $result_sumcount,
-		       $result_funcdata, $checkdata1, $result_testfncdata,
-		       $result_sumfnccount, $result_testbrdata,
-		       $result_sumbrcount, $lines_found, $lines_hit,
-		       $f_found, $f_hit, $br_found, $br_hit);
-
-	return(\%result);
-}
-
-
-#
-# combine_info_files(info_ref1, info_ref2)
-#
-# Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return
-# reference to resulting hash.
-#
-
-sub combine_info_files($$)
-{
-	my %hash1 = %{$_[0]};
-	my %hash2 = %{$_[1]};
-	my $filename;
-
-	foreach $filename (keys(%hash2))
-	{
-		if ($hash1{$filename})
-		{
-			# Entry already exists in hash1, combine them
-			$hash1{$filename} =
-				combine_info_entries($hash1{$filename},
-						     $hash2{$filename},
-						     $filename);
-		}
-		else
-		{
-			# Entry is unique in both hashes, simply add to
-			# resulting hash
-			$hash1{$filename} = $hash2{$filename};
-		}
-	}
-
-	return(\%hash1);
-}
-
-
-#
-# add_traces()
-#
-
-sub add_traces()
-{
-	my $total_trace;
-	my $current_trace;
-	my $tracefile;
-	my @result;
-	local *INFO_HANDLE;
-
-	info("Combining tracefiles.\n");
-
-	foreach $tracefile (@add_tracefile)
-	{
-		$current_trace = read_info_file($tracefile);
-		if ($total_trace)
-		{
-			$total_trace = combine_info_files($total_trace,
-							  $current_trace);
-		}
-		else
-		{
-			$total_trace = $current_trace;
-		}
-	}
-
-	# Write combined data
-	if ($to_file)
-	{
-		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
-			or die("ERROR: cannot write to $output_filename!\n");
-		@result = write_info_file(*INFO_HANDLE, $total_trace);
-		close(*INFO_HANDLE);
-	}
-	else
-	{
-		@result = write_info_file(*STDOUT, $total_trace);
-	}
-
-	return @result;
-}
-
-
-#
-# write_info_file(filehandle, data)
-#
-
-sub write_info_file(*$)
-{
-	local *INFO_HANDLE = $_[0];
-	my %data = %{$_[1]};
-	my $source_file;
-	my $entry;
-	my $testdata;
-	my $sumcount;
-	my $funcdata;
-	my $checkdata;
-	my $testfncdata;
-	my $sumfnccount;
-	my $testbrdata;
-	my $sumbrcount;
-	my $testname;
-	my $line;
-	my $func;
-	my $testcount;
-	my $testfnccount;
-	my $testbrcount;
-	my $found;
-	my $hit;
-	my $f_found;
-	my $f_hit;
-	my $br_found;
-	my $br_hit;
-	my $ln_total_found = 0;
-	my $ln_total_hit = 0;
-	my $fn_total_found = 0;
-	my $fn_total_hit = 0;
-	my $br_total_found = 0;
-	my $br_total_hit = 0;
-
-	foreach $source_file (sort(keys(%data)))
-	{
-		$entry = $data{$source_file};
-		($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
-		 $sumfnccount, $testbrdata, $sumbrcount, $found, $hit,
-		 $f_found, $f_hit, $br_found, $br_hit) =
-			get_info_entry($entry);
-
-		# Add to totals
-		$ln_total_found += $found;
-		$ln_total_hit += $hit;
-		$fn_total_found += $f_found;
-		$fn_total_hit += $f_hit;
-		$br_total_found += $br_found;
-		$br_total_hit += $br_hit;
-
-		foreach $testname (sort(keys(%{$testdata})))
-		{
-			$testcount = $testdata->{$testname};
-			$testfnccount = $testfncdata->{$testname};
-			$testbrcount = $testbrdata->{$testname};
-			$found = 0;
-			$hit   = 0;
-
-			print(INFO_HANDLE "TN:$testname\n");
-			print(INFO_HANDLE "SF:$source_file\n");
-
-			# Write function related data
-			foreach $func (
-				sort({$funcdata->{$a} <=> $funcdata->{$b}}
-				keys(%{$funcdata})))
-			{
-				print(INFO_HANDLE "FN:".$funcdata->{$func}.
-				      ",$func\n");
-			}
-			foreach $func (keys(%{$testfnccount})) {
-				print(INFO_HANDLE "FNDA:".
-				      $testfnccount->{$func}.
-				      ",$func\n");
-			}
-			($f_found, $f_hit) =
-				get_func_found_and_hit($testfnccount);
-			print(INFO_HANDLE "FNF:$f_found\n");
-			print(INFO_HANDLE "FNH:$f_hit\n");
-
-			# Write branch related data
-			$br_found = 0;
-			$br_hit = 0;
-			foreach $line (sort({$a <=> $b}
-					    keys(%{$testbrcount}))) {
-				my $brdata = $testbrcount->{$line};
-				my $num = br_ivec_len($brdata);
-				my $i;
-
-				for ($i = 0; $i < $num; $i++) {
-					my ($block, $branch, $taken) =
-						br_ivec_get($brdata, $i);
-
-					print(INFO_HANDLE "BRDA:$line,$block,".
-					      "$branch,$taken\n");
-					$br_found++;
-					$br_hit++ if ($taken ne '-' &&
-						      $taken > 0);
-				}
-			}
-			if ($br_found > 0) {
-				print(INFO_HANDLE "BRF:$br_found\n");
-				print(INFO_HANDLE "BRH:$br_hit\n");
-			}
-
-			# Write line related data
-			foreach $line (sort({$a <=> $b} keys(%{$testcount})))
-			{
-				print(INFO_HANDLE "DA:$line,".
-				      $testcount->{$line}.
-				      (defined($checkdata->{$line}) &&
-				       $checksum ?
-				       ",".$checkdata->{$line} : "")."\n");
-				$found++;
-				if ($testcount->{$line} > 0)
-				{
-					$hit++;
-				}
-
-			}
-			print(INFO_HANDLE "LF:$found\n");
-			print(INFO_HANDLE "LH:$hit\n");
-			print(INFO_HANDLE "end_of_record\n");
-		}
-	}
-
-	return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit,
-		$br_total_found, $br_total_hit);
-}
-
-
-#
-# transform_pattern(pattern)
-#
-# Transform shell wildcard expression to equivalent PERL regular expression.
-# Return transformed pattern.
-#
-
-sub transform_pattern($)
-{
-	my $pattern = $_[0];
-
-	# Escape special chars
-
-	$pattern =~ s/\\/\\\\/g;
-	$pattern =~ s/\//\\\//g;
-	$pattern =~ s/\^/\\\^/g;
-	$pattern =~ s/\$/\\\$/g;
-	$pattern =~ s/\(/\\\(/g;
-	$pattern =~ s/\)/\\\)/g;
-	$pattern =~ s/\[/\\\[/g;
-	$pattern =~ s/\]/\\\]/g;
-	$pattern =~ s/\{/\\\{/g;
-	$pattern =~ s/\}/\\\}/g;
-	$pattern =~ s/\./\\\./g;
-	$pattern =~ s/\,/\\\,/g;
-	$pattern =~ s/\|/\\\|/g;
-	$pattern =~ s/\+/\\\+/g;
-	$pattern =~ s/\!/\\\!/g;
-
-	# Transform ? => (.) and * => (.*)
-
-	$pattern =~ s/\*/\(\.\*\)/g;
-	$pattern =~ s/\?/\(\.\)/g;
-
-	return $pattern;
-}
-
-
-#
-# extract()
-#
-
-sub extract()
-{
-	my $data = read_info_file($extract);
-	my $filename;
-	my $keep;
-	my $pattern;
-	my @pattern_list;
-	my $extracted = 0;
-	my @result;
-	local *INFO_HANDLE;
-
-	# Need perlreg expressions instead of shell pattern
-	@pattern_list = map({ transform_pattern($_); } @ARGV);
-
-	# Filter out files which do not match any pattern
-	foreach $filename (sort(keys(%{$data})))
-	{
-		$keep = 0;
-
-		foreach $pattern (@pattern_list)
-		{
-			$keep ||= ($filename =~ (/^$pattern$/));
-		}
-
-
-		if (!$keep)
-		{
-			delete($data->{$filename});
-		}
-		else
-		{
-			info("Extracting $filename\n"),
-			$extracted++;
-		}
-	}
-
-	# Write extracted data
-	if ($to_file)
-	{
-		info("Extracted $extracted files\n");
-		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
-			or die("ERROR: cannot write to $output_filename!\n");
-		@result = write_info_file(*INFO_HANDLE, $data);
-		close(*INFO_HANDLE);
-	}
-	else
-	{
-		@result = write_info_file(*STDOUT, $data);
-	}
-
-	return @result;
-}
-
-
-#
-# remove()
-#
-
-sub remove()
-{
-	my $data = read_info_file($remove);
-	my $filename;
-	my $match_found;
-	my $pattern;
-	my @pattern_list;
-	my $removed = 0;
-	my @result;
-	local *INFO_HANDLE;
-
-	# Need perlreg expressions instead of shell pattern
-	@pattern_list = map({ transform_pattern($_); } @ARGV);
-
-	# Filter out files that match the pattern
-	foreach $filename (sort(keys(%{$data})))
-	{
-		$match_found = 0;
-
-		foreach $pattern (@pattern_list)
-		{
-			$match_found ||= ($filename =~ (/$pattern$/));
-		}
-
-
-		if ($match_found)
-		{
-			delete($data->{$filename});
-			info("Removing $filename\n"),
-			$removed++;
-		}
-	}
-
-	# Write data
-	if ($to_file)
-	{
-		info("Deleted $removed files\n");
-		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
-			or die("ERROR: cannot write to $output_filename!\n");
-		@result = write_info_file(*INFO_HANDLE, $data);
-		close(*INFO_HANDLE);
-	}
-	else
-	{
-		@result = write_info_file(*STDOUT, $data);
-	}
-
-	return @result;
-}
-
-
-# get_prefix(max_width, max_percentage_too_long, path_list)
-#
-# Return a path prefix that satisfies the following requirements:
-# - is shared by more paths in path_list than any other prefix
-# - the percentage of paths which would exceed the given max_width length
-#   after applying the prefix does not exceed max_percentage_too_long
-#
-# If multiple prefixes satisfy all requirements, the longest prefix is
-# returned. Return an empty string if no prefix could be found.
-
-sub get_prefix($$@)
-{
-	my ($max_width, $max_long, @path_list) = @_;
-	my $path;
-	my $ENTRY_NUM = 0;
-	my $ENTRY_LONG = 1;
-	my %prefix;
-
-	# Build prefix hash
-	foreach $path (@path_list) {
-		my ($v, $d, $f) = splitpath($path);
-		my @dirs = splitdir($d);
-		my $p_len = length($path);
-		my $i;
-
-		# Remove trailing '/'
-		pop(@dirs) if ($dirs[scalar(@dirs) - 1] eq '');
-		for ($i = 0; $i < scalar(@dirs); $i++) {
-			my $subpath = catpath($v, catdir(@dirs[0..$i]), '');
-			my $entry = $prefix{$subpath};
-
-			$entry = [ 0, 0 ] if (!defined($entry));
-			$entry->[$ENTRY_NUM]++;
-			if (($p_len - length($subpath) - 1) > $max_width) {
-				$entry->[$ENTRY_LONG]++;
-			}
-			$prefix{$subpath} = $entry;
-		}
-	}
-	# Find suitable prefix (sort descending by two keys: 1. number of
-	# entries covered by a prefix, 2. length of prefix)
-	foreach $path (sort {($prefix{$a}->[$ENTRY_NUM] ==
-			      $prefix{$b}->[$ENTRY_NUM]) ?
-				length($b) <=> length($a) :
-				$prefix{$b}->[$ENTRY_NUM] <=>
-				$prefix{$a}->[$ENTRY_NUM]}
-				keys(%prefix)) {
-		my ($num, $long) = @{$prefix{$path}};
-
-		# Check for additional requirement: number of filenames
-		# that would be too long may not exceed a certain percentage
-		if ($long <= $num * $max_long / 100) {
-			return $path;
-		}
-	}
-
-	return "";
-}
-
-
-#
-# shorten_filename(filename, width)
-#
-# Truncate filename if it is longer than width characters.
-#
-
-sub shorten_filename($$)
-{
-	my ($filename, $width) = @_;
-	my $l = length($filename);
-	my $s;
-	my $e;
-
-	return $filename if ($l <= $width);
-	$e = int(($width - 3) / 2);
-	$s = $width - 3 - $e;
-
-	return substr($filename, 0, $s).'...'.substr($filename, $l - $e);
-}
-
-
-sub shorten_number($$)
-{
-	my ($number, $width) = @_;
-	my $result = sprintf("%*d", $width, $number);
-
-	return $result if (length($result) <= $width);
-	$number = $number / 1000;
-	return $result if (length($result) <= $width);
-	$result = sprintf("%*dk", $width - 1, $number);
-	return $result if (length($result) <= $width);
-	$number = $number / 1000;
-	$result = sprintf("%*dM", $width - 1, $number);
-	return $result if (length($result) <= $width);
-	return '#';
-}
-
-sub shorten_rate($$)
-{
-	my ($rate, $width) = @_;
-	my $result = sprintf("%*.1f%%", $width - 3, $rate);
-
-	return $result if (length($result) <= $width);
-	$result = sprintf("%*d%%", $width - 1, $rate);
-	return $result if (length($result) <= $width);
-	return "#";
-}
-
-#
-# list()
-#
-
-sub list()
-{
-	my $data = read_info_file($list);
-	my $filename;
-	my $found;
-	my $hit;
-	my $entry;
-	my $fn_found;
-	my $fn_hit;
-	my $br_found;
-	my $br_hit;
-	my $total_found = 0;
-	my $total_hit = 0;
-	my $fn_total_found = 0;
-	my $fn_total_hit = 0;
-	my $br_total_found = 0;
-	my $br_total_hit = 0;
-	my $prefix;
-	my $strlen = length("Filename");
-	my $format;
-	my $heading1;
-	my $heading2;
-	my @footer;
-	my $barlen;
-	my $rate;
-	my $fnrate;
-	my $brrate;
-	my $lastpath;
-	my $F_LN_NUM = 0;
-	my $F_LN_RATE = 1;
-	my $F_FN_NUM = 2;
-	my $F_FN_RATE = 3;
-	my $F_BR_NUM = 4;
-	my $F_BR_RATE = 5;
-	my @fwidth_narrow = (5, 5, 3, 5, 4, 5);
-	my @fwidth_wide = (6, 5, 5, 5, 6, 5);
-	my @fwidth = @fwidth_wide;
-	my $w;
-	my $max_width = $opt_list_width;
-	my $max_long = $opt_list_truncate_max;
-	my $fwidth_narrow_length;
-	my $fwidth_wide_length;
-	my $got_prefix = 0;
-	my $root_prefix = 0;
-
-	# Calculate total width of narrow fields
-	$fwidth_narrow_length = 0;
-	foreach $w (@fwidth_narrow) {
-		$fwidth_narrow_length += $w + 1;
-	}
-	# Calculate total width of wide fields
-	$fwidth_wide_length = 0;
-	foreach $w (@fwidth_wide) {
-		$fwidth_wide_length += $w + 1;
-	}
-	# Get common file path prefix
-	$prefix = get_prefix($max_width - $fwidth_narrow_length, $max_long,
-			     keys(%{$data}));
-	$root_prefix = 1 if ($prefix eq rootdir());
-	$got_prefix = 1 if (length($prefix) > 0);
-	$prefix =~ s/\/$//;
-	# Get longest filename length
-	foreach $filename (keys(%{$data})) {
-		if (!$opt_list_full_path) {
-			if (!$got_prefix || !$root_prefix &&
-			    !($filename =~ s/^\Q$prefix\/\E//)) {
-				my ($v, $d, $f) = splitpath($filename);
-
-				$filename = $f;
-			}
-		}
-		# Determine maximum length of entries
-		if (length($filename) > $strlen) {
-			$strlen = length($filename)
-		}
-	}
-	if (!$opt_list_full_path) {
-		my $blanks;
-
-		$w = $fwidth_wide_length;
-		# Check if all columns fit into max_width characters
-		if ($strlen + $fwidth_wide_length > $max_width) {
-			# Use narrow fields
-			@fwidth = @fwidth_narrow;
-			$w = $fwidth_narrow_length;
-			if (($strlen + $fwidth_narrow_length) > $max_width) {
-				# Truncate filenames at max width
-				$strlen = $max_width - $fwidth_narrow_length;
-			}
-		}
-		# Add some blanks between filename and fields if possible
-		$blanks = int($strlen * 0.5);
-		$blanks = 4 if ($blanks < 4);
-		$blanks = 8 if ($blanks > 8);
-		if (($strlen + $w + $blanks) < $max_width) {
-			$strlen += $blanks;
-		} else {
-			$strlen = $max_width - $w;
-		}
-	}
-	# Filename
-	$w = $strlen;
-	$format		= "%-${w}s|";
-	$heading1 	= sprintf("%*s|", $w, "");
-	$heading2 	= sprintf("%-*s|", $w, "Filename");
-	$barlen		= $w + 1;
-	# Line coverage rate
-	$w = $fwidth[$F_LN_RATE];
-	$format		.= "%${w}s ";
-	$heading1 	.= sprintf("%-*s |", $w + $fwidth[$F_LN_NUM],
-				   "Lines");
-	$heading2 	.= sprintf("%-*s ", $w, "Rate");
-	$barlen		+= $w + 1;
-	# Number of lines
-	$w = $fwidth[$F_LN_NUM];
-	$format		.= "%${w}s|";
-	$heading2	.= sprintf("%*s|", $w, "Num");
-	$barlen		+= $w + 1;
-	# Function coverage rate
-	$w = $fwidth[$F_FN_RATE];
-	$format		.= "%${w}s ";
-	$heading1 	.= sprintf("%-*s|", $w + $fwidth[$F_FN_NUM] + 1,
-				   "Functions");
-	$heading2 	.= sprintf("%-*s ", $w, "Rate");
-	$barlen		+= $w + 1;
-	# Number of functions
-	$w = $fwidth[$F_FN_NUM];
-	$format		.= "%${w}s|";
-	$heading2	.= sprintf("%*s|", $w, "Num");
-	$barlen		+= $w + 1;
-	# Branch coverage rate
-	$w = $fwidth[$F_BR_RATE];
-	$format		.= "%${w}s ";
-	$heading1 	.= sprintf("%-*s", $w + $fwidth[$F_BR_NUM] + 1,
-				   "Branches");
-	$heading2 	.= sprintf("%-*s ", $w, "Rate");
-	$barlen		+= $w + 1;
-	# Number of branches
-	$w = $fwidth[$F_BR_NUM];
-	$format		.= "%${w}s";
-	$heading2	.= sprintf("%*s", $w, "Num");
-	$barlen		+= $w;
-	# Line end
-	$format		.= "\n";
-	$heading1	.= "\n";
-	$heading2	.= "\n";
-
-	# Print heading
-	print($heading1);
-	print($heading2);
-	print(("="x$barlen)."\n");
-
-	# Print per file information
-	foreach $filename (sort(keys(%{$data})))
-	{
-		my @file_data;
-		my $print_filename = $filename;
-
-		$entry = $data->{$filename};
-		if (!$opt_list_full_path) {
-			my $p;
-
-			$print_filename = $filename;
-			if (!$got_prefix || !$root_prefix &&
-			    !($print_filename =~ s/^\Q$prefix\/\E//)) {
-				my ($v, $d, $f) = splitpath($filename);
-
-				$p = catpath($v, $d, "");
-				$p =~ s/\/$//;
-				$print_filename = $f;
-			} else {
-				$p = $prefix;
-			}
-
-			if (!defined($lastpath) || $lastpath ne $p) {
-				print("\n") if (defined($lastpath));
-				$lastpath = $p;
-				print("[$lastpath/]\n") if (!$root_prefix);
-			}
-			$print_filename = shorten_filename($print_filename,
-							   $strlen);
-		}
-
-		(undef, undef, undef, undef, undef, undef, undef, undef,
-		 $found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
-			get_info_entry($entry);
-
-		# Assume zero count if there is no function data for this file
-		if (!defined($fn_found) || !defined($fn_hit)) {
-			$fn_found = 0;
-			$fn_hit = 0;
-		}
-		# Assume zero count if there is no branch data for this file
-		if (!defined($br_found) || !defined($br_hit)) {
-			$br_found = 0;
-			$br_hit = 0;
-		}
-
-		# Add line coverage totals
-		$total_found += $found;
-		$total_hit += $hit;
-		# Add function coverage totals
-		$fn_total_found += $fn_found;
-		$fn_total_hit += $fn_hit;
-		# Add branch coverage totals
-		$br_total_found += $br_found;
-		$br_total_hit += $br_hit;
-
-		# Determine line coverage rate for this file
-		if ($found == 0) {
-			$rate = "-";
-		} else {
-			$rate = shorten_rate(100 * $hit / $found,
-					     $fwidth[$F_LN_RATE]);
-		}
-		# Determine function coverage rate for this file
-		if (!defined($fn_found) || $fn_found == 0) {
-			$fnrate = "-";
-		} else {
-			$fnrate = shorten_rate(100 * $fn_hit / $fn_found,
-					     $fwidth[$F_FN_RATE]);
-		}
-		# Determine branch coverage rate for this file
-		if (!defined($br_found) || $br_found == 0) {
-			$brrate = "-";
-		} else {
-			$brrate = shorten_rate(100 * $br_hit / $br_found,
-					     $fwidth[$F_BR_RATE]);
-		}
-
-		# Assemble line parameters
-		push(@file_data, $print_filename);
-		push(@file_data, $rate);
-		push(@file_data, shorten_number($found, $fwidth[$F_LN_NUM]));
-		push(@file_data, $fnrate);
-		push(@file_data, shorten_number($fn_found, $fwidth[$F_FN_NUM]));
-		push(@file_data, $brrate);
-		push(@file_data, shorten_number($br_found, $fwidth[$F_BR_NUM]));
-
-		# Print assembled line
-		printf($format, @file_data);
-	}
-
-	# Determine total line coverage rate
-	if ($total_found == 0) {
-		$rate = "-";
-	} else {
-		$rate = shorten_rate(100 * $total_hit / $total_found,
-				     $fwidth[$F_LN_RATE]);
-	}
-	# Determine total function coverage rate
-	if ($fn_total_found == 0) {
-		$fnrate = "-";
-	} else {
-		$fnrate = shorten_rate(100 * $fn_total_hit / $fn_total_found,
-				       $fwidth[$F_FN_RATE]);
-	}
-	# Determine total branch coverage rate
-	if ($br_total_found == 0) {
-		$brrate = "-";
-	} else {
-		$brrate = shorten_rate(100 * $br_total_hit / $br_total_found,
-				       $fwidth[$F_BR_RATE]);
-	}
-
-	# Print separator
-	print(("="x$barlen)."\n");
-
-	# Assemble line parameters
-	push(@footer, sprintf("%*s", $strlen, "Total:"));
-	push(@footer, $rate);
-	push(@footer, shorten_number($total_found, $fwidth[$F_LN_NUM]));
-	push(@footer, $fnrate);
-	push(@footer, shorten_number($fn_total_found, $fwidth[$F_FN_NUM]));
-	push(@footer, $brrate);
-	push(@footer, shorten_number($br_total_found, $fwidth[$F_BR_NUM]));
-
-	# Print assembled line
-	printf($format, @footer);
-}
-
-
-#
-# get_common_filename(filename1, filename2)
-#
-# Check for filename components which are common to FILENAME1 and FILENAME2.
-# Upon success, return
-#
-#   (common, path1, path2)
-#
-#  or 'undef' in case there are no such parts.
-#
-
-sub get_common_filename($$)
-{
-        my @list1 = split("/", $_[0]);
-        my @list2 = split("/", $_[1]);
-	my @result;
-
-	# Work in reverse order, i.e. beginning with the filename itself
-	while (@list1 && @list2 && ($list1[$#list1] eq $list2[$#list2]))
-	{
-		unshift(@result, pop(@list1));
-		pop(@list2);
-	}
-
-	# Did we find any similarities?
-	if (scalar(@result) > 0)
-	{
-	        return (join("/", @result), join("/", @list1),
-			join("/", @list2));
-	}
-	else
-	{
-		return undef;
-	}
-}
-
-
-#
-# strip_directories($path, $depth)
-#
-# Remove DEPTH leading directory levels from PATH.
-#
-
-sub strip_directories($$)
-{
-	my $filename = $_[0];
-	my $depth = $_[1];
-	my $i;
-
-	if (!defined($depth) || ($depth < 1))
-	{
-		return $filename;
-	}
-	for ($i = 0; $i < $depth; $i++)
-	{
-		$filename =~ s/^[^\/]*\/+(.*)$/$1/;
-	}
-	return $filename;
-}
-
-
-#
-# read_diff(filename)
-#
-# Read diff output from FILENAME to memory. The diff file has to follow the
-# format generated by 'diff -u'. Returns a list of hash references:
-#
-#   (mapping, path mapping)
-#
-#   mapping:   filename -> reference to line hash
-#   line hash: line number in new file -> corresponding line number in old file
-#
-#   path mapping:  filename -> old filename
-#
-# Die in case of error.
-#
-
-sub read_diff($)
-{
-	my $diff_file = $_[0];	# Name of diff file
-	my %diff;		# Resulting mapping filename -> line hash
-	my %paths;		# Resulting mapping old path  -> new path
-	my $mapping;		# Reference to current line hash
-	my $line;		# Contents of current line
-	my $num_old;		# Current line number in old file
-	my $num_new;		# Current line number in new file
-	my $file_old;		# Name of old file in diff section
-	my $file_new;		# Name of new file in diff section
-	my $filename;		# Name of common filename of diff section
-	my $in_block = 0;	# Non-zero while we are inside a diff block
-	local *HANDLE;		# File handle for reading the diff file
-
-	info("Reading diff $diff_file\n");
-
-	# Check if file exists and is readable
-	stat($diff_file);
-	if (!(-r _))
-	{
-		die("ERROR: cannot read file $diff_file!\n");
-	}
-
-	# Check if this is really a plain file
-	if (!(-f _))
-	{
-		die("ERROR: not a plain file: $diff_file!\n");
-	}
-
-	# Check for .gz extension
-	if ($diff_file =~ /\.gz$/)
-	{
-		# Check for availability of GZIP tool
-		system_no_output(1, "gunzip", "-h")
-			and die("ERROR: gunzip command not available!\n");
-
-		# Check integrity of compressed file
-		system_no_output(1, "gunzip", "-t", $diff_file)
-			and die("ERROR: integrity check failed for ".
-				"compressed file $diff_file!\n");
-
-		# Open compressed file
-		open(HANDLE, "gunzip -c $diff_file|")
-			or die("ERROR: cannot start gunzip to decompress ".
-			       "file $_[0]!\n");
-	}
-	else
-	{
-		# Open decompressed file
-		open(HANDLE, $diff_file)
-			or die("ERROR: cannot read file $_[0]!\n");
-	}
-
-	# Parse diff file line by line
-	while (<HANDLE>)
-	{
-		chomp($_);
-		$line = $_;
-
-		foreach ($line)
-		{
-			# Filename of old file:
-			# --- <filename> <date>
-			/^--- (\S+)/ && do
-			{
-				$file_old = strip_directories($1, $strip);
-				last;
-			};
-			# Filename of new file:
-			# +++ <filename> <date>
-			/^\+\+\+ (\S+)/ && do
-			{
-				# Add last file to resulting hash
-				if ($filename)
-				{
-					my %new_hash;
-					$diff{$filename} = $mapping;
-					$mapping = \%new_hash;
-				}
-				$file_new = strip_directories($1, $strip);
-				$filename = $file_old;
-				$paths{$filename} = $file_new;
-				$num_old = 1;
-				$num_new = 1;
-				last;
-			};
-			# Start of diff block:
-			# @@ -old_start,old_num, +new_start,new_num @@
-			/^\@\@\s+-(\d+),(\d+)\s+\+(\d+),(\d+)\s+\@\@$/ && do
-			{
-			$in_block = 1;
-			while ($num_old < $1)
-			{
-				$mapping->{$num_new} = $num_old;
-				$num_old++;
-				$num_new++;
-			}
-			last;
-			};
-			# Unchanged line
-			# <line starts with blank>
-			/^ / && do
-			{
-				if ($in_block == 0)
-				{
-					last;
-				}
-				$mapping->{$num_new} = $num_old;
-				$num_old++;
-				$num_new++;
-				last;
-			};
-			# Line as seen in old file
-			# <line starts with '-'>
-			/^-/ && do
-			{
-				if ($in_block == 0)
-				{
-					last;
-				}
-				$num_old++;
-				last;
-			};
-			# Line as seen in new file
-			# <line starts with '+'>
-			/^\+/ && do
-			{
-				if ($in_block == 0)
-				{
-					last;
-				}
-				$num_new++;
-				last;
-			};
-			# Empty line
-			/^$/ && do
-			{
-				if ($in_block == 0)
-				{
-					last;
-				}
-				$mapping->{$num_new} = $num_old;
-				$num_old++;
-				$num_new++;
-				last;
-			};
-		}
-	}
-
-	close(HANDLE);
-
-	# Add final diff file section to resulting hash
-	if ($filename)
-	{
-		$diff{$filename} = $mapping;
-	}
-
-	if (!%diff)
-	{
-		die("ERROR: no valid diff data found in $diff_file!\n".
-		    "Make sure to use 'diff -u' when generating the diff ".
-		    "file.\n");
-	}
-	return (\%diff, \%paths);
-}
-
-
-#
-# apply_diff($count_data, $line_hash)
-#
-# Transform count data using a mapping of lines:
-#
-#   $count_data: reference to hash: line number -> data
-#   $line_hash:  reference to hash: line number new -> line number old
-#
-# Return a reference to transformed count data.
-#
-
-sub apply_diff($$)
-{
-	my $count_data = $_[0];	# Reference to data hash: line -> hash
-	my $line_hash = $_[1];	# Reference to line hash: new line -> old line
-	my %result;		# Resulting hash
-	my $last_new = 0;	# Last new line number found in line hash
-	my $last_old = 0;	# Last old line number found in line hash
-
-	# Iterate all new line numbers found in the diff
-	foreach (sort({$a <=> $b} keys(%{$line_hash})))
-	{
-		$last_new = $_;
-		$last_old = $line_hash->{$last_new};
-
-		# Is there data associated with the corresponding old line?
-		if (defined($count_data->{$line_hash->{$_}}))
-		{
-			# Copy data to new hash with a new line number
-			$result{$_} = $count_data->{$line_hash->{$_}};
-		}
-	}
-	# Transform all other lines which come after the last diff entry
-	foreach (sort({$a <=> $b} keys(%{$count_data})))
-	{
-		if ($_ <= $last_old)
-		{
-			# Skip lines which were covered by line hash
-			next;
-		}
-		# Copy data to new hash with an offset
-		$result{$_ + ($last_new - $last_old)} = $count_data->{$_};
-	}
-
-	return \%result;
-}
-
-
-#
-# apply_diff_to_brcount(brcount, linedata)
-#
-# Adjust line numbers of branch coverage data according to linedata.
-#
-
-sub apply_diff_to_brcount($$)
-{
-	my ($brcount, $linedata) = @_;
-	my $db;
-
-	# Convert brcount to db format
-	$db = brcount_to_db($brcount);
-	# Apply diff to db format
-	$db = apply_diff($db, $linedata);
-	# Convert db format back to brcount format
-	($brcount) = db_to_brcount($db);
-
-	return $brcount;
-}
-
-
-#
-# get_hash_max(hash_ref)
-#
-# Return the highest integer key from hash.
-#
-
-sub get_hash_max($)
-{
-	my ($hash) = @_;
-	my $max;
-
-	foreach (keys(%{$hash})) {
-		if (!defined($max)) {
-			$max = $_;
-		} elsif ($hash->{$_} > $max) {
-			$max = $_;
-		}
-	}
-	return $max;
-}
-
-sub get_hash_reverse($)
-{
-	my ($hash) = @_;
-	my %result;
-
-	foreach (keys(%{$hash})) {
-		$result{$hash->{$_}} = $_;
-	}
-
-	return \%result;
-}
-
-#
-# apply_diff_to_funcdata(funcdata, line_hash)
-#
-
-sub apply_diff_to_funcdata($$)
-{
-	my ($funcdata, $linedata) = @_;
-	my $last_new = get_hash_max($linedata);
-	my $last_old = $linedata->{$last_new};
-	my $func;
-	my %result;
-	my $line_diff = get_hash_reverse($linedata);
-
-	foreach $func (keys(%{$funcdata})) {
-		my $line = $funcdata->{$func};
-
-		if (defined($line_diff->{$line})) {
-			$result{$func} = $line_diff->{$line};
-		} elsif ($line > $last_old) {
-			$result{$func} = $line + $last_new - $last_old;
-		}
-	}
-
-	return \%result;
-}
-
-
-#
-# get_line_hash($filename, $diff_data, $path_data)
-#
-# Find line hash in DIFF_DATA which matches FILENAME. On success, return list
-# line hash. or undef in case of no match. Die if more than one line hashes in
-# DIFF_DATA match.
-#
-
-sub get_line_hash($$$)
-{
-	my $filename = $_[0];
-	my $diff_data = $_[1];
-	my $path_data = $_[2];
-	my $conversion;
-	my $old_path;
-	my $new_path;
-	my $diff_name;
-	my $common;
-	my $old_depth;
-	my $new_depth;
-
-	# Remove trailing slash from diff path
-	$diff_path =~ s/\/$//;
-	foreach (keys(%{$diff_data}))
-	{
-		my $sep = "";
-
-		$sep = '/' if (!/^\//);
-
-		# Try to match diff filename with filename
-		if ($filename =~ /^\Q$diff_path$sep$_\E$/)
-		{
-			if ($diff_name)
-			{
-				# Two files match, choose the more specific one
-				# (the one with more path components)
-				$old_depth = ($diff_name =~ tr/\///);
-				$new_depth = (tr/\///);
-				if ($old_depth == $new_depth)
-				{
-					die("ERROR: diff file contains ".
-					    "ambiguous entries for ".
-					    "$filename\n");
-				}
-				elsif ($new_depth > $old_depth)
-				{
-					$diff_name = $_;
-				}
-			}
-			else
-			{
-				$diff_name = $_;
-			}
-		};
-	}
-	if ($diff_name)
-	{
-		# Get converted path
-		if ($filename =~ /^(.*)$diff_name$/)
-		{
-			($common, $old_path, $new_path) =
-				get_common_filename($filename,
-					$1.$path_data->{$diff_name});
-		}
-		return ($diff_data->{$diff_name}, $old_path, $new_path);
-	}
-	else
-	{
-		return undef;
-	}
-}
-
-
-#
-# convert_paths(trace_data, path_conversion_data)
-#
-# Rename all paths in TRACE_DATA which show up in PATH_CONVERSION_DATA.
-#
-
-sub convert_paths($$)
-{
-	my $trace_data = $_[0];
-	my $path_conversion_data = $_[1];
-	my $filename;
-	my $new_path;
-
-	if (scalar(keys(%{$path_conversion_data})) == 0)
-	{
-		info("No path conversion data available.\n");
-		return;
-	}
-
-	# Expand path conversion list
-	foreach $filename (keys(%{$path_conversion_data}))
-	{
-		$new_path = $path_conversion_data->{$filename};
-		while (($filename =~ s/^(.*)\/[^\/]+$/$1/) &&
-		       ($new_path =~ s/^(.*)\/[^\/]+$/$1/) &&
-		       ($filename ne $new_path))
-		{
-			$path_conversion_data->{$filename} = $new_path;
-		}
-	}
-
-	# Adjust paths
-	FILENAME: foreach $filename (keys(%{$trace_data}))
-	{
-		# Find a path in our conversion table that matches, starting
-		# with the longest path
-		foreach (sort({length($b) <=> length($a)}
-			      keys(%{$path_conversion_data})))
-		{
-			# Is this path a prefix of our filename?
-			if (!($filename =~ /^$_(.*)$/))
-			{
-				next;
-			}
-			$new_path = $path_conversion_data->{$_}.$1;
-
-			# Make sure not to overwrite an existing entry under
-			# that path name
-			if ($trace_data->{$new_path})
-			{
-				# Need to combine entries
-				$trace_data->{$new_path} =
-					combine_info_entries(
-						$trace_data->{$filename},
-						$trace_data->{$new_path},
-						$filename);
-			}
-			else
-			{
-				# Simply rename entry
-				$trace_data->{$new_path} =
-					$trace_data->{$filename};
-			}
-			delete($trace_data->{$filename});
-			next FILENAME;
-		}
-		info("No conversion available for filename $filename\n");
-	}
-}
-
-#
-# sub adjust_fncdata(funcdata, testfncdata, sumfnccount)
-#
-# Remove function call count data from testfncdata and sumfnccount which
-# is no longer present in funcdata.
-#
-
-sub adjust_fncdata($$$)
-{
-	my ($funcdata, $testfncdata, $sumfnccount) = @_;
-	my $testname;
-	my $func;
-	my $f_found;
-	my $f_hit;
-
-	# Remove count data in testfncdata for functions which are no longer
-	# in funcdata
-	foreach $testname (%{$testfncdata}) {
-		my $fnccount = $testfncdata->{$testname};
-
-		foreach $func (%{$fnccount}) {
-			if (!defined($funcdata->{$func})) {
-				delete($fnccount->{$func});
-			}
-		}
-	}
-	# Remove count data in sumfnccount for functions which are no longer
-	# in funcdata
-	foreach $func (%{$sumfnccount}) {
-		if (!defined($funcdata->{$func})) {
-			delete($sumfnccount->{$func});
-		}
-	}
-}
-
-#
-# get_func_found_and_hit(sumfnccount)
-#
-# Return (f_found, f_hit) for sumfnccount
-#
-
-sub get_func_found_and_hit($)
-{
-	my ($sumfnccount) = @_;
-	my $function;
-	my $f_found;
-	my $f_hit;
-
-	$f_found = scalar(keys(%{$sumfnccount}));
-	$f_hit = 0;
-	foreach $function (keys(%{$sumfnccount})) {
-		if ($sumfnccount->{$function} > 0) {
-			$f_hit++;
-		}
-	}
-	return ($f_found, $f_hit);
-}
-
-#
-# diff()
-#
-
-sub diff()
-{
-	my $trace_data = read_info_file($diff);
-	my $diff_data;
-	my $path_data;
-	my $old_path;
-	my $new_path;
-	my %path_conversion_data;
-	my $filename;
-	my $line_hash;
-	my $new_name;
-	my $entry;
-	my $testdata;
-	my $testname;
-	my $sumcount;
-	my $funcdata;
-	my $checkdata;
-	my $testfncdata;
-	my $sumfnccount;
-	my $testbrdata;
-	my $sumbrcount;
-	my $found;
-	my $hit;
-	my $f_found;
-	my $f_hit;
-	my $br_found;
-	my $br_hit;
-	my $converted = 0;
-	my $unchanged = 0;
-	my @result;
-	local *INFO_HANDLE;
-
-	($diff_data, $path_data) = read_diff($ARGV[0]);
-
-        foreach $filename (sort(keys(%{$trace_data})))
-        {
-		# Find a diff section corresponding to this file
-		($line_hash, $old_path, $new_path) =
-			get_line_hash($filename, $diff_data, $path_data);
-		if (!$line_hash)
-		{
-			# There's no diff section for this file
-			$unchanged++;
-			next;
-		}
-		$converted++;
-		if ($old_path && $new_path && ($old_path ne $new_path))
-		{
-			$path_conversion_data{$old_path} = $new_path;
-		}
-		# Check for deleted files
-		if (scalar(keys(%{$line_hash})) == 0)
-		{
-			info("Removing $filename\n");
-			delete($trace_data->{$filename});
-			next;
-		}
-		info("Converting $filename\n");
-		$entry = $trace_data->{$filename};
-		($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
-		 $sumfnccount, $testbrdata, $sumbrcount) =
-			get_info_entry($entry);
-		# Convert test data
-		foreach $testname (keys(%{$testdata}))
-		{
-			# Adjust line numbers of line coverage data
-			$testdata->{$testname} =
-				apply_diff($testdata->{$testname}, $line_hash);
-			# Adjust line numbers of branch coverage data
-			$testbrdata->{$testname} =
-				apply_diff_to_brcount($testbrdata->{$testname},
-						      $line_hash);
-			# Remove empty sets of test data
-			if (scalar(keys(%{$testdata->{$testname}})) == 0)
-			{
-				delete($testdata->{$testname});
-				delete($testfncdata->{$testname});
-				delete($testbrdata->{$testname});
-			}
-		}
-		# Rename test data to indicate conversion
-		foreach $testname (keys(%{$testdata}))
-		{
-			# Skip testnames which already contain an extension
-			if ($testname =~ /,[^,]+$/)
-			{
-				next;
-			}
-			# Check for name conflict
-			if (defined($testdata->{$testname.",diff"}))
-			{
-				# Add counts
-				($testdata->{$testname}) = add_counts(
-					$testdata->{$testname},
-					$testdata->{$testname.",diff"});
-				delete($testdata->{$testname.",diff"});
-				# Add function call counts
-				($testfncdata->{$testname}) = add_fnccount(
-					$testfncdata->{$testname},
-					$testfncdata->{$testname.",diff"});
-				delete($testfncdata->{$testname.",diff"});
-				# Add branch counts
-				($testbrdata->{$testname}) = combine_brcount(
-					$testbrdata->{$testname},
-					$testbrdata->{$testname.",diff"},
-					$BR_ADD);
-				delete($testbrdata->{$testname.",diff"});
-			}
-			# Move test data to new testname
-			$testdata->{$testname.",diff"} = $testdata->{$testname};
-			delete($testdata->{$testname});
-			# Move function call count data to new testname
-			$testfncdata->{$testname.",diff"} =
-				$testfncdata->{$testname};
-			delete($testfncdata->{$testname});
-			# Move branch count data to new testname
-			$testbrdata->{$testname.",diff"} =
-				$testbrdata->{$testname};
-			delete($testbrdata->{$testname});
-		}
-		# Convert summary of test data
-		$sumcount = apply_diff($sumcount, $line_hash);
-		# Convert function data
-		$funcdata = apply_diff_to_funcdata($funcdata, $line_hash);
-		# Convert branch coverage data
-		$sumbrcount = apply_diff_to_brcount($sumbrcount, $line_hash);
-		# Update found/hit numbers
-		# Convert checksum data
-		$checkdata = apply_diff($checkdata, $line_hash);
-		# Convert function call count data
-		adjust_fncdata($funcdata, $testfncdata, $sumfnccount);
-		($f_found, $f_hit) = get_func_found_and_hit($sumfnccount);
-		($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
-		# Update found/hit numbers
-		$found = 0;
-		$hit = 0;
-		foreach (keys(%{$sumcount}))
-		{
-			$found++;
-			if ($sumcount->{$_} > 0)
-			{
-				$hit++;
-			}
-		}
-		if ($found > 0)
-		{
-			# Store converted entry
-			set_info_entry($entry, $testdata, $sumcount, $funcdata,
-				       $checkdata, $testfncdata, $sumfnccount,
-				       $testbrdata, $sumbrcount, $found, $hit,
-				       $f_found, $f_hit, $br_found, $br_hit);
-		}
-		else
-		{
-			# Remove empty data set
-			delete($trace_data->{$filename});
-		}
-        }
-
-	# Convert filenames as well if requested
-	if ($convert_filenames)
-	{
-		convert_paths($trace_data, \%path_conversion_data);
-	}
-
-	info("$converted entr".($converted != 1 ? "ies" : "y")." converted, ".
-	     "$unchanged entr".($unchanged != 1 ? "ies" : "y")." left ".
-	     "unchanged.\n");
-
-	# Write data
-	if ($to_file)
-	{
-		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
-			or die("ERROR: cannot write to $output_filename!\n");
-		@result = write_info_file(*INFO_HANDLE, $trace_data);
-		close(*INFO_HANDLE);
-	}
-	else
-	{
-		@result = write_info_file(*STDOUT, $trace_data);
-	}
-
-	return @result;
-}
-
-
-#
-# system_no_output(mode, parameters)
-#
-# Call an external program using PARAMETERS while suppressing depending on
-# the value of MODE:
-#
-#   MODE & 1: suppress STDOUT
-#   MODE & 2: suppress STDERR
-#
-# Return 0 on success, non-zero otherwise.
-#
-
-sub system_no_output($@)
-{
-	my $mode = shift;
-	my $result;
-	local *OLD_STDERR;
-	local *OLD_STDOUT;
-
-	# Save old stdout and stderr handles
-	($mode & 1) && open(OLD_STDOUT, ">>&STDOUT");
-	($mode & 2) && open(OLD_STDERR, ">>&STDERR");
-
-	# Redirect to /dev/null
-	($mode & 1) && open(STDOUT, ">/dev/null");
-	($mode & 2) && open(STDERR, ">/dev/null");
- 
-	system(@_);
-	$result = $?;
-
-	# Close redirected handles
-	($mode & 1) && close(STDOUT);
-	($mode & 2) && close(STDERR);
-
-	# Restore old handles
-	($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
-	($mode & 2) && open(STDERR, ">>&OLD_STDERR");
- 
-	return $result;
-}
-
-
-#
-# read_config(filename)
-#
-# Read configuration file FILENAME and return a reference to a hash containing
-# all valid key=value pairs found.
-#
-
-sub read_config($)
-{
-	my $filename = $_[0];
-	my %result;
-	my $key;
-	my $value;
-	local *HANDLE;
-
-	if (!open(HANDLE, "<$filename"))
-	{
-		warn("WARNING: cannot read configuration file $filename\n");
-		return undef;
-	}
-	while (<HANDLE>)
-	{
-		chomp;
-		# Skip comments
-		s/#.*//;
-		# Remove leading blanks
-		s/^\s+//;
-		# Remove trailing blanks
-		s/\s+$//;
-		next unless length;
-		($key, $value) = split(/\s*=\s*/, $_, 2);
-		if (defined($key) && defined($value))
-		{
-			$result{$key} = $value;
-		}
-		else
-		{
-			warn("WARNING: malformed statement in line $. ".
-			     "of configuration file $filename\n");
-		}
-	}
-	close(HANDLE);
-	return \%result;
-}
-
-
-#
-# apply_config(REF)
-#
-# REF is a reference to a hash containing the following mapping:
-#
-#   key_string => var_ref
-#
-# where KEY_STRING is a keyword and VAR_REF is a reference to an associated
-# variable. If the global configuration hash CONFIG contains a value for
-# keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
-#
-
-sub apply_config($)
-{
-	my $ref = $_[0];
-
-	foreach (keys(%{$ref}))
-	{
-		if (defined($config->{$_}))
-		{
-			${$ref->{$_}} = $config->{$_};
-		}
-	}
-}
-
-sub warn_handler($)
-{
-	my ($msg) = @_;
-
-	temp_cleanup();
-	warn("$tool_name: $msg");
-}
-
-sub die_handler($)
-{
-	my ($msg) = @_;
-
-	temp_cleanup();
-	die("$tool_name: $msg");
-}
-
-sub abort_handler($)
-{
-	temp_cleanup();
-	exit(1);
-}
-
-sub temp_cleanup()
-{
-	if (@temp_dirs) {
-		info("Removing temporary directories.\n");
-		foreach (@temp_dirs) {
-			rmtree($_);
-		}
-		@temp_dirs = ();
-	}
-}
-
-sub setup_gkv_sys()
-{
-	system_no_output(3, "mount", "-t", "debugfs", "nodev",
-			 "/sys/kernel/debug");
-}
-
-sub setup_gkv_proc()
-{
-	if (system_no_output(3, "modprobe", "gcov_proc")) {
-		system_no_output(3, "modprobe", "gcov_prof");
-	}
-}
-
-sub check_gkv_sys($)
-{
-	my ($dir) = @_;
-
-	if (-e "$dir/reset") {
-		return 1;
-	}
-	return 0;
-}
-
-sub check_gkv_proc($)
-{
-	my ($dir) = @_;
-
-	if (-e "$dir/vmlinux") {
-		return 1;
-	}
-	return 0;
-}
-
-sub setup_gkv()
-{
-	my $dir;
-	my $sys_dir = "/sys/kernel/debug/gcov";
-	my $proc_dir = "/proc/gcov";
-	my @todo;
-
-	if (!defined($gcov_dir)) {
-		info("Auto-detecting gcov kernel support.\n");
-		@todo = ( "cs", "cp", "ss", "cs", "sp", "cp" );
-	} elsif ($gcov_dir =~ /proc/) {
-		info("Checking gcov kernel support at $gcov_dir ".
-		     "(user-specified).\n");
-		@todo = ( "cp", "sp", "cp", "cs", "ss", "cs");
-	} else {
-		info("Checking gcov kernel support at $gcov_dir ".
-		     "(user-specified).\n");
-		@todo = ( "cs", "ss", "cs", "cp", "sp", "cp", );
-	}
-	foreach (@todo) {
-		if ($_ eq "cs") {
-			# Check /sys
-			$dir = defined($gcov_dir) ? $gcov_dir : $sys_dir;
-			if (check_gkv_sys($dir)) {
-				info("Found ".$GKV_NAME[$GKV_SYS]." gcov ".
-				     "kernel support at $dir\n");
-				return ($GKV_SYS, $dir);
-			}
-		} elsif ($_ eq "cp") {
-			# Check /proc
-			$dir = defined($gcov_dir) ? $gcov_dir : $proc_dir;
-			if (check_gkv_proc($dir)) {
-				info("Found ".$GKV_NAME[$GKV_PROC]." gcov ".
-				     "kernel support at $dir\n");
-				return ($GKV_PROC, $dir);
-			}
-		} elsif ($_ eq "ss") {
-			# Setup /sys
-			setup_gkv_sys();
-		} elsif ($_ eq "sp") {
-			# Setup /proc
-			setup_gkv_proc();
-		}
-	}
-	if (defined($gcov_dir)) {
-		die("ERROR: could not find gcov kernel data at $gcov_dir\n");
-	} else {
-		die("ERROR: no gcov kernel data found\n");
-	}
-}
-
-
-#
-# get_overall_line(found, hit, name_singular, name_plural)
-#
-# Return a string containing overall information for the specified
-# found/hit data.
-#
-
-sub get_overall_line($$$$)
-{
-	my ($found, $hit, $name_sn, $name_pl) = @_;
-	my $name;
-
-	return "no data found" if (!defined($found) || $found == 0);
-	$name = ($found == 1) ? $name_sn : $name_pl;
-	return sprintf("%.1f%% (%d of %d %s)", $hit * 100 / $found, $hit,
-		       $found, $name);
-}
-
-
-#
-# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
-#                    br_found, br_hit)
-#
-# Print overall coverage rates for the specified coverage types.
-#
-
-sub print_overall_rate($$$$$$$$$)
-{
-	my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
-	    $br_do, $br_found, $br_hit) = @_;
-
-	info("Overall coverage rate:\n");
-	info("  lines......: %s\n",
-	     get_overall_line($ln_found, $ln_hit, "line", "lines"))
-		if ($ln_do);
-	info("  functions..: %s\n",
-	     get_overall_line($fn_found, $fn_hit, "function", "functions"))
-		if ($fn_do);
-	info("  branches...: %s\n",
-	     get_overall_line($br_found, $br_hit, "branch", "branches"))
-		if ($br_do);
-}
diff --git a/third_party/lcov-1.9/bin/updateversion.pl b/third_party/lcov-1.9/bin/updateversion.pl
deleted file mode 100755
index 55f2bc1..0000000
--- a/third_party/lcov-1.9/bin/updateversion.pl
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/perl -w
-
-use strict;
-
-sub update_man_page($);
-sub update_bin_tool($);
-sub update_txt_file($);
-sub update_spec_file($);
-sub get_file_info($);
-
-our $directory = $ARGV[0];
-our $version = $ARGV[1];
-our $release = $ARGV[2];
-
-our @man_pages = ("man/gendesc.1",  "man/genhtml.1",  "man/geninfo.1",
-		  "man/genpng.1", "man/lcov.1", "man/lcovrc.5");
-our @bin_tools = ("bin/gendesc", "bin/genhtml", "bin/geninfo",
-		  "bin/genpng", "bin/lcov");
-our @txt_files = ("README");
-our @spec_files = ("rpm/lcov.spec");
-
-if (!defined($directory) || !defined($version) || !defined($release)) {
-	die("Usage: $0 <directory> <version string> <release string>\n");
-}
-
-foreach (@man_pages) {
-	print("Updating man page $_\n");
-	update_man_page($directory."/".$_);
-}
-foreach (@bin_tools) {
-	print("Updating bin tool $_\n");
-	update_bin_tool($directory."/".$_);
-}
-foreach (@txt_files) {
-	print("Updating text file $_\n");
-	update_txt_file($directory."/".$_);
-}
-foreach (@spec_files) {
-	print("Updating spec file $_\n");
-	update_spec_file($directory."/".$_);
-}
-print("Done.\n");
-
-sub get_file_info($)
-{
-	my ($filename) = @_;
-	my ($sec, $min, $hour, $year, $month, $day);
-	my @stat;
-
-	@stat = stat($filename);
-	($sec, $min, $hour, $day, $month, $year) = localtime($stat[9]);
-	$year += 1900;
-	$month += 1;
-
-	return (sprintf("%04d-%02d-%02d", $year, $month, $day),
-		sprintf("%04d%02d%02d%02d%02d.%02d", $year, $month, $day,
-			$hour, $min, $sec),
-		sprintf("%o", $stat[2] & 07777));
-}
-
-sub update_man_page($)
-{
-	my ($filename) = @_;
-	my @date = get_file_info($filename);
-	my $date_string = $date[0];
-	local *IN;
-	local *OUT;
-
-	$date_string =~ s/-/\\-/g;
-	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
-	open(OUT, ">$filename.new") ||
-		die("Error: cannot create $filename.new\n");
-	while (<IN>) {
-		s/\"LCOV\s+\d+\.\d+\"/\"LCOV $version\"/g;
-		s/\d\d\d\d\\\-\d\d\\\-\d\d/$date_string/g;
-		print(OUT $_);
-	}
-	close(OUT);
-	close(IN);
-	chmod(oct($date[2]), "$filename.new");
-	system("mv", "-f", "$filename.new", "$filename");
-	system("touch", "$filename", "-t", $date[1]);
-}
-
-sub update_bin_tool($)
-{
-	my ($filename) = @_;
-	my @date = get_file_info($filename);
-	local *IN;
-	local *OUT;
-
-	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
-	open(OUT, ">$filename.new") ||
-		die("Error: cannot create $filename.new\n");
-	while (<IN>) {
-		s/(our\s+\$lcov_version\s*=\s*["']).*(["'].*)$/$1LCOV version $version$2/g;
-		print(OUT $_);
-	}
-	close(OUT);
-	close(IN);
-	chmod(oct($date[2]), "$filename.new");
-	system("mv", "-f", "$filename.new", "$filename");
-	system("touch", "$filename", "-t", $date[1]);
-}
-
-sub update_txt_file($)
-{
-	my ($filename) = @_;
-	my @date = get_file_info($filename);
-	local *IN;
-	local *OUT;
-
-	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
-	open(OUT, ">$filename.new") ||
-		die("Error: cannot create $filename.new\n");
-	while (<IN>) {
-		s/(Last\s+changes:\s+)\d\d\d\d-\d\d-\d\d/$1$date[0]/g;
-		print(OUT $_);
-	}
-	close(OUT);
-	close(IN);
-	chmod(oct($date[2]), "$filename.new");
-	system("mv", "-f", "$filename.new", "$filename");
-	system("touch", "$filename", "-t", $date[1]);
-}
-
-sub update_spec_file($)
-{
-	my ($filename) = @_;
-	my @date = get_file_info($filename);
-	local *IN;
-	local *OUT;
-
-	open(IN, "<$filename") || die ("Error: cannot open $filename\n");
-	open(OUT, ">$filename.new") ||
-		die("Error: cannot create $filename.new\n");
-	while (<IN>) {
-		s/^(Version:\s*)\d+\.\d+.*$/$1$version/;
-		s/^(Release:\s*).*$/$1$release/;
-		print(OUT $_);
-	}
-	close(OUT);
-	close(IN);
-	system("mv", "-f", "$filename.new", "$filename");
-	system("touch", "$filename", "-t", $date[1]);
-}
diff --git a/third_party/lcov-1.9/contrib/galaxy/CHANGES b/third_party/lcov-1.9/contrib/galaxy/CHANGES
deleted file mode 100644
index b09883b..0000000
--- a/third_party/lcov-1.9/contrib/galaxy/CHANGES
+++ /dev/null
@@ -1 +0,0 @@
-09-04-2003 Initial checkin
diff --git a/third_party/lcov-1.9/contrib/galaxy/README b/third_party/lcov-1.9/contrib/galaxy/README
deleted file mode 100644
index e21c509..0000000
--- a/third_party/lcov-1.9/contrib/galaxy/README
+++ /dev/null
@@ -1,48 +0,0 @@
--------------------------------------------------
-- README file for the LCOV galaxy mapping tool  -
-- Last changes: 2003-09-04                      -
--------------------------------------------------
-
-Description
------------
-
-Further README contents
------------------------
-  1. Included files
-  2. Installing 
-  3. Notes and Comments
-
-
-
-1. Important files
-------------------
-  README                       - This README file
-  CHANGES                      - List of changes between releases
-  conglomerate_functions.pl    - Replacement file - Generates shading 
-  genflat.pl                   - Generates info for shading from .info files 
-  gen_makefile.sh              - Replacement file - updates to postscript
-  posterize.pl                 - Replacement file - generates a final ps file
-
-2. Installing 
--------------
-     This install requires fcgp, which means the target kernel src must be on
-the system creating the map.
-
-     Download and copy the new files into the fcgp directory, (Note: its always
-a good idea to have backups). 
-
-     Run genflat.pl against your kernel info files
-        ./genflat.pl kernel.info kernel2.info > coverage.dat
-
-     Run the make command for the fcgp (Note: this can take a while)
-        make KERNEL_DIR=/usr/src/linux
-
-     Update posterize.pl as needed, normally page size, margins, titles.
-Most of these settings will be broken out as command line options in the future.
-
-     Run posterize.pl this will generate the file poster.ps.
-
-3. Notes and Comments
----------------------
-     This is a quick and dirty implementation suited for my needs. It does not
-perform any of the tiling the original did. 
diff --git a/third_party/lcov-1.9/contrib/galaxy/conglomerate_functions.pl b/third_party/lcov-1.9/contrib/galaxy/conglomerate_functions.pl
deleted file mode 100755
index 4e259fe..0000000
--- a/third_party/lcov-1.9/contrib/galaxy/conglomerate_functions.pl
+++ /dev/null
@@ -1,195 +0,0 @@
-#! /usr/bin/perl -w
-
-# Takes a set of ps images (belonging to one file) and produces a
-# conglomerate picture of that file: static functions in the middle,
-# others around it.  Each one gets a box about its area.
-
-use strict;
-
-my $SCRUNCH = $ARGV [0];
-my $BOXSCRUNCH = $ARGV [1];
-my $Tmp;
-my $DEBUG = 1;
-
-shift @ARGV; # skip SCRUNCH and BOXSCRUNCH
-shift @ARGV;
-
-
-DecorateFuncs (@ARGV);
-
-
-#TMPFILE=`mktemp ${TMPDIR:-/tmp}/$$.XXXXXX`
-
-# Arrange.
-my $ArgList = "";
-
-foreach $Tmp (@ARGV) {
-	$ArgList .= "'$Tmp' ";
-}
-
-my @Arranged = `../draw_arrangement $SCRUNCH 0 360 0 $ArgList`;
-
-my $CFile = $ARGV [0];
-$CFile =~ s/\.c\..*$/.c/;
-if ($DEBUG) { print ("% Conglomeration of $CFile\n"); }
-
-print "gsave angle rotate\n";
-
-# Now output the file, except last line.
-my $LastLine = pop (@Arranged);
-my $Fill = Box_2 ($LastLine,$CFile);
-print $Fill;
-# Draw box with file name
-my @Output = Box ('normal', 'Helvetica-Bold', 32, $CFile, $LastLine);
-splice(@Output, $#Output, 0, "grestore\n");
-#print @Output;
-
-print (@Arranged);
-#add a duplicate box to test if this works
-print @Output;
-
-
-sub ParseBound
-{
-	my $BBoxLine = shift;
-
-	$BBoxLine =~ /(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)/;
-
-	# XMin, YMin, XMax, YMax
-	return ($1 * $BOXSCRUNCH, $2 * $BOXSCRUNCH,
-		$3 * $BOXSCRUNCH, $4 * $BOXSCRUNCH);
-}
-
-
-
-# Box (type, font, fontsize, Label, BBoxLine)
-sub Box
-{
-	my $Type     = shift;
-	my $Font     = shift;
-	my $Fontsize = shift;
-	my $Label    = shift;
-	my $BBoxLine = shift;
-        my @Output   = ();
-
-	#        print (STDERR "Box ('$Type', '$Font', '$Fontsize', '$Label', '$BBoxLine')\n");
-	push (@Output, "% start of box\n");
-
-	push (@Output, "D5\n") if ($Type eq "dashed");
-
-	#	print (STDERR "BBoxLine: '$BBoxLine'\n");
-	#	print (STDERR "Parsed: '" . join ("' '", ParseBound ($BBoxLine)) . "\n");
-	my ($XMin, $YMin, $XMax, $YMax) = ParseBound ($BBoxLine);
-
-	my $LeftSpaced   = $XMin + 6;
-	my $BottomSpaced = $YMin + 6;
-
-	# Put black box around it
-	push (@Output, (
-                        "($Label) $LeftSpaced $BottomSpaced $Fontsize /$Font\n",
-                        "$YMin $XMin $YMax $XMax U\n"
-		       )
-	     );
-
-	push (@Output, "D\n") if ($Type eq "dashed");
-	# fill bounding box
-	push (@Output, "% end of box\n");
-
-	# Output bounding box
-	push (@Output, "% bound $XMin $YMin $XMax $YMax\n");
-
-        return @Output;
-}
-
-sub Box_2
-{
-	my $BBoxLine = shift;
-	my $CFile = shift;
-	my $CovFile = "./coverage.dat";
-	my ($XMin, $YMin, $XMax, $YMax) = ParseBound ($BBoxLine);
-	my @output = `fgrep $CFile $CovFile`;
-	chomp $output[0];
-	my ($junk, $Class, $per) = split /\t/, $output[0];
-	return "$XMin $YMin $XMax $YMax $Class\n";
-}
-# Decorate (rgb-vals(1 string) filename)
-sub Decorate
-{
-	my $RGB      = shift;
-        my $Filename = shift;
-
-        my @Input    = ReadPS ($Filename);
-        my $LastLine = pop (@Input);
-	my @Output   = ();
-
-	# Color at the beginning.
-	push (@Output, "C$RGB\n");
-
-	# Now output the file, except last line.
-        push (@Output, @Input);
-
-	# Draw dashed box with function name
-	# FIXME Make bound cover the label as well!
-	my $FuncName = $Filename;
-	$FuncName =~ s/^[^.]+\.c\.(.+?)\..*$/$1/;
-
-	push (@Output, Box ('dashed', 'Helvetica', 24, $FuncName, $LastLine));
-
-	# Slap over the top.
-        WritePS ($Filename, @Output);
-}
-
-
-
-# Add colored boxes around functions
-sub DecorateFuncs
-{
-	my $FName = "";
-        my $FType = "";
-
-	foreach $FName (@ARGV)
-	{
-		$FName =~ /\+([A-Z]+)\+/;
-		$FType = $1;
-
-		if ($FType eq 'STATIC') {
-			Decorate ("2", $FName); # Light green.
- 		}
- 		elsif ($FType eq 'INDIRECT') {
-			Decorate ("3", $FName); # Green.
- 		}
- 		elsif ($FType eq 'EXPORTED') {
-			Decorate ("4", $FName); # Red.
- 		}
- 		elsif ($FType eq 'NORMAL') {
-			Decorate ("5", $FName); # Blue.
-		}
-		else {
-			die ("Unknown extension $FName");
-		}
-	}
-}
-
-
-sub ReadPS
-{
-	my $Filename = shift;
-        my @Contents = ();
-
-	open (INFILE, "$Filename") or die ("Could not read $Filename: $!");
-	@Contents = <INFILE>;
-	close (INFILE);
-
-	return @Contents;
-}
-
-sub WritePS
-{
-	my $Filename = shift;
-
-	open (OUTFILE, ">$Filename")
-		or die ("Could not write $Filename: $!");
-	print (OUTFILE @_);
-        close (OUTFILE);
-}
-
diff --git a/third_party/lcov-1.9/contrib/galaxy/gen_makefile.sh b/third_party/lcov-1.9/contrib/galaxy/gen_makefile.sh
deleted file mode 100755
index ab51a5e..0000000
--- a/third_party/lcov-1.9/contrib/galaxy/gen_makefile.sh
+++ /dev/null
@@ -1,129 +0,0 @@
-#! /bin/sh
-
-cd image
-
-# Space-optimized version: strip comments, drop precision to 3
-# figures, eliminate duplicates.
-# update(creinig): precision reduction is now done in data2ps and comments
-# (except for % bound) now are also ommitted from the start
-
-echo 'image.ps: image-unop.ps'
-#echo '	grep -v "^%" < $< | sed -e "s/\.\([0-9][0-9]\)[0-9]\+/.\1/g" -e "s/\(^\| \|-\)\([0-9][0-9][0-9]\)[0-9][0-9]\.[0-9][0-9]/\1\200/g" -e "s/\(^\| \|-\)\([0-9][0-9][0-9]\)[0-9]\.[0-9][0-9]/\1\20/g" -e "s/\(^\| \|-\)\([0-9][0-9][0-9]\)\.[0-9][0-9]/\1\2/g" -e "s/\(^\| \|-\)\([0-9][0-9]\)\.\([0-9]\)[0-9]/\1\2.\30/g" | awk "\$$0 ~ /lineto/ { if ( LASTLINE == \$$0 ) next; } { LASTLINE=\$$0; print; }" > $@'
-echo '	grep -v "^% bound" < $< > $@'
-# Need last comment (bounding box)
-echo '	tail -1 $< >> $@'
-echo '	ls -l image.ps image-unop.ps'
-
-echo 'image-unop.ps: outline.ps ring1.ps ring2.ps ring3.ps ring4.ps'
-echo '	cat ring[1234].ps > $@'
-# Bounding box is at bottom now.  Next two won't change it.
-echo '	tail -1 $@ > bounding-box'
-echo '	cat outline.ps >> $@'
-echo '	cat ../tux.ps >> $@'
-echo '	cat bounding-box >> $@ && rm bounding-box'
-
-# Finished rings are precious!
-echo .SECONDARY: ring1.ps ring2.ps ring3.ps ring4.ps
-
-# Rings 1 and 4 are all thrown together.
-echo RING1_DEPS:=`find $RING1 -name '*.c.*' | sed 's/\.c.*/-all.ps/' | sort | uniq`
-echo RING4_DEPS:=`find $RING4 -name '*.c.*' | sed 's/\.c.*/-all.ps/' | sort | uniq`
-
-# Other rings are divided into dirs.
-echo RING2_DEPS:=`for d in $RING2; do echo $d-ring2.ps; done`
-echo RING3_DEPS:=`for d in $RING3; do echo $d-ring3.ps; done`
-echo
-
-# First ring starts at inner radius.
-echo 'ring1.ps: $(RING1_DEPS)'
-echo "	@echo Making Ring 1"
-echo "	@echo /angle 0 def > \$@"
-echo "	@../draw_arrangement $FILE_SCRUNCH 0 360 $INNER_RADIUS \$(RING1_DEPS) >> \$@"
-echo "	@echo Done Ring 1"
-
-# Second ring starts at end of above ring (assume it's circular, so
-# grab any bound).
-echo 'ring2.ps: ring1.ps $(RING2_DEPS)'
-echo "	@echo Making Ring 2"
-echo "	@echo /angle 0 def > \$@"
-echo "	@../rotary_arrange.sh $DIR_SPACING" `for f in $RING2; do echo $f-ring2.ps $f-ring2.angle; done` '>> $@'
-echo "	@echo Done Ring 2"
-
-# Third ring starts at end of second ring.
-echo 'ring3.ps: ring2.ps $(RING3_DEPS)'
-echo "	@echo Making Ring 3"
-echo "	@echo /angle 0 def > \$@"
-echo "	@../rotary_arrange.sh $DIR_SPACING" `for f in $RING3; do echo $f-ring3.ps $f-ring3.angle; done` '>> $@'
-echo "	@echo Done Ring 3"
-
-# Outer ring starts at end of fourth ring.
-# And it's just a big ring of drivers.
-echo 'ring4.ps: $(RING4_DEPS) ring3.radius'
-echo "	@echo Making Ring 4"
-echo "	@echo /angle 0 def > \$@"
-echo "	@../draw_arrangement $FILE_SCRUNCH 0 360 \`cat ring3.radius\` \$(RING4_DEPS) >> \$@"
-echo "	@echo Done Ring 4"
-echo
-
-# How to make directory picture: angle file contains start and end angle.
-# Second ring starts at end of above ring (assume it's circular, so
-# grab any bound).
-echo "%-ring2.ps: %-ring2.angle ring1.radius"
-echo "	@echo Rendering \$@"
-echo "	@../draw_arrangement $FILE_SCRUNCH 0 \`cat \$<\` \`cat ring1.radius\` \`find \$* -name '*-all.ps'\` > \$@"
-
-echo "%-ring3.ps: %-ring3.angle ring2.radius"
-echo "	@echo Rendering \$@"
-echo "	@../draw_arrangement $FILE_SCRUNCH 0 \`cat \$<\` \`cat ring2.radius\` \`find \$* -name '*-all.ps'\` > \$@"
-
-# How to extract radii
-echo "%.radius: %.ps"
-echo '	@echo scale=2\; `tail -1 $< | sed "s/^.* //"` + '$RING_SPACING' | bc > $@'
-echo
-
-# How to make angle.  Need total angle for that directory, and weight.
-echo "%-ring2.angle: %-ring2.weight ring2.weight"
-echo '	@echo "scale=2; ( 360 - ' `echo $RING2 | wc -w` ' * ' $DIR_SPACING ') * `cat $<` / `cat ring2.weight`" | bc > $@'
-
-echo "%-ring3.angle: %-ring3.weight ring3.weight"
-echo '	@echo "scale=2; ( 360 - ' `echo $RING3 | wc -w` ' * ' $DIR_SPACING ') * `cat $<` / `cat ring3.weight`" | bc > $@'
-
-# How to make ring weights (sum directory totals).
-echo "ring2.weight:" `for d in $RING2; do echo $d-ring2.weight; done`
-echo '	@cat $^ | ../tally > $@'
-echo "ring3.weight:" `for d in $RING3; do echo $d-ring3.weight; done`
-echo '	@cat $^ | ../tally > $@'
-
-# How to make a wieght.
-echo "%-ring2.weight:" `find $RING2 -name '*.c.*' | sed 's/\.c.*/-all.ps/' | sort | uniq`
-echo '	@../total_area.pl `find $* -name \*-all.ps` > $@'
-echo "%-ring3.weight:" `find $RING3 -name '*.c.*' | sed 's/\.c.*/-all.ps/' | sort | uniq`
-echo '	@../total_area.pl `find $* -name \*-all.ps` > $@'
-echo
-
-# Now rule to make the graphs of a function.
-#echo %.ps::%
-#echo '	@../function2ps `echo $< | sed '\''s/^.*\.\([^.]*\)\.\+.*$$/\1/'\''` > $@ $<'
-## Need the space.
-##echo '	@rm -f $<'
-#echo
-
-# Rule to make all from constituent parts.
-echo %-all.ps:
-echo "	@echo Rendering \$*.c"
-echo "	@../conglomerate_functions.pl $FUNCTION_SCRUNCH $BOX_SCRUNCH \$^ > \$@"
-# Need the space.
-#echo '	@rm -f $^'
-echo
-
-# Generating outline, requires all the angles.
-echo outline.ps: ../make-outline.sh ring1.ps ring2.ps ring3.ps ring4.ps `for f in $RING2; do echo $f-ring2.angle; done` `for f in $RING3; do echo $f-ring3.angle; done`
-echo "	../make-outline.sh $INNER_RADIUS $DIR_SPACING $RING_SPACING \"$RING1\" > \$@"
-echo
-
-# Now all the rules to make each function.
-for d in `find . -type d`; do
-    for f in `cd $d; ls *+.ps 2>/dev/null | sed 's/\.c\..*$//' | uniq`; do
-	echo $d/$f-all.ps: `cd $d; ls $f.c.* | sed -e "s?^?$d/?"`
-    done
-done
diff --git a/third_party/lcov-1.9/contrib/galaxy/genflat.pl b/third_party/lcov-1.9/contrib/galaxy/genflat.pl
deleted file mode 100755
index b8b8ff4..0000000
--- a/third_party/lcov-1.9/contrib/galaxy/genflat.pl
+++ /dev/null
@@ -1,1238 +0,0 @@
-#!/usr/bin/perl -w
-#
-#   Copyright (c) International Business Machines  Corp., 2002
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.                 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-#
-# genflat
-#
-#   This script generates std output from .info files as created by the
-#   geninfo script. Call it with --help to get information on usage and 
-#   available options.  This code is based on the lcov genhtml script
-#   by Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-#
-#
-# History:
-#   2003-08-19 ripped up Peter's script James M Kenefick Jr. <jkenefic@us.ibm.com>
-#
-
-use strict;
-use File::Basename; 
-use Getopt::Long;
-# Constants
-our $lcov_version = "";
-our $lcov_url = "";
-
-# Specify coverage rate limits (in %) for classifying file entries
-# HI:   $hi_limit <= rate <= 100          graph color: green
-# MED: $med_limit <= rate <  $hi_limit    graph color: orange
-# LO:          0  <= rate <  $med_limit   graph color: red
-our $hi_limit	= 50;
-our $med_limit	= 15;
-
-# Data related prototypes
-sub print_usage(*);
-sub gen_html();
-sub process_dir($);
-sub process_file($$$);
-sub info(@);
-sub read_info_file($);
-sub get_info_entry($);
-sub set_info_entry($$$$;$$);
-sub get_prefix(@);
-sub shorten_prefix($);
-sub get_dir_list(@);
-sub get_relative_base_path($);
-sub get_date_string();
-sub split_filename($);
-sub subtract_counts($$);
-sub add_counts($$);
-sub apply_baseline($$);
-sub combine_info_files($$);
-sub combine_info_entries($$);
-sub apply_prefix($$);
-sub escape_regexp($);
-
-
-# HTML related prototypes
-
-
-sub write_file_table(*$$$$);
-
-
-# Global variables & initialization
-our %info_data;		# Hash containing all data from .info file
-our $dir_prefix;	# Prefix to remove from all sub directories
-our %test_description;	# Hash containing test descriptions if available
-our $date = get_date_string();
-
-our @info_filenames;	# List of .info files to use as data source
-our $test_title;	# Title for output as written to each page header
-our $output_directory;	# Name of directory in which to store output
-our $base_filename;	# Optional name of file containing baseline data
-our $desc_filename;	# Name of file containing test descriptions
-our $css_filename;	# Optional name of external stylesheet file to use
-our $quiet;		# If set, suppress information messages
-our $help;		# Help option flag
-our $version;		# Version option flag
-our $show_details;	# If set, generate detailed directory view
-our $no_prefix;		# If set, do not remove filename prefix
-our $frames;		# If set, use frames for source code view
-our $keep_descriptions;	# If set, do not remove unused test case descriptions
-our $no_sourceview;	# If set, do not create a source code view for each file
-our $tab_size = 8;	# Number of spaces to use in place of tab
-
-our $cwd = `pwd`;	# Current working directory
-chomp($cwd);
-our $tool_dir = dirname($0);	# Directory where genhtml tool is installed
-
-
-#
-# Code entry point
-#
-
-# Add current working directory if $tool_dir is not already an absolute path
-if (! ($tool_dir =~ /^\/(.*)$/))
-{
-	$tool_dir = "$cwd/$tool_dir";
-}
-
-# Parse command line options
-if (!GetOptions("output-directory=s"	=> \$output_directory,
-		"css-file=s"		=> \$css_filename,
-		"baseline-file=s"	=> \$base_filename,
-		"prefix=s"		=> \$dir_prefix,
-		"num-spaces=i"		=> \$tab_size,
-		"no-prefix"		=> \$no_prefix,
-		"quiet"			=> \$quiet,
-		"help"			=> \$help,
-		"version"		=> \$version
-		))
-{
-	print_usage(*STDERR);
-	exit(1);
-}
-
-@info_filenames = @ARGV;
-
-# Check for help option
-if ($help)
-{
-	print_usage(*STDOUT);
-	exit(0);
-}
-
-# Check for version option
-if ($version)
-{
-	print($lcov_version."\n");
-	exit(0);
-}
-
-# Check for info filename
-if (!@info_filenames)
-{
-	print(STDERR "No filename specified\n");
-	print_usage(*STDERR);
-	exit(1);
-}
-
-# Generate a title if none is specified
-if (!$test_title)
-{
-	if (scalar(@info_filenames) == 1)
-	{
-		# Only one filename specified, use it as title
-		$test_title = basename($info_filenames[0]);
-	}
-	else
-	{
-		# More than one filename specified, used default title
-		$test_title = "unnamed";
-	}
-}
-
-# Make sure tab_size is within valid range
-if ($tab_size < 1)
-{
-	print(STDERR "ERROR: invalid number of spaces specified: ".
-		     "$tab_size!\n");
-	exit(1);
-}
-
-# Do something
-gen_html();
-
-exit(0);
-
-
-
-#
-# print_usage(handle)
-#
-# Print usage information.
-#
-
-sub print_usage(*)
-{
-	local *HANDLE = $_[0];
-	my $executable_name = basename($0);
-
-	print(HANDLE <<END_OF_USAGE);
-Usage: $executable_name [OPTIONS] INFOFILE(S)
-
-Create HTML output for coverage data found in INFOFILE. Note that INFOFILE
-may also be a list of filenames.
-
-  -h, --help                        Print this help, then exit
-  -v, --version                     Print version number, then exit
-  -q, --quiet                       Do not print progress messages
-  -b, --baseline-file BASEFILE      Use BASEFILE as baseline file
-  -p, --prefix PREFIX               Remove PREFIX from all directory names
-      --no-prefix                   Do not remove prefix from directory names
-      --no-source                   Do not create source code view
-      --num-spaces NUM              Replace tabs with NUM spaces in source view
-
-See $lcov_url for more information about this tool.
-END_OF_USAGE
-	;
-}
-
-
-#
-# gen_html()
-#
-# Generate a set of HTML pages from contents of .info file INFO_FILENAME.
-# Files will be written to the current directory. If provided, test case
-# descriptions will be read from .tests file TEST_FILENAME and included
-# in ouput.
-#
-# Die on error.
-#
-
-sub gen_html()
-{
-	local *HTML_HANDLE;
-	my %overview;
-	my %base_data;
-	my $lines_found;
-	my $lines_hit;
-	my $overall_found = 0;
-	my $overall_hit = 0;
-	my $dir_name;
-	my $link_name;
-	my @dir_list;
-	my %new_info;
-
-	# Read in all specified .info files
-	foreach (@info_filenames)
-	{
-		info("Reading data file $_\n");
-		%new_info = %{read_info_file($_)};
-
-		# Combine %new_info with %info_data
-		%info_data = %{combine_info_files(\%info_data, \%new_info)};
-	}
-
-	info("Found %d entries.\n", scalar(keys(%info_data)));
-
-	# Read and apply baseline data if specified
-	if ($base_filename)
-	{
-		# Read baseline file
-		info("Reading baseline file $base_filename\n");
-		%base_data = %{read_info_file($base_filename)};
-		info("Found %d entries.\n", scalar(keys(%base_data)));
-
-		# Apply baseline
-		info("Subtracting baseline data.\n");
-		%info_data = %{apply_baseline(\%info_data, \%base_data)};
-	}
-
-	@dir_list = get_dir_list(keys(%info_data));
-
-	if ($no_prefix)
-	{
-		# User requested that we leave filenames alone
-		info("User asked not to remove filename prefix\n");
-	}
-	elsif (!defined($dir_prefix))
-	{
-		# Get prefix common to most directories in list
-		$dir_prefix = get_prefix(@dir_list);
-
-		if ($dir_prefix)
-		{
-			info("Found common filename prefix \"$dir_prefix\"\n");
-		}
-		else
-		{
-			info("No common filename prefix found!\n");
-			$no_prefix=1;
-		}
-	}
-	else
-	{
-		info("Using user-specified filename prefix \"".
-		     "$dir_prefix\"\n");
-	}
-
-	# Process each subdirectory and collect overview information
-	foreach $dir_name (@dir_list)
-	{
-		($lines_found, $lines_hit) = process_dir($dir_name);
-
-		$overview{$dir_name} = "$lines_found,$lines_hit, ";
-		$overall_found	+= $lines_found;
-		$overall_hit	+= $lines_hit;
-	}
-
-
-	if ($overall_found == 0)
-	{
-		info("Warning: No lines found!\n");
-	}
-	else
-	{
-		info("Overall coverage rate: %d of %d lines (%.1f%%)\n",
-		     $overall_hit, $overall_found,
-		     $overall_hit*100/$overall_found);
-	}
-}
-
-
-#
-# process_dir(dir_name)
-#
-
-sub process_dir($)
-{
-	my $abs_dir = $_[0];
-	my $trunc_dir;
-	my $rel_dir = $abs_dir;
-	my $base_dir;
-	my $filename;
-	my %overview;
-	my $lines_found;
-	my $lines_hit;
-	my $overall_found=0;
-	my $overall_hit=0;
-	my $base_name;
-	my $extension;
-	my $testdata;
-	my %testhash;
-	local *HTML_HANDLE;
-
-	# Remove prefix if applicable
-	if (!$no_prefix)
-	{
-		# Match directory name beginning with $dir_prefix
-	        $rel_dir = apply_prefix($rel_dir, $dir_prefix);
-	}
-
-	$trunc_dir = $rel_dir;
-
-	# Remove leading /
-	if ($rel_dir =~ /^\/(.*)$/)
-	{
-		$rel_dir = substr($rel_dir, 1);
-	}
-
-	$base_dir = get_relative_base_path($rel_dir);
-
-	$abs_dir = escape_regexp($abs_dir);
-
-	# Match filenames which specify files in this directory, not including
-	# sub-directories
-	foreach $filename (grep(/^$abs_dir\/[^\/]*$/,keys(%info_data)))
-	{
-		($lines_found, $lines_hit, $testdata) =
-			process_file($trunc_dir, $rel_dir, $filename);
-
-		$base_name = basename($filename);
-
-		$overview{$base_name} = "$lines_found,$lines_hit";
-
-		$testhash{$base_name} = $testdata;
-
-		$overall_found	+= $lines_found;
-		$overall_hit	+= $lines_hit;
-	}
-	write_file_table($abs_dir, "./linux/", \%overview, \%testhash, 4);
-
-
-	# Calculate resulting line counts
-	return ($overall_found, $overall_hit);
-}
-
-
-#
-# process_file(trunc_dir, rel_dir, filename)
-#
-
-sub process_file($$$)
-{
-	info("Processing file ".apply_prefix($_[2], $dir_prefix)."\n");
-	my $trunc_dir = $_[0];
-	my $rel_dir = $_[1];
-	my $filename = $_[2];
-	my $base_name = basename($filename);
-	my $base_dir = get_relative_base_path($rel_dir);
-	my $testdata;
-	my $testcount;
-	my $sumcount;
-	my $funcdata;
-	my $lines_found;
-	my $lines_hit;
-	my @source;
-	my $pagetitle;
-
-	($testdata, $sumcount, $funcdata, $lines_found, $lines_hit) =
-		get_info_entry($info_data{$filename});
-	return ($lines_found, $lines_hit, $testdata);
-}
-
-
-#
-# read_info_file(info_filename)
-#
-# Read in the contents of the .info file specified by INFO_FILENAME. Data will
-# be returned as a reference to a hash containing the following mappings:
-#
-# %result: for each filename found in file -> \%data
-#
-# %data: "test"  -> \%testdata
-#        "sum"   -> \%sumcount
-#        "func"  -> \%funcdata
-#        "found" -> $lines_found (number of instrumented lines found in file)
-#	 "hit"   -> $lines_hit (number of executed lines in file)
-#
-# %testdata: name of test affecting this file -> \%testcount
-#
-# %testcount: line number -> execution count for a single test
-# %sumcount : line number -> execution count for all tests
-# %funcdata : line number -> name of function beginning at that line
-# 
-# Note that .info file sections referring to the same file and test name
-# will automatically be combined by adding all execution counts.
-#
-# Note that if INFO_FILENAME ends with ".gz", it is assumed that the file
-# is compressed using GZIP. If available, GUNZIP will be used to decompress
-# this file.
-#
-# Die on error
-#
-
-sub read_info_file($)
-{
-	my $tracefile = $_[0];		# Name of tracefile
-	my %result;			# Resulting hash: file -> data
-	my $data;			# Data handle for current entry
-	my $testdata;			#       "             "
-	my $testcount;			#       "             "
-	my $sumcount;			#       "             "
-	my $funcdata;			#       "             "
-	my $line;			# Current line read from .info file
-	my $testname;			# Current test name
-	my $filename;			# Current filename
-	my $hitcount;			# Count for lines hit
-	my $count;			# Execution count of current line
-	my $negative;			# If set, warn about negative counts
-	local *INFO_HANDLE;		# Filehandle for .info file
-
-	# Check if file exists and is readable
-	stat($_[0]);
-	if (!(-r _))
-	{
-		die("ERROR: cannot read file $_[0]!\n");
-	}
-
-	# Check if this is really a plain file
-	if (!(-f _))
-	{
-		die("ERROR: not a plain file: $_[0]!\n");
-	}
-
-	# Check for .gz extension
-	if ($_[0] =~ /^(.*)\.gz$/)
-	{
-		# Check for availability of GZIP tool
-		system("gunzip -h >/dev/null 2>/dev/null")
-			and die("ERROR: gunzip command not available!\n");
-
-		# Check integrity of compressed file
-		system("gunzip -t $_[0] >/dev/null 2>/dev/null")
-			and die("ERROR: integrity check failed for ".
-				"compressed file $_[0]!\n");
-
-		# Open compressed file
-		open(INFO_HANDLE, "gunzip -c $_[0]|")
-			or die("ERROR: cannot start gunzip to uncompress ".
-			       "file $_[0]!\n");
-	}
-	else
-	{
-		# Open uncompressed file
-		open(INFO_HANDLE, $_[0])
-			or die("ERROR: cannot read file $_[0]!\n");
-	}
-
-	$testname = "";
-	while (<INFO_HANDLE>)
-	{
-		chomp($_);
-		$line = $_;
-
-		# Switch statement
-		foreach ($line)
-		{
-			/^TN:(\w+)/ && do
-			{
-				# Test name information found
-				$testname = $1;
-				last;
-			};
-
-			/^[SK]F:(.*)/ && do
-			{
-				# Filename information found
-				# Retrieve data for new entry
-				$filename = $1;
-
-				$data = $result{$filename};
-				($testdata, $sumcount, $funcdata) =
-					get_info_entry($data);
-
-				if (defined($testname))
-				{
-					$testcount = $testdata->{$testname};
-				}
-				else
-				{
-					my %new_hash;
-					$testcount = \%new_hash;
-				}
-				last;
-			};
-
-			/^DA:(\d+),(-?\d+)/ && do
-			{
-				# Fix negative counts
-				$count = $2 < 0 ? 0 : $2;
-				if ($2 < 0)
-				{
-					$negative = 1;
-				}
-				# Execution count found, add to structure
-				# Add summary counts
-				$sumcount->{$1} += $count;
-
-				# Add test-specific counts
-				if (defined($testname))
-				{
-					$testcount->{$1} += $count;
-				}
-				last;
-			};
-
-			/^FN:(\d+),([^,]+)/ && do
-			{
-				# Function data found, add to structure
-				$funcdata->{$1} = $2;
-				last;
-			};
-
-			/^end_of_record/ && do
-			{
-				# Found end of section marker
-				if ($filename)
-				{
-					# Store current section data
-					if (defined($testname))
-					{
-						$testdata->{$testname} =
-							$testcount;
-					}
-					set_info_entry($data, $testdata,
-						       $sumcount, $funcdata);
-					$result{$filename} = $data;
-				}
-
-			};
-
-			# default
-			last;
-		}
-	}
-	close(INFO_HANDLE);
-
-	# Calculate lines_found and lines_hit for each file
-	foreach $filename (keys(%result))
-	{
-		$data = $result{$filename};
-
-		($testdata, $sumcount, $funcdata) = get_info_entry($data);
-
-		$data->{"found"} = scalar(keys(%{$sumcount}));
-		$hitcount = 0;
-
-		foreach (keys(%{$sumcount}))
-		{
-			if ($sumcount->{$_} >0) { $hitcount++; }
-		}
-
-		$data->{"hit"} = $hitcount;
-
-		$result{$filename} = $data;
-	}
-
-	if (scalar(keys(%result)) == 0)
-	{
-		die("ERROR: No valid records found in tracefile $tracefile\n");
-	}
-	if ($negative)
-	{
-		warn("WARNING: Negative counts found in tracefile ".
-		     "$tracefile\n");
-	}
-
-	return(\%result);
-}
-
-
-#
-# get_info_entry(hash_ref)
-#
-# Retrieve data from an entry of the structure generated by read_info_file().
-# Return a list of references to hashes:
-# (test data hash ref, sum count hash ref, funcdata hash ref, lines found,
-#  lines hit)
-#
-
-sub get_info_entry($)
-{
-	my $testdata_ref = $_[0]->{"test"};
-	my $sumcount_ref = $_[0]->{"sum"};
-	my $funcdata_ref = $_[0]->{"func"};
-	my $lines_found  = $_[0]->{"found"};
-	my $lines_hit    = $_[0]->{"hit"};
-
-	return ($testdata_ref, $sumcount_ref, $funcdata_ref, $lines_found,
-	        $lines_hit);
-}
-
-
-#
-# set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref[,
-#                lines_found, lines_hit])
-#
-# Update the hash referenced by HASH_REF with the provided data references.
-#
-
-sub set_info_entry($$$$;$$)
-{
-	my $data_ref = $_[0];
-
-	$data_ref->{"test"} = $_[1];
-	$data_ref->{"sum"} = $_[2];
-	$data_ref->{"func"} = $_[3];
-
-	if (defined($_[4])) { $data_ref->{"found"} = $_[4]; }
-	if (defined($_[5])) { $data_ref->{"hit"} = $_[5]; }
-}
-
-
-#
-# get_prefix(filename_list)
-#
-# Search FILENAME_LIST for a directory prefix which is common to as many
-# list entries as possible, so that removing this prefix will minimize the
-# sum of the lengths of all resulting shortened filenames.
-#
-
-sub get_prefix(@)
-{
-	my @filename_list = @_;		# provided list of filenames
-	my %prefix;			# mapping: prefix -> sum of lengths
-	my $current;			# Temporary iteration variable
-
-	# Find list of prefixes
-	foreach (@filename_list)
-	{
-		# Need explicit assignment to get a copy of $_ so that
-		# shortening the contained prefix does not affect the list
-		$current = shorten_prefix($_);
-		while ($current = shorten_prefix($current))
-		{
-			# Skip rest if the remaining prefix has already been
-			# added to hash
-			if ($prefix{$current}) { last; }
-
-			# Initialize with 0
-			$prefix{$current}="0";
-		}
-
-	}
-
-	# Calculate sum of lengths for all prefixes
-	foreach $current (keys(%prefix))
-	{
-		foreach (@filename_list)
-		{
-			# Add original length
-			$prefix{$current} += length($_);
-
-			# Check whether prefix matches
-			if (substr($_, 0, length($current)) eq $current)
-			{
-				# Subtract prefix length for this filename
-				$prefix{$current} -= length($current);
-			}
-		}
-	}
-
-	# Find and return prefix with minimal sum
-	$current = (keys(%prefix))[0];
-
-	foreach (keys(%prefix))
-	{
-		if ($prefix{$_} < $prefix{$current})
-		{
-			$current = $_;
-		}
-	}
-
-	return($current);
-}
-
-
-#
-# shorten_prefix(prefix)
-#
-# Return PREFIX shortened by last directory component.
-#
-
-sub shorten_prefix($)
-{
-	my @list = split("/", $_[0]);
-
-	pop(@list);
-	return join("/", @list);
-}
-
-
-
-#
-# get_dir_list(filename_list)
-#
-# Return sorted list of directories for each entry in given FILENAME_LIST.
-#
-
-sub get_dir_list(@)
-{
-	my %result;
-
-	foreach (@_)
-	{
-		$result{shorten_prefix($_)} = "";
-	}
-
-	return(sort(keys(%result)));
-}
-
-
-#
-# get_relative_base_path(subdirectory)
-#
-# Return a relative path string which references the base path when applied
-# in SUBDIRECTORY.
-#
-# Example: get_relative_base_path("fs/mm") -> "../../"
-#
-
-sub get_relative_base_path($)
-{
-	my $result = "";
-	my $index;
-
-	# Make an empty directory path a special case
-	if (!$_[0]) { return(""); }
-
-	# Count number of /s in path
-	$index = ($_[0] =~ s/\//\//g);
-
-	# Add a ../ to $result for each / in the directory path + 1
-	for (; $index>=0; $index--)
-	{
-		$result .= "../";
-	}
-
-	return $result;
-}
-
-
-#
-# get_date_string()
-#
-# Return the current date in the form: yyyy-mm-dd
-#
-
-sub get_date_string()
-{
-	my $year;
-	my $month;
-	my $day;
-
-	($year, $month, $day) = (localtime())[5, 4, 3];
-
-	return sprintf("%d-%02d-%02d", $year+1900, $month+1, $day);
-}
-
-
-#
-# split_filename(filename)
-#
-# Return (path, filename, extension) for a given FILENAME.
-#
-
-sub split_filename($)
-{
-	if (!$_[0]) { return(); }
-	my @path_components = split('/', $_[0]);
-	my @file_components = split('\.', pop(@path_components));
-	my $extension = pop(@file_components);
-
-	return (join("/",@path_components), join(".",@file_components),
-		$extension);
-}
-
-
-#
-# write_file_table(filehandle, base_dir, overview, testhash, fileview)
-#
-# Write a complete file table. OVERVIEW is a reference to a hash containing
-# the following mapping:
-#
-#   filename -> "lines_found,lines_hit,page_link"
-#
-# TESTHASH is a reference to the following hash:
-#
-#   filename -> \%testdata
-#   %testdata: name of test affecting this file -> \%testcount
-#   %testcount: line number -> execution count for a single test
-#
-# Heading of first column is "Filename" if FILEVIEW is true, "Directory name"
-# otherwise.
-#
-
-sub write_file_table(*$$$$)
-{
-	my $dir = $_[0];
-	my $base_dir = $_[1];
-	my %overview = %{$_[2]};
-	my %testhash = %{$_[3]};
-	my $fileview = $_[4];
-	my $filename;
-	my $hit;
-	my $found;
-	my $classification;
-	my $rate_string;
-	my $rate;
-	my $junk;
-
-
-	foreach $filename (sort(keys(%overview)))
-	{
-		($found, $hit, $junk) = split(",", $overview{$filename});
-#James I think this is right
-		$rate = $hit * 100 / $found;
-		$rate_string = sprintf("%.1f", $rate);
-
-		if ($rate < 0.001)			{ $classification = "None"; }
-		elsif ($rate < $med_limit)	{ $classification = "Lo"; }
-		elsif ($rate < $hi_limit)	{ $classification = "Med"; }
-		else				{ $classification = "Hi"; }
-
-		print "$dir/$filename\t$classification\t$rate_string\n";
-
-	}
-}
-
-
-#
-# info(printf_parameter)
-#
-# Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag
-# is not set.
-#
-
-sub info(@)
-{
-	if (!$quiet)
-	{
-		# Print info string
-		printf(STDERR @_);
-	}
-}
-
-
-#
-# subtract_counts(data_ref, base_ref)
-#
-
-sub subtract_counts($$)
-{
-	my %data = %{$_[0]};
-	my %base = %{$_[1]};
-	my $line;
-	my $data_count;
-	my $base_count;
-	my $hit = 0;
-	my $found = 0;
-
-	foreach $line (keys(%data))
-	{
-		$found++;
-		$data_count = $data{$line};
-		$base_count = $base{$line};
-
-		if (defined($base_count))
-		{
-			$data_count -= $base_count;
-
-			# Make sure we don't get negative numbers
-			if ($data_count<0) { $data_count = 0; }
-		}
-
-		$data{$line} = $data_count;
-		if ($data_count > 0) { $hit++; }
-	}
-
-	return (\%data, $found, $hit);
-}
-
-
-#
-# add_counts(data1_ref, data2_ref)
-#
-# DATA1_REF and DATA2_REF are references to hashes containing a mapping
-#
-#   line number -> execution count
-#
-# Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF
-# is a reference to a hash containing the combined mapping in which
-# execution counts are added.
-#
-
-sub add_counts($$)
-{
-	my %data1 = %{$_[0]};	# Hash 1
-	my %data2 = %{$_[1]};	# Hash 2
-	my %result;		# Resulting hash
-	my $line;		# Current line iteration scalar
-	my $data1_count;	# Count of line in hash1
-	my $data2_count;	# Count of line in hash2
-	my $found = 0;		# Total number of lines found
-	my $hit = 0;		# Number of lines with a count > 0
-
-	foreach $line (keys(%data1))
-	{
-		$data1_count = $data1{$line};
-		$data2_count = $data2{$line};
-
-		# Add counts if present in both hashes
-		if (defined($data2_count)) { $data1_count += $data2_count; }
-
-		# Store sum in %result
-		$result{$line} = $data1_count;
-
-		$found++;
-		if ($data1_count > 0) { $hit++; }
-	}
-
-	# Add lines unique to data2
-	foreach $line (keys(%data2))
-	{
-		# Skip lines already in data1
-		if (defined($data1{$line})) { next; }
-
-		# Copy count from data2
-		$result{$line} = $data2{$line};
-
-		$found++;
-		if ($result{$line} > 0) { $hit++; }
-	}
-
-	return (\%result, $found, $hit);
-}
-
-
-#
-# apply_baseline(data_ref, baseline_ref)
-#
-# Subtract the execution counts found in the baseline hash referenced by
-# BASELINE_REF from actual data in DATA_REF.
-#
-
-sub apply_baseline($$)
-{
-	my %data_hash = %{$_[0]};
-	my %base_hash = %{$_[1]};
-	my $filename;
-	my $testname;
-	my $data;
-	my $data_testdata;
-	my $data_funcdata;
-	my $data_count;
-	my $base;
-	my $base_testdata;
-	my $base_count;
-	my $sumcount;
-	my $found;
-	my $hit;
-
-	foreach $filename (keys(%data_hash))
-	{
-		# Get data set for data and baseline
-		$data = $data_hash{$filename};
-		$base = $base_hash{$filename};
-
-		# Get set entries for data and baseline
-		($data_testdata, undef, $data_funcdata) =
-			get_info_entry($data);
-		($base_testdata, $base_count) = get_info_entry($base);
-
-		# Sumcount has to be calculated anew
-		$sumcount = {};
-
-		# For each test case, subtract test specific counts
-		foreach $testname (keys(%{$data_testdata}))
-		{
-			# Get counts of both data and baseline
-			$data_count = $data_testdata->{$testname};
-
-			$hit = 0;
-
-			($data_count, undef, $hit) =
-				subtract_counts($data_count, $base_count);
-
-			# Check whether this test case did hit any line at all
-			if ($hit > 0)
-			{
-				# Write back resulting hash
-				$data_testdata->{$testname} = $data_count;
-			}
-			else
-			{
-				# Delete test case which did not impact this
-				# file
-				delete($data_testdata->{$testname});
-			}
-
-			# Add counts to sum of counts
-			($sumcount, $found, $hit) =
-				add_counts($sumcount, $data_count);
-		}
-
-		# Write back resulting entry
-		set_info_entry($data, $data_testdata, $sumcount,
-			       $data_funcdata, $found, $hit);
-
-		$data_hash{$filename} = $data;
-	}
-
-	return (\%data_hash);
-}
-
-
-#
-# combine_info_entries(entry_ref1, entry_ref2)
-#
-# Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2.
-# Return reference to resulting hash.
-#
-
-sub combine_info_entries($$)
-{
-	my $entry1 = $_[0];	# Reference to hash containing first entry
-	my $testdata1;
-	my $sumcount1;
-	my $funcdata1;
-
-	my $entry2 = $_[1];	# Reference to hash containing second entry
-	my $testdata2;
-	my $sumcount2;
-	my $funcdata2;
-
-	my %result;		# Hash containing combined entry
-	my %result_testdata;
-	my $result_sumcount = {};
-	my %result_funcdata;
-	my $lines_found;
-	my $lines_hit;
-
-	my $testname;
-
-	# Retrieve data
-	($testdata1, $sumcount1, $funcdata1) = get_info_entry($entry1);
-	($testdata2, $sumcount2, $funcdata2) = get_info_entry($entry2);
-
-	# Combine funcdata
-	foreach (keys(%{$funcdata1}))
-	{
-		$result_funcdata{$_} = $funcdata1->{$_};
-	}
-
-	foreach (keys(%{$funcdata2}))
-	{
-		$result_funcdata{$_} = $funcdata2->{$_};
-	}
-	
-	# Combine testdata
-	foreach $testname (keys(%{$testdata1}))
-	{
-		if (defined($testdata2->{$testname}))
-		{
-			# testname is present in both entries, requires
-			# combination
-			($result_testdata{$testname}) =
-				add_counts($testdata1->{$testname},
-					   $testdata2->{$testname});
-		}
-		else
-		{
-			# testname only present in entry1, add to result
-			$result_testdata{$testname} = $testdata1->{$testname};
-		}
-
-		# update sum count hash
-		($result_sumcount, $lines_found, $lines_hit) =
-			add_counts($result_sumcount,
-				   $result_testdata{$testname});
-	}
-
-	foreach $testname (keys(%{$testdata2}))
-	{
-		# Skip testnames already covered by previous iteration
-		if (defined($testdata1->{$testname})) { next; }
-
-		# testname only present in entry2, add to result hash
-		$result_testdata{$testname} = $testdata2->{$testname};
-
-		# update sum count hash
-		($result_sumcount, $lines_found, $lines_hit) =
-			add_counts($result_sumcount,
-				   $result_testdata{$testname});
-	}
-	
-	# Calculate resulting sumcount
-
-	# Store result
-	set_info_entry(\%result, \%result_testdata, $result_sumcount,
-		       \%result_funcdata, $lines_found, $lines_hit);
-
-	return(\%result);
-}
-
-
-#
-# combine_info_files(info_ref1, info_ref2)
-#
-# Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return
-# reference to resulting hash.
-#
-
-sub combine_info_files($$)
-{
-	my %hash1 = %{$_[0]};
-	my %hash2 = %{$_[1]};
-	my $filename;
-
-	foreach $filename (keys(%hash2))
-	{
-		if ($hash1{$filename})
-		{
-			# Entry already exists in hash1, combine them
-			$hash1{$filename} =
-				combine_info_entries($hash1{$filename},
-						     $hash2{$filename});
-		}
-		else
-		{
-			# Entry is unique in both hashes, simply add to
-			# resulting hash
-			$hash1{$filename} = $hash2{$filename};
-		}
-	}
-
-	return(\%hash1);
-}
-
-
-#
-# apply_prefix(filename, prefix)
-#
-# If FILENAME begins with PREFIX, remove PREFIX from FILENAME and return
-# resulting string, otherwise return FILENAME.
-#
-
-sub apply_prefix($$)
-{
-	my $filename = $_[0];
-	my $prefix = $_[1];
-	my $clean_prefix = escape_regexp($prefix);
-
-	if (defined($prefix) && ($prefix ne ""))
-	{
-		if ($filename =~ /^$clean_prefix\/(.*)$/)
-		{
-			return substr($filename, length($prefix) + 1);
-		}
-	}
-
-	return $filename;
-}
-
-
-#
-# escape_regexp(string)
-#
-# Escape special characters in STRING which would be incorrectly interpreted
-# in a PERL regular expression.
-#
-
-sub escape_regexp($)
-{
-	my $string = $_[0];
-	
-	# Escape special characters
-	$string =~ s/\\/\\\\/g;
-	$string =~ s/\^/\\\^/g;
-	$string =~ s/\$/\\\$/g;
-	$string =~ s/\./\\\./g;
-	$string =~ s/\|/\\\|/g;
-	$string =~ s/\(/\\\(/g;
-	$string =~ s/\)/\\\)/g;
-	$string =~ s/\[/\\\[/g;
-	$string =~ s/\]/\\\]/g;
-	$string =~ s/\*/\\\*/g;
-	$string =~ s/\?/\\\?/g;
-	$string =~ s/\{/\\\{/g;
-	$string =~ s/\}/\\\}/g;
-	$string =~ s/\+/\\\+/g;
-
-	return $string;
-}
diff --git a/third_party/lcov-1.9/contrib/galaxy/posterize.pl b/third_party/lcov-1.9/contrib/galaxy/posterize.pl
deleted file mode 100755
index 1b2895e..0000000
--- a/third_party/lcov-1.9/contrib/galaxy/posterize.pl
+++ /dev/null
@@ -1,312 +0,0 @@
-#!/usr/bin/perl
-#
-#   Copyright (c) International Business Machines  Corp., 2002
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
-#
-# posterize.pl
-#
-#   This script generates a postscript file from output generated from the
-#   fcgp http://sourceforge.net/projects/fcgp/ for plotting
-#
-#
-# History:
-#   2003-09-04 wrote - James M Kenefick Jr. <jkenefic@us.ibm.com>
-#
-
-
-
-# a good deal of this could be turned in to cli
-# arguments.
-
-# Constants
-my $Title = "Linux Kernel Coverage";
-my $KernelVersion = "2.5.73";
-my $TestDescription = "A Sample Print";
-my $Image = "../lgp/image.ps";
-
-# Variables
-my $Bounds = "";
-# Paper sizes in inches
-my $PAPER_WIDTH = 34;
-my $PAPER_HEIGHT = 42;
-
-# points per inch 
-my $ppi = 72;
-
-# Margins 
-my $TopMargin = 1;
-my $BottomMargin = 1.5;
-my $LeftMargin = 1;
-my $RightMargin = 1;
-
-
-$RightMargin = $PAPER_WIDTH - $RightMargin;
-$TopMargin = $PAPER_HEIGHT - $TopMargin;
-
-my $filename = "poster.ps";
-
-# Sizes in ppi
-my $PPI_WIDTH = ($PAPER_WIDTH * $ppi);
-my $PPI_HEIGHT = ($PAPER_HEIGHT * $ppi);
-
-# Date we create poster
-my $date = `date`;
-
-print STDERR "Creating Poster\n";
-
-open POSTER, ">$filename";
-
-
-
-print(POSTER <<END_OF_USAGE);
-%!PS-Adobe-1.0
-%%DocumentFonts: Helvetica Helvetica-Bold
-%%Title: Linux 2.4.0 Kernel Poster
-%%Creator: Rusty's scripts and postersize (GPL)
-%%CreationDate: $date 
-%%Pages: 1
-%%BoundingBox: 0 0 $PPI_WIDTH $PPI_HEIGHT
-%%EndComments
-%!
-/PRorig_showpage_x178313 /showpage load def /showpage{
-                                              errordict /handleerror {} put
-                                             }def
-/initgraphics{}def/setpagedevice{pop}def
-statusdict begin /a4tray{}def /lettertray{}def end
-/a4{}def/a3{}def/a0{}def/letter{}def/legal{}def
-/a4small{}def /lettersmall{}def /a4tray{}def /lettertray{}def
-/setscreen{pop pop pop}def
-/ColorManagement {pop} def
-
-
-/A {gsave newpath 0 360 arc stroke grestore} bind def
-/M {moveto} bind def
-/L {lineto} bind def
-/D {[] 0 setdash} bind def
-/D5 {[5] 0 setdash} bind def
-/C0 {0 0 0 setrgbcolor} bind def
-/C1 {.8 .4 .4 setrgbcolor} bind def
-/C2 {.5 1 .5 setrgbcolor} bind def
-/C3 {0 .7 0 setrgbcolor} bind def
-/C4 {1 0 0 setrgbcolor} bind def
-/C5 {0 0 1 setrgbcolor} bind def
-/R {grestore} bind def
-/S {0 0 M stroke} bind def
-/T {gsave translate} bind def
-/U {C0 newpath 4 copy 4 2 roll 8 7 roll M L L L closepath stroke
-C1 findfont exch scalefont setfont M show} bind def
-
-% Added James M Kenefick Jr.
-/Hi_Color {0 0 1} def
-/Med_Color {0 .60 1}  def
-/Lo_Color {0 1 1} def
-/None_Color {.75 .75 .75} def
-/Hi {newpath 4 copy 4 2 roll 8 7 roll M L L L Hi_Color setrgbcolor fill closepath} bind def
-/Med {newpath 4 copy 4 2 roll 8 7 roll M L L L Med_Color setrgbcolor fill closepath} bind def
-/Lo {newpath 4 copy 4 2 roll 8 7 roll M L L L Lo_Color setrgbcolor fill closepath} bind def
-/None {newpath 4 copy 4 2 roll 8 7 roll M L L L None_Color setrgbcolor fill closepath} bind def
-
-/inch
-{
-	72 mul
-}
-def
-
-/LeftMargin $LeftMargin inch def
-/RightMargin $RightMargin inch def
-/TopMargin $TopMargin inch def
-/BottomMargin $BottomMargin inch def
-/FontScale 25 def
-/AuthorFontScale 70 def
-
-/centerText
-{
-	dup
-	stringwidth pop
-	2 div
-	RightMargin LeftMargin sub 2 div
-	exch sub
-	LeftMargin add
-	NextLine moveto
-	show	
-}
-def
-
-/upLine
-{
-	/NextLine 
-	NextLine LineSpace2 add
-	def
-}
-def
-
-/advanceLine
-{
-	/NextLine
-	NextLine LineSpace sub
-	def
-}
-def
-
-/fontScale
-{
-	TopMargin BottomMargin sub FontScale div
-}
-def
-
-/authorfontScale
-{
-	TopMargin BottomMargin sub AuthorFontScale div
-}
-def
-
-/rightJustify
-{
-	dup
-	stringwidth pop
-	RightMargin 1 inch sub
-	exch sub
-	NextLine moveto
-	show
-}
-def
-
-/usableY
-{
-	TopMargin LineSpace 3 mul sub BottomMargin sub	
-}
-def
-
-/usableX
-{
-	RightMargin LeftMargin sub	
-}
-def
-gsave
-/Times-Roman findfont fontScale scalefont setfont
-/LineSpace fontScale def
-/NextLine (B) stringwidth pop TopMargin exch sub def 
-
-%%EndProlog
-%%Page 1
-% title
-
-($Title) centerText advanceLine
-(Kernel: $KernelVersion) centerText advanceLine
-($TestDescription) centerText
-
-% Author Block
-LeftMargin BottomMargin translate
-/Times-Roman findfont authorfontScale scalefont setfont
-/LineSpace2 authorfontScale def
-/NextLine 0 def
-(Based on work by Rusty Russell, Christian Reiniger) rightJustify
-upLine
-(By James M. Kenefick Jr.) rightJustify
-
-grestore
-LeftMargin BottomMargin translate
-
-% Key Block
-15 15 scale
-% This is the key for the graph.
-
-/box { newpath moveto 0 1 rlineto 2 0 rlineto 0 -1 rlineto closepath } def
-/key { setrgbcolor 2 copy box gsave fill grestore 0 0 0 setrgbcolor strokepath fill moveto 2.4 0.25 rmoveto show } def
-
-/Helvetica-Oblique findfont
-1 scalefont setfont
-0.1 setlinewidth
-
-(static functions) 1 5 0.5 1 0.5 key % Light green.
-(indirectly called functions) 1 7 0 0.7 0 key % green
-(exported functions) 1 9 1 0 0 key % red
-(other functions) 1 11 0 0 1 key % blue
-
-(Low Coverage) 1 15 Lo_Color key % blue
-(Medium Coverage) 1 17 Med_Color key % blue
-(Hi Coverage) 1 19 Hi_Color key % blue
-(No Coverage) 1 21 None_Color key % blue
-1 3.25 moveto
-0.8 0.4 0.4 setrgbcolor
-/Helvetica findfont
-1 scalefont setfont
-(xxx) show
-1 3 moveto
-2.4 0.25 rmoveto
-0 0 0 setrgbcolor
-/Helvetica-Oblique findfont
-1 scalefont setfont
-(function name) show
-
-1 1.25 moveto
-0.8 0.4 0.4 setrgbcolor
-/Helvetica-Bold findfont
-1 scalefont setfont
-(xxx) show
-1 1 moveto
-2.4 0.25 rmoveto
-0 0 0 setrgbcolor
-/Helvetica-Oblique findfont
-1 scalefont setfont
-(source filename) show
-
-6 24 moveto
-/Helvetica-Bold findfont
-2 scalefont setfont
-(Key) show
-
-% Box around it
-newpath
-0.2 0.2 moveto
-0.2 27 lineto
-17 27 lineto
-17 0.2 lineto
-closepath
-strokepath fill
-
-
-1 15 div 1 15 div scale
-
-% find and move to center 
-END_OF_USAGE
-
-# Find the bounds for the image
-
-$Bounds = `tail -1 $Image`;
-($Junk, $Junk, $minX, $minY, $maxX, $maxY) = split / /, $Bounds;
-
-my $xRange = $maxX - $minX;
-my $yRange = $maxY - $minY;
-
-if ($xRange < $yRange){
-	$Range = $xRange;
-} else {
-	$Range = $yRange;
-}
-print POSTER " 0 usableY usableX sub 2 div translate\n";
-print POSTER "usableX $Range div usableX $Range div scale\n";
-print POSTER "$Range 2 div $Range 2 div translate\n";
-print POSTER "gsave\n";
-# Paste in actual image.
-print POSTER `cat /home/lgp/image.ps`;
-print POSTER "%%Trailer\n";
-print POSTER "grestore\n";
-print POSTER "showpage\n";
-print POSTER "PRorig_showpage_x178313\n";
-print POSTER "/showpage /PRorig_showpage_x178313 load def\n";
-
diff --git a/third_party/lcov-1.9/descriptions.tests b/third_party/lcov-1.9/descriptions.tests
deleted file mode 100644
index b91fe39..0000000
--- a/third_party/lcov-1.9/descriptions.tests
+++ /dev/null
@@ -1,2990 +0,0 @@
-personality01  
-	Check that we can set the personality for a process.
-personality02  
-	Check that we get EINVAL for a bad personality.
-exit01  
-	Check that exit returns the correct values to the waiting parent
-exit02  
-	Check that exit flushes output file buffers and closes files upon
-	exiting
-wait02
-	Basic test for wait(2) system call. 
-wait401  
-	check that a call to wait4() correctly waits for a child
-	process to exit
-wait402  
-	check for ECHILD errno when using an illegal pid value
-
-waitpid01  
-	Check that when a child kills itself by generating an alarm
-	exception, the waiting parent is correctly notified.
-waitpid02  
-	Check that when a child kills itself by generating an integer zero
-	divide exception, the waiting parent is correctly notified.
-waitpid03  
-	Check that parent waits until specific child has returned.
-waitpid04  
-	test to check the error conditions in waitpid sys call
-waitpid05  
-	Check that when a child kills itself with a kill statement after
-	determining its process id by using getpid, the parent receives a
-	correct report of the cause of its death. This also indirectly
-	checks that getpid returns the correct process id.
-waitpid06  
-	Tests to see if pid's returned from fork and waitpid are same.
-waitpid07  
-	Tests to see if pid's returned from fork and waitpid are same.
-waitpid08  
-	Tests to see if pid's returned from fork and waitpid are same
-waitpid09  
-	Check ability of parent to wait until child returns, and that the
-	child's process id is returned through the waitpid. Check that
-	waitpid returns immediately if no child is present.
-waitpid10  
-	Tests to see if pid's returned from fork and waitpid are same
-waitpid11  
-	Tests to see if pid's returned from fork and waitpid are same
-waitpid12  
-	Tests to see if pid's returned from fork and waitpid are same
-waitpid13  
-	Tests to see if pid's returned from fork and waitpid are same
-fcntl01  
-	Test F_DUPFD, F_SETFL cmds of fcntl
-fcntl02
-	Basic test for fcntl(2) using F_DUPFD argument.
-fcntl03
-	Basic test for fcntl(2) using F_GETFD argument.
-fcntl04
-	Basic test for fcntl(2) using F_GETFL argument. 
-fcntl05
-	Basic test for fcntl(2) using F_GETLK argument. 
-fcntl06  
-	Error checking conditions for remote locking of regions of a file.
-fcntl07
-	Close-On-Exec functional test. 
-fcntl07B
-	Close-On-Exec of named pipe functional test. 
-fcntl08
-	Basic test for fcntl(2) using F_SETFL argument. 
-fcntl09
-	Basic test for fcntl(2) using F_SETLK argument. 
-fcntl10
-	Basic test for fcntl(2) using F_SETLKW argument. 
-fcntl11  
-	Testcase to check locking of regions of a file
-
-fcntl12  
-
-	Testcase to test that fcntl() sets EMFILE for F_DUPFD command.
-
-fcntl13  
-
-	Testcase to test that fcntl() sets errno correctly.
-
-fcntl14  
-
-	File locking test cases for fcntl. In Linux, S_ENFMT is not implemented
-	in the kernel. However all standard Unix kernels define S_ENFMT as
-	S_ISGID. So this test defines S_ENFMT as S_ISGID.
-
-fcntl15  
-
-	Check that file locks are removed when file closed
-
-fcntl16  
-
-	Additional file locking test cases for checking proper notification
-	of processes on lock change
-
-fcntl17  
-
-	Check deadlock detection for file locking
-
-fcntl18  
-
-	Test to check the error conditions in fcntl system call
-
-fcntl19  
-
-	Testcase to check locking of regions of a file
-
-fcntl20  
-
-	Check locking of regions of a file
-
-fcntl21  
-
-	Check locking of regions of a file
-
-dup01		
-
-	Basic test for dup(2).
-
-dup02		 	
-
-	Negative test for dup(2) with bad fd.
-
-dup03
-
-	Negative test for dup(2) (too many fds).
-
-dup04
-
-	Basic test for dup(2) of a system pipe descriptor.
-
-dup05
-
-	Basic test for dup(2) of a named pipe descriptor. 
-
-dup201  
-
-	Negative tests for dup2() with bad fd (EBADF), and for "too many
-	open files" (EMFILE)
-
-dup202  
-
-	Is the access mode the same for both file descriptors?
-	0: read only ?	"0444"
-	1: write only ? "0222"
-	2: read/write ? "0666"
-
-dup203  
-
-	Testcase to check the basic functionality of dup2().
-
-dup204  
-
-	Testcase to check the basic functionality of dup2(2).
-
-
-msync01  
-
-	Verify that, msync() succeeds, when the region to synchronize, is part
-	of, or all of a mapped region.
-
-msync02  
-
-	Verify that msync() succeeds when the region to synchronize is mapped
-	shared and the flags argument is MS_INVALIDATE.
-
-msync03  
-
-	Verify that, msync() fails, when the region to synchronize, is outside
-	the address space of the process.
-
-msync04  
-
-	Verify that, msync() fails, when the region to synchronize, is mapped
-	but the flags argument is invalid.
-
-msync05  
-
-	Verify that, msync() fails, when the region to synchronize, was not
-	mapped.
-
-
-sendfile02  
-
-	Testcase to test the basic functionality of the sendfile(2) system call.
-
-sendfile03  
-
-	Testcase to test that sendfile(2) system call returns appropriate
-	errnos on error.
-
-fork01
-	Basic test for fork(2). 
-fork02  
-	Test correct operation of fork:
-	pid == 0 in child;
-	pid > 0 in parent from wait;
-fork03  
-	Check that child can use a large text space and do a large
-	number of operations.	
-fork04
-	Child inheritance of Environment Variables after fork(). 
-fork05
-	Make sure LDT is propagated correctly 
-fork06  
-	Test that a process can fork children a large number of
-	times in succession
-fork07  
-	Check that all children inherit parent's file descriptor
-fork08  
-	Check if the parent's file descriptors are affected by 
-	actions in the child; they should not be.
-fork09  
-	Check that child has access to a full set of files.
-fork10  
-	Check inheritance of file descriptor by children, they
-	should all be referring to the same file.
-fork11  
-	Test that parent gets a pid from each child when doing wait
-vfork01  
-	Fork a process using vfork() and verify that, the attribute values like
-	euid, ruid, suid, egid, rgid, sgid, umask, inode and device number of
-	root and current working directories are same as that of the parent 
-	process.
-vfork02  
-	Fork a process using vfork() and verify that, the pending signals in
-	the parent are not pending in the child process.
-ioctl01  
-
-	Testcase to check the errnos set by the ioctl(2) system call.
-
-ioctl02  
-
-	Testcase to test the TCGETA, and TCSETA ioctl implementations for
-	the tty driver
-
-sockioctl01  
-
-	Verify that ioctl() on sockets returns the proper errno for various
-	failure cases
-
-getitimer01
-	check that a correct call to getitimer() succeeds
-
-
-getitimer02
-	check that a getitimer() call fails as expected
-	with an incorrect second argument.
-
-getitimer03
-	check that a getitimer() call fails as expected
-	with an incorrect first argument.
-
-setitimer01
-	check that a reasonable setitimer() call succeeds.
-
-
-setitimer02
-	check that a setitimer() call fails as expected
-	with incorrect values.
-
-setitimer03
-	check that a setitimer() call fails as expected
-	with incorrect values.
-
-float_trigo
-	increase CPUs workload - verify that results of some math functions are stable
-	trigonometric (acos, asin, atan, atan2, cos, sin, tan),
-	hyperbolic (cosh, sinh, tanh),
-
-float_exp_log
-	increase CPUs workload - verify that results of some math functions are stable
-	exponential and logarithmic functions (exp, log, log10),
-	Functions that manipulate floating-point numbers (modf, ldexp, frexp),
-	Euclidean distance function (hypot),
-
-float_bessel
-	increase CPUs workload - verify that results of some math functions are stable
-	Bessel (j0, j1, y0, y1),
-	Computes the natural logarithm of the gamma function (lgamma),
-
-fload_power
-	increase CPUs workload - verify that results of some math functions are stable
-	Computes sqrt, power, fmod
-
-float_iperb
-	increase CPUs workload - verify that results of some math functions are stable
-pth_str01
-
-	Creates a tree of threads
-
-pth_str02
-
-	Creates n threads
-
-pth_str03
-
-	Creates a tree of threads does calculations, and
-	returns result to parent
-
-
-asyncio02
-
-	Write/close flushes data to the file.
-
-
-fpathconf
-
-	Basic test for fpathconf(2)
-
-gethostid01
-
-	Basic test for gethostid(2) 
-
-
-pathconf01
-
-	Basic test for pathconf(2) 
-
-setpgrp01
-
-	Basic test for the setpgrp(2) system call.  
-
-setpgrp02  
-
-	Testcase to check the basic functionality of the setpgrp(2) syscall.
-
-
-ulimit01
-
-	Basic test for the ulimit(2) system call. 
-
-mmstress
-
-	Performs General Stress with Race conditions
-
-mmap1
-
-	Test the LINUX memory manager. The program is aimed at
-	stressing the memory manager by simultaneous map/unmap/read
-	by light weight processes, the test is scheduled to run for
-	a minimum of 24 hours.
-
-mmap2
-
-	Test the LINUX memory manager. The program is aimed at
-	stressing the memory manager by repeated map/write/unmap of a
-	of a large gb size file.
-
-mmap3
-
-	Test the LINUX memory manager. The program is aimed at
-	stressing the memory manager by repeated map/write/unmap
-	of file/memory of random size (maximum 1GB) this is done by
-	multiple processes.
-
-mmap001
-
-	Tests mmapping a big file and writing it once 
-
-mmap01  
-
-	Verify that, mmap() succeeds when used to map a file where size of the
-	file is not a multiple of the page size, the memory area beyond the end
-	of the file to the end of the page is accessible. Also, verify that
-	this area is all zeroed and the modifications done to this area are
-	not written to the file.
-
-mmap02  
-
-	Call mmap() with prot parameter set to PROT_READ and with the file
-	descriptor being open for read, to  map a file creating mapped memory
-	with read access. The minimum file permissions should be 0444.
-
-mmap03  
-
-	Call mmap() to map a file creating a mapped region with execute access
-	under the following conditions -
-	- The prot parameter is set to PROT_EXE
-	- The file descriptor is open for read
-	- The file being mapped has execute permission bit set.
-	- The minimum file permissions should be 0555.
-
-	The call should succeed to map the file creating mapped memory with the
-	required attributes.
-
-mmap04  
-
-	Call mmap() to map a file creating a mapped region with read/exec access
-	under the following conditions -
-	- The prot parameter is set to PROT_READ|PROT_EXEC
-	- The file descriptor is open for read
-	- The file being mapped has read and execute permission bit set.
-	- The minimum file permissions should be 0555.
-
-	The call should succeed to map the file creating mapped memory with the
-	required attributes.
-
-
-mmap05  
-
-	Call mmap() to map a file creating mapped memory with no access under
-	the following conditions -
-	- The prot parameter is set to PROT_NONE
-	- The file descriptor is open for read(any mode other than write)
-	- The minimum file permissions should be 0444.
-
-	The call should succeed to map the file creating mapped memory with the
-	required attributes.
-
-mmap06  
-
-	Call mmap() to map a file creating a mapped region with read access
-	under the following conditions -
-	- The prot parameter is set to PROT_READ
-	- The file descriptor is open for writing.
-
-	The call should fail to map the file.
-
-
-mmap07  
-
-	Call mmap() to map a file creating a mapped region with read access
-	under the following conditions -
-	- The prot parameter is set to PROT_WRITE
-	- The file descriptor is open for writing.
-	- The flags parameter has MAP_PRIVATE set.
-
-	The call should fail to map the file.
-
-mmap08  
-
-	Verify that mmap() fails to map a file creating a mapped region 
-	when the file specified by file descriptor is not valid.
-
-
-mremap01  
-
-	Verify that, mremap() succeeds when used to expand the existing
-	virtual memory mapped region to the requested size where the
-	virtual memory area was previously mapped to a file using mmap().
-
-mremap02  
-
-	Verify that, 
-	mremap() fails when used to expand the existing virtual memory mapped 
-	region to the requested size, if the virtual memory area previously 
-	mapped was not page aligned or invalid argument specified.
-
-mremap03  
-
-	Verify that, 
-	mremap() fails when used to expand the existing virtual memory mapped 
-	region to the requested size, if there already exists mappings that
-	cover the whole address space requested or the old address specified was
-	not mapped.
-
-mremap04  
-
-	Verify that, 
-	mremap() fails when used to expand the existing virtual memory mapped 
-	region to the requested size, if the memory area cannot be expanded at
-	the current virtual address and MREMAP_MAYMOVE flag not set.
-
-munmap01  
-
-	Verify that, munmap call will succeed to unmap a mapped file or
-	anonymous shared memory region from the calling process's address space
-	and after successful completion of munmap, the unmapped region is no
-	longer accessible.
-
-munmap02  
-
-	Verify that, munmap call will succeed to unmap a mapped file or
-	anonymous shared memory region from the calling process's address space
-	if the region specified by the address and the length is part or all of
-	the mapped region.
-
-munmap03  
-
-	Verify that, munmap call will fail to unmap a mapped file or anonymous
-	shared memory region from the calling process's address space if the
-	address and the length of the region to be unmapped points outside the
-	calling process's address space
-
-brk01
-	Test the basic functionality of brk.
-
-sbrk01
-	Basic test for the sbrk(2) system call.
-
-
-mprotect01  
-
-	Testcase to check the error conditions for mprotect(2)
-
-mprotect02  
-
-	Testcase to check the mprotect(2) system call.
-
-mprotect03  
-
-	Testcase to check the mprotect(2) system call.
-
-msgctl01 
-	create a message queue, then issue the IPC_STAT command
-	and RMID commands to test the functionality
-
-
-msgctl02 
-	create a message queue, then issue the IPC_SET command
-	to lower the msg_qbytes value.
-
-
-msgctl03
-	create a message queue, then issue the IPC_RMID command
-
-
-
-msgctl04 
-	test for EACCES, EFAULT and EINVAL errors using
-	a variety of incorrect calls.
-
-
-msgctl05 
-	test for EPERM error
-
-
-
-msgget01 
-	create a message queue, write a message to it and
-	read it back.
-
-
-msgget02 
-	test for EEXIST and ENOENT errors
-
-
-msgget03 
-	test for an ENOSPC error by using up all available
-	message queues.
-
-msgget04 
-	test for an EACCES error by creating a message queue
-	with no read or write permission and then attempting
-	to access it with various permissions.
-
-msgrcv01 
-	test that msgrcv() receives the expected message
-
-msgrcv02
-	test for EACCES and EFAULT errors
-
-msgrcv03
-	test for EINVAL error
-
-msgrcv04
-	test for E2BIG and ENOMSG errors
-
-msgrcv05
-	test for EINTR error
-
-msgrcv06
-	test for EIDRM error
-
-msgsnd01
-	test that msgsnd() enqueues a message correctly
-
-msgsnd02
-	test for EACCES and EFAULT errors
-
-msgsnd03
-	test for EINVAL error
-
-msgsnd04
-	test for EAGAIN error
-
-msgsnd05
-	test for EINTR error
-
-
-msgsnd06
-	test for EIDRM error
-
-link02
-
-	Basic test for link(2) 
-
-link03
-
-	Multi links tests
-
-link04
-
-	Negative test cases for link(2)
-
-link05
-
-	Multi links (EMLINK) negative test 
-
-readlink01  
-
-	Verify that, readlink will succeed to read the contents of the symbolic
-	link created the process.
-
-readlink02
-
-	Basic test for the readlink(2) system call 
-
-readlink03  
-
-	Verify that,
-	1) readlink(2) returns -1 and sets errno to EACCES if search/write
-	permission is denied in the directory where the symbolic link
-	resides.
-	2) readlink(2) returns -1 and sets errno to EINVAL if the buffer size
-	is not positive.
-	3) readlink(2) returns -1 and sets errno to EINVAL if the specified
-	file is not a symbolic link file.
-	4) readlink(2) returns -1 and sets errno to ENAMETOOLONG if the 
-	pathname component of symbolic link is too long (ie, > PATH_MAX).
-	5) readlink(2) returns -1 and sets errno to ENOENT if the component of
-	symbolic link points to an empty string.
-
-readlink04  
-
-	Verify that, readlink call will succeed to read the contents of the
-	symbolic link if invoked by non-root user who is not the owner of the
-	symbolic link.
-
-
-symlink01
-
-	Test of various file function calls, such as rename or open, on a symbolic 
-	link file. 
-
-symlink02
-
-	Basic test for the symlink(2) system call. 
-
-symlink03  
-
-	Verify that,
-	1) symlink(2) returns -1 and sets errno to EACCES if search/write
-	permission is denied in the directory where the symbolic link is
-	being created.
-	2) symlink(2) returns -1 and sets errno to EEXIST if the specified 
-	symbolic link already exists.
-	3) symlink(2) returns -1 and sets errno to EFAULT if the specified
-	file or symbolic link points to invalid address.
-	4) symlink(2) returns -1 and sets errno to ENAMETOOLONG if the 
-	pathname component of symbolic link is too long (ie, > PATH_MAX).
-	5) symlink(2) returns -1 and sets errno to ENOTDIR if the directory
-	component in pathname of symbolic link is not a directory.
-	6) symlink(2) returns -1 and sets errno to ENOENT if the component of
-	symbolic link points to an empty string.
-
-symlink04  
-
-	Verify that, symlink will succeed to create a symbolic link of an existing
-	object name path.
-
-
-symlink05  
-
-	Verify that, symlink will succeed to create a symbolic link of an
-	non-existing object name path.
-
-
-unlink05
-
-	Basic test for the unlink(2) system call. 
-
-unlink06
-
-	Test for the unlink(2) system call of a FIFO. 
-
-unlink07
-
-	Tests for error handling for the unlink(2) system call. 
-
-unlink08
-
-	More tests for error handling for the unlink(2) system call.
-
-
-linktest
-
-	Regression test for max links per file
-
-rename01  
-
-	This test will verify the rename(2) syscall basic functionality.
-	Verify rename() works when the "new" file or directory does not exist.
-
-rename02
-
-	Basic test for the rename(2) system call
-
-rename03  
-
-	This test will verify that rename(2) functions correctly
-	when the "new" file or directory exists
-
-rename04  
-
-	This test will verify that rename(2) failed when newpath is 
-	a non-empty directory and return EEXIST or ENOTEMPTY
-
-rename05  
-
-	This test will verify that rename(2) fails with EISDIR
-
-rename06  
-
-	This test will verify that rename(2) failed in EINVAL
-
-rename07  
-
-	This test will verify that rename(2) failed in ENOTDIR
-
-rename08  
-
-	This test will verify that rename(2) syscall failed in EFAULT
-
-rename09  
-
-	check rename() fails with EACCES
-
-rename10  
-
-	This test will verify that rename(2) syscall fails with ENAMETOOLONG
-	and ENOENT
-
-rename11  
-
-	This test will verify that rename(2) failed in EBUSY
-
-rename12  
-
-	check rename() fails with EPERM
-
-rename13  
-
-	Verify rename() return successfully and performs no other action
-	when "old" file and "new" file link to the same file.
-
-rmdir01  
-
-	This test will verify that rmdir(2) syscall basic functionality.
-	verify rmdir(2) returns a value of 0 and the directory being
-	removed 
-
-rmdir02  
-
-	This test will verify that rmdir(2) fail in 
-	1. ENOTEMPTY
-	2. EBUSY
-	3. ENAMETOOLONG
-	4. ENOENT
-	5. ENOTDIR
-	6. EFAULT
-	7. EFAULT
-
-rmdir03  
-
-	check rmdir() fails with EPERM or EACCES
-
-rmdir04
-
-	Basic test for the rmdir(2) system call 
-
-rmdir05
-
-	Verify that rmdir(2) returns a value of -1 and sets errno to indicate the error.
-
-
-
-mkdir01
-
-	Basic errno test for mkdir(2) 
-
-mkdir02  
-
-	This test will verify that new directory created
-	by mkdir(2) inherits the group ID from the parent
-	directory and S_ISGID bit, if the S_ISGID bit is set
-	in the parent directory.
-
-mkdir03  
-
-	Check mkdir() with various error conditions that should produce
-	EFAULT, ENAMETOOLONG, EEXIST, ENOENT and ENOTDIR
-
-mkdir04  
-
-	Attempt to create a directory in a directory having no permissions. 
-
-mkdir05  
-
-	This test will verify the mkdir(2) syscall basic functionality
-
-mkdir08
-
-	Basic test for mkdir(2)
-
-
-mknod01
-
-	Basic test for mknod(2) 
-
-mknod02  
-
-	Verify that mknod(2) succeeds when used to create a filesystem 
-	node with set group-ID bit set on a directory without set group-ID bit set.
-	The node created should have set group-ID bit set and its gid should be 
-	equal to that of its parent directory.
-
-mknod03  
-
-	Verify that mknod(2) succeeds when used to create a filesystem 
-	node with set group-ID bit set on a directory with set group-ID bit set.
-	The node created should have set group-ID bit set and its gid should be 
-	equal to the effective gid of the process.
-
-mknod04  
-
-	Verify that mknod(2) succeeds when used to create a filesystem 
-	node on a directory with set group-ID bit set.
-	The node created should not have group-ID bit set and its gid should be 
-	equal to the effective gid of the process.
-
-mknod05  
-
-	Verify that mknod(2) succeeds when used by root to create a filesystem 
-	node with set group-ID bit set on a directory with set group-ID bit set.
-	The node created should have set group-ID bit set and its gid should be 
-	equal to that of its parent directory.
-
-
-mknod06  
-
-	Verify that,
-	1) mknod(2) returns -1 and sets errno to EEXIST if specified path
-	already exists.
-	2) mknod(2) returns -1 and sets errno to EFAULT if pathname points
-	outside user's accessible address space.
-	3) mknod(2) returns -1 and sets errno to ENOENT if the directory 
-	component in pathname does not exist.
-	4) mknod(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
-	component was too long.
-	5) mknod(2) returns -1 and sets errno to ENOTDIR if the directory
-	component in pathname is not a directory.
-
-mknod07  
-
-	Verify that,
-	1) mknod(2) returns -1 and sets errno to EPERM if the process id of
-	the caller is not super-user.
-	2) mknod(2) returns -1 and sets errno to EACCES if parent directory
-	does not allow  write  permission  to  the process.
-
-mknod08  
-
-	Verify that mknod(2) succeeds when used to create a filesystem 
-	node on a directory without set group-ID bit set. The node created
-	should not have set group-ID bit set and its gid should be equal to that
-	of its parent directory.
-
-
-
-
-access01
-
-	Basic test for access(2) using F_OK, R_OK, W_OK, and X_OK  arguments.
-
-access02  
-
-	Verify that access() succeeds to check the read/write/execute permissions
-	on a file if the mode argument passed was R_OK/W_OK/X_OK.
-
-	Also verify that, access() succeeds to test the accessibility of the file
-	referred to by symbolic link if the pathname points to a symbolic link.
-
-access03
-
-	EFAULT error testing for access(2).
-
-access04  
-
-	Verify that,
-	1. access() fails with -1 return value and sets errno to EACCES
-	if the permission bits of the file mode do not permit the
-	requested (Read/Write/Execute) access.
-	2. access() fails with -1 return value and sets errno to EINVAL
-	if the specified access mode argument is invalid.
-	3. access() fails with -1 return value and sets errno to EFAULT
-	if the pathname points outside allocate address space for the
-	process.
-	4. access() fails with -1 return value and sets errno to ENOENT
-	if the specified file doesn't exist (or pathname is NULL).
-	5. access() fails with -1 return value and sets errno to ENAMETOOLONG
-	if the pathname size is > PATH_MAX characters.
-
-access05  
-
-	Verify that access() succeeds to check the existence of a file if
-	search access is permitted on the pathname of the specified file.
-
-access06
-
-	EFAULT error testing for access(2).
-
-chroot01  
-
-	Testcase to check the whether chroot sets errno to EPERM.
-
-chroot02  
-
-	Test functionality of chroot(2)
-
-chroot03  
-
-	Testcase to test whether chroot(2) sets errno correctly.
-
-pipeio
-
-	This tool can be used to beat on system or named pipes.
-	See the help() function below for user information.
-
-pipe01  
-
-	Testcase to check the basic functionality of the pipe(2) syscall:
-	Check that both ends of the pipe (both file descriptors) are
-	available to a process opening the pipe.
-
-pipe05  
-
-	Check what happens when pipe is passed a bad file descriptor.
-
-pipe06  
-
-	Check what happens when the system runs out of pipes.
-
-pipe08  
-
-	Check that a SIGPIPE signal is generated when a write is
-	attempted on an empty pipe.
-
-pipe09  
-
-	Check that two processes can use the same pipe at the same time.
-
-pipe10  
-
-	Check that parent can open a pipe and have a child read from it
-
-pipe11  
-
-	Check if many children can read what is written to a pipe by the
-	parent.
-
-
-sem01
-
-	Creates a semaphore and two processes.  The processes
-	each go through a loop where they semdown, delay for a
-	random amount of time, and semup, so they will almost
-	always be fighting for control of the semaphore.
-
-sem02
-	The application creates several threads using pthread_create().
-	One thread performs a semop() with the SEM_UNDO flag set. The
-	change in semaphore value performed by that semop should be
-	"undone" only when the last pthread exits.
-
-
-semctl01  
-
-	test the 10 possible semctl() commands
-
-semctl02  
-
-	test for EACCES error
-
-semctl03  
-
-	test for EINVAL and EFAULT errors
-
-semctl04 
-
-	test for EPERM error
-
-
-semctl05
-
-	test for ERANGE error
-
-semget01
-
-	test that semget() correctly creates a semaphore set
-
-semget02 
-
-	test for EACCES and EEXIST errors
-
-semget03 
-
-	test for ENOENT error
-
-semget05 
-
-	test for ENOSPC error
-
-semget06
-
-	test for EINVAL error
-
-semop01 
-
-	test that semop() basic functionality is correct
-
-semop02
-
-	test for E2BIG, EACCES, EFAULT and EINVAL errors
-
-semop03
-
-	test for EFBIG error
-
-semop04
-
-	test for EAGAIN error
-
-semop05
-
-	test for EINTR and EIDRM errors
-
-
-
-msgctl01 
-	create a message queue, then issue the IPC_STAT command
-	and RMID commands to test the functionality
-
-
-msgctl02 
-	create a message queue, then issue the IPC_SET command
-	to lower the msg_qbytes value.
-
-
-msgctl03
-	create a message queue, then issue the IPC_RMID command
-
-
-
-msgctl04 
-	test for EACCES, EFAULT and EINVAL errors using
-	a variety of incorrect calls.
-
-
-msgctl05 
-	test for EPERM error
-
-
-
-msgget01 
-	create a message queue, write a message to it and
-	read it back.
-
-
-msgget02 
-	test for EEXIST and ENOENT errors
-
-
-msgget03 
-	test for an ENOSPC error by using up all available
-	message queues.
-
-msgget04 
-	test for an EACCES error by creating a message queue
-	with no read or write permission and then attempting
-	to access it with various permissions.
-
-msgrcv01 
-	test that msgrcv() receives the expected message
-
-msgrcv02
-	test for EACCES and EFAULT errors
-
-msgrcv03
-	test for EINVAL error
-
-msgrcv04
-	test for E2BIG and ENOMSG errors
-
-msgrcv05
-	test for EINTR error
-
-msgrcv06
-	test for EIDRM error
-
-msgsnd01
-	test that msgsnd() enqueues a message correctly
-
-msgsnd02
-	test for EACCES and EFAULT errors
-
-msgsnd03
-	test for EINVAL error
-
-msgsnd04
-	test for EAGAIN error
-
-msgsnd05
-	test for EINTR error
-
-
-msgsnd06
-	test for EIDRM error
-
-shmat01
-	test that shmat() works correctly
-
-shmat02
-	check for EINVAL and EACCES errors
-
-
-shmat03
-	test for EACCES error
-
-
-shmctl01
-	test the IPC_STAT, IPC_SET and IPC_RMID commands as
-	they are used with shmctl()
-
-
-shmctl02
-	check for EACCES, EFAULT and EINVAL errors
-
-
-shmctl03
-	check for EACCES, and EPERM errors
-
-
-shmdt01
-	check that shared memory is detached correctly
-
-
-shmdt02
-	check for EINVAL error
-
-
-shmget01
-	test that shmget() correctly creates a shared memory segment
-
-
-shmget02
-	check for ENOENT, EEXIST and EINVAL errors
-
-
-shmget03
-	test for ENOSPC error
-
-
-shmget04
-	test for EACCES error
-
-
-shmget05
-	test for EACCES error
-
-openfile
-
-	Creates files and opens simultaneously
-
-open01  
-
-	Open a file with oflag = O_CREAT set, does it set the sticky bit off?
-
-	Open "/tmp" with O_DIRECTORY, does it set the S_IFDIR bit on?
-
-open02  
-
-	Test if open without O_CREAT returns -1 if a file does not exist.
-
-open03
-
-	Basic test for open(2)  
-
-open04  
-
-	Testcase to check that open(2) sets EMFILE if a process opens files
-	more than its descriptor size
-
-open05  
-
-	Testcase to check open(2) sets errno to EACCES correctly.
-
-open06  
-
-	Testcase to check open(2) sets errno to ENXIO correctly.
-
-open07  
-
-	Test the open(2) system call to ensure that it sets ELOOP correctly.
-
-open08  
-
-	Check for the following errors:
-	1.	EEXIST
-	2.	EISDIR
-	3.	ENOTDIR
-	4.	ENAMETOOLONG
-	5.	EFAULT
-	6.	ETXTBSY
-
-
-openfile
-
-	Creates files and opens simultaneously
-
-
-chdir01  
-
-	Check proper operation of chdir(): tests whether the
-	system call can it change the current, working directory, and find a
-	file there? Will it fail on a non-directory entry ?
-
-chdir02	 	
-
-	Basic test for chdir(2).
-
-chdir03  
-
-	Testcase for testing that chdir(2) sets EACCES errno
-
-chdir04  
-
-	Testcase to test whether chdir(2) sets errno correctly.
-
-
-chmod01  
-
-	Verify that, chmod(2) succeeds when used to change the mode permissions
-	of a file. 
-
-chmod02
-
-	Basic test for chmod(2).
-
-chmod03  
-
-	Verify that, chmod(2) will succeed to change the mode of a file
-	and set the sticky bit on it if invoked by non-root (uid != 0)
-	process with the following constraints,
-	- the process is the owner of the file.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is equal to the group ID of the file.
-
-chmod04  
-
-	Verify that, chmod(2) will succeed to change the mode of a directory
-	and set the sticky bit on it if invoked by non-root (uid != 0) process
-	with the following constraints,
-	- the process is the owner of the directory.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is equal to the group ID of the directory.
-
-chmod05  
-
-	Verify that, chmod(2) will succeed to change the mode of a directory
-	but fails to set the setgid bit on it if invoked by non-root (uid != 0)
-	process with the following constraints,
-	- the process is the owner of the directory.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is not equal to the group ID of the directory.
-
-chmod06  
-
-	Verify that,
-	1) chmod(2) returns -1 and sets errno to EPERM if the effective user id
-	of process does not match the owner of the file and the process is
-	not super user.
-	2) chmod(2) returns -1 and sets errno to EACCES if search permission is
-	denied on a component of the path prefix.
-	3) chmod(2) returns -1 and sets errno to EFAULT if pathname points
-	outside user's accessible address space.
-	4) chmod(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
-	component is too long.
-	5) chmod(2) returns -1 and sets errno to ENOTDIR if the directory
-	component in pathname is not a directory.
-	6) chmod(2) returns -1 and sets errno to ENOENT if the specified file
-	does not exists.
-
-chmod07  
-
-	Verify that, chmod(2) will succeed to change the mode of a file/directory
-	and sets the sticky bit on it if invoked by root (uid = 0) process with
-	the following constraints,
-	- the process is not the owner of the file/directory.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is equal to the group ID of the file/directory.
-
-
-chown01
-
-	Basic test for chown(2).
-
-chown02  
-
-	Verify that, when chown(2) invoked by super-user to change the owner and
-	group of a file specified by path to any numeric owner(uid)/group(gid)
-	values,
-	- clears setuid and setgid bits set on an executable file.
-	- preserves setgid bit set on a non-group-executable file.
-
-chown03  
-
-	Verify that, chown(2) succeeds to change the group of a file specified
-	by path when called by non-root user with the following constraints,
-	- euid of the process is equal to the owner of the file.	 
-	- the intended gid is either egid, or one of the supplementary gids
-	of the process.
-	Also, verify that chown() clears the setuid/setgid bits set on the file.
-
-chown04  
-
-	Verify that,
-	1) chown(2) returns -1 and sets errno to EPERM if the effective user id
-	of process does not match the owner of the file and the process is
-	not super user.
-	2) chown(2) returns -1 and sets errno to EACCES if search permission is
-	denied on a component of the path prefix.
-	3) chown(2) returns -1 and sets errno to EFAULT if pathname points
-	outside user's accessible address space.
-	4) chown(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
-	component is too long.
-	5) chown(2) returns -1 and sets errno to ENOTDIR if the directory
-	component in pathname is not a directory.
-	6) chown(2) returns -1 and sets errno to ENOENT if the specified file
-	does not exists.
-
-chown05  
-
-	Verify that, chown(2) succeeds to change the owner and group of a file
-	specified by path to any numeric owner(uid)/group(gid) values when invoked 
-	by super-user.
-
-
-close01  
-
-	Test that closing a regular file and a pipe works correctly
-
-close02  
-
-	Check that an invalid file descriptor returns EBADF
-
-close08
-
-	Basic test for close(2).
-
-
-fchdir01  
-
-	create a directory and cd into it.
-
-fchdir02  
-
-	try to cd into a bad directory (bad fd).
-
-
-fchmod01
-
-	Basic test for Fchmod(2).
-
-fchmod02  
-
-	Verify that, fchmod(2) will succeed to change the mode of a file/directory
-	set the sticky bit on it if invoked by root (uid = 0) process with
-	the following constraints,
-	- the process is not the owner of the file/directory.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is equal to the group ID of the file/directory.
-
-fchmod03  
-
-	Verify that, fchmod(2) will succeed to change the mode of a file
-	and set the sticky bit on it if invoked by non-root (uid != 0)
-	process with the following constraints,
-	- the process is the owner of the file.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is equal to the group ID of the file.
-
-fchmod04  
-
-	Verify that, fchmod(2) will succeed to change the mode of a directory
-	and set the sticky bit on it if invoked by non-root (uid != 0) process
-	with the following constraints,
-	- the process is the owner of the directory.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is equal to the group ID of the directory.
-
-fchmod05  
-
-	Verify that, fchmod(2) will succeed to change the mode of a directory
-	but fails to set the setgid bit on it if invoked by non-root (uid != 0)
-	process with the following constraints,
-	- the process is the owner of the directory.
-	- the effective group ID or one of the supplementary group ID's of the
-	process is not equal to the group ID of the directory.
-
-fchmod06  
-
-	Verify that,
-	1) fchmod(2) returns -1 and sets errno to EPERM if the effective user id
-	of process does not match the owner of the file and the process is
-	not super user.
-	2) fchmod(2) returns -1 and sets errno to EBADF if the file descriptor
-	of the specified file is not valid.
-
-fchmod07  
-
-	Verify that, fchmod(2) succeeds when used to change the mode permissions
-	of a file specified by file descriptor. 
-
-
-fchown01
-
-	Basic test for fchown(2).
-
-fchown02  
-
-	Verify that, when fchown(2) invoked by super-user to change the owner and
-	group of a file specified by file descriptor to any numeric 
-	owner(uid)/group(gid) values,
-	- clears setuid and setgid bits set on an executable file.
-	- preserves setgid bit set on a non-group-executable file.
-
-fchown03  
-
-	Verify that, fchown(2) succeeds to change the group of a file specified
-	by path when called by non-root user with the following constraints,
-	- euid of the process is equal to the owner of the file.	 
-	- the intended gid is either egid, or one of the supplementary gids
-	of the process.
-	Also, verify that fchown() clears the setuid/setgid bits set on the file.
-
-fchown04  
-
-	Verify that,
-	1) fchown(2) returns -1 and sets errno to EPERM if the effective user id
-	of process does not match the owner of the file and the process is
-	not super user.
-	2) fchown(2) returns -1 and sets errno to EBADF if the file descriptor
-	of the specified file is not valid.
-
-fchown05  
-
-	Verify that, fchown(2) succeeds to change the owner and group of a file
-	specified by file descriptor to any numeric owner(uid)/group(gid) values 
-	when invoked by super-user.
-
-lchown01  
-
-	Verify that, lchown(2) succeeds to change the owner and group of a file
-	specified by path to any numeric owner(uid)/group(gid) values when invoked 
-	by super-user.
-
-
-lchown02  
-
-	Verify that,
-	1) lchown(2) returns -1 and sets errno to EPERM if the effective user id
-	of process does not match the owner of the file and the process is
-	not super user.
-	2) lchown(2) returns -1 and sets errno to EACCES if search permission is
-	denied on a component of the path prefix.
-	3) lchown(2) returns -1 and sets errno to EFAULT if pathname points
-	outside user's accessible address space.
-	4) lchown(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
-	component is too long.
-	5) lchown(2) returns -1 and sets errno to ENOTDIR if the directory
-	component in pathname is not a directory.
-	6) lchown(2) returns -1 and sets errno to ENOENT if the specified file
-	does not exists.
-
-
-creat01  
-
-	Testcase to check the basic functionality of the creat(2) system call.
-
-creat03  
-
-	Testcase to check whether the sticky bit cleared.
-
-creat04  
-
-	Testcase to check creat(2) fails with EACCES
-
-creat05  
-
-	Testcase to check that creat(2) system call returns EMFILE.
-
-creat06  
-
-	Testcase to check creat(2) sets the following errnos correctly:
-	1.	EISDIR
-	2.	ENAMETOOLONG
-	3.	ENOENT
-	4.	ENOTDIR
-	5.	EFAULT
-	6.	EACCES
-
-creat07  
-
-	Testcase to check creat(2) sets the following errnos correctly:
-	1.	ETXTBSY
-
-creat09
-
-	Basic test for creat(2) using 0700 argument.
-
-truncate01  
-
-	Verify that, truncate(2) succeeds to truncate a file to a specified
-	length.
-
-
-truncate02  
-
-	Verify that, truncate(2) succeeds to truncate a file to a certain length,
-	but the attempt to read past the truncated length will fail.  
-
-
-truncate03  
-
-	Verify that,
-	1) truncate(2) returns -1 and sets errno to EACCES if search/write
-	permission denied for the process on the component of the path prefix
-		or named file.
-	2) truncate(2) returns -1 and sets errno to ENOTDIR if the component of
-	the path prefix is not a directory.
-	3) truncate(2) returns -1 and sets errno to EFAULT if pathname points
-	outside user's accessible address space.
-	4) truncate(2) returns -1 and sets errno to ENAMETOOLONG if the component
-	of a pathname exceeded 255 characters or entire pathname exceeds 1023
-	characters.
-	5) truncate(2) returns -1 and sets errno to ENOENT if the named file
-	does not exist.
-
-ftruncate01  
-
-	Verify that, ftruncate(2) succeeds to truncate a file to a specified
-	length if the file indicated by file descriptor opened for writing.
-
-ftruncate02  
-
-	Verify that, ftruncate(2) succeeds to truncate a file to a certain length,
-	but the attempt to read past the truncated length will fail.  
-
-ftruncate03  
-
-	Verify that,
-	1) ftruncate(2) returns -1 and sets errno to EINVAL if the specified
-	truncate length is less than 0.
-	2) ftruncate(2) returns -1 and sets errno to EBADF if the file descriptor
-	of the specified file is not valid.
-
-vhangup01  
-
-	Check the return value, and errno of vhangup(2)
-	when a non-root user calls vhangup().
-
-vhangup02  
-
-	To test the basic functionality of vhangup(2)
-growfiles
-
-	This program will grow a list of files.
-	Each file will grow by grow_incr before the same
-	file grows twice.  Each file is open and closed before next file is opened.
-
-pipe01  
-
-	Testcase to check the basic functionality of the pipe(2) syscall:
-	Check that both ends of the pipe (both file descriptors) are
-	available to a process opening the pipe.
-
-pipe05  
-
-	Check what happens when pipe is passed a bad file descriptor.
-
-pipe06  
-
-	Check what happens when the system runs out of pipes.
-
-pipe08  
-
-	Check that a SIGPIPE signal is generated when a write is
-	attempted on an empty pipe.
-
-pipe09  
-
-	Check that two processes can use the same pipe at the same time.
-
-pipe10  
-
-	Check that parent can open a pipe and have a child read from it
-
-pipe11  
-
-	Check if many children can read what is written to a pipe by the
-	parent.
-
-pipeio
-
-	This tool can be used to beat on system or named pipes.
-	See the help() function below for user information.
-
-	/ipc_stress/message_queue_test_01.c
-	/ipc_stress/pipe_test_01.c
-	/ipc_stress/semaphore_test_01.c
-	/ipc_stress/single_test_01.c
-
-proc01
-	Recursively reads all files within /proc filesystem.
-
-lftest
-	The purpose of this test is to verify the file size limitations of a filesystem.
-	It writes one buffer at a time and lseeks from the beginning of the file to the
-	end of the last write position.  The intent is to test lseek64.
-
-
-llseek01  
-
-	Verify that, llseek() call succeeds to set the file pointer position 
-	to an offset larger than file size. Also, verify that any attempt
-	to write to this location fails.
-
-llseek02  
-
-	Verify that,
-	1. llseek() returns -1 and sets errno to EINVAL, if the 'Whence' argument
-	is not a proper value.
-	2. llseek() returns -1 and sets errno to EBADF, if the file handle of
-	the specified file is not valid.
-
-lseek01
-
-	Basic test for lseek(2) 
-
-lseek02
-
-	Negative test for lseek(2) 
-
-lseek03
-
-	Negative test for lseek(2) whence
-
-lseek04
-
-	Negative test for lseek(2) of a fifo 
-
-lseek05
-
-	Negative test for lseek(2) of a pipe
-
-lseek06  
-
-	Verify that, lseek() call succeeds to set the file pointer position 
-	to less  than  or equal to the file size, when a file is opened for
-	read or write.
-
-lseek07  
-
-	Verify that, lseek() call succeeds to set the file pointer position
-	to more than the file size, when a file is opened for reading/writing.
-
-lseek08  
-
-	Verify that, lseek() call succeeds to set the file pointer position 
-	to the end of the file when 'whence' value set to SEEK_END and any
-	attempts to read from that position should fail.
-
-lseek09  
-
-	Verify that, lseek() call succeeds to set the file pointer position 
-	to the current specified location, when 'whence' value is set to
-	SEEK_CUR and the data read from the specified location should match
-	the expected data.
-
-lseek10  
-
-	Verify that,
-	1. lseek() returns -1 and sets errno to ESPIPE, if the file handle of
-	the specified file is associated with a pipe, socket, or  FIFO.	
-	2. lseek() returns -1 and sets errno to EINVAL, if the 'Whence' argument
-	is not a proper value.
-	3. lseek() returns -1 and sets errno to EBADF, if the file handle of
-	the specified file is not valid.
-
-rwtest
-
-	A wrapper for doio and iogen.
-
-doio 
-	a general purpose io initiator with system call and
-	write logging.  See doio.h for the structure which defines
-	what doio requests should look like.
-
-	Currently doio can handle read,write,reada,writea,ssread,
-	sswrite, and many varieties of listio requests.
-	For disk io, if the O_SSD flag is set doio will allocate
-	the appropriate amount of ssd and do the transfer - thus, doio
-	can handle all of the primitive types of file io.
-
-iogen 
-	A tool for generating file/sds io for a doio process
-
-pread01  
-
-	Verify the functionality of pread() by writing known data using pwrite()
-	to the file at various specified offsets and later read from the file from
-	various specified offsets, comparing the data read against the data 
-	written.
-
-pread02  
-
-	Verify that,
-	1) pread() fails when attempted to read from an unnamed pipe.
-	2) pread() fails if the specified offset position was invalid.
-
-
-pwrite01  
-
-	Verify the functionality of pwrite() by writing known data using pwrite()
-	to the file at various specified offsets and later read from the file from
-	various specified offsets, comparing the data written against the data
-	read using read().
-
-pwrite02  
-
-	Verify that,
-	1) pwrite() fails when attempted to write to an unnamed pipe.
-	2) pwrite() fails if the specified offset position was invalid.
-
-
-read01
-
-	Basic test for the read(2) system call
-
-read02  
-
-	test 1: Does read return -1 if file descriptor is not valid, check for EBADF
-
-	test 2: Check if read sets EISDIR, if the fd refers to a directory
-
-	test 3: Check if read sets EFAULT, if buf is -1.
-
-read03  
-
-	Testcase to check that read() sets errno to EAGAIN
-
-read04  
-
-	Testcase to check if read returns the number of bytes read correctly.
-
-
-readv01  
-
-	Testcase to check the basic functionality of the readv(2) system call.
-
-readv02  
-
-	Testcase to check the error conditions of the readv(2) system call.
-
-write01
-
-	Basic test for write(2) system call.
-
-write02  
-
-	Basic functionality test: does the return from write match the count
-	of the number of bytes written.
-
-
-write03  
-
-	Testcase to check that write(2) doesn't corrupt a file when it fails
-
-write04  
-
-	Testcase to check that write() sets errno to EAGAIN
-
-write05  
-
-	Check the return value, and errnos of write(2)
-	- when the file descriptor is invalid - EBADF
-	- when the buf parameter is invalid - EFAULT
-	- on an attempt to write to a pipe that is not open for reading - EPIPE
-
-
-writev01  
-
-	Testcase to check the basic functionality of writev(2) system call.
-
-
-writev02  
-
-	In these testcases, writev() is called with partially valid data 
-	to be written in a sparse file.
-
-
-writev03  
-
-	The testcases are written calling writev() with partially valid data
-	to overwrite the contents, to write in the beginning and to write in
-	the end of the file.
-
-writev04  
-
-	The testcases are written calling writev() with partially valid data
-	to overwrite the contents, to write in the beginning and to write in
-	the end of the file. This is same as writev03, but the length of
-	buffer used here is 8192 bytes.
-
-writev05  
-
-	These testcases are written to test writev() on sparse files. This
-	is same as writev02. But the initial write() with valid data is
-	done at the beginning of the file.
-
-disktest
-
-	Does repeated accesses to a filespec and optionally writes to, reads from,
-	and  verifies  the  data.  By default, disktest makes assumptions about
-	the running environment which allows for a quick start of IO generation.
-	However, Disktest has  a  large  number  of command line options which can
-	be used to adapt the test for a variety of uses including data integrity,
-	medium integrity, performance, and  simple application simulation.
-
-
-
-
-getdents01
-	get a directory entry
-
-getdents02
-	check that we get a failure with a bad file descriptor
-
-
-getdents03
-	check for an EINVAL error
-
-
-getdents04
-	check for an ENOTDIR error
-
-getdents05
-	check that we get a failure with a bad dirp address.
-process_stress
-	Spawn creates a tree
-	of processes with Dval depth and Bval breadth.  Each parent will spawn
-	Bval children.  Each child will store information about themselves
-	in shared memory.  The leaf nodes will communicate the existence
-	of one another through message queues, once each leaf node has
-	received communication from all of her siblings she will reduce
-	the semaphore count and exit.  Meanwhile all parents are waiting
-	to hear from their children through the use of semaphores.  When
-	the semaphore count reaches zero then the parent knows all the
-	children have talked to one another.  Locking of the connter semaphore
-	is provided by the use of another (binary) semaphore.
-
-
-
-
-sched_stress
-	Exports required environment variables and runs sched_driver
-sched_driver
-	This program uses system calls to change the 
-	priorities of the throughput measurement testcases.  
-	When real-time is in effect, priorities 50 through 64
-	are used.  (MAX_PRI and MIN_PRI)  When user-time     
-	(normal) is in effect, 0-14 (corresponding to nice()  
-	calls) is used.  The driver only keeps track of      
-	values from 50 to 64, and the testcases will scale   
-	them down to 0 to 14 when needed, to change the      
-	priority of a user-time process.                       
-
-time-schedule
-	This programme will determine the context switch 
-	(scheduling) overhead on a system. It takes into 
-	account SMP machines. True context switches are 
-	measured.
-trace_sched
-	This utility spawns N tasks, each task sets its priority 
-	by making a system call to the scheduler. The thread 
-	function reads the priority that the scheduler sets for 
-	this task and also reads from /proc the processor this 
-	task last executed on the information that is gathered 
-	by the thread function may be in real-time. Its only an 
-	approximation.         
-
-sched_getscheduler01  
-
-	Testcase to check sched_getscheduler() returns correct return value 
-
-sched_getscheduler02  
-
-	To check for the errno ESRCH
-
-
-sched_setscheduler01  
-
-	Testcase to test whether sched_setscheduler(2) sets the errnos
-	correctly.
-
-sched_setscheduler02  
-
-	Testcase to test whether sched_setscheduler(2) sets the errnos
-	correctly.
-
-
-sched_yield01  
-
-	Testcase to check that sched_yield returns correct values.
-
-
-nice01  
-
-	Verify that root can provide a negative value  to nice()
-	and hence root can decrease the nice value of the process
-	using nice() system call
-
-nice02  
-
-	Verify that any user can successfully increase the nice value of
-	the process by passing a higher increment value (> max. applicable limits)
-	to nice() system call.
-
-nice03  
-
-	Verify that any user can successfully increase the nice value of
-	the process by passing an increment value (< max. applicable limits) to 
-	nice() system call.
-
-nice04  
-
-	Verify that, nice(2) fails when, a non-root user attempts to increase
-	the priority of a process by specifying a negative increment value.
-
-nice05
-
-	Basic test for nice(2) 
-
-
-poll01  
-
-	Verify that valid open file descriptor must be provided to poll() to
-	succeed.
-
-select01
-
-	Basic test for the select(2) system call to a fd of regular file with no I/O 
-	and small timeout 
-
-select02
-
-	Basic test for the select(2) system call to fd of system pipe with no I/O 
-	and small timeout 
-
-select03
-
-	Basic test for the select(2) system call to fd of a named-pipe (FIFO) 
-
-select04  
-
-	Verify that select(2) returns immediately (does not block) if the
-	timeout value is zero.
-
-select05  
-
-	Verify that select(2) fails when one or more of the file descriptor sets
-	specify a file descriptor which is not valid.
-
-select06  
-
-	Verify that select(2) fails when a signal is delivered before any of the
-	selected events occur and before the timeout interval expires.
-
-select07  
-
-	Verify that select(2) fails when an invalid timeout interval is specified.
-
-select08  
-
-	Verify the functionality of select(2) by passing non-null writefds
-	which points to a regular file, pipes or FIFO's.
-
-select09  
-
-	Verify the functionality of select(2) by passing non-null readfds
-	which points to a regular file, pipes or FIFO's.
-
-select10 
-
-	Verify that a successful call to select() shall return the desired 
-	number of modified descriptors for which bits are set in the bit masks, 
-	where descriptors points to a regular file, pipes or FIFO's.
-sem01
-
-	Creates a semaphore and two processes.  The processes
-	each go through a loop where they semdown, delay for a
-	random amount of time, and semup, so they will almost
-	always be fighting for control of the semaphore.
-
-sem02
-	The application creates several threads using pthread_create().
-	One thread performs a semop() with the SEM_UNDO flag set. The
-	change in semaphore value performed by that semop should be
-	"undone" only when the last pthread exits.
-
-
-semctl01  
-
-	test the 10 possible semctl() commands
-
-semctl02  
-
-	test for EACCES error
-
-semctl03  
-
-	test for EINVAL and EFAULT errors
-
-semctl04 
-
-	test for EPERM error
-
-
-semctl05
-
-	test for ERANGE error
-
-semget01
-
-	test that semget() correctly creates a semaphore set
-
-semget02 
-
-	test for EACCES and EEXIST errors
-
-semget03 
-
-	test for ENOENT error
-
-semget05 
-
-	test for ENOSPC error
-
-semget06
-
-	test for EINVAL error
-
-semop01 
-
-	test that semop() basic functionality is correct
-
-semop02
-
-	test for E2BIG, EACCES, EFAULT and EINVAL errors
-
-semop03
-
-	test for EFBIG error
-
-semop04
-
-	test for EAGAIN error
-
-semop05
-
-	test for EINTR and EIDRM errors
-
-
-shmat01
-	test that shmat() works correctly
-
-shmat02
-	check for EINVAL and EACCES errors
-
-
-shmat03
-	test for EACCES error
-
-
-shmctl01
-	test the IPC_STAT, IPC_SET and IPC_RMID commands as
-	they are used with shmctl()
-
-
-shmctl02
-	check for EACCES, EFAULT and EINVAL errors
-
-
-shmctl03
-	check for EACCES, and EPERM errors
-
-
-shmdt01
-	check that shared memory is detached correctly
-
-
-shmdt02
-	check for EINVAL error
-
-
-shmget01
-	test that shmget() correctly creates a shared memory segment
-
-
-shmget02
-	check for ENOENT, EEXIST and EINVAL errors
-
-
-shmget03
-	test for ENOSPC error
-
-
-shmget04
-	test for EACCES error
-
-
-shmget05
-	test for EACCES error
-shmat1
-
-	Test the LINUX memory manager. The program is aimed at
-	stressing the memory manager by repeated shmat/write/read/
-	shmatd of file/memory of random size (maximum 1000 * 4096)
-	done by multiple processes.
-
-shm_test
-
-	This program is designed to stress the Memory management sub -
-	system of Linux. This program will spawn multiple pairs of
-	reader and writer threads. One thread will create the shared
-	segment of random size and write to this memory, the other
-	pair will read from this memory.
-
-sigaction01  
-
-	Test some features of sigaction (see below for more details)
-
-
-sigaction02  
-
-	Testcase to check the basic errnos set by the sigaction(2) syscall.
-
-
-sigaltstack01  
-
-	Send a signal using the main stack. While executing the signal handler
-	compare a variable's address lying on the main stack with the stack
-	boundaries returned by sigaltstack().
-
-
-sigaltstack02  
-
-	Verify that,
-	1. sigaltstack() fails and sets errno to EINVAL when "ss_flags" field
-	pointed to by 'ss' contains invalid flags.
-	2. sigaltstack() fails and sets errno to ENOMEM when the size of alternate
-	stack area is less than MINSIGSTKSZ.
-
-sighold02
-
-	Basic test for the sighold02(2) system call. 
-
-
-signal01
-	set the signal handler to our own function
-
-
-signal02 
-	Test that we get an error using illegal signals
-
-signal03
-
-	Boundary value and other invalid value checking of signal setup and signal 
-	sending. 
-
-
-signal04 
-	restore signals to default behavior
-
-
-signal05 
-	set signals to be ignored
-
-
-sigprocmask01  
-
-	Verify that sigprocmask() succeeds to examine and change the calling
-	process's signal mask. 
-	Also, verify that sigpending() succeeds to store signal mask that are
-	blocked from delivery and pending for the calling process.
-
-sigrelse01
-
-	Basic test for the sigrelse(2) system call. 
-
-sigsuspend01  
-
-	Verify that sigsuspend() succeeds to change process's current signal
-	mask with the specified signal mask and suspends the process execution
-	until the delivery of a signal.
-kill01  
-
-	Test case to check the basic functionality of kill().
-
-kill02
-
-	Sending a signal to processes with the same process group ID
-
-kill03  
-
-	Test case to check that kill fails when given an invalid signal.
-
-kill04  
-
-	Test case to check that kill() fails when passed a non-existent pid.
-
-kill05  
-
-	Test case to check that kill() fails when passed a pid owned by another
-	user.
-
-kill06  
-
-	Test case to check the basic functionality of kill() when killing an
-	entire process group with a negative pid.
-
-kill07  
-
-	Test case to check that SIGKILL can not be caught.
-
-kill08  
-
-	Test case to check the basic functionality of kill() when kill an
-	entire process group.
-
-kill09
-	Basic test for kill(2)
-
-kill10
-	Signal flooding test.
-
-
-mtest01
-        mallocs memory <chunksize> at a time until malloc fails.
-mallocstress
-
-	This program is designed to stress the VMM by doing repeated  */
-	mallocs and frees, with out using the swap space. This is     */
-	achieved by spawning N threads with repeatedly malloc and free*/
-	a memory of size M. The stress can be increased by increasing */
-	the number of repetitions over the default number using the   */
-	-l [num] option.
-
-clisrv
-
-	Sender: Read contents of data file. Write each line to socket, then
-	read line back from socket and write to standard output.      
-	Receiver: Read a stream socket one line at a time and write each line
-	back to the sender.                                       
-	Usage:       pthcli [port number]                 
-			    
-
-socket01  
-
-	Verify that socket() returns the proper errno for various failure cases
-
-
-socketpair01  
-
-	Verify that socketpair() returns the proper errno for various failure cases
-
-
-sockioctl01  
-
-	Verify that ioctl() on sockets returns the proper errno for various
-	failure cases
-
-connect01  
-
-	Verify that connect() returns the proper errno for various failure cases
-
-getpeername01
-
-	Verify that getpeername() returns the proper errno for various failure cases
-
-
-getsockname01      
-
-	Verify that getsockname() returns the proper errno for various failure cases
-
-getsockopt01       
-
-	Verify that getsockopt() returns the proper errno for various failure cases
-
-listen01
-
-	Verify that listen() returns the proper errno for various failure cases
-
-accept01
-
-	Verify that accept() returns the proper errno for various failure cases
-
-bind01
-
-	Verify that bind() returns the proper errno for various failure cases
-
-
-recv01  
-
-	Verify that recv() returns the proper errno for various failure cases
-
-
-recvfrom01  
-
-	Verify that recvfrom() returns the proper errno for various failure cases
-
-
-recvmsg01  
-
-	Verify that recvmsg() returns the proper errno for various failure cases
-
-send01
-
-	Verify that send() returns the proper errno for various failure cases
-
-sendmsg01
-
-	Verify that sendmsg() returns the proper errno for various failure cases
-sendto01
-
-	Verify that sendto() returns the proper errno for various failure cases
-
-setsockopt01  
-
-	Verify that setsockopt() returns the proper errno for various failure cases
-
-
-fstat01
-
-	Basic test for fstat(2)
-
-fstat02  
-
-	Verify that, fstat(2) succeeds to get the status of a file and fills
-	the stat structure elements though file pointed to by file descriptor
-	not opened for reading.
-
-fstat03  
-
-	Verify that, fstat(2) returns -1 and sets errno to EBADF if the file 
-	pointed to by file descriptor is not valid.
-
-fstat04
-
-	Verify that, fstat(2) succeeds to get the status of a file pointed by
-	file descriptor and fills the stat structure elements.
-
-
-fstatfs01
-
-	Basic test for fstatfs(2)
-
-fstatfs02  
-
-	Testcase to check fstatfs() sets errno correctly.
-
-lstat01  
-
-	Verify that, lstat(2) succeeds to get the status of a file pointed to by
-	symlink and fills the stat structure elements.
-
-lstat02
-
-	Basic test for lstat(2) 
-
-lstat03  
-
-	Verify that,
-	1) lstat(2) returns -1 and sets errno to EACCES if search permission is
-	denied on a component of the path prefix.
-	2) lstat(2) returns -1 and sets errno to ENOENT if the specified file
-	does not exists or empty string.
-	3) lstat(2) returns -1 and sets errno to EFAULT if pathname points
-	outside user's accessible address space.
-	4) lstat(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
-	component is too long.
-	5) lstat(2) returns -1 and sets errno to ENOTDIR if the directory
-	component in pathname is not a directory.
-
-stat01  
-
-	Verify that, stat(2) succeeds to get the status of a file and fills the
-	stat structure elements.
-
-stat02  
-
-	Verify that, stat(2) succeeds to get the status of a file and fills the
-	stat structure elements though process doesn't have read access to the
-	file.
-
-
-stat03  
-
-	Verify that,
-	1) stat(2) returns -1 and sets errno to EACCES if search permission is
-	denied on a component of the path prefix.
-	2) stat(2) returns -1 and sets errno to ENOENT if the specified file
-	does not exists or empty string.
-	3) stat(2) returns -1 and sets errno to EFAULT if pathname points
-	outside user's accessible address space.
-	4) stat(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
-	component is too long.
-	5) stat(2) returns -1 and sets errno to ENOTDIR if the directory
-	component in pathname is not a directory.
-
-stat05
-
-	Basic test for the stat05(2) system call. 
-
-statfs01
-
-	Basic test for the statfs(2) system call. 
-
-statfs02  
-
-	Testcase to check that statfs(2) sets errno correctly.
-
-
-read01
-
-	Basic test for the read(2) system call
-
-read02  
-
-	test 1: Does read return -1 if file descriptor is not valid, check for EBADF
-
-	test 2: Check if read sets EISDIR, if the fd refers to a directory
-
-	test 3: Check if read sets EFAULT, if buf is -1.
-
-read03  
-
-	Testcase to check that read() sets errno to EAGAIN
-
-read04  
-
-	Testcase to check if read returns the number of bytes read correctly.
-
-umask01
-
-	Basic test for the umask(2) system call. 
-
-umask02  
-
-	Check that umask changes the mask, and that the previous
-	value of the mask is returned correctly for each value.
-
-umask03  
-
-	Check that umask changes the mask, and that the previous
-	value of the mask is returned correctly for each value.
-
-
-
-getgroups01
-
-	Getgroups system call critical test 
-
-getgroups02
-
-	Basic test for getgroups(2) 
-
-getgroups03  
-
-	Verify that, getgroups() system call gets the supplementary group IDs
-	of the calling process.
-
-getgroups04  
-
-	Verify that,
-	getgroups() fails with -1 and sets errno to EINVAL if the size
-	argument value is -ve.
-
-gethostname01
-
-	Basic test for gethostname(2)
-
-
-getpgid01
-
-	Testcase to check the basic functionality of getpgid().
-
-getpgid02
-
-	Testcase to check the basic functionality of getpgid().
-
-getpgrp01
-	Basic test for getpgrp(2)
-
-
-getpriority01  
-
-	Verify that getpriority() succeeds get the scheduling priority of 
-	the current process, process group or user.
-
-
-getpriority02  
-
-	Verify that,
-	1) getpriority() sets errno to ESRCH  if no process was located
-	was located for 'which' and 'who' arguments.
-	2) getpriority() sets errno to EINVAL if 'which' argument was
-	not one of PRIO_PROCESS, PRIO_PGRP, or PRIO_USER.
-
-getresgid01  
-
-	Verify that getresgid() will be successful to get the real, effective
-	and saved user id of the calling process.
-
-getresgid02  
-
-	Verify that getresgid() will be successful to get the real, effective
-	and saved user ids after calling process invokes setregid() to change
-	the effective/saved gids to that of specified user.
-
-getresgid03  
-
-	Verify that getresgid() will be successful to get the real, effective
-	and saved user ids after calling process invokes setresgid() to change
-	the effective gid to that of specified user.
-
-
-getresuid01  
-
-	Verify that getresuid() will be successful to get the real, effective
-	and saved user id of the calling process.
-
-getresuid02  
-
-	Verify that getresuid() will be successful to get the real, effective
-	and saved user ids after calling process invokes setreuid() to change
-	the effective/saved uids to that of specified user.
-
-getresuid03  
-
-	Verify that getresuid() will be successful to get the real, effective
-	and saved user ids after calling process invokes setresuid() to change
-	the effective uid to that of specified user.
-
-
-getsid01  
-
-	call getsid() and make sure it succeeds
-
-getsid02  
-
-	call getsid() with an invalid PID to produce a failure
-
-
-setfsgid01  
-
-	Testcase to check the basic functionality of setfsgid(2) system
-	call.
-
-setfsuid01  
-
-	Testcase to test the basic functionality of the setfsuid(2) system
-	call.
-
-
-setgid01
-
-	Basic test for the setgid(2) system call. 
-
-setgid02
-
-	Testcase to ensure that the setgid() system call sets errno to EPERM
-
-
-setgroups01
-
-	Basic test for the setgroups(2) system call. 
-
-setgroups02  
-
-	Verify that,
-	1. setgroups() fails with -1 and sets errno to EINVAL if the size
-	argument value is > NGROUPS
-	2. setgroups() fails with -1 and sets errno to EPERM if the
-	calling process is not super-user.
-
-setgroups03  
-
-	Verify that, only root process can invoke setgroups() system call to
-	set the supplementary group IDs of the process.
-
-
-setpgid01	 	
-
-	Basic test for setpgid(2) system call. 
-
-setpgid02  
-
-	Testcase to check that setpgid() sets errno correctly.
-
-setpgid03  
-
-	Test to check the error and trivial conditions in setpgid system call
-
-setpriority01  
-
-	set the priority for the test process lower.
-
-setpriority02  
-
-	test for an expected failure by trying to raise
-	the priority for the test process while not having
-	permissions to do so.
-
-setpriority03  
-
-	test for an expected failure by using an invalid
-	PRIO value
-	setpriority04  
-
-setpriority04
-	test for an expected failure by using an invalid
-	process id
-
-
-setpriority05 
-	test for an expected failure by trying to change
-	a process with an ID that is different from the
-	test process
-
-setregid01	 
-
-	Basic test for the setregid(2) system call. 
-
-setregid02  
-
-	Test that setregid() fails and sets the proper errno values when a
-	non-root user attempts to change the real or effective group id to a 
-	value other than the current gid or the current effective gid. 
-
-setregid03  
-
-	Test setregid() when executed by a non-root user.
-
-setregid04  
-
-	Test setregid() when executed by root.
-
-setresuid01  
-
-	Test setresuid() when executed by root.
-
-setresuid02  
-
-	Test that a non-root user can change the real, effective and saved
-	uid values through the setresuid system call.
-
-
-setresuid03  
-
-	Test that the setresuid system call sets the proper errno
-	values when a non-root user attempts to change the real, effective or
-	saved uid to a value other than one of the current uid, the current
-	effective uid of the current saved uid.  Also verify that setresuid
-	fails if an invalid uid value is given.
-
-setreuid01	 	
-
-	Basic test for the setreuid(2) system call. 
-
-setreuid02  
-
-	Test setreuid() when executed by root.
-
-setreuid03  
-
-	Test setreuid() when executed by an unprivileged user.
-
-
-setreuid04  
-
-	Test that root can change the real and effective uid to an
-	unprivileged user.
-
-setreuid05  
-
-	Test the setreuid() feature, verifying the role of the saved-set-uid
-	and setreuid's effect on it.
-
-setreuid06  
-
-	Test that EINVAL is set when setreuid is given an invalid user id.
-
-setrlimit01  
-
-	Testcase to check the basic functionality of the setrlimit system call.
-
-
-setrlimit02  
-
-	Testcase to test the different errnos set by setrlimit(2) system call.
-
-setrlimit03  
-
-	Test for EPERM when the super-user tries to increase RLIMIT_NOFILE
-	beyond the system limit.
-
-setsid01  
-
-	Test to check the error and trivial conditions in setsid system call
-
-setuid01
-
-	Basic test for the setuid(2) system call. 
-
-setuid02
-
-	Basic test for the setuid(2) system call as root. 
-
-setuid03  
-
-	Test to check the error and trivial conditions in setuid
-
-fs_perms
-
-	Regression test for Linux filesystem permissions.
-uname01
-
-	Basic test for the uname(2) system call.  
-
-uname02  
-
-	Call uname() with an invalid address to produce a failure
-
-uname03  
-
-	Call uname() and make sure it succeeds
-sysctl01  
-
-	Testcase for testing the basic functionality of sysctl(2) system call.
-	This testcase attempts to read the kernel parameters using
-	sysctl({CTL_KERN, KERN_ }, ...) and compares it with the known
-	values.
-
-sysctl03  
-
-	Testcase to check that sysctl(2) sets errno to EPERM correctly.
-
-
-sysctl04  
-
-	Testcase to check that sysctl(2) sets errno to ENOTDIR
-
-
-sysctl05  
-
-	Testcase to check that sysctl(2) sets errno to EFAULT
-
-time01
-
-	Basic test for the time(2) system call. 
-
-
-time02  
-
-	Verify that time(2) returns the value of time in seconds since
-	the Epoch and stores this value in the memory pointed to by the parameter.
-
-times01
-
-	Basic test for the times(2) system call. 
-
-times02  
-
-	Testcase to test that times() sets errno correctly
-
-times03  
-
-	Testcase to check the basic functionality of the times() system call.
-
-utime01  
-
-	Verify that the system call utime() successfully sets the modification
-	and access times of a file to the current time, if the times argument
-	is null, and the user ID of the process is "root".
-
-utime02  
-
-	Verify that the system call utime() successfully sets the modification
-	and access times of a file to the current time, under the following
-	constraints,
-	- The times argument is null.
-	- The user ID of the process is not "root".
-	- The file is owned by the user ID of the process.
-
-utime03  
-
-	Verify that the system call utime() successfully sets the modification
-	and access times of a file to the current time, under the following
-	constraints,
-	- The times argument is null.
-	- The user ID of the process is not "root".
-	- The file is not owned by the user ID of the process.
-	- The user ID of the process has write access to the file.
-
-
-utime04  
-
-	Verify that the system call utime() successfully sets the modification
-	and access times of a file to the time specified by times argument, if
-	the times argument is not null, and the user ID of the process is "root".
-
-
-utime05  
-
-	Verify that the system call utime() successfully sets the modification
-	and access times of a file to the value specified by the times argument
-	under the following constraints,
-	- The times argument is not null,
-	- The user ID of the process is not "root".
-	- The file is owned by the user ID of the process.
-
-
-utime06  
-
-	1. Verify that the system call utime() fails to set the modification
-	and access times of a file to the current time, under the following
-	constraints,
-	- The times argument is null.
-	- The user ID of the process is not "root".
-	- The file is not owned by the user ID of the process.
-	- The user ID of the process does not have write access to the
-	file.
-	2. Verify that the system call utime() fails to set the modification
-	and access times of a file if the specified file doesn't exist.
-
-settimeofday01  
-
-	Testcase to check the basic functionality of settimeofday().
-
-
-settimeofday02  
-
-	Testcase to check that settimeofday() sets errnos correctly.
-
-stime01  
-
-	Verify that the system call stime() successfully sets the system's idea
-	of data and time if invoked by "root" user.
-
-stime02  
-
-	Verify that the system call stime() fails to set the system's idea
-	of data and time if invoked by "non-root" user.
-
-gettimeofday01     
-
-	Testcase to check that gettimeofday(2) sets errno to EFAULT.
-
-
-
-alarm01	 	
-
-	Basic test for alarm(2). 
-
-alarm02
-
-	Boundary Value Test for alarm(2).
-
-alarm03
-
-	Alarm(2) cleared by a fork.
-
-alarm04  
-
-	Check that when an alarm request is made, the signal SIGALRM is received
-	even after the process has done an exec().
-
-alarm05  
-
-	Check the functionality of the Alarm system call when the time input
-	parameter is non zero.
-
-alarm06  
-
-	Check the functionality of the Alarm system call when the time input
-	parameter is zero.
-
-alarm07  
-
-	Check the functionality of the alarm() when the time input
-	parameter is non-zero and the process does a fork.
-
-getegid01
-
-	Basic test for getegid(2) 
-
-
-geteuid01
-
-	Basic test for geteuid(2) 
-
-
-getgid01
-
-	Basic test for getgid(2) 
-
-getgid02  
-
-	Testcase to check the basic functionality of getgid().
-
-getgid03  
-
-	Testcase to check the basic functionality of getegid().
-
-
-getpid01
-
-	Basic test for getpid(2) 
-
-
-getpid02  
-
-	Verify that getpid() system call gets the process ID of the of the
-	calling process.
-
-
-getppid01  
-
-	Testcase to check the basic functionality of the getppid() syscall.
-
-
-getuid01
-
-	Basic test for getuid(2)
-
-getuid02  
-
-	Testcase to check the basic functionality of the geteuid() system call.
-
-getuid03  
-
-	Testcase to check the basic functionality of the getuid() system call.
-
-nanosleep01  
-
-	Verify that nanosleep() will be successful to suspend the execution
-	of a process for a specified time.
-
-nanosleep02  
-
-	Verify that nanosleep() will be successful to suspend the execution
-	of a process, returns after the receipt of a signal and writes the
-	remaining sleep time into the structure.
-
-nanosleep03  
-
-	Verify that nanosleep() will fail to suspend the execution
-	of a process for a specified time if interrupted by a non-blocked signal.
-
-nanosleep04  
-
-	Verify that nanosleep() will fail to suspend the execution
-	of a process if the specified pause time is invalid.
-
diff --git a/third_party/lcov-1.9/example/Makefile b/third_party/lcov-1.9/example/Makefile
deleted file mode 100644
index 5428237..0000000
--- a/third_party/lcov-1.9/example/Makefile
+++ /dev/null
@@ -1,98 +0,0 @@
-#
-# Makefile for the LCOV example program.
-#
-# Make targets:
-#   - example: compile the example program
-#   - output:  run test cases on example program and create HTML output
-#   - clean:   clean up directory
-#
-
-CC      := gcc
-CFLAGS  := -Wall -I. -fprofile-arcs -ftest-coverage
-
-LCOV    := ../bin/lcov
-GENHTML := ../bin/genhtml
-GENDESC := ../bin/gendesc
-GENPNG  := ../bin/genpng
-
-# Depending on the presence of the GD.pm perl module, we can use the
-# special option '--frames' for genhtml
-USE_GENPNG := $(shell $(GENPNG) --help >/dev/null 2>/dev/null; echo $$?)
-
-ifeq ($(USE_GENPNG),0)
-  FRAMES := --frames
-else
-  FRAMES :=
-endif
-
-.PHONY: clean output test_noargs test_2_to_2000 test_overflow
-
-all: output
-
-example: example.o iterate.o gauss.o
-	$(CC) example.o iterate.o gauss.o -o example -lgcov
-
-example.o: example.c iterate.h gauss.h
-	$(CC) $(CFLAGS) -c example.c -o example.o
-
-iterate.o: methods/iterate.c iterate.h
-	$(CC) $(CFLAGS) -c methods/iterate.c -o iterate.o
-
-gauss.o: methods/gauss.c gauss.h
-	$(CC) $(CFLAGS) -c methods/gauss.c -o gauss.o
-
-output: example descriptions test_noargs test_2_to_2000 test_overflow
-	@echo
-	@echo '*'
-	@echo '* Generating HTML output'
-	@echo '*'
-	@echo
-	$(GENHTML) trace_noargs.info trace_args.info trace_overflow.info \
-		   --output-directory output --title "Basic example" \
-		   --show-details --description-file descriptions $(FRAMES) \
-		   --legend
-	@echo
-	@echo '*'
-	@echo '* See '`pwd`/output/index.html
-	@echo '*'
-	@echo
-
-descriptions: descriptions.txt
-	$(GENDESC) descriptions.txt -o descriptions
-
-all_tests: example test_noargs test_2_to_2000 test_overflow
-
-test_noargs:
-	@echo
-	@echo '*'
-	@echo '* Test case 1: running ./example without parameters'
-	@echo '*'
-	@echo
-	$(LCOV) --zerocounters --directory .
-	./example
-	$(LCOV) --capture --directory . --output-file trace_noargs.info --test-name test_noargs
-
-test_2_to_2000:
-	@echo
-	@echo '*'
-	@echo '* Test case 2: running ./example 2 2000'
-	@echo '*'
-	@echo
-	$(LCOV) --zerocounters --directory .
-	./example 2 2000
-	$(LCOV) --capture --directory . --output-file trace_args.info --test-name test_2_to_2000
-
-test_overflow:
-	@echo
-	@echo '*'
-	@echo '* Test case 3: running ./example 0 100000 (causes an overflow)'
-	@echo '*'
-	@echo
-	$(LCOV) --zerocounters --directory .
-	./example 0 100000 || true
-	$(LCOV) --capture --directory . --output-file trace_overflow.info --test-name "test_overflow"
-
-clean:
-	rm -rf *.o *.bb *.bbg *.da *.gcno *.gcda *.info output example \
-	descriptions
-
diff --git a/third_party/lcov-1.9/example/README b/third_party/lcov-1.9/example/README
deleted file mode 100644
index cf6cf2e..0000000
--- a/third_party/lcov-1.9/example/README
+++ /dev/null
@@ -1,6 +0,0 @@
-
-To get an example of how the LCOV generated HTML output looks like,
-type 'make output' and point a web browser to the resulting file
-
-  output/index.html
-
diff --git a/third_party/lcov-1.9/example/descriptions.txt b/third_party/lcov-1.9/example/descriptions.txt
deleted file mode 100644
index 47e6021..0000000
--- a/third_party/lcov-1.9/example/descriptions.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-test_noargs
-	Example program is called without arguments so that default range
-	[0..9] is used.
-
-test_2_to_2000
-	Example program is called with "2" and "2000" as arguments.
-
-test_overflow
-	Example program is called with "0" and "100000" as arguments. The
-	resulting sum is too large to be stored as an int variable.
diff --git a/third_party/lcov-1.9/example/example.c b/third_party/lcov-1.9/example/example.c
deleted file mode 100644
index f9049aa..0000000
--- a/third_party/lcov-1.9/example/example.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  example.c
- * 
- *  Calculate the sum of a given range of integer numbers. The range is
- *  specified by providing two integer numbers as command line argument.
- *  If no arguments are specified, assume the predefined range [0..9].
- *  Abort with an error message if the resulting number is too big to be
- *  stored as int variable.
- *
- *  This program example is similar to the one found in the GCOV documentation.
- *  It is used to demonstrate the HTML output generated by LCOV.
- *
- *  The program is split into 3 modules to better demonstrate the 'directory
- *  overview' function. There are also a lot of bloated comments inserted to
- *  artificially increase the source code size so that the 'source code
- *  overview' function makes at least a minimum of sense.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "iterate.h"
-#include "gauss.h"
-
-static int start = 0;
-static int end = 9;
-
-
-int main (int argc, char* argv[])
-{
-	int total1, total2;
-
-	/* Accept a pair of numbers as command line arguments. */
-
-	if (argc == 3)
-	{
-		start	= atoi(argv[1]);
-		end	= atoi(argv[2]);
-	}
-
-
-	/* Use both methods to calculate the result. */
-
-	total1 = iterate_get_sum (start, end);
-	total2 = gauss_get_sum (start, end);
-
-
-	/* Make sure both results are the same. */
-
-	if (total1 != total2)
-	{
-		printf ("Failure (%d != %d)!\n", total1, total2);
-	}
-	else
-	{
-		printf ("Success, sum[%d..%d] = %d\n", start, end, total1);
-	}
-
-	return 0;
-}
diff --git a/third_party/lcov-1.9/example/gauss.h b/third_party/lcov-1.9/example/gauss.h
deleted file mode 100644
index 302a4a9..0000000
--- a/third_party/lcov-1.9/example/gauss.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef GAUSS_H
-#define GAUSS_H GAUSS_h
-
-extern int gauss_get_sum (int min, int max);
-
-#endif /* GAUSS_H */
diff --git a/third_party/lcov-1.9/example/iterate.h b/third_party/lcov-1.9/example/iterate.h
deleted file mode 100644
index 4713279..0000000
--- a/third_party/lcov-1.9/example/iterate.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef ITERATE_H
-#define ITERATE_H ITERATE_H
-
-extern int iterate_get_sum (int min, int max);
-
-#endif /* ITERATE_H */
diff --git a/third_party/lcov-1.9/example/methods/gauss.c b/third_party/lcov-1.9/example/methods/gauss.c
deleted file mode 100644
index 9da3ce5..0000000
--- a/third_party/lcov-1.9/example/methods/gauss.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  methods/gauss.c
- *
- *  Calculate the sum of a given range of integer numbers.
- *
- *  Somewhat of a more subtle way of calculation - and it even has a story
- *  behind it:
- *
- *  Supposedly during math classes in elementary school, the teacher of
- *  young mathematician Gauss gave the class an assignment to calculate the
- *  sum of all natural numbers between 1 and 100, hoping that this task would
- *  keep the kids occupied for some time. The story goes that Gauss had the
- *  result ready after only a few minutes. What he had written on his black
- *  board was something like this:
- *
- *    1 + 100 = 101
- *    2 + 99  = 101
- *    3 + 98  = 101
- *    .
- *    .
- *    100 + 1 = 101
- *
- *    s = (1/2) * 100 * 101 = 5050
- *
- *  A more general form of this formula would be
- *  
- *    s = (1/2) * (max + min) * (max - min + 1)
- *
- *  which is used in the piece of code below to implement the requested
- *  function in constant time, i.e. without dependencies on the size of the
- *  input parameters.
- *
- */
-
-#include "gauss.h"
-
-
-int gauss_get_sum (int min, int max)
-{
-	/* This algorithm doesn't work well with invalid range specifications
-	   so we're intercepting them here. */
-	if (max < min)
-	{
-		return 0;
-	}
-
-	return (int) ((max + min) * (double) (max - min + 1) / 2);
-}
diff --git a/third_party/lcov-1.9/example/methods/iterate.c b/third_party/lcov-1.9/example/methods/iterate.c
deleted file mode 100644
index 023d180..0000000
--- a/third_party/lcov-1.9/example/methods/iterate.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *  methods/iterate.c
- *  
- *  Calculate the sum of a given range of integer numbers.
- *
- *  This particular method of implementation works by way of brute force,
- *  i.e. it iterates over the entire range while adding the numbers to finally
- *  get the total sum. As a positive side effect, we're able to easily detect
- *  overflows, i.e. situations in which the sum would exceed the capacity
- *  of an integer variable.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "iterate.h"
-
-
-int iterate_get_sum (int min, int max)
-{
-	int i, total;
-
-	total = 0;
-
-	/* This is where we loop over each number in the range, including
-	   both the minimum and the maximum number. */
-
-	for (i = min; i <= max; i++)
-	{
-		/* We can detect an overflow by checking whether the new
-		   sum would become negative. */
-
-		if (total + i < total)
-		{
-			printf ("Error: sum too large!\n");
-			exit (1);
-		}
-
-		/* Everything seems to fit into an int, so continue adding. */
-
-		total += i;
-	}
-
-	return total;
-}
diff --git a/third_party/lcov-1.9/lcovrc b/third_party/lcov-1.9/lcovrc
deleted file mode 100644
index a53977f..0000000
--- a/third_party/lcov-1.9/lcovrc
+++ /dev/null
@@ -1,130 +0,0 @@
-#
-# /etc/lcovrc - system-wide defaults for LCOV
-#
-# To change settings for a single user, place a customized copy of this file
-# at location ~/.lcovrc
-#
-
-# Specify an external style sheet file (same as --css-file option of genhtml)
-#genhtml_css_file = gcov.css
-
-# Specify coverage rate limits (in %) for classifying file entries
-# HI:   hi_limit <= rate <= 100         graph color: green
-# MED: med_limit <= rate <  hi_limit    graph color: orange
-# LO:         0  <= rate <  med_limit   graph color: red
-genhtml_hi_limit = 90
-genhtml_med_limit = 75
-
-# Width of line coverage field in source code view
-genhtml_line_field_width = 12
-
-# Width of branch coverage field in source code view
-genhtml_branch_field_width = 16
-
-# Width of overview image (used by --frames option of genhtml)
-genhtml_overview_width = 80
-
-# Resolution of overview navigation: this number specifies the maximum
-# difference in lines between the position a user selected from the overview
-# and the position the source code window is scrolled to (used by --frames
-# option of genhtml)
-genhtml_nav_resolution = 4
-
-# Clicking a line in the overview image should show the source code view at
-# a position a bit further up so that the requested line is not the first
-# line in the window. This number specifies that offset in lines (used by
-# --frames option of genhtml)
-genhtml_nav_offset = 10
-
-# Do not remove unused test descriptions if non-zero (same as
-# --keep-descriptions option of genhtml)
-genhtml_keep_descriptions = 0
-
-# Do not remove prefix from directory names if non-zero (same as --no-prefix
-# option of genhtml)
-genhtml_no_prefix = 0
-
-# Do not create source code view if non-zero (same as --no-source option of
-# genhtml)
-genhtml_no_source = 0
-
-# Replace tabs with number of spaces in source view (same as --num-spaces
-# option of genhtml)
-genhtml_num_spaces = 8
-
-# Highlight lines with converted-only data if non-zero (same as --highlight
-# option of genhtml)
-genhtml_highlight = 0
-
-# Include color legend in HTML output if non-zero (same as --legend option of
-# genhtml)
-genhtml_legend = 0
-
-# Use FILE as HTML prolog for generated pages (same as --html-prolog option of
-# genhtml)
-#genhtml_html_prolog = FILE
-
-# Use FILE as HTML epilog for generated pages (same as --html-epilog option of
-# genhtml)
-#genhtml_html_epilog = FILE
-
-# Use custom filename extension for pages (same as --html-extension option of
-# genhtml)
-#genhtml_html_extension = html
-
-# Compress all generated html files with gzip.
-#genhtml_html_gzip = 1
-
-# Include sorted overview pages (can be disabled by the --no-sort option of
-# genhtml)
-genhtml_sort = 1
-
-# Include function coverage data display (can be disabled by the
-# --no-func-coverage option of genhtml)
-genhtml_function_coverage = 1
-
-# Include branch coverage data display (can be disabled by the
-# --no-branch-coverage option of genhtml)
-genhtml_branch_coverage = 1
-
-# Location of the gcov tool (same as --gcov-info option of geninfo)
-#geninfo_gcov_tool = gcov
-
-# Adjust test names to include operating system information if non-zero
-#geninfo_adjust_testname = 0
-
-# Calculate checksum for each source code line if non-zero (same as --checksum
-# option of geninfo if non-zero, same as --no-checksum if zero)
-#geninfo_checksum = 1
-
-# Enable libtool compatibility mode if non-zero (same as --compat-libtool option
-# of geninfo if non-zero, same as --no-compat-libtool if zero)
-#geninfo_compat_libtool = 0
-
-# Directory containing gcov kernel files
-# lcov_gcov_dir = /proc/gcov
-
-# Location of the insmod tool
-lcov_insmod_tool = /sbin/insmod
-
-# Location of the modprobe tool
-lcov_modprobe_tool = /sbin/modprobe
-
-# Location of the rmmod tool
-lcov_rmmod_tool = /sbin/rmmod
-
-# Location for temporary directories
-lcov_tmp_dir = /tmp
-
-# Show full paths during list operation if non-zero (same as --list-full-path
-# option of lcov)
-lcov_list_full_path = 0
-
-# Specify the maximum width for list output. This value is ignored when
-# lcov_list_full_path is non-zero.
-lcov_list_width = 80
-
-# Specify the maximum percentage of file names which may be truncated when
-# choosing a directory prefix in list output. This value is ignored when
-# lcov_list_full_path is non-zero.
-lcov_list_truncate_max = 20
diff --git a/third_party/lcov-1.9/man/gendesc.1 b/third_party/lcov-1.9/man/gendesc.1
deleted file mode 100644
index 64b805e..0000000
--- a/third_party/lcov-1.9/man/gendesc.1
+++ /dev/null
@@ -1,78 +0,0 @@
-.TH gendesc 1 "LCOV 1.9" 2010\-08\-06 "User Manuals"
-.SH NAME
-gendesc \- Generate a test case description file
-.SH SYNOPSIS
-.B gendesc
-.RB [ \-h | \-\-help ]
-.RB [ \-v | \-\-version ]
-.RS 8
-.br
-.RB [ \-o | \-\-output\-filename
-.IR filename ]
-.br
-.I inputfile
-.SH DESCRIPTION
-Convert plain text test case descriptions into a format as understood by
-.BR genhtml .
-.I inputfile
-needs to observe the following format:
-
-For each test case:
-.IP "     \-"
-one line containing the test case name beginning at the start of the line
-.RE
-.IP "     \-"
-one or more lines containing the test case description indented with at
-least one whitespace character (tab or space)
-.RE
-
-.B Example input file:
-
-test01
-.RS
-An example test case description.
-.br
-Description continued
-.RE
-
-test42
-.RS
-Supposedly the answer to most of your questions
-.RE
-
-Note: valid test names can consist of letters, decimal digits and the
-underscore character ('_').
-.SH OPTIONS
-.B \-h
-.br
-.B \-\-help
-.RS
-Print a short help text, then exit.
-.RE
-
-.B \-v
-.br
-.B \-\-version
-.RS
-Print version number, then exit.
-.RE
-
-
-.BI "\-o " filename
-.br
-.BI "\-\-output\-filename " filename
-.RS
-Write description data to
-.IR filename .
-
-By default, output is written to STDOUT.
-.RE
-.SH AUTHOR
-Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-
-.SH SEE ALSO
-.BR lcov (1),
-.BR genhtml (1),
-.BR geninfo (1),
-.BR genpng (1),
-.BR gcov (1)
diff --git a/third_party/lcov-1.9/man/genhtml.1 b/third_party/lcov-1.9/man/genhtml.1
deleted file mode 100644
index fc5b9f0..0000000
--- a/third_party/lcov-1.9/man/genhtml.1
+++ /dev/null
@@ -1,502 +0,0 @@
-.TH genhtml 1 "LCOV 1.9" 2010\-08\-06 "User Manuals"
-.SH NAME
-genhtml \- Generate HTML view from LCOV coverage data files
-.SH SYNOPSIS
-.B genhtml
-.RB [ \-h | \-\-help ]
-.RB [ \-v | \-\-version ]
-.RS 8
-.br
-.RB [ \-q | \-\-quiet ]
-.RB [ \-s | \-\-show\-details ]
-.RB [ \-f | \-\-frames ]
-.br
-.RB [ \-b | \-\-baseline\-file  ]
-.IR baseline\-file
-.br
-.RB [ \-o | \-\-output\-directory
-.IR output\-directory ]
-.br
-.RB [ \-t | \-\-title
-.IR title ]
-.br
-.RB [ \-d | \-\-description\-file
-.IR description\-file ]
-.br
-.RB [ \-k | \-\-keep\-descriptions ]
-.RB [ \-c | \-\-css\-file
-.IR css\-file ]
-.br
-.RB [ \-p | \-\-prefix
-.IR prefix ]
-.RB [ \-\-no\-prefix ]
-.br
-.RB [ \-\-no\-source ]
-.RB [ \-\-num\-spaces
-.IR num ]
-.RB [ \-\-highlight ]
-.br
-.RB [ \-\-legend ]
-.RB [ \-\-html\-prolog
-.IR prolog\-file ]
-.br
-.RB [ \-\-html\-epilog
-.IR epilog\-file ]
-.RB [ \-\-html\-extension
-.IR extension ]
-.br
-.RB [ \-\-html\-gzip ]
-.RB [ \-\-sort ]
-.RB [ \-\-no\-sort ]
-.br
-.RB [ \-\-function\-coverage ]
-.RB [ \-\-no\-function\-coverage ]
-.br
-.RB [ \-\-branch\-coverage ]
-.RB [ \-\-no\-branch\-coverage ]
-.br
-.RB [ \-\-demangle\-cpp ]
-.br
-.IR tracefile(s)
-.RE
-.SH DESCRIPTION
-Create an HTML view of coverage data found in
-.IR tracefile .
-Note that
-.I tracefile
-may also be a list of filenames.
-
-HTML output files are created in the current working directory unless the
-\-\-output\-directory option is used. If 
-.I tracefile
-ends with ".gz", it is assumed to be GZIP\-compressed and the gunzip tool
-will be used to decompress it transparently.
-
-Note that all source code files have to be present and readable at the
-exact file system location they were compiled.
-
-Use option
-.I \--css\-file
-to modify layout and colors of the generated HTML output. Files are
-marked in different colors depending on the associated coverage rate. By
-default, the coverage limits for low, medium and high coverage are set to
-0\-15%, 15\-50% and 50\-100% percent respectively. To change these
-values, use configuration file options
-.IR genhtml_hi_limit " and " genhtml_med_limit .
-
-.SH OPTIONS
-.B \-h
-.br
-.B \-\-help
-.RS
-Print a short help text, then exit.
-
-.RE
-.B \-v
-.br
-.B \-\-version
-.RS
-Print version number, then exit.
-
-.RE
-.B \-q
-.br
-.B \-\-quiet
-.RS
-Do not print progress messages.
-
-Suppresses all informational progress output. When this switch is enabled,
-only error or warning messages are printed.
-
-.RE
-.B \-f
-.br
-.B \-\-frames
-.RS
-Use HTML frames for source code view.
-
-If enabled, a frameset is created for each source code file, providing
-an overview of the source code as a "clickable" image. Note that this
-option will slow down output creation noticeably because each source
-code character has to be inspected once. Note also that the GD.pm PERL
-module has to be installed for this option to work (it may be obtained
-from http://www.cpan.org).
-
-.RE
-.B \-s
-.br
-.B \-\-show\-details
-.RS
-Generate detailed directory view.
-
-When this option is enabled,
-.B genhtml
-generates two versions of each
-file view. One containing the standard information plus a link to a
-"detailed" version. The latter additionally contains information about
-which test case covered how many lines of each source file.
-
-.RE
-.BI "\-b " baseline\-file
-.br
-.BI "\-\-baseline\-file " baseline\-file
-.RS
-Use data in
-.I baseline\-file
-as coverage baseline.
-
-The tracefile specified by
-.I baseline\-file
-is read and all counts found in the original
-.I tracefile
-are decremented by the corresponding counts in 
-.I baseline\-file
-before creating any output.
-
-Note that when a count for a particular line in
-.I baseline\-file
-is greater than the count in the
-.IR tracefile ,
-the result is zero.
-
-.RE
-.BI "\-o " output\-directory
-.br
-.BI "\-\-output\-directory " output\-directory
-.RS
-Create files in 
-.I output\-directory.
-
-Use this option to tell 
-.B genhtml
-to write the resulting files to a directory other than
-the current one. If 
-.I output\-directory
-does not exist, it will be created.
-
-It is advisable to use this option since depending on the
-project size, a lot of files and subdirectories may be created.
-
-.RE
-.BI "\-t " title
-.br
-.BI "\-\-title " title
-.RS
-Display 
-.I title
-in header of all pages.
-
-.I title
-is written to the header portion of each generated HTML page to
-identify the context in which a particular output
-was created. By default this is the name of the tracefile.
-
-.RE
-.BI "\-d " description\-file
-.br
-.BI "\-\-description\-file " description\-file
-.RS
-Read test case descriptions from 
-.IR description\-file .
-
-All test case descriptions found in
-.I description\-file
-and referenced in the input data file are read and written to an extra page
-which is then incorporated into the HTML output.
-
-The file format of
-.IR "description\-file " is:
-
-for each test case:
-.RS
-TN:<testname>
-.br
-TD:<test description>
-
-.RE
-
-Valid test case names can consist of letters, numbers and the underscore
-character ('_').
-.RE
-.B \-k
-.br
-.B \-\-keep\-descriptions
-.RS
-Do not remove unused test descriptions.
-
-Keep descriptions found in the description file even if the coverage data
-indicates that the associated test case did not cover any lines of code.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_keep_descriptions .
-
-.RE
-.BI "\-c " css\-file
-.br
-.BI "\-\-css\-file " css\-file
-.RS
-Use external style sheet file
-.IR css\-file .
-
-Using this option, an extra .css file may be specified which will replace
-the default one. This may be helpful if the default colors make your eyes want
-to jump out of their sockets :)
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_css_file .
-
-.RE
-.BI "\-p " prefix
-.br
-.BI "\-\-prefix " prefix
-.RS
-Remove 
-.I prefix
-from all directory names.
-
-Because lists containing long filenames are difficult to read, there is a
-mechanism implemented that will automatically try to shorten all directory
-names on the overview page beginning with a common prefix. By default,
-this is done using an algorithm that tries to find the prefix which, when
-applied, will minimize the resulting sum of characters of all directory
-names.
-
-Use this option to specify the prefix to be removed by yourself.
-
-.RE
-.B \-\-no\-prefix
-.RS
-Do not remove prefix from directory names.
-
-This switch will completely disable the prefix mechanism described in the
-previous section.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_no_prefix .
-
-.RE
-.B \-\-no\-source
-.RS
-Do not create source code view.
-
-Use this switch if you don't want to get a source code view for each file.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_no_source .
-
-.RE
-.BI "\-\-num\-spaces " spaces
-.RS
-Replace tabs in source view with
-.I num
-spaces.
-
-Default value is 8.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_num_spaces .
-
-.RE
-.B \-\-highlight
-.RS
-Highlight lines with converted\-only coverage data.
-
-Use this option in conjunction with the \-\-diff option of
-.B lcov
-to highlight those lines which were only covered in data sets which were
-converted from previous source code versions.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_highlight .
-
-.RE
-.B \-\-legend
-.RS
-Include color legend in HTML output.
-
-Use this option to include a legend explaining the meaning of color coding
-in the resulting HTML output.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_legend .
-
-.RE
-.BI "\-\-html\-prolog " prolog\-file
-.RS
-Read customized HTML prolog from 
-.IR prolog\-file .
-
-Use this option to replace the default HTML prolog (the initial part of the
-HTML source code leading up to and including the <body> tag) with the contents
-of
-.IR prolog\-file .
-Within the prolog text, the following words will be replaced when a page is generated:
-
-.B "@pagetitle@"
-.br
-The title of the page.
-
-.B "@basedir@"
-.br
-A relative path leading to the base directory (e.g. for locating css\-files).
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_html_prolog .
-
-.RE
-.BI "\-\-html\-epilog " epilog\-file
-.RS
-Read customized HTML epilog from 
-.IR epilog\-file .
-
-Use this option to replace the default HTML epilog (the final part of the HTML
-source including </body>) with the contents of
-.IR epilog\-file .
-
-Within the epilog text, the following words will be replaced when a page is generated:
-
-.B "@basedir@"
-.br
-A relative path leading to the base directory (e.g. for locating css\-files).
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_html_epilog .
-
-.RE
-.BI "\-\-html\-extension " extension
-.RS
-Use customized filename extension for generated HTML pages.
-
-This option is useful in situations where different filename extensions
-are required to render the resulting pages correctly (e.g. php). Note that
-a '.' will be inserted between the filename and the extension specified by
-this option.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_html_extension .
-.RE
-
-.B \-\-html\-gzip
-.RS
-Compress all generated html files with gzip and add a .htaccess file specifying
-gzip\-encoding in the root output directory.
-
-Use this option if you want to save space on your webserver. Requires a
-webserver with .htaccess support and a browser with support for gzip
-compressed html.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_html_gzip .
-
-.RE
-.B \-\-sort
-.br
-.B \-\-no\-sort
-.RS
-Specify whether to include sorted views of file and directory overviews.
-
-Use \-\-sort to include sorted views or \-\-no\-sort to not include them.
-Sorted views are
-.B enabled
-by default.
-
-When sorted views are enabled, each overview page will contain links to
-views of that page sorted by coverage rate.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_sort .
-
-.RE
-.B \-\-function\-coverage
-.br
-.B \-\-no\-function\-coverage
-.RS
-Specify whether to display function coverage summaries in HTML output.
-
-Use \-\-function\-coverage to enable function coverage summaries or
-\-\-no\-function\-coverage to disable it. Function coverage summaries are
-.B enabled
-by default
-
-When function coverage summaries are enabled, each overview page will contain
-the number of functions found and hit per file or directory, together with
-the resulting coverage rate. In addition, each source code view will contain
-a link to a page which lists all functions found in that file plus the
-respective call count for those functions.
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_function_coverage .
-
-.RE
-.B \-\-branch\-coverage
-.br
-.B \-\-no\-branch\-coverage
-.RS
-Specify whether to display branch coverage data in HTML output.
-
-Use \-\-branch\-coverage to enable branch coverage display or
-\-\-no\-branch\-coverage to disable it. Branch coverage data display is
-.B enabled
-by default
-
-When branch coverage display is enabled, each overview page will contain
-the number of branches found and hit per file or directory, together with
-the resulting coverage rate. In addition, each source code view will contain
-an extra column which lists all branches of a line with indications of
-whether the branch was taken or not. Branches are shown in the following format:
-
- ' + ': Branch was taken at least once
-.br
- ' - ': Branch was not taken
-.br
- ' # ': The basic block containing the branch was never executed
-.br
-
-This option can also be configured permanently using the configuration file
-option
-.IR genhtml_branch_coverage .
-
-.RE
-.B \-\-demangle\-cpp
-.RS
-Specify whether to demangle C++ function names.
-
-Use this option if you want to convert C++ internal function names to
-human readable format for display on the HTML function overview page.
-This option requires that the c++filt tool is installed (see
-.BR c++filt (1)).
-
-.SH FILES
-
-.I /etc/lcovrc
-.RS
-The system\-wide configuration file.
-.RE
-
-.I ~/.lcovrc
-.RS
-The per\-user configuration file.
-.RE
-
-.SH AUTHOR
-Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-
-.SH SEE ALSO
-.BR lcov (1),
-.BR geninfo (1),
-.BR genpng (1),
-.BR gendesc (1),
-.BR gcov (1)
diff --git a/third_party/lcov-1.9/man/geninfo.1 b/third_party/lcov-1.9/man/geninfo.1
deleted file mode 100644
index 488c1b4..0000000
--- a/third_party/lcov-1.9/man/geninfo.1
+++ /dev/null
@@ -1,366 +0,0 @@
-.TH geninfo 1 "LCOV 1.9" 2010\-08\-06 "User Manuals"
-.SH NAME
-geninfo \- Generate tracefiles from .da files
-.SH SYNOPSIS
-.B geninfo
-.RB [ \-h | \-\-help ]
-.RB [ \-v | \-\-version ]
-.RB [ \-q | \-\-quiet ]
-.br
-.RS 8
-.RB [ \-i | \-\-initial ]
-.RB [ \-t | \-\-test\-name
-.IR test\-name ]
-.br
-.RB [ \-o | \-\-output\-filename
-.IR filename ]
-.RB [ \-f | \-\-follow ]
-.br
-.RB [ \-b | \-\-base\-directory
-.IR directory ]
-.br
-.RB [ \-\-checksum ]
-.RB [ \-\-no\-checksum ]
-.br
-.RB [ \-\-compat\-libtool ]
-.RB [ \-\-no\-compat\-libtool ]
-.br
-.RB [ \-\-gcov\-tool
-.IR tool  ]
-.RB [ \-\-ignore\-errors
-.IR errors  ]
-.br
-.RB [ \-\-no\-recursion ]
-.I directory
-.RE
-.SH DESCRIPTION
-.B geninfo 
-converts all GCOV coverage data files found in 
-.I directory
-into tracefiles, which the
-.B genhtml
-tool can convert to HTML output.
-
-Unless the \-\-output\-filename option is specified,
-.B geninfo
-writes its
-output to one file per .da file, the name of which is generated by simply
-appending ".info" to the respective .da file name.
-
-Note that the current user needs write access to both
-.I directory
-as well as to the original source code location. This is necessary because
-some temporary files have to be created there during the conversion process.
-
-Note also that
-.B geninfo
-is called from within
-.BR lcov ,
-so that there is usually no need to call it directly.
-
-.B Exclusion markers
-
-To exclude specific lines of code from a tracefile, you can add exclusion
-markers to the source code. Exclusion markers are keywords which can for
-example be added in the form of a comment.
-
-The following markers are recognized by geninfo:
-
-LCOV_EXCL_LINE
-.RS
-Lines containing this marker will be excluded.
-.br
-.RE
-LCOV_EXCL_START
-.RS
-Marks the beginning of an excluded section. The current line is part of this
-section.
-.br
-.RE
-LCOV_EXCL_STOP
-.RS
-Marks the end of an excluded section. The current line not part of this
-section.
-.RE
-.br
-
-.SH OPTIONS
-
-.B \-b
-.I directory
-.br
-.B \-\-base\-directory
-.I directory
-.br
-.RS
-.RI "Use " directory
-as base directory for relative paths.
-
-Use this option to specify the base directory of a build\-environment
-when geninfo produces error messages like:
-
-.RS
-ERROR: could not read source file /home/user/project/subdir1/subdir2/subdir1/subdir2/file.c
-.RE
-
-In this example, use /home/user/project as base directory.
-
-This option is required when using geninfo on projects built with libtool or
-similar build environments that work with a base directory, i.e. environments,
-where the current working directory when invoking the compiler is not the same
-directory in which the source code file is located.
-
-Note that this option will not work in environments where multiple base
-directories are used. In that case repeat the geninfo call for each base
-directory while using the \-\-ignore\-errors option to prevent geninfo from
-exiting when the first source code file could not be found. This way you can
-get partial coverage information for each base directory which can then be
-combined using the \-a option.
-.RE
-
-.B \-\-checksum
-.br
-.B \-\-no\-checksum
-.br
-.RS
-Specify whether to generate checksum data when writing tracefiles.
-
-Use \-\-checksum to enable checksum generation or \-\-no\-checksum to
-disable it. Checksum generation is
-.B disabled
-by default.
-
-When checksum generation is enabled, a checksum will be generated for each
-source code line and stored along with the coverage data. This checksum will
-be used to prevent attempts to combine coverage data from different source
-code versions.
-
-If you don't work with different source code versions, disable this option
-to speed up coverage data processing and to reduce the size of tracefiles.
-.RE
-
-.B \-\-compat\-libtool
-.br
-.B \-\-no\-compat\-libtool
-.br
-.RS
-Specify whether to enable libtool compatibility mode.
-
-Use \-\-compat\-libtool to enable libtool compatibility mode or \-\-no\-compat\-libtool
-to disable it. The libtool compatibility mode is
-.B enabled
-by default.
-
-When libtool compatibility mode is enabled, geninfo will assume that the source
-code relating to a .da file located in a directory named ".libs" can be
-found in its parent directory.
-
-If you have directories named ".libs" in your build environment but don't use
-libtool, disable this option to prevent problems when capturing coverage data.
-.RE
-
-.B \-f
-.br
-.B \-\-follow
-.RS
-Follow links when searching .da files.
-.RE
-
-.B \-\-gcov\-tool
-.I tool
-.br
-.RS
-Specify the location of the gcov tool.
-.RE
-
-.B \-h
-.br
-.B \-\-help
-.RS
-Print a short help text, then exit.
-.RE
-
-.B \-\-ignore\-errors
-.I errors
-.br
-.RS
-Specify a list of errors after which to continue processing.
-
-Use this option to specify a list of one or more classes of errors after which
-geninfo should continue processing instead of aborting.
-
-.I errors
-can be a comma\-separated list of the following keywords:
-
-.B gcov:
-the gcov tool returned with a non\-zero return code.
-
-.B source:
-the source code file for a data set could not be found.
-.RE
-
-.B \-i
-.br
-.B \-\-initial
-.RS
-Capture initial zero coverage data.
-
-Run geninfo with this option on the directories containing .bb, .bbg or .gcno
-files before running any test case. The result is a "baseline" coverage data
-file that contains zero coverage for every instrumented line and function.
-Combine this data file (using lcov \-a) with coverage data files captured
-after a test run to ensure that the percentage of total lines covered is
-correct even when not all object code files were loaded during the test.
-
-Note: currently, the \-\-initial option does not generate branch coverage
-information.
-.RE
-
-.B \-\-no\-recursion
-.br
-.RS
-Use this option if you want to get coverage data for the specified directory
-only without processing subdirectories.
-.RE
-
-.BI "\-o " output\-filename
-.br
-.BI "\-\-output\-filename " output\-filename
-.RS
-Write all data to
-.IR output\-filename .
-
-If you want to have all data written to a single file (for easier
-handling), use this option to specify the respective filename. By default,
-one tracefile will be created for each processed .da file.
-.RE
-
-.B \-q
-.br
-.B \-\-quiet
-.RS
-Do not print progress messages.
-
-Suppresses all informational progress output. When this switch is enabled,
-only error or warning messages are printed.
-.RE
-
-.BI "\-t " testname
-.br
-.BI "\-\-test\-name " testname
-.RS
-Use test case name 
-.I testname
-for resulting data. Valid test case names can consist of letters, decimal
-digits and the underscore character ('_').
-
-This proves useful when data from several test cases is merged (i.e. by
-simply concatenating the respective tracefiles) in which case a test
-name can be used to differentiate between data from each test case.
-.RE
-
-.B \-v
-.br
-.B \-\-version
-.RS
-Print version number, then exit.
-.RE
-
-
-.SH FILES
-
-.I /etc/lcovrc
-.RS
-The system\-wide configuration file.
-.RE
-
-.I ~/.lcovrc
-.RS
-The per\-user configuration file.
-.RE
-
-Following is a quick description of the tracefile format as used by
-.BR genhtml ", " geninfo " and " lcov .
-
-A tracefile is made up of several human\-readable lines of text,
-divided into sections. If available, a tracefile begins with the
-.I testname
-which is stored in the following format:
-
-  TN:<test name>
-
-For each source file referenced in the .da file, there is a section containing
-filename and coverage data:
-
-  SF:<absolute path to the source file>
-
-Following is a list of line numbers for each function name found in the
-source file:
-
-  FN:<line number of function start>,<function name>
-
-Next, there is a list of execution counts for each instrumented function:
-
-  FNDA:<execution count>,<function name>
-
-This list is followed by two lines containing the number of functions found
-and hit:
-
-  FNF:<number of functions found>
-  FNH:<number of function hit>
-
-Branch coverage information is stored which one line per branch:
-
-  BRDA:<line number>,<block number>,<branch number>,<taken>
-
-Block number and branch number are gcc internal IDs for the branch. Taken is
-either '-' if the basic block containing the branch was never executed or
-a number indicating how often that branch was taken.
-
-Branch coverage summaries are stored in two lines:
-
-  BRF:<number of branches found>
-  BRH:<number of branches hit>
-
-Then there is a list of execution counts for each instrumented line
-(i.e. a line which resulted in executable code):
-
-  DA:<line number>,<execution count>[,<checksum>]
-
-Note that there may be an optional checksum present for each instrumented
-line. The current
-.B geninfo
-implementation uses an MD5 hash as checksumming algorithm.
-
-At the end of a section, there is a summary about how many lines
-were found and how many were actually instrumented:
-
-  LH:<number of lines with a non\-zero execution count>
-  LF:<number of instrumented lines>
-
-Each sections ends with:
-
-  end_of_record
-
-In addition to the main source code file there are sections for all
-#included files which also contain executable code.
-
-Note that the absolute path of a source file is generated by interpreting
-the contents of the respective .bb file (see
-.BR "gcov " (1)
-for more information on this file type). Relative filenames are prefixed
-with the directory in which the .bb file is found.
-
-Note also that symbolic links to the .bb file will be resolved so that the
-actual file path is used instead of the path to a link. This approach is
-necessary for the mechanism to work with the /proc/gcov files.
-
-.SH AUTHOR
-Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-
-.SH SEE ALSO
-.BR lcov (1),
-.BR genhtml (1),
-.BR genpng (1),
-.BR gendesc (1),
-.BR gcov (1)
diff --git a/third_party/lcov-1.9/man/genpng.1 b/third_party/lcov-1.9/man/genpng.1
deleted file mode 100644
index b2a46ea..0000000
--- a/third_party/lcov-1.9/man/genpng.1
+++ /dev/null
@@ -1,101 +0,0 @@
-.TH genpng 1 "LCOV 1.9" 2010\-08\-06 "User Manuals"
-.SH NAME
-genpng \- Generate an overview image from a source file
-.SH SYNOPSIS
-.B genpng
-.RB [ \-h | \-\-help ]
-.RB [ \-v | \-\-version ]
-.RS 7
-.br
-.RB [ \-t | \-\-tab\-size
-.IR tabsize ]
-.RB [ \-w | \-\-width
-.IR width ]
-.br
-.RB [ \-o | \-\-output\-filename
-.IR output\-filename ]
-.br
-.IR source\-file
-.SH DESCRIPTION
-.B genpng
-creates an overview image for a given source code file of either
-plain text or .gcov file format.
-
-Note that the
-.I GD.pm
-PERL module has to be installed for this script to work
-(it may be obtained from
-.IR http://www.cpan.org ).
-
-Note also that
-.B genpng
-is called from within
-.B genhtml
-so that there is usually no need to call it directly.
-
-.SH OPTIONS
-.B \-h
-.br
-.B \-\-help
-.RS
-Print a short help text, then exit.
-.RE
-
-.B \-v
-.br
-.B \-\-version
-.RS
-Print version number, then exit.
-.RE
-
-.BI "\-t " tab\-size
-.br
-.BI "\-\-tab\-size " tab\-size
-.RS
-Use 
-.I tab\-size
-spaces in place of tab.
-
-All occurrences of tabulator signs in the source code file will be replaced
-by the number of spaces defined by
-.I tab\-size
-(default is 4).
-.RE
-
-.BI "\-w " width
-.br
-.BI "\-\-width " width
-.RS
-Set width of output image to 
-.I width
-pixel.
-
-The resulting image will be exactly
-.I width
-pixel wide (default is 80).
-
-Note that source code lines which are longer than
-.I width
-will be truncated.
-.RE
-
-
-.BI "\-o " filename
-.br
-.BI "\-\-output\-filename " filename
-.RS
-Write image to
-.IR filename .
-
-Specify a name for the resulting image file (default is 
-.IR source\-file .png).
-.RE
-.SH AUTHOR
-Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-
-.SH SEE ALSO
-.BR lcov (1),
-.BR genhtml (1),
-.BR geninfo (1),
-.BR gendesc (1),
-.BR gcov (1)
diff --git a/third_party/lcov-1.9/man/lcov.1 b/third_party/lcov-1.9/man/lcov.1
deleted file mode 100644
index 184c5b4..0000000
--- a/third_party/lcov-1.9/man/lcov.1
+++ /dev/null
@@ -1,707 +0,0 @@
-.TH lcov 1 "LCOV 1.9" 2010\-08\-06 "User Manuals"
-.SH NAME
-lcov \- a graphical GCOV front\-end
-.SH SYNOPSIS
-.B lcov
-.BR \-c | \-\-capture
-.RS 5
-.br
-.RB [ \-d | \-\-directory
-.IR directory ]
-.RB [ \-k | \-\-kernel\-directory
-.IR directory ]
-.br
-.RB [ \-o | \-\-output\-file
-.IR tracefile ]
-.RB [ \-t | \-\-test\-name
-.IR testname ]
-.br
-.RB [ \-b | \-\-base\-directory
-.IR directory ]
-.RB [ \-i | \-\-initial ]
-.RB [ \-\-gcov\-tool
-.IR tool ]
-.br
-.RB [ \-\-checksum ]
-.RB [ \-\-no\-checksum ]
-.RB [ \-\-no\-recursion ]
-.RB [ \-f | \-\-follow ]
-.br
-.RB [ \-\-compat\-libtool ]
-.RB [ \-\-no\-compat\-libtool ]
-.RB [ \-\-ignore\-errors
-.IR errors ]
-.br
-.RB [ \-\-to\-package
-.IR package ]
-.RB [ \-\-from\-package
-.IR package ]
-.RB [ \-q | \-\-quiet ]
-.br
-.RB [ \-\-no\-markers ]
-.br
-.RE
-
-.B lcov
-.BR \-z | \-\-zerocounters
-.RS 5
-.br
-.RB [ \-d | \-\-directory
-.IR directory ]
-.RB [ \-\-no\-recursion ]
-.RB [ \-f | \-\-follow ]
-.br
-.RB [ \-q | \-\-quiet ]
-.br
-.RE
-
-.B lcov
-.BR \-l | \-\-list
-.I tracefile
-.RS 5
-.br
-.RB [ \-q | \-\-quiet ]
-.RB [ \-\-list\-full\-path ]
-.RB [ \-\-no\-list\-full\-path ]
-.br
-.RE
-
-.B lcov
-.BR \-a | \-\-add\-tracefile
-.I tracefile
-.RS 5
-.br
-.RB [ \-o | \-\-output\-file
-.IR tracefile ]
-.RB [ \-\-checksum ]
-.RB [ \-\-no\-checksum ]
-.br
-.RB [ \-q | \-\-quiet ]
-.br
-.RE
-
-.B lcov
-.BR \-e | \-\-extract
-.I tracefile pattern
-.RS 5
-.br
-.RB [ \-o | \-\-output\-file
-.IR tracefile ]
-.RB [ \-\-checksum ]
-.RB [ \-\-no\-checksum ]
-.br
-.RB [ \-q | \-\-quiet ]
-.RE
-
-.B lcov
-.BR \-r | \-\-remove
-.I tracefile pattern
-.RS 5
-.br
-.RB [ \-o | \-\-output\-file
-.IR tracefile ]
-.RB [ \-\-checksum ]
-.RB [ \-\-no\-checksum ]
-.br
-.RB [ \-q | \-\-quiet ]
-.br
-.RE
-
-.B lcov
-.BR \-\-diff
-.IR "tracefile diff"
-.RS 5
-.br
-.RB [ \-o | \-\-output\-file
-.IR tracefile ]
-.RB [ \-\-checksum ]
-.RB [ \-\-no\-checksum ]
-.br
-.RB [ \-\-convert\-filenames ]
-.RB [ \-\-strip
-.IR depth ]
-.RB [ \-\-path
-.IR path ]
-.RB [ \-q | \-\-quiet ]
-.br
-.RE
-
-.B lcov
-.RB [ \-h | \-\-help ]
-.RB [ \-v | \-\-version ]
-.RS 5
-.br
-.RE
-
-.SH DESCRIPTION
-.B lcov
-is a graphical front\-end for GCC's coverage testing tool gcov. It collects
-line, function and branch coverage data for multiple source files and creates
-HTML pages containing the source code annotated with coverage information.
-It also adds overview pages for easy navigation within the file structure.
-
-Use
-.B lcov
-to collect coverage data and
-.B genhtml
-to create HTML pages. Coverage data can either be collected from the
-currently running Linux kernel or from a user space application. To do this,
-you have to complete the following preparation steps:
-
-For Linux kernel coverage:
-.RS
-Follow the setup instructions for the gcov\-kernel infrastructure:
-.I http://ltp.sourceforge.net/coverage/gcov.php
-.br
-
-
-.RE
-For user space application coverage:
-.RS
-Compile the application with GCC using the options
-"\-fprofile\-arcs" and "\-ftest\-coverage".
-.RE
-
-Please note that this man page refers to the output format of
-.B lcov
-as ".info file" or "tracefile" and that the output of GCOV
-is called ".da file".
-.SH OPTIONS
-
-
-.B \-a
-.I tracefile
-.br
-.B \-\-add\-tracefile
-.I tracefile
-.br
-.RS
-Add contents of
-.IR tracefile .
-
-Specify several tracefiles using the \-a switch to combine the coverage data
-contained in these files by adding up execution counts for matching test and
-filename combinations.
-
-The result of the add operation will be written to stdout or the tracefile
-specified with \-o.
-
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
-
-.RE
-
-.B \-b
-.I directory
-.br
-.B \-\-base\-directory
-.I directory
-.br
-.RS
-.RI "Use " directory
-as base directory for relative paths.
-
-Use this option to specify the base directory of a build\-environment
-when lcov produces error messages like:
-
-.RS
-ERROR: could not read source file /home/user/project/subdir1/subdir2/subdir1/subdir2/file.c
-.RE
-
-In this example, use /home/user/project as base directory.
-
-This option is required when using lcov on projects built with libtool or
-similar build environments that work with a base directory, i.e. environments,
-where the current working directory when invoking the compiler is not the same
-directory in which the source code file is located.
-
-Note that this option will not work in environments where multiple base
-directories are used. In that case repeat the lcov call for each base directory
-while using the \-\-ignore\-errors option to prevent lcov from exiting when the
-first source code file could not be found. This way you can get partial coverage
-information for each base directory which can then be combined using the \-a
-option.
-.RE
-
-.B \-c
-.br
-.B \-\-capture
-.br
-.RS
-Capture coverage data.
-
-By default captures the current kernel execution counts and writes the
-resulting coverage data to the standard output. Use the \-\-directory
-option to capture counts for a user space program.
-
-The result of the capture operation will be written to stdout or the tracefile
-specified with \-o.
-
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
-.RE
-
-.B \-\-checksum
-.br
-.B \-\-no\-checksum
-.br
-.RS
-Specify whether to generate checksum data when writing tracefiles.
-
-Use \-\-checksum to enable checksum generation or \-\-no\-checksum to
-disable it. Checksum generation is
-.B disabled
-by default.
-
-When checksum generation is enabled, a checksum will be generated for each
-source code line and stored along with the coverage data. This checksum will
-be used to prevent attempts to combine coverage data from different source
-code versions.
-
-If you don't work with different source code versions, disable this option
-to speed up coverage data processing and to reduce the size of tracefiles.
-.RE
-
-.B \-\-compat\-libtool
-.br
-.B \-\-no\-compat\-libtool
-.br
-.RS
-Specify whether to enable libtool compatibility mode.
-
-Use \-\-compat\-libtool to enable libtool compatibility mode or \-\-no\-compat\-libtool
-to disable it. The libtool compatibility mode is
-.B enabled
-by default.
-
-When libtool compatibility mode is enabled, lcov will assume that the source
-code relating to a .da file located in a directory named ".libs" can be
-found in its parent directory.
-
-If you have directories named ".libs" in your build environment but don't use
-libtool, disable this option to prevent problems when capturing coverage data.
-.RE
-
-.B \-\-convert\-filenames
-.br
-.RS
-Convert filenames when applying diff.
-
-Use this option together with \-\-diff to rename the file names of processed
-data sets according to the data provided by the diff.
-.RE
-
-.B \-\-diff
-.I tracefile
-.I difffile
-.br
-.RS
-Convert coverage data in
-.I tracefile
-using source code diff file
-.IR difffile .
-
-Use this option if you want to merge coverage data from different source code
-levels of a program, e.g. when you have data taken from an older version
-and want to combine it with data from a more current version.
-.B lcov
-will try to map source code lines between those versions and adjust the coverage
-data respectively.
-.I difffile
-needs to be in unified format, i.e. it has to be created using the "\-u" option
-of the
-.B diff
-tool.
-
-Note that lines which are not present in the old version will not be counted
-as instrumented, therefore tracefiles resulting from this operation should
-not be interpreted individually but together with other tracefiles taken
-from the newer version. Also keep in mind that converted coverage data should
-only be used for overview purposes as the process itself introduces a loss
-of accuracy.
-
-The result of the diff operation will be written to stdout or the tracefile
-specified with \-o.
-
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
-.RE
-
-.B \-d
-.I directory
-.br
-.B \-\-directory
-.I  directory
-.br
-.RS
-Use .da files in
-.I directory
-instead of kernel.
-
-If you want to work on coverage data for a user space program, use this
-option to specify the location where the program was compiled (that's
-where the counter files ending with .da will be stored).
-
-Note that you may specify this option more than once.
-.RE
-
-.B \-e
-.I tracefile
-.I pattern
-.br
-.B \-\-extract
-.I tracefile
-.I pattern
-.br
-.RS
-Extract data from
-.IR tracefile .
-
-Use this switch if you want to extract coverage data for only a particular
-set of files from a tracefile. Additional command line parameters will be
-interpreted as shell wildcard patterns (note that they may need to be
-escaped accordingly to prevent the shell from expanding them first).
-Every file entry in
-.I tracefile
-which matches at least one of those patterns will be extracted.
-
-The result of the extract operation will be written to stdout or the tracefile
-specified with \-o.
-
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
-.RE
-
-.B \-f
-.br
-.B \-\-follow
-.br
-.RS
-Follow links when searching for .da files.
-.RE
-
-.B \-\-from\-package
-.I package
-.br
-.RS
-Use .da files in
-.I package
-instead of kernel or directory.
-
-Use this option if you have separate machines for build and test and
-want to perform the .info file creation on the build machine. See
-\-\-to\-package for more information.
-.RE
-
-.B \-\-gcov\-tool
-.I tool
-.br
-.RS
-Specify the location of the gcov tool.
-.RE
-
-.B \-h
-.br
-.B \-\-help
-.br
-.RS
-Print a short help text, then exit.
-.RE
-
-.B \-\-ignore\-errors
-.I errors
-.br
-.RS
-Specify a list of errors after which to continue processing.
-
-Use this option to specify a list of one or more classes of errors after which
-lcov should continue processing instead of aborting.
-
-.I errors
-can be a comma\-separated list of the following keywords:
-
-.B gcov:
-the gcov tool returned with a non\-zero return code.
-
-.B source:
-the source code file for a data set could not be found.
-.RE
-
-.B \-i
-.br
-.B \-\-initial
-.RS
-Capture initial zero coverage data.
-
-Run lcov with \-c and this option on the directories containing .bb, .bbg
-or .gcno files before running any test case. The result is a "baseline"
-coverage data file that contains zero coverage for every instrumented line.
-Combine this data file (using lcov \-a) with coverage data files captured
-after a test run to ensure that the percentage of total lines covered is
-correct even when not all source code files were loaded during the test.
-
-Recommended procedure when capturing data for a test case:
-
-1. create baseline coverage data file
-.RS
-# lcov \-c \-i \-d appdir \-o app_base.info
-.br
-
-.RE
-2. perform test
-.RS
-# appdir/test
-.br
-
-.RE
-3. create test coverage data file
-.RS
-# lcov \-c \-d appdir \-o app_test.info
-.br
-
-.RE
-4. combine baseline and test coverage data
-.RS
-# lcov \-a app_base.info \-a app_test.info \-o app_total.info
-.br
-
-.RE
-.RE
-
-.B \-k
-.I subdirectory
-.br
-.B \-\-kernel\-directory
-.I subdirectory
-.br
-.RS
-Capture kernel coverage data only from
-.IR subdirectory .
-
-Use this option if you don't want to get coverage data for all of the
-kernel, but only for specific subdirectories. This option may be specified
-more than once.
-
-Note that you may need to specify the full path to the kernel subdirectory
-depending on the version of the kernel gcov support.
-.RE
-
-.B \-l
-.I tracefile
-.br
-.B \-\-list
-.I tracefile
-.br
-.RS
-List the contents of the
-.IR tracefile .
-
-Only one of  \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
-.RE
-
-.B \-\-list\-full\-path
-.br
-.B \-\-no\-list\-full\-path
-.br
-.RS
-Specify whether to show full paths during list operation.
-
-Use \-\-list\-full\-path to show full paths during list operation
-or \-\-no\-list\-full\-path to show shortened paths. Paths are
-.B shortened
-by default.
-.RE
-
-.B \-\-no\-markers
-.br
-.RS
-Use this option if you want to get coverage data without regard to exclusion
-markers in the source code file. See
-.BR "geninfo " (1)
-for details on exclusion markers.
-.RE
-
-.B \-\-no\-recursion
-.br
-.RS
-Use this option if you want to get coverage data for the specified directory
-only without processing subdirectories.
-.RE
-
-.B \-o
-.I tracefile
-.br
-.B \-\-output\-file
-.I tracefile
-.br
-.RS
-Write data to
-.I tracefile
-instead of stdout.
-
-Specify "\-" as a filename to use the standard output.
-
-By convention, lcov\-generated coverage data files are called "tracefiles" and
-should have the filename extension ".info".
-.RE
-
-.B \-\-path
-.I path
-.br
-.RS
-Strip path from filenames when applying diff.
-
-Use this option together with \-\-diff to tell lcov to disregard the specified
-initial path component when matching between tracefile and diff filenames.
-.RE
-
-.B \-q
-.br
-.B \-\-quiet
-.br
-.RS
-Do not print progress messages.
-
-This option is implied when no output filename is specified to prevent
-progress messages to mess with coverage data which is also printed to
-the standard output.
-.RE
-
-.B \-r
-.I tracefile
-.I pattern
-.br
-.B \-\-remove
-.I tracefile
-.I pattern
-.br
-.RS
-Remove data from
-.IR tracefile .
-
-Use this switch if you want to remove coverage data for a particular
-set of files from a tracefile. Additional command line parameters will be
-interpreted as shell wildcard patterns (note that they may need to be
-escaped accordingly to prevent the shell from expanding them first).
-Every file entry in
-.I tracefile
-which matches at least one of those patterns will be removed.
-
-The result of the remove operation will be written to stdout or the tracefile
-specified with \-o.
-
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
-.RE
-
-.B \-\-strip
-.I depth
-.br
-.RS
-Strip path components when applying diff.
-
-Use this option together with \-\-diff to tell lcov to disregard the specified
-number of initial directories when matching tracefile and diff filenames.
-.RE
-
-.B \-t
-.I testname
-.br
-.B \-\-test\-name
-.I testname
-.br
-.RS
-Specify test name to be stored in the tracefile.
-
-This name identifies a coverage data set when more than one data set is merged
-into a combined tracefile (see option \-a).
-
-Valid test names can consist of letters, decimal digits and the underscore
-character ("_").
-.RE
-
-.B \-\-to\-package
-.I package
-.br
-.RS
-Store .da files for later processing.
-
-Use this option if you have separate machines for build and test and
-want to perform the .info file creation on the build machine. To do this,
-follow these steps:
-
-On the test machine:
-.RS
-.br
-\- run the test
-.br
-\- run lcov \-c [\-d directory] \-\-to-package
-.I file
-.br
-\- copy
-.I file
-to the build machine
-.RE
-.br
-
-On the build machine:
-.RS
-.br
-\- run lcov \-c \-\-from-package
-.I file
-[\-o and other options]
-.RE
-.br
-
-This works for both kernel and user space coverage data. Note that you might
-have to specify the path to the build directory using \-b with
-either \-\-to\-package or \-\-from-package. Note also that the package data
-must be converted to a .info file before recompiling the program or it will
-become invalid.
-.RE
-
-.B \-v
-.br
-.B \-\-version
-.br
-.RS
-Print version number, then exit.
-.RE
-
-.B \-z
-.br
-.B \-\-zerocounters
-.br
-.RS
-Reset all execution counts to zero.
-
-By default tries to reset kernel execution counts. Use the \-\-directory
-option to reset all counters of a user space program.
-
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
-.RE
-
-.SH FILES
-
-.I /etc/lcovrc
-.RS
-The system\-wide configuration file.
-.RE
-
-.I ~/.lcovrc
-.RS
-The per\-user configuration file.
-.RE
-
-.SH AUTHOR
-Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
-
-.SH SEE ALSO
-.BR lcovrc (5),
-.BR genhtml (1),
-.BR geninfo (1),
-.BR genpng (1),
-.BR gendesc (1),
-.BR gcov (1)
diff --git a/third_party/lcov-1.9/man/lcovrc.5 b/third_party/lcov-1.9/man/lcovrc.5
deleted file mode 100644
index 3258ba0..0000000
--- a/third_party/lcov-1.9/man/lcovrc.5
+++ /dev/null
@@ -1,608 +0,0 @@
-.TH lcovrc 5 "LCOV 1.9" 2010\-08\-06 "User Manuals"
-
-.SH NAME
-lcovrc \- lcov configuration file
-
-.SH DESCRIPTION
-The
-.I lcovrc
-file contains configuration information for the
-.B lcov
-code coverage tool (see
-.BR lcov (1)).
-.br
-
-The system\-wide configuration file is located at
-.IR /etc/lcovrc .
-To change settings for a single user, place a customized copy of this file at
-location
-.IR ~/.lcovrc .
-Where available, command\-line options override configuration file settings.
-
-Lines in a configuration file can either be:
-.IP "     *"
-empty lines or lines consisting only of white space characters. These lines are
-ignored.
-.IP "     *"
-comment lines which start with a hash sign ('#'). These are treated like empty
-lines and will be ignored.
-.IP "     *"
-statements in the form
-.RI ' key " = " value '.
-A list of valid statements and their description can be found in
-section 'OPTIONS' below.
-.PP
-
-.B Example configuration:
-.IP
-#
-.br
-# Example LCOV configuration file
-.br
-#
-.br
-
-# External style sheet file
-.br
-#genhtml_css_file = gcov.css
-.br
-
-# Coverage rate limits
-.br
-genhtml_hi_limit = 90
-.br
-genhtml_med_limit = 75
-.br
-
-# Width of line coverage field in source code view
-.br
-genhtml_line_field_width = 12
-.br
-
-# Width of branch coverage field in source code view
-.br
-genhtml_branch_field_width = 16
-.br
-
-# Width of overview image
-.br
-genhtml_overview_width = 80
-.br
-
-# Resolution of overview navigation
-.br
-genhtml_nav_resolution = 4
-.br
-
-# Offset for source code navigation
-.br
-genhtml_nav_offset = 10
-.br
-
-# Do not remove unused test descriptions if non\-zero
-.br
-genhtml_keep_descriptions = 0
-.br
-
-# Do not remove prefix from directory names if non\-zero
-.br
-genhtml_no_prefix = 0
-.br
-
-# Do not create source code view if non\-zero
-.br
-genhtml_no_source = 0
-.br
-
-# Specify size of tabs
-.br
-genhtml_num_spaces = 8
-.br
-
-# Highlight lines with converted\-only data if non\-zero
-.br
-genhtml_highlight = 0
-.br
-
-# Include color legend in HTML output if non\-zero
-.br
-genhtml_legend = 0
-.br
-
-# Include HTML file at start of HTML output
-.br
-#genhtml_html_prolog = prolog.html
-.br
-
-# Include HTML file at end of HTML output
-.br
-#genhtml_html_epilog = epilog.html
-.br
-
-# Use custom HTML file extension
-.br
-#genhtml_html_extension = html
-.br
-
-# Compress all generated html files with gzip.
-.br
-#genhtml_html_gzip = 1
-.br
-
-# Include sorted overview pages
-.br
-genhtml_sort = 1
-.br
-
-# Include function coverage data display
-.br
-genhtml_function_coverage = 1
-.br
-
-# Include branch coverage data display
-.br
-genhtml_branch_coverage = 1
-.br
-
-# Location of the gcov tool
-.br
-#geninfo_gcov_tool = gcov
-.br
-
-# Adjust test names if non\-zero
-.br
-#geninfo_adjust_testname = 0
-.br
-
-# Calculate a checksum for each line if non\-zero
-.br
-geninfo_checksum = 0
-.br
-
-# Enable libtool compatibility mode if non\-zero
-.br
-geninfo_compat_libtool = 0
-.br
-
-# Directory containing gcov kernel files
-.br
-lcov_gcov_dir = /proc/gcov
-.br
-
-# Location for temporary directories
-.br
-lcov_tmp_dir = /tmp
-.br
-
-# Show full paths during list operation if non\-zero
-.br
-lcov_list_full_path = 0
-.br
-
-# Specify the maximum width for list output. This value is
-.br
-# ignored when lcov_list_full_path is non\-zero.
-.br
-lcov_list_width = 80
-.br
-
-# Specify the maximum percentage of file names which may be
-.br
-# truncated when choosing a directory prefix in list output.
-.br
-# This value is ignored when lcov_list_full_path is non\-zero.
-.br
-
-lcov_list_truncate_max = 20
-.PP
-
-.SH OPTIONS
-
-.BR genhtml_css_file " ="
-.I filename
-.IP
-Specify an external style sheet file. Use this option to modify the appearance of the HTML output as generated by
-.BR genhtml .
-During output generation, a copy of this file will be placed in the output
-directory.
-.br
-
-This option corresponds to the \-\-css\-file command line option of
-.BR genhtml .
-.br
-
-By default, a standard CSS file is generated.
-.PP
-
-.BR genhtml_hi_limit "  ="
-.I hi_limit
-.br
-.BR genhtml_med_limit " ="
-.I med_limit
-.br
-.IP
-Specify coverage rate limits for classifying file entries. Use this option to
-modify the coverage rates (in percent) for line, function and branch coverage at
-which a result is classified as high, medium or low coverage. This
-classification affects the color of the corresponding entries on the overview
-pages of the HTML output:
-.br
-
-High:   hi_limit  <= rate <= 100        default color: green
-.br
-Medium: med_limit <= rate < hi_limit    default color: orange
-.br
-Low:    0         <= rate < med_limit   default color: red
-.br
-
-Defaults are 90 and 75 percent.
-.PP
-
-.BR genhtml_line_field_width " ="
-.I number_of_characters
-.IP
-Specify the width (in characters) of the source code view column containing
-line coverage information.
-.br
-
-Default is 12.
-.PP
-
-.BR genhtml_branch_field_width " ="
-.I number_of_characters
-.IP
-Specify the width (in characters) of the source code view column containing
-branch coverage information.
-.br
-
-Default is 16.
-.PP
-
-.BR genhtml_overview_width " ="
-.I pixel_size
-.IP
-Specify the width (in pixel) of the overview image created when generating HTML
-output using the \-\-frames option of
-.BR genhtml .
-.br
-
-Default is 80.
-.PP
-
-.BR genhtml_nav_resolution " ="
-.I lines
-.IP
-Specify the resolution of overview navigation when generating HTML output using
-the \-\-frames option of
-.BR genhtml .
-This number specifies the maximum difference in lines between the position a
-user selected from the overview and the position the source code window is
-scrolled to.
-.br
-
-Default is 4.
-.PP
-
-
-.BR genhtml_nav_offset " ="
-.I lines
-.IP
-Specify the overview navigation line offset as applied when generating HTML
-output using the \-\-frames option of
-.BR genhtml.
-.br
-
-Clicking a line in the overview image should show the source code view at
-a position a bit further up, so that the requested line is not the first
-line in the window.  This number specifies that offset.
-.br
-
-Default is 10.
-.PP
-
-
-.BR genhtml_keep_descriptions " ="
-.IR 0 | 1
-.IP
-If non\-zero, keep unused test descriptions when generating HTML output using
-.BR genhtml .
-.br
-
-This option corresponds to the \-\-keep\-descriptions option of
-.BR genhtml .
-.br
-
-Default is 0.
-.PP
-
-.BR genhtml_no_prefix " ="
-.IR 0 | 1
-.IP
-If non\-zero, do not try to find and remove a common prefix from directory names.
-.br
-
-This option corresponds to the \-\-no\-prefix option of
-.BR genhtml .
-.br
-
-Default is 0.
-.PP
-
-.BR genhtml_no_source " ="
-.IR 0 | 1
-.IP
-If non\-zero, do not create a source code view when generating HTML output using
-.BR genhtml .
-.br
-
-This option corresponds to the \-\-no\-source option of
-.BR genhtml .
-.br
-
-Default is 0.
-.PP
-
-.BR genhtml_num_spaces " ="
-.I num
-.IP
-Specify the number of spaces to use as replacement for tab characters in the
-HTML source code view as generated by
-.BR genhtml .
-.br
-
-This option corresponds to the \-\-num\-spaces option of
-.BR genthml .
-.br
-
-Default is 8.
-
-.PP
-
-.BR genhtml_highlight " ="
-.IR 0 | 1
-.IP
-If non\-zero, highlight lines with converted\-only data in
-HTML output as generated by
-.BR genhtml .
-.br
-
-This option corresponds to the \-\-highlight option of
-.BR genhtml .
-.br
-
-Default is 0.
-.PP
-
-.BR genhtml_legend " ="
-.IR 0 | 1
-.IP
-If non\-zero, include a legend explaining the meaning of color coding in the HTML
-output as generated by
-.BR genhtml .
-.br
-
-This option corresponds to the \-\-legend option of
-.BR genhtml .
-.br
-
-Default is 0.
-.PP
-
-.BR genhtml_html_prolog " ="
-.I filename
-.IP
-If set, include the contents of the specified file at the beginning of HTML
-output.
-
-This option corresponds to the \-\-html\-prolog option of
-.BR genhtml .
-.br
-
-Default is to use no extra prolog.
-.PP
-
-.BR genhtml_html_epilog " ="
-.I filename
-.IP
-If set, include the contents of the specified file at the end of HTML output.
-
-This option corresponds to the \-\-html\-epilog option of
-.BR genhtml .
-.br
-
-Default is to use no extra epilog.
-.PP
-
-.BR genhtml_html_extension " ="
-.I extension
-.IP
-If set, use the specified string as filename extension for generated HTML files.
-
-This option corresponds to the \-\-html\-extension option of
-.BR genhtml .
-.br
-
-Default extension is "html".
-.PP
-
-.BR genhtml_html_gzip " ="
-.IR 0 | 1
-.IP
-If set, compress all html files using gzip.
-
-This option corresponds to the \-\-html\-gzip option of
-.BR genhtml .
-.br
-
-Default extension is 0.
-.PP
-
-.BR genhtml_sort " ="
-.IR 0 | 1
-.IP
-If non\-zero, create overview pages sorted by coverage rates when generating
-HTML output using
-.BR genhtml .
-.br
-
-This option can be set to 0 by using the \-\-no\-sort option of
-.BR genhtml .
-.br
-
-Default is 1.
-.PP
-
-.BR genhtml_function_coverage " ="
-.IR 0 | 1
-.IP
-If non\-zero, include function coverage data when generating HTML output using
-.BR genhtml .
-.br
-
-This option can be set to 0 by using the \-\-no\-function\-coverage option of
-.BR genhtml .
-.br
-
-Default is 1.
-.PP
-
-.BR genhtml_branch_coverage " ="
-.IR 0 | 1
-.IP
-If non\-zero, include branch coverage data when generating HTML output using
-.BR genhtml .
-.br
-
-This option can be set to 0 by using the \-\-no\-branch\-coverage option of
-.BR genhtml .
-.br
-
-Default is 1.
-.PP
-
-.BR geninfo_gcov_tool " ="
-.I path_to_gcov
-.IP
-Specify the location of the gcov tool (see
-.BR gcov (1))
-which is used to generate coverage information from data files. 
-.br
-
-Default is 'gcov'.
-.PP
-
-.BR geninfo_adjust_testname " ="
-.IR 0 | 1
-.IP
-If non\-zero,  adjust test names to include operating system information
-when capturing coverage data.
-.br
-
-Default is 0.
-.PP
-
-.BR geninfo_checksum " ="
-.IR 0 | 1
-.IP
-If non\-zero, generate source code checksums when capturing coverage data.
-Checksums are useful to prevent merging coverage data from incompatible
-source code versions but checksum generation increases the size of coverage
-files and the time used to generate those files.
-.br
-
-This option corresponds to the \-\-checksum and \-\-no\-checksum command line
-option of
-.BR geninfo .
-.br
-
-Default is 0.
-.PP
-
-.BR geninfo_compat_libtool " ="
-.IR 0 | 1
-.IP
-If non\-zero, enable libtool compatibility mode. When libtool compatibility
-mode is enabled, lcov will assume that the source code relating to a .da file
-located in a directory named ".libs" can be found in its parent directory.
-.br
-
-This option corresponds to the \-\-compat\-libtool and \-\-no\-compat\-libtool
-command line option of
-.BR geninfo .
-.br
-
-Default is 1.
-.PP
-
-.BR lcov_gcov_dir " ="
-.I path_to_kernel_coverage_data
-.IP
-Specify the path to the directory where kernel coverage data can be found
-or leave undefined for auto-detection.
-.br
-
-Default is auto-detection.
-.PP
-
-.BR lcov_tmp_dir " ="
-.I temp
-.IP
-Specify the location of a directory used for temporary files.
-.br
-
-Default is '/tmp'.
-.PP
-
-.BR lcov_list_full_path " ="
-.IR 0 | 1
-.IP
-If non-zero, print the full path to source code files during a list operation.
-.br
-
-This option corresponds to the \-\-list\-full\-path option of
-.BR lcov .
-.br
-
-Default is 0.
-.PP
-
-.BR lcov_list_max_width " ="
-.IR width
-.IP
-Specify the maximum width for list output. This value is ignored when
-lcov_list_full_path is non\-zero.
-.br
-
-Default is 80.
-.PP
-
-.BR lcov_list_truncate_max
-.B " ="
-.IR percentage
-.IP
-Specify the maximum percentage of file names which may be truncated when
-choosing a directory prefix in list output. This value is ignored when
-lcov_list_full_path is non\-zero.
-.br
-
-Default is 20.
-.PP
-
-.SH FILES
-
-.TP
-.I /etc/lcovrc
-The system\-wide
-.B lcov
-configuration file.
-
-.TP
-.I ~/.lcovrc
-The individual per\-user configuration file.
-.PP
-
-.SH SEE ALSO
-.BR lcov (1),
-.BR genhtml (1),
-.BR geninfo (1),
-.BR gcov (1)
diff --git a/third_party/lcov-1.9/rpm/lcov.spec b/third_party/lcov-1.9/rpm/lcov.spec
deleted file mode 100644
index ae9b8bf..0000000
--- a/third_party/lcov-1.9/rpm/lcov.spec
+++ /dev/null
@@ -1,48 +0,0 @@
-Summary: A graphical GCOV front-end
-Name: lcov
-Version: 1.9
-Release: 1
-License: GPL
-Group: Development/Tools
-URL: http://ltp.sourceforge.net/coverage/lcov.php
-Source0: http://downloads.sourceforge.net/ltp/lcov-%{version}.tar.gz
-BuildRoot: /var/tmp/%{name}-%{version}-root
-BuildArch: noarch
-
-%description
-LCOV is a graphical front-end for GCC's coverage testing tool gcov. It collects
-gcov data for multiple source files and creates HTML pages containing the
-source code annotated with coverage information. It also adds overview pages
-for easy navigation within the file structure.
-
-%prep
-%setup -q -n lcov-%{version}
-
-%build
-exit 0
-
-%install
-rm -rf $RPM_BUILD_ROOT
-make install PREFIX=$RPM_BUILD_ROOT
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files
-%defattr(-,root,root)
-/usr/bin
-/usr/share
-/etc
-
-%changelog
-* Wed Aug 13 2008 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
-- changed description + summary text
-* Mon Aug 20 2007 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
-- fixed "Copyright" tag
-* Mon Jul 14 2003 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
-- removed variables for version/release to support source rpm building
-- added initial rm command in install section
-* Mon Apr 7 2003 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
-- implemented variables for version/release
-* Fri Oct 8 2002 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
-- created initial spec file
diff --git a/third_party/lcov/CHANGES b/third_party/lcov/CHANGES
index bb67896..18cfcef 100644
--- a/third_party/lcov/CHANGES
+++ b/third_party/lcov/CHANGES
@@ -1,3 +1,183 @@
+Version 1.10
+============
+
+All:
+- Disabled branch coverage processing per default to improve processing
+  performance (can be re-enabled using a config file setting)
+- Added option --rc to override config file settings from the command line
+- Added option --config-file to override the config file location
+- Fixed handling of '<' in filenames
+
+genhtml:
+- Added option --ignore-errors to continue after errors
+- Added man page note to further explain branch coverage output
+- Fixed man page description of default coverage rates
+- Fixed HTML page title for directory pages
+- Fixed handling of special characters in file and directory names
+- Fixed directory prefix calculation
+- Fixed warning when source files are found in root directory
+
+geninfo:
+- Added options --external and --no-external to include/exclude external
+  source files such as standard libary headers
+- Added option --compat to specify compatibility modes
+- Added missing man page sections for --derive-func-data and --no-markers
+- Added support for MinGW output on MSYS. From martin.hopfeld@sse-erfurt.de
+- Added support for gcc 4.7 .gcno file format.  Based on patch by
+  berrange@redhat.com
+- Added auto-detection of gcc-4.7 function record format. Includes
+  suggestions by garnold@google.com
+- Fixed exclusion markers for --derive-func-data.  Reported by bettse@gmail.com
+- Fixed processing of pre-3.3 gcov files. Reported by georgysebastian@gmail.com
+- Fixed handling of '<built-in>.gcov' files
+- Fixed warning about unhandled .gcov files
+- Improved --debug output
+- Removed help text for obsolete parameter --function-coverage
+
+genpng:
+- Fixed handling of empty source files. Reported by: sylvestre@debian.org
+
+lcov:
+- Added options --external and --no-external to include/exclude external source
+  files such as standard libary headers
+- Added option --summary to show summary coverage information
+- Added option --compat to specify compatibility modes
+- Fixed missing Perl version dependency in RPM spec file. Reported by
+  Martin Hopfeld <martin.hopfeld@sse-erfurt.de>
+- Fixed geninfo not recognizing Objective-C functions. Based on patch
+  by abrahamh@web.de
+- Fixed option --no-recursion not being passed to geninfo
+- Fixed capitalization of the term 'Perl'
+- Improved coverage rate calculation to only show 0%/100% when no/full coverage
+  is achieved.  Based on suggestions by Paul.Zimmermann@loria.fr and
+  vincent@vinc17.net
+
+lcovrc:
+- Added description for geninfo_compat setting
+- Added config file setting 'genhtml_charset' to specify HTML charset
+- Added config file setting 'geninfo_external' to include/exclude external
+  source files such as standard libary headers
+- Added config file setting 'geninfo_gcov_all_blocks' to modify lcov's use
+  of gcov's -a option
+- Added config file setting 'geninfo_compat' to specify compatibility modes
+- Added config file setting 'geninfo_adjust_src_path' to enabled source path
+  adjustments.  Inspired by patch by ammon.riley@gmail.com
+- Added config file setting 'geninfo_auto_base' to automatically determine
+  the base directory when collecting coverage data
+- Added config file setting 'lcov_function_coverage' to enable/disable
+  function coverage processing
+- Added config file setting 'lcov_branch_coverage' to enable/disable
+  branch coverage processing
+
+
+Version 1.9
+===========
+
+genhtml:
+- Improved wording for branch representation tooltip text
+- Fixed vertical alignment of HTML branch representation
+
+geninfo:
+- Improved warning message about --initial not generating branch coverage data
+- Debugging messages are now printed to STDERR instead of STDOUT
+- Fixed problem with some .gcno files. Reported by gui@futarque.com.
+  (file.gcno: reached unexpected end of file)
+- Fixed problem with relative build paths. Reported by zhanbiao2000@gmail.com.
+  (cannot find an entry for ^#src#test.c.gcov in .gcno file, skipping file!)
+- Fixed problem where coverage data is missing for some files. Reported by
+  weston_schmidt@open-roadster.com
+- Fixed problem where exclusion markers are ignored when gathering
+  initial coverage data. Reported by ahmed_osman@mentor.com.
+- Fixed large execution counts showing as negative numbers in HTML output.
+  Reported by kkyriako@yahoo.com.
+- Fixed problem that incorrectly associated branches outside of a block with
+  branches inside the first block
+
+lcov:
+- Fixed problem that made lcov ignore --kernel-directory parameters when
+  specifying --initial. Reported by hjia@redhat.com.
+- Added --list-full-path option to prevent lcov from truncating paths in list
+  output
+- Added lcov_list_width and lcov_list_truncate_max directives to the
+  lcov configuration file to allow for list output customization
+- Improved list output
+
+COPYING:
+- Added license text to better comply with GPL recommendations
+
+
+Version 1.8
+===========
+
+gendesc:
+- Fixed problem with single word descriptions
+
+genhtml:
+- Added support for branch coverage measurements
+- Added --demangle-cpp option to convert C++ function names to human readable
+  format. Based on a patch by slava.semushin@gmail.com.
+- Improved color legend: legend display takes up less space in HTML output
+- Improved coverage rate limits: all coverage types use the same limits
+  unless specified otherwise
+- Fixed CRLF line breaks in source code when generating html output. Based
+  on patch by michael.knigge@set-software.de.
+- Fixed warning when $HOME is not set
+- Fixed problem with --baseline-file option. Reported by sixarm@gmail.com.
+  (Undefined subroutine &main::add_fnccounts called at genhtml line 4560.)
+- Fixed problem with --baseline-file option and files without function
+  coverage data (Can't use an undefined value as a HASH reference at genhtml
+  line 4441.)
+- Fixed short-name option ambiguities
+- Fixed --highlight option not showing line data from converted test data
+- Fixed warnings about undefined value used. Reported by nikita@zhuk.fi.
+- Fixed error when processing tracefiles without function data. Reported
+  by richard.corden@gmail.com (Can't use an undefined value as a HASH
+  reference at genhtml line 1506.)
+
+geninfo:
+- Added support for branch coverage measurements
+- Added support for exclusion markers: Users can exclude lines of code from
+  coverage reports by adding keywords to the source code.
+- Added --derive-func-data option
+- Added --debug option to better debug problems with graph files
+- Fixed CRLF line breaks in source code when generating tracefiles. Based on
+  patch by michael.knigge@set-software.de.
+- Fixed problems with unnamed source files
+- Fixed warning when $HOME is not set. Reported by acalando@free.fr.
+- Fixed errors when processing unnamed source files
+- Fixed help text typo
+- Fixed errors when processing incomplete function names in .bb files
+- Fixed filename prefix detection
+- Fixed problem with matching filename
+- Fixed problem when LANG is set to non-english locale. Reported by
+  benoit_belbezet@yahoo.fr.
+- Fixed short-name option ambiguities
+
+genpng:
+- Fixed runtime-warning
+
+lcov:
+- Added support for branch coverage measurements
+- Added support for the linux-2.6.31 upstream gcov kernel support
+- Added --from-package and --to-package options
+- Added --derive-func-data option
+- Added overall coverage result output for more operations
+- Improved output of lcov --list
+- Improved gcov-kernel handling
+- Fixed minor problem with --diff
+- Fixed double-counting of function data
+- Fixed warning when $HOME is not set. Reported by acalando@free.fr.
+- Fixed error when combining tracefiles without function data. Reported by
+  richard.corden@gmail.com. (Can't use an undefined value as a HASH reference
+  at lcov line 1341.)
+- Fixed help text typo
+- Fixed filename prefix detection
+- Fixed lcov ignoring information about converted test data
+
+README: 
+- Added note to mention required -lgcov switch during linking
+
+ 
 Version 1.7:
 ============
 
@@ -85,7 +265,7 @@
 - Updated help text
 - Updated man page
 - Fixed lcov not working when -k is specified more than once
-- Fixed lcov not deleting .gcda files when specifiying -z and -d
+- Fixed lcov not deleting .gcda files when specifying -z and -d
 
 lcovrc:
 - Added geninfo_compat_libtool option
diff --git a/third_party/lcov-1.9/COPYING b/third_party/lcov/COPYING
similarity index 100%
rename from third_party/lcov-1.9/COPYING
rename to third_party/lcov/COPYING
diff --git a/third_party/lcov/LICENSE b/third_party/lcov/LICENSE
deleted file mode 100644
index 0ba2158..0000000
--- a/third_party/lcov/LICENSE
+++ /dev/null
@@ -1,18 +0,0 @@
-License copied from bin/lcov:
-
-#
-#   Copyright (c) International Business Machines  Corp., 2002,2007
-#
-#   This program is free software;  you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or (at
-#   your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY;  without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.                 
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program;  if not, write to the Free Software
-#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
diff --git a/third_party/lcov/Makefile b/third_party/lcov/Makefile
index f6063e5..7cb838a 100644
--- a/third_party/lcov/Makefile
+++ b/third_party/lcov/Makefile
@@ -11,7 +11,7 @@
 #   - clean:     remove all generated files
 #
 
-VERSION := 1.7
+VERSION := 1.10
 RELEASE := 1
 
 CFG_DIR := $(PREFIX)/etc
@@ -37,18 +37,18 @@
 	make -C example clean
 
 install:
-	bin/install.sh bin/lcov $(BIN_DIR)/lcov
-	bin/install.sh bin/genhtml $(BIN_DIR)/genhtml
-	bin/install.sh bin/geninfo $(BIN_DIR)/geninfo
-	bin/install.sh bin/genpng $(BIN_DIR)/genpng
-	bin/install.sh bin/gendesc $(BIN_DIR)/gendesc
-	bin/install.sh man/lcov.1 $(MAN_DIR)/man1/lcov.1
-	bin/install.sh man/genhtml.1 $(MAN_DIR)/man1/genhtml.1
-	bin/install.sh man/geninfo.1 $(MAN_DIR)/man1/geninfo.1
-	bin/install.sh man/genpng.1 $(MAN_DIR)/man1/genpng.1
-	bin/install.sh man/gendesc.1 $(MAN_DIR)/man1/gendesc.1
-	bin/install.sh man/lcovrc.5 $(MAN_DIR)/man5/lcovrc.5
-	bin/install.sh lcovrc $(CFG_DIR)/lcovrc
+	bin/install.sh bin/lcov $(BIN_DIR)/lcov -m 755
+	bin/install.sh bin/genhtml $(BIN_DIR)/genhtml -m 755
+	bin/install.sh bin/geninfo $(BIN_DIR)/geninfo -m 755
+	bin/install.sh bin/genpng $(BIN_DIR)/genpng -m 755
+	bin/install.sh bin/gendesc $(BIN_DIR)/gendesc -m 755
+	bin/install.sh man/lcov.1 $(MAN_DIR)/man1/lcov.1 -m 644
+	bin/install.sh man/genhtml.1 $(MAN_DIR)/man1/genhtml.1 -m 644
+	bin/install.sh man/geninfo.1 $(MAN_DIR)/man1/geninfo.1 -m 644
+	bin/install.sh man/genpng.1 $(MAN_DIR)/man1/genpng.1 -m 644
+	bin/install.sh man/gendesc.1 $(MAN_DIR)/man1/gendesc.1 -m 644
+	bin/install.sh man/lcovrc.5 $(MAN_DIR)/man5/lcovrc.5 -m 644
+	bin/install.sh lcovrc $(CFG_DIR)/lcovrc -m 644
 
 uninstall:
 	bin/install.sh --uninstall bin/lcov $(BIN_DIR)/lcov
diff --git a/third_party/lcov/README b/third_party/lcov/README
index ad36451..7fcd438 100644
--- a/third_party/lcov/README
+++ b/third_party/lcov/README
@@ -1,13 +1,13 @@
 -------------------------------------------------
 - README file for the LTP GCOV extension (LCOV) -
-- Last changes: 2008-11-17                      -
+- Last changes: 2012-10-10                      -
 -------------------------------------------------
 
 Description
 -----------
   LCOV is an extension of GCOV, a GNU tool which provides information about
   what parts of a program are actually executed (i.e. "covered") while running
-  a particular test case. The extension consists of a set of PERL scripts
+  a particular test case. The extension consists of a set of Perl scripts
   which build on the textual GCOV output to implement the following enhanced
   functionality:
 
@@ -80,7 +80,7 @@
   http://sourceforge.net/projects/ltp
 
 Copy the resulting gcov kernel module file to either the system wide modules
-directory or the same directory as the PERL scripts. As root, do the following:
+directory or the same directory as the Perl scripts. As root, do the following:
 
   a) Resetting counters
 
@@ -100,8 +100,10 @@
 4. An example of how to access coverage data for a user space program
 ---------------------------------------------------------------------
 Requirements: compile the program in question using GCC with the options
--fprofile-arcs and -ftest-coverage. Assuming the compile directory is called
-"appdir", do the following:
+-fprofile-arcs and -ftest-coverage. During linking, make sure to specify
+-lgcov or -coverage.
+
+Assuming the compile directory is called "appdir", do the following:
 
   a) Resetting counters
 
@@ -118,6 +120,13 @@
 
 Point the web browser of your choice to the resulting index.html file.
 
+Please note that independently of where the application is installed or
+from which directory it is run, the --directory statement needs to
+point to the directory in which the application was compiled.
+
+For further information on the gcc profiling mechanism, please also
+consult the gcov man page.
+
 
 5. Questions and comments
 -------------------------
diff --git a/third_party/lcov/README.chromium b/third_party/lcov/README.chromium
index 81da5d4..03f6af9 100644
--- a/third_party/lcov/README.chromium
+++ b/third_party/lcov/README.chromium
@@ -1,13 +1,17 @@
 Name: LCOV - the LTP GCOV extension
 Short Name: lcov
 URL: http://ltp.sourceforge.net/coverage/lcov.php
-Version: 1.7
+Version: 1.10
 License: GPL v2
+License file: COPYING
 Security Critical: no
 
 Description:
-This directory contains a stock lcov-1.7 with the following changes:
+This directory contains a stock lcov-1.10 with the following changes:
 
 - Added bin/mcov, an assembly script derived from lcov which is
  particularly useful for dealing with Mac XCode build paths.
-- Added LICENSE file pulled from the top of bin/lcov.
+- Added LICENSE file which symlinks to COPYING
+
+N.B.: This code will not be shipped with Chrome.
+      It is only part of the build/test infrastructure.
\ No newline at end of file
diff --git a/third_party/lcov/bin/gendesc b/third_party/lcov/bin/gendesc
index e7a8113..f4cfcbc 100755
--- a/third_party/lcov/bin/gendesc
+++ b/third_party/lcov/bin/gendesc
@@ -41,7 +41,7 @@
 
 
 # Constants
-our $lcov_version	= "LCOV version 1.7";
+our $lcov_version	= 'LCOV version 1.10';
 our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
 our $tool_name		= basename($0);
 
@@ -67,6 +67,9 @@
 $SIG{__WARN__} = \&warn_handler;
 $SIG{__DIE__} = \&die_handler;
 
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+
 # Parse command line options
 if (!GetOptions("output-filename=s" => \$output_filename,
 		"version" =>\$version,
@@ -150,13 +153,13 @@
 	local *OUTPUT_HANDLE;
 	my $empty_line = "ignore";
 
-	open(INPUT_HANDLE, $input_filename)
+	open(INPUT_HANDLE, "<", $input_filename)
 		or die("ERROR: cannot open $input_filename!\n");
 
 	# Open output file for writing
 	if ($output_filename)
 	{
-		open(OUTPUT_HANDLE, ">$output_filename")
+		open(OUTPUT_HANDLE, ">", $output_filename)
 			or die("ERROR: cannot create $output_filename!\n");
 	}
 	else
@@ -169,7 +172,7 @@
 	{
 		chomp($_);
 
-		if (/^\s*(\w[\w-]*)(\s*)$/)
+		if (/^(\w[\w-]*)(\s*)$/)
 		{
 			# Matched test name
 			# Name starts with alphanum or _, continues with
diff --git a/third_party/lcov/bin/genhtml b/third_party/lcov/bin/genhtml
index af573ff..8979f8c 100755
--- a/third_party/lcov/bin/genhtml
+++ b/third_party/lcov/bin/genhtml
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 #
-#   Copyright (c) International Business Machines  Corp., 2002
+#   Copyright (c) International Business Machines  Corp., 2002,2012
 #
 #   This program is free software;  you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
@@ -72,7 +72,7 @@
 
 # Global constants
 our $title		= "LCOV - code coverage report";
-our $lcov_version	= "LCOV version 1.7";
+our $lcov_version	= 'LCOV version 1.10';
 our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
 our $tool_name		= basename($0);
 
@@ -81,13 +81,17 @@
 # MED: $med_limit <= rate <  $hi_limit    graph color: orange
 # LO:          0  <= rate <  $med_limit   graph color: red
 
-# For line coverage
-our $hi_limit	= 50;
-our $med_limit	= 15;
+# For line coverage/all coverage types if not specified
+our $hi_limit = 90;
+our $med_limit = 75;
 
 # For function coverage
-our $fn_hi_limit	= 90;
-our $fn_med_limit	= 75;
+our $fn_hi_limit;
+our $fn_med_limit;
+
+# For branch coverage
+our $br_hi_limit;
+our $br_med_limit;
 
 # Width of overview image
 our $overview_width = 80;
@@ -107,7 +111,55 @@
 # specifies that offset in lines.
 our $func_offset = 2;
 
-our $overview_title = "directory";
+our $overview_title = "top level";
+
+# Width for line coverage information in the source code view
+our $line_field_width = 12;
+
+# Width for branch coverage information in the source code view
+our $br_field_width = 16;
+
+# Internal Constants
+
+# Header types
+our $HDR_DIR		= 0;
+our $HDR_FILE		= 1;
+our $HDR_SOURCE		= 2;
+our $HDR_TESTDESC	= 3;
+our $HDR_FUNC		= 4;
+
+# Sort types
+our $SORT_FILE		= 0;
+our $SORT_LINE		= 1;
+our $SORT_FUNC		= 2;
+our $SORT_BRANCH	= 3;
+
+# Fileview heading types
+our $HEAD_NO_DETAIL	= 1;
+our $HEAD_DETAIL_HIDDEN	= 2;
+our $HEAD_DETAIL_SHOWN	= 3;
+
+# Offsets for storing branch coverage data in vectors
+our $BR_BLOCK		= 0;
+our $BR_BRANCH		= 1;
+our $BR_TAKEN		= 2;
+our $BR_VEC_ENTRIES	= 3;
+our $BR_VEC_WIDTH	= 32;
+
+# Additional offsets used when converting branch coverage data to HTML
+our $BR_LEN	= 3;
+our $BR_OPEN	= 4;
+our $BR_CLOSE	= 5;
+
+# Branch data combination types
+our $BR_SUB = 0;
+our $BR_ADD = 1;
+
+# Error classes which users may specify to ignore during processing
+our $ERROR_SOURCE	= 0;
+our %ERROR_ID = (
+	"source" => $ERROR_SOURCE,
+);
 
 # Data related prototypes
 sub print_usage(*);
@@ -118,21 +170,20 @@
 sub info(@);
 sub read_info_file($);
 sub get_info_entry($);
-sub set_info_entry($$$$$$$;$$$$);
-sub get_prefix(@);
+sub set_info_entry($$$$$$$$$;$$$$$$);
+sub get_prefix($@);
 sub shorten_prefix($);
 sub get_dir_list(@);
 sub get_relative_base_path($);
 sub read_testfile($);
 sub get_date_string();
-sub split_filename($);
 sub create_sub_dir($);
 sub subtract_counts($$);
 sub add_counts($$);
 sub apply_baseline($$);
 sub remove_unused_descriptions();
 sub get_found_and_hit($);
-sub get_affecting_tests($$);
+sub get_affecting_tests($$$);
 sub combine_info_files($$);
 sub merge_checksums($$$);
 sub combine_info_entries($$$);
@@ -142,6 +193,19 @@
 sub apply_config($);
 sub get_html_prolog($);
 sub get_html_epilog($);
+sub write_dir_page($$$$$$$$$$$$$$$$$);
+sub classify_rate($$$$);
+sub br_taken_add($$);
+sub br_taken_sub($$);
+sub br_ivec_len($);
+sub br_ivec_get($$);
+sub br_ivec_push($$$$);
+sub combine_brcount($$$);
+sub get_br_found_and_hit($);
+sub warn_handler($);
+sub die_handler($);
+sub parse_ignore_errors(@);
+sub rate($$;$$$);
 
 
 # HTML related prototypes
@@ -151,32 +215,31 @@
 sub write_png_files();
 sub write_htaccess_file();
 sub write_css_file();
-sub write_description_file($$$$$);
-sub write_function_rable(*$$$);
+sub write_description_file($$$$$$$);
+sub write_function_table(*$$$$$$$$$$);
 
 sub write_html(*$);
 sub write_html_prolog(*$$);
 sub write_html_epilog(*$;$);
 
-sub write_header(*$$$$$$$$);
+sub write_header(*$$$$$$$$$$);
 sub write_header_prolog(*$);
-sub write_header_line(*$@);
+sub write_header_line(*@);
 sub write_header_epilog(*$);
 
-sub write_file_table(*$$$$$$);
-sub write_file_table_prolog(*$$$);
-sub write_file_table_entry(*$$$$$$$);
-sub write_file_table_detail_heading(*$$$);
-sub write_file_table_detail_entry(*$$$$$);
+sub write_file_table(*$$$$$$$);
+sub write_file_table_prolog(*$@);
+sub write_file_table_entry(*$$$@);
+sub write_file_table_detail_entry(*$@);
 sub write_file_table_epilog(*);
 
 sub write_test_table_prolog(*$);
 sub write_test_table_entry(*$$);
 sub write_test_table_epilog(*);
 
-sub write_source($$$$$$);
+sub write_source($$$$$$$);
 sub write_source_prolog(*);
-sub write_source_line(*$$$$$);
+sub write_source_line(*$$$$$$);
 sub write_source_epilog(*);
 
 sub write_frameset(*$$$);
@@ -204,8 +267,10 @@
 our $version;		# Version option flag
 our $show_details;	# If set, generate detailed directory view
 our $no_prefix;		# If set, do not remove filename prefix
-our $func_coverage = 1;	# If set, generate function coverage statistics
+our $func_coverage;	# If set, generate function coverage statistics
 our $no_func_coverage;	# Disable func_coverage
+our $br_coverage;	# If set, generate branch coverage statistics
+our $no_br_coverage;	# Disable br_coverage
 our $sort = 1;		# If set, provide directory listings with sorted entries
 our $no_sort;		# Disable sort
 our $frames;		# If set, use frames for source code view
@@ -221,11 +286,19 @@
 our $html_epilog;	# Actual HTML epilog
 our $html_ext = "html";	# Extension for generated HTML files
 our $html_gzip = 0;	# Compress with gzip
+our $demangle_cpp = 0;	# Demangle C++ function names
+our @opt_ignore_errors;	# Ignore certain error classes during processing
+our @ignore;
+our $opt_config_file;	# User-specified configuration file location
+our %opt_rc;
+our $charset = "UTF-8";	# Default charset for HTML pages
 our @fileview_sortlist;
-our @fileview_sortname = ("", "-sort-l", "-sort-f");
+our @fileview_sortname = ("", "-sort-l", "-sort-f", "-sort-b");
 our @funcview_sortlist;
 our @rate_name = ("Lo", "Med", "Hi");
 our @rate_png = ("ruby.png", "amber.png", "emerald.png");
+our $lcov_func_coverage = 1;
+our $lcov_branch_coverage = 0;
 
 our $cwd = `pwd`;	# Current working directory
 chomp($cwd);
@@ -239,14 +312,25 @@
 $SIG{__WARN__} = \&warn_handler;
 $SIG{__DIE__} = \&die_handler;
 
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+
 # Add current working directory if $tool_dir is not already an absolute path
 if (! ($tool_dir =~ /^\/(.*)$/))
 {
 	$tool_dir = "$cwd/$tool_dir";
 }
 
+# Check command line for a configuration file name
+Getopt::Long::Configure("pass_through", "no_auto_abbrev");
+GetOptions("config-file=s" => \$opt_config_file,
+	   "rc=s%" => \%opt_rc);
+Getopt::Long::Configure("default");
+
 # Read configuration file if available
-if (-r $ENV{"HOME"}."/.lcovrc")
+if (defined($opt_config_file)) {
+	$config = read_config($opt_config_file);
+} elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
 {
 	$config = read_config($ENV{"HOME"}."/.lcovrc");
 }
@@ -255,13 +339,14 @@
 	$config = read_config("/etc/lcovrc");
 }
 
-if ($config)
+if ($config || %opt_rc)
 {
-	# Copy configuration file values to variables
+	# Copy configuration file and --rc values to variables
 	apply_config({
 		"genhtml_css_file"		=> \$css_filename,
 		"genhtml_hi_limit"		=> \$hi_limit,
 		"genhtml_med_limit"		=> \$med_limit,
+		"genhtml_line_field_width"	=> \$line_field_width,
 		"genhtml_overview_width"	=> \$overview_width,
 		"genhtml_nav_resolution"	=> \$nav_resolution,
 		"genhtml_nav_offset"		=> \$nav_offset,
@@ -278,36 +363,57 @@
 		"genhtml_function_hi_limit"	=> \$fn_hi_limit,
 		"genhtml_function_med_limit"	=> \$fn_med_limit,
 		"genhtml_function_coverage"	=> \$func_coverage,
+		"genhtml_branch_hi_limit"	=> \$br_hi_limit,
+		"genhtml_branch_med_limit"	=> \$br_med_limit,
+		"genhtml_branch_coverage"	=> \$br_coverage,
+		"genhtml_branch_field_width"	=> \$br_field_width,
 		"genhtml_sort"			=> \$sort,
+		"genhtml_charset"		=> \$charset,
+		"lcov_function_coverage"	=> \$lcov_func_coverage,
+		"lcov_branch_coverage"		=> \$lcov_branch_coverage,
 		});
 }
 
+# Copy related values if not specified
+$fn_hi_limit	= $hi_limit if (!defined($fn_hi_limit));
+$fn_med_limit	= $med_limit if (!defined($fn_med_limit));
+$br_hi_limit	= $hi_limit if (!defined($br_hi_limit));
+$br_med_limit	= $med_limit if (!defined($br_med_limit));
+$func_coverage	= $lcov_func_coverage if (!defined($func_coverage));
+$br_coverage	= $lcov_branch_coverage if (!defined($br_coverage));
+
 # Parse command line options
-if (!GetOptions("output-directory=s"	=> \$output_directory,
-		"title=s"		=> \$test_title,
-		"description-file=s"	=> \$desc_filename,
-		"keep-descriptions"	=> \$keep_descriptions,
-		"css-file=s"		=> \$css_filename,
-		"baseline-file=s"	=> \$base_filename,
-		"prefix=s"		=> \$dir_prefix,
+if (!GetOptions("output-directory|o=s"	=> \$output_directory,
+		"title|t=s"		=> \$test_title,
+		"description-file|d=s"	=> \$desc_filename,
+		"keep-descriptions|k"	=> \$keep_descriptions,
+		"css-file|c=s"		=> \$css_filename,
+		"baseline-file|b=s"	=> \$base_filename,
+		"prefix|p=s"		=> \$dir_prefix,
 		"num-spaces=i"		=> \$tab_size,
 		"no-prefix"		=> \$no_prefix,
 		"no-sourceview"		=> \$no_sourceview,
-		"show-details"		=> \$show_details,
-		"frames"		=> \$frames,
+		"show-details|s"	=> \$show_details,
+		"frames|f"		=> \$frames,
 		"highlight"		=> \$highlight,
 		"legend"		=> \$legend,
-		"quiet"			=> \$quiet,
+		"quiet|q"		=> \$quiet,
 		"help|h|?"		=> \$help,
-		"version"		=> \$version,
+		"version|v"		=> \$version,
 		"html-prolog=s"		=> \$html_prolog_file,
 		"html-epilog=s"		=> \$html_epilog_file,
 		"html-extension=s"	=> \$html_ext,
 		"html-gzip"		=> \$html_gzip,
 		"function-coverage"	=> \$func_coverage,
 		"no-function-coverage"	=> \$no_func_coverage,
+		"branch-coverage"	=> \$br_coverage,
+		"no-branch-coverage"	=> \$no_br_coverage,
 		"sort"			=> \$sort,
 		"no-sort"		=> \$no_sort,
+		"demangle-cpp"		=> \$demangle_cpp,
+		"ignore-errors=s"	=> \@opt_ignore_errors,
+		"config-file=s"		=> \$opt_config_file,
+		"rc=s%"			=> \%opt_rc,
 		))
 {
 	print(STDERR "Use $tool_name --help to get usage information\n");
@@ -317,6 +423,9 @@
 	if ($no_func_coverage) {
 		$func_coverage = 0;
 	}
+	if ($no_br_coverage) {
+		$br_coverage = 0;
+	}
 
 	# Merge sort options
 	if ($no_sort) {
@@ -340,6 +449,9 @@
 	exit(0);
 }
 
+# Determine which errors the user wants us to ignore
+parse_ignore_errors(@opt_ignore_errors);
+
 # Check for info filename
 if (!@info_filenames)
 {
@@ -400,16 +512,14 @@
 	$dir_prefix = undef;
 }
 
+@fileview_sortlist = ($SORT_FILE);
+@funcview_sortlist = ($SORT_FILE);
+
 if ($sort) {
-	@funcview_sortlist = (0, 1);
-	if ($func_coverage) {
-		@fileview_sortlist = (0, 1, 2);
-	} else {
-		@fileview_sortlist = (0, 1);
-	}
-} else {
-	@fileview_sortlist = (0);
-	@funcview_sortlist = (0);
+	push(@fileview_sortlist, $SORT_LINE);
+	push(@fileview_sortlist, $SORT_FUNC) if ($func_coverage);
+	push(@fileview_sortlist, $SORT_BRANCH) if ($br_coverage);
+	push(@funcview_sortlist, $SORT_LINE);
 }
 
 if ($frames)
@@ -418,6 +528,15 @@
 	do("$tool_dir/genpng");
 }
 
+# Ensure that the c++filt tool is available when using --demangle-cpp
+if ($demangle_cpp)
+{
+	if (system_no_output(3, "c++filt", "--version")) {
+		die("ERROR: could not find c++filt tool needed for ".
+		    "--demangle-cpp\n");
+	}
+}
+
 # Make sure output_directory exists, create it if necessary
 if ($output_directory)
 {
@@ -425,8 +544,7 @@
 
 	if (! -e _)
 	{
-		system("mkdir", "-p", $output_directory)
-			and die("ERROR: cannot create directory $_!\n");
+		create_sub_dir($output_directory);
 	}
 }
 
@@ -457,6 +575,9 @@
   -h, --help                        Print this help, then exit
   -v, --version                     Print version number, then exit
   -q, --quiet                       Do not print progress messages
+      --config-file FILENAME        Specify configuration file location
+      --rc SETTING=VALUE            Override configuration file setting
+      --ignore-errors ERRORS        Continue after ERRORS (source)
 
 Operation:
   -o, --output-directory OUTDIR     Write HTML output to OUTDIR
@@ -467,6 +588,7 @@
   -p, --prefix PREFIX               Remove PREFIX from all directory names
       --no-prefix                   Do not remove prefix from directory names
       --(no-)function-coverage      Enable (disable) function coverage display
+      --(no-)branch-coverage        Enable (disable) branch coverage display
 
 HTML output:
   -f, --frames                      Use HTML frames for source code view
@@ -481,6 +603,7 @@
       --html-extension EXT          Use EXT as filename extension for pages
       --html-gzip                   Use gzip to compress HTML
       --(no-)sort                   Enable (disable) sorted coverage views
+      --demangle-cpp                Demangle C++ function names
 
 For more information see: $lcov_url
 END_OF_USAGE
@@ -508,6 +631,49 @@
 
 
 #
+# get_overall_line(found, hit, name_singular, name_plural)
+#
+# Return a string containing overall information for the specified
+# found/hit data.
+#
+
+sub get_overall_line($$$$)
+{
+	my ($found, $hit, $name_sn, $name_pl) = @_;
+	my $name;
+
+	return "no data found" if (!defined($found) || $found == 0);
+	$name = ($found == 1) ? $name_sn : $name_pl;
+	return rate($hit, $found, "% ($hit of $found $name)");
+}
+
+
+#
+# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
+#                    br_found, br_hit)
+#
+# Print overall coverage rates for the specified coverage types.
+#
+
+sub print_overall_rate($$$$$$$$$)
+{
+	my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
+	    $br_do, $br_found, $br_hit) = @_;
+
+	info("Overall coverage rate:\n");
+	info("  lines......: %s\n",
+	     get_overall_line($ln_found, $ln_hit, "line", "lines"))
+		if ($ln_do);
+	info("  functions..: %s\n",
+	     get_overall_line($fn_found, $fn_hit, "function", "functions"))
+		if ($fn_do);
+	info("  branches...: %s\n",
+	     get_overall_line($br_found, $br_hit, "branch", "branches"))
+		if ($br_do);
+}
+
+
+#
 # gen_html()
 #
 # Generate a set of HTML pages from contents of .info file INFO_FILENAME.
@@ -527,10 +693,14 @@
 	my $lines_hit;
 	my $fn_found;
 	my $fn_hit;
+	my $br_found;
+	my $br_hit;
 	my $overall_found = 0;
 	my $overall_hit = 0;
 	my $total_fn_found = 0;
 	my $total_fn_hit = 0;
+	my $total_br_found = 0;
+	my $total_br_hit = 0;
 	my $dir_name;
 	my $link_name;
 	my @dir_list;
@@ -570,7 +740,7 @@
 	elsif (!defined($dir_prefix))
 	{
 		# Get prefix common to most directories in list
-		$dir_prefix = get_prefix(@dir_list);
+		$dir_prefix = get_prefix(1, keys(%info_data));
 
 		if ($dir_prefix)
 		{
@@ -625,9 +795,13 @@
 	# Process each subdirectory and collect overview information
 	foreach $dir_name (@dir_list)
 	{
-		($lines_found, $lines_hit, $fn_found, $fn_hit)
+		($lines_found, $lines_hit, $fn_found, $fn_hit,
+		 $br_found, $br_hit)
 			= process_dir($dir_name);
 
+		# Handle files in root directory gracefully
+		$dir_name = "root" if ($dir_name eq "");
+
 		# Remove prefix if applicable
 		if (!$no_prefix && $dir_prefix)
 		{
@@ -646,13 +820,16 @@
 		}
 
 		$overview{$dir_name} = [$lines_found, $lines_hit, $fn_found,
-					$fn_hit, $link_name,
+					$fn_hit, $br_found, $br_hit, $link_name,
 					get_rate($lines_found, $lines_hit),
-					get_rate($fn_found, $fn_hit)];
+					get_rate($fn_found, $fn_hit),
+					get_rate($br_found, $br_hit)];
 		$overall_found	+= $lines_found;
 		$overall_hit	+= $lines_hit;
 		$total_fn_found	+= $fn_found;
 		$total_fn_hit	+= $fn_hit;
+		$total_br_found	+= $br_found;
+		$total_br_hit	+= $br_hit;
 	}
 
 	# Generate overview page
@@ -662,8 +839,8 @@
 	foreach (@fileview_sortlist) {
 		write_dir_page($fileview_sortname[$_], ".", "", $test_title,
 			       undef, $overall_found, $overall_hit,
-			       $total_fn_found, $total_fn_hit, \%overview,
-			       {}, {}, 0, $_);
+			       $total_fn_found, $total_fn_hit, $total_br_found,
+			       $total_br_hit, \%overview, {}, {}, {}, 0, $_);
 	}
 
 	# Check if there are any test case descriptions to write out
@@ -672,37 +849,15 @@
 		info("Writing test case description file.\n");
 		write_description_file( \%test_description,
 					$overall_found, $overall_hit,
-					$total_fn_found, $total_fn_hit);
+					$total_fn_found, $total_fn_hit,
+					$total_br_found, $total_br_hit);
 	}
 
+	print_overall_rate(1, $overall_found, $overall_hit,
+			   $func_coverage, $total_fn_found, $total_fn_hit,
+			   $br_coverage, $total_br_found, $total_br_hit);
+
 	chdir($cwd);
-
-	info("Overall coverage rate:\n");
-
-	if ($overall_found == 0)
-	{
-		info("  lines......: no data found\n");
-		return;
-	}
-	info("  lines......: %.1f%% (%d of %d lines)\n",
-	     $overall_hit * 100 / $overall_found, $overall_hit,
-	     $overall_found,);
-
-	if ($func_coverage)
-	{
-		if ($total_fn_found == 0)
-		{
-			info("  functions..: no data found\n");
-		}
-		else
-		{
-			info("  functions..: %.1f%% (%d of %d functions)\n",
-			     $total_fn_hit * 100 / $total_fn_found,
-			     $total_fn_hit, $total_fn_found);
-
-		}
-	}
-
 }
 
 #
@@ -716,34 +871,36 @@
 
 	if ($html_gzip)
 	{
-		open($handle, "|gzip -c >$filename")
+		open($handle, "|-", "gzip -c >'$filename'")
 			or die("ERROR: cannot open $filename for writing ".
 			       "(gzip)!\n");
 	}
 	else
 	{
-		open($handle, ">$filename")
+		open($handle, ">", $filename)
 			or die("ERROR: cannot open $filename for writing!\n");
 	}
 }
 
-sub write_dir_page($$$$$$$$$$$$$$)
+sub write_dir_page($$$$$$$$$$$$$$$$$)
 {
 	my ($name, $rel_dir, $base_dir, $title, $trunc_dir, $overall_found,
-	    $overall_hit, $total_fn_found, $total_fn_hit, $overview,
-	    $testhash, $testfnchash, $view_type, $sort_type) = @_;
+	    $overall_hit, $total_fn_found, $total_fn_hit, $total_br_found,
+	    $total_br_hit, $overview, $testhash, $testfnchash, $testbrhash,
+	    $view_type, $sort_type) = @_;
 
 	# Generate directory overview page including details
 	html_create(*HTML_HANDLE, "$rel_dir/index$name.$html_ext");
 	if (!defined($trunc_dir)) {
 		$trunc_dir = "";
 	}
+	$title .= " - " if ($trunc_dir ne "");
 	write_html_prolog(*HTML_HANDLE, $base_dir, "LCOV - $title$trunc_dir");
 	write_header(*HTML_HANDLE, $view_type, $trunc_dir, $rel_dir,
 		     $overall_found, $overall_hit, $total_fn_found,
-		     $total_fn_hit, $sort_type);
+		     $total_fn_hit, $total_br_found, $total_br_hit, $sort_type);
 	write_file_table(*HTML_HANDLE, $base_dir, $overview, $testhash,
-			 $testfnchash, $view_type, $sort_type);
+			 $testfnchash, $testbrhash, $view_type, $sort_type);
 	write_html_epilog(*HTML_HANDLE, $base_dir);
 	close(*HTML_HANDLE);
 }
@@ -765,16 +922,22 @@
 	my $lines_hit;
 	my $fn_found;
 	my $fn_hit;
+	my $br_found;
+	my $br_hit;
 	my $overall_found=0;
 	my $overall_hit=0;
 	my $total_fn_found=0;
 	my $total_fn_hit=0;
+	my $total_br_found = 0;
+	my $total_br_hit = 0;
 	my $base_name;
 	my $extension;
 	my $testdata;
 	my %testhash;
 	my $testfncdata;
 	my %testfnchash;
+	my $testbrdata;
+	my %testbrhash;
 	my @sort_list;
 	local *HTML_HANDLE;
 
@@ -793,6 +956,10 @@
 		$rel_dir = substr($rel_dir, 1);
 	}
 
+	# Handle files in root directory gracefully
+	$rel_dir = "root" if ($rel_dir eq "");
+	$trunc_dir = "root" if ($trunc_dir eq "");
+
 	$base_dir = get_relative_base_path($rel_dir);
 
 	create_sub_dir($rel_dir);
@@ -804,8 +971,9 @@
 		my $page_link;
 		my $func_link;
 
-		($lines_found, $lines_hit, $fn_found, $fn_hit, $testdata,
-		 $testfncdata) = process_file($trunc_dir, $rel_dir, $filename);
+		($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
+		 $br_hit, $testdata, $testfncdata, $testbrdata) =
+			process_file($trunc_dir, $rel_dir, $filename);
 
 		$base_name = basename($filename);
 
@@ -819,18 +987,24 @@
 			$page_link = "$base_name.gcov.$html_ext";
 		}
 		$overview{$base_name} = [$lines_found, $lines_hit, $fn_found,
-					 $fn_hit, $page_link,
+					 $fn_hit, $br_found, $br_hit,
+					 $page_link,
 					 get_rate($lines_found, $lines_hit),
-					 get_rate($fn_found, $fn_hit)];
+					 get_rate($fn_found, $fn_hit),
+					 get_rate($br_found, $br_hit)];
 
 		$testhash{$base_name} = $testdata;
 		$testfnchash{$base_name} = $testfncdata;
+		$testbrhash{$base_name} = $testbrdata;
 
 		$overall_found	+= $lines_found;
 		$overall_hit	+= $lines_hit;
 
 		$total_fn_found += $fn_found;
 		$total_fn_hit   += $fn_hit;
+
+		$total_br_found += $br_found;
+		$total_br_hit   += $br_hit;
 	}
 
 	# Create sorted pages
@@ -839,7 +1013,8 @@
 		write_dir_page($fileview_sortname[$_], $rel_dir, $base_dir,
 			       $test_title, $trunc_dir, $overall_found,
 			       $overall_hit, $total_fn_found, $total_fn_hit,
-			       \%overview, {}, {}, 1, $_);
+			       $total_br_found, $total_br_hit, \%overview, {},
+			       {}, {}, 1, $_);
 		if (!$show_details) {
 			next;
 		}
@@ -847,12 +1022,14 @@
 		write_dir_page("-detail".$fileview_sortname[$_], $rel_dir,
 			       $base_dir, $test_title, $trunc_dir,
 			       $overall_found, $overall_hit, $total_fn_found,
-			       $total_fn_hit, \%overview, \%testhash,
-			       \%testfnchash, 1, $_);
+			       $total_fn_hit, $total_br_found, $total_br_hit,
+			       \%overview, \%testhash, \%testfnchash,
+			       \%testbrhash, 1, $_);
 	}
 
 	# Calculate resulting line counts
-	return ($overall_found, $overall_hit, $total_fn_found, $total_fn_hit);
+	return ($overall_found, $overall_hit, $total_fn_found, $total_fn_hit,
+		$total_br_found, $total_br_hit);
 }
 
 
@@ -913,11 +1090,12 @@
 }
 
 
-sub write_function_page($$$$$$$$$$$$$$)
+sub write_function_page($$$$$$$$$$$$$$$$$$)
 {
 	my ($base_dir, $rel_dir, $trunc_dir, $base_name, $title,
-	    $lines_found, $lines_hit, $fn_found, $fn_hit,
-	    $sumcount, $funcdata, $sumfnccount, $testfncdata, $sort_type) = @_;
+	    $lines_found, $lines_hit, $fn_found, $fn_hit, $br_found, $br_hit,
+	    $sumcount, $funcdata, $sumfnccount, $testfncdata, $sumbrcount,
+	    $testbrdata, $sort_type) = @_;
 	my $pagetitle;
 	my $filename;
 
@@ -932,10 +1110,11 @@
 	write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
 	write_header(*HTML_HANDLE, 4, "$trunc_dir/$base_name",
 		     "$rel_dir/$base_name", $lines_found, $lines_hit,
-		     $fn_found, $fn_hit, $sort_type);
+		     $fn_found, $fn_hit, $br_found, $br_hit, $sort_type);
 	write_function_table(*HTML_HANDLE, "$base_name.gcov.$html_ext",
 			     $sumcount, $funcdata,
-			     $sumfnccount, $testfncdata, $base_name,
+			     $sumfnccount, $testfncdata, $sumbrcount,
+			     $testbrdata, $base_name,
 			     $base_dir, $sort_type);
 	write_html_epilog(*HTML_HANDLE, $base_dir, 1);
 	close(*HTML_HANDLE);
@@ -962,25 +1141,31 @@
 	my $checkdata;
 	my $testfncdata;
 	my $sumfnccount;
+	my $testbrdata;
+	my $sumbrcount;
 	my $lines_found;
 	my $lines_hit;
 	my $fn_found;
 	my $fn_hit;
+	my $br_found;
+	my $br_hit;
 	my $converted;
 	my @source;
 	my $pagetitle;
 	local *HTML_HANDLE;
 
 	($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
-	 $sumfnccount, $lines_found, $lines_hit, $fn_found, $fn_hit)
+	 $sumfnccount, $testbrdata, $sumbrcount, $lines_found, $lines_hit,
+	 $fn_found, $fn_hit, $br_found, $br_hit)
 		= get_info_entry($info_data{$filename});
 
 	# Return after this point in case user asked us not to generate
 	# source code view
 	if ($no_sourceview)
 	{
-		return ($lines_found, $lines_hit,
-			$fn_found, $fn_hit, $testdata);
+		return ($lines_found, $lines_hit, $fn_found, $fn_hit,
+			$br_found, $br_hit, $testdata, $testfncdata,
+			$testbrdata);
 	}
 
 	$converted = get_converted_lines($testdata);
@@ -990,9 +1175,9 @@
 	write_html_prolog(*HTML_HANDLE, $base_dir, $pagetitle);
 	write_header(*HTML_HANDLE, 2, "$trunc_dir/$base_name",
 		     "$rel_dir/$base_name", $lines_found, $lines_hit,
-		     $fn_found, $fn_hit, 0);
+		     $fn_found, $fn_hit, $br_found, $br_hit, 0);
 	@source = write_source(*HTML_HANDLE, $filename, $sumcount, $checkdata,
-			       $converted, $funcdata);
+			       $converted, $funcdata, $sumbrcount);
 
 	write_html_epilog(*HTML_HANDLE, $base_dir, 1);
 	close(*HTML_HANDLE);
@@ -1003,17 +1188,20 @@
 			write_function_page($base_dir, $rel_dir, $trunc_dir,
 					    $base_name, $test_title,
 					    $lines_found, $lines_hit,
-					    $fn_found, $fn_hit, $sumcount,
+					    $fn_found, $fn_hit, $br_found,
+					    $br_hit, $sumcount,
 					    $funcdata, $sumfnccount,
-					    $testfncdata, $_);
+					    $testfncdata, $sumbrcount,
+					    $testbrdata, $_);
 		}
 	}
 
 	# Additional files are needed in case of frame output
 	if (!$frames)
 	{
-		return ($lines_found, $lines_hit,
-			$fn_found, $fn_hit, $testdata);
+		return ($lines_found, $lines_hit, $fn_found, $fn_hit,
+			$br_found, $br_hit, $testdata, $testfncdata,
+			$testbrdata);
 	}
 
 	# Create overview png file
@@ -1033,8 +1221,8 @@
 		       scalar(@source));
 	close(*HTML_HANDLE);
 
-	return ($lines_found, $lines_hit, $fn_found, $fn_hit, $testdata,
-		$testfncdata);
+	return ($lines_found, $lines_hit, $fn_found, $fn_hit, $br_found,
+		$br_hit, $testdata, $testfncdata, $testbrdata);
 }
 
 
@@ -1054,16 +1242,22 @@
 #        "check" -> \%checkdata
 #        "testfnc" -> \%testfncdata
 #        "sumfnc"  -> \%sumfnccount
+#        "testbr"  -> \%testbrdata
+#        "sumbr"   -> \%sumbrcount
 #
 # %testdata   : name of test affecting this file -> \%testcount
 # %testfncdata: name of test affecting this file -> \%testfnccount
+# %testbrdata:  name of test affecting this file -> \%testbrcount
 #
 # %testcount   : line number   -> execution count for a single test
 # %testfnccount: function name -> execution count for a single test
+# %testbrcount : line number   -> branch coverage data for a single test
 # %sumcount    : line number   -> execution count for all tests
 # %sumfnccount : function name -> execution count for all tests
+# %sumbrcount  : line number   -> branch coverage data for all tests
 # %funcdata    : function name -> line number
 # %checkdata   : line number   -> checksum of source code line
+# $brdata      : vector of items: block, branch, taken
 # 
 # Note that .info file sections referring to the same file and test name
 # will automatically be combined by adding all execution counts.
@@ -1088,6 +1282,9 @@
 	my $testfncdata;
 	my $testfnccount;
 	my $sumfnccount;
+	my $testbrdata;
+	my $testbrcount;
+	my $sumbrcount;
 	my $line;			# Current line read from .info file
 	my $testname;			# Current test name
 	my $filename;			# Current filename
@@ -1096,6 +1293,8 @@
 	my $negative;			# If set, warn about negative counts
 	my $changed_testname;		# If set, warn about changed testname
 	my $line_checksum;		# Checksum of current line
+	my $br_found;
+	my $br_hit;
 	local *INFO_HANDLE;		# Filehandle for .info file
 
 	info("Reading data file $tracefile\n");
@@ -1126,14 +1325,14 @@
 				"compressed file $_[0]!\n");
 
 		# Open compressed file
-		open(INFO_HANDLE, "gunzip -c $_[0]|")
+		open(INFO_HANDLE, "-|", "gunzip -c '$_[0]'")
 			or die("ERROR: cannot start gunzip to decompress ".
 			       "file $_[0]!\n");
 	}
 	else
 	{
 		# Open decompressed file
-		open(INFO_HANDLE, $_[0])
+		open(INFO_HANDLE, "<", $_[0])
 			or die("ERROR: cannot read file $_[0]!\n");
 	}
 
@@ -1146,7 +1345,7 @@
 		# Switch statement
 		foreach ($line)
 		{
-			/^TN:([^,]*)/ && do
+			/^TN:([^,]*)(,diff)?/ && do
 			{
 				# Test name information found
 				$testname = defined($1) ? $1 : "";
@@ -1154,6 +1353,7 @@
 				{
 					$changed_testname = 1;
 				}
+				$testname .= $2 if (defined($2));
 				last;
 			};
 
@@ -1165,18 +1365,21 @@
 
 				$data = $result{$filename};
 				($testdata, $sumcount, $funcdata, $checkdata,
-				 $testfncdata, $sumfnccount) =
+				 $testfncdata, $sumfnccount, $testbrdata,
+				 $sumbrcount) =
 					get_info_entry($data);
 
 				if (defined($testname))
 				{
 					$testcount = $testdata->{$testname};
 					$testfnccount = $testfncdata->{$testname};
+					$testbrcount = $testbrdata->{$testname};
 				}
 				else
 				{
 					$testcount = {};
 					$testfnccount = {};
+					$testbrcount = {};
 				}
 				last;
 			};
@@ -1220,6 +1423,8 @@
 
 			/^FN:(\d+),([^,]+)/ && do
 			{
+				last if (!$func_coverage);
+
 				# Function data found, add to structure
 				$funcdata->{$2} = $1;
 
@@ -1238,6 +1443,7 @@
 
 			/^FNDA:(\d+),([^,]+)/ && do
 			{
+				last if (!$func_coverage);
 				# Function call count found, add to structure
 				# Add summary counts
 				$sumfnccount->{$2} += $1;
@@ -1249,6 +1455,28 @@
 				}
 				last;
 			};
+
+			/^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
+				# Branch coverage data found
+				my ($line, $block, $branch, $taken) =
+				   ($1, $2, $3, $4);
+
+				last if (!$br_coverage);
+				$sumbrcount->{$line} =
+					br_ivec_push($sumbrcount->{$line},
+						     $block, $branch, $taken);
+
+				# Add test-specific counts
+				if (defined($testname)) {
+					$testbrcount->{$line} =
+						br_ivec_push(
+							$testbrcount->{$line},
+							$block, $branch,
+							$taken);
+				}
+				last;
+			};
+
 			/^end_of_record/ && do
 			{
 				# Found end of section marker
@@ -1261,12 +1489,16 @@
 							$testcount;
 						$testfncdata->{$testname} =
 							$testfnccount;
+						$testbrdata->{$testname} =
+							$testbrcount;
 					}	
 
 					set_info_entry($data, $testdata,
 						       $sumcount, $funcdata,
 						       $checkdata, $testfncdata,
-						       $sumfnccount);
+						       $sumfnccount,
+						       $testbrdata,
+						       $sumbrcount);
 					$result{$filename} = $data;
 					last;
 				}
@@ -1284,7 +1516,8 @@
 		$data = $result{$filename};
 
 		($testdata, $sumcount, undef, undef, $testfncdata,
-		 $sumfnccount) = get_info_entry($data);
+		 $sumfnccount, $testbrdata, $sumbrcount) =
+			get_info_entry($data);
 
 		# Filter out empty files
 		if (scalar(keys(%{$sumcount})) == 0)
@@ -1323,6 +1556,12 @@
 			}
 		}
 		$data->{"f_hit"} = $hitcount;
+
+		# Get found/hit values for branch data
+		($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
+
+		$data->{"b_found"} = $br_found;
+		$data->{"b_hit"} = $br_hit;
 	}
 
 	if (scalar(keys(%result)) == 0)
@@ -1362,26 +1601,32 @@
 	my $checkdata_ref = $_[0]->{"check"};
 	my $testfncdata = $_[0]->{"testfnc"};
 	my $sumfnccount = $_[0]->{"sumfnc"};
+	my $testbrdata = $_[0]->{"testbr"};
+	my $sumbrcount = $_[0]->{"sumbr"};
 	my $lines_found = $_[0]->{"found"};
 	my $lines_hit = $_[0]->{"hit"};
 	my $fn_found = $_[0]->{"f_found"};
 	my $fn_hit = $_[0]->{"f_hit"};
+	my $br_found = $_[0]->{"b_found"};
+	my $br_hit = $_[0]->{"b_hit"};
 
 	return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
-		$testfncdata, $sumfnccount, $lines_found, $lines_hit,
-		$fn_found, $fn_hit);
+		$testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
+		$lines_found, $lines_hit, $fn_found, $fn_hit,
+		$br_found, $br_hit);
 }
 
 
 #
 # set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
-#                checkdata_ref, testfncdata_ref, sumfcncount_ref[,lines_found,
-#                lines_hit, f_found, f_hit])
+#                checkdata_ref, testfncdata_ref, sumfcncount_ref,
+#                testbrdata_ref, sumbrcount_ref[,lines_found,
+#                lines_hit, f_found, f_hit, $b_found, $b_hit])
 #
 # Update the hash referenced by HASH_REF with the provided data references.
 #
 
-sub set_info_entry($$$$$$$;$$$$)
+sub set_info_entry($$$$$$$$$;$$$$$$)
 {
 	my $data_ref = $_[0];
 
@@ -1391,11 +1636,15 @@
 	$data_ref->{"check"} = $_[4];
 	$data_ref->{"testfnc"} = $_[5];
 	$data_ref->{"sumfnc"} = $_[6];
+	$data_ref->{"testbr"} = $_[7];
+	$data_ref->{"sumbr"} = $_[8];
 
-	if (defined($_[7])) { $data_ref->{"found"} = $_[7]; }
-	if (defined($_[8])) { $data_ref->{"hit"} = $_[8]; }
-	if (defined($_[9])) { $data_ref->{"f_found"} = $_[9]; }
-	if (defined($_[10])) { $data_ref->{"f_hit"} = $_[10]; }
+	if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
+	if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
+	if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
+	if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
+	if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
+	if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
 }
 
 
@@ -1503,7 +1752,9 @@
 	my %result;
 	my $func;
 
-	%result = %{$funcdata1};
+	if (defined($funcdata1)) {
+		%result = %{$funcdata1};
+	}
 
 	foreach $func (keys(%{$funcdata2})) {
 		my $line1 = $result{$func};
@@ -1535,7 +1786,9 @@
 	my $fn_hit;
 	my $function;
 
-	%result = %{$fnccount1};
+	if (defined($fnccount1)) {
+		%result = %{$fnccount1};
+	}
 	foreach $function (keys(%{$fnccount2})) {
 		$result{$function} += $fnccount2->{$function};
 	}
@@ -1589,6 +1842,167 @@
 	return \%result;
 }
 
+
+#
+# brcount_to_db(brcount)
+#
+# Convert brcount data to the following format:
+#
+# db:          line number    -> block hash
+# block hash:  block number   -> branch hash
+# branch hash: branch number  -> taken value
+#
+
+sub brcount_to_db($)
+{
+	my ($brcount) = @_;
+	my $line;
+	my $db;
+
+	# Add branches from first count to database
+	foreach $line (keys(%{$brcount})) {
+		my $brdata = $brcount->{$line};
+		my $i;
+		my $num = br_ivec_len($brdata);
+
+		for ($i = 0; $i < $num; $i++) {
+			my ($block, $branch, $taken) = br_ivec_get($brdata, $i);
+
+			$db->{$line}->{$block}->{$branch} = $taken;
+		}
+	}
+
+	return $db;
+}
+
+
+#
+# db_to_brcount(db)
+#
+# Convert branch coverage data back to brcount format.
+#
+
+sub db_to_brcount($)
+{
+	my ($db) = @_;
+	my $line;
+	my $brcount = {};
+	my $br_found = 0;
+	my $br_hit = 0;
+
+	# Convert database back to brcount format
+	foreach $line (sort({$a <=> $b} keys(%{$db}))) {
+		my $ldata = $db->{$line};
+		my $brdata;
+		my $block;
+
+		foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
+			my $bdata = $ldata->{$block};
+			my $branch;
+
+			foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
+				my $taken = $bdata->{$branch};
+
+				$br_found++;
+				$br_hit++ if ($taken ne "-" && $taken > 0);
+				$brdata = br_ivec_push($brdata, $block,
+						       $branch, $taken);
+			}
+		}
+		$brcount->{$line} = $brdata;
+	}
+
+	return ($brcount, $br_found, $br_hit);
+}
+
+
+#
+# combine_brcount(brcount1, brcount2, type)
+#
+# If add is BR_ADD, add branch coverage data and return list (brcount_added,
+# br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2
+# from brcount1 and return (brcount_sub, br_found, br_hit).
+#
+
+sub combine_brcount($$$)
+{
+	my ($brcount1, $brcount2, $type) = @_;
+	my $line;
+	my $block;
+	my $branch;
+	my $taken;
+	my $db;
+	my $br_found = 0;
+	my $br_hit = 0;
+	my $result;
+
+	# Convert branches from first count to database
+	$db = brcount_to_db($brcount1);
+	# Combine values from database and second count
+	foreach $line (keys(%{$brcount2})) {
+		my $brdata = $brcount2->{$line};
+		my $num = br_ivec_len($brdata);
+		my $i;
+
+		for ($i = 0; $i < $num; $i++) {
+			($block, $branch, $taken) = br_ivec_get($brdata, $i);
+			my $new_taken = $db->{$line}->{$block}->{$branch};
+
+			if ($type == $BR_ADD) {
+				$new_taken = br_taken_add($new_taken, $taken);
+			} elsif ($type == $BR_SUB) {
+				$new_taken = br_taken_sub($new_taken, $taken);
+			}
+			$db->{$line}->{$block}->{$branch} = $new_taken
+				if (defined($new_taken));
+		}
+	}
+	# Convert database back to brcount format
+	($result, $br_found, $br_hit) = db_to_brcount($db);
+
+	return ($result, $br_found, $br_hit);
+}
+
+
+#
+# add_testbrdata(testbrdata1, testbrdata2)
+#
+# Add branch coverage data for several tests. Return reference to
+# added_testbrdata.
+#
+
+sub add_testbrdata($$)
+{
+	my ($testbrdata1, $testbrdata2) = @_;
+	my %result;
+	my $testname;
+
+	foreach $testname (keys(%{$testbrdata1})) {
+		if (defined($testbrdata2->{$testname})) {
+			my $brcount;
+
+			# Branch coverage data for this testname exists
+			# in both data sets: add
+			($brcount) = combine_brcount($testbrdata1->{$testname},
+					 $testbrdata2->{$testname}, $BR_ADD);
+			$result{$testname} = $brcount;
+			next;
+		}
+		# Branch coverage data for this testname is unique to
+		# data set 1: copy
+		$result{$testname} = $testbrdata1->{$testname};
+	}
+
+	# Add count data for testnames unique to data set 2
+	foreach $testname (keys(%{$testbrdata2})) {
+		if (!defined($result{$testname})) {
+			$result{$testname} = $testbrdata2->{$testname};
+		}
+	}
+	return \%result;
+}
+
+
 #
 # combine_info_entries(entry_ref1, entry_ref2, filename)
 #
@@ -1605,6 +2019,8 @@
 	my $checkdata1;
 	my $testfncdata1;
 	my $sumfnccount1;
+	my $testbrdata1;
+	my $sumbrcount1;
 
 	my $entry2 = $_[1];	# Reference to hash containing second entry
 	my $testdata2;
@@ -1613,6 +2029,8 @@
 	my $checkdata2;
 	my $testfncdata2;
 	my $sumfnccount2;
+	my $testbrdata2;
+	my $sumbrcount2;
 
 	my %result;		# Hash containing combined entry
 	my %result_testdata;
@@ -1620,19 +2038,23 @@
 	my $result_funcdata;
 	my $result_testfncdata;
 	my $result_sumfnccount;
+	my $result_testbrdata;
+	my $result_sumbrcount;
 	my $lines_found;
 	my $lines_hit;
 	my $fn_found;
 	my $fn_hit;
+	my $br_found;
+	my $br_hit;
 
 	my $testname;
 	my $filename = $_[2];
 
 	# Retrieve data
 	($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
-	 $sumfnccount1) = get_info_entry($entry1);
+	 $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
 	($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
-	 $sumfnccount2) = get_info_entry($entry2);
+	 $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
 
 	# Merge checksums
 	$checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
@@ -1645,6 +2067,11 @@
 	($result_sumfnccount, $fn_found, $fn_hit) =
 		add_fnccount($sumfnccount1, $sumfnccount2);
 	
+	# Combine branch coverage data
+	$result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
+	($result_sumbrcount, $br_found, $br_hit) =
+		combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
+
 	# Combine testdata
 	foreach $testname (keys(%{$testdata1}))
 	{
@@ -1687,8 +2114,9 @@
 	# Store result
 	set_info_entry(\%result, \%result_testdata, $result_sumcount,
 		       $result_funcdata, $checkdata1, $result_testfncdata,
-		       $result_sumfnccount, $lines_found, $lines_hit,
-		       $fn_found, $fn_hit);
+		       $result_sumfnccount, $result_testbrdata,
+		       $result_sumbrcount, $lines_found, $lines_hit,
+		       $fn_found, $fn_hit, $br_found, $br_hit);
 
 	return(\%result);
 }
@@ -1730,16 +2158,17 @@
 
 
 #
-# get_prefix(filename_list)
+# get_prefix(min_dir, filename_list)
 #
 # Search FILENAME_LIST for a directory prefix which is common to as many
 # list entries as possible, so that removing this prefix will minimize the
-# sum of the lengths of all resulting shortened filenames.
+# sum of the lengths of all resulting shortened filenames while observing
+# that no filename has less than MIN_DIR parent directories.
 #
 
-sub get_prefix(@)
+sub get_prefix($@)
 {
-	my @filename_list = @_;		# provided list of filenames
+	my ($min_dir, @filename_list) = @_;
 	my %prefix;			# mapping: prefix -> sum of lengths
 	my $current;			# Temporary iteration variable
 
@@ -1748,12 +2177,14 @@
 	{
 		# Need explicit assignment to get a copy of $_ so that
 		# shortening the contained prefix does not affect the list
-		$current = shorten_prefix($_);
+		$current = $_;
 		while ($current = shorten_prefix($current))
 		{
+			$current .= "/";
+
 			# Skip rest if the remaining prefix has already been
 			# added to hash
-			if ($prefix{$current}) { last; }
+			if (exists($prefix{$current})) { last; }
 
 			# Initialize with 0
 			$prefix{$current}="0";
@@ -1761,6 +2192,20 @@
 
 	}
 
+	# Remove all prefixes that would cause filenames to have less than
+	# the minimum number of parent directories
+	foreach my $filename (@filename_list) {
+		my $dir = dirname($filename);
+
+		for (my $i = 0; $i < $min_dir; $i++) {
+			delete($prefix{$dir."/"});
+			$dir = shorten_prefix($dir);
+		}
+	}
+
+	# Check if any prefix remains
+	return undef if (!%prefix);
+
 	# Calculate sum of lengths for all prefixes
 	foreach $current (keys(%prefix))
 	{
@@ -1789,6 +2234,8 @@
 		}
 	}
 
+	$current =~ s/\/$//;
+
 	return($current);
 }
 
@@ -1880,7 +2327,7 @@
 	my $changed_testname;
 	local *TEST_HANDLE;
 
-	open(TEST_HANDLE, "<".$_[0])
+	open(TEST_HANDLE, "<", $_[0])
 		or die("ERROR: cannot open $_[0]!\n");
 
 	while (<TEST_HANDLE>)
@@ -1986,14 +2433,17 @@
 
 sub create_sub_dir($)
 {
-	system("mkdir", "-p" ,$_[0])
-		and die("ERROR: cannot create directory $_!\n");
+	my ($dir) = @_;
+
+	system("mkdir", "-p" ,$dir)
+		and die("ERROR: cannot create directory $dir!\n");
 }
 
 
 #
 # write_description_file(descriptions, overall_found, overall_hit,
-#                        total_fn_found, total_fn_hit)
+#                        total_fn_found, total_fn_hit, total_br_found,
+#                        total_br_hit)
 #
 # Write HTML file containing all test case descriptions. DESCRIPTIONS is a
 # reference to a hash containing a mapping
@@ -2003,20 +2453,22 @@
 # Die on error.
 #
 
-sub write_description_file($$$$$)
+sub write_description_file($$$$$$$)
 {
 	my %description = %{$_[0]};
 	my $found = $_[1];
 	my $hit = $_[2];
 	my $fn_found = $_[3];
 	my $fn_hit = $_[4];
+	my $br_found = $_[5];
+	my $br_hit = $_[6];
 	my $test_name;
 	local *HTML_HANDLE;
 
 	html_create(*HTML_HANDLE,"descriptions.$html_ext");
 	write_html_prolog(*HTML_HANDLE, "", "LCOV - test case descriptions");
 	write_header(*HTML_HANDLE, 3, "", "", $found, $hit, $fn_found,
-		     $fn_hit, 0);
+		     $fn_hit, $br_found, $br_hit, 0);
 
 	write_test_table_prolog(*HTML_HANDLE,
 			 "Test case descriptions - alphabetical list");
@@ -2146,7 +2598,7 @@
 		 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82] if ($sort);
 	foreach (keys(%data))
 	{
-		open(PNG_HANDLE, ">".$_)
+		open(PNG_HANDLE, ">", $_)
 			or die("ERROR: cannot create $_!\n");
 		binmode(PNG_HANDLE);
 		print(PNG_HANDLE map(chr,@{$data{$_}}));
@@ -2164,7 +2616,7 @@
 	local *HTACCESS_HANDLE;
 	my $htaccess_data;
 
-	open(*HTACCESS_HANDLE, ">.htaccess")
+	open(*HTACCESS_HANDLE, ">", ".htaccess")
 		or die("ERROR: cannot open .htaccess for writing!\n");
 
 	$htaccess_data = (<<"END_OF_HTACCESS")
@@ -2197,7 +2649,7 @@
 		return;
 	}
 
-	open(CSS_HANDLE, ">gcov.css")
+	open(CSS_HANDLE, ">", "gcov.css")
 		or die ("ERROR: cannot open gcov.css for writing!\n");
 
 
@@ -2328,17 +2780,6 @@
 	  background-color: #FF0000;
 	}
 	
-	/* All views: header legend item for legend entry */
-	td.headerItemLeg
-	{
-	  text-align: right;
-	  padding-right: 6px;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	  vertical-align: bottom;
-	  white-space: nowrap;
-	}
-
 	/* All views: header legend value for legend entry */
 	td.headerValueLeg
 	{
@@ -2419,6 +2860,7 @@
 	  padding-right: 10px;
 	  background-color: #A7FC9D;
 	  font-weight: bold;
+	  font-family: sans-serif;
 	}
 	
 	/* Directory view/File view (all): line count entry for files with
@@ -2430,16 +2872,7 @@
 	  padding-right: 10px;
 	  background-color: #A7FC9D;
 	  white-space: nowrap;
-	}
-	
-	/* Directory view/File view (all): legend entry for high coverage
-	   rate */
-	span.coverLegendHi
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-bottom: 2px;
-	  background-color: #A7FC9D;
+	  font-family: sans-serif;
 	}
 	
 	/* Directory view/File view (all): percentage entry for files with
@@ -2451,6 +2884,7 @@
 	  padding-right: 10px;
 	  background-color: #FFEA20;
 	  font-weight: bold;
+	  font-family: sans-serif;
 	}
 	
 	/* Directory view/File view (all): line count entry for files with
@@ -2462,16 +2896,7 @@
 	  padding-right: 10px;
 	  background-color: #FFEA20;
 	  white-space: nowrap;
-	}
-	
-	/* Directory view/File view (all): legend entry for medium coverage
-	   rate */
-	span.coverLegendMed
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-bottom: 2px;
-	  background-color: #FFEA20;
+	  font-family: sans-serif;
 	}
 	
 	/* Directory view/File view (all): percentage entry for files with
@@ -2483,6 +2908,7 @@
 	  padding-right: 10px;
 	  background-color: #FF0000;
 	  font-weight: bold;
+	  font-family: sans-serif;
 	}
 	
 	/* Directory view/File view (all): line count entry for files with
@@ -2494,53 +2920,28 @@
 	  padding-right: 10px;
 	  background-color: #FF0000;
 	  white-space: nowrap;
-	}
-	
-	/* Directory view/File view (all): legend entry for low coverage
-	   rate */
-	span.coverLegendLo
-	{
-	  padding-left: 10px;
-	  padding-right: 10px;
-	  padding-bottom: 2px;
-	  background-color: #FF0000;
+	  font-family: sans-serif;
 	}
 	
 	/* File view (all): "show/hide details" link format */
 	a.detail:link
 	{
 	  color: #B8D0FF;
+	  font-size:80%;
 	}
 	
 	/* File view (all): "show/hide details" link - visited format */
 	a.detail:visited
 	{
 	  color: #B8D0FF;
+	  font-size:80%;
 	}
 	
 	/* File view (all): "show/hide details" link - activated format */
 	a.detail:active
 	{
 	  color: #FFFFFF;
-	}
-	
-	/* File view (detail): test name table headline format */
-	td.testNameHead
-	{
-	  text-align: right;
-	  padding-right: 10px;
-	  background-color: #DAE7FE;
-	  font-family: sans-serif;
-	  font-weight: bold;
-	}
-	
-	/* File view (detail): test lines table headline format */
-	td.testLinesHead
-	{
-	  text-align: center;
-	  background-color: #DAE7FE;
-	  font-family: sans-serif;
-	  font-weight: bold;
+	  font-size:80%;
 	}
 	
 	/* File view (detail): test name entry */
@@ -2549,6 +2950,7 @@
 	  text-align: right;
 	  padding-right: 10px;
 	  background-color: #DAE7FE;
+	  font-family: sans-serif;
 	}
 	
 	/* File view (detail): test percentage entry */
@@ -2558,6 +2960,7 @@
 	  padding-left: 10px;
 	  padding-right: 10px; 
 	  background-color: #DAE7FE;
+	  font-family: sans-serif;
 	}
 	
 	/* File view (detail): test lines count entry */
@@ -2567,6 +2970,7 @@
 	  padding-left: 10px;
 	  padding-right: 10px; 
 	  background-color: #DAE7FE;
+	  font-family: sans-serif;
 	}
 	
 	/* Test case descriptions: test name format*/
@@ -2605,6 +3009,7 @@
 	  padding-right: 10px;
 	  background-color: #FF0000;
 	  font-weight: bold;
+	  font-family: sans-serif;
 	}
 
 	/* Source code view: function entry nonzero count*/
@@ -2615,14 +3020,15 @@
 	  padding-right: 10px;
 	  background-color: #DAE7FE;
 	  font-weight: bold;
+	  font-family: sans-serif;
 	}
 
 	/* Source code view: source code format */
-	/* Source code view: source code format */
 	pre.source
 	{
 	  font-family: monospace;
 	  white-space: pre;
+	  margin-top: 2px;
 	}
 	
 	/* Source code view: line number format */
@@ -2660,7 +3066,7 @@
 	  padding-left: 10px;
 	  padding-right: 10px;
 	  padding-bottom: 2px;
-	  background-color: #FF0000;
+	  background-color: #FF6230;
 	}
 	
 	/* Source code view (function table): standard link - visited format */
@@ -2678,13 +3084,96 @@
 	  background-color: #B5F7AF;
 	}
 	
-	/* Source code view: format for DiffCov legend */
-	span.LegendDiffCov
+	/* Source code view: format for branches which were executed
+	 * and taken */
+	span.branchCov
 	{
+	  background-color: #CAD7FE;
+	}
+
+	/* Source code view: format for branches which were executed
+	 * but not taken */
+	span.branchNoCov
+	{
+	  background-color: #FF6230;
+	}
+
+	/* Source code view: format for branches which were not executed */
+	span.branchNoExec
+	{
+	  background-color: #FF6230;
+	}
+
+	/* Source code view: format for the source code heading line */
+	pre.sourceHeading
+	{
+	  white-space: pre;
+	  font-family: monospace;
+	  font-weight: bold;
+	  margin: 0px;
+	}
+
+	/* All views: header legend value for low rate */
+	td.headerValueLegL
+	{
+	  font-family: sans-serif;
 	  text-align: center;
+	  white-space: nowrap;
+	  padding-left: 4px;
+	  padding-right: 2px;
+	  background-color: #FF0000;
+	  font-size: 80%;
+	}
+
+	/* All views: header legend value for med rate */
+	td.headerValueLegM
+	{
+	  font-family: sans-serif;
+	  text-align: center;
+	  white-space: nowrap;
+	  padding-left: 2px;
+	  padding-right: 2px;
+	  background-color: #FFEA20;
+	  font-size: 80%;
+	}
+
+	/* All views: header legend value for hi rate */
+	td.headerValueLegH
+	{
+	  font-family: sans-serif;
+	  text-align: center;
+	  white-space: nowrap;
+	  padding-left: 2px;
+	  padding-right: 4px;
+	  background-color: #A7FC9D;
+	  font-size: 80%;
+	}
+
+	/* All views except source code view: legend format for low coverage */
+	span.coverLegendCovLo
+	{
 	  padding-left: 10px;
 	  padding-right: 10px;
-	  background-color: #B5F7AF;
+	  padding-top: 2px;
+	  background-color: #FF0000;
+	}
+
+	/* All views except source code view: legend format for med coverage */
+	span.coverLegendCovMed
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  padding-top: 2px;
+	  background-color: #FFEA20;
+	}
+
+	/* All views except source code view: legend format for hi coverage */
+	span.coverLegendCovHi
+	{
+	  padding-left: 10px;
+	  padding-right: 10px;
+	  padding-top: 2px;
+	  background-color: #A7FC9D;
 	}
 END_OF_CSS
 	;
@@ -2710,6 +3199,7 @@
 
 sub get_bar_graph_code($$$)
 {
+	my ($base_dir, $found, $hit) = @_;
 	my $rate;
 	my $alt;
 	my $width;
@@ -2720,13 +3210,12 @@
 	# Check number of instrumented lines
 	if ($_[1] == 0) { return ""; }
 
-	$rate		= $_[2] * 100 / $_[1];
-	$alt		= sprintf("%.1f", $rate)."%";
-	$width		= sprintf("%.0f", $rate);
-	$remainder	= sprintf("%d", 100-$width);
+	$alt		= rate($hit, $found, "%");
+	$width		= rate($hit, $found, undef, 0);
+	$remainder	= 100 - $width;
 
 	# Decide which .png file to use
-	$png_name = $rate_png[classify_rate($_[1], $_[2], $med_limit,
+	$png_name = $rate_png[classify_rate($found, $hit, $med_limit,
 					    $hi_limit)];
 
 	if ($width == 0)
@@ -2775,7 +3264,7 @@
 	if ($found == 0) {
 		return 2;
 	}
-	$rate = $hit * 100 / $found;
+	$rate = rate($hit, $found);
 	if ($rate < $med) {
 		return 0;
 	} elsif ($rate < $hi) {
@@ -2853,104 +3342,40 @@
 
 
 #
-# write_header_line(filehandle, type, additional params..)
+# write_header_line(handle, content)
 #
-# Write a header line.
+# Write a header line with the specified table contents.
 #
 
-sub write_header_line(*$@)
+sub write_header_line(*@)
 {
-	my $HANDLE = shift;
-	my $type = shift;
-	my @args = @_;
+	my ($handle, @content) = @_;
+	my $entry;
 
-	# Reduce indentation by using gotos
-	if ($type eq 0) {
-		goto header;
-	} elsif ($type eq 1) {
-		goto body;
-	} elsif ($type eq 2) {
-		goto legend_dir;
-	} elsif ($type eq 3) {
-		goto legend_source;
-	} elsif ($type eq 4) {
-		goto half_body;
+	write_html($handle, "          <tr>\n");
+	foreach $entry (@content) {
+		my ($width, $class, $text, $colspan) = @{$entry};
+
+		if (defined($width)) {
+			$width = " width=\"$width\"";
+		} else {
+			$width = "";
+		}
+		if (defined($class)) {
+			$class = " class=\"$class\"";
+		} else {
+			$class = "";
+		}
+		if (defined($colspan)) {
+			$colspan = " colspan=\"$colspan\"";
+		} else {
+			$colspan = "";
+		}
+		$text = "" if (!defined($text));
+		write_html($handle,
+			   "            <td$width$class$colspan>$text</td>\n");
 	}
-
-header:
-	# *************************************************************
-	write_html($HANDLE, <<END_OF_HTML);
-        <tr>
-          <td width="5%"></td>
-          <td width="10%" class="headerItem">$args[0]</td>
-          <td width="35%" class="headerValue">$args[1]</td>
-          <td width="10%"></td>
-          <td width="10%" class="headerCovTableHead">$args[2]</td>
-          <td width="10%" class="headerCovTableHead">$args[3]</td>
-          <td width="15%" class="headerCovTableHead">$args[4]</td>
-          <td width="5%"></td>
-        </tr>
-END_OF_HTML
-	# *************************************************************
-	return;
-
-body:
-	# *************************************************************
-	write_html($HANDLE, <<END_OF_HTML);
-        <tr>
-          <td></td>
-          <td class="headerItem">$args[0]</td>
-          <td class="headerValue">$args[1]</td>
-          <td class="headerItem">$args[2]</td>
-          <td class="headerCovTableEntry">$args[3]</td>
-          <td class="headerCovTableEntry">$args[4]</td>
-          <td class="headerCovTableEntry$args[5]">$args[6]</td>
-        </tr>
-END_OF_HTML
-	# *************************************************************
-	return;
-
-half_body:
-	# *************************************************************
-	write_html($HANDLE, <<END_OF_HTML);
-        <tr>
-          <td></td>
-          <td class="headerItem">$args[0]</td>
-          <td class="headerValue">$args[1]</td>
-        </tr>
-END_OF_HTML
-	# *************************************************************
-	return;
-
-legend_dir:
-	# *************************************************************
-	write_html($HANDLE, <<END_OF_HTML);
-        <tr>
-          <td></td>
-          <td class="headerItemLeg">$args[0]</td>
-          <td class="headerValueLeg">
-$args[1]          </td>
-          <td></td>
-          <td class="headerValueLeg" colspan=3>
-$args[2]          </td>
-        </tr>
-END_OF_HTML
-	# *************************************************************
-	return;
-
-legend_source:
-	# *************************************************************
-	write_html($HANDLE, <<END_OF_HTML);
-        <tr>
-          <td></td>
-          <td class="headerItem">$args[0]</td>
-          <td class="headerValueLeg" colspan=5>
-            <span class="coverLegendNoCov">$args[1]</span>
-            <span class="coverLegendCov">$args[2]</span>
-          </td>
-        </tr>
-END_OF_HTML
-	# *************************************************************
+	write_html($handle, "          </tr>\n");
 }
 
 
@@ -2965,10 +3390,11 @@
 	# *************************************************************
 
 	write_html($_[0], <<END_OF_HTML)
-                <tr><td><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
+	          <tr><td><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
 	        </table>
 	      </td>
 	    </tr>
+
 	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
 	  </table>
 
@@ -2980,244 +3406,170 @@
 
 
 #
-# write_file_table_prolog(filehandle, file_heading, lines_heading, func_heading)
+# write_file_table_prolog(handle, file_heading, ([heading, num_cols], ...))
 #
 # Write heading for file table.
 #
 
-sub write_file_table_prolog(*$$$)
+sub write_file_table_prolog(*$@)
 {
-	# *************************************************************
+	my ($handle, $file_heading, @columns) = @_;
+	my $num_columns = 0;
+	my $file_width;
+	my $col;
+	my $width;
 
-        if ($func_coverage)
-        {
-                write_html($_[0], <<END_OF_HTML)
+	$width = 20 if (scalar(@columns) == 1);
+	$width = 10 if (scalar(@columns) == 2);
+	$width = 8 if (scalar(@columns) > 2);
+
+	foreach $col (@columns) {
+		my ($heading, $cols) = @{$col};
+
+		$num_columns += $cols;
+	}
+	$file_width = 100 - $num_columns * $width;
+
+	# Table definition
+	write_html($handle, <<END_OF_HTML);
 	  <center>
 	  <table width="80%" cellpadding=1 cellspacing=1 border=0>
 
 	    <tr>
-	      <td width="45%"><br></td>
-	      <td width="15%"></td>
-	      <td width="10%"></td>
-	      <td width="10%"></td>
-	      <td width="10%"></td>
-	      <td width="10%"></td>
-	    </tr>
-
-	    <tr>
-	      <td class="tableHead">$_[1]</td>
-	      <td class="tableHead" colspan=3>$_[2]</td>
-	      <td class="tableHead" colspan=2>$_[3]</td>
-	    </tr>
-
+	      <td width="$file_width%"><br></td>
 END_OF_HTML
-                ;
-        }
-        else
-        {
-                write_html($_[0], <<END_OF_HTML)
-	  <center>
-	  <table width="80%" cellpadding=1 cellspacing=1 border=0>
+	# Empty first row
+	foreach $col (@columns) {
+		my ($heading, $cols) = @{$col};
 
-	    <tr>
-	      <td width="50%"><br></td>
-	      <td width="15%"></td>
-	      <td width="15%"></td>
-	      <td width="20%"></td>
-	    </tr>
-
-	    <tr>
-	      <td class="tableHead">$_[1]</td>
-	      <td class="tableHead" colspan=3>$_[2]</td>
-	    </tr>
-
+		while ($cols-- > 0) {
+			write_html($handle, <<END_OF_HTML);
+	      <td width="$width%"></td>
 END_OF_HTML
-                ;
-        }
+		}
+	}
+	# Next row
+	write_html($handle, <<END_OF_HTML);
+	    </tr>
 
-	# *************************************************************
+	    <tr>
+	      <td class="tableHead">$file_heading</td>
+END_OF_HTML
+	# Heading row
+	foreach $col (@columns) {
+		my ($heading, $cols) = @{$col};
+		my $colspan = "";
+
+		$colspan = " colspan=$cols" if ($cols > 1);
+		write_html($handle, <<END_OF_HTML);
+	      <td class="tableHead"$colspan>$heading</td>
+END_OF_HTML
+	}
+	write_html($handle, <<END_OF_HTML);
+	    </tr>
+END_OF_HTML
 }
 
 
-#
-# write_file_table_entry(filehandle, cover_filename, cover_bar_graph,
-#                        cover_found, cover_hit, fn_found, fn_hit,
-#			 page_link, func_link)
+# write_file_table_entry(handle, base_dir, filename, page_link,
+#			 ([ found, hit, med_limit, hi_limit, graph ], ..)
 #
 # Write an entry of the file table.
 #
 
-sub write_file_table_entry(*$$$$$$$)
+sub write_file_table_entry(*$$$@)
 {
-	local *HANDLE = shift;
-	my ($filename, $bar_graph, $found, $hit, $fn_found, $fn_hit,
-	    $page_link) = @_;
-	my $rate;
-	my $rate_string;
-	my $funcs_string;
-	my $class_lines = "Lo";
-	my $class_funcs = "Hi";
+	my ($handle, $base_dir, $filename, $page_link, @entries) = @_;
 	my $file_code;
+	my $entry;
+	my $esc_filename = escape_html($filename);
 
 	# Add link to source if provided
 	if (defined($page_link) && $page_link ne "") {
-		$file_code = "<a href=\"$page_link\">$filename</a>";
+		$file_code = "<a href=\"$page_link\">$esc_filename</a>";
 	} else {
-		$file_code = $filename;
+		$file_code = $esc_filename;
 	}
 
-	# Get line coverage rate
-	if ($found > 0)
-	{
-		$rate = $hit * 100 / $found;
-		$rate_string = sprintf("%.1f", $rate)."&nbsp;%";
-		
-		$class_lines = $rate_name[classify_rate($found, $hit,
-					  $med_limit, $hi_limit)];
-	}
-	else
-	{
-		$rate_string = "-";
-	}
-
-	# Get function coverage rate
-	if ($fn_found > 0)
-	{
-		$rate = $fn_hit * 100 / $fn_found;
-		$class_funcs = $rate_name[classify_rate($fn_found, $fn_hit,
-					  $fn_med_limit, $fn_hi_limit)];
-		$funcs_string = sprintf("%.1f", $rate)."&nbsp;%";		
-	}
-	else
-	{
-		# Define 0 of 0 functions as 100%
-		$rate = 100;
-		$funcs_string = "-";
-	}
-
-	# *************************************************************
-
-	write_html(*HANDLE, <<END_OF_HTML)
+	# First column: filename
+	write_html($handle, <<END_OF_HTML);
 	    <tr>
 	      <td class="coverFile">$file_code</td>
+END_OF_HTML
+	# Columns as defined
+	foreach $entry (@entries) {
+		my ($found, $hit, $med, $hi, $graph) = @{$entry};
+		my $bar_graph;
+		my $class;
+		my $rate;
+
+		# Generate bar graph if requested
+		if ($graph) {
+			$bar_graph = get_bar_graph_code($base_dir, $found,
+							$hit);
+			write_html($handle, <<END_OF_HTML);
 	      <td class="coverBar" align="center">
 	        $bar_graph
 	      </td>
-	      <td class="coverPer$class_lines">$rate_string</td>
-	      <td class="coverNum$class_lines">$hit / $found</td>
 END_OF_HTML
-	;
-
-        if ($func_coverage)
-        {
-                write_html(*HANDLE, <<END_OF_HTML)
-	      <td class="coverPer$class_funcs">$funcs_string</td>
-	      <td class="coverNum$class_funcs">$fn_hit / $fn_found</td>
+		}
+		# Get rate color and text
+		if ($found == 0) {
+			$rate = "-";
+			$class = "Hi";
+		} else {
+			$rate = rate($hit, $found, "&nbsp;%");
+			$class = $rate_name[classify_rate($found, $hit,
+					    $med, $hi)];
+		}
+		write_html($handle, <<END_OF_HTML);
+	      <td class="coverPer$class">$rate</td>
+	      <td class="coverNum$class">$hit / $found</td>
 END_OF_HTML
-	        ;
-        }
-        write_html(*HANDLE, <<END_OF_HTML)
+	}
+	# End of row
+        write_html($handle, <<END_OF_HTML);
 	    </tr>
 END_OF_HTML
-        ;
-
-	# *************************************************************
 }
 
 
 #
-# write_file_table_detail_heading(filehandle, left_heading, right_heading)
-#
-# Write heading for detail section in file table.
-#
-
-sub write_file_table_detail_heading(*$$$)
-{
-        my $func_rows = "";
-
-        if ($func_coverage)
-        {
-                $func_rows = "<td class=\"testLinesHead\" colspan=2>$_[3]</td>";
-        }
-
-	# *************************************************************
-	write_html($_[0], <<END_OF_HTML)
-	    <tr>
-	      <td class="testNameHead" colspan=2>$_[1]</td>
-	      <td class="testLinesHead" colspan=2>$_[2]</td>
-              $func_rows
-	    </tr>
-
-END_OF_HTML
-	;
-
-	# *************************************************************
-}
-
-
-#
-# write_file_table_detail_entry(filehandle, test_name,
-#               cover_found, cover_hit, func_found, func_hit)
+# write_file_table_detail_entry(filehandle, test_name, ([found, hit], ...))
 #
 # Write entry for detail section in file table.
 #
 
-sub write_file_table_detail_entry(*$$$$$)
+sub write_file_table_detail_entry(*$@)
 {
-	my $rate;
-	my $func_rate;
-	my $name = $_[1];
-	
-	if ($_[2]>0)
-	{
-		$rate = sprintf("%.1f", $_[3]*100/$_[2])."&nbsp;%";
-	}
-	else
-	{
-		$rate = "-";
-	}
+	my ($handle, $test, @entries) = @_;
+	my $entry;
 
-	if ($_[4]>0)
-	{
-		$func_rate = sprintf("%.1f", $_[5]*100/$_[4])."&nbsp;%";
+	if ($test eq "") {
+		$test = "<span style=\"font-style:italic\">&lt;unnamed&gt;</span>";
+	} elsif ($test =~ /^(.*),diff$/) {
+		$test = $1." (converted)";
 	}
-	else
-	{
-		$func_rate = "-";
-	}
-
-	if ($name =~ /^(.*),diff$/)
-	{
-		$name = $1." (converted)";
-	}
-
-	if ($name eq "")
-	{
-		$name = "<span style=\"font-style:italic\">&lt;unnamed&gt;</span>";
-	}
-
-	# *************************************************************
-
-	write_html($_[0], <<END_OF_HTML)
+	# Testname
+	write_html($handle, <<END_OF_HTML);
 	    <tr>
-	      <td class="testName" colspan=2>$name</td>
+	      <td class="testName" colspan=2>$test</td>
+END_OF_HTML
+	# Test data
+	foreach $entry (@entries) {
+		my ($found, $hit) = @{$entry};
+		my $rate = rate($hit, $found, "&nbsp;%");
+
+		write_html($handle, <<END_OF_HTML);
 	      <td class="testPer">$rate</td>
-	      <td class="testNum">$_[3]&nbsp;/&nbsp;$_[2]&nbsp;lines</td>
+	      <td class="testNum">$hit&nbsp;/&nbsp;$found</td>
 END_OF_HTML
-	;
-        if ($func_coverage)
-        {
-                write_html($_[0], <<END_OF_HTML)
-	      <td class="testPer">$func_rate</td>
-	      <td class="testNum">$_[5]&nbsp;/&nbsp;$_[4]</td>
-END_OF_HTML
-	        ;
-        }
-        write_html($_[0], <<END_OF_HTML)
+	}
+
+        write_html($handle, <<END_OF_HTML);
 	    </tr>
 
 END_OF_HTML
-        ;
 
 	# *************************************************************
 }
@@ -3322,6 +3674,17 @@
 }
 
 
+sub fmt_centered($$)
+{
+	my ($width, $text) = @_;
+	my $w0 = length($text);
+	my $w1 = int(($width - $w0) / 2);
+	my $w2 = $width - $w0 - $w1;
+
+	return (" "x$w1).$text.(" "x$w2);
+}
+
+
 #
 # write_source_prolog(filehandle)
 #
@@ -3330,6 +3693,15 @@
 
 sub write_source_prolog(*)
 {
+	my $lineno_heading = "         ";
+	my $branch_heading = "";
+	my $line_heading = fmt_centered($line_field_width, "Line data");
+	my $source_heading = " Source code";
+
+	if ($br_coverage) {
+		$branch_heading = fmt_centered($br_field_width, "Branch data").
+				  " ";
+	}
 	# *************************************************************
 
 	write_html($_[0], <<END_OF_HTML)
@@ -3338,7 +3710,9 @@
 	      <td><br></td>
 	    </tr>
 	    <tr>
-	      <td><pre class="source">
+	      <td>
+<pre class="sourceHeading">${lineno_heading}${branch_heading}${line_heading} ${source_heading}</pre>
+<pre class="source">
 END_OF_HTML
 	;
 
@@ -3347,51 +3721,251 @@
 
 
 #
+# get_branch_blocks(brdata)
+#
+# Group branches that belong to the same basic block.
+#
+# Returns: [block1, block2, ...]
+# block:   [branch1, branch2, ...]
+# branch:  [block_num, branch_num, taken_count, text_length, open, close]
+#
+
+sub get_branch_blocks($)
+{
+	my ($brdata) = @_;
+	my $last_block_num;
+	my $block = [];
+	my @blocks;
+	my $i;
+	my $num = br_ivec_len($brdata);
+
+	# Group branches
+	for ($i = 0; $i < $num; $i++) {
+		my ($block_num, $branch, $taken) = br_ivec_get($brdata, $i);
+		my $br;
+
+		if (defined($last_block_num) && $block_num != $last_block_num) {
+			push(@blocks, $block);
+			$block = [];
+		}
+		$br = [$block_num, $branch, $taken, 3, 0, 0];
+		push(@{$block}, $br);
+		$last_block_num = $block_num;
+	}
+	push(@blocks, $block) if (scalar(@{$block}) > 0);
+
+	# Add braces to first and last branch in group
+	foreach $block (@blocks) {
+		$block->[0]->[$BR_OPEN] = 1;
+		$block->[0]->[$BR_LEN]++;
+		$block->[scalar(@{$block}) - 1]->[$BR_CLOSE] = 1;
+		$block->[scalar(@{$block}) - 1]->[$BR_LEN]++;
+	}
+
+	return @blocks;
+}
+
+#
+# get_block_len(block)
+#
+# Calculate total text length of all branches in a block of branches.
+#
+
+sub get_block_len($)
+{
+	my ($block) = @_;
+	my $len = 0;
+	my $branch;
+
+	foreach $branch (@{$block}) {
+		$len += $branch->[$BR_LEN];
+	}
+
+	return $len;
+}
+
+
+#
+# get_branch_html(brdata)
+#
+# Return a list of HTML lines which represent the specified branch coverage
+# data in source code view.
+#
+
+sub get_branch_html($)
+{
+	my ($brdata) = @_;
+	my @blocks = get_branch_blocks($brdata);
+	my $block;
+	my $branch;
+	my $line_len = 0;
+	my $line = [];	# [branch2|" ", branch|" ", ...]
+	my @lines;	# [line1, line2, ...]
+	my @result;
+
+	# Distribute blocks to lines
+	foreach $block (@blocks) {
+		my $block_len = get_block_len($block);
+
+		# Does this block fit into the current line?
+		if ($line_len + $block_len <= $br_field_width) {
+			# Add it
+			$line_len += $block_len;
+			push(@{$line}, @{$block});
+			next;
+		} elsif ($block_len <= $br_field_width) {
+			# It would fit if the line was empty - add it to new
+			# line
+			push(@lines, $line);
+			$line_len = $block_len;
+			$line = [ @{$block} ];
+			next;
+		}
+		# Split the block into several lines
+		foreach $branch (@{$block}) {
+			if ($line_len + $branch->[$BR_LEN] >= $br_field_width) {
+				# Start a new line
+				if (($line_len + 1 <= $br_field_width) &&
+				    scalar(@{$line}) > 0 &&
+				    !$line->[scalar(@$line) - 1]->[$BR_CLOSE]) {
+					# Try to align branch symbols to be in
+					# one # row
+					push(@{$line}, " ");
+				}
+				push(@lines, $line);
+				$line_len = 0;
+				$line = [];
+			}
+			push(@{$line}, $branch);
+			$line_len += $branch->[$BR_LEN];
+		}
+	}
+	push(@lines, $line);
+
+	# Convert to HTML
+	foreach $line (@lines) {
+		my $current = "";
+		my $current_len = 0;
+
+		foreach $branch (@$line) {
+			# Skip alignment space
+			if ($branch eq " ") {
+				$current .= " ";
+				$current_len++;
+				next;
+			}
+
+			my ($block_num, $br_num, $taken, $len, $open, $close) =
+			   @{$branch};
+			my $class;
+			my $title;
+			my $text;
+
+			if ($taken eq '-') {
+				$class	= "branchNoExec";
+				$text	= " # ";
+				$title	= "Branch $br_num was not executed";
+			} elsif ($taken == 0) {
+				$class	= "branchNoCov";
+				$text	= " - ";
+				$title	= "Branch $br_num was not taken";
+			} else {
+				$class	= "branchCov";
+				$text	= " + ";
+				$title	= "Branch $br_num was taken $taken ".
+					  "time";
+				$title .= "s" if ($taken > 1);
+			}
+			$current .= "[" if ($open);
+			$current .= "<span class=\"$class\" title=\"$title\">";
+			$current .= $text."</span>";
+			$current .= "]" if ($close);
+			$current_len += $len;
+		}
+
+		# Right-align result text
+		if ($current_len < $br_field_width) {
+			$current = (" "x($br_field_width - $current_len)).
+				   $current;
+		}
+		push(@result, $current);
+	}
+
+	return @result;
+}
+
+
+#
+# format_count(count, width)
+#
+# Return a right-aligned representation of count that fits in width characters.
+#
+
+sub format_count($$)
+{
+	my ($count, $width) = @_;
+	my $result;
+	my $exp;
+
+	$result = sprintf("%*.0f", $width, $count);
+	while (length($result) > $width) {
+		last if ($count < 10);
+		$exp++;
+		$count = int($count/10);
+		$result = sprintf("%*s", $width, ">$count*10^$exp");
+	}
+	return $result;
+}
+
+#
 # write_source_line(filehandle, line_num, source, hit_count, converted,
-#                   add_anchor)
+#                   brdata, add_anchor)
 #
 # Write formatted source code line. Return a line in a format as needed
 # by gen_png()
 #
 
-sub write_source_line(*$$$$$)
+sub write_source_line(*$$$$$$)
 {
+	my ($handle, $line, $source, $count, $converted, $brdata,
+	    $add_anchor) = @_;
 	my $source_format;
-	my $count;
+	my $count_format;
 	my $result;
 	my $anchor_start = "";
 	my $anchor_end = "";
+	my $count_field_width = $line_field_width - 1;
+	my @br_html;
+	my $html;
 
-	if (!(defined$_[3]))
-	{
+	# Get branch HTML data for this line
+	@br_html = get_branch_html($brdata) if ($br_coverage);
+
+	if (!defined($count)) {
 		$result		= "";
 		$source_format	= "";
-		$count		= " "x15;
+		$count_format	= " "x$count_field_width;
 	}
-	elsif ($_[3] == 0)
-	{
-		$result		= $_[3];
+	elsif ($count == 0) {
+		$result		= $count;
 		$source_format	= '<span class="lineNoCov">';
-		$count		= sprintf("%15d", $_[3]);
+		$count_format	= format_count($count, $count_field_width);
 	}
-	elsif ($_[4] && defined($highlight))
-	{
-		$result		= "*".$_[3];
+	elsif ($converted && defined($highlight)) {
+		$result		= "*".$count;
 		$source_format	= '<span class="lineDiffCov">';
-		$count		= sprintf("%15d", $_[3]);
+		$count_format	= format_count($count, $count_field_width);
 	}
-	else
-	{
-		$result		= $_[3];
+	else {
+		$result		= $count;
 		$source_format	= '<span class="lineCov">';
-		$count		= sprintf("%15d", $_[3]);
+		$count_format	= format_count($count, $count_field_width);
 	}
-
-	$result .= ":".$_[2];
+	$result .= ":".$source;
 
 	# Write out a line number navigation anchor every $nav_resolution
 	# lines if necessary
-	if ($_[5])
+	if ($add_anchor)
 	{
 		$anchor_start	= "<a name=\"$_[1]\">";
 		$anchor_end	= "</a>";
@@ -3400,13 +3974,23 @@
 
 	# *************************************************************
 
-	write_html($_[0],
-		   $anchor_start.
-		   '<span class="lineNum">'.sprintf("%8d", $_[1]).
-		   " </span>$source_format$count : ".
-		   escape_html($_[2]).($source_format?"</span>":"").
-		   $anchor_end."\n");
+	$html = $anchor_start;
+	$html .= "<span class=\"lineNum\">".sprintf("%8d", $line)." </span>";
+	$html .= shift(@br_html).":" if ($br_coverage);
+	$html .= "$source_format$count_format : ";
+	$html .= escape_html($source);
+	$html .= "</span>" if ($source_format);
+	$html .= $anchor_end."\n";
 
+	write_html($handle, $html);
+
+	if ($br_coverage) {
+		# Add lines for overlong branch information
+		foreach (@br_html) {
+			write_html($handle, "<span class=\"lineNum\">".
+				   "         </span>$_\n");
+		}
+	}
 	# *************************************************************
 
 	return($result);
@@ -3460,8 +4044,8 @@
 
 	write_html($_[0], <<END_OF_HTML)
 	  <table width="100%" border=0 cellspacing=0 cellpadding=0>
-	  <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
-	  <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_code>$lcov_version</a></td></tr>
+	    <tr><td class="ruler"><img src="$_[1]glass.png" width=3 height=3 alt=""></td></tr>
+	    <tr><td class="versionInfo">Generated by: <a href="$lcov_url"$break_code>$lcov_version</a></td></tr>
 	  </table>
 	  <br>
 END_OF_HTML
@@ -3491,7 +4075,7 @@
 	<html lang="en">
 
 	<head>
-	  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+	  <meta http-equiv="Content-Type" content="text/html; charset=$charset">
 	  <title>$_[3]</title>
 	  <link rel="stylesheet" type="text/css" href="$_[1]gcov.css">
 	</head>
@@ -3554,7 +4138,7 @@
 
 	<head>
 	  <title>$_[3]</title>
-	  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+	  <meta http-equiv="Content-Type" content="text/html; charset=$charset">
 	  <link rel="stylesheet" type="text/css" href="$_[1]gcov.css">
 	</head>
 
@@ -3601,51 +4185,14 @@
 }
 
 
-# rate_to_col(found, hit)
-#
-# Return Lo, Med or Hi, depending on the coverage rate.
-#
-
-sub rate_to_col($$)
+sub max($$)
 {
-	my ($found, $hit) = @_;
-	my $rate;
+	my ($a, $b) = @_;
 
-	if ($found == 0) {
-		return "Hi";
-	}
-	$rate = 100 * $hit / $found;
-	if ($rate < $med_limit) {
-		return "Lo";
-	} elsif ($rate < $hi_limit) {
-		return "Med";
-	}
-	return "Hi";
+	return $a if ($a > $b);
+	return $b;
 }
 
-# format_rate(found, hit)
-#
-# Return formatted percent string for coverage rate.
-#
-
-sub format_rate($$)
-{	
-	return $_[0] == 0 ? "-" : sprintf("%.1f", $_[1] * 100 / $_[0])." %";
-}
-
-sub get_legend_code($$$)
-{
-	my ($text, $med, $hi) = @_;
-	my $result;
-
-	$result = <<EOF;
-	            $text<br>
-	            <span class="coverLegendLo">0% to $med%</span>
-	            <span class="coverLegendMed">$med% to $hi%</span>
-	            <span class="coverLegendHi">$hi% to 100%</span>
-EOF
-	return $result;
-}
 
 #
 # write_header(filehandle, type, trunc_file_name, rel_file_name, lines_found,
@@ -3656,7 +4203,7 @@
 # header, test case description header, function view header)
 #
 
-sub write_header(*$$$$$$$$)
+sub write_header(*$$$$$$$$$$)
 {
 	local *HTML_HANDLE = $_[0];
 	my $type = $_[1];
@@ -3666,32 +4213,43 @@
 	my $lines_hit = $_[5];
 	my $fn_found = $_[6];
 	my $fn_hit = $_[7];
-	my $sort_type = $_[8];
+	my $br_found = $_[8];
+	my $br_hit = $_[9];
+	my $sort_type = $_[10];
 	my $base_dir;
 	my $view;
 	my $test;
 	my $base_name;
+	my $style;
+	my $rate;
+	my @row_left;
+	my @row_right;
+	my $num_rows;
+	my $i;
+	my $esc_trunc_name = escape_html($trunc_name);
 
 	$base_name = basename($rel_filename);
 
 	# Prepare text for "current view" field
-	if ($type == 0)
+	if ($type == $HDR_DIR)
 	{
 		# Main overview
 		$base_dir = "";
 		$view = $overview_title;
 	}
-	elsif ($type == 1)
+	elsif ($type == $HDR_FILE)
 	{
 		# Directory overview
 		$base_dir = get_relative_base_path($rel_filename);
 		$view = "<a href=\"$base_dir"."index.$html_ext\">".
-			"$overview_title</a> - $trunc_name";
+			"$overview_title</a> - $esc_trunc_name";
 	}
-	elsif ($type == 2 || $type == 4)
+	elsif ($type == $HDR_SOURCE || $type == $HDR_FUNC)
 	{
 		# File view
 		my $dir_name = dirname($rel_filename);
+		my $esc_base_name = escape_html($base_name);
+		my $esc_dir_name = escape_html($dir_name);
 
 		$base_dir = get_relative_base_path($dir_name);
 		if ($frames)
@@ -3701,26 +4259,28 @@
 			$view = "<a href=\"$base_dir"."index.$html_ext\" ".
 				"target=\"_parent\">$overview_title</a> - ".
 				"<a href=\"index.$html_ext\" target=\"_parent\">".
-				"$dir_name</a> - $base_name";
+				"$esc_dir_name</a> - $esc_base_name";
 		}
 		else
 		{
 			$view = "<a href=\"$base_dir"."index.$html_ext\">".
 				"$overview_title</a> - ".
 				"<a href=\"index.$html_ext\">".
-				"$dir_name</a> - $base_name";
+				"$esc_dir_name</a> - $esc_base_name";
 		}
 
 		# Add function suffix
 		if ($func_coverage) {
-			if ($type == 2) {
+			$view .= "<span style=\"font-size: 80%;\">";
+			if ($type == $HDR_SOURCE) {
 				$view .= " (source / <a href=\"$base_name.func.$html_ext\">functions</a>)";
-			} elsif ($type == 4) {
+			} elsif ($type == $HDR_FUNC) {
 				$view .= " (<a href=\"$base_name.gcov.$html_ext\">source</a> / functions)";
 			}
+			$view .= "</span>";
 		}
 	}
-	elsif ($type == 3)
+	elsif ($type == $HDR_TESTDESC)
 	{
 		# Test description header
 		$base_dir = "";
@@ -3732,84 +4292,126 @@
 	$test = escape_html($test_title);
 
 	# Append link to test description page if available
-	if (%test_description && ($type != 3))
+	if (%test_description && ($type != $HDR_TESTDESC))
 	{
-		if ($frames && ($type == 2 || $type == 4))
+		if ($frames && ($type == $HDR_SOURCE || $type == $HDR_FUNC))
 		{
 			# Need to break frameset when clicking this link
-			$test .= " ( <a href=\"$base_dir".
+			$test .= " ( <span style=\"font-size:80%;\">".
+				 "<a href=\"$base_dir".
 				 "descriptions.$html_ext\" target=\"_parent\">".
-				 "view descriptions</a> )";
+				 "view descriptions</a></span> )";
 		}
 		else
 		{
-			$test .= " ( <a href=\"$base_dir".
+			$test .= " ( <span style=\"font-size:80%;\">".
+				 "<a href=\"$base_dir".
 				 "descriptions.$html_ext\">".
-				 "view descriptions</a> )";
+				 "view descriptions</a></span> )";
 		}
 	}
 
 	# Write header
 	write_header_prolog(*HTML_HANDLE, $base_dir);
-	write_header_line(*HTML_HANDLE, 0, "Current view:", $view,
-			  "Found", "Hit", "Coverage");
-	write_header_line(*HTML_HANDLE, 1, "Test:", $test, "Lines:",
-			  $lines_found, $lines_hit,
-			  $rate_name[classify_rate($lines_found, $lines_hit,
-						   $med_limit, $hi_limit)],
-			  format_rate($lines_found, $lines_hit));
-	if ($func_coverage) {
-		write_header_line(*HTML_HANDLE, 1, "Date:", $date, "Functions:",
-				  $fn_found, $fn_hit,
-				  $rate_name[classify_rate($fn_found,
-							   $fn_hit,
-							   $fn_med_limit,
-							   $fn_hi_limit)],
-				  format_rate($fn_found, $fn_hit));
-	} else {
-		write_header_line(*HTML_HANDLE, 4, "Date:", $date);
-	}
-	if ($legend) {
-		if ($type == 0 || $type == 1) {
-			my $line_code = get_legend_code("Line coverage:",
-						$med_limit, $hi_limit);
-			my $func_code = "";
 
-			if ($func_coverage) {
-				$func_code = get_legend_code(
-						"Function coverage:",
-						$fn_med_limit,
-						$fn_hi_limit);
-			}
-			write_header_line(*HTML_HANDLE, 2, "Colors:",
-				$line_code, $func_code);
-		} elsif ($type == 2 || $type == 4) {
-			write_header_line(*HTML_HANDLE, 3, "Colors:",
-					  "not hit", "hit");
+	# Left row
+	push(@row_left, [[ "10%", "headerItem", "Current view:" ],
+			 [ "35%", "headerValue", $view ]]);
+	push(@row_left, [[undef, "headerItem", "Test:"],
+			 [undef, "headerValue", $test]]);
+	push(@row_left, [[undef, "headerItem", "Date:"],
+			 [undef, "headerValue", $date]]);
+
+	# Right row
+	if ($legend && ($type == $HDR_SOURCE || $type == $HDR_FUNC)) {
+		my $text = <<END_OF_HTML;
+            Lines:
+            <span class="coverLegendCov">hit</span>
+            <span class="coverLegendNoCov">not hit</span>
+END_OF_HTML
+		if ($br_coverage) {
+			$text .= <<END_OF_HTML;
+            | Branches:
+            <span class="coverLegendCov">+</span> taken
+            <span class="coverLegendNoCov">-</span> not taken
+            <span class="coverLegendNoCov">#</span> not executed
+END_OF_HTML
 		}
+		push(@row_left, [[undef, "headerItem", "Legend:"],
+				 [undef, "headerValueLeg", $text]]);
+	} elsif ($legend && ($type != $HDR_TESTDESC)) {
+		my $text = <<END_OF_HTML;
+	    Rating:
+            <span class="coverLegendCovLo" title="Coverage rates below $med_limit % are classified as low">low: &lt; $med_limit %</span>
+            <span class="coverLegendCovMed" title="Coverage rates between $med_limit % and $hi_limit % are classified as medium">medium: &gt;= $med_limit %</span>
+            <span class="coverLegendCovHi" title="Coverage rates of $hi_limit % and more are classified as high">high: &gt;= $hi_limit %</span>
+END_OF_HTML
+		push(@row_left, [[undef, "headerItem", "Legend:"],
+				 [undef, "headerValueLeg", $text]]);
 	}
+	if ($type == $HDR_TESTDESC) {
+		push(@row_right, [[ "55%" ]]);
+	} else {
+		push(@row_right, [["15%", undef, undef ],
+				  ["10%", "headerCovTableHead", "Hit" ],
+				  ["10%", "headerCovTableHead", "Total" ],
+				  ["15%", "headerCovTableHead", "Coverage"]]);
+	}
+	# Line coverage
+	$style = $rate_name[classify_rate($lines_found, $lines_hit,
+					  $med_limit, $hi_limit)];
+	$rate = rate($lines_hit, $lines_found, " %");
+	push(@row_right, [[undef, "headerItem", "Lines:"],
+			  [undef, "headerCovTableEntry", $lines_hit],
+			  [undef, "headerCovTableEntry", $lines_found],
+			  [undef, "headerCovTableEntry$style", $rate]])
+			if ($type != $HDR_TESTDESC);
+	# Function coverage
+	if ($func_coverage) {
+		$style = $rate_name[classify_rate($fn_found, $fn_hit,
+						  $fn_med_limit, $fn_hi_limit)];
+		$rate = rate($fn_hit, $fn_found, " %");
+		push(@row_right, [[undef, "headerItem", "Functions:"],
+				  [undef, "headerCovTableEntry", $fn_hit],
+				  [undef, "headerCovTableEntry", $fn_found],
+				  [undef, "headerCovTableEntry$style", $rate]])
+			if ($type != $HDR_TESTDESC);
+	}
+	# Branch coverage
+	if ($br_coverage) {
+		$style = $rate_name[classify_rate($br_found, $br_hit,
+						  $br_med_limit, $br_hi_limit)];
+		$rate = rate($br_hit, $br_found, " %");
+		push(@row_right, [[undef, "headerItem", "Branches:"],
+				  [undef, "headerCovTableEntry", $br_hit],
+				  [undef, "headerCovTableEntry", $br_found],
+				  [undef, "headerCovTableEntry$style", $rate]])
+			if ($type != $HDR_TESTDESC);
+	}
+
+	# Print rows
+	$num_rows = max(scalar(@row_left), scalar(@row_right));
+	for ($i = 0; $i < $num_rows; $i++) {
+		my $left = $row_left[$i];
+		my $right = $row_right[$i];
+
+		if (!defined($left)) {
+			$left = [[undef, undef, undef], [undef, undef, undef]];
+		}
+		if (!defined($right)) {
+			$right = [];
+		}
+		write_header_line(*HTML_HANDLE, @{$left},
+				  [ $i == 0 ? "5%" : undef, undef, undef],
+				  @{$right});
+	}
+
+	# Fourth line
 	write_header_epilog(*HTML_HANDLE, $base_dir);
 }
 
 
 #
-# split_filename(filename)
-#
-# Return (path, filename, extension) for a given FILENAME.
-#
-
-sub split_filename($)
-{
-	if (!$_[0]) { return(); }
-	my @path_components = split('/', $_[0]);
-	my @file_components = split('\.', pop(@path_components));
-	my $extension = pop(@file_components);
-
-	return (join("/",@path_components), join(".",@file_components),
-		$extension);
-}
-
-#
 # get_sorted_keys(hash_ref, sort_type)
 #
 
@@ -3817,15 +4419,18 @@
 {
 	my ($hash, $type) = @_;
 
-	if ($type == 0) {
+	if ($type == $SORT_FILE) {
 		# Sort by name
 		return sort(keys(%{$hash}));
-	} elsif ($type == 1) {
+	} elsif ($type == $SORT_LINE) {
 		# Sort by line coverage
-		return sort({$hash->{$a}[5] <=> $hash->{$b}[5]} keys(%{$hash}));
-	} elsif ($type == 2) {
+		return sort({$hash->{$a}[7] <=> $hash->{$b}[7]} keys(%{$hash}));
+	} elsif ($type == $SORT_FUNC) {
 		# Sort by function coverage;
-		return sort({$hash->{$a}[6] <=> $hash->{$b}[6]}	keys(%{$hash}));
+		return sort({$hash->{$a}[8] <=> $hash->{$b}[8]}	keys(%{$hash}));
+	} elsif ($type == $SORT_BRANCH) {
+		# Sort by br coverage;
+		return sort({$hash->{$a}[9] <=> $hash->{$b}[9]}	keys(%{$hash}));
 	}
 }
 
@@ -3858,7 +4463,7 @@
 	my $link;
 
 	if ($sort_button) {
-		if ($type == 1) {
+		if ($type == $HEAD_NO_DETAIL) {
 			$link = "index.$html_ext";
 		} else {
 			$link = "index-detail.$html_ext";
@@ -3875,12 +4480,12 @@
 	my $result = $text;
 	my $sort_link;
 
-	if ($type == 1) {
+	if ($type == $HEAD_NO_DETAIL) {
 		# Just text
 		if ($sort_button) {
 			$sort_link = "index-sort-l.$html_ext";
 		}
-	} elsif ($type == 2) {
+	} elsif ($type == $HEAD_DETAIL_HIDDEN) {
 		# Text + link to detail view
 		$result .= ' ( <a class="detail" href="index-detail'.
 			   $fileview_sortname[$sort_type].'.'.$html_ext.
@@ -3910,7 +4515,7 @@
 	my $link;
 
 	if ($sort_button) {
-		if ($type == 1) {
+		if ($type == $HEAD_NO_DETAIL) {
 			$link = "index-sort-f.$html_ext";
 		} else {
 			$link = "index-detail-sort-f.$html_ext";
@@ -3920,9 +4525,26 @@
 	return $result;
 }
 
+sub get_br_code($$$$)
+{
+	my ($type, $text, $sort_button, $base) = @_;
+	my $result = $text;
+	my $link;
+
+	if ($sort_button) {
+		if ($type == $HEAD_NO_DETAIL) {
+			$link = "index-sort-b.$html_ext";
+		} else {
+			$link = "index-detail-sort-b.$html_ext";
+		}
+	}
+	$result .= get_sort_code($link, "Sort by branch coverage", $base);
+	return $result;
+}
+
 #
 # write_file_table(filehandle, base_dir, overview, testhash, testfnchash,
-#                  fileview, sort_type)
+#                  testbrhash, fileview, sort_type)
 #
 # Write a complete file table. OVERVIEW is a reference to a hash containing
 # the following mapping:
@@ -3940,70 +4562,107 @@
 # otherwise.
 #
 
-sub write_file_table(*$$$$$$)
+sub write_file_table(*$$$$$$$)
 {
 	local *HTML_HANDLE = $_[0];
 	my $base_dir = $_[1];
 	my $overview = $_[2];
 	my $testhash = $_[3];
 	my $testfnchash = $_[4];
-	my $fileview = $_[5];
-	my $sort_type = $_[6];
+	my $testbrhash = $_[5];
+	my $fileview = $_[6];
+	my $sort_type = $_[7];
 	my $filename;
 	my $bar_graph;
 	my $hit;
 	my $found;
 	my $fn_found;
 	my $fn_hit;
+	my $br_found;
+	my $br_hit;
 	my $page_link;
 	my $testname;
 	my $testdata;
 	my $testfncdata;
-	my $testcount;
-	my $testfnccount;
+	my $testbrdata;
 	my %affecting_tests;
 	my $line_code = "";
 	my $func_code;
+	my $br_code;
 	my $file_code;
+	my @head_columns;
 
 	# Determine HTML code for column headings
 	if (($base_dir ne "") && $show_details)
 	{
 		my $detailed = keys(%{$testhash});
 
-		$file_code = get_file_code($detailed ? 2 : 1,
+		$file_code = get_file_code($detailed ? $HEAD_DETAIL_HIDDEN :
+					$HEAD_NO_DETAIL,
 					$fileview ? "Filename" : "Directory",
-					$sort && $sort_type != 0, $base_dir);
-		$line_code = get_line_code($detailed ? 3 : 2, $sort_type,
+					$sort && $sort_type != $SORT_FILE,
+					$base_dir);
+		$line_code = get_line_code($detailed ? $HEAD_DETAIL_SHOWN :
+					$HEAD_DETAIL_HIDDEN,
+					$sort_type,
 					"Line Coverage",
-					$sort && $sort_type != 1, $base_dir);
-		$func_code = get_func_code($detailed ? 2 : 1, "Functions",
-					$sort && $sort_type != 2, $base_dir);
+					$sort && $sort_type != $SORT_LINE,
+					$base_dir);
+		$func_code = get_func_code($detailed ? $HEAD_DETAIL_HIDDEN :
+					$HEAD_NO_DETAIL,
+					"Functions",
+					$sort && $sort_type != $SORT_FUNC,
+					$base_dir);
+		$br_code = get_br_code($detailed ? $HEAD_DETAIL_HIDDEN :
+					$HEAD_NO_DETAIL,
+					"Branches",
+					$sort && $sort_type != $SORT_BRANCH,
+					$base_dir);
 	} else {
-		$file_code = get_file_code(1,
+		$file_code = get_file_code($HEAD_NO_DETAIL,
 					$fileview ? "Filename" : "Directory",
-					$sort && $sort_type != 0, $base_dir);
-		$line_code = get_line_code(1, $sort_type, "Line Coverage",
-					$sort && $sort_type != 1, $base_dir);
-		$func_code = get_func_code(1, "Functions",
-					$sort && $sort_type != 2, $base_dir);
+					$sort && $sort_type != $SORT_FILE,
+					$base_dir);
+		$line_code = get_line_code($HEAD_NO_DETAIL, $sort_type, "Line Coverage",
+					$sort && $sort_type != $SORT_LINE,
+					$base_dir);
+		$func_code = get_func_code($HEAD_NO_DETAIL, "Functions",
+					$sort && $sort_type != $SORT_FUNC,
+					$base_dir);
+		$br_code = get_br_code($HEAD_NO_DETAIL, "Branches",
+					$sort && $sort_type != $SORT_BRANCH,
+					$base_dir);
 	}
+	push(@head_columns, [ $line_code, 3 ]);
+	push(@head_columns, [ $func_code, 2]) if ($func_coverage);
+	push(@head_columns, [ $br_code, 2]) if ($br_coverage);
 
-	write_file_table_prolog(*HTML_HANDLE, $file_code, $line_code,
-				$func_code);
+	write_file_table_prolog(*HTML_HANDLE, $file_code, @head_columns);
 
 	foreach $filename (get_sorted_keys($overview, $sort_type))
 	{
-		($found, $hit, $fn_found, $fn_hit, $page_link)
-			= @{$overview->{$filename}};
-		$bar_graph = get_bar_graph_code($base_dir, $found, $hit);
+		my @columns;
+		($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit,
+		 $page_link) = @{$overview->{$filename}};
+
+		# Line coverage
+		push(@columns, [$found, $hit, $med_limit, $hi_limit, 1]);
+		# Function coverage
+		if ($func_coverage) {
+			push(@columns, [$fn_found, $fn_hit, $fn_med_limit,
+					$fn_hi_limit, 0]);
+		}
+		# Branch coverage
+		if ($br_coverage) {
+			push(@columns, [$br_found, $br_hit, $br_med_limit,
+					$br_hi_limit, 0]);
+		}
+		write_file_table_entry(*HTML_HANDLE, $base_dir, $filename,
+				       $page_link, @columns);
 
 		$testdata = $testhash->{$filename};
 		$testfncdata = $testfnchash->{$filename};
-
-		write_file_table_entry(*HTML_HANDLE, $filename, $bar_graph,
-				       $found, $hit, $fn_found, $fn_hit,
-				       $page_link);
+		$testbrdata = $testbrhash->{$filename};
 
 		# Check whether we should write test specific coverage
 		# as well
@@ -4011,18 +4670,15 @@
 
 		# Filter out those tests that actually affect this file
 		%affecting_tests = %{ get_affecting_tests($testdata,
-					$testfncdata) };
+					$testfncdata, $testbrdata) };
 
 		# Does any of the tests affect this file at all?
 		if (!%affecting_tests) { next; }
 
-		# Write test details for this entry
-		write_file_table_detail_heading(*HTML_HANDLE, "Test name",
-						"Lines hit", "Functions hit");
-
 		foreach $testname (keys(%affecting_tests))
 		{
-			($found, $hit, $fn_found, $fn_hit) =
+			my @results;
+			($found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
 				split(",", $affecting_tests{$testname});
 
 			# Insert link to description of available
@@ -4033,8 +4689,11 @@
 					    "$testname</a>";
 			}
 
+			push(@results, [$found, $hit]);
+			push(@results, [$fn_found, $fn_hit]) if ($func_coverage);
+			push(@results, [$br_found, $br_hit]) if ($br_coverage);
 			write_file_table_detail_entry(*HTML_HANDLE, $testname,
-				$found, $hit, $fn_found, $fn_hit);
+				@results);
 		}
 	}
 
@@ -4095,39 +4754,224 @@
 
 
 #
-# get_affecting_tests(testdata, testfncdata)
+# br_taken_to_num(taken)
+#
+# Convert a branch taken value .info format to number format.
+#
+
+sub br_taken_to_num($)
+{
+	my ($taken) = @_;
+
+	return 0 if ($taken eq '-');
+	return $taken + 1;
+}
+
+
+#
+# br_num_to_taken(taken)
+#
+# Convert a branch taken value in number format to .info format.
+#
+
+sub br_num_to_taken($)
+{
+	my ($taken) = @_;
+
+	return '-' if ($taken == 0);
+	return $taken - 1;
+}
+
+
+#
+# br_taken_add(taken1, taken2)
+#
+# Return the result of taken1 + taken2 for 'branch taken' values.
+#
+
+sub br_taken_add($$)
+{
+	my ($t1, $t2) = @_;
+
+	return $t1 if (!defined($t2));
+	return $t2 if (!defined($t1));
+	return $t1 if ($t2 eq '-');
+	return $t2 if ($t1 eq '-');
+	return $t1 + $t2;
+}
+
+
+#
+# br_taken_sub(taken1, taken2)
+#
+# Return the result of taken1 - taken2 for 'branch taken' values. Return 0
+# if the result would become negative.
+#
+
+sub br_taken_sub($$)
+{
+	my ($t1, $t2) = @_;
+
+	return $t1 if (!defined($t2));
+	return undef if (!defined($t1));
+	return $t1 if ($t1 eq '-');
+	return $t1 if ($t2 eq '-');
+	return 0 if $t2 > $t1;
+	return $t1 - $t2;
+}
+
+
+#
+# br_ivec_len(vector)
+#
+# Return the number of entries in the branch coverage vector.
+#
+
+sub br_ivec_len($)
+{
+	my ($vec) = @_;
+
+	return 0 if (!defined($vec));
+	return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
+}
+
+
+#
+# br_ivec_get(vector, number)
+#
+# Return an entry from the branch coverage vector.
+#
+
+sub br_ivec_get($$)
+{
+	my ($vec, $num) = @_;
+	my $block;
+	my $branch;
+	my $taken;
+	my $offset = $num * $BR_VEC_ENTRIES;
+
+	# Retrieve data from vector
+	$block	= vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+	$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
+	$taken	= vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
+
+	# Decode taken value from an integer
+	$taken = br_num_to_taken($taken);
+
+	return ($block, $branch, $taken);
+}
+
+
+#
+# br_ivec_push(vector, block, branch, taken)
+#
+# Add an entry to the branch coverage vector. If an entry with the same
+# branch ID already exists, add the corresponding taken values.
+#
+
+sub br_ivec_push($$$$)
+{
+	my ($vec, $block, $branch, $taken) = @_;
+	my $offset;
+	my $num = br_ivec_len($vec);
+	my $i;
+
+	$vec = "" if (!defined($vec));
+
+	# Check if branch already exists in vector
+	for ($i = 0; $i < $num; $i++) {
+		my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
+
+		next if ($v_block != $block || $v_branch != $branch);
+
+		# Add taken counts
+		$taken = br_taken_add($taken, $v_taken);
+		last;
+	}
+
+	$offset = $i * $BR_VEC_ENTRIES;
+	$taken = br_taken_to_num($taken);
+
+	# Add to vector
+	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
+	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
+	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
+
+	return $vec;
+}
+
+
+#
+# get_br_found_and_hit(sumbrcount)
+#
+# Return (br_found, br_hit) for sumbrcount
+#
+
+sub get_br_found_and_hit($)
+{
+	my ($sumbrcount) = @_;
+	my $line;
+	my $br_found = 0;
+	my $br_hit = 0;
+
+	foreach $line (keys(%{$sumbrcount})) {
+		my $brdata = $sumbrcount->{$line};
+		my $i;
+		my $num = br_ivec_len($brdata);
+
+		for ($i = 0; $i < $num; $i++) {
+			my $taken;
+
+			(undef, undef, $taken) = br_ivec_get($brdata, $i);
+
+			$br_found++;
+			$br_hit++ if ($taken ne "-" && $taken > 0);
+		}
+	}
+
+	return ($br_found, $br_hit);
+}
+
+
+#
+# get_affecting_tests(testdata, testfncdata, testbrdata)
 #
 # HASHREF contains a mapping filename -> (linenumber -> exec count). Return
 # a hash containing mapping filename -> "lines found, lines hit" for each
 # filename which has a nonzero hit count.
 #
 
-sub get_affecting_tests($$)
+sub get_affecting_tests($$$)
 {
-	my $testdata = $_[0];
-	my $testfncdata = $_[1];
+	my ($testdata, $testfncdata, $testbrdata) = @_;
 	my $testname;
 	my $testcount;
 	my $testfnccount;
+	my $testbrcount;
 	my %result;
 	my $found;
 	my $hit;
 	my $fn_found;
 	my $fn_hit;
+	my $br_found;
+	my $br_hit;
 
 	foreach $testname (keys(%{$testdata}))
 	{
 		# Get (line number -> count) hash for this test case
 		$testcount = $testdata->{$testname};
 		$testfnccount = $testfncdata->{$testname};
+		$testbrcount = $testbrdata->{$testname};
 
 		# Calculate sum
 		($found, $hit) = get_found_and_hit($testcount);
 		($fn_found, $fn_hit) = get_func_found_and_hit($testfnccount);
+		($br_found, $br_hit) = get_br_found_and_hit($testbrcount);
 
 		if ($hit>0)
 		{
-			$result{$testname} = "$found,$hit,$fn_found,$fn_hit";
+			$result{$testname} = "$found,$hit,$fn_found,$fn_hit,".
+					     "$br_found,$br_hit";
 		}
 	}
 
@@ -4149,7 +4993,7 @@
 
 #
 # write_source(filehandle, source_filename, count_data, checksum_data,
-#              converted_data, func_data)
+#              converted_data, func_data, sumbrcount)
 #
 # Write an HTML view of a source code file. Returns a list containing
 # data as needed by gen_png().
@@ -4157,7 +5001,7 @@
 # Die on error.
 #
 
-sub write_source($$$$$$)
+sub write_source($$$$$$$)
 {
 	local *HTML_HANDLE = $_[0];
 	local *SOURCE_HANDLE;
@@ -4168,24 +5012,51 @@
 	my $checkdata = $_[3];
 	my $converted = $_[4];
 	my $funcdata  = $_[5];
+	my $sumbrcount = $_[6];
 	my $datafunc = get_hash_reverse($funcdata);
 	my $add_anchor;
+	my @file;
 
 	if ($_[2])
 	{
 		%count_data = %{$_[2]};
 	}
 
-	open(SOURCE_HANDLE, "<".$source_filename)
-          # or die("ERROR: cannot open $source_filename for reading!\n");
-          or open(SOURCE_HANDLE, "</dev/null");
+	if (!open(SOURCE_HANDLE, "<", $source_filename)) {
+		my @lines;
+		my $last_line = 0;
+
+		if (!$ignore[$ERROR_SOURCE]) {
+			die("ERROR: cannot read $source_filename\n");
+		}
+
+		# Continue without source file
+		warn("WARNING: cannot read $source_filename!\n");
+
+		@lines = sort( { $a <=> $b }  keys(%count_data));
+		if (@lines) {
+			$last_line = $lines[scalar(@lines) - 1];
+		}
+		return ( ":" ) if ($last_line < 1);
+
+		# Simulate gcov behavior
+		for ($line_number = 1; $line_number <= $last_line;
+		     $line_number++) {
+			push(@file, "/* EOF */");
+		}
+	} else {
+		@file = <SOURCE_HANDLE>;
+	}
 	
 	write_source_prolog(*HTML_HANDLE);
-
-	for ($line_number = 1; <SOURCE_HANDLE> ; $line_number++)
-	{
+	$line_number = 0;
+	foreach (@file) {
+		$line_number++;
 		chomp($_);
 
+		# Also remove CR from line-end
+		s/\015$//;
+
 		# Source code matches coverage data?
 		if (defined($checkdata->{$line_number}) &&
 		    ($checkdata->{$line_number} ne md5_base64($_)))
@@ -4212,7 +5083,7 @@
 		      write_source_line(HTML_HANDLE, $line_number,
 					$_, $count_data{$line_number},
 					$converted->{$line_number},
-					$add_anchor));
+					$sumbrcount->{$line_number}, $add_anchor));
 	}
 
 	close(SOURCE_HANDLE);
@@ -4271,7 +5142,8 @@
 
 #
 # write_function_table(filehandle, source_file, sumcount, funcdata,
-#		       sumfnccount, testfncdata)
+#		       sumfnccount, testfncdata, sumbrcount, testbrdata,
+#		       base_name, base_dir, sort_type)
 #
 # Write an HTML table listing all functions in a source file, including
 # also function call counts and line coverages inside of each function.
@@ -4279,7 +5151,7 @@
 # Die on error.
 #
 
-sub write_function_table(*$$$$$$$$)
+sub write_function_table(*$$$$$$$$$$)
 {
 	local *HTML_HANDLE = $_[0];
 	my $source = $_[1];
@@ -4287,9 +5159,11 @@
 	my $funcdata = $_[3];
 	my $sumfncdata = $_[4];
 	my $testfncdata = $_[5];
-	my $name = $_[6];
-	my $base = $_[7];
-	my $type = $_[8];
+	my $sumbrcount = $_[6];
+	my $testbrdata = $_[7];
+	my $name = $_[8];
+	my $base = $_[9];
+	my $type = $_[10];
 	my $func;
 	my $func_code;
 	my $count_code;
@@ -4310,11 +5184,23 @@
 	
 	# Get a sorted table
 	foreach $func (funcview_get_sorted($funcdata, $sumfncdata, $type)) {
+		if (!defined($funcdata->{$func}))
+		{
+			next;
+		}
+
 		my $startline = $funcdata->{$func} - $func_offset;
-		my $name = escape_html($func);
+		my $name = $func;
 		my $count = $sumfncdata->{$name};
 		my $countstyle;
 
+		# Demangle C++ function names if requested
+		if ($demangle_cpp) {
+			$name = `c++filt "$name"`;
+			chomp($name);
+		}
+		# Escape any remaining special characters
+		$name = escape_html($name);
 		if ($startline < 1) {
 			$startline = 1;
 		}
@@ -4403,14 +5289,16 @@
 
 sub subtract_fnccounts($$)
 {
-	my %data = %{$_[0]};
-	my %base = %{$_[1]};
+	my %data;
+	my %base;
 	my $func;
 	my $data_count;
 	my $base_count;
 	my $fn_hit = 0;
 	my $fn_found = 0;
 
+	%data = %{$_[0]} if (defined($_[0]));
+	%base = %{$_[1]} if (defined($_[1]));
 	foreach $func (keys(%data)) {
 		$fn_found++;
 		$data_count = $data{$func};
@@ -4453,18 +5341,24 @@
 	my $data_funcdata;
 	my $data_checkdata;
 	my $data_testfncdata;
+	my $data_testbrdata;
 	my $data_count;
 	my $data_testfnccount;
+	my $data_testbrcount;
 	my $base;
 	my $base_checkdata;
 	my $base_sumfnccount;
+	my $base_sumbrcount;
 	my $base_count;
 	my $sumcount;
 	my $sumfnccount;
+	my $sumbrcount;
 	my $found;
 	my $hit;
 	my $fn_found;
 	my $fn_hit;
+	my $br_found;
+	my $br_hit;
 
 	foreach $filename (keys(%data_hash))
 	{
@@ -4480,9 +5374,11 @@
 
 		# Get set entries for data and baseline
 		($data_testdata, undef, $data_funcdata, $data_checkdata,
-		 $data_testfncdata) = get_info_entry($data);
+		 $data_testfncdata, undef, $data_testbrdata) =
+			get_info_entry($data);
 		(undef, $base_count, undef, $base_checkdata, undef,
-		 $base_sumfnccount) = get_info_entry($base);
+		 $base_sumfnccount, undef, $base_sumbrcount) =
+			get_info_entry($base);
 
 		# Check for compatible checksums
 		merge_checksums($data_checkdata, $base_checkdata, $filename);
@@ -4490,6 +5386,7 @@
 		# sumcount has to be calculated anew
 		$sumcount = {};
 		$sumfnccount = {};
+		$sumbrcount = {};
 
 		# For each test case, subtract test specific counts
 		foreach $testname (keys(%{$data_testdata}))
@@ -4497,12 +5394,17 @@
 			# Get counts of both data and baseline
 			$data_count = $data_testdata->{$testname};
 			$data_testfnccount = $data_testfncdata->{$testname};
+			$data_testbrcount = $data_testbrdata->{$testname};
 
 			($data_count, undef, $hit) =
 				subtract_counts($data_count, $base_count);
 			($data_testfnccount) =
 				subtract_fnccounts($data_testfnccount,
 						   $base_sumfnccount);
+			($data_testbrcount) =
+				combine_brcount($data_testbrcount,
+						 $base_sumbrcount, $BR_SUB);
+
 
 			# Check whether this test case did hit any line at all
 			if ($hit > 0)
@@ -4511,6 +5413,8 @@
 				$data_testdata->{$testname} = $data_count;
 				$data_testfncdata->{$testname} =
 					$data_testfnccount;
+				$data_testbrdata->{$testname} =
+					$data_testbrcount;
 			}
 			else
 			{
@@ -4518,19 +5422,24 @@
 				# file
 				delete($data_testdata->{$testname});
 				delete($data_testfncdata->{$testname});
+				delete($data_testbrdata->{$testname});
 			}
 
 			# Add counts to sum of counts
 			($sumcount, $found, $hit) =
 				add_counts($sumcount, $data_count);
 			($sumfnccount, $fn_found, $fn_hit) =
-				add_fnccounts($sumfnccount, $data_testfnccount);
+				add_fnccount($sumfnccount, $data_testfnccount);
+			($sumbrcount, $br_found, $br_hit) =
+				combine_brcount($sumbrcount, $data_testbrcount,
+						$BR_ADD);
 		}
 
 		# Write back resulting entry
 		set_info_entry($data, $data_testdata, $sumcount, $data_funcdata,
 			       $data_checkdata, $data_testfncdata, $sumfnccount,
-			       $found, $hit, $fn_found, $fn_hit);
+			       $data_testbrdata, $sumbrcount, $found, $hit,
+			       $fn_found, $fn_hit, $br_found, $br_hit);
 
 		$data_hash{$filename} = $data;
 	}
@@ -4627,12 +5536,12 @@
 	local *OLD_STDOUT;
 
 	# Save old stdout and stderr handles
-	($mode & 1) && open(OLD_STDOUT, ">>&STDOUT");
-	($mode & 2) && open(OLD_STDERR, ">>&STDERR");
+	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
+	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
 
 	# Redirect to /dev/null
-	($mode & 1) && open(STDOUT, ">/dev/null");
-	($mode & 2) && open(STDERR, ">/dev/null");
+	($mode & 1) && open(STDOUT, ">", "/dev/null");
+	($mode & 2) && open(STDERR, ">", "/dev/null");
 
 	system(@_);
 	$result = $?;
@@ -4642,8 +5551,8 @@
 	($mode & 2) && close(STDERR);
 
 	# Restore old handles
-	($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
-	($mode & 2) && open(STDERR, ">>&OLD_STDERR");
+	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
+	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
 
 	return $result;
 }
@@ -4664,7 +5573,7 @@
 	my $value;
 	local *HANDLE;
 
-	if (!open(HANDLE, "<$filename"))
+	if (!open(HANDLE, "<", $filename))
 	{
 		warn("WARNING: cannot read configuration file $filename\n");
 		return undef;
@@ -4703,8 +5612,8 @@
 #   key_string => var_ref
 #
 # where KEY_STRING is a keyword and VAR_REF is a reference to an associated
-# variable. If the global configuration hash CONFIG contains a value for
-# keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
+# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
+# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
 #
 
 sub apply_config($)
@@ -4713,8 +5622,9 @@
 
 	foreach (keys(%{$ref}))
 	{
-		if (defined($config->{$_}))
-		{
+		if (defined($opt_rc{$_})) {
+			${$ref->{$_}} = $opt_rc{$_};
+		} elsif (defined($config->{$_})) {
 			${$ref->{$_}} = $config->{$_};
 		}
 	}
@@ -4737,7 +5647,7 @@
 	{
 		local *HANDLE;
 
-		open(HANDLE, "<".$filename)
+		open(HANDLE, "<", $filename)
 			or die("ERROR: cannot open html prolog $filename!\n");
 		while (<HANDLE>)
 		{
@@ -4753,7 +5663,7 @@
 <html lang="en">
 
 <head>
-  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <meta http-equiv="Content-Type" content="text/html; charset=$charset">
   <title>\@pagetitle\@</title>
   <link rel="stylesheet" type="text/css" href="\@basedir\@gcov.css">
 </head>
@@ -4783,7 +5693,7 @@
 	{
 		local *HANDLE;
 
-		open(HANDLE, "<".$filename)
+		open(HANDLE, "<", $filename)
 			or die("ERROR: cannot open html epilog $filename!\n");
 		while (<HANDLE>)
 		{
@@ -4818,3 +5728,72 @@
 
 	die("$tool_name: $msg");
 }
+
+#
+# parse_ignore_errors(@ignore_errors)
+#
+# Parse user input about which errors to ignore.
+#
+
+sub parse_ignore_errors(@)
+{
+	my (@ignore_errors) = @_;
+	my @items;
+	my $item;
+
+	return if (!@ignore_errors);
+
+	foreach $item (@ignore_errors) {
+		$item =~ s/\s//g;
+		if ($item =~ /,/) {
+			# Split and add comma-separated parameters
+			push(@items, split(/,/, $item));
+		} else {
+			# Add single parameter
+			push(@items, $item);
+		}
+	}
+	foreach $item (@items) {
+		my $item_id = $ERROR_ID{lc($item)};
+
+		if (!defined($item_id)) {
+			die("ERROR: unknown argument for --ignore-errors: ".
+			    "$item\n");
+		}
+		$ignore[$item_id] = 1;
+	}
+}
+
+#
+# rate(hit, found[, suffix, precision, width])
+#
+# Return the coverage rate [0..100] for HIT and FOUND values. 0 is only
+# returned when HIT is 0. 100 is only returned when HIT equals FOUND.
+# PRECISION specifies the precision of the result. SUFFIX defines a
+# string that is appended to the result if FOUND is non-zero. Spaces
+# are added to the start of the resulting string until it is at least WIDTH
+# characters wide.
+#
+
+sub rate($$;$$$)
+{
+        my ($hit, $found, $suffix, $precision, $width) = @_;
+        my $rate; 
+
+	# Assign defaults if necessary
+        $precision	= 1	if (!defined($precision));
+	$suffix		= ""	if (!defined($suffix));
+	$width		= 0	if (!defined($width));
+        
+        return sprintf("%*s", $width, "-") if (!defined($found) || $found == 0);
+        $rate = sprintf("%.*f", $precision, $hit * 100 / $found);
+
+	# Adjust rates if necessary
+        if ($rate == 0 && $hit > 0) {
+		$rate = sprintf("%.*f", $precision, 1 / 10 ** $precision);
+        } elsif ($rate == 100 && $hit != $found) {
+		$rate = sprintf("%.*f", $precision, 100 - 1 / 10 ** $precision);
+	}
+
+	return sprintf("%*s", $width, $rate.$suffix);
+}
diff --git a/third_party/lcov/bin/geninfo b/third_party/lcov/bin/geninfo
index 055641b..9325f9d 100755
--- a/third_party/lcov/bin/geninfo
+++ b/third_party/lcov/bin/geninfo
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 #
-#   Copyright (c) International Business Machines  Corp., 2002,2007
+#   Copyright (c) International Business Machines  Corp., 2002,2012
 #
 #   This program is free software;  you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
@@ -51,16 +51,22 @@
 
 use strict;
 use File::Basename; 
+use File::Spec::Functions qw /abs2rel catdir file_name_is_absolute splitdir
+			      splitpath catpath/;
 use Getopt::Long;
 use Digest::MD5 qw(md5_base64);
-
+if( $^O eq "msys" )
+{
+	require File::Spec::Win32;
+}
 
 # Constants
-our $lcov_version	= "LCOV version 1.7";
+our $lcov_version	= 'LCOV version 1.10';
 our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
 our $gcov_tool		= "gcov";
 our $tool_name		= basename($0);
 
+our $GCOV_VERSION_4_7_0	= 0x40700;
 our $GCOV_VERSION_3_4_0	= 0x30400;
 our $GCOV_VERSION_3_3_0	= 0x30300;
 our $GCNO_FUNCTION_TAG	= 0x01000000;
@@ -68,41 +74,140 @@
 our $GCNO_FILE_MAGIC	= 0x67636e6f;
 our $BBG_FILE_MAGIC	= 0x67626267;
 
-our $COMPAT_HAMMER	= "hammer";
-
+# Error classes which users may specify to ignore during processing
 our $ERROR_GCOV		= 0;
 our $ERROR_SOURCE	= 1;
+our $ERROR_GRAPH	= 2;
+our %ERROR_ID = (
+	"gcov" => $ERROR_GCOV,
+	"source" => $ERROR_SOURCE,
+	"graph" => $ERROR_GRAPH,
+);
+
+our $EXCL_START = "LCOV_EXCL_START";
+our $EXCL_STOP = "LCOV_EXCL_STOP";
+our $EXCL_LINE = "LCOV_EXCL_LINE";
+
+# Compatibility mode values
+our $COMPAT_VALUE_OFF	= 0;
+our $COMPAT_VALUE_ON	= 1;
+our $COMPAT_VALUE_AUTO	= 2;
+
+# Compatibility mode value names
+our %COMPAT_NAME_TO_VALUE = (
+	"off"	=> $COMPAT_VALUE_OFF,
+	"on"	=> $COMPAT_VALUE_ON,
+	"auto"	=> $COMPAT_VALUE_AUTO,
+);
+
+# Compatiblity modes
+our $COMPAT_MODE_LIBTOOL	= 1 << 0;
+our $COMPAT_MODE_HAMMER		= 1 << 1;
+our $COMPAT_MODE_SPLIT_CRC	= 1 << 2;
+
+# Compatibility mode names
+our %COMPAT_NAME_TO_MODE = (
+	"libtool"	=> $COMPAT_MODE_LIBTOOL,
+	"hammer"	=> $COMPAT_MODE_HAMMER,
+	"split_crc"	=> $COMPAT_MODE_SPLIT_CRC,
+	"android_4_4_0"	=> $COMPAT_MODE_SPLIT_CRC,
+);
+
+# Map modes to names
+our %COMPAT_MODE_TO_NAME = (
+	$COMPAT_MODE_LIBTOOL	=> "libtool",
+	$COMPAT_MODE_HAMMER	=> "hammer",
+	$COMPAT_MODE_SPLIT_CRC	=> "split_crc",
+);
+
+# Compatibility mode default values
+our %COMPAT_MODE_DEFAULTS = (
+	$COMPAT_MODE_LIBTOOL	=> $COMPAT_VALUE_ON,
+	$COMPAT_MODE_HAMMER	=> $COMPAT_VALUE_AUTO,
+	$COMPAT_MODE_SPLIT_CRC	=> $COMPAT_VALUE_AUTO,
+);
+
+# Compatibility mode auto-detection routines
+sub compat_hammer_autodetect();
+our %COMPAT_MODE_AUTO = (
+	$COMPAT_MODE_HAMMER	=> \&compat_hammer_autodetect,
+	$COMPAT_MODE_SPLIT_CRC	=> 1,	# will be done later
+);
+
+our $BR_LINE		= 0;
+our $BR_BLOCK		= 1;
+our $BR_BRANCH		= 2;
+our $BR_TAKEN		= 3;
+our $BR_VEC_ENTRIES	= 4;
+our $BR_VEC_WIDTH	= 32;
+
+our $UNNAMED_BLOCK	= 9999;
 
 # Prototypes
 sub print_usage(*);
 sub gen_info($);
-sub process_dafile($);
+sub process_dafile($$);
 sub match_filename($@);
 sub solve_ambiguous_match($$$);
 sub split_filename($);
 sub solve_relative_path($$);
-sub get_dir($);
 sub read_gcov_header($);
 sub read_gcov_file($);
-sub read_bb_file($$);
-sub read_string(*$);
-sub read_gcno_file($$);
-sub read_gcno_string(*$);
-sub read_hammer_bbg_file($$);
-sub read_hammer_bbg_string(*$);
-sub unpack_int32($$);
 sub info(@);
 sub get_gcov_version();
 sub system_no_output($@);
 sub read_config($);
 sub apply_config($);
-sub gen_initial_info($);
-sub process_graphfile($);
+sub get_exclusion_data($);
+sub apply_exclusion_data($$);
+sub process_graphfile($$);
+sub filter_fn_name($);
 sub warn_handler($);
 sub die_handler($);
+sub graph_error($$);
+sub graph_expect($);
+sub graph_read(*$;$$);
+sub graph_skip(*$;$);
+sub sort_uniq(@);
+sub sort_uniq_lex(@);
+sub graph_cleanup($);
+sub graph_find_base($);
+sub graph_from_bb($$$);
+sub graph_add_order($$$);
+sub read_bb_word(*;$);
+sub read_bb_value(*;$);
+sub read_bb_string(*$);
+sub read_bb($);
+sub read_bbg_word(*;$);
+sub read_bbg_value(*;$);
+sub read_bbg_string(*);
+sub read_bbg_lines_record(*$$$$$);
+sub read_bbg($);
+sub read_gcno_word(*;$$);
+sub read_gcno_value(*$;$$);
+sub read_gcno_string(*$);
+sub read_gcno_lines_record(*$$$$$$);
+sub determine_gcno_split_crc($$$);
+sub read_gcno_function_record(*$$$$);
+sub read_gcno($);
+sub get_gcov_capabilities();
+sub get_overall_line($$$$);
+sub print_overall_rate($$$$$$$$$);
+sub br_gvec_len($);
+sub br_gvec_get($$);
+sub debug($);
+sub int_handler();
+sub parse_ignore_errors(@);
+sub is_external($);
+sub compat_name($);
+sub parse_compat_modes($);
+sub is_compat($);
+sub is_compat_auto($);
+
 
 # Global variables
 our $gcov_version;
+our $gcov_version_string;
 our $graph_file_extension;
 our $data_file_extension;
 our @data_directory;
@@ -115,18 +220,35 @@
 our $follow;
 our $checksum;
 our $no_checksum;
-our $preserve_paths;
-our $compat_libtool;
-our $no_compat_libtool;
+our $opt_compat_libtool;
+our $opt_no_compat_libtool;
+our $rc_adjust_src_path;# Regexp specifying parts to remove from source path
+our $adjust_src_pattern;
+our $adjust_src_replace;
 our $adjust_testname;
 our $config;		# Configuration file contents
-our $compatibility;	# Compatibility version flag - used to indicate
-			# non-standard GCOV data format versions
 our @ignore_errors;	# List of errors to ignore (parameter)
 our @ignore;		# List of errors to ignore (array)
 our $initial;
 our $no_recursion = 0;
 our $maxdepth;
+our $no_markers = 0;
+our $opt_derive_func_data = 0;
+our $opt_external = 1;
+our $opt_no_external;
+our $debug = 0;
+our $gcov_caps;
+our @gcov_options;
+our @internal_dirs;
+our $opt_config_file;
+our $opt_gcov_all_blocks = 1;
+our $opt_compat;
+our %opt_rc;
+our %compat_value;
+our $gcno_split_crc;
+our $func_coverage = 1;
+our $br_coverage = 0;
+our $rc_auto_base = 1;
 
 our $cwd = `pwd`;
 chomp($cwd);
@@ -141,8 +263,22 @@
 $SIG{__WARN__} = \&warn_handler;
 $SIG{__DIE__} = \&die_handler;
 
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+
+# Set LANG so that gcov output will be in a unified format
+$ENV{"LANG"} = "C";
+
+# Check command line for a configuration file name
+Getopt::Long::Configure("pass_through", "no_auto_abbrev");
+GetOptions("config-file=s" => \$opt_config_file,
+	   "rc=s%" => \%opt_rc);
+Getopt::Long::Configure("default");
+
 # Read configuration file if available
-if (-r $ENV{"HOME"}."/.lcovrc")
+if (defined($opt_config_file)) {
+	$config = read_config($opt_config_file);
+} elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
 {
 	$config = read_config($ENV{"HOME"}."/.lcovrc");
 }
@@ -151,15 +287,23 @@
 	$config = read_config("/etc/lcovrc");
 }
 
-if ($config)
+if ($config || %opt_rc)
 {
-	# Copy configuration file values to variables
+	# Copy configuration file and --rc values to variables
 	apply_config({
 		"geninfo_gcov_tool"		=> \$gcov_tool,
 		"geninfo_adjust_testname"	=> \$adjust_testname,
 		"geninfo_checksum"		=> \$checksum,
 		"geninfo_no_checksum"		=> \$no_checksum, # deprecated
-		"geninfo_compat_libtool"	=> \$compat_libtool});
+		"geninfo_compat_libtool"	=> \$opt_compat_libtool,
+		"geninfo_external"		=> \$opt_external,
+		"geninfo_gcov_all_blocks"	=> \$opt_gcov_all_blocks,
+		"geninfo_compat"		=> \$opt_compat,
+		"geninfo_adjust_src_path"	=> \$rc_adjust_src_path,
+		"geninfo_auto_base"		=> \$rc_auto_base,
+		"lcov_function_coverage"	=> \$func_coverage,
+		"lcov_branch_coverage"		=> \$br_coverage,
+	});
 
 	# Merge options
 	if (defined($no_checksum))
@@ -167,24 +311,53 @@
 		$checksum = ($no_checksum ? 0 : 1);
 		$no_checksum = undef;
 	}
+
+	# Check regexp
+	if (defined($rc_adjust_src_path)) {
+		my ($pattern, $replace) = split(/\s*=>\s*/,
+						$rc_adjust_src_path);
+		local $SIG{__DIE__};
+		eval '$adjust_src_pattern = qr>'.$pattern.'>;';
+		if (!defined($adjust_src_pattern)) {
+			my $msg = $@;
+
+			chomp($msg);
+			$msg =~ s/at \(eval.*$//;
+			warn("WARNING: invalid pattern in ".
+			     "geninfo_adjust_src_path: $msg\n");
+		} elsif (!defined($replace)) {
+			# If no replacement is specified, simply remove pattern
+			$adjust_src_replace = "";
+		} else {
+			$adjust_src_replace = $replace;
+		}
+	}
 }
 
 # Parse command line options
-if (!GetOptions("test-name=s" => \$test_name,
-		"output-filename=s" => \$output_filename,
+if (!GetOptions("test-name|t=s" => \$test_name,
+		"output-filename|o=s" => \$output_filename,
 		"checksum" => \$checksum,
 		"no-checksum" => \$no_checksum,
-		"base-directory=s" => \$base_directory,
-		"version" =>\$version,
-		"quiet" => \$quiet,
-		"help|?" => \$help,
-		"follow" => \$follow,
-		"compat-libtool" => \$compat_libtool,
-		"no-compat-libtool" => \$no_compat_libtool,
+		"base-directory|b=s" => \$base_directory,
+		"version|v" =>\$version,
+		"quiet|q" => \$quiet,
+		"help|h|?" => \$help,
+		"follow|f" => \$follow,
+		"compat-libtool" => \$opt_compat_libtool,
+		"no-compat-libtool" => \$opt_no_compat_libtool,
 		"gcov-tool=s" => \$gcov_tool,
 		"ignore-errors=s" => \@ignore_errors,
 		"initial|i" => \$initial,
 		"no-recursion" => \$no_recursion,
+		"no-markers" => \$no_markers,
+		"derive-func-data" => \$opt_derive_func_data,
+		"debug" => \$debug,
+		"external" => \$opt_external,
+		"no-external" => \$opt_no_external,
+		"compat=s" => \$opt_compat,
+		"config-file=s" => \$opt_config_file,
+		"rc=s%" => \%opt_rc,
 		))
 {
 	print(STDERR "Use $tool_name --help to get usage information\n");
@@ -199,10 +372,15 @@
 		$no_checksum = undef;
 	}
 
-	if (defined($no_compat_libtool))
+	if (defined($opt_no_compat_libtool))
 	{
-		$compat_libtool = ($no_compat_libtool ? 0 : 1);
-		$no_compat_libtool = undef;
+		$opt_compat_libtool = ($opt_no_compat_libtool ? 0 : 1);
+		$opt_no_compat_libtool = undef;
+	}
+
+	if (defined($opt_no_external)) {
+		$opt_external = 0;
+		$opt_no_external = undef;
 	}
 }
 
@@ -222,6 +400,30 @@
 	exit(0);
 }
 
+# Check gcov tool
+if (system_no_output(3, $gcov_tool, "--help") == -1)
+{
+	die("ERROR: need tool $gcov_tool!\n");
+}
+
+($gcov_version, $gcov_version_string) = get_gcov_version();
+
+# Determine gcov options
+$gcov_caps = get_gcov_capabilities();
+push(@gcov_options, "-b") if ($gcov_caps->{'branch-probabilities'} &&
+			      ($br_coverage || $func_coverage));
+push(@gcov_options, "-c") if ($gcov_caps->{'branch-counts'} &&
+			      $br_coverage);
+push(@gcov_options, "-a") if ($gcov_caps->{'all-blocks'} &&
+			      $opt_gcov_all_blocks && $br_coverage);
+push(@gcov_options, "-p") if ($gcov_caps->{'preserve-paths'});
+
+# Determine compatibility modes
+parse_compat_modes($opt_compat);
+
+# Determine which errors the user wants us to ignore
+parse_ignore_errors(@ignore_errors);
+
 # Make sure test names only contain valid characters
 if ($test_name =~ s/\W/_/g)
 {
@@ -263,17 +465,6 @@
 	$checksum = 0;
 }
 
-# Determine libtool compatibility mode
-if (defined($compat_libtool))
-{
-	$compat_libtool = ($compat_libtool? 1 : 0);
-}
-else
-{
-	# Default is on
-	$compat_libtool = 1;
-}
-
 # Determine max depth for recursion
 if ($no_recursion)
 {
@@ -302,41 +493,9 @@
 	}
 }
 
-if (@ignore_errors)
-{
-	my @expanded;
-	my $error;
-
-	# Expand comma-separated entries
-	foreach (@ignore_errors) {
-		if (/,/)
-		{
-			push(@expanded, split(",", $_));
-		}
-		else
-		{
-			push(@expanded, $_);
-		}
-	}
-
-	foreach (@expanded)
-	{
-		/^gcov$/ && do { $ignore[$ERROR_GCOV] = 1; next; } ;
-		/^source$/ && do { $ignore[$ERROR_SOURCE] = 1; next; };
-		die("ERROR: unknown argument for --ignore-errors: $_\n");
-	}
-}
-
-if (system_no_output(3, $gcov_tool, "--help") == -1)
-{
-	die("ERROR: need tool $gcov_tool!\n");
-}
-
-$gcov_version = get_gcov_version();
-
 if ($gcov_version < $GCOV_VERSION_3_4_0)
 {
-	if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
+	if (is_compat($COMPAT_MODE_HAMMER))
 	{
 		$data_file_extension = ".da";
 		$graph_file_extension = ".bbg";
@@ -353,19 +512,13 @@
 	$graph_file_extension = ".gcno";
 }	
 
-# Check for availability of --preserve-paths option of gcov
-if (`$gcov_tool --help` =~ /--preserve-paths/)
-{
-	$preserve_paths = "--preserve-paths";
-}
-
 # Check output filename
 if (defined($output_filename) && ($output_filename ne "-"))
 {
 	# Initially create output filename, data is appended
 	# for each data file processed
 	local *DUMMY_HANDLE;
-	open(DUMMY_HANDLE, ">$output_filename")
+	open(DUMMY_HANDLE, ">", $output_filename)
 		or die("ERROR: cannot create $output_filename!\n");
 	close(DUMMY_HANDLE);
 
@@ -377,20 +530,20 @@
 	}
 }
 
-# Do something
-if ($initial)
-{
-	foreach (@data_directory)
-	{
-		gen_initial_info($_);
-	}
+# Build list of directories to identify external files
+foreach my $entry(@data_directory, $base_directory) {
+	next if (!defined($entry));
+	push(@internal_dirs, solve_relative_path($cwd, $entry));
 }
-else
-{
-	foreach (@data_directory)
-	{
-		gen_info($_);
-	}
+
+# Do something
+foreach my $entry (@data_directory) {
+	gen_info($entry);
+}
+
+if ($initial && $br_coverage) {
+	warn("Note: --initial does not generate branch coverage ".
+	     "data\n");
 }
 info("Finished .info-file creation\n");
 
@@ -426,15 +579,54 @@
       --(no-)checksum               Enable (disable) line checksumming
       --(no-)compat-libtool         Enable (disable) libtool compatibility mode
       --gcov-tool TOOL              Specify gcov tool location
-      --ignore-errors ERROR         Continue after ERROR (gcov, source)
-      --no-recursion                Exlude subdirectories from processing
-      --function-coverage           Capture function call counts
+      --ignore-errors ERROR         Continue after ERROR (gcov, source, graph)
+      --no-recursion                Exclude subdirectories from processing
+      --no-markers                  Ignore exclusion markers in source code
+      --derive-func-data            Generate function data from line data
+      --(no-)external               Include (ignore) data for external files
+      --config-file FILENAME        Specify configuration file location
+      --rc SETTING=VALUE            Override configuration file setting
+      --compat MODE=on|off|auto     Set compat MODE (libtool, hammer, split_crc)
 
 For more information see: $lcov_url
 END_OF_USAGE
 	;
 }
 
+#
+# get_common_prefix(min_dir, filenames)
+#
+# Return the longest path prefix shared by all filenames. MIN_DIR specifies
+# the minimum number of directories that a filename may have after removing
+# the prefix.
+#
+
+sub get_common_prefix($@)
+{
+	my ($min_dir, @files) = @_;
+	my $file;
+	my @prefix;
+	my $i;
+
+	foreach $file (@files) {
+		my ($v, $d, $f) = splitpath($file);
+		my @comp = splitdir($d);
+
+		if (!@prefix) {
+			@prefix = @comp;
+			next;
+		}
+		for ($i = 0; $i < scalar(@comp) && $i < scalar(@prefix); $i++) {
+			if ($comp[$i] ne $prefix[$i] ||
+			    ((scalar(@comp) - ($i + 1)) <= $min_dir)) {
+				delete(@prefix[$i..scalar(@prefix)]);
+				last;
+			}
+		}
+	}
+
+	return catdir(@prefix);
+}
 
 #
 # gen_info(directory)
@@ -473,52 +665,190 @@
 {
 	my $directory = $_[0];
 	my @file_list;
+	my $file;
+	my $prefix;
+	my $type;
+	my $ext;
+
+	if ($initial) {
+		$type = "graph";
+		$ext = $graph_file_extension;
+	} else {
+		$type = "data";
+		$ext = $data_file_extension;
+	}
 
 	if (-d $directory)
 	{
-		info("Scanning $directory for $data_file_extension ".
-		     "files ...\n");	
+		info("Scanning $directory for $ext files ...\n");
 
-		@file_list = `find "$directory" $maxdepth $follow -name \\*$data_file_extension -type f 2>/dev/null`;
+		@file_list = `find "$directory" $maxdepth $follow -name \\*$ext -type f 2>/dev/null`;
 		chomp(@file_list);
-		@file_list or die("ERROR: no $data_file_extension files found ".
-				  "in $directory!\n");
-		info("Found %d data files in %s\n", $#file_list+1, $directory);
+		@file_list or
+			die("ERROR: no $ext files found in $directory!\n");
+		$prefix = get_common_prefix(1, @file_list);
+		info("Found %d %s files in %s\n", $#file_list+1, $type,
+		     $directory);
 	}
 	else
 	{
 		@file_list = ($directory);
+		$prefix = "";
 	}
 
 	# Process all files in list
-	foreach (@file_list) { process_dafile($_); }
+	foreach $file (@file_list) {
+		# Process file
+		if ($initial) {
+			process_graphfile($file, $prefix);
+		} else {
+			process_dafile($file, $prefix);
+		}
+	}
 }
 
 
 #
-# process_dafile(da_filename)
+# derive_data(contentdata, funcdata, bbdata)
+#
+# Calculate function coverage data by combining line coverage data and the
+# list of lines belonging to a function.
+#
+# contentdata: [ instr1, count1, source1, instr2, count2, source2, ... ]
+# instr<n>: Instrumentation flag for line n
+# count<n>: Execution count for line n
+# source<n>: Source code for line n
+#
+# funcdata: [ count1, func1, count2, func2, ... ]
+# count<n>: Execution count for function number n
+# func<n>: Function name for function number n
+#
+# bbdata: function_name -> [ line1, line2, ... ]
+# line<n>: Line number belonging to the corresponding function
+#
+
+sub derive_data($$$)
+{
+	my ($contentdata, $funcdata, $bbdata) = @_;
+	my @gcov_content = @{$contentdata};
+	my @gcov_functions = @{$funcdata};
+	my %fn_count;
+	my %ln_fn;
+	my $line;
+	my $maxline;
+	my %fn_name;
+	my $fn;
+	my $count;
+
+	if (!defined($bbdata)) {
+		return @gcov_functions;
+	}
+
+	# First add existing function data
+	while (@gcov_functions) {
+		$count = shift(@gcov_functions);
+		$fn = shift(@gcov_functions);
+
+		$fn_count{$fn} = $count;
+	}
+
+	# Convert line coverage data to function data
+	foreach $fn (keys(%{$bbdata})) {
+		my $line_data = $bbdata->{$fn};
+		my $line;
+		my $fninstr = 0;
+
+		if ($fn eq "") {
+			next;
+		}
+		# Find the lowest line count for this function
+		$count = 0;
+		foreach $line (@$line_data) {
+			my $linstr = $gcov_content[ ( $line - 1 ) * 3 + 0 ];
+			my $lcount = $gcov_content[ ( $line - 1 ) * 3 + 1 ];
+
+			next if (!$linstr);
+			$fninstr = 1;
+			if (($lcount > 0) &&
+			    (($count == 0) || ($lcount < $count))) {
+				$count = $lcount;
+			}
+		}
+		next if (!$fninstr);
+		$fn_count{$fn} = $count;
+	}
+
+
+	# Check if we got data for all functions
+	foreach $fn (keys(%fn_name)) {
+		if ($fn eq "") {
+			next;
+		}
+		if (defined($fn_count{$fn})) {
+			next;
+		}
+		warn("WARNING: no derived data found for function $fn\n");
+	}
+
+	# Convert hash to list in @gcov_functions format
+	foreach $fn (sort(keys(%fn_count))) {
+		push(@gcov_functions, $fn_count{$fn}, $fn);
+	}
+
+	return @gcov_functions;
+}
+
+#
+# get_filenames(directory, pattern)
+#
+# Return a list of filenames found in directory which match the specified
+# pattern.
+#
+# Die on error.
+#
+
+sub get_filenames($$)
+{
+	my ($dirname, $pattern) = @_;
+	my @result;
+	my $directory;
+	local *DIR;
+
+	opendir(DIR, $dirname) or
+		die("ERROR: cannot read directory $dirname\n");
+	while ($directory = readdir(DIR)) {
+		push(@result, $directory) if ($directory =~ /$pattern/);
+	}
+	closedir(DIR);
+
+	return @result;
+}
+
+#
+# process_dafile(da_filename, dir)
 #
 # Create a .info file for a single data file.
 #
 # Die on error.
 #
 
-sub process_dafile($)
+sub process_dafile($$)
 {
-	info("Processing %s\n", $_[0]);
-
+	my ($file, $dir) = @_;
 	my $da_filename;	# Name of data file to process
 	my $da_dir;		# Directory of data file
 	my $source_dir;		# Directory of source file
 	my $da_basename;	# data filename without ".da/.gcda" extension
 	my $bb_filename;	# Name of respective graph file
-	my %bb_content;		# Contents of graph file
+	my $bb_basename;	# Basename of the original graph file
+	my $graph;		# Contents of graph file
+	my $instr;		# Contents of graph file part 2
 	my $gcov_error;		# Error code of gcov tool
 	my $object_dir;		# Directory containing all object files
 	my $source_filename;	# Name of a source code file
 	my $gcov_file;		# Name of a .gcov file
 	my @gcov_content;	# Content of a .gcov file
-	my @gcov_branches;	# Branch content of a .gcov file
+	my $gcov_branches;	# Branch content of a .gcov file
 	my @gcov_functions;	# Function calls of a .gcov file
 	my @gcov_list;		# List of generated .gcov files
 	my $line_number;	# Line number count
@@ -526,28 +856,31 @@
 	my $lines_found;	# Number of instrumented lines found
 	my $funcs_hit;		# Number of instrumented functions hit
 	my $funcs_found;	# Number of instrumented functions found
+	my $br_hit;
+	my $br_found;
 	my $source;		# gcov source header information
 	my $object;		# gcov object header information
 	my @matches;		# List of absolute paths matching filename
 	my @unprocessed;	# List of unprocessed source code files
 	my $base_dir;		# Base directory for current file
+	my @tmp_links;		# Temporary links to be cleaned up
 	my @result;
 	my $index;
 	my $da_renamed;		# If data file is to be renamed
 	local *INFO_HANDLE;
 
+	info("Processing %s\n", abs2rel($file, $dir));
 	# Get path to data file in absolute and normalized form (begins with /,
 	# contains no more ../ or ./)
-	$da_filename = solve_relative_path($cwd, $_[0]);
+	$da_filename = solve_relative_path($cwd, $file);
 
 	# Get directory and basename of data file
 	($da_dir, $da_basename) = split_filename($da_filename);
 
-	# avoid files from .libs dirs 	 
-	if ($compat_libtool && $da_dir =~ m/(.*)\/\.libs$/) {
-		$source_dir = $1;
-	} else {
-		$source_dir = $da_dir;
+	$source_dir = $da_dir;
+	if (is_compat($COMPAT_MODE_LIBTOOL)) {
+		# Avoid files from .libs dirs 	 
+		$source_dir =~ s/\.libs$//;
 	}
 
 	if (-z $da_filename)
@@ -577,7 +910,8 @@
 	}
 
 	# Construct name of graph file
-	$bb_filename = $da_dir."/".$da_basename.$graph_file_extension;
+	$bb_basename = $da_basename.$graph_file_extension;
+	$bb_filename = "$da_dir/$bb_basename";
 
 	# Find out the real location of graph file in case we're just looking at
 	# a link
@@ -601,21 +935,27 @@
 	# information about functions and their source code positions.
 	if ($gcov_version < $GCOV_VERSION_3_4_0)
 	{
-		if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
+		if (is_compat($COMPAT_MODE_HAMMER))
 		{
-			%bb_content = read_hammer_bbg_file($bb_filename,
-							   $base_dir);
+			($instr, $graph) = read_bbg($bb_filename);
 		}
 		else
 		{
-			%bb_content = read_bb_file($bb_filename, $base_dir);
+			($instr, $graph) = read_bb($bb_filename);
 		}
 	} 
 	else
 	{
-		%bb_content = read_gcno_file($bb_filename, $base_dir);
+		($instr, $graph) = read_gcno($bb_filename);
 	} 
 
+	# Try to find base directory automatically if requested by user
+	if ($rc_auto_base) {
+		$base_dir = find_base_from_graph($base_dir, $instr, $graph);
+	}
+
+	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+
 	# Set $object_dir to real location of object files. This may differ
 	# from $da_dir if the graph file is just a link to the "real" object
 	# file location.
@@ -630,9 +970,21 @@
 		       "$object_dir/$da_basename$data_file_extension")
 			and die ("ERROR: cannot create link $object_dir/".
 				 "$da_basename$data_file_extension!\n");
+		push(@tmp_links,
+		     "$object_dir/$da_basename$data_file_extension");
+		# Need to create link to graph file if basename of link
+		# and file are different (CONFIG_MODVERSION compat)
+		if ((basename($bb_filename) ne $bb_basename) &&
+		    (! -e "$object_dir/$bb_basename")) {
+			symlink($bb_filename, "$object_dir/$bb_basename") or
+				warn("WARNING: cannot create link ".
+				     "$object_dir/$bb_basename\n");
+			push(@tmp_links, "$object_dir/$bb_basename");
+		}
 	}
 
 	# Change to directory containing data files and apply GCOV
+	debug("chdir($base_dir)\n");
         chdir($base_dir);
 
 	if ($da_renamed)
@@ -644,19 +996,8 @@
 	}
 
 	# Execute gcov command and suppress standard output
-	if ($preserve_paths)
-	{
-		$gcov_error = system_no_output(1, $gcov_tool, $da_filename,
-					       "-o", $object_dir,
-					       "--preserve-paths",
-					       "-b");
-	}
-	else
-	{
-		$gcov_error = system_no_output(1, $gcov_tool, $da_filename,
-					       "-o", $object_dir,
-					       "-b");
-	}
+	$gcov_error = system_no_output(1, $gcov_tool, $da_filename,
+				       "-o", $object_dir, @gcov_options);
 
 	if ($da_renamed)
 	{
@@ -664,10 +1005,9 @@
 			and die ("ERROR: cannot rename $da_filename.ori");
 	}
 
-	# Clean up link
-	if ($object_dir ne $da_dir)
-	{
-		unlink($object_dir."/".$da_basename.$data_file_extension);
+	# Clean up temporary links
+	foreach (@tmp_links) {
+		unlink($_);
 	}
 
 	if ($gcov_error)
@@ -681,7 +1021,7 @@
 	}
 
 	# Collect data from resulting .gcov files and create .info file
-	@gcov_list = glob("*.gcov");
+	@gcov_list = get_filenames('.', '\.gcov$');
 
 	# Check for files
 	if (!@gcov_list)
@@ -700,7 +1040,7 @@
 		else
 		{
 			# Append to output file
-			open(INFO_HANDLE, ">>$output_filename")
+			open(INFO_HANDLE, ">>", $output_filename)
 				or die("ERROR: cannot write to ".
 				       "$output_filename!\n");
 		}
@@ -708,7 +1048,7 @@
 	else
 	{
 		# Open .info file for output
-		open(INFO_HANDLE, ">$da_filename.info")
+		open(INFO_HANDLE, ">", "$da_filename.info")
 			or die("ERROR: cannot create $da_filename.info!\n");
 	}
 
@@ -717,20 +1057,35 @@
 
 	# Traverse the list of generated .gcov files and combine them into a
 	# single .info file
-	@unprocessed = keys(%bb_content);
-	foreach $gcov_file (@gcov_list)
+	@unprocessed = keys(%{$instr});
+	foreach $gcov_file (sort(@gcov_list))
 	{
+		my $i;
+		my $num;
+
+		# Skip gcov file for gcc built-in code
+		next if ($gcov_file eq "<built-in>.gcov");
+
 		($source, $object) = read_gcov_header($gcov_file);
 
-		if (defined($source))
-		{
-			$source = solve_relative_path($base_dir, $source);
+		if (!defined($source)) {
+			# Derive source file name from gcov file name if
+			# header format could not be parsed
+			$source = $gcov_file;
+			$source =~ s/\.gcov$//;
+		}
+
+		$source = solve_relative_path($base_dir, $source);
+
+		if (defined($adjust_src_pattern)) {
+			# Apply transformation as specified by user
+			$source =~ s/$adjust_src_pattern/$adjust_src_replace/g;
 		}
 
 		# gcov will happily create output even if there's no source code
 		# available - this interferes with checksum creation so we need
 		# to pull the emergency brake here.
-		if (defined($source) && ! -r $source && $checksum)
+		if (! -r $source && $checksum)
 		{
 			if ($ignore[$ERROR_SOURCE])
 			{
@@ -741,8 +1096,7 @@
 			die("ERROR: could not read source file $source\n");
 		}
 
-		@matches = match_filename(defined($source) ? $source :
-					  $gcov_file, keys(%bb_content));
+		@matches = match_filename($source, keys(%{$instr}));
 
 		# Skip files that are not mentioned in the graph file
 		if (!@matches)
@@ -756,8 +1110,14 @@
 
 		# Read in contents of gcov file
 		@result = read_gcov_file($gcov_file);
+		if (!defined($result[0])) {
+			warn("WARNING: skipping unreadable file ".
+			     $gcov_file."\n");
+			unlink($gcov_file);
+			next;
+		}
 		@gcov_content = @{$result[0]};
-		@gcov_branches = @{$result[1]};
+		$gcov_branches = $result[1];
 		@gcov_functions = @{$result[2]};
 
 		# Skip empty files
@@ -790,22 +1150,61 @@
 			}
 		}
 
+		# Skip external files if requested
+		if (!$opt_external) {
+			if (is_external($source_filename)) {
+				info("  ignoring data for external file ".
+				     "$source_filename\n");
+				unlink($gcov_file);
+				next;
+			}
+		}
+
 		# Write absolute path of source file
 		printf(INFO_HANDLE "SF:%s\n", $source_filename);
 
-		# Write function-related information
-		if (defined($bb_content{$source_filename}))
-		{
-			foreach (split(",",$bb_content{$source_filename}))
-			{
-				my ($fn, $line) = split("=", $_);
+		# If requested, derive function coverage data from
+		# line coverage data of the first line of a function
+		if ($opt_derive_func_data) {
+			@gcov_functions =
+				derive_data(\@gcov_content, \@gcov_functions,
+					    $graph->{$source_filename});
+		}
 
+		# Write function-related information
+		if (defined($graph->{$source_filename}))
+		{
+			my $fn_data = $graph->{$source_filename};
+			my $fn;
+
+			foreach $fn (sort
+				{$fn_data->{$a}->[0] <=> $fn_data->{$b}->[0]}
+				keys(%{$fn_data})) {
+				my $ln_data = $fn_data->{$fn};
+				my $line = $ln_data->[0];
+
+				# Skip empty function
 				if ($fn eq "") {
 					next;
 				}
+				# Remove excluded functions
+				if (!$no_markers) {
+					my $gfn;
+					my $found = 0;
+
+					foreach $gfn (@gcov_functions) {
+						if ($gfn eq $fn) {
+							$found = 1;
+							last;
+						}
+					}
+					if (!$found) {
+						next;
+					}
+				}
 
 				# Normalize function name
-				$fn =~ s/\W/_/g;
+				$fn = filter_fn_name($fn);
 
 				print(INFO_HANDLE "FN:$line,$fn\n");
 			}
@@ -820,18 +1219,42 @@
 		$funcs_hit = 0;
 		while (@gcov_functions)
 		{
-			printf(INFO_HANDLE "FNDA:%s,%s\n",
-				       $gcov_functions[0],
-				       $gcov_functions[1]);
-				$funcs_found++;
-			$funcs_hit++ if $gcov_functions[0];
-			splice(@gcov_functions,0,2);
+			my $count = shift(@gcov_functions);
+			my $fn = shift(@gcov_functions);
+
+			$fn = filter_fn_name($fn);
+			printf(INFO_HANDLE "FNDA:$count,$fn\n");
+			$funcs_found++;
+			$funcs_hit++ if ($count > 0);
 		}
 		if ($funcs_found > 0) {
 			printf(INFO_HANDLE "FNF:%s\n", $funcs_found);
 			printf(INFO_HANDLE "FNH:%s\n", $funcs_hit);
 		}
 
+		# Write coverage information for each instrumented branch:
+		#
+		#   BRDA:<line number>,<block number>,<branch number>,<taken>
+		#
+		# where 'taken' is the number of times the branch was taken
+		# or '-' if the block to which the branch belongs was never
+		# executed
+		$br_found = 0;
+		$br_hit = 0;
+		$num = br_gvec_len($gcov_branches);
+		for ($i = 0; $i < $num; $i++) {
+			my ($line, $block, $branch, $taken) =
+				br_gvec_get($gcov_branches, $i);
+
+			print(INFO_HANDLE "BRDA:$line,$block,$branch,$taken\n");
+			$br_found++;
+			$br_hit++ if ($taken ne '-' && $taken > 0);
+		}
+		if ($br_found > 0) {
+			printf(INFO_HANDLE "BRF:%s\n", $br_found);
+			printf(INFO_HANDLE "BRH:%s\n", $br_hit);
+		}
+
 		# Reset line counters
 		$line_number = 0;
 		$lines_found = 0;
@@ -862,27 +1285,6 @@
 			splice(@gcov_content,0,3);
 		}
 
-		#--
-		#-- BA: <code-line>, <branch-coverage>
-		#--
-		#-- print one BA line for every branch of a
-		#-- conditional.  <branch-coverage> values
-		#-- are:
-		#--     0 - not executed
-		#--     1 - executed but not taken
-		#--     2 - executed and taken
-		#--
-		while (@gcov_branches)
-		{
-			if ($gcov_branches[0])
-			{
-				printf(INFO_HANDLE "BA:%s,%s\n",
-				       $gcov_branches[0],
-				       $gcov_branches[1]);
-			}
-			splice(@gcov_branches,0,2);
-		}
-
 		# Write line statistics and section separator
 		printf(INFO_HANDLE "LF:%s\n", $lines_found);
 		printf(INFO_HANDLE "LH:%s\n", $lines_hit);
@@ -922,8 +1324,40 @@
 {
 	my $path = $_[0];
 	my $dir = $_[1];
+	my $volume;
+	my $directories;
+	my $filename;
+	my @dirs;			# holds path elements
 	my $result;
 
+	# Convert from Windows path to msys path
+	if( $^O eq "msys" )
+	{
+		# search for a windows drive letter at the beginning
+		($volume, $directories, $filename) = File::Spec::Win32->splitpath( $dir );
+		if( $volume ne '' )
+		{
+			my $uppercase_volume;
+			# transform c/d\../e/f\g to Windows style c\d\..\e\f\g
+			$dir = File::Spec::Win32->canonpath( $dir );
+			# use Win32 module to retrieve path components
+			# $uppercase_volume is not used any further
+			( $uppercase_volume, $directories, $filename ) = File::Spec::Win32->splitpath( $dir );
+			@dirs = File::Spec::Win32->splitdir( $directories );
+			
+			# prepend volume, since in msys C: is always mounted to /c
+			$volume =~ s|^([a-zA-Z]+):|/\L$1\E|;
+			unshift( @dirs, $volume );
+			
+			# transform to Unix style '/' path
+			$directories = File::Spec->catdir( @dirs );
+			$dir = File::Spec->catpath( '', $directories, $filename );
+		} else {
+			# eliminate '\' path separators
+			$dir = File::Spec->canonpath( $dir );
+		}
+	}
+
 	$result = $dir;
 	# Prepend path if not absolute
 	if ($dir =~ /^[^\/]/)
@@ -936,6 +1370,10 @@
 
 	# Remove .
 	$result =~ s/\/\.\//\//g;
+	$result =~ s/\/\.$/\//g;
+
+	# Remove trailing /
+	$result =~ s/\/$//g;
 
 	# Solve ..
 	while ($result =~ s/\/[^\/]+\/\.\.\//\//)
@@ -958,28 +1396,42 @@
 
 sub match_filename($@)
 {
-	my $filename = shift;
-	my @list = @_;
+	my ($filename, @list) = @_;
+	my ($vol, $dir, $file) = splitpath($filename);
+	my @comp = splitdir($dir);
+	my $comps = scalar(@comp);
+	my $entry;
 	my @result;
 
-	$filename =~ s/^(.*).gcov$/$1/;
+entry:
+	foreach $entry (@list) {
+		my ($evol, $edir, $efile) = splitpath($entry);
+		my @ecomp;
+		my $ecomps;
+		my $i;
 
-	if ($filename =~ /^\/(.*)$/)
-	{
-		$filename = "$1";
-	}
-
-	foreach (@list)
-	{
-		if (/\/\Q$filename\E(.*)$/ && $1 eq "")
-		{
-			@result = (@result, $_);
+		# Filename component must match
+		if ($efile ne $file) {
+			next;
 		}
+		# Check directory components last to first for match
+		@ecomp = splitdir($edir);
+		$ecomps = scalar(@ecomp);
+		if ($ecomps < $comps) {
+			next;
+		}
+		for ($i = 0; $i < $comps; $i++) {
+			if ($comp[$comps - $i - 1] ne
+			    $ecomp[$ecomps - $i - 1]) {
+				next entry;
+			}
+		}
+		push(@result, $entry),
 	}
+
 	return @result;
 }
 
-
 #
 # solve_ambiguous_match(rel_filename, matches_ref, gcov_content_ref)
 #
@@ -1006,7 +1458,7 @@
 	{
 
 		# Compare file contents
-		open(SOURCE, $filename)
+		open(SOURCE, "<", $filename)
 			or die("ERROR: cannot read $filename!\n");
 
 		$no_match = 0;
@@ -1014,6 +1466,9 @@
 		{
 			chomp;
 
+			# Also remove CR from line-end
+			s/\015$//;
+
 			if ($_ ne @$content[$index])
 			{
 				$no_match = 1;
@@ -1052,21 +1507,6 @@
 
 
 #
-# get_dir(filename);
-#
-# Return the directory component of a given FILENAME.
-#
-
-sub get_dir($)
-{
-	my @components = split("/", $_[0]);
-	pop(@components);
-
-	return join("/", @components);
-}
-
-
-#
 # read_gcov_header(gcov_filename)
 #
 # Parse file GCOV_FILENAME and return a list containing the following
@@ -1088,7 +1528,7 @@
 	my $object;
 	local *INPUT;
 
-	if (!open(INPUT, $_[0]))
+	if (!open(INPUT, "<", $_[0]))
 	{
 		if ($ignore_errors[$ERROR_GCOV])
 		{
@@ -1102,6 +1542,9 @@
 	{
 		chomp($_);
 
+		# Also remove CR from line-end
+		s/\015$//;
+
 		if (/^\s+-:\s+0:Source:(.*)$/)
 		{
 			# Source: header entry
@@ -1125,6 +1568,84 @@
 
 
 #
+# br_gvec_len(vector)
+#
+# Return the number of entries in the branch coverage vector.
+#
+
+sub br_gvec_len($)
+{
+	my ($vec) = @_;
+
+	return 0 if (!defined($vec));
+	return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
+}
+
+
+#
+# br_gvec_get(vector, number)
+#
+# Return an entry from the branch coverage vector.
+#
+
+sub br_gvec_get($$)
+{
+	my ($vec, $num) = @_;
+	my $line;
+	my $block;
+	my $branch;
+	my $taken;
+	my $offset = $num * $BR_VEC_ENTRIES;
+
+	# Retrieve data from vector
+	$line	= vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH);
+	$block	= vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+	$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
+	$taken	= vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
+
+	# Decode taken value from an integer
+	if ($taken == 0) {
+		$taken = "-";
+	} else {
+		$taken--;
+	}
+
+	return ($line, $block, $branch, $taken);
+}
+
+
+#
+# br_gvec_push(vector, line, block, branch, taken)
+#
+# Add an entry to the branch coverage vector.
+#
+
+sub br_gvec_push($$$$$)
+{
+	my ($vec, $line, $block, $branch, $taken) = @_;
+	my $offset;
+
+	$vec = "" if (!defined($vec));
+	$offset = br_gvec_len($vec) * $BR_VEC_ENTRIES;
+
+	# Encode taken value into an integer
+	if ($taken eq "-") {
+		$taken = 0;
+	} else {
+		$taken++;
+	}
+
+	# Add to vector
+	vec($vec, $offset + $BR_LINE, $BR_VEC_WIDTH) = $line;
+	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
+	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
+	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
+
+	return $vec;
+}
+
+
+#
 # read_gcov_file(gcov_filename)
 #
 # Parse file GCOV_FILENAME (.gcov file format) and return the list:
@@ -1137,8 +1658,8 @@
 # $result[($line_number-1)*3+1] = execution count for line $line_number
 # $result[($line_number-1)*3+2] = source code text for line $line_number
 #
-# gcov_branch is a list of 2 elements
-# (linenumber, branch result) for each branch
+# gcov_branch is a vector of 4 4-byte long elements for each branch:
+# line number, block number, branch number, count + 1 or 0
 #
 # gcov_func is a list of 2 elements
 # (number of calls, function name) for each function
@@ -1150,13 +1671,23 @@
 {
 	my $filename = $_[0];
 	my @result = ();
-	my @branches = ();
+	my $branches = "";
 	my @functions = ();
 	my $number;
+	my $exclude_flag = 0;
+	my $exclude_line = 0;
+	my $last_block = $UNNAMED_BLOCK;
+	my $last_line = 0;
 	local *INPUT;
 
-	open(INPUT, $filename)
-		or die("ERROR: cannot read $filename!\n");
+	if (!open(INPUT, "<", $filename)) {
+		if ($ignore_errors[$ERROR_GCOV])
+		{
+			warn("WARNING: cannot read $filename!\n");
+			return (undef, undef, undef);
+		}
+		die("ERROR: cannot read $filename!\n");
+	}
 
 	if ($gcov_version < $GCOV_VERSION_3_3_0)
 	{
@@ -1165,29 +1696,19 @@
 		{
 			chomp($_);
 
-			if (/^\t\t(.*)$/)
-			{
-				# Uninstrumented line
-				push(@result, 0);
-				push(@result, 0);
-				push(@result, $1);
-			}
-			elsif (/^branch/)
-			{
-				# Branch execution data
-				push(@branches, scalar(@result) / 3);
-				if (/^branch \d+ never executed$/)
-				{
-					push(@branches, 0);
-				}
-				elsif (/^branch \d+ taken = 0%/)
-				{
-					push(@branches, 1);
-				}
-				else
-				{
-					push(@branches, 2);
-				}
+			# Also remove CR from line-end
+			s/\015$//;
+
+			if (/^branch\s+(\d+)\s+taken\s+=\s+(\d+)/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, $2);
+			} elsif (/^branch\s+(\d+)\s+never\s+executed/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, '-');
 			}
 			elsif (/^call/ || /^function/)
 			{
@@ -1195,15 +1716,43 @@
 			}
 			else
 			{
+				$last_line++;
+				# Check for exclusion markers
+				if (!$no_markers) {
+					if (/$EXCL_STOP/) {
+						$exclude_flag = 0;
+					} elsif (/$EXCL_START/) {
+						$exclude_flag = 1;
+					}
+					if (/$EXCL_LINE/ || $exclude_flag) {
+						$exclude_line = 1;
+					} else {
+						$exclude_line = 0;
+					}
+				}
 				# Source code execution data
+				if (/^\t\t(.*)$/)
+				{
+					# Uninstrumented line
+					push(@result, 0);
+					push(@result, 0);
+					push(@result, $1);
+					next;
+				}
 				$number = (split(" ",substr($_, 0, 16)))[0];
 
 				# Check for zero count which is indicated
 				# by ######
 				if ($number eq "######") { $number = 0;	}
 
-				push(@result, 1);
-				push(@result, $number);
+				if ($exclude_line) {
+					# Register uninstrumented line instead
+					push(@result, 0);
+					push(@result, 0);
+				} else {
+					push(@result, 1);
+					push(@result, $number);
+				}
 				push(@result, substr($_, 16));
 			}
 		}
@@ -1215,25 +1764,31 @@
 		{
 			chomp($_);
 
-			if (/^branch\s+\d+\s+(\S+)\s+(\S+)/)
-			{
-				# Branch execution data
-				push(@branches, scalar(@result) / 3);
-				if ($1 eq "never")
-				{
-					push(@branches, 0);
-				}
-				elsif ($2 eq "0%")
-				{
-					push(@branches, 1);
-				}
-				else
-				{
-					push(@branches, 2);
-				}
+			# Also remove CR from line-end
+			s/\015$//;
+
+			if (/^\s*(\d+|\$+):\s*(\d+)-block\s+(\d+)\s*$/) {
+				# Block information - used to group related
+				# branches
+				$last_line = $2;
+				$last_block = $3;
+			} elsif (/^branch\s+(\d+)\s+taken\s+(\d+)/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, $2);
+			} elsif (/^branch\s+(\d+)\s+never\s+executed/) {
+				next if (!$br_coverage);
+				next if ($exclude_line);
+				$branches = br_gvec_push($branches, $last_line,
+						$last_block, $1, '-');
 			}
-			elsif (/^function\s+(\S+)\s+called\s+(\d+)/)
+			elsif (/^function\s+(.+)\s+called\s+(\d+)\s+/)
 			{
+				next if (!$func_coverage);
+				if ($exclude_line) {
+					next;
+				}
 				push(@functions, $2, $1);
 			}
 			elsif (/^call/)
@@ -1242,580 +1797,59 @@
 			}
 			elsif (/^\s*([^:]+):\s*([^:]+):(.*)$/)
 			{
+				my ($count, $line, $code) = ($1, $2, $3);
+
+				$last_line = $line;
+				$last_block = $UNNAMED_BLOCK;
+				# Check for exclusion markers
+				if (!$no_markers) {
+					if (/$EXCL_STOP/) {
+						$exclude_flag = 0;
+					} elsif (/$EXCL_START/) {
+						$exclude_flag = 1;
+					}
+					if (/$EXCL_LINE/ || $exclude_flag) {
+						$exclude_line = 1;
+					} else {
+						$exclude_line = 0;
+					}
+				}
 				# <exec count>:<line number>:<source code>
-				if ($2 eq "0")
+				if ($line eq "0")
 				{
 					# Extra data
 				}
-				elsif ($1 eq "-")
+				elsif ($count eq "-")
 				{
 					# Uninstrumented line
 					push(@result, 0);
 					push(@result, 0);
-					push(@result, $3);
+					push(@result, $code);
 				}
 				else
 				{
-					# Source code execution data
-					$number = $1;
-
-					# Check for zero count
-					if ($number eq "#####")	{ $number = 0; }
-
-					push(@result, 1);
-					push(@result, $number);
-					push(@result, $3);
+					if ($exclude_line) {
+						push(@result, 0);
+						push(@result, 0);
+					} else {
+						# Check for zero count
+						if ($count eq "#####") {
+							$count = 0;
+						}
+						push(@result, 1);
+						push(@result, $count);
+					}
+					push(@result, $code);
 				}
 			}
 		}
 	}
 
 	close(INPUT);
-	return(\@result, \@branches, \@functions);
-}
-
-
-#
-# read_bb_file(bb_filename, base_dir)
-#
-# Read .bb file BB_FILENAME and return a hash containing the following
-# mapping:
-#
-#   filename -> comma-separated list of pairs (function name=starting
-#               line number) to indicate the starting line of a function or
-#               =name to indicate an instrumented line
-#
-# for each entry in the .bb file. Filenames are absolute, i.e. relative
-# filenames are prefixed with BASE_DIR.
-#
-# Die on error.
-#
-
-sub read_bb_file($$)
-{
-	my $bb_filename		= $_[0];
-	my $base_dir = $_[1];
-	my %result;
-	my $filename;
-	my $function_name;
-	my $minus_one		= sprintf("%d", 0x80000001);
-	my $minus_two		= sprintf("%d", 0x80000002);
-	my $value;
-	my $packed_word;
-	local *INPUT;
-
-	open(INPUT, $bb_filename)
-		or die("ERROR: cannot read $bb_filename!\n");
-
-	binmode(INPUT);
-
-	# Read data in words of 4 bytes
-	while (read(INPUT, $packed_word, 4) == 4)
-	{
-		# Decode integer in intel byteorder
-		$value = unpack_int32($packed_word, 0);
-
-		# Note: the .bb file format is documented in GCC info pages
-		if ($value == $minus_one)
-		{
-			# Filename follows
-			$filename = read_string(*INPUT, $minus_one)
-				or die("ERROR: incomplete filename in ".
-				       "$bb_filename!\n");
-
-			# Make path absolute
-			$filename = solve_relative_path($base_dir, $filename);
-
-			# Insert into hash if not yet present.
-			# This is necessary because functions declared as
-			# "inline" are not listed as actual functions in
-			# .bb files
-			if (!$result{$filename})
-			{
-				$result{$filename}="";
-			}
-		}
-		elsif ($value == $minus_two)
-		{
-			# Function name follows
-			$function_name = read_string(*INPUT, $minus_two)
-				 or die("ERROR: incomplete function ".
-					"name in $bb_filename!\n");
-			$function_name =~ s/\W/_/g;
-		}
-		elsif ($value > 0)
-		{
-			if (defined($filename))
-			{
-				$result{$filename} .=
-					($result{$filename} ? "," : "").
-					"=$value";
-			}
-			else
-			{
-				warn("WARNING: unassigned line".
-				     " number in .bb file ".
-				     "$bb_filename\n");
-			}
-			if ($function_name)
-			{
-				# Got a full entry filename, funcname, lineno
-				# Add to resulting hash
-
-				$result{$filename}.=
-				  ($result{$filename} ? "," : "").
-				  join("=",($function_name,$value));
-				undef($function_name);
-			}
-		}
+	if ($exclude_flag) {
+		warn("WARNING: unterminated exclusion section in $filename\n");
 	}
-	close(INPUT);
-
-	if (!scalar(keys(%result)))
-	{
-		die("ERROR: no data found in $bb_filename!\n");
-	}
-	return %result;
-}
-
-
-#
-# read_string(handle, delimiter);
-#
-# Read and return a string in 4-byte chunks from HANDLE until DELIMITER
-# is found.
-#
-# Return empty string on error.
-#
-
-sub read_string(*$)
-{
-	my $HANDLE	= $_[0];
-	my $delimiter	= $_[1];
-	my $string	= "";
-	my $packed_word;
-	my $value;
-
-	while (read($HANDLE,$packed_word,4) == 4)
-	{
-		$value = unpack_int32($packed_word, 0);
-
-		if ($value == $delimiter)
-		{
-			# Remove trailing nil bytes
-			$/="\0";
-			while (chomp($string)) {};
-			$/="\n";
-			return($string);
-		}
-
-		$string = $string.$packed_word;
-	}
-	return("");
-}
-
-
-#
-# read_gcno_file(bb_filename, base_dir)
-#
-# Read .gcno file BB_FILENAME and return a hash containing the following
-# mapping:
-#
-#   filename -> comma-separated list of pairs (function name=starting
-#               line number) to indicate the starting line of a function or
-#               =name to indicate an instrumented line
-#
-# for each entry in the .gcno file. Filenames are absolute, i.e. relative
-# filenames are prefixed with BASE_DIR.
-#
-# Die on error.
-#
-
-sub read_gcno_file($$)
-{
-	my $gcno_filename	= $_[0];
-	my $base_dir = $_[1];
-	my %result;
-	my $filename;
-	my $function_name;
-	my $lineno;
-	my $length;
-	my $value;
-	my $endianness;
-	my $blocks;
-	my $packed_word;
-	my $string;
-	local *INPUT;
-
-	open(INPUT, $gcno_filename)
-		or die("ERROR: cannot read $gcno_filename!\n");
-
-	binmode(INPUT);
-	
-	read(INPUT, $packed_word, 4) == 4
-		or die("ERROR: Invalid gcno file format\n");
-
-	$value = unpack_int32($packed_word, 0);
-	$endianness = !($value == $GCNO_FILE_MAGIC);
-
-	unpack_int32($packed_word, $endianness) == $GCNO_FILE_MAGIC
-		or die("ERROR: gcno file magic does not match\n");
-
-	seek(INPUT, 8, 1);
-
-	# Read data in words of 4 bytes
-	while (read(INPUT, $packed_word, 4) == 4)
-	{
-		# Decode integer in intel byteorder
-		$value = unpack_int32($packed_word, $endianness);
-
-		if ($value == $GCNO_FUNCTION_TAG)
-		{
-			# skip length, ident and checksum
-			seek(INPUT, 12, 1);
-			(undef, $function_name) =
-				read_gcno_string(*INPUT, $endianness);
-			$function_name =~ s/\W/_/g;
-			(undef, $filename) =
-				read_gcno_string(*INPUT, $endianness);
-			$filename = solve_relative_path($base_dir, $filename);
-
-			read(INPUT, $packed_word, 4);
-			$lineno = unpack_int32($packed_word, $endianness);
-
-			$result{$filename}.=
-			    ($result{$filename} ? "," : "").
-				join("=",($function_name,$lineno));
-		}
-		elsif ($value == $GCNO_LINES_TAG)
-		{
-			# Check for names of files containing inlined code
-			# included in this file
-			read(INPUT, $packed_word, 4);
-			$length = unpack_int32($packed_word, $endianness);
-			if ($length > 0)
-			{
-				# Block number
-				read(INPUT, $packed_word, 4);
-				$length--;
-			}
-			while ($length > 0)
-			{
-				read(INPUT, $packed_word, 4);
-				$lineno = unpack_int32($packed_word,
-						       $endianness);
-				$length--;
-				if ($lineno != 0)
-				{
-					if (defined($filename))
-					{
-						$result{$filename} .=
-							($result{$filename} ? "," : "").
-							"=$lineno";
-					}
-					else
-					{
-						warn("WARNING: unassigned line".
-						     " number in .gcno file ".
-						     "$gcno_filename\n");
-					}
-					next;
-				}
-				last if ($length == 0);
-				($blocks, $string) =
-					read_gcno_string(*INPUT, $endianness);
-				if (defined($string))
-				{
-					$filename = $string;
-				}
-				if ($blocks > 1)
-				{
-					$filename = solve_relative_path(
-							$base_dir, $filename);
-					if (!defined($result{$filename}))
-					{
-						$result{$filename} = "";
-					}
-				}
-				$length -= $blocks;
-			}
-		}
-		else
-		{
-			read(INPUT, $packed_word, 4);
-			$length = unpack_int32($packed_word, $endianness);
-			seek(INPUT, 4 * $length, 1);
-		}
-	}
-	close(INPUT);
-
-	if (!scalar(keys(%result)))
-	{
-		die("ERROR: no data found in $gcno_filename!\n");
-	}
-	return %result;
-}
-
-
-#
-# read_gcno_string(handle, endianness);
-#
-# Read a string in 4-byte chunks from HANDLE.
-#
-# Return (number of 4-byte chunks read, string).
-#
-
-sub read_gcno_string(*$)
-{
-	my $handle		= $_[0];
-	my $endianness		= $_[1];
-	my $number_of_blocks	= 0;
-	my $string		= "";
-	my $packed_word;
-
-	read($handle, $packed_word, 4) == 4
-		or die("ERROR: reading string\n");
-
-	$number_of_blocks = unpack_int32($packed_word, $endianness);
-
-	if ($number_of_blocks == 0)
-	{
-		return (1, undef);
-	}
-
-	if (read($handle, $packed_word, 4 * $number_of_blocks) !=
-	     4 * $number_of_blocks)
-	{
-		my $msg = "invalid string size ".(4 * $number_of_blocks)." in ".
-			  "gcno file at position ".tell($handle)."\n";
-		if ($ignore[$ERROR_SOURCE])
-		{
-			warn("WARNING: $msg");
-			return (1, undef);
-		}
-		else
-		{
-			die("ERROR: $msg");
-		}
-	}
-
-	$string = $string . $packed_word;
-
-	# Remove trailing nil bytes
-	$/="\0";
-	while (chomp($string)) {};
-	$/="\n";
-
-	return(1 + $number_of_blocks, $string);
-}
-
-
-#
-# read_hammer_bbg_file(bb_filename, base_dir)
-#
-# Read .bbg file BB_FILENAME and return a hash containing the following
-# mapping:
-#
-#   filename -> comma-separated list of pairs (function name=starting
-#               line number) to indicate the starting line of a function or
-#               =name to indicate an instrumented line
-#
-# for each entry in the .bbg file. Filenames are absolute, i.e. relative
-# filenames are prefixed with BASE_DIR.
-#
-# Die on error.
-#
-
-sub read_hammer_bbg_file($$)
-{
-	my $bbg_filename = $_[0];
-	my $base_dir = $_[1];
-	my %result;
-	my $filename;
-	my $function_name;
-	my $first_line;
-	my $lineno;
-	my $length;
-	my $value;
-	my $endianness;
-	my $blocks;
-	my $packed_word;
-	local *INPUT;
-
-	open(INPUT, $bbg_filename)
-		or die("ERROR: cannot read $bbg_filename!\n");
-
-	binmode(INPUT);
-	
-	# Read magic
-	read(INPUT, $packed_word, 4) == 4
-		or die("ERROR: invalid bbg file format\n");
-
-	$endianness = 1;
-
-	unpack_int32($packed_word, $endianness) == $BBG_FILE_MAGIC
-		or die("ERROR: bbg file magic does not match\n");
-
-	# Skip version
-	seek(INPUT, 4, 1);
-
-	# Read data in words of 4 bytes
-	while (read(INPUT, $packed_word, 4) == 4)
-	{
-		# Get record tag
-		$value = unpack_int32($packed_word, $endianness);
-
-		# Get record length
-		read(INPUT, $packed_word, 4);
-		$length = unpack_int32($packed_word, $endianness);
-
-		if ($value == $GCNO_FUNCTION_TAG)
-		{
-			# Get function name
-			($value, $function_name) =
-				read_hammer_bbg_string(*INPUT, $endianness);
-			$function_name =~ s/\W/_/g;
-			$filename = undef;
-			$first_line = undef;
-
-			seek(INPUT, $length - $value * 4, 1);
-		}
-		elsif ($value == $GCNO_LINES_TAG)
-		{
-			# Get linenumber and filename
-			# Skip block number
-			seek(INPUT, 4, 1);
-			$length -= 4;
-
-			while ($length > 0)
-			{
-				read(INPUT, $packed_word, 4);
-				$lineno = unpack_int32($packed_word,
-						       $endianness);
-				$length -= 4;
-				if ($lineno != 0)
-				{
-					if (!defined($first_line))
-					{
-						$first_line = $lineno;
-					}
-					if (defined($filename))
-					{
-						$result{$filename} .=
-							($result{$filename} ? "," : "").
-							"=$lineno";
-					}
-					else
-					{
-						warn("WARNING: unassigned line".
-						     " number in .bbg file ".
-						     "$bbg_filename\n");
-					}
-					next;
-				}
-				($blocks, $value) =
-					read_hammer_bbg_string(
-						*INPUT, $endianness);
-				# Add all filenames to result list
-				if (defined($value))
-				{
-					$value = solve_relative_path(
-							$base_dir, $value);
-					if (!defined($result{$value}))
-					{
-						$result{$value} = undef;
-					}
-					if (!defined($filename))
-					{
-						$filename = $value;
-					}
-				}
-				$length -= $blocks * 4;
-
-				# Got a complete data set?
-				if (defined($filename) &&
-				    defined($first_line) &&
-				    defined($function_name))
-				{
-					# Add it to our result hash
-					if (defined($result{$filename}))
-					{
-						$result{$filename} .=
-						",$function_name=$first_line";
-					}
-					else
-					{
-						$result{$filename} =
-						"$function_name=$first_line";
-					}
-					$function_name = undef;
-					$filename = undef;
-					$first_line = undef;
-				}
-			}
-		}
-		else
-		{
-			# Skip other records
-			seek(INPUT, $length, 1);
-		}
-	}
-	close(INPUT);
-
-	if (!scalar(keys(%result)))
-	{
-		die("ERROR: no data found in $bbg_filename!\n");
-	}
-	return %result;
-}
-
-
-#
-# read_hammer_bbg_string(handle, endianness);
-#
-# Read a string in 4-byte chunks from HANDLE.
-#
-# Return (number of 4-byte chunks read, string).
-#
-
-sub read_hammer_bbg_string(*$)
-{
-	my $handle		= $_[0];
-	my $endianness		= $_[1];
-	my $length		= 0;
-	my $string		= "";
-	my $packed_word;
-	my $pad;
-
-	read($handle, $packed_word, 4) == 4
-		or die("ERROR: reading string\n");
-
-	$length = unpack_int32($packed_word, $endianness);
-	$pad = 4 - $length % 4;
-
-	if ($length == 0)
-	{
-		return (1, undef);
-	}
-
-	read($handle, $string, $length) ==
-		$length or die("ERROR: reading string\n");
-	seek($handle, $pad, 1);
-
-	return(1 + ($length + $pad) / 4, $string);
-}
-
-#
-# unpack_int32(word, endianness)
-#
-# Interpret 4-byte binary string WORD as signed 32 bit integer in
-# endian encoding defined by ENDIANNESS (0=little, 1=big) and return its
-# value.
-#
-
-sub unpack_int32($$)
-{
-	return sprintf("%d", unpack($_[1] ? "N" : "V",$_[0]));
+	return(\@result, $branches, \@functions);
 }
 
 
@@ -1831,7 +1865,7 @@
 	my $version_string;
 	my $result;
 
-	open(GCOV_PIPE, "$gcov_tool -v |")
+	open(GCOV_PIPE, "-|", "$gcov_tool -v")
 		or die("ERROR: cannot retrieve gcov version!\n");
 	$version_string = <GCOV_PIPE>;
 	close(GCOV_PIPE);
@@ -1850,13 +1884,7 @@
 			$result = $1 << 16 | $2 << 8;
 		}
 	}
-        if ($version_string =~ /suse/i && $result == 0x30303 ||
-            $version_string =~ /mandrake/i && $result == 0x30302)
-	{
-		info("Using compatibility mode for GCC 3.3 (hammer)\n");
-		$compatibility = $COMPAT_HAMMER;
-	}
-	return $result;
+	return ($result, $version_string);
 }
 
 
@@ -1919,13 +1947,14 @@
 	local *OLD_STDOUT;
 
 	# Save old stdout and stderr handles
-	($mode & 1) && open(OLD_STDOUT, ">>&STDOUT");
-	($mode & 2) && open(OLD_STDERR, ">>&STDERR");
+	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
+	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
 
 	# Redirect to /dev/null
-	($mode & 1) && open(STDOUT, ">/dev/null");
-	($mode & 2) && open(STDERR, ">/dev/null");
+	($mode & 1) && open(STDOUT, ">", "/dev/null");
+	($mode & 2) && open(STDERR, ">", "/dev/null");
  
+	debug("system(".join(' ', @_).")\n");
 	system(@_);
 	$result = $?;
 
@@ -1934,8 +1963,8 @@
 	($mode & 2) && close(STDERR);
 
 	# Restore old handles
-	($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
-	($mode & 2) && open(STDERR, ">>&OLD_STDERR");
+	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
+	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
  
 	return $result;
 }
@@ -1956,7 +1985,7 @@
 	my $value;
 	local *HANDLE;
 
-	if (!open(HANDLE, "<$filename"))
+	if (!open(HANDLE, "<", $filename))
 	{
 		warn("WARNING: cannot read configuration file $filename\n");
 		return undef;
@@ -1995,8 +2024,8 @@
 #   key_string => var_ref
 #
 # where KEY_STRING is a keyword and VAR_REF is a reference to an associated
-# variable. If the global configuration hash CONFIG contains a value for
-# keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
+# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
+# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
 #
 
 sub apply_config($)
@@ -2005,51 +2034,175 @@
 
 	foreach (keys(%{$ref}))
 	{
-		if (defined($config->{$_}))
-		{
+		if (defined($opt_rc{$_})) {
+			${$ref->{$_}} = $opt_rc{$_};
+		} elsif (defined($config->{$_})) {
 			${$ref->{$_}} = $config->{$_};
 		}
 	}
 }
 
 
-sub gen_initial_info($)
+#
+# get_exclusion_data(filename)
+#
+# Scan specified source code file for exclusion markers and return
+#   linenumber -> 1
+# for all lines which should be excluded.
+#
+
+sub get_exclusion_data($)
 {
-	my $directory = $_[0];
-	my @file_list;
+	my ($filename) = @_;
+	my %list;
+	my $flag = 0;
+	local *HANDLE;
 
-	if (-d $directory)
-	{
-		info("Scanning $directory for $graph_file_extension ".
-		     "files ...\n");	
-
-		@file_list = `find "$directory" $maxdepth $follow -name \\*$graph_file_extension -type f 2>/dev/null`;
-		chomp(@file_list);
-		@file_list or die("ERROR: no $graph_file_extension files ".
-				  "found in $directory!\n");
-		info("Found %d graph files in %s\n", $#file_list+1, $directory);
+	if (!open(HANDLE, "<", $filename)) {
+		warn("WARNING: could not open $filename\n");
+		return undef;
 	}
-	else
-	{
-		@file_list = ($directory);
+	while (<HANDLE>) {
+		if (/$EXCL_STOP/) {
+			$flag = 0;
+		} elsif (/$EXCL_START/) {
+			$flag = 1;
+		}
+		if (/$EXCL_LINE/ || $flag) {
+			$list{$.} = 1;
+		}
+	}
+	close(HANDLE);
+
+	if ($flag) {
+		warn("WARNING: unterminated exclusion section in $filename\n");
 	}
 
-	# Process all files in list
-	foreach (@file_list) { process_graphfile($_); }
+	return \%list;
 }
 
-sub process_graphfile($)
+
+#
+# apply_exclusion_data(instr, graph)
+#
+# Remove lines from instr and graph data structures which are marked
+# for exclusion in the source code file.
+#
+# Return adjusted (instr, graph).
+#
+# graph         : file name -> function data
+# function data : function name -> line data
+# line data     : [ line1, line2, ... ]
+#
+# instr     : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+
+sub apply_exclusion_data($$)
 {
-	my $graph_filename = $_[0];
+	my ($instr, $graph) = @_;
+	my $filename;
+	my %excl_data;
+	my $excl_read_failed = 0;
+
+	# Collect exclusion marker data
+	foreach $filename (sort_uniq_lex(keys(%{$graph}), keys(%{$instr}))) {
+		my $excl = get_exclusion_data($filename);
+
+		# Skip and note if file could not be read
+		if (!defined($excl)) {
+			$excl_read_failed = 1;
+			next;
+		}
+
+		# Add to collection if there are markers
+		$excl_data{$filename} = $excl if (keys(%{$excl}) > 0);
+	}
+
+	# Warn if not all source files could be read
+	if ($excl_read_failed) {
+		warn("WARNING: some exclusion markers may be ignored\n");
+	}
+
+	# Skip if no markers were found
+	return ($instr, $graph) if (keys(%excl_data) == 0);
+
+	# Apply exclusion marker data to graph
+	foreach $filename (keys(%excl_data)) {
+		my $function_data = $graph->{$filename};
+		my $excl = $excl_data{$filename};
+		my $function;
+
+		next if (!defined($function_data));
+
+		foreach $function (keys(%{$function_data})) {
+			my $line_data = $function_data->{$function};
+			my $line;
+			my @new_data;
+
+			# To be consistent with exclusion parser in non-initial
+			# case we need to remove a function if the first line
+			# was excluded
+			if ($excl->{$line_data->[0]}) {
+				delete($function_data->{$function});
+				next;
+			}
+			# Copy only lines which are not excluded
+			foreach $line (@{$line_data}) {
+				push(@new_data, $line) if (!$excl->{$line});
+			}
+
+			# Store modified list
+			if (scalar(@new_data) > 0) {
+				$function_data->{$function} = \@new_data;
+			} else {
+				# All of this function was excluded
+				delete($function_data->{$function});
+			}
+		}
+
+		# Check if all functions of this file were excluded
+		if (keys(%{$function_data}) == 0) {
+			delete($graph->{$filename});
+		}
+	}
+
+	# Apply exclusion marker data to instr
+	foreach $filename (keys(%excl_data)) {
+		my $line_data = $instr->{$filename};
+		my $excl = $excl_data{$filename};
+		my $line;
+		my @new_data;
+
+		next if (!defined($line_data));
+
+		# Copy only lines which are not excluded
+		foreach $line (@{$line_data}) {
+			push(@new_data, $line) if (!$excl->{$line});
+		}
+
+		# Store modified list
+		$instr->{$filename} = \@new_data;
+	}
+
+	return ($instr, $graph);
+}
+
+
+sub process_graphfile($$)
+{
+	my ($file, $dir) = @_;
+	my $graph_filename = $file;
 	my $graph_dir;
 	my $graph_basename;
 	my $source_dir;
 	my $base_dir;
-	my %graph_data;
+	my $graph;
+	my $instr;
 	my $filename;
 	local *INFO_HANDLE;
 
-	info("Processing $_[0]\n");
+	info("Processing %s\n", abs2rel($file, $dir));
 
 	# Get path to data file in absolute and normalized form (begins with /,
 	# contains no more ../ or ./)
@@ -2058,11 +2211,10 @@
 	# Get directory and basename of data file
 	($graph_dir, $graph_basename) = split_filename($graph_filename);
 
-	# avoid files from .libs dirs 	 
-	if ($compat_libtool && $graph_dir =~ m/(.*)\/\.libs$/) {
-		$source_dir = $1;
-	} else {
-		$source_dir = $graph_dir;
+	$source_dir = $graph_dir;
+	if (is_compat($COMPAT_MODE_LIBTOOL)) {
+		# Avoid files from .libs dirs 	 
+		$source_dir =~ s/\.libs$//;
 	}
 
 	# Construct base_dir for current file
@@ -2077,19 +2229,30 @@
 
 	if ($gcov_version < $GCOV_VERSION_3_4_0)
 	{
-		if (defined($compatibility) && $compatibility eq $COMPAT_HAMMER)
+		if (is_compat($COMPAT_MODE_HAMMER))
 		{
-			%graph_data = read_hammer_bbg_file($graph_filename,
-							   $base_dir);
+			($instr, $graph) = read_bbg($graph_filename);
 		}
 		else
 		{
-			%graph_data = read_bb_file($graph_filename, $base_dir);
+			($instr, $graph) = read_bb($graph_filename);
 		}
 	} 
 	else
 	{
-		%graph_data = read_gcno_file($graph_filename, $base_dir);
+		($instr, $graph) = read_gcno($graph_filename);
+	}
+
+	# Try to find base directory automatically if requested by user
+	if ($rc_auto_base) {
+		$base_dir = find_base_from_graph($base_dir, $instr, $graph);
+	}
+
+	($instr, $graph) = adjust_graph_filenames($base_dir, $instr, $graph);
+
+	if (!$no_markers) {
+		# Apply exclusion marker data to graph file data
+		($instr, $graph) = apply_exclusion_data($instr, $graph);
 	}
 
 	# Check whether we're writing to a single file
@@ -2102,7 +2265,7 @@
 		else
 		{
 			# Append to output file
-			open(INFO_HANDLE, ">>$output_filename")
+			open(INFO_HANDLE, ">>", $output_filename)
 				or die("ERROR: cannot write to ".
 				       "$output_filename!\n");
 		}
@@ -2110,51 +2273,51 @@
 	else
 	{
 		# Open .info file for output
-		open(INFO_HANDLE, ">$graph_filename.info")
+		open(INFO_HANDLE, ">", "$graph_filename.info")
 			or die("ERROR: cannot create $graph_filename.info!\n");
 	}
 
 	# Write test name
 	printf(INFO_HANDLE "TN:%s\n", $test_name);
-	foreach $filename (keys(%graph_data))
+	foreach $filename (sort(keys(%{$instr})))
 	{
-		my %lines;
-		my $count = 0;
-		my @functions;
+		my $funcdata = $graph->{$filename};
+		my $line;
+		my $linedata;
 
 		print(INFO_HANDLE "SF:$filename\n");
 
-		# Write function related data
-		foreach (split(",",$graph_data{$filename}))
-		{
-			my ($fn, $line) = split("=", $_);
+		if (defined($funcdata) && $func_coverage) {
+			my @functions = sort {$funcdata->{$a}->[0] <=>
+					      $funcdata->{$b}->[0]}
+					     keys(%{$funcdata});
+			my $func;
 
-			if ($fn eq "")
-			{
-				$lines{$line} = "";
-				next;
+			# Gather list of instrumented lines and functions
+			foreach $func (@functions) {
+				$linedata = $funcdata->{$func};
+
+				# Print function name and starting line
+				print(INFO_HANDLE "FN:".$linedata->[0].
+				      ",".filter_fn_name($func)."\n");
 			}
-
-			# Normalize function name
-			$fn =~ s/\W/_/g;
-
-			print(INFO_HANDLE "FN:$line,$fn\n");
-			push(@functions, $fn);
+			# Print zero function coverage data
+			foreach $func (@functions) {
+				print(INFO_HANDLE "FNDA:0,".
+				      filter_fn_name($func)."\n");
+			}
+			# Print function summary
+			print(INFO_HANDLE "FNF:".scalar(@functions)."\n");
+			print(INFO_HANDLE "FNH:0\n");
 		}
-		foreach (@functions) {
-			print(INFO_HANDLE "FNDA:$_,0\n");
+		# Print zero line coverage data
+		foreach $line (@{$instr->{$filename}}) {
+			print(INFO_HANDLE "DA:$line,0\n");
 		}
-		print(INFO_HANDLE "FNF:".scalar(@functions)."\n");
-		print(INFO_HANDLE "FNH:0\n");
-
-		# Write line related data
-		foreach (sort {$a <=> $b } keys(%lines))
-		{
-			print(INFO_HANDLE "DA:$_,0\n");
-			$count++;
-		}
+		# Print line summary
+		print(INFO_HANDLE "LF:".scalar(@{$instr->{$filename}})."\n");
 		print(INFO_HANDLE "LH:0\n");
-		print(INFO_HANDLE "LF:$count\n");
+
 		print(INFO_HANDLE "end_of_record\n");
 	}
 	if (!($output_filename && ($output_filename eq "-")))
@@ -2163,6 +2326,16 @@
 	}
 }
 
+sub filter_fn_name($)
+{
+	my ($fn) = @_;
+
+	# Remove characters used internally as function name delimiters
+	$fn =~ s/[,=]/_/g;
+
+	return $fn;
+}
+
 sub warn_handler($)
 {
 	my ($msg) = @_;
@@ -2176,3 +2349,1309 @@
 
 	die("$tool_name: $msg");
 }
+
+
+#
+# graph_error(filename, message)
+#
+# Print message about error in graph file. If ignore_graph_error is set, return.
+# Otherwise abort.
+#
+
+sub graph_error($$)
+{
+	my ($filename, $msg) = @_;
+
+	if ($ignore[$ERROR_GRAPH]) {
+		warn("WARNING: $filename: $msg - skipping\n");
+		return;
+	}
+	die("ERROR: $filename: $msg\n");
+}
+
+#
+# graph_expect(description)
+#
+# If debug is set to a non-zero value, print the specified description of what
+# is expected to be read next from the graph file.
+#
+
+sub graph_expect($)
+{
+	my ($msg) = @_;
+
+	if (!$debug || !defined($msg)) {
+		return;
+	}
+
+	print(STDERR "DEBUG: expecting $msg\n");
+}
+
+#
+# graph_read(handle, bytes[, description, peek])
+#
+# Read and return the specified number of bytes from handle. Return undef
+# if the number of bytes could not be read. If PEEK is non-zero, reset
+# file position after read.
+#
+
+sub graph_read(*$;$$)
+{
+	my ($handle, $length, $desc, $peek) = @_;
+	my $data;
+	my $result;
+	my $pos;
+
+	graph_expect($desc);
+	if ($peek) {
+		$pos = tell($handle);
+		if ($pos == -1) {
+			warn("Could not get current file position: $!\n");
+			return undef;
+		}
+	}
+	$result = read($handle, $data, $length);
+	if ($debug) {
+		my $op = $peek ? "peek" : "read";
+		my $ascii = "";
+		my $hex = "";
+		my $i;
+
+		print(STDERR "DEBUG: $op($length)=$result: ");
+		for ($i = 0; $i < length($data); $i++) {
+			my $c = substr($data, $i, 1);;
+			my $n = ord($c);
+
+			$hex .= sprintf("%02x ", $n);
+			if ($n >= 32 && $n <= 127) {
+				$ascii .= $c;
+			} else {
+				$ascii .= ".";
+			}
+		}
+		print(STDERR "$hex |$ascii|");
+		print(STDERR "\n");
+	}
+	if ($peek) {
+		if (!seek($handle, $pos, 0)) {
+			warn("Could not set file position: $!\n");
+			return undef;
+		}
+	}
+	if ($result != $length) {
+		return undef;
+	}
+	return $data;
+}
+
+#
+# graph_skip(handle, bytes[, description])
+#
+# Read and discard the specified number of bytes from handle. Return non-zero
+# if bytes could be read, zero otherwise.
+#
+
+sub graph_skip(*$;$)
+{
+	my ($handle, $length, $desc) = @_;
+
+	if (defined(graph_read($handle, $length, $desc))) {
+		return 1;
+	}
+	return 0;
+}
+
+#
+# sort_uniq(list)
+#
+# Return list in numerically ascending order and without duplicate entries.
+#
+
+sub sort_uniq(@)
+{
+	my (@list) = @_;
+	my %hash;
+
+	foreach (@list) {
+		$hash{$_} = 1;
+	}
+	return sort { $a <=> $b } keys(%hash);
+}
+
+#
+# sort_uniq_lex(list)
+#
+# Return list in lexically ascending order and without duplicate entries.
+#
+
+sub sort_uniq_lex(@)
+{
+	my (@list) = @_;
+	my %hash;
+
+	foreach (@list) {
+		$hash{$_} = 1;
+	}
+	return sort keys(%hash);
+}
+
+#
+# parent_dir(dir)
+#
+# Return parent directory for DIR. DIR must not contain relative path
+# components.
+#
+
+sub parent_dir($)
+{
+	my ($dir) = @_;
+	my ($v, $d, $f) = splitpath($dir, 1);
+	my @dirs = splitdir($d);
+
+	pop(@dirs);
+
+	return catpath($v, catdir(@dirs), $f);
+}
+
+#
+# find_base_from_graph(base_dir, instr, graph)
+#
+# Try to determine the base directory of the graph file specified by INSTR
+# and GRAPH. The base directory is the base for all relative filenames in
+# the graph file. It is defined by the current working directory at time
+# of compiling the source file.
+#
+# This function implements a heuristic which relies on the following
+# assumptions:
+# - all files used for compilation are still present at their location
+# - the base directory is either BASE_DIR or one of its parent directories
+# - files by the same name are not present in multiple parent directories
+#
+
+sub find_base_from_graph($$$)
+{
+	my ($base_dir, $instr, $graph) = @_;
+	my $old_base;
+	my $best_miss;
+	my $best_base;
+	my %rel_files;
+
+	# Determine list of relative paths
+	foreach my $filename (keys(%{$instr}), keys(%{$graph})) {
+		next if (file_name_is_absolute($filename));
+
+		$rel_files{$filename} = 1;
+	}
+
+	# Early exit if there are no relative paths
+	return $base_dir if (!%rel_files);
+
+	do {
+		my $miss = 0;
+
+		foreach my $filename (keys(%rel_files)) {
+			if (!-e solve_relative_path($base_dir, $filename)) {
+				$miss++;
+			}
+		}
+
+		debug("base_dir=$base_dir miss=$miss\n");
+
+		# Exit if we find an exact match with no misses
+		return $base_dir if ($miss == 0);
+
+		# No exact match, aim for the one with the least source file
+		# misses
+		if (!defined($best_base) || $miss < $best_miss) {
+			$best_base = $base_dir;
+			$best_miss = $miss;
+		}
+
+		# Repeat until there's no more parent directory
+		$old_base = $base_dir;
+		$base_dir = parent_dir($base_dir);
+	} while ($old_base ne $base_dir);
+
+	return $best_base;
+}
+
+#
+# adjust_graph_filenames(base_dir, instr, graph)
+#
+# Make relative paths in INSTR and GRAPH absolute and apply
+# geninfo_adjust_src_path setting to graph file data.
+#
+
+sub adjust_graph_filenames($$$)
+{
+	my ($base_dir, $instr, $graph) = @_;
+
+	foreach my $filename (keys(%{$instr})) {
+		my $old_filename = $filename;
+
+		# Convert to absolute canonical form
+		$filename = solve_relative_path($base_dir, $filename);
+
+		# Apply adjustment
+		if (defined($adjust_src_pattern)) {
+			$filename =~ s/$adjust_src_pattern/$adjust_src_replace/g;
+		}
+
+		if ($filename ne $old_filename) {
+			$instr->{$filename} = delete($instr->{$old_filename});
+		}
+	}
+
+	foreach my $filename (keys(%{$graph})) {
+		my $old_filename = $filename;
+
+		# Make absolute
+		# Convert to absolute canonical form
+		$filename = solve_relative_path($base_dir, $filename);
+
+		# Apply adjustment
+		if (defined($adjust_src_pattern)) {
+			$filename =~ s/$adjust_src_pattern/$adjust_src_replace/g;
+		}
+
+		if ($filename ne $old_filename) {
+			$graph->{$filename} = delete($graph->{$old_filename});
+		}
+	}
+
+	return ($instr, $graph);
+}
+
+#
+# graph_cleanup(graph)
+#
+# Remove entries for functions with no lines. Remove duplicate line numbers.
+# Sort list of line numbers numerically ascending.
+#
+
+sub graph_cleanup($)
+{
+	my ($graph) = @_;
+	my $filename;
+
+	foreach $filename (keys(%{$graph})) {
+		my $per_file = $graph->{$filename};
+		my $function;
+
+		foreach $function (keys(%{$per_file})) {
+			my $lines = $per_file->{$function};
+
+			if (scalar(@$lines) == 0) {
+				# Remove empty function
+				delete($per_file->{$function});
+				next;
+			}
+			# Normalize list
+			$per_file->{$function} = [ sort_uniq(@$lines) ];
+		}
+		if (scalar(keys(%{$per_file})) == 0) {
+			# Remove empty file
+			delete($graph->{$filename});
+		}
+	}
+}
+
+#
+# graph_find_base(bb)
+#
+# Try to identify the filename which is the base source file for the
+# specified bb data.
+#
+
+sub graph_find_base($)
+{
+	my ($bb) = @_;
+	my %file_count;
+	my $basefile;
+	my $file;
+	my $func;
+	my $filedata;
+	my $count;
+	my $num;
+
+	# Identify base name for this bb data.
+	foreach $func (keys(%{$bb})) {
+		$filedata = $bb->{$func};
+
+		foreach $file (keys(%{$filedata})) {
+			$count = $file_count{$file};
+
+			# Count file occurrence
+			$file_count{$file} = defined($count) ? $count + 1 : 1;
+		}
+	}
+	$count = 0;
+	$num = 0;
+	foreach $file (keys(%file_count)) {
+		if ($file_count{$file} > $count) {
+			# The file that contains code for the most functions
+			# is likely the base file
+			$count = $file_count{$file};
+			$num = 1;
+			$basefile = $file;
+		} elsif ($file_count{$file} == $count) {
+			# If more than one file could be the basefile, we
+			# don't have a basefile
+			$basefile = undef;
+		}
+	}
+
+	return $basefile;
+}
+
+#
+# graph_from_bb(bb, fileorder, bb_filename)
+#
+# Convert data from bb to the graph format and list of instrumented lines.
+# Returns (instr, graph).
+#
+# bb         : function name -> file data
+#            : undef -> file order
+# file data  : filename -> line data
+# line data  : [ line1, line2, ... ]
+#
+# file order : function name -> [ filename1, filename2, ... ]
+#
+# graph         : file name -> function data
+# function data : function name -> line data
+# line data     : [ line1, line2, ... ]
+#
+# instr     : filename -> line data
+# line data : [ line1, line2, ... ]
+#
+
+sub graph_from_bb($$$)
+{
+	my ($bb, $fileorder, $bb_filename) = @_;
+	my $graph = {};
+	my $instr = {};
+	my $basefile;
+	my $file;
+	my $func;
+	my $filedata;
+	my $linedata;
+	my $order;
+
+	$basefile = graph_find_base($bb);
+	# Create graph structure
+	foreach $func (keys(%{$bb})) {
+		$filedata = $bb->{$func};
+		$order = $fileorder->{$func};
+
+		# Account for lines in functions
+		if (defined($basefile) && defined($filedata->{$basefile})) {
+			# If the basefile contributes to this function,
+			# account this function to the basefile.
+			$graph->{$basefile}->{$func} = $filedata->{$basefile};
+		} else {
+			# If the basefile does not contribute to this function,
+			# account this function to the first file contributing
+			# lines.
+			$graph->{$order->[0]}->{$func} =
+				$filedata->{$order->[0]};
+		}
+
+		foreach $file (keys(%{$filedata})) {
+			# Account for instrumented lines
+			$linedata = $filedata->{$file};
+			push(@{$instr->{$file}}, @$linedata);
+		}
+	}
+	# Clean up array of instrumented lines
+	foreach $file (keys(%{$instr})) {
+		$instr->{$file} = [ sort_uniq(@{$instr->{$file}}) ];
+	}
+
+	return ($instr, $graph);
+}
+
+#
+# graph_add_order(fileorder, function, filename)
+#
+# Add an entry for filename to the fileorder data set for function.
+#
+
+sub graph_add_order($$$)
+{
+	my ($fileorder, $function, $filename) = @_;
+	my $item;
+	my $list;
+
+	$list = $fileorder->{$function};
+	foreach $item (@$list) {
+		if ($item eq $filename) {
+			return;
+		}
+	}
+	push(@$list, $filename);
+	$fileorder->{$function} = $list;
+}
+
+#
+# read_bb_word(handle[, description])
+#
+# Read and return a word in .bb format from handle.
+#
+
+sub read_bb_word(*;$)
+{
+	my ($handle, $desc) = @_;
+
+	return graph_read($handle, 4, $desc);
+}
+
+#
+# read_bb_value(handle[, description])
+#
+# Read a word in .bb format from handle and return the word and its integer
+# value.
+#
+
+sub read_bb_value(*;$)
+{
+	my ($handle, $desc) = @_;
+	my $word;
+
+	$word = read_bb_word($handle, $desc);
+	return undef if (!defined($word));
+
+	return ($word, unpack("V", $word));
+}
+
+#
+# read_bb_string(handle, delimiter)
+#
+# Read and return a string in .bb format from handle up to the specified
+# delimiter value.
+#
+
+sub read_bb_string(*$)
+{
+	my ($handle, $delimiter) = @_;
+	my $word;
+	my $value;
+	my $string = "";
+
+	graph_expect("string");
+	do {
+		($word, $value) = read_bb_value($handle, "string or delimiter");
+		return undef if (!defined($value));
+		if ($value != $delimiter) {
+			$string .= $word;
+		}
+	} while ($value != $delimiter);
+	$string =~ s/\0//g;
+
+	return $string;
+}
+
+#
+# read_bb(filename)
+#
+# Read the contents of the specified .bb file and return (instr, graph), where:
+#
+#   instr     : filename -> line data
+#   line data : [ line1, line2, ... ]
+#
+#   graph     :     filename -> file_data
+#   file_data : function name -> line_data
+#   line_data : [ line1, line2, ... ]
+#
+# See the gcov info pages of gcc 2.95 for a description of the .bb file format.
+#
+
+sub read_bb($)
+{
+	my ($bb_filename) = @_;
+	my $minus_one = 0x80000001;
+	my $minus_two = 0x80000002;
+	my $value;
+	my $filename;
+	my $function;
+	my $bb = {};
+	my $fileorder = {};
+	my $instr;
+	my $graph;
+	local *HANDLE;
+
+	open(HANDLE, "<", $bb_filename) or goto open_error;
+	binmode(HANDLE);
+	while (!eof(HANDLE)) {
+		$value = read_bb_value(*HANDLE, "data word");
+		goto incomplete if (!defined($value));
+		if ($value == $minus_one) {
+			# Source file name
+			graph_expect("filename");
+			$filename = read_bb_string(*HANDLE, $minus_one);
+			goto incomplete if (!defined($filename));
+		} elsif ($value == $minus_two) {
+			# Function name
+			graph_expect("function name");
+			$function = read_bb_string(*HANDLE, $minus_two);
+			goto incomplete if (!defined($function));
+		} elsif ($value > 0) {
+			# Line number
+			if (!defined($filename) || !defined($function)) {
+				warn("WARNING: unassigned line number ".
+				     "$value\n");
+				next;
+			}
+			push(@{$bb->{$function}->{$filename}}, $value);
+			graph_add_order($fileorder, $function, $filename);
+		}
+	}
+	close(HANDLE);
+	($instr, $graph) = graph_from_bb($bb, $fileorder, $bb_filename);
+	graph_cleanup($graph);
+
+	return ($instr, $graph);
+
+open_error:
+	graph_error($bb_filename, "could not open file");
+	return undef;
+incomplete:
+	graph_error($bb_filename, "reached unexpected end of file");
+	return undef;
+}
+
+#
+# read_bbg_word(handle[, description])
+#
+# Read and return a word in .bbg format.
+#
+
+sub read_bbg_word(*;$)
+{
+	my ($handle, $desc) = @_;
+
+	return graph_read($handle, 4, $desc);
+}
+
+#
+# read_bbg_value(handle[, description])
+#
+# Read a word in .bbg format from handle and return its integer value.
+#
+
+sub read_bbg_value(*;$)
+{
+	my ($handle, $desc) = @_;
+	my $word;
+
+	$word = read_bbg_word($handle, $desc);
+	return undef if (!defined($word));
+
+	return unpack("N", $word);
+}
+
+#
+# read_bbg_string(handle)
+#
+# Read and return a string in .bbg format.
+#
+
+sub read_bbg_string(*)
+{
+	my ($handle, $desc) = @_;
+	my $length;
+	my $string;
+
+	graph_expect("string");
+	# Read string length
+	$length = read_bbg_value($handle, "string length");
+	return undef if (!defined($length));
+	if ($length == 0) {
+		return "";
+	}
+	# Read string
+	$string = graph_read($handle, $length, "string");
+	return undef if (!defined($string));
+	# Skip padding
+	graph_skip($handle, 4 - $length % 4, "string padding") or return undef;
+
+	return $string;
+}
+
+#
+# read_bbg_lines_record(handle, bbg_filename, bb, fileorder, filename,
+#                       function)
+#
+# Read a bbg format lines record from handle and add the relevant data to
+# bb and fileorder. Return filename on success, undef on error.
+#
+
+sub read_bbg_lines_record(*$$$$$)
+{
+	my ($handle, $bbg_filename, $bb, $fileorder, $filename, $function) = @_;
+	my $string;
+	my $lineno;
+
+	graph_expect("lines record");
+	# Skip basic block index
+	graph_skip($handle, 4, "basic block index") or return undef;
+	while (1) {
+		# Read line number
+		$lineno = read_bbg_value($handle, "line number");
+		return undef if (!defined($lineno));
+		if ($lineno == 0) {
+			# Got a marker for a new filename
+			graph_expect("filename");
+			$string = read_bbg_string($handle);
+			return undef if (!defined($string));
+			# Check for end of record
+			if ($string eq "") {
+				return $filename;
+			}
+			$filename = $string;
+			if (!exists($bb->{$function}->{$filename})) {
+				$bb->{$function}->{$filename} = [];
+			}
+			next;
+		}
+		# Got an actual line number
+		if (!defined($filename)) {
+			warn("WARNING: unassigned line number in ".
+			     "$bbg_filename\n");
+			next;
+		}
+		push(@{$bb->{$function}->{$filename}}, $lineno);
+		graph_add_order($fileorder, $function, $filename);
+	}
+}
+
+#
+# read_bbg(filename)
+#
+# Read the contents of the specified .bbg file and return the following mapping:
+#   graph:     filename -> file_data
+#   file_data: function name -> line_data
+#   line_data: [ line1, line2, ... ]
+#
+# See the gcov-io.h file in the SLES 9 gcc 3.3.3 source code for a description
+# of the .bbg format.
+#
+
+sub read_bbg($)
+{
+	my ($bbg_filename) = @_;
+	my $file_magic = 0x67626267;
+	my $tag_function = 0x01000000;
+	my $tag_lines = 0x01450000;
+	my $word;
+	my $tag;
+	my $length;
+	my $function;
+	my $filename;
+	my $bb = {};
+	my $fileorder = {};
+	my $instr;
+	my $graph;
+	local *HANDLE;
+
+	open(HANDLE, "<", $bbg_filename) or goto open_error;
+	binmode(HANDLE);
+	# Read magic
+	$word = read_bbg_value(*HANDLE, "file magic");
+	goto incomplete if (!defined($word));
+	# Check magic
+	if ($word != $file_magic) {
+		goto magic_error;
+	}
+	# Skip version
+	graph_skip(*HANDLE, 4, "version") or goto incomplete;
+	while (!eof(HANDLE)) {
+		# Read record tag
+		$tag = read_bbg_value(*HANDLE, "record tag");
+		goto incomplete if (!defined($tag));
+		# Read record length
+		$length = read_bbg_value(*HANDLE, "record length");
+		goto incomplete if (!defined($tag));
+		if ($tag == $tag_function) {
+			graph_expect("function record");
+			# Read function name
+			graph_expect("function name");
+			$function = read_bbg_string(*HANDLE);
+			goto incomplete if (!defined($function));
+			$filename = undef;
+			# Skip function checksum
+			graph_skip(*HANDLE, 4, "function checksum")
+				or goto incomplete;
+		} elsif ($tag == $tag_lines) {
+			# Read lines record
+			$filename = read_bbg_lines_record(HANDLE, $bbg_filename,
+					  $bb, $fileorder, $filename,
+					  $function);
+			goto incomplete if (!defined($filename));
+		} else {
+			# Skip record contents
+			graph_skip(*HANDLE, $length, "unhandled record")
+				or goto incomplete;
+		}
+	}
+	close(HANDLE);
+	($instr, $graph) = graph_from_bb($bb, $fileorder, $bbg_filename);
+	graph_cleanup($graph);
+
+	return ($instr, $graph);
+
+open_error:
+	graph_error($bbg_filename, "could not open file");
+	return undef;
+incomplete:
+	graph_error($bbg_filename, "reached unexpected end of file");
+	return undef;
+magic_error:
+	graph_error($bbg_filename, "found unrecognized bbg file magic");
+	return undef;
+}
+
+#
+# read_gcno_word(handle[, description, peek])
+#
+# Read and return a word in .gcno format.
+#
+
+sub read_gcno_word(*;$$)
+{
+	my ($handle, $desc, $peek) = @_;
+
+	return graph_read($handle, 4, $desc, $peek);
+}
+
+#
+# read_gcno_value(handle, big_endian[, description, peek])
+#
+# Read a word in .gcno format from handle and return its integer value
+# according to the specified endianness. If PEEK is non-zero, reset file
+# position after read.
+#
+
+sub read_gcno_value(*$;$$)
+{
+	my ($handle, $big_endian, $desc, $peek) = @_;
+	my $word;
+	my $pos;
+
+	$word = read_gcno_word($handle, $desc, $peek);
+	return undef if (!defined($word));
+	if ($big_endian) {
+		return unpack("N", $word);
+	} else {
+		return unpack("V", $word);
+	}
+}
+
+#
+# read_gcno_string(handle, big_endian)
+#
+# Read and return a string in .gcno format.
+#
+
+sub read_gcno_string(*$)
+{
+	my ($handle, $big_endian) = @_;
+	my $length;
+	my $string;
+
+	graph_expect("string");
+	# Read string length
+	$length = read_gcno_value($handle, $big_endian, "string length");
+	return undef if (!defined($length));
+	if ($length == 0) {
+		return "";
+	}
+	$length *= 4;
+	# Read string
+	$string = graph_read($handle, $length, "string and padding");
+	return undef if (!defined($string));
+	$string =~ s/\0//g;
+
+	return $string;
+}
+
+#
+# read_gcno_lines_record(handle, gcno_filename, bb, fileorder, filename,
+#                        function, big_endian)
+#
+# Read a gcno format lines record from handle and add the relevant data to
+# bb and fileorder. Return filename on success, undef on error.
+#
+
+sub read_gcno_lines_record(*$$$$$$)
+{
+	my ($handle, $gcno_filename, $bb, $fileorder, $filename, $function,
+	    $big_endian) = @_;
+	my $string;
+	my $lineno;
+
+	graph_expect("lines record");
+	# Skip basic block index
+	graph_skip($handle, 4, "basic block index") or return undef;
+	while (1) {
+		# Read line number
+		$lineno = read_gcno_value($handle, $big_endian, "line number");
+		return undef if (!defined($lineno));
+		if ($lineno == 0) {
+			# Got a marker for a new filename
+			graph_expect("filename");
+			$string = read_gcno_string($handle, $big_endian);
+			return undef if (!defined($string));
+			# Check for end of record
+			if ($string eq "") {
+				return $filename;
+			}
+			$filename = $string;
+			if (!exists($bb->{$function}->{$filename})) {
+				$bb->{$function}->{$filename} = [];
+			}
+			next;
+		}
+		# Got an actual line number
+		if (!defined($filename)) {
+			warn("WARNING: unassigned line number in ".
+			     "$gcno_filename\n");
+			next;
+		}
+		# Add to list
+		push(@{$bb->{$function}->{$filename}}, $lineno);
+		graph_add_order($fileorder, $function, $filename);
+	}
+}
+
+#
+# determine_gcno_split_crc(handle, big_endian, rec_length)
+#
+# Determine if HANDLE refers to a .gcno file with a split checksum function
+# record format. Return non-zero in case of split checksum format, zero
+# otherwise, undef in case of read error.
+#
+
+sub determine_gcno_split_crc($$$)
+{
+	my ($handle, $big_endian, $rec_length) = @_;
+	my $strlen;
+	my $overlong_string;
+
+	return 1 if ($gcov_version >= $GCOV_VERSION_4_7_0);
+	return 1 if (is_compat($COMPAT_MODE_SPLIT_CRC));
+
+	# Heuristic:
+	# Decide format based on contents of next word in record:
+	# - pre-gcc 4.7
+	#   This is the function name length / 4 which should be
+	#   less than the remaining record length
+	# - gcc 4.7
+	#   This is a checksum, likely with high-order bits set,
+	#   resulting in a large number
+	$strlen = read_gcno_value($handle, $big_endian, undef, 1);
+	return undef if (!defined($strlen));
+	$overlong_string = 1 if ($strlen * 4 >= $rec_length - 12);
+
+	if ($overlong_string) {
+		if (is_compat_auto($COMPAT_MODE_SPLIT_CRC)) {
+			info("Auto-detected compatibility mode for split ".
+			     "checksum .gcno file format\n");
+
+			return 1;
+		} else {
+			# Sanity check
+			warn("Found overlong string in function record: ".
+			     "try '--compat split_crc'\n");
+		}
+	}
+
+	return 0;
+}
+
+#
+# read_gcno_function_record(handle, graph, big_endian, rec_length)
+#
+# Read a gcno format function record from handle and add the relevant data
+# to graph. Return (filename, function) on success, undef on error. 
+#
+
+sub read_gcno_function_record(*$$$$)
+{
+	my ($handle, $bb, $fileorder, $big_endian, $rec_length) = @_;
+	my $filename;
+	my $function;
+	my $lineno;
+	my $lines;
+
+	graph_expect("function record");
+	# Skip ident and checksum
+	graph_skip($handle, 8, "function ident and checksum") or return undef;
+	# Determine if this is a function record with split checksums
+	if (!defined($gcno_split_crc)) {
+		$gcno_split_crc = determine_gcno_split_crc($handle, $big_endian,
+							   $rec_length);
+		return undef if (!defined($gcno_split_crc));
+	}
+	# Skip cfg checksum word in case of split checksums
+	graph_skip($handle, 4, "function cfg checksum") if ($gcno_split_crc);
+	# Read function name
+	graph_expect("function name");
+	$function = read_gcno_string($handle, $big_endian);
+	return undef if (!defined($function));
+	# Read filename
+	graph_expect("filename");
+	$filename = read_gcno_string($handle, $big_endian);
+	return undef if (!defined($filename));
+	# Read first line number
+	$lineno = read_gcno_value($handle, $big_endian, "initial line number");
+	return undef if (!defined($lineno));
+	# Add to list
+	push(@{$bb->{$function}->{$filename}}, $lineno);
+	graph_add_order($fileorder, $function, $filename);
+
+	return ($filename, $function);
+}
+
+#
+# read_gcno(filename)
+#
+# Read the contents of the specified .gcno file and return the following
+# mapping:
+#   graph:    filename -> file_data
+#   file_data: function name -> line_data
+#   line_data: [ line1, line2, ... ]
+#
+# See the gcov-io.h file in the gcc 3.3 source code for a description of
+# the .gcno format.
+#
+
+sub read_gcno($)
+{
+	my ($gcno_filename) = @_;
+	my $file_magic = 0x67636e6f;
+	my $tag_function = 0x01000000;
+	my $tag_lines = 0x01450000;
+	my $big_endian;
+	my $word;
+	my $tag;
+	my $length;
+	my $filename;
+	my $function;
+	my $bb = {};
+	my $fileorder = {};
+	my $instr;
+	my $graph;
+	local *HANDLE;
+
+	open(HANDLE, "<", $gcno_filename) or goto open_error;
+	binmode(HANDLE);
+	# Read magic
+	$word = read_gcno_word(*HANDLE, "file magic");
+	goto incomplete if (!defined($word));
+	# Determine file endianness
+	if (unpack("N", $word) == $file_magic) {
+		$big_endian = 1;
+	} elsif (unpack("V", $word) == $file_magic) {
+		$big_endian = 0;
+	} else {
+		goto magic_error;
+	}
+	# Skip version and stamp
+	graph_skip(*HANDLE, 8, "version and stamp") or goto incomplete;
+	while (!eof(HANDLE)) {
+		my $next_pos;
+		my $curr_pos;
+
+		# Read record tag
+		$tag = read_gcno_value(*HANDLE, $big_endian, "record tag");
+		goto incomplete if (!defined($tag));
+		# Read record length
+		$length = read_gcno_value(*HANDLE, $big_endian,
+					  "record length");
+		goto incomplete if (!defined($length));
+		# Convert length to bytes
+		$length *= 4;
+		# Calculate start of next record
+		$next_pos = tell(HANDLE);
+		goto tell_error if ($next_pos == -1);
+		$next_pos += $length;
+		# Process record
+		if ($tag == $tag_function) {
+			($filename, $function) = read_gcno_function_record(
+				*HANDLE, $bb, $fileorder, $big_endian,
+				$length);
+			goto incomplete if (!defined($function));
+		} elsif ($tag == $tag_lines) {
+			# Read lines record
+			$filename = read_gcno_lines_record(*HANDLE,
+					$gcno_filename, $bb, $fileorder,
+					$filename, $function,
+					$big_endian);
+			goto incomplete if (!defined($filename));
+		} else {
+			# Skip record contents
+			graph_skip(*HANDLE, $length, "unhandled record")
+				or goto incomplete;
+		}
+		# Ensure that we are at the start of the next record
+		$curr_pos = tell(HANDLE);
+		goto tell_error if ($curr_pos == -1);
+		next if ($curr_pos == $next_pos);
+		goto record_error if ($curr_pos > $next_pos);
+		graph_skip(*HANDLE, $next_pos - $curr_pos,
+			   "unhandled record content")
+			or goto incomplete;
+	}
+	close(HANDLE);
+	($instr, $graph) = graph_from_bb($bb, $fileorder, $gcno_filename);
+	graph_cleanup($graph);
+
+	return ($instr, $graph);
+
+open_error:
+	graph_error($gcno_filename, "could not open file");
+	return undef;
+incomplete:
+	graph_error($gcno_filename, "reached unexpected end of file");
+	return undef;
+magic_error:
+	graph_error($gcno_filename, "found unrecognized gcno file magic");
+	return undef;
+tell_error:
+	graph_error($gcno_filename, "could not determine file position");
+	return undef;
+record_error:
+	graph_error($gcno_filename, "found unrecognized record format");
+	return undef;
+}
+
+sub debug($)
+{
+	my ($msg) = @_;
+
+	return if (!$debug);
+	print(STDERR "DEBUG: $msg");
+}
+
+#
+# get_gcov_capabilities
+#
+# Determine the list of available gcov options.
+#
+
+sub get_gcov_capabilities()
+{
+	my $help = `$gcov_tool --help`;
+	my %capabilities;
+
+	foreach (split(/\n/, $help)) {
+		next if (!/--(\S+)/);
+		next if ($1 eq 'help');
+		next if ($1 eq 'version');
+		next if ($1 eq 'object-directory');
+
+		$capabilities{$1} = 1;
+		debug("gcov has capability '$1'\n");
+	}
+
+	return \%capabilities;
+}
+
+#
+# parse_ignore_errors(@ignore_errors)
+#
+# Parse user input about which errors to ignore.
+#
+
+sub parse_ignore_errors(@)
+{
+	my (@ignore_errors) = @_;
+	my @items;
+	my $item;
+
+	return if (!@ignore_errors);
+
+	foreach $item (@ignore_errors) {
+		$item =~ s/\s//g;
+		if ($item =~ /,/) {
+			# Split and add comma-separated parameters
+			push(@items, split(/,/, $item));
+		} else {
+			# Add single parameter
+			push(@items, $item);
+		}
+	}
+	foreach $item (@items) {
+		my $item_id = $ERROR_ID{lc($item)};
+
+		if (!defined($item_id)) {
+			die("ERROR: unknown argument for --ignore-errors: ".
+			    "$item\n");
+		}
+		$ignore[$item_id] = 1;
+	}
+}
+
+#
+# is_external(filename)
+#
+# Determine if a file is located outside of the specified data directories.
+#
+
+sub is_external($)
+{
+	my ($filename) = @_;
+	my $dir;
+
+	foreach $dir (@internal_dirs) {
+		return 0 if ($filename =~ /^\Q$dir\/\E/);
+	}
+	return 1;
+}
+
+#
+# compat_name(mode)
+#
+# Return the name of compatibility mode MODE.
+#
+
+sub compat_name($)
+{
+	my ($mode) = @_;
+	my $name = $COMPAT_MODE_TO_NAME{$mode};
+
+	return $name if (defined($name));
+
+	return "<unknown>";
+}
+
+#
+# parse_compat_modes(opt)
+#
+# Determine compatibility mode settings.
+#
+
+sub parse_compat_modes($)
+{
+	my ($opt) = @_;
+	my @opt_list;
+	my %specified;
+
+	# Initialize with defaults
+	%compat_value = %COMPAT_MODE_DEFAULTS;
+
+	# Add old style specifications
+	if (defined($opt_compat_libtool)) {
+		$compat_value{$COMPAT_MODE_LIBTOOL} =
+			$opt_compat_libtool ? $COMPAT_VALUE_ON
+					    : $COMPAT_VALUE_OFF;
+	}
+
+	# Parse settings
+	if (defined($opt)) {
+		@opt_list = split(/\s*,\s*/, $opt);
+	}
+	foreach my $directive (@opt_list) {
+		my ($mode, $value);
+
+		# Either
+		#   mode=off|on|auto or
+		#   mode (implies on)
+		if ($directive !~ /^(\w+)=(\w+)$/ &&
+		    $directive !~ /^(\w+)$/) {
+			die("ERROR: Unknown compatibility mode specification: ".
+			    "$directive!\n");
+		}
+		# Determine mode
+		$mode = $COMPAT_NAME_TO_MODE{lc($1)};
+		if (!defined($mode)) {
+			die("ERROR: Unknown compatibility mode '$1'!\n");
+		}
+		$specified{$mode} = 1;
+		# Determine value
+		if (defined($2)) {
+			$value = $COMPAT_NAME_TO_VALUE{lc($2)};
+			if (!defined($value)) {
+				die("ERROR: Unknown compatibility mode ".
+				    "value '$2'!\n");
+			}
+		} else {
+			$value = $COMPAT_VALUE_ON;
+		}
+		$compat_value{$mode} = $value;
+	}
+	# Perform auto-detection
+	foreach my $mode (sort(keys(%compat_value))) {
+		my $value = $compat_value{$mode};
+		my $is_autodetect = "";
+		my $name = compat_name($mode);
+
+		if ($value == $COMPAT_VALUE_AUTO) {
+			my $autodetect = $COMPAT_MODE_AUTO{$mode};
+
+			if (!defined($autodetect)) {
+				die("ERROR: No auto-detection for ".
+				    "mode '$name' available!\n");
+			}
+
+			if (ref($autodetect) eq "CODE") {
+				$value = &$autodetect();
+				$compat_value{$mode} = $value;
+				$is_autodetect = " (auto-detected)";
+			}
+		}
+
+		if ($specified{$mode}) {
+			if ($value == $COMPAT_VALUE_ON) {
+				info("Enabling compatibility mode ".
+				     "'$name'$is_autodetect\n");
+			} elsif ($value == $COMPAT_VALUE_OFF) {
+				info("Disabling compatibility mode ".
+				     "'$name'$is_autodetect\n");
+			} else {
+				info("Using delayed auto-detection for ".
+				     "compatibility mode ".
+				     "'$name'\n");
+			}
+		}
+	}
+}
+
+sub compat_hammer_autodetect()
+{
+        if ($gcov_version_string =~ /suse/i && $gcov_version == 0x30303 ||
+            $gcov_version_string =~ /mandrake/i && $gcov_version == 0x30302)
+	{
+		info("Auto-detected compatibility mode for GCC 3.3 (hammer)\n");
+		return $COMPAT_VALUE_ON;
+	}
+	return $COMPAT_VALUE_OFF;
+}
+
+#
+# is_compat(mode)
+#
+# Return non-zero if compatibility mode MODE is enabled.
+#
+
+sub is_compat($)
+{
+	my ($mode) = @_;
+
+	return 1 if ($compat_value{$mode} == $COMPAT_VALUE_ON);
+	return 0;
+}
+
+#
+# is_compat_auto(mode)
+#
+# Return non-zero if compatibility mode MODE is set to auto-detect.
+#
+
+sub is_compat_auto($)
+{
+	my ($mode) = @_;
+
+	return 1 if ($compat_value{$mode} == $COMPAT_VALUE_AUTO);
+	return 0;
+}
diff --git a/third_party/lcov/bin/genpng b/third_party/lcov/bin/genpng
index b4d90c2..5f3084c 100755
--- a/third_party/lcov/bin/genpng
+++ b/third_party/lcov/bin/genpng
@@ -22,7 +22,7 @@
 #   This script creates an overview PNG image of a source code file by
 #   representing each source code character by a single pixel.
 #
-#   Note that the PERL module GD.pm is required for this script to work.
+#   Note that the Perl module GD.pm is required for this script to work.
 #   It may be obtained from http://www.cpan.org
 #
 # History:
@@ -35,7 +35,7 @@
 
 
 # Constants
-our $lcov_version	= "LCOV version 1.7";
+our $lcov_version	= 'LCOV version 1.10';
 our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
 our $tool_name		= basename($0);
 
@@ -45,14 +45,17 @@
 sub check_and_load_module($);
 sub genpng_print_usage(*);
 sub genpng_process_file($$$$);
-sub warn_handler($);
-sub die_handler($);
+sub genpng_warn_handler($);
+sub genpng_die_handler($);
 
 
 #
 # Code entry point
 #
 
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
+
 # Check whether required module GD.pm is installed
 if (check_and_load_module("GD"))
 {
@@ -75,8 +78,8 @@
 	my $help;
 	my $version;
 
-	$SIG{__WARN__} = \&warn_handler;
-	$SIG{__DIE__} = \&die_handler;
+	$SIG{__WARN__} = \&genpng_warn_handler;
+	$SIG{__DIE__} = \&genpng_die_handler;
 
 	# Parse command line options
 	if (!GetOptions("tab-size=i" => \$tab_size,
@@ -179,7 +182,7 @@
 	local *HANDLE;
 	my @source;
 
-	open(HANDLE, "<$filename")
+	open(HANDLE, "<", $filename)
 		or die("ERROR: cannot open $filename!\n");
 
 	# Check for .gcov filename extension
@@ -235,7 +238,7 @@
 	my $overview_width = shift(@_);	# Imagewidth for image
 	my $tab_size = shift(@_);	# Replacement string for tab signs
 	my @source = @_;	# Source code as passed via argument 2
-	my $height = scalar(@source);	# Height as define by source size
+	my $height;		# Height as define by source size
 	my $overview;		# Source code overview image data
 	my $col_plain_back;	# Color for overview background
 	my $col_plain_text;	# Color for uninstrumented text
@@ -258,6 +261,11 @@
 	my $replacement;	# Replacement string for tabulator chars
 	local *PNG_HANDLE;	# Handle for output PNG file
 
+	# Handle empty source files
+	if (!@source) {
+		@source = ( "" );
+	}
+	$height = scalar(@source);
 	# Create image
 	$overview = new GD::Image($overview_width, $height)
 		or die("ERROR: cannot allocate overview image!\n");
@@ -359,21 +367,21 @@
 	}
 
 	# Write PNG file
-	open (PNG_HANDLE, ">$filename")
+	open (PNG_HANDLE, ">", $filename)
 		or die("ERROR: cannot write png file $filename!\n");
 	binmode(*PNG_HANDLE);
 	print(PNG_HANDLE $overview->png());
 	close(PNG_HANDLE);
 }
 
-sub warn_handler($)
+sub genpng_warn_handler($)
 {
 	my ($msg) = @_;
 
 	warn("$tool_name: $msg");
 }
 
-sub die_handler($)
+sub genpng_die_handler($)
 {
 	my ($msg) = @_;
 
diff --git a/third_party/lcov/bin/install.sh b/third_party/lcov/bin/install.sh
index 9d4a9da..27140f9 100755
--- a/third_party/lcov/bin/install.sh
+++ b/third_party/lcov/bin/install.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 #
-# install.sh [--uninstall] sourcefile targetfile
+# install.sh [--uninstall] sourcefile targetfile [install options]
 #
 
 
@@ -9,15 +9,17 @@
   UNINSTALL=true
   SOURCE=$2
   TARGET=$3
+  shift 3
 else
   UNINSTALL=false
   SOURCE=$1
   TARGET=$2
+  shift 2
 fi
 
 # Check usage
 if test -z "$SOURCE" || test -z "$TARGET" ; then
-  echo Usage: install.sh [--uninstall] source target >&2
+  echo Usage: install.sh [--uninstall] source target [install options] >&2
   exit 1
 fi
 
@@ -30,8 +32,9 @@
 {
   local SOURCE=$1
   local TARGET=$2
+  local PARAMS=$3
 
-  install -D $SOURCE $TARGET
+  install -p -D $PARAMS $SOURCE $TARGET
 }
 
 
@@ -62,7 +65,7 @@
 if $UNINSTALL ; then
   do_uninstall $SOURCE $TARGET
 else
-  do_install $SOURCE $TARGET
+  do_install $SOURCE $TARGET "$*"
 fi
 
 exit 0
diff --git a/third_party/lcov/bin/lcov b/third_party/lcov/bin/lcov
index 6304d75..1a7f525 100755
--- a/third_party/lcov/bin/lcov
+++ b/third_party/lcov/bin/lcov
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 #
-#   Copyright (c) International Business Machines  Corp., 2002,2007
+#   Copyright (c) International Business Machines  Corp., 2002,2012
 #
 #   This program is free software;  you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
@@ -60,36 +60,43 @@
 #
 
 use strict;
-use File::Basename; 
+use File::Basename;
+use File::Path;
+use File::Find;
+use File::Temp qw /tempdir/;
+use File::Spec::Functions qw /abs2rel canonpath catdir catfile catpath
+			      file_name_is_absolute rootdir splitdir splitpath/;
 use Getopt::Long;
+use Cwd qw /abs_path getcwd/;
 
 
 # Global constants
-our $lcov_version	= "LCOV version 1.7";
+our $lcov_version	= 'LCOV version 1.10';
 our $lcov_url		= "http://ltp.sourceforge.net/coverage/lcov.php";
 our $tool_name		= basename($0);
 
-# Names of the GCOV kernel module
-our @gcovmod = ("gcov-prof", "gcov-proc");
-
 # Directory containing gcov kernel files
-our $gcov_dir = "/proc/gcov";
-
-# The location of the insmod tool
-our $insmod_tool	= "/sbin/insmod";
-
-# The location of the modprobe tool
-our $modprobe_tool	= "/sbin/modprobe";
-
-# The location of the rmmod tool
-our $rmmod_tool		= "/sbin/rmmod";
+our $gcov_dir;
 
 # Where to create temporary directories
-our $tmp_dir		= "/tmp";
+our $tmp_dir;
 
-# How to prefix a temporary directory name
-our $tmp_prefix		= "tmpdir";
+# Internal constants
+our $GKV_PROC = 0;	# gcov-kernel data in /proc via external patch
+our $GKV_SYS = 1;	# gcov-kernel data in /sys via vanilla 2.6.31+
+our @GKV_NAME = ( "external", "upstream" );
+our $pkg_gkv_file = ".gcov_kernel_version";
+our $pkg_build_file = ".build_directory";
 
+our $BR_BLOCK		= 0;
+our $BR_BRANCH		= 1;
+our $BR_TAKEN		= 2;
+our $BR_VEC_ENTRIES	= 3;
+our $BR_VEC_WIDTH	= 32;
+
+# Branch data combination types
+our $BR_SUB = 0;
+our $BR_ADD = 1;
 
 # Prototypes
 sub print_usage(*);
@@ -98,10 +105,12 @@
 sub userspace_capture();
 sub kernel_reset();
 sub kernel_capture();
+sub kernel_capture_initial();
+sub package_capture();
 sub add_traces();
 sub read_info_file($);
 sub get_info_entry($);
-sub set_info_entry($$$$$$$;$$$$);
+sub set_info_entry($$$$$$$$$;$$$$$$);
 sub add_counts($$);
 sub merge_checksums($$$);
 sub combine_info_entries($$$);
@@ -117,13 +126,21 @@
 sub read_config($);
 sub apply_config($);
 sub info(@);
-sub unload_module($);
-sub check_and_load_kernel_module();
 sub create_temp_dir();
 sub transform_pattern($);
 sub warn_handler($);
 sub die_handler($);
-
+sub abort_handler($);
+sub temp_cleanup();
+sub setup_gkv();
+sub get_overall_line($$$$);
+sub print_overall_rate($$$$$$$$$);
+sub lcov_geninfo(@);
+sub create_package($$$;$);
+sub get_func_found_and_hit($);
+sub br_ivec_get($$);
+sub summary();
+sub rate($$;$$$);
 
 # Global variables & initialization
 our @directory;		# Specifies where to get coverage data from
@@ -142,7 +159,6 @@
 our $version;		# Version option flag
 our $convert_filenames;	# If set, convert filenames when applying diff
 our $strip;		# If set, strip leading directories when applying diff
-our $need_unload;	# If set, unload gcov kernel module
 our $temp_dir_name;	# Name of temporary directory
 our $cwd = `pwd`;	# Current working directory
 our $to_file;		# If set, indicates that output is written to a file
@@ -154,13 +170,38 @@
 our $compat_libtool;	# If set, indicates that libtool mode is to be enabled
 our $no_compat_libtool;	# If set, indicates that libtool mode is to be disabled
 our $gcov_tool;
-our $ignore_errors;
+our @opt_ignore_errors;
 our $initial;
 our $no_recursion = 0;
+our $to_package;
+our $from_package;
 our $maxdepth;
+our $no_markers;
 our $config;		# Configuration file contents
 chomp($cwd);
 our $tool_dir = dirname($0);	# Directory where genhtml tool is installed
+our @temp_dirs;
+our $gcov_gkv;		# gcov kernel support version found on machine
+our $opt_derive_func_data;
+our $opt_debug;
+our $opt_list_full_path;
+our $opt_no_list_full_path;
+our $opt_list_width = 80;
+our $opt_list_truncate_max = 20;
+our $opt_external;
+our $opt_no_external;
+our $opt_config_file;
+our %opt_rc;
+our @opt_summary;
+our $opt_compat;
+our $ln_overall_found;
+our $ln_overall_hit;
+our $fn_overall_found;
+our $fn_overall_hit;
+our $br_overall_found;
+our $br_overall_hit;
+our $func_coverage = 1;
+our $br_coverage = 0;
 
 
 #
@@ -169,6 +210,11 @@
 
 $SIG{__WARN__} = \&warn_handler;
 $SIG{__DIE__} = \&die_handler;
+$SIG{'INT'} = \&abort_handler;
+$SIG{'QUIT'} = \&abort_handler;
+
+# Prettify version string
+$lcov_version =~ s/\$\s*Revision\s*:?\s*(\S+)\s*\$/$1/;
 
 # Add current working directory if $tool_dir is not already an absolute path
 if (! ($tool_dir =~ /^\/(.*)$/))
@@ -176,8 +222,16 @@
 	$tool_dir = "$cwd/$tool_dir";
 }
 
+# Check command line for a configuration file name
+Getopt::Long::Configure("pass_through", "no_auto_abbrev");
+GetOptions("config-file=s" => \$opt_config_file,
+	   "rc=s%" => \%opt_rc);
+Getopt::Long::Configure("default");
+
 # Read configuration file if available
-if (-r $ENV{"HOME"}."/.lcovrc")
+if (defined($opt_config_file)) {
+	$config = read_config($opt_config_file);
+} elsif (defined($ENV{"HOME"}) && (-r $ENV{"HOME"}."/.lcovrc"))
 {
 	$config = read_config($ENV{"HOME"}."/.lcovrc");
 }
@@ -186,45 +240,61 @@
 	$config = read_config("/etc/lcovrc");
 }
 
-if ($config)
+if ($config || %opt_rc)
 {
-	# Copy configuration file values to variables
+	# Copy configuration file and --rc values to variables
 	apply_config({
 		"lcov_gcov_dir"		=> \$gcov_dir,
-		"lcov_insmod_tool"	=> \$insmod_tool,
-		"lcov_modprobe_tool"	=> \$modprobe_tool,
-		"lcov_rmmod_tool"	=> \$rmmod_tool,
-		"lcov_tmp_dir"		=> \$tmp_dir});
+		"lcov_tmp_dir"		=> \$tmp_dir,
+		"lcov_list_full_path"	=> \$opt_list_full_path,
+		"lcov_list_width"	=> \$opt_list_width,
+		"lcov_list_truncate_max"=> \$opt_list_truncate_max,
+		"lcov_branch_coverage"	=> \$br_coverage,
+		"lcov_function_coverage"=> \$func_coverage,
+	});
 }
 
 # Parse command line options
 if (!GetOptions("directory|d|di=s" => \@directory,
-		"add-tracefile=s" => \@add_tracefile,
-		"list=s" => \$list,
-		"kernel-directory=s" => \@kernel_directory,
-		"extract=s" => \$extract,
-		"remove=s" => \$remove,
+		"add-tracefile|a=s" => \@add_tracefile,
+		"list|l=s" => \$list,
+		"kernel-directory|k=s" => \@kernel_directory,
+		"extract|e=s" => \$extract,
+		"remove|r=s" => \$remove,
 		"diff=s" => \$diff,
 		"convert-filenames" => \$convert_filenames,
 		"strip=i" => \$strip,
 		"capture|c" => \$capture,
-		"output-file=s" => \$output_filename,
-		"test-name=s" => \$test_name,
-		"zerocounters" => \$reset,
-		"quiet" => \$quiet,
-		"help|?" => \$help,
-		"version" => \$version,
-		"follow" => \$follow,
+		"output-file|o=s" => \$output_filename,
+		"test-name|t=s" => \$test_name,
+		"zerocounters|z" => \$reset,
+		"quiet|q" => \$quiet,
+		"help|h|?" => \$help,
+		"version|v" => \$version,
+		"follow|f" => \$follow,
 		"path=s" => \$diff_path,
-		"base-directory=s" => \$base_directory,
+		"base-directory|b=s" => \$base_directory,
 		"checksum" => \$checksum,
 		"no-checksum" => \$no_checksum,
 		"compat-libtool" => \$compat_libtool,
 		"no-compat-libtool" => \$no_compat_libtool,
 		"gcov-tool=s" => \$gcov_tool,
-		"ignore-errors=s" => \$ignore_errors,
+		"ignore-errors=s" => \@opt_ignore_errors,
 		"initial|i" => \$initial,
-		"no-recursion" => \$no_recursion
+		"no-recursion" => \$no_recursion,
+		"to-package=s" => \$to_package,
+		"from-package=s" => \$from_package,
+		"no-markers" => \$no_markers,
+		"derive-func-data" => \$opt_derive_func_data,
+		"debug" => \$opt_debug,
+		"list-full-path" => \$opt_list_full_path,
+		"no-list-full-path" => \$opt_no_list_full_path,
+		"external" => \$opt_external,
+		"no-external" => \$opt_no_external,
+		"summary=s" => \@opt_summary,
+		"compat=s" => \$opt_compat,
+		"config-file=s" => \$opt_config_file,
+		"rc=s%" => \%opt_rc,
 		))
 {
 	print(STDERR "Use $tool_name --help to get usage information\n");
@@ -244,6 +314,17 @@
 		$compat_libtool = ($no_compat_libtool ? 0 : 1);
 		$no_compat_libtool = undef;
 	}
+
+	if (defined($opt_no_list_full_path))
+	{
+		$opt_list_full_path = ($opt_no_list_full_path ? 0 : 1);
+		$opt_no_list_full_path = undef;
+	}
+
+	if (defined($opt_no_external)) {
+		$opt_external = 0;
+		$opt_no_external = undef;
+	}
 }
 
 # Check for help option
@@ -260,6 +341,12 @@
 	exit(0);
 }
 
+# Check list width option
+if ($opt_list_width <= 40) {
+	die("ERROR: lcov_list_width parameter out of range (needs to be ".
+	    "larger than 40)\n");
+}
+
 # Normalize --path text
 $diff_path =~ s/\/$//;
 
@@ -285,9 +372,9 @@
 check_options();
 
 # Only --extract, --remove and --diff allow unnamed parameters
-if (@ARGV && !($extract || $remove || $diff))
+if (@ARGV && !($extract || $remove || $diff || @opt_summary))
 {
-	die("Extra parameter found\n".
+	die("Extra parameter found: '".join(" ", @ARGV)."'\n".
 	    "Use $tool_name --help to get usage information\n");
 }
 
@@ -302,13 +389,10 @@
 		$output_filename = "-";
 	}
 }
-else
-{
-	if ($initial)
-	{
-		die("Option --initial is only valid when capturing data (-c)\n".
-		    "Use $tool_name --help to get usage information\n");
-	}
+
+# Determine kernel directory for gcov data
+if (!$from_package && !@directory && ($capture || $reset)) {
+	($gcov_gkv, $gcov_dir) = setup_gkv();
 }
 
 # Check for requested functionality
@@ -326,27 +410,40 @@
 }
 elsif ($capture)
 {
-	# Differentiate between user space and kernel 
-	if (@directory)
-	{
+	# Capture source can be user space, kernel or package
+	if ($from_package) {
+		package_capture();
+	} elsif (@directory) {
 		userspace_capture();
-	}
-	else
-	{
-		kernel_capture();
+	} else {
+		if ($initial) {
+			if (defined($to_package)) {
+				die("ERROR: --initial cannot be used together ".
+				    "with --to-package\n");
+			}
+			kernel_capture_initial();
+		} else {
+			kernel_capture();
+		}
 	}
 }
 elsif (@add_tracefile)
 {
-	add_traces();
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = add_traces();
 }
 elsif ($remove)
 {
-	remove();
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = remove();
 }
 elsif ($extract)
 {
-	extract();
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = extract();
 }
 elsif ($list)
 {
@@ -359,10 +456,26 @@
 		die("ERROR: option --diff requires one additional argument!\n".
 		    "Use $tool_name --help to get usage information\n");
 	}
-	diff();
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = diff();
+}
+elsif (@opt_summary)
+{
+	($ln_overall_found, $ln_overall_hit,
+	 $fn_overall_found, $fn_overall_hit,
+	 $br_overall_found, $br_overall_hit) = summary();
 }
 
-info("Done.\n");
+temp_cleanup();
+
+if (defined($ln_overall_found)) {
+	print_overall_rate(1, $ln_overall_found, $ln_overall_hit,
+			   1, $fn_overall_found, $fn_overall_hit,
+			   1, $br_overall_found, $br_overall_hit);
+} else {
+	info("Done.\n") if (!$list && !$capture);
+}
 exit(0);
 
 #
@@ -395,6 +508,7 @@
   -r, --remove FILE PATTERN       Remove files matching PATTERN from FILE
   -l, --list FILE                 List contents of tracefile FILE
       --diff FILE DIFF            Transform tracefile FILE according to DIFF
+      --summary FILE              Show summary coverage data for tracefiles
 
 Options:
   -i, --initial                   Capture initial zero coverage data
@@ -410,8 +524,17 @@
       --(no-)checksum             Enable (disable) line checksumming
       --(no-)compat-libtool       Enable (disable) libtool compatibility mode
       --gcov-tool TOOL            Specify gcov tool location
-      --ignore-errors ERRORS      Continue after ERRORS (gcov, source)
-      --no-recursion              Exlude subdirectories from processing
+      --ignore-errors ERRORS      Continue after ERRORS (gcov, source, graph)
+      --no-recursion              Exclude subdirectories from processing
+      --to-package FILENAME       Store unprocessed coverage data in FILENAME
+      --from-package FILENAME     Capture from unprocessed data in FILENAME
+      --no-markers                Ignore exclusion markers in source code
+      --derive-func-data          Generate function data from line data
+      --list-full-path            Print full path during a list operation
+      --(no-)external             Include (ignore) data for external files
+      --config-file FILENAME      Specify configuration file location
+      --rc SETTING=VALUE          Override configuration file setting
+      --compat MODE=on|off|auto   Set compat MODE (libtool, hammer, split_crc)
 
 For more information see: $lcov_url
 END_OF_USAGE
@@ -437,17 +560,18 @@
 	$remove && $i++;
 	$list && $i++;
 	$diff && $i++;
+	@opt_summary && $i++;
 	
 	if ($i == 0)
 	{
-		die("Need one of the options -z, -c, -a, -e, -r, -l or ".
-		    "--diff\n".
+		die("Need one of options -z, -c, -a, -e, -r, -l, ".
+		    "--diff or --summary\n".
 		    "Use $tool_name --help to get usage information\n");
 	}
 	elsif ($i > 1)
 	{
-		die("ERROR: only one of -z, -c, -a, -e, -r, -l or ".
-		    "--diff allowed!\n".
+		die("ERROR: only one of -z, -c, -a, -e, -r, -l, ".
+		    "--diff or --summary allowed!\n".
 		    "Use $tool_name --help to get usage information\n");
 	}
 }
@@ -483,77 +607,31 @@
 #
 # userspace_capture()
 #
-# Capture coverage data found in DIRECTORY and write it to OUTPUT_FILENAME
-# if specified, otherwise to STDOUT.
+# Capture coverage data found in DIRECTORY and write it to a package (if
+# TO_PACKAGE specified) or to OUTPUT_FILENAME or STDOUT.
 #
 # Die on error.
 #
 
 sub userspace_capture()
 {
-	my @param;
-	my $file_list = join(" ", @directory);
+	my $dir;
+	my $build;
 
-	info("Capturing coverage data from $file_list\n");
-	@param = ("$tool_dir/geninfo", @directory);
-	if ($output_filename)
-	{
-		@param = (@param, "--output-filename", $output_filename);
+	if (!defined($to_package)) {
+		lcov_geninfo(@directory);
+		return;
 	}
-	if ($test_name)
-	{
-		@param = (@param, "--test-name", $test_name);
+	if (scalar(@directory) != 1) {
+		die("ERROR: -d may be specified only once with --to-package\n");
 	}
-	if ($follow)
-	{
-		@param = (@param, "--follow");
+	$dir = $directory[0];
+	if (defined($base_directory)) {
+		$build = $base_directory;
+	} else {
+		$build = $dir;
 	}
-	if ($quiet)
-	{
-		@param = (@param, "--quiet");
-	}
-	if (defined($checksum))
-	{
-		if ($checksum)
-		{
-			@param = (@param, "--checksum");
-		}
-		else
-		{
-			@param = (@param, "--no-checksum");
-		}
-	}
-	if ($base_directory)
-	{
-		@param = (@param, "--base-directory", $base_directory);
-	}
-	if ($no_compat_libtool)
-	{
-		@param = (@param, "--no-compat-libtool");
-	}
-	elsif ($compat_libtool)
-	{
-		@param = (@param, "--compat-libtool");
-	}
-	if ($gcov_tool)
-	{
-		@param = (@param, "--gcov-tool", $gcov_tool);
-	}
-	if ($ignore_errors)
-	{
-		@param = (@param, "--ignore-errors", $ignore_errors);
-	}
-	if ($initial)
-	{
-		@param = (@param, "--initial");
-	}
-	if ($no_recursion)
-	{
-		@param = (@param, "--no-recursion");
-	}
-
-	system(@param);
-	exit($? >> 8);
+	create_package($to_package, $dir, $build);
 }
 
 
@@ -568,93 +646,158 @@
 sub kernel_reset()
 {
 	local *HANDLE;
-	check_and_load_kernel_module();
+	my $reset_file;
 
 	info("Resetting kernel execution counters\n");
-	open(HANDLE, ">$gcov_dir/vmlinux") or
-		die("ERROR: cannot write to $gcov_dir/vmlinux!\n");
+	if (-e "$gcov_dir/vmlinux") {
+		$reset_file = "$gcov_dir/vmlinux";
+	} elsif (-e "$gcov_dir/reset") {
+		$reset_file = "$gcov_dir/reset";
+	} else {
+		die("ERROR: no reset control found in $gcov_dir\n");
+	}
+	open(HANDLE, ">", $reset_file) or
+		die("ERROR: cannot write to $reset_file!\n");
 	print(HANDLE "0");
 	close(HANDLE);
-
-	# Unload module if we loaded it in the first place
-	if ($need_unload)
-	{
-		unload_module($need_unload);
-	}
 }
 
 
 #
-# kernel_capture()
+# lcov_copy_single(from, to)
+# 
+# Copy single regular file FROM to TO without checking its size. This is
+# required to work with special files generated by the kernel
+# seq_file-interface.
 #
-# Capture kernel coverage data and write it to OUTPUT_FILENAME if specified,
-# otherwise stdout.
 #
-
-sub kernel_capture()
+sub lcov_copy_single($$)
 {
-	my @param;
+	my ($from, $to) = @_;
+	my $content;
+	local $/;
+	local *HANDLE;
 
-	check_and_load_kernel_module();
+	open(HANDLE, "<", $from) or die("ERROR: cannot read $from: $!\n");
+	$content = <HANDLE>;
+	close(HANDLE);
+	open(HANDLE, ">", $to) or die("ERROR: cannot write $from: $!\n");
+	if (defined($content)) {
+		print(HANDLE $content);
+	}
+	close(HANDLE);
+}
 
-	# Make sure the temporary directory is removed upon script termination
-	END
-	{
-		if ($temp_dir_name)
-		{
-			stat($temp_dir_name);
-			if (-r _)
-			{
-				info("Removing temporary directory ".
-				     "$temp_dir_name\n");
+#
+# lcov_find(dir, function, data[, extension, ...)])
+#
+# Search DIR for files and directories whose name matches PATTERN and run
+# FUNCTION for each match. If not pattern is specified, match all names.
+#
+# FUNCTION has the following prototype:
+#   function(dir, relative_name, data)
+#
+# Where:
+#   dir: the base directory for this search
+#   relative_name: the name relative to the base directory of this entry
+#   data: the DATA variable passed to lcov_find
+#
+sub lcov_find($$$;@)
+{
+	my ($dir, $fn, $data, @pattern) = @_;
+	my $result;
+	my $_fn = sub {
+		my $filename = $File::Find::name;
 
-				# Remove temporary directory
-				system("rm", "-rf", $temp_dir_name)
-					and warn("WARNING: cannot remove ".
-						 "temporary directory ".
-						 "$temp_dir_name!\n");
+		if (defined($result)) {
+			return;
+		}		
+		$filename = abs2rel($filename, $dir);
+		foreach (@pattern) {
+			if ($filename =~ /$_/) {
+				goto ok;
 			}
 		}
+		return;
+	ok:
+		$result = &$fn($dir, $filename, $data);
+	};
+	if (scalar(@pattern) == 0) {
+		@pattern = ".*";
 	}
+	find( { wanted => $_fn, no_chdir => 1 }, $dir);
 
-	# Get temporary directory
-	$temp_dir_name = create_temp_dir();
+	return $result;
+}
 
-	info("Copying kernel data to temporary directory $temp_dir_name\n");
+#
+# lcov_copy_fn(from, rel, to)
+#
+# Copy directories, files and links from/rel to to/rel.
+#
 
-	if (!@kernel_directory)
-	{
-		# Copy files from gcov kernel directory
-		system("cp", "-dr", $gcov_dir, $temp_dir_name)
-			and die("ERROR: cannot copy files from $gcov_dir!\n");
+sub lcov_copy_fn($$$)
+{
+	my ($from, $rel, $to) = @_;
+	my $absfrom = canonpath(catfile($from, $rel));
+	my $absto = canonpath(catfile($to, $rel));
+
+	if (-d) {
+		if (! -d $absto) {
+			mkpath($absto) or
+				die("ERROR: cannot create directory $absto\n");
+			chmod(0700, $absto);
+		}
+	} elsif (-l) {
+		# Copy symbolic link
+		my $link = readlink($absfrom);
+
+		if (!defined($link)) {
+			die("ERROR: cannot read link $absfrom: $!\n");
+		}
+		symlink($link, $absto) or
+			die("ERROR: cannot create link $absto: $!\n");
+	} else {
+		lcov_copy_single($absfrom, $absto);
+		chmod(0600, $absto);
 	}
-	else
-	{
-		# Prefix list of kernel sub-directories with the gcov kernel
-		# directory
-		@kernel_directory = map("$gcov_dir/$_", @kernel_directory);
+	return undef;
+}
 
-		# Copy files from gcov kernel directory
-		system("cp", "-dr", @kernel_directory, $temp_dir_name)
-			and die("ERROR: cannot copy files from ".
-				join(" ", @kernel_directory)."!\n");
+#
+# lcov_copy(from, to, subdirs)
+# 
+# Copy all specified SUBDIRS and files from directory FROM to directory TO. For
+# regular files, copy file contents without checking its size. This is required
+# to work with seq_file-generated files.
+#
+
+sub lcov_copy($$;@)
+{
+	my ($from, $to, @subdirs) = @_;
+	my @pattern;
+
+	foreach (@subdirs) {
+		push(@pattern, "^$_");
 	}
+	lcov_find($from, \&lcov_copy_fn, $to, @pattern);
+}
 
-	# Make directories writable
-	system("find", $temp_dir_name, "-type", "d", "-exec", "chmod", "u+w",
-	       "{}", ";")
-		and die("ERROR: cannot modify access rights for ".
-			"$temp_dir_name!\n");
+#
+# lcov_geninfo(directory)
+#
+# Call geninfo for the specified directory and with the parameters specified
+# at the command line.
+#
 
-	# Make files writable
-	system("find", $temp_dir_name, "-type", "f", "-exec", "chmod", "u+w",
-	       "{}", ";")
-		and die("ERROR: cannot modify access rights for ".
-			"$temp_dir_name!\n");
+sub lcov_geninfo(@)
+{
+	my (@dir) = @_;
+	my @param;
 
 	# Capture data
-	info("Capturing coverage data from $temp_dir_name\n");
-	@param = ("$tool_dir/geninfo", $temp_dir_name);
+	info("Capturing coverage data from ".join(" ", @dir)."\n");
+	@param = ("$tool_dir/geninfo", @dir);
 	if ($output_filename)
 	{
 		@param = (@param, "--output-filename", $output_filename);
@@ -698,21 +841,470 @@
 	{
 		@param = (@param, "--gcov-tool", $gcov_tool);
 	}
-	if ($ignore_errors)
-	{
-		@param = (@param, "--ignore-errors", $ignore_errors);
+	foreach (@opt_ignore_errors) {
+		@param = (@param, "--ignore-errors", $_);
+	}
+	if ($no_recursion) {
+		@param = (@param, "--no-recursion");
 	}
 	if ($initial)
 	{
 		@param = (@param, "--initial");
 	}
-	system(@param) and exit($? >> 8);
-
-
-	# Unload module if we loaded it in the first place
-	if ($need_unload)
+	if ($no_markers)
 	{
-		unload_module($need_unload);
+		@param = (@param, "--no-markers");
+	}
+	if ($opt_derive_func_data)
+	{
+		@param = (@param, "--derive-func-data");
+	}
+	if ($opt_debug)
+	{
+		@param = (@param, "--debug");
+	}
+	if (defined($opt_external) && $opt_external)
+	{
+		@param = (@param, "--external");
+	}
+	if (defined($opt_external) && !$opt_external)
+	{
+		@param = (@param, "--no-external");
+	}
+	if (defined($opt_compat)) {
+		@param = (@param, "--compat", $opt_compat);
+	}
+	if (%opt_rc) {
+		foreach my $key (keys(%opt_rc)) {
+			@param = (@param, "--rc", "$key=".$opt_rc{$key});
+		}
+	}
+
+	system(@param) and exit($? >> 8);
+}
+
+#
+# read_file(filename)
+#
+# Return the contents of the file defined by filename.
+#
+
+sub read_file($)
+{
+	my ($filename) = @_;
+	my $content;
+	local $\;
+	local *HANDLE;
+
+	open(HANDLE, "<", $filename) || return undef;
+	$content = <HANDLE>;
+	close(HANDLE);
+
+	return $content;
+}
+
+#
+# get_package(package_file)
+#
+# Unpack unprocessed coverage data files from package_file to a temporary
+# directory and return directory name, build directory and gcov kernel version
+# as found in package.
+#
+
+sub get_package($)
+{
+	my ($file) = @_;
+	my $dir = create_temp_dir();
+	my $gkv;
+	my $build;
+	my $cwd = getcwd();
+	my $count;
+	local *HANDLE;
+
+	info("Reading package $file:\n");
+	info("  data directory .......: $dir\n");
+	$file = abs_path($file);
+	chdir($dir);
+	open(HANDLE, "-|", "tar xvfz '$file' 2>/dev/null")
+		or die("ERROR: could not process package $file\n");
+	while (<HANDLE>) {
+		if (/\.da$/ || /\.gcda$/) {
+			$count++;
+		}
+	}
+	close(HANDLE);
+	$build = read_file("$dir/$pkg_build_file");
+	if (defined($build)) {
+		info("  build directory ......: $build\n");
+	}
+	$gkv = read_file("$dir/$pkg_gkv_file");
+	if (defined($gkv)) {
+		$gkv = int($gkv);
+		if ($gkv != $GKV_PROC && $gkv != $GKV_SYS) {
+			die("ERROR: unsupported gcov kernel version found ".
+			    "($gkv)\n");
+		}
+		info("  content type .........: kernel data\n");
+		info("  gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
+	} else {
+		info("  content type .........: application data\n");
+	}
+	info("  data files ...........: $count\n");
+	chdir($cwd);
+
+	return ($dir, $build, $gkv);
+}
+
+#
+# write_file(filename, $content)
+#
+# Create a file named filename and write the specified content to it.
+#
+
+sub write_file($$)
+{
+	my ($filename, $content) = @_;
+	local *HANDLE;
+
+	open(HANDLE, ">", $filename) || return 0;
+	print(HANDLE $content);
+	close(HANDLE) || return 0;
+
+	return 1;
+}
+
+# count_package_data(filename)
+#
+# Count the number of coverage data files in the specified package file.
+#
+
+sub count_package_data($)
+{
+	my ($filename) = @_;
+	local *HANDLE;
+	my $count = 0;
+
+	open(HANDLE, "-|", "tar tfz '$filename'") or return undef;
+	while (<HANDLE>) {
+		if (/\.da$/ || /\.gcda$/) {
+			$count++;
+		}
+	}
+	close(HANDLE);
+	return $count;
+}
+
+#
+# create_package(package_file, source_directory, build_directory[,
+# 		 kernel_gcov_version])
+#
+# Store unprocessed coverage data files from source_directory to package_file.
+#
+
+sub create_package($$$;$)
+{
+	my ($file, $dir, $build, $gkv) = @_;
+	my $cwd = getcwd();
+
+	# Print information about the package
+	info("Creating package $file:\n");
+	info("  data directory .......: $dir\n");
+
+	# Handle build directory
+	if (defined($build)) {
+		info("  build directory ......: $build\n");
+		write_file("$dir/$pkg_build_file", $build)
+			or die("ERROR: could not write to ".
+			       "$dir/$pkg_build_file\n");
+	}
+
+	# Handle gcov kernel version data
+	if (defined($gkv)) {
+		info("  content type .........: kernel data\n");
+		info("  gcov kernel version ..: %s\n", $GKV_NAME[$gkv]);
+		write_file("$dir/$pkg_gkv_file", $gkv)
+			or die("ERROR: could not write to ".
+			       "$dir/$pkg_gkv_file\n");
+	} else {
+		info("  content type .........: application data\n");
+	}
+
+	# Create package
+	$file = abs_path($file);
+	chdir($dir);
+	system("tar cfz $file .")
+		and die("ERROR: could not create package $file\n");
+
+	# Remove temporary files
+	unlink("$dir/$pkg_build_file");
+	unlink("$dir/$pkg_gkv_file");
+
+	# Show number of data files
+	if (!$quiet) {
+		my $count = count_package_data($file);
+
+		if (defined($count)) {
+			info("  data files ...........: $count\n");
+		}
+	}
+	chdir($cwd);
+}
+
+sub find_link_fn($$$)
+{
+	my ($from, $rel, $filename) = @_;
+	my $absfile = catfile($from, $rel, $filename);
+
+	if (-l $absfile) {
+		return $absfile;
+	}
+	return undef;
+}
+
+#
+# get_base(dir)
+#
+# Return (BASE, OBJ), where
+#  - BASE: is the path to the kernel base directory relative to dir
+#  - OBJ: is the absolute path to the kernel build directory
+#
+
+sub get_base($)
+{
+	my ($dir) = @_;
+	my $marker = "kernel/gcov/base.gcno";
+	my $markerfile;
+	my $sys;
+	my $obj;
+	my $link;
+
+	$markerfile = lcov_find($dir, \&find_link_fn, $marker);
+	if (!defined($markerfile)) {
+		return (undef, undef);
+	}
+
+	# sys base is parent of parent of markerfile.
+	$sys = abs2rel(dirname(dirname(dirname($markerfile))), $dir);
+
+	# obj base is parent of parent of markerfile link target.
+	$link = readlink($markerfile);
+	if (!defined($link)) {
+		die("ERROR: could not read $markerfile\n");
+	}
+	$obj = dirname(dirname(dirname($link)));
+
+	return ($sys, $obj);
+}
+
+#
+# apply_base_dir(data_dir, base_dir, build_dir, @directories)
+#
+# Make entries in @directories relative to data_dir.
+#
+
+sub apply_base_dir($$$@)
+{
+	my ($data, $base, $build, @dirs) = @_;
+	my $dir;
+	my @result;
+
+	foreach $dir (@dirs) {
+		# Is directory path relative to data directory?
+		if (-d catdir($data, $dir)) {
+			push(@result, $dir);
+			next;
+		}
+		# Relative to the auto-detected base-directory?
+		if (defined($base)) {
+			if (-d catdir($data, $base, $dir)) {
+				push(@result, catdir($base, $dir));
+				next;
+			}
+		}
+		# Relative to the specified base-directory?
+		if (defined($base_directory)) {
+			if (file_name_is_absolute($base_directory)) {
+				$base = abs2rel($base_directory, rootdir());
+			} else {
+				$base = $base_directory;
+			}
+			if (-d catdir($data, $base, $dir)) {
+				push(@result, catdir($base, $dir));
+				next;
+			}
+		}
+		# Relative to the build directory?
+		if (defined($build)) {
+			if (file_name_is_absolute($build)) {
+				$base = abs2rel($build, rootdir());
+			} else {
+				$base = $build;
+			}
+			if (-d catdir($data, $base, $dir)) {
+				push(@result, catdir($base, $dir));
+				next;
+			}
+		}
+		die("ERROR: subdirectory $dir not found\n".
+		    "Please use -b to specify the correct directory\n");
+	}
+	return @result;
+}
+
+#
+# copy_gcov_dir(dir, [@subdirectories])
+#
+# Create a temporary directory and copy all or, if specified, only some
+# subdirectories from dir to that directory. Return the name of the temporary
+# directory.
+#
+
+sub copy_gcov_dir($;@)
+{
+	my ($data, @dirs) = @_;
+	my $tempdir = create_temp_dir();
+
+	info("Copying data to temporary directory $tempdir\n");
+	lcov_copy($data, $tempdir, @dirs);
+
+	return $tempdir;
+}
+
+#
+# kernel_capture_initial
+#
+# Capture initial kernel coverage data, i.e. create a coverage data file from
+# static graph files which contains zero coverage data for all instrumented
+# lines.
+#
+
+sub kernel_capture_initial()
+{
+	my $build;
+	my $source;
+	my @params;
+
+	if (defined($base_directory)) {
+		$build = $base_directory;
+		$source = "specified";
+	} else {
+		(undef, $build) = get_base($gcov_dir);
+		if (!defined($build)) {
+			die("ERROR: could not auto-detect build directory.\n".
+			    "Please use -b to specify the build directory\n");
+		}
+		$source = "auto-detected";
+	}
+	info("Using $build as kernel build directory ($source)\n");
+	# Build directory needs to be passed to geninfo
+	$base_directory = $build;
+	if (@kernel_directory) {
+		foreach my $dir (@kernel_directory) {
+			push(@params, "$build/$dir");
+		}
+	} else {
+		push(@params, $build);
+	}
+	lcov_geninfo(@params);
+}
+
+#
+# kernel_capture_from_dir(directory, gcov_kernel_version, build)
+#
+# Perform the actual kernel coverage capturing from the specified directory
+# assuming that the data was copied from the specified gcov kernel version.
+#
+
+sub kernel_capture_from_dir($$$)
+{
+	my ($dir, $gkv, $build) = @_;
+
+	# Create package or coverage file
+	if (defined($to_package)) {
+		create_package($to_package, $dir, $build, $gkv);
+	} else {
+		# Build directory needs to be passed to geninfo
+		$base_directory = $build;
+		lcov_geninfo($dir);
+	}
+}
+
+#
+# adjust_kernel_dir(dir, build)
+#
+# Adjust directories specified with -k so that they point to the directory
+# relative to DIR. Return the build directory if specified or the auto-
+# detected build-directory.
+#
+
+sub adjust_kernel_dir($$)
+{
+	my ($dir, $build) = @_;
+	my ($sys_base, $build_auto) = get_base($dir);
+
+	if (!defined($build)) {
+		$build = $build_auto;
+	}
+	if (!defined($build)) {
+		die("ERROR: could not auto-detect build directory.\n".
+		    "Please use -b to specify the build directory\n");
+	}
+	# Make @kernel_directory relative to sysfs base
+	if (@kernel_directory) {
+		@kernel_directory = apply_base_dir($dir, $sys_base, $build,
+						   @kernel_directory);
+	}
+	return $build;
+}
+
+sub kernel_capture()
+{
+	my $data_dir;
+	my $build = $base_directory;
+
+	if ($gcov_gkv == $GKV_SYS) {
+		$build = adjust_kernel_dir($gcov_dir, $build);
+	}
+	$data_dir = copy_gcov_dir($gcov_dir, @kernel_directory);
+	kernel_capture_from_dir($data_dir, $gcov_gkv, $build);
+}
+
+#
+# package_capture()
+#
+# Capture coverage data from a package of unprocessed coverage data files
+# as generated by lcov --to-package.
+#
+
+sub package_capture()
+{
+	my $dir;
+	my $build;
+	my $gkv;
+
+	($dir, $build, $gkv) = get_package($from_package);
+
+	# Check for build directory
+	if (defined($base_directory)) {
+		if (defined($build)) {
+			info("Using build directory specified by -b.\n");
+		}
+		$build = $base_directory;
+	}
+
+	# Do the actual capture
+	if (defined($gkv)) {
+		if ($gkv == $GKV_SYS) {
+			$build = adjust_kernel_dir($dir, $build);
+		}
+		if (@kernel_directory) {
+			$dir = copy_gcov_dir($dir, @kernel_directory);	
+		}
+		kernel_capture_from_dir($dir, $gkv, $build);
+	} else {
+		# Build directory needs to be passed to geninfo
+		$base_directory = $build;
+		lcov_geninfo($dir);
 	}
 }
 
@@ -731,11 +1323,11 @@
 		# Print info string
 		if ($to_file)
 		{
-			print(@_)
+			printf(@_)
 		}
 		else
 		{
-			# Don't interfer with the .info output to STDOUT
+			# Don't interfere with the .info output to STDOUT
 			printf(STDERR @_);
 		}
 	}
@@ -743,106 +1335,6 @@
 
 
 #
-# Check if the gcov kernel module is loaded. If it is, exit, if not, try
-# to load it.
-#
-# Die on error.
-#
-
-sub check_and_load_kernel_module()
-{
-	my $module_name;
-
-	# Is it loaded already?
-	stat("$gcov_dir");
-	if (-r _) { return(); }
-
-	info("Loading required gcov kernel module.\n");
-
-	# Do we have access to the insmod tool?
-	stat($insmod_tool);
-	if (!-x _)
-	{
-		die("ERROR: need insmod tool ($insmod_tool) to access kernel ".
-		    "coverage data!\n");
-	}
-	# Do we have access to the modprobe tool?
-	stat($modprobe_tool);
-	if (!-x _)
-	{
-		die("ERROR: need modprobe tool ($modprobe_tool) to access ".
-		    "kernel coverage data!\n");
-	}
-
-	# Try some possibilities of where the gcov kernel module may be found
-	foreach $module_name (@gcovmod)
-	{
-		# Try to load module from system wide module directory
-		# /lib/modules
-		if (system_no_output(3, $modprobe_tool, $module_name) == 0)
-		{
-			# Succeeded
-			$need_unload = $module_name;
-			return();
-		}
-
-		# Try to load linux 2.5/2.6 module from tool directory
-		if (system_no_output(3, $insmod_tool,
-				      "$tool_dir/$module_name.ko") == 0)
-		{
-			# Succeeded
-			$need_unload = $module_name;
-			return();
-		}
-
-		# Try to load linux 2.4 module from tool directory
-		if (system_no_output(3, $insmod_tool,
-				     "$tool_dir/$module_name.o") == 0)
-		{
-			# Succeeded
-			$need_unload = $module_name;
-			return();
-		}
-	}
-
-	# Hm, loading failed - maybe we aren't root?
-	if ($> != 0)
-	{
-		die("ERROR: need root access to load kernel module!\n");
-	}
-
-	die("ERROR: cannot load required gcov kernel module!\n");
-}
-
-
-#
-# unload_module()
-#
-# Unload the gcov kernel module.
-#
-
-sub unload_module($)
-{
-	my $module = $_[0];
-
-	info("Unloading kernel module $module\n");
-
-	# Do we have access to the rmmod tool?
-	stat($rmmod_tool);
-	if (!-x _)
-	{
-		warn("WARNING: cannot execute rmmod tool at $rmmod_tool - ".
-		     "gcov module still loaded!\n");
-	}
-
-	# Unload gcov kernel module
-	system_no_output(1, $rmmod_tool, $module)
-		and warn("WARNING: cannot unload gcov kernel module ".
-		         "$module!\n");
-}
-
-
-#
 # create_temp_dir()
 #
 # Create a temporary directory and return its path.
@@ -852,24 +1344,200 @@
 
 sub create_temp_dir()
 {
-	my $dirname;
-	my $number = sprintf("%d", rand(1000));
+	my $dir;
 
-	# Endless loops are evil
-	while ($number++ < 1000)
-	{
-		$dirname = "$tmp_dir/$tmp_prefix$number";
-		stat($dirname);
-		if (-e _) { next; }
+	if (defined($tmp_dir)) {
+		$dir = tempdir(DIR => $tmp_dir, CLEANUP => 1);
+	} else {
+		$dir = tempdir(CLEANUP => 1);
+	}
+	if (!defined($dir)) {
+		die("ERROR: cannot create temporary directory\n");
+	}
+	push(@temp_dirs, $dir);
 
-		mkdir($dirname)
-			or die("ERROR: cannot create temporary directory ".
-			       "$dirname!\n");
+	return $dir;
+}
 
-		return($dirname);
+
+#
+# br_taken_to_num(taken)
+#
+# Convert a branch taken value .info format to number format.
+#
+
+sub br_taken_to_num($)
+{
+	my ($taken) = @_;
+
+	return 0 if ($taken eq '-');
+	return $taken + 1;
+}
+
+
+#
+# br_num_to_taken(taken)
+#
+# Convert a branch taken value in number format to .info format.
+#
+
+sub br_num_to_taken($)
+{
+	my ($taken) = @_;
+
+	return '-' if ($taken == 0);
+	return $taken - 1;
+}
+
+
+#
+# br_taken_add(taken1, taken2)
+#
+# Return the result of taken1 + taken2 for 'branch taken' values.
+#
+
+sub br_taken_add($$)
+{
+	my ($t1, $t2) = @_;
+
+	return $t1 if (!defined($t2));
+	return $t2 if (!defined($t1));
+	return $t1 if ($t2 eq '-');
+	return $t2 if ($t1 eq '-');
+	return $t1 + $t2;
+}
+
+
+#
+# br_taken_sub(taken1, taken2)
+#
+# Return the result of taken1 - taken2 for 'branch taken' values. Return 0
+# if the result would become negative.
+#
+
+sub br_taken_sub($$)
+{
+	my ($t1, $t2) = @_;
+
+	return $t1 if (!defined($t2));
+	return undef if (!defined($t1));
+	return $t1 if ($t1 eq '-');
+	return $t1 if ($t2 eq '-');
+	return 0 if $t2 > $t1;
+	return $t1 - $t2;
+}
+
+
+#
+#
+# br_ivec_len(vector)
+#
+# Return the number of entries in the branch coverage vector.
+#
+
+sub br_ivec_len($)
+{
+	my ($vec) = @_;
+
+	return 0 if (!defined($vec));
+	return (length($vec) * 8 / $BR_VEC_WIDTH) / $BR_VEC_ENTRIES;
+}
+
+
+#
+# br_ivec_push(vector, block, branch, taken)
+#
+# Add an entry to the branch coverage vector. If an entry with the same
+# branch ID already exists, add the corresponding taken values.
+#
+
+sub br_ivec_push($$$$)
+{
+	my ($vec, $block, $branch, $taken) = @_;
+	my $offset;
+	my $num = br_ivec_len($vec);
+	my $i;
+
+	$vec = "" if (!defined($vec));
+
+	# Check if branch already exists in vector
+	for ($i = 0; $i < $num; $i++) {
+		my ($v_block, $v_branch, $v_taken) = br_ivec_get($vec, $i);
+
+		next if ($v_block != $block || $v_branch != $branch);
+
+		# Add taken counts
+		$taken = br_taken_add($taken, $v_taken);
+		last;
 	}
 
-	die("ERROR: cannot create temporary directory in $tmp_dir!\n");
+	$offset = $i * $BR_VEC_ENTRIES;
+	$taken = br_taken_to_num($taken);
+
+	# Add to vector
+	vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH) = $block;
+	vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH) = $branch;
+	vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH) = $taken;
+
+	return $vec;
+}
+
+
+#
+# br_ivec_get(vector, number)
+#
+# Return an entry from the branch coverage vector.
+#
+
+sub br_ivec_get($$)
+{
+	my ($vec, $num) = @_;
+	my $block;
+	my $branch;
+	my $taken;
+	my $offset = $num * $BR_VEC_ENTRIES;
+
+	# Retrieve data from vector
+	$block	= vec($vec, $offset + $BR_BLOCK, $BR_VEC_WIDTH);
+	$branch = vec($vec, $offset + $BR_BRANCH, $BR_VEC_WIDTH);
+	$taken	= vec($vec, $offset + $BR_TAKEN, $BR_VEC_WIDTH);
+
+	# Decode taken value from an integer
+	$taken = br_num_to_taken($taken);
+
+	return ($block, $branch, $taken);
+}
+
+
+#
+# get_br_found_and_hit(brcount)
+#
+# Return (br_found, br_hit) for brcount
+#
+
+sub get_br_found_and_hit($)
+{
+	my ($brcount) = @_;
+	my $line;
+	my $br_found = 0;
+	my $br_hit = 0;
+
+	foreach $line (keys(%{$brcount})) {
+		my $brdata = $brcount->{$line};
+		my $i;
+		my $num = br_ivec_len($brdata);
+
+		for ($i = 0; $i < $num; $i++) {
+			my $taken;
+
+			(undef, undef, $taken) = br_ivec_get($brdata, $i);
+
+			$br_found++;
+			$br_hit++ if ($taken ne "-" && $taken > 0);
+		}
+	}
+
+	return ($br_found, $br_hit);
 }
 
 
@@ -889,16 +1557,22 @@
 #        "check" -> \%checkdata
 #        "testfnc" -> \%testfncdata
 #        "sumfnc"  -> \%sumfnccount
+#        "testbr"  -> \%testbrdata
+#        "sumbr"   -> \%sumbrcount
 #
 # %testdata   : name of test affecting this file -> \%testcount
 # %testfncdata: name of test affecting this file -> \%testfnccount
+# %testbrdata:  name of test affecting this file -> \%testbrcount
 #
 # %testcount   : line number   -> execution count for a single test
 # %testfnccount: function name -> execution count for a single test
+# %testbrcount : line number   -> branch coverage data for a single test
 # %sumcount    : line number   -> execution count for all tests
 # %sumfnccount : function name -> execution count for all tests
+# %sumbrcount  : line number   -> branch coverage data for all tests
 # %funcdata    : function name -> line number
 # %checkdata   : line number   -> checksum of source code line
+# $brdata      : vector of items: block, branch, taken
 # 
 # Note that .info file sections referring to the same file and test name
 # will automatically be combined by adding all execution counts.
@@ -923,6 +1597,9 @@
 	my $testfncdata;
 	my $testfnccount;
 	my $sumfnccount;
+	my $testbrdata;
+	my $testbrcount;
+	my $sumbrcount;
 	my $line;			# Current line read from .info file
 	my $testname;			# Current test name
 	my $filename;			# Current filename
@@ -961,14 +1638,14 @@
 				"compressed file $_[0]!\n");
 
 		# Open compressed file
-		open(INFO_HANDLE, "gunzip -c $_[0]|")
+		open(INFO_HANDLE, "-|", "gunzip -c '$_[0]'")
 			or die("ERROR: cannot start gunzip to decompress ".
 			       "file $_[0]!\n");
 	}
 	else
 	{
 		# Open decompressed file
-		open(INFO_HANDLE, $_[0])
+		open(INFO_HANDLE, "<", $_[0])
 			or die("ERROR: cannot read file $_[0]!\n");
 	}
 
@@ -981,7 +1658,7 @@
 		# Switch statement
 		foreach ($line)
 		{
-			/^TN:([^,]*)/ && do
+			/^TN:([^,]*)(,diff)?/ && do
 			{
 				# Test name information found
 				$testname = defined($1) ? $1 : "";
@@ -989,6 +1666,7 @@
 				{
 					$changed_testname = 1;
 				}
+				$testname .= $2 if (defined($2));
 				last;
 			};
 
@@ -1000,18 +1678,21 @@
 
 				$data = $result{$filename};
 				($testdata, $sumcount, $funcdata, $checkdata,
-				 $testfncdata, $sumfnccount) =
+				 $testfncdata, $sumfnccount, $testbrdata,
+				 $sumbrcount) =
 					get_info_entry($data);
 
 				if (defined($testname))
 				{
 					$testcount = $testdata->{$testname};
 					$testfnccount = $testfncdata->{$testname};
+					$testbrcount = $testbrdata->{$testname};
 				}
 				else
 				{
 					$testcount = {};
 					$testfnccount = {};
+					$testbrcount = {};
 				}
 				last;
 			};
@@ -1055,6 +1736,8 @@
 
 			/^FN:(\d+),([^,]+)/ && do
 			{
+				last if (!$func_coverage);
+
 				# Function data found, add to structure
 				$funcdata->{$2} = $1;
 
@@ -1073,6 +1756,8 @@
 
 			/^FNDA:(\d+),([^,]+)/ && do
 			{
+				last if (!$func_coverage);
+
 				# Function call count found, add to structure
 				# Add summary counts
 				$sumfnccount->{$2} += $1;
@@ -1084,6 +1769,28 @@
 				}
 				last;
 			};
+
+			/^BRDA:(\d+),(\d+),(\d+),(\d+|-)/ && do {
+				# Branch coverage data found
+				my ($line, $block, $branch, $taken) =
+				   ($1, $2, $3, $4);
+
+				last if (!$br_coverage);
+				$sumbrcount->{$line} =
+					br_ivec_push($sumbrcount->{$line},
+						     $block, $branch, $taken);
+
+				# Add test-specific counts
+				if (defined($testname)) {
+					$testbrcount->{$line} =
+						br_ivec_push(
+							$testbrcount->{$line},
+							$block, $branch,
+							$taken);
+				}
+				last;
+			};
+
 			/^end_of_record/ && do
 			{
 				# Found end of section marker
@@ -1096,12 +1803,16 @@
 							$testcount;
 						$testfncdata->{$testname} =
 							$testfnccount;
+						$testbrdata->{$testname} =
+							$testbrcount;
 					}	
 
 					set_info_entry($data, $testdata,
 						       $sumcount, $funcdata,
 						       $checkdata, $testfncdata,
-						       $sumfnccount);
+						       $sumfnccount,
+						       $testbrdata,
+						       $sumbrcount);
 					$result{$filename} = $data;
 					last;
 				}
@@ -1119,7 +1830,8 @@
 		$data = $result{$filename};
 
 		($testdata, $sumcount, undef, undef, $testfncdata,
-		 $sumfnccount) = get_info_entry($data);
+		 $sumfnccount, $testbrdata, $sumbrcount) =
+			get_info_entry($data);
 
 		# Filter out empty files
 		if (scalar(keys(%{$sumcount})) == 0)
@@ -1158,6 +1870,14 @@
 			}
 		}
 		$data->{"f_hit"} = $hitcount;
+
+		# Get found/hit values for branch data
+		{
+			my ($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
+
+			$data->{"b_found"} = $br_found;
+			$data->{"b_hit"} = $br_hit;
+		}
 	}
 
 	if (scalar(keys(%result)) == 0)
@@ -1185,8 +1905,9 @@
 # Retrieve data from an entry of the structure generated by read_info_file().
 # Return a list of references to hashes:
 # (test data hash ref, sum count hash ref, funcdata hash ref, checkdata hash
-#  ref, testfncdata hash ref, sumfnccount hash ref, lines found, lines hit,
-#  functions found, functions hit)
+#  ref, testfncdata hash ref, sumfnccount hash ref, testbrdata hash ref,
+#  sumbrcount hash ref, lines found, lines hit, functions found,
+#  functions hit, branches found, branches hit)
 #
 
 sub get_info_entry($)
@@ -1197,26 +1918,32 @@
 	my $checkdata_ref = $_[0]->{"check"};
 	my $testfncdata = $_[0]->{"testfnc"};
 	my $sumfnccount = $_[0]->{"sumfnc"};
+	my $testbrdata = $_[0]->{"testbr"};
+	my $sumbrcount = $_[0]->{"sumbr"};
 	my $lines_found = $_[0]->{"found"};
 	my $lines_hit = $_[0]->{"hit"};
 	my $f_found = $_[0]->{"f_found"};
 	my $f_hit = $_[0]->{"f_hit"};
+	my $br_found = $_[0]->{"b_found"};
+	my $br_hit = $_[0]->{"b_hit"};
 
 	return ($testdata_ref, $sumcount_ref, $funcdata_ref, $checkdata_ref,
-		$testfncdata, $sumfnccount, $lines_found, $lines_hit,
-		$f_found, $f_hit);
+		$testfncdata, $sumfnccount, $testbrdata, $sumbrcount,
+		$lines_found, $lines_hit, $f_found, $f_hit,
+		$br_found, $br_hit);
 }
 
 
 #
 # set_info_entry(hash_ref, testdata_ref, sumcount_ref, funcdata_ref,
-#                checkdata_ref, testfncdata_ref, sumfcncount_ref[,lines_found,
-#                lines_hit, f_found, f_hit])
+#                checkdata_ref, testfncdata_ref, sumfcncount_ref,
+#                testbrdata_ref, sumbrcount_ref[,lines_found,
+#                lines_hit, f_found, f_hit, $b_found, $b_hit])
 #
 # Update the hash referenced by HASH_REF with the provided data references.
 #
 
-sub set_info_entry($$$$$$$;$$$$)
+sub set_info_entry($$$$$$$$$;$$$$$$)
 {
 	my $data_ref = $_[0];
 
@@ -1226,11 +1953,15 @@
 	$data_ref->{"check"} = $_[4];
 	$data_ref->{"testfnc"} = $_[5];
 	$data_ref->{"sumfnc"} = $_[6];
+	$data_ref->{"testbr"} = $_[7];
+	$data_ref->{"sumbr"} = $_[8];
 
-	if (defined($_[7])) { $data_ref->{"found"} = $_[7]; }
-	if (defined($_[8])) { $data_ref->{"hit"} = $_[8]; }
-	if (defined($_[9])) { $data_ref->{"f_found"} = $_[9]; }
-	if (defined($_[10])) { $data_ref->{"f_hit"} = $_[10]; }
+	if (defined($_[9])) { $data_ref->{"found"} = $_[9]; }
+	if (defined($_[10])) { $data_ref->{"hit"} = $_[10]; }
+	if (defined($_[11])) { $data_ref->{"f_found"} = $_[11]; }
+	if (defined($_[12])) { $data_ref->{"f_hit"} = $_[12]; }
+	if (defined($_[13])) { $data_ref->{"b_found"} = $_[13]; }
+	if (defined($_[14])) { $data_ref->{"b_hit"} = $_[14]; }
 }
 
 
@@ -1338,7 +2069,9 @@
 	my %result;
 	my $func;
 
-	%result = %{$funcdata1};
+	if (defined($funcdata1)) {
+		%result = %{$funcdata1};
+	}
 
 	foreach $func (keys(%{$funcdata2})) {
 		my $line1 = $result{$func};
@@ -1370,7 +2103,9 @@
 	my $f_hit;
 	my $function;
 
-	%result = %{$fnccount1};
+	if (defined($fnccount1)) {
+		%result = %{$fnccount1};
+	}
 	foreach $function (keys(%{$fnccount2})) {
 		$result{$function} += $fnccount2->{$function};
 	}
@@ -1424,6 +2159,167 @@
 	return \%result;
 }
 
+
+#
+# brcount_to_db(brcount)
+#
+# Convert brcount data to the following format:
+#
+# db:          line number    -> block hash
+# block hash:  block number   -> branch hash
+# branch hash: branch number  -> taken value
+#
+
+sub brcount_to_db($)
+{
+	my ($brcount) = @_;
+	my $line;
+	my $db;
+
+	# Add branches from first count to database
+	foreach $line (keys(%{$brcount})) {
+		my $brdata = $brcount->{$line};
+		my $i;
+		my $num = br_ivec_len($brdata);
+
+		for ($i = 0; $i < $num; $i++) {
+			my ($block, $branch, $taken) = br_ivec_get($brdata, $i);
+
+			$db->{$line}->{$block}->{$branch} = $taken;
+		}
+	}
+
+	return $db;
+}
+
+
+#
+# db_to_brcount(db)
+#
+# Convert branch coverage data back to brcount format.
+#
+
+sub db_to_brcount($)
+{
+	my ($db) = @_;
+	my $line;
+	my $brcount = {};
+	my $br_found = 0;
+	my $br_hit = 0;
+
+	# Convert database back to brcount format
+	foreach $line (sort({$a <=> $b} keys(%{$db}))) {
+		my $ldata = $db->{$line};
+		my $brdata;
+		my $block;
+
+		foreach $block (sort({$a <=> $b} keys(%{$ldata}))) {
+			my $bdata = $ldata->{$block};
+			my $branch;
+
+			foreach $branch (sort({$a <=> $b} keys(%{$bdata}))) {
+				my $taken = $bdata->{$branch};
+
+				$br_found++;
+				$br_hit++ if ($taken ne "-" && $taken > 0);
+				$brdata = br_ivec_push($brdata, $block,
+						       $branch, $taken);
+			}
+		}
+		$brcount->{$line} = $brdata;
+	}
+
+	return ($brcount, $br_found, $br_hit);
+}
+
+
+# combine_brcount(brcount1, brcount2, type)
+#
+# If add is BR_ADD, add branch coverage data and return list (brcount_added,
+# br_found, br_hit). If add is BR_SUB, subtract the taken values of brcount2
+# from brcount1 and return (brcount_sub, br_found, br_hit).
+#
+
+sub combine_brcount($$$)
+{
+	my ($brcount1, $brcount2, $type) = @_;
+	my $line;
+	my $block;
+	my $branch;
+	my $taken;
+	my $db;
+	my $br_found = 0;
+	my $br_hit = 0;
+	my $result;
+
+	# Convert branches from first count to database
+	$db = brcount_to_db($brcount1);
+	# Combine values from database and second count
+	foreach $line (keys(%{$brcount2})) {
+		my $brdata = $brcount2->{$line};
+		my $num = br_ivec_len($brdata);
+		my $i;
+
+		for ($i = 0; $i < $num; $i++) {
+			($block, $branch, $taken) = br_ivec_get($brdata, $i);
+			my $new_taken = $db->{$line}->{$block}->{$branch};
+
+			if ($type == $BR_ADD) {
+				$new_taken = br_taken_add($new_taken, $taken);
+			} elsif ($type == $BR_SUB) {
+				$new_taken = br_taken_sub($new_taken, $taken);
+			}
+			$db->{$line}->{$block}->{$branch} = $new_taken
+				if (defined($new_taken));
+		}
+	}
+	# Convert database back to brcount format
+	($result, $br_found, $br_hit) = db_to_brcount($db);
+
+	return ($result, $br_found, $br_hit);
+}
+
+
+#
+# add_testbrdata(testbrdata1, testbrdata2)
+#
+# Add branch coverage data for several tests. Return reference to
+# added_testbrdata.
+#
+
+sub add_testbrdata($$)
+{
+	my ($testbrdata1, $testbrdata2) = @_;
+	my %result;
+	my $testname;
+
+	foreach $testname (keys(%{$testbrdata1})) {
+		if (defined($testbrdata2->{$testname})) {
+			my $brcount;
+
+			# Branch coverage data for this testname exists
+			# in both data sets: add
+			($brcount) = combine_brcount(
+				$testbrdata1->{$testname},
+				$testbrdata2->{$testname}, $BR_ADD);
+			$result{$testname} = $brcount;
+			next;
+		}
+		# Branch coverage data for this testname is unique to
+		# data set 1: copy
+		$result{$testname} = $testbrdata1->{$testname};
+	}
+
+	# Add count data for testnames unique to data set 2
+	foreach $testname (keys(%{$testbrdata2})) {
+		if (!defined($result{$testname})) {
+			$result{$testname} = $testbrdata2->{$testname};
+		}
+	}
+	return \%result;
+}
+
+
 #
 # combine_info_entries(entry_ref1, entry_ref2, filename)
 #
@@ -1440,6 +2336,8 @@
 	my $checkdata1;
 	my $testfncdata1;
 	my $sumfnccount1;
+	my $testbrdata1;
+	my $sumbrcount1;
 
 	my $entry2 = $_[1];	# Reference to hash containing second entry
 	my $testdata2;
@@ -1448,6 +2346,8 @@
 	my $checkdata2;
 	my $testfncdata2;
 	my $sumfnccount2;
+	my $testbrdata2;
+	my $sumbrcount2;
 
 	my %result;		# Hash containing combined entry
 	my %result_testdata;
@@ -1455,19 +2355,23 @@
 	my $result_funcdata;
 	my $result_testfncdata;
 	my $result_sumfnccount;
+	my $result_testbrdata;
+	my $result_sumbrcount;
 	my $lines_found;
 	my $lines_hit;
 	my $f_found;
 	my $f_hit;
+	my $br_found;
+	my $br_hit;
 
 	my $testname;
 	my $filename = $_[2];
 
 	# Retrieve data
 	($testdata1, $sumcount1, $funcdata1, $checkdata1, $testfncdata1,
-	 $sumfnccount1) = get_info_entry($entry1);
+	 $sumfnccount1, $testbrdata1, $sumbrcount1) = get_info_entry($entry1);
 	($testdata2, $sumcount2, $funcdata2, $checkdata2, $testfncdata2,
-	 $sumfnccount2) = get_info_entry($entry2);
+	 $sumfnccount2, $testbrdata2, $sumbrcount2) = get_info_entry($entry2);
 
 	# Merge checksums
 	$checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename);
@@ -1479,7 +2383,12 @@
 	$result_testfncdata = add_testfncdata($testfncdata1, $testfncdata2);
 	($result_sumfnccount, $f_found, $f_hit) =
 		add_fnccount($sumfnccount1, $sumfnccount2);
-	
+
+	# Combine branch coverage data
+	$result_testbrdata = add_testbrdata($testbrdata1, $testbrdata2);
+	($result_sumbrcount, $br_found, $br_hit) =
+		combine_brcount($sumbrcount1, $sumbrcount2, $BR_ADD);
+
 	# Combine testdata
 	foreach $testname (keys(%{$testdata1}))
 	{
@@ -1522,8 +2431,9 @@
 	# Store result
 	set_info_entry(\%result, \%result_testdata, $result_sumcount,
 		       $result_funcdata, $checkdata1, $result_testfncdata,
-		       $result_sumfnccount, $lines_found, $lines_hit,
-		       $f_found, $f_hit);
+		       $result_sumfnccount, $result_testbrdata,
+		       $result_sumbrcount, $lines_found, $lines_hit,
+		       $f_found, $f_hit, $br_found, $br_hit);
 
 	return(\%result);
 }
@@ -1573,6 +2483,7 @@
 	my $total_trace;
 	my $current_trace;
 	my $tracefile;
+	my @result;
 	local *INFO_HANDLE;
 
 	info("Combining tracefiles.\n");
@@ -1595,15 +2506,17 @@
 	if ($to_file)
 	{
 		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
+		open(INFO_HANDLE, ">", $output_filename)
 			or die("ERROR: cannot write to $output_filename!\n");
-		write_info_file(*INFO_HANDLE, $total_trace);
+		@result = write_info_file(*INFO_HANDLE, $total_trace);
 		close(*INFO_HANDLE);
 	}
 	else
 	{
-		write_info_file(*STDOUT, $total_trace);
+		@result = write_info_file(*STDOUT, $total_trace);
 	}
+
+	return @result;
 }
 
 
@@ -1623,25 +2536,48 @@
 	my $checkdata;
 	my $testfncdata;
 	my $sumfnccount;
+	my $testbrdata;
+	my $sumbrcount;
 	my $testname;
 	my $line;
 	my $func;
 	my $testcount;
 	my $testfnccount;
+	my $testbrcount;
 	my $found;
 	my $hit;
 	my $f_found;
 	my $f_hit;
+	my $br_found;
+	my $br_hit;
+	my $ln_total_found = 0;
+	my $ln_total_hit = 0;
+	my $fn_total_found = 0;
+	my $fn_total_hit = 0;
+	my $br_total_found = 0;
+	my $br_total_hit = 0;
 
-	foreach $source_file (keys(%data))
+	foreach $source_file (sort(keys(%data)))
 	{
 		$entry = $data{$source_file};
 		($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
-		 $sumfnccount) = get_info_entry($entry);
-		foreach $testname (keys(%{$testdata}))
+		 $sumfnccount, $testbrdata, $sumbrcount, $found, $hit,
+		 $f_found, $f_hit, $br_found, $br_hit) =
+			get_info_entry($entry);
+
+		# Add to totals
+		$ln_total_found += $found;
+		$ln_total_hit += $hit;
+		$fn_total_found += $f_found;
+		$fn_total_hit += $f_hit;
+		$br_total_found += $br_found;
+		$br_total_hit += $br_hit;
+
+		foreach $testname (sort(keys(%{$testdata})))
 		{
 			$testcount = $testdata->{$testname};
 			$testfnccount = $testfncdata->{$testname};
+			$testbrcount = $testbrdata->{$testname};
 			$found = 0;
 			$hit   = 0;
 
@@ -1666,6 +2602,31 @@
 			print(INFO_HANDLE "FNF:$f_found\n");
 			print(INFO_HANDLE "FNH:$f_hit\n");
 
+			# Write branch related data
+			$br_found = 0;
+			$br_hit = 0;
+			foreach $line (sort({$a <=> $b}
+					    keys(%{$testbrcount}))) {
+				my $brdata = $testbrcount->{$line};
+				my $num = br_ivec_len($brdata);
+				my $i;
+
+				for ($i = 0; $i < $num; $i++) {
+					my ($block, $branch, $taken) =
+						br_ivec_get($brdata, $i);
+
+					print(INFO_HANDLE "BRDA:$line,$block,".
+					      "$branch,$taken\n");
+					$br_found++;
+					$br_hit++ if ($taken ne '-' &&
+						      $taken > 0);
+				}
+			}
+			if ($br_found > 0) {
+				print(INFO_HANDLE "BRF:$br_found\n");
+				print(INFO_HANDLE "BRH:$br_hit\n");
+			}
+
 			# Write line related data
 			foreach $line (sort({$a <=> $b} keys(%{$testcount})))
 			{
@@ -1686,13 +2647,16 @@
 			print(INFO_HANDLE "end_of_record\n");
 		}
 	}
+
+	return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit,
+		$br_total_found, $br_total_hit);
 }
 
 
 #
 # transform_pattern(pattern)
 #
-# Transform shell wildcard expression to equivalent PERL regular expression.
+# Transform shell wildcard expression to equivalent Perl regular expression.
 # Return transformed pattern.
 #
 
@@ -1739,6 +2703,7 @@
 	my $pattern;
 	my @pattern_list;
 	my $extracted = 0;
+	my @result;
 	local *INFO_HANDLE;
 
 	# Need perlreg expressions instead of shell pattern
@@ -1771,15 +2736,17 @@
 	{
 		info("Extracted $extracted files\n");
 		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
+		open(INFO_HANDLE, ">", $output_filename)
 			or die("ERROR: cannot write to $output_filename!\n");
-		write_info_file(*INFO_HANDLE, $data);
+		@result = write_info_file(*INFO_HANDLE, $data);
 		close(*INFO_HANDLE);
 	}
 	else
 	{
-		write_info_file(*STDOUT, $data);
+		@result = write_info_file(*STDOUT, $data);
 	}
+
+	return @result;
 }
 
 
@@ -1795,6 +2762,7 @@
 	my $pattern;
 	my @pattern_list;
 	my $removed = 0;
+	my @result;
 	local *INFO_HANDLE;
 
 	# Need perlreg expressions instead of shell pattern
@@ -1824,18 +2792,128 @@
 	{
 		info("Deleted $removed files\n");
 		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
+		open(INFO_HANDLE, ">", $output_filename)
 			or die("ERROR: cannot write to $output_filename!\n");
-		write_info_file(*INFO_HANDLE, $data);
+		@result = write_info_file(*INFO_HANDLE, $data);
 		close(*INFO_HANDLE);
 	}
 	else
 	{
-		write_info_file(*STDOUT, $data);
+		@result = write_info_file(*STDOUT, $data);
 	}
+
+	return @result;
 }
 
 
+# get_prefix(max_width, max_percentage_too_long, path_list)
+#
+# Return a path prefix that satisfies the following requirements:
+# - is shared by more paths in path_list than any other prefix
+# - the percentage of paths which would exceed the given max_width length
+#   after applying the prefix does not exceed max_percentage_too_long
+#
+# If multiple prefixes satisfy all requirements, the longest prefix is
+# returned. Return an empty string if no prefix could be found.
+
+sub get_prefix($$@)
+{
+	my ($max_width, $max_long, @path_list) = @_;
+	my $path;
+	my $ENTRY_NUM = 0;
+	my $ENTRY_LONG = 1;
+	my %prefix;
+
+	# Build prefix hash
+	foreach $path (@path_list) {
+		my ($v, $d, $f) = splitpath($path);
+		my @dirs = splitdir($d);
+		my $p_len = length($path);
+		my $i;
+
+		# Remove trailing '/'
+		pop(@dirs) if ($dirs[scalar(@dirs) - 1] eq '');
+		for ($i = 0; $i < scalar(@dirs); $i++) {
+			my $subpath = catpath($v, catdir(@dirs[0..$i]), '');
+			my $entry = $prefix{$subpath};
+
+			$entry = [ 0, 0 ] if (!defined($entry));
+			$entry->[$ENTRY_NUM]++;
+			if (($p_len - length($subpath) - 1) > $max_width) {
+				$entry->[$ENTRY_LONG]++;
+			}
+			$prefix{$subpath} = $entry;
+		}
+	}
+	# Find suitable prefix (sort descending by two keys: 1. number of
+	# entries covered by a prefix, 2. length of prefix)
+	foreach $path (sort {($prefix{$a}->[$ENTRY_NUM] ==
+			      $prefix{$b}->[$ENTRY_NUM]) ?
+				length($b) <=> length($a) :
+				$prefix{$b}->[$ENTRY_NUM] <=>
+				$prefix{$a}->[$ENTRY_NUM]}
+				keys(%prefix)) {
+		my ($num, $long) = @{$prefix{$path}};
+
+		# Check for additional requirement: number of filenames
+		# that would be too long may not exceed a certain percentage
+		if ($long <= $num * $max_long / 100) {
+			return $path;
+		}
+	}
+
+	return "";
+}
+
+
+#
+# shorten_filename(filename, width)
+#
+# Truncate filename if it is longer than width characters.
+#
+
+sub shorten_filename($$)
+{
+	my ($filename, $width) = @_;
+	my $l = length($filename);
+	my $s;
+	my $e;
+
+	return $filename if ($l <= $width);
+	$e = int(($width - 3) / 2);
+	$s = $width - 3 - $e;
+
+	return substr($filename, 0, $s).'...'.substr($filename, $l - $e);
+}
+
+
+sub shorten_number($$)
+{
+	my ($number, $width) = @_;
+	my $result = sprintf("%*d", $width, $number);
+
+	return $result if (length($result) <= $width);
+	$number = $number / 1000;
+	return $result if (length($result) <= $width);
+	$result = sprintf("%*dk", $width - 1, $number);
+	return $result if (length($result) <= $width);
+	$number = $number / 1000;
+	$result = sprintf("%*dM", $width - 1, $number);
+	return $result if (length($result) <= $width);
+	return '#';
+}
+
+sub shorten_rate($$$)
+{
+	my ($hit, $found, $width) = @_;
+	my $result = rate($hit, $found, "%", 1, $width);
+
+	return $result if (length($result) <= $width);
+	$result = rate($hit, $found, "%", 0, $width);
+	return $result if (length($result) <= $width);
+	return "#";
+}
+
 #
 # list()
 #
@@ -1847,17 +2925,250 @@
 	my $found;
 	my $hit;
 	my $entry;
+	my $fn_found;
+	my $fn_hit;
+	my $br_found;
+	my $br_hit;
+	my $total_found = 0;
+	my $total_hit = 0;
+	my $fn_total_found = 0;
+	my $fn_total_hit = 0;
+	my $br_total_found = 0;
+	my $br_total_hit = 0;
+	my $prefix;
+	my $strlen = length("Filename");
+	my $format;
+	my $heading1;
+	my $heading2;
+	my @footer;
+	my $barlen;
+	my $rate;
+	my $fnrate;
+	my $brrate;
+	my $lastpath;
+	my $F_LN_NUM = 0;
+	my $F_LN_RATE = 1;
+	my $F_FN_NUM = 2;
+	my $F_FN_RATE = 3;
+	my $F_BR_NUM = 4;
+	my $F_BR_RATE = 5;
+	my @fwidth_narrow = (5, 5, 3, 5, 4, 5);
+	my @fwidth_wide = (6, 5, 5, 5, 6, 5);
+	my @fwidth = @fwidth_wide;
+	my $w;
+	my $max_width = $opt_list_width;
+	my $max_long = $opt_list_truncate_max;
+	my $fwidth_narrow_length;
+	my $fwidth_wide_length;
+	my $got_prefix = 0;
+	my $root_prefix = 0;
 
-	info("Listing contents of $list:\n");
+	# Calculate total width of narrow fields
+	$fwidth_narrow_length = 0;
+	foreach $w (@fwidth_narrow) {
+		$fwidth_narrow_length += $w + 1;
+	}
+	# Calculate total width of wide fields
+	$fwidth_wide_length = 0;
+	foreach $w (@fwidth_wide) {
+		$fwidth_wide_length += $w + 1;
+	}
+	# Get common file path prefix
+	$prefix = get_prefix($max_width - $fwidth_narrow_length, $max_long,
+			     keys(%{$data}));
+	$root_prefix = 1 if ($prefix eq rootdir());
+	$got_prefix = 1 if (length($prefix) > 0);
+	$prefix =~ s/\/$//;
+	# Get longest filename length
+	foreach $filename (keys(%{$data})) {
+		if (!$opt_list_full_path) {
+			if (!$got_prefix || !$root_prefix &&
+			    !($filename =~ s/^\Q$prefix\/\E//)) {
+				my ($v, $d, $f) = splitpath($filename);
 
-	# List all files
+				$filename = $f;
+			}
+		}
+		# Determine maximum length of entries
+		if (length($filename) > $strlen) {
+			$strlen = length($filename)
+		}
+	}
+	if (!$opt_list_full_path) {
+		my $blanks;
+
+		$w = $fwidth_wide_length;
+		# Check if all columns fit into max_width characters
+		if ($strlen + $fwidth_wide_length > $max_width) {
+			# Use narrow fields
+			@fwidth = @fwidth_narrow;
+			$w = $fwidth_narrow_length;
+			if (($strlen + $fwidth_narrow_length) > $max_width) {
+				# Truncate filenames at max width
+				$strlen = $max_width - $fwidth_narrow_length;
+			}
+		}
+		# Add some blanks between filename and fields if possible
+		$blanks = int($strlen * 0.5);
+		$blanks = 4 if ($blanks < 4);
+		$blanks = 8 if ($blanks > 8);
+		if (($strlen + $w + $blanks) < $max_width) {
+			$strlen += $blanks;
+		} else {
+			$strlen = $max_width - $w;
+		}
+	}
+	# Filename
+	$w = $strlen;
+	$format		= "%-${w}s|";
+	$heading1 	= sprintf("%*s|", $w, "");
+	$heading2 	= sprintf("%-*s|", $w, "Filename");
+	$barlen		= $w + 1;
+	# Line coverage rate
+	$w = $fwidth[$F_LN_RATE];
+	$format		.= "%${w}s ";
+	$heading1 	.= sprintf("%-*s |", $w + $fwidth[$F_LN_NUM],
+				   "Lines");
+	$heading2 	.= sprintf("%-*s ", $w, "Rate");
+	$barlen		+= $w + 1;
+	# Number of lines
+	$w = $fwidth[$F_LN_NUM];
+	$format		.= "%${w}s|";
+	$heading2	.= sprintf("%*s|", $w, "Num");
+	$barlen		+= $w + 1;
+	# Function coverage rate
+	$w = $fwidth[$F_FN_RATE];
+	$format		.= "%${w}s ";
+	$heading1 	.= sprintf("%-*s|", $w + $fwidth[$F_FN_NUM] + 1,
+				   "Functions");
+	$heading2 	.= sprintf("%-*s ", $w, "Rate");
+	$barlen		+= $w + 1;
+	# Number of functions
+	$w = $fwidth[$F_FN_NUM];
+	$format		.= "%${w}s|";
+	$heading2	.= sprintf("%*s|", $w, "Num");
+	$barlen		+= $w + 1;
+	# Branch coverage rate
+	$w = $fwidth[$F_BR_RATE];
+	$format		.= "%${w}s ";
+	$heading1 	.= sprintf("%-*s", $w + $fwidth[$F_BR_NUM] + 1,
+				   "Branches");
+	$heading2 	.= sprintf("%-*s ", $w, "Rate");
+	$barlen		+= $w + 1;
+	# Number of branches
+	$w = $fwidth[$F_BR_NUM];
+	$format		.= "%${w}s";
+	$heading2	.= sprintf("%*s", $w, "Num");
+	$barlen		+= $w;
+	# Line end
+	$format		.= "\n";
+	$heading1	.= "\n";
+	$heading2	.= "\n";
+
+	# Print heading
+	print($heading1);
+	print($heading2);
+	print(("="x$barlen)."\n");
+
+	# Print per file information
 	foreach $filename (sort(keys(%{$data})))
 	{
+		my @file_data;
+		my $print_filename = $filename;
+
 		$entry = $data->{$filename};
-		(undef, undef, undef, undef, undef, undef, $found, $hit) =
+		if (!$opt_list_full_path) {
+			my $p;
+
+			$print_filename = $filename;
+			if (!$got_prefix || !$root_prefix &&
+			    !($print_filename =~ s/^\Q$prefix\/\E//)) {
+				my ($v, $d, $f) = splitpath($filename);
+
+				$p = catpath($v, $d, "");
+				$p =~ s/\/$//;
+				$print_filename = $f;
+			} else {
+				$p = $prefix;
+			}
+
+			if (!defined($lastpath) || $lastpath ne $p) {
+				print("\n") if (defined($lastpath));
+				$lastpath = $p;
+				print("[$lastpath/]\n") if (!$root_prefix);
+			}
+			$print_filename = shorten_filename($print_filename,
+							   $strlen);
+		}
+
+		(undef, undef, undef, undef, undef, undef, undef, undef,
+		 $found, $hit, $fn_found, $fn_hit, $br_found, $br_hit) =
 			get_info_entry($entry);
-		printf("$filename: $hit of $found lines hit\n");
+
+		# Assume zero count if there is no function data for this file
+		if (!defined($fn_found) || !defined($fn_hit)) {
+			$fn_found = 0;
+			$fn_hit = 0;
+		}
+		# Assume zero count if there is no branch data for this file
+		if (!defined($br_found) || !defined($br_hit)) {
+			$br_found = 0;
+			$br_hit = 0;
+		}
+
+		# Add line coverage totals
+		$total_found += $found;
+		$total_hit += $hit;
+		# Add function coverage totals
+		$fn_total_found += $fn_found;
+		$fn_total_hit += $fn_hit;
+		# Add branch coverage totals
+		$br_total_found += $br_found;
+		$br_total_hit += $br_hit;
+
+		# Determine line coverage rate for this file
+		$rate = shorten_rate($hit, $found, $fwidth[$F_LN_RATE]);
+		# Determine function coverage rate for this file
+		$fnrate = shorten_rate($fn_hit, $fn_found, $fwidth[$F_FN_RATE]);
+		# Determine branch coverage rate for this file
+		$brrate = shorten_rate($br_hit, $br_found, $fwidth[$F_BR_RATE]);
+
+		# Assemble line parameters
+		push(@file_data, $print_filename);
+		push(@file_data, $rate);
+		push(@file_data, shorten_number($found, $fwidth[$F_LN_NUM]));
+		push(@file_data, $fnrate);
+		push(@file_data, shorten_number($fn_found, $fwidth[$F_FN_NUM]));
+		push(@file_data, $brrate);
+		push(@file_data, shorten_number($br_found, $fwidth[$F_BR_NUM]));
+
+		# Print assembled line
+		printf($format, @file_data);
 	}
+
+	# Determine total line coverage rate
+	$rate = shorten_rate($total_hit, $total_found, $fwidth[$F_LN_RATE]);
+	# Determine total function coverage rate
+	$fnrate = shorten_rate($fn_total_hit, $fn_total_found,
+			       $fwidth[$F_FN_RATE]);
+	# Determine total branch coverage rate
+	$brrate = shorten_rate($br_total_hit, $br_total_found,
+			       $fwidth[$F_BR_RATE]);
+
+	# Print separator
+	print(("="x$barlen)."\n");
+
+	# Assemble line parameters
+	push(@footer, sprintf("%*s", $strlen, "Total:"));
+	push(@footer, $rate);
+	push(@footer, shorten_number($total_found, $fwidth[$F_LN_NUM]));
+	push(@footer, $fnrate);
+	push(@footer, shorten_number($fn_total_found, $fwidth[$F_FN_NUM]));
+	push(@footer, $brrate);
+	push(@footer, shorten_number($br_total_found, $fwidth[$F_BR_NUM]));
+
+	# Print assembled line
+	printf($format, @footer);
 }
 
 
@@ -1981,14 +3292,14 @@
 				"compressed file $diff_file!\n");
 
 		# Open compressed file
-		open(HANDLE, "gunzip -c $diff_file|")
+		open(HANDLE, "-|", "gunzip -c '$diff_file'")
 			or die("ERROR: cannot start gunzip to decompress ".
 			       "file $_[0]!\n");
 	}
 	else
 	{
 		# Open decompressed file
-		open(HANDLE, $diff_file)
+		open(HANDLE, "<", $diff_file)
 			or die("ERROR: cannot read file $_[0]!\n");
 	}
 
@@ -2155,6 +3466,28 @@
 
 
 #
+# apply_diff_to_brcount(brcount, linedata)
+#
+# Adjust line numbers of branch coverage data according to linedata.
+#
+
+sub apply_diff_to_brcount($$)
+{
+	my ($brcount, $linedata) = @_;
+	my $db;
+
+	# Convert brcount to db format
+	$db = brcount_to_db($brcount);
+	# Apply diff to db format
+	$db = apply_diff($db, $linedata);
+	# Convert db format back to brcount format
+	($brcount) = db_to_brcount($db);
+
+	return $brcount;
+}
+
+
+#
 # get_hash_max(hash_ref)
 #
 # Return the highest integer key from hash.
@@ -2235,10 +3568,16 @@
 	my $old_depth;
 	my $new_depth;
 
+	# Remove trailing slash from diff path
+	$diff_path =~ s/\/$//;
 	foreach (keys(%{$diff_data}))
 	{
+		my $sep = "";
+
+		$sep = '/' if (!/^\//);
+
 		# Try to match diff filename with filename
-		if ($filename =~ /^\Q$diff_path\E\/$_$/)
+		if ($filename =~ /^\Q$diff_path$sep$_\E$/)
 		{
 			if ($diff_name)
 			{
@@ -2432,12 +3771,17 @@
 	my $checkdata;
 	my $testfncdata;
 	my $sumfnccount;
+	my $testbrdata;
+	my $sumbrcount;
 	my $found;
 	my $hit;
 	my $f_found;
 	my $f_hit;
+	my $br_found;
+	my $br_hit;
 	my $converted = 0;
 	my $unchanged = 0;
+	my @result;
 	local *INFO_HANDLE;
 
 	($diff_data, $path_data) = read_diff($ARGV[0]);
@@ -2468,17 +3812,24 @@
 		info("Converting $filename\n");
 		$entry = $trace_data->{$filename};
 		($testdata, $sumcount, $funcdata, $checkdata, $testfncdata,
-		 $sumfnccount) = get_info_entry($entry);
+		 $sumfnccount, $testbrdata, $sumbrcount) =
+			get_info_entry($entry);
 		# Convert test data
 		foreach $testname (keys(%{$testdata}))
 		{
+			# Adjust line numbers of line coverage data
 			$testdata->{$testname} =
 				apply_diff($testdata->{$testname}, $line_hash);
+			# Adjust line numbers of branch coverage data
+			$testbrdata->{$testname} =
+				apply_diff_to_brcount($testbrdata->{$testname},
+						      $line_hash);
 			# Remove empty sets of test data
 			if (scalar(keys(%{$testdata->{$testname}})) == 0)
 			{
 				delete($testdata->{$testname});
 				delete($testfncdata->{$testname});
+				delete($testbrdata->{$testname});
 			}
 		}
 		# Rename test data to indicate conversion
@@ -2502,6 +3853,12 @@
 					$testfncdata->{$testname},
 					$testfncdata->{$testname.",diff"});
 				delete($testfncdata->{$testname.",diff"});
+				# Add branch counts
+				($testbrdata->{$testname}) = combine_brcount(
+					$testbrdata->{$testname},
+					$testbrdata->{$testname.",diff"},
+					$BR_ADD);
+				delete($testbrdata->{$testname.",diff"});
 			}
 			# Move test data to new testname
 			$testdata->{$testname.",diff"} = $testdata->{$testname};
@@ -2510,16 +3867,24 @@
 			$testfncdata->{$testname.",diff"} =
 				$testfncdata->{$testname};
 			delete($testfncdata->{$testname});
+			# Move branch count data to new testname
+			$testbrdata->{$testname.",diff"} =
+				$testbrdata->{$testname};
+			delete($testbrdata->{$testname});
 		}
 		# Convert summary of test data
 		$sumcount = apply_diff($sumcount, $line_hash);
 		# Convert function data
 		$funcdata = apply_diff_to_funcdata($funcdata, $line_hash);
+		# Convert branch coverage data
+		$sumbrcount = apply_diff_to_brcount($sumbrcount, $line_hash);
+		# Update found/hit numbers
 		# Convert checksum data
 		$checkdata = apply_diff($checkdata, $line_hash);
 		# Convert function call count data
 		adjust_fncdata($funcdata, $testfncdata, $sumfnccount);
 		($f_found, $f_hit) = get_func_found_and_hit($sumfnccount);
+		($br_found, $br_hit) = get_br_found_and_hit($sumbrcount);
 		# Update found/hit numbers
 		$found = 0;
 		$hit = 0;
@@ -2536,7 +3901,8 @@
 			# Store converted entry
 			set_info_entry($entry, $testdata, $sumcount, $funcdata,
 				       $checkdata, $testfncdata, $sumfnccount,
-				       $found, $hit, $f_found, $f_hit);
+				       $testbrdata, $sumbrcount, $found, $hit,
+				       $f_found, $f_hit, $br_found, $br_hit);
 		}
 		else
 		{
@@ -2559,17 +3925,72 @@
 	if ($to_file)
 	{
 		info("Writing data to $output_filename\n");
-		open(INFO_HANDLE, ">$output_filename")
+		open(INFO_HANDLE, ">", $output_filename)
 			or die("ERROR: cannot write to $output_filename!\n");
-		write_info_file(*INFO_HANDLE, $trace_data);
+		@result = write_info_file(*INFO_HANDLE, $trace_data);
 		close(*INFO_HANDLE);
 	}
 	else
 	{
-		write_info_file(*STDOUT, $trace_data);
+		@result = write_info_file(*STDOUT, $trace_data);
 	}
+
+	return @result;
 }
 
+#
+# summary()
+#
+
+sub summary()
+{
+	my $filename;
+	my $current;
+	my $total;
+	my $ln_total_found;
+	my $ln_total_hit;
+	my $fn_total_found;
+	my $fn_total_hit;
+	my $br_total_found;
+	my $br_total_hit;
+
+	# Read and combine trace files
+	foreach $filename (@opt_summary) {
+		$current = read_info_file($filename);
+		if (!defined($total)) {
+			$total = $current;
+		} else {
+			$total = combine_info_files($total, $current);
+		}
+	}
+	# Calculate coverage data
+	foreach $filename (keys(%{$total}))
+	{
+		my $entry = $total->{$filename};
+		my $ln_found;
+		my $ln_hit;
+		my $fn_found;
+		my $fn_hit;
+		my $br_found;
+		my $br_hit;
+
+		(undef, undef, undef, undef, undef, undef, undef, undef,
+			$ln_found, $ln_hit, $fn_found, $fn_hit, $br_found,
+			$br_hit) = get_info_entry($entry);
+
+		# Add to totals
+		$ln_total_found	+= $ln_found;
+		$ln_total_hit	+= $ln_hit;
+		$fn_total_found += $fn_found;
+		$fn_total_hit	+= $fn_hit;
+		$br_total_found += $br_found;
+		$br_total_hit	+= $br_hit;
+	}
+
+
+	return ($ln_total_found, $ln_total_hit, $fn_total_found, $fn_total_hit,
+		$br_total_found, $br_total_hit);
+}
 
 #
 # system_no_output(mode, parameters)
@@ -2591,12 +4012,12 @@
 	local *OLD_STDOUT;
 
 	# Save old stdout and stderr handles
-	($mode & 1) && open(OLD_STDOUT, ">>&STDOUT");
-	($mode & 2) && open(OLD_STDERR, ">>&STDERR");
+	($mode & 1) && open(OLD_STDOUT, ">>&", "STDOUT");
+	($mode & 2) && open(OLD_STDERR, ">>&", "STDERR");
 
 	# Redirect to /dev/null
-	($mode & 1) && open(STDOUT, ">/dev/null");
-	($mode & 2) && open(STDERR, ">/dev/null");
+	($mode & 1) && open(STDOUT, ">", "/dev/null");
+	($mode & 2) && open(STDERR, ">", "/dev/null");
  
 	system(@_);
 	$result = $?;
@@ -2606,8 +4027,8 @@
 	($mode & 2) && close(STDERR);
 
 	# Restore old handles
-	($mode & 1) && open(STDOUT, ">>&OLD_STDOUT");
-	($mode & 2) && open(STDERR, ">>&OLD_STDERR");
+	($mode & 1) && open(STDOUT, ">>&", "OLD_STDOUT");
+	($mode & 2) && open(STDERR, ">>&", "OLD_STDERR");
  
 	return $result;
 }
@@ -2628,7 +4049,7 @@
 	my $value;
 	local *HANDLE;
 
-	if (!open(HANDLE, "<$filename"))
+	if (!open(HANDLE, "<", $filename))
 	{
 		warn("WARNING: cannot read configuration file $filename\n");
 		return undef;
@@ -2667,8 +4088,8 @@
 #   key_string => var_ref
 #
 # where KEY_STRING is a keyword and VAR_REF is a reference to an associated
-# variable. If the global configuration hash CONFIG contains a value for
-# keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
+# variable. If the global configuration hashes CONFIG or OPT_RC contain a value
+# for keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. 
 #
 
 sub apply_config($)
@@ -2677,8 +4098,9 @@
 
 	foreach (keys(%{$ref}))
 	{
-		if (defined($config->{$_}))
-		{
+		if (defined($opt_rc{$_})) {
+			${$ref->{$_}} = $opt_rc{$_};
+		} elsif (defined($config->{$_})) {
 			${$ref->{$_}} = $config->{$_};
 		}
 	}
@@ -2688,6 +4110,7 @@
 {
 	my ($msg) = @_;
 
+	temp_cleanup();
 	warn("$tool_name: $msg");
 }
 
@@ -2695,5 +4118,186 @@
 {
 	my ($msg) = @_;
 
+	temp_cleanup();
 	die("$tool_name: $msg");
 }
+
+sub abort_handler($)
+{
+	temp_cleanup();
+	exit(1);
+}
+
+sub temp_cleanup()
+{
+	if (@temp_dirs) {
+		info("Removing temporary directories.\n");
+		foreach (@temp_dirs) {
+			rmtree($_);
+		}
+		@temp_dirs = ();
+	}
+}
+
+sub setup_gkv_sys()
+{
+	system_no_output(3, "mount", "-t", "debugfs", "nodev",
+			 "/sys/kernel/debug");
+}
+
+sub setup_gkv_proc()
+{
+	if (system_no_output(3, "modprobe", "gcov_proc")) {
+		system_no_output(3, "modprobe", "gcov_prof");
+	}
+}
+
+sub check_gkv_sys($)
+{
+	my ($dir) = @_;
+
+	if (-e "$dir/reset") {
+		return 1;
+	}
+	return 0;
+}
+
+sub check_gkv_proc($)
+{
+	my ($dir) = @_;
+
+	if (-e "$dir/vmlinux") {
+		return 1;
+	}
+	return 0;
+}
+
+sub setup_gkv()
+{
+	my $dir;
+	my $sys_dir = "/sys/kernel/debug/gcov";
+	my $proc_dir = "/proc/gcov";
+	my @todo;
+
+	if (!defined($gcov_dir)) {
+		info("Auto-detecting gcov kernel support.\n");
+		@todo = ( "cs", "cp", "ss", "cs", "sp", "cp" );
+	} elsif ($gcov_dir =~ /proc/) {
+		info("Checking gcov kernel support at $gcov_dir ".
+		     "(user-specified).\n");
+		@todo = ( "cp", "sp", "cp", "cs", "ss", "cs");
+	} else {
+		info("Checking gcov kernel support at $gcov_dir ".
+		     "(user-specified).\n");
+		@todo = ( "cs", "ss", "cs", "cp", "sp", "cp", );
+	}
+	foreach (@todo) {
+		if ($_ eq "cs") {
+			# Check /sys
+			$dir = defined($gcov_dir) ? $gcov_dir : $sys_dir;
+			if (check_gkv_sys($dir)) {
+				info("Found ".$GKV_NAME[$GKV_SYS]." gcov ".
+				     "kernel support at $dir\n");
+				return ($GKV_SYS, $dir);
+			}
+		} elsif ($_ eq "cp") {
+			# Check /proc
+			$dir = defined($gcov_dir) ? $gcov_dir : $proc_dir;
+			if (check_gkv_proc($dir)) {
+				info("Found ".$GKV_NAME[$GKV_PROC]." gcov ".
+				     "kernel support at $dir\n");
+				return ($GKV_PROC, $dir);
+			}
+		} elsif ($_ eq "ss") {
+			# Setup /sys
+			setup_gkv_sys();
+		} elsif ($_ eq "sp") {
+			# Setup /proc
+			setup_gkv_proc();
+		}
+	}
+	if (defined($gcov_dir)) {
+		die("ERROR: could not find gcov kernel data at $gcov_dir\n");
+	} else {
+		die("ERROR: no gcov kernel data found\n");
+	}
+}
+
+
+#
+# get_overall_line(found, hit, name_singular, name_plural)
+#
+# Return a string containing overall information for the specified
+# found/hit data.
+#
+
+sub get_overall_line($$$$)
+{
+	my ($found, $hit, $name_sn, $name_pl) = @_;
+	my $name;
+
+	return "no data found" if (!defined($found) || $found == 0);
+	$name = ($found == 1) ? $name_sn : $name_pl;
+
+	return rate($hit, $found, "% ($hit of $found $name)");
+}
+
+
+#
+# print_overall_rate(ln_do, ln_found, ln_hit, fn_do, fn_found, fn_hit, br_do
+#                    br_found, br_hit)
+#
+# Print overall coverage rates for the specified coverage types.
+#
+
+sub print_overall_rate($$$$$$$$$)
+{
+	my ($ln_do, $ln_found, $ln_hit, $fn_do, $fn_found, $fn_hit,
+	    $br_do, $br_found, $br_hit) = @_;
+
+	info("Summary coverage rate:\n");
+	info("  lines......: %s\n",
+	     get_overall_line($ln_found, $ln_hit, "line", "lines"))
+		if ($ln_do);
+	info("  functions..: %s\n",
+	     get_overall_line($fn_found, $fn_hit, "function", "functions"))
+		if ($fn_do);
+	info("  branches...: %s\n",
+	     get_overall_line($br_found, $br_hit, "branch", "branches"))
+		if ($br_do);
+}
+
+
+#
+# rate(hit, found[, suffix, precision, width])
+#
+# Return the coverage rate [0..100] for HIT and FOUND values. 0 is only
+# returned when HIT is 0. 100 is only returned when HIT equals FOUND.
+# PRECISION specifies the precision of the result. SUFFIX defines a
+# string that is appended to the result if FOUND is non-zero. Spaces
+# are added to the start of the resulting string until it is at least WIDTH
+# characters wide.
+#
+
+sub rate($$;$$$)
+{
+        my ($hit, $found, $suffix, $precision, $width) = @_;
+        my $rate; 
+
+	# Assign defaults if necessary
+        $precision	= 1	if (!defined($precision));
+	$suffix		= ""	if (!defined($suffix));
+	$width		= 0	if (!defined($width));
+        
+        return sprintf("%*s", $width, "-") if (!defined($found) || $found == 0);
+        $rate = sprintf("%.*f", $precision, $hit * 100 / $found);
+
+	# Adjust rates if necessary
+        if ($rate == 0 && $hit > 0) {
+		$rate = sprintf("%.*f", $precision, 1 / 10 ** $precision);
+        } elsif ($rate == 100 && $hit != $found) {
+		$rate = sprintf("%.*f", $precision, 100 - 1 / 10 ** $precision);
+	}
+
+	return sprintf("%*s", $width, $rate.$suffix);
+}
diff --git a/third_party/lcov/bin/updateversion.pl b/third_party/lcov/bin/updateversion.pl
index 49f639a..55f2bc1 100755
--- a/third_party/lcov/bin/updateversion.pl
+++ b/third_party/lcov/bin/updateversion.pl
@@ -93,7 +93,7 @@
 	open(OUT, ">$filename.new") ||
 		die("Error: cannot create $filename.new\n");
 	while (<IN>) {
-		s/(our\s+\$lcov_version\s*=\s*\").*(\".*)$/$1LCOV version $version$2/g;
+		s/(our\s+\$lcov_version\s*=\s*["']).*(["'].*)$/$1LCOV version $version$2/g;
 		print(OUT $_);
 	}
 	close(OUT);
diff --git a/third_party/lcov/example/Makefile b/third_party/lcov/example/Makefile
index 5428237..2f698a1 100644
--- a/third_party/lcov/example/Makefile
+++ b/third_party/lcov/example/Makefile
@@ -70,7 +70,7 @@
 	@echo
 	$(LCOV) --zerocounters --directory .
 	./example
-	$(LCOV) --capture --directory . --output-file trace_noargs.info --test-name test_noargs
+	$(LCOV) --capture --directory . --output-file trace_noargs.info --test-name test_noargs --no-external
 
 test_2_to_2000:
 	@echo
@@ -80,7 +80,7 @@
 	@echo
 	$(LCOV) --zerocounters --directory .
 	./example 2 2000
-	$(LCOV) --capture --directory . --output-file trace_args.info --test-name test_2_to_2000
+	$(LCOV) --capture --directory . --output-file trace_args.info --test-name test_2_to_2000 --no-external
 
 test_overflow:
 	@echo
@@ -90,7 +90,7 @@
 	@echo
 	$(LCOV) --zerocounters --directory .
 	./example 0 100000 || true
-	$(LCOV) --capture --directory . --output-file trace_overflow.info --test-name "test_overflow"
+	$(LCOV) --capture --directory . --output-file trace_overflow.info --test-name "test_overflow" --no-external
 
 clean:
 	rm -rf *.o *.bb *.bbg *.da *.gcno *.gcda *.info output example \
diff --git a/third_party/lcov/lcovrc b/third_party/lcov/lcovrc
index b0e511a..9c65970 100644
--- a/third_party/lcov/lcovrc
+++ b/third_party/lcov/lcovrc
@@ -12,14 +12,14 @@
 # HI:   hi_limit <= rate <= 100         graph color: green
 # MED: med_limit <= rate <  hi_limit    graph color: orange
 # LO:         0  <= rate <  med_limit   graph color: red
+genhtml_hi_limit = 90
+genhtml_med_limit = 75
 
-# For line coverage
-genhtml_hi_limit = 50
-genhtml_med_limit = 15
+# Width of line coverage field in source code view
+genhtml_line_field_width = 12
 
-# For function coverage
-genhtml_function_hi_limit = 90
-genhtml_function_med_limit = 75
+# Width of branch coverage field in source code view
+genhtml_branch_field_width = 16
 
 # Width of overview image (used by --frames option of genhtml)
 genhtml_overview_width = 80
@@ -81,7 +81,14 @@
 
 # Include function coverage data display (can be disabled by the
 # --no-func-coverage option of genhtml)
-genhtml_function_coverage = 1
+#genhtml_function_coverage = 1
+
+# Include branch coverage data display (can be disabled by the
+# --no-branch-coverage option of genhtml)
+#genhtml_branch_coverage = 1
+
+# Specify the character set of all generated HTML pages
+genhtml_charset=UTF-8
 
 # Location of the gcov tool (same as --gcov-info option of geninfo)
 #geninfo_gcov_tool = gcov
@@ -93,12 +100,30 @@
 # option of geninfo if non-zero, same as --no-checksum if zero)
 #geninfo_checksum = 1
 
+# Specify whether to capture coverage data for external source files (can
+# be overridden by the --external and --no-external options of geninfo/lcov)
+#geninfo_external = 1
+
 # Enable libtool compatibility mode if non-zero (same as --compat-libtool option
 # of geninfo if non-zero, same as --no-compat-libtool if zero)
 #geninfo_compat_libtool = 0
 
+# Use gcov's --all-blocks option if non-zero
+#geninfo_gcov_all_blocks = 1
+
+# Specify compatiblity modes (same as --compat option of geninfo).
+#geninfo_compat = libtool=on, hammer=auto, split_crc=auto
+
+# Adjust path to source files by removing or changing path components that
+# match the specified pattern (Perl regular expression format)
+#geninfo_adjust_src_path = /tmp/build => /usr/src
+
+# Specify if geninfo should try to automatically determine the base-directory
+# when collecting coverage data.
+geninfo_auto_base = 1
+
 # Directory containing gcov kernel files
-lcov_gcov_dir = /proc/gcov
+# lcov_gcov_dir = /proc/gcov
 
 # Location of the insmod tool
 lcov_insmod_tool = /sbin/insmod
@@ -111,3 +136,22 @@
 
 # Location for temporary directories
 lcov_tmp_dir = /tmp
+
+# Show full paths during list operation if non-zero (same as --list-full-path
+# option of lcov)
+lcov_list_full_path = 0
+
+# Specify the maximum width for list output. This value is ignored when
+# lcov_list_full_path is non-zero.
+lcov_list_width = 80
+
+# Specify the maximum percentage of file names which may be truncated when
+# choosing a directory prefix in list output. This value is ignored when
+# lcov_list_full_path is non-zero.
+lcov_list_truncate_max = 20
+
+# Specify if function coverage data should be collected and processed.
+lcov_function_coverage = 1
+
+# Specify if branch coverage data should be collected and processed.
+lcov_branch_coverage = 0
diff --git a/third_party/lcov/man/gendesc.1 b/third_party/lcov/man/gendesc.1
index e1fb38a..d1c5382 100644
--- a/third_party/lcov/man/gendesc.1
+++ b/third_party/lcov/man/gendesc.1
@@ -1,4 +1,4 @@
-.TH gendesc 1 "LCOV 1.7" 2008\-11\-17 "User Manuals"
+.TH gendesc 1 "LCOV 1.10" 2012\-10\-10 "User Manuals"
 .SH NAME
 gendesc \- Generate a test case description file
 .SH SYNOPSIS
diff --git a/third_party/lcov/man/genhtml.1 b/third_party/lcov/man/genhtml.1
index e99c642..9788323 100644
--- a/third_party/lcov/man/genhtml.1
+++ b/third_party/lcov/man/genhtml.1
@@ -1,4 +1,4 @@
-.TH genhtml 1 "LCOV 1.7" 2008\-11\-17 "User Manuals"
+.TH genhtml 1 "LCOV 1.10" 2012\-10\-10 "User Manuals"
 .SH NAME
 genhtml \- Generate HTML view from LCOV coverage data files
 .SH SYNOPSIS
@@ -52,6 +52,18 @@
 .RB [ \-\-function\-coverage ]
 .RB [ \-\-no\-function\-coverage ]
 .br
+.RB [ \-\-branch\-coverage ]
+.RB [ \-\-no\-branch\-coverage ]
+.br
+.RB [ \-\-demangle\-cpp ]
+.RB [ \-\-ignore\-errors
+.IR errors  ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
 .IR tracefile(s)
 .RE
 .SH DESCRIPTION
@@ -75,10 +87,17 @@
 to modify layout and colors of the generated HTML output. Files are
 marked in different colors depending on the associated coverage rate. By
 default, the coverage limits for low, medium and high coverage are set to
-0\-15%, 15\-50% and 50\-100% percent respectively. To change these
+0\-75%, 75\-90% and 90\-100% percent respectively. To change these
 values, use configuration file options
 .IR genhtml_hi_limit " and " genhtml_med_limit .
 
+Also note that when displaying percentages, 0% and 100% are only printed when
+the values are exactly 0% and 100% respectively. Other values which would
+conventionally be rounded to 0% or 100% are instead printed as nearest
+non-boundary value. This behavior is in accordance with that of the
+.BR gcov (1)
+tool.
+
 .SH OPTIONS
 .B \-h
 .br
@@ -113,7 +132,7 @@
 If enabled, a frameset is created for each source code file, providing
 an overview of the source code as a "clickable" image. Note that this
 option will slow down output creation noticeably because each source
-code character has to be inspected once. Note also that the GD.pm PERL
+code character has to be inspected once. Note also that the GD.pm Perl
 module has to be installed for this option to work (it may be obtained
 from http://www.cpan.org).
 
@@ -369,7 +388,6 @@
 .RE
 .BI "\-\-html\-extension " extension
 .RS
-
 Use customized filename extension for generated HTML pages.
 
 This option is useful in situations where different filename extensions
@@ -384,7 +402,6 @@
 
 .B \-\-html\-gzip
 .RS
-
 Compress all generated html files with gzip and add a .htaccess file specifying
 gzip\-encoding in the root output directory.
 
@@ -438,6 +455,96 @@
 .IR genhtml_function_coverage .
 
 .RE
+.B \-\-branch\-coverage
+.br
+.B \-\-no\-branch\-coverage
+.RS
+Specify whether to display branch coverage data in HTML output.
+
+Use \-\-branch\-coverage to enable branch coverage display or
+\-\-no\-branch\-coverage to disable it. Branch coverage data display is
+.B enabled
+by default
+
+When branch coverage display is enabled, each overview page will contain
+the number of branches found and hit per file or directory, together with
+the resulting coverage rate. In addition, each source code view will contain
+an extra column which lists all branches of a line with indications of
+whether the branch was taken or not. Branches are shown in the following format:
+
+ ' + ': Branch was taken at least once
+.br
+ ' - ': Branch was not taken
+.br
+ ' # ': The basic block containing the branch was never executed
+.br
+
+Note that it might not always be possible to relate branches to the
+corresponding source code statements: during compilation, GCC might shuffle
+branches around or eliminate some of them to generate better code.
+
+This option can also be configured permanently using the configuration file
+option
+.IR genhtml_branch_coverage .
+
+.RE
+.B \-\-demangle\-cpp
+.RS
+Specify whether to demangle C++ function names.
+
+Use this option if you want to convert C++ internal function names to
+human readable format for display on the HTML function overview page.
+This option requires that the c++filt tool is installed (see
+.BR c++filt (1)).
+
+.RE
+.B \-\-ignore\-errors
+.I errors
+.br
+.RS
+Specify a list of errors after which to continue processing.
+
+Use this option to specify a list of one or more classes of errors after which
+geninfo should continue processing instead of aborting.
+
+.I errors
+can be a comma\-separated list of the following keywords:
+
+.B source:
+the source code file for a data set could not be found.
+.RE
+
+.B \-\-config\-file
+.I config\-file
+.br
+.RS
+Specify a configuration file to use.
+
+When this option is specified, neither the system\-wide configuration file
+/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
+
+This option may be useful when there is a need to run several
+instances of
+.B genhtml
+with different configuration file options in parallel.
+.RE
+
+.B \-\-rc
+.IR keyword = value
+.br
+.RS
+Override a configuration directive.
+
+Use this option to specify a
+.IR keyword = value
+statement which overrides the corresponding configuration statement in
+the lcovrc configuration file. You can specify this option more than once
+to override multiple configuration statements.
+See
+.BR lcovrc (5)
+for a list of available keywords and their meaning.
+.RE
+
 .SH FILES
 
 .I /etc/lcovrc
@@ -455,6 +562,7 @@
 
 .SH SEE ALSO
 .BR lcov (1),
+.BR lcovrc (5),
 .BR geninfo (1),
 .BR genpng (1),
 .BR gendesc (1),
diff --git a/third_party/lcov/man/geninfo.1 b/third_party/lcov/man/geninfo.1
index 47fcfa3..d9ca97c 100644
--- a/third_party/lcov/man/geninfo.1
+++ b/third_party/lcov/man/geninfo.1
@@ -1,4 +1,4 @@
-.TH geninfo 1 "LCOV 1.7" 2008\-11\-17 "User Manuals"
+.TH geninfo 1 "LCOV 1.10" 2012\-10\-10 "User Manuals"
 .SH NAME
 geninfo \- Generate tracefiles from .da files
 .SH SYNOPSIS
@@ -32,6 +32,19 @@
 .br
 .RB [ \-\-no\-recursion ]
 .I directory
+.RB [ \-\-external ]
+.RB [ \-\-no\-external ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-no\-markers ]
+.br
+.RB [ \-\-derive\-func\-data ]
+.RB [ \-\-compat
+.IR  mode =on|off|auto]
+.br
+.RB [ \-\-rc
+.IR keyword = value ]
 .RE
 .SH DESCRIPTION
 .B geninfo 
@@ -57,6 +70,33 @@
 is called from within
 .BR lcov ,
 so that there is usually no need to call it directly.
+
+.B Exclusion markers
+
+To exclude specific lines of code from a tracefile, you can add exclusion
+markers to the source code. Exclusion markers are keywords which can for
+example be added in the form of a comment.
+
+The following markers are recognized by geninfo:
+
+LCOV_EXCL_LINE
+.RS
+Lines containing this marker will be excluded.
+.br
+.RE
+LCOV_EXCL_START
+.RS
+Marks the beginning of an excluded section. The current line is part of this
+section.
+.br
+.RE
+LCOV_EXCL_STOP
+.RS
+Marks the end of an excluded section. The current line not part of this
+section.
+.RE
+.br
+
 .SH OPTIONS
 
 .B \-b
@@ -84,11 +124,10 @@
 directory in which the source code file is located.
 
 Note that this option will not work in environments where multiple base
-directories are used. In that case repeat the geninfo call for each base
-directory while using the \-\-ignore\-errors option to prevent geninfo from
-exiting when the first source code file could not be found. This way you can
-get partial coverage information for each base directory which can then be
-combined using the \-a option.
+directories are used. In that case use configuration file setting
+.B geninfo_auto_base=1
+(see
+.BR lcovrc (5)).
 .RE
 
 .B \-\-checksum
@@ -112,6 +151,73 @@
 to speed up coverage data processing and to reduce the size of tracefiles.
 .RE
 
+.B \-\-compat
+.IR mode = value [, mode = value ,...]
+.br
+.RS
+Set compatibility mode.
+
+Use \-\-compat to specify that geninfo should enable one or more compatibility
+modes when capturing coverage data. You can provide a comma-separated list
+of mode=value pairs to specify the values for multiple modes.
+
+Valid
+.I values
+are:
+
+.B on
+.RS
+Enable compatibility mode.
+.RE
+.B off
+.RS
+Disable compatibility mode.
+.RE
+.B auto
+.RS
+Apply auto-detection to determine if compatibility mode is required. Note that
+auto-detection is not available for all compatibility modes.
+.RE
+
+If no value is specified, 'on' is assumed as default value.
+
+Valid
+.I modes
+are:
+
+.B libtool
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using the libtool mechanism. See also
+\-\-compat\-libtool.
+
+The default value for this setting is 'on'.
+
+.RE
+.B hammer
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 3.3 that contains a modification
+(hammer patch) of later GCC versions. You can identify a modified GCC 3.3
+by checking the build directory of your project for files ending in the
+extension '.bbg'. Unmodified versions of GCC 3.3 name these files '.bb'.
+
+The default value for this setting is 'auto'.
+
+.RE
+.B split_crc
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 4.6 that contains a modification
+(split function checksums) of later GCC versions. Typical error messages
+when running geninfo on coverage data produced by such GCC versions are
+\'out of memory' and 'reached unexpected end of file'.
+
+The default value for this setting is 'auto'
+.RE
+
+.RE
+
 .B \-\-compat\-libtool
 .br
 .B \-\-no\-compat\-libtool
@@ -132,6 +238,49 @@
 libtool, disable this option to prevent problems when capturing coverage data.
 .RE
 
+.B \-\-config\-file
+.I config\-file
+.br
+.RS
+Specify a configuration file to use.
+
+When this option is specified, neither the system\-wide configuration file
+/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
+
+This option may be useful when there is a need to run several
+instances of
+.B geninfo
+with different configuration file options in parallel.
+.RE
+
+.B \-\-derive\-func\-data
+.br
+.RS
+Calculate function coverage data from line coverage data.
+
+Use this option to collect function coverage data, even if the version of the
+gcov tool installed on the test system does not provide this data. lcov will
+instead derive function coverage data from line coverage data and
+information about which lines belong to a function.
+.RE
+
+.B \-\-external
+.br
+.B \-\-no\-external
+.br
+.RS
+Specify whether to capture coverage data for external source files.
+
+External source files are files which are not located in one of the directories
+specified by \-\-directory or \-\-base\-directory. Use \-\-external to include
+external source files while capturing coverage data or \-\-no\-external to
+ignore this data.
+
+Data for external source files is
+.B included
+by default.
+.RE
+
 .B \-f
 .br
 .B \-\-follow
@@ -180,10 +329,20 @@
 
 Run geninfo with this option on the directories containing .bb, .bbg or .gcno
 files before running any test case. The result is a "baseline" coverage data
-file that contains zero coverage for every instrumented line. Combine this
-data file (using lcov \-a) with coverage data files captured after a test
-run to ensure that the percentage of total lines covered is correct even
-when not all source code files were loaded during the test.
+file that contains zero coverage for every instrumented line and function.
+Combine this data file (using lcov \-a) with coverage data files captured
+after a test run to ensure that the percentage of total lines covered is
+correct even when not all object code files were loaded during the test.
+
+Note: currently, the \-\-initial option does not generate branch coverage
+information.
+.RE
+
+.B \-\-no\-markers
+.br
+.RS
+Use this option if you want to get coverage data without regard to exclusion
+markers in the source code file.
 .RE
 
 .B \-\-no\-recursion
@@ -215,6 +374,22 @@
 only error or warning messages are printed.
 .RE
 
+.B \-\-rc
+.IR keyword = value
+.br
+.RS
+Override a configuration directive.
+
+Use this option to specify a
+.IR keyword = value
+statement which overrides the corresponding configuration statement in
+the lcovrc configuration file. You can specify this option more than once
+to override multiple configuration statements.
+See
+.BR lcovrc (5)
+for a list of available keywords and their meaning.
+.RE
+
 .BI "\-t " testname
 .br
 .BI "\-\-test\-name " testname
@@ -279,6 +454,19 @@
   FNF:<number of functions found>
   FNH:<number of function hit>
 
+Branch coverage information is stored which one line per branch:
+
+  BRDA:<line number>,<block number>,<branch number>,<taken>
+
+Block number and branch number are gcc internal IDs for the branch. Taken is
+either '-' if the basic block containing the branch was never executed or
+a number indicating how often that branch was taken.
+
+Branch coverage summaries are stored in two lines:
+
+  BRF:<number of branches found>
+  BRH:<number of branches hit>
+
 Then there is a list of execution counts for each instrumented line
 (i.e. a line which resulted in executable code):
 
@@ -317,6 +505,7 @@
 
 .SH SEE ALSO
 .BR lcov (1),
+.BR lcovrc (5),
 .BR genhtml (1),
 .BR genpng (1),
 .BR gendesc (1),
diff --git a/third_party/lcov/man/genpng.1 b/third_party/lcov/man/genpng.1
index 147a25d..5c13bd5 100644
--- a/third_party/lcov/man/genpng.1
+++ b/third_party/lcov/man/genpng.1
@@ -1,4 +1,4 @@
-.TH genpng 1 "LCOV 1.7" 2008\-11\-17 "User Manuals"
+.TH genpng 1 "LCOV 1.10" 2012\-10\-10 "User Manuals"
 .SH NAME
 genpng \- Generate an overview image from a source file
 .SH SYNOPSIS
@@ -23,7 +23,7 @@
 
 Note that the
 .I GD.pm
-PERL module has to be installed for this script to work
+Perl module has to be installed for this script to work
 (it may be obtained from
 .IR http://www.cpan.org ).
 
diff --git a/third_party/lcov/man/lcov.1 b/third_party/lcov/man/lcov.1
index aa30fb8..092d865 100644
--- a/third_party/lcov/man/lcov.1
+++ b/third_party/lcov/man/lcov.1
@@ -1,73 +1,186 @@
-.TH lcov 1 "LCOV 1.7" 2008\-11\-17 "User Manuals"
+.TH lcov 1 "LCOV 1.10" 2012\-10\-10 "User Manuals"
 .SH NAME
 lcov \- a graphical GCOV front\-end
 .SH SYNOPSIS
 .B lcov
-.RB [ \-h | \-\-help ]
-.RB [ \-v | \-\-version ]
-.RB [ \-q | \-\-quiet ]
+.BR \-c | \-\-capture
 .RS 5
 .br
-.RB [ \-z | \-\-zerocounters ]
-.RB [ \-c | \-\-capture ]
-.br
-.RB [ \-a | \-\-add\-tracefile
-.IR tracefile ]
-.br
-.RB [ \-e | \-\-extract
-.IR tracefile ]
-.br
-.RB [ \-r | \-\-remove
-.IR tracefile ]
-.br
-.RB [ \-l | \-\-list
-.IR tracefile ]
-.br
-.RB [ \-\-diff
-.IR "tracefile diff" ]
-.br
-.RB [ \-i | \-\-initial ]
-.RB [ \-t | \-\-test\-name
-.IR testname ]
-.br
-.RB [ \-o | \-\-output\-file
-.IR filename ]
-.br
 .RB [ \-d | \-\-directory
 .IR directory ]
-.br
-.RB [ \-f | \-\-follow ]
-.br
 .RB [ \-k | \-\-kernel\-directory
 .IR directory ]
 .br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-t | \-\-test\-name
+.IR testname ]
+.br
 .RB [ \-b | \-\-base\-directory
 .IR directory ]
+.RB [ \-i | \-\-initial ]
+.RB [ \-\-gcov\-tool
+.IR tool ]
+.br
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.RB [ \-\-no\-recursion ]
+.RB [ \-f | \-\-follow ]
+.br
+.RB [ \-\-compat\-libtool ]
+.RB [ \-\-no\-compat\-libtool ]
+.RB [ \-\-ignore\-errors
+.IR errors ]
+.br
+.RB [ \-\-to\-package
+.IR package ]
+.RB [ \-\-from\-package
+.IR package ]
+.RB [ \-q | \-\-quiet ]
+.br
+.RB [ \-\-no\-markers ]
+.RB [ \-\-external ]
+.RB [ \-\-no\-external ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RB [ \-\-compat
+.IR  mode =on|off|auto]
+.br
+.RE
+
+.B lcov
+.BR \-z | \-\-zerocounters
+.RS 5
+.br
+.RB [ \-d | \-\-directory
+.IR directory ]
+.RB [ \-\-no\-recursion ]
+.RB [ \-f | \-\-follow ]
+.br
+.RB [ \-q | \-\-quiet ]
+.br
+.RE
+
+.B lcov
+.BR \-l | \-\-list
+.I tracefile
+.RS 5
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-list\-full\-path ]
+.RB [ \-\-no\-list\-full\-path ]
+.br
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-a | \-\-add\-tracefile
+.I tracefile
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-e | \-\-extract
+.I tracefile pattern
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-r | \-\-remove
+.I tracefile pattern
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
+.br
+.RB [ \-q | \-\-quiet ]
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
+.br
+.RE
+
+.B lcov
+.BR \-\-diff
+.IR "tracefile diff"
+.RS 5
+.br
+.RB [ \-o | \-\-output\-file
+.IR tracefile ]
+.RB [ \-\-checksum ]
+.RB [ \-\-no\-checksum ]
 .br
 .RB [ \-\-convert\-filenames ]
 .RB [ \-\-strip
 .IR depth ]
 .RB [ \-\-path
 .IR path ]
+.RB [ \-q | \-\-quiet ]
 .br
-.RB [ \-\-checksum ]
-.RB [ \-\-no\-checksum ]
+.RB [ \-\-config\-file
+.IR config\-file ]
+.RB [ \-\-rc
+.IR keyword = value ]
 .br
-.RB [ \-\-compat\-libtool ]
-.RB [ \-\-no\-compat\-libtool ]
+.RE
+
+.B lcov
+.BR \-\-summary
+.I tracefile
+.RS 5
 .br
-.RB [ \-\-gcov\-tool
-.IR tool ]
-.RB [ \-\-ignore\-errors
-.IR errors ]
+.RB [ \-q | \-\-quiet ]
 .br
-.RB [ \-\-no\-recursion ]
+.RE
+
+.B lcov
+.RB [ \-h | \-\-help ]
+.RB [ \-v | \-\-version ]
+.RS 5
+.br
+.RE
+
 .SH DESCRIPTION
 .B lcov
 is a graphical front\-end for GCC's coverage testing tool gcov. It collects
-gcov data for multiple source files and creates HTML pages containing the
-source code annotated with coverage information. It also adds overview pages
-for easy navigation within the file structure.
+line, function and branch coverage data for multiple source files and creates
+HTML pages containing the source code annotated with coverage information.
+It also adds overview pages for easy navigation within the file structure.
 
 Use
 .B lcov
@@ -79,8 +192,10 @@
 
 For Linux kernel coverage:
 .RS
-Follow the installation instructions for the gcov\-kernel patch:
+Follow the setup instructions for the gcov\-kernel infrastructure:
 .I http://ltp.sourceforge.net/coverage/gcov.php
+.br
+
 
 .RE
 For user space application coverage:
@@ -93,6 +208,14 @@
 .B lcov
 as ".info file" or "tracefile" and that the output of GCOV
 is called ".da file".
+
+Also note that when printing percentages, 0% and 100% are only printed when
+the values are exactly 0% and 100% respectively. Other values which would
+conventionally be rounded to 0% or 100% are instead printed as nearest
+non-boundary value. This behavior is in accordance with that of the
+.BR gcov (1)
+tool.
+
 .SH OPTIONS
 
 
@@ -113,8 +236,8 @@
 The result of the add operation will be written to stdout or the tracefile
 specified with \-o.
 
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
 
 .RE
 
@@ -143,11 +266,10 @@
 directory in which the source code file is located.
 
 Note that this option will not work in environments where multiple base
-directories are used. In that case repeat the lcov call for each base directory
-while using the \-\-ignore\-errors option to prevent lcov from exiting when the
-first source code file could not be found. This way you can get partial coverage
-information for each base directory which can then be combined using the \-a
-option.
+directories are used. In that case use configuration file setting
+.B geninfo_auto_base=1
+(see
+.BR lcovrc (5)).
 .RE
 
 .B \-c
@@ -164,8 +286,8 @@
 The result of the capture operation will be written to stdout or the tracefile
 specified with \-o.
 
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
 .RE
 
 .B \-\-checksum
@@ -189,6 +311,73 @@
 to speed up coverage data processing and to reduce the size of tracefiles.
 .RE
 
+.B \-\-compat
+.IR mode = value [, mode = value ,...]
+.br
+.RS
+Set compatibility mode.
+
+Use \-\-compat to specify that lcov should enable one or more compatibility
+modes when capturing coverage data. You can provide a comma-separated list
+of mode=value pairs to specify the values for multiple modes.
+
+Valid
+.I values
+are:
+
+.B on
+.RS
+Enable compatibility mode.
+.RE
+.B off
+.RS
+Disable compatibility mode.
+.RE
+.B auto
+.RS
+Apply auto-detection to determine if compatibility mode is required. Note that
+auto-detection is not available for all compatibility modes.
+.RE
+
+If no value is specified, 'on' is assumed as default value.
+
+Valid
+.I modes
+are:
+
+.B libtool
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using the libtool mechanism. See also
+\-\-compat\-libtool.
+
+The default value for this setting is 'on'.
+
+.RE
+.B hammer
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 3.3 that contains a modification
+(hammer patch) of later GCC versions. You can identify a modified GCC 3.3
+by checking the build directory of your project for files ending in the
+extension '.bbg'. Unmodified versions of GCC 3.3 name these files '.bb'.
+
+The default value for this setting is 'auto'.
+
+.RE
+.B split_crc
+.RS
+Enable this mode if you are capturing coverage data for a project that
+was built using a version of GCC 4.6 that contains a modification
+(split function checksums) of later GCC versions. Typical error messages
+when running lcov on coverage data produced by such GCC versions are
+\'out of memory' and 'reached unexpected end of file'.
+
+The default value for this setting is 'auto'
+.RE
+
+.RE
+
 .B \-\-compat\-libtool
 .br
 .B \-\-no\-compat\-libtool
@@ -209,6 +398,21 @@
 libtool, disable this option to prevent problems when capturing coverage data.
 .RE
 
+.B \-\-config\-file
+.I config\-file
+.br
+.RS
+Specify a configuration file to use.
+
+When this option is specified, neither the system\-wide configuration file
+/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
+
+This option may be useful when there is a need to run several
+instances of
+.B lcov
+with different configuration file options in parallel.
+.RE
+
 .B \-\-convert\-filenames
 .br
 .RS
@@ -250,8 +454,8 @@
 The result of the diff operation will be written to stdout or the tracefile
 specified with \-o.
 
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
 .RE
 
 .B \-d
@@ -272,6 +476,23 @@
 Note that you may specify this option more than once.
 .RE
 
+.B \-\-external
+.br
+.B \-\-no\-external
+.br
+.RS
+Specify whether to capture coverage data for external source files.
+
+External source files are files which are not located in one of the directories
+specified by \-\-directory or \-\-base\-directory. Use \-\-external to include
+external source files while capturing coverage data or \-\-no\-external to
+ignore this data.
+
+Data for external source files is
+.B included
+by default.
+.RE
+
 .B \-e
 .I tracefile
 .I pattern
@@ -295,8 +516,8 @@
 The result of the extract operation will be written to stdout or the tracefile
 specified with \-o.
 
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
 .RE
 
 .B \-f
@@ -307,6 +528,19 @@
 Follow links when searching for .da files.
 .RE
 
+.B \-\-from\-package
+.I package
+.br
+.RS
+Use .da files in
+.I package
+instead of kernel or directory.
+
+Use this option if you have separate machines for build and test and
+want to perform the .info file creation on the build machine. See
+\-\-to\-package for more information.
+.RE
+
 .B \-\-gcov\-tool
 .I tool
 .br
@@ -393,9 +627,11 @@
 .IR subdirectory .
 
 Use this option if you don't want to get coverage data for all of the
-kernel, but only for specific subdirectories.
+kernel, but only for specific subdirectories. This option may be specified
+more than once.
 
-Note that you may specify this option more than once.
+Note that you may need to specify the full path to the kernel subdirectory
+depending on the version of the kernel gcov support.
 .RE
 
 .B \-l
@@ -408,8 +644,30 @@
 List the contents of the
 .IR tracefile .
 
-Only one of  \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
+.B \-\-list\-full\-path
+.br
+.B \-\-no\-list\-full\-path
+.br
+.RS
+Specify whether to show full paths during list operation.
+
+Use \-\-list\-full\-path to show full paths during list operation
+or \-\-no\-list\-full\-path to show shortened paths. Paths are
+.B shortened
+by default.
+.RE
+
+.B \-\-no\-markers
+.br
+.RS
+Use this option if you want to get coverage data without regard to exclusion
+markers in the source code file. See
+.BR "geninfo " (1)
+for details on exclusion markers.
 .RE
 
 .B \-\-no\-recursion
@@ -458,6 +716,22 @@
 the standard output.
 .RE
 
+.B \-\-rc
+.IR keyword = value
+.br
+.RS
+Override a configuration directive.
+
+Use this option to specify a
+.IR keyword = value
+statement which overrides the corresponding configuration statement in
+the lcovrc configuration file. You can specify this option more than once
+to override multiple configuration statements.
+See
+.BR lcovrc (5)
+for a list of available keywords and their meaning.
+.RE
+
 .B \-r
 .I tracefile
 .I pattern
@@ -481,8 +755,8 @@
 The result of the remove operation will be written to stdout or the tracefile
 specified with \-o.
 
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
 .RE
 
 .B \-\-strip
@@ -495,6 +769,18 @@
 number of initial directories when matching tracefile and diff filenames.
 .RE
 
+.B \-\-summary
+.I tracefile
+.br
+.RS
+Show summary coverage information for the specified tracefile.
+
+Note that you may specify this option more than once.
+
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
+.RE
+
 .B \-t
 .I testname
 .br
@@ -511,6 +797,46 @@
 character ("_").
 .RE
 
+.B \-\-to\-package
+.I package
+.br
+.RS
+Store .da files for later processing.
+
+Use this option if you have separate machines for build and test and
+want to perform the .info file creation on the build machine. To do this,
+follow these steps:
+
+On the test machine:
+.RS
+.br
+\- run the test
+.br
+\- run lcov \-c [\-d directory] \-\-to-package
+.I file
+.br
+\- copy
+.I file
+to the build machine
+.RE
+.br
+
+On the build machine:
+.RS
+.br
+\- run lcov \-c \-\-from-package
+.I file
+[\-o and other options]
+.RE
+.br
+
+This works for both kernel and user space coverage data. Note that you might
+have to specify the path to the build directory using \-b with
+either \-\-to\-package or \-\-from-package. Note also that the package data
+must be converted to a .info file before recompiling the program or it will
+become invalid.
+.RE
+
 .B \-v
 .br
 .B \-\-version
@@ -529,8 +855,8 @@
 By default tries to reset kernel execution counts. Use the \-\-directory
 option to reset all counters of a user space program.
 
-Only one of \-z, \-c, \-a, \-e, \-r, \-l and \-\-diff may be specified
-at a time.
+Only one of  \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
+specified at a time.
 .RE
 
 .SH FILES
diff --git a/third_party/lcov/man/lcovrc.5 b/third_party/lcov/man/lcovrc.5
index 8bb7a63..8566ef3 100644
--- a/third_party/lcov/man/lcovrc.5
+++ b/third_party/lcov/man/lcovrc.5
@@ -1,4 +1,4 @@
-.TH lcovrc 5 "LCOV 1.7" 2008\-11\-17 "User Manuals"
+.TH lcovrc 5 "LCOV 1.10" 2012\-10\-10 "User Manuals"
 
 .SH NAME
 lcovrc \- lcov configuration file
@@ -47,18 +47,21 @@
 #genhtml_css_file = gcov.css
 .br
 
-# Coverage rate limits for line coverage
+# Coverage rate limits
 .br
-genhtml_hi_limit = 50
+genhtml_hi_limit = 90
 .br
-genhtml_med_limit = 15
+genhtml_med_limit = 75
 .br
 
-# Coverage rate limits for function coverage
+# Width of line coverage field in source code view
 .br
-genhtml_function_hi_limit = 90
+genhtml_line_field_width = 12
 .br
-genhtml_function_med_limit = 75
+
+# Width of branch coverage field in source code view
+.br
+genhtml_branch_field_width = 16
 .br
 
 # Width of overview image
@@ -133,7 +136,17 @@
 
 # Include function coverage data display
 .br
-genhtml_function_coverage = 1
+#genhtml_function_coverage = 1
+.br
+
+# Include branch coverage data display
+.br
+#genhtml_branch_coverage = 1
+.br
+
+# Specify the character set of all generated HTML pages
+.br
+genhtml_charset=UTF\-8
 .br
 
 # Location of the gcov tool
@@ -156,30 +169,83 @@
 geninfo_compat_libtool = 0
 .br
 
+# Specify whether to capture coverage data for external source
+.br
+# files
+.br
+#geninfo_external = 1
+.br
+
+# Use gcov's --all-blocks option if non-zero
+.br
+#geninfo_gcov_all_blocks = 1
+.br
+
+# Specify compatiblity modes (same as \-\-compat option
+.br
+# of geninfo)
+.br
+#geninfo_compat = libtool=on, hammer=auto, split_crc=auto
+.br
+
+# Adjust path to source files by removing or changing path
+.br
+# components that match the specified pattern (Perl regular
+.br
+# expression format)
+.br
+#geninfo_adjust_src_path = /tmp/build => /usr/src
+
+# Specify if geninfo should try to automatically determine
+.br
+# the base-directory when collecting coverage data.
+.br
+geninfo_auto_base = 1
+.br
+
 # Directory containing gcov kernel files
 .br
 lcov_gcov_dir = /proc/gcov
 .br
 
-# Location of the insmod tool
-.br
-lcov_insmod_tool = /sbin/insmod
-.br
-
-# Location of the modprobe tool
-.br
-lcov_modprobe_tool = /sbin/modprobe
-.br
-
-# Location of the rmmod tool
-.br
-lcov_rmmod_tool = /sbin/rmmod
-.br
-
 # Location for temporary directories
 .br
 lcov_tmp_dir = /tmp
 .br
+
+# Show full paths during list operation if non\-zero
+.br
+lcov_list_full_path = 0
+.br
+
+# Specify the maximum width for list output. This value is
+.br
+# ignored when lcov_list_full_path is non\-zero.
+.br
+lcov_list_width = 80
+.br
+
+# Specify the maximum percentage of file names which may be
+.br
+# truncated when choosing a directory prefix in list output.
+.br
+# This value is ignored when lcov_list_full_path is non\-zero.
+.br
+lcov_list_truncate_max = 20
+
+# Specify if function coverage data should be collected and
+.br
+# processed.
+.br
+lcov_function_coverage = 1
+.br
+
+# Specify if branch coverage data should be collected and
+.br
+# processed.
+.br
+lcov_branch_coverage = 0
+.br
 .PP
 
 .SH OPTIONS
@@ -206,17 +272,12 @@
 .BR genhtml_med_limit " ="
 .I med_limit
 .br
-.BR genhtml_function_med_limit " ="
-.I hi_limit
-.br
-.BR genhtml_function_med_limit " ="
-.I med_limit
 .IP
 Specify coverage rate limits for classifying file entries. Use this option to
-modify the coverage rates (in percent) for line or function coverage at which
-a result is classified as high, medium or low coverage. This classification
-affects the color of the corresponding entries on the overview pages of the
-HTML output:
+modify the coverage rates (in percent) for line, function and branch coverage at
+which a result is classified as high, medium or low coverage. This
+classification affects the color of the corresponding entries on the overview
+pages of the HTML output:
 .br
 
 High:   hi_limit  <= rate <= 100        default color: green
@@ -226,8 +287,27 @@
 Low:    0         <= rate < med_limit   default color: red
 .br
 
-Defaults are 50 and 15 percent for line coverage and 90 and 75 percent for
-function coverage.
+Defaults are 90 and 75 percent.
+.PP
+
+.BR genhtml_line_field_width " ="
+.I number_of_characters
+.IP
+Specify the width (in characters) of the source code view column containing
+line coverage information.
+.br
+
+Default is 12.
+.PP
+
+.BR genhtml_branch_field_width " ="
+.I number_of_characters
+.IP
+Specify the width (in characters) of the source code view column containing
+branch coverage information.
+.br
+
+Default is 16.
 .PP
 
 .BR genhtml_overview_width " ="
@@ -438,6 +518,34 @@
 Default is 1.
 .PP
 
+.BR genhtml_branch_coverage " ="
+.IR 0 | 1
+.IP
+If non\-zero, include branch coverage data when generating HTML output using
+.BR genhtml .
+.br
+
+This option can be set to 0 by using the \-\-no\-branch\-coverage option of
+.BR genhtml .
+.br
+
+Default is 1.
+.PP
+
+.BR genhtml_charset " ="
+.I charset
+.IP
+Specify the character set of all generated HTML pages.
+.br
+
+Use this option if the source code contains characters which are not
+part of the default character set. Note that this option is ignored
+when a custom HTML prolog is specified (see also
+.BR genhtml_html_prolog ).
+.br
+
+Default is UTF-8.
+.PP
 .BR geninfo_gcov_tool " ="
 .I path_to_gcov
 .IP
@@ -492,40 +600,129 @@
 Default is 1.
 .PP
 
+.BR geninfo_external " ="
+.IR 0 | 1
+.IP
+If non\-zero, capture coverage data for external source files.
+
+External source files are files which are not located in one of the directories
+(including sub-directories)
+specified by the \-\-directory or \-\-base\-directory options of
+.BR lcov / geninfo .
+
+Default is 1.
+.PP
+
+.BR geninfo_gcov_all_blocks " ="
+.IR 0 | 1
+.IP
+If non\-zero, call the gcov tool with option --all-blocks.
+
+Using --all-blocks will produce more detailed branch coverage information for
+each line. Set this option to zero if you do not need detailed branch coverage
+information to speed up the process of capturing code coverage or to work
+around a bug in some versions of gcov which will cause it to endlessly loop
+when analysing some files.
+
+Default is 1.
+.PP
+
+.BR geninfo_compat " ="
+.IR mode = value [, mode = value ,...]
+.IP
+Specify that geninfo should enable one or more compatibility modes
+when capturing coverage data.
+
+This option corresponds to the \-\-compat command line option of
+.BR geninfo .
+
+Default is 'libtool=on, hammer=auto, split_crc=auto'.
+.PP
+
+.BR geninfo_adjust_src_path " ="
+.IR pattern " => " replacement
+.br
+.BR geninfo_adjust_src_path " ="
+.I pattern
+.IP
+Adjust source paths when capturing coverage data.
+
+Use this option in situations where geninfo cannot find the correct
+path to source code files of a project. By providing a
+.I pattern
+in Perl regular expression format (see
+.BR perlre (1))
+and an optional replacement string, you can instruct geninfo to
+remove or change parts of the incorrect source path.
+
+.B Example:
+.br
+
+1. When geninfo reports that it cannot find source file
+.br
+
+    /path/to/src/.libs/file.c
+.br
+
+while the file is actually located in
+.br
+
+    /path/to/src/file.c
+.br
+
+use the following parameter:
+.br
+
+    geninfo_adjust_src_path = /.libs
+
+This will remove all "/.libs" strings from the path.
+
+2. When geninfo reports that it cannot find source file
+.br
+
+    /tmp/build/file.c
+.br
+
+while the file is actually located in
+.br
+
+    /usr/src/file.c
+.br
+
+use the following parameter:
+.br
+
+    geninfo_adjust_src_path = /tmp/build => /usr/src
+.br
+
+This will change all "/tmp/build" strings in the path to "/usr/src".
+.PP
+
+.BR geninfo_auto_base " ="
+.IR 0 | 1
+.IP
+If non\-zero, apply a heuristic to determine the base directory when
+collecting coverage data.
+.br
+
+Use this option when using geninfo on projects built with libtool or
+similar build environments that work with multiple base directories,
+i.e. environments, where the current working directory when invoking the
+compiler ist not the same directory in which the source code file is
+located, and in addition, is different between files of the same project.
+.br
+
+Default is 1.
+.PP
+
 .BR lcov_gcov_dir " ="
 .I path_to_kernel_coverage_data
 .IP
-Specify the path to the directory where kernel coverage data can be found.
+Specify the path to the directory where kernel coverage data can be found
+or leave undefined for auto-detection.
 .br
 
-Default is '/proc/gcov'.
-.PP
-
-.BR lcov_insmod_tool " ="
-.I path_to_insmod
-.IP
-Specify the location of the insmod tool used to load kernel modules.
-.br
-
-Default is '/sbin/insmod'.
-.PP
-
-.BR lcov_modprobe_tool " ="
-.I path_to_modprobe
-.IP
-Specify the location of the modprobe tool used to load kernel modules.
-.br
-
-Default is '/sbin/modprobe'.
-.PP
-
-.BR lcov_rmmod_tool " ="
-.I path_to_rmmod
-.IP
-Specify the location of the rmmod tool used to unload kernel modules.
-.br
-
-Default is '/sbin/rmmod'.
+Default is auto-detection.
 .PP
 
 .BR lcov_tmp_dir " ="
@@ -537,6 +734,73 @@
 Default is '/tmp'.
 .PP
 
+.BR lcov_list_full_path " ="
+.IR 0 | 1
+.IP
+If non-zero, print the full path to source code files during a list operation.
+.br
+
+This option corresponds to the \-\-list\-full\-path option of
+.BR lcov .
+.br
+
+Default is 0.
+.PP
+
+.BR lcov_list_max_width " ="
+.IR width
+.IP
+Specify the maximum width for list output. This value is ignored when
+lcov_list_full_path is non\-zero.
+.br
+
+Default is 80.
+.PP
+
+.BR lcov_list_truncate_max
+.B " ="
+.IR percentage
+.IP
+Specify the maximum percentage of file names which may be truncated when
+choosing a directory prefix in list output. This value is ignored when
+lcov_list_full_path is non\-zero.
+.br
+
+Default is 20.
+.PP
+
+.BR lcov_function_coverage " ="
+.IR 0 | 1
+.IP
+Specify whether lcov should handle function coverage data.
+.br
+
+Setting this option to 0 can reduce memory and CPU time consumption
+when lcov is collecting and processing coverage data, as well as
+reduce the size of the resulting data files. Note that setting
+.B genhtml_function_coverage
+will override this option for HTML generation.
+.br
+
+Default is 1.
+.PP
+
+.BR lcov_branch_coverage " ="
+.IR 0 | 1
+.IP
+Specify whether lcov should handle branch coverage data.
+.br
+
+Setting this option to 0 can reduce memory and CPU time consumption
+when lcov is collecting and processing coverage data, as well as
+reduce the size of the resulting data files. Note that setting
+.B genhtml_branch_coverage
+will override this option for HTML generation.
+.br
+
+Default is 0.
+.PP
+
 .SH FILES
 
 .TP
diff --git a/third_party/lcov/rpm/lcov.spec b/third_party/lcov/rpm/lcov.spec
index 894e1c4..d1daca1 100644
--- a/third_party/lcov/rpm/lcov.spec
+++ b/third_party/lcov/rpm/lcov.spec
@@ -1,6 +1,6 @@
 Summary: A graphical GCOV front-end
 Name: lcov
-Version: 1.7
+Version: 1.10
 Release: 1
 License: GPL
 Group: Development/Tools
@@ -8,6 +8,7 @@
 Source0: http://downloads.sourceforge.net/ltp/lcov-%{version}.tar.gz
 BuildRoot: /var/tmp/%{name}-%{version}-root
 BuildArch: noarch
+Requires: perl >= 5.8.8
 
 %description
 LCOV is a graphical front-end for GCC's coverage testing tool gcov. It collects
@@ -35,6 +36,8 @@
 /etc
 
 %changelog
+* Mon May 07 2012 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
+- added dependency on perl 5.8.8 for >>& open mode support
 * Wed Aug 13 2008 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
 - changed description + summary text
 * Mon Aug 20 2007 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
diff --git a/third_party/leveldatabase/README.chromium b/third_party/leveldatabase/README.chromium
index d1f08d3..1462c90 100644
--- a/third_party/leveldatabase/README.chromium
+++ b/third_party/leveldatabase/README.chromium
@@ -1,7 +1,7 @@
 Name: LevelDB: A Fast Persistent Key-Value Store
 Short Name: leveldb
 URL: http://code.google.com/p/leveldb/
-Version: r75
+Version: r76
 License: New BSD
 License File: src/LICENSE
 Security Critical: yes
diff --git a/third_party/leveldatabase/port/port_chromium.h b/third_party/leveldatabase/port/port_chromium.h
index 6de765e..661e85b 100644
--- a/third_party/leveldatabase/port/port_chromium.h
+++ b/third_party/leveldatabase/port/port_chromium.h
@@ -22,6 +22,7 @@
 
 #if defined(OS_WIN)
 #define snprintf _snprintf
+typedef SSIZE_T ssize_t;
 #if !defined(__clang__)
 # define va_copy(a, b) do { (a) = (b); } while (0)
 #endif
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index 0acd33d..aba9c46 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://code.google.com/p/webrtc/
 Version: unknown
-Revision: 4533
+Revision: 4595
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/libwebp/README.chromium b/third_party/libwebp/README.chromium
index 63b625c..4bb032b 100644
--- a/third_party/libwebp/README.chromium
+++ b/third_party/libwebp/README.chromium
@@ -23,3 +23,5 @@
 Cherry-picks:
   f626fe2 Detect canvas and image size mismatch in decoder.
   f5fbdee demux: stricter image bounds check
+  a03c351 Demux: WebPIterator now also denotes if the frame has alpha.
+  6284854b Support for "Do not blend" in mux and demux libraries
diff --git a/third_party/libwebp/demux/demux.c b/third_party/libwebp/demux/demux.c
index 8c2250d..1d765c7 100644
--- a/third_party/libwebp/demux/demux.c
+++ b/third_party/libwebp/demux/demux.c
@@ -47,8 +47,10 @@
 typedef struct Frame {
   int x_offset_, y_offset_;
   int width_, height_;
+  int has_alpha_;
   int duration_;
   WebPMuxAnimDispose dispose_method_;
+  WebPMuxAnimBlend blend_method_;
   int is_fragment_;  // this is a frame fragment (and not a full frame).
   int frame_num_;  // the referent frame number for use in assembling fragments.
   int complete_;   // img_components_ contains a full image.
@@ -196,18 +198,13 @@
 }
 
 // Store image bearing chunks to 'frame'.
-// If 'has_vp8l_alpha' is not NULL, it will be set to true if the frame is a
-// lossless image with alpha.
 static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
-                              MemBuffer* const mem, Frame* const frame,
-                              int* const has_vp8l_alpha) {
+                              MemBuffer* const mem, Frame* const frame) {
   int alpha_chunks = 0;
   int image_chunks = 0;
   int done = (MemDataSize(mem) < min_size);
   ParseStatus status = PARSE_OK;
 
-  if (has_vp8l_alpha != NULL) *has_vp8l_alpha = 0;  // Default.
-
   if (done) return PARSE_NEED_MORE_DATA;
 
   do {
@@ -229,6 +226,7 @@
           ++alpha_chunks;
           frame->img_components_[1].offset_ = chunk_start_offset;
           frame->img_components_[1].size_ = chunk_size;
+          frame->has_alpha_ = 1;
           frame->frame_num_ = frame_num;
           Skip(mem, payload_available);
         } else {
@@ -258,7 +256,7 @@
           frame->img_components_[0].size_ = chunk_size;
           frame->width_ = features.width;
           frame->height_ = features.height;
-          if (has_vp8l_alpha != NULL) *has_vp8l_alpha = features.has_alpha;
+          frame->has_alpha_ |= features.has_alpha;
           frame->frame_num_ = frame_num;
           frame->complete_ = (status == PARSE_OK);
           Skip(mem, payload_available);
@@ -306,6 +304,7 @@
   const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
   const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
   int added_frame = 0;
+  int bits;
   MemBuffer* const mem = &dmux->mem_;
   Frame* frame;
   ParseStatus status =
@@ -317,7 +316,10 @@
   frame->width_          = 1 + ReadLE24s(mem);
   frame->height_         = 1 + ReadLE24s(mem);
   frame->duration_       = ReadLE24s(mem);
-  frame->dispose_method_ = (WebPMuxAnimDispose)(ReadByte(mem) & 1);
+  bits = ReadByte(mem);
+  frame->dispose_method_ =
+      (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
+  frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
   if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
     free(frame);
     return PARSE_ERROR;
@@ -325,8 +327,7 @@
 
   // Store a frame only if the animation flag is set there is some data for
   // this frame is available.
-  status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame,
-                      NULL);
+  status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
   if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) {
     added_frame = AddFrame(dmux, frame);
     if (added_frame) {
@@ -361,7 +362,7 @@
 
   // Store a fragment only if the fragments flag is set there is some data for
   // this fragment is available.
-  status = StoreFrame(frame_num, frgm_payload_size, mem, frame, NULL);
+  status = StoreFrame(frame_num, frgm_payload_size, mem, frame);
   if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) {
     added_fragment = AddFrame(dmux, frame);
     if (!added_fragment) {
@@ -424,7 +425,6 @@
   MemBuffer* const mem = &dmux->mem_;
   Frame* frame;
   ParseStatus status;
-  int has_vp8l_alpha = 0;  // Frame contains a lossless image with alpha.
 
   if (dmux->frames_ != NULL) return PARSE_ERROR;
   if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
@@ -435,14 +435,14 @@
 
   // For the single image case we allow parsing of a partial frame, but we need
   // at least CHUNK_HEADER_SIZE for parsing.
-  status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame,
-                      &has_vp8l_alpha);
+  status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame);
   if (status != PARSE_ERROR) {
     const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
     // Clear any alpha when the alpha flag is missing.
     if (!has_alpha && frame->img_components_[1].size_ > 0) {
       frame->img_components_[1].offset_ = 0;
       frame->img_components_[1].size_ = 0;
+      frame->has_alpha_ = 0;
     }
 
     // Use the frame width/height as the canvas values for non-vp8x files.
@@ -451,7 +451,7 @@
       dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
       dmux->canvas_width_ = frame->width_;
       dmux->canvas_height_ = frame->height_;
-      dmux->feature_flags_ |= has_vp8l_alpha ? ALPHA_FLAG : 0;
+      dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
     }
     AddFrame(dmux, frame);
     dmux->num_frames_ = 1;
@@ -836,8 +836,10 @@
   iter->y_offset       = fragment->y_offset_;
   iter->width          = fragment->width_;
   iter->height         = fragment->height_;
+  iter->has_alpha      = fragment->has_alpha_;
   iter->duration       = fragment->duration_;
   iter->dispose_method = fragment->dispose_method_;
+  iter->blend_method   = fragment->blend_method_;
   iter->complete       = fragment->complete_;
   iter->fragment.bytes = payload;
   iter->fragment.size  = payload_size;
diff --git a/third_party/libwebp/webp/demux.h b/third_party/libwebp/webp/demux.h
index c7cd5d6..894ff4e 100644
--- a/third_party/libwebp/webp/demux.h
+++ b/third_party/libwebp/webp/demux.h
@@ -53,7 +53,7 @@
 extern "C" {
 #endif
 
-#define WEBP_DEMUX_ABI_VERSION 0x0100    // MAJOR(8b) + MINOR(8b)
+#define WEBP_DEMUX_ABI_VERSION 0x0101    // MAJOR(8b) + MINOR(8b)
 
 // Note: forward declaring enumerations is not allowed in (strict) C and C++,
 // the types are left here for reference.
@@ -136,8 +136,10 @@
                   // may still be decoded with the WebP incremental decoder.
   WebPData fragment;  // The frame or fragment given by 'frame_num' and
                       // 'fragment_num'.
+  int has_alpha;      // True if the frame or fragment contains transparency.
+  WebPMuxAnimBlend blend_method;  // Blend operation for the frame.
 
-  uint32_t pad[4];         // padding for later use.
+  uint32_t pad[2];         // padding for later use.
   void* private_;          // for internal use only.
 };
 
diff --git a/third_party/libwebp/webp/mux.h b/third_party/libwebp/webp/mux.h
index b8c7dc6..cd56650 100644
--- a/third_party/libwebp/webp/mux.h
+++ b/third_party/libwebp/webp/mux.h
@@ -199,7 +199,8 @@
   WebPChunkId id;         // frame type: should be one of WEBP_CHUNK_ANMF,
                           // WEBP_CHUNK_FRGM or WEBP_CHUNK_IMAGE
   WebPMuxAnimDispose dispose_method;  // Disposal method for the frame.
-  uint32_t    pad[2];     // padding for later use
+  WebPMuxAnimBlend   blend_method;    // Blend operation for the frame.
+  uint32_t    pad[1];     // padding for later use
 };
 
 // Sets the (non-animated and non-fragmented) image in the mux object.
diff --git a/third_party/libwebp/webp/mux_types.h b/third_party/libwebp/webp/mux_types.h
index b8bce36..94d8806 100644
--- a/third_party/libwebp/webp/mux_types.h
+++ b/third_party/libwebp/webp/mux_types.h
@@ -26,6 +26,7 @@
 // the types are left here for reference.
 // typedef enum WebPFeatureFlags WebPFeatureFlags;
 // typedef enum WebPMuxAnimDispose WebPMuxAnimDispose;
+// typedef enum WebPMuxAnimBlend WebPMuxAnimBlend;
 typedef struct WebPData WebPData;
 
 // VP8X Feature Flags.
@@ -45,6 +46,13 @@
   WEBP_MUX_DISPOSE_BACKGROUND  // Dispose to background color.
 } WebPMuxAnimDispose;
 
+// Blend operation (animation only). Indicates how transparent pixels of the
+// current frame are blended with those of the previous canvas.
+typedef enum WebPMuxAnimBlend {
+  WEBP_MUX_BLEND,              // Blend.
+  WEBP_MUX_NO_BLEND            // Do not blend.
+} WebPMuxAnimBlend;
+
 // Data type used to describe 'raw' data, e.g., chunk data
 // (ICC profile, metadata) and WebP compressed image data.
 struct WebPData {
diff --git a/third_party/libxml/chromium/libxml_utils.cc b/third_party/libxml/chromium/libxml_utils.cc
index 63cbb6b..a237be5 100644
--- a/third_party/libxml/chromium/libxml_utils.cc
+++ b/third_party/libxml/chromium/libxml_utils.cc
@@ -48,6 +48,10 @@
   return true;
 }
 
+bool XmlReader::IsClosingElement() {
+  return NodeType() == XML_READER_TYPE_END_ELEMENT;
+}
+
 bool XmlReader::ReadElementContent(std::string* content) {
   const int start_depth = Depth();
 
diff --git a/third_party/libxml/chromium/libxml_utils.h b/third_party/libxml/chromium/libxml_utils.h
index d230c5d..9091f49 100644
--- a/third_party/libxml/chromium/libxml_utils.h
+++ b/third_party/libxml/chromium/libxml_utils.h
@@ -73,6 +73,9 @@
   // returns true and |value| is set to "a".
   bool NodeAttribute(const char* name, std::string* value);
 
+  // Returns true if the node is a closing element (e.g. </foo>).
+  bool IsClosingElement();
+
   // Helper functions not provided by libxml ----------------------------------
 
   // Return the string content within an element.
@@ -133,6 +136,12 @@
     return xmlTextWriterEndElement(writer_) >= 0;
   }
 
+  // Appends to the content of the current open element.
+  bool AppendElementContent(const std::string& content) {
+    return xmlTextWriterWriteString(writer_,
+                                    BAD_CAST content.c_str()) >= 0;
+  }
+
   // Adds an attribute to the current open element. Returns false on error.
   bool AddAttribute(const std::string& attribute_name,
                     const std::string& attribute_value) {
diff --git a/third_party/mach_override/README.chromium b/third_party/mach_override/README.chromium
index adb7d47..46f2010 100644
--- a/third_party/mach_override/README.chromium
+++ b/third_party/mach_override/README.chromium
@@ -19,3 +19,6 @@
 Local Modifications:
 Ensure no rwx pages remain after mach_override_ptr:
 https://codereview.chromium.org/21208002/ 
+
+Randomize mach_override_ptr trampoline addresses on 32-bit:
+https://codereview.chromium.org/22798004/
diff --git a/third_party/mach_override/mach_override.c b/third_party/mach_override/mach_override.c
index ea41569..21afa28 100644
--- a/third_party/mach_override/mach_override.c
+++ b/third_party/mach_override/mach_override.c
@@ -11,6 +11,7 @@
 #include <mach/mach_host.h>
 #include <mach/mach_init.h>
 #include <mach/vm_map.h>
+#include <mach/vm_statistics.h>
 #include <sys/mman.h>
 
 #include <CoreServices/CoreServices.h>
@@ -379,15 +380,22 @@
 	assert( island );
 	
 	assert( sizeof( BranchIsland ) <= kPageSize );
+#if defined(__i386__)
+	vm_address_t page = 0;
+	mach_error_t err = vm_allocate( mach_task_self(), &page, kPageSize, VM_FLAGS_ANYWHERE );
+	if( err == err_none ) {
+		*island = (BranchIsland*) page;
+		return err_none;
+	}
+	return err;
+#else
+
 #if defined(__ppc__) || defined(__POWERPC__)
 	vm_address_t first = 0xfeffffff;
 	vm_address_t last = 0xfe000000 + kPageSize;
 #elif defined(__x86_64__)
 	vm_address_t first = ((uint64_t)originalFunctionAddress & ~(uint64_t)(((uint64_t)1 << 31) - 1)) | ((uint64_t)1 << 31); // start in the middle of the page?
 	vm_address_t last = 0x0;
-#else
-	vm_address_t first = 0xffc00000;
-	vm_address_t last = 0xfffe0000;
 #endif
 
 	vm_address_t page = first;
@@ -410,6 +418,7 @@
 	}
 
 	return KERN_NO_SPACE;
+#endif
 }
 
 /***************************************************************************//**
diff --git a/third_party/polymer/README.chromium b/third_party/polymer/README.chromium
index 36a338b..5d40a6f 100644
--- a/third_party/polymer/README.chromium
+++ b/third_party/polymer/README.chromium
@@ -1,7 +1,7 @@
 Name: Polymer
 URL: http://www.polymer-project.org
-Version: 0.0.20130711
-Revision: 983a363af92ef42f02d54999ef284b706655d15d
+Version: 0.0.20130815
+Revision: e07f3c2148fa37eb5eb50b49d724efcfad4af3c8
 License: BSD
 License File: LICENSE
 Security Critical: no
diff --git a/third_party/polymer/build.log b/third_party/polymer/build.log
index adf4a45..71c1cf1 100644
--- a/third_party/polymer/build.log
+++ b/third_party/polymer/build.log
@@ -1,41 +1,45 @@
 BUILD LOG
 ---------
-Build Time: 2013-07-11T14:50:28
+Build Time: 2013-08-15T16:02:48
 
 NODEJS INFORMATION
 ==================
 nodejs: v0.10.4
-chai: 1.7.1
+chai: 1.7.2
 grunt: 0.4.1
 grunt-audit: 0.0.1
 grunt-contrib-uglify: 0.2.2
 grunt-contrib-yuidoc: 0.4.0
 grunt-karma: 0.5.0
-karma: 0.9.3
+karma: 0.9.7
 karma-chrome-launcher: 0.0.2
-karma-coffee-preprocessor: 0.0.1
+karma-coffee-preprocessor: 0.0.3
 karma-crbot-reporter: 0.0.3
-karma-firefox-launcher: 0.0.2
-karma-jasmine: 0.0.1
-karma-mocha: 0.0.1
+karma-firefox-launcher: 0.0.3
+karma-html2js-preprocessor: 0.0.2
+karma-jasmine: 0.0.3
+karma-mocha: 0.0.4
 karma-phantomjs-launcher: 0.0.2
-karma-requirejs: 0.0.1
-karma-script-launcher: 0.0.1
-mocha: 1.11.0
+karma-requirejs: 0.0.3
+karma-script-launcher: 0.0.2
+mocha: 1.12.0
 
 REPO REVISIONS
 ==============
-polymer: b3727b3cc08225e27a2f72105d6ea495ff975661
-platform: cd92266d192dbc2b82cf37a477b3a5213989114c
-ShadowDOM: 99775988a711e4093153e0f4d68a4d73814f2a1f
-HTMLImports: 69e86c01bde0e88e2a9d85fd5dec01f454edaf55
-CustomElements: ac5a5aba2296d758580063bce5fe8feb59bcc54a
-PointerEvents: ea792e163c90a7199a036b9026b835de2d7d93fb
-PointerGestures: 39a1434940e01109157161110158f8727a981f42
-mdv: 6691933756030c7653234054db34f23f20fe576a
+polymer: a32f21b234129a290ea4931a2c6d7345f6825789
+platform: 8645fe5180f3c122aa509f0c55c956b70ce4bd96
+ShadowDOM: 9d8aa3b41401ebb215bb0879296ce85a28c30f98
+HTMLImports: 71b260f6391bb6174c2699b538127c4cce78dbbd
+CustomElements: 284aa7f202ddd9fd015a6f666e20af784e574e23
+PointerEvents: 1fd01697ac021718453ea0ea8712246578dfc55f
+PointerGestures: 128f4c1c30837f99f9b7282e8cc1ceaef112c2de
+polymer-expressions: 3741c09c245e29db1d697a8bf40014c59800c76f
+observe-js: 35498d97fa6dfe06d15cb7488f1186fa4f5d46ae
+NodeBind: 1e32d4703ce57c31483834c4527c98b9b08597fb
+TemplateBinding: 548f86d763051c59472ad17ac0274efe55cf9d4f
 
 BUILD HASHES
 ============
-polymer.min.js: 983a363af92ef42f02d54999ef284b706655d15d
-polymer.native.min.js: 5b47f9ddbe75673975b5b2b25807e9ca88b6d44f
-polymer.sandbox.min.js: dbdfbb0e57423136557f9fe8959709e294d9560c
+polymer.min.js: e07f3c2148fa37eb5eb50b49d724efcfad4af3c8
+polymer.native.min.js: 1bf3aec7bf2236711599e94efe4a1720b8ca0ee3
+polymer.sandbox.min.js: f7267b34d6c9dcc47f129a52d2117ecdec3f4bd9
\ No newline at end of file
diff --git a/third_party/polymer/polymer.min.js b/third_party/polymer/polymer.min.js
index 939910b..a1d85fa 100644
--- a/third_party/polymer/polymer.min.js
+++ b/third_party/polymer/polymer.min.js
@@ -25,11 +25,13 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-function PointerGestureEvent(a,b){var c=b||{},d=document.createEvent("Event"),e={bubbles:!0,cancelable:!0};return Object.keys(e).forEach(function(a){a in c&&(e[a]=c[a])}),d.initEvent(a,e.bubbles,e.cancelable),Object.keys(c).forEach(function(a){d[a]=b[a]}),d.preventTap=this.preventTap,d}if(window.Platform=window.Platform||{},window.logFlags=window.logFlags||{},function(a){var b=a.flags||{};location.search.slice(1).split("&").forEach(function(a){a=a.split("="),a[0]&&(b[a[0]]=a[1]||!0)}),b.shadow=(b.shadowdom||b.shadow||b.polyfill||!HTMLElement.prototype.webkitCreateShadowRoot)&&"polyfill",a.flags=b}(Platform),"polyfill"===Platform.flags.shadow){var SideTable;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},SideTable.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}();var ShadowDOMPolyfill={};!function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function d(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){switch(c){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":return}Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function e(a){var b=a.__proto__||Object.getPrototypeOf(a),c=z.get(b);if(c)return c;var d=e(b),f=n(d);return k(b,f,a),f}function f(a,b){i(a,b,!0)}function g(a,b){i(b,a,!1)}function h(a){return/^on[a-z]+$/.test(a)}function i(b,c,d){Object.getOwnPropertyNames(b).forEach(function(e){if(!(e in c)){B&&b.__lookupGetter__(e);var f;try{f=Object.getOwnPropertyDescriptor(b,e)}catch(g){f=C}var i,j;if(d&&"function"==typeof f.value)return c[e]=function(){return this.impl[e].apply(this.impl,arguments)},void 0;var k=h(e);i=k?a.getEventHandlerGetter(e):function(){return this.impl[e]},(f.writable||f.set)&&(j=k?a.getEventHandlerSetter(e):function(a){this.impl[e]=a}),Object.defineProperty(c,e,{get:i,set:j,configurable:f.configurable,enumerable:f.enumerable})}})}function j(a,b,c){var e=a.prototype;k(e,b,c),d(b,a)}function k(a,c,d){var e=c.prototype;b(void 0===z.get(a)),z.set(a,c),f(a,e),d&&g(e,d)}function l(a,b){return z.get(b.prototype)===a}function m(a){var b=Object.getPrototypeOf(a),c=e(b),d=n(c);return k(b,d,a),d}function n(a){function b(b){a.call(this,b)}return b.prototype=Object.create(a.prototype),b.prototype.constructor=b,b}function o(a){return a instanceof A.EventTarget||a instanceof A.Event||a instanceof A.DOMImplementation}function p(a){return a instanceof F||a instanceof E||a instanceof G||a instanceof D}function q(a){if(null===a)return null;b(p(a));var c=y.get(a);if(!c){var d=e(a);c=new d(a),y.set(a,c)}return c}function r(a){return null===a?null:(b(o(a)),a.impl)}function s(a){return a&&o(a)?r(a):a}function t(a){return a&&!o(a)?q(a):a}function u(a,c){null!==c&&(b(p(a)),b(void 0===c||o(c)),y.set(a,c))}function v(a,b,c){Object.defineProperty(a.prototype,b,{get:c,configurable:!0,enumerable:!0})}function w(a,b){v(a,b,function(){return q(this.impl[b])})}function x(a,b){a.forEach(function(a){b.forEach(function(b){a.prototype[b]=function(){var a=q(this);return a[b].apply(a,arguments)}})})}var y=new SideTable,z=new SideTable,A=Object.create(null);Object.getOwnPropertyNames(window);var B=/Firefox/.test(navigator.userAgent),C={get:function(){},set:function(){},configurable:!0,enumerable:!0},D=DOMImplementation,E=Event,F=Node,G=Window;a.assert=b,a.defineGetter=v,a.defineWrapGetter=w,a.forwardMethodsToWrapper=x,a.isWrapperFor=l,a.mixin=c,a.registerObject=m,a.registerWrapper=j,a.rewrap=u,a.unwrap=r,a.unwrapIfNeeded=s,a.wrap=q,a.wrapIfNeeded=t,a.wrappers=A}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){return a instanceof N.ShadowRoot}function c(a){var b=a.localName;return"content"===b||"shadow"===b}function d(a){return!!a.shadowRoot}function e(a){var b;return a.parentNode||(b=a.defaultView)&&M(b)||null}function f(f,g,h){if(h.length)return h.shift();if(b(f))return j(f)||a.getHostForShadowRoot(f);var i=a.eventParentsTable.get(f);if(i){for(var k=1;k<i.length;k++)h[k-1]=i[k];return i[0]}if(g&&c(f)){var l=f.parentNode;if(l&&d(l))for(var m=a.getShadowTrees(l),n=j(g),k=0;k<m.length;k++)if(m[k].contains(n))return n}return e(f)}function g(a){for(var d=[],e=a,g=[],i=[];e;){var j=null;if(c(e)){j=h(d);var k=d[d.length-1]||e;d.push(k)}else d.length||d.push(e);var l=d[d.length-1];g.push({target:l,currentTarget:e}),b(e)&&d.pop(),e=f(e,j,i)}return g}function h(a){for(var b=a.length-1;b>=0;b--)if(!c(a[b]))return a[b];return null}function i(d,e){for(var g=[];d;){for(var i=[],j=e,l=void 0;j;){var n=null;if(i.length){if(c(j)&&(n=h(i),k(l))){var o=i[i.length-1];i.push(o)}}else i.push(j);if(m(j,d))return i[i.length-1];b(j)&&i.pop(),l=j,j=f(j,n,g)}d=b(d)?a.getHostForShadowRoot(d):d.parentNode}}function j(b){return a.insertionParentTable.get(b)}function k(a){return j(a)}function l(a){for(var b;b=a.parentNode;)a=b;return a}function m(a,b){return l(a)===l(b)}function n(b,c){if(b===c)return!0;if(b instanceof N.ShadowRoot){var d=a.getHostForShadowRoot(b);return d?n(l(d),c):!1}return!1}function o(a){switch(a){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function p(b){if(!P.get(b)){P.set(b,!0),o(b.type)||a.renderAllPending();var c=M(b.target),d=M(b);return q(d,c)}}function q(a,b){var c=g(b);return"load"===a.type&&2===c.length&&c[0].target instanceof N.Document&&c.shift(),X.set(a,c),r(a,c)&&s(a,c)&&t(a,c),T.set(a,w.NONE),R.set(a,null),a.defaultPrevented}function r(a,b){for(var c,d=b.length-1;d>0;d--){var e=b[d].target,f=b[d].currentTarget;if(e!==f&&(c=w.CAPTURING_PHASE,!u(b[d],a,c)))return!1}return!0}function s(a,b){var c=w.AT_TARGET;return u(b[0],a,c)}function t(a,b){for(var c,d=a.bubbles,e=1;e<b.length;e++){var f=b[e].target,g=b[e].currentTarget;if(f===g)c=w.AT_TARGET;else{if(!d||V.get(a))continue;c=w.BUBBLING_PHASE}if(!u(b[e],a,c))return}}function u(a,b,c){var d=a.target,e=a.currentTarget,f=O.get(e);if(!f)return!0;if("relatedTarget"in b){var g=L(b),h=M(g.relatedTarget),j=i(e,h);if(j===d)return!0;S.set(b,j)}T.set(b,c);var k=b.type,l=!1;Q.set(b,d),R.set(b,e);for(var m=0;m<f.length;m++){var n=f[m];if(n.removed)l=!0;else if(!(n.type!==k||!n.capture&&c===w.CAPTURING_PHASE||n.capture&&c===w.BUBBLING_PHASE))try{if("function"==typeof n.handler?n.handler.call(e,b):n.handler.handleEvent(b),V.get(b))return!1}catch(o){window.onerror?window.onerror(o.message):console.error(o)}}if(l){var p=f.slice();f.length=0;for(var m=0;m<p.length;m++)p[m].removed||f.push(p[m])}return!U.get(b)}function v(a,b,c){this.type=a,this.handler=b,this.capture=Boolean(c)}function w(a,b){return a instanceof Y?(this.impl=a,void 0):M(A(Y,"Event",a,b))}function x(a){return a&&a.relatedTarget?Object.create(a,{relatedTarget:{value:L(a.relatedTarget)}}):a}function y(a,b,c){var d=window[a],e=function(b,c){return b instanceof d?(this.impl=b,void 0):M(A(d,a,b,c))};return e.prototype=Object.create(b.prototype),c&&J(e.prototype,c),d&&(d.prototype["init"+a]?K(d,e,document.createEvent(a)):K(d,e,new d("temp"))),e}function z(a,b){return function(){arguments[b]=L(arguments[b]);var c=L(this);c[a].apply(c,arguments)}}function A(a,b,c,d){if(gb)return new a(c,x(d));var e=L(document.createEvent(b)),f=fb[b],g=[c];return Object.keys(f).forEach(function(a){var b=null!=d&&a in d?d[a]:f[a];"relatedTarget"===a&&(b=L(b)),g.push(b)}),e["init"+b].apply(e,g),e}function B(a){return"function"==typeof a?!0:a&&a.handleEvent}function C(a){this.impl=a}function D(b){return b instanceof N.ShadowRoot&&(b=a.getHostForShadowRoot(b)),L(b)}function E(a){I(a,jb)}function F(b,c,d,e){a.renderAllPending();for(var f=M(kb.call(c.impl,d,e)),h=g(f,this),i=0;i<h.length;i++){var j=h[i];if(j.currentTarget===b)return j.target}return null}function G(a){return function(){var b=W.get(this);return b&&b[a]&&b[a].value||null}}function H(a){var b=a.slice(2);return function(c){var d=W.get(this);d||(d=Object.create(null),W.set(this,d));var e=d[a];if(e&&this.removeEventListener(b,e.wrapped,!1),"function"==typeof c){var f=function(b){var d=c.call(this,b);d===!1?b.preventDefault():"onbeforeunload"===a&&"string"==typeof d&&(b.returnValue=d)};this.addEventListener(b,f,!1),d[a]={value:c,wrapped:f}}}}var I=a.forwardMethodsToWrapper,J=a.mixin,K=a.registerWrapper,L=a.unwrap,M=a.wrap,N=a.wrappers;new SideTable;var O=new SideTable,P=new SideTable,Q=new SideTable,R=new SideTable,S=new SideTable,T=new SideTable,U=new SideTable,V=new SideTable,W=new SideTable,X=new SideTable;v.prototype={equals:function(a){return this.handler===a.handler&&this.type===a.type&&this.capture===a.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var Y=window.Event;w.prototype={get target(){return Q.get(this)},get currentTarget(){return R.get(this)},get eventPhase(){return T.get(this)},get path(){var a=new N.NodeList,b=X.get(this);if(b){for(var c=0,d=b.length-1,e=l(R.get(this)),f=0;d>=f;f++){var g=b[f].currentTarget,h=l(g);n(e,h)&&(f!==d||g instanceof N.Node)&&(a[c++]=g)}a.length=c}return a},stopPropagation:function(){U.set(this,!0)},stopImmediatePropagation:function(){U.set(this,!0),V.set(this,!0)}},K(Y,w,document.createEvent("Event"));var Z=y("UIEvent",w),$=y("CustomEvent",w),_={get relatedTarget(){return S.get(this)||M(L(this).relatedTarget)}},ab=J({initMouseEvent:z("initMouseEvent",14)},_),bb=J({initFocusEvent:z("initFocusEvent",5)},_),cb=y("MouseEvent",Z,ab),db=y("FocusEvent",Z,bb),eb=y("MutationEvent",w,{initMutationEvent:z("initMutationEvent",3),get relatedNode(){return M(this.impl.relatedNode)}}),fb=Object.create(null),gb=function(){try{new window.MouseEvent("click")}catch(a){return!1}return!0}();if(!gb){var hb=function(a,b,c){if(c){var d=fb[c];b=J(J({},d),b)}fb[a]=b};hb("Event",{bubbles:!1,cancelable:!1}),hb("CustomEvent",{detail:null},"Event"),hb("UIEvent",{view:null,detail:0},"Event"),hb("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),hb("FocusEvent",{relatedTarget:null},"UIEvent")}var ib=window.EventTarget,jb=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(a){var b=a.prototype;jb.forEach(function(a){Object.defineProperty(b,a+"_",{value:b[a]})})}),C.prototype={addEventListener:function(a,b,c){if(B(b)){var d=new v(a,b,c),e=O.get(this);if(e){for(var f=0;f<e.length;f++)if(d.equals(e[f]))return}else e=[],O.set(this,e);e.push(d);var g=D(this);g.addEventListener_(a,p,!0)}},removeEventListener:function(a,b,c){c=Boolean(c);var d=O.get(this);if(d){for(var e=0,f=!1,g=0;g<d.length;g++)d[g].type===a&&d[g].capture===c&&(e++,d[g].handler===b&&(f=!0,d[g].remove()));if(f&&1===e){var h=D(this);h.removeEventListener_(a,p,!0)}}},dispatchEvent:function(a){var b=D(this);return b.dispatchEvent_(L(a))}},ib&&K(ib,C);var kb=document.elementFromPoint;a.adjustRelatedTarget=i,a.elementFromPoint=F,a.getEventHandlerGetter=G,a.getEventHandlerSetter=H,a.wrapEventTargetMethods=E,a.wrappers.CustomEvent=$,a.wrappers.Event=w,a.wrappers.EventTarget=C,a.wrappers.FocusEvent=db,a.wrappers.MouseEvent=cb,a.wrappers.MutationEvent=eb,a.wrappers.UIEvent=Z}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,b){Object.defineProperty(a,b,{enumerable:!1})}function c(){this.length=0,b(this,"length")}function d(a){if(null==a)return a;for(var b=new c,d=0,e=a.length;e>d;d++)b[d]=f(a[d]);return b.length=e,b}function e(a,b){a.prototype[b]=function(){return d(this.impl[b].apply(this.impl,arguments))}}var f=a.wrap;c.prototype={item:function(a){return this[a]}},b(c.prototype,"item"),a.wrappers.NodeList=c,a.addWrapNodeListMethod=e,a.wrapNodeList=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){j(a instanceof f)}function c(a,b,c,d){if(a.nodeType!==f.DOCUMENT_FRAGMENT_NODE)return a.parentNode&&a.parentNode.removeChild(a),a.parentNode_=b,a.previousSibling_=c,a.nextSibling_=d,c&&(c.nextSibling_=a),d&&(d.previousSibling_=a),[a];for(var e,g=[];e=a.firstChild;)a.removeChild(e),g.push(e),e.parentNode_=b;for(var h=0;h<g.length;h++)g[h].previousSibling_=g[h-1]||c,g[h].nextSibling_=g[h+1]||d;return c&&(c.nextSibling_=g[0]),d&&(d.previousSibling_=g[g.length-1]),g}function d(a,b){var c=b.length;if(1===c)return m(b[0]);for(var d=m(a.ownerDocument.createDocumentFragment()),e=0;c>e;e++)d.appendChild(m(b[e]));return d}function e(a){for(var b=a.firstChild;b;){j(b.parentNode===a);var c=b.nextSibling,d=m(b),e=d.parentNode;e&&s.call(e,d),b.previousSibling_=b.nextSibling_=b.parentNode_=null,b=c}a.firstChild_=a.lastChild_=null}function f(a){j(a instanceof o),g.call(this,a),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0}var g=a.wrappers.EventTarget,h=a.wrappers.NodeList,i=a.defineWrapGetter,j=a.assert,k=a.mixin,l=a.registerWrapper,m=a.unwrap,n=a.wrap,o=window.Node,p=o.prototype.appendChild,q=o.prototype.insertBefore,r=o.prototype.replaceChild,s=o.prototype.removeChild,t=o.prototype.compareDocumentPosition;f.prototype=Object.create(g.prototype),k(f.prototype,{appendChild:function(a){b(a),this.invalidateShadowRenderer();var e=this.lastChild,f=null,g=c(a,this,e,f);return this.lastChild_=g[g.length-1],e||(this.firstChild_=g[0]),p.call(this.impl,d(this,g)),a},insertBefore:function(a,e){if(!e)return this.appendChild(a);b(a),b(e),j(e.parentNode===this),this.invalidateShadowRenderer();var f=e.previousSibling,g=e,h=c(a,this,f,g);this.firstChild===e&&(this.firstChild_=h[0]);var i=m(e),k=i.parentNode;return k&&q.call(k,d(this,h),i),a},removeChild:function(a){if(b(a),a.parentNode!==this)throw new Error("NotFoundError");this.invalidateShadowRenderer();var c=this.firstChild,d=this.lastChild,e=a.nextSibling,f=a.previousSibling,g=m(a),h=g.parentNode;return h&&s.call(h,g),c===a&&(this.firstChild_=e),d===a&&(this.lastChild_=f),f&&(f.nextSibling_=e),e&&(e.previousSibling_=f),a.previousSibling_=a.nextSibling_=a.parentNode_=null,a},replaceChild:function(a,e){if(b(a),b(e),e.parentNode!==this)throw new Error("NotFoundError");this.invalidateShadowRenderer();var f=e.previousSibling,g=e.nextSibling;g===a&&(g=a.nextSibling);var h=c(a,this,f,g);this.firstChild===e&&(this.firstChild_=h[0]),this.lastChild===e&&(this.lastChild_=h[h.length-1]),e.previousSibling_=null,e.nextSibling_=null,e.parentNode_=null;var i=m(e);return i.parentNode&&r.call(i.parentNode,d(this,h),i),e},hasChildNodes:function(){return null===this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:n(this.impl.parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:n(this.impl.firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:n(this.impl.lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:n(this.impl.nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:n(this.impl.previousSibling)},get parentElement(){for(var a=this.parentNode;a&&a.nodeType!==f.ELEMENT_NODE;)a=a.parentNode;return a},get textContent(){for(var a="",b=this.firstChild;b;b=b.nextSibling)a+=b.textContent;return a},set textContent(a){if(e(this),this.invalidateShadowRenderer(),""!==a){var b=this.impl.ownerDocument.createTextNode(a);this.appendChild(b)}},get childNodes(){for(var a=new h,b=0,c=this.firstChild;c;c=c.nextSibling)a[b++]=c;return a.length=b,a},cloneNode:function(a){if(!this.invalidateShadowRenderer())return n(this.impl.cloneNode(a));var b=n(this.impl.cloneNode(!1));if(a)for(var c=this.firstChild;c;c=c.nextSibling)b.appendChild(c.cloneNode(!0));return b},contains:function(a){if(!a)return!1;if(a===this)return!0;var b=a.parentNode;return b?this.contains(b):!1},compareDocumentPosition:function(a){return t.call(this.impl,m(a))}}),i(f,"ownerDocument"),l(o,f,document.createDocumentFragment()),delete f.prototype.querySelector,delete f.prototype.querySelectorAll,f.prototype=k(Object.create(g.prototype),f.prototype),a.wrappers.Node=f}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,c){for(var d,e=a.firstElementChild;e;){if(e.matches(c))return e;if(d=b(e,c))return d;e=e.nextElementSibling}return null}function c(a,b,d){for(var e=a.firstElementChild;e;)e.matches(b)&&(d[d.length++]=e),c(e,b,d),e=e.nextElementSibling;return d}var d={querySelector:function(a){return b(this,a)},querySelectorAll:function(a){return c(this,a,new NodeList)}},e={getElementsByTagName:function(a){return this.querySelectorAll(a)},getElementsByClassName:function(a){return this.querySelectorAll("."+a)},getElementsByTagNameNS:function(a,b){if("*"===a)return this.getElementsByTagName(b);for(var c=new NodeList,d=this.getElementsByTagName(b),e=0,f=0;e<d.length;e++)d[e].namespaceURI===a&&(c[f++]=d[e]);return c.length=f,c}};a.GetElementsByInterface=e,a.SelectorsInterface=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}function c(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}var d=a.wrappers.NodeList,e={get firstElementChild(){return b(this.firstChild)},get lastElementChild(){return c(this.lastChild)},get childElementCount(){for(var a=0,b=this.firstElementChild;b;b=b.nextElementSibling)a++;return a},get children(){for(var a=new d,b=0,c=this.firstElementChild;c;c=c.nextElementSibling)a[b++]=c;return a.length=b,a}},f={get nextElementSibling(){return b(this.nextSibling)},get previousElementSibling(){return c(this.nextSibling)}};a.ChildNodeInterface=f,a.ParentNodeInterface=e}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){d.call(this,a)}var c=a.ChildNodeInterface,d=a.wrappers.Node,e=a.mixin,f=a.registerWrapper,g=window.CharacterData;b.prototype=Object.create(d.prototype),e(b.prototype,{get textContent(){return this.data},set textContent(a){this.data=a}}),e(b.prototype,c),f(g,b,document.createTextNode("")),a.wrappers.CharacterData=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){e.call(this,a)}var c=a.ChildNodeInterface,d=a.GetElementsByInterface,e=a.wrappers.Node,f=a.ParentNodeInterface,g=a.SelectorsInterface;a.addWrapNodeListMethod;var h=a.mixin,i=a.registerWrapper,j=a.wrappers,k=new SideTable,l=window.Element,m=l.prototype.matches||l.prototype.mozMatchesSelector||l.prototype.msMatchesSelector||l.prototype.webkitMatchesSelector;b.prototype=Object.create(e.prototype),h(b.prototype,{createShadowRoot:function(){var b=new j.ShadowRoot(this);return k.set(this,b),a.getRendererForHost(this),this.invalidateShadowRenderer(!0),b},get shadowRoot(){return k.get(this)||null},setAttribute:function(a,b){this.impl.setAttribute(a,b),this.invalidateShadowRenderer()},matches:function(a){return m.call(this.impl,a)}}),l.prototype.webkitCreateShadowRoot&&(b.prototype.webkitCreateShadowRoot=b.prototype.createShadowRoot),h(b.prototype,c),h(b.prototype,d),h(b.prototype,f),h(b.prototype,g),i(l,b),a.wrappers.Element=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a){case"&":return"&amp;";case"<":return"&lt;";case'"':return"&quot;"}}function c(a){return a.replace(p,b)}function d(a){switch(a.nodeType){case Node.ELEMENT_NODE:for(var b,d=a.tagName.toLowerCase(),f="<"+d,g=a.attributes,h=0;b=g[h];h++)f+=" "+b.name+'="'+c(b.value)+'"';return f+=">",q[d]?f:f+e(a)+"</"+d+">";case Node.TEXT_NODE:return c(a.nodeValue);case Node.COMMENT_NODE:return"<!--"+c(a.nodeValue)+"-->";default:throw console.error(a),new Error("not implemented")}}function e(a){for(var b="",c=a.firstChild;c;c=c.nextSibling)b+=d(c);return b}function f(a,b,c){var d=c||"div";a.textContent="";var e=n(a.ownerDocument.createElement(d));e.innerHTML=b;for(var f;f=e.firstChild;)a.appendChild(o(f))}function g(a){j.call(this,a)}function h(b){k(g,b,function(){return a.renderAllPending(),this.impl[b]})}function i(b){Object.defineProperty(g.prototype,b,{value:function(){return a.renderAllPending(),this.impl[b].apply(this.impl,arguments)},configurable:!0,enumerable:!0})}var j=a.wrappers.Element,k=a.defineGetter,l=a.mixin,m=a.registerWrapper,n=a.unwrap,o=a.wrap,p=/&|<|"/g,q={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},r=window.HTMLElement;g.prototype=Object.create(j.prototype),l(g.prototype,{get innerHTML(){return e(this)},set innerHTML(a){f(this,a,this.tagName)},get outerHTML(){return d(this)},set outerHTML(a){if(this.invalidateShadowRenderer())throw new Error("not implemented");this.impl.outerHTML=a}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollLeft","scrollTop","scrollWidth"].forEach(h),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(i),m(r,g,document.createElement("b")),a.wrappers.HTMLElement=g,a.getInnerHTML=e,a.setInnerHTML=f}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLContentElement;b.prototype=Object.create(c.prototype),d(b.prototype,{get select(){return this.getAttribute("select")},set select(a){this.setAttribute("select",a)},setAttribute:function(a,b){c.prototype.setAttribute.call(this,a,b),"select"===String(a).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),f&&e(f,b),a.wrappers.HTMLContentElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a),this.olderShadowRoot_=null}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLShadowElement;b.prototype=Object.create(c.prototype),d(b.prototype,{get olderShadowRoot(){return this.olderShadowRoot_},invalidateShadowRenderer:function(){c.prototype.invalidateShadowRenderer.call(this,!0)}}),f&&e(f,b),a.wrappers.HTMLShadowElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){if(!a.defaultView)return a;var b=l.get(a);if(!b){for(b=a.implementation.createHTMLDocument("");b.lastChild;)b.removeChild(b.lastChild);l.set(a,b)}return b}function c(a){for(var c,d=b(a.ownerDocument),e=d.createDocumentFragment();c=a.firstChild;)e.appendChild(c);return e}function d(a){e.call(this,a)}var e=a.wrappers.HTMLElement,f=a.getInnerHTML,g=a.mixin,h=a.registerWrapper,i=a.setInnerHTML,j=a.wrap,k=new SideTable,l=new SideTable,m=window.HTMLTemplateElement;d.prototype=Object.create(e.prototype),g(d.prototype,{get content(){if(m)return j(this.impl.content);var a=k.get(this);return a||(a=c(this),k.set(this,a)),a},get innerHTML(){return f(this.content)},set innerHTML(a){i(this.content,a),this.invalidateShadowRenderer()}}),m&&h(m,d),a.wrappers.HTMLTemplateElement=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a.localName){case"content":return new c(a);case"shadow":return new e(a);case"template":return new f(a)}d.call(this,a)}var c=a.wrappers.HTMLContentElement,d=a.wrappers.HTMLElement,e=a.wrappers.HTMLShadowElement,f=a.wrappers.HTMLTemplateElement;a.mixin;var g=a.registerWrapper,h=window.HTMLUnknownElement;b.prototype=Object.create(d.prototype),g(h,b),a.wrappers.HTMLUnknownElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";var b=a.GetElementsByInterface,c=a.ParentNodeInterface,d=a.SelectorsInterface,e=a.mixin,f=a.registerObject,g=f(document.createDocumentFragment());e(g.prototype,c),e(g.prototype,d),e(g.prototype,b);var h=f(document.createTextNode("")),i=f(document.createComment(""));a.wrappers.Comment=i,a.wrappers.DocumentFragment=g,a.wrappers.Text=h}(this.ShadowDOMPolyfill),function(a){"use strict";function b(b){var d=i(b.impl.ownerDocument.createDocumentFragment());c.call(this,d),g(d,this);var e=b.shadowRoot;a.nextOlderShadowTreeTable.set(this,e),j.set(this,b)}var c=a.wrappers.DocumentFragment,d=a.elementFromPoint,e=a.getInnerHTML,f=a.mixin,g=a.rewrap,h=a.setInnerHTML,i=a.unwrap,j=new SideTable;b.prototype=Object.create(c.prototype),f(b.prototype,{get innerHTML(){return e(this)},set innerHTML(a){h(this,a),this.invalidateShadowRenderer()},invalidateShadowRenderer:function(){return j.get(this).invalidateShadowRenderer()},elementFromPoint:function(a,b){return d(this,this.ownerDocument,a,b)},getElementById:function(a){return this.querySelector("#"+a)}}),a.wrappers.ShadowRoot=b,a.getHostForShadowRoot=function(a){return j.get(a)}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){a.previousSibling_=a.previousSibling,a.nextSibling_=a.nextSibling,a.parentNode_=a.parentNode}function c(a){a.firstChild_=a.firstChild,a.lastChild_=a.lastChild}function d(a){E(a instanceof D);for(var d=a.firstChild;d;d=d.nextSibling)b(d);c(a)}function e(a){var b=G(a);d(a),b.textContent=""}function f(a,c){var e=G(a),f=G(c);f.nodeType===D.DOCUMENT_FRAGMENT_NODE?d(c):(h(c),b(c)),a.lastChild_=a.lastChild,a.lastChild===a.firstChild&&(a.firstChild_=a.firstChild);var g=H(e.lastChild);g&&(g.nextSibling_=g.nextSibling),e.appendChild(f)}function g(a,c){var d=G(a),e=G(c);b(c),c.previousSibling&&(c.previousSibling.nextSibling_=c),c.nextSibling&&(c.nextSibling.previousSibling_=c),a.lastChild===c&&(a.lastChild_=c),a.firstChild===c&&(a.firstChild_=c),d.removeChild(e)}function h(a){var b=G(a),c=b.parentNode;c&&g(H(c),a)}function i(a,b){k(b).push(a),A(a,b);var c=J.get(a);c||J.set(a,c=[]),c.push(b)}function j(a){I.set(a,[])}function k(a){return I.get(a)}function l(a){for(var b=[],c=0,d=a.firstChild;d;d=d.nextSibling)b[c++]=d;return b}function m(a,b,c){for(var d=l(a),e=0;e<d.length;e++){var f=d[e];if(b(f)){if(c(f)===!1)return}else m(f,b,c)}}function n(a,b){var c=!1;return m(a,u,function(a){j(a);for(var d=0;d<b.length;d++){var e=b[d];void 0!==e&&p(e,a)&&(i(e,a),b[d]=void 0,c=!0)}}),c?b.filter(function(a){return void 0!==a}):b}function o(a,b){for(var c=0;c<b.length;c++)if(b[c]in a)return b[c]}function p(a,b){var c=b.getAttribute("select");if(!c)return!0;if(c=c.trim(),!c)return!0;if(a.nodeType!==D.ELEMENT_NODE)return!1;if(!O.test(c))return!1;if(":"===c[0]&&!P.test(c))return!1;try{return a.matches(c)}catch(d){return!1}}function q(){F=null,R.forEach(function(a){a.render()}),R=[]}function r(a){this.host=a,this.dirty=!1,this.associateNode(a)}function s(a){var b=M.get(a);return b||(b=new r(a),M.set(a,b)),b}function t(a){return"content"===a.localName}function u(a){return"content"===a.localName}function v(a){return"shadow"===a.localName}function w(a){return"shadow"===a.localName}function x(a){return!!a.shadowRoot}function y(a){return L.get(a)}function z(a){for(var b=[],c=a.shadowRoot;c;c=L.get(c))b.push(c);return b}function A(a,b){K.set(a,b)}function B(a){new r(a).render()}var C=a.wrappers.HTMLContentElement,D=a.wrappers.Node,E=a.assert;a.mixin;var F,G=a.unwrap,H=a.wrap,I=new SideTable,J=new SideTable,K=new SideTable,L=new SideTable,M=new SideTable,N=new SideTable,O=/^[*.:#[a-zA-Z_|]/,P=new RegExp("^:("+["link","visited","target","enabled","disabled","checked","indeterminate","nth-child","nth-last-child","nth-of-type","nth-last-of-type","first-child","last-child","first-of-type","last-of-type","only-of-type"].join("|")+")"),Q=o(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),R=[];r.prototype={render:function(){if(this.dirty){var a=this.host;this.treeComposition();var b=a.shadowRoot;if(b){this.removeAllChildNodes(this.host);var c=l(b);c.forEach(function(c){this.renderNode(a,b,c,!1)},this),this.dirty=!1}}},invalidate:function(){if(!this.dirty){if(this.dirty=!0,R.push(this),F)return;F=window[Q](q,0)}},renderNode:function(a,b,c,d){if(x(c)){this.appendChild(a,c);var e=s(c);e.dirty=!0,e.render()}else t(c)?this.renderInsertionPoint(a,b,c,d):v(c)?this.renderShadowInsertionPoint(a,b,c):this.renderAsAnyDomTree(a,b,c,d)},renderAsAnyDomTree:function(a,b,c,d){if(this.appendChild(a,c),x(c))B(c);else{var e=c,f=l(e);f.forEach(function(a){this.renderNode(e,b,a,d)},this)}},renderInsertionPoint:function(a,b,c,d){var e=k(c);e.length?(this.removeAllChildNodes(c),e.forEach(function(c){t(c)&&d?this.renderInsertionPoint(a,b,c,d):this.renderAsAnyDomTree(a,b,c,d)},this)):this.renderFallbackContent(a,c),this.remove(c)},renderShadowInsertionPoint:function(a,b,c){var d=y(b);if(d){A(d,c),c.olderShadowRoot_=d,this.remove(c);var e=l(d);e.forEach(function(b){this.renderNode(a,d,b,!0)},this)}else this.renderFallbackContent(a,c)},renderFallbackContent:function(a,b){var c=l(b);c.forEach(function(b){this.appendChild(a,b)},this)},treeComposition:function(){var a=this.host,b=a.shadowRoot,c=[],d=l(a);d.forEach(function(a){if(t(a)){var b=k(a);b&&b.length||(b=l(a)),c.push.apply(c,b)}else c.push(a)});for(var e,f;b;){if(e=void 0,m(b,w,function(a){return e=a,!1}),f=e,c=n(b,c),f){var g=y(b);if(g){b=g,A(b,f);continue}break}break}},appendChild:function(a,b){f(a,b),this.associateNode(b)},remove:function(a){h(a),this.associateNode(a)},removeAllChildNodes:function(a){e(a)},associateNode:function(a){N.set(a,this)}},D.prototype.invalidateShadowRenderer=function(a){var b=N.get(this);if(!b)return!1;var c;return(a||this.shadowRoot||(c=this.parentNode)&&(c.shadowRoot||c instanceof ShadowRoot))&&b.invalidate(),!0},C.prototype.getDistributedNodes=function(){return q(),k(this)},a.eventParentsTable=J,a.getRendererForHost=s,a.getShadowTrees=z,a.nextOlderShadowTreeTable=L,a.renderAllPending=q,a.insertionParentTable=K,a.visual={removeAllChildNodes:e,appendChild:f,removeChild:g}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){j.call(this,a)}function c(a){var c=document[a];b.prototype[a]=function(){return t(c.apply(this.impl,arguments))}}function d(a,b){a.shadowRoot&&b.adoptNode(a.shadowRoot),a instanceof m&&e(a,b);for(var c=a.firstChild;c;c=c.nextSibling)d(c,b)}function e(b,c){var d=a.nextOlderShadowTreeTable.get(b);d&&c.adoptNode(d)}function f(a){this.impl=a}function g(a,b){var c=document.implementation[b];a.prototype[b]=function(){return t(c.apply(this.impl,arguments))}}function h(a,b){var c=document.implementation[b];a.prototype[b]=function(){return c.apply(this.impl,arguments)}}var i=a.GetElementsByInterface,j=a.wrappers.Node,k=a.ParentNodeInterface,l=a.SelectorsInterface,m=a.wrappers.ShadowRoot,n=a.defineWrapGetter,o=a.elementFromPoint,p=a.forwardMethodsToWrapper,q=a.mixin,r=a.registerWrapper,s=a.unwrap,t=a.wrap,u=a.wrapEventTargetMethods;a.wrapNodeList;var v=new SideTable;b.prototype=Object.create(j.prototype),n(b,"documentElement"),n(b,"body"),n(b,"head"),["getElementById","createElement","createElementNS","createTextNode","createDocumentFragment","createEvent","createEventNS"].forEach(c);var w=document.adoptNode,x=document.write;q(b.prototype,{adoptNode:function(a){return a.parentNode&&a.parentNode.removeChild(a),w.call(this.impl,s(a)),d(a,this),a},elementFromPoint:function(a,b){return o(this,this,a,b)},write:function(a){for(var b=this.querySelectorAll("*"),c=b[b.length-1];c.nextSibling;)c=c.nextSibling;var d=c.parentNode;d.lastChild_=void 0,c.nextSibling_=void 0,x.call(this.impl,a)}}),p([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement],["appendChild","compareDocumentPosition","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild"]),p([window.HTMLDocument||window.Document],["adoptNode","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createTextNode","elementFromPoint","getElementById","write"]),q(b.prototype,i),q(b.prototype,k),q(b.prototype,l),q(b.prototype,{get implementation(){var a=v.get(this);return a?a:(a=new f(s(this).implementation),v.set(this,a),a)}}),r(window.Document,b,document.implementation.createHTMLDocument("")),window.HTMLDocument&&r(window.HTMLDocument,b),u([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),g(f,"createDocumentType"),g(f,"createDocument"),g(f,"createHTMLDocument"),h(f,"hasFeature"),r(window.DOMImplementation,f),p([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),a.wrappers.Document=b,a.wrappers.DOMImplementation=f
-}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.EventTarget,d=a.mixin,e=a.registerWrapper,f=a.unwrap,g=a.unwrapIfNeeded,h=a.wrap,i=window.Window;b.prototype=Object.create(c.prototype);var j=window.getComputedStyle;i.prototype.getComputedStyle=function(a,b){return j.call(this||window,g(a),b)},["addEventListener","removeEventListener","dispatchEvent"].forEach(function(a){i.prototype[a]=function(){var b=h(this||window);return b[a].apply(b,arguments)}}),d(b.prototype,{getComputedStyle:function(a,b){return j.call(f(this),g(a),b)}}),e(i,b),a.wrappers.Window=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}function c(a){return new b(a)}function d(a){return a.map(c)}function e(a){var b=this;this.impl=new k(function(c){a.call(b,d(c),b)})}var f=a.defineGetter,g=a.defineWrapGetter,h=a.registerWrapper,i=a.unwrapIfNeeded,j=a.wrapNodeList;a.wrappers;var k=window.MutationObserver||window.WebKitMutationObserver;if(k){var l=window.MutationRecord;b.prototype={get addedNodes(){return j(this.impl.addedNodes)},get removedNodes(){return j(this.impl.removedNodes)}},["target","previousSibling","nextSibling"].forEach(function(a){g(b,a)}),["type","attributeName","attributeNamespace","oldValue"].forEach(function(a){f(b,a,function(){return this.impl[a]})}),l&&h(l,b),window.Node,e.prototype={observe:function(a,b){this.impl.observe(i(a),b)},disconnect:function(){this.impl.disconnect()},takeRecords:function(){return d(this.impl.takeRecords())}},a.wrappers.MutationObserver=e,a.wrappers.MutationRecord=b}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=c[a],d=window[b];if(d){var e=document.createElement(a),f=e.constructor;window[b]=f}}a.isWrapperFor;var c={a:"HTMLAnchorElement",applet:"HTMLAppletElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",br:"HTMLBRElement",base:"HTMLBaseElement",body:"HTMLBodyElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",dl:"HTMLDListElement",datalist:"HTMLDataListElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",hr:"HTMLHRElement",head:"HTMLHeadElement",h1:"HTMLHeadingElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",input:"HTMLInputElement",li:"HTMLLIElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",link:"HTMLLinkElement",map:"HTMLMapElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",del:"HTMLModElement",ol:"HTMLOListElement",object:"HTMLObjectElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",table:"HTMLTableElement",tr:"HTMLTableRowElement",thead:"HTMLTableSectionElement",tbody:"HTMLTableSectionElement",textarea:"HTMLTextAreaElement",title:"HTMLTitleElement",ul:"HTMLUListElement",video:"HTMLVideoElement"};Object.keys(c).forEach(b),Object.getOwnPropertyNames(a.wrappers).forEach(function(b){window[b]=a.wrappers[b]}),a.knownElements=c}(this.ShadowDOMPolyfill),function(){window.wrap=function(a){return a.impl?a:ShadowDOMPolyfill.wrap(a)},window.unwrap=function(a){return a.impl?ShadowDOMPolyfill.unwrap(a):a};var a=window.getComputedStyle;window.getComputedStyle=function(b,c){return a.call(window,wrap(b),c)},Object.defineProperties(HTMLElement.prototype,{webkitShadowRoot:{get:function(){return this.shadowRoot}}}),HTMLElement.prototype.webkitCreateShadowRoot=HTMLElement.prototype.createShadowRoot}(),function(a){function b(a,b){var c="";return Array.prototype.forEach.call(a,function(a){c+=a.textContent+"\n\n"}),b||(c=c.replace(m,"")),c}function c(a){var b=document.createElement("style");b.textContent=a,document.head.appendChild(b);var c=b.sheet.cssRules;return b.parentNode.removeChild(b),c}function d(a){for(var b=0,c=[];b<a.length;b++)c.push(a[b].cssText);return c.join("\n\n")}function e(a){a&&f().appendChild(document.createTextNode(a))}function f(){return g||(g=document.createElement("style"),g.setAttribute("ShadowCSSShim","")),g}var g,h={strictStyling:!1,registry:{},shimStyling:function(a,b,c){if(a){var d=this.registerDefinition(a,b,c);this.strictStyling&&this.applyScopeToContent(a,b),this.shimPolyfillDirectives(d.rootStyles,b),this.applyShimming(d.scopeStyles,b)}},shimShadowDOMStyling:function(a,b){this.shimPolyfillDirectives(a,b),this.applyShimming(a,b)},registerDefinition:function(a,b,c){var d=this.registry[b]={root:a,name:b,extendsName:c},e=a.querySelectorAll("style");e=e?Array.prototype.slice.call(e,0):[],d.rootStyles=e,d.scopeStyles=d.rootStyles;var f=this.registry[d.extendsName];return f&&(d.scopeStyles=d.scopeStyles.concat(f.scopeStyles)),d},applyScopeToContent:function(a,b){a&&(Array.prototype.forEach.call(a.querySelectorAll("*"),function(a){a.setAttribute(b,"")}),Array.prototype.forEach.call(a.querySelectorAll("template"),function(a){this.applyScopeToContent(a.content,b)},this))},shimPolyfillDirectives:function(a,b){a&&Array.prototype.forEach.call(a,function(a){a.textContent=this.convertPolyfillDirectives(a.textContent,b)},this)},convertPolyfillDirectives:function(a,b){for(var c,d,e="",f=0;c=n.exec(a);)e+=a.substring(f,c.index),d=c[1].slice(0,-2).replace(q,b),e+=this.scopeSelector(d,b)+"{",f=n.lastIndex;return e+=a.substring(f,a.length)},applyShimming:function(a,b){var c=this.shimAtHost(a,b);c+=this.shimScoping(a,b),e(c)},shimAtHost:function(a,b){return a?this.convertAtHostStyles(a,b):void 0},convertAtHostStyles:function(a,e){for(var f,g=b(a),h="",j=0;f=i.exec(g);)h+=g.substring(j,f.index),h+=this.scopeHostCss(f[1],e),j=i.lastIndex;h+=g.substring(j,g.length);var k=new RegExp("^"+e+p,"m"),g=d(this.findAtHostRules(c(h),k));return g},scopeHostCss:function(a,b){for(var c,d="";c=j.exec(a);)d+=this.scopeHostSelector(c[1],b)+" "+c[2]+"\n	";return d},scopeHostSelector:function(a,b){var c=[],d=a.split(","),e="[is="+b+"]";return d.forEach(function(a){a=a.trim(),a.match(k)?a=a.replace(k,b+"$1$3, "+e+"$1$3"):a.match(l)&&(a=b+a+", "+e+a),c.push(a)},this),c.join(", ")},findAtHostRules:function(a,b){return Array.prototype.filter.call(a,this.isHostRule.bind(this,b))},isHostRule:function(a,b){return b.selectorText&&b.selectorText.match(a)||b.cssRules&&this.findAtHostRules(b.cssRules,a).length||b.type==CSSRule.WEBKIT_KEYFRAMES_RULE},shimScoping:function(a,b){return a?this.convertScopedStyles(a,b):void 0},convertScopedStyles:function(a,d){Array.prototype.forEach.call(a,function(a){a.parentNode&&a.parentNode.removeChild(a)});var e=b(a).replace(i,"");e=this.convertPseudos(e);var f=c(e);return e=this.scopeRules(f,d)},convertPseudos:function(a){return a.replace(o," [pseudo=$1]")},scopeRules:function(a,b){var c="";return Array.prototype.forEach.call(a,function(a){a.selectorText&&a.style&&a.style.cssText?(c+=this.scopeSelector(a.selectorText,b,this.strictStyling)+" {\n	",c+=this.propertiesFromRule(a)+"\n}\n\n"):a.media?(c+="@media "+a.media.mediaText+" {\n",c+=this.scopeRules(a.cssRules,b),c+="\n}\n\n"):a.cssText&&(c+=a.cssText+"\n\n")},this),c},scopeSelector:function(a,b,c){var d=[],e=a.split(",");return e.forEach(function(a){a=a.trim(),this.selectorNeedsScoping(a,b)&&(a=c?this.applyStrictSelectorScope(a,b):this.applySimpleSelectorScope(a,b)),d.push(a)},this),d.join(", ")},selectorNeedsScoping:function(a,b){var c="("+b+"|\\[is="+b+"\\])",d=new RegExp("^"+c+p,"m");return!a.match(d)},applySimpleSelectorScope:function(a,b){return b+" "+a+", "+"[is="+b+"] "+a},applyStrictSelectorScope:function(a,b){var c=[" ",">","+","~"],d=a,e="["+b+"]";return c.forEach(function(a){var b=d.split(a);d=b.map(function(a){var b=a.trim();return b&&c.indexOf(b)<0&&b.indexOf(e)<0&&(a=b.replace(/([^:]*)(:*)(.*)/,"$1"+e+"$2$3")),a}).join(a)}),d},propertiesFromRule:function(a){var b=a.style.cssText;return a.style.content&&!a.style.content.match(/['"]+/)&&(b="content: '"+a.style.content+"';\n"+a.style.cssText.replace(/content:[^;]*;/g,"")),b}},i=/@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,j=/([^{]*)({[\s\S]*?})/gim,k=/(.*)((?:\*)|(?:\:scope))(.*)/,l=/^[.\[:]/,m=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,n=/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,o=/::(x-[^\s{,(]*)/gim,p="([>\\s~+[.,{:][\\s\\S]*)?$",q=/@host/gim;if(window.ShadowDOMPolyfill){e("style { display: none !important; }\n");var r=document.querySelector("head");r.insertBefore(f(),r.childNodes[0])}a.ShadowCSS=h}(window.Platform)}else{var SideTable;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},SideTable.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}(),function(){window.templateContent=window.templateContent||function(a){return a.content},window.wrap=window.unwrap=function(a){return a},Object.defineProperties(HTMLElement.prototype,{shadowRoot:{get:function(){return this.webkitShadowRoot}},createShadowRoot:{value:function(){return this.webkitCreateShadowRoot()}}}),window.templateContent=function(a){if(window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(a),!a.content&&!a._content){for(var b=document.createDocumentFragment();a.firstChild;)b.appendChild(a.firstChild);a._content=b}return a.content||a._content}}()}if(function(a){function b(a){for(var b=a||{},d=1;d<arguments.length;d++){var e=arguments[d];try{for(var f in e)c(f,e,b)}catch(g){}}return b}function c(a,b,c){var e=d(b,a);Object.defineProperty(c,a,e)}function d(a,b){if(a){var c=Object.getOwnPropertyDescriptor(a,b);return c||d(Object.getPrototypeOf(a),b)}}Function.prototype.bind||(Function.prototype.bind=function(a){var b=this,c=Array.prototype.slice.call(arguments,1);return function(){var d=c.slice();return d.push.apply(d,arguments),b.apply(a,d)}}),a.mixin=b}(window.Platform),function(a){"use strict";function b(a,b,c){var d="string"==typeof a?document.createElement(a):a.cloneNode(!0);if(d.innerHTML=b,c)for(var e in c)d.setAttribute(e,c[e]);return d}var c=DOMTokenList.prototype.add,d=DOMTokenList.prototype.remove;DOMTokenList.prototype.add=function(){for(var a=0;a<arguments.length;a++)c.call(this,arguments[a])},DOMTokenList.prototype.remove=function(){for(var a=0;a<arguments.length;a++)d.call(this,arguments[a])},DOMTokenList.prototype.toggle=function(a,b){1==arguments.length&&(b=!this.contains(a)),b?this.add(a):this.remove(a)},DOMTokenList.prototype.switch=function(a,b){a&&this.remove(a),b&&this.add(b)};var e=function(){return Array.prototype.slice.call(this)},f=window.NamedNodeMap||window.MozNamedAttrMap||{};NodeList.prototype.array=e,f.prototype.array=e,HTMLCollection.prototype.array=e;var g=function(a,b){e.call(this).forEach(a,b)};if(NodeList.prototype.forEach=g,f.prototype.forEach=g,HTMLCollection.prototype.forEach=g,!window.performance){var h=Date.now();window.performance={now:function(){return Date.now()-h}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var a=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return a?function(b){return a(function(){b(performance.now())})}:function(a){return window.setTimeout(a,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(a){clearTimeout(a)}}()),a.createDOM=b}(window.Platform),window.templateContent=window.templateContent||function(a){return a.content},function(a){a=a||(window.Inspector={});var b;window.sinspect=function(a,d){b||(b=window.open("","ShadowDOM Inspector",null,!0),b.document.write(c),b.api={shadowize:shadowize}),f(a||wrap(document.body),d)};var c=["<!DOCTYPE html>","<html>","  <head>","    <title>ShadowDOM Inspector</title>","    <style>","      body {","      }","      pre {",'        font: 9pt "Courier New", monospace;',"        line-height: 1.5em;","      }","      tag {","        color: purple;","      }","      ul {","         margin: 0;","         padding: 0;","         list-style: none;","      }","      li {","         display: inline-block;","         background-color: #f1f1f1;","         padding: 4px 6px;","         border-radius: 4px;","         margin-right: 4px;","      }","    </style>","  </head>","  <body>",'    <ul id="crumbs">',"    </ul>",'    <div id="tree"></div>',"  </body>","</html>"].join("\n"),d=[],e=function(){var a=b.document,c=a.querySelector("#crumbs");c.textContent="";for(var e,g=0;e=d[g];g++){var h=a.createElement("a");h.href="#",h.textContent=e.localName,h.idx=g,h.onclick=function(a){for(var b;d.length>this.idx;)b=d.pop();f(b.shadow||b,b),a.preventDefault()},c.appendChild(a.createElement("li")).appendChild(h)}},f=function(a,c){var f=b.document;k=[];var g=c||a;d.push(g),e(),f.body.querySelector("#tree").innerHTML="<pre>"+j(a,a.childNodes)+"</pre>"},g=Array.prototype.forEach.call.bind(Array.prototype.forEach),h={STYLE:1,SCRIPT:1,"#comment":1,TEMPLATE:1},i=function(a){return h[a.nodeName]},j=function(a,b,c){if(i(a))return"";var d=c||"";if(a.localName||11==a.nodeType){var e=a.localName||"shadow-root",f=d+l(a);"content"==e&&(b=a.getDistributedNodes()),f+="<br/>";var h=d+"&nbsp;&nbsp;";g(b,function(a){f+=j(a,a.childNodes,h)}),f+=d,{br:1}[e]||(f+="<tag>&lt;/"+e+"&gt;</tag>",f+="<br/>")}else{var k=a.textContent.trim();f=k?d+'"'+k+'"'+"<br/>":""}return f},k=[],l=function(a){var b="<tag>&lt;",c=a.localName||"shadow-root";return a.webkitShadowRoot||a.shadowRoot?(b+=' <button idx="'+k.length+'" onclick="api.shadowize.call(this)">'+c+"</button>",k.push(a)):b+=c||"shadow-root",a.attributes&&g(a.attributes,function(a){b+=" "+a.name+(a.value?'="'+a.value+'"':"")}),b+="&gt;</tag>"};shadowize=function(){var a=Number(this.attributes.idx.value),b=k[a];b?f(b.webkitShadowRoot||b.shadowRoot,b):(console.log("bad shadowize node"),console.dir(this))},a.output=j}(window.Inspector),function(a){"use strict";function b(){function a(a){"splice"===a[0].type&&"splice"===a[1].type&&(b=!0)}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=!1,c=[0];return Array.observe(c,a),c[1]=1,c.length=0,Object.deliverChangeRecords(a),b}function c(a){return+a===a>>>0}function d(a){return+a}function e(a){return a===Object(a)}function f(a,b){return a===b?0!==a||1/a===1/b:K(a)&&K(b)?!0:a!==a&&b!==b}function g(a){return"string"!=typeof a?!1:(a=a.replace(/\s/g,""),""==a?!0:"."==a[0]?!1:S.test(a))}function h(a){var b=T[a];if(b)return b;if(g(a)){var b=new i(a);return T[a]=b,b}}function i(a){return""==a.trim()?this:c(a)?(this.push(String(a)),this):(a.split(/\./).filter(function(a){return a}).forEach(function(a){this.push(a)},this),H&&this.length&&(this.getValueFrom=this.compiledGetValueFromFn()),void 0)}function j(a){for(var b=0;U>b&&a.check();)a.report(),b++}function k(a){for(var b in a)return!1;return!0}function l(a){return k(a.added)&&k(a.removed)&&k(a.changed)}function m(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function n(a,b){var c=b||(Array.isArray(a)?[]:{});for(var d in a)c[d]=a[d];return Array.isArray(a)&&(c.length=a.length),c}function o(a,b,c,d){this.object=a,this.callback=b,this.target=c,this.token=d,this.reporting=!0,G&&(this.boundInternalCallback=this.internalCallback.bind(this)),this.valid=!0,p(this),this.connect(),this.sync(!0)}function p(a){W&&(V.push(a),o._allObserversCount++)}function q(a,b,c,d){o.call(this,a,b,c,d)}function r(a,b,c,d){if(!Array.isArray(a))throw Error("Provided object is not an Array");o.call(this,a,b,c,d)}function s(a){this.arr=[],this.callback=a,this.isObserved=!0}function t(a,b,c,d,f){this.value=void 0;var g=h(b);return g?g.length?(e(a)&&(this.path=g,o.call(this,a,c,d,f)),void 0):(this.value=a,void 0):void 0}function u(a,b){if("function"==typeof Object.observe){var c=Object.getNotifier(a);return function(d,e){var f={object:a,type:d,name:b};2===arguments.length&&(f.oldValue=e),c.notify(f)}}}function v(a,b,c){for(var d={},e={},f=0;f<b.length;f++){var g=b[f];_[g.type]?(g.name in c||(c[g.name]=g.oldValue),"updated"!=g.type&&("new"!=g.type?g.name in d?(delete d[g.name],delete c[g.name]):e[g.name]=!0:g.name in e?delete e[g.name]:d[g.name]=!0)):(console.error("Unknown changeRecord type: "+g.type),console.error(g))}for(var h in d)d[h]=a[h];for(var h in e)e[h]=void 0;var i={};for(var h in c)if(!(h in d||h in e)){var j=a[h];c[h]!==j&&(i[h]=j)}return{added:d,removed:e,changed:i}}function w(a,b,c,d,e,f){for(var g=f-e+1,h=c-b+1,i=new Array(g),j=0;g>j;j++)i[j]=new Array(h),i[j][0]=j;for(var k=0;h>k;k++)i[0][k]=k;for(var j=1;g>j;j++)for(var k=1;h>k;k++)if(d[e+j-1]===a[b+k-1])i[j][k]=i[j-1][k-1];else{var l=i[j-1][k]+1,m=i[j][k-1]+1;i[j][k]=m>l?l:m}return i}function x(a){for(var b=a.length-1,c=a[0].length-1,d=a[b][c],e=[];b>0||c>0;)if(0!=b)if(0!=c){var f,g=a[b-1][c-1],h=a[b-1][c],i=a[b][c-1];f=i>h?g>h?h:g:g>i?i:g,f==g?(g==d?e.push(ab):(e.push(bb),d=g),b--,c--):f==h?(e.push(db),b--,d=h):(e.push(cb),c--,d=i)}else e.push(db),b--;else e.push(cb),c--;return e.reverse(),e}function y(a,b,c){for(var d=0;c>d;d++)if(a[d]!==b[d])return d;return c}function z(a,b,c){for(var d=a.length,e=b.length,f=0;c>f&&a[--d]===b[--e];)f++;return f}function A(a,b,c){return{index:a,removed:b,addedCount:c}}function B(a,b,c,d,e,f){var g=0,h=0,i=Math.min(c-b,f-e);if(0==b&&0==e&&(g=y(a,d,i)),c==a.length&&f==d.length&&(h=z(a,d,i-g)),b+=g,e+=g,c-=h,f-=h,0==c-b&&0==f-e)return[];if(b==c){for(var j=A(b,[],0);f>e;)j.removed.push(d[e++]);return[j]}if(e==f)return[A(b,[],c-b)];for(var k=x(w(a,b,c,d,e,f)),j=void 0,l=[],m=b,n=e,o=0;o<k.length;o++)switch(k[o]){case ab:j&&(l.push(j),j=void 0),m++,n++;break;case bb:j||(j=A(m,[],0)),j.addedCount++,m++,j.removed.push(d[n]),n++;break;case cb:j||(j=A(m,[],0)),j.addedCount++,m++;break;case db:j||(j=A(m,[],0)),j.removed.push(d[n]),n++}return j&&l.push(j),l}function C(a,b,c,d){return c>b||a>d?-1:b==c||d==a?0:c>a?d>b?b-c:d-c:b>d?d-a:b-a}function D(a,b,c,d){for(var e=A(b,c,d),f=!1,g=0,h=0;h<a.length;h++){var i=a[h];if(i.index+=g,!f){var j=C(e.index,e.index+e.removed.length,i.index,i.index+i.addedCount);if(j>=0){a.splice(h,1),h--,g-=i.addedCount-i.removed.length,e.addedCount+=i.addedCount-j;var k=e.removed.length+i.removed.length-j;if(e.addedCount||k){var c=i.removed;if(e.index<i.index){var l=e.removed.slice(0,i.index-e.index);Array.prototype.push.apply(l,c),c=l}if(e.index+e.removed.length>i.index+i.addedCount){var m=e.removed.slice(i.index+i.addedCount-e.index);Array.prototype.push.apply(c,m)}e.removed=c,i.index<e.index&&(e.index=i.index)}else f=!0}else if(e.index<i.index){f=!0,a.splice(h,0,e),h++;var n=e.addedCount-e.removed.length;i.index+=n,g+=n}}}f||a.push(e)}function E(a,b){for(var e=[],f=0;f<b.length;f++){var g=b[f];switch(g.type){case"splice":D(e,g.index,g.removed.slice(),g.addedCount);break;case"new":case"updated":case"deleted":if(!c(g.name))continue;var h=d(g.name);if(0>h)continue;D(e,h,[g.oldValue],1);break;default:console.error("Unexpected record type: "+JSON.stringify(g))}}return e}function F(a,b){var c=[];return E(a,b).forEach(function(b){return 1==b.addedCount&&1==b.removed.length?(b.removed[0]!==a[b.index]&&c.push(b),void 0):(c=c.concat(B(a,b.index,b.index+b.addedCount,b.removed,0,b.removed.length)),void 0)}),c}var G=b(),H=!1;try{var I=new Function("","return true;");H=I()}catch(J){}var K=a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},L="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c},M="[$_a-zA-Z]",N="[$_a-zA-Z0-9]",O=M+"+"+N+"*",P="(?:[0-9]|[1-9]+[0-9]+)",Q="(?:"+O+"|"+P+")",R="(?:"+Q+")(?:\\."+Q+")*",S=new RegExp("^"+R+"$"),T={};i.prototype=L({__proto__:[],toString:function(){return this.join(".")},getValueFrom:function(a){for(var b=0;b<this.length;b++){if(void 0===a||null===a)return;a=a[this[b]]}return a},getValueFromObserved:function(a,b){b.reset();for(var c=0;c<this.length;c++){if(void 0===a||null===a)return b.cleanup(),void 0;b.observe(a),a=a[this[c]]}return a},compiledGetValueFromFn:function(){var a=this.map(function(a){return c(a)?'["'+a+'"]':"."+a}),b="",d="obj";b+="if (obj !== null && obj !== undefined";for(var e=0;e<this.length-1;e++)this[e],d+=a[e],b+=" &&\n     "+d+" !== null && "+d+" !== undefined";return b+=")\n",d+=a[e],b+="  return "+d+";\nelse\n  return undefined;",new Function("obj",b)},setValueFrom:function(a,b){if(!this.length)return!1;for(var c=0;c<this.length-1;c++){if(void 0===a||null===a)return!1;a=a[this[c]]}return void 0===a||null===a?!1:(a[this[this.length-1]]=b,!0)}});var U=1e3;o.prototype={valid:!1,internalCallback:function(a){this.valid&&this.reporting&&this.check(a)&&(this.report(),this.testingResults&&(this.testingResults.anyChanged=!0))},close:function(){this.valid&&("function"==typeof this.object.unobserved&&this.object.unobserved(),this.disconnect(),this.object=void 0,this.valid=!1)},deliver:function(a){this.valid&&(G?(this.testingResults=a,Object.deliverChangeRecords(this.boundInternalCallback),this.testingResults=void 0):j(this))},report:function(){if(this.reporting){this.sync(!1),this.reportArgs.push(this.token);try{this.callback.apply(this.target,this.reportArgs)}catch(a){o._errorThrownDuringCallback=!0,console.error("Exception caught during observer callback: "+a)}this.reportArgs=void 0}},reset:function(){this.valid&&(G&&(this.reporting=!1,Object.deliverChangeRecords(this.boundInternalCallback),this.reporting=!0),this.sync(!0))}};var V,W=!G||a.forceCollectObservers;o._allObserversCount=0,W&&(V=[]);var X=!1,Y="function"==typeof Object.deliverAllChangeRecords;a.Platform=a.Platform||{},a.Platform.performMicrotaskCheckpoint=function(){if(!X){if(Y)return Object.deliverAllChangeRecords(),void 0;if(W){X=!0;var a=0,b={};do{a++;var c=V;V=[],b.anyChanged=!1;for(var d=0;d<c.length;d++){var e=c[d];e.valid&&(G?e.deliver(b):e.check()&&(b.anyChanged=!0,e.report()),V.push(e))}}while(U>a&&b.anyChanged);o._allObserversCount=V.length,X=!1}}},W&&(a.Platform.clearObservers=function(){V=[]}),q.prototype=L({__proto__:o.prototype,connect:function(){G&&Object.observe(this.object,this.boundInternalCallback)},sync:function(){G||(this.oldObject=n(this.object))},check:function(a){var b,c;if(G){if(!a)return!1;c={},b=v(this.object,a,c)}else c=this.oldObject,b=m(this.object,this.oldObject);return l(b)?!1:(this.reportArgs=[b.added||{},b.removed||{},b.changed||{}],this.reportArgs.push(function(a){return c[a]}),!0)},disconnect:function(){G?this.object&&Object.unobserve(this.object,this.boundInternalCallback):this.oldObject=void 0}}),r.prototype=L({__proto__:q.prototype,connect:function(){G&&Array.observe(this.object,this.boundInternalCallback)},sync:function(){G||(this.oldObject=this.object.slice())},check:function(a){var b;if(G){if(!a)return!1;b=F(this.object,a)}else b=B(this.object,0,this.object.length,this.oldObject,0,this.oldObject.length);return b&&b.length?(this.reportArgs=[b],!0):!1}}),r.applySplices=function(a,b,c){c.forEach(function(c){for(var d=[c.index,c.removed.length],e=c.index;e<c.index+c.addedCount;)d.push(b[e]),e++;Array.prototype.splice.apply(a,d)})};var Z=Object.getPrototypeOf({}),$=Object.getPrototypeOf([]);s.prototype={reset:function(){this.isObserved=!this.isObserved},observe:function(a){if(e(a)&&a!==Z&&a!==$){var b=this.arr.indexOf(a);b>=0&&this.arr[b+1]===this.isObserved||(0>b&&(b=this.arr.length,this.arr[b]=a,Object.observe(a,this.callback)),this.arr[b+1]=this.isObserved,this.observe(Object.getPrototypeOf(a)))}},cleanup:function(){for(var a=0,b=0,c=this.isObserved;b<this.arr.length;){var d=this.arr[b];this.arr[b+1]==c?(b>a&&(this.arr[a]=d,this.arr[a+1]=c),a+=2):Object.unobserve(d,this.callback),b+=2}this.arr.length=a}},t.prototype=L({__proto__:o.prototype,connect:function(){G&&(this.observedSet=new s(this.boundInternalCallback))},disconnect:function(){this.value=void 0,G&&(this.observedSet.reset(),this.observedSet.cleanup(),this.observedSet=void 0)},check:function(){return this.value=G?this.path.getValueFromObserved(this.object,this.observedSet):this.path.getValueFrom(this.object),f(this.value,this.oldValue)?!1:(this.reportArgs=[this.value,this.oldValue],!0)},sync:function(a){a&&(this.value=G?this.path.getValueFromObserved(this.object,this.observedSet):this.path.getValueFrom(this.object)),this.oldValue=this.value}}),t.getValueAtPath=function(a,b){var c=h(b);return c?c.getValueFrom(a):void 0},t.setValueAtPath=function(a,b,c){var d=h(b);d&&d.setValueFrom(a,c)};var _={"new":!0,updated:!0,deleted:!0};t.defineProperty=function(a,b,c){var d=c.object,e=h(c.path),f=u(a,b),g=new t(d,c.path,function(a,b){f&&f("updated",b)});return Object.defineProperty(a,b,{get:function(){return e.getValueFrom(d)},set:function(a){e.setValueFrom(d,a)},configurable:!0}),{close:function(){var c=e.getValueFrom(d);f&&g.deliver(),g.close(),Object.defineProperty(a,b,{value:c,writable:!0,configurable:!0})}}};var ab=0,bb=1,cb=2,db=3;a.Observer=o,a.Observer.hasObjectObserve=G,a.ArrayObserver=r,a.ArrayObserver.calculateSplices=function(a,b){return B(a,0,a.length,b,0,b.length)},a.ObjectObserver=q,a.PathObserver=t,a.Path=i}(this),function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a){for(;a.parentNode;)a=a.parentNode;return"function"==typeof a.getElementById?a:null}function d(a){return a.ownerDocument.contains(a)}function e(a,b,c,d){this.closed=!1,this.node=a,this.property=b,this.model=c,this.path=d,this.observer=new PathObserver(c,d,this.boundValueChanged,this),this.boundValueChanged(this.value)}function f(a,b,c,d){this.conditional="?"==b[b.length-1],this.conditional&&(a.removeAttribute(b),b=b.slice(0,-1)),e.call(this,a,b,c,d)}function g(a){switch(a.type){case"checkbox":return T;case"radio":case"select-multiple":case"select-one":return"change";default:return"input"}}function h(a,b,c,d){e.call(this,a,b,c,d),this.eventType=g(this.node),this.boundNodeValueToModel=this.nodeValueChanged.bind(this),this.node.addEventListener(this.eventType,this.boundNodeValueToModel,!0)}function i(a){if(!d(a))return[];if(a.form)return Q(a.form.elements,function(b){return b!=a&&"INPUT"==b.tagName&&"radio"==b.type&&b.name==a.name});var b=a.ownerDocument.querySelectorAll('input[type="radio"][name="'+a.name+'"]');return Q(b,function(b){return b!=a&&!b.form})}function j(a,b,c){h.call(this,a,"checked",b,c)}function k(a,b,c){h.call(this,a,"selectedIndex",b,c)}function l(a){return $[a.tagName]&&a.hasAttribute("template")}function m(a){return"TEMPLATE"==a.tagName||l(a)}function n(a){return _&&"TEMPLATE"==a.tagName}function o(a,b){var c=a.querySelectorAll(ab);m(a)&&b(a),P(c,b)}function p(a){function b(a){HTMLTemplateElement.decorate(a)||p(a.content)}o(a,b)}function q(a,b){Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))})}function r(a){if(!a.defaultView)return a;var b=eb.get(a);if(!b){for(b=a.implementation.createHTMLDocument("");b.lastChild;)b.removeChild(b.lastChild);eb.set(a,b)}return b}function s(a){var b=a.ownerDocument.createElement("template");a.parentNode.insertBefore(b,a);for(var c=a.attributes,d=c.length;d-->0;){var e=c[d];Z[e.name]&&("template"!==e.name&&b.setAttribute(e.name,e.value),a.removeAttribute(e.name))}return b}function t(a,b,c){var d=a.content;if(c)return d.appendChild(b),void 0;for(var e;e=b.firstChild;)d.appendChild(e)}function u(a){"TEMPLATE"===a.tagName?_||(cb?a.__proto__=HTMLTemplateElement.prototype:q(a,HTMLTemplateElement.prototype)):(q(a,HTMLTemplateElement.prototype),Object.defineProperty(a,"content",ib))}function v(a){var b=lb.get(a);b||(b=function(){H(a,a.model,a.bindingDelegate)},lb.set(a,b)),bb(b)}function w(a,b,c,d){this.closed=!1,this.node=a,this.property=b,this.model=c,this.path=d,this.node.inputs.bind(this.property,c,d||"")}function x(a){return 3==a.length&&0==a[0].length&&0==a[2].length}function y(a){if(a&&a.length){for(var b,c=a.length,d=0,e=0,f=0;c>e;){if(d=a.indexOf("{{",e),f=0>d?-1:a.indexOf("}}",d+2),0>f){if(!b)return;b.push(a.slice(e));break}b=b||[],b.push(a.slice(e,d)),b.push(a.slice(d+2,f).trim()),e=f+2}return e===c&&b.push(""),b}}function z(a,b,c,d,e){var f,g=e&&e[X];return g&&"function"==typeof g&&(f=g(c,d,b,a),f&&(c=f,d="value")),a.bind(b,c,d)}function A(a,b,c,d,e){for(var f=0;f<a.length;f+=2){var g=C(b,a[f],a[f+1],c,d);e&&e.push(g)}}function B(a){return function(b){for(var c="",d=0,e=!0;d<a.length;d++,e=!e)if(e)c+=a[d];else{var f=b[d];void 0!==f&&(c+=f)}return c}}function C(a,b,c,d,e){if(x(c))return z(a,b,d,c[1],e);c.combinator=c.combinator||B(c);var f=new M(c.combinator);f.scheduled=!0;for(var g=1;g<c.length;g+=2)z(f,g,d,c[g],e);return f.resolve(),a.bind(b,f,"value")}function D(a){b(a);for(var c,d=m(a),e=!1,f=!1,g=0;g<a.attributes.length;g++){var h=a.attributes[g],i=h.name,j=h.value;d&&(i===W?e=!0:(i===U||i===V)&&(f=!0,j=j||"{{}}"));var k=y(j);k&&(c=c||[],c.push(i,k))}return e&&!f&&(c=c||[],c.push(U,y("{{}}"))),c}function E(a){if(a.nodeType===Node.ELEMENT_NODE)return D(a);if(a.nodeType===Node.TEXT_NODE){var b=y(a.data);if(b)return["textContent",b]}}function F(a){this.node=a}function G(a,b,c,d,e){if(b&&(b.templateRef&&(HTMLTemplateElement.decorate(a,b.templateRef),d&&kb.set(a,d),e&&e.push(new F(a))),b.length&&A(b,a,c,d,e),b.children))for(var f=0,g=a.firstChild;g;g=g.nextSibling)G(g,b.children[f++],c,d,e)}function H(a,c,d){b(a);var e=E(a);e&&A(e,a,c,d);for(var f=a.firstChild;f;f=f.nextSibling)H(f,c,d)}function I(a,b){var c=a.cloneNode(!1);if(m(c))return c;for(var d=a.firstChild;d;d=d.nextSibling)c.appendChild(I(d,b));return c}function J(a){var b=E(a);m(a)&&(b=b||[],b.templateRef=a,b.hasSubTemplate=!0);for(var c=a.firstChild,d=0;c;c=c.nextSibling,d++){var e=J(c);e&&(b=b||[],b.children=b.children||[],b.children[d]=e,e.hasSubTemplate&&(b.hasSubTemplate=!0))}return b}function K(a,b,c){this.firstNode=a,this.lastNode=b,this.model=c}function L(a,b){if(a.firstChild)for(var c=new K(a.firstChild,a.lastChild,b),d=c.firstNode;d;)mb.set(d,c),d=d.nextSibling}function M(a){this.observers={},this.values={},this.value=void 0,this.size=0,this.combinator_=a,this.closed=!1,this.scheduled=!1}function N(a){this.closed=!1,this.templateElement_=a,this.terminators=[],this.iteratedValue=void 0,this.arrayObserver=void 0,this.inputs=new M(this.resolveInputs.bind(this))}var O,P=Array.prototype.forEach.call.bind(Array.prototype.forEach),Q=Array.prototype.filter.call.bind(Array.prototype.filter);a.Map&&"function"==typeof a.Map.prototype.forEach?O=a.Map:(O=function(){this.keys=[],this.values=[]},O.prototype={set:function(a,b){var c=this.keys.indexOf(a);0>c?(this.keys.push(a),this.values.push(b)):this.values[c]=b},get:function(a){var b=this.keys.indexOf(a);return 0>b?void 0:this.values[b]},"delete":function(a){var b=this.keys.indexOf(a);return 0>b?!1:(this.keys.splice(b,1),this.values.splice(b,1),!0)},forEach:function(a,b){for(var c=0;c<this.keys.length;c++)a.call(b||this,this.values[c],this.keys[c],this)}});var R="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c};"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)});var S;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?S=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;
-S=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},S.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}(),Node.prototype.bind=function(a,b,c){this.bindings=this.bindings||{};var d=this.bindings[a];return d&&d.close(),d=this.createBinding(a,b,c),this.bindings[a]=d,d?d:(console.error("Unhandled binding to Node: ",this,a,b,c),void 0)},Node.prototype.createBinding=function(){},Node.prototype.unbind=function(a){if(this.bindings){var b=this.bindings[a];b&&(b.close(),delete this.bindings[a])}},Node.prototype.unbindAll=function(){if(this.bindings){for(var a=Object.keys(this.bindings),b=0;b<a.length;b++){var c=this.bindings[a[b]];c&&c.close()}this.bindings={}}},e.prototype={boundValueChanged:function(a){this.node[this.property]=this.sanitizeBoundValue(a)},sanitizeBoundValue:function(a){return void 0==a?"":String(a)},close:function(){this.closed||(this.observer.close(),this.observer=void 0,this.node=void 0,this.model=void 0,this.closed=!0)},get value(){return this.observer.value},set value(a){PathObserver.setValueAtPath(this.model,this.path,a)},reset:function(){this.observer.reset()}},Text.prototype.createBinding=function(a,b,c){return"textContent"===a?new e(this,"data",b,c):Node.prototype.createBinding.call(this,a,b,c)},f.prototype=R({__proto__:e.prototype,boundValueChanged:function(a){return this.conditional?(a?this.node.setAttribute(this.property,""):this.node.removeAttribute(this.property),void 0):(this.node.setAttribute(this.property,this.sanitizeBoundValue(a)),void 0)}}),Element.prototype.createBinding=function(a,b,c){return new f(this,a,b,c)};var T;!function(){var a=document.createElement("div"),b=a.appendChild(document.createElement("input"));b.setAttribute("type","checkbox");var c,d=0;b.addEventListener("click",function(){d++,c=c||"click"}),b.addEventListener("change",function(){d++,c=c||"change"});var e=document.createEvent("MouseEvent");e.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),b.dispatchEvent(e),T=1==d?"change":c}(),h.prototype=R({__proto__:e.prototype,nodeValueChanged:function(){this.value=this.node[this.property],this.reset(),this.postUpdateBinding(),Platform.performMicrotaskCheckpoint()},postUpdateBinding:function(){},close:function(){this.closed||(this.node.removeEventListener(this.eventType,this.boundNodeValueToModel,!0),e.prototype.close.call(this))}}),j.prototype=R({__proto__:h.prototype,sanitizeBoundValue:function(a){return Boolean(a)},postUpdateBinding:function(){"INPUT"===this.node.tagName&&"radio"===this.node.type&&i(this.node).forEach(function(a){var b=a.bindings.checked;b&&(b.value=!1)})}}),HTMLInputElement.prototype.createBinding=function(a,b,c){return"value"===a?(this.removeAttribute(a),new h(this,"value",b,c)):"checked"===a?(this.removeAttribute(a),new j(this,b,c)):HTMLElement.prototype.createBinding.call(this,a,b,c)},HTMLTextAreaElement.prototype.createBinding=function(a,b,c){return"value"===a?(this.removeAttribute(a),new h(this,a,b,c)):HTMLElement.prototype.createBinding.call(this,a,b,c)},k.prototype=R({__proto__:h.prototype,boundValueChanged:function(a){function b(){c>e.node.length&&d--?bb(b):e.node[e.property]=c}var c=Number(a);if(c<=this.node.length)return this.node[this.property]=c,void 0;var d=2,e=this;bb(b)}}),HTMLSelectElement.prototype.createBinding=function(a,b,c){return"selectedindex"===a.toLowerCase()?(this.removeAttribute(a),new k(this,b,c)):HTMLElement.prototype.createBinding.call(this,a,b,c)};var U="bind",V="repeat",W="if",X="getBinding",Y="getInstanceModel",Z={template:!0,repeat:!0,bind:!0,ref:!0},$={THEAD:!0,TBODY:!0,TFOOT:!0,TH:!0,TR:!0,TD:!0,COLGROUP:!0,COL:!0,CAPTION:!0,OPTION:!0,OPTGROUP:!0},_="undefined"!=typeof HTMLTemplateElement,ab="template, "+Object.keys($).map(function(a){return a.toLowerCase()+"[template]"}).join(", "),bb=function(){function a(a){this.nextRunner=a,this.value=!1,this.lastValue=this.value,this.scheduled=[],this.scheduledIds=[],this.running=!1,this.observer=new PathObserver(this,"value",this.run,this)}function b(a){var b=a[e];a[e]||(b=d++,a[e]=b),c.schedule(a,b)}a.prototype={schedule:function(a,b){if(!this.scheduledIds[b]){if(this.running)return this.nextRunner.schedule(a,b);this.scheduledIds[b]=!0,this.scheduled.push(a),this.lastValue===this.value&&(this.value=!this.value)}},run:function(){this.running=!0;for(var a=0;a<this.scheduled.length;a++){var b=this.scheduled[a],c=b[e];this.scheduledIds[c]=!1,"function"==typeof b?b():b.resolve()}this.scheduled=[],this.scheduledIds=[],this.lastValue=this.value,this.running=!1}};var c=new a(new a),d=1,e="__scheduledId__";return b}();document.addEventListener("DOMContentLoaded",function(){p(document),Platform.performMicrotaskCheckpoint()},!1),_||(a.HTMLTemplateElement=function(){throw TypeError("Illegal constructor")});var cb="__proto__"in{},db=new S,eb=new S,fb=new S,gb=new S;HTMLTemplateElement.decorate=function(a,c){if(a.templateIsDecorated_)return!1;var d=a;d.templateIsDecorated_=!0;var e=n(d),f=e,g=!e,h=!1;if(!e&&l(d)&&(b(!c),d=s(a),d.templateIsDecorated_=!0,e=n(d),h=!0),!e){u(d);var i=r(d.ownerDocument);db.set(d,i.createDocumentFragment())}return c?fb.set(d,c):g?t(d,a,h):f&&p(d.content),!0},HTMLTemplateElement.bootstrap=p;var hb=a.HTMLUnknownElement||HTMLElement,ib={get:function(){return db.get(this)},enumerable:!0,configurable:!0};_||(HTMLTemplateElement.prototype=Object.create(hb.prototype),Object.defineProperty(HTMLTemplateElement.prototype,"content",ib));var jb=new S,kb=new S,lb=new S;w.prototype=R({__proto__:e.prototype,get value(){},boundValueChanged:function(){},close:function(){this.closed||(this.node.inputs.unbind(this.property),this.node=void 0,this.model=void 0,this.closed=!0)}}),q(HTMLTemplateElement.prototype,{createBinding:function(a,b,c){if(a===U||a===V||a===W){var d=nb.get(this);return d||(d=new N(this),nb.set(this,d)),new w(d,a,b,c||"")}return HTMLElement.prototype.createBinding.call(this,a,b,c)},createInstance:function(a,b,c){var d=this.ref.content,e=gb.get(d);e||(e=J(d)||[],gb.set(d,e));var f=e.hasSubTemplate?I(d):d.cloneNode(!0);return G(f,e,a,b,c),L(f,a),f},get model(){return jb.get(this)},set model(a){jb.set(this,a),v(this)},get bindingDelegate(){return kb.get(this)},set bindingDelegate(a){kb.set(this,a),v(this)},get ref(){var a,b=this.getAttribute("ref");if(b){var d=c(this);d&&(a=d.getElementById(b))}if(a||(a=fb.get(this)),!a)return this;var e=a.ref;return e?e:a}}),F.prototype={close:function(){var a=nb.get(this.node);a&&a.close()}};var mb=new S;Object.defineProperty(Node.prototype,"templateInstance",{get:function(){var a=mb.get(this);return a?a:this.parentNode?this.parentNode.templateInstance:void 0}}),M.prototype={set combinator(a){this.combinator_=a,this.scheduleResolve()},pathValueChanged:function(a,b,c){this.values[c]=a,this.scheduleResolve()},bind:function(a,b,c){this.unbind(a),this.size++;var d=new PathObserver(b,c,this.pathValueChanged,this,a);this.observers[a]=d,this.pathValueChanged(d.value,void 0,a)},unbind:function(a,b){this.observers[a]&&(this.size--,this.observers[a].close(),delete this.observers[a],delete this.values[a],b||this.scheduleResolve())},scheduleResolve:function(){this.scheduled||(this.scheduled=!0,bb(this))},resolve:function(){if(!this.closed){if(!this.combinator_)throw Error("CompoundBinding attempted to resolve without a combinator");this.value=this.combinator_(this.values),this.scheduled=!1}},unobserved:function(){this.close()},close:function(){this.closed||(Object.keys(this.observers).forEach(function(a){this.unbind(a,!0)},this),this.closed=!0,this.value=void 0)}},N.prototype={resolveInputs:function(a){this.closed||(W in a&&!a[W]?this.valueChanged(void 0):V in a?this.valueChanged(a[V]):U in a||W in a?this.valueChanged([a[U]]):this.valueChanged(void 0))},valueChanged:function(a){Array.isArray(a)||(a=void 0);var b=this.iteratedValue;this.unobserve(),this.iteratedValue=a,this.iteratedValue&&(this.arrayObserver=new ArrayObserver(this.iteratedValue,this.handleSplices,this));var c=ArrayObserver.calculateSplices(this.iteratedValue||[],b||[]);c.length&&this.handleSplices(c),this.inputs.size||(nb.delete(this),this.close())},getTerminatorAt:function(a){if(-1==a)return this.templateElement_;var b=this.terminators[2*a];if(b.nodeType!==Node.ELEMENT_NODE||this.templateElement_===b)return b;var c=nb.get(b);return c?c.getTerminatorAt(c.terminators.length/2-1):b},insertInstanceAt:function(a,b,c,d){var e=this.getTerminatorAt(a-1),f=b?b.lastChild||e:c[c.length-1]||e;this.terminators.splice(2*a,0,f,d);var g=this.templateElement_.parentNode,h=e.nextSibling;if(b)return g.insertBefore(b,h),void 0;for(var i=0;i<c.length;i++)g.insertBefore(c[i],h)},extractInstanceAt:function(a){var b=[],c=this.getTerminatorAt(a-1),d=this.getTerminatorAt(a);b.bound=this.terminators[2*a+1],this.terminators.splice(2*a,2);for(var e=this.templateElement_.parentNode;d!==c;){var f=c.nextSibling;f==d&&(d=c),e.removeChild(f),b.push(f)}return b},getInstanceModel:function(a,b,c){var d=c&&c[Y];return d&&"function"==typeof d?d(a,b):b},handleSplices:function(a){if(!this.closed){var b=this.templateElement_;if(!b.parentNode||!b.ownerDocument.defaultView)return this.close(),nb.delete(this),void 0;var c=b.bindingDelegate,d=new O,e=0;a.forEach(function(a){a.removed.forEach(function(b){var c=this.extractInstanceAt(a.index+e);d.set(b,c)},this),e-=a.addedCount},this),a.forEach(function(a){for(var e=a.index;e<a.index+a.addedCount;e++){var f,g=this.iteratedValue[e],h=void 0,i=d.get(g);if(i)d.delete(g),f=i.bound;else{f=[];var j=this.getInstanceModel(b,g,c);h=this.templateElement_.createInstance(j,c,f)}this.insertInstanceAt(e,h,i,f)}},this),d.forEach(function(a){for(var b=a.bound,c=0;c<b.length;c++)b[c].close()})}},unobserve:function(){this.arrayObserver&&(this.arrayObserver.close(),this.arrayObserver=void 0)},close:function(){if(!this.closed){this.unobserve();for(var a=1;a<this.terminators.length;a+=2)for(var b=this.terminators[a],c=0;c<b.length;c++)b[c].close();this.terminators.length=0,this.inputs.close(),this.closed=!0}}};var nb=new S;a.CompoundBinding=M,HTMLTemplateElement.forAllTemplatesFrom_=o}(this),function(a){"use strict";function b(a,b){if(!a)throw new Error("ASSERT: "+b)}function c(a){return a>=48&&57>=a}function d(a){return 32===a||9===a||11===a||12===a||160===a||a>=5760&&" ᠎              ".indexOf(String.fromCharCode(a))>0}function e(a){return 10===a||13===a||8232===a||8233===a}function f(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a}function g(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a||a>=48&&57>=a}function h(a){return"this"===a}function i(){for(;bb>ab&&d(_.charCodeAt(ab));)++ab}function j(){var a,b;for(a=ab++;bb>ab&&(b=_.charCodeAt(ab),g(b));)++ab;return _.slice(a,ab)}function k(){var a,b,c;return a=ab,b=j(),c=1===b.length?X.Identifier:h(b)?X.Keyword:"null"===b?X.NullLiteral:"true"===b||"false"===b?X.BooleanLiteral:X.Identifier,{type:c,value:b,range:[a,ab]}}function l(){var a,b,c,d,e=ab,f=_.charCodeAt(ab),g=_[ab];switch(f){case 46:case 40:case 41:case 59:case 44:case 123:case 125:case 91:case 93:case 58:case 63:case 126:return++ab,{type:X.Punctuator,value:String.fromCharCode(f),range:[e,ab]};default:if(a=_.charCodeAt(ab+1),61===a)switch(f){case 37:case 38:case 42:case 43:case 45:case 47:case 60:case 62:case 94:case 124:return ab+=2,{type:X.Punctuator,value:String.fromCharCode(f)+String.fromCharCode(a),range:[e,ab]};case 33:case 61:return ab+=2,61===_.charCodeAt(ab)&&++ab,{type:X.Punctuator,value:_.slice(e,ab),range:[e,ab]}}}return b=_[ab+1],c=_[ab+2],d=_[ab+3],">"===g&&">"===b&&">"===c&&"="===d?(ab+=4,{type:X.Punctuator,value:">>>=",range:[e,ab]}):">"===g&&">"===b&&">"===c?(ab+=3,{type:X.Punctuator,value:">>>",range:[e,ab]}):"<"===g&&"<"===b&&"="===c?(ab+=3,{type:X.Punctuator,value:"<<=",range:[e,ab]}):">"===g&&">"===b&&"="===c?(ab+=3,{type:X.Punctuator,value:">>=",range:[e,ab]}):g===b&&"+-<>&|".indexOf(g)>=0?(ab+=2,{type:X.Punctuator,value:g+b,range:[e,ab]}):"<>=!+-*%&|^/".indexOf(g)>=0?(++ab,{type:X.Punctuator,value:g,range:[e,ab]}):(s({},$.UnexpectedToken,"ILLEGAL"),void 0)}function m(){var a,d,e;if(e=_[ab],b(c(e.charCodeAt(0))||"."===e,"Numeric literal must start with a decimal digit or a decimal point"),d=ab,a="","."!==e){for(a=_[ab++],e=_[ab],"0"===a&&e&&c(e.charCodeAt(0))&&s({},$.UnexpectedToken,"ILLEGAL");c(_.charCodeAt(ab));)a+=_[ab++];e=_[ab]}if("."===e){for(a+=_[ab++];c(_.charCodeAt(ab));)a+=_[ab++];e=_[ab]}if("e"===e||"E"===e)if(a+=_[ab++],e=_[ab],("+"===e||"-"===e)&&(a+=_[ab++]),c(_.charCodeAt(ab)))for(;c(_.charCodeAt(ab));)a+=_[ab++];else s({},$.UnexpectedToken,"ILLEGAL");return f(_.charCodeAt(ab))&&s({},$.UnexpectedToken,"ILLEGAL"),{type:X.NumericLiteral,value:parseFloat(a),range:[d,ab]}}function n(){var a,c,d,f="",g=!1;for(a=_[ab],b("'"===a||'"'===a,"String literal must starts with a quote"),c=ab,++ab;bb>ab;){if(d=_[ab++],d===a){a="";break}if("\\"===d)if(d=_[ab++],d&&e(d.charCodeAt(0)))"\r"===d&&"\n"===_[ab]&&++ab;else switch(d){case"n":f+="\n";break;case"r":f+="\r";break;case"t":f+="	";break;case"b":f+="\b";break;case"f":f+="\f";break;case"v":f+="";break;default:f+=d}else{if(e(d.charCodeAt(0)))break;f+=d}}return""!==a&&s({},$.UnexpectedToken,"ILLEGAL"),{type:X.StringLiteral,value:f,octal:g,range:[c,ab]}}function o(a){return a.type===X.Identifier||a.type===X.Keyword||a.type===X.BooleanLiteral||a.type===X.NullLiteral}function p(){var a;return i(),ab>=bb?{type:X.EOF,range:[ab,ab]}:(a=_.charCodeAt(ab),40===a||41===a||58===a?l():39===a||34===a?n():f(a)?k():46===a?c(_.charCodeAt(ab+1))?m():l():c(a)?m():l())}function q(){var a;return a=db,ab=a.range[1],db=p(),ab=a.range[1],a}function r(){var a;a=ab,db=p(),ab=a}function s(a,c){var d,e=Array.prototype.slice.call(arguments,2),f=c.replace(/%(\d)/g,function(a,c){return b(c<e.length,"Message reference must be in range"),e[c]});throw d=new Error(f),d.index=ab,d.description=f,d}function t(a){s(a,$.UnexpectedToken,a.value)}function u(a){var b=q();(b.type!==X.Punctuator||b.value!==a)&&t(b)}function v(a){return db.type===X.Punctuator&&db.value===a}function w(a){return db.type===X.Keyword&&db.value===a}function x(){return 59===_.charCodeAt(ab)?(q(),void 0):(i(),v(";")?(q(),void 0):(db.type===X.EOF||v("}")||t(db),void 0))}function y(){var a=[];for(u("[");!v("]");)v(",")?(q(),a.push(null)):(a.push(O()),v("]")||u(","));return u("]"),cb.createArrayExpression(a)}function z(){var a;return i(),a=q(),a.type===X.StringLiteral||a.type===X.NumericLiteral?cb.createLiteral(a):cb.createIdentifier(a.value)}function A(){var a,b;return a=db,i(),(a.type===X.EOF||a.type===X.Punctuator)&&t(a),b=z(),u(":"),cb.createProperty("init",b,O())}function B(){var a=[];for(u("{");!v("}");)a.push(A()),v("}")||u(",");return u("}"),cb.createObjectExpression(a)}function C(){var a;return u("("),a=P(),u(")"),a}function D(){var a,b,c;return v("(")?C():(a=db.type,a===X.Identifier?c=cb.createIdentifier(q().value):a===X.StringLiteral||a===X.NumericLiteral?c=cb.createLiteral(q()):a===X.Keyword?w("this")&&(q(),c=cb.createThisExpression()):a===X.BooleanLiteral?(b=q(),b.value="true"===b.value,c=cb.createLiteral(b)):a===X.NullLiteral?(b=q(),b.value=null,c=cb.createLiteral(b)):v("[")?c=y():v("{")&&(c=B()),c?c:(t(q()),void 0))}function E(){var a=[];if(u("("),!v(")"))for(;bb>ab&&(a.push(O()),!v(")"));)u(",");return u(")"),a}function F(){var a;return a=q(),o(a)||t(a),cb.createIdentifier(a.value)}function G(){return u("."),F()}function H(){var a;return u("["),a=P(),u("]"),a}function I(){var a,b,c;for(a=D();v(".")||v("[")||v("(");)v("(")?(b=E(),a=cb.createCallExpression(a,b)):v("[")?(c=H(),a=cb.createMemberExpression("[",a,c)):(c=G(),a=cb.createMemberExpression(".",a,c));return a}function J(){var a;return a=I(),db.type===X.Punctuator&&(v("++")||v("--"))&&s({},$.UnexpectedToken),a}function K(){var a,b;return db.type!==X.Punctuator&&db.type!==X.Keyword?b=J():v("++")||v("--")?s({},$.UnexpectedToken):v("+")||v("-")||v("~")||v("!")?(a=q(),b=K(),b=cb.createUnaryExpression(a.value,b)):w("delete")||w("void")||w("typeof")?s({},$.UnexpectedToken):b=J(),b}function L(a,b){var c=0;if(a.type!==X.Punctuator&&a.type!==X.Keyword)return 0;switch(a.value){case"||":c=1;break;case"&&":c=2;break;case"|":c=3;break;case"^":c=4;break;case"&":c=5;break;case"==":case"!=":case"===":case"!==":c=6;break;case"<":case">":case"<=":case">=":case"instanceof":c=7;break;case"in":c=b?7:0;break;case"<<":case">>":case">>>":c=8;break;case"+":case"-":c=9;break;case"*":case"/":case"%":c=11}return c}function M(){var a,b,c,d,e,f,g,h,i;if(d=eb.allowIn,eb.allowIn=!0,h=K(),b=db,c=L(b,d),0===c)return h;for(b.prec=c,q(),f=K(),e=[h,b,f];(c=L(db,d))>0;){for(;e.length>2&&c<=e[e.length-2].prec;)f=e.pop(),g=e.pop().value,h=e.pop(),a=cb.createBinaryExpression(g,h,f),e.push(a);b=q(),b.prec=c,e.push(b),a=K(),e.push(a)}for(eb.allowIn=d,i=e.length-1,a=e[i];i>1;)a=cb.createBinaryExpression(e[i-1].value,e[i-2],a),i-=2;return a}function N(){var a,b,c,d;return a=M(),v("?")&&(q(),b=eb.allowIn,eb.allowIn=!0,c=O(),eb.allowIn=b,u(":"),d=O(),a=cb.createConditionalExpression(a,c,d)),a}function O(){var a,b,c;return a=db,c=b=N()}function P(){var a;return a=O()}function Q(){return u(";"),cb.createEmptyStatement()}function R(){var a=P();return x(),cb.createExpressionStatement(a)}function S(){var a,b,c,d=db.type;if(d===X.EOF&&t(db),i(),d===X.Punctuator)switch(db.value){case";":return Q();case"(":return R()}return a=P(),a.type===Z.Identifier&&v(":")?(q(),c="$"+a.name,Object.prototype.hasOwnProperty.call(eb.labelSet,c)&&s({},$.Redeclaration,"Label",a.name),eb.labelSet[c]=!0,b=S(),delete eb.labelSet[c],cb.createLabeledStatement(a,b)):(x(),cb.createExpressionStatement(a))}function T(){return db.type===X.Keyword?S():db.type!==X.EOF?S():void 0}function U(){for(var a,b=[];bb>ab&&(a=T(),"undefined"!=typeof a);)b.push(a);return b}function V(){var a;return i(),r(),a=U(),cb.createProgram(a)}function W(a,b){var c;return c=String,"string"==typeof a||a instanceof String||(a=c(a)),cb=b,_=a,ab=0,bb=_.length,db=null,eb={allowIn:!0,labelSet:{}},bb>0&&"undefined"==typeof _[0]&&a instanceof String&&(_=a.valueOf()),V()}var X,Y,Z,$,_,ab,bb,cb,db,eb;X={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},Y={},Y[X.BooleanLiteral]="Boolean",Y[X.EOF]="<end>",Y[X.Identifier]="Identifier",Y[X.Keyword]="Keyword",Y[X.NullLiteral]="Null",Y[X.NumericLiteral]="Numeric",Y[X.Punctuator]="Punctuator",Y[X.StringLiteral]="String",Z={ArrayExpression:"ArrayExpression",BinaryExpression:"BinaryExpression",CallExpression:"CallExpression",ConditionalExpression:"ConditionalExpression",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",Identifier:"Identifier",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ThisExpression:"ThisExpression",UnaryExpression:"UnaryExpression"},$={UnexpectedToken:"Unexpected token %0",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared"},a.esprima={parse:W}}(this),function(a){"use strict";function b(a,b,d,e){if(e.nodeType===Node.ELEMENT_NODE&&"TEMPLATE"===e.tagName&&("bind"===d||"repeat"===d)){var f,g,h=b.match(r);if(h?(f=h[1],g=h[2]):(h=b.match(s),h&&(f=h[2],g=h[1])),h){var i;if(g=g.trim(),g.match(q))i=new CompoundBinding(function(a){return a.path}),i.bind("path",a,g);else try{i=c(a,g)}catch(j){console.error("Invalid expression syntax: "+g,j)}if(i)return t.set(e,f),i}}}function c(a,b){try{var c=new f;if(esprima.parse(b,c),!c.statements.length&&!c.labeledStatements.length)return;if(!c.labeledStatements.length&&c.statements.length>1)throw Error("Multiple unlabelled statements are not allowed.");var e=c.labeledStatements.length?d(c.labeledStatements):e=c.statements[0],g=[];for(var h in c.deps)g.push(h);if(!g.length)return{value:e({})};for(var i=new CompoundBinding(e),j=0;j<g.length;j++)i.bind(g[j],a,g[j]);return i}catch(k){console.error("Invalid expression syntax: "+b,k)}}function d(a){return function(b){for(var c=[],d=0;d<a.length;d++)a[d].body(b)&&c.push(a[d].label);return c.join(" ")}}function e(a,b,c){this.deps=a,this.name=b,this.last=c}function f(){this.statements=[],this.labeledStatements=[],this.deps={},this.currentPath=void 0}function g(){throw Error("Not Implemented")}function h(){}var i;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?i=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;i=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},i.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}();var j="[$_a-zA-Z]",k="[$_a-zA-Z0-9]",l=j+"+"+k+"*",m="("+l+")",n="(?:[0-9]|[1-9]+[0-9]+)",o="(?:"+l+"|"+n+")",p="(?:"+o+")(?:\\."+o+")*",q=new RegExp("^"+p+"$"),r=new RegExp("^"+m+"\\s* in (.*)$"),s=new RegExp("^(.*) as \\s*"+m+"$"),t=new i;e.prototype={getPath:function(){return this.last?this.last.getPath()+"."+this.name:this.name},valueFn:function(){var a=this.getPath();return this.deps[a]=!0,function(b){return b[a]}}};var u={"+":function(a){return+a},"-":function(a){return-a},"!":function(a){return!a}},v={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"*":function(a,b){return a*b},"/":function(a,b){return a/b},"%":function(a,b){return a%b},"<":function(a,b){return b>a},">":function(a,b){return a>b},"<=":function(a,b){return b>=a},">=":function(a,b){return a>=b},"==":function(a,b){return a==b},"!=":function(a,b){return a!=b},"===":function(a,b){return a===b},"!==":function(a,b){return a!==b},"&&":function(a,b){return a&&b},"||":function(a,b){return a||b}};f.prototype={getFn:function(a){return a instanceof e?a.valueFn():a},createProgram:function(){},createExpressionStatement:function(a){return this.statements.push(a),a},createLabeledStatement:function(a,b){return this.labeledStatements.push({label:a.getPath(),body:b instanceof e?b.valueFn():b}),b},createUnaryExpression:function(a,b){if(!u[a])throw Error("Disallowed operator: "+a);return b=this.getFn(b),function(c){return u[a](b(c))}},createBinaryExpression:function(a,b,c){if(!v[a])throw Error("Disallowed operator: "+a);return b=this.getFn(b),c=this.getFn(c),function(d){return v[a](b(d),c(d))}},createConditionalExpression:function(a,b,c){return a=this.getFn(a),b=this.getFn(b),c=this.getFn(c),function(d){return a(d)?b(d):c(d)}},createIdentifier:function(a){var b=new e(this.deps,a);return b.type="Identifier",b},createMemberExpression:function(a,b,c){return new e(this.deps,c.name,b)},createLiteral:function(a){return function(){return a.value}},createArrayExpression:function(a){for(var b=0;b<a.length;b++)a[b]=this.getFn(a[b]);return function(b){for(var c=[],d=0;d<a.length;d++)c.push(a[d](b));return c}},createProperty:function(a,b,c){return{key:b instanceof e?b.getPath():b(),value:c}},createObjectExpression:function(a){for(var b=0;b<a.length;b++)a[b].value=this.getFn(a[b].value);return function(b){for(var c={},d=0;d<a.length;d++)c[a[d].key]=a[d].value(b);return c}},createCallExpression:g,createEmptyStatement:g,createThisExpression:g},h.prototype={getBinding:function(a,d,e,f){return d=d.trim(),d&&!d.match(q)?b(a,d,e,f)||c(a,d,e,f):void 0},getInstanceModel:function(a,b){var c=t.get(a);if(!c)return b;var d=a.templateInstance?a.templateInstance.model:a.model,e=Object.create(d);return e[c]=b,e}},a.ExpressionSyntax=h}(this),function(a){function b(){logFlags.data&&console.group("Model.dirtyCheck()"),c(),logFlags.data&&console.groupEnd()}function c(){Platform.performMicrotaskCheckpoint()}var d=document.createElement("style");d.textContent="template {display: none !important;} /* injected by platform.js */";var e=document.querySelector("head");e.insertBefore(d,e.firstChild),HTMLTemplateElement.__instanceCreated=function(a){document.adoptNode(a),CustomElements.upgradeAll(a)};var f=125;window.addEventListener("WebComponentsReady",function(){b(),Observer.hasObjectObserve||setInterval(c,f)}),a.flush=b,window.dirtyCheck=b}(window.Platform),function(a){function b(a){return d(a,i)}function c(a){return d(a,j)}function d(a,b){return"link"===a.localName&&a.getAttribute("rel")===b}function e(a){return"script"===a.localName}function f(a,b){var c=a;c instanceof Document||(c=document.implementation.createHTMLDocument(i),c.body.innerHTML=a),c._URL=b;var d=c.createElement("base");return d.setAttribute("href",document.baseURI),c.head.appendChild(d),window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(c),c}a||(a=window.HTMLImports={flags:{}});var g,h=a.xhr,i="import",j="stylesheet",k={documents:{},cache:{},preloadSelectors:["link[rel="+i+"]","element link[rel="+j+"]","template","script[src]:not([type])",'script[src][type="text/javascript"]'].join(","),loader:function(a){return g=new l(k.loaded,a),g.cache=k.cache,g},load:function(a,b){g=k.loader(b),k.preload(a)},preload:function(a){var b=a.querySelectorAll(k.preloadSelectors);b=this.filterMainDocumentNodes(a,b),b=this.extractTemplateNodes(b),g.addNodes(b)},filterMainDocumentNodes:function(a,b){return a===document&&(b=Array.prototype.filter.call(b,function(a){return!e(a)})),b},extractTemplateNodes:function(a){var b=[];return a=Array.prototype.filter.call(a,function(a){if("template"===a.localName){if(a.content){var c=a.content.querySelectorAll("link[rel="+j+"]");c.length&&(b=b.concat(Array.prototype.slice.call(c,0)))}return!1}return!0}),b.length&&(a=a.concat(b)),a},loaded:function(a,d,e){if(b(d)){var g=k.documents[a];g||(g=f(e,a),p.resolvePathsInHTML(g),k.documents[a]=g,k.preload(g)),d.import={href:a,ownerNode:d,content:g},d.content=e=g}d.__resource=e,c(d)&&p.resolvePathsInStylesheet(d)}},l=function(a,b){this.onload=a,this.oncomplete=b,this.inflight=0,this.pending={},this.cache={}};l.prototype={addNodes:function(a){this.inflight+=a.length,q(a,this.require,this),this.checkDone()},require:function(a){var b=p.nodeUrl(a);a.__nodeUrl=b,this.dedupe(b,a)||this.fetch(b,a)},dedupe:function(a,b){return this.pending[a]?(this.pending[a].push(b),!0):this.cache[a]?(this.onload(a,b,g.cache[a]),this.tail(),!0):(this.pending[a]=[b],!1)},fetch:function(a,b){var c=function(c,d){this.receive(a,b,c,d)}.bind(this);h.load(a,c)},receive:function(a,b,c,d){c||(g.cache[a]=d),g.pending[a].forEach(function(b){c||this.onload(a,b,d),this.tail()},this),g.pending[a]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}};var m=["href","src","action"],n="["+m.join("],[")+"]",o="{{.*}}",p={nodeUrl:function(a){return p.resolveUrl(p.getDocumentUrl(document),p.hrefOrSrc(a))},hrefOrSrc:function(a){return a.getAttribute("href")||a.getAttribute("src")},documentUrlFromNode:function(a){return p.getDocumentUrl(a.ownerDocument||a)},getDocumentUrl:function(a){var b=a&&(a._URL||a.impl&&a.impl._URL||a.baseURI||a.URL)||"";return b.split("#")[0]},resolveUrl:function(a,b,c){if(this.isAbsUrl(b))return b;var d=this.compressUrl(this.urlToPath(a)+b);return c&&(d=p.makeRelPath(p.getDocumentUrl(document),d)),d},isAbsUrl:function(a){return/(^data:)|(^http[s]?:)|(^\/)/.test(a)},urlToPath:function(a){var b=a.split("/");return b.pop(),b.push(""),b.join("/")},compressUrl:function(a){for(var b,c=a.split("/"),d=0;d<c.length;d++)b=c[d],".."===b&&(c.splice(d-1,2),d-=2);return c.join("/")},makeRelPath:function(a,b){var c,d;for(c=this.compressUrl(a).split("/"),d=this.compressUrl(b).split("/");c.length&&c[0]===d[0];)c.shift(),d.shift();for(var e=0,f=c.length-1;f>e;e++)d.unshift("..");var g=d.join("/");return g},resolvePathsInHTML:function(a,b){b=b||p.documentUrlFromNode(a),p.resolveAttributes(a,b),p.resolveStyleElts(a,b);var c=a.querySelectorAll("template");c&&q(c,function(a){a.content&&p.resolvePathsInHTML(a.content,b)})},resolvePathsInStylesheet:function(a){var b=p.nodeUrl(a);a.__resource=p.resolveCssText(a.__resource,b)},resolveStyleElts:function(a,b){var c=a.querySelectorAll("style");c&&q(c,function(a){a.textContent=p.resolveCssText(a.textContent,b)})},resolveCssText:function(a,b){return a.replace(/url\([^)]*\)/g,function(a){var c=a.replace(/["']/g,"").slice(4,-1);return c=p.resolveUrl(b,c,!0),"url("+c+")"})},resolveAttributes:function(a,b){var c=a&&a.querySelectorAll(n);c&&q(c,function(a){this.resolveNodeAttributes(a,b)},this)},resolveNodeAttributes:function(a,b){m.forEach(function(c){var d=a.attributes[c];if(d&&d.value&&d.value.search(o)<0){var e=p.resolveUrl(b,d.value,!0);d.value=e}})}};h=h||{async:!0,ok:function(a){return a.status>=200&&a.status<300||304===a.status||0===a.status},load:function(b,c,d){var e=new XMLHttpRequest;return(a.flags.debug||a.flags.bust)&&(b+="?"+Math.random()),e.open("GET",b,h.async),e.addEventListener("readystatechange",function(){4===e.readyState&&c.call(d,!h.ok(e)&&e,e.response,b)}),e.send(),e},loadDocument:function(a,b,c){this.load(a,b,c).responseType="document"}};var q=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.path=p,a.xhr=h,a.importer=k,a.getDocumentUrl=p.getDocumentUrl,a.IMPORT_LINK_TYPE=i}(window.HTMLImports),function(a){function b(a){return"link"===a.localName&&a.getAttribute("rel")===f}function c(a){return a.parentNode&&!d(a)&&!e(a)}function d(a){return a.ownerDocument===document||a.ownerDocument.impl===document}function e(a){return a.parentNode&&"element"===a.parentNode.localName}var f="import",g={selectors:["link[rel="+f+"]","link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'],map:{link:"parseLink",script:"parseScript",style:"parseGeneric"},parse:function(a){if(!a.__importParsed){a.__importParsed=!0;var b=a.querySelectorAll(g.selectors);h(b,function(a){g[g.map[a.localName]](a)})}},parseLink:function(a){b(a)?a.content&&g.parse(a.content):this.parseGeneric(a)},parseGeneric:function(a){c(a)&&document.head.appendChild(a)},parseScript:function(b){if(c(b)){var d=(b.__resource||b.textContent).trim();if(d){var e=b.__nodeUrl;if(!e){var e=a.path.documentUrlFromNode(b),f="["+Math.floor(1e3*(Math.random()+1))+"]",g=d.match(/Polymer\(['"]([^'"]*)/);f=g&&g[1]||f,e+="/"+f+".js"}d+="\n//# sourceURL="+e+"\n",eval.call(window,d)}}}},h=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.parser=g}(HTMLImports),function(){function a(){HTMLImports.importer.load(document,function(){HTMLImports.parser.parse(document),HTMLImports.readyTime=(new Date).getTime(),document.dispatchEvent(new CustomEvent("HTMLImportsLoaded",{bubbles:!0}))})}"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState?a():window.addEventListener("DOMContentLoaded",a)}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w
-}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new SideTable,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g}(this),!window.MutationObserver&&(window.MutationObserver=window.WebKitMutationObserver||window.JsMutationObserver,!MutationObserver))throw new Error("no mutation observer support");!function(a){function b(b,f){var g=f||{};if(!b)throw new Error("Name argument must not be empty");if(g.name=b,!g.prototype)throw new Error("Options missing required prototype property");return g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),m(b,g),g.ctor=n(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,a.ready&&a.upgradeAll(document),g.ctor}function c(a){var b=s[a];return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.name,c&&(a.is=a.name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}}a.native=b}function f(a){return g(t(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.readyCallback&&a.readyCallback()}function k(a){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a,b){l.call(this,a,b,c)}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments),this.attributeChangedCallback&&this.getAttribute(a)!==d&&this.attributeChangedCallback(a,d)}function m(a,b){s[a]=b}function n(a){return function(){return f(a)}}function o(a){var b=s[a];return b?new b.ctor:t(a)}function p(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is")||a.localName,c=s[b];return c&&g(a,c)}}function q(b){var c=u.call(this,b);return a.upgradeAll(c),c}if(a||(a=window.CustomElements={flags:{}}),a.hasNative=(document.webkitRegister||document.register)&&"native"===a.flags.register,a.hasNative){document.register=document.register||document.webkitRegister;var r=function(){};a.registry={},a.upgradeElement=r}else{var s={},t=document.createElement.bind(document),u=Node.prototype.cloneNode;document.register=b,document.createElement=o,Node.prototype.cloneNode=q,a.registry=s,a.upgrade=p}}(window.CustomElements),function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,d){b(a,function(a){return d(a)?!0:(a.webkitShadowRoot&&c(a.webkitShadowRoot,d),void 0)}),a.webkitShadowRoot&&c(a.webkitShadowRoot,d)}function d(a){return g(a)?(h(a),!0):(i(a),void 0)}function e(a){c(a,function(a){return d(a)?!0:void 0})}function f(a){return d(a)||e(a)}function g(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return logFlags.dom&&console.group("upgrade:",b.localName),a.upgrade(b),logFlags.dom&&console.groupEnd(),!0}}function h(a){i(a),l(a)&&c(a,function(a){i(a)})}function i(a){(a.insertedCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.group("inserted:",a.localName),l(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?logFlags.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.insertedCallback&&(logFlags.dom&&console.log("inserted:",a.localName),a.insertedCallback())),logFlags.dom&&console.groupEnd())}function j(a){k(a),c(a,function(a){k(a)})}function k(a){(a.removedCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.log("removed:",a.localName),l(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?logFlags.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.removedCallback&&a.removedCallback()))}function l(a){for(var b=a;b;){if(b==a.ownerDocument)return!0;b=b.parentNode||b.host}}function m(a){a.webkitShadowRoot&&!a.webkitShadowRoot.__watched&&(logFlags.dom&&console.log("watching shadow-root for: ",a.localName),r(a.webkitShadowRoot),a.webkitShadowRoot.__watched=!0)}function n(a){m(a),c(a,function(){m(a)})}function o(a){switch(a.localName){case"style":case"script":case"template":case void 0:return!0}}function p(a){if(logFlags.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(v(a.addedNodes,function(a){o(a)||f(a)}),v(a.removedNodes,function(a){o(a)||j(a)}))}),logFlags.dom&&console.groupEnd()}function q(){p(u.takeRecords())}function r(a){u.observe(a,{childList:!0,subtree:!0})}function s(a){r(a)}function t(a){logFlags.dom&&console.group("upgradeDocument: ",(a.URL||a._URL||"").split("/").pop()),f(a),logFlags.dom&&console.groupEnd()}var u=new MutationObserver(p),v=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.watchShadow=m,a.watchAllShadows=n,a.upgradeAll=f,a.upgradeSubtree=e,a.observeDocument=s,a.upgradeDocument=t,a.takeRecords=q}(window.CustomElements),function(){function parseElementElement(a){var b={name:"","extends":null};takeAttributes(a,b);var c=HTMLElement.prototype;if(b.extends){var d=document.createElement(b.extends);c=d.__proto__||Object.getPrototypeOf(d)}b.prototype=Object.create(c),a.options=b;var e=a.querySelector('script:not([type]),script[type="text/javascript"],scripts');e&&executeComponentScript(e.textContent,a,b.name);var f=document.register(b.name,b);a.ctor=f;var g=a.getAttribute("constructor");g&&(window[g]=f)}function takeAttributes(a,b){for(var c in b){var d=a.attributes[c];d&&(b[c]=d.value)}}function executeComponentScript(inScript,inContext,inName){context=inContext;var owner=context.ownerDocument,url=owner._URL||owner.URL||owner.impl&&(owner.impl._URL||owner.impl.URL),match=url.match(/.*\/([^.]*)[.]?.*$/);if(match){var name=match[1];url+=name!=inName?":"+inName:""}var code="__componentScript('"+inName+"', function(){"+inScript+"});"+"\n//# sourceURL="+url+"\n";eval(code)}function mixin(a,b){a=a||{};try{Object.getOwnPropertyNames(b).forEach(function(c){var d=Object.getOwnPropertyDescriptor(b,c);d&&Object.defineProperty(a,c,d)})}catch(c){}return a}var HTMLElementElement=function(a){return a.register=HTMLElementElement.prototype.register,parseElementElement(a),a};HTMLElementElement.prototype={register:function(a){a&&(this.options.lifecycle=a.lifecycle,a.prototype&&mixin(this.options.prototype,a.prototype))}};var context;window.__componentScript=function(a,b){b.call(context)},window.HTMLElementElement=HTMLElementElement}(),function(){function a(a){return"link"===a.localName&&a.getAttribute("rel")===b}var b=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",c={selectors:["link[rel="+b+"]","element"],map:{link:"parseLink",element:"parseElement"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(c.selectors);d(b,function(a){c[c.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(b){a(b)&&this.parseImport(b)},parseImport:function(a){a.content&&c.parse(a.content)},parseElement:function(a){new HTMLElementElement(a)}},d=Array.prototype.forEach.call.bind(Array.prototype.forEach);CustomElements.parser=c}(),function(){function a(){setTimeout(function(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.body.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))},0)}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState)a();else{var b=window.HTMLImports?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(b,a)}}(),function(){function a(){}var b=document.createElement("style");b.textContent="element {display: none !important;} /* injected by platform.js */";var c=document.querySelector("head");if(c.insertBefore(b,c.firstChild),window.ShadowDOMPolyfill){CustomElements.watchShadow=a,CustomElements.watchAllShadows=a;var d=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],e={};d.forEach(function(a){e[a]=CustomElements[a]}),d.forEach(function(a){CustomElements[a]=function(b){return e[a](wrap(b))}})}}(),function(a){a=a||{};var b={shadow:function(a){return a?a.shadowRoot||a.webkitShadowRoot:void 0},canTarget:function(a){return a&&Boolean(a.elementFromPoint)},targetingShadow:function(a){var b=this.shadow(a);return this.canTarget(b)?b:void 0},olderShadow:function(a){var b=a.olderShadowRoot;if(!b){var c=a.querySelector("shadow");c&&(b=c.olderShadowRoot)}return b},allShadows:function(a){for(var b=[],c=this.shadow(a);c;)b.push(c),c=this.olderShadow(c);return b},searchRoot:function(a,b,c){if(a){var d,e,f=a.elementFromPoint(b,c);for(e=this.targetingShadow(f);e;){if(d=e.elementFromPoint(b,c)){var g=this.targetingShadow(d);return this.searchRoot(g,b,c)||d}e=this.olderShadow(e)}return f}},owner:function(a){for(var b=a;b.parentNode;)b=b.parentNode;return b},findTarget:function(a){var b=a.clientX,c=a.clientY,d=this.owner(a.target);return d.elementFromPoint(b,c)||(d=document),this.searchRoot(document,b,c)}};a.targetFinding=b,a.findTarget=b.findTarget.bind(b),window.PointerEventsPolyfill=a}(window.PointerEventsPolyfill),function(){function a(a){return'[touch-action="'+a+'"]'}function b(a){return"{ -ms-touch-action: "+a+"; touch-action: "+a+"; }"}var c=["none","auto","pan-x","pan-y",{rule:"pan-x pan-y",selectors:["pan-x pan-y","pan-y pan-x"]}],d="";c.forEach(function(c){d+=String(c)===c?a(c)+b(c):c.selectors.map(a)+b(c.rule)});var e=document.createElement("style");e.textContent=d;var f=document.querySelector("head");f.insertBefore(e,f.firstChild)}(),function(a){function b(a,b){var b=b||{},e=b.buttons;if(void 0===e)switch(b.which){case 1:e=1;break;case 2:e=4;break;case 3:e=2;break;default:e=0}var f;if(c)f=new MouseEvent(a,b);else{f=document.createEvent("MouseEvent");var g={bubbles:!1,cancelable:!1,view:null,detail:null,screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null};Object.keys(g).forEach(function(a){a in b&&(g[a]=b[a])}),f.initMouseEvent(a,g.bubbles,g.cancelable,g.view,g.detail,g.screenX,g.screenY,g.clientX,g.clientY,g.ctrlKey,g.altKey,g.shiftKey,g.metaKey,g.button,g.relatedTarget)}d||Object.defineProperty(f,"buttons",{get:function(){return e},enumerable:!0});var h=0;return h=b.pressure?b.pressure:e?.5:0,Object.defineProperties(f,{pointerId:{value:b.pointerId||0,enumerable:!0},width:{value:b.width||0,enumerable:!0},height:{value:b.height||0,enumerable:!0},pressure:{value:h,enumerable:!0},tiltX:{value:b.tiltX||0,enumerable:!0},tiltY:{value:b.tiltY||0,enumerable:!0},pointerType:{value:b.pointerType||"",enumerable:!0},hwTimestamp:{value:b.hwTimestamp||0,enumerable:!0},isPrimary:{value:b.isPrimary||!1,enumerable:!0}}),f}var c=!1,d=!1;try{var e=new MouseEvent("click",{buttons:1});c=!0,d=1===e.buttons}catch(f){}a.PointerEvent||(a.PointerEvent=b)}(window),function(a){function b(){this.ids=[],this.pointers=[]}b.prototype={set:function(a,b){var c=this.ids.indexOf(a);c>-1?this.pointers[c]=b:(this.ids.push(a),this.pointers.push(b))},has:function(a){return this.ids.indexOf(a)>-1},"delete":function(a){var b=this.ids.indexOf(a);b>-1&&(this.ids.splice(b,1),this.pointers.splice(b,1))},get:function(a){var b=this.ids.indexOf(a);return this.pointers[b]},get size(){return this.pointers.length},clear:function(){this.ids.length=0,this.pointers.length=0},forEach:function(a,b){this.ids.forEach(function(c,d){a.call(b,c,this.pointers[d],this)},this)}},a.PointerMap=window.Map&&Map.prototype.forEach?Map:b}(window.PointerEventsPolyfill),function(a){var b;if("undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0)b=WeakMap;else{var c=Object.defineProperty,d=Object.hasOwnProperty,e=(new Date).getTime()%1e9;b=function(){this.name="__st"+(1e9*Math.random()>>>0)+(e++ +"__")},b.prototype={set:function(a,b){c(a,this.name,{value:b,writable:!0})},get:function(a){return d.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}a.SideTable=b}(window.PointerEventsPolyfill),function(a){var b={targets:new a.SideTable,handledEvents:new a.SideTable,pointermap:new a.PointerMap,eventMap:{},eventSources:{},eventSourceList:[],registerSource:function(a,b){var c=b,d=c.events;d&&(d.forEach(function(a){c[a]&&(this.eventMap[a]=c[a].bind(c))},this),this.eventSources[a]=c,this.eventSourceList.push(c))},register:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.register.call(b,a)},unregister:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.unregister.call(b,a)},down:function(a){this.fireEvent("pointerdown",a)},move:function(a){this.fireEvent("pointermove",a)},up:function(a){this.fireEvent("pointerup",a)},enter:function(a){a.bubbles=!1,this.fireEvent("pointerenter",a)},leave:function(a){a.bubbles=!1,this.fireEvent("pointerleave",a)},over:function(a){a.bubbles=!0,this.fireEvent("pointerover",a)},out:function(a){a.bubbles=!0,this.fireEvent("pointerout",a)},cancel:function(a){this.fireEvent("pointercancel",a)},leaveOut:function(a){a.target.contains(a.relatedTarget)||this.leave(a),this.out(a)},enterOver:function(a){a.target.contains(a.relatedTarget)||this.enter(a),this.over(a)},eventHandler:function(a){if(!this.handledEvents.get(a)){var b=a.type,c=this.eventMap&&this.eventMap[b];c&&c(a),this.handledEvents.set(a,!0)}},listen:function(a,b){b.forEach(function(b){this.addEvent(a,b)},this)},unlisten:function(a,b){b.forEach(function(b){this.removeEvent(a,b)},this)},addEvent:function(a,b){a.addEventListener(b,this.boundHandler)},removeEvent:function(a,b){a.removeEventListener(b,this.boundHandler)},makeEvent:function(a,b){var c=new PointerEvent(a,b);return this.targets.set(c,this.targets.get(b)||b.target),c},fireEvent:function(a,b){var c=this.makeEvent(a,b);return this.dispatchEvent(c)},cloneEvent:function(a){var b={};for(var c in a)b[c]=a[c];return b},getTarget:function(a){return this.captureInfo&&this.captureInfo.id===a.pointerId?this.captureInfo.target:this.targets.get(a)},setCapture:function(a,b){this.captureInfo&&this.releaseCapture(this.captureInfo.id),this.captureInfo={id:a,target:b};var c=new PointerEvent("gotpointercapture",{bubbles:!0});this.implicitRelease=this.releaseCapture.bind(this,a),document.addEventListener("pointerup",this.implicitRelease),document.addEventListener("pointercancel",this.implicitRelease),this.targets.set(c,b),this.asyncDispatchEvent(c)},releaseCapture:function(a){if(this.captureInfo&&this.captureInfo.id===a){var b=new PointerEvent("lostpointercapture",{bubbles:!0}),c=this.captureInfo.target;this.captureInfo=null,document.removeEventListener("pointerup",this.implicitRelease),document.removeEventListener("pointercancel",this.implicitRelease),this.targets.set(b,c),this.asyncDispatchEvent(b)}},dispatchEvent:function(a){var b=this.getTarget(a);return b?b.dispatchEvent(a):void 0},asyncDispatchEvent:function(a){setTimeout(this.dispatchEvent.bind(this,a),0)}};b.boundHandler=b.eventHandler.bind(b),a.dispatcher=b,a.register=b.register.bind(b),a.unregister=b.unregister.bind(b)}(window.PointerEventsPolyfill),function(a){function b(a,b,c,d){this.addCallback=a.bind(d),this.removeCallback=b.bind(d),this.changedCallback=c.bind(d),g&&(this.observer=new g(this.mutationWatcher.bind(this)))}var c=Array.prototype.forEach.call.bind(Array.prototype.forEach),d=Array.prototype.map.call.bind(Array.prototype.map),e=Array.prototype.slice.call.bind(Array.prototype.slice),f=Array.prototype.filter.call.bind(Array.prototype.filter),g=window.MutationObserver||window.WebKitMutationObserver,h="[touch-action]",i={subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0,attributeFilter:["touch-action"]};b.prototype={watchSubtree:function(b){a.targetFinding.canTarget(b)&&this.observer.observe(b,i)},enableOnSubtree:function(a){this.watchSubtree(a),a===document&&"complete"!==document.readyState?this.installOnLoad():this.installNewSubtree(a)},installNewSubtree:function(a){c(this.findElements(a),this.addElement,this)},findElements:function(a){return a.querySelectorAll?a.querySelectorAll(h):[]},removeElement:function(a){this.removeCallback(a)},addElement:function(a){this.addCallback(a)},elementChanged:function(a,b){this.changedCallback(a,b)},concatLists:function(a,b){return a.concat(e(b))},installOnLoad:function(){document.addEventListener("DOMContentLoaded",this.installNewSubtree.bind(this,document))},isElement:function(a){return a.nodeType===Node.ELEMENT_NODE},flattenMutationTree:function(a){var b=d(a,this.findElements,this);return b.push(f(a,this.isElement)),b.reduce(this.concatLists,[])},mutationWatcher:function(a){a.forEach(this.mutationHandler,this)},mutationHandler:function(a){if("childList"===a.type){var b=this.flattenMutationTree(a.addedNodes);b.forEach(this.addElement,this);var c=this.flattenMutationTree(a.removedNodes);c.forEach(this.removeElement,this)}else"attributes"===a.type&&this.elementChanged(a.target,a.oldValue)}},g||(b.prototype.watchSubtree=function(){console.warn("PointerEventsPolyfill: MutationObservers not found, touch-action will not be dynamically detected")}),a.Installer=b}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher,c=b.pointermap,d=25,e={POINTER_ID:1,POINTER_TYPE:"mouse",events:["mousedown","mousemove","mouseup","mouseover","mouseout"],register:function(a){b.listen(a,this.events)},unregister:function(a){b.unlisten(a,this.events)},lastTouches:[],isEventSimulatedFromTouch:function(a){for(var b,c=this.lastTouches,e=a.clientX,f=a.clientY,g=0,h=c.length;h>g&&(b=c[g]);g++){var i=Math.abs(e-b.x),j=Math.abs(f-b.y);if(d>=i&&d>=j)return!0}},prepareEvent:function(a){var c=b.cloneEvent(a);return c.pointerId=this.POINTER_ID,c.isPrimary=!0,c.pointerType=this.POINTER_TYPE,c},mousedown:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.has(this.POINTER_ID);d&&this.cancel(a);var e=this.prepareEvent(a);c.set(this.POINTER_ID,a),b.down(e)}},mousemove:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.move(c)}},mouseup:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.get(this.POINTER_ID);if(d&&d.button===a.button){var e=this.prepareEvent(a);b.up(e),this.cleanupMouse()}}},mouseover:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.enterOver(c)}},mouseout:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.leaveOut(c)}},cancel:function(a){var c=this.prepareEvent(a);b.cancel(c),this.cleanupMouse()},cleanupMouse:function(){c.delete(this.POINTER_ID)}};a.mouseEvents=e}(window.PointerEventsPolyfill),function(a){var b,c=a.dispatcher,d=a.findTarget,e=a.targetFinding.allShadows.bind(a.targetFinding),f=c.pointermap,g=Array.prototype.map.call.bind(Array.prototype.map),h=2500,i="touch-action",j="string"==typeof document.head.style.touchAction,k={scrollType:new a.SideTable,events:["touchstart","touchmove","touchend","touchcancel"],register:function(a){j?c.listen(a,this.events):b.enableOnSubtree(a)},unregister:function(a){j&&c.unlisten(a,this.events)},elementAdded:function(a){var b=a.getAttribute(i),d=this.touchActionToScrollType(b);d&&(this.scrollType.set(a,d),c.listen(a,this.events),e(a).forEach(function(a){this.scrollType.set(a,d),c.listen(a,this.events)},this))},elementRemoved:function(a){this.scrollType.delete(a),c.unlisten(a,this.events),e(a).forEach(function(a){this.scrollType.delete(a),c.unlisten(a,this.events)},this)},elementChanged:function(a,b){var c=a.getAttribute(i),d=this.touchActiontoScrollType(c),f=this.touchActionToScrollType(b);d&&f?(this.scrollType.set(a,d),e(a).forEach(function(a){this.scrollType.set(a,d)},this)):f?this.elementRemoved(a):d&&this.elementAdded(a)},scrollTypes:{EMITTER:"none",XSCROLLER:"pan-x",YSCROLLER:"pan-y",SCROLLER:/^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/},touchActionToScrollType:function(a){var b=a,c=this.scrollTypes;return"none"===b?"none":b===c.XSCROLLER?"X":b===c.YSCROLLER?"Y":c.SCROLLER.exec(b)?"XY":void 0},POINTER_TYPE:"touch",firstTouch:null,isPrimaryTouch:function(a){return this.firstTouch===a.identifier},setPrimaryTouch:function(a){null===this.firstTouch&&(this.firstTouch=a.identifier,this.firstXY={X:a.clientX,Y:a.clientY},this.scrolling=!1)},removePrimaryTouch:function(a){this.isPrimaryTouch(a)&&(this.firstTouch=null,this.firstXY=null)},touchToPointer:function(a){var b=c.cloneEvent(a);return b.pointerId=a.identifier+2,b.target=d(b),b.bubbles=!0,b.cancelable=!0,b.button=0,b.buttons=1,b.width=a.webkitRadiusX||a.radiusX||0,b.height=a.webkitRadiusY||a.radiusY||0,b.pressure=a.webkitForce||a.force||.5,b.isPrimary=this.isPrimaryTouch(a),b.pointerType=this.POINTER_TYPE,b},processTouches:function(a,b){var c=a.changedTouches,d=g(c,this.touchToPointer,this);d.forEach(b,this)},shouldScroll:function(a){if(this.firstXY){var b,c=this.scrollType.get(a.currentTarget);if("none"===c)b=!1;else if("XY"===c)b=!0;else{var d=a.changedTouches[0],e=c,f="Y"===c?"X":"Y",g=Math.abs(d["client"+e]-this.firstXY[e]),h=Math.abs(d["client"+f]-this.firstXY[f]);b=g>=h}return this.firstXY=null,b}},findTouch:function(a,b){for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)if(c.identifier===b)return!0},vacuumTouches:function(a){var b=a.touches;if(f.size>=b.length){var c=[];f.forEach(function(a,d){if(1!==a&&!this.findTouch(b,a-2)){var e=d.out;c.push(this.touchToPointer(e))}},this),c.forEach(this.cancelOut,this)}},touchstart:function(a){this.vacuumTouches(a),this.setPrimaryTouch(a.changedTouches[0]),this.dedupSynthMouse(a),this.scrolling||this.processTouches(a,this.overDown)},overDown:function(a){f.set(a.pointerId,{target:a.target,out:a,outTarget:a.target}),c.over(a),c.down(a)},touchmove:function(a){this.scrolling||(this.shouldScroll(a)?(this.scrolling=!0,this.touchcancel(a)):(a.preventDefault(),this.processTouches(a,this.moveOverOut)))},moveOverOut:function(a){var b=a,d=f.get(b.pointerId);if(d){var e=d.out,g=d.outTarget;c.move(b),e&&g!==b.target&&(e.relatedTarget=b.target,b.relatedTarget=g,e.target=g,b.target?(c.leaveOut(e),c.enterOver(b)):(b.target=g,b.relatedTarget=null,this.cancelOut(b))),d.out=b,d.outTarget=b.target}},touchend:function(a){this.dedupSynthMouse(a),this.processTouches(a,this.upOut)},upOut:function(a){this.scrolling||(c.up(a),c.out(a)),this.cleanUpPointer(a)},touchcancel:function(a){this.processTouches(a,this.cancelOut)},cancelOut:function(a){c.cancel(a),c.out(a),this.cleanUpPointer(a)},cleanUpPointer:function(a){f.delete(a.pointerId),this.removePrimaryTouch(a)},dedupSynthMouse:function(b){var c=a.mouseEvents.lastTouches,d=b.changedTouches[0];if(this.isPrimaryTouch(d)){var e={x:d.clientX,y:d.clientY};c.push(e);var f=function(a,b){var c=a.indexOf(b);c>-1&&a.splice(c,1)}.bind(null,c,e);setTimeout(f,h)}}};j||(b=new a.Installer(k.elementAdded,k.elementRemoved,k.elementChanged,k)),a.touchEvents=k}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher,c=b.pointermap,d=window.MSPointerEvent&&"number"==typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,e={events:["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerOut","MSPointerOver","MSPointerCancel","MSGotPointerCapture","MSLostPointerCapture"],register:function(a){b.listen(a,this.events)},unregister:function(a){b.unlisten(a,this.events)},POINTER_TYPES:["","unavailable","touch","pen","mouse"],prepareEvent:function(a){var c=a;return d&&(c=b.cloneEvent(a),c.pointerType=this.POINTER_TYPES[a.pointerType]),c},cleanup:function(a){c.delete(a)},MSPointerDown:function(a){c.set(a.pointerId,a);var d=this.prepareEvent(a);b.down(d)},MSPointerMove:function(a){var c=this.prepareEvent(a);b.move(c)},MSPointerUp:function(a){var c=this.prepareEvent(a);b.up(c),this.cleanup(a.pointerId)},MSPointerOut:function(a){var c=this.prepareEvent(a);b.leaveOut(c)},MSPointerOver:function(a){var c=this.prepareEvent(a);b.enterOver(c)},MSPointerCancel:function(a){var c=this.prepareEvent(a);b.cancel(c),this.cleanup(a.pointerId)},MSLostPointerCapture:function(a){var c=b.makeEvent("lostpointercapture",a);b.dispatchEvent(c)},MSGotPointerCapture:function(a){var c=b.makeEvent("gotpointercapture",a);b.dispatchEvent(c)}};a.msEvents=e}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher;if(void 0===window.navigator.pointerEnabled){if(Object.defineProperty(window.navigator,"pointerEnabled",{value:!0,enumerable:!0}),window.navigator.msPointerEnabled){var c=window.navigator.msMaxTouchPoints;Object.defineProperty(window.navigator,"maxTouchPoints",{value:c,enumerable:!0}),b.registerSource("ms",a.msEvents)}else b.registerSource("mouse",a.mouseEvents),void 0!==window.ontouchstart&&b.registerSource("touch",a.touchEvents);b.register(document)}}(window.PointerEventsPolyfill),function(a){function b(a){if(!e.pointermap.has(a))throw new Error("InvalidPointerId")}var c,d,e=a.dispatcher,f=window.navigator;f.msPointerEnabled?(c=function(a){b(a),this.msSetPointerCapture(a)},d=function(a){b(a),this.msReleasePointerCapture(a)}):(c=function(a){b(a),e.setCapture(a,this)},d=function(a){b(a),e.releaseCapture(a,this)}),Element.prototype.setPointerCapture||Object.defineProperties(Element.prototype,{setPointerCapture:{value:c},releasePointerCapture:{value:d}})}(window.PointerEventsPolyfill),PointerGestureEvent.prototype.preventTap=function(){this.tapPrevented=!0},function(a){a=a||{},a.utils={LCA:{find:function(a,b){if(a===b)return a;if(a.contains){if(a.contains(b))return a;if(b.contains(a))return b}var c=this.depth(a),d=this.depth(b),e=c-d;for(e>0?a=this.walk(a,e):b=this.walk(b,-e);a&&b&&a!==b;)a=this.walk(a,1),b=this.walk(b,1);return a},walk:function(a,b){for(var c=0;b>c;c++)a=a.parentNode;return a},depth:function(a){for(var b=0;a;)b++,a=a.parentNode;return b}}},a.findLCA=function(b,c){return a.utils.LCA.find(b,c)},window.PointerGestures=a}(window.PointerGestures),function(a){var b;if("undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0)b=WeakMap;else{var c=Object.defineProperty,d=Object.hasOwnProperty,e=(new Date).getTime()%1e9;b=function(){this.name="__st"+(1e9*Math.random()>>>0)+(e++ +"__")},b.prototype={set:function(a,b){c(a,this.name,{value:b,writable:!0})},get:function(a){return d.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}a.SideTable=b}(window.PointerGestures),function(a){function b(){this.ids=[],this.pointers=[]}b.prototype={set:function(a,b){var c=this.ids.indexOf(a);c>-1?this.pointers[c]=b:(this.ids.push(a),this.pointers.push(b))},has:function(a){return this.ids.indexOf(a)>-1},"delete":function(a){var b=this.ids.indexOf(a);b>-1&&(this.ids.splice(b,1),this.pointers.splice(b,1))},get:function(a){var b=this.ids.indexOf(a);return this.pointers[b]},get size(){return this.pointers.length},clear:function(){this.ids.length=0,this.pointers.length=0}},window.Map&&(b=window.Map),a.PointerMap=b}(window.PointerGestures),function(a){var b={handledEvents:new a.SideTable,targets:new a.SideTable,handlers:{},recognizers:{},events:["pointerdown","pointermove","pointerup","pointerover","pointerout","pointercancel"],registerRecognizer:function(a,b){var c=b;this.recognizers[a]=c,this.events.forEach(function(a){if(c[a]){var b=c[a].bind(c);this.addHandler(a,b)}},this)},addHandler:function(a,b){var c=a;this.handlers[c]||(this.handlers[c]=[]),this.handlers[c].push(b)},registerTarget:function(a){this.listen(this.events,a)},unregisterTarget:function(a){this.unlisten(this.events,a)},eventHandler:function(a){if(!this.handledEvents.get(a)){var b,c=a.type;(b=this.handlers[c])&&this.makeQueue(b,a),this.handledEvents.set(a,!0)}},makeQueue:function(a,b){var c=this.cloneEvent(b);setTimeout(this.runQueue.bind(this,a,c),0)},runQueue:function(a,b){this.currentPointerId=b.pointerId;for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)c(b);this.currentPointerId=0},listen:function(a,b){a.forEach(function(a){this.addEvent(a,this.boundHandler,!1,b)},this)},unlisten:function(a){a.forEach(function(a){this.removeEvent(a,this.boundHandler,!1,inTarget)},this)},addEvent:function(a,b,c,d){d.addEventListener(a,b,c)},removeEvent:function(a,b,c,d){d.removeEventListener(a,b,c)
-},makeEvent:function(a,b){return new PointerGestureEvent(a,b)},cloneEvent:function(a){var b={};for(var c in a)b[c]=a[c];return b},dispatchEvent:function(a,b){var c=b||this.targets.get(a);c&&(c.dispatchEvent(a),a.tapPrevented&&this.preventTap(this.currentPointerId))},asyncDispatchEvent:function(a,b){var c=function(){this.dispatchEvent(a,b)}.bind(this);setTimeout(c,0)},preventTap:function(a){var b=this.recognizers.tap;b&&b.preventTap(a)}};b.boundHandler=b.eventHandler.bind(b),a.dispatcher=b,a.register=function(b){var c=window.PointerEventsPolyfill;c&&c.register(b),a.dispatcher.registerTarget(b)},b.registerTarget(document)}(window.PointerGestures),function(a){var b=a.dispatcher,c={HOLD_DELAY:200,WIGGLE_THRESHOLD:16,events:["pointerdown","pointermove","pointerup","pointercancel"],heldPointer:null,holdJob:null,pulse:function(){var a=Date.now()-this.heldPointer.timeStamp,b=this.held?"holdpulse":"hold";this.fireHold(b,a),this.held=!0},cancel:function(){clearInterval(this.holdJob),this.held&&this.fireHold("release"),this.held=!1,this.heldPointer=null,this.target=null,this.holdJob=null},pointerdown:function(a){a.isPrimary&&!this.heldPointer&&(this.heldPointer=a,this.target=a.target,this.holdJob=setInterval(this.pulse.bind(this),this.HOLD_DELAY))},pointerup:function(a){this.heldPointer&&this.heldPointer.pointerId===a.pointerId&&this.cancel()},pointercancel:function(){this.cancel()},pointermove:function(a){if(this.heldPointer&&this.heldPointer.pointerId===a.pointerId){var b=a.clientX-this.heldPointer.clientX,c=a.clientY-this.heldPointer.clientY;b*b+c*c>this.WIGGLE_THRESHOLD&&this.cancel()}},fireHold:function(a,c){var d={pointerType:this.heldPointer.pointerType};c&&(d.holdTime=c);var e=b.makeEvent(a,d);b.dispatchEvent(e,this.target),e.tapPrevented&&b.preventTap(this.heldPointer.pointerId)}};b.registerRecognizer("hold",c)}(window.PointerGestures),function(a){var b=a.dispatcher,c=new a.PointerMap,d={events:["pointerdown","pointermove","pointerup","pointercancel"],WIGGLE_THRESHOLD:4,clampDir:function(a){return a>0?1:-1},calcPositionDelta:function(a,b){var c=0,d=0;return a&&b&&(c=b.pageX-a.pageX,d=b.pageY-a.pageY),{x:c,y:d}},fireTrack:function(a,c,d){var e=d,f=this.calcPositionDelta(e.downEvent,c),g=this.calcPositionDelta(e.lastMoveEvent,c);g.x&&(e.xDirection=this.clampDir(g.x)),g.y&&(e.yDirection=this.clampDir(g.y));var h={dx:f.x,dy:f.y,ddx:g.x,ddy:g.y,clientX:c.clientX,clientY:c.clientY,pageX:c.pageX,pageY:c.pageY,screenX:c.screenX,screenY:c.screenY,xDirection:e.xDirection,yDirection:e.yDirection,trackInfo:e.trackInfo,pointerType:c.pointerType};"trackend"===a&&(h._releaseTarget=c.target);var i=b.makeEvent(a,h);e.lastMoveEvent=c,b.dispatchEvent(i,e.downTarget)},pointerdown:function(a){if(a.isPrimary&&("mouse"===a.pointerType?1===a.buttons:!0)){var b={downEvent:a,downTarget:a.target,trackInfo:{},lastMoveEvent:null,xDirection:0,yDirection:0,tracking:!1};c.set(a.pointerId,b)}},pointermove:function(a){var b=c.get(a.pointerId);if(b)if(b.tracking)this.fireTrack("track",a,b);else{var d=this.calcPositionDelta(b.downEvent,a),e=d.x*d.x+d.y*d.y;e>this.WIGGLE_THRESHOLD&&(b.tracking=!0,this.fireTrack("trackstart",b.downEvent,b),this.fireTrack("track",a,b))}},pointerup:function(a){var b=c.get(a.pointerId);b&&(b.tracking&&this.fireTrack("trackend",a,b),c.delete(a.pointerId))},pointercancel:function(a){this.pointerup(a)}};b.registerRecognizer("track",d)}(window.PointerGestures),function(a){var b=a.dispatcher,c={MIN_VELOCITY:.5,MAX_QUEUE:4,moveQueue:[],target:null,pointerId:null,events:["pointerdown","pointermove","pointerup","pointercancel"],pointerdown:function(a){a.isPrimary&&!this.pointerId&&(this.pointerId=a.pointerId,this.target=a.target,this.addMove(a))},pointermove:function(a){a.pointerId===this.pointerId&&this.addMove(a)},pointerup:function(a){a.pointerId===this.pointerId&&this.fireFlick(a),this.cleanup()},pointercancel:function(){this.cleanup()},cleanup:function(){this.moveQueue=[],this.target=null,this.pointerId=null},addMove:function(a){this.moveQueue.length>=this.MAX_QUEUE&&this.moveQueue.shift(),this.moveQueue.push(a)},fireFlick:function(a){for(var c,d,e,f,g,h,i,j=a,k=this.moveQueue.length,l=0,m=0,n=0,o=0;k>o&&(i=this.moveQueue[o]);o++)c=j.timeStamp-i.timeStamp,d=j.clientX-i.clientX,e=j.clientY-i.clientY,f=d/c,g=e/c,h=Math.sqrt(f*f+g*g),h>n&&(l=f,m=g,n=h);var p=Math.abs(l)>Math.abs(m)?"x":"y",q=this.calcAngle(l,m);if(Math.abs(n)>=this.MIN_VELOCITY){var r=b.makeEvent("flick",{xVelocity:l,yVelocity:m,velocity:n,angle:q,majorAxis:p,pointerType:a.pointerType});b.dispatchEvent(r,this.target)}},calcAngle:function(a,b){return 180*Math.atan2(b,a)/Math.PI}};b.registerRecognizer("flick",c)}(window.PointerGestures),function(a){var b=a.dispatcher,c=new a.PointerMap,d={events:["pointerdown","pointermove","pointerup","pointercancel"],pointerdown:function(a){a.isPrimary&&!a.tapPrevented&&c.set(a.pointerId,{target:a.target,x:a.clientX,y:a.clientY})},pointermove:function(a){if(a.isPrimary){var b=c.get(a.pointerId);b&&a.tapPrevented&&c.delete(a.pointerId)}},pointerup:function(d){var e=c.get(d.pointerId);if(e&&!d.tapPrevented){var f=a.findLCA(e.target,d.target);if(f){var g=b.makeEvent("tap",{x:d.clientX,y:d.clientY,pointerType:d.pointerType});b.dispatchEvent(g,f)}}c.delete(d.pointerId)},pointercancel:function(a){c.delete(a.pointerId)},preventTap:function(a){c.delete(a)}};b.registerRecognizer("tap",d)}(window.PointerGestures),Polymer={},function(){var a=document.createElement("style");a.textContent="body {opacity: 0;}";var b=document.querySelector("head");b.insertBefore(a,b.firstChild),window.addEventListener("WebComponentsReady",function(){document.body.style.webkitTransition="opacity 0.3s",document.body.style.opacity=1})}(Polymer),function(a){var b=Array.prototype.forEach.call.bind(Array.prototype.forEach),c=Array.prototype.concat.call.bind(Array.prototype.concat),d=Array.prototype.slice.call.bind(Array.prototype.slice),e={hostRuleRe:/@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,selectorRe:/([^{]*)({[\s\S]*?})/gim,hostElementRe:/(.*)((?:\*)|(?:\:scope))(.*)/,hostFixableRe:/^[.\[:]/,cssCommentRe:/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,cssPolyfillCommentRe:/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,cssPseudoRe:/::(x-[^\s{,(]*)/gim,selectorReSuffix:"([>\\s~+[.,{:][\\s\\S]*)?$",hostRe:/@host/gim,cache:{},shimStyling:function(a){if(window.ShadowDOMPolyfill&&a){var b=a.getAttribute("name");e.cacheDefinition(a),e.shimPolyfillDirectives(a.styles,b),Polymer.strictPolyfillStyling&&e.applyScopeToContent(a.templateContent(),b),e.applyShimming(e.stylesForElement(a),b)}},shimShadowDOMStyling:function(a,b){window.ShadowDOMPolyfill&&(e.shimPolyfillDirectives(a,b),e.applyShimming(a,b))},applyShimming:function(a,b){var c=this.shimAtHost(a,b);c+=this.shimScoping(a,b),this.addCssToDocument(c)},cacheDefinition:function(a){var b=a.getAttribute("name"),c=a.templateContent(),f=c&&c.querySelectorAll("style");a.styles=f?d(f):[],e.cache[b]=a},applyScopeToContent:function(a,c){a&&(b(a.querySelectorAll("*"),function(a){a.setAttribute(c,"")}),b(a.querySelectorAll("template"),function(a){this.applyScopeToContent(templateContent(a),c)},this))},stylesForElement:function(a){var b=a.styles,e=a.templateContent(),f=e&&e.querySelector("shadow");if(f||null===e){var g=this.findExtendee(a.getAttribute("name"));if(g){var h=this.stylesForElement(g);b=c(d(h),d(b))}}return b},findExtendee:function(a){var b=this.cache[a];return b&&this.cache[b.getAttribute("extends")]},shimPolyfillDirectives:function(a,c){window.ShadowDOMPolyfill&&a&&b(a,function(a){a.textContent=this.convertPolyfillDirectives(a.textContent,c)},this)},shimAtHost:function(a,b){return a?this.convertAtHostStyles(a,b):void 0},shimScoping:function(a,b){return a?this.convertScopedStyles(a,b):void 0},convertPolyfillDirectives:function(a,b){for(var c,d,e="",f=0;c=this.cssPolyfillCommentRe.exec(a);)e+=a.substring(f,c.index),d=c[1].slice(0,-2).replace(this.hostRe,b),e+=this.scopeSelector(d,b)+"{",f=this.cssPolyfillCommentRe.lastIndex;return e+=a.substring(f,a.length)},findAtHostRules:function(a,b){return Array.prototype.filter.call(a,this.isHostRule.bind(this,b))},isHostRule:function(a,b){return b.selectorText&&b.selectorText.match(a)||b.cssRules&&this.findAtHostRules(b.cssRules,a).length||b.type==CSSRule.WEBKIT_KEYFRAMES_RULE},convertAtHostStyles:function(a,b){for(var c,d=this.stylesToCssText(a),e="",f=0;c=this.hostRuleRe.exec(d);)e+=d.substring(f,c.index),e+=this.scopeHostCss(c[1],b),f=this.hostRuleRe.lastIndex;e+=d.substring(f,d.length);var g=new RegExp("^"+b+this.selectorReSuffix,"m"),d=this.rulesToCss(this.findAtHostRules(this.cssToRules(e),g));return d},scopeHostCss:function(a,b){for(var c,d="";c=this.selectorRe.exec(a);)d+=this.scopeHostSelector(c[1],b)+" "+c[2]+"\n	";return d},scopeHostSelector:function(a,b){var c=[],d=a.split(","),e="[is="+b+"]";return d.forEach(function(a){a=a.trim(),a.match(this.hostElementRe)?a=a.replace(this.hostElementRe,b+"$1$3, "+e+"$1$3"):a.match(this.hostFixableRe)&&(a=b+a+", "+e+a),c.push(a)},this),c.join(", ")},convertScopedStyles:function(a,c){b(a,function(a){a.parentNode&&a.parentNode.removeChild(a)});var d=this.stylesToCssText(a).replace(this.hostRuleRe,"");d=this.convertPseudos(d);var e=this.cssToRules(d);return d=this.scopeRules(e,c)},convertPseudos:function(a){return a.replace(this.cssPseudoRe," [pseudo=$1]")},scopeRules:function(a,c){var d="";return b(a,function(a){a.selectorText&&a.style&&a.style.cssText?(d+=this.scopeSelector(a.selectorText,c,Polymer.strictPolyfillStyling)+" {\n	",d+=this.propertiesFromRule(a)+"\n}\n\n"):a.media?(d+="@media "+a.media.mediaText+" {\n",d+=this.scopeRules(a.cssRules,c),d+="\n}\n\n"):a.cssText&&(d+=a.cssText+"\n\n")},this),d},propertiesFromRule:function(a){var b=a.style.cssText;return a.style.content&&!a.style.content.match(/['"]+/)&&(b="content: '"+a.style.content+"';\n"+a.style.cssText.replace(/content:[^;]*;/g,"")),b},selectorNeedsScoping:function(a,b){var c="("+b+"|\\[is="+b+"\\])",d=new RegExp("^"+c+this.selectorReSuffix,"m");return!a.match(d)},scopeSelector:function(a,b,c){var d=[],e=a.split(",");return e.forEach(function(a){a=a.trim(),this.selectorNeedsScoping(a,b)&&(a=c?this.applyStrictSelectorScope(a,b):this.applySimpleSelectorScope(a,b)),d.push(a)},this),d.join(", ")},applySimpleSelectorScope:function(a,b){return b+" "+a+", "+"[is="+b+"] "+a},applyStrictSelectorScope:function(a,b){var c=[" ",">","+","~"],d=a,e="["+b+"]";return c.forEach(function(a){var b=d.split(a);d=b.map(function(a){var b=a.trim();return b&&c.indexOf(b)<0&&b.indexOf(e)<0&&(a=b.replace(/([^:]*)(:*)(.*)/,"$1"+e+"$2$3")),a}).join(a)}),d},stylesToCssText:function(a,c){var d="";return b(a,function(a){d+=a.textContent+"\n\n"}),c||(d=this.stripCssComments(d)),d},stripCssComments:function(a){return a.replace(this.cssCommentRe,"")},cssToRules:function(a){var b=document.createElement("style");b.textContent=a,document.head.appendChild(b);var c=b.sheet.cssRules;return b.parentNode.removeChild(b),c},rulesToCss:function(a){for(var b=0,c=[];b<a.length;b++)c.push(a[b].cssText);return c.join("\n\n")},addCssToDocument:function(a){a&&this.getSheet().appendChild(document.createTextNode(a))},getSheet:function(){return this.sheet||(this.sheet=document.createElement("style"),this.sheet.setAttribute("polymer-polyfill","")),this.sheet},addSheetToDocument:function(){this.addCssToDocument("style { display: none !important; }\n");var a=document.querySelector("head");a.insertBefore(this.getSheet(),a.childNodes[0])}};window.ShadowDOMPolyfill&&e.addSheetToDocument(),a.shimStyling=e.shimStyling,a.shimShadowDOMStyling=e.shimShadowDOMStyling,a.shimPolyfillDirectives=e.shimPolyfillDirectives.bind(e),a.strictPolyfillStyling=!1}(Polymer),function(a){function b(a,b){return a&&b&&Object.getOwnPropertyNames(b).forEach(function(c){var d=Object.getOwnPropertyDescriptor(b,c);d&&(Object.defineProperty(a,c,d),"function"==typeof d.value&&(a[c].nom=c))}),a}a.extend=b}(Polymer),function(){var a={};HTMLElement.register=function(b,c){a[b]=c},HTMLElement.getPrototypeForTag=function(b){var c=b?a[b]:HTMLElement.prototype;return c||Object.getPrototypeOf(document.createElement(b))};var b=Event.prototype.stopPropagation;Event.prototype.stopPropagation=function(){this.cancelBubble=!0,b.apply(this,arguments)},HTMLImports.importer.preloadSelectors+=", polymer-element link[rel=stylesheet]"}(Polymer),function(a){function b(a,b){var d=typeof b;return b instanceof Date&&(d="date"),c[d](a,b)}var c={string:function(a){return a},date:function(a){return new Date(Date.parse(a)||Date.now())},"boolean":function(a){return""===a?!0:"false"===a?!1:!!a},number:function(a){var b=parseFloat(a);return String(b)===a?b:a},object:function(a,b){if(!b)return a;try{return JSON.parse(a.replace(/'/g,'"'))}catch(c){return a}}};a.deserializeValue=b}(Polymer),function(a){function b(a,b,d){return a?a.stop():a=new c(this),a.go(b,d),a}var c=function(a){this.context=a};c.prototype={go:function(a,b){this.callback=a,this.handle=setTimeout(this.complete.bind(this),b)},stop:function(){this.handle&&(clearTimeout(this.handle),this.handle=null)},complete:function(){this.handle&&(this.stop(),this.callback.call(this.context))}},a.job=b}(Polymer),function(a){function b(a){var c=b.caller,f=c.nom;"_super"in c||(f||(f=e.call(this,c)),f||console.warn("called super() on a method not installed declaratively (has no .nom property)"),d(c,f,Object.getPrototypeOf(this)));var g=c._super;if(g){var h=g[f];return"_super"in h||d(h,f,g),h.apply(this,a||[])}}function c(a,b,c){for(;a&&(!a.hasOwnProperty(b)||a[b]===c);)a=Object.getPrototypeOf(a);return a}function d(a,b,d){return a._super=c(d,b,a),a._super&&(a._super[b].nom=b),a._super}function e(a){console.warn("nameInThis called");for(var b=this;b&&b!==HTMLElement.prototype;){for(var c,d=Object.getOwnPropertyNames(b),e=0,f=d.length;f>e&&(c=d[e]);e++){var g=Object.getOwnPropertyDescriptor(b,c);if(g.value==a)return c}b=b.__proto__}}a.super=b}(Polymer),function(a){var b={};b.declaration={},b.instance={},a.api=b}(Polymer),function(a){var b={async:function(a,b,c){Platform.flush(),b=b&&b.length?b:[b];var d=function(){(this[a]||a).apply(this,b)}.bind(this);return c?setTimeout(d,c):requestAnimationFrame(d)},fire:function(a,b,c,d){var e=c||this;return e.dispatchEvent(new CustomEvent(a,{bubbles:void 0!==d?!1:!0,detail:b})),b},asyncFire:function(){this.asyncMethod("fire",arguments)},classFollows:function(a,b,c){b&&b.classList.remove(c),a&&a.classList.add(c)}};b.asyncMethod=b.async,a.api.instance.utils=b}(Polymer),function(a){function b(a,b){b.cancelBubble||(b.on=i+b.type,h.events&&console.group("[%s]: listenLocal [%s]",a.localName,b.on),!b.path||window.ShadowDOMPolyfill?d(a,b):c(a,b),h.events&&console.groupEnd())}function c(a,b){var c=null;Array.prototype.some.call(b.path,function(d){return d===a?!0:(c=c===a?c:e(d),c&&f(c,d,b)?!0:void 0)},this)}function d(a,b){h.events&&console.log("event.path() not supported for",b.type);for(var c=b.target,d=null;c&&c!=a;){if(d=d===a?d:e(c),d&&f(d,c,b))return!0;c=c.parentNode}}function e(a){for(;a.parentNode;)a=a.parentNode;return a.host}function f(a,b,c){var d=b.getAttribute&&b.getAttribute(c.on);return d&&g(b,c)&&(h.events&&console.log("[%s] found handler name [%s]",a.localName,d),a.dispatchMethod(b,d,[c,c.detail,b])),c.cancelBubble}function g(a,b){var c=l.get(b);return c||l.set(b,c=[]),c.indexOf(a)<0?(c.push(a),!0):void 0}var h=window.logFlags||{},i="on-",j="eventDelegates",k={EVENT_PREFIX:i,DELEGATES:j,addHostListeners:function(){var a=this[j];h.events&&Object.keys(a).length>0&&console.log("[%s] addHostListeners:",this.localName,a),this.addNodeListeners(this,a,this.hostEventListener)},addInstanceListeners:function(a,b){var c=b.delegates;c&&(h.events&&Object.keys(c).length>0&&console.log("[%s:root] addInstanceListeners:",this.localName,c),this.addNodeListeners(a,c,this.instanceEventListener))},addNodeListeners:function(a,b,c){var d;for(var e in b)d||(d=c.bind(this)),a.addEventListener(e,d)},hostEventListener:function(a){if(!a.cancelBubble){h.events&&console.group("[%s]: hostEventListener(%s)",this.localName,a.type);var b=this.findEventDelegate(a);b&&(h.events&&console.log("[%s] found host handler name [%s]",this.localName,b),this.dispatchMethod(this,b,[a,a.detail,this])),h.events&&console.groupEnd()}},findEventDelegate:function(a){return this[j][a.type]},dispatchMethod:function(a,b,c){if(a){h.events&&console.group("[%s] dispatch [%s]",a.localName,b);var d=this[b];d&&d[c?"apply":"call"](this,c),h.events&&console.groupEnd()}},instanceEventListener:function(a){b(this,a)}},l=new SideTable("handledList");a.api.instance.events=k}(Polymer),function(a){function b(a,b){var c=this[a]||a;"function"==typeof c&&c.apply(this,b)}function c(a,b,c,d){h.bind&&console.log(n,c.localName||"object",d,a.localName,b);var e=PathObserver.getValueAtPath(c,d);return(null===e||void 0===e)&&PathObserver.setValueAtPath(c,d,a[b]),PathObserver.defineProperty(a,b,{object:c,path:d})}function d(a,b,c){var d=g(a);d[b]=c}function e(a,b){var c=g(a);return c&&c[b]?(c[b].close(),c[b]=null,!0):void 0}function f(a){var b=g(a);Object.keys(b).forEach(function(a){b[a].close(),b[a]=null})}function g(a){var b=k.get(a);return b||k.set(a,b={}),b}var h=window.logFlags||{},i="Changed",j={observeProperties:function(){for(var a,b=this.getCustomPropertyNames(),c=0,d=b.length;d>c&&(a=b[c]);c++)this.observeProperty(a)},getCustomPropertyNames:function(){return this.customPropertyNames},observeProperty:function(a){if(this.shouldObserveProperty(a)){h.watch&&console.log(l,this.localName,a);var b=function(b,c){h.watch&&console.log(m,this.localName,this.id||"",a,this[a],c),this.dispatchPropertyChange(a,c)}.bind(this),c=new PathObserver(this,a,b);d(this,a,c)}},bindProperty:function(a,b,d){return c(this,a,b,d)},unbindProperty:function(a,b){return e(this,a,b)},unbindAllProperties:function(){f(this)},shouldObserveProperty:function(a){return Boolean(this[a+i])},dispatchPropertyChange:function(a,c){b.call(this,a+i,[c])}},k=new SideTable,l="[%s] watching [%s]",m="[%s#%s] watch: [%s] now [%s] was [%s]",n="[%s]: bindProperties: [%s] to [%s].[%s]";a.api.instance.properties=j}(Polymer),function(a){var b="__published",c="__instance_attributes",d={PUBLISHED:b,INSTANCE_ATTRIBUTES:c,copyInstanceAttributes:function(){var a=this[c];for(var b in a)this.setAttribute(b,a[b])},takeAttributes:function(){for(var a,b=0,c=this.attributes,d=c.length;(a=c[b])&&d>b;b++)this.attributeToProperty(a.name,a.value)},attributeToProperty:function(b,c){var b=this.propertyForAttribute(b);if(b){if(c.search(a.bindPattern)>=0)return;var d=this[b],c=this.deserializeValue(c,d);c!==d&&(this[b]=c)}},propertyForAttribute:function(a){var c=Object.keys(this[b]);return c[c.map(e).indexOf(a.toLowerCase())]},deserializeValue:function(b,c){return a.deserializeValue(b,c)}},e=String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase);a.api.instance.attributes=d}(Polymer),function(a){function b(a){d(a,c)}function c(a){a.unbindAll()}function d(a,b){if(a){b(a);for(var c=a.firstChild;c;c=c.nextSibling)d(c,b)}}var e=window.logFlags||0,f=new ExpressionSyntax,g={instanceTemplate:function(a){return a.createInstance(this,f)},createBinding:function(a,b,c){var d=this.propertyForAttribute(a);if(d){var e=this.bindProperty(d,b,c);return e.path=c,e}return this.super(arguments)},asyncUnbindAll:function(){this._unbound||(e.unbind&&console.log("[%s] asyncUnbindAll",this.localName),this._unbindAllJob=this.job(this._unbindAllJob,this.unbindAll,0))},unbindAll:function(){this._unbound||(this.unbindAllProperties(),this.super(),b(this.shadowRoot),this._unbound=!0)},cancelUnbindAll:function(a){return this._unbound?(e.unbind&&console.warn("[%s] already unbound, cannot cancel unbindAll",this.localName),void 0):(e.unbind&&console.log("[%s] cancelUnbindAll",this.localName),this._unbindAllJob&&(this._unbindAllJob=this._unbindAllJob.stop()),a||d(this.shadowRoot,function(a){a.cancelUnbindAll&&a.cancelUnbindAll()}),void 0)},insertedCallback:function(){this.cancelUnbindAll(!0),this.inserted&&this.inserted()},removedCallback:function(){this.asyncUnbindAll(),this.removed&&this.removed()}},h=/\{\{([^{}]*)}}/;a.bindPattern=h,a.api.instance.mdv=g}(Polymer),function(a){function b(a){return a.hasOwnProperty("PolymerBase")}function c(){}var d={PolymerBase:!0,job:Polymer.job,"super":Polymer.super,ready:function(){},readyCallback:function(){this.observeProperties(),this.copyInstanceAttributes(),this.takeAttributes(),this.addHostListeners(),this.parseElements(this.__proto__),this.asyncUnbindAll(),this.ready()},parseElements:function(a){a&&a.element&&(this.parseElements(a.__proto__),a.parseElement.call(this,a.element))},parseElement:function(a){this.shadowFromTemplate(this.fetchTemplate(a))},fetchTemplate:function(a){return a.querySelector("template")},shadowFromTemplate:function(a){if(a){var b=this.shadowRoot,c=this.createShadowRoot();c.olderShadowRoot=b,c.applyAuthorStyles=this.applyAuthorStyles,c.resetStyleInheritance=this.resetStyleInheritance,c.host=this;var d=this.instanceTemplate(a);return c.appendChild(d),this.shadowRootReady(c,a),CustomElements.watchShadow(this),c}},shadowRootReady:function(a,b){this.marshalNodeReferences(a),this.addInstanceListeners(a,b),PointerGestures.register(a)},marshalNodeReferences:function(a){var b=this.$=this.$||{};if(a)for(var c,d=a.querySelectorAll("[id]"),e=0,f=d.length;f>e&&(c=d[e]);e++)b[c.id]=c},attributeChangedCallback:function(){this.attributeChanged&&this.attributeChanged.apply(this,arguments)}};c.prototype=d,d.constructor=c,a.Base=c,a.isBase=b,a.api.instance.base=d}(Polymer),function(a){window.logFlags||{};var b="element",c="controller",d={STYLE_SCOPE_ATTRIBUTE:b,installControllerStyles:function(){var a=this.findStyleController();if(a&&!this.scopeHasElementStyle(a,c)){for(var b=Object.getPrototypeOf(this),d="";b&&b.element;)d+=b.element.cssTextForScope(c),b=Object.getPrototypeOf(b);if(d){var e=this.element.cssTextToScopeStyle(d,c);window.ShadowDOMPolyfill&&Platform.ShadowCSS.shimPolyfillDirectives([e],this.localName),Polymer.applyStyleToScope(e,a)}}},scopeHasElementStyle:function(a,c){var d=b+"="+this.localName+"-"+c;return a.querySelector("style["+d+"]")},findStyleController:function(){if(window.ShadowDOMPolyfill)return wrap(document.head);for(var a=this;a.parentNode;)a=a.parentNode;return a===document?document.head:a}};a.api.instance.styles=d}(Polymer),function(a){var b={addResolvePathApi:function(){var a=this.elementPath();this.prototype.resolvePath=function(b){return a+b}},elementPath:function(){return this.urlToPath(HTMLImports.getDocumentUrl(this.ownerDocument))},urlToPath:function(a){if(a){var b=a.split("/");return b.pop(),b.push(""),b.join("/")}return""}};a.api.declaration.path=b}(Polymer),function(a){function b(a,b){if(a){var d=c(a.textContent),e=a.getAttribute(g);e&&d.setAttribute(g,e),b.appendChild(d)}}function c(a){var b=document.createElement("style");return b.textContent=a,b}function d(a){return a&&a.__resource||""}function e(a,b){return n?n.call(a,b):void 0}window.logFlags||{};var f=a.api.instance.styles,g=f.STYLE_SCOPE_ATTRIBUTE,h="style",i="[rel=stylesheet]",j="global",k="polymer-scope",l={installSheets:function(){this.cacheSheets(),this.installLocalSheets(),this.installGlobalStyles()},cacheSheets:function(){this.sheets=this.findNodes(i),this.sheets.forEach(function(a){a.parentNode&&a.parentNode.removeChild(a)})},installLocalSheets:function(){var a=this.sheets.filter(function(a){return!a.hasAttribute(k)}),b=this.templateContent();if(b){var e="";a.forEach(function(a){e+=d(a)+"\n"}),e&&b.insertBefore(c(e),b.firstChild)}},findNodes:function(a,b){var c=this.querySelectorAll(a).array(),d=this.templateContent();if(d){var e=d.querySelectorAll(a).array();c=c.concat(e)}return b?c.filter(b):c},templateContent:function(){var a=this.querySelector("template");return a&&templateContent(a)},installGlobalStyles:function(){var a=this.styleForScope(j);b(a,document.head)},cssTextForScope:function(a){var b="",c="["+k+"="+a+"]",f=function(a){return e(a,c)},g=this.sheets.filter(f);g.forEach(function(a){b+=d(a)+"\n\n"});var i=this.findNodes(h,f);return i.forEach(function(a){a.parentNode.removeChild(a),b+=a.textContent+"\n\n"}),b},styleForScope:function(a){var b=this.cssTextForScope(a);return this.cssTextToScopeStyle(b,a)},cssTextToScopeStyle:function(a,b){if(a){var d=c(a);return d.setAttribute(g,this.getAttribute("name")+"-"+b),d}}},m=HTMLElement.prototype,n=m.matches||m.matchesSelector||m.webkitMatchesSelector||m.mozMatchesSelector;a.api.declaration.styles=l,a.applyStyleToScope=b}(Polymer),function(a){function b(a){return a.slice(0,k)==g}function c(a){return a.slice(k)}function d(a){return a.ref?a.ref.content:a.content}var e=a.api.instance.events,f=e.DELEGATES,g=e.EVENT_PREFIX,h=window.logFlags||{},i={inheritDelegates:function(a){this.inheritObject(a,f)},parseHostEvents:function(){var a=this.prototype[f];this.addAttributeDelegates(a)},addAttributeDelegates:function(a){for(var d,e=0;d=this.attributes[e];e++)b(d.name)&&(a[c(d.name)]=d.value)},parseLocalEvents:function(){this.querySelectorAll("template").forEach(function(a){a.delegates={},this.accumulateTemplatedEvents(a,a.delegates),h.events&&console.log("[%s] parseLocalEvents:",this.attributes.name.value,a.delegates)},this)},accumulateTemplatedEvents:function(a,b){if("template"===a.localName){var c=d(a);c&&this.accumulateChildEvents(c,b)}},accumulateChildEvents:function(a,b){a.childNodes.forEach(function(a){this.accumulateEvents(a,b)},this)},accumulateEvents:function(a,b){return this.accumulateAttributeEvents(a,b),this.accumulateChildEvents(a,b),this.accumulateTemplatedEvents(a,b),b},accumulateAttributeEvents:function(a,d){a.attributes&&a.attributes.forEach(function(a){b(a.name)&&this.accumulateEvent(c(a.name),d)},this)},accumulateEvent:function(a,b){a=j[a]||a,b[a]=b[a]||1}},j={webkitanimationstart:"webkitAnimationStart",webkitanimationend:"webkitAnimationEnd",webkittransitionend:"webkitTransitionEnd",domfocusout:"DOMFocusOut",domfocusin:"DOMFocusIn"},k=g.length;i.event_translations=j,a.api.declaration.events=i}(Polymer),function(a){var b=[],c={cacheProperties:function(){this.prototype.customPropertyNames=this.getCustomPropertyNames(this.prototype)},getCustomPropertyNames:function(c){for(var d,e={};c&&!a.isBase(c);){for(var f,g=Object.getOwnPropertyNames(c),h=0,i=g.length;i>h&&(f=g[h]);h++)e[f]=!0,d=!0;c=c.__proto__}return d?Object.keys(e):b}};a.api.declaration.properties=c}(Polymer),function(a){var b=a.api.instance.attributes,c=b.PUBLISHED,d=b.INSTANCE_ATTRIBUTES,e="publish",f="attributes",g={inheritAttributesObjects:function(a){this.inheritObject(a,c),this.inheritObject(a,d)},parseAttributes:function(){this.publishAttributes(this.prototype),this.publishProperties(this.prototype),this.accumulateInstanceAttributes()},publishAttributes:function(a){var b=a[c],d=this.getAttribute(f);if(d){var e=d.split(d.indexOf(",")>=0?",":" ");e.forEach(function(a){a=a.trim(),!a||a in b||(b[a]=null)})}Object.keys(b).forEach(function(c){c in a||(a[c]=b[c])})},publishProperties:function(a){this.publishPublish(a)},publishPublish:function(a){if(a.hasOwnProperty(e)){var b=a[e];b&&(Object.keys(b).forEach(function(c){a[c]=b[c]}),Platform.mixin(a[c],b))}},accumulateInstanceAttributes:function(){var a=this.prototype[d];this.attributes.forEach(function(b){this.isInstanceAttribute(b.name)&&(a[b.name]=b.value)},this)},isInstanceAttribute:function(a){return!this.blackList[a]&&"on-"!==a.slice(0,3)},blackList:{name:1,"extends":1,constructor:1}};g.blackList[f]=1,a.api.declaration.attributes=g}(Polymer),function(a){function b(a,b){f[a]=b}function c(a){return Object.create(HTMLElement.getPrototypeForTag(a))}var d=Polymer.extend,e=a.api.declaration,f={},g=c();d(g,{readyCallback:function(){var a=this.getAttribute("name"),b=this.getAttribute("extends");this.prototype=this.generateCustomPrototype(a,b),this.prototype.element=this,this.addResolvePathApi(),this.desugar(),window.ShadowDOMPolyfill&&Platform.ShadowCSS.shimStyling(this.templateContent(),a,b),this.register(a),this.publishConstructor()},desugar:function(){this.parseAttributes(),this.parseHostEvents(),this.parseLocalEvents(),this.installSheets(),this.prototype.registerCallback&&this.prototype.registerCallback(this),this.cacheProperties()},generateCustomPrototype:function(a,b){var c=this.generateBasePrototype(b);return this.addNamedApi(c,a)},generateBasePrototype:function(a){var b=c(a);return this.ensureBaseApi(b)},ensureBaseApi:function(b){return b.PolymerBase||(Object.keys(a.api.instance).forEach(function(c){d(b,a.api.instance[c])}),b=Object.create(b)),this.inheritAttributesObjects(b),this.inheritDelegates(b),b},addNamedApi:function(a,b){return d(a,f[b])},inheritObject:function(a,b){a[b]=d({},a.__proto__[b])},register:function(a){this.ctor=document.register(a,{prototype:this.prototype}),this.prototype.constructor=this.ctor,HTMLElement.register(a,this.prototype)},publishConstructor:function(){var a=this.getAttribute("constructor");a&&(window[a]=this.ctor)}}),Object.keys(e).forEach(function(a){d(g,e[a])}),document.register("polymer-element",{prototype:g}),d(b,window.Polymer),window.Polymer=b}(Polymer);
+
+// @version 0.0.20130815
+function PointerGestureEvent(a,b){var c=b||{},d=document.createEvent("Event"),e={bubbles:!0,cancelable:!0};return Object.keys(e).forEach(function(a){a in c&&(e[a]=c[a])}),d.initEvent(a,e.bubbles,e.cancelable),Object.keys(c).forEach(function(a){d[a]=b[a]}),d.preventTap=this.preventTap,d}if(window.Platform=window.Platform||{},window.logFlags=window.logFlags||{},function(a){var b=a.flags||{};location.search.slice(1).split("&").forEach(function(a){a=a.split("="),a[0]&&(b[a[0]]=a[1]||!0)}),b.shadow=(b.shadowdom||b.shadow||b.polyfill||!HTMLElement.prototype.webkitCreateShadowRoot)&&"polyfill",a.flags=b}(Platform),"polyfill"===Platform.flags.shadow){var SideTable;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},SideTable.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}();var ShadowDOMPolyfill={};!function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function d(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){switch(c){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":return}Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function e(a){var b=a.__proto__||Object.getPrototypeOf(a),c=z.get(b);if(c)return c;var d=e(b),f=n(d);return k(b,f,a),f}function f(a,b){i(a,b,!0)}function g(a,b){i(b,a,!1)}function h(a){return/^on[a-z]+$/.test(a)}function i(b,c,d){Object.getOwnPropertyNames(b).forEach(function(e){if(!(e in c)){C&&b.__lookupGetter__(e);var f;try{f=Object.getOwnPropertyDescriptor(b,e)}catch(g){f=D}var i,j;if(d&&"function"==typeof f.value)return c[e]=function(){return this.impl[e].apply(this.impl,arguments)},void 0;var k=h(e);i=k?a.getEventHandlerGetter(e):function(){return this.impl[e]},(f.writable||f.set)&&(j=k?a.getEventHandlerSetter(e):function(a){this.impl[e]=a}),Object.defineProperty(c,e,{get:i,set:j,configurable:f.configurable,enumerable:f.enumerable})}})}function j(a,b,c){var e=a.prototype;k(e,b,c),d(b,a)}function k(a,c,d){var e=c.prototype;b(void 0===z.get(a)),z.set(a,c),A.set(e,a),f(a,e),d&&g(e,d)}function l(a,b){return z.get(b.prototype)===a}function m(a){var b=Object.getPrototypeOf(a),c=e(b),d=n(c);return k(b,d,a),d}function n(a){function b(b){a.call(this,b)}return b.prototype=Object.create(a.prototype),b.prototype.constructor=b,b}function o(a){return a instanceof B.EventTarget||a instanceof B.Event||a instanceof B.Range||a instanceof B.DOMImplementation}function p(a){return a instanceof G||a instanceof F||a instanceof H||a instanceof I||a instanceof E}function q(a){if(null===a)return null;b(p(a));var c=y.get(a);if(!c){var d=e(a);c=new d(a),y.set(a,c)}return c}function r(a){return null===a?null:(b(o(a)),a.impl)}function s(a){return a&&o(a)?r(a):a}function t(a){return a&&!o(a)?q(a):a}function u(a,c){null!==c&&(b(p(a)),b(void 0===c||o(c)),y.set(a,c))}function v(a,b,c){Object.defineProperty(a.prototype,b,{get:c,configurable:!0,enumerable:!0})}function w(a,b){v(a,b,function(){return q(this.impl[b])})}function x(a,b){a.forEach(function(a){b.forEach(function(b){a.prototype[b]=function(){var a=q(this);return a[b].apply(a,arguments)}})})}var y=new SideTable,z=new SideTable,A=new SideTable,B=Object.create(null);Object.getOwnPropertyNames(window);var C=/Firefox/.test(navigator.userAgent),D={get:function(){},set:function(){},configurable:!0,enumerable:!0},E=DOMImplementation,F=Event,G=Node,H=Window,I=Range;a.assert=b,a.constructorTable=z,a.defineGetter=v,a.defineWrapGetter=w,a.forwardMethodsToWrapper=x,a.isWrapperFor=l,a.mixin=c,a.nativePrototypeTable=A,a.registerObject=m,a.registerWrapper=j,a.rewrap=u,a.unwrap=r,a.unwrapIfNeeded=s,a.wrap=q,a.wrapIfNeeded=t,a.wrappers=B}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){return a instanceof N.ShadowRoot}function c(a){var b=a.localName;return"content"===b||"shadow"===b}function d(a){return!!a.shadowRoot}function e(a){var b;return a.parentNode||(b=a.defaultView)&&M(b)||null}function f(f,g,h){if(h.length)return h.shift();if(b(f))return j(f)||a.getHostForShadowRoot(f);var i=a.eventParentsTable.get(f);if(i){for(var k=1;k<i.length;k++)h[k-1]=i[k];return i[0]}if(g&&c(f)){var l=f.parentNode;if(l&&d(l))for(var m=a.getShadowTrees(l),n=j(g),k=0;k<m.length;k++)if(m[k].contains(n))return n}return e(f)}function g(a){for(var d=[],e=a,g=[],i=[];e;){var j=null;if(c(e)){j=h(d);var k=d[d.length-1]||e;d.push(k)}else d.length||d.push(e);var l=d[d.length-1];g.push({target:l,currentTarget:e}),b(e)&&d.pop(),e=f(e,j,i)}return g}function h(a){for(var b=a.length-1;b>=0;b--)if(!c(a[b]))return a[b];return null}function i(d,e){for(var g=[];d;){for(var i=[],j=e,l=void 0;j;){var n=null;if(i.length){if(c(j)&&(n=h(i),k(l))){var o=i[i.length-1];i.push(o)}}else i.push(j);if(m(j,d))return i[i.length-1];b(j)&&i.pop(),l=j,j=f(j,n,g)}d=b(d)?a.getHostForShadowRoot(d):d.parentNode}}function j(b){return a.insertionParentTable.get(b)}function k(a){return j(a)}function l(a){for(var b;b=a.parentNode;)a=b;return a}function m(a,b){return l(a)===l(b)}function n(b,c){if(b===c)return!0;if(b instanceof N.ShadowRoot){var d=a.getHostForShadowRoot(b);return d?n(l(d),c):!1}return!1}function o(a){switch(a){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function p(b){if(!P.get(b)){P.set(b,!0),o(b.type)||a.renderAllPending();var c=M(b.target),d=M(b);return q(d,c)}}function q(a,b){var c=g(b);return"load"===a.type&&2===c.length&&c[0].target instanceof N.Document&&c.shift(),X.set(a,c),r(a,c)&&s(a,c)&&t(a,c),T.set(a,w.NONE),R.set(a,null),a.defaultPrevented}function r(a,b){for(var c,d=b.length-1;d>0;d--){var e=b[d].target,f=b[d].currentTarget;if(e!==f&&(c=w.CAPTURING_PHASE,!u(b[d],a,c)))return!1}return!0}function s(a,b){var c=w.AT_TARGET;return u(b[0],a,c)}function t(a,b){for(var c,d=a.bubbles,e=1;e<b.length;e++){var f=b[e].target,g=b[e].currentTarget;if(f===g)c=w.AT_TARGET;else{if(!d||V.get(a))continue;c=w.BUBBLING_PHASE}if(!u(b[e],a,c))return}}function u(a,b,c){var d=a.target,e=a.currentTarget,f=O.get(e);if(!f)return!0;if("relatedTarget"in b){var g=L(b),h=M(g.relatedTarget),j=i(e,h);if(j===d)return!0;S.set(b,j)}T.set(b,c);var k=b.type,l=!1;Q.set(b,d),R.set(b,e);for(var m=0;m<f.length;m++){var n=f[m];if(n.removed)l=!0;else if(!(n.type!==k||!n.capture&&c===w.CAPTURING_PHASE||n.capture&&c===w.BUBBLING_PHASE))try{if("function"==typeof n.handler?n.handler.call(e,b):n.handler.handleEvent(b),V.get(b))return!1}catch(o){window.onerror?window.onerror(o.message):console.error(o)}}if(l){var p=f.slice();f.length=0;for(var m=0;m<p.length;m++)p[m].removed||f.push(p[m])}return!U.get(b)}function v(a,b,c){this.type=a,this.handler=b,this.capture=Boolean(c)}function w(a,b){return a instanceof Y?(this.impl=a,void 0):M(A(Y,"Event",a,b))}function x(a){return a&&a.relatedTarget?Object.create(a,{relatedTarget:{value:L(a.relatedTarget)}}):a}function y(a,b,c){var d=window[a],e=function(b,c){return b instanceof d?(this.impl=b,void 0):M(A(d,a,b,c))};return e.prototype=Object.create(b.prototype),c&&J(e.prototype,c),d&&(d.prototype["init"+a]?K(d,e,document.createEvent(a)):K(d,e,new d("temp"))),e}function z(a,b){return function(){arguments[b]=L(arguments[b]);var c=L(this);c[a].apply(c,arguments)}}function A(a,b,c,d){if(gb)return new a(c,x(d));var e=L(document.createEvent(b)),f=fb[b],g=[c];return Object.keys(f).forEach(function(a){var b=null!=d&&a in d?d[a]:f[a];"relatedTarget"===a&&(b=L(b)),g.push(b)}),e["init"+b].apply(e,g),e}function B(a){return"function"==typeof a?!0:a&&a.handleEvent}function C(a){this.impl=a}function D(b){return b instanceof N.ShadowRoot&&(b=a.getHostForShadowRoot(b)),L(b)}function E(a){I(a,jb)}function F(b,c,d,e){a.renderAllPending();for(var f=M(kb.call(c.impl,d,e)),h=g(f,this),i=0;i<h.length;i++){var j=h[i];if(j.currentTarget===b)return j.target}return null}function G(a){return function(){var b=W.get(this);return b&&b[a]&&b[a].value||null}}function H(a){var b=a.slice(2);return function(c){var d=W.get(this);d||(d=Object.create(null),W.set(this,d));var e=d[a];if(e&&this.removeEventListener(b,e.wrapped,!1),"function"==typeof c){var f=function(b){var d=c.call(this,b);d===!1?b.preventDefault():"onbeforeunload"===a&&"string"==typeof d&&(b.returnValue=d)};this.addEventListener(b,f,!1),d[a]={value:c,wrapped:f}}}}var I=a.forwardMethodsToWrapper,J=a.mixin,K=a.registerWrapper,L=a.unwrap,M=a.wrap,N=a.wrappers;new SideTable;var O=new SideTable,P=new SideTable,Q=new SideTable,R=new SideTable,S=new SideTable,T=new SideTable,U=new SideTable,V=new SideTable,W=new SideTable,X=new SideTable;v.prototype={equals:function(a){return this.handler===a.handler&&this.type===a.type&&this.capture===a.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var Y=window.Event;w.prototype={get target(){return Q.get(this)},get currentTarget(){return R.get(this)},get eventPhase(){return T.get(this)},get path(){var a=new N.NodeList,b=X.get(this);if(b){for(var c=0,d=b.length-1,e=l(R.get(this)),f=0;d>=f;f++){var g=b[f].currentTarget,h=l(g);n(e,h)&&(f!==d||g instanceof N.Node)&&(a[c++]=g)}a.length=c}return a},stopPropagation:function(){U.set(this,!0)},stopImmediatePropagation:function(){U.set(this,!0),V.set(this,!0)}},K(Y,w,document.createEvent("Event"));var Z=y("UIEvent",w),$=y("CustomEvent",w),_={get relatedTarget(){return S.get(this)||M(L(this).relatedTarget)}},ab=J({initMouseEvent:z("initMouseEvent",14)},_),bb=J({initFocusEvent:z("initFocusEvent",5)},_),cb=y("MouseEvent",Z,ab),db=y("FocusEvent",Z,bb),eb=y("MutationEvent",w,{initMutationEvent:z("initMutationEvent",3),get relatedNode(){return M(this.impl.relatedNode)}}),fb=Object.create(null),gb=function(){try{new window.MouseEvent("click")}catch(a){return!1}return!0}();if(!gb){var hb=function(a,b,c){if(c){var d=fb[c];b=J(J({},d),b)}fb[a]=b};hb("Event",{bubbles:!1,cancelable:!1}),hb("CustomEvent",{detail:null},"Event"),hb("UIEvent",{view:null,detail:0},"Event"),hb("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),hb("FocusEvent",{relatedTarget:null},"UIEvent")}var ib=window.EventTarget,jb=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(a){var b=a.prototype;jb.forEach(function(a){Object.defineProperty(b,a+"_",{value:b[a]})})}),C.prototype={addEventListener:function(a,b,c){if(B(b)){var d=new v(a,b,c),e=O.get(this);if(e){for(var f=0;f<e.length;f++)if(d.equals(e[f]))return}else e=[],O.set(this,e);e.push(d);var g=D(this);g.addEventListener_(a,p,!0)}},removeEventListener:function(a,b,c){c=Boolean(c);var d=O.get(this);if(d){for(var e=0,f=!1,g=0;g<d.length;g++)d[g].type===a&&d[g].capture===c&&(e++,d[g].handler===b&&(f=!0,d[g].remove()));if(f&&1===e){var h=D(this);h.removeEventListener_(a,p,!0)}}},dispatchEvent:function(a){var b=D(this);return b.dispatchEvent_(L(a))}},ib&&K(ib,C);var kb=document.elementFromPoint;a.adjustRelatedTarget=i,a.elementFromPoint=F,a.getEventHandlerGetter=G,a.getEventHandlerSetter=H,a.wrapEventTargetMethods=E,a.wrappers.CustomEvent=$,a.wrappers.Event=w,a.wrappers.EventTarget=C,a.wrappers.FocusEvent=db,a.wrappers.MouseEvent=cb,a.wrappers.MutationEvent=eb,a.wrappers.UIEvent=Z}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,b){Object.defineProperty(a,b,{enumerable:!1})}function c(){this.length=0,b(this,"length")}function d(a){if(null==a)return a;for(var b=new c,d=0,e=a.length;e>d;d++)b[d]=f(a[d]);return b.length=e,b}function e(a,b){a.prototype[b]=function(){return d(this.impl[b].apply(this.impl,arguments))}}var f=a.wrap;c.prototype={item:function(a){return this[a]}},b(c.prototype,"item"),a.wrappers.NodeList=c,a.addWrapNodeListMethod=e,a.wrapNodeList=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){j(a instanceof f)}function c(a,b,c,d){if(a.nodeType!==f.DOCUMENT_FRAGMENT_NODE)return a.parentNode&&a.parentNode.removeChild(a),a.parentNode_=b,a.previousSibling_=c,a.nextSibling_=d,c&&(c.nextSibling_=a),d&&(d.previousSibling_=a),[a];for(var e,g=[];e=a.firstChild;)a.removeChild(e),g.push(e),e.parentNode_=b;for(var h=0;h<g.length;h++)g[h].previousSibling_=g[h-1]||c,g[h].nextSibling_=g[h+1]||d;return c&&(c.nextSibling_=g[0]),d&&(d.previousSibling_=g[g.length-1]),g}function d(a,b){var c=b.length;if(1===c)return m(b[0]);for(var d=m(a.ownerDocument.createDocumentFragment()),e=0;c>e;e++)d.appendChild(m(b[e]));return d}function e(a){for(var b=a.firstChild;b;){j(b.parentNode===a);var c=b.nextSibling,d=m(b),e=d.parentNode;e&&t.call(e,d),b.previousSibling_=b.nextSibling_=b.parentNode_=null,b=c}a.firstChild_=a.lastChild_=null}function f(a){j(a instanceof p),g.call(this,a),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0}var g=a.wrappers.EventTarget,h=a.wrappers.NodeList,i=a.defineWrapGetter,j=a.assert,k=a.mixin,l=a.registerWrapper,m=a.unwrap,n=a.wrap,o=a.wrapIfNeeded,p=window.Node,q=p.prototype.appendChild,r=p.prototype.insertBefore,s=p.prototype.replaceChild,t=p.prototype.removeChild,u=p.prototype.compareDocumentPosition;f.prototype=Object.create(g.prototype),k(f.prototype,{appendChild:function(a){b(a),this.invalidateShadowRenderer();var e=this.lastChild,f=null,g=c(a,this,e,f);return this.lastChild_=g[g.length-1],e||(this.firstChild_=g[0]),q.call(this.impl,d(this,g)),a},insertBefore:function(a,e){if(!e)return this.appendChild(a);b(a),b(e),j(e.parentNode===this),this.invalidateShadowRenderer();var f=e.previousSibling,g=e,h=c(a,this,f,g);this.firstChild===e&&(this.firstChild_=h[0]);var i=m(e),k=i.parentNode;return k&&r.call(k,d(this,h),i),a},removeChild:function(a){if(b(a),a.parentNode!==this)throw new Error("NotFoundError");this.invalidateShadowRenderer();var c=this.firstChild,d=this.lastChild,e=a.nextSibling,f=a.previousSibling,g=m(a),h=g.parentNode;return h&&t.call(h,g),c===a&&(this.firstChild_=e),d===a&&(this.lastChild_=f),f&&(f.nextSibling_=e),e&&(e.previousSibling_=f),a.previousSibling_=a.nextSibling_=a.parentNode_=null,a},replaceChild:function(a,e){if(b(a),b(e),e.parentNode!==this)throw new Error("NotFoundError");this.invalidateShadowRenderer();var f=e.previousSibling,g=e.nextSibling;g===a&&(g=a.nextSibling);var h=c(a,this,f,g);this.firstChild===e&&(this.firstChild_=h[0]),this.lastChild===e&&(this.lastChild_=h[h.length-1]),e.previousSibling_=null,e.nextSibling_=null,e.parentNode_=null;var i=m(e);return i.parentNode&&s.call(i.parentNode,d(this,h),i),e},hasChildNodes:function(){return null===this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:n(this.impl.parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:n(this.impl.firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:n(this.impl.lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:n(this.impl.nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:n(this.impl.previousSibling)},get parentElement(){for(var a=this.parentNode;a&&a.nodeType!==f.ELEMENT_NODE;)a=a.parentNode;return a},get textContent(){for(var a="",b=this.firstChild;b;b=b.nextSibling)a+=b.textContent;return a},set textContent(a){if(e(this),this.invalidateShadowRenderer(),""!==a){var b=this.impl.ownerDocument.createTextNode(a);this.appendChild(b)}},get childNodes(){for(var a=new h,b=0,c=this.firstChild;c;c=c.nextSibling)a[b++]=c;return a.length=b,a},cloneNode:function(a){if(!this.invalidateShadowRenderer())return n(this.impl.cloneNode(a));var b=n(this.impl.cloneNode(!1));if(a)for(var c=this.firstChild;c;c=c.nextSibling)b.appendChild(c.cloneNode(!0));return b},contains:function(a){if(!a)return!1;if(a=o(a),a===this)return!0;var b=a.parentNode;return b?this.contains(b):!1},compareDocumentPosition:function(a){return u.call(this.impl,m(a))}}),i(f,"ownerDocument"),l(p,f,document.createDocumentFragment()),delete f.prototype.querySelector,delete f.prototype.querySelectorAll,f.prototype=k(Object.create(g.prototype),f.prototype),a.wrappers.Node=f}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,c){for(var d,e=a.firstElementChild;e;){if(e.matches(c))return e;if(d=b(e,c))return d;e=e.nextElementSibling}return null}function c(a,b,d){for(var e=a.firstElementChild;e;)e.matches(b)&&(d[d.length++]=e),c(e,b,d),e=e.nextElementSibling;return d}var d={querySelector:function(a){return b(this,a)},querySelectorAll:function(a){return c(this,a,new NodeList)}},e={getElementsByTagName:function(a){return this.querySelectorAll(a)},getElementsByClassName:function(a){return this.querySelectorAll("."+a)},getElementsByTagNameNS:function(a,b){if("*"===a)return this.getElementsByTagName(b);for(var c=new NodeList,d=this.getElementsByTagName(b),e=0,f=0;e<d.length;e++)d[e].namespaceURI===a&&(c[f++]=d[e]);return c.length=f,c}};a.GetElementsByInterface=e,a.SelectorsInterface=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}function c(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}var d=a.wrappers.NodeList,e={get firstElementChild(){return b(this.firstChild)},get lastElementChild(){return c(this.lastChild)},get childElementCount(){for(var a=0,b=this.firstElementChild;b;b=b.nextElementSibling)a++;return a},get children(){for(var a=new d,b=0,c=this.firstElementChild;c;c=c.nextElementSibling)a[b++]=c;return a.length=b,a}},f={get nextElementSibling(){return b(this.nextSibling)},get previousElementSibling(){return c(this.previousSibling)}};a.ChildNodeInterface=f,a.ParentNodeInterface=e}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){d.call(this,a)}var c=a.ChildNodeInterface,d=a.wrappers.Node,e=a.mixin,f=a.registerWrapper,g=window.CharacterData;b.prototype=Object.create(d.prototype),e(b.prototype,{get textContent(){return this.data},set textContent(a){this.data=a}}),e(b.prototype,c),f(g,b,document.createTextNode("")),a.wrappers.CharacterData=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(b,c){var d=b.parentNode;if(d){var e=a.getRendererForHost(d);e&&e.dependsOnAttribute(c)&&e.invalidate()}}function c(a){g.call(this,a)}function d(a,c,d){var e=d||c;Object.defineProperty(a,c,{get:function(){return this.impl[c]},set:function(a){this.impl[c]=a,b(this,e)},configurable:!0,enumerable:!0})}var e=a.ChildNodeInterface,f=a.GetElementsByInterface,g=a.wrappers.Node,h=a.ParentNodeInterface,i=a.SelectorsInterface;a.addWrapNodeListMethod;var j=a.mixin,k=a.registerWrapper,l=a.wrappers,m=new SideTable,n=window.Element,o=n.prototype.matches||n.prototype.mozMatchesSelector||n.prototype.msMatchesSelector||n.prototype.webkitMatchesSelector;c.prototype=Object.create(g.prototype),j(c.prototype,{createShadowRoot:function(){var b=new l.ShadowRoot(this);return m.set(this,b),a.getRendererForHost(this),this.invalidateShadowRenderer(!0),b},get shadowRoot(){return m.get(this)||null},setAttribute:function(a,c){this.impl.setAttribute(a,c),b(this,a)},removeAttribute:function(a){this.impl.removeAttribute(a),b(this,a)},matches:function(a){return o.call(this.impl,a)}}),n.prototype.webkitCreateShadowRoot&&(c.prototype.webkitCreateShadowRoot=c.prototype.createShadowRoot),d(c.prototype,"id"),d(c.prototype,"className","class"),j(c.prototype,e),j(c.prototype,f),j(c.prototype,h),j(c.prototype,i),k(n,c),a.wrappers.Element=c}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a){case"&":return"&amp;";case"<":return"&lt;";case'"':return"&quot;"}}function c(a){return a.replace(p,b)}function d(a){switch(a.nodeType){case Node.ELEMENT_NODE:for(var b,d=a.tagName.toLowerCase(),f="<"+d,g=a.attributes,h=0;b=g[h];h++)f+=" "+b.name+'="'+c(b.value)+'"';return f+=">",q[d]?f:f+e(a)+"</"+d+">";case Node.TEXT_NODE:return c(a.nodeValue);case Node.COMMENT_NODE:return"<!--"+c(a.nodeValue)+"-->";default:throw console.error(a),new Error("not implemented")}}function e(a){for(var b="",c=a.firstChild;c;c=c.nextSibling)b+=d(c);return b}function f(a,b,c){var d=c||"div";a.textContent="";var e=n(a.ownerDocument.createElement(d));e.innerHTML=b;for(var f;f=e.firstChild;)a.appendChild(o(f))}function g(a){j.call(this,a)}function h(b){k(g,b,function(){return a.renderAllPending(),this.impl[b]})}function i(b){Object.defineProperty(g.prototype,b,{value:function(){return a.renderAllPending(),this.impl[b].apply(this.impl,arguments)},configurable:!0,enumerable:!0})}var j=a.wrappers.Element,k=a.defineGetter,l=a.mixin,m=a.registerWrapper,n=a.unwrap,o=a.wrap,p=/&|<|"/g,q={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},r=window.HTMLElement;g.prototype=Object.create(j.prototype),l(g.prototype,{get innerHTML(){return e(this)},set innerHTML(a){f(this,a,this.tagName)},get outerHTML(){return d(this)},set outerHTML(a){if(this.invalidateShadowRenderer())throw new Error("not implemented");this.impl.outerHTML=a}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollLeft","scrollTop","scrollWidth"].forEach(h),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(i),m(r,g,document.createElement("b")),a.wrappers.HTMLElement=g,a.getInnerHTML=e,a.setInnerHTML=f}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLContentElement;b.prototype=Object.create(c.prototype),d(b.prototype,{get select(){return this.getAttribute("select")},set select(a){this.setAttribute("select",a)},setAttribute:function(a,b){c.prototype.setAttribute.call(this,a,b),"select"===String(a).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),f&&e(f,b),a.wrappers.HTMLContentElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLShadowElement;b.prototype=Object.create(c.prototype),d(b.prototype,{invalidateShadowRenderer:function(){c.prototype.invalidateShadowRenderer.call(this,!0)}}),f&&e(f,b),a.wrappers.HTMLShadowElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){if(!a.defaultView)return a;var b=l.get(a);if(!b){for(b=a.implementation.createHTMLDocument("");b.lastChild;)b.removeChild(b.lastChild);l.set(a,b)}return b}function c(a){for(var c,d=b(a.ownerDocument),e=d.createDocumentFragment();c=a.firstChild;)e.appendChild(c);return e}function d(a){e.call(this,a)}var e=a.wrappers.HTMLElement,f=a.getInnerHTML,g=a.mixin,h=a.registerWrapper,i=a.setInnerHTML,j=a.wrap,k=new SideTable,l=new SideTable,m=window.HTMLTemplateElement;d.prototype=Object.create(e.prototype),g(d.prototype,{get content(){if(m)return j(this.impl.content);var a=k.get(this);return a||(a=c(this),k.set(this,a)),a},get innerHTML(){return f(this.content)},set innerHTML(a){i(this.content,a),this.invalidateShadowRenderer()}}),m&&h(m,d),a.wrappers.HTMLTemplateElement=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a.localName){case"content":return new c(a);case"shadow":return new e(a);case"template":return new f(a)}d.call(this,a)}var c=a.wrappers.HTMLContentElement,d=a.wrappers.HTMLElement,e=a.wrappers.HTMLShadowElement,f=a.wrappers.HTMLTemplateElement;a.mixin;var g=a.registerWrapper,h=window.HTMLUnknownElement;b.prototype=Object.create(d.prototype),g(h,b),a.wrappers.HTMLUnknownElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";var b=a.GetElementsByInterface,c=a.ParentNodeInterface,d=a.SelectorsInterface,e=a.mixin,f=a.registerObject,g=f(document.createDocumentFragment());e(g.prototype,c),e(g.prototype,d),e(g.prototype,b);var h=f(document.createTextNode("")),i=f(document.createComment(""));a.wrappers.Comment=i,a.wrappers.DocumentFragment=g,a.wrappers.Text=h}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=i(a.impl.ownerDocument.createDocumentFragment());c.call(this,b),g(b,this);var d=a.shadowRoot;k.set(this,d),j.set(this,a)}var c=a.wrappers.DocumentFragment,d=a.elementFromPoint,e=a.getInnerHTML,f=a.mixin,g=a.rewrap,h=a.setInnerHTML,i=a.unwrap,j=new SideTable,k=new SideTable;b.prototype=Object.create(c.prototype),f(b.prototype,{get innerHTML(){return e(this)},set innerHTML(a){h(this,a),this.invalidateShadowRenderer()},get olderShadowRoot(){return k.get(this)||null},invalidateShadowRenderer:function(){return j.get(this).invalidateShadowRenderer()},elementFromPoint:function(a,b){return d(this,this.ownerDocument,a,b)},getElementById:function(a){return this.querySelector("#"+a)}}),a.wrappers.ShadowRoot=b,a.getHostForShadowRoot=function(a){return j.get(a)}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){a.previousSibling_=a.previousSibling,a.nextSibling_=a.nextSibling,a.parentNode_=a.parentNode}function c(a){a.firstChild_=a.firstChild,a.lastChild_=a.lastChild}function d(a){C(a instanceof B);for(var d=a.firstChild;d;d=d.nextSibling)b(d);c(a)}function e(a){var b=E(a);d(a),b.textContent=""}function f(a,c){var e=E(a),f=E(c);f.nodeType===B.DOCUMENT_FRAGMENT_NODE?d(c):(h(c),b(c)),a.lastChild_=a.lastChild,a.lastChild===a.firstChild&&(a.firstChild_=a.firstChild);var g=F(e.lastChild);g&&(g.nextSibling_=g.nextSibling),e.appendChild(f)}function g(a,c){var d=E(a),e=E(c);b(c),c.previousSibling&&(c.previousSibling.nextSibling_=c),c.nextSibling&&(c.nextSibling.previousSibling_=c),a.lastChild===c&&(a.lastChild_=c),a.firstChild===c&&(a.firstChild_=c),d.removeChild(e)}function h(a){var b=E(a),c=b.parentNode;c&&g(F(c),a)}function i(a,b){k(b).push(a),y(a,b);var c=H.get(a);c||H.set(a,c=[]),c.push(b)}function j(a){G.set(a,[])}function k(a){return G.get(a)}function l(a){for(var b=[],c=0,d=a.firstChild;d;d=d.nextSibling)b[c++]=d;return b}function m(a,b,c){for(var d=l(a),e=0;e<d.length;e++){var f=d[e];if(b(f)){if(c(f)===!1)return}else m(f,b,c)}}function n(a,b){for(var c=0;c<b.length;c++)if(b[c]in a)return b[c]}function o(a,b){var c=b.getAttribute("select");if(!c)return!0;if(c=c.trim(),!c)return!0;if(a.nodeType!==B.ELEMENT_NODE)return!1;if(!L.test(c))return!1;if(":"===c[0]&&!M.test(c))return!1;try{return a.matches(c)}catch(d){return!1}}function p(){D=null,O.forEach(function(a){a.render()}),O=[]}function q(a){this.host=a,this.dirty=!1,this.invalidateAttributes(),this.associateNode(a)}function r(a){var b=J.get(a);return b||(b=new q(a),J.set(a,b)),b}function s(a){return"content"===a.localName}function t(a){return"content"===a.localName}function u(a){return"shadow"===a.localName}function v(a){return"shadow"===a.localName}function w(a){return!!a.shadowRoot}function x(a){for(var b=[],c=a.shadowRoot;c;c=c.olderShadowRoot)b.push(c);return b}function y(a,b){I.set(a,b)}function z(a){new q(a).render()}var A=a.wrappers.HTMLContentElement,B=a.wrappers.Node,C=a.assert;a.mixin;var D,E=a.unwrap,F=a.wrap,G=new SideTable,H=new SideTable,I=new SideTable,J=new SideTable,K=new SideTable,L=/^[*.:#[a-zA-Z_|]/,M=new RegExp("^:("+["link","visited","target","enabled","disabled","checked","indeterminate","nth-child","nth-last-child","nth-of-type","nth-last-of-type","first-child","last-child","first-of-type","last-of-type","only-of-type"].join("|")+")"),N=n(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),O=[];q.prototype={render:function(){if(this.dirty){this.invalidateAttributes(),this.treeComposition();var a=this.host,b=a.shadowRoot;if(b){this.removeAllChildNodes(this.host);var c=l(b);c.forEach(function(c){this.renderNode(a,b,c,!1)},this),this.dirty=!1}}},invalidate:function(){if(!this.dirty){if(this.dirty=!0,O.push(this),D)return;D=window[N](p,0)}},renderNode:function(a,b,c,d){if(w(c)){this.appendChild(a,c);var e=r(c);e.dirty=!0,e.render()}else s(c)?this.renderInsertionPoint(a,b,c,d):u(c)?this.renderShadowInsertionPoint(a,b,c):this.renderAsAnyDomTree(a,b,c,d)},renderAsAnyDomTree:function(a,b,c,d){if(this.appendChild(a,c),w(c))z(c);else{var e=c,f=l(e);f.forEach(function(a){this.renderNode(e,b,a,d)},this)}},renderInsertionPoint:function(a,b,c,d){var e=k(c);e.length?(this.removeAllChildNodes(c),e.forEach(function(c){s(c)&&d?this.renderInsertionPoint(a,b,c,d):this.renderAsAnyDomTree(a,b,c,d)},this)):this.renderFallbackContent(a,c),this.remove(c)},renderShadowInsertionPoint:function(a,b,c){var d=b.olderShadowRoot;if(d){y(d,c),this.remove(c);var e=l(d);e.forEach(function(b){this.renderNode(a,d,b,!0)},this)}else this.renderFallbackContent(a,c)},renderFallbackContent:function(a,b){var c=l(b);c.forEach(function(b){this.appendChild(a,b)},this)},invalidateAttributes:function(){this.attributes=Object.create(null)},updateDependentAttributes:function(a){if(a){var b=this.attributes;/\.\w+/.test(a)&&(b["class"]=!0),/#\w+/.test(a)&&(b.id=!0),a.replace(/\[\s*([^\s=\|~\]]+)/g,function(a,c){b[c]=!0})}},dependsOnAttribute:function(a){return this.attributes[a]},distribute:function(a,b){var c=!1,d=this;return m(a,t,function(a){j(a),d.updateDependentAttributes(a.getAttribute("select"));for(var e=0;e<b.length;e++){var f=b[e];void 0!==f&&o(f,a)&&(i(f,a),b[e]=void 0,c=!0)}}),c?b.filter(function(a){return void 0!==a}):b},treeComposition:function(){var a=this.host,b=a.shadowRoot,c=[],d=l(a);d.forEach(function(a){if(s(a)){var b=k(a);b&&b.length||(b=l(a)),c.push.apply(c,b)}else c.push(a)});for(var e,f;b;){if(e=void 0,m(b,v,function(a){return e=a,!1}),f=e,c=this.distribute(b,c),f){var g=b.olderShadowRoot;if(g){b=g,y(b,f);continue}break}break}},appendChild:function(a,b){f(a,b),this.associateNode(b)},remove:function(a){h(a),this.associateNode(a)},removeAllChildNodes:function(a){e(a)},associateNode:function(a){K.set(a,this)}},B.prototype.invalidateShadowRenderer=function(a){var b=K.get(this);if(!b)return!1;var c;return(a||this.shadowRoot||(c=this.parentNode)&&(c.shadowRoot||c instanceof ShadowRoot))&&b.invalidate(),!0},A.prototype.getDistributedNodes=function(){return p(),k(this)},a.eventParentsTable=H,a.getRendererForHost=r,a.getShadowTrees=x,a.insertionParentTable=I,a.renderAllPending=p,a.visual={removeAllChildNodes:e,appendChild:f,removeChild:g}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(b){if(window[b]){d(!a.wrappers[b]);var i=function(a){c.call(this,a)};i.prototype=Object.create(c.prototype),e(i.prototype,{get form(){return h(g(this).form)}}),f(window[b],i,document.createElement(b.slice(4,-7))),a.wrappers[b]=i}}var c=a.wrappers.HTMLElement,d=a.assert,e=a.mixin,f=a.registerWrapper,g=a.unwrap,h=a.wrap,i=["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLKeygenElement","HTMLLabelElement","HTMLLegendElement","HTMLObjectElement","HTMLOptionElement","HTMLOutputElement","HTMLSelectElement","HTMLTextAreaElement"];i.forEach(b)}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){j.call(this,a)}function c(a){var c=document[a];b.prototype[a]=function(){return t(c.apply(this.impl,arguments))}}function d(a,b){a.shadowRoot&&b.adoptNode(a.shadowRoot),a instanceof m&&e(a,b);for(var c=a.firstChild;c;c=c.nextSibling)d(c,b)}function e(a,b){var c=a.olderShadowRoot;c&&b.adoptNode(c)}function f(a){this.impl=a}function g(a,b){var c=document.implementation[b];a.prototype[b]=function(){return t(c.apply(this.impl,arguments))}}function h(a,b){var c=document.implementation[b];a.prototype[b]=function(){return c.apply(this.impl,arguments)}}var i=a.GetElementsByInterface,j=a.wrappers.Node,k=a.ParentNodeInterface,l=a.SelectorsInterface,m=a.wrappers.ShadowRoot,n=a.defineWrapGetter,o=a.elementFromPoint,p=a.forwardMethodsToWrapper,q=a.mixin,r=a.registerWrapper,s=a.unwrap,t=a.wrap,u=a.wrapEventTargetMethods;
+a.wrapNodeList;var v=new SideTable;b.prototype=Object.create(j.prototype),n(b,"documentElement"),n(b,"body"),n(b,"head"),["createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","getElementById"].forEach(c);var w=document.adoptNode,x=document.write;if(q(b.prototype,{adoptNode:function(a){return a.parentNode&&a.parentNode.removeChild(a),w.call(this.impl,s(a)),d(a,this),a},elementFromPoint:function(a,b){return o(this,this,a,b)},write:function(a){for(var b=this.querySelectorAll("*"),c=b[b.length-1];c.nextSibling;)c=c.nextSibling;var d=c.parentNode;d.lastChild_=void 0,c.nextSibling_=void 0,x.call(this.impl,a)}}),document.register){var y=document.register;b.prototype.register=function(b,c){function d(a){return a?(this.impl=a,void 0):document.createElement(b)}var e=c.prototype;if(a.nativePrototypeTable.get(e))throw new Error("NotSupportedError");for(var f,g=Object.getPrototypeOf(e),h=[];g&&!(f=a.nativePrototypeTable.get(g));)h.push(g),g=Object.getPrototypeOf(g);if(!f)throw new Error("NotSupportedError");for(var i=Object.create(f),j=h.length-1;j>=0;j--)i=Object.create(i);return["createdCallback","enteredDocumentCallback","leftDocumentCallback","attributeChangedCallback"].forEach(function(a){var b=e[a];b&&(i[a]=function(){b.apply(t(this),arguments)})}),y.call(s(this),b,{prototype:i}),d.prototype=e,d.prototype.constructor=d,a.constructorTable.set(i,d),a.nativePrototypeTable.set(e,i),d},p([window.HTMLDocument||window.Document],["register"])}p([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild"]),p([window.HTMLDocument||window.Document],["adoptNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","elementFromPoint","getElementById","write"]),q(b.prototype,i),q(b.prototype,k),q(b.prototype,l),q(b.prototype,{get implementation(){var a=v.get(this);return a?a:(a=new f(s(this).implementation),v.set(this,a),a)}}),r(window.Document,b,document.implementation.createHTMLDocument("")),window.HTMLDocument&&r(window.HTMLDocument,b),u([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),g(f,"createDocumentType"),g(f,"createDocument"),g(f,"createHTMLDocument"),h(f,"hasFeature"),r(window.DOMImplementation,f),p([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),a.wrappers.Document=b,a.wrappers.DOMImplementation=f}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.EventTarget,d=a.mixin,e=a.registerWrapper,f=a.unwrap,g=a.unwrapIfNeeded,h=a.wrap,i=window.Window;b.prototype=Object.create(c.prototype);var j=window.getComputedStyle;i.prototype.getComputedStyle=function(a,b){return j.call(this||window,g(a),b)},["addEventListener","removeEventListener","dispatchEvent"].forEach(function(a){i.prototype[a]=function(){var b=h(this||window);return b[a].apply(b,arguments)}}),d(b.prototype,{getComputedStyle:function(a,b){return j.call(f(this),g(a),b)}}),e(i,b),a.wrappers.Window=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}function c(a){return new b(a)}function d(a){return a.map(c)}function e(a){var b=this;this.impl=new k(function(c){a.call(b,d(c),b)})}var f=a.defineGetter,g=a.defineWrapGetter,h=a.registerWrapper,i=a.unwrapIfNeeded,j=a.wrapNodeList;a.wrappers;var k=window.MutationObserver||window.WebKitMutationObserver;if(k){var l=window.MutationRecord;b.prototype={get addedNodes(){return j(this.impl.addedNodes)},get removedNodes(){return j(this.impl.removedNodes)}},["target","previousSibling","nextSibling"].forEach(function(a){g(b,a)}),["type","attributeName","attributeNamespace","oldValue"].forEach(function(a){f(b,a,function(){return this.impl[a]})}),l&&h(l,b),window.Node,e.prototype={observe:function(a,b){this.impl.observe(i(a),b)},disconnect:function(){this.impl.disconnect()},takeRecords:function(){return d(this.impl.takeRecords())}},a.wrappers.MutationObserver=e,a.wrappers.MutationRecord=b}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}var c=a.registerWrapper,d=a.unwrap,e=a.unwrapIfNeeded,f=a.wrap;b.prototype={get startContainer(){return f(this.impl.startContainer)},get endContainer(){return f(this.impl.endContainer)},get commonAncestorContainer(){return f(this.impl.commonAncestorContainer)},setStart:function(a,b){this.impl.setStart(e(a),b)},setEnd:function(a,b){this.impl.setEnd(e(a),b)},setStartBefore:function(a){this.impl.setStartBefore(e(a))},setStartAfter:function(a){this.impl.setStartAfter(e(a))},setEndBefore:function(a){this.impl.setEndBefore(e(a))},setEndAfter:function(a){this.impl.setEndAfter(e(a))},selectNode:function(a){this.impl.selectNode(e(a))},selectNodeContents:function(a){this.impl.selectNodeContents(e(a))},compareBoundaryPoints:function(a,b){return this.impl.compareBoundaryPoints(a,d(b))},extractContents:function(){return f(this.impl.extractContents())},cloneContents:function(){return f(this.impl.cloneContents())},insertNode:function(a){this.impl.insertNode(e(a))},surroundContents:function(a){this.impl.surroundContents(e(a))},cloneRange:function(){return f(this.impl.cloneRange())},isPointInRange:function(a,b){return this.impl.isPointInRange(e(a),b)},comparePoint:function(a,b){return this.impl.comparePoint(e(a),b)},intersectsNode:function(a){return this.impl.intersectsNode(e(a))},createContextualFragment:function(a){return f(this.impl.createContextualFragment(a))}},c(window.Range,b),a.wrappers.Range=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=c[a],d=window[b];if(d){var e=document.createElement(a),f=e.constructor;window[b]=f}}a.isWrapperFor;var c={a:"HTMLAnchorElement",applet:"HTMLAppletElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",br:"HTMLBRElement",base:"HTMLBaseElement",body:"HTMLBodyElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",dl:"HTMLDListElement",datalist:"HTMLDataListElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",hr:"HTMLHRElement",head:"HTMLHeadElement",h1:"HTMLHeadingElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",input:"HTMLInputElement",li:"HTMLLIElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",link:"HTMLLinkElement",map:"HTMLMapElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",del:"HTMLModElement",ol:"HTMLOListElement",object:"HTMLObjectElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",table:"HTMLTableElement",tr:"HTMLTableRowElement",thead:"HTMLTableSectionElement",tbody:"HTMLTableSectionElement",textarea:"HTMLTextAreaElement",title:"HTMLTitleElement",ul:"HTMLUListElement",video:"HTMLVideoElement"};Object.keys(c).forEach(b),Object.getOwnPropertyNames(a.wrappers).forEach(function(b){window[b]=a.wrappers[b]}),a.knownElements=c}(this.ShadowDOMPolyfill),function(){window.wrap=function(a){return a.impl?a:ShadowDOMPolyfill.wrap(a)},window.unwrap=function(a){return a.impl?ShadowDOMPolyfill.unwrap(a):a};var a=window.getComputedStyle;window.getComputedStyle=function(b,c){return a.call(window,wrap(b),c)},Object.defineProperties(HTMLElement.prototype,{webkitShadowRoot:{get:function(){return this.shadowRoot}}});var b=HTMLElement.prototype.createShadowRoot;HTMLElement.prototype.createShadowRoot=function(){var a=b.call(this);return a.host=this,a},HTMLElement.prototype.webkitCreateShadowRoot=HTMLElement.prototype.createShadowRoot}(),function(a){function b(a,b){var c="";return Array.prototype.forEach.call(a,function(a){c+=a.textContent+"\n\n"}),b||(c=c.replace(m,"")),c}function c(a){var b=document.createElement("style");b.textContent=a,document.head.appendChild(b);var c=b.sheet.cssRules;return b.parentNode.removeChild(b),c}function d(a){for(var b=0,c=[];b<a.length;b++)c.push(a[b].cssText);return c.join("\n\n")}function e(a){a&&f().appendChild(document.createTextNode(a))}function f(){return g||(g=document.createElement("style"),g.setAttribute("ShadowCSSShim","")),g}var g,h={strictStyling:!1,registry:{},shimStyling:function(a,b,c){if(a){var d=this.registerDefinition(a,b,c);this.strictStyling&&this.applyScopeToContent(a,b),this.shimPolyfillDirectives(d.rootStyles,b),this.applyShimming(d.scopeStyles,b)}},shimShadowDOMStyling:function(a,b){this.shimPolyfillDirectives(a,b),this.applyShimming(a,b)},registerDefinition:function(a,b,c){var d=this.registry[b]={root:a,name:b,extendsName:c},e=a.querySelectorAll("style");e=e?Array.prototype.slice.call(e,0):[],d.rootStyles=e,d.scopeStyles=d.rootStyles;var f=this.registry[d.extendsName];return f&&a.querySelector("shadow")&&(d.scopeStyles=f.scopeStyles.concat(d.scopeStyles)),d},applyScopeToContent:function(a,b){a&&(Array.prototype.forEach.call(a.querySelectorAll("*"),function(a){a.setAttribute(b,"")}),Array.prototype.forEach.call(a.querySelectorAll("template"),function(a){this.applyScopeToContent(a.content,b)},this))},shimPolyfillDirectives:function(a,b){a&&Array.prototype.forEach.call(a,function(a){a.textContent=this.convertPolyfillDirectives(a.textContent,b)},this)},convertPolyfillDirectives:function(a,b){for(var c,d,e="",f=0;c=n.exec(a);)e+=a.substring(f,c.index),d=c[1].slice(0,-2).replace(q,b),e+=this.scopeSelector(d,b)+"{",f=n.lastIndex;return e+=a.substring(f,a.length)},applyShimming:function(a,b){var c=this.shimAtHost(a,b);c+=this.shimScoping(a,b),e(c)},shimAtHost:function(a,b){return a?this.convertAtHostStyles(a,b):void 0},convertAtHostStyles:function(a,e){for(var f,g=b(a),h="",j=0;f=i.exec(g);)h+=g.substring(j,f.index),h+=this.scopeHostCss(f[1],e),j=i.lastIndex;h+=g.substring(j,g.length);var k=new RegExp("^"+e+p,"m"),g=d(this.findAtHostRules(c(h),k));return g},scopeHostCss:function(a,b){for(var c,d="";c=j.exec(a);)d+=this.scopeHostSelector(c[1],b)+" "+c[2]+"\n	";return d},scopeHostSelector:function(a,b){var c=[],d=a.split(","),e="[is="+b+"]";return d.forEach(function(a){a=a.trim(),a.match(k)?a=a.replace(k,b+"$1$3, "+e+"$1$3"):a.match(l)&&(a=b+a+", "+e+a),c.push(a)},this),c.join(", ")},findAtHostRules:function(a,b){return Array.prototype.filter.call(a,this.isHostRule.bind(this,b))},isHostRule:function(a,b){return b.selectorText&&b.selectorText.match(a)||b.cssRules&&this.findAtHostRules(b.cssRules,a).length||b.type==CSSRule.WEBKIT_KEYFRAMES_RULE},shimScoping:function(a,b){return a?this.convertScopedStyles(a,b):void 0},convertScopedStyles:function(a,d){Array.prototype.forEach.call(a,function(a){a.parentNode&&a.parentNode.removeChild(a)});var e=b(a).replace(i,"");e=this.convertPseudos(e);var f=c(e);return e=this.scopeRules(f,d)},convertPseudos:function(a){return a.replace(o," [pseudo=$1]")},scopeRules:function(a,b){var c="";return Array.prototype.forEach.call(a,function(a){a.selectorText&&a.style&&a.style.cssText?(c+=this.scopeSelector(a.selectorText,b,this.strictStyling)+" {\n	",c+=this.propertiesFromRule(a)+"\n}\n\n"):a.media?(c+="@media "+a.media.mediaText+" {\n",c+=this.scopeRules(a.cssRules,b),c+="\n}\n\n"):a.cssText&&(c+=a.cssText+"\n\n")},this),c},scopeSelector:function(a,b,c){var d=[],e=a.split(",");return e.forEach(function(a){a=a.trim(),this.selectorNeedsScoping(a,b)&&(a=c?this.applyStrictSelectorScope(a,b):this.applySimpleSelectorScope(a,b)),d.push(a)},this),d.join(", ")},selectorNeedsScoping:function(a,b){var c="("+b+"|\\[is="+b+"\\])",d=new RegExp("^"+c+p,"m");return!a.match(d)},applySimpleSelectorScope:function(a,b){return b+" "+a+", "+"[is="+b+"] "+a},applyStrictSelectorScope:function(a,b){var c=[" ",">","+","~"],d=a,e="["+b+"]";return c.forEach(function(a){var b=d.split(a);d=b.map(function(a){var b=a.trim();return b&&c.indexOf(b)<0&&b.indexOf(e)<0&&(a=b.replace(/([^:]*)(:*)(.*)/,"$1"+e+"$2$3")),a}).join(a)}),d},propertiesFromRule:function(a){var b=a.style.cssText;return a.style.content&&!a.style.content.match(/['"]+/)&&(b="content: '"+a.style.content+"';\n"+a.style.cssText.replace(/content:[^;]*;/g,"")),b}},i=/@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,j=/([^{]*)({[\s\S]*?})/gim,k=/(.*)((?:\*)|(?:\:scope))(.*)/,l=/^[.\[:]/,m=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,n=/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,o=/::(x-[^\s{,(]*)/gim,p="([>\\s~+[.,{:][\\s\\S]*)?$",q=/@host/gim;if(window.ShadowDOMPolyfill){e("style { display: none !important; }\n");var r=document.querySelector("head");r.insertBefore(f(),r.childNodes[0])}a.ShadowCSS=h}(window.Platform)}else{var SideTable;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},SideTable.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}(),function(){window.templateContent=window.templateContent||function(a){return a.content},window.wrap=window.unwrap=function(a){return a};var a=HTMLElement.prototype.webkitCreateShadowRoot;HTMLElement.prototype.webkitCreateShadowRoot=function(){var b=this.webkitShadowRoot,c=a.call(this);return c.olderShadowRoot=b,c.host=this,CustomElements.watchShadow(this),c},Object.defineProperties(HTMLElement.prototype,{shadowRoot:{get:function(){return this.webkitShadowRoot}},createShadowRoot:{value:function(){return this.webkitCreateShadowRoot()}}}),window.templateContent=function(a){if(window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(a),!a.content&&!a._content){for(var b=document.createDocumentFragment();a.firstChild;)b.appendChild(a.firstChild);a._content=b}return a.content||a._content}}()}if(function(a){function b(a){for(var b=a||{},d=1;d<arguments.length;d++){var e=arguments[d];try{for(var f in e)c(f,e,b)}catch(g){}}return b}function c(a,b,c){var e=d(b,a);Object.defineProperty(c,a,e)}function d(a,b){if(a){var c=Object.getOwnPropertyDescriptor(a,b);return c||d(Object.getPrototypeOf(a),b)}}Function.prototype.bind||(Function.prototype.bind=function(a){var b=this,c=Array.prototype.slice.call(arguments,1);return function(){var d=c.slice();return d.push.apply(d,arguments),b.apply(a,d)}}),a.mixin=b}(window.Platform),function(a){"use strict";function b(a,b,c){var d="string"==typeof a?document.createElement(a):a.cloneNode(!0);if(d.innerHTML=b,c)for(var e in c)d.setAttribute(e,c[e]);return d}var c=DOMTokenList.prototype.add,d=DOMTokenList.prototype.remove;DOMTokenList.prototype.add=function(){for(var a=0;a<arguments.length;a++)c.call(this,arguments[a])},DOMTokenList.prototype.remove=function(){for(var a=0;a<arguments.length;a++)d.call(this,arguments[a])},DOMTokenList.prototype.toggle=function(a,b){1==arguments.length&&(b=!this.contains(a)),b?this.add(a):this.remove(a)},DOMTokenList.prototype.switch=function(a,b){a&&this.remove(a),b&&this.add(b)};var e=function(){return Array.prototype.slice.call(this)},f=window.NamedNodeMap||window.MozNamedAttrMap||{};NodeList.prototype.array=e,f.prototype.array=e,HTMLCollection.prototype.array=e;var g=function(a,b){e.call(this).forEach(a,b)};if(NodeList.prototype.forEach=g,f.prototype.forEach=g,HTMLCollection.prototype.forEach=g,!window.performance){var h=Date.now();window.performance={now:function(){return Date.now()-h}}}window.requestAnimationFrame||(window.requestAnimationFrame=function(){var a=window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;return a?function(b){return a(function(){b(performance.now())})}:function(a){return window.setTimeout(a,1e3/60)}}()),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(){return window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||function(a){clearTimeout(a)}}()),a.createDOM=b}(window.Platform),window.templateContent=window.templateContent||function(a){return a.content},function(a){a=a||(window.Inspector={});var b;window.sinspect=function(a,d){b||(b=window.open("","ShadowDOM Inspector",null,!0),b.document.write(c),b.api={shadowize:shadowize}),f(a||wrap(document.body),d)};var c=["<!DOCTYPE html>","<html>","  <head>","    <title>ShadowDOM Inspector</title>","    <style>","      body {","      }","      pre {",'        font: 9pt "Courier New", monospace;',"        line-height: 1.5em;","      }","      tag {","        color: purple;","      }","      ul {","         margin: 0;","         padding: 0;","         list-style: none;","      }","      li {","         display: inline-block;","         background-color: #f1f1f1;","         padding: 4px 6px;","         border-radius: 4px;","         margin-right: 4px;","      }","    </style>","  </head>","  <body>",'    <ul id="crumbs">',"    </ul>",'    <div id="tree"></div>',"  </body>","</html>"].join("\n"),d=[],e=function(){var a=b.document,c=a.querySelector("#crumbs");c.textContent="";for(var e,g=0;e=d[g];g++){var h=a.createElement("a");h.href="#",h.textContent=e.localName,h.idx=g,h.onclick=function(a){for(var b;d.length>this.idx;)b=d.pop();f(b.shadow||b,b),a.preventDefault()},c.appendChild(a.createElement("li")).appendChild(h)}},f=function(a,c){var f=b.document;k=[];var g=c||a;d.push(g),e(),f.body.querySelector("#tree").innerHTML="<pre>"+j(a,a.childNodes)+"</pre>"},g=Array.prototype.forEach.call.bind(Array.prototype.forEach),h={STYLE:1,SCRIPT:1,"#comment":1,TEMPLATE:1},i=function(a){return h[a.nodeName]},j=function(a,b,c){if(i(a))return"";var d=c||"";if(a.localName||11==a.nodeType){var e=a.localName||"shadow-root",f=d+l(a);"content"==e&&(b=a.getDistributedNodes()),f+="<br/>";var h=d+"&nbsp;&nbsp;";g(b,function(a){f+=j(a,a.childNodes,h)}),f+=d,{br:1}[e]||(f+="<tag>&lt;/"+e+"&gt;</tag>",f+="<br/>")}else{var k=a.textContent.trim();f=k?d+'"'+k+'"'+"<br/>":""}return f},k=[],l=function(a){var b="<tag>&lt;",c=a.localName||"shadow-root";return a.webkitShadowRoot||a.shadowRoot?(b+=' <button idx="'+k.length+'" onclick="api.shadowize.call(this)">'+c+"</button>",k.push(a)):b+=c||"shadow-root",a.attributes&&g(a.attributes,function(a){b+=" "+a.name+(a.value?'="'+a.value+'"':"")}),b+="&gt;</tag>"};shadowize=function(){var a=Number(this.attributes.idx.value),b=k[a];b?f(b.webkitShadowRoot||b.shadowRoot,b):(console.log("bad shadowize node"),console.dir(this))},a.output=j}(window.Inspector),function(a){"use strict";function b(){function a(a){"splice"===a[0].type&&"splice"===a[1].type&&(b=!0)}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=!1,c=[0];return Array.observe(c,a),c[1]=1,c.length=0,Object.deliverChangeRecords(a),b}function c(a){return+a===a>>>0}function d(a){return+a}function e(a){return a===Object(a)}function f(a,b){return a===b?0!==a||1/a===1/b:K(a)&&K(b)?!0:a!==a&&b!==b}function g(a){return"string"!=typeof a?!1:(a=a.replace(/\s/g,""),""==a?!0:"."==a[0]?!1:S.test(a))}function h(a){var b=T[a];if(b)return b;if(g(a)){var b=new i(a);return T[a]=b,b}}function i(a){return""==a.trim()?this:c(a)?(this.push(String(a)),this):(a.split(/\./).filter(function(a){return a}).forEach(function(a){this.push(a)},this),H&&this.length&&(this.getValueFrom=this.compiledGetValueFromFn()),void 0)}function j(a){for(var b=0;U>b&&a.check();)a.report(),b++}function k(a){for(var b in a)return!1;return!0}function l(a){return k(a.added)&&k(a.removed)&&k(a.changed)}function m(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function n(a,b){var c=b||(Array.isArray(a)?[]:{});for(var d in a)c[d]=a[d];return Array.isArray(a)&&(c.length=a.length),c}function o(a,b,c,d){if(this.closed=!1,this.object=a,this.callback=b,this.target=c,this.token=d,this.reporting=!0,G){var e=this;this.boundInternalCallback=function(a){e.internalCallback(a)}}p(this),this.connect(),this.sync(!0)}function p(a){W&&(V.push(a),o._allObserversCount++)}function q(a,b,c,d){o.call(this,a,b,c,d)}function r(a,b,c,d){if(!Array.isArray(a))throw Error("Provided object is not an Array");o.call(this,a,b,c,d)}function s(a){this.arr=[],this.callback=a,this.isObserved=!0}function t(a,b,c,d,f){this.value=void 0;var g=h(b);return g?g.length?e(a)?(this.path=g,o.call(this,a,c,d,f),void 0):(this.closed=!0,this.value=void 0,void 0):(this.closed=!0,this.value=a,void 0):(this.closed=!0,this.value=void 0,void 0)}function u(a,b){if("function"==typeof Object.observe){var c=Object.getNotifier(a);return function(d,e){var f={object:a,type:d,name:b};2===arguments.length&&(f.oldValue=e),c.notify(f)}}}function v(a,b,c){for(var d={},e={},f=0;f<b.length;f++){var g=b[f];_[g.type]?(g.name in c||(c[g.name]=g.oldValue),"updated"!=g.type&&("new"!=g.type?g.name in d?(delete d[g.name],delete c[g.name]):e[g.name]=!0:g.name in e?delete e[g.name]:d[g.name]=!0)):(console.error("Unknown changeRecord type: "+g.type),console.error(g))}for(var h in d)d[h]=a[h];for(var h in e)e[h]=void 0;var i={};for(var h in c)if(!(h in d||h in e)){var j=a[h];c[h]!==j&&(i[h]=j)}return{added:d,removed:e,changed:i}}function w(a,b,c,d,e,f){for(var g=f-e+1,h=c-b+1,i=new Array(g),j=0;g>j;j++)i[j]=new Array(h),i[j][0]=j;for(var k=0;h>k;k++)i[0][k]=k;for(var j=1;g>j;j++)for(var k=1;h>k;k++)if(d[e+j-1]===a[b+k-1])i[j][k]=i[j-1][k-1];else{var l=i[j-1][k]+1,m=i[j][k-1]+1;i[j][k]=m>l?l:m}return i}function x(a){for(var b=a.length-1,c=a[0].length-1,d=a[b][c],e=[];b>0||c>0;)if(0!=b)if(0!=c){var f,g=a[b-1][c-1],h=a[b-1][c],i=a[b][c-1];f=i>h?g>h?h:g:g>i?i:g,f==g?(g==d?e.push(ab):(e.push(bb),d=g),b--,c--):f==h?(e.push(db),b--,d=h):(e.push(cb),c--,d=i)}else e.push(db),b--;else e.push(cb),c--;return e.reverse(),e}function y(a,b,c){for(var d=0;c>d;d++)if(a[d]!==b[d])return d;return c}function z(a,b,c){for(var d=a.length,e=b.length,f=0;c>f&&a[--d]===b[--e];)f++;return f}function A(a,b,c){return{index:a,removed:b,addedCount:c}}function B(a,b,c,d,e,f){var g=0,h=0,i=Math.min(c-b,f-e);if(0==b&&0==e&&(g=y(a,d,i)),c==a.length&&f==d.length&&(h=z(a,d,i-g)),b+=g,e+=g,c-=h,f-=h,0==c-b&&0==f-e)return[];if(b==c){for(var j=A(b,[],0);f>e;)j.removed.push(d[e++]);return[j]}if(e==f)return[A(b,[],c-b)];for(var k=x(w(a,b,c,d,e,f)),j=void 0,l=[],m=b,n=e,o=0;o<k.length;o++)switch(k[o]){case ab:j&&(l.push(j),j=void 0),m++,n++;break;case bb:j||(j=A(m,[],0)),j.addedCount++,m++,j.removed.push(d[n]),n++;break;case cb:j||(j=A(m,[],0)),j.addedCount++,m++;break;case db:j||(j=A(m,[],0)),j.removed.push(d[n]),n++}return j&&l.push(j),l}function C(a,b,c,d){return c>b||a>d?-1:b==c||d==a?0:c>a?d>b?b-c:d-c:b>d?d-a:b-a}function D(a,b,c,d){for(var e=A(b,c,d),f=!1,g=0,h=0;h<a.length;h++){var i=a[h];if(i.index+=g,!f){var j=C(e.index,e.index+e.removed.length,i.index,i.index+i.addedCount);if(j>=0){a.splice(h,1),h--,g-=i.addedCount-i.removed.length,e.addedCount+=i.addedCount-j;var k=e.removed.length+i.removed.length-j;if(e.addedCount||k){var c=i.removed;if(e.index<i.index){var l=e.removed.slice(0,i.index-e.index);Array.prototype.push.apply(l,c),c=l}if(e.index+e.removed.length>i.index+i.addedCount){var m=e.removed.slice(i.index+i.addedCount-e.index);Array.prototype.push.apply(c,m)}e.removed=c,i.index<e.index&&(e.index=i.index)}else f=!0}else if(e.index<i.index){f=!0,a.splice(h,0,e),h++;var n=e.addedCount-e.removed.length;i.index+=n,g+=n}}}f||a.push(e)}function E(a,b){for(var e=[],f=0;f<b.length;f++){var g=b[f];switch(g.type){case"splice":D(e,g.index,g.removed.slice(),g.addedCount);break;case"new":case"updated":case"deleted":if(!c(g.name))continue;var h=d(g.name);if(0>h)continue;D(e,h,[g.oldValue],1);break;default:console.error("Unexpected record type: "+JSON.stringify(g))}}return e}function F(a,b){var c=[];return E(a,b).forEach(function(b){return 1==b.addedCount&&1==b.removed.length?(b.removed[0]!==a[b.index]&&c.push(b),void 0):(c=c.concat(B(a,b.index,b.index+b.addedCount,b.removed,0,b.removed.length)),void 0)}),c}var G=b(),H=!1;try{var I=new Function("","return true;");H=I()}catch(J){}var K=a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},L="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c},M="[$_a-zA-Z]",N="[$_a-zA-Z0-9]",O=M+"+"+N+"*",P="(?:[0-9]|[1-9]+[0-9]+)",Q="(?:"+O+"|"+P+")",R="(?:"+Q+")(?:\\."+Q+")*",S=new RegExp("^"+R+"$"),T={};i.prototype=L({__proto__:[],toString:function(){return this.join(".")},getValueFrom:function(a){for(var b=0;b<this.length;b++){if(void 0===a||null===a)return;a=a[this[b]]}return a},getValueFromObserved:function(a,b){b.reset();for(var c=0;c<this.length;c++){if(void 0===a||null===a)return b.cleanup(),void 0;b.observe(a),a=a[this[c]]}return a},compiledGetValueFromFn:function(){var a=this.map(function(a){return c(a)?'["'+a+'"]':"."+a}),b="",d="obj";b+="if (obj !== null && obj !== undefined";for(var e=0;e<this.length-1;e++)this[e],d+=a[e],b+=" &&\n     "+d+" !== null && "+d+" !== undefined";return b+=")\n",d+=a[e],b+="  return "+d+";\nelse\n  return undefined;",new Function("obj",b)},setValueFrom:function(a,b){if(!this.length)return!1;for(var c=0;c<this.length-1;c++){if(void 0===a||null===a)return!1;a=a[this[c]]}return void 0===a||null===a?!1:(a[this[this.length-1]]=b,!0)}});var U=1e3;o.prototype={internalCallback:function(a){this.closed||this.reporting&&this.check(a)&&(this.report(),this.testingResults&&(this.testingResults.anyChanged=!0))},close:function(){this.closed||(this.object&&"function"==typeof this.object.unobserved&&this.object.unobserved(),this.disconnect(),this.object=void 0,this.closed=!0)},deliver:function(a){this.closed||(G?(this.testingResults=a,Object.deliverChangeRecords(this.boundInternalCallback),this.testingResults=void 0):j(this))},report:function(){this.reporting&&(this.sync(!1),this.reportArgs.push(this.token),this.invokeCallback(this.reportArgs),this.reportArgs=void 0)},invokeCallback:function(a){try{this.callback.apply(this.target,a)}catch(b){o._errorThrownDuringCallback=!0,console.error("Exception caught during observer callback: "+b)}},reset:function(){this.closed||(G&&(this.reporting=!1,Object.deliverChangeRecords(this.boundInternalCallback),this.reporting=!0),this.sync(!0))}};var V,W=!G||a.forceCollectObservers;o._allObserversCount=0,W&&(V=[]);var X=!1,Y="function"==typeof Object.deliverAllChangeRecords;a.Platform=a.Platform||{},a.Platform.performMicrotaskCheckpoint=function(){if(!X){if(Y)return Object.deliverAllChangeRecords(),void 0;if(W){X=!0;var a=0,b={};do{a++;var c=V;V=[],b.anyChanged=!1;for(var d=0;d<c.length;d++){var e=c[d];e.closed||(G?e.deliver(b):e.check()&&(b.anyChanged=!0,e.report()),V.push(e))}}while(U>a&&b.anyChanged);o._allObserversCount=V.length,X=!1}}},W&&(a.Platform.clearObservers=function(){V=[]}),q.prototype=L({__proto__:o.prototype,connect:function(){G&&Object.observe(this.object,this.boundInternalCallback)},sync:function(){G||(this.oldObject=n(this.object))},check:function(a){var b,c;if(G){if(!a)return!1;c={},b=v(this.object,a,c)}else c=this.oldObject,b=m(this.object,this.oldObject);return l(b)?!1:(this.reportArgs=[b.added||{},b.removed||{},b.changed||{}],this.reportArgs.push(function(a){return c[a]}),!0)},disconnect:function(){G?this.object&&Object.unobserve(this.object,this.boundInternalCallback):this.oldObject=void 0}}),r.prototype=L({__proto__:q.prototype,connect:function(){G&&Array.observe(this.object,this.boundInternalCallback)},sync:function(){G||(this.oldObject=this.object.slice())},check:function(a){var b;if(G){if(!a)return!1;b=F(this.object,a)}else b=B(this.object,0,this.object.length,this.oldObject,0,this.oldObject.length);return b&&b.length?(this.reportArgs=[b],!0):!1}}),r.applySplices=function(a,b,c){c.forEach(function(c){for(var d=[c.index,c.removed.length],e=c.index;e<c.index+c.addedCount;)d.push(b[e]),e++;Array.prototype.splice.apply(a,d)})};var Z=Object.getPrototypeOf({}),$=Object.getPrototypeOf([]);s.prototype={reset:function(){this.isObserved=!this.isObserved},observe:function(a){if(e(a)&&a!==Z&&a!==$){var b=this.arr.indexOf(a);b>=0&&this.arr[b+1]===this.isObserved||(0>b&&(b=this.arr.length,this.arr[b]=a,Object.observe(a,this.callback)),this.arr[b+1]=this.isObserved,this.observe(Object.getPrototypeOf(a)))}},cleanup:function(){for(var a=0,b=0,c=this.isObserved;b<this.arr.length;){var d=this.arr[b];this.arr[b+1]==c?(b>a&&(this.arr[a]=d,this.arr[a+1]=c),a+=2):Object.unobserve(d,this.callback),b+=2}this.arr.length=a}},t.prototype=L({__proto__:o.prototype,connect:function(){G&&(this.observedSet=new s(this.boundInternalCallback))},disconnect:function(){this.value=void 0,G&&(this.observedSet.reset(),this.observedSet.cleanup(),this.observedSet=void 0)},check:function(){return this.value=G?this.path.getValueFromObserved(this.object,this.observedSet):this.path.getValueFrom(this.object),f(this.value,this.oldValue)?!1:(this.reportArgs=[this.value,this.oldValue],!0)},sync:function(a){a&&(this.value=G?this.path.getValueFromObserved(this.object,this.observedSet):this.path.getValueFrom(this.object)),this.oldValue=this.value}}),t.getValueAtPath=function(a,b){var c=h(b);return c?c.getValueFrom(a):void 0},t.setValueAtPath=function(a,b,c){var d=h(b);d&&d.setValueFrom(a,c)};var _={"new":!0,updated:!0,deleted:!0};t.defineProperty=function(a,b,c){var d=c.object,e=h(c.path),f=u(a,b),g=new t(d,c.path,function(a,b){f&&f("updated",b)});return Object.defineProperty(a,b,{get:function(){return e.getValueFrom(d)},set:function(a){e.setValueFrom(d,a)},configurable:!0}),{close:function(){var c=e.getValueFrom(d);f&&g.deliver(),g.close(),Object.defineProperty(a,b,{value:c,writable:!0,configurable:!0})}}};var ab=0,bb=1,cb=2,db=3;a.Observer=o,a.Observer.hasObjectObserve=G,a.ArrayObserver=r,a.ArrayObserver.calculateSplices=function(a,b){return B(a,0,a.length,b,0,b.length)},a.ObjectObserver=q,a.PathObserver=t,a.Path=i}("undefined"!=typeof global&&global?global:this),function(){"use strict";function a(a,b,c,d){this.closed=!1,this.node=a,this.property=b,this.model=c,this.path=d||"",this.observer=new PathObserver(this.model,this.path,this.boundValueChanged,this),this.boundValueChanged(this.value)}function b(b,c,d,e){this.conditional="?"==c[c.length-1],this.conditional&&(b.removeAttribute(c),c=c.slice(0,-1)),a.call(this,b,c,d,e)}function c(a){switch(a.type){case"checkbox":return k;case"radio":case"select-multiple":case"select-one":return"change";default:return"input"}}function d(b,d,e,f){a.call(this,b,d,e,f),this.eventType=c(this.node),this.boundNodeValueChanged=this.nodeValueChanged.bind(this),this.node.addEventListener(this.eventType,this.boundNodeValueChanged,!0)}function e(a){if(!a.ownerDocument.contains(a))return[];if(a.form)return i(a.form.elements,function(b){return b!=a&&"INPUT"==b.tagName&&"radio"==b.type&&b.name==a.name});var b=a.ownerDocument.querySelectorAll('input[type="radio"][name="'+a.name+'"]');return i(b,function(b){return b!=a&&!b.form})}function f(a,b,c){d.call(this,a,"checked",b,c)}function g(a,b,c){d.call(this,a,"value",b,c)}function h(a,b,c,e){d.call(this,a,b,c,e)}var i=Array.prototype.filter.call.bind(Array.prototype.filter),j="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c};"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)
+}),Node.prototype.bind=function(a,b,c){console.error("Unhandled binding to Node: ",this,a,b,c)},Node.prototype.unbind=function(a){this.bindings=this.bindings||{};var b=this.bindings[a];b&&"function"==typeof b.close&&b.close(),delete this.bindings[a]},Node.prototype.unbindAll=function(){if(this.bindings){for(var a=Object.keys(this.bindings),b=0;b<a.length;b++){var c=this.bindings[a[b]];c&&c.close()}this.bindings={}}},a.prototype={boundValueChanged:function(a){this.node[this.property]=this.sanitizeBoundValue(a)},sanitizeBoundValue:function(a){return void 0==a?"":String(a)},close:function(){this.closed||(this.observer.close(),this.observer=void 0,this.node=void 0,this.model=void 0,this.closed=!0)},get value(){return this.observer.value},set value(a){PathObserver.setValueAtPath(this.model,this.path,a)},reset:function(){this.observer.reset()}},Text.prototype.bind=function(b,c,d){return"textContent"!==b?Node.prototype.bind.call(this,b,c,d):(this.unbind(b),this.bindings[b]=new a(this,"data",c,d))},b.prototype=j({__proto__:a.prototype,boundValueChanged:function(a){return this.conditional?(a?this.node.setAttribute(this.property,""):this.node.removeAttribute(this.property),void 0):(this.node.setAttribute(this.property,this.sanitizeBoundValue(a)),void 0)}}),Element.prototype.bind=function(a,c,d){return this.unbind(a),this.bindings[a]=new b(this,a,c,d)};var k;!function(){var a=document.createElement("div"),b=a.appendChild(document.createElement("input"));b.setAttribute("type","checkbox");var c,d=0;b.addEventListener("click",function(){d++,c=c||"click"}),b.addEventListener("change",function(){d++,c=c||"change"});var e=document.createEvent("MouseEvent");e.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),b.dispatchEvent(e),k=1==d?"change":c}(),d.prototype=j({__proto__:a.prototype,nodeValueChanged:function(){this.value=this.node[this.property],this.reset(),this.postUpdateBinding(),Platform.performMicrotaskCheckpoint()},postUpdateBinding:function(){},close:function(){this.closed||(this.node.removeEventListener(this.eventType,this.boundNodeValueChanged,!0),a.prototype.close.call(this))}}),f.prototype=j({__proto__:d.prototype,sanitizeBoundValue:function(a){return Boolean(a)},postUpdateBinding:function(){"INPUT"===this.node.tagName&&"radio"===this.node.type&&e(this.node).forEach(function(a){var b=a.bindings.checked;b&&(b.value=!1)})}}),HTMLInputElement.prototype.bind=function(a,b,c){return"value"!==a&&"checked"!==a?HTMLElement.prototype.bind.call(this,a,b,c):(this.unbind(a),this.removeAttribute(a),this.bindings[a]="value"===a?new d(this,"value",b,c):new f(this,b,c))},HTMLTextAreaElement.prototype.bind=function(a,b,c){return"value"!==a?HTMLElement.prototype.bind.call(this,a,b,c):(this.unbind(a),this.removeAttribute(a),this.bindings[a]=new d(this,a,b,c))},g.prototype=j({__proto__:d.prototype,boundValueChanged:function(a){var b,c,e=this.node.parentNode instanceof HTMLSelectElement?this.node.parentNode:void 0;e&&e.bindings&&e.bindings.value instanceof h&&(b=e.bindings.value,c=e.value),d.prototype.boundValueChanged.call(this,a),b&&!b.closed&&e.value!==c&&b.nodeValueChanged()}}),HTMLOptionElement.prototype.bind=function(a,b,c){return"value"!==a?HTMLElement.prototype.bind.call(this,a,b,c):(this.unbind(a),this.removeAttribute(a),this.bindings[a]=new g(this,b,c))},h.prototype=j({__proto__:d.prototype,boundValueChanged:function(a){function b(){d.node[d.property]=a,d.node[d.property]!=a&&c--&&l(b)}if(this.node[this.property]=a,this.node[this.property]!=a){var c=2,d=this;l(b)}}}),HTMLSelectElement.prototype.bind=function(a,b,c){return"selectedindex"===a&&(a="selectedIndex"),"selectedIndex"!==a&&"value"!==a?HTMLElement.prototype.bind.call(this,a,b,c):(this.unbind(a),this.removeAttribute(a),this.bindings[a]=new h(this,a,b,c))};var l=function(){function a(a){this.nextRunner=a,this.value=!1,this.lastValue=this.value,this.scheduled=[],this.scheduledIds=[],this.running=!1,this.observer=new PathObserver(this,"value",this.run,this)}function b(a){var b=a[e];a[e]||(b=d++,a[e]=b),c.schedule(a,b)}a.prototype={schedule:function(a,b){if(!this.scheduledIds[b]){if(this.running)return this.nextRunner.schedule(a,b);this.scheduledIds[b]=!0,this.scheduled.push(a),this.lastValue===this.value&&(this.value=!this.value)}},run:function(){this.running=!0;for(var a=0;a<this.scheduled.length;a++){var b=this.scheduled[a],c=b[e];this.scheduledIds[c]=!1,"function"==typeof b?b():b.resolve()}this.scheduled=[],this.scheduledIds=[],this.lastValue=this.value,this.running=!1}};var c=new a(new a),d=1,e="__scheduledId__";return b}()}(this),function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a){for(;a.parentNode;)a=a.parentNode;return"function"==typeof a.getElementById?a:null}function d(a){return P[a.tagName]&&a.hasAttribute("template")}function e(a){return"TEMPLATE"==a.tagName||d(a)}function f(a){return Q&&"TEMPLATE"==a.tagName}function g(a,b){var c=a.querySelectorAll(R);e(a)&&b(a),G(c,b)}function h(a){function b(a){HTMLTemplateElement.decorate(a)||h(a.content)}g(a,b)}function i(a,b){Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))})}function j(a){if(!a.defaultView)return a;var b=V.get(a);if(!b){for(b=a.implementation.createHTMLDocument("");b.lastChild;)b.removeChild(b.lastChild);V.set(a,b)}return b}function k(a){var b=a.ownerDocument.createElement("template");a.parentNode.insertBefore(b,a);for(var c=a.attributes,d=c.length;d-->0;){var e=c[d];O[e.name]&&("template"!==e.name&&b.setAttribute(e.name,e.value),a.removeAttribute(e.name))}return b}function l(a,b,c){var d=a.content;if(c)return d.appendChild(b),void 0;for(var e;e=b.firstChild;)d.appendChild(e)}function m(a){"TEMPLATE"===a.tagName?Q||(T?a.__proto__=HTMLTemplateElement.prototype:i(a,HTMLTemplateElement.prototype)):(i(a,HTMLTemplateElement.prototype),Object.defineProperty(a,"content",Z))}function n(a){var b=ab.get(a);b||(b=function(){y(a,a.model,a.bindingDelegate)},ab.set(a,b)),S(b)}function o(a,b,c,d,e){this.closed=!1,this.node=a,this.property=b,this.model=c,this.path=d||"",this.iterator=e,this.iterator.inputs.bind(this.property,this.model,this.path)}function p(a){return 3==a.length&&0==a[0].length&&0==a[2].length}function q(a){if(a&&a.length){for(var b,c=a.length,d=0,e=0,f=0;c>e;){if(d=a.indexOf("{{",e),f=0>d?-1:a.indexOf("}}",d+2),0>f){if(!b)return;b.push(a.slice(e));break}b=b||[],b.push(a.slice(e,d)),b.push(a.slice(d+2,f).trim()),e=f+2}return e===c&&b.push(""),b}}function r(a,b,c,d,e){var f,g=e&&e[M];return g&&"function"==typeof g&&(f=g(c,d,b,a),f&&(c=f,d="value")),a.bind(b,c,d)}function s(a,b,c,d,e){for(var f=0;f<a.length;f+=2){var g=u(b,a[f],a[f+1],c,d);e&&e.push(g)}}function t(a){return function(b){for(var c=a[0],d=1;d<a.length;d+=2){var e=b[d];void 0!==e&&(c+=e),c+=a[d+1]}return c}}function u(a,b,c,d,e){if(p(c))return r(a,b,d,c[1],e);c.combinator=c.combinator||t(c);var f=new D(c.combinator);f.scheduled=!0;for(var g=1;g<c.length;g+=2)r(f,g,d,c[g],e);return f.resolve(),a.bind(b,f,"value")}function v(a){b(a);for(var c,d=e(a),f=!1,g=!1,h=0;h<a.attributes.length;h++){var i=a.attributes[h],j=i.name,k=i.value;d&&(j===L?(f=!0,k=k||"{{}}"):(j===J||j===K)&&(g=!0,k=k||"{{}}"));var l=q(k);l&&(c=c||[],c.push(j,l))}return f&&!g&&(c=c||[],c.push(J,q("{{}}"))),c}function w(a){if(a.nodeType===Node.ELEMENT_NODE)return v(a);if(a.nodeType===Node.TEXT_NODE){var b=q(a.data);if(b)return["textContent",b]}}function x(a,b,c,d,e){if(b&&(b.templateRef&&(HTMLTemplateElement.decorate(a,b.templateRef),d&&_.set(a,d)),b.length&&s(b,a,c,d,e),b.children))for(var f=0,g=a.firstChild;g;g=g.nextSibling)x(g,b.children[f++],c,d,e)}function y(a,c,d){b(a);var e=w(a);e&&s(e,a,c,d);for(var f=a.firstChild;f;f=f.nextSibling)y(f,c,d)}function z(a,b){var c=a.cloneNode(!1);if(e(c))return c;for(var d=a.firstChild;d;d=d.nextSibling)c.appendChild(z(d,b));return c}function A(a){var b=w(a);e(a)&&(b=b||[],b.templateRef=a,b.hasSubTemplate=!0);for(var c=a.firstChild,d=0;c;c=c.nextSibling,d++){var f=A(c);f&&(b=b||[],b.children=b.children||{},b.children[d]=f,f.hasSubTemplate&&(b.hasSubTemplate=!0))}return b}function B(a,b,c){this.firstNode=a,this.lastNode=b,this.model=c}function C(a,b){if(a.firstChild)for(var c=new B(a.firstChild,a.lastChild,b),d=c.firstNode;d;)bb.set(d,c),d=d.nextSibling}function D(a){this.observers={},this.values={},this.value=void 0,this.size=0,this.combinator_=a,this.closed=!1,this.scheduled=!1}function E(a){this.closed=!1,this.templateElement_=a,this.terminators=[],this.iteratedValue=void 0,this.arrayObserver=void 0,this.inputs=new D(this.resolveInputs.bind(this)),E.templateTable.set(this.templateElement_,this)}var F,G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.Map&&"function"==typeof a.Map.prototype.forEach?F=a.Map:(F=function(){this.keys=[],this.values=[]},F.prototype={set:function(a,b){var c=this.keys.indexOf(a);0>c?(this.keys.push(a),this.values.push(b)):this.values[c]=b},get:function(a){var b=this.keys.indexOf(a);return 0>b?void 0:this.values[b]},"delete":function(a){var b=this.keys.indexOf(a);return 0>b?!1:(this.keys.splice(b,1),this.values.splice(b,1),!0)},forEach:function(a,b){for(var c=0;c<this.keys.length;c++)a.call(b||this,this.values[c],this.keys[c],this)}});var H="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c};"function"!=typeof document.contains&&(Document.prototype.contains=function(a){return a===this||a.parentNode===this?!0:this.documentElement.contains(a)});var I;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?I=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;I=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},I.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}();var J="bind",K="repeat",L="if",M="getBinding",N="getInstanceModel",O={template:!0,repeat:!0,bind:!0,ref:!0},P={THEAD:!0,TBODY:!0,TFOOT:!0,TH:!0,TR:!0,TD:!0,COLGROUP:!0,COL:!0,CAPTION:!0,OPTION:!0,OPTGROUP:!0},Q="undefined"!=typeof HTMLTemplateElement,R="template, "+Object.keys(P).map(function(a){return a.toLowerCase()+"[template]"}).join(", "),S=function(){function a(a){this.nextRunner=a,this.value=!1,this.lastValue=this.value,this.scheduled=[],this.scheduledIds=[],this.running=!1,this.observer=new PathObserver(this,"value",this.run,this)}function b(a){var b=a[e];a[e]||(b=d++,a[e]=b),c.schedule(a,b)}a.prototype={schedule:function(a,b){if(!this.scheduledIds[b]){if(this.running)return this.nextRunner.schedule(a,b);this.scheduledIds[b]=!0,this.scheduled.push(a),this.lastValue===this.value&&(this.value=!this.value)}},run:function(){this.running=!0;for(var a=0;a<this.scheduled.length;a++){var b=this.scheduled[a],c=b[e];this.scheduledIds[c]=!1,"function"==typeof b?b():b.resolve()}this.scheduled=[],this.scheduledIds=[],this.lastValue=this.value,this.running=!1}};var c=new a(new a),d=1,e="__scheduledId__";return b}();document.addEventListener("DOMContentLoaded",function(){h(document),Platform.performMicrotaskCheckpoint()},!1),Q||(a.HTMLTemplateElement=function(){throw TypeError("Illegal constructor")});var T="__proto__"in{},U=new I,V=new I,W=new I,X=new I;HTMLTemplateElement.decorate=function(a,c){if(a.templateIsDecorated_)return!1;var e=a;e.templateIsDecorated_=!0;var g=f(e),i=g,n=!g,o=!1;if(!g&&d(e)&&(b(!c),e=k(a),e.templateIsDecorated_=!0,g=f(e),o=!0),!g){m(e);var p=j(e.ownerDocument);U.set(e,p.createDocumentFragment())}return c?W.set(e,c):n?l(e,a,o):i&&h(e.content),!0},HTMLTemplateElement.bootstrap=h;var Y=a.HTMLUnknownElement||HTMLElement,Z={get:function(){return U.get(this)},enumerable:!0,configurable:!0};Q||(HTMLTemplateElement.prototype=Object.create(Y.prototype),Object.defineProperty(HTMLTemplateElement.prototype,"content",Z));var $=new I,_=new I,ab=new I;o.prototype=H({close:function(){this.closed||(this.iterator.inputs.unbind(this.property),this.iterator=void 0,this.node=void 0,this.model=void 0,this.closed=!0)}}),i(HTMLTemplateElement.prototype,{bind:function(a,b,c){if(a!==J&&a!==K&&a!==L)return HTMLElement.prototype.bind.call(this,a,b,c);var d=E.getOrCreate(this);return this.unbind(a),this.bindings[a]=new o(this,a,b,c,d)},createInstance:function(a,b,c){var d=this.ref.content,e=X.get(d);e||(e=A(d)||[],X.set(d,e));var f=e.hasSubTemplate?z(d):d.cloneNode(!0);return x(f,e,a,b,c),C(f,a),f},get model(){return $.get(this)},set model(a){$.set(this,a),n(this)},get bindingDelegate(){return _.get(this)},set bindingDelegate(a){_.set(this,a),n(this)},get ref(){var a,b=this.getAttribute("ref");if(b){var d=c(this);d&&(a=d.getElementById(b))}if(a||(a=W.get(this)),!a)return this;var e=a.ref;return e?e:a}});var bb=new I;Object.defineProperty(Node.prototype,"templateInstance",{get:function(){var a=bb.get(this);return a?a:this.parentNode?this.parentNode.templateInstance:void 0}}),D.prototype={set combinator(a){this.combinator_=a,this.scheduleResolve()},pathValueChanged:function(a,b,c){this.values[c]=a,this.scheduleResolve()},bind:function(a,b,c){this.unbind(a),this.size++;var d=new PathObserver(b,c,this.pathValueChanged,this,a);this.observers[a]=d,this.pathValueChanged(d.value,void 0,a)},unbind:function(a,b){this.observers[a]&&(this.size--,this.observers[a].close(),delete this.observers[a],delete this.values[a],b||this.scheduleResolve())},scheduleResolve:function(){this.scheduled||(this.scheduled=!0,S(this))},resolve:function(){if(!this.closed){if(!this.combinator_)throw Error("CompoundBinding attempted to resolve without a combinator");this.value=this.combinator_(this.values),this.scheduled=!1}},unobserved:function(){this.close()},close:function(){this.closed||(Object.keys(this.observers).forEach(function(a){this.unbind(a,!0)},this),this.closed=!0,this.value=void 0)}},E.templateTable=new I,E.get=function(a){return E.templateTable.get(a)},E.getOrCreate=function(a){return E.get(a)||new E(a)},E.prototype={resolveInputs:function(a){this.closed||(L in a&&!a[L]?this.valueChanged(void 0):K in a?this.valueChanged(a[K]):J in a||L in a?this.valueChanged([a[J]]):this.valueChanged(void 0))},valueChanged:function(a){Array.isArray(a)||(a=void 0);var b=this.iteratedValue;this.unobserve(),this.iteratedValue=a,this.iteratedValue&&(this.arrayObserver=new ArrayObserver(this.iteratedValue,this.handleSplices,this));var c=ArrayObserver.calculateSplices(this.iteratedValue||[],b||[]);c.length&&this.handleSplices(c),this.inputs.size||this.close()},getTerminatorAt:function(a){if(-1==a)return this.templateElement_;var b=this.terminators[2*a];if(b.nodeType!==Node.ELEMENT_NODE||this.templateElement_===b)return b;var c=E.get(b);return c?c.getTerminatorAt(c.terminators.length/2-1):b},insertInstanceAt:function(a,b,c,d){var e=this.getTerminatorAt(a-1),f=e;b?f=b.lastChild||f:c&&(f=c[c.length-1]||f),this.terminators.splice(2*a,0,f,d);var g=this.templateElement_.parentNode,h=e.nextSibling;if(b)g.insertBefore(b,h);else if(c)for(var i=0;i<c.length;i++)g.insertBefore(c[i],h)},extractInstanceAt:function(a){var b=[],c=this.getTerminatorAt(a-1),d=this.getTerminatorAt(a);b.bound=this.terminators[2*a+1],this.terminators.splice(2*a,2);for(var e=this.templateElement_.parentNode;d!==c;){var f=c.nextSibling;f==d&&(d=c),e.removeChild(f),b.push(f)}return b},getInstanceModel:function(a,b,c){var d=c&&c[N];return d&&"function"==typeof d?d(a,b):b},handleSplices:function(a){if(!this.closed){var b=this.templateElement_;if(!b.parentNode||!b.ownerDocument.defaultView)return this.close(),void 0;var c=b.bindingDelegate,d=new F,e=0;a.forEach(function(a){a.removed.forEach(function(b){var c=this.extractInstanceAt(a.index+e);d.set(b,c)},this),e-=a.addedCount},this),a.forEach(function(a){for(var e=a.index;e<a.index+a.addedCount;e++){var f,g=this.iteratedValue[e],h=void 0,i=d.get(g);if(i)d.delete(g),f=i.bound;else{f=[];var j=this.getInstanceModel(b,g,c);void 0!==g&&(h=this.templateElement_.createInstance(j,c,f))}this.insertInstanceAt(e,h,i,f)}},this),d.forEach(function(a){this.closeInstanceBindings(a.bound)},this)}},closeInstanceBindings:function(a){for(var b=0;b<a.length;b++)a[b].close()},unobserve:function(){this.arrayObserver&&(this.arrayObserver.close(),this.arrayObserver=void 0)},close:function(){if(!this.closed){this.unobserve();for(var a=1;a<this.terminators.length;a+=2)this.closeInstanceBindings(this.terminators[a]);this.terminators.length=0,this.inputs.close(),E.templateTable.delete(this.templateElement_),this.closed=!0}}},a.CompoundBinding=D,HTMLTemplateElement.forAllTemplatesFrom_=g}(this),function(a){"use strict";function b(a,b){if(!a)throw new Error("ASSERT: "+b)}function c(a){return a>=48&&57>=a}function d(a){return 32===a||9===a||11===a||12===a||160===a||a>=5760&&" ᠎              ".indexOf(String.fromCharCode(a))>0}function e(a){return 10===a||13===a||8232===a||8233===a}function f(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a}function g(a){return 36===a||95===a||a>=65&&90>=a||a>=97&&122>=a||a>=48&&57>=a}function h(a){return"this"===a}function i(){for(;bb>ab&&d(_.charCodeAt(ab));)++ab}function j(){var a,b;for(a=ab++;bb>ab&&(b=_.charCodeAt(ab),g(b));)++ab;return _.slice(a,ab)}function k(){var a,b,c;return a=ab,b=j(),c=1===b.length?X.Identifier:h(b)?X.Keyword:"null"===b?X.NullLiteral:"true"===b||"false"===b?X.BooleanLiteral:X.Identifier,{type:c,value:b,range:[a,ab]}}function l(){var a,b,c,d,e=ab,f=_.charCodeAt(ab),g=_[ab];switch(f){case 46:case 40:case 41:case 59:case 44:case 123:case 125:case 91:case 93:case 58:case 63:case 126:return++ab,{type:X.Punctuator,value:String.fromCharCode(f),range:[e,ab]};default:if(a=_.charCodeAt(ab+1),61===a)switch(f){case 37:case 38:case 42:case 43:case 45:case 47:case 60:case 62:case 94:case 124:return ab+=2,{type:X.Punctuator,value:String.fromCharCode(f)+String.fromCharCode(a),range:[e,ab]};case 33:case 61:return ab+=2,61===_.charCodeAt(ab)&&++ab,{type:X.Punctuator,value:_.slice(e,ab),range:[e,ab]}}}return b=_[ab+1],c=_[ab+2],d=_[ab+3],">"===g&&">"===b&&">"===c&&"="===d?(ab+=4,{type:X.Punctuator,value:">>>=",range:[e,ab]}):">"===g&&">"===b&&">"===c?(ab+=3,{type:X.Punctuator,value:">>>",range:[e,ab]}):"<"===g&&"<"===b&&"="===c?(ab+=3,{type:X.Punctuator,value:"<<=",range:[e,ab]}):">"===g&&">"===b&&"="===c?(ab+=3,{type:X.Punctuator,value:">>=",range:[e,ab]}):g===b&&"+-<>&|".indexOf(g)>=0?(ab+=2,{type:X.Punctuator,value:g+b,range:[e,ab]}):"<>=!+-*%&|^/".indexOf(g)>=0?(++ab,{type:X.Punctuator,value:g,range:[e,ab]}):(s({},$.UnexpectedToken,"ILLEGAL"),void 0)}function m(){var a,d,e;if(e=_[ab],b(c(e.charCodeAt(0))||"."===e,"Numeric literal must start with a decimal digit or a decimal point"),d=ab,a="","."!==e){for(a=_[ab++],e=_[ab],"0"===a&&e&&c(e.charCodeAt(0))&&s({},$.UnexpectedToken,"ILLEGAL");c(_.charCodeAt(ab));)a+=_[ab++];e=_[ab]}if("."===e){for(a+=_[ab++];c(_.charCodeAt(ab));)a+=_[ab++];e=_[ab]}if("e"===e||"E"===e)if(a+=_[ab++],e=_[ab],("+"===e||"-"===e)&&(a+=_[ab++]),c(_.charCodeAt(ab)))for(;c(_.charCodeAt(ab));)a+=_[ab++];else s({},$.UnexpectedToken,"ILLEGAL");return f(_.charCodeAt(ab))&&s({},$.UnexpectedToken,"ILLEGAL"),{type:X.NumericLiteral,value:parseFloat(a),range:[d,ab]}}function n(){var a,c,d,f="",g=!1;for(a=_[ab],b("'"===a||'"'===a,"String literal must starts with a quote"),c=ab,++ab;bb>ab;){if(d=_[ab++],d===a){a="";break}if("\\"===d)if(d=_[ab++],d&&e(d.charCodeAt(0)))"\r"===d&&"\n"===_[ab]&&++ab;else switch(d){case"n":f+="\n";break;case"r":f+="\r";break;case"t":f+="	";break;case"b":f+="\b";break;case"f":f+="\f";break;case"v":f+="";break;default:f+=d}else{if(e(d.charCodeAt(0)))break;f+=d}}return""!==a&&s({},$.UnexpectedToken,"ILLEGAL"),{type:X.StringLiteral,value:f,octal:g,range:[c,ab]}}function o(a){return a.type===X.Identifier||a.type===X.Keyword||a.type===X.BooleanLiteral||a.type===X.NullLiteral}function p(){var a;return i(),ab>=bb?{type:X.EOF,range:[ab,ab]}:(a=_.charCodeAt(ab),40===a||41===a||58===a?l():39===a||34===a?n():f(a)?k():46===a?c(_.charCodeAt(ab+1))?m():l():c(a)?m():l())}function q(){var a;return a=db,ab=a.range[1],db=p(),ab=a.range[1],a}function r(){var a;a=ab,db=p(),ab=a}function s(a,c){var d,e=Array.prototype.slice.call(arguments,2),f=c.replace(/%(\d)/g,function(a,c){return b(c<e.length,"Message reference must be in range"),e[c]});throw d=new Error(f),d.index=ab,d.description=f,d}function t(a){s(a,$.UnexpectedToken,a.value)}function u(a){var b=q();(b.type!==X.Punctuator||b.value!==a)&&t(b)}function v(a){return db.type===X.Punctuator&&db.value===a}function w(a){return db.type===X.Keyword&&db.value===a}function x(){return 59===_.charCodeAt(ab)?(q(),void 0):(i(),v(";")?(q(),void 0):(db.type===X.EOF||v("}")||t(db),void 0))}function y(){var a=[];for(u("[");!v("]");)v(",")?(q(),a.push(null)):(a.push(O()),v("]")||u(","));return u("]"),cb.createArrayExpression(a)}function z(){var a;return i(),a=q(),a.type===X.StringLiteral||a.type===X.NumericLiteral?cb.createLiteral(a):cb.createIdentifier(a.value)}function A(){var a,b;return a=db,i(),(a.type===X.EOF||a.type===X.Punctuator)&&t(a),b=z(),u(":"),cb.createProperty("init",b,O())}function B(){var a=[];for(u("{");!v("}");)a.push(A()),v("}")||u(",");return u("}"),cb.createObjectExpression(a)}function C(){var a;return u("("),a=P(),u(")"),a}function D(){var a,b,c;return v("(")?C():(a=db.type,a===X.Identifier?c=cb.createIdentifier(q().value):a===X.StringLiteral||a===X.NumericLiteral?c=cb.createLiteral(q()):a===X.Keyword?w("this")&&(q(),c=cb.createThisExpression()):a===X.BooleanLiteral?(b=q(),b.value="true"===b.value,c=cb.createLiteral(b)):a===X.NullLiteral?(b=q(),b.value=null,c=cb.createLiteral(b)):v("[")?c=y():v("{")&&(c=B()),c?c:(t(q()),void 0))}function E(){var a=[];if(u("("),!v(")"))for(;bb>ab&&(a.push(O()),!v(")"));)u(",");return u(")"),a}function F(){var a;return a=q(),o(a)||t(a),cb.createIdentifier(a.value)}function G(){return u("."),F()}function H(){var a;return u("["),a=P(),u("]"),a}function I(){var a,b,c;for(a=D();v(".")||v("[")||v("(");)v("(")?(b=E(),a=cb.createCallExpression(a,b)):v("[")?(c=H(),a=cb.createMemberExpression("[",a,c)):(c=G(),a=cb.createMemberExpression(".",a,c));return a}function J(){var a;return a=I(),db.type===X.Punctuator&&(v("++")||v("--"))&&s({},$.UnexpectedToken),a}function K(){var a,b;return db.type!==X.Punctuator&&db.type!==X.Keyword?b=J():v("++")||v("--")?s({},$.UnexpectedToken):v("+")||v("-")||v("~")||v("!")?(a=q(),b=K(),b=cb.createUnaryExpression(a.value,b)):w("delete")||w("void")||w("typeof")?s({},$.UnexpectedToken):b=J(),b}function L(a,b){var c=0;if(a.type!==X.Punctuator&&a.type!==X.Keyword)return 0;switch(a.value){case"||":c=1;break;case"&&":c=2;break;case"|":c=3;break;case"^":c=4;break;case"&":c=5;break;case"==":case"!=":case"===":case"!==":c=6;break;case"<":case">":case"<=":case">=":case"instanceof":c=7;break;case"in":c=b?7:0;break;case"<<":case">>":case">>>":c=8;break;case"+":case"-":c=9;break;case"*":case"/":case"%":c=11}return c}function M(){var a,b,c,d,e,f,g,h,i;if(d=eb.allowIn,eb.allowIn=!0,h=K(),b=db,c=L(b,d),0===c)return h;for(b.prec=c,q(),f=K(),e=[h,b,f];(c=L(db,d))>0;){for(;e.length>2&&c<=e[e.length-2].prec;)f=e.pop(),g=e.pop().value,h=e.pop(),a=cb.createBinaryExpression(g,h,f),e.push(a);b=q(),b.prec=c,e.push(b),a=K(),e.push(a)}for(eb.allowIn=d,i=e.length-1,a=e[i];i>1;)a=cb.createBinaryExpression(e[i-1].value,e[i-2],a),i-=2;return a}function N(){var a,b,c,d;return a=M(),v("?")&&(q(),b=eb.allowIn,eb.allowIn=!0,c=O(),eb.allowIn=b,u(":"),d=O(),a=cb.createConditionalExpression(a,c,d)),a}function O(){var a,b,c;return a=db,c=b=N()}function P(){var a;return a=O()}function Q(){return u(";"),cb.createEmptyStatement()}function R(){var a=P();return x(),cb.createExpressionStatement(a)}function S(){var a,b,c,d=db.type;if(d===X.EOF&&t(db),i(),d===X.Punctuator)switch(db.value){case";":return Q();case"(":return R()}return a=P(),a.type===Z.Identifier&&v(":")?(q(),c="$"+a.name,Object.prototype.hasOwnProperty.call(eb.labelSet,c)&&s({},$.Redeclaration,"Label",a.name),eb.labelSet[c]=!0,b=S(),delete eb.labelSet[c],cb.createLabeledStatement(a,b)):(x(),cb.createExpressionStatement(a))}function T(){return db.type===X.Keyword?S():db.type!==X.EOF?S():void 0}function U(){for(var a,b=[];bb>ab&&(a=T(),"undefined"!=typeof a);)b.push(a);return b}function V(){var a;return i(),r(),a=U(),cb.createProgram(a)}function W(a,b){var c;return c=String,"string"==typeof a||a instanceof String||(a=c(a)),cb=b,_=a,ab=0,bb=_.length,db=null,eb={allowIn:!0,labelSet:{}},bb>0&&"undefined"==typeof _[0]&&a instanceof String&&(_=a.valueOf()),V()}var X,Y,Z,$,_,ab,bb,cb,db,eb;X={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},Y={},Y[X.BooleanLiteral]="Boolean",Y[X.EOF]="<end>",Y[X.Identifier]="Identifier",Y[X.Keyword]="Keyword",Y[X.NullLiteral]="Null",Y[X.NumericLiteral]="Numeric",Y[X.Punctuator]="Punctuator",Y[X.StringLiteral]="String",Z={ArrayExpression:"ArrayExpression",BinaryExpression:"BinaryExpression",CallExpression:"CallExpression",ConditionalExpression:"ConditionalExpression",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",Identifier:"Identifier",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ThisExpression:"ThisExpression",UnaryExpression:"UnaryExpression"},$={UnexpectedToken:"Unexpected token %0",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared"},a.esprima={parse:W}}(this),function(a){"use strict";function b(a,b,d,e){if(e.nodeType===Node.ELEMENT_NODE&&"TEMPLATE"===e.tagName&&("bind"===d||"repeat"===d)){var f,g,h=b.match(r);if(h?(f=h[1],g=h[2]):(h=b.match(s),h&&(f=h[2],g=h[1])),h){var i;if(g=g.trim(),g.match(q))i=new CompoundBinding(function(a){return a.path}),i.bind("path",a,g);else try{i=c(a,g)}catch(j){console.error("Invalid expression syntax: "+g,j)}if(i)return t.set(e,f),i}}}function c(a,b){try{var c=new f;if(esprima.parse(b,c),!c.statements.length&&!c.labeledStatements.length)return;if(!c.labeledStatements.length&&c.statements.length>1)throw Error("Multiple unlabelled statements are not allowed.");var e=c.labeledStatements.length?d(c.labeledStatements):e=c.statements[0],g=[];for(var h in c.deps)g.push(h);if(!g.length)return{value:e({})};for(var i=new CompoundBinding(e),j=0;j<g.length;j++)i.bind(g[j],a,g[j]);return i}catch(k){console.error("Invalid expression syntax: "+b,k)}}function d(a){return function(b){for(var c=[],d=0;d<a.length;d++)a[d].body(b)&&c.push(a[d].label);return c.join(" ")}}function e(a,b,c){this.deps=a,this.name=b,this.last=c}function f(){this.statements=[],this.labeledStatements=[],this.deps={},this.currentPath=void 0}function g(){throw Error("Not Implemented")}function h(){}var i;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?i=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;i=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},i.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}();var j="[$_a-zA-Z]",k="[$_a-zA-Z0-9]",l=j+"+"+k+"*",m="("+l+")",n="(?:[0-9]|[1-9]+[0-9]+)",o="(?:"+l+"|"+n+")",p="(?:"+o+")(?:\\."+o+")*",q=new RegExp("^"+p+"$"),r=new RegExp("^"+m+"\\s* in (.*)$"),s=new RegExp("^(.*) as \\s*"+m+"$"),t=new i;e.prototype={getPath:function(){return this.last?this.last.getPath()+"."+this.name:this.name},valueFn:function(){var a=this.getPath();return this.deps[a]=!0,function(b){return b[a]}}};var u={"+":function(a){return+a},"-":function(a){return-a},"!":function(a){return!a}},v={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"*":function(a,b){return a*b},"/":function(a,b){return a/b},"%":function(a,b){return a%b},"<":function(a,b){return b>a},">":function(a,b){return a>b},"<=":function(a,b){return b>=a},">=":function(a,b){return a>=b},"==":function(a,b){return a==b},"!=":function(a,b){return a!=b},"===":function(a,b){return a===b},"!==":function(a,b){return a!==b},"&&":function(a,b){return a&&b},"||":function(a,b){return a||b}};f.prototype={getFn:function(a){return a instanceof e?a.valueFn():a},createProgram:function(){},createExpressionStatement:function(a){return this.statements.push(a),a},createLabeledStatement:function(a,b){return this.labeledStatements.push({label:a.getPath(),body:b instanceof e?b.valueFn():b}),b},createUnaryExpression:function(a,b){if(!u[a])throw Error("Disallowed operator: "+a);return b=this.getFn(b),function(c){return u[a](b(c))}},createBinaryExpression:function(a,b,c){if(!v[a])throw Error("Disallowed operator: "+a);return b=this.getFn(b),c=this.getFn(c),function(d){return v[a](b(d),c(d))}},createConditionalExpression:function(a,b,c){return a=this.getFn(a),b=this.getFn(b),c=this.getFn(c),function(d){return a(d)?b(d):c(d)}},createIdentifier:function(a){var b=new e(this.deps,a);return b.type="Identifier",b},createMemberExpression:function(a,b,c){return new e(this.deps,c.name,b)},createLiteral:function(a){return function(){return a.value}},createArrayExpression:function(a){for(var b=0;b<a.length;b++)a[b]=this.getFn(a[b]);return function(b){for(var c=[],d=0;d<a.length;d++)c.push(a[d](b));return c}},createProperty:function(a,b,c){return{key:b instanceof e?b.getPath():b(),value:c}},createObjectExpression:function(a){for(var b=0;b<a.length;b++)a[b].value=this.getFn(a[b].value);return function(b){for(var c={},d=0;d<a.length;d++)c[a[d].key]=a[d].value(b);return c}},createCallExpression:g,createEmptyStatement:g,createThisExpression:g},h.prototype={getBinding:function(a,d,e,f){return d=d.trim(),d&&!d.match(q)?b(a,d,e,f)||c(a,d,e,f):void 0},getInstanceModel:function(a,b){var c=t.get(a);if(!c)return b;var d=a.templateInstance?a.templateInstance.model:a.model,e=Object.create(d);return e[c]=b,e}},a.PolymerExpressions=h}(this),function(a){function b(){logFlags.data&&console.group("Platform.performMicrotaskCheckpoint()"),c(),logFlags.data&&console.groupEnd()}function c(){a.endOfMicrotask(Platform.performMicrotaskCheckpoint)}var d=document.createElement("style");d.textContent="template {display: none !important;} /* injected by platform.js */";var e=document.querySelector("head");e.insertBefore(d,e.firstChild);var f=125;window.addEventListener("WebComponentsReady",function(){b(),Observer.hasObjectObserve||(a.dirtyPoll=setInterval(c,f))}),a.flush=b,window.dirtyCheck=b}(window.Platform),function(a){function b(a){return d(a,i)}function c(a){return d(a,j)}function d(a,b){return"link"===a.localName&&a.getAttribute("rel")===b}function e(a){return"script"===a.localName}function f(a,b){var c=a;c instanceof Document||(c=document.implementation.createHTMLDocument(i),c.body.innerHTML=a),c._URL=b;var d=c.createElement("base");return d.setAttribute("href",document.baseURI),c.head.appendChild(d),window.HTMLTemplateElement&&HTMLTemplateElement.bootstrap&&HTMLTemplateElement.bootstrap(c),c}a||(a=window.HTMLImports={flags:{}});var g,h=a.xhr,i="import",j="stylesheet",k={documents:{},cache:{},preloadSelectors:["link[rel="+i+"]","element link[rel="+j+"]","template","script[src]:not([type])",'script[src][type="text/javascript"]'].join(","),loader:function(a){return g=new l(k.loaded,a),g.cache=k.cache,g},load:function(a,b){g=k.loader(b),k.preload(a)},preload:function(a){var b=a.querySelectorAll(k.preloadSelectors);b=this.filterMainDocumentNodes(a,b),b=this.extractTemplateNodes(b),g.addNodes(b)},filterMainDocumentNodes:function(a,b){return a===document&&(b=Array.prototype.filter.call(b,function(a){return!e(a)})),b},extractTemplateNodes:function(a){var b=[];return a=Array.prototype.filter.call(a,function(a){if("template"===a.localName){if(a.content){var c=a.content.querySelectorAll("link[rel="+j+"]");c.length&&(b=b.concat(Array.prototype.slice.call(c,0)))}return!1}return!0}),b.length&&(a=a.concat(b)),a
+},loaded:function(a,d,e){if(b(d)){var g=k.documents[a];g||(g=f(e,a),p.resolvePathsInHTML(g),k.documents[a]=g,k.preload(g)),d.import={href:a,ownerNode:d,content:g},d.content=e=g}d.__resource=e,c(d)&&p.resolvePathsInStylesheet(d)}},l=function(a,b){this.onload=a,this.oncomplete=b,this.inflight=0,this.pending={},this.cache={}};l.prototype={addNodes:function(a){this.inflight+=a.length,q(a,this.require,this),this.checkDone()},require:function(a){var b=p.nodeUrl(a);a.__nodeUrl=b,this.dedupe(b,a)||this.fetch(b,a)},dedupe:function(a,b){return this.pending[a]?(this.pending[a].push(b),!0):this.cache[a]?(this.onload(a,b,g.cache[a]),this.tail(),!0):(this.pending[a]=[b],!1)},fetch:function(a,b){var c=function(c,d){this.receive(a,b,c,d)}.bind(this);h.load(a,c)},receive:function(a,b,c,d){c||(g.cache[a]=d),g.pending[a].forEach(function(b){c||this.onload(a,b,d),this.tail()},this),g.pending[a]=null},tail:function(){--this.inflight,this.checkDone()},checkDone:function(){this.inflight||this.oncomplete()}};var m=["href","src","action"],n="["+m.join("],[")+"]",o="{{.*}}",p={nodeUrl:function(a){return p.resolveUrl(p.getDocumentUrl(document),p.hrefOrSrc(a))},hrefOrSrc:function(a){return a.getAttribute("href")||a.getAttribute("src")},documentUrlFromNode:function(a){return p.getDocumentUrl(a.ownerDocument||a)},getDocumentUrl:function(a){var b=a&&(a._URL||a.impl&&a.impl._URL||a.baseURI||a.URL)||"";return b.split("#")[0]},resolveUrl:function(a,b,c){if(this.isAbsUrl(b))return b;var d=this.compressUrl(this.urlToPath(a)+b);return c&&(d=p.makeRelPath(p.getDocumentUrl(document),d)),d},isAbsUrl:function(a){return/(^data:)|(^http[s]?:)|(^\/)/.test(a)},urlToPath:function(a){var b=a.split("/");return b.pop(),b.push(""),b.join("/")},compressUrl:function(a){for(var b,c=a.split("/"),d=0;d<c.length;d++)b=c[d],".."===b&&(c.splice(d-1,2),d-=2);return c.join("/")},makeRelPath:function(a,b){var c,d;for(c=this.compressUrl(a).split("/"),d=this.compressUrl(b).split("/");c.length&&c[0]===d[0];)c.shift(),d.shift();for(var e=0,f=c.length-1;f>e;e++)d.unshift("..");var g=d.join("/");return g},resolvePathsInHTML:function(a,b){b=b||p.documentUrlFromNode(a),p.resolveAttributes(a,b),p.resolveStyleElts(a,b);var c=a.querySelectorAll("template");c&&q(c,function(a){a.content&&p.resolvePathsInHTML(a.content,b)})},resolvePathsInStylesheet:function(a){var b=p.nodeUrl(a);a.__resource=p.resolveCssText(a.__resource,b)},resolveStyleElts:function(a,b){var c=a.querySelectorAll("style");c&&q(c,function(a){a.textContent=p.resolveCssText(a.textContent,b)})},resolveCssText:function(a,b){return a.replace(/url\([^)]*\)/g,function(a){var c=a.replace(/["']/g,"").slice(4,-1);return c=p.resolveUrl(b,c,!0),"url("+c+")"})},resolveAttributes:function(a,b){var c=a&&a.querySelectorAll(n);c&&q(c,function(a){this.resolveNodeAttributes(a,b)},this)},resolveNodeAttributes:function(a,b){m.forEach(function(c){var d=a.attributes[c];if(d&&d.value&&d.value.search(o)<0){var e=p.resolveUrl(b,d.value,!0);d.value=e}})}};h=h||{async:!0,ok:function(a){return a.status>=200&&a.status<300||304===a.status||0===a.status},load:function(b,c,d){var e=new XMLHttpRequest;return(a.flags.debug||a.flags.bust)&&(b+="?"+Math.random()),e.open("GET",b,h.async),e.addEventListener("readystatechange",function(){4===e.readyState&&c.call(d,!h.ok(e)&&e,e.response,b)}),e.send(),e},loadDocument:function(a,b,c){this.load(a,b,c).responseType="document"}};var q=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.path=p,a.xhr=h,a.importer=k,a.getDocumentUrl=p.getDocumentUrl,a.IMPORT_LINK_TYPE=i}(window.HTMLImports),function(a){function b(a){return"link"===a.localName&&a.getAttribute("rel")===f}function c(a){return a.parentNode&&!d(a)&&!e(a)}function d(a){return a.ownerDocument===document||a.ownerDocument.impl===document}function e(a){return a.parentNode&&"element"===a.parentNode.localName}var f="import",g={selectors:["link[rel="+f+"]","link[rel=stylesheet]","style","script:not([type])",'script[type="text/javascript"]'],map:{link:"parseLink",script:"parseScript",style:"parseGeneric"},parse:function(a){if(!a.__importParsed){a.__importParsed=!0;var b=a.querySelectorAll(g.selectors);h(b,function(a){g[g.map[a.localName]](a)})}},parseLink:function(a){b(a)?a.content&&g.parse(a.content):this.parseGeneric(a)},parseGeneric:function(a){c(a)&&document.head.appendChild(a)},parseScript:function(b){if(c(b)){var d=(b.__resource||b.textContent).trim();if(d){var e=b.__nodeUrl;if(!e){var e=a.path.documentUrlFromNode(b),f="["+Math.floor(1e3*(Math.random()+1))+"]",g=d.match(/Polymer\(['"]([^'"]*)/);f=g&&g[1]||f,e+="/"+f+".js"}d+="\n//# sourceURL="+e+"\n",eval.call(window,d)}}}},h=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.parser=g}(HTMLImports),function(){function a(){HTMLImports.importer.load(document,function(){HTMLImports.parser.parse(document),HTMLImports.readyTime=(new Date).getTime(),document.dispatchEvent(new CustomEvent("HTMLImportsLoaded",{bubbles:!0}))})}"function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState?a():window.addEventListener("DOMContentLoaded",a)}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new SideTable,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g}(this),!window.MutationObserver&&(window.MutationObserver=window.WebKitMutationObserver||window.JsMutationObserver,!MutationObserver))throw new Error("no mutation observer support");!function(a){function b(b,f){var g=f||{};if(!b)throw new Error("Name argument must not be empty");if(g.name=b,!g.prototype)throw new Error("Options missing required prototype property");return g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),m(b,g),g.ctor=n(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,a.ready&&a.upgradeAll(document),g.ctor}function c(a){var b=v[a];return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.name,c&&(a.is=a.name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(w(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a,b){l.call(this,a,b,c)}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments),this.attributeChangedCallback&&this.getAttribute(a)!==d&&this.attributeChangedCallback(a,d)}function m(a,b){v[a]=b}function n(a){return function(){return f(a)}}function o(a,b){var c=v[b||a];return c?new c.ctor:w(a,b)}function p(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is")||a.localName,c=v[b];return c&&g(a,c)}}function q(b){var c=x.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var r=a.flags,s=Boolean(document.webkitRegister||document.register),t=!r.register&&s;if(t){document.register=document.register||document.webkitRegister;var u=function(){};a.registry={},a.upgradeElement=u,a.watchShadow=u,a.watchAllShadows=u,a.upgrade=u,a.upgradeAll=u,a.upgradeSubtree=u,a.observeDocument=u,a.upgradeDocument=u,a.takeRecords=u}else{var v={},w=document.createElement.bind(document),x=Node.prototype.cloneNode;document.register=b,document.createElement=o,Node.prototype.cloneNode=q,a.registry=v,a.upgrade=p}a.hasNative=s,a.useNative=t}(window.CustomElements),function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.webkitShadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(j(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return logFlags.dom&&console.group("upgrade:",b.localName),a.upgrade(b),logFlags.dom&&console.groupEnd(),!0}}function i(a){j(a),m(a)&&d(a,function(a){j(a)})}function j(a){(a.enteredDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.group("inserted:",a.localName),m(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?logFlags.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.enteredDocumentCallback&&(logFlags.dom&&console.log("inserted:",a.localName),a.enteredDocumentCallback())),logFlags.dom&&console.groupEnd())}function k(a){l(a),d(a,function(a){l(a)})}function l(a){(a.leftDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.log("removed:",a.localName),m(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?logFlags.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.leftDocumentCallback&&a.leftDocumentCallback()))}function m(a){for(var b=a;b;){if(b==a.ownerDocument)return!0;b=b.parentNode||b.host}}function n(a){if(a.webkitShadowRoot&&!a.webkitShadowRoot.__watched){logFlags.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.webkitShadowRoot;b;)o(b),b=b.olderShadowRoot}}function o(a){a.__watched||(t(a),a.__watched=!0)}function p(a){n(a),d(a,function(){n(a)})}function q(a){switch(a.localName){case"style":case"script":case"template":case void 0:return!0}}function r(a){if(logFlags.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(x(a.addedNodes,function(a){q(a)||g(a)}),x(a.removedNodes,function(a){q(a)||k(a)}))}),logFlags.dom&&console.groupEnd()}function s(){r(w.takeRecords())}function t(a){w.observe(a,{childList:!0,subtree:!0})}function u(a){t(a)}function v(a){logFlags.dom&&console.group("upgradeDocument: ",(a.URL||a._URL||"").split("/").pop()),g(a),logFlags.dom&&console.groupEnd()}var w=new MutationObserver(r),x=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.watchShadow=n,a.watchAllShadows=p,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=u,a.upgradeDocument=v,a.takeRecords=s}(window.CustomElements),function(){function a(a){return"link"===a.localName&&a.getAttribute("rel")===b}var b=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",c={selectors:["link[rel="+b+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(c.selectors);d(b,function(a){c[c.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(b){a(b)&&this.parseImport(b)},parseImport:function(a){a.content&&c.parse(a.content)}},d=Array.prototype.forEach.call.bind(Array.prototype.forEach);CustomElements.parser=c}(),function(){function a(){setTimeout(function(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.body.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))},0)}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState)a();else{var b=window.HTMLImports?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(b,a)}}(),function(){function a(){}var b=document.createElement("style");b.textContent="element {display: none !important;} /* injected by platform.js */";var c=document.querySelector("head");if(c.insertBefore(b,c.firstChild),window.ShadowDOMPolyfill){CustomElements.watchShadow=a,CustomElements.watchAllShadows=a;var d=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],e={};d.forEach(function(a){e[a]=CustomElements[a]}),d.forEach(function(a){CustomElements[a]=function(b){return e[a](wrap(b))}})}}(),function(a){function b(a){e.textContent=c++,d.push(a)}var c=0,d=[],e=document.createTextNode(""),f=window.MutationObserver||window.JsMutationObserver;new f(function(){for(;d.length;)d.shift()()}).observe(e,{characterData:!0}),a.endOfMicrotask=b}(window.Platform),function(a){a=a||{};var b={shadow:function(a){return a?a.shadowRoot||a.webkitShadowRoot:void 0},canTarget:function(a){return a&&Boolean(a.elementFromPoint)},targetingShadow:function(a){var b=this.shadow(a);return this.canTarget(b)?b:void 0},olderShadow:function(a){var b=a.olderShadowRoot;if(!b){var c=a.querySelector("shadow");c&&(b=c.olderShadowRoot)}return b},allShadows:function(a){for(var b=[],c=this.shadow(a);c;)b.push(c),c=this.olderShadow(c);return b},searchRoot:function(a,b,c){if(a){var d,e,f=a.elementFromPoint(b,c);for(e=this.targetingShadow(f);e;){if(d=e.elementFromPoint(b,c)){var g=this.targetingShadow(d);return this.searchRoot(g,b,c)||d}e=this.olderShadow(e)}return f}},owner:function(a){for(var b=a;b.parentNode;)b=b.parentNode;return b},findTarget:function(a){var b=a.clientX,c=a.clientY,d=this.owner(a.target);return d.elementFromPoint(b,c)||(d=document),this.searchRoot(document,b,c)}};a.targetFinding=b,a.findTarget=b.findTarget.bind(b),window.PointerEventsPolyfill=a}(window.PointerEventsPolyfill),function(){function a(a){return'[touch-action="'+a+'"]'}function b(a){return"{ -ms-touch-action: "+a+"; touch-action: "+a+"; }"}var c=["none","auto","pan-x","pan-y",{rule:"pan-x pan-y",selectors:["pan-x pan-y","pan-y pan-x"]}],d="";c.forEach(function(c){d+=String(c)===c?a(c)+b(c):c.selectors.map(a)+b(c.rule)});var e=document.createElement("style");e.textContent=d;var f=document.querySelector("head");f.insertBefore(e,f.firstChild)}(),function(a){function b(a,b){b=b||{};var e=b.buttons;if(void 0===e)switch(b.which){case 1:e=1;break;case 2:e=4;break;case 3:e=2;break;default:e=0}var f;if(c)f=new MouseEvent(a,b);else{f=document.createEvent("MouseEvent");var g={bubbles:!1,cancelable:!1,view:null,detail:null,screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null};Object.keys(g).forEach(function(a){a in b&&(g[a]=b[a])}),f.initMouseEvent(a,g.bubbles,g.cancelable,g.view,g.detail,g.screenX,g.screenY,g.clientX,g.clientY,g.ctrlKey,g.altKey,g.shiftKey,g.metaKey,g.button,g.relatedTarget)}d||Object.defineProperty(f,"buttons",{get:function(){return e},enumerable:!0});var h=0;return h=b.pressure?b.pressure:e?.5:0,Object.defineProperties(f,{pointerId:{value:b.pointerId||0,enumerable:!0},width:{value:b.width||0,enumerable:!0},height:{value:b.height||0,enumerable:!0},pressure:{value:h,enumerable:!0},tiltX:{value:b.tiltX||0,enumerable:!0},tiltY:{value:b.tiltY||0,enumerable:!0},pointerType:{value:b.pointerType||"",enumerable:!0},hwTimestamp:{value:b.hwTimestamp||0,enumerable:!0},isPrimary:{value:b.isPrimary||!1,enumerable:!0}}),f}var c=!1,d=!1;try{var e=new MouseEvent("click",{buttons:1});c=!0,d=1===e.buttons}catch(f){}a.PointerEvent||(a.PointerEvent=b)}(window),function(a){function b(){this.ids=[],this.pointers=[]}b.prototype={set:function(a,b){var c=this.ids.indexOf(a);c>-1?this.pointers[c]=b:(this.ids.push(a),this.pointers.push(b))},has:function(a){return this.ids.indexOf(a)>-1},"delete":function(a){var b=this.ids.indexOf(a);b>-1&&(this.ids.splice(b,1),this.pointers.splice(b,1))},get:function(a){var b=this.ids.indexOf(a);return this.pointers[b]},get size(){return this.pointers.length},clear:function(){this.ids.length=0,this.pointers.length=0},forEach:function(a,b){this.ids.forEach(function(c,d){a.call(b,c,this.pointers[d],this)},this)}},a.PointerMap=window.Map&&Map.prototype.forEach?Map:b}(window.PointerEventsPolyfill),function(a){var b;if("undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0)b=WeakMap;else{var c=Object.defineProperty,d=Object.hasOwnProperty,e=(new Date).getTime()%1e9;b=function(){this.name="__st"+(1e9*Math.random()>>>0)+(e++ +"__")},b.prototype={set:function(a,b){c(a,this.name,{value:b,writable:!0})},get:function(a){return d.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}a.SideTable=b}(window.PointerEventsPolyfill),function(a){var b={targets:new a.SideTable,handledEvents:new a.SideTable,pointermap:new a.PointerMap,eventMap:{},eventSources:{},eventSourceList:[],registerSource:function(a,b){var c=b,d=c.events;d&&(d.forEach(function(a){c[a]&&(this.eventMap[a]=c[a].bind(c))},this),this.eventSources[a]=c,this.eventSourceList.push(c))},register:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.register.call(b,a)},unregister:function(a){for(var b,c=this.eventSourceList.length,d=0;c>d&&(b=this.eventSourceList[d]);d++)b.unregister.call(b,a)},down:function(a){this.fireEvent("pointerdown",a)},move:function(a){this.fireEvent("pointermove",a)},up:function(a){this.fireEvent("pointerup",a)},enter:function(a){a.bubbles=!1,this.fireEvent("pointerenter",a)},leave:function(a){a.bubbles=!1,this.fireEvent("pointerleave",a)},over:function(a){a.bubbles=!0,this.fireEvent("pointerover",a)},out:function(a){a.bubbles=!0,this.fireEvent("pointerout",a)},cancel:function(a){this.fireEvent("pointercancel",a)},leaveOut:function(a){a.target.contains(a.relatedTarget)||this.leave(a),this.out(a)},enterOver:function(a){a.target.contains(a.relatedTarget)||this.enter(a),this.over(a)},eventHandler:function(a){if(!this.handledEvents.get(a)){var b=a.type,c=this.eventMap&&this.eventMap[b];c&&c(a),this.handledEvents.set(a,!0)}},listen:function(a,b){b.forEach(function(b){this.addEvent(a,b)},this)},unlisten:function(a,b){b.forEach(function(b){this.removeEvent(a,b)},this)},addEvent:function(a,b){a.addEventListener(b,this.boundHandler)},removeEvent:function(a,b){a.removeEventListener(b,this.boundHandler)},makeEvent:function(a,b){var c=new PointerEvent(a,b);return this.targets.set(c,this.targets.get(b)||b.target),c},fireEvent:function(a,b){var c=this.makeEvent(a,b);return this.dispatchEvent(c)},cloneEvent:function(a){var b={};for(var c in a)b[c]=a[c];return b},getTarget:function(a){return this.captureInfo&&this.captureInfo.id===a.pointerId?this.captureInfo.target:this.targets.get(a)},setCapture:function(a,b){this.captureInfo&&this.releaseCapture(this.captureInfo.id),this.captureInfo={id:a,target:b};var c=new PointerEvent("gotpointercapture",{bubbles:!0});this.implicitRelease=this.releaseCapture.bind(this,a),document.addEventListener("pointerup",this.implicitRelease),document.addEventListener("pointercancel",this.implicitRelease),this.targets.set(c,b),this.asyncDispatchEvent(c)},releaseCapture:function(a){if(this.captureInfo&&this.captureInfo.id===a){var b=new PointerEvent("lostpointercapture",{bubbles:!0}),c=this.captureInfo.target;this.captureInfo=null,document.removeEventListener("pointerup",this.implicitRelease),document.removeEventListener("pointercancel",this.implicitRelease),this.targets.set(b,c),this.asyncDispatchEvent(b)}},dispatchEvent:function(a){var b=this.getTarget(a);return b?b.dispatchEvent(a):void 0},asyncDispatchEvent:function(a){setTimeout(this.dispatchEvent.bind(this,a),0)}};b.boundHandler=b.eventHandler.bind(b),a.dispatcher=b,a.register=b.register.bind(b),a.unregister=b.unregister.bind(b)}(window.PointerEventsPolyfill),function(a){function b(a,b,c,d){this.addCallback=a.bind(d),this.removeCallback=b.bind(d),this.changedCallback=c.bind(d),g&&(this.observer=new g(this.mutationWatcher.bind(this)))}var c=Array.prototype.forEach.call.bind(Array.prototype.forEach),d=Array.prototype.map.call.bind(Array.prototype.map),e=Array.prototype.slice.call.bind(Array.prototype.slice),f=Array.prototype.filter.call.bind(Array.prototype.filter),g=window.MutationObserver||window.WebKitMutationObserver,h="[touch-action]",i={subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0,attributeFilter:["touch-action"]};b.prototype={watchSubtree:function(b){a.targetFinding.canTarget(b)&&this.observer.observe(b,i)},enableOnSubtree:function(a){this.watchSubtree(a),a===document&&"complete"!==document.readyState?this.installOnLoad():this.installNewSubtree(a)},installNewSubtree:function(a){c(this.findElements(a),this.addElement,this)},findElements:function(a){return a.querySelectorAll?a.querySelectorAll(h):[]},removeElement:function(a){this.removeCallback(a)},addElement:function(a){this.addCallback(a)},elementChanged:function(a,b){this.changedCallback(a,b)},concatLists:function(a,b){return a.concat(e(b))},installOnLoad:function(){document.addEventListener("DOMContentLoaded",this.installNewSubtree.bind(this,document))},isElement:function(a){return a.nodeType===Node.ELEMENT_NODE},flattenMutationTree:function(a){var b=d(a,this.findElements,this);return b.push(f(a,this.isElement)),b.reduce(this.concatLists,[])},mutationWatcher:function(a){a.forEach(this.mutationHandler,this)},mutationHandler:function(a){if("childList"===a.type){var b=this.flattenMutationTree(a.addedNodes);b.forEach(this.addElement,this);var c=this.flattenMutationTree(a.removedNodes);c.forEach(this.removeElement,this)}else"attributes"===a.type&&this.elementChanged(a.target,a.oldValue)}},g||(b.prototype.watchSubtree=function(){console.warn("PointerEventsPolyfill: MutationObservers not found, touch-action will not be dynamically detected")}),a.Installer=b}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher,c=b.pointermap,d=25,e={POINTER_ID:1,POINTER_TYPE:"mouse",events:["mousedown","mousemove","mouseup","mouseover","mouseout"],register:function(a){b.listen(a,this.events)},unregister:function(a){b.unlisten(a,this.events)},lastTouches:[],isEventSimulatedFromTouch:function(a){for(var b,c=this.lastTouches,e=a.clientX,f=a.clientY,g=0,h=c.length;h>g&&(b=c[g]);g++){var i=Math.abs(e-b.x),j=Math.abs(f-b.y);if(d>=i&&d>=j)return!0}},prepareEvent:function(a){var c=b.cloneEvent(a);return c.pointerId=this.POINTER_ID,c.isPrimary=!0,c.pointerType=this.POINTER_TYPE,c},mousedown:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.has(this.POINTER_ID);d&&this.cancel(a);var e=this.prepareEvent(a);c.set(this.POINTER_ID,a),b.down(e)}},mousemove:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.move(c)}},mouseup:function(a){if(!this.isEventSimulatedFromTouch(a)){var d=c.get(this.POINTER_ID);if(d&&d.button===a.button){var e=this.prepareEvent(a);b.up(e),this.cleanupMouse()}}},mouseover:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.enterOver(c)}},mouseout:function(a){if(!this.isEventSimulatedFromTouch(a)){var c=this.prepareEvent(a);b.leaveOut(c)}},cancel:function(a){var c=this.prepareEvent(a);b.cancel(c),this.cleanupMouse()},cleanupMouse:function(){c.delete(this.POINTER_ID)}};a.mouseEvents=e}(window.PointerEventsPolyfill),function(a){var b,c=a.dispatcher,d=a.findTarget,e=a.targetFinding.allShadows.bind(a.targetFinding),f=c.pointermap,g=Array.prototype.map.call.bind(Array.prototype.map),h=2500,i=200,j="touch-action",k="string"==typeof document.head.style.touchAction,l={scrollType:new a.SideTable,events:["touchstart","touchmove","touchend","touchcancel"],register:function(a){k?c.listen(a,this.events):b.enableOnSubtree(a)},unregister:function(a){k&&c.unlisten(a,this.events)},elementAdded:function(a){var b=a.getAttribute(j),d=this.touchActionToScrollType(b);d&&(this.scrollType.set(a,d),c.listen(a,this.events),e(a).forEach(function(a){this.scrollType.set(a,d),c.listen(a,this.events)},this))},elementRemoved:function(a){this.scrollType.delete(a),c.unlisten(a,this.events),e(a).forEach(function(a){this.scrollType.delete(a),c.unlisten(a,this.events)},this)},elementChanged:function(a,b){var c=a.getAttribute(j),d=this.touchActionToScrollType(c),f=this.touchActionToScrollType(b);d&&f?(this.scrollType.set(a,d),e(a).forEach(function(a){this.scrollType.set(a,d)},this)):f?this.elementRemoved(a):d&&this.elementAdded(a)},scrollTypes:{EMITTER:"none",XSCROLLER:"pan-x",YSCROLLER:"pan-y",SCROLLER:/^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/},touchActionToScrollType:function(a){var b=a,c=this.scrollTypes;return"none"===b?"none":b===c.XSCROLLER?"X":b===c.YSCROLLER?"Y":c.SCROLLER.exec(b)?"XY":void 0},POINTER_TYPE:"touch",firstTouch:null,isPrimaryTouch:function(a){return this.firstTouch===a.identifier},setPrimaryTouch:function(a){null===this.firstTouch&&(this.firstTouch=a.identifier,this.firstXY={X:a.clientX,Y:a.clientY},this.scrolling=!1,this.cancelResetClickCount())},removePrimaryTouch:function(a){this.isPrimaryTouch(a)&&(this.firstTouch=null,this.firstXY=null,this.resetClickCount())},clickCount:0,resetId:null,resetClickCount:function(){var a=function(){this.clickCount=0,this.resetId=null}.bind(this);this.resetId=setTimeout(a,i)},cancelResetClickCount:function(){this.resetId&&clearTimeout(this.resetId)},touchToPointer:function(a){var b=c.cloneEvent(a);return b.pointerId=a.identifier+2,b.target=d(b),b.bubbles=!0,b.cancelable=!0,b.detail=this.clickCount,b.button=0,b.buttons=1,b.width=a.webkitRadiusX||a.radiusX||0,b.height=a.webkitRadiusY||a.radiusY||0,b.pressure=a.webkitForce||a.force||.5,b.isPrimary=this.isPrimaryTouch(a),b.pointerType=this.POINTER_TYPE,b},processTouches:function(a,b){var c=a.changedTouches,d=g(c,this.touchToPointer,this);d.forEach(b,this)},shouldScroll:function(a){if(this.firstXY){var b,c=this.scrollType.get(a.currentTarget);if("none"===c)b=!1;else if("XY"===c)b=!0;else{var d=a.changedTouches[0],e=c,f="Y"===c?"X":"Y",g=Math.abs(d["client"+e]-this.firstXY[e]),h=Math.abs(d["client"+f]-this.firstXY[f]);b=g>=h}return this.firstXY=null,b}},findTouch:function(a,b){for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)if(c.identifier===b)return!0},vacuumTouches:function(a){var b=a.touches;if(f.size>=b.length){var c=[];f.forEach(function(a,d){if(1!==a&&!this.findTouch(b,a-2)){var e=d.out;c.push(this.touchToPointer(e))}},this),c.forEach(this.cancelOut,this)}},touchstart:function(a){this.vacuumTouches(a),this.setPrimaryTouch(a.changedTouches[0]),this.dedupSynthMouse(a),this.scrolling||(this.clickCount++,this.processTouches(a,this.overDown))},overDown:function(a){f.set(a.pointerId,{target:a.target,out:a,outTarget:a.target}),c.over(a),c.down(a)},touchmove:function(a){this.scrolling||(this.shouldScroll(a)?(this.scrolling=!0,this.touchcancel(a)):(a.preventDefault(),this.processTouches(a,this.moveOverOut)))},moveOverOut:function(a){var b=a,d=f.get(b.pointerId);if(d){var e=d.out,g=d.outTarget;c.move(b),e&&g!==b.target&&(e.relatedTarget=b.target,b.relatedTarget=g,e.target=g,b.target?(c.leaveOut(e),c.enterOver(b)):(b.target=g,b.relatedTarget=null,this.cancelOut(b))),d.out=b,d.outTarget=b.target}},touchend:function(a){this.dedupSynthMouse(a),this.processTouches(a,this.upOut)
+},upOut:function(a){this.scrolling||(c.up(a),c.out(a)),this.cleanUpPointer(a)},touchcancel:function(a){this.processTouches(a,this.cancelOut)},cancelOut:function(a){c.cancel(a),c.out(a),this.cleanUpPointer(a)},cleanUpPointer:function(a){f.delete(a.pointerId),this.removePrimaryTouch(a)},dedupSynthMouse:function(b){var c=a.mouseEvents.lastTouches,d=b.changedTouches[0];if(this.isPrimaryTouch(d)){var e={x:d.clientX,y:d.clientY};c.push(e);var f=function(a,b){var c=a.indexOf(b);c>-1&&a.splice(c,1)}.bind(null,c,e);setTimeout(f,h)}}};k||(b=new a.Installer(l.elementAdded,l.elementRemoved,l.elementChanged,l)),a.touchEvents=l}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher,c=b.pointermap,d=window.MSPointerEvent&&"number"==typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,e={events:["MSPointerDown","MSPointerMove","MSPointerUp","MSPointerOut","MSPointerOver","MSPointerCancel","MSGotPointerCapture","MSLostPointerCapture"],register:function(a){b.listen(a,this.events)},unregister:function(a){b.unlisten(a,this.events)},POINTER_TYPES:["","unavailable","touch","pen","mouse"],prepareEvent:function(a){var c=a;return d&&(c=b.cloneEvent(a),c.pointerType=this.POINTER_TYPES[a.pointerType]),c},cleanup:function(a){c.delete(a)},MSPointerDown:function(a){c.set(a.pointerId,a);var d=this.prepareEvent(a);b.down(d)},MSPointerMove:function(a){var c=this.prepareEvent(a);b.move(c)},MSPointerUp:function(a){var c=this.prepareEvent(a);b.up(c),this.cleanup(a.pointerId)},MSPointerOut:function(a){var c=this.prepareEvent(a);b.leaveOut(c)},MSPointerOver:function(a){var c=this.prepareEvent(a);b.enterOver(c)},MSPointerCancel:function(a){var c=this.prepareEvent(a);b.cancel(c),this.cleanup(a.pointerId)},MSLostPointerCapture:function(a){var c=b.makeEvent("lostpointercapture",a);b.dispatchEvent(c)},MSGotPointerCapture:function(a){var c=b.makeEvent("gotpointercapture",a);b.dispatchEvent(c)}};a.msEvents=e}(window.PointerEventsPolyfill),function(a){var b=a.dispatcher;if(void 0===window.navigator.pointerEnabled){if(Object.defineProperty(window.navigator,"pointerEnabled",{value:!0,enumerable:!0}),window.navigator.msPointerEnabled){var c=window.navigator.msMaxTouchPoints;Object.defineProperty(window.navigator,"maxTouchPoints",{value:c,enumerable:!0}),b.registerSource("ms",a.msEvents)}else b.registerSource("mouse",a.mouseEvents),void 0!==window.ontouchstart&&b.registerSource("touch",a.touchEvents);b.register(document)}}(window.PointerEventsPolyfill),function(a){function b(a){if(!e.pointermap.has(a))throw new Error("InvalidPointerId")}var c,d,e=a.dispatcher,f=window.navigator;f.msPointerEnabled?(c=function(a){b(a),this.msSetPointerCapture(a)},d=function(a){b(a),this.msReleasePointerCapture(a)}):(c=function(a){b(a),e.setCapture(a,this)},d=function(a){b(a),e.releaseCapture(a,this)}),Element.prototype.setPointerCapture||Object.defineProperties(Element.prototype,{setPointerCapture:{value:c},releasePointerCapture:{value:d}})}(window.PointerEventsPolyfill),PointerGestureEvent.prototype.preventTap=function(){this.tapPrevented=!0},function(a){a=a||{},a.utils={LCA:{find:function(a,b){if(a===b)return a;if(a.contains){if(a.contains(b))return a;if(b.contains(a))return b}var c=this.depth(a),d=this.depth(b),e=c-d;for(e>0?a=this.walk(a,e):b=this.walk(b,-e);a&&b&&a!==b;)a=this.walk(a,1),b=this.walk(b,1);return a},walk:function(a,b){for(var c=0;b>c;c++)a=a.parentNode;return a},depth:function(a){for(var b=0;a;)b++,a=a.parentNode;return b}}},a.findLCA=function(b,c){return a.utils.LCA.find(b,c)},window.PointerGestures=a}(window.PointerGestures),function(a){var b;if("undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0)b=WeakMap;else{var c=Object.defineProperty,d=Object.hasOwnProperty,e=(new Date).getTime()%1e9;b=function(){this.name="__st"+(1e9*Math.random()>>>0)+(e++ +"__")},b.prototype={set:function(a,b){c(a,this.name,{value:b,writable:!0})},get:function(a){return d.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}a.SideTable=b}(window.PointerGestures),function(a){function b(){this.ids=[],this.pointers=[]}b.prototype={set:function(a,b){var c=this.ids.indexOf(a);c>-1?this.pointers[c]=b:(this.ids.push(a),this.pointers.push(b))},has:function(a){return this.ids.indexOf(a)>-1},"delete":function(a){var b=this.ids.indexOf(a);b>-1&&(this.ids.splice(b,1),this.pointers.splice(b,1))},get:function(a){var b=this.ids.indexOf(a);return this.pointers[b]},get size(){return this.pointers.length},clear:function(){this.ids.length=0,this.pointers.length=0}},window.Map&&(b=window.Map),a.PointerMap=b}(window.PointerGestures),function(a){var b={handledEvents:new a.SideTable,targets:new a.SideTable,handlers:{},recognizers:{},events:["pointerdown","pointermove","pointerup","pointerover","pointerout","pointercancel"],registerRecognizer:function(a,b){var c=b;this.recognizers[a]=c,this.events.forEach(function(a){if(c[a]){var b=c[a].bind(c);this.addHandler(a,b)}},this)},addHandler:function(a,b){var c=a;this.handlers[c]||(this.handlers[c]=[]),this.handlers[c].push(b)},registerTarget:function(a){this.listen(this.events,a)},unregisterTarget:function(a){this.unlisten(this.events,a)},eventHandler:function(a){if(!this.handledEvents.get(a)){var b,c=a.type;(b=this.handlers[c])&&this.makeQueue(b,a),this.handledEvents.set(a,!0)}},makeQueue:function(a,b){var c=this.cloneEvent(b);setTimeout(this.runQueue.bind(this,a,c),0)},runQueue:function(a,b){this.currentPointerId=b.pointerId;for(var c,d=0,e=a.length;e>d&&(c=a[d]);d++)c(b);this.currentPointerId=0},listen:function(a,b){a.forEach(function(a){this.addEvent(a,this.boundHandler,!1,b)},this)},unlisten:function(a){a.forEach(function(a){this.removeEvent(a,this.boundHandler,!1,inTarget)},this)},addEvent:function(a,b,c,d){d.addEventListener(a,b,c)},removeEvent:function(a,b,c,d){d.removeEventListener(a,b,c)},makeEvent:function(a,b){return new PointerGestureEvent(a,b)},cloneEvent:function(a){var b={};for(var c in a)b[c]=a[c];return b},dispatchEvent:function(a,b){var c=b||this.targets.get(a);c&&(c.dispatchEvent(a),a.tapPrevented&&this.preventTap(this.currentPointerId))},asyncDispatchEvent:function(a,b){var c=function(){this.dispatchEvent(a,b)}.bind(this);setTimeout(c,0)},preventTap:function(a){var b=this.recognizers.tap;b&&b.preventTap(a)}};b.boundHandler=b.eventHandler.bind(b),a.dispatcher=b,a.register=function(b){var c=window.PointerEventsPolyfill;c&&c.register(b),a.dispatcher.registerTarget(b)},b.registerTarget(document)}(window.PointerGestures),function(a){var b=a.dispatcher,c={HOLD_DELAY:200,WIGGLE_THRESHOLD:16,events:["pointerdown","pointermove","pointerup","pointercancel"],heldPointer:null,holdJob:null,pulse:function(){var a=Date.now()-this.heldPointer.timeStamp,b=this.held?"holdpulse":"hold";this.fireHold(b,a),this.held=!0},cancel:function(){clearInterval(this.holdJob),this.held&&this.fireHold("release"),this.held=!1,this.heldPointer=null,this.target=null,this.holdJob=null},pointerdown:function(a){a.isPrimary&&!this.heldPointer&&(this.heldPointer=a,this.target=a.target,this.holdJob=setInterval(this.pulse.bind(this),this.HOLD_DELAY))},pointerup:function(a){this.heldPointer&&this.heldPointer.pointerId===a.pointerId&&this.cancel()},pointercancel:function(){this.cancel()},pointermove:function(a){if(this.heldPointer&&this.heldPointer.pointerId===a.pointerId){var b=a.clientX-this.heldPointer.clientX,c=a.clientY-this.heldPointer.clientY;b*b+c*c>this.WIGGLE_THRESHOLD&&this.cancel()}},fireHold:function(a,c){var d={pointerType:this.heldPointer.pointerType};c&&(d.holdTime=c);var e=b.makeEvent(a,d);b.dispatchEvent(e,this.target),e.tapPrevented&&b.preventTap(this.heldPointer.pointerId)}};b.registerRecognizer("hold",c)}(window.PointerGestures),function(a){var b=a.dispatcher,c=new a.PointerMap,d={events:["pointerdown","pointermove","pointerup","pointercancel"],WIGGLE_THRESHOLD:4,clampDir:function(a){return a>0?1:-1},calcPositionDelta:function(a,b){var c=0,d=0;return a&&b&&(c=b.pageX-a.pageX,d=b.pageY-a.pageY),{x:c,y:d}},fireTrack:function(a,c,d){var e=d,f=this.calcPositionDelta(e.downEvent,c),g=this.calcPositionDelta(e.lastMoveEvent,c);g.x&&(e.xDirection=this.clampDir(g.x)),g.y&&(e.yDirection=this.clampDir(g.y));var h={dx:f.x,dy:f.y,ddx:g.x,ddy:g.y,clientX:c.clientX,clientY:c.clientY,pageX:c.pageX,pageY:c.pageY,screenX:c.screenX,screenY:c.screenY,xDirection:e.xDirection,yDirection:e.yDirection,trackInfo:e.trackInfo,pointerType:c.pointerType};"trackend"===a&&(h._releaseTarget=c.target);var i=b.makeEvent(a,h);e.lastMoveEvent=c,b.dispatchEvent(i,e.downTarget)},pointerdown:function(a){if(a.isPrimary&&("mouse"===a.pointerType?1===a.buttons:!0)){var b={downEvent:a,downTarget:a.target,trackInfo:{},lastMoveEvent:null,xDirection:0,yDirection:0,tracking:!1};c.set(a.pointerId,b)}},pointermove:function(a){var b=c.get(a.pointerId);if(b)if(b.tracking)this.fireTrack("track",a,b);else{var d=this.calcPositionDelta(b.downEvent,a),e=d.x*d.x+d.y*d.y;e>this.WIGGLE_THRESHOLD&&(b.tracking=!0,this.fireTrack("trackstart",b.downEvent,b),this.fireTrack("track",a,b))}},pointerup:function(a){var b=c.get(a.pointerId);b&&(b.tracking&&this.fireTrack("trackend",a,b),c.delete(a.pointerId))},pointercancel:function(a){this.pointerup(a)}};b.registerRecognizer("track",d)}(window.PointerGestures),function(a){var b=a.dispatcher,c={MIN_VELOCITY:.5,MAX_QUEUE:4,moveQueue:[],target:null,pointerId:null,events:["pointerdown","pointermove","pointerup","pointercancel"],pointerdown:function(a){a.isPrimary&&!this.pointerId&&(this.pointerId=a.pointerId,this.target=a.target,this.addMove(a))},pointermove:function(a){a.pointerId===this.pointerId&&this.addMove(a)},pointerup:function(a){a.pointerId===this.pointerId&&this.fireFlick(a),this.cleanup()},pointercancel:function(){this.cleanup()},cleanup:function(){this.moveQueue=[],this.target=null,this.pointerId=null},addMove:function(a){this.moveQueue.length>=this.MAX_QUEUE&&this.moveQueue.shift(),this.moveQueue.push(a)},fireFlick:function(a){for(var c,d,e,f,g,h,i,j=a,k=this.moveQueue.length,l=0,m=0,n=0,o=0;k>o&&(i=this.moveQueue[o]);o++)c=j.timeStamp-i.timeStamp,d=j.clientX-i.clientX,e=j.clientY-i.clientY,f=d/c,g=e/c,h=Math.sqrt(f*f+g*g),h>n&&(l=f,m=g,n=h);var p=Math.abs(l)>Math.abs(m)?"x":"y",q=this.calcAngle(l,m);if(Math.abs(n)>=this.MIN_VELOCITY){var r=b.makeEvent("flick",{xVelocity:l,yVelocity:m,velocity:n,angle:q,majorAxis:p,pointerType:a.pointerType});b.dispatchEvent(r,this.target)}},calcAngle:function(a,b){return 180*Math.atan2(b,a)/Math.PI}};b.registerRecognizer("flick",c)}(window.PointerGestures),function(a){var b=a.dispatcher,c=new a.PointerMap,d={events:["pointerdown","pointermove","pointerup","pointercancel"],pointerdown:function(a){a.isPrimary&&!a.tapPrevented&&c.set(a.pointerId,{target:a.target,x:a.clientX,y:a.clientY})},pointermove:function(a){if(a.isPrimary){var b=c.get(a.pointerId);b&&a.tapPrevented&&c.delete(a.pointerId)}},pointerup:function(d){var e=c.get(d.pointerId);if(e&&!d.tapPrevented){var f=a.findLCA(e.target,d.target);if(f){var g=b.makeEvent("tap",{x:d.clientX,y:d.clientY,detail:d.detail,pointerType:d.pointerType});b.dispatchEvent(g,f)}}c.delete(d.pointerId)},pointercancel:function(a){c.delete(a.pointerId)},preventTap:function(a){c.delete(a)}};b.registerRecognizer("tap",d)}(window.PointerGestures),Polymer={},function(){var a=document.createElement("style");a.textContent="body {opacity: 0;}";var b=document.querySelector("head");b.insertBefore(a,b.firstChild),window.addEventListener("WebComponentsReady",function(){document.body.style.webkitTransition="opacity 0.3s",document.body.style.opacity=1})}(Polymer),function(a){function b(a,b){return a&&b&&Object.getOwnPropertyNames(b).forEach(function(c){var d=Object.getOwnPropertyDescriptor(b,c);d&&(Object.defineProperty(a,c,d),"function"==typeof d.value&&(a[c].nom=c))}),a}a.extend=b}(Polymer),function(a){function b(a,b,d){return a?a.stop():a=new c(this),a.go(b,d),a}var c=function(a){this.context=a};c.prototype={go:function(a,b){this.callback=a,this.handle=setTimeout(this.complete.bind(this),b)},stop:function(){this.handle&&(clearTimeout(this.handle),this.handle=null)},complete:function(){this.handle&&(this.stop(),this.callback.call(this.context))}},a.job=b}(Polymer),function(){var a={};HTMLElement.register=function(b,c){a[b]=c},HTMLElement.getPrototypeForTag=function(b){var c=b?a[b]:HTMLElement.prototype;return c||Object.getPrototypeOf(document.createElement(b))};var b=Event.prototype.stopPropagation;Event.prototype.stopPropagation=function(){this.cancelBubble=!0,b.apply(this,arguments)},HTMLImports.importer.preloadSelectors+=", polymer-element link[rel=stylesheet]"}(Polymer),function(a){function b(a){var c=b.caller,g=c.nom;"_super"in c||(g||(g=e.call(this,c)),g||console.warn("called super() on a method not installed declaratively (has no .nom property)"),d(c,g,f(this)));var h=c._super;if(h){var i=h[g];return"_super"in i||d(i,g,h),i.apply(this,a||[])}}function c(a,b,c){for(;a&&(!a.hasOwnProperty(b)||a[b]===c);)a=f(a);return a}function d(a,b,d){return a._super=c(d,b,a),a._super&&(a._super[b].nom=b),a._super}function e(a){console.warn("nameInThis called");for(var b=this;b&&b!==HTMLElement.prototype;){for(var c,d=Object.getOwnPropertyNames(b),e=0,f=d.length;f>e&&(c=d[e]);e++){var g=Object.getOwnPropertyDescriptor(b,c);if(g.value==a)return c}b=b.__proto__}}function f(a){return a.__proto__}a.super=b}(Polymer),function(a){function b(a,b){var d=typeof b;return b instanceof Date&&(d="date"),c[d](a,b)}var c={string:function(a){return a},date:function(a){return new Date(Date.parse(a)||Date.now())},"boolean":function(a){return""===a?!0:"false"===a?!1:!!a},number:function(a){var b=parseFloat(a);return String(b)===a?b:a},object:function(a,b){if(null===b)return a;try{return JSON.parse(a.replace(/'/g,'"'))}catch(c){return a}}};a.deserializeValue=b}(Polymer),function(a){var b={};b.declaration={},b.instance={},a.api=b}(Polymer),function(a){var b={async:function(a,b,c){Platform.flush(),b=b&&b.length?b:[b];var d=function(){(this[a]||a).apply(this,b)}.bind(this);return c?setTimeout(d,c):requestAnimationFrame(d)},fire:function(a,b,c,d){var e=c||this;return e.dispatchEvent(new CustomEvent(a,{bubbles:void 0!==d?!1:!0,detail:b})),b},asyncFire:function(){this.asyncMethod("fire",arguments)},classFollows:function(a,b,c){b&&b.classList.remove(c),a&&a.classList.add(c)}};b.asyncMethod=b.async,a.api.instance.utils=b}(Polymer),function(a){function b(a,b){b.cancelBubble||(b.on=i+b.type,h.events&&console.group("[%s]: listenLocal [%s]",a.localName,b.on),b.path?c(a,b):d(a,b),h.events&&console.groupEnd())}function c(a,b){var c=null;Array.prototype.some.call(b.path,function(d){return d===a?!0:(c=c===a?c:e(d),c&&f(c,d,b)?!0:void 0)},this)}function d(a,b){h.events&&console.log("event.path() not supported for",b.type);for(var c=b.target,d=null;c&&c!=a;){if(d=d===a?d:e(c),d&&f(d,c,b))return!0;c=c.parentNode}}function e(a){for(;a.parentNode;)a=a.parentNode;return a.host}function f(a,b,c){var d=b.getAttribute&&b.getAttribute(c.on);return d&&g(b,c)&&(h.events&&console.log("[%s] found handler name [%s]",a.localName,d),a.dispatchMethod(b,d,[c,c.detail,b])),c.cancelBubble}function g(a,b){var c=l.get(b);return c||l.set(b,c=[]),c.indexOf(a)<0?(c.push(a),!0):void 0}var h=window.logFlags||{},i="on-",j="eventDelegates",k={EVENT_PREFIX:i,DELEGATES:j,addHostListeners:function(){var a=this[j];h.events&&Object.keys(a).length>0&&console.log("[%s] addHostListeners:",this.localName,a),this.addNodeListeners(this,a,this.hostEventListener)},addInstanceListeners:function(a,b){var c=b.delegates;c&&(h.events&&Object.keys(c).length>0&&console.log("[%s:root] addInstanceListeners:",this.localName,c),this.addNodeListeners(a,c,this.instanceEventListener))},addNodeListeners:function(a,b,c){var d;for(var e in b)d||(d=c.bind(this)),a.addEventListener(e,d)},hostEventListener:function(a){if(!a.cancelBubble){h.events&&console.group("[%s]: hostEventListener(%s)",this.localName,a.type);var b=this.findEventDelegate(a);b&&(h.events&&console.log("[%s] found host handler name [%s]",this.localName,b),this.dispatchMethod(this,b,[a,a.detail,this])),h.events&&console.groupEnd()}},findEventDelegate:function(a){return this[j][a.type]},dispatchMethod:function(a,b,c){if(a){h.events&&console.group("[%s] dispatch [%s]",a.localName,b);var d=this[b];d&&d[c?"apply":"call"](this,c),h.events&&console.groupEnd()}},instanceEventListener:function(a){b(this,a)}},l=new SideTable("handledList");a.api.instance.events=k}(Polymer),function(a){var b="__published",c="__instance_attributes",d={PUBLISHED:b,INSTANCE_ATTRIBUTES:c,copyInstanceAttributes:function(){var a=this[c];for(var b in a)this.setAttribute(b,a[b])},takeAttributes:function(){for(var a,b=0,c=this.attributes,d=c.length;(a=c[b])&&d>b;b++)this.attributeToProperty(a.name,a.value)},attributeToProperty:function(b,c){var b=this.propertyForAttribute(b);if(b){if(c.search(a.bindPattern)>=0)return;var d=this[b],c=this.deserializeValue(c,d);c!==d&&(this[b]=c)}},propertyForAttribute:function(a){var c=Object.keys(this[b]);return c[c.map(e).indexOf(a.toLowerCase())]},deserializeValue:function(b,c){return a.deserializeValue(b,c)},serializeValue:function(a){return"object"!=typeof a&&void 0!==a?a:void 0},propertyToAttribute:function(a){if(Object.keys(this[b]).indexOf(a)>=0){var c=this.serializeValue(this[a]);void 0!==c&&this.setAttribute(a,c)}}},e=String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase);a.api.instance.attributes=d}(Polymer),function(a){function b(a,b){var c=this[a]||a;"function"==typeof c&&c.apply(this,b)}function c(a,b,c,d){h.bind&&console.log(o,c.localName||"object",d,a.localName,b);var e=PathObserver.getValueAtPath(c,d);return(null===e||void 0===e)&&PathObserver.setValueAtPath(c,d,a[b]),PathObserver.defineProperty(a,b,{object:c,path:d})}function d(a,b,c){var d=g(a);d[b]=c}function e(a,b){var c=g(a);return c&&c[b]?(c[b].close(),c[b]=null,!0):void 0}function f(a){var b=g(a);Object.keys(b).forEach(function(a){b[a].close(),b[a]=null})}function g(a){var b=l.get(a);return b||l.set(a,b={}),b}var h=window.logFlags||{},i="Changed",j=a.api.instance.attributes.PUBLISHED,k={observeProperties:function(){for(var a,b=this.getCustomPropertyNames(),c=0,d=b.length;d>c&&(a=b[c]);c++)this.observeProperty(a)},getCustomPropertyNames:function(){return this.customPropertyNames},observeProperty:function(a){if(this.shouldObserveProperty(a)){h.watch&&console.log(m,this.localName,a);var b=function(b,c){h.watch&&console.log(n,this.localName,this.id||"",a,this[a],c),this.dispatchPropertyChange(a,c)}.bind(this),c=new PathObserver(this,a,b);d(this,a,c)}},bindProperty:function(a,b,d){return c(this,a,b,d)},unbindProperty:function(a,b){return e(this,a,b)},unbindAllProperties:function(){f(this)},shouldObserveProperty:function(a){return Boolean(this[a+i]||Object.keys(this[j]).indexOf(a)>=0)},dispatchPropertyChange:function(a,c){this.propertyToAttribute(a),b.call(this,a+i,[c])}},l=new SideTable,m="[%s] watching [%s]",n="[%s#%s] watch: [%s] now [%s] was [%s]",o="[%s]: bindProperties: [%s] to [%s].[%s]";a.api.instance.properties=k}(Polymer),function(a){function b(a){d(a,c)}function c(a){a.unbindAll()}function d(a,b){if(a){b(a);for(var c=a.firstChild;c;c=c.nextSibling)d(c,b)}}var e=window.logFlags||0,f=new PolymerExpressions,g={instanceTemplate:function(a){return a.createInstance(this,f)},bind:function(a,b,c){var d=this.propertyForAttribute(a);if(d){this.unbind(a);var e=this.bindProperty(d,b,c);return e.path=c,this.bindings[a]=e}return this.super(arguments)},asyncUnbindAll:function(){this._unbound||(e.unbind&&console.log("[%s] asyncUnbindAll",this.localName),this._unbindAllJob=this.job(this._unbindAllJob,this.unbindAll,0))},unbindAll:function(){this._unbound||(this.unbindAllProperties(),this.super(),b(this.shadowRoot),this._unbound=!0)},cancelUnbindAll:function(a){return this._unbound?(e.unbind&&console.warn("[%s] already unbound, cannot cancel unbindAll",this.localName),void 0):(e.unbind&&console.log("[%s] cancelUnbindAll",this.localName),this._unbindAllJob&&(this._unbindAllJob=this._unbindAllJob.stop()),a||d(this.shadowRoot,function(a){a.cancelUnbindAll&&a.cancelUnbindAll()}),void 0)}},h=/\{\{([^{}]*)}}/;a.bindPattern=h,a.api.instance.mdv=g}(Polymer),function(a){function b(a){return a.hasOwnProperty("PolymerBase")}function c(){}var d={PolymerBase:!0,job:Polymer.job,"super":Polymer.super,created:function(){},ready:function(){},readyCallback:function(){this._createdCallback()},createdCallback:function(){this._createdCallback()},_createdCallback:function(){this.observeProperties(),this.copyInstanceAttributes(),this.takeAttributes(),this.addHostListeners(),this.parseElements(this.__proto__),this.ready(),this.created()},insertedCallback:function(){this._enteredDocumentCallback()},enteredDocumentCallback:function(){this._enteredDocumentCallback()},_enteredDocumentCallback:function(){this.cancelUnbindAll(!0),this.inserted&&this.inserted(),this.enteredDocument&&this.enteredDocument()},removedCallback:function(){this._leftDocumentCallback()},leftDocumentCallback:function(){this._leftDocumentCallback()},_leftDocumentCallback:function(){this.asyncUnbindAll(),this.removed&&this.removed(),this.leftDocument&&this.leftDocument()},parseElements:function(a){a&&a.element&&(this.parseElements(a.__proto__),a.parseElement.call(this,a.element))},parseElement:function(a){this.shadowFromTemplate(this.fetchTemplate(a))},fetchTemplate:function(a){return a.querySelector("template")},shadowFromTemplate:function(a){if(a){this.shadowRoot;var b=this.createShadowRoot();b.applyAuthorStyles=this.applyAuthorStyles,b.resetStyleInheritance=this.resetStyleInheritance;var c=this.instanceTemplate(a);return b.appendChild(c),this.shadowRootReady(b,a),b}},shadowRootReady:function(a,b){this.marshalNodeReferences(a),this.addInstanceListeners(a,b),PointerGestures.register(a)},marshalNodeReferences:function(a){var b=this.$=this.$||{};if(a)for(var c,d=a.querySelectorAll("[id]"),e=0,f=d.length;f>e&&(c=d[e]);e++)b[c.id]=c},attributeChangedCallback:function(a){this.attributeToProperty(a,this.getAttribute(a)),this.attributeChanged&&this.attributeChanged.apply(this,arguments)}};c.prototype=d,d.constructor=c,a.Base=c,a.isBase=b,a.api.instance.base=d}(Polymer),function(a){function b(a){return a.__proto__}window.logFlags||{};var c="element",d="controller",e={STYLE_SCOPE_ATTRIBUTE:c,installControllerStyles:function(){var a=this.findStyleController();if(a&&!this.scopeHasElementStyle(a,d)){for(var c=b(this),e="";c&&c.element;)e+=c.element.cssTextForScope(d),c=b(c);if(e){var f=this.element.cssTextToScopeStyle(e,d);window.ShadowDOMPolyfill&&Platform.ShadowCSS.shimPolyfillDirectives([f],this.localName),Polymer.applyStyleToScope(f,a)}}},scopeHasElementStyle:function(a,b){var d=c+"="+this.localName+"-"+b;return a.querySelector("style["+d+"]")},findStyleController:function(){if(window.ShadowDOMPolyfill)return wrap(document.head);for(var a=this;a.parentNode;)a=a.parentNode;return a===document?document.head:a}};a.api.instance.styles=e}(Polymer),function(a){var b={addResolvePathApi:function(){var a=this.elementPath();this.prototype.resolvePath=function(b){return a+b}},elementPath:function(){return this.urlToPath(HTMLImports.getDocumentUrl(this.ownerDocument))},urlToPath:function(a){if(a){var b=a.split("/");return b.pop(),b.push(""),b.join("/")}return""}};a.api.declaration.path=b}(Polymer),function(a){function b(a,b){if(a){var d=c(a.textContent),e=a.getAttribute(g);e&&d.setAttribute(g,e),b.appendChild(d)}}function c(a){var b=document.createElement("style");return b.textContent=a,b}function d(a){return a&&a.__resource||""}function e(a,b){return n?n.call(a,b):void 0}window.logFlags||{};var f=a.api.instance.styles,g=f.STYLE_SCOPE_ATTRIBUTE,h="style",i="[rel=stylesheet]",j="global",k="polymer-scope",l={installSheets:function(){this.cacheSheets(),this.installLocalSheets(),this.installGlobalStyles()},cacheSheets:function(){this.sheets=this.findNodes(i),this.sheets.forEach(function(a){a.parentNode&&a.parentNode.removeChild(a)})},installLocalSheets:function(){var a=this.sheets.filter(function(a){return!a.hasAttribute(k)}),b=this.templateContent();if(b){var e="";a.forEach(function(a){e+=d(a)+"\n"}),e&&b.insertBefore(c(e),b.firstChild)}},findNodes:function(a,b){var c=this.querySelectorAll(a).array(),d=this.templateContent();if(d){var e=d.querySelectorAll(a).array();c=c.concat(e)}return b?c.filter(b):c},templateContent:function(){var a=this.querySelector("template");return a&&templateContent(a)},installGlobalStyles:function(){var a=this.styleForScope(j);b(a,document.head)},cssTextForScope:function(a){var b="",c="["+k+"="+a+"]",f=function(a){return e(a,c)},g=this.sheets.filter(f);g.forEach(function(a){b+=d(a)+"\n\n"});var i=this.findNodes(h,f);return i.forEach(function(a){a.parentNode.removeChild(a),b+=a.textContent+"\n\n"}),b},styleForScope:function(a){var b=this.cssTextForScope(a);return this.cssTextToScopeStyle(b,a)},cssTextToScopeStyle:function(a,b){if(a){var d=c(a);return d.setAttribute(g,this.getAttribute("name")+"-"+b),d}}},m=HTMLElement.prototype,n=m.matches||m.matchesSelector||m.webkitMatchesSelector||m.mozMatchesSelector;a.api.declaration.styles=l,a.applyStyleToScope=b}(Polymer),function(a){function b(a){return a.slice(0,k)==g}function c(a){return a.slice(k)}function d(a){return a.ref?a.ref.content:a.content}var e=a.api.instance.events,f=e.DELEGATES,g=e.EVENT_PREFIX,h=window.logFlags||{},i={inheritDelegates:function(a){this.inheritObject(a,f)},parseHostEvents:function(){var a=this.prototype[f];this.addAttributeDelegates(a)},addAttributeDelegates:function(a){for(var d,e=0;d=this.attributes[e];e++)b(d.name)&&(a[c(d.name)]=d.value)},parseLocalEvents:function(){this.querySelectorAll("template").forEach(function(a){a.delegates={},this.accumulateTemplatedEvents(a,a.delegates),h.events&&console.log("[%s] parseLocalEvents:",this.attributes.name.value,a.delegates)},this)},accumulateTemplatedEvents:function(a,b){if("template"===a.localName){var c=d(a);c&&this.accumulateChildEvents(c,b)}},accumulateChildEvents:function(a,b){a.childNodes.forEach(function(a){this.accumulateEvents(a,b)},this)},accumulateEvents:function(a,b){return this.accumulateAttributeEvents(a,b),this.accumulateChildEvents(a,b),this.accumulateTemplatedEvents(a,b),b},accumulateAttributeEvents:function(a,d){a.attributes&&a.attributes.forEach(function(a){b(a.name)&&this.accumulateEvent(c(a.name),d)},this)},accumulateEvent:function(a,b){a=j[a]||a,b[a]=b[a]||1}},j={webkitanimationstart:"webkitAnimationStart",webkitanimationend:"webkitAnimationEnd",webkittransitionend:"webkitTransitionEnd",domfocusout:"DOMFocusOut",domfocusin:"DOMFocusIn"},k=g.length;i.event_translations=j,a.api.declaration.events=i}(Polymer),function(a){var b=[],c={cacheProperties:function(){this.prototype.customPropertyNames=this.getCustomPropertyNames(this.prototype)},getCustomPropertyNames:function(c){for(var d,e={};c&&!a.isBase(c);){for(var f,g=Object.getOwnPropertyNames(c),h=0,i=g.length;i>h&&(f=g[h]);h++)e[f]=!0,d=!0;c=c.__proto__}return d?Object.keys(e):b}};a.api.declaration.properties=c}(Polymer),function(a){var b=a.api.instance.attributes,c=b.PUBLISHED,d=b.INSTANCE_ATTRIBUTES,e="publish",f="attributes",g={inheritAttributesObjects:function(a){this.inheritObject(a,c),this.inheritObject(a,d)},parseAttributes:function(){this.publishAttributes(this.prototype),this.publishProperties(this.prototype),this.accumulateInstanceAttributes()},publishAttributes:function(a){var b=a[c],d=this.getAttribute(f);if(d){var e=d.split(d.indexOf(",")>=0?",":" ");e.forEach(function(a){a=a.trim(),!a||a in b||(b[a]=null)})}Object.keys(b).forEach(function(c){c in a||(a[c]=b[c])})},publishProperties:function(a){this.publishPublish(a)},publishPublish:function(a){if(a.hasOwnProperty(e)){var b=a[e];b&&(Object.keys(b).forEach(function(c){a[c]=b[c]}),Platform.mixin(a[c],b))}},accumulateInstanceAttributes:function(){var a=this.prototype[d];this.attributes.forEach(function(b){this.isInstanceAttribute(b.name)&&(a[b.name]=b.value)},this)},isInstanceAttribute:function(a){return!this.blackList[a]&&"on-"!==a.slice(0,3)},blackList:{name:1,"extends":1,constructor:1,noscript:1}};g.blackList[f]=1,a.api.declaration.attributes=g}(Polymer),function(a){function b(a){return Object.create(HTMLElement.getPrototypeForTag(a))}function c(a){if(!Object.__proto__){var b=Object.getPrototypeOf(a);a.__proto__=b,e(b)&&(b.__proto__=Object.getPrototypeOf(b))}}var d=a.api,e=a.isBase,f=a.extend,g=b(),g={generateCustomPrototype:function(a,b){var d=this.generateBasePrototype(b);return this.addNamedApi(d,a),c(d),d},generateBasePrototype:function(a){var c=b(a);return this.ensureBaseApi(c)},ensureBaseApi:function(a){return a.PolymerBase||(Object.keys(d.instance).forEach(function(b){f(a,d.instance[b])}),a=Object.create(a)),this.inheritAttributesObjects(a),this.inheritDelegates(a),a},addNamedApi:function(b,c){return f(b,a.getRegisteredPrototype(c))},inheritObject:function(a,b){a[b]=f({},Object.getPrototypeOf(a)[b])},registerPrototype:function(a){this.ctor=document.register(a,{prototype:this.prototype}),this.prototype.constructor=this.ctor,HTMLElement.register(a,this.prototype)}};d.declaration.prototype=g}(Polymer),function(a){function b(a,b){k[a]=b||{},d(a)}function c(a){return k[a]}function d(a){l[a]&&(l[a].registerWhenReady(),delete l[a])}function e(a){n[a]=!0;var b=m[a];b&&(b.forEach(function(a){a.registerWhenReady()}),delete m[a])}function f(a){return n[a]}function g(a){window.HTMLImports&&!HTMLImports.readyTime?addEventListener("HTMLImportsLoaded",a):a()}var h=a.extend,i=a.api.declaration,j=h(Object.create(HTMLElement.prototype),{createdCallback:function(){this.name=this.getAttribute("name"),this.registerWhenReady()},registerWhenReady:function(){var a=this.name;{if(c(a)){var d=this.getAttribute("extends");return d&&d.indexOf("-")>=0&&!f(d)?((m[d]=m[d]||[]).push(this),void 0):(document.contains(this)?g(function(){this.register(a,d)}.bind(this)):this.register(a,d),void 0)}if(l[a]=this,this.hasAttribute("noscript"))if(window.CustomElements&&!CustomElements.useNative)b(a);else{var e=document.createElement("script");e.textContent="Polymer('"+a+"');",this.appendChild(e)}}},register:function(a,b){this.prototype=this.generateCustomPrototype(a,b),this.prototype.element=this,this.addResolvePathApi(),this.desugar(),window.ShadowDOMPolyfill&&Platform.ShadowCSS.shimStyling(this.templateContent(),a,b),this.registerPrototype(a),this.publishConstructor(),e(a)},desugar:function(){this.parseAttributes(),this.parseHostEvents(),this.parseLocalEvents(),this.installSheets(),this.prototype.registerCallback&&this.prototype.registerCallback(this),this.cacheProperties()},publishConstructor:function(){var a=this.getAttribute("constructor");a&&(window[a]=this.ctor)}});Object.keys(i).forEach(function(a){h(j,i[a])}),document.register("polymer-element",{prototype:j});var k={},l={},m={},n={};a.getRegisteredPrototype=c,h(b,a),window.Polymer=b}(Polymer),Polymer.register=function(a){if(a!=window){var b=a.getAttribute("name");throw new Error("Polymer.register is deprecated in declaration of "+b+". Please see http://www.polymer-project.org/getting-started.html")}};
 /*
 //@ sourceMappingURL=polymer.min.js.map
 */
\ No newline at end of file
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium
index c8e411f..50c39c0 100644
--- a/third_party/protobuf/README.chromium
+++ b/third_party/protobuf/README.chromium
@@ -4,7 +4,7 @@
 License: BSD
 License File: COPYING.txt
 Version: unknown
-Revision: r428
+Revision: r476
 Security Critical: yes
 
 Local files (not taken from upstream):
@@ -26,7 +26,7 @@
 targets that depend on it can be componentized. See http://crbug.com/172800 for
 details, and r179806 for the patch.
 
-Revisions r430, r475, r476 and 504 were cherry-picked from upstream.
+Revision 504 was cherry-picked from upstream.
 
 Notes about Java:
 We have not forked the Java version of protobuf-lite, so the Java version does
diff --git a/third_party/protobuf/README.txt b/third_party/protobuf/README.txt
index a8f6604..17551a5 100644
--- a/third_party/protobuf/README.txt
+++ b/third_party/protobuf/README.txt
@@ -115,7 +115,7 @@
 C++ Installation - Windows
 ==========================
 
-If you are using Micosoft Visual C++, see vsprojects/readme.txt.
+If you are using Microsoft Visual C++, see vsprojects/readme.txt.
 
 If you are using Cygwin or MinGW, follow the Unix installation
 instructions, above.
diff --git a/third_party/protobuf/java/pom.xml b/third_party/protobuf/java/pom.xml
index 7ec6d91..9f464c1 100644
--- a/third_party/protobuf/java/pom.xml
+++ b/third_party/protobuf/java/pom.xml
@@ -10,8 +10,8 @@
   </parent>
   <groupId>com.google.protobuf</groupId>
   <artifactId>protobuf-java</artifactId>
-  <version>2.4.2-pre</version>
-  <packaging>jar</packaging>
+  <version>2.5.0-pre</version>
+  <packaging>bundle</packaging>
   <name>Protocol Buffer Java API</name>
   <description>
     Protocol Buffers are a way of encoding structured data in an efficient yet
@@ -132,6 +132,16 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>*</Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
   <profiles>
diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/ByteString.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/ByteString.java
index 1b18169..73d831f 100644
--- a/third_party/protobuf/java/src/main/java/com/google/protobuf/ByteString.java
+++ b/third_party/protobuf/java/src/main/java/com/google/protobuf/ByteString.java
@@ -37,7 +37,6 @@
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -776,6 +775,15 @@
       flushLastBuffer();
       return ByteString.copyFrom(flushedBuffers);
     }
+    
+    /**
+     * Implement java.util.Arrays.copyOf() for jdk 1.5.
+     */
+    private byte[] copyArray(byte[] buffer, int length) {
+      byte[] result = new byte[length];
+      System.arraycopy(buffer, 0, result, 0, Math.min(buffer.length, length));
+      return result;
+    }
 
     /**
      * Writes the complete contents of this byte array output stream to
@@ -800,7 +808,7 @@
         byteString.writeTo(out);
       }
 
-      out.write(Arrays.copyOf(cachedBuffer, cachedBufferPos));
+      out.write(copyArray(cachedBuffer, cachedBufferPos));
     }
 
     /**
@@ -853,7 +861,7 @@
     private void flushLastBuffer()  {
       if (bufferPos < buffer.length) {
         if (bufferPos > 0) {
-          byte[] bufferCopy = Arrays.copyOf(buffer, bufferPos);
+          byte[] bufferCopy = copyArray(buffer, bufferPos);
           flushedBuffers.add(new LiteralByteString(bufferCopy));
         }
         // We reuse this buffer for further writes.
diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyField.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyField.java
index df9425e..c4f9201 100644
--- a/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyField.java
+++ b/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyField.java
@@ -157,12 +157,10 @@
       this.entry = entry;
     }
 
-    @Override
     public K getKey() {
       return entry.getKey();
     }
 
-    @Override
     public Object getValue() {
       LazyField field = entry.getValue();
       if (field == null) {
@@ -175,7 +173,6 @@
       return entry.getValue();
     }
 
-    @Override
     public Object setValue(Object value) {
       if (!(value instanceof MessageLite)) {
         throw new IllegalArgumentException(
@@ -193,13 +190,11 @@
       this.iterator = iterator;
     }
 
-    @Override
     public boolean hasNext() {
       return iterator.hasNext();
     }
 
     @SuppressWarnings("unchecked")
-    @Override
     public Entry<K, Object> next() {
       Entry<K, ?> entry = iterator.next();
       if (entry.getValue() instanceof LazyField) {
@@ -208,7 +203,6 @@
       return (Entry<K, Object>) entry;
     }
 
-    @Override
     public void remove() {
       iterator.remove();
     }
diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
index 75c6a4b..a5f0bd9 100644
--- a/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ b/third_party/protobuf/java/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -172,7 +172,6 @@
     }
   }
 
-  @Override
   public List<?> getUnderlyingElements() {
     return Collections.unmodifiableList(list);
   }
diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/RopeByteString.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/RopeByteString.java
index 8d44d11..4699782 100644
--- a/third_party/protobuf/java/src/main/java/com/google/protobuf/RopeByteString.java
+++ b/third_party/protobuf/java/src/main/java/com/google/protobuf/RopeByteString.java
@@ -36,13 +36,12 @@
 import java.io.UnsupportedEncodingException;
 import java.io.ByteArrayInputStream;
 import java.nio.ByteBuffer;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Deque;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Stack;
 
 /**
  * Class to represent {@code ByteStrings} formed by concatenation of other
@@ -590,8 +589,7 @@
     // Stack containing the part of the string, starting from the left, that
     // we've already traversed.  The final string should be the equivalent of
     // concatenating the strings on the stack from bottom to top.
-    private final Deque<ByteString> prefixesStack =
-        new ArrayDeque<ByteString>(minLengthByDepth.length);
+    private final Stack<ByteString> prefixesStack = new Stack<ByteString>();
 
     private ByteString balance(ByteString left, ByteString right) {
       doBalance(left);
@@ -703,8 +701,8 @@
    */
   private static class PieceIterator implements Iterator<LiteralByteString> {
 
-    private final Deque<RopeByteString> breadCrumbs =
-        new ArrayDeque<RopeByteString>(minLengthByDepth.length);
+    private final Stack<RopeByteString> breadCrumbs =
+        new Stack<RopeByteString>();
     private LiteralByteString next;
 
     private PieceIterator(ByteString root) {
diff --git a/third_party/protobuf/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/third_party/protobuf/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
index f80f096..591bca5 100644
--- a/third_party/protobuf/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
+++ b/third_party/protobuf/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
@@ -145,7 +145,6 @@
     };
   }
 
-  @Override
   public List<?> getUnderlyingElements() {
     // The returned value is already unmodifiable.
     return list.getUnderlyingElements();
diff --git a/third_party/protobuf/protobuf_lite.gypi b/third_party/protobuf/protobuf_lite.gypi
index e66d29f..bbdc072 100644
--- a/third_party/protobuf/protobuf_lite.gypi
+++ b/third_party/protobuf/protobuf_lite.gypi
@@ -32,7 +32,6 @@
     'src/google/protobuf/stubs/once.cc',
     'src/google/protobuf/stubs/hash.h',
     'src/google/protobuf/stubs/map-util.h',
-    'src/google/protobuf/stubs/stl_util-inl.h',
     'src/google/protobuf/extension_set.cc',
     'src/google/protobuf/generated_message_util.cc',
     'src/google/protobuf/message_lite.cc',
diff --git a/third_party/protobuf/python/google/protobuf/pyext/python-proto2.cc b/third_party/protobuf/python/google/protobuf/pyext/python-proto2.cc
index 6275341..eebb752 100644
--- a/third_party/protobuf/python/google/protobuf/pyext/python-proto2.cc
+++ b/third_party/protobuf/python/google/protobuf/pyext/python-proto2.cc
@@ -427,9 +427,6 @@
   GOOGLE_DCHECK(descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING ||
          descriptor->type() == google::protobuf::FieldDescriptor::TYPE_BYTES);
   if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
-#else
-  if (descriptor->file()->options().cc_api_version() == 2 &&
-      descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
     if (!PyString_Check(arg) && !PyUnicode_Check(arg)) {
       FormatTypeError(arg, "str, unicode");
       return false;
@@ -457,9 +454,6 @@
 
   PyObject* encoded_string = NULL;
   if (descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
-#else
-  if (descriptor->file()->options().cc_api_version() == 2 &&
-      descriptor->type() == google::protobuf::FieldDescriptor::TYPE_STRING) {
     if (PyString_Check(arg)) {
       encoded_string = PyString_AsEncodedObject(arg, "utf-8", NULL);
     } else {
diff --git a/third_party/protobuf/python/setup.py b/third_party/protobuf/python/setup.py
index fbe2766..8a98629 100755
--- a/third_party/protobuf/python/setup.py
+++ b/third_party/protobuf/python/setup.py
@@ -26,7 +26,9 @@
 maintainer_email = "protobuf@googlegroups.com"
 
 # Find the Protocol Compiler.
-if os.path.exists("../src/protoc"):
+if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
+  protoc = os.environ['PROTOC']
+elif os.path.exists("../src/protoc"):
   protoc = "../src/protoc"
 elif os.path.exists("../src/protoc.exe"):
   protoc = "../src/protoc.exe"
@@ -154,7 +156,7 @@
         libraries = [ "protobuf" ]))
 
   setup(name = 'protobuf',
-        version = '2.4.2-pre',
+        version = '2.5.0-pre',
         packages = [ 'google' ],
         namespace_packages = [ 'google' ],
         test_suite = 'setup.MakeTestSuite',
@@ -165,6 +167,7 @@
           'google.protobuf.internal.cpp_message',
           'google.protobuf.internal.decoder',
           'google.protobuf.internal.encoder',
+          'google.protobuf.internal.enum_type_wrapper',
           'google.protobuf.internal.message_listener',
           'google.protobuf.internal.python_message',
           'google.protobuf.internal.type_checkers',
diff --git a/third_party/protobuf/src/Makefile.am b/third_party/protobuf/src/Makefile.am
index 172d0cd..df733d9 100644
--- a/third_party/protobuf/src/Makefile.am
+++ b/third_party/protobuf/src/Makefile.am
@@ -37,57 +37,63 @@
 MAINTAINERCLEANFILES =   \
   Makefile.in
 
-nobase_include_HEADERS =                                       \
-  google/protobuf/stubs/atomicops.h                            \
-  google/protobuf/stubs/atomicops_internals_arm_gcc.h          \
-  google/protobuf/stubs/atomicops_internals_macosx.h           \
-  google/protobuf/stubs/atomicops_internals_mips_gcc.h         \
-  google/protobuf/stubs/atomicops_internals_x86_gcc.h          \
-  google/protobuf/stubs/atomicops_internals_x86_msvc.h         \
-  google/protobuf/stubs/common.h                               \
-  google/protobuf/stubs/platform_macros.h                      \
-  google/protobuf/stubs/once.h                                 \
-  google/protobuf/descriptor.h                                 \
-  google/protobuf/descriptor.pb.h                              \
-  google/protobuf/descriptor_database.h                        \
-  google/protobuf/dynamic_message.h                            \
-  google/protobuf/extension_set.h                              \
-  google/protobuf/generated_enum_reflection.h                  \
-  google/protobuf/generated_message_util.h                     \
-  google/protobuf/generated_message_reflection.h               \
-  google/protobuf/message.h                                    \
-  google/protobuf/message_lite.h                               \
-  google/protobuf/reflection_ops.h                             \
-  google/protobuf/repeated_field.h                             \
-  google/protobuf/service.h                                    \
-  google/protobuf/text_format.h                                \
-  google/protobuf/unknown_field_set.h                          \
-  google/protobuf/wire_format.h                                \
-  google/protobuf/wire_format_lite.h                           \
-  google/protobuf/wire_format_lite_inl.h                       \
-  google/protobuf/io/coded_stream.h                            \
-  $(GZHEADERS)                                                 \
-  google/protobuf/io/printer.h                                 \
-  google/protobuf/io/tokenizer.h                               \
-  google/protobuf/io/zero_copy_stream.h                        \
-  google/protobuf/io/zero_copy_stream_impl.h                   \
-  google/protobuf/io/zero_copy_stream_impl_lite.h              \
-  google/protobuf/compiler/code_generator.h                    \
-  google/protobuf/compiler/command_line_interface.h            \
-  google/protobuf/compiler/importer.h                          \
-  google/protobuf/compiler/parser.h                            \
-  google/protobuf/compiler/plugin.h                            \
-  google/protobuf/compiler/plugin.pb.h                         \
-  google/protobuf/compiler/cpp/cpp_generator.h                 \
-  google/protobuf/compiler/java/java_generator.h               \
+nobase_include_HEADERS =                                        \
+  google/protobuf/stubs/atomicops.h                             \
+  google/protobuf/stubs/atomicops_internals_arm_gcc.h           \
+  google/protobuf/stubs/atomicops_internals_arm_qnx.h           \
+  google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
+  google/protobuf/stubs/atomicops_internals_macosx.h            \
+  google/protobuf/stubs/atomicops_internals_mips_gcc.h          \
+  google/protobuf/stubs/atomicops_internals_pnacl.h             \
+  google/protobuf/stubs/atomicops_internals_x86_gcc.h           \
+  google/protobuf/stubs/atomicops_internals_x86_msvc.h          \
+  google/protobuf/stubs/common.h                                \
+  google/protobuf/stubs/platform_macros.h                       \
+  google/protobuf/stubs/once.h                                  \
+  google/protobuf/stubs/template_util.h                         \
+  google/protobuf/stubs/type_traits.h                           \
+  google/protobuf/descriptor.h                                  \
+  google/protobuf/descriptor.pb.h                               \
+  google/protobuf/descriptor_database.h                         \
+  google/protobuf/dynamic_message.h                             \
+  google/protobuf/extension_set.h                               \
+  google/protobuf/generated_enum_reflection.h                   \
+  google/protobuf/generated_message_util.h                      \
+  google/protobuf/generated_message_reflection.h                \
+  google/protobuf/message.h                                     \
+  google/protobuf/message_lite.h                                \
+  google/protobuf/reflection_ops.h                              \
+  google/protobuf/repeated_field.h                              \
+  google/protobuf/service.h                                     \
+  google/protobuf/text_format.h                                 \
+  google/protobuf/unknown_field_set.h                           \
+  google/protobuf/wire_format.h                                 \
+  google/protobuf/wire_format_lite.h                            \
+  google/protobuf/wire_format_lite_inl.h                        \
+  google/protobuf/io/coded_stream.h                             \
+  $(GZHEADERS)                                                  \
+  google/protobuf/io/printer.h                                  \
+  google/protobuf/io/tokenizer.h                                \
+  google/protobuf/io/zero_copy_stream.h                         \
+  google/protobuf/io/zero_copy_stream_impl.h                    \
+  google/protobuf/io/zero_copy_stream_impl_lite.h               \
+  google/protobuf/compiler/code_generator.h                     \
+  google/protobuf/compiler/command_line_interface.h             \
+  google/protobuf/compiler/importer.h                           \
+  google/protobuf/compiler/parser.h                             \
+  google/protobuf/compiler/plugin.h                             \
+  google/protobuf/compiler/plugin.pb.h                          \
+  google/protobuf/compiler/cpp/cpp_generator.h                  \
+  google/protobuf/compiler/java/java_generator.h                \
   google/protobuf/compiler/python/python_generator.h
 
 lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
 
 libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_lite_la_LDFLAGS = -version-info 7:0:0 -export-dynamic -no-undefined
+libprotobuf_lite_la_LDFLAGS = -version-info 8:0:0 -export-dynamic -no-undefined
 libprotobuf_lite_la_SOURCES =                                  \
   google/protobuf/stubs/atomicops_internals_x86_gcc.cc         \
+  google/protobuf/stubs/atomicops_internals_x86_msvc.cc        \
   google/protobuf/stubs/common.cc                              \
   google/protobuf/stubs/once.cc                                \
   google/protobuf/stubs/hash.h                                 \
@@ -95,8 +101,6 @@
   google/protobuf/stubs/stl_util.h                             \
   google/protobuf/stubs/stringprintf.cc                        \
   google/protobuf/stubs/stringprintf.h                         \
-  google/protobuf/stubs/template_util.h                        \
-  google/protobuf/stubs/type_traits.h                          \
   google/protobuf/extension_set.cc                             \
   google/protobuf/generated_message_util.cc                    \
   google/protobuf/message_lite.cc                              \
@@ -108,7 +112,7 @@
   google/protobuf/io/zero_copy_stream_impl_lite.cc
 
 libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
-libprotobuf_la_LDFLAGS = -version-info 7:0:0 -export-dynamic -no-undefined
+libprotobuf_la_LDFLAGS = -version-info 8:0:0 -export-dynamic -no-undefined
 libprotobuf_la_SOURCES =                                       \
   $(libprotobuf_lite_la_SOURCES)                               \
   google/protobuf/stubs/strutil.cc                             \
@@ -136,7 +140,7 @@
   google/protobuf/compiler/parser.cc
 
 libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
-libprotoc_la_LDFLAGS = -version-info 7:0:0 -export-dynamic -no-undefined
+libprotoc_la_LDFLAGS = -version-info 8:0:0 -export-dynamic -no-undefined
 libprotoc_la_SOURCES =                                         \
   google/protobuf/compiler/code_generator.cc                   \
   google/protobuf/compiler/command_line_interface.cc           \
diff --git a/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index b5f9ab5..1eae29b 100644
--- a/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -381,7 +381,6 @@
   EXPECT_EQ("wx", message.repeated_string(0));
 }
 
-
 TEST(GeneratedMessageTest, CopyFrom) {
   unittest::TestAllTypes message1, message2;
 
@@ -394,7 +393,6 @@
   TestUtil::ExpectAllFieldsSet(message2);
 }
 
-
 TEST(GeneratedMessageTest, SwapWithEmpty) {
   unittest::TestAllTypes message1, message2;
   TestUtil::SetAllFields(&message1);
@@ -493,6 +491,8 @@
   TestUtil::ExpectAllFieldsSet(message2);
 }
 
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
+    !defined(GOOGLE_PROTOBUF_NO_RTTI)
 TEST(GeneratedMessageTest, UpcastCopyFrom) {
   // Test the CopyFrom method that takes in the generic const Message&
   // parameter.
@@ -505,6 +505,7 @@
 
   TestUtil::ExpectAllFieldsSet(message2);
 }
+#endif
 
 #ifndef PROTOBUF_TEST_NO_DESCRIPTORS
 
@@ -556,7 +557,9 @@
   TestUtil::ExpectAllFieldsSet(message1);
 }
 
-#ifdef GTEST_HAS_DEATH_TEST
+#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \
+    !defined(GOOGLE_PROTOBUF_NO_RTTI)
+#ifdef PROTOBUF_HAS_DEATH_TEST
 
 TEST(GeneratedMessageTest, MergeFromSelf) {
   unittest::TestAllTypes message;
@@ -565,7 +568,8 @@
                "&from");
 }
 
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HAS_DEATH_TEST
+#endif  // !PROTOBUF_TEST_NO_DESCRIPTORS || !GOOGLE_PROTOBUF_NO_RTTI
 
 // Test the generated SerializeWithCachedSizesToArray(),
 TEST(GeneratedMessageTest, SerializationToArray) {
@@ -1199,7 +1203,7 @@
 TEST_F(GeneratedServiceTest, CallMethodTypeFailure) {
   // Verify death if we call Foo() with Bar's message types.
 
-#ifdef GTEST_HAS_DEATH_TEST  // death tests do not work on Windows yet
+#ifdef PROTOBUF_HAS_DEATH_TEST  // death tests do not work on Windows yet
   EXPECT_DEBUG_DEATH(
     mock_service_.CallMethod(foo_, &mock_controller_,
                              &foo_request_, &bar_response_, done_.get()),
@@ -1210,7 +1214,7 @@
     mock_service_.CallMethod(foo_, &mock_controller_,
                              &bar_request_, &foo_response_, done_.get()),
     "dynamic_cast");
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HAS_DEATH_TEST
 }
 
 TEST_F(GeneratedServiceTest, GetPrototypes) {
diff --git a/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.cc b/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.cc
index 7b0b1f9..88559b8 100644
--- a/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.cc
+++ b/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.cc
@@ -139,7 +139,9 @@
     "atorResponse\022\r\n\005error\030\001 \001(\t\022B\n\004file\030\017 \003("
     "\01324.google.protobuf.compiler.CodeGenerat"
     "orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n"
-    "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\t", 399);
+    "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\tB"
+    ",\n\034com.google.protobuf.compilerB\014PluginP"
+    "rotos", 445);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes);
   CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest();
diff --git a/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.h b/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.h
index 46478c7..68cc21c 100644
--- a/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.h
+++ b/third_party/protobuf/src/google/protobuf/compiler/plugin.pb.h
@@ -8,12 +8,12 @@
 
 #include <google/protobuf/stubs/common.h>
 
-#if GOOGLE_PROTOBUF_VERSION < 2004000
+#if GOOGLE_PROTOBUF_VERSION < 2005000
 #error This file was generated by a newer version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please update
 #error your headers.
 #endif
-#if 2004002 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
 #error This file was generated by an older version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please
 #error regenerate this file with a newer version of protoc.
diff --git a/third_party/protobuf/src/google/protobuf/compiler/plugin.proto b/third_party/protobuf/src/google/protobuf/compiler/plugin.proto
index 651ed10..77b888f 100644
--- a/third_party/protobuf/src/google/protobuf/compiler/plugin.proto
+++ b/third_party/protobuf/src/google/protobuf/compiler/plugin.proto
@@ -45,6 +45,8 @@
 // flag "--${NAME}_out" is passed to protoc.
 
 package google.protobuf.compiler;
+option java_package = "com.google.protobuf.compiler";
+option java_outer_classname = "PluginProtos";
 
 import "google/protobuf/descriptor.proto";
 
diff --git a/third_party/protobuf/src/google/protobuf/compiler/subprocess.cc b/third_party/protobuf/src/google/protobuf/compiler/subprocess.cc
index 860fc87..67da120 100644
--- a/third_party/protobuf/src/google/protobuf/compiler/subprocess.cc
+++ b/third_party/protobuf/src/google/protobuf/compiler/subprocess.cc
@@ -295,8 +295,8 @@
   int stdin_pipe[2];
   int stdout_pipe[2];
 
-  pipe(stdin_pipe);
-  pipe(stdout_pipe);
+  GOOGLE_CHECK(pipe(stdin_pipe) != -1);
+  GOOGLE_CHECK(pipe(stdout_pipe) != -1);
 
   char* argv[2] = { strdup(program.c_str()), NULL };
 
@@ -324,9 +324,11 @@
 
     // Write directly to STDERR_FILENO to avoid stdio code paths that may do
     // stuff that is unsafe here.
-    write(STDERR_FILENO, argv[0], strlen(argv[0]));
+    int ignored;
+    ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
     const char* message = ": program not found or is not executable\n";
-    write(STDERR_FILENO, message, strlen(message));
+    ignored = write(STDERR_FILENO, message, strlen(message));
+    (void) ignored;
 
     // Must use _exit() rather than exit() to avoid flushing output buffers
     // that will also be flushed by the parent.
diff --git a/third_party/protobuf/src/google/protobuf/descriptor.cc b/third_party/protobuf/src/google/protobuf/descriptor.cc
index 45293fe..bcbf1e0 100644
--- a/third_party/protobuf/src/google/protobuf/descriptor.cc
+++ b/third_party/protobuf/src/google/protobuf/descriptor.cc
@@ -2987,7 +2987,11 @@
   //       tables_->AllocateMessage<typename DescriptorT::OptionsType>();
   typename DescriptorT::OptionsType* const dummy = NULL;
   typename DescriptorT::OptionsType* options = tables_->AllocateMessage(dummy);
-  options->CopyFrom(orig_options);
+  // Avoid using MergeFrom()/CopyFrom() in this class to make it -fno-rtti
+  // friendly. Without RTTI, MergeFrom() and CopyFrom() will fallback to the
+  // reflection based method, which requires the Descriptor. However, we are in
+  // the middle of building the descriptors, thus the deadlock.
+  options->ParseFromString(orig_options.SerializeAsString());
   descriptor->options_ = options;
 
   // Don't add to options_to_interpret_ unless there were uninterpreted
@@ -4128,16 +4132,26 @@
 void DescriptorBuilder::ValidateEnumOptions(EnumDescriptor* enm,
                                             const EnumDescriptorProto& proto) {
   VALIDATE_OPTIONS_FROM_ARRAY(enm, value, EnumValue);
-  if (!enm->options().allow_alias()) {
+  if (!enm->options().has_allow_alias() || !enm->options().allow_alias()) {
     map<int, string> used_values;
     for (int i = 0; i < enm->value_count(); ++i) {
       const EnumValueDescriptor* enum_value = enm->value(i);
       if (used_values.find(enum_value->number()) != used_values.end()) {
-        AddError(enm->full_name(), proto,
-                 DescriptorPool::ErrorCollector::NUMBER,
-                 "\"" + enum_value->full_name() +
-                 "\" uses the same enum value as \"" +
-                 used_values[enum_value->number()] + "\"");
+        string error =
+            "\"" + enum_value->full_name() +
+            "\" uses the same enum value as \"" +
+            used_values[enum_value->number()] + "\". If this is intended, set "
+            "'option allow_alias = true;' to the enum definition.";
+        if (!enm->options().allow_alias()) {
+          // Generate error if duplicated enum values are explicitly disallowed.
+          AddError(enm->full_name(), proto,
+                   DescriptorPool::ErrorCollector::NUMBER,
+                   error);
+        } else {
+          // Generate warning if duplicated values are found but the option
+          // isn't set.
+          GOOGLE_LOG(ERROR) << error;
+        }
       } else {
         used_values[enum_value->number()] = enum_value->full_name();
       }
diff --git a/third_party/protobuf/src/google/protobuf/descriptor.h b/third_party/protobuf/src/google/protobuf/descriptor.h
index 410d3ed..33e3af7 100644
--- a/third_party/protobuf/src/google/protobuf/descriptor.h
+++ b/third_party/protobuf/src/google/protobuf/descriptor.h
@@ -58,6 +58,10 @@
 #include <vector>
 #include <google/protobuf/stubs/common.h>
 
+// TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
+#ifdef TYPE_BOOL
+#undef TYPE_BOOL
+#endif  // TYPE_BOOL
 
 namespace google {
 namespace protobuf {
@@ -1334,7 +1338,7 @@
                                const Descriptor::ExtensionRange*)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension,
                                const FieldDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
@@ -1351,7 +1355,7 @@
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, enum_type, const EnumDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, experimental_map_key,
                          const FieldDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FieldDescriptor, FieldOptions)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, has_default_value, bool)
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int32 , int32 )
 PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, default_value_int64 , int64 )
@@ -1371,13 +1375,13 @@
 PROTOBUF_DEFINE_ACCESSOR(EnumDescriptor, value_count, int)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(EnumDescriptor, value,
                                const EnumValueDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumDescriptor, EnumOptions)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(EnumValueDescriptor, full_name)
 PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, number, int)
 PROTOBUF_DEFINE_ACCESSOR(EnumValueDescriptor, type, const EnumDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(EnumValueDescriptor, EnumValueOptions)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(ServiceDescriptor, full_name)
@@ -1385,14 +1389,14 @@
 PROTOBUF_DEFINE_ACCESSOR(ServiceDescriptor, method_count, int)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(ServiceDescriptor, method,
                                const MethodDescriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(ServiceDescriptor, ServiceOptions)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(MethodDescriptor, full_name)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*)
@@ -1403,7 +1407,7 @@
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, enum_type_count, int)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, service_count, int)
 PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, extension_count, int)
-PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions);
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(FileDescriptor, FileOptions)
 
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, message_type, const Descriptor*)
 PROTOBUF_DEFINE_ARRAY_ACCESSOR(FileDescriptor, enum_type, const EnumDescriptor*)
diff --git a/third_party/protobuf/src/google/protobuf/descriptor.pb.h b/third_party/protobuf/src/google/protobuf/descriptor.pb.h
index 5c1175c..f6b83ce 100644
--- a/third_party/protobuf/src/google/protobuf/descriptor.pb.h
+++ b/third_party/protobuf/src/google/protobuf/descriptor.pb.h
@@ -8,12 +8,12 @@
 
 #include <google/protobuf/stubs/common.h>
 
-#if GOOGLE_PROTOBUF_VERSION < 2004000
+#if GOOGLE_PROTOBUF_VERSION < 2005000
 #error This file was generated by a newer version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please update
 #error your headers.
 #endif
-#if 2004002 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
 #error This file was generated by an older version of protoc which is
 #error incompatible with your Protocol Buffer headers.  Please
 #error regenerate this file with a newer version of protoc.
diff --git a/third_party/protobuf/src/google/protobuf/descriptor_unittest.cc b/third_party/protobuf/src/google/protobuf/descriptor_unittest.cc
index 3503f13..86e6a49 100644
--- a/third_party/protobuf/src/google/protobuf/descriptor_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/descriptor_unittest.cc
@@ -1739,7 +1739,7 @@
             message->field(3)->default_value_uint64());
   EXPECT_EQ(4.5             , message->field(4)->default_value_float ());
   EXPECT_EQ(10e100          , message->field(5)->default_value_double());
-  EXPECT_EQ(true            , message->field(6)->default_value_bool  ());
+  EXPECT_TRUE(                message->field(6)->default_value_bool  ());
   EXPECT_EQ("hello"         , message->field(7)->default_value_string());
   EXPECT_EQ("\001\002\003"  , message->field(8)->default_value_string());
   EXPECT_EQ(enum_value_b    , message->field(9)->default_value_enum  ());
@@ -1762,7 +1762,7 @@
   EXPECT_EQ(0    , message->field(14)->default_value_uint64());
   EXPECT_EQ(0.0f , message->field(15)->default_value_float ());
   EXPECT_EQ(0.0  , message->field(16)->default_value_double());
-  EXPECT_EQ(false, message->field(17)->default_value_bool  ());
+  EXPECT_FALSE(    message->field(17)->default_value_bool  ());
   EXPECT_EQ(""   , message->field(18)->default_value_string());
   EXPECT_EQ(""   , message->field(19)->default_value_string());
   EXPECT_EQ(enum_value_a, message->field(20)->default_value_enum());
@@ -2167,7 +2167,7 @@
 
   options =
       &protobuf_unittest::CustomOptionMinIntegerValues::descriptor()->options();
-  EXPECT_EQ(false    , options->GetExtension(protobuf_unittest::bool_opt));
+  EXPECT_FALSE(        options->GetExtension(protobuf_unittest::bool_opt));
   EXPECT_EQ(kint32min, options->GetExtension(protobuf_unittest::int32_opt));
   EXPECT_EQ(kint64min, options->GetExtension(protobuf_unittest::int64_opt));
   EXPECT_EQ(0        , options->GetExtension(protobuf_unittest::uint32_opt));
@@ -2181,7 +2181,7 @@
 
   options =
       &protobuf_unittest::CustomOptionMaxIntegerValues::descriptor()->options();
-  EXPECT_EQ(true      , options->GetExtension(protobuf_unittest::bool_opt));
+  EXPECT_TRUE(          options->GetExtension(protobuf_unittest::bool_opt));
   EXPECT_EQ(kint32max , options->GetExtension(protobuf_unittest::int32_opt));
   EXPECT_EQ(kint64max , options->GetExtension(protobuf_unittest::int64_opt));
   EXPECT_EQ(kuint32max, options->GetExtension(protobuf_unittest::uint32_opt));
@@ -4001,7 +4001,9 @@
     "  options { allow_alias: false }"
     "}",
     "foo.proto: Bar: NUMBER: "
-    "\"ENUM_B\" uses the same enum value as \"ENUM_A\"\n");
+    "\"ENUM_B\" uses the same enum value as \"ENUM_A\". "
+    "If this is intended, set 'option allow_alias = true;' to the enum "
+    "definition.\n");
 }
 
 // ===================================================================
diff --git a/third_party/protobuf/src/google/protobuf/dynamic_message.cc b/third_party/protobuf/src/google/protobuf/dynamic_message.cc
index e4bebb2..09bec54 100644
--- a/third_party/protobuf/src/google/protobuf/dynamic_message.cc
+++ b/third_party/protobuf/src/google/protobuf/dynamic_message.cc
@@ -208,14 +208,6 @@
 
   Metadata GetMetadata() const;
 
-  // We actually allocate more memory than sizeof(*this) when this
-  // class's memory is allocated via the global operator new. Thus, we need to
-  // manually call the global operator delete. Calling the destructor is taken
-  // care of for us.
-  static void operator delete(void* ptr) {
-    ::operator delete(ptr);
-  }
-
  private:
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
 
diff --git a/third_party/protobuf/src/google/protobuf/extension_set_unittest.cc b/third_party/protobuf/src/google/protobuf/extension_set_unittest.cc
index 1e7c5a5..559de6e 100644
--- a/third_party/protobuf/src/google/protobuf/extension_set_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/extension_set_unittest.cc
@@ -550,7 +550,7 @@
   }
 }
 
-#ifdef GTEST_HAS_DEATH_TEST
+#ifdef PROTOBUF_HAS_DEATH_TEST
 
 TEST(ExtensionSetTest, InvalidEnumDeath) {
   unittest::TestAllExtensions message;
@@ -560,7 +560,7 @@
     "IsValid");
 }
 
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HAS_DEATH_TEST
 
 TEST(ExtensionSetTest, DynamicExtensions) {
   // Test adding a dynamic extension to a compiled-in message object.
@@ -695,7 +695,11 @@
     const Message& sub_message =
         message.GetReflection()->GetMessage(message, message_extension);
     const unittest::ForeignMessage* typed_sub_message =
+#ifdef GOOGLE_PROTOBUF_NO_RTTI
+        static_cast<const unittest::ForeignMessage*>(&sub_message);
+#else
         dynamic_cast<const unittest::ForeignMessage*>(&sub_message);
+#endif
     ASSERT_TRUE(typed_sub_message != NULL);
     EXPECT_EQ(456, typed_sub_message->c());
   }
diff --git a/third_party/protobuf/src/google/protobuf/generated_message_reflection.h b/third_party/protobuf/src/google/protobuf/generated_message_reflection.h
index e6670ae..c1c142f 100644
--- a/third_party/protobuf/src/google/protobuf/generated_message_reflection.h
+++ b/third_party/protobuf/src/google/protobuf/generated_message_reflection.h
@@ -50,9 +50,9 @@
 
 namespace google {
 namespace upb {
-namespace proto2_bridge_opensource {
-class FieldAccessor;
-}  // namespace protobuf_bridge_google3
+namespace google_opensource {
+class GMR_Handlers;
+}  // namespace google_opensource
 }  // namespace upb
 
 namespace protobuf {
@@ -287,9 +287,9 @@
  private:
   friend class GeneratedMessage;
 
-  // To parse directly into a proto2 generated class, FieldAccessor needs
-  // access to member offsets and hasbits.
-  friend class LIBPROTOBUF_EXPORT upb::proto2_bridge_opensource::FieldAccessor;
+  // To parse directly into a proto2 generated class, the class GMR_Handlers
+  // needs access to member offsets and hasbits.
+  friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
 
   const Descriptor* descriptor_;
   const Message* default_instance_;
diff --git a/third_party/protobuf/src/google/protobuf/generated_message_reflection_unittest.cc b/third_party/protobuf/src/google/protobuf/generated_message_reflection_unittest.cc
index f60e430..39aa55f 100644
--- a/third_party/protobuf/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -427,7 +427,7 @@
   TestUtil::ExpectAllExtensionsSet(message);
 }
 
-#ifdef GTEST_HAS_DEATH_TEST
+#ifdef PROTOBUF_HAS_DEATH_TEST
 
 TEST(GeneratedMessageReflectionTest, UsageErrors) {
   unittest::TestAllTypes message;
@@ -476,7 +476,7 @@
 #undef f
 }
 
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HAS_DEATH_TEST
 
 
 }  // namespace
diff --git a/third_party/protobuf/src/google/protobuf/io/gzip_stream.h b/third_party/protobuf/src/google/protobuf/io/gzip_stream.h
index 7ee24bc..365e9ea 100644
--- a/third_party/protobuf/src/google/protobuf/io/gzip_stream.h
+++ b/third_party/protobuf/src/google/protobuf/io/gzip_stream.h
@@ -118,7 +118,7 @@
     ZLIB = 2,
   };
 
-  struct Options {
+  struct LIBPROTOBUF_EXPORT Options {
     // Defaults to GZIP.
     Format format;
 
diff --git a/third_party/protobuf/src/google/protobuf/io/printer_unittest.cc b/third_party/protobuf/src/google/protobuf/io/printer_unittest.cc
index 399395c..c9b3035 100644
--- a/third_party/protobuf/src/google/protobuf/io/printer_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/io/printer_unittest.cc
@@ -220,7 +220,7 @@
 }
 
 // Death tests do not work on Windows as of yet.
-#ifdef GTEST_HAS_DEATH_TEST
+#ifdef PROTOBUF_HAS_DEATH_TEST
 TEST(Printer, Death) {
   char buffer[8192];
 
@@ -231,7 +231,7 @@
   EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
   EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
 }
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF__HAS_DEATH_TEST
 
 TEST(Printer, WriteFailurePartial) {
   char buffer[17];
diff --git a/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc b/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc
index 8de4393..dbb5be4 100644
--- a/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/io/tokenizer_unittest.cc
@@ -741,7 +741,7 @@
   EXPECT_EQ(0, ParseInteger("0x"));
 
   uint64 i;
-#ifdef GTEST_HAS_DEATH_TEST  // death tests do not work on Windows yet
+#ifdef PROTOBUF_HASDEATH_TEST  // death tests do not work on Windows yet
   // Test invalid integers that will never be tokenized as integers.
   EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("zxy", kuint64max, &i),
     "passed text that could not have been tokenized as an integer");
@@ -753,7 +753,7 @@
     "passed text that could not have been tokenized as an integer");
   EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("-1", kuint64max, &i),
     "passed text that could not have been tokenized as an integer");
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HASDEATH_TEST
 
   // Test overflows.
   EXPECT_TRUE (Tokenizer::ParseInteger("0", 0, &i));
@@ -796,7 +796,7 @@
   EXPECT_EQ(     0.0, Tokenizer::ParseFloat("1e-9999999999999999999999999999"));
   EXPECT_EQ(HUGE_VAL, Tokenizer::ParseFloat("1e+9999999999999999999999999999"));
 
-#ifdef GTEST_HAS_DEATH_TEST  // death tests do not work on Windows yet
+#ifdef PROTOBUF_HASDEATH_TEST  // death tests do not work on Windows yet
   // Test invalid integers that will never be tokenized as integers.
   EXPECT_DEBUG_DEATH(Tokenizer::ParseFloat("zxy"),
     "passed text that could not have been tokenized as a float");
@@ -804,7 +804,7 @@
     "passed text that could not have been tokenized as a float");
   EXPECT_DEBUG_DEATH(Tokenizer::ParseFloat("-1.0"),
     "passed text that could not have been tokenized as a float");
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HASDEATH_TEST
 }
 
 TEST_F(TokenizerTest, ParseString) {
@@ -843,10 +843,10 @@
   EXPECT_EQ("u0", output);
 
   // Test invalid strings that will never be tokenized as strings.
-#ifdef GTEST_HAS_DEATH_TEST  // death tests do not work on Windows yet
+#ifdef PROTOBUF_HASDEATH_TEST  // death tests do not work on Windows yet
   EXPECT_DEBUG_DEATH(Tokenizer::ParseString("", &output),
     "passed text that could not have been tokenized as a string");
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HASDEATH_TEST
 }
 
 TEST_F(TokenizerTest, ParseStringAppend) {
diff --git a/third_party/protobuf/src/google/protobuf/message.h b/third_party/protobuf/src/google/protobuf/message.h
index 77faa9a..0f90bc1 100644
--- a/third_party/protobuf/src/google/protobuf/message.h
+++ b/third_party/protobuf/src/google/protobuf/message.h
@@ -750,6 +750,27 @@
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
 };
 
+#define DECLARE_GET_REPEATED_FIELD(TYPE)                         \
+template<>                                                       \
+LIBPROTOBUF_EXPORT                                               \
+const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>(   \
+    const Message& message, const FieldDescriptor* field) const; \
+                                                                 \
+template<>                                                       \
+LIBPROTOBUF_EXPORT                                               \
+RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>(     \
+    Message* message, const FieldDescriptor* field) const;
+
+DECLARE_GET_REPEATED_FIELD(int32)
+DECLARE_GET_REPEATED_FIELD(int64)
+DECLARE_GET_REPEATED_FIELD(uint32)
+DECLARE_GET_REPEATED_FIELD(uint64)
+DECLARE_GET_REPEATED_FIELD(float)
+DECLARE_GET_REPEATED_FIELD(double)
+DECLARE_GET_REPEATED_FIELD(bool)
+
+#undef DECLARE_GET_REPEATED_FIELD
+
 // =============================================================================
 // Implementation details for {Get,Mutable}RawRepeatedPtrField.  We provide
 // specializations for <string>, <StringPieceField> and <Message> and handle
diff --git a/third_party/protobuf/src/google/protobuf/message_unittest.cc b/third_party/protobuf/src/google/protobuf/message_unittest.cc
index 8aaeabb..a1449c7 100644
--- a/third_party/protobuf/src/google/protobuf/message_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/message_unittest.cc
@@ -205,7 +205,7 @@
   EXPECT_EQ("a, b, c", message.InitializationErrorString());
 }
 
-#ifdef GTEST_HAS_DEATH_TEST  // death tests do not work on Windows yet.
+#ifdef PROTOBUF_HAS_DEATH_TEST
 
 TEST(MessageTest, SerializeFailsIfNotInitialized) {
   unittest::TestRequired message;
@@ -222,7 +222,7 @@
     "fields: a, b, c");
 }
 
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HAS_DEATH_TEST
 
 TEST(MessageTest, BypassInitializationCheckOnSerialize) {
   unittest::TestRequired message;
diff --git a/third_party/protobuf/src/google/protobuf/reflection_ops_unittest.cc b/third_party/protobuf/src/google/protobuf/reflection_ops_unittest.cc
index 1cd56f1..29229b5 100644
--- a/third_party/protobuf/src/google/protobuf/reflection_ops_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/reflection_ops_unittest.cc
@@ -152,7 +152,7 @@
   EXPECT_EQ(2, message1.unknown_fields().field(1).varint());
 }
 
-#ifdef GTEST_HAS_DEATH_TEST
+#ifdef PROTOBUF_HAS_DEATH_TEST
 
 TEST(ReflectionOpsTest, MergeFromSelf) {
   // Note:  Copy is implemented in terms of Merge() so technically the Copy
@@ -165,7 +165,7 @@
     "&from");
 }
 
-#endif  // GTEST_HAS_DEATH_TEST
+#endif  // PROTOBUF_HAS_DEATH_TEST
 
 TEST(ReflectionOpsTest, Clear) {
   unittest::TestAllTypes message;
diff --git a/third_party/protobuf/src/google/protobuf/repeated_field.h b/third_party/protobuf/src/google/protobuf/repeated_field.h
index b9db2b6..570d4b7 100644
--- a/third_party/protobuf/src/google/protobuf/repeated_field.h
+++ b/third_party/protobuf/src/google/protobuf/repeated_field.h
@@ -57,9 +57,9 @@
 namespace google {
 
 namespace upb {
-namespace proto2_bridge_opensource {
-class FieldAccessor;
-}  // namespace protobuf_bridge_opensource
+namespace google_opensource {
+class GMR_Handlers;
+}  // namespace google_opensource
 }  // namespace upb
 
 namespace protobuf {
@@ -235,9 +235,9 @@
   // use of AddFromCleared(), which is not part of the public interface.
   friend class ExtensionSet;
 
-  // To parse directly into a proto2 generated class, the upb FieldAccessor
+  // To parse directly into a proto2 generated class, the upb class GMR_Handlers
   // needs to be able to modify a RepeatedPtrFieldBase directly.
-  friend class LIBPROTOBUF_EXPORT upb::proto2_bridge_opensource::FieldAccessor;
+  friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
 
   RepeatedPtrFieldBase();
 
diff --git a/third_party/protobuf/src/google/protobuf/repeated_field_reflection_unittest.cc b/third_party/protobuf/src/google/protobuf/repeated_field_reflection_unittest.cc
index 5fcfb00..a40162d 100644
--- a/third_party/protobuf/src/google/protobuf/repeated_field_reflection_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/repeated_field_reflection_unittest.cc
@@ -120,7 +120,7 @@
     EXPECT_EQ(rf_double.Get(i), Func(i, 2));
     EXPECT_EQ(rpf_string.Get(i), StrFunc(i, 5));
     EXPECT_EQ(rpf_foreign_message.Get(i).c(), Func(i, 6));
-    EXPECT_EQ(down_cast<const ForeignMessage&>(rpf_message.Get(i)).c(),
+    EXPECT_EQ(down_cast<const ForeignMessage*>(&rpf_message.Get(i))->c(),
               Func(i, 6));
 
     // Check gets through mutable objects.
@@ -128,7 +128,7 @@
     EXPECT_EQ(mrf_double->Get(i), Func(i, 2));
     EXPECT_EQ(mrpf_string->Get(i), StrFunc(i, 5));
     EXPECT_EQ(mrpf_foreign_message->Get(i).c(), Func(i, 6));
-    EXPECT_EQ(down_cast<const ForeignMessage&>(mrpf_message->Get(i)).c(),
+    EXPECT_EQ(down_cast<const ForeignMessage*>(&mrpf_message->Get(i))->c(),
               Func(i, 6));
 
     // Check sets through mutable objects.
@@ -144,6 +144,7 @@
     EXPECT_EQ(message.repeated_foreign_message(i).c(), Func(i, 7));
   }
 
+#ifdef PROTOBUF_HAS_DEATH_TEST
   // Make sure types are checked correctly at runtime.
   const FieldDescriptor* fd_optional_int32 =
       desc->FindFieldByName("optional_int32");
@@ -153,6 +154,7 @@
       message, fd_repeated_int32), "not the right type");
   EXPECT_DEATH(refl->GetRepeatedPtrField<TestAllTypes>(
       message, fd_repeated_foreign_message), "wrong submessage type");
+#endif  // PROTOBUF_HAS_DEATH_TEST
 }
 
 
diff --git a/third_party/protobuf/src/google/protobuf/repeated_field_unittest.cc b/third_party/protobuf/src/google/protobuf/repeated_field_unittest.cc
index 99d5842..257701e 100644
--- a/third_party/protobuf/src/google/protobuf/repeated_field_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/repeated_field_unittest.cc
@@ -331,7 +331,7 @@
   // Truncations that don't change the size are allowed, but growing is not
   // allowed.
   field.Truncate(field.size());
-#ifdef GTEST_HAS_DEATH_TEST
+#ifdef PROTOBUF_HAS_DEATH_TEST
   EXPECT_DEBUG_DEATH(field.Truncate(field.size() + 1), "new_size");
 #endif
 }
@@ -1007,11 +1007,13 @@
 TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) {
   RepeatedPtrField<string>::pointer_iterator iter =
       proto_array_.pointer_begin();
+  (void) iter;
 }
 
 TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertibleConstPtr) {
   RepeatedPtrField<string>::const_pointer_iterator iter =
       const_proto_array_->pointer_begin();
+  (void) iter;
 }
 
 TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) {
@@ -1136,8 +1138,6 @@
   proto_array_.Add()->assign("y");
 
   {
-    RepeatedPtrField<string>::pointer_iterator iter =
-        proto_array_.pointer_begin();
     string v = "f";
     RepeatedPtrField<string>::pointer_iterator it =
         lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(),
@@ -1149,8 +1149,6 @@
     EXPECT_TRUE(it == proto_array_.pointer_begin() + 3);
   }
   {
-    RepeatedPtrField<string>::const_pointer_iterator iter =
-        const_proto_array_->pointer_begin();
     string v = "f";
     RepeatedPtrField<string>::const_pointer_iterator it =
         lower_bound(const_proto_array_->pointer_begin(),
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops.h b/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
index 9b795ee..ab935b0 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
@@ -54,7 +54,7 @@
 #define GOOGLE_PROTOBUF_ATOMICOPS_H_
 
 // Don't include this file for people not concerned about thread safety.
-#ifndef GOOGLE_PROTOBUF_NO_THREADSAFETY
+#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
 
 #include <google/protobuf/stubs/platform_macros.h>
 
@@ -181,8 +181,12 @@
 #include <google/protobuf/stubs/atomicops_internals_x86_gcc.h>
 #elif defined(GOOGLE_PROTOBUF_ARCH_ARM)
 #include <google/protobuf/stubs/atomicops_internals_arm_gcc.h>
+#elif defined(GOOGLE_PROTOBUF_ARCH_ARM_QNX)
+#include <google/protobuf/stubs/atomicops_internals_arm_qnx.h>
 #elif defined(GOOGLE_PROTOBUF_ARCH_MIPS)
 #include <google/protobuf/stubs/atomicops_internals_mips_gcc.h>
+#elif defined(__pnacl__)
+#include <google/protobuf/stubs/atomicops_internals_pnacl.h>
 #else
 GOOGLE_PROTOBUF_ATOMICOPS_ERROR
 #endif
@@ -200,6 +204,6 @@
 
 #undef GOOGLE_PROTOBUF_ATOMICOPS_ERROR
 
-#endif  // GOOGLE_PROTOBUF_NO_THREADSAFETY
+#endif  // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
 
 #endif  // GOOGLE_PROTOBUF_ATOMICOPS_H_
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_arm_qnx.h b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_arm_qnx.h
new file mode 100644
index 0000000..f050769
--- /dev/null
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_arm_qnx.h
@@ -0,0 +1,146 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
+
+// For _smp_cmpxchg()
+#include <pthread.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 QNXCmpxchg(Atomic32 old_value,
+                           Atomic32 new_value,
+                           volatile Atomic32* ptr) {
+  return static_cast<Atomic32>(
+      _smp_cmpxchg((volatile unsigned *)ptr,
+                   (unsigned)old_value,
+                   (unsigned)new_value));
+}
+
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value = *ptr;
+  do {
+    if (!QNXCmpxchg(old_value, new_value,
+                    const_cast<Atomic32*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (QNXCmpxchg(old_value, new_value,
+                      const_cast<Atomic32*>(ptr)));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  for (;;) {
+    // Atomic exchange the old value with an incremented one.
+    Atomic32 old_value = *ptr;
+    Atomic32 new_value = old_value + increment;
+    if (QNXCmpxchg(old_value, new_value,
+                   const_cast<Atomic32*>(ptr)) == 0) {
+      // The exchange took place as expected.
+      return new_value;
+    }
+    // Otherwise, *ptr changed mid-loop and we need to retry.
+  }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __sync_synchronize();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h
index 8d9a726..e9d8679 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h
@@ -44,7 +44,7 @@
 // On LP64 platforms, AtomicWord and Atomic64 are both always long,
 // so this problem doesn't occur.
 
-#if !defined(GOOGLE_PROTOBUF_HOST_ARCH_64_BIT)
+#if !defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
 
 namespace google {
 namespace protobuf {
@@ -117,6 +117,6 @@
 }   // namespace protobuf
 }   // namespace google
 
-#endif  // !defined(GOOGLE_PROTOBUF_HOST_ARCH_64_BIT)
+#endif  // !defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
 
 #endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_macosx.h b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_macosx.h
index 9af6d63..f9b7581 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_macosx.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_macosx.h
@@ -136,7 +136,7 @@
   Atomic64 prev_value;
   do {
     if (OSAtomicCompareAndSwap64(old_value, new_value,
-                                 const_cast<Atomic64*>(ptr))) {
+                                 reinterpret_cast<volatile int64_t*>(ptr))) {
       return old_value;
     }
     prev_value = *ptr;
@@ -150,18 +150,19 @@
   do {
     old_value = *ptr;
   } while (!OSAtomicCompareAndSwap64(old_value, new_value,
-                                     const_cast<Atomic64*>(ptr)));
+                                     reinterpret_cast<volatile int64_t*>(ptr)));
   return old_value;
 }
 
 inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
                                           Atomic64 increment) {
-  return OSAtomicAdd64(increment, const_cast<Atomic64*>(ptr));
+  return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
 }
 
 inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
                                         Atomic64 increment) {
-  return OSAtomicAdd64Barrier(increment, const_cast<Atomic64*>(ptr));
+  return OSAtomicAdd64Barrier(increment,
+                              reinterpret_cast<volatile int64_t*>(ptr));
 }
 
 inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
@@ -169,8 +170,8 @@
                                        Atomic64 new_value) {
   Atomic64 prev_value;
   do {
-    if (OSAtomicCompareAndSwap64Barrier(old_value, new_value,
-                                        const_cast<Atomic64*>(ptr))) {
+    if (OSAtomicCompareAndSwap64Barrier(
+        old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
       return old_value;
     }
     prev_value = *ptr;
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_pnacl.h b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_pnacl.h
new file mode 100644
index 0000000..04a91a8
--- /dev/null
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_pnacl.h
@@ -0,0 +1,73 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2012 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  return __sync_val_compare_and_swap(ptr, old_value, new_value);
+}
+
+inline void MemoryBarrier() {
+  __sync_synchronize();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return ret;
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
index 8366a89..0b35979 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc
@@ -32,7 +32,7 @@
 // Therefore we move the code depending on windows.h to this separate cc file.
 
 // Don't compile this file for people not concerned about thread safety.
-#ifndef GOOGLE_PROTOBUF_NO_THREADSAFETY
+#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
 
 #include <google/protobuf/stubs/atomicops.h>
 
@@ -109,4 +109,4 @@
 }  // namespace google
 
 #endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_MSVC_H_
-#endif  // GOOGLE_PROTOBUF_NO_THREADSAFETY
+#endif  // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
diff --git a/third_party/protobuf/src/google/protobuf/stubs/common.cc b/third_party/protobuf/src/google/protobuf/stubs/common.cc
index 16d7852..e604502 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/common.cc
+++ b/third_party/protobuf/src/google/protobuf/stubs/common.cc
@@ -110,7 +110,7 @@
 
   // We use fprintf() instead of cerr because we want this to work at static
   // initialization time.
-  fprintf(stderr, "libprotobuf %s %s:%d] %s\n",
+  fprintf(stderr, "[libprotobuf %s %s:%d] %s\n",
           level_names[level], filename, line, message.c_str());
   fflush(stderr);  // Needed on MSVC.
 }
@@ -183,15 +183,15 @@
   if (level_ != LOGLEVEL_FATAL) {
     InitLogSilencerCountOnce();
     MutexLock lock(log_silencer_count_mutex_);
-    suppress = internal::log_silencer_count_ > 0;
+    suppress = log_silencer_count_ > 0;
   }
 
   if (!suppress) {
-    internal::log_handler_(level_, filename_, line_, message_);
+    log_handler_(level_, filename_, line_, message_);
   }
 
   if (level_ == LOGLEVEL_FATAL) {
-#ifdef PROTOBUF_USE_EXCEPTIONS
+#if PROTOBUF_USE_EXCEPTIONS
     throw FatalException(filename_, line_, message_);
 #else
     abort();
@@ -383,7 +383,7 @@
   internal::shutdown_functions_mutex = NULL;
 }
 
-#ifdef PROTOBUF_USE_EXCEPTIONS
+#if PROTOBUF_USE_EXCEPTIONS
 FatalException::~FatalException() throw() {}
 
 const char* FatalException::what() const throw() {
diff --git a/third_party/protobuf/src/google/protobuf/stubs/common.h b/third_party/protobuf/src/google/protobuf/stubs/common.h
index 4c3e0cb..e9d0e35 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/common.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/common.h
@@ -48,12 +48,17 @@
 #include <stdint.h>
 #endif
 
+#ifndef PROTOBUF_USE_EXCEPTIONS
 #if defined(_MSC_VER) && defined(_CPPUNWIND)
-  #define PROTOBUF_USE_EXCEPTIONS
+  #define PROTOBUF_USE_EXCEPTIONS 1
 #elif defined(__EXCEPTIONS)
-  #define PROTOBUF_USE_EXCEPTIONS
+  #define PROTOBUF_USE_EXCEPTIONS 1
+#else
+  #define PROTOBUF_USE_EXCEPTIONS 0
 #endif
-#ifdef PROTOBUF_USE_EXCEPTIONS
+#endif
+
+#if PROTOBUF_USE_EXCEPTIONS
 #include <exception>
 #endif
 
@@ -123,24 +128,24 @@
 
 // The current version, represented as a single integer to make comparison
 // easier:  major * 10^6 + minor * 10^3 + micro
-#define GOOGLE_PROTOBUF_VERSION 2004002
+#define GOOGLE_PROTOBUF_VERSION 2005000
 
 // The minimum library version which works with the current version of the
 // headers.
-#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2004000
+#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2005000
 
 // The minimum header version which works with the current version of
 // the library.  This constant should only be used by protoc's C++ code
 // generator.
-static const int kMinHeaderVersionForLibrary = 2004000;
+static const int kMinHeaderVersionForLibrary = 2005000;
 
 // The minimum protoc version which works with the current version of the
 // headers.
-#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2004000
+#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2005000
 
 // The minimum header version which works with the current version of
 // protoc.  This constant should only be used in VerifyVersion().
-static const int kMinHeaderVersionForProtoc = 2004000;
+static const int kMinHeaderVersionForProtoc = 2005000;
 
 // Verifies that the headers and libraries are compatible.  Use the macro
 // below to call this.
@@ -356,12 +361,6 @@
   return static_cast<To>(f);
 }
 
-// Simplified down_cast for reference type.
-template<typename To, typename From>
-inline To down_cast(From& f) {
-  return static_cast<To>(f);
-}
-
 }  // namespace internal
 
 // We made these internal so that they would show up as such in the docs,
@@ -1209,7 +1208,7 @@
 
 }  // namespace internal
 
-#ifdef PROTOBUF_USE_EXCEPTIONS
+#if PROTOBUF_USE_EXCEPTIONS
 class FatalException : public std::exception {
  public:
   FatalException(const char* filename, int line, const std::string& message)
diff --git a/third_party/protobuf/src/google/protobuf/stubs/common_unittest.cc b/third_party/protobuf/src/google/protobuf/stubs/common_unittest.cc
index 4109a52..43cd6d0 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/common_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/stubs/common_unittest.cc
@@ -94,9 +94,9 @@
 
   string text = GetCapturedTestStderr();
   EXPECT_EQ(
-    "libprotobuf INFO "__FILE__":" + SimpleItoa(line + 1) + "] A message.\n"
-    "libprotobuf WARNING "__FILE__":" + SimpleItoa(line + 2) + "] A warning.\n"
-    "libprotobuf ERROR "__FILE__":" + SimpleItoa(line + 3) + "] An error.\n",
+    "[libprotobuf INFO "__FILE__":" + SimpleItoa(line + 1) + "] A message.\n"
+    "[libprotobuf WARNING "__FILE__":" + SimpleItoa(line + 2) + "] A warning.\n"
+    "[libprotobuf ERROR "__FILE__":" + SimpleItoa(line + 3) + "] An error.\n",
     text);
 }
 
diff --git a/third_party/protobuf/src/google/protobuf/stubs/once.h b/third_party/protobuf/src/google/protobuf/stubs/once.h
index ead86fb..7fbc117 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/once.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/once.h
@@ -118,8 +118,8 @@
 
 #define GOOGLE_PROTOBUF_ONCE_INIT ::google::protobuf::ONCE_STATE_UNINITIALIZED
 
-LIBPROTOBUF_EXPORT void GoogleOnceInitImpl(ProtobufOnceType* once,
-                                           Closure* closure);
+LIBPROTOBUF_EXPORT
+void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure);
 
 inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
   if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
diff --git a/third_party/protobuf/src/google/protobuf/stubs/platform_macros.h b/third_party/protobuf/src/google/protobuf/stubs/platform_macros.h
index cba9fbd..b1df60e 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/platform_macros.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/platform_macros.h
@@ -43,6 +43,9 @@
 #elif defined(_M_IX86) || defined(__i386__)
 #define GOOGLE_PROTOBUF_ARCH_IA32 1
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__QNX__)
+#define GOOGLE_PROTOBUF_ARCH_ARM_QNX 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #elif defined(__ARMEL__)
 #define GOOGLE_PROTOBUF_ARCH_ARM 1
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
@@ -51,6 +54,9 @@
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #elif defined(__pnacl__)
 #define GOOGLE_PROTOBUF_ARCH_32_BIT 1
+#elif defined(__ppc__)
+#define GOOGLE_PROTOBUF_ARCH_PPC 1
+#define GOOGLE_PROTOBUF_ARCH_32_BIT 1
 #else
 #error Host architecture was not detected as supported by protobuf
 #endif
diff --git a/third_party/protobuf/src/google/protobuf/stubs/stl_util-inl.h b/third_party/protobuf/src/google/protobuf/stubs/stl_util-inl.h
deleted file mode 100644
index a2e671b..0000000
--- a/third_party/protobuf/src/google/protobuf/stubs/stl_util-inl.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// http://code.google.com/p/protobuf/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// from google3/util/gtl/stl_util-inl.h
-
-#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
-#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
-
-#include <google/protobuf/stubs/common.h>
-
-namespace google {
-namespace protobuf {
-
-// STLDeleteContainerPointers()
-//  For a range within a container of pointers, calls delete
-//  (non-array version) on these pointers.
-// NOTE: for these three functions, we could just implement a DeleteObject
-// functor and then call for_each() on the range and functor, but this
-// requires us to pull in all of algorithm.h, which seems expensive.
-// For hash_[multi]set, it is important that this deletes behind the iterator
-// because the hash_set may call the hash function on the iterator when it is
-// advanced, which could result in the hash function trying to deference a
-// stale pointer.
-template <class ForwardIterator>
-void STLDeleteContainerPointers(ForwardIterator begin,
-                                ForwardIterator end) {
-  while (begin != end) {
-    ForwardIterator temp = begin;
-    ++begin;
-    delete *temp;
-  }
-}
-
-// Inside Google, this function implements a horrible, disgusting hack in which
-// we reach into the string's private implementation and resize it without
-// initializing the new bytes.  In some cases doing this can significantly
-// improve performance.  However, since it's totally non-portable it has no
-// place in open source code.  Feel free to fill this function in with your
-// own disgusting hack if you want the perf boost.
-inline void STLStringResizeUninitialized(string* s, size_t new_size) {
-  s->resize(new_size);
-}
-
-// Return a mutable char* pointing to a string's internal buffer,
-// which may not be null-terminated. Writing through this pointer will
-// modify the string.
-//
-// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
-// next call to a string method that invalidates iterators.
-//
-// As of 2006-04, there is no standard-blessed way of getting a
-// mutable reference to a string's internal buffer. However, issue 530
-// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
-// proposes this as the method. According to Matt Austern, this should
-// already work on all current implementations.
-inline char* string_as_array(string* str) {
-  // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
-  return str->empty() ? NULL : &*str->begin();
-}
-
-// STLDeleteElements() deletes all the elements in an STL container and clears
-// the container.  This function is suitable for use with a vector, set,
-// hash_set, or any other STL container which defines sensible begin(), end(),
-// and clear() methods.
-//
-// If container is NULL, this function is a no-op.
-//
-// As an alternative to calling STLDeleteElements() directly, consider
-// ElementDeleter (defined below), which ensures that your container's elements
-// are deleted when the ElementDeleter goes out of scope.
-template <class T>
-void STLDeleteElements(T *container) {
-  if (!container) return;
-  STLDeleteContainerPointers(container->begin(), container->end());
-  container->clear();
-}
-
-// Given an STL container consisting of (key, value) pairs, STLDeleteValues
-// deletes all the "value" components and clears the container.  Does nothing
-// in the case it's given a NULL pointer.
-
-template <class T>
-void STLDeleteValues(T *v) {
-  if (!v) return;
-  for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
-    delete i->second;
-  }
-  v->clear();
-}
-
-}  // namespace protobuf
-}  // namespace google
-
-#endif  // GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
diff --git a/third_party/protobuf/src/google/protobuf/stubs/stringprintf.h b/third_party/protobuf/src/google/protobuf/stubs/stringprintf.h
index 573f30f..4a03e5f 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/stringprintf.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/stringprintf.h
@@ -50,25 +50,25 @@
 namespace protobuf {
 
 // Return a C++ string
-extern string StringPrintf(const char* format, ...);
+LIBPROTOBUF_EXPORT extern string StringPrintf(const char* format, ...);
 
 // Store result into a supplied string and return it
-extern const string& SStringPrintf(string* dst, const char* format, ...);
+LIBPROTOBUF_EXPORT extern const string& SStringPrintf(string* dst, const char* format, ...);
 
 // Append result to a supplied string
-extern void StringAppendF(string* dst, const char* format, ...);
+LIBPROTOBUF_EXPORT extern void StringAppendF(string* dst, const char* format, ...);
 
 // Lower-level routine that takes a va_list and appends to a specified
 // string.  All other routines are just convenience wrappers around it.
-extern void StringAppendV(string* dst, const char* format, va_list ap);
+LIBPROTOBUF_EXPORT extern void StringAppendV(string* dst, const char* format, va_list ap);
 
 // The max arguments supported by StringPrintfVector
-extern const int kStringPrintfVectorMaxArgs;
+LIBPROTOBUF_EXPORT extern const int kStringPrintfVectorMaxArgs;
 
 // You can use this version when all your arguments are strings, but
 // you don't know how many arguments you'll have at compile time.
 // StringPrintfVector will LOG(FATAL) if v.size() > kStringPrintfVectorMaxArgs
-extern string StringPrintfVector(const char* format, const vector<string>& v);
+LIBPROTOBUF_EXPORT extern string StringPrintfVector(const char* format, const vector<string>& v);
 
 }  // namespace protobuf
 }  // namespace google
diff --git a/third_party/protobuf/src/google/protobuf/stubs/type_traits.h b/third_party/protobuf/src/google/protobuf/stubs/type_traits.h
index 997f35d..e41f5e6 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/type_traits.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/type_traits.h
@@ -333,14 +333,4 @@
 }  // namespace protobuf
 }  // namespace google
 
-// Right now these macros are no-ops, and mostly just document the fact
-// these types are PODs, for human use.  They may be made more contentful
-// later.  The typedef is just to make it legal to put a semicolon after
-// these macros.
-#define DECLARE_POD(TypeName) typedef int Dummy_Type_For_DECLARE_POD
-#define DECLARE_NESTED_POD(TypeName) DECLARE_POD(TypeName)
-#define PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(TemplateName)             \
-    typedef int Dummy_Type_For_PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT
-#define ENFORCE_POD(TypeName) typedef int Dummy_Type_For_ENFORCE_POD
-
 #endif  // GOOGLE_PROTOBUF_TYPE_TRAITS_H_
diff --git a/third_party/protobuf/src/google/protobuf/stubs/type_traits_unittest.cc b/third_party/protobuf/src/google/protobuf/stubs/type_traits_unittest.cc
index 00e5a47..7a8cbfb 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/type_traits_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/stubs/type_traits_unittest.cc
@@ -47,27 +47,6 @@
 using std::vector;
 using std::pair;
 
-using google::protobuf::internal::add_reference;
-using google::protobuf::internal::has_trivial_assign;
-using google::protobuf::internal::has_trivial_constructor;
-using google::protobuf::internal::has_trivial_copy;
-using google::protobuf::internal::has_trivial_destructor;
-#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
-using google::protobuf::internal::is_convertible;
-using google::protobuf::internal::is_enum;
-#endif
-using google::protobuf::internal::is_floating_point;
-using google::protobuf::internal::is_integral;
-using google::protobuf::internal::is_pointer;
-using google::protobuf::internal::is_pod;
-using google::protobuf::internal::is_reference;
-using google::protobuf::internal::is_same;
-using google::protobuf::internal::remove_const;
-using google::protobuf::internal::remove_cv;
-using google::protobuf::internal::remove_pointer;
-using google::protobuf::internal::remove_reference;
-using google::protobuf::internal::remove_volatile;
-
 
 // This assertion produces errors like "error: invalid use of
 // incomplete type 'struct <unnamed>::AssertTypesEq<const int, int>'"
@@ -175,6 +154,7 @@
 
 namespace google {
 namespace protobuf {
+namespace internal {
 namespace {
 
 // A base class and a derived class that inherits from it, used for
@@ -643,5 +623,6 @@
 }
 
 }  // anonymous namespace
+}  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/third_party/protobuf/src/google/protobuf/test_util.cc b/third_party/protobuf/src/google/protobuf/test_util.cc
index 841f4b3..a9666fe 100644
--- a/third_party/protobuf/src/google/protobuf/test_util.cc
+++ b/third_party/protobuf/src/google/protobuf/test_util.cc
@@ -309,7 +309,7 @@
   EXPECT_EQ(110  , message.optional_sfixed64());
   EXPECT_EQ(111  , message.optional_float   ());
   EXPECT_EQ(112  , message.optional_double  ());
-  EXPECT_EQ(true , message.optional_bool    ());
+  EXPECT_TRUE(     message.optional_bool    ());
   EXPECT_EQ("115", message.optional_string  ());
   EXPECT_EQ("116", message.optional_bytes   ());
 
@@ -369,7 +369,7 @@
   EXPECT_EQ(210  , message.repeated_sfixed64(0));
   EXPECT_EQ(211  , message.repeated_float   (0));
   EXPECT_EQ(212  , message.repeated_double  (0));
-  EXPECT_EQ(true , message.repeated_bool    (0));
+  EXPECT_TRUE(     message.repeated_bool    (0));
   EXPECT_EQ("215", message.repeated_string  (0));
   EXPECT_EQ("216", message.repeated_bytes   (0));
 
@@ -396,7 +396,7 @@
   EXPECT_EQ(310  , message.repeated_sfixed64(1));
   EXPECT_EQ(311  , message.repeated_float   (1));
   EXPECT_EQ(312  , message.repeated_double  (1));
-  EXPECT_EQ(false, message.repeated_bool    (1));
+  EXPECT_FALSE(    message.repeated_bool    (1));
   EXPECT_EQ("315", message.repeated_string  (1));
   EXPECT_EQ("316", message.repeated_bytes   (1));
 
@@ -446,7 +446,7 @@
   EXPECT_EQ(410  , message.default_sfixed64());
   EXPECT_EQ(411  , message.default_float   ());
   EXPECT_EQ(412  , message.default_double  ());
-  EXPECT_EQ(false, message.default_bool    ());
+  EXPECT_FALSE(    message.default_bool    ());
   EXPECT_EQ("415", message.default_string  ());
   EXPECT_EQ("416", message.default_bytes   ());
 
@@ -503,7 +503,7 @@
   EXPECT_EQ(0    , message.optional_sfixed64());
   EXPECT_EQ(0    , message.optional_float   ());
   EXPECT_EQ(0    , message.optional_double  ());
-  EXPECT_EQ(false, message.optional_bool    ());
+  EXPECT_FALSE(    message.optional_bool    ());
   EXPECT_EQ(""   , message.optional_string  ());
   EXPECT_EQ(""   , message.optional_bytes   ());
 
@@ -592,7 +592,7 @@
   EXPECT_EQ(-50    , message.default_sfixed64());
   EXPECT_EQ( 51.5  , message.default_float   ());
   EXPECT_EQ( 52e3  , message.default_double  ());
-  EXPECT_EQ(true   , message.default_bool    ());
+  EXPECT_TRUE(       message.default_bool    ());
   EXPECT_EQ("hello", message.default_string  ());
   EXPECT_EQ("world", message.default_bytes   ());
 
@@ -651,7 +651,7 @@
   EXPECT_EQ(210  , message.repeated_sfixed64(0));
   EXPECT_EQ(211  , message.repeated_float   (0));
   EXPECT_EQ(212  , message.repeated_double  (0));
-  EXPECT_EQ(true , message.repeated_bool    (0));
+  EXPECT_TRUE(     message.repeated_bool    (0));
   EXPECT_EQ("215", message.repeated_string  (0));
   EXPECT_EQ("216", message.repeated_bytes   (0));
 
@@ -679,7 +679,7 @@
   EXPECT_EQ(510  , message.repeated_sfixed64(1));
   EXPECT_EQ(511  , message.repeated_float   (1));
   EXPECT_EQ(512  , message.repeated_double  (1));
-  EXPECT_EQ(true , message.repeated_bool    (1));
+  EXPECT_TRUE(     message.repeated_bool    (1));
   EXPECT_EQ("515", message.repeated_string  (1));
   EXPECT_EQ("516", message.repeated_bytes   (1));
 
@@ -812,7 +812,7 @@
   EXPECT_EQ(610  , message.packed_sfixed64(0));
   EXPECT_EQ(611  , message.packed_float   (0));
   EXPECT_EQ(612  , message.packed_double  (0));
-  EXPECT_EQ(true , message.packed_bool    (0));
+  EXPECT_TRUE(     message.packed_bool    (0));
   EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0));
 
   EXPECT_EQ(701  , message.packed_int32   (1));
@@ -827,7 +827,7 @@
   EXPECT_EQ(710  , message.packed_sfixed64(1));
   EXPECT_EQ(711  , message.packed_float   (1));
   EXPECT_EQ(712  , message.packed_double  (1));
-  EXPECT_EQ(false, message.packed_bool    (1));
+  EXPECT_FALSE(    message.packed_bool    (1));
   EXPECT_EQ(unittest::FOREIGN_BAZ, message.packed_enum(1));
 }
 
@@ -862,7 +862,7 @@
   EXPECT_EQ(610  , message.unpacked_sfixed64(0));
   EXPECT_EQ(611  , message.unpacked_float   (0));
   EXPECT_EQ(612  , message.unpacked_double  (0));
-  EXPECT_EQ(true , message.unpacked_bool    (0));
+  EXPECT_TRUE(     message.unpacked_bool    (0));
   EXPECT_EQ(unittest::FOREIGN_BAR, message.unpacked_enum(0));
 
   EXPECT_EQ(701  , message.unpacked_int32   (1));
@@ -877,7 +877,7 @@
   EXPECT_EQ(710  , message.unpacked_sfixed64(1));
   EXPECT_EQ(711  , message.unpacked_float   (1));
   EXPECT_EQ(712  , message.unpacked_double  (1));
-  EXPECT_EQ(false, message.unpacked_bool    (1));
+  EXPECT_FALSE(    message.unpacked_bool    (1));
   EXPECT_EQ(unittest::FOREIGN_BAZ, message.unpacked_enum(1));
 }
 
@@ -934,7 +934,7 @@
   EXPECT_EQ(610  , message.packed_sfixed64(0));
   EXPECT_EQ(611  , message.packed_float   (0));
   EXPECT_EQ(612  , message.packed_double  (0));
-  EXPECT_EQ(true , message.packed_bool    (0));
+  EXPECT_TRUE(     message.packed_bool    (0));
   EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0));
   // Actually verify the second (modified) elements now.
   EXPECT_EQ(801  , message.packed_int32   (1));
@@ -949,7 +949,7 @@
   EXPECT_EQ(810  , message.packed_sfixed64(1));
   EXPECT_EQ(811  , message.packed_float   (1));
   EXPECT_EQ(812  , message.packed_double  (1));
-  EXPECT_EQ(true , message.packed_bool    (1));
+  EXPECT_TRUE(     message.packed_bool    (1));
   EXPECT_EQ(unittest::FOREIGN_FOO, message.packed_enum(1));
 }
 
@@ -1178,7 +1178,7 @@
   EXPECT_EQ(110  , message.GetExtension(unittest::optional_sfixed64_extension));
   EXPECT_EQ(111  , message.GetExtension(unittest::optional_float_extension   ));
   EXPECT_EQ(112  , message.GetExtension(unittest::optional_double_extension  ));
-  EXPECT_EQ(true , message.GetExtension(unittest::optional_bool_extension    ));
+  EXPECT_TRUE(     message.GetExtension(unittest::optional_bool_extension    ));
   EXPECT_EQ("115", message.GetExtension(unittest::optional_string_extension  ));
   EXPECT_EQ("116", message.GetExtension(unittest::optional_bytes_extension   ));
 
@@ -1238,7 +1238,7 @@
   EXPECT_EQ(210  , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
   EXPECT_EQ(211  , message.GetExtension(unittest::repeated_float_extension   , 0));
   EXPECT_EQ(212  , message.GetExtension(unittest::repeated_double_extension  , 0));
-  EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension    , 0));
+  EXPECT_TRUE(     message.GetExtension(unittest::repeated_bool_extension    , 0));
   EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension  , 0));
   EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension   , 0));
 
@@ -1267,7 +1267,7 @@
   EXPECT_EQ(310  , message.GetExtension(unittest::repeated_sfixed64_extension, 1));
   EXPECT_EQ(311  , message.GetExtension(unittest::repeated_float_extension   , 1));
   EXPECT_EQ(312  , message.GetExtension(unittest::repeated_double_extension  , 1));
-  EXPECT_EQ(false, message.GetExtension(unittest::repeated_bool_extension    , 1));
+  EXPECT_FALSE(    message.GetExtension(unittest::repeated_bool_extension    , 1));
   EXPECT_EQ("315", message.GetExtension(unittest::repeated_string_extension  , 1));
   EXPECT_EQ("316", message.GetExtension(unittest::repeated_bytes_extension   , 1));
 
@@ -1321,7 +1321,7 @@
   EXPECT_EQ(410  , message.GetExtension(unittest::default_sfixed64_extension));
   EXPECT_EQ(411  , message.GetExtension(unittest::default_float_extension   ));
   EXPECT_EQ(412  , message.GetExtension(unittest::default_double_extension  ));
-  EXPECT_EQ(false, message.GetExtension(unittest::default_bool_extension    ));
+  EXPECT_FALSE(    message.GetExtension(unittest::default_bool_extension    ));
   EXPECT_EQ("415", message.GetExtension(unittest::default_string_extension  ));
   EXPECT_EQ("416", message.GetExtension(unittest::default_bytes_extension   ));
 
@@ -1386,7 +1386,7 @@
   EXPECT_EQ(0    , message.GetExtension(unittest::optional_sfixed64_extension));
   EXPECT_EQ(0    , message.GetExtension(unittest::optional_float_extension   ));
   EXPECT_EQ(0    , message.GetExtension(unittest::optional_double_extension  ));
-  EXPECT_EQ(false, message.GetExtension(unittest::optional_bool_extension    ));
+  EXPECT_FALSE(    message.GetExtension(unittest::optional_bool_extension    ));
   EXPECT_EQ(""   , message.GetExtension(unittest::optional_string_extension  ));
   EXPECT_EQ(""   , message.GetExtension(unittest::optional_bytes_extension   ));
 
@@ -1479,7 +1479,7 @@
   EXPECT_EQ(-50    , message.GetExtension(unittest::default_sfixed64_extension));
   EXPECT_EQ( 51.5  , message.GetExtension(unittest::default_float_extension   ));
   EXPECT_EQ( 52e3  , message.GetExtension(unittest::default_double_extension  ));
-  EXPECT_EQ(true   , message.GetExtension(unittest::default_bool_extension    ));
+  EXPECT_TRUE(       message.GetExtension(unittest::default_bool_extension    ));
   EXPECT_EQ("hello", message.GetExtension(unittest::default_string_extension  ));
   EXPECT_EQ("world", message.GetExtension(unittest::default_bytes_extension   ));
 
@@ -1538,7 +1538,7 @@
   EXPECT_EQ(210  , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
   EXPECT_EQ(211  , message.GetExtension(unittest::repeated_float_extension   , 0));
   EXPECT_EQ(212  , message.GetExtension(unittest::repeated_double_extension  , 0));
-  EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension    , 0));
+  EXPECT_TRUE(     message.GetExtension(unittest::repeated_bool_extension    , 0));
   EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension  , 0));
   EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension   , 0));
 
@@ -1568,7 +1568,7 @@
   EXPECT_EQ(510  , message.GetExtension(unittest::repeated_sfixed64_extension, 1));
   EXPECT_EQ(511  , message.GetExtension(unittest::repeated_float_extension   , 1));
   EXPECT_EQ(512  , message.GetExtension(unittest::repeated_double_extension  , 1));
-  EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension    , 1));
+  EXPECT_TRUE(     message.GetExtension(unittest::repeated_bool_extension    , 1));
   EXPECT_EQ("515", message.GetExtension(unittest::repeated_string_extension  , 1));
   EXPECT_EQ("516", message.GetExtension(unittest::repeated_bytes_extension   , 1));
 
@@ -1671,7 +1671,7 @@
   EXPECT_EQ(610  , message.GetExtension(unittest::packed_sfixed64_extension, 0));
   EXPECT_EQ(611  , message.GetExtension(unittest::packed_float_extension   , 0));
   EXPECT_EQ(612  , message.GetExtension(unittest::packed_double_extension  , 0));
-  EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension    , 0));
+  EXPECT_TRUE(     message.GetExtension(unittest::packed_bool_extension    , 0));
   EXPECT_EQ(unittest::FOREIGN_BAR,
             message.GetExtension(unittest::packed_enum_extension, 0));
   EXPECT_EQ(701  , message.GetExtension(unittest::packed_int32_extension   , 1));
@@ -1686,7 +1686,7 @@
   EXPECT_EQ(710  , message.GetExtension(unittest::packed_sfixed64_extension, 1));
   EXPECT_EQ(711  , message.GetExtension(unittest::packed_float_extension   , 1));
   EXPECT_EQ(712  , message.GetExtension(unittest::packed_double_extension  , 1));
-  EXPECT_EQ(false, message.GetExtension(unittest::packed_bool_extension    , 1));
+  EXPECT_FALSE(    message.GetExtension(unittest::packed_bool_extension    , 1));
   EXPECT_EQ(unittest::FOREIGN_BAZ,
             message.GetExtension(unittest::packed_enum_extension, 1));
 }
@@ -1741,7 +1741,7 @@
   EXPECT_EQ(610  , message.GetExtension(unittest::packed_sfixed64_extension, 0));
   EXPECT_EQ(611  , message.GetExtension(unittest::packed_float_extension   , 0));
   EXPECT_EQ(612  , message.GetExtension(unittest::packed_double_extension  , 0));
-  EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension    , 0));
+  EXPECT_TRUE(     message.GetExtension(unittest::packed_bool_extension    , 0));
   EXPECT_EQ(unittest::FOREIGN_BAR,
             message.GetExtension(unittest::packed_enum_extension, 0));
 
@@ -1758,7 +1758,7 @@
   EXPECT_EQ(810  , message.GetExtension(unittest::packed_sfixed64_extension, 1));
   EXPECT_EQ(811  , message.GetExtension(unittest::packed_float_extension   , 1));
   EXPECT_EQ(812  , message.GetExtension(unittest::packed_double_extension  , 1));
-  EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension    , 1));
+  EXPECT_TRUE(     message.GetExtension(unittest::packed_bool_extension    , 1));
   EXPECT_EQ(unittest::FOREIGN_FOO,
             message.GetExtension(unittest::packed_enum_extension, 1));
 }
@@ -1835,7 +1835,7 @@
   EXPECT_EQ(210  , message.repeated_sfixed64(0));
   EXPECT_EQ(211  , message.repeated_float   (0));
   EXPECT_EQ(212  , message.repeated_double  (0));
-  EXPECT_EQ(true , message.repeated_bool    (0));
+  EXPECT_TRUE(     message.repeated_bool    (0));
   EXPECT_EQ("215", message.repeated_string  (0));
   EXPECT_EQ("216", message.repeated_bytes   (0));
 
@@ -1895,7 +1895,7 @@
   EXPECT_EQ(210  , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
   EXPECT_EQ(211  , message.GetExtension(unittest::repeated_float_extension   , 0));
   EXPECT_EQ(212  , message.GetExtension(unittest::repeated_double_extension  , 0));
-  EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension    , 0));
+  EXPECT_TRUE(     message.GetExtension(unittest::repeated_bool_extension    , 0));
   EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension  , 0));
   EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension   , 0));
 
@@ -1988,7 +1988,7 @@
   EXPECT_EQ(210  , message.repeated_sfixed64(1));
   EXPECT_EQ(211  , message.repeated_float   (1));
   EXPECT_EQ(212  , message.repeated_double  (1));
-  EXPECT_EQ(true , message.repeated_bool    (1));
+  EXPECT_TRUE(     message.repeated_bool    (1));
   EXPECT_EQ("215", message.repeated_string  (1));
   EXPECT_EQ("216", message.repeated_bytes   (1));
 
@@ -2014,7 +2014,7 @@
   EXPECT_EQ(310  , message.repeated_sfixed64(0));
   EXPECT_EQ(311  , message.repeated_float   (0));
   EXPECT_EQ(312  , message.repeated_double  (0));
-  EXPECT_EQ(false, message.repeated_bool    (0));
+  EXPECT_FALSE(    message.repeated_bool    (0));
   EXPECT_EQ("315", message.repeated_string  (0));
   EXPECT_EQ("316", message.repeated_bytes   (0));
 
@@ -2072,7 +2072,7 @@
   EXPECT_EQ(210  , message.GetExtension(unittest::repeated_sfixed64_extension, 1));
   EXPECT_EQ(211  , message.GetExtension(unittest::repeated_float_extension   , 1));
   EXPECT_EQ(212  , message.GetExtension(unittest::repeated_double_extension  , 1));
-  EXPECT_EQ(true , message.GetExtension(unittest::repeated_bool_extension    , 1));
+  EXPECT_TRUE(     message.GetExtension(unittest::repeated_bool_extension    , 1));
   EXPECT_EQ("215", message.GetExtension(unittest::repeated_string_extension  , 1));
   EXPECT_EQ("216", message.GetExtension(unittest::repeated_bytes_extension   , 1));
 
@@ -2101,7 +2101,7 @@
   EXPECT_EQ(310  , message.GetExtension(unittest::repeated_sfixed64_extension, 0));
   EXPECT_EQ(311  , message.GetExtension(unittest::repeated_float_extension   , 0));
   EXPECT_EQ(312  , message.GetExtension(unittest::repeated_double_extension  , 0));
-  EXPECT_EQ(false, message.GetExtension(unittest::repeated_bool_extension    , 0));
+  EXPECT_FALSE(    message.GetExtension(unittest::repeated_bool_extension    , 0));
   EXPECT_EQ("315", message.GetExtension(unittest::repeated_string_extension  , 0));
   EXPECT_EQ("316", message.GetExtension(unittest::repeated_bytes_extension   , 0));
 
@@ -2443,7 +2443,7 @@
   EXPECT_EQ(110  , reflection->GetInt64 (message, F("optional_sfixed64")));
   EXPECT_EQ(111  , reflection->GetFloat (message, F("optional_float"   )));
   EXPECT_EQ(112  , reflection->GetDouble(message, F("optional_double"  )));
-  EXPECT_EQ(true , reflection->GetBool  (message, F("optional_bool"    )));
+  EXPECT_TRUE(     reflection->GetBool  (message, F("optional_bool"    )));
   EXPECT_EQ("115", reflection->GetString(message, F("optional_string"  )));
   EXPECT_EQ("116", reflection->GetString(message, F("optional_bytes"   )));
 
@@ -2523,7 +2523,7 @@
   EXPECT_EQ(210  , reflection->GetRepeatedInt64 (message, F("repeated_sfixed64"), 0));
   EXPECT_EQ(211  , reflection->GetRepeatedFloat (message, F("repeated_float"   ), 0));
   EXPECT_EQ(212  , reflection->GetRepeatedDouble(message, F("repeated_double"  ), 0));
-  EXPECT_EQ(true , reflection->GetRepeatedBool  (message, F("repeated_bool"    ), 0));
+  EXPECT_TRUE(     reflection->GetRepeatedBool  (message, F("repeated_bool"    ), 0));
   EXPECT_EQ("215", reflection->GetRepeatedString(message, F("repeated_string"  ), 0));
   EXPECT_EQ("216", reflection->GetRepeatedString(message, F("repeated_bytes"   ), 0));
 
@@ -2565,7 +2565,7 @@
   EXPECT_EQ(310  , reflection->GetRepeatedInt64 (message, F("repeated_sfixed64"), 1));
   EXPECT_EQ(311  , reflection->GetRepeatedFloat (message, F("repeated_float"   ), 1));
   EXPECT_EQ(312  , reflection->GetRepeatedDouble(message, F("repeated_double"  ), 1));
-  EXPECT_EQ(false, reflection->GetRepeatedBool  (message, F("repeated_bool"    ), 1));
+  EXPECT_FALSE(    reflection->GetRepeatedBool  (message, F("repeated_bool"    ), 1));
   EXPECT_EQ("315", reflection->GetRepeatedString(message, F("repeated_string"  ), 1));
   EXPECT_EQ("316", reflection->GetRepeatedString(message, F("repeated_bytes"   ), 1));
 
@@ -2640,7 +2640,7 @@
   EXPECT_EQ(410  , reflection->GetInt64 (message, F("default_sfixed64")));
   EXPECT_EQ(411  , reflection->GetFloat (message, F("default_float"   )));
   EXPECT_EQ(412  , reflection->GetDouble(message, F("default_double"  )));
-  EXPECT_EQ(false, reflection->GetBool  (message, F("default_bool"    )));
+  EXPECT_FALSE(    reflection->GetBool  (message, F("default_bool"    )));
   EXPECT_EQ("415", reflection->GetString(message, F("default_string"  )));
   EXPECT_EQ("416", reflection->GetString(message, F("default_bytes"   )));
 
@@ -2690,7 +2690,7 @@
   EXPECT_EQ(610  , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 0));
   EXPECT_EQ(611  , reflection->GetRepeatedFloat (message, F("packed_float"   ), 0));
   EXPECT_EQ(612  , reflection->GetRepeatedDouble(message, F("packed_double"  ), 0));
-  EXPECT_EQ(true , reflection->GetRepeatedBool  (message, F("packed_bool"    ), 0));
+  EXPECT_TRUE(     reflection->GetRepeatedBool  (message, F("packed_bool"    ), 0));
   EXPECT_EQ(foreign_bar_,
             reflection->GetRepeatedEnum(message, F("packed_enum"), 0));
 
@@ -2706,7 +2706,7 @@
   EXPECT_EQ(710  , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 1));
   EXPECT_EQ(711  , reflection->GetRepeatedFloat (message, F("packed_float"   ), 1));
   EXPECT_EQ(712  , reflection->GetRepeatedDouble(message, F("packed_double"  ), 1));
-  EXPECT_EQ(false, reflection->GetRepeatedBool  (message, F("packed_bool"    ), 1));
+  EXPECT_FALSE(    reflection->GetRepeatedBool  (message, F("packed_bool"    ), 1));
   EXPECT_EQ(foreign_baz_,
             reflection->GetRepeatedEnum(message, F("packed_enum"), 1));
 }
@@ -2763,7 +2763,7 @@
   EXPECT_EQ(0    , reflection->GetInt64 (message, F("optional_sfixed64")));
   EXPECT_EQ(0    , reflection->GetFloat (message, F("optional_float"   )));
   EXPECT_EQ(0    , reflection->GetDouble(message, F("optional_double"  )));
-  EXPECT_EQ(false, reflection->GetBool  (message, F("optional_bool"    )));
+  EXPECT_FALSE(    reflection->GetBool  (message, F("optional_bool"    )));
   EXPECT_EQ(""   , reflection->GetString(message, F("optional_string"  )));
   EXPECT_EQ(""   , reflection->GetString(message, F("optional_bytes"   )));
 
@@ -2867,7 +2867,7 @@
   EXPECT_EQ(-50    , reflection->GetInt64 (message, F("default_sfixed64")));
   EXPECT_EQ( 51.5  , reflection->GetFloat (message, F("default_float"   )));
   EXPECT_EQ( 52e3  , reflection->GetDouble(message, F("default_double"  )));
-  EXPECT_EQ(true   , reflection->GetBool  (message, F("default_bool"    )));
+  EXPECT_TRUE(       reflection->GetBool  (message, F("default_bool"    )));
   EXPECT_EQ("hello", reflection->GetString(message, F("default_string"  )));
   EXPECT_EQ("world", reflection->GetString(message, F("default_bytes"   )));
 
diff --git a/third_party/protobuf/src/google/protobuf/testing/googletest.h b/third_party/protobuf/src/google/protobuf/testing/googletest.h
index 6b17ae4..003be10 100644
--- a/third_party/protobuf/src/google/protobuf/testing/googletest.h
+++ b/third_party/protobuf/src/google/protobuf/testing/googletest.h
@@ -38,6 +38,11 @@
 #include <vector>
 #include <google/protobuf/stubs/common.h>
 
+// Disable death tests if we use exceptions in CHECK().
+#if !PROTOBUF_USE_EXCEPTIONS && defined(GTEST_HAS_DEATH_TEST)
+#define PROTOBUF_HAS_DEATH_TEST
+#endif
+
 namespace google {
 namespace protobuf {
 
diff --git a/third_party/protobuf/src/google/protobuf/text_format.cc b/third_party/protobuf/src/google/protobuf/text_format.cc
index 1ee3df5..cabb99e 100644
--- a/third_party/protobuf/src/google/protobuf/text_format.cc
+++ b/third_party/protobuf/src/google/protobuf/text_format.cc
@@ -434,8 +434,8 @@
     // If a parse info tree exists, add the location for the parsed
     // field.
     if (parse_info_tree_ != NULL) {
-      parse_info_tree_->RecordLocation(field,
-                                       ParseLocation(start_line, start_column));
+      RecordLocation(parse_info_tree_, field,
+                     ParseLocation(start_line, start_column));
     }
 
     return true;
@@ -483,7 +483,7 @@
     // for the nested message.
     ParseInfoTree* parent = parse_info_tree_;
     if (parent != NULL) {
-      parse_info_tree_ = parent->CreateNested(field);
+      parse_info_tree_ = CreateNested(parent, field);
     }
 
     string delimeter;
diff --git a/third_party/protobuf/src/google/protobuf/text_format.h b/third_party/protobuf/src/google/protobuf/text_format.h
index 0974139..01f3ffb 100644
--- a/third_party/protobuf/src/google/protobuf/text_format.h
+++ b/third_party/protobuf/src/google/protobuf/text_format.h
@@ -339,9 +339,30 @@
   };
 
  private:
+  // Hack: ParseInfoTree declares TextFormat as a friend which should extend
+  // the friendship to TextFormat::Parser::ParserImpl, but unfortunately some
+  // old compilers (e.g. GCC 3.4.6) don't implement this correctly. We provide
+  // helpers for ParserImpl to call methods of ParseInfoTree.
+  static inline void RecordLocation(ParseInfoTree* info_tree,
+                                    const FieldDescriptor* field,
+                                    ParseLocation location);
+  static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
+                                            const FieldDescriptor* field);
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat);
 };
 
+inline void TextFormat::RecordLocation(ParseInfoTree* info_tree,
+                                       const FieldDescriptor* field,
+                                       ParseLocation location) {
+  info_tree->RecordLocation(field, location);
+}
+
+inline TextFormat::ParseInfoTree* TextFormat::CreateNested(
+    ParseInfoTree* info_tree, const FieldDescriptor* field) {
+  return info_tree->CreateNested(field);
+}
+
 }  // namespace protobuf
 
 }  // namespace google
diff --git a/third_party/protobuf/src/google/protobuf/text_format_unittest.cc b/third_party/protobuf/src/google/protobuf/text_format_unittest.cc
index 353a5e4..304fb84 100644
--- a/third_party/protobuf/src/google/protobuf/text_format_unittest.cc
+++ b/third_party/protobuf/src/google/protobuf/text_format_unittest.cc
@@ -858,6 +858,12 @@
   EXPECT_EQ(value, message->optional_##name()); \
   EXPECT_TRUE(message->has_optional_##name());
 
+#define EXPECT_BOOL_FIELD(name, value, valuestring) \
+  EXPECT_TRUE(TextFormat::ParseFieldValueFromString( \
+    valuestring, d->FindFieldByName("optional_" #name), message.get())); \
+  EXPECT_TRUE(message->optional_##name() == value); \
+  EXPECT_TRUE(message->has_optional_##name());
+
 #define EXPECT_FLOAT_FIELD(name, value, valuestring) \
   EXPECT_TRUE(TextFormat::ParseFieldValueFromString( \
     valuestring, d->FindFieldByName("optional_" #name), message.get())); \
@@ -915,12 +921,12 @@
   EXPECT_INVALID(fixed64, "1,2");
 
   // bool
-  EXPECT_FIELD(bool, true, "true");
-  EXPECT_FIELD(bool, false, "false");
-  EXPECT_FIELD(bool, true, "1");
-  EXPECT_FIELD(bool, true, "t");
-  EXPECT_FIELD(bool, false, "0");
-  EXPECT_FIELD(bool, false, "f");
+  EXPECT_BOOL_FIELD(bool, true, "true");
+  EXPECT_BOOL_FIELD(bool, false, "false");
+  EXPECT_BOOL_FIELD(bool, true, "1");
+  EXPECT_BOOL_FIELD(bool, true, "t");
+  EXPECT_BOOL_FIELD(bool, false, "0");
+  EXPECT_BOOL_FIELD(bool, false, "f");
   EXPECT_INVALID(bool, "2");
   EXPECT_INVALID(bool, "-0");
   EXPECT_INVALID(bool, "on");
@@ -962,6 +968,7 @@
   EXPECT_INVALID(nested_message, "any");
 
 #undef EXPECT_FIELD
+#undef EXPECT_BOOL_FIELD
 #undef EXPECT_FLOAT_FIELD
 #undef EXPECT_DOUBLE_FIELD
 #undef EXPECT_INVALID
diff --git a/third_party/protobuf/src/google/protobuf/unittest.proto b/third_party/protobuf/src/google/protobuf/unittest.proto
index 0305be6..6eb2d86 100644
--- a/third_party/protobuf/src/google/protobuf/unittest.proto
+++ b/third_party/protobuf/src/google/protobuf/unittest.proto
@@ -434,6 +434,7 @@
 
 // Test an enum that has multiple values with the same number.
 enum TestEnumWithDupValue {
+  option allow_alias = true;
   FOO1 = 1;
   BAR1 = 2;
   BAZ = 3;
diff --git a/third_party/protobuf/src/google/protobuf/wire_format.h b/third_party/protobuf/src/google/protobuf/wire_format.h
index 8a89881..fc60f51 100644
--- a/third_party/protobuf/src/google/protobuf/wire_format.h
+++ b/third_party/protobuf/src/google/protobuf/wire_format.h
@@ -230,6 +230,9 @@
     WireFormat::Operation op) {
 #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
   WireFormat::VerifyUTF8StringFallback(data, size, op);
+#else
+  // Avoid the compiler warning about unsued variables.
+  (void)data; (void)size; (void)op;
 #endif
 }
 
diff --git a/third_party/protobuf/src/google/protobuf/wire_format_lite_inl.h b/third_party/protobuf/src/google/protobuf/wire_format_lite_inl.h
index 0f97386..641cc92 100644
--- a/third_party/protobuf/src/google/protobuf/wire_format_lite_inl.h
+++ b/third_party/protobuf/src/google/protobuf/wire_format_lite_inl.h
@@ -299,12 +299,12 @@
       tag_size, tag, input, values);                                           \
 }
 
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT);
-READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE);
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT)
+READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE)
 
 #undef READ_REPEATED_FIXED_SIZE_PRIMITIVE
 
diff --git a/third_party/protobuf/vsprojects/extract_includes.bat b/third_party/protobuf/vsprojects/extract_includes.bat
index 4dcb4e1..a92d114 100755
--- a/third_party/protobuf/vsprojects/extract_includes.bat
+++ b/third_party/protobuf/vsprojects/extract_includes.bat
@@ -12,6 +12,8 @@
 copy ..\src\google\protobuf\stubs\common.h include\google\protobuf\stubs\common.h

 copy ..\src\google\protobuf\stubs\once.h include\google\protobuf\stubs\once.h

 copy ..\src\google\protobuf\stubs\platform_macros.h include\google\protobuf\stubs\platform_macros.h

+copy ..\src\google\protobuf\stubs\template_util.h include\google\protobuf\stubs\template_util.h

+copy ..\src\google\protobuf\stubs\type_traits.h include\google\protobuf\stubs\type_traits.h

 copy ..\src\google\protobuf\descriptor.h include\google\protobuf\descriptor.h

 copy ..\src\google\protobuf\descriptor.pb.h include\google\protobuf\descriptor.pb.h

 copy ..\src\google\protobuf\descriptor_database.h include\google\protobuf\descriptor_database.h

diff --git a/third_party/zlib/google/zip.gyp b/third_party/zlib/google/zip.gyp
new file mode 100644
index 0000000..9542f9c
--- /dev/null
+++ b/third_party/zlib/google/zip.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': 'zip',
+      'type': 'static_library',
+      'dependencies': [
+        '../zlib.gyp:minizip',
+        '../../../base/base.gyp:base',
+      ],
+      'include_dirs': [
+        '../../..',
+      ],
+      'sources': [
+        'zip.cc',
+        'zip.h',
+        'zip_internal.cc',
+        'zip_internal.h',
+        'zip_reader.cc',
+        'zip_reader.h',
+      ],
+    },
+  ],
+}
diff --git a/third_party/zlib/google/zip.target.darwin-arm.mk b/third_party/zlib/google/zip.target.darwin-arm.mk
new file mode 100644
index 0000000..cdff4da
--- /dev/null
+++ b/third_party/zlib/google/zip.target.darwin-arm.mk
@@ -0,0 +1,255 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_zlib_google_zip_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 :=
+
+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 := \
+	third_party/zlib/google/zip.cc \
+	third_party/zlib/google/zip_internal.cc \
+	third_party/zlib/google/zip_reader.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-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/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+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,--gc-sections \
+	-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
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# 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: third_party_zlib_google_zip_gyp
+
+# Alias gyp target name.
+.PHONY: zip
+zip: third_party_zlib_google_zip_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/google/zip.target.darwin-mips.mk b/third_party/zlib/google/zip.target.darwin-mips.mk
new file mode 100644
index 0000000..a2340e8
--- /dev/null
+++ b/third_party/zlib/google/zip.target.darwin-mips.mk
@@ -0,0 +1,251 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_zlib_google_zip_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 :=
+
+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 := \
+	third_party/zlib/google/zip.cc \
+	third_party/zlib/google/zip_internal.cc \
+	third_party/zlib/google/zip_reader.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-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/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+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,--gc-sections \
+	-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
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# 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: third_party_zlib_google_zip_gyp
+
+# Alias gyp target name.
+.PHONY: zip
+zip: third_party_zlib_google_zip_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/google/zip.target.darwin-x86.mk b/third_party/zlib/google/zip.target.darwin-x86.mk
new file mode 100644
index 0000000..d98bf89
--- /dev/null
+++ b/third_party/zlib/google/zip.target.darwin-x86.mk
@@ -0,0 +1,255 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_zlib_google_zip_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 :=
+
+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 := \
+	third_party/zlib/google/zip.cc \
+	third_party/zlib/google/zip_internal.cc \
+	third_party/zlib/google/zip_reader.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-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/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+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,--gc-sections \
+	-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
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# 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: third_party_zlib_google_zip_gyp
+
+# Alias gyp target name.
+.PHONY: zip
+zip: third_party_zlib_google_zip_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/google/zip.target.linux-arm.mk b/third_party/zlib/google/zip.target.linux-arm.mk
new file mode 100644
index 0000000..cdff4da
--- /dev/null
+++ b/third_party/zlib/google/zip.target.linux-arm.mk
@@ -0,0 +1,255 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_zlib_google_zip_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 :=
+
+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 := \
+	third_party/zlib/google/zip.cc \
+	third_party/zlib/google/zip_internal.cc \
+	third_party/zlib/google/zip_reader.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-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/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+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,--gc-sections \
+	-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
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# 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: third_party_zlib_google_zip_gyp
+
+# Alias gyp target name.
+.PHONY: zip
+zip: third_party_zlib_google_zip_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/google/zip.target.linux-mips.mk b/third_party/zlib/google/zip.target.linux-mips.mk
new file mode 100644
index 0000000..a2340e8
--- /dev/null
+++ b/third_party/zlib/google/zip.target.linux-mips.mk
@@ -0,0 +1,251 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_zlib_google_zip_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 :=
+
+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 := \
+	third_party/zlib/google/zip.cc \
+	third_party/zlib/google/zip_internal.cc \
+	third_party/zlib/google/zip_reader.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-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/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-uninitialized \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+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,--gc-sections \
+	-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
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# 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: third_party_zlib_google_zip_gyp
+
+# Alias gyp target name.
+.PHONY: zip
+zip: third_party_zlib_google_zip_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/google/zip.target.linux-x86.mk b/third_party/zlib/google/zip.target.linux-x86.mk
new file mode 100644
index 0000000..d98bf89
--- /dev/null
+++ b/third_party/zlib/google/zip.target.linux-x86.mk
@@ -0,0 +1,255 @@
+# This file is generated by gyp; do not edit.
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := third_party_zlib_google_zip_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 :=
+
+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 := \
+	third_party/zlib/google/zip.cc \
+	third_party/zlib/google/zip_internal.cc \
+	third_party/zlib/google/zip_reader.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-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/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	--param=ssp-buffer-size=4 \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-Wno-format \
+	-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 \
+	-Wno-address \
+	-Wno-format-security \
+	-Wno-return-type \
+	-Wno-sequence-point \
+	-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' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
+	$(LOCAL_PATH) \
+	$(LOCAL_PATH)/third_party/zlib \
+	$(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 \
+	-Wno-deprecated \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo \
+	-Wno-non-virtual-dtor
+
+
+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,--gc-sections \
+	-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
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# 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: third_party_zlib_google_zip_gyp
+
+# Alias gyp target name.
+.PHONY: zip
+zip: third_party_zlib_google_zip_gyp
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/zip.target.darwin-arm.mk b/third_party/zlib/zip.target.darwin-arm.mk
deleted file mode 100644
index bc40f8c..0000000
--- a/third_party/zlib/zip.target.darwin-arm.mk
+++ /dev/null
@@ -1,255 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := third_party_zlib_zip_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 :=
-
-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 := \
-	third_party/zlib/google/zip.cc \
-	third_party/zlib/google/zip_internal.cc \
-	third_party/zlib/google/zip_reader.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-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/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES :=
-
-# 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: third_party_zlib_zip_gyp
-
-# Alias gyp target name.
-.PHONY: zip
-zip: third_party_zlib_zip_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/zip.target.darwin-mips.mk b/third_party/zlib/zip.target.darwin-mips.mk
deleted file mode 100644
index 554ba41..0000000
--- a/third_party/zlib/zip.target.darwin-mips.mk
+++ /dev/null
@@ -1,251 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := third_party_zlib_zip_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 :=
-
-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 := \
-	third_party/zlib/google/zip.cc \
-	third_party/zlib/google/zip_internal.cc \
-	third_party/zlib/google/zip_reader.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-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/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES :=
-
-# 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: third_party_zlib_zip_gyp
-
-# Alias gyp target name.
-.PHONY: zip
-zip: third_party_zlib_zip_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/zip.target.darwin-x86.mk b/third_party/zlib/zip.target.darwin-x86.mk
deleted file mode 100644
index 101b637..0000000
--- a/third_party/zlib/zip.target.darwin-x86.mk
+++ /dev/null
@@ -1,255 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := third_party_zlib_zip_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 :=
-
-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 := \
-	third_party/zlib/google/zip.cc \
-	third_party/zlib/google/zip_internal.cc \
-	third_party/zlib/google/zip_reader.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-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/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES :=
-
-# 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: third_party_zlib_zip_gyp
-
-# Alias gyp target name.
-.PHONY: zip
-zip: third_party_zlib_zip_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/zip.target.linux-arm.mk b/third_party/zlib/zip.target.linux-arm.mk
deleted file mode 100644
index bc40f8c..0000000
--- a/third_party/zlib/zip.target.linux-arm.mk
+++ /dev/null
@@ -1,255 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := third_party_zlib_zip_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 :=
-
-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 := \
-	third_party/zlib/google/zip.cc \
-	third_party/zlib/google/zip_internal.cc \
-	third_party/zlib/google/zip_reader.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-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/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES :=
-
-# 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: third_party_zlib_zip_gyp
-
-# Alias gyp target name.
-.PHONY: zip
-zip: third_party_zlib_zip_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/zip.target.linux-mips.mk b/third_party/zlib/zip.target.linux-mips.mk
deleted file mode 100644
index 554ba41..0000000
--- a/third_party/zlib/zip.target.linux-mips.mk
+++ /dev/null
@@ -1,251 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := third_party_zlib_zip_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 :=
-
-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 := \
-	third_party/zlib/google/zip.cc \
-	third_party/zlib/google/zip_internal.cc \
-	third_party/zlib/google/zip_reader.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-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/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES :=
-
-# 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: third_party_zlib_zip_gyp
-
-# Alias gyp target name.
-.PHONY: zip
-zip: third_party_zlib_zip_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/zip.target.linux-x86.mk b/third_party/zlib/zip.target.linux-x86.mk
deleted file mode 100644
index 101b637..0000000
--- a/third_party/zlib/zip.target.linux-x86.mk
+++ /dev/null
@@ -1,255 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := third_party_zlib_zip_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 :=
-
-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 := \
-	third_party/zlib/google/zip.cc \
-	third_party/zlib/google/zip_internal.cc \
-	third_party/zlib/google/zip_reader.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-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/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# Include paths placed before CFLAGS/CPPFLAGS
-LOCAL_C_INCLUDES_Release := \
-	$(gyp_shared_intermediate_dir)/shim_headers/ashmem/target \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/zlib \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES :=
-
-# 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: third_party_zlib_zip_gyp
-
-# Alias gyp target name.
-.PHONY: zip
-zip: third_party_zlib_zip_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/third_party/zlib/zlib.gyp b/third_party/zlib/zlib.gyp
index ebdad42..279a6e8 100644
--- a/third_party/zlib/zlib.gyp
+++ b/third_party/zlib/zlib.gyp
@@ -107,24 +107,5 @@
         }],
       ],
     },
-    {
-      'target_name': 'zip',
-      'type': 'static_library',
-      'dependencies': [
-        'minizip',
-        '../../base/base.gyp:base',
-      ],
-      'include_dirs': [
-        '../..',
-      ],
-      'sources': [
-        'google/zip.cc',
-        'google/zip.h',
-        'google/zip_internal.cc',
-        'google/zip_internal.h',
-        'google/zip_reader.cc',
-        'google/zip_reader.h',
-      ],
-    },
   ],
 }
diff --git a/tools/android/android_tools.gyp b/tools/android/android_tools.gyp
index 5aeb96f..c38cd70 100644
--- a/tools/android/android_tools.gyp
+++ b/tools/android/android_tools.gyp
@@ -5,7 +5,7 @@
 {
   'targets': [
     # Intermediate target grouping the android tools needed to run native
-    # unittests apks.
+    # unittests and instrumentation test apks.
     {
       'target_name': 'android_tools',
       'type': 'none',
diff --git a/tools/android/memdump/memreport.py b/tools/android/memdump/memreport.py
index 1db1cb6..80e12a8 100755
--- a/tools/android/memdump/memreport.py
+++ b/tools/android/memdump/memreport.py
@@ -4,10 +4,22 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import collections
+import json
+import optparse
+import os
 import re
+import threading
+import time
 import sys
 
 from sets import Set
+from string import Template
+
+sys.path.append(os.path.join(sys.path[0], os.pardir, os.pardir, os.pardir,
+                             'build','android'))
+from pylib import android_commands
+from pylib import constants
 
 
 _ENTRIES = [
@@ -114,7 +126,145 @@
   print ''
 
 
+def _RunManualGraph(package_name, interval):
+  _AREA_TYPES = ('private', 'private_unevictable',
+                 'shared_app', 'shared_other', 'shared_other_unevictable')
+  all_pids = {}
+  legends = ['Seconds'] + [entry + '_' + area
+                           for entry, _ in _ENTRIES
+                           for area in _AREA_TYPES]
+  should_quit = threading.Event()
+
+  def _GenerateGraph():
+    _HTML_TEMPLATE = """
+<html>
+  <head>
+    <script type='text/javascript' src='https://www.google.com/jsapi'></script>
+    <script type='text/javascript'>
+      google.load('visualization', '1', {packages:['corechart', 'table']});
+      google.setOnLoadCallback(createPidSelector);
+      var pids = $JSON_PIDS;
+      var pids_info = $JSON_PIDS_INFO;
+      function drawVisualization(pid) {
+        var data = google.visualization.arrayToDataTable(
+          pids_info[pid]
+        );
+
+        var charOptions = {
+          title: 'Memory Report (KB) for ' + pid,
+          vAxis: {title: 'Time',  titleTextStyle: {color: 'red'}},
+          isStacked : true
+        };
+
+        var chart = new google.visualization.BarChart(
+            document.getElementById('chart_div'));
+        chart.draw(data, charOptions);
+
+        var table = new google.visualization.Table(
+            document.getElementById('table_div'));
+        table.draw(data);
+      }
+
+      function createPidSelector() {
+        var pid_selector = document.getElementById('pid_selector');
+        for (pid in pids) {
+          var option = document.createElement('option');
+          option.text = option.value = pids[pid];
+          pid_selector.appendChild(option);
+        }
+        pid_selector.addEventListener('change',
+          function() {
+            drawVisualization(this.selectedOptions[0].value);
+          }
+        );
+        drawVisualization(pids[0]);
+      }
+    </script>
+  </head>
+  <body>
+    PIDS: <select id='pid_selector'></select>
+    <div id='chart_div' style="width: 1024px; height: 800px;"></div>
+    <div id='table_div' style="width: 1024px; height: 640px;"></div>
+  </body>
+</html>
+"""
+    pids = sorted(all_pids.keys())
+    pids_info = dict(zip(pids,
+                         [ [legends] +
+                           all_pids[p] for p in pids
+                         ]))
+    print Template(_HTML_TEMPLATE).safe_substitute({
+        'JSON_PIDS': json.dumps(pids),
+        'JSON_PIDS_INFO': json.dumps(pids_info)
+    })
+
+
+
+  def _CollectStats(count):
+    adb = android_commands.AndroidCommands()
+    pid_list = adb.ExtractPid('com.google.android.apps.chrome')
+    memdump = adb.RunShellCommand('/data/local/tmp/memdump ' +
+                                  ' '.join(pid_list))
+    process_stats = _CollectMemoryStats(memdump,
+                                        [value for (key, value) in _ENTRIES])
+    for (pid, process) in zip(pid_list, process_stats):
+      first_pid_entry = True
+      for (k, v) in _ENTRIES:
+        if v not in process:
+          continue
+        for area_type in _AREA_TYPES:
+          legend = k + '_' + area_type
+          if pid not in all_pids:
+            all_pids[pid] = []
+          if first_pid_entry:
+            all_pids[pid].append(['%ds' % (count * interval)] +
+                                 [0] * (len(legends) - 1))
+            first_pid_entry = False
+          mem_kb = process[v][area_type] / 1024
+          all_pids[pid][-1][legends.index(legend)] = mem_kb
+
+  def _Loop():
+    count = 0
+    while not should_quit.is_set():
+      print >>sys.stderr, 'Collecting ', count
+      _CollectStats(count)
+      count += 1
+      should_quit.wait(interval)
+
+  t = threading.Thread(target=_Loop)
+
+
+  print >>sys.stderr, 'Press enter to stop'
+  t.start()
+  try:
+    _ = raw_input()
+  finally:
+    should_quit.set()
+
+  t.join()
+
+  _GenerateGraph()
+
+
 def main(argv):
+  parser = optparse.OptionParser(usage='Usage: %prog [options]',
+                                 description=__doc__)
+  parser.add_option('-m',
+                    '--manual-graph',
+                    action='store_true',
+                    help='Manually collect data and generate a graph.')
+  parser.add_option('-p',
+                    '--package',
+                    default=constants.CHROME_PACKAGE,
+                    help='Package name to collect.')
+  parser.add_option('-i',
+                    '--interval',
+                    default=5,
+                    type='int',
+                    help='Interval in seconds for manual collections.')
+  options, args = parser.parse_args(argv)
+  if options.manual_graph:
+    return _RunManualGraph(options.package, options.interval)
   _DumpCSV(_CollectMemoryStats(sys.stdin, [value for (key, value) in _ENTRIES]))
 
 
diff --git a/tools/bisect-builds.py b/tools/bisect-builds.py
index d9f3947..3e8254b 100755
--- a/tools/bisect-builds.py
+++ b/tools/bisect-builds.py
@@ -346,9 +346,10 @@
   """Ask the user whether build |rev| is good or bad."""
   # Loop until we get a response that we can parse.
   while True:
-    response = raw_input('Revision %s is [(g)ood/(b)ad/(u)nknown/(q)uit]: ' %
+    response = raw_input('Revision %s is ' \
+                         '[(g)ood/(b)ad/(r)etry/(u)nknown/(q)uit]: ' %
                          str(rev))
-    if response and response in ('g', 'b', 'u'):
+    if response and response in ('g', 'b', 'r', 'u'):
       return response
     if response and response == 'q':
       raise SystemExit()
@@ -504,8 +505,6 @@
                                              try_args)
     except Exception, e:
       print >>sys.stderr, e
-    fetch.Stop()
-    fetch = None
 
     # Call the evaluate function to see if the current revision is good or bad.
     # On that basis, kill one of the background downloads and complete the
@@ -514,24 +513,31 @@
       answer = evaluate(rev, official_builds, status, stdout, stderr)
       if answer == 'g' and good_rev < bad_rev or \
           answer == 'b' and bad_rev < good_rev:
+        fetch.Stop()
         minrev = pivot
         if down_fetch:
           down_fetch.Stop()  # Kill the download of the older revision.
+          fetch = None
         if up_fetch:
           up_fetch.WaitFor()
           pivot = up_pivot
           fetch = up_fetch
       elif answer == 'b' and good_rev < bad_rev or \
           answer == 'g' and bad_rev < good_rev:
+        fetch.Stop()
         maxrev = pivot
         if up_fetch:
           up_fetch.Stop()  # Kill the download of the newer revision.
+          fetch = None
         if down_fetch:
           down_fetch.WaitFor()
           pivot = down_pivot
           fetch = down_fetch
+      elif answer == 'r':
+        pass  # Retry requires no changes.
       elif answer == 'u':
         # Nuke the revision from the revlist and choose a new pivot.
+        fetch.Stop()
         revlist.pop(pivot)
         maxrev -= 1  # Assumes maxrev >= pivot.
 
diff --git a/tools/bisect-manual-test.py b/tools/bisect-manual-test.py
index 62aa072..d01adc9 100755
--- a/tools/bisect-manual-test.py
+++ b/tools/bisect-manual-test.py
@@ -21,6 +21,7 @@
   browser_to_create = browser_finder.FindBrowser(options)
   print 'Starting browser: %s.' % options.browser_type
   with browser_to_create.Create() as browser:
+    browser.Start();
 
     # Loop until we get a response that we can parse.
     while True:
diff --git a/tools/bisect-perf-regression.py b/tools/bisect-perf-regression.py
index 4947ece..9eaf50b 100755
--- a/tools/bisect-perf-regression.py
+++ b/tools/bisect-perf-regression.py
@@ -79,7 +79,9 @@
     "src" : "src/v8",
     "recurse" : True,
     "depends" : None,
-    "build_with": 'v8_bleeding_edge',
+    # Bisecting into v8 is broken at the moment.
+    # crbug.com/274818
+    #"build_with": 'v8_bleeding_edge',
     "from" : 'chromium',
     "custom_deps": bisect_utils.GCLIENT_CUSTOM_DEPS_V8
   },
@@ -178,6 +180,15 @@
   return std_dev
 
 
+def CalculateStandardError(v):
+  if len(v) <= 1:
+    return 0.0
+
+  std_dev = CalculateStandardDeviation(v)
+
+  return std_dev / math.sqrt(len(v))
+
+
 def IsStringFloat(string_to_check):
   """Checks whether or not the given string can be converted to a floating
   point number.
@@ -1017,8 +1028,10 @@
 
     # If the metric is times/t, we need to sum the timings in order to get
     # similar regression results as the try-bots.
+    metrics_to_sum = [['times', 't'], ['times', 'page_load_time'],
+        ['cold_times', 'page_load_time'], ['warm_times', 'page_load_time']]
 
-    if metric == ['times', 't']:
+    if metric in metrics_to_sum:
       if values_list:
         values_list = [reduce(lambda x, y: float(x) + float(y), values_list)]
 
@@ -1056,7 +1069,7 @@
     """
 
     if self.opts.debug_ignore_perf_test:
-      return ({'mean': 0.0, 'std_dev': 0.0}, 0)
+      return ({'mean': 0.0, 'std_err': 0.0, 'std_dev': 0.0, 'values': [0.0]}, 0)
 
     if IsWindows():
       command_to_run = command_to_run.replace('/', r'\\')
@@ -1109,15 +1122,18 @@
     if metric_values:
       truncated_mean = CalculateTruncatedMean(metric_values,
           self.opts.truncate_percent)
+      standard_err = CalculateStandardError(metric_values)
       standard_dev = CalculateStandardDeviation(metric_values)
 
       values = {
         'mean': truncated_mean,
+        'std_err': standard_err,
         'std_dev': standard_dev,
+        'values': metric_values,
       }
 
       print 'Results of performance test: %12f %12f' % (
-          truncated_mean, standard_dev)
+          truncated_mean, standard_err)
       print
       return (values, 0)
     else:
@@ -1245,6 +1261,8 @@
       True if successful.
     """
     if depot == 'chromium':
+      if not bisect_utils.RemoveThirdPartyLibjingleDirectory():
+        return False
       return self.PerformWebkitDirectoryCleanup(revision)
     elif depot == 'cros':
       return self.PerformCrosChrootCleanup()
@@ -1464,6 +1482,11 @@
 
       os.chdir(self.depot_cwd[current_depot])
 
+    if current_depot == 'v8':
+      self.warnings.append('Unfortunately, V8 bisection is broken at '
+          'the moment. The script won\'t be able to narrow down the range '
+          'past major releases of V8.')
+
     depot_revision_list = self.GetRevisionList(current_depot,
                                                end_revision,
                                                start_revision)
@@ -1752,11 +1775,17 @@
         bisect_utils.OutputAnnotationStepClosed()
 
       if bad_results[1]:
-        results['error'] = bad_results[0]
+        results['error'] = ('An error occurred while building and running '
+            'the \'bad\' reference value. The bisect cannot continue without '
+            'a working \'bad\' revision to start from.\n\nError: %s' %
+                bad_results[0])
         return results
 
       if good_results[1]:
-        results['error'] = good_results[0]
+        results['error'] = ('An error occurred while building and running '
+            'the \'good\' reference value. The bisect cannot continue without '
+            'a working \'good\' revision to start from.\n\nError: %s' %
+                good_results[0])
         return results
 
 
@@ -1769,12 +1798,12 @@
       # already know the results.
       bad_revision_data = revision_data[revision_list[0]]
       bad_revision_data['external'] = bad_results[2]
-      bad_revision_data['passed'] = 0
+      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['passed'] = 1
+      good_revision_data['passed'] = True
       good_revision_data['value'] = known_good_value
 
       next_revision_depot = target_depot
@@ -1890,7 +1919,7 @@
           if run_results[1] == BUILD_RESULT_SKIPPED:
             next_revision_data['passed'] = 'Skipped'
           elif run_results[1] == BUILD_RESULT_FAIL:
-            next_revision_data['passed'] = 'Failed'
+            next_revision_data['passed'] = 'Build Failed'
 
           print run_results[0]
 
@@ -1914,6 +1943,18 @@
     Args
       bisect_results: The results from a bisection test run.
     """
+    if bisect_results['error']:
+      if self.opts.output_buildbot_annotations:
+        bisect_utils.OutputAnnotationStepStart('Results - Bisect Failed')
+
+      print
+      print bisect_results['error']
+      print
+
+      if self.opts.output_buildbot_annotations:
+        bisect_utils.OutputAnnotationStepClosed()
+      return
+
     revision_data = bisect_results['revision_data']
     revision_data_sorted = sorted(revision_data.iteritems(),
                                   key = lambda x: x[1]['sort'])
@@ -1927,23 +1968,18 @@
       build_status = current_data['passed']
 
       if type(build_status) is bool:
-        build_status = int(build_status)
+        if build_status:
+          build_status = 'Passed'
+        else:
+          build_status = 'Failed'
 
       print '  %8s  %40s  %s' % (current_data['depot'],
                                  current_id, build_status)
     print
 
-    print
-    print 'Tested commits:'
-    for current_id, current_data in revision_data_sorted:
-      if current_data['value']:
-        print '  %8s  %40s  %12f %12f' % (
-            current_data['depot'], current_id,
-            current_data['value']['mean'], current_data['value']['std_dev'])
-    print
-
     # Find range where it possibly broke.
     first_working_revision = None
+    first_working_revision_index = -1
     last_broken_revision = None
     last_broken_revision_index = -1
 
@@ -1952,12 +1988,78 @@
       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
 
+    print
+    print 'Tested commits:'
+    print '  %8s  %40s  %12s %14s %13s' % ('Depot'.center(8, ' '),
+        'Commit SHA'.center(40, ' '), 'Mean'.center(12, ' '),
+        'Std. Error'.center(14, ' '), 'State'.center(13, ' '))
+    state = 0
+    for current_id, current_data in revision_data_sorted:
+      if current_data['value']:
+        if (current_id == last_broken_revision or
+            current_id == first_working_revision):
+          print
+          state += 1
+
+        state_str = 'Bad'
+        if state == 1:
+          state_str = 'Suspected CL'
+        elif state == 2:
+          state_str = 'Good'
+        state_str = state_str.center(13, ' ')
+
+        std_error = ('+-%.02f' %
+            current_data['value']['std_err']).center(14, ' ')
+        mean = ('+-%.02f' %
+            current_data['value']['mean']).center(12, ' ')
+        print '  %8s  %40s  %12s %14s %13s' % (
+            current_data['depot'], current_id, mean, std_error, state_str)
+
     if last_broken_revision != None and first_working_revision != None:
+      # 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
+      # overall graph is.
+      bounds_broken = [revision_data[last_broken_revision]['value']['mean'],
+          revision_data[last_broken_revision]['value']['mean']]
+      broken_mean = []
+      for i in xrange(0, last_broken_revision_index + 1):
+        if revision_data_sorted[i][1]['value']:
+          bounds_broken[0] = min(bounds_broken[0],
+              revision_data_sorted[i][1]['value']['mean'])
+          bounds_broken[1] = max(bounds_broken[1],
+              revision_data_sorted[i][1]['value']['mean'])
+          broken_mean.extend(revision_data_sorted[i][1]['value']['values'])
+
+      bounds_working = [revision_data[first_working_revision]['value']['mean'],
+          revision_data[first_working_revision]['value']['mean']]
+      working_mean = []
+      for i in xrange(first_working_revision_index, len(revision_data_sorted)):
+        if revision_data_sorted[i][1]['value']:
+          bounds_working[0] = min(bounds_working[0],
+              revision_data_sorted[i][1]['value']['mean'])
+          bounds_working[1] = max(bounds_working[1],
+              revision_data_sorted[i][1]['value']['mean'])
+          working_mean.extend(revision_data_sorted[i][1]['value']['values'])
+
+      dist_between_groups = min(math.fabs(bounds_broken[1] - bounds_working[0]),
+          math.fabs(bounds_broken[0] - bounds_working[1]))
+      len_working_group = CalculateStandardError(working_mean)
+      len_broken_group = CalculateStandardError(broken_mean)
+
+      confidence = (dist_between_groups / (
+          max(0.0001, (len_broken_group + len_working_group ))))
+      confidence = min(1.0, max(confidence, 0.0)) * 100.0
+
+      print
+      print 'Confidence in Bisection Results: %d%%' % int(confidence)
+      print
+
       print 'Results: Regression may have occurred in range:'
       print '  -> First Bad Revision: [%40s] [%s]' %\
             (last_broken_revision,
@@ -2039,19 +2141,13 @@
       os.chdir(cwd)
 
       # Give a warning if the values were very close together
-      good_std_dev = revision_data[first_working_revision]['value']['std_dev']
+      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 good_std_dev > 0:
-        deviations = math.fabs(bad_mean - good_mean) / good_std_dev
-
-        if deviations < 1.5:
-          self.warnings.append('Regression was less than 1.5 standard '
-            'deviations from "good" value. Results may not be accurate.')
-      elif self.opts.repeat_test_count == 1:
+      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.')
 
@@ -2318,6 +2414,11 @@
                     'platform), "cros", or "android". If you specify something '
                     'other than "chromium", you must be properly set up to '
                     'build that platform.')
+  parser.add_option('--no_custom_deps',
+                    dest='no_custom_deps',
+                    action="store_true",
+                    default=False,
+                    help='Run the script with custom_deps or not.')
   parser.add_option('--cros_board',
                     type='str',
                     help='The cros board type to build.')
@@ -2401,9 +2502,14 @@
     return 1
 
   if opts.working_directory:
-    if bisect_utils.CreateBisectDirectoryAndSetupDepot(opts):
+    custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS
+    if opts.no_custom_deps:
+      custom_deps = None
+    if bisect_utils.CreateBisectDirectoryAndSetupDepot(opts,
+                                                       custom_deps):
       return 1
 
+
     if not bisect_utils.SetupPlatformBuildEnvironment(opts):
       print 'Error: Failed to set platform environment.'
       print
@@ -2440,16 +2546,13 @@
                                      opts.bad_revision,
                                      opts.good_revision,
                                      metric_values)
-    if not(bisect_results['error']):
-      bisect_test.FormatAndPrintResults(bisect_results)
+    bisect_test.FormatAndPrintResults(bisect_results)
   finally:
     bisect_test.PerformCleanup()
 
-  if not(bisect_results['error']):
+  if not bisect_results['error']:
     return 0
   else:
-    print 'Error: ' + bisect_results['error']
-    print
     return 1
 
 if __name__ == '__main__':
diff --git a/tools/bisect_utils.py b/tools/bisect_utils.py
index 37869df..bdb1675 100644
--- a/tools/bisect_utils.py
+++ b/tools/bisect_utils.py
@@ -9,42 +9,44 @@
 import errno
 import os
 import shutil
+import stat
 import subprocess
 import sys
 
+DEFAULT_GCLIENT_CUSTOM_DEPS = {
+    "src/data/page_cycler": "https://chrome-internal.googlesource.com/"
+                            "chrome/data/page_cycler/.git",
+    "src/data/dom_perf": "https://chrome-internal.googlesource.com/"
+                         "chrome/data/dom_perf/.git",
+    "src/data/mach_ports": "https://chrome-internal.googlesource.com/"
+                           "chrome/data/mach_ports/.git",
+    "src/tools/perf/data": "https://chrome-internal.googlesource.com/"
+                           "chrome/tools/perf/data/.git",
+    "src/third_party/adobe/flash/binaries/ppapi/linux":
+        "https://chrome-internal.googlesource.com/"
+        "chrome/deps/adobe/flash/binaries/ppapi/linux/.git",
+    "src/third_party/adobe/flash/binaries/ppapi/linux_x64":
+        "https://chrome-internal.googlesource.com/"
+        "chrome/deps/adobe/flash/binaries/ppapi/linux_x64/.git",
+    "src/third_party/adobe/flash/binaries/ppapi/mac":
+        "https://chrome-internal.googlesource.com/"
+        "chrome/deps/adobe/flash/binaries/ppapi/mac/.git",
+    "src/third_party/adobe/flash/binaries/ppapi/mac_64":
+        "https://chrome-internal.googlesource.com/"
+        "chrome/deps/adobe/flash/binaries/ppapi/mac_64/.git",
+    "src/third_party/adobe/flash/binaries/ppapi/win":
+        "https://chrome-internal.googlesource.com/"
+        "chrome/deps/adobe/flash/binaries/ppapi/win/.git",
+    "src/third_party/adobe/flash/binaries/ppapi/win_x64":
+        "https://chrome-internal.googlesource.com/"
+        "chrome/deps/adobe/flash/binaries/ppapi/win_x64/.git",}
+
 GCLIENT_SPEC_DATA = [
   { "name"        : "src",
     "url"         : "https://chromium.googlesource.com/chromium/src.git",
     "deps_file"   : ".DEPS.git",
     "managed"     : True,
-    "custom_deps" : {
-      "src/data/page_cycler": "https://chrome-internal.googlesource.com/"
-                              "chrome/data/page_cycler/.git",
-      "src/data/dom_perf": "https://chrome-internal.googlesource.com/"
-                           "chrome/data/dom_perf/.git",
-      "src/data/mach_ports": "https://chrome-internal.googlesource.com/"
-                           "chrome/data/mach_ports/.git",
-      "src/tools/perf/data": "https://chrome-internal.googlesource.com/"
-                             "chrome/tools/perf/data/.git",
-      "src/third_party/adobe/flash/binaries/ppapi/linux":
-          "https://chrome-internal.googlesource.com/"
-          "chrome/deps/adobe/flash/binaries/ppapi/linux/.git",
-      "src/third_party/adobe/flash/binaries/ppapi/linux_x64":
-          "https://chrome-internal.googlesource.com/"
-          "chrome/deps/adobe/flash/binaries/ppapi/linux_x64/.git",
-      "src/third_party/adobe/flash/binaries/ppapi/mac":
-          "https://chrome-internal.googlesource.com/"
-          "chrome/deps/adobe/flash/binaries/ppapi/mac/.git",
-      "src/third_party/adobe/flash/binaries/ppapi/mac_64":
-          "https://chrome-internal.googlesource.com/"
-          "chrome/deps/adobe/flash/binaries/ppapi/mac_64/.git",
-      "src/third_party/adobe/flash/binaries/ppapi/win":
-          "https://chrome-internal.googlesource.com/"
-          "chrome/deps/adobe/flash/binaries/ppapi/win/.git",
-      "src/third_party/adobe/flash/binaries/ppapi/win_x64":
-          "https://chrome-internal.googlesource.com/"
-          "chrome/deps/adobe/flash/binaries/ppapi/win_x64/.git",
-    },
+    "custom_deps" : {},
     "safesync_url": "",
   },
 ]
@@ -225,6 +227,49 @@
   return True
 
 
+def OnAccessError(func, path, exc_info):
+  """
+  Source: http://stackoverflow.com/questions/2656322/python-shutil-rmtree-fails-on-windows-with-access-is-denied
+
+  Error handler for ``shutil.rmtree``.
+
+  If the error is due to an access error (read only file)
+  it attempts to add write permission and then retries.
+
+  If the error is for another reason it re-raises the error.
+
+  Args:
+    func: The function that raised the error.
+    path: The path name passed to func.
+    exc_info: Exception information returned by sys.exc_info().
+  """
+  if not os.access(path, os.W_OK):
+    # Is the error an access error ?
+    os.chmod(path, stat.S_IWUSR)
+    func(path)
+  else:
+    raise
+
+
+def RemoveThirdPartyLibjingleDirectory():
+  """Removes third_party/libjingle. At some point, libjingle was causing issues
+  syncing when using the git workflow (crbug.com/266324).
+
+  Returns:
+    True on success.
+  """
+  path_to_dir = os.path.join(os.getcwd(), 'third_party', 'libjingle')
+  try:
+    if os.path.exists(path_to_dir):
+      shutil.rmtree(path_to_dir, onerror=OnAccessError)
+  except OSError, e:
+    print 'Error #%d while running shutil.rmtree(%s): %s' % (
+        e.errno, path_to_dir, str(e))
+    if e.errno != errno.ENOENT:
+      return False
+  return True
+
+
 def RunGClientAndSync(cwd=None):
   """Runs gclient and does a normal sync.
 
@@ -238,12 +283,13 @@
   return RunGClient(params, cwd=cwd)
 
 
-def SetupGitDepot(opts):
+def SetupGitDepot(opts, custom_deps):
   """Sets up the depot for the bisection. The depot will be located in a
   subdirectory called 'bisect'.
 
   Args:
     opts: The options parsed from the command line through parse_args().
+    custom_deps: A dictionary of additional dependencies to add to .gclient.
 
   Returns:
     True if gclient successfully created the config file and did a sync, False
@@ -256,7 +302,7 @@
 
   passed = False
 
-  if not RunGClientAndCreateConfig(opts):
+  if not RunGClientAndCreateConfig(opts, custom_deps):
     passed_deps_check = True
     if os.path.isfile(os.path.join('src', FILE_DEPS_GIT)):
       cwd = os.getcwd()
@@ -265,6 +311,8 @@
         passed_deps_check = RemoveThirdPartyWebkitDirectory()
       else:
         passed_deps_check = True
+      if passed_deps_check:
+        passed_deps_check = RemoveThirdPartyLibjingleDirectory()
       os.chdir(cwd)
 
     if passed_deps_check:
@@ -378,13 +426,13 @@
   return True
 
 
-def CreateBisectDirectoryAndSetupDepot(opts):
+def CreateBisectDirectoryAndSetupDepot(opts, custom_deps):
   """Sets up a subdirectory 'bisect' and then retrieves a copy of the depot
   there using gclient.
 
   Args:
     opts: The options parsed from the command line through parse_args().
-    reset: Whether to reset any changes to the depot.
+    custom_deps: A dictionary of additional dependencies to add to .gclient.
 
   Returns:
     Returns 0 on success, otherwise 1.
@@ -394,7 +442,7 @@
     print
     return 1
 
-  if not SetupGitDepot(opts):
+  if not SetupGitDepot(opts, custom_deps):
     print 'Error: Failed to grab source.'
     print
     return 1
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py
index 25dedc2..847347c 100755
--- a/tools/checklicenses/checklicenses.py
+++ b/tools/checklicenses/checklicenses.py
@@ -244,9 +244,6 @@
     'third_party/lcov/contrib/galaxy/genflat.pl': [
         'GPL (v2 or later)',
     ],
-    'third_party/lcov-1.9/contrib/galaxy/genflat.pl': [
-        'GPL (v2 or later)',
-    ],
     'third_party/libevent': [  # http://crbug.com/98309
         'UNKNOWN',
     ],
diff --git a/tools/deep_memory_profiler/accumulate.py b/tools/deep_memory_profiler/accumulate.py
new file mode 100755
index 0000000..6998dc0
--- /dev/null
+++ b/tools/deep_memory_profiler/accumulate.py
@@ -0,0 +1,259 @@
+#!/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 script to accumulate values from the 'dmprof cat' command into CSV or else.
+#
+# Usage:
+#   ./accumulate.py -f <format> -t <template-name> < input.json > output
+#
+# <format> is one of "csv", "json", and "tree". If "csv" or "json" is given,
+# accumulate.py dumps a similar file to "dmprof csv|json". If "tree" is given,
+# accumulate.py dumps a human-readable breakdown tree.
+#
+# <template-name> is a label in templates.json.
+
+import datetime
+import json
+import logging
+import optparse
+import sys
+
+from lib.ordered_dict import OrderedDict
+
+
+LOGGER = logging.getLogger('dmprof-accumulate')
+
+
+def visit_in_template(template, snapshot, depth):
+  """Visits all categories via a given template.
+
+  This function is not used. It's a sample function to traverse a template.
+  """
+  world = template[0]
+  breakdown = template[1]
+  rules = template[2]
+
+  for rule, _ in snapshot[world]['breakdown'][breakdown].iteritems():
+    print ('  ' * depth) + rule
+    if rule in rules:
+      visit_in_template(rules[rule], snapshot, depth + 1)
+
+
+def accumulate(template, snapshot, units_dict, target_units):
+  """Accumulates units in a JSON |snapshot| with applying a given |template|.
+
+  Args:
+      template: A template tree included in a dmprof cat JSON file.
+      snapshot: A snapshot in a dmprof cat JSON file.
+      units_dict: A dict of units in worlds.
+      target_units: A list of unit ids which are a target of this accumulation.
+  """
+  world = template[0]
+  breakdown = template[1]
+  rules = template[2]
+
+  remainder_units = target_units.copy()
+  category_tree = OrderedDict()
+  total = 0
+
+  for rule, match in snapshot[world]['breakdown'][breakdown].iteritems():
+    if 'hidden' in match and match['hidden']:
+      continue
+    matched_units = set(match['units']).intersection(target_units)
+    subtotal = 0
+    for unit_id in matched_units:
+      subtotal += units_dict[world][unit_id]
+    total += subtotal
+    remainder_units = remainder_units.difference(matched_units)
+    if rule not in rules:
+      # A category matched with |rule| is a leaf of the breakdown tree.
+      # It is NOT broken down more.
+      category_tree[rule] = subtotal
+      continue
+
+    # A category matched with |rule| is broken down more.
+    subtemplate = rules[rule]
+    subworld = subtemplate[0]
+    subbreakdown = subtemplate[1]
+
+    if subworld == world:
+      # Break down in the same world: consider units.
+      category_tree[rule], accounted_total, subremainder_units = accumulate(
+          subtemplate, snapshot, units_dict, matched_units)
+      subremainder_total = 0
+      if subremainder_units:
+        for unit_id in subremainder_units:
+          subremainder_total += units_dict[world][unit_id]
+        category_tree[rule][None] = subremainder_total
+      if subtotal != accounted_total + subremainder_total:
+        print >> sys.stderr, (
+            'WARNING: Sum of %s:%s is different from %s by %d bytes.' % (
+                subworld, subbreakdown, rule,
+                subtotal - (accounted_total + subremainder_total)))
+    else:
+      # Break down in a different world: consider only the total size.
+      category_tree[rule], accounted_total, _ = accumulate(
+          subtemplate, snapshot, units_dict, set(units_dict[subworld].keys()))
+      if subtotal >= accounted_total:
+        category_tree[rule][None] = subtotal - accounted_total
+      else:
+        print >> sys.stderr, (
+            'WARNING: Sum of %s:%s is larger than %s by %d bytes.' % (
+                subworld, subbreakdown, rule, accounted_total - subtotal))
+        print >> sys.stderr, (
+            'WARNING:   Assuming remainder of %s is 0.' % rule)
+        category_tree[rule][None] = 0
+
+  return category_tree, total, remainder_units
+
+
+def flatten(category_tree, header=''):
+  """Flattens a category tree into a flat list."""
+  result = []
+  for rule, sub in category_tree.iteritems():
+    if not rule:
+      rule = 'remaining'
+    if header:
+      flattened_rule = header + '>' + rule
+    else:
+      flattened_rule = rule
+    if isinstance(sub, dict) or isinstance(sub, OrderedDict):
+      result.extend(flatten(sub, flattened_rule))
+    else:
+      result.append((flattened_rule, sub))
+  return result
+
+
+def print_category_tree(category_tree, output, depth=0):
+  """Prints a category tree in a human-readable format."""
+  for label in category_tree:
+    print >> output, ('  ' * depth),
+    if (isinstance(category_tree[label], dict) or
+        isinstance(category_tree[label], OrderedDict)):
+      print >> output, '%s:' % label
+      print_category_tree(category_tree[label], output, depth + 1)
+    else:
+      print >> output, '%s: %d' % (label, category_tree[label])
+
+
+def flatten_all_category_trees(category_trees):
+  flattened_labels = set()
+  flattened_table = []
+  for category_tree in category_trees:
+    flattened = OrderedDict()
+    for label, subtotal in flatten(category_tree):
+      flattened_labels.add(label)
+      flattened[label] = subtotal
+    flattened_table.append(flattened)
+  return flattened_labels, flattened_table
+
+
+def output_csv(output, category_trees, data, first_time):
+  flattened_labels, flattened_table = flatten_all_category_trees(category_trees)
+
+  sorted_flattened_labels = sorted(flattened_labels)
+  print >> output, ','.join(['second'] + sorted_flattened_labels)
+  for index, row in enumerate(flattened_table):
+    values = [str(data['snapshots'][index]['time'] - first_time)]
+    for label in sorted_flattened_labels:
+      if label in row:
+        values.append(str(row[label] / 1024.0 / 1024.0))
+      else:
+        values.append('0')
+    print >> output, ','.join(values)
+
+
+def output_json(output, category_trees, data, first_time, template_label):
+  flattened_labels, flattened_table = flatten_all_category_trees(category_trees)
+
+  json_snapshots = []
+  for index, row in enumerate(flattened_table):
+    row_with_meta = row.copy()
+    row_with_meta['second'] = data['snapshots'][index]['time'] - first_time
+    row_with_meta['dump_time'] = datetime.datetime.fromtimestamp(
+        data['snapshots'][index]['time']).strftime('%Y-%m-%d %H:%M:%S')
+    json_snapshots.append(row_with_meta)
+  json_root = {
+      'version': 'JSON_DEEP_2',
+      'policies': {
+          template_label: {
+              'legends': sorted(flattened_labels),
+              'snapshots': json_snapshots
+              }
+          }
+      }
+  json.dump(json_root, output, indent=2, sort_keys=True)
+
+
+def output_tree(output, category_trees):
+  for index, category_tree in enumerate(category_trees):
+    print >> output, '< Snapshot #%d >' % index
+    print_category_tree(category_tree, output, 1)
+    print >> output, ''
+
+
+def do_main(cat_input, output, template_label, output_format):
+  """Does the main work: accumulate for every snapshot and print a result."""
+  if output_format not in ['csv', 'json', 'tree']:
+    raise NotImplementedError('The output format \"%s\" is not implemented.' %
+                              output_format)
+
+  data = json.loads(cat_input.read(), object_pairs_hook=OrderedDict)
+
+  templates = data['templates']
+  if not template_label:
+    template_label = data['default_template']
+  if template_label not in templates:
+    LOGGER.error('A template \'%s\' is not found.' % template_label)
+    return
+  template = templates[template_label]
+
+  category_trees = []
+  first_time = None
+
+  for snapshot in data['snapshots']:
+    if not first_time:
+      first_time = snapshot['time']
+
+    units = {}
+    for world_name in snapshot['worlds']:
+      world_units = {}
+      for unit_id, sizes in snapshot['worlds'][world_name]['units'].iteritems():
+        world_units[int(unit_id)] = sizes[0]
+      units[world_name] = world_units
+
+    category_tree, _, _ = accumulate(
+        template, snapshot['worlds'], units, set(units[template[0]].keys()))
+    category_trees.append(category_tree)
+
+  if output_format == 'csv':
+    output_csv(output, category_trees, data, first_time)
+  elif output_format == 'json':
+    output_json(output, category_trees, data, first_time, template_label)
+  elif output_format == 'tree':
+    output_tree(output, category_trees)
+
+
+def main():
+  LOGGER.setLevel(logging.DEBUG)
+  handler = logging.StreamHandler()
+  handler.setLevel(logging.INFO)
+  formatter = logging.Formatter('%(message)s')
+  handler.setFormatter(formatter)
+  LOGGER.addHandler(handler)
+
+  parser = optparse.OptionParser()
+  parser.add_option('-t', '--template', dest='template',
+                    metavar='TEMPLATE',
+                    help='Apply TEMPLATE to list up.')
+  parser.add_option('-f', '--format', dest='format', default='csv',
+                    help='Specify the output format: csv, json or tree.')
+
+  options, _ = parser.parse_args(sys.argv)
+  do_main(sys.stdin, sys.stdout, options.template, options.format)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/deep_memory_profiler/lib/sorter.py b/tools/deep_memory_profiler/lib/sorter.py
index 64e0851..bd56292 100644
--- a/tools/deep_memory_profiler/lib/sorter.py
+++ b/tools/deep_memory_profiler/lib/sorter.py
@@ -8,6 +8,8 @@
 import os
 import re
 
+from lib.ordered_dict import OrderedDict
+
 
 LOGGER = logging.getLogger('dmprof')
 
@@ -193,7 +195,7 @@
 
   def __repr__(self):
     result = cStringIO.StringIO()
-    result.write('{"%s"=>' % self._name)
+    result.write('%s: ' % self._name)
     attributes = []
     attributes.append('mmap: %s' % self._mmap)
     if self._backtrace_function:
@@ -206,7 +208,7 @@
     if self._mapped_permission:
       attributes.append('mapped_permission: "%s"' %
                         self._mapped_permission.pattern)
-    result.write('%s}' % ', '.join(attributes))
+    result.write('{ %s }' % ', '.join(attributes))
     return result.getvalue()
 
   def match(self, unit):
@@ -287,13 +289,14 @@
 
   def __repr__(self):
     result = cStringIO.StringIO()
-    result.write('{"%s"=>' % self._name)
+    result.write('%s: ' % self._name)
     attributes = []
     if self._backtrace_function:
-      attributes.append('backtrace_function: "%s"' % self._backtrace_function)
+      attributes.append('backtrace_function: "%s"' %
+                        self._backtrace_function.pattern)
     if self._typeinfo:
-      attributes.append('typeinfo: "%s"' % self._typeinfo)
-    result.write('%s}' % ', '.join(attributes))
+      attributes.append('typeinfo: "%s"' % self._typeinfo.pattern)
+    result.write('{ %s }' % ', '.join(attributes))
     return result.getvalue()
 
   def match(self, unit):
@@ -312,17 +315,6 @@
             (not self._typeinfo or self._typeinfo.match(typeinfo)))
 
 
-class NoBucketMallocRule(MallocRule):
-  """Represents a Rule that small ignorable units match with."""
-  def __init__(self):
-    super(NoBucketMallocRule, self).__init__({'name': 'tc-no-bucket'})
-    self._no_bucket = True
-
-  @property
-  def no_bucket(self):
-    return self._no_bucket
-
-
 class AbstractSorter(object):
   """An abstract class for classifying Units with a set of Rules."""
   def __init__(self, dct):
@@ -344,17 +336,19 @@
 
   def __repr__(self):
     result = cStringIO.StringIO()
-    result.write('world=%s' % self._world)
-    result.write('order=%s' % self._order)
-    result.write('rules:')
+    print >> result, '%s' % self._name
+    print >> result, 'world=%s' % self._world
+    print >> result, 'name=%s' % self._name
+    print >> result, 'order=%s' % self._order
+    print >> result, 'rules:'
     for rule in self._rules:
-      result.write('  %s' % rule)
+      print >> result, '  %s' % rule
     return result.getvalue()
 
   @staticmethod
   def load(filename):
     with open(filename) as sorter_f:
-      sorter_dict = json.load(sorter_f)
+      sorter_dict = json.load(sorter_f, object_pairs_hook=OrderedDict)
     if sorter_dict['world'] == 'vm':
       return VMSorter(sorter_dict)
     elif sorter_dict['world'] == 'malloc':
@@ -375,6 +369,10 @@
   def root(self):
     return self._root
 
+  def iter_rule(self):
+    for rule in self._rules:
+      yield rule
+
   def find(self, unit):
     raise NotImplementedError()
 
@@ -396,7 +394,7 @@
     for rule in self._rules:
       if rule.match(unit):
         return rule
-    assert False
+    return None
 
 
 class MallocSorter(AbstractSorter):
@@ -404,21 +402,18 @@
   def __init__(self, dct):
     assert dct['world'] == 'malloc'
     super(MallocSorter, self).__init__(dct)
-    self._no_bucket_rule = NoBucketMallocRule()
 
   def find(self, unit):
     if not unit.bucket:
-      return self._no_bucket_rule
+      return None
     assert unit.bucket.allocator_type == 'malloc'
 
-    if unit.bucket.component_cache:
-      return unit.bucket.component_cache
+    # TODO(dmikurube): Utilize component_cache again, or remove it.
 
     for rule in self._rules:
       if rule.match(unit):
-        unit.bucket.component_cache = rule
         return rule
-    assert False
+    return None
 
 
 class SorterTemplates(object):
@@ -432,7 +427,7 @@
   @staticmethod
   def load(filename):
     with open(filename) as templates_f:
-      templates_dict = json.load(templates_f)
+      templates_dict = json.load(templates_f, object_pairs_hook=OrderedDict)
     return SorterTemplates(templates_dict)
 
 
@@ -453,7 +448,9 @@
 
   def __repr__(self):
     result = cStringIO.StringIO()
-    result.write(self._sorters)
+    for world, sorters in self._sorters.iteritems():
+      for sorter in sorters:
+        print >> result, '%s: %s' % (world, sorter)
     return result.getvalue()
 
   def __iter__(self):
diff --git a/tools/deep_memory_profiler/policies.json b/tools/deep_memory_profiler/policies.json
index 775045a..dc62da6 100644
--- a/tools/deep_memory_profiler/policies.json
+++ b/tools/deep_memory_profiler/policies.json
@@ -27,6 +27,10 @@
     "file": "policy.l2.json",
     "format": "json"
   },
+  "linux.browser": {
+    "file": "policy.linux.browser.json",
+    "format": "json"
+  },
   "t0": {
     "file": "policy.t0.json",
     "format": "json"
diff --git a/tools/deep_memory_profiler/policy.android.renderer.json b/tools/deep_memory_profiler/policy.android.renderer.json
index dc1e3b5..c039c6f 100644
--- a/tools/deep_memory_profiler/policy.android.renderer.json
+++ b/tools/deep_memory_profiler/policy.android.renderer.json
@@ -52,6 +52,7 @@
     "tc-webcore-events-related",
     "tc-webcore-document-write",
     "tc-webcore-node-create-renderer",
+    "tc-webcore-image-frame-generator",
     "tc-webcore-render-catch-all",
     "tc-webcore-setInnerHTML-except-node",
     "tc-wtf-StringImpl-user-catch-all",
@@ -414,6 +415,11 @@
       "allocator": "malloc"
     },
     {
+      "name": "tc-webcore-image-frame-generator",
+      "stacktrace": ".*WebCore::ImageFrameGenerator.*",
+      "allocator": "malloc"
+    },
+    {
       "name": "tc-webcore-render-catch-all",
       "stacktrace": ".*WebCore::RenderLayer.*",
       "allocator": "malloc"
diff --git a/tools/deep_memory_profiler/policy.l2.json b/tools/deep_memory_profiler/policy.l2.json
index f0a007b..6fdad40 100644
--- a/tools/deep_memory_profiler/policy.l2.json
+++ b/tools/deep_memory_profiler/policy.l2.json
@@ -19,6 +19,11 @@
     "mmap-v8-heap-coderange",
     "mmap-v8-heap-pagedspace",
     "mmap-v8-other",
+    "mmap-gpu-mappedmemorymanager",
+    "mmap-gpu-command-ringbuffer",
+    "mmap-gpu-transfer-ringbuffer",
+    "mmap-gpu-gles2-createbuffer",
+    "mmap-skia-font",
     "mmap-catch-all",
     "tc-webcore-fontcache",
     "tc-skia",
@@ -166,6 +171,31 @@
       "allocator": "mmap"
     },
     {
+      "name": "mmap-gpu-mappedmemorymanager",
+      "stacktrace": ".*gpu::MappedMemoryManager::Alloc.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-gpu-command-ringbuffer",
+      "stacktrace": ".*gpu::CommandBufferHelper::AllocateRingBuffer.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-gpu-transfer-ringbuffer",
+      "stacktrace": ".*gpu::TransferBuffer::AllocateRingBuffer.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-gpu-gles2-createbuffer",
+      "stacktrace": ".*gpu::gles2::BufferTracker::CreateBuffer.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-skia-font",
+      "stacktrace": ".*SkTypeface::openStream.*",
+      "allocator": "mmap"
+    },
+    {
       "name": "mmap-catch-all",
       "stacktrace": ".*",
       "allocator": "mmap"
diff --git a/tools/deep_memory_profiler/policy.linux.browser.json b/tools/deep_memory_profiler/policy.linux.browser.json
new file mode 100644
index 0000000..16f4e11
--- /dev/null
+++ b/tools/deep_memory_profiler/policy.linux.browser.json
@@ -0,0 +1,381 @@
+{
+  "components": [
+    "second",
+    "mmap-profiler",
+    "mmap-type-profiler",
+    "mmap-tcmalloc",
+    "FROM_HERE_FOR_TOTAL",
+    "mustbezero",
+    "unhooked-absent",
+    "unhooked-anonymous",
+    "unhooked-file-exec",
+    "unhooked-file-nonexec-others",
+    "unhooked-file-nonexec-group",
+    "unhooked-file-nonexec",
+    "unhooked-stack",
+    "unhooked-other",
+    "no-bucket",
+    "mmap-v8-heap-newspace",
+    "mmap-v8-heap-coderange",
+    "mmap-v8-heap-pagedspace",
+    "mmap-v8-other",
+    "mmap-gpu-mappedmemorymanager",
+    "mmap-gpu-command-ringbuffer",
+    "mmap-gpu-transfer-ringbuffer",
+    "mmap-gpu-gles2-createbuffer",
+    "mmap-skia-font",
+    "mmap-catch-all",
+    "tc-glib",
+    "tc-std-bits-string",
+    "tc-std-bits-ptsynch",
+    "tc-skia",
+    "tc-sqlite",
+    "tc-syncer",
+    "tc-domstorage",
+    "tc-safebrowsingdatabase",
+    "tc-threadcontext",
+    "tc-leveldb-readblock",
+    "tc-leveldb",
+    "tc-spdy-doreadloop",
+    "tc-spdy",
+    "tc-net-sslconnectjob",
+    "tc-history-thumbnails",
+    "tc-history-urlindex-privatedata",
+    "tc-crlset",
+    "tc-extension-host",
+    "tc-bookmark-codec",
+    "tc-webkit-catch-all",
+    "tc-v8-catch-all",
+    "tc-toplevel-string",
+    "tc-std-treemap",
+    "tc-std-hashmap",
+    "tc-std-vector",
+    "tc-std-other",
+    "tc-catch-all",
+    "tc-unused",
+    "UNTIL_HERE_FOR_TOTAL",
+    "total-exclude-profiler",
+    "total",
+    "absent",
+    "anonymous",
+    "file-exec",
+    "file-nonexec",
+    "stack",
+    "other",
+    "mmap-total-log",
+    "mmap-no-log",
+    "mmap-total-record",
+    "other-total-log",
+    "tc-total-log",
+    "tc-no-log",
+    "tc-total-record",
+    "tc-total"
+  ],
+  "rules": [
+    {
+      "name": "second",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "mmap-profiler",
+      "stacktrace": ".*(ProfilerMalloc|MemoryRegionMap::).*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-type-profiler",
+      "stacktrace": ".*(TypeProfilerMalloc).*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-tcmalloc",
+      "stacktrace": ".*(DoAllocWithArena|SbrkSysAllocator::Alloc|MmapSysAllocator::Alloc|LowLevelAlloc::Alloc|LowLevelAlloc::AllocWithArena).*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "FROM_HERE_FOR_TOTAL",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "mustbezero",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "unhooked-absent",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "unhooked-anonymous",
+      "mappedpathname": "^$",
+      "allocator": "unhooked"
+    },
+    {
+      "name": "unhooked-file-exec",
+      "mappedpathname": "^/.*",
+      "mappedpermission": "..x.",
+      "allocator": "unhooked"
+    },
+    {
+      "name": "unhooked-file-nonexec-others",
+      "mappedpathname": "^/.*",
+      "allocator": "unhooked",
+      "sharedwith": ["others"]
+    },
+    {
+      "name": "unhooked-file-nonexec-group",
+      "mappedpathname": "^/.*",
+      "allocator": "unhooked",
+      "sharedwith": ["group"]
+    },
+    {
+      "name": "unhooked-file-nonexec",
+      "mappedpathname": "^/.*",
+      "allocator": "unhooked"
+    },
+    {
+      "name": "unhooked-stack",
+      "mappedpathname": ".stack.",
+      "allocator": "unhooked"
+    },
+    {
+      "name": "unhooked-other",
+      "mappedpathname": ".*",
+      "allocator": "unhooked"
+    },
+    {
+      "name": "mmap-v8-heap-newspace",
+      "stacktrace": ".*v8::internal::NewSpace::SetUp.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-v8-heap-coderange",
+      "stacktrace": ".*v8::internal::CodeRange::SetUp.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-v8-heap-pagedspace",
+      "stacktrace": ".*v8::internal::PagedSpace::AllocateRaw.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-v8-other",
+      "stacktrace": ".*v8::.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-gpu-mappedmemorymanager",
+      "stacktrace": ".*gpu::MappedMemoryManager::Alloc.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-gpu-command-ringbuffer",
+      "stacktrace": ".*gpu::CommandBufferHelper::AllocateRingBuffer.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-gpu-transfer-ringbuffer",
+      "stacktrace": ".*gpu::TransferBuffer::AllocateRingBuffer.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-gpu-gles2-createbuffer",
+      "stacktrace": ".*gpu::gles2::BufferTracker::CreateBuffer.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-skia-font",
+      "stacktrace": ".*SkTypeface::openStream.*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "mmap-catch-all",
+      "stacktrace": ".*",
+      "allocator": "mmap"
+    },
+    {
+      "name": "tc-glib",
+      "stacktrace": ".*(g_realloc|g_malloc.?|slab_allocator_alloc_chunk)($| .*)",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-std-bits-string",
+      "stacksourcefile": ".*/usr/include/.*/bits/string.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-std-bits-ptsynch",
+      "stacksourcefile": "/usr/include/.*/bits/ptsynch.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-skia",
+      "stacktrace": ".* Sk[A-Za-z_]+::.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-sqlite",
+      "stacktrace": ".*sqlite3Mem(Malloc|Realloc).*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-syncer",
+      "stacktrace": ".* syncer::.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-domstorage",
+      "stacktrace": ".*content::DOMStorageMessageFilter::OnMessageReceived.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-safebrowsingdatabase",
+      "stacktrace": ".*SafeBrowsingDatabaseNew::UpdateFinished.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-threadcontext",
+      "stacktrace": ".*tracked_objects::ThreadData::InitializeThreadContext.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-leveldb-readblock",
+      "stacktrace": ".*leveldb::ReadBlock.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-leveldb",
+      "stacktrace": ".*leveldb::.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-spdy-doreadloop",
+      "stacktrace": ".*net::SpdySession::DoReadLoop.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-spdy",
+      "stacksourcefile": ".*\\.\\./\\.\\./net/spdy/.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-net-sslconnectjob",
+      "stacktrace": ".*net::SSLConnectJob::DoLoop.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-history-thumbnails",
+      "stacktrace": ".*history::.*",
+      "stacksourcefile": ".*\\.\\./\\.\\./chrome/browser/thumbnails/.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-history-urlindex-privatedata",
+      "stacktrace": ".*history::URLIndexPrivateData::.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-crlset",
+      "stacktrace": ".*CRLSetFetcher::LoadFromDisk.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-extension-host",
+      "stacktrace": ".*extensions::ExtensionHost::ExtensionHost.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-bookmark-codec",
+      "stacktrace": ".*BookmarkCodec::.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-webkit-catch-all",
+      "stacktrace": ".*(WTF::|WebCore::|WebKit::).*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-v8-catch-all",
+      "stacktrace": ".*v8::.*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-toplevel-string",
+      "stacktrace": "std::basic_string::_Rep::_S_create",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-std-treemap",
+      "stacktrace": ".*::allocate std::(_Rb_tree|__1::__tree).*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-std-hashmap",
+      "stacktrace": ".*(std::vector::reserve __gnu_cxx::hashtable|::allocate std::_Hashtable|::allocate std::__1::__hash_table).*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-std-vector",
+      "stacktrace": ".*std::(_Vector_base::_M_allocate|__1::vector::allocate).*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-std-other",
+      "stacktrace": ".*(__gnu_cxx::new_allocator::allocate|std::__1::allocator::allocate).*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "tc-catch-all",
+      "stacktrace": ".*",
+      "allocator": "malloc"
+    },
+    {
+      "name": "UNTIL_HERE_FOR_TOTAL",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "total-exclude-profiler",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "total",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "absent",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "anonymous",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "file-exec",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "file-nonexec",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "stack",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    },
+    {
+      "name": "other",
+      "stacktrace": "optional",
+      "allocator": "optional"
+    }
+  ],
+  "version": "POLICY_DEEP_3"
+}
diff --git a/tools/deep_memory_profiler/subcommands/cat.py b/tools/deep_memory_profiler/subcommands/cat.py
index 1e9e5b3..6a333a4 100644
--- a/tools/deep_memory_profiler/subcommands/cat.py
+++ b/tools/deep_memory_profiler/subcommands/cat.py
@@ -56,9 +56,23 @@
     json_root['default_template'] = 'l2'
     json_root['templates'] = sorters.templates.as_dict()
 
+    orders = OrderedDict()
+    orders['worlds'] = OrderedDict()
+    for world in ['vm', 'malloc']:
+      orders['worlds'][world] = OrderedDict()
+      orders['worlds'][world]['breakdown'] = OrderedDict()
+      for sorter in sorters.iter_world(world):
+        order = []
+        for rule in sorter.iter_rule():
+          if (not order) or (rule.name != order[-1]):
+            order.append(rule.name)
+        orders['worlds'][world]['breakdown'][sorter.name] = order
+    json_root['orders'] = orders
+
     json_root['snapshots'] = []
 
     for dump in dumps:
+      LOGGER.info('Sorting a dump %s...' % dump.path)
       json_root['snapshots'].append(
           self._fill_snapshot(dump, bucket_set, sorters))
 
@@ -107,23 +121,25 @@
     # Iterate for { vm | malloc } sorters.
     root['breakdown'] = OrderedDict()
     for sorter in sorters.iter_world(world):
+      LOGGER.info('  Sorting with %s:%s.' % (sorter.world, sorter.name))
       breakdown = OrderedDict()
+      for rule in sorter.iter_rule():
+        category = OrderedDict()
+        category['name'] = rule.name
+        subs = []
+        for sub_world, sub_breakdown in rule.iter_subs():
+          subs.append([sub_world, sub_breakdown])
+        if subs:
+          category['subs'] = subs
+        if rule.hidden:
+          category['hidden'] = True
+        category['units'] = []
+        breakdown[rule.name] = category
       for unit in unit_set:
         found = sorter.find(unit)
-        if found.name not in breakdown:
-          category = OrderedDict()
-          category['name'] = found.name
-          category['color'] = 'random'
-          subs = []
-          for sub_world, sub_breakdown in found.iter_subs():
-            subs.append([sub_world, sub_breakdown])
-          if subs:
-            category['subs'] = subs
-          if found.hidden:
-            category['hidden'] = True
-          category['units'] = []
-          breakdown[found.name] = category
-        breakdown[found.name]['units'].append(unit.unit_id)
+        if found:
+          # Note that a bucket which doesn't match any rule is just dropped.
+          breakdown[found.name]['units'].append(unit.unit_id)
       root['breakdown'][sorter.name] = breakdown
 
     return root
diff --git a/tools/deep_memory_profiler/subcommands/policies.py b/tools/deep_memory_profiler/subcommands/policies.py
index 182959b..0b9181a 100644
--- a/tools/deep_memory_profiler/subcommands/policies.py
+++ b/tools/deep_memory_profiler/subcommands/policies.py
@@ -27,6 +27,9 @@
                             metavar='/path/on/target@/path/on/host[:...]',
                             help='Read files in /path/on/host/ instead of '
                                  'files in /path/on/target/.')
+    self._parser.add_option('--timestamp', dest='timestamp',
+                            action='store_true', help='Use timestamp.')
+    self._timestamp = False
 
   def _set_up(self, sys_argv):
     options, args = self._parse_args(sys_argv, 1)
@@ -40,6 +43,8 @@
     (bucket_set, dumps) = SubCommand.load_basic_files(
         dump_path, True, alternative_dirs=alternative_dirs_dict)
 
+    self._timestamp = options.timestamp
+
     pfn_counts_dict = {}
     for shared_first_dump_path in shared_first_dump_paths:
       shared_dumps = SubCommand._find_all_dumps(shared_first_dump_path)
@@ -52,8 +57,8 @@
     policy_set = PolicySet.load(SubCommand._parse_policy_list(options.policy))
     return policy_set, dumps, pfn_counts_dict, bucket_set
 
-  @staticmethod
-  def _apply_policy(dump, pfn_counts_dict, policy, bucket_set, first_dump_time):
+  def _apply_policy(self, dump, pfn_counts_dict, policy, bucket_set,
+                    first_dump_time):
     """Aggregates the total memory size of each component.
 
     Iterate through all stacktraces and attribute them to one of the components
@@ -170,7 +175,10 @@
     if 'minute' in sizes:
       sizes['minute'] = (dump.time - first_dump_time) / 60.0
     if 'second' in sizes:
-      sizes['second'] = dump.time - first_dump_time
+      if self._timestamp:
+        sizes['second'] = datetime.datetime.fromtimestamp(dump.time).isoformat()
+      else:
+        sizes['second'] = dump.time - first_dump_time
 
     return sizes
 
@@ -275,11 +283,10 @@
 
   def do(self, sys_argv):
     policy_set, dumps, pfn_counts_dict, bucket_set = self._set_up(sys_argv)
-    return CSVCommand._output(
+    return self._output(
         policy_set, dumps, pfn_counts_dict, bucket_set, sys.stdout)
 
-  @staticmethod
-  def _output(policy_set, dumps, pfn_counts_dict, bucket_set, out):
+  def _output(self, policy_set, dumps, pfn_counts_dict, bucket_set, out):
     max_components = 0
     for label in policy_set:
       max_components = max(max_components, len(policy_set[label].components))
@@ -293,12 +300,15 @@
 
       LOGGER.info('Applying a policy %s to...' % label)
       for dump in dumps:
-        component_sizes = PolicyCommands._apply_policy(
+        component_sizes = self._apply_policy(
             dump, pfn_counts_dict, policy_set[label], bucket_set, dumps[0].time)
         s = []
         for c in components:
           if c in ('hour', 'minute', 'second'):
-            s.append('%05.5f' % (component_sizes[c]))
+            if isinstance(component_sizes[c], str):
+              s.append('%s' % component_sizes[c])
+            else:
+              s.append('%05.5f' % (component_sizes[c]))
           else:
             s.append('%05.5f' % (component_sizes[c] / 1024.0 / 1024.0))
         out.write('%s%s\n' % (
@@ -315,11 +325,10 @@
 
   def do(self, sys_argv):
     policy_set, dumps, pfn_counts_dict, bucket_set = self._set_up(sys_argv)
-    return JSONCommand._output(
+    return self._output(
         policy_set, dumps, pfn_counts_dict, bucket_set, sys.stdout)
 
-  @staticmethod
-  def _output(policy_set, dumps, pfn_counts_dict, bucket_set, out):
+  def _output(self, policy_set, dumps, pfn_counts_dict, bucket_set, out):
     json_base = {
       'version': 'JSON_DEEP_2',
       'policies': {},
@@ -333,7 +342,7 @@
 
       LOGGER.info('Applying a policy %s to...' % label)
       for dump in dumps:
-        component_sizes = PolicyCommands._apply_policy(
+        component_sizes = self._apply_policy(
             dump, pfn_counts_dict, policy_set[label], bucket_set, dumps[0].time)
         component_sizes['dump_path'] = dump.path
         component_sizes['dump_time'] = datetime.datetime.fromtimestamp(
@@ -353,15 +362,14 @@
 
   def do(self, sys_argv):
     policy_set, dumps, pfn_counts_dict, bucket_set = self._set_up(sys_argv)
-    return ListCommand._output(
+    return self._output(
         policy_set, dumps, pfn_counts_dict, bucket_set, sys.stdout)
 
-  @staticmethod
-  def _output(policy_set, dumps, pfn_counts_dict, bucket_set, out):
+  def _output(self, policy_set, dumps, pfn_counts_dict, bucket_set, out):
     for label in sorted(policy_set):
       LOGGER.info('Applying a policy %s to...' % label)
       for dump in dumps:
-        component_sizes = PolicyCommands._apply_policy(
+        component_sizes = self._apply_policy(
             dump, pfn_counts_dict, policy_set[label], bucket_set, dump.time)
         out.write('%s for %s:\n' % (label, dump.path))
         for c in policy_set[label].components:
diff --git a/tools/deep_memory_profiler/visualizer/main.css b/tools/deep_memory_profiler/visualizer/main.css
new file mode 100644
index 0000000..5d9ed53
--- /dev/null
+++ b/tools/deep_memory_profiler/visualizer/main.css
@@ -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. */
+
+.plot-container {
+  width: 1240px;
+  height: 720px;
+  margin: 30px auto 30px auto;
+}
\ No newline at end of file
diff --git a/tools/deep_memory_profiler/visualizer/main.html b/tools/deep_memory_profiler/visualizer/main.html
new file mode 100644
index 0000000..75df003
--- /dev/null
+++ b/tools/deep_memory_profiler/visualizer/main.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<!--
+Copyright 2013 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<meta charset="utf-8">
+<link rel="stylesheet" href="main.css">
+<script src="../../../third_party/flot/jquery.min.js"></script>
+<script src="../../../third_party/flot/jquery.flot.min.js"></script>
+<script src="../../../third_party/flot/jquery.flot.stack.min.js"></script>
+<script src="utility.js"></script>
+<script src="profiler.js"></script>
+<script src="main.js"></script>
+
+<body>
+  <h2>Deep Memory Profiler Visulaizer</h2>
+  <div id="plot" class="plot-container"></div>
+</body>
diff --git a/tools/deep_memory_profiler/visualizer/main.js b/tools/deep_memory_profiler/visualizer/main.js
new file mode 100644
index 0000000..1d96213
--- /dev/null
+++ b/tools/deep_memory_profiler/visualizer/main.js
@@ -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.
+
+/**
+ * Generate lines for flot plotting.
+ * @param  {Array.<Object>} categories
+ * @return {Array.<Object>}
+ */
+var generateLines = function(categories) {
+  var lines = {};
+  var snapshotNum = categories.length;
+
+  // Initialize lines with all zero.
+  categories.forEach(function(categories) {
+    Object.keys(categories).forEach(function(breakdownName) {
+      if (lines[breakdownName])
+        return;
+      lines[breakdownName] = [];
+      for (var i = 0; i < snapshotNum; ++i)
+        lines[breakdownName].push([i, 0]);
+    });
+  });
+
+  // Assignment lines with values of categories.
+  categories.forEach(function(categories, index) {
+    Object.keys(categories).forEach(function(breakdownName) {
+      lines[breakdownName][index] = [index, categories[breakdownName]];
+    });
+  });
+
+  return Object.keys(lines).map(function(breakdownName) {
+    return {
+      label: breakdownName,
+      data: lines[breakdownName]
+    };
+  });
+};
+
+$(function() {
+  // Read original data and plot.
+  $.getJSON('data/result.json', function(jsonData) {
+    var profiler = new Profiler(jsonData);
+    var categories = profiler.getCategories();
+    var lines = generateLines(categories);
+    var placeholder = '#plot';
+
+    // Bind click event so that user can select breakdown by clicking stack
+    // area. It firstly checks x range which clicked point is in, and all lines
+    // share same x values, so it is checked only once at first. Secondly, it
+    // checked y range by accumulated y values because this is a stack graph.
+    $(placeholder).bind('plotclick', function(event, pos, item) {
+      // If only <=1 line exists or axis area clicked, return.
+      var right = binarySearch.call(lines[0].data.map(function(point) {
+        return point[0];
+      }), pos.x);
+      if (lines.length <= 1 || right === lines.length || right === 0)
+        return;
+
+      // Calculate interpolate y value of every line.
+      for (var i = 0; i < lines.length; ++i) {
+        var line = lines[i].data;
+        // [left, right] is the range including clicked point.
+        var left = right - 1;
+        var leftPoint = {
+          x: line[left][0],
+          y: (leftPoint ? leftPoint.y : 0) + line[left][1]
+        };
+        var rightPoint = {
+          x: line[right][0],
+          y: (rightPoint ? rightPoint.y : 0) + line[right][1]
+        };
+
+        // Calculate slope of the linear equation.
+        var slope = (rightPoint.y - leftPoint.y) / (rightPoint.x - leftPoint.x);
+        var interpolateY = slope * (pos.x - rightPoint.x) + rightPoint.y;
+        if (interpolateY >= pos.y)
+          break;
+      }
+
+      // If pos.y is higher than all lines, return.
+      if (i === lines.length)
+        return;
+
+      // TODO(junjianx): temporary log for checking selected object.
+      console.log('line ' + i + ' is selected.');
+    });
+
+    // Plot stack graph.
+    $.plot(placeholder, lines, {
+      series: {
+        stack: true,
+        lines: { show: true, fill: true }
+      },
+      grid: {
+        hoverable: true,
+        clickable: true
+      }
+    });
+  });
+});
diff --git a/tools/deep_memory_profiler/visualizer/profiler.js b/tools/deep_memory_profiler/visualizer/profiler.js
new file mode 100644
index 0000000..672c8f0
--- /dev/null
+++ b/tools/deep_memory_profiler/visualizer/profiler.js
@@ -0,0 +1,110 @@
+// Copyright 2013 The Chromium 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 class provides data access interface for dump file profiler
+ * @constructor
+ */
+var Profiler = function(jsonData) {
+  this._jsonData = jsonData;
+};
+
+/**
+ * Get units of a snapshot in a world.
+ * Exception will be thrown when no world of given name exists.
+ * @param  {string} worldName
+ * @param  {number} snapshotIndex
+ * @return {Object.<string, number>}
+ * @private
+ */
+Profiler.prototype.getUnits_ = function(worldName, snapshotIndex) {
+  var snapshot = this._jsonData.snapshots[snapshotIndex];
+  if (!snapshot.worlds[worldName])
+    throw 'no world ' + worldName + ' in snapshot ' + index;
+
+  // Return units.
+  var world = snapshot.worlds[worldName];
+  var units = {};
+  for (var unitName in world.units)
+    units[unitName] = world.units[unitName][0];
+  return units;
+};
+
+/**
+ * Get first-level breakdowns of a snapshot in a world.
+ * Exception will be thrown when no world of given name exists.
+ * @param  {string} worldName
+ * @param  {number} snapshotIndex
+ * @return {Object.<string, Object>}
+ * @private
+ */
+Profiler.prototype.getBreakdowns_ = function(worldName, snapshotIndex) {
+  var snapshot = this._jsonData.snapshots[snapshotIndex];
+  if (!snapshot.worlds[worldName])
+    throw 'no world ' + worldName + ' in snapshot ' + index;
+
+  // Return breakdowns.
+  // TODO(junjianx): handle breakdown with arbitrary-level structure.
+  return snapshot.worlds[worldName].breakdown;
+};
+
+/**
+ * Get categories from fixed hard-coded worlds and breakdowns temporarily.
+ * TODO(junjianx): remove the hard-code and support general cases.
+ * @return {Array.<Object>}
+ */
+Profiler.prototype.getCategories = function() {
+  var categories = [];
+  var snapshotNum = this._jsonData.snapshots.length;
+
+  for (var snapshotIndex = 0; snapshotIndex < snapshotNum; ++snapshotIndex) {
+    // Initial categories object for one snapshot.
+    categories.push({});
+
+    // Handle breakdowns in malloc world.
+    var mallocBreakdown = this.getBreakdowns_('malloc', snapshotIndex);
+    var mallocUnits = this.getUnits_('malloc', snapshotIndex);
+    if (!mallocBreakdown['component'])
+      throw 'no breakdown ' + 'component' + ' in snapshot ' + snapshotIndex;
+
+    var componentBreakdown = mallocBreakdown['component'];
+    var componentMemory = 0;
+    Object.keys(componentBreakdown).forEach(function(breakdownName) {
+      var breakdown = componentBreakdown[breakdownName];
+      var memory = breakdown.units.reduce(function(previous, current) {
+        return previous + mallocUnits[current];
+      }, 0);
+      componentMemory += memory;
+
+      if (componentBreakdown['hidden'] === true)
+        return;
+      else
+        categories[snapshotIndex][breakdownName] = memory;
+    });
+
+    // Handle breakdowns in vm world.
+    var vmBreakdown = this.getBreakdowns_('vm', snapshotIndex);
+    var vmUnits = this.getUnits_('vm', snapshotIndex);
+    if (!vmBreakdown['map'])
+      throw 'no breakdown ' + 'map' + ' in snapshot ' + snapshotIndex;
+
+    var mapBreakdown = vmBreakdown['map'];
+
+    Object.keys(mapBreakdown).forEach(function(breakdownName) {
+      var breakdown = mapBreakdown[breakdownName];
+      var memory = breakdown.units.reduce(function(previous, current) {
+        return previous + vmUnits[current];
+      }, 0);
+
+      if (vmBreakdown['hidden'] === true)
+        return;
+      else if (breakdownName === 'mmap-tcmalloc')
+        categories[snapshotIndex]['tc-unused'] = memory - componentMemory;
+      else
+        categories[snapshotIndex][breakdownName] = memory;
+    });
+  }
+
+  return categories;
+};
diff --git a/tools/deep_memory_profiler/visualizer/utility.js b/tools/deep_memory_profiler/visualizer/utility.js
new file mode 100644
index 0000000..f595fd0
--- /dev/null
+++ b/tools/deep_memory_profiler/visualizer/utility.js
@@ -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.
+
+/**
+ * This function returns the first element index that >= target, when no element
+ * in the array >= target, return array.length.
+ * This function must be called in the shape of binarySearch(array, target).
+ * @param  {number} target
+ * @return {number}
+ */
+var binarySearch = function(target) {
+    'use strict';
+
+    var left = 0;
+    var right = this.length - 1;
+    while (left <= right) {
+        var mid = Math.floor((left + right) / 2);
+        if (this[mid] < target)
+            left = mid + 1;
+        else if (this[mid] > target)
+            right = mid - 1;
+        else
+            return mid;
+    }
+    return left;
+};
diff --git a/tools/export_tarball/export_v8_tarball.py b/tools/export_tarball/export_v8_tarball.py
index 30767b6..b232c0a 100755
--- a/tools/export_tarball/export_v8_tarball.py
+++ b/tools/export_tarball/export_v8_tarball.py
@@ -32,6 +32,10 @@
   _V8_BUILD_NUMBER_PATTERN,
   _V8_PATCH_LEVEL_PATTERN]
 
+_NONESSENTIAL_DIRS = (
+    'third_party/icu',
+)
+
 
 def GetV8Version(v8_directory):
   """
@@ -63,11 +67,24 @@
 # Workaround lack of the exclude parameter in add method in python-2.4.
 # TODO(phajdan.jr): remove the workaround when it's not needed on the bot.
 class MyTarFile(tarfile.TarFile):
+  def set_remove_nonessential_files(self, remove):
+    self.__remove_nonessential_files = remove
+
   def add(self, name, arcname=None, recursive=True, exclude=None, filter=None):
     head, tail = os.path.split(name)
     if tail in ('.svn', '.git'):
       return
 
+    if self.__remove_nonessential_files:
+      # Remove contents of non-essential directories, but preserve gyp files,
+      # so that build/gyp_chromium can work.
+      for nonessential_dir in _NONESSENTIAL_DIRS:
+        dir_path = os.path.join(GetV8Directory(), nonessential_dir)
+        if (name.startswith(dir_path) and
+            os.path.isfile(name) and
+            'gyp' not in name):
+          return
+
     tarfile.TarFile.add(self, name, arcname=arcname, recursive=recursive)
 
 
@@ -86,20 +103,30 @@
 
   v8_version = GetV8Version(v8_directory)
   print 'Packaging V8 version %s...' % v8_version
-  output_basename = 'v8-%s' % v8_version
-  output_fullname = os.path.join(args[0], output_basename + '.tar.bz2')
-
-  if os.path.exists(output_fullname):
-    print 'Already packaged, exiting.'
-    return 0
 
   subprocess.check_call(["make", "dependencies"], cwd=v8_directory)
 
-  archive = MyTarFile.open(output_fullname, 'w:bz2')
-  try:
-    archive.add(v8_directory, arcname=output_basename)
-  finally:
-    archive.close()
+  output_basename = 'v8-%s' % v8_version
+
+  # Package full tarball.
+  output_fullname = os.path.join(args[0], output_basename + '.tar.bz2')
+  if not os.path.exists(output_fullname):
+    archive = MyTarFile.open(output_fullname, 'w:bz2')
+    archive.set_remove_nonessential_files(False)
+    try:
+      archive.add(v8_directory, arcname=output_basename)
+    finally:
+      archive.close()
+
+  # Package lite tarball.
+  output_fullname = os.path.join(args[0], output_basename + '-lite.tar.bz2')
+  if not os.path.exists(output_fullname):
+    archive = MyTarFile.open(output_fullname, 'w:bz2')
+    archive.set_remove_nonessential_files(True)
+    try:
+      archive.add(v8_directory, arcname=output_basename)
+    finally:
+      archive.close()
 
   return 0
 
diff --git a/tools/generate_library_loader/generate_library_loader.py b/tools/generate_library_loader/generate_library_loader.py
index 866e005..ebf0ab1 100755
--- a/tools/generate_library_loader/generate_library_loader.py
+++ b/tools/generate_library_loader/generate_library_loader.py
@@ -31,18 +31,13 @@
 
 #include <string>
 
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#if defined(%(unique_prefix)s_DLOPEN)
-#include "base/native_library.h"
-#endif
-
 class %(class_name)s {
  public:
   %(class_name)s();
   ~%(class_name)s();
 
-  bool Load(const std::string& library_name) WARN_UNUSED_RESULT;
+  bool Load(const std::string& library_name)
+      __attribute__((warn_unused_result));
 
   bool loaded() const { return loaded_; }
 
@@ -52,12 +47,14 @@
   void CleanUp(bool unload);
 
 #if defined(%(unique_prefix)s_DLOPEN)
-  base::NativeLibrary library_;
+  void* library_;
 #endif
 
   bool loaded_;
 
-  DISALLOW_COPY_AND_ASSIGN(%(class_name)s);
+  // Disallow copy constructor and assignment operator.
+  %(class_name)s(const %(class_name)s&);
+  void operator=(const %(class_name)s&);
 };
 
 #endif  // %(unique_prefix)s
@@ -73,6 +70,8 @@
 
 #include "%(generated_header_name)s"
 
+#include <dlfcn.h>
+
 // Put these sanity checks here so that they fire at most once
 // (to avoid cluttering the build output).
 #if !defined(%(unique_prefix)s_DLOPEN) && !defined(%(unique_prefix)s_DT_NEEDED)
@@ -82,9 +81,6 @@
 #error both %(unique_prefix)s_DLOPEN and %(unique_prefix)s_DT_NEEDED defined
 #endif
 
-#include "base/files/file_path.h"
-#include "base/logging.h"
-
 %(class_name)s::%(class_name)s() : loaded_(false) {
 }
 
@@ -93,13 +89,11 @@
 }
 
 bool %(class_name)s::Load(const std::string& library_name) {
-  if (loaded_) {
-    NOTREACHED();
+  if (loaded_)
     return false;
-  }
 
 #if defined(%(unique_prefix)s_DLOPEN)
-  library_ = base::LoadNativeLibrary(base::FilePath(library_name), NULL);
+  library_ = dlopen(library_name.c_str(), RTLD_LAZY);
   if (!library_)
     return false;
 #endif
@@ -113,7 +107,7 @@
 void %(class_name)s::CleanUp(bool unload) {
 #if defined(%(unique_prefix)s_DLOPEN)
   if (unload) {
-    base::UnloadNativeLibrary(library_);
+    dlclose(library_);
     library_ = NULL;
   }
 #endif
@@ -126,8 +120,7 @@
 #if defined(%(unique_prefix)s_DLOPEN)
   %(function_name)s =
       reinterpret_cast<typeof(this->%(function_name)s)>(
-          base::GetFunctionPointerFromNativeLibrary(
-              library_, "%(function_name)s"));
+          dlsym(library_, "%(function_name)s"));
 #endif
 #if defined(%(unique_prefix)s_DT_NEEDED)
   %(function_name)s = &::%(function_name)s;
diff --git a/tools/gn/BUILD.gn b/tools/gn/BUILD.gn
index f699ab3..a2647e2 100644
--- a/tools/gn/BUILD.gn
+++ b/tools/gn/BUILD.gn
@@ -1,10 +1,16 @@
 static_library("gn_lib") {
   sources = [
+    "args.cc",
+    "args.h",
+    "binary_target_generator.cc",
+    "binary_target_generator.h",
     "build_settings.cc",
     "build_settings.h",
+    "command_args.cc",
     "command_desc.cc",
     "command_gen.cc",
     "command_help.cc",
+    "command_refs.cc",
     "commands.cc",
     "commands.h",
     "config.cc",
@@ -15,6 +21,8 @@
     "config_values_extractors.h",
     "config_values_generator.cc",
     "config_values_generator.h",
+    "copy_target_generator.cc",
+    "copy_target_generator.h",
     "err.cc",
     "err.h",
     "escape.cc",
@@ -30,9 +38,12 @@
     "function_process_file_template.cc",
     "function_read_file.cc",
     "function_set_default_toolchain.cc",
+    "function_set_defaults.cc",
     "function_template.cc",
     "function_toolchain.cc",
     "function_write_file.cc",
+    "group_target_generator.cc",
+    "group_target_generator.h",
     "import_manager.cc",
     "import_manager.h",
     "input_conversion.cc",
@@ -50,10 +61,18 @@
     "label.cc",
     "label.h",
     "location.h",
+    "ninja_binary_target_writer.cc",
+    "ninja_binary_target_writer.h",
     "ninja_build_writer.cc",
     "ninja_build_writer.h",
+    "ninja_copy_target_writer.cc",
+    "ninja_copy_target_writer.h",
+    "ninja_group_target_writer.cc",
+    "ninja_group_target_writer.h",
     "ninja_helper.cc",
     "ninja_helper.h",
+    "ninja_script_target_writer.cc",
+    "ninja_script_target_writer.h",
     "ninja_target_writer.cc",
     "ninja_target_writer.h",
     "ninja_toolchain_writer.cc",
@@ -77,6 +96,10 @@
     "scope.h",
     "scope_per_file_provider.cc",
     "scope_per_file_provider.h",
+    "script_target_generator.cc",
+    "script_target_generator.h",
+    "script_values.cc",
+    "script_values.h",
     "settings.cc",
     "settings.h",
     "setup.cc",
@@ -144,9 +167,9 @@
   ]
   deps = [
     ":gn_lib",
-    "//base:run_all_unittests",
-    "//base:test_support_base",
-    "//testing:gtest",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support_base",
+    "//testing/gtest",
   ]
 }
 
diff --git a/tools/gn/args.cc b/tools/gn/args.cc
new file mode 100644
index 0000000..d340713
--- /dev/null
+++ b/tools/gn/args.cc
@@ -0,0 +1,188 @@
+// 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 "tools/gn/args.h"
+
+#include "tools/gn/variables.h"
+
+const char kBuildArgs_Help[] =
+    "Build Arguments Overview.\n"
+    "\n"
+    "  Build arguments are variables passed in from outside of the build\n"
+    "  that build files can query to determine how the build works.\n"
+    "\n"
+    "How build arguments are set:\n"
+    "\n"
+    "  First, system default arguments are set based on the current system.\n"
+    "  The built-in arguments are:\n"
+    "   - is_linux\n"
+    "   - is_mac\n"
+    "   - is_posix (set for Linux and Mac)\n"
+    "   - is_win\n"
+    "\n"
+    "  Second, arguments specified on the command-line via \"--args\" are\n"
+    "  applied. These can override the system default ones, and add new ones.\n"
+    "  These are whitespace-separated. For example:\n"
+    "\n"
+    "    gn --args=\"is_win=true enable_doom_melon=false\"\n"
+    "\n"
+    "  Third, toolchain overrides are applied. These are specified in the\n"
+    "  toolchain_args section of a toolchain definition. The use-case for\n"
+    "  this is that a toolchain may be building code for a different\n"
+    "  platform, and that it may want to always specify Posix, for example.\n"
+    "  See \"gn help toolchain_args\" for more.\n"
+    "\n"
+    "  It is an error to specify an override for a build argument that never\n"
+    "  appears in a \"declare_args\" call.\n"
+    "\n"
+    "How build arguments are used:\n"
+    "\n"
+    "  If you want to use an argument, you use declare_args() and specify\n"
+    "  default values. These default values will apply if none of the steps\n"
+    "  listed in the \"How build arguments are set\" section above apply to\n"
+    "  the given argument, but the defaults will not override any of these.\n"
+    "\n"
+    "  Often, the root build config file will declare global arguments that\n"
+    "  will be passed to all buildfiles. Individual build files can also\n"
+    "  specify arguments that apply only to those files. It is also usedful\n"
+    "  to specify build args in an \"import\"-ed file if you want such\n"
+    "  arguments to apply to multiple buildfiles.\n";
+
+Args::Args() {
+}
+
+Args::~Args() {
+}
+
+void Args::SwapInArgOverrides(Scope::KeyValueMap* overrides) {
+  DCHECK(overrides_.empty());
+  overrides_.swap(*overrides);
+  for (Scope::KeyValueMap::const_iterator i = overrides_.begin();
+       i != overrides_.end(); ++i)
+    all_overrides_.insert(*i);
+}
+
+void Args::SetupRootScope(Scope* dest,
+                          const Scope::KeyValueMap& toolchain_overrides) const {
+  SetSystemVars(dest);
+  ApplyOverrides(overrides_, dest);
+  ApplyOverrides(toolchain_overrides, dest);
+  SaveOverrideRecord(toolchain_overrides);
+}
+
+bool Args::DeclareArgs(const Scope::KeyValueMap& args,
+                       Scope* scope_to_set,
+                       Err* err) const {
+  base::AutoLock lock(lock_);
+
+  for (Scope::KeyValueMap::const_iterator i = args.begin();
+       i != args.end(); ++i) {
+    // Verify that the value hasn't already been declared. We want each value
+    // to be declared only once.
+    //
+    // The tricky part is that a buildfile can be interpreted multiple times
+    // when used from different toolchains, so we can't just check that we've
+    // seen it before. Instead, we check that the location matches. We
+    // additionally check that the value matches to prevent people from
+    // declaring defaults based on other parameters that may change. The
+    // rationale is that you should have exactly one default value for each
+    // argument that we can display in the help.
+    Scope::KeyValueMap::iterator previously_declared =
+        declared_arguments_.find(i->first);
+    if (previously_declared != declared_arguments_.end()) {
+      if (previously_declared->second.origin() != i->second.origin()) {
+        // Declaration location mismatch.
+        *err = Err(i->second.origin(), "Duplicate build arg declaration.",
+            "Here you're declaring an argument that was already declared "
+            "elsewhere.\nYou can only declare each argument once in the entire "
+            "build so there is one\ncanonical place for documentation and the "
+            "default value. Either move this\nargument to the build config "
+            "file (for visibility everywhere) or to a .gni file\nthat you "
+            "\"import\" from the files where you need it (preferred).");
+        err->AppendSubErr(Err(previously_declared->second.origin(),
+                              "Previous declaration.",
+                              "See also \"gn help buildargs\" for more on how "
+                              "build args work."));
+        return false;
+      } else if (previously_declared->second != i->second) {
+        // Default value mismatch.
+        *err = Err(i->second.origin(),
+            "Non-constant default value for build arg.",
+            "Each build arg should have one default value so we report it "
+            "nicely in the\n\"gn args\" command. Please make this value "
+            "constant.");
+        return false;
+      }
+    } else {
+      declared_arguments_.insert(*i);
+    }
+
+    // Only set on the current scope to the new value if it hasn't been already
+    // set.
+    if (!scope_to_set->GetValue(i->first))
+      scope_to_set->SetValue(i->first, i->second, i->second.origin());
+  }
+
+  return true;
+}
+
+bool Args::VerifyAllOverridesUsed(Err* err) const {
+  base::AutoLock lock(lock_);
+
+  for (Scope::KeyValueMap::const_iterator i = all_overrides_.begin();
+       i != all_overrides_.end(); ++i) {
+    if (declared_arguments_.find(i->first) == declared_arguments_.end()) {
+      *err = Err(i->second.origin(), "Build arg has no effect.",
+          "The value \"" + i->first.as_string() + "\" was set a build "
+          "argument\nbut never appeared in a declare_args() block in any "
+          "buildfile.");
+      return false;
+    }
+  }
+  return true;
+}
+
+void Args::SetSystemVars(Scope* dest) const {
+#if defined(OS_WIN)
+  Value is_win(NULL, true);
+  Value is_posix(NULL, false);
+#else
+  Value is_win(NULL, false);
+  Value is_posix(NULL, true);
+#endif
+  dest->SetValue(variables::kIsWin, is_win, NULL);
+  dest->SetValue(variables::kIsPosix, is_posix, NULL);
+  declared_arguments_[variables::kIsWin] = is_win;
+  declared_arguments_[variables::kIsPosix] = is_posix;
+
+#if defined(OS_MACOSX)
+  Value is_mac(NULL, true);
+#else
+  Value is_mac(NULL, false);
+#endif
+  dest->SetValue(variables::kIsMac, is_mac, NULL);
+  declared_arguments_[variables::kIsMac] = is_mac;
+
+#if defined(OS_LINUX)
+  Value is_linux(NULL, true);
+#else
+  Value is_linux(NULL, false);
+#endif
+  dest->SetValue(variables::kIsLinux, is_linux, NULL);
+  declared_arguments_[variables::kIsLinux] = is_linux;
+}
+
+void Args::ApplyOverrides(const Scope::KeyValueMap& values,
+                          Scope* scope) const {
+  for (Scope::KeyValueMap::const_iterator i = values.begin();
+       i != values.end(); ++i)
+    scope->SetValue(i->first, i->second, i->second.origin());
+}
+
+void Args::SaveOverrideRecord(const Scope::KeyValueMap& values) const {
+  base::AutoLock lock(lock_);
+  for (Scope::KeyValueMap::const_iterator i = values.begin();
+       i != values.end(); ++i)
+    all_overrides_[i->first] = i->second;
+}
diff --git a/tools/gn/args.h b/tools/gn/args.h
new file mode 100644
index 0000000..4d2287d
--- /dev/null
+++ b/tools/gn/args.h
@@ -0,0 +1,88 @@
+// 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 TOOLS_GN_ARGS_H_
+#define TOOLS_GN_ARGS_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/synchronization/lock.h"
+#include "tools/gn/err.h"
+#include "tools/gn/scope.h"
+
+extern const char kBuildArgs_Help[];
+
+// Manages build arguments. It stores the global arguments specified on the
+// command line, and sets up the root scope with the proper values.
+//
+// This class tracks accesses so we can report errors about unused variables.
+// The use case is if the user specifies an override on the command line, but
+// no buildfile actually uses that variable. We want to be able to report that
+// the argument was unused.
+class Args {
+ public:
+  Args();
+  ~Args();
+
+  // Specifies overrides of the build arguments. These are normally specified
+  // on the command line.
+  void SwapInArgOverrides(Scope::KeyValueMap* overrides);
+
+  // Sets up the root scope for a toolchain. This applies the default system
+  // flags, then any overrides stored in this object, then applies any
+  // toolchain overrides specified in the argument.
+  void SetupRootScope(Scope* dest,
+                      const Scope::KeyValueMap& toolchain_overrides) const;
+
+  // Sets up the given scope with arguments passed in.
+  //
+  // If the values specified in the args are not already set, the values in
+  // the args list will be used (which are assumed to be the defaults), but
+  // they will not override the system defaults or the current overrides.
+  //
+  // All args specified in the input will be marked as "used".
+  //
+  // On failure, the err will be set and it will return false.
+  bool DeclareArgs(const Scope::KeyValueMap& args,
+                   Scope* scope_to_set,
+                   Err* err) const;
+
+  // Checks to see if any of the overrides ever used were never declared as
+  // arguments. If there are, this returns false and sets the error.
+  bool VerifyAllOverridesUsed(Err* err) const;
+
+  // This function is not threadsafe, it must only be used when
+  // single-threaded. It's used to implement the "args" command.
+  const Scope::KeyValueMap& declared_arguments() const {
+    return declared_arguments_;
+  }
+
+ private:
+  // Sets the default config based on the current system.
+  void SetSystemVars(Scope* scope) const;
+
+  // Sets the given vars on the given scope.
+  void ApplyOverrides(const Scope::KeyValueMap& values, Scope* scope) const;
+
+  void SaveOverrideRecord(const Scope::KeyValueMap& values) const;
+
+  // Since this is called during setup which we assume is single-threaded,
+  // this is not protected by the lock. It should be set only during init.
+  Scope::KeyValueMap overrides_;
+
+  mutable base::Lock lock_;
+
+  // Maintains a list of all overrides we've ever seen. This is the main
+  // |overrides_| as well as toolchain overrides. Tracking this allows us to
+  // check for overrides that were specified but never used.
+  mutable Scope::KeyValueMap all_overrides_;
+
+  // Tracks all variables declared in any buildfile. This is so we can see if
+  // the user set variables on the command line that are not used anywhere.
+  mutable Scope::KeyValueMap declared_arguments_;
+
+  DISALLOW_COPY_AND_ASSIGN(Args);
+};
+
+#endif  // TOOLS_GN_ARGS_H_
diff --git a/tools/gn/binary_target_generator.cc b/tools/gn/binary_target_generator.cc
new file mode 100644
index 0000000..4638be4
--- /dev/null
+++ b/tools/gn/binary_target_generator.cc
@@ -0,0 +1,37 @@
+// 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 "tools/gn/binary_target_generator.h"
+
+#include "tools/gn/config_values_generator.h"
+#include "tools/gn/err.h"
+#include "tools/gn/scope.h"
+
+BinaryTargetGenerator::BinaryTargetGenerator(Target* target,
+                                             Scope* scope,
+                                             const Token& function_token,
+                                             Target::OutputType type,
+                                             Err* err)
+    : TargetGenerator(target, scope, function_token, err),
+      output_type_(type) {
+}
+
+BinaryTargetGenerator::~BinaryTargetGenerator() {
+}
+
+void BinaryTargetGenerator::DoRun() {
+  target_->set_output_type(output_type_);
+
+  FillSources();
+  FillConfigs();
+
+  // Config values (compiler flags, etc.) set directly on this target.
+  ConfigValuesGenerator gen(&target_->config_values(), scope_,
+                            function_token_, scope_->GetSourceDir(), err_);
+  gen.Run();
+  if (err_->has_error())
+    return;
+
+  SetToolchainDependency();
+}
diff --git a/tools/gn/binary_target_generator.h b/tools/gn/binary_target_generator.h
new file mode 100644
index 0000000..dacb497
--- /dev/null
+++ b/tools/gn/binary_target_generator.h
@@ -0,0 +1,32 @@
+// 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 TOOLS_GN_BINARY_TARGET_GENERATOR_H_
+#define TOOLS_GN_BINARY_TARGET_GENERATOR_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/target_generator.h"
+
+// Populates a Target with the values from a binary rule (executable, shared
+// library, or static library).
+class BinaryTargetGenerator : public TargetGenerator {
+ public:
+  BinaryTargetGenerator(Target* target,
+                        Scope* scope,
+                        const Token& function_token,
+                        Target::OutputType type,
+                        Err* err);
+  virtual ~BinaryTargetGenerator();
+
+ protected:
+  virtual void DoRun() OVERRIDE;
+
+ private:
+  Target::OutputType output_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(BinaryTargetGenerator);
+};
+
+#endif  // TOOLS_GN_BINARY_TARGET_GENERATOR_H_
+
diff --git a/tools/gn/build_settings.cc b/tools/gn/build_settings.cc
index 09b4c99..ebe0323 100644
--- a/tools/gn/build_settings.cc
+++ b/tools/gn/build_settings.cc
@@ -15,6 +15,11 @@
 BuildSettings::~BuildSettings() {
 }
 
+void BuildSettings::SetRootPath(const base::FilePath& r) {
+  root_path_ = r;
+  root_path_utf8_ = FilePathToUTF8(root_path_);
+}
+
 void BuildSettings::SetSecondarySourcePath(const SourceDir& d) {
   secondary_source_path_ = GetFullPath(d);
 }
diff --git a/tools/gn/build_settings.h b/tools/gn/build_settings.h
index fe04266..454eca4 100644
--- a/tools/gn/build_settings.h
+++ b/tools/gn/build_settings.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "tools/gn/args.h"
 #include "tools/gn/item_tree.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/source_dir.h"
@@ -27,7 +28,8 @@
   // Absolute path of the source root on the local system. Everything is
   // relative to this.
   const base::FilePath& root_path() const { return root_path_; }
-  void set_root_path(const base::FilePath& r) { root_path_ = r; }
+  const std::string& root_path_utf8() const { return root_path_utf8_; }
+  void SetRootPath(const base::FilePath& r);
 
   // When nonempty, specifies a parallel directory higherarchy in which to
   // search for buildfiles if they're not found in the root higherarchy. This
@@ -56,6 +58,10 @@
     return build_to_source_dir_string_;
   }
 
+  // The build args are normally specified on the command-line.
+  Args& build_args() { return build_args_; }
+  const Args& build_args() const { return build_args_; }
+
   // These accessors do not return const objects since the resulting objects
   // are threadsafe. In this setting, we use constness primarily to ensure
   // that the Settings object is used in a threadsafe manner. Although this
@@ -90,12 +96,14 @@
 
  private:
   base::FilePath root_path_;
+  std::string root_path_utf8_;
   base::FilePath secondary_source_path_;
   base::FilePath python_path_;
 
   SourceFile build_config_file_;
   SourceDir build_dir_;
   std::string build_to_source_dir_string_;
+  Args build_args_;
 
   TargetResolvedCallback target_resolved_callback_;
 
diff --git a/tools/gn/command_args.cc b/tools/gn/command_args.cc
new file mode 100644
index 0000000..c6b7cfb
--- /dev/null
+++ b/tools/gn/command_args.cc
@@ -0,0 +1,162 @@
+// 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 <map>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "tools/gn/commands.h"
+#include "tools/gn/input_file.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/setup.h"
+#include "tools/gn/standard_out.h"
+#include "tools/gn/tokenizer.h"
+
+namespace commands {
+
+namespace {
+
+bool DoesLineBeginWithComment(const base::StringPiece& line) {
+  // Skip whitespace.
+  size_t i = 0;
+  while (i < line.size() && IsAsciiWhitespace(line[i]))
+    i++;
+
+  return i < line.size() && line[i] == '#';
+}
+
+// Returns the offset of the beginning of the line identified by |offset|.
+size_t BackUpToLineBegin(const std::string& data, size_t offset) {
+  // Degenerate case of an empty line. Below we'll try to return the
+  // character after the newline, but that will be incorrect in this case.
+  if (offset == 0 || Tokenizer::IsNewline(data, offset))
+    return offset;
+
+  size_t cur = offset;
+  do {
+    cur --;
+    if (Tokenizer::IsNewline(data, cur))
+      return cur + 1;  // Want the first character *after* the newline.
+  } while (cur > 0);
+  return 0;
+}
+
+// Assumes DoesLineBeginWithComment().
+std::string StripCommentFromLine(const base::StringPiece& line) {
+  std::string ret = line.as_string();
+  for (size_t i = 0; i < ret.size(); i++) {
+    if (ret[i] == '#') {
+      ret[i] = ' ';
+      break;
+    }
+  }
+  return ret;
+}
+
+// Tries to find the comment before the setting of the given value.
+void GetContextForValue(const Value& value,
+                        std::string* location_str,
+                        std::string* comment) {
+  Location location = value.origin()->GetRange().begin();
+  const InputFile* file = location.file();
+  if (!file)
+    return;
+
+  *location_str = file->name().value() + ":" +
+      base::IntToString(location.line_number());
+
+  const std::string& data = file->contents();
+  size_t line_off =
+      Tokenizer::ByteOffsetOfNthLine(data, location.line_number());
+
+  while (line_off > 1) {
+    line_off -= 2;  // Back up to end of previous line.
+    size_t previous_line_offset = BackUpToLineBegin(data, line_off);
+
+    base::StringPiece line(&data[previous_line_offset],
+                           line_off - previous_line_offset + 1);
+    if (!DoesLineBeginWithComment(line))
+      break;
+
+    comment->insert(0, StripCommentFromLine(line) + "\n");
+    line_off = previous_line_offset;
+  }
+}
+
+void PrintArgHelp(const base::StringPiece& name, const Value& value) {
+  OutputString(name.as_string(), DECORATION_YELLOW);
+  OutputString("  Default = " + value.ToString(true) + "\n");
+
+  if (value.origin()) {
+    std::string location, comment;
+    GetContextForValue(value, &location, &comment);
+    OutputString("    " + location + "\n" + comment);
+  } else {
+    OutputString("    (Internally set)\n");
+  }
+}
+
+}  // namespace
+
+extern const char kArgs[] = "args";
+extern const char kArgs_HelpShort[] =
+    "args: Display configurable arguments declared by the build.";
+extern const char kArgs_Help[] =
+    "gn args [arg name]\n"
+    "  Displays all arguments declared by buildfiles along with their\n"
+    "  description. Build arguments are anything in a declare_args() block\n"
+    "  in any buildfile. The comment preceeding the declaration will be\n"
+    "  displayed here (so comment well!).\n"
+    "\n"
+    "  These arguments can be overriden on the command-line:\n"
+    "    --args=\"doom_melon_setting=5 component_build=1\"\n"
+    "  or in a toolchain definition (see \"gn help buildargs\" for more on\n"
+    "  how this all works).\n"
+    "\n"
+    "  If \"arg name\" is specified, only the information for that argument\n"
+    "  will be displayed. Otherwise all arguments will be displayed.\n";
+
+int RunArgs(const std::vector<std::string>& args) {
+  Setup* setup = new Setup;
+  setup->set_check_for_bad_items(false);
+  if (!setup->DoSetup() || !setup->Run())
+    return 1;
+
+  const Scope::KeyValueMap& build_args =
+      setup->build_settings().build_args().declared_arguments();
+
+  if (args.size() == 1) {
+    // Get help on a specific command.
+    Scope::KeyValueMap::const_iterator found_arg = build_args.find(args[0]);
+    if (found_arg == build_args.end()) {
+      Err(Location(), "Unknown build arg.",
+          "You asked for \"" + args[0] + "\" which I didn't find in any "
+          "buildfile\nassociated with this build.");
+      return 1;
+    }
+    PrintArgHelp(args[0], found_arg->second);
+    return 0;
+  } else if (args.size() > 1) {
+    // Too many arguments.
+    Err(Location(), "You're holding it wrong.",
+        "Usage: \"gn args [arg name]\"").PrintToStdout();
+    return 1;
+  }
+
+  // List all arguments. First put them in a regular map so they're sorted.
+  std::map<base::StringPiece, Value> sorted_args;
+  for (Scope::KeyValueMap::const_iterator i = build_args.begin();
+       i != build_args.end(); ++i)
+    sorted_args.insert(*i);
+
+  for (std::map<base::StringPiece, Value>::iterator i = sorted_args.begin();
+       i != sorted_args.end(); ++i) {
+    PrintArgHelp(i->first, i->second);
+    OutputString("\n");
+  }
+
+  return 0;
+}
+
+}  // namespace commands
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc
index dd78b84..9139d43 100644
--- a/tools/gn/command_desc.cc
+++ b/tools/gn/command_desc.cc
@@ -27,11 +27,17 @@
   }
 };
 
+void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result);
+
 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
   if (result->find(target->label()) != result->end())
     return;  // Already did this target.
   result->insert(target->label());
 
+  RecursiveCollectChildDeps(target, result);
+}
+
+void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result) {
   const std::vector<const Target*>& deps = target->deps();
   for (size_t i = 0; i < deps.size(); i++)
     RecursiveCollectDeps(deps[i], result);
@@ -78,7 +84,7 @@
       OutputString("\nAll recursive dependencies:\n");
 
     std::set<Label> all_deps;
-    RecursiveCollectDeps(target, &all_deps);
+    RecursiveCollectChildDeps(target, &all_deps);
     for (std::set<Label>::iterator i = all_deps.begin();
          i != all_deps.end(); ++i)
       deps.push_back(*i);
@@ -137,7 +143,7 @@
   ItemTree& item_tree = target->settings()->build_settings()->item_tree();
   base::AutoLock lock(item_tree.lock());
 
-  ItemNode* target_node = item_tree.GetExistingNodeLocked(target->label());
+  const ItemNode* target_node = target->item_node();
   CHECK(target_node);
   ItemNode* dep_node = item_tree.GetExistingNodeLocked(dep_label);
   CHECK(dep_node);
@@ -206,7 +212,7 @@
 
   std::string out_str = out.str();
   if (!out_str.empty()) {
-    OutputString(std::string(header_name) + "\n");
+    OutputString("\n" + std::string(header_name) + "\n");
     OutputString(out_str);
   }
 }
@@ -273,6 +279,9 @@
     "      Shows defines set for the //base:base target, annotated by where\n"
     "      each one was set from.\n";
 
+#define OUTPUT_CONFIG_VALUE(name) \
+    OutputRecursiveTargetConfig(target, #name, &ConfigValues::name);
+
 int RunDesc(const std::vector<std::string>& args) {
   if (args.size() != 1 && args.size() != 2) {
     Err(Location(), "You're holding it wrong.",
@@ -285,8 +294,7 @@
     return 1;
 
 #define CONFIG_VALUE_HANDLER(name) \
-    } else if (what == #name) { \
-      OutputRecursiveTargetConfig(target, #name, &ConfigValues::name);
+    } else if (what == #name) { OUTPUT_CONFIG_VALUE(name)
 
   if (args.size() == 2) {
     // User specified one thing to display.
@@ -303,6 +311,8 @@
     CONFIG_VALUE_HANDLER(cflags)
     CONFIG_VALUE_HANDLER(cflags_c)
     CONFIG_VALUE_HANDLER(cflags_cc)
+    CONFIG_VALUE_HANDLER(cflags_objc)
+    CONFIG_VALUE_HANDLER(cflags_objcc)
     CONFIG_VALUE_HANDLER(ldflags)
 
     } else {
@@ -322,20 +332,25 @@
   Label target_toolchain = target->label().GetToolchainLabel();
 
   // Header.
-  std::string title_target =
-      "Target: " + target->label().GetUserVisibleName(false);
-  std::string title_toolchain =
-      "Toolchain: " + target_toolchain.GetUserVisibleName(false);
-  OutputString(title_target + "\n", DECORATION_YELLOW);
-  OutputString(title_toolchain + "\n", DECORATION_YELLOW);
+  OutputString("Target: ", DECORATION_YELLOW);
+  OutputString(target->label().GetUserVisibleName(false) + "\n");
+  OutputString("Type: ", DECORATION_YELLOW);
   OutputString(std::string(
-      std::max(title_target.size(), title_toolchain.size()), '=') + "\n");
+      Target::GetStringForOutputType(target->output_type())) + "\n");
+  OutputString("Toolchain: ", DECORATION_YELLOW);
+  OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
 
   PrintSources(target, true);
   PrintConfigs(target, true);
-  OutputString("\n  (Use \"gn desc <label> <thing you want to see>\" to show "
-               "the actual values\n   applied by the different configs. "
-               "See \"gn help desc\" for more.)\n");
+
+  OUTPUT_CONFIG_VALUE(defines)
+  OUTPUT_CONFIG_VALUE(includes)
+  OUTPUT_CONFIG_VALUE(cflags)
+  OUTPUT_CONFIG_VALUE(cflags_c)
+  OUTPUT_CONFIG_VALUE(cflags_cc)
+  OUTPUT_CONFIG_VALUE(cflags_objc)
+  OUTPUT_CONFIG_VALUE(cflags_objcc)
+
   PrintDeps(target, true);
 
   return 0;
diff --git a/tools/gn/command_help.cc b/tools/gn/command_help.cc
index 2abef9f..de27882 100644
--- a/tools/gn/command_help.cc
+++ b/tools/gn/command_help.cc
@@ -5,10 +5,12 @@
 #include <algorithm>
 #include <iostream>
 
+#include "tools/gn/args.h"
 #include "tools/gn/commands.h"
 #include "tools/gn/err.h"
 #include "tools/gn/functions.h"
 #include "tools/gn/input_conversion.h"
+#include "tools/gn/pattern.h"
 #include "tools/gn/setup.h"
 #include "tools/gn/standard_out.h"
 #include "tools/gn/variables.h"
@@ -43,6 +45,7 @@
       "  When run with no arguments \"gn gen\" is assumed.\n"
       "\n"
       "Common switches:\n"
+      "  --args: Specifies build args overrides. See \"gn help buildargs\".\n"
       "  -q: Quiet mode, don't print anything on success.\n"
       "  --root: Specifies source root (overrides .gn file).\n"
       "  --secondary: Specifies secondary source root (overrides .gn file).\n"
@@ -79,9 +82,11 @@
     PrintShortHelp(i->second.help_short);
 
   OutputString("\nOther help topics:\n");
+  PrintShortHelp("buildargs: How build arguments work.");
   PrintShortHelp("dotfile: Info about the toplevel .gn file.");
   PrintShortHelp(
       "input_conversion: Processing input from exec_script and read_file.");
+  PrintShortHelp("patterns: How to use patterns.");
 }
 
 }  // namespace
@@ -139,11 +144,20 @@
   }
 
   // Random other topics.
+  if (args[0] == "buildargs") {
+    OutputString(kBuildArgs_Help);
+    return 0;
+  }
+  if (args[0] == "dotfile") {
+    OutputString(kDotfile_Help);
+    return 0;
+  }
   if (args[0] == "input_conversion") {
     OutputString(kInputConversion_Help);
     return 0;
-  } if (args[0] == "dotfile") {
-    OutputString(kDotfile_Help);
+  }
+  if (args[0] == "patterns") {
+    OutputString(kPattern_Help);
     return 0;
   }
 
diff --git a/tools/gn/command_refs.cc b/tools/gn/command_refs.cc
new file mode 100644
index 0000000..d49f536
--- /dev/null
+++ b/tools/gn/command_refs.cc
@@ -0,0 +1,130 @@
+// 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 <set>
+
+#include "base/command_line.h"
+#include "tools/gn/commands.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/input_file.h"
+#include "tools/gn/item.h"
+#include "tools/gn/item_node.h"
+#include "tools/gn/pattern.h"
+#include "tools/gn/setup.h"
+#include "tools/gn/standard_out.h"
+#include "tools/gn/target.h"
+
+namespace commands {
+
+namespace {
+
+// Returns the file path generating this item node.
+base::FilePath FilePathForItemNode(const ItemNode& node) {
+  const InputFile* file = node.generated_from_here().begin().file();
+  if (!file)
+    return base::FilePath(FILE_PATH_LITERAL("=UNRESOLVED DEPENDENCY="));
+  return file->physical_name();
+}
+
+}  // namespace
+
+const char kRefs[] = "refs";
+const char kRefs_HelpShort[] =
+    "refs: Find stuff referencing a target, directory, or config.";
+const char kRefs_Help[] =
+    "gn refs <label_pattern> [--files]\n"
+    "  Finds code referencing a given label. The label can be a\n"
+    "  target or config name. Unlike most other commands, unresolved\n"
+    "  dependencies will be tolerated. This allows you to use this command\n"
+    "  to find references to targets you're in the process of moving.\n"
+    "\n"
+    "  By default, the mapping from source item to dest item (where the\n"
+    "  pattern matches the dest item). See \"gn help pattern\" for\n"
+    "  information on pattern-matching rules.\n"
+    "\n"
+    "Option:\n"
+    "  --files\n"
+    "      Output unique filenames referencing a matched target or config.\n"
+    "\n"
+    "Examples:\n"
+    "  gn refs \"//tools/gn/*\"\n"
+    "      Find all targets depending on any target or config in the\n"
+    "      \"tools/gn\" directory.\n"
+    "\n"
+    "  gn refs //tools/gn:gn\n"
+    "      Find all targets depending on the given exact target name.\n"
+    "\n"
+    "  gn refs \"*gtk*\" --files\n"
+    "      Find all unique buildfiles with a dependency on a target that has\n"
+    "      the substring \"gtk\" in the name.\n";
+
+int RunRefs(const std::vector<std::string>& args) {
+  if (args.size() != 1 && args.size() != 2) {
+    Err(Location(), "You're holding it wrong.",
+        "Usage: \"gn refs <label_pattern>\"").PrintToStdout();
+    return 1;
+  }
+
+  // Check for common errors on input.
+  if (args[0].find('*') == std::string::npos) {
+    // We need to begin with a "//" and have a colon if there's no "*" or it
+    // will be impossible to match anything.
+    if (args[0].size() < 2 ||
+        (args[0][0] != '/' && args[0][1] != '/') ||
+        args[0].find(':') == std::string::npos) {
+      Err(Location(), "Patterns match the entire label. Since your pattern "
+          "has no wildcard, it\nshould start with a \"//\" and have a colon "
+          "or it can never match anything.\nTo match a substring, use "
+          "\"*foo*\".").PrintToStdout();
+      return 1;
+    }
+  }
+
+  Pattern pattern(args[0]);
+
+  Setup* setup = new Setup;
+  setup->set_check_for_bad_items(false);
+  if (!setup->DoSetup() || !setup->Run())
+    return 1;
+
+  const ItemTree& item_tree = setup->build_settings().item_tree();
+  base::AutoLock lock(item_tree.lock());
+
+  std::vector<const ItemNode*> nodes;
+  item_tree.GetAllItemNodesLocked(&nodes);
+
+  const CommandLine* cmdline = CommandLine::ForCurrentProcess();
+
+  bool file_output = cmdline->HasSwitch("files");
+  std::set<std::string> unique_output;
+
+  for (size_t node_index = 0; node_index < nodes.size(); node_index++) {
+    const ItemNode& node = *nodes[node_index];
+    const ItemNode::ItemNodeMap& deps = node.direct_dependencies();
+    for (ItemNode::ItemNodeMap::const_iterator d = deps.begin();
+         d != deps.end(); ++d) {
+      std::string label = d->first->item()->label().GetUserVisibleName(false);
+      if (pattern.MatchesString(label)) {
+        // Got a match.
+        if (file_output) {
+          unique_output.insert(FilePathToUTF8(FilePathForItemNode(node)));
+          break;  // Found a match for this target's file, don't need more.
+        } else {
+          // We can get dupes when there are differnet toolchains involved,
+          // so we want to send all output through the de-duper.
+          unique_output.insert(
+              node.item()->label().GetUserVisibleName(false) + " -> " + label);
+        }
+      }
+    }
+  }
+
+  for (std::set<std::string>::iterator i = unique_output.begin();
+       i != unique_output.end(); ++i)
+    OutputString(*i + "\n");
+
+  return 0;
+}
+
+}  // namespace commands
diff --git a/tools/gn/commands.cc b/tools/gn/commands.cc
index cfa55cb..c632cce 100644
--- a/tools/gn/commands.cc
+++ b/tools/gn/commands.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "tools/gn/commands.h"
-
 #include "tools/gn/item.h"
 #include "tools/gn/item_node.h"
 #include "tools/gn/label.h"
@@ -35,9 +34,11 @@
                                        k##cmd##_Help, \
                                        &Run##cmd);
 
+    INSERT_COMMAND(Args)
     INSERT_COMMAND(Desc)
     INSERT_COMMAND(Gen)
     INSERT_COMMAND(Help)
+    INSERT_COMMAND(Refs)
 
     #undef INSERT_COMMAND
   }
@@ -64,7 +65,8 @@
       .GetDefaultToolchainUnlocked();
   Value arg_value(NULL, args[0]);
   Err err;
-  Label label = Label::Resolve(SourceDir(), default_toolchain, arg_value, &err);
+  Label label =
+      Label::Resolve(SourceDir("//"), default_toolchain, arg_value, &err);
   if (err.has_error()) {
     err.PrintToStdout();
     return NULL;
diff --git a/tools/gn/commands.h b/tools/gn/commands.h
index 1a30389..1900820 100644
--- a/tools/gn/commands.h
+++ b/tools/gn/commands.h
@@ -19,6 +19,11 @@
 
 typedef int (*CommandRunner)(const std::vector<std::string>&);
 
+extern const char kArgs[];
+extern const char kArgs_HelpShort[];
+extern const char kArgs_Help[];
+int RunArgs(const std::vector<std::string>& args);
+
 extern const char kDesc[];
 extern const char kDesc_HelpShort[];
 extern const char kDesc_Help[];
@@ -34,6 +39,11 @@
 extern const char kHelp_Help[];
 int RunHelp(const std::vector<std::string>& args);
 
+extern const char kRefs[];
+extern const char kRefs_HelpShort[];
+extern const char kRefs_Help[];
+int RunRefs(const std::vector<std::string>& args);
+
 // -----------------------------------------------------------------------------
 
 struct CommandInfo {
diff --git a/tools/gn/config.cc b/tools/gn/config.cc
index 6edba24..dbe4472 100644
--- a/tools/gn/config.cc
+++ b/tools/gn/config.cc
@@ -72,7 +72,7 @@
   // Keep a record of the guy asking us for this dependency. We know if
   // somebody is adding a dependency, that guy it himself not resolved.
   if (dep_from) {
-    if (!tree->GetExistingNodeLocked(dep_from->label())->AddDependency(
+    if (!dep_from->item_node()->AddDependency(
             settings->build_settings(), specified_from_here, node, err))
       return NULL;
   }
diff --git a/tools/gn/config_values_extractors.cc b/tools/gn/config_values_extractors.cc
index 96b514a..646e2d7 100644
--- a/tools/gn/config_values_extractors.cc
+++ b/tools/gn/config_values_extractors.cc
@@ -4,12 +4,23 @@
 
 #include "tools/gn/config_values_extractors.h"
 
+#include "tools/gn/escape.h"
+
 namespace {
 
-struct StringWriter {
-  void operator()(const std::string& s, std::ostream& out) const {
-    out << " " << s;
+class EscapedStringWriter {
+ public:
+  EscapedStringWriter(const EscapeOptions& escape_options)
+      : escape_options_(escape_options) {
   }
+
+  void operator()(const std::string& s, std::ostream& out) const {
+    out << " ";
+    EscapeStringToStream(out, s, escape_options_);
+  }
+
+ private:
+  const EscapeOptions& escape_options_;
 };
 
 }  // namespace
@@ -17,6 +28,8 @@
 void RecursiveTargetConfigStringsToStream(
     const Target* target,
     const std::vector<std::string>& (ConfigValues::* getter)() const,
+    const EscapeOptions& escape_options,
     std::ostream& out) {
-  RecursiveTargetConfigToStream(target, getter, StringWriter(), out);
+  RecursiveTargetConfigToStream(target, getter,
+                                EscapedStringWriter(escape_options), out);
 }
diff --git a/tools/gn/config_values_extractors.h b/tools/gn/config_values_extractors.h
index 4698f8c..1b3e52c 100644
--- a/tools/gn/config_values_extractors.h
+++ b/tools/gn/config_values_extractors.h
@@ -13,6 +13,8 @@
 #include "tools/gn/config_values.h"
 #include "tools/gn/target.h"
 
+struct EscapeOptions;
+
 template<typename T, class Writer>
 inline void ConfigValuesToStream(
     const ConfigValues& values,
@@ -50,6 +52,7 @@
 void RecursiveTargetConfigStringsToStream(
     const Target* target,
     const std::vector<std::string>& (ConfigValues::* getter)() const,
+    const EscapeOptions& escape_options,
     std::ostream& out);
 
 #endif  // TOOLS_GN_CONFIG_VALUES_EXTRACTORS_H_
diff --git a/tools/gn/config_values_generator.cc b/tools/gn/config_values_generator.cc
index 46c9e88..c6b68ca 100644
--- a/tools/gn/config_values_generator.cc
+++ b/tools/gn/config_values_generator.cc
@@ -6,6 +6,7 @@
 
 #include "tools/gn/config_values.h"
 #include "tools/gn/scope.h"
+#include "tools/gn/settings.h"
 #include "tools/gn/value.h"
 #include "tools/gn/value_extractors.h"
 
@@ -67,7 +68,8 @@
     return;  // No value, empty input and succeed.
 
   std::vector<SourceDir> includes;
-  if (!ExtractListOfRelativeDirs(*value, input_dir_, &includes, err_))
+  if (!ExtractListOfRelativeDirs(scope_->settings()->build_settings(),
+                                 *value, input_dir_, &includes, err_))
     return;
   config_values_->swap_in_includes(&includes);
 }
diff --git a/tools/gn/copy_target_generator.cc b/tools/gn/copy_target_generator.cc
new file mode 100644
index 0000000..6347ca2
--- /dev/null
+++ b/tools/gn/copy_target_generator.cc
@@ -0,0 +1,47 @@
+// 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 "tools/gn/copy_target_generator.h"
+
+#include "tools/gn/build_settings.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/scope.h"
+#include "tools/gn/value.h"
+
+CopyTargetGenerator::CopyTargetGenerator(Target* target,
+                                         Scope* scope,
+                                         const Token& function_token,
+                                         Err* err)
+    : TargetGenerator(target, scope, function_token, err) {
+}
+
+CopyTargetGenerator::~CopyTargetGenerator() {
+}
+
+void CopyTargetGenerator::DoRun() {
+  target_->set_output_type(Target::COPY_FILES);
+
+  FillSources();
+  FillDestDir();
+
+  SetToolchainDependency();
+}
+
+void CopyTargetGenerator::FillDestDir() {
+  // Destdir is required for all targets that use it.
+  const Value* value = scope_->GetValue("destdir", true);
+  if (!value) {
+    *err_ = Err(function_token_, "This target type requires a \"destdir\".");
+    return;
+  }
+  if (!value->VerifyTypeIs(Value::STRING, err_))
+    return;
+
+  if (!EnsureStringIsInOutputDir(
+          GetBuildSettings()->build_dir(),
+          value->string_value(), *value, err_))
+    return;
+  target_->set_destdir(SourceDir(value->string_value()));
+}
+
diff --git a/tools/gn/copy_target_generator.h b/tools/gn/copy_target_generator.h
new file mode 100644
index 0000000..b6f7e14
--- /dev/null
+++ b/tools/gn/copy_target_generator.h
@@ -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.
+
+#ifndef TOOLS_GN_COPY_TARGET_GENERATOR_H_
+#define TOOLS_GN_COPY_TARGET_GENERATOR_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/target_generator.h"
+
+// Populates a Target with the values from a copy rule.
+class CopyTargetGenerator : public TargetGenerator {
+ public:
+  CopyTargetGenerator(Target* target,
+                      Scope* scope,
+                      const Token& function_token,
+                      Err* err);
+  virtual ~CopyTargetGenerator();
+
+ protected:
+  virtual void DoRun() OVERRIDE;
+
+ private:
+  void FillDestDir();
+
+  DISALLOW_COPY_AND_ASSIGN(CopyTargetGenerator);
+};
+
+#endif  // TOOLS_GN_COPY_TARGET_GENERATOR_H_
+
diff --git a/tools/gn/err.cc b/tools/gn/err.cc
index 068ea6d..326f5b3 100644
--- a/tools/gn/err.cc
+++ b/tools/gn/err.cc
@@ -163,14 +163,17 @@
   const InputFile* input_file = location_.file();
   std::string loc_str;
   if (input_file) {
-    std::string path8;
-    path8.assign(input_file->name().value());
+    std::string name;
+    if (input_file->friendly_name().empty())
+      name = input_file->name().value();
+    else
+      name = input_file->friendly_name();
 
     if (is_sub_err)
       loc_str = "See ";
     else
       loc_str = "at ";
-    loc_str += path8 + ": " +
+    loc_str += name + ": " +
         base::IntToString(location_.line_number()) + ":" +
         base::IntToString(location_.char_offset()) + ": ";
   }
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index a108959..dfaa303 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -86,14 +86,18 @@
     case Settings::WIN:
       if (extension == "rc")
         return SOURCE_RC;
+      // TODO(brettw) asm files.
       break;
 
     default:
       break;
   }
 
-  // TODO(brettw) asm files.
-  // TODO(brettw) weird thing with .S on non-Windows platforms.
+  if (os != Settings::WIN) {
+    if (extension == "S")
+      return SOURCE_S;
+  }
+
   return SOURCE_UNKNOWN;
 }
 
@@ -102,17 +106,12 @@
   switch (os) {
     case Settings::MAC:
       switch (type) {
-        case Target::NONE:
-          NOTREACHED();
-          return "";
         case Target::EXECUTABLE:
           return "";
         case Target::SHARED_LIBRARY:
           return "dylib";
         case Target::STATIC_LIBRARY:
           return "a";
-        case Target::LOADABLE_MODULE:
-          return "dylib";  // TODO(brettw) what's this?
         default:
           NOTREACHED();
       }
@@ -120,17 +119,25 @@
 
     case Settings::WIN:
       switch (type) {
-        case Target::NONE:
-          NOTREACHED();
-          return "";
         case Target::EXECUTABLE:
           return "exe";
         case Target::SHARED_LIBRARY:
           return "dll.lib";  // Extension of import library.
         case Target::STATIC_LIBRARY:
           return "lib";
-        case Target::LOADABLE_MODULE:
-          return "dll";  // TODO(brettw) what's this?
+        default:
+          NOTREACHED();
+      }
+      break;
+
+    case Settings::LINUX:
+      switch (type) {
+        case Target::EXECUTABLE:
+          return "";
+        case Target::SHARED_LIBRARY:
+          return "so";
+        case Target::STATIC_LIBRARY:
+          return "a";
         default:
           NOTREACHED();
       }
@@ -244,6 +251,62 @@
   return true;
 }
 
+bool IsPathAbsolute(const base::StringPiece& path) {
+  if (path.empty())
+    return false;
+
+  if (path[0] != '/') {
+#if defined(OS_WIN)
+    // Check for Windows system paths like "C:\foo".
+    if (path.size() > 2 &&
+        path[1] == ':' && (path[2] == '/' || path[2] == '\\'))
+      return true;
+#endif
+    return false;  // Doesn't begin with a slash, is relative.
+  }
+
+  if (path.size() > 1 && path[1] == '/')
+    return false;  // Double slash at the beginning means source-relative.
+
+  return true;
+}
+
+bool MakeAbsolutePathRelativeIfPossible(const base::StringPiece& source_root,
+                                        const base::StringPiece& path,
+                                        std::string* dest) {
+  DCHECK(IsPathAbsolute(source_root));
+  DCHECK(IsPathAbsolute(path));
+
+  dest->clear();
+
+  if (source_root.size() > path.size())
+    return false;  // The source root is longer: the path can never be inside.
+
+#if defined(OS_WIN)
+  // Source root should be canonical on Windows.
+  DCHECK(source_root.size() > 2 && source_root[0] != '/' &&
+         source_root[1] == ':' && source_root[2] =='\\');
+#error
+#else
+  // On non-Windows this is easy. Since we know both are absolute, just do a
+  // prefix check.
+  if (path.substr(0, source_root.size()) == source_root) {
+    dest->assign("//");  // Result is source root relative.
+
+    // The base may or may not have a trailing slash, so skip all slashes from
+    // the path after our prefix match.
+    size_t first_after_slash = source_root.size();
+    while (first_after_slash < path.size() && path[first_after_slash] == '/')
+      first_after_slash++;
+
+    dest->append(&path.data()[first_after_slash],
+                 path.size() - first_after_slash);
+    return true;
+  }
+#endif
+  return false;
+}
+
 std::string InvertDir(const SourceDir& path) {
   const std::string value = path.value();
   if (value.empty())
diff --git a/tools/gn/filesystem_utils.h b/tools/gn/filesystem_utils.h
index 19139f8..4ab4ec5 100644
--- a/tools/gn/filesystem_utils.h
+++ b/tools/gn/filesystem_utils.h
@@ -24,7 +24,7 @@
   SOURCE_H,
   SOURCE_M,
   SOURCE_MM,
-  //SOURCE_S,  // TODO(brettw) what is this?
+  SOURCE_S,
   SOURCE_RC,
 };
 
@@ -99,6 +99,22 @@
 
 // ----------------------------------------------------------------------------
 
+// Returns true if the input string is absolute. Double-slashes at the
+// beginning are treated as source-relative paths. On Windows, this handles
+// paths of both the native format: "C:/foo" and ours "/C:/foo"
+bool IsPathAbsolute(const base::StringPiece& path);
+
+// Given an absolute path, checks to see if is it is inside the source root.
+// If it is, fills a source-absolute path into the given output and returns
+// true. If it isn't, clears the dest and returns false.
+//
+// The source_root should be a base::FilePath converted to UTF-8. On Windows,
+// it should begin with a "C:/" rather than being our SourceFile's style
+// ("/C:/"). The source root can end with a slash or not.
+bool MakeAbsolutePathRelativeIfPossible(const base::StringPiece& source_root,
+                                        const base::StringPiece& path,
+                                        std::string* dest);
+
 // Converts a directory to its inverse (e.g. "/foo/bar/" -> "../../").
 // This will be the empty string for the root directories ("/" and "//"), and
 // in all other cases, this is guaranteed to end in a slash.
diff --git a/tools/gn/filesystem_utils_unittest.cc b/tools/gn/filesystem_utils_unittest.cc
index 75bf7cd..27e65e2 100644
--- a/tools/gn/filesystem_utils_unittest.cc
+++ b/tools/gn/filesystem_utils_unittest.cc
@@ -73,6 +73,43 @@
   EXPECT_EQ("foo/bar/", FindDir(&input));
 }
 
+TEST(FilesystemUtils, IsPathAbsolute) {
+  EXPECT_TRUE(IsPathAbsolute("/foo/bar"));
+  EXPECT_TRUE(IsPathAbsolute("/"));
+  EXPECT_FALSE(IsPathAbsolute(""));
+  EXPECT_FALSE(IsPathAbsolute("//"));
+  EXPECT_FALSE(IsPathAbsolute("//foo/bar"));
+
+#if defined(OS_WIN)
+  EXPECT_TRUE(IsPathAbsolute("C:/foo"));
+  EXPECT_TRUE(IsPathAbsolute("C:/"));
+  EXPECT_TRUE(IsPathAbsolute("C:\\foo"));
+  EXPECT_TRUE(IsPathAbsolute("C:\\"));
+  EXPECT_TRUE(IsPathAbsolute("/C:/foo"));
+  EXPECT_TRUE(IsPathAbsolute("/C:\\foo"));
+#endif
+}
+
+TEST(FilesystemUtils, MakeAbsolutePathRelativeIfPossible) {
+  std::string dest;
+
+  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo/", &dest));
+  EXPECT_EQ("//foo/", dest);
+  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base", "/base/foo", &dest));
+  EXPECT_EQ("//foo", dest);
+  EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("/base/", "/base/foo/",
+                                                 &dest));
+  EXPECT_EQ("//foo/", dest);
+
+  EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("/base", "/ba", &dest));
+  EXPECT_FALSE(MakeAbsolutePathRelativeIfPossible("/base", "/notbase/foo",
+                                                  &dest));
+
+#if defined(OS_WIN)
+  //EXPECT_TRUE(MakeAbsolutePathRelativeIfPossible("
+#endif
+}
+
 TEST(FilesystemUtils, InvertDir) {
   EXPECT_TRUE(InvertDir(SourceDir()) == "");
   EXPECT_TRUE(InvertDir(SourceDir("/")) == "");
diff --git a/tools/gn/function_exec_script.cc b/tools/gn/function_exec_script.cc
index 89454e3..34c5e96 100644
--- a/tools/gn/function_exec_script.cc
+++ b/tools/gn/function_exec_script.cc
@@ -4,7 +4,11 @@
 
 #include "base/command_line.h"
 #include "base/file_util.h"
+#include "base/logging.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 #include "tools/gn/err.h"
 #include "tools/gn/filesystem_utils.h"
@@ -22,6 +26,13 @@
 #include "base/win/scoped_process_information.h"
 #endif
 
+#if defined(OS_POSIX)
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/posix/file_descriptor_shuffle.h"
+#endif
+
 namespace functions {
 
 namespace {
@@ -128,7 +139,91 @@
                  std::string* std_out,
                  std::string* std_err,
                  int* exit_code) {
-  //NOTREACHED() << "Implement me.";
+  *exit_code = EXIT_FAILURE;
+
+  std::vector<std::string> argv = cmdline.argv();
+
+  int pipe_fd[2];
+  pid_t pid;
+  base::InjectiveMultimap fd_shuffle1, fd_shuffle2;
+  scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]);
+
+  fd_shuffle1.reserve(3);
+  fd_shuffle2.reserve(3);
+
+  if (pipe(pipe_fd) < 0)
+    return false;
+
+  switch (pid = fork()) {
+    case -1:  // error
+      close(pipe_fd[0]);
+      close(pipe_fd[1]);
+      return false;
+    case 0:  // child
+      {
+#if defined(OS_MACOSX)
+        base::RestoreDefaultExceptionHandler();
+#endif
+        // DANGER: no calls to malloc are allowed from now on:
+        // http://crbug.com/36678
+
+        // Obscure fork() rule: in the child, if you don't end up doing exec*(),
+        // you call _exit() instead of exit(). This is because _exit() does not
+        // call any previously-registered (in the parent) exit handlers, which
+        // might do things like block waiting for threads that don't even exist
+        // in the child.
+        int dev_null = open("/dev/null", O_WRONLY);
+        if (dev_null < 0)
+          _exit(127);
+
+        fd_shuffle1.push_back(
+            base::InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
+        fd_shuffle1.push_back(
+            base::InjectionArc(dev_null, STDERR_FILENO, true));
+        fd_shuffle1.push_back(
+            base::InjectionArc(dev_null, STDIN_FILENO, true));
+        // Adding another element here? Remeber to increase the argument to
+        // reserve(), above.
+
+        std::copy(fd_shuffle1.begin(), fd_shuffle1.end(),
+                  std::back_inserter(fd_shuffle2));
+
+        if (!ShuffleFileDescriptors(&fd_shuffle1))
+          _exit(127);
+
+        file_util::SetCurrentDirectory(startup_dir);
+
+        // TODO(brettw) the base version GetAppOutput does a
+        // CloseSuperfluousFds call here. Do we need this?
+
+        for (size_t i = 0; i < argv.size(); i++)
+          argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+        argv_cstr[argv.size()] = NULL;
+        execvp(argv_cstr[0], argv_cstr.get());
+        _exit(127);
+      }
+    default:  // parent
+      {
+        // Close our writing end of pipe now. Otherwise later read would not
+        // be able to detect end of child's output (in theory we could still
+        // write to the pipe).
+        close(pipe_fd[1]);
+
+        char buffer[256];
+        ssize_t bytes_read = 0;
+
+        while (true) {
+          bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer)));
+          if (bytes_read <= 0)
+            break;
+          std_out->append(buffer, bytes_read);
+        }
+        close(pipe_fd[0]);
+
+        return base::WaitForExitCode(pid, exit_code);
+      }
+  }
+
   return false;
 }
 #endif
@@ -184,7 +279,7 @@
 
   const Settings* settings = scope->settings();
   const BuildSettings* build_settings = settings->build_settings();
-  const SourceDir& cur_dir = SourceDirForFunctionCall(function);
+  const SourceDir& cur_dir = scope->GetSourceDir();
 
   // Find the python script to run.
   if (!args[0].VerifyTypeIs(Value::STRING, err))
@@ -200,7 +295,7 @@
 
   // Add all dependencies of this script, including the script itself, to the
   // build deps.
-  g_scheduler->AddGenDependency(script_source);
+  g_scheduler->AddGenDependency(script_path);
   if (args.size() == 4) {
     const Value& deps_value = args[3];
     if (!deps_value.VerifyTypeIs(Value::LIST, err))
@@ -209,8 +304,9 @@
     for (size_t i = 0; i < deps_value.list_value().size(); i++) {
       if (!deps_value.list_value()[0].VerifyTypeIs(Value::STRING, err))
         return Value();
-      g_scheduler->AddGenDependency(cur_dir.ResolveRelativeFile(
-          deps_value.list_value()[0].string_value()));
+      g_scheduler->AddGenDependency(
+          build_settings->GetFullPath(cur_dir.ResolveRelativeFile(
+              deps_value.list_value()[0].string_value())));
     }
   }
 
@@ -228,6 +324,17 @@
     cmdline.AppendArg(script_args.list_value()[i].string_value());
   }
 
+  // Log command line for debugging help.
+  base::TimeTicks begin_exec;
+  if (g_scheduler->verbose_logging()) {
+#if defined(OS_WIN)
+    g_scheduler->Log("Pythoning", UTF16ToUTF8(cmdline.GetCommandLineString()));
+#else
+    g_scheduler->Log("Pythoning", cmdline.GetCommandLineString());
+#endif
+    begin_exec = base::TimeTicks::Now();
+  }
+
   // Execute the process.
   // TODO(brettw) set the environment block.
   std::string output;
@@ -239,6 +346,12 @@
         "I was trying to execute \"" + FilePathToUTF8(python_path) + "\".");
     return Value();
   }
+  if (g_scheduler->verbose_logging()) {
+    g_scheduler->Log("Pythoning", script_source.value() + " took " +
+        base::Int64ToString(
+            (base::TimeTicks::Now() - begin_exec).InMilliseconds()) +
+        "ms");
+  }
 
   // TODO(brettw) maybe we need stderr also for reasonable stack dumps.
   if (exit_code != 0) {
diff --git a/tools/gn/function_read_file.cc b/tools/gn/function_read_file.cc
index f64ede9..af8bdb1 100644
--- a/tools/gn/function_read_file.cc
+++ b/tools/gn/function_read_file.cc
@@ -50,13 +50,13 @@
     return Value();
 
   // Compute the file name.
-  const SourceDir& cur_dir = SourceDirForFunctionCall(function);
+  const SourceDir& cur_dir = scope->GetSourceDir();
   SourceFile source_file = cur_dir.ResolveRelativeFile(args[0].string_value());
   base::FilePath file_path =
       scope->settings()->build_settings()->GetFullPath(source_file);
 
   // Ensure that everything is recomputed if the read file changes.
-  g_scheduler->AddGenDependency(source_file);
+  g_scheduler->AddGenDependency(file_path);
 
   // Read contents.
   std::string file_contents;
diff --git a/tools/gn/function_set_default_toolchain.cc b/tools/gn/function_set_default_toolchain.cc
index f6ece07..c2b20a5 100644
--- a/tools/gn/function_set_default_toolchain.cc
+++ b/tools/gn/function_set_default_toolchain.cc
@@ -56,7 +56,7 @@
   if (!scope->IsProcessingDefaultBuildConfig())
     return Value();
 
-  const SourceDir& current_dir = SourceDirForFunctionCall(function);
+  const SourceDir& current_dir = scope->GetSourceDir();
   const Label& default_toolchain = ToolchainLabelForScope(scope);
 
   if (!EnsureSingleStringArg(function, args, err))
diff --git a/tools/gn/function_set_defaults.cc b/tools/gn/function_set_defaults.cc
new file mode 100644
index 0000000..45c6fc5
--- /dev/null
+++ b/tools/gn/function_set_defaults.cc
@@ -0,0 +1,89 @@
+// 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 "tools/gn/err.h"
+#include "tools/gn/functions.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/scope.h"
+
+namespace functions {
+
+const char kSetDefaults[] = "set_defaults";
+const char kSetDefaults_Help[] =
+    "set_defaults: Set default values for a target type.\n"
+    "\n"
+    "  set_defaults(<target_type_name>) { <values...> }\n"
+    "\n"
+    "  Sets the default values for a given target type. Whenever\n"
+    "  target_type_name is seen in the future, the values specified in\n"
+    "  set_default's block will be copied into the current scope.\n"
+    "\n"
+    "  When the target type is used, the variable copying is very strict.\n"
+    "  If a variable with that name is already in scope, the build will fail\n"
+    "  with an error.\n"
+    "\n"
+    "  set_defaults can be used for built-in target types (\"executable\",\n"
+    "  \"shared_library\", etc.) and custom ones defined via the \"template\"\n"
+    "  command.\n"
+    "\n"
+    "Example:\n"
+    "  set_defaults(\"static_library\") {\n"
+    "    configs = [ \"//tools/mything:settings\" ]\n"
+    "  }\n"
+    "\n"
+    "  static_library(\"mylib\")\n"
+    "    # The configs will be auto-populated as above. You can remove it if\n"
+    "    # you don't want the default for a particular default:\n"
+    "    configs -= \"//tools/mything:setgings\"\n"
+    "  }\n";
+
+Value RunSetDefaults(Scope* scope,
+                     const FunctionCallNode* function,
+                     const std::vector<Value>& args,
+                     BlockNode* block,
+                     Err* err) {
+  if (!EnsureSingleStringArg(function, args, err))
+    return Value();
+  const std::string& target_type(args[0].string_value());
+
+  // Ensure there aren't defaults already set.
+  //
+  // It might be nice to allow multiple calls set mutate the defaults. The
+  // main case for this is where some local portions of the code want
+  // additional defaults they specify in an imported file.
+  //
+  // Currently, we don't allow imports to clobber anything, so this wouldn't
+  // work. Additionally, allowing this would be undesirable since we don't
+  // want multiple imports to each try to set defaults, since it might look
+  // like the defaults are modified by each one in sequence, while in fact
+  // imports would always clobber previous values and it would be confusing.
+  //
+  // If we wanted this, the solution would be to allow imports to overwrite
+  // target defaults set up by the default build config only. That way there
+  // are no ordering issues, but this would be more work.
+  if (scope->GetTargetDefaults(target_type)) {
+    *err = Err(function->function(),
+               "This target type defaults were already set.");
+    return Value();
+  }
+
+  if (!block) {
+    FillNeedsBlockError(function, err);
+    return Value();
+  }
+
+  // Run the block for the rule invocation.
+  Scope block_scope(scope);
+  block->ExecuteBlockInScope(&block_scope, err);
+  if (err->has_error())
+    return Value();
+
+  // Now copy the values set on the scope we made into the free-floating one
+  // (with no containing scope) used to hold the target defaults.
+  Scope* dest = scope->MakeTargetDefaults(target_type);
+  block_scope.NonRecursiveMergeTo(dest, function, "<SHOULD NOT FAIL>", err);
+  return Value();
+}
+
+}  // namespace functions
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index f8b9094..7b4458e 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -51,7 +51,7 @@
   // Note that we don't want to use MakeLabelForScope since that will include
   // the toolchain name in the label, and toolchain labels don't themselves
   // have toolchain names.
-  const SourceDir& input_dir = SourceDirForFunctionCall(function);
+  const SourceDir& input_dir = scope->GetSourceDir();
   Label label(input_dir, args[0].string_value(), SourceDir(), std::string());
   if (g_scheduler->verbose_logging())
     g_scheduler->Log("Generating toolchain", label.GetUserVisibleName(false));
@@ -140,4 +140,74 @@
   return Value();
 }
 
+// toolchain_args --------------------------------------------------------------
+
+extern const char kToolchainArgs[] = "toolchain_args";
+extern const char kToolchainArgs_Help[] =
+    "toolchain_args: Set build arguments for toolchain build setup.\n"
+    "\n"
+    "  When you specify a target using an alternate toolchain, the master\n"
+    "  build configuration file is re-interpreted in the context of that\n"
+    "  toolchain. This function allows you to control the arguments passed\n"
+    "  into this alternate invocation of the build.\n"
+    "\n"
+    "  Any default system arguments or arguments passed in on the command-\n"
+    "  line will also be passed to the alternate invocation unless explicitly\n"
+    "  overriddey by toolchain_args.\n"
+    "\n"
+    "  The toolchain_args will be ignored when the toolchain being defined\n"
+    "  is the default. In this case, it's expected you want the default\n"
+    "  argument values.\n"
+    "\n"
+    "  See also \"gn help buildargs\" for an overview of these arguments.\n"
+    "\n"
+    "Example:\n"
+    "  toolchain(\"my_weird_toolchain\") {\n"
+    "    ...\n"
+    "    toolchain_args() {\n"
+    "      # Override the system values for a generic Posix system.\n"
+    "      is_win = false\n"
+    "      is_posix = true\n"
+    "\n"
+    "      # Pass this new value for specific setup for my toolchain.\n"
+    "      is_my_weird_system = true\n"
+    "    }\n"
+    "  }\n";
+
+Value RunToolchainArgs(Scope* scope,
+                       const FunctionCallNode* function,
+                       const std::vector<Value>& args,
+                       BlockNode* block,
+                       Err* err) {
+  // Find the toolchain definition we're executing inside of. The toolchain
+  // function will set a property pointing to it that we'll pick up.
+  Toolchain* toolchain = reinterpret_cast<Toolchain*>(
+      scope->GetProperty(&kToolchainPropertyKey, NULL));
+  if (!toolchain) {
+    *err = Err(function->function(),
+               "toolchain_args() called outside of toolchain().",
+               "The toolchain_args() function can only be used inside a "
+               "toolchain() definition.");
+    return Value();
+  }
+
+  if (!args.empty()) {
+    *err = Err(function->function(), "This function takes no arguments.");
+    return Value();
+  }
+
+  // This function makes a new scope with various variable sets on it, which
+  // we then save on the toolchain to use when re-invoking the build.
+  Scope block_scope(scope);
+  block->ExecuteBlockInScope(&block_scope, err);
+  if (err->has_error())
+    return Value();
+
+  Scope::KeyValueMap values;
+  block_scope.GetCurrentScopeValues(&values);
+  toolchain->args() = values;
+
+  return Value();
+}
+
 }  // namespace functions
diff --git a/tools/gn/function_write_file.cc b/tools/gn/function_write_file.cc
index 90d5074..ea42100 100644
--- a/tools/gn/function_write_file.cc
+++ b/tools/gn/function_write_file.cc
@@ -50,7 +50,7 @@
   // Compute the file name and make sure it's in the output dir.
   if (!args[0].VerifyTypeIs(Value::STRING, err))
     return Value();
-  const SourceDir& cur_dir = SourceDirForFunctionCall(function);
+  const SourceDir& cur_dir = scope->GetSourceDir();
   SourceFile source_file = cur_dir.ResolveRelativeFile(args[0].string_value());
   if (!EnsureStringIsInOutputDir(
           scope->settings()->build_settings()->build_dir(),
@@ -62,9 +62,9 @@
   if (args[1].type() == Value::LIST) {
     const std::vector<Value>& list = args[1].list_value();
     for (size_t i = 0; i < list.size(); i++)
-      contents << list[i].ToString() << std::endl;
+      contents << list[i].ToString(false) << std::endl;
   } else {
-    contents << args[1].ToString();
+    contents << args[1].ToString(false);
   }
 
   // Write file, creating the directory if necessary.
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index de3ddcc..894c934 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -22,12 +22,6 @@
 
 namespace {
 
-void FillNeedsBlockError(const FunctionCallNode* function, Err* err) {
-  *err = Err(function->function(), "This function call requires a block.",
-      "The block's \"{\" must be on the same line as the function "
-      "call's \")\".");
-}
-
 // This is called when a template is invoked. When we see a template
 // declaration, that funciton is RunTemplate.
 Value RunTemplateInvocation(Scope* scope,
@@ -38,9 +32,10 @@
                             Err* err) {
   if (!EnsureNotProcessingImport(invocation, scope, err))
     return Value();
+
   Scope block_scope(scope);
   if (!FillTargetBlockScope(scope, invocation,
-                            invocation->function().value().data(),
+                            invocation->function().value().as_string(),
                             block, args, &block_scope, err))
     return Value();
 
@@ -90,7 +85,7 @@
 
 bool FillTargetBlockScope(const Scope* scope,
                           const FunctionCallNode* function,
-                          const char* target_type,
+                          const std::string& target_type,
                           const BlockNode* block,
                           const std::vector<Value>& args,
                           Scope* block_scope,
@@ -122,6 +117,12 @@
   return true;
 }
 
+void FillNeedsBlockError(const FunctionCallNode* function, Err* err) {
+  *err = Err(function->function(), "This function call requires a block.",
+      "The block's \"{\" must be on the same line as the function "
+      "call's \")\".");
+}
+
 bool EnsureSingleStringArg(const FunctionCallNode* function,
                            const std::vector<Value>& args,
                            Err* err) {
@@ -133,10 +134,6 @@
   return args[0].VerifyTypeIs(Value::STRING, err);
 }
 
-const SourceDir& SourceDirForFunctionCall(const FunctionCallNode* function) {
-  return function->function().location().file()->dir();
-}
-
 const Label& ToolchainLabelForScope(const Scope* scope) {
   return scope->settings()->toolchain()->label();
 }
@@ -144,9 +141,9 @@
 Label MakeLabelForScope(const Scope* scope,
                         const FunctionCallNode* function,
                         const std::string& name) {
-  const SourceDir& input_dir = SourceDirForFunctionCall(function);
   const Label& toolchain_label = ToolchainLabelForScope(scope);
-  return Label(input_dir, name, toolchain_label.dir(), toolchain_label.name());
+  return Label(scope->GetSourceDir(), name, toolchain_label.dir(),
+               toolchain_label.name());
 }
 
 namespace functions {
@@ -155,18 +152,42 @@
 
 const char kAssert[] = "assert";
 const char kAssert_Help[] =
-    "TODO(brettw) WRITE ME";
+    "assert: Assert an expression is true at generation time.\n"
+    "\n"
+    "  assert(<condition> [, <error string>])\n"
+    "\n"
+    "  If the condition is false, the build will fail with an error. If the\n"
+    "  optional second argument is provided, that string will be printed\n"
+    "  with the error message.\n"
+    "\n"
+    "Examples:\n"
+    "  assert(is_win)\n"
+    "  assert(defined(sources), \"Sources must be defined\")\n";
 
 Value RunAssert(Scope* scope,
                 const FunctionCallNode* function,
                 const std::vector<Value>& args,
                 Err* err) {
-  if (args.size() != 1) {
+  if (args.size() != 1 && args.size() != 2) {
     *err = Err(function->function(), "Wrong number of arguments.",
-               "assert() takes one argument, "
+               "assert() takes one or two argument, "
                "were you expecting somethig else?");
-  } else if (args[0].InterpretAsInt() == 0) {
-    *err = Err(function->function(), "Assertion failed.");
+  } else if (args[0].type() != Value::BOOLEAN) {
+    *err = Err(function->function(), "Assertion value not a bool.");
+  } else if (!args[0].boolean_value()) {
+    if (args.size() == 2) {
+      // Optional string message.
+      if (args[1].type() != Value::STRING) {
+        *err = Err(function->function(), "Assertion failed.",
+            "<<<ERROR MESSAGE IS NOT A STRING>>>");
+      } else {
+        *err = Err(function->function(), "Assertion failed.",
+            args[1].string_value());
+      }
+    } else {
+      *err = Err(function->function(), "Assertion failed.");
+    }
+
     if (args[0].origin()) {
       // If you do "assert(foo)" we'd ideally like to show you where foo was
       // set, and in this case the origin of the args will tell us that.
@@ -216,7 +237,7 @@
     return Value();
 
   // Fill it.
-  const SourceDir input_dir = SourceDirForFunctionCall(function);
+  const SourceDir& input_dir = scope->GetSourceDir();
   ConfigValuesGenerator gen(&config->config_values(), scope,
                             function->function(), input_dir, err);
   gen.Run();
@@ -236,48 +257,86 @@
 
 const char kDeclareArgs[] = "declare_args";
 const char kDeclareArgs_Help[] =
-    "TODO(brettw) write this.";
+    "declare_args: Declare build arguments used by this file.\n"
+    "\n"
+    "  Introduces the given arguments into the current scope. If they are\n"
+    "  not specified on the command line or in a toolchain's arguments,\n"
+    "  the default values given in the declare_args block will be used.\n"
+    "  However, these defaults will not override command-line values.\n"
+    "\n"
+    "  See also \"gn help buildargs\" for an overview.\n"
+    "\n"
+    "Example:\n"
+    "  declare_args() {\n"
+    "    enable_teleporter = true\n"
+    "    enable_doom_melon = false\n"
+    "  }\n"
+    "\n"
+    "  If you want to override the (default disabled) Doom Melon:\n"
+    "    gn --args=\"enable_doom_melon=true enable_teleporter=false\"\n"
+    "  This also sets the teleporter, but it's already defaulted to on so\n"
+    "  it will have no effect.\n";
 
-Value RunDeclareArgs(const FunctionCallNode* function,
+Value RunDeclareArgs(Scope* scope,
+                     const FunctionCallNode* function,
                      const std::vector<Value>& args,
-                     Scope* scope,
+                     BlockNode* block,
                      Err* err) {
-  // Only allow this to be called once. We use a variable in the current scope
-  // with a name the parser will reject if the user tried to type it.
-  const char did_declare_args_var[] = "@@declared_args";
-  if (scope->GetValue(did_declare_args_var)) {
-    *err = Err(function->function(), "Duplicate call to declared_args.");
-    err->AppendSubErr(
-        Err(scope->GetValue(did_declare_args_var)->origin()->GetRange(),
-                            "See the original call."));
+  Scope block_scope(scope);
+  block->ExecuteBlockInScope(&block_scope, err);
+  if (err->has_error())
     return Value();
-  }
 
-  // Find the root scope where the values will be set.
-  Scope* root = scope->mutable_containing();
-  if (!root || root->containing() || !scope->IsProcessingBuildConfig()) {
-    *err = Err(function->function(), "declare_args called incorrectly."
-        "It must be called only from the build config script and in the "
-        "root scope.");
-    return Value();
-  }
-
-  // Take all variables set in the current scope as default values and put
-  // them in the parent scope. The values in the current scope are the defaults,
-  // then we apply the external args to this list.
-  Scope::KeyValueVector values;
-  scope->GetCurrentScopeValues(&values);
-  for (size_t i = 0; i < values.size(); i++) {
-    // TODO(brettw) actually import the arguments from the command line rather
-    // than only using the defaults.
-    root->SetValue(values[i].first, values[i].second,
-                   values[i].second.origin());
-  }
-
-  scope->SetValue(did_declare_args_var, Value(function, 1), NULL);
+  // Pass the values from our scope into the Args object for adding to the
+  // scope with the proper values (taking into account the defaults given in
+  // the block_scope, and arguments passed into the build).
+  Scope::KeyValueMap values;
+  block_scope.GetCurrentScopeValues(&values);
+  scope->settings()->build_settings()->build_args().DeclareArgs(
+      values, scope, err);
   return Value();
 }
 
+// defined ---------------------------------------------------------------------
+
+const char kDefined[] = "defined";
+const char kDefined_Help[] =
+    "defined: Returns whether an identifier is defined.\n"
+    "\n"
+    "  Returns true if the given argument is defined. This is most useful in\n"
+    "  templates to assert that the caller set things up properly.\n"
+    "\n"
+    "Example:\n"
+    "\n"
+    "  template(\"mytemplate\") {\n"
+    "    # To help users call this template properly...\n"
+    "    assert(defined(sources), \"Sources must be defined\")\n"
+    "\n"
+    "    # If we want to accept an optional \"values\" argument, we don't\n"
+    "    # want to dereference something that may not be defined.\n"
+    "    if (!defined(outputs)) {\n"
+    "      outputs = []\n"
+    "    }\n"
+    "  }\n";
+
+Value RunDefined(Scope* scope,
+                 const FunctionCallNode* function,
+                 const ListNode* args_list,
+                 Err* err) {
+  const std::vector<const ParseNode*>& args_vector = args_list->contents();
+  const IdentifierNode* identifier = NULL;
+  if (args_vector.size() != 1 ||
+      !(identifier = args_vector[0]->AsIdentifier())) {
+    *err = Err(function, "Bad argument to defined().",
+        "defined() takes one argument which should be an identifier.");
+    return Value();
+  }
+
+  if (scope->GetValue(identifier->value().value()))
+    return Value(function, true);
+  return Value(function, false);
+}
+
 // import ----------------------------------------------------------------------
 
 const char kImport[] = "import";
@@ -319,7 +378,7 @@
       !EnsureNotProcessingImport(function, scope, err))
     return Value();
 
-  const SourceDir input_dir = SourceDirForFunctionCall(function);
+  const SourceDir& input_dir = scope->GetSourceDir();
   SourceFile import_file =
       input_dir.ResolveRelativeFile(args[0].string_value());
   scope->settings()->import_manager().DoImport(import_file, function,
@@ -327,48 +386,6 @@
   return Value();
 }
 
-// set_defaults ----------------------------------------------------------------
-
-const char kSetDefaults[] = "set_defaults";
-const char kSetDefaults_Help[] =
-    "TODO(brettw) write this.";
-
-Value RunSetDefaults(Scope* scope,
-                     const FunctionCallNode* function,
-                     const std::vector<Value>& args,
-                     BlockNode* block,
-                     Err* err) {
-  if (!EnsureSingleStringArg(function, args, err))
-    return Value();
-  const std::string& target_type(args[0].string_value());
-
-  // Ensure there aren't defaults already set.
-  if (scope->GetTargetDefaults(target_type)) {
-    *err = Err(function->function(),
-               "This target type defaults were already set.");
-    return Value();
-  }
-
-  // Execute the block in a new scope that has a parent of the containing
-  // scope.
-  Scope block_scope(scope);
-  if (!FillTargetBlockScope(scope, function,
-                            function->function().value().data(),
-                            block, args, &block_scope, err))
-    return Value();
-
-  // Run the block for the rule invocation.
-  block->ExecuteBlockInScope(&block_scope, err);
-  if (err->has_error())
-    return Value();
-
-  // Now copy the values set on the scope we made into the free-floating one
-  // (with no containing scope) used to hold the target defaults.
-  Scope* dest = scope->MakeTargetDefaults(target_type);
-  block_scope.NonRecursiveMergeTo(dest, function, "<SHOULD NOT FAIL>", err);
-  return Value();
-}
-
 // set_sources_assignment_filter -----------------------------------------------
 
 const char kSetSourcesAssignmentFilter[] = "set_sources_assignment_filter";
@@ -416,7 +433,7 @@
   for (size_t i = 0; i < args.size(); i++) {
     if (i != 0)
       std::cout << " ";
-    std::cout << args[i].ToString();
+    std::cout << args[i].ToString(false);
   }
   std::cout << std::endl;
   return Value();
@@ -425,28 +442,40 @@
 // -----------------------------------------------------------------------------
 
 FunctionInfo::FunctionInfo()
-    : generic_block_runner(NULL),
+    : self_evaluating_args_runner(NULL),
+      generic_block_runner(NULL),
       executed_block_runner(NULL),
       no_block_runner(NULL),
       help(NULL) {
 }
 
+FunctionInfo::FunctionInfo(SelfEvaluatingArgsFunction seaf, const char* in_help)
+    : self_evaluating_args_runner(seaf),
+      generic_block_runner(NULL),
+      executed_block_runner(NULL),
+      no_block_runner(NULL),
+      help(in_help) {
+}
+
 FunctionInfo::FunctionInfo(GenericBlockFunction gbf, const char* in_help)
-    : generic_block_runner(gbf),
+    : self_evaluating_args_runner(NULL),
+      generic_block_runner(gbf),
       executed_block_runner(NULL),
       no_block_runner(NULL),
       help(in_help) {
 }
 
 FunctionInfo::FunctionInfo(ExecutedBlockFunction ebf, const char* in_help)
-    : generic_block_runner(NULL),
+    : self_evaluating_args_runner(NULL),
+      generic_block_runner(NULL),
       executed_block_runner(ebf),
       no_block_runner(NULL),
       help(in_help) {
 }
 
 FunctionInfo::FunctionInfo(NoBlockFunction nbf, const char* in_help)
-    : generic_block_runner(NULL),
+    : self_evaluating_args_runner(NULL),
+      generic_block_runner(NULL),
       executed_block_runner(NULL),
       no_block_runner(nbf),
       help(in_help) {
@@ -470,6 +499,7 @@
     INSERT_FUNCTION(Copy)
     INSERT_FUNCTION(Custom)
     INSERT_FUNCTION(DeclareArgs)
+    INSERT_FUNCTION(Defined)
     INSERT_FUNCTION(ExecScript)
     INSERT_FUNCTION(Executable)
     INSERT_FUNCTION(Group)
@@ -486,6 +516,7 @@
     INSERT_FUNCTION(Test)
     INSERT_FUNCTION(Tool)
     INSERT_FUNCTION(Toolchain)
+    INSERT_FUNCTION(ToolchainArgs)
     INSERT_FUNCTION(WriteFile)
 
     #undef INSERT_FUNCTION
@@ -499,7 +530,7 @@
 
 Value RunFunction(Scope* scope,
                   const FunctionCallNode* function,
-                  const std::vector<Value>& args,
+                  const ListNode* args_list,
                   BlockNode* block,
                   Err* err) {
   const Token& name = function->function();
@@ -511,20 +542,35 @@
     // No build-in function matching this, check for a template.
     const FunctionCallNode* rule =
         scope->GetTemplate(function->function().value().as_string());
-    if (rule)
-      return RunTemplateInvocation(scope, function, args, block, rule, err);
+    if (rule) {
+      Value args = args_list->Execute(scope, err);
+      if (err->has_error())
+        return Value();
+      return RunTemplateInvocation(scope, function, args.list_value(), block,
+                                   rule, err);
+    }
 
     *err = Err(name, "Unknown function.");
     return Value();
   }
 
+  if (found_function->second.self_evaluating_args_runner) {
+    return found_function->second.self_evaluating_args_runner(
+        scope, function, args_list, err);
+  }
+
+  // All other function types take a pre-executed set of args.
+  Value args = args_list->Execute(scope, err);
+  if (err->has_error())
+    return Value();
+
   if (found_function->second.generic_block_runner) {
     if (!block) {
       FillNeedsBlockError(function, err);
       return Value();
     }
     return found_function->second.generic_block_runner(
-        scope, function, args, block, err);
+        scope, function, args.list_value(), block, err);
   }
 
   if (found_function->second.executed_block_runner) {
@@ -538,11 +584,12 @@
     if (err->has_error())
       return Value();
     return found_function->second.executed_block_runner(
-        function, args, &block_scope, err);
+        function, args.list_value(), &block_scope, err);
   }
 
   // Otherwise it's a no-block function.
-  return found_function->second.no_block_runner(scope, function, args, err);
+  return found_function->second.no_block_runner(scope, function,
+                                                args.list_value(), err);
 }
 
 }  // namespace functions
diff --git a/tools/gn/functions.h b/tools/gn/functions.h
index d28804d..351861b 100644
--- a/tools/gn/functions.h
+++ b/tools/gn/functions.h
@@ -18,7 +18,6 @@
 class ListNode;
 class ParseNode;
 class Scope;
-class SourceDir;
 class Token;
 class Value;
 
@@ -26,6 +25,14 @@
 
 namespace functions {
 
+// This type of function invocation has no block and evaluates its arguments
+// itself rather than taking a pre-executed list. This allows us to implement
+// certain built-in functions.
+typedef Value (*SelfEvaluatingArgsFunction)(Scope* scope,
+                                            const FunctionCallNode* function,
+                                            const ListNode* args_list,
+                                            Err* err);
+
 // This type of function invocation takes a block node that it will execute.
 typedef Value (*GenericBlockFunction)(Scope* scope,
                                       const FunctionCallNode* function,
@@ -86,11 +93,19 @@
 
 extern const char kDeclareArgs[];
 extern const char kDeclareArgs_Help[];
-Value RunDeclareArgs(const FunctionCallNode* function,
+Value RunDeclareArgs(Scope* scope,
+                     const FunctionCallNode* function,
                      const std::vector<Value>& args,
-                     Scope* block_scope,
+                     BlockNode* block,
                      Err* err);
 
+extern const char kDefined[];
+extern const char kDefined_Help[];
+Value RunDefined(Scope* scope,
+                 const FunctionCallNode* function,
+                 const ListNode* args_list,
+                 Err* err);
+
 extern const char kExecScript[];
 extern const char kExecScript_Help[];
 Value RunExecScript(Scope* scope,
@@ -212,6 +227,14 @@
                    BlockNode* block,
                    Err* err);
 
+extern const char kToolchainArgs[];
+extern const char kToolchainArgs_Help[];
+Value RunToolchainArgs(Scope* scope,
+                       const FunctionCallNode* function,
+                       const std::vector<Value>& args,
+                       BlockNode* block,
+                       Err* err);
+
 extern const char kWriteFile[];
 extern const char kWriteFile_Help[];
 Value RunWriteFile(Scope* scope,
@@ -225,10 +248,12 @@
 // which indicates the type of function it is.
 struct FunctionInfo {
   FunctionInfo();
+  FunctionInfo(SelfEvaluatingArgsFunction seaf, const char* in_help);
   FunctionInfo(GenericBlockFunction gbf, const char* in_help);
   FunctionInfo(ExecutedBlockFunction ebf, const char* in_help);
   FunctionInfo(NoBlockFunction nbf, const char* in_help);
 
+  SelfEvaluatingArgsFunction self_evaluating_args_runner;
   GenericBlockFunction generic_block_runner;
   ExecutedBlockFunction executed_block_runner;
   NoBlockFunction no_block_runner;
@@ -244,7 +269,7 @@
 // Runs the given function.
 Value RunFunction(Scope* scope,
                   const FunctionCallNode* function,
-                  const std::vector<Value>& args,
+                  const ListNode* args_list,
                   BlockNode* block,  // Optional.
                   Err* err);
 
@@ -274,12 +299,16 @@
 // On success, returns true. On failure, sets the error and returns false.
 bool FillTargetBlockScope(const Scope* scope,
                           const FunctionCallNode* function,
-                          const char* target_type,
+                          const std::string& target_type,
                           const BlockNode* block,
                           const std::vector<Value>& args,
                           Scope* block_scope,
                           Err* err);
 
+// Sets the given error to a message explaining that the function call requires
+// a block.
+void FillNeedsBlockError(const FunctionCallNode* function, Err* err);
+
 // Validates that the given function call has one string argument. This is
 // the most common function signature, so it saves space to have this helper.
 // Returns false and sets the error on failure.
@@ -287,10 +316,6 @@
                            const std::vector<Value>& args,
                            Err* err);
 
-// Returns the source directory for the file comtaining the given function
-// invocation.
-const SourceDir& SourceDirForFunctionCall(const FunctionCallNode* function);
-
 // Returns the name of the toolchain for the given scope.
 const Label& ToolchainLabelForScope(const Scope* scope);
 
diff --git a/tools/gn/gn.gyp b/tools/gn/gn.gyp
index 00cb256..f86a520 100644
--- a/tools/gn/gn.gyp
+++ b/tools/gn/gn.gyp
@@ -10,11 +10,17 @@
         '../../base/base.gyp:base',
       ],
       'sources': [
+        'args.cc',
+        'args.h',
+        'binary_target_generator.cc',
+        'binary_target_generator.h',
         'build_settings.cc',
         'build_settings.h',
+        'command_args.cc',
         'command_desc.cc',
         'command_gen.cc',
         'command_help.cc',
+        'command_refs.cc',
         'commands.cc',
         'commands.h',
         'config.cc',
@@ -25,6 +31,8 @@
         'config_values_extractors.h',
         'config_values_generator.cc',
         'config_values_generator.h',
+        'copy_target_generator.cc',
+        'copy_target_generator.h',
         'err.cc',
         'err.h',
         'escape.cc',
@@ -40,9 +48,12 @@
         'function_process_file_template.cc',
         'function_read_file.cc',
         'function_set_default_toolchain.cc',
+        'function_set_defaults.cc',
         'function_template.cc',
         'function_toolchain.cc',
         'function_write_file.cc',
+        'group_target_generator.cc',
+        'group_target_generator.h',
         'import_manager.cc',
         'import_manager.h',
         'input_conversion.cc',
@@ -60,10 +71,18 @@
         'label.cc',
         'label.h',
         'location.h',
+        'ninja_binary_target_writer.cc',
+        'ninja_binary_target_writer.h',
         'ninja_build_writer.cc',
         'ninja_build_writer.h',
+        'ninja_copy_target_writer.cc',
+        'ninja_copy_target_writer.h',
+        'ninja_group_target_writer.cc',
+        'ninja_group_target_writer.h',
         'ninja_helper.cc',
         'ninja_helper.h',
+        'ninja_script_target_writer.cc',
+        'ninja_script_target_writer.h',
         'ninja_target_writer.cc',
         'ninja_target_writer.h',
         'ninja_toolchain_writer.cc',
@@ -87,6 +106,10 @@
         'scope.h',
         'scope_per_file_provider.cc',
         'scope_per_file_provider.h',
+        'script_target_generator.cc',
+        'script_target_generator.h',
+        'script_values.cc',
+        'script_values.h',
         'settings.cc',
         'settings.h',
         'setup.cc',
diff --git a/tools/gn/group_target_generator.cc b/tools/gn/group_target_generator.cc
new file mode 100644
index 0000000..6f6fe32
--- /dev/null
+++ b/tools/gn/group_target_generator.cc
@@ -0,0 +1,21 @@
+// 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 "tools/gn/group_target_generator.h"
+
+GroupTargetGenerator::GroupTargetGenerator(Target* target,
+                                           Scope* scope,
+                                           const Token& function_token,
+                                           Err* err)
+    : TargetGenerator(target, scope, function_token, err) {
+}
+
+GroupTargetGenerator::~GroupTargetGenerator() {
+}
+
+void GroupTargetGenerator::DoRun() {
+  target_->set_output_type(Target::GROUP);
+  // Groups only have the default types filled in by the target generator
+  // base class.
+}
diff --git a/tools/gn/group_target_generator.h b/tools/gn/group_target_generator.h
new file mode 100644
index 0000000..a88ec03
--- /dev/null
+++ b/tools/gn/group_target_generator.h
@@ -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.
+
+#ifndef TOOLS_GN_GROUP_TARGET_GENERATOR_H_
+#define TOOLS_GN_GROUP_TARGET_GENERATOR_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/target_generator.h"
+
+// Populates a Target with the values for a group rule.
+class GroupTargetGenerator : public TargetGenerator {
+ public:
+  GroupTargetGenerator(Target* target,
+                        Scope* scope,
+                        const Token& function_token,
+                        Err* err);
+  virtual ~GroupTargetGenerator();
+
+ protected:
+  virtual void DoRun() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GroupTargetGenerator);
+};
+
+#endif  // TOOLS_GN_GROUP_TARGET_GENERATOR_H_
+
diff --git a/tools/gn/import_manager.cc b/tools/gn/import_manager.cc
index 774f866..e9e9425 100644
--- a/tools/gn/import_manager.cc
+++ b/tools/gn/import_manager.cc
@@ -24,6 +24,7 @@
   CHECK(block);
 
   scoped_ptr<Scope> scope(new Scope(settings->base_config()));
+  scope->set_source_dir(file.GetDir());
   scope->SetProcessingImport();
   block->ExecuteBlockInScope(scope.get(), err);
   if (err->has_error())
diff --git a/tools/gn/input_conversion.cc b/tools/gn/input_conversion.cc
index 3b104ef..19a8047 100644
--- a/tools/gn/input_conversion.cc
+++ b/tools/gn/input_conversion.cc
@@ -36,7 +36,7 @@
   }
   TrimWhitespaceASCII(result, TRIM_ALL, &result);
 
-  const int kMaxSize = 50;
+  const size_t kMaxSize = 50;
   if (result.size() > kMaxSize) {
     trimmed = true;
     result.resize(kMaxSize);
diff --git a/tools/gn/input_file.h b/tools/gn/input_file.h
index edf39ff..ab7dd70 100644
--- a/tools/gn/input_file.h
+++ b/tools/gn/input_file.h
@@ -31,6 +31,12 @@
   // The physical name tells the actual name on disk, if there is one.
   const base::FilePath& physical_name() const { return physical_name_; }
 
+  // The friendly name can be set to override the name() in cases where there
+  // is no name (like SetContents is used instead) or if the name doesn't
+  // make sense. This will be displayed in error messages.
+  const std::string& friendly_name() const { return friendly_name_; }
+  void set_friendly_name(const std::string& f) { friendly_name_ = f; }
+
   const std::string& contents() const {
     DCHECK(contents_loaded_);
     return contents_;
@@ -48,6 +54,7 @@
   SourceDir dir_;
 
   base::FilePath physical_name_;
+  std::string friendly_name_;
 
   bool contents_loaded_;
   std::string contents_;
diff --git a/tools/gn/item.h b/tools/gn/item.h
index aa71544..2538c50 100644
--- a/tools/gn/item.h
+++ b/tools/gn/item.h
@@ -10,6 +10,7 @@
 #include "tools/gn/label.h"
 
 class Config;
+class ItemNode;
 class Target;
 class Toolchain;
 
@@ -20,8 +21,17 @@
   Item(const Label& label);
   virtual ~Item();
 
+  // This is guaranteed to never change after construction so this can be
+  // accessed from any thread with no locking once the item is constructed.
   const Label& label() const { return label_; }
 
+  // The Item and the ItemNode make a pair. This will be set when the ItemNode
+  // is constructed that owns this Item. The ItemNode should only be
+  // dereferenced with the ItemTree lock held.
+  ItemNode* item_node() { return item_node_; }
+  const ItemNode* item_node() const { return item_node_; }
+  void set_item_node(ItemNode* in) { item_node_ = in; }
+
   // Manual RTTI.
   virtual Config* AsConfig();
   virtual const Config* AsConfig() const;
@@ -40,6 +50,8 @@
 
  private:
   Label label_;
+
+  ItemNode* item_node_;
 };
 
 #endif  // TOOLS_GN_ITEM_H_
diff --git a/tools/gn/item_node.cc b/tools/gn/item_node.cc
index f10bada..2143b06 100644
--- a/tools/gn/item_node.cc
+++ b/tools/gn/item_node.cc
@@ -15,6 +15,7 @@
     : state_(REFERENCED),
       item_(i),
       should_generate_(false) {
+  item_->set_item_node(this);
 }
 
 ItemNode::~ItemNode() {
diff --git a/tools/gn/item_tree.cc b/tools/gn/item_tree.cc
index 054403d..42e005b 100644
--- a/tools/gn/item_tree.cc
+++ b/tools/gn/item_tree.cc
@@ -87,6 +87,14 @@
   return true;
 }
 
+void ItemTree::GetAllItemNodesLocked(std::vector<const ItemNode*>* dest) const {
+  lock_.AssertAcquired();
+  dest->reserve(items_.size());
+  for (StringToNodeHash::const_iterator i = items_.begin();
+       i != items_.end(); ++i)
+    dest->push_back(i->second);
+}
+
 void ItemTree::GetAllItemsLocked(std::vector<const Item*>* dest) const {
   lock_.AssertAcquired();
   dest->reserve(items_.size());
diff --git a/tools/gn/item_tree.h b/tools/gn/item_tree.h
index 4a8f9fb..59de49f 100644
--- a/tools/gn/item_tree.h
+++ b/tools/gn/item_tree.h
@@ -65,6 +65,7 @@
                              Err* err);
 
   // Fills the given vector with all known items.
+  void GetAllItemNodesLocked(std::vector<const ItemNode*>* dest) const;
   void GetAllItemsLocked(std::vector<const Item*>* dest) const;
 
   // Returns an error if there are unresolved dependencies, or no error if
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc
new file mode 100644
index 0000000..dac9c76
--- /dev/null
+++ b/tools/gn/ninja_binary_target_writer.cc
@@ -0,0 +1,311 @@
+// 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 "tools/gn/ninja_binary_target_writer.h"
+
+#include "tools/gn/config_values_extractors.h"
+#include "tools/gn/err.h"
+#include "tools/gn/escape.h"
+#include "tools/gn/string_utils.h"
+
+namespace {
+
+// Returns the proper escape options for writing compiler and linker flags.
+EscapeOptions GetFlagOptions() {
+  EscapeOptions opts;
+  opts.mode = ESCAPE_NINJA;
+
+  // Some flag strings are actually multiple flags that expect to be just
+  // added to the command line. We assume that quoting is done by the
+  // buildfiles if it wants such things quoted.
+  opts.inhibit_quoting = true;
+
+  return opts;
+}
+
+struct DefineWriter {
+  void operator()(const std::string& s, std::ostream& out) const {
+    out << " -D" << s;
+  }
+};
+
+struct IncludeWriter {
+  IncludeWriter(PathOutput& path_output,
+                const NinjaHelper& h)
+      : helper(h),
+        path_output_(path_output),
+        old_inhibit_quoting_(path_output.inhibit_quoting()) {
+    // Inhibit quoting since we'll put quotes around the whole thing ourselves.
+    // Since we're writing in NINJA escaping mode, this won't actually do
+    // anything, but I think we may need to change to shell-and-then-ninja
+    // escaping for this in the future.
+    path_output_.set_inhibit_quoting(true);
+  }
+  ~IncludeWriter() {
+    path_output_.set_inhibit_quoting(old_inhibit_quoting_);
+  }
+
+  void operator()(const SourceDir& d, std::ostream& out) const {
+    out << " \"-I";
+    // It's important not to include the trailing slash on directories or on
+    // Windows it will be a backslash and the compiler might think we're
+    // escaping the quote!
+    path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH);
+    out << "\"";
+  }
+
+  const NinjaHelper& helper;
+  PathOutput& path_output_;
+  bool old_inhibit_quoting_;  // So we can put the PathOutput back.
+};
+
+}  // namespace
+
+NinjaBinaryTargetWriter::NinjaBinaryTargetWriter(const Target* target,
+                                                 std::ostream& out)
+    : NinjaTargetWriter(target, out) {
+}
+
+NinjaBinaryTargetWriter::~NinjaBinaryTargetWriter() {
+}
+
+void NinjaBinaryTargetWriter::Run() {
+  WriteEnvironment();
+
+  WriteCompilerVars();
+
+  std::vector<OutputFile> obj_files;
+  WriteSources(&obj_files);
+
+  WriteLinkerStuff(obj_files);
+}
+
+void NinjaBinaryTargetWriter::WriteCompilerVars() {
+  // Defines.
+  out_ << "defines =";
+  RecursiveTargetConfigToStream(target_, &ConfigValues::defines,
+                                DefineWriter(), out_);
+  out_ << std::endl;
+
+  // Includes.
+  out_ << "includes =";
+  RecursiveTargetConfigToStream(target_, &ConfigValues::includes,
+                                IncludeWriter(path_output_, helper_), out_);
+
+  out_ << std::endl;
+
+  // C flags and friends.
+  EscapeOptions flag_escape_options = GetFlagOptions();
+#define WRITE_FLAGS(name) \
+    out_ << #name " ="; \
+    RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, \
+                                         flag_escape_options, out_); \
+    out_ << std::endl;
+
+  WRITE_FLAGS(cflags)
+  WRITE_FLAGS(cflags_c)
+  WRITE_FLAGS(cflags_cc)
+  WRITE_FLAGS(cflags_objc)
+  WRITE_FLAGS(cflags_objcc)
+
+#undef WRITE_FLAGS
+
+  out_ << std::endl;
+}
+
+void NinjaBinaryTargetWriter::WriteSources(
+    std::vector<OutputFile>* object_files) {
+  const Target::FileList& sources = target_->sources();
+  object_files->reserve(sources.size());
+
+  const Toolchain* toolchain = GetToolchain();
+  for (size_t i = 0; i < sources.size(); i++) {
+    const SourceFile& input_file = sources[i];
+
+    SourceFileType input_file_type = GetSourceFileType(input_file,
+                                                       settings_->target_os());
+    if (input_file_type == SOURCE_UNKNOWN)
+      continue;  // Skip unknown file types.
+    std::string command =
+        helper_.GetRuleForSourceType(settings_, toolchain, input_file_type);
+    if (command.empty())
+      continue;  // Skip files not needing compilation.
+
+    OutputFile output_file = helper_.GetOutputFileForSource(
+        target_, input_file, input_file_type);
+    object_files->push_back(output_file);
+
+    out_ << "build ";
+    path_output_.WriteFile(out_, output_file);
+    out_ << ": " << command << " ";
+    path_output_.WriteFile(out_, input_file);
+    out_ << std::endl;
+  }
+  out_ << std::endl;
+}
+
+void NinjaBinaryTargetWriter::WriteLinkerStuff(
+    const std::vector<OutputFile>& object_files) {
+  // Manifest file on Windows.
+  // TODO(brettw) this seems not to be necessary for static libs, skip in
+  // that case?
+  OutputFile windows_manifest;
+  if (settings_->IsWin()) {
+    windows_manifest.value().assign(helper_.GetTargetOutputDir(target_));
+    windows_manifest.value().append(target_->label().name());
+    windows_manifest.value().append(".intermediate.manifest");
+    out_ << "manifests = ";
+    path_output_.WriteFile(out_, windows_manifest);
+    out_ << std::endl;
+  }
+
+  // Linker flags, append manifest flag on Windows to reference our file.
+  out_ << "ldflags =";
+  RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags,
+                                       GetFlagOptions(), out_);
+  // HACK ERASEME BRETTW FIXME
+  if (settings_->IsWin()) {
+    out_ << " /MANIFEST /ManifestFile:";
+    path_output_.WriteFile(out_, windows_manifest);
+    out_ << " /DEBUG /MACHINE:X86 /LIBPATH:\"C:\\Program Files (x86)\\Windows Kits\\8.0\\Lib\\win8\\um\\x86\" /DELAYLOAD:dbghelp.dll /DELAYLOAD:dwmapi.dll /DELAYLOAD:shell32.dll /DELAYLOAD:uxtheme.dll /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat /SUBSYSTEM:CONSOLE /INCREMENTAL /FIXED:NO /DYNAMICBASE:NO wininet.lib dnsapi.lib version.lib msimg32.lib ws2_32.lib usp10.lib psapi.lib dbghelp.lib winmm.lib shlwapi.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib user32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /NXCOMPAT";
+  }
+  out_ << std::endl;
+
+  // Libraries to link.
+  out_ << "libs =";
+  if (settings_->IsMac()) {
+    // TODO(brettw) fix this.
+    out_ << " -framework AppKit -framework ApplicationServices -framework Carbon -framework CoreFoundation -framework Foundation -framework IOKit -framework Security";
+  }
+  out_ << std::endl;
+
+  // The external output file is the one that other libs depend on.
+  OutputFile external_output_file = helper_.GetTargetOutputFile(target_);
+
+  // The internal output file is the "main thing" we think we're making. In
+  // the case of shared libraries, this is the shared library and the external
+  // output file is the import library. In other cases, the internal one and
+  // the external one are the same.
+  OutputFile internal_output_file;
+  if (target_->output_type() == Target::SHARED_LIBRARY) {
+    if (settings_->IsWin()) {
+      internal_output_file = OutputFile(target_->label().name() + ".dll");
+    } else {
+      internal_output_file = external_output_file;
+    }
+  } else {
+    internal_output_file = external_output_file;
+  }
+
+  // In Python see "self.ninja.build(output, command, input,"
+  WriteLinkCommand(external_output_file, internal_output_file, object_files);
+
+  if (target_->output_type() == Target::SHARED_LIBRARY) {
+    // The shared object name doesn't include a path.
+    out_ << "  soname = ";
+    out_ << FindFilename(&internal_output_file.value());
+    out_ << std::endl;
+
+    out_ << "  lib = ";
+    path_output_.WriteFile(out_, internal_output_file);
+    out_ << std::endl;
+
+    if (settings_->IsWin()) {
+      out_ << "  dll = ";
+      path_output_.WriteFile(out_, internal_output_file);
+      out_ << std::endl;
+    }
+
+    if (settings_->IsWin()) {
+      out_ << "  implibflag = /IMPLIB:";
+      path_output_.WriteFile(out_, external_output_file);
+      out_ << std::endl;
+    }
+
+    // TODO(brettw) postbuild steps.
+    if (settings_->IsMac())
+      out_ << "  postbuilds = $ && (export BUILT_PRODUCTS_DIR=/Users/brettw/prj/src/out/gn; export CONFIGURATION=Debug; export DYLIB_INSTALL_NAME_BASE=@rpath; export EXECUTABLE_NAME=libbase.dylib; export EXECUTABLE_PATH=libbase.dylib; export FULL_PRODUCT_NAME=libbase.dylib; export LD_DYLIB_INSTALL_NAME=@rpath/libbase.dylib; export MACH_O_TYPE=mh_dylib; export PRODUCT_NAME=base; export PRODUCT_TYPE=com.apple.product-type.library.dynamic; export SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk; export SRCROOT=/Users/brettw/prj/src/out/gn/../../base; export SOURCE_ROOT=\"$${SRCROOT}\"; export TARGET_BUILD_DIR=/Users/brettw/prj/src/out/gn; export TEMP_DIR=\"$${TMPDIR}\"; (cd ../../base && ../build/mac/strip_from_xcode); G=$$?; ((exit $$G) || rm -rf libbase.dylib) && exit $$G)";
+  }
+
+  out_ << std::endl;
+}
+
+void NinjaBinaryTargetWriter::WriteLinkCommand(
+    const OutputFile& external_output_file,
+    const OutputFile& internal_output_file,
+    const std::vector<OutputFile>& object_files) {
+  out_ << "build ";
+  path_output_.WriteFile(out_, internal_output_file);
+  if (external_output_file != internal_output_file) {
+    out_ << " ";
+    path_output_.WriteFile(out_, external_output_file);
+  }
+  out_ << ": "
+       << helper_.GetRuleForTargetType(GetToolchain(), target_->output_type());
+
+  // Object files.
+  for (size_t i = 0; i < object_files.size(); i++) {
+    out_ << " ";
+    path_output_.WriteFile(out_, object_files[i]);
+  }
+
+  // Library inputs (deps and inherited static libraries).
+  //
+  // Static libraries since they're just a collection of the object files so
+  // don't need libraries linked with them, but we still need to go through
+  // the list and find non-linkable data deps in the "deps" section. We'll
+  // collect all non-linkable deps and put it in the order-only deps below.
+  std::vector<const Target*> extra_data_deps;
+  const std::vector<const Target*>& deps = target_->deps();
+  const std::set<const Target*>& inherited = target_->inherited_libraries();
+  for (size_t i = 0; i < deps.size(); i++) {
+    if (inherited.find(deps[i]) != inherited.end())
+      continue;
+    if (target_->output_type() != Target::STATIC_LIBRARY &&
+        deps[i]->IsLinkable()) {
+      out_ << " ";
+      path_output_.WriteFile(out_, helper_.GetTargetOutputFile(deps[i]));
+    } else {
+      extra_data_deps.push_back(deps[i]);
+    }
+  }
+  for (std::set<const Target*>::const_iterator i = inherited.begin();
+       i != inherited.end(); ++i) {
+    if (target_->output_type() == Target::STATIC_LIBRARY) {
+      extra_data_deps.push_back(*i);
+    } else {
+      out_ << " ";
+      path_output_.WriteFile(out_, helper_.GetTargetOutputFile(*i));
+    }
+  }
+
+  // Append data dependencies as order-only dependencies.
+  const std::vector<const Target*>& datadeps = target_->datadeps();
+  const std::vector<SourceFile>& data = target_->data();
+  if (!extra_data_deps.empty() || !datadeps.empty() || !data.empty()) {
+    out_ << " ||";
+
+    // Non-linkable deps in the deps section above.
+    for (size_t i = 0; i < extra_data_deps.size(); i++) {
+      out_ << " ";
+      path_output_.WriteFile(out_,
+                             helper_.GetTargetOutputFile(extra_data_deps[i]));
+    }
+
+    // Data deps.
+    for (size_t i = 0; i < datadeps.size(); i++) {
+      out_ << " ";
+      path_output_.WriteFile(out_, helper_.GetTargetOutputFile(datadeps[i]));
+    }
+
+    // Data files.
+    const std::vector<SourceFile>& data = target_->data();
+    for (size_t i = 0; i < data.size(); i++) {
+      out_ << " ";
+      path_output_.WriteFile(out_, data[i]);
+    }
+  }
+
+  out_ << std::endl;
+}
diff --git a/tools/gn/ninja_binary_target_writer.h b/tools/gn/ninja_binary_target_writer.h
new file mode 100644
index 0000000..5e4347a
--- /dev/null
+++ b/tools/gn/ninja_binary_target_writer.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 TOOLS_GN_NINJA_BINARY_TARGET_WRITER_H_
+#define TOOLS_GN_NINJA_BINARY_TARGET_WRITER_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/ninja_target_writer.h"
+
+// Writes a .ninja file for a binary target type (an executable, a shared
+// library, or a static library).
+class NinjaBinaryTargetWriter : public NinjaTargetWriter {
+ public:
+  NinjaBinaryTargetWriter(const Target* target, std::ostream& out);
+  virtual ~NinjaBinaryTargetWriter();
+
+  virtual void Run() OVERRIDE;
+
+ private:
+  void WriteCompilerVars();
+  void WriteSources(std::vector<OutputFile>* object_files);
+  void WriteLinkerStuff(const std::vector<OutputFile>& object_files);
+
+  // Writes the build line for linking the target. Includes newline.
+  void WriteLinkCommand(const OutputFile& external_output_file,
+                        const OutputFile& internal_output_file,
+                        const std::vector<OutputFile>& object_files);
+
+  DISALLOW_COPY_AND_ASSIGN(NinjaBinaryTargetWriter);
+};
+
+#endif  // TOOLS_GN_NINJA_BINARY_TARGET_WRITER_H_
+
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index c41422b..4000d0c 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -62,11 +62,13 @@
     const BuildSettings* build_settings,
     const std::vector<const Settings*>& all_settings,
     const std::vector<const Target*>& default_toolchain_targets,
-    std::ostream& out)
+    std::ostream& out,
+    std::ostream& dep_out)
     : build_settings_(build_settings),
       all_settings_(all_settings),
       default_toolchain_targets_(default_toolchain_targets),
       out_(out),
+      dep_out_(dep_out),
       path_output_(build_settings->build_dir(), ESCAPE_NINJA, true),
       helper_(build_settings) {
 }
@@ -95,8 +97,14 @@
   if (file.fail())
     return false;
 
+  std::ofstream depfile;
+  depfile.open((FilePathToUTF8(ninja_file) + ".d").c_str(),
+               std::ios_base::out | std::ios_base::binary);
+  if (depfile.fail())
+    return false;
+
   NinjaBuildWriter gen(build_settings, all_settings,
-                       default_toolchain_targets, file);
+                       default_toolchain_targets, file, depfile);
   gen.Run();
   return true;
 }
@@ -106,24 +114,25 @@
   out_ << "  command = " << GetSelfInvocationCommand(build_settings_) << "\n";
   out_ << "  description = GN the world\n\n";
 
-  out_ << "build build.ninja: gn";
+  out_ << "build build.ninja: gn\n"
+       << "  depfile = build.ninja.d\n";
 
-  // Input build files.
+  // Input build files. These go in the ".d" file. If we write them as
+  // dependencies in the .ninja file itself, ninja will expect the files to
+  // exist and will error if they don't. When files are listed in a depfile,
+  // missing files are ignored.
+  dep_out_ << "build.ninja:";
   std::vector<base::FilePath> input_files;
   g_scheduler->input_file_manager()->GetAllPhysicalInputFileNames(&input_files);
-  EscapeOptions ninja_options;
-  ninja_options.mode = ESCAPE_NINJA;
   for (size_t i = 0; i < input_files.size(); i++)
-    out_ << " " << EscapeString(FilePathToUTF8(input_files[i]), ninja_options);
+    dep_out_ << " " << FilePathToUTF8(input_files[i]);
 
   // Other files read by the build.
-  std::vector<SourceFile> other_files = g_scheduler->GetGenDependencies();
-  for (size_t i = 0; i < other_files.size(); i++) {
-    out_ << " ";
-    path_output_.WriteFile(out_, other_files[i]);
-  }
+  std::vector<base::FilePath> other_files = g_scheduler->GetGenDependencies();
+  for (size_t i = 0; i < other_files.size(); i++)
+    dep_out_ << " " << FilePathToUTF8(other_files[i]);
 
-  out_ << std::endl << std::endl;
+  out_ << std::endl;
 }
 
 void NinjaBuildWriter::WriteSubninjas() {
@@ -143,8 +152,6 @@
   // we'll get naming conflicts).
   for (size_t i = 0; i < default_toolchain_targets_.size(); i++) {
     const Target* target = default_toolchain_targets_[i];
-    if (target->output_type() == Target::NONE)
-      continue;  // Nothing to generate.
 
     OutputFile target_file = helper_.GetTargetOutputFile(target);
     if (target_file.value() != target->label().name()) {
diff --git a/tools/gn/ninja_build_writer.h b/tools/gn/ninja_build_writer.h
index 85548df..4c72ef9 100644
--- a/tools/gn/ninja_build_writer.h
+++ b/tools/gn/ninja_build_writer.h
@@ -29,7 +29,8 @@
   NinjaBuildWriter(const BuildSettings* settings,
                    const std::vector<const Settings*>& all_settings,
                    const std::vector<const Target*>& default_toolchain_targets,
-                   std::ostream& out);
+                   std::ostream& out,
+                   std::ostream& dep_out);
   ~NinjaBuildWriter();
 
   void Run();
@@ -42,6 +43,7 @@
   std::vector<const Settings*> all_settings_;
   std::vector<const Target*> default_toolchain_targets_;
   std::ostream& out_;
+  std::ostream& dep_out_;
   PathOutput path_output_;
 
   NinjaHelper helper_;
diff --git a/tools/gn/ninja_copy_target_writer.cc b/tools/gn/ninja_copy_target_writer.cc
new file mode 100644
index 0000000..4d2ebe0
--- /dev/null
+++ b/tools/gn/ninja_copy_target_writer.cc
@@ -0,0 +1,64 @@
+// 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 "tools/gn/ninja_copy_target_writer.h"
+
+#include "base/strings/string_util.h"
+#include "tools/gn/string_utils.h"
+
+NinjaCopyTargetWriter::NinjaCopyTargetWriter(const Target* target,
+                                             std::ostream& out)
+    : NinjaTargetWriter(target, out) {
+}
+
+NinjaCopyTargetWriter::~NinjaCopyTargetWriter() {
+}
+
+void NinjaCopyTargetWriter::Run() {
+  // The dest dir should be inside the output dir so we can just remove the
+  // prefix and get ninja-relative paths.
+  const std::string& output_dir =
+      settings_->build_settings()->build_dir().value();
+  const std::string& dest_dir = target_->destdir().value();
+  DCHECK(StartsWithASCII(dest_dir, output_dir, true));
+  std::string relative_dest_dir(&dest_dir[output_dir.size()],
+                                dest_dir.size() - output_dir.size());
+
+  const Target::FileList& sources = target_->sources();
+  std::vector<OutputFile> dest_files;
+  dest_files.reserve(sources.size());
+
+  // Write out rules for each file copied.
+  for (size_t i = 0; i < sources.size(); i++) {
+    const SourceFile& input_file = sources[i];
+
+    // The files should have the same name but in the dest dir.
+    base::StringPiece name_part = FindFilename(&input_file.value());
+    OutputFile dest_file(relative_dest_dir);
+    AppendStringPiece(&dest_file.value(), name_part);
+
+    dest_files.push_back(dest_file);
+
+    out_ << "build ";
+    path_output_.WriteFile(out_, dest_file);
+    out_ << ": copy ";
+    path_output_.WriteFile(out_, input_file);
+    out_ << std::endl;
+  }
+
+  // Write out the rule for the target to copy all of them.
+  out_ << std::endl << "build ";
+  path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
+  out_ << ": stamp";
+  for (size_t i = 0; i < dest_files.size(); i++) {
+    out_ << " ";
+    path_output_.WriteFile(out_, dest_files[i]);
+  }
+  out_ << std::endl;
+
+  // TODO(brettw) need some kind of stamp file for depending on this, as well
+  // as order_only=prebuild.
+  // TODO(brettw) also need to write out the dependencies of this rule (maybe
+  // we're copying output files around).
+}
diff --git a/tools/gn/ninja_copy_target_writer.h b/tools/gn/ninja_copy_target_writer.h
new file mode 100644
index 0000000..99bbaff
--- /dev/null
+++ b/tools/gn/ninja_copy_target_writer.h
@@ -0,0 +1,23 @@
+// 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 TOOLS_GN_NINJA_COPY_TARGET_WRITER_H_
+#define TOOLS_GN_NINJA_COPY_TARGET_WRITER_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/ninja_target_writer.h"
+
+// Writes a .ninja file for a copy target type.
+class NinjaCopyTargetWriter : public NinjaTargetWriter {
+ public:
+  NinjaCopyTargetWriter(const Target* target, std::ostream& out);
+  virtual ~NinjaCopyTargetWriter();
+
+  virtual void Run() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NinjaCopyTargetWriter);
+};
+
+#endif  // TOOLS_GN_NINJA_COPY_TARGET_WRITER_H_
diff --git a/tools/gn/ninja_group_target_writer.cc b/tools/gn/ninja_group_target_writer.cc
new file mode 100644
index 0000000..f31bf1a
--- /dev/null
+++ b/tools/gn/ninja_group_target_writer.cc
@@ -0,0 +1,37 @@
+// 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 "tools/gn/ninja_group_target_writer.h"
+
+#include "base/strings/string_util.h"
+#include "tools/gn/string_utils.h"
+
+NinjaGroupTargetWriter::NinjaGroupTargetWriter(const Target* target,
+                                               std::ostream& out)
+    : NinjaTargetWriter(target, out) {
+}
+
+NinjaGroupTargetWriter::~NinjaGroupTargetWriter() {
+}
+
+void NinjaGroupTargetWriter::Run() {
+  // A group rule just generates a stamp file with dependencies on each of
+  // the deps in the group.
+  out_ << std::endl << "build ";
+  path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
+  out_ << ": stamp";
+
+  const std::vector<const Target*>& deps = target_->deps();
+  for (size_t i = 0; i < deps.size(); i++) {
+    out_ << " ";
+    path_output_.WriteFile(out_, helper_.GetTargetOutputFile(deps[i]));
+  }
+
+  const std::vector<const Target*>& datadeps = target_->datadeps();
+  for (size_t i = 0; i < datadeps.size(); i++) {
+    out_ << " ";
+    path_output_.WriteFile(out_, helper_.GetTargetOutputFile(datadeps[i]));
+  }
+  out_ << std::endl;
+}
diff --git a/tools/gn/ninja_group_target_writer.h b/tools/gn/ninja_group_target_writer.h
new file mode 100644
index 0000000..31625f8
--- /dev/null
+++ b/tools/gn/ninja_group_target_writer.h
@@ -0,0 +1,23 @@
+// 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 TOOLS_GN_NINJA_GROUP_TARGET_WRITER_H_
+#define TOOLS_GN_NINJA_GROUP_TARGET_WRITER_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/ninja_target_writer.h"
+
+// Writes a .ninja file for a group target type.
+class NinjaGroupTargetWriter : public NinjaTargetWriter {
+ public:
+  NinjaGroupTargetWriter(const Target* target, std::ostream& out);
+  virtual ~NinjaGroupTargetWriter();
+
+  virtual void Run() OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NinjaGroupTargetWriter);
+};
+
+#endif  // TOOLS_GN_NINJA_GROUP_TARGET_WRITER_H_
diff --git a/tools/gn/ninja_helper.cc b/tools/gn/ninja_helper.cc
index e4f4082..15c28af 100644
--- a/tools/gn/ninja_helper.cc
+++ b/tools/gn/ninja_helper.cc
@@ -78,6 +78,7 @@
     case SOURCE_CC:
     case SOURCE_M:
     case SOURCE_MM:
+    case SOURCE_S:
       name.append(target->settings()->IsWin() ? "obj" : "o");
       break;
 
@@ -93,7 +94,10 @@
 
   // Use the scheme <path>/<target>.<name>.<extension> so that all output
   // names are unique to different targets.
-  OutputFile ret(kObjectDirNoSlash);
+
+  // This will look like "obj" or "toolchain_name/obj".
+  OutputFile ret(target->settings()->toolchain_output_subdir());
+  ret.value().append(kObjectDirNoSlash);
 
   // Find the directory, assume it starts with two slashes, and trim to one.
   base::StringPiece dir = FindDir(&source.value());
@@ -109,10 +113,6 @@
 
 OutputFile NinjaHelper::GetTargetOutputFile(const Target* target) const {
   OutputFile ret;
-  if (target->output_type() == Target::NONE) {
-    NOTREACHED();
-    return ret;
-  }
 
   // This is prepended to the output file name.
   const char* prefix;
@@ -124,7 +124,7 @@
     prefix = "";
 
   const char* extension;
-  if (target->output_type() == Target::NONE ||
+  if (target->output_type() == Target::GROUP ||
       target->output_type() == Target::COPY_FILES ||
       target->output_type() == Target::CUSTOM) {
     extension = "stamp";
@@ -139,7 +139,6 @@
 
   // Binaries and loadable libraries go into the toolchain root.
   if (target->output_type() == Target::EXECUTABLE ||
-      target->output_type() == Target::LOADABLE_MODULE ||
       (target->settings()->IsMac() &&
           (target->output_type() == Target::SHARED_LIBRARY ||
            target->output_type() == Target::STATIC_LIBRARY)) ||
@@ -173,6 +172,7 @@
   ret.value().append(kObjectDirNoSlash);
   AppendStringPiece(&ret.value(),
                     target->label().dir().SourceAbsoluteWithOneSlash());
+  ret.value().append(prefix);
   ret.value().append(target->label().name());
   if (extension[0]) {
     ret.value().push_back('.');
@@ -180,3 +180,59 @@
   }
   return ret;
 }
+
+std::string NinjaHelper::GetRulePrefix(const Toolchain* toolchain) const {
+  if (toolchain->is_default())
+    return std::string();  // Default toolchain has no prefix.
+  return toolchain->label().name() + "_";
+}
+
+std::string NinjaHelper::GetRuleForSourceType(const Settings* settings,
+                                              const Toolchain* toolchain,
+                                              SourceFileType type) const {
+  // This function may be hot since it will be called for every source file
+  // in the tree. We could cache the results to avoid making a string for
+  // every invocation.
+  std::string prefix = GetRulePrefix(toolchain);
+
+  if (type == SOURCE_C)
+    return prefix + "cc";
+  if (type == SOURCE_CC)
+    return prefix + "cxx";
+
+  // TODO(brettw) asm files.
+
+  if (settings->IsMac()) {
+    if (type == SOURCE_M)
+      return prefix + "objc";
+    if (type == SOURCE_MM)
+      return prefix + "objcxx";
+  }
+
+  if (settings->IsWin()) {
+    if (type == SOURCE_RC)
+      return prefix + "rc";
+  } else {
+    if (type == SOURCE_S)
+      return prefix + "cc";  // Assembly files just get compiled by CC.
+  }
+
+  return std::string();
+}
+
+std::string NinjaHelper::GetRuleForTargetType(
+    const Toolchain* toolchain,
+    Target::OutputType target_type) const {
+  std::string prefix = GetRulePrefix(toolchain);
+
+  if (target_type == Target::STATIC_LIBRARY) {
+    // TODO(brettw) stuff about standalong static libraryes on Unix in
+    // WriteTarget in the Python one, and lots of postbuild steps.
+    return prefix + "alink";
+  }
+
+  if (target_type == Target::SHARED_LIBRARY)
+    return prefix + "solink";
+
+  return prefix + "link";
+}
diff --git a/tools/gn/ninja_helper.h b/tools/gn/ninja_helper.h
index 5bea29e..e893f79 100644
--- a/tools/gn/ninja_helper.h
+++ b/tools/gn/ninja_helper.h
@@ -10,6 +10,7 @@
 
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/output_file.h"
+#include "tools/gn/target.h"
 
 class BuildSettings;
 class SourceDir;
@@ -39,8 +40,8 @@
   // Given a source file relative to the source root, returns the output
   // filename.
   OutputFile GetOutputFileForSource(const Target* target,
-                                   const SourceFile& source,
-                                   SourceFileType type) const;
+                                    const SourceFile& source,
+                                    SourceFileType type) const;
 
   // Returns the filename produced by the given output.
   //
@@ -49,6 +50,18 @@
   // link to (so in this example, the import library).
   OutputFile GetTargetOutputFile(const Target* target) const;
 
+  // Returns the prefix for rules on the given toolchain. We need this to
+  // disambiguate a given rule for each toolchain.
+  std::string GetRulePrefix(const Toolchain* toolchain) const;
+
+  // Returns the name of the rule name for the given toolchain and file/target
+  // type.  Returns the empty string for source files with no command.
+  std::string GetRuleForSourceType(const Settings* settings,
+                                   const Toolchain* toolchain,
+                                   SourceFileType type) const;
+  std::string GetRuleForTargetType(const Toolchain* toolchain,
+                                   Target::OutputType target_type) const;
+
   // Returns the relative directory in either slashes or the system separator
   // from the ninja directory (e.g. "out/Debug") to the source root (e.g.
   // "../.."). It has no terminating slash.
diff --git a/tools/gn/ninja_script_target_writer.cc b/tools/gn/ninja_script_target_writer.cc
new file mode 100644
index 0000000..e259fff
--- /dev/null
+++ b/tools/gn/ninja_script_target_writer.cc
@@ -0,0 +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 "tools/gn/ninja_script_target_writer.h"
+
+#include "base/strings/string_util.h"
+#include "tools/gn/err.h"
+#include "tools/gn/file_template.h"
+#include "tools/gn/string_utils.h"
+#include "tools/gn/target.h"
+
+NinjaScriptTargetWriter::NinjaScriptTargetWriter(const Target* target,
+                                                 std::ostream& out)
+    : NinjaTargetWriter(target, out) {
+}
+
+NinjaScriptTargetWriter::~NinjaScriptTargetWriter() {
+}
+
+void NinjaScriptTargetWriter::Run() {
+  WriteEnvironment();
+
+  // Run the script from the dir of the BUILD file. This has no trailing
+  // slash.
+  const SourceDir& script_cd = target_->label().dir();
+  std::string script_cd_to_root = InvertDir(script_cd);
+  if (script_cd_to_root.empty()) {
+    script_cd_to_root = ".";
+  } else {
+    // Remove trailing slash.
+    DCHECK(script_cd_to_root[script_cd_to_root.size() - 1] == '/');
+    script_cd_to_root.resize(script_cd_to_root.size() - 1);
+  }
+
+  // Compute the relative script file name. The script string should start with
+  // 2 slashes, and we trim 1.
+  DCHECK(target_->script_values().script().is_source_absolute());
+  std::string script_relative_to_cd = script_cd_to_root;
+  const std::string& script_string = target_->script_values().script().value();
+  script_relative_to_cd.append(&script_string[1], script_string.size() - 1);
+
+  std::string custom_rule_name = WriteRuleDefinition(script_relative_to_cd);
+
+  // Precompute the common dependencies for each step. This includes the
+  // script itself (changing the script should force a rebuild) and any data
+  // files.
+  //
+  // TODO(brettw) this needs to be re-thought. "data" is supposed to be runtime
+  // data (i.e. for tests and such) rather than compile-time dependencies for
+  // each target. If we really need this, we need to have a different way to
+  // express it.
+  //
+  // One idea: add an "inputs" variable to specify this kind of thing. We
+  // should probably make it an error to specify data but no inputs for a
+  // script as a way to catch people doing the wrong way.
+  std::ostringstream common_deps_stream;
+  path_output_.WriteFile(common_deps_stream, target_->script_values().script());
+  const Target::FileList& datas = target_->data();
+  for (size_t i = 0; i < datas.size(); i++) {
+    common_deps_stream << " ";
+    path_output_.WriteFile(common_deps_stream, datas[i]);
+  }
+  const std::string& common_deps = common_deps_stream.str();
+
+  // Collects all output files for writing below.
+  std::vector<OutputFile> output_files;
+
+  if (has_sources()) {
+    // Write separate rules for each input source file.
+    WriteSourceRules(custom_rule_name, common_deps, script_cd,
+                     script_cd_to_root, &output_files);
+  } else {
+    // No sources, write a rule that invokes the script once with the
+    // outputs as outputs, and the data as inputs.
+    out_ << "build";
+    const Target::FileList& outputs = target_->script_values().outputs();
+    for (size_t i = 0; i < outputs.size(); i++) {
+      OutputFile output_path(
+          RemovePrefix(outputs[i].value(),
+                       settings_->build_settings()->build_dir().value()));
+      output_files.push_back(output_path);
+      out_ << " ";
+      path_output_.WriteFile(out_, output_path);
+    }
+    out_ << ": " << custom_rule_name << " " << common_deps << std::endl;
+  }
+  out_ << std::endl;
+
+  WriteStamp(output_files);
+}
+
+std::string NinjaScriptTargetWriter::WriteRuleDefinition(
+    const std::string& script_relative_to_cd) {
+  // Make a unique name for this rule.
+  std::string target_label = target_->label().GetUserVisibleName(true);
+  std::string custom_rule_name(target_label);
+  ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
+  custom_rule_name.append("_rule");
+
+  // Use a unique name for the response file when there are multiple build
+  // steps so that they don't stomp on each other. When there are no sources,
+  // there will be only one invocation so we can use a simple name.
+
+  if (settings_->IsWin()) {
+    // Send through gyp-win-tool and use a response file.
+    std::string rspfile = custom_rule_name;
+    if (has_sources())
+      rspfile += ".$unique_name";
+    rspfile += ".rsp";
+
+    out_ << "rule " << custom_rule_name << std::endl;
+    out_ << "  command = $pythonpath gyp-win-tool action-wrapper $arch "
+         << rspfile << " ";
+    path_output_.WriteDir(out_, target_->label().dir(),
+                          PathOutput::DIR_NO_LAST_SLASH);
+    out_ << std::endl;
+    out_ << "  description = CUSTOM " << target_label << std::endl;
+    out_ << "  restat = 1" << std::endl;
+    out_ << "  rspfile = " << rspfile << std::endl;
+
+    // The build command goes in the rsp file.
+    out_ << "  rspfile_content = $pythonpath " << script_relative_to_cd;
+    for (size_t i = 0; i < target_->script_values().args().size(); i++) {
+      const std::string& arg = target_->script_values().args()[i];
+      out_ << " ";
+      WriteArg(arg);
+    }
+  } 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 " << script_relative_to_cd;
+    for (size_t i = 0; i < target_->script_values().args().size(); i++) {
+      const std::string& arg = target_->script_values().args()[i];
+      out_ << " ";
+      WriteArg(arg);
+    }
+    out_ << std::endl;
+    out_ << "  description = CUSTOM " << target_label << std::endl;
+    out_ << "  restat = 1" << std::endl;
+  }
+
+  out_ << std::endl;
+  return custom_rule_name;
+}
+
+void NinjaScriptTargetWriter::WriteArg(const std::string& arg) {
+  // This can be optimized if it's called a lot.
+  EscapeOptions options;
+  options.mode = ESCAPE_NINJA;
+  std::string output_str = EscapeString(arg, options);
+
+  // Do this substitution after escaping our our $ will be escaped (which we
+  // don't want).
+  ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSource,
+                               "${source}");
+  ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSourceNamePart,
+                               "${source_name_part}");
+  out_ << output_str;
+}
+
+void NinjaScriptTargetWriter::WriteSourceRules(
+    const std::string& custom_rule_name,
+    const std::string& common_deps,
+    const SourceDir& script_cd,
+    const std::string& script_cd_to_root,
+    std::vector<OutputFile>* output_files) {
+  // Construct the template for generating the output files from each source.
+  const Target::FileList& outputs = target_->script_values().outputs();
+  std::vector<std::string> output_template_args;
+  for (size_t i = 0; i < outputs.size(); i++) {
+    // All outputs should be in the output dir.
+    output_template_args.push_back(
+        RemovePrefix(outputs[i].value(),
+                     settings_->build_settings()->build_dir().value()));
+  }
+  FileTemplate output_template(output_template_args);
+
+  // Prevent re-allocating each time by initializing outside the loop.
+  std::vector<std::string> output_template_result;
+
+  // Path output formatter for wrigin source paths passed to the script.
+  PathOutput script_source_path_output(script_cd, ESCAPE_SHELL, true);
+
+  const Target::FileList& sources = target_->sources();
+  for (size_t i = 0; i < sources.size(); i++) {
+    // Write outputs for this source file computed by the template.
+    out_ << "build";
+    output_template.ApplyString(sources[i].value(), &output_template_result);
+    for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) {
+      OutputFile output_path(output_template_result[out_i]);
+      output_files->push_back(output_path);
+      out_ << " ";
+      path_output_.WriteFile(out_, output_path);
+    }
+
+    out_ << ": " << custom_rule_name
+         << " " << common_deps
+         << " ";
+    path_output_.WriteFile(out_, sources[i]);
+    out_ << std::endl;
+
+    out_ << "  unique_name = " << i << std::endl;
+
+    // The source file here should be relative to the script directory since
+    // this is the variable passed to the script. Here we slightly abuse the
+    // OutputFile object by putting a non-output-relative path in it to signal
+    // that the PathWriter should not prepend directories.
+    out_ << "  source = ";
+    script_source_path_output.WriteFile(out_, sources[i]);
+    out_ << std::endl;
+
+    out_ << "  source_name_part = "
+         << FindFilenameNoExtension(&sources[i].value()).as_string()
+         << std::endl;
+  }
+}
+
+void NinjaScriptTargetWriter::WriteStamp(
+    const std::vector<OutputFile>& output_files) {
+  out_ << "build ";
+  path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
+  out_ << ": stamp";
+  for (size_t i = 0; i < output_files.size(); i++) {
+    out_ << " ";
+    path_output_.WriteFile(out_, output_files[i]);
+  }
+  out_ << std::endl;
+}
diff --git a/tools/gn/ninja_script_target_writer.h b/tools/gn/ninja_script_target_writer.h
new file mode 100644
index 0000000..27ba45d
--- /dev/null
+++ b/tools/gn/ninja_script_target_writer.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 TOOLS_GN_NINJA_SCRIPT_TARGET_WRITER_H_
+#define TOOLS_GN_NINJA_SCRIPT_TARGET_WRITER_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/ninja_target_writer.h"
+
+// Writes a .ninja file for a custom script target type.
+class NinjaScriptTargetWriter : public NinjaTargetWriter {
+ public:
+  NinjaScriptTargetWriter(const Target* target, std::ostream& out);
+  virtual ~NinjaScriptTargetWriter();
+
+  virtual void Run() OVERRIDE;
+
+ private:
+  bool has_sources() const { return !target_->sources().empty(); }
+
+  // Writes the Ninja rule for invoking the script.
+  //
+  // Returns the name of the custom rule generated. This will be based on the
+  // target name, and will include the string "$unique_name" if there are
+  // multiple inputs.
+  std::string WriteRuleDefinition(const std::string& script_relative_to_cd);
+
+  // Writes the rules for compiling each source, writing all output files
+  // to the given vector.
+  //
+  // common_deps is a precomputed string of all ninja files that are common
+  // to each build step. This is added to each one.
+  void WriteSourceRules(const std::string& custom_rule_name,
+                        const std::string& common_deps,
+                        const SourceDir& script_cd,
+                        const std::string& script_cd_to_root,
+                        std::vector<OutputFile>* output_files);
+
+  void WriteArg(const std::string& arg);
+
+  // Writes the .stamp rule that names this target and collects all invocations
+  // of the script into one thing that other targets can depend on.
+  void WriteStamp(const std::vector<OutputFile>& output_files);
+
+  DISALLOW_COPY_AND_ASSIGN(NinjaScriptTargetWriter);
+};
+
+#endif  // TOOLS_GN_NINJA_SCRIPT_TARGET_WRITER_H_
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index 7ff6df0..2852c9f 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -8,62 +8,14 @@
 #include <sstream>
 
 #include "base/file_util.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "tools/gn/config_values_extractors.h"
 #include "tools/gn/err.h"
-#include "tools/gn/escape.h"
-#include "tools/gn/file_template.h"
-#include "tools/gn/filesystem_utils.h"
-#include "tools/gn/location.h"
-#include "tools/gn/path_output.h"
+#include "tools/gn/ninja_binary_target_writer.h"
+#include "tools/gn/ninja_copy_target_writer.h"
+#include "tools/gn/ninja_group_target_writer.h"
+#include "tools/gn/ninja_script_target_writer.h"
 #include "tools/gn/scheduler.h"
-#include "tools/gn/string_utils.h"
 #include "tools/gn/target.h"
 
-namespace {
-
-static const char kCustomTargetSourceKey[] = "{{source}}";
-static const char kCustomTargetSourceNamePartKey[] = "{{source_name_part}}";
-
-struct DefineWriter {
-  void operator()(const std::string& s, std::ostream& out) const {
-    out << " -D" << s;
-  }
-};
-
-struct IncludeWriter {
-  IncludeWriter(PathOutput& path_output,
-                const NinjaHelper& h)
-      : helper(h),
-        path_output_(path_output),
-        old_inhibit_quoting_(path_output.inhibit_quoting()) {
-    // Inhibit quoting since we'll put quotes around the whole thing ourselves.
-    // Since we're writing in NINJA escaping mode, this won't actually do
-    // anything, but I think we may need to change to shell-and-then-ninja
-    // escaping for this in the future.
-    path_output_.set_inhibit_quoting(true);
-  }
-  ~IncludeWriter() {
-    path_output_.set_inhibit_quoting(old_inhibit_quoting_);
-  }
-
-  void operator()(const SourceDir& d, std::ostream& out) const {
-    out << " \"-I";
-    // It's important not to include the trailing slash on directories or on
-    // Windows it will be a backslash and the compiler might think we're
-    // escaping the quote!
-    path_output_.WriteDir(out, d, PathOutput::DIR_NO_LAST_SLASH);
-    out << "\"";
-  }
-
-  const NinjaHelper& helper;
-  PathOutput& path_output_;
-  bool old_inhibit_quoting_;  // So we can put the PathOutput back.
-};
-
-}  // namespace
-
 NinjaTargetWriter::NinjaTargetWriter(const Target* target, std::ostream& out)
     : settings_(target->settings()),
       target_(target),
@@ -76,30 +28,8 @@
 NinjaTargetWriter::~NinjaTargetWriter() {
 }
 
-void NinjaTargetWriter::Run() {
-  // TODO(brettw) have a better way to do the environment setup on Windows.
-  if (target_->settings()->IsWin())
-    out_ << "arch = environment.x86\n";
-
-  if (target_->output_type() == Target::COPY_FILES) {
-    WriteCopyRules();
-  } else if (target_->output_type() == Target::CUSTOM) {
-    WriteCustomRules();
-  } else {
-    WriteCompilerVars();
-
-    std::vector<OutputFile> obj_files;
-    WriteSources(&obj_files);
-
-    WriteLinkerStuff(obj_files);
-  }
-}
-
 // static
 void NinjaTargetWriter::RunAndWriteFile(const Target* target) {
-  if (target->output_type() == Target::NONE)
-    return;
-
   const Settings* settings = target->settings();
   NinjaHelper helper(settings->build_settings());
 
@@ -123,496 +53,35 @@
     return;
   }
 
-  NinjaTargetWriter gen(target, file);
-  gen.Run();
+  // Call out to the correct sub-type of writer.
+  if (target->output_type() == Target::COPY_FILES) {
+    NinjaCopyTargetWriter writer(target, file);
+    writer.Run();
+  } else if (target->output_type() == Target::CUSTOM) {
+    NinjaScriptTargetWriter writer(target, file);
+    writer.Run();
+  } else if (target->output_type() == Target::GROUP) {
+    NinjaGroupTargetWriter writer(target, file);
+    writer.Run();
+  } else if (target->output_type() == Target::EXECUTABLE ||
+             target->output_type() == Target::STATIC_LIBRARY ||
+             target->output_type() == Target::SHARED_LIBRARY) {
+    NinjaBinaryTargetWriter writer(target, file);
+    writer.Run();
+  } else {
+    CHECK(0);
+  }
 
   std::string contents = file.str();
   file_util::WriteFile(ninja_file, contents.c_str(), contents.size());
 }
 
-void NinjaTargetWriter::WriteCopyRules() {
-  // The dest dir should be inside the output dir so we can just remove the
-  // prefix and get ninja-relative paths.
-  const std::string& output_dir =
-      settings_->build_settings()->build_dir().value();
-  const std::string& dest_dir = target_->destdir().value();
-  DCHECK(StartsWithASCII(dest_dir, output_dir, true));
-  std::string relative_dest_dir(&dest_dir[output_dir.size()],
-                                dest_dir.size() - output_dir.size());
-
-  const Target::FileList& sources = target_->sources();
-  std::vector<OutputFile> dest_files;
-  dest_files.reserve(sources.size());
-
-  // Write out rules for each file copied.
-  for (size_t i = 0; i < sources.size(); i++) {
-    const SourceFile& input_file = sources[i];
-
-    // The files should have the same name but in the dest dir.
-    base::StringPiece name_part = FindFilename(&input_file.value());
-    OutputFile dest_file(relative_dest_dir);
-    AppendStringPiece(&dest_file.value(), name_part);
-
-    dest_files.push_back(dest_file);
-
-    out_ << "build ";
-    path_output_.WriteFile(out_, dest_file);
-    out_ << ": copy ";
-    path_output_.WriteFile(out_, input_file);
-    out_ << std::endl;
-  }
-
-  // Write out the rule for the target to copy all of them.
-  out_ << std::endl << "build ";
-  path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
-  out_ << ": stamp";
-  for (size_t i = 0; i < dest_files.size(); i++) {
-    out_ << " ";
-    path_output_.WriteFile(out_, dest_files[i]);
-  }
-  out_ << std::endl;
-
-  // TODO(brettw) need some kind of stamp file for depending on this, as well
-  // as order_only=prebuild.
+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";
 }
 
-void NinjaTargetWriter::WriteCustomRules() {
-  // Make a unique name for this rule.
-  std::string target_label = target_->label().GetUserVisibleName(true);
-  std::string custom_rule_name(target_label);
-  ReplaceChars(custom_rule_name, ":/()", "_", &custom_rule_name);
-  custom_rule_name.append("_rule");
-
-  // Run the script from the dir of the BUILD file. This has no trailing
-  // slash.
-  const SourceDir& script_cd = target_->label().dir();
-  std::string script_cd_to_root = InvertDir(script_cd);
-  if (script_cd_to_root.empty()) {
-    script_cd_to_root = ".";
-  } else {
-    // Remove trailing slash
-    DCHECK(script_cd_to_root[script_cd_to_root.size() - 1] == '/');
-    script_cd_to_root.resize(script_cd_to_root.size() - 1);
-  }
-
-  std::string script_relative_to_cd =
-      script_cd_to_root + target_->script().value();
-
-  bool no_sources = target_->sources().empty();
-
-  // Use a unique name for the response file when there are multiple build
-  // steps so that they don't stomp on each other.
-  std::string rspfile = custom_rule_name;
-  if (!no_sources)
-    rspfile += ".$unique_name";
-  rspfile += ".rsp";
-
-  // First write the custom rule.
-  out_ << "rule " << custom_rule_name << std::endl;
-  out_ << "  command = $pythonpath gyp-win-tool action-wrapper $arch "
-       << rspfile << " ";
-  path_output_.WriteDir(out_, script_cd, PathOutput::DIR_NO_LAST_SLASH);
-  out_ << std::endl;
-  out_ << "  description = CUSTOM " << target_label << std::endl;
-  out_ << "  restat = 1" << std::endl;
-  out_ << "  rspfile = " << rspfile << std::endl;
-
-  // The build command goes in the rsp file.
-  out_ << "  rspfile_content = $pythonpath " << script_relative_to_cd;
-  for (size_t i = 0; i < target_->script_args().size(); i++) {
-    const std::string& arg = target_->script_args()[i];
-    out_ << " ";
-    WriteCustomArg(arg);
-  }
-  out_ << std::endl << std::endl;
-
-  // Precompute the common dependencies for each step. This includes the
-  // script itself (changing the script should force a rebuild) and any data
-  // files.
-  //
-  // TODO(brettW) this needs to be re-thought. "data" is supposed to be runtime
-  // data (i.e. for tests and such) rather than compile-time dependencies for
-  // each target. If we really need this, we need to have a different way to
-  // express it.
-  //
-  // One idea: add an "inputs" variable to specify this kind of thing. We
-  // should probably make it an error to specify data but no inputs for a
-  // script as a way to catch people doing the wrong way.
-  std::ostringstream common_deps_stream;
-  path_output_.WriteFile(common_deps_stream, target_->script());
-  const Target::FileList& datas = target_->data();
-  for (size_t i = 0; i < datas.size(); i++) {
-    common_deps_stream << " ";
-    path_output_.WriteFile(common_deps_stream, datas[i]);
-  }
-  const std::string& common_deps = common_deps_stream.str();
-
-  // Collects all output files for writing below.
-  std::vector<OutputFile> output_files;
-
-  if (no_sources) {
-    // No sources, write a rule that invokes the script once with the
-    // outputs as outputs, and the data as inputs.
-    out_ << "build";
-    const Target::FileList& outputs = target_->outputs();
-    for (size_t i = 0; i < outputs.size(); i++) {
-      OutputFile output_path(
-          RemovePrefix(outputs[i].value(),
-                       settings_->build_settings()->build_dir().value()));
-      output_files.push_back(output_path);
-      out_ << " ";
-      path_output_.WriteFile(out_, output_path);
-    }
-    out_ << ": " << custom_rule_name << " " << common_deps << std::endl;
-  } else {
-    // Write separate rules for each input source file.
-    WriteCustomSourceRules(custom_rule_name, common_deps, script_cd,
-                           script_cd_to_root, &output_files);
-  }
-  out_ << std::endl;
-
-  // Last write a stamp rule to collect all outputs.
-  out_ << "build ";
-  path_output_.WriteFile(out_, helper_.GetTargetOutputFile(target_));
-  out_ << ": stamp";
-  for (size_t i = 0; i < output_files.size(); i++) {
-    out_ << " ";
-    path_output_.WriteFile(out_, output_files[i]);
-  }
-  out_ << std::endl;
-}
-
-void NinjaTargetWriter::WriteCustomArg(const std::string& arg) {
-  // This can be optimized if it's called a lot.
-  EscapeOptions options;
-  options.mode = ESCAPE_NINJA;
-  std::string output_str = EscapeString(arg, options);
-
-  // Do this substitution after escaping our our $ will be escaped (which we
-  // don't want).
-  ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSource,
-                               "${source}");
-  ReplaceSubstringsAfterOffset(&output_str, 0, FileTemplate::kSourceNamePart,
-                               "${source_name_part}");
-  out_ << output_str;
-}
-
-void NinjaTargetWriter::WriteCustomSourceRules(
-    const std::string& custom_rule_name,
-    const std::string& common_deps,
-    const SourceDir& script_cd,
-    const std::string& script_cd_to_root,
-    std::vector<OutputFile>* output_files) {
-  // Construct the template for generating the output files from each source.
-  const Target::FileList& outputs = target_->outputs();
-  std::vector<std::string> output_template_args;
-  for (size_t i = 0; i < outputs.size(); i++) {
-    // All outputs should be in the output dir.
-    output_template_args.push_back(
-        RemovePrefix(outputs[i].value(),
-                     settings_->build_settings()->build_dir().value()));
-  }
-  FileTemplate output_template(output_template_args);
-
-  // Prevent re-allocating each time by initializing outside the loop.
-  std::vector<std::string> output_template_result;
-
-  // Path output formatter for wrigin source paths passed to the script.
-  PathOutput script_source_path_output(script_cd, ESCAPE_SHELL, true);
-
-  const Target::FileList& sources = target_->sources();
-  for (size_t i = 0; i < sources.size(); i++) {
-    // Write outputs for this source file computed by the template.
-    out_ << "build";
-    output_template.ApplyString(sources[i].value(), &output_template_result);
-    for (size_t out_i = 0; out_i < output_template_result.size(); out_i++) {
-      OutputFile output_path(output_template_result[out_i]);
-      output_files->push_back(output_path);
-      out_ << " ";
-      path_output_.WriteFile(out_, output_path);
-    }
-
-    out_ << ": " << custom_rule_name
-         << " " << common_deps
-         << " ";
-    path_output_.WriteFile(out_, sources[i]);
-    out_ << std::endl;
-
-    out_ << "  unique_name = " << i << std::endl;
-
-    // The source file here should be relative to the script directory since
-    // this is the variable passed to the script. Here we slightly abuse the
-    // OutputFile object by putting a non-output-relative path in it to signal
-    // that the PathWriter should not prepend directories.
-    out_ << "  source = ";
-    script_source_path_output.WriteFile(out_, sources[i]);
-    out_ << std::endl;
-
-    out_ << "  source_name_part = "
-         << FindFilenameNoExtension(&sources[i].value()).as_string()
-         << std::endl;
-  }
-}
-
-void NinjaTargetWriter::WriteCompilerVars() {
-  // Defines.
-  out_ << "defines =";
-  RecursiveTargetConfigToStream(target_, &ConfigValues::defines,
-                                DefineWriter(), out_);
-  out_ << std::endl;
-
-  // Includes.
-  out_ << "includes =";
-  RecursiveTargetConfigToStream(target_, &ConfigValues::includes,
-                                IncludeWriter(path_output_, helper_), out_);
-
-  out_ << std::endl;
-
-  // C flags and friends.
-#define WRITE_FLAGS(name) \
-    out_ << #name " ="; \
-    RecursiveTargetConfigStringsToStream(target_, &ConfigValues::name, out_); \
-    out_ << std::endl;
-
-  WRITE_FLAGS(cflags)
-  WRITE_FLAGS(cflags_c)
-  WRITE_FLAGS(cflags_cc)
-  WRITE_FLAGS(cflags_objc)
-  WRITE_FLAGS(cflags_objcc)
-
-#undef WRITE_FLAGS
-
-  out_ << std::endl;
-}
-
-void NinjaTargetWriter::WriteSources(
-    std::vector<OutputFile>* object_files) {
-  const Target::FileList& sources = target_->sources();
-  object_files->reserve(sources.size());
-
-  for (size_t i = 0; i < sources.size(); i++) {
-    const SourceFile& input_file = sources[i];
-
-    SourceFileType input_file_type = GetSourceFileType(input_file,
-                                                       settings_->target_os());
-    if (input_file_type == SOURCE_UNKNOWN)
-      continue;  // Skip unknown file types.
-    const char* command = GetCommandForSourceType(input_file_type);
-    if (!command)
-      continue;  // Skip files not needing compilation.
-
-    OutputFile output_file = helper_.GetOutputFileForSource(
-        target_, input_file, input_file_type);
-    object_files->push_back(output_file);
-
-    out_ << "build ";
-    path_output_.WriteFile(out_, output_file);
-    out_ << ": " << command << " ";
-    path_output_.WriteFile(out_, input_file);
-    out_ << std::endl;
-  }
-  out_ << std::endl;
-}
-
-void NinjaTargetWriter::WriteLinkerStuff(
-    const std::vector<OutputFile>& object_files) {
-  // Manifest file on Windows.
-  // TODO(brettw) this seems not to be necessary for static libs, skip in
-  // that case?
-  OutputFile windows_manifest;
-  if (settings_->IsWin()) {
-    windows_manifest.value().assign(helper_.GetTargetOutputDir(target_));
-    windows_manifest.value().append(target_->label().name());
-    windows_manifest.value().append(".intermediate.manifest");
-    out_ << "manifests = ";
-    path_output_.WriteFile(out_, windows_manifest);
-    out_ << std::endl;
-  }
-
-  // Linker flags, append manifest flag on Windows to reference our file.
-  out_ << "ldflags =";
-  RecursiveTargetConfigStringsToStream(target_, &ConfigValues::ldflags, out_);
-  // HACK ERASEME BRETTW FIXME
-  if (settings_->IsWin()) {
-    out_ << " /MANIFEST /ManifestFile:";
-    path_output_.WriteFile(out_, windows_manifest);
-    out_ << " /DEBUG /MACHINE:X86 /LIBPATH:\"C:\\Program Files (x86)\\Windows Kits\\8.0\\Lib\\win8\\um\\x86\" /DELAYLOAD:dbghelp.dll /DELAYLOAD:dwmapi.dll /DELAYLOAD:shell32.dll /DELAYLOAD:uxtheme.dll /safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat /SUBSYSTEM:CONSOLE /INCREMENTAL /FIXED:NO /DYNAMICBASE:NO wininet.lib dnsapi.lib version.lib msimg32.lib ws2_32.lib usp10.lib psapi.lib dbghelp.lib winmm.lib shlwapi.lib kernel32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib user32.lib uuid.lib odbc32.lib odbccp32.lib delayimp.lib /NXCOMPAT";
-  }
-  out_ << std::endl;
-
-  // Libraries to link.
-  out_ << "libs =";
-  if (settings_->IsMac()) {
-    // TODO(brettw) fix this.
-    out_ << " -framework AppKit -framework ApplicationServices -framework Carbon -framework CoreFoundation -framework Foundation -framework IOKit -framework Security";
-  }
-  out_ << std::endl;
-
-  // The external output file is the one that other libs depend on.
-  OutputFile external_output_file = helper_.GetTargetOutputFile(target_);
-
-  // The internal output file is the "main thing" we think we're making. In
-  // the case of shared libraries, this is the shared library and the external
-  // output file is the import library. In other cases, the internal one and
-  // the external one are the same.
-  OutputFile internal_output_file;
-  if (target_->output_type() == Target::SHARED_LIBRARY) {
-    if (settings_->IsWin()) {
-      internal_output_file = OutputFile(target_->label().name() + ".dll");
-    } else {
-      internal_output_file = external_output_file;
-    }
-  } else {
-    internal_output_file = external_output_file;
-  }
-
-  // In Python see "self.ninja.build(output, command, input,"
-  WriteLinkCommand(external_output_file, internal_output_file, object_files);
-
-  if (target_->output_type() == Target::SHARED_LIBRARY) {
-    out_ << "  soname = ";
-    path_output_.WriteFile(out_, internal_output_file);
-    out_ << std::endl;
-
-    out_ << "  lib = ";
-    path_output_.WriteFile(out_, internal_output_file);
-    out_ << std::endl;
-
-    out_ << "  dll = ";
-    path_output_.WriteFile(out_, internal_output_file);
-    out_ << std::endl;
-
-    if (settings_->IsWin()) {
-      out_ << "  implibflag = /IMPLIB:";
-      path_output_.WriteFile(out_, external_output_file);
-      out_ << std::endl;
-    }
-
-    // TODO(brettw) postbuild steps.
-    if (settings_->IsMac())
-      out_ << "  postbuilds = $ && (export BUILT_PRODUCTS_DIR=/Users/brettw/prj/src/out/gn; export CONFIGURATION=Debug; export DYLIB_INSTALL_NAME_BASE=@rpath; export EXECUTABLE_NAME=libbase.dylib; export EXECUTABLE_PATH=libbase.dylib; export FULL_PRODUCT_NAME=libbase.dylib; export LD_DYLIB_INSTALL_NAME=@rpath/libbase.dylib; export MACH_O_TYPE=mh_dylib; export PRODUCT_NAME=base; export PRODUCT_TYPE=com.apple.product-type.library.dynamic; export SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk; export SRCROOT=/Users/brettw/prj/src/out/gn/../../base; export SOURCE_ROOT=\"$${SRCROOT}\"; export TARGET_BUILD_DIR=/Users/brettw/prj/src/out/gn; export TEMP_DIR=\"$${TMPDIR}\"; (cd ../../base && ../build/mac/strip_from_xcode); G=$$?; ((exit $$G) || rm -rf libbase.dylib) && exit $$G)";
-  }
-
-  out_ << std::endl;
-}
-
-void NinjaTargetWriter::WriteLinkCommand(
-    const OutputFile& external_output_file,
-    const OutputFile& internal_output_file,
-    const std::vector<OutputFile>& object_files) {
-  out_ << "build ";
-  path_output_.WriteFile(out_, internal_output_file);
-  if (external_output_file != internal_output_file) {
-    out_ << " ";
-    path_output_.WriteFile(out_, external_output_file);
-  }
-  out_ << ": " << GetCommandForTargetType();
-
-  // Object files.
-  for (size_t i = 0; i < object_files.size(); i++) {
-    out_ << " ";
-    path_output_.WriteFile(out_, object_files[i]);
-  }
-
-  // Library inputs (deps and inherited static libraries).
-  //
-  // Static libraries since they're just a collection of the object files so
-  // don't need libraries linked with them, but we still need to go through
-  // the list and find non-linkable data deps in the "deps" section. We'll
-  // collect all non-linkable deps and put it in the order-only deps below.
-  std::vector<const Target*> extra_data_deps;
-  const std::vector<const Target*>& deps = target_->deps();
-  const std::set<const Target*>& inherited = target_->inherited_libraries();
-  for (size_t i = 0; i < deps.size(); i++) {
-    if (inherited.find(deps[i]) != inherited.end())
-      continue;
-    if (target_->output_type() != Target::STATIC_LIBRARY &&
-        deps[i]->IsLinkable()) {
-      out_ << " ";
-      path_output_.WriteFile(out_, helper_.GetTargetOutputFile(deps[i]));
-    } else {
-      extra_data_deps.push_back(deps[i]);
-    }
-  }
-  for (std::set<const Target*>::const_iterator i = inherited.begin();
-       i != inherited.end(); ++i) {
-    if (target_->output_type() == Target::STATIC_LIBRARY) {
-      extra_data_deps.push_back(*i);
-    } else {
-      out_ << " ";
-      path_output_.WriteFile(out_, helper_.GetTargetOutputFile(*i));
-    }
-  }
-
-  // Append data dependencies as order-only dependencies.
-  const std::vector<const Target*>& datadeps = target_->datadeps();
-  const std::vector<SourceFile>& data = target_->data();
-  if (!extra_data_deps.empty() || !datadeps.empty() || !data.empty()) {
-    out_ << " ||";
-
-    // Non-linkable deps in the deps section above.
-    for (size_t i = 0; i < extra_data_deps.size(); i++) {
-      out_ << " ";
-      path_output_.WriteFile(out_,
-                             helper_.GetTargetOutputFile(extra_data_deps[i]));
-    }
-
-    // Data deps.
-    for (size_t i = 0; i < datadeps.size(); i++) {
-      out_ << " ";
-      path_output_.WriteFile(out_, helper_.GetTargetOutputFile(datadeps[i]));
-    }
-
-    // Data files.
-    const std::vector<SourceFile>& data = target_->data();
-    for (size_t i = 0; i < data.size(); i++) {
-      out_ << " ";
-      path_output_.WriteFile(out_, data[i]);
-    }
-  }
-
-  out_ << std::endl;
-}
-
-const char* NinjaTargetWriter::GetCommandForSourceType(
-    SourceFileType type) const {
-  if (type == SOURCE_C)
-    return "cc";
-  if (type == SOURCE_CC)
-    return "cxx";
-
-  // TODO(brettw) asm files.
-
-  if (settings_->IsMac()) {
-    if (type == SOURCE_M)
-      return "objc";
-    if (type == SOURCE_MM)
-      return "objcxx";
-  }
-
-  if (settings_->IsWin()) {
-    if (type == SOURCE_RC)
-      return "rc";
-  }
-
-  // TODO(brettw) stuff about "S" files on non-Windows.
-  return NULL;
-}
-
-const char* NinjaTargetWriter::GetCommandForTargetType() const {
-  if (target_->output_type() == Target::NONE) {
-    NOTREACHED();
-    return "";
-  }
-
-  if (target_->output_type() == Target::STATIC_LIBRARY) {
-    // TODO(brettw) stuff about standalong static libraryes on Unix in
-    // WriteTarget in the Python one, and lots of postbuild steps.
-    return "alink";
-  }
-
-  if (target_->output_type() == Target::SHARED_LIBRARY)
-    return "solink";
-
-  return "link";
+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 076f8b3..4662200 100644
--- a/tools/gn/ninja_target_writer.h
+++ b/tools/gn/ninja_target_writer.h
@@ -6,58 +6,30 @@
 #define TOOLS_GN_NINJA_TARGET_WRITER_H_
 
 #include <iosfwd>
-#include <string>
 
 #include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "tools/gn/filesystem_utils.h"
 #include "tools/gn/ninja_helper.h"
 #include "tools/gn/path_output.h"
-#include "tools/gn/settings.h"
 
+class Settings;
 class Target;
 
 // Generates one target's ".ninja" file. The toplevel "build.ninja" file is
-// generated by the NinjaBuildGenerator.
+// generated by the NinjaBuildWriter.
 class NinjaTargetWriter {
  public:
   NinjaTargetWriter(const Target* target, std::ostream& out);
-  ~NinjaTargetWriter();
-
-  void Run();
+  virtual ~NinjaTargetWriter();
 
   static void RunAndWriteFile(const Target* target);
 
- private:
-  void WriteCopyRules();
+  virtual void Run() = 0;
 
-  void WriteCustomRules();
-  void WriteCustomArg(const std::string& arg);
+ protected:
+  void WriteEnvironment();
 
-  // Writs the rules for compiling each source, writing all output files
-  // to the given vector.
-  //
-  // common_deps is a precomputed string of all ninja files that are common
-  // to each build step. This is added to each one.
-  void WriteCustomSourceRules(const std::string& custom_rule_name,
-                              const std::string& common_deps,
-                              const SourceDir& script_cd,
-                              const std::string& script_cd_to_root,
-                              std::vector<OutputFile>* output_files);
-
-  void WriteCompilerVars();
-  void WriteSources(std::vector<OutputFile>* object_files);
-  void WriteLinkerStuff(const std::vector<OutputFile>& object_files);
-
-  // Writes the build line for linking the target. Includes newline.
-  void WriteLinkCommand(const OutputFile& external_output_file,
-                        const OutputFile& internal_output_file,
-                        const std::vector<OutputFile>& object_files);
-
-  // Returns NULL if the source type should not be compiled on this target.
-  const char* GetCommandForSourceType(SourceFileType type) const;
-
-  const char* GetCommandForTargetType() const;
+  // Returns the toolchain associated with the target.
+  const Toolchain* GetToolchain() const;
 
   const Settings* settings_;  // Non-owning.
   const Target* target_;  // Non-owning.
@@ -66,6 +38,9 @@
 
   NinjaHelper helper_;
 
+ private:
+  void WriteCopyRules();
+
   DISALLOW_COPY_AND_ASSIGN(NinjaTargetWriter);
 };
 
diff --git a/tools/gn/ninja_toolchain_writer.cc b/tools/gn/ninja_toolchain_writer.cc
index 0e38b8c..95cb408 100644
--- a/tools/gn/ninja_toolchain_writer.cc
+++ b/tools/gn/ninja_toolchain_writer.cc
@@ -9,6 +9,7 @@
 #include "base/file_util.h"
 #include "base/strings/stringize_macros.h"
 #include "tools/gn/build_settings.h"
+#include "tools/gn/item_node.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/target.h"
 #include "tools/gn/toolchain.h"
@@ -58,13 +59,17 @@
   const Toolchain* tc = settings_->toolchain();
   std::string indent("  ");
 
+  NinjaHelper helper(settings_->build_settings());
+  std::string rule_prefix = helper.GetRulePrefix(tc);
+
   for (int i = Toolchain::TYPE_NONE + 1; i < Toolchain::TYPE_NUMTYPES; i++) {
     Toolchain::ToolType tool_type = static_cast<Toolchain::ToolType>(i);
     const Toolchain::Tool& tool = tc->GetTool(tool_type);
     if (tool.empty())
       continue;
 
-    out_ << "rule " << Toolchain::ToolTypeToName(tool_type) << std::endl;
+    out_ << "rule " << rule_prefix << Toolchain::ToolTypeToName(tool_type)
+         << std::endl;
 
     #define WRITE_ARG(name) \
       if (!tool.name.empty()) \
@@ -83,12 +88,13 @@
 }
 
 void NinjaToolchainWriter::WriteSubninjas() {
+  // Write subninja commands for each generated target.
   for (size_t i = 0; i < targets_.size(); i++) {
-    if (targets_[i]->output_type() != Target::NONE) {
-      out_ << "subninja ";
-      path_output_.WriteFile(out_, helper_.GetNinjaFileForTarget(targets_[i]));
-      out_ << std::endl;
-    }
+    if (!targets_[i]->item_node()->should_generate())
+      continue;
+    out_ << "subninja ";
+    path_output_.WriteFile(out_, helper_.GetNinjaFileForTarget(targets_[i]));
+    out_ << std::endl;
   }
   out_ << std::endl;
 }
diff --git a/tools/gn/operators.cc b/tools/gn/operators.cc
index afded9f..0e91f6b 100644
--- a/tools/gn/operators.cc
+++ b/tools/gn/operators.cc
@@ -56,6 +56,7 @@
                            Err* err) {
   std::vector<Value>& v = list->list_value();
   switch (to_remove.type()) {
+    case Value::BOOLEAN:
     case Value::INTEGER:  // Filter out the individual int/string.
     case Value::STRING: {
       bool found_match = false;
@@ -69,8 +70,8 @@
       }
       if (!found_match) {
         *err = Err(to_remove.origin()->GetRange(), "Item not found",
-            "You were trying to remove \"" + to_remove.ToString() +
-            "\"\nfrom the list but it wasn't there.");
+            "You were trying to remove " + to_remove.ToString(true) +
+            "\nfrom the list but it wasn't there.");
       }
       break;
     }
@@ -342,8 +343,8 @@
                           const Value& right,
                           Err* err) {
   if (left == right)
-    return Value(op_node, 1);
-  return Value(op_node, 0);
+    return Value(op_node, true);
+  return Value(op_node, false);
 }
 
 Value ExecuteNotEquals(Scope* scope,
@@ -357,10 +358,10 @@
   return result;
 }
 
-Value FillNeedsToIntegersError(const BinaryOpNode* op_node,
-                               const Value& left,
-                               const Value& right,
-                               Err* err) {
+Value FillNeedsTwoIntegersError(const BinaryOpNode* op_node,
+                                const Value& left,
+                                const Value& right,
+                                Err* err) {
   *err = Err(op_node, "Comparison requires two integers.",
              "This operator can only compare two integers.");
   err->AppendRange(left.origin()->GetRange());
@@ -374,7 +375,7 @@
                         const Value& right,
                         Err* err) {
   if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
-    return FillNeedsToIntegersError(op_node, left, right, err);
+    return FillNeedsTwoIntegersError(op_node, left, right, err);
   return Value(op_node, left.int_value() <= right.int_value());
 }
 
@@ -384,7 +385,7 @@
                            const Value& right,
                            Err* err) {
   if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
-    return FillNeedsToIntegersError(op_node, left, right, err);
+    return FillNeedsTwoIntegersError(op_node, left, right, err);
   return Value(op_node, left.int_value() >= right.int_value());
 }
 
@@ -394,7 +395,7 @@
                      const Value& right,
                      Err* err) {
   if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
-    return FillNeedsToIntegersError(op_node, left, right, err);
+    return FillNeedsTwoIntegersError(op_node, left, right, err);
   return Value(op_node, left.int_value() > right.int_value());
 }
 
@@ -404,7 +405,7 @@
                   const Value& right,
                   Err* err) {
   if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
-    return FillNeedsToIntegersError(op_node, left, right, err);
+    return FillNeedsTwoIntegersError(op_node, left, right, err);
   return Value(op_node, left.int_value() < right.int_value());
 }
 
@@ -415,8 +416,14 @@
                 const Value& left,
                 const Value& right,
                 Err* err) {
-  return Value(op_node,
-      static_cast<int64>(left.InterpretAsInt() || right.InterpretAsInt()));
+  if (left.type() != Value::BOOLEAN) {
+    *err = Err(left, "Left side of || operator is not a boolean.");
+    err->AppendRange(op_node->GetRange());
+  } else if (right.type() != Value::BOOLEAN) {
+    *err = Err(right, "Right side of || operator is not a boolean.");
+    err->AppendRange(op_node->GetRange());
+  }
+  return Value(op_node, left.boolean_value() || right.boolean_value());
 }
 
 Value ExecuteAnd(Scope* scope,
@@ -424,8 +431,14 @@
                  const Value& left,
                  const Value& right,
                  Err* err) {
-  return Value(op_node,
-      static_cast<int64>(left.InterpretAsInt() && right.InterpretAsInt()));
+  if (left.type() != Value::BOOLEAN) {
+    *err = Err(left, "Left side of && operator is not a boolean.");
+    err->AppendRange(op_node->GetRange());
+  } else if (right.type() != Value::BOOLEAN) {
+    *err = Err(right, "Right side of && operator is not a boolean.");
+    err->AppendRange(op_node->GetRange());
+  }
+  return Value(op_node, left.boolean_value() && right.boolean_value());
 }
 
 }  // namespace
@@ -433,51 +446,54 @@
 // ----------------------------------------------------------------------------
 
 bool IsUnaryOperator(const Token& token) {
-  if (token.type() != Token::OPERATOR)
-    return false;
-  return token.value() == "!";
+  return token.type() == Token::BANG;
 }
 
 bool IsBinaryOperator(const Token& token) {
-  if (token.type() != Token::OPERATOR)
-    return false;
-  return token.value() == "=" ||
-         token.value() == "+=" ||
-         token.value() == "-=" ||
-         token.value() == "+" ||
-         token.value() == "-" ||
-         token.value() == "==" ||
-         token.value() == "!=" ||
-         token.value() == "<=" ||
-         token.value() == ">=" ||
-         token.value() == "<" ||
-         token.value() == ">" ||
-         token.value() == "&&" ||
-         token.value() == "||";
+  return token.type() == Token::EQUAL ||
+         token.type() == Token::PLUS ||
+         token.type() == Token::MINUS ||
+         token.type() == Token::PLUS_EQUALS ||
+         token.type() == Token::MINUS_EQUALS ||
+         token.type() == Token::EQUAL_EQUAL ||
+         token.type() == Token::NOT_EQUAL ||
+         token.type() == Token::LESS_EQUAL ||
+         token.type() == Token::GREATER_EQUAL ||
+         token.type() == Token::LESS_THAN ||
+         token.type() == Token::GREATER_THAN ||
+         token.type() == Token::BOOLEAN_AND ||
+         token.type() == Token::BOOLEAN_OR;
 }
 
 bool IsFunctionCallArgBeginScoper(const Token& token) {
-  return token.IsScoperEqualTo("(");
+  return token.type() == Token::LEFT_PAREN;
 }
 
 bool IsFunctionCallArgEndScoper(const Token& token) {
-  return token.IsScoperEqualTo(")");
+  return token.type() == Token::RIGHT_PAREN;
 }
 
 bool IsScopeBeginScoper(const Token& token) {
-  return token.IsScoperEqualTo("{");
+  return token.type() == Token::LEFT_BRACE;
 }
 
 bool IsScopeEndScoper(const Token& token) {
-  return token.IsScoperEqualTo("}");
+  return token.type() == Token::RIGHT_BRACE;
 }
 
 Value ExecuteUnaryOperator(Scope* scope,
                            const UnaryOpNode* op_node,
                            const Value& expr,
                            Err* err) {
-  DCHECK(op_node->op().IsOperatorEqualTo("!"));
-  return Value(op_node, !expr.InterpretAsInt());
+  DCHECK(op_node->op().type() == Token::BANG);
+
+  if (expr.type() != Value::BOOLEAN) {
+    *err = Err(expr, "Operand of ! operator is not a boolean.");
+    err->AppendRange(op_node->GetRange());
+    return Value();
+  }
+  // TODO(scottmg): Why no unary minus?
+  return Value(op_node, !expr.boolean_value());
 }
 
 Value ExecuteBinaryOperator(Scope* scope,
@@ -488,9 +504,9 @@
   const Token& op = op_node->op();
 
   // First handle the ones that take an lvalue.
-  if (op.IsOperatorEqualTo("=") ||
-      op.IsOperatorEqualTo("+=") ||
-      op.IsOperatorEqualTo("-=")) {
+  if (op.type() == Token::EQUAL ||
+      op.type() == Token::PLUS_EQUALS ||
+      op.type() == Token::MINUS_EQUALS) {
     const IdentifierNode* left_id = left->AsIdentifier();
     if (!left_id) {
       *err = Err(op, "Operator requires an lvalue.",
@@ -510,11 +526,11 @@
       return Value();
     }
 
-    if (op.IsOperatorEqualTo("="))
+    if (op.type() == Token::EQUAL)
       return ExecuteEquals(scope, op_node, dest, right_value, err);
-    if (op.IsOperatorEqualTo("+="))
+    if (op.type() == Token::PLUS_EQUALS)
       return ExecutePlusEquals(scope, op_node, dest, right_value, err);
-    if (op.IsOperatorEqualTo("-="))
+    if (op.type() == Token::MINUS_EQUALS)
       return ExecuteMinusEquals(scope, op_node, dest, right_value, err);
     NOTREACHED();
     return Value();
@@ -544,29 +560,29 @@
   }
 
   // +, -.
-  if (op.IsOperatorEqualTo("-"))
+  if (op.type() == Token::MINUS)
     return ExecuteMinus(scope, op_node, left_value, right_value, err);
-  if (op.IsOperatorEqualTo("+"))
+  if (op.type() == Token::PLUS)
     return ExecutePlus(scope, op_node, left_value, right_value, err);
 
   // Comparisons.
-  if (op.IsOperatorEqualTo("=="))
+  if (op.type() == Token::EQUAL_EQUAL)
     return ExecuteEqualsEquals(scope, op_node, left_value, right_value, err);
-  if (op.IsOperatorEqualTo("!="))
+  if (op.type() == Token::NOT_EQUAL)
     return ExecuteNotEquals(scope, op_node, left_value, right_value, err);
-  if (op.IsOperatorEqualTo(">="))
+  if (op.type() == Token::GREATER_EQUAL)
     return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err);
-  if (op.IsOperatorEqualTo("<="))
+  if (op.type() == Token::LESS_EQUAL)
     return ExecuteLessEquals(scope, op_node, left_value, right_value, err);
-  if (op.IsOperatorEqualTo(">"))
+  if (op.type() == Token::GREATER_THAN)
     return ExecuteGreater(scope, op_node, left_value, right_value, err);
-  if (op.IsOperatorEqualTo("<"))
+  if (op.type() == Token::LESS_THAN)
     return ExecuteLess(scope, op_node, left_value, right_value, err);
 
   // ||, &&.
-  if (op.IsOperatorEqualTo("||"))
+  if (op.type() == Token::BOOLEAN_OR)
     return ExecuteOr(scope, op_node, left_value, right_value, err);
-  if (op.IsOperatorEqualTo("&&"))
+  if (op.type() == Token::BOOLEAN_AND)
     return ExecuteAnd(scope, op_node, left_value, right_value, err);
 
   return Value();
diff --git a/tools/gn/parse_tree.cc b/tools/gn/parse_tree.cc
index 8e1adde..4ac30a2 100644
--- a/tools/gn/parse_tree.cc
+++ b/tools/gn/parse_tree.cc
@@ -139,10 +139,7 @@
 
 // BlockNode ------------------------------------------------------------------
 
-BlockNode::BlockNode(bool has_scope)
-    : has_scope_(has_scope),
-      begin_token_(NULL),
-      end_token_(NULL) {
+BlockNode::BlockNode(bool has_scope) : has_scope_(has_scope) {
 }
 
 BlockNode::~BlockNode() {
@@ -168,18 +165,19 @@
 }
 
 LocationRange BlockNode::GetRange() const {
-  if (begin_token_ && end_token_) {
-    return begin_token_->range().Union(end_token_->range());
+  if (begin_token_.type() != Token::INVALID &&
+      end_token_.type() != Token::INVALID) {
+    return begin_token_.range().Union(end_token_.range());
+  } else if (!statements_.empty()) {
+    return statements_[0]->GetRange().Union(
+        statements_[statements_.size() - 1]->GetRange());
   }
-  return LocationRange();  // TODO(brettw) indicate the entire file somehow.
+  return LocationRange();
 }
 
 Err BlockNode::MakeErrorDescribing(const std::string& msg,
                                    const std::string& help) const {
-  if (begin_token_)
-    return Err(*begin_token_, msg, help);
-  // TODO(brettw) this should have the beginning of the file in it or something.
-  return Err(Location(NULL, 1, 1), msg, help);
+  return Err(GetRange(), msg, help);
 }
 
 void BlockNode::Print(std::ostream& out, int indent) const {
@@ -220,15 +218,17 @@
   Value condition_result = condition_->Execute(scope, err);
   if (err->has_error())
     return Value();
-  if (condition_result.type() == Value::NONE) {
+  if (condition_result.type() != Value::BOOLEAN) {
     *err = condition_->MakeErrorDescribing(
-        "This does not evaluate to a value.",
-        "Please give me something to work with for the if statement.");
+        "Condition does not evaluate to a boolean value.",
+        std::string("This is a value of type \"") +
+            Value::DescribeType(condition_result.type()) +
+            "\" instead.");
     err->AppendRange(if_token_.range());
     return Value();
   }
 
-  if (condition_result.InterpretAsInt()) {
+  if (condition_result.boolean_value()) {
     if_true_->ExecuteBlockInScope(scope, err);
   } else if (if_false_) {
     // The else block is optional. It's either another condition (for an
@@ -277,11 +277,7 @@
 }
 
 Value FunctionCallNode::Execute(Scope* scope, Err* err) const {
-  Value args = args_->Execute(scope, err);
-  if (err->has_error())
-    return Value();
-  return functions::RunFunction(scope, this, args.list_value(), block_.get(),
-                                err);
+  return functions::RunFunction(scope, this, args_.get(), block_.get(), err);
 }
 
 LocationRange FunctionCallNode::GetRange() const {
@@ -404,6 +400,10 @@
 
 Value LiteralNode::Execute(Scope* scope, Err* err) const {
   switch (value_.type()) {
+    case Token::TRUE_TOKEN:
+      return Value(this, true);
+    case Token::FALSE_TOKEN:
+      return Value(this, false);
     case Token::INTEGER: {
       int64 result_int;
       if (!base::StringToInt64(value_.value(), &result_int)) {
@@ -413,9 +413,6 @@
       return Value(this, result_int);
     }
     case Token::STRING: {
-      // TODO(brettw) Unescaping probably needs to be moved & improved.
-      // The input value includes the quotes around the string, strip those
-      // off and unescape.
       Value v(this, Value::STRING);
       ExpandStringLiteral(scope, value_, &v, err);
       return v;
diff --git a/tools/gn/parse_tree.h b/tools/gn/parse_tree.h
index 09646e5..cc3550f 100644
--- a/tools/gn/parse_tree.h
+++ b/tools/gn/parse_tree.h
@@ -137,7 +137,7 @@
 class BlockNode : public ParseNode {
  public:
   // Set has_scope if this block introduces a nested scope.
-  BlockNode(bool has_scope);
+  explicit BlockNode(bool has_scope);
   virtual ~BlockNode();
 
   virtual const BlockNode* AsBlock() const OVERRIDE;
@@ -148,8 +148,8 @@
       const std::string& help = std::string()) const OVERRIDE;
   virtual void Print(std::ostream& out, int indent) const OVERRIDE;
 
-  void set_begin_token(const Token* t) { begin_token_ = t; }
-  void set_end_token(const Token* t) { end_token_ = t; }
+  void set_begin_token(const Token& t) { begin_token_ = t; }
+  void set_end_token(const Token& t) { end_token_ = t; }
 
   const std::vector<ParseNode*>& statements() const { return statements_; }
   void append_statement(scoped_ptr<ParseNode> s) {
@@ -163,8 +163,8 @@
   bool has_scope_;
 
   // Tokens corresponding to { and }, if any (may be NULL).
-  const Token* begin_token_;
-  const Token* end_token_;
+  Token begin_token_;
+  Token end_token_;
 
   // Owning pointers, use unique_ptr when we can use C++11.
   std::vector<ParseNode*> statements_;
@@ -295,7 +295,7 @@
   void append_item(scoped_ptr<ParseNode> s) {
     contents_.push_back(s.release());
   }
-  const std::vector<ParseNode*>& contents() const { return contents_; }
+  const std::vector<const ParseNode*>& contents() const { return contents_; }
 
  private:
   // Tokens corresponding to the [ and ].
@@ -303,7 +303,7 @@
   Token end_token_;
 
   // Owning pointers, use unique_ptr when we can use C++11.
-  std::vector<ParseNode*> contents_;
+  std::vector<const ParseNode*> contents_;
 
   DISALLOW_COPY_AND_ASSIGN(ListNode);
 };
diff --git a/tools/gn/parser.cc b/tools/gn/parser.cc
index 385aa34..e507dfb 100644
--- a/tools/gn/parser.cc
+++ b/tools/gn/parser.cc
@@ -9,6 +9,15 @@
 #include "tools/gn/operators.h"
 #include "tools/gn/token.h"
 
+// grammar:
+//
+// file       := (statement)*
+// statement  := block | if | assignment
+// block      := '{' statement* '}'
+// if         := 'if' '(' expr ')' statement [ else ]
+// else       := 'else' (if | statement)*
+// assignment := ident {'=' | '+=' | '-='} expr
+
 namespace {
 
 // Returns true if the two tokens are on the same line. We assume they're in
@@ -20,10 +29,65 @@
 
 }  // namespace
 
+enum Precedence {
+  PRECEDENCE_ASSIGNMENT = 1,
+  PRECEDENCE_OR = 2,
+  PRECEDENCE_AND = 3,
+  PRECEDENCE_EQUALITY = 4,
+  PRECEDENCE_RELATION = 5,
+  PRECEDENCE_SUM = 6,
+  PRECEDENCE_PREFIX = 7,
+  PRECEDENCE_CALL = 8,
+};
+
+// The top-level for blocks/ifs is still recursive descent, the expression
+// parser is a Pratt parser. The basic idea there is to have the precedences
+// (and associativities) encoded relative to each other and only parse up
+// until you hit something of that precedence. There's a dispatch table in
+// expressions_ at the top of parser.cc that describes how each token
+// dispatches if it's seen as either a prefix or infix operator, and if it's
+// infix, what its precedence is.
+//
+// Refs:
+// - http://javascript.crockford.com/tdop/tdop.html
+// - http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
+
+// Indexed by Token::Type.
+ParserHelper Parser::expressions_[] = {
+  {NULL, NULL, -1},                                             // INVALID
+  {&Parser::Literal, NULL, -1},                                 // INTEGER
+  {&Parser::Literal, NULL, -1},                                 // STRING
+  {&Parser::Literal, NULL, -1},                                 // TRUE_TOKEN
+  {&Parser::Literal, NULL, -1},                                 // FALSE_TOKEN
+  {NULL, &Parser::Assignment, PRECEDENCE_ASSIGNMENT},           // EQUAL
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_SUM},              // PLUS
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_SUM},              // MINUS
+  {NULL, &Parser::Assignment, PRECEDENCE_ASSIGNMENT},           // PLUS_EQUALS
+  {NULL, &Parser::Assignment, PRECEDENCE_ASSIGNMENT},           // MINUS_EQUALS
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_EQUALITY},         // EQUAL_EQUAL
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_EQUALITY},         // NOT_EQUAL
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // LESS_EQUAL
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // GREATER_EQUAL
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // LESS_THAN
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_RELATION},         // GREATER_THAN
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_AND},              // BOOLEAN_AND
+  {NULL, &Parser::BinaryOperator, PRECEDENCE_OR},               // BOOLEAN_OR
+  {&Parser::Not, NULL, -1},                                     // BANG
+  {&Parser::Group, NULL, -1},                                   // LEFT_PAREN
+  {NULL, NULL, -1},                                             // RIGHT_PAREN
+  {&Parser::List, &Parser::Subscript, PRECEDENCE_CALL},         // LEFT_BRACKET
+  {NULL, NULL, -1},                                             // RIGHT_BRACKET
+  {NULL, NULL, -1},                                             // LEFT_BRACE
+  {NULL, NULL, -1},                                             // RIGHT_BRACE
+  {NULL, NULL, -1},                                             // IF
+  {NULL, NULL, -1},                                             // ELSE
+  {&Parser::Name, &Parser::IdentifierOrCall, PRECEDENCE_CALL},  // IDENTIFIER
+  {NULL, NULL, -1},                                             // COMMA
+  {NULL, NULL, -1},                                             // COMMENT
+};
+
 Parser::Parser(const std::vector<Token>& tokens, Err* err)
-    : tokens_(tokens),
-      err_(err),
-      cur_(0) {
+    : tokens_(tokens), err_(err), cur_(0) {
 }
 
 Parser::~Parser() {
@@ -33,7 +97,7 @@
 scoped_ptr<ParseNode> Parser::Parse(const std::vector<Token>& tokens,
                                     Err* err) {
   Parser p(tokens, err);
-  return p.ParseBlock(false).PassAs<ParseNode>();
+  return p.ParseFile().PassAs<ParseNode>();
 }
 
 // static
@@ -43,428 +107,331 @@
   return p.ParseExpression().Pass();
 }
 
-bool Parser::IsToken(Token::Type type, char* str) const {
+bool Parser::IsAssignment(const ParseNode* node) const {
+  return node && node->AsBinaryOp() &&
+         (node->AsBinaryOp()->op().type() == Token::EQUAL ||
+          node->AsBinaryOp()->op().type() == Token::PLUS_EQUALS ||
+          node->AsBinaryOp()->op().type() == Token::MINUS_EQUALS);
+}
+
+bool Parser::IsStatementBreak(Token::Type token_type) const {
+  switch (token_type) {
+    case Token::IDENTIFIER:
+    case Token::LEFT_BRACE:
+    case Token::RIGHT_BRACE:
+    case Token::IF:
+    case Token::ELSE:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Parser::LookAhead(Token::Type type) {
   if (at_end())
     return false;
-  return cur_token().type() == type || cur_token().value() == str;
+  return cur_token().type() == type;
 }
 
-scoped_ptr<AccessorNode> Parser::ParseAccessor() {
-  scoped_ptr<AccessorNode> accessor(new AccessorNode);
-
-  DCHECK(cur_token().type() == Token::IDENTIFIER);
-  accessor->set_base(cur_token());
-  cur_++;  // Skip identifier.
-  cur_++;  // Skip "[" (we know this exists because the existance of this
-           // token is how the caller knows it's an accessor.
-
-  if (at_end()) {
-    *err_ = MakeEOFError("Got EOF when looking for list index.");
-    return scoped_ptr<AccessorNode>();
-  }
-
-  // Get the expression.
-  scoped_ptr<ParseNode> expr = ParseExpression().Pass();
-  if (has_error())
-    return scoped_ptr<AccessorNode>();
-  if (at_end()) {
-    *err_ = MakeEOFError("Got EOF when looking for list accessor ]");
-    return scoped_ptr<AccessorNode>();
-  }
-  accessor->set_index(expr.Pass());
-
-  // Skip over "]"
-  if (!cur_token().IsScoperEqualTo("]")) {
-    *err_ = Err(cur_token(), "Expecting ]",
-               "You started a list access but didn't terminate it, and instead "
-               "I fould this\nstupid thing.");
-    return scoped_ptr<AccessorNode>();
-  }
-  cur_++;
-
-  return accessor.Pass();
+bool Parser::Match(Token::Type type) {
+  if (!LookAhead(type))
+    return false;
+  Consume();
+  return true;
 }
 
-// Blocks at the file scope don't need {} so we have the option to ignore
-// them. When need_braces is set, we'll expect a begin an end brace.
-//
-// block := "{" block_contents "}"
-// block_contents := (expression | conditional | block)*
-scoped_ptr<BlockNode> Parser::ParseBlock(bool need_braces) {
-  scoped_ptr<BlockNode> block(new BlockNode(true));
+Token Parser::Consume(Token::Type type, const char* error_message) {
+  Token::Type types[1] = { type };
+  return Consume(types, 1, error_message);
+}
 
-  // Eat initial { if necessary.
-  const Token* opening_curly_brace;
-  if (need_braces) {
-    if (at_end()) {
-      *err_ = MakeEOFError("Got EOF when looking for { for block.",
-                           "It should have been after here.");
-      return scoped_ptr<BlockNode>();
-    } else if(!IsScopeBeginScoper(cur_token())) {
-      *err_ = Err(cur_token(), "Expecting { instead of this thing.",
-                  "THOU SHALT USE CURLY BRACES FOR ALL BLOCKS.");
-      return scoped_ptr<BlockNode>();
-    }
-    opening_curly_brace = &cur_token();
-    block->set_begin_token(opening_curly_brace);
+Token Parser::Consume(Token::Type* types,
+                      size_t num_types,
+                      const char* error_message) {
+  if (has_error()) {
+    // Don't overwrite current error, but make progress through tokens so that
+    // a loop that's expecting a particular token will still terminate.
     cur_++;
+    return Token(Location(), Token::INVALID, base::StringPiece());
   }
-
-  // Loop until EOF or end brace found.
-  while (!at_end() && !IsScopeEndScoper(cur_token())) {
-    if (cur_token().IsIdentifierEqualTo("if")) {
-      // Conditional.
-      block->append_statement(ParseCondition().PassAs<ParseNode>());
-    } else if (IsScopeBeginScoper(cur_token())) {
-      // Nested block.
-      block->append_statement(ParseBlock(true).PassAs<ParseNode>());
-    } else {
-      // Everything else is an expression.
-      block->append_statement(ParseExpression().PassAs<ParseNode>());
-    }
-    if (has_error())
-      return scoped_ptr<BlockNode>();
-  }
-
-  // Eat the ending "}" if necessary.
-  if (need_braces) {
-    if (at_end() || !IsScopeEndScoper(cur_token())) {
-      *err_ = Err(*opening_curly_brace, "Expecting }",
-                  "I ran headlong into the end of the file looking for the "
-                  "closing brace\ncorresponding to this one.");
-      return scoped_ptr<BlockNode>();
-    }
-    block->set_end_token(&cur_token());
-    cur_++;  // Skip past "}".
-  }
-
-  return block.Pass();
-}
-
-// conditional := "if (" expression ")" block [else_conditional]
-// else_conditional := ("else" block) | ("else" conditional)
-scoped_ptr<ConditionNode> Parser::ParseCondition() {
-  scoped_ptr<ConditionNode> cond(new ConditionNode);
-
-  // Skip past "if".
-  const Token& if_token = cur_token();
-  cond->set_if_token(if_token);
-  DCHECK(if_token.IsIdentifierEqualTo("if"));
-  cur_++;
-
-  if (at_end() || !IsFunctionCallArgBeginScoper(cur_token())) {
-    *err_ = Err(if_token, "Expecting \"(\" after \"if\"",
-                "Did you think this was Python or something?");
-    return scoped_ptr<ConditionNode>();
-  }
-
-  // Skip over (.
-  const Token& open_paren_token = cur_token();
-  cur_++;
   if (at_end()) {
-    *err_ = Err(if_token, "Unexpected EOF inside if condition");
-    return scoped_ptr<ConditionNode>();
+    const char kEOFMsg[] = "I hit EOF instead.";
+    if (tokens_.empty())
+      *err_ = Err(Location(), error_message, kEOFMsg);
+    else
+      *err_ = Err(tokens_[tokens_.size() - 1], error_message, kEOFMsg);
+    return Token(Location(), Token::INVALID, base::StringPiece());
   }
 
-  // Condition inside ().
-  cond->set_condition(ParseExpression().Pass());
-  if (has_error())
-    return scoped_ptr<ConditionNode>();
-
-  if (at_end() || !IsFunctionCallArgEndScoper(cur_token())) {
-    *err_ = Err(open_paren_token, "Expecting \")\" for \"if\" condition",
-                "You didn't finish the thought you started here.");
-    return scoped_ptr<ConditionNode>();
+  for (size_t i = 0; i < num_types; ++i) {
+    if (cur_token().type() == types[i])
+      return tokens_[cur_++];
   }
-  cur_++;  // Skip over )
-
-  // Contents of {}.
-  cond->set_if_true(ParseBlock(true).Pass());
-  if (has_error())
-    return scoped_ptr<ConditionNode>();
-
-  // Optional "else" at the end.
-  if (!at_end() && cur_token().IsIdentifierEqualTo("else")) {
-    cur_++;
-
-    // The else may be followed by an if or a block.
-    if (at_end()) {
-      *err_ = MakeEOFError("Ran into end of file after \"else\".",
-                           "else, WHAT?!?!?");
-      return scoped_ptr<ConditionNode>();
-    }
-    if (cur_token().IsIdentifierEqualTo("if")) {
-      // "else if() {"
-      cond->set_if_false(ParseCondition().PassAs<ParseNode>());
-    } else if (IsScopeBeginScoper(cur_token())) {
-      // "else {"
-      cond->set_if_false(ParseBlock(true).PassAs<ParseNode>());
-    } else {
-      // else <anything else>
-      *err_ = Err(cur_token(), "Expected \"if\" or \"{\" after \"else\".",
-                  "This is neither of those things.");
-      return scoped_ptr<ConditionNode>();
-    }
-  }
-
-  if (has_error())
-    return scoped_ptr<ConditionNode>();
-  return cond.Pass();
+  *err_ = Err(cur_token(), error_message);
+  return Token(Location(), Token::INVALID, base::StringPiece());
 }
 
-// expression := paren_expression | accessor | identifier | literal |
-//               funccall | unary_expression | binary_expression
-//
-// accessor := identifier <non-newline-whitespace>* "[" expression "]"
-//
-// The "non-newline-whitespace is used to differentiate between this case:
-//   a[1]
-// and this one:
-//   a
-//   [1]
-// The second one is kind of stupid (since it does nothing with the values)
-// but is still legal.
+Token Parser::Consume() {
+  return tokens_[cur_++];
+}
+
 scoped_ptr<ParseNode> Parser::ParseExpression() {
-  scoped_ptr<ParseNode> expr = ParseExpressionExceptBinaryOperators();
-  if (has_error())
+  return ParseExpression(0);
+}
+
+scoped_ptr<ParseNode> Parser::ParseExpression(int precedence) {
+  if (at_end())
     return scoped_ptr<ParseNode>();
 
-  // That may have hit EOF, in which case we can't have any binary operators.
-  if (at_end())
-    return expr.Pass();
+  Token token = Consume();
+  PrefixFunc prefix = expressions_[token.type()].prefix;
 
-  // TODO(brettw) handle operator precidence!
-  // Gobble up all subsequent expressions as long as there are binary
-  // operators.
-
-  if (IsBinaryOperator(cur_token())) {
-    scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode);
-    binary_op->set_left(expr.Pass());
-    const Token& operator_token = cur_token();
-    binary_op->set_op(operator_token);
-    cur_++;
-    if (at_end()) {
-      *err_ = Err(operator_token, "Unexpected EOF in expression.",
-                  "I was looking for the right-hand-side of this operator.");
-      return scoped_ptr<ParseNode>();
-    }
-    binary_op->set_right(ParseExpression().Pass());
-    if (has_error())
-      return scoped_ptr<ParseNode>();
-    return binary_op.PassAs<ParseNode>();
+  if (prefix == NULL) {
+    *err_ = Err(token,
+                std::string("Unexpected token '") + token.value().as_string() +
+                    std::string("'"));
+    return scoped_ptr<ParseNode>();
   }
 
+  scoped_ptr<ParseNode> left = (this->*prefix)(token);
+
+  while (!at_end() && !IsStatementBreak(cur_token().type()) &&
+         precedence <= expressions_[cur_token().type()].precedence) {
+    token = Consume();
+    InfixFunc infix = expressions_[token.type()].infix;
+    if (infix == NULL) {
+      *err_ = Err(token,
+                  std::string("Unexpected token '") +
+                      token.value().as_string() + std::string("'"));
+      return scoped_ptr<ParseNode>();
+    }
+    left = (this->*infix)(left.Pass(), token);
+    if (has_error())
+      return scoped_ptr<ParseNode>();
+  }
+
+  return left.Pass();
+}
+
+scoped_ptr<ParseNode> Parser::Literal(Token token) {
+  return scoped_ptr<ParseNode>(new LiteralNode(token)).Pass();
+}
+
+scoped_ptr<ParseNode> Parser::Name(Token token) {
+  return IdentifierOrCall(scoped_ptr<ParseNode>(), token).Pass();
+}
+
+scoped_ptr<ParseNode> Parser::Group(Token token) {
+  scoped_ptr<ParseNode> expr = ParseExpression();
+  if (has_error())
+    return scoped_ptr<ParseNode>();
+  Consume(Token::RIGHT_PAREN, "Expected ')'");
   return expr.Pass();
 }
 
-
-// This internal one does not handle binary operators, since it requires
-// looking at the "next" thing. The regular ParseExpression above handles it.
-scoped_ptr<ParseNode> Parser::ParseExpressionExceptBinaryOperators() {
-  if (at_end())
+scoped_ptr<ParseNode> Parser::Not(Token token) {
+  scoped_ptr<ParseNode> expr = ParseExpression(PRECEDENCE_PREFIX + 1);
+  if (has_error())
     return scoped_ptr<ParseNode>();
-
-  const Token& token = cur_token();
-
-  // Unary expression.
-  if (IsUnaryOperator(token))
-    return ParseUnaryOp().PassAs<ParseNode>();
-
-  // Parenthesized expressions.
-  if (token.IsScoperEqualTo("("))
-    return ParseParenExpression();
-
-  // Function calls.
-  if (token.type() == Token::IDENTIFIER) {
-    if (has_next_token() && IsFunctionCallArgBeginScoper(next_token()))
-      return ParseFunctionCall().PassAs<ParseNode>();
-  }
-
-  // Lists.
-  if (token.IsScoperEqualTo("[")) {
-    return ParseList(Token(Location(), Token::SCOPER, "["),
-                     Token(Location(), Token::SCOPER, "]")).PassAs<ParseNode>();
-  }
-
-  // Literals.
-  if (token.type() == Token::STRING || token.type() == Token::INTEGER) {
-    cur_++;
-    return scoped_ptr<ParseNode>(new LiteralNode(token));
-  }
-
-  // Accessors.
-  if (token.type() == Token::IDENTIFIER &&
-      has_next_token() && next_token().IsScoperEqualTo("[") &&
-      IsSameLine(token, next_token())) {
-    return ParseAccessor().PassAs<ParseNode>();
-  }
-
-  // Identifiers.
-  if (token.type() == Token::IDENTIFIER) {
-    cur_++;
-    return scoped_ptr<ParseNode>(new IdentifierNode(token));
-  }
-
-  // Handle errors.
-  if (token.type() == Token::SEPARATOR) {
-    *err_ = Err(token, "Unexpected comma.",
-                "You can't put a comma here, it must be in list separating "
-                "complete\nthoughts.");
-  } else if (IsScopeBeginScoper(token)) {
-    *err_ = Err(token, "Unexpected token.",
-                "You can't put a \"{\" scope here, it must be in a block.");
-  } else {
-    *err_ = Err(token, "Unexpected token.",
-                "I was really hoping for something else here and you let me down.");
-  }
-  return scoped_ptr<ParseNode>();
+  scoped_ptr<UnaryOpNode> unary_op(new UnaryOpNode);
+  unary_op->set_op(token);
+  unary_op->set_operand(expr.Pass());
+  return unary_op.PassAs<ParseNode>();
 }
 
-// function_call := identifier "(" list_contents ")"
-//                  [<non-newline-whitespace>* block]
-scoped_ptr<FunctionCallNode> Parser::ParseFunctionCall() {
-  scoped_ptr<FunctionCallNode> func(new FunctionCallNode);
-
-  const Token& function_token = cur_token();
-  func->set_function(function_token);
-
-  // This function should only get called when we know we have a function,
-  // which only happens when there is a paren following the name. Skip past it.
-  DCHECK(has_next_token());
-  cur_++;  // Skip past function name to (.
-  const Token& open_paren_token = cur_token();
-  DCHECK(IsFunctionCallArgBeginScoper(open_paren_token));
-
-  if (at_end()) {
-    *err_ = Err(open_paren_token, "Unexpected EOF for function call.",
-                "You didn't finish the thought you started here.");
-    return scoped_ptr<FunctionCallNode>();
-  }
-
-  // Arguments.
-  func->set_args(ParseList(Token(Location(), Token::SCOPER, "("),
-                           Token(Location(), Token::SCOPER, ")")));
-  if (has_error())
-    return scoped_ptr<FunctionCallNode>();
-
-  // Optional {} after function call for certain functions. The "{" must be on
-  // the same line as the ")" to disambiguate the case of a function followed
-  // by a random block just used for scoping purposes.
-  if (!at_end() && IsScopeBeginScoper(cur_token())) {
-    const Token& args_end_token = tokens_[cur_ - 1];
-    DCHECK(args_end_token.IsScoperEqualTo(")"));
-    if (IsSameLine(args_end_token, cur_token()))
-      func->set_block(ParseBlock(true).Pass());
-  }
-
-  if (has_error())
-    return scoped_ptr<FunctionCallNode>();
-  return func.Pass();
-}
-
-// list := "[" expression* "]"
-// list_contents := [(expression ",")* expression [","]]
-//
-// The list_contents is also used in function calls surrounded by parens, so
-// this function takes the tokens that are expected to surround the list.
-scoped_ptr<ListNode> Parser::ParseList(const Token& expected_begin,
-                                       const Token& expected_end) {
-  scoped_ptr<ListNode> list(new ListNode);
-
-  const Token& open_bracket_token = cur_token();
-  list->set_begin_token(open_bracket_token);
-  cur_++;  // Skip "[" or "(".
-
-  bool need_separator = false;
-  while(true) {
-    if (at_end()) {
-      *err_ = Err(open_bracket_token, "EOF found when parsing list.",
-                  "I expected a \"" + expected_end.value().as_string() +
-                  "\" corresponding to this one.");
-      return scoped_ptr<ListNode>();
-    }
-    if (cur_token().type() == expected_end.type() &&
-        cur_token().value() == expected_end.value()) {
-      list->set_end_token(cur_token());
-      cur_++;
-      break;
-    }
-
-    if (need_separator) {
-      DCHECK(!list->contents().empty());
-      LocationRange prev_item_range =
-          list->contents().at(list->contents().size() - 1)->GetRange();
-      *err_ = Err(prev_item_range.end(),
-                  "Need comma separating items in list.",
-                  "You probably need a comma after this thingy.");
-      err_->AppendRange(prev_item_range);
-      return scoped_ptr<ListNode>();
-    }
-    scoped_ptr<ParseNode> expr = ParseExpression().Pass();
-    if (has_error())
-      return scoped_ptr<ListNode>();
-    list->append_item(expr.Pass());
-
-    need_separator = true;
-    if (!at_end()) {
-      // Skip over the separator, marking that we found it.
-      if (cur_token().type() == Token::SEPARATOR) {
-        cur_++;
-        need_separator = false;
-      }
-    }
-  }
+scoped_ptr<ParseNode> Parser::List(Token node) {
+  scoped_ptr<ParseNode> list(ParseList(Token::RIGHT_BRACKET, true));
+  if (!has_error() && !at_end())
+    Consume(Token::RIGHT_BRACKET, "Expected ']'");
   return list.Pass();
 }
 
-// paren_expression := "(" expression ")"
-scoped_ptr<ParseNode> Parser::ParseParenExpression() {
-  const Token& open_paren_token = cur_token();
-  cur_++;  // Skip over (
-
-  scoped_ptr<ParseNode> ret = ParseExpression();
-  if (has_error())
-    return scoped_ptr<ParseNode>();
-
-  if (at_end()) {
-    *err_ = Err(open_paren_token, "EOF found when parsing expression.",
-                "I was looking for a \")\" corresponding to this one.");
+scoped_ptr<ParseNode> Parser::BinaryOperator(scoped_ptr<ParseNode> left,
+                                             Token token) {
+  scoped_ptr<ParseNode> right =
+      ParseExpression(expressions_[token.type()].precedence + 1);
+  if (!right) {
+    *err_ =
+        Err(token,
+            "Expected right hand side for '" + token.value().as_string() + "'");
     return scoped_ptr<ParseNode>();
   }
-  if (!cur_token().IsScoperEqualTo(")")) {
-    *err_ = Err(open_paren_token, "Expected \")\" for expression",
-                "I was looking for a \")\" corresponding to this one.");
-    return scoped_ptr<ParseNode>();
-  }
-  cur_++;  // Skip over )
-  return ret.Pass();
+  scoped_ptr<BinaryOpNode> binary_op(new BinaryOpNode);
+  binary_op->set_op(token);
+  binary_op->set_left(left.Pass());
+  binary_op->set_right(right.Pass());
+  return binary_op.PassAs<ParseNode>();
 }
 
-// unary_expression := "!" expression
-scoped_ptr<UnaryOpNode> Parser::ParseUnaryOp() {
-  scoped_ptr<UnaryOpNode> unary(new UnaryOpNode);
-
-  DCHECK(!at_end() && IsUnaryOperator(cur_token()));
-  const Token& op_token = cur_token();
-  unary->set_op(op_token);
-  cur_++;
-
-  if (at_end()) {
-    *err_ = Err(op_token, "Expected expression.",
-                "This operator needs something to operate on.");
-    return scoped_ptr<UnaryOpNode>();
+scoped_ptr<ParseNode> Parser::IdentifierOrCall(scoped_ptr<ParseNode> left,
+                                               Token token) {
+  scoped_ptr<ListNode> list(new ListNode);
+  list->set_begin_token(token);
+  list->set_end_token(token);
+  scoped_ptr<BlockNode> block;
+  bool has_arg = false;
+  if (Match(Token::LEFT_PAREN)) {
+    // Parsing a function call.
+    has_arg = true;
+    if (Match(Token::RIGHT_PAREN)) {
+      // Nothing, just an empty call.
+    } else {
+      list = ParseList(Token::RIGHT_PAREN, false);
+      if (has_error())
+        return scoped_ptr<ParseNode>();
+      Consume(Token::RIGHT_PAREN, "Expected ')' after call");
+    }
+    // Optionally with a scope.
+    if (LookAhead(Token::LEFT_BRACE)) {
+      block = ParseBlock();
+      if (has_error())
+        return scoped_ptr<ParseNode>();
+    }
   }
-  unary->set_operand(ParseExpression().Pass());
-  if (has_error())
-    return scoped_ptr<UnaryOpNode>();
-  return unary.Pass();
+
+  if (!left && !has_arg) {
+    // Not a function call, just a standalone identifier.
+    return scoped_ptr<ParseNode>(new IdentifierNode(token)).Pass();
+  }
+  scoped_ptr<FunctionCallNode> func_call(new FunctionCallNode);
+  func_call->set_function(token);
+  func_call->set_args(list.Pass());
+  if (block)
+    func_call->set_block(block.Pass());
+  return func_call.PassAs<ParseNode>();
 }
 
-Err Parser::MakeEOFError(const std::string& message,
-                         const std::string& help) const {
-  if (tokens_.empty())
-    return Err(Location(NULL, 1, 1), message, help);
+scoped_ptr<ParseNode> Parser::Assignment(scoped_ptr<ParseNode> left,
+                                         Token token) {
+  if (left->AsIdentifier() == NULL) {
+    *err_ = Err(left.get(), "Left-hand side of assignment must be identifier.");
+    return scoped_ptr<ParseNode>();
+  }
+  scoped_ptr<ParseNode> value = ParseExpression(PRECEDENCE_ASSIGNMENT);
+  scoped_ptr<BinaryOpNode> assign(new BinaryOpNode);
+  assign->set_op(token);
+  assign->set_left(left.Pass());
+  assign->set_right(value.Pass());
+  return assign.PassAs<ParseNode>();
+}
 
-  const Token& last = tokens_[tokens_.size() - 1];
-  return Err(last, message, help);
+scoped_ptr<ParseNode> Parser::Subscript(scoped_ptr<ParseNode> left,
+                                        Token token) {
+  // TODO: Maybe support more complex expressions like a[0][0]. This would
+  // require work on the evaluator too.
+  if (left->AsIdentifier() == NULL) {
+    *err_ = Err(left.get(), "May only subscript simple identifiers");
+    return scoped_ptr<ParseNode>();
+  }
+  scoped_ptr<ParseNode> value = ParseExpression();
+  Consume(Token::RIGHT_BRACKET, "Expecting ']' after subscript.");
+  scoped_ptr<AccessorNode> accessor(new AccessorNode);
+  accessor->set_base(left->AsIdentifier()->value());
+  accessor->set_index(value.Pass());
+  return accessor.PassAs<ParseNode>();
+}
+
+// Does not Consume the start or end token.
+scoped_ptr<ListNode> Parser::ParseList(Token::Type stop_before,
+                                       bool allow_trailing_comma) {
+  scoped_ptr<ListNode> list(new ListNode);
+  list->set_begin_token(cur_token());
+  bool just_got_comma = false;
+  while (!LookAhead(stop_before)) {
+    just_got_comma = false;
+    // Why _OR? We're parsing things that are higher precedence than the ,
+    // that separates the items of the list. , should appear lower than
+    // boolean expressions (the lowest of which is OR), but above assignments.
+    list->append_item(ParseExpression(PRECEDENCE_OR));
+    if (has_error())
+      return scoped_ptr<ListNode>();
+    if (at_end()) {
+      *err_ =
+          Err(tokens_[tokens_.size() - 1], "Unexpected end of file in list.");
+      return scoped_ptr<ListNode>();
+    }
+    just_got_comma = Match(Token::COMMA);
+  }
+  if (just_got_comma && !allow_trailing_comma) {
+    *err_ = Err(cur_token(), "Trailing comma");
+    return scoped_ptr<ListNode>();
+  }
+  list->set_end_token(cur_token());
+  return list.Pass();
+}
+
+scoped_ptr<ParseNode> Parser::ParseFile() {
+  scoped_ptr<BlockNode> file(new BlockNode(false));
+  for (;;) {
+    if (at_end())
+      break;
+    scoped_ptr<ParseNode> statement = ParseStatement();
+    if (!statement)
+      break;
+    file->append_statement(statement.Pass());
+  }
+  if (!at_end() && !has_error())
+    *err_ = Err(cur_token(), "Unexpected here, should be newline.");
+  if (has_error())
+    return scoped_ptr<ParseNode>();
+  return file.PassAs<ParseNode>();
+}
+
+scoped_ptr<ParseNode> Parser::ParseStatement() {
+  if (LookAhead(Token::LEFT_BRACE)) {
+    return ParseBlock().PassAs<ParseNode>();
+  } else if (LookAhead(Token::IF)) {
+    return ParseCondition();
+  } else {
+    // TODO(scottmg): Is this too strict? Just drop all the testing if we want
+    // to allow "pointless" expressions and return ParseExpression() directly.
+    scoped_ptr<ParseNode> stmt = ParseExpression();
+    if (stmt) {
+      if (stmt->AsFunctionCall() || IsAssignment(stmt.get()))
+        return stmt.Pass();
+    }
+    if (!has_error()) {
+      Token token = at_end() ? tokens_[tokens_.size() - 1] : cur_token();
+      *err_ = Err(token, "Expecting assignment or function call.");
+    }
+    return scoped_ptr<ParseNode>();
+  }
+}
+
+scoped_ptr<BlockNode> Parser::ParseBlock() {
+  Token begin_token =
+      Consume(Token::LEFT_BRACE, "Expected '{' to start a block.");
+  if (has_error())
+    return scoped_ptr<BlockNode>();
+  scoped_ptr<BlockNode> block(new BlockNode(true));
+  block->set_begin_token(begin_token);
+
+  for (;;) {
+    if (LookAhead(Token::RIGHT_BRACE)) {
+      block->set_end_token(Consume());
+      break;
+    }
+
+    scoped_ptr<ParseNode> statement = ParseStatement();
+    if (!statement)
+      return scoped_ptr<BlockNode>();
+    block->append_statement(statement.Pass());
+  }
+  return block.Pass();
+}
+
+scoped_ptr<ParseNode> Parser::ParseCondition() {
+  scoped_ptr<ConditionNode> condition(new ConditionNode);
+  Consume(Token::IF, "Expected 'if'");
+  Consume(Token::LEFT_PAREN, "Expected '(' after 'if'.");
+  condition->set_condition(ParseExpression());
+  if (IsAssignment(condition->condition()))
+    *err_ = Err(condition->condition(), "Assignment not allowed in 'if'.");
+  Consume(Token::RIGHT_PAREN, "Expected ')' after condition of 'if'.");
+  condition->set_if_true(ParseBlock().Pass());
+  if (Match(Token::ELSE))
+    condition->set_if_false(ParseStatement().Pass());
+  if (has_error())
+    return scoped_ptr<ParseNode>();
+  return condition.PassAs<ParseNode>();
 }
diff --git a/tools/gn/parser.h b/tools/gn/parser.h
index 252b801..76cc71a 100644
--- a/tools/gn/parser.h
+++ b/tools/gn/parser.h
@@ -5,6 +5,7 @@
 #ifndef TOOLS_GN_PARSER_H_
 #define TOOLS_GN_PARSER_H_
 
+#include <map>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -13,6 +14,17 @@
 #include "tools/gn/err.h"
 #include "tools/gn/parse_tree.h"
 
+class Parser;
+typedef scoped_ptr<ParseNode> (Parser::*PrefixFunc)(Token token);
+typedef scoped_ptr<ParseNode> (Parser::*InfixFunc)(scoped_ptr<ParseNode> left,
+                                                   Token token);
+
+struct ParserHelper {
+  PrefixFunc prefix;
+  InfixFunc infix;
+  int precedence;
+};
+
 // Parses a series of tokens. The resulting AST will refer to the tokens passed
 // to the input, so the tokens an the file data they refer to must outlive your
 // use of the ParseNode.
@@ -26,29 +38,50 @@
   static scoped_ptr<ParseNode> ParseExpression(const std::vector<Token>& tokens,
                                                Err* err);
 
+  scoped_ptr<ParseNode> ParseExpression();
+
  private:
   // Vector must be valid for lifetime of call.
   Parser(const std::vector<Token>& tokens, Err* err);
   ~Parser();
 
-  scoped_ptr<AccessorNode> ParseAccessor();
-  scoped_ptr<BlockNode> ParseBlock(bool need_braces);
-  scoped_ptr<ConditionNode> ParseCondition();
-  scoped_ptr<ParseNode> ParseExpression();
-  scoped_ptr<ParseNode> ParseExpressionExceptBinaryOperators();
-  scoped_ptr<FunctionCallNode> ParseFunctionCall();
-  scoped_ptr<ListNode> ParseList(const Token& expected_begin,
-                                 const Token& expected_end);
-  scoped_ptr<ParseNode> ParseParenExpression();
-  scoped_ptr<UnaryOpNode> ParseUnaryOp();
+  // Parses an expression with the given precedence or higher.
+  scoped_ptr<ParseNode> ParseExpression(int precedence);
 
-  bool IsToken(Token::Type type, char* str) const;
+  // |PrefixFunc|s used in parsing expressions.
+  scoped_ptr<ParseNode> Literal(Token token);
+  scoped_ptr<ParseNode> Name(Token token);
+  scoped_ptr<ParseNode> Group(Token token);
+  scoped_ptr<ParseNode> Not(Token token);
+  scoped_ptr<ParseNode> List(Token token);
 
-  // Gets an error corresponding to the last token. When we hit an EOF
-  // usually we've already gone beyond the end (or maybe there are no tokens)
-  // so there is some tricky logic to report this.
-  Err MakeEOFError(const std::string& message,
-                   const std::string& help = std::string()) const;
+  // |InfixFunc|s used in parsing expressions.
+  scoped_ptr<ParseNode> BinaryOperator(scoped_ptr<ParseNode> left, Token token);
+  scoped_ptr<ParseNode> IdentifierOrCall(scoped_ptr<ParseNode> left,
+                                         Token token);
+  scoped_ptr<ParseNode> Assignment(scoped_ptr<ParseNode> left, Token token);
+  scoped_ptr<ParseNode> Subscript(scoped_ptr<ParseNode> left, Token token);
+
+  // Helper to parse a comma separated list, optionally allowing trailing
+  // commas (allowed in [] lists, not in function calls).
+  scoped_ptr<ListNode> ParseList(Token::Type stop_before,
+                                 bool allow_trailing_comma);
+
+  scoped_ptr<ParseNode> ParseFile();
+  scoped_ptr<ParseNode> ParseStatement();
+  scoped_ptr<BlockNode> ParseBlock();
+  scoped_ptr<ParseNode> ParseCondition();
+
+  bool IsAssignment(const ParseNode* node) const;
+  bool IsStatementBreak(Token::Type token_type) const;
+
+  bool LookAhead(Token::Type type);
+  bool Match(Token::Type type);
+  Token Consume(Token::Type type, const char* error_message);
+  Token Consume(Token::Type* types,
+                size_t num_types,
+                const char* error_message);
+  Token Consume();
 
   const Token& cur_token() const { return tokens_[cur_]; }
 
@@ -56,11 +89,10 @@
   bool at_end() const { return cur_ >= tokens_.size(); }
   bool has_error() const { return err_->has_error(); }
 
-  const Token& next_token() const { return tokens_[cur_ + 1]; }
-  bool has_next_token() const { return cur_ + 1 < tokens_.size(); }
-
   const std::vector<Token>& tokens_;
 
+  static ParserHelper expressions_[Token::NUM_TYPES];
+
   Err* err_;
 
   // Current index into the tokens.
diff --git a/tools/gn/parser_unittest.cc b/tools/gn/parser_unittest.cc
index 3fd8ebe..06464a2 100644
--- a/tools/gn/parser_unittest.cc
+++ b/tools/gn/parser_unittest.cc
@@ -19,49 +19,6 @@
   return !err.has_error();
 }
 
-bool IsIdentifierEqual(const ParseNode* node, const char* val) {
-  if (!node)
-    return false;
-  const IdentifierNode* ident = node->AsIdentifier();
-  if (!ident)
-    return false;
-  return ident->value().value() == val;
-}
-
-bool IsLiteralEqual(const ParseNode* node, const char* val) {
-  if (!node)
-    return false;
-  const LiteralNode* lit = node->AsLiteral();
-  if (!lit)
-    return false;
-  return lit->value().value() == val;
-}
-
-// Returns true if the given node as a simple assignment to a given value.
-bool IsAssignment(const ParseNode* node, const char* ident, const char* value) {
-  if (!node)
-    return false;
-  const BinaryOpNode* binary = node->AsBinaryOp();
-  if (!binary)
-    return false;
-  return binary->op().IsOperatorEqualTo("=") &&
-         IsIdentifierEqual(binary->left(), ident) &&
-         IsLiteralEqual(binary->right(), value);
-}
-
-// Returns true if the given node is a block with one assignment statement.
-bool IsBlockWithAssignment(const ParseNode* node,
-                           const char* ident, const char* value) {
-  if (!node)
-    return false;
-  const BlockNode* block = node->AsBlock();
-  if (!block)
-    return false;
-  if (block->statements().size() != 1)
-    return false;
-  return IsAssignment(block->statements()[0], ident, value);
-}
-
 void DoParserPrintTest(const char* input, const char* expected) {
   std::vector<Token> tokens;
   InputFile input_file(SourceFile("/test"));
@@ -78,6 +35,22 @@
   EXPECT_EQ(expected, collector.str());
 }
 
+void DoExpressionPrintTest(const char* input, const char* expected) {
+  std::vector<Token> tokens;
+  InputFile input_file(SourceFile("/test"));
+  input_file.SetContents(input);
+  ASSERT_TRUE(GetTokens(&input_file, &tokens));
+
+  Err err;
+  scoped_ptr<ParseNode> result = Parser::ParseExpression(tokens, &err);
+  ASSERT_TRUE(result);
+
+  std::ostringstream collector;
+  result->Print(collector, 0);
+
+  EXPECT_EQ(expected, collector.str());
+}
+
 // Expects the tokenizer or parser to identify an error at the given line and
 // character.
 void DoParserErrorTest(const char* input, int err_line, int err_char) {
@@ -96,108 +69,202 @@
   EXPECT_EQ(err_char, err.location().char_offset());
 }
 
-}  // namespace
+// Expects the tokenizer or parser to identify an error at the given line and
+// character.
+void DoExpressionErrorTest(const char* input, int err_line, int err_char) {
+  InputFile input_file(SourceFile("/test"));
+  input_file.SetContents(input);
 
-TEST(Parser, BinaryOp) {
-  std::vector<Token> tokens;
-
-  // Simple set expression.
-  InputFile expr_input(SourceFile("/test"));
-  expr_input.SetContents("a=2");
-  ASSERT_TRUE(GetTokens(&expr_input, &tokens));
   Err err;
-  Parser set(tokens, &err);
-  scoped_ptr<ParseNode> expr = set.ParseExpression();
-  ASSERT_TRUE(expr);
+  std::vector<Token> tokens = Tokenizer::Tokenize(&input_file, &err);
+  if (!err.has_error()) {
+    scoped_ptr<ParseNode> result = Parser::ParseExpression(tokens, &err);
+    ASSERT_FALSE(result);
+    ASSERT_TRUE(err.has_error());
+  }
 
-  const BinaryOpNode* binary_op = expr->AsBinaryOp();
-  ASSERT_TRUE(binary_op);
-
-  EXPECT_TRUE(binary_op->left()->AsIdentifier());
-
-  EXPECT_TRUE(binary_op->op().type() == Token::OPERATOR);
-  EXPECT_TRUE(binary_op->op().value() == "=");
-
-  EXPECT_TRUE(binary_op->right()->AsLiteral());
+  EXPECT_EQ(err_line, err.location().line_number());
+  EXPECT_EQ(err_char, err.location().char_offset());
 }
 
-TEST(Parser, Condition) {
-  std::vector<Token> tokens;
+}  // namespace
 
-  InputFile cond_input(SourceFile("/test"));
-  cond_input.SetContents("if(1) { a = 2 }");
-  ASSERT_TRUE(GetTokens(&cond_input, &tokens));
-  Err err;
-  Parser simple_if(tokens, &err);
-  scoped_ptr<ConditionNode> cond = simple_if.ParseCondition();
-  ASSERT_TRUE(cond);
+TEST(Parser, Literal) {
+  DoExpressionPrintTest("5", "LITERAL(5)\n");
+  DoExpressionPrintTest("\"stuff\"", "LITERAL(\"stuff\")\n");
+}
 
-  EXPECT_TRUE(IsLiteralEqual(cond->condition(), "1"));
-  EXPECT_FALSE(cond->if_false());  // No else block.
-  EXPECT_TRUE(IsBlockWithAssignment(cond->if_true(), "a", "2"));
-
-  // Now try a complicated if/else if/else one.
-  InputFile complex_if_input(SourceFile("/test"));
-  complex_if_input.SetContents(
-      "if(1) { a = 2 } else if (0) { a = 3 } else { a = 4 }");
-  ASSERT_TRUE(GetTokens(&complex_if_input, &tokens));
-  Parser complex_if(tokens, &err);
-  cond = complex_if.ParseCondition();
-  ASSERT_TRUE(cond);
-
-  EXPECT_TRUE(IsLiteralEqual(cond->condition(), "1"));
-  EXPECT_TRUE(IsBlockWithAssignment(cond->if_true(), "a", "2"));
-
-  ASSERT_TRUE(cond->if_false());
-  const ConditionNode* nested_cond = cond->if_false()->AsConditionNode();
-  ASSERT_TRUE(nested_cond);
-  EXPECT_TRUE(IsLiteralEqual(nested_cond->condition(), "0"));
-  EXPECT_TRUE(IsBlockWithAssignment(nested_cond->if_true(), "a", "3"));
-  EXPECT_TRUE(IsBlockWithAssignment(nested_cond->if_false(), "a", "4"));
+TEST(Parser, BinaryOp) {
+  // TODO(scottmg): The tokenizer is dumb, and treats "5-1" as two integers,
+  // not a binary operator between two positive integers.
+  DoExpressionPrintTest("5 - 1",
+      "BINARY(-)\n"
+      " LITERAL(5)\n"
+      " LITERAL(1)\n");
+  DoExpressionPrintTest("5+1",
+      "BINARY(+)\n"
+      " LITERAL(5)\n"
+      " LITERAL(1)\n");
+  DoExpressionPrintTest("5 - 1 - 2",
+      "BINARY(-)\n"
+      " BINARY(-)\n"
+      "  LITERAL(5)\n"
+      "  LITERAL(1)\n"
+      " LITERAL(2)\n");
 }
 
 TEST(Parser, FunctionCall) {
-  const char* input = "foo(a, 1, 2,) bar()";
-  const char* expected =
-      "BLOCK\n"
-      " FUNCTION(foo)\n"
-      "  LIST\n"
-      "   IDENTIFIER(a)\n"
-      "   LITERAL(1)\n"
-      "   LITERAL(2)\n"
-      " FUNCTION(bar)\n"
-      "  LIST\n";
-  DoParserPrintTest(input, expected);
+  DoExpressionPrintTest("foo()",
+      "FUNCTION(foo)\n"
+      " LIST\n");
+  DoExpressionPrintTest("blah(1, 2)",
+      "FUNCTION(blah)\n"
+      " LIST\n"
+      "  LITERAL(1)\n"
+      "  LITERAL(2)\n");
+  DoExpressionErrorTest("foo(1, 2,)", 1, 10);
 }
 
 TEST(Parser, ParenExpression) {
-  const char* input = "(foo(1)) + (a + b)";
+  const char* input = "(foo(1)) + (a + (b - c) + d)";
   const char* expected =
-      "BLOCK\n"
+      "BINARY(+)\n"
+      " FUNCTION(foo)\n"
+      "  LIST\n"
+      "   LITERAL(1)\n"
       " BINARY(+)\n"
-      "  FUNCTION(foo)\n"
-      "   LIST\n"
-      "    LITERAL(1)\n"
       "  BINARY(+)\n"
       "   IDENTIFIER(a)\n"
-      "   IDENTIFIER(b)\n";
+      "   BINARY(-)\n"
+      "    IDENTIFIER(b)\n"
+      "    IDENTIFIER(c)\n"
+      "  IDENTIFIER(d)\n";
+  DoExpressionPrintTest(input, expected);
+  DoExpressionErrorTest("(a +", 1, 4);
+}
+
+TEST(Parser, OrderOfOperationsLeftAssociative) {
+  const char* input = "5 - 1 - 2\n";
+  const char* expected =
+      "BINARY(-)\n"
+      " BINARY(-)\n"
+      "  LITERAL(5)\n"
+      "  LITERAL(1)\n"
+      " LITERAL(2)\n";
+  DoExpressionPrintTest(input, expected);
+}
+
+TEST(Parser, OrderOfOperationsEqualityBoolean) {
+  const char* input =
+      "if (a == \"b\" && is_stuff) {\n"
+      "  print(\"hai\")\n"
+      "}\n";
+  const char* expected =
+      "BLOCK\n"
+      " CONDITION\n"
+      "  BINARY(&&)\n"
+      "   BINARY(==)\n"
+      "    IDENTIFIER(a)\n"
+      "    LITERAL(\"b\")\n"
+      "   IDENTIFIER(is_stuff)\n"
+      "  BLOCK\n"
+      "   FUNCTION(print)\n"
+      "    LIST\n"
+      "     LITERAL(\"hai\")\n";
   DoParserPrintTest(input, expected);
-  DoParserErrorTest("(a +", 1, 4);
 }
 
 TEST(Parser, UnaryOp) {
-  std::vector<Token> tokens;
+  DoExpressionPrintTest("!foo",
+      "UNARY(!)\n"
+      " IDENTIFIER(foo)\n");
+}
 
-  InputFile ident_input(SourceFile("/test"));
-  ident_input.SetContents("!foo");
-  ASSERT_TRUE(GetTokens(&ident_input, &tokens));
-  Err err;
-  Parser ident(tokens, &err);
-  scoped_ptr<UnaryOpNode> op = ident.ParseUnaryOp();
+TEST(Parser, List) {
+  DoExpressionPrintTest("[]", "LIST\n");
+  DoExpressionPrintTest("[1,asd,]",
+      "LIST\n"
+      " LITERAL(1)\n"
+      " IDENTIFIER(asd)\n");
+  DoExpressionPrintTest("[1, 2+3 - foo]",
+      "LIST\n"
+      " LITERAL(1)\n"
+      " BINARY(-)\n"
+      "  BINARY(+)\n"
+      "   LITERAL(2)\n"
+      "   LITERAL(3)\n"
+      "  IDENTIFIER(foo)\n");
+  DoExpressionPrintTest("[1,\n2,\n 3,\n  4]",
+      "LIST\n"
+      " LITERAL(1)\n"
+      " LITERAL(2)\n"
+      " LITERAL(3)\n"
+      " LITERAL(4)\n");
 
-  ASSERT_TRUE(op);
-  EXPECT_TRUE(op->op().type() == Token::OPERATOR);
-  EXPECT_TRUE(op->op().value() == "!");
+  DoExpressionErrorTest("[a, 2+,]", 1, 6);
+  DoExpressionErrorTest("[,]", 1, 2);
+  DoExpressionErrorTest("[a,,]", 1, 4);
+}
+
+TEST(Parser, Assignment) {
+  DoParserPrintTest("a=2",
+                    "BLOCK\n"
+                    " BINARY(=)\n"
+                    "  IDENTIFIER(a)\n"
+                    "  LITERAL(2)\n");
+}
+
+TEST(Parser, Accessor) {
+  DoParserPrintTest("a=b[2]",
+                    "BLOCK\n"
+                    " BINARY(=)\n"
+                    "  IDENTIFIER(a)\n"
+                    "  ACCESSOR\n"
+                    "   b\n"  // AccessorNode is a bit weird in that it holds
+                              // a Token, not a ParseNode for the base.
+                    "   LITERAL(2)\n");
+  DoParserErrorTest("a = b[1][0]", 1, 5);
+}
+
+TEST(Parser, Condition) {
+  DoParserPrintTest("if(1) { a = 2 }",
+                    "BLOCK\n"
+                    " CONDITION\n"
+                    "  LITERAL(1)\n"
+                    "  BLOCK\n"
+                    "   BINARY(=)\n"
+                    "    IDENTIFIER(a)\n"
+                    "    LITERAL(2)\n");
+
+  DoParserPrintTest("if(1) { a = 2 } else if (0) { a = 3 } else { a = 4 }",
+                    "BLOCK\n"
+                    " CONDITION\n"
+                    "  LITERAL(1)\n"
+                    "  BLOCK\n"
+                    "   BINARY(=)\n"
+                    "    IDENTIFIER(a)\n"
+                    "    LITERAL(2)\n"
+                    "  CONDITION\n"
+                    "   LITERAL(0)\n"
+                    "   BLOCK\n"
+                    "    BINARY(=)\n"
+                    "     IDENTIFIER(a)\n"
+                    "     LITERAL(3)\n"
+                    "   BLOCK\n"
+                    "    BINARY(=)\n"
+                    "     IDENTIFIER(a)\n"
+                    "     LITERAL(4)\n");
+}
+
+TEST(Parser, OnlyCallAndAssignInBody) {
+  DoParserErrorTest("[]", 1, 2);
+  DoParserErrorTest("3 + 4", 1, 5);
+  DoParserErrorTest("6 - 7", 1, 5);
+  DoParserErrorTest("if (1) { 5 } else { print(4) }", 1, 12);
+}
+
+TEST(Parser, NoAssignmentInCondition) {
+  DoParserErrorTest("if (a=2) {}", 1, 5);
 }
 
 TEST(Parser, CompleteFunction) {
@@ -278,7 +345,7 @@
 }
 
 TEST(Parser, NestedBlocks) {
-  const char* input = "{cc_test(\"foo\") {{foo=1}{}}}";
+  const char* input = "{cc_test(\"foo\") {{foo=1}\n{}}}";
   const char* expected =
       "BLOCK\n"
       " BLOCK\n"
@@ -292,38 +359,119 @@
       "      LITERAL(1)\n"
       "    BLOCK\n";
   DoParserPrintTest(input, expected);
-}
-
-TEST(Parser, List) {
-  const char* input = "[] a = [1,asd,] b = [1, 2+3 - foo]";
-  const char* expected =
-      "BLOCK\n"
-      " LIST\n"
-      " BINARY(=)\n"
-      "  IDENTIFIER(a)\n"
-      "  LIST\n"
-      "   LITERAL(1)\n"
-      "   IDENTIFIER(asd)\n"
-      " BINARY(=)\n"
-      "  IDENTIFIER(b)\n"
-      "  LIST\n"
-      "   LITERAL(1)\n"
-      "   BINARY(+)\n"
-      "    LITERAL(2)\n"
-      "    BINARY(-)\n"
-      "     LITERAL(3)\n"
-      "     IDENTIFIER(foo)\n";
-  DoParserPrintTest(input, expected);
-
-  DoParserErrorTest("[a, 2+,]", 1, 7);
-  DoParserErrorTest("[,]", 1, 2);
-  DoParserErrorTest("[a,,]", 1, 4);
+  const char* input_with_newline = "{cc_test(\"foo\") {{foo=1}\n{}}}";
+  DoParserPrintTest(input_with_newline, expected);
 }
 
 TEST(Parser, UnterminatedBlock) {
-  DoParserErrorTest("hello {", 1, 7);
+  DoParserErrorTest("stuff() {", 1, 9);
 }
 
 TEST(Parser, BadlyTerminatedNumber) {
   DoParserErrorTest("1234z", 1, 5);
 }
+
+TEST(Parser, NewlinesInUnusualPlaces) {
+  DoParserPrintTest(
+      "if\n"
+      "(\n"
+      "a\n"
+      ")\n"
+      "{\n"
+      "}\n",
+      "BLOCK\n"
+      " CONDITION\n"
+      "  IDENTIFIER(a)\n"
+      "  BLOCK\n");
+}
+
+TEST(Parser, NewlinesInUnusualPlaces2) {
+  DoParserPrintTest(
+      "a\n=\n2\n",
+      "BLOCK\n"
+      " BINARY(=)\n"
+      "  IDENTIFIER(a)\n"
+      "  LITERAL(2)\n");
+  DoParserPrintTest(
+      "x =\ny if\n(1\n) {}",
+      "BLOCK\n"
+      " BINARY(=)\n"
+      "  IDENTIFIER(x)\n"
+      "  IDENTIFIER(y)\n"
+      " CONDITION\n"
+      "  LITERAL(1)\n"
+      "  BLOCK\n");
+  DoParserPrintTest(
+      "x = 3\n+2",
+      "BLOCK\n"
+      " BINARY(=)\n"
+      "  IDENTIFIER(x)\n"
+      "  BINARY(+)\n"
+      "   LITERAL(3)\n"
+      "   LITERAL(2)\n"
+      );
+}
+
+TEST(Parser, NewlineBeforeSubscript) {
+  const char* input = "a = b[1]";
+  const char* input_with_newline = "a = b\n[1]";
+  const char* expected =
+    "BLOCK\n"
+    " BINARY(=)\n"
+    "  IDENTIFIER(a)\n"
+    "  ACCESSOR\n"
+    "   b\n"
+    "   LITERAL(1)\n";
+  DoParserPrintTest(
+      input,
+      expected);
+  DoParserPrintTest(
+      input_with_newline,
+      expected);
+}
+
+TEST(Parser, SequenceOfExpressions) {
+  DoParserPrintTest(
+      "a = 1 b = 2",
+      "BLOCK\n"
+      " BINARY(=)\n"
+      "  IDENTIFIER(a)\n"
+      "  LITERAL(1)\n"
+      " BINARY(=)\n"
+      "  IDENTIFIER(b)\n"
+      "  LITERAL(2)\n");
+}
+
+TEST(Parser, BlockAfterFunction) {
+  const char* input = "func(\"stuff\") {\n}";
+  // TODO(scottmg): Do we really want these to mean different things?
+  const char* input_with_newline = "func(\"stuff\")\n{\n}";
+  const char* expected =
+    "BLOCK\n"
+    " FUNCTION(func)\n"
+    "  LIST\n"
+    "   LITERAL(\"stuff\")\n"
+    "  BLOCK\n";
+  DoParserPrintTest(input, expected);
+  DoParserPrintTest(input_with_newline, expected);
+}
+
+TEST(Parser, LongExpression) {
+  const char* input = "a = b + c && d || e";
+  const char* expected =
+    "BLOCK\n"
+    " BINARY(=)\n"
+    "  IDENTIFIER(a)\n"
+    "  BINARY(||)\n"
+    "   BINARY(&&)\n"
+    "    BINARY(+)\n"
+    "     IDENTIFIER(b)\n"
+    "     IDENTIFIER(c)\n"
+    "    IDENTIFIER(d)\n"
+    "   IDENTIFIER(e)\n";
+  DoParserPrintTest(input, expected);
+}
+
+TEST(Parser, HangingIf) {
+  DoParserErrorTest("if", 1, 1);
+}
diff --git a/tools/gn/pattern.cc b/tools/gn/pattern.cc
index cc08b2c..b7f4229 100644
--- a/tools/gn/pattern.cc
+++ b/tools/gn/pattern.cc
@@ -6,6 +6,39 @@
 
 #include "tools/gn/value.h"
 
+const char kPattern_Help[] =
+    "Patterns\n"
+    "  Patterns are VERY limited regular expressions that are used in\n"
+    "  several places.\n"
+    "\n"
+    "  Patterns must match the entire input string to be counted as a match.\n"
+    "  In regular expression parlance, there is an implicit \"^...$\"\n"
+    "  surrounding your input. If you want to match a substring, you need to\n"
+    "  use wildcards at the beginning and end.\n"
+    "\n"
+    "  There are only two special tokens understood by the pattern matcher.\n"
+    "  Everything else is a literal.\n"
+    "\n"
+    "   * Matches zero or more of any character. It does not depend on the\n"
+    "     preceeding character (in regular expression parlance it is\n"
+    "     equivalent to \".*\").\n"
+    "\n"
+    "  \\b Matches a path boundary. This will match the beginning or end of\n"
+    "     a string, or a slash.\n"
+    "\n"
+    "Examples:\n"
+    "  \"*asdf*\"\n"
+    "      Matches a string containing \"asdf\" anywhere.\n"
+    "\n"
+    "  \"asdf\"\n"
+    "      Matches only the exact string \"asdf\".\n"
+    "\n"
+    "  \"*.cc\"\n"
+    "      Matches strings ending in the literal \".cc\".\n"
+    "\n"
+    "  \"\\bwin/*\"\n"
+    "      Matches \"win/foo\" and \"foo/win/bar.cc\" but not \"iwin/foo\".\n";
+
 namespace {
 
 void ParsePattern(const std::string& s, std::vector<Pattern::Subrange>* out) {
diff --git a/tools/gn/pattern.h b/tools/gn/pattern.h
index 582cfea..a7769fa 100644
--- a/tools/gn/pattern.h
+++ b/tools/gn/pattern.h
@@ -10,6 +10,8 @@
 
 #include "tools/gn/value.h"
 
+extern const char kPattern_Help[];
+
 class Pattern {
  public:
   struct Subrange {
diff --git a/tools/gn/scheduler.cc b/tools/gn/scheduler.cc
index 33c8f1a..72c310b 100644
--- a/tools/gn/scheduler.cc
+++ b/tools/gn/scheduler.cc
@@ -5,13 +5,29 @@
 #include "tools/gn/scheduler.h"
 
 #include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
 #include "tools/gn/ninja_target_writer.h"
 #include "tools/gn/standard_out.h"
 
 Scheduler* g_scheduler = NULL;
 
+namespace {
+
+int GetThreadCount() {
+  std::string thread_count =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII("threads");
+
+  int result;
+  if (thread_count.empty() || !base::StringToInt(thread_count, &result))
+    return 32;
+  return result;
+}
+
+}  // namespace
+
 Scheduler::Scheduler()
-    : pool_(new base::SequencedWorkerPool(32, "worker_")),
+    : pool_(new base::SequencedWorkerPool(GetThreadCount(), "worker_")),
       input_file_manager_(new InputFileManager),
       verbose_logging_(false),
       work_count_(0),
@@ -77,12 +93,12 @@
       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
 }
 
-void Scheduler::AddGenDependency(const SourceFile& source_file) {
+void Scheduler::AddGenDependency(const base::FilePath& file) {
   base::AutoLock lock(lock_);
-  gen_dependencies_.push_back(source_file);
+  gen_dependencies_.push_back(file);
 }
 
-std::vector<SourceFile> Scheduler::GetGenDependencies() const {
+std::vector<base::FilePath> Scheduler::GetGenDependencies() const {
   base::AutoLock lock(lock_);
   return gen_dependencies_;
 }
diff --git a/tools/gn/scheduler.h b/tools/gn/scheduler.h
index eab996d..4b2c060 100644
--- a/tools/gn/scheduler.h
+++ b/tools/gn/scheduler.h
@@ -7,6 +7,7 @@
 
 #include "base/atomic_ref_count.h"
 #include "base/basictypes.h"
+#include "base/files/file_path.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/synchronization/lock.h"
@@ -46,8 +47,8 @@
   // TODO(brettw) this is global rather than per-BuildSettings. If we
   // start using >1 build settings, then we probably want this to take a
   // BuildSettings object so we know the depdency on a per-build basis.
-  void AddGenDependency(const SourceFile& source_file);
-  std::vector<SourceFile> GetGenDependencies() const;
+  void AddGenDependency(const base::FilePath& file);
+  std::vector<base::FilePath> GetGenDependencies() const;
 
   // We maintain a count of the things we need to do that works like a
   // refcount. When this reaches 0, the program exits.
@@ -79,7 +80,7 @@
   bool is_failed_;
 
   // Additional input dependencies. Protected by the lock.
-  std::vector<SourceFile> gen_dependencies_;
+  std::vector<base::FilePath> gen_dependencies_;
 
   DISALLOW_COPY_AND_ASSIGN(Scheduler);
 };
diff --git a/tools/gn/scope.cc b/tools/gn/scope.cc
index 72664d7..42277f7 100644
--- a/tools/gn/scope.cc
+++ b/tools/gn/scope.cc
@@ -156,7 +156,7 @@
           "\" here and it was unused before it went\nout of scope.";
 
       const BinaryOpNode* binary = i->second.value.origin()->AsBinaryOp();
-      if (binary) {
+      if (binary && binary->op().type() == Token::EQUAL) {
         // Make a nicer error message for normal var sets.
         *err = Err(binary->left()->GetRange(), "Assignment had no effect.",
                    help);
@@ -170,11 +170,9 @@
   return true;
 }
 
-void Scope::GetCurrentScopeValues(KeyValueVector* output) const {
-  output->reserve(values_.size());
-  for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) {
-    output->push_back(std::make_pair(i->first, i->second.value));
-  }
+void Scope::GetCurrentScopeValues(KeyValueMap* output) const {
+  for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i)
+    (*output)[i->first] = i->second.value;
 }
 
 bool Scope::NonRecursiveMergeTo(Scope* dest,
@@ -341,6 +339,14 @@
   return false;
 }
 
+const SourceDir& Scope::GetSourceDir() const {
+  if (!source_dir_.is_null())
+    return source_dir_;
+  if (containing())
+    return containing()->GetSourceDir();
+  return source_dir_;
+}
+
 void Scope::SetProperty(const void* key, void* value) {
   if (!value) {
     DCHECK(properties_.find(key) != properties_.end());
diff --git a/tools/gn/scope.h b/tools/gn/scope.h
index 7d0547e..0d1c156 100644
--- a/tools/gn/scope.h
+++ b/tools/gn/scope.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "tools/gn/err.h"
 #include "tools/gn/pattern.h"
+#include "tools/gn/source_dir.h"
 #include "tools/gn/value.h"
 
 class FunctionCallNode;
@@ -34,7 +35,7 @@
 // variables. So you should use a non-const containing scope whenever possible.
 class Scope {
  public:
-  typedef std::vector<std::pair<base::StringPiece, Value> > KeyValueVector;
+  typedef base::hash_map<base::StringPiece, Value> KeyValueMap;
 
   // Allows code to provide values for built-in variables. This class will
   // automatically register itself on construction and deregister itself on
@@ -126,7 +127,7 @@
 
   // Returns all values set in the current scope, without going to the parent
   // scopes.
-  void GetCurrentScopeValues(KeyValueVector* output) const;
+  void GetCurrentScopeValues(KeyValueMap* output) const;
 
   // Copies this scope's values into the destination. Values from the
   // containing scope(s) (normally shadowed into the current one) will not be
@@ -188,6 +189,12 @@
   void ClearProcessingImport();
   bool IsProcessingImport() const;
 
+  // The source directory associated with this scope. This will check embedded
+  // scopes until it finds a nonempty source directory. This will default to
+  // an empty dir if no containing scope has a source dir set.
+  const SourceDir& GetSourceDir() const;
+  void set_source_dir(const SourceDir& d) { source_dir_ = d; }
+
   // Properties are opaque pointers that code can use to set state on a Scope
   // that it can retrieve later.
   //
@@ -248,12 +255,15 @@
   typedef std::map<std::string, const FunctionCallNode*> TemplateMap;
   TemplateMap templates_;
 
+  // Opaque pointers. See SetProperty() above.
   typedef std::map<const void*, void*> PropertyMap;
   PropertyMap properties_;
 
   typedef std::set<ProgrammaticProvider*> ProviderSet;
   ProviderSet programmatic_providers_;
 
+  SourceDir source_dir_;
+
   DISALLOW_COPY_AND_ASSIGN(Scope);
 };
 
diff --git a/tools/gn/scope_per_file_provider.cc b/tools/gn/scope_per_file_provider.cc
index acb1b3c..6e61dad 100644
--- a/tools/gn/scope_per_file_provider.cc
+++ b/tools/gn/scope_per_file_provider.cc
@@ -29,10 +29,14 @@
   if (ident == variables::kPythonPath)
     return GetPythonPath();
 
+  if (ident == variables::kRelativeBuildToSourceRootDir)
+    return GetRelativeBuildToSourceRootDir();
   if (ident == variables::kRelativeRootOutputDir)
     return GetRelativeRootOutputDir();
   if (ident == variables::kRelativeRootGenDir)
     return GetRelativeRootGenDir();
+  if (ident == variables::kRelativeSourceRootDir)
+    return GetRelativeSourceRootDir();
   if (ident == variables::kRelativeTargetOutputDir)
     return GetRelativeTargetOutputDir();
   if (ident == variables::kRelativeTargetGenDir)
@@ -67,6 +71,16 @@
   return python_path_.get();
 }
 
+const Value* ScopePerFileProvider::GetRelativeBuildToSourceRootDir() {
+  if (!relative_build_to_source_root_dir_) {
+    const SourceDir& build_dir =
+        scope_->settings()->build_settings()->build_dir();
+    relative_build_to_source_root_dir_.reset(
+        new Value(NULL, InvertDirWithNoLastSlash(build_dir)));
+  }
+  return relative_build_to_source_root_dir_.get();
+}
+
 const Value* ScopePerFileProvider::GetRelativeRootOutputDir() {
   if (!relative_root_output_dir_) {
     relative_root_output_dir_.reset(new Value(NULL,
@@ -85,6 +99,14 @@
   return relative_root_gen_dir_.get();
 }
 
+const Value* ScopePerFileProvider::GetRelativeSourceRootDir() {
+  if (!relative_source_root_dir_) {
+    relative_source_root_dir_.reset(new Value(NULL,
+        GetRelativeRootWithNoLastSlash()));
+  }
+  return relative_source_root_dir_.get();
+}
+
 const Value* ScopePerFileProvider::GetRelativeTargetOutputDir() {
   if (!relative_target_output_dir_) {
     relative_target_output_dir_.reset(new Value(NULL,
@@ -110,8 +132,11 @@
     const Settings* settings) {
   const std::string& output_dir =
       settings->build_settings()->build_dir().value();
-  CHECK(!output_dir.empty());
-  return output_dir.substr(1, output_dir.size() - 1);
+
+  // Trim off a leading and trailing slash. So "//foo/bar/" -> /foo/bar".
+  DCHECK(output_dir.size() > 2 && output_dir[0] == '/' &&
+         output_dir[output_dir.size() - 1] == '/');
+  return output_dir.substr(1, output_dir.size() - 2);
 }
 
 // static
@@ -121,12 +146,22 @@
 }
 
 std::string ScopePerFileProvider::GetFileDirWithNoLastSlash() const {
-  std::string dir_value = source_file_.GetDir().value();
-  return dir_value.substr(0, dir_value.size() - 1);
+  const std::string& dir_value = scope_->GetSourceDir().value();
+
+  // Trim off a leading and trailing slash. So "//foo/bar/" -> /foo/bar".
+  DCHECK(dir_value.size() > 2 && dir_value[0] == '/' &&
+         dir_value[dir_value.size() - 1] == '/');
+  return dir_value.substr(1, dir_value.size() - 2);
 }
 
 std::string ScopePerFileProvider::GetRelativeRootWithNoLastSlash() const {
-  std::string inverted = InvertDir(source_file_.GetDir());
+  return InvertDirWithNoLastSlash(scope_->GetSourceDir());
+}
+
+// static
+std::string ScopePerFileProvider::InvertDirWithNoLastSlash(
+    const SourceDir& dir) {
+  std::string inverted = InvertDir(dir);
   if (inverted.empty())
     return ".";
   return inverted.substr(0, inverted.size() - 1);
diff --git a/tools/gn/scope_per_file_provider.h b/tools/gn/scope_per_file_provider.h
index c6d6537..27443b4 100644
--- a/tools/gn/scope_per_file_provider.h
+++ b/tools/gn/scope_per_file_provider.h
@@ -25,8 +25,10 @@
   const Value* GetCurrentToolchain();
   const Value* GetDefaultToolchain();
   const Value* GetPythonPath();
+  const Value* GetRelativeBuildToSourceRootDir();
   const Value* GetRelativeRootOutputDir();
   const Value* GetRelativeRootGenDir();
+  const Value* GetRelativeSourceRootDir();
   const Value* GetRelativeTargetOutputDir();
   const Value* GetRelativeTargetGenDir();
 
@@ -36,14 +38,20 @@
   std::string GetFileDirWithNoLastSlash() const;
   std::string GetRelativeRootWithNoLastSlash() const;
 
+  // Inverts the given directory, returning it with no trailing slash. If the
+  // result would be empty, "." is returned to indicate the current dir.
+  static std::string InvertDirWithNoLastSlash(const SourceDir& dir);
+
   SourceFile source_file_;
 
   // All values are lazily created.
   scoped_ptr<Value> current_toolchain_;
   scoped_ptr<Value> default_toolchain_;
   scoped_ptr<Value> python_path_;
+  scoped_ptr<Value> relative_build_to_source_root_dir_;
   scoped_ptr<Value> relative_root_output_dir_;
   scoped_ptr<Value> relative_root_gen_dir_;
+  scoped_ptr<Value> relative_source_root_dir_;
   scoped_ptr<Value> relative_target_output_dir_;
   scoped_ptr<Value> relative_target_gen_dir_;
 
diff --git a/tools/gn/script_target_generator.cc b/tools/gn/script_target_generator.cc
new file mode 100644
index 0000000..8df05b6
--- /dev/null
+++ b/tools/gn/script_target_generator.cc
@@ -0,0 +1,83 @@
+// 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 "tools/gn/script_target_generator.h"
+
+#include "tools/gn/err.h"
+#include "tools/gn/filesystem_utils.h"
+#include "tools/gn/scope.h"
+#include "tools/gn/value.h"
+#include "tools/gn/value_extractors.h"
+
+ScriptTargetGenerator::ScriptTargetGenerator(Target* target,
+                                             Scope* scope,
+                                             const Token& function_token,
+                                             Err* err)
+    : TargetGenerator(target, scope, function_token, err) {
+}
+
+ScriptTargetGenerator::~ScriptTargetGenerator() {
+}
+
+void ScriptTargetGenerator::DoRun() {
+  target_->set_output_type(Target::CUSTOM);
+
+  FillSources();
+  FillScript();
+  FillScriptArgs();
+  FillOutputs();
+
+  // Script outputs don't depend on the current toolchain so we can skip adding
+  // that dependency.
+}
+
+void ScriptTargetGenerator::FillScript() {
+  // If this gets called, the target type requires a script, so error out
+  // if it doesn't have one.
+  // TODO(brettw) hook up a constant in variables.h
+  const Value* value = scope_->GetValue("script", true);
+  if (!value) {
+    *err_ = Err(function_token_, "This target type requires a \"script\".");
+    return;
+  }
+  if (!value->VerifyTypeIs(Value::STRING, err_))
+    return;
+
+  target_->script_values().set_script(
+      scope_->GetSourceDir().ResolveRelativeFile(value->string_value()));
+}
+
+void ScriptTargetGenerator::FillScriptArgs() {
+  const Value* value = scope_->GetValue("args", true);
+  if (!value)
+    return;
+
+  std::vector<std::string> args;
+  if (!ExtractListOfStringValues(*value, &args, err_))
+    return;
+  target_->script_values().swap_in_args(&args);
+}
+
+void ScriptTargetGenerator::FillOutputs() {
+  // TODO(brettw) hook up a constant in variables.h
+  const Value* value = scope_->GetValue("outputs", true);
+  if (!value)
+    return;
+
+  Target::FileList outputs;
+  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
+                                  scope_->GetSourceDir(), &outputs, err_))
+    return;
+
+  // Validate that outputs are in the output dir.
+  CHECK(outputs.size() == value->list_value().size());
+  for (size_t i = 0; i < outputs.size(); i++) {
+    if (!EnsureStringIsInOutputDir(
+            GetBuildSettings()->build_dir(),
+            outputs[i].value(), value->list_value()[i], err_))
+      return;
+  }
+  target_->script_values().swap_in_outputs(&outputs);
+}
+
diff --git a/tools/gn/script_target_generator.h b/tools/gn/script_target_generator.h
new file mode 100644
index 0000000..c5e1811
--- /dev/null
+++ b/tools/gn/script_target_generator.h
@@ -0,0 +1,32 @@
+// 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 TOOLS_GN_SCRIPT_TARGET_GENERATOR_H_
+#define TOOLS_GN_SCRIPT_TARGET_GENERATOR_H_
+
+#include "base/compiler_specific.h"
+#include "tools/gn/target_generator.h"
+
+// Populates a Target with the values from a custom script rule.
+class ScriptTargetGenerator : public TargetGenerator {
+ public:
+  ScriptTargetGenerator(Target* target,
+                      Scope* scope,
+                      const Token& function_token,
+                      Err* err);
+  virtual ~ScriptTargetGenerator();
+
+ protected:
+  virtual void DoRun() OVERRIDE;
+
+ private:
+  void FillScript();
+  void FillScriptArgs();
+  void FillOutputs();
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptTargetGenerator);
+};
+
+#endif  // TOOLS_GN_SCRIPT_TARGET_GENERATOR_H_
+
diff --git a/tools/gn/script_values.cc b/tools/gn/script_values.cc
new file mode 100644
index 0000000..c5d7989
--- /dev/null
+++ b/tools/gn/script_values.cc
@@ -0,0 +1,11 @@
+// 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 "tools/gn/script_values.h"
+
+ScriptValues::ScriptValues() {
+}
+
+ScriptValues::~ScriptValues() {
+}
diff --git a/tools/gn/script_values.h b/tools/gn/script_values.h
new file mode 100644
index 0000000..4a874b9
--- /dev/null
+++ b/tools/gn/script_values.h
@@ -0,0 +1,41 @@
+// 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 TOOLS_GN_SCRIPT_VALUES_H_
+#define TOOLS_GN_SCRIPT_VALUES_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "tools/gn/source_file.h"
+
+// Holds the values (outputs, args, script name, etc.) for a script-based
+// target.
+class ScriptValues {
+ public:
+  ScriptValues();
+  ~ScriptValues();
+
+  // Filename of the script to execute.
+  const SourceFile& script() const { return script_; }
+  void set_script(const SourceFile& s) { script_ = s; }
+
+  // Arguments to the script.
+  const std::vector<std::string>& args() const { return args_; }
+  void swap_in_args(std::vector<std::string>* a) { args_.swap(*a); }
+
+  // Files created by the script.
+  const std::vector<SourceFile>& outputs() const { return outputs_; }
+  void swap_in_outputs(std::vector<SourceFile>* op) { outputs_.swap(*op); }
+
+ private:
+  SourceFile script_;
+  std::vector<std::string> args_;
+  std::vector<SourceFile> outputs_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScriptValues);
+};
+
+#endif  // TOOLS_GN_SCRIPT_VALUES_H_
diff --git a/tools/gn/secondary/BUILD.gn b/tools/gn/secondary/BUILD.gn
index 2039b82..0ed32b1 100644
--- a/tools/gn/secondary/BUILD.gn
+++ b/tools/gn/secondary/BUILD.gn
@@ -1,6 +1,18 @@
-group("root") {

-  deps = [

-    "//tools/gn",

-    "//ipc",

-  ]

-}

+# 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.
+
+group("root") {
+  deps = [
+    "//base(//build/toolchain/nacl:x86_newlib)",
+    "//crypto",
+    "//ipc",
+    "//net",
+    "//net/third_party/nss/ssl:crssl",
+    "//sdch",
+    "//third_party/icu:icudata",
+    "//third_party/zlib",
+    "//tools/gn",
+    "//url:url_lib",
+  ]
+}
diff --git a/tools/gn/secondary/base/BUILD.gn b/tools/gn/secondary/base/BUILD.gn
index c0013bb..0287b13 100644
--- a/tools/gn/secondary/base/BUILD.gn
+++ b/tools/gn/secondary/base/BUILD.gn
@@ -1,967 +1,878 @@
-# found in the LICENSE file.

-

-component("base") {

-  sources = [

-    "../build/build_config.h",

-    "third_party/dmg_fp/dmg_fp.h",

-    "third_party/dmg_fp/g_fmt.cc",

-    "third_party/dmg_fp/dtoa_wrapper.cc",

-    "third_party/icu/icu_utf.cc",

-    "third_party/icu/icu_utf.h",

-    "third_party/nspr/prcpucfg.h",

-    "third_party/nspr/prcpucfg_freebsd.h",

-    "third_party/nspr/prcpucfg_linux.h",

-    "third_party/nspr/prcpucfg_mac.h",

-    "third_party/nspr/prcpucfg_nacl.h",

-    "third_party/nspr/prcpucfg_openbsd.h",

-    "third_party/nspr/prcpucfg_solaris.h",

-    "third_party/nspr/prcpucfg_win.h",

-    "third_party/nspr/prtime.cc",

-    "third_party/nspr/prtime.h",

-    "third_party/nspr/prtypes.h",

-    "third_party/xdg_mime/xdgmime.h",

-    "allocator/allocator_extension.cc",

-    "allocator/allocator_extension.h",

-    "allocator/type_profiler_control.cc",

-    "allocator/type_profiler_control.h",

-    "android/activity_status.cc",

-    "android/activity_status.h",

-    "android/base_jni_registrar.cc",

-    "android/base_jni_registrar.h",

-    "android/build_info.cc",

-    "android/build_info.h",

-    "android/cpu_features.cc",

-    "android/fifo_utils.cc",

-    "android/fifo_utils.h",

-    "android/important_file_writer_android.cc",

-    "android/important_file_writer_android.h",

-    "android/scoped_java_ref.cc",

-    "android/scoped_java_ref.h",

-    "android/jni_android.cc",

-    "android/jni_android.h",

-    "android/jni_array.cc",

-    "android/jni_array.h",

-    "android/jni_helper.cc",

-    "android/jni_helper.h",

-    "android/jni_registrar.cc",

-    "android/jni_registrar.h",

-    "android/jni_string.cc",

-    "android/jni_string.h",

-    "android/memory_pressure_listener_android.cc",

-    "android/memory_pressure_listener_android.h",

-    "android/path_service_android.cc",

-    "android/path_service_android.h",

-    "android/path_utils.cc",

-    "android/path_utils.h",

-    "android/sys_utils.cc",

-    "android/sys_utils.h",

-    "android/thread_utils.h",

-    "at_exit.cc",

-    "at_exit.h",

-    "atomic_ref_count.h",

-    "atomic_sequence_num.h",

-    "atomicops.h",

-    "atomicops_internals_gcc.h",

-    "atomicops_internals_mac.h",

-    "atomicops_internals_tsan.h",

-    "atomicops_internals_x86_gcc.cc",

-    "atomicops_internals_x86_gcc.h",

-    "atomicops_internals_x86_msvc.h",

-    "base_export.h",

-    "base_paths.cc",

-    "base_paths.h",

-    "base_paths_android.cc",

-    "base_paths_android.h",

-    "base_paths_mac.h",

-    "base_paths_mac.mm",

-    "base_paths_posix.cc",

-    "base_paths_posix.h",

-    "base_paths_win.cc",

-    "base_paths_win.h",

-    "base_switches.h",

-    "base64.cc",

-    "base64.h",

-    "basictypes.h",

-    "bind.h",

-    "bind_helpers.cc",

-    "bind_helpers.h",

-    "bind_internal.h",

-    "bind_internal_win.h",

-    "bits.h",

-    "build_time.cc",

-    "build_time.h",

-    "callback.h",

-    "callback_helpers.h",

-    "callback_internal.cc",

-    "callback_internal.h",

-    "cancelable_callback.h",

-    "chromeos/chromeos_version.cc",

-    "chromeos/chromeos_version.h",

-    "command_line.cc",

-    "command_line.h",

-    "compiler_specific.h",

-    "containers/hash_tables.h",

-    "containers/linked_list.h",

-    "containers/mru_cache.h",

-    "containers/small_map.h",

-    "containers/stack_container.h",

-    "cpu.cc",

-    "cpu.h",

-    "critical_closure.h",

-    "critical_closure_ios.mm",

-    "debug/alias.cc",

-    "debug/alias.h",

-    "debug/crash_logging.cc",

-    "debug/crash_logging.h",

-    "debug/debug_on_start_win.cc",

-    "debug/debug_on_start_win.h",

-    "debug/debugger.cc",

-    "debug/debugger.h",

-    "debug/debugger_posix.cc",

-    "debug/debugger_win.cc",

-    # This file depends on files from the "allocator" target,

-    # but this target does not depend on "allocator" (see

-    # allocator.gyp for details).

-    "debug/leak_annotations.h",

-    "debug/leak_tracker.h",

-    "debug/proc_maps_linux.cc",

-    "debug/proc_maps_linux.h",

-    "debug/profiler.cc",

-    "debug/profiler.h",

-    "debug/stack_trace.cc",

-    "debug/stack_trace.h",

-    "debug/stack_trace_android.cc",

-    "debug/stack_trace_ios.mm",

-    "debug/stack_trace_posix.cc",

-    "debug/stack_trace_win.cc",

-    "debug/trace_event.h",

-    "debug/trace_event_android.cc",

-    "debug/trace_event_impl.cc",

-    "debug/trace_event_impl.h",

-    "debug/trace_event_impl_constants.cc",

-    "debug/trace_event_win.cc",

-    "deferred_sequenced_task_runner.cc",

-    "deferred_sequenced_task_runner.h",

-    "environment.cc",

-    "environment.h",

-    "file_descriptor_posix.h",

-    "file_util.cc",

-    "file_util.h",

-    "file_util_android.cc",

-    "file_util_linux.cc",

-    "file_util_mac.mm",

-    "file_util_posix.cc",

-    "file_util_win.cc",

-    "file_version_info.h",

-    "file_version_info_mac.h",

-    "file_version_info_mac.mm",

-    "file_version_info_win.cc",

-    "file_version_info_win.h",

-    "files/dir_reader_fallback.h",

-    "files/dir_reader_linux.h",

-    "files/dir_reader_posix.h",

-    "files/file_enumerator.cc",

-    "files/file_enumerator.h",

-    "files/file_enumerator_posix.cc",

-    "files/file_enumerator_win.cc",

-    "files/file_path.cc",

-    "files/file_path.h",

-    "files/file_path_constants.cc",

-    "files/file_path_watcher.cc",

-    "files/file_path_watcher.h",

-    "files/file_path_watcher_kqueue.cc",

-    "files/file_path_watcher_linux.cc",

-    "files/file_path_watcher_stub.cc",

-    "files/file_path_watcher_win.cc",

-    "files/file_util_proxy.cc",

-    "files/file_util_proxy.h",

-    "files/important_file_writer.h",

-    "files/important_file_writer.cc",

-    "files/memory_mapped_file.cc",

-    "files/memory_mapped_file.h",

-    "files/memory_mapped_file_posix.cc",

-    "files/memory_mapped_file_win.cc",

-    "files/scoped_temp_dir.cc",

-    "files/scoped_temp_dir.h",

-    "float_util.h",

-    "format_macros.h",

-    "gtest_prod_util.h",

-    "guid.cc",

-    "guid.h",

-    "guid_posix.cc",

-    "guid_win.cc",

-    "hash.cc",

-    "hash.h",

-    "id_map.h",

-    "ini_parser.cc",

-    "ini_parser.h",

-    "ios/device_util.h",

-    "ios/device_util.mm",

-    "ios/ios_util.h",

-    "ios/ios_util.mm",

-    "ios/scoped_critical_action.h",

-    "ios/scoped_critical_action.mm",

-    "json/json_file_value_serializer.cc",

-    "json/json_file_value_serializer.h",

-    "json/json_parser.cc",

-    "json/json_parser.h",

-    "json/json_reader.cc",

-    "json/json_reader.h",

-    "json/json_string_value_serializer.cc",

-    "json/json_string_value_serializer.h",

-    "json/json_value_converter.h",

-    "json/json_writer.cc",

-    "json/json_writer.h",

-    "json/string_escape.cc",

-    "json/string_escape.h",

-    "lazy_instance.cc",

-    "lazy_instance.h",

-    "location.cc",

-    "location.h",

-    "logging.cc",

-    "logging.h",

-    "logging_win.cc",

-    "logging_win.h",

-    "mac/authorization_util.h",

-    "mac/authorization_util.mm",

-    "mac/bind_objc_block.h",

-    "mac/bundle_locations.h",

-    "mac/bundle_locations.mm",

-    "mac/cocoa_protocols.h",

-    "mac/foundation_util.h",

-    "mac/foundation_util.mm",

-    "mac/launch_services_util.cc",

-    "mac/launch_services_util.h",

-    "mac/launchd.cc",

-    "mac/launchd.h",

-    "mac/libdispatch_task_runner.cc",

-    "mac/libdispatch_task_runner.h",

-    "mac/mac_logging.h",

-    "mac/mac_logging.cc",

-    "mac/mac_util.h",

-    "mac/mac_util.mm",

-    "mac/objc_property_releaser.h",

-    "mac/objc_property_releaser.mm",

-    "mac/os_crash_dumps.cc",

-    "mac/os_crash_dumps.h",

-    "mac/scoped_aedesc.h",

-    "mac/scoped_authorizationref.h",

-    "mac/scoped_block.h",

-    "mac/scoped_cftyperef.h",

-    "mac/scoped_ioobject.h",

-    "mac/scoped_ioplugininterface.h",

-    "mac/scoped_launch_data.h",

-    "mac/scoped_mach_port.cc",

-    "mac/scoped_mach_port.h",

-    "mac/scoped_nsautorelease_pool.h",

-    "mac/scoped_nsautorelease_pool.mm",

-    "mac/scoped_nsexception_enabler.h",

-    "mac/scoped_nsexception_enabler.mm",

-    "mac/scoped_nsobject.h",

-    "mac/scoped_sending_event.h",

-    "mac/scoped_sending_event.mm",

-    "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_mac.cc",

-    "memory/linked_ptr.h",

-    "memory/manual_constructor.h",

-    "memory/memory_pressure_listener.cc",

-    "memory/memory_pressure_listener.h",

-    "memory/raw_scoped_refptr_mismatch_checker.h",

-    "memory/ref_counted.cc",

-    "memory/ref_counted.h",

-    "memory/ref_counted_delete_on_message_loop.h",

-    "memory/ref_counted_memory.cc",

-    "memory/ref_counted_memory.h",

-    "memory/scoped_handle.h",

-    "memory/scoped_open_process.h",

-    "memory/scoped_policy.h",

-    "memory/scoped_ptr.h",

-    "memory/scoped_vector.h",

-    "memory/shared_memory.h",

-    "memory/shared_memory_android.cc",

-    "memory/shared_memory_nacl.cc",

-    "memory/shared_memory_posix.cc",

-    "memory/shared_memory_win.cc",

-    "memory/singleton.cc",

-    "memory/singleton.h",

-    "memory/weak_ptr.cc",

-    "memory/weak_ptr.h",

-    "message_loop/incoming_task_queue.cc",

-    "message_loop/incoming_task_queue.h",

-    "message_loop/message_loop.cc",

-    "message_loop/message_loop.h",

-    "message_loop/message_loop_proxy.cc",

-    "message_loop/message_loop_proxy.h",

-    "message_loop/message_loop_proxy_impl.cc",

-    "message_loop/message_loop_proxy_impl.h",

-    "message_loop/message_pump.cc",

-    "message_loop/message_pump.h",

-    "message_loop/message_pump_android.cc",

-    "message_loop/message_pump_android.h",

-    "message_loop/message_pump_aurax11.cc",

-    "message_loop/message_pump_aurax11.h",

-    "message_loop/message_pump_default.cc",

-    "message_loop/message_pump_default.h",

-    "message_loop/message_pump_glib.cc",

-    "message_loop/message_pump_glib.h",

-    "message_loop/message_pump_gtk.cc",

-    "message_loop/message_pump_gtk.h",

-    "message_loop/message_pump_io_ios.cc",

-    "message_loop/message_pump_io_ios.h",

-    "message_loop/message_pump_libevent.cc",

-    "message_loop/message_pump_libevent.h",

-    "message_loop/message_pump_mac.h",

-    "message_loop/message_pump_mac.mm",

-    "message_loop/message_pump_observer.h",

-    "message_loop/message_pump_ozone.cc",

-    "message_loop/message_pump_ozone.h",

-    "message_loop/message_pump_win.cc",

-    "message_loop/message_pump_win.h",

-    "metrics/field_trial.cc",

-    "metrics/field_trial.h",

-    "metrics/sample_map.cc",

-    "metrics/sample_map.h",

-    "metrics/sample_vector.cc",

-    "metrics/sample_vector.h",

-    "metrics/bucket_ranges.cc",

-    "metrics/bucket_ranges.h",

-    "metrics/histogram.cc",

-    "metrics/histogram.h",

-    "metrics/histogram_base.cc",

-    "metrics/histogram_base.h",

-    "metrics/histogram_flattener.h",

-    "metrics/histogram_samples.cc",

-    "metrics/histogram_samples.h",

-    "metrics/histogram_snapshot_manager.cc",

-    "metrics/histogram_snapshot_manager.h",

-    "metrics/sparse_histogram.cc",

-    "metrics/sparse_histogram.h",

-    "metrics/statistics_recorder.cc",

-    "metrics/statistics_recorder.h",

-    "metrics/stats_counters.cc",

-    "metrics/stats_counters.h",

-    "metrics/stats_table.cc",

-    "metrics/stats_table.h",

-    "move.h",

-    "native_library.h",

-    "native_library_mac.mm",

-    "native_library_posix.cc",

-    "native_library_win.cc",

-    "nix/mime_util_xdg.cc",

-    "nix/mime_util_xdg.h",

-    "nix/xdg_util.cc",

-    "nix/xdg_util.h",

-    "observer_list.h",

-    "observer_list_threadsafe.h",

-    "os_compat_android.cc",

-    "os_compat_android.h",

-    "os_compat_nacl.cc",

-    "os_compat_nacl.h",

-    "path_service.cc",

-    "path_service.h",

-    "pending_task.cc",

-    "pending_task.h",

-    "pickle.cc",

-    "pickle.h",

-    "platform_file.cc",

-    "platform_file.h",

-    "platform_file_posix.cc",

-    "platform_file_win.cc",

-    "port.h",

-    "posix/eintr_wrapper.h",

-    "posix/file_descriptor_shuffle.cc",

-    "posix/file_descriptor_shuffle.y",

-    "posix/global_descriptors.cc",

-    "posix/global_descriptors.h",

-    "posix/unix_domain_socket_linux.cc",

-    "posix/unix_domain_socket_linux.h",

-    "power_monitor/power_monitor.cc",

-    "power_monitor/power_monitor.h",

-    "power_monitor/power_monitor_device_source.cc",

-    "power_monitor/power_monitor_device_source.h",

-    "power_monitor/power_monitor_device_source_android.cc",

-    "power_monitor/power_monitor_device_source_android.h",

-    "power_monitor/power_monitor_device_source_ios.mm",

-    "power_monitor/power_monitor_device_source_mac.mm",

-    "power_monitor/power_monitor_device_source_posix.cc",

-    "power_monitor/power_monitor_device_source_win.cc",

-    "power_monitor/power_monitor_source.cc",

-    "power_monitor/power_monitor_source.h",

-    "power_monitor/power_observer.h",

-    "process/internal_linux.cc",

-    "process/internal_linux.h",

-    "process/kill.cc",

-    "process/kill.h",

-    "process/kill_mac.cc",

-    "process/kill_posix.cc",

-    "process/kill_win.cc",

-    "process/launch.h",

-    "process/launch_ios.cc",

-    "process/launch_mac.cc",

-    "process/launch_posix.cc",

-    "process/launch_win.cc",

-    "process/memory.h",

-    "process/memory_linux.cc",

-    "process/memory_mac.mm",

-    "process/memory_win.cc",

-    "process/process.h",

-    "process/process_handle_freebsd.cc",

-    "process/process_handle_linux.cc",

-    "process/process_handle_mac.cc",

-    "process/process_handle_openbsd.cc",

-    "process/process_handle_posix.cc",

-    "process/process_handle_win.cc",

-    "process/process_info.h",

-    "process/process_info_mac.cc",

-    "process/process_info_win.cc",

-    "process/process_iterator.cc",

-    "process/process_iterator.h",

-    "process/process_iterator_freebsd.cc",

-    "process/process_iterator_linux.cc",

-    "process/process_iterator_mac.cc",

-    "process/process_iterator_openbsd.cc",

-    "process/process_iterator_win.cc",

-    "process/process_linux.cc",

-    "process/process_metrics.h",

-    "process/process_metrics_freebsd.cc",

-    "process/process_metrics_ios.cc",

-    "process/process_metrics_linux.cc",

-    "process/process_metrics_mac.cc",

-    "process/process_metrics_openbsd.cc",

-    "process/process_metrics_posix.cc",

-    "process/process_metrics_win.cc",

-    "process/process_posix.cc",

-    "process/process_util.h",

-    "process/process_win.cc",

-    "profiler/scoped_profile.cc",

-    "profiler/scoped_profile.h",

-    "profiler/alternate_timer.cc",

-    "profiler/alternate_timer.h",

-    "profiler/tracked_time.cc",

-    "profiler/tracked_time.h",

-    "rand_util.cc",

-    "rand_util.h",

-    "rand_util_nacl.cc",

-    "rand_util_posix.cc",

-    "rand_util_win.cc",

-    "run_loop.cc",

-    "run_loop.h",

-    "safe_numerics.h",

-    "safe_strerror_posix.cc",

-    "safe_strerror_posix.h",

-    "scoped_native_library.cc",

-    "scoped_native_library.h",

-    "sequence_checker.h",

-    "sequence_checker_impl.cc",

-    "sequence_checker_impl.h",

-    "sequenced_task_runner.cc",

-    "sequenced_task_runner.h",

-    "sequenced_task_runner_helpers.h",

-    "sha1.h",

-    "sha1_portable.cc",

-    "sha1_win.cc",

-    "single_thread_task_runner.h",

-    "stl_util.h",

-    "strings/latin1_string_conversions.cc",

-    "strings/latin1_string_conversions.h",

-    "strings/nullable_string16.cc",

-    "strings/nullable_string16.h",

-    "strings/string16.cc",

-    "strings/string16.h",

-    "strings/string_number_conversions.cc",

-    "strings/string_split.cc",

-    "strings/string_split.h",

-    "strings/string_number_conversions.h",

-    "strings/string_piece.cc",

-    "strings/string_piece.h",

-    "strings/string_tokenizer.h",

-    "strings/string_util.cc",

-    "strings/string_util.h",

-    "strings/string_util_constants.cc",

-    "strings/string_util_posix.h",

-    "strings/string_util_win.h",

-    "strings/stringize_macros.h",

-    "strings/stringprintf.cc",

-    "strings/stringprintf.h",

-    "strings/sys_string_conversions.h",

-    "strings/sys_string_conversions_mac.mm",

-    "strings/sys_string_conversions_posix.cc",

-    "strings/sys_string_conversions_win.cc",

-    "strings/utf_offset_string_conversions.cc",

-    "strings/utf_offset_string_conversions.h",

-    "strings/utf_string_conversion_utils.cc",

-    "strings/utf_string_conversion_utils.h",

-    "strings/utf_string_conversions.cc",

-    "strings/utf_string_conversions.h",

-    "supports_user_data.cc",

-    "supports_user_data.h",

-    "sync_socket.h",

-    "sync_socket_posix.cc",

-    "sync_socket_win.cc",

-    "synchronization/cancellation_flag.cc",

-    "synchronization/cancellation_flag.h",

-    "synchronization/condition_variable.h",

-    "synchronization/condition_variable_posix.cc",

-    "synchronization/condition_variable_win.cc",

-    "synchronization/lock.cc",

-    "synchronization/lock.h",

-    "synchronization/lock_impl.h",

-    "synchronization/lock_impl_posix.cc",

-    "synchronization/lock_impl_win.cc",

-    "synchronization/spin_wait.h",

-    "synchronization/waitable_event.h",

-    "synchronization/waitable_event_posix.cc",

-    "synchronization/waitable_event_watcher.h",

-    "synchronization/waitable_event_watcher_posix.cc",

-    "synchronization/waitable_event_watcher_win.cc",

-    "synchronization/waitable_event_win.cc",

-    "system_monitor/system_monitor.cc",

-    "system_monitor/system_monitor.h",

-    "sys_byteorder.h",

-    "sys_info.cc",

-    "sys_info.h",

-    "sys_info_android.cc",

-    "sys_info_chromeos.cc",

-    "sys_info_freebsd.cc",

-    "sys_info_ios.mm",

-    "sys_info_linux.cc",

-    "sys_info_mac.cc",

-    "sys_info_openbsd.cc",

-    "sys_info_posix.cc",

-    "sys_info_win.cc",

-    "task_runner.cc",

-    "task_runner.h",

-    "task_runner_util.h",

-    "template_util.h",

-    "thread_task_runner_handle.cc",

-    "thread_task_runner_handle.h",

-    "threading/non_thread_safe.h",

-    "threading/non_thread_safe_impl.cc",

-    "threading/non_thread_safe_impl.h",

-    "threading/platform_thread.h",

-    "threading/platform_thread_android.cc",

-    "threading/platform_thread_linux.cc",

-    "threading/platform_thread_mac.mm",

-    "threading/platform_thread_posix.cc",

-    "threading/platform_thread_win.cc",

-    "threading/post_task_and_reply_impl.cc",

-    "threading/post_task_and_reply_impl.h",

-    "threading/sequenced_worker_pool.cc",

-    "threading/sequenced_worker_pool.h",

-    "threading/simple_thread.cc",

-    "threading/simple_thread.h",

-    "threading/thread.cc",

-    "threading/thread.h",

-    "threading/thread_checker.h",

-    "threading/thread_checker_impl.cc",

-    "threading/thread_checker_impl.h",

-    "threading/thread_collision_warner.cc",

-    "threading/thread_collision_warner.h",

-    "threading/thread_id_name_manager.cc",

-    "threading/thread_id_name_manager.h",

-    "threading/thread_local.h",

-    "threading/thread_local_posix.cc",

-    "threading/thread_local_storage.h",

-    "threading/thread_local_storage_posix.cc",

-    "threading/thread_local_storage_win.cc",

-    "threading/thread_local_win.cc",

-    "threading/thread_restrictions.h",

-    "threading/thread_restrictions.cc",

-    "threading/watchdog.cc",

-    "threading/watchdog.h",

-    "threading/worker_pool.h",

-    "threading/worker_pool.cc",

-    "threading/worker_pool_posix.cc",

-    "threading/worker_pool_posix.h",

-    "threading/worker_pool_win.cc",

-    "time/clock.cc",

-    "time/clock.h",

-    "time/default_clock.cc",

-    "time/default_clock.h",

-    "time/default_tick_clock.cc",

-    "time/default_tick_clock.h",

-    "time/tick_clock.cc",

-    "time/tick_clock.h",

-    "time/time.cc",

-    "time/time.h",

-    "time/time_mac.cc",

-    "time/time_posix.cc",

-    "time/time_win.cc",

-    "timer/hi_res_timer_manager_posix.cc",

-    "timer/hi_res_timer_manager_win.cc",

-    "timer/hi_res_timer_manager.h",

-    "timer/timer.cc",

-    "timer/timer.h",

-    "tracked_objects.cc",

-    "tracked_objects.h",

-    "tracking_info.cc",

-    "tracking_info.h",

-    "tuple.h",

-    "values.cc",

-    "values.h",

-    "value_conversions.cc",

-    "value_conversions.h",

-    "version.cc",

-    "version.h",

-    "vlog.cc",

-    "vlog.h",

-    "win/enum_variant.cc",

-    "win/enum_variant.h",

-    "win/event_trace_consumer.h",

-    "win/event_trace_controller.cc",

-    "win/event_trace_controller.h",

-    "win/event_trace_provider.cc",

-    "win/event_trace_provider.h",

-    "win/i18n.cc",

-    "win/i18n.h",

-    "win/iat_patch_function.cc",

-    "win/iat_patch_function.h",

-    "win/iunknown_impl.cc",

-    "win/iunknown_impl.h",

-    "win/message_window.cc",

-    "win/message_window.h",

-    "win/metro.cc",

-    "win/metro.h",

-    "win/object_watcher.cc",

-    "win/object_watcher.h",

-    "win/registry.cc",

-    "win/registry.h",

-    "win/resource_util.cc",

-    "win/resource_util.h",

-    "win/sampling_profiler.cc",

-    "win/sampling_profiler.h",

-    "win/scoped_bstr.cc",

-    "win/scoped_bstr.h",

-    "win/scoped_co_mem.h",

-    "win/scoped_com_initializer.h",

-    "win/scoped_comptr.h",

-    "win/scoped_gdi_object.h",

-    "win/scoped_handle.cc",

-    "win/scoped_handle.h",

-    "win/scoped_hdc.h",

-    "win/scoped_hglobal.h",

-    "win/scoped_process_information.cc",

-    "win/scoped_process_information.h",

-    "win/scoped_propvariant.h",

-    "win/scoped_select_object.h",

-    "win/scoped_variant.cc",

-    "win/scoped_variant.h",

-    "win/shortcut.cc",

-    "win/shortcut.h",

-    "win/startup_information.cc",

-    "win/startup_information.h",

-    "win/text_services_message_filter.cc",

-    "win/text_services_message_filter.h",

-    "win/win_util.cc",

-    "win/win_util.h",

-    "win/windows_version.cc",

-    "win/windows_version.h",

-    "win/wrapped_window_proc.cc",

-    "win/wrapped_window_proc.h",

-  ]

-

-  # TODO(brettw) I don't understand the conditions this file is used.

-  sources -= "files/file_path_watcher_stub.cc"

-

-  sources -= [

-    # TODO(brettw) do these properly.

-    "message_loop/message_pump_aurax11.cc",

-    "message_loop/message_pump_aurax11.h",

-    "message_loop/message_pump_glib.cc",

-    "message_loop/message_pump_glib.h",

-    "message_loop/message_pump_gtk.cc",

-    "message_loop/message_pump_gtk.h",

-    "message_loop/message_pump_ozone.cc",

-    "message_loop/message_pump_ozone.h",

-

-    "process/process_handle_freebsd.cc",

-    "process/process_handle_openbsd.cc",

-    "process/process_iterator_freebsd.cc",

-    "process/process_iterator_openbsd.cc",

-    "process/process_metrics_freebsd.cc",

-    "process/process_metrics_openbsd.cc",

-    "sys_info_freebsd.cc",

-    "sys_info_openbsd.cc",

-  ]

-

-  if (!is_chromeos) {

-    sources -= [

-      "sys_info_chromeos.cc",

-    ]

-  }

-

-  # Remove nacl stuff.

-  if (!is_nacl) {

-    sources -= [

-      "os_compat_nacl.cc",

-      "os_compat_nacl.h",

-      "rand_util_nacl.cc",

-      "third_party/nspr/prcpucfg_nacl.h",

-      "memory/shared_memory_nacl.cc",

-    ]

-  }

-

-  # Windows.

-  if (is_win && !is_nacl) {

-    sources -= [

-      "strings/string16.cc",

-      # Not using sha1_win.cc because it may have caused a

-      # regression to page cycler moz.

-      "sha1_win.cc",

-    ]

-

-    if (is_component_build) {

-      sources -= "debug/debug_on_start_win.cc"

-    }

-  }

-

-  # Mac.

-  if (is_mac) {

-    sources -= [

-      "base_paths_posix.cc",

-      "native_library_posix.cc",

-      "strings/sys_string_conversions_posix.cc",

-    ]

-  } else {

-    sources -= "files/file_path_watcher_kqueue.cc"

-  }

-

-  # Non-Mac Unix stuff.

-  if (is_mac) { #!is_posix || is_mac) {

-    sources -= [

-      "nix/mime_util_xdg.cc",

-      "nix/mime_util_xdg.h",

-      "nix/xdg_util.cc",

-      "nix/xdg_util.h",

-      "third_party/xdg_mime/xdgmime.h",

-    ]

-  }

-

-  defines = [

-    "BASE_IMPLEMENTATION",

-  ]

-

-  deps = [

-    ":base_static",

-    "//base/allocator:allocator_extension_thunks",

-    "//third_party/modp_b64",

-    "//base/third_party/dynamic_annotations",

-  ]

-

-  if (!is_win) {

-    deps += "//third_party/libevent"

-  }

-  if (is_mac) {

-    deps += "//third_party/mach_override"

-  }

-}

-

-# This is the subset of files from base that should not be used with a dynamic

-# library. Note that this library cannot depend on base because base depends on

-# base_static.

-static_library("base_static") {

-  sources = [

-    "base_switches.cc",

-    "base_switches.h",

-    "win/pe_image.cc",

-    "win/pe_image.h",

-  ]

-}

-

-component("base_i18n") {

-  sources = [

-    "i18n/base_i18n_export.h",

-    "i18n/bidi_line_iterator.cc",

-    "i18n/bidi_line_iterator.h",

-    "i18n/break_iterator.cc",

-    "i18n/break_iterator.h",

-    "i18n/char_iterator.cc",

-    "i18n/char_iterator.h",

-    "i18n/case_conversion.cc",

-    "i18n/case_conversion.h",

-    "i18n/file_util_icu.cc",

-    "i18n/file_util_icu.h",

-    "i18n/icu_encoding_detection.cc",

-    "i18n/icu_encoding_detection.h",

-    "i18n/icu_string_conversions.cc",

-    "i18n/icu_string_conversions.h",

-    "i18n/icu_util.cc",

-    "i18n/icu_util.h",

-    "i18n/number_formatting.cc",

-    "i18n/number_formatting.h",

-    "i18n/rtl.cc",

-    "i18n/rtl.h",

-    "i18n/string_compare.cc",

-    "i18n/string_compare.h",

-    "i18n/string_search.cc",

-    "i18n/string_search.h",

-    "i18n/time_formatting.cc",

-    "i18n/time_formatting.h",

-  ]

-  deps = [

-    ":base",

-    "//base/third_party/dynamic_annotations",

-    "//third_party/icu:icui18n",

-    "//third_party/icu:icuuc",

-  ]

-  defines = [

-    "BASE_I18N_IMPLEMENTATION",

-  ]

-  #'conditions': [

-  #  ['toolkit_uses_gtk==1', {

-  #    'deps': [

-  #      # i18n/rtl.cc uses gtk

-  #      '../build/linux/system.gyp:gtk',

-  #    ],

-  #  }],

-  #  ['OS == "win"', {

-  #    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.

-  #    'msvs_disabled_warnings': [

-  #      4267,

-  #    ],

-  #  }],

-  #],

-  #'export_dependent_settings': [

-  #  'base',

-  #],

-  #'variables': {

-  #  'enable_wexit_time_destructors': 1,

-  #  'optimize': 'max',

-  #},

-}

-

-static_library("test_support_base") {

-  sources = [

-    "perftimer.cc",

-    "test/expectations/expectation.cc",

-    "test/expectations/expectation.h",

-    "test/expectations/parser.cc",

-    "test/expectations/parser.h",

-    "test/mock_chrome_application_mac.h",

-    "test/mock_chrome_application_mac.mm",

-    "test/mock_devices_changed_observer.cc",

-    "test/mock_devices_changed_observer.h",

-    "test/mock_time_provider.cc",

-    "test/mock_time_provider.h",

-    "test/multiprocess_test.cc",

-    "test/multiprocess_test.h",

-    "test/multiprocess_test_android.cc",

-    "test/null_task_runner.cc",

-    "test/null_task_runner.h",

-    "test/perf_test_suite.cc",

-    "test/perf_test_suite.h",

-    "test/scoped_locale.cc",

-    "test/scoped_locale.h",

-    "test/scoped_path_override.cc",

-    "test/scoped_path_override.h",

-    "test/sequenced_task_runner_test_template.cc",

-    "test/sequenced_task_runner_test_template.h",

-    "test/sequenced_worker_pool_owner.cc",

-    "test/sequenced_worker_pool_owner.h",

-    "test/simple_test_clock.cc",

-    "test/simple_test_clock.h",

-    "test/simple_test_tick_clock.cc",

-    "test/simple_test_tick_clock.h",

-    "test/task_runner_test_template.cc",

-    "test/task_runner_test_template.h",

-    "test/test_file_util.h",

-    "test/test_file_util_linux.cc",

-    "test/test_file_util_mac.cc",

-    "test/test_file_util_posix.cc",

-    "test/test_file_util_win.cc",

-    "test/test_listener_ios.h",

-    "test/test_listener_ios.mm",

-    "test/test_pending_task.cc",

-    "test/test_pending_task.h",

-    "test/test_process_killer_win.cc",

-    "test/test_process_killer_win.h",

-    "test/test_reg_util_win.cc",

-    "test/test_reg_util_win.h",

-    "test/test_shortcut_win.cc",

-    "test/test_shortcut_win.h",

-    "test/test_simple_task_runner.cc",

-    "test/test_simple_task_runner.h",

-    "test/test_suite.cc",

-    "test/test_suite.h",

-    "test/test_support_android.cc",

-    "test/test_support_android.h",

-    "test/test_support_ios.h",

-    "test/test_support_ios.mm",

-    "test/test_switches.cc",

-    "test/test_switches.h",

-    "test/test_timeouts.cc",

-    "test/test_timeouts.h",

-    "test/thread_test_helper.cc",

-    "test/thread_test_helper.h",

-    "test/trace_event_analyzer.cc",

-    "test/trace_event_analyzer.h",

-    "test/values_test_util.cc",

-    "test/values_test_util.h",

-  ]

-  deps = [

-    ":base",

-    ":base_static",

-    ":base_i18n",

-    "//testing:gmock",

-    "//testing:gtest",

-  ]

-

-  if (!is_posix) {

-    sources -= [

-      "test/scoped_locale.cc",

-      "test/scoped_locale.h",

-    ]

-  }

-  if (is_ios) {

-    # Pull in specific Mac files for iOS (which have been filtered out

-    # by file name rules).

-    {  # Temporarily override the assignment filter in a new scope.

-      set_sources_assignment_filter([])

-      sources += "test/test_file_util_mac.cc"

-    }

-  }

-  #if (!is_bsd) {

-  #  sources -= "test/test_file_util_linux.cc"

-  #}

-  #if (use_gtk) {

-  #  deps += "/build/linux/system:gtk"

-  #}

-  #export_dependent_settings [

-  #  'base',

-  #]

-}

-

-config("perf_test_config") {

-  defines = [ "PERF_TEST" ]

-}

-

-static_library("test_support_perf") {

-  sources = [

-    "perftimer.cc",

-    "test/run_all_perftests.cc",

-  ]

-  deps = [

-    ":base",

-    "//testing:gtest",

-  ]

-

-  direct_dependent_configs = [ ":perf_test_config" ]

-

-  #if (toolkit_uses_gtk) {

-  #  deps += "/build/linux/system:gtk",

-  #}

-}

-

-static_library("run_all_unittests") {

-  sources = [

-    "test/run_all_unittests.cc",

-  ]

-  deps = [

-    ":test_support_base",

-  ]

-}

+# 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.
+
+config("base_libs") {
+  if (!is_win) {
+    ldflags = [ "-ldl" ]
+  }
+}
+
+component("base") {
+  sources = [
+    "../build/build_config.h",
+    "third_party/dmg_fp/dmg_fp.h",
+    "third_party/dmg_fp/g_fmt.cc",
+    "third_party/dmg_fp/dtoa_wrapper.cc",
+    "third_party/icu/icu_utf.cc",
+    "third_party/icu/icu_utf.h",
+    "allocator/allocator_extension.cc",
+    "allocator/allocator_extension.h",
+    "allocator/type_profiler_control.cc",
+    "allocator/type_profiler_control.h",
+    "android/activity_status.cc",
+    "android/activity_status.h",
+    "android/base_jni_registrar.cc",
+    "android/base_jni_registrar.h",
+    "android/build_info.cc",
+    "android/build_info.h",
+    "android/cpu_features.cc",
+    "android/fifo_utils.cc",
+    "android/fifo_utils.h",
+    "android/important_file_writer_android.cc",
+    "android/important_file_writer_android.h",
+    "android/scoped_java_ref.cc",
+    "android/scoped_java_ref.h",
+    "android/jni_android.cc",
+    "android/jni_android.h",
+    "android/jni_array.cc",
+    "android/jni_array.h",
+    "android/jni_helper.cc",
+    "android/jni_helper.h",
+    "android/jni_registrar.cc",
+    "android/jni_registrar.h",
+    "android/jni_string.cc",
+    "android/jni_string.h",
+    "android/memory_pressure_listener_android.cc",
+    "android/memory_pressure_listener_android.h",
+    "android/path_service_android.cc",
+    "android/path_service_android.h",
+    "android/path_utils.cc",
+    "android/path_utils.h",
+    "android/sys_utils.cc",
+    "android/sys_utils.h",
+    "android/thread_utils.h",
+    "at_exit.cc",
+    "at_exit.h",
+    "atomic_ref_count.h",
+    "atomic_sequence_num.h",
+    "atomicops.h",
+    "atomicops_internals_gcc.h",
+    "atomicops_internals_mac.h",
+    "atomicops_internals_tsan.h",
+    "atomicops_internals_x86_gcc.cc",
+    "atomicops_internals_x86_gcc.h",
+    "atomicops_internals_x86_msvc.h",
+    "base_export.h",
+    "base_paths.cc",
+    "base_paths.h",
+    "base_paths_android.cc",
+    "base_paths_android.h",
+    "base_paths_mac.h",
+    "base_paths_mac.mm",
+    "base_paths_posix.cc",
+    "base_paths_posix.h",
+    "base_paths_win.cc",
+    "base_paths_win.h",
+    "base_switches.h",
+    "base64.cc",
+    "base64.h",
+    "basictypes.h",
+    "bind.h",
+    "bind_helpers.cc",
+    "bind_helpers.h",
+    "bind_internal.h",
+    "bind_internal_win.h",
+    "bits.h",
+    "build_time.cc",
+    "build_time.h",
+    "callback.h",
+    "callback_helpers.h",
+    "callback_internal.cc",
+    "callback_internal.h",
+    "cancelable_callback.h",
+    "chromeos/chromeos_version.cc",
+    "chromeos/chromeos_version.h",
+    "command_line.cc",
+    "command_line.h",
+    "compiler_specific.h",
+    "containers/hash_tables.h",
+    "containers/linked_list.h",
+    "containers/mru_cache.h",
+    "containers/small_map.h",
+    "containers/stack_container.h",
+    "cpu.cc",
+    "cpu.h",
+    "critical_closure.h",
+    "critical_closure_ios.mm",
+    "debug/alias.cc",
+    "debug/alias.h",
+    "debug/crash_logging.cc",
+    "debug/crash_logging.h",
+    "debug/debug_on_start_win.cc",
+    "debug/debug_on_start_win.h",
+    "debug/debugger.cc",
+    "debug/debugger.h",
+    "debug/debugger_posix.cc",
+    "debug/debugger_win.cc",
+    # This file depends on files from the "allocator" target,
+    # but this target does not depend on "allocator" (see
+    # allocator.gyp for details).
+    "debug/leak_annotations.h",
+    "debug/leak_tracker.h",
+    "debug/proc_maps_linux.cc",
+    "debug/proc_maps_linux.h",
+    "debug/profiler.cc",
+    "debug/profiler.h",
+    "debug/stack_trace.cc",
+    "debug/stack_trace.h",
+    "debug/stack_trace_android.cc",
+    "debug/stack_trace_ios.mm",
+    "debug/stack_trace_posix.cc",
+    "debug/stack_trace_win.cc",
+    "debug/trace_event.h",
+    "debug/trace_event_android.cc",
+    "debug/trace_event_impl.cc",
+    "debug/trace_event_impl.h",
+    "debug/trace_event_impl_constants.cc",
+    "debug/trace_event_memory.cc",
+    "debug/trace_event_memory.h",
+    "debug/trace_event_win.cc",
+    "deferred_sequenced_task_runner.cc",
+    "deferred_sequenced_task_runner.h",
+    "environment.cc",
+    "environment.h",
+    "file_descriptor_posix.h",
+    "file_util.cc",
+    "file_util.h",
+    "file_util_android.cc",
+    "file_util_linux.cc",
+    "file_util_mac.mm",
+    "file_util_posix.cc",
+    "file_util_win.cc",
+    "file_version_info.h",
+    "file_version_info_mac.h",
+    "file_version_info_mac.mm",
+    "file_version_info_win.cc",
+    "file_version_info_win.h",
+    "files/dir_reader_fallback.h",
+    "files/dir_reader_linux.h",
+    "files/dir_reader_posix.h",
+    "files/file_enumerator.cc",
+    "files/file_enumerator.h",
+    "files/file_enumerator_posix.cc",
+    "files/file_enumerator_win.cc",
+    "files/file_path.cc",
+    "files/file_path.h",
+    "files/file_path_constants.cc",
+    "files/file_path_watcher.cc",
+    "files/file_path_watcher.h",
+    "files/file_path_watcher_kqueue.cc",
+    "files/file_path_watcher_linux.cc",
+    "files/file_path_watcher_stub.cc",
+    "files/file_path_watcher_win.cc",
+    "files/file_util_proxy.cc",
+    "files/file_util_proxy.h",
+    "files/important_file_writer.h",
+    "files/important_file_writer.cc",
+    "files/memory_mapped_file.cc",
+    "files/memory_mapped_file.h",
+    "files/memory_mapped_file_posix.cc",
+    "files/memory_mapped_file_win.cc",
+    "files/scoped_temp_dir.cc",
+    "files/scoped_temp_dir.h",
+    "float_util.h",
+    "format_macros.h",
+    "gtest_prod_util.h",
+    "guid.cc",
+    "guid.h",
+    "guid_posix.cc",
+    "guid_win.cc",
+    "hash.cc",
+    "hash.h",
+    "id_map.h",
+    "ini_parser.cc",
+    "ini_parser.h",
+    "ios/device_util.h",
+    "ios/device_util.mm",
+    "ios/ios_util.h",
+    "ios/ios_util.mm",
+    "ios/scoped_critical_action.h",
+    "ios/scoped_critical_action.mm",
+    "json/json_file_value_serializer.cc",
+    "json/json_file_value_serializer.h",
+    "json/json_parser.cc",
+    "json/json_parser.h",
+    "json/json_reader.cc",
+    "json/json_reader.h",
+    "json/json_string_value_serializer.cc",
+    "json/json_string_value_serializer.h",
+    "json/json_value_converter.h",
+    "json/json_writer.cc",
+    "json/json_writer.h",
+    "json/string_escape.cc",
+    "json/string_escape.h",
+    "lazy_instance.cc",
+    "lazy_instance.h",
+    "location.cc",
+    "location.h",
+    "logging.cc",
+    "logging.h",
+    "logging_win.cc",
+    "logging_win.h",
+    "mac/authorization_util.h",
+    "mac/authorization_util.mm",
+    "mac/bind_objc_block.h",
+    "mac/bundle_locations.h",
+    "mac/bundle_locations.mm",
+    "mac/cocoa_protocols.h",
+    "mac/foundation_util.h",
+    "mac/foundation_util.mm",
+    "mac/launch_services_util.cc",
+    "mac/launch_services_util.h",
+    "mac/launchd.cc",
+    "mac/launchd.h",
+    "mac/libdispatch_task_runner.cc",
+    "mac/libdispatch_task_runner.h",
+    "mac/mac_logging.h",
+    "mac/mac_logging.cc",
+    "mac/mac_util.h",
+    "mac/mac_util.mm",
+    "mac/objc_property_releaser.h",
+    "mac/objc_property_releaser.mm",
+    "mac/os_crash_dumps.cc",
+    "mac/os_crash_dumps.h",
+    "mac/scoped_aedesc.h",
+    "mac/scoped_authorizationref.h",
+    "mac/scoped_block.h",
+    "mac/scoped_cftyperef.h",
+    "mac/scoped_ioobject.h",
+    "mac/scoped_ioplugininterface.h",
+    "mac/scoped_launch_data.h",
+    "mac/scoped_mach_port.cc",
+    "mac/scoped_mach_port.h",
+    "mac/scoped_nsautorelease_pool.h",
+    "mac/scoped_nsautorelease_pool.mm",
+    "mac/scoped_nsexception_enabler.h",
+    "mac/scoped_nsexception_enabler.mm",
+    "mac/scoped_nsobject.h",
+    "mac/scoped_sending_event.h",
+    "mac/scoped_sending_event.mm",
+    "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_mac.cc",
+    "memory/linked_ptr.h",
+    "memory/manual_constructor.h",
+    "memory/memory_pressure_listener.cc",
+    "memory/memory_pressure_listener.h",
+    "memory/raw_scoped_refptr_mismatch_checker.h",
+    "memory/ref_counted.cc",
+    "memory/ref_counted.h",
+    "memory/ref_counted_delete_on_message_loop.h",
+    "memory/ref_counted_memory.cc",
+    "memory/ref_counted_memory.h",
+    "memory/scoped_handle.h",
+    "memory/scoped_open_process.h",
+    "memory/scoped_policy.h",
+    "memory/scoped_ptr.h",
+    "memory/scoped_vector.h",
+    "memory/shared_memory.h",
+    "memory/shared_memory_android.cc",
+    "memory/shared_memory_nacl.cc",
+    "memory/shared_memory_posix.cc",
+    "memory/shared_memory_win.cc",
+    "memory/singleton.cc",
+    "memory/singleton.h",
+    "memory/weak_ptr.cc",
+    "memory/weak_ptr.h",
+    "message_loop/incoming_task_queue.cc",
+    "message_loop/incoming_task_queue.h",
+    "message_loop/message_loop.cc",
+    "message_loop/message_loop.h",
+    "message_loop/message_loop_proxy.cc",
+    "message_loop/message_loop_proxy.h",
+    "message_loop/message_loop_proxy_impl.cc",
+    "message_loop/message_loop_proxy_impl.h",
+    "message_loop/message_pump.cc",
+    "message_loop/message_pump.h",
+    "message_loop/message_pump_android.cc",
+    "message_loop/message_pump_android.h",
+    "message_loop/message_pump_aurax11.cc",
+    "message_loop/message_pump_aurax11.h",
+    "message_loop/message_pump_default.cc",
+    "message_loop/message_pump_default.h",
+    "message_loop/message_pump_glib.cc",
+    "message_loop/message_pump_glib.h",
+    "message_loop/message_pump_gtk.cc",
+    "message_loop/message_pump_gtk.h",
+    "message_loop/message_pump_io_ios.cc",
+    "message_loop/message_pump_io_ios.h",
+    "message_loop/message_pump_libevent.cc",
+    "message_loop/message_pump_libevent.h",
+    "message_loop/message_pump_mac.h",
+    "message_loop/message_pump_mac.mm",
+    "message_loop/message_pump_observer.h",
+    "message_loop/message_pump_ozone.cc",
+    "message_loop/message_pump_ozone.h",
+    "message_loop/message_pump_win.cc",
+    "message_loop/message_pump_win.h",
+    "metrics/field_trial.cc",
+    "metrics/field_trial.h",
+    "metrics/sample_map.cc",
+    "metrics/sample_map.h",
+    "metrics/sample_vector.cc",
+    "metrics/sample_vector.h",
+    "metrics/bucket_ranges.cc",
+    "metrics/bucket_ranges.h",
+    "metrics/histogram.cc",
+    "metrics/histogram.h",
+    "metrics/histogram_base.cc",
+    "metrics/histogram_base.h",
+    "metrics/histogram_flattener.h",
+    "metrics/histogram_samples.cc",
+    "metrics/histogram_samples.h",
+    "metrics/histogram_snapshot_manager.cc",
+    "metrics/histogram_snapshot_manager.h",
+    "metrics/sparse_histogram.cc",
+    "metrics/sparse_histogram.h",
+    "metrics/statistics_recorder.cc",
+    "metrics/statistics_recorder.h",
+    "metrics/stats_counters.cc",
+    "metrics/stats_counters.h",
+    "metrics/stats_table.cc",
+    "metrics/stats_table.h",
+    "move.h",
+    "native_library.h",
+    "native_library_mac.mm",
+    "native_library_posix.cc",
+    "native_library_win.cc",
+    "nix/mime_util_xdg.cc",
+    "nix/mime_util_xdg.h",
+    "nix/xdg_util.cc",
+    "nix/xdg_util.h",
+    "observer_list.h",
+    "observer_list_threadsafe.h",
+    "os_compat_android.cc",
+    "os_compat_android.h",
+    "os_compat_nacl.cc",
+    "os_compat_nacl.h",
+    "path_service.cc",
+    "path_service.h",
+    "pending_task.cc",
+    "pending_task.h",
+    "pickle.cc",
+    "pickle.h",
+    "platform_file.cc",
+    "platform_file.h",
+    "platform_file_posix.cc",
+    "platform_file_win.cc",
+    "port.h",
+    "posix/eintr_wrapper.h",
+    "posix/file_descriptor_shuffle.cc",
+    "posix/file_descriptor_shuffle.y",
+    "posix/global_descriptors.cc",
+    "posix/global_descriptors.h",
+    "posix/unix_domain_socket_linux.cc",
+    "posix/unix_domain_socket_linux.h",
+    "power_monitor/power_monitor.cc",
+    "power_monitor/power_monitor.h",
+    "power_monitor/power_monitor_device_source.cc",
+    "power_monitor/power_monitor_device_source.h",
+    "power_monitor/power_monitor_device_source_android.cc",
+    "power_monitor/power_monitor_device_source_android.h",
+    "power_monitor/power_monitor_device_source_ios.mm",
+    "power_monitor/power_monitor_device_source_mac.mm",
+    "power_monitor/power_monitor_device_source_posix.cc",
+    "power_monitor/power_monitor_device_source_win.cc",
+    "power_monitor/power_monitor_source.cc",
+    "power_monitor/power_monitor_source.h",
+    "power_monitor/power_observer.h",
+    "process/internal_linux.cc",
+    "process/internal_linux.h",
+    "process/kill.cc",
+    "process/kill.h",
+    "process/kill_mac.cc",
+    "process/kill_posix.cc",
+    "process/kill_win.cc",
+    "process/launch.h",
+    "process/launch_ios.cc",
+    "process/launch_mac.cc",
+    "process/launch_posix.cc",
+    "process/launch_win.cc",
+    "process/memory.h",
+    "process/memory_linux.cc",
+    "process/memory_mac.mm",
+    "process/memory_win.cc",
+    "process/process.h",
+    "process/process_handle_freebsd.cc",
+    "process/process_handle_linux.cc",
+    "process/process_handle_mac.cc",
+    "process/process_handle_openbsd.cc",
+    "process/process_handle_posix.cc",
+    "process/process_handle_win.cc",
+    "process/process_info.h",
+    "process/process_info_mac.cc",
+    "process/process_info_win.cc",
+    "process/process_iterator.cc",
+    "process/process_iterator.h",
+    "process/process_iterator_freebsd.cc",
+    "process/process_iterator_linux.cc",
+    "process/process_iterator_mac.cc",
+    "process/process_iterator_openbsd.cc",
+    "process/process_iterator_win.cc",
+    "process/process_linux.cc",
+    "process/process_metrics.h",
+    "process/process_metrics_freebsd.cc",
+    "process/process_metrics_ios.cc",
+    "process/process_metrics_linux.cc",
+    "process/process_metrics_mac.cc",
+    "process/process_metrics_openbsd.cc",
+    "process/process_metrics_posix.cc",
+    "process/process_metrics_win.cc",
+    "process/process_posix.cc",
+    "process/process_util.h",
+    "process/process_win.cc",
+    "profiler/scoped_profile.cc",
+    "profiler/scoped_profile.h",
+    "profiler/alternate_timer.cc",
+    "profiler/alternate_timer.h",
+    "profiler/tracked_time.cc",
+    "profiler/tracked_time.h",
+    "rand_util.cc",
+    "rand_util.h",
+    "rand_util_nacl.cc",
+    "rand_util_posix.cc",
+    "rand_util_win.cc",
+    "run_loop.cc",
+    "run_loop.h",
+    "safe_numerics.h",
+    "safe_strerror_posix.cc",
+    "safe_strerror_posix.h",
+    "scoped_native_library.cc",
+    "scoped_native_library.h",
+    "sequence_checker.h",
+    "sequence_checker_impl.cc",
+    "sequence_checker_impl.h",
+    "sequenced_task_runner.cc",
+    "sequenced_task_runner.h",
+    "sequenced_task_runner_helpers.h",
+    "sha1.h",
+    "sha1_portable.cc",
+    "sha1_win.cc",
+    "single_thread_task_runner.h",
+    "stl_util.h",
+    "strings/latin1_string_conversions.cc",
+    "strings/latin1_string_conversions.h",
+    "strings/nullable_string16.cc",
+    "strings/nullable_string16.h",
+    "strings/string16.cc",
+    "strings/string16.h",
+    "strings/string_number_conversions.cc",
+    "strings/string_split.cc",
+    "strings/string_split.h",
+    "strings/string_number_conversions.h",
+    "strings/string_piece.cc",
+    "strings/string_piece.h",
+    "strings/string_tokenizer.h",
+    "strings/string_util.cc",
+    "strings/string_util.h",
+    "strings/string_util_constants.cc",
+    "strings/string_util_posix.h",
+    "strings/string_util_win.h",
+    "strings/stringize_macros.h",
+    "strings/stringprintf.cc",
+    "strings/stringprintf.h",
+    "strings/sys_string_conversions.h",
+    "strings/sys_string_conversions_mac.mm",
+    "strings/sys_string_conversions_posix.cc",
+    "strings/sys_string_conversions_win.cc",
+    "strings/utf_offset_string_conversions.cc",
+    "strings/utf_offset_string_conversions.h",
+    "strings/utf_string_conversion_utils.cc",
+    "strings/utf_string_conversion_utils.h",
+    "strings/utf_string_conversions.cc",
+    "strings/utf_string_conversions.h",
+    "supports_user_data.cc",
+    "supports_user_data.h",
+    "sync_socket.h",
+    "sync_socket_posix.cc",
+    "sync_socket_win.cc",
+    "synchronization/cancellation_flag.cc",
+    "synchronization/cancellation_flag.h",
+    "synchronization/condition_variable.h",
+    "synchronization/condition_variable_posix.cc",
+    "synchronization/condition_variable_win.cc",
+    "synchronization/lock.cc",
+    "synchronization/lock.h",
+    "synchronization/lock_impl.h",
+    "synchronization/lock_impl_posix.cc",
+    "synchronization/lock_impl_win.cc",
+    "synchronization/spin_wait.h",
+    "synchronization/waitable_event.h",
+    "synchronization/waitable_event_posix.cc",
+    "synchronization/waitable_event_watcher.h",
+    "synchronization/waitable_event_watcher_posix.cc",
+    "synchronization/waitable_event_watcher_win.cc",
+    "synchronization/waitable_event_win.cc",
+    "system_monitor/system_monitor.cc",
+    "system_monitor/system_monitor.h",
+    "sys_byteorder.h",
+    "sys_info.cc",
+    "sys_info.h",
+    "sys_info_android.cc",
+    "sys_info_chromeos.cc",
+    "sys_info_freebsd.cc",
+    "sys_info_ios.mm",
+    "sys_info_linux.cc",
+    "sys_info_mac.cc",
+    "sys_info_openbsd.cc",
+    "sys_info_posix.cc",
+    "sys_info_win.cc",
+    "task_runner.cc",
+    "task_runner.h",
+    "task_runner_util.h",
+    "template_util.h",
+    "thread_task_runner_handle.cc",
+    "thread_task_runner_handle.h",
+    "threading/non_thread_safe.h",
+    "threading/non_thread_safe_impl.cc",
+    "threading/non_thread_safe_impl.h",
+    "threading/platform_thread.h",
+    "threading/platform_thread_android.cc",
+    "threading/platform_thread_linux.cc",
+    "threading/platform_thread_mac.mm",
+    "threading/platform_thread_posix.cc",
+    "threading/platform_thread_win.cc",
+    "threading/post_task_and_reply_impl.cc",
+    "threading/post_task_and_reply_impl.h",
+    "threading/sequenced_worker_pool.cc",
+    "threading/sequenced_worker_pool.h",
+    "threading/simple_thread.cc",
+    "threading/simple_thread.h",
+    "threading/thread.cc",
+    "threading/thread.h",
+    "threading/thread_checker.h",
+    "threading/thread_checker_impl.cc",
+    "threading/thread_checker_impl.h",
+    "threading/thread_collision_warner.cc",
+    "threading/thread_collision_warner.h",
+    "threading/thread_id_name_manager.cc",
+    "threading/thread_id_name_manager.h",
+    "threading/thread_local.h",
+    "threading/thread_local_posix.cc",
+    "threading/thread_local_storage.h",
+    "threading/thread_local_storage_posix.cc",
+    "threading/thread_local_storage_win.cc",
+    "threading/thread_local_win.cc",
+    "threading/thread_restrictions.h",
+    "threading/thread_restrictions.cc",
+    "threading/watchdog.cc",
+    "threading/watchdog.h",
+    "threading/worker_pool.h",
+    "threading/worker_pool.cc",
+    "threading/worker_pool_posix.cc",
+    "threading/worker_pool_posix.h",
+    "threading/worker_pool_win.cc",
+    "time/clock.cc",
+    "time/clock.h",
+    "time/default_clock.cc",
+    "time/default_clock.h",
+    "time/default_tick_clock.cc",
+    "time/default_tick_clock.h",
+    "time/tick_clock.cc",
+    "time/tick_clock.h",
+    "time/time.cc",
+    "time/time.h",
+    "time/time_mac.cc",
+    "time/time_posix.cc",
+    "time/time_win.cc",
+    "timer/hi_res_timer_manager_posix.cc",
+    "timer/hi_res_timer_manager_win.cc",
+    "timer/hi_res_timer_manager.h",
+    "timer/timer.cc",
+    "timer/timer.h",
+    "tracked_objects.cc",
+    "tracked_objects.h",
+    "tracking_info.cc",
+    "tracking_info.h",
+    "tuple.h",
+    "values.cc",
+    "values.h",
+    "value_conversions.cc",
+    "value_conversions.h",
+    "version.cc",
+    "version.h",
+    "vlog.cc",
+    "vlog.h",
+    "win/enum_variant.cc",
+    "win/enum_variant.h",
+    "win/event_trace_consumer.h",
+    "win/event_trace_controller.cc",
+    "win/event_trace_controller.h",
+    "win/event_trace_provider.cc",
+    "win/event_trace_provider.h",
+    "win/i18n.cc",
+    "win/i18n.h",
+    "win/iat_patch_function.cc",
+    "win/iat_patch_function.h",
+    "win/iunknown_impl.cc",
+    "win/iunknown_impl.h",
+    "win/message_window.cc",
+    "win/message_window.h",
+    "win/metro.cc",
+    "win/metro.h",
+    "win/object_watcher.cc",
+    "win/object_watcher.h",
+    "win/registry.cc",
+    "win/registry.h",
+    "win/resource_util.cc",
+    "win/resource_util.h",
+    "win/sampling_profiler.cc",
+    "win/sampling_profiler.h",
+    "win/scoped_bstr.cc",
+    "win/scoped_bstr.h",
+    "win/scoped_co_mem.h",
+    "win/scoped_com_initializer.h",
+    "win/scoped_comptr.h",
+    "win/scoped_gdi_object.h",
+    "win/scoped_handle.cc",
+    "win/scoped_handle.h",
+    "win/scoped_hdc.h",
+    "win/scoped_hglobal.h",
+    "win/scoped_process_information.cc",
+    "win/scoped_process_information.h",
+    "win/scoped_propvariant.h",
+    "win/scoped_select_object.h",
+    "win/scoped_variant.cc",
+    "win/scoped_variant.h",
+    "win/shortcut.cc",
+    "win/shortcut.h",
+    "win/startup_information.cc",
+    "win/startup_information.h",
+    "win/text_services_message_filter.cc",
+    "win/text_services_message_filter.h",
+    "win/win_util.cc",
+    "win/win_util.h",
+    "win/windows_version.cc",
+    "win/windows_version.h",
+    "win/wrapped_window_proc.cc",
+    "win/wrapped_window_proc.h",
+  ]
+
+  # TODO(brettw) I don't understand the conditions this file is used.
+  sources -= "files/file_path_watcher_stub.cc"
+
+  sources -= [
+    # TODO(brettw) do these properly.
+    "message_loop/message_pump_aurax11.cc",
+    "message_loop/message_pump_aurax11.h",
+    "message_loop/message_pump_ozone.cc",
+    "message_loop/message_pump_ozone.h",
+
+    "process/process_handle_freebsd.cc",
+    "process/process_handle_openbsd.cc",
+    "process/process_iterator_freebsd.cc",
+    "process/process_iterator_openbsd.cc",
+    "process/process_metrics_freebsd.cc",
+    "process/process_metrics_openbsd.cc",
+    "sys_info_freebsd.cc",
+    "sys_info_openbsd.cc",
+  ]
+
+  defines = [
+    "BASE_IMPLEMENTATION",
+  ]
+
+  deps = [
+    ":base_static",
+    "//base/allocator:allocator_extension_thunks",
+    "//base/third_party/dynamic_annotations",
+    "//base/third_party/nspr",
+    "//third_party/modp_b64",
+  ]
+
+  # So we can append below without worrying about whether it has been
+  # previously defined or not.
+  all_dependent_configs = [ ":base_libs" ]
+  ldflags = []
+
+  if (!is_chromeos) {
+    sources -= [
+      "sys_info_chromeos.cc",
+    ]
+  }
+
+  if (is_nacl) {
+    # These things would otherwise be built on a Posix build but aren't
+    # supported on NaCl.
+    sources -= [
+      "debug/stack_trace_posix.cc",
+      "files/file_enumerator_posix.cc",
+      "file_util_posix.cc",
+      "message_loop/message_pump_libevent.cc",
+      "process/kill_posix.cc",
+      "process/launch_posix.cc",
+      "process/process_metrics_posix.cc",
+      "process/process_posix.cc",
+      "metrics/field_trial.cc",
+      "native_library_posix.cc",
+      "memory/shared_memory_posix.cc",
+      "sync_socket_posix.cc",
+      "sys_info_posix.cc",
+    ]
+  } else {
+    # Remove nacl stuff.
+    sources -= [
+      "os_compat_nacl.cc",
+      "os_compat_nacl.h",
+      "rand_util_nacl.cc",
+      "memory/shared_memory_nacl.cc",
+    ]
+  }
+
+  # Windows.
+  if (is_win) {
+    sources -= [
+      "strings/string16.cc",
+      # Not using sha1_win.cc because it may have caused a
+      # regression to page cycler moz.
+      "sha1_win.cc",
+    ]
+
+    if (is_component_build) {
+      sources -= "debug/debug_on_start_win.cc"
+    }
+  } else if (!is_nacl) {
+    # Non-Windows.
+    deps += "//third_party/libevent"
+  }
+
+  # Mac.
+  if (is_mac) {
+    sources -= [
+      "base_paths_posix.cc",
+      "native_library_posix.cc",
+      "strings/sys_string_conversions_posix.cc",
+    ]
+    deps += "//third_party/mach_override"
+  } else {
+    # Non-Mac.
+    sources -= "files/file_path_watcher_kqueue.cc"
+  }
+
+  # Linux.
+  if (is_linux) {
+    # TODO(brettw) these will need to be parameterized at some point.
+    linux_configs = [
+      "//build/config/linux:glib",
+      "//build/config/linux:gtk",
+      "//build/config/linux:x11",
+    ]
+    configs += linux_configs
+    all_dependent_configs += linux_configs
+
+    deps += [
+      "//base/third_party/symbolize",
+      "//base/third_party/xdg_mime",
+      "//base/third_party/xdg_user_dirs",
+    ]
+  } else {
+    # Non-Linux.
+    sources -= [
+      "message_loop/message_pump_glib.cc",
+      "message_loop/message_pump_glib.h",
+      "message_loop/message_pump_gtk.cc",
+      "message_loop/message_pump_gtk.h",
+    ]
+  }
+
+  # Non-Mac Unix stuff.
+  if (is_mac) { #!is_posix || is_mac) {
+    sources -= [
+      "nix/mime_util_xdg.cc",
+      "nix/mime_util_xdg.h",
+      "nix/xdg_util.cc",
+      "nix/xdg_util.h",
+      "third_party/xdg_mime/xdgmime.h",
+    ]
+  }
+}
+
+# This is the subset of files from base that should not be used with a dynamic
+# library. Note that this library cannot depend on base because base depends on
+# base_static.
+static_library("base_static") {
+  sources = [
+    "base_switches.cc",
+    "base_switches.h",
+    "win/pe_image.cc",
+    "win/pe_image.h",
+  ]
+}
+
+component("base_i18n") {
+  sources = [
+    "i18n/base_i18n_export.h",
+    "i18n/bidi_line_iterator.cc",
+    "i18n/bidi_line_iterator.h",
+    "i18n/break_iterator.cc",
+    "i18n/break_iterator.h",
+    "i18n/char_iterator.cc",
+    "i18n/char_iterator.h",
+    "i18n/case_conversion.cc",
+    "i18n/case_conversion.h",
+    "i18n/file_util_icu.cc",
+    "i18n/file_util_icu.h",
+    "i18n/icu_encoding_detection.cc",
+    "i18n/icu_encoding_detection.h",
+    "i18n/icu_string_conversions.cc",
+    "i18n/icu_string_conversions.h",
+    "i18n/icu_util.cc",
+    "i18n/icu_util.h",
+    "i18n/number_formatting.cc",
+    "i18n/number_formatting.h",
+    "i18n/rtl.cc",
+    "i18n/rtl.h",
+    "i18n/string_compare.cc",
+    "i18n/string_compare.h",
+    "i18n/string_search.cc",
+    "i18n/string_search.h",
+    "i18n/time_formatting.cc",
+    "i18n/time_formatting.h",
+  ]
+  deps = [
+    ":base",
+    "//base/third_party/dynamic_annotations",
+    "//third_party/icu:icui18n",
+    "//third_party/icu:icuuc",
+  ]
+  defines = [
+    "BASE_I18N_IMPLEMENTATION",
+  ]
+  #'conditions': [
+  #  ['toolkit_uses_gtk==1', {
+  #    'deps': [
+  #      # i18n/rtl.cc uses gtk
+  #      '../build/linux/system.gyp:gtk',
+  #    ],
+  #  }],
+  #  ['OS == "win"', {
+  #    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  #    'msvs_disabled_warnings': [
+  #      4267,
+  #    ],
+  #  }],
+  #],
+  #'export_dependent_settings': [
+  #  'base',
+  #],
+  #'variables': {
+  #  'enable_wexit_time_destructors': 1,
+  #  'optimize': 'max',
+  #},
+}
+
diff --git a/tools/gn/secondary/base/allocator/BUILD.gn b/tools/gn/secondary/base/allocator/BUILD.gn
index bbcfe65..6766911 100644
--- a/tools/gn/secondary/base/allocator/BUILD.gn
+++ b/tools/gn/secondary/base/allocator/BUILD.gn
@@ -1,6 +1,10 @@
-static_library("allocator_extension_thunks") {

-  sources = [

-    "allocator_extension_thunks.cc",

-    "allocator_extension_thunks.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.
+
+static_library("allocator_extension_thunks") {
+  sources = [
+    "allocator_extension_thunks.cc",
+    "allocator_extension_thunks.h",
+  ]
+}
diff --git a/tools/gn/secondary/base/test/BUILD.gn b/tools/gn/secondary/base/test/BUILD.gn
new file mode 100644
index 0000000..0e097ed
--- /dev/null
+++ b/tools/gn/secondary/base/test/BUILD.gn
@@ -0,0 +1,135 @@
+# 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.
+
+static_library("test_support_base") {
+  sources = [
+    # TODO(brettw) move this file to this directory.
+    "../perftimer.cc",
+    "expectations/expectation.cc",
+    "expectations/expectation.h",
+    "expectations/parser.cc",
+    "expectations/parser.h",
+    "mock_chrome_application_mac.h",
+    "mock_chrome_application_mac.mm",
+    "mock_devices_changed_observer.cc",
+    "mock_devices_changed_observer.h",
+    "mock_time_provider.cc",
+    "mock_time_provider.h",
+    "multiprocess_test.cc",
+    "multiprocess_test.h",
+    "multiprocess_test_android.cc",
+    "null_task_runner.cc",
+    "null_task_runner.h",
+    "perf_test_suite.cc",
+    "perf_test_suite.h",
+    "scoped_locale.cc",
+    "scoped_locale.h",
+    "scoped_path_override.cc",
+    "scoped_path_override.h",
+    "sequenced_task_runner_test_template.cc",
+    "sequenced_task_runner_test_template.h",
+    "sequenced_worker_pool_owner.cc",
+    "sequenced_worker_pool_owner.h",
+    "simple_test_clock.cc",
+    "simple_test_clock.h",
+    "simple_test_tick_clock.cc",
+    "simple_test_tick_clock.h",
+    "task_runner_test_template.cc",
+    "task_runner_test_template.h",
+    "test_file_util.h",
+    "test_file_util_linux.cc",
+    "test_file_util_mac.cc",
+    "test_file_util_posix.cc",
+    "test_file_util_win.cc",
+    "test_listener_ios.h",
+    "test_listener_ios.mm",
+    "test_pending_task.cc",
+    "test_pending_task.h",
+    "test_process_killer_win.cc",
+    "test_process_killer_win.h",
+    "test_reg_util_win.cc",
+    "test_reg_util_win.h",
+    "test_shortcut_win.cc",
+    "test_shortcut_win.h",
+    "test_simple_task_runner.cc",
+    "test_simple_task_runner.h",
+    "test_suite.cc",
+    "test_suite.h",
+    "test_support_android.cc",
+    "test_support_android.h",
+    "test_support_ios.h",
+    "test_support_ios.mm",
+    "test_switches.cc",
+    "test_switches.h",
+    "test_timeouts.cc",
+    "test_timeouts.h",
+    "thread_test_helper.cc",
+    "thread_test_helper.h",
+    "trace_event_analyzer.cc",
+    "trace_event_analyzer.h",
+    "values_test_util.cc",
+    "values_test_util.h",
+  ]
+  deps = [
+    "//base",
+    "//base:base_static",
+    "//base:base_i18n",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  if (!is_posix) {
+    sources -= [
+      "scoped_locale.cc",
+      "scoped_locale.h",
+    ]
+  }
+  if (is_ios) {
+    # Pull in specific Mac files for iOS (which have been filtered out
+    # by file name rules).
+    set_sources_assignment_filter([])
+    sources += "test_file_util_mac.cc"
+  }
+  #if (!is_bsd) {
+  #  sources -= "test/test_file_util_linux.cc"
+  #}
+  #if (use_gtk) {
+  #  deps += "/build/linux/system:gtk"
+  #}
+  #export_dependent_settings [
+  #  'base',
+  #]
+}
+
+config("perf_test_config") {
+  defines = [ "PERF_TEST" ]
+}
+
+static_library("test_support_perf") {
+  sources = [
+    # TODO(brettw) move this file to this directory.
+    "../perftimer.cc",
+    "run_all_perftests.cc",
+  ]
+  deps = [
+    "//base",
+    "//testing/gtest",
+  ]
+
+  direct_dependent_configs = [ ":perf_test_config" ]
+
+  #if (toolkit_uses_gtk) {
+  #  deps += "/build/linux/system:gtk",
+  #}
+}
+
+static_library("run_all_unittests") {
+  sources = [
+    "run_all_unittests.cc",
+  ]
+  deps = [
+    ":test_support_base",
+  ]
+}
+
diff --git a/tools/gn/secondary/base/third_party/dynamic_annotations/BUILD.gn b/tools/gn/secondary/base/third_party/dynamic_annotations/BUILD.gn
index e3939c3..bf050bf 100644
--- a/tools/gn/secondary/base/third_party/dynamic_annotations/BUILD.gn
+++ b/tools/gn/secondary/base/third_party/dynamic_annotations/BUILD.gn
@@ -1,7 +1,11 @@
-static_library("dynamic_annotations") {

-  sources = [

-    "dynamic_annotations.c",

-    "dynamic_annotations.h",

-    "../valgrind/valgrind.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.
+
+static_library("dynamic_annotations") {
+  sources = [
+    "dynamic_annotations.c",
+    "dynamic_annotations.h",
+    "../valgrind/valgrind.h",
+  ]
+}
diff --git a/tools/gn/secondary/base/third_party/nspr/BUILD.gn b/tools/gn/secondary/base/third_party/nspr/BUILD.gn
new file mode 100644
index 0000000..dafd9f1
--- /dev/null
+++ b/tools/gn/secondary/base/third_party/nspr/BUILD.gn
@@ -0,0 +1,19 @@
+# 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.
+
+static_library("nspr") {
+  sources = [
+    "prcpucfg.h",
+    "prcpucfg_freebsd.h",
+    "prcpucfg_linux.h",
+    "prcpucfg_mac.h",
+    "prcpucfg_nacl.h",
+    "prcpucfg_openbsd.h",
+    "prcpucfg_solaris.h",
+    "prcpucfg_win.h",
+    "prtime.cc",
+    "prtime.h",
+    "prtypes.h",
+  ]
+}
diff --git a/tools/gn/secondary/base/third_party/symbolize/BUILD.gn b/tools/gn/secondary/base/third_party/symbolize/BUILD.gn
new file mode 100644
index 0000000..c13c0d8
--- /dev/null
+++ b/tools/gn/secondary/base/third_party/symbolize/BUILD.gn
@@ -0,0 +1,19 @@
+# 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.
+
+static_library("symbolize") {
+  sources = [
+    "config.h",
+    "demangle.cc",
+    "demangle.h",
+    "glog/logging.h",
+    "glog/raw_logging.h",
+    "symbolize.cc",
+    "symbolize.h",
+    "utilities.h",
+  ]
+
+  configs -= "//build/config/compiler:chromium_code"
+  configs += "//build/config/compiler:no_chromium_code"
+}
diff --git a/tools/gn/secondary/base/third_party/xdg_mime/BUILD.gn b/tools/gn/secondary/base/third_party/xdg_mime/BUILD.gn
new file mode 100644
index 0000000..9e51bc1
--- /dev/null
+++ b/tools/gn/secondary/base/third_party/xdg_mime/BUILD.gn
@@ -0,0 +1,27 @@
+# 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.
+
+static_library("xdg_mime") {
+  sources = [
+    "xdgmime.c",
+    "xdgmime.h",
+    "xdgmimealias.c",
+    "xdgmimealias.h",
+    "xdgmimecache.c",
+    "xdgmimecache.h",
+    "xdgmimeglob.c",
+    "xdgmimeglob.h",
+    "xdgmimeicon.c",
+    "xdgmimeicon.h",
+    "xdgmimeint.c",
+    "xdgmimeint.h",
+    "xdgmimemagic.c",
+    "xdgmimemagic.h",
+    "xdgmimeparent.c",
+    "xdgmimeparent.h",
+  ]
+
+  configs -= "//build/config/compiler:chromium_code"
+  configs += "//build/config/compiler:no_chromium_code"
+}
diff --git a/tools/gn/secondary/base/third_party/xdg_user_dirs/BUILD.gn b/tools/gn/secondary/base/third_party/xdg_user_dirs/BUILD.gn
new file mode 100644
index 0000000..f2145b7
--- /dev/null
+++ b/tools/gn/secondary/base/third_party/xdg_user_dirs/BUILD.gn
@@ -0,0 +1,10 @@
+# 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.
+
+static_library("xdg_user_dirs") {
+  sources = [
+    "xdg_user_dir_lookup.cc",
+    "xdg_user_dir_lookup.h",
+  ]
+}
diff --git a/tools/gn/secondary/build/config/BUILD.gn b/tools/gn/secondary/build/config/BUILD.gn
index 94cb397..8f77785 100644
--- a/tools/gn/secondary/build/config/BUILD.gn
+++ b/tools/gn/secondary/build/config/BUILD.gn
@@ -1,48 +1,51 @@
-config("my_msvs") {

-  defines = [

-      "CHROMIUM_BUILD",

-      "TOOLKIT_VIEWS=1",

-      "USE_LIBJPEG_TURBO=1",

-      "ENABLE_ONE_CLICK_SIGNIN",

-      "ENABLE_REMOTING=1",

-      "ENABLE_WEBRTC=1",

-      "ENABLE_CONFIGURATION_POLICY",

-      "ENABLE_INPUT_SPEECH",

-      "ENABLE_NOTIFICATIONS",

-      "ENABLE_GPU=1",

-      "ENABLE_EGLIMAGE=1",

-      "ENABLE_TASK_MANAGER=1",

-      "ENABLE_EXTENSIONS=1",

-      "ENABLE_PLUGIN_INSTALLATION=1",

-      "ENABLE_PLUGINS=1",

-      "ENABLE_SESSION_SERVICE=1",

-      "ENABLE_THEMES=1",

-      "ENABLE_AUTOFILL_DIALOG=1",

-      "ENABLE_BACKGROUND=1",

-      "ENABLE_AUTOMATION=1",

-      "ENABLE_GOOGLE_NOW=1",

-      "ENABLE_LANGUAGE_DETECTION=1",

-      "ENABLE_PRINTING=1",

-      "ENABLE_CAPTIVE_PORTAL_DETECTION=1",

-      "ENABLE_APP_LIST=1",

-      "ENABLE_MESSAGE_CENTER=1",

-      "ENABLE_SETTINGS_APP=1",

-      "ENABLE_MANAGED_USERS=1",

-  ]

-}

-

-config("feature_flags") {

-  #defines = 

-}

-

-config("debug") {

-  defines = [

-    "_DEBUG",

-    "DYNAMIC_ANNOTATIONS_ENABLED=1",

-    "WTF_USE_DYNAMIC_ANNOTATIONS=1",

-  ]

-}

-

-config("release") {

-

-}

+# 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.
+
+config("my_msvs") {
+  defines = [
+      "CHROMIUM_BUILD",
+      "TOOLKIT_VIEWS=1",
+      "USE_LIBJPEG_TURBO=1",
+      "ENABLE_ONE_CLICK_SIGNIN",
+      "ENABLE_REMOTING=1",
+      "ENABLE_WEBRTC=1",
+      "ENABLE_CONFIGURATION_POLICY",
+      "ENABLE_INPUT_SPEECH",
+      "ENABLE_NOTIFICATIONS",
+      "ENABLE_GPU=1",
+      "ENABLE_EGLIMAGE=1",
+      "ENABLE_TASK_MANAGER=1",
+      "ENABLE_EXTENSIONS=1",
+      "ENABLE_PLUGIN_INSTALLATION=1",
+      "ENABLE_PLUGINS=1",
+      "ENABLE_SESSION_SERVICE=1",
+      "ENABLE_THEMES=1",
+      "ENABLE_AUTOFILL_DIALOG=1",
+      "ENABLE_BACKGROUND=1",
+      "ENABLE_AUTOMATION=1",
+      "ENABLE_GOOGLE_NOW=1",
+      "ENABLE_PRINTING=1",
+      "ENABLE_CAPTIVE_PORTAL_DETECTION=1",
+      "ENABLE_APP_LIST=1",
+      "ENABLE_MESSAGE_CENTER=1",
+      "ENABLE_SETTINGS_APP=1",
+      "ENABLE_MANAGED_USERS=1",
+  ]
+}
+
+config("feature_flags") {
+  #defines = 
+}
+
+config("debug") {
+  defines = [
+    "_DEBUG",
+    "DYNAMIC_ANNOTATIONS_ENABLED=1",
+    "WTF_USE_DYNAMIC_ANNOTATIONS=1",
+  ]
+}
+
+config("release") {
+
+}
diff --git a/tools/gn/secondary/build/config/BUILDCONFIG.gn b/tools/gn/secondary/build/config/BUILDCONFIG.gn
index d203677..28df11c 100644
--- a/tools/gn/secondary/build/config/BUILDCONFIG.gn
+++ b/tools/gn/secondary/build/config/BUILDCONFIG.gn
@@ -1,202 +1,224 @@
-# =============================================================================

-# BUILD FLAGS

-# =============================================================================

-#

-# This block lists input arguments to the build, along with their default

-# values. GN requires listing them explicitly so it can validate input and have

-# a central place to manage the build flags.

-#

-# If a value is specified on the command line, it will overwrite the defaults

-# given here, otherwise the default will be injected into the root scope.

-#

-# KEEP IN ALPHABETICAL ORDER and write a good description for everything.

-# Use "is_*" names for intrinsic platform descriptions and build modes, and

-# "use_*" names for optional features libraries, and configurations.

-declare_args() {

-  is_android = 0

-  is_component_build = 1

-  is_chromeos = 0

-  is_debug = 1

-  is_ios = 0

-  use_ash = 0

-  use_aura = 0

-  use_ozone = 0

-}

-

-# =============================================================================

-# SOURCES FILTERS

-# =============================================================================

-#

-# These patterns filter out platform-specific files when assigning to the

-# sources variable. The magic variable |sources_assignment_filter| is applied

-# to each assignment or appending to the sources variable and matches are

-# automatcally removed.

-#

-# We define lists of filters for each platform for all builds so they can

-# be used by individual targets if necessary (a target can always change

-# sources_assignment_filter on itself if it needs something more specific).

-#

-# Note that the patterns are NOT regular expressions. Only "*" and "\b" (path

-# boundary = end of string or slash) are supported, and the entire string

-# muct match the pattern (so you need "*.cc" to match all .cc files, for

-# example).

-

-windows_sources_filters = [

-  "*_win.cc",

-  "*_win.h",

-  "*_win_unittest.cc",

-  "*\bwin/*",

-]

-mac_sources_filters = [

-  "*_mac.h",

-  "*_mac.cc",

-  "*_mac.mm",

-  "*_mac_unittest.h",

-  "*_mac_unittest.cc",

-  "*_mac_unittest.mm",

-  "*\bmac/*",

-  "*_cocoa.h",

-  "*_cocoa.cc",

-  "*_cocoa.mm",

-  "*_cocoa_unittest.h",

-  "*_cocoa_unittest.cc",

-  "*_cocoa_unittest.mm",

-  "*\bcocoa/*",

-]

-ios_sources_filters = [

-  "*_ios.h",

-  "*_ios.cc",

-  "*_ios.mm",

-  "*_ios_unittest.h",

-  "*_ios_unittest.cc",

-  "*_ios_unittest.mm",

-  "*\bios/*",

-]

-objective_c_sources_filters = [

-  "*.mm",

-]

-linux_sources_filters = [

-  "*_linux.h",

-  "*_linux.cc",

-  "*_linux_unittest.h",

-  "*_linux_unittest.cc",

-  "*\blinux/*",

-]

-android_sources_filters = [

-  "*_android.h",

-  "*_android.cc",

-  "*_android_unittest.h",

-  "*_android_unittest.cc",

-  "*\bandroid/*",

-]

-posix_sources_filters = [

-  "*_posix.h",

-  "*_posix.cc",

-  "*_posix_unittest.h",

-  "*_posix_unittest.cc",

-  "*\bposix/*",

-]

-

-# Construct the full list of sources we're using for this platform.

-sources_assignment_filter = []

-if (is_win) {

-  sources_assignment_filter += posix_sources_filters

-} else {

-  sources_assignment_filter += windows_sources_filters

-}

-if (!is_mac) {

-  sources_assignment_filter += mac_sources_filters

-}

-if (!is_ios) {

-  sources_assignment_filter += ios_sources_filters

-}

-if (!is_mac && !is_ios) {

-  sources_assignment_filter += objective_c_sources_filters

-}

-if (!is_linux) {

-  sources_assignment_filter += linux_sources_filters

-}

-if (!is_android) {

-  sources_assignment_filter += android_sources_filters

-}

-

-# This is the actual set.

-set_sources_assignment_filter(sources_assignment_filter)

-

-# =============================================================================

-# SYSTEM CONFIG

-# =============================================================================

-

-is_nacl = 0

-

-# =============================================================================

-# BUILD OPTIONS

-# =============================================================================

-

-if (is_component_build) {

-  component_mode = "shared_library"

-} else {

-  component_mode = "static_library"

-}

-

-# =============================================================================

-# TARGET DEFAULTS

-# =============================================================================

-#

-# Set up the default configuration for every build target of the given type.

-# The values configured here will be automatically set on the scope of the

-# corresponding target. Target definitions can add or remove to the settings

-# here as needed.

-

-# Holds all configs used for making native executables and libraries, to avoid

-# duplication in each target below.

-native_compiler_configs = [

-  "//build/config:my_msvs",  # TODO(brettw) eraseme

-

-  "//build/config/compiler:compiler",

-  "//build/config/compiler:chromium_code",

-  "//build/config/compiler:default_warnings",

-  "//build/config/compiler:no_rtti",

-  "//build/config/compiler:runtime_library",

-]

-if (is_win) {

-  native_compiler_configs += "//build/config/win:sdk"

-} else if (is_mac) {

-  # TODO(brettw) this should be in an if (is_clang) block instead but I haven't

-  # written an is_clang flag yet.

-  native_compiler_configs += "//build/config/clang:find_bad_constructs"

-}

-

-if (is_debug) {

-  native_compiler_configs += "//build/config:debug"

-} else {

-  native_compiler_configs += "//build/config:release"

-}

-

-set_defaults("executable") {

-  configs = native_compiler_configs

-  if (is_mac) {

-    configs += "//build/config/mac:mac_dynamic_flags"

-  }

-}

-

-set_defaults("static_library") {

-  configs = native_compiler_configs

-}

-

-set_defaults("shared_library") {

-  configs = native_compiler_configs

-  if (is_mac) {

-    configs += "//build/config/mac:mac_dynamic_flags"

-  }

-}

-

-# ==============================================================================

-# TOOLCHAIN SETUP

-# ==============================================================================

-

-if (is_win) {

-  set_default_toolchain("//build/config/win:32")

-} else if (is_mac) {

-  set_default_toolchain("//build/config/mac:clang")

-}

+# 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.
+
+# =============================================================================
+# BUILD FLAGS
+# =============================================================================
+#
+# This block lists input arguments to the build, along with their default
+# values. GN requires listing them explicitly so it can validate input and have
+# a central place to manage the build flags.
+#
+# If a value is specified on the command line, it will overwrite the defaults
+# given here, otherwise the default will be injected into the root scope.
+#
+# KEEP IN ALPHABETICAL ORDER and write a good description for everything.
+# Use "is_*" names for intrinsic platform descriptions and build modes, and
+# "use_*" names for optional features libraries, and configurations.
+declare_args() {
+  # Set to build the Android version.
+  is_android = false
+  # Component build.
+  is_component_build = true
+  # ChromeOS build.
+  is_chromeos = false
+  # Debug build.
+  is_debug = true
+  # Hello, world
+  # IOS build.
+  is_ios = false
+
+  # Set when building with the "untrusted" Native Client toolchain.
+  #
+  # Do not set directly, this will be set automatically when compiling targets
+  # with a NaCl toolchain.
+  is_nacl = false
+
+  # Set to true when compiling with the Clang compiler. Typically this is used
+  # to configure warnings.
+  is_clang = false
+
+  # ASH is enabled.
+  use_ash = false
+  # Aura is enabled.
+  use_aura = false
+  # Ozone is enabled.
+  use_ozone = false
+}
+
+# =============================================================================
+# SOURCES FILTERS
+# =============================================================================
+#
+# These patterns filter out platform-specific files when assigning to the
+# sources variable. The magic variable |sources_assignment_filter| is applied
+# to each assignment or appending to the sources variable and matches are
+# automatcally removed.
+#
+# We define lists of filters for each platform for all builds so they can
+# be used by individual targets if necessary (a target can always change
+# sources_assignment_filter on itself if it needs something more specific).
+#
+# Note that the patterns are NOT regular expressions. Only "*" and "\b" (path
+# boundary = end of string or slash) are supported, and the entire string
+# muct match the pattern (so you need "*.cc" to match all .cc files, for
+# example).
+
+windows_sources_filters = [
+  "*_win.cc",
+  "*_win.h",
+  "*_win_unittest.cc",
+  "*\bwin/*",
+]
+mac_sources_filters = [
+  "*_mac.h",
+  "*_mac.cc",
+  "*_mac.mm",
+  "*_mac_unittest.h",
+  "*_mac_unittest.cc",
+  "*_mac_unittest.mm",
+  "*\bmac/*",
+  "*_cocoa.h",
+  "*_cocoa.cc",
+  "*_cocoa.mm",
+  "*_cocoa_unittest.h",
+  "*_cocoa_unittest.cc",
+  "*_cocoa_unittest.mm",
+  "*\bcocoa/*",
+]
+ios_sources_filters = [
+  "*_ios.h",
+  "*_ios.cc",
+  "*_ios.mm",
+  "*_ios_unittest.h",
+  "*_ios_unittest.cc",
+  "*_ios_unittest.mm",
+  "*\bios/*",
+]
+objective_c_sources_filters = [
+  "*.mm",
+]
+linux_sources_filters = [
+  "*_linux.h",
+  "*_linux.cc",
+  "*_linux_unittest.h",
+  "*_linux_unittest.cc",
+  "*\blinux/*",
+]
+android_sources_filters = [
+  "*_android.h",
+  "*_android.cc",
+  "*_android_unittest.h",
+  "*_android_unittest.cc",
+  "*\bandroid/*",
+]
+posix_sources_filters = [
+  "*_posix.h",
+  "*_posix.cc",
+  "*_posix_unittest.h",
+  "*_posix_unittest.cc",
+  "*\bposix/*",
+]
+
+# Construct the full list of sources we're using for this platform.
+sources_assignment_filter = []
+if (is_win) {
+  sources_assignment_filter += posix_sources_filters
+} else {
+  sources_assignment_filter += windows_sources_filters
+}
+if (!is_mac) {
+  sources_assignment_filter += mac_sources_filters
+}
+if (!is_ios) {
+  sources_assignment_filter += ios_sources_filters
+}
+if (!is_mac && !is_ios) {
+  sources_assignment_filter += objective_c_sources_filters
+}
+if (!is_linux) {
+  sources_assignment_filter += linux_sources_filters
+}
+if (!is_android) {
+  sources_assignment_filter += android_sources_filters
+}
+
+# This is the actual set.
+set_sources_assignment_filter(sources_assignment_filter)
+
+# =============================================================================
+# BUILD OPTIONS
+# =============================================================================
+
+if (is_component_build) {
+  component_mode = "shared_library"
+} else {
+  component_mode = "static_library"
+}
+
+# =============================================================================
+# TARGET DEFAULTS
+# =============================================================================
+#
+# Set up the default configuration for every build target of the given type.
+# The values configured here will be automatically set on the scope of the
+# corresponding target. Target definitions can add or remove to the settings
+# here as needed.
+
+# Holds all configs used for making native executables and libraries, to avoid
+# duplication in each target below.
+native_compiler_configs = [
+  "//build/config:my_msvs",  # TODO(brettw) eraseme
+
+  "//build/config/compiler:compiler",
+  "//build/config/compiler:chromium_code",
+  "//build/config/compiler:default_warnings",
+  "//build/config/compiler:no_rtti",
+  "//build/config/compiler:runtime_library",
+]
+if (is_win) {
+  native_compiler_configs += "//build/config/win:sdk"
+} else if (is_mac) {
+  # TODO(brettw) this should be in an if (is_clang) block instead but I haven't
+  # written an is_clang flag yet.
+  native_compiler_configs += "//build/config/clang:find_bad_constructs"
+}
+
+if (is_debug) {
+  native_compiler_configs += "//build/config:debug"
+} else {
+  native_compiler_configs += "//build/config:release"
+}
+
+set_defaults("executable") {
+  configs = native_compiler_configs
+  if (is_mac) {
+    configs += "//build/config/mac:mac_dynamic_flags"
+  } else if (is_linux) {
+    configs += "//build/config/linux:executable_ldconfig"
+  }
+}
+
+set_defaults("static_library") {
+  configs = native_compiler_configs
+}
+
+set_defaults("shared_library") {
+  configs = native_compiler_configs
+  if (is_mac) {
+    configs += "//build/config/mac:mac_dynamic_flags"
+  }
+}
+
+# ==============================================================================
+# TOOLCHAIN SETUP
+# ==============================================================================
+
+if (is_win) {
+  set_default_toolchain("//build/toolchain/win:32")
+} else if (is_linux) {
+  set_default_toolchain("//build/toolchain/linux:gcc")
+} else if (is_mac) {
+  set_default_toolchain("//build/toolchain/mac:clang")
+}
diff --git a/tools/gn/secondary/build/config/compiler/BUILD.gn b/tools/gn/secondary/build/config/compiler/BUILD.gn
index 04f73e0..00ebe8f 100644
--- a/tools/gn/secondary/build/config/compiler/BUILD.gn
+++ b/tools/gn/secondary/build/config/compiler/BUILD.gn
@@ -11,67 +11,121 @@
       "/Od", "/WX", "/Zi", "/Gy", "/GS", "/RTC1", "/EHsc",
     ]
   } else {
+    # Common GCC compiler flags setup.
+    # --------------------------------
     cflags = [
-      # TODO(brettw) obviously this needs to be parameterized.
-      "-arch i386",
-
-      # See http://crbug.com/32204
-      "-fno-strict-aliasing",
-
-      "-fno-threadsafe-statics",
-      "-fstack-protector-all",
+      "-fno-strict-aliasing",  # See http://crbug.com/32204
       "-fvisibility=hidden",
+      "-g",  # Debug symbols.
+    ]
+    cflags_c = [
+    ]
+    cflags_cc = [
+      "-fno-exceptions",
+      "-fno-threadsafe-statics",
       "-fvisibility-inlines-hidden",
     ]
-    # !!! Please keep additions sorted alphabetically.
+    ldflags = [
+      "-Wl,-z,now",
+      "-Wl,-z,relro",
+    ]
 
-    # TODO(brettw) these should be clang-only.
-    # if (is_clang) {
+    # Optimization.
+    if (is_debug) {
+      cflags += [
+        "-O0"  # No optimization.
+      ]
+    } else {
+      # TODO(brettw) release optimization.
+    }
+
+    # Stack protection.
+    # TODO(brettw) why do we have different values for all of these cases?
+    if (is_mac) {
+      cflags += "-fstack-protector-all"
+    } else if (is_chromeos) {
+      cflags += "-fstack-protector-strong"
+    } else if (is_linux) {
+      cflags += [ "-fstack-protector", "--param=ssp-buffer-size=4" ]
+    }
+
+    # Mac-specific compiler flags setup.
+    # ----------------------------------
+    if (is_mac) {
+      # These flags are shared between the C compiler and linker.
+      common_mac_flags = [
+        # TODO(brettw) obviously this arch flag needs to be parameterized.
+        "-arch i386",
+
+        # Set which SDK to use.
+        # TODO(brettw) this needs to be configurable somehow.
+        "-isysroot", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk",
+
+        "-mmacosx-version-min=10.6",
+      ]
+
+      cflags += common_mac_flags + [
+        # Without this, the constructors and destructors of a C++ object inside
+        # an Objective C struct won't be called, which is very bad.
+        "-fobjc-call-cxx-cdtors",
+      ]
+
+      cflags_c += [ "-std=c99" ]
+      cflags_cc += [ "-std=gnu++11" ]
+
+      ldflags += common_mac_flags + [
+        "-L.",
+
+        # TODO(brettW) I don't understand these options.
+        "-Wl,-rpath,@loader_path/.",
+        "-Wl,-rpath,@loader_path/../../..",
+      ]
+    }
+
+    # Linux-specific compiler flags setup.
+    # ------------------------------------
+    if (is_linux) {
+      cflags += [
+        "-fPIC",
+        "-pthread",
+        "-pipe",  # Use pipes for communicating between sub-processes. Faster.
+      ]
+      ldflags += [
+        # Use Gold for linking: it is checked out in the source tree.
+        "-B$relative_build_to_source_root_dir/third_party/gold",
+
+        "-fPIC",
+        "-pthread",
+        "-Wl,-z,noexecstack",
+
+        # TODO(brettw) gold linker flags, only target.
+        # There seems to be a conflict of --icf and -pie in gold which can
+        # generate crashy binaries. As a security measure, -pie takes
+        # precendence for now.
+        # TODO(brettw) common.gypi has this only for target toolset.
+        #"-Wl,--icf=safe",
+        "-Wl,--icf=none",
+
+        # TODO(brettw) gold linker flags, only target.
+        # Experimentation found that using four linking threads
+        # saved ~20% of link time.
+        # https://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/281527606915bb36
+        # Only apply this to the target linker, since the host
+        # linker might not be gold, but isn't used much anyway.
+        "-Wl,--threads",
+        "-Wl,--thread-count=4",
+      ]
+    }
+
+    # 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) {
       cflags += [
         "-fcolor-diagnostics",
       ]
-    #}
-
-    cflags_c = [
-      "-std=c99",
-    ]
-
-    cflags_cc = [
-      "-fno-exceptions",
-      "-std=gnu++11",
-    ]
-  }
-
-  if (is_mac) {
-    # These are used for both compiler and linker flags on Mac.
-    common_mac_flags = [
-      # TODO(brettw) obviously this needs to be parameterized.
-      "-arch i386",
-
-      # Set which SDK to use.
-      # TODO(brettw) this needs to be configurable somehow.
-      "-isysroot", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk",
-
-      "-mmacosx-version-min=10.6",
-    ]
-
-    # Mac compiler flags.
-    cflags += [
-      # Without this, the constructors and destructors of a C++ object inside
-      # an Objective C struct won't be called, which is very bad.
-      "-fobjc-call-cxx-cdtors",
-    ]
-    cflags += common_mac_flags
-
-    # Mac linker flags.
-    ldflags = [
-      "-L.",
-
-      # TODO(brettW) I don't understand these options.
-      "-Wl,-rpath,@loader_path/.",
-      "-Wl,-rpath,@loader_path/../../..",
-    ]
-    ldflags += common_mac_flags
+    }
   }
 }
 
@@ -134,12 +188,30 @@
     cflags = [
       "/W4",  # Warning level 4.
     ]
-  } else if (is_mac) {
+  } else {
     cflags = [
       "-Wall",
       "-Werror",
-      "-Wextra",
+
+      # GCC turns on -Wsign-compare for C++ under -Wall, but clang doesn't,
+      # so we specify it explicitly.
+      # TODO(fischman): remove this if http://llvm.org/PR10448 obsoletes it.
+      # http://code.google.com/p/chromium/issues/detail?id=90453
+      "-Wsign-compare",
     ]
+
+    # In Chromium code, we define __STDC_foo_MACROS in order to get the
+    # C99 macros on Mac and Linux.
+    defines = [
+      "__STDC_CONSTANT_MACROS",
+      "__STDC_FORMAT_MACROS",
+    ]
+
+    # TODO(brettw) this should also be enabled on Linux but some files
+    # currently fail.
+    if (is_mac) {
+      cflags += "-Wextra"
+    }
   }
 }
 config("no_chromium_code") {
@@ -211,26 +283,27 @@
       "/wd4706",  # Assignment within conditional expression.
       "/wd4819",  # Character not in the current code page.
     ]
-  }
-
-  # TODO(brettw) this should probably be if(clang).
-  if (is_mac) {
+  } else {
+    # Common GCC warning setup.
     cflags = [
-      # Warn for weird old-style text after an #endif.
-      "-Wendif-labels",
+      # Enables.
+      "-Wendif-labels",  # Weird old-style text after an #endif.
 
-      "-Wnewline-eof",
-
-      # Don't warn about the "struct foo f = {0};" initialization pattern.
-      "-Wno-missing-field-initializers",
-
-      # Don't warn about unused function parameters.
-      "-Wno-unused-parameter",
+      # Disables.
+      "-Wno-missing-field-initializers",  # "struct foo f = {0};"
+      "-Wno-unused-parameter",  # Unused function parameters.
+      "-Wno-write-strings",
     ]
 
+    if (is_mac) {
+      cflags += [
+        "-Wnewline-eof",
+      ]
+    }
+
     # TODO(brettw) Ones below here should be clang-only when we have a flag
     # for it.
-    #if (is_clang) {
+    if (is_mac) { #if (is_clang) {
       cflags += [
         "-Wheader-hygiene",
 
@@ -260,6 +333,6 @@
         # Warns when a const char[] is converted to bool.
         "-Wstring-conversion",
       ]
-    #}  #is_clang
+    }
   }
 }
diff --git a/tools/gn/secondary/build/config/linux/BUILD.gn b/tools/gn/secondary/build/config/linux/BUILD.gn
new file mode 100644
index 0000000..dec72a7
--- /dev/null
+++ b/tools/gn/secondary/build/config/linux/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+# Sets up the dynamic library search path to include our "lib" directory.
+config("executable_ldconfig") {
+  ldflags = [
+    # Want to pass "\$". Need to escape both '\' and '$'. GN will re-escape as
+    # required for ninja.
+    "-Wl,-rpath=\\\$ORIGIN/lib/",
+
+    "-Wl,-rpath-link=lib/",
+  ]
+}
+
+pkg_script = "pkg-config.py"
+
+config("glib") {
+  glib_packages = "glib-2.0 gmodule-2.0 gobject-2.0 gthread-2.0"
+
+  cflags = exec_script(pkg_script, [ "--cflags", glib_packages ], "list lines")
+  ldflags = exec_script(pkg_script, [ "--libs", glib_packages ], "list lines")
+  # if (use_x11) {  # TODO(brettw) need to add use_x11
+    ldflags += "-lXtst"
+  #}
+}
+
+config("gtk") {
+  # Gtk requires gmodule, but it does not list it as a dependency in some
+  # misconfigured systems.
+  gtk_packages = "gmodule-2.0 gtk+-2.0 gthread-2.0"
+
+  cflags = exec_script(pkg_script, [ "--cflags", gtk_packages ], "list lines")
+  ldflags = exec_script(pkg_script, [ "--libs", gtk_packages ], "list lines")
+}
+
+config("x11") {
+  x11_packages = "x11 xi"
+
+  cflags = exec_script(pkg_script, [ "--cflags", x11_packages ], "list lines")
+  ldflags = exec_script(pkg_script, [ "--libs", x11_packages ], "list lines")
+}
diff --git a/tools/gn/secondary/build/config/linux/pkg-config.py b/tools/gn/secondary/build/config/linux/pkg-config.py
new file mode 100644
index 0000000..1cee448
--- /dev/null
+++ b/tools/gn/secondary/build/config/linux/pkg-config.py
@@ -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.
+
+import subprocess
+import sys
+
+sys.exit(subprocess.call(["pkg-config"] + sys.argv[1:]))
diff --git a/tools/gn/secondary/build/config/mac/BUILD.gn b/tools/gn/secondary/build/config/mac/BUILD.gn
index 55ffd03..78c106a 100644
--- a/tools/gn/secondary/build/config/mac/BUILD.gn
+++ b/tools/gn/secondary/build/config/mac/BUILD.gn
@@ -2,76 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# On Mac, this is usefor everything except static libraries.
+# On Mac, this is used for everything except static libraries.
 config("mac_dynamic_flags") {
   ldflags = [
     "-Wl,-search_paths_first",
   ]
 }
-
-
-cc = "../../third_party/llvm-build/Release+Asserts/bin/clang"
-cxx = "../../third_party/llvm-build/Release+Asserts/bin/clang++"
-ld = cxx
-
-toolchain("clang") {
-  tool("cc") {
-    command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c \$cflags_pch_c -c \$in -o \$out"
-    description = "CC \$out"
-    depfile = "\$out.d"
-    deps = "gcc"
-  }
-  tool("cxx") {
-    command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc \$cflags_pch_cc -c \$in -o \$out"
-    description = "CXX \$out"
-    depfile = "\$out.d"
-    deps = "gcc"
-  }
-  tool("objc") {
-    command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c \$cflags_objc \$cflags_pch_objc -c \$in -o \$out"
-    description = "OBJC \$out"
-    depfile = "\$out.d"
-    deps = "gcc"
-  }
-  tool("objcxx") {
-    command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc \$cflags_objcc \$cflags_pch_objcc -c \$in -o \$out"
-    description = "OBJCXX \$out"
-    depfile = "\$out.d"
-    deps = "gcc"
-  }
-  tool("alink") {
-    command = "rm -f \$out && ./gyp-mac-tool filter-libtool libtool \$libtool_flags -static -o \$out \$in \$postbuilds"
-    description = "LIBTOOL-STATIC \$out, POSTBUILDS"
-  }
-  tool("solink") {
-    command = "if [ ! -e \$lib -o ! -e \${lib}.TOC ] || otool -l \$lib | grep -q LC_REEXPORT_DYLIB ; then $ld -shared \$ldflags -o \$lib \$in \$solibs \$libs \$postbuilds && { otool -l \$lib | grep LC_ID_DYLIB -A 5; nm -gP \$lib | cut -f1-2 -d' ' | grep -v U\$\$; true; } > \${lib}.TOC; else $ld -shared \$ldflags -o \$lib \$in \$solibs \$libs \$postbuilds && { otool -l \$lib | grep LC_ID_DYLIB -A 5; nm -gP \$lib | cut -f1-2 -d' ' | grep -v U\$\$; true; } > \${lib}.tmp && if ! cmp -s \${lib}.tmp \${lib}.TOC; then mv \${lib}.tmp \${lib}.TOC ; fi; fi"
-    description = "SOLINK \$lib, POSTBUILDS"
-    #pool = "link_pool"
-    restat = "1"
-  }
-  tool("link") {
-    command = "$ld \$ldflags -o \$out \$in \$solibs \$libs \$postbuilds"
-    description = "LINK \$out, POSTBUILDS"
-    #pool = "link_pool"
-  }
-  #tool("infoplist") {
-  #  command = "$cc -E -P -Wno-trigraphs -x c \$defines \$in -o \$out && plutil -convert xml1 \$out \$out"
-  #  description = "INFOPLIST \$out"
-  #}
-  #tool("mac_tool") {
-  #  command = "\$env ./gyp-mac-tool \$mactool_cmd \$in \$out"
-  #  description = "MACTOOL \$mactool_cmd \$in"
-  #}
-  #tool("package_framework") {
-  #  command = "./gyp-mac-tool package-framework \$out \$version \$postbuilds && touch \$out"
-  #  description = "PACKAGE FRAMEWORK \$out, POSTBUILDS"
-  #}
-  tool("stamp") {
-    command = "\${postbuilds}touch \$out"
-    description = "STAMP \$out"
-  }
-  tool("copy") {
-    command = "ln -f \$in \$out 2>/dev/null || (rm -rf \$out && cp -af \$in \$out)"
-    description = "COPY \$in \$out"
-  }
-}
diff --git a/tools/gn/secondary/build/config/win/BUILD.gn b/tools/gn/secondary/build/config/win/BUILD.gn
index 955504a..3c5958a 100644
--- a/tools/gn/secondary/build/config/win/BUILD.gn
+++ b/tools/gn/secondary/build/config/win/BUILD.gn
@@ -1,184 +1,22 @@
-# 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.

-

-# Should only be running on Windows.

-assert(is_win)

-

-# Setup the Visual Studio state.

-#

-# Its argument is the location to write the environment files.

-# It will write "environment.x86" and "environment.x64" to this directory,

-# and return a list to us.

-#

-# 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")

-

-# 32-bit toolchain -------------------------------------------------------------

-

-toolchain("32") {

-  tool("cc") {

-    command = "ninja -t msvc -e \$arch -- 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"

-    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 \$

-  #      \$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

-  #  description = RC \$in

-  #}

-  #tool("asm") {

-  #  command = $python_path gyp-win-tool asm-wrapper \$arch 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"

-    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 \$

-  #      /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 \$

-  #      \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp \$dll.manifest.res

-  #  description = LINK_EMBED_INC(DLL) \$dll

-  #  restat = 1

-  #  rspfile = \$dll.rsp

-  #  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 \$

-  #      /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 \$

-  #      \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp \$dll.manifest.res

-  #  description = LINK_EMBED_INC(DLL) \$dll

-  #  restat = 1

-  #  rspfile = \$dll.rsp

-  #  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 \$

-  #      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 \$

-  #      @\$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 \$

-  #      /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 \$

-  #      -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 \$

-  #      /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 \$

-  #      -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 \$

-  #      if exist \$out.manifest del \$out.manifest && $python_path gyp-win-tool \$

-  #      manifest-wrapper \$arch 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"

-    description = "LINK(DLL) \$dll"

-    restat = "1"

-    rspfile = "\$dll.rsp"

-    rspfile_content = "\$libs \$in_newline \$ldflags"

-  }

-  tool("solink_module") {

-    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.manifet"

-    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"

-    description = "LINK \$out"

-    rspfile = "\$out.rsp"

-    rspfile_content = "\$in_newline \$libs \$ldflags"

-  }

-  tool("stamp") {

-    command = "$python_path gyp-win-tool stamp \$out"

-    description = "STAMP \$out"

-  }

-  tool("copy") {

-    command = "$python_path gyp-win-tool recursive-mirror \$in \$out"

-    description = "COPY \$in \$out"

-  }

-}

-

-# 64-bit toolchain -------------------------------------------------------------

-

-toolchain("64") {

-}

-

-# SDK setup --------------------------------------------------------------------

-

-config("sdk") {

-  # The include path is the stuff returned by the script plus out own WTL

-  # checkout.

-  # TODO(brettw) should adding WTL be at this level or should it be more on

-  # a per-project basis?

-  includes = msvc_config[0] + "../../third_party/wtl/include"

-

-  defines = [

-    "_ATL_NO_OPENGL",

-    "_SECURE_ATL",

-    "_WIN32_WINNT=0x0602",

-    "_WINDOWS",

-    "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",

-    "NOMINMAX",

-    "NTDDI_VERSION=0x06020000",

-    "PSAPI_VERSION=1",

-    "WIN32",

-    "WIN32_LEAN_AND_MEAN",

-    "WINVER=0x0602",

-  ]

-}

+# 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.
+
+config("sdk") {
+  # The include path is the stuff returned by the script.
+  #includes = msvc_config[0]  TODO(brettw) make this work.
+
+  defines = [
+    "_ATL_NO_OPENGL",
+    "_SECURE_ATL",
+    "_WIN32_WINNT=0x0602",
+    "_WINDOWS",
+    "CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
+    "NOMINMAX",
+    "NTDDI_VERSION=0x06020000",
+    "PSAPI_VERSION=1",
+    "WIN32",
+    "WIN32_LEAN_AND_MEAN",
+    "WINVER=0x0602",
+  ]
+}
diff --git a/tools/gn/secondary/build/toolchain/linux/BUILD.gn b/tools/gn/secondary/build/toolchain/linux/BUILD.gn
new file mode 100644
index 0000000..b3aed22
--- /dev/null
+++ b/tools/gn/secondary/build/toolchain/linux/BUILD.gn
@@ -0,0 +1,47 @@
+# 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.
+
+cc = "gcc"
+cxx = "g++"
+ld = cxx
+
+toolchain("gcc") {
+  tool("cc") {
+    # cflags_pch_c
+    command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c -c \$in -o \$out"
+    description = "CC \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("cxx") {
+    # cflags_pch_cc
+    command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc -c \$in -o \$out"
+    description = "CXX \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("alink") {
+    command = "rm -f \$out && ar rcs \$out \$in"
+    description = "AR \$out"
+  }
+  tool("solink") {
+    command = "if [ ! -e \$lib -o ! -e \${lib}.TOC ]; then $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.TOC; else $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.tmp && if ! cmp -s \${lib}.tmp \${lib}.TOC; then mv \${lib}.tmp \${lib}.TOC ; fi; fi"
+    description = "SOLINK \$lib"
+    #pool = "link_pool"
+    restat = "1"
+  }
+  tool("link") {
+    command = "$ld \$ldflags -o \$out -Wl,--start-group \$in \$solibs -Wl,--end-group \$libs"
+    description = "LINK \$out"
+    #pool = "link_pool"
+  }
+  tool("stamp") {
+    command = "\${postbuilds}touch \$out"
+    description = "STAMP \$out"
+  }
+  tool("copy") {
+    command = "ln -f \$in \$out 2>/dev/null || (rm -rf \$out && cp -af \$in \$out)"
+    description = "COPY \$in \$out"
+  }
+}
diff --git a/tools/gn/secondary/build/toolchain/mac/BUILD.gn b/tools/gn/secondary/build/toolchain/mac/BUILD.gn
new file mode 100644
index 0000000..244ee42
--- /dev/null
+++ b/tools/gn/secondary/build/toolchain/mac/BUILD.gn
@@ -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.
+
+cc = "$relative_build_to_source_root_dir/third_party/llvm-build/Release+Asserts/bin/clang"
+cxx = "$relative_build_to_source_root_dir/third_party/llvm-build/Release+Asserts/bin/clang++"
+ld = cxx
+
+toolchain("clang") {
+  tool("cc") {
+    command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c \$cflags_pch_c -c \$in -o \$out"
+    description = "CC \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("cxx") {
+    command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc \$cflags_pch_cc -c \$in -o \$out"
+    description = "CXX \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("objc") {
+    command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c \$cflags_objc \$cflags_pch_objc -c \$in -o \$out"
+    description = "OBJC \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("objcxx") {
+    command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc \$cflags_objcc \$cflags_pch_objcc -c \$in -o \$out"
+    description = "OBJCXX \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("alink") {
+    command = "rm -f \$out && ./gyp-mac-tool filter-libtool libtool \$libtool_flags -static -o \$out \$in \$postbuilds"
+    description = "LIBTOOL-STATIC \$out, POSTBUILDS"
+  }
+  tool("solink") {
+    command = "if [ ! -e \$lib -o ! -e \${lib}.TOC ] || otool -l \$lib | grep -q LC_REEXPORT_DYLIB ; then $ld -shared \$ldflags -o \$lib \$in \$solibs \$libs \$postbuilds && { otool -l \$lib | grep LC_ID_DYLIB -A 5; nm -gP \$lib | cut -f1-2 -d' ' | grep -v U\$\$; true; } > \${lib}.TOC; else $ld -shared \$ldflags -o \$lib \$in \$solibs \$libs \$postbuilds && { otool -l \$lib | grep LC_ID_DYLIB -A 5; nm -gP \$lib | cut -f1-2 -d' ' | grep -v U\$\$; true; } > \${lib}.tmp && if ! cmp -s \${lib}.tmp \${lib}.TOC; then mv \${lib}.tmp \${lib}.TOC ; fi; fi"
+    description = "SOLINK \$lib, POSTBUILDS"
+    #pool = "link_pool"
+    restat = "1"
+  }
+  tool("link") {
+    command = "$ld \$ldflags -o \$out \$in \$solibs \$libs \$postbuilds"
+    description = "LINK \$out, POSTBUILDS"
+    #pool = "link_pool"
+  }
+  #tool("infoplist") {
+  #  command = "$cc -E -P -Wno-trigraphs -x c \$defines \$in -o \$out && plutil -convert xml1 \$out \$out"
+  #  description = "INFOPLIST \$out"
+  #}
+  #tool("mac_tool") {
+  #  command = "\$env ./gyp-mac-tool \$mactool_cmd \$in \$out"
+  #  description = "MACTOOL \$mactool_cmd \$in"
+  #}
+  #tool("package_framework") {
+  #  command = "./gyp-mac-tool package-framework \$out \$version \$postbuilds && touch \$out"
+  #  description = "PACKAGE FRAMEWORK \$out, POSTBUILDS"
+  #}
+  tool("stamp") {
+    command = "\${postbuilds}touch \$out"
+    description = "STAMP \$out"
+  }
+  tool("copy") {
+    command = "ln -f \$in \$out 2>/dev/null || (rm -rf \$out && cp -af \$in \$out)"
+    description = "COPY \$in \$out"
+  }
+}
diff --git a/tools/gn/secondary/build/toolchain/nacl/BUILD.gn b/tools/gn/secondary/build/toolchain/nacl/BUILD.gn
new file mode 100644
index 0000000..2e2fc7f
--- /dev/null
+++ b/tools/gn/secondary/build/toolchain/nacl/BUILD.gn
@@ -0,0 +1,55 @@
+# 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.
+
+
+toolchain("x86_newlib") {
+  toolprefix = "gen/sdk/toolchain/linux_x86_newlib/bin/x86_64-nacl-"
+  cc = toolprefix + "gcc"
+  cxx = toolprefix + "g++"
+  ld = toolprefix + "g++"
+
+  tool("cc") {
+    command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c -c \$in -o \$out"
+    description = "CC(NaCl x86 Newlib) \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("cxx") {
+    # cflags_pch_cc
+    command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc -c \$in -o \$out"
+    description = "CXX(NaCl x86 Newlib) \$out"
+    depfile = "\$out.d"
+    deps = "gcc"
+  }
+  tool("alink") {
+    command = "rm -f \$out && ${toolprefix}ar rcs \$out \$in"
+    description = "AR(NaCl x86 Newlib) \$out"
+  }
+  tool("solink") {
+    command = "if [ ! -e \$lib -o ! -e \${lib}.TOC ]; then $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.TOC; else $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.tmp && if ! cmp -s \${lib}.tmp \${lib}.TOC; then mv \${lib}.tmp \${lib}.TOC ; fi; fi"
+    description = "SOLINK(NaCl x86 Newlib) \$lib"
+    #pool = "link_pool"
+    restat = "1"
+  }
+  tool("link") {
+    command = "$ld \$ldflags -o \$out -Wl,--start-group \$in \$solibs -Wl,--end-group \$libs"
+    description = "LINK(NaCl x86 Newlib) \$out"
+    #pool = "link_pool"
+  }
+
+  toolchain_args() {
+    is_nacl = true
+
+    # Component build not supported in NaCl, since it does not support shared
+    # libraries.
+    is_component_build = false
+
+    # Override the default OS detection.
+    is_android = false
+    is_mac = false
+    is_posix = true
+    is_linux = false
+    is_win = false
+  }
+}
diff --git a/tools/gn/secondary/build/toolchain/win/BUILD.gn b/tools/gn/secondary/build/toolchain/win/BUILD.gn
new file mode 100644
index 0000000..f602b0b
--- /dev/null
+++ b/tools/gn/secondary/build/toolchain/win/BUILD.gn
@@ -0,0 +1,153 @@
+# 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.
+
+# Should only be running on Windows.
+assert(is_win)
+
+# Setup the Visual Studio state.
+#
+# Its argument is the location to write the environment files.
+# It will write "environment.x86" and "environment.x64" to this directory,
+# and return a list to us.
+#
+# 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")
+
+# 32-bit toolchain -------------------------------------------------------------
+
+toolchain("32") {
+  tool("cc") {
+    command = "ninja -t msvc -e \$arch -- 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"
+    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 \$
+  #      \$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
+  #  description = RC \$in
+  #}
+  #tool("asm") {
+  #  command = $python_path gyp-win-tool asm-wrapper \$arch 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"
+    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 \$
+  #      /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 \$
+  #      \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp \$dll.manifest.res
+  #  description = LINK_EMBED_INC(DLL) \$dll
+  #  restat = 1
+  #  rspfile = \$dll.rsp
+  #  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 \$
+  #      /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 \$
+  #      \$implibflag /DLL /OUT:\$dll /PDB:\$dll.pdb @\$dll.rsp \$dll.manifest.res
+  #  description = LINK_EMBED_INC(DLL) \$dll
+  #  restat = 1
+  #  rspfile = \$dll.rsp
+  #  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 \$
+  #      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 \$
+  #      @\$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 \$
+  #      /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 \$
+  #      -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 \$
+  #      /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 \$
+  #      -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 \$
+  #      if exist \$out.manifest del \$out.manifest && $python_path gyp-win-tool \$
+  #      manifest-wrapper \$arch 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"
+    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"
+    description = "LINK \$out"
+    rspfile = "\$out.rsp"
+    rspfile_content = "\$in_newline \$libs \$ldflags"
+  }
+  tool("stamp") {
+    command = "$python_path gyp-win-tool stamp \$out"
+    description = "STAMP \$out"
+  }
+  tool("copy") {
+    command = "$python_path gyp-win-tool recursive-mirror \$in \$out"
+    description = "COPY \$in \$out"
+  }
+}
+
+# 64-bit toolchain -------------------------------------------------------------
+
+toolchain("64") {
+}
diff --git a/tools/gn/secondary/crypto/BUILD.gn b/tools/gn/secondary/crypto/BUILD.gn
new file mode 100644
index 0000000..ff6a0c3
--- /dev/null
+++ b/tools/gn/secondary/crypto/BUILD.gn
@@ -0,0 +1,235 @@
+# 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("ssl/flags.gni")
+
+component("crypto") {
+  sources = [
+    "apple_keychain.h",
+    "apple_keychain_ios.mm",
+    "apple_keychain_mac.mm",
+    "capi_util.cc",
+    "capi_util.h",
+    "crypto_export.h",
+    "crypto_module_blocking_password_delegate.h",
+    "cssm_init.cc",
+    "cssm_init.h",
+    "curve25519.cc",
+    "curve25519.h",
+    "curve25519-donna.c",
+    "ghash.cc",
+    "ghash.h",
+    "ec_private_key.h",
+    "ec_private_key_nss.cc",
+    "ec_private_key_openssl.cc",
+    "ec_signature_creator.cc",
+    "ec_signature_creator.h",
+    "ec_signature_creator_impl.h",
+    "ec_signature_creator_nss.cc",
+    "ec_signature_creator_openssl.cc",
+    "encryptor.cc",
+    "encryptor.h",
+    "encryptor_nss.cc",
+    "encryptor_openssl.cc",
+    "hkdf.cc",
+    "hkdf.h",
+    "hmac_nss.cc",
+    "hmac_openssl.cc",
+    "mac_security_services_lock.cc",
+    "mac_security_services_lock.h",
+    # TODO(brettw) these mocks should be moved to a test_support_crypto target
+    # if possible.
+    "mock_apple_keychain.cc",
+    "mock_apple_keychain.h",
+    "mock_apple_keychain_ios.cc",
+    "mock_apple_keychain_mac.cc",
+    "p224_spake.cc",
+    "p224_spake.h",
+    "nss_util.cc",
+    "nss_util.h",
+    "nss_util_internal.h",
+    "openpgp_symmetric_encryption.cc",
+    "openpgp_symmetric_encryption.h",
+    "openssl_util.cc",
+    "openssl_util.h",
+    "p224.cc",
+    "p224.h",
+    "random.h",
+    "random.cc",
+    "rsa_private_key.cc",
+    "rsa_private_key.h",
+    "rsa_private_key_nss.cc",
+    "rsa_private_key_openssl.cc",
+    "scoped_capi_types.h",
+    "scoped_nss_types.h",
+    "secure_hash.h",
+    "secure_hash_default.cc",
+    "secure_hash_openssl.cc",
+    "sha2.cc",
+    "sha2.h",
+    "signature_creator.h",
+    "signature_creator_nss.cc",
+    "signature_creator_openssl.cc",
+    "signature_verifier.h",
+    "signature_verifier_nss.cc",
+    "signature_verifier_openssl.cc",
+    "symmetric_key_nss.cc",
+    "symmetric_key_openssl.cc",
+    "third_party/nss/chromium-blapi.h",
+    "third_party/nss/chromium-blapit.h",
+    "third_party/nss/chromium-nss.h",
+    "third_party/nss/pk11akey.cc",
+    "third_party/nss/rsawrapr.c",
+    "third_party/nss/secsign.cc",
+  ]
+
+  deps = [
+    ":crypto_minimal",
+    "//base",
+    "//base/third_party/dynamic_annotations",
+    "//crypto/ssl:metassl",
+  ]
+  forward_dependent_configs_from = [ "//crypto/ssl:metassl" ]
+
+  if (!is_mac && !is_ios) {
+    sources -= [
+      "apple_keychain.h",
+      "mock_apple_keychain.cc",
+      "mock_apple_keychain.h",
+    ]
+  }
+
+  if (!is_linux) {
+    sources -= [
+      "openpgp_symmetric_encryption.cc",
+      "openpgp_symmetric_encryption.h",
+    ]
+  }
+  if (!is_mac) {
+    sources -= [
+      "cssm_init.cc",
+      "cssm_init.h",
+      "mac_security_services_lock.cc",
+      "mac_security_services_lock.h",
+    ]
+  }
+  if (!is_win) {
+    sources -= [
+      "capi_util.cc",
+      "capi_util.h",
+    ]
+  }
+
+  if (use_openssl) {
+    sources -= [
+      "ec_private_key_nss.cc",
+      "ec_signature_creator_nss.cc",
+      "encryptor_nss.cc",
+      "hmac_nss.cc",
+      "nss_util.cc",
+      "nss_util.h",
+      "openpgp_symmetric_encryption.cc",
+      "rsa_private_key_nss.cc",
+      "secure_hash_default.cc",
+      "signature_creator_nss.cc",
+      "signature_verifier_nss.cc",
+      "symmetric_key_nss.cc",
+      "third_party/nss/chromium-blapi.h",
+      "third_party/nss/chromium-blapit.h",
+      "third_party/nss/chromium-nss.h",
+      "third_party/nss/chromium-sha256.h",
+      "third_party/nss/pk11akey.cc",
+      "third_party/nss/rsawrapr.c",
+      "third_party/nss/secsign.cc",
+      "third_party/nss/sha512.cc",
+    ]
+  } else {
+    sources -= [
+      "ec_private_key_openssl.cc",
+      "ec_signature_creator_openssl.cc",
+      "encryptor_openssl.cc",
+      "hmac_openssl.cc",
+      "openssl_util.cc",
+      "openssl_util.h",
+      "rsa_private_key_openssl.cc",
+      "secure_hash_openssl.cc",
+      "signature_creator_openssl.cc",
+      "signature_verifier_openssl.cc",
+      "symmetric_key_openssl.cc",
+    ]
+  }
+
+  defines = [ "CRYPTO_IMPLEMENTATION" ]
+}
+
+# A minimal crypto subset for core features that small standalone targets can
+# use to reduce code size.
+static_library("crypto_minimal") {
+  sources = [
+    "hmac.cc",
+    "hmac.h",
+    "hmac_win.cc",
+    "secure_util.cc",
+    "secure_util.h",
+    "symmetric_key.h",
+    "symmetric_key_win.cc",
+    "third_party/nss/chromium-sha256.h",
+    "third_party/nss/sha512.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//base/third_party/dynamic_annotations",
+  ]
+
+  defines = [ "CRYPTO_IMPLEMENTATION" ]
+}
+
+test("crypto_unittests") {
+  sources = [
+    # Infrastructure files.
+    "run_all_unittests.cc",
+
+    # Tests.
+    "curve25519_unittest.cc",
+    "ec_private_key_unittest.cc",
+    "ec_signature_creator_unittest.cc",
+    "encryptor_unittest.cc",
+    "ghash_unittest.cc",
+    "hkdf_unittest.cc",
+    "hmac_unittest.cc",
+    "nss_util_unittest.cc",
+    "p224_unittest.cc",
+    "p224_spake_unittest.cc",
+    "random_unittest.cc",
+    "rsa_private_key_unittest.cc",
+    "rsa_private_key_nss_unittest.cc",
+    "secure_hash_unittest.cc",
+    "sha2_unittest.cc",
+    "signature_creator_unittest.cc",
+    "signature_verifier_unittest.cc",
+    "symmetric_key_unittest.cc",
+    "openpgp_symmetric_encryption_unittest.cc",
+  ]
+
+  if (use_openssl) {
+    sources -= [
+      "nss_util_unittest.cc",
+      "openpgp_symmetric_encryption_unittest.cc",
+      "rsa_private_key_nss_unittest,cc",
+    ]
+  }
+
+  deps = [
+    ":crypto",
+    "//base",
+    "//base/test:test_support_base",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  if (is_mac) {
+    deps += "//third_party/nss:nspr"
+  }
+}
diff --git a/tools/gn/secondary/crypto/ssl/BUILD.gn b/tools/gn/secondary/crypto/ssl/BUILD.gn
new file mode 100644
index 0000000..dc8f0f2
--- /dev/null
+++ b/tools/gn/secondary/crypto/ssl/BUILD.gn
@@ -0,0 +1,27 @@
+# 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("flags.gni")
+
+config("ssl_preprocessor_flags") {
+  if (use_openssl) {
+    defines = [ "USE_OPENSSL" ]
+  } else if (use_nss) {
+    defines = [ "USE_NSS" ]
+  } else {
+    assert(false)  # Either OpenSSL or NSS should be defined.
+  }
+}
+
+# This meta-target will include the SSL library according to the build flags.
+group("metassl") {
+  direct_dependent_configs = [ ":ssl_preprocessor_flags" ]
+
+  deps = []
+  if (is_linux) {
+    # TODO(brettw) figure this out.
+    deps += [ "//net/third_party/nss/ssl:crssl" ]
+  }
+  forward_dependent_configs_from = deps
+}
diff --git a/tools/gn/secondary/crypto/ssl/flags.gni b/tools/gn/secondary/crypto/ssl/flags.gni
new file mode 100644
index 0000000..598ad71
--- /dev/null
+++ b/tools/gn/secondary/crypto/ssl/flags.gni
@@ -0,0 +1,18 @@
+# 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 file declares build flags for 
+
+declare_args() {
+  use_openssl = false
+
+  # Use the built-in system SSL library rather than our tree's libnss/OpenSSL.
+  use_system_ssl = false
+}
+
+if (is_linux && !use_openssl) {
+  use_nss = true
+} else {
+  use_nss = false
+}
diff --git a/tools/gn/secondary/ipc/BUILD.gn b/tools/gn/secondary/ipc/BUILD.gn
index 5e55ee9..a0b5f2b 100644
--- a/tools/gn/secondary/ipc/BUILD.gn
+++ b/tools/gn/secondary/ipc/BUILD.gn
@@ -1,168 +1,168 @@
-# 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.

-

-component("ipc") {

-  sources = [

-    "file_descriptor_set_posix.cc",

-    "file_descriptor_set_posix.h",

-    "ipc_channel.cc",

-    "ipc_channel.h",

-    "ipc_channel_factory.cc",

-    "ipc_channel_factory.h",

-    "ipc_channel_handle.h",

-    "ipc_channel_nacl.cc",

-    "ipc_channel_nacl.h",

-    "ipc_channel_posix.cc",

-    "ipc_channel_posix.h",

-    "ipc_channel_proxy.cc",

-    "ipc_channel_proxy.h",

-    "ipc_channel_reader.cc",

-    "ipc_channel_reader.h",

-    "ipc_channel_win.cc",

-    "ipc_channel_win.h",

-    "ipc_descriptors.h",

-    "ipc_export.h",

-    "ipc_forwarding_message_filter.cc",

-    "ipc_forwarding_message_filter.h",

-    "ipc_listener.h",

-    "ipc_logging.cc",

-    "ipc_logging.h",

-    "ipc_message.cc",

-    "ipc_message.h",

-    "ipc_message_macros.h",

-    "ipc_message_start.h",

-    "ipc_message_utils.cc",

-    "ipc_message_utils.h",

-    "ipc_param_traits.h",

-    "ipc_platform_file.cc",

-    "ipc_platform_file.h",

-    "ipc_sender.h",

-    "ipc_switches.cc",

-    "ipc_switches.h",

-    "ipc_sync_channel.cc",

-    "ipc_sync_channel.h",

-    "ipc_sync_message.cc",

-    "ipc_sync_message.h",

-    "ipc_sync_message_filter.cc",

-    "ipc_sync_message_filter.h",

-    "param_traits_log_macros.h",

-    "param_traits_macros.h",

-    "param_traits_read_macros.h",

-    "param_traits_write_macros.h",

-    "struct_constructor_macros.h",

-    "struct_destructor_macros.h",

-    "unix_domain_socket_util.cc",

-    "unix_domain_socket_util.h",

-  ]

-

-  #if (!is_untrusted_nacl) {

-    sources -= [

-      "ipc_channel_nacl.cc",

-      "ipc_channel_nacl.h",

-    ]

-

-  if (is_win || is_ios) {

-    sources -= [

-      "ipc_channel_factory.cc",

-      "unix_domain_socket_util.cc",

-    ]

-  }

-

-  defines = [ "IPC_IMPLEMENTATION" ]

-

-  deps = [

-    "//base",

-    # TODO(viettrungluu): Needed for base/lazy_instance.h, which is suspect.

-    "//base/third_party/dynamic_annotations",

-  ]

-}

-

-test("ipc_tests") {

-  sources = [

-    "file_descriptor_set_posix_unittest.cc",

-    "ipc_channel_posix_unittest.cc",

-    "ipc_channel_unittest.cc",

-    "ipc_fuzzing_tests.cc",

-    "ipc_message_unittest.cc",

-    "ipc_message_utils_unittest.cc",

-    "ipc_send_fds_test.cc",

-    "ipc_sync_channel_unittest.cc",

-    "ipc_sync_message_unittest.cc",

-    "ipc_sync_message_unittest.h",

-    "ipc_test_base.cc",

-    "ipc_test_base.h",

-    "sync_socket_unittest.cc",

-    "unix_domain_socket_util_unittest.cc",

-  ]

-

-  #if (toolkit_uses_gtk) {

-  #  deps += "/build/linux/system:gtk"

-  #}

-  if (is_win || is_ios) {

-    sources -= "unix_domain_socket_util_unittest.cc"

-  }

-  #if (is_android && gtest_target_type == "shared_library") {

-  #  deps += "/testing/android/native_test.gyp:native_testNative_code"

-  #}

-  #if (is_posix && !is_mac && !is_android) {

-  #  if (linux_use_tcmalloc) {

-  #    deps += "/base/allocator"

-  #  }

-  #}

-

-  deps = [

-    ":ipc",

-    ":test_support_ipc",

-    "//base",

-    "//base:base_i18n",

-    "//base:run_all_unittests",

-    "//base:test_support_base",

-    "//testing:gtest",

-  ]

-}

-

-test("ipc_perftests") {

-  sources = [

-    "ipc_perftests.cc",

-    "ipc_test_base.cc",

-    "ipc_test_base.h",

-  ]

-

-  #if (toolkit_uses_gtk) {

-  #  deps += "/build/linux/system:gtk"

-  #}

-  #if (is_android && gtest_target_type == "shared_library") {

-  #  deps += "/testing/android/native_test.gyp:native_testNative_code"

-  #}

-  #if (is_posix && !is_mac && !is_android) {

-  #  if (linux_use_tcmalloc) {

-  #    deps += "/base/allocator"

-  #  }

-  #}

-

-  deps = [

-    ":ipc",

-    ":test_support_ipc",

-    "//base",

-    "//base:base_i18n",

-    "//base:test_support_base",

-    "//base:test_support_perf",

-    "//testing:gtest",

-  ]

-}

-

-static_library("test_support_ipc") {

-  sources = [

-    "ipc_multiprocess_test.cc",

-    "ipc_multiprocess_test.h",

-    "ipc_test_sink.cc",

-    "ipc_test_sink.h",

-  ]

-  deps = [

-    ":ipc",

-    "//base",

-    "//testing:gtest",

-  ]

-}

-

+# 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.
+
+component("ipc") {
+  sources = [
+    "file_descriptor_set_posix.cc",
+    "file_descriptor_set_posix.h",
+    "ipc_channel.cc",
+    "ipc_channel.h",
+    "ipc_channel_factory.cc",
+    "ipc_channel_factory.h",
+    "ipc_channel_handle.h",
+    "ipc_channel_nacl.cc",
+    "ipc_channel_nacl.h",
+    "ipc_channel_posix.cc",
+    "ipc_channel_posix.h",
+    "ipc_channel_proxy.cc",
+    "ipc_channel_proxy.h",
+    "ipc_channel_reader.cc",
+    "ipc_channel_reader.h",
+    "ipc_channel_win.cc",
+    "ipc_channel_win.h",
+    "ipc_descriptors.h",
+    "ipc_export.h",
+    "ipc_forwarding_message_filter.cc",
+    "ipc_forwarding_message_filter.h",
+    "ipc_listener.h",
+    "ipc_logging.cc",
+    "ipc_logging.h",
+    "ipc_message.cc",
+    "ipc_message.h",
+    "ipc_message_macros.h",
+    "ipc_message_start.h",
+    "ipc_message_utils.cc",
+    "ipc_message_utils.h",
+    "ipc_param_traits.h",
+    "ipc_platform_file.cc",
+    "ipc_platform_file.h",
+    "ipc_sender.h",
+    "ipc_switches.cc",
+    "ipc_switches.h",
+    "ipc_sync_channel.cc",
+    "ipc_sync_channel.h",
+    "ipc_sync_message.cc",
+    "ipc_sync_message.h",
+    "ipc_sync_message_filter.cc",
+    "ipc_sync_message_filter.h",
+    "param_traits_log_macros.h",
+    "param_traits_macros.h",
+    "param_traits_read_macros.h",
+    "param_traits_write_macros.h",
+    "struct_constructor_macros.h",
+    "struct_destructor_macros.h",
+    "unix_domain_socket_util.cc",
+    "unix_domain_socket_util.h",
+  ]
+
+  #if (!is_untrusted_nacl) {
+    sources -= [
+      "ipc_channel_nacl.cc",
+      "ipc_channel_nacl.h",
+    ]
+
+  if (is_win || is_ios) {
+    sources -= [
+      "ipc_channel_factory.cc",
+      "unix_domain_socket_util.cc",
+    ]
+  }
+
+  defines = [ "IPC_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+    # TODO(viettrungluu): Needed for base/lazy_instance.h, which is suspect.
+    "//base/third_party/dynamic_annotations",
+  ]
+}
+
+test("ipc_tests") {
+  sources = [
+    "file_descriptor_set_posix_unittest.cc",
+    "ipc_channel_posix_unittest.cc",
+    "ipc_channel_unittest.cc",
+    "ipc_fuzzing_tests.cc",
+    "ipc_message_unittest.cc",
+    "ipc_message_utils_unittest.cc",
+    "ipc_send_fds_test.cc",
+    "ipc_sync_channel_unittest.cc",
+    "ipc_sync_message_unittest.cc",
+    "ipc_sync_message_unittest.h",
+    "ipc_test_base.cc",
+    "ipc_test_base.h",
+    "sync_socket_unittest.cc",
+    "unix_domain_socket_util_unittest.cc",
+  ]
+
+  #if (toolkit_uses_gtk) {
+  #  deps += "/build/linux/system:gtk"
+  #}
+  if (is_win || is_ios) {
+    sources -= "unix_domain_socket_util_unittest.cc"
+  }
+  #if (is_android && gtest_target_type == "shared_library") {
+  #  deps += "/testing/android/native_test.gyp:native_testNative_code"
+  #}
+  #if (is_posix && !is_mac && !is_android) {
+  #  if (linux_use_tcmalloc) {
+  #    deps += "/base/allocator"
+  #  }
+  #}
+
+  deps = [
+    ":ipc",
+    ":test_support_ipc",
+    "//base",
+    "//base:base_i18n",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support_base",
+    "//testing/gtest",
+  ]
+}
+
+test("ipc_perftests") {
+  sources = [
+    "ipc_perftests.cc",
+    "ipc_test_base.cc",
+    "ipc_test_base.h",
+  ]
+
+  #if (toolkit_uses_gtk) {
+  #  deps += "/build/linux/system:gtk"
+  #}
+  #if (is_android && gtest_target_type == "shared_library") {
+  #  deps += "/testing/android/native_test.gyp:native_testNative_code"
+  #}
+  #if (is_posix && !is_mac && !is_android) {
+  #  if (linux_use_tcmalloc) {
+  #    deps += "/base/allocator"
+  #  }
+  #}
+
+  deps = [
+    ":ipc",
+    ":test_support_ipc",
+    "//base",
+    "//base:base_i18n",
+    "//base/test:test_support_base",
+    "//base/test:test_support_perf",
+    "//testing/gtest",
+  ]
+}
+
+static_library("test_support_ipc") {
+  sources = [
+    "ipc_multiprocess_test.cc",
+    "ipc_multiprocess_test.h",
+    "ipc_test_sink.cc",
+    "ipc_test_sink.h",
+  ]
+  deps = [
+    ":ipc",
+    "//base",
+    "//testing/gtest",
+  ]
+}
+
diff --git a/tools/gn/secondary/net/BUILD.gn b/tools/gn/secondary/net/BUILD.gn
new file mode 100644
index 0000000..cf70629
--- /dev/null
+++ b/tools/gn/secondary/net/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.
+
+import("//tools/grit/grit_rule.gni")
+
+component("net") {
+  deps = [
+    ":net_resources",
+    "//base",
+    "//base:base_i18n",
+    "//base/third_party/dynamic_annotations",
+    "//crypto",
+    "//sdch",
+    "//third_party/icu:icui18n",
+    "//third_party/icu:icuuc",
+    "//third_party/zlib",
+    "//url:url_lib",
+  ]
+}
+
+
+grit("net_resources") {
+  source = "base/net_resources.grd"
+}
diff --git a/tools/gn/secondary/net/third_party/nss/BUILD.gn b/tools/gn/secondary/net/third_party/nss/BUILD.gn
new file mode 100644
index 0000000..93adecb
--- /dev/null
+++ b/tools/gn/secondary/net/third_party/nss/BUILD.gn
@@ -0,0 +1,12 @@
+# 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.
+
+if (is_linux) {
+  pkg_script = "//build/config/linux/pkg-config.py"
+
+  config("nss_linux_config") {
+    cflags = exec_script(pkg_script, [ "--cflags", "nss" ], "list lines")
+    ldflags = exec_script(pkg_script, [ "--libs", "nss" ], "list lines")
+  }
+}
diff --git a/tools/gn/secondary/net/third_party/nss/ssl/BUILD.gn b/tools/gn/secondary/net/third_party/nss/ssl/BUILD.gn
new file mode 100644
index 0000000..d5658c6
--- /dev/null
+++ b/tools/gn/secondary/net/third_party/nss/ssl/BUILD.gn
@@ -0,0 +1,82 @@
+# 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.
+
+# Not named "ssl" so the lib doesn't conflict with OpenSSL's libssl
+component("crssl") {
+  sources = [
+    "authcert.c",
+    "cmpcert.c",
+    "derive.c",
+    "dtlscon.c",
+    #"os2_err.c",
+    #"os2_err.h",
+    "preenc.h",
+    "prelib.c",
+    "ssl.h",
+    "ssl3con.c",
+    "ssl3ecc.c",
+    "ssl3ext.c",
+    "ssl3gthr.c",
+    "ssl3prot.h",
+    "sslauth.c",
+    "sslcon.c",
+    "ssldef.c",
+    "sslenum.c",
+    "sslerr.c",
+    "sslerr.h",
+    "SSLerrs.h",
+    "sslerrstrs.c",
+    "sslgathr.c",
+    "sslimpl.h",
+    "sslinfo.c",
+    "sslinit.c",
+    "sslmutex.c",
+    "sslmutex.h",
+    "sslnonce.c",
+    "sslplatf.c",
+    "sslproto.h",
+    "sslreveal.c",
+    "sslsecur.c",
+    "sslsnce.c",
+    "sslsock.c",
+    "sslt.h",
+    "ssltrace.c",
+    "sslver.c",
+    "unix_err.c",
+    "unix_err.h",
+    "win32err.c",
+    "win32err.h",
+    "bodge/secitem_array.c",
+  ]
+
+  defines = [
+    "NO_PKCS11_BYPASS",
+    "NSS_ENABLE_ECC",
+    "USE_UTIL_DIRECTLY",
+  ]
+
+  configs -= "//build/config/compiler:chromium_code"
+  configs += "//build/config/compiler:no_chromium_code"
+
+  if (is_win) {
+    sources -= [
+      "unix_err.c",
+      "unix_err.h",
+    ]
+  } else {
+    sources -= [
+      "win32err.c",
+      "win32err.h",
+    ]
+  }
+
+  if (is_linux) {
+    includes = [ "bodge" ]
+    direct_dependent_configs = [ "//net/third_party/nss:nss_linux_config" ]
+  }
+  if (is_mac) {
+    sources -= "bodge/secitem_array.c"
+  }
+
+}
diff --git a/tools/gn/secondary/sdch/BUILD.gn b/tools/gn/secondary/sdch/BUILD.gn
new file mode 100644
index 0000000..2c5849c
--- /dev/null
+++ b/tools/gn/secondary/sdch/BUILD.gn
@@ -0,0 +1,55 @@
+# 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.
+
+config("sdch_config") {
+  includes = [ "open-vcdiff/src" ]
+}
+
+static_library("sdch") {
+  sources = [
+    "open-vcdiff/src/addrcache.cc",
+    "open-vcdiff/src/blockhash.cc",
+    "open-vcdiff/src/blockhash.h",
+    "open-vcdiff/src/checksum.h",
+    "open-vcdiff/src/codetable.cc",
+    "open-vcdiff/src/codetable.h",
+    "open-vcdiff/src/compile_assert.h",
+    "open-vcdiff/src/decodetable.cc",
+    "open-vcdiff/src/decodetable.h",
+    "open-vcdiff/src/encodetable.cc",
+    "open-vcdiff/src/encodetable.h",
+    "open-vcdiff/src/google/output_string.h",
+    "open-vcdiff/src/google/vcdecoder.h",
+    "open-vcdiff/src/headerparser.cc",
+    "open-vcdiff/src/headerparser.h",
+    "open-vcdiff/src/instruction_map.cc",
+    "open-vcdiff/src/instruction_map.h",
+    "open-vcdiff/src/logging.cc",
+    "open-vcdiff/src/logging.h",
+    "open-vcdiff/src/rolling_hash.h",
+    "open-vcdiff/src/testing.h",
+    "open-vcdiff/src/varint_bigendian.cc",
+    "open-vcdiff/src/varint_bigendian.h",
+    "open-vcdiff/src/vcdecoder.cc",
+    "open-vcdiff/src/vcdiff_defs.h",
+    "open-vcdiff/src/vcdiffengine.cc",
+    "open-vcdiff/src/vcdiffengine.h",
+    "open-vcdiff/vsprojects/config.h",
+    "open-vcdiff/vsprojects/stdint.h",
+  ]
+
+  direct_dependent_configs = [ ":sdch_config" ]
+
+  if (is_linux || is_android) {
+    includes = [ "linux" ]
+  } else if (is_ios) {
+    includes = [ "ios" ]
+  } else if (is_mac) {
+    includes = [ "mac" ]
+  } else if (is_win) {
+    includes = [ "win" ]
+  }
+
+  deps = [ "//third_party/zlib" ]
+}
diff --git a/tools/gn/secondary/testing/BUILD.gn b/tools/gn/secondary/testing/BUILD.gn
deleted file mode 100644
index b54ceba..0000000
--- a/tools/gn/secondary/testing/BUILD.gn
+++ /dev/null
@@ -1,44 +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.

-

-static_library("gtest") {

-  sources = [

-    "gtest/include/gtest/gtest-death-test.h",

-    "gtest/include/gtest/gtest-message.h",

-    "gtest/include/gtest/gtest-param-test.h",

-    "gtest/include/gtest/gtest-printers.h",

-    "gtest/include/gtest/gtest-spi.h",

-    "gtest/include/gtest/gtest-test-part.h",

-    "gtest/include/gtest/gtest-typed-test.h",

-    "gtest/include/gtest/gtest.h",

-    "gtest/include/gtest/gtest_pred_impl.h",

-    "gtest/include/gtest/internal/gtest-death-test-internal.h",

-    "gtest/include/gtest/internal/gtest-filepath.h",

-    "gtest/include/gtest/internal/gtest-internal.h",

-    "gtest/include/gtest/internal/gtest-linked_ptr.h",

-    "gtest/include/gtest/internal/gtest-param-util-generated.h",

-    "gtest/include/gtest/internal/gtest-param-util.h",

-    "gtest/include/gtest/internal/gtest-port.h",

-    "gtest/include/gtest/internal/gtest-string.h",

-    "gtest/include/gtest/internal/gtest-tuple.h",

-    "gtest/include/gtest/internal/gtest-type-util.h",

-    #"gtest/src/gtest-all.cc",  # Not needed by our build.

-    "gtest/src/gtest-death-test.cc",

-    "gtest/src/gtest-filepath.cc",

-    "gtest/src/gtest-internal-inl.h",

-    "gtest/src/gtest-port.cc",

-    "gtest/src/gtest-printers.cc",

-    "gtest/src/gtest-test-part.cc",

-    "gtest/src/gtest-typed-test.cc",

-    "gtest/src/gtest.cc",

-    "multiprocess_func_list.cc",

-    "multiprocess_func_list.h",

-    "platform_test.h",

-  ]

-

-}

-

-static_library("gmock") {

-

-}

diff --git a/tools/gn/secondary/testing/gmock/BUILD.gn b/tools/gn/secondary/testing/gmock/BUILD.gn
new file mode 100644
index 0000000..532d2a4
--- /dev/null
+++ b/tools/gn/secondary/testing/gmock/BUILD.gn
@@ -0,0 +1,46 @@
+# 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.
+
+config("gmock_config") {
+  # Gmock headers need to be able to find themselves.
+  includes = [ "include" ]
+}
+
+static_library("gmock") {
+  sources = [
+    # Sources based on files in r173 of gmock.
+    "include/gmock/gmock-actions.h",
+    "include/gmock/gmock-cardinalities.h",
+    "include/gmock/gmock-generated-actions.h",
+    "include/gmock/gmock-generated-function-mockers.h",
+    "include/gmock/gmock-generated-matchers.h",
+    "include/gmock/gmock-generated-nice-strict.h",
+    "include/gmock/gmock-matchers.h",
+    "include/gmock/gmock-spec-builders.h",
+    "include/gmock/gmock.h",
+    "include/gmock/internal/gmock-generated-internal-utils.h",
+    "include/gmock/internal/gmock-internal-utils.h",
+    "include/gmock/internal/gmock-port.h",
+    #"src/gmock-all.cc",  # Not needed by our build.
+    "src/gmock-cardinalities.cc",
+    "src/gmock-internal-utils.cc",
+    "src/gmock-matchers.cc",
+    "src/gmock-spec-builders.cc",
+    "src/gmock.cc",
+    "../gmock_mutant.h",  # gMock helpers
+  ]
+
+  # This project includes some stuff form gtest's guts.
+  includes = [ "../gtest/include" ]
+
+  direct_dependent_configs = [
+    ":gmock_config",
+    "//testing/gtest:gtest_config",
+  ]
+}
+
+static_library("gmock_main") {
+  sources = [ "src/gmock_main.cc" ]
+  deps = [ ":gmock" ]
+}
diff --git a/tools/gn/secondary/testing/gtest/BUILD.gn b/tools/gn/secondary/testing/gtest/BUILD.gn
new file mode 100644
index 0000000..05bedda
--- /dev/null
+++ b/tools/gn/secondary/testing/gtest/BUILD.gn
@@ -0,0 +1,47 @@
+# 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.
+
+config("gtest_config") {
+  defines = [ "UNIT_TEST" ]
+  includes = [ "include" ]  # Gtest headers need to be able to find themselves.
+}
+
+static_library("gtest") {
+  sources = [
+    "include/gtest/gtest-death-test.h",
+    "include/gtest/gtest-message.h",
+    "include/gtest/gtest-param-test.h",
+    "include/gtest/gtest-printers.h",
+    "include/gtest/gtest-spi.h",
+    "include/gtest/gtest-test-part.h",
+    "include/gtest/gtest-typed-test.h",
+    "include/gtest/gtest.h",
+    "include/gtest/gtest_pred_impl.h",
+    "include/gtest/internal/gtest-death-test-internal.h",
+    "include/gtest/internal/gtest-filepath.h",
+    "include/gtest/internal/gtest-internal.h",
+    "include/gtest/internal/gtest-linked_ptr.h",
+    "include/gtest/internal/gtest-param-util-generated.h",
+    "include/gtest/internal/gtest-param-util.h",
+    "include/gtest/internal/gtest-port.h",
+    "include/gtest/internal/gtest-string.h",
+    "include/gtest/internal/gtest-tuple.h",
+    "include/gtest/internal/gtest-type-util.h",
+    #"src/gtest-all.cc",  # Not needed by our build.
+    "src/gtest-death-test.cc",
+    "src/gtest-filepath.cc",
+    "src/gtest-internal-inl.h",
+    "src/gtest-port.cc",
+    "src/gtest-printers.cc",
+    "src/gtest-test-part.cc",
+    "src/gtest-typed-test.cc",
+    "src/gtest.cc",
+    "../multiprocess_func_list.cc",
+    "../multiprocess_func_list.h",
+    "../platform_test.h",
+  ]
+
+  includes = [ "." ]
+  direct_dependent_configs = [ ":gtest_config" ]
+}
diff --git a/tools/gn/secondary/third_party/icu/BUILD.gn b/tools/gn/secondary/third_party/icu/BUILD.gn
new file mode 100644
index 0000000..f78d981
--- /dev/null
+++ b/tools/gn/secondary/third_party/icu/BUILD.gn
@@ -0,0 +1,421 @@
+# 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.
+
+# Shared config used by ICU and all dependents.
+config("icu_config") {
+  defines = [
+    "U_USING_ICU_NAMESPACE=0",
+  ]
+  includes = [
+    "source/common",
+    "source/i18n",
+  ]
+}
+
+# Config used only by ICU code.
+config("icu_code") {
+  if (component_mode == "static_library") {
+    defines = [ "U_STATIC_IMPLEMENTATION" ]
+  }
+
+  if (is_win) {
+    # Disable some compiler warnings.
+    cflags = [
+      "/wd4005",  # Macro redefinition.
+      "/wd4068",  # Unknown pragmas.
+      "/wd4267",  # Conversion from size_t on 64-bits.
+      "/wd4996",  # Deprecated functions.
+    ]
+  } else if (is_linux) {
+    cflags = [
+      # Since ICU wants to internally use its own deprecated APIs, don't
+      # complain about it.
+      "-Wno-deprecated-declarations",
+      "-Wno-unused-function",
+    ]
+  } else if (is_clang) {
+    cflags = [
+      "-Wno-deprecated-declarations",
+      "-Wno-logical-op-parentheses",
+      "-Wno-tautological-compare",
+      "-Wno-switch",
+    ]
+  }
+}
+
+component("icui18n") {
+  sources = [
+    "source/i18n/anytrans.cpp",
+    "source/i18n/astro.cpp",
+    "source/i18n/basictz.cpp",
+    "source/i18n/bms.cpp",
+    "source/i18n/bmsearch.cpp",
+    "source/i18n/bocsu.c",
+    "source/i18n/brktrans.cpp",
+    "source/i18n/buddhcal.cpp",
+    "source/i18n/calendar.cpp",
+    "source/i18n/casetrn.cpp",
+    "source/i18n/cecal.cpp",
+    "source/i18n/chnsecal.cpp",
+    "source/i18n/choicfmt.cpp",
+    "source/i18n/coleitr.cpp",
+    "source/i18n/coll.cpp",
+    "source/i18n/colldata.cpp",
+    "source/i18n/coptccal.cpp",
+    "source/i18n/cpdtrans.cpp",
+    "source/i18n/csdetect.cpp",
+    "source/i18n/csmatch.cpp",
+    "source/i18n/csr2022.cpp",
+    "source/i18n/csrecog.cpp",
+    "source/i18n/csrmbcs.cpp",
+    "source/i18n/csrsbcs.cpp",
+    "source/i18n/csrucode.cpp",
+    "source/i18n/csrutf8.cpp",
+    "source/i18n/curramt.cpp",
+    "source/i18n/currfmt.cpp",
+    "source/i18n/currpinf.cpp",
+    "source/i18n/currunit.cpp",
+    "source/i18n/datefmt.cpp",
+    "source/i18n/dcfmtsym.cpp",
+    "source/i18n/decContext.c",
+    "source/i18n/decNumber.c",
+    "source/i18n/decimfmt.cpp",
+    "source/i18n/digitlst.cpp",
+    "source/i18n/dtfmtsym.cpp",
+    "source/i18n/dtitvfmt.cpp",
+    "source/i18n/dtitvinf.cpp",
+    "source/i18n/dtptngen.cpp",
+    "source/i18n/dtrule.cpp",
+    "source/i18n/esctrn.cpp",
+    "source/i18n/ethpccal.cpp",
+    "source/i18n/fmtable.cpp",
+    "source/i18n/fmtable_cnv.cpp",
+    "source/i18n/format.cpp",
+    "source/i18n/fphdlimp.cpp",
+    "source/i18n/fpositer.cpp",
+    "source/i18n/funcrepl.cpp",
+    "source/i18n/gregocal.cpp",
+    "source/i18n/gregoimp.cpp",
+    "source/i18n/hebrwcal.cpp",
+    "source/i18n/indiancal.cpp",
+    "source/i18n/inputext.cpp",
+    "source/i18n/islamcal.cpp",
+    "source/i18n/japancal.cpp",
+    "source/i18n/locdspnm.cpp",
+    "source/i18n/measfmt.cpp",
+    "source/i18n/measure.cpp",
+    "source/i18n/msgfmt.cpp",
+    "source/i18n/name2uni.cpp",
+    "source/i18n/nfrs.cpp",
+    "source/i18n/nfrule.cpp",
+    "source/i18n/nfsubs.cpp",
+    "source/i18n/nortrans.cpp",
+    "source/i18n/nultrans.cpp",
+    "source/i18n/numfmt.cpp",
+    "source/i18n/numsys.cpp",
+    "source/i18n/olsontz.cpp",
+    "source/i18n/persncal.cpp",
+    "source/i18n/plurfmt.cpp",
+    "source/i18n/plurrule.cpp",
+    "source/i18n/quant.cpp",
+    "source/i18n/rbnf.cpp",
+    "source/i18n/rbt.cpp",
+    "source/i18n/rbt_data.cpp",
+    "source/i18n/rbt_pars.cpp",
+    "source/i18n/rbt_rule.cpp",
+    "source/i18n/rbt_set.cpp",
+    "source/i18n/rbtz.cpp",
+    "source/i18n/regexcmp.cpp",
+    "source/i18n/regexst.cpp",
+    "source/i18n/regextxt.cpp",
+    "source/i18n/reldtfmt.cpp",
+    "source/i18n/rematch.cpp",
+    "source/i18n/remtrans.cpp",
+    "source/i18n/repattrn.cpp",
+    "source/i18n/search.cpp",
+    "source/i18n/selfmt.cpp",
+    "source/i18n/simpletz.cpp",
+    "source/i18n/smpdtfmt.cpp",
+    "source/i18n/sortkey.cpp",
+    "source/i18n/strmatch.cpp",
+    "source/i18n/strrepl.cpp",
+    "source/i18n/stsearch.cpp",
+    "source/i18n/taiwncal.cpp",
+    "source/i18n/tblcoll.cpp",
+    "source/i18n/timezone.cpp",
+    "source/i18n/titletrn.cpp",
+    "source/i18n/tmunit.cpp",
+    "source/i18n/tmutamt.cpp",
+    "source/i18n/tmutfmt.cpp",
+    "source/i18n/tolowtrn.cpp",
+    "source/i18n/toupptrn.cpp",
+    "source/i18n/translit.cpp",
+    "source/i18n/transreg.cpp",
+    "source/i18n/tridpars.cpp",
+    "source/i18n/tzrule.cpp",
+    "source/i18n/tztrans.cpp",
+    "source/i18n/ucal.cpp",
+    "source/i18n/ucln_in.c",
+    "source/i18n/ucol.cpp",
+    "source/i18n/ucol_bld.cpp",
+    "source/i18n/ucol_cnt.cpp",
+    "source/i18n/ucol_elm.cpp",
+    "source/i18n/ucol_res.cpp",
+    "source/i18n/ucol_sit.cpp",
+    "source/i18n/ucol_tok.cpp",
+    "source/i18n/ucol_wgt.cpp",
+    "source/i18n/ucoleitr.cpp",
+    "source/i18n/ucsdet.cpp",
+    "source/i18n/ucurr.cpp",
+    "source/i18n/udat.cpp",
+    "source/i18n/udatpg.cpp",
+    "source/i18n/ulocdata.c",
+    "source/i18n/umsg.cpp",
+    "source/i18n/unesctrn.cpp",
+    "source/i18n/uni2name.cpp",
+    "source/i18n/unum.cpp",
+    "source/i18n/uregex.cpp",
+    "source/i18n/uregexc.cpp",
+    "source/i18n/usearch.cpp",
+    "source/i18n/uspoof.cpp",
+    "source/i18n/uspoof_build.cpp",
+    "source/i18n/uspoof_conf.cpp",
+    "source/i18n/uspoof_impl.cpp",
+    "source/i18n/uspoof_wsconf.cpp",
+    "source/i18n/utmscale.c",
+    "source/i18n/utrans.cpp",
+    "source/i18n/vtzone.cpp",
+    "source/i18n/vzone.cpp",
+    "source/i18n/windtfmt.cpp",
+    "source/i18n/winnmfmt.cpp",
+    "source/i18n/wintzimpl.cpp",
+    "source/i18n/zonemeta.cpp",
+    "source/i18n/zrule.cpp",
+    "source/i18n/zstrfmt.cpp",
+    "source/i18n/ztrans.cpp",
+  ]
+  defines = [
+    "U_I18N_IMPLEMENTATION",
+  ]
+  deps = [
+    ":icuuc",
+  ]
+
+  # ICU uses RTTI, replace the default "no rtti" config.
+  configs -= [
+    "//build/config/compiler:no_rtti",  # ICU uses RTTI.
+    "//build/config/compiler:chromium_code",
+  ]
+  configs += [
+    "//build/config/compiler:rtti",
+    "//build/config/compiler:no_chromium_code",
+  ]
+
+  configs += [ ":icu_code" ]
+  direct_dependent_configs = [ ":icu_config" ]
+}
+
+component("icuuc") {
+  sources = [
+    "source/common/bmpset.cpp",
+    "source/common/brkeng.cpp",
+    "source/common/brkiter.cpp",
+    "source/common/bytestream.cpp",
+    "source/common/caniter.cpp",
+    "source/common/chariter.cpp",
+    "source/common/charstr.cpp",
+    "source/common/cmemory.c",
+    "source/common/cstring.c",
+    "source/common/cwchar.c",
+    "source/common/dictbe.cpp",
+    "source/common/dtintrv.cpp",
+    "source/common/errorcode.cpp",
+    "source/common/filterednormalizer2.cpp",
+    "source/common/icudataver.c",
+    "source/common/icuplug.c",
+    "source/common/locavailable.cpp",
+    "source/common/locbased.cpp",
+    "source/common/locdispnames.cpp",
+    "source/common/locid.cpp",
+    "source/common/loclikely.cpp",
+    "source/common/locmap.c",
+    "source/common/locresdata.cpp",
+    "source/common/locutil.cpp",
+    "source/common/mutex.cpp",
+    "source/common/normalizer2.cpp",
+    "source/common/normalizer2impl.cpp",
+    "source/common/normlzr.cpp",
+    "source/common/parsepos.cpp",
+    "source/common/propname.cpp",
+    "source/common/propsvec.c",
+    "source/common/punycode.c",
+    "source/common/putil.c",
+    "source/common/rbbi.cpp",
+    "source/common/rbbidata.cpp",
+    "source/common/rbbinode.cpp",
+    "source/common/rbbirb.cpp",
+    "source/common/rbbiscan.cpp",
+    "source/common/rbbisetb.cpp",
+    "source/common/rbbistbl.cpp",
+    "source/common/rbbitblb.cpp",
+    "source/common/resbund.cpp",
+    "source/common/resbund_cnv.cpp",
+    "source/common/ruleiter.cpp",
+    "source/common/schriter.cpp",
+    "source/common/serv.cpp",
+    "source/common/servlk.cpp",
+    "source/common/servlkf.cpp",
+    "source/common/servls.cpp",
+    "source/common/servnotf.cpp",
+    "source/common/servrbf.cpp",
+    "source/common/servslkf.cpp",
+    "source/common/stringpiece.cpp",
+    "source/common/triedict.cpp",
+    "source/common/uarrsort.c",
+    "source/common/ubidi.c",
+    "source/common/ubidi_props.c",
+    "source/common/ubidiln.c",
+    "source/common/ubidiwrt.c",
+    "source/common/ubrk.cpp",
+    "source/common/ucase.c",
+    "source/common/ucasemap.c",
+    "source/common/ucat.c",
+    "source/common/uchar.c",
+    "source/common/uchriter.cpp",
+    "source/common/ucln_cmn.c",
+    "source/common/ucmndata.c",
+    "source/common/ucnv.c",
+    "source/common/ucnv2022.c",
+    "source/common/ucnv_bld.c",
+    "source/common/ucnv_cb.c",
+    "source/common/ucnv_cnv.c",
+    "source/common/ucnv_err.c",
+    "source/common/ucnv_ext.c",
+    "source/common/ucnv_io.c",
+    "source/common/ucnv_lmb.c",
+    "source/common/ucnv_set.c",
+    "source/common/ucnv_u16.c",
+    "source/common/ucnv_u32.c",
+    "source/common/ucnv_u7.c",
+    "source/common/ucnv_u8.c",
+    "source/common/ucnvbocu.c",
+    "source/common/ucnvdisp.c",
+    "source/common/ucnvhz.c",
+    "source/common/ucnvisci.c",
+    "source/common/ucnvlat1.c",
+    "source/common/ucnvmbcs.c",
+    "source/common/ucnvscsu.c",
+    "source/common/ucnvsel.cpp",
+    "source/common/ucol_swp.cpp",
+    "source/common/udata.cpp",
+    "source/common/udatamem.c",
+    "source/common/udataswp.c",
+    "source/common/uenum.c",
+    "source/common/uhash.c",
+    "source/common/uhash_us.cpp",
+    "source/common/uidna.cpp",
+    "source/common/uinit.c",
+    "source/common/uinvchar.c",
+    "source/common/uiter.cpp",
+    "source/common/ulist.c",
+    "source/common/uloc.c",
+    "source/common/uloc_tag.c",
+    "source/common/umapfile.c",
+    "source/common/umath.c",
+    "source/common/umutex.c",
+    "source/common/unames.c",
+    "source/common/unifilt.cpp",
+    "source/common/unifunct.cpp",
+    "source/common/uniset.cpp",
+    "source/common/uniset_props.cpp",
+    "source/common/unisetspan.cpp",
+    "source/common/unistr.cpp",
+    "source/common/unistr_case.cpp",
+    "source/common/unistr_cnv.cpp",
+    "source/common/unistr_props.cpp",
+    "source/common/unorm.cpp",
+    "source/common/unorm_it.c",
+    "source/common/unormcmp.cpp",
+    "source/common/uobject.cpp",
+    "source/common/uprops.cpp",
+    "source/common/ures_cnv.c",
+    "source/common/uresbund.c",
+    "source/common/uresdata.c",
+    "source/common/usc_impl.c",
+    "source/common/uscript.c",
+    "source/common/uset.cpp",
+    "source/common/uset_props.cpp",
+    "source/common/usetiter.cpp",
+    "source/common/ushape.c",
+    "source/common/usprep.cpp",
+    "source/common/ustack.cpp",
+    "source/common/ustr_cnv.c",
+    "source/common/ustr_wcs.c",
+    "source/common/ustrcase.c",
+    "source/common/ustrenum.cpp",
+    "source/common/ustrfmt.c",
+    "source/common/ustring.c",
+    "source/common/ustrtrns.c",
+    "source/common/utext.cpp",
+    "source/common/utf_impl.c",
+    "source/common/util.cpp",
+    "source/common/util_props.cpp",
+    "source/common/utrace.c",
+    "source/common/utrie.c",
+    "source/common/utrie2.cpp",
+    "source/common/utrie2_builder.c",
+    "source/common/uts46.cpp",
+    "source/common/utypes.c",
+    "source/common/uvector.cpp",
+    "source/common/uvectr32.cpp",
+    "source/common/uvectr64.cpp",
+    "source/common/wintz.c",
+    "source/stubdata/stubdata.c",
+  ]
+  defines = [
+    "U_COMMON_IMPLEMENTATION",
+  ]
+  deps = [
+    ":icudata",
+  ]
+  configs += [ ":icu_code" ]
+
+  configs -= [
+    "//build/config/compiler:no_rtti",  # ICU uses RTTI.
+    "//build/config/compiler:chromium_code",
+  ]
+  configs += [
+    "//build/config/compiler:rtti",
+    "//build/config/compiler:no_chromium_code",
+  ]
+
+  direct_dependent_configs = [ ":icu_config" ]
+
+  if (!is_win) {
+    sources -= "source/stubdata/stubdata.c"
+  }
+}
+
+if (is_win) {
+  # On Windows the target DLL is pre-built so just use a copy rule.
+  copy("icudata") {
+    sources = [ "windows/icudt.dll" ]
+    destdir = root_output_dir
+  }
+} else {
+  static_library("icudata") {
+    sources = [
+      # These are hand-generated, but will do for now.  The linux version is an
+      # identical copy of the (mac) icudt46l_dat.S file, modulo removal of the
+      # .private_extern and .const directives and with no leading underscore on
+      # the icudt46_dat symbol.
+      "android/icudt46l_dat.S",
+      "linux/icudt46l_dat.S",
+      "mac/icudt46l_dat.S",
+    ]
+    defines = [ "U_HIDE_DATA_SYMBOL" ]
+
+    # TODO(brettw) support use_system_icu and icu_use_data_file_flag.
+  }
+}
diff --git a/tools/gn/secondary/third_party/libevent/BUILD.gn b/tools/gn/secondary/third_party/libevent/BUILD.gn
index d494c84..afbd67d 100644
--- a/tools/gn/secondary/third_party/libevent/BUILD.gn
+++ b/tools/gn/secondary/third_party/libevent/BUILD.gn
@@ -32,7 +32,8 @@
 
   if (is_mac) {
     includes = [ "mac" ]
-  } else {
+  } else if (is_linux) {
+    includes = [ "linux" ]
     sources -= [ "kqueue.c" ]
   }
 
diff --git a/tools/gn/secondary/third_party/modp_b64/BUILD.gn b/tools/gn/secondary/third_party/modp_b64/BUILD.gn
index 5598f12..539abe1 100644
--- a/tools/gn/secondary/third_party/modp_b64/BUILD.gn
+++ b/tools/gn/secondary/third_party/modp_b64/BUILD.gn
@@ -1,11 +1,11 @@
-# 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.

-

-static_library("modp_b64") {

-  sources = [

-    "modp_b64.cc",

-    "modp_b64.h",

-    "modp_b64_data.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.
+
+static_library("modp_b64") {
+  sources = [
+    "modp_b64.cc",
+    "modp_b64.h",
+    "modp_b64_data.h",
+  ]
+}
diff --git a/tools/gn/secondary/third_party/wtl/BUILD.gn b/tools/gn/secondary/third_party/wtl/BUILD.gn
new file mode 100644
index 0000000..07c6ab2
--- /dev/null
+++ b/tools/gn/secondary/third_party/wtl/BUILD.gn
@@ -0,0 +1,14 @@
+# 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.
+
+config("wtl_includes") {
+  includes = [ "include" ]
+}
+
+# WTL is only header files so we use a "group" target type which doesn't
+# actually generate anything linkable, and inject the required config for
+# making the include directories work.
+group("wtl") {
+  all_dependent_configs = ":wtl_includes"
+}
diff --git a/tools/gn/secondary/third_party/zlib/BUILD.gn b/tools/gn/secondary/third_party/zlib/BUILD.gn
new file mode 100644
index 0000000..7805328
--- /dev/null
+++ b/tools/gn/secondary/third_party/zlib/BUILD.gn
@@ -0,0 +1,89 @@
+# 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.
+
+config("zlib_config") {
+  includes = [ "." ]
+}
+
+static_library("zlib") {
+  sources = [
+    "adler32.c",
+    "compress.c",
+    "crc32.c",
+    "crc32.h",
+    "deflate.c",
+    "deflate.h",
+    "gzclose.c",
+    "gzguts.h",
+    "gzlib.c",
+    "gzread.c",
+    "gzwrite.c",
+    "infback.c",
+    "inffast.c",
+    "inffast.h",
+    "inffixed.h",
+    "inflate.c",
+    "inflate.h",
+    "inftrees.c",
+    "inftrees.h",
+    "mozzconf.h",
+    "trees.c",
+    "trees.h",
+    "uncompr.c",
+    "zconf.h",
+    "zlib.h",
+    "zutil.c",
+    "zutil.h",
+  ]
+
+  direct_dependent_configs = [ ":zlib_config" ]
+}
+
+static_library("minizip") {
+  sources = [
+    "contrib/minizip/ioapi.c",
+    "contrib/minizip/ioapi.h",
+    "contrib/minizip/iowin32.c",
+    "contrib/minizip/iowin32.h",
+    "contrib/minizip/unzip.c",
+    "contrib/minizip/unzip.h",
+    "contrib/minizip/zip.c",
+    "contrib/minizip/zip.h",
+  ]
+
+  if (!is_win) {
+    sources -= [
+      "contrib/minizip/iowin32.c",
+      "contrib/minizip/iowin32.h",
+    ]
+  } else if (is_mac || is_ios || is_android) {
+    # Mac, Android and the BSDs don't have fopen64, ftello64, or fseeko64. We
+    # use fopen, ftell, and fseek instead on these systems.
+    defines = [ "USE_FILE32API" ]
+  }
+
+  if (is_clang) {
+    # zlib uses `if ((a == b))` for some reason.
+    cflags = [ "-Wno-parentheses-equality" ]
+  }
+
+  deps = [ ":zlib" ]
+
+  direct_dependent_configs = [ ":zlib_config" ]
+}
+
+static_library("zip") {
+  sources = [
+    "google/zip.cc",
+    "google/zip.h",
+    "google/zip_internal.cc",
+    "google/zip_internal.h",
+    "google/zip_reader.cc",
+    "google/zip_reader.h",
+  ]
+  deps = [
+    ":minizip",
+    "//base",
+  ]
+}
diff --git a/tools/gn/secondary/tools/grit/grit_rule.gni b/tools/gn/secondary/tools/grit/grit_rule.gni
new file mode 100644
index 0000000..7b3ba48
--- /dev/null
+++ b/tools/gn/secondary/tools/grit/grit_rule.gni
@@ -0,0 +1,44 @@
+# 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.
+
+template("grit") {
+  assert(defined(source),
+         "\"source\" must be defined for the grit template $target_name")
+  assert(!defined(sources) && !defined(outputs),
+         "Neither \"sources\" nor \"outputs\" can be defined for the grit " +
+         "template $target_name")
+
+  resource_ids = "$relative_source_root_dir/tools/gritsettings/resource_ids"
+  output_dir = "$relative_target_gen_dir"
+
+  # Note that this needs to be source-absolute since the current directory will
+  # be that of the file invoking the template, not this file.
+  grit_info_script = "$relative_source_root_dir/tools/grit/grit_info.py"
+
+  grit_inputs = exec_script(grit_info_script,
+    [ "--inputs", source, "-f", resource_ids], "list lines")
+  grit_outputs = exec_script(grit_info_script,
+    [ "--outputs", "$output_dir", source, "-f", resource_ids ],
+    "list lines")
+
+  custom(target_name + "_grit") {
+    script = "$relative_source_root_dir/tools/grit/grit.py"
+    data = grit_inputs  # TODO(brettw) this should be inputs or something
+    outputs = grit_outputs
+
+    # TODO(brettw) grit_defines.
+    args = [
+      "-i", source, "build",
+      "-f", resource_ids,
+      "-o", relative_target_gen_dir,
+    ]
+  }
+
+  # This is the thing that people actually link with, it must be named the
+  # same as the argument the template was invoked with.
+  static_library(target_name) {
+    sources = grit_outputs
+    deps = [ ":${target_name}_grit" ]
+  }
+}
diff --git a/tools/gn/secondary/url/BUILD.gn b/tools/gn/secondary/url/BUILD.gn
new file mode 100644
index 0000000..b9d400a
--- /dev/null
+++ b/tools/gn/secondary/url/BUILD.gn
@@ -0,0 +1,67 @@
+# 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.
+
+# Note, this target_name cannot be 'url', because that will generate 'url.dll'
+# for a Windows component build, and that will confuse Windows, which has a
+# system DLL with the same name.
+component("url_lib") {
+  sources = [
+    "gurl.cc",
+    "gurl.h",
+    "third_party/mozilla/url_parse.cc",
+    "third_party/mozilla/url_parse.h",
+    "url_canon.h",
+    "url_canon_etc.cc",
+    "url_canon_filesystemurl.cc",
+    "url_canon_fileurl.cc",
+    "url_canon_host.cc",
+    "url_canon_icu.cc",
+    "url_canon_icu.h",
+    "url_canon_internal.cc",
+    "url_canon_internal.h",
+    "url_canon_internal_file.h",
+    "url_canon_ip.cc",
+    "url_canon_ip.h",
+    "url_canon_mailtourl.cc",
+    "url_canon_path.cc",
+    "url_canon_pathurl.cc",
+    "url_canon_query.cc",
+    "url_canon_relative.cc",
+    "url_canon_stdstring.h",
+    "url_canon_stdurl.cc",
+    "url_file.h",
+    "url_parse_file.cc",
+    "url_parse_internal.h",
+    "url_util.cc",
+    "url_util.h",
+  ]
+
+  defines = [ "URL_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+    "//third_party/icu:icudata",
+    "//third_party/icu:icui18n",
+    "//third_party/icu:icuuc",
+  ]
+}
+
+test("url_unittests") {
+  sources = [
+    "gurl_unittest.cc",
+    "url_canon_unittest.cc",
+    "url_parse_unittest.cc",
+    "url_test_utils.h",
+    "url_util_unittest.cc",
+  ]
+
+  deps = [
+    ":url_lib",
+    "//base:base_i18n",
+    "//base/test:run_all_unittests",
+    "//testing/gtest",
+    "//third_party/icu:icuuc",
+  ]
+}
+
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 72eb8e9..8fba875 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -56,7 +56,12 @@
 // More logging.
 const char kSwitchVerbose[] = "v";
 
+// Set build args.
+const char kSwitchArgs[] = "args";
+
+// Set root dir.
 const char kSwitchRoot[] = "root";
+
 const char kSecondarySource[] = "secondary";
 
 const base::FilePath::CharType kGnFile[] = FILE_PATH_LITERAL(".gn");
@@ -77,10 +82,10 @@
 }  // namespace
 
 Setup::Setup()
-    : dotfile_toolchain_(Label()),
-      dotfile_settings_(&dotfile_build_settings_, &dotfile_toolchain_,
-                        std::string()),
-      dotfile_scope_(&dotfile_settings_) {
+    : check_for_bad_items_(true),
+      empty_toolchain_(Label()),
+      empty_settings_(&empty_build_settings_, &empty_toolchain_, std::string()),
+      dotfile_scope_(&empty_settings_) {
 }
 
 Setup::~Setup() {
@@ -91,6 +96,8 @@
 
   scheduler_.set_verbose_logging(cmdline->HasSwitch(kSwitchVerbose));
 
+  if (!FillArguments(*cmdline))
+    return false;
   if (!FillSourceDir(*cmdline))
     return false;
   if (!RunConfigFile())
@@ -118,11 +125,55 @@
   if (!scheduler_.Run())
     return false;
 
-  Err err = build_settings_.item_tree().CheckForBadItems();
+  Err err;
+  if (check_for_bad_items_) {
+    err = build_settings_.item_tree().CheckForBadItems();
+    if (err.has_error()) {
+      err.PrintToStdout();
+      return false;
+    }
+  }
+
+  if (!build_settings_.build_args().VerifyAllOverridesUsed(&err)) {
+    err.PrintToStdout();
+    return false;
+  }
+  return true;
+}
+
+bool Setup::FillArguments(const CommandLine& cmdline) {
+  std::string args = cmdline.GetSwitchValueASCII(kSwitchArgs);
+  if (args.empty())
+    return true;  // Nothing to set.
+
+  args_input_file_.reset(new InputFile(SourceFile()));
+  args_input_file_->SetContents(args);
+  args_input_file_->set_friendly_name("the command-line \"--args\" settings");
+
+  Err err;
+  args_tokens_ = Tokenizer::Tokenize(args_input_file_.get(), &err);
   if (err.has_error()) {
     err.PrintToStdout();
     return false;
   }
+
+  args_root_ = Parser::Parse(args_tokens_, &err);
+  if (err.has_error()) {
+    err.PrintToStdout();
+    return false;
+  }
+
+  Scope arg_scope(&empty_settings_);
+  args_root_->AsBlock()->ExecuteBlockInScope(&arg_scope, &err);
+  if (err.has_error()) {
+    err.PrintToStdout();
+    return false;
+  }
+
+  // Save the result of the command args.
+  Scope::KeyValueMap overrides;
+  arg_scope.GetCurrentScopeValues(&overrides);
+  build_settings_.build_args().SwapInArgOverrides(&overrides);
   return true;
 }
 
@@ -151,7 +202,7 @@
 
   if (scheduler_.verbose_logging())
     scheduler_.Log("Using source root", FilePathToUTF8(root_path));
-  build_settings_.set_root_path(root_path);
+  build_settings_.SetRootPath(root_path);
 
   return true;
 }
diff --git a/tools/gn/setup.h b/tools/gn/setup.h
index 4070a0f..069da92 100644
--- a/tools/gn/setup.h
+++ b/tools/gn/setup.h
@@ -34,6 +34,10 @@
   // true. On failure, prints the error and returns false.
   bool DoSetup();
 
+  // When true (the default), Run() will check for unresolved dependencies and
+  // cycles upon completion. When false, such errors will be ignored.
+  void set_check_for_bad_items(bool s) { check_for_bad_items_ = s; }
+
   // Runs the load, returning true on success. On failure, prints the error
   // and returns false.
   bool Run();
@@ -42,6 +46,9 @@
   Scheduler& scheduler() { return scheduler_; }
 
  private:
+  // Fills build arguments. Returns true on success.
+  bool FillArguments(const CommandLine& cmdline);
+
   // Fills the root directory into the settings. Returns true on success.
   bool FillSourceDir(const CommandLine& cmdline);
 
@@ -53,17 +60,27 @@
   BuildSettings build_settings_;
   Scheduler scheduler_;
 
+  bool check_for_bad_items_;
+
+  // These empty settings and toolchain are used to interpret the command line
+  // and dot file.
+  BuildSettings empty_build_settings_;
+  Toolchain empty_toolchain_;
+  Settings empty_settings_;
+  Scope dotfile_scope_;
+
   // State for invoking the dotfile.
-  // TODO(brettw) this seems a bit excessive, maybe we can get this down
-  // somehow?
   base::FilePath dotfile_name_;
   scoped_ptr<InputFile> dotfile_input_file_;
   std::vector<Token> dotfile_tokens_;
   scoped_ptr<ParseNode> dotfile_root_;
-  BuildSettings dotfile_build_settings_;
-  Toolchain dotfile_toolchain_;
-  Settings dotfile_settings_;
-  Scope dotfile_scope_;
+
+  // State for invoking the command line args. We specifically want to keep
+  // this around for the entire run so that Values can blame to the command
+  // line when we issue errors about them.
+  scoped_ptr<InputFile> args_input_file_;
+  std::vector<Token> args_tokens_;
+  scoped_ptr<ParseNode> args_root_;
 
   DISALLOW_COPY_AND_ASSIGN(Setup);
 };
diff --git a/tools/gn/source_dir.cc b/tools/gn/source_dir.cc
index 5739b52..7cdd693 100644
--- a/tools/gn/source_dir.cc
+++ b/tools/gn/source_dir.cc
@@ -31,7 +31,9 @@
 SourceDir::~SourceDir() {
 }
 
-SourceFile SourceDir::ResolveRelativeFile(const base::StringPiece& p) const {
+SourceFile SourceDir::ResolveRelativeFile(
+    const base::StringPiece& p,
+    const base::StringPiece& source_root) const {
   SourceFile ret;
 
   // It's an error to resolve an empty string or one that is a directory
@@ -39,9 +41,16 @@
   // to return a file.
   if (p.empty() || (p.size() > 0 && p[p.size() - 1] == '/'))
     return SourceFile();
-  if (p[0] == '/') {
-    // Absolute path.
+  if (p.size() >= 2 && p[0] == '/' && p[1] == '/') {
+    // Source-relative.
     ret.value_.assign(p.data(), p.size());
+    NormalizePath(&ret.value_);
+    return ret;
+  } else if (IsPathAbsolute(p)) {
+    if (source_root.empty() ||
+        !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_))
+      ret.value_.assign(p.data(), p.size());
+    NormalizePath(&ret.value_);
     return ret;
   }
 
@@ -53,13 +62,27 @@
   return ret;
 }
 
-SourceDir SourceDir::ResolveRelativeDir(const base::StringPiece& p) const {
+SourceDir SourceDir::ResolveRelativeDir(
+    const base::StringPiece& p,
+    const base::StringPiece& source_root) const {
   SourceDir ret;
 
   if (p.empty())
     return ret;
-  if (p[0] == '/') {
-    // Absolute path.
+  if (p.size() >= 2 && p[0] == '/' && p[1] == '/') {
+    // Source-relative.
+    ret.value_.assign(p.data(), p.size());
+    if (!EndsWithSlash(ret.value_))
+      ret.value_.push_back('/');
+    NormalizePath(&ret.value_);
+    return ret;
+  } else if (IsPathAbsolute(p)) {
+    if (source_root.empty() ||
+        !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_))
+      ret.value_.assign(p.data(), p.size());
+    NormalizePath(&ret.value_);
+    if (!EndsWithSlash(ret.value_))
+      ret.value_.push_back('/');
     return SourceDir(p);
   }
 
diff --git a/tools/gn/source_dir.h b/tools/gn/source_dir.h
index 3b6caee..4aa344a 100644
--- a/tools/gn/source_dir.h
+++ b/tools/gn/source_dir.h
@@ -31,8 +31,16 @@
   // an empty SourceDir/File on error. Empty input is always an error (it's
   // possible we should say ResolveRelativeDir vs. an empty string should be
   // the source dir, but we require "." instead).
-  SourceFile ResolveRelativeFile(const base::StringPiece& p) const;
-  SourceDir ResolveRelativeDir(const base::StringPiece& p) const;
+  //
+  // If source_root is supplied, these functions will additionally handle the
+  // case where the input is a system-absolute but still inside the source
+  // tree. This is the case for some external tools.
+  SourceFile ResolveRelativeFile(
+      const base::StringPiece& p,
+      const base::StringPiece& source_root = base::StringPiece()) const;
+  SourceDir ResolveRelativeDir(
+      const base::StringPiece& p,
+      const base::StringPiece& source_root = base::StringPiece()) const;
 
   // Resolves this source file relative to some given source root. Returns
   // an empty file path on error.
diff --git a/tools/gn/string_utils.cc b/tools/gn/string_utils.cc
index 14d296a..2812af9 100644
--- a/tools/gn/string_utils.cc
+++ b/tools/gn/string_utils.cc
@@ -113,7 +113,7 @@
     return false;
   }
 
-  output->append(value->ToString());
+  output->append(value->ToString(false));
   return true;
 }
 
diff --git a/tools/gn/string_utils_unittest.cc b/tools/gn/string_utils_unittest.cc
index 81181d2..9e69d40 100644
--- a/tools/gn/string_utils_unittest.cc
+++ b/tools/gn/string_utils_unittest.cc
@@ -14,7 +14,8 @@
 
 bool CheckExpansionCase(const char* input, const char* expected, bool success) {
   Scope scope(static_cast<const Settings*>(NULL));
-  scope.SetValue("one", Value(NULL, 1), NULL);
+  int64 one = 1;
+  scope.SetValue("one", Value(NULL, one), NULL);
   scope.SetValue("onestring", Value(NULL, "one"), NULL);
 
   // Construct the string token, which includes the quotes.
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index 0936f22..0d7a492 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -4,22 +4,65 @@
 
 #include "tools/gn/target.h"
 
+#include <set>
+
 #include "base/bind.h"
 #include "tools/gn/scheduler.h"
 
 namespace {
 
+typedef std::set<const Config*> ConfigSet;
+
 void TargetResolvedThunk(const base::Callback<void(const Target*)>& cb,
                          const Target* t) {
   cb.Run(t);
 }
 
+// Merges the dependent configs from the given target to the given config list.
+// The unique_configs list is used for de-duping so values already added will
+// not be added again.
+void MergeDirectDependentConfigsFrom(const Target* from_target,
+                                     ConfigSet* unique_configs,
+                                     std::vector<const Config*>* dest) {
+  const std::vector<const Config*>& direct =
+      from_target->direct_dependent_configs();
+  for (size_t i = 0; i < direct.size(); i++) {
+    if (unique_configs->find(direct[i]) == unique_configs->end()) {
+      unique_configs->insert(direct[i]);
+      dest->push_back(direct[i]);
+    }
+  }
+}
+
+// Like MergeDirectDependentConfigsFrom above except does the "all dependent"
+// ones. This additionally adds all configs to the all_dependent_configs_ of
+// the dest target given in *all_dest.
+void MergeAllDependentConfigsFrom(const Target* from_target,
+                                  ConfigSet* unique_configs,
+                                  std::vector<const Config*>* dest,
+                                  std::vector<const Config*>* all_dest) {
+  const std::vector<const Config*>& all =
+      from_target->all_dependent_configs();
+  for (size_t i = 0; i < all.size(); i++) {
+    // Always add it to all_dependent_configs_ since it might not be in that
+    // list even if we've seen it applied to this target before. This may
+    // introduce some duplicates in all_dependent_configs_, but those will
+    // we removed when they're actually applied to a target.
+    all_dest->push_back(all[i]);
+    if (unique_configs->find(all[i]) == unique_configs->end()) {
+      // One we haven't seen yet, also apply it to ourselves.
+      dest->push_back(all[i]);
+      unique_configs->insert(all[i]);
+    }
+  }
+}
+
 }  // namespace
 
 Target::Target(const Settings* settings, const Label& label)
     : Item(label),
       settings_(settings),
-      output_type_(NONE),
+      output_type_(UNKNOWN),
       generated_(false),
       generator_function_(NULL) {
 }
@@ -27,6 +70,28 @@
 Target::~Target() {
 }
 
+// static
+const char* Target::GetStringForOutputType(OutputType type) {
+  switch (type) {
+    case UNKNOWN:
+      return "Unknown";
+    case GROUP:
+      return "Group";
+    case EXECUTABLE:
+      return "Executable";
+    case SHARED_LIBRARY:
+      return "Shared library";
+    case STATIC_LIBRARY:
+      return "Static library";
+    case COPY_FILES:
+      return "Copy";
+    case CUSTOM:
+      return "Custom";
+    default:
+      return "";
+  }
+}
+
 Target* Target::AsTarget() {
   return this;
 }
@@ -36,33 +101,42 @@
 }
 
 void Target::OnResolved() {
+  // Only add each config once. First remember the target's configs.
+  std::set<const Config*> unique_configs;
+  for (size_t i = 0; i < configs_.size(); i++)
+    unique_configs.insert(configs_[i]);
+
+  // Copy our own dependent configs to the list of configs applying to us.
+  for (size_t i = 0; i < all_dependent_configs_.size(); i++) {
+    const Config* cur = all_dependent_configs_[i];
+    if (unique_configs.find(cur) == unique_configs.end()) {
+      unique_configs.insert(cur);
+      configs_.push_back(cur);
+    }
+  }
+  for (size_t i = 0; i < direct_dependent_configs_.size(); i++) {
+    const Config* cur = direct_dependent_configs_[i];
+    if (unique_configs.find(cur) == unique_configs.end()) {
+      unique_configs.insert(cur);
+      configs_.push_back(cur);
+    }
+  }
+
   // Gather info from our dependents we need.
   for (size_t dep = 0; dep < deps_.size(); dep++) {
-    // All dependent configs get pulled to us, and to our dependents.
-    const std::vector<const Config*>& all =
-        deps_[dep]->all_dependent_configs();
-    for (size_t i = 0; i < all.size(); i++) {
-      configs_.push_back(all[i]);
-      all_dependent_configs_.push_back(all[i]);
-    }
-
-    // Direct dependent configs get pulled only to us.
-    const std::vector<const Config*>& direct =
-        deps_[dep]->direct_dependent_configs();
-    for (size_t i = 0; i < direct.size(); i++)
-      configs_.push_back(direct[i]);
+    MergeAllDependentConfigsFrom(deps_[dep], &unique_configs, &configs_,
+                                 &all_dependent_configs_);
+    MergeDirectDependentConfigsFrom(deps_[dep], &unique_configs, &configs_);
 
     // Direct dependent libraries.
     if (deps_[dep]->output_type() == STATIC_LIBRARY ||
-        deps_[dep]->output_type() == SHARED_LIBRARY ||
-        deps_[dep]->output_type() == LOADABLE_MODULE)
+        deps_[dep]->output_type() == SHARED_LIBRARY)
       inherited_libraries_.insert(deps_[dep]);
 
-    // Inherited libraries. DOn't pull transitive libraries from shared
+    // Inherited libraries. Don't pull transitive libraries from shared
     // libraries, since obviously those shouldn't be linked directly into
     // later deps unless explicitly specified.
     if (deps_[dep]->output_type() != SHARED_LIBRARY &&
-        deps_[dep]->output_type() != LOADABLE_MODULE &&
         deps_[dep]->output_type() != EXECUTABLE) {
       const std::set<const Target*> inherited =
           deps_[dep]->inherited_libraries();
@@ -72,6 +146,21 @@
     }
   }
 
+  // Forward direct dependent configs if requested.
+  for (size_t dep = 0; dep < forward_dependent_configs_.size(); dep++) {
+    const Target* from_target = forward_dependent_configs_[dep];
+
+    // The forward_dependent_configs_ must be in the deps already, so we
+    // don't need to bother copying to our configs, only forwarding.
+    DCHECK(std::find(deps_.begin(), deps_.end(), from_target) !=
+           deps_.end());
+    const std::vector<const Config*>& direct =
+        from_target->direct_dependent_configs();
+    for (size_t i = 0; i < direct.size(); i++)
+      direct_dependent_configs_.push_back(direct[i]);
+  }
+
+  // Mark as resolved.
   if (!settings_->build_settings()->target_resolved_callback().is_null()) {
     g_scheduler->ScheduleWork(base::Bind(&TargetResolvedThunk,
         settings_->build_settings()->target_resolved_callback(),
diff --git a/tools/gn/target.h b/tools/gn/target.h
index ac0fc59..2e55805 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -16,6 +16,7 @@
 #include "base/synchronization/lock.h"
 #include "tools/gn/config_values.h"
 #include "tools/gn/item.h"
+#include "tools/gn/script_values.h"
 #include "tools/gn/source_file.h"
 
 class InputFile;
@@ -25,11 +26,11 @@
 class Target : public Item {
  public:
   enum OutputType {
-    NONE,
+    UNKNOWN,
+    GROUP,
     EXECUTABLE,
     SHARED_LIBRARY,
     STATIC_LIBRARY,
-    LOADABLE_MODULE,
     COPY_FILES,
     CUSTOM,
   };
@@ -39,6 +40,9 @@
   Target(const Settings* settings, const Label& label);
   virtual ~Target();
 
+  // Returns a string naming the output type.
+  static const char* GetStringForOutputType(OutputType type);
+
   // Item overrides.
   virtual Target* AsTarget() OVERRIDE;
   virtual const Target* AsTarget() const OVERRIDE;
@@ -77,7 +81,8 @@
   void swap_in_configs(std::vector<const Config*>* c) { configs_.swap(*c); }
 
   // List of configs that all dependencies (direct and indirect) of this
-  // target get. These configs are not added to this target.
+  // target get. These configs are not added to this target. Note that due
+  // to the way this is computed, there may be duplicates in this list.
   const std::vector<const Config*>& all_dependent_configs() const {
     return all_dependent_configs_;
   }
@@ -94,6 +99,15 @@
     direct_dependent_configs_.swap(*c);
   }
 
+  // A list of a subset of deps where we'll re-export direct_dependent_configs
+  // as direct_dependent_configs of this target.
+  const std::vector<const Target*>& forward_dependent_configs() const {
+    return forward_dependent_configs_;
+  }
+  void swap_in_forward_dependent_configs(std::vector<const Target*>* t) {
+    forward_dependent_configs_.swap(*t);
+  }
+
   const std::set<const Target*>& inherited_libraries() const {
     return inherited_libraries_;
   }
@@ -102,20 +116,12 @@
   ConfigValues& config_values() { return config_values_; }
   const ConfigValues& config_values() const { return config_values_; }
 
+  ScriptValues& script_values() { return script_values_; }
+  const ScriptValues& script_values() const { return script_values_; }
+
   const SourceDir& destdir() const { return destdir_; }
   void set_destdir(const SourceDir& d) { destdir_ = d; }
 
-  const SourceFile& script() const { return script_; }
-  void set_script(const SourceFile& s) { script_ = s; }
-
-  const std::vector<std::string>& script_args() const { return script_args_; }
-  void swap_in_script_args(std::vector<std::string>* sa) {
-    script_args_.swap(*sa);
-  }
-
-  const FileList& outputs() const { return outputs_; }
-  void swap_in_outputs(FileList* s) { outputs_.swap(*s); }
-
  private:
   const Settings* settings_;
   OutputType output_type_;
@@ -127,21 +133,18 @@
   std::vector<const Config*> configs_;
   std::vector<const Config*> all_dependent_configs_;
   std::vector<const Config*> direct_dependent_configs_;
+  std::vector<const Target*> forward_dependent_configs_;
 
   // Libraries from transitive deps. Libraries need to be linked only
   // with the end target (executable, shared library). These do not get
   // pushed beyond shared library boundaries.
   std::set<const Target*> inherited_libraries_;
 
-  ConfigValues config_values_;
+  ConfigValues config_values_;  // Used for all binary targets.
+  ScriptValues script_values_;  // Used for script (CUSTOM) targets.
 
   SourceDir destdir_;
 
-  // Script target stuff.
-  SourceFile script_;
-  std::vector<std::string> script_args_;
-  FileList outputs_;
-
   bool generated_;
   const Token* generator_function_;  // Who generated this: for error messages.
 
diff --git a/tools/gn/target_generator.cc b/tools/gn/target_generator.cc
index 3fdd9e3..5421d93 100644
--- a/tools/gn/target_generator.cc
+++ b/tools/gn/target_generator.cc
@@ -4,130 +4,52 @@
 
 #include "tools/gn/target_generator.h"
 
-#include "base/files/file_path.h"
-#include "base/logging.h"
+#include "tools/gn/binary_target_generator.h"
 #include "tools/gn/build_settings.h"
 #include "tools/gn/config.h"
-#include "tools/gn/config_values_generator.h"
+#include "tools/gn/copy_target_generator.h"
 #include "tools/gn/err.h"
-#include "tools/gn/filesystem_utils.h"
 #include "tools/gn/functions.h"
-#include "tools/gn/input_file.h"
+#include "tools/gn/group_target_generator.h"
 #include "tools/gn/item_node.h"
-#include "tools/gn/ninja_target_writer.h"
 #include "tools/gn/parse_tree.h"
 #include "tools/gn/scheduler.h"
 #include "tools/gn/scope.h"
+#include "tools/gn/script_target_generator.h"
 #include "tools/gn/target_manager.h"
 #include "tools/gn/token.h"
 #include "tools/gn/value.h"
 #include "tools/gn/value_extractors.h"
 #include "tools/gn/variables.h"
 
-namespace {
-
-bool TypeHasConfigs(Target::OutputType type) {
-  return type == Target::EXECUTABLE ||
-         type == Target::SHARED_LIBRARY ||
-         type == Target::STATIC_LIBRARY ||
-         type == Target::LOADABLE_MODULE;
-}
-
-bool TypeHasConfigValues(Target::OutputType type) {
-  return type == Target::EXECUTABLE ||
-         type == Target::SHARED_LIBRARY ||
-         type == Target::STATIC_LIBRARY ||
-         type == Target::LOADABLE_MODULE;
-}
-
-bool TypeHasSources(Target::OutputType type) {
-  return type != Target::NONE;
-}
-
-bool TypeHasData(Target::OutputType type) {
-  return type != Target::NONE;
-}
-
-bool TypeHasDestDir(Target::OutputType type) {
-  return type == Target::COPY_FILES;
-}
-
-bool TypeHasOutputs(Target::OutputType type) {
-  return type == Target::CUSTOM;
-}
-
-}  // namespace
-
 TargetGenerator::TargetGenerator(Target* target,
                                  Scope* scope,
                                  const Token& function_token,
-                                 const std::vector<Value>& args,
-                                 const std::string& output_type,
                                  Err* err)
     : target_(target),
       scope_(scope),
       function_token_(function_token),
-      args_(args),
-      output_type_(output_type),
-      err_(err),
-      input_directory_(function_token.location().file()->dir()) {
+      err_(err) {
 }
 
 TargetGenerator::~TargetGenerator() {
 }
 
 void TargetGenerator::Run() {
-  // Output type.
-  Target::OutputType output_type = GetOutputType();
-  target_->set_output_type(output_type);
-  if (err_->has_error())
-    return;
+  // All target types use these.
+  FillDependentConfigs();
+  FillData();
+  FillDependencies();
 
-  if (TypeHasConfigs(output_type)) {
-    FillConfigs();
-    FillAllDependentConfigs();
-    FillDirectDependentConfigs();
+  // To type-specific generation.
+  DoRun();
+
+  // Mark the target as complete.
+  if (!err_->has_error()) {
+    target_->SetGenerated(&function_token_);
+    GetBuildSettings()->target_manager().TargetGenerationComplete(
+        target_->label(), err_);
   }
-  if (TypeHasSources(output_type))
-    FillSources();
-  if (TypeHasData(output_type))
-    FillData();
-  if (output_type == Target::CUSTOM) {
-    FillScript();
-    FillScriptArgs();
-  }
-  if (TypeHasOutputs(output_type))
-    FillOutputs();
-  FillDependencies();  // All types have dependencies.
-  FillDataDependencies();  // All types have dependencies.
-
-  if (TypeHasConfigValues(output_type)) {
-    ConfigValuesGenerator gen(&target_->config_values(), scope_,
-                              function_token_, input_directory_, err_);
-    gen.Run();
-    if (err_->has_error())
-      return;
-  }
-
-  if (TypeHasDestDir(output_type))
-    FillDestDir();
-
-  // Set the toolchain as a dependency of the target.
-  // TODO(brettw) currently we lock separately for each config, dep, and
-  // toolchain we add which is bad! Do this in one lock.
-  {
-    ItemTree* tree = &GetBuildSettings()->item_tree();
-    base::AutoLock lock(tree->lock());
-    ItemNode* tc_node =
-        tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_));
-    if (!tree->GetExistingNodeLocked(target_->label())->AddDependency(
-            GetBuildSettings(), function_token_.range(), tc_node, err_))
-      return;
-  }
-
-  target_->SetGenerated(&function_token_);
-  GetBuildSettings()->target_manager().TargetGenerationComplete(
-      target_->label(), err_);
 }
 
 // static
@@ -147,42 +69,105 @@
   // The location of the target is the directory name with no slash at the end.
   // FIXME(brettw) validate name.
   const Label& toolchain_label = ToolchainLabelForScope(scope);
-  Label label(function_token.location().file()->dir(),
-              args[0].string_value(),
+  Label label(scope->GetSourceDir(), args[0].string_value(),
               toolchain_label.dir(), toolchain_label.name());
 
   if (g_scheduler->verbose_logging())
     g_scheduler->Log("Generating target", label.GetUserVisibleName(true));
 
-  Target* t = scope->settings()->build_settings()->target_manager().GetTarget(
-      label, function_token.range(), NULL, err);
+  Target* target =
+      scope->settings()->build_settings()->target_manager().GetTarget(
+          label, function_token.range(), NULL, err);
   if (err->has_error())
     return;
 
-  TargetGenerator gen(t, scope, function_token, args, output_type, err);
-  gen.Run();
+  // Create and call out to the proper generator.
+  if (output_type == functions::kCopy) {
+    CopyTargetGenerator generator(target, scope, function_token, err);
+    generator.Run();
+  } else if (output_type == functions::kCustom) {
+    ScriptTargetGenerator generator(target, scope, function_token, err);
+    generator.Run();
+  } else if (output_type == functions::kExecutable) {
+    BinaryTargetGenerator generator(target, scope, function_token,
+                                    Target::EXECUTABLE, err);
+    generator.Run();
+  } else if (output_type == functions::kGroup) {
+    GroupTargetGenerator generator(target, scope, function_token, err);
+    generator.Run();
+  } else if (output_type == functions::kSharedLibrary) {
+    BinaryTargetGenerator generator(target, scope, function_token,
+                                    Target::SHARED_LIBRARY, err);
+    generator.Run();
+  } else if (output_type == functions::kStaticLibrary) {
+    BinaryTargetGenerator generator(target, scope, function_token,
+                                    Target::STATIC_LIBRARY, err);
+    generator.Run();
+  } else {
+    *err = Err(function_token, "Not a known output type",
+               "I am very confused.");
+  }
 }
 
-Target::OutputType TargetGenerator::GetOutputType() const {
-  if (output_type_ == functions::kGroup)
-    return Target::NONE;
-  if (output_type_ == functions::kExecutable)
-    return Target::EXECUTABLE;
-  if (output_type_ == functions::kSharedLibrary)
-    return Target::SHARED_LIBRARY;
-  if (output_type_ == functions::kStaticLibrary)
-    return Target::STATIC_LIBRARY;
-  // TODO(brettw) what does loadable module mean?
-  //if (output_type_ == ???)
-  //  return Target::LOADABLE_MODULE;
-  if (output_type_ == functions::kCopy)
-    return Target::COPY_FILES;
-  if (output_type_ == functions::kCustom)
-    return Target::CUSTOM;
+const BuildSettings* TargetGenerator::GetBuildSettings() const {
+  return scope_->settings()->build_settings();
+}
 
-  *err_ = Err(function_token_, "Not a known output type",
-              "I am very confused.");
-  return Target::NONE;
+void TargetGenerator::FillSources() {
+  const Value* value = scope_->GetValue(variables::kSources, true);
+  if (!value)
+    return;
+
+  Target::FileList dest_sources;
+  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
+                                  scope_->GetSourceDir(), &dest_sources, err_))
+    return;
+  target_->swap_in_sources(&dest_sources);
+}
+
+void TargetGenerator::FillConfigs() {
+  FillGenericConfigs(variables::kConfigs, &Target::swap_in_configs);
+}
+
+void TargetGenerator::FillDependentConfigs() {
+  FillGenericConfigs(variables::kAllDependentConfigs,
+                     &Target::swap_in_all_dependent_configs);
+  FillGenericConfigs(variables::kDirectDependentConfigs,
+                     &Target::swap_in_direct_dependent_configs);
+}
+
+void TargetGenerator::FillData() {
+  // TODO(brettW) hook this up to the constant when we have cleaned up
+  // how data files are used.
+  const Value* value = scope_->GetValue("data", true);
+  if (!value)
+    return;
+
+  Target::FileList dest_data;
+  if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
+                                  scope_->GetSourceDir(), &dest_data, err_))
+    return;
+  target_->swap_in_data(&dest_data);
+}
+
+void TargetGenerator::FillDependencies() {
+  FillGenericDeps(variables::kDeps, &Target::swap_in_deps);
+  FillGenericDeps(variables::kDatadeps, &Target::swap_in_datadeps);
+
+  // This is a list of dependent targets to have their configs fowarded, so
+  // it goes here rather than in FillConfigs.
+  FillForwardDependentConfigs();
+}
+
+void TargetGenerator::SetToolchainDependency() {
+  // TODO(brettw) currently we lock separately for each config, dep, and
+  // toolchain we add which is bad! Do this in one lock.
+  ItemTree* tree = &GetBuildSettings()->item_tree();
+  base::AutoLock lock(tree->lock());
+  ItemNode* tc_node =
+      tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_));
+  target_->item_node()->AddDependency(
+      GetBuildSettings(), function_token_.range(), tc_node, err_);
 }
 
 void TargetGenerator::FillGenericConfigs(
@@ -193,7 +178,7 @@
     return;
 
   std::vector<Label> labels;
-  if (!ExtractListOfLabels(*value, input_directory_,
+  if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
                            ToolchainLabelForScope(scope_), &labels, err_))
     return;
 
@@ -218,7 +203,7 @@
     return;
 
   std::vector<Label> labels;
-  if (!ExtractListOfLabels(*value, input_directory_,
+  if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
                            ToolchainLabelForScope(scope_), &labels, err_))
     return;
 
@@ -234,117 +219,45 @@
   (target_->*setter)(&dest_deps);
 }
 
-void TargetGenerator::FillConfigs() {
-  FillGenericConfigs(variables::kConfigs, &Target::swap_in_configs);
-}
-
-void TargetGenerator::FillAllDependentConfigs() {
-  FillGenericConfigs(variables::kAllDependentConfigs,
-                     &Target::swap_in_all_dependent_configs);
-}
-
-void TargetGenerator::FillDirectDependentConfigs() {
-  FillGenericConfigs(variables::kDirectDependentConfigs,
-                     &Target::swap_in_direct_dependent_configs);
-}
-
-void TargetGenerator::FillSources() {
-  const Value* value = scope_->GetValue(variables::kSources, true);
+void TargetGenerator::FillForwardDependentConfigs() {
+  const Value* value = scope_->GetValue(
+      variables::kForwardDependentConfigsFrom, true);
   if (!value)
     return;
 
-  Target::FileList dest_sources;
-  if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_sources,
-                                  err_))
-    return;
-  target_->swap_in_sources(&dest_sources);
-}
-
-void TargetGenerator::FillData() {
-  // TODO(brettW) hook this up to the constant when we have cleaned up
-  // how data files are used.
-  const Value* value = scope_->GetValue("data", true);
-  if (!value)
+  std::vector<Label> labels;
+  if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
+                           ToolchainLabelForScope(scope_), &labels, err_))
     return;
 
-  Target::FileList dest_data;
-  if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_data,
-                                  err_))
-    return;
-  target_->swap_in_data(&dest_data);
-}
+  const std::vector<const Target*>& deps = target_->deps();
 
-void TargetGenerator::FillDependencies() {
-  FillGenericDeps(variables::kDeps, &Target::swap_in_deps);
-}
-
-void TargetGenerator::FillDataDependencies() {
-  FillGenericDeps(variables::kDatadeps, &Target::swap_in_datadeps);
-}
-
-void TargetGenerator::FillDestDir() {
-  // Destdir is required for all targets that use it.
-  const Value* value = scope_->GetValue("destdir", true);
-  if (!value) {
-    *err_ = Err(function_token_, "This target type requires a \"destdir\".");
-    return;
-  }
-  if (!value->VerifyTypeIs(Value::STRING, err_))
-    return;
-
-  if (!EnsureStringIsInOutputDir(
-          GetBuildSettings()->build_dir(),
-          value->string_value(), *value, err_))
-    return;
-  target_->set_destdir(SourceDir(value->string_value()));
-}
-
-void TargetGenerator::FillScript() {
-  // If this gets called, the target type requires a script, so error out
-  // if it doesn't have one.
-  const Value* value = scope_->GetValue("script", true);
-  if (!value) {
-    *err_ = Err(function_token_, "This target type requires a \"script\".");
-    return;
-  }
-  if (!value->VerifyTypeIs(Value::STRING, err_))
-    return;
-
-  target_->set_script(
-      input_directory_.ResolveRelativeFile(value->string_value()));
-}
-
-void TargetGenerator::FillScriptArgs() {
-  const Value* value = scope_->GetValue("args", true);
-  if (!value)
-    return;
-
-  std::vector<std::string> args;
-  if (!ExtractListOfStringValues(*value, &args, err_))
-    return;
-  target_->swap_in_script_args(&args);
-}
-
-void TargetGenerator::FillOutputs() {
-  const Value* value = scope_->GetValue("outputs", true);
-  if (!value)
-    return;
-
-  Target::FileList outputs;
-  if (!ExtractListOfRelativeFiles(*value, input_directory_, &outputs, err_))
-    return;
-
-  // Validate that outputs are in the output dir.
-  CHECK(outputs.size() == value->list_value().size());
-  for (size_t i = 0; i < outputs.size(); i++) {
-    if (!EnsureStringIsInOutputDir(
-            GetBuildSettings()->build_dir(),
-            outputs[i].value(), value->list_value()[i], err_))
+  // We currently assume that the list is very small and do a brute-force
+  // search in the deps for the labeled target. This could be optimized.
+  std::vector<const Target*> forward_from_list;
+  for (size_t label_index = 0; label_index < labels.size(); label_index++) {
+    const Target* forward_from = NULL;
+    for (size_t dep_index = 0; dep_index < deps.size(); dep_index++) {
+      if (deps[dep_index]->label() == labels[label_index]) {
+        forward_from = deps[dep_index];
+        break;
+      }
+    }
+    if (!forward_from) {
+      *err_ = Err(value->list_value()[label_index],
+          "Can't forward from this target.",
+          "forward_dependent_configs_from must contain a list of labels that\n"
+          "must all appear in the deps of the same target.");
       return;
+    }
+
+    forward_from_list.push_back(forward_from);
   }
-  target_->swap_in_outputs(&outputs);
+
+  target_->swap_in_forward_dependent_configs(&forward_from_list);
 }
 
-const BuildSettings* TargetGenerator::GetBuildSettings() const {
-  return scope_->settings()->build_settings();
-}
+
+
+
+
diff --git a/tools/gn/target_generator.h b/tools/gn/target_generator.h
index faaa1b5..2b16ee0 100644
--- a/tools/gn/target_generator.h
+++ b/tools/gn/target_generator.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "tools/gn/source_dir.h"
 #include "tools/gn/target.h"
@@ -21,14 +20,15 @@
 class Token;
 class Value;
 
-// Creates Target objects from a Scope (the result of a script execution).
+// Fills the variables in a Target object from a Scope (the result of a script
+// execution). Target-type-specific derivations of this class will be used
+// for each different type of function call. This class implements the common
+// behavior.
 class TargetGenerator {
  public:
   TargetGenerator(Target* target,
                   Scope* scope,
                   const Token& function_token,
-                  const std::vector<Value>& args,
-                  const std::string& output_type,
                   Err* err);
   ~TargetGenerator();
 
@@ -42,9 +42,28 @@
                              const std::string& output_type,
                              Err* err);
 
+ protected:
+  // Derived classes implement this to do type-specific generation.
+  virtual void DoRun() = 0;
+
+  const BuildSettings* GetBuildSettings() const;
+
+  void FillSources();
+  void FillConfigs();
+
+  // Sets the current toolchain as a dependecy of this target. All targets with
+  // a dependency on the toolchain should call this function.
+  void SetToolchainDependency();
+
+  Target* target_;
+  Scope* scope_;
+  const Token& function_token_;
+  Err* err_;
+
  private:
-  // Sets err_ on failure.
-  Target::OutputType GetOutputType() const;
+  void FillDependentConfigs();  // Includes all types of dependent configs.
+  void FillData();
+  void FillDependencies();  // Includes data dependencies.
 
   // Reads configs/deps from the given var name, and uses the given setting on
   // the target to save them.
@@ -53,32 +72,7 @@
   void FillGenericDeps(const char* var_name,
                        void (Target::*setter)(std::vector<const Target*>*));
 
-  void FillConfigs();
-  void FillAllDependentConfigs();
-  void FillDirectDependentConfigs();
-  void FillSources();
-  void FillData();
-  void FillDependencies();
-  void FillDataDependencies();
-  void FillDestDir();
-  void FillScript();
-  void FillScriptArgs();
-  void FillOutputs();
-
-  const BuildSettings* GetBuildSettings() const;
-
-  Target* target_;
-  Scope* scope_;
-  const Token& function_token_;
-  std::vector<Value> args_;
-  std::string output_type_;
-  Err* err_;
-
-  // Sources are relative to this. This comes from the input file which doesn't
-  // get freed so we don't acautlly have to make a copy.
-  const SourceDir& input_directory_;
-
-  FRIEND_TEST_ALL_PREFIXES(TargetGenerator, ResolveInputPath);
+  void FillForwardDependentConfigs();
 
   DISALLOW_COPY_AND_ASSIGN(TargetGenerator);
 };
diff --git a/tools/gn/target_manager.cc b/tools/gn/target_manager.cc
index 3b44e57..3a63936 100644
--- a/tools/gn/target_manager.cc
+++ b/tools/gn/target_manager.cc
@@ -99,8 +99,7 @@
   // Keep a record of the guy asking us for this dependency. We know if
   // somebody is adding a dependency, that guy it himself not resolved.
   if (dep_from && target_node->state() != ItemNode::RESOLVED) {
-    ItemNode* from_node =
-        build_settings_->item_tree().GetExistingNodeLocked(dep_from->label());
+    ItemNode* from_node = dep_from->item_node();
     if (!from_node->AddDependency(build_settings_, specified_from_here,
                                   target_node, err))
       return NULL;
diff --git a/tools/gn/token.cc b/tools/gn/token.cc
index cbce5e7..ba59526 100644
--- a/tools/gn/token.cc
+++ b/tools/gn/token.cc
@@ -40,14 +40,6 @@
   return type_ == IDENTIFIER && value_ == v;
 }
 
-bool Token::IsOperatorEqualTo(const char* v) const {
-  return type_ == OPERATOR && value_ == v;
-}
-
-bool Token::IsScoperEqualTo(const char* v) const {
-  return type_ == SCOPER && value_ == v;
-}
-
 bool Token::IsStringEqualTo(const char* v) const {
   return type_ == STRING && value_ == v;
 }
diff --git a/tools/gn/token.h b/tools/gn/token.h
index 64b06ea..25f176b 100644
--- a/tools/gn/token.h
+++ b/tools/gn/token.h
@@ -14,11 +14,41 @@
     INVALID,
     INTEGER,    // 123
     STRING,     // "blah"
-    OPERATOR,   // =, +=, -=, +, -, ==, !=, <=, >=, <, >
+    TRUE_TOKEN,  // Not "TRUE" to avoid collisions with #define in windows.h.
+    FALSE_TOKEN,
+
+    // Various operators.
+    EQUAL,
+    PLUS,
+    MINUS,
+    PLUS_EQUALS,
+    MINUS_EQUALS,
+    EQUAL_EQUAL,
+    NOT_EQUAL,
+    LESS_EQUAL,
+    GREATER_EQUAL,
+    LESS_THAN,
+    GREATER_THAN,
+    BOOLEAN_AND,
+    BOOLEAN_OR,
+    BANG,
+
+    LEFT_PAREN,
+    RIGHT_PAREN,
+    LEFT_BRACKET,
+    RIGHT_BRACKET,
+    LEFT_BRACE,
+    RIGHT_BRACE,
+
+    IF,
+    ELSE,
     IDENTIFIER, // foo
-    SCOPER,     // (, ), [, ], {, }
-    SEPARATOR,  // ,
-    COMMENT     // #...\n
+    COMMA,  // ,
+    COMMENT,    // #...\n
+
+    UNCLASSIFIED_OPERATOR,  // TODO(scottmg): This shouldn't be necessary.
+
+    NUM_TYPES
   };
 
   Token();
@@ -30,13 +60,12 @@
   LocationRange range() const {
     return LocationRange(location_,
                          Location(location_.file(), location_.line_number(),
-                                  location_.char_offset() + value_.size()));
+                                  location_.char_offset() +
+                                      static_cast<int>(value_.size())));
   }
 
   // Helper functions for comparing this token to something.
   bool IsIdentifierEqualTo(const char* v) const;
-  bool IsOperatorEqualTo(const char* v) const;
-  bool IsScoperEqualTo(const char* v) const;
   bool IsStringEqualTo(const char* v) const;
 
   // For STRING tokens, returns the string value (no quotes at end, does
diff --git a/tools/gn/tokenizer.cc b/tools/gn/tokenizer.cc
index 971f56b..6771927 100644
--- a/tools/gn/tokenizer.cc
+++ b/tools/gn/tokenizer.cc
@@ -10,7 +10,7 @@
 namespace {
 
 bool IsNumberChar(char c) {
-  return c == '-' || (c >= '0' && c <= '9');
+  return c >= '0' && c <= '9';
 }
 
 bool CouldBeTwoCharOperatorBegin(char c) {
@@ -31,14 +31,43 @@
   return CouldBeOneCharOperator(c) || CouldBeTwoCharOperatorBegin(c);
 }
 
-bool IsSeparatorChar(char c) {
-  return c == ',';
-}
-
 bool IsScoperChar(char c) {
   return c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}';
 }
 
+Token::Type GetSpecificOperatorType(base::StringPiece value) {
+  if (value == "=")
+    return Token::EQUAL;
+  if (value == "+")
+    return Token::PLUS;
+  if (value == "-")
+    return Token::MINUS;
+  if (value == "+=")
+    return Token::PLUS_EQUALS;
+  if (value == "-=")
+    return Token::MINUS_EQUALS;
+  if (value == "==")
+    return Token::EQUAL_EQUAL;
+  if (value == "!=")
+    return Token::NOT_EQUAL;
+  if (value == "<=")
+    return Token::LESS_EQUAL;
+  if (value == ">=")
+    return Token::GREATER_EQUAL;
+  if (value == "<")
+    return Token::LESS_THAN;
+  if (value == ">")
+    return Token::GREATER_THAN;
+  if (value == "&&")
+    return Token::BOOLEAN_AND;
+  if (value == "||")
+    return Token::BOOLEAN_OR;
+  if (value == "!")
+    return Token::BANG;
+  NOTREACHED();
+  return Token::INVALID;
+}
+
 }  // namespace
 
 Tokenizer::Tokenizer(const InputFile* input_file, Err* err)
@@ -60,7 +89,7 @@
 }
 
 std::vector<Token> Tokenizer::Run() {
-  std::vector<Token> tokens;
+  DCHECK(tokens_.empty());
   while (!done()) {
     AdvanceToNextToken();
     if (done())
@@ -78,21 +107,32 @@
       break;
     size_t token_end = cur_;
 
+    base::StringPiece token_value(&input_.data()[token_begin],
+                                  token_end - token_begin);
+
+    if (type == Token::UNCLASSIFIED_OPERATOR)
+      type = GetSpecificOperatorType(token_value);
+    if (type == Token::IDENTIFIER) {
+      if (token_value == "if")
+        type = Token::IF;
+      else if (token_value == "else")
+        type = Token::ELSE;
+      else if (token_value == "true")
+        type = Token::TRUE_TOKEN;
+      else if (token_value == "false")
+        type = Token::FALSE_TOKEN;
+    }
+
     // TODO(brettw) This just strips comments from the token stream. This
     // is probably wrong, they should be removed at a later stage so we can
     // do things like rewrite the file. But this makes the parser simpler and
     // is OK for now.
-    if (type != Token::COMMENT) {
-      tokens.push_back(Token(
-          location,
-          type,
-          base::StringPiece(&input_.data()[token_begin],
-                            token_end - token_begin)));
-    }
+    if (type != Token::COMMENT)
+      tokens_.push_back(Token(location, type, token_value));
   }
   if (err_->has_error())
-    tokens.clear();
-  return tokens;
+    tokens_.clear();
+  return tokens_;
 }
 
 // static
@@ -139,16 +179,26 @@
 
   // Note: '-' handled specially below.
   if (next_char != '-' && CouldBeOperator(next_char))
-    return Token::OPERATOR;
+    return Token::UNCLASSIFIED_OPERATOR;
 
   if (IsIdentifierFirstChar(next_char))
     return Token::IDENTIFIER;
 
-  if (IsScoperChar(next_char))
-    return Token::SCOPER;
+  if (next_char == '[')
+    return Token::LEFT_BRACKET;
+  if (next_char == ']')
+    return Token::RIGHT_BRACKET;
+  if (next_char == '(')
+    return Token::LEFT_PAREN;
+  if (next_char == ')')
+    return Token::RIGHT_PAREN;
+  if (next_char == '{')
+    return Token::LEFT_BRACE;
+  if (next_char == '}')
+    return Token::RIGHT_BRACE;
 
-  if (IsSeparatorChar(next_char))
-    return Token::SEPARATOR;
+  if (next_char == ',')
+    return Token::COMMA;
 
   if (next_char == '#')
     return Token::COMMENT;
@@ -157,11 +207,12 @@
   // else.
   if (next_char == '-') {
     if (!CanIncrement())
-      return Token::OPERATOR;  // Just the minus before end of file.
+      return Token::UNCLASSIFIED_OPERATOR;  // Just the minus before end of
+                                            // file.
     char following_char = input_[cur_ + 1];
     if (following_char >= '0' && following_char <= '9')
       return Token::INTEGER;
-    return Token::OPERATOR;
+    return Token::UNCLASSIFIED_OPERATOR;
   }
 
   return Token::INVALID;
@@ -179,7 +230,7 @@
         // or operator.
         char c = cur_char();
         if (!IsCurrentWhitespace() && !CouldBeOperator(c) &&
-            !IsScoperChar(c) && !IsSeparatorChar(c)) {
+            !IsScoperChar(c) && c != ',') {
           *err_ = Err(GetCurrentLocation(),
               "This is not a valid number.",
               "Learn to count.");
@@ -213,7 +264,7 @@
       break;
     }
 
-    case Token::OPERATOR:
+    case Token::UNCLASSIFIED_OPERATOR:
       // Some operators are two characters, some are one.
       if (CouldBeTwoCharOperatorBegin(cur_char())) {
         if (CanIncrement() && CouldBeTwoCharOperatorEnd(input_[cur_ + 1]))
@@ -227,8 +278,13 @@
         Advance();
       break;
 
-    case Token::SCOPER:
-    case Token::SEPARATOR:
+    case Token::LEFT_BRACKET:
+    case Token::RIGHT_BRACKET:
+    case Token::LEFT_BRACE:
+    case Token::RIGHT_BRACE:
+    case Token::LEFT_PAREN:
+    case Token::RIGHT_PAREN:
+    case Token::COMMA:
       Advance();  // All are one char.
       break;
 
@@ -239,6 +295,7 @@
       break;
 
     case Token::INVALID:
+    default:
       *err_ = Err(location, "Everything is all messed up",
                   "Please insert system disk in drive A: and press any key.");
       NOTREACHED();
diff --git a/tools/gn/tokenizer.h b/tools/gn/tokenizer.h
index 5e00169..b1c0cc1 100644
--- a/tools/gn/tokenizer.h
+++ b/tools/gn/tokenizer.h
@@ -72,6 +72,8 @@
 
   bool has_error() const { return err_->has_error(); }
 
+  std::vector<Token> tokens_;
+
   const InputFile* input_file_;
   const base::StringPiece input_;
   Err* err_;
diff --git a/tools/gn/tokenizer_unittest.cc b/tools/gn/tokenizer_unittest.cc
index d1a6788..b02db90 100644
--- a/tools/gn/tokenizer_unittest.cc
+++ b/tools/gn/tokenizer_unittest.cc
@@ -44,7 +44,7 @@
   EXPECT_TRUE(results.empty());
 
   InputFile whitespace_input(SourceFile("/test"));
-  whitespace_input.SetContents("  \n\r");
+  whitespace_input.SetContents("  \r \n \r\n");
 
   results = Tokenizer::Tokenize(&whitespace_input, &err);
   EXPECT_TRUE(results.empty());
@@ -65,6 +65,14 @@
   EXPECT_TRUE(CheckTokenizer("  123 -123 ", integers));
 }
 
+TEST(Tokenizer, IntegerNoSpace) {
+  TokenExpectation integers[] = {
+    { Token::INTEGER, "123" },
+    { Token::INTEGER, "-123" }
+  };
+  EXPECT_TRUE(CheckTokenizer("  123-123 ", integers));
+}
+
 TEST(Tokenizer, String) {
   TokenExpectation strings[] = {
     { Token::STRING, "\"foo\"" },
@@ -77,30 +85,33 @@
 
 TEST(Tokenizer, Operator) {
   TokenExpectation operators[] = {
-    { Token::OPERATOR, "-" },
-    { Token::OPERATOR, "+" },
-    { Token::OPERATOR, "=" },
-    { Token::OPERATOR, "+=" },
-    { Token::OPERATOR, "-=" },
-    { Token::OPERATOR, "!=" },
-    { Token::OPERATOR, "==" },
-    { Token::OPERATOR, "<" },
-    { Token::OPERATOR, ">" },
-    { Token::OPERATOR, "<=" },
-    { Token::OPERATOR, ">=" },
+    { Token::MINUS, "-" },
+    { Token::PLUS, "+" },
+    { Token::EQUAL, "=" },
+    { Token::PLUS_EQUALS, "+=" },
+    { Token::MINUS_EQUALS, "-=" },
+    { Token::NOT_EQUAL, "!=" },
+    { Token::EQUAL_EQUAL, "==" },
+    { Token::LESS_THAN, "<" },
+    { Token::GREATER_THAN, ">" },
+    { Token::LESS_EQUAL, "<=" },
+    { Token::GREATER_EQUAL, ">=" },
+    { Token::BANG, "!" },
+    { Token::BOOLEAN_OR, "||" },
+    { Token::BOOLEAN_AND, "&&" },
   };
-  EXPECT_TRUE(CheckTokenizer("- + = += -= != ==  < > <= >=",
+  EXPECT_TRUE(CheckTokenizer("- + = += -= != ==  < > <= >= ! || &&",
               operators));
 }
 
 TEST(Tokenizer, Scoper) {
   TokenExpectation scopers[] = {
-    { Token::SCOPER, "{" },
-    { Token::SCOPER, "[" },
-    { Token::SCOPER, "]" },
-    { Token::SCOPER, "}" },
-    { Token::SCOPER, "(" },
-    { Token::SCOPER, ")" },
+    { Token::LEFT_BRACE, "{" },
+    { Token::LEFT_BRACKET, "[" },
+    { Token::RIGHT_BRACKET, "]" },
+    { Token::RIGHT_BRACE, "}" },
+    { Token::LEFT_PAREN, "(" },
+    { Token::RIGHT_PAREN, ")" },
   };
   EXPECT_TRUE(CheckTokenizer("{[ ]} ()", scopers));
 }
@@ -108,14 +119,14 @@
 TEST(Tokenizer, FunctionCall) {
   TokenExpectation fn[] = {
     { Token::IDENTIFIER, "fun" },
-    { Token::SCOPER, "(" },
+    { Token::LEFT_PAREN, "(" },
     { Token::STRING, "\"foo\"" },
-    { Token::SCOPER, ")" },
-    { Token::SCOPER, "{" },
+    { Token::RIGHT_PAREN, ")" },
+    { Token::LEFT_BRACE, "{" },
     { Token::IDENTIFIER, "foo" },
-    { Token::OPERATOR, "=" },
+    { Token::EQUAL, "=" },
     { Token::INTEGER, "12" },
-    { Token::SCOPER, "}" },
+    { Token::RIGHT_BRACE, "}" },
   };
   EXPECT_TRUE(CheckTokenizer("fun(\"foo\") {\nfoo = 12}", fn));
 }
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc
index d906b9a..cf9bfdb 100644
--- a/tools/gn/toolchain.cc
+++ b/tools/gn/toolchain.cc
@@ -5,6 +5,7 @@
 #include "tools/gn/toolchain.h"
 
 #include "base/logging.h"
+#include "tools/gn/value.h"
 
 const char* Toolchain::kToolCc = "cc";
 const char* Toolchain::kToolCxx = "cxx";
@@ -23,7 +24,7 @@
 Toolchain::Tool::~Tool() {
 }
 
-Toolchain::Toolchain(const Label& label) : Item(label) {
+Toolchain::Toolchain(const Label& label) : Item(label), is_default_(false) {
 }
 
 Toolchain::~Toolchain() {
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h
index 5223a05..b00c113 100644
--- a/tools/gn/toolchain.h
+++ b/tools/gn/toolchain.h
@@ -8,6 +8,8 @@
 #include "base/compiler_specific.h"
 #include "base/strings/string_piece.h"
 #include "tools/gn/item.h"
+#include "tools/gn/scope.h"
+#include "tools/gn/value.h"
 
 // Holds information on a specific toolchain. This data is filled in when we
 // encounter a toolchain definition.
@@ -87,9 +89,22 @@
   const std::string& environment() const { return environment_; }
   void set_environment(const std::string& env) { environment_ = env; }
 
+  bool is_default() const { return is_default_; }
+  void set_is_default(bool id) { is_default_ = id; }
+
+  // Specifies build argument overrides that will be set on the base scope. It
+  // will be as if these arguments were passed in on the command line. This
+  // allows a toolchain to override the OS type of the default toolchain or
+  // pass in other settings.
+  Scope::KeyValueMap& args() { return args_; }
+  const Scope::KeyValueMap& args() const { return args_; }
+
  private:
   Tool tools_[TYPE_NUMTYPES];
 
+  bool is_default_;
+  Scope::KeyValueMap args_;
+
   std::string environment_;
 };
 
diff --git a/tools/gn/toolchain_manager.cc b/tools/gn/toolchain_manager.cc
index f292626..3e84530 100644
--- a/tools/gn/toolchain_manager.cc
+++ b/tools/gn/toolchain_manager.cc
@@ -17,44 +17,70 @@
 #include "tools/gn/scope.h"
 #include "tools/gn/scope_per_file_provider.h"
 
+// How toolchain loading works
+// ---------------------------
+// When we start loading a build, we'll load the build config file and that
+// will call set_default_toolchain. We'll schedule a load of the file
+// containing the default toolchain definition, and can do this in parallel
+// with all other build files. Targets will have an implicit dependency on the
+// toolchain so we won't write out any files until we've loaded the toolchain
+// definition.
+//
+// When we see a reference to a target using a different toolchain, it gets
+// more complicated. In this case, the toolchain definition contains arguments
+// to pass into the build config file when it is invoked in the context of that
+// toolchain. As a result, we have to actually see the definition of the
+// toolchain before doing anything else.
+//
+// So when we see a reference to a non-default toolchain we do the following:
+//
+//  1. Schedule a load of the file containing the toolchain definition, if it
+//     isn't loaded already.
+//  2. When the toolchain definition is loaded, we schedule a load of the
+//     build config file in the context of that toolchain. We'll use the
+//     arguments from the toolchain definition to execute it.
+//  3. When the build config is set up, then we can load all of the individual
+//     buildfiles in the context of that config that we require.
+
 namespace {
 
+enum ToolchainState {
+  // Toolchain settings have not requested to be loaded. This means we
+  // haven't seen any targets that require this toolchain yet. This means that
+  // we have seen a toolchain definition, but no targets that use it. Not
+  // loading the settings automatically allows you to define a bunch of
+  // toolchains and potentially not use them without much overhead.
+  TOOLCHAIN_NOT_LOADED,
+
+  // The toolchain definition for non-default toolchains has been scheduled
+  // to be loaded but has not completed. When this is done, we can load the
+  // settings file. This is needed to get the arguments out of the toolchain
+  // definition. This is skipped for the default toolchain which has no
+  // arguments (see summary above).
+  TOOLCHAIN_DEFINITION_LOADING,
+
+  // The settings have been scheduled to be loaded but have not completed.
+  TOOLCHAIN_SETTINGS_LOADING,
+
+  // The settings are done being loaded.
+  TOOLCHAIN_SETTINGS_LOADED
+};
+
 SourceFile DirToBuildFile(const SourceDir& dir) {
   return SourceFile(dir.value() + "BUILD.gn");
 }
 
-void SetSystemVars(const Settings& settings, Scope* scope) {
-#if defined(OS_WIN)
-  scope->SetValue("is_win", Value(NULL, 1), NULL);
-  scope->SetValue("is_posix", Value(NULL, 0), NULL);
-#else
-  scope->SetValue("is_win", Value(NULL, 0), NULL);
-  scope->SetValue("is_posix", Value(NULL, 1), NULL);
-#endif
-
-#if defined(OS_MACOSX)
-  scope->SetValue("is_mac", Value(NULL, 1), NULL);
-#else
-  scope->SetValue("is_mac", Value(NULL, 0), NULL);
-#endif
-
-#if defined(OS_LINUX)
-  scope->SetValue("is_linux", Value(NULL, 1), NULL);
-#else
-  scope->SetValue("is_linux", Value(NULL, 0), NULL);
-#endif
-}
-
 }  // namespace
 
 struct ToolchainManager::Info {
   Info(const BuildSettings* build_settings,
        const Label& toolchain_name,
        const std::string& output_subdir_name)
-      : state(TOOLCHAIN_SETTINGS_NOT_LOADED),
+      : state(TOOLCHAIN_NOT_LOADED),
         toolchain(toolchain_name),
         toolchain_set(false),
         settings(build_settings, &toolchain, output_subdir_name),
+        toolchain_file_loaded(false),
         item_node(NULL) {
   }
 
@@ -73,12 +99,17 @@
     }
   }
 
-  SettingsState state;
+  ToolchainState state;
 
   Toolchain toolchain;
   bool toolchain_set;
   LocationRange toolchain_definition_location;
 
+  // The first place in the build that we saw a reference for this toolchain.
+  // This allows us to report errors if it can't be loaded and blame some
+  // reasonable place of the code. This will be empty for the default toolchain.
+  LocationRange specified_from;
+
   // When the state is TOOLCHAIN_SETTINGS_LOADED, the settings should be
   // considered read-only and can be read without locking. Otherwise, they
   // should not be accessed at all except to load them (which can therefore
@@ -86,12 +117,18 @@
   // is only ever read or written inside the lock.
   Settings settings;
 
-  // While state == TOOLCHAIN_SETTINGS_LOADING, this will collect all
-  // scheduled invocations using this toolchain. They'll be issued once the
-  // settings file has been interpreted.
+  // Set when the file corresponding to the toolchain definition is loaded.
+  // This will normally be set right after "toolchain_set". However, if the
+  // toolchain definition is missing, the file might be marked loaded but the
+  // toolchain definition could still be unset.
+  bool toolchain_file_loaded;
+
+  // While state == TOOLCHAIN_SETTINGS_LOADING || TOOLCHAIN_DEFINITION_LOADING,
+  // this will collect all scheduled invocations using this toolchain. They'll
+  // be issued once the settings file has been interpreted.
   //
   // The map maps the source file to "some" location it was invoked from (so
-  // we can give good error messages. It does NOT map to the root of the
+  // we can give good error messages). It does NOT map to the root of the
   // file to be invoked (the file still needs loading). This will be NULL
   // for internally invoked files.
   typedef std::map<SourceFile, LocationRange> ScheduledInvocationMap;
@@ -131,16 +168,8 @@
   info->scheduled_invocations[build_file_name] = LocationRange();
   info->all_invocations.insert(build_file_name);
 
-  g_scheduler->IncrementWorkCount();
-  if (!g_scheduler->input_file_manager()->AsyncLoadFile(
-           LocationRange(), build_settings_,
-           build_settings_->build_config_file(),
-           base::Bind(&ToolchainManager::BackgroundLoadBuildConfig,
-                      base::Unretained(this), info, true),
-           &err)) {
+  if (!ScheduleBuildConfigLoadLocked(info, true, &err))
     g_scheduler->FailWithError(err);
-    g_scheduler->DecrementWorkCount();
-  }
 }
 
 const Settings* ToolchainManager::GetSettingsForToolchainLocked(
@@ -233,7 +262,12 @@
   // The labels should match or else we're setting the wrong one!
   CHECK(info->toolchain.label() == tc.label());
 
+  // Save the toolchain. We can just overwrite our definition, but we need to
+  // be careful to preserve the is_default flag.
+  bool is_default = info->toolchain.is_default();
   info->toolchain = tc;
+  info->toolchain.set_is_default(is_default);
+
   if (info->toolchain_set) {
     *err = Err(defined_from, "Duplicate toolchain definition.");
     err->AppendSubErr(Err(
@@ -290,54 +324,42 @@
 
   info->all_invocations.insert(build_file);
 
-  // True if the settings load needs to be scheduled.
-  bool info_needs_settings_load = false;
-
-  // True if the settings load has completed.
-  bool info_settings_loaded = false;
-
   switch (info->state) {
-    case TOOLCHAIN_SETTINGS_NOT_LOADED:
-      info_needs_settings_load = true;
+    case TOOLCHAIN_NOT_LOADED:
+      // Toolchain needs to be loaded. Start loading it and push this buildfile
+      // on the wait queue. The actual toolchain build file will have been
+      // scheduled to be loaded by LoadNewToolchainLocked() above, so we just
+      // need to request that the build settings be loaded when that toolchain
+      // file is done executing (recall toolchain files are executed in the
+      // context of the default toolchain, which is why we need to do the extra
+      // Info lookup in the make_pair).
+      DCHECK(!default_toolchain_.is_null());
+      pending_build_config_map_[
+              std::make_pair(DirToBuildFile(toolchain_name.dir()),
+                             toolchains_[default_toolchain_])] =
+          info;
       info->scheduled_invocations[build_file] = specified_from;
-      break;
 
+      // Transition to the loading state.
+      info->specified_from = specified_from;
+      info->state = TOOLCHAIN_DEFINITION_LOADING;
+      return true;
+
+    case TOOLCHAIN_DEFINITION_LOADING:
     case TOOLCHAIN_SETTINGS_LOADING:
+      // Toolchain is in the process of loading, push this buildfile on the
+      // wait queue to run when the config is ready.
       info->scheduled_invocations[build_file] = specified_from;
-      break;
+      return true;
 
     case TOOLCHAIN_SETTINGS_LOADED:
-      info_settings_loaded = true;
-      break;
-  }
+      // Everything is ready, just schedule the build file to load.
+      return ScheduleBackgroundInvoke(info, specified_from, build_file, err);
 
-  if (info_needs_settings_load) {
-    // Load the settings file.
-    g_scheduler->IncrementWorkCount();
-    if (!g_scheduler->input_file_manager()->AsyncLoadFile(
-             specified_from, build_settings_,
-             build_settings_->build_config_file(),
-             base::Bind(&ToolchainManager::BackgroundLoadBuildConfig,
-                        base::Unretained(this), info, false),
-             err)) {
-      g_scheduler->DecrementWorkCount();
+    default:
+      NOTREACHED();
       return false;
-    }
-  } else if (info_settings_loaded) {
-    // Settings are ready to go, load the target file.
-    g_scheduler->IncrementWorkCount();
-    if (!g_scheduler->input_file_manager()->AsyncLoadFile(
-             specified_from, build_settings_, build_file,
-             base::Bind(&ToolchainManager::BackgroundInvoke,
-                        base::Unretained(this), info, build_file),
-             err)) {
-      g_scheduler->DecrementWorkCount();
-      return false;
-    }
   }
-  // Else we should have added the infocations to the scheduled_invocations
-  // from within the lock above.
-  return true;
 }
 
 // static
@@ -401,6 +423,7 @@
   // the build config can not change the toolchain, so we won't be overwriting
   // anything useful.
   info->toolchain = Toolchain(default_toolchain_);
+  info->toolchain.set_is_default(true);
   info->EnsureItemNode();
 
   // The default toolchain is loaded in greedy mode so all targets we
@@ -416,6 +439,42 @@
     g_scheduler->FailWithError(err);
 }
 
+bool ToolchainManager::ScheduleBackgroundInvoke(
+    Info* info,
+    const LocationRange& specified_from,
+    const SourceFile& build_file,
+    Err* err) {
+  g_scheduler->IncrementWorkCount();
+  if (!g_scheduler->input_file_manager()->AsyncLoadFile(
+           specified_from, build_settings_, build_file,
+           base::Bind(&ToolchainManager::BackgroundInvoke,
+                      base::Unretained(this), info, build_file),
+           err)) {
+    g_scheduler->DecrementWorkCount();
+    return false;
+  }
+  return true;
+}
+
+bool ToolchainManager::ScheduleBuildConfigLoadLocked(Info* info,
+                                                     bool is_default,
+                                                     Err* err) {
+  GetLock().AssertAcquired();
+
+  g_scheduler->IncrementWorkCount();
+  if (!g_scheduler->input_file_manager()->AsyncLoadFile(
+           info->specified_from, build_settings_,
+           build_settings_->build_config_file(),
+           base::Bind(&ToolchainManager::BackgroundLoadBuildConfig,
+                      base::Unretained(this), info, is_default),
+           err)) {
+    g_scheduler->DecrementWorkCount();
+    return false;
+  }
+  info->state = TOOLCHAIN_SETTINGS_LOADING;
+  return true;
+}
+
 void ToolchainManager::BackgroundLoadBuildConfig(Info* info,
                                                  bool is_default,
                                                  const ParseNode* root) {
@@ -424,7 +483,11 @@
     // Nobody should be accessing settings at this point other than us since we
     // haven't marked it loaded, so we can do it outside the lock.
     Scope* base_config = info->settings.base_config();
-    SetSystemVars(info->settings, base_config);
+    base_config->set_source_dir(SourceDir("//"));
+
+    info->settings.build_settings()->build_args().SetupRootScope(base_config,
+        info->settings.toolchain()->args());
+
     base_config->SetProcessingBuildConfig();
     if (is_default)
       base_config->SetProcessingDefaultBuildConfig();
@@ -454,15 +517,8 @@
       // want to load them in parallel on the pool.
       for (Info::ScheduledInvocationMap::iterator i = schedule_these.begin();
            i != schedule_these.end() && !g_scheduler->is_failed(); ++i) {
-        // Note i->second may be NULL, so don't dereference.
-        g_scheduler->IncrementWorkCount();
-        if (!g_scheduler->input_file_manager()->AsyncLoadFile(
-                 i->second, build_settings_, i->first,
-                 base::Bind(&ToolchainManager::BackgroundInvoke,
-                            base::Unretained(this), info, i->first),
-                 &err)) {
+        if (!ScheduleBackgroundInvoke(info, i->second, i->first, &err)) {
           g_scheduler->FailWithError(err);
-          g_scheduler->DecrementWorkCount();
           break;
         }
       }
@@ -482,11 +538,32 @@
 
     Scope our_scope(info->settings.base_config());
     ScopePerFileProvider per_file_provider(&our_scope, file_name);
+    our_scope.set_source_dir(file_name.GetDir());
 
     Err err;
     root->Execute(&our_scope, &err);
     if (err.has_error())
       g_scheduler->FailWithError(err);
+
+    {
+      // Check to see if any build config invocations depend on this file and
+      // invoke them.
+      base::AutoLock lock(GetLock());
+      BuildConfigInvokeMap::iterator found_file =
+          pending_build_config_map_.find(std::make_pair(file_name, info));
+      if (found_file != pending_build_config_map_.end()) {
+        // The toolchain state should be waiting on the definition, which
+        // should be the thing we just loaded.
+        Info* info_to_load = found_file->second;
+        DCHECK(info_to_load->state == TOOLCHAIN_DEFINITION_LOADING);
+        DCHECK(!info_to_load->toolchain_file_loaded);
+        info_to_load->toolchain_file_loaded = true;
+
+        if (!ScheduleBuildConfigLoadLocked(info_to_load, false, &err))
+          g_scheduler->FailWithError(err);
+        pending_build_config_map_.erase(found_file);
+      }
+    }
   }
 
   g_scheduler->DecrementWorkCount();
diff --git a/tools/gn/toolchain_manager.h b/tools/gn/toolchain_manager.h
index 3ecb16d..9e75f33 100644
--- a/tools/gn/toolchain_manager.h
+++ b/tools/gn/toolchain_manager.h
@@ -102,20 +102,6 @@
                                 Err* err);
 
  private:
-  enum SettingsState {
-    // Toolchain settings have not requested to be loaded. This means we
-    // haven't seen any targets that require this toolchain yet. Not loading
-    // the settings automatically allows you to define a bunch of toolchains
-    // and potentially not use them without much overhead.
-    TOOLCHAIN_SETTINGS_NOT_LOADED,
-
-    // The settings have been scheduled to be loaded but have not completed.
-    TOOLCHAIN_SETTINGS_LOADING,
-
-    // The settings are done being loaded.
-    TOOLCHAIN_SETTINGS_LOADED
-  };
-
   struct Info;
 
   static std::string ToolchainToOutputSubdir(const Label& toolchain_name);
@@ -138,11 +124,18 @@
   // hasn't been set. See the StartLoading() implementation for more.
   void FixupDefaultToolchainLocked();
 
-  // Loads the base config for the given toolchain. Run on a background thread
-  // asynchronously.
-  void BackgroundLoadBuildConfig(Info* info,
-                                 bool is_default,
-                                 const ParseNode* root);
+  // Schedules the buildfile to be invoked for the given toolchain info. The
+  // toolchain must be already loaded. Can be called with the lock held or not
+  // (it does not use any class vars).
+  bool ScheduleBackgroundInvoke(Info* info,
+                                const LocationRange& specified_from,
+                                const SourceFile& build_file,
+                                Err* err);
+
+  // Schedules the build config file for the given info to be loaded and
+  // invoked. The toolchain definition (for non-default toolchains) should
+  // already be loaded.
+  bool ScheduleBuildConfigLoadLocked(Info* info, bool is_default, Err* err);
 
   // Invokes the given file for a toolchain with loaded settings. Run on a
   // background thread asynchronously.
@@ -150,6 +143,11 @@
                         const SourceFile& file_name,
                         const ParseNode* root);
 
+  // Loads the build config file for the given Info.
+  void BackgroundLoadBuildConfig(Info* info,
+                                 bool is_default,
+                                 const ParseNode* root);
+
   // Returns the lock to use.
   base::Lock& GetLock() const;
 
@@ -162,6 +160,10 @@
   Label default_toolchain_;
   LocationRange default_toolchain_defined_here_;
 
+  typedef std::map<std::pair<SourceFile, const Info*>, Info*>
+      BuildConfigInvokeMap;
+  BuildConfigInvokeMap pending_build_config_map_;
+
   DISALLOW_COPY_AND_ASSIGN(ToolchainManager);
 };
 
diff --git a/tools/gn/value.cc b/tools/gn/value.cc
index cb78faa..a8abee4 100644
--- a/tools/gn/value.cc
+++ b/tools/gn/value.cc
@@ -18,15 +18,31 @@
       origin_(origin) {
 }
 
+Value::Value(const ParseNode* origin, bool bool_val)
+    : type_(BOOLEAN),
+      boolean_value_(bool_val),
+      int_value_(0),
+      origin_(origin) {
+}
+
 Value::Value(const ParseNode* origin, int64 int_val)
     : type_(INTEGER),
+      boolean_value_(false),
       int_value_(int_val),
       origin_(origin) {
 }
 
-Value::Value(const ParseNode* origin, const base::StringPiece& str_val)
+Value::Value(const ParseNode* origin, std::string str_val)
     : type_(STRING),
-      string_value_(str_val.as_string()),
+      string_value_(),
+      int_value_(0),
+      origin_(origin) {
+  string_value_.swap(str_val);
+}
+
+Value::Value(const ParseNode* origin, const char* str_val)
+    : type_(STRING),
+      string_value_(str_val),
       int_value_(0),
       origin_(origin) {
 }
@@ -39,6 +55,8 @@
   switch (t) {
     case NONE:
       return "none";
+    case BOOLEAN:
+      return "boolean";
     case INTEGER:
       return "integer";
     case STRING:
@@ -51,38 +69,24 @@
   }
 }
 
-int64 Value::InterpretAsInt() const {
-  switch (type_) {
-    case NONE:
-      return 0;
-    case INTEGER:
-      return int_value_;
-    case STRING:
-      return string_value_.empty() ? 0 : 1;
-    case LIST:
-      return list_value_.empty() ? 0 : 1;
-  }
-  return 0;
-}
-
-std::string Value::ToString() const {
+std::string Value::ToString(bool quote_string) const {
   switch (type_) {
     case NONE:
       return "<void>";
+    case BOOLEAN:
+      return boolean_value_ ? "true" : "false";
     case INTEGER:
       return base::Int64ToString(int_value_);
     case STRING:
+      if (quote_string)
+        return "\"" + string_value_ + "\"";
       return string_value_;
     case LIST: {
       std::string result = "[";
       for (size_t i = 0; i < list_value_.size(); i++) {
         if (i > 0)
           result += ", ";
-        // TODO(brettw) maybe also want to escape quotes in the string.
-        if (list_value_[i].type() == STRING)
-          result += std::string("\"") + list_value_[i].ToString() + "\"";
-        else
-          result += list_value_[i].ToString();
+        result += list_value_[i].ToString(true);
       }
       result.push_back(']');
       return result;
@@ -104,6 +108,8 @@
     return false;
 
   switch (type_) {
+    case Value::BOOLEAN:
+      return boolean_value() == other.boolean_value();
     case Value::INTEGER:
       return int_value() == other.int_value();
     case Value::STRING:
diff --git a/tools/gn/value.h b/tools/gn/value.h
index 8802bff..952f52a 100644
--- a/tools/gn/value.h
+++ b/tools/gn/value.h
@@ -17,6 +17,7 @@
  public:
   enum Type {
     NONE = 0,
+    BOOLEAN,
     INTEGER,
     STRING,
     LIST
@@ -24,8 +25,10 @@
 
   Value();
   Value(const ParseNode* origin, Type t);
+  Value(const ParseNode* origin, bool bool_val);
   Value(const ParseNode* origin, int64 int_val);
-  Value(const ParseNode* origin, const base::StringPiece& str_val);
+  Value(const ParseNode* origin, std::string str_val);
+  Value(const ParseNode* origin, const char* str_val);
   ~Value();
 
   Type type() const { return type_; }
@@ -37,6 +40,15 @@
   const ParseNode* origin() const { return origin_; }
   void set_origin(const ParseNode* o) { origin_ = o; }
 
+  bool& boolean_value() {
+    DCHECK(type_ == BOOLEAN);
+    return boolean_value_;
+  }
+  const bool& boolean_value() const {
+    DCHECK(type_ == BOOLEAN);
+    return boolean_value_;
+  }
+
   int64& int_value() {
     DCHECK(type_ == INTEGER);
     return int_value_;
@@ -64,13 +76,9 @@
     return list_value_;
   }
 
-  // Returns the current value converted to an int, normally used for
-  // boolean operations. Undefined variables, empty lists, and empty strings
-  // are all interpreted as 0, otherwise 1.
-  int64 InterpretAsInt() const;
-
-  // Converts the given value to a string.
-  std::string ToString() const;
+  // Converts the given value to a string. Returns true if strings should be
+  // quoted or the ToString of a string should be the string itself.
+  std::string ToString(bool quote_strings) const;
 
   // Verifies that the value is of the given type. If it isn't, returns
   // false and sets the error.
@@ -83,6 +91,7 @@
  private:
   Type type_;
   std::string string_value_;
+  bool boolean_value_;
   int64 int_value_;
   std::vector<Value> list_value_;
   const ParseNode* origin_;
diff --git a/tools/gn/value_extractors.cc b/tools/gn/value_extractors.cc
index 56a2be2..c2ca285 100644
--- a/tools/gn/value_extractors.cc
+++ b/tools/gn/value_extractors.cc
@@ -4,6 +4,7 @@
 
 #include "tools/gn/value_extractors.h"
 
+#include "tools/gn/build_settings.h"
 #include "tools/gn/err.h"
 #include "tools/gn/label.h"
 #include "tools/gn/source_dir.h"
@@ -14,12 +15,16 @@
 // This extractor rejects files with system-absolute file paths. If we need
 // that in the future, we'll have to add some flag to control this.
 struct RelativeFileConverter {
-  RelativeFileConverter(const SourceDir& current_dir_in)
-      : current_dir(current_dir_in) {}
+  RelativeFileConverter(const BuildSettings* build_settings_in,
+                        const SourceDir& current_dir_in)
+      : build_settings(build_settings_in),
+        current_dir(current_dir_in) {
+  }
   bool operator()(const Value& v, SourceFile* out, Err* err) const {
     if (!v.VerifyTypeIs(Value::STRING, err))
       return false;
-    *out = current_dir.ResolveRelativeFile(v.string_value());
+    *out = current_dir.ResolveRelativeFile(v.string_value(),
+                                           build_settings->root_path_utf8());
     if (out->is_system_absolute()) {
       *err = Err(v, "System-absolute file path.",
           "You can't list a system-absolute file path here. Please include "
@@ -29,18 +34,24 @@
     }
     return true;
   }
+  const BuildSettings* build_settings;
   const SourceDir& current_dir;
 };
 
 struct RelativeDirConverter {
-  RelativeDirConverter(const SourceDir& current_dir_in)
-      : current_dir(current_dir_in) {}
+  RelativeDirConverter(const BuildSettings* build_settings_in,
+                       const SourceDir& current_dir_in)
+      : build_settings(build_settings_in),
+        current_dir(current_dir_in) {
+  }
   bool operator()(const Value& v, SourceDir* out, Err* err) const {
     if (!v.VerifyTypeIs(Value::STRING, err))
       return false;
-    *out = current_dir.ResolveRelativeDir(v.string_value());
+    *out = current_dir.ResolveRelativeDir(v.string_value(),
+                                          build_settings->root_path_utf8());
     return true;
   }
+  const BuildSettings* build_settings;
   const SourceDir& current_dir;
 };
 
@@ -76,20 +87,22 @@
   return true;
 }
 
-bool ExtractListOfRelativeFiles(const Value& value,
+bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
+                                const Value& value,
                                 const SourceDir& current_dir,
                                 std::vector<SourceFile>* files,
                                 Err* err) {
   return ListValueExtractor(value, files, err,
-                            RelativeFileConverter(current_dir));
+                            RelativeFileConverter(build_settings, current_dir));
 }
 
-bool ExtractListOfRelativeDirs(const Value& value,
+bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
+                               const Value& value,
                                const SourceDir& current_dir,
                                std::vector<SourceDir>* dest,
                                Err* err) {
   return ListValueExtractor(value, dest, err,
-                            RelativeDirConverter(current_dir));
+                            RelativeDirConverter(build_settings, current_dir));
 }
 
 bool ExtractListOfLabels(const Value& value,
diff --git a/tools/gn/value_extractors.h b/tools/gn/value_extractors.h
index 556f44f..12fff00 100644
--- a/tools/gn/value_extractors.h
+++ b/tools/gn/value_extractors.h
@@ -10,6 +10,7 @@
 
 #include "tools/gn/value.h"
 
+class BuildSettings;
 class Err;
 class Label;
 class SourceDir;
@@ -37,13 +38,15 @@
                                Err* err);
 
 // Looks for a list of source files relative to a given current dir.
-bool ExtractListOfRelativeFiles(const Value& value,
+bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
+                                const Value& value,
                                 const SourceDir& current_dir,
                                 std::vector<SourceFile>* files,
                                 Err* err);
 
 // Looks for a list of source directories relative to a given current dir.
-bool ExtractListOfRelativeDirs(const Value& value,
+bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
+                               const Value& value,
                                const SourceDir& current_dir,
                                std::vector<SourceDir>* dest,
                                Err* err);
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index 7b96516..f4d1732 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -8,10 +8,10 @@
 
 // Built-in variables ----------------------------------------------------------
 
-extern const char kCurrentToolchain[] = "current_toolchain";
-extern const char kCurrentToolchain_HelpShort[] =
+const char kCurrentToolchain[] = "current_toolchain";
+const char kCurrentToolchain_HelpShort[] =
     "current_toolchain: [string] Label of the current toolchain.";
-extern const char kCurrentToolchain_Help[] =
+const char kCurrentToolchain_Help[] =
     "current_toolchain: Label of the current toolchain.\n"
     "\n"
     "  A fully-qualified label representing the current toolchain. You can\n"
@@ -24,29 +24,89 @@
     "    executable(\"output_thats_64_bit_only\") {\n"
     "      ...\n";
 
-extern const char kDefaultToolchain[] = "default_toolchain";
-extern const char kDefaultToolchain_HelpShort[] =
+const char kDefaultToolchain[] = "default_toolchain";
+const char kDefaultToolchain_HelpShort[] =
     "default_toolchain: [string] Label of the default toolchain.";
-extern const char kDefaultToolchain_Help[] =
+const char kDefaultToolchain_Help[] =
     "default_toolchain: [string] Label of the default toolchain.\n"
     "\n"
     "  A fully-qualified label representing the default toolchain, which may\n"
     "  not necessarily be the current one (see \"current_toolchain\").\n";
 
-extern const char kPythonPath[] = "python_path";
-extern const char kPythonPath_HelpShort[] =
+const char kIsLinux[] = "is_linux";
+const char kIsLinux_HelpShort[] =
+    "is_linux: Indicates the current build is for Linux.";
+const char kIsLinux_Help[] =
+    "is_linux: Indicates the current build is for Linux.\n"
+    "\n"
+    "  Set by default when running on Linux. Can be overridden by command-\n"
+    "  line arguments or by toolchain arguments.\n";
+
+const char kIsMac[] = "is_mac";
+const char kIsMac_HelpShort[] =
+    "is_mac: Indicates the current build is for Mac.";
+const char kIsMac_Help[] =
+    "is_mac: Indicates the current build is for Mac.\n"
+    "\n"
+    "  Set by default when running on Mac. Can be overridden by command-\n"
+    "  line arguments or by toolchain arguments.\n";
+
+const char kIsPosix[] = "is_posix";
+const char kIsPosix_HelpShort[] =
+    "is_posix: Indicates the current build is for Posix.";
+const char kIsPosix_Help[] =
+    "is_posix: Indicates the current build is for Posix.\n"
+    "\n"
+    "  Set by default when running Linux or Mac. Can be overridden by\n"
+    "  command-line arguments or by toolchain arguments.\n";
+
+const char kIsWin[] = "is_win";
+const char kIsWin_HelpShort[] =
+    "is_win: Indicates the current build is for Windows.";
+const char kIsWin_Help[] =
+    "is_win: Indicates the current build is for Windows.\n"
+    "\n"
+    "  Set by default when running on Windows. Can be overridden by command-\n"
+    "  line arguments or by toolchain arguments.\n";
+
+const char kPythonPath[] = "python_path";
+const char kPythonPath_HelpShort[] =
     "python_path: [string] Absolute path of Python.";
-extern const char kPythonPath_Help[] =
+const char kPythonPath_Help[] =
     "python_path: Absolute path of Python.\n"
     "\n"
     "  Normally used in toolchain definitions if running some command\n"
     "  requires Python. You will normally not need this when invoking scripts\n"
     "  since GN automatically finds it for you.\n";
 
-extern const char kRelativeRootGenDir[] = "relative_root_gen_dir";
-extern const char kRelativeRootGenDir_HelpShort[] =
+const char kRelativeBuildToSourceRootDir[] =
+    "relative_build_to_source_root_dir";
+const char kRelativeBuildToSourceRootDir_HelpShort[] =
+    "relative_build_to_source_root_dir: [string] Relative location of root";
+const char kRelativeBuildToSourceRootDir_Help[] =
+    "relative_build_to_source_root_dir: Relative location of root.\n"
+    "\n"
+    "  A relative path from the build directory to the root of the source\n"
+    "  tree, with no terminating slash. The build directory will be the\n"
+    "  directory when executing normal build commands (except for scripts).\n"
+    "\n"
+    "  If the checkout is in \"/foo/src/\" and the build directory is in\n"
+    "  \"/foo/src/out/Debug/\" then the relative build to source root dir\n"
+    "  will be \"../..\".\n"
+    "\n"
+    "  See also relative_source_root_dir.\n"
+    "\n"
+    "Example:\n"
+    "  This is typically used to invoke tools checked out in the tree:\n"
+    "\n"
+    "  tool(\"link\") {\n"
+    "    command = \"$relative_build_to_source_root_dir/third_party/gold/ld\n"
+    "  }\n";
+
+const char kRelativeRootGenDir[] = "relative_root_gen_dir";
+const char kRelativeRootGenDir_HelpShort[] =
     "relative_root_gen_dir: [string] Relative root dir for generated files.";
-extern const char kRelativeRootGenDir_Help[] =
+const char kRelativeRootGenDir_Help[] =
     "relative_root_gen_dir: Relative root for generated files.\n"
     "\n"
     "  Relative path from the directory of the current build file to the\n"
@@ -60,10 +120,10 @@
     "  If your current build file is in \"//tools\", you might write\n"
     "  args = [ \"$relative_root_gen_dir/output.txt\" ]\n";
 
-extern const char kRelativeRootOutputDir[] = "relative_root_output_dir";
-extern const char kRelativeRootOutputDir_HelpShort[] =
+const char kRelativeRootOutputDir[] = "relative_root_output_dir";
+const char kRelativeRootOutputDir_HelpShort[] =
     "relative_root_output_dir: [string] Relative dir for output files.";
-extern const char kRelativeRootOutputDir_Help[] =
+const char kRelativeRootOutputDir_Help[] =
     "relative_root_output_dir: Relative dir for output files.\n"
     "\n"
     "  Relative path from the directory of the current build file to the\n"
@@ -71,10 +131,34 @@
     "\n"
     "  Generally scripts should use \"relative_target_output_dir\" instead.\n";
 
-extern const char kRelativeTargetGenDir[] = "relative_target_gen_dir";
-extern const char kRelativeTargetGenDir_HelpShort[] =
+extern const char kRelativeSourceRootDir[] = "relative_source_root_dir";
+extern const char kRelativeSourceRootDir_HelpShort[] =
+    "relative_source_root_dir: [string] Relative location of root.";
+extern const char kRelativeSourceRootDir_Help[] =
+    "relative_source_root_dir: Relative location of root.\n"
+    "\n"
+    "  A relative path from the current source directory to the root of the\n"
+    "  source tree, with no terminating slash. The build directory will be\n"
+    "  the directory when executing scripts.\n"
+    "\n"
+    "  If the checkout is in \"/foo/src/\" and the build directory is in\n"
+    "  \"/foo/src/out/Debug/\" then the relative build to source root dir\n"
+    "  will be \"../..\".\n"
+    "\n"
+    "  See also relative_build_to_source_root_dir.\n"
+    "\n"
+    "Example:\n"
+    "  This is typically used to invoke tools checked out in the tree:\n"
+    "\n"
+    "  tool(\"link\") {\n"
+    "    command = \"$relative_build_to_source_root_dir/third_party/gold/ld\n"
+    "  }\n";
+
+
+const char kRelativeTargetGenDir[] = "relative_target_gen_dir";
+const char kRelativeTargetGenDir_HelpShort[] =
     "relative_target_gen_dir: [string] Relative dir for generated files.";
-extern const char kRelativeTargetGenDir_Help[] =
+const char kRelativeTargetGenDir_Help[] =
     "relative_target_gen_dir: Relative dir for generated files.\n"
     "\n"
     "  Relative path from the directory of the current build file to the\n"
@@ -91,10 +175,10 @@
     "  If your current build file is in \"//tools\", you might write\n"
     "  args = [ \"$relative_root_gen_dir/output.txt\" ]\n";
 
-extern const char kRelativeTargetOutputDir[] = "relative_target_output_dir";
-extern const char kRelativeTargetOutputDir_HelpShort[] =
+const char kRelativeTargetOutputDir[] = "relative_target_output_dir";
+const char kRelativeTargetOutputDir_HelpShort[] =
     "relative_target_output_dir: [string] Relative dir for build results.";
-extern const char kRelativeTargetOutputDir_Help[] =
+const char kRelativeTargetOutputDir_Help[] =
     "relative_target_output_dir: Relative dir for build results."
     "\n"
     "  Relative path from the directory of the current build file to the\n"
@@ -123,7 +207,7 @@
     "\n"
     "  All targets depending on this one, and recursively, all targets\n"
     "  depending on those, will have the configs listed in this variable\n"
-    "  added to them.\n"
+    "  added to them. These configs will also apply to the current target.\n"
     "\n"
     "  This addition happens in a second phase once a target and all of its\n"
     "  dependencies have been resolved. Therefore, a target will not see\n"
@@ -138,6 +222,12 @@
 const char kCflags_HelpShort[] =
     "cflags: [string list] Flags passed to all C compiler variants.";
 // Avoid writing long help for each variant.
+#define COMMON_FLAGS_HELP \
+    "\n"\
+    "  Flags are never quoted. If your flag includes a string that must be\n"\
+    "  quoted, you must do it yourself. This also means that you can\n"\
+    "  specify more than one flag in a string if necessary (\"--foo --bar\")\n"\
+    "  and have them be seen as separate by the tool.\n"
 const char kCommonCflagsHelp[] =
     "cflags*: Flags passed to the C compiler.\n"
     "\n"
@@ -148,7 +238,8 @@
     "\n"
     "  To target one of these variants individually, use \"cflags_c\",\n"
     "  \"cflags_cc\", \"cflags_objc\", and \"cflags_objcc\", respectively.\n"
-    "  These variant-specific versions will be appended to the \"cflags\".\n";
+    "  These variant-specific versions will be appended to the \"cflags\".\n"
+    COMMON_FLAGS_HELP;
 const char* kCflags_Help = kCommonCflagsHelp;
 
 const char kCflagsC[] = "cflags_c";
@@ -252,7 +343,8 @@
     "  A list of config labels.\n"
     "\n"
     "  Targets directly referencing this one will have the configs listed in\n"
-    "  this variable added to them.\n"
+    "  this variable added to them. These configs will also apply to the\n"
+    "  current target.\n"
     "\n"
     "  This addition happens in a second phase once a target and all of its\n"
     "  dependencies have been resolved. Therefore, a target will not see\n"
@@ -263,6 +355,45 @@
     "\n"
     "  See also \"all_dependent_configs\".\n";
 
+const char kForwardDependentConfigsFrom[] = "forward_dependent_configs_from";
+const char kForwardDependentConfigsFrom_HelpShort[] =
+    "forward_dependent_configs_from: [label list] Forward dependent's configs.";
+const char kForwardDependentConfigsFrom_Help[] =
+    "forward_dependent_configs_from\n"
+    "\n"
+    "  A list of target labels.\n"
+    "\n"
+    "  Exposes the direct_dependent_configs from a dependent target as\n"
+    "  direct_dependent_configs of the current one. Each label in this list\n"
+    "  must also be in the deps.\n"
+    "\n"
+    "  Sometimes you depend on a child library that exports some necessary\n"
+    "  configuration via direct_dependent_configs. If your target in turn\n"
+    "  exposes the child library's headers in its public headers, it might\n"
+    "  mean that targets that depend on you won't work: they'll be seeing the\n"
+    "  child library's code but not the necessary configuration. This list\n"
+    "  specifies which of your deps' direct dependent configs to expose as\n"
+    "  your own.\n"
+    "\n"
+    "Examples:\n"
+    "\n"
+    "  If we use a given library \"a\" from our public headers:\n"
+    "\n"
+    "    deps = [ \":a\", \":b\", ... ]\n"
+    "    forward_dependent_configs_from = [ \":a\" ]\n"
+    "\n"
+    "  This example makes a \"transparent\" target that forwards a dependency\n"
+    "  to another:\n"
+    "\n"
+    "    group(\"frob\") {\n"
+    "      if (use_system_frob) {\n"
+    "        deps = \":system_frob\"\n"
+    "      } else {\n"
+    "        deps = \"//third_party/fallback_frob\"\n"
+    "      }\n"
+    "      forward_dependent_configs_from = deps\n"
+    "    }\n";
+
 const char kLdflags[] = "ldflags";
 const char kLdflags_HelpShort[] =
     "ldflags: [string list] Flags passed to the linker.";
@@ -271,7 +402,8 @@
     "\n"
     "  A list of strings.\n"
     "\n"
-    "  These flags are passed on the command-line to the linker.\n";
+    "  These flags are passed on the command-line to the linker.\n"
+    COMMON_FLAGS_HELP;
 
 const char kSources[] = "sources";
 const char kSources_HelpShort[] =
@@ -301,9 +433,15 @@
   if (info_map.empty()) {
     INSERT_VARIABLE(CurrentToolchain)
     INSERT_VARIABLE(DefaultToolchain)
+    INSERT_VARIABLE(IsLinux)
+    INSERT_VARIABLE(IsMac)
+    INSERT_VARIABLE(IsPosix)
+    INSERT_VARIABLE(IsWin)
     INSERT_VARIABLE(PythonPath)
+    INSERT_VARIABLE(RelativeBuildToSourceRootDir)
     INSERT_VARIABLE(RelativeRootGenDir)
     INSERT_VARIABLE(RelativeRootOutputDir)
+    INSERT_VARIABLE(RelativeSourceRootDir)
     INSERT_VARIABLE(RelativeTargetGenDir)
     INSERT_VARIABLE(RelativeTargetOutputDir)
   }
@@ -323,6 +461,7 @@
     INSERT_VARIABLE(Datadeps)
     INSERT_VARIABLE(Deps)
     INSERT_VARIABLE(DirectDependentConfigs)
+    INSERT_VARIABLE(ForwardDependentConfigsFrom)
     INSERT_VARIABLE(Ldflags)
     INSERT_VARIABLE(Sources)
   }
diff --git a/tools/gn/variables.h b/tools/gn/variables.h
index 2d46100..c1d2a29 100644
--- a/tools/gn/variables.h
+++ b/tools/gn/variables.h
@@ -21,10 +21,30 @@
 extern const char kDefaultToolchain_HelpShort[];
 extern const char kDefaultToolchain_Help[];
 
+extern const char kIsLinux[];
+extern const char kIsLinux_HelpShort[];
+extern const char kIsLinux_Help[];
+
+extern const char kIsMac[];
+extern const char kIsMac_HelpShort[];
+extern const char kIsMac_Help[];
+
+extern const char kIsPosix[];
+extern const char kIsPosix_HelpShort[];
+extern const char kIsPosix_Help[];
+
+extern const char kIsWin[];
+extern const char kIsWin_HelpShort[];
+extern const char kIsWin_Help[];
+
 extern const char kPythonPath[];
 extern const char kPythonPath_HelpShort[];
 extern const char kPythonPath_Help[];
 
+extern const char kRelativeBuildToSourceRootDir[];
+extern const char kRelativeBuildToSourceRootDir_HelpShort[];
+extern const char kRelativeBuildToSourceRootDir_Help[];
+
 extern const char kRelativeRootGenDir[];
 extern const char kRelativeRootGenDir_HelpShort[];
 extern const char kRelativeRootGenDir_Help[];
@@ -33,6 +53,10 @@
 extern const char kRelativeRootOutputDir_HelpShort[];
 extern const char kRelativeRootOutputDir_Help[];
 
+extern const char kRelativeSourceRootDir[];
+extern const char kRelativeSourceRootDir_HelpShort[];
+extern const char kRelativeSourceRootDir_Help[];
+
 extern const char kRelativeTargetGenDir[];
 extern const char kRelativeTargetGenDir_HelpShort[];
 extern const char kRelativeTargetGenDir_Help[];
@@ -87,6 +111,10 @@
 extern const char kDirectDependentConfigs_HelpShort[];
 extern const char kDirectDependentConfigs_Help[];
 
+extern const char kForwardDependentConfigsFrom[];
+extern const char kForwardDependentConfigsFrom_HelpShort[];
+extern const char kForwardDependentConfigsFrom_Help[];
+
 extern const char kLdflags[];
 extern const char kLdflags_HelpShort[];
 extern const char kLdflags_Help[];
diff --git a/tools/heapcheck/suppressions.txt b/tools/heapcheck/suppressions.txt
index f6288e6..96ad3f4 100644
--- a/tools/heapcheck/suppressions.txt
+++ b/tools/heapcheck/suppressions.txt
@@ -154,7 +154,7 @@
    bug_119677
    Heapcheck:Leak
    ...
-   fun:DisplayChangeObserverX11
+   fun:DisplayChangeObserver
    fun:aura::Env::Init
    fun:aura::Env::GetInstance
 }
@@ -180,21 +180,11 @@
    fun:aura::RootWindowHost::Create
 }
 
-# There is not CloseTestNSSDB due to NSS bug 588269.
-# When NSS 3.14 is the minimum version required, this should be removed.
-# http://crbug.com/156433 .
+# When NSS 3.15 is the minimum version required, this should be removed.
 {
-   bug_156433_a
+   bug_272673
    Heapcheck:Leak
-   fun:sqlite3MemMalloc
-   fun:*OpenUserDB
-   fun:*OpenTestNSSDB
-   fun:*ScopedTestNSSDB
-}
-{
-   bug_156433_b
-   Heapcheck:Leak
-   fun:PORT_Alloc_Util
+   fun:*
    fun:*OpenUserDB
    fun:*OpenTestNSSDB
    fun:*ScopedTestNSSDB
@@ -624,15 +614,6 @@
    fun:gfx::PlatformFontPango::*
 }
 {
-   bug_189194_a
-   Heapcheck:Leak
-   ...
-   fun:extensions::SettingsFrontend::Create
-   fun:ExtensionService::ExtensionService
-   fun:extensions::TestExtensionSystem::CreateExtensionService
-   fun:ProfileSigninConfirmationHelperTest::SetUp
-}
-{
   bug_225596
   Heapcheck:Leak
   fun:chromeos::input_method::InputMethodManagerImpl::Init
@@ -850,11 +831,39 @@
    fun:message_center::MessageCenterViewTest::SetUp
 }
 {
-   bug_271431
+   bug_272083
+   Heapcheck:Leak
+   fun:ThemeService::SetManagedUserTheme
+   fun:ThemeService::OnManagedUserInitialized
+}
+{
+   bug_272596
+   Heapcheck:Leak
+   fun:*
+   fun:net::NSSCertDatabase::ListCerts
+   fun:LoadNSSCertificates
+}
+{
+   bug_274114
    Heapcheck:Leak
    ...
-   fun:CreateBubble
-   fun:autofill::GeneratedCreditCardBubbleController::Show
-   fun:autofill::GeneratedCreditCardBubbleController::SetupAndShow
-   fun:autofill::GeneratedCreditCardBubbleController::Show
+   fun:gfx::RenderTextLinux::GetBaseline
+   fun:views::NativeTextfieldViews::GetTextfieldBaseline
+   fun:_init
+   fun:LocationBarView::Init
+   fun:ToolbarView::Init
+   fun:BrowserView::InitViews
+   fun:BrowserView::ViewHierarchyChanged
+   fun:views::View::ViewHierarchyChangedImpl
+   fun:views::View::PropagateAddNotifications
+   fun:views::View::AddChildViewAt
+   fun:views::NonClientView::ViewHierarchyChanged
+   fun:views::View::ViewHierarchyChangedImpl
+   fun:views::View::PropagateAddNotifications
+   fun:views::View::AddChildViewAt
+   fun:views::View::AddChildView
+   fun:views::internal::RootView::SetContentsView
+   fun:views::Widget::SetContentsView
+   fun:views::Widget::Init
+   fun:BrowserFrame::InitBrowserFrame
 }
diff --git a/tools/idl_parser/idl_lexer.py b/tools/idl_parser/idl_lexer.py
index c2569e9..d7311df 100755
--- a/tools/idl_parser/idl_lexer.py
+++ b/tools/idl_parser/idl_lexer.py
@@ -14,7 +14,6 @@
    http://www.dabeaz.com/ply/
 """
 
-import optparse
 import os.path
 import sys
 
@@ -26,7 +25,7 @@
   # Disable lint check which fails to find the ply module.
   # pylint: disable=F0401
   from ply import lex
-except:
+except ImportError:
   module_path, module_name = os.path.split(__file__)
   third_party = os.path.join(module_path, '..', '..', 'third_party')
   sys.path.append(third_party)
@@ -37,6 +36,13 @@
 # IDL Lexer
 #
 class IDLLexer(object):
+  # 'literals' is a value expected by lex which specifies a list of valid
+  # literal tokens, meaning the token type and token value are identical.
+  literals = r'"*.(){}[],;:=+-/~|&^?<>'
+
+  # 't_ignore' contains ignored characters (spaces and tabs)
+  t_ignore = ' \t'
+
   # 'tokens' is a value required by lex which specifies the complete list
   # of valid token types.
   tokens = [
@@ -106,10 +112,15 @@
   # regular expression where a match will emit a token of type <TYPE>.  In the
   # case of a function, the function is called when a match is made. These
   # definitions come from WebIDL.
+  #
+  # These need to be methods for lexer construction, despite not using self.
+  # pylint: disable=R0201
   def t_ELLIPSIS(self, t):
     r'\.\.\.'
     return t
 
+  # Regex needs to be in the docstring
+  # pylint: disable=C0301
   def t_float(self, t):
     r'-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)'
     return t
@@ -236,12 +247,6 @@
       self._lexobj = lex.lex(object=self, lextab=None, optimize=0)
     return self._lexobj
 
-  def _AddConstDefs(self):
-    # 'literals' is a value expected by lex which specifies a list of valid
-    # literal tokens, meaning the token type and token value are identical.
-    self.literals = r'"*.(){}[],;:=+-/~|&^?<>'
-    self.t_ignore = ' \t'
-
   def _AddToken(self, token):
     if token in self.tokens:
       raise RuntimeError('Same token: ' + token)
@@ -269,11 +274,12 @@
     self.filename = None
     self.keywords = {}
     self.tokens = []
-    self._AddConstDefs()
     self._AddTokens(IDLLexer.tokens)
     self._AddKeywords(IDLLexer.keywords)
     self._lexobj = None
+    self.last = None
+    self.lines = None
 
 # If run by itself, attempt to build the lexer
 if __name__ == '__main__':
-  lexer = IDLLexer()
+  lexer_object = IDLLexer()
diff --git a/tools/idl_parser/idl_lexer_test.py b/tools/idl_parser/idl_lexer_test.py
index cba4e48..8b20da8 100755
--- a/tools/idl_parser/idl_lexer_test.py
+++ b/tools/idl_parser/idl_lexer_test.py
@@ -3,10 +3,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import json
-import optparse
-import os
-import sys
 import unittest
 
 from idl_lexer import IDLLexer
@@ -100,4 +96,4 @@
 
 
 if __name__ == '__main__':
-  unittest.main()
\ No newline at end of file
+  unittest.main()
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py
index 10428de..8a682ea 100755
--- a/tools/idl_parser/idl_parser.py
+++ b/tools/idl_parser/idl_parser.py
@@ -36,8 +36,22 @@
 from idl_lexer import IDLLexer
 from idl_node import IDLAttribute, IDLNode
 
-from ply import lex
-from ply import yacc
+#
+# 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.par, os.par, 'third_party')
+  sys.path.append(third_party)
+  # pylint: disable=F0401
+  from ply import lex
+  from ply import yacc
 
 #
 # ERROR_REMAP
@@ -862,7 +876,7 @@
   def __init__(self, lexer, verbose=False, debug=False, mute_error=False):
     self.lexer = lexer
     self.tokens = lexer.KnownTokens()
-    self.yaccobj = yacc.yacc(module=self, tabmodule=None, debug=False,
+    self.yaccobj = yacc.yacc(module=self, tabmodule=None, debug=debug,
                              optimize=0, write_tables=0)
     self.parse_debug = debug
     self.verbose = verbose
@@ -973,6 +987,8 @@
     return IDLAttribute(key, Boolean(True))
 
   def GetErrors(self):
+    # Access lexer errors, despite being private
+    # pylint: disable=W0212
     return self._parse_errors + self.lexer._lex_errors
 
 #
diff --git a/tools/idl_parser/idl_ppapi_lexer.py b/tools/idl_parser/idl_ppapi_lexer.py
index 2595f1c..9e83486 100755
--- a/tools/idl_parser/idl_ppapi_lexer.py
+++ b/tools/idl_parser/idl_ppapi_lexer.py
@@ -15,23 +15,25 @@
 """
 
 from idl_lexer import IDLLexer
-import optparse
-import os.path
-import sys
 
 
 #
 # IDL PPAPI Lexer
 #
 class IDLPPAPILexer(IDLLexer):
+  # Token definitions
+  #
+  # These need to be methods for lexer construction, despite not using self.
+  # pylint: disable=R0201
+
   # Special multi-character operators
   def t_LSHIFT(self, t):
     r'<<'
-    return t;
+    return t
 
   def t_RSHIFT(self, t):
     r'>>'
-    return t;
+    return t
 
   def t_INLINE(self, t):
     r'\#inline (.|\n)*?\#endinl.*'
@@ -45,15 +47,15 @@
     self._AddKeywords(['label', 'struct'])
 
     # Add number types
-    self._AddKeywords(['char', 'int8_t', 'int16_t', 'int32_t', 'int64_t']);
-    self._AddKeywords(['uint8_t', 'uint16_t', 'uint32_t', 'uint64_t']);
-    self._AddKeywords(['double_t', 'float_t']);
+    self._AddKeywords(['char', 'int8_t', 'int16_t', 'int32_t', 'int64_t'])
+    self._AddKeywords(['uint8_t', 'uint16_t', 'uint32_t', 'uint64_t'])
+    self._AddKeywords(['double_t', 'float_t'])
 
     # Add handle types
-    self._AddKeywords(['handle_t', 'PP_FileHandle']);
+    self._AddKeywords(['handle_t', 'PP_FileHandle'])
 
     # Add pointer types (void*, char*, const char*, const void*)
-    self._AddKeywords(['mem_t', 'str_t', 'cstr_t', 'interface_t']);
+    self._AddKeywords(['mem_t', 'str_t', 'cstr_t', 'interface_t'])
 
     # Remove JS types
     self._DelKeywords(['boolean', 'byte', 'Date', 'DOMString', 'double',
@@ -65,4 +67,4 @@
   lexer = IDLPPAPILexer()
   lexer.Tokenize(open('test_parser/inline_ppapi.idl').read())
   for tok in lexer.GetTokens():
-    print '\n' + str(tok)
\ No newline at end of file
+    print '\n' + str(tok)
diff --git a/tools/idl_parser/idl_ppapi_parser.py b/tools/idl_parser/idl_ppapi_parser.py
index 33eb503..c02e42c 100755
--- a/tools/idl_parser/idl_ppapi_parser.py
+++ b/tools/idl_parser/idl_ppapi_parser.py
@@ -29,13 +29,11 @@
 # pylint: disable=R0201
 # pylint: disable=C0301
 
-import os.path
 import sys
-import time
 
 from idl_ppapi_lexer import IDLPPAPILexer
 from idl_parser import IDLParser, ListFromConcat, ParseFile
-from idl_node import IDLAttribute, IDLNode
+from idl_node import IDLNode
 
 class IDLPPAPIParser(IDLParser):
 #
@@ -104,7 +102,8 @@
   def p_LabelCont(self, p):
     """LabelCont : ',' LabelList
                  |"""
-    if len(p) > 1: p[0] = p[2]
+    if len(p) > 1:
+      p[0] = p[2]
 
   def p_LabelContError(self, p):
     """LabelCont : error LabelCont"""
@@ -260,20 +259,21 @@
     arguments = self.BuildProduction('Values', p, 2, p[3])
     p[0] = self.BuildNamed('ExtAttribute', p, 1, arguments)
 
+  def p_ValueList(self, p):
+    """ValueList : ConstValue ValueListCont"""
+    p[0] = ListFromConcat(p[1], p[2])
+
+  def p_ValueListCont(self, p):
+    """ValueListCont : ValueList
+                     |"""
+    if len(p) > 1:
+      p[0] = p[1]
+
   # [76]
   def p_ExtendedAttributeIdentConst(self, p):
     """ExtendedAttributeIdentConst : identifier '=' ConstValue"""
     p[0] = self.BuildNamed('ExtAttribute', p, 1, p[3])
 
-  def p_ValueListCont(self, p):
-    """ValueListCont : ConstValue ValueListCont
-                     |"""
-    if len(p) > 1:
-      p[0] = ListFromConcat(p[1], p[2])
-
-  def p_ValueList(self, p):
-    """ValueList : ConstValue ValueListCont"""
-    values = self.BuildProduction('Values', p, 2, ListFromConcat(p[1], p[2]))
 
   def __init__(self, lexer, verbose=False, debug=False, mute_error=False):
     IDLParser.__init__(self, lexer, verbose, debug, mute_error)
@@ -301,4 +301,4 @@
 
 
 if __name__ == '__main__':
-  sys.exit(main(sys.argv[1:]))
\ No newline at end of file
+  sys.exit(main(sys.argv[1:]))
diff --git a/tools/idl_parser/test_parser/extattr_ppapi.idl b/tools/idl_parser/test_parser/extattr_ppapi.idl
new file mode 100644
index 0000000..0206901
--- /dev/null
+++ b/tools/idl_parser/test_parser/extattr_ppapi.idl
@@ -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. */
+
+/* Test ExtendedAttribute productions
+
+Run with --test to generate an AST and verify that all comments accurately
+reflect the state of the Nodes.
+
+BUILD Type(Name)
+This comment signals that a node of type <Type> is created with the
+name <Name>.
+
+ERROR Error String
+This comment signals that a error of <Error String> is generated.  The error
+is not assigned to a node, but are expected in order.
+
+PROP Key=Value
+This comment signals that a property has been set on the Node such that
+<Key> = <Value>.
+
+TREE
+Type(Name)
+  Type(Name)
+  Type(Name)
+    Type(Name)
+    ...
+This comment signals that a tree of nodes matching the BUILD comment
+symatics should exist.  This is an exact match.
+*/
+
+/* TREE
+ *Interface(Foo)
+ *  ExtAttributes()
+ *    ExtAttribute(foo)
+ *      Arguments()
+ */
+
+[foo()] interface Foo {};
+
+/* TREE
+ *Interface(Foo)
+ *  ExtAttributes()
+ *    ExtAttribute(foo)
+ *      Values()
+ */
+
+[foo(1)] interface Foo {};
+
+/* TREE
+ *Interface(Foo)
+ *  ExtAttributes()
+ *    ExtAttribute(foo)
+ *      Values()
+ */
+
+[foo(1 true 1.2e-3)] interface Foo {};
+
+/* TREE
+ *Interface(Foo)
+ *  ExtAttributes()
+ *    ExtAttribute(foo)
+ *      Arguments()
+ *        Error(Unexpected ).)
+ */
+
+[foo(null)] interface Foo {};
+
+/* TREE
+ *Interface(Foo)
+ *  ExtAttributes()
+ *    ExtAttribute(foo)
+ */
+
+[foo=1] interface Foo {};
+
+/* TREE
+ *Interface(Foo)
+ *  ExtAttributes()
+ *    ExtAttribute(foo)
+ */
+
+[foo=true] interface Foo {};
+
+/* TREE
+ *Interface(Foo)
+ *  ExtAttributes()
+ *    ExtAttribute(foo)
+ */
+
+[foo=1.2e-3] interface Foo {};
diff --git a/tools/json_comment_eater/json_comment_eater.py b/tools/json_comment_eater/json_comment_eater.py
old mode 100644
new mode 100755
index 8587464..93261bf
--- a/tools/json_comment_eater/json_comment_eater.py
+++ b/tools/json_comment_eater/json_comment_eater.py
@@ -1,3 +1,4 @@
+#!/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.
@@ -6,12 +7,16 @@
 json.loads.
 '''
 
+import sys
+
+
 def _Rcount(string, chars):
   '''Returns the number of consecutive characters from |chars| that occur at the
   end of |string|.
   '''
   return len(string) - len(string.rstrip(chars))
 
+
 def _FindNextToken(string, tokens, start):
   '''Finds the next token in |tokens| that occurs in |string| from |start|.
   Returns a tuple (index, token key).
@@ -23,6 +28,7 @@
       min_index, min_key = (index, k)
   return (min_index, min_key)
 
+
 def _ReadString(input, start, output):
   output.append('"')
   start_range, end_range = (start, input.find('"', start))
@@ -35,6 +41,7 @@
   output.append(input[start:end_range + 1])
   return end_range + 1
 
+
 def _ReadComment(input, start, output):
   eol_tokens = ('\n', '\r')
   eol_token_index, eol_token = _FindNextToken(input, eol_tokens, start)
@@ -43,6 +50,7 @@
   output.append(eol_token)
   return eol_token_index + len(eol_token)
 
+
 def Nom(input):
   token_actions = {
     '"': _ReadString,
@@ -58,3 +66,7 @@
     output.append(input[pos:token_index])
     pos = token_actions[token](input, token_index + len(token), output)
   return ''.join(output)
+
+
+if __name__ == '__main__':
+    sys.stdout.write(Nom(sys.stdin.read()))
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index 2c55b1e..45f4d9d 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -45,6 +45,7 @@
       .Append(self._util_cc_helper.GetIncludePath())
       .Append('#include "base/logging.h"')
       .Append('#include "base/strings/string_number_conversions.h"')
+      .Append('#include "base/strings/utf_string_conversions.h"')
       .Append('#include "%s/%s.h"' %
           (self._namespace.source_file_dir, self._namespace.unix_name))
       .Cblock(self._type_helper.GenerateIncludes(include_soft=True))
@@ -449,7 +450,7 @@
 
     var: variable or variable*
 
-    E.g for std::string, generate base::Value::CreateStringValue(var)
+    E.g for std::string, generate new base::StringValue(var)
     """
     underlying_type = self._type_helper.FollowRef(type_)
     if (underlying_type.property_type == PropertyType.CHOICES or
@@ -466,7 +467,7 @@
         vardot = '(%s).' % var
       return '%sDeepCopy()' % vardot
     elif underlying_type.property_type == PropertyType.ENUM:
-      return 'base::Value::CreateStringValue(ToString(%s))' % var
+      return 'new base::StringValue(ToString(%s))' % var
     elif underlying_type.property_type == PropertyType.BINARY:
       if is_ptr:
         vardot = var + '->'
@@ -925,14 +926,14 @@
     if not self._generate_error_messages:
       return c
     (c.Append('if (error)')
-      .Append('  *error = ' + body + ';'))
+      .Append('  *error = UTF8ToUTF16(' + body + ');'))
     return c
 
   def _GenerateParams(self, params):
     """Builds the parameter list for a function, given an array of parameters.
     """
     if self._generate_error_messages:
-      params = list(params) + ['std::string* error']
+      params = list(params) + ['base::string16* error']
     return ', '.join(str(p) for p in params)
 
   def _GenerateArgs(self, args):
diff --git a/tools/json_schema_compiler/h_generator.py b/tools/json_schema_compiler/h_generator.py
index 9a348fe..77356b2 100644
--- a/tools/json_schema_compiler/h_generator.py
+++ b/tools/json_schema_compiler/h_generator.py
@@ -393,5 +393,5 @@
     """Builds the parameter list for a function, given an array of parameters.
     """
     if self._generate_error_messages:
-      params += ('std::string* error = NULL',)
+      params += ('base::string16* error = NULL',)
     return ', '.join(str(p) for p in params)
diff --git a/tools/json_schema_compiler/test/error_generation_unittest.cc b/tools/json_schema_compiler/test/error_generation_unittest.cc
index 3d56595..baf7b51 100644
--- a/tools/json_schema_compiler/test/error_generation_unittest.cc
+++ b/tools/json_schema_compiler/test/error_generation_unittest.cc
@@ -5,6 +5,7 @@
 #include "tools/json_schema_compiler/test/error_generation.h"
 
 #include "base/json/json_writer.h"
+#include "base/strings/utf_string_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/json_schema_compiler/test/test_util.h"
 
@@ -14,37 +15,45 @@
 using json_schema_compiler::test_util::List;
 
 template <typename T>
-std::string GetPopulateError(const base::Value& value) {
-  std::string error;
+base::string16 GetPopulateError(const base::Value& value) {
+  base::string16 error;
   T test_type;
   T::Populate(value, &test_type, &error);
   return error;
 }
 
+testing::AssertionResult EqualsUtf16(const std::string& expected,
+                                     const base::string16& actual) {
+  if (ASCIIToUTF16(expected) != actual)
+    return testing::AssertionFailure() << expected << " != " << actual;
+  return testing::AssertionSuccess();
+}
+
 // GenerateTypePopulate errors
 
 TEST(JsonSchemaCompilerErrorTest, RequiredPropertyPopulate) {
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "string", new StringValue("bling"));
-    EXPECT_EQ("", GetPopulateError<TestType>(*value));
+    EXPECT_TRUE(EqualsUtf16("", GetPopulateError<TestType>(*value)));
   }
   {
     scoped_ptr<base::BinaryValue> value(new base::BinaryValue());
-    EXPECT_EQ("expected dictionary, got binary",
-        GetPopulateError<TestType>(*value));
+    EXPECT_TRUE(EqualsUtf16("expected dictionary, got binary",
+        GetPopulateError<TestType>(*value)));
   }
 }
 
 TEST(JsonSchemaCompilerErrorTest, UnexpectedTypePopulation) {
   {
     scoped_ptr<base::ListValue> value(new base::ListValue());
-    EXPECT_EQ("", GetPopulateError<ChoiceType::Integers>(*value));
+    EXPECT_TRUE(EqualsUtf16("",
+        GetPopulateError<ChoiceType::Integers>(*value)));
   }
   {
     scoped_ptr<base::BinaryValue> value(new base::BinaryValue());
-    EXPECT_EQ("expected integers or integer, got binary",
-        GetPopulateError<ChoiceType::Integers>(*value));
+    EXPECT_TRUE(EqualsUtf16("expected integers or integer, got binary",
+        GetPopulateError<ChoiceType::Integers>(*value)));
   }
 }
 
@@ -54,12 +63,12 @@
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "integers", new FundamentalValue(5));
-    EXPECT_EQ("", GetPopulateError<ChoiceType>(*value));
+    EXPECT_TRUE(EqualsUtf16("", GetPopulateError<ChoiceType>(*value)));
   }
   {
     scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
-    EXPECT_EQ("'integers' is required",
-        GetPopulateError<ChoiceType>(*value));
+    EXPECT_TRUE(EqualsUtf16("'integers' is required",
+        GetPopulateError<ChoiceType>(*value)));
   }
 }
 
@@ -75,9 +84,9 @@
     scoped_ptr<base::ListValue> params_value = List(
         new FundamentalValue(5),
         new FundamentalValue(5));
-    std::string error;
+    base::string16 error;
     EXPECT_FALSE(TestFunction::Params::Create(*params_value, &error));
-    EXPECT_EQ("expected 1 arguments, got 2", error);
+    EXPECT_TRUE(EqualsUtf16("expected 1 arguments, got 2", error));
   }
 }
 
@@ -92,9 +101,9 @@
   {
     scoped_ptr<base::ListValue> params_value = List(
         Value::CreateNullValue());
-    std::string error;
+    base::string16 error;
     EXPECT_FALSE(TestFunction::Params::Create(*params_value, &error));
-    EXPECT_EQ("'num' is required", error);
+    EXPECT_TRUE(EqualsUtf16("'num' is required", error));
   }
 }
 
@@ -104,13 +113,13 @@
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
       "string", new StringValue("yes"));
-    EXPECT_EQ("", GetPopulateError<TestType>(*value));
+    EXPECT_TRUE(EqualsUtf16("", GetPopulateError<TestType>(*value)));
   }
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "string", new FundamentalValue(1.1));
-    EXPECT_EQ("'string': expected string, got number",
-        GetPopulateError<TestType>(*value));
+    EXPECT_TRUE(EqualsUtf16("'string': expected string, got number",
+        GetPopulateError<TestType>(*value)));
   }
 }
 
@@ -123,22 +132,23 @@
   {
     scoped_ptr<base::ListValue> params_value = List(
         new FundamentalValue(5));
-    std::string error;
+    base::string16 error;
     EXPECT_FALSE(TestTypeInObject::Params::Create(*params_value, &error));
-    EXPECT_EQ("'paramObject': expected dictionary, got integer", error);
+    EXPECT_TRUE(EqualsUtf16("'paramObject': expected dictionary, got integer",
+        error));
   }
 }
 
 TEST(JsonSchemaCompilerErrorTest, WrongTypeValueType) {
   {
     scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
-    EXPECT_EQ("", GetPopulateError<ObjectType>(*value));
+    EXPECT_TRUE(EqualsUtf16("", GetPopulateError<ObjectType>(*value)));
   }
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "otherType", new FundamentalValue(1.1));
-    EXPECT_EQ("'otherType': expected dictionary, got number",
-        GetPopulateError<ObjectType>(*value));
+    EXPECT_TRUE(EqualsUtf16("'otherType': expected dictionary, got number",
+        GetPopulateError<ObjectType>(*value)));
   }
 }
 
@@ -146,14 +156,15 @@
   {
     scoped_ptr<base::ListValue> params_value = List(
         new FundamentalValue(5));
-    EXPECT_EQ("", GetPopulateError<ChoiceType::Integers>(*params_value));
+    EXPECT_TRUE(EqualsUtf16("",
+        GetPopulateError<ChoiceType::Integers>(*params_value)));
   }
   {
     scoped_ptr<base::ListValue> params_value = List(
         new FundamentalValue(5),
         new FundamentalValue(false));
-    EXPECT_EQ("unable to populate array 'integers'",
-        GetPopulateError<ChoiceType::Integers>(*params_value));
+    EXPECT_TRUE(EqualsUtf16("unable to populate array 'integers'",
+        GetPopulateError<ChoiceType::Integers>(*params_value)));
   }
 }
 
@@ -161,13 +172,13 @@
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "data", new base::BinaryValue());
-    EXPECT_EQ("", GetPopulateError<BinaryData>(*value));
+    EXPECT_TRUE(EqualsUtf16("", GetPopulateError<BinaryData>(*value)));
   }
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "data", new FundamentalValue(1.1));
-    EXPECT_EQ("'data': expected binary, got number",
-        GetPopulateError<BinaryData>(*value));
+    EXPECT_TRUE(EqualsUtf16("'data': expected binary, got number",
+        GetPopulateError<BinaryData>(*value)));
   }
 }
 
@@ -175,13 +186,13 @@
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "TheArray", new base::ListValue());
-    EXPECT_EQ("", GetPopulateError<ArrayObject>(*value));
+    EXPECT_TRUE(EqualsUtf16("", GetPopulateError<ArrayObject>(*value)));
   }
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "TheArray", new FundamentalValue(5));
-    EXPECT_EQ("'TheArray': expected list, got integer",
-        GetPopulateError<ArrayObject>(*value));
+    EXPECT_TRUE(EqualsUtf16("'TheArray': expected list, got integer",
+        GetPopulateError<ArrayObject>(*value)));
   }
 }
 
@@ -191,13 +202,13 @@
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "enumeration", new StringValue("one"));
-    EXPECT_EQ("", GetPopulateError<HasEnumeration>(*value));
+    EXPECT_TRUE(EqualsUtf16("", GetPopulateError<HasEnumeration>(*value)));
   }
   {
     scoped_ptr<DictionaryValue> value = Dictionary(
         "enumeration", new StringValue("bad sauce"));
-    EXPECT_EQ("'enumeration': expected \"one\" or \"two\" or \"three\", "
-              "got \"bad sauce\"",
-        GetPopulateError<HasEnumeration>(*value));
+    EXPECT_TRUE(EqualsUtf16("'enumeration': expected \"one\" or \"two\" "
+              "or \"three\", got \"bad sauce\"",
+        GetPopulateError<HasEnumeration>(*value)));
   }
 }
diff --git a/tools/json_schema_compiler/util.cc b/tools/json_schema_compiler/util.cc
index c03d076..d0e7765 100644
--- a/tools/json_schema_compiler/util.cc
+++ b/tools/json_schema_compiler/util.cc
@@ -45,19 +45,19 @@
 }
 
 void AddItemToList(const int from, base::ListValue* out) {
-  out->Append(base::Value::CreateIntegerValue(from));
+  out->Append(new base::FundamentalValue(from));
 }
 
 void AddItemToList(const bool from, base::ListValue* out) {
-  out->Append(base::Value::CreateBooleanValue(from));
+  out->Append(new base::FundamentalValue(from));
 }
 
 void AddItemToList(const double from, base::ListValue* out) {
-  out->Append(base::Value::CreateDoubleValue(from));
+  out->Append(new base::FundamentalValue(from));
 }
 
 void AddItemToList(const std::string& from, base::ListValue* out) {
-  out->Append(base::Value::CreateStringValue(from));
+  out->Append(new base::StringValue(from));
 }
 
 void AddItemToList(const linked_ptr<base::Value>& from,
diff --git a/tools/lsan/suppressions.txt b/tools/lsan/suppressions.txt
index 5231000..f2dbbc5 100644
--- a/tools/lsan/suppressions.txt
+++ b/tools/lsan/suppressions.txt
@@ -10,13 +10,14 @@
 # V8 leak, expect 1024 bytes leaked per process. http://crbug.com/99304
 leak:v8::internal::V8::Initialize
 
-# V8 GC issue which comes up in lots of tests. http://crbug.com/169678
-leak:v8::internal::SlotsBufferAllocator::AllocateBuffer
-
 # V8 GC issues in ProxyResolver tests, probably harmless. http://crbug.com/67378
 leak:net::ProxyResolverV8::SetPacScript
 leak:net::(anonymous namespace)::ProxyResolverV8WithMockBindings::SetPacScriptFromDisk
 leak:net::(anonymous namespace)::InitResolver
+leak:net::ProxyResolverScriptData::FromUTF8
+
+# http://crbug.com/270180
+leak:net::ProxyResolverV8::Context::ResolveProxy
 
 # NSS leaks in CertDatabaseNSSTest tests. http://crbug.com/51988
 leak:net::NSSCertDatabase::ImportFromPKCS12
@@ -33,10 +34,6 @@
 # Skia leaks. http://crbug.com/189170
 leak:FontConfigTypeface::LegacyCreateTypeface
 
-# Angle leaks. http://crbug.com/181691
-leak:InitializeGlobalParseContext
-leak:InitializeGlobalPools
-
 # Skia leaks GrGpuGL::ProgramCache::Entry. http://crbug.com/262934
 leak:GrGpuGL::flushGraphicsState
 
@@ -45,3 +42,10 @@
 
 # Leak in base_unittests. http://crbug.com/268267
 leak:base::WeakPtrTest_MoveOwnershipAfterInvalidate_Test::TestBody
+
+# GTK leaks. GTK is deprecated, so we won't be fixing these.
+# Most of them should apply to the full browser process only.
+leak:StatusIconGtk::UpdatePlatformContextMenu
+leak:GlobalMenuBar::GlobalMenuBar
+leak:BookmarkBubbleGtk::InitFolderComboModel
+leak:TranslateInfoBarBase::CreateLanguageCombobox
diff --git a/tools/metrics/histograms/extract_histograms.py b/tools/metrics/histograms/extract_histograms.py
index 1ba030c..6203e3b 100644
--- a/tools/metrics/histograms/extract_histograms.py
+++ b/tools/metrics/histograms/extract_histograms.py
@@ -66,13 +66,23 @@
   pass
 
 
-def JoinChildNodes(tag):
-  return ''.join([c.toxml() for c in tag.childNodes]).strip()
+def _JoinChildNodes(tag):
+  """Join child nodes into a single text.
+
+  Applicable to leafs like 'summary' and 'detail'.
+
+  Args:
+    tag: parent node
+
+  Returns:
+    a string with concatenated nodes' text representation.
+  """
+  return ''.join(c.toxml() for c in tag.childNodes).strip()
 
 
-def NormalizeAttributeValue(s):
-  """Normalizes an attribute value (which might be wrapped over multiple lines)
-  by replacing each whitespace sequence with a single space.
+def _NormalizeString(s):
+  """Normalizes a string (possibly of multiple lines) by replacing each
+  whitespace sequence with a single space.
 
   Args:
     s: The string to normalize, e.g. '  \n a  b c\n d  '
@@ -83,7 +93,7 @@
   return ' '.join(s.split())
 
 
-def NormalizeAllAttributeValues(node):
+def _NormalizeAllAttributeValues(node):
   """Recursively normalizes all tag attribute values in the given tree.
 
   Args:
@@ -94,10 +104,9 @@
   """
   if node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE:
     for a in node.attributes.keys():
-      node.attributes[a].value = NormalizeAttributeValue(
-        node.attributes[a].value)
+      node.attributes[a].value = _NormalizeString(node.attributes[a].value)
 
-  for c in node.childNodes: NormalizeAllAttributeValues(c)
+  for c in node.childNodes: _NormalizeAllAttributeValues(c)
   return node
 
 
@@ -151,32 +160,12 @@
   return cluster + group_name + separator + remainder
 
 
-def ExtractHistograms(filename):
-  """Compute the histogram names and descriptions from the XML representation.
+def _ExtractEnumsFromXmlTree(tree):
+  """Extract all <enum> nodes in the tree into a dictionary."""
 
-  Args:
-    filename: The path to the histograms XML file.
-
-  Returns:
-    { 'histogram_name': 'histogram_description', ... }
-
-  Raises:
-    Error if the file is not well-formatted.
-  """
-  # Slurp in histograms.xml
-  raw_xml = ''
-  with open(filename, 'r') as f:
-    raw_xml = f.read()
-
-  # Parse the XML into a tree
-  tree = xml.dom.minidom.parseString(raw_xml)
-  NormalizeAllAttributeValues(tree)
-
-  histograms = {}
+  enums = {}
   have_errors = False
 
-  # Load the enums.
-  enums = {}
   last_name = None
   for enum in tree.getElementsByTagName("enum"):
     if enum.getAttribute('type') != 'int':
@@ -214,16 +203,24 @@
         have_errors = True
         continue
       value_dict['label'] = int_tag.getAttribute('label')
-      value_dict['summary'] = JoinChildNodes(int_tag)
+      value_dict['summary'] = _JoinChildNodes(int_tag)
       enum_dict['values'][int_value] = value_dict
 
     summary_nodes = enum.getElementsByTagName("summary")
     if len(summary_nodes) > 0:
-      enum_dict['summary'] = JoinChildNodes(summary_nodes[0])
+      enum_dict['summary'] = _NormalizeString(_JoinChildNodes(summary_nodes[0]))
 
     enums[name] = enum_dict
 
+  return enums, have_errors
+
+
+def _ExtractHistogramsFromXmlTree(tree, enums):
+  """Extract all <histogram> nodes in the tree into a dictionary."""
+
   # Process the histograms. The descriptions can include HTML tags.
+  histograms = {}
+  have_errors = False
   last_name = None
   for histogram in tree.getElementsByTagName("histogram"):
     name = histogram.getAttribute('name')
@@ -236,29 +233,31 @@
       logging.error('Duplicate histogram definition %s' % name)
       have_errors = True
       continue
-    histograms[name] = {}
+    histograms[name] = histogram_entry = {}
 
     # Find <summary> tag.
     summary_nodes = histogram.getElementsByTagName("summary")
     if len(summary_nodes) > 0:
-      histograms[name]['summary'] = JoinChildNodes(summary_nodes[0])
+      histogram_entry['summary'] = _NormalizeString(
+          _JoinChildNodes(summary_nodes[0]))
     else:
-      histograms[name]['summary'] = 'TBD'
+      histogram_entry['summary'] = 'TBD'
 
     # Find <obsolete> tag.
     obsolete_nodes = histogram.getElementsByTagName("obsolete")
     if len(obsolete_nodes) > 0:
-      reason = JoinChildNodes(obsolete_nodes[0])
-      histograms[name]['obsolete'] = reason
+      reason = _JoinChildNodes(obsolete_nodes[0])
+      histogram_entry['obsolete'] = reason
 
     # Handle units.
     if histogram.hasAttribute('units'):
-      histograms[name]['units'] = histogram.getAttribute('units')
+      histogram_entry['units'] = histogram.getAttribute('units')
 
     # Find <details> tag.
     details_nodes = histogram.getElementsByTagName("details")
     if len(details_nodes) > 0:
-      histograms[name]['details'] = JoinChildNodes(details_nodes[0])
+      histogram_entry['details'] = _NormalizeString(
+          _JoinChildNodes(details_nodes[0]))
 
     # Handle enum types.
     if histogram.hasAttribute('enum'):
@@ -267,10 +266,28 @@
         logging.error('Unknown enum %s in histogram %s' % (enum_name, name))
         have_errors = True
       else:
-        histograms[name]['enum'] = enums[enum_name]
+        histogram_entry['enum'] = enums[enum_name]
 
-  # Process the field trials and compute the combinations with their affected
-  # histograms.
+  return histograms, have_errors
+
+
+def _UpdateHistogramsWithFieldTrialInformation(tree, histograms):
+  """Process field trials' tags and combine with affected histograms.
+
+  The histograms dictionary will be updated in-place by adding new histograms
+  created by combining histograms themselves with field trials targetting these
+  histograms.
+
+  Args:
+    tree: XML dom tree.
+    histograms: a dictinary of histograms previously extracted from the tree;
+
+  Returns:
+    True if any errors were found.
+  """
+  have_errors = False
+
+  # Verify order of fieldtrial fields first.
   last_name = None
   for fieldtrial in tree.getElementsByTagName("fieldtrial"):
     name = fieldtrial.getAttribute('name')
@@ -279,6 +296,7 @@
                     % (last_name, name))
       have_errors = True
     last_name = name
+
   # Field trials can depend on other field trials, so we need to be careful.
   # Make a temporary copy of the list of field trials to use as a queue.
   # Field trials whose dependencies have not yet been processed will get
@@ -287,6 +305,7 @@
   def GenerateFieldTrials():
     for f in tree.getElementsByTagName("fieldtrial"): yield 0, f
     for r, f in reprocess_queue: yield r, f
+
   for reprocess_count, fieldtrial in GenerateFieldTrials():
     # Check dependencies first
     dependencies_valid = True
@@ -314,6 +333,7 @@
     group_labels = {}
     for group in groups:
       group_labels[group.getAttribute('name')] = group.getAttribute('label')
+
     last_histogram_name = None
     for affected_histogram in affected_histograms:
       histogram_name = affected_histogram.getAttribute('name')
@@ -357,11 +377,44 @@
         except Error:
           have_errors = True
 
-  if have_errors:
-    logging.error('Error parsing %s' % filename)
-    raise Error()
+  return have_errors
 
-  return histograms
+
+def ExtractHistogramsFromFile(file_handle):
+  """Compute the histogram names and descriptions from the XML representation.
+
+  Args:
+    file_handle: A file or file-like with XML content.
+
+  Returns:
+    a tuple of (histograms, status) where histograms is a dictionary mapping
+    histogram names to dictionaries containing histogram descriptions and status
+    is a boolean indicating if errros were encoutered in processing.
+  """
+  tree = xml.dom.minidom.parse(file_handle)
+  _NormalizeAllAttributeValues(tree)
+
+  enums, enum_errors = _ExtractEnumsFromXmlTree(tree)
+  histograms, histogram_errors = _ExtractHistogramsFromXmlTree(tree, enums)
+  update_errors = _UpdateHistogramsWithFieldTrialInformation(tree, histograms)
+
+  return histograms, enum_errors or histogram_errors or update_errors
+
+
+def ExtractHistograms(filename):
+  """Load histogram definitions from a disk file.
+  Args:
+    filename: a file path to load data from.
+
+  Raises:
+    Error if the file is not well-formatted.
+  """
+  with open(filename, 'r') as f:
+    histograms, had_errors = ExtractHistogramsFromFile(f)
+    if had_errors:
+      logging.error('Error parsing %s' % filename)
+      raise Error()
+    return histograms
 
 
 def ExtractNames(histograms):
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 892c88f..05e686c 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -1164,6 +1164,12 @@
   </summary>
 </histogram>
 
+<histogram name="Chrome.BrowserCrashDumpAttempts">
+  <summary>
+    Number of time the browser processes attempts to generate a crash dump.
+  </summary>
+</histogram>
+
 <histogram name="Chrome.SearchSelectExempt" enum="SearchEngine">
   <obsolete>
     Deprecated 8/2013. No longer tracked.
@@ -3885,6 +3891,34 @@
   </summary>
 </histogram>
 
+<histogram name="FileBrowser.FolderShortcut.Add">
+  <summary>
+    Chrome OS File Browser: this is recorded when the user adds a folder
+    shortcut.
+  </summary>
+</histogram>
+
+<histogram name="FileBrowser.FolderShortcut.Count">
+  <summary>
+    Chrome OS File Browser: number of saved folder shorcuts. This is recorded
+    when Files.app is launched.
+  </summary>
+</histogram>
+
+<histogram name="FileBrowser.FolderShortcut.Navigate">
+  <summary>
+    Chrome OS File Browser: this is recorded when the user clicks or selects a
+    folder shortcut and is navigated to the target folder.
+  </summary>
+</histogram>
+
+<histogram name="FileBrowser.FolderShortcut.Remove">
+  <summary>
+    Chrome OS File Browser: this is recorded when the user removes a folder
+    shortcut.
+  </summary>
+</histogram>
+
 <histogram name="FileBrowser.Load" units="milliseconds">
   <summary>
     Chrome OS File Browser is an built-in extension without a background page.
@@ -6781,7 +6815,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.PreconnectedLinkNavigation" enum="PreconnectedNavigation">
+<histogram name="Net.PreconnectedLinkNavigations" enum="PreconnectedNavigation">
   <summary>
     Indicate whether a link navigation was preceded by a recent pre-connect
     trigger (within 10 seconds). There is a high chance that loading the page
@@ -7123,6 +7157,22 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.ConnectionCloseErrorCodeClient"
+    enum="QuicErrorCodes">
+  <summary>
+    The QUIC error code which resulted in the connection being closed by the
+    client.
+  </summary>
+</histogram>
+
+<histogram name="Net.QuicSession.ConnectionCloseErrorCodeServer"
+    enum="QuicErrorCodes">
+  <summary>
+    The QUIC error code which resulted in the connection being closed by the
+    server.
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.OutOfOrderPacketsReceived">
   <summary>
     The number of times packets the current received packet had a lower sequence
@@ -8887,10 +8937,14 @@
   </summary>
 </histogram>
 
-<histogram name="Network.Shill.Wifi.FrequenciesConnectedEver">
+<histogram name="Network.Shill.WiFi.FrequenciesConnectedEver">
   <summary>
-    Chrome OS network diagnostic metric sampling the number of different WiFi
-    frequencies to which the user's machine has ever connected.
+    Chrome OS metric sampling the number of different frequencies (i.e.
+    channels) on which a device has connected to a WiFi network. This value is
+    sampled every time a WiFi connection is established
+    (WPASupplicant::kInterfaceStateCompleted). Note that the word
+    &quot;Ever&quot; in the metric name is misleading. ChromeOS actually ages
+    out historical information, currently after 3 weeks.
   </summary>
 </histogram>
 
@@ -9415,6 +9469,17 @@
   <summary>Time spent on the Suggested Sites NTP pane, in seconds.</summary>
 </histogram>
 
+<histogram name="NewTabPage.ThumbnailErrorRate">
+  <summary>
+    The percentage of errors per attempts to load image thumbnails on the New
+    Tab Page. When an error occurs, a grey tile is shown instead of a thumbnail
+    image. We measure the rate instead of the number of errors because multiple
+    attempts are made to load images at different times during the NTP's
+    lifetime. Each NTP session's error rate is logged after the user navigates
+    to a new URL from that NTP.
+  </summary>
+</histogram>
+
 <histogram name="NewTabPage.VisibleScreenshots">
   <summary>
     The number of screenshots that were cached for the visible suggestions on
@@ -9521,6 +9586,12 @@
   </summary>
 </histogram>
 
+<histogram name="Omnibox.SearchEngineType" enum="OmniboxSearchEngineType">
+  <summary>
+    The type of search engine associated with a match opened from the omnibox.
+  </summary>
+</histogram>
+
 <histogram name="Omnibox.SuggestRequest.Failure.GoogleResponseTime"
     units="milliseconds">
   <summary>
@@ -9587,6 +9658,14 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.ProvisionalSaveFailure"
+    enum="ProvisionalSaveFailure">
+  <summary>
+    Breakdown of cases where a password is submitted, but we don't even try and
+    save it. Recorded for every password form submit.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.TimesGeneratedPasswordUsed">
   <summary>
     The number of times each generated password has been used to log in.
@@ -9935,6 +10014,18 @@
   <summary>Chrome OS stateful partition usage level.</summary>
 </histogram>
 
+<histogram name="Platform.SwapInLong" units="pages/second">
+  <summary>
+    Average pages/second swapped IN over a 30s interval, sampled every 30s.
+  </summary>
+</histogram>
+
+<histogram name="Platform.SwapInShort" units="pages/second">
+  <summary>
+    Average pages/second swapped IN over a 1s interval, sampled every 30s.
+  </summary>
+</histogram>
+
 <histogram name="Platform.SwapJank.Scroll.Cpu.Swap0.Time1" units="%">
   <summary>
     CPU utilization for the specified swap group and time interval after a
@@ -10415,6 +10506,18 @@
   </summary>
 </histogram>
 
+<histogram name="Platform.SwapOutLong" units="pages/second">
+  <summary>
+    Average pages/second swapped OUT over a 30s interval, sampled every 30s.
+  </summary>
+</histogram>
+
+<histogram name="Platform.SwapOutShort" units="pages/second">
+  <summary>
+    Average pages/second swapped OUT over a 1s interval, sampled every 30s.
+  </summary>
+</histogram>
+
 <histogram name="Platform.Temperature.Junction" units="Celsius">
   <summary>
     Peak junction temperature for the last sample interval, read from TSEN on
@@ -10538,6 +10641,13 @@
   <summary>TBD</summary>
 </histogram>
 
+<histogram name="PLT.BeginToFinish_AfterPreconnectRequest" units="milliseconds">
+  <summary>
+    PLT.BeginToFinish, but for pages requested just after a new preconnect
+    request.
+  </summary>
+</histogram>
+
 <histogram name="PLT.BeginToFinish_ContentPrefetcher" units="milliseconds">
   <summary>
     PLT.BeginToFinish, but for pages which contained prefetch links.
@@ -10556,6 +10666,14 @@
   <summary>TBD</summary>
 </histogram>
 
+<histogram name="PLT.BeginToFinishDoc_AfterPreconnectRequest"
+    units="milliseconds">
+  <summary>
+    PLT.BeginToFinishDoc, but for pages requested just after a new preconnect
+    request.
+  </summary>
+</histogram>
+
 <histogram name="PLT.BeginToFinishDoc_ContentPrefetcher" units="milliseconds">
   <summary>
     PLT.BeginToFinishDoc, but for pages which contained prefetch links.
@@ -11643,6 +11761,13 @@
   </summary>
 </histogram>
 
+<histogram name="ProfileReset.SendFeedback" enum="Boolean">
+  <summary>
+    Signifies if the user selected &quot;Send feedback&quot; checkbox in the
+    Reset Profile dialog.
+  </summary>
+</histogram>
+
 <histogram name="Protector.DefaultSearchProvider" enum="ProtectorError">
   <obsolete>
     Deprecated 8/2013. No longer tracked.
@@ -13267,6 +13392,25 @@
   </summary>
 </histogram>
 
+<histogram name="Search.DefaultSearchProviderType"
+    enum="OmniboxSearchEngineType">
+  <summary>
+    The type of the default search engine that is loaded when a profile is
+    opened or after a profile reset.  Note that at least one profile is opened
+    on startup.
+  </summary>
+</histogram>
+
+<histogram name="Settings.DefaultSearchProvider" enum="OmniboxSearchEngine">
+  <obsolete>
+    Deprecated in Chrome 30.  Use Search.DefaultSearchProviderType instead.
+  </obsolete>
+  <summary>
+    The id of the default search engine domain that is specified in user
+    preferences when a profile is loaded.
+  </summary>
+</histogram>
+
 <histogram name="Settings.GivenShowHomeButton_HomePageIsNewTabPage"
     enum="Boolean">
   <summary>
@@ -13275,6 +13419,26 @@
   </summary>
 </histogram>
 
+<histogram name="Settings.HomePageDomain" enum="OmniboxSearchEngine">
+  <obsolete>
+    Deprecated in Chrome 30.  Replaced by Settings.HomePageEngineType.
+  </obsolete>
+  <summary>
+    The id of the home page domain that is specified in user preferences when a
+    profile is loaded.
+  </summary>
+</histogram>
+
+<histogram name="Settings.HomePageEngineType" enum="OmniboxSearchEngineType">
+  <summary>
+    Tries to pretend the home page URL is a search URL, and records the search
+    engine type of that URL by comparing the TLD+1 of the home page URL with
+    those of the different known search engines.  Recorded when a profile is
+    opened, if a home page URL has been set.  Note that at least one profile is
+    opened on startup.
+  </summary>
+</histogram>
+
 <histogram name="Settings.HomePageIsNewTabPage" enum="Boolean">
   <obsolete>
     Deprecated 08/05/2013. Replaced by
@@ -13321,6 +13485,27 @@
   </summary>
 </histogram>
 
+<histogram name="Settings.StartupPageDomains" enum="OmniboxSearchEngine">
+  <obsolete>
+    Deprecated in Chrome 30.  Replaced by Settings.StartupPageEngineTypes.
+  </obsolete>
+  <summary>
+    The ids of startup page domains that are specified in user preferences when
+    a profile is loaded.
+  </summary>
+</histogram>
+
+<histogram name="Settings.StartupPageEngineTypes"
+    enum="OmniboxSearchEngineType">
+  <summary>
+    Tries to pretend the startup page URLs are search URLs, and records the
+    search engine types of those URLs by comparing the TLD+1s of the URLs with
+    those of the different known search engines.  Recorded when a profile is
+    opened, if startup page URLs have been set.  Note that at least one profile
+    is opened on startup.
+  </summary>
+</histogram>
+
 <histogram name="Settings.StartupPageLoadSettings" enum="SessionStartupPref">
   <summary>The startup page settings when a profile is loaded.</summary>
 </histogram>
@@ -13730,6 +13915,13 @@
   </summary>
 </histogram>
 
+<histogram name="SimpleCache.SyncOpenEntryAge" units="hours">
+  <summary>
+    The age of the entry (time since last modified), when opened at the
+    synchronous layer.
+  </summary>
+</histogram>
+
 <histogram name="SimpleCache.SyncOpenPlatformFileError"
     enum="PlatformFileError">
   <summary>
@@ -15125,6 +15317,13 @@
   </summary>
 </histogram>
 
+<histogram name="WebCore.PreloadDelayMs" units="milliseconds">
+  <summary>
+    The delay between when the preload scanner discovers a resource on the
+    parser thread and when the preload request is issued on the main thread.
+  </summary>
+</histogram>
+
 <histogram name="WebCore.V8DOMWindowShell.createContext.IsolatedWorld"
     units="milliseconds">
   <summary>
@@ -15205,6 +15404,16 @@
   </summary>
 </histogram>
 
+<histogram name="WebFont.LayoutLatency" units="milliseconds">
+  <obsolete>
+    Renamed to WebFont.StyleRecalcToDownloadLatency for clarity.
+  </obsolete>
+  <summary>
+    The time from when the webfont was referenced by a calculated style for the
+    first time to the start of the font download.
+  </summary>
+</histogram>
+
 <histogram name="WebFont.LoadTime.0.Under10KB" units="milliseconds">
   <obsolete>
     Deprecated as of 8/2013, replaced by WebFont.DownloadTime.0.Under10KB.
@@ -15272,6 +15481,25 @@
   </summary>
 </histogram>
 
+<histogram name="WebFont.StyleRecalcToDownloadLatency" units="milliseconds">
+  <summary>
+    The time from when the webfont was referenced by a calculated style for the
+    first time to the start of the font download.
+  </summary>
+</histogram>
+
+<histogram name="WebFont.UsageType" enum="WebFontUsageType">
+  <summary>
+    For each webfont, this records (a) if the font was 'styled', i.e. referenced
+    by a calculated style for a RenderText before the font data was used, and
+    (b) if the font was actually used or not, i.e. the renderer requested the
+    font data or not. (A Font can be used without being styled, for example when
+    drawn by a Canvas 2D Context.) This is recorded upon a download request of a
+    webfont, or destruction of a CSSFontFaceSource object. Recorded at most once
+    for each url() source of @font-face CSS rule.
+  </summary>
+</histogram>
+
 <histogram name="WebFont.WebFontsInPage">
   <summary>
     The number of webfonts used in a page. This is recorded when the first
@@ -17139,7 +17367,7 @@
   <int value="34" label="AUTOTESTPRIVATE_RESTART"/>
   <int value="35" label="USB_CLAIMINTERFACE"/>
   <int value="36" label="MEDIAPLAYERPRIVATE_SETWINDOWHEIGHT"/>
-  <int value="37" label="EXPERIMENTAL_PROCESSES_GETPROCESSINFO"/>
+  <int value="37" label="PROCESSES_GETPROCESSINFO"/>
   <int value="38" label="HISTORY_GETVISITS"/>
   <int value="39" label="SOCKET_BIND"/>
   <int value="40" label="TABS_MOVE"/>
@@ -17204,7 +17432,7 @@
   <int value="99" label="WINDOWS_CREATE"/>
   <int value="100" label="DEVELOPERPRIVATE_LOADUNPACKED"/>
   <int value="101" label="DELETED_DOWNLOADS_SETDESTINATION"/>
-  <int value="102" label="EXPERIMENTAL_PROCESSES_GETPROCESSIDFORTAB"/>
+  <int value="102" label="PROCESSES_GETPROCESSIDFORTAB"/>
   <int value="103" label="BOOKMARKS_GETCHILDREN"/>
   <int value="104" label="BROWSERACTION_GETTITLE"/>
   <int value="105" label="TERMINALPRIVATE_OPENTERMINALPROCESS"/>
@@ -17398,7 +17626,7 @@
   <int value="292" label="EXPERIMENTAL_APP_NOTIFY"/>
   <int value="293" label="METRICSPRIVATE_RECORDLONGTIME"/>
   <int value="294" label="SOCKET_READ"/>
-  <int value="295" label="EXPERIMENTAL_PROCESSES_TERMINATE"/>
+  <int value="295" label="PROCESSES_TERMINATE"/>
   <int value="296" label="METRICSPRIVATE_RECORDTIME"/>
   <int value="297" label="BOOKMARKMANAGERPRIVATE_GETSTRINGS"/>
   <int value="298" label="USB_ISOCHRONOUSTRANSFER"/>
@@ -17622,6 +17850,7 @@
   <int value="515" label="SYSTEM_STORAGE_REMOVEALLAVAILABLECAPACITYWATCHES"/>
   <int value="516" label="INFOBARS_SHOW"/>
   <int value="517" label="EXPERIMENTAL_INPUT_VIRTUALKEYBOARD_MOVECURSOR"/>
+  <int value="518" label="AUTOTESTPRIVATE_SIMULATEASANMEMORYBUG"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">
@@ -17747,6 +17976,8 @@
   <int value="3" label="ENABLED (in webstore)"/>
   <int value="4" label="DISABLED (not in webstore)"/>
   <int value="5" label="ENABLED (not in webstore)"/>
+  <int value="6" label="UNINSTALLED (in webstore)"/>
+  <int value="7" label="UNINSTALLED (not in webstore)"/>
 </enum>
 
 <enum name="Exynos5250LotIdEnum" type="int">
@@ -17866,6 +18097,29 @@
   <int value="97" label="SubFrameBeforeUnloadRegistered"/>
   <int value="98" label="SubFrameBeforeUnloadFired"/>
   <int value="99" label="CSSPseudoElementPrefixedDistributed"/>
+  <int value="100" label="TextReplaceWholeText"/>
+  <int value="101" label="PrefixedShadowRootConstructor"/>
+  <int value="102" label="ConsoleMarkTimeline"/>
+  <int value="103" label="CSSPseudoElementUserAgentCustomPseudo"/>
+  <int value="104" label="DocumentTypeEntities"/>
+  <int value="105" label="DocumentTypeInternalSubset"/>
+  <int value="106" label="DocumentTypeNotations"/>
+  <int value="107" label="ElementGetAttributeNode"/>
+  <int value="108" label="ElementSetAttributeNode"/>
+  <int value="109" label="ElementRemoveAttributeNode"/>
+  <int value="110" label="ElementGetAttributeNodeNS"/>
+  <int value="111" label="DocumentCreateAttribute"/>
+  <int value="112" label="DocumentCreateAttributeNS"/>
+  <int value="113" label="DocumentCreateCDATASection"/>
+  <int value="114" label="DocumentInputEncoding"/>
+  <int value="115" label="DocumentXMLEncoding"/>
+  <int value="116" label="DocumentXMLStandalone"/>
+  <int value="117" label="DocumentXMLVersion"/>
+  <int value="118" label="NodeIsSameNode"/>
+  <int value="119" label="NodeIsSupported"/>
+  <int value="120" label="NodeNamespaceURI"/>
+  <int value="121" label="NodePrefix"/>
+  <int value="122" label="NodeLocalName"/>
 </enum>
 
 <enum name="FFmpegCodecs" type="int">
@@ -20393,6 +20647,7 @@
   <int value="32" label="diri"/>
   <int value="33" label="Custom"/>
   <int value="35" label="AOL"/>
+  <int value="36" label="Conduit"/>
   <int value="37" label="Rediff"/>
   <int value="38" label="guruji"/>
   <int value="40" label="GO.com"/>
@@ -20400,6 +20655,7 @@
   <int value="44" label="NETI"/>
   <int value="45" label="DELFI"/>
   <int value="46" label="Fonecta 02.fi"/>
+  <int value="50" label="AVG"/>
   <int value="51" label="search.ch"/>
   <int value="54" label="in.gr"/>
   <int value="55" label="Walla!"/>
@@ -20424,6 +20680,70 @@
   <int value="99" label="Spray"/>
   <int value="100" label="Sanook!"/>
   <int value="101" label="MYNET"/>
+  <int value="102" label="searchnu.com"/>
+  <int value="103" label="babylon.com"/>
+  <int value="104" label="delta-search.com"/>
+  <int value="105" label="iminent.com"/>
+  <int value="106" label="hao123.com"/>
+  <int value="107" label="sweetim.com"/>
+  <int value="108" label="snap.do"/>
+  <int value="109" label="snapdo.com"/>
+  <int value="110" label="softonic.com"/>
+  <int value="111" label="searchfunmoods.com"/>
+  <int value="112" label="incredibar.com"/>
+  <int value="113" label="sweetpacks.com"/>
+  <int value="114" label="imesh.net"/>
+</enum>
+
+<enum name="OmniboxSearchEngineType" type="int">
+  <int value="0" label="Unknown"/>
+  <int value="1" label="AOL"/>
+  <int value="2" label="Ask"/>
+  <int value="3" label="Atlas"/>
+  <int value="4" label="AVG"/>
+  <int value="5" label="Baidu"/>
+  <int value="6" label="Babylon"/>
+  <int value="7" label="Bing"/>
+  <int value="8" label="Conduit"/>
+  <int value="9" label="Daum"/>
+  <int value="10" label="DELFI"/>
+  <int value="11" label="Delta"/>
+  <int value="12" label="Funmoods"/>
+  <int value="13" label="goo"/>
+  <int value="14" label="Google"/>
+  <int value="15" label="iminent.com"/>
+  <int value="16" label="IMesh"/>
+  <int value="17" label="in.gr"/>
+  <int value="18" label="incredibar.com"/>
+  <int value="19" label="Kvasir"/>
+  <int value="20" label="Libero"/>
+  <int value="21" label="@MAIL.RU"/>
+  <int value="22" label="Najdi.si"/>
+  <int value="23" label="Nate"/>
+  <int value="24" label="Naver"/>
+  <int value="25" label="NETI"/>
+  <int value="26" label="Nigma"/>
+  <int value="27" label="OK.hu"/>
+  <int value="28" label="Onet.pl"/>
+  <int value="29" label="Rambler"/>
+  <int value="30" label="SAPO"/>
+  <int value="31" label="searchnu"/>
+  <int value="32" label="search-results.com"/>
+  <int value="33" label="Seznam"/>
+  <int value="34" label="snap.do"/>
+  <int value="35" label="softonic.com"/>
+  <int value="36" label="Sogou"/>
+  <int value="37" label="Soso"/>
+  <int value="38" label="sweetim.com/sweetpacks.com"/>
+  <int value="39" label="Terra"/>
+  <int value="40" label="TUT.BY"/>
+  <int value="41" label="Vinden.nl"/>
+  <int value="42" label="Virgilio"/>
+  <int value="43" label="Walla!"/>
+  <int value="44" label="Wirtualna Polska"/>
+  <int value="45" label="Yahoo!"/>
+  <int value="46" label="Yandex"/>
+  <int value="47" label="Zoznam"/>
 </enum>
 
 <enum name="OmniboxSuggestRequests" type="int">
@@ -20866,6 +21186,16 @@
   <int value="5" label="SPDY 3.0"/>
 </enum>
 
+<enum name="ProvisionalSaveFailure" type="int">
+  <int value="0" label="SAVING_DISABLED"/>
+  <int value="1" label="EMPTY_PASSWORD"/>
+  <int value="2" label="NO_MATCHING_FORM"/>
+  <int value="3" label="MATCHING_NOT_COMPLETE"/>
+  <int value="4" label="FORM_BLACKLISTED"/>
+  <int value="5" label="INVALID_FORM"/>
+  <int value="6" label="AUTOCOMPLETE_OFF"/>
+</enum>
+
 <enum name="ProxyStatus" type="int">
   <int value="0" label="PROXY_STATUS_IGNORED"/>
   <int value="1" label="PROXY_UNINITIALIZED"/>
@@ -20947,6 +21277,9 @@
   <int value="43" label="CRYPTO_DUPLICATE_TAG"/>
   <int value="44" label="CRYPTO_ENCRYPTION_LEVEL_INCORRECT"/>
   <int value="45" label="CRYPTO_SERVER_CONFIG_EXPIRED"/>
+  <int value="46" label="INVALID_STREAM_DATA"/>
+  <int value="47" label="INVALID_CONGESTION_FEEDBACK_DATA"/>
+  <int value="48" label="MISSING_PAYLOAD"/>
 </enum>
 
 <enum name="QuicHandshakeState" type="int">
@@ -21446,8 +21779,12 @@
 </enum>
 
 <enum name="SimpleCacheReadParallelizable" type="int">
-  <int value="0" label="Standalone Read"/>
-  <int value="1" label="Read in a sequence"/>
+  <int value="0" label="Standalone Read (obsolete)"/>
+  <int value="1" label="Follows read"/>
+  <int value="2" label="Follows conflicting write"/>
+  <int value="3" label="Follows non conflicting write"/>
+  <int value="4" label="Follows other operation"/>
+  <int value="5" label="Read alone in queue"/>
 </enum>
 
 <enum name="SimpleCacheReadResult" type="int">
@@ -22582,6 +22919,12 @@
   <int value="11" label="Require phone number"/>
 </enum>
 
+<enum name="WebFontUsageType" type="int">
+  <int value="0" label="Styled, and used"/>
+  <int value="1" label="Styled, but not used"/>
+  <int value="2" label="Not styled, but used"/>
+</enum>
+
 <enum name="WebHistoryStatus" type="int">
   <int value="0" label="WEB_HISTORY_QUERY_FAILED">Failed</int>
   <int value="1" label="WEB_HISTORY_QUERY_SUCCEEDED">Succeeded</int>
diff --git a/tools/perf/benchmarks/page_cycler.py b/tools/perf/benchmarks/page_cycler.py
index ea06ad3..bca43f7 100644
--- a/tools/perf/benchmarks/page_cycler.py
+++ b/tools/perf/benchmarks/page_cycler.py
@@ -32,7 +32,7 @@
 
 class PageCyclerIntlEsFrPtBr(test.Test):
   test = page_cycler.PageCycler
-  page_set = 'page_sets/intel_es_fr_pt-BR.json'
+  page_set = 'page_sets/intl_es_fr_pt-BR.json'
   options = {'pageset_repeat_iters': 10}
 
 
@@ -56,7 +56,7 @@
 
 class PageCyclerMorejs(test.Test):
   test = page_cycler.PageCycler
-  page_set = 'page_sets/morejs.json'
+  page_set = 'page_sets/page_cycler/morejs.json'
   options = {'pageset_repeat_iters': 10}
 
 
@@ -69,7 +69,7 @@
 class PageCyclerNetsimTop25(test.Test):
   """Measures load time of the top 25 sites under simulated cable network."""
   test = page_cycler.PageCycler
-  page_set = 'tools/perf/page_sets/top_25.json'
+  page_set = 'page_sets/top_25.json'
   options = {
     'extra_wpr_args': [
       '--shaping_type=proxy',
diff --git a/tools/perf/measurements/blink_perf.py b/tools/perf/measurements/blink_perf.py
index 39ed0a2..f21cf98 100644
--- a/tools/perf/measurements/blink_perf.py
+++ b/tools/perf/measurements/blink_perf.py
@@ -82,6 +82,7 @@
 
   def CustomizeBrowserOptions(self, options):
     options.AppendExtraBrowserArg('--js-flags=--expose_gc')
+    options.AppendExtraBrowserArg('--enable-experimental-web-platform-features')
 
   def MeasurePage(self, page, tab, results):
     def _IsDone():
diff --git a/tools/perf/measurements/endure.py b/tools/perf/measurements/endure.py
new file mode 100644
index 0000000..9cf4e75
--- /dev/null
+++ b/tools/perf/measurements/endure.py
@@ -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.
+
+from telemetry.page import page_measurement
+
+import optparse
+import time
+
+
+class Endure(page_measurement.PageMeasurement):
+  def __init__(self):
+    super(Endure, self).__init__('endure')
+    self._test_start_time = None
+
+    # Timestamp of the last memory retrieval.
+    self._last_mem_dump = 0
+
+  def AddCommandLineOptions(self, parser):
+    group = optparse.OptionGroup(parser, 'Endure options')
+    group.add_option('--perf-stats-interval',
+                     dest='perf_stats_interval',
+                     default=20,
+                     type='int',
+                     help='Time interval between perf dumps (secs)')
+    parser.add_option_group(group)
+
+  def CanRunForPage(self, page):
+    return hasattr(page, 'endure')
+
+  def WillRunPageRepeats(self, page, tab):
+    """Reset the starting time for each new page."""
+    self._test_start_time = time.time()
+
+  def MeasurePage(self, page, tab, results):
+    """Dump perf information if we have gone past our interval time."""
+    now = time.time()
+    if int(round(now - self._last_mem_dump)) > self.options.perf_stats_interval:
+      self._last_mem_dump = now
+      self._GetPerformanceStats(tab, results, now)
+
+  def _GetPerformanceStats(self, tab, results, now):
+    """Record all memory information."""
+    elapsed_time = int(round(now - self._test_start_time))
+
+    # DOM Nodes
+    dom_node_count = tab.dom_stats['node_count']
+    self._SaveToResults(results, 'TotalDOMNodeCount_X',
+                        'seconds', elapsed_time)
+    self._SaveToResults(results, 'TotalDOMNodeCount_Y',
+                        'nodes', dom_node_count)
+
+    # Event Listeners
+    event_listener_count = tab.dom_stats['event_listener_count']
+    self._SaveToResults(results, 'EventListenerCount_X',
+                        'seconds', elapsed_time)
+    self._SaveToResults(results, 'EventListenerCount_Y',
+                        'listeners', event_listener_count)
+
+  def _SaveToResults(self, results, trace_name, units, value,
+                     chart_name=None, data_type='default'):
+    results.Add(trace_name, units, value, chart_name, data_type)
diff --git a/tools/perf/measurements/loading_profile.py b/tools/perf/measurements/loading_profile.py
index efaf4d7..e6fd88e 100644
--- a/tools/perf/measurements/loading_profile.py
+++ b/tools/perf/measurements/loading_profile.py
@@ -29,7 +29,6 @@
     parser.add_option(page_repeat_option)
 
   def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArg('--no-sandbox')
     perf_profiler.PerfProfiler.CustomizeBrowserOptions(options)
 
   def WillNavigateToPage(self, page, tab):
diff --git a/tools/perf/measurements/loading_timeline.py b/tools/perf/measurements/loading_timeline.py
index 9ec9e70..113f2e1 100644
--- a/tools/perf/measurements/loading_timeline.py
+++ b/tools/perf/measurements/loading_timeline.py
@@ -9,15 +9,14 @@
 class LoadingTimeline(page_measurement.PageMeasurement):
   def __init__(self, *args, **kwargs):
     super(LoadingTimeline, self).__init__(*args, **kwargs)
-    self._metrics = None
+    self._timeline_metric = timeline.TimelineMetric(timeline.TIMELINE_MODE)
 
   @property
   def results_are_the_same_on_every_page(self):
     return False
 
   def WillNavigateToPage(self, page, tab):
-    self._metrics = timeline.TimelineMetrics(timeline.TIMELINE_MODE)
-    self._metrics.Start(tab)
+    self._timeline_metric.Start(page, tab)
 
   def MeasurePage(self, page, tab, results):
     # In current telemetry tests, all tests wait for DocumentComplete state,
@@ -28,7 +27,7 @@
 
     # TODO(nduca): when crbug.com/168431 is fixed, modify the page sets to
     # recognize loading as a toplevel action.
-    self._metrics.Stop(tab)
+    self._timeline_metric.Stop(page, tab)
 
     loading.LoadingMetric().AddResults(tab, results)
-    self._metrics.AddResults(results)
+    self._timeline_metric.AddResults(tab, results)
diff --git a/tools/perf/measurements/loading_trace.py b/tools/perf/measurements/loading_trace.py
index 68f241b..16d9300 100644
--- a/tools/perf/measurements/loading_trace.py
+++ b/tools/perf/measurements/loading_trace.py
@@ -9,15 +9,14 @@
 class LoadingTrace(page_measurement.PageMeasurement):
   def __init__(self, *args, **kwargs):
     super(LoadingTrace, self).__init__(*args, **kwargs)
-    self._metrics = None
+    self._timeline_metric = timeline.TimelineMetric(timeline.TRACING_MODE)
 
   @property
   def results_are_the_same_on_every_page(self):
     return False
 
   def WillNavigateToPage(self, page, tab):
-    self._metrics = timeline.TimelineMetrics(timeline.TRACING_MODE)
-    self._metrics.Start(tab)
+    self._timeline_metric.Start(page, tab)
 
   def MeasurePage(self, page, tab, results):
     # In current telemetry tests, all tests wait for DocumentComplete state,
@@ -28,7 +27,8 @@
 
     # TODO(nduca): when crbug.com/168431 is fixed, modify the page sets to
     # recognize loading as a toplevel action.
-    self._metrics.Stop(tab)
+    self._timeline_metric.Stop(page, tab)
 
     loading.LoadingMetric().AddResults(tab, results)
-    self._metrics.AddResults(results)
+    self._timeline_metric.AddResults(tab, results)
+
diff --git a/tools/perf/measurements/memory.py b/tools/perf/measurements/memory.py
index f15184a..68d4d7d 100644
--- a/tools/perf/measurements/memory.py
+++ b/tools/perf/measurements/memory.py
@@ -1,66 +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.
-from metrics import histogram
+
 from metrics import memory
 from telemetry.page import page_measurement
 
-
-MEMORY_HISTOGRAMS = [
-    {'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent'},
-    {'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb'},
-    {'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb'},
-    {'name': 'Memory.RendererUsed', 'units': 'kb'}]
-
-
-BROWSER_MEMORY_HISTOGRAMS =  [
-    {'name': 'Memory.BrowserUsed', 'units': 'kb'}]
-
-
 class Memory(page_measurement.PageMeasurement):
   def __init__(self):
     super(Memory, self).__init__('stress_memory')
-    self.histograms = (
-        [histogram.HistogramMetric(
-            h, histogram.RENDERER_HISTOGRAM)
-         for h in MEMORY_HISTOGRAMS] +
-        [histogram.HistogramMetric(
-            h, histogram.BROWSER_HISTOGRAM)
-         for h in BROWSER_MEMORY_HISTOGRAMS])
-
     self._memory_metric = None
 
   def DidStartBrowser(self, browser):
     self._memory_metric = memory.MemoryMetric(browser)
-    self._memory_metric.Start()
 
   def DidNavigateToPage(self, page, tab):
-    for h in self.histograms:
-      h.Start(page, tab)
+    self._memory_metric.Start(page, tab)
 
   def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArg('--enable-stats-collection-bindings')
-    options.AppendExtraBrowserArg('--enable-memory-benchmarking')
-    # For a hard-coded set of Google pages (such as GMail), we produce custom
-    # memory histograms (V8.Something_gmail) instead of the generic histograms
-    # (V8.Something), if we detect that a renderer is only rendering this page
-    # and no other pages. For this test, we need to disable histogram
-    # customizing, so that we get the same generic histograms produced for all
-    # pages.
-    options.AppendExtraBrowserArg('--disable-histogram-customizer')
+    memory.MemoryMetric.CustomizeBrowserOptions(options)
+    # Since this is a memory benchmark, we want to sample memory histograms at
+    # a high frequency.
     options.AppendExtraBrowserArg('--memory-metrics')
 
-    # Old commandline flags used for reference builds.
-    options.AppendExtraBrowserArg('--dom-automation')
-    options.AppendExtraBrowserArg(
-          '--reduce-security-for-dom-automation-tests')
-
   def CanRunForPage(self, page):
     return hasattr(page, 'stress_memory')
 
   def MeasurePage(self, page, tab, results):
-    for h in self.histograms:
-      h.GetValue(page, tab, results)
+    self._memory_metric.Stop(page, tab)
+    self._memory_metric.AddResults(tab, results)
 
     if tab.browser.is_profiler_active('tcmalloc-heap'):
       # The tcmalloc_heap_profiler dumps files at regular
@@ -69,12 +36,10 @@
       # the test completes.
       tab.ExecuteJavaScript("""
         if (chrome && chrome.memoryBenchmarking) {
-          chrome.memoryBenchmarking.heapProfilerDump('final', 'renderer');
-          chrome.memoryBenchmarking.heapProfilerDump('final', 'browser');
+          chrome.memoryBenchmarking.heapProfilerDump('renderer', 'final');
+          chrome.memoryBenchmarking.heapProfilerDump('browser', 'final');
         }
       """)
 
   def DidRunTest(self, tab, results):
-    self._memory_metric.Stop()
-    self._memory_metric.AddResults(tab, results)
-
+    self._memory_metric.AddSummaryResults(results)
diff --git a/tools/perf/measurements/page_cycler.py b/tools/perf/measurements/page_cycler.py
index 5ea9897..e373eea 100644
--- a/tools/perf/measurements/page_cycler.py
+++ b/tools/perf/measurements/page_cycler.py
@@ -18,18 +18,11 @@
 import os
 import sys
 
-from metrics import histogram
+from metrics import io
 from metrics import memory
 from telemetry.core import util
 from telemetry.page import page_measurement
 
-
-MEMORY_HISTOGRAMS = [
-    {'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent'},
-    {'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb'},
-    {'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb'}]
-
-
 class PageCycler(page_measurement.PageMeasurement):
   def __init__(self, *args, **kwargs):
     super(PageCycler, self).__init__(*args, **kwargs)
@@ -39,7 +32,6 @@
       self._page_cycler_js = f.read()
 
     self._memory_metric = None
-    self._histograms = None
 
   def AddCommandLineOptions(self, parser):
     # The page cyclers should default to 10 iterations. In order to change the
@@ -53,10 +45,6 @@
   def DidStartBrowser(self, browser):
     """Initialize metrics once right after the browser has been launched."""
     self._memory_metric = memory.MemoryMetric(browser)
-    self._memory_metric.Start()
-    self._histograms = [histogram.HistogramMetric(
-                           h, histogram.RENDERER_HISTOGRAM)
-                       for h in MEMORY_HISTOGRAMS]
 
   def DidStartHTTPServer(self, tab):
     # Avoid paying for a cross-renderer navigation on the first page on legacy
@@ -67,66 +55,30 @@
     page.script_to_evaluate_on_commit = self._page_cycler_js
 
   def DidNavigateToPage(self, page, tab):
-    for h in self._histograms:
-      h.Start(page, tab)
+    self._memory_metric.Start(page, tab)
 
   def CustomizeBrowserOptions(self, options):
-    options.AppendExtraBrowserArg('--enable-stats-collection-bindings')
+    memory.MemoryMetric.CustomizeBrowserOptions(options)
+    io.IOMetric.CustomizeBrowserOptions(options)
     options.AppendExtraBrowserArg('--js-flags=--expose_gc')
-    options.AppendExtraBrowserArg('--no-sandbox')
-
-    # Old commandline flags used for reference builds.
-    options.AppendExtraBrowserArg('--dom-automation')
 
     # Temporarily disable typical_25 page set on mac.
     if sys.platform == 'darwin' and sys.argv[-1].endswith('/typical_25.json'):
       print 'typical_25 is currently disabled on mac. Skipping test.'
       sys.exit(0)
 
-  def MeasureIO(self, tab, results):
-    io_stats = tab.browser.io_stats
-    if not io_stats['Browser']:
-      return
-
-    def AddSummariesForProcessType(process_type_io, process_type_trace):
-      if 'ReadOperationCount' in io_stats[process_type_io]:
-        results.AddSummary('read_operations_' + process_type_trace, '',
-                           io_stats[process_type_io]
-                           ['ReadOperationCount'],
-                           data_type='unimportant')
-      if 'WriteOperationCount' in io_stats[process_type_io]:
-        results.AddSummary('write_operations_' + process_type_trace, '',
-                           io_stats[process_type_io]
-                           ['WriteOperationCount'],
-                           data_type='unimportant')
-      if 'ReadTransferCount' in io_stats[process_type_io]:
-        results.AddSummary('read_bytes_' + process_type_trace, 'kb',
-                           io_stats[process_type_io]
-                           ['ReadTransferCount'] / 1024,
-                           data_type='unimportant')
-      if 'WriteTransferCount' in io_stats[process_type_io]:
-        results.AddSummary('write_bytes_' + process_type_trace, 'kb',
-                           io_stats[process_type_io]
-                           ['WriteTransferCount'] / 1024,
-                           data_type='unimportant')
-    AddSummariesForProcessType('Browser', 'browser')
-    AddSummariesForProcessType('Renderer', 'renderer')
-    AddSummariesForProcessType('Gpu', 'gpu')
-
   def MeasurePage(self, page, tab, results):
     def _IsDone():
       return bool(tab.EvaluateJavaScript('__pc_load_time'))
     util.WaitFor(_IsDone, 60)
-
-    for h in self._histograms:
-      h.GetValue(page, tab, results)
-
     results.Add('page_load_time', 'ms',
                 int(float(tab.EvaluateJavaScript('__pc_load_time'))),
                 chart_name='times')
 
-  def DidRunTest(self, tab, results):
-    self._memory_metric.Stop()
+    self._memory_metric.Stop(page, tab)
     self._memory_metric.AddResults(tab, results)
-    self.MeasureIO(tab, results)
+
+  def DidRunTest(self, tab, results):
+    self._memory_metric.AddSummaryResults(results)
+    io.IOMetric().AddSummaryResults(tab, results)
 
diff --git a/tools/perf/measurements/rasterize_and_record.py b/tools/perf/measurements/rasterize_and_record.py
index 0cab742..5ff174d 100644
--- a/tools/perf/measurements/rasterize_and_record.py
+++ b/tools/perf/measurements/rasterize_and_record.py
@@ -113,17 +113,17 @@
                       '(must be long enough to render one frame)')
 
   def CustomizeBrowserOptions(self, options):
-    options.extra_browser_args.append('--enable-gpu-benchmarking')
+    smoothness.SmoothnessMetrics.CustomizeBrowserOptions(options)
     # 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.
-    options.extra_browser_args.append(
+    options.AppendExtraBrowserArg(
         '--slow-down-raster-scale-factor=' + str(options.raster_record_repeat))
     # Enable impl-side-painting. Current version of benchmark only works for
     # this mode.
-    options.extra_browser_args.append('--enable-impl-side-painting')
-    options.extra_browser_args.append('--force-compositing-mode')
-    options.extra_browser_args.append('--enable-threaded-compositing')
+    options.AppendExtraBrowserArg('--enable-impl-side-painting')
+    options.AppendExtraBrowserArg('--force-compositing-mode')
+    options.AppendExtraBrowserArg('--enable-threaded-compositing')
 
   def MeasurePage(self, page, tab, results):
     self._metrics = smoothness.SmoothnessMetrics(tab)
diff --git a/tools/perf/measurements/smoothness.py b/tools/perf/measurements/smoothness.py
index 4bdbe07..a00c17d 100644
--- a/tools/perf/measurements/smoothness.py
+++ b/tools/perf/measurements/smoothness.py
@@ -19,7 +19,6 @@
   def __init__(self):
     super(Smoothness, self).__init__('smoothness')
     self.force_enable_threaded_compositing = False
-    self.use_gpu_benchmarking_extension = True
     self._metrics = None
 
   def AddCommandLineOptions(self, parser):
@@ -28,8 +27,7 @@
                       help='Reports all data collected, not just FPS')
 
   def CustomizeBrowserOptions(self, options):
-    if self.use_gpu_benchmarking_extension:
-      options.extra_browser_args.append('--enable-gpu-benchmarking')
+    smoothness.SmoothnessMetrics.CustomizeBrowserOptions(options)
     if self.force_enable_threaded_compositing:
       options.extra_browser_args.append('--enable-threaded-compositing')
 
diff --git a/tools/perf/measurements/startup.py b/tools/perf/measurements/startup.py
index 5792fee..0bb6f00 100644
--- a/tools/perf/measurements/startup.py
+++ b/tools/perf/measurements/startup.py
@@ -23,7 +23,6 @@
 
   def __init__(self):
     super(Startup, self).__init__(needs_browser_restart_after_each_run=True)
-    self._cold = False
 
   def AddCommandLineOptions(self, parser):
     parser.add_option('--cold', action='store_true',
@@ -36,9 +35,7 @@
     # or --cold is explicitly specified.
     # assert options.warm != options.cold, \
     #     "You must specify either --warm or --cold"
-    self._cold = options.cold
-
-    if self._cold:
+    if options.cold:
       options.clear_sytem_cache_for_browser_and_profile_on_start = True
     else:
       self.discard_first_result = True
diff --git a/tools/perf/measurements/tab_switching.py b/tools/perf/measurements/tab_switching.py
index d4d8e58..90beb13 100644
--- a/tools/perf/measurements/tab_switching.py
+++ b/tools/perf/measurements/tab_switching.py
@@ -20,6 +20,7 @@
   def CustomizeBrowserOptions(self, options):
     options.AppendExtraBrowserArg('--enable-stats-collection-bindings')
     options.AppendExtraBrowserArg('--dom-automation')
+    options.AppendExtraBrowserArg('--reduce-security-for-dom-automation-tests')
 
   def CanRunForPage(self, page):
     return not page.page_set.pages.index(page)
@@ -30,6 +31,7 @@
 
       page_state = page_runner.PageState()
       page_state.PreparePage(page.page_set.pages[i], t)
+      page_state.ImplicitPageNavigation(page.page_set.pages[i], t)
 
   def MeasurePage(self, _, tab, results):
     """Although this is called MeasurePage, we're actually using this function
@@ -37,7 +39,7 @@
     thenrecord a single histogram for the tab switching metric.
     """
     histogram_name = 'MPArch.RWH_TabSwitchPaintDuration'
-    histogram_type = 'getBrowserHistogram'
+    histogram_type = histogram_util.BROWSER_HISTOGRAM
     first_histogram = histogram_util.GetHistogramFromDomAutomation(
         histogram_type, histogram_name, tab)
     prev_histogram = first_histogram
diff --git a/tools/perf/metrics/__init__.py b/tools/perf/metrics/__init__.py
index 31be468..a1b9e47 100644
--- a/tools/perf/metrics/__init__.py
+++ b/tools/perf/metrics/__init__.py
@@ -11,6 +11,18 @@
   about one thing.
   """
 
+  @classmethod
+  def CustomizeBrowserOptions(cls, options):
+    """Add browser options that are required by this metric.
+
+    Some metrics do not have any special browser options that need
+    to be added, and they do not need to override this method; by
+    default, no browser options are added.
+
+    To add options here, call options.AppendExtraBrowserArg(arg).
+    """
+    pass
+
   def Start(self, page, tab):
     """Start collecting data for this metric."""
     raise NotImplementedError()
diff --git a/tools/perf/metrics/histogram.py b/tools/perf/metrics/histogram.py
deleted file mode 100644
index 147ae96..0000000
--- a/tools/perf/metrics/histogram.py
+++ /dev/null
@@ -1,40 +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.
-from metrics import histogram_util
-
-BROWSER_HISTOGRAM = 'browser_histogram'
-RENDERER_HISTOGRAM = 'renderer_histogram'
-
-class HistogramMetric(object):
-  def __init__(self, histogram, histogram_type):
-    self.name = histogram['name']
-    self.units = histogram['units']
-    self.histogram_type = histogram_type
-    self._start_values = dict()
-
-  def Start(self, page, tab):
-    """Get the starting value for the histogram. This value will then be
-    subtracted from the actual measurement."""
-    data = self._GetHistogramFromDomAutomation(tab)
-    if data:
-      self._start_values[page.url + self.name] = data
-
-  def GetValue(self, page, tab, results):
-    data = self._GetHistogramFromDomAutomation(tab)
-    if not data:
-      return
-    new_histogram = histogram_util.SubtractHistogram(
-        data, self._start_values[page.url + self.name])
-    results.Add(self.name, self.units, new_histogram,
-                data_type='unimportant-histogram')
-
-  @property
-  def histogram_function(self):
-    if self.histogram_type == BROWSER_HISTOGRAM:
-      return 'getBrowserHistogram'
-    return 'getHistogram'
-
-  def _GetHistogramFromDomAutomation(self, tab):
-    return histogram_util.GetHistogramFromDomAutomation(
-        self.histogram_function, self.name, tab)
diff --git a/tools/perf/metrics/histogram_util.py b/tools/perf/metrics/histogram_util.py
index 5b72f5e..1f255ca 100644
--- a/tools/perf/metrics/histogram_util.py
+++ b/tools/perf/metrics/histogram_util.py
@@ -1,12 +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.
+
+"""This is a helper module to get and manipulate histogram data.
+
+The histogram data is the same data as is visible from "chrome://histograms".
+More information can be found at: chromium/src/base/metrics/histogram.h
+
+Histogram data is collected with either the window.statsCollectionController
+object or the window.domAutomationController object.
+"""
+
 import json
 import logging
 
+BROWSER_HISTOGRAM = 'browser_histogram'
+RENDERER_HISTOGRAM = 'renderer_histogram'
+
 def SubtractHistogram(histogram_json, start_histogram_json):
-  """Subtracts a previous histogram from a histogram. Both parameters are json
-  serializations of histograms."""
+  """Subtracts a previous histogram from a histogram.
+
+  Both parameters and the returned result are json serializations.
+  """
   start_histogram = json.loads(start_histogram_json)
   # It's ok if the start histogram is empty (we had no data, maybe even no
   # histogram at all, at the start of the test).
@@ -40,11 +55,20 @@
 
   return json.dumps(histogram)
 
-def GetHistogramFromDomAutomation(function, name, tab):
+
+def GetHistogramFromDomAutomation(histogram_type, histogram_name, tab):
+  """Get a json serialization of a histogram."""
+  assert histogram_type in [BROWSER_HISTOGRAM, RENDERER_HISTOGRAM]
+  function = 'getHistogram'
+  if histogram_type == BROWSER_HISTOGRAM:
+    function = 'getBrowserHistogram'
   # TODO(jeremy): Remove references to
   # domAutomationController when we update the reference builds.
-  js = ('(window.statsCollectionController ? '
-        'statsCollectionController : '
-        'domAutomationController).%s("%s")' %
-        (function, name))
-  return tab.EvaluateJavaScript(js)
+  histogram_json = tab.EvaluateJavaScript(
+      '(window.statsCollectionController ? '
+      'statsCollectionController : '
+      'domAutomationController).%s("%s")' %
+      (function, histogram_name))
+  if histogram_json:
+    return histogram_json
+  return None
diff --git a/tools/perf/metrics/histogram_util_unittest.py b/tools/perf/metrics/histogram_util_unittest.py
index 7db5558..7cf313a 100644
--- a/tools/perf/metrics/histogram_util_unittest.py
+++ b/tools/perf/metrics/histogram_util_unittest.py
@@ -1,6 +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.
+
 import json
 import unittest
 
@@ -9,16 +10,16 @@
 class TestHistogram(unittest.TestCase):
   def testSubtractHistogram(self):
     baseline_histogram = """{"count": 3, "buckets": [
-{"low": 1, "high": 2, "count": 1},
-{"low": 2, "high": 3, "count": 2}]}"""
+        {"low": 1, "high": 2, "count": 1},
+        {"low": 2, "high": 3, "count": 2}]}"""
 
-    histogram = """{"count": 14, "buckets": [
-{"low": 1, "high": 2, "count": 1},
-{"low": 2, "high": 3, "count": 3},
-{"low": 3, "high": 4, "count": 10}]}"""
+    later_histogram = """{"count": 14, "buckets": [
+        {"low": 1, "high": 2, "count": 1},
+        {"low": 2, "high": 3, "count": 3},
+        {"low": 3, "high": 4, "count": 10}]}"""
 
     new_histogram = json.loads(
-        histogram_util.SubtractHistogram(histogram, baseline_histogram))
+        histogram_util.SubtractHistogram(later_histogram, baseline_histogram))
     new_buckets = dict()
     for b in new_histogram['buckets']:
       new_buckets[b['low']] = b['count']
diff --git a/tools/perf/metrics/io.py b/tools/perf/metrics/io.py
new file mode 100644
index 0000000..a52089d
--- /dev/null
+++ b/tools/perf/metrics/io.py
@@ -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.
+
+from metrics import Metric
+
+class IOMetric(Metric):
+  """IO-related metrics, obtained via telemetry.core.Browser."""
+
+  @classmethod
+  def CustomizeBrowserOptions(cls, options):
+    options.AppendExtraBrowserArg('--no-sandbox')
+
+  def Start(self, page, tab):
+    raise NotImplementedError()
+
+  def Stop(self, page, tab):
+    raise NotImplementedError()
+
+  def AddResults(self, tab, results):
+    # This metric currently only returns summary results, not per-page results.
+    raise NotImplementedError()
+
+  def AddSummaryResults(self, tab, results):
+    """Add summary results to the results object."""
+    io_stats = tab.browser.io_stats
+    if not io_stats['Browser']:
+      return
+
+    def AddSummariesForProcessType(process_type_io, process_type_trace):
+      """For a given process type, add all relevant summary results.
+
+      Args:
+        process_type_io: Type of process (eg Browser or Renderer).
+        process_type_trace: String to be added to the trace name in the results.
+      """
+      if 'ReadOperationCount' in io_stats[process_type_io]:
+        results.AddSummary('read_operations_' + process_type_trace, 'count',
+                           io_stats[process_type_io]
+                           ['ReadOperationCount'],
+                           data_type='unimportant')
+      if 'WriteOperationCount' in io_stats[process_type_io]:
+        results.AddSummary('write_operations_' + process_type_trace, 'count',
+                           io_stats[process_type_io]
+                           ['WriteOperationCount'],
+                           data_type='unimportant')
+      if 'ReadTransferCount' in io_stats[process_type_io]:
+        results.AddSummary('read_bytes_' + process_type_trace, 'kb',
+                           io_stats[process_type_io]
+                           ['ReadTransferCount'] / 1024,
+                           data_type='unimportant')
+      if 'WriteTransferCount' in io_stats[process_type_io]:
+        results.AddSummary('write_bytes_' + process_type_trace, 'kb',
+                           io_stats[process_type_io]
+                           ['WriteTransferCount'] / 1024,
+                           data_type='unimportant')
+
+    AddSummariesForProcessType('Browser', 'browser')
+    AddSummariesForProcessType('Renderer', 'renderer')
+    AddSummariesForProcessType('Gpu', 'gpu')
+
diff --git a/tools/perf/metrics/memory.py b/tools/perf/metrics/memory.py
index cbc0660..f6831a1 100644
--- a/tools/perf/metrics/memory.py
+++ b/tools/perf/metrics/memory.py
@@ -1,31 +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.
+
 import sys
 
+from metrics import histogram_util
 from metrics import Metric
 
+_HISTOGRAMS = [
+    {'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent',
+     'type': histogram_util.RENDERER_HISTOGRAM},
+    {'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb',
+     'type': histogram_util.RENDERER_HISTOGRAM},
+    {'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb',
+     'type': histogram_util.RENDERER_HISTOGRAM},
+    {'name': 'Memory.RendererUsed', 'units': 'kb',
+     'type': histogram_util.RENDERER_HISTOGRAM},
+    {'name': 'Memory.BrowserUsed', 'units': 'kb',
+     'type': histogram_util.BROWSER_HISTOGRAM}]
+
 class MemoryMetric(Metric):
-  """MemoryMetric gathers memory statistics from the browser object."""
+  """MemoryMetric gathers memory statistics from the browser object.
+
+  This includes both per-page histogram stats, most about javascript
+  memory usage, and overall memory stats from the system for the whole
+  test run."""
 
   def __init__(self, browser):
     super(MemoryMetric, self).__init__()
     self._browser = browser
-    self._memory_stats = None
-    self._start_commit_charge = None
-
-  def Start(self, page=None, tab=None):
-    """Record the initial value of 'SystemCommitCharge'."""
     self._start_commit_charge = self._browser.memory_stats['SystemCommitCharge']
+    self._memory_stats = None
+    self._histogram_start = dict()
+    self._histogram_delta = dict()
 
-  def Stop(self, page=None, tab=None):
-    """Fetch the browser memory stats."""
-    assert self._start_commit_charge, 'Must call Start() first'
-    self._memory_stats = self._browser.memory_stats
+  @classmethod
+  def CustomizeBrowserOptions(cls, options):
+    options.AppendExtraBrowserArg('--enable-stats-collection-bindings')
+    options.AppendExtraBrowserArg('--enable-memory-benchmarking')
+    # For a hard-coded set of Google pages (such as GMail), we produce custom
+    # memory histograms (V8.Something_gmail) instead of the generic histograms
+    # (V8.Something), if we detect that a renderer is only rendering this page
+    # and no other pages. For this test, we need to disable histogram
+    # customizing, so that we get the same generic histograms produced for all
+    # pages.
+    options.AppendExtraBrowserArg('--disable-histogram-customizer')
+
+    # Old commandline flags used for reference builds.
+    options.AppendExtraBrowserArg('--dom-automation')
+    options.AppendExtraBrowserArg('--reduce-security-for-dom-automation-tests')
+
+  def Start(self, page, tab):
+    """Start the per-page preparation for this metric.
+
+    Here, this consists of recording the start value of all the histograms.
+    """
+    for h in _HISTOGRAMS:
+      histogram_data = histogram_util.GetHistogramFromDomAutomation(
+          h['type'], h['name'], tab)
+      # Histogram data may not be available
+      if not histogram_data:
+        continue
+      self._histogram_start[h['name']] = histogram_data
+
+  def Stop(self, page, tab):
+    """Prepare the results for this page.
+
+    The results are the differences between the current histogram values
+    and the values when Start() was called.
+    """
+    assert self._histogram_start, 'Must call Start() first'
+    for h in _HISTOGRAMS:
+      # Histogram data may not be available
+      if h['name'] not in self._histogram_start:
+        continue
+      histogram_data = histogram_util.GetHistogramFromDomAutomation(
+          h['type'], h['name'], tab)
+      self._histogram_delta[h['name']] = histogram_util.SubtractHistogram(
+          histogram_data, self._histogram_start[h['name']])
 
   def AddResults(self, tab, results):
-    """Add summary results to the results object."""
-    assert self._memory_stats, 'Must call Stop() first'
+    """Add results for this page to the results object."""
+    assert self._histogram_delta, 'Must call Stop() first'
+    for h in _HISTOGRAMS:
+      # Histogram data may not be available
+      if h['name'] not in self._histogram_start:
+        continue
+      results.Add(h['name'], h['units'], self._histogram_delta[h['name']],
+                  data_type='unimportant-histogram')
+
+  def AddSummaryResults(self, results):
+    """Add summary (overall) results to the results object."""
+    self._memory_stats = self._browser.memory_stats
     if not self._memory_stats['Browser']:
       return
 
diff --git a/tools/perf/metrics/smoothness.py b/tools/perf/metrics/smoothness.py
index c4ec7bc..aeee61e 100644
--- a/tools/perf/metrics/smoothness.py
+++ b/tools/perf/metrics/smoothness.py
@@ -14,6 +14,10 @@
       js = f.read()
       tab.ExecuteJavaScript(js)
 
+  @classmethod
+  def CustomizeBrowserOptions(cls, options):
+    options.AppendExtraBrowserArg('--enable-gpu-benchmarking')
+
   def Start(self):
     self._tab.ExecuteJavaScript(
         'window.__renderingStats = new __RenderingStats();'
diff --git a/tools/perf/metrics/speedindex.js b/tools/perf/metrics/speedindex.js
new file mode 100644
index 0000000..b58b704
--- /dev/null
+++ b/tools/perf/metrics/speedindex.js
@@ -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.
+
+'use strict';
+
+/**
+ * @fileoverview This file provides a JavaScript helper function that
+ * determines when the last resource was received.
+ */
+(function() {
+
+  // Set the Resource Timing interface functions that will be used below
+  // to use whatever version is available currently regardless of vendor
+  // prefix.
+  window.performance.clearResourceTimings =
+      (window.performance.clearResourceTimings     ||
+       window.performance.mozClearResourceTimings  ||
+       window.performance.msClearResourceTimings   ||
+       window.performance.oClearResourceTimings    ||
+       window.performance.webkitClearResourceTimings);
+
+  window.performance.getEntriesByType =
+      (window.performance.getEntriesByType     ||
+       window.performance.mozGetEntriesByType  ||
+       window.performance.msGetEntriesByType   ||
+       window.performance.oGetEntriesByType    ||
+       window.performance.webkitGetEntriesByType);
+
+  // This variable will available to the function below and it will be
+  // persistent across different function calls. It stores the last
+  // entry in the list of PerformanceResourceTiming objects returned by
+  // window.performance.getEntriesByType('resource').
+  //
+  // The reason for doing it this way is because the buffer for
+  // PerformanceResourceTiming objects has a limit, and once it's full,
+  // new entries are not added. We're only interested in the last entry,
+  // so we can clear new entries when they're added.
+  var lastEntry = null;
+
+  /**
+   * This method uses the Resource Timing interface, which is described at
+   * http://www.w3.org/TR/resource-timing/. It provides information about
+   * timings for resources such as images and script files, and it includes
+   * resources requested via XMLHttpRequest.
+   *
+   *
+   * @return {number} The time since either the load event, or the last
+   *   the last resource was received after the load event. If the load
+   *   event hasn't yet happened, return 0.
+   */
+  window.timeSinceLastResponseAfterLoadMs = function() {
+    if (window.document.readyState !== 'complete') {
+      return 0;
+    }
+
+    var resourceTimings = window.performance.getEntriesByType('resource');
+    if (resourceTimings.length > 0) {
+      lastEntry = resourceTimings.pop();
+      window.performance.clearResourceTimings();
+    }
+
+    // The times for performance.now() and in the PerformanceResourceTiming
+    // objects are all in milliseconds since performance.timing.navigationStart,
+    // so we must also get load time in the same terms.
+    var timing = window.performance.timing;
+    var loadTime = timing.loadEventEnd - timing.navigationStart;
+    if (loadTime > lastEntry.responseEnd) {
+      return window.performance.now() - loadTime;
+    }
+    return window.performance.now() - lastEntry.responseEnd;
+  }
+
+})();
diff --git a/tools/perf/metrics/speedindex.py b/tools/perf/metrics/speedindex.py
new file mode 100644
index 0000000..8995114
--- /dev/null
+++ b/tools/perf/metrics/speedindex.py
@@ -0,0 +1,225 @@
+# Copyright 2013 The Chromium 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 os
+
+from metrics import Metric
+
+class SpeedIndexMetric(Metric):
+  """The speed index metric is one way of measuring page load speed.
+
+  It is meant to approximate user perception of page load speed --
+  it's based on the amount of time that it takes to paint to the visual
+  portion of the screen -- it includes paint events done after the load
+  event, and it doesn't include time loading things off-screen
+
+  This speed index metric is based on the one in WebPagetest:
+  http://goo.gl/e7AH5l
+  """
+  def __init__(self):
+    super(SpeedIndexMetric, self).__init__()
+    self._script_is_loaded = False
+    self._is_finished = False
+    with open(os.path.join(os.path.dirname(__file__), 'speedindex.js')) as f:
+      self._js = f.read()
+
+  def Start(self, _, tab):
+    """Start recording events.
+
+    This method should be called in the WillNavigateToPage method of
+    a PageMeasurement, so that all the events can be captured. If it's called
+    in DidNavigateToPage, that will be too late.
+    """
+    tab.StartTimelineRecording()
+
+  def Stop(self, _, tab):
+    """Stop timeline recording."""
+    assert self.IsFinished(tab)
+    tab.StopTimelineRecording()
+
+  def AddResults(self, tab, results):
+    """Calculate the speed index and add it to the results."""
+    events = tab.timeline_model.GetAllEvents()
+    assert len(events) > 0
+    results.Add('speed_index', 'ms', _SpeedIndex(events))
+
+  def IsFinished(self, tab):
+    """Decide whether the timeline recording should be stopped.
+
+    When the timeline recording is stopped determines which paint events
+    are used in the speed index metric calculation. In general, the recording
+    should continue if there has just been some data received, because
+    this suggests that painting may continue.
+
+    A page may repeatedly request resources in an infinite loop; a timeout
+    should be placed in any measurement that uses this metric, e.g.:
+      def IsDone():
+        return self._speedindex.IsFinished(tab)
+      util.WaitFor(IsDone, 60)
+
+    Returns:
+      True if 2 seconds have passed since last resource received, false
+      otherwise.
+    """
+    if self._is_finished:
+      return True
+
+    # The script that provides the function window.timeSinceLastResponseMs()
+    # needs to be loaded for this function, but it must be loaded AFTER
+    # the Start method is called, because if the Start method is called in
+    # the PageMeasurement's WillNavigateToPage function, then it will
+    # not be available here. The script should only be loaded once, so that
+    # variables in the script don't get reset.
+    if not self._script_is_loaded:
+      tab.ExecuteJavaScript(self._js)
+      self._script_is_loaded = True
+
+    time_since_last_response_ms = tab.EvaluateJavaScript(
+        "window.timeSinceLastResponseAfterLoadMs()")
+    self._is_finished = time_since_last_response_ms > 2000
+    return self._is_finished
+
+
+def _SpeedIndex(events):
+  """Calculate the speed index of a page load from a list of events.
+
+  Args:
+    events: A flat list of telemetry.core.timeline.slice.Slice objects
+      as returned by telemetry.core.timeline.model.GetAllEvents().
+
+  Returns:
+    A single integer which represents the total time in milliseconds
+    that the page was "visually incomplete". If the page were 100% incomplete
+    (i.e. nothing painted) for 1000 ms, then the score would be 1000; if it
+    were empty for 100 ms, then 90% complete (10% incomplete) for 900 ms, then
+    the score would be 100 + 0.1*900 = 190.
+  """
+  paint_events = _GetPaintEvents(events)
+  time_area_pairs = _GetTimeAreaPairs(paint_events)
+  time_completeness_pairs = _GetTimeCompletenessPairs(time_area_pairs)
+  speed_index = 0
+  prev_time = _StartTime(events)
+  completeness = 0.0
+  for this_time, this_completeness in time_completeness_pairs:
+    # Add the value for the time interval up to this event
+    time_interval = this_time - prev_time
+    speed_index += time_interval * (1 - completeness)
+
+    # Update variables for next iteration
+    completeness = this_completeness
+    prev_time = this_time
+  return speed_index
+
+
+def _GetPaintEvents(timeline_events):
+  """Get the paint events in the time range relevant to the speed index."""
+  start = _StartTime(timeline_events)
+  return [event for event in timeline_events
+          if event.name == 'Paint' and event.start >= start]
+
+
+def _StartTime(timeline_events):
+  """Get the time of the earliest Paint event that should be considered.
+
+  Before there are any ResourceReceiveResponse or Layout events,
+  there may be Paint events. These paint events probably should be ignored,
+  because they probably aren't actual elements of the page being displayed.
+
+  Returns:
+    If there's a ResourceReceiveResponse event then a Layout event, return the
+    start time of the Layout event. Otherwise, return the time of the start
+    of the first event.
+  """
+  has_received_response = False
+  assert len(timeline_events) > 0
+  for event in timeline_events:
+    if event.name == "ResourceReceiveResponse":
+      has_received_response = True
+    elif has_received_response and event.name == "Layout":
+      return event.start
+  return timeline_events[0].start
+
+
+def _GetTimeAreaPairs(paint_events):
+  """Make a list of pairs associating event time and adjusted area value.
+
+  The area value of a paint event is determined by how many paint events paint
+  the same rectangle, and whether it is painting full window.
+
+  Args:
+    paint_events: A list of Paint events
+
+  Returns:
+    A list of pairs of the time of each paint event (in milliseconds) and the
+    adjusted area that the paint event is worth.
+  """
+  def _RectangleArea(rectangle):
+    return rectangle[3] * rectangle[4]
+  grouped = _GroupEventByRectangle(paint_events)
+  fullscreen_area = max([_RectangleArea(rect) for rect in grouped.keys()])
+  event_area_pairs = []
+  for rectangle in grouped:
+    area = _RectangleArea(rectangle)
+    # Paint events that are considered "full-screen" paint events
+    # are discounted because they're often just painting a white background.
+    # They are not completely disregarded though, because if we're painting
+    # a colored background, it should be counted.
+    if _RectangleArea(rectangle) == fullscreen_area:
+      area /= 2
+    area_per_event = area / len(grouped[rectangle])
+    for event in grouped[rectangle]:
+      end_time = event.end
+      event_area_pairs.append((end_time, area_per_event))
+  return event_area_pairs
+
+
+def _GroupEventByRectangle(paint_events):
+  """Group all paint events according to the rectangle that they update."""
+  result = collections.defaultdict(list)
+  for event in paint_events:
+    assert event.name == 'Paint'
+    result[_GetRectangle(event)].append(event)
+  return result
+
+
+def _GetRectangle(paint_event):
+  """Get the specific rectangle on the screen for a paint event.
+
+  Each paint event belongs to a frame (as in html <frame> or <iframe>).
+  This, together with location and dimensions, comprises a rectangle.
+  """
+  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 _GetBox(quad):
+  """Convert the "clip" data in a paint event to coordinates and dimensions.
+
+  In the timeline data from devtools, paint rectangle dimensions are
+  represented x-y coordinates of four corners, clockwise from the top-left.
+  See: function WebInspector.TimelinePresentationModel.quadFromRectData
+  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)
+
+
+def _GetTimeCompletenessPairs(time_area_pairs):
+  """Make a list associating time with the % completeness at that time.
+
+  The list returned will also be ordered by time.
+  """
+  total_area = float(sum([area for (_, area) in time_area_pairs]))
+  time_completeness_pairs = []
+  completeness = 0
+  for event_time, area in sorted(time_area_pairs):
+    completeness_impact = float(area) / total_area
+    completeness += completeness_impact
+    time_completeness_pairs.append((event_time, completeness))
+  return time_completeness_pairs
+
diff --git a/tools/perf/metrics/speedindex_unittest.py b/tools/perf/metrics/speedindex_unittest.py
new file mode 100644
index 0000000..f306f61
--- /dev/null
+++ b/tools/perf/metrics/speedindex_unittest.py
@@ -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.
+
+import unittest
+
+from telemetry.core.timeline import model
+from metrics import speedindex
+
+# pylint: disable=W0212
+# (Disabled because these tests test private methods in speed_index_metric)
+
+_RAW_EVENTS =  [
+  { "type": "Paint",
+    "startTime": 100,
+    "endTime": 110,
+    "frameId": "1.1",
+    "data": {"clip": [0, 0, 1000, 0, 1000, 500, 0, 500]},
+    "children": [],
+  },
+  { "type": "ResourceReceiveResponse",
+    "startTime": 120,
+    "endTime": 130,
+    "frameId": "1.1",
+    "data": {},
+    "children": [],
+  },
+  { "type": "Layout",
+    "startTime": 140,
+    "endTime": 150,
+    "frameId": "1.1",
+    "data": {},
+    "children": [],
+  },
+  { "type": "Paint",
+    "startTime": 300,
+    "endTime": 400,
+    "frameId": "1.1",
+    "data": {"clip": [375, 300, 380, 300, 380, 400, 375, 400]},
+    "children": [],
+  },
+  { "type": "Paint",
+    "startTime": 400,
+    "endTime": 500,
+    "frameId": "1.1",
+    "data": {"clip": [0, 0, 500, 0, 500, 100, 0, 100]},
+    "children": [],
+  }
+]
+
+_RAW_EVENTS_SAME_RECTANGLE =  [
+  { "type": "Paint",
+    "startTime": 0,
+    "endTime": 100,
+    "frameId": "1.1",
+    "data": {"clip": [0, 0, 500, 0, 500, 100, 0, 100]},
+    "children": [],
+  },
+  { "type": "Paint",
+    "startTime": 400,
+    "endTime": 500,
+    "frameId": "1.1",
+    "data": {"clip": [ 0, 0, 500, 0, 500, 100, 0, 100]},
+    "children": [],
+  }
+]
+
+_EVENTS = model.TimelineModel(event_data=_RAW_EVENTS,
+    shift_world_to_zero=False).GetAllEvents()
+
+_EVENTS_ONLY_PAINT = [e for e in _EVENTS if e.name == 'Paint']
+
+_EVENTS_SAME_RECTANGLE = model.TimelineModel(
+  event_data=_RAW_EVENTS_SAME_RECTANGLE,
+  shift_world_to_zero=False).GetAllEvents()
+
+
+class _StartTimeTest(unittest.TestCase):
+  def testWithAllEvents(self):
+    start_time = speedindex._StartTime(_EVENTS)
+    self.assertEquals(140, start_time)
+
+  def testWithNoLayoutEvents(self):
+    start_time = speedindex._StartTime(_EVENTS_SAME_RECTANGLE)
+    self.assertEquals(0, start_time)
+
+
+class _GetRectangleTest(unittest.TestCase):
+  def testGetRectangleBig(self):
+    rectangle = speedindex._GetRectangle(_EVENTS[0])
+    self.assertEquals(("1.1", 0, 0, 1000, 500), rectangle)
+
+  def testGetRectangleSmall(self):
+    rectangle = speedindex._GetRectangle(_EVENTS[3])
+    self.assertEquals(("1.1", 375, 300, 5, 100), rectangle)
+
+
+class _GroupEventByRectangleTest(unittest.TestCase):
+  def testNotGrouped(self):
+    grouped = speedindex._GroupEventByRectangle(_EVENTS_ONLY_PAINT)
+    self.assertEquals(3, len(grouped.keys()))
+    self.assertEquals(1, len(grouped.values()[0]))
+
+  def testGrouped(self):
+    grouped = speedindex._GroupEventByRectangle(_EVENTS_SAME_RECTANGLE)
+    self.assertEquals(1, len(grouped.keys()))
+    self.assertEquals(2, len(grouped.values()[0]))
+
+
+class _GetTimeAreaPairsTest(unittest.TestCase):
+  def testAdjusted(self):
+    time_area_pairs = (speedindex._GetTimeAreaPairs(_EVENTS_ONLY_PAINT))
+    total_area = sum([area for _, area in time_area_pairs])
+    expected_total_area = (1000*500/2) + (5*100) + (500*100)
+    self.assertEquals(expected_total_area, total_area)
+
+  def testAdjustedWithSameRectangle(self):
+    time_area_pairs = (speedindex._GetTimeAreaPairs(_EVENTS_SAME_RECTANGLE))
+    total_area = sum([area for _, area in time_area_pairs])
+    expected_total_area = (500*100/2)
+    self.assertEquals(expected_total_area, total_area)
+
+
+class _GetTimeCompletenessPairsTest(unittest.TestCase):
+  def setUp(self):
+    time_area_pairs = (speedindex._GetTimeAreaPairs(_EVENTS_ONLY_PAINT))
+    self.time_completeness_pairs = (speedindex.
+                                    _GetTimeCompletenessPairs(time_area_pairs))
+
+  def testEndsWithOne(self):
+    self.assertEquals(1.0, self.time_completeness_pairs[-1][1])
+
+  def testMonotonicallyIncreasing(self):
+    prev_completeness = 0
+    for _, completeness in self.time_completeness_pairs:
+      self.assertTrue(prev_completeness <= completeness)
+      prev_completeness = completeness
+
+
+class _SpeedIndexTest(unittest.TestCase):
+  def testOne(self):
+    area1, area2 = 5 * 100, 500 * 100 / 2
+    total_area = float(area1 + area2)
+    completeness1 = area1 / total_area
+    interval1 = 1.0 * (400 - 140)  # before first paint event
+    interval2 = (1.0 - completeness1) * (500 - 400)
+    expected = interval1 + interval2
+    self.assertEquals(expected, speedindex._SpeedIndex(_EVENTS))
+
+  def testTwo(self):
+    interval1 = 1.0 * (100 - 0)  # before first paint event
+    interval2 = 0.5 * (500 - 100)  # between paint event 1 and 2
+    expected = interval1 + interval2
+    self.assertEquals(expected, speedindex._SpeedIndex(_EVENTS_SAME_RECTANGLE))
+
+
+if __name__ == "__main__":
+  unittest.main()
+
diff --git a/tools/perf/metrics/timeline.py b/tools/perf/metrics/timeline.py
index 37bc3e6..6462646 100644
--- a/tools/perf/metrics/timeline.py
+++ b/tools/perf/metrics/timeline.py
@@ -3,17 +3,20 @@
 # found in the LICENSE file.
 import collections
 
+from metrics import Metric
+
 TRACING_MODE = 'tracing-mode'
 TIMELINE_MODE = 'timeline-mode'
 
-class TimelineMetrics(object):
+class TimelineMetric(Metric):
   def __init__(self, mode):
     assert mode in (TRACING_MODE, TIMELINE_MODE)
+    super(TimelineMetric, self).__init__()
     self._mode = mode
     self._model = None
     self._thread_for_tab = None
 
-  def Start(self, tab):
+  def Start(self, page, tab):
     self._model = None
     self._thread_for_tab = None
 
@@ -25,7 +28,7 @@
       assert self._mode == TIMELINE_MODE
       tab.StartTimelineRecording()
 
-  def Stop(self, tab):
+  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
@@ -49,7 +52,7 @@
       self._model = tab.timeline_model
       self._thread_for_tab = self._model.GetAllThreads()[0]
 
-  def AddResults(self, results):
+  def AddResults(self, tab, results):
     assert self._model
 
     events = self._thread_for_tab.all_slices
@@ -58,10 +61,11 @@
     for e in events:
       events_by_name[e.name].append(e)
 
-    for key, group in events_by_name.items():
-      times = [e.self_time for e in group]
+    for event_name, event_group in events_by_name.iteritems():
+      times = [event.self_time for event in event_group]
       total = sum(times)
       biggest_jank = max(times)
-      results.Add(key, 'ms', total)
-      results.Add(key + '_max', 'ms', biggest_jank)
-      results.Add(key + '_avg', 'ms', total / len(times))
+      results.Add(event_name, 'ms', total)
+      results.Add(event_name + '_max', 'ms', biggest_jank)
+      results.Add(event_name + '_avg', 'ms', total / len(times))
+
diff --git a/tools/perf/page_sets/blank_page.json b/tools/perf/page_sets/blank_page.json
index ebd896c..79bb01d 100644
--- a/tools/perf/page_sets/blank_page.json
+++ b/tools/perf/page_sets/blank_page.json
@@ -1,6 +1,6 @@
 {
   "description": "A single blank page.",
   "pages": [
-    { "url": "file:///blank_page.html" }
+    { "url": "file:///blank_page/blank_page.html" }
   ]
 }
diff --git a/tools/perf/page_sets/blank_page.html b/tools/perf/page_sets/blank_page/blank_page.html
similarity index 100%
rename from tools/perf/page_sets/blank_page.html
rename to tools/perf/page_sets/blank_page/blank_page.html
diff --git a/tools/perf/page_sets/calendar_forward_backward.json b/tools/perf/page_sets/calendar_forward_backward.json
new file mode 100644
index 0000000..7e5257f
--- /dev/null
+++ b/tools/perf/page_sets/calendar_forward_backward.json
@@ -0,0 +1,66 @@
+{
+  "description": "Chrome Endure test for Google Calendar.",
+  "archive_data_file": "../data/calendar_forward_backward.json",
+  "credentials_path": "../data/credentials.json",
+  "user_agent_type": "desktop",
+  "pages": [
+    {
+      "url": "https://www.google.com/calendar/",
+      "why": "Click forward(4x) and backwards(4x) repeatedly",
+      "credentials": "google",
+      "wait_for_element_with_selector": "div[class~=\"navForward\"]",
+      "post_navigate_javascript_to_execute": "(function() { var elem = document.createElement('meta');elem.name='viewport';elem.content='initial-scale=1';document.body.appendChild(elem); })();",
+      "wait_seconds": 2,
+      "endure": [
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navForward\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navForward\"]"
+        },
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navForward\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navForward\"]"
+        },
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navForward\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navForward\"]"
+        },
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navForward\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navBack\"]"
+        },
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navBack\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navBack\"]"
+        },
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navBack\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navBack\"]"
+        },
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navBack\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navBack\"]"
+        },
+        {
+          "action": "click_element",
+          "selector": "div[class~=\"navBack\"]",
+          "wait_seconds": 2,
+          "wait_for_element_with_selector": "div[class~=\"navForward\"]"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tools/perf/page_sets/tough_video_cases.json b/tools/perf/page_sets/tough_video_cases.json
index 5f4f593..969a767 100644
--- a/tools/perf/page_sets/tough_video_cases.json
+++ b/tools/perf/page_sets/tough_video_cases.json
@@ -24,10 +24,6 @@
       "media_metrics": {"action": "play_audio"}
     },
     {
-      "url": "file:///tough_video_cases/video.html?src=crowd1080.mp4&id=video_1&type=video",
-      "media_metrics": {"action": "play_video"}
-    },
-    {
       "url": "file:///tough_video_cases/video.html?src=crowd1080.ogv&id=video_1&type=video",
       "media_metrics": {"action": "play_video"}
     },
@@ -36,10 +32,6 @@
       "media_metrics": {"action": "play_video"}
     },
     {
-      "url": "file:///tough_video_cases/video.html?src=crowd2160.mp4&id=video_1&type=video",
-      "media_metrics": {"action": "play_video"}
-    },
-    {
       "url": "file:///tough_video_cases/video.html?src=crowd2160.ogv&id=video_1&type=video",
       "media_metrics": {"action": "play_video"}
     },
@@ -48,10 +40,6 @@
       "media_metrics": {"action": "play_video"}
     },
     {
-      "url": "file:///tough_video_cases/video.html?src=tulip2.mp3&id=audio_1&type=audio",
-      "media_metrics": {"action": "play_audio"}
-    },
-    {
       "url": "file:///tough_video_cases/video.html?src=tulip2.ogg&id=audio_1&type=audio",
       "media_metrics": {"action": "play_audio"}
     },
@@ -60,10 +48,6 @@
       "media_metrics": {"action": "play_audio"}
     },
     {
-      "url": "file:///tough_video_cases/video.html?src=tulip2.mp4&id=video_1&type=video",
-      "media_metrics": {"action": "play_video"}
-    },
-    {
       "url": "file:///tough_video_cases/video.html?src=tulip2.ogv&id=video_1&type=video",
       "media_metrics": {"action": "play_video"}
     },
diff --git a/tools/perf/perf_tools/__init__.py b/tools/perf/perf_tools/__init__.py
index 3e13108..72020f9 100644
--- a/tools/perf/perf_tools/__init__.py
+++ b/tools/perf/perf_tools/__init__.py
@@ -1,7 +1,9 @@
 # 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 library for Chrome GPU test code."""
+
 import os
 import sys
 
@@ -18,13 +20,15 @@
       pyc_path = os.path.join(dirname, filename)
       py_path = os.path.join(dirname, root + '.py')
       if not os.path.exists(py_path):
+        print >> sys.stderr, 'Removing stale .pyc file:', pyc_path
         os.remove(pyc_path)
 
-    if not os.listdir(dirname):
+    if os.path.isdir(dirname) and not os.listdir(dirname):
+      print >> sys.stderr, 'Removing empty directory:', dirname
       os.removedirs(dirname)
 
 
-def Init():
+def _Init():
   telemetry_path = os.path.join(os.path.dirname(__file__),
                                 os.pardir, os.pardir, 'telemetry')
   absolute_telemetry_path = os.path.abspath(telemetry_path)
@@ -36,4 +40,4 @@
 
 
 _RemoveAllStalePycFiles()
-Init()
+_Init()
diff --git a/tools/perf/run_tests b/tools/perf/run_tests
index 36eefbb..24370d7 100755
--- a/tools/perf/run_tests
+++ b/tools/perf/run_tests
@@ -19,13 +19,13 @@
   top_level_dir = os.path.abspath(os.path.dirname(__file__))
   runner = gtest_testrunner.GTestTestRunner(print_result_after_run=False)
 
-  start_dir = 'measurements'
+  start_dir = os.path.join(top_level_dir, 'measurements')
   ret = run_tests.Main(sys.argv[1:], start_dir, top_level_dir, runner)
 
-  start_dir = 'perf_tools'
+  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 = 'metrics'
+  start_dir = os.path.join(top_level_dir, 'metrics')
   ret += run_tests.Main(sys.argv[1:], start_dir, top_level_dir, runner)
 
   if runner.result:
diff --git a/tools/perf_expectations/perf_expectations.json b/tools/perf_expectations/perf_expectations.json
index e510bc6..4f2e4b0 100644
--- a/tools/perf_expectations/perf_expectations.json
+++ b/tools/perf_expectations/perf_expectations.json
@@ -2,7 +2,6 @@
  "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": 216959, "revb": 216961, "type": "absolute", "better": "lower", "improve": 33, "regress": 33, "tolerance": 0, "sha1": "ebd8c26b"},
  "linux-release-64/sizes/chrome-text/text": {"reva": 203454, "revb": 203474, "type": "absolute", "better": "lower", "improve": 94012670, "regress": 103908994, "sha1": "a8dc15a3"},
- "linux-release-64/sizes/chrome.pak/chrome.pak": {"reva": 214295, "revb": 214296, "type": "absolute", "better": "lower", "improve": 4578193, "regress": 5060109, "sha1": "0785f1c1"},
  "linux-release-64/sizes/chrome/chrome": {"reva": 203454, "revb": 203474, "type": "absolute", "better": "lower", "improve": 128793270, "regress": 142351155, "sha1": "193926f5"},
  "linux-release-64/sizes/nacl_helper-bss/bss": {"reva": 193069, "revb": 193093, "type": "absolute", "better": "lower", "improve": 200024, "regress": 221080, "sha1": "5dfae63b"},
  "linux-release-64/sizes/nacl_helper-data/data": {"reva": 195191, "revb": 203172, "type": "absolute", "better": "lower", "improve": 22942, "regress": 26878, "sha1": "6d52a881"},
@@ -368,7 +367,6 @@
  "linux-release/sizes/chrome-si/initializers": {"reva": 216959, "revb": 216961, "type": "absolute", "better": "lower", "improve": 34, "regress": 34, "tolerance": 0, "sha1": "69a4e038"},
  "linux-release/sizes/chrome-text/text": {"reva": 203454, "revb": 203474, "type": "absolute", "better": "lower", "improve": 79833368, "regress": 88237335, "sha1": "e1b38def"},
  "linux-release/sizes/chrome-textrel/textrel": {"reva": 135570, "revb": 135664, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "sha1": "832078e7"},
- "linux-release/sizes/chrome.pak/chrome.pak": {"reva": 214295, "revb": 214296, "type": "absolute", "better": "lower", "improve": 4578193, "regress": 5060109, "sha1": "a95a611b"},
  "linux-release/sizes/chrome/chrome": {"reva": 203454, "revb": 203474, "type": "absolute", "better": "lower", "improve": 108516653, "regress": 119939890, "sha1": "a6649863"},
  "linux-release/sizes/libffmpegsumo.so-textrel/textrel": {"reva": 200467, "revb": 203456, "type": "absolute", "better": "lower", "improve": 1075, "regress": 1189, "sha1": "a10d4ea4"},
  "linux-release/sizes/nacl_helper-bss/bss": {"reva": 193069, "revb": 193093, "type": "absolute", "better": "lower", "improve": 100506, "regress": 111086, "sha1": "805988e3"},
@@ -737,7 +735,7 @@
  "win-release/media_tests_av_perf/ttp/Wifi_dartmoor2.ogg": {"reva": 17420, "revb": 174996, "type": "absolute", "better": "lower", "improve": 12396.55, "regress": 14062.125, "sha1": "9ca7f6b1"},
  "win-release/media_tests_av_perf/ttp/Wifi_dartmoor2.wav": {"reva": 17420, "revb": 174996, "type": "absolute", "better": "lower", "improve": 6859.95, "regress": 24904.425, "sha1": "0e5625a5"},
  "win-release/media_tests_av_perf/ttp/Wifi_roller.webm": {"reva": 175328, "revb": 176157, "type": "absolute", "better": "lower", "improve": 906.775, "regress": 1184.925, "sha1": "d49e638f"},
- "xp-release/sizes/chrome.dll/chrome.dll": {"reva": 203454, "revb": 203508, "type": "absolute", "better": "lower", "improve": 55459814, "regress": 61312205, "sha1": "b01d47d9"},
+ "xp-release/sizes/chrome.dll/chrome.dll": {"reva": 218681, "revb": 218708, "type": "absolute", "better": "lower", "improve": 37718374, "regress": 41694106, "sha1": "9f89d61e"},
  "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": 212973, "revb": 213132, "type": "absolute", "better": "lower", "improve": 28051174, "regress": 31094247, "sha1": "303dac45"},
  "xp-release/sizes/npchrome_frame.dll/npchrome_frame.dll": {"reva": 213618, "revb": 213647, "type": "absolute", "better": "lower", "improve": 2320128, "regress": 2567040, "sha1": "a9618db1"},
diff --git a/tools/prepare-bisect-perf-regression.py b/tools/prepare-bisect-perf-regression.py
index 88c62f3..efcafc2 100755
--- a/tools/prepare-bisect-perf-regression.py
+++ b/tools/prepare-bisect-perf-regression.py
@@ -57,7 +57,9 @@
     parser.print_help()
     return 1
 
-  return bisect_utils.CreateBisectDirectoryAndSetupDepot(opts)
+  return bisect_utils.CreateBisectDirectoryAndSetupDepot(
+             opts,
+             bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS)
 
 
 if __name__ == '__main__':
diff --git a/tools/run-bisect-manual-test.py b/tools/run-bisect-manual-test.py
index 7b038db..3b69358 100755
--- a/tools/run-bisect-manual-test.py
+++ b/tools/run-bisect-manual-test.py
@@ -3,7 +3,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Run Manual Test Bisect Tool"""
+"""Run Manual Test Bisect Tool
+
+An example usage:
+tools/run-bisect-manual-test.py -g 201281 -b 201290
+
+"""
 
 import os
 import subprocess
@@ -27,7 +32,7 @@
   Returns:
     0 on success, otherwise 1.
   """
-  test_command = 'python %s --browser=%s' %\
+  test_command = 'python %s --browser=%s --chrome-root=.' %\
       (os.path.join(_DIR_TOOLS_ROOT, 'bisect-manual-test.py'),
        options.browser_type)
 
@@ -39,7 +44,8 @@
          '-r', '1',
          '--working_directory', options.working_directory,
          '--build_preference', 'ninja',
-         '--use_goma']
+         '--use_goma',
+         '--no_custom_deps']
 
   if 'cros' in options.browser_type:
     cmd.extend(['--target_platform', 'cros'])
@@ -71,7 +77,7 @@
   usage = ('%prog [options]\n'
            'Used to run the bisection script with a manual test.')
 
-  options = browser_options.BrowserOptions()
+  options = browser_options.BrowserOptions('release')
   parser = options.CreateParser(usage)
 
   parser.add_option('-b', '--bad_revision',
@@ -86,16 +92,13 @@
                     'bad revision. May be either a git or svn revision.')
   parser.add_option('-w', '--working_directory',
                     type='str',
+                    default='..',
                     help='A working directory to supply to the bisection '
                     'script, which will use it as the location to checkout '
                     'a copy of the chromium depot.')
-  options, args = parser.parse_args()
 
+  options, args = parser.parse_args()
   error_msg = ''
-  if not options.browser_type:
-    error_msg += 'Error: missing required parameter: --browser\n'
-  if not options.working_directory:
-    error_msg += 'Error: missing required parameter: --working_directory\n'
   if not options.good_revision:
     error_msg += 'Error: missing required parameter: --good_revision\n'
   if not options.bad_revision:
diff --git a/tools/telemetry/build/update_docs.py b/tools/telemetry/build/update_docs.py
index 8c42b30..2b11da5 100644
--- a/tools/telemetry/build/update_docs.py
+++ b/tools/telemetry/build/update_docs.py
@@ -125,15 +125,15 @@
 def Main(args):
   parser = optparse.OptionParser()
   parser.add_option(
-      '-v', '--verbose', action='count', default=0,
+      '-v', '--verbose', action='count', dest='verbosity',
       help='Increase verbosity level (repeat as needed)')
   options, args = parser.parse_args(args)
-  if options.verbose >= 2:
-    logging.basicConfig(level=logging.DEBUG)
-  elif options.verbose:
-    logging.basicConfig(level=logging.INFO)
+  if options.verbosity >= 2:
+    logging.getLogger().setLevel(logging.DEBUG)
+  elif options.verbosity:
+    logging.getLogger().setLevel(logging.INFO)
   else:
-    logging.basicConfig(level=logging.WARNING)
+    logging.getLogger().setLevel(logging.WARNING)
 
   assert os.path.isdir(docs_dir)
 
diff --git a/tools/telemetry/run_tests b/tools/telemetry/run_tests
index 6b4bd53..d02a0a7 100755
--- a/tools/telemetry/run_tests
+++ b/tools/telemetry/run_tests
@@ -11,7 +11,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 = 'telemetry'
+  start_dir = os.path.join(top_level_dir, 'telemetry')
   ret = run_tests.Main(sys.argv[1:], start_dir, top_level_dir, runner)
 
   if runner.result:
diff --git a/tools/telemetry/support/html_output/results-template.html b/tools/telemetry/support/html_output/results-template.html
index 898d057..63619c4 100644
--- a/tools/telemetry/support/html_output/results-template.html
+++ b/tools/telemetry/support/html_output/results-template.html
@@ -10,6 +10,14 @@
     position: relative;
 }
 
+.collapsed:before {
+    content: '\25B8\00A0';
+}
+
+.expanded:before {
+    content: '\25BE\00A0';
+}
+
 .time-plots {
     padding-left: 25px;
 }
@@ -21,6 +29,29 @@
     margin-right: 10px;
 }
 
+.closeButton {
+    background: #fff;
+    border: 1px solid black;
+    border-radius: 2px;
+    display: inline-block;
+    float: right;
+    line-height: 11px;
+    margin-top: 3px;
+    width: 11px;
+}
+
+.closeButton:hover {
+    background: #F09C9C;
+}
+
+.label {
+    cursor: text;
+}
+
+.label:hover {
+    background: #ffcc66;
+}
+
 section h1 {
     text-align: center;
     font-size: 1em;
@@ -96,6 +127,7 @@
 }
 
 td.missing {
+    color: #aaa;
     text-align: center;
 }
 
@@ -133,7 +165,7 @@
 <div style="padding: 0 10px; white-space: nowrap;">
 Result <span id="time-memory" class="checkbox"><span class="checked">Time</span><span>Memory</span></span>
 Reference <span id="reference" class="checkbox"></span>
-Run Telemetry with --reset-html-results to clear all runs
+<span class="checkbox"><span class="checked" id="undelete">Undelete</span></span>
 </div>
 <table id="container"></table>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
@@ -169,14 +201,21 @@
 }
 
 function TestRun(entry) {
-    this.description = function () { return entry['description']; }
+    this.id = function() { return entry['buildTime']; }
     this.revision = function () { return entry['revision']; }
     this.label = function () {
-        var label = 'r' + this.revision();
-        if (this.description())
-            label += ' &dash; ' + this.description();
-        return label;
+        if (labelKey in localStorage)
+            return localStorage[labelKey];
+        return 'r' + this.revision();
     }
+    this.setLabel = function(label) { localStorage[labelKey] = label; }
+    this.isHidden = function() { return localStorage[hiddenKey]; }
+    this.hide = function() { localStorage[hiddenKey] = true; }
+    this.show = function() { localStorage.removeItem(hiddenKey); }
+    this.description = function() { return new Date(entry['buildTime']).toLocaleString() + '\n' + entry['platform'] + ' r' + entry['revision']; }
+
+    var labelKey = 'telemetry_label_' + this.id();
+    var hiddenKey = 'telemetry_hide_' + this.id();
 }
 
 function PerfTestMetric(name, metric, unit, isImportant) {
@@ -212,8 +251,8 @@
                 unit == 'KB' ||
                 unit == 'MB' ||
                 unit == 'bytes' ||
-                !metric.indexOf('V8.') ||
-                metric == 'processes');
+                unit == 'count' ||
+                !metric.indexOf('V8.'));
     }
     this.addResult = function (newResult) {
         testResults.push(newResult);
@@ -243,6 +282,33 @@
     }
 }
 
+function UndeleteManager() {
+    var key = 'telemetry_undeleteIds'
+    var undeleteIds = localStorage[key];
+    if (undeleteIds) {
+        undeleteIds = JSON.parse(undeleteIds);
+    } else {
+        undeleteIds = [];
+    }
+
+    this.ondelete = function(id) {
+        undeleteIds.push(id);
+        localStorage[key] = JSON.stringify(undeleteIds);
+    }
+    this.undeleteMostRecent = function() {
+        if (!this.mostRecentlyDeletedId())
+            return;
+        undeleteIds.pop();
+        localStorage[key] = JSON.stringify(undeleteIds);
+    }
+    this.mostRecentlyDeletedId = function() {
+        if (!undeleteIds.length)
+            return undefined;
+        return undeleteIds[undeleteIds.length-1];
+    }
+}
+var undeleteManager = new UndeleteManager();
+
 var plotColor = 'rgb(230,50,50)';
 var subpointsPlotOptions = {
     lines: {show:true, lineWidth: 0},
@@ -365,20 +431,61 @@
 }
 
 function createTable(tests, runs, shouldIgnoreMemory, referenceIndex) {
-    $('#container').html('<thead><tr><th>Test</th><th>Unit</th>' + runs.map(function (run, index) {
-        return '<th colspan="' + (index == referenceIndex ? 2 : 3) + '" class="{sorter: \'comparison\'}">' + run.label() + '</th>';
+    $('#container').html('<thead><tr><th class="headerSortDown">Test</th><th>Unit</th>' + runs.map(function (run, index) {
+         return '<th colspan="' + (index == referenceIndex ? 2 : 3) + '" class="{sorter: \'comparison\'}" id="' + run.id() + '" title="' + run.description() + '"><span class="label" title="Edit run label">' + run.label() + '</span><div class="closeButton" title="Delete run">x</div></th>';
     }).reduce(function (markup, cell) { return markup + cell; }, '') + '</tr></head><tbody></tbody>');
 
     var testNames = [];
     for (testName in tests)
         testNames.push(testName);
 
+    window.isFirstImportantRow = true;
+
     testNames.sort().map(function (testName) {
         var test = tests[testName];
         if (test.isMemoryTest() != shouldIgnoreMemory)
             createTableRow(runs, test, referenceIndex);
     });
 
+    $('.closeButton').click(function(event) {
+        for (var i = 0; i < runs.length; i++) {
+            if (runs[i].id() == event.target.parentNode.id) {
+                runs[i].hide();
+                undeleteManager.ondelete(runs[i].id());
+                location.reload();
+                break;
+            }
+        }
+        event.stopPropagation();
+    });
+
+    $('.label').click(function(event) {
+        for (var i = 0; i < runs.length; i++) {
+            if (runs[i].id() == event.target.parentNode.id) {
+                $(event.target).replaceWith('<input id="labelEditor" type="text" value="' + runs[i].label()  + '">');
+                $('#labelEditor').focusout(function() {
+                    runs[i].setLabel(this.value);
+                    location.reload();
+                });
+                $('#labelEditor').keypress(function(event) {
+                    if (event.which == 13) {
+                        runs[i].setLabel(this.value);
+                        location.reload();
+                    }
+                });
+                $('#labelEditor').click(function (event) {
+                    event.stopPropagation();
+                });
+                $('#labelEditor').mousedown(function (event) {
+                    event.stopPropagation();
+                });
+                $('#labelEditor').select();
+                break;
+            }
+        }
+        event.stopPropagation();
+    });
+
     $('#container').tablesorter({widgets: ['zebra']});
 }
 
@@ -421,7 +528,7 @@
     + '</svg>';
 
 function createTableRow(runs, test, referenceIndex) {
-    var tableRow = $('<tr><td class="test"' + (test.isImportant ? ' style="font-weight:bold"' : '') + '>' + test.name() + '</td><td class="unit">' + test.unit() + '</td></tr>');
+    var tableRow = $('<tr><td class="test collapsed"' + (test.isImportant ? ' style="font-weight:bold"' : '') + '>' + test.name() + '</td><td class="unit">' + test.unit() + '</td></tr>');
 
     function markupForRun(result, referenceResult) {
         var comparisonCell = '';
@@ -492,6 +599,8 @@
         if (firstCell.children('section').length) {
             firstCell.children('section').remove();
             tableRow.children('td').css({'padding-bottom': ''});
+            tableRow.children('td').first().addClass('collapsed');
+            tableRow.children('td').first().removeClass('expanded');
         } else {
             var plot = createPlot(firstCell, test);
             plot.css({'position': 'absolute', 'z-index': 2});
@@ -500,6 +609,8 @@
             offset.top += tableRow.outerHeight();
             plot.offset(offset);
             tableRow.children('td').css({'padding-bottom': plot.outerHeight() + 5});
+            tableRow.children('td').first().removeClass('collapsed');
+            tableRow.children('td').first().addClass('expanded');
         }
 
         return false;
@@ -514,7 +625,8 @@
         toggle();
     });
 
-    if (test.isImportant) {
+    if (test.isImportant && window.isFirstImportantRow) {
+        window.isFirstImportantRow = false;
         toggle();
     }
 }
@@ -534,31 +646,33 @@
 
     var runs = [];
     var metrics = {};
+    var deletedRunsById = {};
     $.each(JSON.parse(document.getElementById('results-json').textContent), function (index, entry) {
         var run = new TestRun(entry);
+        if (run.isHidden()) {
+            deletedRunsById[run.id()] = run;
+            return;
+        }
+
         runs.push(run);
 
-        function addTests(tests, parentFullName) {
+        function addTests(tests) {
             for (var testName in tests) {
-                var fullTestName = parentFullName + '/' + testName;
                 var rawMetrics = tests[testName].metrics;
 
                 for (var metricName in rawMetrics) {
-                    var fullMetricName = fullTestName + ':' + metricName;
+                    var fullMetricName = testName + ':' + metricName;
                     var metric = metrics[fullMetricName];
                     if (!metric) {
-                        metric = new PerfTestMetric(fullTestName, metricName, rawMetrics[metricName].units, rawMetrics[metricName].important);
+                        metric = new PerfTestMetric(testName, metricName, rawMetrics[metricName].units, rawMetrics[metricName].important);
                         metrics[fullMetricName] = metric;
                     }
                     metric.addResult(new TestResult(metric, rawMetrics[metricName].current, run));
                 }
-
-                if (tests[testName].tests)
-                    addTests(tests[testName].tests, fullTestName);
             }
         }
 
-        addTests(entry.tests, '');
+        addTests(entry.tests);
     });
 
     var shouldIgnoreMemory= true;
@@ -572,7 +686,7 @@
     });
 
     runs.map(function (run, index) {
-        $('#reference').append('<span value="' + index + '"' + (index == referenceIndex ? ' class="checked"' : '') + '>' + run.label() + '</span>');
+        $('#reference').append('<span value="' + index + '"' + (index == referenceIndex ? ' class="checked"' : '') + ' title="' + run.description() + '">' + run.label() + '</span>');
     })
 
     $('#reference').bind('change', function (event, checkedElement) {
@@ -589,6 +703,18 @@
             $(checkbox).trigger('change', $(this));
         });
     });
+
+    if (undeleteManager.mostRecentlyDeletedId()) {
+        $('#undelete').html('Undelete ' + deletedRunsById[undeleteManager.mostRecentlyDeletedId()].label());
+        $('#undelete').attr('title', deletedRunsById[undeleteManager.mostRecentlyDeletedId()].description());
+        $('#undelete').click(function (event) {
+            deletedRunsById[undeleteManager.mostRecentlyDeletedId()].show();
+            undeleteManager.undeleteMostRecent();
+            location.reload();
+        });
+    } else {
+        $('#undelete').hide();
+    }
 }
 
 </script>
diff --git a/tools/telemetry/telemetry/__init__.py b/tools/telemetry/telemetry/__init__.py
index db26220..cb4f71d 100644
--- a/tools/telemetry/telemetry/__init__.py
+++ b/tools/telemetry/telemetry/__init__.py
@@ -1,9 +1,9 @@
 # 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.
-"""
-A library for cross-platform browser tests.
-"""
+
+"""A library for cross-platform browser tests."""
+
 import inspect
 import os
 import sys
@@ -42,9 +42,11 @@
       pyc_path = os.path.join(dirname, filename)
       py_path = os.path.join(dirname, root + '.py')
       if not os.path.exists(py_path):
+        print >> sys.stderr, 'Removing stale .pyc file:', pyc_path
         os.remove(pyc_path)
 
-    if not os.listdir(dirname):
+    if os.path.isdir(dirname) and not os.listdir(dirname):
+      print >> sys.stderr, 'Removing empty directory:', dirname
       os.removedirs(dirname)
 
 
diff --git a/tools/telemetry/telemetry/core/backends/browser_backend.py b/tools/telemetry/telemetry/core/backends/browser_backend.py
index bb120bd..521b949 100644
--- a/tools/telemetry/telemetry/core/backends/browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/browser_backend.py
@@ -55,6 +55,10 @@
   def supports_tracing(self):
     raise NotImplementedError()
 
+  @property
+  def supports_system_info(self):
+    return False
+
   def StartTracing(self, custom_categories=None,
                    timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
     raise NotImplementedError()
@@ -83,6 +87,9 @@
   def GetStackTrace(self):
     raise NotImplementedError()
 
+  def GetSystemInfo(self):
+    raise NotImplementedError()
+
 class DoNothingForwarder(object):
   def __init__(self, *port_pairs):
     self._host_port = port_pairs[0].local_port
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 50ca98b..de8a611 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
@@ -18,6 +18,7 @@
 from telemetry.core.backends import browser_backend
 from telemetry.core.chrome import extension_dict_backend
 from telemetry.core.chrome import misc_web_contents_backend
+from telemetry.core.chrome import system_info_backend
 from telemetry.core.chrome import tab_list_backend
 from telemetry.core.chrome import tracing_backend
 from telemetry.unittest import options_for_unittests
@@ -36,8 +37,9 @@
     self._port = None
 
     self._inspector_protocol_version = 0
-    self._chrome_branch_number = 0
+    self._chrome_branch_number = None
     self._tracing_backend = None
+    self._system_info_backend = None
 
     self.webpagereplay_local_http_port = util.GetAvailableLocalPort()
     self.webpagereplay_local_https_port = util.GetAvailableLocalPort()
@@ -75,6 +77,7 @@
     args.append('--disable-background-networking')
     args.append('--metrics-recording-only')
     args.append('--no-first-run')
+    args.append('--no-proxy-server')
     if self.options.wpr_mode != wpr_modes.WPR_OFF:
       args.extend(wpr_server.GetChromeFlags(
           self.WEBPAGEREPLAY_HOST,
@@ -142,6 +145,9 @@
     if 'Protocol-Version' in resp:
       self._inspector_protocol_version = resp['Protocol-Version']
 
+      if self._chrome_branch_number:
+        return
+
       if 'Browser' in resp:
         branch_number_match = re.search('Chrome/\d+\.\d+\.(\d+)\.\d+',
                                         resp['Browser'])
@@ -167,7 +173,9 @@
     if path:
       url += '/' + path
     try:
-      req = urllib2.urlopen(url, timeout=timeout)
+      proxy_handler = urllib2.ProxyHandler({})  # Bypass any system proxy.
+      opener = urllib2.build_opener(proxy_handler)
+      req = opener.open(url, timeout=timeout)
       return req.read()
     except (socket.error, httplib.BadStatusLine, urllib2.URLError) as e:
       if throw_network_exception:
@@ -186,15 +194,16 @@
 
   @property
   def chrome_branch_number(self):
+    assert self._chrome_branch_number
     return self._chrome_branch_number
 
   @property
   def supports_tab_control(self):
-    return self._chrome_branch_number >= 1303
+    return self.chrome_branch_number >= 1303
 
   @property
   def supports_tracing(self):
-    return self.is_content_shell or self._chrome_branch_number >= 1385
+    return self.is_content_shell or self.chrome_branch_number >= 1385
 
   def StartTracing(self, custom_categories=None,
                    timeout=web_contents.DEFAULT_WEB_CONTENTS_TIMEOUT):
@@ -229,3 +238,21 @@
     if self._tracing_backend:
       self._tracing_backend.Close()
       self._tracing_backend = None
+    if self._system_info_backend:
+      self._system_info_backend.Close()
+      self._system_info_backend = None
+
+  @property
+  def supports_system_info(self):
+    return self.GetSystemInfo() != None
+
+  def GetSystemInfo(self):
+    if self._system_info_backend is None:
+      self._system_info_backend = system_info_backend.SystemInfoBackend(
+          self._port)
+    return self._system_info_backend.GetSystemInfo()
+
+  def _SetBranchNumber(self, version):
+    assert version
+    self._chrome_branch_number = re.search(r'\d+\.\d+\.(\d+)\.\d+',
+                                           version).group(1)
diff --git a/tools/telemetry/telemetry/core/backends/webdriver/__init__.py b/tools/telemetry/telemetry/core/backends/webdriver/__init__.py
new file mode 100644
index 0000000..9228df8
--- /dev/null
+++ b/tools/telemetry/telemetry/core/backends/webdriver/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2013 The Chromium 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/tools/telemetry/telemetry/core/backends/webdriver/webdriver_browser_backend.py b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_browser_backend.py
new file mode 100644
index 0000000..2eb01f2
--- /dev/null
+++ b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_browser_backend.py
@@ -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.
+
+from telemetry.core.backends import browser_backend
+from telemetry.core.backends.webdriver import webdriver_tab_list_backend
+
+class WebDriverBrowserBackend(browser_backend.BrowserBackend):
+  """The webdriver-based backend for controlling a locally-executed browser
+  instance, on Linux, Mac, and Windows.
+  """
+
+  def __init__(self, driver_creator, supports_extensions, options):
+    super(WebDriverBrowserBackend, self).__init__(
+        is_content_shell=False,
+        supports_extensions=supports_extensions,
+        options=options,
+        tab_list_backend=webdriver_tab_list_backend.WebDriverTabListBackend)
+
+    self._driver_creator = driver_creator
+    self._driver = None
+    self.webpagereplay_local_http_port = 80
+    self.webpagereplay_local_https_port = 443
+    self.webpagereplay_remote_http_port = self.webpagereplay_local_http_port
+    self.webpagereplay_remote_https_port = self.webpagereplay_local_https_port
+
+  def Start(self):
+    assert not self._driver
+    self._driver = self._driver_creator()
+
+  @property
+  def driver(self):
+    assert self._driver
+    return self._driver
+
+  @property
+  def supports_tab_control(self):
+    # Based on webdriver protocol API, only closing a tab is supported while
+    # activating or creating a tab is not. Thus, tab control is not supported.
+    return False
+
+  @property
+  def supports_tracing(self):
+    # Tracing is not available in IE/Firefox yet and not supported through
+    # webdriver API.
+    return False
+
+  def GetProcessName(self, _):
+    # Leave implementation details to subclass as process name depends on the
+    # type of browser.
+    raise NotImplementedError()
+
+  def Close(self):
+    if self._driver:
+      self._driver.quit()
+      self._driver = None
+
+  def CreateForwarder(self, *port_pairs):
+    return browser_backend.DoNothingForwarder(*port_pairs)
+
+  def IsBrowserRunning(self):
+    # Assume the browser is running if not explicitly closed.
+    return self._driver is not None
+
+  def GetStandardOutput(self):
+    # TODO(chrisgao): check if python client can get stdout of browsers.
+    return ''
+
+  def __del__(self):
+    self.Close()
diff --git a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_desktop_browser_finder.py b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_desktop_browser_finder.py
new file mode 100644
index 0000000..e75fcba
--- /dev/null
+++ b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_desktop_browser_finder.py
@@ -0,0 +1,96 @@
+# Copyright 2013 The Chromium 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 desktop browsers that can be controlled by telemetry."""
+
+import logging
+import os
+import sys
+
+from telemetry.core import browser
+from telemetry.core import possible_browser
+from telemetry.core import platform
+from telemetry.core import util
+from telemetry.core.backends.webdriver import webdriver_browser_backend
+
+# Try to import the selenium python lib which may be not available.
+util.AddDirToPythonPath(
+    util.GetChromiumSrcDir(), 'third_party', 'webdriver', 'pylib')
+try:
+  from selenium import webdriver  # pylint: disable=F0401
+except ImportError:
+  webdriver = None
+
+ALL_BROWSER_TYPES = ''
+if webdriver:
+  ALL_BROWSER_TYPES = ','.join([
+      'internet-explorer',
+      'internet-explorer-x64'])
+else:
+  logging.warning('Webdriver backend is unsupported without selenium pylib. '
+                  'For installation of selenium pylib, please refer to '
+                  'https://code.google.com/p/selenium/wiki/PythonBindings.')
+
+
+class PossibleWebDriverBrowser(possible_browser.PossibleBrowser):
+  """A browser that can be controlled through webdriver API."""
+
+  def __init__(self, browser_type, options):
+    super(PossibleWebDriverBrowser, self).__init__(browser_type, options)
+
+  def CreateWebDriverBackend(self):
+    raise NotImplementedError()
+
+  def Create(self):
+    backend = self.CreateWebDriverBackend()
+    b = browser.Browser(backend, platform.CreatePlatformBackendForCurrentOS())
+    return b
+
+  def SupportsOptions(self, options):
+    # TODO(chrisgao): Check if some options are not supported.
+    return True
+
+  @property
+  def last_modification_time(self):
+    return -1
+
+
+class PossibleDesktopIE(PossibleWebDriverBrowser):
+  def __init__(self, browser_type, options, architecture):
+    super(PossibleDesktopIE, self).__init__(browser_type, options)
+    self._architecture = architecture
+
+  def CreateWebDriverBackend(self):
+    assert webdriver
+    def DriverCreator():
+      # TODO(chrisgao): Check in IEDriverServer.exe and specify path to it when
+      # creating the webdriver instance. crbug.com/266170
+      return webdriver.Ie()
+    return webdriver_browser_backend.WebDriverBrowserBackend(
+        DriverCreator, False, self.options)
+
+def SelectDefaultBrowser(_):
+  return None
+
+def FindAllAvailableBrowsers(options):
+  """Finds all the desktop browsers available on this machine."""
+  browsers = []
+  if not webdriver:
+    return browsers
+
+  # Look for the IE browser in the standard location.
+  if sys.platform.startswith('win'):
+    ie_path = os.path.join('Internet Explorer', 'iexplore.exe')
+    win_search_paths = {
+        '32' : { 'path' : os.getenv('PROGRAMFILES(X86)'),
+                 'type' : 'internet-explorer'},
+        '64' : { 'path' : os.getenv('PROGRAMFILES'),
+                 'type' : 'internet-explorer-x64'}}
+    for architecture, ie_info in win_search_paths.iteritems():
+      if not ie_info['path']:
+        continue
+      if os.path.exists(os.path.join(ie_info['path'], ie_path)):
+        browsers.append(
+            PossibleDesktopIE(ie_info['type'], options, architecture))
+
+  return browsers
diff --git a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py
new file mode 100644
index 0000000..df2e7ae
--- /dev/null
+++ b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_backend.py
@@ -0,0 +1,120 @@
+# Copyright 2013 The Chromium 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
+
+# TODO(chrisgao): Make png_bitmap sharable for both chrome and webdriver.
+from telemetry.core.chrome import png_bitmap
+
+class WebDriverTabBackend(object):
+  def __init__(self, browser_backend, window_handle):
+    self._browser_backend = browser_backend
+    self._window_handle = window_handle
+
+  def Disconnect(self):
+    pass
+
+  @property
+  def browser(self):
+    return self._browser_backend.browser
+
+  @property
+  def window_handle(self):
+    return self._window_handle
+
+  @property
+  def url(self):
+    self._browser_backend.driver.switch_to_window(self._window_handle)
+    return self._browser_backend.driver.current_url
+
+  def Activate(self):
+    # Webdriver doesn't support tab control.
+    raise NotImplementedError()
+
+  def Close(self):
+    self._browser_backend.driver.switch_to_window(self._window_handle)
+    self._browser_backend.driver.close()
+
+  def WaitForDocumentReadyStateToBeComplete(self, timeout=None):
+    # TODO(chrisgao): Double check of document state.
+    pass
+
+  def WaitForDocumentReadyStateToBeInteractiveOrBetter(self, timeout=None):
+    # TODO(chrisgao): Double check of document state.
+    pass
+
+  @property
+  def screenshot_supported(self):
+    return True
+
+  def Screenshot(self, timeout=None):  # pylint: disable=W0613
+    if timeout:
+      logging.warning('timeout is not supported')
+    self._browser_backend.driver.switch_to_window(self._window_handle)
+    snap = self._browser_backend.driver.get_screenshot_as_base64()
+    if snap:
+      return png_bitmap.PngBitmap(snap)
+    return None
+
+  @property
+  def message_output_stream(self):
+    # Webdriver has no API for grabbing console messages.
+    raise NotImplementedError()
+
+  @message_output_stream.setter
+  def message_output_stream(self, stream):
+    raise NotImplementedError()
+
+  def GetDOMStats(self, timeout=None):
+    # Webdriver has no API for DOM status.
+    raise NotImplementedError()
+
+  def PerformActionAndWaitForNavigate(self, action_function, _):
+    # TODO(chrisgao): Double check of navigation.
+    action_function()
+
+  def Navigate(self, url, script_to_evaluate_on_commit=None, timeout=None):
+    if script_to_evaluate_on_commit:
+      raise NotImplementedError('script_to_evaluate_on_commit is NOT supported')
+    self._browser_backend.driver.switch_to_window(self._window_handle)
+    if timeout:
+      self._browser_backend.driver.set_page_load_timeout(timeout * 1000)
+    self._browser_backend.driver.get(url)
+
+  def GetCookieByName(self, name, timeout=None):
+    if timeout:
+      logging.warning('timeout is not supported')
+    self._browser_backend.driver.switch_to_window(self._window_handle)
+    cookie = self._browser_backend.driver.get_cookie(name)
+    if cookie:
+      return cookie['value']
+    return None
+
+  def ExecuteJavaScript(self, expr, timeout=None):
+    self._browser_backend.driver.switch_to_window(self._window_handle)
+    if timeout:
+      logging.warning('timeout is not supported')
+    self._browser_backend.driver.execute_script(expr)
+
+  def EvaluateJavaScript(self, expr, timeout=None):
+    self._browser_backend.driver.switch_to_window(self._window_handle)
+    if timeout:
+      logging.warning('timeout is not supported')
+    return self._browser_backend.driver.execute_script(
+        'return eval(\'%s\')' % expr.replace('\'', '\\\'').replace('\n', ' '))
+
+  @property
+  def timeline_model(self):
+    # IE/Firefox has no timeline.
+    raise NotImplementedError()
+
+  def StartTimelineRecording(self):
+    raise NotImplementedError()
+
+  def StopTimelineRecording(self):
+    raise NotImplementedError()
+
+  def ClearCache(self):
+    # Can't find a way to clear cache of a tab in IE/Firefox.
+    raise NotImplementedError()
diff --git a/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_list_backend.py b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_list_backend.py
new file mode 100644
index 0000000..ea9c834
--- /dev/null
+++ b/tools/telemetry/telemetry/core/backends/webdriver/webdriver_tab_list_backend.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.
+
+from telemetry.core.backends.webdriver import webdriver_tab_backend
+
+class WebDriverTabListBackend(object):
+  def __init__(self, browser_backend):
+    self._browser_backend = browser_backend
+    # Stores the window handles.
+    self._tab_list = []
+
+  def Init(self):
+    self._UpdateTabList()
+
+  def New(self, timeout=None):
+    # Webdriver API doesn't support tab controlling.
+    raise NotImplementedError()
+
+  def __iter__(self):
+    self._UpdateTabList()
+    return self._tab_list.__iter__()
+
+  def __len__(self):
+    self._UpdateTabList()
+    return len(self._tab_list)
+
+  def __getitem__(self, index):
+    self._UpdateTabList()
+    if len(self._tab_list) <= index:
+      raise IndexError('list index out of range')
+    return self._tab_list[index]
+
+  def _UpdateTabList(self):
+    window_handles = self._browser_backend.driver.window_handles
+    old_tab_list = self._tab_list
+    self._tab_list = []
+    for window_handle in window_handles:
+      tab = None
+      for old_tab in old_tab_list:
+        if old_tab.window_handle == window_handle:
+          tab = old_tab
+          break
+      else:
+        tab = webdriver_tab_backend.WebDriverTabBackend(
+            self._browser_backend, window_handle)
+      self._tab_list.append(tab)
diff --git a/tools/telemetry/telemetry/core/browser.py b/tools/telemetry/telemetry/core/browser.py
index a04b058..d35a7fc 100644
--- a/tools/telemetry/telemetry/core/browser.py
+++ b/tools/telemetry/telemetry/core/browser.py
@@ -317,3 +317,13 @@
 
   def GetStackTrace(self):
     return self._browser_backend.GetStackTrace()
+
+  @property
+  def supports_system_info(self):
+    return self._browser_backend.supports_system_info
+
+  def GetSystemInfo(self):
+    """Returns low-level information about the system, if available.
+
+       See the documentation of the SystemInfo class for more details."""
+    return self._browser_backend.GetSystemInfo()
diff --git a/tools/telemetry/telemetry/core/browser_credentials.py b/tools/telemetry/telemetry/core/browser_credentials.py
index fadeaa1..d53c6a8 100644
--- a/tools/telemetry/telemetry/core/browser_credentials.py
+++ b/tools/telemetry/telemetry/core/browser_credentials.py
@@ -5,6 +5,7 @@
 import json
 import os
 
+from telemetry.core import util
 from telemetry.core.chrome import facebook_credentials_backend
 from telemetry.core.chrome import google_credentials_backend
 from telemetry.unittest import options_for_unittests
@@ -126,11 +127,8 @@
                                        page_set.credentials_path)))
       files_to_tweak.append('~/.telemetry-credentials')
 
-      example_credentials_file = (
-        os.path.relpath(
-          os.path.join(
-            os.path.dirname(__file__),
-            '..', 'examples', 'credentials_example.json')))
+      example_credentials_file = os.path.join(
+          util.GetTelemetryDir(), 'examples', 'credentials_example.json')
 
       logging.warning("""
         Credentials for %s were not found. %i pages will not be tested.
diff --git a/tools/telemetry/telemetry/core/browser_finder.py b/tools/telemetry/telemetry/core/browser_finder.py
index e316e05..0248857 100644
--- a/tools/telemetry/telemetry/core/browser_finder.py
+++ b/tools/telemetry/telemetry/core/browser_finder.py
@@ -5,6 +5,7 @@
 
 import logging
 
+from telemetry.core.backends.webdriver import webdriver_desktop_browser_finder
 from telemetry.core.chrome import android_browser_finder
 from telemetry.core.chrome import cros_browser_finder
 from telemetry.core.chrome import desktop_browser_finder
@@ -12,7 +13,8 @@
 BROWSER_FINDERS = [
   desktop_browser_finder,
   android_browser_finder,
-  cros_browser_finder
+  cros_browser_finder,
+  webdriver_desktop_browser_finder,
   ]
 
 ALL_BROWSER_TYPES = ','.join([bf.ALL_BROWSER_TYPES for bf in BROWSER_FINDERS])
diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py
index 69f3048..4078fe4 100644
--- a/tools/telemetry/telemetry/core/browser_options.py
+++ b/tools/telemetry/telemetry/core/browser_options.py
@@ -54,6 +54,7 @@
 
     self.repeat_options = repeat_options.RepeatOptions()
     self.output_file = None
+    self.skip_navigate_on_repeat = False
 
   def Copy(self):
     return copy.deepcopy(self)
@@ -185,11 +186,11 @@
       ret = real_parse(args, self) # pylint: disable=E1121
 
       if self.verbosity >= 2:
-        logging.basicConfig(level=logging.DEBUG)
+        logging.getLogger().setLevel(logging.DEBUG)
       elif self.verbosity:
-        logging.basicConfig(level=logging.INFO)
+        logging.getLogger().setLevel(logging.INFO)
       else:
-        logging.basicConfig(level=logging.WARNING)
+        logging.getLogger().setLevel(logging.WARNING)
 
       if self.browser_executable and not self.browser_type:
         self.browser_type = 'exact'
@@ -215,10 +216,6 @@
       if self.profile_type == 'default':
         self.dont_override_profile = True
 
-      if ((hasattr(self, 'output_format') and self.output_format == 'html') and
-          (not hasattr(self, 'output_file') or not self.output_file)):
-        self.output_file = os.path.join(util.GetBaseDir(), 'results.html')
-
       # Parse repeat options
       self.repeat_options.UpdateFromParseResults(self, parser)
 
diff --git a/tools/telemetry/telemetry/core/browser_unittest.py b/tools/telemetry/telemetry/core/browser_unittest.py
index 81a80f7..bf73325 100644
--- a/tools/telemetry/telemetry/core/browser_unittest.py
+++ b/tools/telemetry/telemetry/core/browser_unittest.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 logging
-import os
 import unittest
 
 from telemetry.core import browser_finder
+from telemetry.core import gpu_device
+from telemetry.core import gpu_info
+from telemetry.core import system_info
+from telemetry.core import util
 from telemetry.unittest import options_for_unittests
 
 class BrowserTest(unittest.TestCase):
@@ -39,9 +42,7 @@
     self._browser = browser_to_create.Create()
     self._browser.Start()
 
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
 
     return self._browser
 
@@ -72,7 +73,7 @@
     v = b._browser_backend._inspector_protocol_version # pylint: disable=W0212
     self.assertTrue(v > 0)
 
-    v = b._browser_backend._chrome_branch_number > 0 # pylint: disable=W0212
+    v = b._browser_backend.chrome_branch_number # pylint: disable=W0212
     self.assertTrue(v > 0)
 
   def testNewCloseTab(self):
@@ -123,3 +124,22 @@
       return
 
     self.assertEquals(1, len(b.tabs))
+
+  def testGetSystemInfo(self):
+    b = self.CreateBrowser()
+    if not b.supports_system_info:
+      logging.warning(
+          'Browser does not support getting system info, skipping test.')
+      return
+
+    info = b.GetSystemInfo()
+
+    self.assertTrue(isinstance(info, system_info.SystemInfo))
+    self.assertTrue(hasattr(info, 'model_name'))
+    self.assertTrue(hasattr(info, 'gpu'))
+    self.assertTrue(isinstance(info.gpu, gpu_info.GPUInfo))
+    self.assertTrue(hasattr(info.gpu, 'devices'))
+    self.assertTrue(len(info.gpu.devices) > 0)
+    for g in info.gpu.devices:
+      self.assertTrue(isinstance(g, gpu_device.GPUDevice))
+
diff --git a/tools/telemetry/telemetry/core/camel_case.py b/tools/telemetry/telemetry/core/camel_case.py
new file mode 100644
index 0000000..4c2939b
--- /dev/null
+++ b/tools/telemetry/telemetry/core/camel_case.py
@@ -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.
+
+import re
+
+
+def ToUnderscore(obj):
+  """Converts a string, list, or dict from camelCase to lower_with_underscores.
+
+  Descends recursively into lists and dicts, converting all dict keys.
+  Returns a newly allocated object of the same structure as the input.
+  """
+  if isinstance(obj, basestring):
+    return re.sub('(?!^)([A-Z]+)', r'_\1', obj).lower()
+
+  elif isinstance(obj, list):
+    return [ToUnderscore(item) for item in obj]
+
+  elif isinstance(obj, dict):
+    output = {}
+    for k, v in obj.iteritems():
+      if isinstance(v, list) or isinstance(v, dict):
+        output[ToUnderscore(k)] = ToUnderscore(v)
+      else:
+        output[ToUnderscore(k)] = v
+    return output
+
+  else:
+    raise NotImplementedError()
diff --git a/tools/telemetry/telemetry/core/camel_case_unittest.py b/tools/telemetry/telemetry/core/camel_case_unittest.py
new file mode 100644
index 0000000..81df388
--- /dev/null
+++ b/tools/telemetry/telemetry/core/camel_case_unittest.py
@@ -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.
+
+import unittest
+
+from telemetry.core import camel_case
+
+
+class CamelCaseTest(unittest.TestCase):
+  def testString(self):
+    self.assertEqual(camel_case.ToUnderscore('camelCase'), 'camel_case')
+    self.assertEqual(camel_case.ToUnderscore('CamelCase'), 'camel_case')
+    self.assertEqual(camel_case.ToUnderscore('Camel2Case'), 'camel2_case')
+    self.assertEqual(camel_case.ToUnderscore('Camel2Case2'), 'camel2_case2')
+    self.assertEqual(camel_case.ToUnderscore('2012Q3'), '2012_q3')
+
+  def testList(self):
+    camel_case_list = ['CamelCase', ['NestedList']]
+    underscore_list = ['camel_case', ['nested_list']]
+    self.assertEquals(camel_case.ToUnderscore(camel_case_list), underscore_list)
+
+  def testDict(self):
+    camel_case_dict = {
+      'gpu': {
+        'vendorId': 1000,
+        'deviceId': 2000,
+        'vendorString': 'aString',
+        'deviceString': 'bString' },
+      'secondaryGpus': [
+        { 'vendorId': 3000, 'deviceId': 4000,
+          'vendorString': 'k', 'deviceString': 'l' }
+      ]
+    }
+    underscore_dict = {
+      'gpu': {
+        'vendor_id': 1000,
+        'device_id': 2000,
+        'vendor_string': 'aString',
+        'device_string': 'bString' },
+      'secondary_gpus': [
+        { 'vendor_id': 3000, 'device_id': 4000,
+          'vendor_string': 'k', 'device_string': 'l' }
+      ]
+    }
+    self.assertEquals(camel_case.ToUnderscore(camel_case_dict), underscore_dict)
+
+  def testOther(self):
+    self.assertRaises(
+        NotImplementedError,
+        lambda: camel_case.ToUnderscore(lambda: None))
diff --git a/tools/telemetry/telemetry/core/chrome/adb_commands.py b/tools/telemetry/telemetry/core/chrome/adb_commands.py
index 890327b..d1ee0bb 100644
--- a/tools/telemetry/telemetry/core/chrome/adb_commands.py
+++ b/tools/telemetry/telemetry/core/chrome/adb_commands.py
@@ -4,22 +4,19 @@
 """Brings in Chrome Android's android_commands module, which itself is a
 thin(ish) wrapper around adb."""
 import os
-import sys
+
+from telemetry.core import util
 
 # This is currently a thin wrapper around Chrome Android's
 # build scripts, located in chrome/build/android. This file exists mainly to
 # deal with locating the module.
 
-# Get build/android scripts into our path.
-sys.path.append(
-    os.path.abspath(
-        os.path.join(os.path.dirname(__file__),
-                     '..', '..', '..', '..', '..', 'build', 'android')))
+util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
 try:
-  from pylib import android_commands # pylint: disable=F0401
-  from pylib import cmd_helper # pylint: disable=F0401
-  from pylib import forwarder # pylint: disable=F0401
-  from pylib import ports # pylint: disable=F0401
+  from pylib import android_commands  # pylint: disable=F0401
+  from pylib import cmd_helper  # pylint: disable=F0401
+  from pylib import forwarder  # pylint: disable=F0401
+  from pylib import ports  # pylint: disable=F0401
 except Exception:
   android_commands = None
 
@@ -117,7 +114,8 @@
   def StartActivity(self, package, activity, wait_for_completion=False,
                     action='android.intent.action.VIEW',
                     category=None, data=None,
-                    extras=None, trace_file_name=None):
+                    extras=None, trace_file_name=None,
+                    flags=None):
     """Starts |package|'s activity on the device.
 
     Args:
@@ -134,7 +132,8 @@
     return self._adb.StartActivity(package, activity, wait_for_completion,
                     action,
                     category, data,
-                    extras, trace_file_name)
+                    extras, trace_file_name,
+                    flags)
 
   def Push(self, local, remote):
     return self._adb.Adb().Push(local, remote)
diff --git a/tools/telemetry/telemetry/core/chrome/android_browser_finder.py b/tools/telemetry/telemetry/core/chrome/android_browser_finder.py
index 86a942f..c85d32a 100644
--- a/tools/telemetry/telemetry/core/chrome/android_browser_finder.py
+++ b/tools/telemetry/telemetry/core/chrome/android_browser_finder.py
@@ -12,6 +12,7 @@
 from telemetry.core import browser
 from telemetry.core import possible_browser
 from telemetry.core import profile_types
+from telemetry.core import util
 from telemetry.core.chrome import adb_commands
 from telemetry.core.chrome import android_browser_backend
 from telemetry.core.platform import android_platform_backend
@@ -91,8 +92,7 @@
           logging.warn('  sudo `which adb` devices\n\n')
         adb_works = True
     except OSError:
-      platform_tools_path = os.path.join(
-          os.path.dirname(__file__), '..', '..', '..', '..', '..'
+      platform_tools_path = os.path.join(util.GetChromiumSrcDir(),
           'third_party', 'android_tools', 'sdk', 'platform-tools')
       if (sys.platform.startswith('linux') and
           os.path.exists(os.path.join(platform_tools_path, 'adb'))):
@@ -101,6 +101,19 @@
         adb_works = True
       else:
         adb_works = False
+  if adb_works and sys.platform.startswith('linux'):
+    # Workaround for crbug.com/268450
+    import psutil
+    adb_commands.GetAttachedDevices()
+    pids  = [p.pid for p in psutil.process_iter() if 'adb' in p.name]
+    with open(os.devnull, 'w') as devnull:
+      for pid in pids:
+        ret = subprocess.call(['taskset', '-p', '0x1', str(pid)],
+                              stdout=subprocess.PIPE,
+                              stderr=subprocess.PIPE,
+                              stdin=devnull)
+        if ret:
+          logging.warn('Failed to taskset %d (%s)', pid, ret)
 
   return adb_works
 
diff --git a/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py b/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py
index 0f73add..5165420 100644
--- a/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py
+++ b/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py
@@ -31,6 +31,8 @@
     self._port = self._remote_debugging_port
     self._forwarder = None
 
+    self._SetBranchNumber(self._GetChromeVersion())
+
     self._login_ext_dir = os.path.join(os.path.dirname(__file__),
                                        'chromeos_login_ext')
 
@@ -106,7 +108,7 @@
   def _GetSessionManagerPid(self, procs):
     """Returns the pid of the session_manager process, given the list of
     processes."""
-    for pid, process, _ in procs:
+    for pid, process, _, _ in procs:
       if process.startswith('/sbin/session_manager '):
         return pid
     return None
@@ -129,7 +131,7 @@
       return None
 
     # Find the chrome process that is the child of the session_manager.
-    for pid, process, ppid in procs:
+    for pid, process, ppid, _ in procs:
       if ppid != session_manager_pid:
         continue
       for path in self.CHROME_PATHS:
@@ -137,6 +139,13 @@
           return {'pid': pid, 'path': path}
     return None
 
+  def _GetChromeVersion(self):
+    result = self._GetChromeProcess()
+    assert result and result['path']
+    (version, _) = self._cri.RunCmdOnDevice([result['path'], '--version'])
+    assert version
+    return version
+
   @property
   def pid(self):
     result = self._GetChromeProcess()
@@ -148,7 +157,7 @@
   def browser_directory(self):
     result = self._GetChromeProcess()
     if result and 'path' in result:
-      return result['path']
+      return os.path.dirname(result['path'])
     return None
 
   @property
diff --git a/tools/telemetry/telemetry/core/chrome/cros_interface.py b/tools/telemetry/telemetry/core/chrome/cros_interface.py
index a825e5b..6f1f160 100644
--- a/tools/telemetry/telemetry/core/chrome/cros_interface.py
+++ b/tools/telemetry/telemetry/core/chrome/cros_interface.py
@@ -245,19 +245,19 @@
         return res
 
   def ListProcesses(self):
-    """Returns a tuple (pid, cmd, ppid) of all processes on the device."""
+    """Returns (pid, cmd, ppid, state) of all processes on the device."""
     stdout, stderr = self.RunCmdOnDevice([
         '/bin/ps', '--no-headers',
         '-A',
-        '-o', 'pid,ppid,args'], quiet=True)
+        '-o', 'pid,ppid,args,state'], quiet=True)
     assert stderr == '', stderr
     procs = []
     for l in stdout.split('\n'): # pylint: disable=E1103
       if l == '':
         continue
-      m = re.match('^\s*(\d+)\s+(\d+)\s+(.+)', l, re.DOTALL)
+      m = re.match('^\s*(\d+)\s+(\d+)\s+(.+)\s+(.+)', l, re.DOTALL)
       assert m
-      procs.append((int(m.group(1)), m.group(3), int(m.group(2))))
+      procs.append((int(m.group(1)), m.group(3), int(m.group(2)), m.group(4)))
     logging.debug("ListProcesses(<predicate>)->[%i processes]" % len(procs))
     return procs
 
@@ -267,7 +267,7 @@
 
   def KillAllMatching(self, predicate):
     kills = ['kill', '-KILL']
-    for pid, cmd, _ in self.ListProcesses():
+    for pid, cmd, _, _ in self.ListProcesses():
       if predicate(cmd):
         logging.info('Killing %s, pid %d' % cmd, pid)
         kills.append(pid)
diff --git a/tools/telemetry/telemetry/core/chrome/crx_id.py b/tools/telemetry/telemetry/core/chrome/crx_id.py
index ebff59c..db56353 100644
--- a/tools/telemetry/telemetry/core/chrome/crx_id.py
+++ b/tools/telemetry/telemetry/core/chrome/crx_id.py
@@ -3,16 +3,11 @@
 # found in the LICENSE file.
 from __future__ import absolute_import
 
-import os
-import sys
+from telemetry.core import util
 
-def __init__():
-  path = os.path.abspath(
-      os.path.join(os.path.dirname(__file__), '..', '..', '..', '..'))
-  sys.path.append(path)
+util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'tools')
+from crx_id import crx_id  # pylint: disable=F0401
 
-__init__()
 
-from crx_id import crx_id # pylint: disable=F0401
 GetCRXAppID = crx_id.GetCRXAppID
-HasPublicKey = crx_id.HasPublicKey
\ No newline at end of file
+HasPublicKey = crx_id.HasPublicKey
diff --git a/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py b/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py
index 834278d..eccdb5a 100644
--- a/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py
+++ b/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py
@@ -1,12 +1,15 @@
 # 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 glob
+import heapq
 import logging
 import os
 import subprocess as subprocess
 import shutil
 import sys
 import tempfile
+import time
 
 from telemetry.core import util
 from telemetry.core.backends import browser_backend
@@ -25,7 +28,7 @@
 
     # Initialize fields so that an explosion during init doesn't break in Close.
     self._proc = None
-    self._tmpdir = None
+    self._tmp_profile_dir = None
     self._tmp_output_file = None
 
     self._executable = executable
@@ -48,29 +51,33 @@
     self._profile_dir = None
     self._supports_net_benchmarking = True
     self._delete_profile_dir_after_run = delete_profile_dir_after_run
+    self._tmp_minidump_dir = tempfile.mkdtemp()
 
     self._SetupProfile()
 
   def _SetupProfile(self):
     if not self.options.dont_override_profile:
-      self._tmpdir = tempfile.mkdtemp()
+      self._tmp_profile_dir = tempfile.mkdtemp()
       profile_dir = self._profile_dir or self.options.profile_dir
       if profile_dir:
         if self.is_content_shell:
           logging.critical('Profiles cannot be used with content shell')
           sys.exit(1)
-        shutil.rmtree(self._tmpdir)
-        shutil.copytree(profile_dir, self._tmpdir)
+        shutil.rmtree(self._tmp_profile_dir)
+        shutil.copytree(profile_dir, self._tmp_profile_dir)
 
   def _LaunchBrowser(self):
     args = [self._executable]
     args.extend(self.GetBrowserStartupArgs())
+    env = os.environ.copy()
+    env['CHROME_HEADLESS'] = '1'  # Don't upload minidumps.
+    env['BREAKPAD_DUMP_LOCATION'] = self._tmp_minidump_dir
     if not self.options.show_stdout:
       self._tmp_output_file = tempfile.NamedTemporaryFile('w', 0)
       self._proc = subprocess.Popen(
-          args, stdout=self._tmp_output_file, stderr=subprocess.STDOUT)
+          args, stdout=self._tmp_output_file, stderr=subprocess.STDOUT, env=env)
     else:
-      self._proc = subprocess.Popen(args)
+      self._proc = subprocess.Popen(args, env=env)
 
     try:
       self._WaitForBrowserToComeUp()
@@ -82,6 +89,7 @@
   def GetBrowserStartupArgs(self):
     args = super(DesktopBrowserBackend, self).GetBrowserStartupArgs()
     args.append('--remote-debugging-port=%i' % self._port)
+    args.append('--enable-crash-reporter-for-testing')
     if not self.is_content_shell:
       args.append('--window-size=1280,1024')
       if self._flash_path:
@@ -91,7 +99,7 @@
       else:
         args.append('--enable-benchmarking')
       if not self.options.dont_override_profile:
-        args.append('--user-data-dir=%s' % self._tmpdir)
+        args.append('--user-data-dir=%s' % self._tmp_profile_dir)
     return args
 
   def SetProfileDirectory(self, profile_dir):
@@ -109,7 +117,7 @@
 
     # For old chrome versions, might have to relaunch to have the
     # correct net_benchmarking switch.
-    if self._chrome_branch_number < 1418:
+    if self.chrome_branch_number < 1418:
       self.Close()
       self._supports_net_benchmarking = False
       self._LaunchBrowser()
@@ -126,7 +134,7 @@
 
   @property
   def profile_directory(self):
-    return self._tmpdir
+    return self._tmp_profile_dir
 
   def IsBrowserRunning(self):
     return self._proc.poll() == None
@@ -141,10 +149,46 @@
       return ''
 
   def GetStackTrace(self):
-    # crbug.com/223572, symbolize stack trace for desktop browsers.
-    logging.warning('Stack traces not supported on desktop browsers, '
-                    'returning stdout')
-    return self.GetStandardOutput()
+    stackwalk = util.FindSupportBinary('minidump_stackwalk')
+    if not stackwalk:
+      logging.warning('minidump_stackwalk binary not found. Must build it to '
+                      'symbolize crash dumps. Returning browser stdout.')
+      return self.GetStandardOutput()
+
+    dumps = glob.glob(os.path.join(self._tmp_minidump_dir, '*.dmp'))
+    if not dumps:
+      logging.warning('No crash dump found. Returning browser stdout.')
+      return self.GetStandardOutput()
+    most_recent_dump = heapq.nlargest(1, dumps, os.path.getmtime)[0]
+    if os.path.getmtime(most_recent_dump) < (time.time() - (5 * 60)):
+      logging.warn('Crash dump is older than 5 minutes. May not be correct.')
+
+    minidump = most_recent_dump + '.stripped'
+    with open(most_recent_dump, 'rb') as infile:
+      with open(minidump, 'wb') as outfile:
+        outfile.write(''.join(infile.read().partition('MDMP')[1:]))
+
+    symbols = glob.glob(os.path.join(os.path.dirname(stackwalk), '*.breakpad*'))
+    if not symbols:
+      logging.warning('No breakpad symbols found. Returning browser stdout.')
+      return self.GetStandardOutput()
+
+    symbols_path = os.path.join(self._tmp_minidump_dir, 'symbols')
+    for symbol in symbols:
+      with open(symbol, 'r') as f:
+        fields = f.readline().split()
+        if not fields:
+          continue
+        sha = fields[3]
+        binary = ' '.join(fields[4:])
+      symbol_path = os.path.join(symbols_path, binary, sha)
+      os.makedirs(symbol_path)
+      shutil.copyfile(symbol, os.path.join(symbol_path, binary + '.sym'))
+
+    error = tempfile.NamedTemporaryFile('w', 0)
+    return subprocess.Popen(
+        [stackwalk, minidump, symbols_path],
+        stdout=subprocess.PIPE, stderr=error).communicate()[0]
 
   def __del__(self):
     self.Close()
@@ -178,9 +222,9 @@
           raise Exception('Could not shutdown the browser.')
 
     if self._delete_profile_dir_after_run and \
-        self._tmpdir and os.path.exists(self._tmpdir):
-      shutil.rmtree(self._tmpdir, ignore_errors=True)
-      self._tmpdir = None
+        self._tmp_profile_dir and os.path.exists(self._tmp_profile_dir):
+      shutil.rmtree(self._tmp_profile_dir, ignore_errors=True)
+      self._tmp_profile_dir = None
 
     if self._tmp_output_file:
       self._tmp_output_file.close()
diff --git a/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py b/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py
index 8ef4d6d..93f33d8 100644
--- a/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py
+++ b/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py
@@ -150,10 +150,13 @@
   else:
     raise Exception('Platform not recognized')
 
+  def IsExecutable(path):
+    return os.path.isfile(path) and os.access(path, os.X_OK)
+
   # Add the explicit browser executable if given.
   if options.browser_executable:
     normalized_executable = os.path.expanduser(options.browser_executable)
-    if os.path.exists(normalized_executable):
+    if IsExecutable(normalized_executable):
       browser_directory = os.path.dirname(options.browser_executable)
       browsers.append(PossibleDesktopBrowser('exact', options,
                                              normalized_executable, flash_path,
@@ -165,7 +168,7 @@
   def AddIfFound(browser_type, build_dir, type_dir, app_name, content_shell):
     browser_directory = os.path.join(chrome_root, build_dir, type_dir)
     app = os.path.join(browser_directory, app_name)
-    if os.path.exists(app):
+    if IsExecutable(app):
       browsers.append(PossibleDesktopBrowser(browser_type, options,
                                              app, flash_path, content_shell,
                                              browser_directory,
@@ -186,12 +189,12 @@
     mac_canary = mac_canary_root + 'Contents/MacOS/Google Chrome Canary'
     mac_system_root = '/Applications/Google Chrome.app'
     mac_system = mac_system_root + '/Contents/MacOS/Google Chrome'
-    if os.path.exists(mac_canary):
+    if IsExecutable(mac_canary):
       browsers.append(PossibleDesktopBrowser('canary', options,
                                              mac_canary, None, False,
                                              mac_canary_root))
 
-    if os.path.exists(mac_system):
+    if IsExecutable(mac_system):
       browsers.append(PossibleDesktopBrowser('system', options,
                                              mac_system, None, False,
                                              mac_system_root))
@@ -223,7 +226,7 @@
     def AddIfFoundWin(browser_name, app_path):
       browser_directory = os.path.join(path, app_path)
       app = os.path.join(browser_directory, chromium_app_name)
-      if os.path.exists(app):
+      if IsExecutable(app):
         browsers.append(PossibleDesktopBrowser(browser_name, options,
                                                app, flash_path, False,
                                                browser_directory))
diff --git a/tools/telemetry/telemetry/core/chrome/form_based_credentials_backend_unittest_base.py b/tools/telemetry/telemetry/core/chrome/form_based_credentials_backend_unittest_base.py
index 6c6449f..2577b93 100644
--- a/tools/telemetry/telemetry/core/chrome/form_based_credentials_backend_unittest_base.py
+++ b/tools/telemetry/telemetry/core/chrome/form_based_credentials_backend_unittest_base.py
@@ -6,6 +6,7 @@
 import unittest
 
 from telemetry.core import browser_finder
+from telemetry.core import util
 from telemetry.unittest import simple_mock
 from telemetry.unittest import options_for_unittests
 from telemetry.unittest import DisabledTest
@@ -15,9 +16,8 @@
 
 def _GetCredentialsPath():
   # TODO: This shouldn't depend on tools/perf.
-  credentials_path = os.path.join(
-      os.path.dirname(__file__),
-      '..', '..', '..', '..', 'perf', 'data', 'credentials.json')
+  credentials_path = os.path.join(util.GetChromiumSrcDir(),
+      'tools', 'perf', 'data', 'credentials.json')
   if not os.path.exists(credentials_path):
     return None
   return credentials_path
diff --git a/tools/telemetry/telemetry/core/chrome/inspector_console_unittest.py b/tools/telemetry/telemetry/core/chrome/inspector_console_unittest.py
index 3db6eb4..ec85cc8 100644
--- a/tools/telemetry/telemetry/core/chrome/inspector_console_unittest.py
+++ b/tools/telemetry/telemetry/core/chrome/inspector_console_unittest.py
@@ -1,7 +1,6 @@
 # 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 re
 import StringIO
 
@@ -10,9 +9,7 @@
 
 class TabConsoleTest(tab_test_case.TabTestCase):
   def testConsoleOutputStream(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
 
     stream = StringIO.StringIO()
     self._tab.message_output_stream = stream
diff --git a/tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py b/tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py
index f8c0ad3..bb4761b 100644
--- a/tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py
+++ b/tools/telemetry/telemetry/core/chrome/inspector_memory_unittest.py
@@ -1,15 +1,13 @@
 # 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
 
+from telemetry.core import util
 from telemetry.unittest import tab_test_case
 
 class InspectorMemoryTest(tab_test_case.TabTestCase):
   def testGetDOMStats(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
 
     # Due to an issue with CrOS, we create a new tab here rather than
     # using self._tab to get a consistent starting page on all platforms
diff --git a/tools/telemetry/telemetry/core/chrome/inspector_page_unittest.py b/tools/telemetry/telemetry/core/chrome/inspector_page_unittest.py
index c01c330..97cb413 100644
--- a/tools/telemetry/telemetry/core/chrome/inspector_page_unittest.py
+++ b/tools/telemetry/telemetry/core/chrome/inspector_page_unittest.py
@@ -1,12 +1,10 @@
 # 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
 
+from telemetry.core import util
 from telemetry.unittest import tab_test_case
 
-unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                 '..', '..', '..', 'unittest_data')
 
 class InspectorPageTest(tab_test_case.TabTestCase):
   def __init__(self, *args):
@@ -14,7 +12,7 @@
 
   def setUp(self):
     super(InspectorPageTest, self).setUp()
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
 
   def testPageNavigateToNormalUrl(self):
     self._tab.Navigate(self._browser.http_server.UrlOf('blank.html'))
diff --git a/tools/telemetry/telemetry/core/chrome/inspector_timeline_unittest.py b/tools/telemetry/telemetry/core/chrome/inspector_timeline_unittest.py
index 4b7a707..67c6137 100644
--- a/tools/telemetry/telemetry/core/chrome/inspector_timeline_unittest.py
+++ b/tools/telemetry/telemetry/core/chrome/inspector_timeline_unittest.py
@@ -1,7 +1,6 @@
 # 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
 
 from telemetry.core import util
 from telemetry.core.chrome import inspector_timeline
@@ -9,9 +8,7 @@
 
 class InspectorTimelineTabTest(tab_test_case.TabTestCase):
   def _StartServer(self):
-    base_dir = os.path.dirname(__file__)
-    self._browser.SetHTTPServerDirectories(os.path.join(base_dir, '..', '..',
-        'unittest_data'))
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
 
   def _WaitForAnimationFrame(self):
     def _IsDone():
diff --git a/tools/telemetry/telemetry/core/chrome/png_bitmap.py b/tools/telemetry/telemetry/core/chrome/png_bitmap.py
index fc8d89e..dede6fb 100644
--- a/tools/telemetry/telemetry/core/chrome/png_bitmap.py
+++ b/tools/telemetry/telemetry/core/chrome/png_bitmap.py
@@ -1,18 +1,13 @@
 # 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 sys
-import os
 import base64
 
-def _EnsurePngIsInPath():
-  png_path = os.path.join(os.path.dirname(__file__),
-                          '..', '..', '..', 'third_party', 'png')
-  if png_path not in sys.path:
-    sys.path.append(png_path)
+from telemetry.core import util
 
-_EnsurePngIsInPath()
-import png # pylint: disable=F0401
+util.AddDirToPythonPath(util.GetTelemetryDir(), 'third_party', 'png')
+import png  # pylint: disable=F0401
+
 
 class PngColor(object):
   """Encapsulates an RGB color retreived from a PngBitmap"""
@@ -39,6 +34,7 @@
   def AssertIsRGBA(self, r, g, b, a, tolerance=0):
     assert self.IsEqual(PngColor(r, g, b, a), tolerance)
 
+
 class PngBitmap(object):
   """Utilities for parsing and inspecting inspecting a PNG"""
 
diff --git a/tools/telemetry/telemetry/core/chrome/system_info_backend.py b/tools/telemetry/telemetry/core/chrome/system_info_backend.py
new file mode 100644
index 0000000..9ff12e1
--- /dev/null
+++ b/tools/telemetry/telemetry/core/chrome/system_info_backend.py
@@ -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.
+
+from telemetry.core import camel_case
+from telemetry.core import system_info
+from telemetry.core.chrome import websocket_browser_connection as browser_conn
+
+
+class SystemInfoBackend(object):
+  def __init__(self, devtools_port):
+    self._conn = browser_conn.WebSocketBrowserConnection(devtools_port)
+
+  def Close(self):
+    self._conn.Close()
+
+  def GetSystemInfo(self, timeout=10):
+    req = {'method': 'SystemInfo.getInfo'}
+    res = self._conn.SyncRequest(req, timeout)
+    if 'error' in res:
+      return None
+    return system_info.SystemInfo.FromDict(
+        camel_case.ToUnderscore(res['result']))
diff --git a/tools/telemetry/telemetry/core/chrome/tracing_backend.py b/tools/telemetry/telemetry/core/chrome/tracing_backend.py
index 471ff22..0c02d2e 100644
--- a/tools/telemetry/telemetry/core/chrome/tracing_backend.py
+++ b/tools/telemetry/telemetry/core/chrome/tracing_backend.py
@@ -9,9 +9,9 @@
 import threading
 
 
-from telemetry.core import util
 from telemetry.core.chrome import trace_result
 from telemetry.core.chrome import websocket
+from telemetry.core.chrome import websocket_browser_connection as browser_conn
 from telemetry.core.timeline import model
 
 
@@ -67,10 +67,7 @@
 
 class TracingBackend(object):
   def __init__(self, devtools_port):
-    debugger_url = 'ws://localhost:%i/devtools/browser' % devtools_port
-    self._socket = websocket.create_connection(debugger_url)
-    self._next_request_id = 0
-    self._cur_socket_timeout = 0
+    self._conn = browser_conn.WebSocketBrowserConnection(devtools_port)
     self._thread = None
     self._tracing_data = []
 
@@ -79,7 +76,7 @@
     req = {'method': 'Tracing.start'}
     if custom_categories:
       req['params'] = {'categories': custom_categories}
-    self._SyncRequest(req, timeout)
+    self._conn.SendRequest(req, timeout)
     # Tracing.start will send asynchronous notifications containing trace
     # data, until Tracing.end is called.
     self._thread = threading.Thread(target=self._TracingReader)
@@ -87,7 +84,7 @@
 
   def EndTracing(self):
     req = {'method': 'Tracing.end'}
-    self._SyncRequest(req)
+    self._conn.SendRequest(req)
     self._thread.join()
     self._thread = None
 
@@ -100,15 +97,10 @@
     self._tracing_data = []
     return trace_result.TraceResult(result_impl)
 
-  def Close(self):
-    if self._socket:
-      self._socket.close()
-      self._socket = None
-
   def _TracingReader(self):
-    while self._socket:
+    while self._conn.socket:
       try:
-        data = self._socket.recv()
+        data = self._conn.socket.recv()
         if not data:
           break
         res = json.loads(data)
@@ -126,36 +118,15 @@
       except (socket.error, websocket.WebSocketException):
         logging.warning('Timeout waiting for tracing response, unusual.')
 
-  def _SyncRequest(self, req, timeout=10):
-    self._SetTimeout(timeout)
-    req['id'] = self._next_request_id
-    self._next_request_id += 1
-    data = json.dumps(req)
-    logging.debug('will send [%s]', data)
-    self._socket.send(data)
-
-  def _SetTimeout(self, timeout):
-    if self._cur_socket_timeout != timeout:
-      self._socket.settimeout(timeout)
-      self._cur_socket_timeout = timeout
+  def Close(self):
+    self._conn.Close()
 
   def _CheckNotificationSupported(self):
     """Ensures we're running against a compatible version of chrome."""
     req = {'method': 'Tracing.hasCompleted'}
-    self._SyncRequest(req)
-    while True:
-      try:
-        data = self._socket.recv()
-      except (socket.error, websocket.WebSocketException):
-        raise util.TimeoutException(
-            'Timed out waiting for reply. This is unusual.')
-      logging.debug('got [%s]', data)
-      res = json.loads(data)
-      if res['id'] != req['id']:
-        logging.debug('Dropped reply: %s', json.dumps(res))
-        continue
-      if res.get('response'):
-        raise TracingUnsupportedException(
-            'Tracing not supported for this browser')
-      elif 'error' in res:
-        return
+    res = self._conn.SyncRequest(req)
+    if res.get('response'):
+      raise TracingUnsupportedException(
+          'Tracing not supported for this browser')
+    elif 'error' in res:
+      return
diff --git a/tools/telemetry/telemetry/core/chrome/tracing_backend_unittest.py b/tools/telemetry/telemetry/core/chrome/tracing_backend_unittest.py
index 69b56e9..f383078 100644
--- a/tools/telemetry/telemetry/core/chrome/tracing_backend_unittest.py
+++ b/tools/telemetry/telemetry/core/chrome/tracing_backend_unittest.py
@@ -5,7 +5,6 @@
 import cStringIO
 import json
 import logging
-import os
 import unittest
 
 from telemetry.core import util
@@ -15,9 +14,7 @@
 
 class TracingBackendTest(tab_test_case.TabTestCase):
   def _StartServer(self):
-    base_dir = os.path.dirname(__file__)
-    self._browser.SetHTTPServerDirectories(
-        os.path.join(base_dir, '..', '..', '..', 'unittest_data'))
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
 
   def _WaitForAnimationFrame(self):
     def _IsDone():
diff --git a/tools/telemetry/telemetry/core/chrome/websocket.py b/tools/telemetry/telemetry/core/chrome/websocket.py
index c4a7f40..55f3fc0 100644
--- a/tools/telemetry/telemetry/core/chrome/websocket.py
+++ b/tools/telemetry/telemetry/core/chrome/websocket.py
@@ -2,18 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 from __future__ import absolute_import
-import os
-import sys
 
-def __init__():
-  ws_path = os.path.join(os.path.dirname(__file__),
-                         '..', '..', '..', 'third_party', 'websocket-client')
-  ws_path = os.path.abspath(ws_path)
-  assert os.path.exists(os.path.join(ws_path, 'websocket.py'))
-  if ws_path not in sys.path:
-    sys.path.append(ws_path)
+from telemetry.core import util
 
-__init__()
-
-from websocket import create_connection # pylint: disable=W0611
-from websocket import WebSocketException # pylint: disable=W0611
+util.AddDirToPythonPath(
+    util.GetTelemetryDir(), 'third_party', 'websocket-client')
+from websocket import create_connection  # pylint: disable=W0611
+from websocket import WebSocketException  # pylint: disable=W0611
diff --git a/tools/telemetry/telemetry/core/chrome/websocket_browser_connection.py b/tools/telemetry/telemetry/core/chrome/websocket_browser_connection.py
new file mode 100644
index 0000000..efaba9c
--- /dev/null
+++ b/tools/telemetry/telemetry/core/chrome/websocket_browser_connection.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.
+
+import json
+import logging
+import socket
+
+from telemetry.core import util
+from telemetry.core.chrome import websocket
+
+class WebSocketBrowserConnection(object):
+  """Represents a websocket connection to the browser for backends
+     which use one."""
+
+  def __init__(self, devtools_port):
+    debugger_url = 'ws://localhost:%i/devtools/browser' % devtools_port
+    self._socket = websocket.create_connection(debugger_url)
+    self._next_request_id = 0
+    self._cur_socket_timeout = 0
+
+  def Close(self):
+    if self._socket:
+      self._socket.close()
+      self._socket = None
+
+  def SendRequest(self, req, timeout=10):
+    self._SetTimeout(timeout)
+    req['id'] = self._next_request_id
+    self._next_request_id += 1
+    data = json.dumps(req)
+    logging.debug('will send [%s]', data)
+    self._socket.send(data)
+
+  def SyncRequest(self, req, timeout=10):
+    self.SendRequest(req, timeout)
+    while True:
+      try:
+        data = self._socket.recv()
+      except (socket.error, websocket.WebSocketException):
+        raise util.TimeoutException(
+            "Timed out waiting for reply. This is unusual.")
+      res = json.loads(data)
+      logging.debug('got [%s]', data)
+      if res['id'] != req['id']:
+        logging.debug('Dropped reply: %s', json.dumps(res))
+        continue
+      return res
+
+  @property
+  def socket(self):
+    """Returns the socket for raw access. Please be sure you know what
+       you are doing."""
+    return self._socket
+
+  def _SetTimeout(self, timeout):
+    if self._cur_socket_timeout != timeout:
+      self._socket.settimeout(timeout)
+      self._cur_socket_timeout = timeout
diff --git a/tools/telemetry/telemetry/core/discover.py b/tools/telemetry/telemetry/core/discover.py
index ece12f9..10cc731 100644
--- a/tools/telemetry/telemetry/core/discover.py
+++ b/tools/telemetry/telemetry/core/discover.py
@@ -1,11 +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.
+
 import fnmatch
 import inspect
 import os
 import re
 
+from telemetry.core import camel_case
+
 
 def DiscoverModules(start_dir, top_level_dir, pattern='*'):
   """Discover all modules in |start_dir| which match |pattern|.
@@ -65,7 +68,7 @@
       if (inspect.isclass(obj) and obj is not base_class and
           issubclass(obj, base_class)):
         if index_by_class_name:
-          key_name = re.sub('(?!^)([A-Z]+)', r'_\1', obj.__name__).lower()
+          key_name = camel_case.ToUnderscore(obj.__name__)
         else:
           key_name = module.__name__.split('.')[-1]
         classes[key_name] = obj
diff --git a/tools/telemetry/telemetry/core/discover_unittest.py b/tools/telemetry/telemetry/core/discover_unittest.py
index 49d046d..dda14a3 100644
--- a/tools/telemetry/telemetry/core/discover_unittest.py
+++ b/tools/telemetry/telemetry/core/discover_unittest.py
@@ -5,16 +5,14 @@
 import unittest
 
 from telemetry.core import discover
+from telemetry.core import util
 
 class DiscoverTest(unittest.TestCase):
   def testDiscoverClasses(self):
-    telemetry_dir = os.path.join(
-        os.path.dirname(discover.__file__), '..', '..')
-    telemetry_dir = os.path.abspath(telemetry_dir)
-    top_level_dir = os.path.join(telemetry_dir, 'unittest_data')
-    start_dir = os.path.join(top_level_dir, 'discoverable_classes')
+    base_dir = util.GetUnittestDataDir()
+    start_dir = os.path.join(base_dir, 'discoverable_classes')
     base_class = Exception
-    classes = discover.DiscoverClasses(start_dir, top_level_dir, base_class)
+    classes = discover.DiscoverClasses(start_dir, base_dir, base_class)
     self.assertTrue(len(classes) > 0)
 
     found_dummy_exception = False
@@ -23,4 +21,4 @@
         found_dummy_exception = True
       self.assertTrue(issubclass(c, Exception))
 
-    self.assertTrue(found_dummy_exception)
\ No newline at end of file
+    self.assertTrue(found_dummy_exception)
diff --git a/tools/telemetry/telemetry/core/extension_unittest.py b/tools/telemetry/telemetry/core/extension_unittest.py
index eb3b596..986139e 100644
--- a/tools/telemetry/telemetry/core/extension_unittest.py
+++ b/tools/telemetry/telemetry/core/extension_unittest.py
@@ -9,14 +9,13 @@
 
 from telemetry.core import browser_finder
 from telemetry.core import extension_to_load
+from telemetry.core import util
 from telemetry.core.chrome import extension_dict_backend
 from telemetry.unittest import options_for_unittests
 
 class ExtensionTest(unittest.TestCase):
   def setUp(self):
-    extension_path = os.path.join(os.path.dirname(__file__),
-        '..', '..', 'unittest_data', 'simple_extension')
-
+    extension_path = os.path.join(util.GetUnittestDataDir(), 'simple_extension')
     options = options_for_unittests.GetCopy()
     load_extension = extension_to_load.ExtensionToLoad(
         extension_path, options.browser_type)
@@ -60,8 +59,7 @@
 class NonExistentExtensionTest(unittest.TestCase):
   def testNonExistentExtensionPath(self):
     """Test that a non-existent extension path will raise an exception."""
-    extension_path = os.path.join(os.path.dirname(__file__),
-        '..', '..', 'unittest_data', 'foo')
+    extension_path = os.path.join(util.GetUnittestDataDir(), 'foo')
     options = options_for_unittests.GetCopy()
     self.assertRaises(extension_to_load.ExtensionPathNonExistentException,
                       lambda: extension_to_load.ExtensionToLoad(
@@ -69,8 +67,7 @@
 
   def testExtensionNotLoaded(self):
     """Querying an extension that was not loaded will return None"""
-    extension_path = os.path.join(os.path.dirname(__file__),
-        '..', '..', 'unittest_data', 'simple_extension')
+    extension_path = os.path.join(util.GetUnittestDataDir(), 'simple_extension')
     options = options_for_unittests.GetCopy()
     load_extension = extension_to_load.ExtensionToLoad(
         extension_path, options.browser_type)
@@ -87,8 +84,8 @@
     number of temporary directories to load as extensions"""
     self._extension_dirs = [tempfile.mkdtemp()
                             for i in range(3)] # pylint: disable=W0612
-    src_extension_dir = os.path.abspath(os.path.join(os.path.dirname(__file__),
-        '..', '..', 'unittest_data', 'simple_extension'))
+    src_extension_dir = os.path.join(
+        util.GetUnittestDataDir(), 'simple_extension')
     manifest_path = os.path.join(src_extension_dir, 'manifest.json')
     script_path = os.path.join(src_extension_dir, 'background.js')
     for d in self._extension_dirs:
@@ -131,8 +128,8 @@
 
 class ComponentExtensionTest(unittest.TestCase):
   def testComponentExtensionBasic(self):
-    extension_path = os.path.join(os.path.dirname(__file__),
-        '..', '..', 'unittest_data', 'component_extension')
+    extension_path = os.path.join(
+        util.GetUnittestDataDir(), 'component_extension')
     options = options_for_unittests.GetCopy()
     load_extension = extension_to_load.ExtensionToLoad(
         extension_path, options.browser_type, is_component=True)
@@ -152,8 +149,7 @@
 
   def testComponentExtensionNoPublicKey(self):
     # simple_extension does not have a public key.
-    extension_path = os.path.join(os.path.dirname(__file__),
-        '..', '..', 'unittest_data', 'simple_extension')
+    extension_path = os.path.join(util.GetUnittestDataDir(), 'simple_extension')
     options = options_for_unittests.GetCopy()
     self.assertRaises(extension_to_load.MissingPublicKeyException,
                       lambda: extension_to_load.ExtensionToLoad(
diff --git a/tools/telemetry/telemetry/core/gpu_device.py b/tools/telemetry/telemetry/core/gpu_device.py
new file mode 100644
index 0000000..f4da64b
--- /dev/null
+++ b/tools/telemetry/telemetry/core/gpu_device.py
@@ -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.
+
+class GPUDevice(object):
+  """Provides information about an individual GPU device.
+
+     On platforms which support them, the vendor_id and device_id are
+     PCI IDs. On other platforms, the vendor_string and device_string
+     are platform-dependent strings.
+  """
+
+  def __init__(self, vendor_id, device_id, vendor_string, device_string):
+    self._vendor_id = vendor_id
+    self._device_id = device_id
+    self._vendor_string = vendor_string
+    self._device_string = device_string
+
+  @classmethod
+  def FromDict(cls, attrs):
+    """Constructs a GPUDevice from a dictionary. Requires the
+       following attributes to be present in the dictionary:
+
+         vendor_id
+         device_id
+         vendor_string
+         device_string
+
+       Raises an exception if any attributes are missing.
+    """
+    return cls(attrs["vendor_id"], attrs["device_id"],
+               attrs["vendor_string"], attrs["device_string"])
+
+  @property
+  def vendor_id(self):
+    """The GPU vendor's PCI ID as a number, or 0 if not available.
+
+       Most desktop machines supply this information rather than the
+       vendor and device strings."""
+    return self._vendor_id
+
+  @property
+  def device_id(self):
+    """The GPU device's PCI ID as a number, or 0 if not available.
+
+       Most desktop machines supply this information rather than the
+       vendor and device strings."""
+    return self._device_id
+
+  @property
+  def vendor_string(self):
+    """The GPU vendor's name as a string, or the empty string if not
+       available.
+
+       Most mobile devices supply this information rather than the PCI
+       IDs."""
+    return self._vendor_string
+
+  @property
+  def device_string(self):
+    """The GPU device's name as a string, or the empty string if not
+       available.
+
+       Most mobile devices supply this information rather than the PCI
+       IDs."""
+    return self._device_string
diff --git a/tools/telemetry/telemetry/core/gpu_device_unittest.py b/tools/telemetry/telemetry/core/gpu_device_unittest.py
new file mode 100644
index 0000000..c3a3b91
--- /dev/null
+++ b/tools/telemetry/telemetry/core/gpu_device_unittest.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.
+import unittest
+
+from telemetry.core import gpu_device
+
+class TestGPUDevice(unittest.TestCase):
+  def testConstruction(self):
+    device = gpu_device.GPUDevice(1000, 2000, 'test_vendor', 'test_device')
+    self.assertEquals(device.vendor_id, 1000)
+    self.assertEquals(device.device_id, 2000)
+    self.assertEquals(device.vendor_string, 'test_vendor')
+    self.assertEquals(device.device_string, 'test_device')
+
+  def testFromDict(self):
+    dictionary = { 'vendor_id': 3000,
+                   'device_id': 4000,
+                   'vendor_string': 'test_vendor_2',
+                   'device_string': 'test_device_2' }
+    device = gpu_device.GPUDevice.FromDict(dictionary)
+    self.assertEquals(device.vendor_id, 3000)
+    self.assertEquals(device.device_id, 4000)
+    self.assertEquals(device.vendor_string, 'test_vendor_2')
+    self.assertEquals(device.device_string, 'test_device_2')
+
+  def testMissingAttrsFromDict(self):
+    data = {
+      'vendor_id': 1,
+      'device_id': 2,
+      'vendor_string': 'a',
+      'device_string': 'b'
+    }
+
+    for k in data:
+      data_copy = data.copy()
+      del data_copy[k]
+      try:
+        gpu_device.GPUDevice.FromDict(data_copy)
+        self.fail('Should raise exception if attribute "%s" is missing' % k)
+      except AssertionError:
+        raise
+      except:
+        pass
diff --git a/tools/telemetry/telemetry/core/gpu_info.py b/tools/telemetry/telemetry/core/gpu_info.py
new file mode 100644
index 0000000..86f9803
--- /dev/null
+++ b/tools/telemetry/telemetry/core/gpu_info.py
@@ -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.
+from telemetry.core import gpu_device
+
+class GPUInfo(object):
+  """Provides information about the GPUs on the system."""
+
+  def __init__(self, device_array, aux_attributes):
+    if device_array == None:
+      raise Exception("Missing required 'devices' property")
+    if len(device_array) == 0:
+      raise Exception("Missing at least one GPU in device_array")
+
+    self._devices = [gpu_device.GPUDevice.FromDict(d) for d in device_array]
+    self._aux_attributes = aux_attributes
+
+  @classmethod
+  def FromDict(cls, attrs):
+    """Constructs a GPUInfo from a dictionary of attributes.
+       Attributes currently required to be present in the dictionary:
+
+         devices (array of dictionaries, each of which contains
+             GPUDevice's required attributes)
+    """
+    return cls(attrs["devices"], attrs.get("aux_attributes"))
+
+  @property
+  def devices(self):
+    "An array of GPUDevices. Element 0 is the primary GPU on the system."
+    return self._devices
+
+  @property
+  def aux_attributes(self):
+    """Returns a dictionary of auxiliary, optional, attributes. On the
+       Chrome browser, for example, this dictionary contains:
+
+         optimus (boolean)
+         amd_switchable (boolean)
+         lenovo_dcute (boolean)
+         driver_vendor (string)
+         driver_version (string)
+         driver_date (string)
+         gl_version_string (string)
+         gl_vendor (string)
+         gl_renderer (string)
+         gl_extensions (string)
+         display_link_version (string)
+    """
+    return self._aux_attributes
diff --git a/tools/telemetry/telemetry/core/gpu_info_unittest.py b/tools/telemetry/telemetry/core/gpu_info_unittest.py
new file mode 100644
index 0000000..adc9e2b
--- /dev/null
+++ b/tools/telemetry/telemetry/core/gpu_info_unittest.py
@@ -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.
+import unittest
+
+from telemetry.core import gpu_info
+from telemetry.core import gpu_device
+
+class TestGPUInfo(unittest.TestCase):
+  def testConstruction(self):
+    data = {
+      'devices': [
+        { 'vendor_id': 1000, 'device_id': 2000,
+          'vendor_string': 'a', 'device_string': 'b' },
+        { 'vendor_id': 3000, 'device_id': 4000,
+          'vendor_string': 'k', 'device_string': 'l' }
+      ],
+      'aux_attributes': {
+        'optimus': False,
+        'amd_switchable': False,
+        'lenovo_dcute': False,
+        'driver_vendor': 'c',
+        'driver_version': 'd',
+        'driver_date': 'e',
+        'gl_version_string': 'g',
+        'gl_vendor': 'h',
+        'gl_renderer': 'i',
+        'gl_extensions': 'j',
+      }
+    }
+    info = gpu_info.GPUInfo.FromDict(data)
+    self.assertTrue(len(info.devices) == 2)
+    self.assertTrue(isinstance(info.devices[0], gpu_device.GPUDevice))
+    self.assertEquals(info.devices[0].vendor_id, 1000)
+    self.assertEquals(info.devices[0].device_id, 2000)
+    self.assertEquals(info.devices[0].vendor_string, 'a')
+    self.assertEquals(info.devices[0].device_string, 'b')
+    self.assertTrue(isinstance(info.devices[1], gpu_device.GPUDevice))
+    self.assertEquals(info.devices[1].vendor_id, 3000)
+    self.assertEquals(info.devices[1].device_id, 4000)
+    self.assertEquals(info.devices[1].vendor_string, 'k')
+    self.assertEquals(info.devices[1].device_string, 'l')
+    self.assertEquals(info.aux_attributes['optimus'], False)
+    self.assertEquals(info.aux_attributes['amd_switchable'], False)
+    self.assertEquals(info.aux_attributes['lenovo_dcute'], False)
+    self.assertEquals(info.aux_attributes['driver_vendor'], 'c')
+    self.assertEquals(info.aux_attributes['driver_version'], 'd')
+    self.assertEquals(info.aux_attributes['driver_date'], 'e')
+    self.assertEquals(info.aux_attributes['gl_version_string'], 'g')
+    self.assertEquals(info.aux_attributes['gl_vendor'], 'h')
+    self.assertEquals(info.aux_attributes['gl_renderer'], 'i')
+    self.assertEquals(info.aux_attributes['gl_extensions'], 'j')
+
+  def testMissingAttrsFromDict(self):
+    data = {
+      'devices': [{ 'vendor_id': 1000, 'device_id': 2000,
+                    'vendor_string': 'a', 'device_string': 'b' }]
+    }
+
+    for k in data:
+      data_copy = data.copy()
+      del data_copy[k]
+      try:
+        gpu_info.GPUInfo.FromDict(data_copy)
+        self.fail('Should raise exception if attribute "%s" is missing' % k)
+      except AssertionError:
+        raise
+      except:
+        pass
+
+  def testMissingDevices(self):
+    data = {
+      'devices': []
+    }
+
+    try:
+      gpu_info.GPUInfo.FromDict(data)
+      self.fail('Should raise exception if devices array is empty')
+    except AssertionError:
+      raise
+    except:
+      pass
diff --git a/tools/telemetry/telemetry/core/platform/android_platform_backend.py b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
index a879a7f..c399827 100644
--- a/tools/telemetry/telemetry/core/platform/android_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
@@ -3,23 +3,18 @@
 # found in the LICENSE file.
 
 import logging
-import os
-import sys
 
 from telemetry.core import platform
+from telemetry.core import util
 from telemetry.core.platform import platform_backend
 
 # Get build/android scripts into our path.
-sys.path.append(
-    os.path.abspath(
-        os.path.join(os.path.dirname(__file__),
-                     '../../../build/android')))
-
+util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
 from pylib import perf_tests_helper  # pylint: disable=F0401
 from pylib import thermal_throttle  # pylint: disable=F0401
 
 try:
-  from pylib import surface_stats_collector # pylint: disable=F0401
+  from pylib import surface_stats_collector  # pylint: disable=F0401
 except Exception:
   surface_stats_collector = None
 
diff --git a/tools/telemetry/telemetry/core/platform/cros_platform_backend.py b/tools/telemetry/telemetry/core/platform/cros_platform_backend.py
index 3c0a25c..02f6a71 100644
--- a/tools/telemetry/telemetry/core/platform/cros_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/cros_platform_backend.py
@@ -53,6 +53,18 @@
   def GetOSName(self):
     return 'chromeos'
 
+  def GetChildPids(self, pid):
+    """Returns a list of child pids of |pid|."""
+    all_process_info = self._cri.ListProcesses()
+    processes = []
+    for pid, _, ppid, state in all_process_info:
+      processes.append((pid, ppid, state))
+    return proc_util.GetChildPids(processes, pid)
+
+  def GetCommandLine(self, pid):
+    command = self._GetPsOutput(['command'], pid)
+    return command[0] if command else None
+
   def CanFlushIndividualFilesFromSystemCache(self):
     return True
 
diff --git a/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py b/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
index b71deab..e2bceaa 100644
--- a/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/desktop_platform_backend.py
@@ -17,26 +17,10 @@
   def GetFlushUtilityName(self):
     return NotImplementedError()
 
-  def _FindNewestFlushUtility(self):
-    flush_command = None
-    flush_command_mtime = 0
-
-    chrome_root = util.GetChromiumSrcDir()
-    for build_dir, build_type in util.GetBuildDirectories():
-      candidate = os.path.join(chrome_root, build_dir, build_type,
-                               self.GetFlushUtilityName())
-      if os.access(candidate, os.X_OK):
-        candidate_mtime = os.stat(candidate).st_mtime
-        if candidate_mtime > flush_command_mtime:
-          flush_command = candidate
-          flush_command_mtime = candidate_mtime
-
-    return flush_command
-
   def FlushSystemCacheForDirectory(self, directory, ignoring=None):
     assert directory and os.path.exists(directory), \
         'Target directory %s must exist' % directory
-    flush_command = self._FindNewestFlushUtility()
+    flush_command = util.FindSupportBinary(self.GetFlushUtilityName())
     assert flush_command, \
         'You must build %s first' % self.GetFlushUtilityName()
 
diff --git a/tools/telemetry/telemetry/core/platform/posix_platform_backend.py b/tools/telemetry/telemetry/core/platform/posix_platform_backend.py
index e3c60ac..fa20b54 100644
--- a/tools/telemetry/telemetry/core/platform/posix_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/posix_platform_backend.py
@@ -4,9 +4,8 @@
 
 import subprocess
 
-from collections import defaultdict
-
 from telemetry.core.platform import desktop_platform_backend
+from telemetry.core.platform import proc_util
 
 
 class PosixPlatformBackend(desktop_platform_backend.DesktopPlatformBackend):
@@ -38,23 +37,11 @@
 
   def GetChildPids(self, pid):
     """Returns a list of child pids of |pid|."""
-    pid_ppid_state_list = self._GetPsOutput(['pid', 'ppid', 'state'])
-
-    child_dict = defaultdict(list)
-    for pid_ppid_state in pid_ppid_state_list:
-      curr_pid, curr_ppid, state = pid_ppid_state.split()
-      if 'Z' in state:
-        continue  # Ignore zombie processes
-      child_dict[int(curr_ppid)].append(int(curr_pid))
-    queue = [pid]
-    child_ids = []
-    while queue:
-      parent = queue.pop()
-      if parent in child_dict:
-        children = child_dict[parent]
-        queue.extend(children)
-        child_ids.extend(children)
-    return child_ids
+    ps_output = self._GetPsOutput(['pid', 'ppid', 'state'])
+    processes = []
+    for pid_ppid_state in ps_output:
+      processes.append(pid_ppid_state.split())
+    return proc_util.GetChildPids(processes, pid)
 
   def GetCommandLine(self, pid):
     command = self._GetPsOutput(['command'], pid)
diff --git a/tools/telemetry/telemetry/core/platform/proc_util.py b/tools/telemetry/telemetry/core/platform/proc_util.py
index 9be108f..656eb84 100644
--- a/tools/telemetry/telemetry/core/platform/proc_util.py
+++ b/tools/telemetry/telemetry/core/platform/proc_util.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 collections import defaultdict
+
 try:
   import resource  # pylint: disable=F0401
 except ImportError:
@@ -11,6 +13,7 @@
 def _ConvertKbToByte(value):
   return int(value.replace('kB','')) * 1024
 
+
 def _GetProcFileDict(contents):
   retval = {}
   for line in contents.splitlines():
@@ -18,6 +21,7 @@
     retval[key.strip()] = value.strip()
   return retval
 
+
 def GetSystemCommitCharge(meminfo_contents):
   meminfo = _GetProcFileDict(meminfo_contents)
   return (_ConvertKbToByte(meminfo['MemTotal'])
@@ -25,6 +29,7 @@
           - _ConvertKbToByte(meminfo['Buffers'])
           - _ConvertKbToByte(meminfo['Cached']))
 
+
 def GetMemoryStats(status_contents, stats):
   status = _GetProcFileDict(status_contents)
   if not status or not stats or 'Z' in status['State']:
@@ -34,9 +39,27 @@
           'WorkingSetSize': int(stats[23]) * resource.getpagesize(),
           'WorkingSetSizePeak': _ConvertKbToByte(status['VmHWM'])}
 
+
 def GetIOStats(io_contents):
   io = _GetProcFileDict(io_contents)
   return {'ReadOperationCount': int(io['syscr']),
           'WriteOperationCount': int(io['syscw']),
           'ReadTransferCount': int(io['rchar']),
           'WriteTransferCount': int(io['wchar'])}
+
+
+def GetChildPids(processes, pid):
+  child_dict = defaultdict(list)
+  for curr_pid, curr_ppid, state in processes:
+    if 'Z' in state:
+      continue  # Ignore zombie processes
+    child_dict[int(curr_ppid)].append(int(curr_pid))
+  queue = [pid]
+  child_ids = []
+  while queue:
+    parent = queue.pop()
+    if parent in child_dict:
+      children = child_dict[parent]
+      queue.extend(children)
+      child_ids.extend(children)
+  return child_ids
diff --git a/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py
index 4f25b1e..b5e5e2d 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/iprofiler_profiler.py
@@ -11,8 +11,7 @@
 from telemetry.core.platform import profiler
 
 # pexpect is not available on all platforms so use the third_party version.
-sys.path.append(os.path.join(
-    util.GetChromiumSrcDir(), 'third_party', 'pexpect'))
+util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'third_party', 'pexpect')
 try:
   import pexpect  # pylint: disable=F0401
 except ImportError:
diff --git a/tools/telemetry/telemetry/core/platform/profiler/monsoon_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/monsoon_profiler.py
new file mode 100644
index 0000000..1a000cb
--- /dev/null
+++ b/tools/telemetry/telemetry/core/platform/profiler/monsoon_profiler.py
@@ -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.
+
+import csv
+import multiprocessing
+import os
+import sys
+
+from telemetry.core import exceptions
+from telemetry.core import util
+from telemetry.core.platform import profiler
+
+sys.path.append(os.path.join(util.GetTelemetryDir(), 'third_party', 'internal'))
+try:
+  import monsoon  # pylint: disable=F0401
+except ImportError:
+  monsoon = None
+
+
+def _CollectData(output_path, is_collecting):
+  mon = monsoon.Monsoon(wait=False)
+  mon.SetMaxCurrent(2.0)
+  # Note: Telemetry requires the device to be connected by USB, but that
+  # puts it in charging mode. This increases the power consumption.
+  mon.SetUsbPassthrough(1)
+  # Nominal Li-ion voltage is 3.7V, but it puts out 4.2V at max capacity. Use
+  # 4.0V to simulate a "~80%" charged battery. Google "li-ion voltage curve".
+  # This is true only for a single cell. (Most smartphones, some tablets.)
+  mon.SetVoltage(4.0)
+
+  samples = []
+  try:
+    mon.StartDataCollection()
+    # Do one CollectData() to make the Monsoon set up, which takes about
+    # 0.3 seconds, and only signal that we've started after that.
+    mon.CollectData()
+    is_collecting.set()
+    while is_collecting.is_set():
+      samples += mon.CollectData()
+  finally:
+    mon.StopDataCollection()
+
+  # Add x-axis labels.
+  plot_data = [(i / 5000., sample) for i, sample in enumerate(samples)]
+
+  # Print data in csv.
+  with open(output_path, 'w') as output_file:
+    output_writer = csv.writer(output_file)
+    output_writer.writerows(plot_data)
+    output_file.flush()
+
+  print 'To view the Monsoon profile, run:'
+  print ('  echo "set datafile separator \',\'; plot \'%s\' with lines" | '
+      'gnuplot --persist' % output_path)
+
+
+class MonsoonProfiler(profiler.Profiler):
+  """Profiler that tracks current using Monsoon Power Monitor.
+
+  http://www.msoon.com/LabEquipment/PowerMonitor/
+  The Monsoon device measures current in amps at 5000 samples/second.
+  """
+  def __init__(self, browser_backend, platform_backend, output_path):
+    super(MonsoonProfiler, self).__init__(
+        browser_backend, platform_backend, output_path)
+    # We collect the data in a separate process, so we can continuously
+    # read the samples from the USB port while running the test.
+    self._is_collecting = multiprocessing.Event()
+    self._collector = multiprocessing.Process(
+        target=_CollectData, args=(output_path, self._is_collecting))
+    self._collector.start()
+    if not self._is_collecting.wait(timeout=0.5):
+      self._collector.terminate()
+      raise exceptions.ProfilingException('Failed to start data collection.')
+
+  @classmethod
+  def name(cls):
+    return 'monsoon'
+
+  @classmethod
+  def is_supported(cls, options):
+    if not monsoon:
+      return False
+    try:
+      monsoon.Monsoon(wait=False)
+    except IOError:
+      return False
+    else:
+      return True
+
+  def CollectProfile(self):
+    self._is_collecting.clear()
+    self._collector.join()
+    return [self._output_path]
diff --git a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler_unittest.py b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler_unittest.py
index 8ca407f..e2aa5a8 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler_unittest.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler_unittest.py
@@ -5,8 +5,10 @@
 import logging
 import unittest
 
+from telemetry.core import util
 from telemetry.core.platform.profiler import perf_profiler
 from telemetry.unittest import options_for_unittests
+from telemetry.unittest import simple_mock
 
 class TestPerfProfiler(unittest.TestCase):
   def testPerfProfiler(self):
@@ -15,17 +17,33 @@
       logging.warning('PerfProfiler is not supported. Skipping test')
       return
 
-    profile_file = os.path.join(os.path.dirname(__file__),
-                                'testdata', 'perf.profile')
-    self.assertEqual(perf_profiler.PerfProfiler.GetTopSamples(profile_file, 10),
-        { 'v8::internal::StaticMarkingVisitor::MarkMapContents': 63615201,
-          'v8::internal::RelocIterator::next': 38271931,
-          'v8::internal::LAllocator::MeetConstraintsBetween': 42913933,
-          'v8::internal::FlexibleBodyVisitor::Visit': 31909537,
-          'v8::internal::LiveRange::CreateAssignedOperand': 42913933,
-          'void v8::internal::RelocInfo::Visit': 96878864,
-          'WebCore::HTMLTokenizer::nextToken': 48240439,
-          'v8::internal::Scanner::ScanIdentifierOrKeyword': 46054550,
-          'sk_memset32_SSE2': 45121317,
-          'v8::internal::HeapObject::Size': 39786862
-          })
+    profile_file = os.path.join(
+        util.GetUnittestDataDir(), 'perf_report_output.txt')
+    perf_report_output = open(profile_file, 'r').read()
+
+    mock_popen = simple_mock.MockObject()
+    mock_popen.ExpectCall('communicate').WillReturn([perf_report_output])
+
+    mock_subprocess = simple_mock.MockObject()
+    mock_subprocess.ExpectCall(
+        'Popen').WithArgs(simple_mock.DONT_CARE).WillReturn(mock_popen)
+    setattr(mock_subprocess, 'PIPE', simple_mock.MockObject())
+
+    real_subprocess = perf_profiler.subprocess
+    perf_profiler.subprocess = mock_subprocess
+    try:
+      self.assertEqual(
+          perf_profiler.PerfProfiler.GetTopSamples(profile_file, 10),
+          { 'v8::internal::StaticMarkingVisitor::MarkMapContents': 63615201,
+            'v8::internal::RelocIterator::next': 38271931,
+            'v8::internal::LAllocator::MeetConstraintsBetween': 42913933,
+            'v8::internal::FlexibleBodyVisitor::Visit': 31909537,
+            'v8::internal::LiveRange::CreateAssignedOperand': 42913933,
+            'void v8::internal::RelocInfo::Visit': 96878864,
+            'WebCore::HTMLTokenizer::nextToken': 48240439,
+            'v8::internal::Scanner::ScanIdentifierOrKeyword': 46054550,
+            'sk_memset32_SSE2': 45121317,
+            'v8::internal::HeapObject::Size': 39786862
+            })
+    finally:
+      perf_profiler.subprocess = real_subprocess
diff --git a/tools/telemetry/telemetry/core/platform/profiler/strace_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/strace_profiler.py
new file mode 100644
index 0000000..186a8d0
--- /dev/null
+++ b/tools/telemetry/telemetry/core/platform/profiler/strace_profiler.py
@@ -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.
+
+import json
+import logging
+import re
+import signal
+import subprocess
+import sys
+import tempfile
+
+from telemetry.core.platform import profiler
+
+
+# Parses one line of strace output, for example:
+# 6052  1311456063.159722 read(8, "\1\0\0\0\0\0\0\0", 8) = 8 <0.000022>
+_STRACE_LINE_RE = re.compile(
+    '^(?P<tid>\d+)\s+'
+    '(?P<ts>\d+)'
+    '(?P<micro>.\d+)\s+'
+    '(?P<func>.*?)'
+    '[(](?P<args>.*?)[)]\s+=\s+'
+    '(?P<ret>.*?)\s+'
+    '<(?P<dur>[\d.]+)>$')
+
+_UNFINISHED_LINE_RE = re.compile(
+    '^(?P<tid>\d+)\s+'
+    '(?P<line>.*?)'
+    '<unfinished ...>$')
+
+_RESUMED_LINE_RE = re.compile(
+    '^(?P<tid>\d+)\s+'
+    '(?P<ts>\d+)'
+    '(?P<micro>.\d+)\s+'
+    '<[.][.][.]\s(?P<func>.*?)\sresumed>'
+    '(?P<line>.*?)$')
+
+_KILLED_LINE_RE = re.compile(
+    '^(?P<tid>\d+)\s+'
+    '(?P<ts>\d+)'
+    '(?P<micro>.\d+)\s+'
+    '[+][+][+] killed by SIGKILL [+][+][+]$')
+
+
+def _StraceToChromeTrace(pid, infile):
+  """Returns chrometrace json format for |infile| strace output."""
+  # Map of fd:file_name for open file descriptors. Useful for displaying
+  # file name instead of the descriptor number.
+  fd_map = {}
+
+  # Map of tid:interrupted_call for the interrupted call on each thread. It is
+  # possible to context switch during a system call. In this case we must
+  # match up the lines.
+  interrupted_call_map = {}
+
+  out = []
+  with open(infile, 'r') as f:
+    for line in f.readlines():
+      # Ignore kill lines for now.
+      m = _KILLED_LINE_RE.match(line)
+      if m:
+        continue
+
+      # If this line is interrupted, then remember it and continue.
+      m = _UNFINISHED_LINE_RE.match(line)
+      if m:
+        assert m.group('tid') not in interrupted_call_map
+        interrupted_call_map[m.group('tid')] = line
+        continue
+
+      # If this is a resume of a previous line, stitch it together.
+      interrupted = False
+      m = _RESUMED_LINE_RE.match(line)
+      if m:
+        interrupted = True
+        assert m.group('tid') in interrupted_call_map
+        line = interrupted_call_map[m.group('tid')].replace(
+            '<unfinished ...>', m.group('line'))
+        del interrupted_call_map[m.group('tid')]
+
+      # At this point we can do a normal match.
+      m = _STRACE_LINE_RE.match(line)
+      if not m:
+        if ('exit' not in line and
+            'Profiling timer expired' not in line and
+            '<unavailable>' not in line):
+          logging.warn('Failed to parse line: %s' % line)
+        continue
+
+      ts_begin = int(1000000 * (int(m.group('ts')) + float(m.group('micro'))))
+      ts_end = ts_begin + int(1000000 * float(m.group('dur')))
+      tid = int(m.group('tid'))
+      function_name = unicode(m.group('func'), errors='ignore')
+      function_args = unicode(m.group('args'), errors='ignore')
+      ret = unicode(m.group('ret'), errors='ignore')
+      cat = 'strace'
+
+      possible_fd_arg = None
+      first_arg = function_args.split(',')[0]
+      if first_arg and first_arg.strip().isdigit():
+        possible_fd_arg = first_arg.strip()
+
+      if function_name == 'open' and ret.isdigit():
+        # 1918  1311606151.649379 open("/foo/bar.so", O_RDONLY) = 7 <0.000088>
+        fd_map[ret] = first_arg
+
+      args = {
+          'args': function_args,
+          'ret': ret,
+          }
+      if interrupted:
+        args['interrupted'] = True
+      if possible_fd_arg and possible_fd_arg in fd_map:
+        args['fd%s' % first_arg] = fd_map[possible_fd_arg]
+
+      out.append({
+          'cat': cat,
+          'pid': pid,
+          'tid': tid,
+          'ts': ts_begin,
+          'ph': 'B',  # Begin
+          'name': function_name,
+          })
+      out.append({
+          'cat': cat,
+          'pid': pid,
+          'tid': tid,
+          'ts': ts_end,
+          'ph': 'E',  # End
+          'name': function_name,
+          'args': args,
+          })
+
+  return out
+
+
+def _GenerateTraceMetadata(model):
+  out = []
+  for process in model.processes:
+    out.append({
+        'name': 'process_name',
+        'ph': 'M',  # Metadata
+        'pid': process,
+        'args': {
+          'name': model.processes[process].name
+          }
+        })
+    for thread in model.processes[process].threads:
+      out.append({
+          'name': 'thread_name',
+          'ph': 'M',  # Metadata
+          'pid': process,
+          'tid': thread,
+          'args': {
+            'name': model.processes[process].threads[thread].name
+            }
+          })
+  return out
+
+
+class _SingleProcessStraceProfiler(object):
+  """An internal class for using perf for a given process."""
+  def __init__(self, pid, output_file, platform_backend):
+    self._pid = pid
+    self._platform_backend = platform_backend
+    self._output_file = output_file
+    self._tmp_output_file = tempfile.NamedTemporaryFile('w', 0)
+    self._proc = subprocess.Popen(
+        ['strace', '-ttt', '-f', '-T', '-p', str(pid), '-o', output_file],
+        stdout=self._tmp_output_file, stderr=subprocess.STDOUT)
+
+  def CollectProfile(self):
+    if ('renderer' in self._output_file and
+        not self._platform_backend.GetCommandLine(self._pid)):
+      logging.warning('Renderer was swapped out during profiling. '
+                      'To collect a full profile rerun with '
+                      '"--extra-browser-args=--single-process"')
+    self._proc.send_signal(signal.SIGINT)
+    exit_code = self._proc.wait()
+    try:
+      if exit_code:
+        raise Exception('strace failed with exit code %d. Output:\n%s' % (
+                        exit_code, self._GetStdOut()))
+    finally:
+      self._tmp_output_file.close()
+
+    return _StraceToChromeTrace(self._pid, self._output_file)
+
+  def _GetStdOut(self):
+    self._tmp_output_file.flush()
+    try:
+      with open(self._tmp_output_file.name) as f:
+        return f.read()
+    except IOError:
+      return ''
+
+
+class StraceProfiler(profiler.Profiler):
+
+  def __init__(self, browser_backend, platform_backend, output_path):
+    super(StraceProfiler, self).__init__(
+        browser_backend, platform_backend, output_path)
+    assert self._browser_backend.supports_tracing
+    self._browser_backend.StartTracing(None, 10)
+    process_output_file_map = self._GetProcessOutputFileMap()
+    self._process_profilers = []
+    self._output_file = output_path + '.json'
+    for pid, output_file in process_output_file_map.iteritems():
+      if 'zygote' in output_file:
+        continue
+      self._process_profilers.append(
+          _SingleProcessStraceProfiler(pid, output_file, platform_backend))
+
+  @classmethod
+  def name(cls):
+    return 'strace'
+
+  @classmethod
+  def is_supported(cls, options):
+    if sys.platform != 'linux2':
+      return False
+    # TODO(tonyg): This should be supported on android and cros.
+    if options and (options.browser_type.startswith('android')
+                    or options.browser_type.startswith('cros')):
+      return False
+    return True
+
+  @classmethod
+  def CustomizeBrowserOptions(cls, options):
+    options.AppendExtraBrowserArg('--no-sandbox')
+    options.AppendExtraBrowserArg('--allow-sandbox-debugging')
+
+  def CollectProfile(self):
+    print 'Processing trace...'
+
+    out_json = []
+
+    for single_process in self._process_profilers:
+      out_json.extend(single_process.CollectProfile())
+
+    self._browser_backend.StopTracing()
+    model = self._browser_backend.GetTraceResultAndReset().AsTimelineModel()
+    out_json.extend(_GenerateTraceMetadata(model))
+
+    with open(self._output_file, 'w') as f:
+      f.write(json.dumps(out_json, separators=(',', ':')))
+
+    print 'Trace saved as %s' % self._output_file
+    print 'To view, open in chrome://tracing'
+    return [self._output_file]
diff --git a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
index 9395149..95b6a8f 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
@@ -121,5 +121,9 @@
       return android_browser_finder.CanFindAvailableBrowsers()
     return options.browser_type.startswith('android')
 
+  @classmethod
+  def CustomizeBrowserOptions(cls, options):
+    options.AppendExtraBrowserArg('--no-sandbox')
+
   def CollectProfile(self):
     return self._platform_profiler.CollectProfile()
diff --git a/tools/telemetry/telemetry/core/platform/profiler/testdata/perf.profile b/tools/telemetry/telemetry/core/platform/profiler/testdata/perf.profile
deleted file mode 100644
index db955dd..0000000
--- a/tools/telemetry/telemetry/core/platform/profiler/testdata/perf.profile
+++ /dev/null
Binary files differ
diff --git a/tools/telemetry/telemetry/core/profile_types.py b/tools/telemetry/telemetry/core/profile_types.py
index 92a8a77..6ea4ee3 100644
--- a/tools/telemetry/telemetry/core/profile_types.py
+++ b/tools/telemetry/telemetry/core/profile_types.py
@@ -6,6 +6,7 @@
 
 from telemetry.core import discover
 from telemetry.core import profile_creator
+from telemetry.core import util
 
 BASE_PROFILE_TYPES = ['clean', 'default']
 
@@ -60,8 +61,8 @@
       profile_type in PROFILE_CREATORS):
     return None
 
-  path = os.path.abspath(os.path.join(os.path.dirname(__file__),
-      '..', '..', '..', '..', *PROFILE_TYPE_MAPPING[profile_type].split('/')))
+  path = os.path.join(
+    util.GetChromiumSrcDir(), *PROFILE_TYPE_MAPPING[profile_type].split('/'))
   assert os.path.exists(path)
   return path
 
diff --git a/tools/telemetry/telemetry/core/system_info.py b/tools/telemetry/telemetry/core/system_info.py
new file mode 100644
index 0000000..45a6f24
--- /dev/null
+++ b/tools/telemetry/telemetry/core/system_info.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 telemetry.core import gpu_info
+
+class SystemInfo(object):
+  """Provides low-level system information."""
+
+  def __init__(self, model_name, gpu_dict):
+    if (model_name == None) or (gpu_dict == None):
+      raise Exception("Missing model_name or gpu_dict argument")
+    self._model_name = model_name
+    self._gpu = gpu_info.GPUInfo.FromDict(gpu_dict)
+
+  @classmethod
+  def FromDict(cls, attrs):
+    """Constructs a SystemInfo from a dictionary of attributes.
+       Attributes currently required to be present in the dictionary:
+
+         model_name (string): a platform-dependent string
+           describing the model of machine, or the empty string if not
+           supported.
+         gpu (object containing GPUInfo's required attributes)
+    """
+    return cls(attrs["model_name"], attrs["gpu"])
+
+  @property
+  def model_name(self):
+    """A string describing the machine model.
+
+       This is a highly platform-dependent value and not currently
+       specified for any machine type aside from Macs. On Mac OS, this
+       is the model identifier, reformatted slightly; for example,
+       'MacBookPro 10.1'."""
+    return self._model_name
+
+  @property
+  def gpu(self):
+    """A GPUInfo object describing the graphics processor(s) on the system."""
+    return self._gpu
diff --git a/tools/telemetry/telemetry/core/system_info_unittest.py b/tools/telemetry/telemetry/core/system_info_unittest.py
new file mode 100644
index 0000000..3daf5dc
--- /dev/null
+++ b/tools/telemetry/telemetry/core/system_info_unittest.py
@@ -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.
+import unittest
+
+from telemetry.core import gpu_device
+from telemetry.core import gpu_info
+from telemetry.core import system_info
+
+class TestSystemInfo(unittest.TestCase):
+  def testConstruction(self):
+    data = {
+      'model_name': 'MacBookPro 10.1',
+      'gpu': {
+        'devices': [
+          { 'vendor_id': 1000, 'device_id': 2000,
+            'vendor_string': 'a', 'device_string': 'b' },
+        ]
+      }
+    }
+    info = system_info.SystemInfo.FromDict(data)
+    self.assertTrue(isinstance(info, system_info.SystemInfo))
+    self.assertTrue(isinstance(info.gpu, gpu_info.GPUInfo))
+    self.assertEquals(info.model_name, 'MacBookPro 10.1')
+    self.assertTrue(len(info.gpu.devices) == 1)
+    self.assertTrue(isinstance(info.gpu.devices[0], gpu_device.GPUDevice))
+    self.assertEquals(info.gpu.devices[0].vendor_id, 1000)
+    self.assertEquals(info.gpu.devices[0].device_id, 2000)
+    self.assertEquals(info.gpu.devices[0].vendor_string, 'a')
+    self.assertEquals(info.gpu.devices[0].device_string, 'b')
+
+  def testEmptyModelName(self):
+    data = {
+      'model_name': '',
+      'gpu': {
+        'devices': [
+          { 'vendor_id': 1000, 'device_id': 2000,
+            'vendor_string': 'a', 'device_string': 'b' },
+        ]
+      }
+    }
+    try:
+      info = system_info.SystemInfo.FromDict(data)
+      self.assertEquals(info.model_name, '')
+    except AssertionError:
+      raise
+    except:
+      self.fail('Should not raise exception for empty model_name string')
+
+  def testMissingAttrsFromDict(self):
+    data = {
+      'model_name': 'MacBookPro 10.1',
+      'devices': [{ 'vendor_id': 1000, 'device_id': 2000,
+                    'vendor_string': 'a', 'device_string': 'b' }]
+    }
+
+    for k in data:
+      data_copy = data.copy()
+      del data_copy[k]
+      try:
+        system_info.SystemInfo.FromDict(data_copy)
+        self.fail('Should raise exception if attribute "%s" is missing' % k)
+      except AssertionError:
+        raise
+      except:
+        pass
diff --git a/tools/telemetry/telemetry/core/tab_unittest.py b/tools/telemetry/telemetry/core/tab_unittest.py
index 156c935..7c356bf 100644
--- a/tools/telemetry/telemetry/core/tab_unittest.py
+++ b/tools/telemetry/telemetry/core/tab_unittest.py
@@ -1,8 +1,8 @@
 # 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 logging
-import os
 import time
 
 from telemetry.core import util
@@ -19,16 +19,12 @@
 
 class TabTest(tab_test_case.TabTestCase):
   def testNavigateAndWaitToForCompleteState(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
     self._tab.Navigate(self._browser.http_server.UrlOf('blank.html'))
     self._tab.WaitForDocumentReadyStateToBeComplete()
 
   def testNavigateAndWaitToForInteractiveState(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
     self._tab.Navigate(self._browser.http_server.UrlOf('blank.html'))
     self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
 
@@ -64,9 +60,7 @@
       logging.warning('Browser does not support screenshots, skipping test.')
       return
 
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
     self._tab.Navigate(
       self._browser.http_server.UrlOf('green_rect.html'))
     self._tab.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/telemetry/telemetry/core/temporary_http_server_unittest.py b/tools/telemetry/telemetry/core/temporary_http_server_unittest.py
index 984eb21..64ad67e 100644
--- a/tools/telemetry/telemetry/core/temporary_http_server_unittest.py
+++ b/tools/telemetry/telemetry/core/temporary_http_server_unittest.py
@@ -1,21 +1,20 @@
 # 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 unittest
 
 from telemetry.core import browser_finder
+from telemetry.core import util
 from telemetry.unittest import options_for_unittests
 
 class TemporaryHTTPServerTest(unittest.TestCase):
   def testBasicHosting(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', 'unittest_data')
     options = options_for_unittests.GetCopy()
     browser_to_create = browser_finder.FindBrowser(options)
     with browser_to_create.Create() as b:
       b.Start()
-      b.SetHTTPServerDirectories(unittest_data_dir)
+      b.SetHTTPServerDirectories(util.GetUnittestDataDir())
       t = b.tabs[0]
       t.Navigate(b.http_server.UrlOf('/blank.html'))
       t.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/telemetry/telemetry/core/util.py b/tools/telemetry/telemetry/core/util.py
index fddab1c..7988015 100644
--- a/tools/telemetry/telemetry/core/util.py
+++ b/tools/telemetry/telemetry/core/util.py
@@ -7,9 +7,11 @@
 import sys
 import time
 
+
 class TimeoutException(Exception):
   pass
 
+
 def GetBaseDir():
   main_module = sys.modules['__main__']
   if hasattr(main_module, '__file__'):
@@ -17,16 +19,26 @@
   else:
     return os.getcwd()
 
+
 def GetTelemetryDir():
   return os.path.normpath(os.path.join(
       __file__, os.pardir, os.pardir, os.pardir))
 
+
 def GetUnittestDataDir():
   return os.path.join(GetTelemetryDir(), 'unittest_data')
 
+
 def GetChromiumSrcDir():
   return os.path.normpath(os.path.join(GetTelemetryDir(), os.pardir, os.pardir))
 
+
+def AddDirToPythonPath(*path_parts):
+  path = os.path.abspath(os.path.join(*path_parts))
+  if os.path.isdir(path) and path not in sys.path:
+    sys.path.append(path)
+
+
 def WaitFor(condition,
             timeout, poll_interval=0.1,
             pass_time_left_to_func=False):
@@ -51,6 +63,7 @@
                              (timeout, condition_string))
     time.sleep(poll_interval)
 
+
 def FindElementAndPerformAction(tab, text, callback_code):
   """JavaScript snippet for finding an element with a given text on a page."""
   code = """
@@ -73,11 +86,13 @@
       })();"""
   return tab.EvaluateJavaScript(code)
 
+
 class PortPair(object):
   def __init__(self, local_port, remote_port):
     self.local_port = local_port
     self.remote_port = remote_port
 
+
 def GetAvailableLocalPort():
   tmp = socket.socket()
   tmp.bind(('', 0))
@@ -86,6 +101,7 @@
 
   return port
 
+
 def CloseConnections(tab):
   """Closes all TCP sockets held open by the browser."""
   try:
@@ -94,6 +110,7 @@
   except Exception:
     pass
 
+
 def GetBuildDirectories():
   """Yields all combination of Chromium build output directories."""
   build_dirs = ['build',
@@ -106,3 +123,20 @@
   for build_dir in build_dirs:
     for build_type in build_types:
       yield build_dir, build_type
+
+def FindSupportBinary(binary_name):
+  """Returns the path to the given binary name."""
+  # TODO(tonyg/dtu): This should support finding binaries in cloud storage.
+  command = None
+  command_mtime = 0
+
+  chrome_root = GetChromiumSrcDir()
+  for build_dir, build_type in GetBuildDirectories():
+    candidate = os.path.join(chrome_root, build_dir, build_type, binary_name)
+    if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
+      candidate_mtime = os.stat(candidate).st_mtime
+      if candidate_mtime > command_mtime:
+        command = candidate
+        command_mtime = candidate_mtime
+
+  return command
diff --git a/tools/telemetry/telemetry/core/wpr_server.py b/tools/telemetry/telemetry/core/wpr_server.py
index 88abc5b..d36874e 100644
--- a/tools/telemetry/telemetry/core/wpr_server.py
+++ b/tools/telemetry/telemetry/core/wpr_server.py
@@ -1,17 +1,12 @@
 # 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
 
 from telemetry.core import util
 
-# Get chrome/test/functional scripts into our path.
 # TODO(tonyg): Move webpagereplay.py to a common location.
-sys.path.append(
-    os.path.abspath(
-        os.path.join(os.path.dirname(__file__),
-                     '..', '..', '..', '..', 'chrome', 'test', 'functional')))
+util.AddDirToPythonPath(
+    util.GetChromiumSrcDir(), 'chrome', 'test', 'functional')
 import webpagereplay  # pylint: disable=F0401
 
 def GetChromeFlags(replay_host, http_port, https_port):
diff --git a/tools/telemetry/telemetry/page/actions/all_page_actions.py b/tools/telemetry/telemetry/page/actions/all_page_actions.py
index 115bb45..805fdea 100644
--- a/tools/telemetry/telemetry/page/actions/all_page_actions.py
+++ b/tools/telemetry/telemetry/page/actions/all_page_actions.py
@@ -4,12 +4,11 @@
 import os
 
 from telemetry.core import discover
+from telemetry.core import util
 from telemetry.page.actions import page_action
 
 _page_action_classes = discover.DiscoverClasses(
-    os.path.dirname(__file__),
-    os.path.join(os.path.dirname(__file__), '..', '..', '..'),
-    page_action.PageAction)
+    os.path.dirname(__file__), util.GetTelemetryDir(), page_action.PageAction)
 
 def GetAllClasses():
   return list(_page_action_classes.values())
diff --git a/tools/telemetry/telemetry/page/actions/click_element_unittest.py b/tools/telemetry/telemetry/page/actions/click_element_unittest.py
index 03eb87a..a32baec 100644
--- a/tools/telemetry/telemetry/page/actions/click_element_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/click_element_unittest.py
@@ -1,16 +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.
-import os
 
+from telemetry.core import util
 from telemetry.page.actions import click_element
 from telemetry.unittest import tab_test_case
 
 class ClickElementActionTest(tab_test_case.TabTestCase):
   def testClickWithSelectorWaitForNavigation(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
     self._tab.Navigate(
       self._browser.http_server.UrlOf('page_with_link.html'))
     self._tab.WaitForDocumentReadyStateToBeComplete()
@@ -27,9 +25,7 @@
         '/blank.html')
 
   def testClickWithTextWaitForRefChange(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
     self._tab.Navigate(
       self._browser.http_server.UrlOf('page_with_link.html'))
     self._tab.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/telemetry/telemetry/page/actions/javascript.py b/tools/telemetry/telemetry/page/actions/javascript.py
new file mode 100644
index 0000000..2edccef
--- /dev/null
+++ b/tools/telemetry/telemetry/page/actions/javascript.py
@@ -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.
+
+from telemetry.page.actions import page_action
+
+
+class JavascriptAction(page_action.PageAction):
+  def __init__(self, attributes=None):
+    super(JavascriptAction, self).__init__(attributes)
+
+  def RunAction(self, page, tab, previous_action):
+    assert hasattr(self, 'expression')
+    tab.ExecuteJavaScript(self.expression)
\ No newline at end of file
diff --git a/tools/telemetry/telemetry/page/actions/navigate.py b/tools/telemetry/telemetry/page/actions/navigate.py
new file mode 100644
index 0000000..73fb320
--- /dev/null
+++ b/tools/telemetry/telemetry/page/actions/navigate.py
@@ -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.
+
+from telemetry.page.actions import page_action
+
+
+class NavigateAction(page_action.PageAction):
+  def __init__(self, attributes=None):
+    super(NavigateAction, self).__init__(attributes)
+
+  def RunAction(self, page, tab, previous_action):
+    if page.is_file:
+      filename = page.serving_dirs_and_file[1]
+      target_side_url = tab.browser.http_server.UrlOf(filename)
+    else:
+      target_side_url = page.url
+
+    tab.Navigate(target_side_url, page.script_to_evaluate_on_commit)
+    tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
\ No newline at end of file
diff --git a/tools/telemetry/telemetry/page/actions/navigate_unittest.py b/tools/telemetry/telemetry/page/actions/navigate_unittest.py
new file mode 100644
index 0000000..d28ab47
--- /dev/null
+++ b/tools/telemetry/telemetry/page/actions/navigate_unittest.py
@@ -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.
+
+from telemetry.core import util
+from telemetry.page import page as page_module
+from telemetry.page.actions import navigate
+from telemetry.unittest import tab_test_case
+
+
+class NavigateActionTest(tab_test_case.TabTestCase):
+  def CreatePageFromUnittestDataDir(self, filename):
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
+    return page_module.Page(
+        self._browser.http_server.UrlOf(filename),
+        None  # In this test, we don't need a page set.
+    )
+
+  def testNavigateAction(self):
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
+
+    page = self.CreatePageFromUnittestDataDir('blank.html')
+    i = navigate.NavigateAction()
+    i.RunAction(page, self._tab, None)
+    self.assertEquals(
+        self._tab.EvaluateJavaScript('document.location.pathname;'),
+        '/blank.html')
diff --git a/tools/telemetry/telemetry/page/actions/play_unittest.py b/tools/telemetry/telemetry/page/actions/play_unittest.py
index b29f8f8..a20a6de 100644
--- a/tools/telemetry/telemetry/page/actions/play_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/play_unittest.py
@@ -58,7 +58,8 @@
     self.assertTrue(self._tab.EvaluateJavaScript(VIDEO_1_PLAYING_CHECK))
     self.assertTrue(self._tab.EvaluateJavaScript(AUDIO_1_PLAYING_CHECK))
 
-  def testPlayWaitForPlayTimeout(self):
+  # http://crbug.com/273887
+  def DISABLED_testPlayWaitForPlayTimeout(self):
     """Tests that wait_for_playing timeouts if video does not play."""
     data = {'selector': '#video_1',
             'wait_for_playing': True,
diff --git a/tools/telemetry/telemetry/page/actions/scroll.py b/tools/telemetry/telemetry/page/actions/scroll.py
index f7df4ad..d044060 100644
--- a/tools/telemetry/telemetry/page/actions/scroll.py
+++ b/tools/telemetry/telemetry/page/actions/scroll.py
@@ -11,9 +11,7 @@
     super(ScrollAction, self).__init__(attributes)
 
   def WillRunAction(self, page, tab):
-    with open(
-      os.path.join(os.path.dirname(__file__),
-                   'scroll.js')) as f:
+    with open(os.path.join(os.path.dirname(__file__), 'scroll.js')) as f:
       js = f.read()
       tab.ExecuteJavaScript(js)
 
diff --git a/tools/telemetry/telemetry/page/actions/scroll_unittest.py b/tools/telemetry/telemetry/page/actions/scroll_unittest.py
index 29b3da2..8c6be84 100644
--- a/tools/telemetry/telemetry/page/actions/scroll_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/scroll_unittest.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 import os
 
+from telemetry.core import util
 from telemetry.page import page as page_module
 from telemetry.page.actions import scroll
 from telemetry.unittest import tab_test_case
@@ -10,9 +11,7 @@
 class ScrollActionTest(tab_test_case.TabTestCase):
   def CreateAndNavigateToPageFromUnittestDataDir(
     self, filename, page_attributes):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
     page = page_module.Page(
       self._browser.http_server.UrlOf(filename),
       None, # In this test, we don't need a page set.
@@ -60,9 +59,7 @@
 
   def testBoundingClientRect(self):
     self.CreateAndNavigateToPageFromUnittestDataDir('blank.html', {})
-    with open(
-      os.path.join(os.path.dirname(__file__),
-                   'scroll.js')) as f:
+    with open(os.path.join(os.path.dirname(__file__), 'scroll.js')) as f:
       js = f.read()
       self._tab.ExecuteJavaScript(js)
 
diff --git a/tools/telemetry/telemetry/page/actions/seek_unittest.py b/tools/telemetry/telemetry/page/actions/seek_unittest.py
index 2f9d5a9..b14dda7 100644
--- a/tools/telemetry/telemetry/page/actions/seek_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/seek_unittest.py
@@ -54,7 +54,8 @@
     self.assertTrue(self._tab.EvaluateJavaScript(VIDEO_1_SEEKED_CHECK))
     self.assertTrue(self._tab.EvaluateJavaScript(AUDIO_1_SEEKED_CHECK))
 
-  def testSeekWaitForSeekTimeout(self):
+  # http://crbug.com/273887
+  def DISABLED_testSeekWaitForSeekTimeout(self):
     """Tests that wait_for_seeked timeouts if video does not seek."""
     data = {'selector': '#video_1',
             'wait_for_seeked': True,
diff --git a/tools/telemetry/telemetry/page/actions/wait.py b/tools/telemetry/telemetry/page/actions/wait.py
index bfe0b27..2210a2d 100644
--- a/tools/telemetry/telemetry/page/actions/wait.py
+++ b/tools/telemetry/telemetry/page/actions/wait.py
@@ -1,15 +1,16 @@
 # 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 re
 import time
 
 from telemetry.core import util
 from telemetry.page.actions import page_action
 
 class WaitAction(page_action.PageAction):
-  DEFAULT_TIMEOUT = 60
-
   def __init__(self, attributes=None):
+    self.timeout = 60
     super(WaitAction, self).__init__(attributes)
 
   def RunsPreviousAction(self):
@@ -27,33 +28,33 @@
       if not previous_action:
         raise page_action.PageActionFailed('You need to perform an action '
                                            'before waiting for navigate.')
-      previous_action.WillRunAction()
+      previous_action.WillRunAction(page, tab)
       action_to_perform = lambda: previous_action.RunAction(page, tab, None)
-      tab.PerformActionAndWaitForNavigate(action_to_perform)
+      tab.PerformActionAndWaitForNavigate(action_to_perform, self.timeout)
 
     elif self.condition == 'href_change':
       if not previous_action:
         raise page_action.PageActionFailed('You need to perform an action '
                                            'before waiting for a href change.')
-      previous_action.WillRunAction()
+      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.DEFAULT_TIMEOUT)
+          'document.location.href') != old_url, self.timeout)
 
     elif self.condition == 'element':
       assert hasattr(self, 'text') or hasattr(self, 'selector')
-      if self.text:
+      if hasattr(self, 'text'):
         callback_code = 'function(element) { return element != null; }'
         util.WaitFor(
             lambda: util.FindElementAndPerformAction(
-                tab, self.text, callback_code), self.DEFAULT_TIMEOUT)
-      elif self.selector:
+                tab, self.text, callback_code), self.timeout)
+      else:
         util.WaitFor(lambda: tab.EvaluateJavaScript(
-             'document.querySelector("%s") != null' % self.selector),
-             self.DEFAULT_TIMEOUT)
+             'document.querySelector("%s") != null' % re.escape(self.selector)),
+             self.timeout)
 
     elif self.condition == 'javascript':
       assert hasattr(self, 'javascript')
       util.WaitFor(lambda: tab.EvaluateJavaScript(self.javascript),
-                   self.DEFAULT_TIMEOUT)
+                   self.timeout)
diff --git a/tools/telemetry/telemetry/page/actions/wait_unittest.py b/tools/telemetry/telemetry/page/actions/wait_unittest.py
index 589870b..9fac176 100644
--- a/tools/telemetry/telemetry/page/actions/wait_unittest.py
+++ b/tools/telemetry/telemetry/page/actions/wait_unittest.py
@@ -1,17 +1,16 @@
 # 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 time
 
+from telemetry.core import util
 from telemetry.page.actions import wait
 from telemetry.unittest import tab_test_case
 
 class WaitActionTest(tab_test_case.TabTestCase):
   def testWaitAction(self):
-    unittest_data_dir = os.path.join(os.path.dirname(__file__),
-                                     '..', '..', '..', 'unittest_data')
-    self._browser.SetHTTPServerDirectories(unittest_data_dir)
+    self._browser.SetHTTPServerDirectories(util.GetUnittestDataDir())
     self._tab.Navigate(
       self._browser.http_server.UrlOf('blank.html'))
     self._tab.WaitForDocumentReadyStateToBeComplete()
@@ -24,3 +23,16 @@
     start_time = time.time()
     i.RunAction(None, self._tab, None)
     self.assertAlmostEqual(time.time() - start_time, 1, places=1)
+
+  def testWaitActionTimeout(self):
+    wait_action = wait.WaitAction({
+      'condition': 'javascript',
+      'javascript': '1 + 1 === 3',
+      'timeout': 1
+    })
+
+    start_time = time.time()
+    self.assertRaises(
+        util.TimeoutException,
+        lambda: wait_action.RunAction(None, self._tab, None))
+    self.assertTrue(time.time() - start_time < 5)
diff --git a/tools/telemetry/telemetry/page/block_page_measurement_results.py b/tools/telemetry/telemetry/page/block_page_measurement_results.py
index 625c5c8..ab9f7aa 100644
--- a/tools/telemetry/telemetry/page/block_page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/block_page_measurement_results.py
@@ -14,6 +14,11 @@
   def DidMeasurePage(self):
     page_values = self.values_for_current_page
 
+    if not page_values.values:
+      # Do not output if no results were added on this page.
+      super(BlockPageMeasurementResults, self).DidMeasurePage()
+      return
+
     lines = ['url: %s' %
              self.values_for_current_page.page.url]
     sorted_measurement_names = page_values.measurement_names
diff --git a/tools/telemetry/telemetry/page/cloud_storage.py b/tools/telemetry/telemetry/page/cloud_storage.py
index d52c622..1188252 100644
--- a/tools/telemetry/telemetry/page/cloud_storage.py
+++ b/tools/telemetry/telemetry/page/cloud_storage.py
@@ -27,6 +27,18 @@
   pass
 
 
+class CredentialsError(CloudStorageError):
+  def __init__(self, gsutil_path):
+    super(CredentialsError, self).__init__(
+        'Attempted to download a file from Cloud Storage but you have no '
+        'configured credentials. Run "%s config" to configure your '
+        'credentials. The project-id field can be left blank.' % gsutil_path)
+
+
+class NotFoundError(CloudStorageError):
+  pass
+
+
 def _DownloadGsutil():
   logging.info('Downloading gsutil')
   response = urllib2.urlopen(_GSUTIL_URL)
@@ -64,7 +76,12 @@
   stdout, stderr = gsutil.communicate()
 
   if gsutil.returncode:
-    raise CloudStorageError(stderr.splitlines()[-1])
+    if ('You are attempting to access protected data with '
+        'no configured credentials.' in stderr):
+      raise CredentialsError(gsutil_path)
+    if stderr.startswith('InvalidUriError') or 'No such object' in stderr:
+      raise NotFoundError(stderr)
+    raise CloudStorageError(stderr)
 
   return stdout
 
@@ -93,15 +110,24 @@
 
 
 def GetIfChanged(bucket, file_path):
-  """Gets the file at file_path if it has a hash file that doesn't match."""
+  """Gets the file at file_path if it has a hash file that doesn't match.
+
+  If the file is not in Cloud Storage, log a warning instead of raising an
+  exception. We assume that the user just hasn't uploaded the file yet.
+  """
   hash_path = file_path + '.sha1'
   if not os.path.exists(hash_path):
     return
 
   with open(hash_path, 'rb') as f:
     expected_hash = f.read(1024).rstrip()
-  if not os.path.exists(file_path) or GetHash(file_path) != expected_hash:
+  if os.path.exists(file_path) and GetHash(file_path) == expected_hash:
+    return
+
+  try:
     Get(bucket, expected_hash, file_path)
+  except NotFoundError:
+    logging.warning('Unable to update file %s from Cloud Storage.' % file_path)
 
 
 def GetHash(file_path):
diff --git a/tools/telemetry/telemetry/page/csv_page_measurement_results.py b/tools/telemetry/telemetry/page/csv_page_measurement_results.py
index 2440dd8..3770021 100644
--- a/tools/telemetry/telemetry/page/csv_page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/csv_page_measurement_results.py
@@ -7,17 +7,20 @@
 
 class CsvPageMeasurementResults(
     page_measurement_results.PageMeasurementResults):
-  def __init__(self, output_stream=None, output_after_every_page=None):
+  def __init__(self, output_stream, output_after_every_page=None):
     super(CsvPageMeasurementResults, self).__init__()
-    if output_stream:
-      self._results_writer = csv.writer(output_stream)
+    self._results_writer = csv.writer(output_stream)
     self._did_output_header = False
     self._header_names_written_to_writer = None
     self._output_after_every_page = output_after_every_page
 
   def DidMeasurePage(self):
     assert self.values_for_current_page, 'Failed to call WillMeasurePage'
-    if not self._output_after_every_page:
+
+    if (not self.values_for_current_page.values or
+        not self._output_after_every_page):
+      # Do not output if no results were added on this page or if output flag
+      # is not set.
       super(CsvPageMeasurementResults, self).DidMeasurePage()
       return
 
diff --git a/tools/telemetry/telemetry/page/gtest_test_results.py b/tools/telemetry/telemetry/page/gtest_test_results.py
index 31e85f9..7dd2522 100644
--- a/tools/telemetry/telemetry/page/gtest_test_results.py
+++ b/tools/telemetry/telemetry/page/gtest_test_results.py
@@ -9,13 +9,13 @@
 from telemetry.page import page_test_results
 
 class GTestTestResults(page_test_results.PageTestResults):
-  def __init__(self):
+  def __init__(self, output_stream):
     super(GTestTestResults, self).__init__()
-    self.timestamp = None
-    self.num_successes = 0
+    self._output_stream = output_stream
+    self._timestamp = None
 
   def _GetMs(self):
-    return (time.time() - self.timestamp) * 1000
+    return (time.time() - self._timestamp) * 1000
 
   @property
   def num_errors(self):
@@ -30,46 +30,51 @@
       return str(test)
 
   def _emitFailure(self, test, err):
-    print self._exc_info_to_string(err, test)
+    print >> self._output_stream, self._exc_info_to_string(err, test)
     test_name = GTestTestResults._formatTestname(test)
-    print '[  FAILED  ]', test_name, '(%0.f ms)' % self._GetMs()
+    print >> self._output_stream, '[  FAILED  ]', test_name, (
+        '(%0.f ms)' % self._GetMs())
     sys.stdout.flush()
 
   def addError(self, test, err):
-    self._emitFailure(test, err)
     super(GTestTestResults, self).addError(test, err)
+    self._emitFailure(test, err)
 
   def addFailure(self, test, err):
-    self._emitFailure(test, err)
     super(GTestTestResults, self).addFailure(test, err)
+    self._emitFailure(test, err)
 
   def startTest(self, test):
-    print '[ RUN      ]', GTestTestResults._formatTestname(test)
-    sys.stdout.flush()
-    self.timestamp = time.time()
     super(GTestTestResults, self).startTest(test)
+    print >> self._output_stream, '[ RUN      ]', (
+        GTestTestResults._formatTestname(test))
+    sys.stdout.flush()
+    self._timestamp = time.time()
 
   def addSuccess(self, test):
-    self.num_successes = self.num_successes + 1
-    test_name = GTestTestResults._formatTestname(test)
-    print '[       OK ]', test_name, '(%0.f ms)' % self._GetMs()
-    sys.stdout.flush()
     super(GTestTestResults, self).addSuccess(test)
+    test_name = GTestTestResults._formatTestname(test)
+    print >> self._output_stream, '[       OK ]', test_name, (
+        '(%0.f ms)' % self._GetMs())
+    sys.stdout.flush()
 
   def PrintSummary(self):
-    unit = 'test' if self.num_successes == 1 else 'tests'
-    print '[  PASSED  ] %d %s.' % (self.num_successes, unit)
+    unit = 'test' if len(self.successes) == 1 else 'tests'
+    print >> self._output_stream, '[  PASSED  ]', (
+        '%d %s.' % (len(self.successes), unit))
     if self.errors or self.failures:
       all_errors = self.errors[:]
       all_errors.extend(self.failures)
       unit = 'test' if len(all_errors) == 1 else 'tests'
-      print '[  FAILED  ] %d %s, listed below:' % (len(all_errors), unit)
+      print >> self._output_stream, '[  FAILED  ]', (
+          '%d %s, listed below:' % (len(all_errors), unit))
       for test, _ in all_errors:
-        print '[  FAILED  ] ', GTestTestResults._formatTestname(test)
+        print >> self._output_stream, '[  FAILED  ] ', (
+            GTestTestResults._formatTestname(test))
     if not self.wasSuccessful():
-      print
+      print >> self._output_stream
       count = len(self.errors) + len(self.failures)
       unit = 'TEST' if count == 1 else 'TESTS'
-      print '%d FAILED %s' % (count, unit)
-    print
+      print >> self._output_stream, '%d FAILED %s' % (count, unit)
+    print >> self._output_stream
     sys.stdout.flush()
diff --git a/tools/telemetry/telemetry/page/html_page_measurement_results.py b/tools/telemetry/telemetry/page/html_page_measurement_results.py
index 6c6e3cc..fb0f58d 100644
--- a/tools/telemetry/telemetry/page/html_page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/html_page_measurement_results.py
@@ -7,14 +7,11 @@
 import logging
 import os
 import re
-import sys
 
 from telemetry.core import util
 from telemetry.page import buildbot_page_measurement_results
 
-# Get build/util scripts into our path.
-sys.path.append(os.path.abspath(os.path.join(
-    util.GetChromiumSrcDir(), 'build', 'util')))
+util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'util')
 import lastchange  # pylint: disable=F0401
 
 
@@ -30,12 +27,10 @@
 
 class HtmlPageMeasurementResults(
     buildbot_page_measurement_results.BuildbotPageMeasurementResults):
-  def __init__(self, output_stream, test_name, reset_results, browser_type,
-               trace_tag=''):
+  def __init__(self, output_stream, test_name, browser_type, trace_tag=''):
     super(HtmlPageMeasurementResults, self).__init__(trace_tag)
 
     self._output_stream = output_stream
-    self._reset_results = reset_results
     self._test_name = test_name
     self._result_json = {
         'buildTime': self._GetBuildTime(),
@@ -66,7 +61,7 @@
 
   def _GetResultsJson(self):
     results_html = self._output_stream.read()
-    if self._reset_results or not results_html:
+    if not results_html:
       return []
     m = re.search(
         '^<script id="results-json" type="application/json">(.*?)</script>$',
@@ -74,7 +69,7 @@
     if not m:
       logging.warn('Failed to extract previous results from HTML output')
       return []
-    return json.loads(m.group(1))
+    return json.loads(m.group(1))[:512]
 
   def _SaveResults(self, results):
     self._output_stream.seek(0)
diff --git a/tools/telemetry/telemetry/page/html_page_measurement_results_unittest.py b/tools/telemetry/telemetry/page/html_page_measurement_results_unittest.py
index 2a42208..9a9e9b5 100644
--- a/tools/telemetry/telemetry/page/html_page_measurement_results_unittest.py
+++ b/tools/telemetry/telemetry/page/html_page_measurement_results_unittest.py
@@ -48,7 +48,7 @@
 
     # Run the first time and verify the results are written to the HTML file.
     results = DeterministicHtmlPageMeasurementResults(
-        output_file, 'test_name', False, 'browser_type')
+        output_file, 'test_name', 'browser_type')
     results.WillMeasurePage(test_page_set.pages[0])
     results.Add('a', 'seconds', 3)
     results.DidMeasurePage()
@@ -91,7 +91,7 @@
     # Run the second time and verify the results are appended to the HTML file.
     output_file.seek(0)
     results = DeterministicHtmlPageMeasurementResults(
-        output_file, 'test_name', False, 'browser_type')
+        output_file, 'test_name', 'browser_type')
     results.WillMeasurePage(test_page_set.pages[0])
     results.Add('a', 'seconds', 4)
     results.DidMeasurePage()
@@ -156,48 +156,3 @@
           '}]'
         '</script>')
     self.assertIn(expected, output_file.getvalue())
-    last_output_len = len(output_file.getvalue())
-
-    # Now reset the results and verify the old ones are gone.
-    output_file.seek(0)
-    results = DeterministicHtmlPageMeasurementResults(
-        output_file, 'test_name', True, 'browser_type')
-    results.WillMeasurePage(test_page_set.pages[0])
-    results.Add('a', 'seconds', 5)
-    results.DidMeasurePage()
-    results.WillMeasurePage(test_page_set.pages[1])
-    results.Add('a', 'seconds', 9)
-    results.DidMeasurePage()
-
-    results.PrintSummary()
-    expected = (
-        '<script id="results-json" type="application/json">'
-          '[{'
-            '"platform": "browser_type", '
-            '"buildTime": "build_time", '
-            '"tests": {'
-              '"test_name": {'
-                '"metrics": {'
-                  '"a": {'
-                    '"current": [5, 9], '
-                    '"units": "seconds", '
-                    '"important": true'
-                  '}, '
-                  '"a_by_url.http://www.bar.com/": {'
-                    '"current": [9], '
-                    '"units": "seconds", '
-                    '"important": false'
-                  '}, '
-                  '"a_by_url.http://www.foo.com/": {'
-                    '"current": [5], '
-                    '"units": "seconds", '
-                    '"important": false'
-                  '}'
-                '}'
-              '}'
-            '}, '
-            '"revision": "revision"'
-          '}]'
-        '</script>')
-    self.assertIn(expected, output_file.getvalue())
-    self.assertTrue(len(output_file.getvalue()) < last_output_len)
diff --git a/tools/telemetry/telemetry/page/page_measurement.py b/tools/telemetry/telemetry/page/page_measurement.py
index be3bb51..8d2cdb0 100644
--- a/tools/telemetry/telemetry/page/page_measurement.py
+++ b/tools/telemetry/telemetry/page/page_measurement.py
@@ -1,21 +1,16 @@
 # 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
 
-from telemetry.page import block_page_measurement_results
-from telemetry.page import buildbot_page_measurement_results
-from telemetry.page import csv_page_measurement_results
-from telemetry.page import html_page_measurement_results
-from telemetry.page import page_measurement_results
 from telemetry.page import page_test
 
+
 class MeasurementFailure(page_test.Failure):
   """Exception that can be thrown from MeasurePage to indicate an undesired but
   designed-for problem."""
   pass
 
+
 class PageMeasurement(page_test.PageTest):
   """Glue code for running a measurement across a set of pages.
 
@@ -59,56 +54,6 @@
     self.MeasurePage(page, tab, results)
     results.DidMeasurePage()
 
-  def AddOutputOptions(self, parser):
-    super(PageMeasurement, self).AddOutputOptions(parser)
-    parser.add_option('-o', '--output',
-                      dest='output_file',
-                      help='Redirects output to a file. Defaults to stdout.')
-    parser.add_option('--output-trace-tag',
-                      default='',
-                      help='Append a tag to the key of each result trace.')
-    parser.add_option('--reset-html-results', action='store_true',
-                      help='Delete all stored runs in HTML output')
-
-  @property
-  def output_format_choices(self):
-    return ['html', 'buildbot', 'block', 'csv', 'none']
-
-  def PrepareResults(self, options):
-    if hasattr(options, 'output_file') and options.output_file:
-      output_file = os.path.expanduser(options.output_file)
-      open(output_file, 'a').close()  # Create file if it doesn't exist.
-      output_stream = open(output_file, 'r+')
-    else:
-      output_stream = sys.stdout
-    if not hasattr(options, 'output_format'):
-      options.output_format = self.output_format_choices[0]
-    if not hasattr(options, 'output_trace_tag'):
-      options.output_trace_tag = ''
-
-    if options.output_format == 'csv':
-      return csv_page_measurement_results.CsvPageMeasurementResults(
-        output_stream,
-        self.results_are_the_same_on_every_page)
-    elif options.output_format == 'block':
-      return block_page_measurement_results.BlockPageMeasurementResults(
-        output_stream)
-    elif options.output_format == 'buildbot':
-      return buildbot_page_measurement_results.BuildbotPageMeasurementResults(
-          trace_tag=options.output_trace_tag)
-    elif options.output_format == 'html':
-      return html_page_measurement_results.HtmlPageMeasurementResults(
-          output_stream, self.__class__.__name__, options.reset_html_results,
-          options.browser_type, trace_tag=options.output_trace_tag)
-    elif options.output_format == 'none':
-      return page_measurement_results.PageMeasurementResults(
-          trace_tag=options.output_trace_tag)
-    else:
-      # Should never be reached. The parser enforces the choices.
-      raise Exception('Invalid --output-format "%s". Valid choices are: %s'
-                      % (options.output_format,
-                         ', '.join(self.output_format_choices)))
-
   @property
   def results_are_the_same_on_every_page(self):
     """By default, measurements are assumed to output the same values for every
diff --git a/tools/telemetry/telemetry/page/page_measurement_results.py b/tools/telemetry/telemetry/page/page_measurement_results.py
index 9b8f088..02ebd2a 100644
--- a/tools/telemetry/telemetry/page/page_measurement_results.py
+++ b/tools/telemetry/telemetry/page/page_measurement_results.py
@@ -108,5 +108,8 @@
 
   def DidMeasurePage(self):
     assert self._values_for_current_page, 'Failed to call WillMeasurePage'
+    if not self.values_for_current_page.values:
+      # Do not store to page_results list if no results were added on this page.
+      return
     self._page_results.append(self._values_for_current_page)
     self._values_for_current_page = None
diff --git a/tools/telemetry/telemetry/page/page_measurement_unittest.py b/tools/telemetry/telemetry/page/page_measurement_unittest.py
index 873ba2e..9cffaea 100644
--- a/tools/telemetry/telemetry/page/page_measurement_unittest.py
+++ b/tools/telemetry/telemetry/page/page_measurement_unittest.py
@@ -64,7 +64,7 @@
     self.assertEquals(0, len(all_results.failures))
 
   def testGotQueryParams(self):
-    ps = self.CreatePageSet('file:///../../unittest_data/blank.html?foo=1')
+    ps = self.CreatePageSet('file:///blank.html?foo=1')
     measurement = MeasurementQueryParams()
     ps.pages[-1].query_params = '?foo=1'
     all_results = self.RunMeasurement(measurement, ps, options=self._options)
diff --git a/tools/telemetry/telemetry/page/page_measurement_unittest_base.py b/tools/telemetry/telemetry/page/page_measurement_unittest_base.py
index 6c570c8..389f057 100644
--- a/tools/telemetry/telemetry/page/page_measurement_unittest_base.py
+++ b/tools/telemetry/telemetry/page/page_measurement_unittest_base.py
@@ -1,9 +1,10 @@
 # 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 unittest
 
+from telemetry.core import util
 from telemetry.page import page_runner
 from telemetry.page import page as page_module
 from telemetry.page import page_set
@@ -15,12 +16,11 @@
   for a measurement."""
 
   def CreatePageSetFromFileInUnittestDataDir(self, test_filename):
-    return self.CreatePageSet('file:///' + os.path.join(
-        '..', '..', 'unittest_data', test_filename))
+    return self.CreatePageSet('file:///' + test_filename)
 
   def CreatePageSet(self, test_filename):
-    base_dir = os.path.dirname(__file__)
-    ps = page_set.PageSet(file_path=os.path.join(base_dir, 'foo.json'))
+    base_dir = util.GetUnittestDataDir()
+    ps = page_set.PageSet(file_path=base_dir)
     page = page_module.Page(test_filename, ps, base_dir=base_dir)
     setattr(page, 'smoothness', {'action': 'scroll'})
     ps.pages.append(page)
diff --git a/tools/telemetry/telemetry/page/page_runner.py b/tools/telemetry/telemetry/page/page_runner.py
index 1df51de..e622072 100644
--- a/tools/telemetry/telemetry/page/page_runner.py
+++ b/tools/telemetry/telemetry/page/page_runner.py
@@ -20,6 +20,8 @@
 from telemetry.page import page_measurement_results
 from telemetry.page import page_runner_repeat
 from telemetry.page import page_test
+from telemetry.page import results_options
+from telemetry.page.actions import navigate
 
 
 class _RunState(object):
@@ -32,6 +34,7 @@
     self._first_browser = True
     self.first_page = collections.defaultdict(lambda: True)
     self.profiler_dir = None
+    self.repeat_state = None
 
   def StartBrowser(self, test, page_set, page, possible_browser,
                    credentials_path, archive_path):
@@ -110,12 +113,9 @@
 
   def PreparePage(self, page, tab, test=None):
     if page.is_file:
-      serving_dirs, filename = page.serving_dirs_and_file
+      serving_dirs = page.serving_dirs_and_file[0]
       if tab.browser.SetHTTPServerDirectories(serving_dirs) and test:
         test.DidStartHTTPServer(tab)
-      target_side_url = tab.browser.http_server.UrlOf(filename)
-    else:
-      target_side_url = page.url
 
     if page.credentials:
       if not tab.browser.credentials.LoginNeeded(tab, page.credentials):
@@ -125,13 +125,20 @@
     if test:
       if test.clear_cache_before_each_run:
         tab.ClearCache()
-      test.WillNavigateToPage(page, tab)
-    tab.Navigate(target_side_url, page.script_to_evaluate_on_commit)
-    if test:
-      test.DidNavigateToPage(page, tab)
 
-    page.WaitToLoad(tab, 60)
-    tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+  def ImplicitPageNavigation(self, page, tab, 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)
+    else:
+      i = navigate.NavigateAction()
+      i.RunAction(page, tab, None)
+      page.WaitToLoad(tab, 60)
 
   def CleanUpPage(self, page, tab):
     if page.credentials and self._did_login:
@@ -140,6 +147,7 @@
 
 def AddCommandLineOptions(parser):
   page_filter_module.PageFilter.AddCommandLineOptions(parser)
+  results_options.AddResultsOptions(parser)
 
 
 def _LogStackTrace(title, browser):
@@ -172,16 +180,15 @@
       state.StartBrowser(test, page_set, page, possible_browser,
                          credentials_path, page.archive_path)
 
+      expectation = expectations.GetExpectationForPage(state.browser, page)
+
       _WaitForThermalThrottlingIfNeeded(state.browser.platform)
 
       if options.profiler:
         state.StartProfiling(page, options)
 
-      expectation = expectations.GetExpectationForPage(
-          state.browser.platform, page)
-
       try:
-        _RunPage(test, page, state.tab, expectation,
+        _RunPage(test, page, state, expectation,
                  results_for_current_run, options)
         _CheckThermalThrottling(state.browser.platform)
       except exceptions.TabCrashException:
@@ -208,7 +215,7 @@
 
 def Run(test, page_set, expectations, options):
   """Runs a given test against a given page_set with the given options."""
-  results = test.PrepareResults(options)
+  results = results_options.PrepareResults(test, options)
 
   # Create a possible_browser with the given options.
   test.CustomizeBrowserOptions(options)
@@ -262,19 +269,21 @@
 
   try:
     test.WillRunTest(state.tab)
-    repeat_state = page_runner_repeat.PageRunnerRepeatState(
-        options.repeat_options)
+    state.repeat_state = page_runner_repeat.PageRunnerRepeatState(
+                             options.repeat_options)
 
-    repeat_state.WillRunPageSet()
-    while repeat_state.ShouldRepeatPageSet():
+    state.repeat_state.WillRunPageSet()
+    while state.repeat_state.ShouldRepeatPageSet():
       for page in pages:
-        repeat_state.WillRunPage()
-        while repeat_state.ShouldRepeatPage():
+        state.repeat_state.WillRunPage()
+        test.WillRunPageRepeats(page, state.tab)
+        while state.repeat_state.ShouldRepeatPage():
           # execute test on page
           _PrepareAndRunPage(test, page_set, expectations, options, page,
                              credentials_path, possible_browser, results, state)
-          repeat_state.DidRunPage()
-      repeat_state.DidRunPageSet()
+          state.repeat_state.DidRunPage()
+        test.DidRunPageRepeats(page, state.tab)
+      state.repeat_state.DidRunPageSet()
 
     test.DidRunTest(state.tab, results)
   finally:
@@ -356,13 +365,24 @@
           pages_missing_archive_path + pages_missing_archive_data]
 
 
-def _RunPage(test, page, tab, expectation, results, options):
+def _RunPage(test, page, state, expectation, results, options):
   logging.info('Running %s' % page.url)
 
   page_state = PageState()
+  tab = state.tab
+
+  def ProcessError():
+    logging.error('%s:\n%s', page.url, traceback.format_exc())
+    if expectation == 'fail':
+      logging.info('Error was expected\n')
+      results.AddSuccess(page)
+    else:
+      results.AddError(page, sys.exc_info())
 
   try:
     page_state.PreparePage(page, tab, test)
+    if state.repeat_state.ShouldNavigate(options.skip_navigate_on_repeat):
+      page_state.ImplicitPageNavigation(page, tab, test)
     test.Run(options, page, tab, results)
     util.CloseConnections(tab)
   except page_test.Failure:
@@ -374,11 +394,9 @@
       results.AddFailure(page, sys.exc_info())
   except (util.TimeoutException, exceptions.LoginException,
           exceptions.ProfilingException):
-    logging.error('%s:\n%s', page.url, traceback.format_exc())
-    results.AddError(page, sys.exc_info())
+    ProcessError()
   except (exceptions.TabCrashException, exceptions.BrowserGoneException):
-    logging.error('%s:\n%s', page.url, traceback.format_exc())
-    results.AddError(page, sys.exc_info())
+    ProcessError()
     # Run() catches these exceptions to relaunch the tab/browser, so re-raise.
     raise
   except Exception:
diff --git a/tools/telemetry/telemetry/page/page_runner_repeat.py b/tools/telemetry/telemetry/page/page_runner_repeat.py
index acec0b0..5c80f5c 100644
--- a/tools/telemetry/telemetry/page/page_runner_repeat.py
+++ b/tools/telemetry/telemetry/page/page_runner_repeat.py
@@ -52,3 +52,10 @@
           self.page_iters >= self.options.page_repeat_iters):
       return False
     return True
+
+  def ShouldNavigate(self, skip_navigate_on_repeat):
+    """Returns whether we are navigating to pages on page repeats.
+
+    Always navigate on the first iteration of a page and on every new pageset.
+    """
+    return self.page_iters == 0 or not skip_navigate_on_repeat
\ No newline at end of file
diff --git a/tools/telemetry/telemetry/page/page_runner_unittest.py b/tools/telemetry/telemetry/page/page_runner_unittest.py
index 2ff1cfc..c3d4f2b 100644
--- a/tools/telemetry/telemetry/page/page_runner_unittest.py
+++ b/tools/telemetry/telemetry/page/page_runner_unittest.py
@@ -59,19 +59,34 @@
     options.output_format = 'none'
     results = page_runner.Run(Test('RunTest'), ps, expectations, options)
     self.assertEquals(0, len(results.successes))
+    self.assertEquals(0, len(results.failures))
     self.assertEquals(1, len(results.errors))
 
+  def testHandlingOfCrashedTabWithExpectedFailure(self):
+    ps = page_set.PageSet()
+    expectations = test_expectations.TestExpectations()
+    expectations.Fail('chrome://crash')
+    page1 = page_module.Page('chrome://crash', ps)
+    ps.pages.append(page1)
+
+    class Test(page_test.PageTest):
+      def RunTest(self, *args):
+        pass
+
+    options = options_for_unittests.GetCopy()
+    options.output_format = 'none'
+    results = page_runner.Run(Test('RunTest'), ps, expectations, options)
+    self.assertEquals(1, len(results.successes))
+    self.assertEquals(0, len(results.failures))
+    self.assertEquals(0, len(results.errors))
+
   def testDiscardFirstResult(self):
     ps = page_set.PageSet()
     expectations = test_expectations.TestExpectations()
     ps.pages.append(page_module.Page(
-        'file:///' + os.path.join(util.GetUnittestDataDir(), 'blank.html'),
-        ps,
-        base_dir=os.path.dirname(__file__)))
+        'file:///blank.html', ps, base_dir=util.GetUnittestDataDir()))
     ps.pages.append(page_module.Page(
-        'file:///' + os.path.join(util.GetUnittestDataDir(), 'blank.html'),
-        ps,
-        base_dir=os.path.dirname(__file__)))
+        'file:///blank.html', ps, base_dir=util.GetUnittestDataDir()))
 
     class Measurement(page_measurement.PageMeasurement):
       @property
@@ -128,9 +143,7 @@
     ps = page_set.PageSet()
     expectations = test_expectations.TestExpectations()
     page = page_module.Page(
-        'file:///' + os.path.join(util.GetUnittestDataDir(), 'blank.html'),
-        ps,
-        base_dir=os.path.dirname(__file__))
+        'file:///blank.html', ps, base_dir=util.GetUnittestDataDir())
     page.credentials = "test"
     ps.pages.append(page)
 
@@ -165,9 +178,7 @@
     ps = page_set.PageSet()
     expectations = test_expectations.TestExpectations()
     page = page_module.Page(
-        'file:///' + os.path.join(util.GetUnittestDataDir(), 'blank.html'),
-        ps,
-        base_dir=os.path.dirname(__file__))
+        'file:///blank.html', ps, base_dir=util.GetUnittestDataDir())
     ps.pages.append(page)
     ps.user_agent_type = 'tablet'
 
@@ -194,9 +205,7 @@
     ps = page_set.PageSet()
     expectations = test_expectations.TestExpectations()
     page = page_module.Page(
-        'file:///' + os.path.join(util.GetUnittestDataDir(), 'blank.html'),
-        ps,
-        base_dir=os.path.dirname(__file__))
+        'file:///blank.html', ps, base_dir=util.GetUnittestDataDir())
     ps.pages.append(page)
 
     class TestOneTab(page_test.PageTest):
@@ -230,9 +239,7 @@
     ps = page_set.PageSet()
     expectations = test_expectations.TestExpectations()
     page = page_module.Page(
-        'file:///' + os.path.join(util.GetUnittestDataDir(), 'blank.html'),
-        ps,
-        base_dir=os.path.dirname(__file__))
+        'file:///blank.html', ps, base_dir=util.GetUnittestDataDir())
     ps.pages.append(page)
 
     class TestBeforeLaunch(page_test.PageTest):
diff --git a/tools/telemetry/telemetry/page/page_test.py b/tools/telemetry/telemetry/page/page_test.py
index 12940bd..e9d7147 100644
--- a/tools/telemetry/telemetry/page/page_test.py
+++ b/tools/telemetry/telemetry/page/page_test.py
@@ -4,12 +4,12 @@
 import logging
 
 from telemetry.core import util
-from telemetry.page import gtest_test_results
 from telemetry.page import test_expectations
-from telemetry.page import page_test_results
 from telemetry.page.actions import all_page_actions
+from telemetry.page.actions import navigate
 from telemetry.page.actions import page_action
 
+
 def _GetActionFromData(action_data):
   action_name = action_data['action']
   action = all_page_actions.FindClassWithName(action_name)
@@ -20,6 +20,7 @@
     raise Exception('Action "%s" not found.' % action_name)
   return action(action_data)
 
+
 def GetCompoundActionFromPage(page, action_name):
   if not action_name:
     return []
@@ -38,11 +39,13 @@
     action_list += subaction * subaction_data.get('repeat', 1)
   return action_list
 
+
 class Failure(Exception):
   """Exception that can be thrown from PageMeasurement to indicate an
   undesired but designed-for problem."""
   pass
 
+
 class PageTest(object):
   """A class styled on unittest.TestCase for creating page-specific tests."""
 
@@ -127,6 +130,14 @@
     """
     pass
 
+  def WillRunPageRepeats(self, page, tab):
+    """Override to do operations before each page is iterated over."""
+    pass
+
+  def DidRunPageRepeats(self, page, tab):
+    """Override to do operations after each page is iterated over."""
+    pass
+
   def DidStartHTTPServer(self, tab):
     """Override to do operations after the HTTP server is started."""
     pass
@@ -158,32 +169,6 @@
     any that may have been defined in the page set."""
     return test_expectations.TestExpectations()
 
-  def AddOutputOptions(self, parser):
-    parser.add_option('--output-format',
-                      default=self.output_format_choices[0],
-                      choices=self.output_format_choices,
-                      help='Output format. Defaults to "%%default". '
-                      'Can be %s.' % ', '.join(self.output_format_choices))
-
-  @property
-  def output_format_choices(self):
-    """Allowed output formats. The default is the first item in the list."""
-    return ['gtest', 'none']
-
-  def PrepareResults(self, options):
-    if not hasattr(options, 'output_format'):
-      options.output_format = self.output_format_choices[0]
-
-    if options.output_format == 'gtest':
-      return gtest_test_results.GTestTestResults()
-    elif options.output_format == 'none':
-      return page_test_results.PageTestResults()
-    else:
-      # Should never be reached. The parser enforces the choices.
-      raise Exception('Invalid --output-format "%s". Valid choices are: %s'
-                      % (options.output_format,
-                         ', '.join(self.output_format_choices)))
-
   def Run(self, options, page, tab, results):
     self.options = options
     compound_action = GetCompoundActionFromPage(page, self._action_name_to_run)
@@ -193,7 +178,7 @@
     finally:
       self.options = None
 
-  def _RunCompoundAction(self, page, tab, actions):
+  def _RunCompoundAction(self, page, tab, actions, run_setup_methods=True):
     for i, action in enumerate(actions):
       prev_action = actions[i - 1] if i > 0 else None
       next_action = actions[i + 1] if i < len(actions) - 1 else None
@@ -205,16 +190,38 @@
 
       if not (next_action and next_action.RunsPreviousAction()):
         action.WillRunAction(page, tab)
-        self.WillRunAction(page, tab, action)
+        if run_setup_methods:
+          self.WillRunAction(page, tab, action)
         try:
           action.RunAction(page, tab, prev_action)
         finally:
-          self.DidRunAction(page, tab, action)
+          if run_setup_methods:
+            self.DidRunAction(page, tab, action)
 
       # Closing the connections periodically is needed; otherwise we won't be
       # able to open enough sockets, and the pages will time out.
       util.CloseConnections(tab)
 
+  def RunNavigateSteps(self, page, tab):
+    """Navigates the tab to the page URL attribute.
+
+    If 'navigate_steps' is defined for the page, this will attempt to
+    run it as a compound action.
+    """
+    if hasattr(page, 'navigate_steps'):
+      navigate_actions = GetCompoundActionFromPage(page, 'navigate_steps')
+      if not any(isinstance(action, navigate.NavigateAction)
+          for action in navigate_actions):
+        raise page_action.PageActionFailed(
+            'No NavigateAction in navigate_steps')
+      self._RunCompoundAction(page, tab, navigate_actions, False)
+    else:
+      # TODO(edmundyan): Make a default navigate_steps action on the page object
+      # once we can deprecate page.WaitToLoad()
+      i = navigate.NavigateAction()
+      i.RunAction(page, tab, None)
+      page.WaitToLoad(tab, 60)
+
   @property
   def action_name_to_run(self):
     return self._action_name_to_run
diff --git a/tools/telemetry/telemetry/page/page_test_runner.py b/tools/telemetry/telemetry/page/page_test_runner.py
index 6b8fa9b..623a5c8 100644
--- a/tools/telemetry/telemetry/page/page_test_runner.py
+++ b/tools/telemetry/telemetry/page/page_test_runner.py
@@ -143,7 +143,6 @@
         page_test = test.test()
       else:
         page_test = test
-      page_test.AddOutputOptions(self._parser)
       page_test.AddCommandLineOptions(self._parser)
     page_runner.AddCommandLineOptions(self._parser)
 
diff --git a/tools/telemetry/telemetry/page/page_test_unittest.py b/tools/telemetry/telemetry/page/page_test_unittest.py
index 6b68d9d..3b2e626 100644
--- a/tools/telemetry/telemetry/page/page_test_unittest.py
+++ b/tools/telemetry/telemetry/page/page_test_unittest.py
@@ -1,18 +1,18 @@
 # 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 unittest
 
+from telemetry.core import util
 from telemetry.page import page as page_module
 from telemetry.page import page_test
 from telemetry.page.actions import all_page_actions
 from telemetry.page.actions import page_action
 
 def _CreatePage(test_filename):
-  url = 'file:///' + os.path.join('..', '..', 'unittest_data', test_filename)
-  base_dir = os.path.dirname(__file__)
-  page = page_module.Page(url, None, base_dir=base_dir)
+  url = 'file:///' + test_filename
+  page = page_module.Page(url, None, base_dir=util.GetUnittestDataDir())
   return page
 
 class DoNothingPageTest(page_test.PageTest):
diff --git a/tools/telemetry/telemetry/page/perf_tests_helper.py b/tools/telemetry/telemetry/page/perf_tests_helper.py
index 285e032..d72835d 100644
--- a/tools/telemetry/telemetry/page/perf_tests_helper.py
+++ b/tools/telemetry/telemetry/page/perf_tests_helper.py
@@ -3,25 +3,15 @@
 # found in the LICENSE file.
 from __future__ import absolute_import
 
-import os
-import sys
+from telemetry.core import util
 
-def __init__():
-  path = os.path.join(os.path.dirname(__file__),
-                      '..', '..', '..', '..', 'build', 'android')
-  path = os.path.abspath(path)
-  assert os.path.exists(os.path.join(path,
-                                     'pylib', '__init__.py'))
-  if path not in sys.path:
-    sys.path.append(path)
+util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
+from pylib import perf_tests_helper  # pylint: disable=F0401
 
-__init__()
 
-from pylib import perf_tests_helper # pylint: disable=F0401
 GeomMeanAndStdDevFromHistogram = \
     perf_tests_helper.GeomMeanAndStdDevFromHistogram
 PrintPerfResult = \
     perf_tests_helper.PrintPerfResult
 PrintPages = \
     perf_tests_helper.PrintPages
-
diff --git a/tools/telemetry/telemetry/page/record_wpr.py b/tools/telemetry/telemetry/page/record_wpr.py
index ff295e4..1329073 100755
--- a/tools/telemetry/telemetry/page/record_wpr.py
+++ b/tools/telemetry/telemetry/page/record_wpr.py
@@ -47,8 +47,7 @@
     should_reload = False
     for compound_action in self._CompoundActionsForPage(page):
       if should_reload:
-        tab.Navigate(page.url)
-        tab.WaitForDocumentReadyStateToBeComplete()
+        self.RunNavigateSteps(page, tab)
       self._RunCompoundAction(page, tab, compound_action)
       should_reload = True
 
@@ -72,7 +71,6 @@
 
   recorder = RecordPage(measurements)
   recorder.AddCommandLineOptions(parser)
-  recorder.AddOutputOptions(parser)
 
   _, args = parser.parse_args()
 
diff --git a/tools/telemetry/telemetry/page/results_options.py b/tools/telemetry/telemetry/page/results_options.py
new file mode 100644
index 0000000..4d8471f
--- /dev/null
+++ b/tools/telemetry/telemetry/page/results_options.py
@@ -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.
+
+import optparse
+import os
+import sys
+
+from telemetry.core import util
+from telemetry.page import block_page_measurement_results
+from telemetry.page import buildbot_page_measurement_results
+from telemetry.page import csv_page_measurement_results
+from telemetry.page import gtest_test_results
+from telemetry.page import html_page_measurement_results
+from telemetry.page import page_measurement
+from telemetry.page import page_measurement_results
+
+
+# Allowed output formats. The default is the first item in the list.
+_OUTPUT_FORMAT_CHOICES = ('html', 'buildbot', 'block', 'csv', 'gtest', 'none')
+
+
+def AddResultsOptions(parser):
+  group = optparse.OptionGroup(parser, 'Results options')
+  group.add_option('--output-format',
+                    default=_OUTPUT_FORMAT_CHOICES[0],
+                    choices=_OUTPUT_FORMAT_CHOICES,
+                    help='Output format. Defaults to "%%default". '
+                    'Can be %s.' % ', '.join(_OUTPUT_FORMAT_CHOICES))
+  group.add_option('-o', '--output',
+                    dest='output_file',
+                    help='Redirects output to a file. Defaults to stdout.')
+  group.add_option('--output-trace-tag',
+                    default='',
+                    help='Append a tag to the key of each result trace.')
+  parser.add_option_group(group)
+
+
+def PrepareResults(test, options):
+  if not isinstance(test, page_measurement.PageMeasurement):
+    # Sort of hacky. The default for non-Measurements should be "gtest."
+    if options.output_format != 'none':
+      options.output_format = 'gtest'
+
+  if options.output_format == 'html' and not options.output_file:
+    options.output_file = os.path.join(util.GetBaseDir(), 'results.html')
+
+  if hasattr(options, 'output_file') and options.output_file:
+    output_file = os.path.expanduser(options.output_file)
+    open(output_file, 'a').close()  # Create file if it doesn't exist.
+    output_stream = open(output_file, 'r+')
+  else:
+    output_stream = sys.stdout
+  if not hasattr(options, 'output_format'):
+    options.output_format = _OUTPUT_FORMAT_CHOICES[0]
+  if not hasattr(options, 'output_trace_tag'):
+    options.output_trace_tag = ''
+
+  if options.output_format == 'none':
+    return page_measurement_results.PageMeasurementResults(
+        trace_tag=options.output_trace_tag)
+  elif options.output_format == 'csv':
+    return csv_page_measurement_results.CsvPageMeasurementResults(
+      output_stream,
+      test.results_are_the_same_on_every_page)
+  elif options.output_format == 'block':
+    return block_page_measurement_results.BlockPageMeasurementResults(
+      output_stream)
+  elif options.output_format == 'buildbot':
+    return buildbot_page_measurement_results.BuildbotPageMeasurementResults(
+        trace_tag=options.output_trace_tag)
+  elif options.output_format == 'gtest':
+    return gtest_test_results.GTestTestResults(output_stream)
+  elif options.output_format == 'html':
+    return html_page_measurement_results.HtmlPageMeasurementResults(
+        output_stream, test.__class__.__name__, options.browser_type,
+        trace_tag=options.output_trace_tag)
+  else:
+    # Should never be reached. The parser enforces the choices.
+    raise Exception('Invalid --output-format "%s". Valid choices are: %s'
+                    % (options.output_format,
+                       ', '.join(_OUTPUT_FORMAT_CHOICES)))
diff --git a/tools/telemetry/telemetry/page/test_expectations.py b/tools/telemetry/telemetry/page/test_expectations.py
index 4568922..cd9244d 100644
--- a/tools/telemetry/telemetry/page/test_expectations.py
+++ b/tools/telemetry/telemetry/page/test_expectations.py
@@ -6,7 +6,7 @@
 
 OS_MODIFIERS = ['win', 'xp', 'vista', 'win7',
                 'mac', 'leopard', 'snowleopard', 'lion', 'mountainlion',
-                'linux', 'chromeos']
+                'linux', 'chromeos', 'android']
 GPU_MODIFIERS = ['nvidia', 'amd', 'intel']
 CONFIG_MODIFIERS = ['debug', 'release']
 
@@ -19,6 +19,7 @@
     self.os_conditions = []
     self.gpu_conditions = []
     self.config_conditions = []
+    self.device_id_conditions = []
 
     # Make sure that non-absolute paths are searchable
     if not '://' in self.url_pattern:
@@ -26,15 +27,20 @@
 
     if conditions:
       for c in conditions:
-        condition = c.lower()
-        if condition in OS_MODIFIERS:
-          self.os_conditions.append(condition)
-        elif condition in GPU_MODIFIERS:
-          self.gpu_conditions.append(condition)
-        elif condition in CONFIG_MODIFIERS:
-          self.config_conditions.append(condition)
+        if isinstance(c, tuple):
+          c0 = c[0].lower()
+          if c0 in GPU_MODIFIERS:
+            self.device_id_conditions.append((c0, c[1]))
         else:
-          raise ValueError('Unknown expectation condition: "%s"' % condition)
+          condition = c.lower()
+          if condition in OS_MODIFIERS:
+            self.os_conditions.append(condition)
+          elif condition in GPU_MODIFIERS:
+            self.gpu_conditions.append(condition)
+          elif condition in CONFIG_MODIFIERS:
+            self.config_conditions.append(condition)
+          else:
+            raise ValueError('Unknown expectation condition: "%s"' % condition)
 
 class TestExpectations(object):
   """A class which defines the expectations for a page set test execution"""
@@ -54,19 +60,55 @@
     self.expectations.append(Expectation(expectation, url_pattern, conditions,
       bug))
 
-  def GetExpectationForPage(self, platform, page):
+  def GetExpectationForPage(self, browser, page):
+    platform = browser.platform
+    gpu_info = None
+
     for e in self.expectations:
       if fnmatch.fnmatch(page.url, e.url_pattern):
-        if self._ModifiersApply(platform, e):
+        if gpu_info == None and browser.supports_system_info:
+          gpu_info = browser.GetSystemInfo().gpu
+        if self._ModifiersApply(platform, gpu_info, e):
           return e.expectation
     return 'pass'
 
-  def _ModifiersApply(self, platform, expectation):
+  def _GetGpuVendorString(self, gpu_info):
+    if gpu_info:
+      primary_gpu = gpu_info.devices[0]
+      if primary_gpu:
+        vendor_string = primary_gpu.vendor_string.lower()
+        vendor_id = primary_gpu.vendor_id
+        if vendor_string:
+          return vendor_string
+        elif vendor_id == 0x10DE:
+          return 'nvidia'
+        elif vendor_id == 0x1002:
+          return 'amd'
+        elif vendor_id == 0x8086:
+          return 'intel'
+
+    return 'unknown_gpu'
+
+  def _GetGpuDeviceId(self, gpu_info):
+    if gpu_info:
+      primary_gpu = gpu_info.devices[0]
+      if primary_gpu:
+        return primary_gpu.device_id
+
+    return 0
+
+  def _ModifiersApply(self, platform, gpu_info, expectation):
     """Determines if the conditions for an expectation apply to this system."""
     os_matches = (not expectation.os_conditions or
-          platform.GetOSName() in expectation.os_conditions or
-          platform.GetOSVersionName() in expectation.os_conditions)
+        platform.GetOSName() in expectation.os_conditions or
+        platform.GetOSVersionName() in expectation.os_conditions)
 
-    # TODO: Add checks against other modifiers (GPU, configuration, etc.)
+    gpu_vendor = self._GetGpuVendorString(gpu_info)
+    gpu_device_id = self._GetGpuDeviceId(gpu_info)
 
-    return os_matches
\ No newline at end of file
+    gpu_matches = ((not expectation.gpu_conditions and
+        not expectation.device_id_conditions) or
+        gpu_vendor in expectation.gpu_conditions or
+        (gpu_vendor, gpu_device_id) in expectation.device_id_conditions)
+
+    return os_matches and gpu_matches
diff --git a/tools/telemetry/telemetry/page/test_expectations_unittest.py b/tools/telemetry/telemetry/page/test_expectations_unittest.py
index ee4a1b8..cf0d6a5 100644
--- a/tools/telemetry/telemetry/page/test_expectations_unittest.py
+++ b/tools/telemetry/telemetry/page/test_expectations_unittest.py
@@ -3,10 +3,15 @@
 # found in the LICENSE file.
 import unittest
 
+from telemetry.core import system_info
 from telemetry.page import page as page_module
 from telemetry.page import page_set
 from telemetry.page import test_expectations
 
+VENDOR_NVIDIA = 0x10DE
+VENDOR_AMD = 0x1002
+VENDOR_INTEL = 0x8086
+
 class StubPlatform(object):
   def __init__(self, os_name, os_version_name=None):
     self.os_name = os_name
@@ -18,6 +23,26 @@
   def GetOSVersionName(self):
     return self.os_version_name
 
+class StubBrowser(object):
+  def __init__(self, platform, gpu, device):
+    self.platform = platform
+    self.system_info = system_info.SystemInfo.FromDict({
+      'model_name': '',
+      'gpu': {
+        'devices': [
+          { 'vendor_id': gpu, 'device_id': device,
+            'vendor_string': '', 'device_string': '' },
+        ]
+      }
+    })
+
+  @property
+  def supports_system_info(self):
+    return False if not self.system_info else True
+
+  def GetSystemInfo(self):
+    return self.system_info
+
 class SampleTestExpectations(test_expectations.TestExpectations):
   def SetExpectations(self):
     self.Fail('page1.html', ['win', 'mac'], bug=123)
@@ -25,54 +50,59 @@
     self.Fail('page3.html', bug=123)
     self.Fail('page4.*', bug=123)
     self.Fail('http://test.com/page5.html', bug=123)
+    self.Fail('page6.html', ['nvidia', 'intel'], bug=123)
+    self.Fail('page7.html', [('nvidia', 0x1001), ('nvidia', 0x1002)], bug=123)
+    self.Fail('page8.html', ['win', 'intel', ('amd', 0x1001)], bug=123)
 
 class TestExpectationsTest(unittest.TestCase):
   def setUp(self):
     self.expectations = SampleTestExpectations()
 
-  def assertExpectationEquals(self, expected, platform, page):
-    result = self.expectations.GetExpectationForPage(platform, page)
+  def assertExpectationEquals(self, expected, page, platform='', gpu='',
+      device=0):
+    result = self.expectations.GetExpectationForPage(StubBrowser(platform, gpu,
+        device), page)
     self.assertEquals(expected, result)
 
   # Pages with no expectations should always return 'pass'
   def testNoExpectations(self):
     ps = page_set.PageSet()
     page = page_module.Page('http://test.com/page0.html', ps)
-    self.assertExpectationEquals('pass', StubPlatform('win'), page)
+    self.assertExpectationEquals('pass', page, StubPlatform('win'))
 
   # Pages with expectations for an OS should only return them when running on
   # that OS
   def testOSExpectations(self):
     ps = page_set.PageSet()
     page = page_module.Page('http://test.com/page1.html', ps)
-    self.assertExpectationEquals('fail', StubPlatform('win'), page)
-    self.assertExpectationEquals('fail', StubPlatform('mac'), page)
-    self.assertExpectationEquals('pass', StubPlatform('linux'), page)
+    self.assertExpectationEquals('fail', page, StubPlatform('win'))
+    self.assertExpectationEquals('fail', page, StubPlatform('mac'))
+    self.assertExpectationEquals('pass', page, StubPlatform('linux'))
 
   # Pages with expectations for an OS version should only return them when
   # running on that OS version
   def testOSVersionExpectations(self):
     ps = page_set.PageSet()
     page = page_module.Page('http://test.com/page2.html', ps)
-    self.assertExpectationEquals('fail', StubPlatform('win', 'vista'), page)
-    self.assertExpectationEquals('pass', StubPlatform('win', 'win7'), page)
+    self.assertExpectationEquals('fail', page, StubPlatform('win', 'vista'))
+    self.assertExpectationEquals('pass', page, StubPlatform('win', 'win7'))
 
   # Pages with non-conditional expectations should always return that
   # expectation regardless of OS or OS version
   def testConditionlessExpectations(self):
     ps = page_set.PageSet()
     page = page_module.Page('http://test.com/page3.html', ps)
-    self.assertExpectationEquals('fail', StubPlatform('win'), page)
-    self.assertExpectationEquals('fail', StubPlatform('mac', 'lion'), page)
-    self.assertExpectationEquals('fail', StubPlatform('linux'), page)
+    self.assertExpectationEquals('fail', page, StubPlatform('win'))
+    self.assertExpectationEquals('fail', page, StubPlatform('mac', 'lion'))
+    self.assertExpectationEquals('fail', page, StubPlatform('linux'))
 
   # Expectations with wildcard characters should return for matching patterns
   def testWildcardExpectations(self):
     ps = page_set.PageSet()
     page = page_module.Page('http://test.com/page4.html', ps)
     page_js = page_module.Page('http://test.com/page4.html', ps)
-    self.assertExpectationEquals('fail', StubPlatform('win'), page)
-    self.assertExpectationEquals('fail', StubPlatform('win'), page_js)
+    self.assertExpectationEquals('fail', page, StubPlatform('win'))
+    self.assertExpectationEquals('fail', page_js, StubPlatform('win'))
 
   # Expectations with absolute paths should match the entire path
   def testAbsoluteExpectations(self):
@@ -80,6 +110,41 @@
     page = page_module.Page('http://test.com/page5.html', ps)
     page_org = page_module.Page('http://test.org/page5.html', ps)
     page_https = page_module.Page('https://test.com/page5.html', ps)
-    self.assertExpectationEquals('fail', StubPlatform('win'), page)
-    self.assertExpectationEquals('pass', StubPlatform('win'), page_org)
-    self.assertExpectationEquals('pass', StubPlatform('win'), page_https)
+    self.assertExpectationEquals('fail', page, StubPlatform('win'))
+    self.assertExpectationEquals('pass', page_org, StubPlatform('win'))
+    self.assertExpectationEquals('pass', page_https, StubPlatform('win'))
+
+  # Pages with expectations for a GPU should only return them when running with
+  # that GPU
+  def testGpuExpectations(self):
+    ps = page_set.PageSet()
+    page = page_module.Page('http://test.com/page6.html', ps)
+    self.assertExpectationEquals('fail', page, gpu=VENDOR_NVIDIA)
+    self.assertExpectationEquals('fail', page, gpu=VENDOR_INTEL)
+    self.assertExpectationEquals('pass', page, gpu=VENDOR_AMD)
+
+  # Pages with expectations for a GPU should only return them when running with
+  # that GPU
+  def testGpuDeviceIdExpectations(self):
+    ps = page_set.PageSet()
+    page = page_module.Page('http://test.com/page7.html', ps)
+    self.assertExpectationEquals('fail', page, gpu=VENDOR_NVIDIA, device=0x1001)
+    self.assertExpectationEquals('fail', page, gpu=VENDOR_NVIDIA, device=0x1002)
+    self.assertExpectationEquals('pass', page, gpu=VENDOR_NVIDIA, device=0x1003)
+    self.assertExpectationEquals('pass', page, gpu=VENDOR_AMD, device=0x1001)
+
+  # Pages with multiple expectations should only return them when all criteria
+  # is met
+  def testMultipleExpectations(self):
+    ps = page_set.PageSet()
+    page = page_module.Page('http://test.com/page8.html', ps)
+    self.assertExpectationEquals('fail', page,
+        StubPlatform('win'), VENDOR_AMD, 0x1001)
+    self.assertExpectationEquals('fail', page,
+        StubPlatform('win'), VENDOR_INTEL, 0x1002)
+    self.assertExpectationEquals('pass', page,
+        StubPlatform('win'), VENDOR_NVIDIA, 0x1001)
+    self.assertExpectationEquals('pass', page,
+        StubPlatform('mac'), VENDOR_AMD, 0x1001)
+    self.assertExpectationEquals('pass', page,
+        StubPlatform('win'), VENDOR_AMD, 0x1002)
diff --git a/tools/telemetry/telemetry/test.py b/tools/telemetry/telemetry/test.py
index 3b5bcf3..1cda68a 100644
--- a/tools/telemetry/telemetry/test.py
+++ b/tools/telemetry/telemetry/test.py
@@ -1,7 +1,7 @@
 # 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 optparse
+
 import os
 
 from telemetry.core import repeat_options
@@ -36,7 +36,7 @@
     expectations = self.CreateExpectations(ps)
 
     # Ensure the test's default options are set if needed.
-    parser = optparse.OptionParser()
+    parser = options.CreateParser()
     test.AddCommandLineOptions(parser)
     options.MergeDefaultValues(parser.get_default_values())
 
@@ -72,3 +72,7 @@
       return self.expectations
     else:
       return test_expectations.TestExpectations()
+
+  @staticmethod
+  def AddCommandLineOptions(parser):
+    page_runner.AddCommandLineOptions(parser)
diff --git a/tools/telemetry/telemetry/test_runner.py b/tools/telemetry/telemetry/test_runner.py
index ebae40c..d3c4def 100644
--- a/tools/telemetry/telemetry/test_runner.py
+++ b/tools/telemetry/telemetry/test_runner.py
@@ -93,6 +93,9 @@
     parser = options.CreateParser('%%prog %s %s' % (self.name, self.usage))
     return parser
 
+  def AddParserOptions(self, parser):
+    test.Test.AddCommandLineOptions(parser)
+
   def ValidateCommandLine(self, parser, options, args):
     if not args:
       parser.error('Must provide at least one test name')
diff --git a/tools/telemetry/telemetry/unittest/gtest_testrunner.py b/tools/telemetry/telemetry/unittest/gtest_testrunner.py
index 0d88555..b33bf6e 100755
--- a/tools/telemetry/telemetry/unittest/gtest_testrunner.py
+++ b/tools/telemetry/telemetry/unittest/gtest_testrunner.py
@@ -9,6 +9,7 @@
 designed to be a drop-in replacement for unittest's TextTestRunner.
 """
 
+import sys
 import time
 import unittest
 
@@ -44,7 +45,7 @@
   def run(self, test):
     "Run the given test case or test suite."
     if not self.result:
-      self.result = gtest_test_results.GTestTestResults()
+      self.result = gtest_test_results.GTestTestResults(sys.stdout)
     test(self.result)
     if self.print_result_after_run:
       self.result.PrintSummary()
diff --git a/tools/telemetry/telemetry/unittest/run_tests.py b/tools/telemetry/telemetry/unittest/run_tests.py
index bc8b1b1..89f4ad1 100644
--- a/tools/telemetry/telemetry/unittest/run_tests.py
+++ b/tools/telemetry/telemetry/unittest/run_tests.py
@@ -2,12 +2,11 @@
 # 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 sys
 import unittest
 
 from telemetry.core import browser_options
 from telemetry.core import discover
+from telemetry.core import util
 from telemetry.unittest import gtest_testrunner
 from telemetry.unittest import options_for_unittests
 
@@ -84,9 +83,7 @@
 def Main(args, start_dir, top_level_dir, runner=None):
   """Unit test suite that collects all test cases for telemetry."""
   # Add unittest_data to the path so we can import packages from it.
-  unittest_data_dir = os.path.abspath(os.path.join(
-        os.path.dirname(__file__), '..', '..', 'unittest_data'))
-  sys.path.append(unittest_data_dir)
+  util.AddDirToPythonPath(util.GetUnittestDataDir())
 
   default_options = browser_options.BrowserOptions()
   default_options.browser_type = 'any'
@@ -121,9 +118,7 @@
 
   options_for_unittests.Set(default_options,
                             browser_to_create.browser_type)
-  olddir = os.getcwd()
   try:
-    os.chdir(top_level_dir)
     success = True
     for _ in range(
         default_options.run_test_repeat_count): # pylint: disable=E1101
@@ -133,7 +128,6 @@
     if success:
       return 0
   finally:
-    os.chdir(olddir)
     options_for_unittests.Set(None, None)
     if default_options.verbosity == 0:
       # Restore logging level.
diff --git a/tools/telemetry/telemetry/unittest/simple_mock.py b/tools/telemetry/telemetry/unittest/simple_mock.py
index 6f7afb6..e468460 100644
--- a/tools/telemetry/telemetry/unittest/simple_mock.py
+++ b/tools/telemetry/telemetry/unittest/simple_mock.py
@@ -77,7 +77,7 @@
     return call
 
   def _install_hook(self, func_name):
-    def handler(*args):
+    def handler(*args, **_):
       got_call = MockFunctionCall(
         func_name).WithArgs(*args).WillReturn(DONT_CARE)
       if self._trace.next_call_index >= len(self._trace.expected_calls):
@@ -93,6 +93,3 @@
       return expected_call.return_value
     handler.is_hook = True
     setattr(self, func_name, handler)
-
-
-
diff --git a/tools/telemetry/telemetry/unittest/system_stub.py b/tools/telemetry/telemetry/unittest/system_stub.py
index 4207844..b647f5f 100644
--- a/tools/telemetry/telemetry/unittest/system_stub.py
+++ b/tools/telemetry/telemetry/unittest/system_stub.py
@@ -88,6 +88,9 @@
     def exists(self, path):
       return path in self.files
 
+    def isfile(self, path):
+      return path in self.files
+
     def join(self, *paths):
       def IsAbsolutePath(path):
         if self.sys.platform.startswith('win'):
@@ -115,6 +118,8 @@
     def dirname(self, filename): # pylint: disable=R0201
       return os.path.dirname(filename)
 
+  X_OK = os.X_OK
+
   def __init__(self, sys_module=real_sys):
     self.path = OsModuleStub.OsPathModuleStub(sys_module)
     self.display = ':0'
@@ -123,6 +128,9 @@
     self.program_files_x86 = None
     self.devnull = os.devnull
 
+  def access(self, path, _):
+    return path in self.path.files
+
   def getenv(self, name):
     if name == 'DISPLAY':
       return self.display
diff --git a/tools/telemetry/unittest_data/perf_report_output.txt b/tools/telemetry/unittest_data/perf_report_output.txt
new file mode 100644
index 0000000..d9e9c44
--- /dev/null
+++ b/tools/telemetry/unittest_data/perf_report_output.txt
@@ -0,0 +1,2497 @@
+# ========
+# captured on: Thu Aug 15 09:40:36 2013
+# hostname : tonyg-linux.mtv.corp.google.com
+# os release : 3.2.5-gg1236
+# perf version : 3.2.5
+# arch : x86_64
+# nrcpus online : 32
+# nrcpus avail : 32
+# cpudesc : Intel(R) Xeon(R) CPU E5-2690 0 @ 2.90GHz
+# cpuid : GenuineIntel,6,45,7
+# total memory : 65904780 kB
+# cmdline : /usr/bin/perf_3.2.5-gg1236 record --call-graph --pid 20916 --output /tmp/tmprt1Qz7/http___www_techcrunch_com__001.renderer0 
+# event : name = cycles, type = 0, config = 0x0, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern = 0, id = { 40116, 40117, 40118, 40119, 40120, 40121, 40122, 40123, 40124 }
+# HEADER_CPU_TOPOLOGY info available, use -I to display
+# HEADER_NUMA_TOPOLOGY info available, use -I to display
+# ========
+#
+# Events: 825  cycles
+#
+# Overhead^Period^Command^Shared Object^Symbol
+3.22^96878864^HTMLParserThrea^chrome               ^[.] void v8::internal::RelocInfo::Visit<v8::internal::MarkCompactMarkingVisitor>(v8::internal::Heap*)
+            |
+            --- void v8::internal::RelocInfo::Visit<v8::internal::MarkCompactMarkingVisitor>(v8::internal::Heap*)
+
+2.11^63615201^HTMLParserThrea^chrome               ^[.] v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::MarkMapContents(v8::internal::Heap*, v8::internal::Map*)
+            |
+            --- v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::MarkMapContents(v8::internal::Heap*, v8::internal::Map*)
+
+1.60^48240439^HTMLParserThrea^chrome               ^[.] WebCore::HTMLTokenizer::nextToken(WebCore::SegmentedString&, WebCore::HTMLToken&)
+            |
+            --- WebCore::HTMLTokenizer::nextToken(WebCore::SegmentedString&, WebCore::HTMLToken&)
+               |          
+                --100.00%-- 0x3b2abdf74074
+
+1.53^46054550^HTMLParserThrea^chrome               ^[.] v8::internal::Scanner::ScanIdentifierOrKeyword()
+            |
+            --- v8::internal::Scanner::ScanIdentifierOrKeyword()
+               |          
+               |--33.87%-- 0x3b2abe3e3700
+               |          
+               |--33.85%-- 0x3b2abdf52240
+               |          
+                --32.28%-- 0x3b2abd766000
+
+1.50^45121317^HTMLParserThrea^chrome               ^[.] sk_memset32_SSE2(unsigned int*, unsigned int, int)
+            |
+            --- sk_memset32_SSE2(unsigned int*, unsigned int, int)
+
+1.43^42913933^HTMLParserThrea^chrome               ^[.] v8::internal::LiveRange::CreateAssignedOperand(v8::internal::Zone*)
+            |
+            --- v8::internal::LiveRange::CreateAssignedOperand(v8::internal::Zone*)
+
+1.43^42913933^HTMLParserThrea^chrome               ^[.] v8::internal::LAllocator::MeetConstraintsBetween(v8::internal::LInstruction*, v8::internal::LInstruction*, int)
+            |
+            --- v8::internal::LAllocator::MeetConstraintsBetween(v8::internal::LInstruction*, v8::internal::LInstruction*, int)
+
+1.32^39786862^HTMLParserThrea^chrome               ^[.] v8::internal::HeapObject::Size()
+            |
+            --- v8::internal::HeapObject::Size()
+               |          
+                --100.00%-- 0x1d00000015
+
+1.27^38271931^HTMLParserThrea^chrome               ^[.] v8::internal::RelocIterator::next()
+            |
+            --- v8::internal::RelocIterator::next()
+               |          
+               |--85.80%-- 0x228100000001
+               |          
+                --14.20%-- 0x7fff30e90200
+
+1.06^31909537^HTMLParserThrea^chrome               ^[.] v8::internal::FlexibleBodyVisitor<v8::internal::MarkCompactMarkingVisitor, v8::internal::FixedArray::BodyDescriptor, void>::Visit(v8::internal::Map*, v8::internal::HeapObject*)
+            |
+            --- v8::internal::FlexibleBodyVisitor<v8::internal::MarkCompactMarkingVisitor, v8::internal::FixedArray::BodyDescriptor, void>::Visit(v8::internal::Map*, v8::internal::HeapObject*)
+
+0.98^29461075^HTMLParserThrea^chrome               ^[.] operator new(unsigned long)
+            |
+            --- operator new(unsigned long)
+
+0.88^26612604^HTMLParserThrea^chrome               ^[.] v8::internal::InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(unsigned char*)
+            |
+            --- v8::internal::InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer(unsigned char*)
+
+0.83^25019326^HTMLParserThrea^chrome               ^[.] v8::internal::Scanner::Scan()
+            |
+            --- v8::internal::Scanner::Scan()
+               |          
+               |--31.35%-- 0x7fff30e9065000
+               |          
+               |--25.38%-- 0x7fff30e915a000
+               |          
+               |--22.29%-- 0x7fff30e9081000
+               |          
+                --20.99%-- 0x7fff30e91900
+                          0x900000001
+
+0.80^24225440^HTMLParserThrea^chrome               ^[.] WebCore::TokenPreloadScanner::scan(WebCore::CompactHTMLToken const&, WebCore::SegmentedString const&, WTF::Vector<WTF::OwnPtr<WebCore::PreloadRequest>, 0ul>&)
+            |
+            --- WebCore::TokenPreloadScanner::scan(WebCore::CompactHTMLToken const&, WebCore::SegmentedString const&, WTF::Vector<WTF::OwnPtr<WebCore::PreloadRequest>, 0ul>&)
+
+0.73^22115352^HTMLParserThrea^chrome               ^[.] v8::internal::DescriptorArray::Append(v8::internal::Descriptor*)
+            |
+            --- v8::internal::DescriptorArray::Append(v8::internal::Descriptor*)
+
+0.73^21947849^HTMLParserThrea^chrome               ^[.] v8::internal::HRepresentationChangesPhase::InsertRepresentationChangesForValue(v8::internal::HValue*)
+            |
+            --- v8::internal::HRepresentationChangesPhase::InsertRepresentationChangesForValue(v8::internal::HValue*)
+
+0.72^21805774^HTMLParserThrea^chrome               ^[.] SkBlitLCD16OpaqueRow_SSE2(unsigned int*, unsigned short const*, unsigned int, int, unsigned int)
+            |
+            --- SkBlitLCD16OpaqueRow_SSE2(unsigned int*, unsigned short const*, unsigned int, int, unsigned int)
+
+0.71^21252690^HTMLParserThrea^chrome               ^[.] int v8::internal::Search<(v8::internal::SearchMode)1, v8::internal::DescriptorArray>(v8::internal::DescriptorArray*, v8::internal::Name*, int)
+            |
+            --- int v8::internal::Search<(v8::internal::SearchMode)1, v8::internal::DescriptorArray>(v8::internal::DescriptorArray*, v8::internal::Name*, int)
+
+0.63^18864914^HTMLParserThrea^chrome               ^[.] v8::internal::HashTable<v8::internal::StringTableShape, v8::internal::HashTableKey*>::FindEntry(v8::internal::Isolate*, v8::internal::HashTableKey*)
+            |
+            --- v8::internal::HashTable<v8::internal::StringTableShape, v8::internal::HashTableKey*>::FindEntry(v8::internal::Isolate*, v8::internal::HashTableKey*)
+               |          
+                --100.00%-- 0x3b2abdff2b80
+
+0.56^16917055^HTMLParserThrea^chrome               ^[.] WebCore::LayoutUnit::LayoutUnit(int)
+            |
+            --- WebCore::LayoutUnit::LayoutUnit(int)
+               |          
+                --100.00%-- (nil)
+
+0.54^16308133^HTMLParserThrea^chrome               ^[.] event_base_loop
+            |
+            --- event_base_loop
+                0x7f7a0b959fc0
+                epoll_init
+                0x7265727265666572
+
+0.51^15412114^HTMLParserThrea^chrome               ^[.] tc_malloc
+            |
+            --- tc_malloc
+
+0.51^15239999^HTMLParserThrea^chrome               ^[.] v8::internal::Scanner::Next()
+            |
+            --- v8::internal::Scanner::Next()
+               |          
+               |--23.51%-- 0x7fff30e9054a
+               |          
+               |--23.51%-- 0x7fff30e906ca
+               |          
+               |--23.38%-- (nil)
+               |          
+               |--15.20%-- 0x7fff30e9081000
+               |          
+                --14.39%-- 0x7fff30e9048c
+
+0.47^14231099^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::DoScavenge(v8::internal::ObjectVisitor*, unsigned char*)
+            |
+            --- v8::internal::Heap::DoScavenge(v8::internal::ObjectVisitor*, unsigned char*)
+
+0.47^14229607^HTMLParserThrea^chrome               ^[.] bool WebCore::SelectorChecker::checkOne<WebCore::DOMSiblingTraversalStrategy>(WebCore::SelectorChecker::SelectorCheckingContext const&, WebCore::DOMSiblingTraversalStrategy const&) const
+            |
+            --- bool WebCore::SelectorChecker::checkOne<WebCore::DOMSiblingTraversalStrategy>(WebCore::SelectorChecker::SelectorCheckingContext const&, WebCore::DOMSiblingTraversalStrategy const&) const
+               |          
+               |--25.11%-- 0x1e83176cd048
+               |          
+               |--25.08%-- 0x7f7a0b9980e000
+               |          
+               |--24.93%-- 0x7f7a00000000
+               |          
+                --24.88%-- 0x7f7a0b997c9000
+
+0.46^13955450^HTMLParserThrea^chrome               ^[.] tc_realloc
+            |
+            --- tc_realloc
+
+0.46^13941187^HTMLParserThrea^chrome               ^[.] WebCore::minimumValueForLength(WebCore::Length const&, WebCore::LayoutUnit, WebCore::RenderView*, bool)
+            |
+            --- WebCore::minimumValueForLength(WebCore::Length const&, WebCore::LayoutUnit, WebCore::RenderView*, bool)
+
+0.46^13834654^HTMLParserThrea^chrome               ^[.] v8::internal::JSReceiver::LocalLookup(v8::internal::Name*, v8::internal::LookupResult*, bool)
+            |
+            --- v8::internal::JSReceiver::LocalLookup(v8::internal::Name*, v8::internal::LookupResult*, bool)
+               |          
+               |--33.05%-- 0x7fff30e91860
+               |          
+               |--26.80%-- (nil)
+               |          
+               |--20.72%-- 0x7fff30e91a10
+               |          
+                --19.43%-- 0x7fff30e90860
+
+0.44^13202625^HTMLParserThrea^chrome               ^[.] v8::internal::Expression::Expression(v8::internal::Isolate*)
+            |
+            --- v8::internal::Expression::Expression(v8::internal::Isolate*)
+               |          
+               |--35.68%-- 0x7fff30e9198000
+               |          
+               |--32.51%-- 0x7f7a00000000
+               |          
+                --31.81%-- (nil)
+
+0.44^13149418^HTMLParserThrea^chrome               ^[.] v8::internal::String::IsOneByteEqualTo(v8::internal::Vector<unsigned char const>)
+            |
+            --- v8::internal::String::IsOneByteEqualTo(v8::internal::Vector<unsigned char const>)
+
+0.43^13061272^HTMLParserThrea^chrome               ^[.] event_active
+            |
+            --- event_active
+                0x40
+
+0.43^12899765^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::Name*, v8::internal::LookupResult*)
+            |
+            --- v8::internal::JSObject::LocalLookupRealNamedProperty(v8::internal::Name*, v8::internal::LookupResult*)
+               |          
+               |--79.39%-- (nil)
+               |          
+                --20.61%-- 0x7fff30e90ab0
+
+0.42^12696531^HTMLParserThrea^chrome               ^[.] v8::internal::IsIdentifier(v8::internal::UnicodeCache*, v8::internal::Name*)
+            |
+            --- v8::internal::IsIdentifier(v8::internal::UnicodeCache*, v8::internal::Name*)
+
+0.41^12442842^HTMLParserThrea^chrome               ^[.] v8::internal::PointersUpdatingVisitor::VisitPointers(v8::internal::Object**, v8::internal::Object**)
+            |
+            --- v8::internal::PointersUpdatingVisitor::VisitPointers(v8::internal::Object**, v8::internal::Object**)
+
+0.41^12212739^HTMLParserThrea^chrome               ^[.] v8::internal::StubCompiler::CheckPrototypes(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Register, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Register, v8::internal::Register, v8::internal::Register, v8::internal::Handle<v8::internal::Name>, int, v8::internal::Label*, v8::internal::PrototypeCheckType)
+            |
+            --- v8::internal::StubCompiler::CheckPrototypes(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Register, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Register, v8::internal::Register, v8::internal::Register, v8::internal::Handle<v8::internal::Name>, int, v8::internal::Label*, v8::internal::PrototypeCheckType)
+               |          
+                --100.00%-- 0x29f988404121
+
+0.40^11929902^HTMLParserThrea^chrome               ^[.] _ZN2v88internal12BinarySearchILNS0_10SearchModeE1ENS0_15DescriptorArrayEEEiPT0_PNS0_4NameEiii.constprop.530
+            |
+            --- _ZN2v88internal12BinarySearchILNS0_10SearchModeE1ENS0_15DescriptorArrayEEEiPT0_PNS0_4NameEiii.constprop.530
+
+0.36^10844486^HTMLParserThrea^chrome               ^[.] content::VideoCaptureMessageFilter::OnMessageReceived(IPC::Message const&)
+            |
+            --- content::VideoCaptureMessageFilter::OnMessageReceived(IPC::Message const&)
+                0xfffffffc0000000e
+                IPC::ChannelProxy::Context::OnChannelConnected(int)
+                0x6c894cfb8948d824
+
+0.36^10745270^HTMLParserThrea^chrome               ^[.] v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitJSFunctionStrongCode(v8::internal::Heap*, v8::internal::HeapObject*)
+            |
+            --- v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitJSFunctionStrongCode(v8::internal::Heap*, v8::internal::HeapObject*)
+
+0.36^10717680^HTMLParserThrea^chrome               ^[.] v8::internal::TemplateHashMapImpl<v8::internal::ZoneAllocationPolicy>::Lookup(void*, unsigned int, bool, v8::internal::ZoneAllocationPolicy)
+            |
+            --- v8::internal::TemplateHashMapImpl<v8::internal::ZoneAllocationPolicy>::Lookup(void*, unsigned int, bool, v8::internal::ZoneAllocationPolicy)
+
+0.36^10710349^HTMLParserThrea^chrome               ^[.] v8::internal::Code::CopyFrom(v8::internal::CodeDesc const&)
+            |
+            --- v8::internal::Code::CopyFrom(v8::internal::CodeDesc const&)
+
+0.35^10674297^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseBinaryExpression(int, bool, bool*)
+            |
+            --- v8::internal::Parser::ParseBinaryExpression(int, bool, bool*)
+               |          
+               |--66.59%-- (nil)
+               |          
+                --33.41%-- 0x7f7a0b98e010
+
+0.35^10650066^HTMLParserThrea^chrome               ^[.] WebCore::SelectorFilter::pushParentStackFrame(WebCore::Element*)
+            |
+            --- WebCore::SelectorFilter::pushParentStackFrame(WebCore::Element*)
+
+0.35^10614251^HTMLParserThrea^libc-2.15.so         ^[.] __memcpy_ssse3_back
+            |
+            --- __memcpy_ssse3_back
+
+0.35^10611142^HTMLParserThrea^chrome               ^[.] v8::internal::GlobalHandles::ComputeObjectGroupsAndImplicitReferences()
+            |
+            --- v8::internal::GlobalHandles::ComputeObjectGroupsAndImplicitReferences()
+
+0.35^10527946^HTMLParserThrea^chrome               ^[.] tcmalloc::FL_PopRange(void**, int, void**, void**)
+            |
+            --- tcmalloc::FL_PopRange(void**, int, void**, void**)
+
+0.35^10514181^HTMLParserThrea^libpthread-2.15.so   ^[.] pthread_getspecific
+            |
+            --- pthread_getspecific
+
+0.35^10497704^HTMLParserThrea^chrome               ^[.] v8::internal::IC::PostPatching(unsigned char*, v8::internal::Code*, v8::internal::Code*)
+            |
+            --- v8::internal::IC::PostPatching(unsigned char*, v8::internal::Code*, v8::internal::Code*)
+
+0.35^10452932^HTMLParserThrea^chrome               ^[.] _ZN2v88internal12StringHasher13AddCharactersIhEEvPKT_i.constprop.518
+            |
+            --- _ZN2v88internal12StringHasher13AddCharactersIhEEvPKT_i.constprop.518
+
+0.35^10426463^HTMLParserThrea^chrome               ^[.] _ZN2v88internalL13LookupForReadENS0_6HandleINS0_6ObjectEEENS1_INS0_6StringEEEPNS0_12LookupResultE.constprop.171
+            |
+            --- _ZN2v88internalL13LookupForReadENS0_6HandleINS0_6ObjectEEENS1_INS0_6StringEEEPNS0_12LookupResultE.constprop.171
+               |          
+               |--65.70%-- (nil)
+               |          
+                --34.30%-- 0x7fff30e91e38
+
+0.34^10228287^HTMLParserThrea^chrome               ^[.] WTF::Unicode::convertLatin1ToUTF8(unsigned char const**, unsigned char const*, char**, char*)
+            |
+            --- WTF::Unicode::convertLatin1ToUTF8(unsigned char const**, unsigned char const*, char**, char*)
+               |          
+               |--34.63%-- 0x3b2abdeedb48
+               |          
+               |--32.97%-- webkit_glue::(anonymous namespace)::HeaderFlattener::visitHeader(WebKit::WebString const&, WebKit::WebString const&)
+               |          0x3b2abdfe9230
+               |          
+                --32.40%-- void WTF::StringBuilder::reallocateBuffer<unsigned char>(unsigned int)
+
+0.34^10139628^HTMLParserThrea^chrome               ^[.] base::subtle::RefCountedThreadSafeBase::Release() const
+            |
+            --- base::subtle::RefCountedThreadSafeBase::Release() const
+               |          
+               |--63.45%-- base::internal::Invoker<1, base::internal::BindState<base::internal::RunnableAdapter<void (base::BaseTimerTaskInternal::*)()>, void ()(base::BaseTimerTaskInternal*), void ()(base::internal::OwnedWrapper<base::BaseTimerTaskInternal>)>, void ()(base::BaseTimerTaskInternal*)>::Run(base::internal::BindStateBase*)
+               |          
+                --36.55%-- 0x7f7a0b8ff200
+
+0.33^9932889^HTMLParserThrea^chrome               ^[.] void WebCore::StyleResolver::applyProperties<(WebCore::StyleResolver::StyleApplicationPass)1>(WebCore::StyleResolverState&, WebCore::StylePropertySet const*, WebCore::StyleRule*, bool, bool, WebCore::PropertyWhitelistType)
+            |
+            --- void WebCore::StyleResolver::applyProperties<(WebCore::StyleResolver::StyleApplicationPass)1>(WebCore::StyleResolverState&, WebCore::StylePropertySet const*, WebCore::StyleRule*, bool, bool, WebCore::PropertyWhitelistType)
+
+0.33^9928749^HTMLParserThrea^chrome               ^[.] v8::internal::CodeStub::GetCode(v8::internal::Isolate*)
+            |
+            --- v8::internal::CodeStub::GetCode(v8::internal::Isolate*)
+
+0.33^9868335^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateSharedFunctionInfo(v8::internal::Object*)
+            |
+            --- v8::internal::Heap::AllocateSharedFunctionInfo(v8::internal::Object*)
+
+0.33^9807337^HTMLParserThrea^chrome               ^[.] v8::internal::Zone::New(int)
+            |
+            --- v8::internal::Zone::New(int)
+               |          
+                --100.00%-- 0x7fff30e91d48
+
+0.32^9579492^HTMLParserThrea^chrome               ^[.] v8::internal::Object::GetProperty(v8::internal::Object*, v8::internal::LookupResult*, v8::internal::Name*, PropertyAttributes*)
+            |
+            --- v8::internal::Object::GetProperty(v8::internal::Object*, v8::internal::LookupResult*, v8::internal::Name*, PropertyAttributes*)
+               |          
+               |--58.83%-- 0x2281c1418f41
+               |          
+                --41.17%-- (nil)
+
+0.32^9578890^HTMLParserThrea^chrome               ^[.] _ZN2v88internal15DescriptorArray3SetEiPNS0_10DescriptorERKNS1_16WhitenessWitnessE.isra.252
+            |
+            --- _ZN2v88internal15DescriptorArray3SetEiPNS0_10DescriptorERKNS1_16WhitenessWitnessE.isra.252
+
+0.31^9412432^HTMLParserThrea^chrome               ^[.] WebCore::ScrollView::unscaledVisibleContentSize(WebCore::ScrollableArea::VisibleContentRectIncludesScrollbars) const
+            |
+            --- WebCore::ScrollView::unscaledVisibleContentSize(WebCore::ScrollableArea::VisibleContentRectIncludesScrollbars) const
+
+0.31^9384389^HTMLParserThrea^chrome               ^[.] v8::internal::CallICBase::ReceiverToObjectIfRequired(v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>)
+            |
+            --- v8::internal::CallICBase::ReceiverToObjectIfRequired(v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>)
+               |          
+               |--37.40%-- 0x2281c141ab41
+               |          
+               |--35.85%-- 0x2281c1419541
+               |          
+                --26.75%-- 0x2281c141a941
+
+0.31^9309826^HTMLParserThrea^chrome               ^[.] v8::internal::Factory::NewFunctionFromSharedFunctionInfo(v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Handle<v8::internal::Context>, v8::internal::PretenureFlag)
+            |
+            --- v8::internal::Factory::NewFunctionFromSharedFunctionInfo(v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Handle<v8::internal::Context>, v8::internal::PretenureFlag)
+
+0.31^9238181^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseAssignmentExpression(bool, bool*)
+            |
+            --- v8::internal::Parser::ParseAssignmentExpression(bool, bool*)
+               |          
+               |--73.43%-- (nil)
+               |          
+                --26.57%-- 0x7fff30e9136000
+
+0.30^9076438^HTMLParserThrea^chrome               ^[.] WebCore::RenderObject* WebCore::bidiNextShared<WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun> >(WebCore::RenderObject*, WebCore::RenderObject*, WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>*, WebCore::EmptyInlineBehavior, bool*)
+            |
+            --- WebCore::RenderObject* WebCore::bidiNextShared<WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun> >(WebCore::RenderObject*, WebCore::RenderObject*, WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>*, WebCore::EmptyInlineBehavior, bool*)
+               |          
+                --100.00%-- 0x3b2abd841928
+
+0.30^8941888^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateStruct(v8::internal::InstanceType)
+            |
+            --- v8::internal::Heap::AllocateStruct(v8::internal::InstanceType)
+
+0.29^8602723^HTMLParserThrea^chrome               ^[.] v8::internal::LoadIC::ComputeLoadHandler(v8::internal::LookupResult*, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::String>)
+            |
+            --- v8::internal::LoadIC::ComputeLoadHandler(v8::internal::LookupResult*, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::String>)
+               |          
+                --100.00%-- 0x7fff30e90648
+
+0.28^8470525^HTMLParserThrea^chrome               ^[.] void v8::internal::String::WriteToFlat<unsigned char>(v8::internal::String*, unsigned char*, int, int)
+            |
+            --- void v8::internal::String::WriteToFlat<unsigned char>(v8::internal::String*, unsigned char*, int, int)
+
+0.28^8366209^HTMLParserThrea^chrome               ^[.] WTF::StringImpl::hashSlowCase() const
+            |
+            --- WTF::StringImpl::hashSlowCase() const
+               |          
+               |--36.45%-- 0x7f7a11ebab98
+               |          0x7f7a0b9bd000
+               |          
+               |--33.90%-- 0xfffe02a2
+               |          0x1e83176903e8
+               |          
+                --29.65%-- 0x3b2abd1fa100
+
+0.27^8156738^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime_ParallelRecompile(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::Runtime_ParallelRecompile(int, v8::internal::Object**, v8::internal::Isolate*)
+                0x2281c142b871
+                0x2281c1f35545
+                0x2281c1f31dba
+                0x2281c140e854
+                0x2281c142b65e
+                0x2281c1417d97
+                v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)
+
+0.27^8131676^HTMLParserThrea^chrome               ^[.] v8::internal::FixedArray::set(int, v8::internal::Object*)
+            |
+            --- v8::internal::FixedArray::set(int, v8::internal::Object*)
+
+0.27^8075110^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateRaw(int, v8::internal::AllocationSpace, v8::internal::AllocationSpace)
+            |
+            --- v8::internal::Heap::AllocateRaw(int, v8::internal::AllocationSpace, v8::internal::AllocationSpace)
+
+0.26^7972021^HTMLParserThrea^chrome               ^[.] WebCore::MarkupAccumulator::appendCharactersReplacingEntities(WTF::StringBuilder&, WTF::String const&, unsigned int, unsigned int, WebCore::EntityMask)
+            |
+            --- WebCore::MarkupAccumulator::appendCharactersReplacingEntities(WTF::StringBuilder&, WTF::String const&, unsigned int, unsigned int, WebCore::EntityMask)
+
+0.25^7610316^HTMLParserThrea^chrome               ^[.] _ZN12_GLOBAL__N_121do_free_with_callbackEPvPFvS0_E.constprop.42
+            |
+            --- _ZN12_GLOBAL__N_121do_free_with_callbackEPvPFvS0_E.constprop.42
+
+0.25^7488722^HTMLParserThrea^chrome               ^[.] WebCore::NodeListV8Internal::indexedPropertyGetterCallback(unsigned int, v8::PropertyCallbackInfo<v8::Value> const&)
+            |
+            --- WebCore::NodeListV8Internal::indexedPropertyGetterCallback(unsigned int, v8::PropertyCallbackInfo<v8::Value> const&)
+                0x7f7a0b900000
+               |          
+                --100.00%-- 0x7f7a0b900000
+
+0.25^7420533^HTMLParserThrea^chrome               ^[.] webkit_glue::WebThreadBase::TaskObserverAdapter::DidProcessTask(base::PendingTask const&)
+            |
+            --- webkit_glue::WebThreadBase::TaskObserverAdapter::DidProcessTask(base::PendingTask const&)
+                0x7f7a0b8ff200
+
+0.24^7201464^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::computeRectForRepaint(WebCore::RenderLayerModelObject const*, WebCore::LayoutRect&, bool) const
+            |
+            --- WebCore::RenderBox::computeRectForRepaint(WebCore::RenderLayerModelObject const*, WebCore::LayoutRect&, bool) const
+               |          
+               |--50.28%-- 0x124000002bc0
+               |          
+                --49.72%-- 0x194000003e80
+
+0.24^7186236^HTMLParserThrea^chrome               ^[.] v8::internal::StoreBuffer::IteratePointersInStoreBuffer(void (*)(v8::internal::HeapObject**, v8::internal::HeapObject*), bool)
+            |
+            --- v8::internal::StoreBuffer::IteratePointersInStoreBuffer(void (*)(v8::internal::HeapObject**, v8::internal::HeapObject*), bool)
+
+0.24^7180913^HTMLParserThrea^chrome               ^[.] v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitJSFunction(v8::internal::Map*, v8::internal::HeapObject*)
+            |
+            --- v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitJSFunction(v8::internal::Map*, v8::internal::HeapObject*)
+
+0.24^7180572^HTMLParserThrea^chrome               ^[.] v8::internal::MarkCompactCollector::ClearNonLivePrototypeTransitions(v8::internal::Map*)
+            |
+            --- v8::internal::MarkCompactCollector::ClearNonLivePrototypeTransitions(v8::internal::Map*)
+
+0.24^7178618^HTMLParserThrea^chrome               ^[.] v8::internal::MarkCompactCollector::SweepSpace(v8::internal::PagedSpace*, v8::internal::MarkCompactCollector::SweeperType)
+            |
+            --- v8::internal::MarkCompactCollector::SweepSpace(v8::internal::PagedSpace*, v8::internal::MarkCompactCollector::SweeperType)
+
+0.24^7154254^HTMLParserThrea^chrome               ^[.] WTF::HashTableConstIterator<WebCore::RenderObject const*, WebCore::RenderObject const*, WTF::IdentityExtractor, WTF::PtrHash<WebCore::RenderObject const*>, WTF::HashTraits<WebCore::RenderObject const*>, WTF::HashTraits<WebCore::RenderObject const*> > WTF::HashTable<WebCore::RenderObject const*, WebCore::RenderObject const*, WTF::IdentityExtractor, WTF::PtrHash<WebCore::RenderObject const*>, WTF::HashTraits<WebCore::RenderObject const*>, WTF::HashTraits
+            |
+            --- WTF::HashTableConstIterator<WebCore::RenderObject const*, WebCore::RenderObject const*, WTF::IdentityExtractor, WTF::PtrHash<WebCore::RenderObject const*>, WTF::HashTraits<WebCore::RenderObject const*>, WTF::HashTraits<WebCore::RenderObject const*> > WTF::HashTable<WebCore::RenderObject const*, WebCore::RenderObject const*, WTF::IdentityExtractor, WTF::PtrHash<WebCore::RenderObject const*>, WTF::HashTraits<WebCore::RenderObject const*>, WTF::HashTraits<WebCore::RenderObject const*> >::find<WTF::IdentityHashTranslator<WTF::PtrHash<WebCore::RenderObject const*> >, WebCore::RenderObject const*>(WebCore::RenderObject const* const&) const
+
+0.24^7150261^HTMLParserThrea^chrome               ^[.] void url_parse::(anonymous namespace)::DoParseAuthority<char>(char const*, url_parse::Component const&, url_parse::Component*, url_parse::Component*, url_parse::Component*, url_parse::Component*)
+            |
+            --- void url_parse::(anonymous namespace)::DoParseAuthority<char>(char const*, url_parse::Component const&, url_parse::Component*, url_parse::Component*, url_parse::Component*, url_parse::Component*)
+               |          
+                --100.00%-- 0xffffffff00000000
+
+0.24^7147589^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateFixedArray(int)
+            |
+            --- v8::internal::Heap::AllocateFixedArray(int)
+
+0.24^7145279^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::MustAllocate(v8::internal::Variable*)
+            |
+            --- v8::internal::Scope::MustAllocate(v8::internal::Variable*)
+
+0.24^7140300^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::fillAvailableMeasure(WebCore::LayoutUnit, WebCore::LayoutUnit&, WebCore::LayoutUnit&) const
+            |
+            --- WebCore::RenderBox::fillAvailableMeasure(WebCore::LayoutUnit, WebCore::LayoutUnit&, WebCore::LayoutUnit&) const
+
+0.24^7139300^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::computeInlinePreferredLogicalWidths(WebCore::LayoutUnit&, WebCore::LayoutUnit&)
+            |
+            --- WebCore::RenderBlock::computeInlinePreferredLogicalWidths(WebCore::LayoutUnit&, WebCore::LayoutUnit&)
+
+0.24^7134579^HTMLParserThrea^chrome               ^[.] v8::internal::Scanner::ScanString()
+            |
+            --- v8::internal::Scanner::ScanString()
+
+0.24^7132161^HTMLParserThrea^chrome               ^[.] WebCore::ElementRuleCollector::collectRuleIfMatches(WebCore::RuleData const&, WebCore::MatchRequest const&, WebCore::RuleRange&)
+            |
+            --- WebCore::ElementRuleCollector::collectRuleIfMatches(WebCore::RuleData const&, WebCore::MatchRequest const&, WebCore::RuleRange&)
+
+0.24^7127556^HTMLParserThrea^chrome               ^[.] v8::internal::TemplateHashMapImpl<v8::internal::FreeStoreAllocationPolicy>::Lookup(void*, unsigned int, bool, v8::internal::FreeStoreAllocationPolicy)
+            |
+            --- v8::internal::TemplateHashMapImpl<v8::internal::FreeStoreAllocationPolicy>::Lookup(void*, unsigned int, bool, v8::internal::FreeStoreAllocationPolicy)
+
+0.24^7124874^HTMLParserThrea^chrome               ^[.] url_canon::RemoveURLWhitespace(char const*, int, url_canon::CanonOutputT<char>*, int*)
+            |
+            --- url_canon::RemoveURLWhitespace(char const*, int, url_canon::CanonOutputT<char>*, int*)
+
+0.24^7120126^HTMLParserThrea^chrome               ^[.] v8::internal::RelocInfoWriter::Write(v8::internal::RelocInfo const*)
+            |
+            --- v8::internal::RelocInfoWriter::Write(v8::internal::RelocInfo const*)
+
+0.24^7115866^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseMemberWithNewPrefixesExpression(v8::internal::PositionStack*, bool*)
+            |
+            --- v8::internal::Parser::ParseMemberWithNewPrefixesExpression(v8::internal::PositionStack*, bool*)
+               |          
+               |--50.15%-- 0x7fff30e9065000
+               |          
+                --49.85%-- 0x7fff30e914d000
+
+0.24^7113138^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::AddFastPropertyUsingMap(v8::internal::Map*, v8::internal::Name*, v8::internal::Object*, int, v8::internal::Representation)
+            |
+            --- v8::internal::JSObject::AddFastPropertyUsingMap(v8::internal::Map*, v8::internal::Name*, v8::internal::Object*, int, v8::internal::Representation)
+
+0.24^7106943^HTMLParserThrea^chrome               ^[.] v8::internal::StoreBuffer::Compact()
+            |
+            --- v8::internal::StoreBuffer::Compact()
+
+0.24^7104154^HTMLParserThrea^chrome               ^[.] WebCore::VisitedLinkState::determineLinkStateSlowCase(WebCore::Element*)
+            |
+            --- WebCore::VisitedLinkState::determineLinkStateSlowCase(WebCore::Element*)
+
+0.24^7089266^HTMLParserThrea^chrome               ^[.] WebCore::selectorIdentifierHash(WebCore::CSSSelector const*)
+            |
+            --- WebCore::selectorIdentifierHash(WebCore::CSSSelector const*)
+
+0.24^7086923^HTMLParserThrea^chrome               ^[.] v8::internal::InnerPointerToCodeCache::GetCacheEntry(unsigned char*)
+            |
+            --- v8::internal::InnerPointerToCodeCache::GetCacheEntry(unsigned char*)
+               |          
+                --100.00%-- 0x7fff30e912c0
+                          0xc6a3430a8a9
+
+0.24^7081815^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseUnaryExpression(bool*)
+            |
+            --- v8::internal::Parser::ParseUnaryExpression(bool*)
+                (nil)
+
+0.24^7079188^HTMLParserThrea^chrome               ^[.] WebCore::SelectorFilter::fastRejectSelector(WebCore::CSSSelector const*) const
+            |
+            --- WebCore::SelectorFilter::fastRejectSelector(WebCore::CSSSelector const*) const
+
+0.24^7077714^HTMLParserThrea^chrome               ^[.] v8::internal::CallICBase::LoadFunction(v8::internal::InlineCacheState, int, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::String>)
+            |
+            --- v8::internal::CallICBase::LoadFunction(v8::internal::InlineCacheState, int, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::String>)
+               |          
+               |--50.54%-- 0x7fff30e90d30
+               |          
+                --49.46%-- 0x7fff30e90270
+
+0.23^7065769^HTMLParserThrea^chrome               ^[.] WebCore::RenderBoxModelObject::computedCSSPadding(WebCore::Length) const
+            |
+            --- WebCore::RenderBoxModelObject::computedCSSPadding(WebCore::Length) const
+
+0.23^7059576^HTMLParserThrea^chrome               ^[.] v8::internal::Deserializer::ReadChunk(v8::internal::Object**, v8::internal::Object**, int, unsigned char*)
+            |
+            --- v8::internal::Deserializer::ReadChunk(v8::internal::Object**, v8::internal::Object**, int, unsigned char*)
+                0x7f7a0b900000
+
+0.23^7058229^HTMLParserThrea^chrome               ^[.] visitedlink::VisitedLinkCommon::IsVisited(unsigned long) const
+            |
+            --- visitedlink::VisitedLinkCommon::IsVisited(unsigned long) const
+
+0.23^7051436^HTMLParserThrea^chrome               ^[.] v8::internal::AllocateFixedArrayWithFiller(v8::internal::Heap*, int, v8::internal::PretenureFlag, v8::internal::Object*)
+            |
+            --- v8::internal::AllocateFixedArrayWithFiller(v8::internal::Heap*, int, v8::internal::PretenureFlag, v8::internal::Object*)
+
+0.23^7043481^HTMLParserThrea^chrome               ^[.] v8::internal::FuncNameInferrer::PushLiteralName(v8::internal::Handle<v8::internal::String>)
+            |
+            --- v8::internal::FuncNameInferrer::PushLiteralName(v8::internal::Handle<v8::internal::String>)
+
+0.23^7023232^HTMLParserThrea^chrome               ^[.] v8::internal::VariableProxy::VariableProxy(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>, bool, v8::internal::Interface*, int)
+            |
+            --- v8::internal::VariableProxy::VariableProxy(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>, bool, v8::internal::Interface*, int)
+               |          
+                --100.00%-- 0x7fff30e90ed8
+
+0.23^7022335^HTMLParserThrea^chrome               ^[.] WebCore::V8CSSStyleDeclaration::createWrapper(WTF::PassRefPtr<WebCore::CSSStyleDeclaration>, v8::Handle<v8::Object>, v8::Isolate*)
+            |
+            --- WebCore::V8CSSStyleDeclaration::createWrapper(WTF::PassRefPtr<WebCore::CSSStyleDeclaration>, v8::Handle<v8::Object>, v8::Isolate*)
+                0x7f7a0b93a3c0
+
+0.23^7015773^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::LineBreaker::nextSegmentBreak(WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>&, WebCore::LineInfo&, WebCore::RenderBlock::RenderTextInfo&, WebCore::RenderBlock::FloatingObject*, unsigned int, WTF::Vector<WebCore::WordMeasurement, 64ul>&)
+            |
+            --- WebCore::RenderBlock::LineBreaker::nextSegmentBreak(WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>&, WebCore::LineInfo&, WebCore::RenderBlock::RenderTextInfo&, WebCore::RenderBlock::FloatingObject*, unsigned int, WTF::Vector<WebCore::WordMeasurement, 64ul>&)
+
+0.23^7009841^HTMLParserThrea^chrome               ^[.] v8::internal::CodeCache::LookupDefaultCache(v8::internal::Name*, unsigned int)
+            |
+            --- v8::internal::CodeCache::LookupDefaultCache(v8::internal::Name*, unsigned int)
+
+0.23^6940000^HTMLParserThrea^chrome               ^[.] v8::internal::PositionsRecorder::RecordPosition(int)
+            |
+            --- v8::internal::PositionsRecorder::RecordPosition(int)
+
+0.23^6866416^HTMLParserThrea^chrome               ^[.] _ZN2v88internal6Parser25ParseVariableDeclarationsENS1_26VariableDeclarationContextEPNS1_29VariableDeclarationPropertiesEPNS0_8ZoneListINS0_6HandleINS0_6StringEEEEEPS8_Pb.constprop.454
+            |
+            --- _ZN2v88internal6Parser25ParseVariableDeclarationsENS1_26VariableDeclarationContextEPNS1_29VariableDeclarationPropertiesEPNS0_8ZoneListINS0_6HandleINS0_6StringEEEEEPS8_Pb.constprop.454
+
+0.23^6858851^HTMLParserThrea^chrome               ^[.] S32A_Opaque_BlitRow32_SSE2(unsigned int*, unsigned int const*, int, unsigned int)
+            |
+            --- S32A_Opaque_BlitRow32_SSE2(unsigned int*, unsigned int const*, int, unsigned int)
+
+0.23^6846415^HTMLParserThrea^chrome               ^[.] v8::internal::String::SlowEquals(v8::internal::String*)
+            |
+            --- v8::internal::String::SlowEquals(v8::internal::String*)
+
+0.22^6771375^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::Expect(v8::internal::Token::Value, bool*)
+            |
+            --- v8::internal::Parser::Expect(v8::internal::Token::Value, bool*)
+               |          
+               |--52.15%-- 0x7fff30e905d002
+               |          
+                --47.85%-- (nil)
+
+0.22^6645010^HTMLParserThrea^chrome               ^[.] v8::internal::DeoptimizerData::FindDeoptimizingCode(unsigned char*)
+            |
+            --- v8::internal::DeoptimizerData::FindDeoptimizingCode(unsigned char*)
+
+0.22^6627879^HTMLParserThrea^chrome               ^[.] v8::internal::StoreIC::Store(v8::internal::InlineCacheState, v8::internal::StrictModeFlag, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::Object>, v8::internal::JSReceiver::StoreFromKeyed)
+            |
+            --- v8::internal::StoreIC::Store(v8::internal::InlineCacheState, v8::internal::StrictModeFlag, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::Object>, v8::internal::JSReceiver::StoreFromKeyed)
+               |          
+               |--53.63%-- 0xc6a34268609
+               |          
+                --46.37%-- 0xc6a34ea2a81
+
+0.22^6600293^HTMLParserThrea^chrome               ^[.] WTF::HashTableAddResult<WTF::HashTableIterator<WTF::AtomicString, WTF::AtomicString, WTF::IdentityExtractor, WTF::AtomicStringHash, WTF::HashTraits<WTF::AtomicString>, WTF::HashTraits<WTF::AtomicString> > > WTF::HashTable<WTF::AtomicString, WTF::AtomicString, WTF::IdentityExtractor, WTF::AtomicStringHash, WTF::HashTraits<WTF::AtomicString>, WTF::HashTraits<WTF::AtomicString> >::add<WTF::IdentityHashTranslator<WTF::AtomicStringHash>, WTF::AtomicString, 
+            |
+            --- WTF::HashTableAddResult<WTF::HashTableIterator<WTF::AtomicString, WTF::AtomicString, WTF::IdentityExtractor, WTF::AtomicStringHash, WTF::HashTraits<WTF::AtomicString>, WTF::HashTraits<WTF::AtomicString> > > WTF::HashTable<WTF::AtomicString, WTF::AtomicString, WTF::IdentityExtractor, WTF::AtomicStringHash, WTF::HashTraits<WTF::AtomicString>, WTF::HashTraits<WTF::AtomicString> >::add<WTF::IdentityHashTranslator<WTF::AtomicStringHash>, WTF::AtomicString, WTF::AtomicString>(WTF::AtomicString const&, WTF::AtomicString const&)
+
+0.22^6596875^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::bind(v8::internal::Label*)
+            |
+            --- v8::internal::Assembler::bind(v8::internal::Label*)
+
+0.22^6594480^HTMLParserThrea^chrome               ^[.] WebCore::InspectorInstrumentation::instrumentingAgentsForPage(WebCore::Page*)
+            |
+            --- WebCore::InspectorInstrumentation::instrumentingAgentsForPage(WebCore::Page*)
+
+0.22^6579973^HTMLParserThrea^chrome               ^[.] v8::internal::IC::PatchCache(v8::internal::InlineCacheState, v8::internal::StrictModeFlag, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::Code>)
+            |
+            --- v8::internal::IC::PatchCache(v8::internal::InlineCacheState, v8::internal::StrictModeFlag, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::Code>)
+               |          
+               |--54.27%-- 0x29f988404121
+               |          
+                --45.73%-- 0xc6a3487f2f1
+
+0.22^6576754^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::movq(v8::internal::Register, v8::internal::Handle<v8::internal::Object>, v8::internal::RelocInfo::Mode)
+            |
+            --- v8::internal::Assembler::movq(v8::internal::Register, v8::internal::Handle<v8::internal::Object>, v8::internal::RelocInfo::Mode)
+
+0.22^6564875^HTMLParserThrea^libpthread-2.15.so   ^[.] pthread_mutex_lock
+            |
+            --- pthread_mutex_lock
+
+0.22^6559671^HTMLParserThrea^chrome               ^[.] v8::internal::VariableProxy::node_type() const
+            |
+            --- v8::internal::VariableProxy::node_type() const
+
+0.22^6543901^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime_NewClosure(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::Runtime_NewClosure(int, v8::internal::Object**, v8::internal::Isolate*)
+               |          
+                --100.00%-- 0x2281c1ab1279
+                          0x2281c142b664
+                          0x2281c1417d97
+                          v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)
+
+0.22^6487316^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateConsString(v8::internal::String*, v8::internal::String*)
+            |
+            --- v8::internal::Heap::AllocateConsString(v8::internal::String*, v8::internal::String*)
+
+0.21^6470256^HTMLParserThrea^chrome               ^[.] v8::internal::StringTable::LookupOneByteString(v8::internal::Vector<unsigned char const>, v8::internal::Object**)
+            |
+            --- v8::internal::StringTable::LookupOneByteString(v8::internal::Vector<unsigned char const>, v8::internal::Object**)
+
+0.21^6461476^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::SetLocalPropertyIgnoreAttributes(v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::Object::ValueType)
+            |
+            --- v8::internal::JSObject::SetLocalPropertyIgnoreAttributes(v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::Object::ValueType)
+
+0.21^6410633^HTMLParserThrea^chrome               ^[.] v8::internal::BaseLoadStoreStubCompiler::CompilePolymorphicIC(v8::internal::List<v8::internal::Handle<v8::internal::Map>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::List<v8::internal::Handle<v8::internal::Code>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::Handle<v8::internal::Name>, v8::internal::Code::StubType, v8::internal::IcCheckType)
+            |
+            --- v8::internal::BaseLoadStoreStubCompiler::CompilePolymorphicIC(v8::internal::List<v8::internal::Handle<v8::internal::Map>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::List<v8::internal::Handle<v8::internal::Code>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::Handle<v8::internal::Name>, v8::internal::Code::StubType, v8::internal::IcCheckType)
+                0x7f7a0b900000
+
+0.21^6354296^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseExpressionOrLabelledStatement(v8::internal::ZoneList<v8::internal::Handle<v8::internal::String> >*, bool*)
+            |
+            --- v8::internal::Parser::ParseExpressionOrLabelledStatement(v8::internal::ZoneList<v8::internal::Handle<v8::internal::String> >*, bool*)
+               |          
+               |--55.30%-- 0x7fff30e9145000
+               |          
+                --44.70%-- 0x7fff30e906e000
+
+0.21^6319435^HTMLParserThrea^chrome               ^[.] _ZN2v88internal14NameDictionary9FindEntryEPNS0_4NameE.part.385
+            |
+            --- _ZN2v88internal14NameDictionary9FindEntryEPNS0_4NameE.part.385
+               |          
+                --100.00%-- (nil)
+
+0.21^6243685^HTMLParserThrea^chrome               ^[.] WebCore::Font::glyphDataAndPageForCharacter(int, bool, WebCore::FontDataVariant) const
+            |
+            --- WebCore::Font::glyphDataAndPageForCharacter(int, bool, WebCore::FontDataVariant) const
+                0x7fff30e8f0e0
+
+0.20^6145083^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::AccumulatorValueContext::Plug(v8::internal::Register) const
+            |
+            --- v8::internal::FullCodeGenerator::AccumulatorValueContext::Plug(v8::internal::Register) const
+
+0.20^6137312^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::SetPropertyForResult(v8::internal::LookupResult*, v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::StrictModeFlag, v8::internal::JSReceiver::StoreFromKeyed)
+            |
+            --- v8::internal::JSObject::SetPropertyForResult(v8::internal::LookupResult*, v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::StrictModeFlag, v8::internal::JSReceiver::StoreFromKeyed)
+
+0.20^6135468^HTMLParserThrea^chrome               ^[.] v8::internal::Factory::NewNumber(double, v8::internal::PretenureFlag)
+            |
+            --- v8::internal::Factory::NewNumber(double, v8::internal::PretenureFlag)
+               |          
+                --100.00%-- 0x7fff30e9160000
+
+0.20^6051127^HTMLParserThrea^chrome               ^[.] WebCore::WidthIterator::glyphDataForCharacter(int, bool, int, unsigned int&)
+            |
+            --- WebCore::WidthIterator::glyphDataForCharacter(int, bool, int, unsigned int&)
+               |          
+               |--58.44%-- 0x7fff30e8cfa0
+               |          
+                --41.56%-- 0x7fff30e8f550
+
+0.20^6000454^HTMLParserThrea^chrome               ^[.] v8::internal::CodeCache::UpdateDefaultCache(v8::internal::Name*, v8::internal::Code*)
+            |
+            --- v8::internal::CodeCache::UpdateDefaultCache(v8::internal::Name*, v8::internal::Code*)
+               |          
+                --100.00%-- 0xc6a355788f1
+
+0.20^5976974^HTMLParserThrea^chrome               ^[.] WebCore::RenderObject::containingBlock() const
+            |
+            --- WebCore::RenderObject::containingBlock() const
+
+0.20^5926952^HTMLParserThrea^chrome               ^[.] v8::internal::GlobalHandles::Create(v8::internal::Object*)
+            |
+            --- v8::internal::GlobalHandles::Create(v8::internal::Object*)
+
+0.20^5880116^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseLeftHandSideExpression(bool*)
+            |
+            --- v8::internal::Parser::ParseLeftHandSideExpression(bool*)
+               |          
+                --100.00%-- 0x7fff30e9151000
+
+0.19^5834557^HTMLParserThrea^chrome               ^[.] WebCore::CachedRawResource::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&)
+            |
+            --- WebCore::CachedRawResource::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&)
+
+0.18^5527800^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::paint(WebCore::PaintInfo&, WebCore::LayoutPoint const&)
+            |
+            --- WebCore::RenderBlock::paint(WebCore::PaintInfo&, WebCore::LayoutPoint const&)
+
+0.18^5461500^HTMLParserThrea^chrome               ^[.] WebCore::Document::updateStyleIfNeeded()
+            |
+            --- WebCore::Document::updateStyleIfNeeded()
+
+0.18^5428693^HTMLParserThrea^libc-2.15.so         ^[.] __memset_sse2
+            |
+            --- __memset_sse2
+
+0.18^5423805^HTMLParserThrea^chrome               ^[.] WebCore::FrameView::paintContents(WebCore::GraphicsContext*, WebCore::IntRect const&)
+            |
+            --- WebCore::FrameView::paintContents(WebCore::GraphicsContext*, WebCore::IntRect const&)
+               |          
+               |--61.15%-- 0x5a000002d8
+               |          
+                --38.85%-- 0x2e00000092
+
+0.18^5363793^HTMLParserThrea^chrome               ^[.] WebCore::HTTPHeaderMap::get(WTF::AtomicString const&) const
+            |
+            --- WebCore::HTTPHeaderMap::get(WTF::AtomicString const&) const
+
+0.18^5306454^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::Scope(v8::internal::Scope*, v8::internal::ScopeType, v8::internal::Zone*)
+            |
+            --- v8::internal::Scope::Scope(v8::internal::Scope*, v8::internal::ScopeType, v8::internal::Zone*)
+
+0.18^5274362^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::bind_to(v8::internal::Label*, int)
+            |
+            --- v8::internal::Assembler::bind_to(v8::internal::Label*, int)
+               |          
+                --100.00%-- 0x3b2abd7c3000
+
+0.18^5270432^HTMLParserThrea^chrome               ^[.] SkDraw::drawPosText(char const*, unsigned long, float const*, float, int, SkPaint const&) const
+            |
+            --- SkDraw::drawPosText(char const*, unsigned long, float const*, float, int, SkPaint const&) const
+                (nil)
+               |          
+               |--55.20%-- 0x4f005200260003
+               |          
+                --44.80%-- 0x52004a00440003
+
+0.17^5196475^HTMLParserThrea^chrome               ^[.] WTF::equalNonNull(WTF::StringImpl const*, WTF::StringImpl const*)
+            |
+            --- WTF::equalNonNull(WTF::StringImpl const*, WTF::StringImpl const*)
+                0x7f7a0b975100
+
+0.17^5103842^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::convertToLayerCoords(WebCore::RenderLayer const*, WebCore::LayoutPoint&) const
+            |
+            --- WebCore::RenderLayer::convertToLayerCoords(WebCore::RenderLayer const*, WebCore::LayoutPoint&) const
+
+0.17^4967343^HTMLParserThrea^chrome               ^[.] _ZN2v88internal4ListINS0_16FuncNameInferrer4NameENS0_20ZoneAllocationPolicyEE3AddERKS3_S4_.constprop.51
+            |
+            --- _ZN2v88internal4ListINS0_16FuncNameInferrer4NameENS0_20ZoneAllocationPolicyEE3AddERKS3_S4_.constprop.51
+
+0.16^4900762^HTMLParserThrea^libc-2.15.so         ^[.] __memcmp_sse4_1
+            |
+            --- __memcmp_sse4_1
+               |          
+                --100.00%-- 0x7f7a0b975100
+
+0.15^4610114^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::GetPropertyWithCallback(v8::internal::Object*, v8::internal::Object*, v8::internal::Name*)
+            |
+            --- v8::internal::JSObject::GetPropertyWithCallback(v8::internal::Object*, v8::internal::Object*, v8::internal::Name*)
+
+0.15^4535632^HTMLParserThrea^chrome               ^[.] v8::HandleScope::HandleScope()
+            |
+            --- v8::HandleScope::HandleScope()
+
+0.15^4419717^HTMLParserThrea^chrome               ^[.] WebCore::MarkupAccumulator::appendStartTag(WebCore::Node*, WTF::HashMap<WTF::AtomicStringImpl*, WTF::AtomicStringImpl*, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*> >*)
+            |
+            --- WebCore::MarkupAccumulator::appendStartTag(WebCore::Node*, WTF::HashMap<WTF::AtomicStringImpl*, WTF::AtomicStringImpl*, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*> >*)
+
+0.14^4269939^HTMLParserThrea^chrome               ^[.] cssyyparse(WebCore::CSSParser*)
+            |
+            --- cssyyparse(WebCore::CSSParser*)
+               |          
+               |--56.10%-- content::PepperGraphics2DHost::Paint(SkCanvas*, gfx::Rect const&, gfx::Rect const&)
+               |          
+                --43.90%-- 0x1b800000b600
+
+0.14^4189741^HTMLParserThrea^chrome               ^[.] v8::internal::HandleScope::Extend(v8::internal::Isolate*)
+            |
+            --- v8::internal::HandleScope::Extend(v8::internal::Isolate*)
+
+0.13^3989323^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::overflowRectForPaintRejection() const
+            |
+            --- WebCore::RenderBox::overflowRectForPaintRejection() const
+
+0.12^3691476^HTMLParserThrea^libstdc++.so.6.0.16  ^[.] std::_Rb_tree_increment(std::_Rb_tree_node_base*)
+            |
+            --- std::_Rb_tree_increment(std::_Rb_tree_node_base*)
+
+0.12^3619871^HTMLParserThrea^chrome               ^[.] WebCore::ChildNodeInsertionNotifier::notifyDescendantInsertedIntoTree(WebCore::ContainerNode*)
+            |
+            --- WebCore::ChildNodeInsertionNotifier::notifyDescendantInsertedIntoTree(WebCore::ContainerNode*)
+                (nil)
+
+0.12^3610233^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::addLayoutOverflow(WebCore::LayoutRect const&)
+            |
+            --- WebCore::RenderBox::addLayoutOverflow(WebCore::LayoutRect const&)
+
+0.12^3602214^HTMLParserThrea^chrome               ^[.] v8::internal::RelocIterator::RelocIterator(v8::internal::Code*, int)
+            |
+            --- v8::internal::RelocIterator::RelocIterator(v8::internal::Code*, int)
+
+0.12^3592533^HTMLParserThrea^chrome               ^[.] v8::internal::MarkCompactCollector::MigrateObject(unsigned char*, unsigned char*, int, v8::internal::AllocationSpace)
+            |
+            --- v8::internal::MarkCompactCollector::MigrateObject(unsigned char*, unsigned char*, int, v8::internal::AllocationSpace)
+
+0.12^3591487^HTMLParserThrea^chrome               ^[.] v8::internal::StringTableCleaner::VisitPointers(v8::internal::Object**, v8::internal::Object**)
+            |
+            --- v8::internal::StringTableCleaner::VisitPointers(v8::internal::Object**, v8::internal::Object**)
+
+0.12^3590966^HTMLParserThrea^chrome               ^[.] v8::internal::MarkCompactCollector::DiscoverAndPromoteBlackObjectsOnPage(v8::internal::NewSpace*, v8::internal::NewSpacePage*)
+            |
+            --- v8::internal::MarkCompactCollector::DiscoverAndPromoteBlackObjectsOnPage(v8::internal::NewSpace*, v8::internal::NewSpacePage*)
+
+0.12^3590884^HTMLParserThrea^chrome               ^[.] v8::internal::MarkCompactCollector::ClearNonLiveReferences()
+            |
+            --- v8::internal::MarkCompactCollector::ClearNonLiveReferences()
+
+0.12^3590478^HTMLParserThrea^chrome               ^[.] void std::__introsort_loop<v8::internal::ObjectGroupConnection*, long>(v8::internal::ObjectGroupConnection*, v8::internal::ObjectGroupConnection*, long)
+            |
+            --- void std::__introsort_loop<v8::internal::ObjectGroupConnection*, long>(v8::internal::ObjectGroupConnection*, v8::internal::ObjectGroupConnection*, long)
+
+0.12^3590200^HTMLParserThrea^chrome               ^[.] v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitPropertyCell(v8::internal::Map*, v8::internal::HeapObject*)
+            |
+            --- v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitPropertyCell(v8::internal::Map*, v8::internal::HeapObject*)
+
+0.12^3589094^HTMLParserThrea^chrome               ^[.] long v8::internal::MarkCompactCollector::SweepConservatively<(v8::internal::MarkCompactCollector::SweepingParallelism)0>(v8::internal::PagedSpace*, v8::internal::FreeList*, v8::internal::Page*)
+            |
+            --- long v8::internal::MarkCompactCollector::SweepConservatively<(v8::internal::MarkCompactCollector::SweepingParallelism)0>(v8::internal::PagedSpace*, v8::internal::FreeList*, v8::internal::Page*)
+
+0.12^3589023^HTMLParserThrea^chrome               ^[.] WebCore::RenderStyle::~RenderStyle()
+            |
+            --- WebCore::RenderStyle::~RenderStyle()
+
+0.12^3588259^HTMLParserThrea^chrome               ^[.] v8::internal::FlexibleBodyVisitor<v8::internal::MarkCompactMarkingVisitor, v8::internal::JSObject::BodyDescriptor, void>::Visit(v8::internal::Map*, v8::internal::HeapObject*)
+            |
+            --- v8::internal::FlexibleBodyVisitor<v8::internal::MarkCompactMarkingVisitor, v8::internal::JSObject::BodyDescriptor, void>::Visit(v8::internal::Map*, v8::internal::HeapObject*)
+
+0.12^3588121^HTMLParserThrea^chrome               ^[.] v8::internal::GlobalHandles::IterateWeakRoots(v8::internal::ObjectVisitor*)
+            |
+            --- v8::internal::GlobalHandles::IterateWeakRoots(v8::internal::ObjectVisitor*)
+
+0.12^3587651^HTMLParserThrea^chrome               ^[.] v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::MarkTransitionArray(v8::internal::Heap*, v8::internal::TransitionArray*)
+            |
+            --- v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::MarkTransitionArray(v8::internal::Heap*, v8::internal::TransitionArray*)
+
+0.12^3585248^HTMLParserThrea^chrome               ^[.] v8::internal::SequentialStringKey<unsigned char>::Hash()
+            |
+            --- v8::internal::SequentialStringKey<unsigned char>::Hash()
+
+0.12^3584278^HTMLParserThrea^chrome               ^[.] v8::internal::ChoiceNode::Emit(v8::internal::RegExpCompiler*, v8::internal::Trace*)
+            |
+            --- v8::internal::ChoiceNode::Emit(v8::internal::RegExpCompiler*, v8::internal::Trace*)
+                0x3b2abd5271d8
+
+0.12^3583348^HTMLParserThrea^chrome               ^[.] v8::internal::LoadIC::UpdateMonomorphicIC(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::Code>, v8::internal::Handle<v8::internal::String>, v8::internal::StrictModeFlag)
+            |
+            --- v8::internal::LoadIC::UpdateMonomorphicIC(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::Code>, v8::internal::Handle<v8::internal::String>, v8::internal::StrictModeFlag)
+                0xc6a34dd2791
+
+0.12^3582808^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseIfStatement(v8::internal::ZoneList<v8::internal::Handle<v8::internal::String> >*, bool*)
+            |
+            --- v8::internal::Parser::ParseIfStatement(v8::internal::ZoneList<v8::internal::Handle<v8::internal::String> >*, bool*)
+                0x3b2abdf3f010
+
+0.12^3582142^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::addOverflowFromInlineChildren()
+            |
+            --- WebCore::RenderBlock::addOverflowFromInlineChildren()
+
+0.12^3581759^HTMLParserThrea^chrome               ^[.] _ZN7WebCore10RenderText29computePreferredLogicalWidthsEfRN3WTF7HashSetIPKNS_14SimpleFontDataENS1_7PtrHashIS5_EENS1_10HashTraitsIS5_EEEERNS_13GlyphOverflowE.part.184
+            |
+            --- _ZN7WebCore10RenderText29computePreferredLogicalWidthsEfRN3WTF7HashSetIPKNS_14SimpleFontDataENS1_7PtrHashIS5_EENS1_10HashTraitsIS5_EEEERNS_13GlyphOverflowE.part.184
+
+0.12^3581038^HTMLParserThrea^chrome               ^[.] WTF::String WebCore::v8StringToWebCoreString<WTF::String>(v8::Handle<v8::String>, WebCore::ExternalMode)
+            |
+            --- WTF::String WebCore::v8StringToWebCoreString<WTF::String>(v8::Handle<v8::String>, WebCore::ExternalMode)
+                0xc6a34d43fe9
+
+0.12^3581023^HTMLParserThrea^chrome               ^[.] WebCore::RenderInline::marginLeft() const
+            |
+            --- WebCore::RenderInline::marginLeft() const
+
+0.12^3580522^HTMLParserThrea^chrome               ^[.] WTF::Vector<WebCore::GraphicsContext::DeferredSaveState, 0ul>::expandCapacity(unsigned long)
+            |
+            --- WTF::Vector<WebCore::GraphicsContext::DeferredSaveState, 0ul>::expandCapacity(unsigned long)
+                0x100017718028
+
+0.12^3580338^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime_MaterializeRegExpLiteral(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::Runtime_MaterializeRegExpLiteral(int, v8::internal::Object**, v8::internal::Isolate*)
+
+0.12^3579940^HTMLParserThrea^chrome               ^[.] v8::internal::FunctionLiteral::AllowsLazyCompilation()
+            |
+            --- v8::internal::FunctionLiteral::AllowsLazyCompilation()
+
+0.12^3579555^HTMLParserThrea^chrome               ^[.] WebCore::XMLHttpRequest::isAllowedHTTPMethod(WTF::String const&)
+            |
+            --- WebCore::XMLHttpRequest::isAllowedHTTPMethod(WTF::String const&)
+                0x7f7a0b900000
+
+0.12^3579477^HTMLParserThrea^chrome               ^[.] ppapi::PpapiGlobals::Get()
+            |
+            --- ppapi::PpapiGlobals::Get()
+
+0.12^3579477^HTMLParserThrea^chrome               ^[.] v8::internal::StaticVisitorBase::GetVisitorId(int, int)
+            |
+            --- v8::internal::StaticVisitorBase::GetVisitorId(int, int)
+
+0.12^3578703^HTMLParserThrea^chrome               ^[.] v8::internal::LoadIC::ComputePolymorphicIC(v8::internal::List<v8::internal::Handle<v8::internal::Map>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::List<v8::internal::Handle<v8::internal::Code>, v8::internal::FreeStoreAllocationPolicy>*, int, v8::internal::Handle<v8::internal::Name>, v8::internal::StrictModeFlag)
+            |
+            --- v8::internal::LoadIC::ComputePolymorphicIC(v8::internal::List<v8::internal::Handle<v8::internal::Map>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::List<v8::internal::Handle<v8::internal::Code>, v8::internal::FreeStoreAllocationPolicy>*, int, v8::internal::Handle<v8::internal::Name>, v8::internal::StrictModeFlag)
+                0xc6a354cfa21
+
+0.12^3578592^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::BuildObjectLiteralConstantProperties(v8::internal::ZoneList<v8::internal::ObjectLiteralProperty*>*, v8::internal::Handle<v8::internal::FixedArray>, bool*, bool*, int*, bool*)
+            |
+            --- v8::internal::Parser::BuildObjectLiteralConstantProperties(v8::internal::ZoneList<v8::internal::ObjectLiteralProperty*>*, v8::internal::Handle<v8::internal::FixedArray>, bool*, bool*, int*, bool*)
+
+0.12^3578004^HTMLParserThrea^chrome               ^[.] v8::internal::StubCache::ComputePolymorphicLoadIC(v8::internal::List<v8::internal::Handle<v8::internal::Map>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::List<v8::internal::Handle<v8::internal::Code>, v8::internal::FreeStoreAllocationPolicy>*, int, v8::internal::Handle<v8::internal::Name>)
+            |
+            --- v8::internal::StubCache::ComputePolymorphicLoadIC(v8::internal::List<v8::internal::Handle<v8::internal::Map>, v8::internal::FreeStoreAllocationPolicy>*, v8::internal::List<v8::internal::Handle<v8::internal::Code>, v8::internal::FreeStoreAllocationPolicy>*, int, v8::internal::Handle<v8::internal::Name>)
+                0xc6a3444c2a9
+
+0.12^3577719^HTMLParserThrea^chrome               ^[.] v8::internal::BoyerMooreLookahead::FindBestInterval(int, int, int*, int*)
+            |
+            --- v8::internal::BoyerMooreLookahead::FindBestInterval(int, int, int*, int*)
+
+0.12^3577405^HTMLParserThrea^chrome               ^[.] WebCore::RenderBoxModelObject::continuation() const
+            |
+            --- WebCore::RenderBoxModelObject::continuation() const
+
+0.12^3576942^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::hasPercentHeightDescendant(WebCore::RenderBox*)
+            |
+            --- WebCore::RenderBlock::hasPercentHeightDescendant(WebCore::RenderBox*)
+
+0.12^3575468^HTMLParserThrea^chrome               ^[.] v8::internal::VariableProxy* v8::internal::Scope::NewUnresolved<v8::internal::AstConstructionVisitor>(v8::internal::AstNodeFactory<v8::internal::AstConstructionVisitor>*, v8::internal::Handle<v8::internal::String>, v8::internal::Interface*, int)
+            |
+            --- v8::internal::VariableProxy* v8::internal::Scope::NewUnresolved<v8::internal::AstConstructionVisitor>(v8::internal::AstNodeFactory<v8::internal::AstConstructionVisitor>*, v8::internal::Handle<v8::internal::String>, v8::internal::Interface*, int)
+                0x7fff30e91928
+
+0.12^3575428^HTMLParserThrea^chrome               ^[.] WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>::createBidiRunsForLine(WebCore::InlineIterator const&, WebCore::VisualDirectionOverride, bool)
+            |
+            --- WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>::createBidiRunsForLine(WebCore::InlineIterator const&, WebCore::VisualDirectionOverride, bool)
+                0x3b2abd843120
+
+0.12^3574896^HTMLParserThrea^chrome               ^[.] v8::internal::FixedArray::set(int, v8::internal::Object*, v8::internal::WriteBarrierMode)
+            |
+            --- v8::internal::FixedArray::set(int, v8::internal::Object*, v8::internal::WriteBarrierMode)
+
+0.12^3574498^HTMLParserThrea^chrome               ^[.] v8::internal::String::Equals(v8::internal::String*)
+            |
+            --- v8::internal::String::Equals(v8::internal::String*)
+
+0.12^3574405^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::ExpressionContext::IsTest() const
+            |
+            --- v8::internal::FullCodeGenerator::ExpressionContext::IsTest() const
+
+0.12^3574327^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::ResolveVariable(v8::internal::CompilationInfo*, v8::internal::VariableProxy*, v8::internal::AstNodeFactory<v8::internal::AstNullVisitor>*)
+            |
+            --- v8::internal::Scope::ResolveVariable(v8::internal::CompilationInfo*, v8::internal::VariableProxy*, v8::internal::AstNodeFactory<v8::internal::AstNullVisitor>*)
+
+0.12^3573789^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateMap(v8::internal::InstanceType, int, v8::internal::ElementsKind)
+            |
+            --- v8::internal::Heap::AllocateMap(v8::internal::InstanceType, int, v8::internal::ElementsKind)
+
+0.12^3573631^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime::CreateArrayLiteralBoilerplate(v8::internal::Isolate*, v8::internal::Handle<v8::internal::FixedArray>, v8::internal::Handle<v8::internal::FixedArray>)
+            |
+            --- v8::internal::Runtime::CreateArrayLiteralBoilerplate(v8::internal::Isolate*, v8::internal::Handle<v8::internal::FixedArray>, v8::internal::Handle<v8::internal::FixedArray>)
+
+0.12^3573214^HTMLParserThrea^chrome               ^[.] WTF::HashTableIterator<WebCore::CachedResource*, WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::PtrHash<WebCore::CachedResource*>, WTF::HashMapValueTraits<WTF::HashTraits<WebCore::CachedResource*>, WTF::HashTraits<WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::HashTraits<WebCore::Cache
+            |
+            --- WTF::HashTableIterator<WebCore::CachedResource*, WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::PtrHash<WebCore::CachedResource*>, WTF::HashMapValueTraits<WTF::HashTraits<WebCore::CachedResource*>, WTF::HashTraits<WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::HashTraits<WebCore::CachedResource*> > WTF::HashTable<WebCore::CachedResource*, WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::PtrHash<WebCore::CachedResource*>, WTF::HashMapValueTraits<WTF::HashTraits<WebCore::CachedResource*>, WTF::HashTraits<WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::HashTraits<WebCore::CachedResource*> >::find<WTF::IdentityHashTranslator<WTF::PtrHash<WebCore::CachedResource*> >, WebCore::CachedResource*>(WebCore::CachedResource* const&)
+
+0.12^3573010^HTMLParserThrea^chrome               ^[.] Pickle::Resize(unsigned long)
+            |
+            --- Pickle::Resize(unsigned long)
+
+0.12^3572646^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::floatingObjects() const
+            |
+            --- WebCore::RenderBlock::floatingObjects() const
+
+0.12^3572547^HTMLParserThrea^chrome               ^[.] WebCore::LiveNodeListBase::item(unsigned int) const
+            |
+            --- WebCore::LiveNodeListBase::item(unsigned int) const
+
+0.12^3572456^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::computeLogicalHeight(WebCore::LayoutUnit, WebCore::LayoutUnit, WebCore::RenderBox::LogicalExtentComputedValues&) const
+            |
+            --- WebCore::RenderBox::computeLogicalHeight(WebCore::LayoutUnit, WebCore::LayoutUnit, WebCore::RenderBox::LogicalExtentComputedValues&) const
+                (nil)
+
+0.12^3572406^HTMLParserThrea^chrome               ^[.] WebCore::ScriptController::callFunction(v8::Handle<v8::Function>, v8::Handle<v8::Object>, int, v8::Handle<v8::Value>*)
+            |
+            --- WebCore::ScriptController::callFunction(v8::Handle<v8::Function>, v8::Handle<v8::Object>, int, v8::Handle<v8::Value>*)
+
+0.12^3571839^HTMLParserThrea^chrome               ^[.] WTF::HashTableAddResult<WTF::HashTableIterator<WTF::AtomicStringImpl*, WTF::KeyValuePair<WTF::AtomicStringImpl*, WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WTF::AtomicStringImpl*, WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > > >, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashMapValueTraits<WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleDa
+            |
+            --- WTF::HashTableAddResult<WTF::HashTableIterator<WTF::AtomicStringImpl*, WTF::KeyValuePair<WTF::AtomicStringImpl*, WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WTF::AtomicStringImpl*, WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > > >, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashMapValueTraits<WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > > >, WTF::HashTraits<WTF::AtomicStringImpl*> > > WTF::HashTable<WTF::AtomicStringImpl*, WTF::KeyValuePair<WTF::AtomicStringImpl*, WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WTF::AtomicStringImpl*, WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > > >, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashMapValueTraits<WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > > >, WTF::HashTraits<WTF::AtomicStringImpl*> >::add<WTF::HashMapTranslator<WTF::HashMapValueTraits<WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::OwnPtr<WTF::LinkedStack<WebCore::RuleData> > > >, WTF::PtrHash<WTF::AtomicStringImpl*> >, WTF::AtomicStringImpl*, WTF::PassOwnPtr<WTF::LinkedStack<WebCore::RuleData> > >(WTF::AtomicStringImpl* const&, WTF::PassOwnPtr<WTF::LinkedStack<WebCore::RuleData> > const&)
+
+0.12^3571626^HTMLParserThrea^chrome               ^[.] v8::internal::Factory::ObjectLiteralMapFromCache(v8::internal::Handle<v8::internal::Context>, v8::internal::Handle<v8::internal::FixedArray>)
+            |
+            --- v8::internal::Factory::ObjectLiteralMapFromCache(v8::internal::Handle<v8::internal::Context>, v8::internal::Handle<v8::internal::FixedArray>)
+
+0.12^3571455^HTMLParserThrea^chrome               ^[.] WebCore::RenderView::intervalArena()
+            |
+            --- WebCore::RenderView::intervalArena()
+
+0.12^3571267^HTMLParserThrea^chrome               ^[.] v8::internal::VarAndOrder::Compare(v8::internal::VarAndOrder const*, v8::internal::VarAndOrder const*)
+            |
+            --- v8::internal::VarAndOrder::Compare(v8::internal::VarAndOrder const*, v8::internal::VarAndOrder const*)
+
+0.12^3570914^HTMLParserThrea^chrome               ^[.] bool WebCore::shouldInvalidateNodeListCachesForAttr<2u>(unsigned int const*, WebCore::QualifiedName const&)
+            |
+            --- bool WebCore::shouldInvalidateNodeListCachesForAttr<2u>(unsigned int const*, WebCore::QualifiedName const&)
+
+0.12^3570523^HTMLParserThrea^chrome               ^[.] v8::internal::CodeCacheHashTableKey::IsMatch(v8::internal::Object*)
+            |
+            --- v8::internal::CodeCacheHashTableKey::IsMatch(v8::internal::Object*)
+
+0.12^3570308^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::hasRelativeDimensions() const
+            |
+            --- WebCore::RenderBox::hasRelativeDimensions() const
+
+0.12^3570109^HTMLParserThrea^chrome               ^[.] WTF::HashMap<WTF::AtomicStringImpl*, WTF::OwnPtr<WebCore::RuleData>, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::OwnPtr<WebCore::RuleData> > >::get(WTF::AtomicStringImpl* const&) const
+            |
+            --- WTF::HashMap<WTF::AtomicStringImpl*, WTF::OwnPtr<WebCore::RuleData>, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::OwnPtr<WebCore::RuleData> > >::get(WTF::AtomicStringImpl* const&) const
+                void WTF::Vector<WebCore::StyleRule*, 64ul>::appendSlowCase<WebCore::StyleRule*>(WebCore::StyleRule* const&)
+
+0.12^3569976^HTMLParserThrea^chrome               ^[.] v8::internal::IC::address() const
+            |
+            --- v8::internal::IC::address() const
+
+0.12^3569735^HTMLParserThrea^chrome               ^[.] v8::internal::StringTable::LookupUtf8String(v8::internal::Vector<char const>, v8::internal::Object**)
+            |
+            --- v8::internal::StringTable::LookupUtf8String(v8::internal::Vector<char const>, v8::internal::Object**)
+
+0.12^3569690^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::updateLogicalWidthForAlignment(WebCore::ETextAlign const&, WebCore::BidiRun*, float&, float&, float&, int)
+            |
+            --- WebCore::RenderBlock::updateLogicalWidthForAlignment(WebCore::ETextAlign const&, WebCore::BidiRun*, float&, float&, float&, int)
+
+0.12^3569632^HTMLParserThrea^chrome               ^[.] content::GetContentClient()
+            |
+            --- content::GetContentClient()
+                WebCore::Node::invalidateNodeListCachesInAncestors(WebCore::QualifiedName const*, WebCore::Element*)
+
+0.12^3569389^HTMLParserThrea^chrome               ^[.] v8::internal::Scanner::SkipSingleLineComment()
+            |
+            --- v8::internal::Scanner::SkipSingleLineComment()
+
+0.12^3568302^HTMLParserThrea^chrome               ^[.] v8::internal::PagedSpace::AllocateRaw(int)
+            |
+            --- v8::internal::PagedSpace::AllocateRaw(int)
+                0x5d00001000
+
+0.12^3567675^HTMLParserThrea^chrome               ^[.] v8::internal::HashTable<v8::internal::NameDictionaryShape, v8::internal::Name*>::FindEntry(v8::internal::Isolate*, v8::internal::Name*)
+            |
+            --- v8::internal::HashTable<v8::internal::NameDictionaryShape, v8::internal::Name*>::FindEntry(v8::internal::Isolate*, v8::internal::Name*)
+
+0.12^3567487^HTMLParserThrea^chrome               ^[.] WebCore::ImageLoader::updateFromElement()
+            |
+            --- WebCore::ImageLoader::updateFromElement()
+
+0.12^3567473^HTMLParserThrea^chrome               ^[.] WebCore::RenderObject::localToContainerQuad(WebCore::FloatQuad const&, WebCore::RenderLayerModelObject const*, unsigned int, bool*) const
+            |
+            --- WebCore::RenderObject::localToContainerQuad(WebCore::FloatQuad const&, WebCore::RenderLayerModelObject const*, unsigned int, bool*) const
+
+0.12^3567274^HTMLParserThrea^chrome               ^[.] webCoreInitializeScriptWrappableForInterface(WebCore::DocumentFragment*)
+            |
+            --- webCoreInitializeScriptWrappableForInterface(WebCore::DocumentFragment*)
+
+0.12^3567005^HTMLParserThrea^chrome               ^[.] WebCore::Frame::settings() const
+            |
+            --- WebCore::Frame::settings() const
+
+0.12^3566636^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseIdentifier(bool*)
+            |
+            --- v8::internal::Parser::ParseIdentifier(bool*)
+                0x7fff30e90bf000
+
+0.12^3566359^HTMLParserThrea^chrome               ^[.] WebCore::CachedImage::didAddClient(WebCore::CachedResourceClient*)
+            |
+            --- WebCore::CachedImage::didAddClient(WebCore::CachedResourceClient*)
+
+0.12^3566119^HTMLParserThrea^chrome               ^[.] WebCore::RenderStyle::diff(WebCore::RenderStyle const*, unsigned int&) const
+            |
+            --- WebCore::RenderStyle::diff(WebCore::RenderStyle const*, unsigned int&) const
+
+0.12^3565713^HTMLParserThrea^chrome               ^[.] WebCore::LiveNodeListBase::invalidateCache() const
+            |
+            --- WebCore::LiveNodeListBase::invalidateCache() const
+
+0.12^3565698^HTMLParserThrea^chrome               ^[.] WebCore::SelectorChecker::SelectorChecker(WebCore::Document*, WebCore::SelectorChecker::Mode)
+            |
+            --- WebCore::SelectorChecker::SelectorChecker(WebCore::Document*, WebCore::SelectorChecker::Mode)
+
+0.12^3565455^HTMLParserThrea^chrome               ^[.] WebCore::HTMLTreeBuilder::processEndTag(WebCore::AtomicHTMLToken*)
+            |
+            --- WebCore::HTMLTreeBuilder::processEndTag(WebCore::AtomicHTMLToken*)
+                0x7f7a11e52eb0
+
+0.12^3565182^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::arithmetic_op_32(unsigned char, v8::internal::Register, v8::internal::Register)
+            |
+            --- v8::internal::Assembler::arithmetic_op_32(unsigned char, v8::internal::Register, v8::internal::Register)
+
+0.12^3565074^HTMLParserThrea^chrome               ^[.] v8::internal::TranslationBuffer::Add(int, v8::internal::Zone*)
+            |
+            --- v8::internal::TranslationBuffer::Add(int, v8::internal::Zone*)
+
+0.12^3565037^HTMLParserThrea^chrome               ^[.] WebCore::Node::parentOrShadowHostElement() const
+            |
+            --- WebCore::Node::parentOrShadowHostElement() const
+
+0.12^3564789^HTMLParserThrea^chrome               ^[.] void v8::internal::FlexibleBodyVisitor<v8::internal::MarkCompactMarkingVisitor, v8::internal::StructBodyDescriptor, void>::VisitSpecialized<56>(v8::internal::Map*, v8::internal::HeapObject*)
+            |
+            --- void v8::internal::FlexibleBodyVisitor<v8::internal::MarkCompactMarkingVisitor, v8::internal::StructBodyDescriptor, void>::VisitSpecialized<56>(v8::internal::Map*, v8::internal::HeapObject*)
+
+0.12^3564677^HTMLParserThrea^chrome               ^[.] v8::internal::Map::RawCopy(int)
+            |
+            --- v8::internal::Map::RawCopy(int)
+
+0.12^3563819^HTMLParserThrea^chrome               ^[.] _ZN2v88internal8LCodeGen16WriteTranslationEPNS0_12LEnvironmentEPNS0_11TranslationE.constprop.384
+            |
+            --- _ZN2v88internal8LCodeGen16WriteTranslationEPNS0_12LEnvironmentEPNS0_11TranslationE.constprop.384
+
+0.12^3563122^HTMLParserThrea^chrome               ^[.] WebCore::MatchedProperties::~MatchedProperties()
+            |
+            --- WebCore::MatchedProperties::~MatchedProperties()
+                0x3b2abdb056b8
+                0x1e83176feba8
+
+0.12^3562575^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::MakeCode(v8::internal::CompilationInfo*)
+            |
+            --- v8::internal::FullCodeGenerator::MakeCode(v8::internal::CompilationInfo*)
+
+0.12^3561995^HTMLParserThrea^chrome               ^[.] v8::internal::BaseLoadStoreStubCompiler::GetICCode(v8::internal::Code::Kind, v8::internal::Code::StubType, v8::internal::Handle<v8::internal::Name>, v8::internal::InlineCacheState)
+            |
+            --- v8::internal::BaseLoadStoreStubCompiler::GetICCode(v8::internal::Code::Kind, v8::internal::Code::StubType, v8::internal::Handle<v8::internal::Name>, v8::internal::InlineCacheState)
+                0x9d2ae798179
+
+0.12^3561893^HTMLParserThrea^chrome               ^[.] int v8::internal::FlexibleBodyVisitor<v8::internal::NewSpaceScavenger, v8::internal::JSObject::BodyDescriptor, int>::VisitSpecialized<24>(v8::internal::Map*, v8::internal::HeapObject*)
+            |
+            --- int v8::internal::FlexibleBodyVisitor<v8::internal::NewSpaceScavenger, v8::internal::JSObject::BodyDescriptor, int>::VisitSpecialized<24>(v8::internal::Map*, v8::internal::HeapObject*)
+
+0.12^3561621^HTMLParserThrea^chrome               ^[.] WTF::AtomicString::addSlowCase(WTF::StringImpl*)
+            |
+            --- WTF::AtomicString::addSlowCase(WTF::StringImpl*)
+
+0.12^3561375^HTMLParserThrea^chrome               ^[.] WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*)
+            |
+            --- WebCore::StyleResolver::styleForElement(WebCore::Element*, WebCore::RenderStyle*, WebCore::StyleSharingBehavior, WebCore::RuleMatchingBehavior, WebCore::RenderRegion*)
+
+0.12^3561200^HTMLParserThrea^chrome               ^[.] v8::internal::Builtins::LoadIC_PreMonomorphic()
+            |
+            --- v8::internal::Builtins::LoadIC_PreMonomorphic()
+                0x29f9884600a9
+
+0.12^3561181^HTMLParserThrea^chrome               ^[.] WebCore::FloatPoint::FloatPoint(WebCore::LayoutPoint const&)
+            |
+            --- WebCore::FloatPoint::FloatPoint(WebCore::LayoutPoint const&)
+                WebCore::RenderBox::clippedOverflowRectForRepaint(WebCore::RenderLayerModelObject const*) const
+                WebCore::RenderBox::contentWidth() const
+
+0.12^3561117^HTMLParserThrea^chrome               ^[.] v8::internal::LoadStubCompiler::registers()
+            |
+            --- v8::internal::LoadStubCompiler::registers()
+                0xc6a34d0ef91
+
+0.12^3561066^HTMLParserThrea^chrome               ^[.] WebCore::BorderData::BorderData()
+            |
+            --- WebCore::BorderData::BorderData()
+
+0.12^3560598^HTMLParserThrea^chrome               ^[.] WebCore::HTMLElement::parseAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&)
+            |
+            --- WebCore::HTMLElement::parseAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&)
+
+0.12^3560313^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::createLineBoxesFromBidiRuns(WebCore::BidiRunList<WebCore::BidiRun>&, WebCore::InlineIterator const&, WebCore::LineInfo&, WebCore::VerticalPositionCache&, WebCore::BidiRun*, WTF::Vector<WebCore::WordMeasurement, 64ul>&)
+            |
+            --- WebCore::RenderBlock::createLineBoxesFromBidiRuns(WebCore::BidiRunList<WebCore::BidiRun>&, WebCore::InlineIterator const&, WebCore::LineInfo&, WebCore::VerticalPositionCache&, WebCore::BidiRun*, WTF::Vector<WebCore::WordMeasurement, 64ul>&)
+                0x3b2abd54deb0
+
+0.12^3560066^HTMLParserThrea^chrome               ^[.] void WebCore::StringCache::setReturnValueFromString<v8::PropertyCallbackInfo<v8::Value> >(v8::PropertyCallbackInfo<v8::Value> const&, WTF::StringImpl*, v8::Isolate*)
+            |
+            --- void WebCore::StringCache::setReturnValueFromString<v8::PropertyCallbackInfo<v8::Value> >(v8::PropertyCallbackInfo<v8::Value> const&, WTF::StringImpl*, v8::Isolate*)
+                0xc6a35a2a0c9
+                v8::internal::JSReceiver::LocalLookup(v8::internal::Name*, v8::internal::LookupResult*, bool)
+
+0.12^3560037^HTMLParserThrea^chrome               ^[.] v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitSharedFunctionInfo(v8::internal::Map*, v8::internal::HeapObject*)
+            |
+            --- v8::internal::StaticMarkingVisitor<v8::internal::MarkCompactMarkingVisitor>::VisitSharedFunctionInfo(v8::internal::Map*, v8::internal::HeapObject*)
+
+0.12^3559792^HTMLParserThrea^chrome               ^[.] WebCore::ComposedShadowTreeWalker::traverseParent(WebCore::Node const*, WebCore::NodeRenderingTraversal::ParentDetails*) const
+            |
+            --- WebCore::ComposedShadowTreeWalker::traverseParent(WebCore::Node const*, WebCore::NodeRenderingTraversal::ParentDetails*) const
+
+0.12^3559628^HTMLParserThrea^chrome               ^[.] WebCore::Element::rebuildPresentationAttributeStyle()
+            |
+            --- WebCore::Element::rebuildPresentationAttributeStyle()
+                0x1e83176beb48
+
+0.12^3558753^HTMLParserThrea^chrome               ^[.] v8::internal::LoadStubCompiler::JitEvent(v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Code>)
+            |
+            --- v8::internal::LoadStubCompiler::JitEvent(v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Code>)
+                0xc6a354902f1
+
+0.12^3557965^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::lea(v8::internal::Register, v8::internal::Operand const&)
+            |
+            --- v8::internal::Assembler::lea(v8::internal::Register, v8::internal::Operand const&)
+
+0.12^3557486^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::updateShapeInsideInfoAfterStyleChange(WebCore::ShapeValue const*, WebCore::ShapeValue const*)
+            |
+            --- WebCore::RenderBlock::updateShapeInsideInfoAfterStyleChange(WebCore::ShapeValue const*, WebCore::ShapeValue const*)
+
+0.12^3556781^HTMLParserThrea^libc-2.15.so         ^[.] __strlen_sse2_pminub
+            |
+            --- __strlen_sse2_pminub
+
+0.12^3556662^HTMLParserThrea^chrome               ^[.] WebCore::ElementRuleCollector::collectMatchingRulesForList(WebCore::RuleData const*, WebCore::MatchRequest const&, WebCore::RuleRange&)
+            |
+            --- WebCore::ElementRuleCollector::collectMatchingRulesForList(WebCore::RuleData const*, WebCore::MatchRequest const&, WebCore::RuleRange&)
+
+0.12^3556305^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::Scavenge()
+            |
+            --- v8::internal::Heap::Scavenge()
+
+0.12^3556183^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::linkToEndLineIfNeeded(WebCore::LineLayoutState&)
+            |
+            --- WebCore::RenderBlock::linkToEndLineIfNeeded(WebCore::LineLayoutState&)
+
+0.12^3555975^HTMLParserThrea^chrome               ^[.] WebCore::SharedStyleFinder::locateCousinList(WebCore::Element*, unsigned int&) const
+            |
+            --- WebCore::SharedStyleFinder::locateCousinList(WebCore::Element*, unsigned int&) const
+                0x176da48800000000
+
+0.12^3555563^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::PrepareForBailoutForId(v8::internal::BailoutId, v8::internal::FullCodeGenerator::State)
+            |
+            --- v8::internal::FullCodeGenerator::PrepareForBailoutForId(v8::internal::BailoutId, v8::internal::FullCodeGenerator::State)
+
+0.12^3555363^HTMLParserThrea^chrome               ^[.] v8::internal::PropertyCallbackArguments::Call(v8::Handle<v8::Value> (*)(v8::Local<v8::String>, v8::AccessorInfo const&), v8::Local<v8::String>)
+            |
+            --- v8::internal::PropertyCallbackArguments::Call(v8::Handle<v8::Value> (*)(v8::Local<v8::String>, v8::AccessorInfo const&), v8::Local<v8::String>)
+                0x7f7a0b900000
+
+0.12^3554978^HTMLParserThrea^chrome               ^[.] v8::internal::Object::Lookup(v8::internal::Name*, v8::internal::LookupResult*)
+            |
+            --- v8::internal::Object::Lookup(v8::internal::Name*, v8::internal::LookupResult*)
+
+0.12^3554874^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateRawOneByteString(int, v8::internal::PretenureFlag)
+            |
+            --- v8::internal::Heap::AllocateRawOneByteString(int, v8::internal::PretenureFlag)
+
+0.12^3554475^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::styleWillChange(WebCore::StyleDifference, WebCore::RenderStyle const*)
+            |
+            --- WebCore::RenderBlock::styleWillChange(WebCore::StyleDifference, WebCore::RenderStyle const*)
+
+0.12^3553383^HTMLParserThrea^chrome               ^[.] base::Time::Now()
+            |
+            --- base::Time::Now()
+
+0.12^3553107^HTMLParserThrea^chrome               ^[.] WebCore::ElementRuleCollector::~ElementRuleCollector()
+            |
+            --- WebCore::ElementRuleCollector::~ElementRuleCollector()
+
+0.12^3550744^HTMLParserThrea^chrome               ^[.] net::HttpResponseHeaders::FindHeader(unsigned long, base::BasicStringPiece<std::string> const&) const
+            |
+            --- net::HttpResponseHeaders::FindHeader(unsigned long, base::BasicStringPiece<std::string> const&) const
+
+0.12^3550703^HTMLParserThrea^chrome               ^[.] WebCore::NodeRenderingContext::createRendererForElementIfNeeded()
+            |
+            --- WebCore::NodeRenderingContext::createRendererForElementIfNeeded()
+
+0.12^3550144^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::ScavengeObject(v8::internal::HeapObject**, v8::internal::HeapObject*)
+            |
+            --- v8::internal::Heap::ScavengeObject(v8::internal::HeapObject**, v8::internal::HeapObject*)
+
+0.12^3550090^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayerModelObject::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*)
+            |
+            --- WebCore::RenderLayerModelObject::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*)
+
+0.12^3549513^HTMLParserThrea^chrome               ^[.] std::_Rb_tree<extensions::ChromeV8Context*, extensions::ChromeV8Context*, std::_Identity<extensions::ChromeV8Context*>, std::less<extensions::ChromeV8Context*>, std::allocator<extensions::ChromeV8Context*> >::_M_insert_unique(extensions::ChromeV8Context* const&)
+            |
+            --- std::_Rb_tree<extensions::ChromeV8Context*, extensions::ChromeV8Context*, std::_Identity<extensions::ChromeV8Context*>, std::less<extensions::ChromeV8Context*>, std::allocator<extensions::ChromeV8Context*> >::_M_insert_unique(extensions::ChromeV8Context* const&)
+
+0.12^3549422^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::clearFloats()
+            |
+            --- WebCore::RenderBlock::clearFloats()
+
+0.12^3548487^HTMLParserThrea^chrome               ^[.] WebCore::RenderReplaced::computeAspectRatioInformationForRenderBox(WebCore::RenderBox*, WebCore::FloatSize&, double&, bool&) const
+            |
+            --- WebCore::RenderReplaced::computeAspectRatioInformationForRenderBox(WebCore::RenderBox*, WebCore::FloatSize&, double&, bool&) const
+                0x3b2abdce1ed8
+
+0.12^3545724^HTMLParserThrea^chrome               ^[.] WebCore::SVGRenderSupport::styleChanged(WebCore::RenderObject*)
+            |
+            --- WebCore::SVGRenderSupport::styleChanged(WebCore::RenderObject*)
+
+0.12^3545370^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::AllocateNonParameterLocals()
+            |
+            --- v8::internal::Scope::AllocateNonParameterLocals()
+                0x700000007
+
+0.12^3545160^HTMLParserThrea^chrome               ^[.] WebCore::Element::hasFlagsSetDuringStylingOfChildren() const
+            |
+            --- WebCore::Element::hasFlagsSetDuringStylingOfChildren() const
+
+0.12^3543621^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::visualOverflowRectForPropagation(WebCore::RenderStyle*) const
+            |
+            --- WebCore::RenderBox::visualOverflowRectForPropagation(WebCore::RenderStyle*) const
+
+0.12^3542672^HTMLParserThrea^libm-2.15.so         ^[.] __ceilf_sse41
+            |
+            --- __ceilf_sse41
+
+0.12^3542332^HTMLParserThrea^chrome               ^[.] v8::internal::CallStubCompiler::CompileHandlerFrontend(v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::Name>, v8::internal::CheckType, v8::internal::Label*)
+            |
+            --- v8::internal::CallStubCompiler::CompileHandlerFrontend(v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::Name>, v8::internal::CheckType, v8::internal::Label*)
+                0x7f7a11d17f90
+
+0.12^3542050^HTMLParserThrea^chrome               ^[.] v8::internal::MarkCompactCollector::RecordRelocSlot(v8::internal::RelocInfo*, v8::internal::Object*)
+            |
+            --- v8::internal::MarkCompactCollector::RecordRelocSlot(v8::internal::RelocInfo*, v8::internal::Object*)
+
+0.12^3540984^HTMLParserThrea^chrome               ^[.] v8::internal::RegExpMacroAssemblerX64::CheckSpecialCharacterClass(unsigned short, v8::internal::Label*)
+            |
+            --- v8::internal::RegExpMacroAssemblerX64::CheckSpecialCharacterClass(unsigned short, v8::internal::Label*)
+
+0.12^3537796^HTMLParserThrea^chrome               ^[.] SkBitmapProcState::chooseProcs(SkMatrix const&, SkPaint const&)
+            |
+            --- SkBitmapProcState::chooseProcs(SkMatrix const&, SkPaint const&)
+                0x3f80000041400000
+
+0.12^3537246^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::CreateCode(v8::internal::CodeDesc const&, unsigned int, v8::internal::Handle<v8::internal::Object>, bool, bool)
+            |
+            --- v8::internal::Heap::CreateCode(v8::internal::CodeDesc const&, unsigned int, v8::internal::Handle<v8::internal::Object>, bool, bool)
+                0x8f00001000
+
+0.12^3535475^HTMLParserThrea^chrome               ^[.] WebCore::Element::getAttribute(WebCore::QualifiedName const&) const
+            |
+            --- WebCore::Element::getAttribute(WebCore::QualifiedName const&) const
+
+0.12^3534788^HTMLParserThrea^chrome               ^[.] v8::internal::ToBooleanIC_Miss(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::ToBooleanIC_Miss(int, v8::internal::Object**, v8::internal::Isolate*)
+
+0.12^3534268^HTMLParserThrea^chrome               ^[.] WebCore::FormElementKey::deref() const
+            |
+            --- WebCore::FormElementKey::deref() const
+
+0.12^3533584^HTMLParserThrea^chrome               ^[.] std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> >::assign(std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > const&)
+            |
+            --- std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> >::assign(std::basic_string<unsigned short, base::string16_char_traits, std::allocator<unsigned short> > const&)
+                0x33d2a411c441
+
+0.12^3533503^HTMLParserThrea^chrome               ^[.] void v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::EvacuateObject<(v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::ObjectContents)1, (v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::SizeRestriction)0, 8>(v8::internal::Map*, v8::internal::HeapObject**, v8::internal::HeapObject*, int)
+            |
+            --- void v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::EvacuateObject<(v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::ObjectContents)1, (v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::SizeRestriction)0, 8>(v8::internal::Map*, v8::internal::HeapObject**, v8::internal::HeapObject*, int)
+
+0.12^3532801^HTMLParserThrea^chrome               ^[.] WebCore::HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned int&) const
+            |
+            --- WebCore::HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned int&) const
+
+0.12^3531175^HTMLParserThrea^chrome               ^[.] v8::internal::StubCache::ComputeLoadNonexistent(v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::JSObject>)
+            |
+            --- v8::internal::StubCache::ComputeLoadNonexistent(v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::JSObject>)
+
+0.12^3529077^HTMLParserThrea^chrome               ^[.] WTF::currentTime()
+            |
+            --- WTF::currentTime()
+
+0.12^3527952^HTMLParserThrea^chrome               ^[.] void WebCore::SelectorDataList::execute<false>(WebCore::Node*, WTF::Vector<WTF::RefPtr<WebCore::Node>, 0ul>&) const
+            |
+            --- void WebCore::SelectorDataList::execute<false>(WebCore::Node*, WTF::Vector<WTF::RefPtr<WebCore::Node>, 0ul>&) const
+
+0.12^3527820^HTMLParserThrea^chrome               ^[.] v8::preparser::PreParser::ParseStatement(bool*)
+            |
+            --- v8::preparser::PreParser::ParseStatement(bool*)
+                0x3b2abd78300000
+
+0.12^3526909^HTMLParserThrea^chrome               ^[.] v8::internal::MacroAssembler::LoadSmiConstant(v8::internal::Register, v8::internal::Smi*)
+            |
+            --- v8::internal::MacroAssembler::LoadSmiConstant(v8::internal::Register, v8::internal::Smi*)
+
+0.12^3526173^HTMLParserThrea^chrome               ^[.] v8::internal::MacroAssembler::CheckMap(v8::internal::Register, v8::internal::Handle<v8::internal::Map>, v8::internal::Label*, v8::internal::SmiCheckType)
+            |
+            --- v8::internal::MacroAssembler::CheckMap(v8::internal::Register, v8::internal::Handle<v8::internal::Map>, v8::internal::Label*, v8::internal::SmiCheckType)
+
+0.12^3525548^HTMLParserThrea^chrome               ^[.] v8::internal::String::SlowTryFlatten(v8::internal::PretenureFlag)
+            |
+            --- v8::internal::String::SlowTryFlatten(v8::internal::PretenureFlag)
+
+0.12^3525251^HTMLParserThrea^chrome               ^[.] WebCore::RuleSet::addChildRules(WTF::Vector<WTF::RefPtr<WebCore::StyleRuleBase>, 0ul> const&, WebCore::MediaQueryEvaluator const&, WebCore::StyleResolver*, WebCore::ContainerNode const*, bool, WebCore::AddRuleFlags)
+            |
+            --- WebCore::RuleSet::addChildRules(WTF::Vector<WTF::RefPtr<WebCore::StyleRuleBase>, 0ul> const&, WebCore::MediaQueryEvaluator const&, WebCore::StyleResolver*, WebCore::ContainerNode const*, bool, WebCore::AddRuleFlags)
+
+0.12^3524914^HTMLParserThrea^chrome               ^[.] v8::internal::PositionsRecorder::WriteRecordedPositions()
+            |
+            --- v8::internal::PositionsRecorder::WriteRecordedPositions()
+
+0.12^3524273^HTMLParserThrea^chrome               ^[.] WebCore::FrameLoader::checkLoadComplete()
+            |
+            --- WebCore::FrameLoader::checkLoadComplete()
+
+0.12^3523358^HTMLParserThrea^chrome               ^[.] v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::EvacuateFixedArray(v8::internal::Map*, v8::internal::HeapObject**, v8::internal::HeapObject*)
+            |
+            --- v8::internal::ScavengingVisitor<(v8::internal::MarksHandling)1, (v8::internal::LoggingAndProfiling)1>::EvacuateFixedArray(v8::internal::Map*, v8::internal::HeapObject**, v8::internal::HeapObject*)
+
+0.12^3522817^HTMLParserThrea^chrome               ^[.] WebCore::HTMLFrameElementBase::attach(WebCore::Node::AttachContext const&)
+            |
+            --- WebCore::HTMLFrameElementBase::attach(WebCore::Node::AttachContext const&)
+
+0.12^3522399^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime::SetObjectProperty(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, PropertyAttributes, v8::internal::StrictModeFlag)
+            |
+            --- v8::internal::Runtime::SetObjectProperty(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, PropertyAttributes, v8::internal::StrictModeFlag)
+                0x2281c143442a
+                0x2281c143180c
+                0x2281c14310e9
+                0x2281c140e854
+                0x2281c14317b0
+                0x2281c14310e9
+                0x2281c140e854
+                0x2281c14317b0
+                0x2281c14310e9
+                0x2281c140e854
+                0x2281c142b65e
+                0x2281c1417d97
+                v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)
+
+0.12^3521835^HTMLParserThrea^chrome               ^[.] v8::Object::SetAlignedPointerInInternalField(int, void*)
+            |
+            --- v8::Object::SetAlignedPointerInInternalField(int, void*)
+
+0.12^3519670^HTMLParserThrea^chrome               ^[.] v8::internal::HDeadCodeEliminationPhase::RemoveDeadInstructions()
+            |
+            --- v8::internal::HDeadCodeEliminationPhase::RemoveDeadInstructions()
+                0x7fff30e8edb0
+
+0.12^3518719^HTMLParserThrea^chrome               ^[.] v8::internal::LCodeGen::Comment(char const*, ...)
+            |
+            --- v8::internal::LCodeGen::Comment(char const*, ...)
+
+0.12^3518131^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::HasRealNamedProperty(v8::internal::Isolate*, v8::internal::Name*)
+            |
+            --- v8::internal::JSObject::HasRealNamedProperty(v8::internal::Isolate*, v8::internal::Name*)
+
+0.12^3516705^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime_GetTemplateField(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::Runtime_GetTemplateField(int, v8::internal::Object**, v8::internal::Isolate*)
+                0x2281c1431084
+                0x2281c140e854
+                0x2281c142b65e
+                0x2281c1417d97
+                v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)
+
+0.12^3515242^HTMLParserThrea^chrome               ^[.] void WebCore::StyleResolver::applyProperties<(WebCore::StyleResolver::StyleApplicationPass)0>(WebCore::StyleResolverState&, WebCore::StylePropertySet const*, WebCore::StyleRule*, bool, bool, WebCore::PropertyWhitelistType)
+            |
+            --- void WebCore::StyleResolver::applyProperties<(WebCore::StyleResolver::StyleApplicationPass)0>(WebCore::StyleResolverState&, WebCore::StylePropertySet const*, WebCore::StyleRule*, bool, bool, WebCore::PropertyWhitelistType)
+
+0.12^3514809^HTMLParserThrea^chrome               ^[.] url_util::LowerCaseEqualsASCII(char const*, char const*, char const*)
+            |
+            --- url_util::LowerCaseEqualsASCII(char const*, char const*, char const*)
+
+0.12^3514002^HTMLParserThrea^chrome               ^[.] v8::internal::ScavengeVisitor::VisitPointer(v8::internal::Object**)
+            |
+            --- v8::internal::ScavengeVisitor::VisitPointer(v8::internal::Object**)
+
+0.12^3513688^HTMLParserThrea^chrome               ^[.] _ZN2v88internal15DescriptorArray6AppendEPNS0_10DescriptorERKNS1_16WhitenessWitnessE.constprop.537
+            |
+            --- _ZN2v88internal15DescriptorArray6AppendEPNS0_10DescriptorERKNS1_16WhitenessWitnessE.constprop.537
+
+0.12^3512883^HTMLParserThrea^chrome               ^[.] v8::internal::LoadIC_Miss(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::LoadIC_Miss(int, v8::internal::Object**, v8::internal::Isolate*)
+                0x7fff30e92040
+
+0.12^3511238^HTMLParserThrea^chrome               ^[.] WebCore::V8ScriptRunner::precompileScript(v8::Handle<v8::String>, WebCore::CachedScript*)
+            |
+            --- WebCore::V8ScriptRunner::precompileScript(v8::Handle<v8::String>, WebCore::CachedScript*)
+
+0.12^3506824^HTMLParserThrea^chrome               ^[.] v8::internal::Factory::NewAllocationSite()
+            |
+            --- v8::internal::Factory::NewAllocationSite()
+
+0.12^3504680^HTMLParserThrea^chrome               ^[.] WebCore::InputTypeNames::text()
+            |
+            --- WebCore::InputTypeNames::text()
+
+0.12^3503829^HTMLParserThrea^chrome               ^[.] v8::internal::FastElementsAccessor<v8::internal::FastPackedObjectElementsAccessor, v8::internal::ElementsKindTraits<(v8::internal::ElementsKind)2>, 8>::SetLengthWithoutNormalize(v8::internal::FixedArrayBase*, v8::internal::JSArray*, v8::internal::Object*, unsigned int)
+            |
+            --- v8::internal::FastElementsAccessor<v8::internal::FastPackedObjectElementsAccessor, v8::internal::ElementsKindTraits<(v8::internal::ElementsKind)2>, 8>::SetLengthWithoutNormalize(v8::internal::FixedArrayBase*, v8::internal::JSArray*, v8::internal::Object*, unsigned int)
+
+0.12^3500368^HTMLParserThrea^chrome               ^[.] WTF::Vector<WTF::String, 0ul>::expandCapacity(unsigned long)
+            |
+            --- WTF::Vector<WTF::String, 0ul>::expandCapacity(unsigned long)
+                0x1000
+
+0.12^3497657^HTMLParserThrea^chrome               ^[.] WebCore::RenderObject::adjustStyleDifference(WebCore::StyleDifference, unsigned int) const
+            |
+            --- WebCore::RenderObject::adjustStyleDifference(WebCore::StyleDifference, unsigned int) const
+
+0.12^3494287^HTMLParserThrea^chrome               ^[.] v8::internal::IC::Clear(unsigned char*)
+            |
+            --- v8::internal::IC::Clear(unsigned char*)
+
+0.12^3492300^HTMLParserThrea^chrome               ^[.] ppapi::proxy::InterfaceProxy::Send(IPC::Message*)
+            |
+            --- ppapi::proxy::InterfaceProxy::Send(IPC::Message*)
+
+0.12^3492214^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::Assembler(v8::internal::Isolate*, void*, int)
+            |
+            --- v8::internal::Assembler::Assembler(v8::internal::Isolate*, void*, int)
+                0xc6a346f4711
+
+0.12^3489812^HTMLParserThrea^chrome               ^[.] WebCore::SelectorCheckerFastPath::matchesRightmostSelector(WebCore::SelectorChecker::VisitedMatchType) const
+            |
+            --- WebCore::SelectorCheckerFastPath::matchesRightmostSelector(WebCore::SelectorChecker::VisitedMatchType) const
+
+0.12^3488486^HTMLParserThrea^chrome               ^[.] tc_free
+            |
+            --- tc_free
+                0x100000000
+                0x29f988404121
+
+0.12^3488229^HTMLParserThrea^chrome               ^[.] WebCore::RenderObject::updateFillImages(WebCore::FillLayer const*, WebCore::FillLayer const*)
+            |
+            --- WebCore::RenderObject::updateFillImages(WebCore::FillLayer const*, WebCore::FillLayer const*)
+
+0.12^3486534^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParsePostfixExpression(bool*)
+            |
+            --- v8::internal::Parser::ParsePostfixExpression(bool*)
+                0x7fff30e905d002
+
+0.12^3484804^HTMLParserThrea^chrome               ^[.] v8::internal::SharedStoreIC_ExtendStorage(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::SharedStoreIC_ExtendStorage(int, v8::internal::Object**, v8::internal::Isolate*)
+
+0.12^3484146^HTMLParserThrea^chrome               ^[.] WebCore::RenderCounter::rendererSubtreeAttached(WebCore::RenderObject*)
+            |
+            --- WebCore::RenderCounter::rendererSubtreeAttached(WebCore::RenderObject*)
+
+0.12^3483547^HTMLParserThrea^chrome               ^[.] WebCore::LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned int, WebCore::ContainerNode*) const
+            |
+            --- WebCore::LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned int, WebCore::ContainerNode*) const
+
+0.12^3482072^HTMLParserThrea^chrome               ^[.] v8::internal::CPU::FlushICache(void*, unsigned long)
+            |
+            --- v8::internal::CPU::FlushICache(void*, unsigned long)
+
+0.12^3481935^HTMLParserThrea^chrome               ^[.] WebCore::StyleResolver::matchAuthorRules(WebCore::Element*, WebCore::ElementRuleCollector&, bool)
+            |
+            --- WebCore::StyleResolver::matchAuthorRules(WebCore::Element*, WebCore::ElementRuleCollector&, bool)
+                0x1e83176abb08
+
+0.12^3481470^HTMLParserThrea^chrome               ^[.] v8::internal::StackFrame::GetCallerState(v8::internal::StackFrame::State*) const
+            |
+            --- v8::internal::StackFrame::GetCallerState(v8::internal::StackFrame::State*) const
+                0x7fff30e8f698
+                0x9d2ae7aa1e1
+
+0.12^3479937^HTMLParserThrea^chrome               ^[.] WTF::AtomicString::add(unsigned char const*)
+            |
+            --- WTF::AtomicString::add(unsigned char const*)
+
+0.12^3476115^HTMLParserThrea^chrome               ^[.] WebCore::StyleAdjuster::adjustRenderStyle(WebCore::RenderStyle*, WebCore::RenderStyle*, WebCore::Element*)
+            |
+            --- WebCore::StyleAdjuster::adjustRenderStyle(WebCore::RenderStyle*, WebCore::RenderStyle*, WebCore::Element*)
+
+0.12^3474363^HTMLParserThrea^chrome               ^[.] WebCore::CSSValue::deref()
+            |
+            --- WebCore::CSSValue::deref()
+
+0.12^3473710^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::movq(v8::internal::Register, long, v8::internal::RelocInfo::Mode)
+            |
+            --- v8::internal::Assembler::movq(v8::internal::Register, long, v8::internal::RelocInfo::Mode)
+
+0.12^3471996^HTMLParserThrea^chrome               ^[.] v8::internal::RegExpEngine::Compile(v8::internal::RegExpCompileData*, bool, bool, bool, v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::String>, bool, v8::internal::Zone*)
+            |
+            --- v8::internal::RegExpEngine::Compile(v8::internal::RegExpCompileData*, bool, bool, bool, v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::String>, bool, v8::internal::Zone*)
+                0xc6a3439fca1
+
+0.12^3468177^HTMLParserThrea^chrome               ^[.] v8::internal::Context::global_proxy()
+            |
+            --- v8::internal::Context::global_proxy()
+
+0.12^3467384^HTMLParserThrea^chrome               ^[.] WTF::Vector<std::pair<void (*)(WebCore::Node*), WTF::RefPtr<WebCore::Node> >, 0ul>::shrinkCapacity(unsigned long)
+            |
+            --- WTF::Vector<std::pair<void (*)(WebCore::Node*), WTF::RefPtr<WebCore::Node> >, 0ul>::shrinkCapacity(unsigned long)
+
+0.12^3466196^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::GetSymbol()
+            |
+            --- v8::internal::Parser::GetSymbol()
+                0x7fff30e9182000
+
+0.12^3462208^HTMLParserThrea^chrome               ^[.] v8::internal::JSReceiver::SetProperty(v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::StrictModeFlag, v8::internal::JSReceiver::StoreFromKeyed)
+            |
+            --- v8::internal::JSReceiver::SetProperty(v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::StrictModeFlag, v8::internal::JSReceiver::StoreFromKeyed)
+                0x7fff30e91950
+
+0.12^3461655^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::shouldBeNormalFlowOnlyIgnoringCompositedScrolling() const
+            |
+            --- WebCore::RenderLayer::shouldBeNormalFlowOnlyIgnoringCompositedScrolling() const
+
+0.11^3453572^HTMLParserThrea^chrome               ^[.] v8::internal::HBasicBlock::HBasicBlock(v8::internal::HGraph*)
+            |
+            --- v8::internal::HBasicBlock::HBasicBlock(v8::internal::HGraph*)
+
+0.11^3450775^HTMLParserThrea^chrome               ^[.] WebCore::RenderObject::invalidateContainerPreferredLogicalWidths()
+            |
+            --- WebCore::RenderObject::invalidateContainerPreferredLogicalWidths()
+
+0.11^3446446^HTMLParserThrea^chrome               ^[.] WebCore::LayoutUnit::round() const
+            |
+            --- WebCore::LayoutUnit::round() const
+
+0.11^3445539^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime_RegExpExec(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::Runtime_RegExpExec(int, v8::internal::Object**, v8::internal::Isolate*)
+                0xc6a3540bd09
+
+0.11^3445347^HTMLParserThrea^chrome               ^[.] v8::internal::BaseLoadStubCompiler::GenerateLoadCallback(v8::internal::Register, v8::internal::Handle<v8::internal::ExecutableAccessorInfo>)
+            |
+            --- v8::internal::BaseLoadStubCompiler::GenerateLoadCallback(v8::internal::Register, v8::internal::Handle<v8::internal::ExecutableAccessorInfo>)
+
+0.11^3444801^HTMLParserThrea^chrome               ^[.] v8::internal::BufferedUtf16CharacterStream::ReadBlock()
+            |
+            --- v8::internal::BufferedUtf16CharacterStream::ReadBlock()
+                0x7fff30e91798
+
+0.11^3436515^HTMLParserThrea^chrome               ^[.] WTF::Vector<unsigned short, 256ul>::shrinkCapacity(unsigned long)
+            |
+            --- WTF::Vector<unsigned short, 256ul>::shrinkCapacity(unsigned long)
+
+0.11^3435352^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseFunctionLiteral(v8::internal::Handle<v8::internal::String>, bool, bool, int, v8::internal::FunctionLiteral::FunctionType, bool*)
+            |
+            --- v8::internal::Parser::ParseFunctionLiteral(v8::internal::Handle<v8::internal::String>, bool, bool, int, v8::internal::FunctionLiteral::FunctionType, bool*)
+                0x7fff30e903a000
+
+0.11^3434720^HTMLParserThrea^chrome               ^[.] WebCore::ImageSource::setData(WebCore::SharedBuffer*, bool)
+            |
+            --- WebCore::ImageSource::setData(WebCore::SharedBuffer*, bool)
+
+0.11^3432682^HTMLParserThrea^chrome               ^[.] v8::internal::StandardFrame::ComputeCallerState(v8::internal::StackFrame::State*) const
+            |
+            --- v8::internal::StandardFrame::ComputeCallerState(v8::internal::StackFrame::State*) const
+                0x7fff30e90df8
+                0xc6a346b4fe9
+
+0.11^3432008^HTMLParserThrea^chrome               ^[.] v8::internal::VariableProxy::Accept(v8::internal::AstVisitor*)
+            |
+            --- v8::internal::VariableProxy::Accept(v8::internal::AstVisitor*)
+
+0.11^3420656^HTMLParserThrea^chrome               ^[.] SkBlitter::Choose(SkBitmap const&, SkMatrix const&, SkPaint const&, void*, unsigned long)
+            |
+            --- SkBlitter::Choose(SkBitmap const&, SkMatrix const&, SkPaint const&, void*, unsigned long)
+
+0.11^3420637^HTMLParserThrea^chrome               ^[.] v8::internal::Map::UpdateCodeCache(v8::internal::Name*, v8::internal::Code*)
+            |
+            --- v8::internal::Map::UpdateCodeCache(v8::internal::Name*, v8::internal::Code*)
+
+0.11^3419913^HTMLParserThrea^chrome               ^[.] WebCore::Element::childrenChanged(bool, WebCore::Node*, WebCore::Node*, int)
+            |
+            --- WebCore::Element::childrenChanged(bool, WebCore::Node*, WebCore::Node*, int)
+
+0.11^3413310^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::ResolveVariablesRecursively(v8::internal::CompilationInfo*, v8::internal::AstNodeFactory<v8::internal::AstNullVisitor>*)
+            |
+            --- v8::internal::Scope::ResolveVariablesRecursively(v8::internal::CompilationInfo*, v8::internal::AstNodeFactory<v8::internal::AstNullVisitor>*)
+
+0.11^3413062^HTMLParserThrea^chrome               ^[.] void WTF::Vector<WebCore::MatchedProperties, 0ul>::append<WebCore::MatchedProperties>(WebCore::MatchedProperties const*, unsigned long)
+            |
+            --- void WTF::Vector<WebCore::MatchedProperties, 0ul>::append<WebCore::MatchedProperties>(WebCore::MatchedProperties const*, unsigned long)
+
+0.11^3409803^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::movq(v8::internal::Register, v8::internal::Operand const&)
+            |
+            --- v8::internal::Assembler::movq(v8::internal::Register, v8::internal::Operand const&)
+
+0.11^3406785^HTMLParserThrea^chrome               ^[.] v8::internal::HashTable<v8::internal::MapCacheShape, v8::internal::HashTableKey*>::FindEntry(v8::internal::Isolate*, v8::internal::HashTableKey*)
+            |
+            --- v8::internal::HashTable<v8::internal::MapCacheShape, v8::internal::HashTableKey*>::FindEntry(v8::internal::Isolate*, v8::internal::HashTableKey*)
+
+0.11^3404799^HTMLParserThrea^chrome               ^[.] WebCore::RenderLineBoxList::removeLineBox(WebCore::InlineFlowBox*)
+            |
+            --- WebCore::RenderLineBoxList::removeLineBox(WebCore::InlineFlowBox*)
+
+0.11^3398149^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::clippingRootForPainting() const
+            |
+            --- WebCore::RenderLayer::clippingRootForPainting() const
+                0x2bc00000a000
+
+0.11^3390095^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::VarOperand(v8::internal::Variable*, v8::internal::Register)
+            |
+            --- v8::internal::FullCodeGenerator::VarOperand(v8::internal::Variable*, v8::internal::Register)
+                0x7fff30e91980
+
+0.11^3388424^HTMLParserThrea^chrome               ^[.] WebCore::DOMTimer::fired()
+            |
+            --- WebCore::DOMTimer::fired()
+
+0.11^3378612^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::SetFastElementsCapacityAndLength(int, int, v8::internal::JSObject::SetFastElementsCapacitySmiMode)
+            |
+            --- v8::internal::JSObject::SetFastElementsCapacityAndLength(int, int, v8::internal::JSObject::SetFastElementsCapacitySmiMode)
+
+0.11^3374619^HTMLParserThrea^chrome               ^[.] v8::internal::Code::MakeCodeAgeSequenceYoung(unsigned char*)
+            |
+            --- v8::internal::Code::MakeCodeAgeSequenceYoung(unsigned char*)
+                0x2281c140e854
+                0x2281c1e636e1
+                0x2281c1e52c8f
+                0x2281c142b664
+                0x2281c1417d97
+                v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)
+
+0.11^3373628^HTMLParserThrea^chrome               ^[.] ucase_fold_46
+            |
+            --- ucase_fold_46
+
+0.11^3372159^HTMLParserThrea^chrome               ^[.] WebCore::LayoutState::LayoutState(WebCore::LayoutState*, WebCore::RenderBox*, WebCore::LayoutSize const&, WebCore::LayoutUnit, bool, WebCore::ColumnInfo*)
+            |
+            --- WebCore::LayoutState::LayoutState(WebCore::LayoutState*, WebCore::RenderBox*, WebCore::LayoutSize const&, WebCore::LayoutUnit, bool, WebCore::ColumnInfo*)
+
+0.11^3365891^HTMLParserThrea^chrome               ^[.] v8::internal::HOptimizedGraphBuilder::BuildGraph()
+            |
+            --- v8::internal::HOptimizedGraphBuilder::BuildGraph()
+
+0.11^3359190^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::Initialize()
+            |
+            --- v8::internal::Scope::Initialize()
+
+0.11^3356725^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::updateScrollbarsAfterLayout()
+            |
+            --- WebCore::RenderLayer::updateScrollbarsAfterLayout()
+
+0.11^3356459^HTMLParserThrea^chrome               ^[.] _ZN7WebCoreplEiRKNS_10LayoutUnitE.constprop.860
+            |
+            --- _ZN7WebCoreplEiRKNS_10LayoutUnitE.constprop.860
+
+0.11^3355399^HTMLParserThrea^chrome               ^[.] v8::internal::ExitFrame::GetCallerStackPointer() const
+            |
+            --- v8::internal::ExitFrame::GetCallerStackPointer() const
+                (nil)
+
+0.11^3351779^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::layoutRunsAndFloatsInRange(WebCore::LineLayoutState&, WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>&, WebCore::InlineIterator const&, WebCore::BidiStatus const&, unsigned int)
+            |
+            --- WebCore::RenderBlock::layoutRunsAndFloatsInRange(WebCore::LineLayoutState&, WebCore::BidiResolver<WebCore::InlineIterator, WebCore::BidiRun>&, WebCore::InlineIterator const&, WebCore::BidiStatus const&, unsigned int)
+                0x3b2abd866648
+
+0.11^3344999^HTMLParserThrea^chrome               ^[.] v8::internal::CompilationCacheRegExp::Lookup(v8::internal::Handle<v8::internal::String>, v8::internal::JSRegExp::Flags)
+            |
+            --- v8::internal::CompilationCacheRegExp::Lookup(v8::internal::Handle<v8::internal::String>, v8::internal::JSRegExp::Flags)
+
+0.11^3344476^HTMLParserThrea^chrome               ^[.] tracked_objects::DeathData::RecordDeath(int, int, int)
+            |
+            --- tracked_objects::DeathData::RecordDeath(int, int, int)
+
+0.11^3343357^HTMLParserThrea^chrome               ^[.] void WTF::Vector<WebCore::SelectorFilter::ParentStackFrame, 0ul>::appendSlowCase<WebCore::SelectorFilter::ParentStackFrame>(WebCore::SelectorFilter::ParentStackFrame const&)
+            |
+            --- void WTF::Vector<WebCore::SelectorFilter::ParentStackFrame, 0ul>::appendSlowCase<WebCore::SelectorFilter::ParentStackFrame>(WebCore::SelectorFilter::ParentStackFrame const&)
+
+0.11^3341336^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::VisitObjectLiteral(v8::internal::ObjectLiteral*)
+            |
+            --- v8::internal::FullCodeGenerator::VisitObjectLiteral(v8::internal::ObjectLiteral*)
+
+0.11^3340676^HTMLParserThrea^chrome               ^[.] v8::internal::Assignment::Accept(v8::internal::AstVisitor*)
+            |
+            --- v8::internal::Assignment::Accept(v8::internal::AstVisitor*)
+
+0.11^3336841^HTMLParserThrea^chrome               ^[.] v8::internal::MacroAssembler::Set(v8::internal::Register, long)
+            |
+            --- v8::internal::MacroAssembler::Set(v8::internal::Register, long)
+                0x3b2abd624000
+
+0.11^3335871^HTMLParserThrea^chrome               ^[.] v8::internal::Scanner::ScanRegExpPattern(bool)
+            |
+            --- v8::internal::Scanner::ScanRegExpPattern(bool)
+                0x10e8a1901
+
+0.11^3313926^HTMLParserThrea^chrome               ^[.] v8::internal::ToBooleanStub::Types::UpdateStatus(v8::internal::Handle<v8::internal::Object>)
+            |
+            --- v8::internal::ToBooleanStub::Types::UpdateStatus(v8::internal::Handle<v8::internal::Object>)
+                0x2281c14140c1
+
+0.11^3300775^HTMLParserThrea^chrome               ^[.] WebCore::SVGRenderSupport::setRendererHasSVGShadow(WebCore::RenderObject*, bool)
+            |
+            --- WebCore::SVGRenderSupport::setRendererHasSVGShadow(WebCore::RenderObject*, bool)
+
+0.11^3292871^HTMLParserThrea^chrome               ^[.] base::debug::TraceLog::GetInstance()
+            |
+            --- base::debug::TraceLog::GetInstance()
+
+0.11^3289620^HTMLParserThrea^chrome               ^[.] WebCore::FrameView::pagination() const
+            |
+            --- WebCore::FrameView::pagination() const
+                (nil)
+                0x3b2abdc16c30
+
+0.11^3274771^HTMLParserThrea^chrome               ^[.] v8::internal::Factory::NewMap(v8::internal::InstanceType, int, v8::internal::ElementsKind)
+            |
+            --- v8::internal::Factory::NewMap(v8::internal::InstanceType, int, v8::internal::ElementsKind)
+
+0.11^3268228^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool, WebCore::RenderBox*)
+            |
+            --- WebCore::RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool, WebCore::RenderBox*)
+
+0.11^3264333^HTMLParserThrea^chrome               ^[.] v8::internal::CreateObjectLiteralBoilerplate(v8::internal::Isolate*, v8::internal::Handle<v8::internal::FixedArray>, v8::internal::Handle<v8::internal::FixedArray>, bool, bool)
+            |
+            --- v8::internal::CreateObjectLiteralBoilerplate(v8::internal::Isolate*, v8::internal::Handle<v8::internal::FixedArray>, v8::internal::Handle<v8::internal::FixedArray>, bool, bool)
+
+0.11^3263293^HTMLParserThrea^chrome               ^[.] content::RenderViewObserver::DidClearWindowObject(WebKit::WebFrame*)
+            |
+            --- content::RenderViewObserver::DidClearWindowObject(WebKit::WebFrame*)
+
+0.11^3263262^HTMLParserThrea^chrome               ^[.] WebCore::V8HiddenPropertyName::sleepFunction()
+            |
+            --- WebCore::V8HiddenPropertyName::sleepFunction()
+                0x5bf5d67bd1
+
+0.11^3253742^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::boundingBox(WebCore::RenderLayer const*, unsigned int, WebCore::LayoutPoint const*) const
+            |
+            --- WebCore::RenderLayer::boundingBox(WebCore::RenderLayer const*, unsigned int, WebCore::LayoutPoint const*) const
+                (nil)
+
+0.11^3250656^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime_StringCharCodeAt(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::Runtime_StringCharCodeAt(int, v8::internal::Object**, v8::internal::Isolate*)
+                0x2281c1449ea3
+                0x2281c14497a7
+                0x2281c1425b83
+                0x2281c141b848
+                0x2281c1443ab6
+                0x2281c14480ae
+                0x2281c144938f
+                0x2281c142b664
+                0x2281c1417d97
+                v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)
+
+0.11^3240988^HTMLParserThrea^chrome               ^[.] WTF::equalIgnoringCaseNonNull(WTF::StringImpl const*, WTF::StringImpl const*)
+            |
+            --- WTF::equalIgnoringCaseNonNull(WTF::StringImpl const*, WTF::StringImpl const*)
+
+0.11^3237736^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::call(v8::internal::Handle<v8::internal::Code>, v8::internal::RelocInfo::Mode, v8::internal::TypeFeedbackId)
+            |
+            --- v8::internal::Assembler::call(v8::internal::Handle<v8::internal::Code>, v8::internal::RelocInfo::Mode, v8::internal::TypeFeedbackId)
+
+0.11^3228754^HTMLParserThrea^libpthread-2.15.so   ^[.] pthread_mutex_unlock
+            |
+            --- pthread_mutex_unlock
+
+0.11^3225835^HTMLParserThrea^chrome               ^[.] WebCore::RenderObject::repaintUsingContainer(WebCore::RenderLayerModelObject const*, WebCore::IntRect const&) const
+            |
+            --- WebCore::RenderObject::repaintUsingContainer(WebCore::RenderLayerModelObject const*, WebCore::IntRect const&) const
+
+0.11^3219559^HTMLParserThrea^chrome               ^[.] icu_46::RuleBasedBreakIterator::handleNext(icu_46::RBBIStateTable const*)
+            |
+            --- icu_46::RuleBasedBreakIterator::handleNext(icu_46::RBBIStateTable const*)
+
+0.11^3215902^HTMLParserThrea^chrome               ^[.] v8::internal::Scanner::Scanner(v8::internal::UnicodeCache*)
+            |
+            --- v8::internal::Scanner::Scanner(v8::internal::UnicodeCache*)
+                0x7f7a0b900000
+
+0.11^3202188^HTMLParserThrea^chrome               ^[.] v8::Object::FindInstanceInPrototypeChain(v8::Handle<v8::FunctionTemplate>)
+            |
+            --- v8::Object::FindInstanceInPrototypeChain(v8::Handle<v8::FunctionTemplate>)
+
+0.11^3202083^HTMLParserThrea^chrome               ^[.] WebCore::Element::attach(WebCore::Node::AttachContext const&)
+            |
+            --- WebCore::Element::attach(WebCore::Node::AttachContext const&)
+
+0.11^3200673^HTMLParserThrea^chrome               ^[.] v8::internal::CompareIC::NewInputState(v8::internal::CompareIC::State, v8::internal::Handle<v8::internal::Object>)
+            |
+            --- v8::internal::CompareIC::NewInputState(v8::internal::CompareIC::State, v8::internal::Handle<v8::internal::Object>)
+
+0.11^3176018^HTMLParserThrea^chrome               ^[.] WebCore::Element::recalcStyle(WebCore::Node::StyleChange)
+            |
+            --- WebCore::Element::recalcStyle(WebCore::Node::StyleChange)
+
+0.11^3170916^HTMLParserThrea^chrome               ^[.] WebCore::MajorGCWrapperVisitor::VisitPersistentHandle(v8::Persistent<v8::Value>*, unsigned short)
+            |
+            --- WebCore::MajorGCWrapperVisitor::VisitPersistentHandle(v8::Persistent<v8::Value>*, unsigned short)
+                0x80e894c5308
+
+0.10^3137671^HTMLParserThrea^chrome               ^[.] v8::internal::DependentCode::DeoptimizeDependentCodeGroup(v8::internal::Isolate*, v8::internal::DependentCode::DependencyGroup)
+            |
+            --- v8::internal::DependentCode::DeoptimizeDependentCodeGroup(v8::internal::Isolate*, v8::internal::DependentCode::DependencyGroup)
+
+0.10^3136480^HTMLParserThrea^chrome               ^[.] WebCore::DOMWindow::document() const
+            |
+            --- WebCore::DOMWindow::document() const
+
+0.10^3136403^HTMLParserThrea^chrome               ^[.] _ZNK3WTF7HashMapIPN7WebCore12RenderObjectENS_6RefPtrINS1_18CompositeAnimationEEENS_7PtrHashIS3_EENS_10HashTraitsIS3_EENS9_IS6_EEE3getERKS3_.isra.185
+            |
+            --- _ZNK3WTF7HashMapIPN7WebCore12RenderObjectENS_6RefPtrINS1_18CompositeAnimationEEENS_7PtrHashIS3_EENS_10HashTraitsIS3_EENS9_IS6_EEE3getERKS3_.isra.185
+
+0.10^3126165^HTMLParserThrea^chrome               ^[.] v8::internal::VariableProxy::BindTo(v8::internal::Variable*)
+            |
+            --- v8::internal::VariableProxy::BindTo(v8::internal::Variable*)
+                0x3b2abdf3f010
+
+0.10^3124159^HTMLParserThrea^chrome               ^[.] WebCore::InlineTextBox::logicalOverflowRect() const
+            |
+            --- WebCore::InlineTextBox::logicalOverflowRect() const
+                0xaf00000000
+                0x3b2abdda8680
+
+0.10^3121836^HTMLParserThrea^chrome               ^[.] v8::internal::JSObject::SetPropertyViaPrototypes(v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::StrictModeFlag, bool*)
+            |
+            --- v8::internal::JSObject::SetPropertyViaPrototypes(v8::internal::Name*, v8::internal::Object*, PropertyAttributes, v8::internal::StrictModeFlag, bool*)
+
+0.10^3107295^HTMLParserThrea^chrome               ^[.] WebCore::ElementStyleResources::ElementStyleResources()
+            |
+            --- WebCore::ElementStyleResources::ElementStyleResources()
+
+0.10^3103474^HTMLParserThrea^chrome               ^[.] void WTF::deleteAllValues<true, WebCore::RenderBlock::FloatingObject*, WTF::HashTable<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*, WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*, WTF::IdentityExtractor, WTF::ListHashSetNodeHashFunctions<WebCore::RenderBlock::FloatingObjectHashFunctions>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*>, WTF::HashTraits<WTF::ListHashSetNode<WebCo
+            |
+            --- void WTF::deleteAllValues<true, WebCore::RenderBlock::FloatingObject*, WTF::HashTable<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*, WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*, WTF::IdentityExtractor, WTF::ListHashSetNodeHashFunctions<WebCore::RenderBlock::FloatingObjectHashFunctions>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*> > const>(WTF::HashTable<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*, WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*, WTF::IdentityExtractor, WTF::ListHashSetNodeHashFunctions<WebCore::RenderBlock::FloatingObjectHashFunctions>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::RenderBlock::FloatingObject*, 4ul>*> > const&)
+
+0.10^3103474^HTMLParserThrea^chrome               ^[.] base::subtle::RefCountedBase::Release() const
+            |
+            --- base::subtle::RefCountedBase::Release() const
+
+0.10^3092884^HTMLParserThrea^chrome               ^[.] WebCore::RenderView::usesCompositing() const
+            |
+            --- WebCore::RenderView::usesCompositing() const
+
+0.10^3090079^HTMLParserThrea^chrome               ^[.] webCoreInitializeScriptWrappableForInterface(WebCore::Element*)
+            |
+            --- webCoreInitializeScriptWrappableForInterface(WebCore::Element*)
+
+0.10^3084985^HTMLParserThrea^chrome               ^[.] WebCore::ScopedStyleTree::pushStyleCache(WebCore::ContainerNode const*, WebCore::ContainerNode const*)
+            |
+            --- WebCore::ScopedStyleTree::pushStyleCache(WebCore::ContainerNode const*, WebCore::ContainerNode const*)
+
+0.10^3075629^HTMLParserThrea^chrome               ^[.] v8::internal::HydrogenCodeStub::MinorKey()
+            |
+            --- v8::internal::HydrogenCodeStub::MinorKey()
+
+0.10^3075535^HTMLParserThrea^librt-2.15.so        ^[.] clock_gettime
+            |
+            --- clock_gettime
+
+0.10^3066941^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::jmp(v8::internal::Handle<v8::internal::Code>, v8::internal::RelocInfo::Mode)
+            |
+            --- v8::internal::Assembler::jmp(v8::internal::Handle<v8::internal::Code>, v8::internal::RelocInfo::Mode)
+
+0.10^3064555^HTMLParserThrea^chrome               ^[.] WebCore::RenderStyle::getRoundedBorderFor(WebCore::LayoutRect const&, WebCore::RenderView*, bool, bool) const
+            |
+            --- WebCore::RenderStyle::getRoundedBorderFor(WebCore::LayoutRect const&, WebCore::RenderView*, bool, bool) const
+
+0.10^3056872^HTMLParserThrea^chrome               ^[.] WebCore::LayoutRect::intersect(WebCore::LayoutRect const&)
+            |
+            --- WebCore::LayoutRect::intersect(WebCore::LayoutRect const&)
+                (nil)
+
+0.10^3056623^HTMLParserThrea^chrome               ^[.] v8::internal::CodeCacheHashTable::Put(v8::internal::Name*, v8::internal::Code*)
+            |
+            --- v8::internal::CodeCacheHashTable::Put(v8::internal::Name*, v8::internal::Code*)
+
+0.10^3054623^HTMLParserThrea^chrome               ^[.] v8::internal::ActionNode::GetQuickCheckDetails(v8::internal::QuickCheckDetails*, v8::internal::RegExpCompiler*, int, bool)
+            |
+            --- v8::internal::ActionNode::GetQuickCheckDetails(v8::internal::QuickCheckDetails*, v8::internal::RegExpCompiler*, int, bool)
+                0x3b2a00000002
+
+0.10^3051571^HTMLParserThrea^chrome               ^[.] _ZN2v88internal12PropertyCell17SetValueInferTypeEPNS0_6ObjectENS0_16WriteBarrierModeE.part.326
+            |
+            --- _ZN2v88internal12PropertyCell17SetValueInferTypeEPNS0_6ObjectENS0_16WriteBarrierModeE.part.326
+
+0.10^3047011^HTMLParserThrea^chrome               ^[.] WebCore::RenderBoxModelObject::paintFillLayerExtended(WebCore::PaintInfo const&, WebCore::Color const&, WebCore::FillLayer const*, WebCore::LayoutRect const&, WebCore::BackgroundBleedAvoidance, WebCore::InlineFlowBox*, WebCore::LayoutSize const&, WebCore::CompositeOperator, WebCore::RenderObject*)
+            |
+            --- WebCore::RenderBoxModelObject::paintFillLayerExtended(WebCore::PaintInfo const&, WebCore::Color const&, WebCore::FillLayer const*, WebCore::LayoutRect const&, WebCore::BackgroundBleedAvoidance, WebCore::InlineFlowBox*, WebCore::LayoutSize const&, WebCore::CompositeOperator, WebCore::RenderObject*)
+
+0.10^3047011^HTMLParserThrea^chrome               ^[.] WebCore::Timer<WebCore::EventSender<WebCore::ImageLoader> >::fired()
+            |
+            --- WebCore::Timer<WebCore::EventSender<WebCore::ImageLoader> >::fired()
+
+0.10^3042405^HTMLParserThrea^chrome               ^[.] SkGlyphCache::getGlyphIDMetrics(unsigned short)
+            |
+            --- SkGlyphCache::getGlyphIDMetrics(unsigned short)
+
+0.10^3034275^HTMLParserThrea^chrome               ^[.] WebCore::StyleBuilder::applyProperty(WebCore::CSSPropertyID, WebCore::StyleResolver*, WebCore::StyleResolverState&, WebCore::CSSValue*, bool, bool)
+            |
+            --- WebCore::StyleBuilder::applyProperty(WebCore::CSSPropertyID, WebCore::StyleResolver*, WebCore::StyleResolverState&, WebCore::CSSValue*, bool, bool)
+                0x1e83176a8568
+
+0.10^3027837^HTMLParserThrea^chrome               ^[.] v8::preparser::PreParser::ParseBinaryExpression(int, bool, bool*)
+            |
+            --- v8::preparser::PreParser::ParseBinaryExpression(int, bool, bool*)
+                0x7f7a0b96214000
+
+0.10^3027190^HTMLParserThrea^chrome               ^[.] v8::internal::CallOptimization::GetPrototypeDepthOfExpectedType(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::JSObject>) const
+            |
+            --- v8::internal::CallOptimization::GetPrototypeDepthOfExpectedType(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::JSObject>) const
+
+0.10^3025376^HTMLParserThrea^chrome               ^[.] v8::Function::Call(v8::Handle<v8::Object>, int, v8::Handle<v8::Value>*)
+            |
+            --- v8::Function::Call(v8::Handle<v8::Object>, int, v8::Handle<v8::Value>*)
+
+0.10^3019937^HTMLParserThrea^chrome               ^[.] net::HttpResponseHeaders::EnumerateHeader(void**, base::BasicStringPiece<std::string> const&, std::string*) const
+            |
+            --- net::HttpResponseHeaders::EnumerateHeader(void**, base::BasicStringPiece<std::string> const&, std::string*) const
+                0x7fff30e91800
+
+0.10^3017488^HTMLParserThrea^chrome               ^[.] v8::internal::Parser::ParseLazy()
+            |
+            --- v8::internal::Parser::ParseLazy()
+
+0.10^3014944^HTMLParserThrea^chrome               ^[.] WebCore::MarkupAccumulator::appendAttribute(WTF::StringBuilder&, WebCore::Element*, WebCore::Attribute const&, WTF::HashMap<WTF::AtomicStringImpl*, WTF::AtomicStringImpl*, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*> >*)
+            |
+            --- WebCore::MarkupAccumulator::appendAttribute(WTF::StringBuilder&, WebCore::Element*, WebCore::Attribute const&, WTF::HashMap<WTF::AtomicStringImpl*, WTF::AtomicStringImpl*, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*> >*)
+
+0.10^3005563^HTMLParserThrea^chrome               ^[.] tcmalloc::PageHeap::Carve(tcmalloc::Span*, unsigned long)
+            |
+            --- tcmalloc::PageHeap::Carve(tcmalloc::Span*, unsigned long)
+
+0.10^3002471^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::paintOutlineForFragments(WTF::Vector<WebCore::LayerFragment, 1ul> const&, WebCore::GraphicsContext*, WebCore::RenderLayer::LayerPaintingInfo const&, unsigned int, WebCore::RenderObject*)
+            |
+            --- WebCore::RenderLayer::paintOutlineForFragments(WTF::Vector<WebCore::LayerFragment, 1ul> const&, WebCore::GraphicsContext*, WebCore::RenderLayer::LayerPaintingInfo const&, unsigned int, WebCore::RenderObject*)
+
+0.10^2988466^HTMLParserThrea^chrome               ^[.] v8::internal::CompareIC::TargetState(v8::internal::CompareIC::State, v8::internal::CompareIC::State, v8::internal::CompareIC::State, bool, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>)
+            |
+            --- v8::internal::CompareIC::TargetState(v8::internal::CompareIC::State, v8::internal::CompareIC::State, v8::internal::CompareIC::State, bool, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>)
+
+0.10^2985776^HTMLParserThrea^chrome               ^[.] v8::internal::CodeStub::UseSpecialCache()
+            |
+            --- v8::internal::CodeStub::UseSpecialCache()
+
+0.10^2983793^HTMLParserThrea^chrome               ^[.] v8::internal::Genesis::TransferNamedProperties(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::JSObject>)
+            |
+            --- v8::internal::Genesis::TransferNamedProperties(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::JSObject>)
+
+0.10^2978233^HTMLParserThrea^chrome               ^[.] v8::internal::ReturnStatement::Accept(v8::internal::AstVisitor*)
+            |
+            --- v8::internal::ReturnStatement::Accept(v8::internal::AstVisitor*)
+
+0.10^2961361^HTMLParserThrea^chrome               ^[.] WebCore::HTMLInputElement::parseAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&)
+            |
+            --- WebCore::HTMLInputElement::parseAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&)
+                WebCore::V8PerIsolateData::hasInstance(WebCore::WrapperTypeInfo*, v8::Handle<v8::Value>, WebCore::WrapperWorldType)
+
+0.10^2950771^HTMLParserThrea^chrome               ^[.] webkit::ppapi::PluginInstance::Paint(SkCanvas*, gfx::Rect const&, gfx::Rect const&)
+            |
+            --- webkit::ppapi::PluginInstance::Paint(SkCanvas*, gfx::Rect const&, gfx::Rect const&)
+
+0.10^2941407^HTMLParserThrea^chrome               ^[.] WebCore::DocumentStyleSheetCollection::combineCSSFeatureFlags(WebCore::RuleFeatureSet const&)
+            |
+            --- WebCore::DocumentStyleSheetCollection::combineCSSFeatureFlags(WebCore::RuleFeatureSet const&)
+
+0.10^2927492^HTMLParserThrea^chrome               ^[.] SkCanvas::~SkCanvas()
+            |
+            --- SkCanvas::~SkCanvas()
+
+0.10^2924222^HTMLParserThrea^chrome               ^[.] WTF::HashTableAddResult<WTF::HashTableIterator<unsigned long, WTF::KeyValuePair<unsigned long, WTF::OwnPtr<WebCore::ProgressItem> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<unsigned long, WTF::OwnPtr<WebCore::ProgressItem> > >, WTF::IntHash<unsigned long>, WTF::HashMapValueTraits<WTF::HashTraits<unsigned long>, WTF::HashTraits<WTF::OwnPtr<WebCore::ProgressItem> > >, WTF::HashTraits<unsigned long> > > WTF::HashTable<unsigned long, WTF::KeyValueP
+            |
+            --- WTF::HashTableAddResult<WTF::HashTableIterator<unsigned long, WTF::KeyValuePair<unsigned long, WTF::OwnPtr<WebCore::ProgressItem> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<unsigned long, WTF::OwnPtr<WebCore::ProgressItem> > >, WTF::IntHash<unsigned long>, WTF::HashMapValueTraits<WTF::HashTraits<unsigned long>, WTF::HashTraits<WTF::OwnPtr<WebCore::ProgressItem> > >, WTF::HashTraits<unsigned long> > > WTF::HashTable<unsigned long, WTF::KeyValuePair<unsigned long, WTF::OwnPtr<WebCore::ProgressItem> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<unsigned long, WTF::OwnPtr<WebCore::ProgressItem> > >, WTF::IntHash<unsigned long>, WTF::HashMapValueTraits<WTF::HashTraits<unsigned long>, WTF::HashTraits<WTF::OwnPtr<WebCore::ProgressItem> > >, WTF::HashTraits<unsigned long> >::add<WTF::HashMapTranslator<WTF::HashMapValueTraits<WTF::HashTraits<unsigned long>, WTF::HashTraits<WTF::OwnPtr<WebCore::ProgressItem> > >, WTF::IntHash<unsigned long> >, unsigned long, WTF::PassOwnPtr<WebCore::ProgressItem> >(unsigned long const&, WTF::PassOwnPtr<WebCore::ProgressItem> const&)
+
+0.10^2912173^HTMLParserThrea^chrome               ^[.] v8::internal::Genesis::CreateNewGlobals(v8::Handle<v8::ObjectTemplate>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::GlobalObject>*)
+            |
+            --- v8::internal::Genesis::CreateNewGlobals(v8::Handle<v8::ObjectTemplate>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::GlobalObject>*)
+
+0.10^2898436^HTMLParserThrea^chrome               ^[.] v8::internal::Runtime_FunctionSetName(int, v8::internal::Object**, v8::internal::Isolate*)
+            |
+            --- v8::internal::Runtime_FunctionSetName(int, v8::internal::Object**, v8::internal::Isolate*)
+                0x2281c14315f1
+                0x2281c14310e9
+                0x2281c1434402
+                0x2281c142b664
+                0x2281c1417d97
+                v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)
+
+0.10^2892794^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::AllocateUninitializedFixedArray(int)
+            |
+            --- v8::internal::Heap::AllocateUninitializedFixedArray(int)
+
+0.10^2891663^HTMLParserThrea^chrome               ^[.] content::RenderViewImpl::didCommitProvisionalLoad(WebKit::WebFrame*, bool)
+            |
+            --- content::RenderViewImpl::didCommitProvisionalLoad(WebKit::WebFrame*, bool)
+
+0.10^2867709^HTMLParserThrea^chrome               ^[.] v8::internal::Object::GetPropertyWithReceiver(v8::internal::Object*, v8::internal::Name*, PropertyAttributes*)
+            |
+            --- v8::internal::Object::GetPropertyWithReceiver(v8::internal::Object*, v8::internal::Name*, PropertyAttributes*)
+
+0.09^2852873^HTMLParserThrea^chrome               ^[.] WebCore::RenderLineBoxList::deleteLineBoxes(WebCore::RenderArena*)
+            |
+            --- WebCore::RenderLineBoxList::deleteLineBoxes(WebCore::RenderArena*)
+
+0.09^2848135^HTMLParserThrea^chrome               ^[.] base::internal::IncomingTaskQueue::PostPendingTask(base::PendingTask*)
+            |
+            --- base::internal::IncomingTaskQueue::PostPendingTask(base::PendingTask*)
+
+0.09^2845960^HTMLParserThrea^chrome               ^[.] WebCore::V8HTMLEmbedElement::namedPropertyGetterCustom(v8::Local<v8::String>, v8::PropertyCallbackInfo<v8::Value> const&)
+            |
+            --- WebCore::V8HTMLEmbedElement::namedPropertyGetterCustom(v8::Local<v8::String>, v8::PropertyCallbackInfo<v8::Value> const&)
+                0x7f7a0b900000
+
+0.09^2831855^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::paintLayerContents(WebCore::GraphicsContext*, WebCore::RenderLayer::LayerPaintingInfo const&, unsigned int)
+            |
+            --- WebCore::RenderLayer::paintLayerContents(WebCore::GraphicsContext*, WebCore::RenderLayer::LayerPaintingInfo const&, unsigned int)
+                (nil)
+
+0.09^2830116^HTMLParserThrea^chrome               ^[.] v8::internal::RegExpParser::Advance()
+            |
+            --- v8::internal::RegExpParser::Advance()
+                0x3b2abdce1010
+
+0.09^2802116^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::logicalLeftFloatOffsetForLine(WebCore::LayoutUnit, WebCore::LayoutUnit, WebCore::LayoutUnit*, WebCore::LayoutUnit, WebCore::RenderBlock::ShapeOutsideFloatOffsetMode) const
+            |
+            --- WebCore::RenderBlock::logicalLeftFloatOffsetForLine(WebCore::LayoutUnit, WebCore::LayoutUnit, WebCore::LayoutUnit*, WebCore::LayoutUnit, WebCore::RenderBlock::ShapeOutsideFloatOffsetMode) const
+
+0.09^2792893^HTMLParserThrea^chrome               ^[.] v8::internal::HashTable<v8::internal::UnseededNumberDictionaryShape, unsigned int>::FindEntry(v8::internal::Isolate*, unsigned int)
+            |
+            --- v8::internal::HashTable<v8::internal::UnseededNumberDictionaryShape, unsigned int>::FindEntry(v8::internal::Isolate*, unsigned int)
+
+0.09^2758347^HTMLParserThrea^chrome               ^[.] v8::internal::ElementsAccessorBase<v8::internal::DictionaryElementsAccessor, v8::internal::ElementsKindTraits<(v8::internal::ElementsKind)6> >::Get(v8::internal::Object*, v8::internal::JSObject*, unsigned int, v8::internal::FixedArrayBase*)
+            |
+            --- v8::internal::ElementsAccessorBase<v8::internal::DictionaryElementsAccessor, v8::internal::ElementsKindTraits<(v8::internal::ElementsKind)6> >::Get(v8::internal::Object*, v8::internal::JSObject*, unsigned int, v8::internal::FixedArrayBase*)
+
+0.09^2738185^HTMLParserThrea^chrome               ^[.] v8::internal::LoadFieldStub::MajorKey()
+            |
+            --- v8::internal::LoadFieldStub::MajorKey()
+
+0.09^2719813^HTMLParserThrea^chrome               ^[.] _ZN2v88internal9Execution4CallENS0_6HandleINS0_6ObjectEEES4_iPS4_Pbb.constprop.84
+            |
+            --- _ZN2v88internal9Execution4CallENS0_6HandleINS0_6ObjectEEES4_iPS4_Pbb.constprop.84
+
+0.09^2709340^HTMLParserThrea^chrome               ^[.] operator delete(void*)
+            |
+            --- operator delete(void*)
+
+0.09^2697911^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::AllocateVariablesRecursively()
+            |
+            --- v8::internal::Scope::AllocateVariablesRecursively()
+
+0.09^2685980^HTMLParserThrea^chrome               ^[.] IPC::SyncChannel::SendWithTimeout(IPC::Message*, int)
+            |
+            --- IPC::SyncChannel::SendWithTimeout(IPC::Message*, int)
+
+0.09^2673092^HTMLParserThrea^chrome               ^[.] v8::internal::StubCache::ComputeCallPreMonomorphic(int, v8::internal::Code::Kind, int)
+            |
+            --- v8::internal::StubCache::ComputeCallPreMonomorphic(int, v8::internal::Code::Kind, int)
+
+0.09^2660139^HTMLParserThrea^chrome               ^[.] v8::internal::HashTable<v8::internal::CodeCacheHashTableShape, v8::internal::HashTableKey*>::FindEntry(v8::internal::HashTableKey*)
+            |
+            --- v8::internal::HashTable<v8::internal::CodeCacheHashTableShape, v8::internal::HashTableKey*>::FindEntry(v8::internal::HashTableKey*)
+
+0.09^2639411^HTMLParserThrea^chrome               ^[.] base::subtle::RefCountedThreadSafeBase::HasOneRef() const
+            |
+            --- base::subtle::RefCountedThreadSafeBase::HasOneRef() const
+                0x3b2abd1f8b20
+
+0.09^2639411^HTMLParserThrea^chrome               ^[.] PickleIterator::ReadLong(long*)
+            |
+            --- PickleIterator::ReadLong(long*)
+                0x2e40c81e951be0
+
+0.09^2632999^HTMLParserThrea^chrome               ^[.] IPC::SyncChannel::SyncContext::DispatchMessages()
+            |
+            --- IPC::SyncChannel::SyncContext::DispatchMessages()
+
+0.09^2600329^HTMLParserThrea^chrome               ^[.] v8::internal::Operand::Operand(v8::internal::Register, int)
+            |
+            --- v8::internal::Operand::Operand(v8::internal::Register, int)
+                0x3b2abd628000
+
+0.09^2577224^HTMLParserThrea^chrome               ^[.] v8::internal::CompareIC::ComputeCondition(v8::internal::Token::Value)
+            |
+            --- v8::internal::CompareIC::ComputeCondition(v8::internal::Token::Value)
+
+0.09^2566312^HTMLParserThrea^chrome               ^[.] v8::internal::Rewriter::Rewrite(v8::internal::CompilationInfo*)
+            |
+            --- v8::internal::Rewriter::Rewrite(v8::internal::CompilationInfo*)
+                0x7f7a0b900000
+
+0.08^2546113^HTMLParserThrea^chrome               ^[.] WebCore::RenderBoxModelObject::borderLeft() const
+            |
+            --- WebCore::RenderBoxModelObject::borderLeft() const
+
+0.08^2538991^HTMLParserThrea^chrome               ^[.] v8::internal::Handle<v8::internal::String> v8::internal::URIEscape::Escape<unsigned char>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>)
+            |
+            --- v8::internal::Handle<v8::internal::String> v8::internal::URIEscape::Escape<unsigned char>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>)
+
+0.08^2527291^HTMLParserThrea^chrome               ^[.] WTF::HashTableAddResult<WTF::HashTableIterator<WTF::StringImpl*, WTF::StringImpl*, WTF::IdentityExtractor, WTF::StringHash, WTF::HashTraits<WTF::StringImpl*>, WTF::HashTraits<WTF::StringImpl*> > > WTF::HashTable<WTF::StringImpl*, WTF::StringImpl*, WTF::IdentityExtractor, WTF::StringHash, WTF::HashTraits<WTF::StringImpl*>, WTF::HashTraits<WTF::StringImpl*> >::add<WTF::IdentityHashTranslator<WTF::StringHash>, WTF::StringImpl*, WTF::StringImpl*>(WTF::Stri
+            |
+            --- WTF::HashTableAddResult<WTF::HashTableIterator<WTF::StringImpl*, WTF::StringImpl*, WTF::IdentityExtractor, WTF::StringHash, WTF::HashTraits<WTF::StringImpl*>, WTF::HashTraits<WTF::StringImpl*> > > WTF::HashTable<WTF::StringImpl*, WTF::StringImpl*, WTF::IdentityExtractor, WTF::StringHash, WTF::HashTraits<WTF::StringImpl*>, WTF::HashTraits<WTF::StringImpl*> >::add<WTF::IdentityHashTranslator<WTF::StringHash>, WTF::StringImpl*, WTF::StringImpl*>(WTF::StringImpl* const&, WTF::StringImpl* const&)
+                0x7fff30e91098
+
+0.08^2505118^HTMLParserThrea^chrome               ^[.] v8::internal::AssertionNode::Emit(v8::internal::RegExpCompiler*, v8::internal::Trace*)
+            |
+            --- v8::internal::AssertionNode::Emit(v8::internal::RegExpCompiler*, v8::internal::Trace*)
+                0xa
+
+0.08^2499686^HTMLParserThrea^chrome               ^[.] base::SampleVector::GetBucketIndex(int) const
+            |
+            --- base::SampleVector::GetBucketIndex(int) const
+
+0.08^2493442^HTMLParserThrea^chrome               ^[.] v8::internal::RegExpImpl::SetLastMatchInfo(v8::internal::Handle<v8::internal::JSArray>, v8::internal::Handle<v8::internal::String>, int, int*)
+            |
+            --- v8::internal::RegExpImpl::SetLastMatchInfo(v8::internal::Handle<v8::internal::JSArray>, v8::internal::Handle<v8::internal::String>, int, int*)
+
+0.08^2449547^HTMLParserThrea^chrome               ^[.] content::(anonymous namespace)::RendererMessageLoopObserver::DidProcessTask(base::PendingTask const&)
+            |
+            --- content::(anonymous namespace)::RendererMessageLoopObserver::DidProcessTask(base::PendingTask const&)
+                0x7f7a0b8ff200
+
+0.08^2382741^HTMLParserThrea^chrome               ^[.] WTF::HashTableAddResult<WTF::HashTableIterator<WebCore::CachedResource*, WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::PtrHash<WebCore::CachedResource*>, WTF::HashMapValueTraits<WTF::HashTraits<WebCore::CachedResource*>, WTF::HashTraits<WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::H
+            |
+            --- WTF::HashTableAddResult<WTF::HashTableIterator<WebCore::CachedResource*, WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::PtrHash<WebCore::CachedResource*>, WTF::HashMapValueTraits<WTF::HashTraits<WebCore::CachedResource*>, WTF::HashTraits<WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::HashTraits<WebCore::CachedResource*> > > WTF::HashTable<WebCore::CachedResource*, WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> >, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WebCore::CachedResource*, WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::PtrHash<WebCore::CachedResource*>, WTF::HashMapValueTraits<WTF::HashTraits<WebCore::CachedResource*>, WTF::HashTraits<WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::HashTraits<WebCore::CachedResource*> >::add<WTF::HashMapTranslator<WTF::HashMapValueTraits<WTF::HashTraits<WebCore::CachedResource*>, WTF::HashTraits<WTF::RefPtr<WebCore::ResourceTimingInfo> > >, WTF::PtrHash<WebCore::CachedResource*> >, WebCore::CachedResource*, WTF::PassRefPtr<WebCore::ResourceTimingInfo> >(WebCore::CachedResource* const&, WTF::PassRefPtr<WebCore::ResourceTimingInfo> const&)
+
+0.08^2347799^HTMLParserThrea^chrome               ^[.] v8::internal::Isolate::MayNamedAccess(v8::internal::JSObject*, v8::internal::Object*, v8::AccessType)
+            |
+            --- v8::internal::Isolate::MayNamedAccess(v8::internal::JSObject*, v8::internal::Object*, v8::AccessType)
+
+0.08^2337746^HTMLParserThrea^chrome               ^[.] v8::internal::Heap::NumberFromDouble(double, v8::internal::PretenureFlag)
+            |
+            --- v8::internal::Heap::NumberFromDouble(double, v8::internal::PretenureFlag)
+
+0.08^2334937^HTMLParserThrea^chrome               ^[.] WebCore::LayoutRect::intersects(WebCore::LayoutRect const&) const
+            |
+            --- WebCore::LayoutRect::intersects(WebCore::LayoutRect const&) const
+
+0.08^2315633^HTMLParserThrea^chrome               ^[.] _ZN7content14RenderViewImpl15willSendRequestEPN6WebKit8WebFrameEjRNS1_13WebURLRequestERKNS1_14WebURLResponseE.part.953
+            |
+            --- _ZN7content14RenderViewImpl15willSendRequestEPN6WebKit8WebFrameEjRNS1_13WebURLRequestERKNS1_14WebURLResponseE.part.953
+                0x7f7a11c1f320
+                0x7fff30e90fd0
+
+0.08^2309876^HTMLParserThrea^libstdc++.so.6.0.16  ^[.] std::string::find_first_not_of(char const*, unsigned long, unsigned long) const
+            |
+            --- std::string::find_first_not_of(char const*, unsigned long, unsigned long) const
+                (nil)
+
+0.08^2271635^HTMLParserThrea^chrome               ^[.] base::TaskQueue::Swap(base::TaskQueue*)
+            |
+            --- base::TaskQueue::Swap(base::TaskQueue*)
+
+0.08^2270859^HTMLParserThrea^chrome               ^[.] v8::internal::Map::ShareDescriptor(v8::internal::DescriptorArray*, v8::internal::Descriptor*)
+            |
+            --- v8::internal::Map::ShareDescriptor(v8::internal::DescriptorArray*, v8::internal::Descriptor*)
+
+0.08^2267153^HTMLParserThrea^chrome               ^[.] v8::internal::Map::EnsureDescriptorSlack(v8::internal::Handle<v8::internal::Map>, int)
+            |
+            --- v8::internal::Map::EnsureDescriptorSlack(v8::internal::Handle<v8::internal::Map>, int)
+
+0.07^2254719^HTMLParserThrea^chrome               ^[.] v8::internal::Map::IndexInCodeCache(v8::internal::Object*, v8::internal::Code*)
+            |
+            --- v8::internal::Map::IndexInCodeCache(v8::internal::Object*, v8::internal::Code*)
+
+0.07^2218397^HTMLParserThrea^chrome               ^[.] WebCore::RenderBlock::paintContents(WebCore::PaintInfo&, WebCore::LayoutPoint const&)
+            |
+            --- WebCore::RenderBlock::paintContents(WebCore::PaintInfo&, WebCore::LayoutPoint const&)
+
+0.07^2215989^HTMLParserThrea^chrome               ^[.] SkRegion::freeRuns()
+            |
+            --- SkRegion::freeRuns()
+
+0.07^2213591^HTMLParserThrea^libpthread-2.15.so   ^[.] pthread_cond_destroy@@GLIBC_2.3.2
+            |
+            --- pthread_cond_destroy@@GLIBC_2.3.2
+
+0.07^2185498^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::paintForegroundForFragmentsWithPhase(WebCore::PaintPhase, WTF::Vector<WebCore::LayerFragment, 1ul> const&, WebCore::GraphicsContext*, WebCore::RenderLayer::LayerPaintingInfo const&, unsigned int, WebCore::RenderObject*)
+            |
+            --- WebCore::RenderLayer::paintForegroundForFragmentsWithPhase(WebCore::PaintPhase, WTF::Vector<WebCore::LayerFragment, 1ul> const&, WebCore::GraphicsContext*, WebCore::RenderLayer::LayerPaintingInfo const&, unsigned int, WebCore::RenderObject*)
+                (nil)
+
+0.07^2181719^HTMLParserThrea^chrome               ^[.] v8::internal::JSFunction::CompileLazy(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ClearExceptionFlag)
+            |
+            --- v8::internal::JSFunction::CompileLazy(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ClearExceptionFlag)
+
+0.07^2181709^HTMLParserThrea^chrome               ^[.] base::subtle::RefCountedThreadSafeBase::AddRef() const
+            |
+            --- base::subtle::RefCountedThreadSafeBase::AddRef() const
+
+0.07^2162161^HTMLParserThrea^chrome               ^[.] v8::internal::LChunk::MarkEmptyBlocks()
+            |
+            --- v8::internal::LChunk::MarkEmptyBlocks()
+
+0.07^2154798^HTMLParserThrea^chrome               ^[.] v8::preparser::PreParser::ParsePostfixExpression(bool*)
+            |
+            --- v8::preparser::PreParser::ParsePostfixExpression(bool*)
+
+0.07^2153747^HTMLParserThrea^chrome               ^[.] WebCore::deviceScaleFactor(WebCore::Frame*)
+            |
+            --- WebCore::deviceScaleFactor(WebCore::Frame*)
+                (nil)
+
+0.07^2111797^HTMLParserThrea^chrome               ^[.] v8::preparser::PreParser::ParseConditionalExpression(bool, bool*)
+            |
+            --- v8::preparser::PreParser::ParseConditionalExpression(bool, bool*)
+                0x3b2abe08368000
+
+0.07^2107366^HTMLParserThrea^chrome               ^[.] ppapi::thunk::subtle::EnterBase::EnterBase(int)
+            |
+            --- ppapi::thunk::subtle::EnterBase::EnterBase(int)
+
+0.07^2061079^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::EmitBackEdgeTable()
+            |
+            --- v8::internal::FullCodeGenerator::EmitBackEdgeTable()
+
+0.07^2055678^HTMLParserThrea^chrome               ^[.] WebCore::MarkupAccumulator::appendStartMarkup(WTF::StringBuilder&, WebCore::Node const*, WTF::HashMap<WTF::AtomicStringImpl*, WTF::AtomicStringImpl*, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*> >*)
+            |
+            --- WebCore::MarkupAccumulator::appendStartMarkup(WTF::StringBuilder&, WebCore::Node const*, WTF::HashMap<WTF::AtomicStringImpl*, WTF::AtomicStringImpl*, WTF::PtrHash<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*>, WTF::HashTraits<WTF::AtomicStringImpl*> >*)
+                (nil)
+
+0.07^2053845^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::flipForWritingMode(WebCore::LayoutRect&) const
+            |
+            --- WebCore::RenderBox::flipForWritingMode(WebCore::LayoutRect&) const
+
+0.07^2043240^HTMLParserThrea^chrome               ^[.] net::HttpUtil::HeadersIterator::GetNext()
+            |
+            --- net::HttpUtil::HeadersIterator::GetNext()
+                0x7f7a0689c4d8
+
+0.07^2038325^HTMLParserThrea^chrome               ^[.] WTF::HashTable<WTF::AtomicString, WTF::KeyValuePair<WTF::AtomicString, WTF::AtomicString>, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WTF::AtomicString, WTF::AtomicString> >, WTF::CaseFoldingHash, WTF::HashMapValueTraits<WTF::HashTraits<WTF::AtomicString>, WTF::HashTraits<WTF::AtomicString> >, WTF::HashTraits<WTF::AtomicString> >::rehash(int)
+            |
+            --- WTF::HashTable<WTF::AtomicString, WTF::KeyValuePair<WTF::AtomicString, WTF::AtomicString>, WTF::KeyValuePairKeyExtractor<WTF::KeyValuePair<WTF::AtomicString, WTF::AtomicString> >, WTF::CaseFoldingHash, WTF::HashMapValueTraits<WTF::HashTraits<WTF::AtomicString>, WTF::HashTraits<WTF::AtomicString> >, WTF::HashTraits<WTF::AtomicString> >::rehash(int)
+
+0.07^2038325^HTMLParserThrea^chrome               ^[.] WebCore::KURL::isValid() const
+            |
+            --- WebCore::KURL::isValid() const
+
+0.07^2030555^HTMLParserThrea^chrome               ^[.] v8::internal::Scope::LocalLookup(v8::internal::Handle<v8::internal::String>)
+            |
+            --- v8::internal::Scope::LocalLookup(v8::internal::Handle<v8::internal::String>)
+
+0.07^2017287^HTMLParserThrea^chrome               ^[.] WebKit::WebFrameImpl::document() const
+            |
+            --- WebKit::WebFrameImpl::document() const
+
+0.07^1991309^HTMLParserThrea^chrome               ^[.] v8::internal::Assembler::int3()
+            |
+            --- v8::internal::Assembler::int3()
+
+0.07^1989976^HTMLParserThrea^chrome               ^[.] __gnu_cxx::hashtable<std::pair<int const, std::pair<ppapi::Resource*, int> >, int, __gnu_cxx::hash<int>, std::_Select1st<std::pair<int const, std::pair<ppapi::Resource*, int> > >, std::equal_to<int>, std::allocator<std::pair<ppapi::Resource*, int> > >::find_or_insert(std::pair<int const, std::pair<ppapi::Resource*, int> > const&)
+            |
+            --- __gnu_cxx::hashtable<std::pair<int const, std::pair<ppapi::Resource*, int> >, int, __gnu_cxx::hash<int>, std::_Select1st<std::pair<int const, std::pair<ppapi::Resource*, int> > >, std::equal_to<int>, std::allocator<std::pair<ppapi::Resource*, int> > >::find_or_insert(std::pair<int const, std::pair<ppapi::Resource*, int> > const&)
+                (nil)
+
+0.07^1989976^HTMLParserThrea^chrome               ^[.] content::PaintAggregator::InvalidateRect(gfx::Rect const&)
+            |
+            --- content::PaintAggregator::InvalidateRect(gfx::Rect const&)
+
+0.07^1983969^HTMLParserThrea^chrome               ^[.] tracked_objects::ThreadData::TallyADeath(tracked_objects::Births const&, int, int)
+            |
+            --- tracked_objects::ThreadData::TallyADeath(tracked_objects::Births const&, int, int)
+
+0.07^1983969^HTMLParserThrea^chrome               ^[.] WebCore::HTMLDocumentParser::pumpTokenizer(WebCore::HTMLDocumentParser::SynchronousMode)
+            |
+            --- WebCore::HTMLDocumentParser::pumpTokenizer(WebCore::HTMLDocumentParser::SynchronousMode)
+
+0.07^1964943^HTMLParserThrea^chrome               ^[.] v8::internal::NormalizedMapCache::Get(v8::internal::JSObject*, v8::internal::PropertyNormalizationMode)
+            |
+            --- v8::internal::NormalizedMapCache::Get(v8::internal::JSObject*, v8::internal::PropertyNormalizationMode)
+
+0.07^1960139^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::visualOverflowRect() const
+            |
+            --- WebCore::RenderBox::visualOverflowRect() const
+
+0.06^1953892^HTMLParserThrea^chrome               ^[.] base::MessagePumpDefault::ScheduleWork()
+            |
+            --- base::MessagePumpDefault::ScheduleWork()
+
+0.06^1922033^HTMLParserThrea^chrome               ^[.] v8::preparser::PreParser::ParseIdentifier(bool*)
+            |
+            --- v8::preparser::PreParser::ParseIdentifier(bool*)
+                0x3b2abe08368000
+
+0.06^1902957^HTMLParserThrea^chrome               ^[.] base::MessageLoop::ScheduleWork(bool)
+            |
+            --- base::MessageLoop::ScheduleWork(bool)
+
+0.06^1857157^HTMLParserThrea^chrome               ^[.] v8::internal::FullCodeGenerator::DoTest(v8::internal::Expression*, v8::internal::Label*, v8::internal::Label*, v8::internal::Label*)
+            |
+            --- v8::internal::FullCodeGenerator::DoTest(v8::internal::Expression*, v8::internal::Label*, v8::internal::Label*, v8::internal::Label*)
+                0x7fff30e91bc0
+
+0.06^1758928^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::ancestorStackingContainer() const
+            |
+            --- WebCore::RenderLayer::ancestorStackingContainer() const
+
+0.06^1708834^HTMLParserThrea^libcairo.so.2.11000.2^[.] _cairo_matrix_is_identity
+            |
+            --- _cairo_matrix_is_identity
+
+0.06^1707254^HTMLParserThrea^chrome               ^[.] WebCore::RenderLineBoxList::anyLineIntersectsRect(WebCore::RenderBoxModelObject*, WebCore::LayoutRect const&, WebCore::LayoutPoint const&, WebCore::LayoutUnit) const
+            |
+            --- WebCore::RenderLineBoxList::anyLineIntersectsRect(WebCore::RenderBoxModelObject*, WebCore::LayoutRect const&, WebCore::LayoutPoint const&, WebCore::LayoutUnit) const
+
+0.06^1695178^HTMLParserThrea^chrome               ^[.] base::internal::CallbackBase::CallbackBase(base::internal::BindStateBase*)
+            |
+            --- base::internal::CallbackBase::CallbackBase(base::internal::BindStateBase*)
+
+0.06^1682330^HTMLParserThrea^chrome               ^[.] WebCore::RenderBox::clippedOverflowRectForRepaint(WebCore::RenderLayerModelObject const*) const
+            |
+            --- WebCore::RenderBox::clippedOverflowRectForRepaint(WebCore::RenderLayerModelObject const*) const
+
+0.06^1665533^HTMLParserThrea^chrome               ^[.] v8::internal::Zone::DeleteAll()
+            |
+            --- v8::internal::Zone::DeleteAll()
+
+0.05^1641632^HTMLParserThrea^chrome               ^[.] WebCore::Color::blend(WebCore::Color const&) const
+            |
+            --- WebCore::Color::blend(WebCore::Color const&) const
+
+0.05^1611521^HTMLParserThrea^chrome               ^[.] WebKit::currentTimeFunction()
+            |
+            --- WebKit::currentTimeFunction()
+
+0.05^1539536^HTMLParserThrea^chrome               ^[.] WebCore::RenderLayer::collectFragments(WTF::Vector<WebCore::LayerFragment, 1ul>&, WebCore::RenderLayer const*, WebCore::RenderRegion*, WebCore::LayoutRect const&, WebCore::ClipRectsType, WebCore::OverlayScrollbarSizeRelevancy, WebCore::ShouldRespectOverflowClip, WebCore::LayoutPoint const*, WebCore::LayoutRect const*)
+            |
+            --- WebCore::RenderLayer::collectFragments(WTF::Vector<WebCore::LayerFragment, 1ul>&, WebCore::RenderLayer const*, WebCore::RenderRegion*, WebCore::LayoutRect const&, WebCore::ClipRectsType, WebCore::OverlayScrollbarSizeRelevancy, WebCore::ShouldRespectOverflowClip, WebCore::LayoutPoint const*, WebCore::LayoutRect const*)
+
+0.05^1523423^HTMLParserThrea^chrome               ^[.] v8::internal::StubCache::ComputeLoadNormal(v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::JSObject>)
+            |
+            --- v8::internal::StubCache::ComputeLoadNormal(v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::JSObject>)
+                (nil)
+
+0.05^1521966^HTMLParserThrea^chrome               ^[.] void url_canon::(anonymous namespace)::DoHost<char, unsigned char>(char const*, url_parse::Component const&, url_canon::CanonOutputT<char>*, url_canon::CanonHostInfo*)
+            |
+            --- void url_canon::(anonymous namespace)::DoHost<char, unsigned char>(char const*, url_parse::Component const&, url_canon::CanonOutputT<char>*, url_canon::CanonHostInfo*)
+                0xffffffff00000000
+
+0.05^1443413^HTMLParserThrea^chrome               ^[.] WTF::HashTableAddResult<WTF::HashTableIterator<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*, WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*, WTF::IdentityExtractor, WTF::ListHashSetNodeHashFunctions<WTF::PtrHash<WebCore::CachedResource*> >, WTF::HashTraits<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*> > > WTF::HashTable<WTF::ListHashSetNode<WebCore::Cac
+            |
+            --- WTF::HashTableAddResult<WTF::HashTableIterator<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*, WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*, WTF::IdentityExtractor, WTF::ListHashSetNodeHashFunctions<WTF::PtrHash<WebCore::CachedResource*> >, WTF::HashTraits<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*> > > WTF::HashTable<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*, WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*, WTF::IdentityExtractor, WTF::ListHashSetNodeHashFunctions<WTF::PtrHash<WebCore::CachedResource*> >, WTF::HashTraits<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*>, WTF::HashTraits<WTF::ListHashSetNode<WebCore::CachedResource*, 256ul>*> >::add<WTF::ListHashSetTranslator<WTF::PtrHash<WebCore::CachedResource*> >, WebCore::CachedResource*, WTF::ListHashSetNodeAllocator<WebCore::CachedResource*, 256ul>*>(WebCore::CachedResource* const&, WTF::ListHashSetNodeAllocator<WebCore::CachedResource*, 256ul>* const&)
+                (nil)
+
+0.05^1380694^HTMLParserThrea^chrome               ^[.] v8::internal::HBasicBlock::Finish(v8::internal::HControlInstruction*)
+            |
+            --- v8::internal::HBasicBlock::Finish(v8::internal::HControlInstruction*)
+
+0.04^1244009^HTMLParserThrea^chrome               ^[.] WebCore::Node::isWebVTTElement() const
+            |
+            --- WebCore::Node::isWebVTTElement() const
+                0x7fff30e91700
+
+
+
+#
+# (For a higher level overview, try: perf report --sort comm,dso)
+#
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index 07de66b..243ad65 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -444,8 +444,9 @@
     # the two values "Release" and "Debug".
     # TODO(Hercules): unify how all our scripts pass around build mode
     # (--mode / --target / --build_dir / --debug)
-    if self._options.build_dir.endswith("Debug"):
-      script_cmd.append("--debug");
+    if self._options.build_dir:
+      build_root, mode = os.path.split(self._options.build_dir)
+      script_cmd.extend(["--build-directory", build_root, "--target", mode])
     if (chunk_size > 0):
       script_cmd.append("--run-chunk=%d:%d" % (chunk_num, chunk_size))
     if len(self._args):
diff --git a/tools/valgrind/chrome_tests.sh b/tools/valgrind/chrome_tests.sh
index d8cebd4..df5e8e7 100755
--- a/tools/valgrind/chrome_tests.sh
+++ b/tools/valgrind/chrome_tests.sh
@@ -50,7 +50,7 @@
 
 if [ "$NEEDS_VALGRIND" == "1" ]
 then
-  CHROME_VALGRIND=`sh $THISDIR/locate_valgrind.sh`
+  export CHROME_VALGRIND=`sh $THISDIR/locate_valgrind.sh`
   if [ "$CHROME_VALGRIND" = "" ]
   then
     # locate_valgrind.sh failed
diff --git a/tools/valgrind/gtest_exclude/ash_unittests.gtest.txt b/tools/valgrind/gtest_exclude/ash_unittests.gtest.txt
deleted file mode 100644
index b7a178d..0000000
--- a/tools/valgrind/gtest_exclude/ash_unittests.gtest.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# crbug.com/234854
-PanelLayoutManagerTest.PanelAlignmentSecondDisplay 
diff --git a/tools/valgrind/gtest_exclude/content_unittests.gtest_mac.txt b/tools/valgrind/gtest_exclude/content_unittests.gtest_mac.txt
index 562c242..6e10951 100644
--- a/tools/valgrind/gtest_exclude/content_unittests.gtest_mac.txt
+++ b/tools/valgrind/gtest_exclude/content_unittests.gtest_mac.txt
@@ -48,8 +48,5 @@
 FontSerializationTest.StyledFonts
 MacSandboxTest.FontLoadingTest
 
-# http://crbug.com/247685
-DesktopCaptureDeviceTest.Capture
-
 # http://crbug.com/270254
 DeviceOrientationEventPumpTest.*
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 2bd1806..929207d 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -208,6 +208,13 @@
    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
+   fun:_dlerror_run
+   fun:dlopen@@GLIBC_2.2.5
+}
+{
    glibc leak.  See also http://sources.redhat.com/bugzilla/show_bug.cgi?id=2451
    Memcheck:Leak
    fun:malloc
@@ -6261,12 +6268,6 @@
    fun:_ZN7WebCore12EventHandler10mouseMovedERKNS_18PlatformMouseEventE
 }
 {
-   bug_189194
-   Memcheck:Leak
-   ...
-   fun:*ProfileSigninConfirmationDialogTest_*
-}
-{
    bug_195160_a
    Memcheck:Leak
    fun:_Znw*
@@ -6586,16 +6587,6 @@
    fun:_ZN7WebCore10UseCounter17recordMeasurementENS0_7FeatureE
 }
 {
-   bug_241044
-   Memcheck:Uninitialized
-   fun:_ZN7WebCore8Settings29setOpenGLMultisamplingEnabledEb
-   fun:_ZN6WebKit15WebSettingsImpl29setOpenGLMultisamplingEnabledEb
-   fun:_ZN11webkit_glue19ApplyWebPreferencesERK14WebPreferencesPN6WebKit7WebViewE
-   fun:_ZN7content14RenderViewImpl10InitializeEPNS_20RenderViewImplParamsE
-   fun:_ZN7content14RenderViewImpl6CreateEiRKNS_19RendererPreferencesERK14WebPreferencesPN4base14RefCountedDataIiEEiilRKSbItNS7_20string16_char_traitsESaItEEbbiRKN6WebKit13WebScreenInfoE17AccessibilityModeb
-   fun:_ZN7content16RenderThreadImpl15OnCreateNewViewERK18ViewMsg_New_Params
-}
-{
    bug_241892a
    Memcheck:Leak
    fun:_Znw*
@@ -6641,6 +6632,17 @@
    fun:_ZN7WebCore14NodeV8InternalL37appendChildMethodCallbackForMainWorldERKN2v820FunctionCallbackInfoINS1_5ValueEEE
 }
 {
+   bug_241892d
+   Memcheck:Leak
+   fun:malloc
+   fun:_ZN3WTF10fastMallocEm
+   fun:_ZN3WTF10RefCountedIN7WebCore11CSSSelector8RareDataEEnwEm
+   fun:_ZN7WebCore11CSSSelector8RareData6createEN3WTF10PassRefPtrINS2_10StringImplEEE
+   fun:_ZN7WebCore11CSSSelector14createRareDataEv
+   ...
+   fun:_Z10cssyyparsePN7WebCore9CSSParserE
+}
+{
    bug_241932
    Memcheck:Leak
    fun:calloc
@@ -6777,10 +6779,10 @@
    Memcheck:Uninitialized
    fun:_ZN7WebCore8Settings29setOpenGLMultisamplingEnabledEb
    fun:_ZN6WebKit15WebSettingsImpl29setOpenGLMultisamplingEnabledEb
-   fun:_ZN11webkit_glue19ApplyWebPreferencesERK14WebPreferencesPN6WebKit7WebViewE
+   fun:_ZN7content19ApplyWebPreferencesERK14WebPreferencesPN6WebKit7WebViewE
    ...
    fun:_ZN7content14RenderViewImpl10InitializeEPNS_20RenderViewImplParamsE
-   fun:_ZN7content14RenderViewImpl6CreateEiRKNS_19RendererPreferencesERK14WebPreferencesPN4base14RefCountedDataIiEEiiilRKSbItNS7_20string16_char_traitsESaItEEbbiRKN6WebKit13WebScreenInfoE17AccessibilityModeb
+   fun:_ZN7content14RenderViewImpl6CreateE*
    fun:_ZN7content16RenderThreadImpl15OnCreateNewViewERK18ViewMsg_New_Params
 }
 {
@@ -7142,16 +7144,6 @@
    fun:_ZN4base45WeakPtrTest_MoveOwnershipAfterInvalidate_Test8TestBodyEv
 }
 {
-  bug_268368
-  Memcheck:Leak
-  fun:calloc
-  fun:_dlerror_run
-  ...
-  fun:_ZN4base17LoadNativeLibraryERKNS_8FilePathEPSs
-  fun:_ZN7content10PluginList17ReadWebPluginInfoERKN4base8FilePathEPNS_13WebPluginInfoE
-  fun:_ZN7content10PluginList14ReadPluginInfoERKN4base8FilePathEPNS_13WebPluginInfoE
-}
-{
    bug_269201
    Memcheck:Unaddressable
    ...
@@ -7173,24 +7165,6 @@
    fun:_ZN4base11MessageLoop8PostTaskERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEE
 }
 {
-   bug_269884a
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN24SkColorFilterImageFilter6CreateEP13SkColorFilterP13SkImageFilterPK7SkIRect
-   fun:_ZN7WebCore22SkiaImageFilterBuilder19transformColorSpaceEP13SkImageFilterNS_10ColorSpaceES3_
-   fun:_ZN7WebCore22SkiaImageFilterBuilder5buildERKNS_16FilterOperationsE
-}
-{
-   bug_269884b
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN19SkPerlinNoiseShader15CreateTubulenceEffifPK7SkTSizeIiE
-   fun:_ZN7WebCore12FETurbulence12createShaderERKNS_7IntRectE
-   fun:_ZN7WebCore12FETurbulence17createImageFilterEPNS_22SkiaImageFilterBuilderE
-   fun:_ZN7WebCore22SkiaImageFilterBuilder5buildEPNS_12FilterEffectENS_10ColorSpaceE
-   fun:_ZN7WebCore22SkiaImageFilterBuilder5buildERKNS_16FilterOperationsE
-}
-{
    bug_270312
    Memcheck:Leak
    fun:_Znw*
@@ -7199,13 +7173,66 @@
    fun:_ZN14message_center21MessageCenterViewTest5SetUpEv
 }
 {
-   bug_271431
+   bug_272179_a
+   Memcheck:Uninitialized
+   ...
+   fun:_ZN7WebCore14HarfBuzzShaper17shapeHarfBuzzRuns*
+}
+{
+   bug_272179_b
+   Memcheck:Uninitialized
+   ...
+   fun:_ZN7WebCore14HarfBuzzShaper19collectHarfBuzzRunsEv
+}
+{
+   bug_272179_c 
+   Memcheck:Param
+   sendmsg(msg.msg_iov[0])
+   obj:/lib/x86_64-linux-gnu/libpthread-2.15.so
+   ...
+   fun:_ZN7WebCore14HarfBuzzShaper19collectHarfBuzzRunsEv
+}
+{
+   bug_272596
+   Memcheck:Leak
+   ...
+   fun:nssPKIObjectCollection_AddInstanceAsObject
+   fun:nssToken_TraverseCertificates
+   fun:NSSTrustDomain_TraverseCertificates
+   fun:PK11_ListCerts
+   fun:_ZN3net15NSSCertDatabase9ListCertsEPSt6vectorI13scoped_refptrINS_15X509CertificateEESaIS4_EE
+   fun:_ZN8chromeos12_GLOBAL__N_119LoadNSSCertificatesEPSt6vectorI13scoped_refptrIN3net15X509CertificateEESaIS5_EE
+}
+{
+   bug_272083
    Memcheck:Leak
    fun:_Znw*
-   fun:_ZN8autofill33TestGeneratedCreditCardBubbleView6CreateERKN4base7WeakPtrINS_35GeneratedCreditCardBubbleControllerEEE
-   fun:_ZN8autofill12_GLOBAL__N_139TestGeneratedCreditCardBubbleController12CreateBubbleEv
-   fun:_ZN8autofill35GeneratedCreditCardBubbleController4ShowEb
-   fun:_ZN8autofill35GeneratedCreditCardBubbleController12SetupAndShowERKSbItN4base20string16_char_traitsESaItEES6_
-   fun:_ZN8autofill35GeneratedCreditCardBubbleController4ShowEPN7content11WebContentsERKSbItN4base20string16_char_traitsESaItEES9_
-   fun:_ZN8autofill12_GLOBAL__N_139GeneratedCreditCardBubbleControllerTest4ShowEv
+   fun:_ZN12ThemeService19SetManagedUserThemeEv
+   fun:_ZN12ThemeService24OnManagedUserInitializedEv
+}
+{
+   bug_273398
+   Memcheck:Leak
+   ...
+   fun:_ZN6Pickle6ResizeEm
+   fun:_ZN6PickleC1Ev
+   fun:_ZN7content14ZygoteHostImpl20GetTerminationStatusEibPi
+   fun:_ZN7content20ChildProcessLauncher25GetChildTerminationStatusEbPi
+   fun:_ZN7content27BrowserChildProcessHostImpl20GetTerminationStatusEPi
+   fun:_ZN7content27BrowserChildProcessHostImpl19OnChildDisconnectedEv
+}
+{
+   bug_274193
+   Memcheck:Leak
+   ...
+   fun:_mesa_glsl_compile_shader
+   fun:compile_shader
+   fun:_mesa_CompileShaderARB
+   fun:shared_dispatch_stub_529
+   fun:_ZN3gfx9GLApiBase17glCompileShaderFnEj
+   fun:_ZN3gpu5gles214ProgramManager15DoCompileShaderEPNS0_6ShaderEPNS0_16ShaderTranslatorEPNS0_11FeatureInfoE
+   fun:_ZN3gpu5gles216GLES2DecoderImpl15DoCompileShaderEj
+   fun:_ZN3gpu5gles216GLES2DecoderImpl19HandleCompileShaderEjRKNS0_4cmds13CompileShaderE
+   fun:_ZN3gpu5gles216GLES2DecoderImpl9DoCommandEjjPKv
+   fun:_ZN3gpu13CommandParser14ProcessCommandEv
 }
diff --git a/tools/valgrind/tsan/ignores_win32.txt b/tools/valgrind/tsan/ignores_win32.txt
index c6c12a5..f38b00f 100644
--- a/tools/valgrind/tsan/ignores_win32.txt
+++ b/tools/valgrind/tsan/ignores_win32.txt
@@ -59,3 +59,6 @@
 fun_r:_flsbuf
 fun_r:_unlock_file
 fun_r:_getstream
+
+# http://crbug.com/272065
+obj:*NLAapi.dll
diff --git a/tools/valgrind/tsan_v2/suppressions.txt b/tools/valgrind/tsan_v2/suppressions.txt
index 2514e17..274059e 100644
--- a/tools/valgrind/tsan_v2/suppressions.txt
+++ b/tools/valgrind/tsan_v2/suppressions.txt
@@ -14,6 +14,7 @@
 
 # http://crbug.com/46840
 race:history::HistoryBackend::DeleteFTSIndexDatabases
+race:history::InMemoryHistoryBackend::Init
 
 # http://crbug.com/84094
 race:sqlite3StatusSet
@@ -107,11 +108,14 @@
 # http://crbug.com/268946
 race:CommandLine::HasSwitch
 
-# http://crbug.com/269965
-race:DesktopMediaPickerModelTest_UpdateThumbnail_Test
-
 # http://crbug.com/270037
 race:gLibCleanupFunctions
 
 # http://crbug.com/270675
 race:net::RuleBasedHostResolverProc::Resolve
+
+# http://crbug.com/272095
+race:base::g_top_manager
+
+# http://crbug.com/273047
+race:base::*::g_lazy_tls_ptr
diff --git a/tools/valgrind/valgrind_test.py b/tools/valgrind/valgrind_test.py
index cafe7f9..1d8d78c 100644
--- a/tools/valgrind/valgrind_test.py
+++ b/tools/valgrind/valgrind_test.py
@@ -357,7 +357,11 @@
     if self.SelfContained():
       proc = ["valgrind-%s.sh" % tool_name]
     else:
-      proc = ["valgrind", "--tool=%s" % tool_name]
+      if 'CHROME_VALGRIND' in os.environ:
+        path = os.path.join(os.environ['CHROME_VALGRIND'], "bin", "valgrind")
+      else:
+        path = "valgrind"
+      proc = [path, "--tool=%s" % tool_name]
 
     proc += ["--num-callers=%i" % int(self._options.num_callers)]
 
diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp
index 35b4663..b0c6428 100644
--- a/ui/app_list/app_list.gyp
+++ b/ui/app_list/app_list.gyp
@@ -36,7 +36,6 @@
         'app_list_model.h',
         'app_list_model_observer.h',
         'app_list_view_delegate.h',
-        'apps_grid_view_delegate.h',
         'cocoa/app_list_pager_view.h',
         'cocoa/app_list_pager_view.mm',
         'cocoa/app_list_view_controller.h',
@@ -72,13 +71,10 @@
         'search_box_model.cc',
         'search_box_model.h',
         'search_box_model_observer.h',
-        'search_box_view_delegate.h',
         'search_result.cc',
         'search_result.h',
-        'search_result_list_view_delegate.h',
         'signin_delegate.cc',
         'signin_delegate.h',
-        'signin_delegate_observer.h',
         'views/app_list_background.cc',
         'views/app_list_background.h',
         'views/app_list_drag_and_drop_host.h',
@@ -92,6 +88,7 @@
         'views/app_list_view.h',
         'views/apps_grid_view.cc',
         'views/apps_grid_view.h',
+        'views/apps_grid_view_delegate.h',
         'views/cached_label.cc',
         'views/cached_label.h',
         'views/contents_view.cc',
@@ -104,10 +101,12 @@
         'views/pulsing_block_view.h',
         'views/search_box_view.cc',
         'views/search_box_view.h',
+        'views/search_box_view_delegate.h',
         'views/search_result_actions_view.cc',
         'views/search_result_actions_view.h',
         'views/search_result_list_view.cc',
         'views/search_result_list_view.h',
+        'views/search_result_list_view_delegate.h',
         'views/search_result_view.cc',
         'views/search_result_view.h',
         'views/search_result_view_delegate.h',
diff --git a/ui/app_list/app_list_model.cc b/ui/app_list/app_list_model.cc
index 4f473ef..a932069 100644
--- a/ui/app_list/app_list_model.cc
+++ b/ui/app_list/app_list_model.cc
@@ -15,6 +15,7 @@
     : apps_(new Apps),
       search_box_(new SearchBoxModel),
       results_(new SearchResults),
+      signed_in_(false),
       status_(STATUS_NORMAL) {
 }
 
@@ -39,4 +40,27 @@
                     OnAppListModelStatusChanged());
 }
 
+void AppListModel::SetCurrentUser(const base::string16& current_user_name,
+                                  const base::string16& current_user_email) {
+  if (current_user_name_ == current_user_name &&
+      current_user_email_ == current_user_email) {
+    return;
+  }
+  current_user_name_ = current_user_name;
+  current_user_email_ = current_user_email;
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListModelCurrentUserChanged());
+}
+
+void AppListModel::SetSignedIn(bool signed_in) {
+  if (signed_in_ == signed_in)
+    return;
+
+  signed_in_ = signed_in;
+  FOR_EACH_OBSERVER(AppListModelObserver,
+                    observers_,
+                    OnAppListModelSigninStatusChanged());
+}
+
 }  // namespace app_list
diff --git a/ui/app_list/app_list_model.h b/ui/app_list/app_list_model.h
index 4c46a01..196adc4 100644
--- a/ui/app_list/app_list_model.h
+++ b/ui/app_list/app_list_model.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
+#include "base/strings/string16.h"
 #include "ui/app_list/app_list_export.h"
 #include "ui/base/models/list_model.h"
 
@@ -39,11 +40,19 @@
   void RemoveObserver(AppListModelObserver* observer);
 
   void SetStatus(Status status);
+  void SetCurrentUser(const base::string16& current_user_name,
+                      const base::string16& current_user_email);
+  void SetSignedIn(bool signed_in);
 
   Apps* apps() { return apps_.get(); }
   SearchBoxModel* search_box() { return search_box_.get(); }
   SearchResults* results() { return results_.get(); }
   Status status() const { return status_; }
+  bool signed_in() const { return signed_in_; }
+  const base::string16& current_user_name() const { return current_user_name_; }
+  const base::string16& current_user_email() const {
+    return current_user_email_;
+  }
 
  private:
   scoped_ptr<Apps> apps_;
@@ -51,6 +60,10 @@
   scoped_ptr<SearchBoxModel> search_box_;
   scoped_ptr<SearchResults> results_;
 
+  base::string16 current_user_name_;
+  base::string16 current_user_email_;
+  bool signed_in_;
+
   Status status_;
   ObserverList<AppListModelObserver> observers_;
 
diff --git a/ui/app_list/app_list_model_observer.h b/ui/app_list/app_list_model_observer.h
index c843894..07716de 100644
--- a/ui/app_list/app_list_model_observer.h
+++ b/ui/app_list/app_list_model_observer.h
@@ -12,7 +12,13 @@
 class APP_LIST_EXPORT AppListModelObserver {
  public:
   // Invoked when AppListModel's status has changed.
-  virtual void OnAppListModelStatusChanged() = 0;
+  virtual void OnAppListModelStatusChanged() {}
+
+  // Invoked when AppListModel's current user details have changed.
+  virtual void OnAppListModelCurrentUserChanged() {}
+
+  // Invoked when AppListModel's current user's signin status has changed.
+  virtual void OnAppListModelSigninStatusChanged() {}
 
  protected:
   virtual ~AppListModelObserver() {}
diff --git a/ui/app_list/app_list_view_delegate.h b/ui/app_list/app_list_view_delegate.h
index bd7e3d3..e674d22 100644
--- a/ui/app_list/app_list_view_delegate.h
+++ b/ui/app_list/app_list_view_delegate.h
@@ -70,18 +70,9 @@
   // Invoked when the app list is closing.
   virtual void ViewClosing() = 0;
 
-  // Invoked when the app list's activated state changes.
-  virtual void ViewActivationChanged(bool active) = 0;
-
   // Returns the icon to be displayed in the window and taskbar.
   virtual gfx::ImageSkia GetWindowIcon() = 0;
 
-  // Returns the name of the current user.
-  virtual base::string16 GetCurrentUserName() = 0;
-
-  // Returns the email of the current user.
-  virtual base::string16 GetCurrentUserEmail() = 0;
-
   // Open the settings UI.
   virtual void OpenSettings() = 0;
 
diff --git a/ui/app_list/apps_grid_view_delegate.h b/ui/app_list/apps_grid_view_delegate.h
deleted file mode 100644
index 59dc8f6..0000000
--- a/ui/app_list/apps_grid_view_delegate.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 UI_APP_LIST_APPS_GRID_VIEW_DELEGATE_H_
-#define UI_APP_LIST_APPS_GRID_VIEW_DELEGATE_H_
-
-#include "base/callback_forward.h"
-#include "ui/app_list/app_list_export.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace app_list {
-
-class AppListItemModel;
-
-class APP_LIST_EXPORT AppsGridViewDelegate {
- public:
-  // Invoked when an item is activated on the grid view. |event_flags| contains
-  // the flags of the keyboard/mouse event that triggers the activation request.
-  virtual void ActivateApp(AppListItemModel* item, int event_flags) = 0;
-
-  // Gets the path to a shortcut for the app represented by |item|. |callback|
-  // may be run immediately.
-  virtual void GetShortcutPathForApp(
-      const std::string& app_id,
-      const base::Callback<void(const base::FilePath&)>& callback) = 0;
-
- protected:
-  virtual ~AppsGridViewDelegate() {}
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_APPS_GRID_VIEW_DELEGATE_H_
diff --git a/ui/app_list/cocoa/app_list_view_controller.h b/ui/app_list/cocoa/app_list_view_controller.h
index 2815e0a..b993a67 100644
--- a/ui/app_list/cocoa/app_list_view_controller.h
+++ b/ui/app_list/cocoa/app_list_view_controller.h
@@ -17,7 +17,7 @@
 namespace app_list {
 class AppListViewDelegate;
 class AppListModel;
-class SigninDelegateObserverBridge;
+class AppListModelObserverBridge;
 }
 
 @class AppListPagerView;
@@ -46,7 +46,8 @@
   base::scoped_nsobject<NSView> contentsView_;
 
   scoped_ptr<app_list::AppListViewDelegate> delegate_;
-  scoped_ptr<app_list::SigninDelegateObserverBridge> signin_observer_bridge_;
+  scoped_ptr<app_list::AppListModelObserverBridge>
+      app_list_model_observer_bridge_;
   BOOL showingSearchResults_;
 }
 
diff --git a/ui/app_list/cocoa/app_list_view_controller.mm b/ui/app_list/cocoa/app_list_view_controller.mm
index e464721..5b36f4e 100644
--- a/ui/app_list/cocoa/app_list_view_controller.mm
+++ b/ui/app_list/cocoa/app_list_view_controller.mm
@@ -6,12 +6,13 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
 #include "skia/ext/skia_utils_mac.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_model.h"
+#include "ui/app_list/app_list_model_observer.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/signin_delegate.h"
-#include "ui/app_list/signin_delegate_observer.h"
 #import "ui/app_list/cocoa/app_list_pager_view.h"
 #import "ui/app_list/cocoa/apps_grid_controller.h"
 #import "ui/app_list/cocoa/signin_view_controller.h"
@@ -75,34 +76,44 @@
 
 - (void)loadAndSetView;
 - (void)revealSearchResults:(BOOL)show;
-- (app_list::SigninDelegate*)signinDelegate;
 
 @end
 
 namespace app_list {
 
-class SigninDelegateObserverBridge : public SigninDelegateObserver {
+class AppListModelObserverBridge : public AppListModelObserver {
  public:
-  SigninDelegateObserverBridge(AppListViewController* parent)
-      : parent_(parent) {
-    [parent_ signinDelegate]->AddObserver(this);
-  }
-
-  virtual ~SigninDelegateObserverBridge() {
-    [parent_ signinDelegate]->RemoveObserver(this);
-  }
+  AppListModelObserverBridge(AppListViewController* parent);
+  virtual ~AppListModelObserverBridge();
 
  private:
-  // SigninDelegateObserver override:
-  virtual void OnSigninSuccess() OVERRIDE {
-    [parent_ onSigninStatusChanged];
-  }
+  // Overridden from app_list::AppListModelObserver:
+  virtual void OnAppListModelCurrentUserChanged() OVERRIDE;
+  virtual void OnAppListModelSigninStatusChanged() OVERRIDE;
 
   AppListViewController* parent_;  // Weak. Owns us.
 
-  DISALLOW_COPY_AND_ASSIGN(SigninDelegateObserverBridge);
+  DISALLOW_COPY_AND_ASSIGN(AppListModelObserverBridge);
 };
 
+AppListModelObserverBridge::AppListModelObserverBridge(
+    AppListViewController* parent)
+    : parent_(parent) {
+  [[parent_ appsGridController] model]->AddObserver(this);
+}
+
+AppListModelObserverBridge::~AppListModelObserverBridge() {
+  [[parent_ appsGridController] model]->RemoveObserver(this);
+}
+
+void AppListModelObserverBridge::OnAppListModelCurrentUserChanged() {
+  [parent_ onSigninStatusChanged];
+}
+
+void AppListModelObserverBridge::OnAppListModelSigninStatusChanged() {
+  [parent_ onSigninStatusChanged];
+}
+
 }  // namespace app_list
 
 @implementation AppListViewController
@@ -148,7 +159,7 @@
       withTestModel:(scoped_ptr<app_list::AppListModel>)newModel {
   if (delegate_) {
     // First clean up, in reverse order.
-    signin_observer_bridge_.reset();
+    app_list_model_observer_bridge_.reset();
     [appsSearchResultsController_ setDelegate:nil];
     [appsSearchBoxController_ setDelegate:nil];
   }
@@ -158,6 +169,8 @@
     [appsGridController_ setModel:newModel.Pass()];
   [appsSearchBoxController_ setDelegate:self];
   [appsSearchResultsController_ setDelegate:self];
+  app_list_model_observer_bridge_.reset(
+      new app_list::AppListModelObserverBridge(self));
   [self onSigninStatusChanged];
 }
 
@@ -309,6 +322,16 @@
   return [appsGridController_ model];
 }
 
+- (NSString*)currentUserName {
+  return base::SysUTF16ToNSString(
+      [appsGridController_ model]->current_user_name());
+}
+
+- (NSString*)currentUserEmail {
+  return base::SysUTF16ToNSString(
+      [appsGridController_ model]->current_user_email());
+}
+
 - (void)openResult:(app_list::SearchResult*)result {
   if (delegate_)
     delegate_->OpenSearchResult(result, 0 /* event flags */);
@@ -316,13 +339,21 @@
   [appsSearchBoxController_ clearSearch];
 }
 
+- (void)redoSearch {
+  [self modelTextDidChange];
+}
+
 - (void)onSigninStatusChanged {
   [appsSearchBoxController_ rebuildMenu];
-  app_list::SigninDelegate* signinDelegate = [self signinDelegate];
-  BOOL needsSignin = signinDelegate && signinDelegate->NeedSignin();
-  if (!needsSignin) {
+  app_list::SigninDelegate* signinDelegate =
+      delegate_ ? delegate_->GetSigninDelegate() : NULL;
+  BOOL show_signin_view =
+      signinDelegate && ![appsGridController_ model]->signed_in();
+  if (!!signinViewController_ == show_signin_view)
+    return;
+
+  if (!show_signin_view) {
     [[signinViewController_ view] removeFromSuperview];
-    signin_observer_bridge_.reset();
     signinViewController_.reset();
     [backgroundView_ setHidden:NO];
     return;
@@ -333,13 +364,7 @@
       [[SigninViewController alloc] initWithFrame:[backgroundView_ frame]
                                      cornerRadius:kBubbleCornerRadius
                                          delegate:signinDelegate]);
-  signin_observer_bridge_.reset(
-      new app_list::SigninDelegateObserverBridge(self));
   [[self view] addSubview:[signinViewController_ view]];
 }
 
-- (app_list::SigninDelegate*)signinDelegate {
-  return delegate_ ? delegate_->GetSigninDelegate() : NULL;
-}
-
 @end
diff --git a/ui/app_list/cocoa/app_list_view_controller_unittest.mm b/ui/app_list/cocoa/app_list_view_controller_unittest.mm
index 70769ab..2836ceb 100644
--- a/ui/app_list/cocoa/app_list_view_controller_unittest.mm
+++ b/ui/app_list/cocoa/app_list_view_controller_unittest.mm
@@ -67,22 +67,6 @@
   DISALLOW_COPY_AND_ASSIGN(AppListViewControllerTest);
 };
 
-// Helper class allowing NeedSignin() to return true during SetUp(), to test an
-// initial state where signin is required, and the regular view starts hidden.
-class AppListViewControllerSigninTest : public AppListViewControllerTest {
- public:
-  AppListViewControllerSigninTest() : needs_signin_(true) {}
-
-  // SigninDelegate override:
-  virtual bool NeedSignin() OVERRIDE { return needs_signin_; }
-
- protected:
-  bool needs_signin_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AppListViewControllerSigninTest);
-};
-
 TEST_VIEW(AppListViewControllerTest, [app_list_view_controller_ view]);
 
 // Test that adding and removing pages updates the pager.
@@ -136,13 +120,16 @@
 }
 
 // Test the view when signin is required.
-TEST_F(AppListViewControllerSigninTest, NeedsSignin) {
+TEST_F(AppListViewControllerTest, NeedsSignin) {
+  // Begin the test with a signed out app list.
+  scoped_ptr<AppListModel> new_model(new AppListModel);
+  new_model->SetSignedIn(false);
+  ResetModel(new_model.Pass());
   EXPECT_EQ(2u, [[[app_list_view_controller_ view] subviews] count]);
   EXPECT_TRUE([[app_list_view_controller_ backgroundView] isHidden]);
 
   // Simulate signing in, should enter the SignedIn state.
-  needs_signin_ = false;
-  NotifySigninSuccess();
+  model()->SetSignedIn(true);
   EXPECT_EQ(1u, [[[app_list_view_controller_ view] subviews] count]);
   EXPECT_FALSE([[app_list_view_controller_ backgroundView] isHidden]);
 }
diff --git a/ui/app_list/cocoa/apps_grid_controller.mm b/ui/app_list/cocoa/apps_grid_controller.mm
index d32a791..a963182 100644
--- a/ui/app_list/cocoa/apps_grid_controller.mm
+++ b/ui/app_list/cocoa/apps_grid_controller.mm
@@ -546,9 +546,6 @@
   }
 
   [self updatePages:start];
-
-  for (size_t i = start; i < start + count; ++i)
-    [[self itemAtIndex:i] onInitialModelBuilt];
 }
 
 - (void)listItemsRemoved:(size_t)start
diff --git a/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
index 1e331bc..dba0065 100644
--- a/ui/app_list/cocoa/apps_grid_controller_unittest.mm
+++ b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
@@ -908,50 +908,5 @@
   EXPECT_NSEQ(@"Menu For: Item Two", [[menu itemAtIndex:0] title]);
 }
 
-TEST_F(AppsGridControllerTest, HighlightedOnFirstShow) {
-  scoped_ptr<AppListTestModel> test_model(new AppListTestModel);
-  test_model->PopulateApps(kItemsPerPage * 3);
-
-  // Manipulate the second item on the second page.
-  const size_t kTestItemIndex = kItemsPerPage + 1;
-
-  // When shown for the first time during an in-progress install, item should be
-  // visible, but not selected.
-  AppListItemModel* test_item = test_model->apps()->GetItemAt(kTestItemIndex);
-  test_item->SetHighlighted(true);
-  test_item->SetIsInstalling(true);
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  ResetModel(test_model.PassAs<AppListModel>());
-  EXPECT_EQ(3u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(NSNotFound, [apps_grid_controller_ selectedItemIndex]);
-
-  // Updating download progress should add a progress bar lazily.
-  NSView* containerView = [GetItemViewAt(kTestItemIndex) superview];
-  EXPECT_EQ(1u, [[containerView subviews] count]);
-  test_item->SetPercentDownloaded(50);
-  EXPECT_EQ(2u, [[containerView subviews] count]);
-
-  // Completing install should remove the progress bar, and select the item.
-  test_item->SetIsInstalling(false);
-  EXPECT_EQ(1u, [[containerView subviews] count]);
-  EXPECT_EQ(kTestItemIndex, [apps_grid_controller_ selectedItemIndex]);
-
-  // Reset to unconstructed state.
-  ResetModel(scoped_ptr<AppListModel>());
-  EXPECT_EQ(0u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(1u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(NSNotFound, [apps_grid_controller_ selectedItemIndex]);
-
-  // If shown after install completes, item should also be selected.
-  test_model.reset(new AppListTestModel);
-  test_model->PopulateApps(kItemsPerPage * 3);
-  test_model->apps()->GetItemAt(kTestItemIndex)->SetHighlighted(true);
-  ResetModel(test_model.PassAs<AppListModel>());
-  EXPECT_EQ(3u, [apps_grid_controller_ pageCount]);
-  EXPECT_EQ(1u, [apps_grid_controller_ visiblePage]);
-  EXPECT_EQ(kTestItemIndex, [apps_grid_controller_ selectedItemIndex]);
-}
-
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/cocoa/apps_grid_view_item.h b/ui/app_list/cocoa/apps_grid_view_item.h
index d968e0c..b42eec1 100644
--- a/ui/app_list/cocoa/apps_grid_view_item.h
+++ b/ui/app_list/cocoa/apps_grid_view_item.h
@@ -50,10 +50,6 @@
 // the initial snapshot are restored.
 - (NSBitmapImageRep*)dragRepresentationForRestore:(BOOL)isRestore;
 
-// Called the first time an item is added to the grid view, once the grid view
-// is consistent with items being added at the same time.
-- (void)onInitialModelBuilt;
-
 @end
 
 #endif  // UI_APP_LIST_COCOA_APPS_GRID_VIEW_ITEM_H_
diff --git a/ui/app_list/cocoa/apps_grid_view_item.mm b/ui/app_list/cocoa/apps_grid_view_item.mm
index 34fe975..9d83d15 100644
--- a/ui/app_list/cocoa/apps_grid_view_item.mm
+++ b/ui/app_list/cocoa/apps_grid_view_item.mm
@@ -271,6 +271,7 @@
 }
 
 - (void)setModel:(app_list::AppListItemModel*)itemModel {
+  [trackingArea_.get() clearOwner];
   if (!itemModel) {
     observerBridge_.reset();
     return;
@@ -335,14 +336,6 @@
   return imageRep;
 }
 
-- (void)onInitialModelBuilt {
-  if ([self model]->highlighted()) {
-    [self ensureVisible];
-    if (![self model]->is_installing())
-      [self setSelected:YES];
-  }
-}
-
 - (void)ensureVisible {
   NSCollectionView* collectionView = [self collectionView];
   AppsGridController* gridController =
diff --git a/ui/app_list/cocoa/apps_search_box_controller.h b/ui/app_list/cocoa/apps_search_box_controller.h
index d28c67a..bb60cab 100644
--- a/ui/app_list/cocoa/apps_search_box_controller.h
+++ b/ui/app_list/cocoa/apps_search_box_controller.h
@@ -27,6 +27,8 @@
 - (app_list::AppListViewDelegate*)appListDelegate;
 - (app_list::SearchBoxModel*)searchBoxModel;
 - (void)modelTextDidChange;
+- (NSString*)currentUserName;
+- (NSString*)currentUserEmail;
 
 @end
 
diff --git a/ui/app_list/cocoa/apps_search_box_controller.mm b/ui/app_list/cocoa/apps_search_box_controller.mm
index 4f02a20..2d2826f 100644
--- a/ui/app_list/cocoa/apps_search_box_controller.mm
+++ b/ui/app_list/cocoa/apps_search_box_controller.mm
@@ -381,7 +381,8 @@
     return;
 
   base::scoped_nsobject<NSView> customItemView([[CurrentUserMenuItemView alloc]
-      initWithDelegate:[[searchBoxController_ delegate] appListDelegate]]);
+      initWithCurrentUser:[[searchBoxController_ delegate] currentUserName]
+                userEmail:[[searchBoxController_ delegate] currentUserEmail]]);
   [[menu itemAtIndex:index] setView:customItemView];
 }
 
diff --git a/ui/app_list/cocoa/apps_search_box_controller_unittest.mm b/ui/app_list/cocoa/apps_search_box_controller_unittest.mm
index d702549..eb38982 100644
--- a/ui/app_list/cocoa/apps_search_box_controller_unittest.mm
+++ b/ui/app_list/cocoa/apps_search_box_controller_unittest.mm
@@ -52,6 +52,14 @@
   return 3;
 }
 
+- (NSString*)currentUserName {
+  return @"";
+}
+
+- (NSString*)currentUserEmail {
+  return @"";
+}
+
 @end
 
 namespace app_list {
@@ -168,9 +176,9 @@
   }
 
   virtual void SetUp() OVERRIDE {
-    scoped_ptr<AppListViewDelegate> delegate(new AppListTestViewDelegate);
     current_user_menu_item_.reset([[[CurrentUserMenuItemView alloc]
-        initWithDelegate:delegate.get()] retain]);
+        initWithCurrentUser:@"testUser"
+                  userEmail:@"testUser@chromium.org"] retain]);
     ui::CocoaTest::SetUp();
     [[test_window() contentView] addSubview:current_user_menu_item_];
   }
diff --git a/ui/app_list/cocoa/apps_search_results_controller.h b/ui/app_list/cocoa/apps_search_results_controller.h
index b69fc51..52290c7 100644
--- a/ui/app_list/cocoa/apps_search_results_controller.h
+++ b/ui/app_list/cocoa/apps_search_results_controller.h
@@ -10,20 +10,21 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "ui/app_list/app_list_export.h"
+#include "ui/app_list/app_list_model.h"
 #import "ui/base/cocoa/tracking_area.h"
 
 namespace app_list {
-class AppListModel;
 class AppsSearchResultsModelBridge;
 class SearchResult;
 }
 
 @class AppsSearchResultsCell;
 
-@protocol AppsSearchResultsDelegate
+@protocol AppsSearchResultsDelegate<NSObject>
 
 - (app_list::AppListModel*)appListModel;
 - (void)openResult:(app_list::SearchResult*)result;
+- (void)redoSearch;
 
 @end
 
@@ -40,10 +41,12 @@
   NSPoint lastMouseDownInView_;
   NSInteger hoveredRowIndex_;
   scoped_ptr<app_list::AppsSearchResultsModelBridge> bridge_;
-  id<AppsSearchResultsDelegate> delegate_;  // Weak. Owns us.
+  NSObject<AppsSearchResultsDelegate>* delegate_;  // Weak. Owns us.
 }
 
-@property(assign, nonatomic) id<AppsSearchResultsDelegate> delegate;
+@property(assign, nonatomic) NSObject<AppsSearchResultsDelegate>* delegate;
+@property(readonly, nonatomic) app_list::AppListModel::SearchResults* results;
+@property(readonly, nonatomic) NSTableView* tableView;
 
 - (id)initWithAppsSearchResultsFrameSize:(NSSize)size;
 
@@ -53,10 +56,4 @@
 
 @end
 
-@interface AppsSearchResultsController (TestingAPI)
-
-- (NSTableView*)tableView;
-
-@end
-
 #endif  // UI_APP_LIST_COCOA_APPS_SEARCH_RESULTS_CONTROLLER_H_
diff --git a/ui/app_list/cocoa/apps_search_results_controller.mm b/ui/app_list/cocoa/apps_search_results_controller.mm
index b22d836..314f079 100644
--- a/ui/app_list/cocoa/apps_search_results_controller.mm
+++ b/ui/app_list/cocoa/apps_search_results_controller.mm
@@ -86,6 +86,15 @@
   return self;
 }
 
+- (app_list::AppListModel::SearchResults*)results {
+  DCHECK([delegate_ appListModel]);
+  return [delegate_ appListModel]->results();
+}
+
+- (NSTableView*)tableView {
+  return tableView_;
+}
+
 - (void)setDelegate:(id<AppsSearchResultsDelegate>)newDelegate {
   bridge_.reset();
   delegate_ = newDelegate;
@@ -95,8 +104,7 @@
     return;
   }
 
-  bridge_.reset(new app_list::AppsSearchResultsModelBridge(
-      appListModel->results(), tableView_));
+  bridge_.reset(new app_list::AppsSearchResultsModelBridge(self));
   [tableView_ reloadData];
 }
 
@@ -116,10 +124,6 @@
   return NO;
 }
 
-- (NSTableView*)tableView {
-  return tableView_;
-}
-
 - (void)loadAndSetViewWithResultsFrameSize:(NSSize)size {
   tableView_.reset(
       [[AppsSearchResultsTableView alloc] initWithFrame:NSZeroRect]);
diff --git a/ui/app_list/cocoa/apps_search_results_controller_unittest.mm b/ui/app_list/cocoa/apps_search_results_controller_unittest.mm
index 14ce5d2..218ad44 100644
--- a/ui/app_list/cocoa/apps_search_results_controller_unittest.mm
+++ b/ui/app_list/cocoa/apps_search_results_controller_unittest.mm
@@ -5,6 +5,7 @@
 #import "ui/app_list/cocoa/apps_search_results_controller.h"
 
 #include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -20,15 +21,18 @@
  @private
   app_list::test::AppListTestModel appListModel_;
   app_list::SearchResult* lastOpenedResult_;
+  int redoSearchCount_;
 }
 
 @property(readonly, nonatomic) app_list::SearchResult* lastOpenedResult;
+@property(readonly, nonatomic) int redoSearchCount;
 
 @end
 
 @implementation TestAppsSearchResultsDelegate
 
 @synthesize lastOpenedResult = lastOpenedResult_;
+@synthesize redoSearchCount = redoSearchCount_;
 
 - (app_list::AppListModel*)appListModel {
   return &appListModel_;
@@ -38,6 +42,10 @@
   lastOpenedResult_ = result;
 }
 
+- (void)redoSearch {
+  ++redoSearchCount_;
+}
+
 @end
 
 namespace app_list {
@@ -265,5 +273,15 @@
   EXPECT_NSEQ(@"Menu For: Result 1", [[menu itemAtIndex:0] title]);
 }
 
+// Test that observing a search result item uninstall performs the search again.
+TEST_F(AppsSearchResultsControllerTest, UninstallRedperformsSearch) {
+  base::MessageLoopForUI message_loop;
+  EXPECT_EQ(0, [delegate_ redoSearchCount]);
+  ModelResultAt(0)->NotifyItemUninstalled();
+  message_loop.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+  message_loop.Run();
+  EXPECT_EQ(1, [delegate_ redoSearchCount]);
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/cocoa/apps_search_results_model_bridge.h b/ui/app_list/cocoa/apps_search_results_model_bridge.h
index e1d70ac..8939d26 100644
--- a/ui/app_list/cocoa/apps_search_results_model_bridge.h
+++ b/ui/app_list/cocoa/apps_search_results_model_bridge.h
@@ -7,11 +7,10 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_vector.h"
-#include "ui/app_list/app_list_model.h"
 #include "ui/base/models/list_model_observer.h"
 
 @class NSMenu;
-@class NSTableView;
+@class AppsSearchResultsController;
 
 namespace app_list {
 
@@ -19,8 +18,8 @@
 // and updating the NSTableView where they are displayed.
 class AppsSearchResultsModelBridge : public ui::ListModelObserver {
  public:
-  AppsSearchResultsModelBridge(AppListModel::SearchResults* results_model,
-                               NSTableView* results_table_view);
+  explicit AppsSearchResultsModelBridge(
+      AppsSearchResultsController* results_controller);
   virtual ~AppsSearchResultsModelBridge();
 
   // Returns the context menu for the item at |index| in the search results
@@ -40,8 +39,7 @@
   virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE;
   virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE;
 
-  AppListModel::SearchResults* results_;   // Weak. Owned by AppListModel.
-  base::scoped_nsobject<NSTableView> table_view_;
+  AppsSearchResultsController* parent_;  // Weak. Owns us.
   ScopedVector<ItemObserver> item_observers_;
 
   DISALLOW_COPY_AND_ASSIGN(AppsSearchResultsModelBridge);
diff --git a/ui/app_list/cocoa/apps_search_results_model_bridge.mm b/ui/app_list/cocoa/apps_search_results_model_bridge.mm
index d56c5fd..66d6f07 100644
--- a/ui/app_list/cocoa/apps_search_results_model_bridge.mm
+++ b/ui/app_list/cocoa/apps_search_results_model_bridge.mm
@@ -7,6 +7,8 @@
 #import <Cocoa/Cocoa.h>
 
 #include "base/strings/sys_string_conversions.h"
+#include "ui/app_list/app_list_model.h"
+#import "ui/app_list/cocoa/apps_search_results_controller.h"
 #include "ui/app_list/search_result.h"
 #include "ui/app_list/search_result_observer.h"
 #import "ui/base/cocoa/menu_controller.h"
@@ -19,7 +21,7 @@
       : bridge_(bridge), row_in_view_(index) {
     // Cache the result, because the results array is updated before notifying
     // observers (which happens before deleting the SearchResult).
-    result_ = bridge_->results_->GetItemAt(index);
+    result_ = [bridge_->parent_ results]->GetItemAt(index);
     result_->AddObserver(this);
   }
 
@@ -44,7 +46,7 @@
   virtual void OnIsInstallingChanged() OVERRIDE {}
   virtual void OnPercentDownloadedChanged() OVERRIDE {}
   virtual void OnItemInstalled() OVERRIDE {}
-  virtual void OnItemUninstalled() OVERRIDE {}
+  virtual void OnItemUninstalled() OVERRIDE;
 
  private:
   AppsSearchResultsModelBridge* bridge_;  // Weak. Owns us.
@@ -55,17 +57,24 @@
   DISALLOW_COPY_AND_ASSIGN(ItemObserver);
 };
 
+void AppsSearchResultsModelBridge::ItemObserver::OnItemUninstalled() {
+  // Performing the search again will destroy |this|, so post a task. This also
+  // ensures that the AppSearchProvider has observed the uninstall before
+  // performing the search again, otherwise it will provide a NULL result.
+  [[bridge_->parent_ delegate] performSelector:@selector(redoSearch)
+                                    withObject:nil
+                                    afterDelay:0];
+}
+
 AppsSearchResultsModelBridge::AppsSearchResultsModelBridge(
-    AppListModel::SearchResults* results_model,
-    NSTableView* results_table_view)
-    : results_(results_model),
-      table_view_([results_table_view retain]) {
+    AppsSearchResultsController* results_controller)
+    : parent_(results_controller) {
   UpdateItemObservers();
-  results_->AddObserver(this);
+  [parent_ results]->AddObserver(this);
 }
 
 AppsSearchResultsModelBridge::~AppsSearchResultsModelBridge() {
-  results_->RemoveObserver(this);
+  [parent_ results]->RemoveObserver(this);
 }
 
 NSMenu* AppsSearchResultsModelBridge::MenuForItem(size_t index) {
@@ -75,7 +84,7 @@
 
 void AppsSearchResultsModelBridge::UpdateItemObservers() {
   DCHECK(item_observers_.empty());
-  const size_t itemCount = results_->item_count();
+  const size_t itemCount = [parent_ results]->item_count();
   for (size_t i = 0 ; i < itemCount; ++i)
     item_observers_.push_back(new ItemObserver(this, i));
 }
@@ -85,27 +94,27 @@
   NSIndexSet* column = [NSIndexSet indexSetWithIndex:0];
   NSIndexSet* rows =
       [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(start, count)];
-  [table_view_ reloadDataForRowIndexes:rows
-                         columnIndexes:column];
+  [[parent_ tableView] reloadDataForRowIndexes:rows
+                                 columnIndexes:column];
 }
 
 void AppsSearchResultsModelBridge::ListItemsAdded(
     size_t start, size_t count) {
   item_observers_.clear();
-  if (start == static_cast<size_t>([table_view_ numberOfRows]))
-    [table_view_ noteNumberOfRowsChanged];
+  if (start == static_cast<size_t>([[parent_ tableView] numberOfRows]))
+    [[parent_ tableView] noteNumberOfRowsChanged];
   else
-    [table_view_ reloadData];
+    [[parent_ tableView] reloadData];
   UpdateItemObservers();
 }
 
 void AppsSearchResultsModelBridge::ListItemsRemoved(
     size_t start, size_t count) {
   item_observers_.clear();
-  if (start == results_->item_count())
-    [table_view_ noteNumberOfRowsChanged];
+  if (start == [parent_ results]->item_count())
+    [[parent_ tableView] noteNumberOfRowsChanged];
   else
-    [table_view_ reloadData];
+    [[parent_ tableView] reloadData];
   UpdateItemObservers();
 }
 
diff --git a/ui/app_list/cocoa/current_user_menu_item_view.h b/ui/app_list/cocoa/current_user_menu_item_view.h
index 84c240a..6ba3b6d 100644
--- a/ui/app_list/cocoa/current_user_menu_item_view.h
+++ b/ui/app_list/cocoa/current_user_menu_item_view.h
@@ -9,15 +9,12 @@
 
 #include "ui/app_list/app_list_export.h"
 
-namespace app_list {
-class AppListViewDelegate;
-}
-
 // The custom in-menu view representing the currently signed-in user.
 APP_LIST_EXPORT
 @interface CurrentUserMenuItemView : NSView
 
-- (id)initWithDelegate:(app_list::AppListViewDelegate*)delegate;
+- (id)initWithCurrentUser:(NSString*)userName
+                userEmail:(NSString*)userEmail;
 
 @end
 
diff --git a/ui/app_list/cocoa/current_user_menu_item_view.mm b/ui/app_list/cocoa/current_user_menu_item_view.mm
index 6aac34c..c82d6fe 100644
--- a/ui/app_list/cocoa/current_user_menu_item_view.mm
+++ b/ui/app_list/cocoa/current_user_menu_item_view.mm
@@ -4,11 +4,8 @@
 
 #import "ui/app_list/cocoa/current_user_menu_item_view.h"
 
-#include "base/logging.h"
 #include "base/mac/scoped_nsobject.h"
-#include "base/strings/sys_string_conversions.h"
 #include "grit/ui_resources.h"
-#include "ui/app_list/app_list_view_delegate.h"
 #include "ui/base/resource/resource_bundle.h"
 
 namespace {
@@ -16,39 +13,42 @@
 // Padding on the left of the indicator icon.
 const CGFloat kMenuLeftMargin = 3;
 
+// Padding on the top and bottom of the menu item.
+const CGFloat kMenuTopBottomPadding = 2;
+
 }
 
 @interface CurrentUserMenuItemView ()
 
 // Adds a text label in the custom view in the menu showing the current user.
 - (NSTextField*)addLabelWithFrame:(NSPoint)origin
-                        labelText:(const string16&)labelText;
+                        labelText:(NSString*)labelText;
 
 @end
 
 @implementation CurrentUserMenuItemView
 
-- (id)initWithDelegate:(app_list::AppListViewDelegate*)delegate {
-  DCHECK(delegate);
+- (id)initWithCurrentUser:(NSString*)userName
+                userEmail:(NSString*)userEmail {
   if ((self = [super initWithFrame:NSZeroRect])) {
     NSImage* userImage = ui::ResourceBundle::GetSharedInstance().
         GetNativeImageNamed(IDR_APP_LIST_USER_INDICATOR).AsNSImage();
-    NSRect imageRect = NSMakeRect(kMenuLeftMargin, 0, 0, 0);
+    NSRect imageRect = NSMakeRect(kMenuLeftMargin, kMenuTopBottomPadding, 0, 0);
     imageRect.size = [userImage size];
     base::scoped_nsobject<NSImageView> userImageView(
         [[NSImageView alloc] initWithFrame:imageRect]);
     [userImageView setImage:userImage];
     [self addSubview:userImageView];
 
-    NSPoint labelOrigin = NSMakePoint(NSMaxX(imageRect), 0);
+    NSPoint labelOrigin = NSMakePoint(NSMaxX(imageRect), kMenuTopBottomPadding);
     NSTextField* userField =
         [self addLabelWithFrame:labelOrigin
-                      labelText:delegate->GetCurrentUserName()];
+                      labelText:userName];
 
     labelOrigin.y = NSMaxY([userField frame]);
     NSTextField* emailField =
         [self addLabelWithFrame:labelOrigin
-                      labelText:delegate->GetCurrentUserEmail()];
+                      labelText:userEmail];
     [emailField setTextColor:[NSColor disabledControlTextColor]];
 
     // Size the container view to fit the longest label.
@@ -57,18 +57,18 @@
       labelFrame.size.width = NSWidth([userField frame]);
     [self setFrameSize:NSMakeSize(
         NSMaxX(labelFrame) + NSMaxX(imageRect),
-        NSMaxY(labelFrame))];
+        NSMaxY(labelFrame) + kMenuTopBottomPadding)];
   }
   return self;
 }
 
 - (NSTextField*)addLabelWithFrame:(NSPoint)origin
-                        labelText:(const string16&)labelText {
+                        labelText:(NSString*)labelText {
   NSRect labelFrame = NSZeroRect;
   labelFrame.origin = origin;
   base::scoped_nsobject<NSTextField> label(
       [[NSTextField alloc] initWithFrame:labelFrame]);
-  [label setStringValue:base::SysUTF16ToNSString(labelText)];
+  [label setStringValue:labelText];
   [label setEditable:NO];
   [label setBordered:NO];
   [label setDrawsBackground:NO];
diff --git a/ui/app_list/search_box_view_delegate.h b/ui/app_list/search_box_view_delegate.h
deleted file mode 100644
index df5d2b4..0000000
--- a/ui/app_list/search_box_view_delegate.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 UI_APP_LIST_SEARCH_BOX_VIEW_DELEGATE_H_
-#define UI_APP_LIST_SEARCH_BOX_VIEW_DELEGATE_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class SearchBoxView;
-
-class APP_LIST_EXPORT SearchBoxViewDelegate {
- public:
-  // Invoked when query text has changed by the user.
-  virtual void QueryChanged(SearchBoxView* sender) = 0;
-
- protected:
-  virtual ~SearchBoxViewDelegate() {}
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_SEARCH_BOX_VIEW_DELEGATE_H_
diff --git a/ui/app_list/search_result_list_view_delegate.h b/ui/app_list/search_result_list_view_delegate.h
deleted file mode 100644
index e45ac4b..0000000
--- a/ui/app_list/search_result_list_view_delegate.h
+++ /dev/null
@@ -1,40 +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_APP_LIST_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
-#define UI_APP_LIST_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-class SearchResult;
-
-class APP_LIST_EXPORT SearchResultListViewDelegate {
- public:
-  // Invoked to open given |result|. |event_flags| contains the flags of the
-  // keyboard/mouse event that triggers the "open" request. Delegate could use
-  // the |event_flags| information to choose different ways to open the result.
-  virtual void OpenResult(SearchResult* result,
-                          int event_flags) = 0;
-
-  // Called to invoke a custom action on |result|.  |action_index| corresponds
-  // to the index of the icon in |result.action_icons()| that was activated.
-  virtual void InvokeResultAction(SearchResult* result,
-                                  int action_index,
-                                  int event_flags) = 0;
-
-  // Called when the app represented by |result| is installed.
-  virtual void OnResultInstalled(SearchResult* result) = 0;
-
-  // Called when the app represented by |result| is uninstalled.
-  virtual void OnResultUninstalled(SearchResult* result) = 0;
-
- protected:
-  virtual ~SearchResultListViewDelegate() {}
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
diff --git a/ui/app_list/signin_delegate.cc b/ui/app_list/signin_delegate.cc
index 51eb830..b0dd7e6 100644
--- a/ui/app_list/signin_delegate.cc
+++ b/ui/app_list/signin_delegate.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "ui/app_list/signin_delegate.h"
-#include "ui/app_list/signin_delegate_observer.h"
 
 namespace app_list {
 
@@ -11,17 +10,4 @@
 
 SigninDelegate::~SigninDelegate() {}
 
-void SigninDelegate::AddObserver(SigninDelegateObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void SigninDelegate::RemoveObserver(SigninDelegateObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void SigninDelegate::NotifySigninSuccess() {
-  FOR_EACH_OBSERVER(app_list::SigninDelegateObserver, observers_,
-                    OnSigninSuccess());
-}
-
 }  // namespace app_list
diff --git a/ui/app_list/signin_delegate.h b/ui/app_list/signin_delegate.h
index eda67f4..54f5917 100644
--- a/ui/app_list/signin_delegate.h
+++ b/ui/app_list/signin_delegate.h
@@ -6,14 +6,11 @@
 #define UI_APP_LIST_SIGNIN_DELEGATE_H_
 
 #include "base/basictypes.h"
-#include "base/observer_list.h"
 #include "base/strings/string16.h"
 #include "ui/app_list/app_list_export.h"
 
 namespace app_list {
 
-class SigninDelegateObserver;
-
 class APP_LIST_EXPORT SigninDelegate {
  public:
   SigninDelegate();
@@ -30,15 +27,7 @@
   virtual base::string16 GetLearnMoreLinkText() = 0;
   virtual base::string16 GetSettingsLinkText() = 0;
 
-  void AddObserver(SigninDelegateObserver* observer);
-  void RemoveObserver(SigninDelegateObserver* observer);
-
- protected:
-  void NotifySigninSuccess();
-
  private:
-  ObserverList<SigninDelegateObserver, true> observers_;
-
   DISALLOW_COPY_AND_ASSIGN(SigninDelegate);
 };
 
diff --git a/ui/app_list/signin_delegate_observer.h b/ui/app_list/signin_delegate_observer.h
deleted file mode 100644
index 47c49926..0000000
--- a/ui/app_list/signin_delegate_observer.h
+++ /dev/null
@@ -1,24 +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_APP_LIST_SIGNIN_DELEGATE_OBSERVER_H_
-#define UI_APP_LIST_SIGNIN_DELEGATE_OBSERVER_H_
-
-#include "ui/app_list/app_list_export.h"
-
-namespace app_list {
-
-// Abstract interface to allow handling app list signin success.
-class APP_LIST_EXPORT SigninDelegateObserver {
- public:
-  // Called by the SigninDelegate when signin has successfully completed.
-  virtual void OnSigninSuccess() = 0;
-
- protected:
-  virtual ~SigninDelegateObserver() {}
-};
-
-}  // namespace app_list
-
-#endif  // UI_APP_LIST_SIGNIN_DELEGATE_OBSERVER_H_
diff --git a/ui/app_list/test/app_list_test_model.cc b/ui/app_list/test/app_list_test_model.cc
index 67331f3..c320a0c 100644
--- a/ui/app_list/test/app_list_test_model.cc
+++ b/ui/app_list/test/app_list_test_model.cc
@@ -10,6 +10,10 @@
 namespace app_list {
 namespace test {
 
+AppListTestModel::AppListTestModel() {
+  SetSignedIn(true);
+}
+
 void AppListTestModel::PopulateApps(int n) {
   for (int i = 0; i < n; ++i)
     AddItem(base::StringPrintf("Item %d", i));
diff --git a/ui/app_list/test/app_list_test_model.h b/ui/app_list/test/app_list_test_model.h
index 75fabf5..b918bcf 100644
--- a/ui/app_list/test/app_list_test_model.h
+++ b/ui/app_list/test/app_list_test_model.h
@@ -18,7 +18,7 @@
 // Extends AppListModel with helper functions for use in tests.
 class AppListTestModel : public AppListModel {
  public:
-  AppListTestModel() {}
+  AppListTestModel();
 
   // Populate the model with |n| items titled "Item #".
   void PopulateApps(int n);
diff --git a/ui/app_list/test/app_list_test_view_delegate.cc b/ui/app_list/test/app_list_test_view_delegate.cc
index 3e7b2df..1a56714 100644
--- a/ui/app_list/test/app_list_test_view_delegate.cc
+++ b/ui/app_list/test/app_list_test_view_delegate.cc
@@ -44,13 +44,5 @@
   return gfx::ImageSkia();
 }
 
-base::string16 AppListTestViewDelegate::GetCurrentUserName() {
-  return base::string16();
-}
-
-base::string16 AppListTestViewDelegate::GetCurrentUserEmail() {
-  return base::string16();
-}
-
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/test/app_list_test_view_delegate.h b/ui/app_list/test/app_list_test_view_delegate.h
index 0b513a1..3dd2599 100644
--- a/ui/app_list/test/app_list_test_view_delegate.h
+++ b/ui/app_list/test/app_list_test_view_delegate.h
@@ -42,10 +42,7 @@
                                         int event_flags) OVERRIDE {}
   virtual void Dismiss() OVERRIDE;
   virtual void ViewClosing() OVERRIDE {}
-  virtual void ViewActivationChanged(bool active) OVERRIDE {}
   virtual gfx::ImageSkia GetWindowIcon() OVERRIDE;
-  virtual base::string16 GetCurrentUserName() OVERRIDE;
-  virtual base::string16 GetCurrentUserEmail() OVERRIDE;
   virtual void OpenSettings() OVERRIDE {}
   virtual void OpenHelp() OVERRIDE {}
   virtual void OpenFeedback() OVERRIDE {}
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc
index fa0de27..d2df1de 100644
--- a/ui/app_list/views/app_list_main_view.cc
+++ b/ui/app_list/views/app_list_main_view.cc
@@ -134,7 +134,7 @@
 }
 
 void AppListMainView::SetDragAndDropHostOfCurrentAppList(
-    app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+    ApplicationDragAndDropHost* drag_and_drop_host) {
   contents_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
 }
 
diff --git a/ui/app_list/views/app_list_main_view.h b/ui/app_list/views/app_list_main_view.h
index 1909d97..1bb6981 100644
--- a/ui/app_list/views/app_list_main_view.h
+++ b/ui/app_list/views/app_list_main_view.h
@@ -9,9 +9,9 @@
 
 #include "base/memory/scoped_vector.h"
 #include "base/timer/timer.h"
-#include "ui/app_list/apps_grid_view_delegate.h"
-#include "ui/app_list/search_box_view_delegate.h"
-#include "ui/app_list/search_result_list_view_delegate.h"
+#include "ui/app_list/views/apps_grid_view_delegate.h"
+#include "ui/app_list/views/search_box_view_delegate.h"
+#include "ui/app_list/views/search_result_list_view_delegate.h"
 #include "ui/views/view.h"
 
 namespace views {
diff --git a/ui/app_list/views/app_list_menu_views.cc b/ui/app_list/views/app_list_menu_views.cc
index 0eb8536..3dca543 100644
--- a/ui/app_list/views/app_list_menu_views.cc
+++ b/ui/app_list/views/app_list_menu_views.cc
@@ -5,6 +5,7 @@
 #include "ui/app_list/views/app_list_menu_views.h"
 
 #include "grit/ui_resources.h"
+#include "ui/app_list/app_list_model.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/views/controls/button/menu_button.h"
@@ -88,9 +89,11 @@
 class AppListMenuModelAdapter : public views::MenuModelAdapter {
  public:
   AppListMenuModelAdapter(ui::MenuModel* menu_model,
-                          AppListViewDelegate* delegate)
+                          AppListViewDelegate* delegate,
+                          AppListModel* app_list_model)
       : views::MenuModelAdapter(menu_model),
-        delegate_(delegate) {}
+        delegate_(delegate),
+        app_list_model_(app_list_model) {}
   virtual ~AppListMenuModelAdapter() {}
 
   // Overridden from views::MenuModelAdapter:
@@ -108,8 +111,8 @@
     MenuItemView* item = new CurrentUserMenuItem(
         menu,
         id,
-        delegate_->GetCurrentUserName(),
-        delegate_->GetCurrentUserEmail(),
+        app_list_model_->current_user_name(),
+        app_list_model_->current_user_email(),
         *rb.GetImageSkiaNamed(IDR_APP_LIST_USER_INDICATOR));
     menu->CreateSubmenu();
     menu->GetSubmenu()->AddChildViewAt(item, index);
@@ -118,15 +121,19 @@
 
  private:
   AppListViewDelegate* delegate_;
+  AppListModel* app_list_model_;  // Weak. Owned by AppListView.
 
   DISALLOW_COPY_AND_ASSIGN(AppListMenuModelAdapter);
 };
 
 }  // namespace
 
-AppListMenuViews::AppListMenuViews(AppListViewDelegate* delegate)
+AppListMenuViews::AppListMenuViews(AppListViewDelegate* delegate,
+                                   AppListModel* app_list_model)
     : AppListMenu(delegate) {
-  menu_delegate_.reset(new AppListMenuModelAdapter(menu_model(), delegate));
+  menu_delegate_.reset(new AppListMenuModelAdapter(menu_model(),
+                                                   delegate,
+                                                   app_list_model));
   menu_ = new MenuItemView(menu_delegate_.get());
   menu_runner_.reset(new views::MenuRunner(menu_));
   menu_delegate_->BuildMenu(menu_);
diff --git a/ui/app_list/views/app_list_menu_views.h b/ui/app_list/views/app_list_menu_views.h
index 15f3dbb..2dc3d01 100644
--- a/ui/app_list/views/app_list_menu_views.h
+++ b/ui/app_list/views/app_list_menu_views.h
@@ -20,11 +20,14 @@
 
 namespace app_list {
 
+class AppListModel;
+
 // Views implementation of the app list menu.
 // TODO(benwells): We should consider moving this into Chrome.
-class AppListMenuViews : public app_list::AppListMenu {
+class AppListMenuViews : public AppListMenu {
  public:
-  explicit AppListMenuViews(AppListViewDelegate* delegate);
+  AppListMenuViews(AppListViewDelegate* delegate,
+                   AppListModel* model);
   virtual ~AppListMenuViews();
 
   void RunMenuAt(views::MenuButton* button, const gfx::Point& point);
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 118ab2b..29b3f7c 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -4,6 +4,7 @@
 
 #include "ui/app_list/views/app_list_view.h"
 
+#include "base/callback.h"
 #include "base/command_line.h"
 #include "base/strings/string_util.h"
 #include "ui/app_list/app_list_constants.h"
@@ -37,6 +38,8 @@
 
 namespace {
 
+base::Closure g_next_paint_callback;
+
 // The distance between the arrow tip and edge of the anchor view.
 const int kArrowOffset = 10;
 
@@ -52,14 +55,11 @@
       signin_view_(NULL) {
   if (delegate_)
     delegate_->SetModel(model_.get());
-  if (GetSigninDelegate())
-    GetSigninDelegate()->AddObserver(this);
+  model_->AddObserver(this);
 }
 
 AppListView::~AppListView() {
-  if (GetSigninDelegate())
-    GetSigninDelegate()->RemoveObserver(this);
-
+  model_->RemoveObserver(this);
   // Models are going away, ensure their references are cleared.
   RemoveAllChildViews(true);
 }
@@ -142,7 +142,7 @@
 }
 
 void AppListView::SetDragAndDropHostOfCurrentAppList(
-    app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+    ApplicationDragAndDropHost* drag_and_drop_host) {
   app_list_main_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
 }
 
@@ -166,6 +166,14 @@
   return app_list_main_view_->GetPreferredSize();
 }
 
+void AppListView::Paint(gfx::Canvas* canvas) {
+  views::BubbleDelegateView::Paint(canvas);
+  if (!g_next_paint_callback.is_null()) {
+    g_next_paint_callback.Run();
+    g_next_paint_callback.Reset();
+  }
+}
+
 bool AppListView::ShouldHandleSystemCommands() const {
   return true;
 }
@@ -175,14 +183,24 @@
 }
 
 void AppListView::OnSigninStatusChanged() {
-  const bool needs_signin =
-      GetSigninDelegate() && GetSigninDelegate()->NeedSignin();
-
-  signin_view_->SetVisible(needs_signin);
-  app_list_main_view_->SetVisible(!needs_signin);
+  signin_view_->SetVisible(!model_->signed_in());
+  app_list_main_view_->SetVisible(model_->signed_in());
   app_list_main_view_->search_box_view()->InvalidateMenu();
 }
 
+void AppListView::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void AppListView::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+// static
+void AppListView::SetNextPaintCallback(const base::Closure& callback) {
+  g_next_paint_callback = callback;
+}
+
 #if defined(OS_WIN)
 HWND AppListView::GetHWND() const {
 #if defined(USE_AURA)
@@ -247,8 +265,9 @@
                                             bool active) {
   // Do not called inherited function as the bubble delegate auto close
   // functionality is not used.
-  if (delegate_ && widget == GetWidget())
-    delegate_->ViewActivationChanged(active);
+  if (widget == GetWidget())
+    FOR_EACH_OBSERVER(Observer, observers_,
+                      OnActivationChanged(widget, active));
 }
 
 void AppListView::OnWidgetVisibilityChanged(views::Widget* widget,
@@ -268,12 +287,16 @@
   Layout();
 }
 
-void AppListView::OnSigninSuccess() {
+SigninDelegate* AppListView::GetSigninDelegate() {
+  return delegate_ ? delegate_->GetSigninDelegate() : NULL;
+}
+
+void AppListView::OnAppListModelSigninStatusChanged() {
   OnSigninStatusChanged();
 }
 
-SigninDelegate* AppListView::GetSigninDelegate() {
-  return delegate_ ? delegate_->GetSigninDelegate() : NULL;
+void AppListView::OnAppListModelCurrentUserChanged() {
+  OnSigninStatusChanged();
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index fff4815..53d08a4 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -5,9 +5,11 @@
 #ifndef UI_APP_LIST_VIEWS_APP_LIST_VIEW_H_
 #define UI_APP_LIST_VIEWS_APP_LIST_VIEW_H_
 
+#include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
 #include "ui/app_list/app_list_export.h"
-#include "ui/app_list/signin_delegate_observer.h"
+#include "ui/app_list/app_list_model_observer.h"
 #include "ui/views/bubble/bubble_delegate.h"
 
 namespace views {
@@ -26,8 +28,13 @@
 // AppListView is the top-level view and controller of app list UI. It creates
 // and hosts a AppsGridView and passes AppListModel to it for display.
 class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView,
-                                    public SigninDelegateObserver {
+                                    public AppListModelObserver {
  public:
+  class Observer {
+  public:
+    virtual void OnActivationChanged(views::Widget* widget, bool active) = 0;
+  };
+
   // Takes ownership of |delegate|.
   explicit AppListView(AppListViewDelegate* delegate);
   virtual ~AppListView();
@@ -49,7 +56,7 @@
   // InitAsBubble was called since the app list object needs to exist so that
   // it can set the host.
   void SetDragAndDropHostOfCurrentAppList(
-      app_list::ApplicationDragAndDropHost* drag_and_drop_host);
+      ApplicationDragAndDropHost* drag_and_drop_host);
 
   // Shows the UI when there are no pending icon loads. Otherwise, starts a
   // timer to show the UI when a maximum allowed wait time has expired.
@@ -61,6 +68,7 @@
 
   // Overridden from views::View:
   virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
 
   // WidgetDelegate overrides:
   virtual bool ShouldHandleSystemCommands() const OVERRIDE;
@@ -70,6 +78,12 @@
   // Invoked when the sign-in status is changed to switch on/off sign-in view.
   void OnSigninStatusChanged();
 
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+  // Set a callback to be called the next time any app list paints.
+  static void SetNextPaintCallback(const base::Closure& callback);
+
 #if defined(OS_WIN)
   HWND GetHWND() const;
 #endif
@@ -92,8 +106,9 @@
   virtual void OnWidgetActivationChanged(
       views::Widget* widget, bool active) OVERRIDE;
 
-  // Overridden from SigninDelegateObserver:
-  virtual void OnSigninSuccess() OVERRIDE;
+  // Overridden from AppListModelObserver:
+  virtual void OnAppListModelSigninStatusChanged() OVERRIDE;
+  virtual void OnAppListModelCurrentUserChanged() OVERRIDE;
 
   SigninDelegate* GetSigninDelegate();
 
@@ -103,6 +118,8 @@
   AppListMainView*  app_list_main_view_;
   SigninView* signin_view_;
 
+  ObserverList<Observer> observers_;
+
   DISALLOW_COPY_AND_ASSIGN(AppListView);
 };
 
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 1e9b2bf..c9f28e1 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -7,10 +7,10 @@
 #include <algorithm>
 
 #include "ui/app_list/app_list_item_model.h"
-#include "ui/app_list/apps_grid_view_delegate.h"
 #include "ui/app_list/pagination_model.h"
 #include "ui/app_list/views/app_list_drag_and_drop_host.h"
 #include "ui/app_list/views/app_list_item_view.h"
+#include "ui/app_list/views/apps_grid_view_delegate.h"
 #include "ui/app_list/views/page_switcher.h"
 #include "ui/app_list/views/pulsing_block_view.h"
 #include "ui/base/animation/animation.h"
@@ -34,6 +34,8 @@
 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
 #endif
 
+namespace app_list {
+
 namespace {
 
 // Distance a drag needs to be from the app grid to be considered 'outside', at
@@ -66,7 +68,7 @@
 const float kDragAndDropProxyScale = 1.5f;
 
 // For testing we remember the last created grid view.
-app_list::AppsGridView* last_created_grid_view_for_test = NULL;
+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
@@ -120,8 +122,6 @@
 
 }  // namespace
 
-namespace app_list {
-
 #if defined(OS_WIN) && !defined(USE_AURA)
 // Interprets drag events sent from Windows via the drag/drop API and forwards
 // them to AppsGridView.
@@ -134,16 +134,15 @@
 // Windows drag that never enters the synchronous drag phase.
 class SynchronousDrag : public ui::DragSourceWin {
  public:
-  SynchronousDrag(app_list::AppsGridView* grid_view,
-              app_list::AppListItemView* drag_view,
-              const gfx::Point& drag_view_offset)
+  SynchronousDrag(AppsGridView* grid_view,
+                  AppListItemView* drag_view,
+                  const gfx::Point& drag_view_offset)
       : grid_view_(grid_view),
         drag_view_(drag_view),
         drag_view_offset_(drag_view_offset),
         has_shortcut_path_(false),
         running_(false),
-        canceled_(false) {
-  }
+        canceled_(false) {}
 
   void set_shortcut_path(const base::FilePath& shortcut_path) {
     has_shortcut_path_ = true;
@@ -187,8 +186,7 @@
   }
 
   virtual void OnDragSourceMove() OVERRIDE {
-    grid_view_->UpdateDrag(app_list::AppsGridView::MOUSE,
-                           GetCursorInGridViewCoords());
+    grid_view_->UpdateDrag(AppsGridView::MOUSE, GetCursorInGridViewCoords());
   }
 
   void SetupExchangeData(ui::OSExchangeData* data) {
@@ -221,8 +219,8 @@
     return grid_view_pt;
   }
 
-  app_list::AppsGridView* grid_view_;
-  app_list::AppListItemView* drag_view_;
+  AppsGridView* grid_view_;
+  AppListItemView* drag_view_;
   gfx::Point drag_view_offset_;
   bool has_shortcut_path_;
   base::FilePath shortcut_path_;
diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h
index 9c20164..59e4173 100644
--- a/ui/app_list/views/apps_grid_view.h
+++ b/ui/app_list/views/apps_grid_view.h
@@ -135,7 +135,7 @@
   }
 
  private:
-  friend class app_list::test::AppsGridViewTestApi;
+  friend class test::AppsGridViewTestApi;
 
   // Represents the index to an item view in the grid.
   struct Index {
diff --git a/ui/app_list/views/apps_grid_view_delegate.h b/ui/app_list/views/apps_grid_view_delegate.h
new file mode 100644
index 0000000..83430b0
--- /dev/null
+++ b/ui/app_list/views/apps_grid_view_delegate.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_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
+#define UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
+
+#include "base/callback_forward.h"
+#include "ui/app_list/app_list_export.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace app_list {
+
+class AppListItemModel;
+
+class APP_LIST_EXPORT AppsGridViewDelegate {
+ public:
+  // Invoked when an item is activated on the grid view. |event_flags| contains
+  // the flags of the keyboard/mouse event that triggers the activation request.
+  virtual void ActivateApp(AppListItemModel* item, int event_flags) = 0;
+
+  // Gets the path to a shortcut for the app represented by |item|. |callback|
+  // may be run immediately.
+  virtual void GetShortcutPathForApp(
+      const std::string& app_id,
+      const base::Callback<void(const base::FilePath&)>& callback) = 0;
+
+ protected:
+  virtual ~AppsGridViewDelegate() {}
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_VIEWS_APPS_GRID_VIEW_DELEGATE_H_
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc
index 87d5f67..2abb76f 100644
--- a/ui/app_list/views/apps_grid_view_unittest.cc
+++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -47,10 +47,14 @@
     DCHECK(!wait_);
     wait_ = true;
     page_changed_ = false;
-    wait_timer_.Stop();
-    wait_timer_.Start(FROM_HERE,
-                      base::TimeDelta::FromMilliseconds(time_out_ms),
-                      this, &PageFlipWaiter::OnWaitTimeOut);
+
+    if (time_out_ms) {
+      wait_timer_.Stop();
+      wait_timer_.Start(FROM_HERE,
+                        base::TimeDelta::FromMilliseconds(time_out_ms),
+                        this, &PageFlipWaiter::OnWaitTimeOut);
+    }
+
     ui_loop_->Run();
     wait_ = false;
     return page_changed_;
@@ -260,15 +264,7 @@
   test_api_->LayoutToIdealBounds();
 }
 
-// Test fails sometimes on chrome os.
-// http://crbug.com/242248
-#if defined(OS_CHROMEOS)
-#define MAYBE_MouseDragFlipPage DISABLED_MouseDragFlipPage
-#else
-#define MAYBE_MouseDragFlipPage MouseDragFlipPage
-#endif  // defined(OS_CHROMEOS)
-
-TEST_F(AppsGridViewTest, MAYBE_MouseDragFlipPage) {
+TEST_F(AppsGridViewTest, MouseDragFlipPage) {
   test_api_->SetPageFlipDelay(10);
   pagination_model_->SetTransitionDurations(10, 10);
 
@@ -288,11 +284,11 @@
   SimulateDrag(AppsGridView::MOUSE, from, to);
 
   // Page should be flipped after sometime.
-  EXPECT_TRUE(page_flip_waiter.Wait(100));
+  EXPECT_TRUE(page_flip_waiter.Wait(0));
   EXPECT_EQ(1, pagination_model_->selected_page());
 
   // Stay there and page should be flipped again.
-  EXPECT_TRUE(page_flip_waiter.Wait(100));
+  EXPECT_TRUE(page_flip_waiter.Wait(0));
   EXPECT_EQ(2, pagination_model_->selected_page());
 
   // Stay there longer and no page flip happen since we are at the last page.
@@ -306,10 +302,10 @@
 
   SimulateDrag(AppsGridView::MOUSE, from, to);
 
-  EXPECT_TRUE(page_flip_waiter.Wait(100));
+  EXPECT_TRUE(page_flip_waiter.Wait(0));
   EXPECT_EQ(1, pagination_model_->selected_page());
 
-  EXPECT_TRUE(page_flip_waiter.Wait(100));
+  EXPECT_TRUE(page_flip_waiter.Wait(0));
   EXPECT_EQ(0, pagination_model_->selected_page());
 
   EXPECT_FALSE(page_flip_waiter.Wait(100));
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index 5211eb1..7d14d17 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -77,7 +77,7 @@
 }
 
 void ContentsView::SetDragAndDropHostOfCurrentAppList(
-    app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
+    ApplicationDragAndDropHost* drag_and_drop_host) {
   apps_grid_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
 }
 
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h
index f0b974c..4cc42da 100644
--- a/ui/app_list/views/contents_view.h
+++ b/ui/app_list/views/contents_view.h
@@ -37,7 +37,7 @@
   // If |drag_and_drop| is not NULL it will be called upon drag and drop
   // operations outside the application list.
   void SetDragAndDropHostOfCurrentAppList(
-      app_list::ApplicationDragAndDropHost* drag_and_drop_host);
+      ApplicationDragAndDropHost* drag_and_drop_host);
 
   void ShowSearchResults(bool show);
 
diff --git a/ui/app_list/views/page_switcher.cc b/ui/app_list/views/page_switcher.cc
index 665b023..f8690a7 100644
--- a/ui/app_list/views/page_switcher.cc
+++ b/ui/app_list/views/page_switcher.cc
@@ -15,6 +15,8 @@
 #include "ui/views/controls/button/custom_button.h"
 #include "ui/views/layout/box_layout.h"
 
+namespace app_list {
+
 namespace {
 
 const int kPreferredHeight = 57;
@@ -52,11 +54,10 @@
   }
 
   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
-    if (state() == STATE_HOVERED) {
-      PaintButton(canvas, app_list::kPagerHoverColor);
-    } else {
-      PaintButton(canvas, app_list::kPagerNormalColor);
-    }
+    if (state() == STATE_HOVERED)
+      PaintButton(canvas, kPagerHoverColor);
+    else
+      PaintButton(canvas, kPagerNormalColor);
   }
 
  private:
@@ -94,7 +95,7 @@
       selected_path.addRoundRect(gfx::RectToSkRect(selected_rect),
                                  SkIntToScalar(kButtonCornerRadius),
                                  SkIntToScalar(kButtonCornerRadius));
-      paint.setColor(app_list::kPagerSelectedColor);
+      paint.setColor(kPagerSelectedColor);
       canvas->DrawPath(selected_path, paint);
     }
   }
@@ -116,8 +117,6 @@
 
 }  // namespace
 
-namespace app_list {
-
 PageSwitcher::PageSwitcher(PaginationModel* model)
     : model_(model),
       buttons_(new views::View) {
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 1d997e5..ae5d715 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -9,8 +9,8 @@
 #include "grit/ui_resources.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/search_box_model.h"
-#include "ui/app_list/search_box_view_delegate.h"
 #include "ui/app_list/views/app_list_menu_views.h"
+#include "ui/app_list/views/search_box_view_delegate.h"
 #include "ui/base/events/event.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/views/controls/button/menu_button.h"
@@ -40,7 +40,7 @@
                              AppListModel* model)
     : delegate_(delegate),
       view_delegate_(view_delegate),
-      model_(model->search_box()),
+      model_(model),
       icon_view_(new views::ImageView),
       search_box_(new views::Textfield),
       contents_view_(NULL) {
@@ -65,13 +65,13 @@
   search_box_->SetController(this);
   AddChildView(search_box_);
 
-  model_->AddObserver(this);
+  model_->search_box()->AddObserver(this);
   IconChanged();
   HintTextChanged();
 }
 
 SearchBoxView::~SearchBoxView() {
-  model_->RemoveObserver(this);
+  model_->search_box()->RemoveObserver(this);
 }
 
 bool SearchBoxView::HasSearch() const {
@@ -132,10 +132,10 @@
 
 void SearchBoxView::UpdateModel() {
   // Temporarily remove from observer to ignore notifications caused by us.
-  model_->RemoveObserver(this);
-  model_->SetText(search_box_->text());
-  model_->SetSelectionModel(search_box_->GetSelectionModel());
-  model_->AddObserver(this);
+  model_->search_box()->RemoveObserver(this);
+  model_->search_box()->SetText(search_box_->text());
+  model_->search_box()->SetSelectionModel(search_box_->GetSelectionModel());
+  model_->search_box()->AddObserver(this);
 }
 
 void SearchBoxView::NotifyQueryChanged() {
@@ -160,7 +160,7 @@
 
 void SearchBoxView::OnMenuButtonClicked(View* source, const gfx::Point& point) {
   if (!menu_)
-    menu_.reset(new AppListMenuViews(view_delegate_));
+    menu_.reset(new AppListMenuViews(view_delegate_, model_));
 
   const gfx::Point menu_location =
       menu_button_->GetBoundsInScreen().bottom_right() +
@@ -169,19 +169,19 @@
 }
 
 void SearchBoxView::IconChanged() {
-  icon_view_->SetImage(model_->icon());
+  icon_view_->SetImage(model_->search_box()->icon());
 }
 
 void SearchBoxView::HintTextChanged() {
-  search_box_->set_placeholder_text(model_->hint_text());
+  search_box_->set_placeholder_text(model_->search_box()->hint_text());
 }
 
 void SearchBoxView::SelectionModelChanged() {
-  search_box_->SelectSelectionModel(model_->selection_model());
+  search_box_->SelectSelectionModel(model_->search_box()->selection_model());
 }
 
 void SearchBoxView::TextChanged() {
-  search_box_->SetText(model_->text());
+  search_box_->SetText(model_->search_box()->text());
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index 439a4cf..c069902 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -21,8 +21,8 @@
 namespace app_list {
 
 class AppListMenuViews;
-class AppListViewDelegate;
 class AppListModel;
+class AppListViewDelegate;
 class SearchBoxModel;
 class SearchBoxViewDelegate;
 
@@ -80,7 +80,7 @@
 
   SearchBoxViewDelegate* delegate_;  // Not owned.
   AppListViewDelegate* view_delegate_;  // Not owned.
-  SearchBoxModel* model_;  // Owned by AppListModel.
+  AppListModel* model_;  // Owned by AppListView.
 
   scoped_ptr<AppListMenuViews> menu_;
 
diff --git a/ui/app_list/views/search_box_view_delegate.h b/ui/app_list/views/search_box_view_delegate.h
new file mode 100644
index 0000000..cdbf238
--- /dev/null
+++ b/ui/app_list/views/search_box_view_delegate.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 UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_DELEGATE_H_
+#define UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_DELEGATE_H_
+
+#include "ui/app_list/app_list_export.h"
+
+namespace app_list {
+
+class SearchBoxView;
+
+class APP_LIST_EXPORT SearchBoxViewDelegate {
+ public:
+  // Invoked when query text has changed by the user.
+  virtual void QueryChanged(SearchBoxView* sender) = 0;
+
+ protected:
+  virtual ~SearchBoxViewDelegate() {}
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_VIEWS_SEARCH_BOX_VIEW_DELEGATE_H_
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc
index 5eaad3c..9e61432 100644
--- a/ui/app_list/views/search_result_list_view.cc
+++ b/ui/app_list/views/search_result_list_view.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
-#include "ui/app_list/search_result_list_view_delegate.h"
+#include "ui/app_list/views/search_result_list_view_delegate.h"
 #include "ui/app_list/views/search_result_view.h"
 #include "ui/base/events/event.h"
 #include "ui/views/layout/box_layout.h"
diff --git a/ui/app_list/views/search_result_list_view_delegate.h b/ui/app_list/views/search_result_list_view_delegate.h
new file mode 100644
index 0000000..405094b
--- /dev/null
+++ b/ui/app_list/views/search_result_list_view_delegate.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 UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
+#define UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
+
+#include "ui/app_list/app_list_export.h"
+
+namespace app_list {
+
+class SearchResult;
+
+class APP_LIST_EXPORT SearchResultListViewDelegate {
+ public:
+  // Invoked to open given |result|. |event_flags| contains the flags of the
+  // keyboard/mouse event that triggers the "open" request. Delegate could use
+  // the |event_flags| information to choose different ways to open the result.
+  virtual void OpenResult(SearchResult* result,
+                          int event_flags) = 0;
+
+  // Called to invoke a custom action on |result|.  |action_index| corresponds
+  // to the index of the icon in |result.action_icons()| that was activated.
+  virtual void InvokeResultAction(SearchResult* result,
+                                  int action_index,
+                                  int event_flags) = 0;
+
+  // Called when the app represented by |result| is installed.
+  virtual void OnResultInstalled(SearchResult* result) = 0;
+
+  // Called when the app represented by |result| is uninstalled.
+  virtual void OnResultUninstalled(SearchResult* result) = 0;
+
+ protected:
+  virtual ~SearchResultListViewDelegate() {}
+};
+
+}  // namespace app_list
+
+#endif  // UI_APP_LIST_VIEWS_SEARCH_RESULT_LIST_VIEW_DELEGATE_H_
diff --git a/ui/app_list/views/search_result_view.cc b/ui/app_list/views/search_result_view.cc
index 55b9e0b..9e7fe51 100644
--- a/ui/app_list/views/search_result_view.cc
+++ b/ui/app_list/views/search_result_view.cc
@@ -20,6 +20,8 @@
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/controls/menu/menu_runner.h"
 
+namespace app_list {
+
 namespace {
 
 const int kPreferredWidth = 300;
@@ -36,24 +38,24 @@
 // Creates a RenderText of given |text| and |styles|. Caller takes ownership
 // of returned RenderText.
 gfx::RenderText* CreateRenderText(const base::string16& text,
-                                  const app_list::SearchResult::Tags& tags) {
+                                  const SearchResult::Tags& tags) {
   gfx::RenderText* render_text = gfx::RenderText::CreateInstance();
   render_text->SetText(text);
-  render_text->SetColor(app_list::kResultDefaultTextColor);
+  render_text->SetColor(kResultDefaultTextColor);
 
-  for (app_list::SearchResult::Tags::const_iterator it = tags.begin();
+  for (SearchResult::Tags::const_iterator it = tags.begin();
        it != tags.end();
        ++it) {
     // NONE means default style so do nothing.
-    if (it->styles == app_list::SearchResult::Tag::NONE)
+    if (it->styles == SearchResult::Tag::NONE)
       continue;
 
-    if (it->styles & app_list::SearchResult::Tag::MATCH)
+    if (it->styles & SearchResult::Tag::MATCH)
       render_text->ApplyStyle(gfx::BOLD, true, it->range);
-    if (it->styles & app_list::SearchResult::Tag::DIM)
-      render_text->ApplyColor(app_list::kResultDimmedTextColor, it->range);
-    else if (it->styles & app_list::SearchResult::Tag::URL)
-      render_text->ApplyColor(app_list::kResultURLTextColor, it->range);
+    if (it->styles & SearchResult::Tag::DIM)
+      render_text->ApplyColor(kResultDimmedTextColor, it->range);
+    else if (it->styles & SearchResult::Tag::URL)
+      render_text->ApplyColor(kResultURLTextColor, it->range);
   }
 
   return render_text;
@@ -61,8 +63,6 @@
 
 }  // namespace
 
-namespace app_list {
-
 // static
 const char SearchResultView::kViewClassName[] = "ui/app_list/SearchResultView";
 
diff --git a/ui/aura/bench/DEPS b/ui/aura/bench/DEPS
index 69deb97..1fda554 100644
--- a/ui/aura/bench/DEPS
+++ b/ui/aura/bench/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+cc",
   "+third_party/khronos",
   "+third_party/WebKit/public/platform",
 ]
diff --git a/ui/aura/bench/bench_main.cc b/ui/aura/bench/bench_main.cc
index aee7e79..c6b03eb 100644
--- a/ui/aura/bench/bench_main.cc
+++ b/ui/aura/bench/bench_main.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_split.h"
 #include "base/time/time.h"
+#include "cc/output/context_provider.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/skia/include/core/SkXfermode.h"
 #include "ui/aura/client/default_capture_client.h"
@@ -181,7 +182,7 @@
         parent_(parent),
         webgl_(ui::LAYER_TEXTURED),
         compositor_(compositor),
-        context_(),
+        context_provider_(),
         texture_(),
         fbo_(0),
         do_draw_(true) {
@@ -207,24 +208,26 @@
     webgl_.SetBounds(bounds);
     parent_->Add(&webgl_);
 
-    context_ = ui::ContextFactory::GetInstance()->CreateOffscreenContext();
-    context_->makeContextCurrent();
-    texture_ = new WebGLTexture(context_.get(), bounds.size());
-    fbo_ = context_->createFramebuffer();
+    context_provider_ = ui::ContextFactory::GetInstance()
+        ->OffscreenContextProviderForMainThread();
+    WebKit::WebGraphicsContext3D* context = context_provider_->Context3d();
+    context->makeContextCurrent();
+    texture_ = new WebGLTexture(context, bounds.size());
+    fbo_ = context->createFramebuffer();
     compositor->AddObserver(this);
     webgl_.SetExternalTexture(texture_.get());
-    context_->bindFramebuffer(GL_FRAMEBUFFER, fbo_);
-    context_->framebufferTexture2D(
+    context->bindFramebuffer(GL_FRAMEBUFFER, fbo_);
+    context->framebufferTexture2D(
         GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
         GL_TEXTURE_2D, texture_->PrepareTexture(), 0);
-    context_->clearColor(0.f, 1.f, 0.f, 1.f);
-    context_->clear(GL_COLOR_BUFFER_BIT);
-    context_->flush();
+    context->clearColor(0.f, 1.f, 0.f, 1.f);
+    context->clear(GL_COLOR_BUFFER_BIT);
+    context->flush();
   }
 
   virtual ~WebGLBench() {
-    context_->makeContextCurrent();
-    context_->deleteFramebuffer(fbo_);
+    context_provider_->Context3d()->makeContextCurrent();
+    context_provider_->Context3d()->deleteFramebuffer(fbo_);
     webgl_.SetExternalTexture(NULL);
     texture_ = NULL;
     compositor_->RemoveObserver(this);
@@ -232,10 +235,11 @@
 
   virtual void Draw() OVERRIDE {
     if (do_draw_) {
-      context_->makeContextCurrent();
-      context_->clearColor((frames() % kFrames)*1.0/kFrames, 1.f, 0.f, 1.f);
-      context_->clear(GL_COLOR_BUFFER_BIT);
-      context_->flush();
+      WebKit::WebGraphicsContext3D* context = context_provider_->Context3d();
+      context->makeContextCurrent();
+      context->clearColor((frames() % kFrames)*1.0/kFrames, 1.f, 0.f, 1.f);
+      context->clear(GL_COLOR_BUFFER_BIT);
+      context->flush();
     }
     webgl_.SetExternalTexture(texture_.get());
     webgl_.SchedulePaint(gfx::Rect(webgl_.bounds().size()));
@@ -246,7 +250,7 @@
   Layer* parent_;
   Layer webgl_;
   Compositor* compositor_;
-  scoped_ptr<WebGraphicsContext3D> context_;
+  scoped_refptr<cc::ContextProvider> context_provider_;
   scoped_refptr<WebGLTexture> texture_;
 
   // The FBO that is used to render to the texture.
@@ -297,7 +301,7 @@
   base::AtExitManager exit_manager;
 
   ui::RegisterPathProvider();
-  icu_util::Initialize();
+  base::i18n::InitializeICU();
   ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL);
 
   base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
diff --git a/ui/aura/client/cursor_client.h b/ui/aura/client/cursor_client.h
index acdf255..c68c9aa 100644
--- a/ui/aura/client/cursor_client.h
+++ b/ui/aura/client/cursor_client.h
@@ -60,6 +60,9 @@
   // EnableMouseEvents/DisableMouseEvents.
   virtual void UnlockCursor() = 0;
 
+  // Returns true if the cursor is locked.
+  virtual bool IsCursorLocked() const = 0;
+
   // Used to add or remove a CursorClientObserver.
   virtual void AddObserver(CursorClientObserver* observer) = 0;
   virtual void RemoveObserver(CursorClientObserver* observer) = 0;
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc
index 06938d8..9bd8ad0 100644
--- a/ui/aura/demo/demo_main.cc
+++ b/ui/aura/demo/demo_main.cc
@@ -160,7 +160,7 @@
   base::AtExitManager exit_manager;
 
   ui::RegisterPathProvider();
-  icu_util::Initialize();
+  base::i18n::InitializeICU();
   ResourceBundle::InitSharedInstanceWithLocale("en-US", NULL);
 
   return DemoMain();
diff --git a/ui/aura/remote_root_window_host_win.cc b/ui/aura/remote_root_window_host_win.cc
index f5dc26b..d428538 100644
--- a/ui/aura/remote_root_window_host_win.cc
+++ b/ui/aura/remote_root_window_host_win.cc
@@ -339,13 +339,6 @@
   return true;
 }
 
-bool RemoteRootWindowHostWin::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                                 const gfx::Point& dest_offset,
-                                                 SkCanvas* canvas) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 void RemoteRootWindowHostWin::UnConfineCursor() {
 }
 
diff --git a/ui/aura/remote_root_window_host_win.h b/ui/aura/remote_root_window_host_win.h
index 132f0f2..e2e6d1c 100644
--- a/ui/aura/remote_root_window_host_win.h
+++ b/ui/aura/remote_root_window_host_win.h
@@ -184,9 +184,6 @@
   virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
   virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) OVERRIDE;
   virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
   virtual void PrepareForShutdown() OVERRIDE;
diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc
index 43366f0..e65e2b2 100644
--- a/ui/aura/root_window.cc
+++ b/ui/aura/root_window.cc
@@ -216,6 +216,8 @@
 }
 
 void RootWindow::RepostEvent(const ui::LocatedEvent& event) {
+  DCHECK(event.type() == ui::ET_MOUSE_PRESSED ||
+         event.type() == ui::ET_GESTURE_TAP_DOWN);
   // We allow for only one outstanding repostable event. This is used
   // in exiting context menus.  A dropped repost request is allowed.
   if (event.type() == ui::ET_MOUSE_PRESSED) {
@@ -224,15 +226,22 @@
             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 {
-    DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN);
-    held_repostable_event_.reset();
-    // TODO(sschmitz): add similar code for gesture events.
+    const ui::GestureEvent* gesture_event =
+        static_cast<const ui::GestureEvent*>(&event);
+    held_repostable_event_.reset(new ui::GestureEvent(
+        gesture_event->type(),
+        gesture_event->root_location().x(),
+        gesture_event->root_location().y(),
+        gesture_event->flags(),
+        gesture_event->time_stamp(),
+        gesture_event->details(),
+        gesture_event->touch_ids_bitfield()));
   }
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&RootWindow::DispatchHeldEvents,
+                  repostable_event_factory_.GetWeakPtr()));
 }
 
 RootWindowHostDelegate* RootWindow::AsRootWindowHostDelegate() {
@@ -499,15 +508,6 @@
   host_->SetFocusWhenShown(focused);
 }
 
-bool RootWindow::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                    const gfx::Point& dest_offset,
-                                    SkCanvas* canvas) {
-  DCHECK(canvas);
-  DCHECK(bounds().Contains(source_bounds));
-  gfx::Rect source_pixels = ui::ConvertRectToPixel(layer(), source_bounds);
-  return host_->CopyAreaToSkCanvas(source_pixels, dest_offset, canvas);
-}
-
 gfx::Point RootWindow::GetLastMouseLocationInRoot() const {
   gfx::Point location = Env::GetInstance()->last_mouse_location();
   client::ScreenPositionClient* client = client::GetScreenPositionClient(this);
@@ -698,12 +698,6 @@
   return host_->QueryMouseLocation(point);
 }
 
-void RootWindow::ClearMouseHandlers() {
-  mouse_pressed_handler_ = NULL;
-  mouse_moved_handler_ = NULL;
-  mouse_event_dispatch_target_ = NULL;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // RootWindow, private:
 
@@ -973,7 +967,9 @@
 }
 
 void RootWindow::OnHostLostMouseGrab() {
-  ClearMouseHandlers();
+  mouse_pressed_handler_ = NULL;
+  mouse_moved_handler_ = NULL;
+  mouse_event_dispatch_target_ = NULL;
 }
 
 void RootWindow::OnHostPaint(const gfx::Rect& damage_rect) {
@@ -1026,6 +1022,23 @@
   return DispatchMouseEventToTarget(event, target);
 }
 
+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) {
+    ProcessEvent(new_consumer, event);
+    return event->handled();
+  }
+  return false;
+}
+
 bool RootWindow::DispatchMouseEventToTarget(ui::MouseEvent* event,
                                             Window* target) {
   client::CursorClient* cursor_client = client::GetCursorClient(this);
@@ -1153,11 +1166,14 @@
     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
+      held_repostable_event_.reset();  // must be reset before dispatch
       DispatchMouseEventRepost(&mouse_event);
     } else {
       DCHECK(held_repostable_event_->type() == ui::ET_GESTURE_TAP_DOWN);
-      // TODO(sschmitz): add similar code for gesture events
+      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);
     }
     held_repostable_event_.reset();
   }
diff --git a/ui/aura/root_window.h b/ui/aura/root_window.h
index e8a6b26..c84f7d2 100644
--- a/ui/aura/root_window.h
+++ b/ui/aura/root_window.h
@@ -29,8 +29,6 @@
 #include "ui/gfx/point.h"
 #include "ui/gfx/transform.h"
 
-class SkCanvas;
-
 namespace gfx {
 class Size;
 class Transform;
@@ -86,6 +84,7 @@
   ui::Compositor* compositor() { return compositor_.get(); }
   gfx::NativeCursor last_cursor() const { return last_cursor_; }
   Window* mouse_pressed_handler() { return mouse_pressed_handler_; }
+  Window* mouse_moved_handler() { return mouse_moved_handler_; }
 
   // Initializes the root window.
   void Init();
@@ -100,6 +99,8 @@
   void PrepareForShutdown();
 
   // Repost event for re-processing. Used when exiting context menus.
+  // We only support the ET_MOUSE_PRESSED and ET_GESTURE_TAP_DOWN event
+  // types.
   void RepostEvent(const ui::LocatedEvent& event);
 
   RootWindowHostDelegate* AsRootWindowHostDelegate();
@@ -239,12 +240,6 @@
   // Sets if the window should be focused when shown.
   void SetFocusWhenShown(bool focus_when_shown);
 
-  // Copies |source_bounds| from the root window (as displayed on the host
-  // machine) to |canvas| at offset |dest_offset|.
-  bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                          const gfx::Point& dest_offset,
-                          SkCanvas* canvas);
-
   // Gets the last location seen in a mouse event in this root window's
   // coordinates. This may return a point outside the root window's bounds.
   gfx::Point GetLastMouseLocationInRoot() const;
@@ -286,10 +281,6 @@
   // Exposes RootWindowHost::QueryMouseLocation() for test purposes.
   bool QueryMouseLocationForTest(gfx::Point* point) const;
 
-  // Clears internal mouse state (such as mouse ups should be sent to the same
-  // window that ate mouse downs).
-  void ClearMouseHandlers();
-
   void SetRootWindowTransformer(scoped_ptr<RootWindowTransformer> transformer);
   gfx::Transform GetRootTransform() const;
 
@@ -406,6 +397,10 @@
 
   gfx::Transform GetInverseRootTransform() const;
 
+  // Reposts the gesture event to the Window which is a target for the event
+  // passed in.
+  bool DispatchGestureEventRepost(ui::GestureEvent* event);
+
   scoped_ptr<ui::Compositor> compositor_;
 
   scoped_ptr<RootWindowHost> host_;
diff --git a/ui/aura/root_window_host.h b/ui/aura/root_window_host.h
index 09e48fa..f1b5204 100644
--- a/ui/aura/root_window_host.h
+++ b/ui/aura/root_window_host.h
@@ -12,8 +12,6 @@
 #include "ui/base/cursor/cursor.h"
 #include "ui/gfx/native_widget_types.h"
 
-class SkCanvas;
-
 namespace gfx {
 class Insets;
 class Point;
@@ -99,13 +97,6 @@
   // Sets if the window should be focused when shown.
   virtual void SetFocusWhenShown(bool focus_when_shown) = 0;
 
-  // Copies |source_bounds| from the root window (as displayed on the host
-  // machine) to |canvas| at offset |dest_offset|.  The bounds need to be in
-  // physical pixels.
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) = 0;
-
   // Posts |native_event| to the platform's event queue.
 #if !defined(OS_MACOSX)
   virtual void PostNativeEvent(const base::NativeEvent& native_event) = 0;
diff --git a/ui/aura/root_window_host_mac.mm b/ui/aura/root_window_host_mac.mm
index 28943a9..de00e9b 100644
--- a/ui/aura/root_window_host_mac.mm
+++ b/ui/aura/root_window_host_mac.mm
@@ -46,9 +46,6 @@
   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
   virtual bool ConfineCursorToRootWindow() OVERRIDE;
   virtual void UnConfineCursor() OVERRIDE;
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) OVERRIDE;
   // RootWindowHostMacDelegate:
   virtual void SendEvent(const base::NativeEvent& native_event) OVERRIDE;
 
diff --git a/ui/aura/root_window_host_ozone.cc b/ui/aura/root_window_host_ozone.cc
index 28c8d0c..d3fe7c3 100644
--- a/ui/aura/root_window_host_ozone.cc
+++ b/ui/aura/root_window_host_ozone.cc
@@ -106,13 +106,6 @@
   NOTIMPLEMENTED();
 }
 
-bool RootWindowHostOzone::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                             const gfx::Point& dest_offset,
-                                             SkCanvas* canvas) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 void RootWindowHostOzone::PostNativeEvent(
     const base::NativeEvent& native_event) {
   NOTIMPLEMENTED();
diff --git a/ui/aura/root_window_host_ozone.h b/ui/aura/root_window_host_ozone.h
index 6acd1a2..f510d41 100644
--- a/ui/aura/root_window_host_ozone.h
+++ b/ui/aura/root_window_host_ozone.h
@@ -46,9 +46,6 @@
   virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
   virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) OVERRIDE;
   virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
   virtual void PrepareForShutdown() OVERRIDE;
diff --git a/ui/aura/root_window_host_win.cc b/ui/aura/root_window_host_win.cc
index 5c67b77..723de57 100644
--- a/ui/aura/root_window_host_win.cc
+++ b/ui/aura/root_window_host_win.cc
@@ -210,13 +210,6 @@
   return ClipCursor(&window_rect) != 0;
 }
 
-bool RootWindowHostWin::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                           const gfx::Point& dest_offset,
-                                           SkCanvas* canvas) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 void RootWindowHostWin::UnConfineCursor() {
   ClipCursor(NULL);
 }
diff --git a/ui/aura/root_window_host_win.h b/ui/aura/root_window_host_win.h
index 491ab90..e2a60dd 100644
--- a/ui/aura/root_window_host_win.h
+++ b/ui/aura/root_window_host_win.h
@@ -37,9 +37,6 @@
   virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
   virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) OVERRIDE;
   virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
   virtual void PrepareForShutdown() OVERRIDE;
diff --git a/ui/aura/root_window_host_x11.cc b/ui/aura/root_window_host_x11.cc
index f69a54a..783e960 100644
--- a/ui/aura/root_window_host_x11.cc
+++ b/ui/aura/root_window_host_x11.cc
@@ -25,9 +25,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkPostConfig.h"
 #include "ui/aura/client/capture_client.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/screen_position_client.h"
@@ -45,7 +42,6 @@
 #include "ui/base/x/x11_util.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/compositor/layer.h"
-#include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/screen.h"
 
 #if defined(OS_CHROMEOS)
@@ -819,51 +815,6 @@
   }
 }
 
-bool RootWindowHostX11::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                             const gfx::Point& dest_offset,
-                                             SkCanvas* canvas) {
-  ui::XScopedImage scoped_image(
-      XGetImage(xdisplay_, xwindow_,
-                source_bounds.x(), source_bounds.y(),
-                source_bounds.width(), source_bounds.height(),
-                AllPlanes, ZPixmap));
-  XImage* image = scoped_image.get();
-  if (!image) {
-    LOG(ERROR) << "XGetImage failed";
-    return false;
-  }
-
-  if (image->bits_per_pixel == 32) {
-    if ((0xff << SK_R32_SHIFT) != image->red_mask ||
-        (0xff << SK_G32_SHIFT) != image->green_mask ||
-        (0xff << SK_B32_SHIFT) != image->blue_mask) {
-      LOG(WARNING) << "XImage and Skia byte orders differ";
-      return false;
-    }
-
-    // Set the alpha channel before copying to the canvas.  Otherwise, areas of
-    // the framebuffer that were cleared by ply-image rather than being obscured
-    // by an image during boot may end up transparent.
-    // TODO(derat|marcheu): Remove this if/when ply-image has been updated to
-    // set the framebuffer's alpha channel regardless of whether the device
-    // claims to support alpha or not.
-    for (int i = 0; i < image->width * image->height * 4; i += 4)
-      image->data[i + 3] = 0xff;
-
-    SkBitmap bitmap;
-    bitmap.setConfig(SkBitmap::kARGB_8888_Config,
-                     image->width, image->height,
-                     image->bytes_per_line);
-    bitmap.setPixels(image->data);
-    canvas->drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), NULL);
-  } else {
-    NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel;
-    return false;
-  }
-
-  return true;
-}
-
 void RootWindowHostX11::PostNativeEvent(
     const base::NativeEvent& native_event) {
   DCHECK(xwindow_);
diff --git a/ui/aura/root_window_host_x11.h b/ui/aura/root_window_host_x11.h
index c38002d..ac9cc74 100644
--- a/ui/aura/root_window_host_x11.h
+++ b/ui/aura/root_window_host_x11.h
@@ -63,9 +63,6 @@
   virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
   virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) OVERRIDE;
   virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
   virtual void PrepareForShutdown() OVERRIDE;
diff --git a/ui/aura/root_window_unittest.cc b/ui/aura/root_window_unittest.cc
index 739de66..5eeb39a 100644
--- a/ui/aura/root_window_unittest.cc
+++ b/ui/aura/root_window_unittest.cc
@@ -882,4 +882,30 @@
   EXPECT_EQ(1, d2.gesture_end_count());
 }
 
+// Tests whether we can repost the Tap down gesture event.
+TEST_F(RootWindowTest, RepostTapdownGestureTest) {
+  EventFilterRecorder* filter = new EventFilterRecorder;
+  root_window()->SetEventFilter(filter);  // passes ownership
+
+  test::TestWindowDelegate delegate;
+  scoped_ptr<aura::Window> window(CreateTestWindowWithDelegate(
+      &delegate, 1, gfx::Rect(0, 0, 100, 100), root_window()));
+
+  ui::GestureEventDetails details(ui::ET_GESTURE_TAP_DOWN, 0.0f, 0.0f);
+  gfx::Point point(10, 10);
+  ui::GestureEvent event(
+      ui::ET_GESTURE_TAP_DOWN,
+      point.x(),
+      point.y(),
+      0,
+      ui::EventTimeForNow(),
+      details,
+      0);
+  root_window()->RepostEvent(event);
+  RunAllPendingInMessageLoop();
+  EXPECT_TRUE(EventTypesToString(filter->events()).find("GESTURE_TAP_DOWN") !=
+              std::string::npos);
+  filter->events().clear();
+}
+
 }  // namespace aura
diff --git a/ui/aura/test/test_cursor_client.cc b/ui/aura/test/test_cursor_client.cc
index b82abbf..463589f 100644
--- a/ui/aura/test/test_cursor_client.cc
+++ b/ui/aura/test/test_cursor_client.cc
@@ -12,6 +12,7 @@
 TestCursorClient::TestCursorClient(aura::Window* root_window)
     : visible_(true),
       mouse_events_enabled_(true),
+      cursor_lock_count_(0),
       root_window_(root_window) {
   client::SetCursorClient(root_window, this);
 }
@@ -58,9 +59,17 @@
 }
 
 void TestCursorClient::LockCursor() {
+  cursor_lock_count_++;
 }
 
 void TestCursorClient::UnlockCursor() {
+  cursor_lock_count_--;
+  if (cursor_lock_count_ < 0)
+    cursor_lock_count_ = 0;
+}
+
+bool TestCursorClient::IsCursorLocked() const {
+  return cursor_lock_count_ > 0;
 }
 
 void TestCursorClient::AddObserver(
diff --git a/ui/aura/test/test_cursor_client.h b/ui/aura/test/test_cursor_client.h
index 62ccf7f..850ff68 100644
--- a/ui/aura/test/test_cursor_client.h
+++ b/ui/aura/test/test_cursor_client.h
@@ -29,6 +29,7 @@
   virtual void SetDisplay(const gfx::Display& display) OVERRIDE;
   virtual void LockCursor() OVERRIDE;
   virtual void UnlockCursor() OVERRIDE;
+  virtual bool IsCursorLocked() const OVERRIDE;
   virtual void AddObserver(
       aura::client::CursorClientObserver* observer) OVERRIDE;
   virtual void RemoveObserver(
@@ -37,6 +38,7 @@
  private:
   bool visible_;
   bool mouse_events_enabled_;
+  int cursor_lock_count_;
   ObserverList<aura::client::CursorClientObserver> observers_;
   aura::Window* root_window_;
 
diff --git a/ui/base/accessibility/accessible_text_utils.cc b/ui/base/accessibility/accessible_text_utils.cc
index 72ab60e..5fab22e 100644
--- a/ui/base/accessibility/accessible_text_utils.cc
+++ b/ui/base/accessibility/accessible_text_utils.cc
@@ -9,7 +9,7 @@
 
 namespace ui {
 
-size_t FindAccessibleTextBoundary(const string16& text,
+size_t FindAccessibleTextBoundary(const base::string16& text,
                                   const std::vector<int>& line_breaks,
                                   TextBoundaryType boundary,
                                   size_t start_offset,
diff --git a/ui/base/accessibility/accessible_text_utils.h b/ui/base/accessibility/accessible_text_utils.h
index 479e719..a64088c 100644
--- a/ui/base/accessibility/accessible_text_utils.h
+++ b/ui/base/accessibility/accessible_text_utils.h
@@ -42,7 +42,7 @@
 // (depending on |direction|) from the given |start_offset| until the
 // given boundary is found, and return the offset of that boundary,
 // using the vector of line break character offsets in |line_breaks|.
-size_t UI_EXPORT FindAccessibleTextBoundary(const string16& text,
+size_t UI_EXPORT FindAccessibleTextBoundary(const base::string16& text,
                                             const std::vector<int>& line_breaks,
                                             TextBoundaryType boundary,
                                             size_t start_offset,
diff --git a/ui/base/accessibility/accessible_view_state.h b/ui/base/accessibility/accessible_view_state.h
index 1809025..9553d1c 100644
--- a/ui/base/accessibility/accessible_view_state.h
+++ b/ui/base/accessibility/accessible_view_state.h
@@ -33,16 +33,16 @@
   AccessibilityTypes::State state;
 
   // The view's name / label.
-  string16 name;
+  base::string16 name;
 
   // The view's value, for example the text content.
-  string16 value;
+  base::string16 value;
 
   // The name of the default action if the user clicks on this view.
-  string16 default_action;
+  base::string16 default_action;
 
   // The keyboard shortcut to activate this view, if any.
-  string16 keyboard_shortcut;
+  base::string16 keyboard_shortcut;
 
   // The selection start and end. Only applies to views with text content,
   // such as a text box or combo box; start and end should be -1 otherwise.
diff --git a/ui/base/clipboard/clipboard_aurax11.cc b/ui/base/clipboard/clipboard_aurax11.cc
index 287941d..e32961a 100644
--- a/ui/base/clipboard/clipboard_aurax11.cc
+++ b/ui/base/clipboard/clipboard_aurax11.cc
@@ -12,6 +12,7 @@
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/memory/ref_counted_memory.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_pump_aurax11.h"
@@ -25,7 +26,7 @@
 #include "ui/base/x/selection_utils.h"
 #include "ui/base/x/x11_atom_cache.h"
 #include "ui/base/x/x11_util.h"
-
+#include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/size.h"
 
 namespace ui {
@@ -33,7 +34,6 @@
 namespace {
 
 const char kClipboard[] = "CLIPBOARD";
-const char kMimeTypeBitmap[] = "image/bmp";
 const char kMimeTypeFilename[] = "chromium/filename";
 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
@@ -41,7 +41,7 @@
 
 const char* kAtomsToCache[] = {
   kClipboard,
-  kMimeTypeBitmap,
+  Clipboard::kMimeTypePNG,
   kMimeTypeFilename,
   kMimeTypeMozillaURL,
   kMimeTypeWebkitSmartPaste,
@@ -653,7 +653,16 @@
 
 SkBitmap Clipboard::ReadImage(Buffer buffer) const {
   DCHECK(CalledOnValidThread());
-  NOTIMPLEMENTED();
+
+  SelectionData data(aurax11_details_->RequestAndWaitForTypes(
+      buffer,
+      aurax11_details_->GetAtomsForFormat(GetBitmapFormatType())));
+  if (data.IsValid()) {
+    SkBitmap bitmap;
+    if (gfx::PNGCodec::Decode(data.GetData(), data.GetSize(), &bitmap))
+      return SkBitmap(bitmap);
+  }
+
   return SkBitmap();
 }
 
@@ -749,10 +758,21 @@
 }
 
 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
-  // TODO(erg): I'm not sure if we should be writting BMP data here or
-  // not. It's what the GTK port does, but I'm not sure it's the right thing to
-  // do.
-  NOTIMPLEMENTED();
+  const gfx::Size* size = reinterpret_cast<const gfx::Size*>(size_data);
+
+  // Adopt the pixels into a SkBitmap. Note that the pixel order in memory is
+  // actually BGRA.
+  SkBitmap bitmap;
+  bitmap.setConfig(SkBitmap::kARGB_8888_Config, size->width(), size->height());
+  bitmap.setPixels(const_cast<char*>(pixel_data));
+
+  // Encode the bitmap as a PNG for transport.
+  std::vector<unsigned char> output;
+  if (gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, false, &output)) {
+    aurax11_details_->InsertMapping(kMimeTypePNG,
+                                    base::RefCountedBytes::TakeVector(
+                                        &output));
+  }
 }
 
 void Clipboard::WriteData(const FormatType& format,
@@ -822,7 +842,7 @@
 
 // static
 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
-  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
+  CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePNG));
   return type;
 }
 
diff --git a/ui/base/clipboard/clipboard_unittest.cc b/ui/base/clipboard/clipboard_unittest.cc
index f131e0e..7fd111c 100644
--- a/ui/base/clipboard/clipboard_unittest.cc
+++ b/ui/base/clipboard/clipboard_unittest.cc
@@ -318,8 +318,6 @@
 #endif
 }
 
-// TODO(erg): Reenable this everywhere once linux_aura learns what bitmaps are.
-#if !(defined(USE_AURA) && !defined(OS_CHROMEOS))
 TEST_F(ClipboardTest, SharedBitmapTest) {
   unsigned int fake_bitmap[] = {
     0x46155189, 0xF6A55C8D, 0x79845674, 0xFA57BD89,
@@ -362,14 +360,11 @@
   EXPECT_TRUE(clipboard().IsFormatAvailable(Clipboard::GetBitmapFormatType(),
                                             Clipboard::BUFFER_STANDARD));
 }
-#endif
 
-// The following test somehow fails on GTK. The image when read back from the
-// clipboard has the alpha channel set to 0xFF for some reason. The other
-// channels stay intact. So I am turning this on only for aura.
-//
-// TODO(erg): This also crashes in linux_aura. Investigate once bitmap writing
-// is implemented.
+// The following test somehow fails on GTK and linux_aura. The image when read
+// back from the clipboard has the alpha channel set to 0xFF for some
+// reason. The other channels stay intact. So I am turning this on only for
+// aura.
 #if (defined(USE_AURA) && !(defined(OS_WIN) || !defined(OS_CHROMEOS))) || \
     defined(OS_ANDROID)
 TEST_F(ClipboardTest, MultipleBitmapReadWriteTest) {
diff --git a/ui/base/cocoa/menu_controller.mm b/ui/base/cocoa/menu_controller.mm
index 1179284..ebec346 100644
--- a/ui/base/cocoa/menu_controller.mm
+++ b/ui/base/cocoa/menu_controller.mm
@@ -12,6 +12,7 @@
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/text/text_elider.h"
+#include "ui/gfx/font.h"
 #include "ui/gfx/image/image.h"
 
 @interface MenuController (Private)
diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc b/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
index 52aa7c6..55841c7 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
+++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc
@@ -196,13 +196,14 @@
 
       std::vector<base::string16> tokens;
       size_t num_tokens = Tokenize(unparsed, ASCIIToUTF16("\n"), &tokens);
-      if (num_tokens >= 2) {
+      if (num_tokens > 0) {
+        if (num_tokens > 1)
+          *title = tokens[1];
+        else
+          *title = string16();
+
         *url = GURL(tokens[0]);
-        *title = tokens[1];
         return true;
-      } else {
-        NOTREACHED() << "Data that claimed to be a Mozilla URL has "
-                     << num_tokens << " tokens instead of 2.";
       }
     } else if (data.GetType() == atom_cache_.GetAtom(
                    Clipboard::kMimeTypeURIList)) {
diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc b/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
new file mode 100644
index 0000000..c3a944a
--- /dev/null
+++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc
@@ -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.
+
+#include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
+
+// Clean up X11 header polution
+#undef None
+#undef Bool
+
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+const char kGoogleTitle[] = "Google";
+const char kGoogleURL[] = "http://www.google.com/";
+
+TEST(OSExchangeDataProviderAuraX11Test, MozillaURL) {
+  base::MessageLoopForUI message_loop;
+  ui::OSExchangeDataProviderAuraX11 provider;
+
+  // Check that we can get titled entries.
+  provider.SetURL(GURL(kGoogleURL), ASCIIToUTF16(kGoogleTitle));
+  {
+    GURL out_gurl;
+    base::string16 out_str;
+    EXPECT_TRUE(provider.GetURLAndTitle(&out_gurl, &out_str));
+    EXPECT_EQ(ASCIIToUTF16(kGoogleTitle), out_str);
+    EXPECT_EQ(kGoogleURL, out_gurl.spec());
+  }
+
+  // Check that we can get non-titled entries.
+  provider.SetURL(GURL(kGoogleURL), string16());
+  {
+    GURL out_gurl;
+    base::string16 out_str;
+    EXPECT_TRUE(provider.GetURLAndTitle(&out_gurl, &out_str));
+    EXPECT_EQ(string16(), out_str);
+    EXPECT_EQ(kGoogleURL, out_gurl.spec());
+  }
+}
diff --git a/ui/base/events/event.h b/ui/base/events/event.h
index 193e6e6..bfe0a59 100644
--- a/ui/base/events/event.h
+++ b/ui/base/events/event.h
@@ -702,6 +702,10 @@
   // 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_;
 
@@ -710,8 +714,6 @@
   // This value is stored as a bitfield because the number of touch ids varies,
   // but we currently don't need more than 32 touches at a time.
   const unsigned int touch_ids_bitfield_;
-
-  DISALLOW_COPY_AND_ASSIGN(GestureEvent);
 };
 
 }  // namespace ui
diff --git a/ui/base/ime/ime_unittests.gypi b/ui/base/ime/ime_unittests.gypi
index 173e74c..10a087f 100644
--- a/ui/base/ime/ime_unittests.gypi
+++ b/ui/base/ime/ime_unittests.gypi
@@ -12,6 +12,7 @@
   'sources': [
     '<@(ime_test_files)',
     'win/imm32_manager_unittest.cc',
+    'win/tsf_input_scope_unittest.cc',
     'win/tsf_text_store_unittest.cc',
   ],
   'conditions': [
@@ -21,9 +22,8 @@
       ],
     }],
     ['OS!="win"', {
-      'sources!': [
-        'win/imm32_manager_unittest.cc',
-        'win/tsf_text_store_unittest.cc',
+      'sources/': [
+        ['exclude', '^win'],
       ],
     }],
   ],
diff --git a/ui/base/ime/input_method_ibus.h b/ui/base/ime/input_method_ibus.h
index 8580528..cdb273f 100644
--- a/ui/base/ime/input_method_ibus.h
+++ b/ui/base/ime/input_method_ibus.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/ibus/ibus_input_context_client.h"
+#include "chromeos/ime/ibus_bridge.h"
 #include "chromeos/ime/ibus_daemon_controller.h"
 #include "ui/base/ime/character_composer.h"
 #include "ui/base/ime/composition_text.h"
diff --git a/ui/base/ime/input_method_win.cc b/ui/base/ime/input_method_win.cc
index 4e3df39..21c3d06 100644
--- a/ui/base/ime/input_method_win.cc
+++ b/ui/base/ime/input_method_win.cc
@@ -148,6 +148,10 @@
   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].
diff --git a/ui/base/ime/win/tsf_input_scope.cc b/ui/base/ime/win/tsf_input_scope.cc
index cb6792e..06481e9 100644
--- a/ui/base/ime/win/tsf_input_scope.cc
+++ b/ui/base/ime/win/tsf_input_scope.cc
@@ -4,8 +4,7 @@
 
 #include "ui/base/ime/win/tsf_input_scope.h"
 
-#include <InputScope.h>
-#include <vector>
+#include <algorithm>
 
 #include "base/compiler_specific.h"
 #include "base/logging.h"
@@ -16,6 +15,20 @@
 namespace tsf_inputscope {
 namespace {
 
+void AppendNonTrivialInputScope(std::vector<InputScope>* input_scopes,
+                                InputScope input_scope) {
+  DCHECK(input_scopes);
+
+  if (input_scope == IS_DEFAULT)
+    return;
+
+  if (std::find(input_scopes->begin(), input_scopes->end(), input_scope) !=
+      input_scopes->end())
+    return;
+
+  input_scopes->push_back(input_scope);
+}
+
 class TSFInputScope : public ITfInputScope {
  public:
   explicit TSFInputScope(const std::vector<InputScope>& input_scopes)
@@ -145,11 +158,6 @@
 
 InputScope ConvertTextInputModeToInputScope(TextInputMode text_input_mode) {
   switch (text_input_mode) {
-    case TEXT_INPUT_MODE_VERBATIM:
-    case TEXT_INPUT_MODE_LATIN:
-    case TEXT_INPUT_MODE_LATIN_NAME:
-    case TEXT_INPUT_MODE_LATIN_PROSE:
-      return IS_ALPHANUMERIC_HALFWIDTH;
     case TEXT_INPUT_MODE_FULL_WIDTH_LATIN:
       return IS_ALPHANUMERIC_FULLWIDTH;
     case TEXT_INPUT_MODE_KANA:
@@ -171,10 +179,24 @@
 
 }  // namespace
 
-ITfInputScope* CreateInputScope(TextInputType text_input_type) {
-  std::vector<InputScope> input_scopes(1);
-  input_scopes.push_back(ConvertTextInputTypeToInputScope(text_input_type));
-  return new TSFInputScope(input_scopes);
+std::vector<InputScope> GetInputScopes(TextInputType text_input_type,
+                                       TextInputMode text_input_mode) {
+  std::vector<InputScope> input_scopes;
+
+  AppendNonTrivialInputScope(&input_scopes,
+                             ConvertTextInputTypeToInputScope(text_input_type));
+  AppendNonTrivialInputScope(&input_scopes,
+                             ConvertTextInputModeToInputScope(text_input_mode));
+
+  if (input_scopes.empty())
+    input_scopes.push_back(IS_DEFAULT);
+
+  return input_scopes;
+}
+
+ITfInputScope* CreateInputScope(TextInputType text_input_type,
+                                TextInputMode text_input_mode) {
+  return new TSFInputScope(GetInputScopes(text_input_type, text_input_mode));
 }
 
 void SetInputScopeForTsfUnawareWindow(
@@ -185,14 +207,10 @@
   if (!set_input_scopes)
     return;
 
-  InputScope input_scopes[] = {
-      ConvertTextInputTypeToInputScope(text_input_type),
-      ConvertTextInputModeToInputScope(text_input_mode),
-  };
-
-  set_input_scopes(window_handle, input_scopes,
-                   (input_scopes[0] == input_scopes[1] ? 1 : 2), NULL, 0, NULL,
-                   NULL);
+  std::vector<InputScope> input_scopes = GetInputScopes(text_input_type,
+                                                        text_input_mode);
+  set_input_scopes(window_handle, &input_scopes[0], input_scopes.size(), NULL,
+                   0, NULL, NULL);
 }
 
 }  // namespace tsf_inputscope
diff --git a/ui/base/ime/win/tsf_input_scope.h b/ui/base/ime/win/tsf_input_scope.h
index 24ac94c..2e5856c 100644
--- a/ui/base/ime/win/tsf_input_scope.h
+++ b/ui/base/ime/win/tsf_input_scope.h
@@ -5,24 +5,32 @@
 #ifndef UI_BASE_IME_WIN_TSF_INPUT_SCOPE_H_
 #define UI_BASE_IME_WIN_TSF_INPUT_SCOPE_H_
 
+#include <InputScope.h>
 #include <Windows.h>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "ui/base/ime/text_input_mode.h"
 #include "ui/base/ime/text_input_type.h"
 #include "ui/base/ui_export.h"
 
-struct ITfInputScope;
-
 namespace ui {
 namespace tsf_inputscope {
 
+// Returns InputScope list corresoponding to ui::TextInputType and
+// ui::TextInputMode.
+// This function is only used from following functions but declared for test.
+UI_EXPORT std::vector<InputScope> GetInputScopes(TextInputType text_input_type,
+                                                 TextInputMode text_input_mode);
+
 // Returns an instance of ITfInputScope, which is the Windows-specific
-// category representation corresponding to ui::TextInputType that we are
-// using to specify the expected text type in the target field.
+// category representation corresponding to ui::TextInputType and
+// ui::TextInputMode that we are using to specify the expected text type
+// in the target field.
 // The returned instance has 0 reference count. The caller must maintain its
 // reference count.
-UI_EXPORT ITfInputScope* CreateInputScope(TextInputType text_input_type);
+UI_EXPORT ITfInputScope* CreateInputScope(TextInputType text_input_type,
+                                          TextInputMode text_input_mode);
 
 // A wrapper of the SetInputScopes API exported by msctf.dll.
 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms629026.aspx
diff --git a/ui/base/ime/win/tsf_input_scope_unittest.cc b/ui/base/ime/win/tsf_input_scope_unittest.cc
new file mode 100644
index 0000000..de6ede1
--- /dev/null
+++ b/ui/base/ime/win/tsf_input_scope_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 "ui/base/ime/win/tsf_input_scope.h"
+
+#include <InputScope.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+namespace {
+
+struct GetInputScopesTestCase {
+  TextInputType input_type;
+  TextInputMode input_mode;
+  size_t expected_size;
+  InputScope expected_input_scopes[2];
+};
+
+// Google Test pretty-printer.
+void PrintTo(const GetInputScopesTestCase& data, std::ostream* os) {
+  *os << " input_type: " << testing::PrintToString(data.input_type)
+      << "; input_mode: " << testing::PrintToString(data.input_mode);
+}
+
+class TSFInputScopeTest
+    : public testing::TestWithParam<GetInputScopesTestCase> {
+};
+
+const GetInputScopesTestCase kGetInputScopesTestCases[] = {
+  // Test cases of TextInputType.
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_TEXT, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_PASSWORD, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_PASSWORD}},
+  {TEXT_INPUT_TYPE_SEARCH, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_SEARCH}},
+  {TEXT_INPUT_TYPE_EMAIL, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_EMAIL_SMTPEMAILADDRESS}},
+  {TEXT_INPUT_TYPE_NUMBER, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_NUMBER}},
+  {TEXT_INPUT_TYPE_TELEPHONE, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_TELEPHONE_FULLTELEPHONENUMBER}},
+  {TEXT_INPUT_TYPE_URL, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_URL}},
+  {TEXT_INPUT_TYPE_DATE, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_DATE_TIME, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_DATE_TIME_LOCAL, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_MONTH, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_TIME, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_WEEK, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_TEXT_AREA, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_CONTENT_EDITABLE, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_DATE_TIME_FIELD, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  // Test cases of TextInputMode.
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_DEFAULT,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_VERBATIM,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_LATIN,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_LATIN_NAME,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_LATIN_PROSE,
+   1, {IS_DEFAULT}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_FULL_WIDTH_LATIN,
+   1, {IS_ALPHANUMERIC_FULLWIDTH}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_KANA,
+   1, {IS_HIRAGANA}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_KATAKANA,
+   1, {IS_KATAKANA_FULLWIDTH}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_NUMERIC,
+   1, {IS_NUMBER}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_TEL,
+   1, {IS_TELEPHONE_FULLTELEPHONENUMBER}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_EMAIL,
+   1, {IS_EMAIL_SMTPEMAILADDRESS}},
+  {TEXT_INPUT_TYPE_NONE, TEXT_INPUT_MODE_URL,
+   1, {IS_URL}},
+   // Mixed test cases.
+  {TEXT_INPUT_TYPE_SEARCH, TEXT_INPUT_MODE_KANA,
+   2, {IS_SEARCH, IS_HIRAGANA}},
+  {TEXT_INPUT_TYPE_EMAIL, TEXT_INPUT_MODE_EMAIL,
+   1, {IS_EMAIL_SMTPEMAILADDRESS}},
+  {TEXT_INPUT_TYPE_NUMBER, TEXT_INPUT_MODE_NUMERIC,
+   1, {IS_NUMBER}},
+  {TEXT_INPUT_TYPE_TELEPHONE, TEXT_INPUT_MODE_TEL,
+   1, {IS_TELEPHONE_FULLTELEPHONENUMBER}},
+  {TEXT_INPUT_TYPE_URL, TEXT_INPUT_MODE_URL,
+   1, {IS_URL}},
+};
+
+TEST_P(TSFInputScopeTest, GetInputScopes) {
+  const GetInputScopesTestCase& test_case = GetParam();
+
+  std::vector<InputScope> input_scopes = tsf_inputscope::GetInputScopes(
+      test_case.input_type, test_case.input_mode);
+
+  EXPECT_EQ(test_case.expected_size, input_scopes.size());
+  for (size_t i = 0; i < test_case.expected_size; ++i)
+    EXPECT_EQ(test_case.expected_input_scopes[i], input_scopes[i]);
+}
+
+INSTANTIATE_TEST_CASE_P(,
+                        TSFInputScopeTest,
+                        ::testing::ValuesIn(kGetInputScopesTestCases));
+
+}  // namespace
+}  // namespace ui
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index 40f02bf..27739ad 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -610,7 +610,7 @@
   attribute_buffer[0].idAttr = GUID_PROP_INPUTSCOPE;
   attribute_buffer[0].varValue.vt = VT_UNKNOWN;
   attribute_buffer[0].varValue.punkVal = tsf_inputscope::CreateInputScope(
-      text_input_client_->GetTextInputType());
+      text_input_client_->GetTextInputType(), TEXT_INPUT_MODE_DEFAULT);
   attribute_buffer[0].varValue.punkVal->AddRef();
   *attribute_buffer_copied = 1;
   return S_OK;
diff --git a/ui/base/layout.cc b/ui/base/layout.cc
index 024948c..d384301 100644
--- a/ui/base/layout.cc
+++ b/ui/base/layout.cc
@@ -66,7 +66,8 @@
 }
 #endif  // defined(OS_WIN)
 
-const float kScaleFactorScales[] = {1.0f, 1.0f, 1.33f, 1.4f, 1.5f, 1.8f, 2.0f};
+const float kScaleFactorScales[] = {1.0f, 1.0f, 1.25f, 1.33f, 1.4f, 1.5f, 1.8f,
+                                    2.0f};
 COMPILE_ASSERT(NUM_SCALE_FACTORS == arraysize(kScaleFactorScales),
                kScaleFactorScales_incorrect_size);
 const size_t kScaleFactorScalesLength = arraysize(kScaleFactorScales);
diff --git a/ui/base/layout.h b/ui/base/layout.h
index 236e58e..1292c38 100644
--- a/ui/base/layout.h
+++ b/ui/base/layout.h
@@ -36,6 +36,7 @@
 enum ScaleFactor {
   SCALE_FACTOR_NONE = 0,
   SCALE_FACTOR_100P,
+  SCALE_FACTOR_125P,
   SCALE_FACTOR_133P,
   SCALE_FACTOR_140P,
   SCALE_FACTOR_150P,
diff --git a/ui/base/layout_unittest.cc b/ui/base/layout_unittest.cc
index a230d5a..8a74182 100644
--- a/ui/base/layout_unittest.cc
+++ b/ui/base/layout_unittest.cc
@@ -15,6 +15,7 @@
 
 TEST(LayoutTest, GetScaleFactorScale) {
   EXPECT_FLOAT_EQ(1.0f, GetScaleFactorScale(SCALE_FACTOR_100P));
+  EXPECT_FLOAT_EQ(1.25f, GetScaleFactorScale(SCALE_FACTOR_125P));
   EXPECT_FLOAT_EQ(1.33f, GetScaleFactorScale(SCALE_FACTOR_133P));
   EXPECT_FLOAT_EQ(1.4f, GetScaleFactorScale(SCALE_FACTOR_140P));
   EXPECT_FLOAT_EQ(1.5f, GetScaleFactorScale(SCALE_FACTOR_150P));
@@ -47,8 +48,9 @@
   EXPECT_EQ(SCALE_FACTOR_100P, GetScaleFactorFromScale(0.1f));
   EXPECT_EQ(SCALE_FACTOR_100P, GetScaleFactorFromScale(0.9f));
   EXPECT_EQ(SCALE_FACTOR_100P, GetScaleFactorFromScale(1.0f));
-  EXPECT_EQ(SCALE_FACTOR_133P, GetScaleFactorFromScale(1.19f));
-  EXPECT_EQ(SCALE_FACTOR_133P, GetScaleFactorFromScale(1.21f));
+  EXPECT_EQ(SCALE_FACTOR_125P, GetScaleFactorFromScale(1.19f));
+  EXPECT_EQ(SCALE_FACTOR_125P, GetScaleFactorFromScale(1.21f));
+  EXPECT_EQ(SCALE_FACTOR_133P, GetScaleFactorFromScale(1.291f));
   EXPECT_EQ(SCALE_FACTOR_133P, GetScaleFactorFromScale(1.3f));
   EXPECT_EQ(SCALE_FACTOR_140P, GetScaleFactorFromScale(1.4f));
   EXPECT_EQ(SCALE_FACTOR_150P, GetScaleFactorFromScale(1.59f));
diff --git a/ui/base/ozone/evdev/touch_event_converter_ozone.cc b/ui/base/ozone/evdev/touch_event_converter_ozone.cc
index 0e4f560..148ed72 100644
--- a/ui/base/ozone/evdev/touch_event_converter_ozone.cc
+++ b/ui/base/ozone/evdev/touch_event_converter_ozone.cc
@@ -11,6 +11,7 @@
 #include <unistd.h>
 
 #include <cmath>
+#include <limits>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -36,6 +37,8 @@
       pressure_max_(0),
       x_scale_(1.),
       y_scale_(1.),
+      x_max_(std::numeric_limits<int>::max()),
+      y_max_(std::numeric_limits<int>::max()),
       current_slot_(0),
       fd_(fd),
       id_(id) {
@@ -83,6 +86,8 @@
     if (sc == 2) {
       x_scale_ = (double)screen_width / (x_max - x_min);
       y_scale_ = (double)screen_height / (y_max - y_min);
+      x_max_ = screen_width - 1;
+      y_max_ = screen_height - 1;
       LOG(INFO) << "touch input x_scale=" << x_scale_
                 << " y_scale=" << y_scale_;
     } else {
@@ -151,7 +156,8 @@
               // TODO(rjkroege): Support elliptical finger regions.
               scoped_ptr<TouchEvent> tev(new TouchEvent(
                   events_[j].type_,
-                  gfx::Point(events_[j].x_, events_[j].y_),
+                  gfx::Point(std::min(x_max_, events_[j].x_),
+                             std::min(y_max_, events_[j].y_)),
                   /* flags */ 0,
                   /* touch_id */ j,
                   base::TimeDelta::FromMicroseconds(
@@ -160,8 +166,11 @@
                   events_[j].pressure_ * kFingerWidth,
                   /* angle */ 0.,
                   events_[j].pressure_));
-              events_[j].type_ = ET_TOUCH_MOVED;
               DispatchEvent(tev.PassAs<ui::Event>());
+
+              // Subsequent events for this finger will be touch-move until it
+              // is released.
+              events_[j].type_ = ET_TOUCH_MOVED;
             }
           }
           altered_slots_.reset();
diff --git a/ui/base/ozone/evdev/touch_event_converter_ozone.h b/ui/base/ozone/evdev/touch_event_converter_ozone.h
index ef96be4..24be78e 100644
--- a/ui/base/ozone/evdev/touch_event_converter_ozone.h
+++ b/ui/base/ozone/evdev/touch_event_converter_ozone.h
@@ -42,6 +42,10 @@
   float x_scale_;
   float y_scale_;
 
+  // Maximum coordinate-values allowed for the events.
+  int x_max_;
+  int y_max_;
+
   // Touch point currently being updated from the /dev/input/event* stream.
   int current_slot_;
 
diff --git a/ui/base/ozone/surface_factory_ozone.cc b/ui/base/ozone/surface_factory_ozone.cc
index f082e7d..7d8d64b 100644
--- a/ui/base/ozone/surface_factory_ozone.cc
+++ b/ui/base/ozone/surface_factory_ozone.cc
@@ -57,6 +57,10 @@
   return  "720x1280*2";
 }
 
+gfx::Screen* SurfaceFactoryOzone::CreateDesktopScreen() {
+  return NULL;
+}
+
 // static
 SurfaceFactoryOzone* SurfaceFactoryOzone::CreateTestHelper() {
   return new SurfaceFactoryOzoneStub;
diff --git a/ui/base/ozone/surface_factory_ozone.h b/ui/base/ozone/surface_factory_ozone.h
index 50a9b4b..5df6bd9 100644
--- a/ui/base/ozone/surface_factory_ozone.h
+++ b/ui/base/ozone/surface_factory_ozone.h
@@ -10,25 +10,30 @@
 #include "ui/gfx/rect.h"
 
 namespace gfx {
+class Screen;
 class VSyncProvider;
 } //  namespace gfx
 
 namespace ui {
 
-class SurfaceFactoryOzone {
+class UI_EXPORT SurfaceFactoryOzone {
  public:
   SurfaceFactoryOzone();
   virtual ~SurfaceFactoryOzone();
 
   // Returns the instance
-  UI_EXPORT static SurfaceFactoryOzone* GetInstance();
+  static SurfaceFactoryOzone* GetInstance();
 
   // Returns a display spec as in |CreateDisplayFromSpec| for the default
   // native surface.
   virtual const char* DefaultDisplaySpec();
 
   // Sets the implementation delegate. Ownership is retained by the caller.
-  UI_EXPORT static void SetInstance(SurfaceFactoryOzone* impl);
+  static void SetInstance(SurfaceFactoryOzone* impl);
+
+  // TODO(rjkroege): decide how to separate screen/display stuff from SFOz
+  // This method implements gfx::Screen, particularly useful in Desktop Aura.
+  virtual gfx::Screen* CreateDesktopScreen();
 
   // TODO(rjkroege): Add a status code if necessary.
   // Configures the display hardware. Must be called from within the GPU
@@ -68,7 +73,7 @@
   virtual gfx::VSyncProvider* GetVSyncProvider(gfx::AcceleratedWidget w) = 0;
 
   // Create a default SufaceFactoryOzone implementation useful for tests.
-  UI_EXPORT static SurfaceFactoryOzone* CreateTestHelper();
+  static SurfaceFactoryOzone* CreateTestHelper();
 
  private:
   static SurfaceFactoryOzone* impl_; // not owned
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc
index 70623c2..893d5f4 100644
--- a/ui/base/resource/resource_bundle.cc
+++ b/ui/base/resource/resource_bundle.cc
@@ -321,7 +321,7 @@
     image = delegate_->GetImageNamed(resource_id);
 
   if (image.IsEmpty()) {
-    DCHECK(!delegate_ && !data_packs_.empty()) <<
+    DCHECK(!data_packs_.empty()) <<
         "Missing call to SetResourcesDataDLL?";
 
     // TODO(oshima): Consider reading the image size from png IHDR chunk and
diff --git a/ui/base/resource/resource_bundle_android.cc b/ui/base/resource/resource_bundle_android.cc
index c701a29..b194269 100644
--- a/ui/base/resource/resource_bundle_android.cc
+++ b/ui/base/resource/resource_bundle_android.cc
@@ -19,8 +19,6 @@
 void ResourceBundle::LoadCommonResources() {
   base::FilePath path;
   PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &path);
-  AddDataPackFromPath(path.AppendASCII("chrome.pak"),
-                      SCALE_FACTOR_NONE);
   AddDataPackFromPath(path.AppendASCII("chrome_100_percent.pak"),
                       SCALE_FACTOR_100P);
 }
diff --git a/ui/base/resource/resource_bundle_auralinux.cc b/ui/base/resource/resource_bundle_auralinux.cc
index 4bc7ee6..d535717 100644
--- a/ui/base/resource/resource_bundle_auralinux.cc
+++ b/ui/base/resource/resource_bundle_auralinux.cc
@@ -33,9 +33,6 @@
   // Always load the 1x data pack first as the 2x data pack contains both 1x and
   // 2x images. The 1x data pack only has 1x images, thus passes in an accurate
   // scale factor to gfx::ImageSkia::AddRepresentation.
-
-  AddDataPackFromPath(GetResourcesPakFilePath("chrome.pak"),
-                      SCALE_FACTOR_NONE);
   AddDataPackFromPath(GetResourcesPakFilePath(
       "chrome_100_percent.pak"), SCALE_FACTOR_100P);
 
diff --git a/ui/base/resource/resource_bundle_gtk.cc b/ui/base/resource/resource_bundle_gtk.cc
index 4d16b61..679b85c 100644
--- a/ui/base/resource/resource_bundle_gtk.cc
+++ b/ui/base/resource/resource_bundle_gtk.cc
@@ -65,8 +65,6 @@
 }  // namespace
 
 void ResourceBundle::LoadCommonResources() {
-  AddDataPackFromPath(GetResourcesPakFilePath("chrome.pak"),
-                      SCALE_FACTOR_NONE);
   AddDataPackFromPath(GetResourcesPakFilePath(
                       "chrome_100_percent.pak"),
                       SCALE_FACTOR_100P);
diff --git a/ui/base/resource/resource_bundle_mac.mm b/ui/base/resource/resource_bundle_mac.mm
index 5de8ecc..56d16d5 100644
--- a/ui/base/resource/resource_bundle_mac.mm
+++ b/ui/base/resource/resource_bundle_mac.mm
@@ -49,8 +49,6 @@
 }  // namespace
 
 void ResourceBundle::LoadCommonResources() {
-  AddDataPackFromPath(GetResourcesPakFilePath(@"chrome", nil),
-                      SCALE_FACTOR_NONE);
   AddDataPackFromPath(GetResourcesPakFilePath(@"chrome_100_percent",
                         nil), SCALE_FACTOR_100P);
   AddDataPackFromPath(GetResourcesPakFilePath(@"webkit_resources_100_percent",
diff --git a/ui/base/strings/app_locale_settings.grd b/ui/base/strings/app_locale_settings.grd
index 2b862d5..eb64af3 100644
--- a/ui/base/strings/app_locale_settings.grd
+++ b/ui/base/strings/app_locale_settings.grd
@@ -75,11 +75,11 @@
          be 'nb'. -->
     <output filename="app_locale_settings_nb.pak" type="data_package" lang="no" />
     <output filename="app_locale_settings_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="app_locale_settings_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="app_locale_settings_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="app_locale_settings_pt-PT.pak" type="data_package" lang="pt-PT" />
@@ -212,7 +212,7 @@
           75%
         </message>
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <!-- The font used in Web UI (e.g. History). -->
         <message name="IDS_WEB_FONT_FAMILY" use_name_for_id="true">
           'Lucida Grande', sans-serif
diff --git a/ui/base/strings/app_locale_settings_ja.xtb b/ui/base/strings/app_locale_settings_ja.xtb
index 9edc4a1..1e843b0 100644
--- a/ui/base/strings/app_locale_settings_ja.xtb
+++ b/ui/base/strings/app_locale_settings_ja.xtb
@@ -7,7 +7,7 @@
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,Meiryo,'MS PGothic',sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,Meiryo,'MS PGothic',sans-serif</translation>
 </if>
-<if expr="is_macosx">
+<if expr="is_macosx or is_ios">
   <translation id="IDS_WEB_FONT_FAMILY">Helvetica,Hiragino Kaku Gothic Pro,sans-serif</translation>
 </if>
 <if expr="is_linux and not pp_ifdef('chromeos')">
diff --git a/ui/base/strings/app_locale_settings_ko.xtb b/ui/base/strings/app_locale_settings_ko.xtb
index 9d7f042..e1db12e 100644
--- a/ui/base/strings/app_locale_settings_ko.xtb
+++ b/ui/base/strings/app_locale_settings_ko.xtb
@@ -7,7 +7,7 @@
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Malgun Gothic',Gulim,sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Malgun Gothic',Gulim,sans-serif</translation>
 </if>
-<if expr="is_macosx">
+<if expr="is_macosx or is_ios">
   <translation id="IDS_WEB_FONT_FAMILY">Helvetica,AppleGothic,sans-serif</translation>
 </if>
 <if expr="is_linux and not pp_ifdef('chromeos')">
diff --git a/ui/base/strings/app_locale_settings_zh-CN.xtb b/ui/base/strings/app_locale_settings_zh-CN.xtb
index 6b4c700..e67b6c1 100644
--- a/ui/base/strings/app_locale_settings_zh-CN.xtb
+++ b/ui/base/strings/app_locale_settings_zh-CN.xtb
@@ -7,7 +7,7 @@
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Yahei',Simsun,sans-serif</translation>
 </if>
-<if expr="is_macosx">
+<if expr="is_macosx or is_ios">
   <translation id="IDS_WEB_FONT_FAMILY">Helvetica,STHeiti,sans-serif</translation>
 </if>
 <if expr="pp_ifdef('chromeos') and pp_ifdef('_google_chrome')">
diff --git a/ui/base/strings/app_locale_settings_zh-TW.xtb b/ui/base/strings/app_locale_settings_zh-TW.xtb
index 14ae8b0..2492fbc 100644
--- a/ui/base/strings/app_locale_settings_zh-TW.xtb
+++ b/ui/base/strings/app_locale_settings_zh-TW.xtb
@@ -7,7 +7,7 @@
   <translation id="IDS_WEB_FONT_FAMILY">'Segoe UI',Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
   <translation id="IDS_WEB_FONT_FAMILY_XP">Arial,'Microsoft Jhenghei',PMingLiu,sans-serif</translation>
 </if>
-<if expr="is_macosx">
+<if expr="is_macosx or is_ios">
   <translation id="IDS_WEB_FONT_FAMILY">Helvetica,LiHei Pro,sans-serif</translation>
 </if>
 <if expr="pp_ifdef('chromeos') and pp_ifdef('_google_chrome')">
diff --git a/ui/base/strings/ui_strings.grd b/ui/base/strings/ui_strings.grd
index ec198ad..fd4eb5a 100644
--- a/ui/base/strings/ui_strings.grd
+++ b/ui/base/strings/ui_strings.grd
@@ -86,11 +86,11 @@
          be 'nb'. -->
     <output filename="ui_strings_nb.pak" type="data_package" lang="no" />
     <output filename="ui_strings_pl.pak" type="data_package" lang="pl" />
-    <if expr="pp_ifdef('ios')">
+    <if expr="is_ios">
       <!-- iOS uses pt for pt-BR -->
       <output filename="ui_strings_pt.pak" type="data_package" lang="pt-BR" />
     </if>
-    <if expr="not pp_ifdef('ios')">
+    <if expr="not is_ios">
       <output filename="ui_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
     </if>
     <output filename="ui_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
diff --git a/ui/base/strings/ui_strings_fr.xtb b/ui/base/strings/ui_strings_fr.xtb
index ffff784..3c88329 100644
--- a/ui/base/strings/ui_strings_fr.xtb
+++ b/ui/base/strings/ui_strings_fr.xtb
@@ -61,7 +61,7 @@
 <translation id="7907591526440419938">Ouvrir le fichier</translation>
 <translation id="1293699935367580298">Échap</translation>
 <translation id="815598010540052116">Défilement vers le bas</translation>
-<translation id="3157931365184549694">Rétablir</translation>
+<translation id="3157931365184549694">Restaurer</translation>
 <translation id="8179976553408161302">Entrer</translation>
 <translation id="945522503751344254">Envoyer le commentaire</translation>
 <translation id="9170848237812810038">Ann&amp;uler</translation>
diff --git a/ui/base/strings/ui_strings_id.xtb b/ui/base/strings/ui_strings_id.xtb
index aac085b..6aa52b2 100644
--- a/ui/base/strings/ui_strings_id.xtb
+++ b/ui/base/strings/ui_strings_id.xtb
@@ -61,7 +61,7 @@
 <translation id="7907591526440419938">Buka File</translation>
 <translation id="1293699935367580298">Esc</translation>
 <translation id="815598010540052116">Gulir ke Bawah</translation>
-<translation id="3157931365184549694">Kembalikan</translation>
+<translation id="3157931365184549694">Pulihkan</translation>
 <translation id="8179976553408161302">Masuk</translation>
 <translation id="945522503751344254">Kirim masukan</translation>
 <translation id="9170848237812810038">&amp;Urung</translation>
diff --git a/ui/base/strings/ui_strings_ja.xtb b/ui/base/strings/ui_strings_ja.xtb
index ee86eed..8ae0b03 100644
--- a/ui/base/strings/ui_strings_ja.xtb
+++ b/ui/base/strings/ui_strings_ja.xtb
@@ -23,7 +23,7 @@
 <translation id="7460907917090416791"><ph name="QUANTITY"/> TB</translation>
 <translation id="4999762576397546063">Ctrl+<ph name="KEY_COMBO_NAME"/></translation>
 <translation id="3234408098842461169">下矢印キー</translation>
-<translation id="3087734570205094154">一番下</translation>
+<translation id="3087734570205094154">下</translation>
 <translation id="1860796786778352021">通知を閉じる</translation>
 <translation id="6364916375976753737">左にスクロール</translation>
 <translation id="6945221475159498467">選択</translation>
diff --git a/ui/base/strings/ui_strings_ml.xtb b/ui/base/strings/ui_strings_ml.xtb
index 1591833..897419d 100644
--- a/ui/base/strings/ui_strings_ml.xtb
+++ b/ui/base/strings/ui_strings_ml.xtb
@@ -61,7 +61,7 @@
 <translation id="7907591526440419938">ഫയല്‍ തുറക്കുക</translation>
 <translation id="1293699935367580298">Esc</translation>
 <translation id="815598010540052116">താഴേക്ക് സ്ക്രോള്‍ചെയ്യൂ</translation>
-<translation id="3157931365184549694">പുനസ്ഥാപിക്കുക</translation>
+<translation id="3157931365184549694">പുനഃസ്ഥാപിക്കുക</translation>
 <translation id="8179976553408161302">നൽകുക</translation>
 <translation id="945522503751344254">ഫീഡ്ബാക്ക് അയയ്ക്കുക</translation>
 <translation id="9170848237812810038">‍&amp;പൂര്‍വാവസ്ഥയിലാക്കുക</translation>
diff --git a/ui/base/strings/ui_strings_sw.xtb b/ui/base/strings/ui_strings_sw.xtb
index 13ad5d0..299f3c2 100644
--- a/ui/base/strings/ui_strings_sw.xtb
+++ b/ui/base/strings/ui_strings_sw.xtb
@@ -25,7 +25,7 @@
 <translation id="3234408098842461169">Mshale Chini</translation>
 <translation id="3087734570205094154">Chini</translation>
 <translation id="1860796786778352021">Funga arifa</translation>
-<translation id="6364916375976753737">Vingirisha Kushoto</translation>
+<translation id="6364916375976753737">Sogeza Kushoto</translation>
 <translation id="6945221475159498467">Chagua</translation>
 <translation id="6620110761915583480">Hifadhi Faili</translation>
 <translation id="8210608804940886430">Ukurasa mmoja chini</translation>
@@ -47,20 +47,20 @@
 <translation id="2168039046890040389">Ukurasa mmoja juu</translation>
 <translation id="4927753642311223124">Hakuna cha kuangalia hapa, endelea.</translation>
 <translation id="2482878487686419369">Arifa</translation>
-<translation id="3183922693828471536">Vingirisha Hadi Hapa</translation>
+<translation id="3183922693828471536">Sogeza Hadi Hapa</translation>
 <translation id="4552416320897244156">PgDwn</translation>
 <translation id="7052633198403197513">F1</translation>
 <translation id="8677655579646609597"><ph name="QUANTITY"/> KB/s</translation>
 <translation id="7960078400008666149">Usinisumbue kwa saa moja</translation>
 <translation id="2190355936436201913">(tupu)</translation>
 <translation id="8447116497070723931">PgUp</translation>
-<translation id="4588090240171750605">Vingirisha Kulia</translation>
+<translation id="4588090240171750605">Sogeza Kulia</translation>
 <translation id="2666092431469916601">Ya Juu</translation>
-<translation id="8331626408530291785">Vingirisha Juu</translation>
+<translation id="8331626408530291785">Sogeza Juu</translation>
 <translation id="4773379706300191099">Zima arifa kutoka <ph name="EXTENSION_NAME"/></translation>
 <translation id="7907591526440419938">Fungua Faili</translation>
 <translation id="1293699935367580298">Esc</translation>
-<translation id="815598010540052116">Vingirisha Chini</translation>
+<translation id="815598010540052116">Sogeza Chini</translation>
 <translation id="3157931365184549694">Rejesha</translation>
 <translation id="8179976553408161302">Enter</translation>
 <translation id="945522503751344254">Tuma maoni</translation>
diff --git a/ui/base/strings/ui_strings_th.xtb b/ui/base/strings/ui_strings_th.xtb
index cc153f2..9429be6 100644
--- a/ui/base/strings/ui_strings_th.xtb
+++ b/ui/base/strings/ui_strings_th.xtb
@@ -61,7 +61,7 @@
 <translation id="7907591526440419938">เปิดไฟล์</translation>
 <translation id="1293699935367580298">Esc</translation>
 <translation id="815598010540052116">เลื่อนลง</translation>
-<translation id="3157931365184549694">คืนสภาพ</translation>
+<translation id="3157931365184549694">คืนค่า</translation>
 <translation id="8179976553408161302">เข้าใช้</translation>
 <translation id="945522503751344254">ส่งความคิดเห็น</translation>
 <translation id="9170848237812810038">เ&amp;ลิกทำ</translation>
diff --git a/ui/base/test/ui_cocoa_test_helper.mm b/ui/base/test/ui_cocoa_test_helper.mm
index 478aa31..a33228f 100644
--- a/ui/base/test/ui_cocoa_test_helper.mm
+++ b/ui/base/test/ui_cocoa_test_helper.mm
@@ -6,6 +6,7 @@
 
 #include "base/debug/debugger.h"
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "base/test/test_timeouts.h"
 
 @implementation CocoaTestHelperWindow
@@ -179,10 +180,8 @@
 
 std::set<NSWindow*> CocoaTest::WindowsLeft() {
   const std::set<NSWindow*> windows(ApplicationWindows());
-  std::set<NSWindow*> windows_left;
-  std::set_difference(windows.begin(), windows.end(),
-                      initial_windows_.begin(), initial_windows_.end(),
-                      std::inserter(windows_left, windows_left.begin()));
+  std::set<NSWindow*> windows_left =
+      base::STLSetDifference<std::set<NSWindow*> >(windows, initial_windows_);
   return windows_left;
 }
 
diff --git a/ui/base/text/text_elider.cc b/ui/base/text/text_elider.cc
index 0590981..76dbb71 100644
--- a/ui/base/text/text_elider.cc
+++ b/ui/base/text/text_elider.cc
@@ -26,7 +26,8 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "third_party/icu/source/common/unicode/rbbi.h"
 #include "third_party/icu/source/common/unicode/uloc.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/text_utils.h"
 #include "url/gurl.h"
 
 namespace ui {
@@ -115,7 +116,7 @@
 
   // Add |filename|, ellipsis if necessary.
   if (num_components != (path_elements.size() - 1))
-    path += UTF8ToUTF16(kEllipsis) + kForwardSlash;
+    path += string16(kEllipsisUTF16) + kForwardSlash;
   path += filename;
 
   return path;
@@ -128,7 +129,7 @@
                                 const std::vector<string16>& url_path_elements,
                                 const string16& url_filename,
                                 const string16& url_query,
-                                const gfx::Font& font,
+                                const gfx::FontList& font_list,
                                 int available_pixel_width) {
   const size_t url_path_number_of_elements = url_path_elements.size();
 
@@ -136,9 +137,9 @@
   for (size_t i = url_path_number_of_elements - 1; i > 0; --i) {
     string16 elided_path = BuildPathFromComponents(url_path_prefix,
         url_path_elements, url_filename, i);
-    if (available_pixel_width >= font.GetStringWidth(elided_path))
-      return ElideText(elided_path + url_query,
-                       font, available_pixel_width, ELIDE_AT_END);
+    if (available_pixel_width >= gfx::GetStringWidth(elided_path, font_list))
+      return ElideText(elided_path + url_query, font_list,
+                       available_pixel_width, ELIDE_AT_END);
   }
 
   return string16();
@@ -147,9 +148,9 @@
 }  // namespace
 
 string16 ElideEmail(const string16& email,
-                    const gfx::Font& font,
+                    const gfx::FontList& font_list,
                     int available_pixel_width) {
-  if (font.GetStringWidth(email) <= available_pixel_width)
+  if (gfx::GetStringWidth(email, font_list) <= available_pixel_width)
     return email;
 
   // Split the email into its local-part (username) and domain-part. The email
@@ -166,16 +167,17 @@
 
   // Subtract the @ symbol from the available width as it is mandatory.
   const string16 kAtSignUTF16 = ASCIIToUTF16("@");
-  available_pixel_width -= font.GetStringWidth(kAtSignUTF16);
+  available_pixel_width -= gfx::GetStringWidth(kAtSignUTF16, font_list);
 
   // Check whether eliding the domain is necessary: if eliding the username
   // is sufficient, the domain will not be elided.
-  const int full_username_width = font.GetStringWidth(username);
+  const int full_username_width = gfx::GetStringWidth(username, font_list);
   const int available_domain_width =
       available_pixel_width -
       std::min(full_username_width,
-               font.GetStringWidth(username.substr(0, 1) + kEllipsisUTF16));
-  if (font.GetStringWidth(domain) > available_domain_width) {
+               gfx::GetStringWidth(username.substr(0, 1) + kEllipsisUTF16,
+                                   font_list));
+  if (gfx::GetStringWidth(domain, font_list) > available_domain_width) {
     // Elide the domain so that it only takes half of the available width.
     // Should the username not need all the width available in its half, the
     // domain will occupy the leftover width.
@@ -186,7 +188,8 @@
         std::min(available_domain_width,
                  std::max(available_pixel_width - full_username_width,
                           available_pixel_width / 2));
-    domain = ElideText(domain, font, desired_domain_width, ELIDE_IN_MIDDLE);
+    domain = ElideText(domain, font_list, desired_domain_width,
+                       ELIDE_IN_MIDDLE);
     // Failing to elide the domain such that at least one character remains
     // (other than the ellipsis itself) remains: return a single ellipsis.
     if (domain.length() <= 1U)
@@ -196,20 +199,25 @@
   // Fit the username in the remaining width (at this point the elided username
   // is guaranteed to fit with at least one character remaining given all the
   // precautions taken earlier).
-  username = ElideText(username,
-                       font,
-                       available_pixel_width - font.GetStringWidth(domain),
+  available_pixel_width -= gfx::GetStringWidth(domain, font_list);
+  username = ElideText(username, font_list, available_pixel_width,
                        ELIDE_AT_END);
 
   return username + kAtSignUTF16 + domain;
 }
 
+string16 ElideEmail(const string16& email,
+                    const gfx::Font& font,
+                    int available_pixel_width) {
+  return ElideEmail(email, gfx::FontList(font), available_pixel_width);
+}
+
 // TODO(pkasting): http://crbug.com/77883 This whole function gets
 // kerning/ligatures/etc. issues potentially wrong by assuming that the width of
 // a rendered string is always the sum of the widths of its substrings.  Also I
 // suspect it could be made simpler.
 string16 ElideUrl(const GURL& url,
-                  const gfx::Font& font,
+                  const gfx::FontList& font_list,
                   int available_pixel_width,
                   const std::string& languages) {
   // Get a formatted string and corresponding parsing of the url.
@@ -222,11 +230,12 @@
 
   // If non-standard, return plain eliding.
   if (!url.IsStandard())
-    return ElideText(url_string, font, available_pixel_width, ELIDE_AT_END);
+    return ElideText(url_string, font_list, available_pixel_width,
+                     ELIDE_AT_END);
 
   // Now start eliding url_string to fit within available pixel width.
   // Fist pass - check to see whether entire url_string fits.
-  const int pixel_width_url_string = font.GetStringWidth(url_string);
+  const int pixel_width_url_string = gfx::GetStringWidth(url_string, font_list);
   if (available_pixel_width >= pixel_width_url_string)
     return url_string;
 
@@ -239,8 +248,9 @@
   // Return general elided text if url minus the query fits.
   const string16 url_minus_query =
       url_string.substr(0, path_start_index + path_len);
-  if (available_pixel_width >= font.GetStringWidth(url_minus_query))
-    return ElideText(url_string, font, available_pixel_width, ELIDE_AT_END);
+  if (available_pixel_width >= gfx::GetStringWidth(url_minus_query, font_list))
+    return ElideText(url_string, font_list, available_pixel_width,
+                     ELIDE_AT_END);
 
   // Get Host.
   string16 url_host = UTF8ToUTF16(url.host());
@@ -288,15 +298,17 @@
   }
 
   // Second Pass - remove scheme - the rest fits.
-  const int pixel_width_url_host = font.GetStringWidth(url_host);
-  const int pixel_width_url_path = font.GetStringWidth(url_path_query_etc);
+  const int pixel_width_url_host = gfx::GetStringWidth(url_host, font_list);
+  const int pixel_width_url_path = gfx::GetStringWidth(url_path_query_etc,
+                                                       font_list);
   if (available_pixel_width >=
       pixel_width_url_host + pixel_width_url_path)
     return url_host + url_path_query_etc;
 
   // Third Pass: Subdomain, domain and entire path fits.
-  const int pixel_width_url_domain = font.GetStringWidth(url_domain);
-  const int pixel_width_url_subdomain = font.GetStringWidth(url_subdomain);
+  const int pixel_width_url_domain = gfx::GetStringWidth(url_domain, font_list);
+  const int pixel_width_url_subdomain = gfx::GetStringWidth(url_subdomain,
+                                                            font_list);
   if (available_pixel_width >=
       pixel_width_url_subdomain + pixel_width_url_domain +
       pixel_width_url_path)
@@ -304,15 +316,15 @@
 
   // Query element.
   string16 url_query;
-  const int kPixelWidthDotsTrailer =
-      font.GetStringWidth(UTF8ToUTF16(kEllipsis));
+  const int kPixelWidthDotsTrailer = gfx::GetStringWidth(
+      string16(kEllipsisUTF16), font_list);
   if (parsed.query.is_nonempty()) {
     url_query = UTF8ToUTF16("?") + url_string.substr(parsed.query.begin);
-    if (available_pixel_width >= (pixel_width_url_subdomain +
-        pixel_width_url_domain + pixel_width_url_path -
-        font.GetStringWidth(url_query))) {
+    if (available_pixel_width >=
+        (pixel_width_url_subdomain + pixel_width_url_domain +
+         pixel_width_url_path - gfx::GetStringWidth(url_query, font_list))) {
       return ElideText(url_subdomain + url_domain + url_path_query_etc,
-                       font, available_pixel_width, ELIDE_AT_END);
+                       font_list, available_pixel_width, ELIDE_AT_END);
     }
   }
 
@@ -339,18 +351,19 @@
       url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) {
     // No path to elide, or too long of a path (could overflow in loop below)
     // Just elide this as a text string.
-    return ElideText(url_subdomain + url_domain + url_path_query_etc, font,
+    return ElideText(url_subdomain + url_domain + url_path_query_etc, font_list,
                      available_pixel_width, ELIDE_AT_END);
   }
 
   // Start eliding the path and replacing elements by ".../".
-  const string16 kEllipsisAndSlash = UTF8ToUTF16(kEllipsis) + kForwardSlash;
-  const int pixel_width_ellipsis_slash = font.GetStringWidth(kEllipsisAndSlash);
+  const string16 kEllipsisAndSlash = string16(kEllipsisUTF16) + kForwardSlash;
+  const int pixel_width_ellipsis_slash = gfx::GetStringWidth(kEllipsisAndSlash,
+                                                             font_list);
 
   // Check with both subdomain and domain.
   string16 elided_path =
       ElideComponentizedPath(url_subdomain + url_domain, url_path_elements,
-                             url_filename, url_query, font,
+                             url_filename, url_query, font_list,
                              available_pixel_width);
   if (!elided_path.empty())
     return elided_path;
@@ -368,7 +381,7 @@
       url_elided_domain = url_domain;
 
     elided_path = ElideComponentizedPath(url_elided_domain, url_path_elements,
-                                         url_filename, url_query, font,
+                                         url_filename, url_query, font_list,
                                          available_pixel_width);
 
     if (!elided_path.empty())
@@ -377,24 +390,32 @@
 
   // Return elided domain/.../filename anyway.
   string16 final_elided_url_string(url_elided_domain);
-  const int url_elided_domain_width = font.GetStringWidth(url_elided_domain);
+  const int url_elided_domain_width = gfx::GetStringWidth(url_elided_domain,
+                                                          font_list);
 
   // A hack to prevent trailing ".../...".
   if ((available_pixel_width - url_elided_domain_width) >
       pixel_width_ellipsis_slash + kPixelWidthDotsTrailer +
-      font.GetStringWidth(ASCIIToUTF16("UV"))) {
+      gfx::GetStringWidth(ASCIIToUTF16("UV"), font_list)) {
     final_elided_url_string += BuildPathFromComponents(string16(),
         url_path_elements, url_filename, 1);
   } else {
     final_elided_url_string += url_path;
   }
 
-  return ElideText(final_elided_url_string, font, available_pixel_width,
+  return ElideText(final_elided_url_string, font_list, available_pixel_width,
                    ELIDE_AT_END);
 }
 
+string16 ElideUrl(const GURL& url,
+                  const gfx::Font& font,
+                  int available_pixel_width,
+                  const std::string& languages) {
+  return ElideUrl(url, gfx::FontList(font), available_pixel_width, languages);
+}
+
 string16 ElideFilename(const base::FilePath& filename,
-                       const gfx::Font& font,
+                       const gfx::FontList& font_list,
                        int available_pixel_width) {
 #if defined(OS_WIN)
   string16 filename_utf16 = filename.value();
@@ -409,18 +430,18 @@
       filename.BaseName().RemoveExtension().value()));
 #endif
 
-  const int full_width = font.GetStringWidth(filename_utf16);
+  const int full_width = gfx::GetStringWidth(filename_utf16, font_list);
   if (full_width <= available_pixel_width)
     return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16);
 
   if (rootname.empty() || extension.empty()) {
-    const string16 elided_name = ElideText(filename_utf16, font,
+    const string16 elided_name = ElideText(filename_utf16, font_list,
                                            available_pixel_width, ELIDE_AT_END);
     return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
   }
 
-  const int ext_width = font.GetStringWidth(extension);
-  const int root_width = font.GetStringWidth(rootname);
+  const int ext_width = gfx::GetStringWidth(extension, font_list);
+  const int root_width = gfx::GetStringWidth(rootname, font_list);
 
   // We may have trimmed the path.
   if (root_width + ext_width <= available_pixel_width) {
@@ -429,7 +450,7 @@
   }
 
   if (ext_width >= available_pixel_width) {
-    const string16 elided_name = ElideText(rootname + extension, font,
+    const string16 elided_name = ElideText(rootname + extension, font_list,
                                            available_pixel_width,
                                            ELIDE_IN_MIDDLE);
     return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
@@ -437,19 +458,25 @@
 
   int available_root_width = available_pixel_width - ext_width;
   string16 elided_name =
-      ElideText(rootname, font, available_root_width, ELIDE_AT_END);
+      ElideText(rootname, font_list, available_root_width, ELIDE_AT_END);
   elided_name += extension;
   return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
 }
 
+string16 ElideFilename(const base::FilePath& filename,
+                       const gfx::Font& font,
+                       int available_pixel_width) {
+  return ElideFilename(filename, gfx::FontList(font), available_pixel_width);
+}
+
 string16 ElideText(const string16& text,
-                   const gfx::Font& font,
+                   const gfx::FontList& font_list,
                    int available_pixel_width,
                    ElideBehavior elide_behavior) {
   if (text.empty())
     return text;
 
-  const int current_text_pixel_width = font.GetStringWidth(text);
+  const int current_text_pixel_width = gfx::GetStringWidth(text, font_list);
   const bool elide_in_middle = (elide_behavior == ELIDE_IN_MIDDLE);
   const bool insert_ellipsis = (elide_behavior != TRUNCATE_AT_END);
 
@@ -466,13 +493,14 @@
   // ridiculous), but we should check other widths for bogus values as well.
   if (current_text_pixel_width <= 0 && !text.empty()) {
     const string16 cut = slicer.CutString(text.length() / 2, false);
-    return ElideText(cut, font, available_pixel_width, elide_behavior);
+    return ElideText(cut, font_list, available_pixel_width, elide_behavior);
   }
 
   if (current_text_pixel_width <= available_pixel_width)
     return text;
 
-  if (insert_ellipsis && font.GetStringWidth(ellipsis) > available_pixel_width)
+  if (insert_ellipsis &&
+      gfx::GetStringWidth(ellipsis, font_list) > available_pixel_width)
     return string16();
 
   // Use binary search to compute the elided text.
@@ -483,12 +511,12 @@
     // We check the length of the whole desired string at once to ensure we
     // handle kerning/ligatures/etc. correctly.
     const string16 cut = slicer.CutString(guess, insert_ellipsis);
-    const int guess_length = font.GetStringWidth(cut);
+    const int guess_length = gfx::GetStringWidth(cut, font_list);
     // Check again that we didn't hit a Pango width overflow. If so, cut the
     // current string in half and start over.
     if (guess_length <= 0) {
       return ElideText(slicer.CutString(guess / 2, false),
-                       font, available_pixel_width, elide_behavior);
+                       font_list, available_pixel_width, elide_behavior);
     }
     if (guess_length > available_pixel_width)
       hi = guess - 1;
@@ -499,6 +527,14 @@
   return slicer.CutString(guess, insert_ellipsis);
 }
 
+string16 ElideText(const string16& text,
+                   const gfx::Font& font,
+                   int available_pixel_width,
+                   ElideBehavior elide_behavior) {
+  return ElideText(text, gfx::FontList(font), available_pixel_width,
+                   elide_behavior);
+}
+
 SortedDisplayURL::SortedDisplayURL(const GURL& url,
                                    const std::string& languages) {
   net::AppendFormattedHost(url, languages, &sort_host_);
@@ -775,13 +811,13 @@
 // can be broken into smaller methods sharing this state.
 class RectangleText {
  public:
-  RectangleText(const gfx::Font& font,
+  RectangleText(const gfx::FontList& font_list,
                 int available_pixel_width,
                 int available_pixel_height,
                 ui::WordWrapBehavior wrap_behavior,
                 std::vector<string16>* lines)
-      : font_(font),
-        line_height_(font.GetHeight()),
+      : font_list_(font_list),
+        line_height_(font_list.GetHeight()),
         available_pixel_width_(available_pixel_width),
         available_pixel_height_(available_pixel_height),
         wrap_behavior_(wrap_behavior),
@@ -833,8 +869,8 @@
   // Set the current position to the beginning of the next line.
   bool NewLine();
 
-  // The font used for measuring text width.
-  const gfx::Font& font_;
+  // The font list used for measuring text width.
+  const gfx::FontList& font_list_;
 
   // The height of each line of text.
   const int line_height_;
@@ -907,7 +943,7 @@
 }
 
 void RectangleText::AddLine(const string16& line) {
-  const int line_width = font_.GetStringWidth(line);
+  const int line_width = gfx::GetStringWidth(line, font_list_);
   if (line_width <= available_pixel_width_) {
     AddToCurrentLineWithWidth(line, line_width);
   } else {
@@ -948,7 +984,8 @@
   bool first_fragment = true;
   while (!insufficient_height_ && !text.empty()) {
     string16 fragment =
-        ui::ElideText(text, font_, available_pixel_width_, ui::TRUNCATE_AT_END);
+        ui::ElideText(text, font_list_, available_pixel_width_,
+                      ui::TRUNCATE_AT_END);
     // At least one character has to be added at every line, even if the
     // available space is too small.
     if(fragment.empty())
@@ -982,7 +1019,7 @@
         (wrap_behavior_ == ui::ELIDE_LONG_WORDS ? ui::ELIDE_AT_END :
                                                   ui::TRUNCATE_AT_END);
     const string16 elided_word =
-        ui::ElideText(word, font_, available_pixel_width_, elide_behavior);
+        ui::ElideText(word, font_list_, available_pixel_width_, elide_behavior);
     AddToCurrentLine(elided_word);
     insufficient_width_ = true;
   }
@@ -994,7 +1031,7 @@
   int lines_added = 0;
   string16 trimmed;
   TrimWhitespace(word, TRIM_TRAILING, &trimmed);
-  const int trimmed_width = font_.GetStringWidth(trimmed);
+  const int trimmed_width = gfx::GetStringWidth(trimmed, font_list_);
   if (trimmed_width <= available_pixel_width_) {
     // Word can be made to fit, no need to fragment it.
     if ((current_width_ + trimmed_width > available_pixel_width_) && NewLine())
@@ -1009,7 +1046,7 @@
 }
 
 void RectangleText::AddToCurrentLine(const string16& text) {
-  AddToCurrentLineWithWidth(text, font_.GetStringWidth(text));
+  AddToCurrentLineWithWidth(text, gfx::GetStringWidth(text, font_list_));
 }
 
 void RectangleText::AddToCurrentLineWithWidth(const string16& text,
@@ -1049,12 +1086,12 @@
 }
 
 int ElideRectangleText(const string16& input,
-                        const gfx::Font& font,
-                        int available_pixel_width,
-                        int available_pixel_height,
-                        WordWrapBehavior wrap_behavior,
-                        std::vector<string16>* lines) {
-  RectangleText rect(font,
+                       const gfx::FontList& font_list,
+                       int available_pixel_width,
+                       int available_pixel_height,
+                       WordWrapBehavior wrap_behavior,
+                       std::vector<string16>* lines) {
+  RectangleText rect(font_list,
                      available_pixel_width,
                      available_pixel_height,
                      wrap_behavior,
@@ -1064,6 +1101,17 @@
   return rect.Finalize();
 }
 
+int ElideRectangleText(const string16& input,
+                       const gfx::Font& font,
+                       int available_pixel_width,
+                       int available_pixel_height,
+                       WordWrapBehavior wrap_behavior,
+                       std::vector<string16>* lines) {
+  return ElideRectangleText(input, gfx::FontList(font),
+                            available_pixel_width, available_pixel_height,
+                            wrap_behavior, lines);
+}
+
 string16 TruncateString(const string16& string, size_t length) {
   if (string.size() <= length)
     // String fits, return it.
diff --git a/ui/base/text/text_elider.h b/ui/base/text/text_elider.h
index 1d31f8e..a4ea50d 100644
--- a/ui/base/text/text_elider.h
+++ b/ui/base/text/text_elider.h
@@ -15,7 +15,6 @@
 #include "third_party/icu/source/common/unicode/uchar.h"
 #include "third_party/icu/source/i18n/unicode/coll.h"
 #include "ui/base/ui_export.h"
-#include "ui/gfx/font.h"
 
 class GURL;
 
@@ -23,13 +22,18 @@
 class FilePath;
 }
 
+namespace gfx {
+class Font;
+class FontList;
+}  // namespace gfx
+
 namespace ui {
 
 UI_EXPORT extern const char kEllipsis[];
 UI_EXPORT extern const char16 kEllipsisUTF16[];
 
 // Elides a well-formed email address (e.g. username@domain.com) to fit into
-// |available_pixel_width| using the specified |font|.
+// |available_pixel_width| using the specified |font_list|.
 // This function guarantees that the string returned will contain at least one
 // character, other than the ellipses, on either side of the '@'. If it is
 // impossible to achieve these requirements: only an ellipsis will be returned.
@@ -39,6 +43,10 @@
 // doesn't need half the available width: the elided domain will occupy that
 // extra width).
 UI_EXPORT string16 ElideEmail(const string16& email,
+                              const gfx::FontList& font_list,
+                              int available_pixel_width);
+// Obsolete version.  Use the above version which takes gfx::FontList.
+UI_EXPORT string16 ElideEmail(const string16& email,
                               const gfx::Font& font,
                               int available_pixel_width);
 
@@ -57,6 +65,11 @@
 // is displayed properly in an RTL context. Please refer to
 // http://crbug.com/6487 for more information.
 UI_EXPORT string16 ElideUrl(const GURL& url,
+                            const gfx::FontList& font_list,
+                            int available_pixel_width,
+                            const std::string& languages);
+// Obsolete version.  Use the above version which takes gfx::FontList.
+UI_EXPORT string16 ElideUrl(const GURL& url,
                             const gfx::Font& font,
                             int available_pixel_width,
                             const std::string& languages);
@@ -73,6 +86,11 @@
 // Elides |text| to fit in |available_pixel_width| according to the specified
 // |elide_behavior|.
 UI_EXPORT string16 ElideText(const string16& text,
+                             const gfx::FontList& font_list,
+                             int available_pixel_width,
+                             ElideBehavior elide_behavior);
+// Obsolete version.  Use the above version which takes gfx::FontList.
+UI_EXPORT string16 ElideText(const string16& text,
                              const gfx::Font& font,
                              int available_pixel_width,
                              ElideBehavior elide_behavior);
@@ -84,6 +102,10 @@
 // the elided filename is wrapped with LRE (Left-To-Right Embedding) mark and
 // PDF (Pop Directional Formatting) mark.
 UI_EXPORT string16 ElideFilename(const base::FilePath& filename,
+                                 const gfx::FontList& font_list,
+                                 int available_pixel_width);
+// Obsolete version.  Use the above version which takes gfx::FontList.
+UI_EXPORT string16 ElideFilename(const base::FilePath& filename,
                                  const gfx::Font& font,
                                  int available_pixel_width);
 
@@ -181,12 +203,19 @@
 
 // Reformats |text| into output vector |lines| so that the resulting text fits
 // into an |available_pixel_width| by |available_pixel_height| rectangle with
-// the specified |font|. Input newlines are respected, but lines that are too
-// long are broken into pieces. For words that are too wide to fit on a single
-// line, the wrapping behavior can be specified with the |wrap_behavior| param.
-// Returns a combination of |ReformattingResultFlags| that indicate whether the
-// given rectangle had insufficient space to accommodate |texŧ|, leading to
-// elision or truncation (and not just reformatting).
+// the specified |font_list|. Input newlines are respected, but lines that are
+// too long are broken into pieces. For words that are too wide to fit on a
+// single line, the wrapping behavior can be specified with the |wrap_behavior|
+// param. Returns a combination of |ReformattingResultFlags| that indicate
+// whether the given rectangle had insufficient space to accommodate |texŧ|,
+// leading to elision or truncation (and not just reformatting).
+UI_EXPORT int ElideRectangleText(const string16& text,
+                                 const gfx::FontList& font_list,
+                                 int available_pixel_width,
+                                 int available_pixel_height,
+                                 WordWrapBehavior wrap_behavior,
+                                 std::vector<string16>* lines);
+// Obsolete version.  Use the above version which takes gfx::FontList.
 UI_EXPORT int ElideRectangleText(const string16& text,
                                  const gfx::Font& font,
                                  int available_pixel_width,
diff --git a/ui/base/win/hwnd_util.cc b/ui/base/win/hwnd_util.cc
index 7299c8c..0a8dfb2 100644
--- a/ui/base/win/hwnd_util.cc
+++ b/ui/base/win/hwnd_util.cc
@@ -7,6 +7,7 @@
 #include "base/i18n/rtl.h"
 #include "base/strings/string_util.h"
 #include "base/win/metro.h"
+#include "base/win/win_util.h"
 #include "ui/gfx/point.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
@@ -23,7 +24,7 @@
     if (hmon) {
       MONITORINFO mi;
       mi.cbSize = sizeof(mi);
-      GetMonitorInfo(hmon, &mi);
+      base::win::GetMonitorInfoWrapper(hmon, &mi);
       gfx::Rect window_rect(bounds);
       gfx::Rect monitor_rect(mi.rcWork);
       gfx::Rect new_window_rect = window_rect;
@@ -131,7 +132,7 @@
     if (monitor) {
       MONITORINFO mi = {0};
       mi.cbSize = sizeof(mi);
-      GetMonitorInfo(monitor, &mi);
+      base::win::GetMonitorInfoWrapper(monitor, &mi);
       center_bounds = mi.rcWork;
     } else {
       NOTREACHED() << "Unable to get default monitor";
diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc
index df90108..0f95537 100644
--- a/ui/base/win/shell.cc
+++ b/ui/base/win/shell.cc
@@ -98,6 +98,22 @@
                          SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_DDEWAIT);
 }
 
+bool PreventWindowFromPinning(HWND hwnd) {
+  // This functionality is only available on Win7+. It also doesn't make sense
+  // to do this for Chrome Metro.
+  if (base::win::GetVersion() < base::win::VERSION_WIN7 ||
+      base::win::IsMetroProcess())
+    return false;
+  base::win::ScopedComPtr<IPropertyStore> pps;
+  HRESULT result = SHGetPropertyStoreForWindow(
+      hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive()));
+  if (FAILED(result))
+    return false;
+
+  return base::win::SetBooleanValueForPropertyStore(
+             pps, PKEY_AppUserModel_PreventPinning, true);
+}
+
 void SetAppIdForWindow(const string16& app_id, HWND hwnd) {
   SetAppDetailsForWindow(app_id, string16(), string16(), string16(), hwnd);
 }
diff --git a/ui/base/win/shell.h b/ui/base/win/shell.h
index 364b7a3..31dbb88 100644
--- a/ui/base/win/shell.h
+++ b/ui/base/win/shell.h
@@ -41,6 +41,11 @@
 // Returns 'true' on successful open, 'false' otherwise.
 bool OpenItemWithExternalApp(const string16& full_path);
 
+// Disables the ability of the specified window to be pinned to the taskbar or
+// the Start menu. This will remove "Pin this program to taskbar" from the
+// taskbar menu of the specified window.
+UI_EXPORT bool PreventWindowFromPinning(HWND hwnd);
+
 // Sets the application id given as the Application Model ID for the window
 // specified.  This method is used to insure that different web applications
 // do not group together on the Win7 task bar.
diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc
index 03d4ae2..22c3f68 100644
--- a/ui/base/x/events_x.cc
+++ b/ui/base/x/events_x.cc
@@ -9,7 +9,6 @@
 #include <X11/extensions/XInput2.h>
 #include <X11/Xlib.h>
 
-#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "base/message_loop/message_pump_aurax11.h"
@@ -33,19 +32,6 @@
 const int kMinWheelButton = 4;
 const int kMaxWheelButton = 7;
 
-// A workaround for some incorrect implemented input drivers:
-// Ignore their mouse input valuators.
-bool IgnoreMouseValuators() {
-  static bool initialized = false;
-  static bool ignore_valuators = true;
-  if (initialized)
-    return ignore_valuators;
-  ignore_valuators =
-      CommandLine::ForCurrentProcess()->HasSwitch("disable-mouse-valuators");
-  initialized = true;
-  return ignore_valuators;
-}
-
 // A class to track current modifier state on master device. Only track ctrl,
 // alt, shift and caps lock keys currently. The tracked state can then be used
 // by floating device.
@@ -476,40 +462,8 @@
     case GenericEvent: {
       XIDeviceEvent* xievent =
           static_cast<XIDeviceEvent*>(native_event->xcookie.data);
-
-#if defined(USE_XI2_MT)
-      // Touch event valuators aren't coordinates.
-      // Return the |event_x|/|event_y| directly as event's position.
-      if (xievent->evtype == XI_TouchBegin ||
-          xievent->evtype == XI_TouchUpdate ||
-          xievent->evtype == XI_TouchEnd)
-        // Note: Touch events are always touch screen events.
-        return gfx::Point(static_cast<int>(xievent->event_x),
-                          static_cast<int>(xievent->event_y));
-#endif
-      if (IgnoreMouseValuators()) {
-        return gfx::Point(static_cast<int>(xievent->event_x),
-                          static_cast<int>(xievent->event_y));
-      }
-      // Read the position from the valuators, because the location reported in
-      // event_x/event_y seems to be different (and doesn't match for events
-      // coming from slave device and master device) from the values in the
-      // valuators. See more on crbug.com/103981. The position in the valuators
-      // is in the global screen coordinates. But it is necessary to convert it
-      // into the window's coordinates. If the valuator is not set, that means
-      // the value hasn't changed, and so we can use the value from
-      // event_x/event_y (which are in the window's coordinates).
-      double* valuators = xievent->valuators.values;
-
-      double x = xievent->event_x;
-      if (XIMaskIsSet(xievent->valuators.mask, 0))
-        x = *valuators++ - (xievent->root_x - xievent->event_x);
-
-      double y = xievent->event_y;
-      if (XIMaskIsSet(xievent->valuators.mask, 1))
-        y = *valuators++ - (xievent->root_y - xievent->event_y);
-
-      return gfx::Point(static_cast<int>(x), static_cast<int>(y));
+      return gfx::Point(static_cast<int>(xievent->event_x),
+                        static_cast<int>(xievent->event_y));
     }
   }
   return gfx::Point();
diff --git a/ui/base/x/selection_utils.cc b/ui/base/x/selection_utils.cc
index 4696b00..a128986 100644
--- a/ui/base/x/selection_utils.cc
+++ b/ui/base/x/selection_utils.cc
@@ -104,6 +104,7 @@
 void SelectionFormatMap::Insert(
     ::Atom atom,
     const scoped_refptr<base::RefCountedMemory>& item) {
+  data_.erase(atom);
   data_.insert(std::make_pair(atom, item));
 }
 
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index 836feae..3a1ced1 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -32,11 +32,17 @@
 #include "base/strings/stringprintf.h"
 #include "base/sys_byteorder.h"
 #include "base/threading/thread.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkPostConfig.h"
 #include "ui/base/events/event_utils.h"
 #include "ui/base/keycodes/keyboard_code_conversion_x.h"
 #include "ui/base/touch/touch_factory_x11.h"
 #include "ui/base/x/device_data_manager.h"
 #include "ui/base/x/x11_util_internal.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
+#include "ui/gfx/point.h"
 #include "ui/gfx/point_conversions.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
@@ -49,7 +55,6 @@
 #if defined(USE_AURA)
 #include <X11/Xcursor/Xcursor.h>
 #include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/skia_util.h"
 #endif
 
@@ -1183,6 +1188,55 @@
     NOTREACHED();
 }
 
+bool CopyAreaToCanvas(XID drawable,
+                      gfx::Rect source_bounds,
+                      gfx::Point dest_offset,
+                      gfx::Canvas* canvas) {
+  ui::XScopedImage scoped_image(
+      XGetImage(GetXDisplay(), drawable,
+                source_bounds.x(), source_bounds.y(),
+                source_bounds.width(), source_bounds.height(),
+                AllPlanes, ZPixmap));
+  XImage* image = scoped_image.get();
+  if (!image) {
+    LOG(ERROR) << "XGetImage failed";
+    return false;
+  }
+
+  if (image->bits_per_pixel == 32) {
+    if ((0xff << SK_R32_SHIFT) != image->red_mask ||
+        (0xff << SK_G32_SHIFT) != image->green_mask ||
+        (0xff << SK_B32_SHIFT) != image->blue_mask) {
+      LOG(WARNING) << "XImage and Skia byte orders differ";
+      return false;
+    }
+
+    // Set the alpha channel before copying to the canvas.  Otherwise, areas of
+    // the framebuffer that were cleared by ply-image rather than being obscured
+    // by an image during boot may end up transparent.
+    // TODO(derat|marcheu): Remove this if/when ply-image has been updated to
+    // set the framebuffer's alpha channel regardless of whether the device
+    // claims to support alpha or not.
+    for (int i = 0; i < image->width * image->height * 4; i += 4)
+      image->data[i + 3] = 0xff;
+
+    SkBitmap bitmap;
+    bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+                     image->width, image->height,
+                     image->bytes_per_line);
+    bitmap.setPixels(image->data);
+    gfx::ImageSkia image_skia;
+    gfx::ImageSkiaRep image_rep(bitmap, canvas->scale_factor());
+    image_skia.AddRepresentation(image_rep);
+    canvas->DrawImageInt(image_skia, dest_offset.x(), dest_offset.y());
+  } else {
+    NOTIMPLEMENTED() << "Unsupported bits-per-pixel " << image->bits_per_pixel;
+    return false;
+  }
+
+  return true;
+}
+
 XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap) {
   XID picture = XRenderCreatePicture(
       display, pixmap, GetRenderARGB32Format(display), 0, NULL);
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h
index c1c72ba..f0cf1b7 100644
--- a/ui/base/x/x11_util.h
+++ b/ui/base/x/x11_util.h
@@ -39,13 +39,15 @@
 #endif
 
 namespace gfx {
+class Canvas;
+class Point;
 class Rect;
 }
 class SkBitmap;
 
 namespace ui {
 
-// These functions use the GDK default display and this /must/ be called from
+// These functions use the default display and this /must/ be called from
 // the UI thread. Thus, they don't support multiple displays.
 
 // These functions cache their results ---------------------------------
@@ -259,6 +261,16 @@
                                              int shared_memory_support);
 UI_EXPORT void DetachSharedMemory(Display* display, XSharedMemoryId shmseg);
 
+// Copies |source_bounds| from |drawable| to |canvas| at offset |dest_offset|.
+// |source_bounds| is in physical pixels, while |dest_offset| is relative to
+// the canvas's scale. Note that this function is slow since it uses
+// XGetImage() to copy the data from the X server to this process before
+// copying it to |canvas|.
+UI_EXPORT bool CopyAreaToCanvas(XID drawable,
+                                gfx::Rect source_bounds,
+                                gfx::Point dest_offset,
+                                gfx::Canvas* canvas);
+
 // Return a handle to an XRender picture where |pixmap| is a handle to a
 // pixmap containing Skia ARGB data.
 UI_EXPORT XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap);
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 5739bbf..b6b15f4 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -16,6 +16,8 @@
 #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"
@@ -24,15 +26,14 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/compositor/compositor_observer.h"
 #include "ui/compositor/compositor_switches.h"
-#include "ui/compositor/context_provider_from_context_factory.h"
 #include "ui/compositor/dip_util.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/reflector.h"
-#include "ui/compositor/test_web_graphics_context_3d.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"
 
@@ -108,13 +109,23 @@
 
 scoped_ptr<cc::OutputSurface> DefaultContextFactory::CreateOutputSurface(
     Compositor* compositor) {
-  return make_scoped_ptr(new cc::OutputSurface(
-      CreateContextCommon(compositor, false)));
-}
+  WebKit::WebGraphicsContext3D::Attributes attrs;
+  attrs.depth = false;
+  attrs.stencil = false;
+  attrs.antialias = false;
+  attrs.shareResources = true;
 
-scoped_ptr<WebKit::WebGraphicsContext3D>
-DefaultContextFactory::CreateOffscreenContext() {
-  return CreateContextCommon(NULL, 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());
+
+  return make_scoped_ptr(new cc::OutputSurface(context_provider));
 }
 
 scoped_refptr<Reflector> DefaultContextFactory::CreateReflector(
@@ -132,7 +143,7 @@
   if (!offscreen_contexts_main_thread_.get() ||
       !offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
     offscreen_contexts_main_thread_ =
-        ContextProviderFromContextFactory::CreateForOffscreen(this);
+        webkit::gpu::ContextProviderInProcess::CreateOffscreen();
     if (offscreen_contexts_main_thread_.get() &&
         !offscreen_contexts_main_thread_->BindToCurrentThread())
       offscreen_contexts_main_thread_ = NULL;
@@ -145,7 +156,7 @@
   if (!offscreen_contexts_compositor_thread_.get() ||
       !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
     offscreen_contexts_compositor_thread_ =
-        ContextProviderFromContextFactory::CreateForOffscreen(this);
+        webkit::gpu::ContextProviderInProcess::CreateOffscreen();
   }
   return offscreen_contexts_compositor_thread_;
 }
@@ -155,39 +166,14 @@
 
 bool DefaultContextFactory::DoesCreateTestContexts() { return false; }
 
-scoped_ptr<WebKit::WebGraphicsContext3D>
-DefaultContextFactory::CreateContextCommon(Compositor* compositor,
-                                           bool offscreen) {
-  DCHECK(offscreen || compositor);
-  WebKit::WebGraphicsContext3D::Attributes attrs;
-  attrs.depth = false;
-  attrs.stencil = false;
-  attrs.antialias = false;
-  attrs.shareResources = true;
-  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
-  if (offscreen) {
-    return WebGraphicsContext3DInProcessCommandBufferImpl::
-        CreateOffscreenContext(attrs);
-  }
-  return WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
-      attrs, compositor->widget());
-}
-
 TestContextFactory::TestContextFactory() {}
 
 TestContextFactory::~TestContextFactory() {}
 
 scoped_ptr<cc::OutputSurface> TestContextFactory::CreateOutputSurface(
     Compositor* compositor) {
-  return make_scoped_ptr(new cc::OutputSurface(CreateOffscreenContext()));
-}
-
-scoped_ptr<WebKit::WebGraphicsContext3D>
-TestContextFactory::CreateOffscreenContext() {
-  scoped_ptr<ui::TestWebGraphicsContext3D> context(
-      new ui::TestWebGraphicsContext3D);
-  context->Initialize();
-  return context.PassAs<WebKit::WebGraphicsContext3D>();
+  return make_scoped_ptr(
+      new cc::OutputSurface(cc::TestContextProvider::Create()));
 }
 
 scoped_refptr<Reflector> TestContextFactory::CreateReflector(
@@ -203,8 +189,7 @@
 TestContextFactory::OffscreenContextProviderForMainThread() {
   if (!offscreen_contexts_main_thread_.get() ||
       offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
-    offscreen_contexts_main_thread_ =
-        ContextProviderFromContextFactory::CreateForOffscreen(this);
+    offscreen_contexts_main_thread_ = cc::TestContextProvider::Create();
     CHECK(offscreen_contexts_main_thread_->BindToCurrentThread());
   }
   return offscreen_contexts_main_thread_;
@@ -214,8 +199,7 @@
 TestContextFactory::OffscreenContextProviderForCompositorThread() {
   if (!offscreen_contexts_compositor_thread_.get() ||
       offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
-    offscreen_contexts_compositor_thread_ =
-        ContextProviderFromContextFactory::CreateForOffscreen(this);
+    offscreen_contexts_compositor_thread_ = cc::TestContextProvider::Create();
   }
   return offscreen_contexts_compositor_thread_;
 }
diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp
index 57a4aaf..83d1971 100644
--- a/ui/compositor/compositor.gyp
+++ b/ui/compositor/compositor.gyp
@@ -30,8 +30,6 @@
         'compositor_observer.h',
         'compositor_switches.cc',
         'compositor_switches.h',
-        'context_provider_from_context_factory.cc',
-        'context_provider_from_context_factory.h',
         'debug_utils.cc',
         'debug_utils.h',
         'dip_util.cc',
@@ -58,9 +56,6 @@
         'scoped_animation_duration_scale_mode.h',
         'scoped_layer_animation_settings.cc',
         'scoped_layer_animation_settings.h',
-        # UI tests need TestWebGraphicsContext3D, so we always build it.
-        'test_web_graphics_context_3d.cc',
-        'test_web_graphics_context_3d.h',
         'transform_animation_curve_adapter.cc',
         'transform_animation_curve_adapter.h',
       ],
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 92cdd71..e6ce889 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -34,6 +34,7 @@
 class Layer;
 class LayerTreeDebugState;
 class LayerTreeHost;
+class TestContextProvider;
 }
 
 namespace gfx {
@@ -49,6 +50,13 @@
 class WebGraphicsContext3D;
 }
 
+namespace webkit {
+namespace gpu {
+class ContextProviderInProcess;
+class WebGraphicsContext3DInProcessCommandBufferImpl;
+}
+}
+
 namespace ui {
 
 class Compositor;
@@ -80,10 +88,6 @@
   virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
       Compositor* compositor) = 0;
 
-  // Creates a context used for offscreen rendering. This context can be shared
-  // with all compositors.
-  virtual scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext() = 0;
-
   // Creates a reflector that copies the content of the |mirrored_compositor|
   // onto |mirroing_layer|.
   virtual scoped_refptr<Reflector> CreateReflector(
@@ -114,8 +118,6 @@
   // ContextFactory implementation
   virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
       Compositor* compositor) OVERRIDE;
-  virtual scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext()
-      OVERRIDE;
 
   virtual scoped_refptr<Reflector> CreateReflector(
       Compositor* compositor,
@@ -132,13 +134,9 @@
   bool Initialize();
 
  private:
-  scoped_ptr<WebKit::WebGraphicsContext3D> CreateContextCommon(
-      Compositor* compositor,
-      bool offscreen);
-
-  scoped_refptr<ContextProviderFromContextFactory>
+  scoped_refptr<webkit::gpu::ContextProviderInProcess>
       offscreen_contexts_main_thread_;
-  scoped_refptr<ContextProviderFromContextFactory>
+  scoped_refptr<webkit::gpu::ContextProviderInProcess>
       offscreen_contexts_compositor_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultContextFactory);
@@ -153,8 +151,6 @@
   // ContextFactory implementation
   virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface(
       Compositor* compositor) OVERRIDE;
-  virtual scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext()
-      OVERRIDE;
 
   virtual scoped_refptr<Reflector> CreateReflector(
       Compositor* mirrored_compositor,
@@ -169,10 +165,8 @@
   virtual bool DoesCreateTestContexts() OVERRIDE;
 
  private:
-  scoped_refptr<ContextProviderFromContextFactory>
-      offscreen_contexts_main_thread_;
-  scoped_refptr<ContextProviderFromContextFactory>
-      offscreen_contexts_compositor_thread_;
+  scoped_refptr<cc::TestContextProvider> offscreen_contexts_main_thread_;
+  scoped_refptr<cc::TestContextProvider> offscreen_contexts_compositor_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(TestContextFactory);
 };
diff --git a/ui/compositor/context_provider_from_context_factory.cc b/ui/compositor/context_provider_from_context_factory.cc
deleted file mode 100644
index 262998a..0000000
--- a/ui/compositor/context_provider_from_context_factory.cc
+++ /dev/null
@@ -1,76 +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 "context_provider_from_context_factory.h"
-
-#include "base/logging.h"
-
-namespace ui {
-
-// static
-scoped_refptr<ContextProviderFromContextFactory>
-ContextProviderFromContextFactory::CreateForOffscreen(ContextFactory* factory) {
-  scoped_refptr<ContextProviderFromContextFactory> provider =
-      new ContextProviderFromContextFactory(factory);
-  if (!provider->InitializeOnMainThread())
-    return NULL;
-  return provider;
-}
-
-ContextProviderFromContextFactory::ContextProviderFromContextFactory(
-    ContextFactory* factory)
-    : factory_(factory),
-      destroyed_(false) {
-}
-
-ContextProviderFromContextFactory::~ContextProviderFromContextFactory() {
-}
-
-bool ContextProviderFromContextFactory::BindToCurrentThread() {
-  DCHECK(context3d_);
-  return context3d_->makeContextCurrent();
-}
-
-WebKit::WebGraphicsContext3D* ContextProviderFromContextFactory::Context3d() {
-  DCHECK(context3d_);
-  return context3d_.get();
-}
-
-class GrContext* ContextProviderFromContextFactory::GrContext() {
-  DCHECK(context3d_);
-
-  if (!gr_context_) {
-    gr_context_.reset(
-        new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
-  }
-  return gr_context_->get();
-}
-
-void ContextProviderFromContextFactory::VerifyContexts() {
-  DCHECK(context3d_);
-
-  if (context3d_->isContextLost()) {
-    base::AutoLock lock(destroyed_lock_);
-    destroyed_ = true;
-  }
-}
-
-bool ContextProviderFromContextFactory::DestroyedOnMainThread() {
-  base::AutoLock lock(destroyed_lock_);
-  return destroyed_;
-}
-
-void ContextProviderFromContextFactory::SetLostContextCallback(
-    const LostContextCallback& cb) {
-  NOTIMPLEMENTED();
-}
-
-bool ContextProviderFromContextFactory::InitializeOnMainThread() {
-  if (context3d_)
-    return true;
-  context3d_ = factory_->CreateOffscreenContext();
-  return !!context3d_;
-}
-
-}  // namespace ui
diff --git a/ui/compositor/context_provider_from_context_factory.h b/ui/compositor/context_provider_from_context_factory.h
deleted file mode 100644
index 57be7f4..0000000
--- a/ui/compositor/context_provider_from_context_factory.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 UI_COMPOSITOR_CONTEXT_PROVIDER_FROM_CONTEXT_FACTORY_H_
-#define UI_COMPOSITOR_CONTEXT_PROVIDER_FROM_CONTEXT_FACTORY_H_
-
-#include "base/synchronization/lock.h"
-#include "cc/output/context_provider.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-#include "ui/compositor/compositor.h"
-#include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
-
-namespace ui {
-
-class ContextProviderFromContextFactory
-    : public cc::ContextProvider {
- public:
-  static scoped_refptr<ContextProviderFromContextFactory> CreateForOffscreen(
-      ContextFactory* factory);
-
-  virtual bool BindToCurrentThread() OVERRIDE;
-  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE;
-  virtual class GrContext* GrContext() OVERRIDE;
-  virtual void VerifyContexts() OVERRIDE;
-  virtual bool DestroyedOnMainThread() OVERRIDE;
-  virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE;
-
- protected:
-  ContextProviderFromContextFactory(ContextFactory* factory);
-  virtual ~ContextProviderFromContextFactory();
-
-  bool InitializeOnMainThread();
-
- private:
-  ContextFactory* factory_;
-  base::Lock destroyed_lock_;
-  bool destroyed_;
-  scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
-  scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
-};
-
-}  // namespace ui
-
-#endif  // UI_COMPOSITOR_CONTEXT_PROVIDER_FROM_CONTEXT_FACTORY_H_
diff --git a/ui/compositor/debug_utils.cc b/ui/compositor/debug_utils.cc
index 016ff17..b9ee5ce 100644
--- a/ui/compositor/debug_utils.cc
+++ b/ui/compositor/debug_utils.cc
@@ -28,7 +28,6 @@
                             gfx::Point mouse_location,
                             std::wostringstream* out) {
   std::string indent_str(indent, ' ');
-  std::string content_indent_str(indent+1, ' ');
 
   layer->transform().TransformPointReverse(mouse_location);
   bool mouse_inside_layer_bounds = layer->bounds().Contains(mouse_location);
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 6c0fde3..f5bf42c 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -552,7 +552,7 @@
 }
 
 void Layer::TakeUnusedResourcesForChildCompositor(
-    cc::TransferableResourceArray* list) {
+    cc::ReturnedResourceArray* list) {
   if (delegated_renderer_layer_.get())
     delegated_renderer_layer_->TakeUnusedResourcesForChildCompositor(list);
 }
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index aa78d93..cd640b1 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -38,8 +38,8 @@
 class ResourceUpdateQueue;
 class SolidColorLayer;
 class TextureLayer;
-struct TransferableResource;
-typedef std::vector<TransferableResource> TransferableResourceArray;
+struct ReturnedResource;
+typedef std::vector<ReturnedResource> ReturnedResourceArray;
 }
 
 namespace ui {
@@ -267,7 +267,7 @@
 
   // Gets unused resources to recycle to the child compositor.
   void TakeUnusedResourcesForChildCompositor(
-      cc::TransferableResourceArray* array);
+      cc::ReturnedResourceArray* array);
 
   // Sets the layer's fill color.  May only be called for LAYER_SOLID_COLOR.
   void SetColor(SkColor color);
diff --git a/ui/compositor/layer_animation_sequence.cc b/ui/compositor/layer_animation_sequence.cc
index 371e540..f1c7eba 100644
--- a/ui/compositor/layer_animation_sequence.cc
+++ b/ui/compositor/layer_animation_sequence.cc
@@ -8,6 +8,7 @@
 #include <iterator>
 
 #include "base/debug/trace_event.h"
+#include "cc/animation/animation_id_provider.h"
 #include "ui/compositor/layer_animation_delegate.h"
 #include "ui/compositor/layer_animation_element.h"
 #include "ui/compositor/layer_animation_observer.h"
@@ -76,8 +77,10 @@
   }
 
   if (is_cyclic_ || last_element_ < elements_.size()) {
-    if (!elements_[current_index]->Started())
+    if (!elements_[current_index]->Started()) {
+      animation_group_id_ = cc::AnimationIdProvider::NextGroupId();
       elements_[current_index]->Start(delegate, animation_group_id_);
+    }
     if (elements_[current_index]->Progress(now, delegate))
       redraw_required = true;
     last_progressed_fraction_ =
diff --git a/ui/compositor/layer_animation_sequence.h b/ui/compositor/layer_animation_sequence.h
index 838c6b9..a2972f7 100644
--- a/ui/compositor/layer_animation_sequence.h
+++ b/ui/compositor/layer_animation_sequence.h
@@ -102,6 +102,8 @@
   bool IsFirstElementThreaded() const;
 
   // Used to identify groups of sequences that are supposed to start together.
+  // Once started, used to identify the sequence that owns a particular
+  // threaded animation.
   int animation_group_id() const { return animation_group_id_; }
   void set_animation_group_id(int id) { animation_group_id_ = id; }
 
@@ -164,6 +166,9 @@
   bool waiting_for_group_start_;
 
   // Identifies groups of sequences that are supposed to start together.
+  // Also used to identify the owner of a particular threaded animation; any
+  // in-progress threaded animation owned by this sequence will have this
+  // group id.
   int animation_group_id_;
 
   // These parties are notified when layer animations end.
diff --git a/ui/compositor/layer_animation_sequence_unittest.cc b/ui/compositor/layer_animation_sequence_unittest.cc
index fe70601..3b45917 100644
--- a/ui/compositor/layer_animation_sequence_unittest.cc
+++ b/ui/compositor/layer_animation_sequence_unittest.cc
@@ -82,8 +82,8 @@
       LayerAnimationElement::CreateOpacityElement(target, delta));
 
   for (int i = 0; i < 2; ++i) {
-    int group_id = 1;
-    sequence.set_animation_group_id(group_id);
+    int starting_group_id = 1;
+    sequence.set_animation_group_id(starting_group_id);
     start_time = effective_start + delta;
     sequence.set_start_time(start_time);
     delegate.SetOpacityFromAnimation(start);
@@ -94,7 +94,7 @@
     sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
         cc::AnimationEvent::Started,
         0,
-        group_id,
+        sequence.animation_group_id(),
         cc::Animation::Opacity,
         (effective_start - base::TimeTicks()).InSecondsF()));
     sequence.Progress(effective_start + delta/2, &delegate);
@@ -139,8 +139,8 @@
       LayerAnimationElement::CreateTransformElement(target_transform, delta));
 
   for (int i = 0; i < 2; ++i) {
-    int group_id = 1;
-    sequence.set_animation_group_id(group_id);
+    int starting_group_id = 1;
+    sequence.set_animation_group_id(starting_group_id);
     start_time = opacity_effective_start + 4 * delta;
     sequence.set_start_time(start_time);
     delegate.SetOpacityFromAnimation(start_opacity);
@@ -150,10 +150,11 @@
     sequence.Progress(start_time, &delegate);
     EXPECT_FLOAT_EQ(0.0, sequence.last_progressed_fraction());
     opacity_effective_start = start_time + delta;
+    EXPECT_EQ(starting_group_id, sequence.animation_group_id());
     sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
         cc::AnimationEvent::Started,
         0,
-        group_id,
+        sequence.animation_group_id(),
         cc::Animation::Opacity,
         (opacity_effective_start - base::TimeTicks()).InSecondsF()));
     sequence.Progress(opacity_effective_start + delta/2, &delegate);
@@ -180,10 +181,11 @@
                             delegate.GetTransformForAnimation());
     EXPECT_FLOAT_EQ(0.0, sequence.last_progressed_fraction());
     transform_effective_start = opacity_effective_start + 3 * delta;
+    EXPECT_NE(starting_group_id, sequence.animation_group_id());
     sequence.OnThreadedAnimationStarted(cc::AnimationEvent(
         cc::AnimationEvent::Started,
         0,
-        group_id,
+        sequence.animation_group_id(),
         cc::Animation::Transform,
         (transform_effective_start - base::TimeTicks()).InSecondsF()));
     sequence.Progress(transform_effective_start + delta/2, &delegate);
diff --git a/ui/compositor/test_web_graphics_context_3d.cc b/ui/compositor/test_web_graphics_context_3d.cc
deleted file mode 100644
index d8febc9..0000000
--- a/ui/compositor/test_web_graphics_context_3d.cc
+++ /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.
-
-#include "ui/compositor/test_web_graphics_context_3d.h"
-
-#include "ui/gl/gl_bindings.h"
-#include "ui/gl/gl_context_stub.h"
-#include "ui/gl/gl_surface_stub.h"
-
-namespace ui {
-
-TestWebGraphicsContext3D::TestWebGraphicsContext3D()
-    : next_texture_id_(1) {}
-
-TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {}
-
-void TestWebGraphicsContext3D::Initialize() {
-  gl_surface_ = new gfx::GLSurfaceStub;
-  gl_context_ = new gfx::GLContextStub;
-  gl_context_->MakeCurrent(gl_surface_.get());
-}
-
-bool TestWebGraphicsContext3D::makeContextCurrent() {
-  return true;
-}
-
-int TestWebGraphicsContext3D::width() {
-  return 0;
-}
-
-int TestWebGraphicsContext3D::height() {
-  return 0;
-}
-
-bool TestWebGraphicsContext3D::isContextLost() {
-  return false;
-}
-
-void* TestWebGraphicsContext3D::mapBufferSubDataCHROMIUM(
-    WebKit::WGC3Denum target,
-    WebKit::WGC3Dintptr offset,
-    WebKit::WGC3Dsizeiptr size,
-    WebKit::WGC3Denum access) {
-  return 0;
-}
-
-void* TestWebGraphicsContext3D::mapTexSubImage2DCHROMIUM(
-    WebKit::WGC3Denum target,
-    WebKit::WGC3Dint level,
-    WebKit::WGC3Dint xoffset,
-    WebKit::WGC3Dint yoffset,
-    WebKit::WGC3Dsizei width,
-    WebKit::WGC3Dsizei height,
-    WebKit::WGC3Denum format,
-    WebKit::WGC3Denum type,
-    WebKit::WGC3Denum access) {
-  return 0;
-}
-
-WebKit::WebString TestWebGraphicsContext3D::getRequestableExtensionsCHROMIUM() {
-  return WebKit::WebString();
-}
-
-WebKit::WGC3Denum TestWebGraphicsContext3D::checkFramebufferStatus(
-    WebKit::WGC3Denum target) {
-  return GL_FRAMEBUFFER_COMPLETE;
-}
-
-bool TestWebGraphicsContext3D::getActiveAttrib(WebKit::WebGLId program,
-                                               WebKit::WGC3Duint index,
-                                               ActiveInfo& info) {
-  return false;
-}
-
-bool TestWebGraphicsContext3D::getActiveUniform(WebKit::WebGLId program,
-                                                WebKit::WGC3Duint index,
-                                                ActiveInfo& info) {
-  return false;
-}
-
-WebKit::WGC3Dint TestWebGraphicsContext3D::getAttribLocation(
-    WebKit::WebGLId program,
-    const WebKit::WGC3Dchar* name) {
-  return 0;
-}
-
-TestWebGraphicsContext3D::Attributes
-TestWebGraphicsContext3D::getContextAttributes() {
-  return Attributes();
-}
-
-WebKit::WGC3Denum TestWebGraphicsContext3D::getError() {
-  return 0;
-}
-
-void TestWebGraphicsContext3D::getIntegerv(WebKit::WGC3Denum pname,
-                                           WebKit::WGC3Dint* value) {
-  if (pname == GL_MAX_TEXTURE_SIZE)
-    *value = 1024;
-  else if (pname == GL_ACTIVE_TEXTURE)
-    *value = GL_TEXTURE0;
-}
-
-void TestWebGraphicsContext3D::getProgramiv(WebKit::WebGLId program,
-                                            WebKit::WGC3Denum pname,
-                                            WebKit::WGC3Dint* value) {
-  if (pname == GL_LINK_STATUS)
-    *value = 1;
-}
-
-WebKit::WebString TestWebGraphicsContext3D::getProgramInfoLog(
-    WebKit::WebGLId program) {
-  return WebKit::WebString();
-}
-
-void TestWebGraphicsContext3D::getShaderiv(WebKit::WebGLId shader,
-                                           WebKit::WGC3Denum pname,
-                                           WebKit::WGC3Dint* value) {
-  if (pname == GL_COMPILE_STATUS)
-    *value = 1;
-}
-
-WebKit::WebString TestWebGraphicsContext3D::getShaderInfoLog(
-    WebKit::WebGLId shader) {
-  return WebKit::WebString();
-}
-
-WebKit::WebString TestWebGraphicsContext3D::getShaderSource(
-    WebKit::WebGLId shader) {
-  return WebKit::WebString();
-}
-
-WebKit::WebString TestWebGraphicsContext3D::getString(WebKit::WGC3Denum name) {
-  return WebKit::WebString();
-}
-
-WebKit::WGC3Dint TestWebGraphicsContext3D::getUniformLocation(
-    WebKit::WebGLId program,
-    const WebKit::WGC3Dchar* name) {
-  return 0;
-}
-
-WebKit::WGC3Dsizeiptr TestWebGraphicsContext3D::getVertexAttribOffset(
-    WebKit::WGC3Duint index,
-    WebKit::WGC3Denum pname) {
-  return 0;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isBuffer(
-    WebKit::WebGLId buffer) {
-  return false;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isEnabled(
-    WebKit::WGC3Denum cap) {
-  return false;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isFramebuffer(
-    WebKit::WebGLId framebuffer) {
-  return false;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isProgram(
-    WebKit::WebGLId program) {
-  return false;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isRenderbuffer(
-    WebKit::WebGLId renderbuffer) {
-  return false;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isShader(
-    WebKit::WebGLId shader) {
-  return false;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isTexture(
-    WebKit::WebGLId texture) {
-  return false;
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::createBuffer() {
-  return 1;
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::createFramebuffer() {
-  return 1;
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::createProgram() {
-  return 1;
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::createRenderbuffer() {
-  return 1;
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::createShader(
-    WebKit::WGC3Denum value) {
-  return 1;
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::createTexture() {
-  return next_texture_id_++;
-}
-
-WebKit::WebGLId TestWebGraphicsContext3D::createQueryEXT()
-{
-  return 1;
-}
-
-WebKit::WGC3Dboolean TestWebGraphicsContext3D::isQueryEXT(WebKit::WebGLId)
-{
-  return true;
-}
-
-}  // namespace ui
diff --git a/ui/compositor/test_web_graphics_context_3d.h b/ui/compositor/test_web_graphics_context_3d.h
deleted file mode 100644
index f7a9622..0000000
--- a/ui/compositor/test_web_graphics_context_3d.h
+++ /dev/null
@@ -1,450 +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_COMPOSITOR_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
-#define UI_COMPOSITOR_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
-
-#include "base/logging.h"
-#include "base/memory/ref_counted.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "ui/compositor/compositor_export.h"
-
-namespace gfx {
-class GLContext;
-class GLSurface;
-}
-
-namespace ui {
-
-// WebGraphicsContext3D that does nothing. Suitable for testing.
-class COMPOSITOR_EXPORT TestWebGraphicsContext3D :
-    public NON_EXPORTED_BASE(WebKit::WebGraphicsContext3D) {
- public:
-  TestWebGraphicsContext3D();
-  virtual ~TestWebGraphicsContext3D();
-
-  void Initialize();
-  virtual bool makeContextCurrent();
-  virtual int width();
-  virtual int height();
-  virtual void reshape(int width, int height) {}
-  virtual void prepareTexture() {}
-  virtual void postSubBufferCHROMIUM(int x, int y, int width, int height) {}
-  virtual void synthesizeGLError(WebKit::WGC3Denum value) {}
-  virtual bool isContextLost();
-  virtual void* mapBufferSubDataCHROMIUM(WebKit::WGC3Denum target,
-                                         WebKit::WGC3Dintptr offset,
-                                         WebKit::WGC3Dsizeiptr size,
-                                         WebKit::WGC3Denum access);
-  virtual void unmapBufferSubDataCHROMIUM(const void* data) {}
-  virtual void* mapTexSubImage2DCHROMIUM(WebKit::WGC3Denum target,
-                                         WebKit::WGC3Dint level,
-                                         WebKit::WGC3Dint xoffset,
-                                         WebKit::WGC3Dint yoffset,
-                                         WebKit::WGC3Dsizei width,
-                                         WebKit::WGC3Dsizei height,
-                                         WebKit::WGC3Denum format,
-                                         WebKit::WGC3Denum type,
-                                         WebKit::WGC3Denum access);
-  virtual void unmapTexSubImage2DCHROMIUM(const void* data) {}
-  virtual void setVisibilityCHROMIUM(bool visible) {}
-  virtual void discardFramebufferEXT(WebKit::WGC3Denum target,
-                                     WebKit::WGC3Dsizei numAttachments,
-                                     const WebKit::WGC3Denum* attachments) {}
-  virtual void setMemoryAllocationChangedCallbackCHROMIUM(
-      WebGraphicsMemoryAllocationChangedCallbackCHROMIUM*) { }
-  virtual WebKit::WebString getRequestableExtensionsCHROMIUM();
-  virtual void requestExtensionCHROMIUM(const char*) {}
-  virtual void blitFramebufferCHROMIUM(WebKit::WGC3Dint src_x0,
-                                       WebKit::WGC3Dint src_y0,
-                                       WebKit::WGC3Dint src_x1,
-                                       WebKit::WGC3Dint src_y1,
-                                       WebKit::WGC3Dint dst_x0,
-                                       WebKit::WGC3Dint dst_y0,
-                                       WebKit::WGC3Dint dst_x1,
-                                       WebKit::WGC3Dint dst_y1,
-                                       WebKit::WGC3Dbitfield mask,
-                                       WebKit::WGC3Denum filter) {}
-  virtual void renderbufferStorageMultisampleCHROMIUM(
-      WebKit::WGC3Denum target,
-      WebKit::WGC3Dsizei samples,
-      WebKit::WGC3Denum internalformat,
-      WebKit::WGC3Dsizei width,
-      WebKit::WGC3Dsizei height) {}
-  virtual void activeTexture(WebKit::WGC3Denum texture) {}
-  virtual void attachShader(WebKit::WebGLId program, WebKit::WebGLId shader) {}
-  virtual void bindAttribLocation(WebKit::WebGLId program,
-                                  WebKit::WGC3Duint index,
-                                  const WebKit::WGC3Dchar* name) {}
-  virtual void bindBuffer(WebKit::WGC3Denum target, WebKit::WebGLId buffer) {}
-  virtual void bindFramebuffer(WebKit::WGC3Denum target,
-                               WebKit::WebGLId framebuffer) {}
-  virtual void bindRenderbuffer(WebKit::WGC3Denum target,
-                                WebKit::WebGLId renderbuffer) {}
-  virtual void bindTexture(WebKit::WGC3Denum target, WebKit::WebGLId texture) {}
-  virtual void blendColor(WebKit::WGC3Dclampf red,
-                          WebKit::WGC3Dclampf green,
-                          WebKit::WGC3Dclampf blue,
-                          WebKit::WGC3Dclampf alpha) {}
-  virtual void blendEquation(WebKit::WGC3Denum mode) {}
-  virtual void blendEquationSeparate(WebKit::WGC3Denum modeRGB,
-                                     WebKit::WGC3Denum modeAlpha) {}
-  virtual void blendFunc(WebKit::WGC3Denum sfactor,
-                         WebKit::WGC3Denum dfactor) {}
-  virtual void blendFuncSeparate(WebKit::WGC3Denum src_rgb,
-                                 WebKit::WGC3Denum dst_rgb,
-                                 WebKit::WGC3Denum src_alpha,
-                                 WebKit::WGC3Denum dst_alpha) {}
-  virtual void bufferData(WebKit::WGC3Denum target,
-                          WebKit::WGC3Dsizeiptr size,
-                          const void* data,
-                          WebKit::WGC3Denum usage) {}
-  virtual void bufferSubData(WebKit::WGC3Denum target,
-                             WebKit::WGC3Dintptr offset,
-                             WebKit::WGC3Dsizeiptr size,
-                             const void* data) {}
-  virtual WebKit::WGC3Denum checkFramebufferStatus(WebKit::WGC3Denum target);
-  virtual void clear(WebKit::WGC3Dbitfield mask) {}
-  virtual void clearColor(WebKit::WGC3Dclampf red,
-                          WebKit::WGC3Dclampf green,
-                          WebKit::WGC3Dclampf blue,
-                          WebKit::WGC3Dclampf alpha) {}
-  virtual void clearDepth(WebKit::WGC3Dclampf depth) {}
-  virtual void clearStencil(WebKit::WGC3Dint s) {}
-  virtual void colorMask(WebKit::WGC3Dboolean red,
-                         WebKit::WGC3Dboolean green,
-                         WebKit::WGC3Dboolean blue,
-                         WebKit::WGC3Dboolean alpha) {}
-  virtual void compileShader(WebKit::WebGLId shader) {}
-  virtual void compressedTexImage2D(WebKit::WGC3Denum target,
-                                    WebKit::WGC3Dint level,
-                                    WebKit::WGC3Denum internalformat,
-                                    WebKit::WGC3Dsizei width,
-                                    WebKit::WGC3Dsizei height,
-                                    WebKit::WGC3Dint border,
-                                    WebKit::WGC3Dsizei imageSize,
-                                    const void* data) {}
-  virtual void compressedTexSubImage2D(WebKit::WGC3Denum target,
-                                       WebKit::WGC3Dint level,
-                                       WebKit::WGC3Dint xoffset,
-                                       WebKit::WGC3Dint yoffset,
-                                       WebKit::WGC3Dsizei width,
-                                       WebKit::WGC3Dsizei height,
-                                       WebKit::WGC3Denum format,
-                                       WebKit::WGC3Dsizei imageSize,
-                                       const void* data) {}
-  virtual void copyTexImage2D(WebKit::WGC3Denum target,
-                              WebKit::WGC3Dint level,
-                              WebKit::WGC3Denum internal_format,
-                              WebKit::WGC3Dint x,
-                              WebKit::WGC3Dint y,
-                              WebKit::WGC3Dsizei width,
-                              WebKit::WGC3Dsizei height,
-                              WebKit::WGC3Dint border) {}
-  virtual void copyTexSubImage2D(WebKit::WGC3Denum target,
-                                 WebKit::WGC3Dint level,
-                                 WebKit::WGC3Dint xoffset,
-                                 WebKit::WGC3Dint yoffset,
-                                 WebKit::WGC3Dint x,
-                                 WebKit::WGC3Dint y,
-                                 WebKit::WGC3Dsizei width,
-                                 WebKit::WGC3Dsizei height) {}
-  virtual void cullFace(WebKit::WGC3Denum mode) {}
-  virtual void depthFunc(WebKit::WGC3Denum func) {}
-  virtual void depthMask(WebKit::WGC3Dboolean flag) {}
-  virtual void depthRange(WebKit::WGC3Dclampf z_near,
-                          WebKit::WGC3Dclampf z_far) {}
-  virtual void detachShader(WebKit::WebGLId program, WebKit::WebGLId shader) {}
-  virtual void disable(WebKit::WGC3Denum cap) {}
-  virtual void disableVertexAttribArray(WebKit::WGC3Duint index) {}
-  virtual void drawArrays(WebKit::WGC3Denum mode, WebKit::WGC3Dint first,
-                          WebKit::WGC3Dsizei count) {}
-  virtual void drawElements(WebKit::WGC3Denum mode,
-                            WebKit::WGC3Dsizei count,
-                            WebKit::WGC3Denum type,
-                            WebKit::WGC3Dintptr offset) {}
-  virtual void enable(WebKit::WGC3Denum cap) {}
-  virtual void enableVertexAttribArray(WebKit::WGC3Duint index) {}
-  virtual void finish() {}
-  virtual void flush() {}
-  virtual void framebufferRenderbuffer(WebKit::WGC3Denum target,
-                                       WebKit::WGC3Denum attachment,
-                                       WebKit::WGC3Denum renderbuffertarget,
-                                       WebKit::WebGLId renderbuffer) {}
-  virtual void framebufferTexture2D(WebKit::WGC3Denum target,
-                                    WebKit::WGC3Denum attachment,
-                                    WebKit::WGC3Denum textarget,
-                                    WebKit::WebGLId texture,
-                                    WebKit::WGC3Dint level) {}
-  virtual void frontFace(WebKit::WGC3Denum mode) {}
-  virtual void generateMipmap(WebKit::WGC3Denum target) {}
-  virtual bool getActiveAttrib(WebKit::WebGLId program,
-                               WebKit::WGC3Duint index,
-                               ActiveInfo& info);
-  virtual bool getActiveUniform(WebKit::WebGLId program,
-                                WebKit::WGC3Duint index,
-                                ActiveInfo& info);
-  virtual void getAttachedShaders(WebKit::WebGLId program,
-                                  WebKit::WGC3Dsizei maxCount,
-                                  WebKit::WGC3Dsizei* count,
-                                  WebKit::WebGLId* shaders) {}
-  virtual WebKit::WGC3Dint getAttribLocation(WebKit::WebGLId program,
-                                             const WebKit::WGC3Dchar* name);
-  virtual void getBooleanv(WebKit::WGC3Denum pname,
-                           WebKit::WGC3Dboolean* value) {}
-  virtual void getBufferParameteriv(WebKit::WGC3Denum target,
-                                    WebKit::WGC3Denum pname,
-                                    WebKit::WGC3Dint* value) {}
-  virtual Attributes getContextAttributes();
-  virtual WebKit::WGC3Denum getError();
-  virtual void getFloatv(WebKit::WGC3Denum pname, WebKit::WGC3Dfloat* value) {}
-  virtual void getFramebufferAttachmentParameteriv(WebKit::WGC3Denum target,
-                                                   WebKit::WGC3Denum attachment,
-                                                   WebKit::WGC3Denum pname,
-                                                   WebKit::WGC3Dint* value) {}
-  virtual void getIntegerv(WebKit::WGC3Denum pname, WebKit::WGC3Dint* value);
-  virtual void getProgramiv(WebKit::WebGLId program,
-                            WebKit::WGC3Denum pname,
-                            WebKit::WGC3Dint* value);
-  virtual WebKit::WebString getProgramInfoLog(WebKit::WebGLId program);
-  virtual void getRenderbufferParameteriv(WebKit::WGC3Denum target,
-                                          WebKit::WGC3Denum pname,
-                                          WebKit::WGC3Dint* value) {}
-  virtual void getShaderiv(WebKit::WebGLId shader,
-                           WebKit::WGC3Denum pname,
-                           WebKit::WGC3Dint* value);
-  virtual WebKit::WebString getShaderInfoLog(WebKit::WebGLId shader);
-  virtual void getShaderPrecisionFormat(WebKit::WGC3Denum shaderType,
-                                        WebKit::WGC3Denum precisionType,
-                                        WebKit::WGC3Dint* range,
-                                        WebKit::WGC3Dint* precision) {}
-  virtual WebKit::WebString getShaderSource(WebKit::WebGLId shader);
-  virtual WebKit::WebString getString(WebKit::WGC3Denum name);
-  virtual void getTexParameterfv(WebKit::WGC3Denum target,
-                                 WebKit::WGC3Denum pname,
-                                 WebKit::WGC3Dfloat* value) {}
-  virtual void getTexParameteriv(WebKit::WGC3Denum target,
-                                 WebKit::WGC3Denum pname,
-                                 WebKit::WGC3Dint* value) {}
-  virtual void getUniformfv(WebKit::WebGLId program,
-                            WebKit::WGC3Dint location,
-                            WebKit::WGC3Dfloat* value) {}
-  virtual void getUniformiv(WebKit::WebGLId program,
-                            WebKit::WGC3Dint location,
-                            WebKit::WGC3Dint* value) {}
-  virtual WebKit::WGC3Dint getUniformLocation(WebKit::WebGLId program,
-                                              const WebKit::WGC3Dchar* name);
-  virtual void getVertexAttribfv(WebKit::WGC3Duint index,
-                                 WebKit::WGC3Denum pname,
-                                 WebKit::WGC3Dfloat* value) {}
-  virtual void getVertexAttribiv(WebKit::WGC3Duint index,
-                                 WebKit::WGC3Denum pname,
-                                 WebKit::WGC3Dint* value) {}
-  virtual WebKit::WGC3Dsizeiptr getVertexAttribOffset(WebKit::WGC3Duint index,
-                                                      WebKit::WGC3Denum pname);
-  virtual void hint(WebKit::WGC3Denum target, WebKit::WGC3Denum mode) {}
-  virtual WebKit::WGC3Dboolean isBuffer(WebKit::WebGLId buffer);
-  virtual WebKit::WGC3Dboolean isEnabled(WebKit::WGC3Denum cap);
-  virtual WebKit::WGC3Dboolean isFramebuffer(WebKit::WebGLId framebuffer);
-  virtual WebKit::WGC3Dboolean isProgram(WebKit::WebGLId program);
-  virtual WebKit::WGC3Dboolean isRenderbuffer(WebKit::WebGLId renderbuffer);
-  virtual WebKit::WGC3Dboolean isShader(WebKit::WebGLId shader);
-  virtual WebKit::WGC3Dboolean isTexture(WebKit::WebGLId texture);
-  virtual void lineWidth(WebKit::WGC3Dfloat) {}
-  virtual void linkProgram(WebKit::WebGLId program) {}
-  virtual void pixelStorei(WebKit::WGC3Denum pname, WebKit::WGC3Dint param) {}
-  virtual void polygonOffset(WebKit::WGC3Dfloat factor,
-                             WebKit::WGC3Dfloat units) {}
-  virtual void readPixels(WebKit::WGC3Dint x,
-                          WebKit::WGC3Dint y,
-                          WebKit::WGC3Dsizei width,
-                          WebKit::WGC3Dsizei height,
-                          WebKit::WGC3Denum format,
-                          WebKit::WGC3Denum type,
-                          void* pixels) {}
-  virtual void releaseShaderCompiler() {}
-  virtual void renderbufferStorage(WebKit::WGC3Denum target,
-                                   WebKit::WGC3Denum internalformat,
-                                   WebKit::WGC3Dsizei width,
-                                   WebKit::WGC3Dsizei height) {}
-  virtual void sampleCoverage(WebKit::WGC3Dclampf value,
-                              WebKit::WGC3Dboolean invert) {}
-  virtual void scissor(WebKit::WGC3Dint x,
-                       WebKit::WGC3Dint y,
-                       WebKit::WGC3Dsizei width,
-                       WebKit::WGC3Dsizei height) {}
-  virtual void shaderSource(WebKit::WebGLId shader,
-                            const WebKit::WGC3Dchar* string) {}
-  virtual void stencilFunc(WebKit::WGC3Denum func,
-                           WebKit::WGC3Dint ref,
-                           WebKit::WGC3Duint mask) {}
-  virtual void stencilFuncSeparate(WebKit::WGC3Denum face,
-                                   WebKit::WGC3Denum func,
-                                   WebKit::WGC3Dint ref,
-                                   WebKit::WGC3Duint mask) {}
-  virtual void stencilMask(WebKit::WGC3Duint mask) {}
-  virtual void stencilMaskSeparate(WebKit::WGC3Denum face,
-                                   WebKit::WGC3Duint mask) {}
-  virtual void stencilOp(WebKit::WGC3Denum fail,
-                         WebKit::WGC3Denum zfail,
-                         WebKit::WGC3Denum zpass) {}
-  virtual void stencilOpSeparate(WebKit::WGC3Denum face,
-                                 WebKit::WGC3Denum fail,
-                                 WebKit::WGC3Denum zfail,
-                                 WebKit::WGC3Denum zpass) {}
-  virtual void texImage2D(WebKit::WGC3Denum target,
-                          WebKit::WGC3Dint level,
-                          WebKit::WGC3Denum internal_format,
-                          WebKit::WGC3Dsizei width,
-                          WebKit::WGC3Dsizei height,
-                          WebKit::WGC3Dint border,
-                          WebKit::WGC3Denum format,
-                          WebKit::WGC3Denum type,
-                          const void* pixels) {}
-  virtual void texParameterf(WebKit::WGC3Denum target,
-                             WebKit::WGC3Denum pname,
-                             WebKit::WGC3Dfloat param) {}
-  virtual void texParameteri(WebKit::WGC3Denum target,
-                             WebKit::WGC3Denum pname,
-                             WebKit::WGC3Dint param) {}
-  virtual void texSubImage2D(WebKit::WGC3Denum target,
-                             WebKit::WGC3Dint level,
-                             WebKit::WGC3Dint xoffset,
-                             WebKit::WGC3Dint yoffset,
-                             WebKit::WGC3Dsizei width,
-                             WebKit::WGC3Dsizei height,
-                             WebKit::WGC3Denum format,
-                             WebKit::WGC3Denum type,
-                             const void* pixels) {}
-  virtual void uniform1f(WebKit::WGC3Dint location, WebKit::WGC3Dfloat x) {}
-  virtual void uniform1fv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dfloat* v) {}
-  virtual void uniform1i(WebKit::WGC3Dint location, WebKit::WGC3Dint x) {}
-  virtual void uniform1iv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dint* v) {}
-  virtual void uniform2f(WebKit::WGC3Dint location,
-                         WebKit::WGC3Dfloat x,
-                         WebKit::WGC3Dfloat y) {}
-  virtual void uniform2fv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dfloat* v) {}
-  virtual void uniform2i(WebKit::WGC3Dint location,
-                         WebKit::WGC3Dint x,
-                         WebKit::WGC3Dint y) {}
-  virtual void uniform2iv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dint* v) {}
-  virtual void uniform3f(WebKit::WGC3Dint location,
-                         WebKit::WGC3Dfloat x,
-                         WebKit::WGC3Dfloat y,
-                         WebKit::WGC3Dfloat z) {}
-  virtual void uniform3fv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dfloat* v) {}
-  virtual void uniform3i(WebKit::WGC3Dint location,
-                         WebKit::WGC3Dint x,
-                         WebKit::WGC3Dint y,
-                         WebKit::WGC3Dint z) {}
-  virtual void uniform3iv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dint* v) {}
-  virtual void uniform4f(WebKit::WGC3Dint location,
-                         WebKit::WGC3Dfloat x,
-                         WebKit::WGC3Dfloat y,
-                         WebKit::WGC3Dfloat z,
-                         WebKit::WGC3Dfloat w) {}
-  virtual void uniform4fv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dfloat* v) {}
-  virtual void uniform4i(WebKit::WGC3Dint location,
-                         WebKit::WGC3Dint x,
-                         WebKit::WGC3Dint y,
-                         WebKit::WGC3Dint z,
-                         WebKit::WGC3Dint w) {}
-  virtual void uniform4iv(WebKit::WGC3Dint location,
-                          WebKit::WGC3Dsizei count,
-                          const WebKit::WGC3Dint* v) {}
-  virtual void uniformMatrix2fv(WebKit::WGC3Dint location,
-                                WebKit::WGC3Dsizei count,
-                                WebKit::WGC3Dboolean transpose,
-                                const WebKit::WGC3Dfloat* value) {}
-  virtual void uniformMatrix3fv(WebKit::WGC3Dint location,
-                                WebKit::WGC3Dsizei count,
-                                WebKit::WGC3Dboolean transpose,
-                                const WebKit::WGC3Dfloat* value) {}
-  virtual void uniformMatrix4fv(WebKit::WGC3Dint location,
-                                WebKit::WGC3Dsizei count,
-                                WebKit::WGC3Dboolean transpose,
-                                const WebKit::WGC3Dfloat* value) {}
-  virtual void useProgram(WebKit::WebGLId program) {}
-  virtual void validateProgram(WebKit::WebGLId program) {}
-  virtual void vertexAttrib1f(WebKit::WGC3Duint index, WebKit::WGC3Dfloat x) {}
-  virtual void vertexAttrib1fv(WebKit::WGC3Duint index,
-                               const WebKit::WGC3Dfloat* values) {}
-  virtual void vertexAttrib2f(WebKit::WGC3Duint index,
-                              WebKit::WGC3Dfloat x,
-                              WebKit::WGC3Dfloat y) {}
-  virtual void vertexAttrib2fv(WebKit::WGC3Duint index,
-                               const WebKit::WGC3Dfloat* values) {}
-  virtual void vertexAttrib3f(WebKit::WGC3Duint index,
-                              WebKit::WGC3Dfloat x,
-                              WebKit::WGC3Dfloat y,
-                              WebKit::WGC3Dfloat z) {}
-  virtual void vertexAttrib3fv(WebKit::WGC3Duint index,
-                               const WebKit::WGC3Dfloat* values) {}
-  virtual void vertexAttrib4f(WebKit::WGC3Duint index,
-                              WebKit::WGC3Dfloat x,
-                              WebKit::WGC3Dfloat y,
-                              WebKit::WGC3Dfloat z,
-                              WebKit::WGC3Dfloat w) {}
-  virtual void vertexAttrib4fv(WebKit::WGC3Duint index,
-                               const WebKit::WGC3Dfloat* values) {}
-  virtual void vertexAttribPointer(WebKit::WGC3Duint index,
-                                   WebKit::WGC3Dint size,
-                                   WebKit::WGC3Denum type,
-                                   WebKit::WGC3Dboolean normalized,
-                                   WebKit::WGC3Dsizei stride,
-                                   WebKit::WGC3Dintptr offset) {}
-  virtual void viewport(WebKit::WGC3Dint x,
-                        WebKit::WGC3Dint y,
-                        WebKit::WGC3Dsizei width,
-                        WebKit::WGC3Dsizei height) {}
-  virtual WebKit::WebGLId createBuffer();
-  virtual WebKit::WebGLId createFramebuffer();
-  virtual WebKit::WebGLId createProgram();
-  virtual WebKit::WebGLId createRenderbuffer();
-  virtual WebKit::WebGLId createShader(WebKit::WGC3Denum value);
-  virtual WebKit::WebGLId createTexture();
-  virtual void deleteBuffer(WebKit::WebGLId) {}
-  virtual void deleteFramebuffer(WebKit::WebGLId) {}
-  virtual void deleteProgram(WebKit::WebGLId) {}
-  virtual void deleteRenderbuffer(WebKit::WebGLId) {}
-  virtual void deleteShader(WebKit::WebGLId) {}
-  virtual void deleteTexture(WebKit::WebGLId) {}
-  virtual WebKit::WebGLId createQueryEXT();
-  virtual void deleteQueryEXT(WebKit::WebGLId) {};
-  virtual WebKit::WGC3Dboolean isQueryEXT(WebKit::WebGLId query);
-  virtual void beginQueryEXT(WebKit::WGC3Denum, WebKit::WebGLId) {}
-  virtual void endQueryEXT(WebKit::WGC3Denum) {}
-  virtual void getQueryivEXT(WebKit::WGC3Denum,
-                             WebKit::WGC3Denum,
-                             WebKit::WGC3Dint*) {}
-  virtual void getQueryObjectuivEXT(WebKit::WebGLId,
-                                    WebKit::WGC3Denum,
-                                    WebKit::WGC3Duint*) {}
-
- private:
-  scoped_refptr<gfx::GLContext> gl_context_;
-  scoped_refptr<gfx::GLSurface> gl_surface_;
-  unsigned next_texture_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWebGraphicsContext3D);
-};
-
-}  // namespace ui
-
-#endif  // UI_COMPOSITOR_TEST_WEB_GRAPHICS_CONTEXT_3D_H_
diff --git a/ui/compositor/transform_animation_curve_adapter.cc b/ui/compositor/transform_animation_curve_adapter.cc
index 96500b3..4b493bc 100644
--- a/ui/compositor/transform_animation_curve_adapter.cc
+++ b/ui/compositor/transform_animation_curve_adapter.cc
@@ -51,4 +51,13 @@
   return gfx::ComposeTransform(to_return);
 }
 
+bool TransformAnimationCurveAdapter::AnimatedBoundsForBox(
+    const gfx::BoxF& box,
+    gfx::BoxF* bounds) const {
+  // TODO(ajuma): Once cc::TransformOperation::BlendedBoundsForBox supports
+  // computing bounds for TransformOperationMatrix, use that to compute
+  // the bounds we need here.
+  return false;
+}
+
 }  // namespace ui
diff --git a/ui/compositor/transform_animation_curve_adapter.h b/ui/compositor/transform_animation_curve_adapter.h
index 7b6bdce..e721550 100644
--- a/ui/compositor/transform_animation_curve_adapter.h
+++ b/ui/compositor/transform_animation_curve_adapter.h
@@ -26,6 +26,8 @@
   virtual double Duration() const OVERRIDE;
   virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE;
   virtual gfx::Transform GetValue(double t) const OVERRIDE;
+  virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
+                                    gfx::BoxF* bounds) const OVERRIDE;
 
  private:
   Tween::Type tween_type_;
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index 2b0f504..b59d2a0 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -11,7 +11,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size_conversions.h"
 #include "ui/gfx/skia_util.h"
@@ -23,13 +23,11 @@
 
 namespace gfx {
 
-Canvas::Canvas(const gfx::Size& size,
-               ui::ScaleFactor scale_factor,
-               bool is_opaque)
-      : scale_factor_(scale_factor),
-        canvas_(NULL) {
-  gfx::Size pixel_size = gfx::ToCeiledSize(
-      gfx::ScaleSize(size, ui::GetScaleFactorScale(scale_factor)));
+Canvas::Canvas(const Size& size, ui::ScaleFactor scale_factor, bool is_opaque)
+    : scale_factor_(scale_factor),
+      canvas_(NULL) {
+  Size pixel_size = ToCeiledSize(
+      ScaleSize(size, ui::GetScaleFactorScale(scale_factor)));
   owned_canvas_ = skia::AdoptRef(skia::CreatePlatformCanvas(pixel_size.width(),
                                                             pixel_size.height(),
                                                             is_opaque));
@@ -45,7 +43,7 @@
   canvas_->scale(scale, scale);
 }
 
-Canvas::Canvas(const gfx::ImageSkiaRep& image_rep, bool is_opaque)
+Canvas::Canvas(const ImageSkiaRep& image_rep, bool is_opaque)
     : scale_factor_(image_rep.scale_factor()),
       owned_canvas_(skia::AdoptRef(
           skia::CreatePlatformCanvas(image_rep.pixel_width(),
@@ -54,7 +52,7 @@
       canvas_(owned_canvas_.get()) {
   SkScalar scale = SkFloatToScalar(ui::GetScaleFactorScale(scale_factor_));
   canvas_->scale(scale, scale);
-  DrawImageInt(gfx::ImageSkia(image_rep), 0, 0);
+  DrawImageInt(ImageSkia(image_rep), 0, 0);
 }
 
 Canvas::Canvas()
@@ -72,12 +70,12 @@
   return new Canvas(canvas, scale_factor);
 }
 
-void Canvas::RecreateBackingCanvas(const gfx::Size& size,
+void Canvas::RecreateBackingCanvas(const Size& size,
                                    ui::ScaleFactor scale_factor,
                                    bool is_opaque) {
   scale_factor_ = scale_factor;
-  gfx::Size pixel_size = gfx::ToFlooredSize(
-      gfx::ScaleSize(size, ui::GetScaleFactorScale(scale_factor)));
+  Size pixel_size = ToFlooredSize(
+      ScaleSize(size, ui::GetScaleFactorScale(scale_factor)));
   owned_canvas_ = skia::AdoptRef(skia::CreatePlatformCanvas(pixel_size.width(),
                                                             pixel_size.height(),
                                                             is_opaque));
@@ -87,9 +85,27 @@
 }
 
 // static
-int Canvas::GetStringWidth(const base::string16& text, const gfx::Font& font) {
+void Canvas::SizeStringInt(const base::string16& text,
+                           const Font& font,
+                           int* width,
+                           int* height,
+                           int line_height,
+                           int flags) {
+  SizeStringInt(text, FontList(font), width, height, line_height, flags);
+}
+
+// static
+int Canvas::GetStringWidth(const base::string16& text,
+                           const FontList& font_list) {
   int width = 0, height = 0;
-  Canvas::SizeStringInt(text, font, &width, &height, 0, NO_ELLIPSIS);
+  SizeStringInt(text, font_list, &width, &height, 0, NO_ELLIPSIS);
+  return width;
+}
+
+// static
+int Canvas::GetStringWidth(const base::string16& text, const Font& font) {
+  int width = 0, height = 0;
+  SizeStringInt(text, FontList(font), &width, &height, 0, NO_ELLIPSIS);
   return width;
 }
 
@@ -98,7 +114,20 @@
   return base::i18n::IsRTL() ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
 }
 
-gfx::ImageSkiaRep Canvas::ExtractImageRep() const {
+void Canvas::DrawStringWithHalo(const base::string16& text,
+                                const Font& font,
+                                SkColor text_color,
+                                SkColor halo_color_in,
+                                int x,
+                                int y,
+                                int w,
+                                int h,
+                                int flags) {
+  DrawStringRectWithHalo(text, FontList(font), text_color, halo_color_in,
+                         Rect(x, y, w, h), flags);
+}
+
+ImageSkiaRep Canvas::ExtractImageRep() const {
   const SkBitmap& device_bitmap = canvas_->getDevice()->accessBitmap(false);
 
   // Make a bitmap to return, and a canvas to draw into it. We don't just want
@@ -107,10 +136,10 @@
   SkBitmap result;
   device_bitmap.copyTo(&result, SkBitmap::kARGB_8888_Config);
 
-  return gfx::ImageSkiaRep(result, scale_factor_);
+  return ImageSkiaRep(result, scale_factor_);
 }
 
-void Canvas::DrawDashedRect(const gfx::Rect& rect, SkColor color) {
+void Canvas::DrawDashedRect(const Rect& rect, SkColor color) {
   // Create a 2D bitmap containing alternating on/off pixels - we do this
   // so that you never get two pixels of the same color around the edges
   // of the focus rect (this may mean that opposing edges of the rect may
@@ -149,11 +178,11 @@
   SkPaint paint;
   paint.setShader(shader.get());
 
-  DrawRect(gfx::Rect(rect.x(), rect.y(), rect.width(), 1), paint);
-  DrawRect(gfx::Rect(rect.x(), rect.y() + rect.height() - 1, rect.width(), 1),
+  DrawRect(Rect(rect.x(), rect.y(), rect.width(), 1), paint);
+  DrawRect(Rect(rect.x(), rect.y() + rect.height() - 1, rect.width(), 1),
            paint);
-  DrawRect(gfx::Rect(rect.x(), rect.y(), 1, rect.height()), paint);
-  DrawRect(gfx::Rect(rect.x() + rect.width() - 1, rect.y(), 1, rect.height()),
+  DrawRect(Rect(rect.x(), rect.y(), 1, rect.height()), paint);
+  DrawRect(Rect(rect.x() + rect.width() - 1, rect.y(), 1, rect.height()),
            paint);
 }
 
@@ -166,8 +195,8 @@
 }
 
 
-void Canvas::SaveLayerAlpha(uint8 alpha, const gfx::Rect& layer_bounds) {
-  SkRect bounds(gfx::RectToSkRect(layer_bounds));
+void Canvas::SaveLayerAlpha(uint8 alpha, const Rect& layer_bounds) {
+  SkRect bounds(RectToSkRect(layer_bounds));
   canvas_->saveLayerAlpha(&bounds, alpha);
 }
 
@@ -175,22 +204,22 @@
   canvas_->restore();
 }
 
-bool Canvas::ClipRect(const gfx::Rect& rect) {
-  return canvas_->clipRect(gfx::RectToSkRect(rect));
+bool Canvas::ClipRect(const Rect& rect) {
+  return canvas_->clipRect(RectToSkRect(rect));
 }
 
 bool Canvas::ClipPath(const SkPath& path) {
   return canvas_->clipPath(path);
 }
 
-bool Canvas::GetClipBounds(gfx::Rect* bounds) {
+bool Canvas::GetClipBounds(Rect* bounds) {
   SkRect out;
   bool has_non_empty_clip = canvas_->getClipBounds(&out);
   bounds->SetRect(out.left(), out.top(), out.width(), out.height());
   return has_non_empty_clip;
 }
 
-void Canvas::Translate(const gfx::Vector2d& offset) {
+void Canvas::Translate(const Vector2d& offset) {
   canvas_->translate(SkIntToScalar(offset.x()), SkIntToScalar(offset.y()));
 }
 
@@ -206,11 +235,11 @@
   canvas_->drawColor(color, mode);
 }
 
-void Canvas::FillRect(const gfx::Rect& rect, SkColor color) {
+void Canvas::FillRect(const Rect& rect, SkColor color) {
   FillRect(rect, color, SkXfermode::kSrcOver_Mode);
 }
 
-void Canvas::FillRect(const gfx::Rect& rect,
+void Canvas::FillRect(const Rect& rect,
                       SkColor color,
                       SkXfermode::Mode mode) {
   SkPaint paint;
@@ -220,11 +249,11 @@
   DrawRect(rect, paint);
 }
 
-void Canvas::DrawRect(const gfx::Rect& rect, SkColor color) {
+void Canvas::DrawRect(const Rect& rect, SkColor color) {
   DrawRect(rect, color, SkXfermode::kSrcOver_Mode);
 }
 
-void Canvas::DrawRect(const gfx::Rect& rect,
+void Canvas::DrawRect(const Rect& rect,
                       SkColor color,
                       SkXfermode::Mode mode) {
   SkPaint paint;
@@ -239,38 +268,34 @@
   DrawRect(rect, paint);
 }
 
-void Canvas::DrawRect(const gfx::Rect& rect, const SkPaint& paint) {
+void Canvas::DrawRect(const Rect& rect, const SkPaint& paint) {
   canvas_->drawIRect(RectToSkIRect(rect), paint);
 }
 
-void Canvas::DrawPoint(const gfx::Point& p1, const SkPaint& paint) {
+void Canvas::DrawPoint(const Point& p1, const SkPaint& paint) {
   canvas_->drawPoint(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()), paint);
 }
 
-void Canvas::DrawLine(const gfx::Point& p1,
-                      const gfx::Point& p2,
-                      SkColor color) {
+void Canvas::DrawLine(const Point& p1, const Point& p2, SkColor color) {
   SkPaint paint;
   paint.setColor(color);
   paint.setStrokeWidth(SkIntToScalar(1));
   DrawLine(p1, p2, paint);
 }
 
-void Canvas::DrawLine(const gfx::Point& p1,
-                      const gfx::Point& p2,
-                      const SkPaint& paint) {
+void Canvas::DrawLine(const Point& p1, const Point& p2, const SkPaint& paint) {
   canvas_->drawLine(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()),
                     SkIntToScalar(p2.x()), SkIntToScalar(p2.y()), paint);
 }
 
-void Canvas::DrawCircle(const gfx::Point& center_point,
+void Canvas::DrawCircle(const Point& center_point,
                         int radius,
                         const SkPaint& paint) {
   canvas_->drawCircle(SkIntToScalar(center_point.x()),
       SkIntToScalar(center_point.y()), SkIntToScalar(radius), paint);
 }
 
-void Canvas::DrawRoundRect(const gfx::Rect& rect,
+void Canvas::DrawRoundRect(const Rect& rect,
                            int radius,
                            const SkPaint& paint) {
   canvas_->drawRoundRect(RectToSkRect(rect), SkIntToScalar(radius),
@@ -281,25 +306,26 @@
   canvas_->drawPath(path, paint);
 }
 
-void Canvas::DrawFocusRect(const gfx::Rect& rect) {
+void Canvas::DrawFocusRect(const Rect& rect) {
   DrawDashedRect(rect, SK_ColorGRAY);
 }
 
-void Canvas::DrawImageInt(const gfx::ImageSkia& image, int x, int y) {
+void Canvas::DrawImageInt(const ImageSkia& image, int x, int y) {
   SkPaint paint;
   DrawImageInt(image, x, y, paint);
 }
 
-void Canvas::DrawImageInt(const gfx::ImageSkia& image, int x, int y, uint8 a) {
+void Canvas::DrawImageInt(const ImageSkia& image, int x, int y, uint8 a) {
   SkPaint paint;
   paint.setAlpha(a);
   DrawImageInt(image, x, y, paint);
 }
 
-void Canvas::DrawImageInt(const gfx::ImageSkia& image,
-                          int x, int y,
+void Canvas::DrawImageInt(const ImageSkia& image,
+                          int x,
+                          int y,
                           const SkPaint& paint) {
-  const gfx::ImageSkiaRep& image_rep = GetImageRepToPaint(image);
+  const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
   if (image_rep.is_null())
     return;
   const SkBitmap& bitmap = image_rep.sk_bitmap();
@@ -315,18 +341,30 @@
   canvas_->restore();
 }
 
-void Canvas::DrawImageInt(const gfx::ImageSkia& image,
-                          int src_x, int src_y, int src_w, int src_h,
-                          int dest_x, int dest_y, int dest_w, int dest_h,
+void Canvas::DrawImageInt(const ImageSkia& image,
+                          int src_x,
+                          int src_y,
+                          int src_w,
+                          int src_h,
+                          int dest_x,
+                          int dest_y,
+                          int dest_w,
+                          int dest_h,
                           bool filter) {
   SkPaint p;
   DrawImageInt(image, src_x, src_y, src_w, src_h, dest_x, dest_y,
                dest_w, dest_h, filter, p);
 }
 
-void Canvas::DrawImageInt(const gfx::ImageSkia& image,
-                          int src_x, int src_y, int src_w, int src_h,
-                          int dest_x, int dest_y, int dest_w, int dest_h,
+void Canvas::DrawImageInt(const ImageSkia& image,
+                          int src_x,
+                          int src_y,
+                          int src_w,
+                          int src_h,
+                          int dest_x,
+                          int dest_y,
+                          int dest_w,
+                          int dest_h,
                           bool filter,
                           const SkPaint& paint) {
   DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
@@ -342,7 +380,7 @@
   float user_scale_x = static_cast<float>(dest_w) / src_w;
   float user_scale_y = static_cast<float>(dest_h) / src_h;
 
-  const gfx::ImageSkiaRep& image_rep = GetImageRepToPaint(image,
+  const ImageSkiaRep& image_rep = GetImageRepToPaint(image,
       user_scale_x, user_scale_y);
   if (image_rep.is_null())
     return;
@@ -373,7 +411,7 @@
   shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
   shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
 
-  skia::RefPtr<SkShader> shader = gfx::CreateImageRepShader(
+  skia::RefPtr<SkShader> shader = CreateImageRepShader(
       image_rep,
       SkShader::kRepeat_TileMode,
       shader_scale);
@@ -388,18 +426,18 @@
   canvas_->drawRect(dest_rect, p);
 }
 
-void Canvas::DrawImageInPath(const gfx::ImageSkia& image,
+void Canvas::DrawImageInPath(const ImageSkia& image,
                              int x,
                              int y,
                              const SkPath& path,
                              const SkPaint& paint) {
-  const gfx::ImageSkiaRep& image_rep = GetImageRepToPaint(image);
+  const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
   if (image_rep.is_null())
     return;
 
   SkMatrix matrix;
   matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
-  skia::RefPtr<SkShader> shader = gfx::CreateImageRepShader(
+  skia::RefPtr<SkShader> shader = CreateImageRepShader(
       image_rep,
       SkShader::kRepeat_TileMode,
       matrix);
@@ -409,55 +447,96 @@
   canvas_->drawPath(path, p);
 }
 
+void Canvas::DrawStringRect(const base::string16& text,
+                            const FontList& font_list,
+                            SkColor color,
+                            const Rect& display_rect) {
+  DrawStringRectWithFlags(text, font_list, color, display_rect,
+                          DefaultCanvasTextAlignment());
+}
+
+void Canvas::DrawStringRectWithFlags(const base::string16& text,
+                                     const FontList& font_list,
+                                     SkColor color,
+                                     const Rect& display_rect,
+                                     int flags) {
+  DrawStringRectWithShadows(text, font_list, color, display_rect, 0, flags,
+                            ShadowValues());
+}
+
 void Canvas::DrawStringInt(const base::string16& text,
-                           const gfx::Font& font,
+                           const Font& font,
                            SkColor color,
-                           int x, int y, int w, int h) {
+                           int x,
+                           int y,
+                           int w,
+                           int h) {
   DrawStringInt(text, font, color, x, y, w, h, DefaultCanvasTextAlignment());
 }
 
 void Canvas::DrawStringInt(const base::string16& text,
-                           const gfx::Font& font,
+                           const Font& font,
                            SkColor color,
-                           const gfx::Rect& display_rect) {
+                           const Rect& display_rect) {
   DrawStringInt(text, font, color, display_rect.x(), display_rect.y(),
                 display_rect.width(), display_rect.height());
 }
 
 void Canvas::DrawStringInt(const base::string16& text,
-                           const gfx::Font& font,
+                           const Font& font,
                            SkColor color,
-                           int x, int y, int w, int h,
+                           int x,
+                           int y,
+                           int w,
+                           int h,
                            int flags) {
-  DrawStringWithShadows(text,
-                        font,
-                        color,
-                        gfx::Rect(x, y, w, h),
-                        0,
-                        flags,
+  DrawStringWithShadows(text, font, color, Rect(x, y, w, h), 0, flags,
                         ShadowValues());
 }
 
-void Canvas::TileImageInt(const gfx::ImageSkia& image,
-                          int x, int y, int w, int h) {
+void Canvas::DrawStringWithShadows(const base::string16& text,
+                                   const Font& font,
+                                   SkColor color,
+                                   const Rect& text_bounds,
+                                   int line_height,
+                                   int flags,
+                                   const ShadowValues& shadows) {
+  DrawStringRectWithShadows(text, FontList(font), color, text_bounds,
+                            line_height, flags, shadows);
+}
+
+void Canvas::TileImageInt(const ImageSkia& image,
+                          int x,
+                          int y,
+                          int w,
+                          int h) {
   TileImageInt(image, 0, 0, x, y, w, h);
 }
 
-void Canvas::TileImageInt(const gfx::ImageSkia& image,
-                          int src_x, int src_y,
-                          int dest_x, int dest_y, int w, int h) {
+void Canvas::TileImageInt(const ImageSkia& image,
+                          int src_x,
+                          int src_y,
+                          int dest_x,
+                          int dest_y,
+                          int w,
+                          int h) {
   TileImageInt(image, src_x, src_y, 1.0f, 1.0f, dest_x, dest_y, w, h);
 }
 
-void Canvas::TileImageInt(const gfx::ImageSkia& image,
-                          int src_x, int src_y,
-                          float tile_scale_x, float tile_scale_y,
-                          int dest_x, int dest_y, int w, int h) {
+void Canvas::TileImageInt(const ImageSkia& image,
+                          int src_x,
+                          int src_y,
+                          float tile_scale_x,
+                          float tile_scale_y,
+                          int dest_x,
+                          int dest_y,
+                          int w,
+                          int h) {
   if (!IntersectsClipRectInt(dest_x, dest_y, w, h))
     return;
 
-  const gfx::ImageSkiaRep& image_rep = GetImageRepToPaint(image,
-      tile_scale_x, tile_scale_y);
+  const ImageSkiaRep& image_rep = GetImageRepToPaint(
+      image, tile_scale_x, tile_scale_y);
   if (image_rep.is_null())
     return;
 
@@ -467,7 +546,7 @@
   shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
   shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
 
-  skia::RefPtr<SkShader> shader = gfx::CreateImageRepShader(
+  skia::RefPtr<SkShader> shader = CreateImageRepShader(
       image_rep,
       SkShader::kRepeat_TileMode,
       shader_scale);
@@ -483,7 +562,7 @@
   canvas_->drawRect(dest_rect, paint);
 }
 
-gfx::NativeDrawingContext Canvas::BeginPlatformPaint() {
+NativeDrawingContext Canvas::BeginPlatformPaint() {
   return skia::BeginPlatformPaint(canvas_);
 }
 
@@ -509,21 +588,20 @@
                      SkIntToScalar(y + h));
 }
 
-bool Canvas::IntersectsClipRect(const gfx::Rect& rect) {
+bool Canvas::IntersectsClipRect(const Rect& rect) {
   return IntersectsClipRectInt(rect.x(), rect.y(),
                                rect.width(), rect.height());
 }
 
-const gfx::ImageSkiaRep& Canvas::GetImageRepToPaint(
-    const gfx::ImageSkia& image) const {
+const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const {
   return GetImageRepToPaint(image, 1.0f, 1.0f);
 }
 
-const gfx::ImageSkiaRep& Canvas::GetImageRepToPaint(
-    const gfx::ImageSkia& image,
+const ImageSkiaRep& Canvas::GetImageRepToPaint(
+    const ImageSkia& image,
     float user_additional_scale_x,
     float user_additional_scale_y) const {
-  const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(scale_factor_);
+  const ImageSkiaRep& image_rep = image.GetRepresentation(scale_factor_);
 
   if (!image_rep.is_null()) {
     SkMatrix m = canvas_->getTotalMatrix();
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index 8baa45c..c8996a2 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -20,6 +20,7 @@
 
 class Rect;
 class Font;
+class FontList;
 class Point;
 class Size;
 class Transform;
@@ -95,17 +96,15 @@
   // Creates canvas with provided DIP |size| and |scale_factor|.
   // If this canvas is not opaque, it's explicitly cleared to transparent before
   // being returned.
-  Canvas(const gfx::Size& size,
-         ui::ScaleFactor scale_factor,
-         bool is_opaque);
+  Canvas(const Size& size, ui::ScaleFactor scale_factor, bool is_opaque);
 
   // Constructs a canvas with the size and the scale factor of the
   // provided |image_rep|, and draws the |image_rep| into it.
-  Canvas(const gfx::ImageSkiaRep& image_rep, bool is_opaque);
+  Canvas(const ImageSkiaRep& image_rep, bool is_opaque);
 
   virtual ~Canvas();
 
-  // Creates a gfx::Canvas backed by an |sk_canvas| with |scale_factor|.
+  // Creates a Canvas backed by an |sk_canvas| with |scale_factor|.
   // |sk_canvas| is assumed to be already scaled based on |scale_factor|
   // so no additional scaling is applied.
   static Canvas* CreateCanvasWithoutScaling(SkCanvas* sk_canvas,
@@ -117,36 +116,47 @@
   // canvas after having initialized the canvas.
   // TODO(pkotwicz): Push the scale factor into skia::PlatformCanvas such that
   // this method can be private.
-  void RecreateBackingCanvas(const gfx::Size& size,
+  void RecreateBackingCanvas(const Size& size,
                              ui::ScaleFactor scale_factor,
                              bool is_opaque);
 
-  // Compute the size required to draw some text with the provided font.
+  // Compute the size required to draw some text with the provided fonts.
   // Attempts to fit the text with the provided width and height. Increases
   // height and then width as needed to make the text fit. This method
   // supports multiple lines. On Skia only a line_height can be specified and
   // specifying a 0 value for it will cause the default height to be used.
   static void SizeStringInt(const base::string16& text,
-                            const gfx::Font& font,
-                            int* width, int* height,
+                            const FontList& font_list,
+                            int* width,
+                            int* height,
+                            int line_height,
+                            int flags);
+  // Obsolete version.  Use the above version which takes FontList.
+  static void SizeStringInt(const base::string16& text,
+                            const Font& font,
+                            int* width,
+                            int* height,
                             int line_height,
                             int flags);
 
   // Returns the number of horizontal pixels needed to display the specified
-  // |text| with |font|.
-  static int GetStringWidth(const base::string16& text, const gfx::Font& font);
+  // |text| with |font_list|.
+  static int GetStringWidth(const base::string16& text,
+                            const FontList& font_list);
+  // Obsolete version.  Use the above version which takes FontList.
+  static int GetStringWidth(const base::string16& text, const Font& font);
 
   // Returns the default text alignment to be used when drawing text on a
-  // gfx::Canvas based on the directionality of the system locale language.
-  // This function is used by gfx::Canvas::DrawStringInt when the text alignment
+  // Canvas based on the directionality of the system locale language.
+  // This function is used by Canvas::DrawStringInt when the text alignment
   // is not specified.
   //
-  // This function returns either gfx::Canvas::TEXT_ALIGN_LEFT or
-  // gfx::Canvas::TEXT_ALIGN_RIGHT.
+  // This function returns either Canvas::TEXT_ALIGN_LEFT or
+  // Canvas::TEXT_ALIGN_RIGHT.
   static int DefaultCanvasTextAlignment();
 
   // Draws text with a 1-pixel halo around it of the given color.
-  // On Windows, it allows ClearType to be drawn to an otherwise transparenct
+  // On Windows, it allows ClearType to be drawn to an otherwise transparent
   //   bitmap for drag images. Drag images have only 1-bit of transparency, so
   //   we don't do any fancy blurring.
   // On Linux, text with halo is created by stroking it with 2px |halo_color|
@@ -154,18 +164,28 @@
   // On Mac, NOTIMPLEMENTED.
   //   TODO(dhollowa): Skia-native implementation is underway.  Cut over to
   //   that when ready.  http::/crbug.com/109946
+  void DrawStringRectWithHalo(const base::string16& text,
+                              const FontList& font_list,
+                              SkColor text_color,
+                              SkColor halo_color,
+                              const Rect& display_rect,
+                              int flags);
+  // Obsolete version.  Use the above version which takes FontList.
   void DrawStringWithHalo(const base::string16& text,
-                          const gfx::Font& font,
+                          const Font& font,
                           SkColor text_color,
                           SkColor halo_color,
-                          int x, int y, int w, int h,
+                          int x,
+                          int y,
+                          int w,
+                          int h,
                           int flags);
 
   // Extracts an ImageSkiaRep from the contents of this canvas.
-  gfx::ImageSkiaRep ExtractImageRep() const;
+  ImageSkiaRep ExtractImageRep() const;
 
   // Draws a dashed rectangle of the specified color.
-  void DrawDashedRect(const gfx::Rect& rect, SkColor color);
+  void DrawDashedRect(const Rect& rect, SkColor color);
 
   // Saves a copy of the drawing state onto a stack, operating on this copy
   // until a balanced call to Restore() is made.
@@ -176,7 +196,7 @@
   // |layer_bounds| are the bounds of the layer relative to the current
   // transform.
   void SaveLayerAlpha(uint8 alpha);
-  void SaveLayerAlpha(uint8 alpha, const gfx::Rect& layer_bounds);
+  void SaveLayerAlpha(uint8 alpha, const Rect& layer_bounds);
 
   // Restores the drawing state after a call to Save*(). It is an error to
   // call Restore() more times than Save*().
@@ -184,7 +204,7 @@
 
   // Adds |rect| to the current clip. Returns true if the resulting clip is
   // non-empty.
-  bool ClipRect(const gfx::Rect& rect);
+  bool ClipRect(const Rect& rect);
 
   // Adds |path| to the current clip. Returns true if the resulting clip is
   // non-empty.
@@ -192,9 +212,9 @@
 
   // Returns the bounds of the current clip (in local coordinates) in the
   // |bounds| parameter, and returns true if it is non empty.
-  bool GetClipBounds(gfx::Rect* bounds);
+  bool GetClipBounds(Rect* bounds);
 
-  void Translate(const gfx::Vector2d& offset);
+  void Translate(const Vector2d& offset);
 
   void Scale(int x_scale, int y_scale);
 
@@ -208,45 +228,43 @@
 
   // Fills |rect| with |color| using a transfer mode of
   // SkXfermode::kSrcOver_Mode.
-  void FillRect(const gfx::Rect& rect, SkColor color);
+  void FillRect(const Rect& rect, SkColor color);
 
   // Fills |rect| with the specified |color| and |mode|.
-  void FillRect(const gfx::Rect& rect, SkColor color, SkXfermode::Mode mode);
+  void FillRect(const Rect& rect, SkColor color, SkXfermode::Mode mode);
 
   // Draws a single pixel rect in the specified region with the specified
   // color, using a transfer mode of SkXfermode::kSrcOver_Mode.
   //
   // NOTE: if you need a single pixel line, use DrawLine.
-  void DrawRect(const gfx::Rect& rect, SkColor color);
+  void DrawRect(const Rect& rect, SkColor color);
 
   // Draws a single pixel rect in the specified region with the specified
   // color and transfer mode.
   //
   // NOTE: if you need a single pixel line, use DrawLine.
-  void DrawRect(const gfx::Rect& rect, SkColor color, SkXfermode::Mode mode);
+  void DrawRect(const Rect& rect, SkColor color, SkXfermode::Mode mode);
 
   // Draws the given rectangle with the given |paint| parameters.
-  void DrawRect(const gfx::Rect& rect, const SkPaint& paint);
+  void DrawRect(const Rect& rect, const SkPaint& paint);
 
   // Draw the given point with the given |paint| parameters.
-  void DrawPoint(const gfx::Point& p, const SkPaint& paint);
+  void DrawPoint(const Point& p, const SkPaint& paint);
 
   // Draws a single pixel line with the specified color.
-  void DrawLine(const gfx::Point& p1, const gfx::Point& p2, SkColor color);
+  void DrawLine(const Point& p1, const Point& p2, SkColor color);
 
   // Draws a line with the given |paint| parameters.
-  void DrawLine(const gfx::Point& p1,
-                const gfx::Point& p2,
-                const SkPaint& paint);
+  void DrawLine(const Point& p1, const Point& p2, const SkPaint& paint);
 
   // Draws a circle with the given |paint| parameters.
-  void DrawCircle(const gfx::Point& center_point,
+  void DrawCircle(const Point& center_point,
                   int radius,
                   const SkPaint& paint);
 
   // Draws the given rectangle with rounded corners of |radius| using the
   // given |paint| parameters.
-  void DrawRoundRect(const gfx::Rect& rect, int radius, const SkPaint& paint);
+  void DrawRoundRect(const Rect& rect, int radius, const SkPaint& paint);
 
   // Draws the given path using the given |paint| parameters.
   void DrawPath(const SkPath& path, const SkPaint& paint);
@@ -255,19 +273,20 @@
   // corner of the bitmap is rendered at the specified location.
   // Parameters are specified relative to current canvas scale not in pixels.
   // Thus, x is 2 pixels if canvas scale = 2 & |x| = 1.
-  void DrawImageInt(const gfx::ImageSkia&, int x, int y);
+  void DrawImageInt(const ImageSkia&, int x, int y);
 
   // Helper for DrawImageInt(..., paint) that constructs a temporary paint and
   // calls paint.setAlpha(alpha).
-  void DrawImageInt(const gfx::ImageSkia&, int x, int y, uint8 alpha);
+  void DrawImageInt(const ImageSkia&, int x, int y, uint8 alpha);
 
   // Draws an image with the origin at the specified location, using the
   // specified paint. The upper left corner of the bitmap is rendered at the
   // specified location.
   // Parameters are specified relative to current canvas scale not in pixels.
   // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1.
-  void DrawImageInt(const gfx::ImageSkia& image,
-                    int x, int y,
+  void DrawImageInt(const ImageSkia& image,
+                    int x,
+                    int y,
                     const SkPaint& paint);
 
   // Draws a portion of an image in the specified location. The src parameters
@@ -282,13 +301,25 @@
   // An optional custom SkPaint can be provided.
   // Parameters are specified relative to current canvas scale not in pixels.
   // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1.
-  void DrawImageInt(const gfx::ImageSkia& image,
-                    int src_x, int src_y, int src_w, int src_h,
-                    int dest_x, int dest_y, int dest_w, int dest_h,
+  void DrawImageInt(const ImageSkia& image,
+                    int src_x,
+                    int src_y,
+                    int src_w,
+                    int src_h,
+                    int dest_x,
+                    int dest_y,
+                    int dest_w,
+                    int dest_h,
                     bool filter);
-  void DrawImageInt(const gfx::ImageSkia& image,
-                    int src_x, int src_y, int src_w, int src_h,
-                    int dest_x, int dest_y, int dest_w, int dest_h,
+  void DrawImageInt(const ImageSkia& image,
+                    int src_x,
+                    int src_y,
+                    int src_w,
+                    int src_h,
+                    int dest_x,
+                    int dest_y,
+                    int dest_w,
+                    int dest_h,
                     bool filter,
                     const SkPaint& paint);
 
@@ -296,59 +327,96 @@
   // |path|.
   // Parameters are specified relative to current canvas scale not in pixels.
   // Thus, x is 2 pixels if canvas scale = 2 & |x| = 1.
-  void DrawImageInPath(const gfx::ImageSkia& image,
+  void DrawImageInPath(const ImageSkia& image,
                        int x,
                        int y,
                        const SkPath& path,
                        const SkPaint& paint);
 
-  // Draws text with the specified color, font and location. The text is
+  // Draws text with the specified color, fonts and location. The text is
   // aligned to the left, vertically centered, clipped to the region. If the
   // text is too big, it is truncated and '...' is added to the end.
+  void DrawStringRect(const base::string16& text,
+                      const FontList& font_list,
+                      SkColor color,
+                      const Rect& display_rect);
+  // Obsolete versions.  Use the above versions which take FontList.
   void DrawStringInt(const base::string16& text,
-                     const gfx::Font& font,
+                     const Font& font,
                      SkColor color,
-                     int x, int y, int w, int h);
+                     int x,
+                     int y,
+                     int w,
+                     int h);
   void DrawStringInt(const base::string16& text,
-                     const gfx::Font& font,
+                     const Font& font,
                      SkColor color,
-                     const gfx::Rect& display_rect);
+                     const Rect& display_rect);
 
-  // Draws text with the specified color, font and location. The last argument
+  // Draws text with the specified color, fonts and location. The last argument
   // specifies flags for how the text should be rendered. It can be one of
   // TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT or TEXT_ALIGN_LEFT.
+  void DrawStringRectWithFlags(const base::string16& text,
+                               const FontList& font_list,
+                               SkColor color,
+                               const Rect& display_rect,
+                               int flags);
+  // Obsolete version.  Use the above version which takes FontList.
   void DrawStringInt(const base::string16& text,
-                     const gfx::Font& font,
+                     const Font& font,
                      SkColor color,
-                     int x, int y, int w, int h,
+                     int x,
+                     int y,
+                     int w,
+                     int h,
                      int flags);
 
   // Similar to above DrawStringInt method but with text shadows support.
   // Currently it's only implemented for canvas skia. Specifying a 0 line_height
   // will cause the default height to be used.
+  void DrawStringRectWithShadows(const base::string16& text,
+                                 const FontList& font_list,
+                                 SkColor color,
+                                 const Rect& text_bounds,
+                                 int line_height,
+                                 int flags,
+                                 const ShadowValues& shadows);
+  // Obsolete version.  Use the above version which takes FontList.
   void DrawStringWithShadows(const base::string16& text,
-                             const gfx::Font& font,
+                             const Font& font,
                              SkColor color,
-                             const gfx::Rect& text_bounds,
+                             const Rect& text_bounds,
                              int line_height,
                              int flags,
                              const ShadowValues& shadows);
 
   // Draws a dotted gray rectangle used for focus purposes.
-  void DrawFocusRect(const gfx::Rect& rect);
+  void DrawFocusRect(const Rect& rect);
 
   // Tiles the image in the specified region.
   // Parameters are specified relative to current canvas scale not in pixels.
   // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1.
-  void TileImageInt(const gfx::ImageSkia& image,
-                    int x, int y, int w, int h);
-  void TileImageInt(const gfx::ImageSkia& image,
-                    int src_x, int src_y,
-                    int dest_x, int dest_y, int w, int h);
-  void TileImageInt(const gfx::ImageSkia& image,
-                    int src_x, int src_y,
-                    float tile_scale_x, float tile_scale_y,
-                    int dest_x, int dest_y, int w, int h);
+  void TileImageInt(const ImageSkia& image,
+                    int x,
+                    int y,
+                    int w,
+                    int h);
+  void TileImageInt(const ImageSkia& image,
+                    int src_x,
+                    int src_y,
+                    int dest_x,
+                    int dest_y,
+                    int w,
+                    int h);
+  void TileImageInt(const ImageSkia& image,
+                    int src_x,
+                    int src_y,
+                    float tile_scale_x,
+                    float tile_scale_y,
+                    int dest_x,
+                    int dest_y,
+                    int w,
+                    int h);
 
   // Returns a native drawing context for platform specific drawing routines to
   // use. Must be balanced by a call to EndPlatformPaint().
@@ -359,19 +427,27 @@
   void EndPlatformPaint();
 
   // Apply transformation on the canvas.
-  void Transform(const gfx::Transform& transform);
+  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.
+  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(
       const base::string16& text,
       TruncateFadeMode truncate_mode,
       size_t desired_characters_to_truncate_from_head,
-      const gfx::Font& font,
+      const Font& font,
       SkColor color,
-      const gfx::Rect& display_rect);
+      const Rect& display_rect);
 
   skia::PlatformCanvas* platform_canvas() const { return owned_canvas_.get(); }
   SkCanvas* sk_canvas() const { return canvas_; }
@@ -382,19 +458,18 @@
 
   // Test whether the provided rectangle intersects the current clip rect.
   bool IntersectsClipRectInt(int x, int y, int w, int h);
-  bool IntersectsClipRect(const gfx::Rect& rect);
+  bool IntersectsClipRect(const Rect& rect);
 
   // Returns the image rep which best matches the canvas |scale_factor_|.
   // Returns a null image rep if |image| contains no image reps.
   // Builds mip map for returned image rep if necessary.
   //
   // An optional additional user defined scale can be provided.
-  const gfx::ImageSkiaRep& GetImageRepToPaint(
-      const gfx::ImageSkia& image) const;
-  const gfx::ImageSkiaRep& GetImageRepToPaint(
-      const gfx::ImageSkia& image,
+  const ImageSkiaRep& GetImageRepToPaint(const ImageSkia& image) const;
+  const ImageSkiaRep& GetImageRepToPaint(
+      const ImageSkia& image,
       float user_defined_scale_factor_x,
-      float user_defined_scale_factor_y)  const;
+      float user_defined_scale_factor_y) const;
 
   // The device scale factor at which drawing on this canvas occurs.
   // An additional scale can be applied via Canvas::Scale(). However,
diff --git a/ui/gfx/canvas_android.cc b/ui/gfx/canvas_android.cc
index c26a668..54e45f7 100644
--- a/ui/gfx/canvas_android.cc
+++ b/ui/gfx/canvas_android.cc
@@ -5,13 +5,12 @@
 #include "ui/gfx/canvas.h"
 
 #include "base/logging.h"
-#include "ui/gfx/font.h"
 
 namespace gfx {
 
 // static
 void Canvas::SizeStringInt(const base::string16& text,
-                           const gfx::Font& font,
+                           const FontList& font_list,
                            int* width,
                            int* height,
                            int line_height,
@@ -19,13 +18,22 @@
   NOTIMPLEMENTED();
 }
 
-void Canvas::DrawStringWithShadows(const base::string16& text,
-                                   const gfx::Font& font,
-                                   SkColor color,
-                                   const gfx::Rect& text_bounds,
-                                   int line_height,
-                                   int flags,
-                                   const ShadowValues& shadows) {
+void Canvas::DrawStringRectWithHalo(const base::string16& text,
+                                    const FontList& font_list,
+                                    SkColor text_color,
+                                    SkColor halo_color_in,
+                                    const Rect& display_rect,
+                                    int flags) {
+  NOTIMPLEMENTED();
+}
+
+void Canvas::DrawStringRectWithShadows(const base::string16& text,
+                                       const FontList& font_list,
+                                       SkColor color,
+                                       const Rect& text_bounds,
+                                       int line_height,
+                                       int flags,
+                                       const ShadowValues& shadows) {
   NOTIMPLEMENTED();
 }
 
diff --git a/ui/gfx/canvas_mac.mm b/ui/gfx/canvas_mac.mm
index a906873..247c28b 100644
--- a/ui/gfx/canvas_mac.mm
+++ b/ui/gfx/canvas_mac.mm
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import <Cocoa/Cocoa.h>
-
 #include "ui/gfx/canvas.h"
 
+#import <Cocoa/Cocoa.h>
+
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
 #include "third_party/skia/include/core/SkTypeface.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
 #include "ui/gfx/rect.h"
 
 // Note: This is a temporary Skia-based implementation of the ui/gfx text
@@ -36,7 +36,7 @@
 
 // static
 void Canvas::SizeStringInt(const base::string16& text,
-                           const gfx::Font& font,
+                           const FontList& font_list,
                            int* width,
                            int* height,
                            int line_height,
@@ -44,27 +44,28 @@
   DLOG_IF(WARNING, line_height != 0) << "Line heights not implemented.";
   DLOG_IF(WARNING, flags & Canvas::MULTI_LINE) << "Multi-line not implemented.";
 
-  NSFont* native_font = font.GetNativeFont();
+  NSFont* native_font = font_list.GetPrimaryFont().GetNativeFont();
   NSString* ns_string = base::SysUTF16ToNSString(text);
   NSDictionary* attributes =
       [NSDictionary dictionaryWithObject:native_font
                                   forKey:NSFontAttributeName];
   NSSize string_size = [ns_string sizeWithAttributes:attributes];
   *width = string_size.width;
-  *height = font.GetHeight();
+  *height = font_list.GetHeight();
 }
 
-void Canvas::DrawStringWithShadows(const base::string16& text,
-                                   const gfx::Font& font,
-                                   SkColor color,
-                                   const gfx::Rect& text_bounds,
-                                   int line_height,
-                                   int flags,
-                                   const ShadowValues& shadows) {
+void Canvas::DrawStringRectWithShadows(const base::string16& text,
+                                       const FontList& font_list,
+                                       SkColor color,
+                                       const Rect& text_bounds,
+                                       int line_height,
+                                       int flags,
+                                       const ShadowValues& shadows) {
   DLOG_IF(WARNING, line_height != 0) << "Line heights not implemented.";
   DLOG_IF(WARNING, flags & Canvas::MULTI_LINE) << "Multi-line not implemented.";
   DLOG_IF(WARNING, !shadows.empty()) << "Text shadows not implemented.";
 
+  const Font& font = font_list.GetPrimaryFont();
   skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(
       SkTypeface::CreateFromName(
           font.GetFontName().c_str(), FontTypefaceStyle(font)));
@@ -78,12 +79,12 @@
                     paint);
 }
 
-void Canvas::DrawStringWithHalo(const base::string16& text,
-                                const gfx::Font& font,
-                                SkColor text_color,
-                                SkColor halo_color,
-                                int x, int y, int w, int h,
-                                int flags) {
+void Canvas::DrawStringRectWithHalo(const base::string16& text,
+                                    const FontList& font_list,
+                                    SkColor text_color,
+                                    SkColor halo_color,
+                                    const Rect& display_rect,
+                                    int flags) {
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc
index bb8ce7d..11378d7 100644
--- a/ui/gfx/canvas_skia.cc
+++ b/ui/gfx/canvas_skia.cc
@@ -9,7 +9,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "ui/base/range/range.h"
 #include "ui/base/text/text_elider.h"
-#include "ui/gfx/font.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/insets.h"
 #include "ui/gfx/rect.h"
@@ -57,9 +56,9 @@
 // Checks each pixel immediately adjacent to the given pixel in the bitmap. If
 // any of them are not the halo color, returns true. This defines the halo of
 // pixels that will appear around the text. Note that we have to check each
-// pixel against both the halo color and transparent since |DrawStringWithHalo|
-// will modify the bitmap as it goes, and cleared pixels shouldn't count as
-// changed.
+// pixel against both the halo color and transparent since
+// |DrawStringRectWithHalo| will modify the bitmap as it goes, and cleared
+// pixels shouldn't count as changed.
 bool PixelShouldGetHalo(const SkBitmap& bitmap,
                         int x, int y,
                         SkColor halo_color) {
@@ -98,13 +97,13 @@
 
 // Elides |text| and adjusts |range| appropriately. If eliding causes |range|
 // to no longer point to the same character in |text|, |range| is made invalid.
-void ElideTextAndAdjustRange(const Font& font,
+void ElideTextAndAdjustRange(const FontList& font_list,
                              int width,
                              base::string16* text,
                              ui::Range* range) {
   const base::char16 start_char =
       (range->IsValid() ? text->at(range->start()) : 0);
-  *text = ui::ElideText(*text, font, width, ui::ELIDE_AT_END);
+  *text = ui::ElideText(*text, font_list, width, ui::ELIDE_AT_END);
   if (!range->IsValid())
     return;
   if (range->start() >= text->length() ||
@@ -116,16 +115,16 @@
 // Updates |render_text| from the specified parameters.
 void UpdateRenderText(const Rect& rect,
                       const base::string16& text,
-                      const Font& font,
+                      const FontList& font_list,
                       int flags,
                       SkColor color,
                       RenderText* render_text) {
-  render_text->SetFont(font);
+  render_text->SetFontList(font_list);
   render_text->SetText(text);
   render_text->SetCursorEnabled(false);
 
   Rect display_rect = rect;
-  display_rect.set_height(font.GetHeight());
+  display_rect.set_height(font_list.GetHeight());
   render_text->SetDisplayRect(display_rect);
 
   // Set the text alignment explicitly based on the directionality of the UI,
@@ -147,9 +146,10 @@
     render_text->set_background_is_transparent(true);
 
   render_text->SetColor(color);
-  render_text->SetStyle(BOLD, (font.GetStyle() & Font::BOLD) != 0);
-  render_text->SetStyle(ITALIC, (font.GetStyle() & Font::ITALIC) != 0);
-  render_text->SetStyle(UNDERLINE, (font.GetStyle() & Font::UNDERLINE) != 0);
+  const int font_style = font_list.GetFontStyle();
+  render_text->SetStyle(BOLD, (font_style & Font::BOLD) != 0);
+  render_text->SetStyle(ITALIC, (font_style & Font::ITALIC) != 0);
+  render_text->SetStyle(UNDERLINE, (font_style & Font::UNDERLINE) != 0);
 }
 
 // Returns updated |flags| to match platform-specific expected behavior.
@@ -168,7 +168,7 @@
 
 // static
 void Canvas::SizeStringInt(const base::string16& text,
-                           const Font& font,
+                           const FontList& font_list,
                            int* width, int* height,
                            int line_height,
                            int flags) {
@@ -191,17 +191,19 @@
 
     Rect rect(*width, INT_MAX);
     std::vector<base::string16> strings;
-    ui::ElideRectangleText(adjusted_text, font, rect.width(), rect.height(),
+    ui::ElideRectangleText(adjusted_text, font_list,
+                           rect.width(), rect.height(),
                            wrap_behavior, &strings);
     scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
-    UpdateRenderText(rect, base::string16(), font, flags, 0, render_text.get());
+    UpdateRenderText(rect, base::string16(), font_list, flags, 0,
+                     render_text.get());
 
     int h = 0;
     int w = 0;
     for (size_t i = 0; i < strings.size(); ++i) {
       StripAcceleratorChars(flags, &strings[i]);
       render_text->SetText(strings[i]);
-      const Size string_size = render_text->GetStringSize();
+      const Size& string_size = render_text->GetStringSize();
       w = std::max(w, string_size.width());
       h += (i > 0 && line_height > 0) ? line_height : string_size.height();
     }
@@ -212,27 +214,28 @@
     // will inexplicably fail with result E_INVALIDARG. Guard against this.
     const size_t kMaxRenderTextLength = 5000;
     if (adjusted_text.length() >= kMaxRenderTextLength) {
-      *width = adjusted_text.length() * font.GetAverageCharacterWidth();
-      *height = font.GetHeight();
+      *width = font_list.GetExpectedTextWidth(adjusted_text.length());
+      *height = font_list.GetHeight();
     } else {
       scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
       Rect rect(*width, *height);
       StripAcceleratorChars(flags, &adjusted_text);
-      UpdateRenderText(rect, adjusted_text, font, flags, 0, render_text.get());
-      const Size string_size = render_text->GetStringSize();
+      UpdateRenderText(rect, adjusted_text, font_list, flags, 0,
+                       render_text.get());
+      const Size& string_size = render_text->GetStringSize();
       *width = string_size.width();
       *height = string_size.height();
     }
   }
 }
 
-void Canvas::DrawStringWithShadows(const base::string16& text,
-                                   const Font& font,
-                                   SkColor color,
-                                   const Rect& text_bounds,
-                                   int line_height,
-                                   int flags,
-                                   const ShadowValues& shadows) {
+void Canvas::DrawStringRectWithShadows(const base::string16& text,
+                                       const FontList& font_list,
+                                       SkColor color,
+                                       const Rect& text_bounds,
+                                       int line_height,
+                                       int flags,
+                                       const ShadowValues& shadows) {
   if (!IntersectsClipRect(text_bounds))
     return;
 
@@ -263,14 +266,15 @@
 
     std::vector<base::string16> strings;
     ui::ElideRectangleText(adjusted_text,
-                           font,
+                           font_list,
                            text_bounds.width(), text_bounds.height(),
                            wrap_behavior,
                            &strings);
 
     for (size_t i = 0; i < strings.size(); i++) {
       ui::Range range = StripAcceleratorChars(flags, &strings[i]);
-      UpdateRenderText(rect, strings[i], font, flags, color, render_text.get());
+      UpdateRenderText(rect, strings[i], font_list, flags, color,
+                       render_text.get());
       int line_padding = 0;
       if (line_height > 0)
         line_padding = line_height - render_text->GetStringSize().height();
@@ -311,13 +315,13 @@
 #endif
 
     if (elide_text) {
-      ElideTextAndAdjustRange(font,
+      ElideTextAndAdjustRange(font_list,
                               text_bounds.width(),
                               &adjusted_text,
                               &range);
     }
 
-    UpdateRenderText(rect, adjusted_text, font, flags, color,
+    UpdateRenderText(rect, adjusted_text, font_list, flags, color,
                      render_text.get());
 
     const int text_height = render_text->GetStringSize().height();
@@ -333,19 +337,19 @@
   canvas_->restore();
 }
 
-void Canvas::DrawStringWithHalo(const base::string16& text,
-                                const Font& font,
-                                SkColor text_color,
-                                SkColor halo_color_in,
-                                int x, int y, int w, int h,
-                                int flags) {
+void Canvas::DrawStringRectWithHalo(const base::string16& text,
+                                    const FontList& font_list,
+                                    SkColor text_color,
+                                    SkColor halo_color_in,
+                                    const Rect& display_rect,
+                                    int flags) {
   // Some callers will have semitransparent halo colors, which we don't handle
   // (since the resulting image can have 1-bit transparency only).
   SkColor halo_color = SkColorSetA(halo_color_in, 0xFF);
 
   // Create a temporary buffer filled with the halo color. It must leave room
   // for the 1-pixel border around the text.
-  Size size(w + 2, h + 2);
+  Size size(display_rect.width() + 2, display_rect.height() + 2);
   Canvas text_canvas(size, scale_factor(), true);
   SkPaint bkgnd_paint;
   bkgnd_paint.setColor(halo_color);
@@ -353,7 +357,9 @@
 
   // Draw the text into the temporary buffer. This will have correct
   // ClearType since the background color is the same as the halo color.
-  text_canvas.DrawStringInt(text, font, text_color, 1, 1, w, h, flags);
+  text_canvas.DrawStringRectWithFlags(
+      text, font_list, text_color,
+      Rect(1, 1, display_rect.width(), display_rect.height()), flags);
 
   uint32_t halo_premul = SkPreMultiplyColor(halo_color);
   SkBitmap& text_bitmap = const_cast<SkBitmap&>(
@@ -376,22 +382,21 @@
   // Draw the halo bitmap with blur.
   ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap,
       text_canvas.scale_factor()));
-  DrawImageInt(text_image, x - 1, y - 1);
+  DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1);
 }
 
-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) {
+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;
 
   // If the whole string fits in the destination then just draw it directly.
-  if (GetStringWidth(text, font) <= display_rect.width()) {
-    DrawStringInt(text, font, color, display_rect.x(), display_rect.y(),
-                  display_rect.width(), display_rect.height(), flags);
+  if (GetStringWidth(text, font_list) <= display_rect.width()) {
+    DrawStringRectWithFlags(text, font_list, color, display_rect, flags);
     return;
   }
 
@@ -437,7 +442,8 @@
     flags |= TEXT_ALIGN_LEFT;
 
   Rect rect = display_rect;
-  UpdateRenderText(rect, clipped_text, font, flags, color, render_text.get());
+  UpdateRenderText(rect, clipped_text, font_list, flags, color,
+                   render_text.get());
 
   const int line_height = render_text->GetStringSize().height();
   // Center the text vertically.
@@ -451,4 +457,16 @@
   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/OWNERS b/ui/gfx/codec/OWNERS
new file mode 100644
index 0000000..44aa7e4
--- /dev/null
+++ b/ui/gfx/codec/OWNERS
@@ -0,0 +1,2 @@
+erg@chromium.org
+dcheng@chromium.org
diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc
index 360526b..ed503fb 100644
--- a/ui/gfx/codec/png_codec.cc
+++ b/ui/gfx/codec/png_codec.cc
@@ -767,8 +767,8 @@
   SkAutoLockPixels lock_input(input);
   if (input.empty())
     return false;
-  DCHECK(input.bytesPerPixel() == bbp);
-  DCHECK(static_cast<int>(input.rowBytes()) >= input.width() * bbp);
+  DCHECK_EQ(input.bytesPerPixel(), bbp);
+  DCHECK_GE(static_cast<int>(input.rowBytes()), input.width() * bbp);
 
   return Encode(reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)),
                 FORMAT_SkBitmap, Size(input.width(), input.height()),
@@ -776,6 +776,25 @@
                 std::vector<Comment>(), output);
 }
 
+// static
+bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input,
+                                      bool discard_transparency,
+                                      std::vector<unsigned char>* output) {
+  static const int bbp = 4;
+
+  SkAutoLockPixels lock_input(input);
+  if (input.empty())
+    return false;
+  DCHECK_EQ(input.bytesPerPixel(), bbp);
+  DCHECK_GE(static_cast<int>(input.rowBytes()), input.width() * bbp);
+
+  return EncodeWithCompressionLevel(
+      reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)),
+      FORMAT_SkBitmap, Size(input.width(), input.height()),
+      static_cast<int>(input.rowBytes()), discard_transparency,
+      std::vector<Comment>(), Z_BEST_SPEED, output);
+}
+
 PNGCodec::Comment::Comment(const std::string& k, const std::string& t)
     : key(k), text(t) {
 }
diff --git a/ui/gfx/codec/png_codec.h b/ui/gfx/codec/png_codec.h
index 3a6d295..eec36ae 100644
--- a/ui/gfx/codec/png_codec.h
+++ b/ui/gfx/codec/png_codec.h
@@ -97,6 +97,13 @@
                                  bool discard_transparency,
                                  std::vector<unsigned char>* output);
 
+  // Call PNGCodec::Encode on the supplied SkBitmap |input|. The difference
+  // between this and the previous method is that this restricts compression to
+  // zlib q1, which is just rle encoding.
+  static bool FastEncodeBGRASkBitmap(const SkBitmap& input,
+                                     bool discard_transparency,
+                                     std::vector<unsigned char>* output);
+
   // Decodes the PNG data contained in input of length input_size. The
   // decoded data will be placed in *output with the dimensions in *w and *h
   // on success (returns true). This data will be written in the 'format'
diff --git a/ui/gfx/platform_font_pango_unittest.cc b/ui/gfx/platform_font_pango_unittest.cc
index 228c66b..f30e584 100644
--- a/ui/gfx/platform_font_pango_unittest.cc
+++ b/ui/gfx/platform_font_pango_unittest.cc
@@ -21,8 +21,10 @@
 // Test that PlatformFontPango is able to cope with PangoFontDescriptions
 // containing multiple font families.  The first family should be preferred.
 TEST(PlatformFontPangoTest, FamilyList) {
-  // Needed for GLib versions prior to 2.36.
+  // Needed for GLib versions prior to 2.36, but deprecated starting 2.35.
+#if !GLIB_CHECK_VERSION(2, 35, 0)
   g_type_init();
+#endif
 
   ScopedPangoFontDescription desc(
       pango_font_description_from_string("Arial,Times New Roman, 13px"));
diff --git a/ui/gfx/screen_win.cc b/ui/gfx/screen_win.cc
index 06c14bd..8bb1548 100644
--- a/ui/gfx/screen_win.cc
+++ b/ui/gfx/screen_win.cc
@@ -7,6 +7,7 @@
 #include <windows.h>
 
 #include "base/logging.h"
+#include "base/win/win_util.h"
 #include "ui/base/win/dpi.h"
 #include "ui/gfx/display.h"
 
@@ -15,7 +16,7 @@
 MONITORINFO GetMonitorInfoForMonitor(HMONITOR monitor) {
   MONITORINFO monitor_info = { 0 };
   monitor_info.cbSize = sizeof(monitor_info);
-  GetMonitorInfo(monitor, &monitor_info);
+  base::win::GetMonitorInfoWrapper(monitor, &monitor_info);
   return monitor_info;
 }
 
@@ -69,8 +70,8 @@
 
   MONITORINFO monitor_info;
   monitor_info.cbSize = sizeof(monitor_info);
-  GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST),
-                 &monitor_info);
+  base::win::GetMonitorInfoWrapper(
+      MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), &monitor_info);
   return GetDisplay(monitor_info);
 }
 
@@ -79,8 +80,9 @@
   HMONITOR monitor = MonitorFromPoint(initial_loc, MONITOR_DEFAULTTONEAREST);
   MONITORINFO mi = {0};
   mi.cbSize = sizeof(mi);
-  if (monitor && GetMonitorInfo(monitor, &mi))
+  if (monitor && base::win::GetMonitorInfoWrapper(monitor, &mi)) {
     return GetDisplay(mi);
+  }
   return gfx::Display();
 }
 
diff --git a/ui/gfx/text_utils.h b/ui/gfx/text_utils.h
index 42bce43..15bf3ca 100644
--- a/ui/gfx/text_utils.h
+++ b/ui/gfx/text_utils.h
@@ -10,6 +10,8 @@
 
 namespace gfx {
 
+class FontList;
+
 // Strip the accelerator char (typically '&') from a menu string.  A double
 // accelerator char ('&&') will be converted to a single char.  The out params
 // |accelerated_char_pos| and |accelerated_char_span| will be set to the index
@@ -20,6 +22,11 @@
                                                int* accelerated_char_pos,
                                                int* accelerated_char_span);
 
+// Returns the number of horizontal pixels needed to display the specified
+// |text| with |font_list|.
+UI_EXPORT int GetStringWidth(const base::string16& text,
+                             const FontList& font_list);
+
 }  // namespace gfx
 
 #endif  // UI_GFX_TEXT_UTILS_H_
diff --git a/ui/gfx/text_utils_android.cc b/ui/gfx/text_utils_android.cc
new file mode 100644
index 0000000..c564b9b
--- /dev/null
+++ b/ui/gfx/text_utils_android.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 "ui/gfx/text_utils.h"
+
+#include "base/logging.h"
+
+namespace gfx {
+
+int GetStringWidth(const base::string16& text, const FontList& font_list) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/text_utils_ios.mm b/ui/gfx/text_utils_ios.mm
new file mode 100644
index 0000000..1841864
--- /dev/null
+++ b/ui/gfx/text_utils_ios.mm
@@ -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 "ui/gfx/text_utils.h"
+
+#import <UIKit/UIKit.h>
+
+#include <cmath>
+
+#include "base/strings/sys_string_conversions.h"
+#include "ui/gfx/font_list.h"
+
+namespace gfx {
+
+int GetStringWidth(const base::string16& text, const FontList& font_list) {
+  NSString* ns_text = base::SysUTF16ToNSString(text);
+  NativeFont native_font = font_list.GetPrimaryFont().GetNativeFont();
+  return std::ceil([ns_text sizeWithFont:native_font].width);
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/text_utils_skia.cc b/ui/gfx/text_utils_skia.cc
new file mode 100644
index 0000000..0de1156
--- /dev/null
+++ b/ui/gfx/text_utils_skia.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 "ui/gfx/text_utils.h"
+
+#include "ui/gfx/canvas.h"
+
+namespace gfx {
+
+int GetStringWidth(const base::string16& text, const FontList& font_list) {
+  return Canvas::GetStringWidth(text, font_list);
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/transform.cc b/ui/gfx/transform.cc
index c7bf91a..3e94f44 100644
--- a/ui/gfx/transform.cc
+++ b/ui/gfx/transform.cc
@@ -9,6 +9,7 @@
 
 #include <cmath>
 
+#include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "ui/gfx/point.h"
 #include "ui/gfx/point3_f.h"
@@ -366,6 +367,14 @@
   matrix_.setDouble(2, 3, 0.0);
 }
 
+Vector2dF Transform::To2dTranslation() const {
+  DCHECK(IsIdentityOrTranslation());
+  // Ensure that this translation is truly 2d.
+  const double translate_z = matrix_.getDouble(2, 3);
+  DCHECK_EQ(0.0, translate_z);
+  return gfx::Vector2dF(matrix_.getDouble(0, 3), matrix_.getDouble(1, 3));
+}
+
 void Transform::TransformPoint(Point& point) const {
   TransformPointInternal(matrix_, point);
 }
diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h
index 66e76ea..7a7543a 100644
--- a/ui/gfx/transform.h
+++ b/ui/gfx/transform.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "third_party/skia/include/utils/SkMatrix44.h"
 #include "ui/base/ui_export.h"
+#include "ui/gfx/vector2d_f.h"
 
 namespace gfx {
 
@@ -161,6 +162,10 @@
   //
   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.
+  Vector2dF To2dTranslation() const;
+
   // Applies the transformation on the point. Returns true if the point is
   // transformed successfully.
   void TransformPoint(Point3F& point) const;
diff --git a/ui/gfx/transform_unittest.cc b/ui/gfx/transform_unittest.cc
index f56ca6d..95ffa1f 100644
--- a/ui/gfx/transform_unittest.cc
+++ b/ui/gfx/transform_unittest.cc
@@ -2494,6 +2494,16 @@
   EXPECT_TRUE(transform.Preserves2dAxisAlignment());
 }
 
+TEST(XFormTest, To2dTranslation) {
+  Vector2dF translation(3.f, 7.f);
+  Transform transform;
+  transform.Translate(translation.x(), translation.y() + 1);
+  EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
+  transform.MakeIdentity();
+  transform.Translate(translation.x(), translation.y());
+  EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
+}
+
 }  // namespace
 
 }  // namespace gfx
diff --git a/ui/gl/gl_context_android.cc b/ui/gl/gl_context_android.cc
index 882c33e..d8238db 100644
--- a/ui/gl/gl_context_android.cc
+++ b/ui/gl/gl_context_android.cc
@@ -4,6 +4,7 @@
 
 #include "ui/gl/gl_context.h"
 
+#include "base/android/sys_utils.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/sys_info.h"
@@ -100,17 +101,21 @@
   // Droid Razr M(1GB)  91MB
   // Galaxy Nexus(1GB)  85MB
   // Xoom(1GB)          85MB
-  // Nexus S(512MB)     36MB
+  // Nexus S(low-end)   16MB
   static size_t limit_bytes = 0;
   if (limit_bytes == 0) {
-    if (physical_memory_mb >= 1536)
-      limit_bytes = physical_memory_mb / 8;
-    else if (physical_memory_mb >= 1152)
-      limit_bytes = physical_memory_mb / 10;
-    else if (physical_memory_mb >= 768)
-      limit_bytes = physical_memory_mb / 12;
-    else
-      limit_bytes = physical_memory_mb / 16;
+    if (!base::android::SysUtils::IsLowEndDevice()) {
+      if (physical_memory_mb >= 1536)
+        limit_bytes = physical_memory_mb / 8;
+      else if (physical_memory_mb >= 1152)
+        limit_bytes = physical_memory_mb / 10;
+      else if (physical_memory_mb >= 768)
+        limit_bytes = physical_memory_mb / 12;
+      else
+        limit_bytes = physical_memory_mb / 16;
+    } else {
+      limit_bytes = physical_memory_mb / 32;
+    }
     limit_bytes = limit_bytes * 1024 * 1024;
   }
   *bytes = limit_bytes;
diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h
index f1d0537..8d59bc4 100644
--- a/ui/gl/gl_image.h
+++ b/ui/gl/gl_image.h
@@ -38,7 +38,9 @@
 
   // Create a GL image for a GPU Memory buffer.
   static scoped_refptr<GLImage> CreateGLImageForGpuMemoryBuffer(
-      gfx::GpuMemoryBufferHandle buffer, gfx::Size size);
+      gfx::GpuMemoryBufferHandle buffer,
+      gfx::Size size,
+      unsigned internalformat);
 
  protected:
   virtual ~GLImage();
diff --git a/ui/gl/gl_image_android.cc b/ui/gl/gl_image_android.cc
index fe871e7..e56dc2d 100644
--- a/ui/gl/gl_image_android.cc
+++ b/ui/gl/gl_image_android.cc
@@ -26,13 +26,16 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationEGLGLES2:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;
 
diff --git a/ui/gl/gl_image_mac.cc b/ui/gl/gl_image_mac.cc
index b244a22..04dc61e 100644
--- a/ui/gl/gl_image_mac.cc
+++ b/ui/gl/gl_image_mac.cc
@@ -27,7 +27,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
@@ -35,7 +37,8 @@
     case kGLImplementationAppleGL:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;
 
diff --git a/ui/gl/gl_image_ozone.cc b/ui/gl/gl_image_ozone.cc
index c217f99..a1c1329 100644
--- a/ui/gl/gl_image_ozone.cc
+++ b/ui/gl/gl_image_ozone.cc
@@ -27,7 +27,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
diff --git a/ui/gl/gl_image_shm.cc b/ui/gl/gl_image_shm.cc
index 14ed836..78e8164 100644
--- a/ui/gl/gl_image_shm.cc
+++ b/ui/gl/gl_image_shm.cc
@@ -10,7 +10,11 @@
 
 namespace gfx {
 
-GLImageShm::GLImageShm(gfx::Size size) : size_(size) {
+GLImageShm::GLImageShm(gfx::Size size, unsigned internalformat)
+    : size_(size),
+      internalformat_(internalformat) {
+  // GL_RGBA8_OES is currently the only supported internalformat.
+  DCHECK_EQ(static_cast<GLenum>(GL_RGBA8_OES), internalformat);
 }
 
 GLImageShm::~GLImageShm() {
@@ -40,8 +44,23 @@
   TRACE_EVENT0("gpu", "GLImageShm::BindTexImage");
   DCHECK(shared_memory_);
 
-  const int kBytesPerPixel = 4;
-  size_t size = size_.GetArea() * kBytesPerPixel;
+  GLenum internalformat;
+  GLenum format;
+  GLenum type;
+  int bytes_per_pixel;
+  switch (internalformat_) {
+    case GL_RGBA8_OES:
+      internalformat = GL_RGBA;
+      format = GL_RGBA;
+      type = GL_UNSIGNED_BYTE;
+      bytes_per_pixel = 4;
+      break;
+    default:
+      DVLOG(0) << "Invalid format: " << internalformat_;
+      return false;
+  }
+
+  size_t size = size_.GetArea() * bytes_per_pixel;
   DCHECK(!shared_memory_->memory());
   if (!shared_memory_->Map(size)) {
     DVLOG(0) << "Failed to map shared memory.";
@@ -51,12 +70,12 @@
   DCHECK(shared_memory_->memory());
   glTexImage2D(GL_TEXTURE_2D,
                0,  // mip level
-               GL_RGBA,
+               internalformat,
                size_.width(),
                size_.height(),
                0,  // border
-               GL_RGBA,
-               GL_UNSIGNED_BYTE,
+               format,
+               type,
                shared_memory_->memory());
 
   shared_memory_->Unmap();
diff --git a/ui/gl/gl_image_shm.h b/ui/gl/gl_image_shm.h
index 70233f9..ffdfc8b 100644
--- a/ui/gl/gl_image_shm.h
+++ b/ui/gl/gl_image_shm.h
@@ -12,7 +12,7 @@
 
 class GL_EXPORT GLImageShm : public GLImage {
  public:
-  explicit GLImageShm(gfx::Size size);
+  GLImageShm(gfx::Size size, unsigned internalformat);
 
   bool Initialize(gfx::GpuMemoryBufferHandle buffer);
 
@@ -28,6 +28,7 @@
  private:
   scoped_ptr<base::SharedMemory> shared_memory_;
   gfx::Size size_;
+  unsigned internalformat_;
 
   DISALLOW_COPY_AND_ASSIGN(GLImageShm);
 };
diff --git a/ui/gl/gl_image_win.cc b/ui/gl/gl_image_win.cc
index 26b4a8f..1486520 100644
--- a/ui/gl/gl_image_win.cc
+++ b/ui/gl/gl_image_win.cc
@@ -27,7 +27,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
@@ -35,7 +37,8 @@
     case kGLImplementationEGLGLES2:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;
 
diff --git a/ui/gl/gl_image_x11.cc b/ui/gl/gl_image_x11.cc
index a6c09a1..6f7d8c6 100644
--- a/ui/gl/gl_image_x11.cc
+++ b/ui/gl/gl_image_x11.cc
@@ -35,7 +35,9 @@
 }
 
 scoped_refptr<GLImage> GLImage::CreateGLImageForGpuMemoryBuffer(
-    gfx::GpuMemoryBufferHandle buffer, gfx::Size size) {
+    gfx::GpuMemoryBufferHandle buffer,
+    gfx::Size size,
+    unsigned internalformat) {
   TRACE_EVENT0("gpu", "GLImage::CreateGLImageForGpuMemoryBuffer");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
@@ -43,7 +45,8 @@
     case kGLImplementationEGLGLES2:
       switch (buffer.type) {
         case SHARED_MEMORY_BUFFER: {
-          scoped_refptr<GLImageShm> image(new GLImageShm(size));
+          scoped_refptr<GLImageShm> image(
+              new GLImageShm(size, internalformat));
           if (!image->Initialize(buffer))
             return NULL;
 
diff --git a/ui/gl/gl_implementation_win.cc b/ui/gl/gl_implementation_win.cc
index c98c3c0..87328a3 100644
--- a/ui/gl/gl_implementation_win.cc
+++ b/ui/gl/gl_implementation_win.cc
@@ -8,6 +8,7 @@
 #include "base/base_paths.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/debug/trace_event.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/native_library.h"
@@ -58,6 +59,45 @@
   return true;
 }
 
+const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) {
+  return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
+}
+
+void AngleAddTraceEvent(char phase,
+                        const unsigned char* category_group_enabled,
+                        const char* name,
+                        unsigned long long id,
+                        int num_args,
+                        const char** arg_names,
+                        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);
+}
+
+typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name);
+typedef void (*AddTraceEventFunc)(char phase,
+                                  const unsigned char* categoryGroupEnabled,
+                                  const char* name,
+                                  unsigned long long id,
+                                  int numArgs,
+                                  const char** argNames,
+                                  const unsigned char* argTypes,
+                                  const unsigned long long* argValues,
+                                  unsigned char flags);
+typedef void (__stdcall *SetTraceFunctionPointersFunc)(
+    GetCategoryEnabledFlagFunc get_category_enabled_flag,
+    AddTraceEventFunc add_trace_event_func);
+
 }  // namespace
 
 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
@@ -167,6 +207,17 @@
       }
 #endif
 
+      if (!using_swift_shader) {
+        SetTraceFunctionPointersFunc set_trace_function_pointers =
+            reinterpret_cast<SetTraceFunctionPointersFunc>(
+                base::GetFunctionPointerFromNativeLibrary(
+                    gles_library, "SetTraceFunctionPointers"));
+        if (set_trace_function_pointers) {
+          set_trace_function_pointers(&AngleGetTraceCategoryEnabledFlag,
+                                      &AngleAddTraceEvent);
+        }
+      }
+
       GLGetProcAddressProc get_proc_address =
           reinterpret_cast<GLGetProcAddressProc>(
               base::GetFunctionPointerFromNativeLibrary(
diff --git a/ui/keyboard/keyboard.gyp b/ui/keyboard/keyboard.gyp
index d4d7ea1..7ec43f3 100644
--- a/ui/keyboard/keyboard.gyp
+++ b/ui/keyboard/keyboard.gyp
@@ -92,14 +92,13 @@
         'keyboard_test_suite.cc',
       ],
       'conditions': [
-        [ 'os_posix == 1 and OS != "mac" and OS != "android" and OS != "ios"', {
-          'conditions': [
-            ['linux_use_tcmalloc==1', {
-              'dependencies': [
-                '../../base/allocator/allocator.gyp:allocator',
-              ],
-            }],
+        ['OS=="linux" and linux_use_tcmalloc==1', {
+          'dependencies': [
+            '<(DEPTH)/base/allocator/allocator.gyp:allocator',
           ],
+          'link_settings': {
+            'ldflags': ['-rdynamic'],
+          },
         }],
       ],
     },
diff --git a/ui/keyboard/keyboard_resources.grd b/ui/keyboard/keyboard_resources.grd
index 2509d68..b099792 100644
--- a/ui/keyboard/keyboard_resources.grd
+++ b/ui/keyboard/keyboard_resources.grd
@@ -23,6 +23,7 @@
       <include name="IDR_KEYBOARD_ELEMENTS_ALTKEY_SET" file="resources/elements/kb-altkey-set.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_KEY" file="resources/elements/kb-key.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_KEY_BASE" file="resources/elements/kb-key-base.html" type="BINDATA" />
+      <include name="IDR_KEYBOARD_ELEMENTS_KEY_CODES" file="resources/elements/kb-key-codes.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_KEY_IMPORT" file="resources/elements/kb-key-import.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_KEY_SEQUENCE" file="resources/elements/kb-key-sequence.html" type="BINDATA" />
       <include name="IDR_KEYBOARD_ELEMENTS_KEYBOARD" file="resources/elements/kb-keyboard.html" type="BINDATA" />
diff --git a/ui/keyboard/keyboard_ui_controller.cc b/ui/keyboard/keyboard_ui_controller.cc
index 1ee8d40..f2824cf 100644
--- a/ui/keyboard/keyboard_ui_controller.cc
+++ b/ui/keyboard/keyboard_ui_controller.cc
@@ -30,6 +30,8 @@
   source->AddResourcePath("elements/kb-key.html", IDR_KEYBOARD_ELEMENTS_KEY);
   source->AddResourcePath("elements/kb-key-base.html",
                           IDR_KEYBOARD_ELEMENTS_KEY_BASE);
+  source->AddResourcePath("elements/kb-key-codes.html",
+                          IDR_KEYBOARD_ELEMENTS_KEY_CODES);
   source->AddResourcePath("elements/kb-keyboard.html",
                           IDR_KEYBOARD_ELEMENTS_KEYBOARD);
   source->AddResourcePath("elements/kb-keyset.html",
diff --git a/ui/keyboard/keyboard_util.cc b/ui/keyboard/keyboard_util.cc
index 1579068..2054e67 100644
--- a/ui/keyboard/keyboard_util.cc
+++ b/ui/keyboard/keyboard_util.cc
@@ -118,6 +118,7 @@
     {"keyboard/elements/kb-altkey-set.html", IDR_KEYBOARD_ELEMENTS_ALTKEY_SET},
     {"keyboard/elements/kb-key.html", IDR_KEYBOARD_ELEMENTS_KEY},
     {"keyboard/elements/kb-key-base.html", IDR_KEYBOARD_ELEMENTS_KEY_BASE},
+    {"keyboard/elements/kb-key-codes.html", IDR_KEYBOARD_ELEMENTS_KEY_CODES},
     {"keyboard/elements/kb-key-import.html",
         IDR_KEYBOARD_ELEMENTS_KEY_IMPORT},
     {"keyboard/elements/kb-key-sequence.html",
diff --git a/ui/keyboard/resources/elements/kb-key-base.html b/ui/keyboard/resources/elements/kb-key-base.html
index 497da30..0b017ff 100644
--- a/ui/keyboard/resources/elements/kb-key-base.html
+++ b/ui/keyboard/resources/elements/kb-key-base.html
@@ -110,7 +110,7 @@
       },
       down: function(event) {
         var detail = {
-            char: this.char || this.textContent,
+            char: this.charValue,
             toLayout: this.toLayout,
             repeat: this.repeat
         };
@@ -121,7 +121,7 @@
         this.fire('key-down', detail);
         this.longPressTimer = this.asyncMethod(function() {
           var detail = {
-            char: this.char || this.textContent,
+            char: this.charValue,
             superscript: this.superscript
           };
           if (this.keysetRules && this.keysetRules.long != undefined) {
@@ -137,7 +137,7 @@
       up: function(event) {
         clearTimeout(this.longPressTimer);
         var detail = {
-            char: this.char || this.textContent,
+            char: this.charValue,
             toLayout: this.toLayout
         };
         if (this.keysetRules && this.keysetRules.up != undefined) {
@@ -145,7 +145,17 @@
           detail.nextKeyset = this.keysetRules.up[NEXT_KEYSET - OFFSET];
         }
         this.fire('key-up', detail);
-      }
+      },
+
+      /**
+       * Character value associated with the key. Typically, the value is a
+       * single charcater, but may be multi-character in cases like a ".com"
+       * button.
+       * @type {string}
+       */
+      get charValue() {
+        return this.char || this.textContent;
+      },
     });
   </script>
 </polymer-element>
diff --git a/ui/keyboard/resources/elements/kb-key-codes.html b/ui/keyboard/resources/elements/kb-key-codes.html
new file mode 100644
index 0000000..cf1a7c2
--- /dev/null
+++ b/ui/keyboard/resources/elements/kb-key-codes.html
@@ -0,0 +1,172 @@
+<!--
+  -- Copyright 2013 The Chromium 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-key-codes">
+<script>
+  (function() {
+    // Keycodes have been deprecated in the KeyEvent specification, but are
+    // nonetheless required to support legacy web content.  The Keycodes in the
+    // following table are based on subset of US-EN 101-key keyboard. These
+    // codes are used in the absence of explicit keycodes for kb-key and
+    // kb-keysequence elements. Keyboard layout authors may explicitly set the
+    // 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.
+    var keyCodes = {
+      '\b': {keyCode: 0x08, shiftModifier: false},
+      '\t': {keyCode: 0x09, shiftModifier: false},
+      '\n': {keyCode: 0x0D, shiftModifier: false},
+      ' ': {keyCode: 0x20, shiftModifier: false},
+      '0': {keyCode: 0x30, shiftModifier: false},
+      ')': {keyCode: 0x30, shiftModifier: true},
+      '1': {keyCode: 0x31, shiftModifier: false},
+      '!': {keyCode: 0x31, shiftModifier: true},
+      '2': {keyCode: 0x32, shiftModifier: false},
+      '@': {keyCode: 0x32, shiftModifier: true},
+      '3': {keyCode: 0x33, shiftModifier: false},
+      '#': {keyCode: 0x33, shiftModifier: true},
+      '4': {keyCode: 0x34, shiftModifier: false},
+      '$': {keyCode: 0x34, shiftModifier: true},
+      '5': {keyCode: 0x35, shiftModifier: false},
+      '%': {keyCode: 0x35, shiftModifier: true},
+      '6': {keyCode: 0x36, shiftModifier: false},
+      '^': {keyCode: 0x36, shiftModifier: true},
+      '7': {keyCode: 0x37, shiftModifier: false},
+      '&': {keyCode: 0x37, shiftModifier: true},
+      '8': {keyCode: 0x38, shiftModifier: false},
+      '*': {keyCode: 0x38, shiftModifier: true},
+      '9': {keyCode: 0x39, shiftModifier: false},
+      '(': {keyCode: 0x39, shiftModifier: true},
+      'a': {keyCode: 0x41, shiftModifier: false},
+      'A': {keyCode: 0x41, shiftModifier: true},
+      'b': {keyCode: 0x42, shiftModifier: false},
+      'B': {keyCode: 0x42, shiftModifier: true},
+      'c': {keyCode: 0x43, shiftModifier: false},
+      'C': {keyCode: 0x43, shiftModifier: true},
+      'd': {keyCode: 0x44, shiftModifier: false},
+      'D': {keyCode: 0x44, shiftModifier: true},
+      'e': {keyCode: 0x45, shiftModifier: false},
+      'E': {keyCode: 0x45, shiftModifier: true},
+      'f': {keyCode: 0x46, shiftModifier: false},
+      'F': {keyCode: 0x46, shiftModifier: true},
+      'g': {keyCode: 0x47, shiftModifier: false},
+      'G': {keyCode: 0x47, shiftModifier: true},
+      'h': {keyCode: 0x48, shiftModifier: false},
+      'H': {keyCode: 0x48, shiftModifier: true},
+      'i': {keyCode: 0x49, shiftModifier: false},
+      'I': {keyCode: 0x49, shiftModifier: true},
+      'j': {keyCode: 0x4A, shiftModifier: false},
+      'J': {keyCode: 0x4A, shiftModifier: true},
+      'k': {keyCode: 0x4B, shiftModifier: false},
+      'K': {keyCode: 0x4B, shiftModifier: true},
+      'l': {keyCode: 0x4C, shiftModifier: false},
+      'L': {keyCode: 0x4C, shiftModifier: true},
+      'm': {keyCode: 0x4D, shiftModifier: false},
+      'M': {keyCode: 0x4D, shiftModifier: true},
+      'n': {keyCode: 0x4E, shiftModifier: false},
+      'N': {keyCode: 0x4E, shiftModifier: true},
+      'o': {keyCode: 0x4F, shiftModifier: false},
+      'O': {keyCode: 0x4F, shiftModifier: true},
+      'p': {keyCode: 0x50, shiftModifier: false},
+      'P': {keyCode: 0x50, shiftModifier: true},
+      'q': {keyCode: 0x51, shiftModifier: false},
+      'Q': {keyCode: 0x51, shiftModifier: true},
+      'r': {keyCode: 0x52, shiftModifier: false},
+      'R': {keyCode: 0x52, shiftModifier: true},
+      's': {keyCode: 0x53, shiftModifier: false},
+      'S': {keyCode: 0x53, shiftModifier: true},
+      't': {keyCode: 0x54, shiftModifier: false},
+      'T': {keyCode: 0x54, shiftModifier: true},
+      'u': {keyCode: 0x55, shiftModifier: false},
+      'U': {keyCode: 0x55, shiftModifier: true},
+      'v': {keyCode: 0x56, shiftModifier: false},
+      'V': {keyCode: 0x56, shiftModifier: true},
+      'w': {keyCode: 0x57, shiftModifier: false},
+      'W': {keyCode: 0x57, shiftModifier: true},
+      'x': {keyCode: 0x58, shiftModifier: false},
+      'X': {keyCode: 0x58, shiftModifier: true},
+      'y': {keyCode: 0x59, shiftModifier: false},
+      'Y': {keyCode: 0x59, shiftModifier: true},
+      'z': {keyCode: 0x5A, shiftModifier: false},
+      'Z': {keyCode: 0x5A, shiftModifier: true},
+      ';': {keyCode: 0xBA, shiftModifier: false},
+      ':': {keyCode: 0xBA, shiftModifier: true},
+      '=': {keyCode: 0xBB, shiftModifier: false},
+      '+': {keyCode: 0xBB, shiftModifier: true},
+      ',': {keyCode: 0xBC, shiftModifier: false},
+      '<': {keyCode: 0xBC, shiftModifier: true},
+      '-': {keyCode: 0xBD, shiftModifier: false},
+      '_': {keyCode: 0xBD, shiftModifier: true},
+      '.': {keyCode: 0xBE, shiftModifier: false}, 
+      '>': {keyCode: 0xBE, shiftModifier: true}, 
+      '/': {keyCode: 0xBF, shiftModifier: false},
+      '?': {keyCode: 0xBF, shiftModifier: true}, 
+      '`': {keyCode: 0xC0, shiftModifier: false},
+      '~': {keyCode: 0xC0, shiftModifier: true},
+      '[': {keyCode: 0xDB, shiftModifier: false},
+      '{': {keyCode: 0xDB, shiftModifier: true},
+      '\\': {keyCode: 0xDC, shiftModifier: false},
+      '|': {keyCode: 0xDC, shiftModifier: true}, 
+      ']': {keyCode: 0xDD, shiftModifier: false},
+      '}': {keyCode: 0xDD, shiftModifier: true},
+      '\'': {keyCode: 0xDE, shiftModifier: false},
+      '"': {keyCode: 0xDE, shiftModifier: true},
+    };
+
+    Polymer('kb-key-codes', {
+      /**
+       * Retrieves the keyCode and status of the shift modifier.
+       * @param {string} id ID of an entry in the code table.
+       * @return {keyCode: numeric, shiftModifier: boolean}
+       */
+      GetKeyCodeAndModifiers: function(id) {
+        var entry = keyCodes[id];
+        if (entry) {
+          return {
+            keyCode: entry.keyCode,
+            shiftModifier: entry.shiftModifier
+          };
+        }
+        return {
+          keyCode: 0,
+          shiftModifier: false
+        };
+      },
+
+     /**
+      * Creates a virtual key event for use with the keyboard extension API.
+      * @param {kb-key} key Instance of the kb-key element being pressed or
+      *     released.
+      * @param {string} type The type of key event, which may be keydown
+      *     or keyreleased.
+      * @return {keyCode: numeric,
+      *          modifiers: Array.<string>,
+      *          type: string,
+      *          value: string}
+      */
+     CreateVirtualKeyEvent: function(key, type) {
+       var keyCode = key.keyCode;
+       var shiftModifier = key.shiftModifier;
+       if (keyCode == undefined) {
+         var state = this.GetKeyCodeAndModifiers(key.charValue);
+         keyCode = state.keyCode;
+         shiftModifier = state.shiftModifier;
+       }
+       var modifiers = [];
+       if (shiftModifier)
+         modifiers.push('shiftKey');
+       return {
+         keyCode: keyCode,
+         modifiers: modifiers,
+         type: type,
+         value: key.charValue,
+       };
+     },
+    });
+  })();
+</script>
+</polymer-element>
diff --git a/ui/keyboard/resources/elements/kb-key-sequence.html b/ui/keyboard/resources/elements/kb-key-sequence.html
index dee295b..e575212 100644
--- a/ui/keyboard/resources/elements/kb-key-sequence.html
+++ b/ui/keyboard/resources/elements/kb-key-sequence.html
@@ -4,7 +4,7 @@
   -- found in the LICENSE file.
   -->
 
-<polymer-element name="kb-key-sequence" attributes="keys superscripts">
+<polymer-element name="kb-key-sequence" attributes="keys superscripts keyCodes">
   <template>
     <style>
       @host {
@@ -13,6 +13,7 @@
         }
       }
     </style>
+    <kb-key-codes id="keyCodeMetadata"></kb-key-codes>
   </template>
   <script>
     Polymer('kb-key-sequence', {
@@ -28,6 +29,11 @@
             console.error('keys and superscripts do not match');
             return;
           }
+          var keyCodes = this.keyCodes || newKeys;
+          if (keyCodes && newKeys.length != keyCodes.length) {
+             console.error('keys and keyCodes do not match');
+            return;
+          }
           var replacement = document.createDocumentFragment();
           for (var i = 0; i < newKeys.length; i++) {
             var key = document.createElement('kb-key');
@@ -35,6 +41,12 @@
             key.accents = newKeys[i];
             if (newSuperScripts)
               key.superscript = newSuperScripts[i];
+            var state = this.$.keyCodeMetadata.GetKeyCodeAndModifiers(
+                keyCodes[i]);
+            if (state) {
+              key.keyCode = state.keyCode;
+              key.shiftModifier = state.shiftModifier;
+            }
             replacement.appendChild(key);
           }
           result = replacement;
diff --git a/ui/keyboard/resources/elements/kb-key.html b/ui/keyboard/resources/elements/kb-key.html
index fc366bb..c37d707 100644
--- a/ui/keyboard/resources/elements/kb-key.html
+++ b/ui/keyboard/resources/elements/kb-key.html
@@ -4,7 +4,8 @@
   -- found in the LICENSE file.
   -->
 
-<polymer-element name="kb-key" extends="kb-key-base" attributes="weight">
+<polymer-element name="kb-key" extends="kb-key-base"
+    attributes="keyCode shiftModifier weight">
   <template>
     <style>
       @host {
@@ -20,6 +21,24 @@
   </template>
   <script>
     Polymer('kb-key', {
+      /**
+       * Key codes have been deprecated in DOM3 key events, but are required
+       * for legacy web content. The key codes depend on the position of the
+       * key on the keyboard and is independent of which modifier keys (shift,
+       *  alt, ...) are active.
+       * @type {number|undefined}
+       */
+      keyCode: undefined,
+      /**
+       * Whether the shift key is pressed when producing the key value.
+       * @type {boolean}
+       */
+      shiftModifier: false,
+      /**
+       * Weighting to use for layout in order to properly size the key.
+       * Keys with a high weighting are wider than normal keys.
+       * @type {number}
+       */
       weight: 1
     });
   </script>
diff --git a/ui/keyboard/resources/elements/kb-keyboard.html b/ui/keyboard/resources/elements/kb-keyboard.html
index f4efb31..e6b8c5d 100644
--- a/ui/keyboard/resources/elements/kb-keyboard.html
+++ b/ui/keyboard/resources/elements/kb-keyboard.html
@@ -112,7 +112,6 @@
 
     /**
      * The boolean to decide if it is swipe in process or finished.
-     * @const
      * @type {boolean}
      */
     var swipeInProgress = false;
@@ -347,7 +346,6 @@
           swipeInProgress = false;
           swipeStatus.resetAll();
         }
-        // Remove the pointermove event hander here.
         this.removeEventListener('pointermove', this.swipeHandler, false);
       },
 
@@ -411,6 +409,8 @@
        * @param {Object} detail The detail of pressed key.
        */
       keyLongpress: function(event, detail) {
+        // If the gesture is long press, remove the pointermove listener.
+        this.removeEventListener('pointermove', this.swipeHandler, false);
         var toKeyset = detail.toKeyset;
         // Keyset transtion key.
         if (toKeyset) {
diff --git a/ui/keyboard/resources/index.html b/ui/keyboard/resources/index.html
index ac2982b..3812f9f 100644
--- a/ui/keyboard/resources/index.html
+++ b/ui/keyboard/resources/index.html
@@ -23,7 +23,7 @@
     <link rel="import" href="elements/kb-altkey.html">
     <link rel="import" href="elements/kb-altkey-data.html">
     <link rel="import" href="elements/kb-altkey-set.html">
-
+    <link rel="import" href="elements/kb-key-codes.html">
     <link rel="import" href="elements/kb-key-base.html">
     <link rel="import" href="elements/kb-key.html">
     <link rel="import" href="elements/kb-keyboard.html">
diff --git a/ui/keyboard/resources/webui_index.html b/ui/keyboard/resources/webui_index.html
index 48b1637..ed6329c 100644
--- a/ui/keyboard/resources/webui_index.html
+++ b/ui/keyboard/resources/webui_index.html
@@ -25,6 +25,7 @@
     <link rel="import" href="elements/kb-altkey-container.html">
     <link rel="import" href="elements/kb-altkey-data.html">
     <link rel="import" href="elements/kb-altkey-set.html">
+    <link rel="import" href="elements/kb-key-codes.html">
     <link rel="import" href="elements/kb-key-base.html">
     <link rel="import" href="elements/kb-key.html">
     <link rel="import" href="elements/kb-keyboard.html">
diff --git a/ui/message_center/cocoa/tray_view_controller.mm b/ui/message_center/cocoa/tray_view_controller.mm
index 67b0cdf..2290e7e 100644
--- a/ui/message_center/cocoa/tray_view_controller.mm
+++ b/ui/message_center/cocoa/tray_view_controller.mm
@@ -126,6 +126,9 @@
     animation_.reset();
   }
   if (clearAllInProgress_) {
+    // To stop chain of clearOneNotification calls to start new animations.
+    [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
     for (NSViewAnimation* animation in clearAllAnimations_.get()) {
       [animation stopAnimation];
       [animation setDelegate:nil];
diff --git a/ui/message_center/notification.cc b/ui/message_center/notification.cc
index 5d3014e..692d140 100644
--- a/ui/message_center/notification.cc
+++ b/ui/message_center/notification.cc
@@ -5,6 +5,7 @@
 #include "ui/message_center/notification.h"
 
 #include "base/logging.h"
+#include "ui/message_center/notification_delegate.h"
 #include "ui/message_center/notification_types.h"
 
 namespace {
@@ -119,4 +120,26 @@
   optional_fields_.never_timeout = true;
 }
 
+// static
+scoped_ptr<Notification> Notification::CreateSystemNotification(
+    const std::string& notification_id,
+    const base::string16& title,
+    const base::string16& message,
+    const gfx::Image& icon,
+    const base::Closure& click_callback) {
+  scoped_ptr<Notification> notification(
+      new Notification(
+          NOTIFICATION_TYPE_SIMPLE,
+          notification_id,
+          title,
+          message,
+          icon,
+          base::string16()  /* display_source */,
+          std::string()  /* extension_id */,
+          RichNotificationData(),
+          new HandleNotificationClickedDelegate(click_callback)));
+  notification->SetSystemPriority();
+  return notification.Pass();
+}
+
 }  // namespace message_center
diff --git a/ui/message_center/notification.h b/ui/message_center/notification.h
index bda6900..cfcef43 100644
--- a/ui/message_center/notification.h
+++ b/ui/message_center/notification.h
@@ -167,6 +167,15 @@
   void ButtonClick(int index) const { delegate()->ButtonClick(index); }
   void Close(bool by_user) const { delegate()->Close(by_user); }
 
+  // Helper method to create a simple System notification. |click_callback|
+  // will be invoked when the notification is clicked.
+  static scoped_ptr<Notification> CreateSystemNotification(
+      const std::string& notification_id,
+      const base::string16& title,
+      const base::string16& message,
+      const gfx::Image& icon,
+      const base::Closure& click_callback);
+
  protected:
   // The type of notification we'd like displayed.
   NotificationType type_;
diff --git a/ui/message_center/views/message_center_button_bar.cc b/ui/message_center/views/message_center_button_bar.cc
index b6ebd81..149c3ed 100644
--- a/ui/message_center/views/message_center_button_bar.cc
+++ b/ui/message_center/views/message_center_button_bar.cc
@@ -158,7 +158,11 @@
                                    IDR_NOTIFICATION_CLEAR_ALL_HOVER,
                                    IDR_NOTIFICATION_CLEAR_ALL_PRESSED,
                                    IDS_MESSAGE_CENTER_CLEAR_ALL);
+  close_all_button_->SetImage(
+      views::Button::STATE_DISABLED,
+      resource_bundle.GetImageSkiaNamed(IDR_NOTIFICATION_CLEAR_ALL_DISABLED));
   button_container_->AddChildView(close_all_button_);
+
   settings_button_ =
       new NotificationCenterButton(this,
                                    IDR_NOTIFICATION_SETTINGS,
diff --git a/ui/message_center/views/message_center_button_bar.h b/ui/message_center/views/message_center_button_bar.h
index 950e25e..8190e3e 100644
--- a/ui/message_center/views/message_center_button_bar.h
+++ b/ui/message_center/views/message_center_button_bar.h
@@ -67,7 +67,7 @@
   NotificationCenterButton* title_arrow_;
   views::Label* notification_label_;
   views::View* button_container_;
-  views::Button* close_all_button_;
+  NotificationCenterButton* close_all_button_;
   NotificationCenterButton* settings_button_;
   NotificationCenterButton* quiet_mode_button_;
 
diff --git a/ui/message_center/views/toast_contents_view.cc b/ui/message_center/views/toast_contents_view.cc
index b7dae98..6db7f21 100644
--- a/ui/message_center/views/toast_contents_view.cc
+++ b/ui/message_center/views/toast_contents_view.cc
@@ -91,8 +91,10 @@
   Layout();
   // If it has the contents already, this invocation means an update of the
   // popup toast, and the new contents should be read through a11y feature.
+  // The notification type should be ALERT, otherwise the accessibility message
+  // won't be read for this view which returns ROLE_WINDOW.
   if (already_has_contents)
-    NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, false);
+    NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_ALERT, false);
 }
 
 void ToastContentsView::RevealWithAnimation(gfx::Point origin) {
diff --git a/ui/resources/default_100_percent/common/drag_tip_copy.png b/ui/resources/default_100_percent/common/drag_tip_copy.png
new file mode 100644
index 0000000..f642042
--- /dev/null
+++ b/ui/resources/default_100_percent/common/drag_tip_copy.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/drag_tip_link.png b/ui/resources/default_100_percent/common/drag_tip_link.png
new file mode 100644
index 0000000..8f61a39
--- /dev/null
+++ b/ui/resources/default_100_percent/common/drag_tip_link.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/drag_tip_move.png b/ui/resources/default_100_percent/common/drag_tip_move.png
new file mode 100644
index 0000000..a897ef4
--- /dev/null
+++ b/ui/resources/default_100_percent/common/drag_tip_move.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/drag_tip_nodrop.png b/ui/resources/default_100_percent/common/drag_tip_nodrop.png
new file mode 100644
index 0000000..0ee96bf
--- /dev/null
+++ b/ui/resources/default_100_percent/common/drag_tip_nodrop.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/notification_clear_all_disabled.png b/ui/resources/default_100_percent/common/notification_clear_all_disabled.png
new file mode 100644
index 0000000..a15a261
--- /dev/null
+++ b/ui/resources/default_100_percent/common/notification_clear_all_disabled.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/drag_tip_copy.png b/ui/resources/default_200_percent/common/drag_tip_copy.png
new file mode 100644
index 0000000..53dafb5
--- /dev/null
+++ b/ui/resources/default_200_percent/common/drag_tip_copy.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/drag_tip_link.png b/ui/resources/default_200_percent/common/drag_tip_link.png
new file mode 100644
index 0000000..fe0fd25
--- /dev/null
+++ b/ui/resources/default_200_percent/common/drag_tip_link.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/drag_tip_move.png b/ui/resources/default_200_percent/common/drag_tip_move.png
new file mode 100644
index 0000000..e2374ec
--- /dev/null
+++ b/ui/resources/default_200_percent/common/drag_tip_move.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/drag_tip_nodrop.png b/ui/resources/default_200_percent/common/drag_tip_nodrop.png
new file mode 100644
index 0000000..f96948f
--- /dev/null
+++ b/ui/resources/default_200_percent/common/drag_tip_nodrop.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/notification_clear_all_disabled.png b/ui/resources/default_200_percent/common/notification_clear_all_disabled.png
new file mode 100644
index 0000000..30578aa
--- /dev/null
+++ b/ui/resources/default_200_percent/common/notification_clear_all_disabled.png
Binary files differ
diff --git a/ui/resources/resource_check/resource_scale_factors.py b/ui/resources/resource_check/resource_scale_factors.py
index f974447..9ddc70f 100644
--- a/ui/resources/resource_check/resource_scale_factors.py
+++ b/ui/resources/resource_check/resource_scale_factors.py
@@ -15,6 +15,10 @@
 import struct
 
 
+class InvalidPNGException(Exception):
+  pass
+
+
 class ResourceScaleFactors(object):
   """Verifier of image dimensions for Chromium resources.
 
@@ -44,7 +48,8 @@
     def ImageSize(filename):
       with open(filename, 'rb', buffering=0) as f:
         data = f.read(24)
-      assert data[:8] == '\x89PNG\r\n\x1A\n' and data[12:16] == 'IHDR'
+      if data[:8] != '\x89PNG\r\n\x1A\n' or data[12:16] != 'IHDR':
+        raise InvalidPNGException
       return struct.unpack('>ii', data[16:24])
 
     # Returns a list of valid scaled image sizes. The valid sizes are the
@@ -75,6 +80,9 @@
           if relative_path not in files:
             files.append(relative_path)
 
+    corrupt_png_error = ('Corrupt PNG in file %s. Note that binaries are not '
+        'correctly uploaded to the code review tool and must be directly '
+        'submitted using the dcommit command.')
     for f in files:
       base_image = self.input_api.os_path.join(self.paths[0][1], f)
       if not os.path.exists(base_image):
@@ -82,7 +90,12 @@
             'Base image %s does not exist' % self.input_api.os_path.join(
             repository_path, base_image)))
         continue
-      base_dimensions = ImageSize(base_image)
+      try:
+        base_dimensions = ImageSize(base_image)
+      except InvalidPNGException:
+        results.append(self.output_api.PresubmitError(corrupt_png_error %
+            self.input_api.os_path.join(repository_path, base_image)))
+        continue
       # Find all scaled versions of the base image and verify their sizes.
       for i in range(1, len(self.paths)):
         image_path = self.input_api.os_path.join(self.paths[i][1], f)
@@ -90,7 +103,12 @@
           continue
         # Ensure that each image for a particular scale factor is the
         # correct scale of the base image.
-        scaled_dimensions = ImageSize(image_path)
+        try:
+          scaled_dimensions = ImageSize(image_path)
+        except InvalidPNGException:
+          results.append(self.output_api.PresubmitError(corrupt_png_error %
+              self.input_api.os_path.join(repository_path, image_path)))
+          continue
         for dimension_name, base_size, scaled_size in zip(
             ('width', 'height'), base_dimensions, scaled_dimensions):
           valid_sizes = ValidSizes(base_size, self.paths[i][0])
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index 1aeb4d1..2cb91be 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -154,7 +154,7 @@
       <structure type="chrome_scaled_image" name="IDR_RADIO_HOVER" file="common/radio_hover.png" />
       <structure type="chrome_scaled_image" name="IDR_RADIO_PRESSED" file="common/radio_pressed.png" />
       <structure type="chrome_scaled_image" name="IDR_TEXT_SELECTION_HANDLE" file="common/text_selection_handle_small.png" />
-      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_CLOSE" file="linux/linux_close.png" />
       </if>
       <if expr="pp_ifdef('toolkit_views')">
@@ -167,7 +167,7 @@
       <structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG" file="close_dialog.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG_H" file="close_dialog_hover.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_DIALOG_P" file="close_dialog_pressed.png" />
-      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_CLOSE_H" file="linux/linux_close_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_CLOSE_P" file="linux/linux_close_pressed.png" />
       </if>
@@ -193,7 +193,7 @@
       <structure type="chrome_scaled_image" name="IDR_FRAME" file="frame_default.png" />
       <structure type="chrome_scaled_image" name="IDR_FRAME_APP_PANEL" file="frame_app_panel_default.png" />
       <structure type="chrome_scaled_image" name="IDR_FRAME_INACTIVE" file="frame_default_inactive.png" />
-      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_MAXIMIZE" file="linux/linux_maximize.png" />
         <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_H" file="linux/linux_maximize_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_P" file="linux/linux_maximize_pressed.png" />
@@ -204,7 +204,7 @@
         <structure type="chrome_scaled_image" name="IDR_MAXIMIZE_P" file="maximize_pressed.png" />
         <structure type="chrome_scaled_image" name="IDR_MENU_HIERARCHY_ARROW" file="common/menu_hierarchy_arrow.png" />
       </if>
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_MENU_HIERARCHY_ARROW" file="mac/menu_hierarchy_arrow.png" />
       </if>
       <if expr="pp_ifdef('toolkit_views')">
@@ -226,7 +226,7 @@
       </if>
       <structure type="chrome_scaled_image" name="IDR_MENU_DROPARROW" file="cros/menu_droparrow.png" />
       <structure type="chrome_scaled_image" name="IDR_MESSAGE_CLOSE" file="common/message_close.png" />
-      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_MINIMIZE" file="linux/linux_minimize.png" />
         <structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="linux/linux_minimize_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_MINIMIZE_P" file="linux/linux_minimize_pressed.png" />
@@ -240,6 +240,7 @@
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_HOVER" file="common/notification_arrow_hover.png"/>
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_PRESSED" file="common/notification_arrow_pressed.png"/>
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL" file="common/notification_clear_all.png"/>
+      <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_DISABLED" file="common/notification_clear_all_disabled.png"/>
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_HOVER" file="common/notification_clear_all_hover.png"/>
       <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_PRESSED" file="common/notification_clear_all_pressed.png"/>
       <if expr="is_win">
@@ -271,7 +272,7 @@
       <structure type="chrome_scaled_image" name="IDR_PANEL_TOP_RIGHT_CORNER" file="panel_top_right_corner.png" />
       <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_LEFT_CORNER" file="panel_bottom_left_corner.png" />
       <structure type="chrome_scaled_image" name="IDR_PANEL_BOTTOM_RIGHT_CORNER" file="panel_bottom_right_corner.png" />
-      <if expr="is_posix and not is_macosx and not pp_ifdef('use_aura')">
+      <if expr="is_posix and not is_macosx and not is_ios and not pp_ifdef('use_aura')">
         <structure type="chrome_scaled_image" name="IDR_PROGRESS_BAR" file="linux/linux-progress-bar.png" />
         <structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_LEFT" file="linux/linux-progress-border-left.png" />
         <structure type="chrome_scaled_image" name="IDR_PROGRESS_BORDER_RIGHT" file="linux/linux-progress-border-right.png" />
@@ -308,7 +309,7 @@
         <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_TOP_H" file="cros/aura_scrollbar_thumb_vertical_hover_top.png" />
         <structure type="chrome_scaled_image" name="IDR_SCROLL_THUMB_VERTICAL_TOP_P" file="cros/aura_scrollbar_thumb_vertical_pressed_top.png" />
       </if>
-      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx">
+      <if expr="not pp_ifdef('toolkit_views') and is_posix and not is_macosx and not is_ios">
         <structure type="chrome_scaled_image" name="IDR_RESTORE" file="linux/linux_restore.png" />
         <structure type="chrome_scaled_image" name="IDR_RESTORE_H" file="linux/linux_restore_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_RESTORE_P" file="linux/linux_restore_pressed.png" />
@@ -337,7 +338,7 @@
       <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP_LEFT" file="common/textbutton_pressed_top_left.png" />
       <structure type="chrome_scaled_image" name="IDR_TEXTBUTTON_PRESSED_TOP_RIGHT" file="common/textbutton_pressed_top_right.png" />
       <structure type="chrome_scaled_image" name="IDR_THROBBER" file="throbber.png" />
-      <if expr="is_macosx">
+      <if expr="is_macosx or is_ios">
         <structure type="chrome_scaled_image" name="IDR_TRAY_ATTENTION" file="mac/notification_tray_attention.png"/>
         <structure type="chrome_scaled_image" name="IDR_TRAY_ATTENTION_PRESSED" file="mac/notification_tray_attention_pressed.png"/>
         <structure type="chrome_scaled_image" name="IDR_TRAY_DO_NOT_DISTURB_ATTENTION" file="mac/notification_tray_do_not_disturb_attention.png"/>
diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc
index 3b86db0..74ebdac 100644
--- a/ui/surface/accelerated_surface_win.cc
+++ b/ui/surface/accelerated_surface_win.cc
@@ -728,6 +728,7 @@
     return;
   }
 
+#if !defined(USE_AURA)
   // If the window is a different size than the swap chain that is being
   // presented then drop the frame.
   gfx::Size window_size = GetWindowSize();
@@ -750,7 +751,7 @@
                  "windowheight", window_size.height());
     return;
   }
-
+#endif
   // Round up size so the swap chain is not continuously resized with the
   // surface, which could lead to memory fragmentation.
   const int kRound = 64;
diff --git a/ui/ui.gyp b/ui/ui.gyp
index 2aa50d4..8d5f9bc 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -419,12 +419,12 @@
         'gfx/canvas.h',
         'gfx/canvas_android.cc',
         'gfx/canvas_mac.mm',
+        'gfx/canvas_paint_gtk.cc',
         'gfx/canvas_paint_gtk.h',
         'gfx/canvas_paint_mac.h',
-        'gfx/canvas_paint_win.h',
-        'gfx/canvas_paint_gtk.cc',
         'gfx/canvas_paint_mac.mm',
         'gfx/canvas_paint_win.cc',
+        'gfx/canvas_paint_win.h',
         'gfx/canvas_skia.cc',
         'gfx/canvas_skia_paint.h',
         'gfx/codec/jpeg_codec.cc',
@@ -583,6 +583,9 @@
         'gfx/text_constants.h',
         'gfx/text_utils.cc',
         'gfx/text_utils.h',
+        'gfx/text_utils_android.cc',
+        'gfx/text_utils_ios.mm',
+        'gfx/text_utils_skia.cc',
         'gfx/transform.cc',
         'gfx/transform.h',
         'gfx/transform_util.cc',
@@ -908,6 +911,7 @@
           'sources!': [
             'gfx/render_text.cc',
             'gfx/render_text.h',
+            'gfx/text_utils_skia.cc',
           ],
         }],
         ['OS=="linux"', {
diff --git a/ui/ui.target.darwin-arm.mk b/ui/ui.target.darwin-arm.mk
index 9cb1441..238d397 100644
--- a/ui/ui.target.darwin-arm.mk
+++ b/ui/ui.target.darwin-arm.mk
@@ -140,6 +140,7 @@
 	ui/gfx/switches.cc \
 	ui/gfx/sys_color_change_listener.cc \
 	ui/gfx/text_utils.cc \
+	ui/gfx/text_utils_android.cc \
 	ui/gfx/transform.cc \
 	ui/gfx/transform_util.cc \
 	ui/gfx/vector2d.cc \
diff --git a/ui/ui.target.darwin-mips.mk b/ui/ui.target.darwin-mips.mk
index c7155a4..ece97a9 100644
--- a/ui/ui.target.darwin-mips.mk
+++ b/ui/ui.target.darwin-mips.mk
@@ -140,6 +140,7 @@
 	ui/gfx/switches.cc \
 	ui/gfx/sys_color_change_listener.cc \
 	ui/gfx/text_utils.cc \
+	ui/gfx/text_utils_android.cc \
 	ui/gfx/transform.cc \
 	ui/gfx/transform_util.cc \
 	ui/gfx/vector2d.cc \
diff --git a/ui/ui.target.darwin-x86.mk b/ui/ui.target.darwin-x86.mk
index d941b2f..aa55166 100644
--- a/ui/ui.target.darwin-x86.mk
+++ b/ui/ui.target.darwin-x86.mk
@@ -140,6 +140,7 @@
 	ui/gfx/switches.cc \
 	ui/gfx/sys_color_change_listener.cc \
 	ui/gfx/text_utils.cc \
+	ui/gfx/text_utils_android.cc \
 	ui/gfx/transform.cc \
 	ui/gfx/transform_util.cc \
 	ui/gfx/vector2d.cc \
diff --git a/ui/ui.target.linux-arm.mk b/ui/ui.target.linux-arm.mk
index 9cb1441..238d397 100644
--- a/ui/ui.target.linux-arm.mk
+++ b/ui/ui.target.linux-arm.mk
@@ -140,6 +140,7 @@
 	ui/gfx/switches.cc \
 	ui/gfx/sys_color_change_listener.cc \
 	ui/gfx/text_utils.cc \
+	ui/gfx/text_utils_android.cc \
 	ui/gfx/transform.cc \
 	ui/gfx/transform_util.cc \
 	ui/gfx/vector2d.cc \
diff --git a/ui/ui.target.linux-mips.mk b/ui/ui.target.linux-mips.mk
index c7155a4..ece97a9 100644
--- a/ui/ui.target.linux-mips.mk
+++ b/ui/ui.target.linux-mips.mk
@@ -140,6 +140,7 @@
 	ui/gfx/switches.cc \
 	ui/gfx/sys_color_change_listener.cc \
 	ui/gfx/text_utils.cc \
+	ui/gfx/text_utils_android.cc \
 	ui/gfx/transform.cc \
 	ui/gfx/transform_util.cc \
 	ui/gfx/vector2d.cc \
diff --git a/ui/ui.target.linux-x86.mk b/ui/ui.target.linux-x86.mk
index d941b2f..aa55166 100644
--- a/ui/ui.target.linux-x86.mk
+++ b/ui/ui.target.linux-x86.mk
@@ -140,6 +140,7 @@
 	ui/gfx/switches.cc \
 	ui/gfx/sys_color_change_listener.cc \
 	ui/gfx/text_utils.cc \
+	ui/gfx/text_utils_android.cc \
 	ui/gfx/transform.cc \
 	ui/gfx/transform_util.cc \
 	ui/gfx/vector2d.cc \
diff --git a/ui/ui_resources.target.darwin-arm.mk b/ui/ui_resources.target.darwin-arm.mk
index 93a21dd..e336274 100644
--- a/ui/ui_resources.target.darwin-arm.mk
+++ b/ui/ui_resources.target.darwin-arm.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from resources/ui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i resources/ui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
@@ -36,7 +36,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/apps/common.css $(LOCAL_PATH)/ui/webui/resources/css/apps/topbutton_bar.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/ui/webui/resources/js/webui_resource_test.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from webui/resources/webui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i webui/resources/webui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/ui/ui_resources.target.darwin-mips.mk b/ui/ui_resources.target.darwin-mips.mk
index 93a21dd..e336274 100644
--- a/ui/ui_resources.target.darwin-mips.mk
+++ b/ui/ui_resources.target.darwin-mips.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from resources/ui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i resources/ui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
@@ -36,7 +36,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/apps/common.css $(LOCAL_PATH)/ui/webui/resources/css/apps/topbutton_bar.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/ui/webui/resources/js/webui_resource_test.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from webui/resources/webui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i webui/resources/webui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/ui/ui_resources.target.darwin-x86.mk b/ui/ui_resources.target.darwin-x86.mk
index 93a21dd..e336274 100644
--- a/ui/ui_resources.target.darwin-x86.mk
+++ b/ui/ui_resources.target.darwin-x86.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from resources/ui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i resources/ui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
@@ -36,7 +36,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/apps/common.css $(LOCAL_PATH)/ui/webui/resources/css/apps/topbutton_bar.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/ui/webui/resources/js/webui_resource_test.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from webui/resources/webui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i webui/resources/webui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/ui/ui_resources.target.linux-arm.mk b/ui/ui_resources.target.linux-arm.mk
index 93a21dd..e336274 100644
--- a/ui/ui_resources.target.linux-arm.mk
+++ b/ui/ui_resources.target.linux-arm.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from resources/ui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i resources/ui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
@@ -36,7 +36,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/apps/common.css $(LOCAL_PATH)/ui/webui/resources/css/apps/topbutton_bar.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/ui/webui/resources/js/webui_resource_test.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from webui/resources/webui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i webui/resources/webui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/ui/ui_resources.target.linux-mips.mk b/ui/ui_resources.target.linux-mips.mk
index 93a21dd..e336274 100644
--- a/ui/ui_resources.target.linux-mips.mk
+++ b/ui/ui_resources.target.linux-mips.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from resources/ui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i resources/ui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
@@ -36,7 +36,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/apps/common.css $(LOCAL_PATH)/ui/webui/resources/css/apps/topbutton_bar.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/ui/webui/resources/js/webui_resource_test.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from webui/resources/webui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i webui/resources/webui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/ui/ui_resources.target.linux-x86.mk b/ui/ui_resources.target.linux-x86.mk
index 93a21dd..e336274 100644
--- a/ui/ui_resources.target.linux-x86.mk
+++ b/ui/ui_resources.target.linux-x86.mk
@@ -18,7 +18,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/ui_resources.h: $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/ui_resources.grd $(LOCAL_PATH)/ui/resources/default_100_percent/app_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_shadow_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_32.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/default_favicon_64.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/window_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_center.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_left_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/content_right_side.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_app_panel_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default.png $(LOCAL_PATH)/ui/resources/default_100_percent/frame_default_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-bar.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-left.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-border-right.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux-progress-value.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_close_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_maximize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_minimize_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/linux/linux_restore_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_bottom_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_left_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/panel_top_right_corner.png $(LOCAL_PATH)/ui/resources/default_100_percent/throbber.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_pointer_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/bubble_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_mask.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_2_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/close_dialog_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/browser_action_badge_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/buy_with_google_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkmark.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/default_favicon.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/message_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_arrow_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_disabled.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_clear_all_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_close_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_do_not_disturb_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_expand_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/notification_settings_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_focused_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_inactive.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/radio_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/text_selection_handle_small.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_big_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_small_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_big_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_bubble_shadow_spike_small_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_active_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_bottom_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_left.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/window_shadow_inactive_top_right.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_normal.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/action_box_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/cros/menu_droparrow.png $(LOCAL_PATH)/ui/resources/default_200_percent/throbber.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_100_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_140_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_hover_top_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_bottom_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_center.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_right.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_left.png $(LOCAL_PATH)/ui/resources/touch_180_percent/common/textbutton_pressed_top_right.png $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from resources/ui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i resources/ui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
@@ -36,7 +36,7 @@
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
 $(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
-$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
+$(gyp_shared_intermediate_dir)/ui/ui_resources/grit/webui_resources.h: $(LOCAL_PATH)/third_party/jstemplate/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/webui_resources.grd $(LOCAL_PATH)/tools/gritsettings/resource_ids $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_inactive.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_closed_rtl.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open.png $(LOCAL_PATH)/ui/resources/default_100_percent/common/folder_open_rtl.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/blue_button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/button_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_checked_pressed.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_hover.png $(LOCAL_PATH)/ui/resources/default_200_percent/common/checkbox_pressed.png $(LOCAL_PATH)/ui/webui/resources/css/alert_overlay.css $(LOCAL_PATH)/ui/webui/resources/css/apps/common.css $(LOCAL_PATH)/ui/webui/resources/css/apps/topbutton_bar.css $(LOCAL_PATH)/ui/webui/resources/css/bubble.css $(LOCAL_PATH)/ui/webui/resources/css/bubble_button.css $(LOCAL_PATH)/ui/webui/resources/css/butter_bar.css $(LOCAL_PATH)/ui/webui/resources/css/chrome_shared.css $(LOCAL_PATH)/ui/webui/resources/css/dialogs.css $(LOCAL_PATH)/ui/webui/resources/css/list.css $(LOCAL_PATH)/ui/webui/resources/css/menu.css $(LOCAL_PATH)/ui/webui/resources/css/menu_button.css $(LOCAL_PATH)/ui/webui/resources/css/overlay.css $(LOCAL_PATH)/ui/webui/resources/css/spinner.css $(LOCAL_PATH)/ui/webui/resources/css/table.css $(LOCAL_PATH)/ui/webui/resources/css/tabs.css $(LOCAL_PATH)/ui/webui/resources/css/throbber.css $(LOCAL_PATH)/ui/webui/resources/css/trash.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css $(LOCAL_PATH)/ui/webui/resources/css/tree.css.js $(LOCAL_PATH)/ui/webui/resources/css/widgets.css $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/2x/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_close.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_maximize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_minimize.png $(LOCAL_PATH)/ui/webui/resources/images/apps/topbar_button_settings.png $(LOCAL_PATH)/ui/webui/resources/images/check.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_black.png $(LOCAL_PATH)/ui/webui/resources/images/checkbox_white.png $(LOCAL_PATH)/ui/webui/resources/images/clouds.png $(LOCAL_PATH)/ui/webui/resources/images/disabled_select.png $(LOCAL_PATH)/ui/webui/resources/images/gear.png $(LOCAL_PATH)/ui/webui/resources/images/google-transparent.png $(LOCAL_PATH)/ui/webui/resources/images/help.png $(LOCAL_PATH)/ui/webui/resources/images/select.png $(LOCAL_PATH)/ui/webui/resources/images/spinner.svg $(LOCAL_PATH)/ui/webui/resources/images/throbber.svg $(LOCAL_PATH)/ui/webui/resources/images/trash.png $(LOCAL_PATH)/ui/webui/resources/js/assert.js $(LOCAL_PATH)/ui/webui/resources/js/cr.js $(LOCAL_PATH)/ui/webui/resources/js/cr/event_target.js $(LOCAL_PATH)/ui/webui/resources/js/cr/link_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/promise.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/alert_overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/array_data_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/autocomplete_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/bubble_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/card_slider.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/command.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/context_menu_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/dialogs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/drag_wrapper.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/focus_outline_manager.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/grid.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_controller.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/list_single_selection_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/menu_item.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/overlay.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/position_util.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/repeating_button.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_column_model.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_header.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_list.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/table/table_splitter.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tabs.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/touch_handler.js $(LOCAL_PATH)/ui/webui/resources/js/cr/ui/tree.js $(LOCAL_PATH)/ui/webui/resources/js/event_tracker.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_process.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template2.js $(LOCAL_PATH)/ui/webui/resources/js/i18n_template_no_process.js $(LOCAL_PATH)/ui/webui/resources/js/jstemplate_compiled.js $(LOCAL_PATH)/ui/webui/resources/js/load_time_data.js $(LOCAL_PATH)/ui/webui/resources/js/local_strings.js $(LOCAL_PATH)/ui/webui/resources/js/media_common.js $(LOCAL_PATH)/ui/webui/resources/js/parse_html_subset.js $(LOCAL_PATH)/ui/webui/resources/js/util.js $(LOCAL_PATH)/ui/webui/resources/js/webui_resource_test.js $(LOCAL_PATH)/tools/grit/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit.py $(LOCAL_PATH)/tools/grit/grit/__init__.py $(LOCAL_PATH)/tools/grit/grit/clique.py $(LOCAL_PATH)/tools/grit/grit/clique_unittest.py $(LOCAL_PATH)/tools/grit/grit/constants.py $(LOCAL_PATH)/tools/grit/grit/exception.py $(LOCAL_PATH)/tools/grit/grit/extern/BogoFP.py $(LOCAL_PATH)/tools/grit/grit/extern/FP.py $(LOCAL_PATH)/tools/grit/grit/extern/__init__.py $(LOCAL_PATH)/tools/grit/grit/extern/tclib.py $(LOCAL_PATH)/tools/grit/grit/format/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml.py $(LOCAL_PATH)/tools/grit/grit/format/android_xml_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/c_format.py $(LOCAL_PATH)/tools/grit/grit/format/c_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json.py $(LOCAL_PATH)/tools/grit/grit/format/chrome_messages_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack.py $(LOCAL_PATH)/tools/grit/grit/format/data_pack_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline.py $(LOCAL_PATH)/tools/grit/grit/format/html_inline_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format.py $(LOCAL_PATH)/tools/grit/grit/format/js_map_format_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/PRESUBMIT.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/policy_template_generator_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/template_formatter.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writer_configuration.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/__init__.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adm_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/adml_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/admx_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/doc_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/json_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/mock_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_helper.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_strings_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/plist_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/reg_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/template_writer_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/writer_unittest_common.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_formatted_writer.py $(LOCAL_PATH)/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header.py $(LOCAL_PATH)/tools/grit/grit/format/rc_header_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/format/repack.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map.py $(LOCAL_PATH)/tools/grit/grit/format/resource_map_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/__init__.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template.py $(LOCAL_PATH)/tools/grit/grit/gather/admin_template_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image.py $(LOCAL_PATH)/tools/grit/grit/gather/chrome_scaled_image_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/igoogle_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/interface.py $(LOCAL_PATH)/tools/grit/grit/gather/json_loader.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings.py $(LOCAL_PATH)/tools/grit/grit/gather/muppet_strings_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json.py $(LOCAL_PATH)/tools/grit/grit/gather/policy_json_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/rc.py $(LOCAL_PATH)/tools/grit/grit/gather/rc_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/regexp.py $(LOCAL_PATH)/tools/grit/grit/gather/skeleton_gatherer.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html.py $(LOCAL_PATH)/tools/grit/grit/gather/tr_html_unittest.py $(LOCAL_PATH)/tools/grit/grit/gather/txt.py $(LOCAL_PATH)/tools/grit/grit/gather/txt_unittest.py $(LOCAL_PATH)/tools/grit/grit/grd_reader.py $(LOCAL_PATH)/tools/grit/grit/grd_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit/grit_runner.py $(LOCAL_PATH)/tools/grit/grit/grit_runner_unittest.py $(LOCAL_PATH)/tools/grit/grit/lazy_re.py $(LOCAL_PATH)/tools/grit/grit/lazy_re_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/base.py $(LOCAL_PATH)/tools/grit/grit/node/base_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/custom/__init__.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename.py $(LOCAL_PATH)/tools/grit/grit/node/custom/filename_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/empty.py $(LOCAL_PATH)/tools/grit/grit/node/include.py $(LOCAL_PATH)/tools/grit/grit/node/include_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/io.py $(LOCAL_PATH)/tools/grit/grit/node/io_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/mapping.py $(LOCAL_PATH)/tools/grit/grit/node/message.py $(LOCAL_PATH)/tools/grit/grit/node/message_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/misc.py $(LOCAL_PATH)/tools/grit/grit/node/misc_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/structure.py $(LOCAL_PATH)/tools/grit/grit/node/structure_unittest.py $(LOCAL_PATH)/tools/grit/grit/node/variant.py $(LOCAL_PATH)/tools/grit/grit/pseudo.py $(LOCAL_PATH)/tools/grit/grit/pseudo_rtl.py $(LOCAL_PATH)/tools/grit/grit/pseudo_unittest.py $(LOCAL_PATH)/tools/grit/grit/scons.py $(LOCAL_PATH)/tools/grit/grit/shortcuts.py $(LOCAL_PATH)/tools/grit/grit/shortcuts_unittests.py $(LOCAL_PATH)/tools/grit/grit/tclib.py $(LOCAL_PATH)/tools/grit/grit/tclib_unittest.py $(LOCAL_PATH)/tools/grit/grit/test_suite_all.py $(LOCAL_PATH)/tools/grit/grit/tool/__init__.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/android2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/build.py $(LOCAL_PATH)/tools/grit/grit/tool/build_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo.py $(LOCAL_PATH)/tools/grit/grit/tool/buildinfo_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/count.py $(LOCAL_PATH)/tools/grit/grit/tool/diff_structures.py $(LOCAL_PATH)/tools/grit/grit/tool/interface.py $(LOCAL_PATH)/tools/grit/grit/tool/menu_from_parts.py $(LOCAL_PATH)/tools/grit/grit/tool/newgrd.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/postprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_interface.py $(LOCAL_PATH)/tools/grit/grit/tool/preprocess_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd.py $(LOCAL_PATH)/tools/grit/grit/tool/rc2grd_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/resize.py $(LOCAL_PATH)/tools/grit/grit/tool/test.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_postprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/toolbar_preprocess.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc.py $(LOCAL_PATH)/tools/grit/grit/tool/transl2tc_unittest.py $(LOCAL_PATH)/tools/grit/grit/tool/unit.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb.py $(LOCAL_PATH)/tools/grit/grit/tool/xmb_unittest.py $(LOCAL_PATH)/tools/grit/grit/util.py $(LOCAL_PATH)/tools/grit/grit/util_unittest.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader.py $(LOCAL_PATH)/tools/grit/grit/xtb_reader_unittest.py $(LOCAL_PATH)/tools/grit/grit_info.py $(GYP_TARGET_DEPENDENCIES)
 	@echo "Gyp action: Generating resources from webui/resources/webui_resources.grd ($@)"
 	$(hide)cd $(gyp_local_path)/ui; mkdir -p $(gyp_shared_intermediate_dir)/ui/ui_resources/grit $(gyp_shared_intermediate_dir)/ui/ui_resources; python ../tools/grit/grit.py -i webui/resources/webui_resources.grd build -f ../tools/gritsettings/resource_ids -o "$(gyp_shared_intermediate_dir)/ui/ui_resources" -D _chromium -E "CHROMIUM_BUILD=chromium" -t android -E "ANDROID_JAVA_TAGGED_ONLY=true" -D use_concatenated_impulse_responses
 
diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi
index e62af93..e54e963 100644
--- a/ui/ui_unittests.gypi
+++ b/ui/ui_unittests.gypi
@@ -152,6 +152,7 @@
         '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/events/event_dispatcher_unittest.cc',
         'base/events/event_unittest.cc',
         'base/gtk/gtk_expanded_container_unittest.cc',
@@ -322,6 +323,11 @@
             'gfx/screen_unittest.cc',
           ],
         }],
+        ['chromeos==1', {
+          'sources!': [
+            'base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc',
+          ],
+        }],
       ],
       'target_conditions': [
         ['OS == "ios"', {
diff --git a/ui/ui_unittests.isolate b/ui/ui_unittests.isolate
index 35f732b..55ce04a 100644
--- a/ui/ui_unittests.isolate
+++ b/ui/ui_unittests.isolate
@@ -7,7 +7,6 @@
       'variables': {
         'isolate_dependency_tracked': [
           'base/test/data/data_pack_unittest/truncated-header.pak',
-          '<(PRODUCT_DIR)/chrome.pak',
           '<(PRODUCT_DIR)/locales/en-US.pak',
         ],
       },
diff --git a/ui/views/bubble/bubble_delegate.cc b/ui/views/bubble/bubble_delegate.cc
index 3987589..5eb9943 100644
--- a/ui/views/bubble/bubble_delegate.cc
+++ b/ui/views/bubble/bubble_delegate.cc
@@ -223,20 +223,21 @@
   }
 }
 
+void BubbleDelegateView::OnWidgetVisibilityChanging(Widget* widget,
+                                                    bool visible) {
+#if defined(OS_WIN)
+  // On Windows we need to handle this before the bubble is visible or hidden.
+  // Please see the comment on the OnWidgetVisibilityChanging function. On
+  // other platforms it is fine to handle it after the bubble is shown/hidden.
+  HandleVisibilityChanged(widget, visible);
+#endif
+}
+
 void BubbleDelegateView::OnWidgetVisibilityChanged(Widget* widget,
                                                    bool visible) {
-  if (widget != GetWidget())
-    return;
-
-  if (visible) {
-    if (border_widget_)
-      border_widget_->ShowInactive();
-    if (anchor_widget() && anchor_widget()->GetTopLevelWidget())
-      anchor_widget()->GetTopLevelWidget()->DisableInactiveRendering();
-  } else {
-    if (border_widget_)
-      border_widget_->Hide();
-  }
+#if !defined(OS_WIN)
+  HandleVisibilityChanged(widget, visible);
+#endif
 }
 
 void BubbleDelegateView::OnWidgetActivationChanged(Widget* widget,
@@ -405,4 +406,20 @@
 }
 #endif
 
+void BubbleDelegateView::HandleVisibilityChanged(Widget* widget,
+                                                 bool visible) {
+  if (widget != GetWidget())
+    return;
+
+  if (visible) {
+    if (border_widget_)
+      border_widget_->ShowInactive();
+    if (anchor_widget() && anchor_widget()->GetTopLevelWidget())
+      anchor_widget()->GetTopLevelWidget()->DisableInactiveRendering();
+  } else {
+    if (border_widget_)
+      border_widget_->Hide();
+  }
+}
+
 }  // namespace views
diff --git a/ui/views/bubble/bubble_delegate.h b/ui/views/bubble/bubble_delegate.h
index c534273..dff9bd4 100644
--- a/ui/views/bubble/bubble_delegate.h
+++ b/ui/views/bubble/bubble_delegate.h
@@ -47,7 +47,10 @@
 
   // WidgetObserver overrides:
   virtual void OnWidgetDestroying(Widget* widget) OVERRIDE;
-  virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible) OVERRIDE;
+  virtual void OnWidgetVisibilityChanging(Widget* widget, bool visible)
+      OVERRIDE;
+  virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible)
+      OVERRIDE;
   virtual void OnWidgetActivationChanged(Widget* widget, bool active) OVERRIDE;
   virtual void OnWidgetBoundsChanged(Widget* widget,
                                      const gfx::Rect& new_bounds) OVERRIDE;
@@ -161,6 +164,9 @@
   gfx::Rect GetBubbleClientBounds() const;
 #endif
 
+  // Handles widget visibility changes.
+  void HandleVisibilityChanged(Widget* widget, bool visible);
+
   // Fade animation for bubble.
   scoped_ptr<ui::SlideAnimation> fade_animation_;
 
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc
index 0d8accd..825c6ce 100644
--- a/ui/views/bubble/tray_bubble_view.cc
+++ b/ui/views/bubble/tray_bubble_view.cc
@@ -38,12 +38,40 @@
 const int kArrowOffsetRight = -5;
 const int kOffsetLeftRightForTopBottomOrientation = 5;
 
+// The sampling time for mouse position changes in ms - which is roughly a frame
+// time.
+const int kFrameTimeInMS = 30;
 }  // namespace
 
 namespace views {
 
 namespace internal {
 
+// Detects any mouse movement. This is needed to detect mouse movements by the
+// user over the bubble if the bubble got created underneath the cursor.
+class MouseMoveDetectorHost : public MouseWatcherHost {
+ public:
+  MouseMoveDetectorHost();
+  virtual ~MouseMoveDetectorHost();
+
+  virtual bool Contains(const gfx::Point& screen_point,
+                        MouseEventType type) OVERRIDE;
+ private:
+
+  DISALLOW_COPY_AND_ASSIGN(MouseMoveDetectorHost);
+};
+
+MouseMoveDetectorHost::MouseMoveDetectorHost() {
+}
+
+MouseMoveDetectorHost::~MouseMoveDetectorHost() {
+}
+
+bool MouseMoveDetectorHost::Contains(const gfx::Point& screen_point,
+                                     MouseEventType type) {
+  return false;
+}
+
 // Custom border for TrayBubbleView. Contains special logic for GetBounds()
 // to stack bubbles with no arrows correctly. Also calculates the arrow offset.
 class TrayBubbleBorder : public BubbleBorder {
@@ -293,7 +321,8 @@
       delegate_(delegate),
       preferred_width_(init_params.min_width),
       bubble_border_(NULL),
-      is_gesture_dragging_(false) {
+      is_gesture_dragging_(false),
+      mouse_actively_entered_(false) {
   set_parent_window(parent_window);
   set_notify_enter_exit_on_child(true);
   set_close_on_deactivate(init_params.close_on_deactivate);
@@ -309,6 +338,7 @@
 }
 
 TrayBubbleView::~TrayBubbleView() {
+  mouse_watcher_.reset();
   // Inform host items (models) that their views are being destroyed.
   if (delegate_)
     delegate_->BubbleViewDestroyed();
@@ -414,12 +444,36 @@
 }
 
 void TrayBubbleView::OnMouseEntered(const ui::MouseEvent& event) {
-  if (delegate_)
+  mouse_watcher_.reset();
+  if (delegate_ && !(event.flags() & ui::EF_IS_SYNTHESIZED)) {
+    // Coming here the user was actively moving the mouse over the bubble and
+    // we inform the delegate that we entered. This will prevent the bubble
+    // to auto close.
     delegate_->OnMouseEnteredView();
+    mouse_actively_entered_ = true;
+  } else {
+    // Coming here the bubble got shown and the mouse was 'accidentally' over it
+    // which is not a reason to prevent the bubble to auto close. As such we
+    // do not call the delegate, but wait for the first mouse move within the
+    // bubble. The used MouseWatcher will notify use of a movement and call
+    // |MouseMovedOutOfHost|.
+    mouse_watcher_.reset(new MouseWatcher(
+        new views::internal::MouseMoveDetectorHost(),
+        this));
+    // Set the mouse sampling frequency to roughly a frame time so that the user
+    // cannot see a lag.
+    mouse_watcher_->set_notify_on_exit_time(
+        base::TimeDelta::FromMilliseconds(kFrameTimeInMS));
+    mouse_watcher_->Start();
+  }
 }
 
 void TrayBubbleView::OnMouseExited(const ui::MouseEvent& event) {
-  if (delegate_)
+  // If there was a mouse watcher waiting for mouse movements we disable it
+  // immediately since we now leave the bubble.
+  mouse_watcher_.reset();
+  // Do not notify the delegate of an exit if we never told it that we entered.
+  if (delegate_ && mouse_actively_entered_)
     delegate_->OnMouseExitedView();
 }
 
@@ -430,6 +484,15 @@
   }
 }
 
+void TrayBubbleView::MouseMovedOutOfHost() {
+  // The mouse was accidentally over the bubble when it opened and the AutoClose
+  // logic was not activated. Now that the user did move the mouse we tell the
+  // delegate to disable AutoClose.
+  delegate_->OnMouseEnteredView();
+  mouse_actively_entered_ = true;
+  mouse_watcher_->Stop();
+}
+
 void TrayBubbleView::ChildPreferredSizeChanged(View* child) {
   SizeToContents();
 }
diff --git a/ui/views/bubble/tray_bubble_view.h b/ui/views/bubble/tray_bubble_view.h
index 9c96c54..1e9d482 100644
--- a/ui/views/bubble/tray_bubble_view.h
+++ b/ui/views/bubble/tray_bubble_view.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/mouse_watcher.h"
 #include "ui/views/views_export.h"
 
 // Specialized bubble view for bubbles associated with a tray icon (e.g. the
@@ -30,7 +31,8 @@
 class TrayBubbleContentMask;
 }
 
-class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView {
+class VIEWS_EXPORT TrayBubbleView : public views::BubbleDelegateView,
+                                    public views::MouseWatcherListener {
  public:
   // AnchorType differentiates between bubbles that are anchored on a tray
   // element (ANCHOR_TYPE_TRAY) and display an arrow, or that are floating on
@@ -62,6 +64,8 @@
     virtual void BubbleViewDestroyed() = 0;
 
     // Called when the mouse enters/exits the view.
+    // Note: This event will only be called if the mouse gets actively moved by
+    // the user to enter the view.
     virtual void OnMouseEnteredView() = 0;
     virtual void OnMouseExitedView() = 0;
 
@@ -159,6 +163,9 @@
   virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
   virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
 
+  // Overridden from MouseWatcherListener
+  virtual void MouseMovedOutOfHost() OVERRIDE;
+
  protected:
   TrayBubbleView(gfx::NativeView parent_window,
                  views::View* anchor,
@@ -181,6 +188,13 @@
   scoped_ptr<internal::TrayBubbleContentMask> bubble_content_mask_;
   bool is_gesture_dragging_;
 
+  // True once the mouse cursor was actively moved by the user over the bubble.
+  // Only then the OnMouseExitedView() event will get passed on to listeners.
+  bool mouse_actively_entered_;
+
+  // Used to find any mouse movements.
+  scoped_ptr<MouseWatcher> mouse_watcher_;
+
   DISALLOW_COPY_AND_ASSIGN(TrayBubbleView);
 };
 
diff --git a/ui/views/controls/button/blue_button.cc b/ui/views/controls/button/blue_button.cc
index a17441e..5163630 100644
--- a/ui/views/controls/button/blue_button.cc
+++ b/ui/views/controls/button/blue_button.cc
@@ -78,9 +78,4 @@
   return BlueButton::kViewClassName;
 }
 
-// TODO(msw): Re-enable animations for blue buttons. See crbug.com/239121.
-const ui::Animation* BlueButton::GetThemeAnimation() const {
-  return NULL;
-}
-
 }  // namespace views
diff --git a/ui/views/controls/button/blue_button.h b/ui/views/controls/button/blue_button.h
index 0415bf4..c939e00 100644
--- a/ui/views/controls/button/blue_button.h
+++ b/ui/views/controls/button/blue_button.h
@@ -6,7 +6,6 @@
 #define UI_VIEWS_CONTROLS_BUTTON_BLUE_BUTTON_H_
 
 #include "base/compiler_specific.h"
-#include "base/strings/string16.h"
 #include "ui/views/controls/button/label_button.h"
 
 namespace views {
@@ -22,7 +21,6 @@
  private:
   // Overridden from LabelButton:
   virtual const char* GetClassName() const OVERRIDE;
-  virtual const ui::Animation* GetThemeAnimation() const OVERRIDE;
 
   DISALLOW_COPY_AND_ASSIGN(BlueButton);
 };
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index 9fab63b..7abdc3b 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -128,7 +128,7 @@
   // STYLE_BUTTON uses bold text to indicate default buttons.
   if (style_ == STYLE_BUTTON) {
     int style = label_->font().GetStyle();
-    style = is_default ? style | gfx::Font::BOLD : style & !gfx::Font::BOLD;
+    style = is_default ? style | gfx::Font::BOLD : style & ~gfx::Font::BOLD;
     label_->SetFont(label_->font().DeriveFont(0, style));
   }
 }
diff --git a/ui/views/controls/button/label_button_border.cc b/ui/views/controls/button/label_button_border.cc
index efb80df..34ea502 100644
--- a/ui/views/controls/button/label_button_border.cc
+++ b/ui/views/controls/button/label_button_border.cc
@@ -6,10 +6,13 @@
 
 #include "base/logging.h"
 #include "grit/ui_resources.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/effects/SkLerpXfermode.h"
 #include "ui/base/animation/animation.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/rect.h"
+#include "ui/gfx/skia_util.h"
 #include "ui/gfx/sys_color_change_listener.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/controls/button/label_button.h"
@@ -119,17 +122,22 @@
   ui::NativeTheme::State state = native_theme_delegate->GetThemeState(&extra);
 
   if (animation && animation->is_animating()) {
-    // Composite the background and foreground painters during state animations.
-    int alpha = animation->CurrentValueBetween(0, 0xff);
+    // Linearly interpolate background and foreground painters during animation.
+    const SkRect sk_rect = gfx::RectToSkRect(rect);
+    canvas->sk_canvas()->saveLayer(&sk_rect, NULL);
     state = native_theme_delegate->GetBackgroundThemeState(&extra);
-    canvas->SaveLayerAlpha(static_cast<uint8>(0xff - alpha));
     PaintHelper(this, canvas, theme, part, state, rect, extra);
-    canvas->Restore();
 
+    SkPaint paint;
+    skia::RefPtr<SkXfermode> sk_lerp_xfer =
+        skia::AdoptRef(SkLerpXfermode::Create(animation->GetCurrentValue()));
+    paint.setXfermode(sk_lerp_xfer.get());
+    canvas->sk_canvas()->saveLayer(&sk_rect, &paint);
     state = native_theme_delegate->GetForegroundThemeState(&extra);
-    canvas->SaveLayerAlpha(static_cast<uint8>(alpha));
     PaintHelper(this, canvas, theme, part, state, rect, extra);
-    canvas->Restore();
+    canvas->sk_canvas()->restore();
+
+    canvas->sk_canvas()->restore();
   } else {
     PaintHelper(this, canvas, theme, part, state, rect, extra);
   }
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index 3e81ce5..05f9aed 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -19,9 +19,9 @@
 #include "ui/base/text/text_elider.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
-#include "ui/gfx/font.h"
 #include "ui/gfx/insets.h"
 #include "ui/gfx/shadow_value.h"
+#include "ui/gfx/text_utils.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/background.h"
 
@@ -31,6 +31,11 @@
 const int kFocusBorderPadding = 1;
 const int kCachedSizeLimit = 10;
 
+gfx::FontList GetDefaultFontList() {
+  return ui::ResourceBundle::GetSharedInstance().GetFontList(
+      ui::ResourceBundle::BaseFont);
+}
+
 }  // namespace
 
 namespace views {
@@ -39,27 +44,39 @@
 const char Label::kViewClassName[] = "Label";
 
 Label::Label() {
-  Init(string16(), GetDefaultFont());
+  Init(string16(), GetDefaultFontList());
 }
 
 Label::Label(const string16& text) {
-  Init(text, GetDefaultFont());
+  Init(text, GetDefaultFontList());
+}
+
+Label::Label(const string16& text, const gfx::FontList& font_list) {
+  Init(text, font_list);
 }
 
 Label::Label(const string16& text, const gfx::Font& font) {
-  Init(text, font);
+  Init(text, gfx::FontList(font));
 }
 
 Label::~Label() {
 }
 
-void Label::SetFont(const gfx::Font& font) {
-  font_ = font;
+void Label::SetFontList(const gfx::FontList& font_list) {
+  font_list_ = font_list;
   ResetCachedSize();
   PreferredSizeChanged();
   SchedulePaint();
 }
 
+const gfx::Font& Label::font() const {
+  return font_list_.GetPrimaryFont();
+}
+
+void Label::SetFont(const gfx::Font& font) {
+  SetFontList(gfx::FontList(font));
+}
+
 void Label::SetText(const string16& text) {
   if (text == text_)
     return;
@@ -172,7 +189,7 @@
   int label_width = 0;
   for (std::vector<string16>::const_iterator iter = lines.begin();
        iter != lines.end(); ++iter) {
-    label_width = std::max(label_width, font_.GetStringWidth(*iter));
+    label_width = std::max(label_width, gfx::GetStringWidth(*iter, font_list_));
   }
 
   label_width += GetInsets().width();
@@ -202,7 +219,7 @@
 }
 
 int Label::GetBaseline() const {
-  return GetInsets().top() + font_.GetBaseline();
+  return GetInsets().top() + font_list_.GetBaseline();
 }
 
 gfx::Size Label::GetPreferredSize() {
@@ -234,9 +251,9 @@
 
   int cache_width = w;
 
-  int h = font_.GetHeight();
+  int h = font_list_.GetHeight();
   const int flags = ComputeDrawStringFlags();
-  gfx::Canvas::SizeStringInt(text_, font_, &w, &h, line_height_, flags);
+  gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, line_height_, flags);
   cached_heights_[cached_heights_cursor_] = gfx::Size(cache_width, h);
   cached_heights_cursor_ = (cached_heights_cursor_ + 1) % kCachedSizeLimit;
   return h + GetInsets().height();
@@ -297,7 +314,7 @@
   if (has_shadow_)
     shadows.push_back(gfx::ShadowValue(shadow_offset_, 0,
         enabled() ? enabled_shadow_color_ : disabled_shadow_color_));
-  canvas->DrawStringWithShadows(text, font_,
+  canvas->DrawStringRectWithShadows(text, font_list_,
       enabled() ? actual_enabled_color_ : actual_disabled_color_,
       text_bounds, line_height_, flags, shadows);
 
@@ -316,13 +333,13 @@
     // on Linux.
     int w = is_multi_line_ ?
         GetAvailableRect().width() : std::numeric_limits<int>::max();
-    int h = font_.GetHeight();
+    int h = font_list_.GetHeight();
     // For single-line strings, ignore the available width and calculate how
     // wide the text wants to be.
     int flags = ComputeDrawStringFlags();
     if (!is_multi_line_)
       flags |= gfx::Canvas::NO_ELLIPSIS;
-    gfx::Canvas::SizeStringInt(text_, font_, &w, &h, line_height_, flags);
+    gfx::Canvas::SizeStringInt(text_, font_list_, &w, &h, line_height_, flags);
     text_size_.SetSize(w, h);
     text_size_valid_ = true;
   }
@@ -352,13 +369,8 @@
   UpdateColorsFromTheme(theme);
 }
 
-// static
-gfx::Font Label::GetDefaultFont() {
-  return ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
-}
-
-void Label::Init(const string16& text, const gfx::Font& font) {
-  font_ = font;
+void Label::Init(const string16& text, const gfx::FontList& font_list) {
+  font_list_ = font_list;
   enabled_color_set_ = disabled_color_set_ = background_color_set_ = false;
   auto_color_readability_ = true;
   UpdateColorsFromTheme(ui::NativeTheme::instance());
@@ -483,14 +495,14 @@
   if (is_multi_line_ || (elide_behavior_ == NO_ELIDE)) {
     *paint_text = text_;
   } else if (elide_behavior_ == ELIDE_IN_MIDDLE) {
-    *paint_text = ui::ElideText(text_, font_, GetAvailableRect().width(),
+    *paint_text = ui::ElideText(text_, font_list_, GetAvailableRect().width(),
                                 ui::ELIDE_IN_MIDDLE);
   } else if (elide_behavior_ == ELIDE_AT_END) {
-    *paint_text = ui::ElideText(text_, font_, GetAvailableRect().width(),
+    *paint_text = ui::ElideText(text_, font_list_, GetAvailableRect().width(),
                                 ui::ELIDE_AT_END);
   } else {
     DCHECK_EQ(ELIDE_AS_EMAIL, elide_behavior_);
-    *paint_text = ui::ElideEmail(text_, font_, GetAvailableRect().width());
+    *paint_text = ui::ElideEmail(text_, font_list_, GetAvailableRect().width());
   }
 
   *text_bounds = GetTextBounds();
@@ -524,7 +536,7 @@
 
 bool Label::ShouldShowDefaultTooltip() const {
   return !is_multi_line_ &&
-      font_.GetStringWidth(text_) > GetAvailableRect().width();
+      gfx::GetStringWidth(text_, font_list_) > GetAvailableRect().width();
 }
 
 }  // namespace views
diff --git a/ui/views/controls/label.h b/ui/views/controls/label.h
index d637d7f..40534ff 100644
--- a/ui/views/controls/label.h
+++ b/ui/views/controls/label.h
@@ -12,7 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/strings/string16.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
 #include "ui/gfx/text_constants.h"
 #include "ui/views/view.h"
 
@@ -54,12 +54,16 @@
 
   Label();
   explicit Label(const string16& text);
-  Label(const string16& text, const gfx::Font& font);
+  Label(const string16& text, const gfx::FontList& font_list);
+  Label(const string16& text, const gfx::Font& font);  // OBSOLETE
   virtual ~Label();
 
-  // Get or set the font used by this label.
-  const gfx::Font& font() const { return font_; }
-  virtual void SetFont(const gfx::Font& font);
+  // Gets or sets the fonts used by this label.
+  const gfx::FontList& font_list() const { return font_list_; }
+  virtual void SetFontList(const gfx::FontList& font_list);
+  // Obsolete gfx::Font version.  Should use gfx::FontList version instead.
+  const gfx::Font& font() const;  // OBSOLETE
+  virtual void SetFont(const gfx::Font& font);  // OBSOLETE
 
   // Get or set the label text.
   const string16& text() const { return text_; }
@@ -119,7 +123,7 @@
 
   // Get or set the distance in pixels between baselines of multi-line text.
   // Default is 0, indicating the distance between lines should be the standard
-  // one for the label's text, font, and platform.
+  // one for the label's text, font list, and platform.
   int line_height() const { return line_height_; }
   void SetLineHeight(int height);
 
@@ -208,9 +212,7 @@
   // Calls ComputeDrawStringFlags().
   FRIEND_TEST_ALL_PREFIXES(LabelTest, DisableSubpixelRendering);
 
-  static gfx::Font GetDefaultFont();
-
-  void Init(const string16& text, const gfx::Font& font);
+  void Init(const string16& text, const gfx::FontList& font_list);
 
   void RecalculateColors();
 
@@ -236,7 +238,7 @@
   bool ShouldShowDefaultTooltip() const;
 
   string16 text_;
-  gfx::Font font_;
+  gfx::FontList font_list_;
   SkColor requested_enabled_color_;
   SkColor actual_enabled_color_;
   SkColor requested_disabled_color_;
diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc
index 134a05d..be75281 100644
--- a/ui/views/controls/label_unittest.cc
+++ b/ui/views/controls/label_unittest.cc
@@ -16,17 +16,13 @@
 // All text sizing measurements (width and height) should be greater than this.
 const int kMinTextDimension = 4;
 
-TEST(LabelTest, FontPropertyCourier) {
+TEST(LabelTest, FontPropertySymbol) {
   Label label;
-  std::string font_name("courier");
-  // Note: This test is size dependent since Courier does not support all sizes.
+  std::string font_name("symbol");
   gfx::Font font(font_name, 26);
-  label.SetFont(font);
-  gfx::Font font_used = label.font();
-#if defined(OS_WIN)
-  // On Linux, this results in "Sans" instead of "courier".
+  label.SetFontList(gfx::FontList(font));
+  gfx::Font font_used = label.font_list().GetPrimaryFont();
   EXPECT_EQ(font_name, font_used.GetFontName());
-#endif
   EXPECT_EQ(26, font_used.GetFontSize());
 }
 
@@ -34,8 +30,8 @@
   Label label;
   std::string font_name("arial");
   gfx::Font font(font_name, 30);
-  label.SetFont(font);
-  gfx::Font font_used = label.font();
+  label.SetFontList(gfx::FontList(font));
+  gfx::Font font_used = label.font_list().GetPrimaryFont();
   EXPECT_EQ(font_name, font_used.GetFontName());
   EXPECT_EQ(30, font_used.GetFontSize());
 }
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index 960130d..afbd6b0 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -2124,6 +2124,15 @@
         PostMessage(window, event_type, nc_hit_result,
                     MAKELPARAM(screen_loc.x(), screen_loc.y()));
       }
+    } else if (event.type() == ui::ET_GESTURE_TAP_DOWN) {
+#if defined(USE_AURA)
+      // Gesture events need to be posted to the target root window. In
+      // desktop chrome there could be multiple root windows.
+      aura::RootWindow* target_root =
+          aura::RootWindow::GetForAcceleratedWidget(window);
+      if (target_root)
+        target_root->RepostEvent(event);
+#endif
     }
   }
 }
diff --git a/ui/views/controls/textfield/native_textfield_views.cc b/ui/views/controls/textfield/native_textfield_views.cc
index bf514d6..d572a72 100644
--- a/ui/views/controls/textfield/native_textfield_views.cc
+++ b/ui/views/controls/textfield/native_textfield_views.cc
@@ -718,7 +718,7 @@
 }
 
 int NativeTextfieldViews::GetTextfieldBaseline() const {
-  return GetRenderText()->font_list().GetBaseline();
+  return GetRenderText()->GetBaseline();
 }
 
 int NativeTextfieldViews::GetWidthNeededForText() const {
diff --git a/ui/views/controls/textfield/native_textfield_views_unittest.cc b/ui/views/controls/textfield/native_textfield_views_unittest.cc
index adaac20..5e8c689 100644
--- a/ui/views/controls/textfield/native_textfield_views_unittest.cc
+++ b/ui/views/controls/textfield/native_textfield_views_unittest.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 "ui/views/controls/textfield/native_textfield_views.h"
+
 #include <set>
 #include <string>
 #include <vector>
@@ -26,7 +28,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/gfx/render_text.h"
-#include "ui/views/controls/textfield/native_textfield_views.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/views/controls/textfield/textfield_views_model.h"
@@ -38,6 +39,10 @@
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 #define EXPECT_STR_EQ(ascii, utf16) EXPECT_EQ(ASCIIToUTF16(ascii), utf16)
 
 namespace {
@@ -179,6 +184,7 @@
 
     textfield_view_ = static_cast<NativeTextfieldViews*>(
         textfield_->GetNativeWrapperForTesting());
+    DCHECK(textfield_view_);
     textfield_view_->SetBoundsRect(params.bounds);
     textfield_->set_id(1);
 
@@ -188,7 +194,6 @@
       textfield->set_id(i + 1);
     }
 
-    DCHECK(textfield_view_);
     model_ = textfield_view_->model_.get();
     model_->ClearEditHistory();
 
@@ -1881,4 +1886,26 @@
   EXPECT_TRUE(textfield_view_->CanStartDragForView(NULL,
       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;
+#endif
+
+  InitTextfield(Textfield::STYLE_DEFAULT);
+  textfield_->SetText(UTF8ToUTF16("abc"));
+  const int old_baseline = textfield_->GetBaseline();
+
+  // Set text which may fall back to a font which has taller baseline than
+  // the default font.  |new_baseline| will be greater than |old_baseline|.
+  textfield_->SetText(UTF8ToUTF16("\xE0\xB9\x91"));
+  const int new_baseline = textfield_->GetBaseline();
+
+  EXPECT_GT(new_baseline, old_baseline);
+}
+
 }  // namespace views
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 6d982e0..4787e4e 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -28,7 +28,6 @@
 #include "ui/views/widget/widget.h"
 
 #if defined(OS_WIN)
-#include "base/win/metro.h"
 #include "base/win/win_util.h"
 // TODO(beng): this should be removed when the OS_WIN hack from
 // ViewHierarchyChanged is removed.
@@ -63,13 +62,6 @@
     return false;
   if (command_line->HasSwitch(switches::kEnableViewsTextfield))
     return true;
-  // Non-Aura Windows 8 Metro TSF is broken for Views Textfields. This temporary
-  // workaround reverts to the Windows native textfield controls in that case
-  // instead of disabling Views Textfields everywhere: http://crbug.com/259125
-  // The appropriate long-term fix to add that support for Views Textfields via
-  // InputMethodBridge is currently a work in progress: http://crbug.com/239690
-  if (base::win::IsMetroProcess())
-    return false;
   // The new dialog style cannot host native Windows textfield controls.
   if (switches::IsNewDialogStyleEnabled())
     return true;
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 2004a0a..4b453cb 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -171,9 +171,6 @@
   // Sets the text to display when empty.
   void set_placeholder_text(const string16& text) {
     placeholder_text_ = text;
-#if !defined(OS_LINUX)
-    NOTIMPLEMENTED();
-#endif
   }
   const string16& placeholder_text() const {
     return placeholder_text_;
diff --git a/ui/views/corewm/capture_controller.cc b/ui/views/corewm/capture_controller.cc
new file mode 100644
index 0000000..faf0caf
--- /dev/null
+++ b/ui/views/corewm/capture_controller.cc
@@ -0,0 +1,138 @@
+// 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/corewm/capture_controller.h"
+
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+
+namespace views {
+namespace corewm {
+
+////////////////////////////////////////////////////////////////////////////////
+// CaptureController, public:
+
+void CaptureController::Attach(aura::RootWindow* root) {
+  DCHECK_EQ(0u, root_windows_.count(root));
+  root_windows_.insert(root);
+  aura::client::SetCaptureClient(root, this);
+}
+
+void CaptureController::Detach(aura::RootWindow* root) {
+  root_windows_.erase(root);
+  aura::client::SetCaptureClient(root, NULL);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CaptureController, client::CaptureClient implementation:
+
+void CaptureController::SetCapture(aura::Window* new_capture_window) {
+  if (capture_window_ == new_capture_window)
+    return;
+
+  // Make sure window has a root window.
+  DCHECK(!new_capture_window || new_capture_window->GetRootWindow());
+  DCHECK(!capture_window_ || capture_window_->GetRootWindow());
+
+  aura::Window* old_capture_window = capture_window_;
+  aura::RootWindow* old_capture_root = old_capture_window ?
+      old_capture_window->GetRootWindow() : NULL;
+
+  // Copy the list in case it's modified out from under us.
+  RootWindows root_windows(root_windows_);
+
+  // 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
+  // distinction between the touches/gestures that were in the window all
+  // along (and so shouldn't be canceled) and those that got moved, so
+  // just leave them all where they are.
+  if (new_capture_window) {
+    for (RootWindows::const_iterator i = root_windows.begin();
+         i != root_windows.end(); ++i) {
+      (*i)->gesture_recognizer()->TransferEventsTo(
+          old_capture_window, new_capture_window);
+    }
+  }
+
+  capture_window_ = new_capture_window;
+
+  for (RootWindows::const_iterator i = root_windows.begin();
+       i != root_windows.end(); ++i) {
+    (*i)->UpdateCapture(old_capture_window, new_capture_window);
+  }
+
+  aura::RootWindow* capture_root =
+      capture_window_ ? capture_window_->GetRootWindow() : NULL;
+  if (capture_root != old_capture_root) {
+    if (old_capture_root)
+      old_capture_root->ReleaseNativeCapture();
+    if (capture_root)
+      capture_root->SetNativeCapture();
+  }
+}
+
+void CaptureController::ReleaseCapture(aura::Window* window) {
+  if (capture_window_ != window)
+    return;
+  SetCapture(NULL);
+}
+
+aura::Window* CaptureController::GetCaptureWindow() {
+  return capture_window_;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CaptureController, private:
+
+CaptureController::CaptureController()
+    : capture_window_(NULL) {
+}
+
+CaptureController::~CaptureController() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ScopedCaptureClient:
+
+// static
+CaptureController* ScopedCaptureClient::capture_controller_ = NULL;
+
+ScopedCaptureClient::ScopedCaptureClient(aura::RootWindow* root)
+    : root_window_(root) {
+  root->AddObserver(this);
+  if (!capture_controller_)
+    capture_controller_ = new CaptureController;
+  capture_controller_->Attach(root);
+}
+
+ScopedCaptureClient::~ScopedCaptureClient() {
+  Shutdown();
+}
+
+// static
+bool ScopedCaptureClient::IsActive() {
+  return capture_controller_ && capture_controller_->is_active();
+}
+
+void ScopedCaptureClient::OnWindowDestroyed(aura::Window* window) {
+  DCHECK_EQ(window, root_window_);
+  Shutdown();
+}
+
+void ScopedCaptureClient::Shutdown() {
+  if (!root_window_)
+    return;
+
+  root_window_->RemoveObserver(this);
+  capture_controller_->Detach(root_window_);
+  if (!capture_controller_->is_active()) {
+    delete capture_controller_;
+    capture_controller_ = NULL;
+  }
+  root_window_ = NULL;
+}
+
+}  // namespace corewm
+}  // namespace views
diff --git a/ui/views/corewm/capture_controller.h b/ui/views/corewm/capture_controller.h
new file mode 100644
index 0000000..343c3c0
--- /dev/null
+++ b/ui/views/corewm/capture_controller.h
@@ -0,0 +1,87 @@
+// 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_VIEWS_COREWM_CAPTURE_CONTROLLER_H_
+#define UI_VIEWS_COREWM_CAPTURE_CONTROLLER_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "ui/aura/client/capture_client.h"
+#include "ui/aura/window_observer.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+namespace corewm {
+
+// Internal CaptureClient implementation. See ScopedCaptureClient for details.
+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);
+
+  // Removes |root| from the list of RootWindows notified when capture changes.
+  void Detach(aura::RootWindow* root);
+
+  // Returns true if this CaptureController is installed on at least one
+  // RootWindow.
+  bool is_active() const { return !root_windows_.empty(); }
+
+  // Overridden from aura::client::CaptureClient:
+  virtual void SetCapture(aura::Window* window) OVERRIDE;
+  virtual void ReleaseCapture(aura::Window* window) OVERRIDE;
+  virtual aura::Window* GetCaptureWindow() OVERRIDE;
+
+ private:
+  friend class ScopedCaptureClient;
+  typedef std::set<aura::RootWindow*> RootWindows;
+
+  CaptureController();
+  virtual ~CaptureController();
+
+  // The current capture window. NULL if there is no capture window.
+  aura::Window* capture_window_;
+
+  // Set of RootWindows notified when capture changes.
+  RootWindows root_windows_;
+
+  DISALLOW_COPY_AND_ASSIGN(CaptureController);
+};
+
+// ScopedCaptureClient is responsible for creating a CaptureClient for a
+// RootWindow. Specifically it creates a single CaptureController that is shared
+// among all ScopedCaptureClients and adds the RootWindow to it.
+class VIEWS_EXPORT ScopedCaptureClient : public aura::WindowObserver {
+ public:
+  explicit ScopedCaptureClient(aura::RootWindow* root);
+  virtual ~ScopedCaptureClient();
+
+  // Returns true if there is a CaptureController with at least one RootWindow.
+  static bool IsActive();
+
+  aura::client::CaptureClient* capture_client() {
+    return capture_controller_;
+  }
+
+  // Overridden from aura::WindowObserver:
+  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
+
+ private:
+  // Invoked from destructor and OnWindowDestroyed() to cleanup.
+  void Shutdown();
+
+  // The single CaptureController instance.
+  static CaptureController* capture_controller_;
+
+  // RootWindow this ScopedCaptureClient was create for.
+  aura::RootWindow* root_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCaptureClient);
+};
+
+}  // namespace corewm
+}  // namespace views
+
+#endif  // UI_VIEWS_COREWM_CAPTURE_CONTROLLER_H_
diff --git a/ui/views/corewm/capture_controller_unittest.cc b/ui/views/corewm/capture_controller_unittest.cc
new file mode 100644
index 0000000..395c6f6
--- /dev/null
+++ b/ui/views/corewm/capture_controller_unittest.cc
@@ -0,0 +1,135 @@
+// 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/views/corewm/capture_controller.h"
+
+#include "base/logging.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_screen.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/base/events/event.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/root_view.h"
+#include "ui/views/widget/widget.h"
+
+#if !defined(OS_CHROMEOS)
+#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
+#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
+#endif
+
+namespace views {
+
+class CaptureControllerTest : public aura::test::AuraTestBase {
+ public:
+  CaptureControllerTest() {}
+
+  virtual void SetUp() OVERRIDE {
+    AuraTestBase::SetUp();
+    capture_controller_.reset(new corewm::ScopedCaptureClient(root_window()));
+
+    second_root_.reset(new aura::RootWindow(
+        aura::RootWindow::CreateParams(gfx::Rect(0, 0, 800, 600))));
+    second_root_->Init();
+    second_root_->Show();
+    second_root_->SetHostSize(gfx::Size(800, 600));
+    second_capture_controller_.reset(
+        new corewm::ScopedCaptureClient(second_root_.get()));
+
+#if !defined(OS_CHROMEOS)
+    desktop_position_client_.reset(new DesktopScreenPositionClient());
+    aura::client::SetScreenPositionClient(root_window(),
+                                          desktop_position_client_.get());
+
+    second_desktop_position_client_.reset(new DesktopScreenPositionClient());
+    aura::client::SetScreenPositionClient(
+        second_root_.get(),
+        second_desktop_position_client_.get());
+#endif
+  }
+
+  virtual void TearDown() OVERRIDE {
+    RunAllPendingInMessageLoop();
+
+#if !defined(OS_CHROMEOS)
+    second_desktop_position_client_.reset();
+#endif
+    second_capture_controller_.reset();
+
+    // Kill any active compositors before we hit the compositor shutdown paths.
+    second_root_.reset();
+
+#if !defined(OS_CHROMEOS)
+    desktop_position_client_.reset();
+#endif
+    capture_controller_.reset();
+
+    AuraTestBase::TearDown();
+  }
+
+  aura::Window* GetCaptureWindow() {
+    return capture_controller_->capture_client()->GetCaptureWindow();
+  }
+
+  aura::Window* GetSecondCaptureWindow() {
+    return second_capture_controller_->capture_client()->GetCaptureWindow();
+  }
+
+  scoped_ptr<corewm::ScopedCaptureClient> capture_controller_;
+  scoped_ptr<aura::RootWindow> second_root_;
+  scoped_ptr<corewm::ScopedCaptureClient> second_capture_controller_;
+#if !defined(OS_CHROMEOS)
+  scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client_;
+  scoped_ptr<aura::client::ScreenPositionClient>
+      second_desktop_position_client_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(CaptureControllerTest);
+};
+
+// Makes sure that internal details that are set on mouse down (such as
+// mouse_pressed_handler()) are cleared when another root window takes capture.
+TEST_F(CaptureControllerTest, ResetMouseEventHandlerOnCapture) {
+  // Create a window inside the RootWindow.
+  scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
+
+  // Make a synthesized mouse down event. Ensure that the RootWindow will
+  // dispatch further mouse events to |w1|.
+  ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 5),
+                                     gfx::Point(5, 5), 0);
+  root_window()->AsRootWindowHostDelegate()->OnHostMouseEvent(
+      &mouse_pressed_event);
+  EXPECT_EQ(w1.get(), root_window()->mouse_pressed_handler());
+
+  // Build a window in the second RootWindow.
+  scoped_ptr<aura::Window> w2(CreateNormalWindow(2, second_root_.get(), NULL));
+
+  // The act of having the second window take capture should clear out mouse
+  // pressed handler in the first RootWindow.
+  w2->SetCapture();
+  EXPECT_EQ(NULL, root_window()->mouse_pressed_handler());
+}
+
+// Makes sure that when one window gets capture, it forces the release on the
+// other. This is needed has to be handled explicitly on Linux, and is a sanity
+// check on Windows.
+TEST_F(CaptureControllerTest, ResetOtherWindowCaptureOnCapture) {
+  // Create a window inside the RootWindow.
+  scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
+  w1->SetCapture();
+  // Both capture clients should return the same capture window.
+  EXPECT_EQ(w1.get(), GetCaptureWindow());
+  EXPECT_EQ(w1.get(), GetSecondCaptureWindow());
+
+  // Build a window in the second RootWindow and give it capture. Both capture
+  // clients should return the same capture window.
+  scoped_ptr<aura::Window> w2(CreateNormalWindow(2, second_root_.get(), NULL));
+  w2->SetCapture();
+  EXPECT_EQ(w2.get(), GetCaptureWindow());
+  EXPECT_EQ(w2.get(), GetSecondCaptureWindow());
+}
+
+}  // namespace views
diff --git a/ui/views/corewm/compound_event_filter.cc b/ui/views/corewm/compound_event_filter.cc
index 91c1520..f1df8b5 100644
--- a/ui/views/corewm/compound_event_filter.cc
+++ b/ui/views/corewm/compound_event_filter.cc
@@ -5,6 +5,7 @@
 #include "ui/views/corewm/compound_event_filter.h"
 
 #include "base/containers/hash_tables.h"
+#include "base/logging.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/drag_drop_client.h"
@@ -183,6 +184,12 @@
   } else if (!show && !cursor_hidden_by_filter_) {
     cursor_hidden_by_filter_ = true;
     client->HideCursor();
+  } else if (show && !client->IsCursorVisible() && !client->IsCursorLocked()) {
+    // TODO(tdanderson): Remove this temporary logging once the issues related
+    // to a disappearing mouse cursor on the Pixel login screen / Pixel
+    // wakeup have been resolved. See crbug.com/275826.
+    LOG(ERROR) << "Event of type " << event->type() << " did not show cursor."
+               << " Mouse enabled state is " << client->IsMouseEventsEnabled();
   }
 }
 
diff --git a/ui/views/corewm/cursor_manager.cc b/ui/views/corewm/cursor_manager.cc
index 5c4dc81..07a71dc 100644
--- a/ui/views/corewm/cursor_manager.cc
+++ b/ui/views/corewm/cursor_manager.cc
@@ -172,6 +172,10 @@
   }
 }
 
+bool CursorManager::IsCursorLocked() const {
+  return cursor_lock_count_ > 0;
+}
+
 void CursorManager::AddObserver(
     aura::client::CursorClientObserver* observer) {
   observers_.AddObserver(observer);
diff --git a/ui/views/corewm/cursor_manager.h b/ui/views/corewm/cursor_manager.h
index 9e31640..659992b 100644
--- a/ui/views/corewm/cursor_manager.h
+++ b/ui/views/corewm/cursor_manager.h
@@ -38,8 +38,6 @@
   CursorManager(scoped_ptr<NativeCursorManager> delegate);
   virtual ~CursorManager();
 
-  bool is_cursor_locked() const { return cursor_lock_count_ > 0; }
-
   // Overridden from aura::client::CursorClient:
   virtual void SetCursor(gfx::NativeCursor) OVERRIDE;
   virtual void ShowCursor() OVERRIDE;
@@ -53,6 +51,7 @@
   virtual void SetDisplay(const gfx::Display& display) OVERRIDE;
   virtual void LockCursor() OVERRIDE;
   virtual void UnlockCursor() OVERRIDE;
+  virtual bool IsCursorLocked() const OVERRIDE;
   virtual void AddObserver(
       aura::client::CursorClientObserver* observer) OVERRIDE;
   virtual void RemoveObserver(
diff --git a/ui/views/corewm/desktop_capture_controller_unittest.cc b/ui/views/corewm/desktop_capture_controller_unittest.cc
new file mode 100644
index 0000000..830466a
--- /dev/null
+++ b/ui/views/corewm/desktop_capture_controller_unittest.cc
@@ -0,0 +1,170 @@
+// 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/views/corewm/capture_controller.h"
+
+#include "base/logging.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/base/events/event.h"
+#include "ui/views/test/views_test_base.h"
+#include "ui/views/view.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.h"
+
+namespace views {
+
+typedef ViewsTestBase DesktopCaptureControllerTest;
+
+// NOTE: these tests do native capture, so they have to be in
+// interactive_ui_tests.
+
+// This class provides functionality to verify whether the View instance
+// received the gesture event.
+class DesktopViewInputTest : public View {
+ public:
+  DesktopViewInputTest()
+      : received_gesture_event_(false) {}
+
+  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
+    received_gesture_event_ = true;
+    return View::OnGestureEvent(event);
+  }
+
+  // Resets state maintained by this class.
+  void Reset() {
+    received_gesture_event_ = false;
+  }
+
+  bool received_gesture_event() const { return received_gesture_event_; }
+
+ private:
+  bool received_gesture_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(DesktopViewInputTest);
+};
+
+// 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
+// aura::Windows one by one. It then sends a gesture event and validates whether
+// the window which had capture receives the gesture.
+TEST_F(DesktopCaptureControllerTest, CaptureWindowInputEventTest) {
+  scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client1;
+  scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client2;
+
+  scoped_ptr<Widget> widget1(new Widget());
+  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+  scoped_ptr<corewm::ScopedCaptureClient> scoped_capture_client(
+      new corewm::ScopedCaptureClient(params.context->GetRootWindow()));
+  aura::client::CaptureClient* capture_client =
+      scoped_capture_client->capture_client();
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.bounds = gfx::Rect(50, 50, 650, 650);
+  widget1->Init(params);
+  internal::RootView* root1 =
+      static_cast<internal::RootView*>(widget1->GetRootView());
+
+  desktop_position_client1.reset(new DesktopScreenPositionClient());
+  aura::client::SetScreenPositionClient(
+      widget1->GetNativeView()->GetRootWindow(),
+      desktop_position_client1.get());
+
+  DesktopViewInputTest* v1 = new DesktopViewInputTest();
+  v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+  root1->AddChildView(v1);
+  widget1->Show();
+
+  scoped_ptr<Widget> widget2(new Widget());
+
+  params = CreateParams(Widget::InitParams::TYPE_POPUP);
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params.bounds = gfx::Rect(50, 50, 650, 650);
+  widget2->Init(params);
+
+  internal::RootView* root2 =
+      static_cast<internal::RootView*>(widget2->GetRootView());
+  desktop_position_client2.reset(new DesktopScreenPositionClient());
+  aura::client::SetScreenPositionClient(
+      widget2->GetNativeView()->GetRootWindow(),
+      desktop_position_client2.get());
+
+  DesktopViewInputTest* v2 = new DesktopViewInputTest();
+  v2->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
+  root2->AddChildView(v2);
+  widget2->Show();
+
+  EXPECT_FALSE(widget1->GetNativeView()->HasCapture());
+  EXPECT_FALSE(widget2->GetNativeView()->HasCapture());
+  EXPECT_EQ(reinterpret_cast<aura::Window*>(0),
+            capture_client->GetCaptureWindow());
+
+  widget1->GetNativeView()->SetCapture();
+  EXPECT_TRUE(widget1->GetNativeView()->HasCapture());
+  EXPECT_FALSE(widget2->GetNativeView()->HasCapture());
+  EXPECT_EQ(capture_client->GetCaptureWindow(), widget1->GetNativeView());
+
+  ui::GestureEvent g1(ui::ET_GESTURE_LONG_PRESS, 80, 80, 0,
+                      base::TimeDelta(),
+                      ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS,
+                                              0.0f, 0.0f), 0);
+  root1->DispatchGestureEvent(&g1);
+  EXPECT_TRUE(v1->received_gesture_event());
+  EXPECT_FALSE(v2->received_gesture_event());
+  v1->Reset();
+  v2->Reset();
+
+  widget2->GetNativeView()->SetCapture();
+
+  EXPECT_FALSE(widget1->GetNativeView()->HasCapture());
+  EXPECT_TRUE(widget2->GetNativeView()->HasCapture());
+  EXPECT_EQ(capture_client->GetCaptureWindow(), widget2->GetNativeView());
+
+  root2->DispatchGestureEvent(&g1);
+  EXPECT_TRUE(v2->received_gesture_event());
+  EXPECT_FALSE(v1->received_gesture_event());
+
+  widget1->CloseNow();
+  widget2->CloseNow();
+  RunPendingMessages();
+}
+
+// Verifies aura::RootWindow is correctly notified on capture changes.
+TEST_F(DesktopCaptureControllerTest, TransferOnCapture) {
+  Widget widget1;
+  Widget::InitParams params1 =
+      CreateParams(views::Widget::InitParams::TYPE_WINDOW);
+  params1.native_widget = new DesktopNativeWidgetAura(&widget1);
+  params1.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  widget1.Init(params1);
+  widget1.Show();
+
+  Widget widget2;
+  Widget::InitParams params2 =
+      CreateParams(views::Widget::InitParams::TYPE_WINDOW);
+  params2.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params2.native_widget = new DesktopNativeWidgetAura(&widget2);
+  widget2.Init(params2);
+  widget2.Show();
+
+  // Set capture to |widget2|, then |widget1| and lastly release capture.
+  aura::Env::GetInstance()->set_mouse_button_flags(1);
+  widget2.SetCapture(widget2.GetRootView());
+  widget1.SetCapture(widget1.GetRootView());
+  widget1.ReleaseCapture();
+  // Widget1's RootWindow should still have a non-NULL |mouse_moved_handler_|
+  // (since it contains the view that had capture). OTOH Widget2 doesn't contain
+  // the Window that had capture and so its |mouse_moved_handler_| should be
+  // NULL.
+  EXPECT_NE(static_cast<aura::Window*>(NULL),
+            widget1.GetNativeView()->GetRootWindow()->mouse_moved_handler());
+  EXPECT_EQ(static_cast<aura::Window*>(NULL),
+            widget2.GetNativeView()->GetRootWindow()->mouse_moved_handler());
+  aura::Env::GetInstance()->set_mouse_button_flags(0);
+}
+
+}  // namespace views
diff --git a/ui/views/examples/content_client/examples_browser_main_parts.cc b/ui/views/examples/content_client/examples_browser_main_parts.cc
index d357e76..2cea5ef 100644
--- a/ui/views/examples/content_client/examples_browser_main_parts.cc
+++ b/ui/views/examples/content_client/examples_browser_main_parts.cc
@@ -12,7 +12,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/common/content_switches.h"
-#include "content/shell/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_context.h"
 #include "ui/views/examples/examples_window_with_content.h"
 #include "ui/views/focus/accelerator_handler.h"
 #include "ui/views/test/desktop_test_views_delegate.h"
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc
index 0a60ee1..a2b88b0 100644
--- a/ui/views/focus/focus_manager.cc
+++ b/ui/views/focus/focus_manager.cc
@@ -451,7 +451,6 @@
   while (new_focus_traversable) {
     DCHECK(!v);
     focus_traversable = new_focus_traversable;
-    starting_view = new_starting_view;
     new_focus_traversable = NULL;
     starting_view = NULL;
     v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc
index b83b82d..1a6f5c9 100644
--- a/ui/views/test/views_test_base.cc
+++ b/ui/views/test/views_test_base.cc
@@ -12,6 +12,7 @@
 #include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/aura_test_helper.h"
+#include "ui/views/corewm/capture_controller.h"
 #endif
 
 namespace views {
@@ -52,7 +53,8 @@
   ui::ShutdownInputMethodForTesting();
 #if defined(USE_AURA)
   aura_test_helper_->TearDown();
-#endif
+  CHECK(!corewm::ScopedCaptureClient::IsActive());
+#endif  // USE_AURA
 }
 
 void ViewsTestBase::RunPendingMessages() {
diff --git a/ui/views/view.cc b/ui/views/view.cc
index 080df12..73b1e4e 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -9,6 +9,7 @@
 #include <algorithm>
 #include <cmath>
 
+#include "base/auto_reset.h"
 #include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
@@ -185,6 +186,7 @@
       accessibility_focusable_(false),
       context_menu_controller_(NULL),
       drag_controller_(NULL),
+      currently_dragging_(false),
       post_dispatch_handler_(new internal::PostEventDispatchHandler(this)),
       native_view_accessibility_(NULL) {
   AddPostTargetHandler(post_dispatch_handler_.get());
@@ -194,6 +196,10 @@
   if (parent_)
     parent_->RemoveChildView(this);
 
+  // If we destroy the view during a drag, AutoReset will probably write to
+  // freed memory.
+  DCHECK(!currently_dragging_);
+
   for (Views::const_iterator i(children_.begin()); i != children_.end(); ++i) {
     (*i)->parent_ = NULL;
     if (!(*i)->owned_by_client_)
@@ -2318,10 +2324,14 @@
                   const gfx::Point& press_pt,
                   ui::DragDropTypes::DragEventSource source) {
 #if !defined(OS_MACOSX)
+  if (currently_dragging_)
+    return false;
+
   int drag_operations = GetDragOperations(press_pt);
   if (drag_operations == ui::DragDropTypes::DRAG_NONE)
     return false;
 
+  base::AutoReset<bool> updating_focus(&currently_dragging_, true);
   OSExchangeData data;
   WriteDragData(press_pt, &data);
 
@@ -2331,6 +2341,7 @@
   ConvertPointToWidget(this, &widget_location);
   GetWidget()->RunShellDrag(this, data, widget_location, drag_operations,
       source);
+
   return true;
 #else
   return false;
diff --git a/ui/views/view.h b/ui/views/view.h
index 2ffc620..337012c 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1540,6 +1540,11 @@
 
   DragController* drag_controller_;
 
+  // True while we're performing DoDrag(). On X11, we can have multiple mouse
+  // move events in our event queue when we start a drag, so we need a way to
+  // ignore events after the first one.
+  bool currently_dragging_;
+
   // Input  --------------------------------------------------------------------
 
   scoped_ptr<internal::PostEventDispatchHandler> post_dispatch_handler_;
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index 53b28f3..dfb604e 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -1601,31 +1601,6 @@
     view_test_->RunPendingMessages();
   }
 
-  void CheckEnumeratingNativeWidgets() {
-    if (!host_->GetTopLevelWidget())
-      return;
-    Widget::Widgets widgets;
-    Widget::GetAllChildWidgets(host_->GetNativeView(), &widgets);
-    EXPECT_EQ(TestNativeViewHierarchy::kTotalViews + 1, widgets.size());
-    // Unfortunately there is no guarantee the sequence of views here so always
-    // go through all of them.
-    for (Widget::Widgets::iterator i = widgets.begin();
-         i != widgets.end(); ++i) {
-      View* root_view = (*i)->GetRootView();
-      if (host_->GetRootView() == root_view)
-        continue;
-      size_t j;
-      for (j = 0; j < TestNativeViewHierarchy::kTotalViews; ++j)
-        if (root_views_[j] == root_view)
-          break;
-      // EXPECT_LT/GT/GE() fails to compile with class-defined constants
-      // with gcc, with error
-      // "error: undefined reference to 'TestNativeViewHierarchy::kTotalViews'"
-      // so I forced to use EXPECT_TRUE() instead.
-      EXPECT_TRUE(TestNativeViewHierarchy::kTotalViews > j);
-    }
-  }
-
   void CheckChangingHierarhy() {
     size_t i;
     for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) {
@@ -1656,14 +1631,6 @@
   ViewTest* view_test_;
 };
 
-TEST_F(ViewTest, ChangeNativeViewHierarchyFindRoots) {
-  // TODO(georgey): Fix the test for Linux
-#if defined(OS_WIN)
-  TestChangeNativeViewHierarchy test(this);
-  test.CheckEnumeratingNativeWidgets();
-#endif
-}
-
 TEST_F(ViewTest, ChangeNativeViewHierarchyChangeHierarchy) {
   // TODO(georgey): Fix the test for Linux
 #if defined(OS_WIN)
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index ff3ab0a..a8d444c 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -237,6 +237,8 @@
         'controls/tree/tree_view_controller.h',
         'corewm/base_focus_rules.cc',
         'corewm/base_focus_rules.h',
+        'corewm/capture_controller.cc',
+        'corewm/capture_controller.h',
         'corewm/compound_event_filter.cc',
         'corewm/compound_event_filter.h',
         'corewm/corewm_switches.cc',
@@ -349,8 +351,6 @@
         'widget/child_window_message_processor.h',
         'widget/desktop_aura/desktop_activation_client.cc',
         'widget/desktop_aura/desktop_activation_client.h',
-        '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_aurax11.cc',
         'widget/desktop_aura/desktop_cursor_loader_updater_aurax11.h',
@@ -376,6 +376,7 @@
         'widget/desktop_aura/desktop_root_window_host_x11.cc',
         'widget/desktop_aura/desktop_root_window_host_x11.h',
         'widget/desktop_aura/desktop_screen.h',
+        'widget/desktop_aura/desktop_screen_ozone.cc',
         'widget/desktop_aura/desktop_screen_position_client.cc',
         'widget/desktop_aura/desktop_screen_position_client.h',
         'widget/desktop_aura/desktop_screen_win.cc',
@@ -712,6 +713,7 @@
         'controls/textfield/native_textfield_views_unittest.cc',
         'controls/textfield/textfield_views_model_unittest.cc',
         'controls/tree/tree_view_unittest.cc',
+        'corewm/capture_controller_unittest.cc',
         'corewm/compound_event_filter_unittest.cc',
         'corewm/cursor_manager_unittest.cc',
         'corewm/focus_controller_unittest.cc',
@@ -736,7 +738,6 @@
         'view_unittest.cc',
         'window/dialog_client_view_unittest.cc',
         'window/dialog_delegate_unittest.cc',
-        'widget/desktop_aura/desktop_capture_client_unittest.cc',
         'widget/desktop_aura/desktop_screen_position_client_unittest.cc',
         'widget/native_widget_aura_unittest.cc',
         'widget/native_widget_unittest.cc',
diff --git a/ui/views/widget/desktop_aura/desktop_capture_client.cc b/ui/views/widget/desktop_aura/desktop_capture_client.cc
deleted file mode 100644
index bf89a4e..0000000
--- a/ui/views/widget/desktop_aura/desktop_capture_client.cc
+++ /dev/null
@@ -1,88 +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/widget/desktop_aura/desktop_capture_client.h"
-
-#include "ui/aura/root_window.h"
-
-namespace views {
-
-std::set<DesktopCaptureClient*> DesktopCaptureClient::live_capture_clients_;
-
-DesktopCaptureClient::DesktopCaptureClient(aura::RootWindow* root_window)
-    : root_window_(root_window),
-      capture_window_(NULL) {
-  aura::client::SetCaptureClient(root_window_, this);
-  live_capture_clients_.insert(this);
-}
-
-DesktopCaptureClient::~DesktopCaptureClient() {
-  live_capture_clients_.erase(this);
-  aura::client::SetCaptureClient(root_window_, NULL);
-}
-
-void DesktopCaptureClient::SetCapture(aura::Window* window) {
-  if (capture_window_ == window)
-    return;
-  if (window) {
-    // 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
-    // distinction between the touches/gestures that were in the window all
-    // along (and so shouldn't be canceled) and those that got moved, so
-    // just leave them all where they are.
-    for (std::set<DesktopCaptureClient*>::iterator it =
-             live_capture_clients_.begin(); it != live_capture_clients_.end();
-         ++it) {
-      (*it)->root_window_->gesture_recognizer()->TransferEventsTo(
-          capture_window_, window);
-    }
-  }
-  aura::Window* old_capture_window = GetCaptureWindow();
-  capture_window_ = window;
-
-  if (capture_window_) {
-    root_window_->SetNativeCapture();
-
-    for (std::set<DesktopCaptureClient*>::iterator it =
-             live_capture_clients_.begin(); it != live_capture_clients_.end();
-         ++it) {
-      if (*it != this)
-        (*it)->OnOtherCaptureClientTookCapture();
-    }
-  } else {
-    root_window_->ReleaseNativeCapture();
-  }
-
-  root_window_->UpdateCapture(old_capture_window, capture_window_);
-}
-
-void DesktopCaptureClient::ReleaseCapture(aura::Window* window) {
-  if (capture_window_ != window)
-    return;
-  SetCapture(NULL);
-}
-
-aura::Window* DesktopCaptureClient::GetCaptureWindow() {
-  for (std::set<DesktopCaptureClient*>::iterator it =
-            live_capture_clients_.begin(); it != live_capture_clients_.end();
-        ++it) {
-    if ((*it)->capture_window_)
-      return (*it)->capture_window_;
-  }
-  return NULL;
-}
-
-void DesktopCaptureClient::OnOtherCaptureClientTookCapture() {
-  if (capture_window_ == NULL) {
-    // While RootWindow may not technically have capture, it will store state
-    // that needs to be cleared on capture changed regarding mouse up/down.
-    root_window_->ClearMouseHandlers();
-  }
-  else {
-    SetCapture(NULL);
-  }
-}
-
-}  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_capture_client.h b/ui/views/widget/desktop_aura/desktop_capture_client.h
deleted file mode 100644
index ba12682..0000000
--- a/ui/views/widget/desktop_aura/desktop_capture_client.h
+++ /dev/null
@@ -1,44 +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_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CAPTURE_CLIENT_H_
-#define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CAPTURE_CLIENT_H_
-
-#include <set>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/aura/client/capture_client.h"
-#include "ui/views/views_export.h"
-
-namespace views {
-
-// A capture client which will collaborate with all other capture clients of
-// its class. When capture is changed in an instance of this capture client,
-// capture is released in all other windows.
-class VIEWS_EXPORT DesktopCaptureClient : public aura::client::CaptureClient {
- public:
-  explicit DesktopCaptureClient(aura::RootWindow* root_window);
-  virtual ~DesktopCaptureClient();
-
-  // Overridden from client::CaptureClient:
-  virtual void SetCapture(aura::Window* window) OVERRIDE;
-  virtual void ReleaseCapture(aura::Window* window) OVERRIDE;
-  virtual aura::Window* GetCaptureWindow() OVERRIDE;
-
- private:
-  // Called when another instance of the capture client takes capture.
-  void OnOtherCaptureClientTookCapture();
-
-  aura::RootWindow* root_window_;
-  aura::Window* capture_window_;
-
-  static std::set<DesktopCaptureClient*> live_capture_clients_;
-
-  DISALLOW_COPY_AND_ASSIGN(DesktopCaptureClient);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_CAPTURE_CLIENT_H_
diff --git a/ui/views/widget/desktop_aura/desktop_capture_client_unittest.cc b/ui/views/widget/desktop_aura/desktop_capture_client_unittest.cc
deleted file mode 100644
index d96c445..0000000
--- a/ui/views/widget/desktop_aura/desktop_capture_client_unittest.cc
+++ /dev/null
@@ -1,231 +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 "ui/views/widget/desktop_aura/desktop_capture_client.h"
-
-#include "ui/aura/root_window.h"
-#include "ui/aura/test/aura_test_base.h"
-#include "ui/aura/test/test_screen.h"
-#include "ui/aura/test/test_window_delegate.h"
-#include "ui/base/events/event.h"
-#include "ui/views/test/views_test_base.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/desktop_aura/desktop_screen_position_client.h"
-#include "ui/views/widget/root_view.h"
-#include "ui/views/widget/widget.h"
-
-namespace views {
-
-typedef ViewsTestBase ViewTest;
-
-class DesktopCaptureClientTest : public aura::test::AuraTestBase {
- public:
-  virtual void SetUp() OVERRIDE {
-    AuraTestBase::SetUp();
-    desktop_capture_client_.reset(new DesktopCaptureClient(root_window()));
-
-    second_root_.reset(new aura::RootWindow(
-        aura::RootWindow::CreateParams(gfx::Rect(0, 0, 800, 600))));
-    second_root_->Init();
-    second_root_->Show();
-    second_root_->SetHostSize(gfx::Size(800, 600));
-    second_desktop_capture_client_.reset(
-      new DesktopCaptureClient(second_root_.get()));
-
-    desktop_position_client_.reset(new DesktopScreenPositionClient());
-    aura::client::SetScreenPositionClient(root_window(),
-                                          desktop_position_client_.get());
-
-    second_desktop_position_client_.reset(new DesktopScreenPositionClient());
-    aura::client::SetScreenPositionClient(
-        second_root_.get(),
-        second_desktop_position_client_.get());
-  }
-
-  virtual void TearDown() OVERRIDE {
-    RunAllPendingInMessageLoop();
-
-    second_desktop_position_client_.reset();
-    second_desktop_capture_client_.reset();
-
-    // Kill any active compositors before we hit the compositor shutdown paths.
-    second_root_.reset();
-
-    desktop_position_client_.reset();
-    desktop_capture_client_.reset();
-
-    AuraTestBase::TearDown();
-  }
-
-  scoped_ptr<DesktopCaptureClient> desktop_capture_client_;
-  scoped_ptr<aura::RootWindow> second_root_;
-  scoped_ptr<DesktopCaptureClient> second_desktop_capture_client_;
-  scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client_;
-  scoped_ptr<aura::client::ScreenPositionClient>
-      second_desktop_position_client_;
-};
-
-// Makes sure that internal details that are set on mouse down (such as
-// mouse_pressed_handler()) are cleared when another root window takes capture.
-TEST_F(DesktopCaptureClientTest, ResetMouseEventHandlerOnCapture) {
-  // Create a window inside the RootWindow.
-  scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
-
-  // Make a synthesized mouse down event. Ensure that the RootWindow will
-  // dispatch further mouse events to |w1|.
-  ui::MouseEvent mouse_pressed_event(ui::ET_MOUSE_PRESSED, gfx::Point(5, 5),
-                                     gfx::Point(5, 5), 0);
-  root_window()->AsRootWindowHostDelegate()->OnHostMouseEvent(
-      &mouse_pressed_event);
-  EXPECT_EQ(w1.get(), root_window()->mouse_pressed_handler());
-
-  // Build a window in the second RootWindow.
-  scoped_ptr<aura::Window> w2(CreateNormalWindow(2, second_root_.get(), NULL));
-
-  // The act of having the second window take capture should clear out mouse
-  // pressed handler in the first RootWindow.
-  w2->SetCapture();
-  EXPECT_EQ(NULL, root_window()->mouse_pressed_handler());
-}
-
-// Makes sure that when one window gets capture, it forces the release on the
-// other. This is needed has to be handled explicitly on Linux, and is a sanity
-// check on Windows.
-TEST_F(DesktopCaptureClientTest, ResetOtherWindowCaptureOnCapture) {
-  // Create a window inside the RootWindow.
-  scoped_ptr<aura::Window> w1(CreateNormalWindow(1, root_window(), NULL));
-  w1->SetCapture();
-  // Both capture clients should return the same capture window.
-  EXPECT_EQ(w1.get(), desktop_capture_client_->GetCaptureWindow());
-  EXPECT_EQ(w1.get(), second_desktop_capture_client_->GetCaptureWindow());
-
-  // Build a window in the second RootWindow and give it capture. Both capture
-  // clients should return the same capture window.
-  scoped_ptr<aura::Window> w2(CreateNormalWindow(2, second_root_.get(), NULL));
-  w2->SetCapture();
-  EXPECT_EQ(w2.get(), desktop_capture_client_->GetCaptureWindow());
-  EXPECT_EQ(w2.get(), second_desktop_capture_client_->GetCaptureWindow());
-}
-
-// This class provides functionality to verify whether the View instance
-// received the gesture event.
-class DesktopViewInputTest : public View {
- public:
-  DesktopViewInputTest()
-      : received_gesture_event_(false) {}
-
-  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
-    received_gesture_event_ = true;
-    return View::OnGestureEvent(event);
-  }
-
-  // Resets state maintained by this class.
-  void Reset() {
-    received_gesture_event_ = false;
-  }
-
-  bool received_gesture_event() const { return received_gesture_event_; }
-
- private:
-  bool received_gesture_event_;
-
-  DISALLOW_COPY_AND_ASSIGN(DesktopViewInputTest);
-};
-
-// 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
-// aura::Windows one by one. It then sends a gesture event and validates whether
-// the window which had capture receives the gesture.
-TEST_F(ViewTest, CaptureWindowInputEventTest) {
-  scoped_ptr<DesktopCaptureClient> desktop_capture_client1;
-  scoped_ptr<DesktopCaptureClient> desktop_capture_client2;
-  scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client1;
-  scoped_ptr<aura::client::ScreenPositionClient> desktop_position_client2;
-
-  scoped_ptr<Widget> widget1(new Widget());
-  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.bounds = gfx::Rect(50, 50, 650, 650);
-  widget1->Init(params);
-  internal::RootView* root1 =
-      static_cast<internal::RootView*>(widget1->GetRootView());
-
-  desktop_capture_client1.reset(new DesktopCaptureClient(
-      widget1->GetNativeView()->GetRootWindow()));
-  desktop_position_client1.reset(new DesktopScreenPositionClient());
-  aura::client::SetScreenPositionClient(
-      widget1->GetNativeView()->GetRootWindow(),
-      desktop_position_client1.get());
-
-  DesktopViewInputTest* v1 = new DesktopViewInputTest();
-  v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
-  root1->AddChildView(v1);
-  widget1->Show();
-
-  scoped_ptr<Widget> widget2(new Widget());
-
-  params = CreateParams(Widget::InitParams::TYPE_POPUP);
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.bounds = gfx::Rect(50, 50, 650, 650);
-  widget2->Init(params);
-
-  internal::RootView* root2 =
-      static_cast<internal::RootView*>(widget2->GetRootView());
-  desktop_capture_client2.reset(new DesktopCaptureClient(
-      widget2->GetNativeView()->GetRootWindow()));
-  desktop_position_client2.reset(new DesktopScreenPositionClient());
-  aura::client::SetScreenPositionClient(
-      widget2->GetNativeView()->GetRootWindow(),
-      desktop_position_client2.get());
-
-  DesktopViewInputTest* v2 = new DesktopViewInputTest();
-  v2->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
-  root2->AddChildView(v2);
-  widget2->Show();
-
-  EXPECT_FALSE(widget1->GetNativeView()->HasCapture());
-  EXPECT_FALSE(widget2->GetNativeView()->HasCapture());
-  EXPECT_EQ(desktop_capture_client1->GetCaptureWindow(),
-            reinterpret_cast<aura::Window*>(0));
-  EXPECT_EQ(desktop_capture_client2->GetCaptureWindow(),
-            reinterpret_cast<aura::Window*>(0));
-
-  widget1->GetNativeView()->SetCapture();
-  EXPECT_TRUE(widget1->GetNativeView()->HasCapture());
-  EXPECT_FALSE(widget2->GetNativeView()->HasCapture());
-  EXPECT_EQ(desktop_capture_client1->GetCaptureWindow(),
-            widget1->GetNativeView());
-  EXPECT_EQ(desktop_capture_client2->GetCaptureWindow(),
-            widget1->GetNativeView());
-
-  ui::GestureEvent g1(ui::ET_GESTURE_LONG_PRESS, 80, 80, 0,
-                      base::TimeDelta(),
-                      ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS,
-                                              0.0f, 0.0f), 0);
-  root1->DispatchGestureEvent(&g1);
-  EXPECT_TRUE(v1->received_gesture_event());
-  EXPECT_FALSE(v2->received_gesture_event());
-  v1->Reset();
-  v2->Reset();
-
-  widget2->GetNativeView()->SetCapture();
-
-  EXPECT_FALSE(widget1->GetNativeView()->HasCapture());
-  EXPECT_TRUE(widget2->GetNativeView()->HasCapture());
-  EXPECT_EQ(desktop_capture_client1->GetCaptureWindow(),
-            widget2->GetNativeView());
-  EXPECT_EQ(desktop_capture_client2->GetCaptureWindow(),
-            widget2->GetNativeView());
-
-  root2->DispatchGestureEvent(&g1);
-  EXPECT_TRUE(v2->received_gesture_event());
-  EXPECT_FALSE(v1->received_gesture_event());
-
-  widget1->CloseNow();
-  widget2->CloseNow();
-  RunPendingMessages();
-}
-
-}  // namespace views
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 207e655..859decc 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -23,6 +23,7 @@
 #include "ui/gfx/screen.h"
 #include "ui/gfx/size_conversions.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/corewm/capture_controller.h"
 #include "ui/views/corewm/compound_event_filter.h"
 #include "ui/views/corewm/corewm_switches.h"
 #include "ui/views/corewm/input_method_event_filter.h"
@@ -36,6 +37,7 @@
 #include "ui/views/ime/input_method_bridge.h"
 #include "ui/views/widget/desktop_aura/desktop_root_window_host.h"
 #include "ui/views/widget/drop_helper.h"
+#include "ui/views/widget/native_widget_aura.h"
 #include "ui/views/widget/native_widget_aura_window_observer.h"
 #include "ui/views/widget/root_view.h"
 #include "ui/views/widget/tooltip_manager_aura.h"
@@ -218,6 +220,11 @@
   root_window_event_filter_->AddHandler(input_method_event_filter_.get());
 }
 
+void DesktopNativeWidgetAura::CreateCaptureClient(aura::RootWindow* root) {
+  DCHECK(!capture_client_.get());
+  capture_client_.reset(new corewm::ScopedCaptureClient(root));
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation:
 
@@ -225,7 +232,7 @@
     const Widget::InitParams& params) {
   ownership_ = params.ownership;
 
-  window_->set_user_data(this);
+  NativeWidgetAura::RegisterNativeWidgetForWindow(this, window_);
   window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
   window_->SetTransparent(true);
   window_->Init(params.layer_type);
@@ -315,15 +322,16 @@
 }
 
 const ui::Compositor* DesktopNativeWidgetAura::GetCompositor() const {
-  return window_->layer()->GetCompositor();
+  return window_ ? window_->layer()->GetCompositor() : NULL;
 }
 
 ui::Compositor* DesktopNativeWidgetAura::GetCompositor() {
-  return window_->layer()->GetCompositor();
+  return const_cast<ui::Compositor*>(
+      const_cast<const DesktopNativeWidgetAura*>(this)->GetCompositor());
 }
 
 ui::Layer* DesktopNativeWidgetAura::GetLayer() {
-  return window_->layer();
+  return window_ ? window_->layer() : NULL;
 }
 
 void DesktopNativeWidgetAura::ReorderNativeViews() {
@@ -335,11 +343,12 @@
 
 void DesktopNativeWidgetAura::SetNativeWindowProperty(const char* name,
                                                       void* value) {
-  window_->SetNativeWindowProperty(name, value);
+  if (window_)
+    window_->SetNativeWindowProperty(name, value);
 }
 
 void* DesktopNativeWidgetAura::GetNativeWindowProperty(const char* name) const {
-  return window_->GetNativeWindowProperty(name);
+  return window_ ? window_->GetNativeWindowProperty(name) : NULL;
 }
 
 TooltipManager* DesktopNativeWidgetAura::GetTooltipManager() const {
@@ -347,6 +356,9 @@
 }
 
 void DesktopNativeWidgetAura::SetCapture() {
+  if (!window_)
+    return;
+
   window_->SetCapture();
   // aura::Window doesn't implicitly update capture on the RootWindowHost, so
   // we have to do that manually.
@@ -355,6 +367,9 @@
 }
 
 void DesktopNativeWidgetAura::ReleaseCapture() {
+  if (!window_)
+    return;
+
   window_->ReleaseCapture();
   // aura::Window doesn't implicitly update capture on the RootWindowHost, so
   // we have to do that manually.
@@ -363,7 +378,8 @@
 }
 
 bool DesktopNativeWidgetAura::HasCapture() const {
-  return window_->HasCapture() && desktop_root_window_host_->HasCapture();
+  return window_ && window_->HasCapture() &&
+      desktop_root_window_host_->HasCapture();
 }
 
 InputMethod* DesktopNativeWidgetAura::CreateInputMethod() {
@@ -377,46 +393,53 @@
 }
 
 void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) {
-  desktop_root_window_host_->CenterWindow(size);
+  if (window_)
+    desktop_root_window_host_->CenterWindow(size);
 }
 
 void DesktopNativeWidgetAura::GetWindowPlacement(
       gfx::Rect* bounds,
       ui::WindowShowState* maximized) const {
-  desktop_root_window_host_->GetWindowPlacement(bounds, maximized);
+  if (window_)
+    desktop_root_window_host_->GetWindowPlacement(bounds, maximized);
 }
 
 void DesktopNativeWidgetAura::SetWindowTitle(const string16& title) {
-  desktop_root_window_host_->SetWindowTitle(title);
+  if (window_)
+    desktop_root_window_host_->SetWindowTitle(title);
 }
 
 void DesktopNativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
                                              const gfx::ImageSkia& app_icon) {
-  desktop_root_window_host_->SetWindowIcons(window_icon, app_icon);
+  if (window_)
+    desktop_root_window_host_->SetWindowIcons(window_icon, app_icon);
 }
 
 void DesktopNativeWidgetAura::InitModalType(ui::ModalType modal_type) {
   // 99% of the time, we should not be asked to create a
-  // DesktopNativeWidgetAura that is modal. The case where this breaks down is
-  // when there are no browser windows and a background extension tries to
-  // display a simple alert dialog. (This case was masked because we used to
-  // have a hidden RootWindow which was the parent of these modal dialogs; they
-  // weren't displayed to the user.)
+  // DesktopNativeWidgetAura that is modal. We only support window modal
+  // dialogs on the same lines as non AURA.
+  desktop_root_window_host_->InitModalType(modal_type);
 }
 
 gfx::Rect DesktopNativeWidgetAura::GetWindowBoundsInScreen() const {
-  return desktop_root_window_host_->GetWindowBoundsInScreen();
+  return window_ ? desktop_root_window_host_->GetWindowBoundsInScreen() :
+      gfx::Rect();
 }
 
 gfx::Rect DesktopNativeWidgetAura::GetClientAreaBoundsInScreen() const {
-  return desktop_root_window_host_->GetClientAreaBoundsInScreen();
+  return window_ ? desktop_root_window_host_->GetClientAreaBoundsInScreen() :
+      gfx::Rect();
 }
 
 gfx::Rect DesktopNativeWidgetAura::GetRestoredBounds() const {
-  return desktop_root_window_host_->GetRestoredBounds();
+  return window_ ? desktop_root_window_host_->GetRestoredBounds() : gfx::Rect();
 }
 
 void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
+  if (!window_)
+    return;
+
   float scale = 1;
   aura::RootWindow* root = root_window_.get();
   if (root) {
@@ -430,7 +453,8 @@
 }
 
 void DesktopNativeWidgetAura::SetSize(const gfx::Size& size) {
-  desktop_root_window_host_->SetSize(size);
+  if (window_)
+    desktop_root_window_host_->SetSize(size);
 }
 
 void DesktopNativeWidgetAura::StackAbove(gfx::NativeView native_view) {
@@ -443,98 +467,117 @@
 }
 
 void DesktopNativeWidgetAura::SetShape(gfx::NativeRegion shape) {
-  desktop_root_window_host_->SetShape(shape);
+  if (window_)
+    desktop_root_window_host_->SetShape(shape);
 }
 
 void DesktopNativeWidgetAura::Close() {
+  if (!window_)
+    return;
   desktop_root_window_host_->Close();
-  if (window_)
-    window_->SuppressPaint();
+  window_->SuppressPaint();
 }
 
 void DesktopNativeWidgetAura::CloseNow() {
-  desktop_root_window_host_->CloseNow();
+  if (window_)
+    desktop_root_window_host_->CloseNow();
 }
 
 void DesktopNativeWidgetAura::Show() {
+  if (!window_)
+    return;
   desktop_root_window_host_->AsRootWindowHost()->Show();
   window_->Show();
 }
 
 void DesktopNativeWidgetAura::Hide() {
+  if (!window_)
+    return;
   desktop_root_window_host_->AsRootWindowHost()->Hide();
-  if (window_)
-    window_->Hide();
+  window_->Hide();
 }
 
 void DesktopNativeWidgetAura::ShowMaximizedWithBounds(
       const gfx::Rect& restored_bounds) {
+  if (!window_)
+    return;
   desktop_root_window_host_->ShowMaximizedWithBounds(restored_bounds);
   window_->Show();
 }
 
 void DesktopNativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
+  if (!window_)
+    return;
   desktop_root_window_host_->ShowWindowWithState(state);
   window_->Show();
 }
 
 bool DesktopNativeWidgetAura::IsVisible() const {
-  return desktop_root_window_host_->IsVisible();
+  return window_ && desktop_root_window_host_->IsVisible();
 }
 
 void DesktopNativeWidgetAura::Activate() {
-  desktop_root_window_host_->Activate();
+  if (window_)
+    desktop_root_window_host_->Activate();
 }
 
 void DesktopNativeWidgetAura::Deactivate() {
-  desktop_root_window_host_->Deactivate();
+  if (window_)
+    desktop_root_window_host_->Deactivate();
 }
 
 bool DesktopNativeWidgetAura::IsActive() const {
-  return desktop_root_window_host_->IsActive();
+  return window_ && desktop_root_window_host_->IsActive();
 }
 
 void DesktopNativeWidgetAura::SetAlwaysOnTop(bool always_on_top) {
-  desktop_root_window_host_->SetAlwaysOnTop(always_on_top);
+  if (window_)
+    desktop_root_window_host_->SetAlwaysOnTop(always_on_top);
 }
 
 void DesktopNativeWidgetAura::Maximize() {
-  desktop_root_window_host_->Maximize();
+  if (window_)
+    desktop_root_window_host_->Maximize();
 }
 
 void DesktopNativeWidgetAura::Minimize() {
-  desktop_root_window_host_->Minimize();
+  if (window_)
+    desktop_root_window_host_->Minimize();
 }
 
 bool DesktopNativeWidgetAura::IsMaximized() const {
-  return desktop_root_window_host_->IsMaximized();
+  return window_ && desktop_root_window_host_->IsMaximized();
 }
 
 bool DesktopNativeWidgetAura::IsMinimized() const {
-  return desktop_root_window_host_->IsMinimized();
+  return window_ && desktop_root_window_host_->IsMinimized();
 }
 
 void DesktopNativeWidgetAura::Restore() {
-  desktop_root_window_host_->Restore();
+  if (window_)
+    desktop_root_window_host_->Restore();
 }
 
 void DesktopNativeWidgetAura::SetFullscreen(bool fullscreen) {
-  desktop_root_window_host_->SetFullscreen(fullscreen);
+  if (window_)
+    desktop_root_window_host_->SetFullscreen(fullscreen);
 }
 
 bool DesktopNativeWidgetAura::IsFullscreen() const {
-  return desktop_root_window_host_->IsFullscreen();
+  return window_ && desktop_root_window_host_->IsFullscreen();
 }
 
 void DesktopNativeWidgetAura::SetOpacity(unsigned char opacity) {
-  desktop_root_window_host_->SetOpacity(opacity);
+  if (window_)
+    desktop_root_window_host_->SetOpacity(opacity);
 }
 
 void DesktopNativeWidgetAura::SetUseDragFrame(bool use_drag_frame) {
 }
 
 void DesktopNativeWidgetAura::FlashFrame(bool flash_frame) {
-  desktop_root_window_host_->FlashFrame(flash_frame);
+  if (window_)
+    desktop_root_window_host_->FlashFrame(flash_frame);
 }
 
 void DesktopNativeWidgetAura::RunShellDrag(
@@ -560,6 +603,8 @@
 }
 
 bool DesktopNativeWidgetAura::IsMouseEventsEnabled() const {
+  if (!window_)
+    return false;
   aura::client::CursorClient* cursor_client =
       aura::client::GetCursorClient(window_->GetRootWindow());
   return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
@@ -579,28 +624,34 @@
 }
 
 void DesktopNativeWidgetAura::SetInactiveRenderingDisabled(bool value) {
+  if (!window_)
+    return;
+
   if (!value) {
     active_window_observer_.reset();
   } else {
     active_window_observer_.reset(
         new NativeWidgetAuraWindowObserver(window_, native_widget_delegate_));
   }
-  desktop_root_window_host_->SetInactiveRenderingDisabled(value);
 }
 
 Widget::MoveLoopResult DesktopNativeWidgetAura::RunMoveLoop(
     const gfx::Vector2d& drag_offset,
     Widget::MoveLoopSource source) {
+  if (!window_)
+    return Widget::MOVE_LOOP_CANCELED;
   return desktop_root_window_host_->RunMoveLoop(drag_offset, source);
 }
 
 void DesktopNativeWidgetAura::EndMoveLoop() {
-  desktop_root_window_host_->EndMoveLoop();
+  if (window_)
+    desktop_root_window_host_->EndMoveLoop();
 }
 
 void DesktopNativeWidgetAura::SetVisibilityChangedAnimationsEnabled(
     bool value) {
-  desktop_root_window_host_->SetVisibilityChangedAnimationsEnabled(value);
+  if (window_)
+    desktop_root_window_host_->SetVisibilityChangedAnimationsEnabled(value);
 }
 
 ui::NativeTheme* DesktopNativeWidgetAura::GetNativeTheme() const {
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 b98e1cc..ce95139 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -27,6 +27,7 @@
 namespace corewm {
 class CompoundEventFilter;
 class InputMethodEventFilter;
+class ScopedCaptureClient;
 class ShadowController;
 class TooltipController;
 class VisibilityController;
@@ -69,6 +70,9 @@
     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;
 
@@ -209,6 +213,8 @@
   // See class documentation for Widget in widget.h for a note about ownership.
   Widget::InitParams::Ownership ownership_;
 
+  scoped_ptr<corewm::ScopedCaptureClient> capture_client_;
+
   // The NativeWidget owns the RootWindow. Required because the RootWindow owns
   // its RootWindowHost, so DesktopRootWindowHost can't own it.
   scoped_ptr<aura::RootWindow> root_window_;
@@ -224,7 +230,11 @@
 
   // Ownership passed to RootWindow on Init.
   DesktopRootWindowHost* desktop_root_window_host_;
+
+  // The content of |root_window_|. WARNING: this may be NULL if deleted out
+  // from under us.
   aura::Window* window_;
+
   internal::NativeWidgetDelegate* native_widget_delegate_;
 
   scoped_ptr<aura::client::StackingClient> stacking_client_;
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 afc412a..9bdc946 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host.h
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host.h
@@ -113,9 +113,6 @@
   // blurred.
   virtual void OnNativeWidgetFocus() = 0;
   virtual void OnNativeWidgetBlur() = 0;
-
-  // Paints the host window as activated depending on the bool passed in.
-  virtual void SetInactiveRenderingDisabled(bool disable_inactive) = 0;
 };
 
 }  // 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 159ffc1..52b1b50 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
@@ -30,7 +30,6 @@
 #include "ui/views/corewm/window_animations.h"
 #include "ui/views/ime/input_method_bridge.h"
 #include "ui/views/widget/desktop_aura/desktop_activation_client.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_drag_drop_client_win.h"
@@ -134,8 +133,7 @@
   root_window_->Init();
   root_window_->AddChild(content_window_);
 
-  capture_client_.reset(new views::DesktopCaptureClient(root_window_));
-  aura::client::SetCaptureClient(root_window_, capture_client_.get());
+  desktop_native_widget_aura_->CreateCaptureClient(root_window_);
 
   if (corewm::UseFocusControllerOnDesktop()) {
     corewm::FocusController* focus_controller =
@@ -388,13 +386,6 @@
 void DesktopRootWindowHostWin::OnNativeWidgetBlur() {
 }
 
-void DesktopRootWindowHostWin::SetInactiveRenderingDisabled(
-    bool disable_inactive) {
-  // Force the non-client area (most notably the title bar) to paint as either
-  // active or inactive, depending on the input.
-  SendMessage(message_handler_->hwnd(), WM_NCACTIVATE, !!disable_inactive, 0);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopRootWindowHostWin, RootWindowHost implementation:
 
@@ -506,14 +497,6 @@
 void DesktopRootWindowHostWin::SetFocusWhenShown(bool focus_when_shown) {
 }
 
-bool DesktopRootWindowHostWin::CopyAreaToSkCanvas(
-    const gfx::Rect& source_bounds,
-    const gfx::Point& dest_offset,
-    SkCanvas* canvas) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 void DesktopRootWindowHostWin::PostNativeEvent(
     const base::NativeEvent& native_event) {
 }
@@ -751,6 +734,10 @@
   GetWidget()->widget_delegate()->OnWorkAreaChanged();
 }
 
+void DesktopRootWindowHostWin::HandleVisibilityChanging(bool visible) {
+  native_widget_delegate_->OnNativeWidgetVisibilityChanging(visible);
+}
+
 void DesktopRootWindowHostWin::HandleVisibilityChanged(bool visible) {
   native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
 }
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 9ad6b69..59e54d8 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
@@ -20,7 +20,6 @@
 
 namespace views {
 class DesktopActivationClient;
-class DesktopCaptureClient;
 class DesktopCursorClient;
 class DesktopDispatcherClient;
 class DesktopDragDropClientWin;
@@ -96,7 +95,6 @@
   virtual void FlashFrame(bool flash_frame) OVERRIDE;
   virtual void OnNativeWidgetFocus() OVERRIDE;
   virtual void OnNativeWidgetBlur() OVERRIDE;
-  virtual void SetInactiveRenderingDisabled(bool disable_inactive) OVERRIDE;
 
   // Overridden from aura::RootWindowHost:
   virtual void SetDelegate(aura::RootWindowHostDelegate* delegate) OVERRIDE;
@@ -119,9 +117,6 @@
   virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
   virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) OVERRIDE;
   virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
   virtual void PrepareForShutdown() OVERRIDE;
@@ -175,6 +170,7 @@
   virtual void HandleEndWMSizeMove() OVERRIDE;
   virtual void HandleMove() OVERRIDE;
   virtual void HandleWorkAreaChanged() OVERRIDE;
+  virtual void HandleVisibilityChanging(bool visible) OVERRIDE;
   virtual void HandleVisibilityChanged(bool visible) OVERRIDE;
   virtual void HandleClientSizeChanged(const gfx::Size& new_size) OVERRIDE;
   virtual void HandleFrameChanged() OVERRIDE;
@@ -215,7 +211,6 @@
   aura::RootWindow* root_window_;
 
   scoped_ptr<HWNDMessageHandler> message_handler_;
-  scoped_ptr<DesktopCaptureClient> capture_client_;
   scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
   scoped_ptr<aura::client::FocusClient> focus_client_;
   // Depends on focus_manager_.
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 8c4ba7c..b6a1c13 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
@@ -33,7 +33,6 @@
 #include "ui/views/corewm/focus_controller.h"
 #include "ui/views/ime/input_method.h"
 #include "ui/views/widget/desktop_aura/desktop_activation_client.h"
-#include "ui/views/widget/desktop_aura/desktop_capture_client.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"
@@ -521,8 +520,15 @@
 }
 
 void DesktopRootWindowHostX11::InitModalType(ui::ModalType modal_type) {
-  // TODO(erg):
-  NOTIMPLEMENTED();
+  switch (modal_type) {
+    case ui::MODAL_TYPE_NONE:
+      break;
+    default:
+      // TODO(erg): Figure out under what situations |modal_type| isn't
+      // none. The comment in desktop_native_widget_aura.cc suggests that this
+      // is rare.
+      NOTIMPLEMENTED();
+  }
 }
 
 void DesktopRootWindowHostX11::FlashFrame(bool flash_frame) {
@@ -539,10 +545,6 @@
     native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
 }
 
-void DesktopRootWindowHostX11::SetInactiveRenderingDisabled(
-    bool disable_inactive) {
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopRootWindowHostX11, aura::RootWindowHost implementation:
 
@@ -731,14 +733,6 @@
   }
 }
 
-bool DesktopRootWindowHostX11::CopyAreaToSkCanvas(
-    const gfx::Rect& source_bounds,
-    const gfx::Point& dest_offset,
-    SkCanvas* canvas) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
 void DesktopRootWindowHostX11::PostNativeEvent(
     const base::NativeEvent& native_event) {
   DCHECK(xwindow_);
@@ -903,8 +897,7 @@
 
   native_widget_delegate_->OnNativeWidgetCreated(true);
 
-  capture_client_.reset(new views::DesktopCaptureClient(root_window_));
-  aura::client::SetCaptureClient(root_window_, capture_client_.get());
+  desktop_native_widget_aura_->CreateCaptureClient(root_window_);
 
   // Ensure that the X11DesktopHandler exists so that it dispatches activation
   // messages to us.
@@ -1340,8 +1333,8 @@
     DesktopNativeWidgetAura* desktop_native_widget_aura,
     const gfx::Rect& initial_bounds) {
   return new DesktopRootWindowHostX11(native_widget_delegate,
-                                        desktop_native_widget_aura,
-                                        initial_bounds);
+                                      desktop_native_widget_aura,
+                                      initial_bounds);
 }
 
 // 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 e1dcc76..65a135a 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
@@ -30,7 +30,6 @@
 
 namespace views {
 class DesktopActivationClient;
-class DesktopCaptureClient;
 class DesktopDragDropClientAuraX11;
 class DesktopDispatcherClient;
 class DesktopRootWindowHostObserverX11;
@@ -123,7 +122,6 @@
   virtual void FlashFrame(bool flash_frame) OVERRIDE;
   virtual void OnNativeWidgetFocus() OVERRIDE;
   virtual void OnNativeWidgetBlur() OVERRIDE;
-  virtual void SetInactiveRenderingDisabled(bool disable_inactive) OVERRIDE;
 
   // Overridden from aura::RootWindowHost:
   virtual void SetDelegate(aura::RootWindowHostDelegate* delegate) OVERRIDE;
@@ -146,9 +144,6 @@
   virtual void OnCursorVisibilityChanged(bool show) OVERRIDE;
   virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE;
   virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE;
-  virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
-                                  const gfx::Point& dest_offset,
-                                  SkCanvas* canvas) OVERRIDE;
   virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE;
   virtual void PrepareForShutdown() OVERRIDE;
@@ -228,7 +223,6 @@
   aura::RootWindow* root_window_;
 
   // aura:: objects that we own.
-  scoped_ptr<DesktopCaptureClient> capture_client_;
   scoped_ptr<aura::client::FocusClient> focus_client_;
   scoped_ptr<DesktopActivationClient> activation_client_;
   scoped_ptr<views::corewm::CursorManager> cursor_client_;
diff --git a/ui/views/widget/desktop_aura/desktop_screen_ozone.cc b/ui/views/widget/desktop_aura/desktop_screen_ozone.cc
new file mode 100644
index 0000000..10a012a
--- /dev/null
+++ b/ui/views/widget/desktop_aura/desktop_screen_ozone.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 "ui/views/widget/desktop_aura/desktop_screen.h"
+
+#include "ui/base/ozone/surface_factory_ozone.h"
+
+namespace views {
+
+gfx::Screen* CreateDesktopScreen() {
+  return ui::SurfaceFactoryOzone::GetInstance()->CreateDesktopScreen();
+}
+
+}  // namespace views
diff --git a/ui/views/widget/monitor_win.cc b/ui/views/widget/monitor_win.cc
index c183cb0..1292692 100644
--- a/ui/views/widget/monitor_win.cc
+++ b/ui/views/widget/monitor_win.cc
@@ -7,6 +7,7 @@
 #include <shellapi.h>
 
 #include "base/logging.h"
+#include "base/win/win_util.h"
 #include "ui/gfx/rect.h"
 
 namespace views {
@@ -17,7 +18,7 @@
   if (monitor) {
     MONITORINFO mi = {0};
     mi.cbSize = sizeof(mi);
-    GetMonitorInfo(monitor, &mi);
+    base::win::GetMonitorInfoWrapper(monitor, &mi);
     return gfx::Rect(mi.rcWork);
   }
   NOTREACHED();
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 8c9ad02..5348f24 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -95,6 +95,13 @@
 #endif
 }
 
+// static
+void NativeWidgetAura::RegisterNativeWidgetForWindow(
+      internal::NativeWidgetPrivate* native_widget,
+      aura::Window* window) {
+  window->set_user_data(native_widget);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // NativeWidgetAura, internal::NativeWidgetPrivate implementation:
 
@@ -105,7 +112,7 @@
 
   ownership_ = params.ownership;
 
-  window_->set_user_data(this);
+  RegisterNativeWidgetForWindow(this, window_);
   window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
   window_->SetProperty(aura::client::kShowStateKey, params.show_state);
   if (params.type == Widget::InitParams::TYPE_BUBBLE)
@@ -222,15 +229,15 @@
 }
 
 const ui::Compositor* NativeWidgetAura::GetCompositor() const {
-  return window_->layer()->GetCompositor();
+  return window_ ? window_->layer()->GetCompositor() : NULL;
 }
 
 ui::Compositor* NativeWidgetAura::GetCompositor() {
-  return window_->layer()->GetCompositor();
+  return window_ ? window_->layer()->GetCompositor() : NULL;
 }
 
 ui::Layer* NativeWidgetAura::GetLayer() {
-  return window_->layer();
+  return window_ ? window_->layer() : NULL;
 }
 
 void NativeWidgetAura::ReorderNativeViews() {
@@ -256,18 +263,22 @@
 }
 
 void NativeWidgetAura::SetCapture() {
-  window_->SetCapture();
+  if (window_)
+    window_->SetCapture();
 }
 
 void NativeWidgetAura::ReleaseCapture() {
-  window_->ReleaseCapture();
+  if (window_)
+    window_->ReleaseCapture();
 }
 
 bool NativeWidgetAura::HasCapture() const {
-  return window_->HasCapture();
+  return window_ && window_->HasCapture();
 }
 
 InputMethod* NativeWidgetAura::CreateInputMethod() {
+  if (!window_)
+    return NULL;
   aura::RootWindow* root_window = window_->GetRootWindow();
   ui::InputMethod* host =
       root_window->GetProperty(aura::client::kRootWindowInputMethodKey);
@@ -279,6 +290,9 @@
 }
 
 void NativeWidgetAura::CenterWindow(const gfx::Size& size) {
+  if (!window_)
+    return;
+
   gfx::Rect parent_bounds(window_->parent()->GetBoundsInRootWindow());
   // When centering window, we take the intersection of the host and
   // the parent. We assume the root window represents the visible
@@ -330,11 +344,13 @@
     ui::WindowShowState* show_state) const {
   // The interface specifies returning restored bounds, not current bounds.
   *bounds = GetRestoredBounds();
-  *show_state = window_->GetProperty(aura::client::kShowStateKey);
+  *show_state = window_ ? window_->GetProperty(aura::client::kShowStateKey) :
+      ui::SHOW_STATE_DEFAULT;
 }
 
 void NativeWidgetAura::SetWindowTitle(const string16& title) {
-  window_->set_title(title);
+  if (window_)
+    window_->set_title(title);
 }
 
 void NativeWidgetAura::SetWindowIcons(const gfx::ImageSkia& window_icon,
@@ -348,16 +364,19 @@
 }
 
 gfx::Rect NativeWidgetAura::GetWindowBoundsInScreen() const {
-  return window_->GetBoundsInScreen();
+  return window_ ? window_->GetBoundsInScreen() : gfx::Rect();
 }
 
 gfx::Rect NativeWidgetAura::GetClientAreaBoundsInScreen() const {
   // View-to-screen coordinate system transformations depend on this returning
   // the full window bounds, for example View::ConvertPointToScreen().
-  return window_->GetBoundsInScreen();
+  return window_ ? window_->GetBoundsInScreen() : gfx::Rect();
 }
 
 gfx::Rect NativeWidgetAura::GetRestoredBounds() const {
+  if (!window_)
+    return gfx::Rect();
+
   // Restored bounds should only be relevant if the window is minimized or
   // maximized. However, in some places the code expects GetRestoredBounds()
   // to return the current window bounds if the window is not in either state.
@@ -372,6 +391,9 @@
 }
 
 void NativeWidgetAura::SetBounds(const gfx::Rect& bounds) {
+  if (!window_)
+    return;
+
   aura::RootWindow* root = window_->GetRootWindow();
   if (root) {
     aura::client::ScreenPositionClient* screen_position_client =
@@ -387,20 +409,24 @@
 }
 
 void NativeWidgetAura::SetSize(const gfx::Size& size) {
-  window_->SetBounds(gfx::Rect(window_->bounds().origin(), size));
+  if (window_)
+    window_->SetBounds(gfx::Rect(window_->bounds().origin(), size));
 }
 
 void NativeWidgetAura::StackAbove(gfx::NativeView native_view) {
-  if (window_->parent() && window_->parent() == native_view->parent())
+  if (window_ && window_->parent() &&
+      window_->parent() == native_view->parent())
     window_->parent()->StackChildAbove(window_, native_view);
 }
 
 void NativeWidgetAura::StackAtTop() {
-  window_->parent()->StackChildAtTop(window_);
+  if (window_)
+    window_->parent()->StackChildAtTop(window_);
 }
 
 void NativeWidgetAura::StackBelow(gfx::NativeView native_view) {
-  if (window_->parent() && window_->parent() == native_view->parent())
+  if (window_ && window_->parent() &&
+      window_->parent() == native_view->parent())
     window_->parent()->StackChildBelow(window_, native_view);
 }
 
@@ -438,7 +464,8 @@
 }
 
 void NativeWidgetAura::Hide() {
-  window_->Hide();
+  if (window_)
+    window_->Hide();
 }
 
 void NativeWidgetAura::ShowMaximizedWithBounds(
@@ -448,6 +475,9 @@
 }
 
 void NativeWidgetAura::ShowWithWindowState(ui::WindowShowState state) {
+  if (!window_)
+    return;
+
   if (state == ui::SHOW_STATE_MAXIMIZED || state == ui::SHOW_STATE_FULLSCREEN)
     window_->SetProperty(aura::client::kShowStateKey, state);
   window_->Show();
@@ -466,10 +496,13 @@
 }
 
 bool NativeWidgetAura::IsVisible() const {
-  return window_->IsVisible();
+  return window_ && window_->IsVisible();
 }
 
 void NativeWidgetAura::Activate() {
+  if (!window_)
+    return;
+
   // We don't necessarily have a root window yet. This can happen with
   // constrained windows.
   if (window_->GetRootWindow()) {
@@ -481,43 +514,50 @@
 }
 
 void NativeWidgetAura::Deactivate() {
+  if (!window_)
+    return;
   aura::client::GetActivationClient(window_->GetRootWindow())->DeactivateWindow(
       window_);
 }
 
 bool NativeWidgetAura::IsActive() const {
-  return aura::client::GetActivationClient(window_->GetRootWindow())->
-      GetActiveWindow() == window_;
+  return window_ &&
+      aura::client::GetActivationClient(window_->GetRootWindow())->
+          GetActiveWindow() == window_;
 }
 
 void NativeWidgetAura::SetAlwaysOnTop(bool on_top) {
-  window_->SetProperty(aura::client::kAlwaysOnTopKey, on_top);
+  if (window_)
+    window_->SetProperty(aura::client::kAlwaysOnTopKey, on_top);
 }
 
 void NativeWidgetAura::Maximize() {
-  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
+  if (window_)
+    window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED);
 }
 
 void NativeWidgetAura::Minimize() {
-  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
+  if (window_)
+    window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED);
 }
 
 bool NativeWidgetAura::IsMaximized() const {
-  return window_->GetProperty(aura::client::kShowStateKey) ==
+  return window_ && window_->GetProperty(aura::client::kShowStateKey) ==
       ui::SHOW_STATE_MAXIMIZED;
 }
 
 bool NativeWidgetAura::IsMinimized() const {
-  return window_->GetProperty(aura::client::kShowStateKey) ==
+  return window_ && window_->GetProperty(aura::client::kShowStateKey) ==
       ui::SHOW_STATE_MINIMIZED;
 }
 
 void NativeWidgetAura::Restore() {
-  window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
+  if (window_)
+    window_->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
 }
 
 void NativeWidgetAura::SetFullscreen(bool fullscreen) {
-  if (IsFullscreen() == fullscreen)
+  if (!window_ || IsFullscreen() == fullscreen)
     return;  // Nothing to do.
 
   // Save window state before entering full screen so that it could restored
@@ -531,12 +571,13 @@
 }
 
 bool NativeWidgetAura::IsFullscreen() const {
-  return window_->GetProperty(aura::client::kShowStateKey) ==
+  return window_ && window_->GetProperty(aura::client::kShowStateKey) ==
       ui::SHOW_STATE_FULLSCREEN;
 }
 
 void NativeWidgetAura::SetOpacity(unsigned char opacity) {
-  window_->layer()->SetOpacity(opacity / 255.0);
+  if (window_)
+    window_->layer()->SetOpacity(opacity / 255.0);
 }
 
 void NativeWidgetAura::SetUseDragFrame(bool use_drag_frame) {
@@ -544,7 +585,8 @@
 }
 
 void NativeWidgetAura::FlashFrame(bool flash) {
-  window_->SetProperty(aura::client::kDrawAttentionKey, flash);
+  if (window_)
+    window_->SetProperty(aura::client::kDrawAttentionKey, flash);
 }
 
 void NativeWidgetAura::RunShellDrag(View* view,
@@ -552,7 +594,8 @@
                                     const gfx::Point& location,
                                     int operation,
                                     ui::DragDropTypes::DragEventSource source) {
-  views::RunShellDrag(window_, data, location, operation, source);
+  if (window_)
+    views::RunShellDrag(window_, data, location, operation, source);
 }
 
 void NativeWidgetAura::SchedulePaintInRect(const gfx::Rect& rect) {
@@ -569,6 +612,8 @@
 }
 
 bool NativeWidgetAura::IsMouseEventsEnabled() const {
+  if (!window_)
+    return false;
   aura::client::CursorClient* cursor_client =
       aura::client::GetCursorClient(window_->GetRootWindow());
   return cursor_client ? cursor_client->IsMouseEventsEnabled() : true;
@@ -581,11 +626,16 @@
 }
 
 gfx::Rect NativeWidgetAura::GetWorkAreaBoundsInScreen() const {
-  return gfx::Screen::GetScreenFor(GetNativeView())->
-      GetDisplayNearestWindow(GetNativeView()).work_area();
+  if (!window_)
+    return gfx::Rect();
+  return gfx::Screen::GetScreenFor(window_)->
+      GetDisplayNearestWindow(window_).work_area();
 }
 
 void NativeWidgetAura::SetInactiveRenderingDisabled(bool value) {
+  if (!window_)
+    return;
+
   if (!value) {
     active_window_observer_.reset();
   } else {
@@ -597,7 +647,7 @@
 Widget::MoveLoopResult NativeWidgetAura::RunMoveLoop(
     const gfx::Vector2d& drag_offset,
     Widget::MoveLoopSource source) {
-  if (window_->parent() &&
+  if (window_ && window_->parent() &&
       aura::client::GetWindowMoveClient(window_->parent())) {
     SetCapture();
     aura::client::WindowMoveSource window_move_source =
@@ -614,14 +664,15 @@
 }
 
 void NativeWidgetAura::EndMoveLoop() {
-  if (window_->parent() &&
+  if (window_ && window_->parent() &&
       aura::client::GetWindowMoveClient(window_->parent())) {
     aura::client::GetWindowMoveClient(window_->parent())->EndMoveLoop();
   }
 }
 
 void NativeWidgetAura::SetVisibilityChangedAnimationsEnabled(bool value) {
-  window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
+  if (window_)
+    window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
 }
 
 ui::NativeTheme* NativeWidgetAura::GetNativeTheme() const {
@@ -759,6 +810,7 @@
 // NativeWidgetAura, ui::EventHandler implementation:
 
 void NativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) {
+  DCHECK(window_);
   if (event->is_char()) {
     // If a ui::InputMethod object is attached to the root window, character
     // events are handled inside the object and are not passed to this function.
@@ -775,6 +827,7 @@
 }
 
 void NativeWidgetAura::OnMouseEvent(ui::MouseEvent* event) {
+  DCHECK(window_);
   DCHECK(window_->IsVisible());
   if (event->type() == ui::ET_MOUSEWHEEL) {
     delegate_->OnMouseEvent(event);
@@ -792,11 +845,13 @@
 }
 
 void NativeWidgetAura::OnTouchEvent(ui::TouchEvent* event) {
+  DCHECK(window_);
   DCHECK(window_->IsVisible());
   delegate_->OnTouchEvent(event);
 }
 
 void NativeWidgetAura::OnGestureEvent(ui::GestureEvent* event) {
+  DCHECK(window_);
   DCHECK(window_->IsVisible());
   delegate_->OnGestureEvent(event);
 }
@@ -975,12 +1030,14 @@
 // static
 NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
     gfx::NativeView native_view) {
+  // Cast must match type supplied to RegisterNativeWidgetForWindow().
   return reinterpret_cast<NativeWidgetPrivate*>(native_view->user_data());
 }
 
 // static
 NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
     gfx::NativeWindow native_window) {
+  // Cast must match type supplied to RegisterNativeWidgetForWindow().
   return reinterpret_cast<NativeWidgetPrivate*>(native_window->user_data());
 }
 
@@ -1012,10 +1069,7 @@
   const aura::Window::Windows& child_windows = native_view->children();
   for (aura::Window::Windows::const_iterator i = child_windows.begin();
        i != child_windows.end(); ++i) {
-    NativeWidgetAura* native_widget =
-        static_cast<NativeWidgetAura*>(GetNativeWidgetForNativeView(*i));
-    if (native_widget)
-      children->insert(native_widget->GetWidget());
+    GetAllChildWidgets((*i), children);
   }
 }
 
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h
index 57271e8..b14da5c 100644
--- a/ui/views/widget/native_widget_aura.h
+++ b/ui/views/widget/native_widget_aura.h
@@ -46,6 +46,12 @@
   //             NativeWidgetWin.
   static gfx::Font GetWindowTitleFont();
 
+  // Called internally by NativeWidgetAura and DesktopNativeWidgetAura to
+  // associate |native_widget| with |window|.
+  static void RegisterNativeWidgetForWindow(
+      internal::NativeWidgetPrivate* native_widget,
+      aura::Window* window);
+
   // Overridden from internal::NativeWidgetPrivate:
   virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE;
   virtual NonClientFrameView* CreateNonClientFrameView() OVERRIDE;
@@ -189,6 +195,9 @@
 
   internal::NativeWidgetDelegate* delegate_;
 
+  // WARNING: set to NULL when destroyed. As the Widget is not necessarily
+  // destroyed along with |window_| all usage of |window_| should first verify
+  // non-NULL.
   aura::Window* window_;
 
   // See class documentation for Widget in widget.h for a note about ownership.
diff --git a/ui/views/widget/native_widget_delegate.h b/ui/views/widget/native_widget_delegate.h
index c1fd073..bc0d974 100644
--- a/ui/views/widget/native_widget_delegate.h
+++ b/ui/views/widget/native_widget_delegate.h
@@ -61,6 +61,9 @@
   virtual void OnNativeFocus(gfx::NativeView focused_view) = 0;
   virtual void OnNativeBlur(gfx::NativeView focused_view) = 0;
 
+  // Called when the window is about to be shown/hidden.
+  virtual void OnNativeWidgetVisibilityChanging(bool visible) = 0;
+
   // Called when the window is shown/hidden.
   virtual void OnNativeWidgetVisibilityChanged(bool visible) = 0;
 
diff --git a/ui/views/widget/native_widget_win.cc b/ui/views/widget/native_widget_win.cc
index d6ebdd6..c0b84b6 100644
--- a/ui/views/widget/native_widget_win.cc
+++ b/ui/views/widget/native_widget_win.cc
@@ -717,6 +717,10 @@
   GetWidget()->widget_delegate()->OnWorkAreaChanged();
 }
 
+void NativeWidgetWin::HandleVisibilityChanging(bool visible) {
+  delegate_->OnNativeWidgetVisibilityChanging(visible);
+}
+
 void NativeWidgetWin::HandleVisibilityChanged(bool visible) {
   delegate_->OnNativeWidgetVisibilityChanged(visible);
 }
diff --git a/ui/views/widget/native_widget_win.h b/ui/views/widget/native_widget_win.h
index 81fa718..544e18b 100644
--- a/ui/views/widget/native_widget_win.h
+++ b/ui/views/widget/native_widget_win.h
@@ -202,6 +202,7 @@
   virtual void HandleEndWMSizeMove() OVERRIDE;
   virtual void HandleMove() OVERRIDE;
   virtual void HandleWorkAreaChanged() OVERRIDE;
+  virtual void HandleVisibilityChanging(bool visible) OVERRIDE;
   virtual void HandleVisibilityChanged(bool visible) OVERRIDE;
   virtual void HandleClientSizeChanged(const gfx::Size& new_size) OVERRIDE;
   virtual void HandleFrameChanged() OVERRIDE;
diff --git a/ui/views/widget/tooltip_manager.cc b/ui/views/widget/tooltip_manager.cc
index bfcbf02..f600a12 100644
--- a/ui/views/widget/tooltip_manager.cc
+++ b/ui/views/widget/tooltip_manager.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/text/text_elider.h"
+#include "ui/gfx/font.h"
 
 namespace {
 
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index e97c950..0de8ccf 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -29,6 +29,7 @@
 #include "ui/views/widget/widget_deletion_observer.h"
 #include "ui/views/widget/widget_observer.h"
 #include "ui/views/window/custom_frame_view.h"
+#include "ui/views/window/dialog_delegate.h"
 
 #if !defined(OS_MACOSX)
 #include "ui/views/controls/menu/menu_controller.h"
@@ -243,6 +244,30 @@
 }
 
 // static
+Widget* Widget::CreateWindowAsFramelessChild(WidgetDelegate* widget_delegate,
+                                             gfx::NativeView parent,
+                                             gfx::NativeView new_style_parent) {
+  views::Widget* widget = new views::Widget;
+
+  views::Widget::InitParams params;
+  params.delegate = widget_delegate;
+  params.child = true;
+  if (views::DialogDelegate::UseNewStyle()) {
+    params.parent = new_style_parent;
+    params.remove_standard_frame = true;
+#if defined(USE_AURA)
+    params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+#endif
+  } else {
+    params.parent = parent;
+  }
+
+  widget->Init(params);
+
+  return widget;
+}
+
+// static
 Widget* Widget::GetWidgetForNativeView(gfx::NativeView native_view) {
   internal::NativeWidgetPrivate* native_widget =
       internal::NativeWidgetPrivate::GetNativeWidgetForNativeView(native_view);
@@ -923,10 +948,6 @@
   return !!v;
 }
 
-View* Widget::GetChildViewParent() {
-  return GetContentsView() ? GetContentsView() : GetRootView();
-}
-
 gfx::Rect Widget::GetWorkAreaBoundsInScreen() const {
   return native_widget_->GetWorkAreaBoundsInScreen();
 }
@@ -987,6 +1008,11 @@
                                                         new_focused_view);
 }
 
+void Widget::OnNativeWidgetVisibilityChanging(bool visible) {
+  FOR_EACH_OBSERVER(WidgetObserver, observers_,
+                    OnWidgetVisibilityChanging(this, visible));
+}
+
 void Widget::OnNativeWidgetVisibilityChanged(bool visible) {
   View* root = GetRootView();
   if (root)
diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h
index f020a0c..ed64f3b 100644
--- a/ui/views/widget/widget.h
+++ b/ui/views/widget/widget.h
@@ -156,7 +156,6 @@
     InitParams();
     explicit InitParams(Type type);
 
-
     // Will return the first of the following that isn't NULL: the native view,
     // |parent|, |context|.
     gfx::NativeView GetContext() const;
@@ -248,6 +247,14 @@
                                                   gfx::NativeView context,
                                                   const gfx::Rect& bounds);
 
+  // Creates an undecorated child window Widget. |new_style_parent| is the
+  // parent to use for new style dialogs, |parent| for currently-styled dialogs.
+  //
+  // TODO(wittman): use a single parent parameter once we move fully to
+  // new-style dialogs.
+  static Widget* CreateWindowAsFramelessChild(WidgetDelegate* widget_delegate,
+                                              gfx::NativeView parent,
+                                              gfx::NativeView new_style_parent);
 
   // Enumerates all windows pertaining to us and notifies their
   // view hierarchies that the locale has changed.
@@ -637,11 +644,6 @@
     focus_on_creation_ = focus_on_creation;
   }
 
-  // Returns a View* that any child Widgets backed by NativeWidgetViews
-  // are added to.  The default implementation returns the contents view
-  // if it exists and the root view otherwise.
-  virtual View* GetChildViewParent();
-
   // True if the widget is considered top level widget. Top level widget
   // is a widget of TYPE_WINDOW, TYPE_PANEL, TYPE_WINDOW_FRAMELESS, BUBBLE,
   // POPUP or MENU, and has a focus manager and input method object associated
@@ -674,6 +676,7 @@
   virtual void OnNativeWidgetActivationChanged(bool active) OVERRIDE;
   virtual void OnNativeFocus(gfx::NativeView old_focused_view) OVERRIDE;
   virtual void OnNativeBlur(gfx::NativeView new_focused_view) OVERRIDE;
+  virtual void OnNativeWidgetVisibilityChanging(bool visible) OVERRIDE;
   virtual void OnNativeWidgetVisibilityChanged(bool visible) OVERRIDE;
   virtual void OnNativeWidgetCreated(bool desktop_widget) OVERRIDE;
   virtual void OnNativeWidgetDestroying() OVERRIDE;
diff --git a/ui/views/widget/widget_observer.h b/ui/views/widget/widget_observer.h
index e156ef8..fc13afa 100644
--- a/ui/views/widget/widget_observer.h
+++ b/ui/views/widget/widget_observer.h
@@ -36,6 +36,8 @@
   // widget has been destroyed.
   virtual void OnWidgetDestroyed(Widget* widget) {}
 
+  virtual void OnWidgetVisibilityChanging(Widget* widget, bool visible) {}
+
   virtual void OnWidgetVisibilityChanged(Widget* widget, bool visible) {}
 
   virtual void OnWidgetActivationChanged(Widget* widget, bool active) {}
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index 1153538..e00f93d 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <algorithm>
+#include <set>
+
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
@@ -941,6 +944,99 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// Test to verify using various Widget methods doesn't crash when the underlying
+// NativeView is destroyed.
+//
+class WidgetWithDestroyedNativeViewTest : public ViewsTestBase {
+ public:
+  WidgetWithDestroyedNativeViewTest() {}
+  virtual ~WidgetWithDestroyedNativeViewTest() {}
+
+  void InvokeWidgetMethods(Widget* widget) {
+    widget->GetNativeView();
+    widget->GetNativeWindow();
+    ui::Accelerator accelerator;
+    widget->GetAccelerator(0, &accelerator);
+    widget->GetTopLevelWidget();
+    widget->GetWindowBoundsInScreen();
+    widget->GetClientAreaBoundsInScreen();
+    widget->SetBounds(gfx::Rect(0, 0, 100, 80));
+    widget->SetSize(gfx::Size(10, 11));
+    widget->SetBoundsConstrained(gfx::Rect(0, 0, 120, 140));
+    widget->SetVisibilityChangedAnimationsEnabled(false);
+    widget->StackAtTop();
+    widget->IsClosed();
+    widget->Close();
+    widget->Show();
+    widget->Hide();
+    widget->Activate();
+    widget->Deactivate();
+    widget->IsActive();
+    widget->DisableInactiveRendering();
+    widget->SetAlwaysOnTop(true);
+    widget->Maximize();
+    widget->Minimize();
+    widget->Restore();
+    widget->IsMaximized();
+    widget->IsFullscreen();
+    widget->SetOpacity(0);
+    widget->SetUseDragFrame(true);
+    widget->FlashFrame(true);
+    widget->IsVisible();
+    widget->GetThemeProvider();
+    widget->GetNativeTheme();
+    widget->GetFocusManager();
+    widget->GetInputMethod();
+    widget->SchedulePaintInRect(gfx::Rect(0, 0, 1, 2));
+    widget->IsMouseEventsEnabled();
+    widget->SetNativeWindowProperty("xx", widget);
+    widget->GetNativeWindowProperty("xx");
+    widget->GetFocusTraversable();
+    widget->GetLayer();
+    widget->ReorderNativeViews();
+    widget->SetCapture(widget->GetRootView());
+    widget->ReleaseCapture();
+    widget->HasCapture();
+    widget->TooltipTextChanged(widget->GetRootView());
+    widget->GetWorkAreaBoundsInScreen();
+    // These three crash with NativeWidgetWin, so I'm assuming we don't need
+    // them to work for the other NativeWidget impls.
+    // widget->CenterWindow(gfx::Size(50, 60));
+    // widget->GetRestoredBounds();
+    // widget->ShowInactive();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WidgetWithDestroyedNativeViewTest);
+};
+
+TEST_F(WidgetWithDestroyedNativeViewTest, Test) {
+  {
+    Widget widget;
+    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    widget.Init(params);
+    widget.Show();
+
+    widget.native_widget_private()->CloseNow();
+    InvokeWidgetMethods(&widget);
+  }
+#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+  {
+    Widget widget;
+    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+    params.native_widget = new DesktopNativeWidgetAura(&widget);
+    params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    widget.Init(params);
+    widget.Show();
+
+    widget.native_widget_private()->CloseNow();
+    InvokeWidgetMethods(&widget);
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // Widget observer tests.
 //
 
@@ -1181,7 +1277,15 @@
 // Checks that if a mouse-press triggers a capture on a different widget (which
 // consumes the mouse-release event), then the target of the press does not have
 // capture.
-TEST_F(WidgetTest, CaptureWidgetFromMousePress) {
+// Fails on chromium.webkit Windows bot, see crbug.com/264872.
+#if defined(OS_WIN)
+#define MAYBE_DisableCaptureWidgetFromMousePress\
+    DISABLED_CaptureWidgetFromMousePress
+#else
+#define MAYBE_DisableCaptureWidgetFromMousePress\
+    CaptureWidgetFromMousePress
+#endif
+TEST_F(WidgetTest, MAYBE_DisableCaptureWidgetFromMousePress) {
   // The test creates two widgets: |first| and |second|.
   // The View in |first| makes |second| visible, sets capture on it, and starts
   // a nested loop (like a menu does). The View in |second| terminates the
@@ -2063,7 +2167,15 @@
 };
 
 // Checks if RootView::*_handler_ fields are unset when widget is hidden.
-TEST_F(WidgetTest, TestRootViewHandlersWhenHidden) {
+// Fails on chromium.webkit Windows bot, see crbug.com/264872.
+#if defined(OS_WIN)
+#define MAYBE_DisableTestRootViewHandlersWhenHidden\
+    DISABLED_TestRootViewHandlersWhenHidden
+#else
+#define MAYBE_DisableTestRootViewHandlersWhenHidden\
+    TestRootViewHandlersWhenHidden
+#endif
+TEST_F(WidgetTest, MAYBE_DisableTestRootViewHandlersWhenHidden) {
   Widget* widget = CreateTopLevelNativeWidget();
   widget->SetBounds(gfx::Rect(0, 0, 300, 300));
   View* view = new RootViewTestView();
@@ -2112,5 +2224,37 @@
   widget->Close();
 }
 
+// Test the result of Widget::GetAllChildWidgets().
+TEST_F(WidgetTest, GetAllChildWidgets) {
+  // Create the following widget hierarchy:
+  //
+  // toplevel
+  // +-- w1
+  //     +-- w11
+  // +-- w2
+  //     +-- w21
+  //     +-- w22
+  Widget* toplevel = CreateTopLevelPlatformWidget();
+  Widget* w1 = CreateChildPlatformWidget(toplevel->GetNativeView());
+  Widget* w11 = CreateChildPlatformWidget(w1->GetNativeView());
+  Widget* w2 = CreateChildPlatformWidget(toplevel->GetNativeView());
+  Widget* w21 = CreateChildPlatformWidget(w2->GetNativeView());
+  Widget* w22 = CreateChildPlatformWidget(w2->GetNativeView());
+
+  std::set<Widget*> expected;
+  expected.insert(toplevel);
+  expected.insert(w1);
+  expected.insert(w11);
+  expected.insert(w2);
+  expected.insert(w21);
+  expected.insert(w22);
+
+  std::set<Widget*> widgets;
+  Widget::GetAllChildWidgets(toplevel->GetNativeView(), &widgets);
+
+  EXPECT_EQ(expected.size(), widgets.size());
+  EXPECT_TRUE(std::equal(expected.begin(), expected.end(), widgets.begin()));
+}
+
 }  // namespace test
 }  // namespace views
diff --git a/ui/views/win/fullscreen_handler.cc b/ui/views/win/fullscreen_handler.cc
index 33a0475..2fe8cea 100644
--- a/ui/views/win/fullscreen_handler.cc
+++ b/ui/views/win/fullscreen_handler.cc
@@ -5,6 +5,7 @@
 #include "ui/views/win/fullscreen_handler.h"
 
 #include "base/logging.h"
+#include "base/win/win_util.h"
 #include "ui/gfx/rect.h"
 #include "ui/views/win/scoped_fullscreen_visibility.h"
 
@@ -75,8 +76,8 @@
     if (!for_metro) {
       MONITORINFO monitor_info;
       monitor_info.cbSize = sizeof(monitor_info);
-      GetMonitorInfo(MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST),
-                     &monitor_info);
+      base::win::GetMonitorInfoWrapper(
+          MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONEAREST), &monitor_info);
       gfx::Rect window_rect(monitor_info.rcMonitor);
       SetWindowPos(hwnd_, NULL, window_rect.x(), window_rect.y(),
                    window_rect.width(), window_rect.height(),
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 1a62709..d17c841 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/debug/trace_event.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "ui/base/events/event.h"
 #include "ui/base/events/event_utils.h"
@@ -180,7 +181,7 @@
     return false;
   MONITORINFO monitor_info = { 0 };
   monitor_info.cbSize = sizeof(monitor_info);
-  GetMonitorInfo(*monitor, &monitor_info);
+  base::win::GetMonitorInfoWrapper(*monitor, &monitor_info);
   *monitor_rect = gfx::Rect(monitor_info.rcMonitor);
   *work_area = gfx::Rect(monitor_info.rcWork);
   return true;
@@ -392,7 +393,8 @@
       paint_layered_window_factory_(this),
       can_update_layered_window_(true),
       is_first_nccalc_(true),
-      autohide_factory_(this) {
+      autohide_factory_(this),
+      touch_event_factory_(this) {
 }
 
 HWNDMessageHandler::~HWNDMessageHandler() {
@@ -503,7 +505,7 @@
     } else {
       MONITORINFO mi;
       mi.cbSize = sizeof(mi);
-      const bool succeeded = GetMonitorInfo(
+      const bool succeeded = base::win::GetMonitorInfoWrapper(
           MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST), &mi) != 0;
       DCHECK(succeeded);
 
@@ -1120,7 +1122,7 @@
     HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST);
     MONITORINFO mi;
     mi.cbSize = sizeof mi;
-    GetMonitorInfo(monitor, &mi);
+    base::win::GetMonitorInfoWrapper(monitor, &mi);
     CRect work_rect = mi.rcWork;
     work_rect.OffsetRect(-window_rect.left, -window_rect.top);
     new_region = CreateRectRgnIndirect(&work_rect);
@@ -1591,6 +1593,8 @@
   // cleared before it is converted to BOOL.
   BOOL active = static_cast<BOOL>(LOWORD(w_param));
 
+  bool inactive_rendering_disabled = delegate_->IsInactiveRenderingDisabled();
+
   if (delegate_->CanActivate())
     delegate_->HandleActivationChanged(!!active);
 
@@ -1603,7 +1607,6 @@
     return TRUE;
 
   // On activation, lift any prior restriction against rendering as inactive.
-  bool inactive_rendering_disabled = delegate_->IsInactiveRenderingDisabled();
   if (active && inactive_rendering_disabled)
     delegate_->EnableInactiveRendering();
 
@@ -2039,11 +2042,17 @@
 LRESULT HWNDMessageHandler::OnTouchEvent(UINT message,
                                          WPARAM w_param,
                                          LPARAM l_param) {
+  // Handle touch events only on Aura for now.
+#if !defined(USE_AURA)
+  SetMsgHandled(FALSE);
+  return 0;
+#endif
   int num_points = LOWORD(w_param);
   scoped_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]);
   if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param),
                                    num_points, input.get(),
                                    sizeof(TOUCHINPUT))) {
+    TouchEvents touch_events;
     for (int i = 0; i < num_points; ++i) {
       ui::EventType touch_event_type = ui::ET_UNKNOWN;
 
@@ -2056,8 +2065,6 @@
       } else if (input[i].dwFlags & TOUCHEVENTF_MOVE) {
         touch_event_type = ui::ET_TOUCH_MOVED;
       }
-      // Handle touch events only on Aura for now.
-#if defined(USE_AURA)
       if (touch_event_type != ui::ET_UNKNOWN) {
         POINT point;
         point.x = TOUCH_COORD_TO_PIXEL(input[i].x) /
@@ -2072,10 +2079,16 @@
             gfx::Point(point.x, point.y),
             input[i].dwID % ui::GestureSequence::kMaxGesturePoints,
             base::TimeDelta::FromMilliseconds(input[i].dwTime));
-        delegate_->HandleTouchEvent(event);
+        touch_events.push_back(event);
       }
-#endif
     }
+    // Handle the touch events asynchronously. We need this because touch
+    // events on windows don't fire if we enter a modal loop in the context of
+    // a touch event.
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&HWNDMessageHandler::HandleTouchEvents,
+            touch_event_factory_.GetWeakPtr(), touch_events));
   }
   CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(l_param));
   SetMsgHandled(FALSE);
@@ -2155,6 +2168,11 @@
     window_pos->flags &= ~SWP_SHOWWINDOW;
   }
 
+  if (window_pos->flags & SWP_SHOWWINDOW)
+    delegate_->HandleVisibilityChanging(true);
+  else if (window_pos->flags & SWP_HIDEWINDOW)
+    delegate_->HandleVisibilityChanging(false);
+
   SetMsgHandled(FALSE);
 }
 
@@ -2174,4 +2192,11 @@
   SetMsgHandled(FALSE);
 }
 
+void HWNDMessageHandler::HandleTouchEvents(const TouchEvents& touch_events) {
+  if (!delegate_)
+    return;
+  for (size_t i = 0; i < touch_events.size(); ++i)
+    delegate_->HandleTouchEvent(touch_events[i]);
+}
+
 }  // namespace views
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index c1c724c..8ae4619 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -11,6 +11,7 @@
 #include <windows.h>
 
 #include <set>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
@@ -20,6 +21,7 @@
 #include "base/strings/string16.h"
 #include "base/win/win_util.h"
 #include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/events/event.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/base/win/window_impl.h"
 #include "ui/gfx/rect.h"
@@ -364,6 +366,12 @@
   void OnWindowPosChanging(WINDOWPOS* window_pos);
   void OnWindowPosChanged(WINDOWPOS* window_pos);
 
+  typedef std::vector<ui::TouchEvent> TouchEvents;
+  // Helper to handle the list of touch events passed in. We need this because
+  // touch events on windows don't fire if we enter a modal loop in the context
+  // of a touch event.
+  void HandleTouchEvents(const TouchEvents& touch_events);
+
   HWNDMessageHandlerDelegate* delegate_;
 
   scoped_ptr<FullscreenHandler> fullscreen_handler_;
@@ -470,6 +478,9 @@
   // A factory used to lookup appbar autohide edges.
   base::WeakPtrFactory<HWNDMessageHandler> autohide_factory_;
 
+  // A factory that allows us to process touch events asynchronously.
+  base::WeakPtrFactory<HWNDMessageHandler> touch_event_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(HWNDMessageHandler);
 };
 
diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h
index 5831850..b3bbadb 100644
--- a/ui/views/win/hwnd_message_handler_delegate.h
+++ b/ui/views/win/hwnd_message_handler_delegate.h
@@ -153,6 +153,10 @@
   // Called when the system's work area has changed.
   virtual void HandleWorkAreaChanged() = 0;
 
+  // Called when the window's visibility is changing. |visible| holds the new
+  // state.
+  virtual void HandleVisibilityChanging(bool visible) = 0;
+
   // Called when the window's visibility changed. |visible| holds the new state.
   virtual void HandleVisibilityChanged(bool visible) = 0;
 
diff --git a/ui/views/window/dialog_delegate.cc b/ui/views/window/dialog_delegate.cc
index 9291fc7..84a6ee4 100644
--- a/ui/views/window/dialog_delegate.cc
+++ b/ui/views/window/dialog_delegate.cc
@@ -52,12 +52,6 @@
   params.parent = parent;
   params.top_level = true;
   widget->Init(params);
-  if (use_new_style) {
-#if defined(USE_AURA)
-    // TODO(msw): Add a matching shadow type and remove the bubble frame border?
-    corewm::SetShadowType(widget->GetNativeWindow(), corewm::SHADOW_TYPE_NONE);
-#endif
-  }
   return widget;
 }
 
@@ -199,6 +193,10 @@
   }
   if (force_opaque_border)
     widget->set_frame_type(views::Widget::FRAME_TYPE_FORCE_CUSTOM);
+#if defined(USE_AURA)
+  // TODO(msw): Add a matching shadow type and remove the bubble frame border?
+  corewm::SetShadowType(widget->GetNativeWindow(), corewm::SHADOW_TYPE_NONE);
+#endif
   return frame;
 }
 
diff --git a/ui/webui/resources/css/apps/common.css b/ui/webui/resources/css/apps/common.css
new file mode 100644
index 0000000..31b510d
--- /dev/null
+++ b/ui/webui/resources/css/apps/common.css
@@ -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. */
+
+button.white-button,
+button.blue-button {
+  border: 5px solid transparent;
+  box-sizing: content-box;
+  cursor: default;
+  height: 21px;
+  line-height: 21px;
+  margin: 0;
+  min-height: 21px;
+  min-width: 55px;
+  padding: 0 10px;
+  position: relative;
+  outline: none;
+  text-align: center;
+  z-index: 1;
+}
+
+button.white-button {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/button.png') 1x,
+    url('chrome://resources/images/2x/apps/button.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+button.white-button:hover {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/button_hover.png') 1x,
+    url('chrome://resources/images/2x/apps/button_hover.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+button.white-button:active {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/button_pressed.png') 1x,
+    url('chrome://resources/images/2x/apps/button_pressed.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+button.white-button[disabled] {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/button_inactive.png') 1x,
+    url('chrome://resources/images/2x/apps/button_inactive.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+button.blue-button {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/blue_button.png') 1x,
+    url('chrome://resources/images/2x/apps/_bluebutton.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+button.blue-button:hover {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/blue_button_hover.png') 1x,
+    url('chrome://resources/images/2x/apps/blue_button_hover.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+button.blue-button:active {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/blue_button_pressed.png') 1x,
+    url('chrome://resources/images/2x/apps/blue_button_pressed.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+button.blue-button[disabled] {
+  border-image: -webkit-image-set(
+    url('chrome://resources/images/apps/blue_button_inactive.png') 1x,
+    url('chrome://resources/images/2x/apps/blue_button_inactive.png')
+        2x) 5 fill / 5px / 2px repeat;
+}
+
+input[type='checkbox'] {
+  -webkit-appearance: none;
+  border: none;
+  outline: none;
+}
+
+input[type='checkbox']::after {
+  content: '';
+  display: block;
+  height: 16px;
+  left: -2px;
+  top: -2px;
+  width: 16px;
+}
+
+input[type='checkbox']:not(:checked)::after {
+  background-image: -webkit-image-set(
+    url('chrome://resources/images/apps/checkbox.png') 1x,
+    url('chrome://resources/images/2x/apps/checkbox.png') 2x);
+}
+
+input[type='checkbox']:checked::after {
+  background-image: -webkit-image-set(
+    url('chrome://resources/images/apps/checkbox_checked.png') 1x,
+    url('chrome://resources/images/2x/apps/checkbox_checked.png') 2x);
+}
diff --git a/ui/webui/resources/css/apps/topbutton_bar.css b/ui/webui/resources/css/apps/topbutton_bar.css
new file mode 100644
index 0000000..aa91875
--- /dev/null
+++ b/ui/webui/resources/css/apps/topbutton_bar.css
@@ -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. */
+
+.topbutton-bar {
+  -webkit-box-align: center;
+  display: -webkit-box;
+}
+
+.topbutton-bar button {
+  -webkit-app-region: no-drag;
+  -webkit-box-shadow: none;
+  -webkit-margin-end: 10px;
+  background-color: transparent;
+  background-image: none;
+  background-position: center;
+  background-repeat: no-repeat;
+  border: 0;
+  display: block;
+  height: 32px;
+  outline: none;
+  padding: 0;
+  width: 32px;
+}
+
+.topbutton-bar button:active {
+  -webkit-box-shadow:
+    0 1px 0 0 #c2c2c2 inset,
+    0 0 0 1px #dedede inset;
+}
+
+.topbutton-bar button:hover,
+.topbutton-bar button:focus,
+.topbutton-bar button:active {
+  background-color: #ededed;
+}
+
+.topbutton-bar .maximize-button {
+  background-image: -webkit-image-set(
+      url('chrome://resources/images/apps/topbar_button_maximize.png') 1x,
+      url('chrome://resources/images/2x/apps/topbar_button_maximize.png') 2x);
+}
+
+.topbutton-bar .minimize-button {
+  background-image: -webkit-image-set(
+      url('chrome://resources/images/apps/topbar_button_minimize.png') 1x,
+      url('chrome://resources/images/2x/apps/topbar_button_minimize.png') 2x);
+}
+
+.topbutton-bar .close-button {
+  background-image: -webkit-image-set(
+      url('chrome://resources/images/apps/topbar_button_close.png') 1x,
+      url('chrome://resources/images/2x/apps/topbar_button_close.png') 2x);
+}
+
+.topbutton-bar .gear-button {
+  background-image: -webkit-image-set(
+      url('chrome://resources/images/apps/topbar_button_settings.png') 1x,
+      url('chrome://resources/images/2x/apps/topbar_button_settings.png') 2x);
+}
diff --git a/ui/webui/resources/css/overlay.css b/ui/webui/resources/css/overlay.css
index af47453..5bf914c 100644
--- a/ui/webui/resources/css/overlay.css
+++ b/ui/webui/resources/css/overlay.css
@@ -151,7 +151,7 @@
 /* On OSX 10.7, hidden scrollbars may prevent the user from realizing that the
  * overlay contains scrollable content. To resolve this, style the scrollbars on
  * OSX so they are always visible. See http://crbug.com/123010. */
-<if expr="is_macosx">
+<if expr="is_macosx or is_ios">
 .overlay .page .content-area::-webkit-scrollbar {
   -webkit-appearance: none;
   width: 11px;
diff --git a/ui/webui/resources/css/tree.css b/ui/webui/resources/css/tree.css
index 64ae212..3bd08f7 100644
--- a/ui/webui/resources/css/tree.css
+++ b/ui/webui/resources/css/tree.css
@@ -169,7 +169,7 @@
   font-size: inherit;
   font-weight: inherit;
   margin: -2px -8px -2px -3px;
-<if expr="not is_macosx">
+<if expr="not is_macosx and not is_ios">
   outline: none;
 </if>
   padding: 1px 7px 1px 1px;
diff --git a/ui/webui/resources/css/widgets.css b/ui/webui/resources/css/widgets.css
index 5a69ea8..68b7c26 100644
--- a/ui/webui/resources/css/widgets.css
+++ b/ui/webui/resources/css/widgets.css
@@ -98,7 +98,7 @@
   /* Use min-height to accommodate addditional padding for touch as needed. */
   min-height: 2em;
   padding: 3px;
-<if expr="is_win or is_macosx">
+<if expr="is_win or is_macosx or is_ios">
   /* For better alignment between adjacent buttons and inputs. */
   padding-bottom: 4px;
 </if>
diff --git a/ui/webui/resources/js/webui_resource_test.js b/ui/webui/resources/js/webui_resource_test.js
new file mode 100644
index 0000000..cce993d
--- /dev/null
+++ b/ui/webui/resources/js/webui_resource_test.js
@@ -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.
+
+/**
+ * Tests that an observation matches the expected value.
+ * @param {Object} expected The expected value.
+ * @param {Object} observed The actual value.
+ * @param {string=} opt_message Optional message to include with a test
+ *     failure.
+ */
+function assertEquals(expected, observed, opt_message) {
+  if (observed !== expected) {
+    var message = 'Assertion Failed\n  Observed: ' + observed +
+        '\n  Expected: ' + expected;
+    if (opt_message)
+      message = message + '\n  ' + opt_message;
+    throw new Error(message);
+  }
+}
+
+/**
+ * Verifies that a test result is true.
+ * @param {boolean} observed The observed value.
+ * @param {string=} opt_message Optional message to include with a test
+ *     failure.
+ */
+function assertTrue(observed, opt_message) {
+  assertEquals(true, observed, opt_message);
+}
+
+/**
+ * Verifies that a test result is false.
+ * @param {boolean} observed The observed value.
+ * @param {string=} opt_message Optional message to include with a test
+ *     failure.
+ */
+function assertFalse(observed, opt_message) {
+  assertEquals(false, observed, opt_message);
+}
+
+/**
+ * Verifies that the observed and reference values differ.
+ * @param {Object} reference The target value for comparison.
+ * @param {Object} observed The test result.
+ * @param {string=} opt_message Optional message to include with a test
+ *     failure.
+ */
+function assertNotEqual(reference, observed, opt_message) {
+  if (observed === reference) {
+    var message = 'Assertion Failed\n  Observed: ' + observed +
+        '\n  Reference: ' + reference;
+    if (opt_message)
+      message = message + '\n  ' + opt_message;
+    throw new Error(message);
+  }
+}
+
+/**
+ * Verifies that a test evaluation results in an exception.
+ * @param {!Function} f The test function.
+ */
+function assertThrows(f) {
+  var triggeredError = false;
+  try {
+    f();
+  } catch(err) {
+    triggeredError = true;
+  }
+  if (!triggeredError)
+    throw new Error('Assertion Failed: throw expected.');
+}
+
+/**
+ * Verifies that the contents of the expected and observed arrays match.
+ * @param {!Array} expected The expected result.
+ * @param {!Array} observed The actual result.
+ */
+function assertArrayEquals(expected, observed) {
+  var v1 = Array.prototype.slice.call(expected);
+  var v2 = Array.prototype.slice.call(observed);
+  var equal = v1.length == v2.length;
+  if (equal) {
+    for (var i = 0; i < v1.length; i++) {
+      if (v1[i] !== v2[i]) {
+        equal = false;
+        break;
+      }
+    }
+  }
+  if (!equal) {
+    var message =
+       ['Assertion Failed', 'Observed: ' + v2, 'Expected: ' + v1].join('\n  ');
+    throw new Error(message);
+  }
+}
+
+/**
+ * Verifies that the expected and observed result have the same content.
+ * @param {*} expected The expected result.
+ * @param {*} observed The actual result.
+ */
+function assertDeepEquals(expected, observed, opt_message) {
+  if (typeof expected == 'object' && expected != null) {
+    assertNotEqual(null, observed);
+    for (var key in expected) {
+      assertTrue(key in observed, opt_message);
+      assertDeepEquals(expected[key], observed[key], opt_message);
+    }
+    for (var key in observed) {
+      assertTrue(key in expected, opt_message);
+    }
+  } else {
+    assertEquals(expected, observed, opt_message);
+  }
+}
+
+/**
+ * Defines runTests.
+ */
+(function(exports) {
+  /**
+   * List of test cases.
+   * @type {Array.<string>} List of function names for tests to run.
+   */
+  var testCases = [];
+
+  /**
+   * Indicates if all tests have run successfully.
+   * @type {boolean}
+   */
+  var cleanTestRun = true;
+
+  /**
+   * Armed during setup of a test to call the matching tear down code.
+   * @type {Function}
+   */
+  var pendingTearDown = null;
+
+  /**
+   * Runs all functions starting with test and reports success or
+   * failure of the test suite.
+   */
+  function runTests() {
+    for (var name in window) {
+      if (typeof window[name] == 'function' && /^test/.test(name))
+        testCases.push(name);
+    }
+    if (!testCases.length) {
+      console.error('Failed to find test cases.');
+      cleanTestRun = false;
+    }
+    continueTesting();
+  }
+
+  /**
+   * Runs the next test in the queue. Reports the test results if the queue is
+   * empty.
+   */
+  function continueTesting() {
+    if (pendingTearDown) {
+      pendingTearDown();
+      pendingTearDown = null;
+    }
+    if (testCases.length > 0) {
+      var fn = testCases.pop();
+      var isAsyncTest = window[fn].length;
+      try {
+        if (window.setUp)
+          window.setUp();
+        pendingTearDown = window.tearDown;
+        window[fn](continueTesting);
+      } catch(err) {
+        console.error('Failure in test ' + fn + '\n' + err);
+        console.log(err.stack);
+        cleanTestRun = false;
+      }
+      // Asynchronous tests must manually call continueTesting when complete.
+      if (!isAsyncTest)
+        continueTesting();
+    } else {
+      endTests(cleanTestRun);
+    }
+    if (testCases.length) {
+      domAutomationController.setAutomationId(1);
+      domAutomationController.send('PENDING');
+    }
+  };
+
+  exports.runTests = runTests;
+})(this);
+
+/**
+ * Signals completion of a test.
+ * @param {boolean} success Indicates if the test completed successfully.
+ */
+function endTests(success) {
+  domAutomationController.setAutomationId(1);
+  domAutomationController.send(success ? 'SUCCESS' : 'FAILURE');
+}
+
+window.onerror = function() {
+  endTests(false);
+};
diff --git a/ui/webui/resources/webui_resources.grd b/ui/webui/resources/webui_resources.grd
index 219ebbf..cd725a3 100644
--- a/ui/webui/resources/webui_resources.grd
+++ b/ui/webui/resources/webui_resources.grd
@@ -17,6 +17,79 @@
       <include name="IDR_WEBUI_I18N_TEMPLATE_JS" file="js/i18n_template.js" type="BINDATA" />
       <include name="IDR_WEBUI_I18N_TEMPLATE2_JS" file="js/i18n_template2.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_WEBUI_JSTEMPLATE_JS" file="js/jstemplate_compiled.js" flattenhtml="true" type="BINDATA" />
+
+      <!-- Component apps common image resources - 1x -->
+      <include name="IDR_WEBUI_IMAGES_APPS_BUTTON"
+               file="../../resources/default_100_percent/common/button.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BUTTON_PRESSED"
+               file="../../resources/default_100_percent/common/button_pressed.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BUTTON_HOVER"
+               file="../../resources/default_100_percent/common/button_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BUTTON_DISABLED"
+               file="../../resources/default_100_percent/common/button_inactive.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BLUE_BUTTON"
+               file="../../resources/default_100_percent/common/blue_button.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BLUE_BUTTON_PRESSED"
+               file="../../resources/default_100_percent/common/blue_button_pressed.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BLUE_BUTTON_HOVER"
+               file="../../resources/default_100_percent/common/blue_button_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BLUE_BUTTON_DISABLED"
+               file="../../resources/default_100_percent/common/blue_button_inactive.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_CLOSE"
+               file="images/apps/topbar_button_close.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MAXIMIZE"
+               file="images/apps/topbar_button_maximize.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MINIMIZE"
+               file="images/apps/topbar_button_minimize.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_SETTINGS"
+               file="images/apps/topbar_button_settings.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX"
+               file="../../resources/default_100_percent/common/checkbox.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_HOVER"
+               file="../../resources/default_100_percent/common/checkbox_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_PRESSED"
+               file="../../resources/default_100_percent/common/checkbox_pressed.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_CHECKED"
+               file="../../resources/default_100_percent/common/checkbox_checked.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_CHECKED_HOVER"
+               file="../../resources/default_100_percent/common/checkbox_checked_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_CHECKED_PRESSED"
+               file="../../resources/default_100_percent/common/checkbox_checked_pressed.png" type="BINDATA" />
+
+      <!-- Component apps common image resources - 2x -->
+      <include name="IDR_WEBUI_IMAGES_APPS_BUTTON_2X"
+               file="../../resources/default_200_percent/common/button.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BUTTON_PRESSED_2X"
+               file="../../resources/default_200_percent/common/button_pressed.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BUTTON_HOVER_2X"
+               file="../../resources/default_200_percent/common/button_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BLUE_BUTTON_2X"
+               file="../../resources/default_200_percent/common/blue_button.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BLUE_BUTTON_PRESSED_2X"
+               file="../../resources/default_200_percent/common/blue_button_pressed.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_BLUE_BUTTON_HOVER_2X_2X"
+               file="../../resources/default_200_percent/common/blue_button_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_CLOSE_2X"
+               file="images/2x/apps/topbar_button_close.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MAXIMIZE_2X"
+               file="images/2x/apps/topbar_button_maximize.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MINIMIZE_2X"
+               file="images/2x/apps/topbar_button_minimize.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_SETTINGS_2X"
+               file="images/2x/apps/topbar_button_settings.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_2X"
+               file="../../resources/default_200_percent/common/checkbox.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_HOVER_2X"
+               file="../../resources/default_200_percent/common/checkbox_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_PRESSED_2X"
+               file="../../resources/default_200_percent/common/checkbox_pressed.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_CHECKED_2X"
+               file="../../resources/default_200_percent/common/checkbox_checked.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_CHECKED_HOVER_2X"
+               file="../../resources/default_200_percent/common/checkbox_checked_hover.png" type="BINDATA" />
+      <include name="IDR_WEBUI_IMAGES_APPS_CHECKBOX_CHECKED_PRESSED_2X"
+               file="../../resources/default_200_percent/common/checkbox_checked_pressed.png" type="BINDATA" />
+
       <include name="IDR_WEBUI_IMAGES_CHECK"
                file="images/check.png" type="BINDATA" />
       <include name="IDR_WEBUI_IMAGES_CHECKBOX_BLACK"
@@ -51,6 +124,10 @@
                  file="css/bubble_button.css" type="chrome_html" />
       <structure name="IDR_WEBUI_CSS_BUTTER_BAR"
                  file="css/butter_bar.css" type="chrome_html" />
+      <structure name="IDR_WEBUI_CSS_APPS_COMMON"
+                 file="css/apps/common.css" type="chrome_html" />
+      <structure name="IDR_WEBUI_CSS_APPS_TOPBUTTON_BAR"
+                 file="css/apps/topbutton_bar.css" type="chrome_html" />
       <structure name="IDR_WEBUI_CSS_DIALOGS"
                  file="css/dialogs.css" type="chrome_html" />
       <structure name="IDR_WEBUI_CSS_LIST"
@@ -204,6 +281,8 @@
                  file="js/parse_html_subset.js" type="chrome_html" />
       <structure name="IDR_WEBUI_JS_UTIL"
                  file="js/util.js" type="chrome_html" flattenhtml="true" />
+      <structure name="IDR_WEBUI_JS_WEBUI_RESOURCE_TEST"
+                 file="js/webui_resource_test.js" type="chrome_html" />
       <if expr="pp_ifdef('chromeos')">
         <structure name="IDR_WEBUI_CSS_UI_ACCOUNT_TWEAKS"
                    file="css/chromeos/ui_account_tweaks.css"
diff --git a/url/gurl.cc b/url/gurl.cc
index 09b8abb..229df5d 100644
--- a/url/gurl.cc
+++ b/url/gurl.cc
@@ -367,6 +367,10 @@
                                         lower_ascii_scheme);
 }
 
+bool GURL::SchemeIsHTTPOrHTTPS() const {
+  return SchemeIs("http") || SchemeIs("https");
+}
+
 int GURL::IntPort() const {
   if (parsed_.port.is_nonempty())
     return url_parse::ParsePort(spec_.data(), parsed_.port);
diff --git a/url/gurl.h b/url/gurl.h
index da5f736..4b986a6 100644
--- a/url/gurl.h
+++ b/url/gurl.h
@@ -203,6 +203,9 @@
   // object constructions are done.
   bool SchemeIs(const char* lower_ascii_scheme) const;
 
+  // Returns true if the scheme is "http" or "https".
+  bool SchemeIsHTTPOrHTTPS() const;
+
   // We often need to know if this is a file URL. File URLs are "standard", but
   // are often treated separately by some programs.
   bool SchemeIsFile() const {
diff --git a/url/gurl_test_main.cc b/url/gurl_test_main.cc
deleted file mode 100644
index d35e5d4..0000000
--- a/url/gurl_test_main.cc
+++ /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.
-
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#include <string>
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/icu/source/common/unicode/putil.h"
-#include "third_party/icu/source/common/unicode/udata.h"
-
-#define ICU_UTIL_DATA_SHARED 1
-#define ICU_UTIL_DATA_STATIC 2
-
-#ifndef ICU_UTIL_DATA_IMPL
-
-#if defined(OS_WIN)
-#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_SHARED
-#elif defined(OS_MACOSX)
-#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_STATIC
-#elif defined(OS_LINUX)
-#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_FILE
-#endif
-
-#endif  // ICU_UTIL_DATA_IMPL
-
-#if defined(OS_WIN)
-#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
-#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt" U_ICU_VERSION_SHORT ".dll"
-#endif
-
-bool InitializeICU() {
-#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
-  // We expect to find the ICU data module alongside the current module.
-  // Because the module name is ASCII-only, "A" API should be safe.
-  // Chrome's copy of ICU dropped a version number XX from icudt dll,
-  // but 3rd-party embedders may need it. So, we try both.
-  HMODULE module = LoadLibraryA("icudt.dll");
-  if (!module) {
-    module = LoadLibraryA(ICU_UTIL_DATA_SHARED_MODULE_NAME);
-    if (!module)
-      return false;
-  }
-
-  FARPROC addr = GetProcAddress(module, ICU_UTIL_DATA_SYMBOL);
-  if (!addr)
-    return false;
-
-  UErrorCode err = U_ZERO_ERROR;
-  udata_setCommonData(reinterpret_cast<void*>(addr), &err);
-  return err == U_ZERO_ERROR;
-#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
-  // Mac bundles the ICU data in.
-  return true;
-#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
-  // We expect to find the ICU data module alongside the current module.
-  u_setDataDirectory(".");
-  // Only look for the packaged data file;
-  // the default behavior is to look for individual files.
-  UErrorCode err = U_ZERO_ERROR;
-  udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
-  return err == U_ZERO_ERROR;
-#endif
-}
-
-int main(int argc, char **argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-
-  InitializeICU();
-
-  return RUN_ALL_TESTS();
-}
diff --git a/url/url_canon_icu.h b/url/url_canon_icu.h
index 9bfd643..1159768 100644
--- a/url/url_canon_icu.h
+++ b/url/url_canon_icu.h
@@ -7,6 +7,7 @@
 
 // ICU integration functions.
 
+#include "base/compiler_specific.h"
 #include "url/url_canon.h"
 #include "url/url_export.h"
 
@@ -27,7 +28,7 @@
 
   virtual void ConvertFromUTF16(const base::char16* input,
                                 int input_len,
-                                CanonOutput* output);
+                                CanonOutput* output) OVERRIDE;
 
  private:
   // The ICU converter, not owned by this class.
diff --git a/url/url_canon_stdstring.h b/url/url_canon_stdstring.h
index 7450f15..9b4a6c2 100644
--- a/url/url_canon_stdstring.h
+++ b/url/url_canon_stdstring.h
@@ -11,6 +11,7 @@
 
 #include <string>
 
+#include "base/compiler_specific.h"
 #include "url/url_canon.h"
 
 namespace url_canon {
@@ -51,7 +52,7 @@
     buffer_len_ = cur_len_;
   }
 
-  virtual void Resize(int sz) {
+  virtual void Resize(int sz) OVERRIDE {
     str_->resize(sz);
     buffer_ = str_->empty() ? NULL : &(*str_)[0];
     buffer_len_ = sz;
diff --git a/url/url_util_unittest.cc b/url/url_util_unittest.cc
index 26d4dc7..8b16d79 100644
--- a/url/url_util_unittest.cc
+++ b/url/url_util_unittest.cc
@@ -241,22 +241,32 @@
       // A non-standard hierarchical base is resolved with path URL
       // canoncialization rules.
     {"data:/Blah:Blah/", "file.html", true, "data:/Blah:Blah/file.html"},
-    {"data:/Path/../part/part2", "file.html", true, "data:/Path/../part/file.html"},
+    {"data:/Path/../part/part2", "file.html", true,
+      "data:/Path/../part/file.html"},
       // Path URL canonicalization rules also apply to non-standard authority-
       // based URLs.
-    {"custom://Authority/", "file.html", true, "custom://Authority/file.html"},
+    {"custom://Authority/", "file.html", true,
+      "custom://Authority/file.html"},
     {"custom://Authority/", "other://Auth/", true, "other://Auth/"},
-    {"custom://Authority/", "../../file.html", true, "custom://Authority/file.html"},
-    {"custom://Authority/path/", "file.html", true, "custom://Authority/path/file.html"},
-    {"custom://Authority:NoCanon/path/", "file.html", true, "custom://Authority:NoCanon/path/file.html"},
+    {"custom://Authority/", "../../file.html", true,
+      "custom://Authority/file.html"},
+    {"custom://Authority/path/", "file.html", true,
+      "custom://Authority/path/file.html"},
+    {"custom://Authority:NoCanon/path/", "file.html", true,
+      "custom://Authority:NoCanon/path/file.html"},
       // It's still possible to get an invalid path URL.
     {"custom://Invalid:!#Auth/", "file.html", false, ""},
       // A path with an authority section gets canonicalized under standard URL
       // rules, even though the base was non-standard.
-    {"content://content.Provider/", "//other.Provider", true, "content://other.provider/"},
+    {"content://content.Provider/", "//other.Provider", true,
+      "content://other.provider/"},
       // Resolving an absolute URL doesn't cause canonicalization of the
       // result.
     {"about:blank", "custom://Authority", true, "custom://Authority"},
+      // Fragment URLs can be resolved against a non-standard base.
+    {"scheme://Authority/path", "#fragment", true,
+      "scheme://Authority/path#fragment"},
+    {"scheme://Authority/", "#fragment", true, "scheme://Authority/#fragment"},
       // Resolving should fail if the base URL is authority-based but is
       // missing a path component (the '/' at the end).
     {"scheme://Authority", "path", false, ""},
diff --git a/webkit/browser/fileapi/async_file_test_helper.cc b/webkit/browser/fileapi/async_file_test_helper.cc
index 8a01fd2..ff38d1f 100644
--- a/webkit/browser/fileapi/async_file_test_helper.cc
+++ b/webkit/browser/fileapi/async_file_test_helper.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webkit/browser/fileapi/async_file_test_helper.h"
@@ -164,6 +166,25 @@
   return result;
 }
 
+base::PlatformFileError AsyncFileTestHelper::CreateFileWithData(
+    FileSystemContext* context,
+    const FileSystemURL& url,
+    const char* buf,
+    int buf_size) {
+  base::ScopedTempDir dir;
+  if (!dir.CreateUniqueTempDir())
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  base::FilePath local_path = dir.path().AppendASCII("tmp");
+  if (buf_size != file_util::WriteFile(local_path, buf, buf_size))
+    return base::PLATFORM_FILE_ERROR_FAILED;
+  base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED;
+  base::RunLoop run_loop;
+  context->operation_runner()->CopyInForeignFile(
+      local_path, url, AssignAndQuitCallback(&run_loop, &result));
+  run_loop.Run();
+  return result;
+}
+
 base::PlatformFileError AsyncFileTestHelper::TruncateFile(
     FileSystemContext* context,
     const FileSystemURL& url,
diff --git a/webkit/browser/fileapi/async_file_test_helper.h b/webkit/browser/fileapi/async_file_test_helper.h
index cfa7981..da27bf2 100644
--- a/webkit/browser/fileapi/async_file_test_helper.h
+++ b/webkit/browser/fileapi/async_file_test_helper.h
@@ -54,6 +54,13 @@
   static base::PlatformFileError CreateFile(FileSystemContext* context,
                                             const FileSystemURL& url);
 
+  // Creates a file at |url| and fills with |buf|.
+  static base::PlatformFileError CreateFileWithData(
+      FileSystemContext* context,
+      const FileSystemURL& url,
+      const char* buf,
+      int buf_size);
+
   // Truncates the file |url| to |size|.
   static base::PlatformFileError TruncateFile(FileSystemContext* context,
                                               const FileSystemURL& url,
diff --git a/webkit/browser/fileapi/file_system_context.cc b/webkit/browser/fileapi/file_system_context.cc
index 88abd24..f2973d3 100644
--- a/webkit/browser/fileapi/file_system_context.cc
+++ b/webkit/browser/fileapi/file_system_context.cc
@@ -108,14 +108,14 @@
     : io_task_runner_(io_task_runner),
       default_file_task_runner_(file_task_runner),
       quota_manager_proxy_(quota_manager_proxy),
-      sandbox_context_(new SandboxContext(
+      sandbox_delegate_(new SandboxFileSystemBackendDelegate(
           quota_manager_proxy,
           file_task_runner,
           partition_path,
           special_storage_policy,
           options)),
       sandbox_backend_(new SandboxFileSystemBackend(
-          sandbox_context_.get())),
+          sandbox_delegate_.get())),
       isolated_backend_(new IsolatedFileSystemBackend()),
       additional_backends_(additional_backends.Pass()),
       external_mount_points_(external_mount_points),
@@ -174,6 +174,16 @@
   return success;
 }
 
+void FileSystemContext::Shutdown() {
+  if (!io_task_runner_->RunsTasksOnCurrentThread()) {
+    io_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&FileSystemContext::Shutdown,
+                              make_scoped_refptr(this)));
+    return;
+  }
+  operation_runner_->Shutdown();
+}
+
 FileSystemQuotaUtil*
 FileSystemContext::GetQuotaUtil(FileSystemType type) const {
   FileSystemBackend* backend = GetFileSystemBackend(type);
diff --git a/webkit/browser/fileapi/file_system_context.h b/webkit/browser/fileapi/file_system_context.h
index 8f84970..528f7a2 100644
--- a/webkit/browser/fileapi/file_system_context.h
+++ b/webkit/browser/fileapi/file_system_context.h
@@ -17,7 +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/sandbox_context.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"
 #include "webkit/common/fileapi/file_system_types.h"
@@ -108,6 +108,9 @@
     return quota_manager_proxy_.get();
   }
 
+  // Discards inflight operations in the operation runner.
+  void Shutdown();
+
   // Returns a quota util for a given filesystem type.  This may
   // return NULL if the type does not support the usage tracking or
   // it is not a quota-managed storage.
@@ -225,7 +228,9 @@
   void EnableTemporaryFileSystemInIncognito();
 #endif
 
-  SandboxContext* sandbox_context() { return sandbox_context_.get(); }
+  SandboxFileSystemBackendDelegate* sandbox_delegate() {
+    return sandbox_delegate_.get();
+  }
 
  private:
   typedef std::map<FileSystemType, FileSystemBackend*>
@@ -280,7 +285,7 @@
 
   scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
 
-  scoped_ptr<SandboxContext> sandbox_context_;
+  scoped_ptr<SandboxFileSystemBackendDelegate> sandbox_delegate_;
 
   // Regular file system backends.
   scoped_ptr<SandboxFileSystemBackend> sandbox_backend_;
diff --git a/webkit/browser/fileapi/file_system_quota_util.h b/webkit/browser/fileapi/file_system_quota_util.h
index be98936..5f3c7dd 100644
--- a/webkit/browser/fileapi/file_system_quota_util.h
+++ b/webkit/browser/fileapi/file_system_quota_util.h
@@ -56,11 +56,6 @@
       const GURL& origin_url,
       fileapi::FileSystemType type) = 0;
 
-  virtual void InvalidateUsageCache(const GURL& origin_url,
-                                    fileapi::FileSystemType type) = 0;
-  virtual void StickyInvalidateUsageCache(const GURL& origin,
-                                          fileapi::FileSystemType type) = 0;
-
   virtual void AddFileUpdateObserver(
       FileSystemType type,
       FileUpdateObserver* observer,
@@ -73,6 +68,9 @@
       FileSystemType type,
       FileAccessObserver* observer,
       base::SequencedTaskRunner* task_runner) = 0;
+
+  // Returns the observer list for |type|, or returns NULL if any observers
+  // have not been registered on |type|.
   virtual const UpdateObserverList* GetUpdateObservers(
       FileSystemType type) const = 0;
   virtual const ChangeObserverList* GetChangeObservers(
diff --git a/webkit/browser/fileapi/obfuscated_file_util.cc b/webkit/browser/fileapi/obfuscated_file_util.cc
index 77e2d86..7e2f7df 100644
--- a/webkit/browser/fileapi/obfuscated_file_util.cc
+++ b/webkit/browser/fileapi/obfuscated_file_util.cc
@@ -276,7 +276,7 @@
       file_flags & base::PLATFORM_FILE_WRITE &&
       context->quota_limit_type() == quota::kQuotaLimitTypeUnlimited) {
     DCHECK_EQ(base::PLATFORM_FILE_OK, error);
-    context->file_system_context()->GetQuotaUtil(url.type())->
+    context->file_system_context()->sandbox_delegate()->
         StickyInvalidateUsageCache(url.origin(), url.type());
   }
   return error;
@@ -1261,7 +1261,7 @@
     FileSystemOperationContext* context,
     const GURL& origin,
     FileSystemType type) {
-  context->file_system_context()->GetQuotaUtil(type)->
+  context->file_system_context()->sandbox_delegate()->
       InvalidateUsageCache(origin, type);
 }
 
diff --git a/webkit/browser/fileapi/sandbox_context.cc b/webkit/browser/fileapi/sandbox_context.cc
deleted file mode 100644
index d8b7293..0000000
--- a/webkit/browser/fileapi/sandbox_context.cc
+++ /dev/null
@@ -1,427 +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 "webkit/browser/fileapi/sandbox_context.h"
-
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/metrics/histogram.h"
-#include "base/stl_util.h"
-#include "base/task_runner_util.h"
-#include "net/base/net_util.h"
-#include "webkit/browser/fileapi/async_file_util_adapter.h"
-#include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_operation_context.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/file_system_usage_cache.h"
-#include "webkit/browser/fileapi/obfuscated_file_util.h"
-#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
-#include "webkit/browser/fileapi/sandbox_quota_observer.h"
-#include "webkit/browser/quota/quota_manager.h"
-#include "webkit/common/fileapi/file_system_util.h"
-
-namespace fileapi {
-
-namespace {
-
-const char kOpenFileSystemLabel[] = "FileSystem.OpenFileSystem";
-const char kOpenFileSystemDetailLabel[] = "FileSystem.OpenFileSystemDetail";
-const char kOpenFileSystemDetailNonThrottledLabel[] =
-    "FileSystem.OpenFileSystemDetailNonthrottled";
-int64 kMinimumStatsCollectionIntervalHours = 1;
-
-enum FileSystemError {
-  kOK = 0,
-  kIncognito,
-  kInvalidSchemeError,
-  kCreateDirectoryError,
-  kNotFound,
-  kUnknownError,
-  kFileSystemErrorMax,
-};
-
-// Restricted names.
-// http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
-const base::FilePath::CharType* const kRestrictedNames[] = {
-  FILE_PATH_LITERAL("."), FILE_PATH_LITERAL(".."),
-};
-
-// Restricted chars.
-const base::FilePath::CharType kRestrictedChars[] = {
-  FILE_PATH_LITERAL('/'), FILE_PATH_LITERAL('\\'),
-};
-
-class ObfuscatedOriginEnumerator
-    : public SandboxContext::OriginEnumerator {
- public:
-  explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) {
-    enum_.reset(file_util->CreateOriginEnumerator());
-  }
-  virtual ~ObfuscatedOriginEnumerator() {}
-
-  virtual GURL Next() OVERRIDE {
-    return enum_->Next();
-  }
-
-  virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE {
-    return enum_->HasFileSystemType(type);
-  }
-
- private:
-  scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_;
-};
-
-void OpenFileSystemOnFileThread(
-    ObfuscatedFileUtil* file_util,
-    const GURL& origin_url,
-    FileSystemType type,
-    OpenFileSystemMode mode,
-    base::PlatformFileError* error_ptr) {
-  DCHECK(error_ptr);
-  const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT);
-  file_util->GetDirectoryForOriginAndType(origin_url, type, create, error_ptr);
-  if (*error_ptr != base::PLATFORM_FILE_OK) {
-    UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel,
-                              kCreateDirectoryError,
-                              kFileSystemErrorMax);
-  } else {
-    UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, kOK, kFileSystemErrorMax);
-  }
-  // The reference of file_util will be derefed on the FILE thread
-  // when the storage of this callback gets deleted regardless of whether
-  // this method is called or not.
-}
-
-void DidOpenFileSystem(
-    base::WeakPtr<SandboxContext> sandbox_context,
-    const base::Callback<void(base::PlatformFileError error)>& callback,
-    base::PlatformFileError* error) {
-  if (sandbox_context.get())
-    sandbox_context.get()->CollectOpenFileSystemMetrics(*error);
-  callback.Run(*error);
-}
-
-}  // namespace
-
-const base::FilePath::CharType
-SandboxContext::kFileSystemDirectory[] = FILE_PATH_LITERAL("File System");
-
-SandboxContext::SandboxContext(
-    quota::QuotaManagerProxy* quota_manager_proxy,
-    base::SequencedTaskRunner* file_task_runner,
-    const base::FilePath& profile_path,
-    quota::SpecialStoragePolicy* special_storage_policy,
-    const FileSystemOptions& file_system_options)
-    : file_task_runner_(file_task_runner),
-      sandbox_file_util_(new AsyncFileUtilAdapter(
-          new ObfuscatedFileUtil(
-              special_storage_policy,
-              profile_path.Append(kFileSystemDirectory),
-              file_task_runner))),
-      file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)),
-      quota_observer_(new SandboxQuotaObserver(
-          quota_manager_proxy,
-          file_task_runner,
-          sync_file_util(),
-          usage_cache())),
-      special_storage_policy_(special_storage_policy),
-      file_system_options_(file_system_options),
-      weak_factory_(this) {
-}
-
-SandboxContext::~SandboxContext() {
-  if (!file_task_runner_->RunsTasksOnCurrentThread()) {
-    AsyncFileUtilAdapter* 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;
-  }
-}
-
-bool SandboxContext::IsAccessValid(const FileSystemURL& url) const {
-  if (!IsAllowedScheme(url.origin()))
-    return false;
-
-  if (url.path().ReferencesParent())
-    return false;
-
-  // Return earlier if the path is '/', because VirtualPath::BaseName()
-  // returns '/' for '/' and we fail the "basename != '/'" check below.
-  // (We exclude '.' because it's disallowed by spec.)
-  if (VirtualPath::IsRootPath(url.path()) &&
-      url.path() != base::FilePath(base::FilePath::kCurrentDirectory))
-    return true;
-
-  // Restricted names specified in
-  // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
-  base::FilePath filename = VirtualPath::BaseName(url.path());
-  // See if the name is allowed to create.
-  for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
-    if (filename.value() == kRestrictedNames[i])
-      return false;
-  }
-  for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
-    if (filename.value().find(kRestrictedChars[i]) !=
-        base::FilePath::StringType::npos)
-      return false;
-  }
-
-  return true;
-}
-
-bool SandboxContext::IsAllowedScheme(const GURL& url) const {
-  // Basically we only accept http or https. We allow file:// URLs
-  // only if --allow-file-access-from-files flag is given.
-  if (url.SchemeIs("http") || url.SchemeIs("https"))
-    return true;
-  if (url.SchemeIsFileSystem())
-    return url.inner_url() && IsAllowedScheme(*url.inner_url());
-
-  for (size_t i = 0;
-       i < file_system_options_.additional_allowed_schemes().size();
-       ++i) {
-    if (url.SchemeIs(
-            file_system_options_.additional_allowed_schemes()[i].c_str()))
-      return true;
-  }
-  return false;
-}
-
-SandboxContext::OriginEnumerator* SandboxContext::CreateOriginEnumerator() {
-  return new ObfuscatedOriginEnumerator(sync_file_util());
-}
-
-base::FilePath SandboxContext::GetBaseDirectoryForOriginAndType(
-    const GURL& origin_url, fileapi::FileSystemType type, bool create) {
-  base::PlatformFileError error = base::PLATFORM_FILE_OK;
-  base::FilePath path = sync_file_util()->GetDirectoryForOriginAndType(
-      origin_url, type, create, &error);
-  if (error != base::PLATFORM_FILE_OK)
-    return base::FilePath();
-  return path;
-}
-
-void SandboxContext::OpenFileSystem(
-    const GURL& origin_url,
-    fileapi::FileSystemType type,
-    OpenFileSystemMode mode,
-    const OpenFileSystemCallback& callback,
-    const GURL& root_url) {
-  if (!IsAllowedScheme(origin_url)) {
-    callback.Run(GURL(), std::string(), base::PLATFORM_FILE_ERROR_SECURITY);
-    return;
-  }
-
-  std::string name = GetFileSystemName(origin_url, type);
-
-  base::PlatformFileError* error_ptr = new base::PlatformFileError;
-  file_task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::Bind(&OpenFileSystemOnFileThread,
-                 sync_file_util(), origin_url, type, mode,
-                 base::Unretained(error_ptr)),
-      base::Bind(&DidOpenFileSystem,
-                 weak_factory_.GetWeakPtr(),
-                 base::Bind(callback, root_url, name),
-                 base::Owned(error_ptr)));
-}
-
-base::PlatformFileError SandboxContext::DeleteOriginDataOnFileThread(
-    FileSystemContext* file_system_context,
-    quota::QuotaManagerProxy* proxy,
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  int64 usage = GetOriginUsageOnFileThread(
-      file_system_context, origin_url, type);
-  usage_cache()->CloseCacheFiles();
-  bool result = sync_file_util()->DeleteDirectoryForOriginAndType(
-      origin_url, type);
-  if (result && proxy) {
-    proxy->NotifyStorageModified(
-        quota::QuotaClient::kFileSystem,
-        origin_url,
-        FileSystemTypeToQuotaStorageType(type),
-        -usage);
-  }
-
-  if (result)
-    return base::PLATFORM_FILE_OK;
-  return base::PLATFORM_FILE_ERROR_FAILED;
-}
-
-void SandboxContext::GetOriginsForTypeOnFileThread(
-    fileapi::FileSystemType type, std::set<GURL>* origins) {
-  DCHECK(origins);
-  scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
-  GURL origin;
-  while (!(origin = enumerator->Next()).is_empty()) {
-    if (enumerator->HasFileSystemType(type))
-      origins->insert(origin);
-  }
-}
-
-void SandboxContext::GetOriginsForHostOnFileThread(
-    fileapi::FileSystemType type, const std::string& host,
-    std::set<GURL>* origins) {
-  DCHECK(origins);
-  scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
-  GURL origin;
-  while (!(origin = enumerator->Next()).is_empty()) {
-    if (host == net::GetHostOrSpecFromURL(origin) &&
-        enumerator->HasFileSystemType(type))
-      origins->insert(origin);
-  }
-}
-
-int64 SandboxContext::GetOriginUsageOnFileThread(
-    FileSystemContext* file_system_context,
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  // Don't use usage cache and return recalculated usage for sticky invalidated
-  // origins.
-  if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type)))
-    return RecalculateUsage(file_system_context, origin_url, type);
-
-  base::FilePath base_path =
-      GetBaseDirectoryForOriginAndType(origin_url, type, false);
-  if (base_path.empty() || !base::DirectoryExists(base_path))
-    return 0;
-  base::FilePath usage_file_path =
-      base_path.Append(FileSystemUsageCache::kUsageFileName);
-
-  bool is_valid = usage_cache()->IsValid(usage_file_path);
-  uint32 dirty_status = 0;
-  bool dirty_status_available =
-      usage_cache()->GetDirty(usage_file_path, &dirty_status);
-  bool visited = !visited_origins_.insert(origin_url).second;
-  if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) {
-    // The usage cache is clean (dirty == 0) or the origin is already
-    // initialized and running.  Read the cache file to get the usage.
-    int64 usage = 0;
-    return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1;
-  }
-  // The usage cache has not been initialized or the cache is dirty.
-  // Get the directory size now and update the cache.
-  usage_cache()->Delete(usage_file_path);
-
-  int64 usage = RecalculateUsage(file_system_context, origin_url, type);
-
-  // This clears the dirty flag too.
-  usage_cache()->UpdateUsage(usage_file_path, usage);
-  return usage;
-}
-
-void SandboxContext::InvalidateUsageCache(
-    const GURL& origin,
-    fileapi::FileSystemType type) {
-  base::PlatformFileError error = base::PLATFORM_FILE_OK;
-  base::FilePath usage_file_path = GetUsageCachePathForOriginAndType(
-      sync_file_util(), origin, type, &error);
-  if (error != base::PLATFORM_FILE_OK)
-    return;
-  usage_cache()->IncrementDirty(usage_file_path);
-}
-
-void SandboxContext::StickyInvalidateUsageCache(
-    const GURL& origin,
-    fileapi::FileSystemType type) {
-  sticky_dirty_origins_.insert(std::make_pair(origin, type));
-  quota_observer()->SetUsageCacheEnabled(origin, type, false);
-  InvalidateUsageCache(origin, type);
-}
-
-base::FilePath SandboxContext::GetUsageCachePathForOriginAndType(
-    const GURL& origin_url,
-    FileSystemType type) {
-  base::PlatformFileError error;
-  base::FilePath path = GetUsageCachePathForOriginAndType(
-      sync_file_util(), origin_url, type, &error);
-  if (error != base::PLATFORM_FILE_OK)
-    return base::FilePath();
-  return path;
-}
-
-// static
-base::FilePath SandboxContext::GetUsageCachePathForOriginAndType(
-    ObfuscatedFileUtil* sandbox_file_util,
-    const GURL& origin_url,
-    fileapi::FileSystemType type,
-    base::PlatformFileError* error_out) {
-  DCHECK(error_out);
-  *error_out = base::PLATFORM_FILE_OK;
-  base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType(
-      origin_url, type, false /* create */, error_out);
-  if (*error_out != base::PLATFORM_FILE_OK)
-    return base::FilePath();
-  return base_path.Append(FileSystemUsageCache::kUsageFileName);
-}
-
-int64 SandboxContext::RecalculateUsage(FileSystemContext* context,
-                                       const GURL& origin,
-                                       FileSystemType type) {
-  FileSystemOperationContext operation_context(context);
-  FileSystemURL url = context->CreateCrackedFileSystemURL(
-      origin, type, base::FilePath());
-  scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator(
-      sync_file_util()->CreateFileEnumerator(&operation_context, url, true));
-
-  base::FilePath file_path_each;
-  int64 usage = 0;
-
-  while (!(file_path_each = enumerator->Next()).empty()) {
-    usage += enumerator->Size();
-    usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each);
-  }
-
-  return usage;
-}
-
-void SandboxContext::CollectOpenFileSystemMetrics(
-    base::PlatformFileError error_code) {
-  base::Time now = base::Time::Now();
-  bool throttled = now < next_release_time_for_open_filesystem_stat_;
-  if (!throttled) {
-    next_release_time_for_open_filesystem_stat_ =
-        now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours);
-  }
-
-#define REPORT(report_value)                                            \
-  UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel,                 \
-                            (report_value),                             \
-                            kFileSystemErrorMax);                       \
-  if (!throttled) {                                                     \
-    UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel,   \
-                              (report_value),                           \
-                              kFileSystemErrorMax);                     \
-  }
-
-  switch (error_code) {
-    case base::PLATFORM_FILE_OK:
-      REPORT(kOK);
-      break;
-    case base::PLATFORM_FILE_ERROR_INVALID_URL:
-      REPORT(kInvalidSchemeError);
-      break;
-    case base::PLATFORM_FILE_ERROR_NOT_FOUND:
-      REPORT(kNotFound);
-      break;
-    case base::PLATFORM_FILE_ERROR_FAILED:
-    default:
-      REPORT(kUnknownError);
-      break;
-  }
-#undef REPORT
-}
-
-ObfuscatedFileUtil* SandboxContext::sync_file_util() {
-  return static_cast<ObfuscatedFileUtil*>(file_util()->sync_file_util());
-}
-
-}  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_context.h b/webkit/browser/fileapi/sandbox_context.h
deleted file mode 100644
index c765077..0000000
--- a/webkit/browser/fileapi/sandbox_context.h
+++ /dev/null
@@ -1,189 +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 WEBKIT_BROWSER_FILEAPI_SANDBOX_CONTEXT_H_
-#define WEBKIT_BROWSER_FILEAPI_SANDBOX_CONTEXT_H_
-
-#include <set>
-#include <string>
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "webkit/browser/fileapi/file_system_backend.h"
-#include "webkit/browser/fileapi/file_system_options.h"
-#include "webkit/browser/fileapi/file_system_quota_util.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
-
-namespace quota {
-class QuotaManagerProxy;
-class SpecialStoragePolicy;
-}
-
-namespace fileapi {
-
-class AsyncFileUtilAdapter;
-class FileSystemURL;
-class FileSystemUsageCache;
-class ObfuscatedFileUtil;
-class SandboxFileSystemBackend;
-class SandboxFileSystemTestHelper;
-class SandboxQuotaObserver;
-
-// This class keeps and provides a sandbox file system context.
-// An instance of this class is created and owned by FileSystemContext.
-class WEBKIT_STORAGE_BROWSER_EXPORT SandboxContext {
- public:
-  typedef FileSystemBackend::OpenFileSystemCallback OpenFileSystemCallback;
-
-  // The FileSystem directory name.
-  static const base::FilePath::CharType kFileSystemDirectory[];
-
-  // Origin enumerator interface.
-  // An instance of this interface is assumed to be called on the file thread.
-  class OriginEnumerator {
-   public:
-    virtual ~OriginEnumerator() {}
-
-    // Returns the next origin.  Returns empty if there are no more origins.
-    virtual GURL Next() = 0;
-
-    // Returns the current origin's information.
-    virtual bool HasFileSystemType(FileSystemType type) const = 0;
-  };
-
-  SandboxContext(
-      quota::QuotaManagerProxy* quota_manager_proxy,
-      base::SequencedTaskRunner* file_task_runner,
-      const base::FilePath& profile_path,
-      quota::SpecialStoragePolicy* special_storage_policy,
-      const FileSystemOptions& file_system_options);
-
-  ~SandboxContext();
-
-  // Performs API-specific validity checks on the given path |url|.
-  // Returns true if access to |url| is valid in this filesystem.
-  bool IsAccessValid(const FileSystemURL& url) const;
-
-  // Returns true if the given |url|'s scheme is allowed to access
-  // filesystem.
-  bool IsAllowedScheme(const GURL& url) const;
-
-  // Returns an origin enumerator of sandbox filesystem.
-  // This method can only be called on the file thread.
-  OriginEnumerator* CreateOriginEnumerator();
-
-  // Gets a base directory path of the sandboxed filesystem that is
-  // specified by |origin_url| and |type|.
-  // (The path is similar to the origin's root path but doesn't contain
-  // the 'unique' part.)
-  // Returns an empty path if the given type is invalid.
-  // This method can only be called on the file thread.
-  base::FilePath GetBaseDirectoryForOriginAndType(
-      const GURL& origin_url,
-      FileSystemType type,
-      bool create);
-
-  // FileSystemBackend helpers.
-  void OpenFileSystem(
-      const GURL& origin_url,
-      FileSystemType type,
-      OpenFileSystemMode mode,
-      const OpenFileSystemCallback& callback,
-      const GURL& root_url);
-
-  // FileSystemQuotaUtil helpers.
-  base::PlatformFileError DeleteOriginDataOnFileThread(
-      FileSystemContext* context,
-      quota::QuotaManagerProxy* proxy,
-      const GURL& origin_url,
-      FileSystemType type);
-  void GetOriginsForTypeOnFileThread(
-      FileSystemType type,
-      std::set<GURL>* origins);
-  void GetOriginsForHostOnFileThread(
-      FileSystemType type,
-      const std::string& host,
-      std::set<GURL>* origins);
-  int64 GetOriginUsageOnFileThread(
-      FileSystemContext* context,
-      const GURL& origin_url,
-      FileSystemType type);
-  void InvalidateUsageCache(
-      const GURL& origin_url,
-      FileSystemType type);
-  void StickyInvalidateUsageCache(
-      const GURL& origin_url,
-      FileSystemType type);
-
-  void CollectOpenFileSystemMetrics(base::PlatformFileError error_code);
-
-  base::SequencedTaskRunner* file_task_runner() {
-    return file_task_runner_.get();
-  }
-
-  AsyncFileUtilAdapter* file_util() { return sandbox_file_util_.get(); }
-  FileSystemUsageCache* usage_cache() { return file_system_usage_cache_.get(); }
-  SandboxQuotaObserver* quota_observer() { return quota_observer_.get(); };
-
-  quota::SpecialStoragePolicy* special_storage_policy() {
-    return special_storage_policy_.get();
-  }
-
-  FileSystemOptions file_system_options() { return file_system_options_; }
-
-  ObfuscatedFileUtil* sync_file_util();
-
- private:
-  friend class SandboxQuotaObserver;
-  friend class SandboxFileSystemTestHelper;
-
-  // Returns a path to the usage cache file.
-  base::FilePath GetUsageCachePathForOriginAndType(
-      const GURL& origin_url,
-      FileSystemType type);
-
-  // Returns a path to the usage cache file (static version).
-  static base::FilePath GetUsageCachePathForOriginAndType(
-      ObfuscatedFileUtil* sandbox_file_util,
-      const GURL& origin_url,
-      FileSystemType type,
-      base::PlatformFileError* error_out);
-
-  int64 RecalculateUsage(FileSystemContext* context,
-                         const GURL& origin,
-                         FileSystemType type);
-
-  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
-
-  scoped_ptr<AsyncFileUtilAdapter> sandbox_file_util_;
-  scoped_ptr<FileSystemUsageCache> file_system_usage_cache_;
-  scoped_ptr<SandboxQuotaObserver> quota_observer_;
-
-  scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
-
-  FileSystemOptions file_system_options_;
-
-  // Acccessed only on the file thread.
-  std::set<GURL> visited_origins_;
-
-  std::set<std::pair<GURL, FileSystemType> > sticky_dirty_origins_;
-
-  base::Time next_release_time_for_open_filesystem_stat_;
-
-  base::WeakPtrFactory<SandboxContext> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(SandboxContext);
-};
-
-}  // namespace fileapi
-
-#endif  // WEBKIT_BROWSER_FILEAPI_SANDBOX_CONTEXT_H_
diff --git a/webkit/browser/fileapi/sandbox_context_unittest.cc b/webkit/browser/fileapi/sandbox_context_unittest.cc
deleted file mode 100644
index 841e10b..0000000
--- a/webkit/browser/fileapi/sandbox_context_unittest.cc
+++ /dev/null
@@ -1,82 +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 "webkit/browser/fileapi/sandbox_context.h"
-
-#include "base/basictypes.h"
-#include "base/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-#include "webkit/browser/fileapi/file_system_url.h"
-#include "webkit/browser/fileapi/mock_file_system_options.h"
-
-namespace fileapi {
-
-namespace {
-
-FileSystemURL CreateFileSystemURL(const char* path) {
-  const GURL kOrigin("http://foo/");
-  return FileSystemURL::CreateForTest(
-      kOrigin, kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe(path));
-}
-
-}  // namespace
-
-class SandboxContextTest : public testing::Test {
- protected:
-  virtual void SetUp() {
-    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
-    context_.reset(new SandboxContext(
-        NULL /* quota_manager_proxy */,
-        base::MessageLoopProxy::current().get(),
-        data_dir_.path(),
-        NULL /* special_storage_policy */,
-        CreateAllowFileAccessOptions()));
-  }
-
-  base::ScopedTempDir data_dir_;
-  base::MessageLoop message_loop_;
-  scoped_ptr<SandboxContext> context_;
-};
-
-TEST_F(SandboxContextTest, IsAccessValid) {
-  // Normal case.
-  EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL("a")));
-
-  // Access to a path with parent references ('..') should be disallowed.
-  EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL("a/../b")));
-
-  // Access from non-allowed scheme should be disallowed.
-  EXPECT_FALSE(context_->IsAccessValid(
-      FileSystemURL::CreateForTest(
-          GURL("unknown://bar"), kFileSystemTypeTemporary,
-          base::FilePath::FromUTF8Unsafe("foo"))));
-
-  // Access with restricted name should be disallowed.
-  EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL(".")));
-  EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL("..")));
-
-  // This is also disallowed due to Windows XP parent path handling.
-  EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL("...")));
-
-  // These are identified as unsafe cases due to weird path handling
-  // on Windows.
-  EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL(" ..")));
-  EXPECT_FALSE(context_->IsAccessValid(CreateFileSystemURL(".. ")));
-
-  // Similar but safe cases.
-  EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL(" .")));
-  EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL(". ")));
-  EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL("b.")));
-  EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL(".b")));
-
-  // A path that looks like a drive letter.
-  EXPECT_TRUE(context_->IsAccessValid(CreateFileSystemURL("c:")));
-}
-
-}  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_file_system_backend.cc b/webkit/browser/fileapi/sandbox_file_system_backend.cc
index 20f7329..5cf2464 100644
--- a/webkit/browser/fileapi/sandbox_file_system_backend.cc
+++ b/webkit/browser/fileapi/sandbox_file_system_backend.cc
@@ -19,8 +19,8 @@
 #include "webkit/browser/fileapi/file_system_options.h"
 #include "webkit/browser/fileapi/file_system_usage_cache.h"
 #include "webkit/browser/fileapi/obfuscated_file_util.h"
-#include "webkit/browser/fileapi/sandbox_context.h"
 #include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
+#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "webkit/browser/fileapi/sandbox_quota_observer.h"
 #include "webkit/browser/quota/quota_manager.h"
 #include "webkit/common/fileapi/file_system_types.h"
@@ -31,16 +31,9 @@
 
 namespace fileapi {
 
-namespace {
-
-const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount";
-const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount";
-
-}  // anonymous namespace
-
 SandboxFileSystemBackend::SandboxFileSystemBackend(
-    SandboxContext* sandbox_context)
-    : sandbox_context_(sandbox_context),
+    SandboxFileSystemBackendDelegate* delegate)
+    : delegate_(delegate),
       enable_temporary_file_system_in_incognito_(false) {
 }
 
@@ -53,12 +46,24 @@
 }
 
 void SandboxFileSystemBackend::Initialize(FileSystemContext* context) {
+  DCHECK(delegate_);
+
   // Set quota observers.
-  update_observers_ = update_observers_.AddObserver(
-      sandbox_context_->quota_observer(),
-      sandbox_context_->file_task_runner());
-  access_observers_ = access_observers_.AddObserver(
-      sandbox_context_->quota_observer(), NULL);
+  delegate_->AddFileUpdateObserver(
+      fileapi::kFileSystemTypeTemporary,
+      delegate_->quota_observer(),
+      delegate_->file_task_runner());
+  delegate_->AddFileAccessObserver(
+      fileapi::kFileSystemTypeTemporary,
+      delegate_->quota_observer(), NULL);
+
+  delegate_->AddFileUpdateObserver(
+      fileapi::kFileSystemTypePersistent,
+      delegate_->quota_observer(),
+      delegate_->file_task_runner());
+  delegate_->AddFileAccessObserver(
+      fileapi::kFileSystemTypePersistent,
+      delegate_->quota_observer(), NULL);
 }
 
 void SandboxFileSystemBackend::OpenFileSystem(
@@ -67,8 +72,8 @@
     OpenFileSystemMode mode,
     const OpenFileSystemCallback& callback) {
   DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  if (sandbox_context_->file_system_options().is_incognito() &&
+  DCHECK(delegate_);
+  if (delegate_->file_system_options().is_incognito() &&
       !(type == kFileSystemTypeTemporary &&
         enable_temporary_file_system_in_incognito_)) {
     // TODO(kinuko): return an isolated temporary directory.
@@ -76,20 +81,20 @@
     return;
   }
 
-  sandbox_context_->OpenFileSystem(
+  delegate_->OpenFileSystem(
       origin_url, type, mode, callback,
       GetFileSystemRootURI(origin_url, type));
 }
 
 FileSystemFileUtil* SandboxFileSystemBackend::GetFileUtil(
     FileSystemType type) {
-  return sandbox_context_->sync_file_util();
+  return delegate_->sync_file_util();
 }
 
 AsyncFileUtil* SandboxFileSystemBackend::GetAsyncFileUtil(
     FileSystemType type) {
-  DCHECK(sandbox_context_);
-  return sandbox_context_->file_util();
+  DCHECK(delegate_);
+  return delegate_->file_util();
 }
 
 CopyOrMoveFileValidatorFactory*
@@ -106,18 +111,15 @@
     FileSystemContext* context,
     base::PlatformFileError* error_code) const {
   DCHECK(CanHandleType(url.type()));
-  DCHECK(sandbox_context_);
-  if (!sandbox_context_->IsAccessValid(url)) {
-    *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
+  DCHECK(error_code);
+
+  DCHECK(delegate_);
+  scoped_ptr<FileSystemOperationContext> operation_context =
+      delegate_->CreateFileSystemOperationContext(url, context, error_code);
+  if (!operation_context)
     return NULL;
-  }
 
-  scoped_ptr<FileSystemOperationContext> operation_context(
-      new FileSystemOperationContext(context));
-  operation_context->set_update_observers(update_observers_);
-  operation_context->set_change_observers(change_observers_);
-
-  SpecialStoragePolicy* policy = sandbox_context_->special_storage_policy();
+  SpecialStoragePolicy* policy = delegate_->special_storage_policy();
   if (policy && policy->IsStorageUnlimited(url.origin()))
     operation_context->set_quota_limit_type(quota::kQuotaLimitTypeUnlimited);
   else
@@ -133,12 +135,9 @@
     const base::Time& expected_modification_time,
     FileSystemContext* context) const {
   DCHECK(CanHandleType(url.type()));
-  DCHECK(sandbox_context_);
-  if (!sandbox_context_->IsAccessValid(url))
-    return scoped_ptr<webkit_blob::FileStreamReader>();
-  return scoped_ptr<webkit_blob::FileStreamReader>(
-      new FileSystemFileStreamReader(
-          context, url, offset, expected_modification_time));
+  DCHECK(delegate_);
+  return delegate_->CreateFileStreamReader(
+      url, offset, expected_modification_time, context);
 }
 
 scoped_ptr<fileapi::FileStreamWriter>
@@ -147,128 +146,18 @@
     int64 offset,
     FileSystemContext* context) const {
   DCHECK(CanHandleType(url.type()));
-  DCHECK(sandbox_context_);
-  if (!sandbox_context_->IsAccessValid(url))
-    return scoped_ptr<fileapi::FileStreamWriter>();
-  return scoped_ptr<fileapi::FileStreamWriter>(
-      new SandboxFileStreamWriter(context, url, offset, update_observers_));
+  DCHECK(delegate_);
+  return delegate_->CreateFileStreamWriter(url, offset, context, url.type());
 }
 
 FileSystemQuotaUtil* SandboxFileSystemBackend::GetQuotaUtil() {
-  return this;
+  return delegate_;
 }
 
-SandboxContext::OriginEnumerator*
+SandboxFileSystemBackendDelegate::OriginEnumerator*
 SandboxFileSystemBackend::CreateOriginEnumerator() {
-  DCHECK(sandbox_context_);
-  return sandbox_context_->CreateOriginEnumerator();
-}
-
-base::PlatformFileError
-SandboxFileSystemBackend::DeleteOriginDataOnFileThread(
-    FileSystemContext* file_system_context,
-    QuotaManagerProxy* proxy,
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  return sandbox_context_->DeleteOriginDataOnFileThread(
-      file_system_context, proxy, origin_url, type);
-}
-
-void SandboxFileSystemBackend::GetOriginsForTypeOnFileThread(
-    fileapi::FileSystemType type, std::set<GURL>* origins) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->GetOriginsForTypeOnFileThread(type, origins);
-  switch (type) {
-    case kFileSystemTypeTemporary:
-      UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size());
-      break;
-    case kFileSystemTypePersistent:
-      UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size());
-      break;
-    default:
-      break;
-  }
-}
-
-void SandboxFileSystemBackend::GetOriginsForHostOnFileThread(
-    fileapi::FileSystemType type, const std::string& host,
-    std::set<GURL>* origins) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->GetOriginsForHostOnFileThread(type, host, origins);
-}
-
-int64 SandboxFileSystemBackend::GetOriginUsageOnFileThread(
-    FileSystemContext* file_system_context,
-    const GURL& origin_url,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  return sandbox_context_->GetOriginUsageOnFileThread(
-      file_system_context, origin_url, type);
-}
-
-void SandboxFileSystemBackend::InvalidateUsageCache(
-    const GURL& origin,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->InvalidateUsageCache(origin, type);
-}
-
-void SandboxFileSystemBackend::StickyInvalidateUsageCache(
-    const GURL& origin,
-    fileapi::FileSystemType type) {
-  DCHECK(CanHandleType(type));
-  DCHECK(sandbox_context_);
-  sandbox_context_->StickyInvalidateUsageCache(origin, type);
-}
-
-void SandboxFileSystemBackend::AddFileUpdateObserver(
-    FileSystemType type,
-    FileUpdateObserver* observer,
-    base::SequencedTaskRunner* task_runner) {
-  DCHECK(CanHandleType(type));
-  UpdateObserverList* list = &update_observers_;
-  *list = list->AddObserver(observer, task_runner);
-}
-
-void SandboxFileSystemBackend::AddFileChangeObserver(
-    FileSystemType type,
-    FileChangeObserver* observer,
-    base::SequencedTaskRunner* task_runner) {
-  DCHECK(CanHandleType(type));
-  ChangeObserverList* list = &change_observers_;
-  *list = list->AddObserver(observer, task_runner);
-}
-
-void SandboxFileSystemBackend::AddFileAccessObserver(
-    FileSystemType type,
-    FileAccessObserver* observer,
-    base::SequencedTaskRunner* task_runner) {
-  DCHECK(CanHandleType(type));
-  access_observers_ = access_observers_.AddObserver(observer, task_runner);
-}
-
-const UpdateObserverList* SandboxFileSystemBackend::GetUpdateObservers(
-    FileSystemType type) const {
-  DCHECK(CanHandleType(type));
-  return &update_observers_;
-}
-
-const ChangeObserverList* SandboxFileSystemBackend::GetChangeObservers(
-    FileSystemType type) const {
-  DCHECK(CanHandleType(type));
-  return &change_observers_;
-}
-
-const AccessObserverList* SandboxFileSystemBackend::GetAccessObservers(
-    FileSystemType type) const {
-  DCHECK(CanHandleType(type));
-  return &access_observers_;
+  DCHECK(delegate_);
+  return delegate_->CreateOriginEnumerator();
 }
 
 }  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_file_system_backend.h b/webkit/browser/fileapi/sandbox_file_system_backend.h
index 3e7ff60..207600e 100644
--- a/webkit/browser/fileapi/sandbox_file_system_backend.h
+++ b/webkit/browser/fileapi/sandbox_file_system_backend.h
@@ -14,7 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "webkit/browser/fileapi/file_system_backend.h"
 #include "webkit/browser/fileapi/file_system_quota_util.h"
-#include "webkit/browser/fileapi/sandbox_context.h"
+#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "webkit/browser/fileapi/task_runner_bound_observer_list.h"
 #include "webkit/browser/quota/special_storage_policy.h"
 #include "webkit/browser/webkit_storage_browser_export.h"
@@ -27,10 +27,9 @@
 // This interface also lets one enumerate and remove storage for the origins
 // that use the filesystem.
 class WEBKIT_STORAGE_BROWSER_EXPORT SandboxFileSystemBackend
-    : public FileSystemBackend,
-      public FileSystemQuotaUtil {
+    : public FileSystemBackend {
  public:
-  explicit SandboxFileSystemBackend(SandboxContext* sandbox_context);
+  explicit SandboxFileSystemBackend(SandboxFileSystemBackendDelegate* delegate);
   virtual ~SandboxFileSystemBackend();
 
   // FileSystemBackend overrides.
@@ -63,64 +62,17 @@
 
   // Returns an origin enumerator of this backend.
   // This method can only be called on the file thread.
-  SandboxContext::OriginEnumerator* CreateOriginEnumerator();
-
-  // FileSystemQuotaUtil overrides.
-  virtual base::PlatformFileError DeleteOriginDataOnFileThread(
-      FileSystemContext* context,
-      quota::QuotaManagerProxy* proxy,
-      const GURL& origin_url,
-      FileSystemType type) OVERRIDE;
-  virtual void GetOriginsForTypeOnFileThread(
-      FileSystemType type,
-      std::set<GURL>* origins) OVERRIDE;
-  virtual void GetOriginsForHostOnFileThread(
-      FileSystemType type,
-      const std::string& host,
-      std::set<GURL>* origins) OVERRIDE;
-  virtual int64 GetOriginUsageOnFileThread(
-      FileSystemContext* context,
-      const GURL& origin_url,
-      FileSystemType type) OVERRIDE;
-  virtual void InvalidateUsageCache(
-      const GURL& origin_url,
-      FileSystemType type) OVERRIDE;
-  virtual void StickyInvalidateUsageCache(
-      const GURL& origin_url,
-      FileSystemType type) OVERRIDE;
-  virtual void AddFileUpdateObserver(
-      FileSystemType type,
-      FileUpdateObserver* observer,
-      base::SequencedTaskRunner* task_runner) OVERRIDE;
-  virtual void AddFileChangeObserver(
-      FileSystemType type,
-      FileChangeObserver* observer,
-      base::SequencedTaskRunner* task_runner) OVERRIDE;
-  virtual void AddFileAccessObserver(
-      FileSystemType type,
-      FileAccessObserver* observer,
-      base::SequencedTaskRunner* task_runner) OVERRIDE;
-  virtual const UpdateObserverList* GetUpdateObservers(
-      FileSystemType type) const OVERRIDE;
-  virtual const ChangeObserverList* GetChangeObservers(
-      FileSystemType type) const OVERRIDE;
-  virtual const AccessObserverList* GetAccessObservers(
-      FileSystemType type) const OVERRIDE;
+  SandboxFileSystemBackendDelegate::OriginEnumerator* CreateOriginEnumerator();
 
   void set_enable_temporary_file_system_in_incognito(bool enable) {
     enable_temporary_file_system_in_incognito_ = enable;
   }
 
  private:
-  SandboxContext* sandbox_context_;  // Not owned.
+  SandboxFileSystemBackendDelegate* delegate_;  // Not owned.
 
   bool enable_temporary_file_system_in_incognito_;
 
-  // Observers.
-  UpdateObserverList update_observers_;
-  ChangeObserverList change_observers_;
-  AccessObserverList access_observers_;
-
   DISALLOW_COPY_AND_ASSIGN(SandboxFileSystemBackend);
 };
 
diff --git a/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc b/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc
new file mode 100644
index 0000000..c1c8c88
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc
@@ -0,0 +1,564 @@
+// Copyright 2013 The Chromium Authors. 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_file_system_backend_delegate.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/metrics/histogram.h"
+#include "base/stl_util.h"
+#include "base/task_runner_util.h"
+#include "net/base/net_util.h"
+#include "webkit/browser/fileapi/async_file_util_adapter.h"
+#include "webkit/browser/fileapi/file_system_context.h"
+#include "webkit/browser/fileapi/file_system_file_stream_reader.h"
+#include "webkit/browser/fileapi/file_system_operation_context.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/file_system_usage_cache.h"
+#include "webkit/browser/fileapi/obfuscated_file_util.h"
+#include "webkit/browser/fileapi/sandbox_file_stream_writer.h"
+#include "webkit/browser/fileapi/sandbox_file_system_backend.h"
+#include "webkit/browser/fileapi/sandbox_quota_observer.h"
+#include "webkit/browser/quota/quota_manager.h"
+#include "webkit/common/fileapi/file_system_util.h"
+
+namespace fileapi {
+
+namespace {
+
+const char kTemporaryOriginsCountLabel[] = "FileSystem.TemporaryOriginsCount";
+const char kPersistentOriginsCountLabel[] = "FileSystem.PersistentOriginsCount";
+
+const char kOpenFileSystemLabel[] = "FileSystem.OpenFileSystem";
+const char kOpenFileSystemDetailLabel[] = "FileSystem.OpenFileSystemDetail";
+const char kOpenFileSystemDetailNonThrottledLabel[] =
+    "FileSystem.OpenFileSystemDetailNonthrottled";
+int64 kMinimumStatsCollectionIntervalHours = 1;
+
+enum FileSystemError {
+  kOK = 0,
+  kIncognito,
+  kInvalidSchemeError,
+  kCreateDirectoryError,
+  kNotFound,
+  kUnknownError,
+  kFileSystemErrorMax,
+};
+
+// Restricted names.
+// http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
+const base::FilePath::CharType* const kRestrictedNames[] = {
+  FILE_PATH_LITERAL("."), FILE_PATH_LITERAL(".."),
+};
+
+// Restricted chars.
+const base::FilePath::CharType kRestrictedChars[] = {
+  FILE_PATH_LITERAL('/'), FILE_PATH_LITERAL('\\'),
+};
+
+class ObfuscatedOriginEnumerator
+    : public SandboxFileSystemBackendDelegate::OriginEnumerator {
+ public:
+  explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) {
+    enum_.reset(file_util->CreateOriginEnumerator());
+  }
+  virtual ~ObfuscatedOriginEnumerator() {}
+
+  virtual GURL Next() OVERRIDE {
+    return enum_->Next();
+  }
+
+  virtual bool HasFileSystemType(FileSystemType type) const OVERRIDE {
+    return enum_->HasFileSystemType(type);
+  }
+
+ private:
+  scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_;
+};
+
+void OpenFileSystemOnFileThread(
+    ObfuscatedFileUtil* file_util,
+    const GURL& origin_url,
+    FileSystemType type,
+    OpenFileSystemMode mode,
+    base::PlatformFileError* error_ptr) {
+  DCHECK(error_ptr);
+  const bool create = (mode == OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT);
+  file_util->GetDirectoryForOriginAndType(origin_url, type, create, error_ptr);
+  if (*error_ptr != base::PLATFORM_FILE_OK) {
+    UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel,
+                              kCreateDirectoryError,
+                              kFileSystemErrorMax);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemLabel, kOK, kFileSystemErrorMax);
+  }
+  // The reference of file_util will be derefed on the FILE thread
+  // when the storage of this callback gets deleted regardless of whether
+  // this method is called or not.
+}
+
+void DidOpenFileSystem(
+    base::WeakPtr<SandboxFileSystemBackendDelegate> delegate,
+    const base::Callback<void(base::PlatformFileError error)>& callback,
+    base::PlatformFileError* error) {
+  if (delegate.get())
+    delegate.get()->CollectOpenFileSystemMetrics(*error);
+  callback.Run(*error);
+}
+
+}  // namespace
+
+const base::FilePath::CharType
+SandboxFileSystemBackendDelegate::kFileSystemDirectory[] =
+    FILE_PATH_LITERAL("File System");
+
+SandboxFileSystemBackendDelegate::SandboxFileSystemBackendDelegate(
+    quota::QuotaManagerProxy* quota_manager_proxy,
+    base::SequencedTaskRunner* file_task_runner,
+    const base::FilePath& profile_path,
+    quota::SpecialStoragePolicy* special_storage_policy,
+    const FileSystemOptions& file_system_options)
+    : file_task_runner_(file_task_runner),
+      sandbox_file_util_(new AsyncFileUtilAdapter(
+          new ObfuscatedFileUtil(
+              special_storage_policy,
+              profile_path.Append(kFileSystemDirectory),
+              file_task_runner))),
+      file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)),
+      quota_observer_(new SandboxQuotaObserver(
+          quota_manager_proxy,
+          file_task_runner,
+          obfuscated_file_util(),
+          usage_cache())),
+      special_storage_policy_(special_storage_policy),
+      file_system_options_(file_system_options),
+      is_filesystem_opened_(false),
+      weak_factory_(this) {
+}
+
+SandboxFileSystemBackendDelegate::~SandboxFileSystemBackendDelegate() {
+  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;
+  }
+}
+
+bool SandboxFileSystemBackendDelegate::IsAccessValid(
+    const FileSystemURL& url) const {
+  if (!IsAllowedScheme(url.origin()))
+    return false;
+
+  if (url.path().ReferencesParent())
+    return false;
+
+  // Return earlier if the path is '/', because VirtualPath::BaseName()
+  // returns '/' for '/' and we fail the "basename != '/'" check below.
+  // (We exclude '.' because it's disallowed by spec.)
+  if (VirtualPath::IsRootPath(url.path()) &&
+      url.path() != base::FilePath(base::FilePath::kCurrentDirectory))
+    return true;
+
+  // Restricted names specified in
+  // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
+  base::FilePath filename = VirtualPath::BaseName(url.path());
+  // See if the name is allowed to create.
+  for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
+    if (filename.value() == kRestrictedNames[i])
+      return false;
+  }
+  for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
+    if (filename.value().find(kRestrictedChars[i]) !=
+        base::FilePath::StringType::npos)
+      return false;
+  }
+
+  return true;
+}
+
+bool SandboxFileSystemBackendDelegate::IsAllowedScheme(const GURL& url) const {
+  // Basically we only accept http or https. We allow file:// URLs
+  // only if --allow-file-access-from-files flag is given.
+  if (url.SchemeIsHTTPOrHTTPS())
+    return true;
+  if (url.SchemeIsFileSystem())
+    return url.inner_url() && IsAllowedScheme(*url.inner_url());
+
+  for (size_t i = 0;
+       i < file_system_options_.additional_allowed_schemes().size();
+       ++i) {
+    if (url.SchemeIs(
+            file_system_options_.additional_allowed_schemes()[i].c_str()))
+      return true;
+  }
+  return false;
+}
+
+SandboxFileSystemBackendDelegate::OriginEnumerator*
+SandboxFileSystemBackendDelegate::CreateOriginEnumerator() {
+  return new ObfuscatedOriginEnumerator(obfuscated_file_util());
+}
+
+base::FilePath
+SandboxFileSystemBackendDelegate::GetBaseDirectoryForOriginAndType(
+    const GURL& origin_url,
+    FileSystemType type,
+    bool create) {
+  base::PlatformFileError error = base::PLATFORM_FILE_OK;
+  base::FilePath path = obfuscated_file_util()->GetDirectoryForOriginAndType(
+      origin_url, type, create, &error);
+  if (error != base::PLATFORM_FILE_OK)
+    return base::FilePath();
+  return path;
+}
+
+void SandboxFileSystemBackendDelegate::OpenFileSystem(
+    const GURL& origin_url,
+    FileSystemType type,
+    OpenFileSystemMode mode,
+    const OpenFileSystemCallback& callback,
+    const GURL& root_url) {
+  if (!IsAllowedScheme(origin_url)) {
+    callback.Run(GURL(), std::string(), base::PLATFORM_FILE_ERROR_SECURITY);
+    return;
+  }
+
+  std::string name = GetFileSystemName(origin_url, type);
+
+  base::PlatformFileError* error_ptr = new base::PlatformFileError;
+  file_task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&OpenFileSystemOnFileThread,
+                 obfuscated_file_util(), origin_url, type, mode,
+                 base::Unretained(error_ptr)),
+      base::Bind(&DidOpenFileSystem,
+                 weak_factory_.GetWeakPtr(),
+                 base::Bind(callback, root_url, name),
+                 base::Owned(error_ptr)));
+
+  is_filesystem_opened_ = true;
+}
+
+scoped_ptr<FileSystemOperationContext>
+SandboxFileSystemBackendDelegate::CreateFileSystemOperationContext(
+    const FileSystemURL& url,
+    FileSystemContext* context,
+    base::PlatformFileError* error_code) const {
+  if (!IsAccessValid(url)) {
+    *error_code = base::PLATFORM_FILE_ERROR_SECURITY;
+    return scoped_ptr<FileSystemOperationContext>();
+  }
+
+  const UpdateObserverList* update_observers = GetUpdateObservers(url.type());
+  const ChangeObserverList* change_observers = GetChangeObservers(url.type());
+  DCHECK(update_observers);
+
+  scoped_ptr<FileSystemOperationContext> operation_context(
+      new FileSystemOperationContext(context));
+  operation_context->set_update_observers(*update_observers);
+  operation_context->set_change_observers(
+      change_observers ? *change_observers : ChangeObserverList());
+
+  return operation_context.Pass();
+}
+
+scoped_ptr<webkit_blob::FileStreamReader>
+SandboxFileSystemBackendDelegate::CreateFileStreamReader(
+    const FileSystemURL& url,
+    int64 offset,
+    const base::Time& expected_modification_time,
+    FileSystemContext* context) const {
+  if (!IsAccessValid(url))
+    return scoped_ptr<webkit_blob::FileStreamReader>();
+  return scoped_ptr<webkit_blob::FileStreamReader>(
+      new FileSystemFileStreamReader(
+          context, url, offset, expected_modification_time));
+}
+
+scoped_ptr<FileStreamWriter>
+SandboxFileSystemBackendDelegate::CreateFileStreamWriter(
+    const FileSystemURL& url,
+    int64 offset,
+    FileSystemContext* context,
+    FileSystemType type) const {
+  if (!IsAccessValid(url))
+    return scoped_ptr<FileStreamWriter>();
+  const UpdateObserverList* observers = GetUpdateObservers(type);
+  DCHECK(observers);
+  return scoped_ptr<FileStreamWriter>(
+      new SandboxFileStreamWriter(context, url, offset, *observers));
+}
+
+base::PlatformFileError
+SandboxFileSystemBackendDelegate::DeleteOriginDataOnFileThread(
+    FileSystemContext* file_system_context,
+    quota::QuotaManagerProxy* proxy,
+    const GURL& origin_url,
+    FileSystemType type) {
+  int64 usage = GetOriginUsageOnFileThread(
+      file_system_context, origin_url, type);
+  usage_cache()->CloseCacheFiles();
+  bool result = obfuscated_file_util()->DeleteDirectoryForOriginAndType(
+      origin_url, type);
+  if (result && proxy) {
+    proxy->NotifyStorageModified(
+        quota::QuotaClient::kFileSystem,
+        origin_url,
+        FileSystemTypeToQuotaStorageType(type),
+        -usage);
+  }
+
+  if (result)
+    return base::PLATFORM_FILE_OK;
+  return base::PLATFORM_FILE_ERROR_FAILED;
+}
+
+void SandboxFileSystemBackendDelegate::GetOriginsForTypeOnFileThread(
+    FileSystemType type, std::set<GURL>* origins) {
+  DCHECK(origins);
+  scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
+  GURL origin;
+  while (!(origin = enumerator->Next()).is_empty()) {
+    if (enumerator->HasFileSystemType(type))
+      origins->insert(origin);
+  }
+  switch (type) {
+    case kFileSystemTypeTemporary:
+      UMA_HISTOGRAM_COUNTS(kTemporaryOriginsCountLabel, origins->size());
+      break;
+    case kFileSystemTypePersistent:
+      UMA_HISTOGRAM_COUNTS(kPersistentOriginsCountLabel, origins->size());
+      break;
+    default:
+      break;
+  }
+}
+
+void SandboxFileSystemBackendDelegate::GetOriginsForHostOnFileThread(
+    FileSystemType type, const std::string& host,
+    std::set<GURL>* origins) {
+  DCHECK(origins);
+  scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator());
+  GURL origin;
+  while (!(origin = enumerator->Next()).is_empty()) {
+    if (host == net::GetHostOrSpecFromURL(origin) &&
+        enumerator->HasFileSystemType(type))
+      origins->insert(origin);
+  }
+}
+
+int64 SandboxFileSystemBackendDelegate::GetOriginUsageOnFileThread(
+    FileSystemContext* file_system_context,
+    const GURL& origin_url,
+    FileSystemType type) {
+  // Don't use usage cache and return recalculated usage for sticky invalidated
+  // origins.
+  if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type)))
+    return RecalculateUsage(file_system_context, origin_url, type);
+
+  base::FilePath base_path =
+      GetBaseDirectoryForOriginAndType(origin_url, type, false);
+  if (base_path.empty() || !base::DirectoryExists(base_path))
+    return 0;
+  base::FilePath usage_file_path =
+      base_path.Append(FileSystemUsageCache::kUsageFileName);
+
+  bool is_valid = usage_cache()->IsValid(usage_file_path);
+  uint32 dirty_status = 0;
+  bool dirty_status_available =
+      usage_cache()->GetDirty(usage_file_path, &dirty_status);
+  bool visited = !visited_origins_.insert(origin_url).second;
+  if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) {
+    // The usage cache is clean (dirty == 0) or the origin is already
+    // initialized and running.  Read the cache file to get the usage.
+    int64 usage = 0;
+    return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1;
+  }
+  // The usage cache has not been initialized or the cache is dirty.
+  // Get the directory size now and update the cache.
+  usage_cache()->Delete(usage_file_path);
+
+  int64 usage = RecalculateUsage(file_system_context, origin_url, type);
+
+  // This clears the dirty flag too.
+  usage_cache()->UpdateUsage(usage_file_path, usage);
+  return usage;
+}
+
+void SandboxFileSystemBackendDelegate::AddFileUpdateObserver(
+    FileSystemType type,
+    FileUpdateObserver* observer,
+    base::SequencedTaskRunner* task_runner) {
+  DCHECK(!is_filesystem_opened_);
+  update_observers_[type] =
+      update_observers_[type].AddObserver(observer, task_runner);
+}
+
+void SandboxFileSystemBackendDelegate::AddFileChangeObserver(
+    FileSystemType type,
+    FileChangeObserver* observer,
+    base::SequencedTaskRunner* task_runner) {
+  DCHECK(!is_filesystem_opened_);
+  change_observers_[type] =
+      change_observers_[type].AddObserver(observer, task_runner);
+}
+
+void SandboxFileSystemBackendDelegate::AddFileAccessObserver(
+    FileSystemType type,
+    FileAccessObserver* observer,
+    base::SequencedTaskRunner* task_runner) {
+  DCHECK(!is_filesystem_opened_);
+  access_observers_[type] =
+      access_observers_[type].AddObserver(observer, task_runner);
+}
+
+const UpdateObserverList* SandboxFileSystemBackendDelegate::GetUpdateObservers(
+    FileSystemType type) const {
+  std::map<FileSystemType, UpdateObserverList>::const_iterator iter =
+      update_observers_.find(type);
+  if (iter == update_observers_.end())
+    return NULL;
+  return &iter->second;
+}
+
+const ChangeObserverList* SandboxFileSystemBackendDelegate::GetChangeObservers(
+    FileSystemType type) const {
+  std::map<FileSystemType, ChangeObserverList>::const_iterator iter =
+      change_observers_.find(type);
+  if (iter == change_observers_.end())
+    return NULL;
+  return &iter->second;
+}
+
+const AccessObserverList* SandboxFileSystemBackendDelegate::GetAccessObservers(
+    FileSystemType type) const {
+  std::map<FileSystemType, AccessObserverList>::const_iterator iter =
+      access_observers_.find(type);
+  if (iter == access_observers_.end())
+    return NULL;
+  return &iter->second;
+}
+
+void SandboxFileSystemBackendDelegate::InvalidateUsageCache(
+    const GURL& origin,
+    FileSystemType type) {
+  base::PlatformFileError error = base::PLATFORM_FILE_OK;
+  base::FilePath usage_file_path = GetUsageCachePathForOriginAndType(
+      obfuscated_file_util(), origin, type, &error);
+  if (error != base::PLATFORM_FILE_OK)
+    return;
+  usage_cache()->IncrementDirty(usage_file_path);
+}
+
+void SandboxFileSystemBackendDelegate::StickyInvalidateUsageCache(
+    const GURL& origin,
+    FileSystemType type) {
+  sticky_dirty_origins_.insert(std::make_pair(origin, type));
+  quota_observer()->SetUsageCacheEnabled(origin, type, false);
+  InvalidateUsageCache(origin, type);
+}
+
+FileSystemFileUtil* SandboxFileSystemBackendDelegate::sync_file_util() {
+  return static_cast<AsyncFileUtilAdapter*>(file_util())->sync_file_util();
+}
+
+base::FilePath
+SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
+    const GURL& origin_url,
+    FileSystemType type) {
+  base::PlatformFileError error;
+  base::FilePath path = GetUsageCachePathForOriginAndType(
+      obfuscated_file_util(), origin_url, type, &error);
+  if (error != base::PLATFORM_FILE_OK)
+    return base::FilePath();
+  return path;
+}
+
+// static
+base::FilePath
+SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
+    ObfuscatedFileUtil* sandbox_file_util,
+    const GURL& origin_url,
+    FileSystemType type,
+    base::PlatformFileError* error_out) {
+  DCHECK(error_out);
+  *error_out = base::PLATFORM_FILE_OK;
+  base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType(
+      origin_url, type, false /* create */, error_out);
+  if (*error_out != base::PLATFORM_FILE_OK)
+    return base::FilePath();
+  return base_path.Append(FileSystemUsageCache::kUsageFileName);
+}
+
+int64 SandboxFileSystemBackendDelegate::RecalculateUsage(
+    FileSystemContext* context,
+    const GURL& origin,
+    FileSystemType type) {
+  FileSystemOperationContext operation_context(context);
+  FileSystemURL url = context->CreateCrackedFileSystemURL(
+      origin, type, base::FilePath());
+  scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator(
+      obfuscated_file_util()->CreateFileEnumerator(
+          &operation_context, url, true));
+
+  base::FilePath file_path_each;
+  int64 usage = 0;
+
+  while (!(file_path_each = enumerator->Next()).empty()) {
+    usage += enumerator->Size();
+    usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each);
+  }
+
+  return usage;
+}
+
+void SandboxFileSystemBackendDelegate::CollectOpenFileSystemMetrics(
+    base::PlatformFileError error_code) {
+  base::Time now = base::Time::Now();
+  bool throttled = now < next_release_time_for_open_filesystem_stat_;
+  if (!throttled) {
+    next_release_time_for_open_filesystem_stat_ =
+        now + base::TimeDelta::FromHours(kMinimumStatsCollectionIntervalHours);
+  }
+
+#define REPORT(report_value)                                            \
+  UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailLabel,                 \
+                            (report_value),                             \
+                            kFileSystemErrorMax);                       \
+  if (!throttled) {                                                     \
+    UMA_HISTOGRAM_ENUMERATION(kOpenFileSystemDetailNonThrottledLabel,   \
+                              (report_value),                           \
+                              kFileSystemErrorMax);                     \
+  }
+
+  switch (error_code) {
+    case base::PLATFORM_FILE_OK:
+      REPORT(kOK);
+      break;
+    case base::PLATFORM_FILE_ERROR_INVALID_URL:
+      REPORT(kInvalidSchemeError);
+      break;
+    case base::PLATFORM_FILE_ERROR_NOT_FOUND:
+      REPORT(kNotFound);
+      break;
+    case base::PLATFORM_FILE_ERROR_FAILED:
+    default:
+      REPORT(kUnknownError);
+      break;
+  }
+#undef REPORT
+}
+
+ObfuscatedFileUtil* SandboxFileSystemBackendDelegate::obfuscated_file_util() {
+  return static_cast<ObfuscatedFileUtil*>(sync_file_util());
+}
+
+}  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_file_system_backend_delegate.h b/webkit/browser/fileapi/sandbox_file_system_backend_delegate.h
new file mode 100644
index 0000000..61fe700
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_file_system_backend_delegate.h
@@ -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.
+
+#ifndef WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_BACKEND_DELEGATE_H_
+#define WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_BACKEND_DELEGATE_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "webkit/browser/fileapi/file_system_backend.h"
+#include "webkit/browser/fileapi/file_system_options.h"
+#include "webkit/browser/fileapi/file_system_quota_util.h"
+#include "webkit/browser/webkit_storage_browser_export.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace quota {
+class QuotaManagerProxy;
+class SpecialStoragePolicy;
+}
+
+namespace webkit_blob {
+class FileStreamReader;
+}
+
+namespace fileapi {
+
+class AsyncFileUtil;
+class FileStreamWriter;
+class FileSystemFileUtil;
+class FileSystemOperationContext;
+class FileSystemURL;
+class FileSystemUsageCache;
+class ObfuscatedFileUtil;
+class SandboxFileSystemBackend;
+class SandboxFileSystemTestHelper;
+class SandboxQuotaObserver;
+
+// Delegate implementation of the some methods in Sandbox/SyncFileSystemBackend.
+// An instance of this class is created and owned by FileSystemContext.
+class WEBKIT_STORAGE_BROWSER_EXPORT SandboxFileSystemBackendDelegate
+    : public FileSystemQuotaUtil {
+ public:
+  typedef FileSystemBackend::OpenFileSystemCallback OpenFileSystemCallback;
+
+  // The FileSystem directory name.
+  static const base::FilePath::CharType kFileSystemDirectory[];
+
+  // Origin enumerator interface.
+  // An instance of this interface is assumed to be called on the file thread.
+  class OriginEnumerator {
+   public:
+    virtual ~OriginEnumerator() {}
+
+    // Returns the next origin.  Returns empty if there are no more origins.
+    virtual GURL Next() = 0;
+
+    // Returns the current origin's information.
+    virtual bool HasFileSystemType(FileSystemType type) const = 0;
+  };
+
+  SandboxFileSystemBackendDelegate(
+      quota::QuotaManagerProxy* quota_manager_proxy,
+      base::SequencedTaskRunner* file_task_runner,
+      const base::FilePath& profile_path,
+      quota::SpecialStoragePolicy* special_storage_policy,
+      const FileSystemOptions& file_system_options);
+
+  virtual ~SandboxFileSystemBackendDelegate();
+
+  // Performs API-specific validity checks on the given path |url|.
+  // Returns true if access to |url| is valid in this filesystem.
+  bool IsAccessValid(const FileSystemURL& url) const;
+
+  // Returns true if the given |url|'s scheme is allowed to access
+  // filesystem.
+  bool IsAllowedScheme(const GURL& url) const;
+
+  // Returns an origin enumerator of sandbox filesystem.
+  // This method can only be called on the file thread.
+  OriginEnumerator* CreateOriginEnumerator();
+
+  // Gets a base directory path of the sandboxed filesystem that is
+  // specified by |origin_url| and |type|.
+  // (The path is similar to the origin's root path but doesn't contain
+  // the 'unique' part.)
+  // Returns an empty path if the given type is invalid.
+  // This method can only be called on the file thread.
+  base::FilePath GetBaseDirectoryForOriginAndType(
+      const GURL& origin_url,
+      FileSystemType type,
+      bool create);
+
+  // FileSystemBackend helpers.
+  void OpenFileSystem(
+      const GURL& origin_url,
+      FileSystemType type,
+      OpenFileSystemMode mode,
+      const OpenFileSystemCallback& callback,
+      const GURL& root_url);
+  scoped_ptr<FileSystemOperationContext> CreateFileSystemOperationContext(
+      const FileSystemURL& url,
+      FileSystemContext* context,
+      base::PlatformFileError* error_code) const;
+  scoped_ptr<webkit_blob::FileStreamReader> CreateFileStreamReader(
+      const FileSystemURL& url,
+      int64 offset,
+      const base::Time& expected_modification_time,
+      FileSystemContext* context) const;
+  scoped_ptr<FileStreamWriter> CreateFileStreamWriter(
+      const FileSystemURL& url,
+      int64 offset,
+      FileSystemContext* context,
+      FileSystemType type) const;
+
+  // FileSystemQuotaUtil overrides.
+  virtual base::PlatformFileError DeleteOriginDataOnFileThread(
+      FileSystemContext* context,
+      quota::QuotaManagerProxy* proxy,
+      const GURL& origin_url,
+      FileSystemType type) OVERRIDE;
+  virtual void GetOriginsForTypeOnFileThread(
+      FileSystemType type,
+      std::set<GURL>* origins) OVERRIDE;
+  virtual void GetOriginsForHostOnFileThread(
+      FileSystemType type,
+      const std::string& host,
+      std::set<GURL>* origins) OVERRIDE;
+  virtual int64 GetOriginUsageOnFileThread(
+      FileSystemContext* context,
+      const GURL& origin_url,
+      FileSystemType type) OVERRIDE;
+  virtual void AddFileUpdateObserver(
+      FileSystemType type,
+      FileUpdateObserver* observer,
+      base::SequencedTaskRunner* task_runner) OVERRIDE;
+  virtual void AddFileChangeObserver(
+      FileSystemType type,
+      FileChangeObserver* observer,
+      base::SequencedTaskRunner* task_runner) OVERRIDE;
+  virtual void AddFileAccessObserver(
+      FileSystemType type,
+      FileAccessObserver* observer,
+      base::SequencedTaskRunner* task_runner) OVERRIDE;
+  virtual const UpdateObserverList* GetUpdateObservers(
+      FileSystemType type) const OVERRIDE;
+  virtual const ChangeObserverList* GetChangeObservers(
+      FileSystemType type) const OVERRIDE;
+  virtual const AccessObserverList* GetAccessObservers(
+      FileSystemType type) const OVERRIDE;
+
+  void InvalidateUsageCache(const GURL& origin_url,
+                            FileSystemType type);
+  void StickyInvalidateUsageCache(const GURL& origin_url,
+                                  FileSystemType type);
+
+  void CollectOpenFileSystemMetrics(base::PlatformFileError error_code);
+
+  base::SequencedTaskRunner* file_task_runner() {
+    return file_task_runner_.get();
+  }
+
+  AsyncFileUtil* file_util() { return sandbox_file_util_.get(); }
+  FileSystemUsageCache* usage_cache() { return file_system_usage_cache_.get(); }
+  SandboxQuotaObserver* quota_observer() { return quota_observer_.get(); }
+
+  quota::SpecialStoragePolicy* special_storage_policy() {
+    return special_storage_policy_.get();
+  }
+
+  const FileSystemOptions& file_system_options() const {
+    return file_system_options_;
+  }
+
+  FileSystemFileUtil* sync_file_util();
+
+ private:
+  friend class SandboxQuotaObserver;
+  friend class SandboxFileSystemTestHelper;
+
+  // Returns a path to the usage cache file.
+  base::FilePath GetUsageCachePathForOriginAndType(
+      const GURL& origin_url,
+      FileSystemType type);
+
+  // Returns a path to the usage cache file (static version).
+  static base::FilePath GetUsageCachePathForOriginAndType(
+      ObfuscatedFileUtil* sandbox_file_util,
+      const GURL& origin_url,
+      FileSystemType type,
+      base::PlatformFileError* error_out);
+
+  int64 RecalculateUsage(FileSystemContext* context,
+                         const GURL& origin,
+                         FileSystemType type);
+
+  ObfuscatedFileUtil* obfuscated_file_util();
+
+  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+
+  scoped_ptr<AsyncFileUtil> sandbox_file_util_;
+  scoped_ptr<FileSystemUsageCache> file_system_usage_cache_;
+  scoped_ptr<SandboxQuotaObserver> quota_observer_;
+
+  scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+
+  FileSystemOptions file_system_options_;
+
+  bool is_filesystem_opened_;
+
+  // Accessed only on the file thread.
+  std::set<GURL> visited_origins_;
+
+  std::set<std::pair<GURL, FileSystemType> > sticky_dirty_origins_;
+
+  std::map<FileSystemType, UpdateObserverList> update_observers_;
+  std::map<FileSystemType, ChangeObserverList> change_observers_;
+  std::map<FileSystemType, AccessObserverList> access_observers_;
+
+  base::Time next_release_time_for_open_filesystem_stat_;
+
+  base::WeakPtrFactory<SandboxFileSystemBackendDelegate> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(SandboxFileSystemBackendDelegate);
+};
+
+}  // namespace fileapi
+
+#endif  // WEBKIT_BROWSER_FILEAPI_SANDBOX_FILE_SYSTEM_BACKEND_DELEGATE_H_
diff --git a/webkit/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc b/webkit/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
new file mode 100644
index 0000000..48c3b8c
--- /dev/null
+++ b/webkit/browser/fileapi/sandbox_file_system_backend_delegate_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 "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "webkit/browser/fileapi/file_system_url.h"
+#include "webkit/browser/fileapi/mock_file_system_options.h"
+
+namespace fileapi {
+
+namespace {
+
+FileSystemURL CreateFileSystemURL(const char* path) {
+  const GURL kOrigin("http://foo/");
+  return FileSystemURL::CreateForTest(
+      kOrigin, kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe(path));
+}
+
+}  // namespace
+
+class SandboxFileSystemBackendDelegateTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
+    delegate_.reset(new SandboxFileSystemBackendDelegate(
+        NULL /* quota_manager_proxy */,
+        base::MessageLoopProxy::current().get(),
+        data_dir_.path(),
+        NULL /* special_storage_policy */,
+        CreateAllowFileAccessOptions()));
+  }
+
+  base::ScopedTempDir data_dir_;
+  base::MessageLoop message_loop_;
+  scoped_ptr<SandboxFileSystemBackendDelegate> delegate_;
+};
+
+TEST_F(SandboxFileSystemBackendDelegateTest, IsAccessValid) {
+  // Normal case.
+  EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL("a")));
+
+  // Access to a path with parent references ('..') should be disallowed.
+  EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL("a/../b")));
+
+  // Access from non-allowed scheme should be disallowed.
+  EXPECT_FALSE(delegate_->IsAccessValid(
+      FileSystemURL::CreateForTest(
+          GURL("unknown://bar"), kFileSystemTypeTemporary,
+          base::FilePath::FromUTF8Unsafe("foo"))));
+
+  // Access with restricted name should be disallowed.
+  EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL(".")));
+  EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL("..")));
+
+  // This is also disallowed due to Windows XP parent path handling.
+  EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL("...")));
+
+  // These are identified as unsafe cases due to weird path handling
+  // on Windows.
+  EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL(" ..")));
+  EXPECT_FALSE(delegate_->IsAccessValid(CreateFileSystemURL(".. ")));
+
+  // Similar but safe cases.
+  EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL(" .")));
+  EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL(". ")));
+  EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL("b.")));
+  EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL(".b")));
+
+  // A path that looks like a drive letter.
+  EXPECT_TRUE(delegate_->IsAccessValid(CreateFileSystemURL("c:")));
+}
+
+}  // namespace fileapi
diff --git a/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc b/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc
index ec213a3..c7f0317 100644
--- a/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc
+++ b/webkit/browser/fileapi/sandbox_file_system_backend_unittest.cc
@@ -17,7 +17,7 @@
 #include "webkit/browser/fileapi/file_system_backend.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/mock_file_system_options.h"
-#include "webkit/browser/fileapi/sandbox_context.h"
+#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "webkit/common/fileapi/file_system_util.h"
 
 // PS stands for path separator.
@@ -85,11 +85,11 @@
  protected:
   virtual void SetUp() {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
-    SetUpNewSandboxContext(CreateAllowFileAccessOptions());
+    SetUpNewDelegate(CreateAllowFileAccessOptions());
   }
 
-  void SetUpNewSandboxContext(const FileSystemOptions& options) {
-    context_.reset(new SandboxContext(
+  void SetUpNewDelegate(const FileSystemOptions& options) {
+    delegate_.reset(new SandboxFileSystemBackendDelegate(
         NULL /* quota_manager_proxy */,
         base::MessageLoopProxy::current().get(),
         data_dir_.path(),
@@ -98,17 +98,18 @@
   }
 
   void SetUpNewBackend(const FileSystemOptions& options) {
-    SetUpNewSandboxContext(options);
-    backend_.reset(new SandboxFileSystemBackend(context_.get()));
+    SetUpNewDelegate(options);
+    backend_.reset(new SandboxFileSystemBackend(delegate_.get()));
   }
 
-  SandboxContext::OriginEnumerator* CreateOriginEnumerator() const {
+  SandboxFileSystemBackendDelegate::OriginEnumerator*
+  CreateOriginEnumerator() const {
     return backend_->CreateOriginEnumerator();
   }
 
   void CreateOriginTypeDirectory(const GURL& origin,
                                  fileapi::FileSystemType type) {
-    base::FilePath target = context_->
+    base::FilePath target = delegate_->
         GetBaseDirectoryForOriginAndType(origin, type, true);
     ASSERT_TRUE(!target.empty());
     ASSERT_TRUE(base::DirectoryExists(target));
@@ -126,7 +127,7 @@
     if (error != base::PLATFORM_FILE_OK)
       return false;
     base::FilePath returned_root_path =
-        context_->GetBaseDirectoryForOriginAndType(
+        delegate_->GetBaseDirectoryForOriginAndType(
             origin_url, type, false /* create */);
     if (root_path)
       *root_path = returned_root_path;
@@ -134,18 +135,19 @@
   }
 
   base::FilePath file_system_path() const {
-    return data_dir_.path().Append(SandboxContext::kFileSystemDirectory);
+    return data_dir_.path().Append(
+        SandboxFileSystemBackendDelegate::kFileSystemDirectory);
   }
 
   base::ScopedTempDir data_dir_;
   base::MessageLoop message_loop_;
-  scoped_ptr<SandboxContext> context_;
+  scoped_ptr<SandboxFileSystemBackendDelegate> delegate_;
   scoped_ptr<SandboxFileSystemBackend> backend_;
 };
 
 TEST_F(SandboxFileSystemBackendTest, Empty) {
   SetUpNewBackend(CreateAllowFileAccessOptions());
-  scoped_ptr<SandboxContext::OriginEnumerator> enumerator(
+  scoped_ptr<SandboxFileSystemBackendDelegate::OriginEnumerator> enumerator(
       CreateOriginEnumerator());
   ASSERT_TRUE(enumerator->Next().is_empty());
 }
@@ -178,7 +180,7 @@
     persistent_set.insert(GURL(persistent_origins[i]));
   }
 
-  scoped_ptr<SandboxContext::OriginEnumerator> enumerator(
+  scoped_ptr<SandboxFileSystemBackendDelegate::OriginEnumerator> enumerator(
       CreateOriginEnumerator());
   size_t temporary_actual_size = 0;
   size_t persistent_actual_size = 0;
diff --git a/webkit/browser/fileapi/sandbox_file_system_test_helper.cc b/webkit/browser/fileapi/sandbox_file_system_test_helper.cc
index 179bf9b..75c29e2 100644
--- a/webkit/browser/fileapi/sandbox_file_system_test_helper.cc
+++ b/webkit/browser/fileapi/sandbox_file_system_test_helper.cc
@@ -61,7 +61,7 @@
 }
 
 base::FilePath SandboxFileSystemTestHelper::GetOriginRootPath() {
-  return file_system_context_->sandbox_context()->
+  return file_system_context_->sandbox_delegate()->
       GetBaseDirectoryForOriginAndType(origin_, type_, false);
 }
 
@@ -80,8 +80,8 @@
 }
 
 base::FilePath SandboxFileSystemTestHelper::GetUsageCachePath() const {
-  return file_system_context_->
-      sandbox_context()->GetUsageCachePathForOriginAndType(origin_, type_);
+  return file_system_context_->sandbox_delegate()->
+      GetUsageCachePathForOriginAndType(origin_, type_);
 }
 
 FileSystemURL SandboxFileSystemTestHelper::CreateURL(
@@ -124,12 +124,12 @@
 
 void SandboxFileSystemTestHelper::AddFileChangeObserver(
     FileChangeObserver* observer) {
-  file_system_context_->sandbox_backend()->
+  file_system_context_->sandbox_backend()->GetQuotaUtil()->
       AddFileChangeObserver(type_, observer, NULL);
 }
 
 FileSystemUsageCache* SandboxFileSystemTestHelper::usage_cache() {
-  return file_system_context()->sandbox_context()->usage_cache();
+  return file_system_context()->sandbox_delegate()->usage_cache();
 }
 
 void SandboxFileSystemTestHelper::SetUpFileSystem() {
@@ -140,7 +140,7 @@
   DCHECK(file_util_);
 
   // Prepare the origin's root directory.
-  file_system_context_->sandbox_context()->
+  file_system_context_->sandbox_delegate()->
       GetBaseDirectoryForOriginAndType(origin_, type_, true /* create */);
 
   // Initialize the usage cache file.
diff --git a/webkit/browser/fileapi/sandbox_quota_observer.cc b/webkit/browser/fileapi/sandbox_quota_observer.cc
index 02a47ee..fe5ee37 100644
--- a/webkit/browser/fileapi/sandbox_quota_observer.cc
+++ b/webkit/browser/fileapi/sandbox_quota_observer.cc
@@ -7,7 +7,7 @@
 #include "base/sequenced_task_runner.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/file_system_usage_cache.h"
-#include "webkit/browser/fileapi/sandbox_context.h"
+#include "webkit/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "webkit/browser/fileapi/timed_task_helper.h"
 #include "webkit/browser/quota/quota_client.h"
 #include "webkit/browser/quota/quota_manager.h"
@@ -107,7 +107,7 @@
   DCHECK(sandbox_file_util_);
   base::PlatformFileError error = base::PLATFORM_FILE_OK;
   base::FilePath path =
-      SandboxContext::GetUsageCachePathForOriginAndType(
+      SandboxFileSystemBackendDelegate::GetUsageCachePathForOriginAndType(
           sandbox_file_util_, url.origin(), url.type(), &error);
   if (error != base::PLATFORM_FILE_OK) {
     LOG(WARNING) << "Could not get usage cache path for: "
diff --git a/webkit/browser/fileapi/test_file_system_backend.cc b/webkit/browser/fileapi/test_file_system_backend.cc
index 584e2e3..1cff5c2 100644
--- a/webkit/browser/fileapi/test_file_system_backend.cc
+++ b/webkit/browser/fileapi/test_file_system_backend.cc
@@ -66,17 +66,6 @@
     return usage_;
   }
 
-  virtual void InvalidateUsageCache(const GURL& origin_url,
-                                    FileSystemType type) OVERRIDE {
-    // Do nothing.
-  }
-
-  virtual void StickyInvalidateUsageCache(
-      const GURL& origin,
-      FileSystemType type) OVERRIDE {
-    // Do nothing.
-  }
-
   virtual void AddFileUpdateObserver(
       FileSystemType type,
       FileUpdateObserver* observer,
diff --git a/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc b/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
index e6e0d4c..f79fd73 100644
--- a/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
+++ b/webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc
@@ -9,9 +9,9 @@
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/fileapi/async_file_test_helper.h"
 #include "webkit/browser/fileapi/file_system_backend.h"
 #include "webkit/browser/fileapi/file_system_context.h"
-#include "webkit/browser/fileapi/file_system_file_util.h"
 #include "webkit/browser/fileapi/file_system_operation_context.h"
 #include "webkit/browser/fileapi/file_system_url.h"
 #include "webkit/browser/fileapi/mock_file_system_context.h"
@@ -89,31 +89,14 @@
             kFileSystemType,
             base::FilePath().AppendASCII(filename));
 
-    fileapi::FileSystemFileUtil* file_util =
-        file_system_context_->GetFileUtil(kFileSystemType);
-
-    fileapi::FileSystemOperationContext context(file_system_context_.get());
-    context.set_allowed_bytes_growth(1024);
-
-    base::PlatformFile handle = base::kInvalidPlatformFileValue;
-    bool created = false;
-    ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen(
-        &context,
-        url,
-        base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE,
-        &handle,
-        &created));
-    EXPECT_TRUE(created);
-    ASSERT_NE(base::kInvalidPlatformFileValue, handle);
-    ASSERT_EQ(buf_size,
-        base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size));
-    base::ClosePlatformFile(handle);
+    ASSERT_EQ(base::PLATFORM_FILE_OK,
+              AsyncFileTestHelper::CreateFileWithData(
+                  file_system_context_, url, buf, buf_size));
 
     base::PlatformFileInfo file_info;
-    base::FilePath platform_path;
     ASSERT_EQ(base::PLATFORM_FILE_OK,
-              file_util->GetFileInfo(&context, url, &file_info,
-                                     &platform_path));
+              AsyncFileTestHelper::GetMetadata(
+                  file_system_context_, url, &file_info));
     *modification_time = file_info.last_modified;
   }
 
diff --git a/webkit/child/webkitplatformsupport_impl.cc b/webkit/child/webkitplatformsupport_impl.cc
index ccd988a..bb7cae3 100644
--- a/webkit/child/webkitplatformsupport_impl.cc
+++ b/webkit/child/webkitplatformsupport_impl.cc
@@ -605,6 +605,7 @@
 #endif
 #if defined(OS_MACOSX)
   { "overhangPattern", IDR_OVERHANG_PATTERN, ui::SCALE_FACTOR_100P },
+  { "overhangShadow", IDR_OVERHANG_SHADOW, ui::SCALE_FACTOR_100P },
 #endif
   { "panIcon", IDR_PAN_SCROLL_ICON, ui::SCALE_FACTOR_100P },
   { "searchCancel", IDR_SEARCH_CANCEL, ui::SCALE_FACTOR_100P },
diff --git a/webkit/common/gpu/context_provider_in_process.cc b/webkit/common/gpu/context_provider_in_process.cc
index e56da80..b7e3cc4 100644
--- a/webkit/common/gpu/context_provider_in_process.cc
+++ b/webkit/common/gpu/context_provider_in_process.cc
@@ -4,9 +4,11 @@
 
 #include "webkit/common/gpu/context_provider_in_process.h"
 
+#include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "cc/output/managed_memory_policy.h"
 #include "webkit/common/gpu/grcontext_for_webgraphicscontext3d.h"
-#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
+#include "webkit/common/gpu/managed_memory_policy_convert.h"
 
 namespace webkit {
 namespace gpu {
@@ -31,6 +33,27 @@
   ContextProviderInProcess* provider_;
 };
 
+class ContextProviderInProcess::SwapBuffersCompleteCallbackProxy
+    : public WebKit::WebGraphicsContext3D::
+          WebGraphicsSwapBuffersCompleteCallbackCHROMIUM {
+ public:
+  explicit SwapBuffersCompleteCallbackProxy(ContextProviderInProcess* provider)
+      : provider_(provider) {
+    provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(this);
+  }
+
+  virtual ~SwapBuffersCompleteCallbackProxy() {
+    provider_->context3d_->setSwapBuffersCompleteCallbackCHROMIUM(NULL);
+  }
+
+  virtual void onSwapBuffersComplete() {
+    provider_->OnSwapBuffersComplete();
+  }
+
+ private:
+  ContextProviderInProcess* provider_;
+};
+
 class ContextProviderInProcess::MemoryAllocationCallbackProxy
     : public WebKit::WebGraphicsContext3D::
           WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
@@ -45,29 +68,25 @@
   }
 
   virtual void onMemoryAllocationChanged(
-      WebKit::WebGraphicsMemoryAllocation alloc) {
-    provider_->OnMemoryAllocationChanged(!!alloc.gpuResourceSizeInBytes);
+      WebKit::WebGraphicsMemoryAllocation allocation) {
+    provider_->OnMemoryAllocationChanged(allocation);
   }
 
  private:
   ContextProviderInProcess* provider_;
 };
 
-ContextProviderInProcess::ContextProviderInProcess()
-    : destroyed_(false) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-  context_thread_checker_.DetachFromThread();
+// static
+scoped_refptr<ContextProviderInProcess> ContextProviderInProcess::Create(
+    scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d) {
+  if (!context3d)
+    return NULL;
+  return new ContextProviderInProcess(context3d.Pass());
 }
 
-ContextProviderInProcess::~ContextProviderInProcess() {
-  DCHECK(main_thread_checker_.CalledOnValidThread() ||
-         context_thread_checker_.CalledOnValidThread());
-}
-
-bool ContextProviderInProcess::InitializeOnMainThread() {
-  DCHECK(!context3d_);
-  DCHECK(main_thread_checker_.CalledOnValidThread());
-
+// static
+scoped_refptr<ContextProviderInProcess>
+ContextProviderInProcess::CreateOffscreen() {
   WebKit::WebGraphicsContext3D::Attributes attributes;
   attributes.depth = false;
   attributes.stencil = true;
@@ -75,12 +94,23 @@
   attributes.shareResources = true;
   attributes.noAutomaticFlushes = true;
 
-  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
-  context3d_ =
+  return Create(
       WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
-          attributes);
+          attributes));
+}
 
-  return context3d_;
+ContextProviderInProcess::ContextProviderInProcess(
+    scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d)
+    : context3d_(context3d.Pass()),
+      destroyed_(false) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK(context3d_);
+  context_thread_checker_.DetachFromThread();
+}
+
+ContextProviderInProcess::~ContextProviderInProcess() {
+  DCHECK(main_thread_checker_.CalledOnValidThread() ||
+         context_thread_checker_.CalledOnValidThread());
 }
 
 bool ContextProviderInProcess::BindToCurrentThread() {
@@ -96,10 +126,15 @@
     return false;
 
   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;
 }
 
-WebKit::WebGraphicsContext3D* ContextProviderInProcess::Context3d() {
+webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl*
+ContextProviderInProcess::Context3d() {
   DCHECK(context3d_);
   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
   DCHECK(context_thread_checker_.CalledOnValidThread());
@@ -117,8 +152,6 @@
 
   gr_context_.reset(
       new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
-  memory_allocation_callback_proxy_.reset(
-      new MemoryAllocationCallbackProxy(this));
   return gr_context_->get();
 }
 
@@ -143,6 +176,33 @@
     base::ResetAndReturn(&lost_context_callback_).Run();
 }
 
+void ContextProviderInProcess::OnSwapBuffersComplete() {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+  if (!swap_buffers_complete_callback_.is_null())
+    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());
 
@@ -153,15 +213,25 @@
 void ContextProviderInProcess::SetLostContextCallback(
     const LostContextCallback& lost_context_callback) {
   DCHECK(context_thread_checker_.CalledOnValidThread());
-  DCHECK(lost_context_callback_.is_null());
+  DCHECK(lost_context_callback_.is_null() ||
+         lost_context_callback.is_null());
   lost_context_callback_ = lost_context_callback;
 }
 
-void ContextProviderInProcess::OnMemoryAllocationChanged(
-    bool nonzero_allocation) {
+void ContextProviderInProcess::SetSwapBuffersCompleteCallback(
+    const SwapBuffersCompleteCallback& swap_buffers_complete_callback) {
   DCHECK(context_thread_checker_.CalledOnValidThread());
-  if (gr_context_)
-    gr_context_->SetMemoryLimit(nonzero_allocation);
+  DCHECK(swap_buffers_complete_callback_.is_null() ||
+         swap_buffers_complete_callback.is_null());
+  swap_buffers_complete_callback_ = swap_buffers_complete_callback;
+}
+
+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;
 }
 
 }  // namespace gpu
diff --git a/webkit/common/gpu/context_provider_in_process.h b/webkit/common/gpu/context_provider_in_process.h
index b427abe..2379dd2 100644
--- a/webkit/common/gpu/context_provider_in_process.h
+++ b/webkit/common/gpu/context_provider_in_process.h
@@ -10,10 +10,12 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "cc/output/context_provider.h"
+#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 {
@@ -23,39 +25,49 @@
 class WEBKIT_GPU_EXPORT ContextProviderInProcess
     : NON_EXPORTED_BASE(public cc::ContextProvider) {
  public:
-  static scoped_refptr<ContextProviderInProcess> Create() {
-    scoped_refptr<ContextProviderInProcess> provider =
-        new ContextProviderInProcess;
-    if (!provider->InitializeOnMainThread())
-      return NULL;
-    return provider;
-  }
+  static scoped_refptr<ContextProviderInProcess> Create(
+      scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d);
+
+  // Calls Create() with a default factory method for creating an offscreen
+  // context.
+  static scoped_refptr<ContextProviderInProcess> CreateOffscreen();
 
   virtual bool BindToCurrentThread() OVERRIDE;
-  virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE;
+  virtual webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl*
+      Context3d() OVERRIDE;
   virtual class GrContext* GrContext() OVERRIDE;
   virtual void VerifyContexts() OVERRIDE;
   virtual bool DestroyedOnMainThread() OVERRIDE;
   virtual void SetLostContextCallback(
       const LostContextCallback& lost_context_callback) OVERRIDE;
+  virtual void SetSwapBuffersCompleteCallback(
+      const SwapBuffersCompleteCallback& swap_buffers_complete_callback)
+      OVERRIDE;
+  virtual void SetMemoryPolicyChangedCallback(
+      const MemoryPolicyChangedCallback& memory_policy_changed_callback)
+      OVERRIDE;
 
  protected:
-  ContextProviderInProcess();
+  ContextProviderInProcess(
+      scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d);
   virtual ~ContextProviderInProcess();
 
-  bool InitializeOnMainThread();
-
   void OnLostContext();
-  void OnMemoryAllocationChanged(bool nonzero_allocation);
+  void OnSwapBuffersComplete();
+  void OnMemoryAllocationChanged(
+      const WebKit::WebGraphicsMemoryAllocation& allocation);
 
  private:
   base::ThreadChecker main_thread_checker_;
   base::ThreadChecker context_thread_checker_;
 
-  scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
+  scoped_ptr<webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl>
+      context3d_;
   scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
 
   LostContextCallback lost_context_callback_;
+  SwapBuffersCompleteCallback swap_buffers_complete_callback_;
+  MemoryPolicyChangedCallback memory_policy_changed_callback_;
 
   base::Lock destroyed_lock_;
   bool destroyed_;
@@ -63,6 +75,10 @@
   class LostContextCallbackProxy;
   scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_;
 
+  class SwapBuffersCompleteCallbackProxy;
+  scoped_ptr<SwapBuffersCompleteCallbackProxy>
+      swap_buffers_complete_callback_proxy_;
+
   class MemoryAllocationCallbackProxy;
   scoped_ptr<MemoryAllocationCallbackProxy> memory_allocation_callback_proxy_;
 };
diff --git a/webkit/common/gpu/managed_memory_policy_convert.cc b/webkit/common/gpu/managed_memory_policy_convert.cc
new file mode 100644
index 0000000..548e2ae
--- /dev/null
+++ b/webkit/common/gpu/managed_memory_policy_convert.cc
@@ -0,0 +1,43 @@
+// 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
new file mode 100644
index 0000000..0309683
--- /dev/null
+++ b/webkit/common/gpu/managed_memory_policy_convert.h
@@ -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.
+
+#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/test_context_provider_factory.cc b/webkit/common/gpu/test_context_provider_factory.cc
index 88464c0..7e4f04f 100644
--- a/webkit/common/gpu/test_context_provider_factory.cc
+++ b/webkit/common/gpu/test_context_provider_factory.cc
@@ -27,7 +27,7 @@
 scoped_refptr<cc::ContextProvider> TestContextProviderFactory::
     OffscreenContextProviderForMainThread() {
   if (!main_thread_.get() || main_thread_->DestroyedOnMainThread()) {
-    main_thread_ = ContextProviderInProcess::Create();
+    main_thread_ = ContextProviderInProcess::CreateOffscreen();
     if (main_thread_.get() && !main_thread_->BindToCurrentThread())
       main_thread_ = NULL;
   }
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 886e40f..9207ef9 100644
--- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -66,11 +66,11 @@
 }  // namespace anonymous
 
 // static
-scoped_ptr<WebKit::WebGraphicsContext3D>
+scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
 WebGraphicsContext3DInProcessCommandBufferImpl::CreateViewContext(
     const WebKit::WebGraphicsContext3D::Attributes& attributes,
     gfx::AcceleratedWidget window) {
-  scoped_ptr<WebKit::WebGraphicsContext3D> context;
+  scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context;
   if (gfx::GLSurface::InitializeOneOff()) {
     context.reset(new WebGraphicsContext3DInProcessCommandBufferImpl(
       scoped_ptr< ::gpu::GLInProcessContext>(), attributes, false, window));
@@ -79,7 +79,7 @@
 }
 
 // static
-scoped_ptr<WebKit::WebGraphicsContext3D>
+scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
 WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
     const WebKit::WebGraphicsContext3D::Attributes& attributes) {
   return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl(
@@ -87,10 +87,10 @@
                              attributes,
                              true,
                              gfx::kNullAcceleratedWidget))
-      .PassAs<WebKit::WebGraphicsContext3D>();
+      .Pass();
 }
 
-scoped_ptr<WebKit::WebGraphicsContext3D>
+scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
 WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
     scoped_ptr< ::gpu::GLInProcessContext> context,
     const WebKit::WebGraphicsContext3D::Attributes& attributes) {
@@ -100,7 +100,7 @@
           attributes,
           true /* is_offscreen. Not used. */,
           gfx::kNullAcceleratedWidget /* window. Not used. */))
-      .PassAs<WebKit::WebGraphicsContext3D>();
+      .Pass();
 }
 
 WebGraphicsContext3DInProcessCommandBufferImpl::
@@ -1117,6 +1117,11 @@
 DELEGATE_TO_GL_2(releaseTexImage2DCHROMIUM, ReleaseTexImage2DCHROMIUM,
                  WGC3Denum, WGC3Dint)
 
+DELEGATE_TO_GL_1R(createStreamTextureCHROMIUM, CreateStreamTextureCHROMIUM,
+                  WebGLId, WebGLId)
+DELEGATE_TO_GL_1(destroyStreamTextureCHROMIUM, DestroyStreamTextureCHROMIUM,
+                 WebGLId)
+
 void* WebGraphicsContext3DInProcessCommandBufferImpl::mapBufferCHROMIUM(
     WGC3Denum target, WGC3Denum access) {
   ClearContext();
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 d3620b4..d763e14 100644
--- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
+++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
@@ -48,16 +48,19 @@
 class WEBKIT_GPU_EXPORT WebGraphicsContext3DInProcessCommandBufferImpl
     : public NON_EXPORTED_BASE(WebKit::WebGraphicsContext3D) {
  public:
-  static scoped_ptr<WebKit::WebGraphicsContext3D> CreateViewContext(
-      const WebKit::WebGraphicsContext3D::Attributes& attributes,
-      gfx::AcceleratedWidget window);
+  static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
+      CreateViewContext(
+          const WebKit::WebGraphicsContext3D::Attributes& attributes,
+          gfx::AcceleratedWidget window);
 
-  static scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext(
-      const WebKit::WebGraphicsContext3D::Attributes& attributes);
+  static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
+      CreateOffscreenContext(
+          const WebKit::WebGraphicsContext3D::Attributes& attributes);
 
-  static scoped_ptr<WebKit::WebGraphicsContext3D> WrapContext(
-      scoped_ptr< ::gpu::GLInProcessContext> context,
-      const WebKit::WebGraphicsContext3D::Attributes& attributes);
+  static scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
+      WrapContext(
+          scoped_ptr< ::gpu::GLInProcessContext> context,
+          const WebKit::WebGraphicsContext3D::Attributes& attributes);
 
   virtual ~WebGraphicsContext3DInProcessCommandBufferImpl();
 
@@ -465,6 +468,9 @@
   virtual void bindTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId);
   virtual void releaseTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId);
 
+  virtual WebGLId createStreamTextureCHROMIUM(WebGLId texture);
+  virtual void destroyStreamTextureCHROMIUM(WebGLId texture);
+
   virtual void texStorage2DEXT(
       WGC3Denum target, WGC3Dint levels, WGC3Duint internalformat,
       WGC3Dint width, WGC3Dint height);
diff --git a/webkit/common/gpu/webkit_gpu.gyp b/webkit/common/gpu/webkit_gpu.gyp
index 5390c9a..2831446 100644
--- a/webkit/common/gpu/webkit_gpu.gyp
+++ b/webkit/common/gpu/webkit_gpu.gyp
@@ -15,6 +15,7 @@
           'variables': { 'enable_wexit_time_destructors': 1, },
           'dependencies': [
             '<(DEPTH)/base/base.gyp:base',
+            '<(DEPTH)/cc/cc.gyp:cc',
             '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
             '<(DEPTH)/gpu/command_buffer/command_buffer.gyp:gles2_utils',
             '<(DEPTH)/gpu/gpu.gyp:command_buffer_service',
@@ -34,6 +35,8 @@
             '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 1c5f79d..0da070d 100644
--- a/webkit/common/gpu/webkit_gpu.target.darwin-arm.mk
+++ b/webkit/common/gpu/webkit_gpu.target.darwin-arm.mk
@@ -31,6 +31,7 @@
 	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
@@ -113,9 +114,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
@@ -229,9 +230,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
diff --git a/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk b/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk
index a75efc9..b20d23c 100644
--- a/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk
+++ b/webkit/common/gpu/webkit_gpu.target.darwin-mips.mk
@@ -31,6 +31,7 @@
 	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
@@ -113,9 +114,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
@@ -229,9 +230,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
diff --git a/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk b/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk
index 15e7074..46e5c85 100644
--- a/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk
+++ b/webkit/common/gpu/webkit_gpu.target.darwin-x86.mk
@@ -31,6 +31,7 @@
 	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
@@ -114,9 +115,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
@@ -232,9 +233,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
diff --git a/webkit/common/gpu/webkit_gpu.target.linux-arm.mk b/webkit/common/gpu/webkit_gpu.target.linux-arm.mk
index 1c5f79d..0da070d 100644
--- a/webkit/common/gpu/webkit_gpu.target.linux-arm.mk
+++ b/webkit/common/gpu/webkit_gpu.target.linux-arm.mk
@@ -31,6 +31,7 @@
 	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
@@ -113,9 +114,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
@@ -229,9 +230,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
diff --git a/webkit/common/gpu/webkit_gpu.target.linux-mips.mk b/webkit/common/gpu/webkit_gpu.target.linux-mips.mk
index a75efc9..b20d23c 100644
--- a/webkit/common/gpu/webkit_gpu.target.linux-mips.mk
+++ b/webkit/common/gpu/webkit_gpu.target.linux-mips.mk
@@ -31,6 +31,7 @@
 	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
@@ -113,9 +114,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
@@ -229,9 +230,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
diff --git a/webkit/common/gpu/webkit_gpu.target.linux-x86.mk b/webkit/common/gpu/webkit_gpu.target.linux-x86.mk
index 15e7074..46e5c85 100644
--- a/webkit/common/gpu/webkit_gpu.target.linux-x86.mk
+++ b/webkit/common/gpu/webkit_gpu.target.linux-x86.mk
@@ -31,6 +31,7 @@
 	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
@@ -114,9 +115,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
@@ -232,9 +233,9 @@
 	$(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) \
 	$(LOCAL_PATH)/third_party/khronos \
 	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
 	$(LOCAL_PATH)/third_party/skia/src/core \
 	$(LOCAL_PATH)/skia/config \
 	$(LOCAL_PATH)/third_party/skia/include/config \
diff --git a/webkit/glue/resources/default_100_percent/overhang_shadow.png b/webkit/glue/resources/default_100_percent/overhang_shadow.png
new file mode 100644
index 0000000..687b292
--- /dev/null
+++ b/webkit/glue/resources/default_100_percent/overhang_shadow.png
Binary files differ
diff --git a/webkit/glue/resources/webkit_resources.grd b/webkit/glue/resources/webkit_resources.grd
index aaf330d..9e5cb25 100644
--- a/webkit/glue/resources/webkit_resources.grd
+++ b/webkit/glue/resources/webkit_resources.grd
@@ -57,6 +57,7 @@
       </if>
       <if expr="is_macosx">
         <structure type="chrome_scaled_image" name="IDR_OVERHANG_PATTERN" file="overhang_pattern.png" />
+        <structure type="chrome_scaled_image" name="IDR_OVERHANG_SHADOW" file="overhang_shadow.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_PAN_SCROLL_ICON" file="pan_icon.png" />
       <structure type="chrome_scaled_image" name="IDR_SEARCH_CANCEL" file="search_cancel.png" />
diff --git a/webkit/glue/resources/webkit_strings_et.xtb b/webkit/glue/resources/webkit_strings_et.xtb
index 4103de5..599b997 100644
--- a/webkit/glue/resources/webkit_strings_et.xtb
+++ b/webkit/glue/resources/webkit_strings_et.xtb
@@ -18,7 +18,7 @@
 <translation id="8785498733064193001">taasesituse alustamine</translation>
 <translation id="7057186640035488495">video aeg</translation>
 <translation id="8199524924445686405">aaaa</translation>
-<translation id="795667975304826397">Ühtegi faili pole valitud</translation>
+<translation id="795667975304826397">Pole valitud</translation>
 <translation id="1320012872283894746">kiiresti tagasikerimine</translation>
 <translation id="7789962463072032349">peata</translation>
 <translation id="6853785296079745596">subtiitrite peitmine</translation>
diff --git a/webkit/glue/simple_webmimeregistry_impl.cc b/webkit/glue/simple_webmimeregistry_impl.cc
index 8340458..48364ef 100644
--- a/webkit/glue/simple_webmimeregistry_impl.cc
+++ b/webkit/glue/simple_webmimeregistry_impl.cc
@@ -94,12 +94,4 @@
   return WebString::fromUTF8(mime_type);
 }
 
-WebString SimpleWebMimeRegistryImpl::preferredExtensionForMIMEType(
-    const WebString& mime_type) {
-  base::FilePath::StringType file_extension;
-  net::GetPreferredExtensionForMimeType(ToASCIIOrEmpty(mime_type),
-                                        &file_extension);
-  return base::FilePath(file_extension).AsUTF16Unsafe();
-}
-
 }  // namespace webkit_glue
diff --git a/webkit/glue/simple_webmimeregistry_impl.h b/webkit/glue/simple_webmimeregistry_impl.h
index 39972eb..1055dfe 100644
--- a/webkit/glue/simple_webmimeregistry_impl.h
+++ b/webkit/glue/simple_webmimeregistry_impl.h
@@ -45,8 +45,6 @@
   virtual WebKit::WebString wellKnownMimeTypeForExtension(
       const WebKit::WebString&);
   virtual WebKit::WebString mimeTypeFromFile(const WebKit::WebString&);
-  virtual WebKit::WebString preferredExtensionForMIMEType(
-      const WebKit::WebString&);
 };
 
 }  // namespace webkit_glue
diff --git a/webkit/renderer/compositor_bindings/compositor_bindings.gyp b/webkit/renderer/compositor_bindings/compositor_bindings.gyp
index 9cc2b4a..abd2db1 100644
--- a/webkit/renderer/compositor_bindings/compositor_bindings.gyp
+++ b/webkit/renderer/compositor_bindings/compositor_bindings.gyp
@@ -64,6 +64,8 @@
         'web_layer_impl.h',
         'web_layer_impl_fixed_bounds.cc',
         'web_layer_impl_fixed_bounds.h',
+        'web_nine_patch_layer_impl.cc',
+        'web_nine_patch_layer_impl.h',
         'web_scrollbar_layer_impl.cc',
         'web_scrollbar_layer_impl.h',
         'web_solid_color_layer_impl.cc',
diff --git a/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc b/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc
index 108ff7a..4cb5dd9 100644
--- a/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_compositor_support_impl.cc
@@ -17,6 +17,7 @@
 #include "webkit/renderer/compositor_bindings/web_float_animation_curve_impl.h"
 #include "webkit/renderer/compositor_bindings/web_image_layer_impl.h"
 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
+#include "webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.h"
 #include "webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.h"
 #include "webkit/renderer/compositor_bindings/web_solid_color_layer_impl.h"
 #include "webkit/renderer/compositor_bindings/web_transform_animation_curve_impl.h"
@@ -31,6 +32,7 @@
 using WebKit::WebFilterOperations;
 using WebKit::WebFloatAnimationCurve;
 using WebKit::WebImageLayer;
+using WebKit::WebNinePatchLayer;
 using WebKit::WebLayer;
 using WebKit::WebScrollbar;
 using WebKit::WebScrollbarLayer;
@@ -64,6 +66,10 @@
   return new WebImageLayerImpl();
 }
 
+WebKit::WebNinePatchLayer* WebCompositorSupportImpl::createNinePatchLayer() {
+  return new WebNinePatchLayerImpl();
+}
+
 WebSolidColorLayer* WebCompositorSupportImpl::createSolidColorLayer() {
   return new WebSolidColorLayerImpl();
 }
diff --git a/webkit/renderer/compositor_bindings/web_compositor_support_impl.h b/webkit/renderer/compositor_bindings/web_compositor_support_impl.h
index 7900465..c3c8778 100644
--- a/webkit/renderer/compositor_bindings/web_compositor_support_impl.h
+++ b/webkit/renderer/compositor_bindings/web_compositor_support_impl.h
@@ -28,6 +28,7 @@
   virtual WebKit::WebExternalTextureLayer* createExternalTextureLayer(
       WebKit::WebExternalTextureLayerClient* client);
   virtual WebKit::WebImageLayer* createImageLayer();
+  virtual WebKit::WebNinePatchLayer* createNinePatchLayer();
   virtual WebKit::WebSolidColorLayer* createSolidColorLayer();
   virtual WebKit::WebScrollbarLayer* createScrollbarLayer(
       WebKit::WebScrollbar* scrollbar,
diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.cc b/webkit/renderer/compositor_bindings/web_layer_impl.cc
index 0545b3a..f2a3cde 100644
--- a/webkit/renderer/compositor_bindings/web_layer_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_layer_impl.cc
@@ -13,6 +13,7 @@
 #include "third_party/WebKit/public/platform/WebCompositingReasons.h"
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebFloatRect.h"
+#include "third_party/WebKit/public/platform/WebLayerClient.h"
 #include "third_party/WebKit/public/platform/WebLayerPositionConstraint.h"
 #include "third_party/WebKit/public/platform/WebLayerScrollClient.h"
 #include "third_party/WebKit/public/platform/WebSize.h"
@@ -33,13 +34,20 @@
 
 namespace webkit {
 
-WebLayerImpl::WebLayerImpl() : layer_(Layer::Create()) {}
+WebLayerImpl::WebLayerImpl() : layer_(Layer::Create()) {
+  web_layer_client_ = NULL;
+  layer_->SetLayerClient(this);
+}
 
-WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer) : layer_(layer) {}
+WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer) : layer_(layer) {
+  web_layer_client_ = NULL;
+  layer_->SetLayerClient(this);
+}
 
 WebLayerImpl::~WebLayerImpl() {
   layer_->ClearRenderSurface();
   layer_->set_layer_animation_delegate(NULL);
+  web_layer_client_ = NULL;
 }
 
 int WebLayerImpl::id() const { return layer_->id(); }
@@ -174,10 +182,6 @@
   layer_->SetFilter(skia::SharePtr(filter));
 }
 
-void WebLayerImpl::setDebugName(WebKit::WebString name) {
-  layer_->SetDebugName(UTF16ToASCII(name));
-}
-
 void WebLayerImpl::setCompositingReasons(
     WebKit::WebCompositingReasons reasons) {
   layer_->SetCompositingReasons(reasons);
@@ -366,6 +370,29 @@
   web_layer_client_ = client;
 }
 
+std::string WebLayerImpl::DebugName() {
+  if (!web_layer_client_)
+    return std::string();
+
+  std::string name = web_layer_client_->debugName(this).utf8();
+  DCHECK(IsStringASCII(name));
+  return name;
+}
+
+void WebLayerImpl::setScrollParent(WebKit::WebLayer* parent) {
+  cc::Layer* scroll_parent = NULL;
+  if (parent)
+    scroll_parent = static_cast<WebLayerImpl*>(parent)->layer();
+  layer_->SetScrollParent(scroll_parent);
+}
+
+void WebLayerImpl::setClipParent(WebKit::WebLayer* parent) {
+  cc::Layer* clip_parent = NULL;
+  if (parent)
+    clip_parent = static_cast<WebLayerImpl*>(parent)->layer();
+  layer_->SetClipParent(clip_parent);
+}
+
 Layer* WebLayerImpl::layer() const { return layer_.get(); }
 
 }  // namespace webkit
diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.h b/webkit/renderer/compositor_bindings/web_layer_impl.h
index ee5997d..169b818 100644
--- a/webkit/renderer/compositor_bindings/web_layer_impl.h
+++ b/webkit/renderer/compositor_bindings/web_layer_impl.h
@@ -5,9 +5,13 @@
 #ifndef WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_LAYER_IMPL_H_
 #define WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_LAYER_IMPL_H_
 
+#include <string>
+
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "cc/layers/layer_client.h"
 #include "third_party/WebKit/public/platform/WebAnimation.h"
+#include "third_party/WebKit/public/platform/WebCString.h"
 #include "third_party/WebKit/public/platform/WebColor.h"
 #include "third_party/WebKit/public/platform/WebCompositingReasons.h"
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
@@ -35,7 +39,7 @@
 
 class WebToCCAnimationDelegateAdapter;
 
-class WebLayerImpl : public WebKit::WebLayer {
+class WebLayerImpl : public WebKit::WebLayer, public cc::LayerClient {
  public:
   WEBKIT_COMPOSITOR_BINDINGS_EXPORT WebLayerImpl();
   WEBKIT_COMPOSITOR_BINDINGS_EXPORT explicit WebLayerImpl(
@@ -83,7 +87,6 @@
   virtual void setFilter(SkImageFilter* filter);
   virtual void setFilters(const WebKit::WebFilterOperations& filters);
   virtual void setBackgroundFilters(const WebKit::WebFilterOperations& filters);
-  virtual void setDebugName(WebKit::WebString name);
   virtual void setCompositingReasons(WebKit::WebCompositingReasons);
   virtual void setAnimationDelegate(WebKit::WebAnimationDelegate* delegate);
   virtual bool addAnimation(WebKit::WebAnimation* animation);
@@ -120,6 +123,12 @@
   virtual bool isOrphan() const;
   virtual void setWebLayerClient(WebKit::WebLayerClient* client);
 
+  // LayerClient implementation.
+  virtual std::string DebugName() OVERRIDE;
+
+  virtual void setScrollParent(WebKit::WebLayer* parent);
+  virtual void setClipParent(WebKit::WebLayer* parent);
+
  protected:
   scoped_refptr<cc::Layer> layer_;
   WebKit::WebLayerClient* web_layer_client_;
diff --git a/webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc b/webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc
new file mode 100644
index 0000000..0c64a06
--- /dev/null
+++ b/webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.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 "webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.h"
+
+#include "base/command_line.h"
+#include "cc/base/switches.h"
+#include "cc/layers/nine_patch_layer.h"
+#include "cc/layers/picture_image_layer.h"
+#include "webkit/renderer/compositor_bindings/web_layer_impl.h"
+#include "webkit/renderer/compositor_bindings/web_layer_impl_fixed_bounds.h"
+
+namespace webkit {
+
+WebNinePatchLayerImpl::WebNinePatchLayerImpl() {
+  layer_.reset(new WebLayerImpl(cc::NinePatchLayer::Create()));
+}
+
+WebNinePatchLayerImpl::~WebNinePatchLayerImpl() {}
+
+WebKit::WebLayer* WebNinePatchLayerImpl::layer() { return layer_.get(); }
+
+void WebNinePatchLayerImpl::setBitmap(SkBitmap bitmap,
+                                      const WebKit::WebRect& aperture) {
+  static_cast<cc::NinePatchLayer*>(layer_->layer())->SetBitmap(
+      bitmap, gfx::Rect(aperture));
+}
+
+}  // namespace webkit
diff --git a/webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.h b/webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.h
new file mode 100644
index 0000000..34c8eff
--- /dev/null
+++ b/webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.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 WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_NINE_PATCH_LAYER_IMPL_H_
+#define WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_NINE_PATCH_LAYER_IMPL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "third_party/WebKit/public/platform/WebNinePatchLayer.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "webkit/renderer/compositor_bindings/webkit_compositor_bindings_export.h"
+
+namespace webkit {
+
+class WebLayerImpl;
+
+class WebNinePatchLayerImpl : public WebKit::WebNinePatchLayer {
+ public:
+  WEBKIT_COMPOSITOR_BINDINGS_EXPORT WebNinePatchLayerImpl();
+  virtual ~WebNinePatchLayerImpl();
+
+  // WebKit::WebNinePatchLayer implementation.
+  virtual WebKit::WebLayer* layer();
+  virtual void setBitmap(SkBitmap, const WebKit::WebRect& aperture);
+
+ private:
+  scoped_ptr<WebLayerImpl> layer_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebNinePatchLayerImpl);
+};
+
+}  // namespace webkit
+
+#endif  // WEBKIT_RENDERER_COMPOSITOR_BINDINGS_WEB_NINE_PATCH_LAYER_IMPL_H_
diff --git a/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc b/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc
index a808021..0529d5c 100644
--- a/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc
@@ -4,12 +4,12 @@
 
 #include "webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.h"
 
-#include "cc/layers/scrollbar_layer.h"
+#include "cc/layers/painted_scrollbar_layer.h"
 #include "third_party/WebKit/public/platform/WebScrollbar.h"
 #include "webkit/renderer/compositor_bindings/scrollbar_impl.h"
 #include "webkit/renderer/compositor_bindings/web_layer_impl.h"
 
-using cc::ScrollbarLayer;
+using cc::PaintedScrollbarLayer;
 
 namespace webkit {
 
@@ -17,7 +17,7 @@
     WebKit::WebScrollbar* scrollbar,
     WebKit::WebScrollbarThemePainter painter,
     WebKit::WebScrollbarThemeGeometry* geometry)
-    : layer_(new WebLayerImpl(ScrollbarLayer::Create(
+    : layer_(new WebLayerImpl(PaintedScrollbarLayer::Create(
           scoped_ptr<cc::Scrollbar>(new ScrollbarImpl(
               make_scoped_ptr(scrollbar),
               painter,
@@ -29,7 +29,7 @@
 
 void WebScrollbarLayerImpl::setScrollLayer(WebKit::WebLayer* layer) {
   int id = layer ? static_cast<WebLayerImpl*>(layer)->layer()->id() : 0;
-  static_cast<ScrollbarLayer*>(layer_->layer())->SetScrollLayerId(id);
+  static_cast<PaintedScrollbarLayer*>(layer_->layer())->SetScrollLayerId(id);
 }
 
 }  // namespace webkit
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 4e47a78..2dd75a2 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
@@ -40,6 +40,7 @@
 	webkit/renderer/compositor_bindings/web_image_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl_fixed_bounds.cc \
+	webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_solid_color_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_to_cc_animation_delegate_adapter.cc \
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 df70c4f..57bfbdd 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
@@ -40,6 +40,7 @@
 	webkit/renderer/compositor_bindings/web_image_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl_fixed_bounds.cc \
+	webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_solid_color_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_to_cc_animation_delegate_adapter.cc \
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 393f643..acf7f82 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
@@ -40,6 +40,7 @@
 	webkit/renderer/compositor_bindings/web_image_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl_fixed_bounds.cc \
+	webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_solid_color_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_to_cc_animation_delegate_adapter.cc \
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 4e47a78..2dd75a2 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
@@ -40,6 +40,7 @@
 	webkit/renderer/compositor_bindings/web_image_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl_fixed_bounds.cc \
+	webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_solid_color_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_to_cc_animation_delegate_adapter.cc \
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 df70c4f..57bfbdd 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
@@ -40,6 +40,7 @@
 	webkit/renderer/compositor_bindings/web_image_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl_fixed_bounds.cc \
+	webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_solid_color_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_to_cc_animation_delegate_adapter.cc \
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 393f643..acf7f82 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
@@ -40,6 +40,7 @@
 	webkit/renderer/compositor_bindings/web_image_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_layer_impl_fixed_bounds.cc \
+	webkit/renderer/compositor_bindings/web_nine_patch_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_scrollbar_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_solid_color_layer_impl.cc \
 	webkit/renderer/compositor_bindings/web_to_cc_animation_delegate_adapter.cc \
diff --git a/webkit/renderer/fileapi/OWNERS b/webkit/renderer/fileapi/OWNERS
deleted file mode 100644
index 13c3288..0000000
--- a/webkit/renderer/fileapi/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-ericu@chromium.org
diff --git a/webkit/renderer/fileapi/webfilewriter_base.cc b/webkit/renderer/fileapi/webfilewriter_base.cc
deleted file mode 100644
index 92c7ae1..0000000
--- a/webkit/renderer/fileapi/webfilewriter_base.cc
+++ /dev/null
@@ -1,154 +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 "webkit/renderer/fileapi/webfilewriter_base.h"
-
-#include "base/logging.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/web/WebFileError.h"
-#include "third_party/WebKit/public/web/WebFileWriterClient.h"
-#include "webkit/common/fileapi/file_system_util.h"
-
-namespace fileapi {
-
-WebFileWriterBase::WebFileWriterBase(
-     const GURL& path, WebKit::WebFileWriterClient* client)
-  : path_(path),
-    client_(client),
-    operation_(kOperationNone),
-    cancel_state_(kCancelNotInProgress) {
-}
-
-WebFileWriterBase::~WebFileWriterBase() {
-}
-
-void WebFileWriterBase::truncate(long long length) {
-  DCHECK(kOperationNone == operation_);
-  DCHECK(kCancelNotInProgress == cancel_state_);
-  operation_ = kOperationTruncate;
-  DoTruncate(path_, length);
-}
-
-void WebFileWriterBase::write(
-      long long position,
-      const WebKit::WebURL& blob_url) {
-  DCHECK(kOperationNone == operation_);
-  DCHECK(kCancelNotInProgress == cancel_state_);
-  operation_ = kOperationWrite;
-  DoWrite(path_, blob_url, position);
-}
-
-// When we cancel a write/truncate, we always get back the result of the write
-// before the result of the cancel, no matter what happens.
-// So we'll get back either
-//   success [of the write/truncate, in a DidWrite(XXX, true)/DidSucceed() call]
-//     followed by failure [of the cancel]; or
-//   failure [of the write, either from cancel or other reasons] followed by
-//     the result of the cancel.
-// In the write case, there could also be queued up non-terminal DidWrite calls
-// before any of that comes back, but there will always be a terminal write
-// response [success or failure] after them, followed by the cancel result, so
-// we can ignore non-terminal write responses, take the terminal write success
-// or the first failure as the last write response, then know that the next
-// thing to come back is the cancel response.  We only notify the
-// AsyncFileWriterClient when it's all over.
-void WebFileWriterBase::cancel() {
-  // Check for the cancel passing the previous operation's return in-flight.
-  if (kOperationWrite != operation_ && kOperationTruncate != operation_)
-    return;
-  if (kCancelNotInProgress != cancel_state_)
-    return;
-  cancel_state_ = kCancelSent;
-  DoCancel();
-}
-
-void WebFileWriterBase::DidFinish(base::PlatformFileError error_code) {
-  if (error_code == base::PLATFORM_FILE_OK)
-    DidSucceed();
-  else
-    DidFail(error_code);
-}
-
-void WebFileWriterBase::DidWrite(int64 bytes, bool complete) {
-  DCHECK(kOperationWrite == operation_);
-  switch (cancel_state_) {
-    case kCancelNotInProgress:
-      if (complete)
-        operation_ = kOperationNone;
-      client_->didWrite(bytes, complete);
-      break;
-    case kCancelSent:
-      // This is the success call of the write, which we'll eat, even though
-      // it succeeded before the cancel got there.  We accepted the cancel call,
-      // so the write will eventually return an error.
-      if (complete)
-        cancel_state_ = kCancelReceivedWriteResponse;
-      break;
-    case kCancelReceivedWriteResponse:
-    default:
-      NOTREACHED();
-  }
-}
-
-void WebFileWriterBase::DidSucceed() {
-  // Write never gets a DidSucceed call, so this is either a cancel or truncate
-  // response.
-  switch (cancel_state_) {
-    case kCancelNotInProgress:
-      // A truncate succeeded, with no complications.
-      DCHECK(kOperationTruncate == operation_);
-      operation_ = kOperationNone;
-      client_->didTruncate();
-      break;
-    case kCancelSent:
-      DCHECK(kOperationTruncate == operation_);
-      // This is the success call of the truncate, which we'll eat, even though
-      // it succeeded before the cancel got there.  We accepted the cancel call,
-      // so the truncate will eventually return an error.
-      cancel_state_ = kCancelReceivedWriteResponse;
-      break;
-    case kCancelReceivedWriteResponse:
-      // This is the success of the cancel operation.
-      FinishCancel();
-      break;
-    default:
-      NOTREACHED();
-  }
-}
-
-void WebFileWriterBase::DidFail(base::PlatformFileError error_code) {
-  DCHECK(kOperationNone != operation_);
-  switch (cancel_state_) {
-    case kCancelNotInProgress:
-      // A write or truncate failed.
-      operation_ = kOperationNone;
-      client_->didFail(
-          PlatformFileErrorToWebFileError(error_code));
-      break;
-    case kCancelSent:
-      // This is the failure of a write or truncate; the next message should be
-      // the result of the cancel.  We don't assume that it'll be a success, as
-      // the write/truncate could have failed for other reasons.
-      cancel_state_ = kCancelReceivedWriteResponse;
-      break;
-    case kCancelReceivedWriteResponse:
-      // The cancel reported failure, meaning that the write or truncate
-      // finished before the cancel got there.  But we suppressed the
-      // write/truncate's response, and will now report that it was cancelled.
-      FinishCancel();
-      break;
-    default:
-      NOTREACHED();
-  }
-}
-
-void WebFileWriterBase::FinishCancel() {
-  DCHECK(kCancelReceivedWriteResponse == cancel_state_);
-  DCHECK(kOperationNone != operation_);
-  cancel_state_ = kCancelNotInProgress;
-  operation_ = kOperationNone;
-  client_->didFail(WebKit::WebFileErrorAbort);
-}
-
-}  // namespace fileapi
diff --git a/webkit/renderer/fileapi/webfilewriter_base.h b/webkit/renderer/fileapi/webfilewriter_base.h
deleted file mode 100644
index dc1d730..0000000
--- a/webkit/renderer/fileapi/webfilewriter_base.h
+++ /dev/null
@@ -1,71 +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 WEBKIT_RENDERER_FILEAPI_WEBFILEWRITER_BASE_H_
-#define WEBKIT_RENDERER_FILEAPI_WEBFILEWRITER_BASE_H_
-
-#include "base/platform_file.h"
-#include "third_party/WebKit/public/web/WebFileWriter.h"
-#include "url/gurl.h"
-#include "webkit/renderer/webkit_storage_renderer_export.h"
-
-namespace WebKit {
-class WebFileWriterClient;
-class WebURL;
-}
-
-namespace fileapi {
-
-class WEBKIT_STORAGE_RENDERER_EXPORT WebFileWriterBase
-    : public NON_EXPORTED_BASE(WebKit::WebFileWriter) {
- public:
-  WebFileWriterBase(
-      const GURL& path, WebKit::WebFileWriterClient* client);
-  virtual ~WebFileWriterBase();
-
-  // WebFileWriter implementation
-  virtual void truncate(long long length);
-  virtual void write(long long position, const WebKit::WebURL& blobURL);
-  virtual void cancel();
-
- protected:
-  // This calls DidSucceed() or DidFail() based on the value of |error_code|.
-  void DidFinish(base::PlatformFileError error_code);
-
-  void DidWrite(int64 bytes, bool complete);
-  void DidSucceed();
-  void DidFail(base::PlatformFileError error_code);
-
-  // Derived classes must provide these methods to asynchronously perform
-  // 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 DoWrite(const GURL& path, const GURL& blob_url,
-                       int64 offset) = 0;
-  virtual void DoCancel() = 0;
-
- private:
-  enum OperationType {
-    kOperationNone,
-    kOperationWrite,
-    kOperationTruncate
-  };
-
-  enum CancelState {
-    kCancelNotInProgress,
-    kCancelSent,
-    kCancelReceivedWriteResponse,
-  };
-
-  void FinishCancel();
-
-  GURL path_;
-  WebKit::WebFileWriterClient* client_;
-  OperationType operation_;
-  CancelState cancel_state_;
-};
-
-}  // namespace fileapi
-
-#endif  // WEBKIT_RENDERER_FILEAPI_WEBFILEWRITER_BASE_H_
diff --git a/webkit/renderer/fileapi/webfilewriter_base_unittest.cc b/webkit/renderer/fileapi/webfilewriter_base_unittest.cc
deleted file mode 100644
index d706738..0000000
--- a/webkit/renderer/fileapi/webfilewriter_base_unittest.cc
+++ /dev/null
@@ -1,411 +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 "webkit/renderer/fileapi/webfilewriter_base.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/WebKit/public/web/WebFileError.h"
-#include "third_party/WebKit/public/web/WebFileWriterClient.h"
-#include "url/gurl.h"
-
-namespace fileapi {
-
-namespace {
-
-// We use particular offsets to trigger particular behaviors
-// in the TestableFileWriter.
-const int kNoOffset = -1;
-const int kBasicFileTruncate_Offset = 1;
-const int kErrorFileTruncate_Offset = 2;
-const int kCancelFileTruncate_Offset = 3;
-const int kCancelFailedTruncate_Offset = 4;
-const int kBasicFileWrite_Offset = 1;
-const int kErrorFileWrite_Offset = 2;
-const int kMultiFileWrite_Offset = 3;
-const int kCancelFileWriteBeforeCompletion_Offset = 4;
-const int kCancelFileWriteAfterCompletion_Offset = 5;
-
-GURL mock_path_as_gurl() {
-  return GURL("MockPath");
-}
-
-}  // namespace
-
-class TestableFileWriter : public WebFileWriterBase {
- public:
-  explicit TestableFileWriter(WebKit::WebFileWriterClient* client)
-      : WebFileWriterBase(mock_path_as_gurl(), client) {
-    reset();
-  }
-
-  void reset() {
-    received_truncate_ = false;
-    received_truncate_path_ = GURL();
-    received_truncate_offset_ = kNoOffset;
-    received_write_ = false;
-    received_write_path_ = GURL();
-    received_write_offset_ = kNoOffset;
-    received_write_blob_url_ = GURL();
-    received_cancel_ = false;
-  }
-
-  bool received_truncate_;
-  GURL received_truncate_path_;
-  int64 received_truncate_offset_;
-  bool received_write_;
-  GURL received_write_path_;
-  GURL received_write_blob_url_;
-  int64 received_write_offset_;
-  bool received_cancel_;
-
- protected:
-  virtual void DoTruncate(const GURL& path, int64 offset) OVERRIDE {
-    received_truncate_ = true;
-    received_truncate_path_ = path;
-    received_truncate_offset_ = offset;
-
-    if (offset == kBasicFileTruncate_Offset) {
-      DidSucceed();
-    } else if (offset == kErrorFileTruncate_Offset) {
-      DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND);
-    } else if (offset == kCancelFileTruncate_Offset) {
-      cancel();
-      DidSucceed();  // truncate completion
-      DidSucceed();  // cancel completion
-    } else if (offset == kCancelFailedTruncate_Offset) {
-      cancel();
-      DidFail(base::PLATFORM_FILE_ERROR_NOT_FOUND);  // truncate completion
-      DidSucceed();  // cancel completion
-    } else {
-      FAIL();
-    }
-  }
-
-  virtual void DoWrite(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 DoCancel() OVERRIDE {
-    received_cancel_ = true;
-  }
-};
-
-class FileWriterTest : public testing::Test,
-                       public WebKit::WebFileWriterClient {
- public:
-  FileWriterTest() {
-    reset();
-  }
-
-  WebKit::WebFileWriter* writer() {
-    return testable_writer_.get();
-  }
-
-  // WebFileWriterClient overrides
-  virtual void didWrite(long long bytes, bool complete) {
-    EXPECT_FALSE(received_did_write_complete_);
-    ++received_did_write_count_;
-    received_did_write_bytes_total_ += bytes;
-    if (complete)
-      received_did_write_complete_ = true;
-
-    if (delete_in_client_callback_)
-      testable_writer_.reset(NULL);
-  }
-
-  virtual void didTruncate() {
-    EXPECT_FALSE(received_did_truncate_);
-    received_did_truncate_ = true;
-    if (delete_in_client_callback_)
-      testable_writer_.reset(NULL);
-  }
-
-  virtual void didFail(WebKit::WebFileError error) {
-    EXPECT_FALSE(received_did_fail_);
-    received_did_fail_ = true;
-    fail_error_received_ = error;
-    if (delete_in_client_callback_)
-      testable_writer_.reset(NULL);
-  }
-
- protected:
-  void reset() {
-    testable_writer_.reset(new TestableFileWriter(this));
-    delete_in_client_callback_ = false;
-    received_did_write_count_ = 0;
-    received_did_write_bytes_total_ = 0;
-    received_did_write_complete_ = false;
-    received_did_truncate_ = false;
-    received_did_fail_ = false;
-    fail_error_received_ = static_cast<WebKit::WebFileError>(0);
-  }
-
-  scoped_ptr<TestableFileWriter> testable_writer_;
-  bool delete_in_client_callback_;
-
-  // Observed WebFileWriterClient artifacts.
-  int received_did_write_count_;
-  long long received_did_write_bytes_total_;
-  bool received_did_write_complete_;
-  bool received_did_truncate_;
-  bool received_did_fail_;
-  WebKit::WebFileError fail_error_received_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileWriterTest);
-};
-
-TEST_F(FileWriterTest, BasicFileWrite) {
-  // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kBasicFileWrite_Offset, kBlobUrl);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_write_);
-  EXPECT_EQ(testable_writer_->received_write_path_,
-            mock_path_as_gurl());
-  EXPECT_EQ(kBasicFileWrite_Offset,
-            testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
-  EXPECT_FALSE(testable_writer_->received_truncate_);
-  EXPECT_FALSE(testable_writer_->received_cancel_);
-
-  // Check that the client gets called correctly.
-  EXPECT_EQ(1, received_did_write_count_);
-  EXPECT_TRUE(received_did_write_complete_);
-  EXPECT_EQ(1, received_did_write_bytes_total_);
-  EXPECT_FALSE(received_did_truncate_);
-  EXPECT_FALSE(received_did_fail_);
-}
-
-TEST_F(FileWriterTest, BasicFileTruncate) {
-  // Call the webkit facing api.
-  writer()->truncate(kBasicFileTruncate_Offset);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_truncate_);
-  EXPECT_EQ(mock_path_as_gurl(),
-            testable_writer_->received_truncate_path_);
-  EXPECT_EQ(kBasicFileTruncate_Offset,
-            testable_writer_->received_truncate_offset_);
-  EXPECT_FALSE(testable_writer_->received_write_);
-  EXPECT_FALSE(testable_writer_->received_cancel_);
-
-  // Check that the client gets called correctly.
-  EXPECT_TRUE(received_did_truncate_);
-  EXPECT_EQ(0, received_did_write_count_);
-  EXPECT_FALSE(received_did_fail_);
-}
-
-TEST_F(FileWriterTest, ErrorFileWrite) {
-  // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kErrorFileWrite_Offset, kBlobUrl);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_write_);
-  EXPECT_EQ(testable_writer_->received_write_path_,
-            mock_path_as_gurl());
-  EXPECT_EQ(kErrorFileWrite_Offset,
-            testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
-  EXPECT_FALSE(testable_writer_->received_truncate_);
-  EXPECT_FALSE(testable_writer_->received_cancel_);
-
-  // Check that the client gets called correctly.
-  EXPECT_TRUE(received_did_fail_);
-  EXPECT_EQ(WebKit::WebFileErrorNotFound, fail_error_received_);
-  EXPECT_EQ(0, received_did_write_count_);
-  EXPECT_FALSE(received_did_truncate_);
-}
-
-TEST_F(FileWriterTest, ErrorFileTruncate) {
-  // Call the webkit facing api.
-  writer()->truncate(kErrorFileTruncate_Offset);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_truncate_);
-  EXPECT_EQ(mock_path_as_gurl(),
-            testable_writer_->received_truncate_path_);
-  EXPECT_EQ(kErrorFileTruncate_Offset,
-            testable_writer_->received_truncate_offset_);
-  EXPECT_FALSE(testable_writer_->received_write_);
-  EXPECT_FALSE(testable_writer_->received_cancel_);
-
-  // Check that the client gets called correctly.
-  EXPECT_TRUE(received_did_fail_);
-  EXPECT_EQ(WebKit::WebFileErrorNotFound, fail_error_received_);
-  EXPECT_FALSE(received_did_truncate_);
-  EXPECT_EQ(0, received_did_write_count_);
-}
-
-TEST_F(FileWriterTest, MultiFileWrite) {
-  // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kMultiFileWrite_Offset, kBlobUrl);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_write_);
-  EXPECT_EQ(testable_writer_->received_write_path_,
-            mock_path_as_gurl());
-  EXPECT_EQ(kMultiFileWrite_Offset,
-            testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
-  EXPECT_FALSE(testable_writer_->received_truncate_);
-  EXPECT_FALSE(testable_writer_->received_cancel_);
-
-  // Check that the client gets called correctly.
-  EXPECT_EQ(3, received_did_write_count_);
-  EXPECT_TRUE(received_did_write_complete_);
-  EXPECT_EQ(3, received_did_write_bytes_total_);
-  EXPECT_FALSE(received_did_truncate_);
-  EXPECT_FALSE(received_did_fail_);
-}
-
-TEST_F(FileWriterTest, CancelFileWriteBeforeCompletion) {
-  // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kCancelFileWriteBeforeCompletion_Offset, kBlobUrl);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_write_);
-  EXPECT_EQ(testable_writer_->received_write_path_,
-            mock_path_as_gurl());
-  EXPECT_EQ(kCancelFileWriteBeforeCompletion_Offset,
-            testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
-  EXPECT_TRUE(testable_writer_->received_cancel_);
-  EXPECT_FALSE(testable_writer_->received_truncate_);
-
-  // Check that the client gets called correctly.
-  EXPECT_TRUE(received_did_fail_);
-  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
-  EXPECT_EQ(1, received_did_write_count_);
-  EXPECT_FALSE(received_did_write_complete_);
-  EXPECT_EQ(1, received_did_write_bytes_total_);
-  EXPECT_FALSE(received_did_truncate_);
-}
-
-TEST_F(FileWriterTest, CancelFileWriteAfterCompletion) {
-  // Call the webkit facing api.
-  const GURL kBlobUrl("blob://bloburl/");
-  writer()->write(kCancelFileWriteAfterCompletion_Offset, kBlobUrl);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_write_);
-  EXPECT_EQ(testable_writer_->received_write_path_,
-            mock_path_as_gurl());
-  EXPECT_EQ(kCancelFileWriteAfterCompletion_Offset,
-            testable_writer_->received_write_offset_);
-  EXPECT_EQ(kBlobUrl, testable_writer_->received_write_blob_url_);
-  EXPECT_TRUE(testable_writer_->received_cancel_);
-  EXPECT_FALSE(testable_writer_->received_truncate_);
-
-  // Check that the client gets called correctly.
-  EXPECT_TRUE(received_did_fail_);
-  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
-  EXPECT_EQ(1, received_did_write_count_);
-  EXPECT_FALSE(received_did_write_complete_);
-  EXPECT_EQ(1, received_did_write_bytes_total_);
-  EXPECT_FALSE(received_did_truncate_);
-}
-
-TEST_F(FileWriterTest, CancelFileTruncate) {
-  // Call the webkit facing api.
-  writer()->truncate(kCancelFileTruncate_Offset);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_truncate_);
-  EXPECT_EQ(mock_path_as_gurl(),
-            testable_writer_->received_truncate_path_);
-  EXPECT_EQ(kCancelFileTruncate_Offset,
-            testable_writer_->received_truncate_offset_);
-  EXPECT_TRUE(testable_writer_->received_cancel_);
-  EXPECT_FALSE(testable_writer_->received_write_);
-
-  // Check that the client gets called correctly.
-  EXPECT_TRUE(received_did_fail_);
-  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
-  EXPECT_FALSE(received_did_truncate_);
-  EXPECT_EQ(0, received_did_write_count_);
-}
-
-TEST_F(FileWriterTest, CancelFailedTruncate) {
-  // Call the webkit facing api.
-  writer()->truncate(kCancelFailedTruncate_Offset);
-
-  // Check that the derived class gets called correctly.
-  EXPECT_TRUE(testable_writer_->received_truncate_);
-  EXPECT_EQ(mock_path_as_gurl(),
-            testable_writer_->received_truncate_path_);
-  EXPECT_EQ(kCancelFailedTruncate_Offset,
-            testable_writer_->received_truncate_offset_);
-  EXPECT_TRUE(testable_writer_->received_cancel_);
-  EXPECT_FALSE(testable_writer_->received_write_);
-
-  // Check that the client gets called correctly.
-  EXPECT_TRUE(received_did_fail_);
-  EXPECT_EQ(WebKit::WebFileErrorAbort, fail_error_received_);
-  EXPECT_FALSE(received_did_truncate_);
-  EXPECT_EQ(0, received_did_write_count_);
-}
-
-TEST_F(FileWriterTest, DeleteInCompletionCallbacks) {
-  delete_in_client_callback_ = true;
-  writer()->write(kBasicFileWrite_Offset, GURL("blob://bloburl/"));
-  EXPECT_FALSE(testable_writer_.get());
-
-  reset();
-  delete_in_client_callback_ = true;
-  writer()->truncate(kBasicFileTruncate_Offset);
-  EXPECT_FALSE(testable_writer_.get());
-
-  reset();
-  delete_in_client_callback_ = true;
-  writer()->write(kErrorFileWrite_Offset, GURL("blob://bloburl/"));
-  EXPECT_FALSE(testable_writer_.get());
-
-  reset();
-  delete_in_client_callback_ = true;
-  writer()->truncate(kErrorFileTruncate_Offset);
-  EXPECT_FALSE(testable_writer_.get());
-
-  // Not crashing counts as passing.
-}
-
-}  // namespace fileapi
diff --git a/webkit/renderer/webkit_renderer.gyp b/webkit/renderer/webkit_renderer.gyp
index f698d8c..2e85bf9 100644
--- a/webkit/renderer/webkit_renderer.gyp
+++ b/webkit/renderer/webkit_renderer.gyp
@@ -30,8 +30,6 @@
         'clipboard_utils.cc',
         'clipboard_utils.h',
         'webkit_renderer_export.h',
-        'webpreferences_renderer.cc',
-        'webpreferences_renderer.h',
       ],
     },
   ],
diff --git a/webkit/renderer/webkit_renderer.target.darwin-arm.mk b/webkit/renderer/webkit_renderer.target.darwin-arm.mk
index 664f1ee..52a45f7 100644
--- a/webkit/renderer/webkit_renderer.target.darwin-arm.mk
+++ b/webkit/renderer/webkit_renderer.target.darwin-arm.mk
@@ -30,8 +30,7 @@
 LOCAL_SRC_FILES := \
 	webkit/renderer/cpp_bound_class.cc \
 	webkit/renderer/cpp_variant.cc \
-	webkit/renderer/clipboard_utils.cc \
-	webkit/renderer/webpreferences_renderer.cc
+	webkit/renderer/clipboard_utils.cc
 
 
 # Flags passed to both C and C++ files.
diff --git a/webkit/renderer/webkit_renderer.target.darwin-mips.mk b/webkit/renderer/webkit_renderer.target.darwin-mips.mk
index 48ce79b..e44f4b0 100644
--- a/webkit/renderer/webkit_renderer.target.darwin-mips.mk
+++ b/webkit/renderer/webkit_renderer.target.darwin-mips.mk
@@ -30,8 +30,7 @@
 LOCAL_SRC_FILES := \
 	webkit/renderer/cpp_bound_class.cc \
 	webkit/renderer/cpp_variant.cc \
-	webkit/renderer/clipboard_utils.cc \
-	webkit/renderer/webpreferences_renderer.cc
+	webkit/renderer/clipboard_utils.cc
 
 
 # Flags passed to both C and C++ files.
diff --git a/webkit/renderer/webkit_renderer.target.darwin-x86.mk b/webkit/renderer/webkit_renderer.target.darwin-x86.mk
index d183a66..b515e18 100644
--- a/webkit/renderer/webkit_renderer.target.darwin-x86.mk
+++ b/webkit/renderer/webkit_renderer.target.darwin-x86.mk
@@ -30,8 +30,7 @@
 LOCAL_SRC_FILES := \
 	webkit/renderer/cpp_bound_class.cc \
 	webkit/renderer/cpp_variant.cc \
-	webkit/renderer/clipboard_utils.cc \
-	webkit/renderer/webpreferences_renderer.cc
+	webkit/renderer/clipboard_utils.cc
 
 
 # Flags passed to both C and C++ files.
diff --git a/webkit/renderer/webkit_renderer.target.linux-arm.mk b/webkit/renderer/webkit_renderer.target.linux-arm.mk
index 664f1ee..52a45f7 100644
--- a/webkit/renderer/webkit_renderer.target.linux-arm.mk
+++ b/webkit/renderer/webkit_renderer.target.linux-arm.mk
@@ -30,8 +30,7 @@
 LOCAL_SRC_FILES := \
 	webkit/renderer/cpp_bound_class.cc \
 	webkit/renderer/cpp_variant.cc \
-	webkit/renderer/clipboard_utils.cc \
-	webkit/renderer/webpreferences_renderer.cc
+	webkit/renderer/clipboard_utils.cc
 
 
 # Flags passed to both C and C++ files.
diff --git a/webkit/renderer/webkit_renderer.target.linux-mips.mk b/webkit/renderer/webkit_renderer.target.linux-mips.mk
index 48ce79b..e44f4b0 100644
--- a/webkit/renderer/webkit_renderer.target.linux-mips.mk
+++ b/webkit/renderer/webkit_renderer.target.linux-mips.mk
@@ -30,8 +30,7 @@
 LOCAL_SRC_FILES := \
 	webkit/renderer/cpp_bound_class.cc \
 	webkit/renderer/cpp_variant.cc \
-	webkit/renderer/clipboard_utils.cc \
-	webkit/renderer/webpreferences_renderer.cc
+	webkit/renderer/clipboard_utils.cc
 
 
 # Flags passed to both C and C++ files.
diff --git a/webkit/renderer/webkit_renderer.target.linux-x86.mk b/webkit/renderer/webkit_renderer.target.linux-x86.mk
index d183a66..b515e18 100644
--- a/webkit/renderer/webkit_renderer.target.linux-x86.mk
+++ b/webkit/renderer/webkit_renderer.target.linux-x86.mk
@@ -30,8 +30,7 @@
 LOCAL_SRC_FILES := \
 	webkit/renderer/cpp_bound_class.cc \
 	webkit/renderer/cpp_variant.cc \
-	webkit/renderer/clipboard_utils.cc \
-	webkit/renderer/webpreferences_renderer.cc
+	webkit/renderer/clipboard_utils.cc
 
 
 # Flags passed to both C and C++ files.
diff --git a/webkit/renderer/webkit_storage_renderer_export.h b/webkit/renderer/webkit_storage_renderer_export.h
deleted file mode 100644
index 4225bc6..0000000
--- a/webkit/renderer/webkit_storage_renderer_export.h
+++ /dev/null
@@ -1,29 +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_RENDERER_WEBKIT_STORAGE_RENDERER_EXPORT_H_
-#define WEBKIT_RENDERER_WEBKIT_STORAGE_RENDERER_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(WEBKIT_STORAGE_RENDERER_IMPLEMENTATION)
-#define WEBKIT_STORAGE_RENDERER_EXPORT __declspec(dllexport)
-#else
-#define WEBKIT_STORAGE_RENDERER_EXPORT __declspec(dllimport)
-#endif  // defined(WEBKIT_STORAGE_RENDERER_IMPLEMENTATION)
-
-#else // defined(WIN32)
-#if defined(WEBKIT_STORAGE_RENDERER_IMPLEMENTATION)
-#define WEBKIT_STORAGE_RENDERER_EXPORT __attribute__((visibility("default")))
-#else
-#define WEBKIT_STORAGE_RENDERER_EXPORT
-#endif
-#endif
-
-#else // defined(COMPONENT_BUILD)
-#define WEBKIT_STORAGE_RENDERER_EXPORT
-#endif
-
-#endif  // WEBKIT_RENDERER_WEBKIT_STORAGE_RENDERER_EXPORT_H_
diff --git a/webkit/renderer/webpreferences_renderer.cc b/webkit/renderer/webpreferences_renderer.cc
deleted file mode 100644
index 0b07385..0000000
--- a/webkit/renderer/webpreferences_renderer.cc
+++ /dev/null
@@ -1,348 +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 "webkit/renderer/webpreferences_renderer.h"
-
-#include "base/strings/utf_string_conversions.h"
-#include "third_party/WebKit/public/web/WebKit.h"
-#include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
-#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
-#include "third_party/WebKit/public/web/WebSettings.h"
-#include "third_party/WebKit/public/web/WebView.h"
-#include "third_party/WebKit/public/platform/WebString.h"
-#include "third_party/WebKit/public/platform/WebURL.h"
-#include "third_party/icu/source/common/unicode/uchar.h"
-#include "third_party/icu/source/common/unicode/uscript.h"
-#include "webkit/common/webpreferences.h"
-
-using WebKit::WebNetworkStateNotifier;
-using WebKit::WebRuntimeFeatures;
-using WebKit::WebSettings;
-using WebKit::WebString;
-using WebKit::WebURL;
-using WebKit::WebView;
-
-namespace {
-
-typedef void (*SetFontFamilyWrapper)(
-    WebKit::WebSettings*, const base::string16&, UScriptCode);
-
-void setStandardFontFamilyWrapper(WebSettings* settings,
-                                  const base::string16& font,
-                                  UScriptCode script) {
-  settings->setStandardFontFamily(font, script);
-}
-
-void setFixedFontFamilyWrapper(WebSettings* settings,
-                               const base::string16& font,
-                               UScriptCode script) {
-  settings->setFixedFontFamily(font, script);
-}
-
-void setSerifFontFamilyWrapper(WebSettings* settings,
-                               const base::string16& font,
-                               UScriptCode script) {
-  settings->setSerifFontFamily(font, script);
-}
-
-void setSansSerifFontFamilyWrapper(WebSettings* settings,
-                                   const base::string16& font,
-                                   UScriptCode script) {
-  settings->setSansSerifFontFamily(font, script);
-}
-
-void setCursiveFontFamilyWrapper(WebSettings* settings,
-                                 const base::string16& font,
-                                 UScriptCode script) {
-  settings->setCursiveFontFamily(font, script);
-}
-
-void setFantasyFontFamilyWrapper(WebSettings* settings,
-                                 const base::string16& font,
-                                 UScriptCode script) {
-  settings->setFantasyFontFamily(font, script);
-}
-
-void setPictographFontFamilyWrapper(WebSettings* settings,
-                               const base::string16& font,
-                               UScriptCode script) {
-  settings->setPictographFontFamily(font, script);
-}
-
-// If |scriptCode| is a member of a family of "similar" script codes, returns
-// the script code in that family that is used by WebKit for font selection
-// purposes.  For example, USCRIPT_KATAKANA_OR_HIRAGANA and USCRIPT_JAPANESE are
-// considered equivalent for the purposes of font selection.  WebKit uses the
-// script code USCRIPT_KATAKANA_OR_HIRAGANA.  So, if |scriptCode| is
-// USCRIPT_JAPANESE, the function returns USCRIPT_KATAKANA_OR_HIRAGANA.  WebKit
-// uses different scripts than the ones in Chrome pref names because the version
-// of ICU included on certain ports does not have some of the newer scripts.  If
-// |scriptCode| is not a member of such a family, returns |scriptCode|.
-UScriptCode GetScriptForWebSettings(UScriptCode scriptCode) {
-  switch (scriptCode) {
-  case USCRIPT_HIRAGANA:
-  case USCRIPT_KATAKANA:
-  case USCRIPT_JAPANESE:
-    return USCRIPT_KATAKANA_OR_HIRAGANA;
-  case USCRIPT_KOREAN:
-    return USCRIPT_HANGUL;
-  default:
-    return scriptCode;
-  }
-}
-
-void ApplyFontsFromMap(const webkit_glue::ScriptFontFamilyMap& map,
-                       SetFontFamilyWrapper setter,
-                       WebSettings* settings) {
-  for (webkit_glue::ScriptFontFamilyMap::const_iterator it = map.begin();
-       it != map.end(); ++it) {
-    int32 script = u_getPropertyValueEnum(UCHAR_SCRIPT, (it->first).c_str());
-    if (script >= 0 && script < USCRIPT_CODE_LIMIT) {
-      UScriptCode code = static_cast<UScriptCode>(script);
-      (*setter)(settings, it->second, GetScriptForWebSettings(code));
-    }
-  }
-}
-
-}  // namespace
-
-namespace webkit_glue {
-
-void ApplyWebPreferences(const WebPreferences& prefs, WebView* web_view) {
-  WebSettings* settings = web_view->settings();
-  ApplyFontsFromMap(prefs.standard_font_family_map,
-                    setStandardFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.fixed_font_family_map,
-                    setFixedFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.serif_font_family_map,
-                    setSerifFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.sans_serif_font_family_map,
-                    setSansSerifFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.cursive_font_family_map,
-                    setCursiveFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.fantasy_font_family_map,
-                    setFantasyFontFamilyWrapper, settings);
-  ApplyFontsFromMap(prefs.pictograph_font_family_map,
-                    setPictographFontFamilyWrapper, settings);
-  settings->setDefaultFontSize(prefs.default_font_size);
-  settings->setDefaultFixedFontSize(prefs.default_fixed_font_size);
-  settings->setMinimumFontSize(prefs.minimum_font_size);
-  settings->setMinimumLogicalFontSize(prefs.minimum_logical_font_size);
-  settings->setDefaultTextEncodingName(ASCIIToUTF16(prefs.default_encoding));
-  settings->setJavaScriptEnabled(prefs.javascript_enabled);
-  settings->setWebSecurityEnabled(prefs.web_security_enabled);
-  settings->setJavaScriptCanOpenWindowsAutomatically(
-      prefs.javascript_can_open_windows_automatically);
-  settings->setLoadsImagesAutomatically(prefs.loads_images_automatically);
-  settings->setImagesEnabled(prefs.images_enabled);
-  settings->setPluginsEnabled(prefs.plugins_enabled);
-  settings->setDOMPasteAllowed(prefs.dom_paste_enabled);
-  settings->setNeedsSiteSpecificQuirks(prefs.site_specific_quirks_enabled);
-  settings->setShrinksStandaloneImagesToFit(
-      prefs.shrinks_standalone_images_to_fit);
-  settings->setUsesEncodingDetector(prefs.uses_universal_detector);
-  settings->setTextAreasAreResizable(prefs.text_areas_are_resizable);
-  settings->setAllowScriptsToCloseWindows(prefs.allow_scripts_to_close_windows);
-  if (prefs.user_style_sheet_enabled)
-    settings->setUserStyleSheetLocation(prefs.user_style_sheet_location);
-  else
-    settings->setUserStyleSheetLocation(WebURL());
-  settings->setAuthorAndUserStylesEnabled(prefs.author_and_user_styles_enabled);
-  settings->setDownloadableBinaryFontsEnabled(prefs.remote_fonts_enabled);
-  settings->setJavaScriptCanAccessClipboard(
-      prefs.javascript_can_access_clipboard);
-  settings->setXSSAuditorEnabled(prefs.xss_auditor_enabled);
-  settings->setDNSPrefetchingEnabled(prefs.dns_prefetching_enabled);
-  settings->setLocalStorageEnabled(prefs.local_storage_enabled);
-  settings->setSyncXHRInDocumentsEnabled(prefs.sync_xhr_in_documents_enabled);
-  WebRuntimeFeatures::enableDatabase(prefs.databases_enabled);
-  settings->setOfflineWebApplicationCacheEnabled(
-      prefs.application_cache_enabled);
-  settings->setCaretBrowsingEnabled(prefs.caret_browsing_enabled);
-  settings->setHyperlinkAuditingEnabled(prefs.hyperlink_auditing_enabled);
-  settings->setCookieEnabled(prefs.cookie_enabled);
-
-  // This setting affects the behavior of links in an editable region:
-  // clicking the link should select it rather than navigate to it.
-  // Safari uses the same default. It is unlikley an embedder would want to
-  // change this, since it would break existing rich text editors.
-  settings->setEditableLinkBehaviorNeverLive();
-
-  settings->setJavaEnabled(prefs.java_enabled);
-
-  // By default, allow_universal_access_from_file_urls is set to false and thus
-  // we mitigate attacks from local HTML files by not granting file:// URLs
-  // universal access. Only test shell will enable this.
-  settings->setAllowUniversalAccessFromFileURLs(
-      prefs.allow_universal_access_from_file_urls);
-  settings->setAllowFileAccessFromFileURLs(
-      prefs.allow_file_access_from_file_urls);
-
-  // Enable the web audio API if requested on the command line.
-  settings->setWebAudioEnabled(prefs.webaudio_enabled);
-
-  // Enable experimental WebGL support if requested on command line
-  // and support is compiled in.
-  settings->setExperimentalWebGLEnabled(prefs.experimental_webgl_enabled);
-
-  // Disable GL multisampling if requested on command line.
-  settings->setOpenGLMultisamplingEnabled(prefs.gl_multisampling_enabled);
-
-  // Enable privileged WebGL extensions for Chrome extensions or if requested
-  // on command line.
-  settings->setPrivilegedWebGLExtensionsEnabled(
-      prefs.privileged_webgl_extensions_enabled);
-
-  // Enable WebGL errors to the JS console if requested.
-  settings->setWebGLErrorsToConsoleEnabled(
-      prefs.webgl_errors_to_console_enabled);
-
-  // Enables accelerated compositing for overflow scroll.
-  settings->setAcceleratedCompositingForOverflowScrollEnabled(
-      prefs.accelerated_compositing_for_overflow_scroll_enabled);
-
-  // Enables accelerated compositing for scrollable frames if requested on
-  // command line.
-  settings->setAcceleratedCompositingForScrollableFramesEnabled(
-      prefs.accelerated_compositing_for_scrollable_frames_enabled);
-
-  // Enables composited scrolling for frames if requested on command line.
-  settings->setCompositedScrollingForFramesEnabled(
-      prefs.composited_scrolling_for_frames_enabled);
-
-  // Uses the mock theme engine for scrollbars.
-  settings->setMockScrollbarsEnabled(prefs.mock_scrollbars_enabled);
-
-  settings->setThreadedHTMLParser(prefs.threaded_html_parser);
-
-  // Display visualization of what has changed on the screen using an
-  // overlay of rects, if requested on the command line.
-  settings->setShowPaintRects(prefs.show_paint_rects);
-
-  // Enable gpu-accelerated compositing if requested on the command line.
-  settings->setAcceleratedCompositingEnabled(
-      prefs.accelerated_compositing_enabled);
-
-  // Enable gpu-accelerated 2d canvas if requested on the command line.
-  settings->setAccelerated2dCanvasEnabled(prefs.accelerated_2d_canvas_enabled);
-
-  settings->setMinimumAccelerated2dCanvasSize(
-      prefs.minimum_accelerated_2d_canvas_size);
-
-  // Disable antialiasing for 2d canvas if requested on the command line.
-  settings->setAntialiased2dCanvasEnabled(
-      !prefs.antialiased_2d_canvas_disabled);
-
-  // Enable gpu-accelerated filters if requested on the command line.
-  settings->setAcceleratedFiltersEnabled(prefs.accelerated_filters_enabled);
-
-  // Enable gesture tap highlight if requested on the command line.
-  settings->setGestureTapHighlightEnabled(prefs.gesture_tap_highlight_enabled);
-
-  // Enabling accelerated layers from the command line enabled accelerated
-  // 3D CSS, Video, and Animations.
-  settings->setAcceleratedCompositingFor3DTransformsEnabled(
-      prefs.accelerated_compositing_for_3d_transforms_enabled);
-  settings->setAcceleratedCompositingForVideoEnabled(
-      prefs.accelerated_compositing_for_video_enabled);
-  settings->setAcceleratedCompositingForAnimationEnabled(
-      prefs.accelerated_compositing_for_animation_enabled);
-
-  // Enabling accelerated plugins if specified from the command line.
-  settings->setAcceleratedCompositingForPluginsEnabled(
-      prefs.accelerated_compositing_for_plugins_enabled);
-
-  // WebGL and accelerated 2D canvas are always gpu composited.
-  settings->setAcceleratedCompositingForCanvasEnabled(
-      prefs.experimental_webgl_enabled || prefs.accelerated_2d_canvas_enabled);
-
-  // Enable memory info reporting to page if requested on the command line.
-  settings->setMemoryInfoEnabled(prefs.memory_info_enabled);
-
-  settings->setAsynchronousSpellCheckingEnabled(
-      prefs.asynchronous_spell_checking_enabled);
-  settings->setUnifiedTextCheckerEnabled(prefs.unified_textchecker_enabled);
-
-  for (webkit_glue::WebInspectorPreferences::const_iterator it =
-           prefs.inspector_settings.begin();
-       it != prefs.inspector_settings.end(); ++it)
-    web_view->setInspectorSetting(WebString::fromUTF8(it->first),
-                                  WebString::fromUTF8(it->second));
-
-  // Tabs to link is not part of the settings. WebCore calls
-  // ChromeClient::tabsToLinks which is part of the glue code.
-  web_view->setTabsToLinks(prefs.tabs_to_links);
-
-  settings->setFullScreenEnabled(prefs.fullscreen_enabled);
-  settings->setAllowDisplayOfInsecureContent(
-      prefs.allow_displaying_insecure_content);
-  settings->setAllowRunningOfInsecureContent(
-      prefs.allow_running_insecure_content);
-  settings->setPasswordEchoEnabled(prefs.password_echo_enabled);
-  settings->setShouldPrintBackgrounds(prefs.should_print_backgrounds);
-  settings->setEnableScrollAnimator(prefs.enable_scroll_animator);
-  settings->setVisualWordMovementEnabled(prefs.visual_word_movement_enabled);
-
-  settings->setCSSStickyPositionEnabled(prefs.css_sticky_position_enabled);
-  settings->setExperimentalCSSCustomFilterEnabled(prefs.css_shaders_enabled);
-  settings->setRegionBasedColumnsEnabled(prefs.region_based_columns_enabled);
-
-  WebRuntimeFeatures::enableLazyLayout(prefs.lazy_layout_enabled);
-  WebRuntimeFeatures::enableTouch(prefs.touch_enabled);
-  settings->setDeviceSupportsTouch(prefs.device_supports_touch);
-  settings->setDeviceSupportsMouse(prefs.device_supports_mouse);
-  settings->setEnableTouchAdjustment(prefs.touch_adjustment_enabled);
-
-  settings->setFixedPositionCreatesStackingContext(
-      prefs.fixed_position_creates_stacking_context);
-
-  settings->setDeferredImageDecodingEnabled(
-      prefs.deferred_image_decoding_enabled);
-  settings->setShouldRespectImageOrientation(
-      prefs.should_respect_image_orientation);
-
-  settings->setUnsafePluginPastingEnabled(false);
-  settings->setEditingBehavior(
-      static_cast<WebSettings::EditingBehavior>(prefs.editing_behavior));
-
-  settings->setSupportsMultipleWindows(prefs.supports_multiple_windows);
-
-  settings->setViewportEnabled(prefs.viewport_enabled);
-  settings->setInitializeAtMinimumPageScale(
-      prefs.initialize_at_minimum_page_scale);
-
-  settings->setSmartInsertDeleteEnabled(prefs.smart_insert_delete_enabled);
-
-  settings->setSpatialNavigationEnabled(prefs.spatial_navigation_enabled);
-
-  settings->setSelectionIncludesAltImageText(true);
-
-#if defined(OS_ANDROID)
-  settings->setAllowCustomScrollbarInMainFrame(false);
-  settings->setTextAutosizingEnabled(prefs.text_autosizing_enabled);
-  settings->setTextAutosizingFontScaleFactor(prefs.font_scale_factor);
-  web_view->setIgnoreViewportTagScaleLimits(prefs.force_enable_zoom);
-  settings->setAutoZoomFocusedNodeToLegibleScale(true);
-  settings->setDoubleTapToZoomEnabled(prefs.double_tap_to_zoom_enabled);
-  settings->setMediaPlaybackRequiresUserGesture(
-      prefs.user_gesture_required_for_media_playback);
-  settings->setDefaultVideoPosterURL(
-        ASCIIToUTF16(prefs.default_video_poster_url.spec()));
-  settings->setSupportDeprecatedTargetDensityDPI(
-      prefs.support_deprecated_target_density_dpi);
-  settings->setUseWideViewport(prefs.use_wide_viewport);
-#endif
-
-  WebNetworkStateNotifier::setOnLine(prefs.is_online);
-  settings->setExperimentalWebSocketEnabled(
-      prefs.experimental_websocket_enabled);
-  settings->setPinchVirtualViewportEnabled(
-      prefs.pinch_virtual_viewport_enabled);
-
-  settings->setPinchOverlayScrollbarThickness(
-      prefs.pinch_overlay_scrollbar_thickness);
-}
-
-
-}  // namespace webkit_glue
diff --git a/webkit/renderer/webpreferences_renderer.h b/webkit/renderer/webpreferences_renderer.h
deleted file mode 100644
index ad7305a..0000000
--- a/webkit/renderer/webpreferences_renderer.h
+++ /dev/null
@@ -1,24 +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 WEBKIT_RENDERER_WEBPREFERENCES_RENDERER_H_
-#define WEBKIT_RENDERER_WEBPREFERENCES_RENDERER_H_
-
-#include "webkit/renderer/webkit_renderer_export.h"
-
-namespace WebKit {
-class WebView;
-}
-
-struct WebPreferences;
-
-namespace webkit_glue {
-
-WEBKIT_RENDERER_EXPORT void ApplyWebPreferences(
-    const WebPreferences& prefs,
-    WebKit::WebView* web_view);
-
-}  // namespace webkit_glue
-
-#endif  // WEBKIT_RENDERER_WEBPREFERENCES_RENDERER_H_
diff --git a/webkit/storage_browser.gyp b/webkit/storage_browser.gyp
index 04e609a..04d2565 100644
--- a/webkit/storage_browser.gyp
+++ b/webkit/storage_browser.gyp
@@ -154,14 +154,14 @@
         'browser/fileapi/recursive_operation_delegate.h',
         'browser/fileapi/remove_operation_delegate.cc',
         'browser/fileapi/remove_operation_delegate.h',
-        'browser/fileapi/sandbox_context.cc',
-        'browser/fileapi/sandbox_context.h',
         'browser/fileapi/sandbox_directory_database.cc',
         'browser/fileapi/sandbox_directory_database.h',
         'browser/fileapi/sandbox_file_stream_writer.cc',
         'browser/fileapi/sandbox_file_stream_writer.h',
         'browser/fileapi/sandbox_file_system_backend.cc',
         'browser/fileapi/sandbox_file_system_backend.h',
+        'browser/fileapi/sandbox_file_system_backend_delegate.cc',
+        'browser/fileapi/sandbox_file_system_backend_delegate.h',
         'browser/fileapi/sandbox_isolated_origin_database.cc',
         'browser/fileapi/sandbox_isolated_origin_database.h',
         'browser/fileapi/sandbox_origin_database.cc',
diff --git a/webkit/storage_renderer.gyp b/webkit/storage_renderer.gyp
deleted file mode 100644
index dc406e2..0000000
--- a/webkit/storage_renderer.gyp
+++ /dev/null
@@ -1,29 +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.
-
-{
-  'targets': [
-    {
-      'target_name': 'webkit_storage_renderer',
-      'type': '<(component)',
-      'variables': { 'enable_wexit_time_destructors': 1, },
-      'dependencies': [
-        '<(DEPTH)/base/base.gyp:base',
-        '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
-        '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink',
-        '<(DEPTH)/url/url.gyp:url_lib',
-        '<(DEPTH)/webkit/common/webkit_common.gyp:webkit_common',
-        '<(DEPTH)/webkit/storage_common.gyp:webkit_storage_common',
-      ],
-      'defines': ['WEBKIT_STORAGE_RENDERER_IMPLEMENTATION'],
-      'sources': [
-        'renderer/webkit_storage_renderer_export.h',
-        'renderer/fileapi/webfilewriter_base.cc',
-        'renderer/fileapi/webfilewriter_base.h',
-      ],
-      # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-      'msvs_disabled_warnings': [ 4267, ],
-    },
-  ],
-}
diff --git a/webkit/support/drt_application_mac.h b/webkit/support/drt_application_mac.h
deleted file mode 100644
index 969894f..0000000
--- a/webkit/support/drt_application_mac.h
+++ /dev/null
@@ -1,23 +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 WEBKIT_SUPPORT_DRT_APPLICATION_MAC_H
-#define WEBKIT_SUPPORT_DRT_APPLICATION_MAC_H
-
-#include "base/mac/scoped_sending_event.h"
-#include "base/message_loop/message_pump_mac.h"
-
-@interface CrDrtApplication : NSApplication<CrAppProtocol,
-                                            CrAppControlProtocol> {
- @private
-  BOOL handlingSendEvent_;
-}
-// CrAppProtocol
-- (BOOL)isHandlingSendEvent;
-
-// CrAppControlProtocol
-- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
-@end
-
-#endif  // WEBKIT_SUPPORT_DRT_APPLICATION_MAC_H
diff --git a/webkit/support/drt_application_mac.mm b/webkit/support/drt_application_mac.mm
deleted file mode 100644
index 0c2f900..0000000
--- a/webkit/support/drt_application_mac.mm
+++ /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.
-
-#include "webkit/support/drt_application_mac.h"
-
-#include "base/auto_reset.h"
-
-@implementation CrDrtApplication
-
-- (BOOL)isHandlingSendEvent {
-  return handlingSendEvent_;
-}
-
-- (void)sendEvent:(NSEvent*)event {
-  base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
-  [super sendEvent:event];
-}
-
-- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
-  handlingSendEvent_ = handlingSendEvent;
-}
-
-@end
diff --git a/webkit/support/mac/DumpRenderTreePasteboard.h b/webkit/support/mac/DumpRenderTreePasteboard.h
deleted file mode 100644
index 41796ea..0000000
--- a/webkit/support/mac/DumpRenderTreePasteboard.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007 Apple, Inc.  All rights reserved.
- *           (C) 2007 Graham Dennis (graham.dennis@gmail.com)
- *           (C) 2007 Eric Seidel <eric@webkit.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-//
-// This file comes from WebKit:
-//    WebKit/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m
-// It is copied here since that location is the best for pulling into Chromium
-// and has a few includes commented out.  darin@chromium.org suggests in the
-// future we see if there is a better place for it to live so it could be
-// shared.
-//
-
-#import <AppKit/AppKit.h>
-// #import <WebKit/WebTypesInternal.h>
-
-@interface DumpRenderTreePasteboard : NSPasteboard
-- (NSInteger)declareType:(NSString *)type owner:(id)newOwner;
-+ (void)releaseLocalPasteboards;
-@end
diff --git a/webkit/support/mac/DumpRenderTreePasteboard.m b/webkit/support/mac/DumpRenderTreePasteboard.m
deleted file mode 100644
index 3e3cf1c..0000000
--- a/webkit/support/mac/DumpRenderTreePasteboard.m
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007 Apple, Inc.  All rights reserved.
- *           (C) 2007 Graham Dennis (graham.dennis@gmail.com)
- *           (C) 2007 Eric Seidel <eric@webkit.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-//
-// This file comes from WebKit:
-//    WebKit/Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.m
-// It is copied here since that location is the best for pulling into Chromium
-// and has a few includes commented out.  darin@chromium.org suggests in the
-// future we see if there is a better place for it to live so it could be
-// shared.
-//
-
-// #import "DumpRenderTreeMac.h"
-#import "DumpRenderTreePasteboard.h"
-
-// #import <WebKit/WebTypesInternal.h>
-
-@interface LocalPasteboard : NSPasteboard
-{
-    NSMutableArray *typesArray;
-    NSMutableSet *typesSet;
-    NSMutableDictionary *dataByType;
-    NSInteger changeCount;
-}
-@end
-
-static NSMutableDictionary *localPasteboards;
-
-@implementation DumpRenderTreePasteboard
-
-// Return a local pasteboard so we don't disturb the real pasteboards when running tests.
-+ (NSPasteboard *)_pasteboardWithName:(NSString *)name
-{
-    static int number = 0;
-    if (!name)
-        name = [NSString stringWithFormat:@"LocalPasteboard%d", ++number];
-    if (!localPasteboards)
-        localPasteboards = [[NSMutableDictionary alloc] init];
-    LocalPasteboard *pasteboard = [localPasteboards objectForKey:name];
-    if (pasteboard)
-        return pasteboard;
-    pasteboard = [[LocalPasteboard alloc] init];
-    [localPasteboards setObject:pasteboard forKey:name];
-    [pasteboard release];
-    return pasteboard;
-}
-
-+ (void)releaseLocalPasteboards
-{
-    [localPasteboards release];
-    localPasteboards = nil;
-}
-
-// Convenience method for JS so that it doesn't have to try and create a NSArray on the objc side instead
-// of the usual WebScriptObject that is passed around
-- (NSInteger)declareType:(NSString *)type owner:(id)newOwner
-{
-    return [self declareTypes:[NSArray arrayWithObject:type] owner:newOwner];
-}
-
-@end
-
-@implementation LocalPasteboard
-
-+ (id)alloc
-{
-    return NSAllocateObject(self, 0, 0);
-}
-
-- (id)init
-{
-    typesArray = [[NSMutableArray alloc] init];
-    typesSet = [[NSMutableSet alloc] init];
-    dataByType = [[NSMutableDictionary alloc] init];
-    return self;
-}
-
-- (void)dealloc
-{
-    [typesArray release];
-    [typesSet release];
-    [dataByType release];
-    [super dealloc];
-}
-
-- (NSString *)name
-{
-    return nil;
-}
-
-- (void)releaseGlobally
-{
-}
-
-- (NSInteger)declareTypes:(NSArray *)newTypes owner:(id)newOwner
-{
-    [typesArray removeAllObjects];
-    [typesSet removeAllObjects];
-    [dataByType removeAllObjects];
-    return [self addTypes:newTypes owner:newOwner];
-}
-
-- (NSInteger)addTypes:(NSArray *)newTypes owner:(id)newOwner
-{
-    unsigned count = [newTypes count];
-    unsigned i;
-    for (i = 0; i < count; ++i) {
-        NSString *type = [newTypes objectAtIndex:i];
-        NSString *setType = [typesSet member:type];
-        if (!setType) {
-            setType = [type copy];
-            [typesArray addObject:setType];
-            [typesSet addObject:setType];
-            [setType release];
-        }
-        if (newOwner && [newOwner respondsToSelector:@selector(pasteboard:provideDataForType:)])
-            [newOwner pasteboard:self provideDataForType:setType];
-    }
-    return ++changeCount;
-}
-
-- (NSInteger)changeCount
-{
-    return changeCount;
-}
-
-- (NSArray *)types
-{
-    return typesArray;
-}
-
-- (NSString *)availableTypeFromArray:(NSArray *)types
-{
-    unsigned count = [types count];
-    unsigned i;
-    for (i = 0; i < count; ++i) {
-        NSString *type = [types objectAtIndex:i];
-        NSString *setType = [typesSet member:type];
-        if (setType)
-            return setType;
-    }
-    return nil;
-}
-
-- (BOOL)setData:(NSData *)data forType:(NSString *)dataType
-{
-    if (data == nil)
-        data = [NSData data];
-    if (![typesSet containsObject:dataType])
-        return NO;
-    [dataByType setObject:data forKey:dataType];
-    ++changeCount;
-    return YES;
-}
-
-- (NSData *)dataForType:(NSString *)dataType
-{
-    return [dataByType objectForKey:dataType];
-}
-
-- (BOOL)setPropertyList:(id)propertyList forType:(NSString *)dataType
-{
-    CFDataRef data = NULL;
-    if (propertyList)
-        data = CFPropertyListCreateXMLData(NULL, propertyList);
-    BOOL result = [self setData:(NSData *)data forType:dataType];
-    if (data)
-        CFRelease(data);
-    return result;
-}
-
-- (BOOL)setString:(NSString *)string forType:(NSString *)dataType
-{
-    CFDataRef data = NULL;
-    if (string) {
-        if ([string length] == 0)
-            data = CFDataCreate(NULL, NULL, 0);
-        else
-            data = CFStringCreateExternalRepresentation(NULL, (CFStringRef)string, kCFStringEncodingUTF8, 0);
-    }
-    BOOL result = [self setData:(NSData *)data forType:dataType];
-    if (data)
-        CFRelease(data);
-    return result;
-}
-
-@end
diff --git a/webkit/support/platform_support.h b/webkit/support/platform_support.h
deleted file mode 100644
index 73ab950..0000000
--- a/webkit/support/platform_support.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.
-
-#ifndef WEBKIT_SUPPORT_PLATFORM_SUPORT_H_
-#define WEBKIT_SUPPORT_PLATFORM_SUPORT_H_
-
-namespace webkit_support {
-// Called before WebKit::initialize().
-void BeforeInitialize();
-
-// Called after WebKit::initialize().
-void AfterInitialize();
-
-// Called before WebKit::shutdown().
-void BeforeShutdown();
-
-// Called after WebKit::shutdown().
-void AfterShutdown();
-}  // namespace webkit_support
-
-#endif  // WEBKIT_SUPPORT_PLATFORM_SUPORT_H_
diff --git a/webkit/support/platform_support_android.cc b/webkit/support/platform_support_android.cc
deleted file mode 100644
index 582dc3a..0000000
--- a/webkit/support/platform_support_android.cc
+++ /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.
-
-#include "webkit/support/platform_support.h"
-
-#include "base/android/jni_android.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/string_piece.h"
-#include "base/test/test_support_android.h"
-#include "grit/webkit_resources.h"
-#include "media/base/android/media_jni_registrar.h"
-#include "net/android/net_jni_registrar.h"
-#include "net/android/network_library.h"
-#include "ui/android/ui_jni_registrar.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gl/android/gl_jni_registrar.h"
-#include "url/gurl.h"
-#include "webkit/support/test_webkit_platform_support.h"
-
-namespace {
-
-// The place where the Android layout test script will put the required tools
-// and resources. Must keep consistent with DEVICE_DRT_DIR in
-// WebKit/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py.
-const char kDumpRenderTreeDir[] = "/data/local/tmp/drt";
-
-}
-
-namespace webkit_support {
-
-void BeforeInitialize() {
-  base::InitAndroidTestPaths();
-
-  // Place cache under kDumpRenderTreeDir to allow the NRWT script to clear it.
-  base::FilePath path(kDumpRenderTreeDir);
-  path = path.Append("cache");
-  PathService::Override(base::DIR_CACHE, path);
-
-  // Set XML_CATALOG_FILES environment variable to blank to prevent libxml from
-  // loading and complaining the non-exsistent /etc/xml/catalog file.
-  setenv("XML_CATALOG_FILES", "", 0);
-
-  JNIEnv* env = base::android::AttachCurrentThread();
-  net::android::RegisterNetworkLibrary(env);
-}
-
-void AfterInitialize() {
-}
-
-void BeforeShutdown() {
-}
-
-void AfterShutdown() {
-}
-
-}  // namespace webkit_support
-
diff --git a/webkit/support/platform_support_linux.cc b/webkit/support/platform_support_linux.cc
deleted file mode 100644
index 85cc841..0000000
--- a/webkit/support/platform_support_linux.cc
+++ /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.
-
-#include "webkit/support/platform_support.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/string_piece.h"
-#include "grit/webkit_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "webkit/support/test_webkit_platform_support.h"
-
-namespace webkit_support {
-
-// TODO(tkent): Implement some of the followings for platform-dependent tasks
-// such as loading resource.
-
-void BeforeInitialize() {
-}
-
-void AfterInitialize() {
-}
-
-void BeforeShutdown() {
-}
-
-void AfterShutdown() {
-}
-
-}  // namespace webkit_support
-
diff --git a/webkit/support/platform_support_mac.mm b/webkit/support/platform_support_mac.mm
deleted file mode 100644
index 6d96ec1..0000000
--- a/webkit/support/platform_support_mac.mm
+++ /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.
-
-#include "webkit/support/platform_support.h"
-
-#import <AppKit/AppKit.h>
-#include <AvailabilityMacros.h>
-#import <Foundation/Foundation.h>
-#import <objc/objc-runtime.h>
-
-#include "base/base_paths.h"
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "grit/webkit_resources.h"
-#include "ui/base/resource/data_pack.h"
-#import "webkit/support/drt_application_mac.h"
-#import "webkit/support/mac/DumpRenderTreePasteboard.h"
-#include "webkit/support/test_webkit_platform_support.h"
-
-namespace webkit_support {
-
-static NSAutoreleasePool* autorelease_pool;
-
-void BeforeInitialize() {
-  [CrDrtApplication sharedApplication];
-  autorelease_pool = [[NSAutoreleasePool alloc] init];
-  DCHECK(autorelease_pool);
-}
-
-void AfterInitialize() {
-}
-
-void BeforeShutdown() {
-}
-
-void AfterShutdown() {
-  [DumpRenderTreePasteboard releaseLocalPasteboards];
-  [autorelease_pool drain];
-}
-
-}  // namespace webkit_support
-
diff --git a/webkit/support/platform_support_win.cc b/webkit/support/platform_support_win.cc
deleted file mode 100644
index ce601c5..0000000
--- a/webkit/support/platform_support_win.cc
+++ /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.
-
-#include "webkit/support/platform_support.h"
-
-#include "base/base_paths.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/string_piece.h"
-#include "base/win/resource_util.h"
-#include "grit/blink_resources.h"
-#include "grit/webkit_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "webkit/support/test_webkit_platform_support.h"
-
-
-namespace webkit_support {
-
-void BeforeInitialize() {
-}
-
-void AfterInitialize() {
-}
-
-void BeforeShutdown() {
-}
-
-void AfterShutdown() {
-}
-
-}  // namespace webkit_support
-
diff --git a/webkit/support/web_layer_tree_view_impl_for_testing.cc b/webkit/support/web_layer_tree_view_impl_for_testing.cc
index e4b858c..93bfcbe 100644
--- a/webkit/support/web_layer_tree_view_impl_for_testing.cc
+++ b/webkit/support/web_layer_tree_view_impl_for_testing.cc
@@ -8,12 +8,10 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/lock.h"
 #include "cc/base/switches.h"
-#include "cc/debug/fake_web_graphics_context_3d.h"
+#include "cc/debug/test_context_provider.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/output/software_output_device.h"
 #include "cc/trees/layer_tree_host.h"
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
@@ -159,11 +157,8 @@
 
 scoped_ptr<cc::OutputSurface>
 WebLayerTreeViewImplForTesting::CreateOutputSurface(bool fallback) {
-  scoped_ptr<cc::OutputSurface> surface;
-  scoped_ptr<WebGraphicsContext3D> context3d(
-      new cc::FakeWebGraphicsContext3D);
-  surface.reset(new cc::OutputSurface(context3d.Pass()));
-  return surface.Pass();
+  return make_scoped_ptr(
+      new cc::OutputSurface(cc::TestContextProvider::Create()));
 }
 
 void WebLayerTreeViewImplForTesting::ScheduleComposite() {
diff --git a/webkit/support/webkit_support.cc b/webkit/support/webkit_support.cc
index c584638..6f9d41a 100644
--- a/webkit/support/webkit_support.cc
+++ b/webkit/support/webkit_support.cc
@@ -4,78 +4,27 @@
 
 #include "webkit/support/webkit_support.h"
 
-#include "base/command_line.h"
-#include "base/debug/debugger.h"
-#include "base/debug/stack_trace.h"
-#include "base/logging.h"
 #include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/process/memory.h"
 #include "base/run_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebCache.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "url/url_util.h"
-#include "webkit/child/webkitplatformsupport_impl.h"
 #include "webkit/common/user_agent/user_agent.h"
 #include "webkit/common/user_agent/user_agent_util.h"
-#include "webkit/glue/webkit_glue.h"
-#include "webkit/support/platform_support.h"
 #include "webkit/support/test_webkit_platform_support.h"
 
 #if defined(OS_ANDROID)
-#include "base/test/test_support_android.h"
+#include "base/android/jni_android.h"
+#include "net/android/network_library.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/test/mock_chrome_application_mac.h"
 #endif
 
 namespace {
 
-// All fatal log messages (e.g. DCHECK failures) imply unit test failures
-void UnitTestAssertHandler(const std::string& str) {
-  FAIL() << str;
-}
-
-void InitLogging() {
-#if defined(OS_WIN)
-  if (!::IsDebuggerPresent()) {
-    UINT new_flags = SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX
-        | SEM_NOGPFAULTERRORBOX;
-
-    // Preserve existing error mode, as discussed at
-    // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
-    UINT existing_flags = SetErrorMode(new_flags);
-    SetErrorMode(existing_flags | new_flags);
-
-    // Don't pop up dialog on assertion failure, log to stdout instead.
-    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
-    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
-  }
-#endif
-
-#if defined(OS_ANDROID)
-  // On Android we expect the log to appear in logcat.
-  base::InitAndroidTestLogging();
-#else
-  base::FilePath log_filename;
-  PathService::Get(base::DIR_EXE, &log_filename);
-  log_filename = log_filename.AppendASCII("DumpRenderTree.log");
-  logging::LoggingSettings settings;
-  // Only log to a file. This prevents debugging output from disrupting
-  // whether or not we pass.
-  settings.logging_dest = logging::LOG_TO_FILE;
-  settings.log_file = log_filename.value().c_str();
-  settings.delete_old = logging::DELETE_OLD_LOG_FILE;
-  logging::InitLogging(settings);
-
-  // We want process and thread IDs because we may have multiple processes.
-  const bool kProcessId = true;
-  const bool kThreadId = true;
-  const bool kTimestamp = true;
-  const bool kTickcount = true;
-  logging::SetLogItems(kProcessId, kThreadId, !kTimestamp, kTickcount);
-#endif  // else defined(OS_ANDROID)
-}
-
 class TestEnvironment {
  public:
 #if defined(OS_ANDROID)
@@ -86,7 +35,6 @@
 #endif
 
   TestEnvironment() {
-    logging::SetLogAssertHandler(UnitTestAssertHandler);
     main_message_loop_.reset(new MessageLoopType);
 
     // TestWebKitPlatformSupport must be instantiated after MessageLoopType.
@@ -109,30 +57,24 @@
 namespace webkit_support {
 
 void SetUpTestEnvironmentForUnitTests() {
-  base::debug::EnableInProcessStackDumping();
-  base::EnableTerminationOnHeapCorruption();
-
-  // Initialize the singleton CommandLine with fixed values.  Some code refer to
-  // CommandLine::ForCurrentProcess().  We don't use the actual command-line
-  // arguments of DRT to avoid unexpected behavior change.
-  //
-  // webkit/glue/plugin/plugin_list_posix.cc checks --debug-plugin-loading.
-  // webkit/glue/plugin/plugin_list_win.cc checks --old-wmp.
-  // If DRT needs these flags, specify them in the following kFixedArguments.
-  const char* kFixedArguments[] = {"DumpRenderTree"};
-  CommandLine::Init(arraysize(kFixedArguments), kFixedArguments);
-
   WebKit::WebRuntimeFeatures::enableStableFeatures(true);
   WebKit::WebRuntimeFeatures::enableExperimentalFeatures(true);
   WebKit::WebRuntimeFeatures::enableTestOnlyFeatures(true);
 
+#if defined(OS_ANDROID)
+  JNIEnv* env = base::android::AttachCurrentThread();
+  net::android::RegisterNetworkLibrary(env);
+#endif
+
+#if defined(OS_MACOSX)
+  mock_cr_app::RegisterMockCrApp();
+#endif
+
   // Explicitly initialize the GURL library before spawning any threads.
   // Otherwise crash may happend when different threads try to create a GURL
   // at same time.
   url_util::Initialize();
-  webkit_support::BeforeInitialize();
   test_environment = new TestEnvironment;
-  webkit_support::AfterInitialize();
   webkit_glue::SetUserAgent(webkit_glue::BuildUserAgentFromProduct(
       "DumpRenderTree/0.0.0.0"), false);
 }
@@ -142,14 +84,11 @@
   // http://code.google.com/p/chromium/issues/detail?id=9500
   base::RunLoop().RunUntilIdle();
 
-  BeforeShutdown();
   if (RunningOnValgrind())
     WebKit::WebCache::clear();
   WebKit::shutdown();
   delete test_environment;
   test_environment = NULL;
-  AfterShutdown();
-  logging::CloseLogFile();
 }
 
 }  // namespace webkit_support
diff --git a/webkit/support/webkit_support.gypi b/webkit/support/webkit_support.gypi
index bc7fae0..e8227f0 100644
--- a/webkit/support/webkit_support.gypi
+++ b/webkit/support/webkit_support.gypi
@@ -31,7 +31,6 @@
         '<(DEPTH)/webkit/renderer/webkit_renderer.gyp:webkit_renderer',
         '<(DEPTH)/webkit/storage_browser.gyp:webkit_storage_browser',
         '<(DEPTH)/webkit/storage_common.gyp:webkit_storage_common',
-        '<(DEPTH)/webkit/storage_renderer.gyp:webkit_storage_renderer',
         'glue',
         'glue_child',
         'webkit_support_common',
@@ -45,13 +44,6 @@
         'UNIT_TEST'
       ],
       'sources': [
-        'drt_application_mac.h',
-        'drt_application_mac.mm',
-        'platform_support.h',
-        'platform_support_android.cc',
-        'platform_support_linux.cc',
-        'platform_support_mac.mm',
-        'platform_support_win.cc',
         'test_webkit_platform_support.cc',
         'test_webkit_platform_support.h',
         'webkit_support.cc',
@@ -107,8 +99,6 @@
         '<(DEPTH)/base/base.gyp:base',
       ],
       'sources': [
-        '<(DEPTH)/webkit/support/mac/DumpRenderTreePasteboard.h',
-        '<(DEPTH)/webkit/support/mac/DumpRenderTreePasteboard.m',
         '<(DEPTH)/webkit/support/mock_webclipboard_impl.cc',
         '<(DEPTH)/webkit/support/mock_webclipboard_impl.h',
       ],
diff --git a/webkit/support/webkit_support.h b/webkit/support/webkit_support.h
index 9369be1..ed09e67 100644
--- a/webkit/support/webkit_support.h
+++ b/webkit/support/webkit_support.h
@@ -5,19 +5,10 @@
 #ifndef WEBKIT_SUPPORT_WEBKIT_SUPPORT_H_
 #define WEBKIT_SUPPORT_WEBKIT_SUPPORT_H_
 
-// This package provides functions used by DumpRenderTree/chromium.
+// This package provides functions used by webkit_unit_tests.
 namespace webkit_support {
 
-// Initializes or terminates a test environment.
-// |unit_test_mode| should be set to true when running in a TestSuite, in which
-// case no AtExitManager is created and ICU is not initialized (as it is already
-// done by the TestSuite).
-// SetUpTestEnvironment() and SetUpTestEnvironmentForUnitTests() calls
-// WebKit::initialize().
-// TearDownTestEnvironment() calls WebKit::shutdown().
-// SetUpTestEnvironmentForUnitTests() should be used when running in a
-// TestSuite, in which case no AtExitManager is created and ICU is not
-// initialized (as it is already done by the TestSuite).
+// Initializes or terminates a test environment for unit tests.
 void SetUpTestEnvironmentForUnitTests();
 void TearDownTestEnvironment();
 
diff --git a/webkit/webkit_storage_browser.target.darwin-arm.mk b/webkit/webkit_storage_browser.target.darwin-arm.mk
index f4e5d71..f6d7f76 100644
--- a/webkit/webkit_storage_browser.target.darwin-arm.mk
+++ b/webkit/webkit_storage_browser.target.darwin-arm.mk
@@ -85,10 +85,10 @@
 	webkit/browser/fileapi/obfuscated_file_util.cc \
 	webkit/browser/fileapi/recursive_operation_delegate.cc \
 	webkit/browser/fileapi/remove_operation_delegate.cc \
-	webkit/browser/fileapi/sandbox_context.cc \
 	webkit/browser/fileapi/sandbox_directory_database.cc \
 	webkit/browser/fileapi/sandbox_file_stream_writer.cc \
 	webkit/browser/fileapi/sandbox_file_system_backend.cc \
+	webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc \
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
diff --git a/webkit/webkit_storage_browser.target.darwin-mips.mk b/webkit/webkit_storage_browser.target.darwin-mips.mk
index 3f7a6f8..4f50ef8 100644
--- a/webkit/webkit_storage_browser.target.darwin-mips.mk
+++ b/webkit/webkit_storage_browser.target.darwin-mips.mk
@@ -85,10 +85,10 @@
 	webkit/browser/fileapi/obfuscated_file_util.cc \
 	webkit/browser/fileapi/recursive_operation_delegate.cc \
 	webkit/browser/fileapi/remove_operation_delegate.cc \
-	webkit/browser/fileapi/sandbox_context.cc \
 	webkit/browser/fileapi/sandbox_directory_database.cc \
 	webkit/browser/fileapi/sandbox_file_stream_writer.cc \
 	webkit/browser/fileapi/sandbox_file_system_backend.cc \
+	webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc \
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
diff --git a/webkit/webkit_storage_browser.target.darwin-x86.mk b/webkit/webkit_storage_browser.target.darwin-x86.mk
index 2cb73eb..e9a5f77 100644
--- a/webkit/webkit_storage_browser.target.darwin-x86.mk
+++ b/webkit/webkit_storage_browser.target.darwin-x86.mk
@@ -85,10 +85,10 @@
 	webkit/browser/fileapi/obfuscated_file_util.cc \
 	webkit/browser/fileapi/recursive_operation_delegate.cc \
 	webkit/browser/fileapi/remove_operation_delegate.cc \
-	webkit/browser/fileapi/sandbox_context.cc \
 	webkit/browser/fileapi/sandbox_directory_database.cc \
 	webkit/browser/fileapi/sandbox_file_stream_writer.cc \
 	webkit/browser/fileapi/sandbox_file_system_backend.cc \
+	webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc \
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
diff --git a/webkit/webkit_storage_browser.target.linux-arm.mk b/webkit/webkit_storage_browser.target.linux-arm.mk
index f4e5d71..f6d7f76 100644
--- a/webkit/webkit_storage_browser.target.linux-arm.mk
+++ b/webkit/webkit_storage_browser.target.linux-arm.mk
@@ -85,10 +85,10 @@
 	webkit/browser/fileapi/obfuscated_file_util.cc \
 	webkit/browser/fileapi/recursive_operation_delegate.cc \
 	webkit/browser/fileapi/remove_operation_delegate.cc \
-	webkit/browser/fileapi/sandbox_context.cc \
 	webkit/browser/fileapi/sandbox_directory_database.cc \
 	webkit/browser/fileapi/sandbox_file_stream_writer.cc \
 	webkit/browser/fileapi/sandbox_file_system_backend.cc \
+	webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc \
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
diff --git a/webkit/webkit_storage_browser.target.linux-mips.mk b/webkit/webkit_storage_browser.target.linux-mips.mk
index 3f7a6f8..4f50ef8 100644
--- a/webkit/webkit_storage_browser.target.linux-mips.mk
+++ b/webkit/webkit_storage_browser.target.linux-mips.mk
@@ -85,10 +85,10 @@
 	webkit/browser/fileapi/obfuscated_file_util.cc \
 	webkit/browser/fileapi/recursive_operation_delegate.cc \
 	webkit/browser/fileapi/remove_operation_delegate.cc \
-	webkit/browser/fileapi/sandbox_context.cc \
 	webkit/browser/fileapi/sandbox_directory_database.cc \
 	webkit/browser/fileapi/sandbox_file_stream_writer.cc \
 	webkit/browser/fileapi/sandbox_file_system_backend.cc \
+	webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc \
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
diff --git a/webkit/webkit_storage_browser.target.linux-x86.mk b/webkit/webkit_storage_browser.target.linux-x86.mk
index 2cb73eb..e9a5f77 100644
--- a/webkit/webkit_storage_browser.target.linux-x86.mk
+++ b/webkit/webkit_storage_browser.target.linux-x86.mk
@@ -85,10 +85,10 @@
 	webkit/browser/fileapi/obfuscated_file_util.cc \
 	webkit/browser/fileapi/recursive_operation_delegate.cc \
 	webkit/browser/fileapi/remove_operation_delegate.cc \
-	webkit/browser/fileapi/sandbox_context.cc \
 	webkit/browser/fileapi/sandbox_directory_database.cc \
 	webkit/browser/fileapi/sandbox_file_stream_writer.cc \
 	webkit/browser/fileapi/sandbox_file_system_backend.cc \
+	webkit/browser/fileapi/sandbox_file_system_backend_delegate.cc \
 	webkit/browser/fileapi/sandbox_isolated_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database.cc \
 	webkit/browser/fileapi/sandbox_origin_database_interface.cc \
diff --git a/webkit/webkit_storage_renderer.target.darwin-arm.mk b/webkit/webkit_storage_renderer.target.darwin-arm.mk
deleted file mode 100644
index 0a0e5c8..0000000
--- a/webkit/webkit_storage_renderer.target.darwin-arm.mk
+++ /dev/null
@@ -1,318 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := webkit_webkit_storage_renderer_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,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a
-
-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 := \
-	webkit/renderer/fileapi/webfilewriter_base.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# 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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_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: webkit_webkit_storage_renderer_gyp
-
-# Alias gyp target name.
-.PHONY: webkit_storage_renderer
-webkit_storage_renderer: webkit_webkit_storage_renderer_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/webkit/webkit_storage_renderer.target.darwin-mips.mk b/webkit/webkit_storage_renderer.target.darwin-mips.mk
deleted file mode 100644
index d88d614..0000000
--- a/webkit/webkit_storage_renderer.target.darwin-mips.mk
+++ /dev/null
@@ -1,314 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := webkit_webkit_storage_renderer_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,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a
-
-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 := \
-	webkit/renderer/fileapi/webfilewriter_base.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# 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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_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: webkit_webkit_storage_renderer_gyp
-
-# Alias gyp target name.
-.PHONY: webkit_storage_renderer
-webkit_storage_renderer: webkit_webkit_storage_renderer_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/webkit/webkit_storage_renderer.target.darwin-x86.mk b/webkit/webkit_storage_renderer.target.darwin-x86.mk
deleted file mode 100644
index 0e0b0fd..0000000
--- a/webkit/webkit_storage_renderer.target.darwin-x86.mk
+++ /dev/null
@@ -1,318 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := webkit_webkit_storage_renderer_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,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a
-
-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 := \
-	webkit/renderer/fileapi/webfilewriter_base.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# 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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_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: webkit_webkit_storage_renderer_gyp
-
-# Alias gyp target name.
-.PHONY: webkit_storage_renderer
-webkit_storage_renderer: webkit_webkit_storage_renderer_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/webkit/webkit_storage_renderer.target.linux-arm.mk b/webkit/webkit_storage_renderer.target.linux-arm.mk
deleted file mode 100644
index 0a0e5c8..0000000
--- a/webkit/webkit_storage_renderer.target.linux-arm.mk
+++ /dev/null
@@ -1,318 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := webkit_webkit_storage_renderer_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,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a
-
-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 := \
-	webkit/renderer/fileapi/webfilewriter_base.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# 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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-abi \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_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: webkit_webkit_storage_renderer_gyp
-
-# Alias gyp target name.
-.PHONY: webkit_storage_renderer
-webkit_storage_renderer: webkit_webkit_storage_renderer_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/webkit/webkit_storage_renderer.target.linux-mips.mk b/webkit/webkit_storage_renderer.target.linux-mips.mk
deleted file mode 100644
index d88d614..0000000
--- a/webkit/webkit_storage_renderer.target.linux-mips.mk
+++ /dev/null
@@ -1,314 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := webkit_webkit_storage_renderer_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,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a
-
-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 := \
-	webkit/renderer/fileapi/webfilewriter_base.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	-fstack-protector \
-	--param=ssp-buffer-size=4 \
-	 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# 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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-uninitialized \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_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: webkit_webkit_storage_renderer_gyp
-
-# Alias gyp target name.
-.PHONY: webkit_storage_renderer
-webkit_storage_renderer: webkit_webkit_storage_renderer_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/webkit/webkit_storage_renderer.target.linux-x86.mk b/webkit/webkit_storage_renderer.target.linux-x86.mk
deleted file mode 100644
index 0e0b0fd..0000000
--- a/webkit/webkit_storage_renderer.target.linux-x86.mk
+++ /dev/null
@@ -1,318 +0,0 @@
-# This file is generated by gyp; do not edit.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := webkit_webkit_storage_renderer_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,third_party_WebKit_public_blink_gyp)/blink.stamp \
-	$(call intermediates-dir-for,STATIC_LIBRARIES,skia_skia_library_gyp)/skia_skia_library_gyp.a
-
-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 := \
-	webkit/renderer/fileapi/webfilewriter_base.cc
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Debug := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-# Flags passed to both C and C++ files.
-MY_CFLAGS_Release := \
-	--param=ssp-buffer-size=4 \
-	-fno-exceptions \
-	-fno-strict-aliasing \
-	-Wno-unused-parameter \
-	-Wno-missing-field-initializers \
-	-fvisibility=hidden \
-	-pipe \
-	-fPIC \
-	-Wno-format \
-	-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 \
-	-Wno-address \
-	-Wno-format-security \
-	-Wno-return-type \
-	-Wno-sequence-point \
-	-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' \
-	'-DENABLE_GPU=1' \
-	'-DUSE_OPENSSL=1' \
-	'-DENABLE_EGLIMAGE=1' \
-	'-DWEBKIT_STORAGE_RENDERER_IMPLEMENTATION' \
-	'-DSK_ENABLE_INST_COUNT=0' \
-	'-DSK_SUPPORT_GPU=1' \
-	'-DGR_GL_CUSTOM_SETUP_HEADER="GrGLConfig_chrome.h"' \
-	'-DSK_BUILD_FOR_ANDROID' \
-	'-DUSE_CHROMIUM_SKIA' \
-	'-DSK_USE_POSIX_THREADS' \
-	'-DSK_DEFERRED_CANVAS_USES_FACTORIES=1' \
-	'-DU_USING_ICU_NAMESPACE=0' \
-	'-DANDROID' \
-	'-D__GNU_SOURCE=1' \
-	'-DUSE_STLPORT=1' \
-	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
-	'-DCHROME_BUILD_ID=""' \
-	'-DNDEBUG' \
-	'-DNVALGRIND' \
-	'-DDYNAMIC_ANNOTATIONS_ENABLED=0'
-
-
-# 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)/third_party/khronos \
-	$(LOCAL_PATH)/gpu \
-	$(LOCAL_PATH) \
-	$(LOCAL_PATH)/third_party/WebKit \
-	$(LOCAL_PATH)/third_party/skia/src/core \
-	$(LOCAL_PATH)/skia/config \
-	$(LOCAL_PATH)/third_party/skia/include/config \
-	$(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/ext \
-	$(PWD)/external/icu4c/common \
-	$(PWD)/external/icu4c/i18n \
-	$(LOCAL_PATH)/third_party/npapi \
-	$(LOCAL_PATH)/third_party/npapi/bindings \
-	$(LOCAL_PATH)/v8/include \
-	$(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 \
-	-Wno-deprecated \
-	-Wno-error=c++0x-compat \
-	-Wno-non-virtual-dtor \
-	-Wno-sign-promo \
-	-Wno-non-virtual-dtor
-
-
-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,--gc-sections \
-	-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
-
-
-LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
-
-LOCAL_STATIC_LIBRARIES := \
-	skia_skia_library_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: webkit_webkit_storage_renderer_gyp
-
-# Alias gyp target name.
-.PHONY: webkit_storage_renderer
-webkit_storage_renderer: webkit_webkit_storage_renderer_gyp
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/win8/metro_driver/chrome_app_view_ash.cc b/win8/metro_driver/chrome_app_view_ash.cc
index b98d7ac..8686b53 100644
--- a/win8/metro_driver/chrome_app_view_ash.cc
+++ b/win8/metro_driver/chrome_app_view_ash.cc
@@ -637,9 +637,10 @@
     return hr;
 
   if (pointer.IsMouse()) {
-    ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(pointer.x(),
-                                                        pointer.y(),
-                                                        mouse_down_flags_));
+    ui_channel_->Send(new MetroViewerHostMsg_MouseMoved(
+        pointer.x(),
+        pointer.y(),
+        mouse_down_flags_ | GetKeyboardEventFlags()));
   } else {
     DCHECK(pointer.IsTouch());
     ui_channel_->Send(new MetroViewerHostMsg_TouchMoved(pointer.x(),
@@ -665,11 +666,13 @@
 
   if (pointer.IsMouse()) {
     mouse_down_flags_ = pointer.flags();
-    ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(),
-                                                         pointer.y(),
-                                                         0,
-                                                         ui::ET_MOUSE_PRESSED,
-                                                         mouse_down_flags_));
+    ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
+        pointer.x(),
+        pointer.y(),
+        0,
+        ui::ET_MOUSE_PRESSED,
+        static_cast<ui::EventFlags>(
+            mouse_down_flags_ | GetKeyboardEventFlags())));
   } else {
     DCHECK(pointer.IsTouch());
     ui_channel_->Send(new MetroViewerHostMsg_TouchDown(pointer.x(),
@@ -690,11 +693,13 @@
 
   if (pointer.IsMouse()) {
     mouse_down_flags_ = ui::EF_NONE;
-    ui_channel_->Send(new MetroViewerHostMsg_MouseButton(pointer.x(),
-                                                         pointer.y(),
-                                                         0,
-                                                         ui::ET_MOUSE_RELEASED,
-                                                         pointer.flags()));
+    ui_channel_->Send(new MetroViewerHostMsg_MouseButton(
+        pointer.x(),
+        pointer.y(),
+        0,
+        ui::ET_MOUSE_RELEASED,
+        static_cast<ui::EventFlags>(
+            pointer.flags() | GetKeyboardEventFlags())));
   } else {
     DCHECK(pointer.IsTouch());
     ui_channel_->Send(new MetroViewerHostMsg_TouchUp(pointer.x(),
diff --git a/win8/metro_driver/file_picker.cc b/win8/metro_driver/file_picker.cc
index 4557665..cf1c878 100644
--- a/win8/metro_driver/file_picker.cc
+++ b/win8/metro_driver/file_picker.cc
@@ -311,7 +311,6 @@
 
       // Metro wants suffixes only, not patterns.
       mswrw::HString extension;
-      std::vector<string16> extensions;
       for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
         if (extensions_win32_style[i] == L"*.*") {
           // The wildcard filter is "*" for Metro. The string "*.*" produces
diff --git a/win8/metro_driver/file_picker_ash.cc b/win8/metro_driver/file_picker_ash.cc
index fbccee5..343d7b4 100644
--- a/win8/metro_driver/file_picker_ash.cc
+++ b/win8/metro_driver/file_picker_ash.cc
@@ -152,7 +152,7 @@
       LOG(ERROR) << "NULL IStorageItem";
     }
   } else {
-    LOG(ERROR) << "Unexpected async status " << status;
+    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
   }
   app_view_->OnOpenFileCompleted(this, success_);
   return S_OK;
@@ -203,7 +203,7 @@
       LOG(ERROR) << "NULL StorageFileVectorCollection";
     }
   } else {
-    LOG(ERROR) << "Unexpected async status " << status;
+    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
   }
   app_view_->OnOpenFileCompleted(this, success_);
   return S_OK;
@@ -249,7 +249,6 @@
 
       // Metro wants suffixes only, not patterns.
       mswrw::HString extension;
-      std::vector<string16> extensions;
       for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
         if (extensions_win32_style[i] == L"*.*") {
           // The wildcard filter is "*" for Metro. The string "*.*" produces
@@ -543,7 +542,7 @@
       LOG(ERROR) << "NULL IStorageItem";
     }
   } else {
-    LOG(ERROR) << "Unexpected async status " << status;
+    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
   }
   app_view_->OnSaveFileCompleted(this, success_);
   return S_OK;
@@ -612,7 +611,7 @@
       LOG(ERROR) << "NULL IStorageItem";
     }
   } else {
-    LOG(ERROR) << "Unexpected async status " << status;
+    LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
   }
   app_view_->OnFolderPickerCompleted(this, success_);
   return S_OK;